From 2c160a8a2567cec4cbe9f73f88e4f40b9a700164 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 May 2023 09:38:21 +1200 Subject: [PATCH 0001/2607] Bump version to 2023.5.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 46e5545078..56034bfbf6 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0-dev" +__version__ = "2023.5.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From d80885c7a8868b8bd4b25cb7d2a262282d82d622 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 11 May 2023 00:00:28 +0200 Subject: [PATCH 0002/2607] Fixed access point for ESP32 IDF platform (#4784) --- esphome/components/wifi/wifi_component_esp_idf.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 1c70f33040..e18d3cc043 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -767,11 +767,10 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.gw.addr = static_cast(network::IPAddress(192, 168, 4, 1)); info.netmask.addr = static_cast(network::IPAddress(255, 255, 255, 0)); } - esp_netif_dhcp_status_t dhcp_status; - esp_netif_dhcps_get_status(s_sta_netif, &dhcp_status); - err = esp_netif_dhcps_stop(s_sta_netif); - if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_stop failed! %d", err); + + err = esp_netif_dhcpc_stop(s_sta_netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { + ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); return false; } From d88358be8e9a18994c3c37a9be4397b2910ddcea Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 May 2023 11:33:59 +1200 Subject: [PATCH 0003/2607] Remove AUTO_LOAD from apds9960 (#4746) --- esphome/components/apds9960/__init__.py | 1 - esphome/components/apds9960/apds9960.cpp | 71 ++++++++++++++------ esphome/components/apds9960/apds9960.h | 41 +++++------ esphome/components/apds9960/binary_sensor.py | 11 +-- esphome/components/apds9960/sensor.py | 12 +--- 5 files changed, 79 insertions(+), 57 deletions(-) diff --git a/esphome/components/apds9960/__init__.py b/esphome/components/apds9960/__init__.py index 37dc4c0b28..06b3c85aee 100644 --- a/esphome/components/apds9960/__init__.py +++ b/esphome/components/apds9960/__init__.py @@ -4,7 +4,6 @@ from esphome.components import i2c from esphome.const import CONF_ID DEPENDENCIES = ["i2c"] -AUTO_LOAD = ["sensor", "binary_sensor"] MULTI_CONF = True CONF_APDS9960_ID = "apds9960_id" diff --git a/esphome/components/apds9960/apds9960.cpp b/esphome/components/apds9960/apds9960.cpp index 1c6ec5c14a..d91378afee 100644 --- a/esphome/components/apds9960/apds9960.cpp +++ b/esphome/components/apds9960/apds9960.cpp @@ -116,8 +116,12 @@ void APDS9960::setup() { APDS9960_WRITE_BYTE(0x80, val); } bool APDS9960::is_color_enabled_() const { - return this->red_channel_ != nullptr || this->green_channel_ != nullptr || this->blue_channel_ != nullptr || - this->clear_channel_ != nullptr; +#ifdef USE_SENSOR + return this->red_sensor_ != nullptr || this->green_sensor_ != nullptr || this->blue_sensor_ != nullptr || + this->clear_sensor_ != nullptr; +#else + return false; +#endif } void APDS9960::dump_config() { @@ -125,6 +129,15 @@ void APDS9960::dump_config() { LOG_I2C_DEVICE(this); LOG_UPDATE_INTERVAL(this); + +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Red channel", this->red_sensor_); + LOG_SENSOR(" ", "Green channel", this->green_sensor_); + LOG_SENSOR(" ", "Blue channel", this->blue_sensor_); + LOG_SENSOR(" ", "Clear channel", this->clear_sensor_); + LOG_SENSOR(" ", "Proximity", this->proximity_sensor_); +#endif + if (this->is_failed()) { switch (this->error_code_) { case COMMUNICATION_FAILED: @@ -181,17 +194,22 @@ void APDS9960::read_color_data_(uint8_t status) { float blue_perc = (uint_blue / float(UINT16_MAX)) * 100.0f; ESP_LOGD(TAG, "Got clear=%.1f%% red=%.1f%% green=%.1f%% blue=%.1f%%", clear_perc, red_perc, green_perc, blue_perc); - if (this->clear_channel_ != nullptr) - this->clear_channel_->publish_state(clear_perc); - if (this->red_channel_ != nullptr) - this->red_channel_->publish_state(red_perc); - if (this->green_channel_ != nullptr) - this->green_channel_->publish_state(green_perc); - if (this->blue_channel_ != nullptr) - this->blue_channel_->publish_state(blue_perc); +#ifdef USE_SENSOR + if (this->clear_sensor_ != nullptr) + this->clear_sensor_->publish_state(clear_perc); + if (this->red_sensor_ != nullptr) + this->red_sensor_->publish_state(red_perc); + if (this->green_sensor_ != nullptr) + this->green_sensor_->publish_state(green_perc); + if (this->blue_sensor_ != nullptr) + this->blue_sensor_->publish_state(blue_perc); +#endif } void APDS9960::read_proximity_data_(uint8_t status) { - if (this->proximity_ == nullptr) +#ifndef USE_SENSOR + return; +#else + if (this->proximity_sensor_ == nullptr) return; if ((status & 0b10) == 0x00) { @@ -204,7 +222,8 @@ void APDS9960::read_proximity_data_(uint8_t status) { float prox_perc = (prox / float(UINT8_MAX)) * 100.0f; ESP_LOGD(TAG, "Got proximity=%.1f%%", prox_perc); - this->proximity_->publish_state(prox_perc); + this->proximity_sensor_->publish_state(prox_perc); +#endif } void APDS9960::read_gesture_data_() { if (!this->is_gesture_enabled_()) @@ -256,28 +275,29 @@ void APDS9960::read_gesture_data_() { } } void APDS9960::report_gesture_(int gesture) { +#ifdef USE_BINARY_SENSOR binary_sensor::BinarySensor *bin; switch (gesture) { case 1: - bin = this->up_direction_; + bin = this->up_direction_binary_sensor_; this->gesture_up_started_ = false; this->gesture_down_started_ = false; ESP_LOGD(TAG, "Got gesture UP"); break; case 2: - bin = this->down_direction_; + bin = this->down_direction_binary_sensor_; this->gesture_up_started_ = false; this->gesture_down_started_ = false; ESP_LOGD(TAG, "Got gesture DOWN"); break; case 3: - bin = this->left_direction_; + bin = this->left_direction_binary_sensor_; this->gesture_left_started_ = false; this->gesture_right_started_ = false; ESP_LOGD(TAG, "Got gesture LEFT"); break; case 4: - bin = this->right_direction_; + bin = this->right_direction_binary_sensor_; this->gesture_left_started_ = false; this->gesture_right_started_ = false; ESP_LOGD(TAG, "Got gesture RIGHT"); @@ -290,6 +310,7 @@ void APDS9960::report_gesture_(int gesture) { bin->publish_state(true); bin->publish_state(false); } +#endif } void APDS9960::process_dataset_(int up, int down, int left, int right) { /* Algorithm: (see Figure 11 in datasheet) @@ -365,10 +386,22 @@ void APDS9960::process_dataset_(int up, int down, int left, int right) { } } float APDS9960::get_setup_priority() const { return setup_priority::DATA; } -bool APDS9960::is_proximity_enabled_() const { return this->proximity_ != nullptr || this->is_gesture_enabled_(); } +bool APDS9960::is_proximity_enabled_() const { + return +#ifdef USE_SENSOR + this->proximity_sensor_ != nullptr +#else + false +#endif + || this->is_gesture_enabled_(); +} bool APDS9960::is_gesture_enabled_() const { - return this->up_direction_ != nullptr || this->left_direction_ != nullptr || this->down_direction_ != nullptr || - this->right_direction_ != nullptr; +#ifdef USE_BINARY_SENSOR + return this->up_direction_binary_sensor_ != nullptr || this->left_direction_binary_sensor_ != nullptr || + this->down_direction_binary_sensor_ != nullptr || this->right_direction_binary_sensor_ != nullptr; +#else + return false; +#endif } } // namespace apds9960 diff --git a/esphome/components/apds9960/apds9960.h b/esphome/components/apds9960/apds9960.h index 23d9835640..2a0fbb5c19 100644 --- a/esphome/components/apds9960/apds9960.h +++ b/esphome/components/apds9960/apds9960.h @@ -1,14 +1,34 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" +#endif namespace esphome { namespace apds9960 { class APDS9960 : public PollingComponent, public i2c::I2CDevice { +#ifdef USE_SENSOR + SUB_SENSOR(red) + SUB_SENSOR(green) + SUB_SENSOR(blue) + SUB_SENSOR(clear) + SUB_SENSOR(proximity) +#endif + +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(up_direction) + SUB_BINARY_SENSOR(right_direction) + SUB_BINARY_SENSOR(down_direction) + SUB_BINARY_SENSOR(left_direction) +#endif + public: void setup() override; void dump_config() override; @@ -23,16 +43,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice { void set_gesture_gain(uint8_t gain) { this->gesture_gain_ = gain; } void set_gesture_wait_time(uint8_t wait_time) { this->gesture_wait_time_ = wait_time; } - void set_red_channel(sensor::Sensor *red_channel) { red_channel_ = red_channel; } - void set_green_channel(sensor::Sensor *green_channel) { green_channel_ = green_channel; } - void set_blue_channel(sensor::Sensor *blue_channel) { blue_channel_ = blue_channel; } - void set_clear_channel(sensor::Sensor *clear_channel) { clear_channel_ = clear_channel; } - void set_up_direction(binary_sensor::BinarySensor *up_direction) { up_direction_ = up_direction; } - void set_right_direction(binary_sensor::BinarySensor *right_direction) { right_direction_ = right_direction; } - void set_down_direction(binary_sensor::BinarySensor *down_direction) { down_direction_ = down_direction; } - void set_left_direction(binary_sensor::BinarySensor *left_direction) { left_direction_ = left_direction; } - void set_proximity(sensor::Sensor *proximity) { proximity_ = proximity; } - protected: bool is_color_enabled_() const; bool is_proximity_enabled_() const; @@ -50,15 +60,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice { uint8_t gesture_gain_; uint8_t gesture_wait_time_; - sensor::Sensor *red_channel_{nullptr}; - sensor::Sensor *green_channel_{nullptr}; - sensor::Sensor *blue_channel_{nullptr}; - sensor::Sensor *clear_channel_{nullptr}; - binary_sensor::BinarySensor *up_direction_{nullptr}; - binary_sensor::BinarySensor *right_direction_{nullptr}; - binary_sensor::BinarySensor *down_direction_{nullptr}; - binary_sensor::BinarySensor *left_direction_{nullptr}; - sensor::Sensor *proximity_{nullptr}; enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, diff --git a/esphome/components/apds9960/binary_sensor.py b/esphome/components/apds9960/binary_sensor.py index 04dc6f4d5d..46b08d8d69 100644 --- a/esphome/components/apds9960/binary_sensor.py +++ b/esphome/components/apds9960/binary_sensor.py @@ -6,19 +6,14 @@ from . import APDS9960, CONF_APDS9960_ID DEPENDENCIES = ["apds9960"] -DIRECTIONS = { - "UP": "set_up_direction", - "DOWN": "set_down_direction", - "LEFT": "set_left_direction", - "RIGHT": "set_right_direction", -} +DIRECTIONS = ["up", "down", "left", "right"] CONFIG_SCHEMA = binary_sensor.binary_sensor_schema( device_class=DEVICE_CLASS_MOVING ).extend( { cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960), - cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True), + cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, lower=True), } ) @@ -26,5 +21,5 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema( async def to_code(config): hub = await cg.get_variable(config[CONF_APDS9960_ID]) var = await binary_sensor.new_binary_sensor(config) - func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]]) + func = getattr(hub, f"set_{config[CONF_DIRECTION]}_direction_binary_sensor") cg.add(func(var)) diff --git a/esphome/components/apds9960/sensor.py b/esphome/components/apds9960/sensor.py index e1990ec26e..c9865f8687 100644 --- a/esphome/components/apds9960/sensor.py +++ b/esphome/components/apds9960/sensor.py @@ -11,13 +11,7 @@ from . import APDS9960, CONF_APDS9960_ID DEPENDENCIES = ["apds9960"] -TYPES = { - "CLEAR": "set_clear_channel", - "RED": "set_red_channel", - "GREEN": "set_green_channel", - "BLUE": "set_blue_channel", - "PROXIMITY": "set_proximity", -} +TYPES = ["clear", "red", "green", "blue", "proximity"] CONFIG_SCHEMA = sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, @@ -26,7 +20,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( state_class=STATE_CLASS_MEASUREMENT, ).extend( { - cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True), + cv.Required(CONF_TYPE): cv.one_of(*TYPES, lower=True), cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960), } ) @@ -35,5 +29,5 @@ CONFIG_SCHEMA = sensor.sensor_schema( async def to_code(config): hub = await cg.get_variable(config[CONF_APDS9960_ID]) var = await sensor.new_sensor(config) - func = getattr(hub, TYPES[config[CONF_TYPE]]) + func = getattr(hub, f"set_{config[CONF_TYPE]}_sensor") cg.add(func(var)) From 2fd2e5ceb2044e2faadb56fddd67351b0ed23840 Mon Sep 17 00:00:00 2001 From: Alex Dekker Date: Thu, 11 May 2023 23:25:34 +0200 Subject: [PATCH 0004/2607] Supposed to fix #4069, by changing the default value to 0s (timeunit instead of int) to pass validation (#4806) Co-authored-by: Alex1602 --- esphome/components/sprinkler/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sprinkler/__init__.py b/esphome/components/sprinkler/__init__.py index 6aa76dcd2f..5097abc7e7 100644 --- a/esphome/components/sprinkler/__init__.py +++ b/esphome/components/sprinkler/__init__.py @@ -275,7 +275,7 @@ SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA = cv.Schema( SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA = cv.Schema( { cv.Required(CONF_ID): cv.use_id(Sprinkler), - cv.Optional(CONF_RUN_DURATION, default=0): cv.templatable( + cv.Optional(CONF_RUN_DURATION, default="0s"): cv.templatable( cv.positive_time_period_seconds ), cv.Required(CONF_VALVE_NUMBER): cv.templatable(cv.positive_int), From e2f3e7c3a60f1617d4ed05a73764975de20b7b4a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 May 2023 10:32:59 +1200 Subject: [PATCH 0005/2607] Bump version to 2023.5.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 56034bfbf6..48009df20a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0b1" +__version__ = "2023.5.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From af95e781f519e0c6230d94d4412b58f08cc14f23 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Fri, 12 May 2023 02:46:47 +0100 Subject: [PATCH 0006/2607] Wording (#4805) --- esphome/components/sen5x/sen5x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sen5x/sen5x.cpp b/esphome/components/sen5x/sen5x.cpp index 865fae373b..ddce568c97 100644 --- a/esphome/components/sen5x/sen5x.cpp +++ b/esphome/components/sen5x/sen5x.cpp @@ -252,7 +252,7 @@ void SEN5XComponent::dump_config() { ESP_LOGCONFIG(TAG, " Firmware version: %d", this->firmware_version_); ESP_LOGCONFIG(TAG, " Serial number %02d.%02d.%02d", serial_number_[0], serial_number_[1], serial_number_[2]); if (this->auto_cleaning_interval_.has_value()) { - ESP_LOGCONFIG(TAG, " Auto auto cleaning interval %d seconds", auto_cleaning_interval_.value()); + ESP_LOGCONFIG(TAG, " Auto cleaning interval %d seconds", auto_cleaning_interval_.value()); } if (this->acceleration_mode_.has_value()) { switch (this->acceleration_mode_.value()) { From e0ee8ca17ca810b55d50d36fc524ca51a1aae71e Mon Sep 17 00:00:00 2001 From: richardhopton Date: Fri, 12 May 2023 20:16:28 -0700 Subject: [PATCH 0007/2607] Tuya: Prevent loop when setting colors on case-sensitive dps (#4809) Co-authored-by: Samuel Sieb --- esphome/components/tuya/light/tuya_light.cpp | 46 +++++++++++--------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/esphome/components/tuya/light/tuya_light.cpp b/esphome/components/tuya/light/tuya_light.cpp index 869e20871d..7b7a974de2 100644 --- a/esphome/components/tuya/light/tuya_light.cpp +++ b/esphome/components/tuya/light/tuya_light.cpp @@ -57,37 +57,43 @@ void TuyaLight::setup() { return; } + float red, green, blue; switch (*this->color_type_) { case TuyaColorType::RGBHSV: case TuyaColorType::RGB: { - auto red = parse_hex(datapoint.value_string.substr(0, 2)); - auto green = parse_hex(datapoint.value_string.substr(2, 2)); - auto blue = parse_hex(datapoint.value_string.substr(4, 2)); - if (red.has_value() && green.has_value() && blue.has_value()) { - auto rgb_call = this->state_->make_call(); - rgb_call.set_rgb(float(*red) / 255, float(*green) / 255, float(*blue) / 255); - rgb_call.perform(); - } + auto rgb = parse_hex(datapoint.value_string.substr(0, 6)); + if (!rgb.has_value()) + return; + + red = (*rgb >> 16) / 255.0f; + green = ((*rgb >> 8) & 0xff) / 255.0f; + blue = (*rgb & 0xff) / 255.0f; break; } case TuyaColorType::HSV: { auto hue = parse_hex(datapoint.value_string.substr(0, 4)); auto saturation = parse_hex(datapoint.value_string.substr(4, 4)); auto value = parse_hex(datapoint.value_string.substr(8, 4)); - if (hue.has_value() && saturation.has_value() && value.has_value()) { - float red, green, blue; - hsv_to_rgb(*hue, float(*saturation) / 1000, float(*value) / 1000, red, green, blue); - auto rgb_call = this->state_->make_call(); - rgb_call.set_rgb(red, green, blue); - rgb_call.perform(); - } + if (!hue.has_value() || !saturation.has_value() || !value.has_value()) + return; + + hsv_to_rgb(*hue, float(*saturation) / 1000, float(*value) / 1000, red, green, blue); break; } } + + float current_red, current_green, current_blue; + this->state_->current_values_as_rgb(¤t_red, ¤t_green, ¤t_blue); + if (red == current_red && green == current_green && blue == current_blue) + return; + auto rgb_call = this->state_->make_call(); + rgb_call.set_rgb(red, green, blue); + rgb_call.perform(); }); } + if (min_value_datapoint_id_.has_value()) { - parent_->set_integer_datapoint_value(*this->min_value_datapoint_id_, this->min_value_); + this->parent_->set_integer_datapoint_value(*this->min_value_datapoint_id_, this->min_value_); } } @@ -156,7 +162,7 @@ void TuyaLight::write_state(light::LightState *state) { } if (!state->current_values.is_on() && this->switch_id_.has_value()) { - parent_->set_boolean_datapoint_value(*this->switch_id_, false); + this->parent_->set_boolean_datapoint_value(*this->switch_id_, false); return; } @@ -166,14 +172,14 @@ void TuyaLight::write_state(light::LightState *state) { if (this->color_temperature_invert_) { color_temp_int = this->color_temperature_max_value_ - color_temp_int; } - parent_->set_integer_datapoint_value(*this->color_temperature_id_, color_temp_int); + this->parent_->set_integer_datapoint_value(*this->color_temperature_id_, color_temp_int); } if (this->dimmer_id_.has_value()) { auto brightness_int = static_cast(brightness * this->max_value_); brightness_int = std::max(brightness_int, this->min_value_); - parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int); + this->parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int); } } @@ -210,7 +216,7 @@ void TuyaLight::write_state(light::LightState *state) { } if (this->switch_id_.has_value()) { - parent_->set_boolean_datapoint_value(*this->switch_id_, true); + this->parent_->set_boolean_datapoint_value(*this->switch_id_, true); } } From 625126df686a782a54aaf79dbeced59911b3b953 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 13 May 2023 17:19:06 +1200 Subject: [PATCH 0008/2607] Fix i2s media player volume control (#4813) --- .../media_player/i2s_audio_media_player.cpp | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 2e9ded601d..4de1136987 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -22,14 +22,14 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->start(); } } - if (this->i2s_state_ != I2S_STATE_RUNNING) { - return; - } if (call.get_volume().has_value()) { this->volume = call.get_volume().value(); this->set_volume_(volume); this->unmute_(); } + if (this->i2s_state_ != I2S_STATE_RUNNING) { + return; + } if (call.get_command().has_value()) { switch (call.get_command().value()) { case media_player::MEDIA_PLAYER_COMMAND_PLAY: @@ -97,7 +97,8 @@ void I2SAudioMediaPlayer::unmute_() { this->muted_ = false; } void I2SAudioMediaPlayer::set_volume_(float volume, bool publish) { - this->audio_->setVolume(remap(volume, 0.0f, 1.0f, 0, 21)); + if (this->audio_ != nullptr) + this->audio_->setVolume(remap(volume, 0.0f, 1.0f, 0, 21)); if (publish) this->volume = volume; } @@ -157,13 +158,23 @@ void I2SAudioMediaPlayer::start_() { #endif this->i2s_state_ = I2S_STATE_RUNNING; this->high_freq_.start(); + this->audio_->setVolume(remap(this->volume, 0.0f, 1.0f, 0, 21)); if (this->current_url_.has_value()) { this->audio_->connecttohost(this->current_url_.value().c_str()); this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; this->publish_state(); } } -void I2SAudioMediaPlayer::stop() { this->i2s_state_ = I2S_STATE_STOPPING; } +void I2SAudioMediaPlayer::stop() { + if (this->i2s_state_ == I2S_STATE_STOPPED) { + return; + } + if (this->i2s_state_ == I2S_STATE_STARTING) { + this->i2s_state_ = I2S_STATE_STOPPED; + return; + } + this->i2s_state_ = I2S_STATE_STOPPING; +} void I2SAudioMediaPlayer::stop_() { if (this->audio_->isRunning()) { this->audio_->stopSong(); From 65cda1088400b257c68fca0f87e73b49abf9f50e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 15 May 2023 10:11:48 +1200 Subject: [PATCH 0009/2607] Dontr try stop if not actually started (#4814) --- .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 4 ++++ esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 2b38853528..0f45cf95c6 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -89,6 +89,10 @@ void I2SAudioMicrophone::start_() { void I2SAudioMicrophone::stop() { if (this->state_ == microphone::STATE_STOPPED || this->is_failed()) return; + if (this->state_ == microphone::STATE_STARTING) { + this->state_ = microphone::STATE_STOPPED; + return; + } this->state_ = microphone::STATE_STOPPING; } diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index fa41a70277..5ae597dc7c 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -136,6 +136,10 @@ void I2SAudioSpeaker::player_task(void *params) { void I2SAudioSpeaker::stop() { if (this->state_ == speaker::STATE_STOPPED) return; + if (this->state_ == speaker::STATE_STARTING) { + this->state_ = speaker::STATE_STOPPED; + return; + } this->state_ = speaker::STATE_STOPPING; DataEvent data; data.stop = true; From e25d92e1f5d35049faeb331d8eebaea2c716a2a7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 15 May 2023 11:37:55 +1200 Subject: [PATCH 0010/2607] Bump version to 2023.5.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 48009df20a..9c2ab5e2b8 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0b2" +__version__ = "2023.5.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 6ccea59f71a58559fc48e631e1b221bfb6e9fce1 Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Mon, 15 May 2023 22:24:03 +0200 Subject: [PATCH 0011/2607] Fix missing stop trait in send_cover_info (#4826) --- esphome/components/api/api_connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 013b46695d..c350197e68 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -223,6 +223,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) { msg.assumed_state = traits.get_is_assumed_state(); msg.supports_position = traits.get_supports_position(); msg.supports_tilt = traits.get_supports_tilt(); + msg.supports_stop = traits.get_supports_stop(); msg.device_class = cover->get_device_class(); msg.disabled_by_default = cover->is_disabled_by_default(); msg.icon = cover->get_icon(); From e13e754bc46ecdfc67f76fe164ab00c1d982c7bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 08:24:58 +1200 Subject: [PATCH 0012/2607] Bump aioesphomeapi from 13.7.2 to 13.7.5 (#4830) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a62c48e235..8a2281b96f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.6 # When updating platformio, also update Dockerfile esptool==4.5.1 click==8.1.3 esphome-dashboard==20230214.0 -aioesphomeapi==13.7.2 +aioesphomeapi==13.7.5 zeroconf==0.60.0 # esp-idf requires this, but doesn't bundle it by default From c16ca7be133d292eed6f0a7b52197101453bffce Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 15 May 2023 21:29:00 +0100 Subject: [PATCH 0013/2607] Update PulseLightEffect with range brightness (#4820) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/light/base_light_effects.h | 9 ++++++++- esphome/components/light/effects.py | 9 +++++++++ esphome/components/shelly_dimmer/light.py | 5 +++-- esphome/const.py | 2 ++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/esphome/components/light/base_light_effects.h b/esphome/components/light/base_light_effects.h index 6291aa0610..9211bba7c9 100644 --- a/esphome/components/light/base_light_effects.h +++ b/esphome/components/light/base_light_effects.h @@ -25,7 +25,7 @@ class PulseLightEffect : public LightEffect { return; } auto call = this->state_->turn_on(); - float out = this->on_ ? 1.0 : 0.0; + float out = this->on_ ? this->max_brightness : this->min_brightness; call.set_brightness_if_supported(out); this->on_ = !this->on_; call.set_transition_length_if_supported(this->transition_length_); @@ -41,11 +41,18 @@ class PulseLightEffect : public LightEffect { void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; } + void set_min_max_brightness(float min, float max) { + this->min_brightness = min; + this->max_brightness = max; + } + protected: bool on_ = false; uint32_t last_color_change_{0}; uint32_t transition_length_{}; uint32_t update_interval_{}; + float min_brightness{0.0}; + float max_brightness{1.0}; }; /// Random effect. Sets random colors every 10 seconds and slowly transitions between them. diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index cef7cd7f3a..c694d6f50c 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -28,6 +28,8 @@ from esphome.const import ( CONF_NUM_LEDS, CONF_RANDOM, CONF_SEQUENCE, + CONF_MAX_BRIGHTNESS, + CONF_MIN_BRIGHTNESS, ) from esphome.util import Registry from .types import ( @@ -174,12 +176,19 @@ async def automation_effect_to_code(config, effect_id): cv.Optional( CONF_UPDATE_INTERVAL, default="1s" ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_MIN_BRIGHTNESS, default="0%"): cv.percentage, + cv.Optional(CONF_MAX_BRIGHTNESS, default="100%"): cv.percentage, }, ) async def pulse_effect_to_code(config, effect_id): effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH])) cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL])) + cg.add( + effect.set_min_max_brightness( + config[CONF_MIN_BRIGHTNESS], config[CONF_MAX_BRIGHTNESS] + ) + ) return effect diff --git a/esphome/components/shelly_dimmer/light.py b/esphome/components/shelly_dimmer/light.py index 20e0e8156b..c49193d135 100644 --- a/esphome/components/shelly_dimmer/light.py +++ b/esphome/components/shelly_dimmer/light.py @@ -23,6 +23,8 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_CURRENT, + CONF_MIN_BRIGHTNESS, + CONF_MAX_BRIGHTNESS, ) from esphome.core import HexInt, CORE @@ -41,8 +43,7 @@ CONF_UPDATE = "update" CONF_LEADING_EDGE = "leading_edge" CONF_WARMUP_BRIGHTNESS = "warmup_brightness" # CONF_WARMUP_TIME = "warmup_time" -CONF_MIN_BRIGHTNESS = "min_brightness" -CONF_MAX_BRIGHTNESS = "max_brightness" + CONF_NRST_PIN = "nrst_pin" CONF_BOOT0_PIN = "boot0_pin" diff --git a/esphome/const.py b/esphome/const.py index 9c2ab5e2b8..8cc689fa58 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -377,6 +377,7 @@ CONF_MAKE_ID = "make_id" CONF_MANUAL_IP = "manual_ip" CONF_MANUFACTURER_ID = "manufacturer_id" CONF_MASK_DISTURBER = "mask_disturber" +CONF_MAX_BRIGHTNESS = "max_brightness" CONF_MAX_COOLING_RUN_TIME = "max_cooling_run_time" CONF_MAX_CURRENT = "max_current" CONF_MAX_DURATION = "max_duration" @@ -396,6 +397,7 @@ CONF_MEDIUM = "medium" CONF_MEMORY_BLOCKS = "memory_blocks" CONF_METHOD = "method" CONF_MICROPHONE = "microphone" +CONF_MIN_BRIGHTNESS = "min_brightness" CONF_MIN_COOLING_OFF_TIME = "min_cooling_off_time" CONF_MIN_COOLING_RUN_TIME = "min_cooling_run_time" CONF_MIN_FAN_MODE_SWITCHING_TIME = "min_fan_mode_switching_time" From f66024b37c975f418dc4bbe8298b1f1961c53170 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 May 2023 10:25:49 +1200 Subject: [PATCH 0014/2607] Bump esphome-dashboard to 20230516.0 (#4831) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8a2281b96f..b791311152 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pyserial==3.5 platformio==6.1.6 # When updating platformio, also update Dockerfile esptool==4.5.1 click==8.1.3 -esphome-dashboard==20230214.0 +esphome-dashboard==20230516.0 aioesphomeapi==13.7.5 zeroconf==0.60.0 From 2e5757a3f0de22dfc851a2333ea19c901c36ec51 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Mon, 15 May 2023 23:28:01 +0100 Subject: [PATCH 0015/2607] Fix time period validation for the auto cleaning interval (#4811) --- esphome/components/sen5x/sensor.py | 2 +- tests/test5.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/sen5x/sensor.py b/esphome/components/sen5x/sensor.py index 489fda8335..392510e417 100644 --- a/esphome/components/sen5x/sensor.py +++ b/esphome/components/sen5x/sensor.py @@ -119,7 +119,7 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_PM10, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.time_period_in_seconds_, + cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.update_interval, cv.Optional(CONF_VOC): sensor.sensor_schema( icon=ICON_RADIATOR, accuracy_decimals=0, diff --git a/tests/test5.yaml b/tests/test5.yaml index 6b64ef2d15..cb4b559b06 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -489,6 +489,7 @@ sensor: offset: 0 normalized_offset_slope: 0 time_constant: 0 + auto_cleaning_interval: 604800s acceleration_mode: low store_baseline: true address: 0x69 From daa966975e2660d0ddbec98141506b59d04fd091 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 10:30:08 +1200 Subject: [PATCH 0016/2607] Bump tzlocal from 4.2 to 5.0.1 (#4829) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b791311152..0da1d8a812 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ PyYAML==6.0 paho-mqtt==1.6.1 colorama==0.4.6 tornado==6.3.1 -tzlocal==4.2 # from time +tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.6 # When updating platformio, also update Dockerfile From c71e7d0132c9f0a6de02ebc9c85f15b8f75834ba Mon Sep 17 00:00:00 2001 From: Justin Gerace Date: Mon, 15 May 2023 16:00:05 -0700 Subject: [PATCH 0017/2607] Start UART assignment at UART0 if the logger is not enabled or is not configured for hardware logging on ESP32 (#4762) --- .../uart/uart_component_esp32_arduino.cpp | 20 +++++++++++++++++-- .../uart/uart_component_esp32_arduino.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/esphome/components/uart/uart_component_esp32_arduino.cpp b/esphome/components/uart/uart_component_esp32_arduino.cpp index 8bbbc1a650..7306dd2f31 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.cpp +++ b/esphome/components/uart/uart_component_esp32_arduino.cpp @@ -86,10 +86,26 @@ void ESP32ArduinoUARTComponent::setup() { is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 1; is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 3; #endif - if (is_default_tx && is_default_rx) { + static uint8_t next_uart_num = 0; + if (is_default_tx && is_default_rx && next_uart_num == 0) { this->hw_serial_ = &Serial; + next_uart_num++; } else { - static uint8_t next_uart_num = 1; +#ifdef USE_LOGGER + // The logger doesn't use this UART component, instead it targets the UARTs + // directly (i.e. Serial/Serial0, Serial1, and Serial2). If the logger is + // enabled, skip the UART that it is configured to use. + if (logger::global_logger->get_baud_rate() > 0 && logger::global_logger->get_uart() == next_uart_num) { + next_uart_num++; + } +#endif // USE_LOGGER + + if (next_uart_num >= UART_NUM_MAX) { + ESP_LOGW(TAG, "Maximum number of UART components created already."); + this->mark_failed(); + return; + } + this->number_ = next_uart_num; this->hw_serial_ = new HardwareSerial(next_uart_num++); // NOLINT(cppcoreguidelines-owning-memory) } diff --git a/esphome/components/uart/uart_component_esp32_arduino.h b/esphome/components/uart/uart_component_esp32_arduino.h index f85c709097..02dfd0531e 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.h +++ b/esphome/components/uart/uart_component_esp32_arduino.h @@ -2,6 +2,7 @@ #ifdef USE_ESP32_FRAMEWORK_ARDUINO +#include #include #include #include "esphome/core/component.h" From a4e63c5f86f3e007d20f7eff4bdcf4cd5549b74a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 23:13:17 +0000 Subject: [PATCH 0018/2607] Synchronise Device Classes from Home Assistant (#4825) Co-authored-by: esphomebot --- esphome/components/number/__init__.py | 2 ++ esphome/components/sensor/__init__.py | 2 ++ esphome/const.py | 1 + 3 files changed, 5 insertions(+) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index f532f4e405..73fbfd6e90 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -57,6 +57,7 @@ from esphome.const import ( DEVICE_CLASS_SULPHUR_DIOXIDE, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, @@ -109,6 +110,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_SULPHUR_DIOXIDE, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index f0a58d908c..06b96171a7 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -73,6 +73,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, @@ -129,6 +130,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, diff --git a/esphome/const.py b/esphome/const.py index 8cc689fa58..692325603c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1004,6 +1004,7 @@ DEVICE_CLASS_TIMESTAMP = "timestamp" DEVICE_CLASS_UPDATE = "update" DEVICE_CLASS_VIBRATION = "vibration" DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" +DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS = "volatile_organic_compounds_parts" DEVICE_CLASS_VOLTAGE = "voltage" DEVICE_CLASS_VOLUME = "volume" DEVICE_CLASS_VOLUME_STORAGE = "volume_storage" From 71c4714a6e5bfddc0d9584af921eeb901fd170f9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 May 2023 11:16:14 +1200 Subject: [PATCH 0019/2607] Bump version to 2023.5.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 692325603c..83b3425e7d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0b3" +__version__ = "2023.5.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From cc76e5353c360bcd63d798c77921e014a644c3d6 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 16 May 2023 04:36:02 -0700 Subject: [PATCH 0020/2607] support sending keys to the collector (#4838) Co-authored-by: Samuel Sieb --- esphome/components/key_collector/__init__.py | 7 ++++--- esphome/components/key_collector/key_collector.cpp | 2 ++ esphome/components/key_collector/key_collector.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/components/key_collector/__init__.py b/esphome/components/key_collector/__init__.py index 2099e28109..fd142b3cd7 100644 --- a/esphome/components/key_collector/__init__.py +++ b/esphome/components/key_collector/__init__.py @@ -33,7 +33,7 @@ CONFIG_SCHEMA = cv.All( cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(KeyCollector), - cv.GenerateID(CONF_SOURCE_ID): cv.use_id(key_provider.KeyProvider), + cv.Optional(CONF_SOURCE_ID): cv.use_id(key_provider.KeyProvider), cv.Optional(CONF_MIN_LENGTH): cv.int_, cv.Optional(CONF_MAX_LENGTH): cv.int_, cv.Optional(CONF_START_KEYS): cv.string, @@ -55,8 +55,9 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - source = await cg.get_variable(config[CONF_SOURCE_ID]) - cg.add(var.set_provider(source)) + if CONF_SOURCE_ID in config: + source = await cg.get_variable(config[CONF_SOURCE_ID]) + cg.add(var.set_provider(source)) if CONF_MIN_LENGTH in config: cg.add(var.set_min_length(config[CONF_MIN_LENGTH])) if CONF_MAX_LENGTH in config: diff --git a/esphome/components/key_collector/key_collector.cpp b/esphome/components/key_collector/key_collector.cpp index a9213890ee..bf2333d97d 100644 --- a/esphome/components/key_collector/key_collector.cpp +++ b/esphome/components/key_collector/key_collector.cpp @@ -52,6 +52,8 @@ void KeyCollector::clear(bool progress_update) { this->progress_trigger_->trigger(this->result_, 0); } +void KeyCollector::send_key(uint8_t key) { this->key_pressed_(key); } + void KeyCollector::key_pressed_(uint8_t key) { this->last_key_time_ = millis(); if (!this->start_keys_.empty() && !this->start_key_) { diff --git a/esphome/components/key_collector/key_collector.h b/esphome/components/key_collector/key_collector.h index 5e63397839..7ef53929ef 100644 --- a/esphome/components/key_collector/key_collector.h +++ b/esphome/components/key_collector/key_collector.h @@ -27,6 +27,7 @@ class KeyCollector : public Component { void set_timeout(int timeout) { this->timeout_ = timeout; }; void clear(bool progress_update = true); + void send_key(uint8_t key); protected: void key_pressed_(uint8_t key); From c941bc4109a4fc7c1ae9553e48907c295ef7491a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 16 May 2023 14:30:14 -0700 Subject: [PATCH 0021/2607] handle Wiegand 8-bit keys (#4837) Co-authored-by: Samuel Sieb --- esphome/components/wiegand/wiegand.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esphome/components/wiegand/wiegand.cpp b/esphome/components/wiegand/wiegand.cpp index c4e834c85a..10c77a8aa2 100644 --- a/esphome/components/wiegand/wiegand.cpp +++ b/esphome/components/wiegand/wiegand.cpp @@ -102,6 +102,16 @@ void Wiegand::loop() { uint8_t key = KEYS[value]; this->send_key_(key); } + } else if (count == 8) { + if ((value ^ 0xf0) >> 4 == (value & 0xf)) { + value &= 0xf; + for (auto *trigger : this->key_triggers_) + trigger->trigger(value); + if (value < 12) { + uint8_t key = KEYS[value]; + this->send_key_(key); + } + } } else { ESP_LOGD(TAG, "received unknown %d-bit value: %llx", count, value); } From 3c371a0c59c08f5e2774711e3c0f3fc627271fbe Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 May 2023 09:57:36 +1200 Subject: [PATCH 0022/2607] Bump version to 2023.5.0b5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 83b3425e7d..c1b35aafff 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0b4" +__version__ = "2023.5.0b5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 726bdd7be2ed38cf9536f1caf4d61615778c8c36 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 May 2023 12:45:42 +1200 Subject: [PATCH 0023/2607] Bump version to 2023.5.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c1b35aafff..c22cf9acca 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0b5" +__version__ = "2023.5.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From bfaad1f28de907922fbc3cef43f44f417744383a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 18 May 2023 11:34:18 +1200 Subject: [PATCH 0024/2607] Remove i2c dependency from ttp229_bsf (#4851) --- esphome/components/ttp229_bsf/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/ttp229_bsf/__init__.py b/esphome/components/ttp229_bsf/__init__.py index f1f86c929e..9c8208df83 100644 --- a/esphome/components/ttp229_bsf/__init__.py +++ b/esphome/components/ttp229_bsf/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import pins from esphome.const import CONF_ID, CONF_SDO_PIN, CONF_SCL_PIN -DEPENDENCIES = ["i2c"] AUTO_LOAD = ["binary_sensor"] CONF_TTP229_ID = "ttp229_id" From 9bf946e1962bbb7e43bcf809d1e8584a988bb7aa Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 17 May 2023 18:36:52 -0500 Subject: [PATCH 0025/2607] Sprinkler fixes (#4816) --- esphome/components/sprinkler/__init__.py | 140 ++++++++++----------- esphome/components/sprinkler/sprinkler.cpp | 126 +++++++++++++------ esphome/components/sprinkler/sprinkler.h | 12 +- 3 files changed, 162 insertions(+), 116 deletions(-) diff --git a/esphome/components/sprinkler/__init__.py b/esphome/components/sprinkler/__init__.py index 5097abc7e7..e1d855778a 100644 --- a/esphome/components/sprinkler/__init__.py +++ b/esphome/components/sprinkler/__init__.py @@ -599,15 +599,6 @@ async def to_code(config): ) cg.add(var.set_controller_auto_adv_switch(sw_aa_var)) - if CONF_QUEUE_ENABLE_SWITCH in sprinkler_controller: - sw_qen_var = await switch.new_switch( - sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] - ) - await cg.register_component( - sw_qen_var, sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] - ) - cg.add(var.set_controller_queue_enable_switch(sw_qen_var)) - if CONF_REVERSE_SWITCH in sprinkler_controller: sw_rev_var = await switch.new_switch( sprinkler_controller[CONF_REVERSE_SWITCH] @@ -617,78 +608,83 @@ async def to_code(config): ) cg.add(var.set_controller_reverse_switch(sw_rev_var)) - if CONF_STANDBY_SWITCH in sprinkler_controller: - sw_stb_var = await switch.new_switch( - sprinkler_controller[CONF_STANDBY_SWITCH] - ) - await cg.register_component( - sw_stb_var, sprinkler_controller[CONF_STANDBY_SWITCH] - ) - cg.add(var.set_controller_standby_switch(sw_stb_var)) + if CONF_STANDBY_SWITCH in sprinkler_controller: + sw_stb_var = await switch.new_switch( + sprinkler_controller[CONF_STANDBY_SWITCH] + ) + await cg.register_component( + sw_stb_var, sprinkler_controller[CONF_STANDBY_SWITCH] + ) + cg.add(var.set_controller_standby_switch(sw_stb_var)) - if CONF_MULTIPLIER_NUMBER in sprinkler_controller: - num_mult_var = await number.new_number( - sprinkler_controller[CONF_MULTIPLIER_NUMBER], - min_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][ - CONF_MIN_VALUE - ], - max_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][ - CONF_MAX_VALUE - ], - step=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_STEP], + if CONF_QUEUE_ENABLE_SWITCH in sprinkler_controller: + sw_qen_var = await switch.new_switch( + sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] + ) + await cg.register_component( + sw_qen_var, sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] + ) + cg.add(var.set_controller_queue_enable_switch(sw_qen_var)) + + if CONF_MULTIPLIER_NUMBER in sprinkler_controller: + num_mult_var = await number.new_number( + sprinkler_controller[CONF_MULTIPLIER_NUMBER], + min_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_MIN_VALUE], + max_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_MAX_VALUE], + step=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_STEP], + ) + await cg.register_component( + num_mult_var, sprinkler_controller[CONF_MULTIPLIER_NUMBER] + ) + cg.add( + num_mult_var.set_initial_value( + sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_INITIAL_VALUE] ) - await cg.register_component( - num_mult_var, sprinkler_controller[CONF_MULTIPLIER_NUMBER] + ) + cg.add( + num_mult_var.set_restore_value( + sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_RESTORE_VALUE] ) - cg.add( - num_mult_var.set_initial_value( - sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_INITIAL_VALUE] - ) - ) - cg.add( - num_mult_var.set_restore_value( - sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_RESTORE_VALUE] - ) + ) + + if CONF_SET_ACTION in sprinkler_controller[CONF_MULTIPLIER_NUMBER]: + await automation.build_automation( + num_mult_var.get_set_trigger(), + [(float, "x")], + sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_SET_ACTION], ) - if CONF_SET_ACTION in sprinkler_controller[CONF_MULTIPLIER_NUMBER]: - await automation.build_automation( - num_mult_var.get_set_trigger(), - [(float, "x")], - sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_SET_ACTION], - ) + cg.add(var.set_controller_multiplier_number(num_mult_var)) - cg.add(var.set_controller_multiplier_number(num_mult_var)) + if CONF_REPEAT_NUMBER in sprinkler_controller: + num_repeat_var = await number.new_number( + sprinkler_controller[CONF_REPEAT_NUMBER], + min_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MIN_VALUE], + max_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MAX_VALUE], + step=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_STEP], + ) + await cg.register_component( + num_repeat_var, sprinkler_controller[CONF_REPEAT_NUMBER] + ) + cg.add( + num_repeat_var.set_initial_value( + sprinkler_controller[CONF_REPEAT_NUMBER][CONF_INITIAL_VALUE] + ) + ) + cg.add( + num_repeat_var.set_restore_value( + sprinkler_controller[CONF_REPEAT_NUMBER][CONF_RESTORE_VALUE] + ) + ) - if CONF_REPEAT_NUMBER in sprinkler_controller: - num_repeat_var = await number.new_number( - sprinkler_controller[CONF_REPEAT_NUMBER], - min_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MIN_VALUE], - max_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MAX_VALUE], - step=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_STEP], - ) - await cg.register_component( - num_repeat_var, sprinkler_controller[CONF_REPEAT_NUMBER] - ) - cg.add( - num_repeat_var.set_initial_value( - sprinkler_controller[CONF_REPEAT_NUMBER][CONF_INITIAL_VALUE] - ) - ) - cg.add( - num_repeat_var.set_restore_value( - sprinkler_controller[CONF_REPEAT_NUMBER][CONF_RESTORE_VALUE] - ) + if CONF_SET_ACTION in sprinkler_controller[CONF_REPEAT_NUMBER]: + await automation.build_automation( + num_repeat_var.get_set_trigger(), + [(float, "x")], + sprinkler_controller[CONF_REPEAT_NUMBER][CONF_SET_ACTION], ) - if CONF_SET_ACTION in sprinkler_controller[CONF_REPEAT_NUMBER]: - await automation.build_automation( - num_repeat_var.get_set_trigger(), - [(float, "x")], - sprinkler_controller[CONF_REPEAT_NUMBER][CONF_SET_ACTION], - ) - - cg.add(var.set_controller_repeat_number(num_repeat_var)) + cg.add(var.set_controller_repeat_number(num_repeat_var)) for valve in sprinkler_controller[CONF_VALVES]: sw_valve_var = await switch.new_switch(valve[CONF_VALVE_SWITCH]) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 52a6cd2af4..095884997c 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -147,22 +147,22 @@ SprinklerValveOperator::SprinklerValveOperator(SprinklerValve *valve, Sprinkler : controller_(controller), valve_(valve) {} void SprinklerValveOperator::loop() { - if (millis() >= this->pinned_millis_) { // dummy check + if (millis() >= this->start_millis_) { // dummy check switch (this->state_) { case STARTING: - if (millis() > (this->pinned_millis_ + this->start_delay_)) { + if (millis() > (this->start_millis_ + this->start_delay_)) { this->run_(); // start_delay_ has been exceeded, so ensure both valves are on and update the state } break; case ACTIVE: - if (millis() > (this->pinned_millis_ + this->start_delay_ + this->run_duration_)) { + if (millis() > (this->start_millis_ + this->start_delay_ + this->run_duration_)) { this->stop(); // start_delay_ + run_duration_ has been exceeded, start shutting down } break; case STOPPING: - if (millis() > (this->pinned_millis_ + this->stop_delay_)) { + if (millis() > (this->stop_millis_ + this->stop_delay_)) { this->kill_(); // stop_delay_has been exceeded, ensure all valves are off } break; @@ -183,11 +183,12 @@ void SprinklerValveOperator::set_controller(Sprinkler *controller) { void SprinklerValveOperator::set_valve(SprinklerValve *valve) { if (valve != nullptr) { - this->state_ = IDLE; // reset state - this->run_duration_ = 0; // reset to ensure the valve isn't started without updating it - this->pinned_millis_ = 0; // reset because (new) valve has not been started yet - this->kill_(); // ensure everything is off before we let go! - this->valve_ = valve; // finally, set the pointer to the new valve + this->state_ = IDLE; // reset state + this->run_duration_ = 0; // reset to ensure the valve isn't started without updating it + this->start_millis_ = 0; // reset because (new) valve has not been started yet + this->stop_millis_ = 0; // reset because (new) valve has not been started yet + this->kill_(); // ensure everything is off before we let go! + this->valve_ = valve; // finally, set the pointer to the new valve } } @@ -221,7 +222,8 @@ void SprinklerValveOperator::start() { } else { this->run_(); // there is no start_delay_, so just start the pump and valve } - this->pinned_millis_ = millis(); // save the time the start request was made + this->stop_millis_ = 0; + this->start_millis_ = millis(); // save the time the start request was made } void SprinklerValveOperator::stop() { @@ -238,19 +240,33 @@ void SprinklerValveOperator::stop() { if (this->pump_switch()->state()) { // if the pump is still on at this point, it may be in use... this->valve_off_(); // ...so just switch the valve off now to ensure consistent run time } - this->pinned_millis_ = millis(); // save the time the stop request was made } else { this->kill_(); // there is no stop_delay_, so just stop the pump and valve } + this->stop_millis_ = millis(); // save the time the stop request was made } -uint32_t SprinklerValveOperator::run_duration() { return this->run_duration_; } +uint32_t SprinklerValveOperator::run_duration() { return this->run_duration_ / 1000; } uint32_t SprinklerValveOperator::time_remaining() { - if ((this->state_ == STARTING) || (this->state_ == ACTIVE)) { - return (this->pinned_millis_ + this->start_delay_ + this->run_duration_ - millis()) / 1000; + if (this->start_millis_ == 0) { + return this->run_duration(); // hasn't been started yet } - return 0; + + if (this->stop_millis_) { + if (this->stop_millis_ - this->start_millis_ >= this->start_delay_ + this->run_duration_) { + return 0; // valve was active for more than its configured duration, so we are done + } else { + // we're stopped; return time remaining + return (this->run_duration_ - (this->stop_millis_ - this->start_millis_)) / 1000; + } + } + + auto completed_millis = this->start_millis_ + this->start_delay_ + this->run_duration_; + if (completed_millis > millis()) { + return (completed_millis - millis()) / 1000; // running now + } + return 0; // run completed } SprinklerState SprinklerValveOperator::state() { return this->state_; } @@ -386,6 +402,9 @@ void Sprinkler::loop() { for (auto &vo : this->valve_op_) { vo.loop(); } + if (this->prev_req_.has_request() && this->prev_req_.valve_operator()->state() == IDLE) { + this->prev_req_.reset(); + } } void Sprinkler::add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControllerSwitch *enable_sw) { @@ -732,7 +751,7 @@ bool Sprinkler::auto_advance() { if (this->auto_adv_sw_ != nullptr) { return this->auto_adv_sw_->state; } - return false; + return true; } float Sprinkler::multiplier() { @@ -972,7 +991,14 @@ optional Sprinkler::active_valve_request_is_from return nullopt; } -optional Sprinkler::active_valve() { return this->active_req_.valve_as_opt(); } +optional Sprinkler::active_valve() { + if (!this->valve_overlap_ && this->prev_req_.has_request() && + (this->prev_req_.valve_operator()->state() == STARTING || this->prev_req_.valve_operator()->state() == ACTIVE)) { + return this->prev_req_.valve_as_opt(); + } + return this->active_req_.valve_as_opt(); +} + optional Sprinkler::paused_valve() { return this->paused_valve_; } optional Sprinkler::queued_valve() { @@ -1097,22 +1123,35 @@ uint32_t Sprinkler::total_cycle_time_enabled_valves() { uint32_t Sprinkler::total_cycle_time_enabled_incomplete_valves() { uint32_t total_time_remaining = 0; - uint32_t valve_count = 0; + uint32_t enabled_valve_count = 0; + uint32_t incomplete_valve_count = 0; for (size_t valve = 0; valve < this->number_of_valves(); valve++) { - if (this->valve_is_enabled_(valve) && !this->valve_cycle_complete_(valve)) { - if (!this->active_valve().has_value() || (valve != this->active_valve().value())) { - total_time_remaining += this->valve_run_duration_adjusted(valve); - valve_count++; + if (this->valve_is_enabled_(valve)) { + enabled_valve_count++; + if (!this->valve_cycle_complete_(valve)) { + if (!this->active_valve().has_value() || (valve != this->active_valve().value())) { + total_time_remaining += this->valve_run_duration_adjusted(valve); + incomplete_valve_count++; + } else { + // to get here, there must be an active valve and this valve must be equal to 'valve' + if (this->active_req_.valve_operator() == nullptr) { // no SVO has been assigned yet so it hasn't started + total_time_remaining += this->valve_run_duration_adjusted(valve); + incomplete_valve_count++; + } + } } } } - if (valve_count) { + if (incomplete_valve_count >= enabled_valve_count) { + incomplete_valve_count--; + } + if (incomplete_valve_count) { if (this->valve_overlap_) { - total_time_remaining -= this->switching_delay_.value_or(0) * (valve_count - 1); + total_time_remaining -= this->switching_delay_.value_or(0) * incomplete_valve_count; } else { - total_time_remaining += this->switching_delay_.value_or(0) * (valve_count - 1); + total_time_remaining += this->switching_delay_.value_or(0) * incomplete_valve_count; } } @@ -1149,31 +1188,32 @@ optional Sprinkler::time_remaining_active_valve() { return this->active_req_.valve_operator()->time_remaining(); } } - for (auto &vo : this->valve_op_) { // ...else return the value from the first non-IDLE SprinklerValveOperator - if (vo.state() != IDLE) { - return vo.time_remaining(); + if (this->prev_req_.has_request()) { // try to return the value based on prev_req_... + if (this->prev_req_.valve_operator() != nullptr) { + return this->prev_req_.valve_operator()->time_remaining(); } } return nullopt; } optional Sprinkler::time_remaining_current_operation() { - auto total_time_remaining = this->time_remaining_active_valve(); + if (!this->time_remaining_active_valve().has_value() && this->state_ == IDLE) { + return nullopt; + } - if (total_time_remaining.has_value()) { - if (this->auto_advance()) { - total_time_remaining = total_time_remaining.value() + this->total_cycle_time_enabled_incomplete_valves(); - total_time_remaining = - total_time_remaining.value() + + auto total_time_remaining = this->time_remaining_active_valve().value_or(0); + if (this->auto_advance()) { + total_time_remaining += this->total_cycle_time_enabled_incomplete_valves(); + if (this->repeat().value_or(0) > 0) { + total_time_remaining += (this->total_cycle_time_enabled_valves() * (this->repeat().value_or(0) - this->repeat_count().value_or(0))); } - - if (this->queue_enabled()) { - total_time_remaining = total_time_remaining.value() + this->total_queue_time(); - } - return total_time_remaining; } - return nullopt; + + if (this->queue_enabled()) { + total_time_remaining += this->total_queue_time(); + } + return total_time_remaining; } bool Sprinkler::any_controller_is_active() { @@ -1305,6 +1345,12 @@ optional Sprinkler::next_valve_number_in_cycle_(const optional f } void Sprinkler::load_next_valve_run_request_(const optional first_valve) { + if (this->active_req_.has_request()) { + this->prev_req_ = this->active_req_; + } else { + this->prev_req_.reset(); + } + if (this->next_req_.has_request()) { if (!this->next_req_.run_duration()) { // ensure the run duration is set correctly for consumption later on this->next_req_.set_run_duration(this->valve_run_duration_adjusted(this->next_req_.valve())); diff --git a/esphome/components/sprinkler/sprinkler.h b/esphome/components/sprinkler/sprinkler.h index 7a8285ae73..ae7554d3af 100644 --- a/esphome/components/sprinkler/sprinkler.h +++ b/esphome/components/sprinkler/sprinkler.h @@ -170,7 +170,8 @@ class SprinklerValveOperator { uint32_t start_delay_{0}; uint32_t stop_delay_{0}; uint32_t run_duration_{0}; - uint64_t pinned_millis_{0}; + uint64_t start_millis_{0}; + uint64_t stop_millis_{0}; Sprinkler *controller_{nullptr}; SprinklerValve *valve_{nullptr}; SprinklerState state_{IDLE}; @@ -538,15 +539,18 @@ class Sprinkler : public Component { /// The valve run request that is currently active SprinklerValveRunRequest active_req_; + /// The next run request for the controller to consume after active_req_ is complete + SprinklerValveRunRequest next_req_; + + /// The previous run request the controller processed + SprinklerValveRunRequest prev_req_; + /// The number of the manually selected valve currently selected optional manual_valve_; /// The number of the valve to resume from (if paused) optional paused_valve_; - /// The next run request for the controller to consume after active_req_ is complete - SprinklerValveRunRequest next_req_; - /// Set the number of times to repeat a full cycle optional target_repeats_; From f30f20db8645e0dc75a52b3b836e8c307e2408d0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 18 May 2023 13:00:37 +1200 Subject: [PATCH 0026/2607] Bump version to 2023.5.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c22cf9acca..93c0961561 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.0" +__version__ = "2023.5.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 2d3b48f86f98f5de828495c415281e62d832e7d3 Mon Sep 17 00:00:00 2001 From: Stefan Rado Date: Sun, 21 May 2023 22:10:23 +0200 Subject: [PATCH 0027/2607] Fix i2s_audio media_player mutex acquisition (#4867) Co-authored-by: Rajan Patel --- .../i2s_audio/media_player/i2s_audio_media_player.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 4de1136987..6eaa32c23c 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -133,7 +133,7 @@ void I2SAudioMediaPlayer::play_() { void I2SAudioMediaPlayer::start() { this->i2s_state_ = I2S_STATE_STARTING; } void I2SAudioMediaPlayer::start_() { - if (this->parent_->try_lock()) { + if (!this->parent_->try_lock()) { return; // Waiting for another i2s to return lock } @@ -156,6 +156,7 @@ void I2SAudioMediaPlayer::start_() { #if SOC_I2S_SUPPORTS_DAC } #endif + this->i2s_state_ = I2S_STATE_RUNNING; this->high_freq_.start(); this->audio_->setVolume(remap(this->volume, 0.0f, 1.0f, 0, 21)); @@ -218,6 +219,12 @@ void I2SAudioMediaPlayer::dump_config() { default: break; } + } else { +#endif + ESP_LOGCONFIG(TAG, " External DAC channels: %d", this->external_dac_channels_); + ESP_LOGCONFIG(TAG, " I2S DOUT Pin: %d", this->dout_pin_); + LOG_PIN(" Mute Pin: ", this->mute_pin_); +#if SOC_I2S_SUPPORTS_DAC } #endif } From 8fcec8e2cbaff5a225170dd9ffcd0193b3f00435 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 22 May 2023 11:31:30 +1200 Subject: [PATCH 0028/2607] Bump version to 2023.5.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 93c0961561..1e2218b0da 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.1" +__version__ = "2023.5.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 148eb03d1336d6aad46d52464a7280e86ca4c3b7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 May 2023 07:02:16 +1200 Subject: [PATCH 0029/2607] Allow microphone channel to be specified in config (#4871) --- esphome/components/i2s_audio/microphone/__init__.py | 11 ++++++++++- .../i2s_audio/microphone/i2s_audio_microphone.cpp | 2 +- .../i2s_audio/microphone/i2s_audio_microphone.h | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index 48d4d28f8e..089e796ae0 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -2,7 +2,7 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome import pins -from esphome.const import CONF_ID, CONF_NUMBER +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER from esphome.components import microphone, esp32 from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin @@ -25,6 +25,12 @@ I2SAudioMicrophone = i2s_audio_ns.class_( "I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component ) +i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t") +CHANNELS = { + "left": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, + "right": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, +} + INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32] PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3] @@ -47,6 +53,7 @@ BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(I2SAudioMicrophone), cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), + cv.Optional(CONF_CHANNEL, default="right"): cv.enum(CHANNELS), } ).extend(cv.COMPONENT_SCHEMA) @@ -86,4 +93,6 @@ async def to_code(config): cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) cg.add(var.set_pdm(config[CONF_PDM])) + cg.add(var.set_channel(CHANNELS[config[CONF_CHANNEL]])) + await microphone.register_microphone(var, config) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 0f45cf95c6..9452762e94 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -49,7 +49,7 @@ void I2SAudioMicrophone::start_() { .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = 16000, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, + .channel_format = this->channel_, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 4, diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index e704ed2915..acc7d2b45a 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -28,6 +28,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub } #endif + void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } + protected: void start_(); void stop_(); @@ -40,6 +42,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub #endif bool pdm_{false}; std::vector buffer_; + i2s_channel_fmt_t channel_; HighFrequencyLoopRequester high_freq_; }; From d2480d31946b5fa3e713ea583cd683003b6bf473 Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 22 May 2023 22:43:03 +0200 Subject: [PATCH 0030/2607] [PSRam] Change log unit to KB to minimize rounding error. (#4872) Co-authored-by: Your Name --- esphome/components/psram/psram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/psram/psram.cpp b/esphome/components/psram/psram.cpp index 8325709632..68d8dfd697 100644 --- a/esphome/components/psram/psram.cpp +++ b/esphome/components/psram/psram.cpp @@ -21,7 +21,7 @@ void PsramComponent::dump_config() { ESP_LOGCONFIG(TAG, " Available: %s", YESNO(available)); #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0) if (available) { - ESP_LOGCONFIG(TAG, " Size: %d MB", heap_caps_get_total_size(MALLOC_CAP_SPIRAM) / 1024 / 1024); + ESP_LOGCONFIG(TAG, " Size: %d KB", heap_caps_get_total_size(MALLOC_CAP_SPIRAM) / 1024); } #endif } From 9d2467cf62fc6ada43d0dc80cd9693f48e79de50 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 May 2023 16:53:10 -0500 Subject: [PATCH 0031/2607] Bump version to 2023.5.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 1e2218b0da..5304e9b65a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.2" +__version__ = "2023.5.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 19f91a7debafbb6bc54a80baef6edb0121d92664 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 23 May 2023 21:51:12 +0200 Subject: [PATCH 0032/2607] [internal_temperature] ESP32-S3 needs ESP IDF V4.4.3 or higher (#4873) Co-authored-by: Your Name --- .../internal_temperature.cpp | 4 +++ .../components/internal_temperature/sensor.py | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index 9a22a77f63..a387708263 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -33,6 +33,10 @@ void InternalTemperatureSensor::update() { temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT(); temp_sensor_set_config(tsens); temp_sensor_start(); +#if defined(USE_ESP32_VARIANT_ESP32S3) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 3)) +#error \ + "ESP32-S3 internal temperature sensor requires ESP IDF V4.4.3 or higher. See https://github.com/esphome/issues/issues/4271" +#endif esp_err_t result = temp_sensor_read_celsius(&temperature); temp_sensor_stop(); success = (result == ESP_OK); diff --git a/esphome/components/internal_temperature/sensor.py b/esphome/components/internal_temperature/sensor.py index 2655711bb5..8d462bd801 100644 --- a/esphome/components/internal_temperature/sensor.py +++ b/esphome/components/internal_temperature/sensor.py @@ -1,18 +1,45 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor +from esphome.components.esp32 import get_esp32_variant +from esphome.components.esp32.const import ( + VARIANT_ESP32S3, +) from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, DEVICE_CLASS_TEMPERATURE, ENTITY_CATEGORY_DIAGNOSTIC, + KEY_CORE, + KEY_FRAMEWORK_VERSION, ) +from esphome.core import CORE internal_temperature_ns = cg.esphome_ns.namespace("internal_temperature") InternalTemperatureSensor = internal_temperature_ns.class_( "InternalTemperatureSensor", sensor.Sensor, cg.PollingComponent ) + +def validate_config(config): + if CORE.is_esp32: + variant = get_esp32_variant() + if variant == VARIANT_ESP32S3: + if CORE.using_arduino and CORE.data[KEY_CORE][ + KEY_FRAMEWORK_VERSION + ] < cv.Version(2, 0, 6): + raise cv.Invalid( + "ESP32-S3 Internal Temperature Sensor requires framework version 2.0.6 or higher. See ." + ) + if CORE.using_esp_idf and CORE.data[KEY_CORE][ + KEY_FRAMEWORK_VERSION + ] < cv.Version(4, 4, 3): + raise cv.Invalid( + "ESP32-S3 Internal Temperature Sensor requires framework version 4.4.3 or higher. See ." + ) + return config + + CONFIG_SCHEMA = cv.All( sensor.sensor_schema( InternalTemperatureSensor, @@ -23,6 +50,7 @@ CONFIG_SCHEMA = cv.All( entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ).extend(cv.polling_component_schema("60s")), cv.only_on(["esp32", "rp2040"]), + validate_config, ) From fb4cb07c6fe20adce221bf991748df477dd9421c Mon Sep 17 00:00:00 2001 From: Davrosx <75336029+Davrosx@users.noreply.github.com> Date: Tue, 23 May 2023 20:52:34 +0100 Subject: [PATCH 0033/2607] Update cover.h for compile errors with stop() (#4879) --- esphome/components/cover/cover.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index d21fbe02be..89598a9636 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -140,8 +140,9 @@ class Cover : public EntityBase, public EntityBase_DeviceClass { /** Stop the cover. * * This is a legacy method and may be removed later, please use `.make_call()` instead. + * As per solution from issue #2885 the call should include perform() */ - ESPDEPRECATED("stop() is deprecated, use make_call().set_command_stop() instead.", "2021.9") + ESPDEPRECATED("stop() is deprecated, use make_call().set_command_stop().perform() instead.", "2021.9") void stop(); void add_on_state_callback(std::function &&f); From 7d2ae4e25248a2d11888281e81dd4372ba11d077 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 24 May 2023 09:56:15 +1200 Subject: [PATCH 0034/2607] Print ESPHome version when running commands (#4883) --- esphome/__main__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/__main__.py b/esphome/__main__.py index 78320a05f0..85f7106e3f 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -932,6 +932,8 @@ def run_esphome(argv): _LOGGER.error(e, exc_info=args.verbose) return 1 + safe_print(f"ESPHome {const.__version__}") + for conf_path in args.configuration: if any(os.path.basename(conf_path) == x for x in SECRETS_FILES): _LOGGER.warning("Skipping secrets file %s", conf_path) From 6e414180e0d411ec88211650ec19914b85b76ec8 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 23 May 2023 15:00:33 -0700 Subject: [PATCH 0035/2607] fix modbus sending FP32_R values (#4882) --- esphome/components/modbus_controller/modbus_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 57f714f233..79c13e3f68 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -506,12 +506,12 @@ void number_to_payload(std::vector &data, int64_t value, SensorValueTy case SensorValueType::U_DWORD: case SensorValueType::S_DWORD: case SensorValueType::FP32: - case SensorValueType::FP32_R: data.push_back((value & 0xFFFF0000) >> 16); data.push_back(value & 0xFFFF); break; case SensorValueType::U_DWORD_R: case SensorValueType::S_DWORD_R: + case SensorValueType::FP32_R: data.push_back(value & 0xFFFF); data.push_back((value & 0xFFFF0000) >> 16); break; From 91ff502872bd86e3dd5d19733c54fb1236fe53b7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 24 May 2023 19:20:06 +1200 Subject: [PATCH 0036/2607] Fix esp32_rmt_led_strip color modes (#4886) --- esphome/components/esp32_rmt_led_strip/led_strip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index 508f784ec8..11d61b07e1 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -34,7 +34,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { light::LightTraits get_traits() override { auto traits = light::LightTraits(); if (this->is_rgbw_) { - traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::RGB_WHITE}); + traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE}); } else { traits.set_supported_color_modes({light::ColorMode::RGB}); } From 316171491f78842dc342cd3da07c6226ccbc7608 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 24 May 2023 15:58:54 -0500 Subject: [PATCH 0037/2607] Bump version to 2023.5.4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5304e9b65a..0fe9ce18a4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.3" +__version__ = "2023.5.4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 71387846dc201400ae4a476bb2aac55327554d70 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 28 May 2023 13:49:27 -0700 Subject: [PATCH 0038/2607] move pio tools to LED component (#4903) --- esphome/components/rp2040/__init__.py | 1 - .../components/rp2040_pio_led_strip/light.py | 6 ++++ tests/test6.yaml | 36 +++++++++---------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 1eba0bf192..ad66ce6d18 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -157,7 +157,6 @@ async def to_code(config): "platform_packages", [ f"earlephilhower/framework-arduinopico@{conf[CONF_SOURCE]}", - "earlephilhower/tool-pioasm-rp2040-earlephilhower", ], ) diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index 432ff6935a..a2ba72318f 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -265,3 +265,9 @@ async def to_code(config): time_to_cycles(config[CONF_BIT1_LOW]), ), ) + cg.add_platformio_option( + "platform_packages", + [ + "earlephilhower/tool-pioasm-rp2040-earlephilhower", + ], + ) diff --git a/tests/test6.yaml b/tests/test6.yaml index 6d956aa9c8..6224563a77 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -37,24 +37,24 @@ switch: output: pin_4 id: pin_4_switch -light: - - platform: rp2040_pio_led_strip - id: led_strip - pin: GPIO13 - num_leds: 60 - pio: 0 - rgb_order: GRB - chipset: WS2812 - - platform: rp2040_pio_led_strip - id: led_strip_custom_timings - pin: GPIO13 - num_leds: 60 - pio: 1 - rgb_order: GRB - bit0_high: .1us - bit0_low: 1.2us - bit1_high: .69us - bit1_low: .4us +#light: +# - platform: rp2040_pio_led_strip +# id: led_strip +# pin: GPIO13 +# num_leds: 60 +# pio: 0 +# rgb_order: GRB +# chipset: WS2812 +# - platform: rp2040_pio_led_strip +# id: led_strip_custom_timings +# pin: GPIO13 +# num_leds: 60 +# pio: 1 +# rgb_order: GRB +# bit0_high: .1us +# bit0_low: 1.2us +# bit1_high: .69us +# bit1_low: .4us sensor: From ebad40758674a0f2533053708cc6ae143f78692b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 May 2023 09:18:01 +1200 Subject: [PATCH 0039/2607] Fix version printing not breaking yaml parsing (#4904) --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 603a06bdd2..c7c83ad83b 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -980,7 +980,7 @@ def run_esphome(argv): _LOGGER.error(e, exc_info=args.verbose) return 1 - safe_print(f"ESPHome {const.__version__}") + _LOGGER.info("ESPHome %s", const.__version__) for conf_path in args.configuration: if any(os.path.basename(conf_path) == x for x in SECRETS_FILES): From 69f5674d9e3c9b34e7ed818232ade99fc1b79fde Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 May 2023 09:18:01 +1200 Subject: [PATCH 0040/2607] Fix version printing not breaking yaml parsing (#4904) --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 85f7106e3f..11a363691f 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -932,7 +932,7 @@ def run_esphome(argv): _LOGGER.error(e, exc_info=args.verbose) return 1 - safe_print(f"ESPHome {const.__version__}") + _LOGGER.info("ESPHome %s", const.__version__) for conf_path in args.configuration: if any(os.path.basename(conf_path) == x for x in SECRETS_FILES): From 1057ac4db75a96bd6b7e194e200d520d84e6c583 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 May 2023 09:42:12 +1200 Subject: [PATCH 0041/2607] Bump version to 2023.5.5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 0fe9ce18a4..fce8ab9f1c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.5.4" +__version__ = "2023.5.5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From 57023457ee08625ac96d13272fd9a398f3aa901e Mon Sep 17 00:00:00 2001 From: Regev Brody Date: Mon, 29 May 2023 00:44:05 +0300 Subject: [PATCH 0042/2607] add SUB_SELECT macro (#4897) --- esphome/components/select/select.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/components/select/select.h b/esphome/components/select/select.h index 23258d5785..8ca9a69d1c 100644 --- a/esphome/components/select/select.h +++ b/esphome/components/select/select.h @@ -17,6 +17,13 @@ namespace select { } \ } +#define SUB_SELECT(name) \ + protected: \ + select::Select *name##_select_{nullptr}; \ +\ + public: \ + void set_##name##_select(select::Select *select) { this->name##_select_ = select; } + /** Base-class for all selects. * * A select can use publish_state to send out a new value. From 7dcdf80f4929260471db944012522a14905497c6 Mon Sep 17 00:00:00 2001 From: Regev Brody Date: Mon, 29 May 2023 00:44:35 +0300 Subject: [PATCH 0043/2607] add SUB_SWITCH macro (#4898) --- esphome/components/switch/switch.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/components/switch/switch.h b/esphome/components/switch/switch.h index 9daac4ee23..b5395a2c83 100644 --- a/esphome/components/switch/switch.h +++ b/esphome/components/switch/switch.h @@ -8,6 +8,13 @@ namespace esphome { namespace switch_ { +#define SUB_SWITCH(name) \ + protected: \ + switch_::Switch *name##_switch_{nullptr}; \ +\ + public: \ + void set_##name##_switch(switch_::Switch *s) { this->name##_switch_ = s; } + // bit0: on/off. bit1: persistent. bit2: inverted. bit3: disabled const int RESTORE_MODE_ON_MASK = 0x01; const int RESTORE_MODE_PERSISTENT_MASK = 0x02; From 796b64541f34d84699adc025e5dcd680234e39ae Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Tue, 30 May 2023 02:07:36 +0300 Subject: [PATCH 0044/2607] esp32_rmt_led_strip: fix compile with ESP-IDF >= 5 (#4856) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32_rmt_led_strip/led_strip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index eec1bdc992..df6ee2ce2f 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -1,3 +1,4 @@ +#include #include "led_strip.h" #ifdef USE_ESP32 @@ -195,7 +196,7 @@ void ESP32RMTLEDStripLightOutput::dump_config() { break; } ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order); - ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_); + ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_); ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_); } From 8adb7dc97cdc3c43e4ca9678823603b659d4719f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 09:05:40 +1200 Subject: [PATCH 0045/2607] Bump aioesphomeapi from 13.7.5 to 13.9.0 (#4907) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2b5b2c7e1f..9fa93e44fe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.5.1 click==8.1.3 esphome-dashboard==20230516.0 -aioesphomeapi==13.7.5 +aioesphomeapi==13.9.0 zeroconf==0.62.0 # esp-idf requires this, but doesn't bundle it by default From ccba94197d2c55e90727e2624e4cc81ccc6e9638 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Wed, 31 May 2023 04:47:11 +0300 Subject: [PATCH 0046/2607] ota: fix compile with ESP-IDF >= 5 (#4857) --- esphome/components/ota/ota_component.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index 39ba3dbed4..acf9e923b6 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -99,7 +99,7 @@ void OTAComponent::dump_config() { #endif if (this->has_safe_mode_ && this->safe_mode_rtc_value_ > 1 && this->safe_mode_rtc_value_ != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %d restarts", + ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %" PRIu32 " restarts", this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_); } } @@ -191,7 +191,7 @@ void OTAComponent::handle_() { this->writeall_(buf, 1); md5::MD5Digest md5{}; md5.init(); - sprintf(sbuf, "%08X", random_uint32()); + sprintf(sbuf, "%08" PRIx32, random_uint32()); md5.add(sbuf, 8); md5.calculate(); md5.get_hex(sbuf); @@ -466,7 +466,7 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_ if (is_manual_safe_mode) { ESP_LOGI(TAG, "Safe mode has been entered manually"); } else { - ESP_LOGCONFIG(TAG, "There have been %u suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_); + ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_); } if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) { From 3ead48f0db16e1c98f5995bb00bb478d40c03fd3 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Wed, 31 May 2023 04:48:34 +0300 Subject: [PATCH 0047/2607] ota: fix TWDT with ESP-IDF >= 5 (#4858) --- esphome/components/ota/ota_backend_esp_idf.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp index 7688629e39..319a1482f1 100644 --- a/esphome/components/ota/ota_backend_esp_idf.cpp +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -21,25 +21,35 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION; } +#if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 // The following function takes longer than the 5 seconds timeout of WDT #if ESP_IDF_VERSION_MAJOR >= 5 esp_task_wdt_config_t wdtc; - wdtc.timeout_ms = 15000; wdtc.idle_core_mask = 0; +#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + wdtc.idle_core_mask |= (1 << 0); +#endif +#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + wdtc.idle_core_mask |= (1 << 1); +#endif + wdtc.timeout_ms = 15000; wdtc.trigger_panic = false; esp_task_wdt_reconfigure(&wdtc); #else esp_task_wdt_init(15, false); +#endif #endif esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); +#if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 // Set the WDT back to the configured timeout #if ESP_IDF_VERSION_MAJOR >= 5 - wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S; + wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; esp_task_wdt_reconfigure(&wdtc); #else esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); +#endif #endif if (err != ESP_OK) { From f9f335e692b14a9747392d9f94f2512d9b52a3dc Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Wed, 31 May 2023 04:49:31 +0300 Subject: [PATCH 0048/2607] light: fix compile with ESP-IDF >= 5 (#4855) --- esphome/components/light/light_call.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/light/light_call.cpp b/esphome/components/light/light_call.cpp index fb4e45b3b6..8dc5d4fbe7 100644 --- a/esphome/components/light/light_call.cpp +++ b/esphome/components/light/light_call.cpp @@ -1,3 +1,4 @@ +#include #include "light_call.h" #include "light_state.h" #include "esphome/core/log.h" @@ -283,7 +284,7 @@ LightColorValues LightCall::validate_() { // validate effect index if (this->has_effect_() && *this->effect_ > this->parent_->effects_.size()) { - ESP_LOGW(TAG, "'%s' - Invalid effect index %u!", name, *this->effect_); + ESP_LOGW(TAG, "'%s' - Invalid effect index %" PRIu32 "!", name, *this->effect_); this->effect_.reset(); } From 1ea5d90ea32fe9b8f4adf0e120cc3e260f290c34 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 31 May 2023 16:30:53 +1200 Subject: [PATCH 0049/2607] Continuous voice_assistant and silence detection (#4892) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_connection.cpp | 3 +- esphome/components/api/api_connection.h | 2 +- esphome/components/api/api_pb2.cpp | 19 +++++- esphome/components/api/api_pb2.h | 2 + esphome/components/api/api_server.cpp | 6 +- esphome/components/api/api_server.h | 2 +- .../i2s_audio/microphone/__init__.py | 2 +- .../components/voice_assistant/__init__.py | 49 ++++++++++++-- .../voice_assistant/voice_assistant.cpp | 67 ++++++++++++++++--- .../voice_assistant/voice_assistant.h | 47 ++++++++++++- esphome/const.py | 1 + 12 files changed, 176 insertions(+), 25 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 4cc98c91d9..34678fde0f 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1397,6 +1397,7 @@ message VoiceAssistantRequest { option (ifdef) = "USE_VOICE_ASSISTANT"; bool start = 1; + string conversation_id = 2; } message VoiceAssistantResponse { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index c350197e68..3983c6403b 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -895,11 +895,12 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ #endif #ifdef USE_VOICE_ASSISTANT -bool APIConnection::request_voice_assistant(bool start) { +bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id) { if (!this->voice_assistant_subscription_) return false; VoiceAssistantRequest msg; msg.start = start; + msg.conversation_id = conversation_id; return this->send_voice_assistant_request(msg); } void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 78ecbb98e6..d4e9cc656e 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -128,7 +128,7 @@ class APIConnection : public APIServerConnection { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { this->voice_assistant_subscription_ = msg.subscribe; } - bool request_voice_assistant(bool start); + bool request_voice_assistant(bool start, const std::string &conversation_id); void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 1dd8c82e00..29e8e207dd 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -6187,7 +6187,20 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) return false; } } -void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); } +bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->conversation_id = value.as_string(); + return true; + } + default: + return false; + } +} +void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_bool(1, this->start); + buffer.encode_string(2, this->conversation_id); +} #ifdef HAS_PROTO_MESSAGE_DUMP void VoiceAssistantRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; @@ -6195,6 +6208,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append(" start: "); out.append(YESNO(this->start)); out.append("\n"); + + out.append(" conversation_id: "); + out.append("'").append(this->conversation_id).append("'"); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 0f4b79de19..cd1cfb595a 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1604,12 +1604,14 @@ class SubscribeVoiceAssistantRequest : public ProtoMessage { class VoiceAssistantRequest : public ProtoMessage { public: bool start{false}; + std::string conversation_id{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; #endif protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class VoiceAssistantResponse : public ProtoMessage { diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 068f74315c..3dd47c4dd8 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -428,16 +428,16 @@ void APIServer::on_shutdown() { } #ifdef USE_VOICE_ASSISTANT -bool APIServer::start_voice_assistant() { +bool APIServer::start_voice_assistant(const std::string &conversation_id) { for (auto &c : this->clients_) { - if (c->request_voice_assistant(true)) + if (c->request_voice_assistant(true, conversation_id)) return true; } return false; } void APIServer::stop_voice_assistant() { for (auto &c : this->clients_) { - if (c->request_voice_assistant(false)) + if (c->request_voice_assistant(false, "")) return; } } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index a1bec2802f..79ba7b17f1 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -96,7 +96,7 @@ class APIServer : public Component, public Controller { #endif #ifdef USE_VOICE_ASSISTANT - bool start_voice_assistant(); + bool start_voice_assistant(const std::string &conversation_id); void stop_voice_assistant(); #endif diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index 07f5158188..b917da3045 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -62,7 +62,7 @@ BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( cv.GenerateID(): cv.declare_id(I2SAudioMicrophone), cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), cv.Optional(CONF_CHANNEL, default="right"): cv.enum(CHANNELS), - cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All( + cv.Optional(CONF_BITS_PER_SAMPLE, default="32bit"): cv.All( _validate_bits, cv.enum(BITS_PER_SAMPLE) ), } diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index 624fcdf52c..55d995be88 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -1,16 +1,23 @@ import esphome.config_validation as cv import esphome.codegen as cg -from esphome.const import CONF_ID, CONF_MICROPHONE, CONF_SPEAKER +from esphome.const import ( + CONF_ID, + CONF_MICROPHONE, + CONF_SPEAKER, + CONF_MEDIA_PLAYER, +) from esphome import automation -from esphome.automation import register_action -from esphome.components import microphone, speaker +from esphome.automation import register_action, register_condition +from esphome.components import microphone, speaker, media_player AUTO_LOAD = ["socket"] DEPENDENCIES = ["api", "microphone"] CODEOWNERS = ["@jesserockz"] +CONF_SILENCE_DETECTION = "silence_detection" +CONF_ON_LISTENING = "on_listening" CONF_ON_START = "on_start" CONF_ON_STT_END = "on_stt_end" CONF_ON_TTS_START = "on_tts_start" @@ -25,16 +32,25 @@ VoiceAssistant = voice_assistant_ns.class_("VoiceAssistant", cg.Component) StartAction = voice_assistant_ns.class_( "StartAction", automation.Action, cg.Parented.template(VoiceAssistant) ) +StartContinuousAction = voice_assistant_ns.class_( + "StartContinuousAction", automation.Action, cg.Parented.template(VoiceAssistant) +) StopAction = voice_assistant_ns.class_( "StopAction", automation.Action, cg.Parented.template(VoiceAssistant) ) +IsRunningCondition = voice_assistant_ns.class_( + "IsRunningCondition", automation.Condition, cg.Parented.template(VoiceAssistant) +) CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(VoiceAssistant), cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), - cv.Optional(CONF_SPEAKER): cv.use_id(speaker.Speaker), + cv.Exclusive(CONF_SPEAKER, "output"): cv.use_id(speaker.Speaker), + cv.Exclusive(CONF_MEDIA_PLAYER, "output"): cv.use_id(media_player.MediaPlayer), + cv.Optional(CONF_SILENCE_DETECTION, default=True): cv.boolean, + cv.Optional(CONF_ON_LISTENING): automation.validate_automation(single=True), cv.Optional(CONF_ON_START): automation.validate_automation(single=True), cv.Optional(CONF_ON_STT_END): automation.validate_automation(single=True), cv.Optional(CONF_ON_TTS_START): automation.validate_automation(single=True), @@ -56,6 +72,17 @@ async def to_code(config): spkr = await cg.get_variable(config[CONF_SPEAKER]) cg.add(var.set_speaker(spkr)) + if CONF_MEDIA_PLAYER in config: + mp = await cg.get_variable(config[CONF_MEDIA_PLAYER]) + cg.add(var.set_media_player(mp)) + + cg.add(var.set_silence_detection(config[CONF_SILENCE_DETECTION])) + + if CONF_ON_LISTENING in config: + await automation.build_automation( + var.get_listening_trigger(), [], config[CONF_ON_LISTENING] + ) + if CONF_ON_START in config: await automation.build_automation( var.get_start_trigger(), [], config[CONF_ON_START] @@ -96,6 +123,11 @@ async def to_code(config): VOICE_ASSISTANT_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(VoiceAssistant)}) +@register_action( + "voice_assistant.start_continuous", + StartContinuousAction, + VOICE_ASSISTANT_ACTION_SCHEMA, +) @register_action("voice_assistant.start", StartAction, VOICE_ASSISTANT_ACTION_SCHEMA) async def voice_assistant_listen_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) @@ -108,3 +140,12 @@ async def voice_assistant_stop_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) return var + + +@register_condition( + "voice_assistant.is_running", IsRunningCondition, VOICE_ASSISTANT_ACTION_SCHEMA +) +async def voice_assistant_is_running_to_code(config, condition_id, template_arg, args): + var = cg.new_Pvariable(condition_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 4245578711..44d640ff39 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -69,17 +69,42 @@ void VoiceAssistant::setup() { void VoiceAssistant::loop() { #ifdef USE_SPEAKER - if (this->speaker_ == nullptr) { + if (this->speaker_ != nullptr) { + uint8_t buf[1024]; + auto len = this->socket_->read(buf, sizeof(buf)); + if (len == -1) { + return; + } + this->speaker_->play(buf, len); + this->set_timeout("data-incoming", 200, [this]() { + if (this->continuous_) { + this->request_start(true); + } + }); return; } - - uint8_t buf[1024]; - auto len = this->socket_->read(buf, sizeof(buf)); - if (len == -1) { - return; - } - this->speaker_->play(buf, len); #endif +#ifdef USE_MEDIA_PLAYER + if (this->media_player_ != nullptr) { + if (!this->playing_tts_ || + this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING) { + return; + } + this->set_timeout("playing-media", 1000, [this]() { + this->playing_tts_ = false; + if (this->continuous_) { + this->request_start(true); + } + }); + return; + } +#endif + // Set a 1 second timeout to start the voice assistant again. + this->set_timeout("continuous-no-sound", 1000, [this]() { + if (this->continuous_) { + this->request_start(true); + } + }); } void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { @@ -100,14 +125,19 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { } this->running_ = true; this->mic_->start(); + this->listening_trigger_->trigger(); } -void VoiceAssistant::request_start() { +void VoiceAssistant::request_start(bool continuous) { ESP_LOGD(TAG, "Requesting start..."); - if (!api::global_api_server->start_voice_assistant()) { + if (!api::global_api_server->start_voice_assistant(this->conversation_id_)) { ESP_LOGW(TAG, "Could not request start."); this->error_trigger_->trigger("not-connected", "Could not request start."); + this->continuous_ = false; + return; } + this->continuous_ = continuous; + this->set_timeout("reset-conversation_id", 5 * 60 * 1000, [this]() { this->conversation_id_ = ""; }); } void VoiceAssistant::signal_stop() { @@ -136,9 +166,18 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { return; } ESP_LOGD(TAG, "Speech recognised as: \"%s\"", text.c_str()); + this->signal_stop(); this->stt_end_trigger_->trigger(text); break; } + case api::enums::VOICE_ASSISTANT_INTENT_END: { + for (auto arg : msg.data) { + if (arg.name == "conversation_id") { + this->conversation_id_ = std::move(arg.value); + } + } + break; + } case api::enums::VOICE_ASSISTANT_TTS_START: { std::string text; for (auto arg : msg.data) { @@ -166,6 +205,12 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { return; } ESP_LOGD(TAG, "Response URL: \"%s\"", url.c_str()); +#ifdef USE_MEDIA_PLAYER + if (this->media_player_ != nullptr) { + this->playing_tts_ = true; + this->media_player_->make_call().set_media_url(url).perform(); + } +#endif this->tts_end_trigger_->trigger(url); break; } @@ -184,6 +229,8 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } } ESP_LOGE(TAG, "Error: %s - %s", code.c_str(), message.c_str()); + this->continuous_ = false; + this->signal_stop(); this->error_trigger_->trigger(code, message); } default: diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index c1a6e8883b..b103584509 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -15,6 +15,9 @@ #ifdef USE_SPEAKER #include "esphome/components/speaker/speaker.h" #endif +#ifdef USE_MEDIA_PLAYER +#include "esphome/components/media_player/media_player.h" +#endif #include "esphome/components/socket/socket.h" namespace esphome { @@ -22,8 +25,10 @@ namespace voice_assistant { // Version 1: Initial version // Version 2: Adds raw speaker support +// Version 3: Adds continuous support static const uint32_t INITIAL_VERSION = 1; static const uint32_t SPEAKER_SUPPORT = 2; +static const uint32_t SILENCE_DETECTION_SUPPORT = 3; class VoiceAssistant : public Component { public: @@ -36,20 +41,34 @@ class VoiceAssistant : public Component { #ifdef USE_SPEAKER void set_speaker(speaker::Speaker *speaker) { this->speaker_ = speaker; } #endif +#ifdef USE_MEDIA_PLAYER + void set_media_player(media_player::MediaPlayer *media_player) { this->media_player_ = media_player; } +#endif uint32_t get_version() const { #ifdef USE_SPEAKER - if (this->speaker_ != nullptr) + if (this->speaker_ != nullptr) { + if (this->silence_detection_) { + return SILENCE_DETECTION_SUPPORT; + } return SPEAKER_SUPPORT; + } #endif return INITIAL_VERSION; } - void request_start(); + void request_start(bool continuous = false); void signal_stop(); void on_event(const api::VoiceAssistantEventResponse &msg); + bool is_running() const { return this->running_; } + void set_continuous(bool continuous) { this->continuous_ = continuous; } + bool is_continuous() const { return this->continuous_; } + + void set_silence_detection(bool silence_detection) { this->silence_detection_ = silence_detection; } + + Trigger<> *get_listening_trigger() const { return this->listening_trigger_; } Trigger<> *get_start_trigger() const { return this->start_trigger_; } Trigger *get_stt_end_trigger() const { return this->stt_end_trigger_; } Trigger *get_tts_start_trigger() const { return this->tts_start_trigger_; } @@ -61,6 +80,7 @@ class VoiceAssistant : public Component { std::unique_ptr socket_ = nullptr; struct sockaddr_storage dest_addr_; + Trigger<> *listening_trigger_ = new Trigger<>(); Trigger<> *start_trigger_ = new Trigger<>(); Trigger *stt_end_trigger_ = new Trigger(); Trigger *tts_start_trigger_ = new Trigger(); @@ -72,8 +92,16 @@ class VoiceAssistant : public Component { #ifdef USE_SPEAKER speaker::Speaker *speaker_{nullptr}; #endif +#ifdef USE_MEDIA_PLAYER + media_player::MediaPlayer *media_player_{nullptr}; + bool playing_tts_{false}; +#endif + + std::string conversation_id_{""}; bool running_{false}; + bool continuous_{false}; + bool silence_detection_; }; template class StartAction : public Action, public Parented { @@ -81,9 +109,22 @@ template class StartAction : public Action, public Parent void play(Ts... x) override { this->parent_->request_start(); } }; +template class StartContinuousAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->request_start(true); } +}; + template class StopAction : public Action, public Parented { public: - void play(Ts... x) override { this->parent_->signal_stop(); } + void play(Ts... x) override { + this->parent_->set_continuous(false); + this->parent_->signal_stop(); + } +}; + +template class IsRunningCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->is_running() || this->parent_->is_continuous(); } }; extern VoiceAssistant *global_voice_assistant; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/const.py b/esphome/const.py index cbc8f428f5..470f8a46e5 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -399,6 +399,7 @@ CONF_MAX_VOLTAGE = "max_voltage" CONF_MDNS = "mdns" CONF_MEASUREMENT_DURATION = "measurement_duration" CONF_MEASUREMENT_SEQUENCE_NUMBER = "measurement_sequence_number" +CONF_MEDIA_PLAYER = "media_player" CONF_MEDIUM = "medium" CONF_MEMORY_BLOCKS = "memory_blocks" CONF_METHOD = "method" From b06bdc2da347c28f0b7488bd6ccce9e580190cef Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:34:35 +1200 Subject: [PATCH 0050/2607] Allow WIFI to be disabled and enabled (#4810) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Péter Sárközi Co-authored-by: Ash McKenzie --- esphome/components/wifi/__init__.py | 22 +++++++++++++ esphome/components/wifi/wifi_component.cpp | 37 ++++++++++++++++++++-- esphome/components/wifi/wifi_component.h | 28 +++++++++++++--- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index c9da07795c..068d015732 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -53,6 +53,9 @@ WIFI_POWER_SAVE_MODES = { "HIGH": WiFiPowerSaveMode.WIFI_POWER_SAVE_HIGH, } WiFiConnectedCondition = wifi_ns.class_("WiFiConnectedCondition", Condition) +WiFiEnabledCondition = wifi_ns.class_("WiFiEnabledCondition", Condition) +WiFiEnableAction = wifi_ns.class_("WiFiEnableAction", automation.Action) +WiFiDisableAction = wifi_ns.class_("WiFiDisableAction", automation.Action) def validate_password(value): @@ -253,6 +256,7 @@ def _validate(config): CONF_OUTPUT_POWER = "output_power" CONF_PASSIVE_SCAN = "passive_scan" +CONF_ENABLE_ON_BOOT = "enable_on_boot" CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -286,6 +290,7 @@ CONFIG_SCHEMA = cv.All( "This option has been removed. Please use the [disabled] option under the " "new mdns component instead." ), + cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, } ), _validate, @@ -385,6 +390,8 @@ async def to_code(config): if CONF_OUTPUT_POWER in config: cg.add(var.set_output_power(config[CONF_OUTPUT_POWER])) + cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) + if CORE.is_esp8266: cg.add_library("ESP8266WiFi", None) elif CORE.is_esp32 and CORE.using_arduino: @@ -410,3 +417,18 @@ async def to_code(config): @automation.register_condition("wifi.connected", WiFiConnectedCondition, cv.Schema({})) async def wifi_connected_to_code(config, condition_id, template_arg, args): return cg.new_Pvariable(condition_id, template_arg) + + +@automation.register_condition("wifi.enabled", WiFiEnabledCondition, cv.Schema({})) +async def wifi_enabled_to_code(config, condition_id, template_arg, args): + return cg.new_Pvariable(condition_id, template_arg) + + +@automation.register_action("wifi.enable", WiFiEnableAction, cv.Schema({})) +async def wifi_enable_to_code(config, action_id, template_arg, args): + return cg.new_Pvariable(action_id, template_arg) + + +@automation.register_action("wifi.disable", WiFiDisableAction, cv.Schema({})) +async def wifi_disable_to_code(config, action_id, template_arg, args): + return cg.new_Pvariable(action_id, template_arg) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index db19f9bcc0..ff621291f0 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -36,9 +36,18 @@ float WiFiComponent::get_setup_priority() const { return setup_priority::WIFI; } void WiFiComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up WiFi..."); + this->wifi_pre_setup_(); + if (this->enable_on_boot_) { + this->start(); + } else { + this->state_ = WIFI_COMPONENT_STATE_DISABLED; + } +} + +void WiFiComponent::start() { + ESP_LOGCONFIG(TAG, "Starting WiFi..."); ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); this->last_connected_ = millis(); - this->wifi_pre_setup_(); uint32_t hash = this->has_sta() ? fnv1_hash(App.get_compilation_time()) : 88491487UL; @@ -135,6 +144,8 @@ void WiFiComponent::loop() { case WIFI_COMPONENT_STATE_OFF: case WIFI_COMPONENT_STATE_AP: break; + case WIFI_COMPONENT_STATE_DISABLED: + return; } if (this->has_ap() && !this->ap_setup_) { @@ -387,6 +398,28 @@ void WiFiComponent::print_connect_params_() { #endif } +void WiFiComponent::enable() { + if (this->state_ != WIFI_COMPONENT_STATE_DISABLED) + return; + + ESP_LOGD(TAG, "Enabling WIFI..."); + this->error_from_callback_ = false; + this->state_ = WIFI_COMPONENT_STATE_OFF; + this->start(); +} + +void WiFiComponent::disable() { + if (this->state_ == WIFI_COMPONENT_STATE_DISABLED) + return; + + ESP_LOGD(TAG, "Disabling WIFI..."); + this->state_ = WIFI_COMPONENT_STATE_DISABLED; + this->wifi_disconnect_(); + this->wifi_mode_(false, false); +} + +bool WiFiComponent::is_disabled() { return this->state_ == WIFI_COMPONENT_STATE_DISABLED; } + void WiFiComponent::start_scanning() { this->action_started_ = millis(); ESP_LOGD(TAG, "Starting scan..."); @@ -608,7 +641,7 @@ void WiFiComponent::retry_connect() { } bool WiFiComponent::can_proceed() { - if (!this->has_sta()) { + if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED) { return true; } return this->is_connected(); diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d42be43b2d..d39b062990 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -47,6 +47,8 @@ struct SavedWifiSettings { enum WiFiComponentState { /** Nothing has been initialized yet. Internal AP, if configured, is disabled at this point. */ WIFI_COMPONENT_STATE_OFF = 0, + /** WiFi is disabled. */ + WIFI_COMPONENT_STATE_DISABLED, /** WiFi is in cooldown mode because something went wrong, scanning will begin after a short period of time. */ WIFI_COMPONENT_STATE_COOLDOWN, /** WiFi is in STA-only mode and currently scanning for APs. */ @@ -198,6 +200,9 @@ class WiFiComponent : public Component { void set_ap(const WiFiAP &ap); WiFiAP get_ap() { return this->ap_; } + void enable(); + void disable(); + bool is_disabled(); void start_scanning(); void check_scanning_finished(); void start_connecting(const WiFiAP &ap, bool two); @@ -224,6 +229,7 @@ class WiFiComponent : public Component { // (In most use cases you won't need these) /// Setup WiFi interface. void setup() override; + void start(); void dump_config() override; /// WIFI setup_priority. float get_setup_priority() const override; @@ -282,6 +288,8 @@ class WiFiComponent : public Component { int8_t wifi_rssi(); + void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; } + protected: static std::string format_mac_addr(const uint8_t mac[6]); void setup_ap_config_(); @@ -359,18 +367,30 @@ class WiFiComponent : public Component { bool btm_{false}; bool rrm_{false}; #endif + bool enable_on_boot_; }; extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) template class WiFiConnectedCondition : public Condition { public: - bool check(Ts... x) override; + bool check(Ts... x) override { return global_wifi_component->is_connected(); } }; -template bool WiFiConnectedCondition::check(Ts... x) { - return global_wifi_component->is_connected(); -} +template class WiFiEnabledCondition : public Condition { + public: + bool check(Ts... x) override { return !global_wifi_component->is_disabled(); } +}; + +template class WiFiEnableAction : public Action { + public: + void play(Ts... x) override { global_wifi_component->enable(); } +}; + +template class WiFiDisableAction : public Action { + public: + void play(Ts... x) override { global_wifi_component->disable(); } +}; } // namespace wifi } // namespace esphome From 4858882816bec73adfdcff9065a5363c6e68651f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:17:57 +1200 Subject: [PATCH 0051/2607] Bump frenck/action-yamllint from 1.4.0 to 1.4.1 (#4876) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b04d04672..95e7619a19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - name: Run yamllint - uses: frenck/action-yamllint@v1.4.0 + uses: frenck/action-yamllint@v1.4.1 black: name: Check black From 5621d592b49b6d5d9ba77ed7267661f1c67ccf03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:18:12 +1200 Subject: [PATCH 0052/2607] Bump pytest-cov from 4.0.0 to 4.1.0 (#4888) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 42aba7ddcf..c099250bd7 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -6,7 +6,7 @@ pre-commit # Unit tests pytest==7.3.1 -pytest-cov==4.0.0 +pytest-cov==4.1.0 pytest-mock==3.10.0 pytest-asyncio==0.21.0 asyncmock==0.4.2 From ae4c130a61e4b20b85e127698e2e969c955bfc4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:18:29 +1200 Subject: [PATCH 0053/2607] Bump zeroconf from 0.62.0 to 0.63.0 (#4890) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9fa93e44fe..391597f6fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.5.1 click==8.1.3 esphome-dashboard==20230516.0 aioesphomeapi==13.9.0 -zeroconf==0.62.0 +zeroconf==0.63.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 09a4d869f6b63995925d77ddc9a3a077fde6d748 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 01:47:16 +0000 Subject: [PATCH 0054/2607] Bump esptool from 4.5.1 to 4.6 (#4906) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 391597f6fd..a39f5afb1c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile -esptool==4.5.1 +esptool==4.6 click==8.1.3 esphome-dashboard==20230516.0 aioesphomeapi==13.9.0 From 8bb4c65272b41ccc6fa25a9e39096617c8c041c5 Mon Sep 17 00:00:00 2001 From: Nick Owens Date: Wed, 31 May 2023 19:31:58 -0700 Subject: [PATCH 0055/2607] prometheus: fix compilation with EntityBase (#4895) --- esphome/components/prometheus/prometheus_handler.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index f416ecf246..0ae2856ce4 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -5,6 +5,7 @@ #include #include +#include "esphome/core/entity_base.h" #include "esphome/components/web_server_base/web_server_base.h" #include "esphome/core/controller.h" #include "esphome/core/component.h" From aeb94e166b456f1a21ae52c3a90c66266a75772b Mon Sep 17 00:00:00 2001 From: PlainTechEnthusiast <135363826+PlainTechEnthusiast@users.noreply.github.com> Date: Sat, 3 Jun 2023 17:07:24 -0400 Subject: [PATCH 0056/2607] Support for Adafruit ESP32-S2 TFT Feather (#4912) Support for optional PowerSupply component for ST7789V This commit makes the power supply required if the model configured in the ST7789V component is set to ADAFRUIT_S2_TFT_FEATHER_240X135. There are at least two boards from Adafruit with this configuration but with a different pin out. This also adds the board pins definition for the board I have. There is discussion on the forums about the other board's documentation not matching reality and I don't have a physical board to confirm. --- esphome/components/esp32/boards.py | 33 ++++++++++++++++++++++++++ esphome/components/st7789v/display.py | 17 ++++++++++++- esphome/components/st7789v/st7789v.cpp | 16 +++++++++++++ esphome/components/st7789v/st7789v.h | 10 ++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index e4fdaec0aa..30297654bc 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -42,6 +42,39 @@ ESP32_BASE_PINS = { } ESP32_BOARD_PINS = { + "adafruit_feather_esp32s2_tft": { + "BUTTON": 0, + "A0": 18, + "A1": 17, + "A2": 16, + "A3": 15, + "A4": 14, + "A5": 8, + "SCK": 36, + "MOSI": 35, + "MISO": 37, + "RX": 2, + "TX": 1, + "D13": 13, + "D12": 12, + "D11": 11, + "D10": 10, + "D9": 9, + "D6": 6, + "D5": 5, + "NEOPIXEL": 33, + "PIN_NEOPIXEL": 33, + "NEOPIXEL_POWER": 34, + "SCL": 41, + "SDA": 42, + "TFT_I2C_POWER": 21, + "TFT_CS": 7, + "TFT_DC": 39, + "TFT_RESET": 40, + "TFT_BACKLIGHT": 45, + "LED": 13, + "LED_BUILTIN": 13, + }, "adafruit_qtpy_esp32c3": { "A0": 4, "A1": 3, diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index d18e305cc2..a81101f2d1 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import display, spi +from esphome.components import display, spi, power_supply from esphome.const import ( CONF_BACKLIGHT_PIN, CONF_DC_PIN, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_MODEL, CONF_RESET_PIN, CONF_WIDTH, + CONF_POWER_SUPPLY, ) from . import st7789v_ns @@ -32,6 +33,7 @@ MODELS = { "TTGO_TDISPLAY_135X240": ST7789VModel.ST7789V_MODEL_TTGO_TDISPLAY_135_240, "ADAFRUIT_FUNHOUSE_240X240": ST7789VModel.ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240, "ADAFRUIT_RR_280X240": ST7789VModel.ST7789V_MODEL_ADAFRUIT_RR_280_240, + "ADAFRUIT_S2_TFT_FEATHER_240X135": ST7789VModel.ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135, "CUSTOM": ST7789VModel.ST7789V_MODEL_CUSTOM, } @@ -58,6 +60,14 @@ def validate_st7789v(config): raise cv.Invalid( f'Do not specify {CONF_HEIGHT}, {CONF_WIDTH}, {CONF_OFFSET_HEIGHT} or {CONF_OFFSET_WIDTH} when using {CONF_MODEL} that is not "CUSTOM"' ) + + if ( + config[CONF_MODEL].upper() == "ADAFRUIT_S2_TFT_FEATHER_240X135" + and CONF_POWER_SUPPLY not in config + ): + raise cv.Invalid( + f'{CONF_POWER_SUPPLY} must be specified when {CONF_MODEL} is "ADAFRUIT_S2_TFT_FEATHER_240X135"' + ) return config @@ -69,6 +79,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_BACKLIGHT_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), cv.Optional(CONF_EIGHTBITCOLOR, default=False): cv.boolean, cv.Optional(CONF_HEIGHT): cv.int_, cv.Optional(CONF_WIDTH): cv.int_, @@ -113,3 +124,7 @@ async def to_code(config): config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) + + if CONF_POWER_SUPPLY in config: + ps = await cg.get_variable(config[CONF_POWER_SUPPLY]) + cg.add(var.set_power_supply(ps)) diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index 8a4fcfb179..0e7c9b9123 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -8,6 +8,10 @@ static const char *const TAG = "st7789v"; void ST7789V::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI ST7789V..."); +#ifdef USE_POWER_SUPPLY + this->power_.request(); + // the PowerSupply component takes care of post turn-on delay +#endif this->spi_setup(); this->dc_pin_->setup(); // OUTPUT @@ -128,6 +132,9 @@ void ST7789V::dump_config() { LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" B/L Pin: ", this->backlight_pin_); LOG_UPDATE_INTERVAL(this); +#ifdef USE_POWER_SUPPLY + ESP_LOGCONFIG(TAG, " Power Supply Configured: yes"); +#endif } float ST7789V::get_setup_priority() const { return setup_priority::PROCESSOR; } @@ -162,6 +169,13 @@ void ST7789V::set_model(ST7789VModel model) { this->offset_width_ = 20; break; + case ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135: + this->height_ = 240; + this->width_ = 135; + this->offset_height_ = 52; + this->offset_width_ = 40; + break; + default: break; } @@ -323,6 +337,8 @@ const char *ST7789V::model_str_() { return "Adafruit Funhouse 240x240"; case ST7789V_MODEL_ADAFRUIT_RR_280_240: return "Adafruit Round-Rectangular 280x240"; + case ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135: + return "Adafruit ESP32-S2 TFT Feather"; default: return "Custom"; } diff --git a/esphome/components/st7789v/st7789v.h b/esphome/components/st7789v/st7789v.h index 96e97c9d78..ccbe50cf85 100644 --- a/esphome/components/st7789v/st7789v.h +++ b/esphome/components/st7789v/st7789v.h @@ -3,6 +3,9 @@ #include "esphome/core/component.h" #include "esphome/components/spi/spi.h" #include "esphome/components/display/display_buffer.h" +#ifdef USE_POWER_SUPPLY +#include "esphome/components/power_supply/power_supply.h" +#endif namespace esphome { namespace st7789v { @@ -11,6 +14,7 @@ enum ST7789VModel { ST7789V_MODEL_TTGO_TDISPLAY_135_240, ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240, ST7789V_MODEL_ADAFRUIT_RR_280_240, + ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135, ST7789V_MODEL_CUSTOM }; @@ -120,6 +124,9 @@ class ST7789V : public PollingComponent, void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_backlight_pin(GPIOPin *backlight_pin) { this->backlight_pin_ = backlight_pin; } +#ifdef USE_POWER_SUPPLY + void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); } +#endif void set_eightbitcolor(bool eightbitcolor) { this->eightbitcolor_ = eightbitcolor; } void set_height(uint32_t height) { this->height_ = height; } @@ -143,6 +150,9 @@ class ST7789V : public PollingComponent, GPIOPin *dc_pin_{nullptr}; GPIOPin *reset_pin_{nullptr}; GPIOPin *backlight_pin_{nullptr}; +#ifdef USE_POWER_SUPPLY + power_supply::PowerSupplyRequester power_; +#endif bool eightbitcolor_{false}; uint16_t height_{0}; From 6b00622329894149a5608af91c0f0e2d2442f33c Mon Sep 17 00:00:00 2001 From: guillempages Date: Tue, 6 Jun 2023 23:32:21 +0200 Subject: [PATCH 0057/2607] Add support for mdi images (#4654) --- docker/Dockerfile | 2 + esphome/components/image/__init__.py | 176 ++++++++++++++++++++++++--- requirements_optional.txt | 1 + tests/test2.yaml | 7 ++ 4 files changed, 169 insertions(+), 17 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 95b6677815..2d9a8a9ae4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,6 +29,8 @@ RUN \ git=1:2.30.2-1+deb11u2 \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ + libcairo2=1.16.0-5 \ + python3-cffi=1.14.5-1 \ && rm -rf \ /tmp/* \ /var/{cache,log}/* \ diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 4260636fa9..113c5a2df1 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -1,5 +1,10 @@ import logging +import io +from pathlib import Path +import re +import requests + from esphome import core from esphome.components import display, font import esphome.config_validation as cv @@ -7,15 +12,19 @@ import esphome.codegen as cg from esphome.const import ( CONF_DITHER, CONF_FILE, + CONF_ICON, CONF_ID, + CONF_PATH, CONF_RAW_DATA_ID, CONF_RESIZE, + CONF_SOURCE, CONF_TYPE, ) from esphome.core import CORE, HexInt _LOGGER = logging.getLogger(__name__) +DOMAIN = "image" DEPENDENCIES = ["display"] MULTI_CONF = True @@ -31,9 +40,58 @@ IMAGE_TYPE = { CONF_USE_TRANSPARENCY = "use_transparency" +# If the MDI file cannot be downloaded within this time, abort. +MDI_DOWNLOAD_TIMEOUT = 30 # seconds + +SOURCE_LOCAL = "local" +SOURCE_MDI = "mdi" + Image_ = display.display_ns.class_("Image") +def _compute_local_icon_path(value) -> Path: + base_dir = Path(CORE.config_dir) / ".esphome" / DOMAIN / "mdi" + return base_dir / f"{value[CONF_ICON]}.svg" + + +def download_mdi(value): + mdi_id = value[CONF_ICON] + path = _compute_local_icon_path(value) + if path.is_file(): + return value + url = f"https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg/{mdi_id}.svg" + _LOGGER.debug("Downloading %s MDI image from %s", mdi_id, url) + try: + req = requests.get(url, timeout=MDI_DOWNLOAD_TIMEOUT) + req.raise_for_status() + except requests.exceptions.RequestException as e: + raise cv.Invalid(f"Could not download MDI image {mdi_id} from {url}: {e}") + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(req.content) + return value + + +def validate_cairosvg_installed(value): + """Validate that cairosvg is installed""" + try: + import cairosvg + except ImportError as err: + raise cv.Invalid( + "Please install the cairosvg python package to use this feature. " + "(pip install cairosvg)" + ) from err + + major, minor, _ = cairosvg.__version__.split(".") + if major < "2" or major == "2" and minor < "2": + raise cv.Invalid( + "Please update your cairosvg installation to at least 2.2.0. " + "(pip install -U cairosvg)" + ) + + return value + + def validate_cross_dependencies(config): """ Validate fields whose possible values depend on other fields. @@ -41,6 +99,13 @@ def validate_cross_dependencies(config): have "use_transparency" set to True. Also set the default value for those kind of dependent fields. """ + is_mdi = CONF_FILE in config and config[CONF_FILE][CONF_SOURCE] == SOURCE_MDI + if CONF_TYPE not in config: + if is_mdi: + config[CONF_TYPE] = "TRANSPARENT_BINARY" + else: + config[CONF_TYPE] = "BINARY" + image_type = config[CONF_TYPE] is_transparent_type = image_type in ["TRANSPARENT_BINARY", "RGBA"] @@ -51,16 +116,74 @@ def validate_cross_dependencies(config): if is_transparent_type and not config[CONF_USE_TRANSPARENCY]: raise cv.Invalid(f"Image type {image_type} must always be transparent.") + if is_mdi and config[CONF_TYPE] not in ["BINARY", "TRANSPARENT_BINARY"]: + raise cv.Invalid("MDI images must be binary images.") + return config +def validate_file_shorthand(value): + value = cv.string_strict(value) + if value.startswith("mdi:"): + validate_cairosvg_installed(value) + + match = re.search(r"mdi:([a-zA-Z0-9\-]+)", value) + if match is None: + raise cv.Invalid("Could not parse mdi icon name.") + icon = match.group(1) + return FILE_SCHEMA( + { + CONF_SOURCE: SOURCE_MDI, + CONF_ICON: icon, + } + ) + return FILE_SCHEMA( + { + CONF_SOURCE: SOURCE_LOCAL, + CONF_PATH: value, + } + ) + + +LOCAL_SCHEMA = cv.Schema( + { + cv.Required(CONF_PATH): cv.file_, + } +) + +MDI_SCHEMA = cv.All( + { + cv.Required(CONF_ICON): cv.string, + }, + download_mdi, +) + +TYPED_FILE_SCHEMA = cv.typed_schema( + { + SOURCE_LOCAL: LOCAL_SCHEMA, + SOURCE_MDI: MDI_SCHEMA, + }, + key=CONF_SOURCE, +) + + +def _file_schema(value): + if isinstance(value, str): + return validate_file_shorthand(value) + return TYPED_FILE_SCHEMA(value) + + +FILE_SCHEMA = cv.Schema(_file_schema) + IMAGE_SCHEMA = cv.Schema( cv.All( { cv.Required(CONF_ID): cv.declare_id(Image_), - cv.Required(CONF_FILE): cv.file_, + cv.Required(CONF_FILE): FILE_SCHEMA, cv.Optional(CONF_RESIZE): cv.dimensions, - cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(IMAGE_TYPE, upper=True), + # Not setting default here on purpose; the default depends on the source type + # (file or mdi), and will be set in the "validate_cross_dependencies" validator. + cv.Optional(CONF_TYPE): cv.enum(IMAGE_TYPE, upper=True), # Not setting default here on purpose; the default depends on the image type, # and thus will be set in the "validate_cross_dependencies" validator. cv.Optional(CONF_USE_TRANSPARENCY): cv.boolean, @@ -79,24 +202,43 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) async def to_code(config): from PIL import Image - path = CORE.relative_config_path(config[CONF_FILE]) - try: - image = Image.open(path) - except Exception as e: - raise core.EsphomeError(f"Could not load image file {path}: {e}") + conf_file = config[CONF_FILE] + + if conf_file[CONF_SOURCE] == SOURCE_LOCAL: + path = CORE.relative_config_path(conf_file[CONF_PATH]) + try: + image = Image.open(path) + except Exception as e: + raise core.EsphomeError(f"Could not load image file {path}: {e}") + if CONF_RESIZE in config: + image.thumbnail(config[CONF_RESIZE]) + elif conf_file[CONF_SOURCE] == SOURCE_MDI: + # Those imports are only needed in case of MDI images; adding them + # to the top would force configurations not using MDI to also have them + # installed for no reason. + from cairosvg import svg2png + + svg_file = _compute_local_icon_path(conf_file) + if CONF_RESIZE in config: + req_width, req_height = config[CONF_RESIZE] + svg_image = svg2png( + url=svg_file.as_posix(), + output_width=req_width, + output_height=req_height, + ) + else: + svg_image = svg2png(url=svg_file.as_posix()) + + image = Image.open(io.BytesIO(svg_image)) width, height = image.size - if CONF_RESIZE in config: - image.thumbnail(config[CONF_RESIZE]) - width, height = image.size - else: - if width > 500 or height > 500: - _LOGGER.warning( - 'The image "%s" you requested is very big. Please consider' - " using the resize parameter.", - path, - ) + if CONF_RESIZE not in config and (width > 500 or height > 500): + _LOGGER.warning( + 'The image "%s" you requested is very big. Please consider' + " using the resize parameter.", + path, + ) transparent = config[CONF_USE_TRANSPARENCY] diff --git a/requirements_optional.txt b/requirements_optional.txt index 2c73430109..df6b3b387e 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,2 +1,3 @@ pillow>4.0.0 +cairosvg>=2.2.0 cryptography>=2.0.0,<4 diff --git a/tests/test2.yaml b/tests/test2.yaml index 8f56336848..0dae0b2570 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -680,6 +680,13 @@ image: type: RGB565 use_transparency: no + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY + cap1188: id: cap1188_component address: 0x29 From d1253922c393d9cee1264cd99538a69005200421 Mon Sep 17 00:00:00 2001 From: Simone Rossetto Date: Wed, 7 Jun 2023 00:38:18 +0200 Subject: [PATCH 0058/2607] Increase SNTP setup priority (#4917) --- esphome/components/sntp/sntp_component.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sntp/sntp_component.h b/esphome/components/sntp/sntp_component.h index 4c70a6b09f..987dd23a19 100644 --- a/esphome/components/sntp/sntp_component.h +++ b/esphome/components/sntp/sntp_component.h @@ -22,7 +22,7 @@ class SNTPComponent : public time::RealTimeClock { this->server_2_ = server_2; this->server_3_ = server_3; } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + float get_setup_priority() const override { return setup_priority::BEFORE_CONNECTION; } void update() override; void loop() override; From 1cf210fa258592231002e624df61d32cb1940b18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:27:39 +1200 Subject: [PATCH 0059/2607] Bump aioesphomeapi from 13.9.0 to 14.0.0 (#4925) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a39f5afb1c..b994de1932 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6 click==8.1.3 esphome-dashboard==20230516.0 -aioesphomeapi==13.9.0 +aioesphomeapi==14.0.0 zeroconf==0.63.0 # esp-idf requires this, but doesn't bundle it by default From ce139796908e376a1093f8b1694f7b547d6ed0c6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 9 Jun 2023 07:41:09 +1200 Subject: [PATCH 0060/2607] Bluetooth Proxy: Raw bundled advertisements (#4924) --- esphome/components/api/api.proto | 22 ++- esphome/components/api/api_connection.cpp | 23 ++- esphome/components/api/api_connection.h | 13 +- esphome/components/api/api_pb2.cpp | 126 ++++++++++++- esphome/components/api/api_pb2.h | 31 +++- esphome/components/api/api_pb2_service.cpp | 9 + esphome/components/api/api_pb2_service.h | 3 + esphome/components/api/api_server.cpp | 105 ----------- esphome/components/api/api_server.h | 15 -- .../bluetooth_proxy/bluetooth_connection.cpp | 52 +++--- .../bluetooth_proxy/bluetooth_proxy.cpp | 170 ++++++++++++++---- .../bluetooth_proxy/bluetooth_proxy.h | 67 ++++++- esphome/components/esp32_ble/ble.cpp | 11 ++ esphome/components/esp32_ble/ble.h | 2 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 33 ++-- .../esp32_ble_tracker/esp32_ble_tracker.h | 3 + 16 files changed, 450 insertions(+), 235 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 34678fde0f..74d08195a0 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -206,7 +206,8 @@ message DeviceInfoResponse { uint32 webserver_port = 10; - uint32 bluetooth_proxy_version = 11; + uint32 legacy_bluetooth_proxy_version = 11; + uint32 bluetooth_proxy_feature_flags = 15; string manufacturer = 12; @@ -1130,6 +1131,8 @@ message SubscribeBluetoothLEAdvertisementsRequest { option (id) = 66; option (source) = SOURCE_CLIENT; option (ifdef) = "USE_BLUETOOTH_PROXY"; + + uint32 flags = 1; } message BluetoothServiceData { @@ -1154,6 +1157,23 @@ message BluetoothLEAdvertisementResponse { uint32 address_type = 7; } +message BluetoothLERawAdvertisement { + uint64 address = 1; + sint32 rssi = 2; + uint32 address_type = 3; + + bytes data = 4; +} + +message BluetoothLERawAdvertisementsResponse { + option (id) = 93; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_BLUETOOTH_PROXY"; + option (no_delay) = true; + + repeated BluetoothLERawAdvertisement advertisements = 1; +} + enum BluetoothDeviceRequestType { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0; BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 3983c6403b..53e6ccd6dc 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -51,6 +51,14 @@ void APIConnection::start() { helper_->set_log_info(client_info_); } +APIConnection::~APIConnection() { +#ifdef USE_BLUETOOTH_PROXY + if (bluetooth_proxy::global_bluetooth_proxy->get_api_connection() == this) { + bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this); + } +#endif +} + void APIConnection::loop() { if (this->remove_) return; @@ -845,9 +853,13 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) { #endif #ifdef USE_BLUETOOTH_PROXY +void APIConnection::subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) { + bluetooth_proxy::global_bluetooth_proxy->subscribe_api_connection(this, msg.flags); +} +void APIConnection::unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { + bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this); +} bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg) { - if (!this->bluetooth_le_advertisement_subscription_) - return false; if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) { BluetoothLEAdvertisementResponse resp = msg; for (auto &service : resp.service_data) { @@ -943,7 +955,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { HelloResponse resp; resp.api_version_major = 1; - resp.api_version_minor = 8; + resp.api_version_minor = 9; resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; resp.name = App.get_name(); @@ -995,9 +1007,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.webserver_port = USE_WEBSERVER_PORT; #endif #ifdef USE_BLUETOOTH_PROXY - resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() - ? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION - : bluetooth_proxy::PASSIVE_ONLY_VERSION; + resp.legacy_bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->get_legacy_version(); + resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags(); #endif #ifdef USE_VOICE_ASSISTANT resp.voice_assistant_version = voice_assistant::global_voice_assistant->get_version(); diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index d4e9cc656e..5398234f9f 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -16,7 +16,7 @@ namespace api { class APIConnection : public APIServerConnection { public: APIConnection(std::unique_ptr socket, APIServer *parent); - virtual ~APIConnection() = default; + virtual ~APIConnection(); void start(); void loop(); @@ -98,12 +98,8 @@ class APIConnection : public APIServerConnection { this->send_homeassistant_service_response(call); } #ifdef USE_BLUETOOTH_PROXY - void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { - this->bluetooth_le_advertisement_subscription_ = true; - } - void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override { - this->bluetooth_le_advertisement_subscription_ = false; - } + void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; + void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override; bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg); void bluetooth_device_request(const BluetoothDeviceRequest &msg) override; @@ -211,9 +207,6 @@ class APIConnection : public APIServerConnection { uint32_t last_traffic_; bool sent_ping_{false}; bool service_call_subscription_{false}; -#ifdef USE_BLUETOOTH_PROXY - bool bluetooth_le_advertisement_subscription_{false}; -#endif #ifdef USE_VOICE_ASSISTANT bool voice_assistant_subscription_{false}; #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 29e8e207dd..019e653a7f 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -617,7 +617,11 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { return true; } case 11: { - this->bluetooth_proxy_version = value.as_uint32(); + this->legacy_bluetooth_proxy_version = value.as_uint32(); + return true; + } + case 15: { + this->bluetooth_proxy_feature_flags = value.as_uint32(); return true; } case 14: { @@ -681,7 +685,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(8, this->project_name); buffer.encode_string(9, this->project_version); buffer.encode_uint32(10, this->webserver_port); - buffer.encode_uint32(11, this->bluetooth_proxy_version); + buffer.encode_uint32(11, this->legacy_bluetooth_proxy_version); + buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags); buffer.encode_string(12, this->manufacturer); buffer.encode_string(13, this->friendly_name); buffer.encode_uint32(14, this->voice_assistant_version); @@ -731,8 +736,13 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append(buffer); out.append("\n"); - out.append(" bluetooth_proxy_version: "); - sprintf(buffer, "%u", this->bluetooth_proxy_version); + out.append(" legacy_bluetooth_proxy_version: "); + sprintf(buffer, "%u", this->legacy_bluetooth_proxy_version); + out.append(buffer); + out.append("\n"); + + out.append(" bluetooth_proxy_feature_flags: "); + sprintf(buffer, "%u", this->bluetooth_proxy_feature_flags); out.append(buffer); out.append("\n"); @@ -5041,10 +5051,28 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif -void SubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {} +bool SubscribeBluetoothLEAdvertisementsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->flags = value.as_uint32(); + return true; + } + default: + return false; + } +} +void SubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint32(1, this->flags); +} #ifdef HAS_PROTO_MESSAGE_DUMP void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { - out.append("SubscribeBluetoothLEAdvertisementsRequest {}"); + __attribute__((unused)) char buffer[64]; + out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); + out.append(" flags: "); + sprintf(buffer, "%u", this->flags); + out.append(buffer); + out.append("\n"); + out.append("}"); } #endif bool BluetoothServiceData::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -5197,6 +5225,92 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool BluetoothLERawAdvertisement::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->address = value.as_uint64(); + return true; + } + case 2: { + this->rssi = value.as_sint32(); + return true; + } + case 3: { + this->address_type = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool BluetoothLERawAdvertisement::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 4: { + this->data = value.as_string(); + return true; + } + default: + return false; + } +} +void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint64(1, this->address); + buffer.encode_sint32(2, this->rssi); + buffer.encode_uint32(3, this->address_type); + buffer.encode_string(4, this->data); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void BluetoothLERawAdvertisement::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothLERawAdvertisement {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" rssi: "); + sprintf(buffer, "%d", this->rssi); + out.append(buffer); + out.append("\n"); + + out.append(" address_type: "); + sprintf(buffer, "%u", this->address_type); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append("'").append(this->data).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +bool BluetoothLERawAdvertisementsResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->advertisements.push_back(value.as_message()); + return true; + } + default: + return false; + } +} +void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer buffer) const { + for (auto &it : this->advertisements) { + buffer.encode_message(1, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void BluetoothLERawAdvertisementsResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothLERawAdvertisementsResponse {\n"); + for (const auto &it : this->advertisements) { + out.append(" advertisements: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +#endif bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index cd1cfb595a..49307dfce0 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -287,7 +287,8 @@ class DeviceInfoResponse : public ProtoMessage { std::string project_name{}; std::string project_version{}; uint32_t webserver_port{0}; - uint32_t bluetooth_proxy_version{0}; + uint32_t legacy_bluetooth_proxy_version{0}; + uint32_t bluetooth_proxy_feature_flags{0}; std::string manufacturer{}; std::string friendly_name{}; uint32_t voice_assistant_version{0}; @@ -1247,12 +1248,14 @@ class MediaPlayerCommandRequest : public ProtoMessage { }; class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { public: + uint32_t flags{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; #endif protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class BluetoothServiceData : public ProtoMessage { public: @@ -1286,6 +1289,32 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class BluetoothLERawAdvertisement : public ProtoMessage { + public: + uint64_t address{0}; + int32_t rssi{0}; + uint32_t address_type{0}; + std::string data{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class BluetoothLERawAdvertisementsResponse : public ProtoMessage { + public: + std::vector advertisements{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; +}; class BluetoothDeviceRequest : public ProtoMessage { public: uint64_t address{0}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index df36d0fdea..e14e22cdc1 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -339,6 +339,15 @@ bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const Blu } #endif #ifdef USE_BLUETOOTH_PROXY +bool APIServerConnectionBase::send_bluetooth_le_raw_advertisements_response( + const BluetoothLERawAdvertisementsResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_bluetooth_le_raw_advertisements_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 93); +} +#endif +#ifdef USE_BLUETOOTH_PROXY #endif #ifdef USE_BLUETOOTH_PROXY bool APIServerConnectionBase::send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 3808f128a4..8af7a53381 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -161,6 +161,9 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg); #endif +#ifdef USE_BLUETOOTH_PROXY + bool send_bluetooth_le_raw_advertisements_response(const BluetoothLERawAdvertisementsResponse &msg); +#endif #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_device_request(const BluetoothDeviceRequest &value){}; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 3dd47c4dd8..27c82f7ccc 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -291,112 +291,7 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon client->send_homeassistant_service_call(call); } } -#ifdef USE_BLUETOOTH_PROXY -void APIServer::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_le_advertisement(call); - } -} -void APIServer::send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) { - BluetoothDeviceConnectionResponse call; - call.address = address; - call.connected = connected; - call.mtu = mtu; - call.error = error; - for (auto &client : this->clients_) { - client->send_bluetooth_device_connection_response(call); - } -} - -void APIServer::send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error) { - BluetoothDevicePairingResponse call; - call.address = address; - call.paired = paired; - call.error = error; - - for (auto &client : this->clients_) { - client->send_bluetooth_device_pairing_response(call); - } -} - -void APIServer::send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error) { - BluetoothDeviceUnpairingResponse call; - call.address = address; - call.success = success; - call.error = error; - - for (auto &client : this->clients_) { - client->send_bluetooth_device_unpairing_response(call); - } -} - -void APIServer::send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error) { - BluetoothDeviceClearCacheResponse call; - call.address = address; - call.success = success; - call.error = error; - - for (auto &client : this->clients_) { - client->send_bluetooth_device_clear_cache_response(call); - } -} - -void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) { - BluetoothConnectionsFreeResponse call; - call.free = free; - call.limit = limit; - - for (auto &client : this->clients_) { - client->send_bluetooth_connections_free_response(call); - } -} - -void APIServer::send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_read_response(call); - } -} -void APIServer::send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_write_response(call); - } -} -void APIServer::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_notify_data_response(call); - } -} -void APIServer::send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_notify_response(call); - } -} -void APIServer::send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call) { - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_get_services_response(call); - } -} -void APIServer::send_bluetooth_gatt_services_done(uint64_t address) { - BluetoothGATTGetServicesDoneResponse call; - call.address = address; - - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_get_services_done_response(call); - } -} -void APIServer::send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) { - BluetoothGATTErrorResponse call; - call.address = address; - call.handle = handle; - call.error = error; - - for (auto &client : this->clients_) { - client->send_bluetooth_gatt_error_response(call); - } -} - -#endif APIServer::APIServer() { global_api_server = this; } void APIServer::subscribe_home_assistant_state(std::string entity_id, optional attribute, std::function f) { diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 79ba7b17f1..28e53f22e2 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -75,21 +75,6 @@ class APIServer : public Component, public Controller { void on_media_player_update(media_player::MediaPlayer *obj) override; #endif void send_homeassistant_service_call(const HomeassistantServiceResponse &call); -#ifdef USE_BLUETOOTH_PROXY - void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call); - void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK); - void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK); - void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK); - void send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK); - void send_bluetooth_connections_free(uint8_t free, uint8_t limit); - void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call); - void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call); - void send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call); - void send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call); - void send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call); - void send_bluetooth_gatt_services_done(uint64_t address); - void send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error); -#endif void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } #ifdef USE_HOMEASSISTANT_TIME void request_time(); diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 9354ab36d6..26304325c1 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -1,6 +1,6 @@ #include "bluetooth_connection.h" -#include "esphome/components/api/api_server.h" +#include "esphome/components/api/api_pb2.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" @@ -20,24 +20,21 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga switch (event) { case ESP_GATTC_DISCONNECT_EVT: { - api::global_api_server->send_bluetooth_device_connection(this->address_, false, 0, param->disconnect.reason); + this->proxy_->send_device_connection(this->address_, false, 0, param->disconnect.reason); this->set_address(0); - api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), - this->proxy_->get_bluetooth_connections_limit()); + this->proxy_->send_connections_free(); break; } case ESP_GATTC_OPEN_EVT: { if (param->open.conn_id != this->conn_id_) break; if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) { - api::global_api_server->send_bluetooth_device_connection(this->address_, false, 0, param->open.status); + this->proxy_->send_device_connection(this->address_, false, 0, param->open.status); this->set_address(0); - api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), - this->proxy_->get_bluetooth_connections_limit()); + this->proxy_->send_connections_free(); } else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) { - api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_); - api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), - this->proxy_->get_bluetooth_connections_limit()); + this->proxy_->send_device_connection(this->address_, true, this->mtu_); + this->proxy_->send_connections_free(); } this->seen_mtu_or_services_ = false; break; @@ -52,9 +49,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga this->seen_mtu_or_services_ = true; break; } - api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_); - api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), - this->proxy_->get_bluetooth_connections_limit()); + this->proxy_->send_device_connection(this->address_, true, this->mtu_); + this->proxy_->send_connections_free(); break; } case ESP_GATTC_SEARCH_CMPL_EVT: { @@ -67,9 +63,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga this->seen_mtu_or_services_ = true; break; } - api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_); - api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), - this->proxy_->get_bluetooth_connections_limit()); + this->proxy_->send_device_connection(this->address_, true, this->mtu_); + this->proxy_->send_connections_free(); break; } case ESP_GATTC_READ_DESCR_EVT: @@ -79,7 +74,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga if (param->read.status != ESP_GATT_OK) { ESP_LOGW(TAG, "[%d] [%s] Error reading char/descriptor at handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->read.handle, param->read.status); - api::global_api_server->send_bluetooth_gatt_error(this->address_, param->read.handle, param->read.status); + this->proxy_->send_gatt_error(this->address_, param->read.handle, param->read.status); break; } api::BluetoothGATTReadResponse resp; @@ -89,7 +84,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga for (uint16_t i = 0; i < param->read.value_len; i++) { resp.data.push_back(param->read.value[i]); } - api::global_api_server->send_bluetooth_gatt_read_response(resp); + this->proxy_->get_api_connection()->send_bluetooth_gatt_read_response(resp); break; } case ESP_GATTC_WRITE_CHAR_EVT: @@ -99,13 +94,13 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga if (param->write.status != ESP_GATT_OK) { ESP_LOGW(TAG, "[%d] [%s] Error writing char/descriptor at handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->write.handle, param->write.status); - api::global_api_server->send_bluetooth_gatt_error(this->address_, param->write.handle, param->write.status); + this->proxy_->send_gatt_error(this->address_, param->write.handle, param->write.status); break; } api::BluetoothGATTWriteResponse resp; resp.address = this->address_; resp.handle = param->write.handle; - api::global_api_server->send_bluetooth_gatt_write_response(resp); + this->proxy_->get_api_connection()->send_bluetooth_gatt_write_response(resp); break; } case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { @@ -113,28 +108,26 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle, param->unreg_for_notify.status); - api::global_api_server->send_bluetooth_gatt_error(this->address_, param->unreg_for_notify.handle, - param->unreg_for_notify.status); + this->proxy_->send_gatt_error(this->address_, param->unreg_for_notify.handle, param->unreg_for_notify.status); break; } api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->unreg_for_notify.handle; - api::global_api_server->send_bluetooth_gatt_notify_response(resp); + this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_response(resp); break; } case ESP_GATTC_REG_FOR_NOTIFY_EVT: { if (param->reg_for_notify.status != ESP_GATT_OK) { ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status); - api::global_api_server->send_bluetooth_gatt_error(this->address_, param->reg_for_notify.handle, - param->reg_for_notify.status); + this->proxy_->send_gatt_error(this->address_, param->reg_for_notify.handle, param->reg_for_notify.status); break; } api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->reg_for_notify.handle; - api::global_api_server->send_bluetooth_gatt_notify_response(resp); + this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_response(resp); break; } case ESP_GATTC_NOTIFY_EVT: { @@ -149,7 +142,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga for (uint16_t i = 0; i < param->notify.value_len; i++) { resp.data.push_back(param->notify.value[i]); } - api::global_api_server->send_bluetooth_gatt_notify_data_response(resp); + this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_data_response(resp); break; } default: @@ -166,10 +159,9 @@ void BluetoothConnection::gap_event_handler(esp_gap_ble_cb_event_t event, esp_bl if (memcmp(param->ble_security.auth_cmpl.bd_addr, this->remote_bda_, 6) != 0) break; if (param->ble_security.auth_cmpl.success) { - api::global_api_server->send_bluetooth_device_pairing(this->address_, true); + this->proxy_->send_device_pairing(this->address_, true); } else { - api::global_api_server->send_bluetooth_device_pairing(this->address_, false, - param->ble_security.auth_cmpl.fail_reason); + this->proxy_->send_device_pairing(this->address_, false, param->ble_security.auth_cmpl.fail_reason); } break; default: diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 76950c944e..b633fe2430 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -1,11 +1,10 @@ #include "bluetooth_proxy.h" #include "esphome/core/log.h" +#include "esphome/core/macros.h" #ifdef USE_ESP32 -#include "esphome/components/api/api_server.h" - namespace esphome { namespace bluetooth_proxy { @@ -27,15 +26,39 @@ std::vector get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) { BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; } bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { - if (!api::global_api_server->is_connected()) + if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || this->raw_advertisements_) return false; + ESP_LOGV(TAG, "Proxying packet from %s - %s. RSSI: %d dB", device.get_name().c_str(), device.address_str().c_str(), device.get_rssi()); this->send_api_packet_(device); - return true; } +bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) { + if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_) + return false; + + api::BluetoothLERawAdvertisementsResponse resp; + for (size_t i = 0; i < count; i++) { + auto &result = advertisements[i]; + api::BluetoothLERawAdvertisement adv; + adv.address = esp32_ble::ble_addr_to_uint64(result.bda); + adv.rssi = result.rssi; + adv.address_type = result.ble_addr_type; + + uint8_t length = result.adv_data_len + result.scan_rsp_len; + adv.data.reserve(length); + for (uint16_t i = 0; i < length; i++) { + adv.data.push_back(result.ble_adv[i]); + } + + resp.advertisements.push_back(std::move(adv)); + } + ESP_LOGV(TAG, "Proxying %d packets", count); + this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); + return true; +} void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) { api::BluetoothLEAdvertisementResponse resp; resp.address = device.address_uint64(); @@ -58,7 +81,7 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi manufacturer_data.data.assign(data.data.begin(), data.data.end()); resp.manufacturer_data.push_back(std::move(manufacturer_data)); } - api::global_api_server->send_bluetooth_le_advertisement(resp); + this->api_connection_->send_bluetooth_le_advertisement(resp); } void BluetoothProxy::dump_config() { @@ -81,7 +104,7 @@ int BluetoothProxy::get_bluetooth_connections_free() { } void BluetoothProxy::loop() { - if (!api::global_api_server->is_connected()) { + if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr) { for (auto *connection : this->connections_) { if (connection->get_address() != 0) { connection->disconnect(); @@ -92,7 +115,7 @@ void BluetoothProxy::loop() { for (auto *connection : this->connections_) { if (connection->send_service_ == connection->service_count_) { connection->send_service_ = DONE_SENDING_SERVICES; - api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address()); + this->send_gatt_services_done(connection->get_address()); if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE || connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { connection->release_services(); @@ -170,7 +193,7 @@ void BluetoothProxy::loop() { service_resp.characteristics.push_back(std::move(characteristic_resp)); } resp.services.push_back(std::move(service_resp)); - api::global_api_server->send_bluetooth_gatt_services(resp); + this->api_connection_->send_bluetooth_gatt_get_services_response(resp); } } } @@ -208,16 +231,15 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest auto *connection = this->get_connection_(msg.address, true); if (connection == nullptr) { ESP_LOGW(TAG, "No free connections available"); - api::global_api_server->send_bluetooth_device_connection(msg.address, false); + this->send_device_connection(msg.address, false); return; } if (connection->state() == espbt::ClientState::CONNECTED || connection->state() == espbt::ClientState::ESTABLISHED) { ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(), connection->address_str().c_str()); - api::global_api_server->send_bluetooth_device_connection(msg.address, true); - api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(), - this->get_bluetooth_connections_limit()); + this->send_device_connection(msg.address, true); + this->send_connections_free(); return; } else if (connection->state() == espbt::ClientState::SEARCHING) { ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device", @@ -263,25 +285,22 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest } else { connection->set_state(espbt::ClientState::SEARCHING); } - api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(), - this->get_bluetooth_connections_limit()); + this->send_connections_free(); break; } case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT: { auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { - api::global_api_server->send_bluetooth_device_connection(msg.address, false); - api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(), - this->get_bluetooth_connections_limit()); + this->send_device_connection(msg.address, false); + this->send_connections_free(); return; } if (connection->state() != espbt::ClientState::IDLE) { connection->disconnect(); } else { connection->set_address(0); - api::global_api_server->send_bluetooth_device_connection(msg.address, false); - api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(), - this->get_bluetooth_connections_limit()); + this->send_device_connection(msg.address, false); + this->send_connections_free(); } break; } @@ -291,10 +310,10 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest if (!connection->is_paired()) { auto err = connection->pair(); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_device_pairing(msg.address, false, err); + this->send_device_pairing(msg.address, false, err); } } else { - api::global_api_server->send_bluetooth_device_pairing(msg.address, true); + this->send_device_pairing(msg.address, true); } } break; @@ -303,14 +322,20 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest esp_bd_addr_t address; uint64_to_bd_addr(msg.address, address); esp_err_t ret = esp_ble_remove_bond_device(address); - api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret); + this->send_device_pairing(msg.address, ret == ESP_OK, ret); break; } case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: { esp_bd_addr_t address; uint64_to_bd_addr(msg.address, address); esp_err_t ret = esp_ble_gattc_cache_clean(address); - api::global_api_server->send_bluetooth_device_clear_cache(msg.address, ret == ESP_OK, ret); + api::BluetoothDeviceClearCacheResponse call; + call.address = msg.address; + call.success = ret == ESP_OK; + call.error = ret; + + this->api_connection_->send_bluetooth_device_clear_cache_response(call); + break; } } @@ -320,13 +345,13 @@ void BluetoothProxy::bluetooth_gatt_read(const api::BluetoothGATTReadRequest &ms auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); return; } auto err = connection->read_characteristic(msg.handle); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); + this->send_gatt_error(msg.address, msg.handle, err); } } @@ -334,13 +359,13 @@ void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest & auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); return; } auto err = connection->write_characteristic(msg.handle, msg.data, msg.response); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); + this->send_gatt_error(msg.address, msg.handle, err); } } @@ -348,13 +373,13 @@ void BluetoothProxy::bluetooth_gatt_read_descriptor(const api::BluetoothGATTRead auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { ESP_LOGW(TAG, "Cannot read GATT descriptor, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); return; } auto err = connection->read_descriptor(msg.handle); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); + this->send_gatt_error(msg.address, msg.handle, err); } } @@ -362,13 +387,13 @@ void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWri auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { ESP_LOGW(TAG, "Cannot write GATT descriptor, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); return; } auto err = connection->write_descriptor(msg.handle, msg.data, true); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); + this->send_gatt_error(msg.address, msg.handle, err); } } @@ -376,12 +401,12 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr || !connection->connected()) { ESP_LOGW(TAG, "Cannot get GATT services, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED); return; } if (!connection->service_count_) { ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str()); - api::global_api_server->send_bluetooth_gatt_services_done(msg.address); + this->send_gatt_services_done(msg.address); return; } if (connection->send_service_ == @@ -393,16 +418,89 @@ void BluetoothProxy::bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest auto *connection = this->get_connection_(msg.address, false); if (connection == nullptr) { ESP_LOGW(TAG, "Cannot notify GATT characteristic, not connected"); - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); + this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED); return; } auto err = connection->notify_characteristic(msg.handle, msg.enable); if (err != ESP_OK) { - api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); + this->send_gatt_error(msg.address, msg.handle, err); } } +void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags) { + if (this->api_connection_ != nullptr) { + ESP_LOGE(TAG, "Only one API subscription is allowed at a time"); + return; + } + this->api_connection_ = api_connection; + this->raw_advertisements_ = flags & BluetoothProxySubscriptionFlag::SUBSCRIPTION_RAW_ADVERTISEMENTS; +} + +void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connection) { + if (this->api_connection_ != api_connection) { + ESP_LOGV(TAG, "API connection is not subscribed"); + return; + } + this->api_connection_ = nullptr; + this->raw_advertisements_ = false; +} + +void BluetoothProxy::send_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) { + if (this->api_connection_ == nullptr) + return; + api::BluetoothDeviceConnectionResponse call; + call.address = address; + call.connected = connected; + call.mtu = mtu; + call.error = error; + this->api_connection_->send_bluetooth_device_connection_response(call); +} +void BluetoothProxy::send_connections_free() { + if (this->api_connection_ == nullptr) + return; + api::BluetoothConnectionsFreeResponse call; + call.free = this->get_bluetooth_connections_free(); + call.limit = this->get_bluetooth_connections_limit(); + this->api_connection_->send_bluetooth_connections_free_response(call); +} + +void BluetoothProxy::send_gatt_services_done(uint64_t address) { + if (this->api_connection_ == nullptr) + return; + api::BluetoothGATTGetServicesDoneResponse call; + call.address = address; + this->api_connection_->send_bluetooth_gatt_get_services_done_response(call); +} + +void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) { + if (this->api_connection_ == nullptr) + return; + api::BluetoothGATTErrorResponse call; + call.address = address; + call.handle = handle; + call.error = error; + this->api_connection_->send_bluetooth_gatt_error_response(call); +} + +void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_t error) { + api::BluetoothDevicePairingResponse call; + call.address = address; + call.paired = paired; + call.error = error; + + this->api_connection_->send_bluetooth_device_pairing_response(call); +} + +void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_err_t error) { + api::BluetoothDeviceUnpairingResponse call; + call.address = address; + call.success = success; + call.error = error; + + this->api_connection_->send_bluetooth_device_unpairing_response(call); +} + BluetoothProxy *global_bluetooth_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace bluetooth_proxy diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index a582abc8a3..97b6396b55 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -5,6 +5,7 @@ #include #include +#include "esphome/components/api/api_connection.h" #include "esphome/components/api/api_pb2.h" #include "esphome/components/esp32_ble_client/ble_client_base.h" #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" @@ -21,10 +22,33 @@ static const esp_err_t ESP_GATT_NOT_CONNECTED = -1; using namespace esp32_ble_client; +// Legacy versions: +// Version 1: Initial version without active connections +// Version 2: Support for active connections +// Version 3: New connection API +// Version 4: Pairing support +// Version 5: Cache clear support +static const uint32_t LEGACY_ACTIVE_CONNECTIONS_VERSION = 5; +static const uint32_t LEGACY_PASSIVE_ONLY_VERSION = 1; + +enum BluetoothProxyFeature : uint32_t { + FEATURE_PASSIVE_SCAN = 1 << 0, + FEATURE_ACTIVE_CONNECTIONS = 1 << 1, + FEATURE_REMOTE_CACHING = 1 << 2, + FEATURE_PAIRING = 1 << 3, + FEATURE_CACHE_CLEARING = 1 << 4, + FEATURE_RAW_ADVERTISEMENTS = 1 << 5, +}; + +enum BluetoothProxySubscriptionFlag : uint32_t { + SUBSCRIPTION_RAW_ADVERTISEMENTS = 1 << 0, +}; + class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Component { public: BluetoothProxy(); bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; + bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) override; void dump_config() override; void loop() override; @@ -44,6 +68,18 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com int get_bluetooth_connections_free(); int get_bluetooth_connections_limit() { return this->connections_.size(); } + void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags); + void unsubscribe_api_connection(api::APIConnection *api_connection); + api::APIConnection *get_api_connection() { return this->api_connection_; } + + void send_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK); + void send_connections_free(); + void send_gatt_services_done(uint64_t address); + void send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error); + void send_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK); + void send_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK); + void send_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK); + static void uint64_to_bd_addr(uint64_t address, esp_bd_addr_t bd_addr) { bd_addr[0] = (address >> 40) & 0xff; bd_addr[1] = (address >> 32) & 0xff; @@ -56,6 +92,27 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com void set_active(bool active) { this->active_ = active; } bool has_active() { return this->active_; } + uint32_t get_legacy_version() const { + if (this->active_) { + return LEGACY_ACTIVE_CONNECTIONS_VERSION; + } + return LEGACY_PASSIVE_ONLY_VERSION; + } + + uint32_t get_feature_flags() const { + uint32_t flags = 0; + flags |= BluetoothProxyFeature::FEATURE_PASSIVE_SCAN; + flags |= BluetoothProxyFeature::FEATURE_RAW_ADVERTISEMENTS; + if (this->active_) { + flags |= BluetoothProxyFeature::FEATURE_ACTIVE_CONNECTIONS; + flags |= BluetoothProxyFeature::FEATURE_REMOTE_CACHING; + flags |= BluetoothProxyFeature::FEATURE_PAIRING; + flags |= BluetoothProxyFeature::FEATURE_CACHE_CLEARING; + } + + return flags; + } + protected: void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device); @@ -64,18 +121,12 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com bool active_; std::vector connections_{}; + api::APIConnection *api_connection_{nullptr}; + bool raw_advertisements_{false}; }; extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -// Version 1: Initial version without active connections -// Version 2: Support for active connections -// Version 3: New connection API -// Version 4: Pairing support -// Version 5: Cache clear support -static const uint32_t ACTIVE_CONNECTIONS_VERSION = 5; -static const uint32_t PASSIVE_ONLY_VERSION = 1; - } // namespace bluetooth_proxy } // namespace esphome diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 21ec005e07..6c9124447a 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -244,6 +244,17 @@ void ESP32BLE::dump_config() { } } +uint64_t ble_addr_to_uint64(const esp_bd_addr_t address) { + uint64_t u = 0; + u |= uint64_t(address[0] & 0xFF) << 40; + u |= uint64_t(address[1] & 0xFF) << 32; + u |= uint64_t(address[2] & 0xFF) << 24; + u |= uint64_t(address[3] & 0xFF) << 16; + u |= uint64_t(address[4] & 0xFF) << 8; + u |= uint64_t(address[5] & 0xFF) << 0; + return u; +} + ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace esp32_ble diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 11ae826544..cde17da425 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -18,6 +18,8 @@ namespace esphome { namespace esp32_ble { +uint64_t ble_addr_to_uint64(const esp_bd_addr_t address); + // NOLINTNEXTLINE(modernize-use-using) typedef struct { void *peer_device; diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 26687ba9cc..0f6c4117d2 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -34,17 +34,6 @@ static const char *const TAG = "esp32_ble_tracker"; ESP32BLETracker *global_esp32_ble_tracker = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -uint64_t ble_addr_to_uint64(const esp_bd_addr_t address) { - uint64_t u = 0; - u |= uint64_t(address[0] & 0xFF) << 40; - u |= uint64_t(address[1] & 0xFF) << 32; - u |= uint64_t(address[2] & 0xFF) << 24; - u |= uint64_t(address[3] & 0xFF) << 16; - u |= uint64_t(address[4] & 0xFF) << 8; - u |= uint64_t(address[5] & 0xFF) << 0; - return u; -} - float ESP32BLETracker::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; } void ESP32BLETracker::setup() { @@ -114,10 +103,20 @@ void ESP32BLETracker::loop() { if (this->scan_result_index_ && // if it looks like we have a scan result we will take the lock xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) { uint32_t index = this->scan_result_index_; - if (index) { - if (index >= ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { - ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); - } + if (index >= ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { + ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); + } + + bool bulk_parsed = false; + + for (auto *listener : this->listeners_) { + bulk_parsed |= listener->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } + for (auto *client : this->clients_) { + bulk_parsed |= client->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } + + if (!bulk_parsed) { for (size_t i = 0; i < index; i++) { ESPBTDevice device; device.parse_scan_rst(this->scan_result_buffer_[i]); @@ -141,8 +140,8 @@ void ESP32BLETracker::loop() { this->print_bt_device_info(device); } } - this->scan_result_index_ = 0; } + this->scan_result_index_ = 0; xSemaphoreGive(this->scan_result_lock_); } @@ -585,7 +584,7 @@ std::string ESPBTDevice::address_str() const { this->address_[3], this->address_[4], this->address_[5]); return mac; } -uint64_t ESPBTDevice::address_uint64() const { return ble_addr_to_uint64(this->address_); } +uint64_t ESPBTDevice::address_uint64() const { return esp32_ble::ble_addr_to_uint64(this->address_); } void ESP32BLETracker::dump_config() { ESP_LOGCONFIG(TAG, "BLE Tracker:"); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 798f68f2bd..43e88fbf2b 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -113,6 +113,9 @@ class ESPBTDeviceListener { public: virtual void on_scan_end() {} virtual bool parse_device(const ESPBTDevice &device) = 0; + virtual bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) { + return false; + }; void set_parent(ESP32BLETracker *parent) { parent_ = parent; } protected: From 302dea4169ce574bc3ff89b53dcdda724ce4ec3f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:24:44 +1200 Subject: [PATCH 0061/2607] Move ESPTime into core esphome namespace (#4926) * Prep-work for datetime entities * Fix some includes and remove some restrictions on printing time on displays * format * format * More formatting * Move function contents * Ignore clang-tidy --- esphome/components/bedjet/bedjet_hub.cpp | 2 +- esphome/components/bedjet/bedjet_hub.h | 1 + .../deep_sleep/deep_sleep_component.h | 7 +- esphome/components/display/display_buffer.cpp | 13 +- esphome/components/display/display_buffer.h | 24 +-- esphome/components/ds1307/ds1307.cpp | 16 +- esphome/components/gps/time/gps_time.cpp | 2 +- esphome/components/lcd_base/lcd_display.cpp | 6 +- esphome/components/lcd_base/lcd_display.h | 13 +- esphome/components/max7219/max7219.cpp | 6 +- esphome/components/max7219/max7219.h | 12 +- .../components/max7219digit/max7219digit.cpp | 6 +- .../components/max7219digit/max7219digit.h | 13 +- esphome/components/nextion/nextion.h | 10 +- .../components/nextion/nextion_commands.cpp | 4 +- esphome/components/pcf85063/pcf85063.cpp | 2 +- esphome/components/sun/sun.cpp | 36 ++-- esphome/components/sun/sun.h | 18 +- .../sun/text_sensor/sun_text_sensor.h | 4 +- esphome/components/time/automation.cpp | 2 + esphome/components/time/automation.h | 4 +- esphome/components/time/real_time_clock.cpp | 166 ----------------- esphome/components/time/real_time_clock.h | 97 +--------- esphome/components/tm1637/tm1637.cpp | 6 +- esphome/components/tm1637/tm1637.h | 11 +- esphome/components/tm1638/tm1638.cpp | 6 +- esphome/components/tm1638/tm1638.h | 13 +- esphome/components/tuya/tuya.cpp | 2 +- esphome/components/tuya/tuya.h | 1 + esphome/core/time.cpp | 171 ++++++++++++++++++ esphome/core/time.h | 105 +++++++++++ 31 files changed, 376 insertions(+), 403 deletions(-) create mode 100644 esphome/core/time.cpp create mode 100644 esphome/core/time.h diff --git a/esphome/components/bedjet/bedjet_hub.cpp b/esphome/components/bedjet/bedjet_hub.cpp index fbd2876dc9..c355953d94 100644 --- a/esphome/components/bedjet/bedjet_hub.cpp +++ b/esphome/components/bedjet/bedjet_hub.cpp @@ -442,7 +442,7 @@ uint8_t BedJetHub::write_notify_config_descriptor_(bool enable) { void BedJetHub::send_local_time() { if (this->time_id_.has_value()) { auto *time_id = *this->time_id_; - time::ESPTime now = time_id->now(); + ESPTime now = time_id->now(); if (now.is_valid()) { this->set_clock(now.hour, now.minute); ESP_LOGD(TAG, "Using time component to set BedJet clock: %d:%02d", now.hour, now.minute); diff --git a/esphome/components/bedjet/bedjet_hub.h b/esphome/components/bedjet/bedjet_hub.h index 5809827cfa..bb1349b2ac 100644 --- a/esphome/components/bedjet/bedjet_hub.h +++ b/esphome/components/bedjet/bedjet_hub.h @@ -13,6 +13,7 @@ #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" +#include "esphome/core/time.h" #endif #include diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h index 8dc87cece8..2e54e53c56 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.h +++ b/esphome/components/deep_sleep/deep_sleep_component.h @@ -1,9 +1,9 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/helpers.h" #include "esphome/core/automation.h" +#include "esphome/core/component.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #ifdef USE_ESP32 #include @@ -11,6 +11,7 @@ #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" +#include "esphome/core/time.h" #endif namespace esphome { @@ -170,7 +171,7 @@ template class EnterDeepSleepAction : public Action { if (after_time) timestamp += 60 * 60 * 24; - int32_t offset = time::ESPTime::timezone_offset(); + int32_t offset = ESPTime::timezone_offset(); timestamp -= offset; // Change timestamp to utc const uint32_t ms_left = (timestamp - timestamp_now) * 1000; this->deep_sleep_->set_sleep_duration(ms_left); diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 0d76fa09ec..1be2950d68 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -3,9 +3,9 @@ #include #include "esphome/core/application.h" #include "esphome/core/color.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace display { @@ -490,24 +490,21 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) this->trigger(from, to); } -#ifdef USE_TIME -void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, - time::ESPTime time) { +void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) this->print(x, y, font, color, align, buffer); } -void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) { +void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time) { this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); } -void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) { +void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time) { this->strftime(x, y, font, COLOR_ON, align, format, time); } -void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, time::ESPTime time) { +void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, ESPTime time) { this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time); } -#endif void DisplayBuffer::start_clipping(Rect rect) { if (!this->clipping_rectangle_.empty()) { diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 2474d6f5a0..bcfe75f6b4 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -1,15 +1,12 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/defines.h" -#include "esphome/core/automation.h" -#include "display_color_utils.h" #include #include - -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif +#include "display_color_utils.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/time.h" #ifdef USE_GRAPH #include "esphome/components/graph/graph.h" @@ -263,7 +260,6 @@ class DisplayBuffer { */ void printf(int x, int y, Font *font, const char *format, ...) __attribute__((format(printf, 5, 6))); -#ifdef USE_TIME /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. * * @param x The x coordinate of the text alignment anchor point. @@ -274,7 +270,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time) + void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) __attribute__((format(strftime, 7, 0))); /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. @@ -286,7 +282,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) + void strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time) __attribute__((format(strftime, 6, 0))); /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. @@ -298,7 +294,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) + void strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time) __attribute__((format(strftime, 6, 0))); /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. @@ -309,9 +305,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, const char *format, time::ESPTime time) - __attribute__((format(strftime, 5, 0))); -#endif + void strftime(int x, int y, Font *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0))); /** Draw the `image` with the top-left corner at [x,y] to the screen. * diff --git a/esphome/components/ds1307/ds1307.cpp b/esphome/components/ds1307/ds1307.cpp index d249e9743a..472ccc7a9a 100644 --- a/esphome/components/ds1307/ds1307.cpp +++ b/esphome/components/ds1307/ds1307.cpp @@ -37,14 +37,14 @@ void DS1307Component::read_time() { ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); return; } - time::ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), - .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), - .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), - .day_of_week = uint8_t(ds1307_.reg.weekday), - .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), - .day_of_year = 1, // ignored by recalc_timestamp_utc(false) - .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), - .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)}; + ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), + .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), + .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), + .day_of_week = uint8_t(ds1307_.reg.weekday), + .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), + .day_of_year = 1, // ignored by recalc_timestamp_utc(false) + .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), + .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)}; rtc_time.recalc_timestamp_utc(false); if (!rtc_time.is_valid()) { ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); diff --git a/esphome/components/gps/time/gps_time.cpp b/esphome/components/gps/time/gps_time.cpp index e46f24ba8e..0f1b989f77 100644 --- a/esphome/components/gps/time/gps_time.cpp +++ b/esphome/components/gps/time/gps_time.cpp @@ -16,7 +16,7 @@ void GPSTime::from_tiny_gps_(TinyGPSPlus &tiny_gps) { if (tiny_gps.date.year() < 2019) return; - time::ESPTime val{}; + ESPTime val{}; val.year = tiny_gps.date.year(); val.month = tiny_gps.date.month(); val.day_of_month = tiny_gps.date.day(); diff --git a/esphome/components/lcd_base/lcd_display.cpp b/esphome/components/lcd_base/lcd_display.cpp index 180d5e93ac..65d7aa508f 100644 --- a/esphome/components/lcd_base/lcd_display.cpp +++ b/esphome/components/lcd_base/lcd_display.cpp @@ -158,15 +158,13 @@ void LCDDisplay::clear() { for (uint8_t i = 0; i < this->rows_ * this->columns_; i++) this->buffer_[i] = ' '; } -#ifdef USE_TIME -void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, time::ESPTime time) { +void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) this->print(column, row, buffer); } -void LCDDisplay::strftime(const char *format, time::ESPTime time) { this->strftime(0, 0, format, time); } -#endif +void LCDDisplay::strftime(const char *format, ESPTime time) { this->strftime(0, 0, format, time); } void LCDDisplay::loadchar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 this->command_(LCD_DISPLAY_COMMAND_SET_CGRAM_ADDR | (location << 3)); diff --git a/esphome/components/lcd_base/lcd_display.h b/esphome/components/lcd_base/lcd_display.h index c1dc54a9ed..473acb0bd3 100644 --- a/esphome/components/lcd_base/lcd_display.h +++ b/esphome/components/lcd_base/lcd_display.h @@ -1,11 +1,7 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/core/defines.h" - -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif +#include "esphome/core/time.h" #include #include @@ -44,13 +40,10 @@ class LCDDisplay : public PollingComponent { /// Evaluate the printf-format and print the text at column=0 and row=0. void printf(const char *format, ...) __attribute__((format(printf, 2, 3))); -#ifdef USE_TIME /// Evaluate the strftime-format and print the text at the specified column and row. - void strftime(uint8_t column, uint8_t row, const char *format, time::ESPTime time) - __attribute__((format(strftime, 4, 0))); + void strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) __attribute__((format(strftime, 4, 0))); /// Evaluate the strftime-format and print the text at column=0 and row=0. - void strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0))); -#endif + void strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0))); /// Load custom char to given location void loadchar(uint8_t location, uint8_t charmap[]); diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index b50a78eb96..38b4a165cb 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -223,16 +223,14 @@ void MAX7219Component::set_intensity(uint8_t intensity) { } void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; } -#ifdef USE_TIME -uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, time::ESPTime time) { +uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) return this->print(pos, buffer); return 0; } -uint8_t MAX7219Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); } -#endif +uint8_t MAX7219Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); } } // namespace max7219 } // namespace esphome diff --git a/esphome/components/max7219/max7219.h b/esphome/components/max7219/max7219.h index 47b54a4c50..1b724cef69 100644 --- a/esphome/components/max7219/max7219.h +++ b/esphome/components/max7219/max7219.h @@ -1,11 +1,7 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/core/defines.h" - -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif +#include "esphome/core/time.h" #include "esphome/components/spi/spi.h" @@ -46,13 +42,11 @@ class MAX7219Component : public PollingComponent, /// Print `str` at position 0. uint8_t print(const char *str); -#ifdef USE_TIME /// Evaluate the strftime-format and print the result at the given position. - uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0))); + uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0))); /// Evaluate the strftime-format and print the result at position 0. - uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0))); -#endif + uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0))); protected: void send_byte_(uint8_t a_register, uint8_t data); diff --git a/esphome/components/max7219digit/max7219digit.cpp b/esphome/components/max7219digit/max7219digit.cpp index c65b8e4823..7d21032b8a 100644 --- a/esphome/components/max7219digit/max7219digit.cpp +++ b/esphome/components/max7219digit/max7219digit.cpp @@ -325,18 +325,16 @@ uint8_t MAX7219Component::printdigitf(const char *format, ...) { return 0; } -#ifdef USE_TIME -uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, time::ESPTime time) { +uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) return this->printdigit(pos, buffer); return 0; } -uint8_t MAX7219Component::strftimedigit(const char *format, time::ESPTime time) { +uint8_t MAX7219Component::strftimedigit(const char *format, ESPTime time) { return this->strftimedigit(0, format, time); } -#endif } // namespace max7219digit } // namespace esphome diff --git a/esphome/components/max7219digit/max7219digit.h b/esphome/components/max7219digit/max7219digit.h index 17e369a9d9..93d2af21f9 100644 --- a/esphome/components/max7219digit/max7219digit.h +++ b/esphome/components/max7219digit/max7219digit.h @@ -1,16 +1,13 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/core/defines.h" +#include "esphome/core/time.h" + #include "esphome/components/display/display_buffer.h" #include "esphome/components/spi/spi.h" #include -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif - namespace esphome { namespace max7219digit { @@ -88,13 +85,11 @@ class MAX7219Component : public PollingComponent, /// Print `str` at position 0. uint8_t printdigit(const char *str); -#ifdef USE_TIME /// Evaluate the strftime-format and print the result at the given position. - uint8_t strftimedigit(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0))); + uint8_t strftimedigit(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0))); /// Evaluate the strftime-format and print the result at position 0. - uint8_t strftimedigit(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0))); -#endif + uint8_t strftimedigit(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0))); display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; } diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 86610ef564..28663138d7 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -4,6 +4,8 @@ #include #include "esphome/core/defines.h" +#include "esphome/core/time.h" + #include "esphome/components/uart/uart.h" #include "nextion_base.h" #include "nextion_component.h" @@ -19,10 +21,6 @@ #endif #endif -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif - namespace esphome { namespace nextion { @@ -318,13 +316,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Changes the font of the component named `textveiw`. Font IDs are set in the Nextion Editor. */ void set_component_font(const char *component, uint8_t font_id) override; -#ifdef USE_TIME /** * Send the current time to the nextion display. * @param time The time instance to send (get this with id(my_time).now() ). */ - void set_nextion_rtc_time(time::ESPTime time); -#endif + void set_nextion_rtc_time(ESPTime time); /** * Show the page with a given name. diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index 308e02bce8..0409e5ea6c 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -219,8 +219,7 @@ void Nextion::filled_circle(int center_x, int center_y, int radius, Color color) display::ColorUtil::color_to_565(color)); } -#ifdef USE_TIME -void Nextion::set_nextion_rtc_time(time::ESPTime time) { +void Nextion::set_nextion_rtc_time(ESPTime time) { this->add_no_result_to_queue_with_printf_("rtc0", "rtc0=%u", time.year); this->add_no_result_to_queue_with_printf_("rtc1", "rtc1=%u", time.month); this->add_no_result_to_queue_with_printf_("rtc2", "rtc2=%u", time.day_of_month); @@ -228,7 +227,6 @@ void Nextion::set_nextion_rtc_time(time::ESPTime time) { this->add_no_result_to_queue_with_printf_("rtc4", "rtc4=%u", time.minute); this->add_no_result_to_queue_with_printf_("rtc5", "rtc5=%u", time.second); } -#endif } // namespace nextion } // namespace esphome diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp index 5073522655..debc007cb8 100644 --- a/esphome/components/pcf85063/pcf85063.cpp +++ b/esphome/components/pcf85063/pcf85063.cpp @@ -37,7 +37,7 @@ void PCF85063Component::read_time() { ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); return; } - time::ESPTime rtc_time{ + ESPTime rtc_time{ .second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10), .minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10), .hour = uint8_t(pcf85063_.reg.hour + 10u * pcf85063_.reg.hour_10), diff --git a/esphome/components/sun/sun.cpp b/esphome/components/sun/sun.cpp index 5f9179682a..2fd9394a5e 100644 --- a/esphome/components/sun/sun.cpp +++ b/esphome/components/sun/sun.cpp @@ -37,7 +37,7 @@ num_t EquatorialCoordinate::declination_rad() const { return radians(declination num_t HorizontalCoordinate::elevation_rad() const { return radians(elevation); } num_t HorizontalCoordinate::azimuth_rad() const { return radians(azimuth); } -num_t julian_day(time::ESPTime moment) { +num_t julian_day(ESPTime moment) { // p. 59 // UT -> JD, TT -> JDE int y = moment.year; @@ -54,7 +54,7 @@ num_t julian_day(time::ESPTime moment) { int b = 2 - a + a / 4; return ((int) (365.25 * (y + 4716))) + ((int) (30.6001 * (m + 1))) + d + b - 1524.5; } -num_t delta_t(time::ESPTime moment) { +num_t delta_t(ESPTime moment) { // approximation for 2005-2050 from NASA (https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html) int t = moment.year - 2000; return 62.92 + t * (0.32217 + t * 0.005589); @@ -199,7 +199,7 @@ struct SunAtLocation { // see chapter 12, p. 87 num_t jd = moment.jd(); // eq 12.1, p.87; jd for 0h UT of this date - time::ESPTime moment_0h = moment.dt; + ESPTime moment_0h = moment.dt; moment_0h.hour = moment_0h.minute = moment_0h.second = 0; num_t jd0 = Moment{moment_0h}.jd(); num_t t = (jd0 - 2451545) / 36525; @@ -227,9 +227,9 @@ struct SunAtLocation { return HorizontalCoordinate{degrees(elevation_rad), degrees(azimuth_rad) + 180}; } - optional sunrise(time::ESPTime date, num_t zenith) const { return event(true, date, zenith); } - optional sunset(time::ESPTime date, num_t zenith) const { return event(false, date, zenith); } - optional event(bool rise, time::ESPTime date, num_t zenith) const { + optional sunrise(ESPTime date, num_t zenith) const { return event(true, date, zenith); } + optional sunset(ESPTime date, num_t zenith) const { return event(false, date, zenith); } + optional event(bool rise, ESPTime date, num_t zenith) const { // couldn't get the method described in chapter 15 to work, // so instead this is based on the algorithm in time4j // https://github.com/MenoData/Time4J/blob/master/base/src/main/java/net/time4j/calendar/astro/StdSolarCalculator.java @@ -244,7 +244,7 @@ struct SunAtLocation { new_h = *x; } while (std::abs(new_h - old_h) >= 15); time_t new_timestamp = m.timestamp + (time_t) new_h; - return time::ESPTime::from_epoch_local(new_timestamp); + return ESPTime::from_epoch_local(new_timestamp); } protected: @@ -263,14 +263,14 @@ struct SunAtLocation { return hour_angle; } - time::ESPTime local_event_(time::ESPTime date, int hour) const { + ESPTime local_event_(ESPTime date, int hour) const { // input date should be in UTC, and hour/minute/second fields 0 num_t added_d = hour / 24.0 - location.longitude / 360; num_t jd = julian_day(date) + added_d; num_t eot = SunAtTime(jd).equation_of_time() * 240; time_t new_timestamp = (time_t) (date.timestamp + added_d * 86400 - eot); - return time::ESPTime::from_epoch_utc(new_timestamp); + return ESPTime::from_epoch_utc(new_timestamp); } }; @@ -287,7 +287,7 @@ HorizontalCoordinate Sun::calc_coords_() { */ return sun.true_coordinate(m); } -optional Sun::calc_event_(time::ESPTime date, bool rising, double zenith) { +optional Sun::calc_event_(ESPTime date, bool rising, double zenith) { SunAtLocation sun{location_}; if (!date.is_valid()) return {}; @@ -301,24 +301,20 @@ optional Sun::calc_event_(time::ESPTime date, bool rising, double // We're calculating *next* sunrise/sunset, but calculated event // is today, so try again tomorrow time_t new_timestamp = today.timestamp + 24 * 60 * 60; - today = time::ESPTime::from_epoch_utc(new_timestamp); + today = ESPTime::from_epoch_utc(new_timestamp); it = sun.event(rising, today, zenith); } return it; } -optional Sun::calc_event_(bool rising, double zenith) { +optional Sun::calc_event_(bool rising, double zenith) { auto it = Sun::calc_event_(this->time_->utcnow(), rising, zenith); return it; } -optional Sun::sunrise(double elevation) { return this->calc_event_(true, 90 - elevation); } -optional Sun::sunset(double elevation) { return this->calc_event_(false, 90 - elevation); } -optional Sun::sunrise(time::ESPTime date, double elevation) { - return this->calc_event_(date, true, 90 - elevation); -} -optional Sun::sunset(time::ESPTime date, double elevation) { - return this->calc_event_(date, false, 90 - elevation); -} +optional Sun::sunrise(double elevation) { return this->calc_event_(true, 90 - elevation); } +optional Sun::sunset(double elevation) { return this->calc_event_(false, 90 - elevation); } +optional Sun::sunrise(ESPTime date, double elevation) { return this->calc_event_(date, true, 90 - elevation); } +optional Sun::sunset(ESPTime date, double elevation) { return this->calc_event_(date, false, 90 - elevation); } double Sun::elevation() { return this->calc_coords_().elevation; } double Sun::azimuth() { return this->calc_coords_().azimuth; } diff --git a/esphome/components/sun/sun.h b/esphome/components/sun/sun.h index 9547b2f280..de4801a655 100644 --- a/esphome/components/sun/sun.h +++ b/esphome/components/sun/sun.h @@ -1,8 +1,10 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include "esphome/core/automation.h" +#include "esphome/core/time.h" + #include "esphome/components/time/real_time_clock.h" namespace esphome { @@ -26,7 +28,7 @@ struct GeoLocation { }; struct Moment { - time::ESPTime dt; + ESPTime dt; num_t jd() const; num_t jde() const; @@ -57,18 +59,18 @@ class Sun { void set_latitude(double latitude) { location_.latitude = latitude; } void set_longitude(double longitude) { location_.longitude = longitude; } - optional sunrise(double elevation); - optional sunset(double elevation); - optional sunrise(time::ESPTime date, double elevation); - optional sunset(time::ESPTime date, double elevation); + optional sunrise(double elevation); + optional sunset(double elevation); + optional sunrise(ESPTime date, double elevation); + optional sunset(ESPTime date, double elevation); double elevation(); double azimuth(); protected: internal::HorizontalCoordinate calc_coords_(); - optional calc_event_(bool rising, double zenith); - optional calc_event_(time::ESPTime date, bool rising, double zenith); + optional calc_event_(bool rising, double zenith); + optional calc_event_(ESPTime date, bool rising, double zenith); time::RealTimeClock *time_; internal::GeoLocation location_; diff --git a/esphome/components/sun/text_sensor/sun_text_sensor.h b/esphome/components/sun/text_sensor/sun_text_sensor.h index ad01d64ff1..ce7d21fb86 100644 --- a/esphome/components/sun/text_sensor/sun_text_sensor.h +++ b/esphome/components/sun/text_sensor/sun_text_sensor.h @@ -1,6 +1,8 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/time.h" + #include "esphome/components/sun/sun.h" #include "esphome/components/text_sensor/text_sensor.h" @@ -15,7 +17,7 @@ class SunTextSensor : public text_sensor::TextSensor, public PollingComponent { void set_format(const std::string &format) { format_ = format; } void update() override { - optional res; + optional res; if (this->sunrise_) { res = this->parent_->sunrise(this->elevation_); } else { diff --git a/esphome/components/time/automation.cpp b/esphome/components/time/automation.cpp index af2b6c720c..f7c1916ffe 100644 --- a/esphome/components/time/automation.cpp +++ b/esphome/components/time/automation.cpp @@ -1,5 +1,7 @@ #include "automation.h" + #include "esphome/core/log.h" + #include namespace esphome { diff --git a/esphome/components/time/automation.h b/esphome/components/time/automation.h index e97413e420..b5c8291533 100644 --- a/esphome/components/time/automation.h +++ b/esphome/components/time/automation.h @@ -1,7 +1,9 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/time.h" + #include "real_time_clock.h" #include diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index de76676a4d..10fa9597b9 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -52,171 +52,5 @@ void RealTimeClock::apply_timezone_() { tzset(); } -size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { - struct tm c_tm = this->to_c_tm(); - return ::strftime(buffer, buffer_len, format, &c_tm); -} -ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) { - ESPTime res{}; - res.second = uint8_t(c_tm->tm_sec); - res.minute = uint8_t(c_tm->tm_min); - res.hour = uint8_t(c_tm->tm_hour); - res.day_of_week = uint8_t(c_tm->tm_wday + 1); - res.day_of_month = uint8_t(c_tm->tm_mday); - res.day_of_year = uint16_t(c_tm->tm_yday + 1); - res.month = uint8_t(c_tm->tm_mon + 1); - res.year = uint16_t(c_tm->tm_year + 1900); - res.is_dst = bool(c_tm->tm_isdst); - res.timestamp = c_time; - return res; -} -struct tm ESPTime::to_c_tm() { - struct tm c_tm {}; - c_tm.tm_sec = this->second; - c_tm.tm_min = this->minute; - c_tm.tm_hour = this->hour; - c_tm.tm_mday = this->day_of_month; - c_tm.tm_mon = this->month - 1; - c_tm.tm_year = this->year - 1900; - c_tm.tm_wday = this->day_of_week - 1; - c_tm.tm_yday = this->day_of_year - 1; - c_tm.tm_isdst = this->is_dst; - return c_tm; -} -std::string ESPTime::strftime(const std::string &format) { - std::string timestr; - timestr.resize(format.size() * 4); - struct tm c_tm = this->to_c_tm(); - size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); - while (len == 0) { - timestr.resize(timestr.size() * 2); - len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); - } - timestr.resize(len); - return timestr; -} - -template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end) { - current++; - if (current >= end) { - current = begin; - return true; - } - return false; -} - -static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } - -static uint8_t days_in_month(uint8_t month, uint16_t year) { - static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - uint8_t days = DAYS_IN_MONTH[month]; - if (month == 2 && is_leap_year(year)) - return 29; - return days; -} - -void ESPTime::increment_second() { - this->timestamp++; - if (!increment_time_value(this->second, 0, 60)) - return; - - // second roll-over, increment minute - if (!increment_time_value(this->minute, 0, 60)) - return; - - // minute roll-over, increment hour - if (!increment_time_value(this->hour, 0, 24)) - return; - - // hour roll-over, increment day - increment_time_value(this->day_of_week, 1, 8); - - if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) { - // day of month roll-over, increment month - increment_time_value(this->month, 1, 13); - } - - uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365; - if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) { - // day of year roll-over, increment year - this->year++; - } -} -void ESPTime::increment_day() { - this->timestamp += 86400; - - // increment day - increment_time_value(this->day_of_week, 1, 8); - - if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) { - // day of month roll-over, increment month - increment_time_value(this->month, 1, 13); - } - - uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365; - if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) { - // day of year roll-over, increment year - this->year++; - } -} -void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { - time_t res = 0; - - if (!this->fields_in_range()) { - this->timestamp = -1; - return; - } - - for (int i = 1970; i < this->year; i++) - res += is_leap_year(i) ? 366 : 365; - - if (use_day_of_year) { - res += this->day_of_year - 1; - } else { - for (int i = 1; i < this->month; i++) - res += days_in_month(i, this->year); - - res += this->day_of_month - 1; - } - - res *= 24; - res += this->hour; - res *= 60; - res += this->minute; - res *= 60; - res += this->second; - this->timestamp = res; -} - -int32_t ESPTime::timezone_offset() { - int32_t offset = 0; - time_t now = ::time(nullptr); - auto local = ESPTime::from_epoch_local(now); - auto utc = ESPTime::from_epoch_utc(now); - bool negative = utc.hour > local.hour && local.day_of_year <= utc.day_of_year; - - if (utc.minute > local.minute) { - local.minute += 60; - local.hour -= 1; - } - offset += (local.minute - utc.minute) * 60; - - if (negative) { - offset -= (utc.hour - local.hour) * 3600; - } else { - if (utc.hour > local.hour) { - local.hour += 24; - } - offset += (local.hour - utc.hour) * 3600; - } - return offset; -} - -bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; } -bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; } -bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; } -bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; } -bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; } - } // namespace time } // namespace esphome diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 7f4afee306..a17168ae6f 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -1,106 +1,15 @@ #pragma once +#include +#include #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include -#include -#include +#include "esphome/core/time.h" namespace esphome { namespace time { -/// A more user-friendly version of struct tm from time.h -struct ESPTime { - /** seconds after the minute [0-60] - * @note second is generally 0-59; the extra range is to accommodate leap seconds. - */ - uint8_t second; - /// minutes after the hour [0-59] - uint8_t minute; - /// hours since midnight [0-23] - uint8_t hour; - /// day of the week; sunday=1 [1-7] - uint8_t day_of_week; - /// day of the month [1-31] - uint8_t day_of_month; - /// day of the year [1-366] - uint16_t day_of_year; - /// month; january=1 [1-12] - uint8_t month; - /// year - uint16_t year; - /// daylight saving time flag - bool is_dst; - /// unix epoch time (seconds since UTC Midnight January 1, 1970) - time_t timestamp; - - /** Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument. - * Up to buffer_len bytes are written. - * - * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime - */ - size_t strftime(char *buffer, size_t buffer_len, const char *format); - - /** Convert this ESPTime struct to a string as specified by the format argument. - * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime - * - * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some - * microcontrollers. - */ - std::string strftime(const std::string &format); - - /// Check if this ESPTime is valid (all fields in range and year is greater than 2018) - bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); } - - /// Check if all time fields of this ESPTime are in range. - bool fields_in_range() const { - return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 && - this->day_of_week < 8 && this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 && - this->day_of_year < 367 && this->month > 0 && this->month < 13; - } - - /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. - static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); - - /** Convert an UTC epoch timestamp to a local time ESPTime instance. - * - * @param epoch Seconds since 1st January 1970. In UTC. - * @return The generated ESPTime - */ - static ESPTime from_epoch_local(time_t epoch) { - struct tm *c_tm = ::localtime(&epoch); - return ESPTime::from_c_tm(c_tm, epoch); - } - /** Convert an UTC epoch timestamp to a UTC time ESPTime instance. - * - * @param epoch Seconds since 1st January 1970. In UTC. - * @return The generated ESPTime - */ - static ESPTime from_epoch_utc(time_t epoch) { - struct tm *c_tm = ::gmtime(&epoch); - return ESPTime::from_c_tm(c_tm, epoch); - } - - /// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC). - void recalc_timestamp_utc(bool use_day_of_year = true); - - /// Convert this ESPTime instance back to a tm struct. - struct tm to_c_tm(); - - static int32_t timezone_offset(); - - /// Increment this clock instance by one second. - void increment_second(); - /// Increment this clock instance by one day. - void increment_day(); - bool operator<(ESPTime other); - bool operator<=(ESPTime other); - bool operator==(ESPTime other); - bool operator>=(ESPTime other); - bool operator>(ESPTime other); -}; - /// The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock. /// /// \note diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 5b8cbc6004..434c6e65f3 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -368,16 +368,14 @@ uint8_t TM1637Display::printf(const char *format, ...) { return 0; } -#ifdef USE_TIME -uint8_t TM1637Display::strftime(uint8_t pos, const char *format, time::ESPTime time) { +uint8_t TM1637Display::strftime(uint8_t pos, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) return this->print(pos, buffer); return 0; } -uint8_t TM1637Display::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); } -#endif +uint8_t TM1637Display::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); } } // namespace tm1637 } // namespace esphome diff --git a/esphome/components/tm1637/tm1637.h b/esphome/components/tm1637/tm1637.h index 2fb572bc55..aba0071b12 100644 --- a/esphome/components/tm1637/tm1637.h +++ b/esphome/components/tm1637/tm1637.h @@ -3,13 +3,10 @@ #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/hal.h" +#include "esphome/core/time.h" #include -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif - #ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" #endif @@ -61,12 +58,10 @@ class TM1637Display : public PollingComponent { void add_tm1637_key(TM1637Key *tm1637_key) { this->tm1637_keys_.push_back(tm1637_key); } #endif -#ifdef USE_TIME /// Evaluate the strftime-format and print the result at the given position. - uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0))); + uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0))); /// Evaluate the strftime-format and print the result at position 0. - uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0))); -#endif + uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0))); protected: void bit_delay_(); diff --git a/esphome/components/tm1638/tm1638.cpp b/esphome/components/tm1638/tm1638.cpp index 24cb4122bf..a15b006046 100644 --- a/esphome/components/tm1638/tm1638.cpp +++ b/esphome/components/tm1638/tm1638.cpp @@ -211,16 +211,14 @@ uint8_t TM1638Component::printf(const char *format, ...) { return 0; } -#ifdef USE_TIME -uint8_t TM1638Component::strftime(uint8_t pos, const char *format, time::ESPTime time) { +uint8_t TM1638Component::strftime(uint8_t pos, const char *format, ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) return this->print(pos, buffer); return 0; } -uint8_t TM1638Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); } -#endif +uint8_t TM1638Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); } //////////////// SPI //////////////// diff --git a/esphome/components/tm1638/tm1638.h b/esphome/components/tm1638/tm1638.h index 2e1ac6fad3..add72cfdf3 100644 --- a/esphome/components/tm1638/tm1638.h +++ b/esphome/components/tm1638/tm1638.h @@ -1,16 +1,13 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/defines.h" -#include "esphome/core/automation.h" #include "esphome/core/hal.h" +#include "esphome/core/time.h" #include -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif - namespace esphome { namespace tm1638 { @@ -52,12 +49,10 @@ class TM1638Component : public PollingComponent { void loop() override; uint8_t get_keys(); -#ifdef USE_TIME /// Evaluate the strftime-format and print the result at the given position. - uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0))); + uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0))); /// Evaluate the strftime-format and print the result at position 0. - uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0))); -#endif + uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0))); void set_led(int led_pos, bool led_on_off); diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 040b9b7ed5..7e6b1d53fe 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -508,7 +508,7 @@ void Tuya::send_wifi_status_() { void Tuya::send_local_time_() { std::vector payload; auto *time_id = *this->time_id_; - time::ESPTime now = time_id->now(); + ESPTime now = time_id->now(); if (now.is_valid()) { uint8_t year = now.year - 2000; uint8_t month = now.month; diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index 8d6153482f..b9901dd5e7 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -7,6 +7,7 @@ #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" +#include "esphome/core/time.h" #endif #include diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp new file mode 100644 index 0000000000..c03506fd2a --- /dev/null +++ b/esphome/core/time.cpp @@ -0,0 +1,171 @@ +#include "time.h" // NOLINT + +namespace esphome { + +size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { + struct tm c_tm = this->to_c_tm(); + return ::strftime(buffer, buffer_len, format, &c_tm); +} +ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) { + ESPTime res{}; + res.second = uint8_t(c_tm->tm_sec); + res.minute = uint8_t(c_tm->tm_min); + res.hour = uint8_t(c_tm->tm_hour); + res.day_of_week = uint8_t(c_tm->tm_wday + 1); + res.day_of_month = uint8_t(c_tm->tm_mday); + res.day_of_year = uint16_t(c_tm->tm_yday + 1); + res.month = uint8_t(c_tm->tm_mon + 1); + res.year = uint16_t(c_tm->tm_year + 1900); + res.is_dst = bool(c_tm->tm_isdst); + res.timestamp = c_time; + return res; +} +struct tm ESPTime::to_c_tm() { + struct tm c_tm {}; + c_tm.tm_sec = this->second; + c_tm.tm_min = this->minute; + c_tm.tm_hour = this->hour; + c_tm.tm_mday = this->day_of_month; + c_tm.tm_mon = this->month - 1; + c_tm.tm_year = this->year - 1900; + c_tm.tm_wday = this->day_of_week - 1; + c_tm.tm_yday = this->day_of_year - 1; + c_tm.tm_isdst = this->is_dst; + return c_tm; +} +std::string ESPTime::strftime(const std::string &format) { + std::string timestr; + timestr.resize(format.size() * 4); + struct tm c_tm = this->to_c_tm(); + size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); + while (len == 0) { + timestr.resize(timestr.size() * 2); + len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); + } + timestr.resize(len); + return timestr; +} + +void ESPTime::increment_second() { + this->timestamp++; + if (!increment_time_value(this->second, 0, 60)) + return; + + // second roll-over, increment minute + if (!increment_time_value(this->minute, 0, 60)) + return; + + // minute roll-over, increment hour + if (!increment_time_value(this->hour, 0, 24)) + return; + + // hour roll-over, increment day + increment_time_value(this->day_of_week, 1, 8); + + if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) { + // day of month roll-over, increment month + increment_time_value(this->month, 1, 13); + } + + uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365; + if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) { + // day of year roll-over, increment year + this->year++; + } +} +void ESPTime::increment_day() { + this->timestamp += 86400; + + // increment day + increment_time_value(this->day_of_week, 1, 8); + + if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) { + // day of month roll-over, increment month + increment_time_value(this->month, 1, 13); + } + + uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365; + if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) { + // day of year roll-over, increment year + this->year++; + } +} +void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { + time_t res = 0; + + if (!this->fields_in_range()) { + this->timestamp = -1; + return; + } + + for (int i = 1970; i < this->year; i++) + res += is_leap_year(i) ? 366 : 365; + + if (use_day_of_year) { + res += this->day_of_year - 1; + } else { + for (int i = 1; i < this->month; i++) + res += days_in_month(i, this->year); + + res += this->day_of_month - 1; + } + + res *= 24; + res += this->hour; + res *= 60; + res += this->minute; + res *= 60; + res += this->second; + this->timestamp = res; +} + +int32_t ESPTime::timezone_offset() { + int32_t offset = 0; + time_t now = ::time(nullptr); + auto local = ESPTime::from_epoch_local(now); + auto utc = ESPTime::from_epoch_utc(now); + bool negative = utc.hour > local.hour && local.day_of_year <= utc.day_of_year; + + if (utc.minute > local.minute) { + local.minute += 60; + local.hour -= 1; + } + offset += (local.minute - utc.minute) * 60; + + if (negative) { + offset -= (utc.hour - local.hour) * 3600; + } else { + if (utc.hour > local.hour) { + local.hour += 24; + } + offset += (local.hour - utc.hour) * 3600; + } + return offset; +} + +bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; } +bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; } +bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; } +bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; } +bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; } + +template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end) { + current++; + if (current >= end) { + current = begin; + return true; + } + return false; +} + +static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } + +static uint8_t days_in_month(uint8_t month, uint16_t year) { + static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + uint8_t days = DAYS_IN_MONTH[month]; + if (month == 2 && is_leap_year(year)) + return 29; + return days; +} + +} // namespace esphome diff --git a/esphome/core/time.h b/esphome/core/time.h new file mode 100644 index 0000000000..e1bdc8c839 --- /dev/null +++ b/esphome/core/time.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include + +namespace esphome { + +template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end); + +static bool is_leap_year(uint32_t year); + +static uint8_t days_in_month(uint8_t month, uint16_t year); + +/// A more user-friendly version of struct tm from time.h +struct ESPTime { + /** seconds after the minute [0-60] + * @note second is generally 0-59; the extra range is to accommodate leap seconds. + */ + uint8_t second; + /// minutes after the hour [0-59] + uint8_t minute; + /// hours since midnight [0-23] + uint8_t hour; + /// day of the week; sunday=1 [1-7] + uint8_t day_of_week; + /// day of the month [1-31] + uint8_t day_of_month; + /// day of the year [1-366] + uint16_t day_of_year; + /// month; january=1 [1-12] + uint8_t month; + /// year + uint16_t year; + /// daylight saving time flag + bool is_dst; + /// unix epoch time (seconds since UTC Midnight January 1, 1970) + time_t timestamp; + + /** Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument. + * Up to buffer_len bytes are written. + * + * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime + */ + size_t strftime(char *buffer, size_t buffer_len, const char *format); + + /** Convert this ESPTime struct to a string as specified by the format argument. + * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime + * + * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some + * microcontrollers. + */ + std::string strftime(const std::string &format); + + /// Check if this ESPTime is valid (all fields in range and year is greater than 2018) + bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); } + + /// Check if all time fields of this ESPTime are in range. + bool fields_in_range() const { + return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 && + this->day_of_week < 8 && this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 && + this->day_of_year < 367 && this->month > 0 && this->month < 13; + } + + /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. + static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); + + /** Convert an UTC epoch timestamp to a local time ESPTime instance. + * + * @param epoch Seconds since 1st January 1970. In UTC. + * @return The generated ESPTime + */ + static ESPTime from_epoch_local(time_t epoch) { + struct tm *c_tm = ::localtime(&epoch); + return ESPTime::from_c_tm(c_tm, epoch); + } + /** Convert an UTC epoch timestamp to a UTC time ESPTime instance. + * + * @param epoch Seconds since 1st January 1970. In UTC. + * @return The generated ESPTime + */ + static ESPTime from_epoch_utc(time_t epoch) { + struct tm *c_tm = ::gmtime(&epoch); + return ESPTime::from_c_tm(c_tm, epoch); + } + + /// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC). + void recalc_timestamp_utc(bool use_day_of_year = true); + + /// Convert this ESPTime instance back to a tm struct. + struct tm to_c_tm(); + + static int32_t timezone_offset(); + + /// Increment this clock instance by one second. + void increment_second(); + /// Increment this clock instance by one day. + void increment_day(); + bool operator<(ESPTime other); + bool operator<=(ESPTime other); + bool operator==(ESPTime other); + bool operator>=(ESPTime other); + bool operator>(ESPTime other); +}; +} // namespace esphome From 5f0892dec43a4c1fdbb3d3853bac0f2a0fee1bbd Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Fri, 9 Jun 2023 02:53:30 +0200 Subject: [PATCH 0062/2607] Allow multiple MAC addresses for 'on_ble_advertise' filter (#4773) --- esphome/components/esp32_ble_tracker/__init__.py | 7 +++++-- esphome/components/esp32_ble_tracker/automation.h | 12 ++++++++---- tests/test2.yaml | 8 ++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 23f109b5ac..30589f1a3f 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -167,7 +167,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_ON_BLE_ADVERTISE): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPBTAdvertiseTrigger), - cv.Optional(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_MAC_ADDRESS): cv.ensure_list(cv.mac_address), } ), cv.Optional(CONF_ON_BLE_SERVICE_DATA_ADVERTISE): automation.validate_automation( @@ -223,7 +223,10 @@ async def to_code(config): for conf in config.get(CONF_ON_BLE_ADVERTISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) if CONF_MAC_ADDRESS in conf: - cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex)) + addr_list = [] + for it in conf[CONF_MAC_ADDRESS]: + addr_list.append(it.as_hex) + cg.add(trigger.set_addresses(addr_list)) await automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf) for conf in config.get(CONF_ON_BLE_SERVICE_DATA_ADVERTISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) diff --git a/esphome/components/esp32_ble_tracker/automation.h b/esphome/components/esp32_ble_tracker/automation.h index 6131d6ddf7..6bef9edcb3 100644 --- a/esphome/components/esp32_ble_tracker/automation.h +++ b/esphome/components/esp32_ble_tracker/automation.h @@ -10,18 +10,22 @@ namespace esp32_ble_tracker { class ESPBTAdvertiseTrigger : public Trigger, public ESPBTDeviceListener { public: explicit ESPBTAdvertiseTrigger(ESP32BLETracker *parent) { parent->register_listener(this); } - void set_address(uint64_t address) { this->address_ = address; } + void set_addresses(const std::vector &addresses) { this->address_vec_ = addresses; } bool parse_device(const ESPBTDevice &device) override { - if (this->address_ && device.address_uint64() != this->address_) { - return false; + uint64_t u64_addr = device.address_uint64(); + if (!address_vec_.empty()) { + if (std::find(address_vec_.begin(), address_vec_.end(), u64_addr) == address_vec_.end()) { + return false; + } } + this->trigger(device); return true; } protected: - uint64_t address_ = 0; + std::vector address_vec_; }; class BLEServiceDataAdvertiseTrigger : public Trigger, public ESPBTDeviceListener { diff --git a/tests/test2.yaml b/tests/test2.yaml index 0dae0b2570..2873d0e8e0 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -488,6 +488,14 @@ binary_sensor: esp32_ble_tracker: on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length - mac_address: AC:37:43:77:5F:4C then: # yamllint disable rule:line-length From c74105aad78a88e7f518e5e720db4eb1c58aeed8 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sun, 11 Jun 2023 23:36:37 +0200 Subject: [PATCH 0063/2607] Add SVG image support (#4922) --- esphome/components/image/__init__.py | 53 +++++++++++++++++----------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 113c5a2df1..e7cf492c7b 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -199,6 +199,27 @@ IMAGE_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) +def load_svg_image(file: str, resize: tuple[int, int]): + from PIL import Image + + # This import is only needed in case of SVG images; adding it + # to the top would force configurations not using SVG to also have it + # installed for no reason. + from cairosvg import svg2png + + if resize: + req_width, req_height = resize + svg_image = svg2png( + url=file, + output_width=req_width, + output_height=req_height, + ) + else: + svg_image = svg2png(url=file) + + return Image.open(io.BytesIO(svg_image)) + + async def to_code(config): from PIL import Image @@ -206,30 +227,20 @@ async def to_code(config): if conf_file[CONF_SOURCE] == SOURCE_LOCAL: path = CORE.relative_config_path(conf_file[CONF_PATH]) - try: - image = Image.open(path) - except Exception as e: - raise core.EsphomeError(f"Could not load image file {path}: {e}") - if CONF_RESIZE in config: - image.thumbnail(config[CONF_RESIZE]) + elif conf_file[CONF_SOURCE] == SOURCE_MDI: - # Those imports are only needed in case of MDI images; adding them - # to the top would force configurations not using MDI to also have them - # installed for no reason. - from cairosvg import svg2png + path = _compute_local_icon_path(conf_file).as_posix() - svg_file = _compute_local_icon_path(conf_file) - if CONF_RESIZE in config: - req_width, req_height = config[CONF_RESIZE] - svg_image = svg2png( - url=svg_file.as_posix(), - output_width=req_width, - output_height=req_height, - ) + try: + resize = config.get(CONF_RESIZE) + if path.lower().endswith(".svg"): + image = load_svg_image(path, resize) else: - svg_image = svg2png(url=svg_file.as_posix()) - - image = Image.open(io.BytesIO(svg_image)) + image = Image.open(path) + if resize: + image.thumbnail(resize) + except Exception as e: + raise core.EsphomeError(f"Could not load image file {path}: {e}") width, height = image.size From b9e7fdd2b02d25993a55912d05c356f47957a42c Mon Sep 17 00:00:00 2001 From: jimtng <2554958+jimtng@users.noreply.github.com> Date: Mon, 12 Jun 2023 11:31:00 +1000 Subject: [PATCH 0064/2607] Add !extend to devcontainer's customTags (#4749) --- .devcontainer/devcontainer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b3fa6d4932..ab4f8cc960 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -40,6 +40,7 @@ "yaml.customTags": [ "!secret scalar", "!lambda scalar", + "!extend scalar", "!include_dir_named scalar", "!include_dir_list scalar", "!include_dir_merge_list scalar", From 0a407c542588c2a25184641aac2e4d29a31e1fe5 Mon Sep 17 00:00:00 2001 From: Pascal Date: Mon, 12 Jun 2023 06:59:25 +0200 Subject: [PATCH 0065/2607] =?UTF-8?q?[max7219digit]=20fix=20270=C2=B0=20ro?= =?UTF-8?q?tation=20(#4930)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/max7219digit/max7219digit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/max7219digit/max7219digit.cpp b/esphome/components/max7219digit/max7219digit.cpp index 7d21032b8a..ec9970d1a0 100644 --- a/esphome/components/max7219digit/max7219digit.cpp +++ b/esphome/components/max7219digit/max7219digit.cpp @@ -278,7 +278,9 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) { } } } else { - b = pixels[7 - col]; + for (uint8_t i = 0; i < 8; i++) { + b |= ((pixels[7 - col] >> i) & 1) << (7 - i); + } } // send this byte to display at selected chip if (this->invert_) { From f7c0ec65959723c7ec63fe9cce2add83c95268ed Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:00:34 +1200 Subject: [PATCH 0066/2607] proto generation updates (#4653) --- .vscode/tasks.json | 18 ++++++++++++++++++ requirements_test.txt | 2 ++ script/api_protobuf/api_protobuf.py | 17 +++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 307dd496f0..acf1f29410 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -36,6 +36,24 @@ ] } ] + }, + { + "label": "Generate proto files", + "type": "shell", + "command": "${command:python.interpreterPath}", + "args": [ + "./script/api_protobuf/api_protobuf.py" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "never", + "close": true, + "panel": "new" + }, + "problemMatcher": [] } ] } diff --git a/requirements_test.txt b/requirements_test.txt index c099250bd7..d5235d733b 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -11,3 +11,5 @@ pytest-mock==3.10.0 pytest-asyncio==0.21.0 asyncmock==0.4.2 hypothesis==5.49.0 + +clang-format==13.0.1 ; platform_machine != 'armv7l' diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index dba6f47d43..5a0c92350d 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -18,6 +18,7 @@ will be generated, they still need to be formatted """ import re +import os from pathlib import Path from textwrap import dedent from subprocess import call @@ -944,3 +945,19 @@ with open(root / "api_pb2_service.cpp", "w") as f: f.write(cpp) prot.unlink() + +try: + import clang_format + + def exec_clang_format(path): + clang_format_path = os.path.join( + os.path.dirname(clang_format.__file__), "data", "bin", "clang-format" + ) + call([clang_format_path, "-i", path]) + + exec_clang_format(root / "api_pb2_service.h") + exec_clang_format(root / "api_pb2_service.cpp") + exec_clang_format(root / "api_pb2.h") + exec_clang_format(root / "api_pb2.cpp") +except ImportError: + pass From 5afdb1e97fc045a7596f158d59038dcb0797603d Mon Sep 17 00:00:00 2001 From: Carlos Cordero Date: Mon, 12 Jun 2023 21:48:01 +0200 Subject: [PATCH 0067/2607] I2S media player allow setting communication format for external DACs (#4918) Co-authored-by: Carlos Cordero --- esphome/components/i2s_audio/media_player/__init__.py | 7 +++++++ .../i2s_audio/media_player/i2s_audio_media_player.cpp | 1 + .../i2s_audio/media_player/i2s_audio_media_player.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/esphome/components/i2s_audio/media_player/__init__.py b/esphome/components/i2s_audio/media_player/__init__.py index dfc3fb2be2..600a308e6c 100644 --- a/esphome/components/i2s_audio/media_player/__init__.py +++ b/esphome/components/i2s_audio/media_player/__init__.py @@ -27,6 +27,7 @@ i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") CONF_MUTE_PIN = "mute_pin" CONF_AUDIO_ID = "audio_id" CONF_DAC_TYPE = "dac_type" +CONF_I2S_COMM_FMT = "i2s_comm_fmt" INTERNAL_DAC_OPTIONS = { "left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, @@ -38,6 +39,8 @@ EXTERNAL_DAC_OPTIONS = ["mono", "stereo"] NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] +I2C_COMM_FMT_OPTIONS = ["lsb", "msb"] + def validate_esp32_variant(config): if config[CONF_DAC_TYPE] != "internal": @@ -69,6 +72,9 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MODE, default="mono"): cv.one_of( *EXTERNAL_DAC_OPTIONS, lower=True ), + cv.Optional(CONF_I2S_COMM_FMT, default="msb"): cv.one_of( + *I2C_COMM_FMT_OPTIONS, lower=True + ), } ).extend(cv.COMPONENT_SCHEMA), }, @@ -94,6 +100,7 @@ async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_MUTE_PIN]) cg.add(var.set_mute_pin(pin)) cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) + cg.add(var.set_i2s_comm_fmt_lsb(config[CONF_I2S_COMM_FMT] == "lsb")) cg.add_library("WiFiClientSecure", None) cg.add_library("HTTPClient", None) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 6eaa32c23c..9e2e3f136a 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -148,6 +148,7 @@ void I2SAudioMediaPlayer::start_() { pin_config.data_out_num = this->dout_pin_; i2s_set_pin(this->parent_->get_port(), &pin_config); + this->audio_->setI2SCommFMT_LSB(this->i2s_comm_fmt_lsb_); this->audio_->forceMono(this->external_dac_channels_ == 1); if (this->mute_pin_ != nullptr) { this->mute_pin_->setup(); diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index dab9a85d7c..092e6de8e8 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -39,6 +39,8 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, #endif void set_external_dac_channels(uint8_t channels) { this->external_dac_channels_ = channels; } + void set_i2s_comm_fmt_lsb(bool lsb) { this->i2s_comm_fmt_lsb_ = lsb; } + media_player::MediaPlayerTraits get_traits() override; bool is_muted() const override { return this->muted_; } @@ -71,6 +73,8 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, #endif uint8_t external_dac_channels_; + bool i2s_comm_fmt_lsb_; + HighFrequencyLoopRequester high_freq_; optional current_url_{}; From 035c3ef8fe655e9592a49b907a270f15d09aafa3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:30:40 +1200 Subject: [PATCH 0068/2607] Add MULTI_CONF to pn53_i2c (#4938) --- esphome/components/pn532_i2c/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/pn532_i2c/__init__.py b/esphome/components/pn532_i2c/__init__.py index 36af2f8aa0..f7b8743967 100644 --- a/esphome/components/pn532_i2c/__init__.py +++ b/esphome/components/pn532_i2c/__init__.py @@ -6,6 +6,7 @@ from esphome.const import CONF_ID AUTO_LOAD = ["pn532"] CODEOWNERS = ["@OttoWinter", "@jesserockz"] DEPENDENCIES = ["i2c"] +MULTI_CONF = True pn532_i2c_ns = cg.esphome_ns.namespace("pn532_i2c") PN532I2C = pn532_i2c_ns.class_("PN532I2C", pn532.PN532, i2c.I2CDevice) From cef659b0deaa27763745251c2d651eebf1781d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Wed, 14 Jun 2023 23:50:24 +0200 Subject: [PATCH 0069/2607] display: Improve Image rendering by removing usage of virtual functions (#4931) --- esphome/components/display/display_buffer.cpp | 101 ++++++------------ esphome/components/display/display_buffer.h | 18 ++-- 2 files changed, 39 insertions(+), 80 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 1be2950d68..ebeb4ce1bf 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -15,6 +15,25 @@ static const char *const TAG = "display"; const Color COLOR_OFF(0, 0, 0, 255); const Color COLOR_ON(255, 255, 255, 255); +static int image_type_to_bpp(ImageType type) { + switch (type) { + case IMAGE_TYPE_BINARY: + return 1; + case IMAGE_TYPE_GRAYSCALE: + return 8; + case IMAGE_TYPE_RGB565: + return 16; + case IMAGE_TYPE_RGB24: + return 24; + case IMAGE_TYPE_RGBA: + return 32; + default: + return 0; + } +} + +static int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } + void Rect::expand(int16_t horizontal, int16_t vertical) { if (this->is_set() && (this->w >= (-2 * horizontal)) && (this->h >= (-2 * vertical))) { this->x = this->x - horizontal; @@ -699,78 +718,9 @@ Image::Image(const uint8_t *data_start, int width, int height, ImageType type) : width_(width), height_(height), type_(type), data_start_(data_start) {} int Image::get_current_frame() const { return 0; } -bool Animation::get_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return false; - const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; - const uint32_t frame_index = this->height_ * width_8 * this->current_frame_; - if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) - return false; - const uint32_t pos = x + y * width_8 + frame_index; - return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); -} -Color Animation::get_rgba_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; - const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) - return Color::BLACK; - const uint32_t pos = (x + y * this->width_ + frame_index) * 4; - return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); -} -Color Animation::get_color_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; - const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) - return Color::BLACK; - const uint32_t pos = (x + y * this->width_ + frame_index) * 3; - Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2)); - if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) { - // (0, 0, 1) has been defined as transparent color for non-alpha images. - // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if) - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Animation::get_rgb565_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; - const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) - return Color::BLACK; - const uint32_t pos = (x + y * this->width_ + frame_index) * 2; - uint16_t rgb565 = - progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); - auto r = (rgb565 & 0xF800) >> 11; - auto g = (rgb565 & 0x07E0) >> 5; - auto b = rgb565 & 0x001F; - Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); - if (rgb565 == 0x0020 && transparent_) { - // darkest green has been defined as transparent color for transparent RGB565 images. - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Animation::get_grayscale_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; - const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) - return Color::BLACK; - const uint32_t pos = (x + y * this->width_ + frame_index); - const uint8_t gray = progmem_read_byte(this->data_start_ + pos); - uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; - return Color(gray, gray, gray, alpha); -} Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) : Image(data_start, width, height, type), + animation_data_start_(data_start), current_frame_(0), animation_frame_count_(animation_frame_count), loop_start_frame_(0), @@ -797,12 +747,16 @@ void Animation::next_frame() { this->loop_current_iteration_ = 1; this->current_frame_ = 0; } + + this->update_data_start_(); } void Animation::prev_frame() { this->current_frame_--; if (this->current_frame_ < 0) { this->current_frame_ = this->animation_frame_count_ - 1; } + + this->update_data_start_(); } void Animation::set_frame(int frame) { @@ -815,6 +769,13 @@ void Animation::set_frame(int frame) { this->current_frame_ = this->animation_frame_count_ - abs_frame; } } + + this->update_data_start_(); +} + +void Animation::update_data_start_() { + const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; + this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; } DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index bcfe75f6b4..33e74b8df4 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -532,11 +532,11 @@ class Font { class Image { public: Image(const uint8_t *data_start, int width, int height, ImageType type); - virtual bool get_pixel(int x, int y) const; - virtual Color get_color_pixel(int x, int y) const; - virtual Color get_rgba_pixel(int x, int y) const; - virtual Color get_rgb565_pixel(int x, int y) const; - virtual Color get_grayscale_pixel(int x, int y) const; + bool get_pixel(int x, int y) const; + Color get_color_pixel(int x, int y) const; + Color get_rgba_pixel(int x, int y) const; + Color get_rgb565_pixel(int x, int y) const; + Color get_grayscale_pixel(int x, int y) const; int get_width() const; int get_height() const; ImageType get_type() const; @@ -557,11 +557,6 @@ class Image { class Animation : public Image { public: Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); - bool get_pixel(int x, int y) const override; - Color get_color_pixel(int x, int y) const override; - Color get_rgba_pixel(int x, int y) const override; - Color get_rgb565_pixel(int x, int y) const override; - Color get_grayscale_pixel(int x, int y) const override; uint32_t get_animation_frame_count() const; int get_current_frame() const override; @@ -577,6 +572,9 @@ class Animation : public Image { void set_loop(uint32_t start_frame, uint32_t end_frame, int count); protected: + void update_data_start_(); + + const uint8_t *animation_data_start_; int current_frame_; uint32_t animation_frame_count_; uint32_t loop_start_frame_; From 0411d524200893714fe8d4836e7b676e425e128d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 15 Jun 2023 01:15:46 +0200 Subject: [PATCH 0070/2607] display: add `BaseImage` and provide only `Image::get_pixel` method (#4932) --- esphome/components/display/display_buffer.cpp | 152 +++++++++--------- esphome/components/display/display_buffer.h | 33 ++-- 2 files changed, 101 insertions(+), 84 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index ebeb4ce1bf..c8dc7b62e2 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -325,63 +325,8 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al this->print(x, y, font, color, align, buffer); } -void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) { - bool transparent = image->has_transparency(); - - switch (image->get_type()) { - case IMAGE_TYPE_BINARY: { - for (int img_x = 0; img_x < image->get_width(); img_x++) { - for (int img_y = 0; img_y < image->get_height(); img_y++) { - if (image->get_pixel(img_x, img_y)) { - this->draw_pixel_at(x + img_x, y + img_y, color_on); - } else if (!transparent) { - this->draw_pixel_at(x + img_x, y + img_y, color_off); - } - } - } - break; - } - case IMAGE_TYPE_GRAYSCALE: - for (int img_x = 0; img_x < image->get_width(); img_x++) { - for (int img_y = 0; img_y < image->get_height(); img_y++) { - auto color = image->get_grayscale_pixel(img_x, img_y); - if (color.w >= 0x80) { - this->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB565: - for (int img_x = 0; img_x < image->get_width(); img_x++) { - for (int img_y = 0; img_y < image->get_height(); img_y++) { - auto color = image->get_rgb565_pixel(img_x, img_y); - if (color.w >= 0x80) { - this->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB24: - for (int img_x = 0; img_x < image->get_width(); img_x++) { - for (int img_y = 0; img_y < image->get_height(); img_y++) { - auto color = image->get_color_pixel(img_x, img_y); - if (color.w >= 0x80) { - this->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGBA: - for (int img_x = 0; img_x < image->get_width(); img_x++) { - for (int img_y = 0; img_y < image->get_height(); img_y++) { - auto color = image->get_rgba_pixel(img_x, img_y); - if (color.w >= 0x80) { - this->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - } +void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) { + image->draw(x, y, this, color_on, color_off); } #ifdef USE_GRAPH @@ -656,23 +601,91 @@ Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : basel glyphs_.emplace_back(&data[i]); } -bool Image::get_pixel(int x, int y) const { +void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { + switch (type_) { + case IMAGE_TYPE_BINARY: { + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + if (this->get_binary_pixel_(img_x, img_y)) { + display->draw_pixel_at(x + img_x, y + img_y, color_on); + } else if (!this->transparent_) { + display->draw_pixel_at(x + img_x, y + img_y, color_off); + } + } + } + break; + } + case IMAGE_TYPE_GRAYSCALE: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_grayscale_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB565: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb565_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB24: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb24_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGBA: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgba_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + } +} +Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return false; + return color_off; + switch (this->type_) { + case IMAGE_TYPE_BINARY: + return this->get_binary_pixel_(x, y) ? color_on : color_off; + case IMAGE_TYPE_GRAYSCALE: + return this->get_grayscale_pixel_(x, y); + case IMAGE_TYPE_RGB565: + return this->get_rgb565_pixel_(x, y); + case IMAGE_TYPE_RGB24: + return this->get_rgb24_pixel_(x, y); + case IMAGE_TYPE_RGBA: + return this->get_rgba_pixel_(x, y); + default: + return color_off; + } +} +bool Image::get_binary_pixel_(int x, int y) const { const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; const uint32_t pos = x + y * width_8; return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); } -Color Image::get_rgba_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; +Color Image::get_rgba_pixel_(int x, int y) const { const uint32_t pos = (x + y * this->width_) * 4; return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); } -Color Image::get_color_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; +Color Image::get_rgb24_pixel_(int x, int y) const { const uint32_t pos = (x + y * this->width_) * 3; Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), progmem_read_byte(this->data_start_ + pos + 2)); @@ -685,9 +698,7 @@ Color Image::get_color_pixel(int x, int y) const { } return color; } -Color Image::get_rgb565_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; +Color Image::get_rgb565_pixel_(int x, int y) const { const uint32_t pos = (x + y * this->width_) * 2; uint16_t rgb565 = progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); @@ -703,9 +714,7 @@ Color Image::get_rgb565_pixel(int x, int y) const { } return color; } -Color Image::get_grayscale_pixel(int x, int y) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return Color::BLACK; +Color Image::get_grayscale_pixel_(int x, int y) const { const uint32_t pos = (x + y * this->width_); const uint8_t gray = progmem_read_byte(this->data_start_ + pos); uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; @@ -716,7 +725,6 @@ int Image::get_height() const { return this->height_; } ImageType Image::get_type() const { return this->type_; } Image::Image(const uint8_t *data_start, int width, int height, ImageType type) : width_(width), height_(height), type_(type), data_start_(data_start) {} -int Image::get_current_frame() const { return 0; } Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) : Image(data_start, width, height, type), diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 33e74b8df4..0c31ac24d9 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -123,8 +123,8 @@ class Rect { void info(const std::string &prefix = "rect info:"); }; +class BaseImage; class Font; -class Image; class DisplayBuffer; class DisplayPage; class DisplayOnPageChangeTrigger; @@ -315,7 +315,7 @@ class DisplayBuffer { * @param color_on The color to replace in binary images for the on bits. * @param color_off The color to replace in binary images for the off bits. */ - void image(int x, int y, Image *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); #ifdef USE_GRAPH /** Draw the `graph` with the top-left corner at [x,y] to the screen. @@ -529,24 +529,33 @@ class Font { int height_; }; -class Image { +class BaseImage { + public: + virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; +}; + +class Image : public BaseImage { public: Image(const uint8_t *data_start, int width, int height, ImageType type); - bool get_pixel(int x, int y) const; - Color get_color_pixel(int x, int y) const; - Color get_rgba_pixel(int x, int y) const; - Color get_rgb565_pixel(int x, int y) const; - Color get_grayscale_pixel(int x, int y) const; - int get_width() const; - int get_height() const; + Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; + int get_width() const override; + int get_height() const override; ImageType get_type() const; - virtual int get_current_frame() const; + void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; void set_transparency(bool transparent) { transparent_ = transparent; } bool has_transparency() const { return transparent_; } protected: + bool get_binary_pixel_(int x, int y) const; + Color get_rgb24_pixel_(int x, int y) const; + Color get_rgba_pixel_(int x, int y) const; + Color get_rgb565_pixel_(int x, int y) const; + Color get_grayscale_pixel_(int x, int y) const; + int width_; int height_; ImageType type_; @@ -559,7 +568,7 @@ class Animation : public Image { Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); uint32_t get_animation_frame_count() const; - int get_current_frame() const override; + int get_current_frame() const; void next_frame(); void prev_frame(); From 54474e5b332af41b1accfbaf48dafcf43e217f1d Mon Sep 17 00:00:00 2001 From: Graham Brown Date: Thu, 15 Jun 2023 02:34:39 +0200 Subject: [PATCH 0071/2607] Add Alarm Control Panel (#4770) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 + .../alarm_control_panel/__init__.py | 165 +++++++++++ .../alarm_control_panel.cpp | 111 ++++++++ .../alarm_control_panel/alarm_control_panel.h | 136 +++++++++ .../alarm_control_panel_call.cpp | 99 +++++++ .../alarm_control_panel_call.h | 40 +++ .../alarm_control_panel_state.cpp | 34 +++ .../alarm_control_panel_state.h | 29 ++ .../alarm_control_panel/automation.h | 115 ++++++++ esphome/components/api/api.proto | 62 +++++ esphome/components/api/api_connection.cpp | 58 ++++ esphome/components/api/api_connection.h | 6 + esphome/components/api/api_pb2.cpp | 262 ++++++++++++++++++ esphome/components/api/api_pb2.h | 71 +++++ esphome/components/api/api_pb2_service.cpp | 43 +++ esphome/components/api/api_pb2_service.h | 15 + esphome/components/api/api_server.cpp | 9 + esphome/components/api/api_server.h | 4 + esphome/components/api/list_entities.cpp | 5 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.cpp | 5 + esphome/components/api/subscribe_state.h | 3 + .../template/alarm_control_panel/__init__.py | 123 ++++++++ .../template_alarm_control_panel.cpp | 180 ++++++++++++ .../template_alarm_control_panel.h | 116 ++++++++ .../components/web_server/list_entities.cpp | 10 + esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 49 +++- esphome/components/web_server/web_server.h | 11 + esphome/core/application.h | 24 ++ esphome/core/component_iterator.cpp | 15 + esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + tests/test1.yaml | 18 ++ tests/test3.yaml | 21 +- 37 files changed, 1860 insertions(+), 6 deletions(-) create mode 100644 esphome/components/alarm_control_panel/__init__.py create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel.cpp create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel.h create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel_call.cpp create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel_call.h create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel_state.cpp create mode 100644 esphome/components/alarm_control_panel/alarm_control_panel_state.h create mode 100644 esphome/components/alarm_control_panel/automation.h create mode 100644 esphome/components/template/alarm_control_panel/__init__.py create mode 100644 esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp create mode 100644 esphome/components/template/alarm_control_panel/template_alarm_control_panel.h diff --git a/CODEOWNERS b/CODEOWNERS index 1b75203654..c6cbf3c2ab 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -19,6 +19,7 @@ esphome/components/addressable_light/* @justfalter esphome/components/airthings_ble/* @jeromelaban esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban +esphome/components/alarm_control_panel/* @grahambrown11 esphome/components/am43/* @buxtronix esphome/components/am43/cover/* @buxtronix esphome/components/am43/sensor/* @buxtronix @@ -277,6 +278,7 @@ esphome/components/tca9548a/* @andreashergert1984 esphome/components/tcl112/* @glmnet esphome/components/tee501/* @Stock-M esphome/components/teleinfo/* @0hax +esphome/components/template/alarm_control_panel/* @grahambrown11 esphome/components/thermostat/* @kbx81 esphome/components/time/* @OttoWinter esphome/components/tlc5947/* @rnauber diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py new file mode 100644 index 0000000000..963d5ae719 --- /dev/null +++ b/esphome/components/alarm_control_panel/__init__.py @@ -0,0 +1,165 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.automation import maybe_simple_id +from esphome.core import CORE, coroutine_with_priority +from esphome.const import ( + CONF_ID, + CONF_ON_STATE, + CONF_TRIGGER_ID, + CONF_CODE, +) +from esphome.cpp_helpers import setup_entity + +CODEOWNERS = ["@grahambrown11"] +IS_PLATFORM_COMPONENT = True + +CONF_ON_TRIGGERED = "on_triggered" +CONF_ON_CLEARED = "on_cleared" + +alarm_control_panel_ns = cg.esphome_ns.namespace("alarm_control_panel") +AlarmControlPanel = alarm_control_panel_ns.class_("AlarmControlPanel", cg.EntityBase) + +StateTrigger = alarm_control_panel_ns.class_( + "StateTrigger", automation.Trigger.template() +) +TriggeredTrigger = alarm_control_panel_ns.class_( + "TriggeredTrigger", automation.Trigger.template() +) +ClearedTrigger = alarm_control_panel_ns.class_( + "ClearedTrigger", automation.Trigger.template() +) +ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) +ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) +DisarmAction = alarm_control_panel_ns.class_("DisarmAction", automation.Action) +PendingAction = alarm_control_panel_ns.class_("PendingAction", automation.Action) +TriggeredAction = alarm_control_panel_ns.class_("TriggeredAction", automation.Action) +AlarmControlPanelCondition = alarm_control_panel_ns.class_( + "AlarmControlPanelCondition", automation.Condition +) + +ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AlarmControlPanel), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), + } + ), + cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger), + } + ), + cv.Optional(CONF_ON_CLEARED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger), + } + ), + } +) + +ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id( + { + cv.GenerateID(): cv.use_id(AlarmControlPanel), + cv.Optional(CONF_CODE): cv.templatable(cv.string), + } +) + +ALARM_CONTROL_PANEL_CONDITION_SCHEMA = maybe_simple_id( + { + cv.GenerateID(): cv.use_id(AlarmControlPanel), + } +) + + +async def setup_alarm_control_panel_core_(var, config): + await setup_entity(var, config) + for conf in config.get(CONF_ON_STATE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_TRIGGERED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_CLEARED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + + +async def register_alarm_control_panel(var, config): + if not CORE.has_id(config[CONF_ID]): + var = cg.Pvariable(config[CONF_ID], var) + cg.add(cg.App.register_alarm_control_panel(var)) + await setup_alarm_control_panel_core_(var, config) + + +@automation.register_action( + "alarm_control_panel.arm_away", ArmAwayAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_arm_away_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if CONF_CODE in config: + templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + cg.add(var.set_code(templatable_)) + return var + + +@automation.register_action( + "alarm_control_panel.arm_home", ArmHomeAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_arm_home_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if CONF_CODE in config: + templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + cg.add(var.set_code(templatable_)) + return var + + +@automation.register_action( + "alarm_control_panel.disarm", DisarmAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_disarm_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if CONF_CODE in config: + templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + cg.add(var.set_code(templatable_)) + return var + + +@automation.register_action( + "alarm_control_panel.pending", PendingAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_pending_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +@automation.register_action( + "alarm_control_panel.triggered", TriggeredAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_trigger_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +@automation.register_condition( + "alarm_control_panel.is_armed", + AlarmControlPanelCondition, + ALARM_CONTROL_PANEL_CONDITION_SCHEMA, +) +async def alarm_control_panel_is_armed_to_code( + config, condition_id, template_arg, args +): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren) + + +@coroutine_with_priority(100.0) +async def to_code(config): + cg.add_global(alarm_control_panel_ns.using) + cg.add_define("USE_ALARM_CONTROL_PANEL") diff --git a/esphome/components/alarm_control_panel/alarm_control_panel.cpp b/esphome/components/alarm_control_panel/alarm_control_panel.cpp new file mode 100644 index 0000000000..74c9a502df --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel.cpp @@ -0,0 +1,111 @@ +#include + +#include "alarm_control_panel.h" + +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace alarm_control_panel { + +static const char *const TAG = "alarm_control_panel"; + +AlarmControlPanelCall AlarmControlPanel::make_call() { return AlarmControlPanelCall(this); } + +bool AlarmControlPanel::is_state_armed(AlarmControlPanelState state) { + switch (state) { + case ACP_STATE_ARMED_AWAY: + case ACP_STATE_ARMED_HOME: + case ACP_STATE_ARMED_NIGHT: + case ACP_STATE_ARMED_VACATION: + case ACP_STATE_ARMED_CUSTOM_BYPASS: + return true; + default: + return false; + } +}; + +void AlarmControlPanel::publish_state(AlarmControlPanelState state) { + this->last_update_ = millis(); + if (state != this->current_state_) { + auto prev_state = this->current_state_; + ESP_LOGD(TAG, "Set state to: %s, previous: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(state)), + LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state))); + this->current_state_ = state; + this->state_callback_.call(); + if (state == ACP_STATE_TRIGGERED) { + this->triggered_callback_.call(); + } + if (prev_state == ACP_STATE_TRIGGERED) { + this->cleared_callback_.call(); + } + if (state == this->desired_state_) { + // only store when in the desired state + this->pref_.save(&state); + } + } +} + +void AlarmControlPanel::add_on_state_callback(std::function &&callback) { + this->state_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_triggered_callback(std::function &&callback) { + this->triggered_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_cleared_callback(std::function &&callback) { + this->cleared_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::arm_away(optional code) { + auto call = this->make_call(); + call.arm_away(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +void AlarmControlPanel::arm_home(optional code) { + auto call = this->make_call(); + call.arm_home(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +void AlarmControlPanel::arm_night(optional code) { + auto call = this->make_call(); + call.arm_night(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +void AlarmControlPanel::arm_vacation(optional code) { + auto call = this->make_call(); + call.arm_vacation(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +void AlarmControlPanel::arm_custom_bypass(optional code) { + auto call = this->make_call(); + call.arm_custom_bypass(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +void AlarmControlPanel::disarm(optional code) { + auto call = this->make_call(); + call.disarm(); + if (code.has_value()) + call.set_code(code.value()); + call.perform(); +} + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/alarm_control_panel.h b/esphome/components/alarm_control_panel/alarm_control_panel.h new file mode 100644 index 0000000000..4f15ccb45a --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel.h @@ -0,0 +1,136 @@ +#pragma once + +#include + +#include "alarm_control_panel_call.h" +#include "alarm_control_panel_state.h" + +#include "esphome/core/automation.h" +#include "esphome/core/entity_base.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace alarm_control_panel { + +enum AlarmControlPanelFeature : uint8_t { + // Matches Home Assistant values + ACP_FEAT_ARM_HOME = 1 << 0, + ACP_FEAT_ARM_AWAY = 1 << 1, + ACP_FEAT_ARM_NIGHT = 1 << 2, + ACP_FEAT_TRIGGER = 1 << 3, + ACP_FEAT_ARM_CUSTOM_BYPASS = 1 << 4, + ACP_FEAT_ARM_VACATION = 1 << 5, +}; + +class AlarmControlPanel : public EntityBase { + public: + /** Make a AlarmControlPanelCall + * + */ + AlarmControlPanelCall make_call(); + + /** Set the state of the alarm_control_panel. + * + * @param state The AlarmControlPanelState. + */ + void publish_state(AlarmControlPanelState state); + + /** Add a callback for when the state of the alarm_control_panel changes + * + * @param callback The callback function + */ + void add_on_state_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel chanes to triggered + * + * @param callback The callback function + */ + void add_on_triggered_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel clears from triggered + * + * @param callback The callback function + */ + void add_on_cleared_callback(std::function &&callback); + + /** A numeric representation of the supported features as per HomeAssistant + * + */ + virtual uint32_t get_supported_features() const = 0; + + /** Returns if the alarm_control_panel has a code + * + */ + virtual bool get_requires_code() const = 0; + + /** Returns if the alarm_control_panel requires a code to arm + * + */ + virtual bool get_requires_code_to_arm() const = 0; + + /** arm the alarm in away mode + * + * @param code The code + */ + void arm_away(optional code = nullopt); + + /** arm the alarm in home mode + * + * @param code The code + */ + void arm_home(optional code = nullopt); + + /** arm the alarm in night mode + * + * @param code The code + */ + void arm_night(optional code = nullopt); + + /** arm the alarm in vacation mode + * + * @param code The code + */ + void arm_vacation(optional code = nullopt); + + /** arm the alarm in custom bypass mode + * + * @param code The code + */ + void arm_custom_bypass(optional code = nullopt); + + /** disarm the alarm + * + * @param code The code + */ + void disarm(optional code = nullopt); + + /** Get the state + * + */ + AlarmControlPanelState get_state() const { return this->current_state_; } + + // is the state one of the armed states + bool is_state_armed(AlarmControlPanelState state); + + protected: + friend AlarmControlPanelCall; + // in order to store last panel state in flash + ESPPreferenceObject pref_; + // current state + AlarmControlPanelState current_state_; + // the desired (or previous) state + AlarmControlPanelState desired_state_; + // last time the state was updated + uint32_t last_update_; + // the call control function + virtual void control(const AlarmControlPanelCall &call) = 0; + // state callback + CallbackManager state_callback_{}; + // trigger callback + CallbackManager triggered_callback_{}; + // clear callback + CallbackManager cleared_callback_{}; +}; + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp new file mode 100644 index 0000000000..eb50c4f4b5 --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp @@ -0,0 +1,99 @@ +#include "alarm_control_panel_call.h" + +#include "alarm_control_panel.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace alarm_control_panel { + +static const char *const TAG = "alarm_control_panel"; + +AlarmControlPanelCall::AlarmControlPanelCall(AlarmControlPanel *parent) : parent_(parent) {} + +AlarmControlPanelCall &AlarmControlPanelCall::set_code(const std::string &code) { + this->code_ = code; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::arm_away() { + this->state_ = ACP_STATE_ARMED_AWAY; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::arm_home() { + this->state_ = ACP_STATE_ARMED_HOME; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::arm_night() { + this->state_ = ACP_STATE_ARMED_NIGHT; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::arm_vacation() { + this->state_ = ACP_STATE_ARMED_VACATION; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::arm_custom_bypass() { + this->state_ = ACP_STATE_ARMED_CUSTOM_BYPASS; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::disarm() { + this->state_ = ACP_STATE_DISARMED; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::pending() { + this->state_ = ACP_STATE_PENDING; + return *this; +} + +AlarmControlPanelCall &AlarmControlPanelCall::triggered() { + this->state_ = ACP_STATE_TRIGGERED; + return *this; +} + +const optional &AlarmControlPanelCall::get_state() const { return this->state_; } +const optional &AlarmControlPanelCall::get_code() const { return this->code_; } + +void AlarmControlPanelCall::validate_() { + if (this->state_.has_value()) { + auto state = *this->state_; + if (this->parent_->is_state_armed(state) && this->parent_->get_state() != ACP_STATE_DISARMED) { + ESP_LOGW(TAG, "Cannot arm when not disarmed"); + this->state_.reset(); + return; + } + if (state == ACP_STATE_PENDING && this->parent_->get_state() == ACP_STATE_DISARMED) { + ESP_LOGW(TAG, "Cannot trip alarm when disarmed"); + this->state_.reset(); + return; + } + if (state == ACP_STATE_DISARMED && + !(this->parent_->is_state_armed(this->parent_->get_state()) || + this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_ARMING || + this->parent_->get_state() == ACP_STATE_TRIGGERED)) { + ESP_LOGW(TAG, "Cannot disarm when not armed"); + this->state_.reset(); + return; + } + if (state == ACP_STATE_ARMED_HOME && (this->parent_->get_supported_features() & ACP_FEAT_ARM_HOME) == 0) { + ESP_LOGW(TAG, "Cannot arm home when not supported"); + this->state_.reset(); + return; + } + } +} + +void AlarmControlPanelCall::perform() { + this->validate_(); + if (this->state_) { + this->parent_->control(*this); + } +} + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_call.h b/esphome/components/alarm_control_panel/alarm_control_panel_call.h new file mode 100644 index 0000000000..034e3142da --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel_call.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "alarm_control_panel_state.h" + +#include "esphome/core/helpers.h" + +namespace esphome { +namespace alarm_control_panel { + +class AlarmControlPanel; + +class AlarmControlPanelCall { + public: + AlarmControlPanelCall(AlarmControlPanel *parent); + + AlarmControlPanelCall &set_code(const std::string &code); + AlarmControlPanelCall &arm_away(); + AlarmControlPanelCall &arm_home(); + AlarmControlPanelCall &arm_night(); + AlarmControlPanelCall &arm_vacation(); + AlarmControlPanelCall &arm_custom_bypass(); + AlarmControlPanelCall &disarm(); + AlarmControlPanelCall &pending(); + AlarmControlPanelCall &triggered(); + + void perform(); + const optional &get_state() const; + const optional &get_code() const; + + protected: + AlarmControlPanel *parent_; + optional code_{}; + optional state_{}; + void validate_(); +}; + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp b/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp new file mode 100644 index 0000000000..231e7228e1 --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp @@ -0,0 +1,34 @@ +#include "alarm_control_panel_state.h" + +namespace esphome { +namespace alarm_control_panel { + +const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state) { + switch (state) { + case ACP_STATE_DISARMED: + return LOG_STR("DISARMED"); + case ACP_STATE_ARMED_HOME: + return LOG_STR("ARMED_HOME"); + case ACP_STATE_ARMED_AWAY: + return LOG_STR("ARMED_AWAY"); + case ACP_STATE_ARMED_NIGHT: + return LOG_STR("NIGHT"); + case ACP_STATE_ARMED_VACATION: + return LOG_STR("ARMED_VACATION"); + case ACP_STATE_ARMED_CUSTOM_BYPASS: + return LOG_STR("ARMED_CUSTOM_BYPASS"); + case ACP_STATE_PENDING: + return LOG_STR("PENDING"); + case ACP_STATE_ARMING: + return LOG_STR("ARMING"); + case ACP_STATE_DISARMING: + return LOG_STR("DISARMING"); + case ACP_STATE_TRIGGERED: + return LOG_STR("TRIGGERED"); + default: + return LOG_STR("UNKNOWN"); + } +} + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_state.h b/esphome/components/alarm_control_panel/alarm_control_panel_state.h new file mode 100644 index 0000000000..ad16222dc0 --- /dev/null +++ b/esphome/components/alarm_control_panel/alarm_control_panel_state.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "esphome/core/log.h" + +namespace esphome { +namespace alarm_control_panel { + +enum AlarmControlPanelState : uint8_t { + ACP_STATE_DISARMED = 0, + ACP_STATE_ARMED_HOME = 1, + ACP_STATE_ARMED_AWAY = 2, + ACP_STATE_ARMED_NIGHT = 3, + ACP_STATE_ARMED_VACATION = 4, + ACP_STATE_ARMED_CUSTOM_BYPASS = 5, + ACP_STATE_PENDING = 6, + ACP_STATE_ARMING = 7, + ACP_STATE_DISARMING = 8, + ACP_STATE_TRIGGERED = 9 +}; + +/** Returns a string representation of the state. + * + * @param state The AlarmControlPanelState. + */ +const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state); + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/alarm_control_panel/automation.h b/esphome/components/alarm_control_panel/automation.h new file mode 100644 index 0000000000..4368129609 --- /dev/null +++ b/esphome/components/alarm_control_panel/automation.h @@ -0,0 +1,115 @@ + +#pragma once +#include "esphome/core/automation.h" +#include "alarm_control_panel.h" + +namespace esphome { +namespace alarm_control_panel { + +class StateTrigger : public Trigger<> { + public: + explicit StateTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_state_callback([this]() { this->trigger(); }); + } +}; + +class TriggeredTrigger : public Trigger<> { + public: + explicit TriggeredTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_triggered_callback([this]() { this->trigger(); }); + } +}; + +class ClearedTrigger : public Trigger<> { + public: + explicit ClearedTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_cleared_callback([this]() { this->trigger(); }); + } +}; + +template class ArmAwayAction : public Action { + public: + explicit ArmAwayAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + TEMPLATABLE_VALUE(std::string, code) + + void play(Ts... x) override { + auto call = this->alarm_control_panel_->make_call(); + auto code = this->code_.optional_value(x...); + if (code.has_value()) { + call.set_code(code.value()); + } + call.arm_away(); + call.perform(); + } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + +template class ArmHomeAction : public Action { + public: + explicit ArmHomeAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + TEMPLATABLE_VALUE(std::string, code) + + void play(Ts... x) override { + auto call = this->alarm_control_panel_->make_call(); + auto code = this->code_.optional_value(x...); + if (code.has_value()) { + call.set_code(code.value()); + } + call.arm_home(); + call.perform(); + } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + +template class DisarmAction : public Action { + public: + explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + TEMPLATABLE_VALUE(std::string, code) + + void play(Ts... x) override { this->alarm_control_panel_->disarm(this->code_.optional_value(x...)); } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + +template class PendingAction : public Action { + public: + explicit PendingAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + void play(Ts... x) override { this->alarm_control_panel_->make_call().pending().perform(); } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + +template class TriggeredAction : public Action { + public: + explicit TriggeredAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + void play(Ts... x) override { this->alarm_control_panel_->make_call().triggered().perform(); } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + +template class AlarmControlPanelCondition : public Condition { + public: + AlarmControlPanelCondition(AlarmControlPanel *parent) : parent_(parent) {} + bool check(Ts... x) override { + return this->parent_->is_state_armed(this->parent_->get_state()) || + this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_TRIGGERED; + } + + protected: + AlarmControlPanel *parent_; +}; + +} // namespace alarm_control_panel +} // namespace esphome diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 74d08195a0..0d68d9fe55 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -56,6 +56,8 @@ service APIConnection { rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {} + + rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {} } @@ -1454,3 +1456,63 @@ message VoiceAssistantEventResponse { VoiceAssistantEvent event_type = 1; repeated VoiceAssistantEventData data = 2; } + +// ==================== ALARM CONTROL PANEL ==================== +enum AlarmControlPanelState { + ALARM_STATE_DISARMED = 0; + ALARM_STATE_ARMED_HOME = 1; + ALARM_STATE_ARMED_AWAY = 2; + ALARM_STATE_ARMED_NIGHT = 3; + ALARM_STATE_ARMED_VACATION = 4; + ALARM_STATE_ARMED_CUSTOM_BYPASS = 5; + ALARM_STATE_PENDING = 6; + ALARM_STATE_ARMING = 7; + ALARM_STATE_DISARMING = 8; + ALARM_STATE_TRIGGERED = 9; +} + +enum AlarmControlPanelStateCommand { + ALARM_CONTROL_PANEL_DISARM = 0; + ALARM_CONTROL_PANEL_ARM_AWAY = 1; + ALARM_CONTROL_PANEL_ARM_HOME = 2; + ALARM_CONTROL_PANEL_ARM_NIGHT = 3; + ALARM_CONTROL_PANEL_ARM_VACATION = 4; + ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5; + ALARM_CONTROL_PANEL_TRIGGER = 6; +} + +message ListEntitiesAlarmControlPanelResponse { + option (id) = 94; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_ALARM_CONTROL_PANEL"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; + uint32 supported_features = 8; + bool requires_code = 9; + bool requires_code_to_arm = 10; +} + +message AlarmControlPanelStateResponse { + option (id) = 95; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_ALARM_CONTROL_PANEL"; + option (no_delay) = true; + fixed32 key = 1; + AlarmControlPanelState state = 2; +} + +message AlarmControlPanelCommandRequest { + option (id) = 96; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_ALARM_CONTROL_PANEL"; + option (no_delay) = true; + fixed32 key = 1; + AlarmControlPanelStateCommand command = 2; + string code = 3; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 53e6ccd6dc..858ff0e525 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -931,6 +931,64 @@ void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventR #endif +#ifdef USE_ALARM_CONTROL_PANEL +bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + if (!this->state_subscription_) + return false; + + AlarmControlPanelStateResponse resp{}; + resp.key = a_alarm_control_panel->get_object_id_hash(); + resp.state = static_cast(a_alarm_control_panel->get_state()); + return this->send_alarm_control_panel_state_response(resp); +} +bool APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + ListEntitiesAlarmControlPanelResponse msg; + msg.key = a_alarm_control_panel->get_object_id_hash(); + msg.object_id = a_alarm_control_panel->get_object_id(); + msg.name = a_alarm_control_panel->get_name(); + msg.unique_id = get_default_unique_id("alarm_control_panel", a_alarm_control_panel); + msg.icon = a_alarm_control_panel->get_icon(); + msg.disabled_by_default = a_alarm_control_panel->is_disabled_by_default(); + msg.entity_category = static_cast(a_alarm_control_panel->get_entity_category()); + msg.supported_features = a_alarm_control_panel->get_supported_features(); + msg.requires_code = a_alarm_control_panel->get_requires_code(); + msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm(); + return this->send_list_entities_alarm_control_panel_response(msg); +} +void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) { + alarm_control_panel::AlarmControlPanel *a_alarm_control_panel = App.get_alarm_control_panel_by_key(msg.key); + if (a_alarm_control_panel == nullptr) + return; + + auto call = a_alarm_control_panel->make_call(); + switch (msg.command) { + case enums::ALARM_CONTROL_PANEL_DISARM: + call.disarm(); + break; + case enums::ALARM_CONTROL_PANEL_ARM_AWAY: + call.arm_away(); + break; + case enums::ALARM_CONTROL_PANEL_ARM_HOME: + call.arm_home(); + break; + case enums::ALARM_CONTROL_PANEL_ARM_NIGHT: + call.arm_night(); + break; + case enums::ALARM_CONTROL_PANEL_ARM_VACATION: + call.arm_vacation(); + break; + case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS: + call.arm_custom_bypass(); + break; + case enums::ALARM_CONTROL_PANEL_TRIGGER: + call.pending(); + break; + } + call.set_code(msg.code); + call.perform(); +} +#endif + bool APIConnection::send_log_message(int level, const char *tag, const char *line) { if (this->log_subscription_ < level) return false; diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 5398234f9f..c146adff02 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -129,6 +129,12 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; #endif +#ifdef USE_ALARM_CONTROL_PANEL + bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); + bool send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); + void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override; +#endif + void on_disconnect_response(const DisconnectResponse &value) override; void on_ping_response(const PingResponse &value) override { // we initiated ping diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 019e653a7f..8c7f6d0c4a 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -433,6 +433,57 @@ template<> const char *proto_enum_to_string(enums::V } } #endif +#ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::AlarmControlPanelState value) { + switch (value) { + case enums::ALARM_STATE_DISARMED: + return "ALARM_STATE_DISARMED"; + case enums::ALARM_STATE_ARMED_HOME: + return "ALARM_STATE_ARMED_HOME"; + case enums::ALARM_STATE_ARMED_AWAY: + return "ALARM_STATE_ARMED_AWAY"; + case enums::ALARM_STATE_ARMED_NIGHT: + return "ALARM_STATE_ARMED_NIGHT"; + case enums::ALARM_STATE_ARMED_VACATION: + return "ALARM_STATE_ARMED_VACATION"; + case enums::ALARM_STATE_ARMED_CUSTOM_BYPASS: + return "ALARM_STATE_ARMED_CUSTOM_BYPASS"; + case enums::ALARM_STATE_PENDING: + return "ALARM_STATE_PENDING"; + case enums::ALARM_STATE_ARMING: + return "ALARM_STATE_ARMING"; + case enums::ALARM_STATE_DISARMING: + return "ALARM_STATE_DISARMING"; + case enums::ALARM_STATE_TRIGGERED: + return "ALARM_STATE_TRIGGERED"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef HAS_PROTO_MESSAGE_DUMP +template<> +const char *proto_enum_to_string(enums::AlarmControlPanelStateCommand value) { + switch (value) { + case enums::ALARM_CONTROL_PANEL_DISARM: + return "ALARM_CONTROL_PANEL_DISARM"; + case enums::ALARM_CONTROL_PANEL_ARM_AWAY: + return "ALARM_CONTROL_PANEL_ARM_AWAY"; + case enums::ALARM_CONTROL_PANEL_ARM_HOME: + return "ALARM_CONTROL_PANEL_ARM_HOME"; + case enums::ALARM_CONTROL_PANEL_ARM_NIGHT: + return "ALARM_CONTROL_PANEL_ARM_NIGHT"; + case enums::ALARM_CONTROL_PANEL_ARM_VACATION: + return "ALARM_CONTROL_PANEL_ARM_VACATION"; + case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS: + return "ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS"; + case enums::ALARM_CONTROL_PANEL_TRIGGER: + return "ALARM_CONTROL_PANEL_TRIGGER"; + default: + return "UNKNOWN"; + } +} +#endif bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6436,6 +6487,217 @@ void VoiceAssistantEventResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + case 8: { + this->supported_features = value.as_uint32(); + return true; + } + case 9: { + this->requires_code = value.as_bool(); + return true; + } + case 10: { + this->requires_code_to_arm = value.as_bool(); + return true; + } + default: + return false; + } +} +bool ListEntitiesAlarmControlPanelResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + default: + return false; + } +} +bool ListEntitiesAlarmControlPanelResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); + buffer.encode_uint32(8, this->supported_features); + buffer.encode_bool(9, this->requires_code); + buffer.encode_bool(10, this->requires_code_to_arm); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesAlarmControlPanelResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%u", this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" supported_features: "); + sprintf(buffer, "%u", this->supported_features); + out.append(buffer); + out.append("\n"); + + out.append(" requires_code: "); + out.append(YESNO(this->requires_code)); + out.append("\n"); + + out.append(" requires_code_to_arm: "); + out.append(YESNO(this->requires_code_to_arm)); + out.append("\n"); + out.append("}"); +} +#endif +bool AlarmControlPanelStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->state = value.as_enum(); + return true; + } + default: + return false; + } +} +bool AlarmControlPanelStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_enum(2, this->state); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void AlarmControlPanelStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("AlarmControlPanelStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%u", this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(proto_enum_to_string(this->state)); + out.append("\n"); + out.append("}"); +} +#endif +bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->command = value.as_enum(); + return true; + } + default: + return false; + } +} +bool AlarmControlPanelCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 3: { + this->code = value.as_string(); + return true; + } + default: + return false; + } +} +bool AlarmControlPanelCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void AlarmControlPanelCommandRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_enum(2, this->command); + buffer.encode_string(3, this->code); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("AlarmControlPanelCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%u", this->key); + out.append(buffer); + out.append("\n"); + + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); + out.append("\n"); + + out.append(" code: "); + out.append("'").append(this->code).append("'"); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 49307dfce0..769f7aaff5 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -176,6 +176,27 @@ enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_TTS_START = 7, VOICE_ASSISTANT_TTS_END = 8, }; +enum AlarmControlPanelState : uint32_t { + ALARM_STATE_DISARMED = 0, + ALARM_STATE_ARMED_HOME = 1, + ALARM_STATE_ARMED_AWAY = 2, + ALARM_STATE_ARMED_NIGHT = 3, + ALARM_STATE_ARMED_VACATION = 4, + ALARM_STATE_ARMED_CUSTOM_BYPASS = 5, + ALARM_STATE_PENDING = 6, + ALARM_STATE_ARMING = 7, + ALARM_STATE_DISARMING = 8, + ALARM_STATE_TRIGGERED = 9, +}; +enum AlarmControlPanelStateCommand : uint32_t { + ALARM_CONTROL_PANEL_DISARM = 0, + ALARM_CONTROL_PANEL_ARM_AWAY = 1, + ALARM_CONTROL_PANEL_ARM_HOME = 2, + ALARM_CONTROL_PANEL_ARM_NIGHT = 3, + ALARM_CONTROL_PANEL_ARM_VACATION = 4, + ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5, + ALARM_CONTROL_PANEL_TRIGGER = 6, +}; } // namespace enums @@ -1680,6 +1701,56 @@ class VoiceAssistantEventResponse : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + uint32_t supported_features{0}; + bool requires_code{false}; + bool requires_code_to_arm{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class AlarmControlPanelStateResponse : public ProtoMessage { + public: + uint32_t key{0}; + enums::AlarmControlPanelState state{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class AlarmControlPanelCommandRequest : public ProtoMessage { + public: + uint32_t key{0}; + enums::AlarmControlPanelStateCommand command{}; + std::string code{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index e14e22cdc1..8752ae6cfd 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -476,6 +476,25 @@ bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantR #endif #ifdef USE_VOICE_ASSISTANT #endif +#ifdef USE_ALARM_CONTROL_PANEL +bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( + const ListEntitiesAlarmControlPanelResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_alarm_control_panel_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 94); +} +#endif +#ifdef USE_ALARM_CONTROL_PANEL +bool APIServerConnectionBase::send_alarm_control_panel_state_response(const AlarmControlPanelStateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_alarm_control_panel_state_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 95); +} +#endif +#ifdef USE_ALARM_CONTROL_PANEL +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -883,6 +902,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str()); #endif this->on_voice_assistant_event_response(msg); +#endif + break; + } + case 96: { +#ifdef USE_ALARM_CONTROL_PANEL + AlarmControlPanelCommandRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_alarm_control_panel_command_request: %s", msg.dump().c_str()); +#endif + this->on_alarm_control_panel_command_request(msg); #endif break; } @@ -1295,6 +1325,19 @@ void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVo this->subscribe_voice_assistant(msg); } #endif +#ifdef USE_ALARM_CONTROL_PANEL +void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->alarm_control_panel_command(msg); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 8af7a53381..2864e303c0 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -239,6 +239,15 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){}; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); +#endif +#ifdef USE_ALARM_CONTROL_PANEL + bool send_alarm_control_panel_state_response(const AlarmControlPanelStateResponse &msg); +#endif +#ifdef USE_ALARM_CONTROL_PANEL + virtual void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -324,6 +333,9 @@ class APIServerConnection : public APIServerConnectionBase { #endif #ifdef USE_VOICE_ASSISTANT virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0; #endif protected: void on_hello_request(const HelloRequest &msg) override; @@ -405,6 +417,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_VOICE_ASSISTANT void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override; #endif +#ifdef USE_ALARM_CONTROL_PANEL + void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override; +#endif }; } // namespace api diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 27c82f7ccc..87b5f9e63f 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -338,5 +338,14 @@ void APIServer::stop_voice_assistant() { } #endif +#ifdef USE_ALARM_CONTROL_PANEL +void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) { + if (obj->is_internal()) + return; + for (auto &c : this->clients_) + c->send_alarm_control_panel_state(obj); +} +#endif + } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 28e53f22e2..be124f42ff 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -85,6 +85,10 @@ class APIServer : public Component, public Controller { void stop_voice_assistant(); #endif +#ifdef USE_ALARM_CONTROL_PANEL + void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override; +#endif + bool is_connected() const; struct HomeAssistantStateSubscription { diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index 85d4cd61ef..cd73d1ef5d 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -69,6 +69,11 @@ bool ListEntitiesIterator::on_media_player(media_player::MediaPlayer *media_play return this->client_->send_media_player_info(media_player); } #endif +#ifdef USE_ALARM_CONTROL_PANEL +bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + return this->client_->send_alarm_control_panel_info(a_alarm_control_panel); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index 4fbaa509a2..b40d77e841 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -54,6 +54,9 @@ class ListEntitiesIterator : public ComponentIterator { #endif #ifdef USE_MEDIA_PLAYER bool on_media_player(media_player::MediaPlayer *media_player) override; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; #endif bool on_end() override; diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 1d1ba0245e..66b5f40928 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -55,6 +55,11 @@ bool InitialStateIterator::on_media_player(media_player::MediaPlayer *media_play return this->client_->send_media_player_state(media_player); } #endif +#ifdef USE_ALARM_CONTROL_PANEL +bool InitialStateIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + return this->client_->send_alarm_control_panel_state(a_alarm_control_panel); +} +#endif InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {} } // namespace api diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 7a7ba697c0..0597b9f384 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -51,6 +51,9 @@ class InitialStateIterator : public ComponentIterator { #endif #ifdef USE_MEDIA_PLAYER bool on_media_player(media_player::MediaPlayer *media_player) override; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; #endif protected: APIConnection *client_; diff --git a/esphome/components/template/alarm_control_panel/__init__.py b/esphome/components/template/alarm_control_panel/__init__.py new file mode 100644 index 0000000000..5156a0832a --- /dev/null +++ b/esphome/components/template/alarm_control_panel/__init__.py @@ -0,0 +1,123 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import ( + binary_sensor, + alarm_control_panel, +) +from esphome.const import ( + CONF_ID, + CONF_BINARY_SENSORS, + CONF_INPUT, + CONF_RESTORE_MODE, +) +from .. import template_ns + +CODEOWNERS = ["@grahambrown11"] + +CONF_CODES = "codes" +CONF_BYPASS_ARMED_HOME = "bypass_armed_home" +CONF_REQUIRES_CODE_TO_ARM = "requires_code_to_arm" +CONF_ARMING_HOME_TIME = "arming_home_time" +CONF_ARMING_AWAY_TIME = "arming_away_time" +CONF_PENDING_TIME = "pending_time" +CONF_TRIGGER_TIME = "trigger_time" + +FLAG_NORMAL = "normal" +FLAG_BYPASS_ARMED_HOME = "bypass_armed_home" + +BinarySensorFlags = { + FLAG_NORMAL: 1 << 0, + FLAG_BYPASS_ARMED_HOME: 1 << 1, +} + +TemplateAlarmControlPanel = template_ns.class_( + "TemplateAlarmControlPanel", alarm_control_panel.AlarmControlPanel, cg.Component +) + +TemplateAlarmControlPanelRestoreMode = template_ns.enum( + "TemplateAlarmControlPanelRestoreMode" +) +RESTORE_MODES = { + "ALWAYS_DISARMED": TemplateAlarmControlPanelRestoreMode.ALARM_CONTROL_PANEL_ALWAYS_DISARMED, + "RESTORE_DEFAULT_DISARMED": TemplateAlarmControlPanelRestoreMode.ALARM_CONTROL_PANEL_RESTORE_DEFAULT_DISARMED, +} + + +def validate_config(config): + if config.get(CONF_REQUIRES_CODE_TO_ARM, False) and not config.get(CONF_CODES, []): + raise cv.Invalid( + f"{CONF_REQUIRES_CODE_TO_ARM} cannot be True when there are no codes." + ) + return config + + +TEMPLATE_ALARM_CONTROL_PANEL_BINARY_SENSOR_SCHEMA = cv.maybe_simple_value( + { + cv.Required(CONF_INPUT): cv.use_id(binary_sensor.BinarySensor), + cv.Optional(CONF_BYPASS_ARMED_HOME, default=False): cv.boolean, + }, + key=CONF_INPUT, +) + +TEMPLATE_ALARM_CONTROL_PANEL_SCHEMA = ( + alarm_control_panel.ALARM_CONTROL_PANEL_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(TemplateAlarmControlPanel), + cv.Optional(CONF_CODES): cv.ensure_list(cv.string_strict), + cv.Optional(CONF_REQUIRES_CODE_TO_ARM): cv.boolean, + cv.Optional(CONF_ARMING_HOME_TIME): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_ARMING_AWAY_TIME, default="0s" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_PENDING_TIME, default="0s" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TRIGGER_TIME, default="0s" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_BINARY_SENSORS): cv.ensure_list( + TEMPLATE_ALARM_CONTROL_PANEL_BINARY_SENSOR_SCHEMA + ), + cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_DISARMED"): cv.enum( + RESTORE_MODES, upper=True + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + +CONFIG_SCHEMA = cv.All( + TEMPLATE_ALARM_CONTROL_PANEL_SCHEMA, + validate_config, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await alarm_control_panel.register_alarm_control_panel(var, config) + if CONF_CODES in config: + for acode in config[CONF_CODES]: + cg.add(var.add_code(acode)) + if CONF_REQUIRES_CODE_TO_ARM in config: + cg.add(var.set_requires_code_to_arm(config[CONF_REQUIRES_CODE_TO_ARM])) + + cg.add(var.set_arming_away_time(config[CONF_ARMING_AWAY_TIME])) + cg.add(var.set_pending_time(config[CONF_PENDING_TIME])) + cg.add(var.set_trigger_time(config[CONF_TRIGGER_TIME])) + + supports_arm_home = False + if CONF_ARMING_HOME_TIME in config: + cg.add(var.set_arming_home_time(config[CONF_ARMING_HOME_TIME])) + supports_arm_home = True + + for sensor in config.get(CONF_BINARY_SENSORS, []): + bs = await cg.get_variable(sensor[CONF_INPUT]) + flags = BinarySensorFlags[FLAG_NORMAL] + if sensor[CONF_BYPASS_ARMED_HOME]: + flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_HOME] + supports_arm_home = True + cg.add(var.add_sensor(bs, flags)) + + cg.add(var.set_supports_arm_home(supports_arm_home)) + + cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp new file mode 100644 index 0000000000..1c54998e42 --- /dev/null +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp @@ -0,0 +1,180 @@ +#include "template_alarm_control_panel.h" +#include +#include "esphome/components/alarm_control_panel/alarm_control_panel.h" +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace template_ { + +using namespace esphome::alarm_control_panel; + +static const char *const TAG = "template.alarm_control_panel"; + +TemplateAlarmControlPanel::TemplateAlarmControlPanel(){}; + +#ifdef USE_BINARY_SENSOR +void TemplateAlarmControlPanel::add_sensor(binary_sensor::BinarySensor *sensor, uint16_t flags) { + this->sensor_map_[sensor] = flags; +}; +#endif + +void TemplateAlarmControlPanel::dump_config() { + ESP_LOGCONFIG(TAG, "TemplateAlarmControlPanel:"); + ESP_LOGCONFIG(TAG, " Current State: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(this->current_state_))); + ESP_LOGCONFIG(TAG, " Number of Codes: %u", this->codes_.size()); + if (!this->codes_.empty()) + ESP_LOGCONFIG(TAG, " Requires Code To Arm: %s", YESNO(this->requires_code_to_arm_)); + ESP_LOGCONFIG(TAG, " Arming Away Time: %us", (this->arming_away_time_ / 1000)); + if (this->arming_home_time_ != 0) + ESP_LOGCONFIG(TAG, " Arming Home Time: %us", (this->arming_home_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Pending Time: %us", (this->pending_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Trigger Time: %us", (this->trigger_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Supported Features: %u", this->get_supported_features()); +#ifdef USE_BINARY_SENSOR + for (auto sensor_pair : this->sensor_map_) { + ESP_LOGCONFIG(TAG, " Binary Sesnsor:"); + ESP_LOGCONFIG(TAG, " Name: %s", sensor_pair.first->get_name().c_str()); + ESP_LOGCONFIG(TAG, " Armed home bypass: %s", + TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); + } +#endif +} + +void TemplateAlarmControlPanel::setup() { + ESP_LOGCONFIG(TAG, "Setting up Template AlarmControlPanel '%s'...", this->name_.c_str()); + switch (this->restore_mode_) { + case ALARM_CONTROL_PANEL_ALWAYS_DISARMED: + this->current_state_ = ACP_STATE_DISARMED; + break; + case ALARM_CONTROL_PANEL_RESTORE_DEFAULT_DISARMED: { + uint8_t value; + this->pref_ = global_preferences->make_preference(this->get_object_id_hash()); + if (this->pref_.load(&value)) { + this->current_state_ = static_cast(value); + } else { + this->current_state_ = ACP_STATE_DISARMED; + } + break; + } + } + this->desired_state_ = this->current_state_; +} + +void TemplateAlarmControlPanel::loop() { + // change from ARMING to ARMED_x after the arming_time_ has passed + if (this->current_state_ == ACP_STATE_ARMING) { + auto delay = this->arming_away_time_; + if (this->desired_state_ == ACP_STATE_ARMED_HOME) { + delay = this->arming_home_time_; + } + if ((millis() - this->last_update_) > delay) { + this->publish_state(this->desired_state_); + } + return; + } + // change from PENDING to TRIGGERED after the delay_time_ has passed + if (this->current_state_ == ACP_STATE_PENDING && (millis() - this->last_update_) > this->pending_time_) { + this->publish_state(ACP_STATE_TRIGGERED); + return; + } + auto future_state = this->current_state_; + // reset triggered if all clear + if (this->current_state_ == ACP_STATE_TRIGGERED && this->trigger_time_ > 0 && + (millis() - this->last_update_) > this->trigger_time_) { + future_state = this->desired_state_; + } + bool trigger = false; +#ifdef USE_BINARY_SENSOR + if (this->is_state_armed(future_state)) { + // TODO might be better to register change for each sensor in setup... + for (auto sensor_pair : this->sensor_map_) { + if (sensor_pair.first->state) { + if (this->current_state_ == ACP_STATE_ARMED_HOME && + (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)) { + continue; + } + trigger = true; + break; + } + } + } +#endif + if (trigger) { + if (this->pending_time_ > 0 && this->current_state_ != ACP_STATE_TRIGGERED) { + this->publish_state(ACP_STATE_PENDING); + } else { + this->publish_state(ACP_STATE_TRIGGERED); + } + } else if (future_state != this->current_state_) { + this->publish_state(future_state); + } +} + +bool TemplateAlarmControlPanel::is_code_valid_(optional code) { + if (!this->codes_.empty()) { + if (code.has_value()) { + ESP_LOGVV(TAG, "Checking code: %s", code.value().c_str()); + return (std::count(this->codes_.begin(), this->codes_.end(), code.value()) == 1); + } + ESP_LOGD(TAG, "No code provided"); + return false; + } + return true; +} + +uint32_t TemplateAlarmControlPanel::get_supported_features() const { + uint32_t features = ACP_FEAT_ARM_AWAY | ACP_FEAT_TRIGGER; + if (this->supports_arm_home_) { + features |= ACP_FEAT_ARM_HOME; + } + return features; +} + +bool TemplateAlarmControlPanel::get_requires_code() const { return !this->codes_.empty(); } + +void TemplateAlarmControlPanel::arm_(optional code, alarm_control_panel::AlarmControlPanelState state, + uint32_t delay) { + if (this->current_state_ != ACP_STATE_DISARMED) { + ESP_LOGW(TAG, "Cannot arm when not disarmed"); + return; + } + if (this->requires_code_to_arm_ && !this->is_code_valid_(std::move(code))) { + ESP_LOGW(TAG, "Not arming code doesn't match"); + return; + } + this->desired_state_ = state; + if (delay > 0) { + this->publish_state(ACP_STATE_ARMING); + } else { + this->publish_state(state); + } +} + +void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) { + if (call.get_state()) { + if (call.get_state() == ACP_STATE_ARMED_AWAY) { + this->arm_(call.get_code(), ACP_STATE_ARMED_AWAY, this->arming_away_time_); + } else if (call.get_state() == ACP_STATE_ARMED_HOME) { + this->arm_(call.get_code(), ACP_STATE_ARMED_HOME, this->arming_home_time_); + } else if (call.get_state() == ACP_STATE_DISARMED) { + if (!this->is_code_valid_(call.get_code())) { + ESP_LOGW(TAG, "Not disarming code doesn't match"); + return; + } + this->desired_state_ = ACP_STATE_DISARMED; + this->publish_state(ACP_STATE_DISARMED); + } else if (call.get_state() == ACP_STATE_TRIGGERED) { + this->publish_state(ACP_STATE_TRIGGERED); + } else if (call.get_state() == ACP_STATE_PENDING) { + this->publish_state(ACP_STATE_PENDING); + } else { + ESP_LOGE(TAG, "State not yet implemented: %s", + LOG_STR_ARG(alarm_control_panel_state_to_string(*call.get_state()))); + } + } +} + +} // namespace template_ +} // namespace esphome diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h new file mode 100644 index 0000000000..4065356ba8 --- /dev/null +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h @@ -0,0 +1,116 @@ +#pragma once + +#include + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" + +#include "esphome/components/alarm_control_panel/alarm_control_panel.h" + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +namespace esphome { +namespace template_ { + +#ifdef USE_BINARY_SENSOR +enum BinarySensorFlags : uint16_t { + BINARY_SENSOR_MODE_NORMAL = 1 << 0, + BINARY_SENSOR_MODE_BYPASS_ARMED_HOME = 1 << 1, +}; +#endif + +enum TemplateAlarmControlPanelRestoreMode { + ALARM_CONTROL_PANEL_ALWAYS_DISARMED, + ALARM_CONTROL_PANEL_RESTORE_DEFAULT_DISARMED, +}; + +class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, public Component { + public: + TemplateAlarmControlPanel(); + void dump_config() override; + void setup() override; + void loop() override; + uint32_t get_supported_features() const override; + bool get_requires_code() const override; + bool get_requires_code_to_arm() const override { return this->requires_code_to_arm_; } + void set_restore_mode(TemplateAlarmControlPanelRestoreMode restore_mode) { this->restore_mode_ = restore_mode; } + +#ifdef USE_BINARY_SENSOR + /** Add a binary_sensor to the alarm_panel. + * + * @param sensor The BinarySensor instance. + * @param ignore_when_home if this should be ignored when armed_home mode + */ + void add_sensor(binary_sensor::BinarySensor *sensor, uint16_t flags = 0); +#endif + + /** add a code + * + * @param code The code + */ + void add_code(const std::string &code) { this->codes_.push_back(code); } + + /** set requires a code to arm + * + * @param code_to_arm The requires code to arm + */ + void set_requires_code_to_arm(bool code_to_arm) { this->requires_code_to_arm_ = code_to_arm; } + + /** set the delay before arming away + * + * @param time The milliseconds + */ + void set_arming_away_time(uint32_t time) { this->arming_away_time_ = time; } + + /** set the delay before arming home + * + * @param time The milliseconds + */ + void set_arming_home_time(uint32_t time) { this->arming_home_time_ = time; } + + /** set the delay before triggering + * + * @param time The milliseconds + */ + void set_pending_time(uint32_t time) { this->pending_time_ = time; } + + /** set the delay before resetting after triggered + * + * @param time The milliseconds + */ + void set_trigger_time(uint32_t time) { this->trigger_time_ = time; } + + void set_supports_arm_home(bool supports_arm_home) { supports_arm_home_ = supports_arm_home; } + + protected: + void control(const alarm_control_panel::AlarmControlPanelCall &call) override; +#ifdef USE_BINARY_SENSOR + // the map of binary sensors that the alarm_panel monitors with their modes + std::map sensor_map_; +#endif + TemplateAlarmControlPanelRestoreMode restore_mode_{}; + + // the arming away delay + uint32_t arming_away_time_; + // the arming home delay + uint32_t arming_home_time_{0}; + // the trigger delay + uint32_t pending_time_; + // the time in trigger + uint32_t trigger_time_; + // a list of codes + std::vector codes_; + // requires a code to arm + bool requires_code_to_arm_ = false; + bool supports_arm_home_ = false; + // check if the code is valid + bool is_code_valid_(optional code); + + void arm_(optional code, alarm_control_panel::AlarmControlPanelState state, uint32_t delay); +}; + +} // namespace template_ +} // namespace esphome diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 6f833a5c83..ce7b4be7f3 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -91,6 +91,16 @@ bool ListEntitiesIterator::on_select(select::Select *select) { } #endif +#ifdef USE_ALARM_CONTROL_PANEL +bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + this->web_server_->events_.send( + this->web_server_->alarm_control_panel_json(a_alarm_control_panel, a_alarm_control_panel->get_state(), DETAIL_ALL) + .c_str(), + "state"); + return true; +} +#endif + } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index 85868caff8..8ddca15edf 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -49,6 +49,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_LOCK bool on_lock(lock::Lock *a_lock) override; #endif +#ifdef USE_ALARM_CONTROL_PANEL + bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; +#endif protected: WebServer *web_server_; diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 00b2e20015..1ac94375c2 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -813,6 +813,9 @@ std::string WebServer::select_json(select::Select *obj, const std::string &value } #endif +// Longest: HORIZONTAL +#define PSTR_LOCAL(mode_s) strncpy_P(buf, (PGM_P) ((mode_s)), 15) + #ifdef USE_CLIMATE void WebServer::on_climate_update(climate::Climate *obj) { this->events_.send(this->climate_json(obj, DETAIL_STATE).c_str(), "state"); @@ -869,16 +872,13 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url request->send(404); } -// Longest: HORIZONTAL -#define PSTR_LOCAL(mode_s) strncpy_P(__buf, (PGM_P) ((mode_s)), 15) - std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_config) { return json::build_json([obj, start_config](JsonObject root) { set_json_id(root, obj, "climate-" + obj->get_object_id(), start_config); const auto traits = obj->get_traits(); int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals(); int8_t current_accuracy = traits.get_current_temperature_accuracy_decimals(); - char __buf[16]; + char buf[16]; if (start_config == DETAIL_ALL) { JsonArray opt = root.createNestedArray("modes"); @@ -996,6 +996,34 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat } #endif +#ifdef USE_ALARM_CONTROL_PANEL +void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) { + this->events_.send(this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE).c_str(), "state"); +} +std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmControlPanel *obj, + alarm_control_panel::AlarmControlPanelState value, + JsonDetail start_config) { + return json::build_json([obj, value, start_config](JsonObject root) { + char buf[16]; + set_json_icon_state_value(root, obj, "alarm-control-panel-" + obj->get_object_id(), + PSTR_LOCAL(alarm_control_panel_state_to_string(value)), value, start_config); + }); +} +void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (alarm_control_panel::AlarmControlPanel *obj : App.get_alarm_control_panels()) { + if (obj->get_object_id() != match.id) + continue; + + if (request->method() == HTTP_GET) { + std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE); + request->send(200, "application/json", data.c_str()); + return; + } + } + request->send(404); +} +#endif + bool WebServer::canHandle(AsyncWebServerRequest *request) { if (request->url() == "/") return true; @@ -1073,6 +1101,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_ALARM_CONTROL_PANEL + if (request->method() == HTTP_GET && match.domain == "alarm_control_panel") + return true; +#endif + return false; } void WebServer::handleRequest(AsyncWebServerRequest *request) { @@ -1180,6 +1213,14 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { return; } #endif + +#ifdef USE_ALARM_CONTROL_PANEL + if (match.domain == "alarm_control_panel") { + this->handle_alarm_control_panel_request(request, match); + + return; + } +#endif } bool WebServer::isRequestHandlerTrivial() { return false; } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index f4122ef754..45d0bc03a4 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -216,6 +216,17 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string lock_json(lock::Lock *obj, lock::LockState value, JsonDetail start_config); #endif +#ifdef USE_ALARM_CONTROL_PANEL + void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override; + + /// Handle a alarm_control_panel request under '/alarm_control_panel/'. + void handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match); + + /// Dump the alarm_control_panel state with its value as a JSON string. + std::string alarm_control_panel_json(alarm_control_panel::AlarmControlPanel *obj, + alarm_control_panel::AlarmControlPanelState value, JsonDetail start_config); +#endif + /// Override the web handler's canHandle method. bool canHandle(AsyncWebServerRequest *request) override; /// Override the web handler's handleRequest method. diff --git a/esphome/core/application.h b/esphome/core/application.h index 0992a4df39..0501d1a56a 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -48,6 +48,9 @@ #ifdef USE_MEDIA_PLAYER #include "esphome/components/media_player/media_player.h" #endif +#ifdef USE_ALARM_CONTROL_PANEL +#include "esphome/components/alarm_control_panel/alarm_control_panel.h" +#endif namespace esphome { @@ -126,6 +129,12 @@ class Application { void register_media_player(media_player::MediaPlayer *media_player) { this->media_players_.push_back(media_player); } #endif +#ifdef USE_ALARM_CONTROL_PANEL + void register_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + this->alarm_control_panels_.push_back(a_alarm_control_panel); + } +#endif + /// Register the component in this Application instance. template C *register_component(C *c) { static_assert(std::is_base_of::value, "Only Component subclasses can be registered"); @@ -296,6 +305,18 @@ class Application { } #endif +#ifdef USE_ALARM_CONTROL_PANEL + const std::vector &get_alarm_control_panels() { + return this->alarm_control_panels_; + } + alarm_control_panel::AlarmControlPanel *get_alarm_control_panel_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->alarm_control_panels_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif + Scheduler scheduler; protected: @@ -349,6 +370,9 @@ class Application { #ifdef USE_MEDIA_PLAYER std::vector media_players_{}; #endif +#ifdef USE_ALARM_CONTROL_PANEL + std::vector alarm_control_panels_{}; +#endif std::string name_; std::string friendly_name_; diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index 16c56a90c5..871f6d6c0e 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -246,6 +246,21 @@ void ComponentIterator::advance() { } } break; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + case IteratorState::ALARM_CONTROL_PANEL: + if (this->at_ >= App.get_alarm_control_panels().size()) { + advance_platform = true; + } else { + auto *a_alarm_control_panel = App.get_alarm_control_panels()[this->at_]; + if (a_alarm_control_panel->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_alarm_control_panel(a_alarm_control_panel); + } + } + break; #endif case IteratorState::MAX: if (this->on_end()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index e8e048bd73..8b2da6218c 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -65,6 +65,9 @@ class ComponentIterator { #endif #ifdef USE_MEDIA_PLAYER virtual bool on_media_player(media_player::MediaPlayer *media_player); +#endif +#ifdef USE_ALARM_CONTROL_PANEL + virtual bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) = 0; #endif virtual bool on_end(); @@ -116,6 +119,9 @@ class ComponentIterator { #endif #ifdef USE_MEDIA_PLAYER MEDIA_PLAYER, +#endif +#ifdef USE_ALARM_CONTROL_PANEL + ALARM_CONTROL_PANEL, #endif MAX, } state_{IteratorState::NONE}; diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index 857ee6398f..2ce471ead0 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -79,6 +79,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_state_callback([this, obj]() { this->on_media_player_update(obj); }); } #endif +#ifdef USE_ALARM_CONTROL_PANEL + for (auto *obj : App.get_alarm_control_panels()) { + if (include_internal || !obj->is_internal()) + obj->add_on_state_callback([this, obj]() { this->on_alarm_control_panel_update(obj); }); + } +#endif } } // namespace esphome diff --git a/esphome/core/controller.h b/esphome/core/controller.h index 0966504c43..25a4acb36e 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -40,6 +40,9 @@ #ifdef USE_MEDIA_PLAYER #include "esphome/components/media_player/media_player.h" #endif +#ifdef USE_ALARM_CONTROL_PANEL +#include "esphome/components/alarm_control_panel/alarm_control_panel.h" +#endif namespace esphome { @@ -82,6 +85,9 @@ class Controller { #ifdef USE_MEDIA_PLAYER virtual void on_media_player_update(media_player::MediaPlayer *obj){}; #endif +#ifdef USE_ALARM_CONTROL_PANEL + virtual void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj){}; +#endif }; } // namespace esphome diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 64edabc878..638dd39364 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -17,6 +17,7 @@ #define USE_API #define USE_API_NOISE #define USE_API_PLAINTEXT +#define USE_ALARM_CONTROL_PANEL #define USE_BINARY_SENSOR #define USE_BUTTON #define USE_CLIMATE diff --git a/tests/test1.yaml b/tests/test1.yaml index bee0d93faf..f8928430f4 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3371,3 +3371,21 @@ lcd_menu: on_prev: then: lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' + +alarm_control_panel: + - platform: template + id: alarmcontrolpanel1 + name: Alarm Panel + codes: + - "1234" + requires_code_to_arm: true + arming_home_time: 1s + arming_away_time: 15s + pending_time: 15s + trigger_time: 30s + binary_sensors: + - binary_sensor1 + on_state: + then: + - lambda: !lambda |- + ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); diff --git a/tests/test3.yaml b/tests/test3.yaml index c4847725e8..8307ac2984 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -822,7 +822,6 @@ switch: name: R0 Switch component_name: page0.r0 - climate: - platform: bang_bang name: Bang Bang Climate @@ -1106,7 +1105,6 @@ rf_bridge: - rf_bridge.send_raw: raw: "AAA5070008001000ABC12355" - display: - platform: nextion uart_id: uart_1 @@ -1171,3 +1169,22 @@ daly_bms: qr_code: - id: homepage_qr value: https://esphome.io/index.html + +alarm_control_panel: + - platform: template + id: alarmcontrolpanel1 + name: Alarm Panel + codes: + - "1234" + requires_code_to_arm: true + arming_home_time: 1s + arming_away_time: 15s + pending_time: 15s + trigger_time: 30s + binary_sensors: + - input: bin1 + bypass_armed_home: true + on_state: + then: + - lambda: !lambda |- + ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); From 5ebb468ccfab535672e8e09e0ee0bc858f9a7957 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:25:36 +1200 Subject: [PATCH 0072/2607] Bump version to 2023.6.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 470f8a46e5..8820c39d17 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0-dev" +__version__ = "2023.6.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 27f69f5439c046abd1e738885d9811f5bc7f9400 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:25:36 +1200 Subject: [PATCH 0073/2607] Bump version to 2023.7.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 470f8a46e5..f07eb49b5a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0-dev" +__version__ = "2023.7.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From a023f24a08462e1ad50070a8799b668bb0ff04a0 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:51:44 +1000 Subject: [PATCH 0074/2607] Add support in vbus component for Deltasol BS 2009 (#4943) --- esphome/components/vbus/__init__.py | 1 + .../components/vbus/binary_sensor/__init__.py | 52 ++++++++ .../vbus/binary_sensor/vbus_binary_sensor.cpp | 22 ++++ .../vbus/binary_sensor/vbus_binary_sensor.h | 21 +++ esphome/components/vbus/sensor/__init__.py | 121 ++++++++++++++++++ .../components/vbus/sensor/vbus_sensor.cpp | 41 ++++++ esphome/components/vbus/sensor/vbus_sensor.h | 31 +++++ 7 files changed, 289 insertions(+) diff --git a/esphome/components/vbus/__init__.py b/esphome/components/vbus/__init__.py index 70f130e23b..99a473a3dc 100644 --- a/esphome/components/vbus/__init__.py +++ b/esphome/components/vbus/__init__.py @@ -15,6 +15,7 @@ VBus = vbus_ns.class_("VBus", uart.UARTDevice, cg.Component) CONF_VBUS_ID = "vbus_id" CONF_DELTASOL_BS_PLUS = "deltasol_bs_plus" +CONF_DELTASOL_BS_2009 = "deltasol_bs_2009" CONF_DELTASOL_C = "deltasol_c" CONF_DELTASOL_CS2 = "deltasol_cs2" CONF_DELTASOL_CS_PLUS = "deltasol_cs_plus" diff --git a/esphome/components/vbus/binary_sensor/__init__.py b/esphome/components/vbus/binary_sensor/__init__.py index 9901fb2724..70fbda2d1f 100644 --- a/esphome/components/vbus/binary_sensor/__init__.py +++ b/esphome/components/vbus/binary_sensor/__init__.py @@ -18,12 +18,14 @@ from .. import ( VBus, CONF_VBUS_ID, CONF_DELTASOL_BS_PLUS, + CONF_DELTASOL_BS_2009, CONF_DELTASOL_C, CONF_DELTASOL_CS2, CONF_DELTASOL_CS_PLUS, ) DeltaSol_BS_Plus = vbus_ns.class_("DeltaSolBSPlusBSensor", cg.Component) +DeltaSol_BS_2009 = vbus_ns.class_("DeltaSolBS2009BSensor", cg.Component) DeltaSol_C = vbus_ns.class_("DeltaSolCBSensor", cg.Component) DeltaSol_CS2 = vbus_ns.class_("DeltaSolCS2BSensor", cg.Component) DeltaSol_CS_Plus = vbus_ns.class_("DeltaSolCSPlusBSensor", cg.Component) @@ -42,6 +44,7 @@ CONF_COLLECTOR_FROST = "collector_frost" CONF_TUBE_COLLECTOR = "tube_collector" CONF_RECOOLING = "recooling" CONF_HQM = "hqm" +CONF_FROST_PROTECTION_ACTIVE = "frost_protection_active" CONFIG_SCHEMA = cv.typed_schema( { @@ -87,6 +90,33 @@ CONFIG_SCHEMA = cv.typed_schema( ), } ), + CONF_DELTASOL_BS_2009: cv.COMPONENT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(DeltaSol_BS_2009), + cv.GenerateID(CONF_VBUS_ID): cv.use_id(VBus), + cv.Optional(CONF_SENSOR1_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR2_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR3_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR4_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional( + CONF_FROST_PROTECTION_ACTIVE + ): binary_sensor.binary_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ), CONF_DELTASOL_C: cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(DeltaSol_C), @@ -222,6 +252,28 @@ async def to_code(config): sens = await binary_sensor.new_binary_sensor(config[CONF_HQM]) cg.add(var.set_hqm_bsensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_BS_2009: + cg.add(var.set_command(0x0100)) + cg.add(var.set_source(0x427B)) + cg.add(var.set_dest(0x0010)) + if CONF_SENSOR1_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR1_ERROR]) + cg.add(var.set_s1_error_bsensor(sens)) + if CONF_SENSOR2_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR2_ERROR]) + cg.add(var.set_s2_error_bsensor(sens)) + if CONF_SENSOR3_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR3_ERROR]) + cg.add(var.set_s3_error_bsensor(sens)) + if CONF_SENSOR4_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR4_ERROR]) + cg.add(var.set_s4_error_bsensor(sens)) + if CONF_FROST_PROTECTION_ACTIVE in config: + sens = await binary_sensor.new_binary_sensor( + config[CONF_FROST_PROTECTION_ACTIVE] + ) + cg.add(var.set_frost_protection_active_bsensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_C: cg.add(var.set_command(0x0100)) cg.add(var.set_source(0x4212)) diff --git a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp index 6edbae22ba..087d049a57 100644 --- a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp +++ b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp @@ -50,6 +50,28 @@ void DeltaSolBSPlusBSensor::handle_message(std::vector &message) { this->hqm_bsensor_->publish_state(message[15] & 0x20); } +void DeltaSolBS2009BSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Deltasol BS 2009:"); + LOG_BINARY_SENSOR(" ", "Sensor 1 Error", this->s1_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 2 Error", this->s2_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 3 Error", this->s3_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 4 Error", this->s4_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Frost Protection Active", this->frost_protection_active_bsensor_); +} + +void DeltaSolBS2009BSensor::handle_message(std::vector &message) { + if (this->s1_error_bsensor_ != nullptr) + this->s1_error_bsensor_->publish_state(message[20] & 1); + if (this->s2_error_bsensor_ != nullptr) + this->s2_error_bsensor_->publish_state(message[20] & 2); + if (this->s3_error_bsensor_ != nullptr) + this->s3_error_bsensor_->publish_state(message[20] & 4); + if (this->s4_error_bsensor_ != nullptr) + this->s4_error_bsensor_->publish_state(message[20] & 8); + if (this->frost_protection_active_bsensor_ != nullptr) + this->frost_protection_active_bsensor_->publish_state(message[25] & 1); +} + void DeltaSolCBSensor::dump_config() { ESP_LOGCONFIG(TAG, "Deltasol C:"); LOG_BINARY_SENSOR(" ", "Sensor 1 Error", this->s1_error_bsensor_); diff --git a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h index c0a823a0ab..146aa1b673 100644 --- a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h +++ b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h @@ -39,6 +39,27 @@ class DeltaSolBSPlusBSensor : public VBusListener, public Component { void handle_message(std::vector &message) override; }; +class DeltaSolBS2009BSensor : public VBusListener, public Component { + public: + void dump_config() override; + void set_s1_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s1_error_bsensor_ = bsensor; } + void set_s2_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s2_error_bsensor_ = bsensor; } + void set_s3_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s3_error_bsensor_ = bsensor; } + void set_s4_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s4_error_bsensor_ = bsensor; } + void set_frost_protection_active_bsensor(binary_sensor::BinarySensor *bsensor) { + this->frost_protection_active_bsensor_ = bsensor; + } + + protected: + binary_sensor::BinarySensor *s1_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s2_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s3_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s4_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *frost_protection_active_bsensor_{nullptr}; + + void handle_message(std::vector &message) override; +}; + class DeltaSolCBSensor : public VBusListener, public Component { public: void dump_config() override; diff --git a/esphome/components/vbus/sensor/__init__.py b/esphome/components/vbus/sensor/__init__.py index bce28758ce..2ad9da424e 100644 --- a/esphome/components/vbus/sensor/__init__.py +++ b/esphome/components/vbus/sensor/__init__.py @@ -33,12 +33,14 @@ from .. import ( VBus, CONF_VBUS_ID, CONF_DELTASOL_BS_PLUS, + CONF_DELTASOL_BS_2009, CONF_DELTASOL_C, CONF_DELTASOL_CS2, CONF_DELTASOL_CS_PLUS, ) DeltaSol_BS_Plus = vbus_ns.class_("DeltaSolBSPlusSensor", cg.Component) +DeltaSol_BS_2009 = vbus_ns.class_("DeltaSolBS2009Sensor", cg.Component) DeltaSol_C = vbus_ns.class_("DeltaSolCSensor", cg.Component) DeltaSol_CS2 = vbus_ns.class_("DeltaSolCS2Sensor", cg.Component) DeltaSol_CS_Plus = vbus_ns.class_("DeltaSolCSPlusSensor", cg.Component) @@ -142,6 +144,87 @@ CONFIG_SCHEMA = cv.typed_schema( ), } ), + CONF_DELTASOL_BS_2009: cv.COMPONENT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(DeltaSol_BS_2009), + cv.GenerateID(CONF_VBUS_ID): cv.use_id(VBus), + cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_3): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_4): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PUMP_SPEED_1): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PUMP_SPEED_2): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_OPERATING_HOURS_1): sensor.sensor_schema( + unit_of_measurement=UNIT_HOUR, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_OPERATING_HOURS_2): sensor.sensor_schema( + unit_of_measurement=UNIT_HOUR, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_HEAT_QUANTITY): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT_HOURS, + icon=ICON_RADIATOR, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TIME): sensor.sensor_schema( + unit_of_measurement=UNIT_MINUTE, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_VERSION): sensor.sensor_schema( + accuracy_decimals=2, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ), CONF_DELTASOL_C: cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(DeltaSol_C), @@ -437,6 +520,44 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_VERSION]) cg.add(var.set_version_sensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_BS_2009: + cg.add(var.set_command(0x0100)) + cg.add(var.set_source(0x427B)) + cg.add(var.set_dest(0x0010)) + if CONF_TEMPERATURE_1 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_1]) + cg.add(var.set_temperature1_sensor(sens)) + if CONF_TEMPERATURE_2 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_2]) + cg.add(var.set_temperature2_sensor(sens)) + if CONF_TEMPERATURE_3 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_3]) + cg.add(var.set_temperature3_sensor(sens)) + if CONF_TEMPERATURE_4 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_4]) + cg.add(var.set_temperature4_sensor(sens)) + if CONF_PUMP_SPEED_1 in config: + sens = await sensor.new_sensor(config[CONF_PUMP_SPEED_1]) + cg.add(var.set_pump_speed1_sensor(sens)) + if CONF_PUMP_SPEED_2 in config: + sens = await sensor.new_sensor(config[CONF_PUMP_SPEED_2]) + cg.add(var.set_pump_speed2_sensor(sens)) + if CONF_OPERATING_HOURS_1 in config: + sens = await sensor.new_sensor(config[CONF_OPERATING_HOURS_1]) + cg.add(var.set_operating_hours1_sensor(sens)) + if CONF_OPERATING_HOURS_2 in config: + sens = await sensor.new_sensor(config[CONF_OPERATING_HOURS_2]) + cg.add(var.set_operating_hours2_sensor(sens)) + if CONF_HEAT_QUANTITY in config: + sens = await sensor.new_sensor(config[CONF_HEAT_QUANTITY]) + cg.add(var.set_heat_quantity_sensor(sens)) + if CONF_TIME in config: + sens = await sensor.new_sensor(config[CONF_TIME]) + cg.add(var.set_time_sensor(sens)) + if CONF_VERSION in config: + sens = await sensor.new_sensor(config[CONF_VERSION]) + cg.add(var.set_version_sensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_C: cg.add(var.set_command(0x0100)) cg.add(var.set_source(0x4212)) diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 8261773431..5644f707d0 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -57,6 +57,47 @@ void DeltaSolBSPlusSensor::handle_message(std::vector &message) { this->version_sensor_->publish_state(get_u16(message, 26) * 0.01f); } +void DeltaSolBS2009Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "Deltasol BS 2009:"); + LOG_SENSOR(" ", "Temperature 1", this->temperature1_sensor_); + LOG_SENSOR(" ", "Temperature 2", this->temperature2_sensor_); + LOG_SENSOR(" ", "Temperature 3", this->temperature3_sensor_); + LOG_SENSOR(" ", "Temperature 4", this->temperature4_sensor_); + LOG_SENSOR(" ", "Pump Speed 1", this->pump_speed1_sensor_); + LOG_SENSOR(" ", "Pump Speed 2", this->pump_speed2_sensor_); + LOG_SENSOR(" ", "Operating Hours 1", this->operating_hours1_sensor_); + LOG_SENSOR(" ", "Operating Hours 2", this->operating_hours2_sensor_); + LOG_SENSOR(" ", "Heat Quantity", this->heat_quantity_sensor_); + LOG_SENSOR(" ", "System Time", this->time_sensor_); + LOG_SENSOR(" ", "FW Version", this->version_sensor_); +} + +void DeltaSolBS2009Sensor::handle_message(std::vector &message) { + if (this->temperature1_sensor_ != nullptr) + this->temperature1_sensor_->publish_state(get_i16(message, 0) * 0.1f); + if (this->temperature2_sensor_ != nullptr) + this->temperature2_sensor_->publish_state(get_i16(message, 2) * 0.1f); + if (this->temperature3_sensor_ != nullptr) + this->temperature3_sensor_->publish_state(get_i16(message, 4) * 0.1f); + if (this->temperature4_sensor_ != nullptr) + this->temperature4_sensor_->publish_state(get_i16(message, 6) * 0.1f); + if (this->pump_speed1_sensor_ != nullptr) + this->pump_speed1_sensor_->publish_state(message[8]); + if (this->pump_speed2_sensor_ != nullptr) + this->pump_speed2_sensor_->publish_state(message[12]); + if (this->operating_hours1_sensor_ != nullptr) + this->operating_hours1_sensor_->publish_state(get_u16(message, 10)); + if (this->operating_hours2_sensor_ != nullptr) + this->operating_hours2_sensor_->publish_state(get_u16(message, 18)); + if (this->heat_quantity_sensor_ != nullptr) { + this->heat_quantity_sensor_->publish_state(get_u16(message, 28) + get_u16(message, 30) * 1000); + } + if (this->time_sensor_ != nullptr) + this->time_sensor_->publish_state(get_u16(message, 22)); + if (this->version_sensor_ != nullptr) + this->version_sensor_->publish_state(get_u16(message, 32) * 0.01f); +} + void DeltaSolCSensor::dump_config() { ESP_LOGCONFIG(TAG, "Deltasol C:"); LOG_SENSOR(" ", "Temperature 1", this->temperature1_sensor_); diff --git a/esphome/components/vbus/sensor/vbus_sensor.h b/esphome/components/vbus/sensor/vbus_sensor.h index 6ba752b68c..d5535b2019 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.h +++ b/esphome/components/vbus/sensor/vbus_sensor.h @@ -37,6 +37,37 @@ class DeltaSolBSPlusSensor : public VBusListener, public Component { void handle_message(std::vector &message) override; }; +class DeltaSolBS2009Sensor : public VBusListener, public Component { + public: + void dump_config() override; + void set_temperature1_sensor(sensor::Sensor *sensor) { this->temperature1_sensor_ = sensor; } + void set_temperature2_sensor(sensor::Sensor *sensor) { this->temperature2_sensor_ = sensor; } + void set_temperature3_sensor(sensor::Sensor *sensor) { this->temperature3_sensor_ = sensor; } + void set_temperature4_sensor(sensor::Sensor *sensor) { this->temperature4_sensor_ = sensor; } + void set_pump_speed1_sensor(sensor::Sensor *sensor) { this->pump_speed1_sensor_ = sensor; } + void set_pump_speed2_sensor(sensor::Sensor *sensor) { this->pump_speed2_sensor_ = sensor; } + void set_operating_hours1_sensor(sensor::Sensor *sensor) { this->operating_hours1_sensor_ = sensor; } + void set_operating_hours2_sensor(sensor::Sensor *sensor) { this->operating_hours2_sensor_ = sensor; } + void set_heat_quantity_sensor(sensor::Sensor *sensor) { this->heat_quantity_sensor_ = sensor; } + void set_time_sensor(sensor::Sensor *sensor) { this->time_sensor_ = sensor; } + void set_version_sensor(sensor::Sensor *sensor) { this->version_sensor_ = sensor; } + + protected: + sensor::Sensor *temperature1_sensor_{nullptr}; + sensor::Sensor *temperature2_sensor_{nullptr}; + sensor::Sensor *temperature3_sensor_{nullptr}; + sensor::Sensor *temperature4_sensor_{nullptr}; + sensor::Sensor *pump_speed1_sensor_{nullptr}; + sensor::Sensor *pump_speed2_sensor_{nullptr}; + sensor::Sensor *operating_hours1_sensor_{nullptr}; + sensor::Sensor *operating_hours2_sensor_{nullptr}; + sensor::Sensor *heat_quantity_sensor_{nullptr}; + sensor::Sensor *time_sensor_{nullptr}; + sensor::Sensor *version_sensor_{nullptr}; + + void handle_message(std::vector &message) override; +}; + class DeltaSolCSensor : public VBusListener, public Component { public: void dump_config() override; From 467e42d8aa5c1dd8a6ec13b09075117d2f209e6a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 15 Jun 2023 01:05:28 -0700 Subject: [PATCH 0075/2607] fix vbus sensor offsets (#4952) --- esphome/components/vbus/sensor/vbus_sensor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 5644f707d0..5b4f57f73d 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -207,9 +207,9 @@ void DeltaSolCSPlusSensor::handle_message(std::vector &message) { if (this->heat_quantity_sensor_ != nullptr) this->heat_quantity_sensor_->publish_state((get_u16(message, 30) << 16) + get_u16(message, 28)); if (this->time_sensor_ != nullptr) - this->time_sensor_->publish_state(get_u16(message, 12)); + this->time_sensor_->publish_state(get_u16(message, 22)); if (this->version_sensor_ != nullptr) - this->version_sensor_->publish_state(get_u16(message, 26) * 0.01f); + this->version_sensor_->publish_state(get_u16(message, 32) * 0.01f); if (this->flow_rate_sensor_ != nullptr) this->flow_rate_sensor_->publish_state(get_u16(message, 38)); } From 17fed954bf74a018f527b541dab2d30101169bb8 Mon Sep 17 00:00:00 2001 From: guillempages Date: Fri, 16 Jun 2023 01:39:50 +0200 Subject: [PATCH 0076/2607] Add support for ESP32-S3-BOX-Lite displays (#4941) --- esphome/components/ili9xxx/display.py | 1 + .../components/ili9xxx/ili9xxx_display.cpp | 12 ++++++++ esphome/components/ili9xxx/ili9xxx_display.h | 5 ++++ esphome/components/ili9xxx/ili9xxx_init.h | 30 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 780c64ec70..98edadb6a5 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -44,6 +44,7 @@ MODELS = { "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), + "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), } COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 67d643fe31..ad70bd6e48 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -421,5 +421,17 @@ void ILI9XXXST7796::initialize() { } } +// 24_TFT rotated display +void ILI9XXXS3BoxLite::initialize() { + this->init_lcd_(INITCMD_S3BOXLITE); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 240; + } + this->invert_display_(true); +} + } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 8a8cd4bb44..dbdf023bc0 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -134,5 +134,10 @@ class ILI9XXXST7796 : public ILI9XXXDisplay { void initialize() override; }; +class ILI9XXXS3BoxLite : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 593b9a79ce..36cc30ec2e 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -169,6 +169,36 @@ static const uint8_t PROGMEM INITCMD_ST7796[] = { 0x00 // End of list }; +static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, 0x40, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x18, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + // clang-format on } // namespace ili9xxx } // namespace esphome From ffa669899aa9d4b5892bc3cec18c4f39031a77e6 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sat, 17 Jun 2023 10:32:07 +0200 Subject: [PATCH 0077/2607] Split display_buffer sub-components into own files (#4950) * Split display_buffer sub-components into own files Move the Image, Animation and Font classes to their own h/cpp pairs, instead of having everything into the display_buffer h/cpp files. * Fixed COLOR_ON duplicate definition --- esphome/components/display/animation.cpp | 69 ++++ esphome/components/display/animation.h | 37 +++ esphome/components/display/display_buffer.cpp | 303 +----------------- esphome/components/display/display_buffer.h | 136 +------- esphome/components/display/font.cpp | 105 ++++++ esphome/components/display/font.h | 66 ++++ esphome/components/display/image.cpp | 135 ++++++++ esphome/components/display/image.h | 75 +++++ tests/test2.yaml | 7 + 9 files changed, 502 insertions(+), 431 deletions(-) create mode 100644 esphome/components/display/animation.cpp create mode 100644 esphome/components/display/animation.h create mode 100644 esphome/components/display/font.cpp create mode 100644 esphome/components/display/font.h create mode 100644 esphome/components/display/image.cpp create mode 100644 esphome/components/display/image.h diff --git a/esphome/components/display/animation.cpp b/esphome/components/display/animation.cpp new file mode 100644 index 0000000000..d68084b68d --- /dev/null +++ b/esphome/components/display/animation.cpp @@ -0,0 +1,69 @@ +#include "animation.h" + +#include "esphome/core/hal.h" + +namespace esphome { +namespace display { + +Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) + : Image(data_start, width, height, type), + animation_data_start_(data_start), + current_frame_(0), + animation_frame_count_(animation_frame_count), + loop_start_frame_(0), + loop_end_frame_(animation_frame_count_), + loop_count_(0), + loop_current_iteration_(1) {} +void Animation::set_loop(uint32_t start_frame, uint32_t end_frame, int count) { + loop_start_frame_ = std::min(start_frame, animation_frame_count_); + loop_end_frame_ = std::min(end_frame, animation_frame_count_); + loop_count_ = count; + loop_current_iteration_ = 1; +} + +uint32_t Animation::get_animation_frame_count() const { return this->animation_frame_count_; } +int Animation::get_current_frame() const { return this->current_frame_; } +void Animation::next_frame() { + this->current_frame_++; + if (loop_count_ && this->current_frame_ == loop_end_frame_ && + (this->loop_current_iteration_ < loop_count_ || loop_count_ < 0)) { + this->current_frame_ = loop_start_frame_; + this->loop_current_iteration_++; + } + if (this->current_frame_ >= animation_frame_count_) { + this->loop_current_iteration_ = 1; + this->current_frame_ = 0; + } + + this->update_data_start_(); +} +void Animation::prev_frame() { + this->current_frame_--; + if (this->current_frame_ < 0) { + this->current_frame_ = this->animation_frame_count_ - 1; + } + + this->update_data_start_(); +} + +void Animation::set_frame(int frame) { + unsigned abs_frame = abs(frame); + + if (abs_frame < this->animation_frame_count_) { + if (frame >= 0) { + this->current_frame_ = frame; + } else { + this->current_frame_ = this->animation_frame_count_ - abs_frame; + } + } + + this->update_data_start_(); +} + +void Animation::update_data_start_() { + const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; + this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; +} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/animation.h b/esphome/components/display/animation.h new file mode 100644 index 0000000000..38e632ccf0 --- /dev/null +++ b/esphome/components/display/animation.h @@ -0,0 +1,37 @@ +#pragma once +#include "image.h" + +namespace esphome { +namespace display { + +class Animation : public Image { + public: + Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); + + uint32_t get_animation_frame_count() const; + int get_current_frame() const; + void next_frame(); + void prev_frame(); + + /** Selects a specific frame within the animation. + * + * @param frame If possitive, advance to the frame. If negative, recede to that frame from the end frame. + */ + void set_frame(int frame); + + void set_loop(uint32_t start_frame, uint32_t end_frame, int count); + + protected: + void update_data_start_(); + + const uint8_t *animation_data_start_; + int current_frame_; + uint32_t animation_frame_count_; + uint32_t loop_start_frame_; + uint32_t loop_end_frame_; + int loop_count_; + int loop_current_iteration_; +}; + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index c8dc7b62e2..8092b9f12f 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -7,6 +7,10 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "animation.h" +#include "image.h" +#include "font.h" + namespace esphome { namespace display { @@ -15,25 +19,6 @@ static const char *const TAG = "display"; const Color COLOR_OFF(0, 0, 0, 255); const Color COLOR_ON(255, 255, 255, 255); -static int image_type_to_bpp(ImageType type) { - switch (type) { - case IMAGE_TYPE_BINARY: - return 1; - case IMAGE_TYPE_GRAYSCALE: - return 8; - case IMAGE_TYPE_RGB565: - return 16; - case IMAGE_TYPE_RGB24: - return 24; - case IMAGE_TYPE_RGBA: - return 32; - default: - return 0; - } -} - -static int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } - void Rect::expand(int16_t horizontal, int16_t vertical) { if (this->is_set() && (this->w >= (-2 * horizontal)) && (this->h >= (-2 * vertical))) { this->x = this->x - horizontal; @@ -505,286 +490,6 @@ Rect DisplayBuffer::get_clipping() { return this->clipping_rectangle_.back(); } } -bool Glyph::get_pixel(int x, int y) const { - const int x_data = x - this->glyph_data_->offset_x; - const int y_data = y - this->glyph_data_->offset_y; - if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) - return false; - const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; - const uint32_t pos = x_data + y_data * width_8; - return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); -} -const char *Glyph::get_char() const { return this->glyph_data_->a_char; } -bool Glyph::compare_to(const char *str) const { - // 1 -> this->char_ - // 2 -> str - for (uint32_t i = 0;; i++) { - if (this->glyph_data_->a_char[i] == '\0') - return true; - if (str[i] == '\0') - return false; - if (this->glyph_data_->a_char[i] > str[i]) - return false; - if (this->glyph_data_->a_char[i] < str[i]) - return true; - } - // this should not happen - return false; -} -int Glyph::match_length(const char *str) const { - for (uint32_t i = 0;; i++) { - if (this->glyph_data_->a_char[i] == '\0') - return i; - if (str[i] != this->glyph_data_->a_char[i]) - return 0; - } - // this should not happen - return 0; -} -void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { - *x1 = this->glyph_data_->offset_x; - *y1 = this->glyph_data_->offset_y; - *width = this->glyph_data_->width; - *height = this->glyph_data_->height; -} -int Font::match_next_glyph(const char *str, int *match_length) { - int lo = 0; - int hi = this->glyphs_.size() - 1; - while (lo != hi) { - int mid = (lo + hi + 1) / 2; - if (this->glyphs_[mid].compare_to(str)) { - lo = mid; - } else { - hi = mid - 1; - } - } - *match_length = this->glyphs_[lo].match_length(str); - if (*match_length <= 0) - return -1; - return lo; -} -void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) { - *baseline = this->baseline_; - *height = this->height_; - int i = 0; - int min_x = 0; - bool has_char = false; - int x = 0; - while (str[i] != '\0') { - int match_length; - int glyph_n = this->match_next_glyph(str + i, &match_length); - if (glyph_n < 0) { - // Unknown char, skip - if (!this->get_glyphs().empty()) - x += this->get_glyphs()[0].glyph_data_->width; - i++; - continue; - } - - const Glyph &glyph = this->glyphs_[glyph_n]; - if (!has_char) { - min_x = glyph.glyph_data_->offset_x; - } else { - min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); - } - x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; - - i += match_length; - has_char = true; - } - *x_offset = min_x; - *width = x - min_x; -} -Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { - glyphs_.reserve(data_nr); - for (int i = 0; i < data_nr; ++i) - glyphs_.emplace_back(&data[i]); -} - -void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { - switch (type_) { - case IMAGE_TYPE_BINARY: { - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - if (this->get_binary_pixel_(img_x, img_y)) { - display->draw_pixel_at(x + img_x, y + img_y, color_on); - } else if (!this->transparent_) { - display->draw_pixel_at(x + img_x, y + img_y, color_off); - } - } - } - break; - } - case IMAGE_TYPE_GRAYSCALE: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_grayscale_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB565: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgb565_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB24: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgb24_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGBA: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgba_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - } -} -Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return color_off; - switch (this->type_) { - case IMAGE_TYPE_BINARY: - return this->get_binary_pixel_(x, y) ? color_on : color_off; - case IMAGE_TYPE_GRAYSCALE: - return this->get_grayscale_pixel_(x, y); - case IMAGE_TYPE_RGB565: - return this->get_rgb565_pixel_(x, y); - case IMAGE_TYPE_RGB24: - return this->get_rgb24_pixel_(x, y); - case IMAGE_TYPE_RGBA: - return this->get_rgba_pixel_(x, y); - default: - return color_off; - } -} -bool Image::get_binary_pixel_(int x, int y) const { - const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; - const uint32_t pos = x + y * width_8; - return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); -} -Color Image::get_rgba_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 4; - return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); -} -Color Image::get_rgb24_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 3; - Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2)); - if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) { - // (0, 0, 1) has been defined as transparent color for non-alpha images. - // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if) - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Image::get_rgb565_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 2; - uint16_t rgb565 = - progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); - auto r = (rgb565 & 0xF800) >> 11; - auto g = (rgb565 & 0x07E0) >> 5; - auto b = rgb565 & 0x001F; - Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); - if (rgb565 == 0x0020 && transparent_) { - // darkest green has been defined as transparent color for transparent RGB565 images. - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Image::get_grayscale_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_); - const uint8_t gray = progmem_read_byte(this->data_start_ + pos); - uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; - return Color(gray, gray, gray, alpha); -} -int Image::get_width() const { return this->width_; } -int Image::get_height() const { return this->height_; } -ImageType Image::get_type() const { return this->type_; } -Image::Image(const uint8_t *data_start, int width, int height, ImageType type) - : width_(width), height_(height), type_(type), data_start_(data_start) {} - -Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) - : Image(data_start, width, height, type), - animation_data_start_(data_start), - current_frame_(0), - animation_frame_count_(animation_frame_count), - loop_start_frame_(0), - loop_end_frame_(animation_frame_count_), - loop_count_(0), - loop_current_iteration_(1) {} -void Animation::set_loop(uint32_t start_frame, uint32_t end_frame, int count) { - loop_start_frame_ = std::min(start_frame, animation_frame_count_); - loop_end_frame_ = std::min(end_frame, animation_frame_count_); - loop_count_ = count; - loop_current_iteration_ = 1; -} - -uint32_t Animation::get_animation_frame_count() const { return this->animation_frame_count_; } -int Animation::get_current_frame() const { return this->current_frame_; } -void Animation::next_frame() { - this->current_frame_++; - if (loop_count_ && this->current_frame_ == loop_end_frame_ && - (this->loop_current_iteration_ < loop_count_ || loop_count_ < 0)) { - this->current_frame_ = loop_start_frame_; - this->loop_current_iteration_++; - } - if (this->current_frame_ >= animation_frame_count_) { - this->loop_current_iteration_ = 1; - this->current_frame_ = 0; - } - - this->update_data_start_(); -} -void Animation::prev_frame() { - this->current_frame_--; - if (this->current_frame_ < 0) { - this->current_frame_ = this->animation_frame_count_ - 1; - } - - this->update_data_start_(); -} - -void Animation::set_frame(int frame) { - unsigned abs_frame = abs(frame); - - if (abs_frame < this->animation_frame_count_) { - if (frame >= 0) { - this->current_frame_ = frame; - } else { - this->current_frame_ = this->animation_frame_count_ - abs_frame; - } - } - - this->update_data_start_(); -} - -void Animation::update_data_start_() { - const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; - this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; -} DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} void DisplayPage::show() { this->parent_->show_page(this); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 0c31ac24d9..b66ec529f7 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -16,6 +16,10 @@ #include "esphome/components/qr_code/qr_code.h" #endif +#include "animation.h" +#include "font.h" +#include "image.h" + namespace esphome { namespace display { @@ -70,19 +74,6 @@ enum class TextAlign { BOTTOM_RIGHT = BOTTOM | RIGHT, }; -/// Turn the pixel OFF. -extern const Color COLOR_OFF; -/// Turn the pixel ON. -extern const Color COLOR_ON; - -enum ImageType { - IMAGE_TYPE_BINARY = 0, - IMAGE_TYPE_GRAYSCALE = 1, - IMAGE_TYPE_RGB24 = 2, - IMAGE_TYPE_RGB565 = 3, - IMAGE_TYPE_RGBA = 4, -}; - enum DisplayType { DISPLAY_TYPE_BINARY = 1, DISPLAY_TYPE_GRAYSCALE = 2, @@ -123,8 +114,6 @@ class Rect { void info(const std::string &prefix = "rect info:"); }; -class BaseImage; -class Font; class DisplayBuffer; class DisplayPage; class DisplayOnPageChangeTrigger; @@ -475,123 +464,6 @@ class DisplayPage { DisplayPage *next_{nullptr}; }; -struct GlyphData { - const char *a_char; - const uint8_t *data; - int offset_x; - int offset_y; - int width; - int height; -}; - -class Glyph { - public: - Glyph(const GlyphData *data) : glyph_data_(data) {} - - bool get_pixel(int x, int y) const; - - const char *get_char() const; - - bool compare_to(const char *str) const; - - int match_length(const char *str) const; - - void scan_area(int *x1, int *y1, int *width, int *height) const; - - protected: - friend Font; - friend DisplayBuffer; - - const GlyphData *glyph_data_; -}; - -class Font { - public: - /** Construct the font with the given glyphs. - * - * @param glyphs A vector of glyphs, must be sorted lexicographically. - * @param baseline The y-offset from the top of the text to the baseline. - * @param bottom The y-offset from the top of the text to the bottom (i.e. height). - */ - Font(const GlyphData *data, int data_nr, int baseline, int height); - - int match_next_glyph(const char *str, int *match_length); - - void measure(const char *str, int *width, int *x_offset, int *baseline, int *height); - inline int get_baseline() { return this->baseline_; } - inline int get_height() { return this->height_; } - - const std::vector> &get_glyphs() const { return glyphs_; } - - protected: - std::vector> glyphs_; - int baseline_; - int height_; -}; - -class BaseImage { - public: - virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; -}; - -class Image : public BaseImage { - public: - Image(const uint8_t *data_start, int width, int height, ImageType type); - Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; - int get_width() const override; - int get_height() const override; - ImageType get_type() const; - - void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; - - void set_transparency(bool transparent) { transparent_ = transparent; } - bool has_transparency() const { return transparent_; } - - protected: - bool get_binary_pixel_(int x, int y) const; - Color get_rgb24_pixel_(int x, int y) const; - Color get_rgba_pixel_(int x, int y) const; - Color get_rgb565_pixel_(int x, int y) const; - Color get_grayscale_pixel_(int x, int y) const; - - int width_; - int height_; - ImageType type_; - const uint8_t *data_start_; - bool transparent_; -}; - -class Animation : public Image { - public: - Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); - - uint32_t get_animation_frame_count() const; - int get_current_frame() const; - void next_frame(); - void prev_frame(); - - /** Selects a specific frame within the animation. - * - * @param frame If possitive, advance to the frame. If negative, recede to that frame from the end frame. - */ - void set_frame(int frame); - - void set_loop(uint32_t start_frame, uint32_t end_frame, int count); - - protected: - void update_data_start_(); - - const uint8_t *animation_data_start_; - int current_frame_; - uint32_t animation_frame_count_; - uint32_t loop_start_frame_; - uint32_t loop_end_frame_; - int loop_count_; - int loop_current_iteration_; -}; - template class DisplayPageShowAction : public Action { public: TEMPLATABLE_VALUE(DisplayPage *, page) diff --git a/esphome/components/display/font.cpp b/esphome/components/display/font.cpp new file mode 100644 index 0000000000..1833ef5023 --- /dev/null +++ b/esphome/components/display/font.cpp @@ -0,0 +1,105 @@ +#include "font.h" + +#include "esphome/core/hal.h" + +namespace esphome { +namespace display { + +bool Glyph::get_pixel(int x, int y) const { + const int x_data = x - this->glyph_data_->offset_x; + const int y_data = y - this->glyph_data_->offset_y; + if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) + return false; + const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; + const uint32_t pos = x_data + y_data * width_8; + return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); +} +const char *Glyph::get_char() const { return this->glyph_data_->a_char; } +bool Glyph::compare_to(const char *str) const { + // 1 -> this->char_ + // 2 -> str + for (uint32_t i = 0;; i++) { + if (this->glyph_data_->a_char[i] == '\0') + return true; + if (str[i] == '\0') + return false; + if (this->glyph_data_->a_char[i] > str[i]) + return false; + if (this->glyph_data_->a_char[i] < str[i]) + return true; + } + // this should not happen + return false; +} +int Glyph::match_length(const char *str) const { + for (uint32_t i = 0;; i++) { + if (this->glyph_data_->a_char[i] == '\0') + return i; + if (str[i] != this->glyph_data_->a_char[i]) + return 0; + } + // this should not happen + return 0; +} +void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { + *x1 = this->glyph_data_->offset_x; + *y1 = this->glyph_data_->offset_y; + *width = this->glyph_data_->width; + *height = this->glyph_data_->height; +} +int Font::match_next_glyph(const char *str, int *match_length) { + int lo = 0; + int hi = this->glyphs_.size() - 1; + while (lo != hi) { + int mid = (lo + hi + 1) / 2; + if (this->glyphs_[mid].compare_to(str)) { + lo = mid; + } else { + hi = mid - 1; + } + } + *match_length = this->glyphs_[lo].match_length(str); + if (*match_length <= 0) + return -1; + return lo; +} +void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) { + *baseline = this->baseline_; + *height = this->height_; + int i = 0; + int min_x = 0; + bool has_char = false; + int x = 0; + while (str[i] != '\0') { + int match_length; + int glyph_n = this->match_next_glyph(str + i, &match_length); + if (glyph_n < 0) { + // Unknown char, skip + if (!this->get_glyphs().empty()) + x += this->get_glyphs()[0].glyph_data_->width; + i++; + continue; + } + + const Glyph &glyph = this->glyphs_[glyph_n]; + if (!has_char) { + min_x = glyph.glyph_data_->offset_x; + } else { + min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); + } + x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; + + i += match_length; + has_char = true; + } + *x_offset = min_x; + *width = x - min_x; +} +Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { + glyphs_.reserve(data_nr); + for (int i = 0; i < data_nr; ++i) + glyphs_.emplace_back(&data[i]); +} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/font.h b/esphome/components/display/font.h new file mode 100644 index 0000000000..08b457116e --- /dev/null +++ b/esphome/components/display/font.h @@ -0,0 +1,66 @@ +#pragma once + +#include "esphome/core/datatypes.h" + +namespace esphome { +namespace display { + +class DisplayBuffer; +class Font; + +struct GlyphData { + const char *a_char; + const uint8_t *data; + int offset_x; + int offset_y; + int width; + int height; +}; + +class Glyph { + public: + Glyph(const GlyphData *data) : glyph_data_(data) {} + + bool get_pixel(int x, int y) const; + + const char *get_char() const; + + bool compare_to(const char *str) const; + + int match_length(const char *str) const; + + void scan_area(int *x1, int *y1, int *width, int *height) const; + + protected: + friend Font; + friend DisplayBuffer; + + const GlyphData *glyph_data_; +}; + +class Font { + public: + /** Construct the font with the given glyphs. + * + * @param glyphs A vector of glyphs, must be sorted lexicographically. + * @param baseline The y-offset from the top of the text to the baseline. + * @param bottom The y-offset from the top of the text to the bottom (i.e. height). + */ + Font(const GlyphData *data, int data_nr, int baseline, int height); + + int match_next_glyph(const char *str, int *match_length); + + void measure(const char *str, int *width, int *x_offset, int *baseline, int *height); + inline int get_baseline() { return this->baseline_; } + inline int get_height() { return this->height_; } + + const std::vector> &get_glyphs() const { return glyphs_; } + + protected: + std::vector> glyphs_; + int baseline_; + int height_; +}; + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/image.cpp b/esphome/components/display/image.cpp new file mode 100644 index 0000000000..b3cab3ff7f --- /dev/null +++ b/esphome/components/display/image.cpp @@ -0,0 +1,135 @@ +#include "image.h" + +#include "esphome/core/hal.h" +#include "display_buffer.h" + +namespace esphome { +namespace display { + +void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { + switch (type_) { + case IMAGE_TYPE_BINARY: { + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + if (this->get_binary_pixel_(img_x, img_y)) { + display->draw_pixel_at(x + img_x, y + img_y, color_on); + } else if (!this->transparent_) { + display->draw_pixel_at(x + img_x, y + img_y, color_off); + } + } + } + break; + } + case IMAGE_TYPE_GRAYSCALE: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_grayscale_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB565: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb565_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB24: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb24_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGBA: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgba_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + } +} +Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { + if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) + return color_off; + switch (this->type_) { + case IMAGE_TYPE_BINARY: + return this->get_binary_pixel_(x, y) ? color_on : color_off; + case IMAGE_TYPE_GRAYSCALE: + return this->get_grayscale_pixel_(x, y); + case IMAGE_TYPE_RGB565: + return this->get_rgb565_pixel_(x, y); + case IMAGE_TYPE_RGB24: + return this->get_rgb24_pixel_(x, y); + case IMAGE_TYPE_RGBA: + return this->get_rgba_pixel_(x, y); + default: + return color_off; + } +} +bool Image::get_binary_pixel_(int x, int y) const { + const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; + const uint32_t pos = x + y * width_8; + return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); +} +Color Image::get_rgba_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 4; + return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), + progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); +} +Color Image::get_rgb24_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 3; + Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), + progmem_read_byte(this->data_start_ + pos + 2)); + if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) { + // (0, 0, 1) has been defined as transparent color for non-alpha images. + // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if) + color.w = 0; + } else { + color.w = 0xFF; + } + return color; +} +Color Image::get_rgb565_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 2; + uint16_t rgb565 = + progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); + auto r = (rgb565 & 0xF800) >> 11; + auto g = (rgb565 & 0x07E0) >> 5; + auto b = rgb565 & 0x001F; + Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); + if (rgb565 == 0x0020 && transparent_) { + // darkest green has been defined as transparent color for transparent RGB565 images. + color.w = 0; + } else { + color.w = 0xFF; + } + return color; +} +Color Image::get_grayscale_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_); + const uint8_t gray = progmem_read_byte(this->data_start_ + pos); + uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; + return Color(gray, gray, gray, alpha); +} +int Image::get_width() const { return this->width_; } +int Image::get_height() const { return this->height_; } +ImageType Image::get_type() const { return this->type_; } +Image::Image(const uint8_t *data_start, int width, int height, ImageType type) + : width_(width), height_(height), type_(type), data_start_(data_start) {} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/image.h b/esphome/components/display/image.h new file mode 100644 index 0000000000..ac2d5a3421 --- /dev/null +++ b/esphome/components/display/image.h @@ -0,0 +1,75 @@ +#pragma once +#include "esphome/core/color.h" + +namespace esphome { +namespace display { + +enum ImageType { + IMAGE_TYPE_BINARY = 0, + IMAGE_TYPE_GRAYSCALE = 1, + IMAGE_TYPE_RGB24 = 2, + IMAGE_TYPE_RGB565 = 3, + IMAGE_TYPE_RGBA = 4, +}; + +inline int image_type_to_bpp(ImageType type) { + switch (type) { + case IMAGE_TYPE_BINARY: + return 1; + case IMAGE_TYPE_GRAYSCALE: + return 8; + case IMAGE_TYPE_RGB565: + return 16; + case IMAGE_TYPE_RGB24: + return 24; + case IMAGE_TYPE_RGBA: + return 32; + } + return 0; +} + +inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } + +/// Turn the pixel OFF. +extern const Color COLOR_OFF; +/// Turn the pixel ON. +extern const Color COLOR_ON; + +class DisplayBuffer; + +class BaseImage { + public: + virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; +}; + +class Image : public BaseImage { + public: + Image(const uint8_t *data_start, int width, int height, ImageType type); + Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; + int get_width() const override; + int get_height() const override; + ImageType get_type() const; + + void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; + + void set_transparency(bool transparent) { transparent_ = transparent; } + bool has_transparency() const { return transparent_; } + + protected: + bool get_binary_pixel_(int x, int y) const; + Color get_rgb24_pixel_(int x, int y) const; + Color get_rgba_pixel_(int x, int y) const; + Color get_rgb565_pixel_(int x, int y) const; + Color get_grayscale_pixel_(int x, int y) const; + + int width_; + int height_; + ImageType type_; + const uint8_t *data_start_; + bool transparent_; +}; + +} // namespace display +} // namespace esphome diff --git a/tests/test2.yaml b/tests/test2.yaml index 2873d0e8e0..fa4b97c7c1 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -695,6 +695,13 @@ image: file: mdi:alert-outline type: BINARY +graph: + - id: my_graph + sensor: ha_hello_world_temperature + duration: 1h + width: 100 + height: 100 + cap1188: id: cap1188_component address: 0x29 From 1a7f121ac67f17957ce34962b37fec56d74d63d6 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sat, 17 Jun 2023 10:38:44 +0200 Subject: [PATCH 0078/2607] Add support for ESP32-S3-BOX displays (#4942) The ESP32-S3-BOX display has an ILI9xxx driver Add the needed configuration so that it works. --- esphome/components/ili9xxx/display.py | 1 + .../components/ili9xxx/ili9xxx_display.cpp | 11 +++++++ esphome/components/ili9xxx/ili9xxx_display.h | 5 ++++ esphome/components/ili9xxx/ili9xxx_init.h | 30 +++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 98edadb6a5..29603eb30f 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -44,6 +44,7 @@ MODELS = { "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), + "S3BOX": ili9XXX_ns.class_("ILI9XXXS3Box", ili9XXXSPI), "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), } diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index ad70bd6e48..6fc6da3cdb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -421,6 +421,17 @@ void ILI9XXXST7796::initialize() { } } +// 24_TFT rotated display +void ILI9XXXS3Box::initialize() { + this->init_lcd_(INITCMD_S3BOX); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 240; + } +} + // 24_TFT rotated display void ILI9XXXS3BoxLite::initialize() { this->init_lcd_(INITCMD_S3BOXLITE); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index dbdf023bc0..dc7bfdc6eb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -134,6 +134,11 @@ class ILI9XXXST7796 : public ILI9XXXDisplay { void initialize() override; }; +class ILI9XXXS3Box : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + class ILI9XXXS3BoxLite : public ILI9XXXDisplay { protected: void initialize() override; diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 36cc30ec2e..a17e6b127c 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -169,6 +169,36 @@ static const uint8_t PROGMEM INITCMD_ST7796[] = { 0x00 // End of list }; +static const uint8_t PROGMEM INITCMD_S3BOX[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, 0xC8, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x18, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { 0xEF, 3, 0x03, 0x80, 0x02, 0xCF, 3, 0x00, 0xC1, 0x30, From e1b0d860988be0aeb113da20c11d4ad20298dd00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Sun, 18 Jun 2023 21:24:23 +0200 Subject: [PATCH 0079/2607] display: allow to align image with `ImageAlign` (#4933) --- esphome/components/display/display_buffer.cpp | 31 ++++++++++ esphome/components/display/display_buffer.h | 61 ++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 8092b9f12f..672c6a22b0 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -311,6 +311,37 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al } void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) { + this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off); +} + +void DisplayBuffer::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) { + auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT))); + auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT))); + + switch (x_align) { + case ImageAlign::RIGHT: + x -= image->get_width(); + break; + case ImageAlign::CENTER_HORIZONTAL: + x -= image->get_width() / 2; + break; + case ImageAlign::LEFT: + default: + break; + } + + switch (y_align) { + case ImageAlign::BOTTOM: + y -= image->get_height(); + break; + case ImageAlign::CENTER_VERTICAL: + y -= image->get_height() / 2; + break; + case ImageAlign::TOP: + default: + break; + } + image->draw(x, y, this, color_on, color_off); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index b66ec529f7..652039517f 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -74,6 +74,54 @@ enum class TextAlign { BOTTOM_RIGHT = BOTTOM | RIGHT, }; +/** ImageAlign is used to tell the display class how to position a image. By default + * the coordinates you enter for the image() functions take the upper left corner of the image + * as the "anchor" point. You can customize this behavior to, for example, make the coordinates + * refer to the *center* of the image. + * + * All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis + * these options are allowed: + * + * - LEFT (x-coordinate of anchor point is on left) + * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image) + * - RIGHT (x-coordinate of anchor point is on right) + * + * For the Y-Axis alignment these options are allowed: + * + * - TOP (y-coordinate of anchor is on the top of the image) + * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image) + * - BOTTOM (y-coordinate of anchor is on the bottom of the image) + * + * These options are then combined to create combined TextAlignment options like: + * - TOP_LEFT (default) + * - CENTER (anchor point is in the middle of the image bounds) + * - ... + */ +enum class ImageAlign { + TOP = 0x00, + CENTER_VERTICAL = 0x01, + BOTTOM = 0x02, + + LEFT = 0x00, + CENTER_HORIZONTAL = 0x04, + RIGHT = 0x08, + + TOP_LEFT = TOP | LEFT, + TOP_CENTER = TOP | CENTER_HORIZONTAL, + TOP_RIGHT = TOP | RIGHT, + + CENTER_LEFT = CENTER_VERTICAL | LEFT, + CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, + CENTER_RIGHT = CENTER_VERTICAL | RIGHT, + + BOTTOM_LEFT = BOTTOM | LEFT, + BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, + BOTTOM_RIGHT = BOTTOM | RIGHT, + + HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT, + VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM +}; + enum DisplayType { DISPLAY_TYPE_BINARY = 1, DISPLAY_TYPE_GRAYSCALE = 2, @@ -300,12 +348,23 @@ class DisplayBuffer { * * @param x The x coordinate of the upper left corner. * @param y The y coordinate of the upper left corner. - * @param image The image to draw + * @param image The image to draw. * @param color_on The color to replace in binary images for the on bits. * @param color_off The color to replace in binary images for the off bits. */ void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + /** Draw the `image` at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param image The image to draw. + * @param align The alignment of the image. + * @param color_on The color to replace in binary images for the on bits. + * @param color_off The color to replace in binary images for the off bits. + */ + void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + #ifdef USE_GRAPH /** Draw the `graph` with the top-left corner at [x,y] to the screen. * From d4099d68a78fb97bb921eb851fa72a3e3407624e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Jun 2023 07:24:44 +1200 Subject: [PATCH 0080/2607] Use HW SPI for rp2040 (#4955) --- esphome/components/spi/spi.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 141bfb9448..c9bb075fb5 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -87,6 +87,30 @@ void SPIComponent::setup() { return; } #endif // USE_ESP32 +#ifdef USE_RP2040 + static uint8_t spi_bus_num = 0; + if (spi_bus_num >= 2) { + use_hw_spi = false; + } + if (use_hw_spi) { + SPIClassRP2040 *spi; + if (spi_bus_num == 0) { + spi = &SPI; + } else { + spi = &SPI1; + } + spi_bus_num++; + + if (miso_pin != -1) + spi->setRX(miso_pin); + if (mosi_pin != -1) + spi->setTX(mosi_pin); + spi->setSCK(clk_pin); + this->hw_spi_ = spi; + this->hw_spi_->begin(); + return; + } +#endif // USE_RP2040 #endif // USE_SPI_ARDUINO_BACKEND if (this->miso_ != nullptr) { From 2ffd430b0ba66b2450f7c8845a2252b7a987a2f1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:51:44 +1000 Subject: [PATCH 0081/2607] Add support in vbus component for Deltasol BS 2009 (#4943) --- esphome/components/vbus/__init__.py | 1 + .../components/vbus/binary_sensor/__init__.py | 52 ++++++++ .../vbus/binary_sensor/vbus_binary_sensor.cpp | 22 ++++ .../vbus/binary_sensor/vbus_binary_sensor.h | 21 +++ esphome/components/vbus/sensor/__init__.py | 121 ++++++++++++++++++ .../components/vbus/sensor/vbus_sensor.cpp | 41 ++++++ esphome/components/vbus/sensor/vbus_sensor.h | 31 +++++ 7 files changed, 289 insertions(+) diff --git a/esphome/components/vbus/__init__.py b/esphome/components/vbus/__init__.py index 70f130e23b..99a473a3dc 100644 --- a/esphome/components/vbus/__init__.py +++ b/esphome/components/vbus/__init__.py @@ -15,6 +15,7 @@ VBus = vbus_ns.class_("VBus", uart.UARTDevice, cg.Component) CONF_VBUS_ID = "vbus_id" CONF_DELTASOL_BS_PLUS = "deltasol_bs_plus" +CONF_DELTASOL_BS_2009 = "deltasol_bs_2009" CONF_DELTASOL_C = "deltasol_c" CONF_DELTASOL_CS2 = "deltasol_cs2" CONF_DELTASOL_CS_PLUS = "deltasol_cs_plus" diff --git a/esphome/components/vbus/binary_sensor/__init__.py b/esphome/components/vbus/binary_sensor/__init__.py index 9901fb2724..70fbda2d1f 100644 --- a/esphome/components/vbus/binary_sensor/__init__.py +++ b/esphome/components/vbus/binary_sensor/__init__.py @@ -18,12 +18,14 @@ from .. import ( VBus, CONF_VBUS_ID, CONF_DELTASOL_BS_PLUS, + CONF_DELTASOL_BS_2009, CONF_DELTASOL_C, CONF_DELTASOL_CS2, CONF_DELTASOL_CS_PLUS, ) DeltaSol_BS_Plus = vbus_ns.class_("DeltaSolBSPlusBSensor", cg.Component) +DeltaSol_BS_2009 = vbus_ns.class_("DeltaSolBS2009BSensor", cg.Component) DeltaSol_C = vbus_ns.class_("DeltaSolCBSensor", cg.Component) DeltaSol_CS2 = vbus_ns.class_("DeltaSolCS2BSensor", cg.Component) DeltaSol_CS_Plus = vbus_ns.class_("DeltaSolCSPlusBSensor", cg.Component) @@ -42,6 +44,7 @@ CONF_COLLECTOR_FROST = "collector_frost" CONF_TUBE_COLLECTOR = "tube_collector" CONF_RECOOLING = "recooling" CONF_HQM = "hqm" +CONF_FROST_PROTECTION_ACTIVE = "frost_protection_active" CONFIG_SCHEMA = cv.typed_schema( { @@ -87,6 +90,33 @@ CONFIG_SCHEMA = cv.typed_schema( ), } ), + CONF_DELTASOL_BS_2009: cv.COMPONENT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(DeltaSol_BS_2009), + cv.GenerateID(CONF_VBUS_ID): cv.use_id(VBus), + cv.Optional(CONF_SENSOR1_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR2_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR3_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_SENSOR4_ERROR): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PROBLEM, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional( + CONF_FROST_PROTECTION_ACTIVE + ): binary_sensor.binary_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ), CONF_DELTASOL_C: cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(DeltaSol_C), @@ -222,6 +252,28 @@ async def to_code(config): sens = await binary_sensor.new_binary_sensor(config[CONF_HQM]) cg.add(var.set_hqm_bsensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_BS_2009: + cg.add(var.set_command(0x0100)) + cg.add(var.set_source(0x427B)) + cg.add(var.set_dest(0x0010)) + if CONF_SENSOR1_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR1_ERROR]) + cg.add(var.set_s1_error_bsensor(sens)) + if CONF_SENSOR2_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR2_ERROR]) + cg.add(var.set_s2_error_bsensor(sens)) + if CONF_SENSOR3_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR3_ERROR]) + cg.add(var.set_s3_error_bsensor(sens)) + if CONF_SENSOR4_ERROR in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_SENSOR4_ERROR]) + cg.add(var.set_s4_error_bsensor(sens)) + if CONF_FROST_PROTECTION_ACTIVE in config: + sens = await binary_sensor.new_binary_sensor( + config[CONF_FROST_PROTECTION_ACTIVE] + ) + cg.add(var.set_frost_protection_active_bsensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_C: cg.add(var.set_command(0x0100)) cg.add(var.set_source(0x4212)) diff --git a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp index 6edbae22ba..087d049a57 100644 --- a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp +++ b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp @@ -50,6 +50,28 @@ void DeltaSolBSPlusBSensor::handle_message(std::vector &message) { this->hqm_bsensor_->publish_state(message[15] & 0x20); } +void DeltaSolBS2009BSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Deltasol BS 2009:"); + LOG_BINARY_SENSOR(" ", "Sensor 1 Error", this->s1_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 2 Error", this->s2_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 3 Error", this->s3_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Sensor 4 Error", this->s4_error_bsensor_); + LOG_BINARY_SENSOR(" ", "Frost Protection Active", this->frost_protection_active_bsensor_); +} + +void DeltaSolBS2009BSensor::handle_message(std::vector &message) { + if (this->s1_error_bsensor_ != nullptr) + this->s1_error_bsensor_->publish_state(message[20] & 1); + if (this->s2_error_bsensor_ != nullptr) + this->s2_error_bsensor_->publish_state(message[20] & 2); + if (this->s3_error_bsensor_ != nullptr) + this->s3_error_bsensor_->publish_state(message[20] & 4); + if (this->s4_error_bsensor_ != nullptr) + this->s4_error_bsensor_->publish_state(message[20] & 8); + if (this->frost_protection_active_bsensor_ != nullptr) + this->frost_protection_active_bsensor_->publish_state(message[25] & 1); +} + void DeltaSolCBSensor::dump_config() { ESP_LOGCONFIG(TAG, "Deltasol C:"); LOG_BINARY_SENSOR(" ", "Sensor 1 Error", this->s1_error_bsensor_); diff --git a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h index c0a823a0ab..146aa1b673 100644 --- a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h +++ b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.h @@ -39,6 +39,27 @@ class DeltaSolBSPlusBSensor : public VBusListener, public Component { void handle_message(std::vector &message) override; }; +class DeltaSolBS2009BSensor : public VBusListener, public Component { + public: + void dump_config() override; + void set_s1_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s1_error_bsensor_ = bsensor; } + void set_s2_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s2_error_bsensor_ = bsensor; } + void set_s3_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s3_error_bsensor_ = bsensor; } + void set_s4_error_bsensor(binary_sensor::BinarySensor *bsensor) { this->s4_error_bsensor_ = bsensor; } + void set_frost_protection_active_bsensor(binary_sensor::BinarySensor *bsensor) { + this->frost_protection_active_bsensor_ = bsensor; + } + + protected: + binary_sensor::BinarySensor *s1_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s2_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s3_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *s4_error_bsensor_{nullptr}; + binary_sensor::BinarySensor *frost_protection_active_bsensor_{nullptr}; + + void handle_message(std::vector &message) override; +}; + class DeltaSolCBSensor : public VBusListener, public Component { public: void dump_config() override; diff --git a/esphome/components/vbus/sensor/__init__.py b/esphome/components/vbus/sensor/__init__.py index bce28758ce..2ad9da424e 100644 --- a/esphome/components/vbus/sensor/__init__.py +++ b/esphome/components/vbus/sensor/__init__.py @@ -33,12 +33,14 @@ from .. import ( VBus, CONF_VBUS_ID, CONF_DELTASOL_BS_PLUS, + CONF_DELTASOL_BS_2009, CONF_DELTASOL_C, CONF_DELTASOL_CS2, CONF_DELTASOL_CS_PLUS, ) DeltaSol_BS_Plus = vbus_ns.class_("DeltaSolBSPlusSensor", cg.Component) +DeltaSol_BS_2009 = vbus_ns.class_("DeltaSolBS2009Sensor", cg.Component) DeltaSol_C = vbus_ns.class_("DeltaSolCSensor", cg.Component) DeltaSol_CS2 = vbus_ns.class_("DeltaSolCS2Sensor", cg.Component) DeltaSol_CS_Plus = vbus_ns.class_("DeltaSolCSPlusSensor", cg.Component) @@ -142,6 +144,87 @@ CONFIG_SCHEMA = cv.typed_schema( ), } ), + CONF_DELTASOL_BS_2009: cv.COMPONENT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(DeltaSol_BS_2009), + cv.GenerateID(CONF_VBUS_ID): cv.use_id(VBus), + cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_3): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_4): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PUMP_SPEED_1): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PUMP_SPEED_2): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_OPERATING_HOURS_1): sensor.sensor_schema( + unit_of_measurement=UNIT_HOUR, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_OPERATING_HOURS_2): sensor.sensor_schema( + unit_of_measurement=UNIT_HOUR, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_HEAT_QUANTITY): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT_HOURS, + icon=ICON_RADIATOR, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TIME): sensor.sensor_schema( + unit_of_measurement=UNIT_MINUTE, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DURATION, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_VERSION): sensor.sensor_schema( + accuracy_decimals=2, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ), CONF_DELTASOL_C: cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(DeltaSol_C), @@ -437,6 +520,44 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_VERSION]) cg.add(var.set_version_sensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_BS_2009: + cg.add(var.set_command(0x0100)) + cg.add(var.set_source(0x427B)) + cg.add(var.set_dest(0x0010)) + if CONF_TEMPERATURE_1 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_1]) + cg.add(var.set_temperature1_sensor(sens)) + if CONF_TEMPERATURE_2 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_2]) + cg.add(var.set_temperature2_sensor(sens)) + if CONF_TEMPERATURE_3 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_3]) + cg.add(var.set_temperature3_sensor(sens)) + if CONF_TEMPERATURE_4 in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE_4]) + cg.add(var.set_temperature4_sensor(sens)) + if CONF_PUMP_SPEED_1 in config: + sens = await sensor.new_sensor(config[CONF_PUMP_SPEED_1]) + cg.add(var.set_pump_speed1_sensor(sens)) + if CONF_PUMP_SPEED_2 in config: + sens = await sensor.new_sensor(config[CONF_PUMP_SPEED_2]) + cg.add(var.set_pump_speed2_sensor(sens)) + if CONF_OPERATING_HOURS_1 in config: + sens = await sensor.new_sensor(config[CONF_OPERATING_HOURS_1]) + cg.add(var.set_operating_hours1_sensor(sens)) + if CONF_OPERATING_HOURS_2 in config: + sens = await sensor.new_sensor(config[CONF_OPERATING_HOURS_2]) + cg.add(var.set_operating_hours2_sensor(sens)) + if CONF_HEAT_QUANTITY in config: + sens = await sensor.new_sensor(config[CONF_HEAT_QUANTITY]) + cg.add(var.set_heat_quantity_sensor(sens)) + if CONF_TIME in config: + sens = await sensor.new_sensor(config[CONF_TIME]) + cg.add(var.set_time_sensor(sens)) + if CONF_VERSION in config: + sens = await sensor.new_sensor(config[CONF_VERSION]) + cg.add(var.set_version_sensor(sens)) + elif config[CONF_MODEL] == CONF_DELTASOL_C: cg.add(var.set_command(0x0100)) cg.add(var.set_source(0x4212)) diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 8261773431..5644f707d0 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -57,6 +57,47 @@ void DeltaSolBSPlusSensor::handle_message(std::vector &message) { this->version_sensor_->publish_state(get_u16(message, 26) * 0.01f); } +void DeltaSolBS2009Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "Deltasol BS 2009:"); + LOG_SENSOR(" ", "Temperature 1", this->temperature1_sensor_); + LOG_SENSOR(" ", "Temperature 2", this->temperature2_sensor_); + LOG_SENSOR(" ", "Temperature 3", this->temperature3_sensor_); + LOG_SENSOR(" ", "Temperature 4", this->temperature4_sensor_); + LOG_SENSOR(" ", "Pump Speed 1", this->pump_speed1_sensor_); + LOG_SENSOR(" ", "Pump Speed 2", this->pump_speed2_sensor_); + LOG_SENSOR(" ", "Operating Hours 1", this->operating_hours1_sensor_); + LOG_SENSOR(" ", "Operating Hours 2", this->operating_hours2_sensor_); + LOG_SENSOR(" ", "Heat Quantity", this->heat_quantity_sensor_); + LOG_SENSOR(" ", "System Time", this->time_sensor_); + LOG_SENSOR(" ", "FW Version", this->version_sensor_); +} + +void DeltaSolBS2009Sensor::handle_message(std::vector &message) { + if (this->temperature1_sensor_ != nullptr) + this->temperature1_sensor_->publish_state(get_i16(message, 0) * 0.1f); + if (this->temperature2_sensor_ != nullptr) + this->temperature2_sensor_->publish_state(get_i16(message, 2) * 0.1f); + if (this->temperature3_sensor_ != nullptr) + this->temperature3_sensor_->publish_state(get_i16(message, 4) * 0.1f); + if (this->temperature4_sensor_ != nullptr) + this->temperature4_sensor_->publish_state(get_i16(message, 6) * 0.1f); + if (this->pump_speed1_sensor_ != nullptr) + this->pump_speed1_sensor_->publish_state(message[8]); + if (this->pump_speed2_sensor_ != nullptr) + this->pump_speed2_sensor_->publish_state(message[12]); + if (this->operating_hours1_sensor_ != nullptr) + this->operating_hours1_sensor_->publish_state(get_u16(message, 10)); + if (this->operating_hours2_sensor_ != nullptr) + this->operating_hours2_sensor_->publish_state(get_u16(message, 18)); + if (this->heat_quantity_sensor_ != nullptr) { + this->heat_quantity_sensor_->publish_state(get_u16(message, 28) + get_u16(message, 30) * 1000); + } + if (this->time_sensor_ != nullptr) + this->time_sensor_->publish_state(get_u16(message, 22)); + if (this->version_sensor_ != nullptr) + this->version_sensor_->publish_state(get_u16(message, 32) * 0.01f); +} + void DeltaSolCSensor::dump_config() { ESP_LOGCONFIG(TAG, "Deltasol C:"); LOG_SENSOR(" ", "Temperature 1", this->temperature1_sensor_); diff --git a/esphome/components/vbus/sensor/vbus_sensor.h b/esphome/components/vbus/sensor/vbus_sensor.h index 6ba752b68c..d5535b2019 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.h +++ b/esphome/components/vbus/sensor/vbus_sensor.h @@ -37,6 +37,37 @@ class DeltaSolBSPlusSensor : public VBusListener, public Component { void handle_message(std::vector &message) override; }; +class DeltaSolBS2009Sensor : public VBusListener, public Component { + public: + void dump_config() override; + void set_temperature1_sensor(sensor::Sensor *sensor) { this->temperature1_sensor_ = sensor; } + void set_temperature2_sensor(sensor::Sensor *sensor) { this->temperature2_sensor_ = sensor; } + void set_temperature3_sensor(sensor::Sensor *sensor) { this->temperature3_sensor_ = sensor; } + void set_temperature4_sensor(sensor::Sensor *sensor) { this->temperature4_sensor_ = sensor; } + void set_pump_speed1_sensor(sensor::Sensor *sensor) { this->pump_speed1_sensor_ = sensor; } + void set_pump_speed2_sensor(sensor::Sensor *sensor) { this->pump_speed2_sensor_ = sensor; } + void set_operating_hours1_sensor(sensor::Sensor *sensor) { this->operating_hours1_sensor_ = sensor; } + void set_operating_hours2_sensor(sensor::Sensor *sensor) { this->operating_hours2_sensor_ = sensor; } + void set_heat_quantity_sensor(sensor::Sensor *sensor) { this->heat_quantity_sensor_ = sensor; } + void set_time_sensor(sensor::Sensor *sensor) { this->time_sensor_ = sensor; } + void set_version_sensor(sensor::Sensor *sensor) { this->version_sensor_ = sensor; } + + protected: + sensor::Sensor *temperature1_sensor_{nullptr}; + sensor::Sensor *temperature2_sensor_{nullptr}; + sensor::Sensor *temperature3_sensor_{nullptr}; + sensor::Sensor *temperature4_sensor_{nullptr}; + sensor::Sensor *pump_speed1_sensor_{nullptr}; + sensor::Sensor *pump_speed2_sensor_{nullptr}; + sensor::Sensor *operating_hours1_sensor_{nullptr}; + sensor::Sensor *operating_hours2_sensor_{nullptr}; + sensor::Sensor *heat_quantity_sensor_{nullptr}; + sensor::Sensor *time_sensor_{nullptr}; + sensor::Sensor *version_sensor_{nullptr}; + + void handle_message(std::vector &message) override; +}; + class DeltaSolCSensor : public VBusListener, public Component { public: void dump_config() override; From 407b5e199e40d4b66e60ad4ec6454f38b87112bd Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 15 Jun 2023 01:05:28 -0700 Subject: [PATCH 0082/2607] fix vbus sensor offsets (#4952) --- esphome/components/vbus/sensor/vbus_sensor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 5644f707d0..5b4f57f73d 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -207,9 +207,9 @@ void DeltaSolCSPlusSensor::handle_message(std::vector &message) { if (this->heat_quantity_sensor_ != nullptr) this->heat_quantity_sensor_->publish_state((get_u16(message, 30) << 16) + get_u16(message, 28)); if (this->time_sensor_ != nullptr) - this->time_sensor_->publish_state(get_u16(message, 12)); + this->time_sensor_->publish_state(get_u16(message, 22)); if (this->version_sensor_ != nullptr) - this->version_sensor_->publish_state(get_u16(message, 26) * 0.01f); + this->version_sensor_->publish_state(get_u16(message, 32) * 0.01f); if (this->flow_rate_sensor_ != nullptr) this->flow_rate_sensor_->publish_state(get_u16(message, 38)); } From abca47f36f9ed9f08dc4c67ac20b038c6b5e0110 Mon Sep 17 00:00:00 2001 From: guillempages Date: Fri, 16 Jun 2023 01:39:50 +0200 Subject: [PATCH 0083/2607] Add support for ESP32-S3-BOX-Lite displays (#4941) --- esphome/components/ili9xxx/display.py | 1 + .../components/ili9xxx/ili9xxx_display.cpp | 12 ++++++++ esphome/components/ili9xxx/ili9xxx_display.h | 5 ++++ esphome/components/ili9xxx/ili9xxx_init.h | 30 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 780c64ec70..98edadb6a5 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -44,6 +44,7 @@ MODELS = { "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), + "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), } COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 67d643fe31..ad70bd6e48 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -421,5 +421,17 @@ void ILI9XXXST7796::initialize() { } } +// 24_TFT rotated display +void ILI9XXXS3BoxLite::initialize() { + this->init_lcd_(INITCMD_S3BOXLITE); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 240; + } + this->invert_display_(true); +} + } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 8a8cd4bb44..dbdf023bc0 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -134,5 +134,10 @@ class ILI9XXXST7796 : public ILI9XXXDisplay { void initialize() override; }; +class ILI9XXXS3BoxLite : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 593b9a79ce..36cc30ec2e 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -169,6 +169,36 @@ static const uint8_t PROGMEM INITCMD_ST7796[] = { 0x00 // End of list }; +static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, 0x40, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x18, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + // clang-format on } // namespace ili9xxx } // namespace esphome From 6aa3092be075a4d0886fe0f8827751a41ce18931 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sat, 17 Jun 2023 10:32:07 +0200 Subject: [PATCH 0084/2607] Split display_buffer sub-components into own files (#4950) * Split display_buffer sub-components into own files Move the Image, Animation and Font classes to their own h/cpp pairs, instead of having everything into the display_buffer h/cpp files. * Fixed COLOR_ON duplicate definition --- esphome/components/display/animation.cpp | 69 ++++ esphome/components/display/animation.h | 37 +++ esphome/components/display/display_buffer.cpp | 303 +----------------- esphome/components/display/display_buffer.h | 136 +------- esphome/components/display/font.cpp | 105 ++++++ esphome/components/display/font.h | 66 ++++ esphome/components/display/image.cpp | 135 ++++++++ esphome/components/display/image.h | 75 +++++ tests/test2.yaml | 7 + 9 files changed, 502 insertions(+), 431 deletions(-) create mode 100644 esphome/components/display/animation.cpp create mode 100644 esphome/components/display/animation.h create mode 100644 esphome/components/display/font.cpp create mode 100644 esphome/components/display/font.h create mode 100644 esphome/components/display/image.cpp create mode 100644 esphome/components/display/image.h diff --git a/esphome/components/display/animation.cpp b/esphome/components/display/animation.cpp new file mode 100644 index 0000000000..d68084b68d --- /dev/null +++ b/esphome/components/display/animation.cpp @@ -0,0 +1,69 @@ +#include "animation.h" + +#include "esphome/core/hal.h" + +namespace esphome { +namespace display { + +Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) + : Image(data_start, width, height, type), + animation_data_start_(data_start), + current_frame_(0), + animation_frame_count_(animation_frame_count), + loop_start_frame_(0), + loop_end_frame_(animation_frame_count_), + loop_count_(0), + loop_current_iteration_(1) {} +void Animation::set_loop(uint32_t start_frame, uint32_t end_frame, int count) { + loop_start_frame_ = std::min(start_frame, animation_frame_count_); + loop_end_frame_ = std::min(end_frame, animation_frame_count_); + loop_count_ = count; + loop_current_iteration_ = 1; +} + +uint32_t Animation::get_animation_frame_count() const { return this->animation_frame_count_; } +int Animation::get_current_frame() const { return this->current_frame_; } +void Animation::next_frame() { + this->current_frame_++; + if (loop_count_ && this->current_frame_ == loop_end_frame_ && + (this->loop_current_iteration_ < loop_count_ || loop_count_ < 0)) { + this->current_frame_ = loop_start_frame_; + this->loop_current_iteration_++; + } + if (this->current_frame_ >= animation_frame_count_) { + this->loop_current_iteration_ = 1; + this->current_frame_ = 0; + } + + this->update_data_start_(); +} +void Animation::prev_frame() { + this->current_frame_--; + if (this->current_frame_ < 0) { + this->current_frame_ = this->animation_frame_count_ - 1; + } + + this->update_data_start_(); +} + +void Animation::set_frame(int frame) { + unsigned abs_frame = abs(frame); + + if (abs_frame < this->animation_frame_count_) { + if (frame >= 0) { + this->current_frame_ = frame; + } else { + this->current_frame_ = this->animation_frame_count_ - abs_frame; + } + } + + this->update_data_start_(); +} + +void Animation::update_data_start_() { + const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; + this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; +} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/animation.h b/esphome/components/display/animation.h new file mode 100644 index 0000000000..38e632ccf0 --- /dev/null +++ b/esphome/components/display/animation.h @@ -0,0 +1,37 @@ +#pragma once +#include "image.h" + +namespace esphome { +namespace display { + +class Animation : public Image { + public: + Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); + + uint32_t get_animation_frame_count() const; + int get_current_frame() const; + void next_frame(); + void prev_frame(); + + /** Selects a specific frame within the animation. + * + * @param frame If possitive, advance to the frame. If negative, recede to that frame from the end frame. + */ + void set_frame(int frame); + + void set_loop(uint32_t start_frame, uint32_t end_frame, int count); + + protected: + void update_data_start_(); + + const uint8_t *animation_data_start_; + int current_frame_; + uint32_t animation_frame_count_; + uint32_t loop_start_frame_; + uint32_t loop_end_frame_; + int loop_count_; + int loop_current_iteration_; +}; + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index c8dc7b62e2..8092b9f12f 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -7,6 +7,10 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "animation.h" +#include "image.h" +#include "font.h" + namespace esphome { namespace display { @@ -15,25 +19,6 @@ static const char *const TAG = "display"; const Color COLOR_OFF(0, 0, 0, 255); const Color COLOR_ON(255, 255, 255, 255); -static int image_type_to_bpp(ImageType type) { - switch (type) { - case IMAGE_TYPE_BINARY: - return 1; - case IMAGE_TYPE_GRAYSCALE: - return 8; - case IMAGE_TYPE_RGB565: - return 16; - case IMAGE_TYPE_RGB24: - return 24; - case IMAGE_TYPE_RGBA: - return 32; - default: - return 0; - } -} - -static int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } - void Rect::expand(int16_t horizontal, int16_t vertical) { if (this->is_set() && (this->w >= (-2 * horizontal)) && (this->h >= (-2 * vertical))) { this->x = this->x - horizontal; @@ -505,286 +490,6 @@ Rect DisplayBuffer::get_clipping() { return this->clipping_rectangle_.back(); } } -bool Glyph::get_pixel(int x, int y) const { - const int x_data = x - this->glyph_data_->offset_x; - const int y_data = y - this->glyph_data_->offset_y; - if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) - return false; - const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; - const uint32_t pos = x_data + y_data * width_8; - return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); -} -const char *Glyph::get_char() const { return this->glyph_data_->a_char; } -bool Glyph::compare_to(const char *str) const { - // 1 -> this->char_ - // 2 -> str - for (uint32_t i = 0;; i++) { - if (this->glyph_data_->a_char[i] == '\0') - return true; - if (str[i] == '\0') - return false; - if (this->glyph_data_->a_char[i] > str[i]) - return false; - if (this->glyph_data_->a_char[i] < str[i]) - return true; - } - // this should not happen - return false; -} -int Glyph::match_length(const char *str) const { - for (uint32_t i = 0;; i++) { - if (this->glyph_data_->a_char[i] == '\0') - return i; - if (str[i] != this->glyph_data_->a_char[i]) - return 0; - } - // this should not happen - return 0; -} -void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { - *x1 = this->glyph_data_->offset_x; - *y1 = this->glyph_data_->offset_y; - *width = this->glyph_data_->width; - *height = this->glyph_data_->height; -} -int Font::match_next_glyph(const char *str, int *match_length) { - int lo = 0; - int hi = this->glyphs_.size() - 1; - while (lo != hi) { - int mid = (lo + hi + 1) / 2; - if (this->glyphs_[mid].compare_to(str)) { - lo = mid; - } else { - hi = mid - 1; - } - } - *match_length = this->glyphs_[lo].match_length(str); - if (*match_length <= 0) - return -1; - return lo; -} -void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) { - *baseline = this->baseline_; - *height = this->height_; - int i = 0; - int min_x = 0; - bool has_char = false; - int x = 0; - while (str[i] != '\0') { - int match_length; - int glyph_n = this->match_next_glyph(str + i, &match_length); - if (glyph_n < 0) { - // Unknown char, skip - if (!this->get_glyphs().empty()) - x += this->get_glyphs()[0].glyph_data_->width; - i++; - continue; - } - - const Glyph &glyph = this->glyphs_[glyph_n]; - if (!has_char) { - min_x = glyph.glyph_data_->offset_x; - } else { - min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); - } - x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; - - i += match_length; - has_char = true; - } - *x_offset = min_x; - *width = x - min_x; -} -Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { - glyphs_.reserve(data_nr); - for (int i = 0; i < data_nr; ++i) - glyphs_.emplace_back(&data[i]); -} - -void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { - switch (type_) { - case IMAGE_TYPE_BINARY: { - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - if (this->get_binary_pixel_(img_x, img_y)) { - display->draw_pixel_at(x + img_x, y + img_y, color_on); - } else if (!this->transparent_) { - display->draw_pixel_at(x + img_x, y + img_y, color_off); - } - } - } - break; - } - case IMAGE_TYPE_GRAYSCALE: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_grayscale_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB565: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgb565_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGB24: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgb24_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - case IMAGE_TYPE_RGBA: - for (int img_x = 0; img_x < width_; img_x++) { - for (int img_y = 0; img_y < height_; img_y++) { - auto color = this->get_rgba_pixel_(img_x, img_y); - if (color.w >= 0x80) { - display->draw_pixel_at(x + img_x, y + img_y, color); - } - } - } - break; - } -} -Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { - if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) - return color_off; - switch (this->type_) { - case IMAGE_TYPE_BINARY: - return this->get_binary_pixel_(x, y) ? color_on : color_off; - case IMAGE_TYPE_GRAYSCALE: - return this->get_grayscale_pixel_(x, y); - case IMAGE_TYPE_RGB565: - return this->get_rgb565_pixel_(x, y); - case IMAGE_TYPE_RGB24: - return this->get_rgb24_pixel_(x, y); - case IMAGE_TYPE_RGBA: - return this->get_rgba_pixel_(x, y); - default: - return color_off; - } -} -bool Image::get_binary_pixel_(int x, int y) const { - const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; - const uint32_t pos = x + y * width_8; - return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); -} -Color Image::get_rgba_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 4; - return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); -} -Color Image::get_rgb24_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 3; - Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), - progmem_read_byte(this->data_start_ + pos + 2)); - if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) { - // (0, 0, 1) has been defined as transparent color for non-alpha images. - // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if) - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Image::get_rgb565_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 2; - uint16_t rgb565 = - progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); - auto r = (rgb565 & 0xF800) >> 11; - auto g = (rgb565 & 0x07E0) >> 5; - auto b = rgb565 & 0x001F; - Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); - if (rgb565 == 0x0020 && transparent_) { - // darkest green has been defined as transparent color for transparent RGB565 images. - color.w = 0; - } else { - color.w = 0xFF; - } - return color; -} -Color Image::get_grayscale_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_); - const uint8_t gray = progmem_read_byte(this->data_start_ + pos); - uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; - return Color(gray, gray, gray, alpha); -} -int Image::get_width() const { return this->width_; } -int Image::get_height() const { return this->height_; } -ImageType Image::get_type() const { return this->type_; } -Image::Image(const uint8_t *data_start, int width, int height, ImageType type) - : width_(width), height_(height), type_(type), data_start_(data_start) {} - -Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) - : Image(data_start, width, height, type), - animation_data_start_(data_start), - current_frame_(0), - animation_frame_count_(animation_frame_count), - loop_start_frame_(0), - loop_end_frame_(animation_frame_count_), - loop_count_(0), - loop_current_iteration_(1) {} -void Animation::set_loop(uint32_t start_frame, uint32_t end_frame, int count) { - loop_start_frame_ = std::min(start_frame, animation_frame_count_); - loop_end_frame_ = std::min(end_frame, animation_frame_count_); - loop_count_ = count; - loop_current_iteration_ = 1; -} - -uint32_t Animation::get_animation_frame_count() const { return this->animation_frame_count_; } -int Animation::get_current_frame() const { return this->current_frame_; } -void Animation::next_frame() { - this->current_frame_++; - if (loop_count_ && this->current_frame_ == loop_end_frame_ && - (this->loop_current_iteration_ < loop_count_ || loop_count_ < 0)) { - this->current_frame_ = loop_start_frame_; - this->loop_current_iteration_++; - } - if (this->current_frame_ >= animation_frame_count_) { - this->loop_current_iteration_ = 1; - this->current_frame_ = 0; - } - - this->update_data_start_(); -} -void Animation::prev_frame() { - this->current_frame_--; - if (this->current_frame_ < 0) { - this->current_frame_ = this->animation_frame_count_ - 1; - } - - this->update_data_start_(); -} - -void Animation::set_frame(int frame) { - unsigned abs_frame = abs(frame); - - if (abs_frame < this->animation_frame_count_) { - if (frame >= 0) { - this->current_frame_ = frame; - } else { - this->current_frame_ = this->animation_frame_count_ - abs_frame; - } - } - - this->update_data_start_(); -} - -void Animation::update_data_start_() { - const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; - this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; -} DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} void DisplayPage::show() { this->parent_->show_page(this); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 0c31ac24d9..b66ec529f7 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -16,6 +16,10 @@ #include "esphome/components/qr_code/qr_code.h" #endif +#include "animation.h" +#include "font.h" +#include "image.h" + namespace esphome { namespace display { @@ -70,19 +74,6 @@ enum class TextAlign { BOTTOM_RIGHT = BOTTOM | RIGHT, }; -/// Turn the pixel OFF. -extern const Color COLOR_OFF; -/// Turn the pixel ON. -extern const Color COLOR_ON; - -enum ImageType { - IMAGE_TYPE_BINARY = 0, - IMAGE_TYPE_GRAYSCALE = 1, - IMAGE_TYPE_RGB24 = 2, - IMAGE_TYPE_RGB565 = 3, - IMAGE_TYPE_RGBA = 4, -}; - enum DisplayType { DISPLAY_TYPE_BINARY = 1, DISPLAY_TYPE_GRAYSCALE = 2, @@ -123,8 +114,6 @@ class Rect { void info(const std::string &prefix = "rect info:"); }; -class BaseImage; -class Font; class DisplayBuffer; class DisplayPage; class DisplayOnPageChangeTrigger; @@ -475,123 +464,6 @@ class DisplayPage { DisplayPage *next_{nullptr}; }; -struct GlyphData { - const char *a_char; - const uint8_t *data; - int offset_x; - int offset_y; - int width; - int height; -}; - -class Glyph { - public: - Glyph(const GlyphData *data) : glyph_data_(data) {} - - bool get_pixel(int x, int y) const; - - const char *get_char() const; - - bool compare_to(const char *str) const; - - int match_length(const char *str) const; - - void scan_area(int *x1, int *y1, int *width, int *height) const; - - protected: - friend Font; - friend DisplayBuffer; - - const GlyphData *glyph_data_; -}; - -class Font { - public: - /** Construct the font with the given glyphs. - * - * @param glyphs A vector of glyphs, must be sorted lexicographically. - * @param baseline The y-offset from the top of the text to the baseline. - * @param bottom The y-offset from the top of the text to the bottom (i.e. height). - */ - Font(const GlyphData *data, int data_nr, int baseline, int height); - - int match_next_glyph(const char *str, int *match_length); - - void measure(const char *str, int *width, int *x_offset, int *baseline, int *height); - inline int get_baseline() { return this->baseline_; } - inline int get_height() { return this->height_; } - - const std::vector> &get_glyphs() const { return glyphs_; } - - protected: - std::vector> glyphs_; - int baseline_; - int height_; -}; - -class BaseImage { - public: - virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; -}; - -class Image : public BaseImage { - public: - Image(const uint8_t *data_start, int width, int height, ImageType type); - Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; - int get_width() const override; - int get_height() const override; - ImageType get_type() const; - - void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; - - void set_transparency(bool transparent) { transparent_ = transparent; } - bool has_transparency() const { return transparent_; } - - protected: - bool get_binary_pixel_(int x, int y) const; - Color get_rgb24_pixel_(int x, int y) const; - Color get_rgba_pixel_(int x, int y) const; - Color get_rgb565_pixel_(int x, int y) const; - Color get_grayscale_pixel_(int x, int y) const; - - int width_; - int height_; - ImageType type_; - const uint8_t *data_start_; - bool transparent_; -}; - -class Animation : public Image { - public: - Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); - - uint32_t get_animation_frame_count() const; - int get_current_frame() const; - void next_frame(); - void prev_frame(); - - /** Selects a specific frame within the animation. - * - * @param frame If possitive, advance to the frame. If negative, recede to that frame from the end frame. - */ - void set_frame(int frame); - - void set_loop(uint32_t start_frame, uint32_t end_frame, int count); - - protected: - void update_data_start_(); - - const uint8_t *animation_data_start_; - int current_frame_; - uint32_t animation_frame_count_; - uint32_t loop_start_frame_; - uint32_t loop_end_frame_; - int loop_count_; - int loop_current_iteration_; -}; - template class DisplayPageShowAction : public Action { public: TEMPLATABLE_VALUE(DisplayPage *, page) diff --git a/esphome/components/display/font.cpp b/esphome/components/display/font.cpp new file mode 100644 index 0000000000..1833ef5023 --- /dev/null +++ b/esphome/components/display/font.cpp @@ -0,0 +1,105 @@ +#include "font.h" + +#include "esphome/core/hal.h" + +namespace esphome { +namespace display { + +bool Glyph::get_pixel(int x, int y) const { + const int x_data = x - this->glyph_data_->offset_x; + const int y_data = y - this->glyph_data_->offset_y; + if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) + return false; + const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; + const uint32_t pos = x_data + y_data * width_8; + return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); +} +const char *Glyph::get_char() const { return this->glyph_data_->a_char; } +bool Glyph::compare_to(const char *str) const { + // 1 -> this->char_ + // 2 -> str + for (uint32_t i = 0;; i++) { + if (this->glyph_data_->a_char[i] == '\0') + return true; + if (str[i] == '\0') + return false; + if (this->glyph_data_->a_char[i] > str[i]) + return false; + if (this->glyph_data_->a_char[i] < str[i]) + return true; + } + // this should not happen + return false; +} +int Glyph::match_length(const char *str) const { + for (uint32_t i = 0;; i++) { + if (this->glyph_data_->a_char[i] == '\0') + return i; + if (str[i] != this->glyph_data_->a_char[i]) + return 0; + } + // this should not happen + return 0; +} +void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { + *x1 = this->glyph_data_->offset_x; + *y1 = this->glyph_data_->offset_y; + *width = this->glyph_data_->width; + *height = this->glyph_data_->height; +} +int Font::match_next_glyph(const char *str, int *match_length) { + int lo = 0; + int hi = this->glyphs_.size() - 1; + while (lo != hi) { + int mid = (lo + hi + 1) / 2; + if (this->glyphs_[mid].compare_to(str)) { + lo = mid; + } else { + hi = mid - 1; + } + } + *match_length = this->glyphs_[lo].match_length(str); + if (*match_length <= 0) + return -1; + return lo; +} +void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) { + *baseline = this->baseline_; + *height = this->height_; + int i = 0; + int min_x = 0; + bool has_char = false; + int x = 0; + while (str[i] != '\0') { + int match_length; + int glyph_n = this->match_next_glyph(str + i, &match_length); + if (glyph_n < 0) { + // Unknown char, skip + if (!this->get_glyphs().empty()) + x += this->get_glyphs()[0].glyph_data_->width; + i++; + continue; + } + + const Glyph &glyph = this->glyphs_[glyph_n]; + if (!has_char) { + min_x = glyph.glyph_data_->offset_x; + } else { + min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); + } + x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; + + i += match_length; + has_char = true; + } + *x_offset = min_x; + *width = x - min_x; +} +Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { + glyphs_.reserve(data_nr); + for (int i = 0; i < data_nr; ++i) + glyphs_.emplace_back(&data[i]); +} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/font.h b/esphome/components/display/font.h new file mode 100644 index 0000000000..08b457116e --- /dev/null +++ b/esphome/components/display/font.h @@ -0,0 +1,66 @@ +#pragma once + +#include "esphome/core/datatypes.h" + +namespace esphome { +namespace display { + +class DisplayBuffer; +class Font; + +struct GlyphData { + const char *a_char; + const uint8_t *data; + int offset_x; + int offset_y; + int width; + int height; +}; + +class Glyph { + public: + Glyph(const GlyphData *data) : glyph_data_(data) {} + + bool get_pixel(int x, int y) const; + + const char *get_char() const; + + bool compare_to(const char *str) const; + + int match_length(const char *str) const; + + void scan_area(int *x1, int *y1, int *width, int *height) const; + + protected: + friend Font; + friend DisplayBuffer; + + const GlyphData *glyph_data_; +}; + +class Font { + public: + /** Construct the font with the given glyphs. + * + * @param glyphs A vector of glyphs, must be sorted lexicographically. + * @param baseline The y-offset from the top of the text to the baseline. + * @param bottom The y-offset from the top of the text to the bottom (i.e. height). + */ + Font(const GlyphData *data, int data_nr, int baseline, int height); + + int match_next_glyph(const char *str, int *match_length); + + void measure(const char *str, int *width, int *x_offset, int *baseline, int *height); + inline int get_baseline() { return this->baseline_; } + inline int get_height() { return this->height_; } + + const std::vector> &get_glyphs() const { return glyphs_; } + + protected: + std::vector> glyphs_; + int baseline_; + int height_; +}; + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/image.cpp b/esphome/components/display/image.cpp new file mode 100644 index 0000000000..b3cab3ff7f --- /dev/null +++ b/esphome/components/display/image.cpp @@ -0,0 +1,135 @@ +#include "image.h" + +#include "esphome/core/hal.h" +#include "display_buffer.h" + +namespace esphome { +namespace display { + +void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { + switch (type_) { + case IMAGE_TYPE_BINARY: { + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + if (this->get_binary_pixel_(img_x, img_y)) { + display->draw_pixel_at(x + img_x, y + img_y, color_on); + } else if (!this->transparent_) { + display->draw_pixel_at(x + img_x, y + img_y, color_off); + } + } + } + break; + } + case IMAGE_TYPE_GRAYSCALE: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_grayscale_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB565: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb565_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGB24: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgb24_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + case IMAGE_TYPE_RGBA: + for (int img_x = 0; img_x < width_; img_x++) { + for (int img_y = 0; img_y < height_; img_y++) { + auto color = this->get_rgba_pixel_(img_x, img_y); + if (color.w >= 0x80) { + display->draw_pixel_at(x + img_x, y + img_y, color); + } + } + } + break; + } +} +Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { + if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) + return color_off; + switch (this->type_) { + case IMAGE_TYPE_BINARY: + return this->get_binary_pixel_(x, y) ? color_on : color_off; + case IMAGE_TYPE_GRAYSCALE: + return this->get_grayscale_pixel_(x, y); + case IMAGE_TYPE_RGB565: + return this->get_rgb565_pixel_(x, y); + case IMAGE_TYPE_RGB24: + return this->get_rgb24_pixel_(x, y); + case IMAGE_TYPE_RGBA: + return this->get_rgba_pixel_(x, y); + default: + return color_off; + } +} +bool Image::get_binary_pixel_(int x, int y) const { + const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; + const uint32_t pos = x + y * width_8; + return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); +} +Color Image::get_rgba_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 4; + return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), + progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3)); +} +Color Image::get_rgb24_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 3; + Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1), + progmem_read_byte(this->data_start_ + pos + 2)); + if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) { + // (0, 0, 1) has been defined as transparent color for non-alpha images. + // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if) + color.w = 0; + } else { + color.w = 0xFF; + } + return color; +} +Color Image::get_rgb565_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_) * 2; + uint16_t rgb565 = + progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); + auto r = (rgb565 & 0xF800) >> 11; + auto g = (rgb565 & 0x07E0) >> 5; + auto b = rgb565 & 0x001F; + Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); + if (rgb565 == 0x0020 && transparent_) { + // darkest green has been defined as transparent color for transparent RGB565 images. + color.w = 0; + } else { + color.w = 0xFF; + } + return color; +} +Color Image::get_grayscale_pixel_(int x, int y) const { + const uint32_t pos = (x + y * this->width_); + const uint8_t gray = progmem_read_byte(this->data_start_ + pos); + uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF; + return Color(gray, gray, gray, alpha); +} +int Image::get_width() const { return this->width_; } +int Image::get_height() const { return this->height_; } +ImageType Image::get_type() const { return this->type_; } +Image::Image(const uint8_t *data_start, int width, int height, ImageType type) + : width_(width), height_(height), type_(type), data_start_(data_start) {} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/image.h b/esphome/components/display/image.h new file mode 100644 index 0000000000..ac2d5a3421 --- /dev/null +++ b/esphome/components/display/image.h @@ -0,0 +1,75 @@ +#pragma once +#include "esphome/core/color.h" + +namespace esphome { +namespace display { + +enum ImageType { + IMAGE_TYPE_BINARY = 0, + IMAGE_TYPE_GRAYSCALE = 1, + IMAGE_TYPE_RGB24 = 2, + IMAGE_TYPE_RGB565 = 3, + IMAGE_TYPE_RGBA = 4, +}; + +inline int image_type_to_bpp(ImageType type) { + switch (type) { + case IMAGE_TYPE_BINARY: + return 1; + case IMAGE_TYPE_GRAYSCALE: + return 8; + case IMAGE_TYPE_RGB565: + return 16; + case IMAGE_TYPE_RGB24: + return 24; + case IMAGE_TYPE_RGBA: + return 32; + } + return 0; +} + +inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } + +/// Turn the pixel OFF. +extern const Color COLOR_OFF; +/// Turn the pixel ON. +extern const Color COLOR_ON; + +class DisplayBuffer; + +class BaseImage { + public: + virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; +}; + +class Image : public BaseImage { + public: + Image(const uint8_t *data_start, int width, int height, ImageType type); + Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; + int get_width() const override; + int get_height() const override; + ImageType get_type() const; + + void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; + + void set_transparency(bool transparent) { transparent_ = transparent; } + bool has_transparency() const { return transparent_; } + + protected: + bool get_binary_pixel_(int x, int y) const; + Color get_rgb24_pixel_(int x, int y) const; + Color get_rgba_pixel_(int x, int y) const; + Color get_rgb565_pixel_(int x, int y) const; + Color get_grayscale_pixel_(int x, int y) const; + + int width_; + int height_; + ImageType type_; + const uint8_t *data_start_; + bool transparent_; +}; + +} // namespace display +} // namespace esphome diff --git a/tests/test2.yaml b/tests/test2.yaml index 2873d0e8e0..fa4b97c7c1 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -695,6 +695,13 @@ image: file: mdi:alert-outline type: BINARY +graph: + - id: my_graph + sensor: ha_hello_world_temperature + duration: 1h + width: 100 + height: 100 + cap1188: id: cap1188_component address: 0x29 From a4ef26749b391daed1543950d4aeab78b45654e1 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sat, 17 Jun 2023 10:38:44 +0200 Subject: [PATCH 0085/2607] Add support for ESP32-S3-BOX displays (#4942) The ESP32-S3-BOX display has an ILI9xxx driver Add the needed configuration so that it works. --- esphome/components/ili9xxx/display.py | 1 + .../components/ili9xxx/ili9xxx_display.cpp | 11 +++++++ esphome/components/ili9xxx/ili9xxx_display.h | 5 ++++ esphome/components/ili9xxx/ili9xxx_init.h | 30 +++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 98edadb6a5..29603eb30f 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -44,6 +44,7 @@ MODELS = { "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), + "S3BOX": ili9XXX_ns.class_("ILI9XXXS3Box", ili9XXXSPI), "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), } diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index ad70bd6e48..6fc6da3cdb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -421,6 +421,17 @@ void ILI9XXXST7796::initialize() { } } +// 24_TFT rotated display +void ILI9XXXS3Box::initialize() { + this->init_lcd_(INITCMD_S3BOX); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 240; + } +} + // 24_TFT rotated display void ILI9XXXS3BoxLite::initialize() { this->init_lcd_(INITCMD_S3BOXLITE); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index dbdf023bc0..dc7bfdc6eb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -134,6 +134,11 @@ class ILI9XXXST7796 : public ILI9XXXDisplay { void initialize() override; }; +class ILI9XXXS3Box : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + class ILI9XXXS3BoxLite : public ILI9XXXDisplay { protected: void initialize() override; diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 36cc30ec2e..a17e6b127c 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -169,6 +169,36 @@ static const uint8_t PROGMEM INITCMD_ST7796[] = { 0x00 // End of list }; +static const uint8_t PROGMEM INITCMD_S3BOX[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, 0xC8, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x18, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { 0xEF, 3, 0x03, 0x80, 0x02, 0xCF, 3, 0x00, 0xC1, 0x30, From b558a1c9ddb5d9d1fba2944a0836f3ccb6365d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Sun, 18 Jun 2023 21:24:23 +0200 Subject: [PATCH 0086/2607] display: allow to align image with `ImageAlign` (#4933) --- esphome/components/display/display_buffer.cpp | 31 ++++++++++ esphome/components/display/display_buffer.h | 61 ++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 8092b9f12f..672c6a22b0 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -311,6 +311,37 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al } void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) { + this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off); +} + +void DisplayBuffer::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) { + auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT))); + auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT))); + + switch (x_align) { + case ImageAlign::RIGHT: + x -= image->get_width(); + break; + case ImageAlign::CENTER_HORIZONTAL: + x -= image->get_width() / 2; + break; + case ImageAlign::LEFT: + default: + break; + } + + switch (y_align) { + case ImageAlign::BOTTOM: + y -= image->get_height(); + break; + case ImageAlign::CENTER_VERTICAL: + y -= image->get_height() / 2; + break; + case ImageAlign::TOP: + default: + break; + } + image->draw(x, y, this, color_on, color_off); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index b66ec529f7..652039517f 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -74,6 +74,54 @@ enum class TextAlign { BOTTOM_RIGHT = BOTTOM | RIGHT, }; +/** ImageAlign is used to tell the display class how to position a image. By default + * the coordinates you enter for the image() functions take the upper left corner of the image + * as the "anchor" point. You can customize this behavior to, for example, make the coordinates + * refer to the *center* of the image. + * + * All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis + * these options are allowed: + * + * - LEFT (x-coordinate of anchor point is on left) + * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image) + * - RIGHT (x-coordinate of anchor point is on right) + * + * For the Y-Axis alignment these options are allowed: + * + * - TOP (y-coordinate of anchor is on the top of the image) + * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image) + * - BOTTOM (y-coordinate of anchor is on the bottom of the image) + * + * These options are then combined to create combined TextAlignment options like: + * - TOP_LEFT (default) + * - CENTER (anchor point is in the middle of the image bounds) + * - ... + */ +enum class ImageAlign { + TOP = 0x00, + CENTER_VERTICAL = 0x01, + BOTTOM = 0x02, + + LEFT = 0x00, + CENTER_HORIZONTAL = 0x04, + RIGHT = 0x08, + + TOP_LEFT = TOP | LEFT, + TOP_CENTER = TOP | CENTER_HORIZONTAL, + TOP_RIGHT = TOP | RIGHT, + + CENTER_LEFT = CENTER_VERTICAL | LEFT, + CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, + CENTER_RIGHT = CENTER_VERTICAL | RIGHT, + + BOTTOM_LEFT = BOTTOM | LEFT, + BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, + BOTTOM_RIGHT = BOTTOM | RIGHT, + + HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT, + VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM +}; + enum DisplayType { DISPLAY_TYPE_BINARY = 1, DISPLAY_TYPE_GRAYSCALE = 2, @@ -300,12 +348,23 @@ class DisplayBuffer { * * @param x The x coordinate of the upper left corner. * @param y The y coordinate of the upper left corner. - * @param image The image to draw + * @param image The image to draw. * @param color_on The color to replace in binary images for the on bits. * @param color_off The color to replace in binary images for the off bits. */ void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + /** Draw the `image` at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param image The image to draw. + * @param align The alignment of the image. + * @param color_on The color to replace in binary images for the on bits. + * @param color_off The color to replace in binary images for the off bits. + */ + void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + #ifdef USE_GRAPH /** Draw the `graph` with the top-left corner at [x,y] to the screen. * From 29f44306589978c084b3f276dd3db8b9a5eaa7b5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Jun 2023 07:24:44 +1200 Subject: [PATCH 0087/2607] Use HW SPI for rp2040 (#4955) --- esphome/components/spi/spi.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 141bfb9448..c9bb075fb5 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -87,6 +87,30 @@ void SPIComponent::setup() { return; } #endif // USE_ESP32 +#ifdef USE_RP2040 + static uint8_t spi_bus_num = 0; + if (spi_bus_num >= 2) { + use_hw_spi = false; + } + if (use_hw_spi) { + SPIClassRP2040 *spi; + if (spi_bus_num == 0) { + spi = &SPI; + } else { + spi = &SPI1; + } + spi_bus_num++; + + if (miso_pin != -1) + spi->setRX(miso_pin); + if (mosi_pin != -1) + spi->setTX(mosi_pin); + spi->setSCK(clk_pin); + this->hw_spi_ = spi; + this->hw_spi_->begin(); + return; + } +#endif // USE_RP2040 #endif // USE_SPI_ARDUINO_BACKEND if (this->miso_ != nullptr) { From 88c13768e352608dc3bab8b9079f6acb5979512d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Jun 2023 07:35:03 +1200 Subject: [PATCH 0088/2607] Bump version to 2023.6.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8820c39d17..d4cfd30c32 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b1" +__version__ = "2023.6.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 5a8e93ed0a7cfe1af626ba5701f0373ad34dbf34 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Mon, 19 Jun 2023 00:24:52 +0200 Subject: [PATCH 0089/2607] Upgraded Haier climate component implementation (#4521) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Pavlo Dudnytskyi Co-authored-by: esphomebot --- CODEOWNERS | 2 +- esphome/components/haier/__init__.py | 1 - esphome/components/haier/automation.h | 130 +++ esphome/components/haier/climate.py | 359 +++++++- esphome/components/haier/haier.cpp | 302 ------ esphome/components/haier/haier.h | 37 - esphome/components/haier/haier_base.cpp | 311 +++++++ esphome/components/haier/haier_base.h | 142 +++ esphome/components/haier/hon_climate.cpp | 857 ++++++++++++++++++ esphome/components/haier/hon_climate.h | 95 ++ esphome/components/haier/hon_packet.h | 228 +++++ esphome/components/haier/logger_handler.cpp | 33 + esphome/components/haier/logger_handler.h | 14 + .../components/haier/smartair2_climate.cpp | 457 ++++++++++ esphome/components/haier/smartair2_climate.h | 31 + esphome/components/haier/smartair2_packet.h | 97 ++ platformio.ini | 1 + tests/test3.yaml | 26 +- 18 files changed, 2758 insertions(+), 365 deletions(-) create mode 100644 esphome/components/haier/automation.h delete mode 100644 esphome/components/haier/haier.cpp delete mode 100644 esphome/components/haier/haier.h create mode 100644 esphome/components/haier/haier_base.cpp create mode 100644 esphome/components/haier/haier_base.h create mode 100644 esphome/components/haier/hon_climate.cpp create mode 100644 esphome/components/haier/hon_climate.h create mode 100644 esphome/components/haier/hon_packet.h create mode 100644 esphome/components/haier/logger_handler.cpp create mode 100644 esphome/components/haier/logger_handler.h create mode 100644 esphome/components/haier/smartair2_climate.cpp create mode 100644 esphome/components/haier/smartair2_climate.h create mode 100644 esphome/components/haier/smartair2_packet.h diff --git a/CODEOWNERS b/CODEOWNERS index c6cbf3c2ab..595e4a5684 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -102,7 +102,7 @@ esphome/components/gpio/* @esphome/core esphome/components/gps/* @coogle esphome/components/graph/* @synco esphome/components/growatt_solar/* @leeuwte -esphome/components/haier/* @Yarikx +esphome/components/haier/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal esphome/components/hbridge/fan/* @WeekendWarrior esphome/components/hbridge/light/* @DotNetDann diff --git a/esphome/components/haier/__init__.py b/esphome/components/haier/__init__.py index b9ea055a41..e69de29bb2 100644 --- a/esphome/components/haier/__init__.py +++ b/esphome/components/haier/__init__.py @@ -1 +0,0 @@ -CODEOWNERS = ["@Yarikx"] diff --git a/esphome/components/haier/automation.h b/esphome/components/haier/automation.h new file mode 100644 index 0000000000..84e4554db8 --- /dev/null +++ b/esphome/components/haier/automation.h @@ -0,0 +1,130 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "haier_base.h" +#include "hon_climate.h" + +namespace esphome { +namespace haier { + +template class DisplayOnAction : public Action { + public: + DisplayOnAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_display_state(true); } + + protected: + HaierClimateBase *parent_; +}; + +template class DisplayOffAction : public Action { + public: + DisplayOffAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_display_state(false); } + + protected: + HaierClimateBase *parent_; +}; + +template class BeeperOnAction : public Action { + public: + BeeperOnAction(HonClimate *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_beeper_state(true); } + + protected: + HonClimate *parent_; +}; + +template class BeeperOffAction : public Action { + public: + BeeperOffAction(HonClimate *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_beeper_state(false); } + + protected: + HonClimate *parent_; +}; + +template class VerticalAirflowAction : public Action { + public: + VerticalAirflowAction(HonClimate *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(AirflowVerticalDirection, direction) + void play(Ts... x) { this->parent_->set_vertical_airflow(this->direction_.value(x...)); } + + protected: + HonClimate *parent_; +}; + +template class HorizontalAirflowAction : public Action { + public: + HorizontalAirflowAction(HonClimate *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(AirflowHorizontalDirection, direction) + void play(Ts... x) { this->parent_->set_horizontal_airflow(this->direction_.value(x...)); } + + protected: + HonClimate *parent_; +}; + +template class HealthOnAction : public Action { + public: + HealthOnAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_health_mode(true); } + + protected: + HaierClimateBase *parent_; +}; + +template class HealthOffAction : public Action { + public: + HealthOffAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->set_health_mode(false); } + + protected: + HaierClimateBase *parent_; +}; + +template class StartSelfCleaningAction : public Action { + public: + StartSelfCleaningAction(HonClimate *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->start_self_cleaning(); } + + protected: + HonClimate *parent_; +}; + +template class StartSteriCleaningAction : public Action { + public: + StartSteriCleaningAction(HonClimate *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->start_steri_cleaning(); } + + protected: + HonClimate *parent_; +}; + +template class PowerOnAction : public Action { + public: + PowerOnAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->send_power_on_command(); } + + protected: + HaierClimateBase *parent_; +}; + +template class PowerOffAction : public Action { + public: + PowerOffAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->send_power_off_command(); } + + protected: + HaierClimateBase *parent_; +}; + +template class PowerToggleAction : public Action { + public: + PowerToggleAction(HaierClimateBase *parent) : parent_(parent) {} + void play(Ts... x) { this->parent_->toggle_power(); } + + protected: + HaierClimateBase *parent_; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index cee83232a1..12b76084ba 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -1,43 +1,364 @@ -from esphome.components import climate +import logging import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import uart -from esphome.components.climate import ClimateSwingMode -from esphome.const import CONF_ID, CONF_SUPPORTED_SWING_MODES +import esphome.final_validate as fv +from esphome.components import uart, sensor, climate, logger +from esphome import automation +from esphome.const import ( + CONF_BEEPER, + CONF_ID, + CONF_LEVEL, + CONF_LOGGER, + CONF_LOGS, + CONF_MAX_TEMPERATURE, + CONF_MIN_TEMPERATURE, + CONF_PROTOCOL, + CONF_SUPPORTED_MODES, + CONF_SUPPORTED_SWING_MODES, + CONF_VISUAL, + CONF_WIFI, + DEVICE_CLASS_TEMPERATURE, + ICON_THERMOMETER, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) +from esphome.components.climate import ( + ClimateSwingMode, + ClimateMode, +) -DEPENDENCIES = ["uart"] +_LOGGER = logging.getLogger(__name__) + +PROTOCOL_MIN_TEMPERATURE = 16.0 +PROTOCOL_MAX_TEMPERATURE = 30.0 +PROTOCOL_TEMPERATURE_STEP = 1.0 + +CODEOWNERS = ["@paveldn"] +AUTO_LOAD = ["sensor"] +DEPENDENCIES = ["climate", "uart"] +CONF_WIFI_SIGNAL = "wifi_signal" +CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" +CONF_VERTICAL_AIRFLOW = "vertical_airflow" +CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow" + + +PROTOCOL_HON = "HON" +PROTOCOL_SMARTAIR2 = "SMARTAIR2" +PROTOCOLS_SUPPORTED = [PROTOCOL_HON, PROTOCOL_SMARTAIR2] haier_ns = cg.esphome_ns.namespace("haier") -HaierClimate = haier_ns.class_( - "HaierClimate", climate.Climate, cg.PollingComponent, uart.UARTDevice +HaierClimateBase = haier_ns.class_( + "HaierClimateBase", uart.UARTDevice, climate.Climate, cg.Component ) +HonClimate = haier_ns.class_("HonClimate", HaierClimateBase) +Smartair2Climate = haier_ns.class_("Smartair2Climate", HaierClimateBase) -ALLOWED_CLIMATE_SWING_MODES = { - "BOTH": ClimateSwingMode.CLIMATE_SWING_BOTH, - "VERTICAL": ClimateSwingMode.CLIMATE_SWING_VERTICAL, - "HORIZONTAL": ClimateSwingMode.CLIMATE_SWING_HORIZONTAL, + +AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection") +AIRFLOW_VERTICAL_DIRECTION_OPTIONS = { + "UP": AirflowVerticalDirection.UP, + "CENTER": AirflowVerticalDirection.CENTER, + "DOWN": AirflowVerticalDirection.DOWN, } -validate_swing_modes = cv.enum(ALLOWED_CLIMATE_SWING_MODES, upper=True) +AirflowHorizontalDirection = haier_ns.enum("AirflowHorizontalDirection") +AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS = { + "LEFT": AirflowHorizontalDirection.LEFT, + "CENTER": AirflowHorizontalDirection.CENTER, + "RIGHT": AirflowHorizontalDirection.RIGHT, +} -CONFIG_SCHEMA = cv.All( +SUPPORTED_SWING_MODES_OPTIONS = { + "OFF": ClimateSwingMode.CLIMATE_SWING_OFF, # always available + "VERTICAL": ClimateSwingMode.CLIMATE_SWING_VERTICAL, # always available + "HORIZONTAL": ClimateSwingMode.CLIMATE_SWING_HORIZONTAL, + "BOTH": ClimateSwingMode.CLIMATE_SWING_BOTH, +} + +SUPPORTED_CLIMATE_MODES_OPTIONS = { + "OFF": ClimateMode.CLIMATE_MODE_OFF, # always available + "AUTO": ClimateMode.CLIMATE_MODE_AUTO, # always available + "COOL": ClimateMode.CLIMATE_MODE_COOL, + "HEAT": ClimateMode.CLIMATE_MODE_HEAT, + "DRY": ClimateMode.CLIMATE_MODE_DRY, + "FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY, +} + + +def validate_visual(config): + if CONF_VISUAL in config: + visual_config = config[CONF_VISUAL] + if CONF_MIN_TEMPERATURE in visual_config: + min_temp = visual_config[CONF_MIN_TEMPERATURE] + if min_temp < PROTOCOL_MIN_TEMPERATURE: + raise cv.Invalid( + f"Configured visual minimum temperature {min_temp} is lower than supported by Haier protocol is {PROTOCOL_MIN_TEMPERATURE}" + ) + else: + config[CONF_VISUAL][CONF_MIN_TEMPERATURE] = PROTOCOL_MIN_TEMPERATURE + if CONF_MAX_TEMPERATURE in visual_config: + max_temp = visual_config[CONF_MAX_TEMPERATURE] + if max_temp > PROTOCOL_MAX_TEMPERATURE: + raise cv.Invalid( + f"Configured visual maximum temperature {max_temp} is higher than supported by Haier protocol is {PROTOCOL_MAX_TEMPERATURE}" + ) + else: + config[CONF_VISUAL][CONF_MAX_TEMPERATURE] = PROTOCOL_MAX_TEMPERATURE + else: + config[CONF_VISUAL] = { + CONF_MIN_TEMPERATURE: PROTOCOL_MIN_TEMPERATURE, + CONF_MAX_TEMPERATURE: PROTOCOL_MAX_TEMPERATURE, + } + return config + + +BASE_CONFIG_SCHEMA = ( climate.CLIMATE_SCHEMA.extend( { - cv.GenerateID(): cv.declare_id(HaierClimate), - cv.Optional(CONF_SUPPORTED_SWING_MODES): cv.ensure_list( - validate_swing_modes + cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list( + cv.enum(SUPPORTED_CLIMATE_MODES_OPTIONS, upper=True) ), + cv.Optional( + CONF_SUPPORTED_SWING_MODES, + default=[ + "OFF", + "VERTICAL", + "HORIZONTAL", + "BOTH", + ], + ): cv.ensure_list(cv.enum(SUPPORTED_SWING_MODES_OPTIONS, upper=True)), } ) - .extend(cv.polling_component_schema("5s")) - .extend(uart.UART_DEVICE_SCHEMA), + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) ) +CONFIG_SCHEMA = cv.All( + cv.typed_schema( + { + PROTOCOL_SMARTAIR2: BASE_CONFIG_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(Smartair2Climate), + } + ), + PROTOCOL_HON: BASE_CONFIG_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(HonClimate), + cv.Optional(CONF_WIFI_SIGNAL, default=True): cv.boolean, + cv.Optional(CONF_BEEPER, default=True): cv.boolean, + cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ), + }, + key=CONF_PROTOCOL, + default_type=PROTOCOL_SMARTAIR2, + upper=True, + ), + validate_visual, +) + + +# Actions +DisplayOnAction = haier_ns.class_("DisplayOnAction", automation.Action) +DisplayOffAction = haier_ns.class_("DisplayOffAction", automation.Action) +BeeperOnAction = haier_ns.class_("BeeperOnAction", automation.Action) +BeeperOffAction = haier_ns.class_("BeeperOffAction", automation.Action) +StartSelfCleaningAction = haier_ns.class_("StartSelfCleaningAction", automation.Action) +StartSteriCleaningAction = haier_ns.class_( + "StartSteriCleaningAction", automation.Action +) +VerticalAirflowAction = haier_ns.class_("VerticalAirflowAction", automation.Action) +HorizontalAirflowAction = haier_ns.class_("HorizontalAirflowAction", automation.Action) +HealthOnAction = haier_ns.class_("HealthOnAction", automation.Action) +HealthOffAction = haier_ns.class_("HealthOffAction", automation.Action) +PowerOnAction = haier_ns.class_("PowerOnAction", automation.Action) +PowerOffAction = haier_ns.class_("PowerOffAction", automation.Action) +PowerToggleAction = haier_ns.class_("PowerToggleAction", automation.Action) + +HAIER_BASE_ACTION_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(HaierClimateBase), + } +) + +HAIER_HON_BASE_ACTION_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(HonClimate), + } +) + + +@automation.register_action( + "climate.haier.display_on", DisplayOnAction, HAIER_BASE_ACTION_SCHEMA +) +@automation.register_action( + "climate.haier.display_off", DisplayOffAction, HAIER_BASE_ACTION_SCHEMA +) +async def display_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +@automation.register_action( + "climate.haier.beeper_on", BeeperOnAction, HAIER_HON_BASE_ACTION_SCHEMA +) +@automation.register_action( + "climate.haier.beeper_off", BeeperOffAction, HAIER_HON_BASE_ACTION_SCHEMA +) +async def beeper_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +# Start self cleaning or steri-cleaning action action +@automation.register_action( + "climate.haier.start_self_cleaning", + StartSelfCleaningAction, + HAIER_HON_BASE_ACTION_SCHEMA, +) +@automation.register_action( + "climate.haier.start_steri_cleaning", + StartSteriCleaningAction, + HAIER_HON_BASE_ACTION_SCHEMA, +) +async def start_cleaning_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +# Set vertical airflow direction action +@automation.register_action( + "climate.haier.set_vertical_airflow", + VerticalAirflowAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(HonClimate), + cv.Required(CONF_VERTICAL_AIRFLOW): cv.templatable( + cv.enum(AIRFLOW_VERTICAL_DIRECTION_OPTIONS, upper=True) + ), + } + ), +) +async def haier_set_vertical_airflow_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable( + config[CONF_VERTICAL_AIRFLOW], args, AirflowVerticalDirection + ) + cg.add(var.set_direction(template_)) + return var + + +# Set horizontal airflow direction action +@automation.register_action( + "climate.haier.set_horizontal_airflow", + HorizontalAirflowAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(HonClimate), + cv.Required(CONF_HORIZONTAL_AIRFLOW): cv.templatable( + cv.enum(AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS, upper=True) + ), + } + ), +) +async def haier_set_horizontal_airflow_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable( + config[CONF_HORIZONTAL_AIRFLOW], args, AirflowHorizontalDirection + ) + cg.add(var.set_direction(template_)) + return var + + +@automation.register_action( + "climate.haier.health_on", HealthOnAction, HAIER_BASE_ACTION_SCHEMA +) +@automation.register_action( + "climate.haier.health_off", HealthOffAction, HAIER_BASE_ACTION_SCHEMA +) +async def health_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +@automation.register_action( + "climate.haier.power_on", PowerOnAction, HAIER_BASE_ACTION_SCHEMA +) +@automation.register_action( + "climate.haier.power_off", PowerOffAction, HAIER_BASE_ACTION_SCHEMA +) +@automation.register_action( + "climate.haier.power_toggle", PowerToggleAction, HAIER_BASE_ACTION_SCHEMA +) +async def power_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +def _final_validate(config): + full_config = fv.full_config.get() + if CONF_LOGGER in full_config: + _level = "NONE" + logger_config = full_config[CONF_LOGGER] + if CONF_LOGS in logger_config: + if "haier.protocol" in logger_config[CONF_LOGS]: + _level = logger_config[CONF_LOGS]["haier.protocol"] + else: + _level = logger_config[CONF_LEVEL] + _LOGGER.info("Detected log level for Haier protocol: %s", _level) + if _level not in logger.LOG_LEVEL_SEVERITY: + raise cv.Invalid("Unknown log level for Haier protocol") + _severity = logger.LOG_LEVEL_SEVERITY.index(_level) + cg.add_build_flag(f"-DHAIER_LOG_LEVEL={_severity}") + else: + _LOGGER.info( + "No logger component found, logging for Haier protocol is disabled" + ) + cg.add_build_flag("-DHAIER_LOG_LEVEL=0") + if ( + (CONF_WIFI_SIGNAL in config) + and (config[CONF_WIFI_SIGNAL]) + and CONF_WIFI not in full_config + ): + raise cv.Invalid( + f"No WiFi configured, if you want to use haier climate without WiFi add {CONF_WIFI_SIGNAL}: false to climate configuration" + ) + return config + + +FINAL_VALIDATE_SCHEMA = _final_validate + async def to_code(config): + cg.add(haier_ns.init_haier_protocol_logging()) var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - await climate.register_climate(var, config) await uart.register_uart_device(var, config) + await climate.register_climate(var, config) + + if (CONF_WIFI_SIGNAL in config) and (config[CONF_WIFI_SIGNAL]): + cg.add(var.set_send_wifi(config[CONF_WIFI_SIGNAL])) + if CONF_BEEPER in config: + cg.add(var.set_beeper_state(config[CONF_BEEPER])) + if CONF_OUTDOOR_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) + cg.add(var.set_outdoor_temperature_sensor(sens)) + if CONF_SUPPORTED_MODES in config: + cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES])) if CONF_SUPPORTED_SWING_MODES in config: cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES])) + # https://github.com/paveldn/HaierProtocol + cg.add_library("pavlodn/HaierProtocol", "0.9.18") diff --git a/esphome/components/haier/haier.cpp b/esphome/components/haier/haier.cpp deleted file mode 100644 index cf69d483b5..0000000000 --- a/esphome/components/haier/haier.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include -#include "haier.h" -#include "esphome/core/macros.h" - -namespace esphome { -namespace haier { - -static const char *const TAG = "haier"; - -static const uint8_t TEMPERATURE = 13; -static const uint8_t HUMIDITY = 15; - -static const uint8_t MODE = 23; - -static const uint8_t FAN_SPEED = 25; - -static const uint8_t SWING = 27; - -static const uint8_t POWER = 29; -static const uint8_t POWER_MASK = 1; - -static const uint8_t SET_TEMPERATURE = 35; -static const uint8_t DECIMAL_MASK = (1 << 5); - -static const uint8_t CRC = 36; - -static const uint8_t COMFORT_PRESET_MASK = (1 << 3); - -static const uint8_t MIN_VALID_TEMPERATURE = 16; -static const uint8_t MAX_VALID_TEMPERATURE = 50; -static const float TEMPERATURE_STEP = 0.5f; - -static const uint8_t POLL_REQ[13] = {255, 255, 10, 0, 0, 0, 0, 0, 1, 1, 77, 1, 90}; -static const uint8_t OFF_REQ[13] = {255, 255, 10, 0, 0, 0, 0, 0, 1, 1, 77, 3, 92}; - -void HaierClimate::dump_config() { - ESP_LOGCONFIG(TAG, "Haier:"); - ESP_LOGCONFIG(TAG, " Update interval: %u", this->get_update_interval()); - this->dump_traits_(TAG); - this->check_uart_settings(9600); -} - -void HaierClimate::loop() { - if (this->available() >= sizeof(this->data_)) { - this->read_array(this->data_, sizeof(this->data_)); - if (this->data_[0] != 255 || this->data_[1] != 255) - return; - - read_state_(this->data_, sizeof(this->data_)); - } -} - -void HaierClimate::update() { - this->write_array(POLL_REQ, sizeof(POLL_REQ)); - dump_message_("Poll sent", POLL_REQ, sizeof(POLL_REQ)); -} - -climate::ClimateTraits HaierClimate::traits() { - auto traits = climate::ClimateTraits(); - - traits.set_visual_min_temperature(MIN_VALID_TEMPERATURE); - traits.set_visual_max_temperature(MAX_VALID_TEMPERATURE); - traits.set_visual_temperature_step(TEMPERATURE_STEP); - - traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT_COOL, climate::CLIMATE_MODE_COOL, - climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY}); - - traits.set_supported_fan_modes({ - climate::CLIMATE_FAN_AUTO, - climate::CLIMATE_FAN_LOW, - climate::CLIMATE_FAN_MEDIUM, - climate::CLIMATE_FAN_HIGH, - }); - - traits.set_supported_swing_modes(this->supported_swing_modes_); - traits.set_supports_current_temperature(true); - traits.set_supports_two_point_target_temperature(false); - - traits.add_supported_preset(climate::CLIMATE_PRESET_NONE); - traits.add_supported_preset(climate::CLIMATE_PRESET_COMFORT); - - return traits; -} - -void HaierClimate::read_state_(const uint8_t *data, uint8_t size) { - dump_message_("Received state", data, size); - - uint8_t check = data[CRC]; - - uint8_t crc = get_checksum_(data, size); - - if (check != crc) { - ESP_LOGW(TAG, "Invalid checksum"); - return; - } - - this->current_temperature = data[TEMPERATURE]; - - this->target_temperature = data[SET_TEMPERATURE] + MIN_VALID_TEMPERATURE; - - if (data[POWER] & DECIMAL_MASK) { - this->target_temperature += 0.5f; - } - - switch (data[MODE]) { - case MODE_SMART: - this->mode = climate::CLIMATE_MODE_HEAT_COOL; - break; - case MODE_COOL: - this->mode = climate::CLIMATE_MODE_COOL; - break; - case MODE_HEAT: - this->mode = climate::CLIMATE_MODE_HEAT; - break; - case MODE_ONLY_FAN: - this->mode = climate::CLIMATE_MODE_FAN_ONLY; - break; - case MODE_DRY: - this->mode = climate::CLIMATE_MODE_DRY; - break; - default: // other modes are unsupported - this->mode = climate::CLIMATE_MODE_HEAT_COOL; - } - - switch (data[FAN_SPEED]) { - case FAN_AUTO: - this->fan_mode = climate::CLIMATE_FAN_AUTO; - break; - - case FAN_MIN: - this->fan_mode = climate::CLIMATE_FAN_LOW; - break; - - case FAN_MIDDLE: - this->fan_mode = climate::CLIMATE_FAN_MEDIUM; - break; - - case FAN_MAX: - this->fan_mode = climate::CLIMATE_FAN_HIGH; - break; - } - - switch (data[SWING]) { - case SWING_OFF: - this->swing_mode = climate::CLIMATE_SWING_OFF; - break; - - case SWING_VERTICAL: - this->swing_mode = climate::CLIMATE_SWING_VERTICAL; - break; - - case SWING_HORIZONTAL: - this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; - break; - - case SWING_BOTH: - this->swing_mode = climate::CLIMATE_SWING_BOTH; - break; - } - - if (data[POWER] & COMFORT_PRESET_MASK) { - this->preset = climate::CLIMATE_PRESET_COMFORT; - } else { - this->preset = climate::CLIMATE_PRESET_NONE; - } - - if ((data[POWER] & POWER_MASK) == 0) { - this->mode = climate::CLIMATE_MODE_OFF; - } - - this->publish_state(); -} - -void HaierClimate::control(const climate::ClimateCall &call) { - if (call.get_mode().has_value()) { - switch (call.get_mode().value()) { - case climate::CLIMATE_MODE_OFF: - send_data_(OFF_REQ, sizeof(OFF_REQ)); - break; - - case climate::CLIMATE_MODE_HEAT_COOL: - case climate::CLIMATE_MODE_AUTO: - data_[POWER] |= POWER_MASK; - data_[MODE] = MODE_SMART; - break; - case climate::CLIMATE_MODE_HEAT: - data_[POWER] |= POWER_MASK; - data_[MODE] = MODE_HEAT; - break; - case climate::CLIMATE_MODE_COOL: - data_[POWER] |= POWER_MASK; - data_[MODE] = MODE_COOL; - break; - - case climate::CLIMATE_MODE_FAN_ONLY: - data_[POWER] |= POWER_MASK; - data_[MODE] = MODE_ONLY_FAN; - break; - - case climate::CLIMATE_MODE_DRY: - data_[POWER] |= POWER_MASK; - data_[MODE] = MODE_DRY; - break; - } - } - - if (call.get_preset().has_value()) { - if (call.get_preset().value() == climate::CLIMATE_PRESET_COMFORT) { - data_[POWER] |= COMFORT_PRESET_MASK; - } else { - data_[POWER] &= ~COMFORT_PRESET_MASK; - } - } - - if (call.get_target_temperature().has_value()) { - float target = call.get_target_temperature().value() - MIN_VALID_TEMPERATURE; - - data_[SET_TEMPERATURE] = (uint8_t) target; - - if ((int) target == std::lroundf(target)) { - data_[POWER] &= ~DECIMAL_MASK; - } else { - data_[POWER] |= DECIMAL_MASK; - } - } - - if (call.get_fan_mode().has_value()) { - switch (call.get_fan_mode().value()) { - case climate::CLIMATE_FAN_AUTO: - data_[FAN_SPEED] = FAN_AUTO; - break; - case climate::CLIMATE_FAN_LOW: - data_[FAN_SPEED] = FAN_MIN; - break; - case climate::CLIMATE_FAN_MEDIUM: - data_[FAN_SPEED] = FAN_MIDDLE; - break; - case climate::CLIMATE_FAN_HIGH: - data_[FAN_SPEED] = FAN_MAX; - break; - - default: // other modes are unsupported - break; - } - } - - if (call.get_swing_mode().has_value()) { - switch (call.get_swing_mode().value()) { - case climate::CLIMATE_SWING_OFF: - data_[SWING] = SWING_OFF; - break; - case climate::CLIMATE_SWING_VERTICAL: - data_[SWING] = SWING_VERTICAL; - break; - case climate::CLIMATE_SWING_HORIZONTAL: - data_[SWING] = SWING_HORIZONTAL; - break; - case climate::CLIMATE_SWING_BOTH: - data_[SWING] = SWING_BOTH; - break; - } - } - - // Parts of the message that must have specific values for "send" command. - // The meaning of those values is unknown at the moment. - data_[9] = 1; - data_[10] = 77; - data_[11] = 95; - data_[17] = 0; - - // Compute checksum - uint8_t crc = get_checksum_(data_, sizeof(data_)); - data_[CRC] = crc; - - send_data_(data_, sizeof(data_)); -} - -void HaierClimate::send_data_(const uint8_t *message, uint8_t size) { - this->write_array(message, size); - - dump_message_("Sent message", message, size); -} - -void HaierClimate::dump_message_(const char *title, const uint8_t *message, uint8_t size) { - ESP_LOGV(TAG, "%s:", title); - for (int i = 0; i < size; i++) { - ESP_LOGV(TAG, " byte %02d - %d", i, message[i]); - } -} - -uint8_t HaierClimate::get_checksum_(const uint8_t *message, size_t size) { - uint8_t position = size - 1; - uint8_t crc = 0; - - for (int i = 2; i < position; i++) - crc += message[i]; - - return crc; -} - -} // namespace haier -} // namespace esphome diff --git a/esphome/components/haier/haier.h b/esphome/components/haier/haier.h deleted file mode 100644 index 5399fd187b..0000000000 --- a/esphome/components/haier/haier.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" -#include "esphome/components/climate/climate.h" -#include "esphome/components/uart/uart.h" - -namespace esphome { -namespace haier { - -enum Mode : uint8_t { MODE_SMART = 0, MODE_COOL = 1, MODE_HEAT = 2, MODE_ONLY_FAN = 3, MODE_DRY = 4 }; -enum FanSpeed : uint8_t { FAN_MAX = 0, FAN_MIDDLE = 1, FAN_MIN = 2, FAN_AUTO = 3 }; -enum SwingMode : uint8_t { SWING_OFF = 0, SWING_VERTICAL = 1, SWING_HORIZONTAL = 2, SWING_BOTH = 3 }; - -class HaierClimate : public climate::Climate, public uart::UARTDevice, public PollingComponent { - public: - void loop() override; - void update() override; - void dump_config() override; - void control(const climate::ClimateCall &call) override; - void set_supported_swing_modes(const std::set &modes) { - this->supported_swing_modes_ = modes; - } - - protected: - climate::ClimateTraits traits() override; - void read_state_(const uint8_t *data, uint8_t size); - void send_data_(const uint8_t *message, uint8_t size); - void dump_message_(const char *title, const uint8_t *message, uint8_t size); - uint8_t get_checksum_(const uint8_t *message, size_t size); - - private: - uint8_t data_[37]; - std::set supported_swing_modes_{}; -}; - -} // namespace haier -} // namespace esphome diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp new file mode 100644 index 0000000000..d9349cb8fe --- /dev/null +++ b/esphome/components/haier/haier_base.cpp @@ -0,0 +1,311 @@ +#include +#include +#include "esphome/components/climate/climate.h" +#include "esphome/components/uart/uart.h" +#include "haier_base.h" + +using namespace esphome::climate; +using namespace esphome::uart; + +namespace esphome { +namespace haier { + +static const char *const TAG = "haier.climate"; +constexpr size_t COMMUNICATION_TIMEOUT_MS = 60000; +constexpr size_t STATUS_REQUEST_INTERVAL_MS = 5000; +constexpr size_t PROTOCOL_INITIALIZATION_INTERVAL = 10000; +constexpr size_t DEFAULT_MESSAGES_INTERVAL_MS = 2000; +constexpr size_t CONTROL_MESSAGES_INTERVAL_MS = 400; +constexpr size_t CONTROL_TIMEOUT_MS = 7000; +constexpr size_t NO_COMMAND = 0xFF; // Indicate that there is no command supplied + +#if (HAIER_LOG_LEVEL > 4) +// To reduce size of binary this function only available when log level is Verbose +const char *HaierClimateBase::phase_to_string_(ProtocolPhases phase) { + static const char *phase_names[] = { + "SENDING_INIT_1", + "WAITING_ANSWER_INIT_1", + "SENDING_INIT_2", + "WAITING_ANSWER_INIT_2", + "SENDING_FIRST_STATUS_REQUEST", + "WAITING_FIRST_STATUS_ANSWER", + "SENDING_ALARM_STATUS_REQUEST", + "WAITING_ALARM_STATUS_ANSWER", + "IDLE", + "SENDING_STATUS_REQUEST", + "WAITING_STATUS_ANSWER", + "SENDING_UPDATE_SIGNAL_REQUEST", + "WAITING_UPDATE_SIGNAL_ANSWER", + "SENDING_SIGNAL_LEVEL", + "WAITING_SIGNAL_LEVEL_ANSWER", + "SENDING_CONTROL", + "WAITING_CONTROL_ANSWER", + "SENDING_POWER_ON_COMMAND", + "WAITING_POWER_ON_ANSWER", + "SENDING_POWER_OFF_COMMAND", + "WAITING_POWER_OFF_ANSWER", + "UNKNOWN" // Should be the last! + }; + int phase_index = (int) phase; + if ((phase_index > (int) ProtocolPhases::NUM_PROTOCOL_PHASES) || (phase_index < 0)) + phase_index = (int) ProtocolPhases::NUM_PROTOCOL_PHASES; + return phase_names[phase_index]; +} +#endif + +HaierClimateBase::HaierClimateBase() + : haier_protocol_(*this), + protocol_phase_(ProtocolPhases::SENDING_INIT_1), + action_request_(ActionRequest::NO_ACTION), + display_status_(true), + health_mode_(false), + force_send_control_(false), + forced_publish_(false), + forced_request_status_(false), + first_control_attempt_(false), + reset_protocol_request_(false) { + this->traits_ = climate::ClimateTraits(); + this->traits_.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, + climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, + climate::CLIMATE_MODE_AUTO}); + this->traits_.set_supported_fan_modes( + {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH}); + this->traits_.set_supported_swing_modes({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, + climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL}); + this->traits_.set_supports_current_temperature(true); +} + +HaierClimateBase::~HaierClimateBase() {} + +void HaierClimateBase::set_phase_(ProtocolPhases phase) { + if (this->protocol_phase_ != phase) { +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGV(TAG, "Phase transition: %s => %s", phase_to_string_(this->protocol_phase_), phase_to_string_(phase)); +#else + ESP_LOGV(TAG, "Phase transition: %d => %d", (int) this->protocol_phase_, (int) phase); +#endif + this->protocol_phase_ = phase; + } +} + +bool HaierClimateBase::check_timeout_(std::chrono::steady_clock::time_point now, + std::chrono::steady_clock::time_point tpoint, size_t timeout) { + return std::chrono::duration_cast(now - tpoint).count() > timeout; +} + +bool HaierClimateBase::is_message_interval_exceeded_(std::chrono::steady_clock::time_point now) { + return this->check_timeout_(now, this->last_request_timestamp_, DEFAULT_MESSAGES_INTERVAL_MS); +} + +bool HaierClimateBase::is_status_request_interval_exceeded_(std::chrono::steady_clock::time_point now) { + return this->check_timeout_(now, this->last_status_request_, STATUS_REQUEST_INTERVAL_MS); +} + +bool HaierClimateBase::is_control_message_timeout_exceeded_(std::chrono::steady_clock::time_point now) { + return this->check_timeout_(now, this->control_request_timestamp_, CONTROL_TIMEOUT_MS); +} + +bool HaierClimateBase::is_control_message_interval_exceeded_(std::chrono::steady_clock::time_point now) { + return this->check_timeout_(now, this->last_request_timestamp_, CONTROL_MESSAGES_INTERVAL_MS); +} + +bool HaierClimateBase::is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now) { + return this->check_timeout_(now, this->last_request_timestamp_, PROTOCOL_INITIALIZATION_INTERVAL); +} + +bool HaierClimateBase::get_display_state() const { return this->display_status_; } + +void HaierClimateBase::set_display_state(bool state) { + if (this->display_status_ != state) { + this->display_status_ = state; + this->set_force_send_control_(true); + } +} + +bool HaierClimateBase::get_health_mode() const { return this->health_mode_; } + +void HaierClimateBase::set_health_mode(bool state) { + if (this->health_mode_ != state) { + this->health_mode_ = state; + this->set_force_send_control_(true); + } +} + +void HaierClimateBase::send_power_on_command() { this->action_request_ = ActionRequest::TURN_POWER_ON; } + +void HaierClimateBase::send_power_off_command() { this->action_request_ = ActionRequest::TURN_POWER_OFF; } + +void HaierClimateBase::toggle_power() { this->action_request_ = ActionRequest::TOGGLE_POWER; } +void HaierClimateBase::set_supported_swing_modes(const std::set &modes) { + this->traits_.set_supported_swing_modes(modes); + this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); // Always available + this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); // Always available +} + +void HaierClimateBase::set_supported_modes(const std::set &modes) { + this->traits_.set_supported_modes(modes); + this->traits_.add_supported_mode(climate::CLIMATE_MODE_OFF); // Always available + this->traits_.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Always available +} + +haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(uint8_t request_message_type, + uint8_t expected_request_message_type, + uint8_t answer_message_type, + uint8_t expected_answer_message_type, + ProtocolPhases expected_phase) { + haier_protocol::HandlerError result = haier_protocol::HandlerError::HANDLER_OK; + if ((expected_request_message_type != NO_COMMAND) && (request_message_type != expected_request_message_type)) + result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + if ((expected_answer_message_type != NO_COMMAND) && (answer_message_type != expected_answer_message_type)) + result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + if ((expected_phase != ProtocolPhases::UNKNOWN) && (expected_phase != this->protocol_phase_)) + result = haier_protocol::HandlerError::UNEXPECTED_MESSAGE; + if (is_message_invalid(answer_message_type)) + result = haier_protocol::HandlerError::INVALID_ANSWER; + return result; +} + +haier_protocol::HandlerError HaierClimateBase::timeout_default_handler_(uint8_t request_type) { +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGW(TAG, "Answer timeout for command %02X, phase %s", request_type, phase_to_string_(this->protocol_phase_)); +#else + ESP_LOGW(TAG, "Answer timeout for command %02X, phase %d", request_type, (int) this->protocol_phase_); +#endif + if (this->protocol_phase_ > ProtocolPhases::IDLE) { + this->set_phase_(ProtocolPhases::IDLE); + } else { + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + } + return haier_protocol::HandlerError::HANDLER_OK; +} + +void HaierClimateBase::setup() { + ESP_LOGI(TAG, "Haier initialization..."); + // Set timestamp here to give AC time to boot + this->last_request_timestamp_ = std::chrono::steady_clock::now(); + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_answers_handlers(); + this->haier_protocol_.set_default_timeout_handler( + std::bind(&esphome::haier::HaierClimateBase::timeout_default_handler_, this, std::placeholders::_1)); +} + +void HaierClimateBase::dump_config() { + LOG_CLIMATE("", "Haier Climate", this); + ESP_LOGCONFIG(TAG, " Device communication status: %s", + (this->protocol_phase_ >= ProtocolPhases::IDLE) ? "established" : "none"); +} + +void HaierClimateBase::loop() { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + if ((std::chrono::duration_cast(now - this->last_valid_status_timestamp_).count() > + COMMUNICATION_TIMEOUT_MS) || + (this->reset_protocol_request_)) { + if (this->protocol_phase_ >= ProtocolPhases::IDLE) { + // No status too long, reseting protocol + if (this->reset_protocol_request_) { + this->reset_protocol_request_ = false; + ESP_LOGW(TAG, "Protocol reset requested"); + } else { + ESP_LOGW(TAG, "Communication timeout, reseting protocol"); + } + this->last_valid_status_timestamp_ = now; + this->set_force_send_control_(false); + if (this->hvac_settings_.valid) + this->hvac_settings_.reset(); + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + return; + } else { + // No need to reset protocol if we didn't pass initialization phase + this->last_valid_status_timestamp_ = now; + } + }; + if ((this->protocol_phase_ == ProtocolPhases::IDLE) || + (this->protocol_phase_ == ProtocolPhases::SENDING_STATUS_REQUEST) || + (this->protocol_phase_ == ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST) || + (this->protocol_phase_ == ProtocolPhases::SENDING_SIGNAL_LEVEL)) { + // If control message or action is pending we should send it ASAP unless we are in initialisation + // procedure or waiting for an answer + if (this->action_request_ != ActionRequest::NO_ACTION) { + this->process_pending_action(); + } else if (this->hvac_settings_.valid || this->force_send_control_) { + ESP_LOGV(TAG, "Control packet is pending..."); + this->set_phase_(ProtocolPhases::SENDING_CONTROL); + } + } + this->process_phase(now); + this->haier_protocol_.loop(); +} + +void HaierClimateBase::process_pending_action() { + ActionRequest request = this->action_request_; + if (this->action_request_ == ActionRequest::TOGGLE_POWER) { + request = this->mode == CLIMATE_MODE_OFF ? ActionRequest::TURN_POWER_ON : ActionRequest::TURN_POWER_OFF; + } + switch (request) { + case ActionRequest::TURN_POWER_ON: + this->set_phase_(ProtocolPhases::SENDING_POWER_ON_COMMAND); + break; + case ActionRequest::TURN_POWER_OFF: + this->set_phase_(ProtocolPhases::SENDING_POWER_OFF_COMMAND); + break; + case ActionRequest::TOGGLE_POWER: + case ActionRequest::NO_ACTION: + // shouldn't get here, do nothing + break; + default: + ESP_LOGW(TAG, "Unsupported action: %d", (uint8_t) this->action_request_); + break; + } + this->action_request_ = ActionRequest::NO_ACTION; +} + +ClimateTraits HaierClimateBase::traits() { return traits_; } + +void HaierClimateBase::control(const ClimateCall &call) { + ESP_LOGD("Control", "Control call"); + if (this->protocol_phase_ < ProtocolPhases::IDLE) { + ESP_LOGW(TAG, "Can't send control packet, first poll answer not received"); + return; // cancel the control, we cant do it without a poll answer. + } + if (this->hvac_settings_.valid) { + ESP_LOGW(TAG, "Overriding old valid settings before they were applied!"); + } + { + if (call.get_mode().has_value()) + this->hvac_settings_.mode = call.get_mode(); + if (call.get_fan_mode().has_value()) + this->hvac_settings_.fan_mode = call.get_fan_mode(); + if (call.get_swing_mode().has_value()) + this->hvac_settings_.swing_mode = call.get_swing_mode(); + if (call.get_target_temperature().has_value()) + this->hvac_settings_.target_temperature = call.get_target_temperature(); + if (call.get_preset().has_value()) + this->hvac_settings_.preset = call.get_preset(); + this->hvac_settings_.valid = true; + } + this->first_control_attempt_ = true; +} + +void HaierClimateBase::HvacSettings::reset() { + this->valid = false; + this->mode.reset(); + this->fan_mode.reset(); + this->swing_mode.reset(); + this->target_temperature.reset(); + this->preset.reset(); +} + +void HaierClimateBase::set_force_send_control_(bool status) { + this->force_send_control_ = status; + if (status) { + this->first_control_attempt_ = true; + } +} + +void HaierClimateBase::send_message_(const haier_protocol::HaierMessage &command, bool use_crc) { + this->haier_protocol_.send_message(command, use_crc); + this->last_request_timestamp_ = std::chrono::steady_clock::now(); +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h new file mode 100644 index 0000000000..046b59af96 --- /dev/null +++ b/esphome/components/haier/haier_base.h @@ -0,0 +1,142 @@ +#pragma once + +#include +#include +#include "esphome/components/climate/climate.h" +#include "esphome/components/uart/uart.h" +// HaierProtocol +#include + +namespace esphome { +namespace haier { + +enum class ActionRequest : uint8_t { + NO_ACTION = 0, + TURN_POWER_ON = 1, + TURN_POWER_OFF = 2, + TOGGLE_POWER = 3, + START_SELF_CLEAN = 4, // only hOn + START_STERI_CLEAN = 5, // only hOn +}; + +class HaierClimateBase : public esphome::Component, + public esphome::climate::Climate, + public esphome::uart::UARTDevice, + public haier_protocol::ProtocolStream { + public: + HaierClimateBase(); + HaierClimateBase(const HaierClimateBase &) = delete; + HaierClimateBase &operator=(const HaierClimateBase &) = delete; + ~HaierClimateBase(); + void setup() override; + void loop() override; + void control(const esphome::climate::ClimateCall &call) override; + void dump_config() override; + float get_setup_priority() const override { return esphome::setup_priority::HARDWARE; } + void set_fahrenheit(bool fahrenheit); + void set_display_state(bool state); + bool get_display_state() const; + void set_health_mode(bool state); + bool get_health_mode() const; + void send_power_on_command(); + void send_power_off_command(); + void toggle_power(); + void reset_protocol() { this->reset_protocol_request_ = true; }; + void set_supported_modes(const std::set &modes); + void set_supported_swing_modes(const std::set &modes); + size_t available() noexcept override { return esphome::uart::UARTDevice::available(); }; + size_t read_array(uint8_t *data, size_t len) noexcept override { + return esphome::uart::UARTDevice::read_array(data, len) ? len : 0; + }; + void write_array(const uint8_t *data, size_t len) noexcept override { + esphome::uart::UARTDevice::write_array(data, len); + }; + bool can_send_message() const { return haier_protocol_.get_outgoing_queue_size() == 0; }; + + protected: + enum class ProtocolPhases { + UNKNOWN = -1, + // INITIALIZATION + SENDING_INIT_1 = 0, + WAITING_ANSWER_INIT_1 = 1, + SENDING_INIT_2 = 2, + WAITING_ANSWER_INIT_2 = 3, + SENDING_FIRST_STATUS_REQUEST = 4, + WAITING_FIRST_STATUS_ANSWER = 5, + SENDING_ALARM_STATUS_REQUEST = 6, + WAITING_ALARM_STATUS_ANSWER = 7, + // FUNCTIONAL STATE + IDLE = 8, + SENDING_STATUS_REQUEST = 9, + WAITING_STATUS_ANSWER = 10, + SENDING_UPDATE_SIGNAL_REQUEST = 11, + WAITING_UPDATE_SIGNAL_ANSWER = 12, + SENDING_SIGNAL_LEVEL = 13, + WAITING_SIGNAL_LEVEL_ANSWER = 14, + SENDING_CONTROL = 15, + WAITING_CONTROL_ANSWER = 16, + SENDING_POWER_ON_COMMAND = 17, + WAITING_POWER_ON_ANSWER = 18, + SENDING_POWER_OFF_COMMAND = 19, + WAITING_POWER_OFF_ANSWER = 20, + NUM_PROTOCOL_PHASES + }; +#if (HAIER_LOG_LEVEL > 4) + const char *phase_to_string_(ProtocolPhases phase); +#endif + virtual void set_answers_handlers() = 0; + virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; + virtual haier_protocol::HaierMessage get_control_message() = 0; + virtual bool is_message_invalid(uint8_t message_type) = 0; + virtual void process_pending_action(); + esphome::climate::ClimateTraits traits() override; + // Answers handlers + haier_protocol::HandlerError answer_preprocess_(uint8_t request_message_type, uint8_t expected_request_message_type, + uint8_t answer_message_type, uint8_t expected_answer_message_type, + ProtocolPhases expected_phase); + // Timeout handler + haier_protocol::HandlerError timeout_default_handler_(uint8_t request_type); + // Helper functions + void set_force_send_control_(bool status); + void send_message_(const haier_protocol::HaierMessage &command, bool use_crc); + void set_phase_(ProtocolPhases phase); + bool check_timeout_(std::chrono::steady_clock::time_point now, std::chrono::steady_clock::time_point tpoint, + size_t timeout); + bool is_message_interval_exceeded_(std::chrono::steady_clock::time_point now); + bool is_status_request_interval_exceeded_(std::chrono::steady_clock::time_point now); + bool is_control_message_timeout_exceeded_(std::chrono::steady_clock::time_point now); + bool is_control_message_interval_exceeded_(std::chrono::steady_clock::time_point now); + bool is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now); + + struct HvacSettings { + esphome::optional mode; + esphome::optional fan_mode; + esphome::optional swing_mode; + esphome::optional target_temperature; + esphome::optional preset; + bool valid; + HvacSettings() : valid(false){}; + void reset(); + }; + haier_protocol::ProtocolHandler haier_protocol_; + ProtocolPhases protocol_phase_; + ActionRequest action_request_; + uint8_t fan_mode_speed_; + uint8_t other_modes_fan_speed_; + bool display_status_; + bool health_mode_; + bool force_send_control_; + bool forced_publish_; + bool forced_request_status_; + bool first_control_attempt_; + bool reset_protocol_request_; + esphome::climate::ClimateTraits traits_; + HvacSettings hvac_settings_; + std::chrono::steady_clock::time_point last_request_timestamp_; // For interval between messages + std::chrono::steady_clock::time_point last_valid_status_timestamp_; // For protocol timeout + std::chrono::steady_clock::time_point last_status_request_; // To request AC status + std::chrono::steady_clock::time_point control_request_timestamp_; // To send control message +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp new file mode 100644 index 0000000000..3016cda397 --- /dev/null +++ b/esphome/components/haier/hon_climate.cpp @@ -0,0 +1,857 @@ +#include +#include +#include "esphome/components/climate/climate.h" +#include "esphome/components/uart/uart.h" +#ifdef USE_WIFI +#include "esphome/components/wifi/wifi_component.h" +#endif +#include "hon_climate.h" +#include "hon_packet.h" + +using namespace esphome::climate; +using namespace esphome::uart; + +namespace esphome { +namespace haier { + +static const char *const TAG = "haier.climate"; +constexpr size_t SIGNAL_LEVEL_UPDATE_INTERVAL_MS = 10000; +constexpr int PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET = -64; + +hon_protocol::VerticalSwingMode get_vertical_swing_mode(AirflowVerticalDirection direction) { + switch (direction) { + case AirflowVerticalDirection::HEALTH_UP: + return hon_protocol::VerticalSwingMode::HEALTH_UP; + case AirflowVerticalDirection::MAX_UP: + return hon_protocol::VerticalSwingMode::MAX_UP; + case AirflowVerticalDirection::UP: + return hon_protocol::VerticalSwingMode::UP; + case AirflowVerticalDirection::DOWN: + return hon_protocol::VerticalSwingMode::DOWN; + case AirflowVerticalDirection::HEALTH_DOWN: + return hon_protocol::VerticalSwingMode::HEALTH_DOWN; + default: + return hon_protocol::VerticalSwingMode::CENTER; + } +} + +hon_protocol::HorizontalSwingMode get_horizontal_swing_mode(AirflowHorizontalDirection direction) { + switch (direction) { + case AirflowHorizontalDirection::MAX_LEFT: + return hon_protocol::HorizontalSwingMode::MAX_LEFT; + case AirflowHorizontalDirection::LEFT: + return hon_protocol::HorizontalSwingMode::LEFT; + case AirflowHorizontalDirection::RIGHT: + return hon_protocol::HorizontalSwingMode::RIGHT; + case AirflowHorizontalDirection::MAX_RIGHT: + return hon_protocol::HorizontalSwingMode::MAX_RIGHT; + default: + return hon_protocol::HorizontalSwingMode::CENTER; + } +} + +HonClimate::HonClimate() + : last_status_message_(new uint8_t[sizeof(hon_protocol::HaierPacketControl)]), + cleaning_status_(CleaningState::NO_CLEANING), + got_valid_outdoor_temp_(false), + hvac_hardware_info_available_(false), + hvac_functions_{false, false, false, false, false}, + use_crc_(hvac_functions_[2]), + active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + outdoor_sensor_(nullptr), + send_wifi_signal_(true) { + this->traits_.set_supported_presets({ + climate::CLIMATE_PRESET_NONE, + climate::CLIMATE_PRESET_ECO, + climate::CLIMATE_PRESET_BOOST, + climate::CLIMATE_PRESET_SLEEP, + }); + this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID; + this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO; +} + +HonClimate::~HonClimate() {} + +void HonClimate::set_beeper_state(bool state) { this->beeper_status_ = state; } + +bool HonClimate::get_beeper_state() const { return this->beeper_status_; } + +void HonClimate::set_outdoor_temperature_sensor(esphome::sensor::Sensor *sensor) { this->outdoor_sensor_ = sensor; } + +AirflowVerticalDirection HonClimate::get_vertical_airflow() const { return this->vertical_direction_; }; + +void HonClimate::set_vertical_airflow(AirflowVerticalDirection direction) { + if (direction > AirflowVerticalDirection::DOWN) { + this->vertical_direction_ = AirflowVerticalDirection::CENTER; + } else { + this->vertical_direction_ = direction; + } + this->set_force_send_control_(true); +} + +AirflowHorizontalDirection HonClimate::get_horizontal_airflow() const { return this->horizontal_direction_; } + +void HonClimate::set_horizontal_airflow(AirflowHorizontalDirection direction) { + if (direction > AirflowHorizontalDirection::RIGHT) { + this->horizontal_direction_ = AirflowHorizontalDirection::CENTER; + } else { + this->horizontal_direction_ = direction; + } + this->set_force_send_control_(true); +} + +std::string HonClimate::get_cleaning_status_text() const { + switch (this->cleaning_status_) { + case CleaningState::SELF_CLEAN: + return "Self clean"; + case CleaningState::STERI_CLEAN: + return "56°C Steri-Clean"; + default: + return "No cleaning"; + } +} + +CleaningState HonClimate::get_cleaning_status() const { return this->cleaning_status_; } + +void HonClimate::start_self_cleaning() { + if (this->cleaning_status_ == CleaningState::NO_CLEANING) { + ESP_LOGI(TAG, "Sending self cleaning start request"); + this->action_request_ = ActionRequest::START_SELF_CLEAN; + this->set_force_send_control_(true); + } +} + +void HonClimate::start_steri_cleaning() { + if (this->cleaning_status_ == CleaningState::NO_CLEANING) { + ESP_LOGI(TAG, "Sending steri cleaning start request"); + this->action_request_ = ActionRequest::START_STERI_CLEAN; + this->set_force_send_control_(true); + } +} + +void HonClimate::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; } + +haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size) { + haier_protocol::HandlerError result = this->answer_preprocess_( + request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, message_type, + (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_1); + if (result == haier_protocol::HandlerError::HANDLER_OK) { + if (data_size < sizeof(hon_protocol::DeviceVersionAnswer)) { + // Wrong structure + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; + } + // All OK + hon_protocol::DeviceVersionAnswer *answr = (hon_protocol::DeviceVersionAnswer *) data; + char tmp[9]; + tmp[8] = 0; + strncpy(tmp, answr->protocol_version, 8); + this->hvac_protocol_version_ = std::string(tmp); + strncpy(tmp, answr->software_version, 8); + this->hvac_software_version_ = std::string(tmp); + strncpy(tmp, answr->hardware_version, 8); + this->hvac_hardware_version_ = std::string(tmp); + strncpy(tmp, answr->device_name, 8); + this->hvac_device_name_ = std::string(tmp); + this->hvac_functions_[0] = (answr->functions[1] & 0x01) != 0; // interactive mode support + this->hvac_functions_[1] = (answr->functions[1] & 0x02) != 0; // controller-device mode support + this->hvac_functions_[2] = (answr->functions[1] & 0x04) != 0; // crc support + this->hvac_functions_[3] = (answr->functions[1] & 0x08) != 0; // multiple AC support + this->hvac_functions_[4] = (answr->functions[1] & 0x20) != 0; // roles support + this->hvac_hardware_info_available_ = true; + this->set_phase_(ProtocolPhases::SENDING_INIT_2); + return result; + } else { + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); + return result; + } +} + +haier_protocol::HandlerError HonClimate::get_device_id_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size) { + haier_protocol::HandlerError result = this->answer_preprocess_( + request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID, message_type, + (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_2); + if (result == haier_protocol::HandlerError::HANDLER_OK) { + this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + return result; + } else { + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); + return result; + } +} + +haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size) { + haier_protocol::HandlerError result = + this->answer_preprocess_(request_type, (uint8_t) hon_protocol::FrameType::CONTROL, message_type, + (uint8_t) hon_protocol::FrameType::STATUS, ProtocolPhases::UNKNOWN); + if (result == haier_protocol::HandlerError::HANDLER_OK) { + result = this->process_status_message_(data, data_size); + if (result != haier_protocol::HandlerError::HANDLER_OK) { + ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); + } else { + if (data_size >= sizeof(hon_protocol::HaierPacketControl) + 2) { + memcpy(this->last_status_message_.get(), data + 2, sizeof(hon_protocol::HaierPacketControl)); + } else { + ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, + sizeof(hon_protocol::HaierPacketControl)); + } + if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { + ESP_LOGI(TAG, "First HVAC status received"); + this->set_phase_(ProtocolPhases::SENDING_ALARM_STATUS_REQUEST); + } else if ((this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) || + (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_ON_ANSWER) || + (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_OFF_ANSWER)) { + this->set_phase_(ProtocolPhases::IDLE); + } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { + this->set_phase_(ProtocolPhases::IDLE); + this->set_force_send_control_(false); + if (this->hvac_settings_.valid) + this->hvac_settings_.reset(); + } + } + return result; + } else { + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); + return result; + } +} + +haier_protocol::HandlerError HonClimate::get_management_information_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, + size_t data_size) { + haier_protocol::HandlerError result = + this->answer_preprocess_(request_type, (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION, + message_type, (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION_RESPONSE, + ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); + if (result == haier_protocol::HandlerError::HANDLER_OK) { + this->set_phase_(ProtocolPhases::SENDING_SIGNAL_LEVEL); + return result; + } else { + this->set_phase_(ProtocolPhases::IDLE); + return result; + } +} + +haier_protocol::HandlerError HonClimate::report_network_status_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, size_t data_size) { + haier_protocol::HandlerError result = + this->answer_preprocess_(request_type, (uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, message_type, + (uint8_t) hon_protocol::FrameType::CONFIRM, ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + this->set_phase_(ProtocolPhases::IDLE); + return result; +} + +haier_protocol::HandlerError HonClimate::get_alarm_status_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size) { + if (request_type == (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS) { + if (message_type != (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS_RESPONSE) { + // Unexpected answer to request + this->set_phase_(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + } + if (this->protocol_phase_ != ProtocolPhases::WAITING_ALARM_STATUS_ANSWER) { + // Don't expect this answer now + this->set_phase_(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNEXPECTED_MESSAGE; + } + memcpy(this->active_alarms_, data + 2, 8); + this->set_phase_(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::HANDLER_OK; + } else { + this->set_phase_(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + } +} + +void HonClimate::set_answers_handlers() { + // Set handlers + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::GET_DEVICE_VERSION), + std::bind(&HonClimate::get_device_version_answer_handler_, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::GET_DEVICE_ID), + std::bind(&HonClimate::get_device_id_answer_handler_, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::CONTROL), + std::bind(&HonClimate::status_handler_, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION), + std::bind(&HonClimate::get_management_information_answer_handler_, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::GET_ALARM_STATUS), + std::bind(&HonClimate::get_alarm_status_answer_handler_, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (hon_protocol::FrameType::REPORT_NETWORK_STATUS), + std::bind(&HonClimate::report_network_status_answer_handler_, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); +} + +void HonClimate::dump_config() { + HaierClimateBase::dump_config(); + ESP_LOGCONFIG(TAG, " Protocol version: hOn"); + if (this->hvac_hardware_info_available_) { + ESP_LOGCONFIG(TAG, " Device protocol version: %s", this->hvac_protocol_version_.c_str()); + ESP_LOGCONFIG(TAG, " Device software version: %s", this->hvac_software_version_.c_str()); + ESP_LOGCONFIG(TAG, " Device hardware version: %s", this->hvac_hardware_version_.c_str()); + ESP_LOGCONFIG(TAG, " Device name: %s", this->hvac_device_name_.c_str()); + ESP_LOGCONFIG(TAG, " Device features:%s%s%s%s%s", (this->hvac_functions_[0] ? " interactive" : ""), + (this->hvac_functions_[1] ? " controller-device" : ""), (this->hvac_functions_[2] ? " crc" : ""), + (this->hvac_functions_[3] ? " multinode" : ""), (this->hvac_functions_[4] ? " role" : "")); + ESP_LOGCONFIG(TAG, " Active alarms: %s", buf_to_hex(this->active_alarms_, sizeof(this->active_alarms_)).c_str()); + } +} + +void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { + switch (this->protocol_phase_) { + case ProtocolPhases::SENDING_INIT_1: + if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { + this->hvac_hardware_info_available_ = false; + // Indicate device capabilities: + // bit 0 - if 1 module support interactive mode + // bit 1 - if 1 module support controller-device mode + // bit 2 - if 1 module support crc + // bit 3 - if 1 module support multiple devices + // bit 4..bit 15 - not used + uint8_t module_capabilities[2] = {0b00000000, 0b00000111}; + static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST( + (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, sizeof(module_capabilities)); + this->send_message_(DEVICE_VERSION_REQUEST, this->use_crc_); + this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_1); + } + break; + case ProtocolPhases::SENDING_INIT_2: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static const haier_protocol::HaierMessage DEVICEID_REQUEST((uint8_t) hon_protocol::FrameType::GET_DEVICE_ID); + this->send_message_(DEVICEID_REQUEST, this->use_crc_); + this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_2); + } + break; + case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: + case ProtocolPhases::SENDING_STATUS_REQUEST: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static const haier_protocol::HaierMessage STATUS_REQUEST( + (uint8_t) hon_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcomandsControl::GET_USER_DATA); + this->send_message_(STATUS_REQUEST, this->use_crc_); + this->last_status_request_ = now; + this->set_phase_((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); + } + break; +#ifdef USE_WIFI + case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static const haier_protocol::HaierMessage UPDATE_SIGNAL_REQUEST( + (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION); + this->send_message_(UPDATE_SIGNAL_REQUEST, this->use_crc_); + this->last_signal_request_ = now; + this->set_phase_(ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); + } + break; + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static uint8_t wifi_status_data[4] = {0x00, 0x00, 0x00, 0x00}; + if (wifi::global_wifi_component->is_connected()) { + wifi_status_data[1] = 0; + int8_t rssi = wifi::global_wifi_component->wifi_rssi(); + wifi_status_data[3] = uint8_t((128 + rssi) / 1.28f); + ESP_LOGD(TAG, "WiFi signal is: %ddBm => %d%%", rssi, wifi_status_data[3]); + } else { + ESP_LOGD(TAG, "WiFi is not connected"); + wifi_status_data[1] = 1; + wifi_status_data[3] = 0; + } + haier_protocol::HaierMessage wifi_status_request((uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, + wifi_status_data, sizeof(wifi_status_data)); + this->send_message_(wifi_status_request, this->use_crc_); + this->set_phase_(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + } + break; + case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + break; +#else + case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + this->set_phase_(ProtocolPhases::IDLE); + break; +#endif + case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static const haier_protocol::HaierMessage ALARM_STATUS_REQUEST( + (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS); + this->send_message_(ALARM_STATUS_REQUEST, this->use_crc_); + this->set_phase_(ProtocolPhases::WAITING_ALARM_STATUS_ANSWER); + } + break; + case ProtocolPhases::SENDING_CONTROL: + if (this->first_control_attempt_) { + this->control_request_timestamp_ = now; + this->first_control_attempt_ = false; + } + if (this->is_control_message_timeout_exceeded_(now)) { + ESP_LOGW(TAG, "Sending control packet timeout!"); + this->set_force_send_control_(false); + if (this->hvac_settings_.valid) + this->hvac_settings_.reset(); + this->forced_request_status_ = true; + this->forced_publish_ = true; + this->set_phase_(ProtocolPhases::IDLE); + } else if (this->can_send_message() && this->is_control_message_interval_exceeded_(now)) { + haier_protocol::HaierMessage control_message = get_control_message(); + this->send_message_(control_message, this->use_crc_); + ESP_LOGI(TAG, "Control packet sent"); + this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + } + break; + case ProtocolPhases::SENDING_POWER_ON_COMMAND: + case ProtocolPhases::SENDING_POWER_OFF_COMMAND: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + uint8_t pwr_cmd_buf[2] = {0x00, 0x00}; + if (this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND) + pwr_cmd_buf[1] = 0x01; + haier_protocol::HaierMessage power_cmd((uint8_t) hon_protocol::FrameType::CONTROL, + ((uint16_t) hon_protocol::SubcomandsControl::SET_SINGLE_PARAMETER) + 1, + pwr_cmd_buf, sizeof(pwr_cmd_buf)); + this->send_message_(power_cmd, this->use_crc_); + this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + } + break; + + case ProtocolPhases::WAITING_ANSWER_INIT_1: + case ProtocolPhases::WAITING_ANSWER_INIT_2: + case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: + case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: + case ProtocolPhases::WAITING_STATUS_ANSWER: + case ProtocolPhases::WAITING_CONTROL_ANSWER: + case ProtocolPhases::WAITING_POWER_ON_ANSWER: + case ProtocolPhases::WAITING_POWER_OFF_ANSWER: + break; + case ProtocolPhases::IDLE: { + if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { + this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->forced_request_status_ = false; + } +#ifdef USE_WIFI + else if (this->send_wifi_signal_ && + (std::chrono::duration_cast(now - this->last_signal_request_).count() > + SIGNAL_LEVEL_UPDATE_INTERVAL_MS)) + this->set_phase_(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); +#endif + } break; + default: + // Shouldn't get here +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGE(TAG, "Wrong protocol handler state: %s (%d), resetting communication", + phase_to_string_(this->protocol_phase_), (int) this->protocol_phase_); +#else + ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); +#endif + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + break; + } +} + +haier_protocol::HaierMessage HonClimate::get_control_message() { + uint8_t control_out_buffer[sizeof(hon_protocol::HaierPacketControl)]; + memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(hon_protocol::HaierPacketControl)); + hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; + bool has_hvac_settings = false; + if (this->hvac_settings_.valid) { + has_hvac_settings = true; + HvacSettings climate_control; + climate_control = this->hvac_settings_; + if (climate_control.mode.has_value()) { + switch (climate_control.mode.value()) { + case CLIMATE_MODE_OFF: + out_data->ac_power = 0; + break; + case CLIMATE_MODE_AUTO: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::AUTO; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + case CLIMATE_MODE_HEAT: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::HEAT; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + case CLIMATE_MODE_DRY: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + case CLIMATE_MODE_FAN_ONLY: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::FAN; + out_data->fan_mode = this->fan_mode_speed_; // Auto doesn't work in fan only mode + // Disabling boost and eco mode for Fan only + out_data->quiet_mode = 0; + out_data->fast_mode = 0; + break; + case CLIMATE_MODE_COOL: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::COOL; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + default: + ESP_LOGE("Control", "Unsupported climate mode"); + break; + } + } + // Set fan speed, if we are in fan mode, reject auto in fan mode + if (climate_control.fan_mode.has_value()) { + switch (climate_control.fan_mode.value()) { + case CLIMATE_FAN_LOW: + out_data->fan_mode = (uint8_t) hon_protocol::FanMode::FAN_LOW; + break; + case CLIMATE_FAN_MEDIUM: + out_data->fan_mode = (uint8_t) hon_protocol::FanMode::FAN_MID; + break; + case CLIMATE_FAN_HIGH: + out_data->fan_mode = (uint8_t) hon_protocol::FanMode::FAN_HIGH; + break; + case CLIMATE_FAN_AUTO: + if (mode != CLIMATE_MODE_FAN_ONLY) // if we are not in fan only mode + out_data->fan_mode = (uint8_t) hon_protocol::FanMode::FAN_AUTO; + break; + default: + ESP_LOGE("Control", "Unsupported fan mode"); + break; + } + } + // Set swing mode + if (climate_control.swing_mode.has_value()) { + switch (climate_control.swing_mode.value()) { + case CLIMATE_SWING_OFF: + out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); + out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); + break; + case CLIMATE_SWING_VERTICAL: + out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::AUTO; + break; + case CLIMATE_SWING_HORIZONTAL: + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::AUTO; + out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); + break; + case CLIMATE_SWING_BOTH: + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::AUTO; + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::AUTO; + break; + } + } + if (climate_control.target_temperature.has_value()) { + out_data->set_point = + climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + } + if (out_data->ac_power == 0) { + // If AC is off - no presets alowed + out_data->quiet_mode = 0; + out_data->fast_mode = 0; + out_data->sleep_mode = 0; + } else if (climate_control.preset.has_value()) { + switch (climate_control.preset.value()) { + case CLIMATE_PRESET_NONE: + out_data->quiet_mode = 0; + out_data->fast_mode = 0; + out_data->sleep_mode = 0; + break; + case CLIMATE_PRESET_ECO: + // Eco is not supported in Fan only mode + out_data->quiet_mode = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 1 : 0; + out_data->fast_mode = 0; + out_data->sleep_mode = 0; + break; + case CLIMATE_PRESET_BOOST: + out_data->quiet_mode = 0; + // Boost is not supported in Fan only mode + out_data->fast_mode = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 1 : 0; + out_data->sleep_mode = 0; + break; + case CLIMATE_PRESET_AWAY: + out_data->quiet_mode = 0; + out_data->fast_mode = 0; + out_data->sleep_mode = 0; + break; + case CLIMATE_PRESET_SLEEP: + out_data->quiet_mode = 0; + out_data->fast_mode = 0; + out_data->sleep_mode = 1; + break; + default: + ESP_LOGE("Control", "Unsupported preset"); + break; + } + } + } else { + if (out_data->vertical_swing_mode != (uint8_t) hon_protocol::VerticalSwingMode::AUTO) + out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); + if (out_data->horizontal_swing_mode != (uint8_t) hon_protocol::HorizontalSwingMode::AUTO) + out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); + } + out_data->beeper_status = ((!this->beeper_status_) || (!has_hvac_settings)) ? 1 : 0; + control_out_buffer[4] = 0; // This byte should be cleared before setting values + out_data->display_status = this->display_status_ ? 1 : 0; + out_data->health_mode = this->health_mode_ ? 1 : 0; + switch (this->action_request_) { + case ActionRequest::START_SELF_CLEAN: + this->action_request_ = ActionRequest::NO_ACTION; + out_data->self_cleaning_status = 1; + out_data->steri_clean = 0; + out_data->set_point = 0x06; + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; + out_data->light_status = 0; + break; + case ActionRequest::START_STERI_CLEAN: + this->action_request_ = ActionRequest::NO_ACTION; + out_data->self_cleaning_status = 0; + out_data->steri_clean = 1; + out_data->set_point = 0x06; + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; + out_data->light_status = 0; + break; + default: + // No change + break; + } + return haier_protocol::HaierMessage((uint8_t) hon_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcomandsControl::SET_GROUP_PARAMETERS, + control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); +} + +haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { + if (size < sizeof(hon_protocol::HaierStatus)) + return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; + hon_protocol::HaierStatus packet; + if (size < sizeof(hon_protocol::HaierStatus)) + size = sizeof(hon_protocol::HaierStatus); + memcpy(&packet, packet_buffer, size); + if (packet.sensors.error_status != 0) { + ESP_LOGW(TAG, "HVAC error, code=0x%02X", packet.sensors.error_status); + } + if ((this->outdoor_sensor_ != nullptr) && (got_valid_outdoor_temp_ || (packet.sensors.outdoor_temperature > 0))) { + got_valid_outdoor_temp_ = true; + float otemp = (float) (packet.sensors.outdoor_temperature + PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET); + if ((!this->outdoor_sensor_->has_state()) || (this->outdoor_sensor_->get_raw_state() != otemp)) + this->outdoor_sensor_->publish_state(otemp); + } + bool should_publish = false; + { + // Extra modes/presets + optional old_preset = this->preset; + if (packet.control.quiet_mode != 0) { + this->preset = CLIMATE_PRESET_ECO; + } else if (packet.control.fast_mode != 0) { + this->preset = CLIMATE_PRESET_BOOST; + } else if (packet.control.sleep_mode != 0) { + this->preset = CLIMATE_PRESET_SLEEP; + } else { + this->preset = CLIMATE_PRESET_NONE; + } + should_publish = should_publish || (!old_preset.has_value()) || (old_preset.value() != this->preset.value()); + } + { + // Target temperature + float old_target_temperature = this->target_temperature; + this->target_temperature = packet.control.set_point + 16.0f; + should_publish = should_publish || (old_target_temperature != this->target_temperature); + } + { + // Current temperature + float old_current_temperature = this->current_temperature; + this->current_temperature = packet.sensors.room_temperature / 2.0f; + should_publish = should_publish || (old_current_temperature != this->current_temperature); + } + { + // Fan mode + optional old_fan_mode = this->fan_mode; + // remember the fan speed we last had for climate vs fan + if (packet.control.ac_mode == (uint8_t) hon_protocol::ConditioningMode::FAN) { + if (packet.control.fan_mode != (uint8_t) hon_protocol::FanMode::FAN_AUTO) + this->fan_mode_speed_ = packet.control.fan_mode; + } else { + this->other_modes_fan_speed_ = packet.control.fan_mode; + } + switch (packet.control.fan_mode) { + case (uint8_t) hon_protocol::FanMode::FAN_AUTO: + if (packet.control.ac_mode != (uint8_t) hon_protocol::ConditioningMode::FAN) { + this->fan_mode = CLIMATE_FAN_AUTO; + } else { + // Shouldn't accept fan speed auto in fan-only mode even if AC reports it + ESP_LOGI(TAG, "Fan speed Auto is not supported in Fan only AC mode, ignoring"); + } + break; + case (uint8_t) hon_protocol::FanMode::FAN_MID: + this->fan_mode = CLIMATE_FAN_MEDIUM; + break; + case (uint8_t) hon_protocol::FanMode::FAN_LOW: + this->fan_mode = CLIMATE_FAN_LOW; + break; + case (uint8_t) hon_protocol::FanMode::FAN_HIGH: + this->fan_mode = CLIMATE_FAN_HIGH; + break; + } + should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value()); + } + { + // Display status + // should be before "Climate mode" because it is changing this->mode + if (packet.control.ac_power != 0) { + // if AC is off display status always ON so process it only when AC is on + bool disp_status = packet.control.display_status != 0; + if (disp_status != this->display_status_) { + // Do something only if display status changed + if (this->mode == CLIMATE_MODE_OFF) { + // AC just turned on from remote need to turn off display + this->set_force_send_control_(true); + } else { + this->display_status_ = disp_status; + } + } + } + } + { + // Health mode + bool old_health_mode = this->health_mode_; + this->health_mode_ = packet.control.health_mode == 1; + should_publish = should_publish || (old_health_mode != this->health_mode_); + } + { + CleaningState new_cleaning; + if (packet.control.steri_clean == 1) { + // Steri-cleaning + new_cleaning = CleaningState::STERI_CLEAN; + } else if (packet.control.self_cleaning_status == 1) { + // Self-cleaning + new_cleaning = CleaningState::SELF_CLEAN; + } else { + // No cleaning + new_cleaning = CleaningState::NO_CLEANING; + } + if (new_cleaning != this->cleaning_status_) { + ESP_LOGD(TAG, "Cleaning status change: %d => %d", (uint8_t) this->cleaning_status_, (uint8_t) new_cleaning); + if (new_cleaning == CleaningState::NO_CLEANING) { + // Turnuin AC off after cleaning + this->action_request_ = ActionRequest::TURN_POWER_OFF; + } + this->cleaning_status_ = new_cleaning; + } + } + { + // Climate mode + ClimateMode old_mode = this->mode; + if (packet.control.ac_power == 0) { + this->mode = CLIMATE_MODE_OFF; + } else { + // Check current hvac mode + switch (packet.control.ac_mode) { + case (uint8_t) hon_protocol::ConditioningMode::COOL: + this->mode = CLIMATE_MODE_COOL; + break; + case (uint8_t) hon_protocol::ConditioningMode::HEAT: + this->mode = CLIMATE_MODE_HEAT; + break; + case (uint8_t) hon_protocol::ConditioningMode::DRY: + this->mode = CLIMATE_MODE_DRY; + break; + case (uint8_t) hon_protocol::ConditioningMode::FAN: + this->mode = CLIMATE_MODE_FAN_ONLY; + break; + case (uint8_t) hon_protocol::ConditioningMode::AUTO: + this->mode = CLIMATE_MODE_AUTO; + break; + } + } + should_publish = should_publish || (old_mode != this->mode); + } + { + // Swing mode + ClimateSwingMode old_swing_mode = this->swing_mode; + if (packet.control.horizontal_swing_mode == (uint8_t) hon_protocol::HorizontalSwingMode::AUTO) { + if (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO) { + this->swing_mode = CLIMATE_SWING_BOTH; + } else { + this->swing_mode = CLIMATE_SWING_HORIZONTAL; + } + } else { + if (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO) { + this->swing_mode = CLIMATE_SWING_VERTICAL; + } else { + this->swing_mode = CLIMATE_SWING_OFF; + } + } + should_publish = should_publish || (old_swing_mode != this->swing_mode); + } + this->last_valid_status_timestamp_ = std::chrono::steady_clock::now(); + if (this->forced_publish_ || should_publish) { +#if (HAIER_LOG_LEVEL > 4) + std::chrono::high_resolution_clock::time_point _publish_start = std::chrono::high_resolution_clock::now(); +#endif + this->publish_state(); +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGV(TAG, "Publish delay: %lld ms", + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - + _publish_start) + .count()); +#endif + this->forced_publish_ = false; + } + if (should_publish) { + ESP_LOGI(TAG, "HVAC values changed"); + } + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "HVAC Mode = 0x%X", packet.control.ac_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Fan speed Status = 0x%X", packet.control.fan_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Horizontal Swing Status = 0x%X", packet.control.horizontal_swing_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Vertical Swing Status = 0x%X", packet.control.vertical_swing_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Set Point Status = 0x%X", packet.control.set_point); + return haier_protocol::HandlerError::HANDLER_OK; +} + +bool HonClimate::is_message_invalid(uint8_t message_type) { + return message_type == (uint8_t) hon_protocol::FrameType::INVALID; +} + +void HonClimate::process_pending_action() { + switch (this->action_request_) { + case ActionRequest::START_SELF_CLEAN: + case ActionRequest::START_STERI_CLEAN: + // Will reset action with control message sending + this->set_phase_(ProtocolPhases::SENDING_CONTROL); + break; + default: + HaierClimateBase::process_pending_action(); + break; + } +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h new file mode 100644 index 0000000000..ab913f44e2 --- /dev/null +++ b/esphome/components/haier/hon_climate.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include "esphome/components/sensor/sensor.h" +#include "haier_base.h" + +namespace esphome { +namespace haier { + +enum class AirflowVerticalDirection : uint8_t { + HEALTH_UP = 0, + MAX_UP = 1, + UP = 2, + CENTER = 3, + DOWN = 4, + HEALTH_DOWN = 5, +}; + +enum class AirflowHorizontalDirection : uint8_t { + MAX_LEFT = 0, + LEFT = 1, + CENTER = 2, + RIGHT = 3, + MAX_RIGHT = 4, +}; + +enum class CleaningState : uint8_t { + NO_CLEANING = 0, + SELF_CLEAN = 1, + STERI_CLEAN = 2, +}; + +class HonClimate : public HaierClimateBase { + public: + HonClimate(); + HonClimate(const HonClimate &) = delete; + HonClimate &operator=(const HonClimate &) = delete; + ~HonClimate(); + void dump_config() override; + void set_beeper_state(bool state); + bool get_beeper_state() const; + void set_outdoor_temperature_sensor(esphome::sensor::Sensor *sensor); + AirflowVerticalDirection get_vertical_airflow() const; + void set_vertical_airflow(AirflowVerticalDirection direction); + AirflowHorizontalDirection get_horizontal_airflow() const; + void set_horizontal_airflow(AirflowHorizontalDirection direction); + std::string get_cleaning_status_text() const; + CleaningState get_cleaning_status() const; + void start_self_cleaning(); + void start_steri_cleaning(); + void set_send_wifi(bool send_wifi); + + protected: + void set_answers_handlers() override; + void process_phase(std::chrono::steady_clock::time_point now) override; + haier_protocol::HaierMessage get_control_message() override; + bool is_message_invalid(uint8_t message_type) override; + void process_pending_action() override; + + // Answers handlers + haier_protocol::HandlerError get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_device_id_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, + size_t data_size); + haier_protocol::HandlerError get_management_information_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError report_network_status_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_alarm_status_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + // Helper functions + haier_protocol::HandlerError process_status_message_(const uint8_t *packet, uint8_t size); + std::unique_ptr last_status_message_; + bool beeper_status_; + CleaningState cleaning_status_; + bool got_valid_outdoor_temp_; + AirflowVerticalDirection vertical_direction_; + AirflowHorizontalDirection horizontal_direction_; + bool hvac_hardware_info_available_; + std::string hvac_protocol_version_; + std::string hvac_software_version_; + std::string hvac_hardware_version_; + std::string hvac_device_name_; + bool hvac_functions_[5]; + bool &use_crc_; + uint8_t active_alarms_[8]; + esphome::sensor::Sensor *outdoor_sensor_; + bool send_wifi_signal_; + std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/hon_packet.h b/esphome/components/haier/hon_packet.h new file mode 100644 index 0000000000..d572ce80d9 --- /dev/null +++ b/esphome/components/haier/hon_packet.h @@ -0,0 +1,228 @@ +#pragma once + +#include + +namespace esphome { +namespace haier { +namespace hon_protocol { + +enum class VerticalSwingMode : uint8_t { + HEALTH_UP = 0x01, + MAX_UP = 0x02, + HEALTH_DOWN = 0x03, + UP = 0x04, + CENTER = 0x06, + DOWN = 0x08, + AUTO = 0x0C +}; + +enum class HorizontalSwingMode : uint8_t { + CENTER = 0x00, + MAX_LEFT = 0x03, + LEFT = 0x04, + RIGHT = 0x05, + MAX_RIGHT = 0x06, + AUTO = 0x07 +}; + +enum class ConditioningMode : uint8_t { + AUTO = 0x00, + COOL = 0x01, + DRY = 0x02, + HEALTHY_DRY = 0x03, + HEAT = 0x04, + ENERGY_SAVING = 0x05, + FAN = 0x06 +}; + +enum class SpecialMode : uint8_t { NONE = 0x00, ELDERLY = 0x01, CHILDREN = 0x02, PREGNANT = 0x03 }; + +enum class FanMode : uint8_t { FAN_HIGH = 0x01, FAN_MID = 0x02, FAN_LOW = 0x03, FAN_AUTO = 0x05 }; + +struct HaierPacketControl { + // Control bytes starts here + // 10 + uint8_t set_point; // Target temperature with 16°C offset (0x00 = 16°C) + // 11 + uint8_t vertical_swing_mode : 4; // See enum VerticalSwingMode + uint8_t : 0; + // 12 + uint8_t fan_mode : 3; // See enum FanMode + uint8_t special_mode : 2; // See enum SpecialMode + uint8_t ac_mode : 3; // See enum ConditioningMode + // 13 + uint8_t : 8; + // 14 + uint8_t ten_degree : 1; // 10 degree status + uint8_t display_status : 1; // If 0 disables AC's display + uint8_t half_degree : 1; // Use half degree + uint8_t intelegence_status : 1; // Intelligence status + uint8_t pmv_status : 1; // Comfort/PMV status + uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius + uint8_t : 1; + uint8_t steri_clean : 1; + // 15 + uint8_t ac_power : 1; // Is ac on or off + uint8_t health_mode : 1; // Health mode (negative ions) on or off + uint8_t electric_heating_status : 1; // Electric heating status + uint8_t fast_mode : 1; // Fast mode + uint8_t quiet_mode : 1; // Quiet mode + uint8_t sleep_mode : 1; // Sleep mode + uint8_t lock_remote : 1; // Disable remote + uint8_t beeper_status : 1; // If 1 disables AC's command feedback beeper (need to be set on every control command) + // 16 + uint8_t target_humidity; // Target humidity (0=30% .. 3C=90%, step = 1%) + // 17 + uint8_t horizontal_swing_mode : 3; // See enum HorizontalSwingMode + uint8_t : 3; + uint8_t human_sensing_status : 2; // Human sensing status + // 18 + uint8_t change_filter : 1; // Filter need replacement + uint8_t : 0; + // 19 + uint8_t fresh_air_status : 1; // Fresh air status + uint8_t humidification_status : 1; // Humidification status + uint8_t pm2p5_cleaning_status : 1; // PM2.5 cleaning status + uint8_t ch2o_cleaning_status : 1; // CH2O cleaning status + uint8_t self_cleaning_status : 1; // Self cleaning status + uint8_t light_status : 1; // Light status + uint8_t energy_saving_status : 1; // Energy saving status + uint8_t cleaning_time_status : 1; // Cleaning time (0 - accumulation, 1 - clear) +}; + +struct HaierPacketSensors { + // 20 + uint8_t room_temperature; // 0.5°C step + // 21 + uint8_t room_humidity; // 0%-100% with 1% step + // 22 + uint8_t outdoor_temperature; // 1°C step, -64°C offset (0=-64°C) + // 23 + uint8_t pm2p5_level : 2; // Indoor PM2.5 grade (00: Excellent, 01: good, 02: Medium, 03: Bad) + uint8_t air_quality : 2; // Air quality grade (00: Excellent, 01: good, 02: Medium, 03: Bad) + uint8_t human_sensing : 2; // Human presence result (00: N/A, 01: not detected, 02: One, 03: Multiple) + uint8_t : 1; + uint8_t ac_type : 1; // 00 - Heat and cool, 01 - Cool only) + // 24 + uint8_t error_status; // See enum ErrorStatus + // 25 + uint8_t operation_source : 2; // who is controlling AC (00: Other, 01: Remote control, 02: Button, 03: ESP) + uint8_t operation_mode_hk : 2; // Homekit only, operation mode (00: Cool, 01: Dry, 02: Heat, 03: Fan) + uint8_t : 3; + uint8_t err_confirmation : 1; // If 1 clear error status + // 26 + uint16_t total_cleaning_time; // Cleaning cumulative time (1h step) + // 28 + uint16_t indoor_pm2p5_value; // Indoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step) + // 30 + uint16_t outdoor_pm2p5_value; // Outdoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step) + // 32 + uint16_t ch2o_value; // Formaldehyde value (0 ug/m3 - 10000 ug/m3, 1 ug/m3 step) + // 34 + uint16_t voc_value; // VOC value (Volatile Organic Compounds) (0 ug/m3 - 1023 ug/m3, 1 ug/m3 step) + // 36 + uint16_t co2_value; // CO2 value (0 PPM - 10000 PPM, 1 PPM step) +}; + +struct HaierStatus { + uint16_t subcommand; + HaierPacketControl control; + HaierPacketSensors sensors; +}; + +struct DeviceVersionAnswer { + char protocol_version[8]; + char software_version[8]; + uint8_t encryption[3]; + char hardware_version[8]; + uint8_t : 8; + char device_name[8]; + uint8_t functions[2]; +}; + +// In this section comments: +// - module is the ESP32 control module (communication module in Haier protocol document) +// - device is the conditioner control board (network appliances in Haier protocol document) +enum class FrameType : uint8_t { + CONTROL = 0x01, // Requests or sets one or multiple parameters (module <-> device, required) + STATUS = 0x02, // Contains one or multiple parameters values, usually answer to control frame (module <-> device, + // required) + INVALID = 0x03, // Communication error indication (module <-> device, required) + ALARM_STATUS = 0x04, // Alarm status report (module <-> device, interactive, required) + CONFIRM = 0x05, // Acknowledgment, usually used to confirm reception of frame if there is no special answer (module + // <-> device, required) + REPORT = 0x06, // Report frame (module <-> device, interactive, required) + STOP_FAULT_ALARM = 0x09, // Stop fault alarm frame (module -> device, interactive, required) + SYSTEM_DOWNLIK = 0x11, // System downlink frame (module -> device, optional) + DEVICE_UPLINK = 0x12, // Device uplink frame (module <- device , interactive, optional) + SYSTEM_QUERY = 0x13, // System query frame (module -> device, optional) + SYSTEM_QUERY_RESPONSE = 0x14, // System query response frame (module <- device , optional) + DEVICE_QUERY = 0x15, // Device query frame (module <- device, optional) + DEVICE_QUERY_RESPONSE = 0x16, // Device query response frame (module -> device, optional) + GROUP_COMMAND = 0x60, // Group command frame (module -> device, interactive, optional) + GET_DEVICE_VERSION = 0x61, // Requests device version (module -> device, required) + GET_DEVICE_VERSION_RESPONSE = 0x62, // Device version answer (module <- device, required_ + GET_ALL_ADDRESSES = 0x67, // Requests all devices addresses (module -> device, interactive, optional) + GET_ALL_ADDRESSES_RESPONSE = + 0x68, // Answer to request of all devices addresses (module <- device , interactive, optional) + HANDSET_CHANGE_NOTIFICATION = 0x69, // Handset change notification frame (module <- device , interactive, optional) + GET_DEVICE_ID = 0x70, // Requests Device ID (module -> device, required) + GET_DEVICE_ID_RESPONSE = 0x71, // Response to device ID request (module <- device , required) + GET_ALARM_STATUS = 0x73, // Alarm status request (module -> device, required) + GET_ALARM_STATUS_RESPONSE = 0x74, // Response to alarm status request (module <- device, required) + GET_DEVICE_CONFIGURATION = 0x7C, // Requests device configuration (module -> device, interactive, required) + GET_DEVICE_CONFIGURATION_RESPONSE = + 0x7D, // Response to device configuration request (module <- device, interactive, required) + DOWNLINK_TRANSPARENT_TRANSMISSION = 0x8C, // Downlink transparent transmission (proxy data Haier cloud -> device) + // (module -> device, interactive, optional) + UPLINK_TRANSPARENT_TRANSMISSION = 0x8D, // Uplink transparent transmission (proxy data device -> Haier cloud) (module + // <- device, interactive, optional) + START_DEVICE_UPGRADE = 0xE1, // Initiate device OTA upgrade (module -> device, OTA required) + START_DEVICE_UPGRADE_RESPONSE = 0xE2, // Response to initiate device upgrade command (module <- device, OTA required) + GET_FIRMWARE_CONTENT = 0xE5, // Requests to send firmware (module <- device, OTA required) + GET_FIRMWARE_CONTENT_RESPONSE = + 0xE6, // Response to send firmware request (module -> device, OTA required) (multipacket?) + CHANGE_BAUD_RATE = 0xE7, // Requests to change port baud rate (module <- device, OTA required) + CHANGE_BAUD_RATE_RESPONSE = 0xE8, // Response to change port baud rate request (module -> device, OTA required) + GET_SUBBOARD_INFO = 0xE9, // Requests subboard information (module -> device, required) + GET_SUBBOARD_INFO_RESPONSE = 0xEA, // Response to subboard information request (module <- device, required) + GET_HARDWARE_INFO = 0xEB, // Requests information about device and subboard (module -> device, required) + GET_HARDWARE_INFO_RESPONSE = 0xEC, // Response to hardware information request (module <- device, required) + GET_UPGRADE_RESULT = 0xED, // Requests result of the firmware update (module <- device, OTA required) + GET_UPGRADE_RESULT_RESPONSE = 0xEF, // Response to firmware update results request (module -> device, OTA required) + GET_NETWORK_STATUS = 0xF0, // Requests network status (module <- device, interactive, optional) + GET_NETWORK_STATUS_RESPONSE = 0xF1, // Response to network status request (module -> device, interactive, optional) + START_WIFI_CONFIGURATION = 0xF2, // Starts WiFi configuration procedure (module <- device, interactive, required) + START_WIFI_CONFIGURATION_RESPONSE = + 0xF3, // Response to start WiFi configuration request (module -> device, interactive, required) + STOP_WIFI_CONFIGURATION = 0xF4, // Stop WiFi configuration procedure (module <- device, interactive, required) + STOP_WIFI_CONFIGURATION_RESPONSE = + 0xF5, // Response to stop WiFi configuration request (module -> device, interactive, required) + REPORT_NETWORK_STATUS = 0xF7, // Reports network status (module -> device, required) + CLEAR_CONFIGURATION = 0xF8, // Request to clear module configuration (module <- device, interactive, optional) + BIG_DATA_REPORT_CONFIGURATION = + 0xFA, // Configuration for autoreport device full status (module -> device, interactive, optional) + BIG_DATA_REPORT_CONFIGURATION_RESPONSE = + 0xFB, // Response to set big data configuration (module <- device, interactive, optional) + GET_MANAGEMENT_INFORMATION = 0xFC, // Request management information from device (module -> device, required) + GET_MANAGEMENT_INFORMATION_RESPONSE = + 0xFD, // Response to management information request (module <- device, required) + WAKE_UP = 0xFE, // Request to wake up (module <-> device, optional) +}; + +enum class SubcomandsControl : uint16_t { + GET_PARAMETERS = 0x4C01, // Request specific parameters (packet content: parameter ID1 + parameter ID2 + ...) + GET_USER_DATA = 0x4D01, // Request all user data from device (packet content: None) + GET_BIG_DATA = 0x4DFE, // Request big data information from device (packet content: None) + SET_PARAMETERS = 0x5C01, // Set parameters of the device and device return parameters (packet content: parameter ID1 + // + parameter data1 + parameter ID2 + parameter data 2 + ...) + SET_SINGLE_PARAMETER = 0x5D00, // Set single parameter (0x5DXX second byte define parameter ID) and return all user + // data (packet content: ???) + SET_GROUP_PARAMETERS = 0x6001, // Set group parameters to device (0x60XX second byte define parameter is group ID, + // the only group mentioned in document is 1) and return all user data (packet + // content: all values like in status packet) +}; + +} // namespace hon_protocol +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/logger_handler.cpp b/esphome/components/haier/logger_handler.cpp new file mode 100644 index 0000000000..f886318097 --- /dev/null +++ b/esphome/components/haier/logger_handler.cpp @@ -0,0 +1,33 @@ +#include "logger_handler.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace haier { + +void esphome_logger(haier_protocol::HaierLogLevel level, const char *tag, const char *message) { + switch (level) { + case haier_protocol::HaierLogLevel::LEVEL_ERROR: + esp_log_printf_(ESPHOME_LOG_LEVEL_ERROR, tag, __LINE__, "%s", message); + break; + case haier_protocol::HaierLogLevel::LEVEL_WARNING: + esp_log_printf_(ESPHOME_LOG_LEVEL_WARN, tag, __LINE__, "%s", message); + break; + case haier_protocol::HaierLogLevel::LEVEL_INFO: + esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, tag, __LINE__, "%s", message); + break; + case haier_protocol::HaierLogLevel::LEVEL_DEBUG: + esp_log_printf_(ESPHOME_LOG_LEVEL_DEBUG, tag, __LINE__, "%s", message); + break; + case haier_protocol::HaierLogLevel::LEVEL_VERBOSE: + esp_log_printf_(ESPHOME_LOG_LEVEL_VERBOSE, tag, __LINE__, "%s", message); + break; + default: + // Just ignore everything else + break; + } +} + +void init_haier_protocol_logging() { haier_protocol::set_log_handler(esphome::haier::esphome_logger); }; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/logger_handler.h b/esphome/components/haier/logger_handler.h new file mode 100644 index 0000000000..2955468f37 --- /dev/null +++ b/esphome/components/haier/logger_handler.h @@ -0,0 +1,14 @@ +#pragma once + +// HaierProtocol +#include + +namespace esphome { +namespace haier { + +// This file is called in the code generated by python script +// Do not use it directly! +void init_haier_protocol_logging(); + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp new file mode 100644 index 0000000000..9c0fbac350 --- /dev/null +++ b/esphome/components/haier/smartair2_climate.cpp @@ -0,0 +1,457 @@ +#include +#include "esphome/components/climate/climate.h" +#include "esphome/components/uart/uart.h" +#include "smartair2_climate.h" +#include "smartair2_packet.h" + +using namespace esphome::climate; +using namespace esphome::uart; + +namespace esphome { +namespace haier { + +static const char *const TAG = "haier.climate"; + +Smartair2Climate::Smartair2Climate() + : last_status_message_(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]) { + this->traits_.set_supported_presets({ + climate::CLIMATE_PRESET_NONE, + climate::CLIMATE_PRESET_BOOST, + climate::CLIMATE_PRESET_COMFORT, + }); +} + +haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size) { + haier_protocol::HandlerError result = + this->answer_preprocess_(request_type, (uint8_t) smartair2_protocol::FrameType::CONTROL, message_type, + (uint8_t) smartair2_protocol::FrameType::STATUS, ProtocolPhases::UNKNOWN); + if (result == haier_protocol::HandlerError::HANDLER_OK) { + result = this->process_status_message_(data, data_size); + if (result != haier_protocol::HandlerError::HANDLER_OK) { + ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + } else { + if (data_size >= sizeof(smartair2_protocol::HaierPacketControl) + 2) { + memcpy(this->last_status_message_.get(), data + 2, sizeof(smartair2_protocol::HaierPacketControl)); + } else { + ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, + sizeof(smartair2_protocol::HaierPacketControl)); + } + if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { + ESP_LOGI(TAG, "First HVAC status received"); + this->set_phase_(ProtocolPhases::IDLE); + } else if (this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) { + this->set_phase_(ProtocolPhases::IDLE); + } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { + this->set_phase_(ProtocolPhases::IDLE); + this->set_force_send_control_(false); + if (this->hvac_settings_.valid) + this->hvac_settings_.reset(); + } + } + return result; + } else { + this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + return result; + } +} + +void Smartair2Climate::set_answers_handlers() { + this->haier_protocol_.set_answer_handler( + (uint8_t) (smartair2_protocol::FrameType::CONTROL), + std::bind(&Smartair2Climate::status_handler_, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); +} + +void Smartair2Climate::dump_config() { + HaierClimateBase::dump_config(); + ESP_LOGCONFIG(TAG, " Protocol version: smartAir2"); +} + +void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) { + switch (this->protocol_phase_) { + case ProtocolPhases::SENDING_INIT_1: + this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + break; + case ProtocolPhases::WAITING_ANSWER_INIT_1: + case ProtocolPhases::SENDING_INIT_2: + case ProtocolPhases::WAITING_ANSWER_INIT_2: + case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: + case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: + this->set_phase_(ProtocolPhases::SENDING_INIT_1); + break; + case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: + case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + this->set_phase_(ProtocolPhases::IDLE); + break; + case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: + if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { + static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, + 0x4D01); + this->send_message_(STATUS_REQUEST, false); + this->last_status_request_ = now; + this->set_phase_(ProtocolPhases::WAITING_FIRST_STATUS_ANSWER); + } + break; + case ProtocolPhases::SENDING_STATUS_REQUEST: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, + 0x4D01); + this->send_message_(STATUS_REQUEST, false); + this->last_status_request_ = now; + this->set_phase_(ProtocolPhases::WAITING_STATUS_ANSWER); + } + break; + case ProtocolPhases::SENDING_CONTROL: + if (this->first_control_attempt_) { + this->control_request_timestamp_ = now; + this->first_control_attempt_ = false; + } + if (this->is_control_message_timeout_exceeded_(now)) { + ESP_LOGW(TAG, "Sending control packet timeout!"); + this->set_force_send_control_(false); + if (this->hvac_settings_.valid) + this->hvac_settings_.reset(); + this->forced_request_status_ = true; + this->forced_publish_ = true; + this->set_phase_(ProtocolPhases::IDLE); + } else if (this->can_send_message() && this->is_control_message_interval_exceeded_( + now)) // Using CONTROL_MESSAGES_INTERVAL_MS to speedup requests + { + haier_protocol::HaierMessage control_message = get_control_message(); + this->send_message_(control_message, false); + ESP_LOGI(TAG, "Control packet sent"); + this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + } + break; + case ProtocolPhases::SENDING_POWER_ON_COMMAND: + case ProtocolPhases::SENDING_POWER_OFF_COMMAND: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + haier_protocol::HaierMessage power_cmd( + (uint8_t) smartair2_protocol::FrameType::CONTROL, + this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND ? 0x4D02 : 0x4D03); + this->send_message_(power_cmd, false); + this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + } + break; + case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: + case ProtocolPhases::WAITING_STATUS_ANSWER: + case ProtocolPhases::WAITING_CONTROL_ANSWER: + case ProtocolPhases::WAITING_POWER_ON_ANSWER: + case ProtocolPhases::WAITING_POWER_OFF_ANSWER: + break; + case ProtocolPhases::IDLE: { + if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { + this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->forced_request_status_ = false; + } + } break; + default: + // Shouldn't get here + ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); + this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + break; + } +} + +haier_protocol::HaierMessage Smartair2Climate::get_control_message() { + uint8_t control_out_buffer[sizeof(smartair2_protocol::HaierPacketControl)]; + memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(smartair2_protocol::HaierPacketControl)); + smartair2_protocol::HaierPacketControl *out_data = (smartair2_protocol::HaierPacketControl *) control_out_buffer; + out_data->cntrl = 0; + if (this->hvac_settings_.valid) { + HvacSettings climate_control; + climate_control = this->hvac_settings_; + if (climate_control.mode.has_value()) { + switch (climate_control.mode.value()) { + case CLIMATE_MODE_OFF: + out_data->ac_power = 0; + break; + + case CLIMATE_MODE_AUTO: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::AUTO; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + + case CLIMATE_MODE_HEAT: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::HEAT; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + + case CLIMATE_MODE_DRY: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::DRY; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + + case CLIMATE_MODE_FAN_ONLY: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::FAN; + out_data->fan_mode = this->fan_mode_speed_; // Auto doesn't work in fan only mode + break; + + case CLIMATE_MODE_COOL: + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::COOL; + out_data->fan_mode = this->other_modes_fan_speed_; + break; + default: + ESP_LOGE("Control", "Unsupported climate mode"); + break; + } + } + // Set fan speed, if we are in fan mode, reject auto in fan mode + if (climate_control.fan_mode.has_value()) { + switch (climate_control.fan_mode.value()) { + case CLIMATE_FAN_LOW: + out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_LOW; + break; + case CLIMATE_FAN_MEDIUM: + out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_MID; + break; + case CLIMATE_FAN_HIGH: + out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_HIGH; + break; + case CLIMATE_FAN_AUTO: + if (this->mode != CLIMATE_MODE_FAN_ONLY) // if we are not in fan only mode + out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_AUTO; + break; + default: + ESP_LOGE("Control", "Unsupported fan mode"); + break; + } + } + // Set swing mode + if (climate_control.swing_mode.has_value()) { + switch (climate_control.swing_mode.value()) { + case CLIMATE_SWING_OFF: + out_data->use_swing_bits = 0; + out_data->swing_both = 0; + break; + case CLIMATE_SWING_VERTICAL: + out_data->swing_both = 0; + out_data->vertical_swing = 1; + out_data->horizontal_swing = 0; + break; + case CLIMATE_SWING_HORIZONTAL: + out_data->swing_both = 0; + out_data->vertical_swing = 0; + out_data->horizontal_swing = 1; + break; + case CLIMATE_SWING_BOTH: + out_data->swing_both = 1; + out_data->use_swing_bits = 0; + out_data->vertical_swing = 0; + out_data->horizontal_swing = 0; + break; + } + } + if (climate_control.target_temperature.has_value()) { + out_data->set_point = + climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + } + if (out_data->ac_power == 0) { + // If AC is off - no presets alowed + out_data->turbo_mode = 0; + out_data->quiet_mode = 0; + } else if (climate_control.preset.has_value()) { + switch (climate_control.preset.value()) { + case CLIMATE_PRESET_NONE: + out_data->turbo_mode = 0; + out_data->quiet_mode = 0; + break; + case CLIMATE_PRESET_BOOST: + out_data->turbo_mode = 1; + out_data->quiet_mode = 0; + break; + case CLIMATE_PRESET_COMFORT: + out_data->turbo_mode = 0; + out_data->quiet_mode = 1; + break; + default: + ESP_LOGE("Control", "Unsupported preset"); + out_data->turbo_mode = 0; + out_data->quiet_mode = 0; + break; + } + } + } + out_data->display_status = this->display_status_ ? 0 : 1; + out_data->health_mode = this->health_mode_ ? 1 : 0; + return haier_protocol::HaierMessage((uint8_t) smartair2_protocol::FrameType::CONTROL, 0x4D5F, control_out_buffer, + sizeof(smartair2_protocol::HaierPacketControl)); +} + +haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { + if (size < sizeof(smartair2_protocol::HaierStatus)) + return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; + smartair2_protocol::HaierStatus packet; + memcpy(&packet, packet_buffer, size); + bool should_publish = false; + { + // Extra modes/presets + optional old_preset = this->preset; + if (packet.control.turbo_mode != 0) { + this->preset = CLIMATE_PRESET_BOOST; + } else if (packet.control.quiet_mode != 0) { + this->preset = CLIMATE_PRESET_COMFORT; + } else { + this->preset = CLIMATE_PRESET_NONE; + } + should_publish = should_publish || (!old_preset.has_value()) || (old_preset.value() != this->preset.value()); + } + { + // Target temperature + float old_target_temperature = this->target_temperature; + this->target_temperature = packet.control.set_point + 16.0f; + should_publish = should_publish || (old_target_temperature != this->target_temperature); + } + { + // Current temperature + float old_current_temperature = this->current_temperature; + this->current_temperature = packet.control.room_temperature; + should_publish = should_publish || (old_current_temperature != this->current_temperature); + } + { + // Fan mode + optional old_fan_mode = this->fan_mode; + // remember the fan speed we last had for climate vs fan + if (packet.control.ac_mode == (uint8_t) smartair2_protocol::ConditioningMode::FAN) { + if (packet.control.fan_mode != (uint8_t) smartair2_protocol::FanMode::FAN_AUTO) + this->fan_mode_speed_ = packet.control.fan_mode; + } else { + this->other_modes_fan_speed_ = packet.control.fan_mode; + } + switch (packet.control.fan_mode) { + case (uint8_t) smartair2_protocol::FanMode::FAN_AUTO: + // Somtimes AC reports in fan only mode that fan speed is auto + // but never accept this value back + if (packet.control.ac_mode != (uint8_t) smartair2_protocol::ConditioningMode::FAN) { + this->fan_mode = CLIMATE_FAN_AUTO; + } else { + should_publish = true; + } + break; + case (uint8_t) smartair2_protocol::FanMode::FAN_MID: + this->fan_mode = CLIMATE_FAN_MEDIUM; + break; + case (uint8_t) smartair2_protocol::FanMode::FAN_LOW: + this->fan_mode = CLIMATE_FAN_LOW; + break; + case (uint8_t) smartair2_protocol::FanMode::FAN_HIGH: + this->fan_mode = CLIMATE_FAN_HIGH; + break; + } + should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value()); + } + { + // Display status + // should be before "Climate mode" because it is changing this->mode + if (packet.control.ac_power != 0) { + // if AC is off display status always ON so process it only when AC is on + bool disp_status = packet.control.display_status == 0; + if (disp_status != this->display_status_) { + // Do something only if display status changed + if (this->mode == CLIMATE_MODE_OFF) { + // AC just turned on from remote need to turn off display + this->set_force_send_control_(true); + } else { + this->display_status_ = disp_status; + } + } + } + } + { + // Climate mode + ClimateMode old_mode = this->mode; + if (packet.control.ac_power == 0) { + this->mode = CLIMATE_MODE_OFF; + } else { + // Check current hvac mode + switch (packet.control.ac_mode) { + case (uint8_t) smartair2_protocol::ConditioningMode::COOL: + this->mode = CLIMATE_MODE_COOL; + break; + case (uint8_t) smartair2_protocol::ConditioningMode::HEAT: + this->mode = CLIMATE_MODE_HEAT; + break; + case (uint8_t) smartair2_protocol::ConditioningMode::DRY: + this->mode = CLIMATE_MODE_DRY; + break; + case (uint8_t) smartair2_protocol::ConditioningMode::FAN: + this->mode = CLIMATE_MODE_FAN_ONLY; + break; + case (uint8_t) smartair2_protocol::ConditioningMode::AUTO: + this->mode = CLIMATE_MODE_AUTO; + break; + } + } + should_publish = should_publish || (old_mode != this->mode); + } + { + // Health mode + bool old_health_mode = this->health_mode_; + this->health_mode_ = packet.control.health_mode == 1; + should_publish = should_publish || (old_health_mode != this->health_mode_); + } + { + // Swing mode + ClimateSwingMode old_swing_mode = this->swing_mode; + if (packet.control.swing_both == 0) { + if (packet.control.vertical_swing != 0) { + this->swing_mode = CLIMATE_SWING_VERTICAL; + } else if (packet.control.horizontal_swing != 0) { + this->swing_mode = CLIMATE_SWING_HORIZONTAL; + } else { + this->swing_mode = CLIMATE_SWING_OFF; + } + } else { + swing_mode = CLIMATE_SWING_BOTH; + } + should_publish = should_publish || (old_swing_mode != this->swing_mode); + } + this->last_valid_status_timestamp_ = std::chrono::steady_clock::now(); + if (this->forced_publish_ || should_publish) { +#if (HAIER_LOG_LEVEL > 4) + std::chrono::high_resolution_clock::time_point _publish_start = std::chrono::high_resolution_clock::now(); +#endif + this->publish_state(); +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGV(TAG, "Publish delay: %lld ms", + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - + _publish_start) + .count()); +#endif + this->forced_publish_ = false; + } + if (should_publish) { + ESP_LOGI(TAG, "HVAC values changed"); + } + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "HVAC Mode = 0x%X", packet.control.ac_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Fan speed Status = 0x%X", packet.control.fan_mode); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Horizontal Swing Status = 0x%X", packet.control.horizontal_swing); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Vertical Swing Status = 0x%X", packet.control.vertical_swing); + esp_log_printf_((should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG), TAG, __LINE__, + "Set Point Status = 0x%X", packet.control.set_point); + return haier_protocol::HandlerError::HANDLER_OK; +} + +bool Smartair2Climate::is_message_invalid(uint8_t message_type) { + return message_type == (uint8_t) smartair2_protocol::FrameType::INVALID; +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/smartair2_climate.h b/esphome/components/haier/smartair2_climate.h new file mode 100644 index 0000000000..c89d1f0be9 --- /dev/null +++ b/esphome/components/haier/smartair2_climate.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "haier_base.h" + +namespace esphome { +namespace haier { + +class Smartair2Climate : public HaierClimateBase { + public: + Smartair2Climate(); + Smartair2Climate(const Smartair2Climate &) = delete; + Smartair2Climate &operator=(const Smartair2Climate &) = delete; + ~Smartair2Climate(); + void dump_config() override; + + protected: + void set_answers_handlers() override; + void process_phase(std::chrono::steady_clock::time_point now) override; + haier_protocol::HaierMessage get_control_message() override; + bool is_message_invalid(uint8_t message_type) override; + // Answers handlers + haier_protocol::HandlerError status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, + size_t data_size); + // Helper functions + haier_protocol::HandlerError process_status_message_(const uint8_t *packet, uint8_t size); + std::unique_ptr last_status_message_; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/smartair2_packet.h b/esphome/components/haier/smartair2_packet.h new file mode 100644 index 0000000000..8046516c5f --- /dev/null +++ b/esphome/components/haier/smartair2_packet.h @@ -0,0 +1,97 @@ +#pragma once + +namespace esphome { +namespace haier { +namespace smartair2_protocol { + +enum class ConditioningMode : uint8_t { AUTO = 0x00, COOL = 0x01, HEAT = 0x02, FAN = 0x03, DRY = 0x04 }; + +enum class FanMode : uint8_t { FAN_HIGH = 0x00, FAN_MID = 0x01, FAN_LOW = 0x02, FAN_AUTO = 0x03 }; + +struct HaierPacketControl { + // Control bytes starts here + // 10 + uint8_t : 8; // Temperature high byte + // 11 + uint8_t room_temperature; // current room temperature 1°C step + // 12 + uint8_t : 8; // Humidity high byte + // 13 + uint8_t room_humidity; // Humidity 0%-100% with 1% step + // 14 + uint8_t : 8; + // 15 + uint8_t cntrl; // In AC => ESP packets - 0x7F, in ESP => AC packets - 0x00 + // 16 + uint8_t : 8; + // 17 + uint8_t : 8; + // 18 + uint8_t : 8; + // 19 + uint8_t : 8; + // 20 + uint8_t : 8; + // 21 + uint8_t ac_mode; // See enum ConditioningMode + // 22 + uint8_t : 8; + // 23 + uint8_t fan_mode; // See enum FanMode + // 24 + uint8_t : 8; + // 25 + uint8_t swing_both; // If 1 - swing both direction, if 0 - horizontal_swing and vertical_swing define + // vertical/horizontal/off + // 26 + uint8_t : 3; + uint8_t use_fahrenheit : 1; + uint8_t : 3; + uint8_t lock_remote : 1; // Disable remote + // 27 + uint8_t ac_power : 1; // Is ac on or off + uint8_t : 2; + uint8_t health_mode : 1; // Health mode on or off + uint8_t compressor : 1; // Compressor on or off ??? + uint8_t : 1; + uint8_t ten_degree : 1; // 10 degree status (only work in heat mode) + uint8_t : 0; + // 28 + uint8_t : 8; + // 29 + uint8_t use_swing_bits : 1; // Indicate if horizontal_swing and vertical_swing should be used + uint8_t turbo_mode : 1; // Turbo mode + uint8_t quiet_mode : 1; // Sleep mode + uint8_t horizontal_swing : 1; // Horizontal swing (if swing_both == 0) + uint8_t vertical_swing : 1; // Vertical swing (if swing_both == 0) if vertical_swing and horizontal_swing both 0 => + // swing off + uint8_t display_status : 1; // Led on or off + uint8_t : 0; + // 30 + uint8_t : 8; + // 31 + uint8_t : 8; + // 32 + uint8_t : 8; // Target temperature high byte + // 33 + uint8_t set_point; // Target temperature with 16°C offset, 1°C step +}; + +struct HaierStatus { + uint16_t subcommand; + HaierPacketControl control; +}; + +enum class FrameType : uint8_t { + CONTROL = 0x01, + STATUS = 0x02, + INVALID = 0x03, + CONFIRM = 0x05, + GET_DEVICE_VERSION = 0x61, + REPORT_NETWORK_STATUS = 0xF7, + NO_COMMAND = 0xFF, +}; + +} // namespace smartair2_protocol +} // namespace haier +} // namespace esphome diff --git a/platformio.ini b/platformio.ini index 3565b15809..ab16d47c6f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,6 +39,7 @@ lib_deps = bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 + pavlodn/HaierProtocol@0.9.18 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library build_flags = diff --git a/tests/test3.yaml b/tests/test3.yaml index 8307ac2984..f7b66a748e 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -944,13 +944,29 @@ climate: kd_multiplier: 0.0 deadband_output_averaging_samples: 1 - platform: haier + protocol: hOn name: Haier AC - supported_swing_modes: - - vertical - - horizontal - - both - update_interval: 10s uart_id: uart_12 + wifi_signal: true + beeper: true + outdoor_temperature: + name: Haier AC outdoor temperature + visual: + min_temperature: 16 °C + max_temperature: 30 °C + temperature_step: 1 °C + supported_modes: + - 'OFF' + - AUTO + - COOL + - HEAT + - DRY + - FAN_ONLY + supported_swing_modes: + - 'OFF' + - VERTICAL + - HORIZONTAL + - BOTH sprinkler: - id: yard_sprinkler_ctrlr From 8c9d63f48f49b4ff98f1564e7d667ec60e713d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 19 Jun 2023 01:04:19 +0200 Subject: [PATCH 0090/2607] display: add `BaseFont` and introduce `Font::draw` methods (#4963) --- esphome/components/display/display_buffer.cpp | 77 ++++--------------- esphome/components/display/display_buffer.h | 51 +++++++----- esphome/components/display/font.cpp | 52 ++++++++++++- esphome/components/display/font.h | 9 ++- esphome/components/display/image.cpp | 1 - esphome/components/display/image.h | 15 +--- esphome/components/graph/graph.cpp | 1 + 7 files changed, 106 insertions(+), 100 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 672c6a22b0..fc59f9abb5 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -7,10 +7,6 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "animation.h" -#include "image.h" -#include "font.h" - namespace esphome { namespace display { @@ -256,54 +252,14 @@ void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, Color } while (dx <= 0); } -void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align, const char *text) { +void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) { int x_start, y_start; int width, height; this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height); - - int i = 0; - int x_at = x_start; - while (text[i] != '\0') { - int match_length; - int glyph_n = font->match_next_glyph(text + i, &match_length); - if (glyph_n < 0) { - // Unknown char, skip - ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); - if (!font->get_glyphs().empty()) { - uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width; - for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) { - for (int glyph_y = 0; glyph_y < height; glyph_y++) - this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); - } - x_at += glyph_width; - } - - i++; - continue; - } - - const Glyph &glyph = font->get_glyphs()[glyph_n]; - int scan_x1, scan_y1, scan_width, scan_height; - glyph.scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height); - - { - const int glyph_x_max = scan_x1 + scan_width; - const int glyph_y_max = scan_y1 + scan_height; - for (int glyph_x = scan_x1; glyph_x < glyph_x_max; glyph_x++) { - for (int glyph_y = scan_y1; glyph_y < glyph_y_max; glyph_y++) { - if (glyph.get_pixel(glyph_x, glyph_y)) { - this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); - } - } - } - } - - x_at += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; - - i += match_length; - } + font->print(x_start, y_start, this, color, text); } -void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg) { +void DisplayBuffer::vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, + va_list arg) { char buffer[256]; int ret = vsnprintf(buffer, sizeof(buffer), format, arg); if (ret > 0) @@ -358,7 +314,7 @@ void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_ } #endif // USE_QR_CODE -void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, +void DisplayBuffer::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width, int *height) { int x_offset, baseline; font->measure(text, width, &x_offset, &baseline, height); @@ -396,34 +352,34 @@ void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, break; } } -void DisplayBuffer::print(int x, int y, Font *font, Color color, const char *text) { +void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, const char *text) { this->print(x, y, font, color, TextAlign::TOP_LEFT, text); } -void DisplayBuffer::print(int x, int y, Font *font, TextAlign align, const char *text) { +void DisplayBuffer::print(int x, int y, BaseFont *font, TextAlign align, const char *text) { this->print(x, y, font, COLOR_ON, align, text); } -void DisplayBuffer::print(int x, int y, Font *font, const char *text) { +void DisplayBuffer::print(int x, int y, BaseFont *font, const char *text) { this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text); } -void DisplayBuffer::printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...) { +void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) { va_list arg; va_start(arg, format); this->vprintf_(x, y, font, color, align, format, arg); va_end(arg); } -void DisplayBuffer::printf(int x, int y, Font *font, Color color, const char *format, ...) { +void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) { va_list arg; va_start(arg, format); this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg); va_end(arg); } -void DisplayBuffer::printf(int x, int y, Font *font, TextAlign align, const char *format, ...) { +void DisplayBuffer::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) { va_list arg; va_start(arg, format); this->vprintf_(x, y, font, COLOR_ON, align, format, arg); va_end(arg); } -void DisplayBuffer::printf(int x, int y, Font *font, const char *format, ...) { +void DisplayBuffer::printf(int x, int y, BaseFont *font, const char *format, ...) { va_list arg; va_start(arg, format); this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg); @@ -470,19 +426,20 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) this->trigger(from, to); } -void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) { +void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, + ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) this->print(x, y, font, color, align, buffer); } -void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time) { +void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) { this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); } -void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time) { +void DisplayBuffer::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) { this->strftime(x, y, font, COLOR_ON, align, format, time); } -void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, ESPTime time) { +void DisplayBuffer::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) { this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 652039517f..b5cd2737be 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -16,10 +16,6 @@ #include "esphome/components/qr_code/qr_code.h" #endif -#include "animation.h" -#include "font.h" -#include "image.h" - namespace esphome { namespace display { @@ -175,6 +171,24 @@ using display_writer_t = std::function; ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \ } +/// Turn the pixel OFF. +extern const Color COLOR_OFF; +/// Turn the pixel ON. +extern const Color COLOR_ON; + +class BaseImage { + public: + virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; +}; + +class BaseFont { + public: + virtual void print(int x, int y, DisplayBuffer *display, Color color, const char *text) = 0; + virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0; +}; + class DisplayBuffer { public: /// Fill the entire screen with the given color. @@ -221,7 +235,7 @@ class DisplayBuffer { * @param align The alignment of the text. * @param text The text to draw. */ - void print(int x, int y, Font *font, Color color, TextAlign align, const char *text); + void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text); /** Print `text` with the top left at [x,y] with `font`. * @@ -231,7 +245,7 @@ class DisplayBuffer { * @param color The color to draw the text with. * @param text The text to draw. */ - void print(int x, int y, Font *font, Color color, const char *text); + void print(int x, int y, BaseFont *font, Color color, const char *text); /** Print `text` with the anchor point at [x,y] with `font`. * @@ -241,7 +255,7 @@ class DisplayBuffer { * @param align The alignment of the text. * @param text The text to draw. */ - void print(int x, int y, Font *font, TextAlign align, const char *text); + void print(int x, int y, BaseFont *font, TextAlign align, const char *text); /** Print `text` with the top left at [x,y] with `font`. * @@ -250,7 +264,7 @@ class DisplayBuffer { * @param font The font to draw the text with. * @param text The text to draw. */ - void print(int x, int y, Font *font, const char *text); + void print(int x, int y, BaseFont *font, const char *text); /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. * @@ -262,7 +276,7 @@ class DisplayBuffer { * @param format The format to use. * @param ... The arguments to use for the text formatting. */ - void printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...) + void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) __attribute__((format(printf, 7, 8))); /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. @@ -274,7 +288,7 @@ class DisplayBuffer { * @param format The format to use. * @param ... The arguments to use for the text formatting. */ - void printf(int x, int y, Font *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7))); + void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7))); /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. * @@ -285,7 +299,8 @@ class DisplayBuffer { * @param format The format to use. * @param ... The arguments to use for the text formatting. */ - void printf(int x, int y, Font *font, TextAlign align, const char *format, ...) __attribute__((format(printf, 6, 7))); + void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) + __attribute__((format(printf, 6, 7))); /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. * @@ -295,7 +310,7 @@ class DisplayBuffer { * @param format The format to use. * @param ... The arguments to use for the text formatting. */ - void printf(int x, int y, Font *font, const char *format, ...) __attribute__((format(printf, 5, 6))); + void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6))); /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. * @@ -307,7 +322,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) + void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) __attribute__((format(strftime, 7, 0))); /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. @@ -319,7 +334,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time) + void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) __attribute__((format(strftime, 6, 0))); /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. @@ -331,7 +346,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time) + void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) __attribute__((format(strftime, 6, 0))); /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. @@ -342,7 +357,7 @@ class DisplayBuffer { * @param format The strftime format to use. * @param time The time to format. */ - void strftime(int x, int y, Font *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0))); + void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0))); /** Draw the `image` with the top-left corner at [x,y] to the screen. * @@ -412,7 +427,7 @@ class DisplayBuffer { * @param width A pointer to store the returned text width in. * @param height A pointer to store the returned text height in. */ - void get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, int *width, + void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width, int *height); /// Internal method to set the display writer lambda. @@ -487,7 +502,7 @@ class DisplayBuffer { bool is_clipping() const { return !this->clipping_rectangle_.empty(); } protected: - void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg); + void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg); virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; diff --git a/esphome/components/display/font.cpp b/esphome/components/display/font.cpp index 1833ef5023..a7d0b7780c 100644 --- a/esphome/components/display/font.cpp +++ b/esphome/components/display/font.cpp @@ -1,10 +1,13 @@ #include "font.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace display { +static const char *const TAG = "display"; + bool Glyph::get_pixel(int x, int y) const { const int x_data = x - this->glyph_data_->offset_x; const int y_data = y - this->glyph_data_->offset_y; @@ -14,6 +17,20 @@ bool Glyph::get_pixel(int x, int y) const { const uint32_t pos = x_data + y_data * width_8; return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); } +void Glyph::draw(int x_at, int y_start, DisplayBuffer *display, Color color) const { + int scan_x1, scan_y1, scan_width, scan_height; + this->scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height); + + const int glyph_x_max = scan_x1 + scan_width; + const int glyph_y_max = scan_y1 + scan_height; + for (int glyph_x = scan_x1; glyph_x < glyph_x_max; glyph_x++) { + for (int glyph_y = scan_y1; glyph_y < glyph_y_max; glyph_y++) { + if (this->get_pixel(glyph_x, glyph_y)) { + display->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); + } + } + } +} const char *Glyph::get_char() const { return this->glyph_data_->a_char; } bool Glyph::compare_to(const char *str) const { // 1 -> this->char_ @@ -47,6 +64,12 @@ void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { *width = this->glyph_data_->width; *height = this->glyph_data_->height; } + +Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { + glyphs_.reserve(data_nr); + for (int i = 0; i < data_nr; ++i) + glyphs_.emplace_back(&data[i]); +} int Font::match_next_glyph(const char *str, int *match_length) { int lo = 0; int hi = this->glyphs_.size() - 1; @@ -95,10 +118,31 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in *x_offset = min_x; *width = x - min_x; } -Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { - glyphs_.reserve(data_nr); - for (int i = 0; i < data_nr; ++i) - glyphs_.emplace_back(&data[i]); +void Font::print(int x_start, int y_start, DisplayBuffer *display, Color color, const char *text) { + int i = 0; + int x_at = x_start; + while (text[i] != '\0') { + int match_length; + int glyph_n = this->match_next_glyph(text + i, &match_length); + if (glyph_n < 0) { + // Unknown char, skip + ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); + if (!this->get_glyphs().empty()) { + uint8_t glyph_width = this->get_glyphs()[0].glyph_data_->width; + display->filled_rectangle(x_at, y_start, glyph_width, this->height_, color); + x_at += glyph_width; + } + + i++; + continue; + } + + const Glyph &glyph = this->get_glyphs()[glyph_n]; + glyph.draw(x_at, y_start, display, color); + x_at += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; + + i += match_length; + } } } // namespace display diff --git a/esphome/components/display/font.h b/esphome/components/display/font.h index 08b457116e..678aee65a1 100644 --- a/esphome/components/display/font.h +++ b/esphome/components/display/font.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/datatypes.h" +#include "display_buffer.h" namespace esphome { namespace display { @@ -23,6 +24,8 @@ class Glyph { bool get_pixel(int x, int y) const; + void draw(int x, int y, DisplayBuffer *display, Color color) const; + const char *get_char() const; bool compare_to(const char *str) const; @@ -33,12 +36,11 @@ class Glyph { protected: friend Font; - friend DisplayBuffer; const GlyphData *glyph_data_; }; -class Font { +class Font : public BaseFont { public: /** Construct the font with the given glyphs. * @@ -50,7 +52,8 @@ class Font { int match_next_glyph(const char *str, int *match_length); - void measure(const char *str, int *width, int *x_offset, int *baseline, int *height); + void print(int x_start, int y_start, DisplayBuffer *display, Color color, const char *text) override; + void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override; inline int get_baseline() { return this->baseline_; } inline int get_height() { return this->height_; } diff --git a/esphome/components/display/image.cpp b/esphome/components/display/image.cpp index b3cab3ff7f..33c26ef127 100644 --- a/esphome/components/display/image.cpp +++ b/esphome/components/display/image.cpp @@ -1,7 +1,6 @@ #include "image.h" #include "esphome/core/hal.h" -#include "display_buffer.h" namespace esphome { namespace display { diff --git a/esphome/components/display/image.h b/esphome/components/display/image.h index ac2d5a3421..b16828a5be 100644 --- a/esphome/components/display/image.h +++ b/esphome/components/display/image.h @@ -1,5 +1,6 @@ #pragma once #include "esphome/core/color.h" +#include "display_buffer.h" namespace esphome { namespace display { @@ -30,20 +31,6 @@ inline int image_type_to_bpp(ImageType type) { inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } -/// Turn the pixel OFF. -extern const Color COLOR_OFF; -/// Turn the pixel ON. -extern const Color COLOR_ON; - -class DisplayBuffer; - -class BaseImage { - public: - virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; -}; - class Image : public BaseImage { public: Image(const uint8_t *data_start, int width, int height, ImageType type); diff --git a/esphome/components/graph/graph.cpp b/esphome/components/graph/graph.cpp index c229f17dd8..88850f4b92 100644 --- a/esphome/components/graph/graph.cpp +++ b/esphome/components/graph/graph.cpp @@ -1,5 +1,6 @@ #include "graph.h" #include "esphome/components/display/display_buffer.h" +#include "esphome/components/display/font.h" #include "esphome/core/color.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" From 77a7d3f24b8b9b4a73c3f65252f7688e1fabd0d2 Mon Sep 17 00:00:00 2001 From: Hawawa McTaru <86658622+TaruDesigns@users.noreply.github.com> Date: Mon, 19 Jun 2023 01:20:32 +0200 Subject: [PATCH 0091/2607] Fix for Fujitsu AC not having Quiet Fan Mode (#4962) --- esphome/components/fujitsu_general/fujitsu_general.cpp | 7 +++++-- esphome/components/fujitsu_general/fujitsu_general.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/fujitsu_general/fujitsu_general.cpp b/esphome/components/fujitsu_general/fujitsu_general.cpp index 291af8c8cd..6c7adebfea 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.cpp +++ b/esphome/components/fujitsu_general/fujitsu_general.cpp @@ -151,11 +151,13 @@ void FujitsuGeneralClimate::transmit_state() { case climate::CLIMATE_FAN_LOW: SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_LOW); break; + case climate::CLIMATE_FAN_QUIET: + SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_SILENT); + break; case climate::CLIMATE_FAN_AUTO: default: SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_AUTO); break; - // TODO Quiet / Silent } // Set swing @@ -345,8 +347,9 @@ bool FujitsuGeneralClimate::on_receive(remote_base::RemoteReceiveData data) { const uint8_t recv_fan_mode = GET_NIBBLE(recv_message, FUJITSU_GENERAL_FAN_NIBBLE); ESP_LOGV(TAG, "Received fan mode %X", recv_fan_mode); switch (recv_fan_mode) { - // TODO No Quiet / Silent in ESPH case FUJITSU_GENERAL_FAN_SILENT: + this->fan_mode = climate::CLIMATE_FAN_QUIET; + break; case FUJITSU_GENERAL_FAN_LOW: this->fan_mode = climate::CLIMATE_FAN_LOW; break; diff --git a/esphome/components/fujitsu_general/fujitsu_general.h b/esphome/components/fujitsu_general/fujitsu_general.h index ee83ae9d19..d7d01bf6f3 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.h +++ b/esphome/components/fujitsu_general/fujitsu_general.h @@ -52,7 +52,7 @@ class FujitsuGeneralClimate : public climate_ir::ClimateIR { FujitsuGeneralClimate() : ClimateIR(FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1.0f, true, true, {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, - climate::CLIMATE_FAN_HIGH}, + climate::CLIMATE_FAN_HIGH, climate::CLIMATE_FAN_QUIET}, {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {} From 54eb52c19aa185c26150353762fd1db794952c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 19 Jun 2023 01:29:43 +0200 Subject: [PATCH 0092/2607] display/font: optimise font rendering by about 25% (#4956) --- esphome/components/display/font.cpp | 28 +++++++++++++--------------- esphome/components/display/font.h | 2 -- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/esphome/components/display/font.cpp b/esphome/components/display/font.cpp index a7d0b7780c..0a5881b48b 100644 --- a/esphome/components/display/font.cpp +++ b/esphome/components/display/font.cpp @@ -8,25 +8,23 @@ namespace display { static const char *const TAG = "display"; -bool Glyph::get_pixel(int x, int y) const { - const int x_data = x - this->glyph_data_->offset_x; - const int y_data = y - this->glyph_data_->offset_y; - if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) - return false; - const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; - const uint32_t pos = x_data + y_data * width_8; - return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); -} void Glyph::draw(int x_at, int y_start, DisplayBuffer *display, Color color) const { int scan_x1, scan_y1, scan_width, scan_height; this->scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height); - const int glyph_x_max = scan_x1 + scan_width; - const int glyph_y_max = scan_y1 + scan_height; - for (int glyph_x = scan_x1; glyph_x < glyph_x_max; glyph_x++) { - for (int glyph_y = scan_y1; glyph_y < glyph_y_max; glyph_y++) { - if (this->get_pixel(glyph_x, glyph_y)) { - display->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); + const unsigned char *data = this->glyph_data_->data; + const int max_x = x_at + scan_x1 + scan_width; + const int max_y = y_start + scan_y1 + scan_height; + + for (int glyph_y = y_start + scan_y1; glyph_y < max_y; glyph_y++) { + for (int glyph_x = x_at + scan_x1; glyph_x < max_x; data++, glyph_x += 8) { + uint8_t pixel_data = progmem_read_byte(data); + const int pixel_max_x = std::min(max_x, glyph_x + 8); + + for (int pixel_x = glyph_x; pixel_x < pixel_max_x && pixel_data; pixel_x++, pixel_data <<= 1) { + if (pixel_data & 0x80) { + display->draw_pixel_at(pixel_x, glyph_y, color); + } } } } diff --git a/esphome/components/display/font.h b/esphome/components/display/font.h index 678aee65a1..5ba6685a1c 100644 --- a/esphome/components/display/font.h +++ b/esphome/components/display/font.h @@ -22,8 +22,6 @@ class Glyph { public: Glyph(const GlyphData *data) : glyph_data_(data) {} - bool get_pixel(int x, int y) const; - void draw(int x, int y, DisplayBuffer *display, Color color) const; const char *get_char() const; From 62d2640c3728a73350a19162b24c6ba0099480b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 19 Jun 2023 01:32:39 +0200 Subject: [PATCH 0093/2607] display: move `Rect` into `rect.cpp/.h` (#4957) --- esphome/components/display/display_buffer.cpp | 87 ---------------- esphome/components/display/display_buffer.h | 28 +----- esphome/components/display/rect.cpp | 98 +++++++++++++++++++ esphome/components/display/rect.h | 36 +++++++ 4 files changed, 135 insertions(+), 114 deletions(-) create mode 100644 esphome/components/display/rect.cpp create mode 100644 esphome/components/display/rect.h diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index fc59f9abb5..8d37d6536a 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -15,93 +15,6 @@ static const char *const TAG = "display"; const Color COLOR_OFF(0, 0, 0, 255); const Color COLOR_ON(255, 255, 255, 255); -void Rect::expand(int16_t horizontal, int16_t vertical) { - if (this->is_set() && (this->w >= (-2 * horizontal)) && (this->h >= (-2 * vertical))) { - this->x = this->x - horizontal; - this->y = this->y - vertical; - this->w = this->w + (2 * horizontal); - this->h = this->h + (2 * vertical); - } -} - -void Rect::extend(Rect rect) { - if (!this->is_set()) { - this->x = rect.x; - this->y = rect.y; - this->w = rect.w; - this->h = rect.h; - } else { - if (this->x > rect.x) { - this->w = this->w + (this->x - rect.x); - this->x = rect.x; - } - if (this->y > rect.y) { - this->h = this->h + (this->y - rect.y); - this->y = rect.y; - } - if (this->x2() < rect.x2()) { - this->w = rect.x2() - this->x; - } - if (this->y2() < rect.y2()) { - this->h = rect.y2() - this->y; - } - } -} -void Rect::shrink(Rect rect) { - if (!this->inside(rect)) { - (*this) = Rect(); - } else { - if (this->x2() > rect.x2()) { - this->w = rect.x2() - this->x; - } - if (this->x < rect.x) { - this->w = this->w + (this->x - rect.x); - this->x = rect.x; - } - if (this->y2() > rect.y2()) { - this->h = rect.y2() - this->y; - } - if (this->y < rect.y) { - this->h = this->h + (this->y - rect.y); - this->y = rect.y; - } - } -} - -bool Rect::equal(Rect rect) { - return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h); -} - -bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT - if (!this->is_set()) { - return true; - } - if (absolute) { - return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2())); - } else { - return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h)); - } -} - -bool Rect::inside(Rect rect, bool absolute) { - if (!this->is_set() || !rect.is_set()) { - return true; - } - if (absolute) { - return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y)); - } else { - return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); - } -} - -void Rect::info(const std::string &prefix) { - if (this->is_set()) { - ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(), - this->y2()); - } else - ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str()); -} - void DisplayBuffer::init_internal_(uint32_t buffer_length) { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); this->buffer_ = allocator.allocate(buffer_length); diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index b5cd2737be..1a62da2323 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -2,6 +2,7 @@ #include #include +#include "rect.h" #include "display_color_utils.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" @@ -131,33 +132,6 @@ enum DisplayRotation { DISPLAY_ROTATION_270_DEGREES = 270, }; -static const int16_t VALUE_NO_SET = 32766; - -class Rect { - public: - int16_t x; ///< X coordinate of corner - int16_t y; ///< Y coordinate of corner - int16_t w; ///< Width of region - int16_t h; ///< Height of region - - Rect() : x(VALUE_NO_SET), y(VALUE_NO_SET), w(VALUE_NO_SET), h(VALUE_NO_SET) {} // NOLINT - inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE : x(x), y(y), w(w), h(h) {} - inline int16_t x2() { return this->x + this->w; }; ///< X coordinate of corner - inline int16_t y2() { return this->y + this->h; }; ///< Y coordinate of corner - - inline bool is_set() ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } - - void expand(int16_t horizontal, int16_t vertical); - - void extend(Rect rect); - void shrink(Rect rect); - - bool inside(Rect rect, bool absolute = true); - bool inside(int16_t test_x, int16_t test_y, bool absolute = true); - bool equal(Rect rect); - void info(const std::string &prefix = "rect info:"); -}; - class DisplayBuffer; class DisplayPage; class DisplayOnPageChangeTrigger; diff --git a/esphome/components/display/rect.cpp b/esphome/components/display/rect.cpp new file mode 100644 index 0000000000..6e91c86c4f --- /dev/null +++ b/esphome/components/display/rect.cpp @@ -0,0 +1,98 @@ +#include "rect.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace display { + +static const char *const TAG = "display"; + +void Rect::expand(int16_t horizontal, int16_t vertical) { + if (this->is_set() && (this->w >= (-2 * horizontal)) && (this->h >= (-2 * vertical))) { + this->x = this->x - horizontal; + this->y = this->y - vertical; + this->w = this->w + (2 * horizontal); + this->h = this->h + (2 * vertical); + } +} + +void Rect::extend(Rect rect) { + if (!this->is_set()) { + this->x = rect.x; + this->y = rect.y; + this->w = rect.w; + this->h = rect.h; + } else { + if (this->x > rect.x) { + this->w = this->w + (this->x - rect.x); + this->x = rect.x; + } + if (this->y > rect.y) { + this->h = this->h + (this->y - rect.y); + this->y = rect.y; + } + if (this->x2() < rect.x2()) { + this->w = rect.x2() - this->x; + } + if (this->y2() < rect.y2()) { + this->h = rect.y2() - this->y; + } + } +} +void Rect::shrink(Rect rect) { + if (!this->inside(rect)) { + (*this) = Rect(); + } else { + if (this->x2() > rect.x2()) { + this->w = rect.x2() - this->x; + } + if (this->x < rect.x) { + this->w = this->w + (this->x - rect.x); + this->x = rect.x; + } + if (this->y2() > rect.y2()) { + this->h = rect.y2() - this->y; + } + if (this->y < rect.y) { + this->h = this->h + (this->y - rect.y); + this->y = rect.y; + } + } +} + +bool Rect::equal(Rect rect) { + return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h); +} + +bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT + if (!this->is_set()) { + return true; + } + if (absolute) { + return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2())); + } else { + return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h)); + } +} + +bool Rect::inside(Rect rect, bool absolute) { + if (!this->is_set() || !rect.is_set()) { + return true; + } + if (absolute) { + return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y)); + } else { + return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); + } +} + +void Rect::info(const std::string &prefix) { + if (this->is_set()) { + ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(), + this->y2()); + } else + ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str()); +} + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/rect.h b/esphome/components/display/rect.h new file mode 100644 index 0000000000..867a9c67c7 --- /dev/null +++ b/esphome/components/display/rect.h @@ -0,0 +1,36 @@ +#pragma once + +#include "esphome/core/helpers.h" + +namespace esphome { +namespace display { + +static const int16_t VALUE_NO_SET = 32766; + +class Rect { + public: + int16_t x; ///< X coordinate of corner + int16_t y; ///< Y coordinate of corner + int16_t w; ///< Width of region + int16_t h; ///< Height of region + + Rect() : x(VALUE_NO_SET), y(VALUE_NO_SET), w(VALUE_NO_SET), h(VALUE_NO_SET) {} // NOLINT + inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE : x(x), y(y), w(w), h(h) {} + inline int16_t x2() { return this->x + this->w; }; ///< X coordinate of corner + inline int16_t y2() { return this->y + this->h; }; ///< Y coordinate of corner + + inline bool is_set() ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } + + void expand(int16_t horizontal, int16_t vertical); + + void extend(Rect rect); + void shrink(Rect rect); + + bool inside(Rect rect, bool absolute = true); + bool inside(int16_t test_x, int16_t test_y, bool absolute = true); + bool equal(Rect rect); + void info(const std::string &prefix = "rect info:"); +}; + +} // namespace display +} // namespace esphome From b9f20b36cbae0515f36a877615b880e1491dde61 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Jun 2023 18:35:47 -0500 Subject: [PATCH 0094/2607] Store app comment and compilation_time in flash (#4945) --- esphome/core/application.cpp | 2 +- esphome/core/application.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index c012195f34..d82a7a5d37 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -99,7 +99,7 @@ void Application::loop() { if (this->dump_config_at_ < this->components_.size()) { if (this->dump_config_at_ == 0) { - ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str()); + ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_); #ifdef ESPHOME_PROJECT_NAME ESP_LOGI(TAG, "Project " ESPHOME_PROJECT_NAME " version " ESPHOME_PROJECT_VERSION); #endif diff --git a/esphome/core/application.h b/esphome/core/application.h index 0501d1a56a..054f2ea648 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -56,7 +56,7 @@ namespace esphome { class Application { public: - void pre_setup(const std::string &name, const std::string &friendly_name, const std::string &comment, + void pre_setup(const std::string &name, const std::string &friendly_name, const char *comment, const char *compilation_time, bool name_add_mac_suffix) { arch_init(); this->name_add_mac_suffix_ = name_add_mac_suffix; @@ -154,11 +154,11 @@ class Application { /// Get the friendly name of this Application set by pre_setup(). const std::string &get_friendly_name() const { return this->friendly_name_; } /// Get the comment of this Application set by pre_setup(). - const std::string &get_comment() const { return this->comment_; } + std::string get_comment() const { return this->comment_; } bool is_name_add_mac_suffix_enabled() const { return this->name_add_mac_suffix_; } - const std::string &get_compilation_time() const { return this->compilation_time_; } + std::string get_compilation_time() const { return this->compilation_time_; } /** Set the target interval with which to run the loop() calls. * If the loop() method takes longer than the target interval, ESPHome won't @@ -376,8 +376,8 @@ class Application { std::string name_; std::string friendly_name_; - std::string comment_; - std::string compilation_time_; + const char *comment_{nullptr}; + const char *compilation_time_{nullptr}; bool name_add_mac_suffix_; uint32_t last_loop_{0}; uint32_t loop_interval_{16}; From cd57271386bfb844d430c386d386ddf19fa97621 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Jun 2023 20:51:19 -0500 Subject: [PATCH 0095/2607] Construct web_server assets at build time instead of run time (#4944) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/web_server/__init__.py | 49 ++++++++++++++--- esphome/components/web_server/web_server.cpp | 53 ++++++++----------- esphome/components/web_server/web_server.h | 42 ++++++++++++--- .../web_server_base/web_server_base.h | 1 + 4 files changed, 100 insertions(+), 45 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index d8343c6c39..130c082277 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -81,6 +81,37 @@ CONFIG_SCHEMA = cv.All( ) +def build_index_html(config) -> str: + html = "" + css_include = config.get(CONF_CSS_INCLUDE) + js_include = config.get(CONF_JS_INCLUDE) + if css_include: + html += "" + if config[CONF_CSS_URL]: + html += f'' + html += "" + if js_include: + html += "" + html += "" + if config[CONF_JS_URL]: + html += f'' + html += "" + return html + + +def add_resource_as_progmem(resource_name: str, content: str) -> None: + """Add a resource to progmem.""" + content_encoded = content.encode("utf-8") + content_encoded_size = len(content_encoded) + bytes_as_int = ", ".join(str(x) for x in content_encoded) + uint8_t = f"const uint8_t ESPHOME_WEBSERVER_{resource_name}[{content_encoded_size}] PROGMEM = {{{bytes_as_int}}}" + size_t = ( + f"const size_t ESPHOME_WEBSERVER_{resource_name}_SIZE = {content_encoded_size}" + ) + cg.add_global(cg.RawExpression(uint8_t)) + cg.add_global(cg.RawExpression(size_t)) + + @coroutine_with_priority(40.0) async def to_code(config): paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) @@ -89,13 +120,17 @@ async def to_code(config): await cg.register_component(var, config) cg.add_define("USE_WEBSERVER") + version = config[CONF_VERSION] cg.add(paren.set_port(config[CONF_PORT])) cg.add_define("USE_WEBSERVER") cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) - cg.add_define("USE_WEBSERVER_VERSION", config[CONF_VERSION]) - cg.add(var.set_css_url(config[CONF_CSS_URL])) - cg.add(var.set_js_url(config[CONF_JS_URL])) + cg.add_define("USE_WEBSERVER_VERSION", version) + if version == 2: + add_resource_as_progmem("INDEX_HTML", build_index_html(config)) + else: + cg.add(var.set_css_url(config[CONF_CSS_URL])) + cg.add(var.set_js_url(config[CONF_JS_URL])) cg.add(var.set_allow_ota(config[CONF_OTA])) if CONF_AUTH in config: cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME])) @@ -103,13 +138,13 @@ async def to_code(config): if CONF_CSS_INCLUDE in config: cg.add_define("USE_WEBSERVER_CSS_INCLUDE") path = CORE.relative_config_path(config[CONF_CSS_INCLUDE]) - with open(file=path, encoding="utf-8") as myfile: - cg.add(var.set_css_include(myfile.read())) + with open(file=path, encoding="utf-8") as css_file: + add_resource_as_progmem("CSS_INCLUDE", css_file.read()) if CONF_JS_INCLUDE in config: cg.add_define("USE_WEBSERVER_JS_INCLUDE") path = CORE.relative_config_path(config[CONF_JS_INCLUDE]) - with open(file=path, encoding="utf-8") as myfile: - cg.add(var.set_js_include(myfile.read())) + with open(file=path, encoding="utf-8") as js_file: + add_resource_as_progmem("JS_INCLUDE", js_file.read()) cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL])) if CONF_LOCAL in config and config[CONF_LOCAL]: cg.add_define("USE_WEBSERVER_LOCAL") diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 1ac94375c2..b3a2dfdb66 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -90,10 +90,17 @@ WebServer::WebServer(web_server_base::WebServerBase *base) #endif } +#if USE_WEBSERVER_VERSION == 1 void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; } -void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; } void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; } +#endif + +#ifdef USE_WEBSERVER_CSS_INCLUDE +void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; } +#endif +#ifdef USE_WEBSERVER_JS_INCLUDE void WebServer::set_js_include(const char *js_include) { this->js_include_ = js_include; } +#endif void WebServer::setup() { ESP_LOGCONFIG(TAG, "Setting up web server..."); @@ -159,20 +166,14 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { response->addHeader("Content-Encoding", "gzip"); request->send(response); } -#else +#elif USE_WEBSERVER_VERSION == 1 void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncResponseStream *stream = request->beginResponseStream("text/html"); - // All content is controlled and created by user - so allowing all origins is fine here. - stream->addHeader("Access-Control-Allow-Origin", "*"); -#if USE_WEBSERVER_VERSION == 1 const std::string &title = App.get_name(); stream->print(F("")); stream->print(title.c_str()); stream->print(F("")); -#else - stream->print(F("")); -#endif #ifdef USE_WEBSERVER_CSS_INCLUDE stream->print(F("")); #endif @@ -182,7 +183,6 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("\">")); } stream->print(F("")); -#if USE_WEBSERVER_VERSION == 1 stream->print(F("

")); stream->print(title.c_str()); stream->print(F("

")); @@ -308,49 +308,40 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { "type=\"file\" name=\"update\">")); } stream->print(F("

Debug Log

"));
-#endif
 #ifdef USE_WEBSERVER_JS_INCLUDE
   if (this->js_include_ != nullptr) {
     stream->print(F(""));
   }
-#endif
-#if USE_WEBSERVER_VERSION == 2
-  stream->print(F(""));
 #endif
   if (strlen(this->js_url_) > 0) {
     stream->print(F(""));
   }
-#if USE_WEBSERVER_VERSION == 1
   stream->print(F("
")); -#else - stream->print(F("")); -#endif - request->send(stream); } +#elif USE_WEBSERVER_VERSION == 2 +void WebServer::handle_index_request(AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); + request->send(response); +} #endif + #ifdef USE_WEBSERVER_CSS_INCLUDE void WebServer::handle_css_request(AsyncWebServerRequest *request) { - AsyncResponseStream *stream = request->beginResponseStream("text/css"); - if (this->css_include_ != nullptr) { - stream->print(this->css_include_); - } - - request->send(stream); + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/css", ESPHOME_WEBSERVER_CSS_INCLUDE, ESPHOME_WEBSERVER_CSS_INCLUDE_SIZE); + request->send(response); } #endif #ifdef USE_WEBSERVER_JS_INCLUDE void WebServer::handle_js_request(AsyncWebServerRequest *request) { - AsyncResponseStream *stream = request->beginResponseStream("text/javascript"); - if (this->js_include_ != nullptr) { - stream->addHeader("Access-Control-Allow-Origin", "*"); - stream->print(this->js_include_); - } - - request->send(stream); + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/javascript", ESPHOME_WEBSERVER_JS_INCLUDE, ESPHOME_WEBSERVER_JS_INCLUDE_SIZE); + request->send(response); } #endif diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 45d0bc03a4..a664bb5a12 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -14,6 +14,22 @@ #include #include #endif + +#if USE_WEBSERVER_VERSION == 2 +extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; +#endif + +#ifdef USE_WEBSERVER_CSS_INCLUDE +extern const uint8_t ESPHOME_WEBSERVER_CSS_INCLUDE[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_CSS_INCLUDE_SIZE; +#endif + +#ifdef USE_WEBSERVER_JS_INCLUDE +extern const uint8_t ESPHOME_WEBSERVER_JS_INCLUDE[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_JS_INCLUDE_SIZE; +#endif + namespace esphome { namespace web_server { @@ -40,6 +56,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { public: WebServer(web_server_base::WebServerBase *base); +#if USE_WEBSERVER_VERSION == 1 /** Set the URL to the CSS that's sent to each client. Defaults to * https://esphome.io/_static/webserver-v1.min.css * @@ -47,24 +64,29 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { */ void set_css_url(const char *css_url); - /** Set local path to the script that's embedded in the index page. Defaults to - * - * @param css_include Local path to web server script. - */ - void set_css_include(const char *css_include); - /** Set the URL to the script that's embedded in the index page. Defaults to * https://esphome.io/_static/webserver-v1.min.js * * @param js_url The url to the web server script. */ void set_js_url(const char *js_url); +#endif +#ifdef USE_WEBSERVER_CSS_INCLUDE + /** Set local path to the script that's embedded in the index page. Defaults to + * + * @param css_include Local path to web server script. + */ + void set_css_include(const char *css_include); +#endif + +#ifdef USE_WEBSERVER_JS_INCLUDE /** Set local path to the script that's embedded in the index page. Defaults to * * @param js_include Local path to web server script. */ void set_js_include(const char *js_include); +#endif /** Determine whether internal components should be displayed on the web server. * Defaults to false. @@ -240,10 +262,16 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { web_server_base::WebServerBase *base_; AsyncEventSource events_{"/events"}; ListEntitiesIterator entities_iterator_; +#if USE_WEBSERVER_VERSION == 1 const char *css_url_{nullptr}; - const char *css_include_{nullptr}; const char *js_url_{nullptr}; +#endif +#ifdef USE_WEBSERVER_CSS_INCLUDE + const char *css_include_{nullptr}; +#endif +#ifdef USE_WEBSERVER_JS_INCLUDE const char *js_include_{nullptr}; +#endif bool include_internal_{false}; bool allow_ota_{true}; #ifdef USE_ESP32 diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index f6d3a84f89..ae286b1e22 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -83,6 +83,7 @@ class WebServerBase : public Component { return; } this->server_ = std::make_shared(this->port_); + // All content is controlled and created by user - so allowing all origins is fine here. DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); this->server_->begin(); From b346ad8080b3a9b29a3920c4ecb56c2dc69321bb Mon Sep 17 00:00:00 2001 From: Stanislav Habich Date: Mon, 19 Jun 2023 03:56:12 +0200 Subject: [PATCH 0096/2607] Update pca9685_output.cpp (#4929) --- esphome/components/pca9685/pca9685_output.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/pca9685/pca9685_output.cpp b/esphome/components/pca9685/pca9685_output.cpp index c61251b66f..d92312355a 100644 --- a/esphome/components/pca9685/pca9685_output.cpp +++ b/esphome/components/pca9685/pca9685_output.cpp @@ -29,13 +29,10 @@ void PCA9685Output::setup() { ESP_LOGCONFIG(TAG, "Setting up PCA9685OutputComponent..."); ESP_LOGV(TAG, " Resetting devices..."); - uint8_t address_tmp = this->address_; - this->set_i2c_address(0x00); if (!this->write_bytes(PCA9685_REGISTER_SOFTWARE_RESET, nullptr, 0)) { this->mark_failed(); return; } - this->set_i2c_address(address_tmp); if (!this->write_byte(PCA9685_REGISTER_MODE1, PCA9685_MODE1_RESTART | PCA9685_MODE1_AUTOINC)) { this->mark_failed(); From c151df32bcc1de5a73b0e14113f0e7a2232f4299 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:58:01 +1200 Subject: [PATCH 0097/2607] Bump pytest from 7.3.1 to 7.3.2 (#4936) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index d5235d733b..66ce075f91 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.4.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==7.3.1 +pytest==7.3.2 pytest-cov==4.1.0 pytest-mock==3.10.0 pytest-asyncio==0.21.0 From 67771abc9d57d87ae0ceb434998e9b171e6527e5 Mon Sep 17 00:00:00 2001 From: Carson Full Date: Sun, 18 Jun 2023 21:10:05 -0500 Subject: [PATCH 0098/2607] Add read/write for 16bit registers (#4844) --- esphome/components/i2c/i2c.cpp | 39 ++++++++++++++++++++++++++++++++++ esphome/components/i2c/i2c.h | 22 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp index fdc9fd1ddf..2b2190d28b 100644 --- a/esphome/components/i2c/i2c.cpp +++ b/esphome/components/i2c/i2c.cpp @@ -14,6 +14,14 @@ ErrorCode I2CDevice::read_register(uint8_t a_register, uint8_t *data, size_t len return bus_->read(address_, data, len); } +ErrorCode I2CDevice::read_register16(uint16_t a_register, uint8_t *data, size_t len, bool stop) { + a_register = convert_big_endian(a_register); + ErrorCode const err = this->write(reinterpret_cast(&a_register), 2, stop); + if (err != ERROR_OK) + return err; + return bus_->read(address_, data, len); +} + ErrorCode I2CDevice::write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop) { WriteBuffer buffers[2]; buffers[0].data = &a_register; @@ -23,6 +31,16 @@ ErrorCode I2CDevice::write_register(uint8_t a_register, const uint8_t *data, siz return bus_->writev(address_, buffers, 2, stop); } +ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, size_t len, bool stop) { + a_register = convert_big_endian(a_register); + WriteBuffer buffers[2]; + buffers[0].data = reinterpret_cast(&a_register); + buffers[0].len = 2; + buffers[1].data = data; + buffers[1].len = len; + return bus_->writev(address_, buffers, 2, stop); +} + bool I2CDevice::read_bytes_16(uint8_t a_register, uint16_t *data, uint8_t len) { if (read_register(a_register, reinterpret_cast(data), len * 2) != ERROR_OK) return false; @@ -60,5 +78,26 @@ uint8_t I2CRegister::get() const { return value; } +I2CRegister16 &I2CRegister16::operator=(uint8_t value) { + this->parent_->write_register16(this->register_, &value, 1); + return *this; +} +I2CRegister16 &I2CRegister16::operator&=(uint8_t value) { + value &= get(); + this->parent_->write_register16(this->register_, &value, 1); + return *this; +} +I2CRegister16 &I2CRegister16::operator|=(uint8_t value) { + value |= get(); + this->parent_->write_register16(this->register_, &value, 1); + return *this; +} + +uint8_t I2CRegister16::get() const { + uint8_t value = 0x00; + this->parent_->read_register16(this->register_, &value, 1); + return value; +} + } // namespace i2c } // namespace esphome diff --git a/esphome/components/i2c/i2c.h b/esphome/components/i2c/i2c.h index 780528a5c7..eb5d463b65 100644 --- a/esphome/components/i2c/i2c.h +++ b/esphome/components/i2c/i2c.h @@ -31,6 +31,25 @@ class I2CRegister { uint8_t register_; }; +class I2CRegister16 { + public: + I2CRegister16 &operator=(uint8_t value); + I2CRegister16 &operator&=(uint8_t value); + I2CRegister16 &operator|=(uint8_t value); + + explicit operator uint8_t() const { return get(); } + + uint8_t get() const; + + protected: + friend class I2CDevice; + + I2CRegister16(I2CDevice *parent, uint16_t a_register) : parent_(parent), register_(a_register) {} + + I2CDevice *parent_; + uint16_t register_; +}; + // like ntohs/htons but without including networking headers. // ("i2c" byte order is big-endian) inline uint16_t i2ctohs(uint16_t i2cshort) { return convert_big_endian(i2cshort); } @@ -44,12 +63,15 @@ class I2CDevice { void set_i2c_bus(I2CBus *bus) { bus_ = bus; } I2CRegister reg(uint8_t a_register) { return {this, a_register}; } + I2CRegister16 reg16(uint16_t a_register) { return {this, a_register}; } ErrorCode read(uint8_t *data, size_t len) { return bus_->read(address_, data, len); } ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len, bool stop = true); + ErrorCode read_register16(uint16_t a_register, uint8_t *data, size_t len, bool stop = true); ErrorCode write(const uint8_t *data, uint8_t len, bool stop = true) { return bus_->write(address_, data, len, stop); } ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop = true); + ErrorCode write_register16(uint16_t a_register, const uint8_t *data, size_t len, bool stop = true); // Compat APIs From 41a618737be7173ea2bc60a9b0e5873bf2fb05d3 Mon Sep 17 00:00:00 2001 From: MrEditor97 Date: Mon, 19 Jun 2023 04:26:06 +0100 Subject: [PATCH 0099/2607] XL9535 I/O Expander (#4899) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/xl9535/__init__.py | 73 +++++++++++++++ esphome/components/xl9535/xl9535.cpp | 122 ++++++++++++++++++++++++++ esphome/components/xl9535/xl9535.h | 54 ++++++++++++ tests/test4.yaml | 13 +++ 5 files changed, 263 insertions(+) create mode 100644 esphome/components/xl9535/__init__.py create mode 100644 esphome/components/xl9535/xl9535.cpp create mode 100644 esphome/components/xl9535/xl9535.h diff --git a/CODEOWNERS b/CODEOWNERS index 595e4a5684..93a599d7fd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -318,4 +318,5 @@ esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_mhoc303/* @drug123 esphome/components/xiaomi_mhoc401/* @vevsvevs esphome/components/xiaomi_rtcgq02lm/* @jesserockz +esphome/components/xl9535/* @mreditor97 esphome/components/xpt2046/* @nielsnl68 @numo68 diff --git a/esphome/components/xl9535/__init__.py b/esphome/components/xl9535/__init__.py new file mode 100644 index 0000000000..7fcac50ba7 --- /dev/null +++ b/esphome/components/xl9535/__init__.py @@ -0,0 +1,73 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from esphome.const import ( + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, +) +from esphome import pins + +CONF_XL9535 = "xl9535" + +DEPENDENCIES = ["i2c"] +CODEOWNERS = ["@mreditor97"] + +xl9535_ns = cg.esphome_ns.namespace(CONF_XL9535) + +XL9535Component = xl9535_ns.class_("XL9535Component", cg.Component, i2c.I2CDevice) +XL9535GPIOPin = xl9535_ns.class_("XL9535GPIOPin", cg.GPIOPin) + +MULTI_CONF = True +CONFIG_SCHEMA = ( + cv.Schema({cv.Required(CONF_ID): cv.declare_id(XL9535Component)}) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x20)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +def validate_mode(mode): + if not (mode[CONF_INPUT] or mode[CONF_OUTPUT]) or ( + mode[CONF_INPUT] and mode[CONF_OUTPUT] + ): + raise cv.Invalid("Mode must be either a input or a output") + return mode + + +XL9535_PIN_SCHEMA = cv.All( + { + cv.GenerateID(): cv.declare_id(XL9535GPIOPin), + cv.Required(CONF_XL9535): cv.use_id(XL9535Component), + cv.Required(CONF_NUMBER): cv.int_range(min=0, max=15), + cv.Optional(CONF_MODE, default={}): cv.All( + { + cv.Optional(CONF_INPUT, default=False): cv.boolean, + cv.Optional(CONF_OUTPUT, default=False): cv.boolean, + }, + validate_mode, + ), + cv.Optional(CONF_INVERTED, default=False): cv.boolean, + } +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_XL9535, XL9535_PIN_SCHEMA) +async def xl9535_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_XL9535]) + + cg.add(var.set_parent(parent)) + cg.add(var.set_pin(config[CONF_NUMBER])) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + + return var diff --git a/esphome/components/xl9535/xl9535.cpp b/esphome/components/xl9535/xl9535.cpp new file mode 100644 index 0000000000..8f4f556b4a --- /dev/null +++ b/esphome/components/xl9535/xl9535.cpp @@ -0,0 +1,122 @@ +#include "xl9535.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace xl9535 { + +static const char *const TAG = "xl9535"; + +void XL9535Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up XL9535..."); + + // Check to see if the device can read from the register + uint8_t port = 0; + if (this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { + this->mark_failed(); + return; + } +} + +void XL9535Component::dump_config() { + ESP_LOGCONFIG(TAG, "XL9535:"); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with XL9535 failed!"); + } +} + +bool XL9535Component::digital_read(uint8_t pin) { + bool state = false; + uint8_t port = 0; + + if (pin > 7) { + if (this->read_register(XL9535_INPUT_PORT_1_REGISTER, &port, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return state; + } + + state = (port & (pin - 10)) != 0; + } else { + if (this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return state; + } + + state = (port & pin) != 0; + } + + this->status_clear_warning(); + return state; +} + +void XL9535Component::digital_write(uint8_t pin, bool value) { + uint8_t port = 0; + uint8_t register_data = 0; + + if (pin > 7) { + if (this->read_register(XL9535_OUTPUT_PORT_1_REGISTER, ®ister_data, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + register_data = register_data & (~(1 << (pin - 10))); + port = register_data | value << (pin - 10); + + if (this->write_register(XL9535_OUTPUT_PORT_1_REGISTER, &port, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + } else { + if (this->read_register(XL9535_OUTPUT_PORT_0_REGISTER, ®ister_data, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + register_data = register_data & (~(1 << pin)); + port = register_data | value << pin; + + if (this->write_register(XL9535_OUTPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + } + + this->status_clear_warning(); +} + +void XL9535Component::pin_mode(uint8_t pin, gpio::Flags mode) { + uint8_t port = 0; + + if (pin > 7) { + this->read_register(XL9535_CONFIG_PORT_1_REGISTER, &port, 1); + + if (mode == gpio::FLAG_INPUT) { + port = port | (1 << (pin - 10)); + } else if (mode == gpio::FLAG_OUTPUT) { + port = port & (~(1 << (pin - 10))); + } + + this->write_register(XL9535_CONFIG_PORT_1_REGISTER, &port, 1); + } else { + this->read_register(XL9535_CONFIG_PORT_0_REGISTER, &port, 1); + + if (mode == gpio::FLAG_INPUT) { + port = port | (1 << pin); + } else if (mode == gpio::FLAG_OUTPUT) { + port = port & (~(1 << pin)); + } + + this->write_register(XL9535_CONFIG_PORT_0_REGISTER, &port, 1); + } +} + +void XL9535GPIOPin::setup() { this->pin_mode(this->flags_); } + +std::string XL9535GPIOPin::dump_summary() const { return str_snprintf("%u via XL9535", 15, this->pin_); } + +void XL9535GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } +bool XL9535GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } +void XL9535GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } + +} // namespace xl9535 +} // namespace esphome diff --git a/esphome/components/xl9535/xl9535.h b/esphome/components/xl9535/xl9535.h new file mode 100644 index 0000000000..8f0a868c42 --- /dev/null +++ b/esphome/components/xl9535/xl9535.h @@ -0,0 +1,54 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace xl9535 { + +enum { + XL9535_INPUT_PORT_0_REGISTER = 0x00, + XL9535_INPUT_PORT_1_REGISTER = 0x01, + XL9535_OUTPUT_PORT_0_REGISTER = 0x02, + XL9535_OUTPUT_PORT_1_REGISTER = 0x03, + XL9535_INVERSION_PORT_0_REGISTER = 0x04, + XL9535_INVERSION_PORT_1_REGISTER = 0x05, + XL9535_CONFIG_PORT_0_REGISTER = 0x06, + XL9535_CONFIG_PORT_1_REGISTER = 0x07, +}; + +class XL9535Component : public Component, public i2c::I2CDevice { + public: + bool digital_read(uint8_t pin); + void digital_write(uint8_t pin, bool value); + void pin_mode(uint8_t pin, gpio::Flags mode); + + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } +}; + +class XL9535GPIOPin : public GPIOPin { + public: + void set_parent(XL9535Component *parent) { this->parent_ = parent; } + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } + + void setup() override; + std::string dump_summary() const override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + + protected: + XL9535Component *parent_; + + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +} // namespace xl9535 +} // namespace esphome diff --git a/tests/test4.yaml b/tests/test4.yaml index 8e76a5fd66..3c9f9f610c 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -384,6 +384,15 @@ binary_sensor: pullup: true inverted: false + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + climate: - platform: tuya id: tuya_climate @@ -745,3 +754,7 @@ voice_assistant: max6956: - id: max6956_1 address: 0x40 + +xl9535: + - id: xl9535_hub + address: 0x20 From 5a8b7c17daf7152e8f56a1966ee8f921d016fbce Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 20 Jun 2023 09:08:23 +1200 Subject: [PATCH 0100/2607] Fix python venv restoring (#4965) * Fix python venv restoring * Add shell * Fix indentation --- .github/actions/restore-python/action.yml | 38 ++++++++++ .github/workflows/ci.yml | 90 +++++++++++------------ 2 files changed, 81 insertions(+), 47 deletions(-) create mode 100644 .github/actions/restore-python/action.yml diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml new file mode 100644 index 0000000000..c6e9ca4153 --- /dev/null +++ b/.github/actions/restore-python/action.yml @@ -0,0 +1,38 @@ +name: Restore Python +inputs: + python-version: + description: Python version to restore + required: true + type: string + cache-key: + description: Cache key to use + required: true + type: string +outputs: + python-version: + description: Python version restored + value: ${{ steps.python.outputs.python-version }} +runs: + using: "composite" + steps: + - name: Set up Python ${{ inputs.python-version }} + id: python + uses: actions/setup-python@v4.6.0 + with: + python-version: ${{ inputs.python-version }} + - name: Restore Python virtual environment + id: cache-venv + uses: actions/cache/restore@v3.3.1 + with: + path: venv + # yamllint disable-line rule:line-length + key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ inputs.cache-key }} + - name: Create Python virtual environment + if: steps.cache-venv.outputs.cache-hit != 'true' + shell: bash + run: | + python -m venv venv + . venv/bin/activate + python --version + pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt + pip install -e . diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95e7619a19..105f0f12b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,10 +26,16 @@ jobs: common: name: Create common environment runs-on: ubuntu-latest + outputs: + cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 + - name: Generate cache-key + id: cache-key + run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} + id: python uses: actions/setup-python@v4.6.0 with: python-version: ${{ env.DEFAULT_PYTHON }} @@ -39,7 +45,7 @@ jobs: with: path: venv # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ steps.cache-key.outputs.key }} - name: Create Python virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | @@ -66,12 +72,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Run black run: | . venv/bin/activate @@ -88,12 +93,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Run flake8 run: | . venv/bin/activate @@ -110,12 +114,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Run pylint run: | . venv/bin/activate @@ -132,12 +135,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Run pyupgrade run: | . venv/bin/activate @@ -154,12 +156,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Register matcher run: echo "::add-matcher::.github/workflows/matchers/ci-custom.json" - name: Run script/ci-custom @@ -176,12 +177,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Register matcher run: echo "::add-matcher::.github/workflows/matchers/pytest.json" - name: Run pytest @@ -197,12 +197,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Install clang-format run: | . venv/bin/activate @@ -237,12 +236,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Cache platformio uses: actions/cache@v3.3.1 with: @@ -300,13 +298,11 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v3.5.2 - - name: Restore Python virtual environment - uses: actions/cache/restore@v3.3.1 + - name: Restore Python + uses: ./.github/actions/restore-python with: - path: venv - # yamllint disable-line rule:line-length - key: ${{ runner.os }}-${{ env.DEFAULT_PYTHON }}-venv-${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }} - # Use per check platformio cache because checks use different parts + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} - name: Cache platformio uses: actions/cache@v3.3.1 with: From 7ceb16cc5a4b078eebe0e67e82462f16faee9f1f Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 20 Jun 2023 00:34:46 +0200 Subject: [PATCH 0101/2607] Preprocess away unused code when IPv6 is disabled (#4973) --- esphome/components/wifi/wifi_component_esp_idf.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index e18d3cc043..744fc755fe 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -58,7 +58,9 @@ struct IDFWiFiEvent { wifi_event_ap_probe_req_rx_t ap_probe_req_rx; wifi_event_bss_rssi_low_t bss_rssi_low; ip_event_got_ip_t ip_got_ip; +#if LWIP_IPV6 ip_event_got_ip6_t ip_got_ip6; +#endif ip_event_ap_staipassigned_t ip_ap_staipassigned; } data; }; @@ -82,8 +84,10 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi memcpy(&event.data.sta_disconnected, event_data, sizeof(wifi_event_sta_disconnected_t)); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { memcpy(&event.data.ip_got_ip, event_data, sizeof(ip_event_got_ip_t)); +#if LWIP_IPV6 } else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) { memcpy(&event.data.ip_got_ip6, event_data, sizeof(ip_event_got_ip6_t)); +#endif } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) { // NOLINT(bugprone-branch-clone) // no data } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) { @@ -504,7 +508,9 @@ const char *get_auth_mode_str(uint8_t mode) { } std::string format_ip4_addr(const esp_ip4_addr_t &ip) { return str_snprintf(IPSTR, 15, IP2STR(&ip)); } +#if LWIP_IPV6 std::string format_ip6_addr(const esp_ip6_addr_t &ip) { return str_snprintf(IPV6STR, 39, IPV62STR(ip)); } +#endif const char *get_disconnect_reason_str(uint8_t reason) { switch (reason) { case WIFI_REASON_AUTH_EXPIRE: @@ -644,9 +650,11 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { format_ip4_addr(it.ip_info.gw).c_str()); s_sta_got_ip = true; +#if LWIP_IPV6 } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) { const auto &it = data->data.ip_got_ip6; ESP_LOGV(TAG, "Event: Got IPv6 address=%s", format_ip6_addr(it.ip6_info.ip).c_str()); +#endif } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) { ESP_LOGV(TAG, "Event: Lost IP"); From b2ccd32cd7d81034febdb551142394977c8b806c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:35:26 +1200 Subject: [PATCH 0102/2607] Bump aioesphomeapi from 14.0.0 to 14.1.0 (#4972) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b994de1932..e0d6108526 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6 click==8.1.3 esphome-dashboard==20230516.0 -aioesphomeapi==14.0.0 +aioesphomeapi==14.1.0 zeroconf==0.63.0 # esp-idf requires this, but doesn't bundle it by default From ee12c68b8faa24241941033d7259e08958b41fef Mon Sep 17 00:00:00 2001 From: guillempages Date: Tue, 20 Jun 2023 00:50:02 +0200 Subject: [PATCH 0103/2607] Add actions to animation (#4959) --- esphome/components/animation/__init__.py | 45 ++++++++++++++++++++++-- esphome/components/display/animation.h | 30 ++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index f51d115d9e..8a39ec5a87 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -1,6 +1,6 @@ import logging -from esphome import core +from esphome import automation, core from esphome.components import display, font import esphome.components.image as espImage from esphome.components.image import CONF_USE_TRANSPARENCY @@ -18,15 +18,28 @@ from esphome.core import CORE, HexInt _LOGGER = logging.getLogger(__name__) +CODEOWNERS = ["@syndlex"] DEPENDENCIES = ["display"] MULTI_CONF = True CONF_LOOP = "loop" CONF_START_FRAME = "start_frame" CONF_END_FRAME = "end_frame" +CONF_FRAME = "frame" Animation_ = display.display_ns.class_("Animation", espImage.Image_) +# Actions +NextFrameAction = display.display_ns.class_( + "AnimationNextFrameAction", automation.Action, cg.Parented.template(Animation_) +) +PrevFrameAction = display.display_ns.class_( + "AnimationPrevFrameAction", automation.Action, cg.Parented.template(Animation_) +) +SetFrameAction = display.display_ns.class_( + "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_) +) + def validate_cross_dependencies(config): """ @@ -74,7 +87,35 @@ ANIMATION_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA) -CODEOWNERS = ["@syndlex"] +NEXT_FRAME_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(Animation_), + } +) +PREV_FRAME_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(Animation_), + } +) +SET_FRAME_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(Animation_), + cv.Required(CONF_FRAME): cv.uint16_t, + } +) + + +@automation.register_action("animation.next_frame", NextFrameAction, NEXT_FRAME_SCHEMA) +@automation.register_action("animation.prev_frame", PrevFrameAction, PREV_FRAME_SCHEMA) +@automation.register_action("animation.set_frame", SetFrameAction, SET_FRAME_SCHEMA) +async def animation_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + if CONF_FRAME in config: + template_ = await cg.templatable(config[CONF_FRAME], args, cg.uint16) + cg.add(var.set_frame(template_)) + return var async def to_code(config): diff --git a/esphome/components/display/animation.h b/esphome/components/display/animation.h index 38e632ccf0..3371cd9e71 100644 --- a/esphome/components/display/animation.h +++ b/esphome/components/display/animation.h @@ -1,6 +1,8 @@ #pragma once #include "image.h" +#include "esphome/core/automation.h" + namespace esphome { namespace display { @@ -33,5 +35,33 @@ class Animation : public Image { int loop_current_iteration_; }; +template class AnimationNextFrameAction : public Action { + public: + AnimationNextFrameAction(Animation *parent) : parent_(parent) {} + void play(Ts... x) override { this->parent_->next_frame(); } + + protected: + Animation *parent_; +}; + +template class AnimationPrevFrameAction : public Action { + public: + AnimationPrevFrameAction(Animation *parent) : parent_(parent) {} + void play(Ts... x) override { this->parent_->prev_frame(); } + + protected: + Animation *parent_; +}; + +template class AnimationSetFrameAction : public Action { + public: + AnimationSetFrameAction(Animation *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(uint16_t, frame) + void play(Ts... x) override { this->parent_->set_frame(this->frame_.value(x...)); } + + protected: + Animation *parent_; +}; + } // namespace display } // namespace esphome From 5ba04eb620aebfa76d50e34fb4f1949493daf813 Mon Sep 17 00:00:00 2001 From: Hawawa McTaru <86658622+TaruDesigns@users.noreply.github.com> Date: Mon, 19 Jun 2023 01:20:32 +0200 Subject: [PATCH 0104/2607] Fix for Fujitsu AC not having Quiet Fan Mode (#4962) --- esphome/components/fujitsu_general/fujitsu_general.cpp | 7 +++++-- esphome/components/fujitsu_general/fujitsu_general.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/fujitsu_general/fujitsu_general.cpp b/esphome/components/fujitsu_general/fujitsu_general.cpp index 291af8c8cd..6c7adebfea 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.cpp +++ b/esphome/components/fujitsu_general/fujitsu_general.cpp @@ -151,11 +151,13 @@ void FujitsuGeneralClimate::transmit_state() { case climate::CLIMATE_FAN_LOW: SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_LOW); break; + case climate::CLIMATE_FAN_QUIET: + SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_SILENT); + break; case climate::CLIMATE_FAN_AUTO: default: SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_AUTO); break; - // TODO Quiet / Silent } // Set swing @@ -345,8 +347,9 @@ bool FujitsuGeneralClimate::on_receive(remote_base::RemoteReceiveData data) { const uint8_t recv_fan_mode = GET_NIBBLE(recv_message, FUJITSU_GENERAL_FAN_NIBBLE); ESP_LOGV(TAG, "Received fan mode %X", recv_fan_mode); switch (recv_fan_mode) { - // TODO No Quiet / Silent in ESPH case FUJITSU_GENERAL_FAN_SILENT: + this->fan_mode = climate::CLIMATE_FAN_QUIET; + break; case FUJITSU_GENERAL_FAN_LOW: this->fan_mode = climate::CLIMATE_FAN_LOW; break; diff --git a/esphome/components/fujitsu_general/fujitsu_general.h b/esphome/components/fujitsu_general/fujitsu_general.h index ee83ae9d19..d7d01bf6f3 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.h +++ b/esphome/components/fujitsu_general/fujitsu_general.h @@ -52,7 +52,7 @@ class FujitsuGeneralClimate : public climate_ir::ClimateIR { FujitsuGeneralClimate() : ClimateIR(FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1.0f, true, true, {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, - climate::CLIMATE_FAN_HIGH}, + climate::CLIMATE_FAN_HIGH, climate::CLIMATE_FAN_QUIET}, {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {} From 76e947651dc54f2e884103de6b7f47f29f287bb5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Jun 2023 18:35:47 -0500 Subject: [PATCH 0105/2607] Store app comment and compilation_time in flash (#4945) --- esphome/core/application.cpp | 2 +- esphome/core/application.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index c012195f34..d82a7a5d37 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -99,7 +99,7 @@ void Application::loop() { if (this->dump_config_at_ < this->components_.size()) { if (this->dump_config_at_ == 0) { - ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str()); + ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_); #ifdef ESPHOME_PROJECT_NAME ESP_LOGI(TAG, "Project " ESPHOME_PROJECT_NAME " version " ESPHOME_PROJECT_VERSION); #endif diff --git a/esphome/core/application.h b/esphome/core/application.h index 0501d1a56a..054f2ea648 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -56,7 +56,7 @@ namespace esphome { class Application { public: - void pre_setup(const std::string &name, const std::string &friendly_name, const std::string &comment, + void pre_setup(const std::string &name, const std::string &friendly_name, const char *comment, const char *compilation_time, bool name_add_mac_suffix) { arch_init(); this->name_add_mac_suffix_ = name_add_mac_suffix; @@ -154,11 +154,11 @@ class Application { /// Get the friendly name of this Application set by pre_setup(). const std::string &get_friendly_name() const { return this->friendly_name_; } /// Get the comment of this Application set by pre_setup(). - const std::string &get_comment() const { return this->comment_; } + std::string get_comment() const { return this->comment_; } bool is_name_add_mac_suffix_enabled() const { return this->name_add_mac_suffix_; } - const std::string &get_compilation_time() const { return this->compilation_time_; } + std::string get_compilation_time() const { return this->compilation_time_; } /** Set the target interval with which to run the loop() calls. * If the loop() method takes longer than the target interval, ESPHome won't @@ -376,8 +376,8 @@ class Application { std::string name_; std::string friendly_name_; - std::string comment_; - std::string compilation_time_; + const char *comment_{nullptr}; + const char *compilation_time_{nullptr}; bool name_add_mac_suffix_; uint32_t last_loop_{0}; uint32_t loop_interval_{16}; From 959e7745a6809310f9ac16464e6ff45efd8521a0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Jun 2023 20:51:19 -0500 Subject: [PATCH 0106/2607] Construct web_server assets at build time instead of run time (#4944) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/web_server/__init__.py | 49 ++++++++++++++--- esphome/components/web_server/web_server.cpp | 53 ++++++++----------- esphome/components/web_server/web_server.h | 42 ++++++++++++--- .../web_server_base/web_server_base.h | 1 + 4 files changed, 100 insertions(+), 45 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index d8343c6c39..130c082277 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -81,6 +81,37 @@ CONFIG_SCHEMA = cv.All( ) +def build_index_html(config) -> str: + html = "" + css_include = config.get(CONF_CSS_INCLUDE) + js_include = config.get(CONF_JS_INCLUDE) + if css_include: + html += "" + if config[CONF_CSS_URL]: + html += f'' + html += "" + if js_include: + html += "" + html += "" + if config[CONF_JS_URL]: + html += f'' + html += "" + return html + + +def add_resource_as_progmem(resource_name: str, content: str) -> None: + """Add a resource to progmem.""" + content_encoded = content.encode("utf-8") + content_encoded_size = len(content_encoded) + bytes_as_int = ", ".join(str(x) for x in content_encoded) + uint8_t = f"const uint8_t ESPHOME_WEBSERVER_{resource_name}[{content_encoded_size}] PROGMEM = {{{bytes_as_int}}}" + size_t = ( + f"const size_t ESPHOME_WEBSERVER_{resource_name}_SIZE = {content_encoded_size}" + ) + cg.add_global(cg.RawExpression(uint8_t)) + cg.add_global(cg.RawExpression(size_t)) + + @coroutine_with_priority(40.0) async def to_code(config): paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) @@ -89,13 +120,17 @@ async def to_code(config): await cg.register_component(var, config) cg.add_define("USE_WEBSERVER") + version = config[CONF_VERSION] cg.add(paren.set_port(config[CONF_PORT])) cg.add_define("USE_WEBSERVER") cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) - cg.add_define("USE_WEBSERVER_VERSION", config[CONF_VERSION]) - cg.add(var.set_css_url(config[CONF_CSS_URL])) - cg.add(var.set_js_url(config[CONF_JS_URL])) + cg.add_define("USE_WEBSERVER_VERSION", version) + if version == 2: + add_resource_as_progmem("INDEX_HTML", build_index_html(config)) + else: + cg.add(var.set_css_url(config[CONF_CSS_URL])) + cg.add(var.set_js_url(config[CONF_JS_URL])) cg.add(var.set_allow_ota(config[CONF_OTA])) if CONF_AUTH in config: cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME])) @@ -103,13 +138,13 @@ async def to_code(config): if CONF_CSS_INCLUDE in config: cg.add_define("USE_WEBSERVER_CSS_INCLUDE") path = CORE.relative_config_path(config[CONF_CSS_INCLUDE]) - with open(file=path, encoding="utf-8") as myfile: - cg.add(var.set_css_include(myfile.read())) + with open(file=path, encoding="utf-8") as css_file: + add_resource_as_progmem("CSS_INCLUDE", css_file.read()) if CONF_JS_INCLUDE in config: cg.add_define("USE_WEBSERVER_JS_INCLUDE") path = CORE.relative_config_path(config[CONF_JS_INCLUDE]) - with open(file=path, encoding="utf-8") as myfile: - cg.add(var.set_js_include(myfile.read())) + with open(file=path, encoding="utf-8") as js_file: + add_resource_as_progmem("JS_INCLUDE", js_file.read()) cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL])) if CONF_LOCAL in config and config[CONF_LOCAL]: cg.add_define("USE_WEBSERVER_LOCAL") diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 1ac94375c2..b3a2dfdb66 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -90,10 +90,17 @@ WebServer::WebServer(web_server_base::WebServerBase *base) #endif } +#if USE_WEBSERVER_VERSION == 1 void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; } -void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; } void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; } +#endif + +#ifdef USE_WEBSERVER_CSS_INCLUDE +void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; } +#endif +#ifdef USE_WEBSERVER_JS_INCLUDE void WebServer::set_js_include(const char *js_include) { this->js_include_ = js_include; } +#endif void WebServer::setup() { ESP_LOGCONFIG(TAG, "Setting up web server..."); @@ -159,20 +166,14 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { response->addHeader("Content-Encoding", "gzip"); request->send(response); } -#else +#elif USE_WEBSERVER_VERSION == 1 void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncResponseStream *stream = request->beginResponseStream("text/html"); - // All content is controlled and created by user - so allowing all origins is fine here. - stream->addHeader("Access-Control-Allow-Origin", "*"); -#if USE_WEBSERVER_VERSION == 1 const std::string &title = App.get_name(); stream->print(F("")); stream->print(title.c_str()); stream->print(F("")); -#else - stream->print(F("")); -#endif #ifdef USE_WEBSERVER_CSS_INCLUDE stream->print(F("")); #endif @@ -182,7 +183,6 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("\">")); } stream->print(F("")); -#if USE_WEBSERVER_VERSION == 1 stream->print(F("

")); stream->print(title.c_str()); stream->print(F("

")); @@ -308,49 +308,40 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { "type=\"file\" name=\"update\">")); } stream->print(F("

Debug Log

"));
-#endif
 #ifdef USE_WEBSERVER_JS_INCLUDE
   if (this->js_include_ != nullptr) {
     stream->print(F(""));
   }
-#endif
-#if USE_WEBSERVER_VERSION == 2
-  stream->print(F(""));
 #endif
   if (strlen(this->js_url_) > 0) {
     stream->print(F(""));
   }
-#if USE_WEBSERVER_VERSION == 1
   stream->print(F("
")); -#else - stream->print(F("")); -#endif - request->send(stream); } +#elif USE_WEBSERVER_VERSION == 2 +void WebServer::handle_index_request(AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); + request->send(response); +} #endif + #ifdef USE_WEBSERVER_CSS_INCLUDE void WebServer::handle_css_request(AsyncWebServerRequest *request) { - AsyncResponseStream *stream = request->beginResponseStream("text/css"); - if (this->css_include_ != nullptr) { - stream->print(this->css_include_); - } - - request->send(stream); + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/css", ESPHOME_WEBSERVER_CSS_INCLUDE, ESPHOME_WEBSERVER_CSS_INCLUDE_SIZE); + request->send(response); } #endif #ifdef USE_WEBSERVER_JS_INCLUDE void WebServer::handle_js_request(AsyncWebServerRequest *request) { - AsyncResponseStream *stream = request->beginResponseStream("text/javascript"); - if (this->js_include_ != nullptr) { - stream->addHeader("Access-Control-Allow-Origin", "*"); - stream->print(this->js_include_); - } - - request->send(stream); + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/javascript", ESPHOME_WEBSERVER_JS_INCLUDE, ESPHOME_WEBSERVER_JS_INCLUDE_SIZE); + request->send(response); } #endif diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 45d0bc03a4..a664bb5a12 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -14,6 +14,22 @@ #include #include #endif + +#if USE_WEBSERVER_VERSION == 2 +extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; +#endif + +#ifdef USE_WEBSERVER_CSS_INCLUDE +extern const uint8_t ESPHOME_WEBSERVER_CSS_INCLUDE[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_CSS_INCLUDE_SIZE; +#endif + +#ifdef USE_WEBSERVER_JS_INCLUDE +extern const uint8_t ESPHOME_WEBSERVER_JS_INCLUDE[] PROGMEM; +extern const size_t ESPHOME_WEBSERVER_JS_INCLUDE_SIZE; +#endif + namespace esphome { namespace web_server { @@ -40,6 +56,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { public: WebServer(web_server_base::WebServerBase *base); +#if USE_WEBSERVER_VERSION == 1 /** Set the URL to the CSS that's sent to each client. Defaults to * https://esphome.io/_static/webserver-v1.min.css * @@ -47,24 +64,29 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { */ void set_css_url(const char *css_url); - /** Set local path to the script that's embedded in the index page. Defaults to - * - * @param css_include Local path to web server script. - */ - void set_css_include(const char *css_include); - /** Set the URL to the script that's embedded in the index page. Defaults to * https://esphome.io/_static/webserver-v1.min.js * * @param js_url The url to the web server script. */ void set_js_url(const char *js_url); +#endif +#ifdef USE_WEBSERVER_CSS_INCLUDE + /** Set local path to the script that's embedded in the index page. Defaults to + * + * @param css_include Local path to web server script. + */ + void set_css_include(const char *css_include); +#endif + +#ifdef USE_WEBSERVER_JS_INCLUDE /** Set local path to the script that's embedded in the index page. Defaults to * * @param js_include Local path to web server script. */ void set_js_include(const char *js_include); +#endif /** Determine whether internal components should be displayed on the web server. * Defaults to false. @@ -240,10 +262,16 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { web_server_base::WebServerBase *base_; AsyncEventSource events_{"/events"}; ListEntitiesIterator entities_iterator_; +#if USE_WEBSERVER_VERSION == 1 const char *css_url_{nullptr}; - const char *css_include_{nullptr}; const char *js_url_{nullptr}; +#endif +#ifdef USE_WEBSERVER_CSS_INCLUDE + const char *css_include_{nullptr}; +#endif +#ifdef USE_WEBSERVER_JS_INCLUDE const char *js_include_{nullptr}; +#endif bool include_internal_{false}; bool allow_ota_{true}; #ifdef USE_ESP32 diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index f6d3a84f89..ae286b1e22 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -83,6 +83,7 @@ class WebServerBase : public Component { return; } this->server_ = std::make_shared(this->port_); + // All content is controlled and created by user - so allowing all origins is fine here. DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); this->server_->begin(); From 5513b0e121776616485527d67e4d47f75a7e66a5 Mon Sep 17 00:00:00 2001 From: Stanislav Habich Date: Mon, 19 Jun 2023 03:56:12 +0200 Subject: [PATCH 0107/2607] Update pca9685_output.cpp (#4929) --- esphome/components/pca9685/pca9685_output.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/pca9685/pca9685_output.cpp b/esphome/components/pca9685/pca9685_output.cpp index c61251b66f..d92312355a 100644 --- a/esphome/components/pca9685/pca9685_output.cpp +++ b/esphome/components/pca9685/pca9685_output.cpp @@ -29,13 +29,10 @@ void PCA9685Output::setup() { ESP_LOGCONFIG(TAG, "Setting up PCA9685OutputComponent..."); ESP_LOGV(TAG, " Resetting devices..."); - uint8_t address_tmp = this->address_; - this->set_i2c_address(0x00); if (!this->write_bytes(PCA9685_REGISTER_SOFTWARE_RESET, nullptr, 0)) { this->mark_failed(); return; } - this->set_i2c_address(address_tmp); if (!this->write_byte(PCA9685_REGISTER_MODE1, PCA9685_MODE1_RESTART | PCA9685_MODE1_AUTOINC)) { this->mark_failed(); From 501fe837104b0ecee6f3733ad6257907ff86cb9b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:10:48 +1200 Subject: [PATCH 0108/2607] Bump version to 2023.6.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d4cfd30c32..8d15ede755 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b2" +__version__ = "2023.6.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 24067312f68aedfa3c360f823210853464fa2723 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:18:06 +1200 Subject: [PATCH 0109/2607] Bump zeroconf from 0.63.0 to 0.69.0 (#4970) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e0d6108526..269405d55e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6 click==8.1.3 esphome-dashboard==20230516.0 aioesphomeapi==14.1.0 -zeroconf==0.63.0 +zeroconf==0.69.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From bfe85dd710fc1d34dd9413d268f72999b546ad2c Mon Sep 17 00:00:00 2001 From: Martin Murray Date: Tue, 20 Jun 2023 19:53:21 -0400 Subject: [PATCH 0110/2607] Apply configured IIR filter setting in generated BMP280 code (#4975) Co-authored-by: Martin Murray --- esphome/components/bmp280/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index 95a9577f7e..e80511a509 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -94,3 +94,5 @@ async def to_code(config): sens = await sensor.new_sensor(conf) cg.add(var.set_pressure_sensor(sens)) cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) + + cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) From cb5a01da29001759eb2deb0e8866e9be311e4baf Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Wed, 21 Jun 2023 02:53:32 +0300 Subject: [PATCH 0111/2607] mqtt: add ESP-IDF >= 5.0 support (#4854) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mqtt/mqtt_backend_idf.cpp | 39 +++++++++++++++++++- esphome/components/mqtt/mqtt_backend_idf.h | 2 + esphome/components/mqtt/mqtt_component.cpp | 2 +- esphome/components/mqtt/mqtt_sensor.cpp | 3 +- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/esphome/components/mqtt/mqtt_backend_idf.cpp b/esphome/components/mqtt/mqtt_backend_idf.cpp index 812e36d522..7a7aca3fa6 100644 --- a/esphome/components/mqtt/mqtt_backend_idf.cpp +++ b/esphome/components/mqtt/mqtt_backend_idf.cpp @@ -11,6 +11,7 @@ namespace mqtt { static const char *const TAG = "mqtt.idf"; bool MQTTBackendIDF::initialize_() { +#if ESP_IDF_VERSION_MAJOR < 5 mqtt_cfg_.user_context = (void *) this; mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE; @@ -47,6 +48,41 @@ bool MQTTBackendIDF::initialize_() { } else { mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP; } +#else + mqtt_cfg_.broker.address.hostname = this->host_.c_str(); + mqtt_cfg_.broker.address.port = this->port_; + mqtt_cfg_.session.keepalive = this->keep_alive_; + mqtt_cfg_.session.disable_clean_session = !this->clean_session_; + + if (!this->username_.empty()) { + mqtt_cfg_.credentials.username = this->username_.c_str(); + if (!this->password_.empty()) { + mqtt_cfg_.credentials.authentication.password = this->password_.c_str(); + } + } + + if (!this->lwt_topic_.empty()) { + mqtt_cfg_.session.last_will.topic = this->lwt_topic_.c_str(); + this->mqtt_cfg_.session.last_will.qos = this->lwt_qos_; + this->mqtt_cfg_.session.last_will.retain = this->lwt_retain_; + + if (!this->lwt_message_.empty()) { + mqtt_cfg_.session.last_will.msg = this->lwt_message_.c_str(); + mqtt_cfg_.session.last_will.msg_len = this->lwt_message_.size(); + } + } + + if (!this->client_id_.empty()) { + mqtt_cfg_.credentials.client_id = this->client_id_.c_str(); + } + if (ca_certificate_.has_value()) { + mqtt_cfg_.broker.verification.certificate = ca_certificate_.value().c_str(); + mqtt_cfg_.broker.verification.skip_cert_common_name_check = skip_cert_cn_check_; + mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_SSL; + } else { + mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP; + } +#endif auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_); if (mqtt_client) { handler_.reset(mqtt_client); @@ -78,9 +114,8 @@ void MQTTBackendIDF::mqtt_event_handler_(const Event &event) { case MQTT_EVENT_CONNECTED: ESP_LOGV(TAG, "MQTT_EVENT_CONNECTED"); - // TODO session present check this->is_connected_ = true; - this->on_connect_.call(!mqtt_cfg_.disable_clean_session); + this->on_connect_.call(event.session_present); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGV(TAG, "MQTT_EVENT_DISCONNECTED"); diff --git a/esphome/components/mqtt/mqtt_backend_idf.h b/esphome/components/mqtt/mqtt_backend_idf.h index 900ee9709b..9c7a5f80e9 100644 --- a/esphome/components/mqtt/mqtt_backend_idf.h +++ b/esphome/components/mqtt/mqtt_backend_idf.h @@ -22,6 +22,7 @@ struct Event { bool retain; int qos; bool dup; + bool session_present; esp_mqtt_error_codes_t error_handle; // Construct from esp_mqtt_event_t @@ -36,6 +37,7 @@ struct Event { retain(event.retain), qos(event.qos), dup(event.dup), + session_present(event.session_present), error_handle(*event.error_handle) {} }; diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index cf228efd1b..b663d7751d 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -118,7 +118,7 @@ bool MQTTComponent::send_discovery_() { } else { if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) { char friendly_name_hash[9]; - sprintf(friendly_name_hash, "%08x", fnv1_hash(this->friendly_name())); + sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name())); friendly_name_hash[8] = 0; // ensure the hash-string ends with null root[MQTT_UNIQUE_ID] = get_mac_address() + "-" + this->component_type() + "-" + friendly_name_hash; } else { diff --git a/esphome/components/mqtt/mqtt_sensor.cpp b/esphome/components/mqtt/mqtt_sensor.cpp index 4946cfb924..fff75a3c00 100644 --- a/esphome/components/mqtt/mqtt_sensor.cpp +++ b/esphome/components/mqtt/mqtt_sensor.cpp @@ -1,3 +1,4 @@ +#include #include "mqtt_sensor.h" #include "esphome/core/log.h" @@ -26,7 +27,7 @@ void MQTTSensorComponent::setup() { void MQTTSensorComponent::dump_config() { ESP_LOGCONFIG(TAG, "MQTT Sensor '%s':", this->sensor_->get_name().c_str()); if (this->get_expire_after() > 0) { - ESP_LOGCONFIG(TAG, " Expire After: %us", this->get_expire_after() / 1000); + ESP_LOGCONFIG(TAG, " Expire After: %" PRIu32 "s", this->get_expire_after() / 1000); } LOG_MQTT_COMPONENT(true, false) } From 8bd9f5065909fa0487b76f5db342f808d8e6550c Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 20 Jun 2023 19:53:44 -0400 Subject: [PATCH 0112/2607] airthings_wave: refactor to eliminate code duplication (#4910) --- CODEOWNERS | 1 + .../airthings_wave_base/__init__.py | 81 ++++++++++++ .../airthings_wave_base.cpp | 83 ++++++++++++ .../airthings_wave_base/airthings_wave_base.h | 50 ++++++++ .../airthings_wave_mini.cpp | 102 ++++----------- .../airthings_wave_mini/airthings_wave_mini.h | 34 +---- .../components/airthings_wave_mini/sensor.py | 74 ++--------- .../airthings_wave_plus.cpp | 118 +++++------------- .../airthings_wave_plus/airthings_wave_plus.h | 31 +---- .../components/airthings_wave_plus/sensor.py | 108 +++++----------- tests/test2.yaml | 6 +- 11 files changed, 317 insertions(+), 371 deletions(-) create mode 100644 esphome/components/airthings_wave_base/__init__.py create mode 100644 esphome/components/airthings_wave_base/airthings_wave_base.cpp create mode 100644 esphome/components/airthings_wave_base/airthings_wave_base.h diff --git a/CODEOWNERS b/CODEOWNERS index 93a599d7fd..94813f73dd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -17,6 +17,7 @@ esphome/components/adc/* @esphome/core esphome/components/adc128s102/* @DeerMaximum esphome/components/addressable_light/* @justfalter esphome/components/airthings_ble/* @jeromelaban +esphome/components/airthings_wave_base/* @jeromelaban @ncareau esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban esphome/components/alarm_control_panel/* @grahambrown11 diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py new file mode 100644 index 0000000000..3ff55fc6b0 --- /dev/null +++ b/esphome/components/airthings_wave_base/__init__.py @@ -0,0 +1,81 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, ble_client + +from esphome.const import ( + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, + UNIT_PERCENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, + CONF_HUMIDITY, + CONF_TVOC, + CONF_PRESSURE, + CONF_TEMPERATURE, + UNIT_PARTS_PER_BILLION, + ICON_RADIATOR, +) + +CODEOWNERS = ["@ncareau", "@jeromelaban"] + +DEPENDENCIES = ["ble_client"] + +airthings_wave_base_ns = cg.esphome_ns.namespace("airthings_wave_base") +AirthingsWaveBase = airthings_wave_base_ns.class_( + "AirthingsWaveBase", cg.PollingComponent, ble_client.BLEClientNode +) + + +BASE_SCHEMA = ( + sensor.SENSOR_SCHEMA.extend( + { + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + accuracy_decimals=0, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TVOC): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_BILLION, + icon=ICON_RADIATOR, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("5min")) + .extend(ble_client.BLE_CLIENT_SCHEMA) +) + + +async def wave_base_to_code(var, config): + await cg.register_component(var, config) + + await ble_client.register_ble_node(var, config) + + if CONF_HUMIDITY in config: + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + cg.add(var.set_humidity(sens)) + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature(sens)) + if CONF_PRESSURE in config: + sens = await sensor.new_sensor(config[CONF_PRESSURE]) + cg.add(var.set_pressure(sens)) + if CONF_TVOC in config: + sens = await sensor.new_sensor(config[CONF_TVOC]) + cg.add(var.set_tvoc(sens)) diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.cpp b/esphome/components/airthings_wave_base/airthings_wave_base.cpp new file mode 100644 index 0000000000..349d8d58eb --- /dev/null +++ b/esphome/components/airthings_wave_base/airthings_wave_base.cpp @@ -0,0 +1,83 @@ +#include "airthings_wave_base.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace airthings_wave_base { + +static const char *const TAG = "airthings_wave_base"; + +void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) { + switch (event) { + case ESP_GATTC_OPEN_EVT: { + if (param->open.status == ESP_GATT_OK) { + ESP_LOGI(TAG, "Connected successfully!"); + } + break; + } + + case ESP_GATTC_DISCONNECT_EVT: { + ESP_LOGW(TAG, "Disconnected!"); + break; + } + + case ESP_GATTC_SEARCH_CMPL_EVT: { + this->handle_ = 0; + auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); + if (chr == nullptr) { + ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), + this->sensors_data_characteristic_uuid_.to_string().c_str()); + break; + } + this->handle_ = chr->handle; + this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; + + this->request_read_values_(); + break; + } + + case ESP_GATTC_READ_CHAR_EVT: { + if (param->read.conn_id != this->parent()->get_conn_id()) + break; + if (param->read.status != ESP_GATT_OK) { + ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); + break; + } + if (param->read.handle == this->handle_) { + this->read_sensors(param->read.value, param->read.value_len); + } + break; + } + + default: + break; + } +} + +bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } + +void AirthingsWaveBase::update() { + if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { + if (!this->parent()->enabled) { + ESP_LOGW(TAG, "Reconnecting to device"); + this->parent()->set_enabled(true); + this->parent()->connect(); + } else { + ESP_LOGW(TAG, "Connection in progress"); + } + } +} + +void AirthingsWaveBase::request_read_values_() { + auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, + ESP_GATT_AUTH_REQ_NONE); + if (status) { + ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); + } +} + +} // namespace airthings_wave_base +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.h b/esphome/components/airthings_wave_base/airthings_wave_base.h new file mode 100644 index 0000000000..68c0b3497d --- /dev/null +++ b/esphome/components/airthings_wave_base/airthings_wave_base.h @@ -0,0 +1,50 @@ +#pragma once + +#ifdef USE_ESP32 + +#include +#include +#include +#include "esphome/components/ble_client/ble_client.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace airthings_wave_base { + +class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientNode { + public: + AirthingsWaveBase() = default; + + void update() override; + + void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) override; + + void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } + void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } + void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } + void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } + + protected: + bool is_valid_voc_value_(uint16_t voc); + + virtual void read_sensors(uint8_t *value, uint16_t value_len) = 0; + void request_read_values_(); + + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *humidity_sensor_{nullptr}; + sensor::Sensor *pressure_sensor_{nullptr}; + sensor::Sensor *tvoc_sensor_{nullptr}; + + uint16_t handle_; + esp32_ble_tracker::ESPBTUUID service_uuid_; + esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; +}; + +} // namespace airthings_wave_base +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp index 40873ec005..331a13434f 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp @@ -7,105 +7,47 @@ namespace airthings_wave_mini { static const char *const TAG = "airthings_wave_mini"; -void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) { - switch (event) { - case ESP_GATTC_OPEN_EVT: { - if (param->open.status == ESP_GATT_OK) { - ESP_LOGI(TAG, "Connected successfully!"); - } - break; - } - - case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGW(TAG, "Disconnected!"); - break; - } - - case ESP_GATTC_SEARCH_CMPL_EVT: { - this->handle_ = 0; - auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); - if (chr == nullptr) { - ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), - sensors_data_characteristic_uuid_.to_string().c_str()); - break; - } - this->handle_ = chr->handle; - this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; - - request_read_values_(); - break; - } - - case ESP_GATTC_READ_CHAR_EVT: { - if (param->read.conn_id != this->parent()->get_conn_id()) - break; - if (param->read.status != ESP_GATT_OK) { - ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); - break; - } - if (param->read.handle == this->handle_) { - read_sensors_(param->read.value, param->read.value_len); - } - break; - } - - default: - break; - } -} - -void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) { +void AirthingsWaveMini::read_sensors(uint8_t *raw_value, uint16_t value_len) { auto *value = (WaveMiniReadings *) raw_value; if (sizeof(WaveMiniReadings) <= value_len) { - this->humidity_sensor_->publish_state(value->humidity / 100.0f); - this->pressure_sensor_->publish_state(value->pressure / 50.0f); - this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); - if (is_valid_voc_value_(value->voc)) { + if (this->humidity_sensor_ != nullptr) { + this->humidity_sensor_->publish_state(value->humidity / 100.0f); + } + + if (this->pressure_sensor_ != nullptr) { + this->pressure_sensor_->publish_state(value->pressure / 50.0f); + } + + if (this->temperature_sensor_ != nullptr) { + this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); + } + + if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } // This instance must not stay connected // so other clients can connect to it (e.g. the // mobile app). - parent()->set_enabled(false); - } -} - -bool AirthingsWaveMini::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } - -void AirthingsWaveMini::update() { - if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { - if (!parent()->enabled) { - ESP_LOGW(TAG, "Reconnecting to device"); - parent()->set_enabled(true); - parent()->connect(); - } else { - ESP_LOGW(TAG, "Connection in progress"); - } - } -} - -void AirthingsWaveMini::request_read_values_() { - auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, - ESP_GATT_AUTH_REQ_NONE); - if (status) { - ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); + this->parent()->set_enabled(false); } } void AirthingsWaveMini::dump_config() { + // these really don't belong here, but there doesn't seem to be a + // practical way to have the base class use LOG_SENSOR and include + // the TAG from this component LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); } -AirthingsWaveMini::AirthingsWaveMini() - : PollingComponent(10000), - service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), - sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} +AirthingsWaveMini::AirthingsWaveMini() { + this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); +} } // namespace airthings_wave_mini } // namespace esphome diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.h b/esphome/components/airthings_wave_mini/airthings_wave_mini.h index 128774f9cb..ec4fd23e60 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.h +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.h @@ -2,14 +2,7 @@ #ifdef USE_ESP32 -#include -#include -#include -#include "esphome/components/ble_client/ble_client.h" -#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" -#include "esphome/components/sensor/sensor.h" -#include "esphome/core/component.h" -#include "esphome/core/log.h" +#include "esphome/components/airthings_wave_base/airthings_wave_base.h" namespace esphome { namespace airthings_wave_mini { @@ -17,35 +10,14 @@ namespace airthings_wave_mini { static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba"; -class AirthingsWaveMini : public PollingComponent, public ble_client::BLEClientNode { +class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase { public: AirthingsWaveMini(); void dump_config() override; - void update() override; - - void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) override; - - void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } - void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } - void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } - void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } protected: - bool is_valid_voc_value_(uint16_t voc); - - void read_sensors_(uint8_t *value, uint16_t value_len); - void request_read_values_(); - - sensor::Sensor *temperature_sensor_{nullptr}; - sensor::Sensor *humidity_sensor_{nullptr}; - sensor::Sensor *pressure_sensor_{nullptr}; - sensor::Sensor *tvoc_sensor_{nullptr}; - - uint16_t handle_; - esp32_ble_tracker::ESPBTUUID service_uuid_; - esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; + void read_sensors(uint8_t *value, uint16_t value_len) override; struct WaveMiniReadings { uint16_t unused01; diff --git a/esphome/components/airthings_wave_mini/sensor.py b/esphome/components/airthings_wave_mini/sensor.py index d38354fa84..0f4fd1a13a 100644 --- a/esphome/components/airthings_wave_mini/sensor.py +++ b/esphome/components/airthings_wave_mini/sensor.py @@ -1,82 +1,28 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor, ble_client +from esphome.components import airthings_wave_base from esphome.const import ( - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, - STATE_CLASS_MEASUREMENT, - UNIT_PERCENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, CONF_ID, - CONF_HUMIDITY, - CONF_TVOC, - CONF_PRESSURE, - CONF_TEMPERATURE, - UNIT_PARTS_PER_BILLION, - ICON_RADIATOR, ) -DEPENDENCIES = ["ble_client"] +DEPENDENCIES = airthings_wave_base.DEPENDENCIES + +AUTO_LOAD = ["airthings_wave_base"] airthings_wave_mini_ns = cg.esphome_ns.namespace("airthings_wave_mini") AirthingsWaveMini = airthings_wave_mini_ns.class_( - "AirthingsWaveMini", cg.PollingComponent, ble_client.BLEClientNode + "AirthingsWaveMini", airthings_wave_base.AirthingsWaveBase ) -CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(AirthingsWaveMini), - cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - unit_of_measurement=UNIT_PERCENT, - device_class=DEVICE_CLASS_HUMIDITY, - state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=2, - ), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=2, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=2, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TVOC): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - } - ) - .extend(cv.polling_component_schema("5min")) - .extend(ble_client.BLE_CLIENT_SCHEMA), +CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AirthingsWaveMini), + } ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - - await ble_client.register_ble_node(var, config) - - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) - cg.add(var.set_humidity(sens)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) - cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - sens = await sensor.new_sensor(config[CONF_PRESSURE]) - cg.add(var.set_pressure(sens)) - if CONF_TVOC in config: - sens = await sensor.new_sensor(config[CONF_TVOC]) - cg.add(var.set_tvoc(sens)) + await airthings_wave_base.wave_base_to_code(var, config) diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index 11f86307fe..acd3a4316d 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -7,55 +7,7 @@ namespace airthings_wave_plus { static const char *const TAG = "airthings_wave_plus"; -void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) { - switch (event) { - case ESP_GATTC_OPEN_EVT: { - if (param->open.status == ESP_GATT_OK) { - ESP_LOGI(TAG, "Connected successfully!"); - } - break; - } - - case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGW(TAG, "Disconnected!"); - break; - } - - case ESP_GATTC_SEARCH_CMPL_EVT: { - this->handle_ = 0; - auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); - if (chr == nullptr) { - ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), - sensors_data_characteristic_uuid_.to_string().c_str()); - break; - } - this->handle_ = chr->handle; - this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; - - request_read_values_(); - break; - } - - case ESP_GATTC_READ_CHAR_EVT: { - if (param->read.conn_id != this->parent()->get_conn_id()) - break; - if (param->read.status != ESP_GATT_OK) { - ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); - break; - } - if (param->read.handle == this->handle_) { - read_sensors_(param->read.value, param->read.value_len); - } - break; - } - - default: - break; - } -} - -void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { +void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { auto *value = (WavePlusReadings *) raw_value; if (sizeof(WavePlusReadings) <= value_len) { @@ -64,26 +16,38 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { if (value->version == 1) { ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); - this->humidity_sensor_->publish_state(value->humidity / 2.0f); - if (is_valid_radon_value_(value->radon)) { + if (this->humidity_sensor_ != nullptr) { + this->humidity_sensor_->publish_state(value->humidity / 2.0f); + } + + if ((this->radon_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon)) { this->radon_sensor_->publish_state(value->radon); } - if (is_valid_radon_value_(value->radon_lt)) { + + if ((this->radon_long_term_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon_lt)) { this->radon_long_term_sensor_->publish_state(value->radon_lt); } - this->temperature_sensor_->publish_state(value->temperature / 100.0f); - this->pressure_sensor_->publish_state(value->pressure / 50.0f); - if (is_valid_co2_value_(value->co2)) { + + if (this->temperature_sensor_ != nullptr) { + this->temperature_sensor_->publish_state(value->temperature / 100.0f); + } + + if (this->pressure_sensor_ != nullptr) { + this->pressure_sensor_->publish_state(value->pressure / 50.0f); + } + + if ((this->co2_sensor_ != nullptr) && this->is_valid_co2_value_(value->co2)) { this->co2_sensor_->publish_state(value->co2); } - if (is_valid_voc_value_(value->voc)) { + + if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } // This instance must not stay connected // so other clients can connect to it (e.g. the // mobile app). - parent()->set_enabled(false); + this->parent()->set_enabled(false); } else { ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); } @@ -92,44 +56,26 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } -bool AirthingsWavePlus::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } - bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } -void AirthingsWavePlus::update() { - if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { - if (!parent()->enabled) { - ESP_LOGW(TAG, "Reconnecting to device"); - parent()->set_enabled(true); - parent()->connect(); - } else { - ESP_LOGW(TAG, "Connection in progress"); - } - } -} - -void AirthingsWavePlus::request_read_values_() { - auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, - ESP_GATT_AUTH_REQ_NONE); - if (status) { - ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); - } -} - void AirthingsWavePlus::dump_config() { + // these really don't belong here, but there doesn't seem to be a + // practical way to have the base class use LOG_SENSOR and include + // the TAG from this component LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); - LOG_SENSOR(" ", "Radon", this->radon_sensor_); - LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); - LOG_SENSOR(" ", "CO2", this->co2_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); + + LOG_SENSOR(" ", "Radon", this->radon_sensor_); + LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); + LOG_SENSOR(" ", "CO2", this->co2_sensor_); } -AirthingsWavePlus::AirthingsWavePlus() - : PollingComponent(10000), - service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), - sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} +AirthingsWavePlus::AirthingsWavePlus() { + this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); +} } // namespace airthings_wave_plus } // namespace esphome diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.h b/esphome/components/airthings_wave_plus/airthings_wave_plus.h index 9dd6ed92d5..4acfb9279a 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.h +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.h @@ -2,14 +2,7 @@ #ifdef USE_ESP32 -#include -#include -#include -#include "esphome/components/ble_client/ble_client.h" -#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" -#include "esphome/components/sensor/sensor.h" -#include "esphome/core/component.h" -#include "esphome/core/log.h" +#include "esphome/components/airthings_wave_base/airthings_wave_base.h" namespace esphome { namespace airthings_wave_plus { @@ -17,43 +10,25 @@ namespace airthings_wave_plus { static const char *const SERVICE_UUID = "b42e1c08-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e2a68-ade7-11e4-89d3-123b93f75cba"; -class AirthingsWavePlus : public PollingComponent, public ble_client::BLEClientNode { +class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { public: AirthingsWavePlus(); void dump_config() override; - void update() override; - void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) override; - - void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } - void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } - void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } - void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } protected: bool is_valid_radon_value_(uint16_t radon); - bool is_valid_voc_value_(uint16_t voc); bool is_valid_co2_value_(uint16_t co2); - void read_sensors_(uint8_t *value, uint16_t value_len); - void request_read_values_(); + void read_sensors(uint8_t *value, uint16_t value_len) override; - sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *radon_sensor_{nullptr}; sensor::Sensor *radon_long_term_sensor_{nullptr}; - sensor::Sensor *humidity_sensor_{nullptr}; - sensor::Sensor *pressure_sensor_{nullptr}; sensor::Sensor *co2_sensor_{nullptr}; - sensor::Sensor *tvoc_sensor_{nullptr}; - - uint16_t handle_; - esp32_ble_tracker::ESPBTUUID service_uuid_; - esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; struct WavePlusReadings { uint8_t version; diff --git a/esphome/components/airthings_wave_plus/sensor.py b/esphome/components/airthings_wave_plus/sensor.py index 727fbe15fb..a5903b1d42 100644 --- a/esphome/components/airthings_wave_plus/sensor.py +++ b/esphome/components/airthings_wave_plus/sensor.py @@ -1,116 +1,64 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor, ble_client +from esphome.components import sensor, airthings_wave_base from esphome.const import ( DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, STATE_CLASS_MEASUREMENT, - UNIT_PERCENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, ICON_RADIOACTIVE, CONF_ID, CONF_RADON, CONF_RADON_LONG_TERM, - CONF_HUMIDITY, - CONF_TVOC, CONF_CO2, - CONF_PRESSURE, - CONF_TEMPERATURE, UNIT_BECQUEREL_PER_CUBIC_METER, UNIT_PARTS_PER_MILLION, - UNIT_PARTS_PER_BILLION, - ICON_RADIATOR, ) -DEPENDENCIES = ["ble_client"] +DEPENDENCIES = airthings_wave_base.DEPENDENCIES + +AUTO_LOAD = ["airthings_wave_base"] airthings_wave_plus_ns = cg.esphome_ns.namespace("airthings_wave_plus") AirthingsWavePlus = airthings_wave_plus_ns.class_( - "AirthingsWavePlus", cg.PollingComponent, ble_client.BLEClientNode + "AirthingsWavePlus", airthings_wave_base.AirthingsWaveBase ) -CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(AirthingsWavePlus), - cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - unit_of_measurement=UNIT_PERCENT, - device_class=DEVICE_CLASS_HUMIDITY, - state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=0, - ), - cv.Optional(CONF_RADON): sensor.sensor_schema( - unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, - icon=ICON_RADIOACTIVE, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( - unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, - icon=ICON_RADIOACTIVE, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=2, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_CO2): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_MILLION, - accuracy_decimals=0, - device_class=DEVICE_CLASS_CARBON_DIOXIDE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TVOC): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - } - ) - .extend(cv.polling_component_schema("5min")) - .extend(ble_client.BLE_CLIENT_SCHEMA), +CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AirthingsWavePlus), + cv.Optional(CONF_RADON): sensor.sensor_schema( + unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, + icon=ICON_RADIOACTIVE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( + unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, + icon=ICON_RADIOACTIVE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CO2): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + accuracy_decimals=0, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) + await airthings_wave_base.wave_base_to_code(var, config) - await ble_client.register_ble_node(var, config) - - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) - cg.add(var.set_humidity(sens)) if CONF_RADON in config: sens = await sensor.new_sensor(config[CONF_RADON]) cg.add(var.set_radon(sens)) if CONF_RADON_LONG_TERM in config: sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) cg.add(var.set_radon_long_term(sens)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) - cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - sens = await sensor.new_sensor(config[CONF_PRESSURE]) - cg.add(var.set_pressure(sens)) if CONF_CO2 in config: sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2(sens)) - if CONF_TVOC in config: - sens = await sensor.new_sensor(config[CONF_TVOC]) - cg.add(var.set_tvoc(sens)) diff --git a/tests/test2.yaml b/tests/test2.yaml index fa4b97c7c1..aa3e467816 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -312,7 +312,8 @@ sensor: id: freezer_temp_source reference_voltage: 3.19 number: 0 - - platform: airthings_wave_plus + - id: airthingswp + platform: airthings_wave_plus ble_client_id: airthings01 update_interval: 5min temperature: @@ -329,7 +330,8 @@ sensor: name: Wave Plus CO2 tvoc: name: Wave Plus VOC - - platform: airthings_wave_mini + - id: airthingswm + platform: airthings_wave_mini ble_client_id: airthingsmini01 update_interval: 5min temperature: From 9e7e3708e37987955e624e220f05fa424e2bdc55 Mon Sep 17 00:00:00 2001 From: Onne Date: Wed, 21 Jun 2023 02:22:32 +0200 Subject: [PATCH 0113/2607] Make growatt play nicer with other modbus components. (#4947) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../growatt_solar/growatt_solar.cpp | 31 +++++++++++++++++++ .../components/growatt_solar/growatt_solar.h | 4 +++ 2 files changed, 35 insertions(+) diff --git a/esphome/components/growatt_solar/growatt_solar.cpp b/esphome/components/growatt_solar/growatt_solar.cpp index ed753c4d3f..c4ed5ab841 100644 --- a/esphome/components/growatt_solar/growatt_solar.cpp +++ b/esphome/components/growatt_solar/growatt_solar.cpp @@ -9,11 +9,42 @@ static const char *const TAG = "growatt_solar"; static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04; static const uint8_t MODBUS_REGISTER_COUNT[] = {33, 95}; // indexed with enum GrowattProtocolVersion +void GrowattSolar::loop() { + // If update() was unable to send we retry until we can send. + if (!this->waiting_to_update_) + return; + update(); +} + void GrowattSolar::update() { + // If our last send has had no reply yet, and it wasn't that long ago, do nothing. + uint32_t now = millis(); + if (now - this->last_send_ < this->get_update_interval() / 2) { + return; + } + + // The bus might be slow, or there might be other devices, or other components might be talking to our device. + if (this->waiting_for_response()) { + this->waiting_to_update_ = true; + return; + } + + this->waiting_to_update_ = false; this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT[this->protocol_version_]); + this->last_send_ = millis(); } void GrowattSolar::on_modbus_data(const std::vector &data) { + // Other components might be sending commands to our device. But we don't get called with enough + // context to know what is what. So if we didn't do a send, we ignore the data. + if (!this->last_send_) + return; + this->last_send_ = 0; + + // Also ignore the data if the message is too short. Otherwise we will publish invalid values. + if (data.size() < MODBUS_REGISTER_COUNT[this->protocol_version_] * 2) + return; + auto publish_1_reg_sensor_state = [&](sensor::Sensor *sensor, size_t i, float unit) -> void { if (sensor == nullptr) return; diff --git a/esphome/components/growatt_solar/growatt_solar.h b/esphome/components/growatt_solar/growatt_solar.h index d1b08b534a..b0ddd4b99d 100644 --- a/esphome/components/growatt_solar/growatt_solar.h +++ b/esphome/components/growatt_solar/growatt_solar.h @@ -19,6 +19,7 @@ enum GrowattProtocolVersion { class GrowattSolar : public PollingComponent, public modbus::ModbusDevice { public: + void loop() override; void update() override; void on_modbus_data(const std::vector &data) override; void dump_config() override; @@ -55,6 +56,9 @@ class GrowattSolar : public PollingComponent, public modbus::ModbusDevice { } protected: + bool waiting_to_update_; + uint32_t last_send_; + struct GrowattPhase { sensor::Sensor *voltage_sensor_{nullptr}; sensor::Sensor *current_sensor_{nullptr}; From de6c527ca43bdcf4eeb66041da991d6f9c7ee10c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:30:19 +1200 Subject: [PATCH 0114/2607] Bump esphome-dashboard to 20230621.0 (#4980) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 269405d55e..a2ef604446 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6 click==8.1.3 -esphome-dashboard==20230516.0 +esphome-dashboard==20230621.0 aioesphomeapi==14.1.0 zeroconf==0.69.0 From 867b4719d1d87bf8db5f408a460264b694cbe8f7 Mon Sep 17 00:00:00 2001 From: Martin Murray Date: Tue, 20 Jun 2023 19:53:21 -0400 Subject: [PATCH 0115/2607] Apply configured IIR filter setting in generated BMP280 code (#4975) Co-authored-by: Martin Murray --- esphome/components/bmp280/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index 95a9577f7e..e80511a509 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -94,3 +94,5 @@ async def to_code(config): sens = await sensor.new_sensor(conf) cg.add(var.set_pressure_sensor(sens)) cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) + + cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) From 0671287b8012d18c36775915a0cfb4a19455d9e8 Mon Sep 17 00:00:00 2001 From: Onne Date: Wed, 21 Jun 2023 02:22:32 +0200 Subject: [PATCH 0116/2607] Make growatt play nicer with other modbus components. (#4947) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../growatt_solar/growatt_solar.cpp | 31 +++++++++++++++++++ .../components/growatt_solar/growatt_solar.h | 4 +++ 2 files changed, 35 insertions(+) diff --git a/esphome/components/growatt_solar/growatt_solar.cpp b/esphome/components/growatt_solar/growatt_solar.cpp index ed753c4d3f..c4ed5ab841 100644 --- a/esphome/components/growatt_solar/growatt_solar.cpp +++ b/esphome/components/growatt_solar/growatt_solar.cpp @@ -9,11 +9,42 @@ static const char *const TAG = "growatt_solar"; static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04; static const uint8_t MODBUS_REGISTER_COUNT[] = {33, 95}; // indexed with enum GrowattProtocolVersion +void GrowattSolar::loop() { + // If update() was unable to send we retry until we can send. + if (!this->waiting_to_update_) + return; + update(); +} + void GrowattSolar::update() { + // If our last send has had no reply yet, and it wasn't that long ago, do nothing. + uint32_t now = millis(); + if (now - this->last_send_ < this->get_update_interval() / 2) { + return; + } + + // The bus might be slow, or there might be other devices, or other components might be talking to our device. + if (this->waiting_for_response()) { + this->waiting_to_update_ = true; + return; + } + + this->waiting_to_update_ = false; this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT[this->protocol_version_]); + this->last_send_ = millis(); } void GrowattSolar::on_modbus_data(const std::vector &data) { + // Other components might be sending commands to our device. But we don't get called with enough + // context to know what is what. So if we didn't do a send, we ignore the data. + if (!this->last_send_) + return; + this->last_send_ = 0; + + // Also ignore the data if the message is too short. Otherwise we will publish invalid values. + if (data.size() < MODBUS_REGISTER_COUNT[this->protocol_version_] * 2) + return; + auto publish_1_reg_sensor_state = [&](sensor::Sensor *sensor, size_t i, float unit) -> void { if (sensor == nullptr) return; diff --git a/esphome/components/growatt_solar/growatt_solar.h b/esphome/components/growatt_solar/growatt_solar.h index d1b08b534a..b0ddd4b99d 100644 --- a/esphome/components/growatt_solar/growatt_solar.h +++ b/esphome/components/growatt_solar/growatt_solar.h @@ -19,6 +19,7 @@ enum GrowattProtocolVersion { class GrowattSolar : public PollingComponent, public modbus::ModbusDevice { public: + void loop() override; void update() override; void on_modbus_data(const std::vector &data) override; void dump_config() override; @@ -55,6 +56,9 @@ class GrowattSolar : public PollingComponent, public modbus::ModbusDevice { } protected: + bool waiting_to_update_; + uint32_t last_send_; + struct GrowattPhase { sensor::Sensor *voltage_sensor_{nullptr}; sensor::Sensor *current_sensor_{nullptr}; From 6c00be0a638eaa0ebb6c0ff3385dc8d7f9be44ee Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:30:19 +1200 Subject: [PATCH 0117/2607] Bump esphome-dashboard to 20230621.0 (#4980) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b994de1932..934e0b46a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6 click==8.1.3 -esphome-dashboard==20230516.0 +esphome-dashboard==20230621.0 aioesphomeapi==14.0.0 zeroconf==0.63.0 From d919373853abcfa107dbd8d39e61cc71f0e81426 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:32:53 +1200 Subject: [PATCH 0118/2607] Bump version to 2023.6.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8d15ede755..6a3286abd7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b3" +__version__ = "2023.6.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From e8ce7048d8b5d2bccbf23581c47822e2954645aa Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 16:36:54 +1200 Subject: [PATCH 0119/2607] Fix pypi release (#4983) --- .github/workflows/release.yml | 4 +++- script/setup | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ebd04e793..74ff4d87f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,9 +49,11 @@ jobs: with: python-version: "3.x" - name: Set up python environment + env: + ESPHOME_NO_VENV: 1 run: | script/setup - pip install setuptools wheel twine + pip install twine - name: Build run: python setup.py sdist bdist_wheel - name: Upload diff --git a/script/setup b/script/setup index 656e95eba6..e1b5941d0e 100755 --- a/script/setup +++ b/script/setup @@ -5,12 +5,13 @@ set -e cd "$(dirname "$0")/.." -if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ]; then +if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ] && [ ! "$ESPHOME_NO_VENV" ]; then python3 -m venv venv source venv/bin/activate fi pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt +pip3 install setuptools wheel pip3 install --no-use-pep517 -e . pre-commit install From a064ab5c2b05573f1ca91c25f0f587cb5bb8a6dc Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 16:36:54 +1200 Subject: [PATCH 0120/2607] Fix pypi release (#4983) --- .github/workflows/release.yml | 4 +++- script/setup | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ebd04e793..74ff4d87f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,9 +49,11 @@ jobs: with: python-version: "3.x" - name: Set up python environment + env: + ESPHOME_NO_VENV: 1 run: | script/setup - pip install setuptools wheel twine + pip install twine - name: Build run: python setup.py sdist bdist_wheel - name: Upload diff --git a/script/setup b/script/setup index 656e95eba6..e1b5941d0e 100755 --- a/script/setup +++ b/script/setup @@ -5,12 +5,13 @@ set -e cd "$(dirname "$0")/.." -if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ]; then +if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ] && [ ! "$ESPHOME_NO_VENV" ]; then python3 -m venv venv source venv/bin/activate fi pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt +pip3 install setuptools wheel pip3 install --no-use-pep517 -e . pre-commit install From 2047bba4f7a3e294efab85dffe77d97d22fc5c83 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Jun 2023 16:39:52 +1200 Subject: [PATCH 0121/2607] Bump version to 2023.6.0b5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 6a3286abd7..32231d5c83 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b4" +__version__ = "2023.6.0b5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 1cc7428445431f5c2b5e493ca9f240448d94a6fe Mon Sep 17 00:00:00 2001 From: Dion Hulse Date: Thu, 22 Jun 2023 07:58:49 +1000 Subject: [PATCH 0122/2607] Add configuration option to disable the log UI. (#4419) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/web_server/__init__.py | 3 +++ esphome/components/web_server/web_server.cpp | 21 +++++++++++--------- esphome/components/web_server/web_server.h | 9 +++++++++ esphome/const.py | 1 + 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 130c082277..25c0254f90 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_PASSWORD, CONF_INCLUDE_INTERNAL, CONF_OTA, + CONF_LOG, CONF_VERSION, CONF_LOCAL, ) @@ -71,6 +72,7 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean, cv.Optional(CONF_OTA, default=True): cv.boolean, + cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), @@ -132,6 +134,7 @@ async def to_code(config): cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL])) cg.add(var.set_allow_ota(config[CONF_OTA])) + cg.add(var.set_expose_log(config[CONF_LOG])) if CONF_AUTH in config: cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME])) cg.add(paren.set_auth_password(config[CONF_AUTH][CONF_PASSWORD])) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index b3a2dfdb66..eb1858a09c 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -102,6 +102,16 @@ void WebServer::set_css_include(const char *css_include) { this->css_include_ = void WebServer::set_js_include(const char *js_include) { this->js_include_ = js_include; } #endif +std::string WebServer::get_config_json() { + return json::build_json([this](JsonObject root) { + root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name(); + root["comment"] = App.get_comment(); + root["ota"] = this->allow_ota_; + root["log"] = this->expose_log_; + root["lang"] = "en"; + }); +} + void WebServer::setup() { ESP_LOGCONFIG(TAG, "Setting up web server..."); this->setup_controller(this->include_internal_); @@ -109,20 +119,13 @@ void WebServer::setup() { this->events_.onConnect([this](AsyncEventSourceClient *client) { // Configure reconnect timeout and send config - - client->send(json::build_json([this](JsonObject root) { - root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name(); - root["comment"] = App.get_comment(); - root["ota"] = this->allow_ota_; - root["lang"] = "en"; - }).c_str(), - "ping", millis(), 30000); + client->send(this->get_config_json().c_str(), "ping", millis(), 30000); this->entities_iterator_.begin(this->include_internal_); }); #ifdef USE_LOGGER - if (logger::global_logger != nullptr) { + if (logger::global_logger != nullptr && this->expose_log_) { logger::global_logger->add_on_log_callback( [this](int level, const char *tag, const char *message) { this->events_.send(message, "log", millis()); }); } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index a664bb5a12..83ebba205f 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -99,6 +99,11 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { * @param allow_ota. */ void set_allow_ota(bool allow_ota) { this->allow_ota_ = allow_ota; } + /** Set whether or not the webserver should expose the Log. + * + * @param expose_log. + */ + void set_expose_log(bool expose_log) { this->expose_log_ = expose_log; } // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -114,6 +119,9 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { /// Handle an index request under '/'. void handle_index_request(AsyncWebServerRequest *request); + /// Return the webserver configuration as JSON. + std::string get_config_json(); + #ifdef USE_WEBSERVER_CSS_INCLUDE /// Handle included css request under '/0.css'. void handle_css_request(AsyncWebServerRequest *request); @@ -274,6 +282,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { #endif bool include_internal_{false}; bool allow_ota_{true}; + bool expose_log_{true}; #ifdef USE_ESP32 std::deque> to_schedule_; SemaphoreHandle_t to_schedule_lock_; diff --git a/esphome/const.py b/esphome/const.py index f07eb49b5a..c8b85fcdeb 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -368,6 +368,7 @@ CONF_LINE_TYPE = "line_type" CONF_LOADED_INTEGRATIONS = "loaded_integrations" CONF_LOCAL = "local" CONF_LOCK_ACTION = "lock_action" +CONF_LOG = "log" CONF_LOG_TOPIC = "log_topic" CONF_LOGGER = "logger" CONF_LOGS = "logs" From 211453df43576b109d14665fe5cd55dee9e805b6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:12:25 +1200 Subject: [PATCH 0123/2607] Update webserver and captive portal pages to 67c48ee9 (#4986) --- .../components/captive_portal/captive_index.h | 190 ++- esphome/components/web_server/server_index.h | 1169 +++++++++-------- 2 files changed, 684 insertions(+), 675 deletions(-) diff --git a/esphome/components/captive_portal/captive_index.h b/esphome/components/captive_portal/captive_index.h index bf2e6e6e8b..56071f3d2a 100644 --- a/esphome/components/captive_portal/captive_index.h +++ b/esphome/components/captive_portal/captive_index.h @@ -6,102 +6,100 @@ namespace esphome { namespace captive_portal { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xdd, 0x58, 0x09, 0x6f, 0xdc, 0x36, 0x16, 0xfe, 0x2b, - 0xac, 0x92, 0x74, 0x34, 0x8d, 0xc5, 0xd1, 0x31, 0x97, 0x35, 0xd2, 0x14, 0x89, 0x37, 0x45, 0x0b, 0x24, 0x69, 0x00, - 0xbb, 0x5d, 0x14, 0x69, 0x00, 0x73, 0x24, 0x6a, 0xc4, 0x58, 0xa2, 0x54, 0x91, 0x9a, 0x23, 0x83, 0xd9, 0xdf, 0xde, - 0x47, 0x52, 0x73, 0x38, 0x6b, 0x2f, 0x90, 0x62, 0x8b, 0xa2, 0x4d, 0x6c, 0x9a, 0xc7, 0x3b, 0x3f, 0xf2, 0xf1, 0x3d, - 0x2a, 0xfa, 0x2a, 0xad, 0x12, 0xb9, 0xad, 0x29, 0xca, 0x65, 0x59, 0xcc, 0x23, 0xd5, 0xa2, 0x82, 0xf0, 0x65, 0x4c, - 0x39, 0x8c, 0x28, 0x49, 0xe7, 0x51, 0x49, 0x25, 0x41, 0x49, 0x4e, 0x1a, 0x41, 0x65, 0xfc, 0xd3, 0xcd, 0x77, 0xce, - 0x14, 0x0d, 0xe6, 0x51, 0xc1, 0xf8, 0x1d, 0x6a, 0x68, 0x11, 0xb3, 0xa4, 0xe2, 0x28, 0x6f, 0x68, 0x16, 0xa7, 0x44, - 0x92, 0x90, 0x95, 0x64, 0x49, 0x15, 0x81, 0x66, 0xe3, 0xa4, 0xa4, 0xf1, 0x8a, 0xd1, 0x75, 0x5d, 0x35, 0x12, 0x01, - 0xa5, 0xa4, 0x5c, 0xc6, 0xd6, 0x9a, 0xa5, 0x32, 0x8f, 0x53, 0xba, 0x62, 0x09, 0x75, 0xf4, 0xe0, 0x82, 0x71, 0x26, - 0x19, 0x29, 0x1c, 0x91, 0x90, 0x82, 0xc6, 0xde, 0x45, 0x2b, 0x68, 0xa3, 0x07, 0x64, 0x01, 0x63, 0x5e, 0x59, 0x20, - 0x52, 0x24, 0x0d, 0xab, 0x25, 0x52, 0xf6, 0xc6, 0x65, 0x95, 0xb6, 0x05, 0x9d, 0x67, 0x2d, 0x4f, 0x24, 0x03, 0x0b, - 0x84, 0xcd, 0xfb, 0xbb, 0x82, 0x4a, 0x44, 0xe3, 0x37, 0x44, 0xe6, 0xb8, 0x24, 0x1b, 0xdb, 0x74, 0x18, 0xb7, 0xfd, - 0x6f, 0x6c, 0xfe, 0xdc, 0x73, 0xdd, 0xfe, 0x85, 0x6e, 0xdc, 0xfe, 0x00, 0xfe, 0xce, 0x1a, 0x2a, 0xdb, 0x86, 0x23, - 0x62, 0xdf, 0x46, 0x35, 0x50, 0xa2, 0x34, 0xb6, 0x4a, 0xcf, 0xc7, 0xae, 0x3b, 0x45, 0xde, 0x25, 0xf6, 0x47, 0x8e, - 0xe7, 0xe1, 0xc0, 0xf1, 0x46, 0xc9, 0xc4, 0x19, 0x21, 0x6f, 0x08, 0x8d, 0xef, 0xe3, 0x11, 0x72, 0x3f, 0x59, 0x28, - 0x63, 0x45, 0x11, 0x5b, 0xbc, 0xe2, 0xd4, 0x42, 0x42, 0x36, 0xd5, 0x1d, 0x8d, 0xad, 0xa4, 0x6d, 0x1a, 0xf0, 0xee, - 0xaa, 0x2a, 0xaa, 0x06, 0xac, 0xfd, 0x95, 0xa3, 0x7b, 0xff, 0xbe, 0x58, 0x87, 0x6c, 0x08, 0x17, 0x59, 0xd5, 0x94, - 0xb1, 0xa5, 0x41, 0xb1, 0x9f, 0xee, 0xe8, 0x1e, 0xa9, 0xa6, 0x7f, 0xb6, 0xe8, 0x54, 0x0d, 0x5b, 0x32, 0x1e, 0x5b, - 0x9e, 0x8f, 0xbc, 0x29, 0xe8, 0xbd, 0xed, 0xef, 0x8f, 0xa0, 0x10, 0x05, 0x4a, 0xe7, 0x66, 0x65, 0xbf, 0xbf, 0x8d, - 0xc4, 0x6a, 0x89, 0x36, 0x65, 0xc1, 0x45, 0x6c, 0xe5, 0x52, 0xd6, 0xe1, 0x60, 0xb0, 0x5e, 0xaf, 0xf1, 0x3a, 0xc0, - 0x55, 0xb3, 0x1c, 0xf8, 0xae, 0xeb, 0x0e, 0x80, 0xc2, 0x42, 0x66, 0x7f, 0x2c, 0x7f, 0x68, 0xa1, 0x9c, 0xb2, 0x65, - 0x2e, 0x75, 0x7f, 0xfe, 0x74, 0xc7, 0xf7, 0x91, 0xa2, 0x98, 0xdf, 0x7e, 0x38, 0xd3, 0xd2, 0x9c, 0x69, 0xe1, 0xdf, - 0x12, 0xdb, 0x3a, 0xb8, 0xda, 0x7b, 0xa3, 0x8c, 0x9a, 0x10, 0x1f, 0xf9, 0xc8, 0xd5, 0xff, 0x7d, 0x47, 0xf5, 0xbb, - 0x91, 0xf3, 0xd9, 0x08, 0x9d, 0x8d, 0xe0, 0xaf, 0x02, 0xd0, 0x2f, 0xc7, 0xce, 0xe5, 0x91, 0xdf, 0x53, 0xeb, 0x2b, - 0xcf, 0x3d, 0x4d, 0x28, 0xa6, 0xef, 0xc7, 0xe7, 0x63, 0xc7, 0xff, 0x59, 0x11, 0x68, 0xf4, 0x8f, 0x5c, 0x8e, 0x9f, - 0x7b, 0x3f, 0x8f, 0xc9, 0x08, 0x8d, 0xba, 0x99, 0x91, 0xa3, 0xfa, 0xc7, 0x91, 0xd6, 0x85, 0x46, 0x2b, 0x20, 0x2b, - 0x9d, 0xb1, 0x33, 0x22, 0x01, 0x0a, 0x3a, 0xab, 0xa0, 0x07, 0xd3, 0x63, 0xe0, 0x3e, 0x9b, 0x73, 0x82, 0x4f, 0xbd, - 0xc1, 0xdc, 0xea, 0x87, 0x96, 0x75, 0x82, 0xa1, 0x3a, 0x87, 0x01, 0x7f, 0xac, 0xe0, 0xdc, 0x59, 0x56, 0x7f, 0x6f, - 0x7d, 0x2b, 0xc8, 0x8a, 0x5a, 0x71, 0x1c, 0x43, 0xa8, 0xb5, 0x25, 0x9c, 0x10, 0x5c, 0x54, 0x09, 0x51, 0x2c, 0x58, - 0x50, 0xd2, 0x24, 0xf9, 0xd7, 0x5f, 0xdb, 0xc7, 0xa5, 0x25, 0x95, 0xaf, 0x0a, 0xaa, 0xba, 0xe2, 0xe5, 0xf6, 0x86, - 0x2c, 0xdf, 0x42, 0x00, 0xd9, 0x16, 0x11, 0x2c, 0xa5, 0x56, 0xff, 0xbd, 0xfb, 0x01, 0x0b, 0xb9, 0x2d, 0x28, 0x4e, - 0x99, 0xa8, 0x0b, 0xb2, 0x8d, 0xad, 0x05, 0xc8, 0xba, 0xb3, 0xfa, 0x17, 0x19, 0x95, 0x49, 0x6e, 0x5b, 0x03, 0x08, - 0xb1, 0x8c, 0x2d, 0xf1, 0x47, 0x51, 0x71, 0xab, 0x8f, 0x65, 0x4e, 0xb9, 0x6d, 0x1f, 0x2c, 0x54, 0xf6, 0x71, 0xbd, - 0x64, 0x3f, 0xb4, 0x74, 0xb4, 0x41, 0x32, 0xa9, 0x42, 0x0e, 0xab, 0xe0, 0xbd, 0x38, 0xce, 0x2e, 0xaa, 0x74, 0xfb, - 0x88, 0x79, 0xb9, 0x67, 0x6c, 0x63, 0x9c, 0xd3, 0xe6, 0x86, 0x6e, 0xe0, 0xb8, 0xfc, 0x9b, 0x7d, 0xc7, 0xd0, 0x5b, - 0x2a, 0xd7, 0x55, 0x73, 0x27, 0x42, 0x64, 0x3d, 0x37, 0xe2, 0x66, 0x26, 0x42, 0x39, 0x26, 0xb5, 0xc0, 0xa2, 0x80, - 0xf0, 0xb7, 0xbd, 0x3e, 0xc4, 0x6a, 0x7d, 0xdf, 0x14, 0x83, 0xe2, 0x6d, 0x94, 0xb2, 0x15, 0x4a, 0x0a, 0x22, 0xe0, - 0xb8, 0x72, 0x23, 0xcb, 0x42, 0x87, 0xb8, 0xaa, 0x78, 0x02, 0xfc, 0x77, 0xb1, 0xf5, 0x00, 0x76, 0x2f, 0xb7, 0x3f, - 0xa4, 0x76, 0x4f, 0x00, 0x6a, 0xbd, 0x3e, 0x5e, 0x91, 0xa2, 0xa5, 0x28, 0x46, 0x32, 0x67, 0xe2, 0x64, 0xe2, 0xec, - 0x51, 0xb6, 0x5a, 0xdc, 0x01, 0x57, 0x06, 0xcb, 0xc2, 0xee, 0x5b, 0xc7, 0x38, 0x8e, 0x88, 0xb9, 0xe5, 0xac, 0x27, - 0xd6, 0x67, 0x36, 0x39, 0x05, 0xcd, 0xa4, 0x75, 0x16, 0xf0, 0x4f, 0x77, 0x70, 0x1b, 0xe1, 0x06, 0xf4, 0xf7, 0xf7, - 0xa7, 0xd9, 0x48, 0xd4, 0x84, 0x7f, 0xce, 0xaa, 0x6c, 0xd4, 0x81, 0x85, 0x55, 0x4f, 0x45, 0x17, 0x10, 0x9d, 0x74, - 0x0e, 0xc8, 0xb1, 0xff, 0x74, 0x07, 0x71, 0xa6, 0x8e, 0xce, 0xdd, 0x49, 0x68, 0x34, 0x00, 0x84, 0xe6, 0xb7, 0xfb, - 0x7e, 0xff, 0xe4, 0xce, 0x6f, 0x2d, 0x6d, 0xb6, 0xd7, 0xb4, 0xa0, 0x89, 0xac, 0x1a, 0xdb, 0x7a, 0x02, 0x9a, 0xe0, - 0x24, 0x68, 0xbf, 0xbf, 0xbf, 0x79, 0xf3, 0x3a, 0xae, 0x6c, 0xda, 0xbf, 0x78, 0x8c, 0x5a, 0xdd, 0xea, 0xef, 0xe1, - 0x56, 0xff, 0x4f, 0xdc, 0x53, 0xf7, 0x7a, 0xef, 0x03, 0xb0, 0x1a, 0xaf, 0x4f, 0x97, 0xbb, 0xba, 0x00, 0x9e, 0xc3, - 0x25, 0x72, 0x61, 0x3d, 0x17, 0xb6, 0x33, 0x1e, 0xf5, 0x41, 0x3d, 0xfc, 0x80, 0xe9, 0xfa, 0x7a, 0x86, 0x6b, 0x5a, - 0x1d, 0xd1, 0xf9, 0x37, 0xbb, 0x45, 0xb5, 0x71, 0x04, 0xfb, 0xc4, 0xf8, 0x32, 0x64, 0x3c, 0xa7, 0x0d, 0x93, 0x7b, - 0x30, 0x17, 0x6e, 0xfa, 0xba, 0x95, 0xbb, 0x9a, 0xa4, 0xa9, 0x5a, 0x19, 0xd5, 0x9b, 0x59, 0x06, 0x79, 0x41, 0x51, - 0xd2, 0xd0, 0xa3, 0xe5, 0xde, 0xac, 0xeb, 0x2b, 0x28, 0xbc, 0x1c, 0x3d, 0xdb, 0xab, 0x83, 0xb7, 0x93, 0xb0, 0x65, - 0x0e, 0x29, 0xd8, 0x92, 0x87, 0x09, 0xd8, 0x4d, 0x1b, 0xc3, 0x94, 0x91, 0x92, 0x15, 0xdb, 0x50, 0xc0, 0x65, 0xe8, - 0x40, 0xc2, 0x60, 0xd9, 0x7e, 0xd1, 0x4a, 0x59, 0x71, 0xd0, 0xdd, 0xa4, 0xb4, 0x09, 0xdd, 0x99, 0xe9, 0x38, 0x0d, - 0x49, 0x59, 0x2b, 0x42, 0x1c, 0x34, 0xb4, 0x9c, 0x2d, 0x48, 0x72, 0xb7, 0x6c, 0xaa, 0x96, 0xa7, 0x4e, 0xa2, 0x6e, - 0xeb, 0xf0, 0x89, 0x97, 0x91, 0x80, 0x26, 0xb3, 0x6e, 0x94, 0x65, 0xd9, 0x0c, 0x90, 0xa0, 0x8e, 0xb9, 0xfc, 0x42, - 0x1f, 0x0f, 0x15, 0xdb, 0x99, 0x99, 0xd8, 0x57, 0x13, 0xc6, 0x46, 0x48, 0x25, 0xcf, 0x66, 0x07, 0x77, 0xdc, 0x19, - 0xa4, 0x01, 0x01, 0x42, 0x6a, 0x88, 0x7f, 0x30, 0x73, 0x5f, 0x12, 0xc6, 0xcf, 0xad, 0x57, 0x67, 0x65, 0xd6, 0x85, - 0x2f, 0xc0, 0xa2, 0xd5, 0xe8, 0x20, 0x9e, 0x41, 0xa2, 0x32, 0xb9, 0x30, 0xf4, 0xc7, 0x6e, 0xbd, 0xd9, 0xe3, 0xee, - 0x8c, 0xec, 0x0e, 0xd4, 0x59, 0x41, 0x37, 0xb3, 0x8f, 0xad, 0x90, 0x2c, 0xdb, 0x3a, 0x5d, 0x2e, 0x0d, 0xe1, 0xbc, - 0x40, 0x0e, 0x5d, 0x00, 0x29, 0xa5, 0x7c, 0xa6, 0x75, 0x38, 0x4c, 0xd2, 0x52, 0x74, 0x38, 0x1d, 0xc5, 0xe8, 0x53, - 0x7a, 0x5f, 0xd6, 0xff, 0xa2, 0x56, 0xc7, 0x71, 0x57, 0x92, 0x06, 0x72, 0x8b, 0xb3, 0xa8, 0x00, 0xd3, 0x32, 0x74, - 0x26, 0xb0, 0x57, 0xdd, 0x94, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xfa, 0x6e, 0x3a, 0xe0, 0xed, 0xd5, 0x1b, 0x24, 0xaa, - 0x82, 0xa5, 0x1d, 0x9d, 0x26, 0x41, 0xee, 0x11, 0x1e, 0x0f, 0xb6, 0x1b, 0xa9, 0xb9, 0x03, 0xd4, 0xc3, 0x6c, 0x4a, - 0x3c, 0xf7, 0x81, 0x1d, 0x49, 0xb3, 0xcc, 0x5f, 0x64, 0x47, 0xa4, 0x54, 0xaa, 0xdd, 0xb3, 0xee, 0x54, 0xf8, 0x43, - 0x10, 0x70, 0xd8, 0x1b, 0xe8, 0xef, 0x99, 0x8e, 0x8b, 0xdd, 0x99, 0x14, 0x7d, 0x52, 0xc3, 0xb6, 0x29, 0xec, 0x87, - 0x4e, 0xee, 0xb3, 0xe0, 0xea, 0x94, 0x09, 0x7b, 0x8f, 0x67, 0xc2, 0x1e, 0x52, 0xb5, 0xcb, 0xcb, 0x6a, 0x13, 0xf7, - 0x74, 0x4e, 0x1a, 0xc2, 0x4f, 0xef, 0x59, 0xf0, 0x0a, 0xf8, 0xff, 0x2f, 0x29, 0xee, 0x0f, 0xa7, 0xb7, 0x2f, 0x48, - 0x6d, 0x5f, 0x98, 0xd5, 0x8c, 0x77, 0xca, 0x79, 0xe8, 0x41, 0xfa, 0x62, 0x58, 0xb0, 0xa5, 0xf7, 0x67, 0x40, 0xfb, - 0xdf, 0x38, 0x06, 0x2f, 0xbc, 0x29, 0xbe, 0x44, 0xba, 0x31, 0x10, 0xe1, 0x60, 0x8a, 0x26, 0x57, 0x43, 0x3c, 0xf4, - 0x90, 0xaa, 0x9a, 0xc6, 0x68, 0x82, 0xa7, 0x40, 0x30, 0xc6, 0xc1, 0x04, 0x26, 0x90, 0xef, 0xe1, 0xd1, 0x6b, 0x3f, - 0xc0, 0xe3, 0x11, 0x50, 0xf9, 0x2e, 0x0e, 0x7c, 0x64, 0x68, 0xc7, 0xd8, 0x07, 0x71, 0x8a, 0x24, 0x28, 0x01, 0xe8, - 0x24, 0xc0, 0xee, 0x04, 0xc4, 0x8d, 0xb1, 0x7b, 0x89, 0xa7, 0x63, 0x34, 0xc5, 0x13, 0x80, 0x0e, 0x0f, 0x47, 0x85, - 0x33, 0xc2, 0x1e, 0x4c, 0x07, 0x63, 0x32, 0xc5, 0xc3, 0x00, 0xe9, 0xc6, 0xc0, 0x31, 0x01, 0x11, 0x0e, 0x76, 0xbd, - 0xd7, 0x01, 0xf6, 0x27, 0xa0, 0x77, 0x38, 0x7c, 0x01, 0x62, 0x2f, 0x87, 0xc8, 0xb4, 0x06, 0x5e, 0x50, 0x30, 0x7a, - 0x0c, 0x34, 0xff, 0x9f, 0x0b, 0x1a, 0x40, 0xe2, 0xa1, 0x00, 0x5f, 0x42, 0xec, 0x7a, 0x8a, 0xdf, 0xb4, 0x06, 0x37, - 0xcf, 0x43, 0xee, 0x1f, 0xc6, 0x2c, 0xf8, 0xe7, 0x62, 0xe6, 0x29, 0x04, 0xa0, 0x0b, 0xba, 0x41, 0x0e, 0xd2, 0x8d, - 0xd1, 0x0d, 0xcc, 0xd3, 0xab, 0x4b, 0x34, 0x05, 0xae, 0xf1, 0x14, 0x5d, 0xa2, 0x91, 0x42, 0x17, 0xd8, 0x87, 0x86, - 0xc9, 0x01, 0xa6, 0x2f, 0x84, 0x71, 0xf8, 0x37, 0x86, 0xf1, 0x31, 0x9f, 0xfe, 0xc6, 0x2e, 0xfd, 0x15, 0x57, 0x10, - 0x94, 0x63, 0xba, 0x0c, 0x8b, 0x06, 0xe6, 0x15, 0xaf, 0xaa, 0x28, 0x78, 0x94, 0x43, 0x35, 0x02, 0xef, 0x7a, 0x0f, - 0xb1, 0x34, 0xce, 0xbd, 0xf9, 0xbd, 0x2a, 0x1d, 0x28, 0xbd, 0x79, 0xa4, 0xd3, 0xf9, 0xfc, 0x26, 0xa7, 0xe8, 0xd5, - 0xf5, 0x3b, 0x78, 0x08, 0x16, 0x05, 0xe2, 0xd5, 0x1a, 0xde, 0x9b, 0x5b, 0x24, 0x2b, 0xf5, 0x82, 0xe7, 0x50, 0x2a, - 0xaa, 0x2e, 0x3c, 0x20, 0x50, 0x57, 0x2c, 0x60, 0x8c, 0xa3, 0x45, 0x33, 0x7f, 0x57, 0x50, 0x22, 0x28, 0x5a, 0xb2, - 0x15, 0x45, 0x4c, 0x42, 0x1d, 0x50, 0x52, 0x24, 0x99, 0x6a, 0x8e, 0x8c, 0x9a, 0xee, 0x6d, 0x25, 0x69, 0x88, 0xae, - 0xaa, 0x7a, 0xab, 0x85, 0x24, 0x39, 0xe1, 0x4b, 0x9a, 0x1e, 0x84, 0x29, 0xea, 0x6d, 0xd5, 0x36, 0xe8, 0x97, 0x17, - 0x6f, 0x5e, 0xab, 0x87, 0x36, 0x45, 0x4e, 0xa7, 0x6c, 0x23, 0xd1, 0x8f, 0x37, 0x2f, 0x50, 0x5b, 0xc3, 0xa6, 0x53, - 0x63, 0x5b, 0xb5, 0xa2, 0xcd, 0x1a, 0x2a, 0x4b, 0xaa, 0x48, 0x40, 0xb9, 0xa0, 0x52, 0x42, 0xa1, 0x21, 0x30, 0x94, - 0xce, 0xda, 0x13, 0x53, 0x75, 0x83, 0xbb, 0x20, 0x7e, 0xde, 0x95, 0xd7, 0x51, 0x1e, 0x18, 0xd7, 0xaf, 0x3b, 0x6a, - 0x70, 0x3d, 0x98, 0x47, 0xea, 0x39, 0x8d, 0x88, 0x7e, 0x84, 0xc4, 0x83, 0x35, 0xcb, 0x98, 0x7a, 0xb8, 0xcd, 0x23, - 0x5d, 0x8f, 0x2a, 0x09, 0xaa, 0x24, 0x32, 0x5f, 0x34, 0x74, 0xaf, 0xa0, 0x7c, 0x09, 0xaf, 0x64, 0xd8, 0x70, 0xa8, - 0x50, 0x12, 0x9a, 0x57, 0x05, 0x54, 0x40, 0xf1, 0xf5, 0xf5, 0x0f, 0xff, 0x52, 0x9f, 0x3f, 0xc0, 0xcf, 0x13, 0x27, - 0x3c, 0x29, 0x0c, 0xa3, 0xea, 0x74, 0x7c, 0xe3, 0xa1, 0xf9, 0x90, 0x51, 0xc3, 0x7b, 0x00, 0xfc, 0x4e, 0xef, 0x49, - 0x79, 0x77, 0x98, 0xec, 0x24, 0xe9, 0x5f, 0x5d, 0xd9, 0x1a, 0x26, 0xd1, 0x2e, 0x4a, 0x26, 0xe7, 0xd7, 0x60, 0x60, - 0x34, 0x30, 0x0b, 0xe0, 0x9c, 0x72, 0xc0, 0xd0, 0xe6, 0x1d, 0x0f, 0xec, 0xa8, 0x42, 0xec, 0x27, 0x8d, 0x98, 0xd9, - 0x60, 0xed, 0x65, 0x49, 0x65, 0x5e, 0xa5, 0xf1, 0xbb, 0x1f, 0xaf, 0x6f, 0x8e, 0x1e, 0x77, 0xb0, 0x52, 0x9e, 0x98, - 0x0f, 0x2c, 0x6d, 0x21, 0x59, 0x4d, 0x1a, 0xa9, 0xc5, 0x3a, 0x2a, 0xce, 0x0e, 0x1e, 0xe9, 0x75, 0xbd, 0x33, 0xda, - 0xa9, 0x8e, 0x71, 0x30, 0x47, 0x0f, 0xd9, 0x78, 0xd0, 0xfd, 0x99, 0x95, 0x03, 0x73, 0x14, 0x07, 0xe6, 0x5c, 0x0e, - 0xf4, 0xe7, 0xa7, 0xdf, 0x01, 0xf1, 0x69, 0xfc, 0xac, 0x8e, 0x12, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x5b, 0x8f, 0xdb, 0x36, 0x16, 0x7e, 0xef, + 0xaf, 0xe0, 0x2a, 0x49, 0x2d, 0x37, 0x23, 0xea, 0x66, 0xf9, 0x2a, 0xa9, 0x48, 0xb2, 0x29, 0x5a, 0x20, 0x69, 0x03, + 0xcc, 0xb4, 0xfb, 0x10, 0x04, 0x18, 0x5a, 0xa2, 0x2c, 0x66, 0x24, 0x4a, 0x15, 0xe9, 0x5b, 0x0c, 0xef, 0x6f, 0xdf, + 0x43, 0x52, 0xf6, 0x38, 0xb3, 0x99, 0x05, 0x52, 0xec, 0x62, 0xd1, 0x4e, 0x26, 0x1c, 0x92, 0x3a, 0xd7, 0x4f, 0x3c, + 0x17, 0x2a, 0xfe, 0x5b, 0xde, 0x64, 0x72, 0xdf, 0x52, 0x54, 0xca, 0xba, 0x4a, 0x63, 0x35, 0xa2, 0x8a, 0xf0, 0x55, + 0x42, 0x39, 0xac, 0x28, 0xc9, 0xd3, 0xb8, 0xa6, 0x92, 0xa0, 0xac, 0x24, 0x9d, 0xa0, 0x32, 0xf9, 0xf5, 0xe6, 0x07, + 0x67, 0x8a, 0xdc, 0x34, 0xae, 0x18, 0xbf, 0x43, 0x1d, 0xad, 0x12, 0x96, 0x35, 0x1c, 0x95, 0x1d, 0x2d, 0x92, 0x9c, + 0x48, 0x32, 0x67, 0x35, 0x59, 0x51, 0x45, 0xa0, 0xd9, 0x38, 0xa9, 0x69, 0xb2, 0x61, 0x74, 0xdb, 0x36, 0x9d, 0x44, + 0x40, 0x29, 0x29, 0x97, 0x89, 0xb5, 0x65, 0xb9, 0x2c, 0x93, 0x9c, 0x6e, 0x58, 0x46, 0x1d, 0xbd, 0xb8, 0x62, 0x9c, + 0x49, 0x46, 0x2a, 0x47, 0x64, 0xa4, 0xa2, 0x89, 0x7f, 0xb5, 0x16, 0xb4, 0xd3, 0x0b, 0xb2, 0x84, 0x35, 0x6f, 0x2c, + 0x10, 0x29, 0xb2, 0x8e, 0xb5, 0x12, 0x29, 0x7b, 0x93, 0xba, 0xc9, 0xd7, 0x15, 0x4d, 0x5d, 0x97, 0x08, 0xb0, 0x4b, + 0xb8, 0x8c, 0xe7, 0x74, 0x87, 0xa7, 0xb3, 0x68, 0x32, 0x9e, 0xe6, 0x13, 0xfc, 0x51, 0x7c, 0x03, 0x9e, 0xad, 0x6b, + 0x50, 0x87, 0xab, 0x26, 0x23, 0x92, 0x35, 0x1c, 0x0b, 0x4a, 0xba, 0xac, 0x4c, 0x92, 0xc4, 0xfa, 0x5e, 0x90, 0x0d, + 0xb5, 0xbe, 0xfd, 0xd6, 0x3e, 0x13, 0xad, 0xa8, 0x7c, 0x5d, 0x51, 0x35, 0x15, 0x2f, 0xf7, 0x37, 0x64, 0xf5, 0x33, + 0x58, 0x6e, 0x5b, 0x44, 0xb0, 0x9c, 0x5a, 0xc3, 0xf7, 0xde, 0x07, 0x2c, 0xe4, 0xbe, 0xa2, 0x38, 0x67, 0xa2, 0xad, + 0xc8, 0x3e, 0xb1, 0x96, 0x20, 0xf5, 0xce, 0x1a, 0x2e, 0x8a, 0x35, 0xcf, 0x94, 0x70, 0x24, 0x6c, 0x3a, 0x3c, 0x54, + 0x14, 0xcc, 0x4b, 0xde, 0x12, 0x59, 0xe2, 0x9a, 0xec, 0x6c, 0x33, 0x61, 0xdc, 0x0e, 0xbe, 0xb3, 0xe9, 0x73, 0xdf, + 0xf3, 0x86, 0x57, 0x7a, 0xf0, 0x86, 0x2e, 0xfc, 0x5d, 0x74, 0x54, 0xae, 0x3b, 0x8e, 0x88, 0x7d, 0x1b, 0xb7, 0x40, + 0x89, 0xf2, 0xc4, 0xaa, 0xfd, 0x00, 0x7b, 0xde, 0x14, 0xf9, 0x33, 0x1c, 0x44, 0x8e, 0xef, 0xe3, 0xd0, 0xf1, 0xa3, + 0x6c, 0xe2, 0x44, 0xc8, 0x1f, 0xc1, 0x10, 0x04, 0x38, 0x42, 0xde, 0x27, 0x0b, 0x15, 0xac, 0xaa, 0x12, 0x8b, 0x37, + 0x9c, 0x5a, 0x48, 0xc8, 0xae, 0xb9, 0xa3, 0x89, 0x95, 0xad, 0xbb, 0x0e, 0xec, 0x7f, 0xd5, 0x54, 0x4d, 0x07, 0x70, + 0x7d, 0x83, 0x3e, 0xfb, 0xf9, 0x6a, 0x15, 0xb2, 0x23, 0x5c, 0x14, 0x4d, 0x57, 0x27, 0x96, 0x7e, 0x29, 0xf6, 0xd3, + 0x83, 0x3c, 0x22, 0x35, 0x0c, 0x2f, 0x1e, 0x3a, 0x4d, 0xc7, 0x56, 0x8c, 0x27, 0x96, 0x1f, 0x20, 0x7f, 0x0a, 0x6a, + 0x6f, 0x87, 0xc7, 0x33, 0x26, 0x44, 0x61, 0xd2, 0x7b, 0xd9, 0xd8, 0xef, 0x6f, 0x63, 0xb1, 0x59, 0xa1, 0x5d, 0x5d, + 0x71, 0x91, 0x58, 0xa5, 0x94, 0xed, 0xdc, 0x75, 0xb7, 0xdb, 0x2d, 0xde, 0x86, 0xb8, 0xe9, 0x56, 0x6e, 0xe0, 0x79, + 0x9e, 0x0b, 0x14, 0x16, 0x32, 0xe7, 0xc3, 0x0a, 0x46, 0x16, 0x2a, 0x29, 0x5b, 0x95, 0x52, 0xcf, 0xd3, 0xa7, 0x07, + 0x7a, 0x8c, 0x15, 0x45, 0x7a, 0xfb, 0xe1, 0x42, 0x4b, 0x77, 0xa1, 0x85, 0x7e, 0x7f, 0x81, 0xe6, 0xe0, 0xad, 0x32, + 0x6a, 0x42, 0x02, 0x14, 0x20, 0x4f, 0xff, 0x0b, 0x1c, 0x35, 0xef, 0x57, 0xce, 0x83, 0x15, 0xba, 0x58, 0xc1, 0x5f, + 0xc0, 0x2f, 0xa8, 0xc7, 0xce, 0xec, 0xcc, 0xee, 0xab, 0xc7, 0x1b, 0xdf, 0xbb, 0xdf, 0x50, 0x3c, 0x3f, 0x8e, 0x2f, + 0xd7, 0x4e, 0xf0, 0x9b, 0x22, 0x50, 0xd8, 0x9f, 0x99, 0x9c, 0xa0, 0xf4, 0x7f, 0x1b, 0x93, 0x08, 0x45, 0xfd, 0x4e, + 0xe4, 0xa8, 0xf9, 0x79, 0xa5, 0x34, 0xa1, 0x68, 0x03, 0x54, 0xb5, 0x33, 0x76, 0x22, 0x12, 0xa2, 0xb0, 0x37, 0x09, + 0x66, 0xb0, 0x3d, 0x06, 0xe6, 0x8b, 0x3d, 0x27, 0xfc, 0x34, 0x50, 0x30, 0xcf, 0x2d, 0xeb, 0x1e, 0x83, 0xe6, 0x12, + 0x03, 0xfc, 0xb1, 0x81, 0x33, 0x67, 0x59, 0x80, 0x11, 0x95, 0x59, 0x69, 0x5b, 0x2e, 0x44, 0x5e, 0xc1, 0x56, 0x10, + 0x15, 0x0d, 0xb7, 0x86, 0x58, 0x96, 0x94, 0xdb, 0x27, 0x56, 0xc5, 0x48, 0xf5, 0x13, 0xfb, 0xe1, 0x13, 0x39, 0x3c, + 0x9c, 0xe3, 0x43, 0x32, 0x09, 0x71, 0x28, 0xb1, 0x8a, 0xe8, 0xab, 0xf3, 0xee, 0xb2, 0xc9, 0xf7, 0x8f, 0x84, 0x4e, + 0xe9, 0x9b, 0xb8, 0x61, 0x9c, 0xd3, 0xee, 0x86, 0xee, 0xe0, 0x1d, 0xfe, 0x83, 0xfd, 0xc0, 0xd0, 0xcf, 0x54, 0x6e, + 0x9b, 0xee, 0x4e, 0xcc, 0x91, 0xf5, 0xdc, 0x88, 0x5b, 0xa8, 0xa8, 0x61, 0x20, 0x9b, 0xb4, 0x02, 0x8b, 0x0a, 0x72, + 0x82, 0xed, 0x0f, 0x21, 0x7e, 0xda, 0x7b, 0x4b, 0xf8, 0xc9, 0xb9, 0xdb, 0x38, 0x67, 0x1b, 0x94, 0x55, 0x10, 0xf5, + 0x70, 0xfc, 0x8d, 0x28, 0x0b, 0xf5, 0x47, 0xbd, 0xe1, 0x19, 0x70, 0xdf, 0x25, 0xd6, 0x17, 0xa2, 0xfa, 0xe5, 0xfe, + 0xa7, 0xdc, 0x1e, 0x08, 0x88, 0xe7, 0xc1, 0x10, 0x6f, 0x48, 0xb5, 0xa6, 0x28, 0x41, 0xb2, 0x64, 0xe2, 0xde, 0xc0, + 0xc5, 0xa3, 0x6c, 0xad, 0xb8, 0x03, 0xae, 0x02, 0x1e, 0x0b, 0x7b, 0x68, 0x9d, 0x22, 0x2b, 0x26, 0x26, 0xef, 0x59, + 0x4f, 0xac, 0x07, 0x16, 0x39, 0x15, 0x2d, 0xa4, 0x75, 0x1f, 0x81, 0x4f, 0x0f, 0xc2, 0xe6, 0xb8, 0x03, 0xed, 0xc3, + 0xe3, 0x79, 0x33, 0x16, 0x2d, 0xe1, 0x0f, 0x19, 0x95, 0x81, 0xea, 0xa0, 0x43, 0xb2, 0x82, 0x99, 0x3a, 0xed, 0x40, + 0x74, 0x56, 0xe8, 0x92, 0xd3, 0xf4, 0xe9, 0xa1, 0x03, 0x89, 0x2a, 0x07, 0x9d, 0x25, 0xc6, 0x2e, 0x40, 0x93, 0xde, + 0x1e, 0x87, 0xf7, 0x7e, 0xfc, 0xbe, 0xa6, 0xdd, 0xfe, 0x9a, 0x56, 0x34, 0x93, 0x4d, 0x67, 0x5b, 0x4f, 0x40, 0x0b, + 0xbc, 0x7e, 0xed, 0xf0, 0x8f, 0x37, 0x6f, 0xdf, 0x24, 0x8d, 0xcd, 0x86, 0x57, 0x8f, 0x51, 0xab, 0x0c, 0xff, 0x1e, + 0x32, 0xfc, 0x3f, 0x93, 0x81, 0xca, 0xf1, 0x83, 0x0f, 0xc0, 0xaa, 0xfd, 0xbd, 0xbd, 0x4f, 0xf4, 0x2a, 0x18, 0x9f, + 0x43, 0x40, 0x5f, 0x29, 0x0f, 0x9d, 0x71, 0x34, 0x3c, 0x82, 0x7e, 0xb0, 0x00, 0xec, 0xd6, 0xb9, 0x1a, 0x72, 0xb6, + 0x4a, 0x9b, 0xe9, 0x77, 0x87, 0x65, 0xb3, 0x73, 0x04, 0xfb, 0xc4, 0xf8, 0x6a, 0xce, 0x78, 0x49, 0x3b, 0x26, 0x8f, + 0x60, 0x2e, 0xa4, 0xfd, 0x76, 0x2d, 0x0f, 0x2d, 0xc9, 0x73, 0xf5, 0x24, 0x6a, 0x77, 0x8b, 0x02, 0x8a, 0x84, 0xa2, + 0xa4, 0x73, 0x9f, 0xd6, 0x47, 0xf3, 0x5c, 0xe7, 0x83, 0xf9, 0x2c, 0x7a, 0x76, 0x54, 0x07, 0xee, 0x20, 0xe1, 0x65, + 0x39, 0xa4, 0x62, 0x2b, 0x3e, 0xcf, 0xc0, 0x70, 0xda, 0x19, 0xa6, 0x82, 0xd4, 0xac, 0xda, 0xcf, 0x05, 0x64, 0x26, + 0x07, 0xaa, 0x07, 0x2b, 0x8e, 0xcb, 0xb5, 0x94, 0x0d, 0x07, 0xdd, 0x5d, 0x4e, 0xbb, 0xb9, 0xb7, 0x30, 0x13, 0xa7, + 0x23, 0x39, 0x5b, 0x8b, 0x39, 0x0e, 0x3b, 0x5a, 0x2f, 0x96, 0x24, 0xbb, 0x5b, 0x75, 0xcd, 0x9a, 0xe7, 0x4e, 0xa6, + 0x32, 0xe7, 0xfc, 0x89, 0x5f, 0x90, 0x90, 0x66, 0x8b, 0x7e, 0x55, 0x14, 0xc5, 0x02, 0xa0, 0xa0, 0x8e, 0xc9, 0x44, + 0xf3, 0x00, 0x8f, 0x14, 0xdb, 0x85, 0x99, 0x38, 0x50, 0x1b, 0xc6, 0x46, 0x48, 0xeb, 0xcf, 0x16, 0x27, 0x77, 0xbc, + 0x05, 0xa4, 0x64, 0x01, 0x42, 0x5a, 0x88, 0x47, 0x30, 0xf3, 0x58, 0x13, 0xc6, 0x2f, 0xad, 0x57, 0xc7, 0x64, 0xd1, + 0x97, 0x14, 0x80, 0x45, 0xab, 0xd1, 0x85, 0x65, 0x01, 0x45, 0xc3, 0x14, 0xc6, 0x79, 0x30, 0xf6, 0xda, 0xdd, 0x11, + 0xf7, 0x07, 0xe4, 0x70, 0xa2, 0x2e, 0x2a, 0xba, 0x5b, 0x7c, 0x5c, 0x0b, 0xc9, 0x8a, 0xbd, 0xd3, 0x17, 0xd6, 0x39, + 0x1c, 0x16, 0x28, 0xa8, 0x4b, 0x20, 0xa5, 0x94, 0x2f, 0xb4, 0x0e, 0x87, 0x49, 0x5a, 0x8b, 0x1e, 0xa7, 0xb3, 0x18, + 0x7d, 0x40, 0x3f, 0x97, 0xf5, 0x9f, 0xa8, 0xd5, 0x59, 0x3c, 0xd4, 0xa4, 0x83, 0x44, 0xef, 0x2c, 0x1b, 0xc0, 0xb4, + 0x9e, 0x3b, 0x13, 0x78, 0x57, 0xfd, 0x96, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xba, 0x5e, 0x9e, 0xf0, 0xf6, 0xdb, 0x1d, + 0x12, 0x4d, 0xc5, 0xf2, 0x9e, 0x4e, 0x93, 0x20, 0xef, 0x0c, 0x8f, 0x0f, 0xaf, 0x1b, 0xa9, 0xbd, 0x13, 0xd4, 0xa3, + 0x62, 0x4a, 0x7c, 0xef, 0x0b, 0x6f, 0x24, 0x2f, 0x8a, 0x60, 0x59, 0x9c, 0x91, 0x52, 0x65, 0xef, 0xc8, 0xfa, 0x53, + 0x11, 0x8c, 0x40, 0xc0, 0xe9, 0xdd, 0xc0, 0xfc, 0xc8, 0x74, 0x58, 0x1c, 0x2e, 0xa4, 0xe8, 0xa3, 0x3a, 0x5f, 0x77, + 0x95, 0x6d, 0x7d, 0xe1, 0xe8, 0x3e, 0x0b, 0x5f, 0xdd, 0x97, 0xa5, 0xc1, 0xe3, 0x65, 0x69, 0x80, 0x54, 0x23, 0xf3, + 0xb2, 0xd9, 0x25, 0x03, 0x5d, 0x20, 0x46, 0xf0, 0x3b, 0x78, 0x16, 0xbe, 0x06, 0xfe, 0xff, 0x4a, 0xbd, 0xf9, 0xc3, + 0xc5, 0xe6, 0x2b, 0x2a, 0xcd, 0x57, 0x56, 0x19, 0xe3, 0x9d, 0x72, 0x1e, 0x66, 0x50, 0x4e, 0x18, 0x16, 0x6c, 0xe5, + 0xff, 0x2f, 0xa0, 0xfd, 0x77, 0x1c, 0xc3, 0x17, 0xfe, 0x14, 0xcf, 0x90, 0x1e, 0x0c, 0x44, 0x38, 0x9c, 0xa2, 0xc9, + 0xab, 0x11, 0x1e, 0xf9, 0x48, 0xb5, 0x30, 0x63, 0x34, 0x81, 0x7e, 0x0f, 0xf9, 0x63, 0x1c, 0x4e, 0x60, 0x03, 0x05, + 0x3e, 0x8e, 0xde, 0x04, 0x21, 0x1e, 0x47, 0x40, 0x15, 0x78, 0x38, 0x0c, 0x90, 0xa1, 0x1d, 0xe3, 0x00, 0xc4, 0x29, + 0x92, 0xb0, 0x06, 0xa0, 0xb3, 0x10, 0x7b, 0x13, 0x10, 0x37, 0xc6, 0xde, 0x0c, 0x4f, 0xc7, 0x68, 0x8a, 0x27, 0x00, + 0x1d, 0x1e, 0x45, 0x95, 0x13, 0x61, 0x1f, 0xb6, 0xc3, 0x31, 0x99, 0xe2, 0x51, 0x88, 0xf4, 0x60, 0xe0, 0x98, 0x80, + 0x08, 0x07, 0x7b, 0xfe, 0x9b, 0x10, 0x07, 0x13, 0xd0, 0x3b, 0x1a, 0xbd, 0x00, 0xb1, 0xb3, 0x11, 0x32, 0xa3, 0x81, + 0x17, 0x14, 0x44, 0x8f, 0x81, 0x16, 0xfc, 0x75, 0x41, 0x03, 0x48, 0x7c, 0x14, 0xe2, 0x19, 0xc4, 0xae, 0xaf, 0xf8, + 0xcd, 0x68, 0x70, 0xf3, 0x7d, 0xe4, 0xfd, 0x61, 0xcc, 0xc2, 0xbf, 0x2e, 0x66, 0xbe, 0x42, 0x00, 0xa6, 0xa0, 0x1b, + 0xe4, 0x20, 0x3d, 0x18, 0xdd, 0xc0, 0x3c, 0x7d, 0x35, 0x43, 0x53, 0xe0, 0x1a, 0x4f, 0xd1, 0x0c, 0x45, 0x0a, 0x5d, + 0x60, 0x1f, 0x19, 0x26, 0x07, 0x98, 0xbe, 0x12, 0xc6, 0xd1, 0x9f, 0x18, 0xc6, 0xc7, 0x7c, 0xfa, 0x13, 0xbb, 0xf4, + 0xff, 0x48, 0x41, 0xd0, 0x8e, 0xe9, 0x36, 0x2c, 0x76, 0xcd, 0x95, 0x5e, 0x75, 0x51, 0x70, 0x43, 0x87, 0x6e, 0x04, + 0x2e, 0xf9, 0x3e, 0x62, 0x79, 0x52, 0xfa, 0xe9, 0x67, 0xdd, 0x39, 0x50, 0xfa, 0x69, 0xac, 0xcb, 0x79, 0x7a, 0x53, + 0x52, 0xf4, 0xfa, 0xfa, 0x1d, 0xdc, 0xca, 0xaa, 0x0a, 0xf1, 0x66, 0x0b, 0x97, 0xbf, 0x3d, 0x92, 0x8d, 0xba, 0xce, + 0x73, 0xe8, 0x15, 0xd5, 0x14, 0xee, 0x0d, 0xa8, 0x6f, 0x16, 0x30, 0xc6, 0xf1, 0xb2, 0x4b, 0xdf, 0x55, 0x94, 0x08, + 0x8a, 0x56, 0x6c, 0x43, 0x11, 0x93, 0xd0, 0x07, 0xd4, 0x14, 0x49, 0xa6, 0x86, 0x33, 0xa3, 0xa6, 0x83, 0x9e, 0x56, + 0x2b, 0x31, 0xdd, 0x30, 0x58, 0x02, 0x62, 0xd2, 0xbe, 0xed, 0x8d, 0xcb, 0xd0, 0x58, 0x75, 0x4d, 0xa5, 0x84, 0x8e, + 0x41, 0x59, 0x15, 0xa6, 0xb1, 0xba, 0x76, 0x22, 0xa2, 0x2f, 0x06, 0x89, 0xbb, 0x65, 0x05, 0x53, 0x97, 0xf9, 0x34, + 0xd6, 0xad, 0xa2, 0x92, 0xa0, 0xba, 0x15, 0xf3, 0xe5, 0x41, 0xcf, 0x2a, 0xca, 0x57, 0x70, 0x9b, 0x84, 0x77, 0x01, + 0xcd, 0x43, 0x46, 0xcb, 0xa6, 0x82, 0xe6, 0x24, 0xb9, 0xbe, 0xfe, 0xe9, 0xef, 0xea, 0x33, 0x85, 0x32, 0xe1, 0xcc, + 0x09, 0x7d, 0xbe, 0x61, 0x54, 0x93, 0x9e, 0x6f, 0x3c, 0x32, 0x1f, 0x1c, 0x5a, 0xe8, 0xd3, 0xc1, 0xbf, 0xfc, 0x33, + 0x29, 0xef, 0x4e, 0x9b, 0xbd, 0x24, 0xfd, 0x5f, 0x37, 0x9d, 0x86, 0x49, 0xac, 0x97, 0x35, 0x93, 0xe9, 0x35, 0x18, + 0x18, 0xbb, 0xe6, 0x01, 0x38, 0xa7, 0x1c, 0x30, 0xb4, 0x65, 0xcf, 0x03, 0x60, 0xff, 0x72, 0xf3, 0x02, 0xfd, 0xda, + 0xc2, 0x09, 0xa6, 0x06, 0x7b, 0xed, 0x65, 0x4d, 0x65, 0xd9, 0xe4, 0xc9, 0xbb, 0x5f, 0xae, 0x6f, 0xce, 0x1e, 0xaf, + 0x35, 0x11, 0xa2, 0x3c, 0x33, 0x1f, 0x42, 0xd6, 0x95, 0x64, 0x2d, 0xe9, 0xa4, 0x16, 0xeb, 0xa8, 0x10, 0x38, 0x79, + 0xa4, 0x9f, 0x17, 0xac, 0xa2, 0xc6, 0xa9, 0x9e, 0xd1, 0x4d, 0xd1, 0x97, 0x6c, 0x3c, 0xe9, 0x7e, 0x60, 0xa5, 0x6b, + 0x4e, 0x89, 0x6b, 0x8e, 0x8c, 0xab, 0x3f, 0x13, 0xfd, 0x0b, 0x65, 0x37, 0xa3, 0x8e, 0x36, 0x12, 0x00, 0x00}; } // namespace captive_portal } // namespace esphome diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 8eaaaf4581..4e6e136f8c 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,585 +6,596 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xdb, 0xc8, 0x92, 0xe0, 0xf3, - 0x9c, 0xd3, 0x7f, 0x30, 0x2f, 0x30, 0x4a, 0x6d, 0x03, 0x57, 0x20, 0x44, 0x52, 0x96, 0xed, 0x02, 0x05, 0xf2, 0xca, - 0x4b, 0x5d, 0xbb, 0xca, 0x5b, 0x59, 0xb2, 0x6b, 0x51, 0xb1, 0x2c, 0x88, 0x4c, 0x8a, 0x28, 0x83, 0x00, 0x0b, 0x48, - 0x6a, 0x29, 0x0a, 0x7d, 0xfa, 0xa9, 0x9f, 0xe6, 0x9c, 0x59, 0x1f, 0xfa, 0x65, 0x4e, 0xf7, 0xc3, 0x7c, 0xc4, 0x3c, - 0xf7, 0xa7, 0xdc, 0x1f, 0x98, 0xfe, 0x84, 0x89, 0x88, 0x5c, 0x90, 0x00, 0xa9, 0xc5, 0xd5, 0xd5, 0x7d, 0xbc, 0x08, - 0xc8, 0x35, 0x22, 0x32, 0x32, 0xb6, 0x8c, 0x84, 0x76, 0xef, 0x8c, 0xb3, 0x11, 0xbf, 0x98, 0x33, 0x6b, 0xca, 0x67, - 0x49, 0x7f, 0x57, 0xfe, 0xcf, 0xa2, 0x71, 0x7f, 0x37, 0x89, 0xd3, 0x4f, 0x56, 0xce, 0x92, 0x30, 0x1e, 0x65, 0xa9, - 0x35, 0xcd, 0xd9, 0x24, 0x1c, 0x47, 0x3c, 0x0a, 0xe2, 0x59, 0x74, 0xc2, 0xac, 0xad, 0xfe, 0xee, 0x8c, 0xf1, 0xc8, - 0x1a, 0x4d, 0xa3, 0xbc, 0x60, 0x3c, 0x7c, 0x7f, 0xf0, 0x55, 0xeb, 0x51, 0x7f, 0xb7, 0x18, 0xe5, 0xf1, 0x9c, 0x5b, - 0x38, 0x64, 0x38, 0xcb, 0xc6, 0x8b, 0x84, 0xf5, 0x4f, 0xa3, 0xdc, 0x7a, 0xc6, 0xc2, 0x37, 0xc7, 0xbf, 0xb0, 0x11, - 0xf7, 0xc7, 0x6c, 0x12, 0xa7, 0xec, 0x6d, 0x9e, 0xcd, 0x59, 0xce, 0x2f, 0xbc, 0xfd, 0xf5, 0x15, 0x31, 0x2b, 0xbc, - 0x4f, 0xba, 0xea, 0x84, 0xf1, 0x37, 0x67, 0xa9, 0xea, 0xf3, 0x94, 0x89, 0x49, 0xb2, 0xbc, 0xf0, 0x8a, 0x2b, 0xda, - 0xec, 0x5f, 0xcc, 0x8e, 0xb3, 0xa4, 0xf0, 0x9e, 0xe8, 0xfa, 0x79, 0x9e, 0xf1, 0x0c, 0xc1, 0xf2, 0xa7, 0x51, 0x61, - 0xb4, 0xf4, 0xde, 0xac, 0x69, 0x32, 0x97, 0x95, 0x2f, 0x8a, 0x67, 0xe9, 0x62, 0xc6, 0xf2, 0xe8, 0x38, 0x61, 0x5e, - 0xcc, 0x42, 0x87, 0x79, 0xdc, 0x8b, 0xdd, 0xb0, 0xcf, 0xad, 0x38, 0xb5, 0xd8, 0xe0, 0x19, 0xa3, 0x92, 0x25, 0xd3, - 0xad, 0x82, 0x3b, 0x6d, 0x0f, 0xc8, 0x35, 0x89, 0x4f, 0x16, 0xfa, 0xfd, 0x2c, 0x8f, 0xb9, 0x7a, 0x3e, 0x8d, 0x92, - 0x05, 0x0b, 0xe2, 0xd2, 0x0d, 0xd8, 0x21, 0x1f, 0x86, 0xb1, 0xf7, 0x84, 0x06, 0x85, 0x21, 0x97, 0x93, 0x2c, 0x77, - 0x90, 0x56, 0x31, 0x8e, 0xcd, 0x2f, 0x2f, 0x1d, 0x1e, 0x2e, 0x4b, 0xd7, 0x7d, 0xc2, 0xfc, 0x51, 0x94, 0x24, 0x0e, - 0x4e, 0x7c, 0xf7, 0x6e, 0x8c, 0x33, 0xc6, 0x1e, 0x3f, 0x8c, 0x87, 0x6e, 0x2f, 0x9e, 0x38, 0x05, 0x73, 0xab, 0x7e, - 0xd9, 0xc4, 0x2a, 0x98, 0xc3, 0x5d, 0xf7, 0xcd, 0xd5, 0x7d, 0x72, 0xc6, 0x17, 0x39, 0xc0, 0x5e, 0x7a, 0x6f, 0xd4, - 0xcc, 0xfb, 0x58, 0xff, 0x89, 0x3a, 0xf6, 0x00, 0xf6, 0x82, 0x5b, 0x1f, 0xc2, 0xb3, 0x38, 0x1d, 0x67, 0x67, 0xfe, - 0xfe, 0x34, 0x82, 0x1f, 0xef, 0xb2, 0x8c, 0xdf, 0xbd, 0xeb, 0x9c, 0x66, 0xf1, 0xd8, 0x6a, 0x87, 0xa1, 0x59, 0x79, - 0xf1, 0x64, 0x7f, 0xff, 0xf2, 0xb2, 0x51, 0xe0, 0xa7, 0x11, 0x8f, 0x4f, 0x99, 0xe8, 0x0c, 0x00, 0xd8, 0xf0, 0x73, - 0xce, 0xd9, 0x78, 0x9f, 0x5f, 0x24, 0x50, 0xca, 0x18, 0x2f, 0x6c, 0xc0, 0xf1, 0x69, 0x36, 0x02, 0xb2, 0xa5, 0x06, - 0xe1, 0xa1, 0x69, 0xce, 0xe6, 0x49, 0x34, 0x62, 0x58, 0x0f, 0x23, 0x55, 0x3d, 0xaa, 0x46, 0xde, 0x57, 0xa1, 0x58, - 0x5e, 0xc7, 0xf5, 0x72, 0x16, 0xa6, 0xec, 0xcc, 0x7a, 0x15, 0xcd, 0x7b, 0xa3, 0x24, 0x2a, 0x0a, 0x2b, 0x63, 0x4b, - 0x42, 0x21, 0x5f, 0x8c, 0x80, 0x41, 0x08, 0xc1, 0x25, 0x90, 0x89, 0x4f, 0xe3, 0xc2, 0xff, 0xb8, 0x31, 0x2a, 0x8a, - 0x77, 0xac, 0x58, 0x24, 0x7c, 0x23, 0x84, 0xb5, 0xe0, 0x77, 0xc2, 0xf0, 0x2b, 0x97, 0x4f, 0xf3, 0xec, 0xcc, 0x7a, - 0x96, 0xe7, 0xd0, 0xdc, 0x86, 0x29, 0x45, 0x03, 0x2b, 0x2e, 0xac, 0x34, 0xe3, 0x96, 0x1e, 0x0c, 0x17, 0xd0, 0xb7, - 0xde, 0x17, 0xcc, 0x3a, 0x5a, 0xa4, 0x45, 0x34, 0x61, 0xd0, 0xf4, 0xc8, 0xca, 0x72, 0xeb, 0x08, 0x06, 0x3d, 0x82, - 0x25, 0x2b, 0x38, 0xec, 0x1a, 0xdf, 0x76, 0x7b, 0x34, 0x17, 0x14, 0x1e, 0xb0, 0x73, 0x1e, 0xb2, 0x12, 0x18, 0xd3, - 0x2a, 0x34, 0x1a, 0x8e, 0xbb, 0x4c, 0xa0, 0x80, 0x85, 0x39, 0x43, 0x96, 0x75, 0xcc, 0xc6, 0x7a, 0x71, 0x3e, 0xdc, - 0xbd, 0xab, 0x69, 0x0d, 0x34, 0x71, 0xa0, 0x6d, 0xd1, 0x68, 0xeb, 0x09, 0xc4, 0x6b, 0x24, 0x72, 0x3d, 0xe6, 0x4b, - 0xf2, 0xed, 0x5f, 0xa4, 0xa3, 0xfa, 0xd8, 0x50, 0x59, 0xf2, 0x6c, 0x9f, 0xe7, 0x71, 0x7a, 0x02, 0x40, 0xc8, 0x99, - 0xcc, 0x26, 0x65, 0x29, 0x16, 0xff, 0x2d, 0x0b, 0x59, 0xd8, 0xc7, 0xd1, 0x33, 0xe6, 0xd8, 0x05, 0xf5, 0xb0, 0xc3, - 0x10, 0x49, 0x0f, 0x0c, 0xc6, 0x06, 0x2c, 0x60, 0x9b, 0xb6, 0xed, 0x7d, 0xe5, 0x7a, 0x17, 0xc8, 0x41, 0xbe, 0xef, - 0x13, 0xfb, 0x8a, 0xce, 0x71, 0xd8, 0x41, 0xa0, 0xfd, 0x84, 0xa5, 0x27, 0x7c, 0x3a, 0x60, 0x87, 0xed, 0x61, 0xc0, - 0x01, 0xaa, 0xf1, 0x62, 0xc4, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, 0x77, 0x08, - 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x63, 0x96, 0x1b, 0x70, 0xe8, 0x66, - 0xbd, 0xda, 0x0a, 0x2e, 0x60, 0x85, 0xa0, 0x9f, 0x35, 0x59, 0xa4, 0x23, 0x1e, 0x83, 0xe0, 0xb2, 0x37, 0x01, 0x5c, - 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0x67, 0xe8, 0x21, 0x94, 0x9a, - 0xf8, 0x12, 0xf1, 0x18, 0x10, 0x2c, 0xbd, 0xf7, 0x4c, 0x6f, 0xcf, 0x0f, 0x03, 0xe6, 0xaf, 0xf2, 0x71, 0xc8, 0xfd, - 0x59, 0x34, 0x47, 0x6c, 0x18, 0xf1, 0x40, 0x94, 0x8e, 0x10, 0xba, 0xda, 0xba, 0x20, 0xc5, 0xfc, 0x8a, 0x05, 0x5c, - 0x20, 0x08, 0xec, 0xd9, 0x67, 0xd1, 0x68, 0x0a, 0x5b, 0xbc, 0x22, 0xdc, 0x58, 0x6d, 0x87, 0x51, 0xce, 0x22, 0xce, - 0x9e, 0x25, 0x0c, 0xdf, 0x70, 0x05, 0xa0, 0xa7, 0x0d, 0xbc, 0xae, 0xf6, 0x5d, 0x12, 0xf3, 0xd7, 0x19, 0xcc, 0xd3, - 0x13, 0x4c, 0x02, 0x5c, 0x9c, 0xc3, 0x26, 0x47, 0x16, 0xd9, 0xe3, 0xb0, 0x5a, 0xc7, 0x0b, 0x0e, 0xeb, 0x96, 0x62, - 0x0b, 0x1b, 0xa8, 0xed, 0xc5, 0x3e, 0x07, 0x22, 0x3e, 0xc9, 0x52, 0x0e, 0xc3, 0x01, 0xbc, 0x9a, 0x83, 0xfc, 0x68, - 0x3e, 0x67, 0xe9, 0xf8, 0xc9, 0x34, 0x4e, 0xc6, 0x40, 0x8d, 0x12, 0xf0, 0x4d, 0x59, 0x08, 0x78, 0x02, 0x32, 0xc1, - 0xf5, 0x18, 0xd1, 0xf2, 0x21, 0x23, 0xf3, 0xd0, 0xb6, 0x7b, 0x28, 0x81, 0x24, 0x16, 0x28, 0x83, 0x68, 0xe1, 0xde, - 0x81, 0xe8, 0x2f, 0x5c, 0xbe, 0x19, 0xc6, 0x7a, 0x19, 0x25, 0x81, 0xdf, 0xa2, 0xa4, 0x01, 0xfa, 0x33, 0x90, 0x81, - 0x3d, 0x14, 0x5c, 0xdf, 0x49, 0xa9, 0x93, 0x30, 0x85, 0x21, 0x10, 0x60, 0x84, 0x12, 0x44, 0xd2, 0xe0, 0x6d, 0x96, - 0x5c, 0x4c, 0xe2, 0x24, 0xd9, 0x5f, 0xcc, 0xe7, 0x59, 0xce, 0xbd, 0xaf, 0xc3, 0x25, 0xcf, 0x2a, 0x5c, 0x69, 0x93, - 0x17, 0x67, 0x31, 0x47, 0x82, 0xba, 0xcb, 0x51, 0x04, 0x4b, 0xfd, 0x38, 0xcb, 0x12, 0x16, 0xa5, 0x80, 0x06, 0x1b, - 0xd8, 0x76, 0x90, 0x2e, 0x92, 0xa4, 0x77, 0x0c, 0xc3, 0x7e, 0xea, 0x51, 0xb5, 0x90, 0xf8, 0x01, 0x3d, 0xef, 0xe5, - 0x79, 0x74, 0x01, 0x0d, 0xb1, 0x0d, 0xf0, 0x22, 0xac, 0xd6, 0xd7, 0xfb, 0x6f, 0x5e, 0xfb, 0x82, 0xf1, 0xe3, 0xc9, - 0x05, 0x00, 0x5a, 0x56, 0x52, 0x73, 0x92, 0x67, 0xb3, 0xc6, 0xd4, 0x48, 0x87, 0x38, 0x64, 0xbd, 0x2b, 0x40, 0x88, - 0x69, 0x64, 0x58, 0x25, 0x66, 0x42, 0xf0, 0x9a, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, 0x43, 0x20, 0x8a, 0x61, - 0xca, 0xeb, 0xa1, 0xe5, 0xf9, 0xc5, 0x32, 0x0e, 0x09, 0xce, 0x39, 0xea, 0x5f, 0x84, 0x71, 0x14, 0xc1, 0xec, 0x4b, - 0x31, 0x60, 0xa9, 0x20, 0x8e, 0xcb, 0xd2, 0x8b, 0x34, 0x13, 0xa3, 0xc4, 0x43, 0x81, 0xc2, 0x61, 0x1b, 0x5d, 0x5e, - 0x32, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x65, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, 0x02, 0x35, 0xd9, - 0x29, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x10, 0xb5, 0x93, 0x04, 0xa1, 0xb8, 0xd3, 0xf1, 0x40, 0x83, 0x3e, 0x99, 0x46, - 0xe9, 0x09, 0x1b, 0x07, 0x11, 0x2b, 0xa5, 0xe4, 0xdd, 0xb3, 0x60, 0x8d, 0x81, 0x9d, 0x0a, 0xeb, 0xf9, 0xc1, 0xab, - 0x97, 0x72, 0xe5, 0x6a, 0xc2, 0x18, 0x16, 0x69, 0x01, 0x6a, 0x15, 0xc4, 0xb6, 0x14, 0xc7, 0xcf, 0xb8, 0x92, 0xde, - 0xa2, 0x24, 0x2e, 0xde, 0xcf, 0xc1, 0xc4, 0x60, 0x6f, 0x61, 0x18, 0x98, 0x3e, 0x84, 0xa9, 0xa8, 0x1c, 0xe6, 0x13, - 0x15, 0x63, 0x5d, 0x04, 0x9d, 0x05, 0xa6, 0xe2, 0x35, 0x73, 0xdc, 0x12, 0x58, 0x95, 0xc7, 0x23, 0x2b, 0x1a, 0x8f, - 0x5f, 0xa4, 0x31, 0x8f, 0xa3, 0x24, 0xfe, 0x8d, 0x28, 0xb9, 0x44, 0x1e, 0xe3, 0x3d, 0xb9, 0x08, 0x80, 0x3b, 0xf5, - 0x48, 0x5c, 0x25, 0x64, 0xef, 0x10, 0x31, 0x84, 0xb4, 0x4c, 0xc2, 0xc3, 0xa1, 0x04, 0x2f, 0xf1, 0xe7, 0x8b, 0x62, - 0x8a, 0x84, 0x95, 0x03, 0xa3, 0x20, 0xcf, 0x8e, 0x0b, 0x96, 0x9f, 0xb2, 0xb1, 0xe6, 0x80, 0x02, 0xb0, 0xa2, 0xe6, - 0x60, 0xbc, 0xd0, 0x8c, 0x8e, 0xd2, 0xa1, 0x0c, 0x86, 0xea, 0x99, 0x62, 0x96, 0x49, 0x66, 0xd6, 0x16, 0x8e, 0x96, - 0x02, 0x8e, 0x30, 0x2a, 0xa4, 0x24, 0xc8, 0x43, 0x85, 0xe1, 0x14, 0xa4, 0x10, 0x68, 0x05, 0x73, 0x9b, 0x2b, 0x4d, - 0xf6, 0x6c, 0x41, 0x2a, 0x21, 0x87, 0x8e, 0xb0, 0x91, 0x09, 0xd2, 0xdc, 0x85, 0x5d, 0x05, 0x52, 0x5e, 0x82, 0x2b, - 0xa4, 0x88, 0x32, 0x73, 0x90, 0x01, 0xc2, 0x6f, 0x84, 0x2e, 0xf4, 0xb1, 0x05, 0xb1, 0x81, 0xaf, 0x57, 0x1e, 0x08, - 0x2b, 0xf1, 0xae, 0x10, 0xf1, 0xae, 0x00, 0x1b, 0x27, 0x46, 0x7e, 0xf2, 0xee, 0x70, 0x3f, 0xcd, 0xf6, 0x46, 0x23, - 0x56, 0x14, 0x19, 0xc0, 0x76, 0x87, 0xda, 0x5f, 0x65, 0x68, 0x01, 0x25, 0x5d, 0x2d, 0xeb, 0xec, 0x82, 0x34, 0xb8, - 0xa9, 0x56, 0x94, 0x4e, 0x0f, 0xec, 0x8f, 0x1f, 0x41, 0x66, 0x7b, 0x92, 0x0c, 0x40, 0xf5, 0x55, 0xc3, 0x4f, 0xd8, - 0x33, 0x75, 0xca, 0xac, 0xb5, 0x2f, 0x9d, 0x3a, 0x48, 0x1e, 0x0c, 0xeb, 0x96, 0xc6, 0x82, 0xae, 0x1d, 0x1a, 0x57, - 0x43, 0x2a, 0xc8, 0xe5, 0x09, 0xa9, 0x6c, 0x63, 0x19, 0xc1, 0x6a, 0x2b, 0x3d, 0x22, 0xbd, 0xc2, 0xa6, 0x20, 0x40, - 0x0f, 0xd9, 0xb0, 0x27, 0xeb, 0xc3, 0x5c, 0x50, 0x2e, 0x67, 0xbf, 0x2e, 0x58, 0xc1, 0x05, 0xeb, 0xc2, 0xb8, 0x05, - 0x8c, 0x5b, 0xae, 0x58, 0x87, 0x35, 0xdb, 0x71, 0x1d, 0x6c, 0x6f, 0xe6, 0xa8, 0xc7, 0x0a, 0xe4, 0xe4, 0xeb, 0xd9, - 0x09, 0x61, 0x65, 0xee, 0xe5, 0xe5, 0x37, 0x6a, 0x90, 0x6a, 0x29, 0xb5, 0x0d, 0xd4, 0x58, 0x13, 0x5b, 0x35, 0x19, - 0xdb, 0xae, 0x54, 0xa8, 0x77, 0x3a, 0xbd, 0x1a, 0x1f, 0xc0, 0x9e, 0x6b, 0x6b, 0x96, 0xae, 0x8c, 0xed, 0xb7, 0x8a, - 0xa6, 0x6f, 0xc4, 0xc8, 0x64, 0x8d, 0xb2, 0x9b, 0xb9, 0x47, 0xed, 0x78, 0x68, 0xbb, 0x52, 0x57, 0x09, 0x86, 0x45, - 0x5d, 0x30, 0x34, 0xa1, 0x9e, 0xeb, 0x2e, 0xb6, 0x66, 0x2a, 0x16, 0xaa, 0xb5, 0x56, 0x0e, 0x04, 0x0f, 0x0f, 0xc1, - 0x38, 0x59, 0xeb, 0x1f, 0xbc, 0x8e, 0x66, 0x0c, 0x29, 0xea, 0x5d, 0xd5, 0x40, 0x3a, 0x10, 0xd0, 0x64, 0xd8, 0x54, - 0x6f, 0xdc, 0x15, 0x56, 0x53, 0x7d, 0x7f, 0xc5, 0x60, 0x45, 0x80, 0x7d, 0x5d, 0xae, 0x59, 0x22, 0xd2, 0x9b, 0x82, - 0x4b, 0x34, 0x7d, 0x44, 0x99, 0x58, 0x13, 0x52, 0xf0, 0x80, 0x3c, 0x2c, 0x7f, 0x63, 0xe1, 0x64, 0x2b, 0xa6, 0x70, - 0xe4, 0x28, 0x53, 0x80, 0xce, 0xa4, 0x04, 0x40, 0x5c, 0xd2, 0xcf, 0xda, 0xc6, 0x42, 0xb2, 0xed, 0x23, 0x1f, 0xf8, - 0x93, 0x24, 0xe2, 0x4e, 0x67, 0xab, 0xed, 0x02, 0x1f, 0x82, 0x10, 0x07, 0x1d, 0x01, 0xe6, 0x7d, 0x85, 0x0a, 0x43, - 0x54, 0x62, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe3, 0x09, 0x77, 0x52, 0x54, 0x22, 0x6e, 0xc9, 0x12, 0x50, 0x32, 0x7a, - 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, 0x0b, 0x2a, 0x08, 0x0c, - 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x15, 0x8b, 0x32, 0x1e, 0xc4, 0xab, 0x85, 0xa0, - 0x86, 0x7d, 0x9e, 0xbd, 0xcc, 0xce, 0x58, 0xfe, 0x24, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, 0x49, 0x4f, 0x02, 0x9d, - 0xf5, 0x14, 0xaf, 0x9c, 0x12, 0xd2, 0xb0, 0x10, 0xb3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, - 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x65, 0x9d, 0xb7, 0x60, 0x84, 0xb9, 0xe2, 0xd6, 0xfa, 0x8e, 0x75, - 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x79, 0x59, 0x19, 0xe9, 0xa0, 0x4c, 0xb5, 0x34, - 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, 0x8b, 0xbc, 0xb8, 0xe7, - 0x34, 0xd4, 0x11, 0x40, 0x31, 0xab, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, 0x8d, 0xbc, 0xaa, 0x89, - 0x80, 0x38, 0x1d, 0xb3, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, 0x83, 0x84, 0x57, 0x08, - 0x80, 0x79, 0xe2, 0x4f, 0xb3, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xf2, 0x32, 0x16, 0xfe, 0x22, 0x32, 0x40, 0xce, - 0x66, 0xd9, 0x29, 0x5b, 0x03, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, 0x54, 0xcb, 0x3c, 0x89, - 0x47, 0x4c, 0x6b, 0xa9, 0x99, 0x0f, 0x06, 0x1d, 0x3b, 0x07, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, 0xdf, 0xf6, 0x3a, 0x6e, - 0x29, 0x08, 0xbe, 0x5c, 0xa1, 0xe8, 0x35, 0xfa, 0x51, 0x9a, 0xe0, 0xeb, 0x64, 0x01, 0x77, 0x0d, 0xa5, 0xc8, 0x85, - 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x63, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, 0xdb, 0xf6, 0x9d, 0x26, - 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, 0x5a, 0x89, 0x54, 0x0d, - 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x41, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, 0xef, 0x99, 0x04, 0x73, - 0x1d, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x02, 0xcb, 0x73, 0x1c, 0x8d, 0x3e, 0x69, 0x70, - 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, 0xb6, 0x51, 0xc0, 0x21, - 0x5b, 0x61, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0x5c, 0xc3, 0x72, 0x5c, 0x49, - 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8e, 0x8b, 0xab, 0x49, 0xf0, 0x87, 0x82, 0xf9, - 0xd4, 0x98, 0xe9, 0x46, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, 0xd4, 0x7c, 0x83, 0x86, - 0x0a, 0x71, 0xfc, 0x89, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, 0x2a, 0x5a, 0xa4, 0x4c, - 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, 0xdc, 0x34, 0xd4, 0xc2, - 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, 0xfb, 0x86, 0x0f, 0x65, - 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, 0x74, 0x41, 0xa0, 0x48, - 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, 0x4a, 0x33, 0x2f, 0x75, - 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x71, 0x41, 0x99, 0xd8, 0xbb, 0x8e, 0x36, 0x5e, 0x1a, 0x66, 0xc2, 0xfa, 0x15, - 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, 0xb1, 0xa7, 0x00, 0x94, - 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x10, 0x1d, 0x2b, 0x11, 0x5a, 0x13, 0xf9, 0x5a, 0x9f, - 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, 0x25, 0x83, 0x84, 0x1c, - 0xd2, 0x55, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x0e, 0xc3, 0xc8, 0x41, 0xc7, 0x9d, 0xd6, 0x62, - 0x85, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, 0x0e, 0xa0, 0x03, 0x62, - 0x7f, 0x85, 0xf5, 0xd6, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0x97, 0x97, 0x11, 0xf2, 0x83, 0x30, 0x78, 0x61, 0xcd, - 0x06, 0x4a, 0xf6, 0xee, 0xbd, 0xc4, 0x56, 0x64, 0x7f, 0x56, 0x25, 0x95, 0xa7, 0x50, 0xe3, 0xdc, 0xfa, 0x3a, 0x31, - 0x33, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, 0x76, 0x5d, 0x37, - 0xc8, 0xc9, 0x79, 0xb9, 0xb3, 0xce, 0x85, 0xbc, 0x7b, 0xd7, 0xf4, 0x99, 0x4e, 0xf5, 0xf0, 0x4f, 0x1c, 0x54, 0xce, - 0xc5, 0x45, 0x4a, 0x16, 0xcc, 0x13, 0xa5, 0x8e, 0x56, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, 0x2c, 0x8a, 0xb9, - 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, 0xda, 0xa2, 0xc5, - 0x68, 0xca, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x41, 0xbc, 0xc5, 0xc0, 0x6c, 0x3d, 0xec, 0x65, 0xb3, - 0x7b, 0xcd, 0xfc, 0x87, 0x35, 0x02, 0xd9, 0x36, 0x53, 0x75, 0x65, 0xe3, 0x5d, 0x8a, 0x48, 0x8c, 0xb0, 0xad, 0x1b, - 0x5b, 0xda, 0xfa, 0xbd, 0x86, 0x7b, 0x5d, 0x39, 0xe6, 0x35, 0xa5, 0xda, 0xd0, 0xc3, 0xca, 0xcd, 0x61, 0xa6, 0x23, - 0x2f, 0x56, 0xd0, 0xed, 0x89, 0xa0, 0x10, 0x38, 0x11, 0xda, 0x1e, 0x54, 0xdc, 0x40, 0xa4, 0xe4, 0x4a, 0xab, 0x66, - 0x8b, 0x64, 0x2c, 0x81, 0x05, 0x17, 0x96, 0x4b, 0x3e, 0x3a, 0x8b, 0x93, 0xa4, 0x2a, 0xfd, 0x43, 0x05, 0xbc, 0x18, - 0xf6, 0x26, 0xd1, 0x2e, 0x30, 0x5a, 0x28, 0x10, 0x5c, 0x6d, 0x84, 0xbd, 0x77, 0xdc, 0x6a, 0xdd, 0x45, 0xc4, 0x91, - 0x9b, 0xd1, 0x08, 0xa8, 0xc7, 0x08, 0xab, 0x66, 0xed, 0xbd, 0x67, 0x18, 0x52, 0x33, 0xf0, 0x41, 0x75, 0x46, 0xc5, - 0x9f, 0x65, 0x4f, 0x7d, 0x26, 0x7a, 0x37, 0xaa, 0xae, 0x66, 0x40, 0x45, 0x05, 0x3e, 0xcc, 0x10, 0x4b, 0x5b, 0x05, - 0x02, 0x72, 0x3d, 0x2c, 0x4a, 0x01, 0x93, 0x34, 0x58, 0x50, 0x0a, 0xac, 0xb5, 0xb2, 0x7b, 0x79, 0x53, 0x30, 0x87, - 0x42, 0xe1, 0xa2, 0xff, 0x93, 0x6c, 0x36, 0x47, 0xcb, 0xac, 0xc1, 0xd4, 0xd0, 0xe0, 0x7d, 0xa3, 0xbe, 0x5c, 0x53, - 0x56, 0xeb, 0x43, 0x3b, 0xb2, 0xc6, 0x4f, 0xda, 0x51, 0x06, 0x87, 0x6a, 0xa1, 0x8b, 0xea, 0x76, 0x73, 0x53, 0xc4, - 0xac, 0xe3, 0x71, 0x9f, 0xf4, 0xb6, 0xb6, 0x26, 0x3d, 0x4d, 0x03, 0x92, 0x49, 0x92, 0xe1, 0x4d, 0x06, 0x28, 0x2b, - 0xe2, 0x2c, 0xcb, 0x06, 0xf9, 0x96, 0x65, 0x89, 0xeb, 0xf7, 0x6d, 0x6f, 0xaf, 0xe6, 0x59, 0x7b, 0x7b, 0x57, 0xbb, - 0xc8, 0x55, 0x9d, 0xf4, 0x20, 0x0f, 0x87, 0x50, 0xb4, 0x62, 0x53, 0x86, 0xcb, 0x59, 0x36, 0x66, 0x81, 0x0d, 0xdd, - 0x53, 0xbb, 0x94, 0x9b, 0x26, 0x81, 0xcd, 0x91, 0x30, 0x67, 0xf9, 0xae, 0x1e, 0x49, 0x0d, 0xf6, 0x80, 0x05, 0xb4, - 0xb9, 0xf0, 0x5d, 0x78, 0x92, 0x64, 0xc7, 0x51, 0x72, 0x20, 0x14, 0x78, 0xad, 0xe5, 0x07, 0x70, 0x19, 0xc9, 0x62, - 0x35, 0x94, 0xd4, 0x77, 0x83, 0xef, 0x82, 0x9b, 0x7b, 0x54, 0xde, 0x8a, 0xdd, 0xf1, 0xdb, 0x7e, 0xc7, 0x56, 0x11, - 0xb1, 0x97, 0xe6, 0x74, 0xa0, 0x71, 0x0a, 0xa0, 0xcc, 0x01, 0x68, 0xb2, 0xc2, 0x9b, 0xb2, 0xf0, 0xe5, 0xe0, 0xa5, - 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, 0x8a, 0x0a, 0x8c, 0x2b, - 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0xf7, 0x31, 0x3c, 0x82, 0x66, 0x1b, 0x1b, 0x4b, 0xe7, 0x55, 0xc4, 0xa7, 0x7e, - 0x1e, 0xa5, 0xe3, 0x6c, 0xe6, 0xb8, 0x9b, 0xb6, 0xed, 0xfa, 0x05, 0x79, 0x22, 0x5f, 0xba, 0xe5, 0xc6, 0x91, 0x37, - 0x62, 0xa1, 0x3d, 0xb0, 0x37, 0x3f, 0x7a, 0x07, 0x2c, 0x3c, 0xda, 0xdd, 0x58, 0x8e, 0x58, 0xd9, 0x3f, 0xf2, 0xce, - 0x75, 0xcc, 0xdd, 0x7b, 0x8b, 0x52, 0x06, 0x7a, 0x85, 0xfd, 0x73, 0x09, 0x06, 0xb0, 0x1b, 0xc5, 0xdf, 0x41, 0xca, - 0xbd, 0xa7, 0x03, 0x11, 0x19, 0xa7, 0xbd, 0xbc, 0xb4, 0x33, 0x8a, 0x18, 0xd8, 0x77, 0xb4, 0xb3, 0x7a, 0xf7, 0x6e, - 0xa5, 0xe6, 0xab, 0x52, 0xf0, 0x3e, 0xc2, 0x9a, 0xa7, 0xee, 0x3d, 0xa7, 0xa3, 0x95, 0xfa, 0x46, 0x1e, 0x33, 0x52, - 0x9a, 0xab, 0x76, 0x82, 0x63, 0x6c, 0xf1, 0xf5, 0xdb, 0xfa, 0x50, 0x44, 0x29, 0xfc, 0x18, 0xac, 0x97, 0x08, 0xd4, - 0x37, 0x38, 0x38, 0xde, 0x41, 0xb8, 0xb5, 0xeb, 0x0c, 0x02, 0xe7, 0x4e, 0xab, 0x75, 0xf9, 0xd3, 0xd6, 0xe1, 0xcf, - 0x51, 0xeb, 0xb7, 0xbd, 0xd6, 0x8f, 0x43, 0xf7, 0xd2, 0xf9, 0x69, 0x6b, 0x70, 0x28, 0xdf, 0x0e, 0x7f, 0xee, 0xff, - 0x54, 0x0c, 0xff, 0x24, 0x0a, 0x37, 0x5c, 0x77, 0xeb, 0xc4, 0x5b, 0xb0, 0x70, 0xab, 0xd5, 0xea, 0xc3, 0xd3, 0x1c, - 0x9e, 0xf0, 0xe7, 0x19, 0xfc, 0xb8, 0x3c, 0xb4, 0xfe, 0xd3, 0x4f, 0xe9, 0xdf, 0xfc, 0x94, 0x0f, 0x71, 0xcc, 0xc3, - 0x9f, 0x7f, 0x2a, 0xec, 0x7b, 0xfd, 0x70, 0x6b, 0xb8, 0xe9, 0x3a, 0xba, 0xe6, 0x4f, 0x61, 0xf5, 0x08, 0xad, 0x0e, - 0x7f, 0x96, 0x6f, 0xf6, 0xbd, 0xa3, 0xdd, 0x7e, 0x38, 0xbc, 0x74, 0xec, 0xcb, 0x7b, 0xee, 0xa5, 0xeb, 0x5e, 0x6e, - 0xe0, 0x3c, 0x27, 0x30, 0xfa, 0x3d, 0xf8, 0x79, 0x0a, 0x3f, 0x6d, 0xf8, 0x39, 0x81, 0x9f, 0x3f, 0x43, 0x37, 0x11, - 0x7f, 0xbb, 0xa4, 0x58, 0xc8, 0x25, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, - 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0xf9, 0x71, 0x03, 0x16, 0x1d, 0x39, 0x67, 0x23, 0x60, 0x9e, 0x88, 0x1c, - 0x14, 0x01, 0x17, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xe3, 0x70, 0x83, 0x39, 0x60, 0x14, 0xbc, 0x66, 0xf8, 0xd0, - 0x75, 0xbd, 0x67, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, 0xed, 0x7a, 0xf3, 0x35, 0x95, - 0xb0, 0xad, 0xd3, 0x13, 0xa8, 0x9b, 0x89, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, 0xb7, 0xe4, 0x2b, 0xe3, 0x10, 0x78, - 0xc5, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xc7, 0x0c, 0x66, 0x58, 0x31, 0x11, 0x39, 0x29, 0x4d, - 0x61, 0xd9, 0xc2, 0xe4, 0x6f, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, 0x64, 0x9b, 0x96, 0xfe, 0x2d, 0xa6, - 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xed, 0x70, 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, - 0x9f, 0xf3, 0x16, 0xd5, 0x18, 0xfc, 0x95, 0x61, 0x06, 0x4f, 0xcc, 0x87, 0x21, 0x9a, 0x65, 0xa9, 0x83, 0x5b, 0x29, - 0x8a, 0xfb, 0x17, 0xb8, 0x33, 0xd2, 0xd2, 0xdb, 0x0f, 0xd5, 0x8e, 0x39, 0xc8, 0x19, 0xfb, 0x2e, 0x4a, 0x3e, 0xb1, - 0xdc, 0x39, 0xf7, 0x3a, 0xdd, 0x2f, 0xa9, 0xb3, 0x87, 0xb6, 0xd9, 0xbb, 0xea, 0x18, 0x4d, 0x99, 0x05, 0xea, 0x88, - 0xb0, 0xd5, 0xf1, 0x72, 0x8c, 0x6a, 0x21, 0x09, 0x0a, 0x2f, 0x0b, 0xbb, 0xc4, 0xe1, 0xf6, 0x6e, 0x71, 0x7a, 0xd2, - 0xb7, 0x03, 0xdb, 0x06, 0x8b, 0xff, 0x80, 0xc2, 0x56, 0xc2, 0xb0, 0x00, 0x83, 0x6c, 0x37, 0xee, 0xf1, 0xcd, 0xcd, - 0x2a, 0xe0, 0x84, 0x07, 0xe9, 0xd4, 0x3d, 0xf1, 0x22, 0x6f, 0x1a, 0xc2, 0x80, 0x23, 0x68, 0x86, 0x5d, 0x7a, 0xa3, - 0xdd, 0x58, 0x4e, 0x83, 0xb1, 0x10, 0x3f, 0x89, 0x0a, 0xfe, 0x02, 0xe3, 0x11, 0xe1, 0x08, 0x8d, 0x7d, 0x9f, 0x9d, - 0xb3, 0x91, 0xb2, 0x33, 0x80, 0x50, 0x91, 0xdb, 0x73, 0x47, 0xa1, 0xd1, 0x0c, 0xe6, 0x0e, 0xc3, 0x83, 0x81, 0x0d, - 0x7b, 0x09, 0x76, 0x65, 0x18, 0x1d, 0x76, 0x86, 0x83, 0x34, 0x5c, 0xb0, 0x40, 0xd3, 0x56, 0x16, 0xcd, 0x6b, 0x45, - 0xdd, 0xe1, 0xc0, 0x99, 0x80, 0x91, 0x0e, 0xb6, 0xb8, 0x83, 0x6f, 0x18, 0xa1, 0x28, 0xc2, 0x77, 0xec, 0xe4, 0xd9, - 0xf9, 0xdc, 0xb1, 0x77, 0xb7, 0xec, 0x4d, 0x2c, 0xf5, 0x6c, 0x60, 0x2f, 0x98, 0x3b, 0x3c, 0x73, 0xcd, 0xce, 0xdb, - 0x43, 0x04, 0x15, 0x0b, 0x71, 0xf2, 0xb3, 0x81, 0xdd, 0x17, 0x53, 0xb7, 0x61, 0xd0, 0x54, 0x2e, 0x3f, 0xae, 0xe8, - 0x01, 0xa1, 0xaa, 0xba, 0x2a, 0xe8, 0xa0, 0xac, 0x1b, 0x38, 0x53, 0x13, 0x89, 0x16, 0x4e, 0x26, 0xa9, 0x00, 0x0e, - 0x0f, 0x36, 0x83, 0x49, 0x8d, 0x6e, 0xdb, 0xc3, 0xc1, 0x59, 0x70, 0xcf, 0xbe, 0xa7, 0x5e, 0x4e, 0x59, 0x70, 0xc2, - 0xc4, 0xf4, 0xa7, 0x20, 0xed, 0xf0, 0xe7, 0x09, 0x03, 0x24, 0xcf, 0xa8, 0x68, 0x21, 0x8b, 0xe6, 0x58, 0x74, 0x10, - 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xe3, 0x90, 0x60, 0xbf, 0x7b, 0x17, 0x96, 0x66, 0xb3, 0x33, 0xc4, - 0xf3, 0x86, 0x9c, 0x17, 0xdf, 0xc5, 0x1c, 0x54, 0xc2, 0x56, 0xdf, 0x76, 0x07, 0xb6, 0x85, 0x4b, 0xdb, 0xcb, 0x36, - 0x43, 0x41, 0xe1, 0x78, 0xf3, 0x80, 0x05, 0xd3, 0x7e, 0xd8, 0x1e, 0x38, 0xb9, 0x50, 0x1d, 0x09, 0x9e, 0x5b, 0x0a, - 0x09, 0xde, 0xf6, 0xa6, 0x20, 0xd0, 0x91, 0x73, 0x37, 0xec, 0x4d, 0x55, 0x08, 0x45, 0x1f, 0x37, 0xc7, 0x6e, 0x10, - 0xc3, 0x0f, 0xa7, 0x85, 0x4c, 0x33, 0xd5, 0x7d, 0xb5, 0x66, 0x76, 0x83, 0xb1, 0xb2, 0xc8, 0x93, 0x30, 0xdb, 0x74, - 0x30, 0x42, 0x0b, 0x92, 0x76, 0x77, 0x00, 0x30, 0x6c, 0x3a, 0x8a, 0xd3, 0xb6, 0x14, 0xab, 0x29, 0xfb, 0xfc, 0x50, - 0x2f, 0xc7, 0x94, 0x0d, 0xa6, 0xcc, 0xaf, 0xb4, 0x0f, 0x80, 0x15, 0x24, 0x5e, 0x3e, 0x54, 0x67, 0x5e, 0xcf, 0x6b, - 0xe7, 0x5b, 0x4b, 0x25, 0x8a, 0x98, 0x67, 0x48, 0x28, 0x5e, 0x6a, 0x37, 0x4c, 0x98, 0xdb, 0x73, 0x24, 0x86, 0x66, - 0xf9, 0xb0, 0x0d, 0x4c, 0xaf, 0x02, 0xec, 0xa9, 0xb9, 0x2d, 0x92, 0xb0, 0x6a, 0xee, 0x1d, 0x02, 0x6b, 0x0f, 0x81, - 0x87, 0x68, 0x1b, 0xf5, 0x54, 0x34, 0x9f, 0x25, 0xe1, 0xf3, 0xc6, 0x71, 0x71, 0x84, 0x27, 0x42, 0xfb, 0xfe, 0x68, - 0x91, 0x83, 0x3c, 0xe0, 0xaf, 0xc1, 0x32, 0x08, 0x65, 0x53, 0x74, 0xf4, 0xf0, 0x08, 0xd8, 0x23, 0xc4, 0x1b, 0x61, - 0x73, 0xa3, 0x1a, 0x2d, 0x4a, 0x32, 0x5e, 0xe8, 0x60, 0xb8, 0xc7, 0xa5, 0x6b, 0x8f, 0x82, 0x41, 0x9e, 0x18, 0x3b, - 0x78, 0xe6, 0xef, 0x8f, 0xb0, 0x1a, 0x27, 0x28, 0xdc, 0x92, 0x76, 0x5b, 0x25, 0xfe, 0xf6, 0xfd, 0x14, 0x24, 0x38, - 0xd6, 0x81, 0x9f, 0x75, 0xf7, 0x6e, 0x22, 0x91, 0xda, 0x4d, 0x7b, 0x74, 0x12, 0x81, 0xf1, 0xe0, 0xdc, 0x4f, 0xa1, - 0x1a, 0x49, 0x44, 0x45, 0x39, 0x5a, 0xa0, 0xe6, 0xa9, 0x5a, 0x05, 0xdf, 0xa1, 0x19, 0x81, 0xe7, 0x18, 0xb6, 0x26, - 0x3f, 0x55, 0x37, 0x16, 0xb1, 0x7c, 0xd7, 0xa5, 0xa3, 0x2d, 0x3c, 0x80, 0x14, 0x8c, 0x26, 0x18, 0xc6, 0xa5, 0xa0, - 0x64, 0xc5, 0x7f, 0x1f, 0x8d, 0x58, 0xf9, 0xf4, 0x30, 0xdb, 0xdc, 0x1c, 0x8a, 0x73, 0x0b, 0x62, 0x1c, 0x6e, 0x44, - 0x57, 0xe3, 0x0a, 0x80, 0xfa, 0x74, 0x4e, 0x5c, 0x0f, 0x4c, 0x2b, 0xd6, 0x74, 0x29, 0xf6, 0xc9, 0x61, 0x06, 0xa0, - 0xe0, 0x96, 0x73, 0xe8, 0x0f, 0xfe, 0x3c, 0x04, 0xf7, 0xd8, 0xff, 0x93, 0xbb, 0xa5, 0x04, 0x4d, 0x4f, 0x9e, 0x29, - 0x2e, 0xe9, 0x8c, 0xb5, 0xe3, 0x51, 0x6c, 0x34, 0x28, 0xbc, 0x14, 0x30, 0x00, 0x6d, 0x0e, 0x32, 0xa1, 0xe2, 0x20, - 0xe4, 0xa8, 0xc0, 0xf6, 0x71, 0xf3, 0x73, 0xdc, 0xd9, 0x4f, 0xc1, 0xc2, 0x1b, 0xe8, 0xb7, 0x97, 0xf0, 0xf6, 0x67, - 0xfd, 0xf6, 0x0b, 0x0b, 0x7e, 0x29, 0x65, 0xe8, 0xbe, 0x36, 0xc5, 0x03, 0x35, 0x45, 0x29, 0x96, 0xc8, 0xa0, 0x21, - 0x73, 0xf3, 0x95, 0x98, 0x0d, 0x77, 0x4b, 0x20, 0x86, 0x12, 0x5d, 0xb9, 0xcf, 0xa3, 0x13, 0x24, 0xae, 0x6b, 0x92, - 0xc2, 0xc8, 0x25, 0x30, 0x11, 0xae, 0xf8, 0x96, 0x98, 0xb3, 0xdf, 0x06, 0x1b, 0xbc, 0x96, 0x77, 0x80, 0xf6, 0x1d, - 0x9b, 0xcd, 0xf9, 0xc5, 0x3e, 0x29, 0xfa, 0x40, 0xa6, 0x0d, 0x88, 0xb3, 0xf3, 0x76, 0x2f, 0xde, 0xe5, 0xbd, 0x18, - 0xa4, 0x7a, 0xae, 0x58, 0x0c, 0xf7, 0xaa, 0xf7, 0x16, 0xa3, 0x94, 0x26, 0x33, 0x79, 0x35, 0xf4, 0xba, 0x12, 0xbd, - 0xcd, 0x4d, 0x40, 0xb0, 0x67, 0x74, 0xe5, 0xa2, 0x6b, 0x59, 0x0a, 0x9a, 0x00, 0x44, 0x8f, 0xea, 0x2c, 0x47, 0x1c, - 0x87, 0xd9, 0x6c, 0x50, 0x3c, 0x62, 0xee, 0xda, 0x51, 0x71, 0x4c, 0xec, 0x2e, 0x13, 0x76, 0x00, 0x33, 0xe2, 0xf2, - 0x56, 0x47, 0x44, 0x87, 0x45, 0x7f, 0x1d, 0xdf, 0xfe, 0xe8, 0xb1, 0xcd, 0x8e, 0x0b, 0x1a, 0xa4, 0x36, 0xd6, 0xc3, - 0x6a, 0x2c, 0xa8, 0x0f, 0x3f, 0x6a, 0x2a, 0x95, 0xc5, 0xe6, 0x66, 0x59, 0x3f, 0xaa, 0x55, 0x3b, 0xb8, 0x76, 0x9a, - 0x72, 0xde, 0xcc, 0x06, 0xe1, 0x40, 0xc4, 0x04, 0x0a, 0xb4, 0xb4, 0xb2, 0x62, 0x80, 0x21, 0x65, 0x39, 0xca, 0xa7, - 0x90, 0x79, 0x71, 0x59, 0xea, 0xd4, 0x17, 0x19, 0x8f, 0x0c, 0xf1, 0xd4, 0x93, 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, - 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x33, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, - 0x0c, 0xda, 0xfe, 0x49, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x87, 0x01, 0xd5, 0x2f, 0xa4, 0x04, 0x9b, - 0x86, 0xef, 0x81, 0x8d, 0x2a, 0xc7, 0x93, 0x04, 0xe1, 0xd3, 0x38, 0x67, 0xe4, 0x29, 0x6c, 0x48, 0x98, 0xa5, 0x69, - 0x1b, 0xa9, 0x76, 0x91, 0x19, 0x84, 0x72, 0x51, 0xf0, 0x1a, 0x67, 0x17, 0x59, 0xb8, 0xd2, 0x1a, 0xcc, 0x8f, 0x37, - 0x26, 0x40, 0xd9, 0xe5, 0x65, 0x26, 0x7c, 0xdc, 0x88, 0xec, 0x0d, 0x5d, 0x31, 0x1d, 0x28, 0xa4, 0x02, 0x27, 0x22, - 0x8b, 0x87, 0xce, 0x50, 0x68, 0x84, 0x03, 0x3a, 0x45, 0xce, 0x5d, 0x63, 0xd3, 0xe7, 0x03, 0xed, 0x1b, 0xa5, 0xa1, - 0x93, 0x80, 0x10, 0x10, 0xb8, 0x1b, 0xd6, 0x54, 0x3a, 0x48, 0x83, 0x84, 0x4a, 0xd1, 0xcf, 0x01, 0xfc, 0xc3, 0x48, - 0x52, 0x00, 0xec, 0x87, 0x6a, 0xa4, 0x88, 0xb2, 0x2c, 0x70, 0x01, 0x68, 0xae, 0x7d, 0x5c, 0x09, 0x5f, 0x18, 0xa8, - 0x30, 0x3d, 0xcd, 0xca, 0x4b, 0xa1, 0x44, 0x1e, 0xaf, 0x49, 0x59, 0x23, 0x99, 0x7c, 0x8a, 0x0e, 0x9f, 0xf2, 0xae, - 0x5f, 0x4b, 0x3c, 0x74, 0xc1, 0x53, 0x58, 0x56, 0xf5, 0xfc, 0x2a, 0xe4, 0xe4, 0x5c, 0x83, 0xae, 0x90, 0x42, 0x7f, - 0xc5, 0x49, 0xde, 0x7b, 0xe5, 0x57, 0xb5, 0xd4, 0x18, 0xca, 0xde, 0xaf, 0x6b, 0x86, 0xe5, 0xe5, 0xbc, 0x0a, 0x53, - 0x10, 0x70, 0x4b, 0x96, 0x04, 0x4b, 0xa9, 0x21, 0xc0, 0xc2, 0xf6, 0x48, 0x2b, 0x05, 0x79, 0xa9, 0xc3, 0x3b, 0x4f, - 0xc1, 0x0a, 0x30, 0x0e, 0xb5, 0x54, 0x32, 0x8d, 0x24, 0xbe, 0x54, 0xa2, 0xc0, 0x94, 0xfb, 0x23, 0xf0, 0x53, 0x9b, - 0x27, 0x5d, 0xe7, 0xae, 0x1f, 0xcf, 0x30, 0xb5, 0x87, 0x40, 0x8f, 0xbd, 0x3b, 0x60, 0x4a, 0xd4, 0x75, 0x58, 0x41, - 0x1c, 0x9a, 0xd5, 0x34, 0x0b, 0x98, 0x31, 0x6d, 0xd0, 0x92, 0x6d, 0xb0, 0xe5, 0x72, 0xb0, 0x8f, 0xc4, 0xf6, 0xac, - 0x56, 0x40, 0xe8, 0x1a, 0x34, 0x30, 0xe4, 0x2e, 0x15, 0x5a, 0x98, 0xf7, 0xba, 0x54, 0x84, 0xfb, 0x73, 0xc0, 0xa5, - 0x15, 0x9c, 0x79, 0x19, 0x0d, 0xbc, 0x1f, 0x1f, 0x27, 0x98, 0xf8, 0x82, 0x58, 0x81, 0x1d, 0x1c, 0x74, 0x9a, 0x4d, - 0x81, 0x53, 0x71, 0x91, 0x32, 0x58, 0x56, 0x94, 0xda, 0xf0, 0x43, 0x8a, 0x6c, 0xdd, 0xe5, 0x81, 0xee, 0x42, 0x2c, - 0x80, 0x9d, 0x7e, 0xc3, 0xc8, 0xb7, 0xac, 0x97, 0x01, 0x83, 0x53, 0xad, 0x71, 0x10, 0xf8, 0xcd, 0xcd, 0x64, 0x58, - 0xa6, 0xc4, 0x76, 0x4d, 0x56, 0x17, 0x90, 0xc3, 0x50, 0x4d, 0xdc, 0x41, 0x58, 0x2a, 0x7b, 0xbc, 0x28, 0x67, 0xb8, - 0x5c, 0xca, 0x42, 0x6e, 0x9e, 0x57, 0xd3, 0x7c, 0x6e, 0xa5, 0xd9, 0x74, 0xbc, 0x15, 0x5f, 0x14, 0xfc, 0x03, 0x27, - 0x96, 0x56, 0x3d, 0xa5, 0x56, 0x78, 0x94, 0xb9, 0x25, 0xeb, 0x94, 0xd4, 0xea, 0xba, 0x81, 0x6a, 0x84, 0xa7, 0x69, - 0xd8, 0x08, 0x84, 0x98, 0xe0, 0xe2, 0xd7, 0x4d, 0x26, 0xa6, 0xbd, 0x25, 0xa4, 0x8e, 0xb0, 0x7b, 0x28, 0x27, 0xb8, - 0xab, 0x79, 0xf6, 0x79, 0x38, 0xbf, 0x9a, 0xb9, 0xf7, 0x0c, 0xe6, 0x7e, 0x1c, 0x72, 0x83, 0xd1, 0x63, 0x99, 0xf0, - 0x23, 0x63, 0x1f, 0xb9, 0xaa, 0x7a, 0x72, 0x12, 0x56, 0x22, 0x4b, 0x3c, 0x19, 0x47, 0x1d, 0xc6, 0xa9, 0x68, 0x4d, - 0x90, 0x5d, 0x5e, 0x16, 0xe6, 0x5e, 0xa0, 0xa0, 0xa9, 0xc7, 0xeb, 0x71, 0xda, 0x8a, 0x9d, 0x8d, 0x48, 0xe4, 0xde, - 0xab, 0x5a, 0x24, 0xb2, 0xe2, 0x73, 0x1c, 0xe9, 0x8a, 0x83, 0xdc, 0x27, 0x27, 0xab, 0x9b, 0x54, 0xe8, 0x16, 0x8d, - 0xb6, 0xb1, 0x47, 0xf5, 0x81, 0xa4, 0x9e, 0x51, 0x81, 0x55, 0x8d, 0x7d, 0xf7, 0x6e, 0x47, 0xa4, 0x5b, 0x2a, 0xc5, - 0x06, 0x4b, 0x0b, 0xa3, 0x19, 0xa3, 0x60, 0x50, 0x52, 0x64, 0xa0, 0x46, 0xf9, 0x15, 0x82, 0x61, 0x8f, 0x1a, 0x80, - 0xe2, 0x5c, 0x5f, 0xfd, 0xb8, 0x94, 0x6c, 0x21, 0x20, 0x71, 0x97, 0x0c, 0xc4, 0x9a, 0x60, 0x66, 0xe4, 0x93, 0xf7, - 0xc0, 0x79, 0x03, 0x86, 0x0e, 0x01, 0xf8, 0x05, 0x62, 0xd3, 0x83, 0x89, 0x6d, 0x13, 0x51, 0xf4, 0xd9, 0xc0, 0x73, - 0x00, 0x76, 0x5e, 0x85, 0x46, 0xdf, 0x55, 0x29, 0x60, 0xc8, 0x06, 0x6e, 0xc0, 0xaa, 0xb0, 0xdc, 0xde, 0x73, 0x70, - 0x1b, 0xe0, 0xf5, 0x99, 0x6c, 0xbe, 0x81, 0x79, 0x82, 0xd5, 0xd9, 0x85, 0x5f, 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, - 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x39, 0x46, 0x58, 0xc4, 0xfb, 0x2b, 0x7c, 0xd7, 0xe3, 0x96, 0x7b, - 0x1a, 0x2d, 0xc2, 0x74, 0x95, 0x34, 0x06, 0x25, 0xeb, 0x7e, 0x32, 0xe2, 0x5e, 0xee, 0x8b, 0x58, 0x70, 0x85, 0x23, - 0xab, 0x42, 0x8a, 0x0d, 0x24, 0xe9, 0x69, 0x8f, 0x0e, 0xd8, 0x37, 0x9a, 0xbd, 0x80, 0x32, 0xef, 0x2b, 0x52, 0x49, - 0x48, 0x69, 0x76, 0x43, 0x24, 0x09, 0x6b, 0x45, 0x9e, 0x3a, 0xef, 0x3b, 0xda, 0xe7, 0x56, 0x12, 0xc1, 0x08, 0x4e, - 0xc2, 0x74, 0xac, 0x3c, 0x68, 0x0a, 0x70, 0x15, 0x1d, 0x31, 0x7d, 0x13, 0x90, 0xdf, 0x0c, 0xe4, 0xf6, 0x4a, 0x72, - 0x6d, 0xae, 0x61, 0x78, 0x82, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x8d, 0x09, 0xc9, 0xeb, 0x3c, 0x0f, 0x30, 0xe1, - 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x56, 0x02, 0xdd, 0x80, 0xe5, 0xfa, 0x38, 0x35, 0x2a, 0x12, 0x17, - 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x33, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, 0xa9, 0x8f, 0x99, 0x23, 0x64, - 0xae, 0xb0, 0x3e, 0xe7, 0x4e, 0x6d, 0xea, 0x1e, 0xa3, 0x6e, 0x9e, 0xa4, 0x16, 0xaf, 0xd3, 0xa6, 0x94, 0x88, 0x49, - 0x89, 0x39, 0x13, 0xa9, 0xd8, 0x4c, 0x89, 0x3b, 0xb7, 0xbe, 0xd1, 0x42, 0xda, 0x68, 0x33, 0x91, 0x83, 0xcd, 0x2a, - 0x79, 0x4f, 0x60, 0x3c, 0x17, 0x84, 0x2f, 0x91, 0xb1, 0x96, 0x63, 0xe6, 0x98, 0x08, 0x56, 0x2f, 0xa6, 0x22, 0x7f, - 0xe7, 0xe8, 0x34, 0x7b, 0x83, 0x1e, 0xa4, 0xde, 0x40, 0x62, 0xd6, 0xc4, 0x77, 0x21, 0x0d, 0x75, 0x84, 0x40, 0x65, - 0x54, 0xcb, 0x74, 0x9c, 0x58, 0x85, 0x6f, 0x04, 0x5f, 0xbd, 0xd5, 0xc7, 0xf9, 0xc6, 0x73, 0x63, 0x35, 0x82, 0x18, - 0xbc, 0x85, 0x7c, 0xe8, 0x49, 0x11, 0x0e, 0x84, 0xcb, 0x37, 0x37, 0x7b, 0xf9, 0x2e, 0xaf, 0x42, 0x24, 0x15, 0x8c, - 0x31, 0x66, 0x14, 0xe3, 0x9e, 0xa8, 0xa9, 0xc5, 0x1c, 0x06, 0x96, 0xad, 0xc3, 0x1c, 0x0f, 0x00, 0xa0, 0xa5, 0x29, - 0xbd, 0x6a, 0x2a, 0x54, 0x9e, 0xe7, 0x12, 0x3e, 0xd5, 0x21, 0xaa, 0x6a, 0xfc, 0x76, 0x7d, 0x06, 0x0a, 0xc1, 0x7d, - 0xa7, 0xe3, 0xe1, 0x21, 0x04, 0xac, 0xa2, 0x90, 0x05, 0x7a, 0x83, 0xf6, 0xaa, 0x44, 0x28, 0x66, 0x4e, 0xd6, 0x63, - 0x86, 0x93, 0x0a, 0xb6, 0x50, 0x09, 0x4b, 0xa5, 0x05, 0x7e, 0xb5, 0x11, 0x9a, 0xa7, 0x8c, 0x7b, 0xaf, 0x2a, 0x9c, - 0x41, 0x7f, 0x30, 0x6f, 0x95, 0x51, 0xdf, 0xae, 0x9c, 0xc8, 0x54, 0x60, 0xe2, 0x66, 0x96, 0xda, 0xef, 0x97, 0x75, - 0xda, 0xcf, 0x2b, 0xe4, 0x3e, 0x27, 0xcd, 0xd7, 0xb9, 0x85, 0xe6, 0x93, 0xe1, 0x7e, 0xa5, 0xfc, 0xd0, 0xc2, 0xa8, - 0x29, 0xbf, 0xbc, 0xae, 0xfc, 0x0a, 0x4f, 0x85, 0xb7, 0xfa, 0x5d, 0x14, 0xba, 0xa8, 0xcf, 0xc1, 0x10, 0xd2, 0x8f, - 0xe0, 0x1a, 0x1a, 0x3c, 0x28, 0x92, 0xc5, 0x62, 0xed, 0x82, 0xb8, 0x3e, 0xe6, 0x54, 0x3b, 0x94, 0x31, 0x46, 0x3c, - 0x2d, 0x39, 0x48, 0x32, 0x38, 0x18, 0xbf, 0x81, 0x01, 0x31, 0x29, 0x09, 0xe9, 0x10, 0x3a, 0x6b, 0x33, 0x11, 0x95, - 0xbb, 0x78, 0xb3, 0x71, 0x59, 0x53, 0x28, 0xc2, 0x4e, 0x30, 0x53, 0x29, 0x15, 0x04, 0xd2, 0xe4, 0xbb, 0xd3, 0xa9, - 0x05, 0x43, 0x0b, 0xd7, 0x54, 0x40, 0x5e, 0xdb, 0xf5, 0xa0, 0xc9, 0x7b, 0x8a, 0xa1, 0xaf, 0x53, 0x23, 0x5e, 0x66, - 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x26, 0x62, 0xaf, 0xe0, 0x13, 0x21, 0x9b, 0x82, 0x9d, 0x09, 0xf4, - 0x43, 0xbb, 0xb2, 0x97, 0xee, 0x16, 0x95, 0x4b, 0x8b, 0xc6, 0x56, 0xa2, 0x66, 0xcd, 0x0f, 0xe3, 0xcd, 0x14, 0xf6, - 0xb3, 0x47, 0x09, 0x04, 0xa4, 0xa9, 0x9c, 0xa4, 0x9a, 0xf7, 0x30, 0x1d, 0x02, 0x48, 0xb0, 0xfb, 0x09, 0x2c, 0xf4, - 0x9b, 0x12, 0x13, 0x2c, 0xaa, 0xc6, 0x6e, 0x73, 0xd0, 0x9a, 0x73, 0xd2, 0x7c, 0x73, 0xd4, 0xda, 0x9b, 0xca, 0x7a, - 0xc6, 0xec, 0x00, 0xdb, 0x76, 0x37, 0x8b, 0xc3, 0x74, 0xb3, 0x33, 0x34, 0x04, 0x17, 0x1e, 0xff, 0x27, 0x25, 0xa6, - 0x81, 0xe4, 0x52, 0x37, 0x7e, 0x42, 0x1d, 0x86, 0xff, 0x2d, 0x49, 0x01, 0x0f, 0x6a, 0xab, 0xb1, 0xe2, 0xdc, 0x2b, - 0x8e, 0x92, 0xcb, 0xaa, 0xda, 0xd5, 0x12, 0x34, 0x74, 0x23, 0x19, 0x13, 0xc5, 0x3c, 0x27, 0x00, 0x46, 0xb1, 0xf9, - 0x53, 0xa6, 0x93, 0xbc, 0x7f, 0x59, 0x9b, 0xda, 0xed, 0xfb, 0x7e, 0x94, 0x9f, 0xd0, 0x91, 0x8a, 0xca, 0xe6, 0x24, - 0xe6, 0xdf, 0x16, 0x60, 0x9a, 0x13, 0x1f, 0xea, 0xb9, 0x86, 0xa1, 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0x97, 0xbf, - 0x77, 0xb6, 0xfb, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0xb9, 0x02, 0x5f, 0xc0, 0x32, 0xb8, 0x25, 0xfd, 0xf4, 0xa6, - 0xbf, 0x0a, 0x3e, 0x63, 0xff, 0x0b, 0x40, 0xab, 0x02, 0x03, 0xca, 0x9d, 0xa6, 0x61, 0x25, 0xc4, 0x25, 0x2a, 0xcc, - 0x2a, 0xce, 0x1f, 0xd7, 0x79, 0xdd, 0xb4, 0x2c, 0x31, 0x28, 0x3f, 0x77, 0x0d, 0x37, 0xbe, 0xd7, 0xc8, 0x1f, 0xdf, - 0x7b, 0x0e, 0xba, 0x9d, 0x48, 0x7b, 0xf7, 0x6e, 0x7e, 0x87, 0x2c, 0x34, 0xbc, 0x17, 0x36, 0x87, 0xb6, 0x48, 0x97, - 0x5c, 0x3d, 0x63, 0x31, 0xde, 0x16, 0xa1, 0x32, 0x7c, 0xc0, 0x82, 0x39, 0x60, 0x08, 0x1e, 0x3b, 0x95, 0xc9, 0x67, - 0xd8, 0x68, 0x8a, 0x5d, 0x73, 0x61, 0xf0, 0x81, 0xaa, 0x2c, 0x24, 0x2f, 0xd6, 0xc9, 0xf6, 0xec, 0x14, 0x9e, 0x5f, - 0xc6, 0x05, 0x50, 0x07, 0xd0, 0xaf, 0xa8, 0x2c, 0x36, 0x90, 0x8b, 0x9b, 0xb2, 0xd6, 0x2b, 0x1a, 0x8f, 0xaf, 0xed, - 0xc2, 0xea, 0x0a, 0x7c, 0x1a, 0xa5, 0xe3, 0x44, 0x4c, 0x62, 0x26, 0x55, 0xae, 0xc9, 0xb5, 0xd1, 0xbd, 0xb4, 0x45, - 0xf3, 0x5c, 0x48, 0xf0, 0x8a, 0xc0, 0x0d, 0xa1, 0xaf, 0xf4, 0xe5, 0x7a, 0x03, 0x05, 0x8f, 0xda, 0x9b, 0x8b, 0x60, - 0x62, 0xe2, 0x31, 0x43, 0x6a, 0xfa, 0x75, 0x38, 0x15, 0xdf, 0xfc, 0xb6, 0xe2, 0xf0, 0xeb, 0x9c, 0xb1, 0x86, 0x02, - 0x20, 0x3e, 0x79, 0x70, 0xb5, 0x9b, 0xf4, 0x4a, 0x69, 0x07, 0xa5, 0x11, 0xe2, 0xdb, 0x0a, 0x5f, 0x77, 0xa9, 0xf8, - 0xca, 0x55, 0xf7, 0xbe, 0x8e, 0x99, 0x71, 0xc1, 0xe8, 0x39, 0x9f, 0x25, 0x8d, 0x6b, 0x37, 0x74, 0x57, 0xe7, 0x47, - 0xef, 0x07, 0x99, 0xb7, 0x70, 0x0c, 0x6c, 0x72, 0xcc, 0x9c, 0xe7, 0xde, 0x6b, 0xe3, 0x44, 0xf9, 0x5b, 0xf3, 0x88, - 0x57, 0x0e, 0xb3, 0xee, 0x24, 0xf9, 0xdb, 0xc1, 0xb7, 0xc1, 0xd5, 0x2d, 0x8d, 0x13, 0xe4, 0xae, 0x3a, 0x41, 0x26, - 0xca, 0xcd, 0xf4, 0x86, 0xdb, 0xbb, 0xad, 0x40, 0x10, 0xa7, 0x62, 0xfa, 0xa8, 0x1c, 0xd7, 0x8f, 0x16, 0xa8, 0x54, - 0x44, 0x7c, 0xaa, 0x72, 0x57, 0xae, 0x4c, 0x0d, 0xf5, 0xb8, 0x4e, 0x66, 0xa1, 0x69, 0xd6, 0xe4, 0x52, 0x36, 0x3d, - 0x46, 0xa6, 0xd9, 0xa9, 0x36, 0xbf, 0x7b, 0xe5, 0x21, 0x1d, 0x43, 0x73, 0xb1, 0x56, 0x0b, 0xee, 0x77, 0x15, 0x85, - 0x77, 0xbd, 0xd8, 0x48, 0x65, 0xa8, 0x59, 0x8f, 0xa2, 0x8f, 0xe3, 0x36, 0x73, 0x79, 0x94, 0xfd, 0x59, 0x03, 0xc0, - 0x74, 0x84, 0x45, 0x77, 0xd3, 0x33, 0xf6, 0x04, 0x7a, 0x7a, 0x22, 0x83, 0x44, 0xaf, 0x74, 0xbe, 0x6a, 0x95, 0x58, - 0xba, 0x86, 0xc0, 0xee, 0x35, 0x19, 0xab, 0x92, 0x76, 0xab, 0xf5, 0xab, 0x79, 0x3e, 0x4f, 0xf9, 0x4a, 0x9e, 0x4f, - 0xcd, 0xa2, 0xbb, 0xd3, 0x76, 0xaf, 0x4f, 0x0d, 0x15, 0x73, 0xad, 0x6f, 0xf2, 0x3b, 0xa6, 0xeb, 0x60, 0xa8, 0x45, - 0x90, 0x59, 0xed, 0xaa, 0x67, 0x65, 0x39, 0xab, 0x67, 0x72, 0xcc, 0x84, 0x6f, 0x2a, 0xdd, 0x21, 0xba, 0x61, 0xaa, - 0x66, 0xfa, 0xb1, 0xb1, 0x2d, 0x64, 0x9b, 0xe7, 0x17, 0xe3, 0x1c, 0x28, 0x2d, 0xf7, 0x97, 0x09, 0xc3, 0x8f, 0x97, - 0x97, 0x3f, 0x0a, 0x39, 0x55, 0x75, 0xf4, 0x96, 0x2f, 0x75, 0xcf, 0x60, 0x56, 0x2a, 0x27, 0xe2, 0x23, 0x5b, 0x3f, - 0x78, 0x73, 0xf7, 0x0a, 0x58, 0x3e, 0x02, 0x76, 0x1f, 0x99, 0xd3, 0x18, 0xaa, 0xda, 0xc0, 0x3f, 0xac, 0x1f, 0x6c, - 0xdd, 0x1e, 0xfe, 0x61, 0xf0, 0x43, 0x70, 0x6d, 0x63, 0x63, 0x1b, 0x6f, 0xd7, 0x12, 0x41, 0x5e, 0xe1, 0x81, 0x3e, - 0x5e, 0x7d, 0x14, 0xb4, 0x5c, 0x27, 0xb6, 0x07, 0x0e, 0x85, 0xad, 0x41, 0xbe, 0x49, 0x99, 0x34, 0x5a, 0x14, 0x3c, - 0x9b, 0xc9, 0x19, 0x0a, 0x79, 0xcd, 0xc7, 0x41, 0xdb, 0x11, 0xfe, 0x06, 0x4e, 0xed, 0x78, 0x79, 0xf9, 0x09, 0xfa, - 0x80, 0xa7, 0x2b, 0xa5, 0xa9, 0x88, 0x53, 0xca, 0x2d, 0xba, 0x5a, 0xe7, 0xc1, 0x48, 0x71, 0x31, 0x45, 0xa5, 0xe3, - 0x2e, 0xaf, 0x9d, 0x8d, 0x9c, 0xfe, 0x12, 0xaf, 0x2e, 0xd2, 0xe5, 0x23, 0x91, 0xad, 0x5a, 0x7a, 0x2f, 0xf4, 0xe9, - 0xb6, 0x3d, 0x63, 0x7c, 0x9a, 0x8d, 0xe9, 0x60, 0xc6, 0xc7, 0x89, 0xf0, 0xfa, 0xc4, 0x58, 0xdf, 0x2d, 0x02, 0xd3, - 0xcd, 0xb1, 0xc9, 0x0f, 0xc7, 0xeb, 0xcd, 0x66, 0x8d, 0x3b, 0x78, 0xe3, 0x3c, 0x71, 0x96, 0x25, 0x46, 0x54, 0x96, - 0x1a, 0x1e, 0xd0, 0x0a, 0x71, 0xf3, 0x9e, 0x09, 0x8c, 0xcb, 0x2e, 0x48, 0x6a, 0xbb, 0x81, 0xc0, 0xc5, 0x9e, 0xc4, - 0x2c, 0x19, 0xdb, 0x1e, 0x94, 0x07, 0xfa, 0x62, 0x34, 0xdd, 0x02, 0xa6, 0xe5, 0xb5, 0xb3, 0xb3, 0xd4, 0xf6, 0xaa, - 0xa9, 0x02, 0x98, 0x25, 0xcb, 0xe3, 0x13, 0x64, 0xdd, 0x6f, 0xa0, 0x8b, 0x18, 0x30, 0x36, 0xae, 0xcc, 0xb9, 0xcb, - 0x75, 0x2b, 0xe2, 0x1b, 0x4d, 0xa4, 0x49, 0x7d, 0x48, 0x7d, 0x87, 0x61, 0xad, 0xae, 0x72, 0x90, 0xc0, 0x3d, 0xf2, - 0x6e, 0x89, 0x4b, 0x4f, 0x9f, 0x59, 0x4c, 0xaa, 0xf4, 0x2d, 0x75, 0x2d, 0xae, 0x19, 0xf6, 0x8a, 0x07, 0x60, 0x7f, - 0x60, 0xdc, 0x22, 0x16, 0xf1, 0x76, 0x5e, 0x4b, 0x61, 0x6d, 0xcc, 0x81, 0xe6, 0x86, 0x1b, 0xbc, 0x60, 0xd5, 0x9a, - 0x81, 0x19, 0x66, 0x9c, 0x91, 0xfc, 0x66, 0xdc, 0xab, 0x9a, 0x38, 0x72, 0x15, 0x40, 0xf4, 0x2d, 0xe9, 0x92, 0x1c, - 0x5e, 0xc9, 0x72, 0xd5, 0x19, 0xf2, 0xaf, 0xb0, 0xce, 0x7a, 0x71, 0x02, 0x66, 0xd2, 0x94, 0x97, 0x98, 0x98, 0x22, - 0x2e, 0x37, 0xcb, 0x98, 0xa7, 0xe9, 0xb3, 0x68, 0x07, 0x27, 0x37, 0x12, 0x38, 0x62, 0xdf, 0x58, 0x86, 0x66, 0xc2, - 0x46, 0x4c, 0xa4, 0x51, 0x29, 0x25, 0x7c, 0x20, 0x97, 0x5a, 0xf2, 0x97, 0xb9, 0xbc, 0xfa, 0x72, 0x9b, 0xe0, 0x80, - 0xbc, 0x06, 0x96, 0x43, 0xe3, 0xb8, 0x65, 0x20, 0x11, 0x8b, 0x01, 0x31, 0x6a, 0x55, 0xae, 0x26, 0xa3, 0x3a, 0x99, - 0xaf, 0x90, 0x0b, 0x15, 0x79, 0x70, 0x4b, 0xa0, 0xe4, 0xcf, 0x31, 0x75, 0x30, 0x2b, 0xb5, 0x9b, 0x16, 0x9b, 0x24, - 0xef, 0x99, 0x01, 0xc9, 0xf5, 0xd7, 0xf0, 0xd0, 0xf8, 0xc5, 0x2b, 0x73, 0x4a, 0xf8, 0xa2, 0x8c, 0xa5, 0xa5, 0x31, - 0x97, 0xfe, 0x83, 0xbc, 0x4f, 0x2b, 0x01, 0xfb, 0x15, 0xc4, 0x94, 0x81, 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, - 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x2b, 0x26, 0x5d, 0xa5, 0xb2, 0xae, 0xb0, 0xea, 0x7e, 0x5d, 0xb0, 0xfc, 0x62, 0x9f, - 0x61, 0x6e, 0x32, 0x1a, 0x64, 0x2b, 0x66, 0x36, 0xe5, 0x57, 0x7b, 0xd7, 0x7e, 0xe5, 0xa1, 0xa4, 0x43, 0xb5, 0x4a, - 0x37, 0xaf, 0xdc, 0x70, 0x8c, 0x1b, 0x37, 0x1c, 0x01, 0x6c, 0x0c, 0x3b, 0x55, 0xa4, 0xd6, 0xf9, 0xef, 0xab, 0xe1, - 0x27, 0xda, 0x6b, 0x43, 0xbd, 0xeb, 0x86, 0x6b, 0xd3, 0xd3, 0xaf, 0x41, 0xd5, 0xc8, 0x12, 0xba, 0x0e, 0x55, 0x4c, - 0x46, 0xa2, 0xc4, 0x74, 0x95, 0xf2, 0xa8, 0xaf, 0x11, 0xe7, 0x20, 0x6e, 0x28, 0x7f, 0xf1, 0x2f, 0xe1, 0xc5, 0x51, - 0x80, 0x46, 0xd4, 0x72, 0x92, 0xa5, 0xbc, 0x35, 0x89, 0x66, 0x71, 0x72, 0x11, 0x2c, 0xe2, 0xd6, 0x2c, 0x4b, 0xb3, - 0x62, 0x0e, 0x5c, 0xe9, 0x15, 0x17, 0x60, 0xc3, 0xcf, 0x5a, 0x8b, 0xd8, 0x7b, 0xce, 0x92, 0x53, 0xc6, 0xe3, 0x51, - 0xe4, 0xd9, 0x7b, 0x39, 0x88, 0x07, 0xeb, 0x75, 0x94, 0xe7, 0xd9, 0x99, 0xed, 0xbd, 0xcb, 0x8e, 0x81, 0x69, 0xbd, - 0x37, 0xe7, 0x17, 0x27, 0x2c, 0xf5, 0xde, 0x1f, 0x2f, 0x52, 0xbe, 0xf0, 0x8a, 0x28, 0x2d, 0x5a, 0x05, 0xcb, 0xe3, - 0x09, 0xa8, 0x89, 0x24, 0xcb, 0x5b, 0x98, 0xff, 0x3c, 0x63, 0x41, 0x12, 0x9f, 0x4c, 0xb9, 0x35, 0x8e, 0xf2, 0x4f, - 0xbd, 0x56, 0x6b, 0x9e, 0xc7, 0xb3, 0x28, 0xbf, 0x68, 0x51, 0x8b, 0xe0, 0x8b, 0xf6, 0x76, 0xf4, 0xe5, 0xe4, 0x7e, - 0x8f, 0xe7, 0xd0, 0x37, 0x46, 0x2a, 0x06, 0x20, 0x7c, 0xac, 0xed, 0x9d, 0xf6, 0xac, 0xb8, 0x23, 0x4e, 0x94, 0xa2, - 0x94, 0x97, 0x47, 0xde, 0x19, 0x03, 0xb8, 0xfd, 0x63, 0x9e, 0x7a, 0xe0, 0xcb, 0xf1, 0x2c, 0x5d, 0x8e, 0x16, 0x79, - 0x01, 0x03, 0xcc, 0xb3, 0x38, 0xe5, 0x2c, 0xef, 0x1d, 0x67, 0x39, 0x90, 0xad, 0x95, 0x47, 0xe3, 0x78, 0x51, 0x04, - 0xf7, 0xe7, 0xe7, 0x3d, 0xb4, 0x15, 0x4e, 0xf2, 0x6c, 0x91, 0x8e, 0xe5, 0x5c, 0x71, 0x0a, 0x1b, 0x23, 0xe6, 0x66, - 0x05, 0x7d, 0x09, 0x05, 0xe0, 0x4b, 0x59, 0x94, 0xb7, 0x4e, 0xb0, 0x33, 0x1a, 0xfa, 0xed, 0x31, 0x3b, 0xf1, 0xf2, - 0x93, 0xe3, 0xc8, 0xe9, 0x74, 0x1f, 0x7a, 0xea, 0x9f, 0xbf, 0xe3, 0x82, 0xe1, 0xbe, 0xb6, 0xb8, 0xd3, 0x6e, 0xff, - 0xad, 0xdb, 0x6b, 0xcc, 0x42, 0x00, 0x05, 0x9d, 0xf9, 0xb9, 0x55, 0x64, 0x09, 0xac, 0xcf, 0xba, 0x9e, 0xbd, 0x39, - 0xf8, 0x4d, 0x71, 0x7a, 0x12, 0x74, 0xe7, 0xe7, 0x25, 0x62, 0x17, 0x88, 0x84, 0x4c, 0x89, 0xa4, 0x7c, 0x5b, 0xfe, - 0x5e, 0x88, 0x1f, 0xad, 0x87, 0xb8, 0xab, 0x20, 0xae, 0xa8, 0xde, 0x1a, 0xc3, 0x3e, 0x20, 0xf2, 0x77, 0x0a, 0x01, - 0xc8, 0x14, 0x9c, 0xc0, 0x5c, 0xc1, 0x41, 0x2f, 0xbf, 0x1b, 0x8c, 0xee, 0x7a, 0x30, 0x1e, 0xdd, 0x04, 0x46, 0x9e, - 0x8e, 0x97, 0xf5, 0x75, 0xed, 0x80, 0x73, 0xda, 0x9b, 0x32, 0xe4, 0xa7, 0xa0, 0x8b, 0xcf, 0x67, 0xf1, 0x98, 0x4f, - 0xc5, 0x23, 0xb1, 0xf3, 0x99, 0xa8, 0xdb, 0x69, 0xb7, 0xc5, 0x7b, 0x01, 0x0a, 0x2d, 0xe8, 0xf8, 0xd8, 0x00, 0x98, - 0xe8, 0xab, 0xab, 0x3e, 0x62, 0xf3, 0xdd, 0x8d, 0x5f, 0xaa, 0xf1, 0x2e, 0x54, 0xde, 0xa0, 0x50, 0x11, 0xea, 0x9b, - 0x2d, 0x98, 0xf1, 0x96, 0xf7, 0x3b, 0xfa, 0xa0, 0x6a, 0xf0, 0x1d, 0x23, 0xad, 0x17, 0x70, 0xcf, 0xcc, 0x05, 0xea, - 0xa5, 0x7d, 0x0c, 0x49, 0xb5, 0x5a, 0x2e, 0xe8, 0x0d, 0x86, 0x21, 0x24, 0x3a, 0x10, 0x74, 0xf2, 0x41, 0x41, 0xdf, - 0xd4, 0xc8, 0xdc, 0xa0, 0x70, 0x32, 0x17, 0xb6, 0x7c, 0xa6, 0xe5, 0x3a, 0x28, 0x69, 0xf0, 0xb2, 0xbf, 0x62, 0xb2, - 0x01, 0x48, 0xef, 0x4a, 0xd2, 0x7e, 0xaf, 0x4f, 0x9e, 0x94, 0xc7, 0x97, 0x8d, 0x88, 0x70, 0xe0, 0xea, 0xf3, 0x29, - 0xba, 0xdd, 0xfa, 0x3b, 0x31, 0x46, 0x46, 0xcd, 0x96, 0xed, 0x0e, 0x98, 0x4e, 0xca, 0xc2, 0xe4, 0x33, 0x56, 0xe2, - 0x28, 0x5f, 0xb3, 0xf0, 0x7b, 0x0c, 0xbc, 0xb2, 0x50, 0x78, 0x69, 0xca, 0x47, 0x9b, 0x5d, 0x77, 0xfb, 0x1f, 0x16, - 0x3c, 0xa6, 0x64, 0xe7, 0xc3, 0xe1, 0xbf, 0xc1, 0x67, 0x70, 0x34, 0x06, 0x45, 0xb6, 0xc8, 0x47, 0x14, 0x04, 0x5c, - 0x0d, 0x26, 0xd8, 0xa4, 0xcb, 0x6d, 0x8f, 0x69, 0x15, 0x82, 0x1e, 0x76, 0xed, 0xfb, 0x09, 0x9c, 0xce, 0x57, 0xc4, - 0xf5, 0x05, 0x19, 0x40, 0x51, 0x10, 0xa2, 0x56, 0x1c, 0x53, 0x2a, 0x1d, 0x5d, 0xed, 0xf4, 0x17, 0x69, 0x0c, 0x42, - 0xf4, 0x63, 0x3c, 0xa6, 0x2b, 0x2d, 0xf1, 0x98, 0xce, 0x38, 0x5a, 0x94, 0xd3, 0x84, 0x41, 0x73, 0x28, 0x90, 0xb4, - 0xc5, 0x67, 0x99, 0x23, 0x63, 0xb7, 0x6c, 0x3c, 0xa7, 0x30, 0xb4, 0xf0, 0x38, 0x9b, 0x45, 0x71, 0x1a, 0xe0, 0xa7, - 0x47, 0x3c, 0x3d, 0x62, 0x80, 0x5d, 0x3c, 0xf8, 0xa9, 0xc8, 0xdc, 0x71, 0xfd, 0x5f, 0x40, 0x44, 0x51, 0xff, 0x52, - 0xba, 0x78, 0x1a, 0x2e, 0x75, 0x82, 0x5c, 0x2f, 0x05, 0xb1, 0xc6, 0x95, 0x39, 0xcc, 0x28, 0x84, 0xb2, 0xcb, 0xe9, - 0xc7, 0xa0, 0xd5, 0x09, 0x3a, 0xda, 0x2b, 0xae, 0x5d, 0x74, 0x15, 0x69, 0x32, 0xf2, 0xb2, 0x24, 0xc1, 0xa0, 0x9f, - 0x05, 0x9c, 0xd5, 0xbb, 0x86, 0xd5, 0x93, 0x2c, 0x8f, 0xb1, 0xa1, 0x93, 0xd4, 0xa9, 0x01, 0x41, 0xc7, 0x0c, 0x57, - 0x4c, 0xe5, 0x96, 0x11, 0x31, 0xe1, 0x63, 0x92, 0x0d, 0xf5, 0x6b, 0x4a, 0x78, 0x25, 0xa9, 0x9e, 0x5d, 0xa5, 0xb3, - 0xa4, 0x8f, 0x76, 0x85, 0x30, 0xb1, 0x88, 0xc7, 0x42, 0x1b, 0x76, 0xb7, 0x6d, 0xfd, 0x79, 0x04, 0x54, 0xfa, 0x14, - 0xda, 0x1b, 0x4b, 0x47, 0xe5, 0xec, 0xe7, 0x30, 0xd7, 0x9e, 0x50, 0xa8, 0x74, 0xd9, 0xdf, 0xee, 0x6f, 0x2c, 0x79, - 0xb9, 0xbb, 0x25, 0x7a, 0xf7, 0x8f, 0xca, 0x82, 0x74, 0x9f, 0x19, 0xa3, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, - 0x06, 0xe3, 0xb8, 0xb9, 0xb6, 0xe7, 0x44, 0x30, 0x5a, 0xb2, 0x5d, 0x81, 0x99, 0x50, 0x51, 0x0e, 0xdb, 0x5d, 0xe7, - 0xba, 0x14, 0x22, 0xbd, 0xa3, 0xb7, 0x0a, 0xc5, 0x11, 0x42, 0x30, 0xd8, 0x58, 0xc6, 0x65, 0xb8, 0xb1, 0x64, 0xe9, - 0x28, 0x1b, 0xb3, 0xf7, 0xef, 0x5e, 0xe0, 0x75, 0x86, 0x2c, 0x45, 0xb9, 0x97, 0xb9, 0xe5, 0x11, 0x18, 0x42, 0x08, - 0x69, 0xae, 0xbe, 0x26, 0x03, 0xc0, 0x88, 0x98, 0x8e, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, - 0x1c, 0x4e, 0x2c, 0x00, 0x53, 0x91, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, - 0x9a, 0x23, 0x1a, 0x15, 0xaa, 0x98, 0xfd, 0x63, 0xa2, 0x3b, 0x8e, 0x4f, 0x35, 0x39, 0x29, 0x15, 0xba, 0xbf, 0x9b, - 0x44, 0xc7, 0x2c, 0x81, 0x21, 0x8b, 0xcb, 0xcb, 0x36, 0x8c, 0x24, 0x5e, 0xad, 0xdd, 0x38, 0x9d, 0x2f, 0xe4, 0x57, - 0xbd, 0x60, 0xe2, 0x0e, 0x1e, 0xb4, 0xe2, 0xa5, 0x83, 0x81, 0x3a, 0x39, 0x0c, 0xe4, 0x00, 0x00, 0x22, 0x1d, 0x5a, - 0x20, 0x74, 0x15, 0xab, 0x40, 0x69, 0x3c, 0x5e, 0x2d, 0x83, 0xdd, 0x39, 0xc7, 0xd2, 0x14, 0x9e, 0x67, 0x71, 0x8a, - 0x8f, 0x05, 0x3e, 0x46, 0xe7, 0xf8, 0x98, 0xc1, 0xa3, 0xc6, 0x3d, 0x2f, 0xed, 0x7f, 0xd7, 0x55, 0xc9, 0xe4, 0x0a, - 0x58, 0x9a, 0x00, 0xd9, 0xe5, 0x25, 0xa8, 0x17, 0x4d, 0x82, 0xdd, 0x2d, 0x20, 0x16, 0x72, 0x8f, 0xf8, 0xc6, 0x0b, - 0x33, 0xc9, 0xc8, 0x8a, 0x79, 0x4b, 0x94, 0x5b, 0xa4, 0xc4, 0x43, 0xf0, 0xf1, 0x72, 0xa7, 0x61, 0xab, 0x78, 0x32, - 0x9b, 0xe5, 0x09, 0xbe, 0xb8, 0xb6, 0x25, 0x3e, 0xc2, 0x21, 0x88, 0x42, 0x8f, 0x88, 0xa1, 0x2e, 0xe3, 0xf2, 0xf3, - 0x3a, 0x71, 0x68, 0xe3, 0x2c, 0x60, 0x2e, 0xa2, 0xd2, 0xe1, 0x51, 0x9c, 0x88, 0xc6, 0x6b, 0xf0, 0x69, 0xa4, 0x25, - 0x12, 0x3a, 0xbb, 0x5b, 0x15, 0x6c, 0x00, 0xfc, 0x48, 0x5c, 0xea, 0x76, 0x44, 0xca, 0xa5, 0x2d, 0xca, 0xe9, 0xa8, - 0x5e, 0x6e, 0x73, 0x19, 0x48, 0x16, 0xa1, 0x79, 0x8d, 0x2a, 0xa5, 0x48, 0xda, 0x93, 0x28, 0x5d, 0xd7, 0x14, 0xa0, - 0x9f, 0x33, 0x36, 0xf6, 0x6c, 0x0b, 0xe4, 0xab, 0x78, 0xfe, 0x98, 0xb0, 0x53, 0x26, 0x3f, 0xcc, 0xa2, 0x07, 0xd1, - 0x95, 0x23, 0xb0, 0x00, 0xb8, 0xbc, 0x33, 0x2a, 0xd9, 0x53, 0xe1, 0x28, 0x29, 0x51, 0x47, 0xc4, 0xb3, 0x8d, 0x41, - 0x9b, 0x73, 0xb4, 0xeb, 0xc3, 0x7a, 0xa0, 0x93, 0x6c, 0x5b, 0xc0, 0x4b, 0x66, 0xe3, 0xcd, 0xc8, 0xc1, 0x00, 0xc7, - 0x39, 0x36, 0x4d, 0x59, 0x51, 0xac, 0x03, 0x0b, 0x9c, 0x60, 0xcf, 0xae, 0x9a, 0xd8, 0xb5, 0x0e, 0x00, 0x40, 0x77, - 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x32, 0x81, 0x8d, 0x87, 0x1a, 0x23, 0xe1, 0x18, 0xf6, 0x0f, 0xfb, 0xf6, 0x6b, - 0xd8, 0xe3, 0x36, 0xf8, 0x57, 0xae, 0x3e, 0xc0, 0xa5, 0xe9, 0x95, 0x10, 0x32, 0xe6, 0x10, 0x9d, 0x8d, 0x61, 0xf4, - 0x93, 0x81, 0x54, 0x36, 0xfa, 0xb4, 0x06, 0x27, 0xe0, 0xc2, 0x0d, 0x11, 0x40, 0x6e, 0xc8, 0x56, 0xfb, 0x5f, 0xff, - 0xe9, 0x7f, 0xfd, 0x37, 0x18, 0x9b, 0xfa, 0xb9, 0xa5, 0x75, 0x75, 0xab, 0xff, 0x09, 0xad, 0x16, 0xe9, 0x0d, 0xed, - 0xfe, 0xfa, 0x0f, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x23, 0x90, 0x59, 0x04, 0xd1, 0x08, 0x6d, 0xbb, 0xcf, 0x02, 0xa9, - 0x36, 0xc8, 0x95, 0x33, 0xfd, 0x23, 0x82, 0x5d, 0xf0, 0x6c, 0x7e, 0x2d, 0x38, 0x08, 0xf5, 0x28, 0xc9, 0x0a, 0xa6, - 0xe1, 0x11, 0x72, 0xfe, 0xf3, 0x00, 0xa2, 0xb9, 0xe6, 0xb0, 0x9b, 0x0a, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xdd, 0x38, - 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0x5c, 0x02, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x8f, 0x5b, 0xff, 0x78, - 0xd9, 0xfa, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x48, 0x8d, 0x00, 0x3f, 0x41, 0x38, 0x7e, 0xd4, 0xcf, 0xd1, - 0xb9, 0x7e, 0x46, 0x01, 0x2a, 0x26, 0x00, 0x3d, 0x38, 0x43, 0x13, 0xc7, 0x9c, 0x41, 0x64, 0x37, 0x54, 0xee, 0xb1, - 0x91, 0x24, 0x23, 0x84, 0xe4, 0x47, 0xcc, 0x25, 0xc5, 0x9b, 0x43, 0x8b, 0x9c, 0x7d, 0x4c, 0xb2, 0x33, 0x8c, 0xb9, - 0x21, 0x91, 0xae, 0xaa, 0x2f, 0xff, 0xe5, 0x9f, 0x7d, 0xff, 0x5f, 0xfe, 0xf9, 0x8a, 0x06, 0x53, 0xd8, 0x13, 0x60, - 0x24, 0xf3, 0x50, 0xd3, 0xb9, 0x81, 0xd6, 0xfa, 0x41, 0x11, 0xcf, 0xf5, 0x35, 0x12, 0x71, 0x2c, 0x95, 0x78, 0xcb, - 0x47, 0x42, 0x5b, 0x33, 0xc5, 0xcd, 0xb3, 0x20, 0x64, 0x57, 0x4c, 0x83, 0x55, 0x37, 0xcc, 0x73, 0xe4, 0x06, 0xd7, - 0xd0, 0xe5, 0x33, 0x31, 0x5e, 0x0f, 0xc6, 0x8d, 0x10, 0x78, 0xa0, 0x65, 0x84, 0x1e, 0x7a, 0x22, 0xb4, 0x48, 0x20, - 0x96, 0x41, 0xea, 0x94, 0x1a, 0x40, 0x9e, 0x75, 0x40, 0x13, 0x50, 0x93, 0xb8, 0xd2, 0xe1, 0x64, 0x06, 0x1d, 0xe7, - 0xfd, 0x57, 0x78, 0x59, 0xd0, 0xc2, 0xde, 0xa8, 0xc1, 0x0b, 0x32, 0x38, 0x38, 0x19, 0x1c, 0x52, 0xd3, 0x99, 0xba, - 0x1e, 0x1d, 0xa7, 0x6c, 0xbd, 0x4e, 0xff, 0x88, 0xdd, 0x6b, 0x5a, 0x99, 0x4b, 0xad, 0x1c, 0x4b, 0x2b, 0x5a, 0x6a, - 0x65, 0xfc, 0x24, 0x4c, 0x43, 0x2b, 0xc7, 0x57, 0x6a, 0x65, 0xa4, 0xdc, 0x00, 0x47, 0x0e, 0xed, 0x4d, 0x8c, 0x0e, - 0x19, 0x36, 0x00, 0x47, 0xfb, 0x67, 0x34, 0x65, 0xa3, 0x4f, 0xd2, 0xfc, 0x21, 0x04, 0x30, 0x3c, 0xa2, 0x8d, 0x3c, - 0x81, 0x01, 0xa8, 0xf2, 0xa3, 0x52, 0x6f, 0x7a, 0x7c, 0x34, 0x26, 0xe0, 0xee, 0x72, 0xc2, 0x50, 0xf4, 0xc3, 0x9a, - 0x7d, 0xcd, 0xca, 0x2d, 0x1c, 0x47, 0x6c, 0x18, 0xf1, 0x0c, 0x98, 0x6d, 0xe1, 0x60, 0x47, 0xde, 0x52, 0x04, 0xdb, - 0x02, 0xfb, 0xed, 0x9b, 0xfd, 0x03, 0xdb, 0x3b, 0xce, 0xc6, 0x17, 0x81, 0x0d, 0xde, 0x0c, 0x58, 0x39, 0xae, 0xcf, - 0xa7, 0x2c, 0x75, 0x94, 0x3f, 0x91, 0x25, 0xe0, 0xaa, 0x65, 0x27, 0xe2, 0xdb, 0x10, 0xcd, 0x83, 0x02, 0x20, 0x2c, - 0x7d, 0x3c, 0xb2, 0xbf, 0xcb, 0xc5, 0x77, 0x55, 0x79, 0x8e, 0x8f, 0x7d, 0x4c, 0x95, 0xd8, 0xdd, 0x82, 0x07, 0x7c, - 0xd9, 0x47, 0xbd, 0xa7, 0xdf, 0x04, 0xb0, 0x85, 0x78, 0xdf, 0xc2, 0xf6, 0x5b, 0xaa, 0x2f, 0x42, 0xd1, 0x97, 0xdc, - 0xa6, 0x4d, 0xfe, 0xca, 0x66, 0xa4, 0xb1, 0xc7, 0x68, 0x12, 0x92, 0xc9, 0x0f, 0x24, 0xe1, 0x63, 0x5d, 0x22, 0xcc, - 0x0c, 0xa3, 0x88, 0x46, 0xa9, 0x8c, 0x02, 0x59, 0x85, 0x13, 0x92, 0x19, 0x29, 0x26, 0x83, 0x9f, 0x04, 0xfe, 0x91, - 0xf9, 0x1d, 0x34, 0xf1, 0xc9, 0x22, 0x8d, 0xe4, 0xe1, 0x5f, 0xbc, 0x33, 0xe6, 0x5d, 0x1c, 0x51, 0x4b, 0xe5, 0x74, - 0x63, 0x34, 0x08, 0x83, 0x13, 0x6d, 0x15, 0x5d, 0x01, 0x3b, 0x28, 0x89, 0xe6, 0x05, 0x0b, 0xd4, 0x83, 0xf4, 0xbf, - 0xd1, 0x8d, 0x5f, 0x0d, 0x78, 0x98, 0xf6, 0x52, 0xc9, 0xa7, 0x4b, 0xd3, 0x41, 0x7f, 0x00, 0x0e, 0x3a, 0x5e, 0x2e, - 0x68, 0x45, 0xa0, 0xe5, 0xd3, 0x20, 0x61, 0x13, 0x5e, 0x72, 0xbc, 0xbd, 0xbe, 0x54, 0x11, 0x11, 0xbf, 0xbb, 0x03, - 0x4e, 0xbb, 0xe5, 0xe3, 0xff, 0x37, 0x8d, 0x3d, 0x0e, 0x52, 0x70, 0xb2, 0xe9, 0x3a, 0x0b, 0x5e, 0x15, 0x04, 0x88, - 0xcc, 0xf7, 0xa5, 0x31, 0xd1, 0x88, 0x61, 0xb4, 0xa8, 0xe4, 0x39, 0xc8, 0x6d, 0x8f, 0xe7, 0x66, 0x3b, 0x90, 0xb7, - 0x2b, 0x21, 0xa3, 0xd5, 0xa0, 0xc5, 0xb6, 0x2b, 0xfd, 0x8f, 0xd5, 0xc6, 0x2a, 0xf2, 0x53, 0x7f, 0x5b, 0xa1, 0x90, - 0x11, 0xa3, 0x2a, 0x85, 0xaa, 0x59, 0x8a, 0x1e, 0x26, 0x4e, 0xab, 0xd1, 0xab, 0x1b, 0x2d, 0xd2, 0x92, 0xb6, 0xfd, - 0x21, 0x6d, 0x7b, 0x12, 0x63, 0xc3, 0xa5, 0x98, 0x7b, 0x14, 0x25, 0x23, 0x07, 0x01, 0xb0, 0x5a, 0xd6, 0x23, 0xa0, - 0xa6, 0xab, 0x22, 0x28, 0xfe, 0x43, 0x24, 0x6e, 0x29, 0x84, 0xde, 0x1a, 0x2a, 0x1d, 0x0d, 0xcb, 0xb2, 0x77, 0xc1, - 0x9c, 0xc3, 0xdf, 0xe4, 0x65, 0x08, 0x71, 0x07, 0x56, 0x7f, 0x47, 0xb0, 0x5d, 0xba, 0x43, 0x8f, 0x31, 0xe3, 0xeb, - 0x6c, 0xb6, 0xe2, 0x68, 0xdb, 0xeb, 0x52, 0x3c, 0x01, 0x7b, 0xbf, 0x72, 0x6c, 0x34, 0x62, 0xa9, 0xea, 0xa2, 0x45, - 0x1c, 0x66, 0x53, 0x47, 0x11, 0xcd, 0xff, 0xe6, 0xaa, 0xa0, 0xcc, 0xb7, 0x37, 0x07, 0x65, 0xf8, 0x2d, 0x83, 0x32, - 0xdf, 0xfe, 0xc1, 0x41, 0x99, 0x6f, 0xcc, 0xa0, 0x0c, 0xca, 0xca, 0x17, 0x9f, 0x13, 0x39, 0xc9, 0xb3, 0xb3, 0x22, - 0xec, 0xc8, 0x24, 0x00, 0x10, 0x3b, 0xff, 0x31, 0x21, 0x14, 0x98, 0xa8, 0x11, 0x40, 0xa1, 0x88, 0x89, 0xc8, 0x5b, - 0x04, 0x09, 0x2f, 0xe3, 0x15, 0x6d, 0x9d, 0x20, 0xd8, 0xba, 0xaf, 0x6e, 0x44, 0x81, 0x77, 0xe8, 0xea, 0xb0, 0x51, - 0x57, 0x45, 0x34, 0x02, 0xfa, 0xa4, 0xa9, 0xee, 0xd8, 0xdd, 0x54, 0x99, 0x69, 0xe6, 0x08, 0x3d, 0x75, 0xe0, 0x20, - 0x38, 0x68, 0x69, 0xff, 0xe7, 0xc3, 0x4e, 0x6f, 0xbb, 0x33, 0x83, 0xde, 0xa0, 0x4b, 0xe1, 0xad, 0xdd, 0xdb, 0xde, - 0xc6, 0xb7, 0x33, 0xf5, 0xd6, 0xc5, 0xb7, 0x58, 0xbd, 0xed, 0xe0, 0xdb, 0x48, 0xbd, 0x3d, 0xc0, 0xb7, 0xb1, 0x7a, - 0x7b, 0x88, 0x6f, 0xa7, 0x76, 0x79, 0xc8, 0x35, 0x70, 0x0f, 0x81, 0xb1, 0xc8, 0xb1, 0x08, 0x54, 0x19, 0xec, 0x5b, - 0xbc, 0x49, 0x18, 0x9d, 0x04, 0xb1, 0x27, 0x1c, 0xb0, 0x20, 0xf7, 0xce, 0x40, 0xf8, 0x07, 0x94, 0x38, 0xf7, 0x14, - 0x3f, 0x29, 0x01, 0xfe, 0xca, 0x41, 0x3c, 0x63, 0xea, 0xdb, 0xba, 0x0a, 0x6b, 0xb0, 0x25, 0x0f, 0xdb, 0xc3, 0xb2, - 0xa7, 0xd7, 0x49, 0x04, 0x6c, 0x54, 0x62, 0x02, 0xad, 0x5c, 0x55, 0x27, 0xa6, 0x6b, 0xe9, 0x15, 0xbe, 0x42, 0x95, - 0x18, 0x2e, 0xfb, 0x04, 0x6c, 0xa4, 0xd6, 0x39, 0x38, 0x79, 0x6b, 0xd5, 0x0b, 0x42, 0xa4, 0x15, 0x0a, 0xe1, 0xa4, - 0xdf, 0x0e, 0xa2, 0x13, 0xfd, 0xfc, 0x0a, 0x8c, 0xde, 0xe8, 0x84, 0xdd, 0xa4, 0x6a, 0x08, 0x44, 0x53, 0xcd, 0x28, - 0x20, 0xc8, 0x2a, 0x82, 0xa5, 0x41, 0x67, 0x53, 0xaa, 0x19, 0xa4, 0x4e, 0x5d, 0xf1, 0xd0, 0xf4, 0xf5, 0x22, 0xa0, - 0x68, 0x55, 0xb0, 0x0b, 0xb6, 0x37, 0x95, 0x0a, 0x0a, 0x43, 0x05, 0x16, 0x5c, 0xab, 0x8d, 0xb4, 0x3f, 0x7e, 0xa5, - 0x4e, 0xb2, 0x94, 0x3a, 0x32, 0x0f, 0x2a, 0xf4, 0x29, 0xc5, 0xaa, 0x84, 0xfc, 0xa2, 0x33, 0xc2, 0x3f, 0x52, 0xfe, - 0x7e, 0x31, 0x99, 0x4c, 0xae, 0x55, 0x4f, 0x5f, 0x8c, 0x27, 0xac, 0xcb, 0x76, 0x7a, 0x18, 0xc4, 0x6e, 0x49, 0x89, - 0xd8, 0x29, 0x89, 0x76, 0xcb, 0xdb, 0x35, 0x46, 0xe1, 0x09, 0x1a, 0xeb, 0xf6, 0x7a, 0xac, 0x04, 0xaa, 0x2c, 0x41, - 0x7e, 0x9f, 0xc4, 0x69, 0xd0, 0x2e, 0xfd, 0x53, 0x29, 0xf8, 0xbf, 0x78, 0xf4, 0xe8, 0x51, 0xe9, 0x8f, 0xd5, 0x5b, - 0x7b, 0x3c, 0x2e, 0xfd, 0xd1, 0x52, 0xa3, 0xd1, 0x6e, 0x4f, 0x26, 0xa5, 0x1f, 0xab, 0x82, 0xed, 0xee, 0x68, 0xbc, - 0xdd, 0x2d, 0xfd, 0x33, 0xa3, 0x45, 0xe9, 0x33, 0xf9, 0x96, 0xb3, 0x71, 0x2d, 0x12, 0xfe, 0xb0, 0x0d, 0x95, 0x82, - 0xd1, 0x96, 0xe8, 0xe8, 0x89, 0xc7, 0x20, 0x5a, 0xf0, 0x0c, 0x6c, 0x2c, 0xe0, 0x6d, 0x10, 0xd0, 0x13, 0x29, 0xde, - 0xc5, 0xa7, 0x6b, 0x51, 0xa8, 0xbf, 0x30, 0x65, 0x3a, 0x32, 0x33, 0xc9, 0x73, 0x4e, 0xaa, 0xa0, 0x59, 0x8d, 0x9c, - 0x45, 0xd5, 0x2f, 0x42, 0x5e, 0x49, 0x7b, 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xaf, 0x92, 0xf1, 0x3f, 0xdc, - 0x2c, 0xe3, 0x8f, 0x6f, 0x27, 0xe2, 0x7f, 0xf8, 0x83, 0x45, 0xfc, 0x8f, 0xa6, 0x88, 0x17, 0x42, 0x6c, 0x0f, 0xac, - 0x58, 0x32, 0x5f, 0x8f, 0xb3, 0xf3, 0x16, 0x6e, 0x89, 0xdc, 0x26, 0xe9, 0xb9, 0x71, 0x2b, 0xe1, 0xbf, 0x26, 0xb5, - 0x49, 0x0d, 0x66, 0x7c, 0x07, 0x97, 0x67, 0x27, 0x27, 0x09, 0x53, 0x32, 0xde, 0xa8, 0x20, 0xcb, 0xf8, 0x4d, 0x1a, - 0xda, 0x6f, 0xc0, 0x49, 0x35, 0x4a, 0x26, 0x13, 0x28, 0x9a, 0x4c, 0x6c, 0x95, 0xfa, 0x0b, 0xf2, 0x8c, 0x5a, 0xbd, - 0xae, 0x95, 0x50, 0xab, 0xaf, 0xbe, 0x32, 0xcb, 0xcc, 0x02, 0x19, 0xf5, 0x32, 0xed, 0x09, 0x59, 0x33, 0x8e, 0x0b, - 0xdc, 0x83, 0xd5, 0x77, 0x7b, 0xd1, 0x64, 0x99, 0x81, 0x52, 0x89, 0x47, 0xf8, 0x41, 0x98, 0xe6, 0x37, 0x52, 0x44, - 0x9a, 0xf6, 0x2a, 0x72, 0xd5, 0x51, 0xae, 0xf1, 0x39, 0xbe, 0xea, 0xf8, 0x16, 0x16, 0x5f, 0xa6, 0x6a, 0x3c, 0xbe, - 0x78, 0x31, 0x76, 0xf6, 0xc0, 0x94, 0x8d, 0x8b, 0x37, 0x69, 0x23, 0x05, 0x4e, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, - 0x20, 0x58, 0x75, 0x17, 0xa0, 0xaa, 0xec, 0x19, 0x9d, 0x64, 0xa6, 0x14, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, - 0x93, 0xba, 0x90, 0xbe, 0xcb, 0x2e, 0xf2, 0x47, 0x4e, 0xe5, 0x07, 0xbc, 0xe9, 0xf4, 0x61, 0x29, 0xf5, 0x87, 0xcc, - 0x2c, 0xa8, 0x7a, 0x62, 0xc0, 0x5f, 0xcc, 0x30, 0x2e, 0x55, 0x90, 0x1f, 0x08, 0x37, 0xc7, 0xaf, 0x0d, 0x89, 0x21, - 0x54, 0x2c, 0xbd, 0xa2, 0xde, 0xe5, 0xa5, 0xf9, 0xd1, 0xcb, 0xda, 0x07, 0x12, 0x1b, 0x3c, 0xc0, 0xf0, 0x6b, 0xb5, - 0xa8, 0x0d, 0xb2, 0x05, 0x77, 0x1c, 0x6a, 0xe5, 0xb8, 0xa5, 0xb7, 0xd3, 0x6e, 0x83, 0x8a, 0xf1, 0xc5, 0x27, 0x8d, - 0x1c, 0xdd, 0x59, 0xe2, 0x7b, 0x55, 0xe8, 0x7e, 0xe5, 0x13, 0x63, 0x9a, 0xc4, 0xf8, 0x0d, 0x14, 0x81, 0xa8, 0x71, - 0x0d, 0x46, 0x2d, 0x62, 0xf3, 0xdd, 0x57, 0x6e, 0x9c, 0x41, 0x58, 0x77, 0x1d, 0x07, 0xcb, 0x34, 0xd1, 0x7a, 0x21, - 0xb6, 0x15, 0x56, 0xcd, 0x2a, 0x38, 0x37, 0xe8, 0xcc, 0xe2, 0xcc, 0x88, 0x71, 0xd7, 0xb6, 0x41, 0xa9, 0x82, 0xdc, - 0x22, 0x52, 0xbd, 0x87, 0xf1, 0x58, 0xe1, 0x03, 0x2b, 0xa0, 0xeb, 0xde, 0xa7, 0x01, 0x39, 0xfa, 0xa5, 0x9a, 0xd1, - 0x55, 0x95, 0x2a, 0x28, 0xcd, 0x53, 0x0a, 0x03, 0x19, 0x0a, 0x36, 0xc3, 0x1a, 0xa7, 0x42, 0x6f, 0xc1, 0x34, 0x24, - 0x80, 0xb5, 0x53, 0x86, 0x9e, 0x89, 0xad, 0xc0, 0x16, 0xd2, 0x02, 0x94, 0x1e, 0x76, 0xe8, 0x5b, 0x35, 0xd0, 0xd3, - 0xd5, 0x18, 0xf5, 0x75, 0x7e, 0xda, 0xc5, 0x91, 0x5f, 0x9c, 0x79, 0xf0, 0xcf, 0xfa, 0xd3, 0x12, 0xa4, 0xfc, 0xf1, - 0xa7, 0x98, 0x83, 0x51, 0x3d, 0x6f, 0x61, 0x24, 0x84, 0x42, 0xa6, 0x52, 0x1d, 0xd2, 0xa9, 0xaa, 0xb8, 0xfd, 0xd4, - 0x5b, 0x14, 0xe8, 0xce, 0x91, 0xdf, 0x12, 0xa4, 0x59, 0xca, 0x7a, 0xf5, 0xd3, 0x73, 0xd3, 0x75, 0x50, 0xc4, 0x1a, - 0x2e, 0x33, 0x74, 0xff, 0xf8, 0x05, 0xb8, 0x7f, 0x42, 0x8d, 0xb6, 0x95, 0xdf, 0xd0, 0x5e, 0xdb, 0x3e, 0x90, 0xb4, - 0xdd, 0x24, 0x6b, 0x21, 0x5f, 0xf5, 0x8f, 0xae, 0xf2, 0x6f, 0x6e, 0x3a, 0x4b, 0xc6, 0xf8, 0xac, 0xfa, 0x67, 0x1c, - 0xc2, 0x37, 0x8b, 0xe9, 0x2c, 0xf9, 0x36, 0x90, 0x05, 0xd1, 0x04, 0x3f, 0x16, 0x78, 0x9b, 0x96, 0xc7, 0x94, 0xc8, - 0xb9, 0x44, 0xb5, 0x1e, 0x74, 0x1e, 0x81, 0xc3, 0x76, 0xeb, 0xe1, 0xaf, 0x47, 0xbf, 0x94, 0x34, 0x52, 0xf7, 0x71, - 0x6d, 0xbb, 0x87, 0xf2, 0x22, 0x89, 0x2e, 0xc0, 0x6f, 0x24, 0x1b, 0xe3, 0x18, 0x03, 0xb9, 0xbd, 0x79, 0x26, 0x93, - 0x22, 0x72, 0x96, 0xd0, 0x6f, 0xe4, 0x90, 0x4b, 0xb1, 0xfd, 0x60, 0x7e, 0xae, 0x56, 0xa3, 0xd3, 0x48, 0x76, 0xf8, - 0x43, 0x73, 0x1a, 0xae, 0x4e, 0xa2, 0xa8, 0x9f, 0xcb, 0xef, 0x00, 0x0c, 0xc2, 0xb0, 0x69, 0xe5, 0x02, 0xaa, 0x36, - 0x94, 0x18, 0x59, 0x1d, 0xd5, 0x40, 0x96, 0xbf, 0x0d, 0xaa, 0x32, 0x2a, 0x58, 0x0f, 0xbf, 0xda, 0x18, 0x83, 0x77, - 0x2a, 0x8d, 0xa7, 0x59, 0x3c, 0x1e, 0x27, 0xac, 0xa7, 0xec, 0x23, 0xab, 0xf3, 0x00, 0x93, 0x22, 0xcc, 0x25, 0xab, - 0xaf, 0x8a, 0x41, 0x3c, 0x4d, 0xa7, 0xe8, 0x18, 0xec, 0x35, 0xfc, 0xf4, 0xe2, 0x5a, 0x72, 0xca, 0x6c, 0x81, 0x76, - 0x45, 0x3c, 0x7a, 0xae, 0xe3, 0xb2, 0x03, 0xc6, 0x22, 0x2d, 0x78, 0xbb, 0xc7, 0xb3, 0x79, 0xd0, 0xda, 0xae, 0x23, - 0x82, 0x55, 0x1a, 0x05, 0x6f, 0x0d, 0x5a, 0x1e, 0x5a, 0x07, 0x42, 0xcb, 0x59, 0x7e, 0x47, 0x96, 0xd1, 0x00, 0xf8, - 0x79, 0x3f, 0x5d, 0x54, 0xd6, 0x91, 0xf9, 0xf7, 0xd9, 0x2d, 0x5f, 0xae, 0xdf, 0x2d, 0x5f, 0xaa, 0xdd, 0x72, 0x3d, - 0xc7, 0x7e, 0x31, 0xe9, 0xe0, 0x9f, 0x5e, 0x85, 0x10, 0xac, 0x0a, 0x90, 0xc3, 0x42, 0xbb, 0xb8, 0xd5, 0x85, 0xff, - 0x68, 0xe8, 0xb6, 0x87, 0x7f, 0x7c, 0xb0, 0x00, 0xdb, 0x16, 0x16, 0xe2, 0xbf, 0x76, 0xad, 0xaa, 0x73, 0x1f, 0xeb, - 0xb0, 0xd7, 0xce, 0x6a, 0x5d, 0xf7, 0xfa, 0x4d, 0x0b, 0xf2, 0x8a, 0x3b, 0x81, 0x12, 0xc6, 0xe0, 0xaa, 0x45, 0xc7, - 0xc7, 0x50, 0x3a, 0xc9, 0x46, 0x8b, 0xe2, 0xef, 0x24, 0xfc, 0x92, 0x88, 0xd7, 0x6e, 0xe9, 0xc6, 0x38, 0xaa, 0xab, - 0xc8, 0xb0, 0x51, 0x23, 0x2c, 0xf5, 0x3a, 0x05, 0x05, 0x30, 0x26, 0x73, 0xba, 0xfe, 0xfd, 0x35, 0x9b, 0xe0, 0x3f, - 0x64, 0x6d, 0xd6, 0x22, 0xf3, 0x6f, 0x25, 0xc6, 0xb5, 0x44, 0xf8, 0x2c, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb4, 0x1e, - 0xdc, 0x43, 0x35, 0xd3, 0x50, 0x29, 0x05, 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0x16, 0x09, 0xbf, 0x7e, 0xd4, 0xab, 0x38, - 0x63, 0x65, 0xd4, 0x6b, 0x04, 0x7a, 0xd5, 0xf6, 0x96, 0x52, 0xfa, 0x8b, 0x2f, 0xef, 0xe3, 0x1f, 0x11, 0xfb, 0x3a, - 0xae, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, 0x68, 0xa3, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x6d, 0x5b, 0xa3, - 0xb1, 0x7e, 0xab, 0xe6, 0xd2, 0x2a, 0xfd, 0xac, 0xd6, 0x9f, 0x37, 0xf8, 0x2d, 0xdb, 0x8e, 0x84, 0x43, 0x50, 0x6f, - 0x2b, 0x7f, 0x3b, 0xca, 0x4a, 0x63, 0x45, 0xf1, 0xdb, 0xb6, 0xaf, 0x4c, 0x62, 0xea, 0xb1, 0x11, 0x1e, 0x6b, 0x27, - 0x52, 0x9e, 0x6f, 0x63, 0x0f, 0xe1, 0x47, 0xfe, 0x85, 0x85, 0xf7, 0xf0, 0xc3, 0x62, 0xd6, 0xf9, 0x2c, 0x49, 0xc1, - 0xac, 0x9a, 0x72, 0x3e, 0x0f, 0xb6, 0xb6, 0xce, 0xce, 0xce, 0xfc, 0xb3, 0x6d, 0x3f, 0xcb, 0x4f, 0xb6, 0xba, 0xed, - 0x76, 0x1b, 0xbf, 0x07, 0x65, 0x5b, 0xa7, 0x31, 0x3b, 0x7b, 0x0c, 0xee, 0x87, 0xfd, 0xd0, 0x7a, 0x64, 0x3d, 0xdc, - 0xb6, 0x76, 0x1e, 0xd8, 0x16, 0x29, 0x00, 0x28, 0xd9, 0xb6, 0x2d, 0xa1, 0x00, 0x42, 0x1b, 0x8a, 0xfb, 0xbb, 0x27, - 0xca, 0x86, 0xc3, 0x7c, 0x7b, 0x61, 0x21, 0x81, 0xff, 0x96, 0x7d, 0x62, 0xf5, 0xad, 0x2e, 0xca, 0x5a, 0x52, 0x8d, - 0xa8, 0x57, 0xdc, 0xef, 0xa3, 0x68, 0x1e, 0x10, 0x1b, 0x99, 0x85, 0x18, 0x26, 0x13, 0xa5, 0x34, 0x05, 0xda, 0xa5, - 0xc7, 0xf0, 0x84, 0x19, 0x5a, 0x16, 0x3c, 0xbf, 0xea, 0x3e, 0x04, 0x1d, 0x77, 0xda, 0xba, 0x3f, 0x6a, 0xb7, 0x3a, - 0x56, 0xa7, 0xd5, 0xf5, 0x1f, 0x5a, 0x5d, 0xf1, 0x3f, 0xc8, 0xc8, 0x6d, 0xab, 0x03, 0x4f, 0xdb, 0x16, 0xbc, 0x9f, - 0xde, 0x17, 0xe9, 0x17, 0x91, 0xbd, 0xd5, 0xdf, 0xc5, 0x5f, 0x8f, 0x04, 0x48, 0x7d, 0x69, 0x8b, 0x5f, 0xe8, 0x66, - 0x7f, 0x61, 0x96, 0x76, 0x1e, 0xad, 0x2d, 0xee, 0x3e, 0x5c, 0x5b, 0xbc, 0xfd, 0x60, 0x6d, 0xf1, 0xfd, 0x9d, 0x7a, - 0xf1, 0xd6, 0x89, 0xa8, 0xd2, 0x72, 0x21, 0xb4, 0x67, 0x11, 0x30, 0xca, 0xb9, 0xd3, 0x01, 0x38, 0xdb, 0x56, 0x0b, - 0x7f, 0x3c, 0xec, 0xba, 0xba, 0xd7, 0x31, 0xf6, 0xd2, 0x58, 0x3e, 0x7c, 0x04, 0x58, 0x3e, 0xef, 0x3e, 0x18, 0x61, - 0x3b, 0x42, 0x14, 0xfe, 0x9d, 0x6e, 0x3f, 0x1a, 0x81, 0x46, 0xb0, 0xf0, 0x1f, 0xfc, 0x99, 0xee, 0x74, 0x47, 0xe2, - 0xa5, 0x8d, 0xf5, 0x1f, 0x3a, 0x0f, 0x0b, 0x68, 0x8a, 0x7f, 0x7e, 0xd3, 0x26, 0x34, 0x1a, 0xf0, 0xe6, 0xb8, 0xf7, - 0x81, 0x46, 0x8f, 0xa6, 0x5d, 0xff, 0xcb, 0xd3, 0x87, 0xfe, 0xa3, 0x69, 0xe7, 0xe1, 0x07, 0xf1, 0x96, 0x00, 0x05, - 0xbf, 0xc4, 0x7f, 0x1f, 0xb6, 0xdb, 0xd3, 0x56, 0xc7, 0x7f, 0x74, 0xba, 0xed, 0x6f, 0x27, 0xad, 0x07, 0xfe, 0x23, - 0xfc, 0x57, 0x0d, 0x37, 0xcd, 0x66, 0xcc, 0xb6, 0x70, 0xbd, 0x1b, 0x7e, 0xaf, 0x39, 0x47, 0xf7, 0xbe, 0xb5, 0x73, - 0xff, 0xf9, 0x23, 0x58, 0xa3, 0x69, 0xa7, 0x0b, 0xff, 0x5f, 0xf5, 0xf8, 0x01, 0x09, 0x2f, 0x07, 0x8e, 0x18, 0x66, - 0xca, 0x2a, 0xc2, 0xd1, 0xb7, 0xc9, 0xee, 0x79, 0xdf, 0x5f, 0x15, 0x00, 0x61, 0xfc, 0xe6, 0x20, 0x37, 0xbf, 0x5d, - 0x04, 0x84, 0x3e, 0x9c, 0xff, 0x07, 0x46, 0x40, 0xbe, 0x6f, 0x06, 0xb9, 0xcf, 0x57, 0xf3, 0x03, 0x9b, 0xce, 0xda, - 0x6b, 0xe6, 0x1c, 0xfe, 0x85, 0x0d, 0x31, 0x2b, 0x1c, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0xe7, 0x32, - 0xea, 0x5f, 0xf0, 0x2b, 0x08, 0x12, 0xdf, 0x4c, 0x90, 0x5f, 0x6f, 0x47, 0x8f, 0xf8, 0x0f, 0xa6, 0x47, 0xc1, 0x0d, - 0x7a, 0xd4, 0x22, 0xee, 0x14, 0x31, 0x20, 0x47, 0x7f, 0x9f, 0xde, 0x9d, 0xef, 0xf1, 0xab, 0x62, 0x5b, 0x0c, 0x4b, - 0x0a, 0x5b, 0xe4, 0x24, 0xbe, 0xfb, 0x9c, 0x13, 0x02, 0x91, 0x38, 0x1d, 0xda, 0x32, 0x08, 0x33, 0xc7, 0xcf, 0xef, - 0xaa, 0x97, 0x53, 0x71, 0x39, 0x27, 0xa4, 0x9b, 0x75, 0x3b, 0x3a, 0x80, 0x83, 0xb9, 0xec, 0xe1, 0x32, 0xe3, 0x11, - 0xfe, 0x7e, 0x27, 0x1e, 0xf3, 0x04, 0xef, 0xfd, 0xca, 0x3b, 0x72, 0x98, 0x7a, 0xfd, 0x2d, 0xa6, 0x8d, 0xab, 0x83, - 0x82, 0x19, 0x06, 0x0d, 0x5e, 0xb1, 0x71, 0x1c, 0x39, 0xb6, 0x33, 0x87, 0x5d, 0x0b, 0x63, 0xb6, 0x6a, 0x39, 0xdb, - 0x94, 0xae, 0xed, 0xda, 0xea, 0x57, 0x0a, 0xe5, 0xf8, 0x89, 0xb6, 0xf0, 0x50, 0x06, 0x19, 0x6d, 0xe9, 0x05, 0xc0, - 0xf8, 0xaa, 0x24, 0x47, 0x81, 0x5f, 0x59, 0x0e, 0xb6, 0x30, 0x1d, 0x3a, 0x7e, 0x17, 0x5c, 0x09, 0x2a, 0xc6, 0x4f, - 0x5e, 0xfd, 0xe0, 0xb4, 0xb6, 0xc1, 0xb4, 0x31, 0xba, 0xe9, 0x81, 0x86, 0x2b, 0xa1, 0x24, 0x11, 0x20, 0x68, 0x94, - 0x7a, 0xfa, 0x77, 0xac, 0x55, 0x21, 0xa3, 0xe2, 0xf1, 0xc5, 0x81, 0xbc, 0xd6, 0x6e, 0x63, 0xf4, 0x96, 0xa2, 0xf6, - 0xd5, 0x27, 0xb5, 0x36, 0x41, 0x65, 0xd0, 0x2f, 0xba, 0xa4, 0x33, 0x70, 0xd4, 0x0a, 0x98, 0x55, 0x6e, 0x49, 0xef, - 0x21, 0xb4, 0x85, 0x4e, 0x18, 0xb3, 0xd3, 0x78, 0x24, 0x45, 0xbb, 0x67, 0xc9, 0xdb, 0x30, 0x2d, 0xc2, 0x22, 0xec, - 0x78, 0xc2, 0x7f, 0x86, 0x17, 0xd4, 0x6c, 0x61, 0x9a, 0xd9, 0xfd, 0x7b, 0x3d, 0x0d, 0x49, 0x3d, 0x21, 0xdf, 0xc6, - 0xdf, 0xba, 0x79, 0x08, 0xfe, 0xda, 0xdf, 0x85, 0xf7, 0xf0, 0xf7, 0x6e, 0xde, 0x1b, 0xda, 0xae, 0x4f, 0x82, 0xf1, - 0x5e, 0xf5, 0xcb, 0x37, 0x51, 0x2a, 0x6c, 0x82, 0x0e, 0xf3, 0x6e, 0xab, 0xcc, 0xa4, 0xe2, 0xea, 0xee, 0x54, 0x8a, - 0x0b, 0x9e, 0x0d, 0x49, 0x05, 0x42, 0xb4, 0xeb, 0xef, 0x18, 0xe2, 0xf0, 0xb4, 0x85, 0x3f, 0x6b, 0x02, 0xf1, 0x3e, - 0x34, 0x50, 0x12, 0xf1, 0x25, 0x34, 0xdf, 0x16, 0xc2, 0x17, 0xfa, 0xfd, 0x48, 0xe2, 0x4a, 0x88, 0xaa, 0x3a, 0xc7, - 0xac, 0x39, 0x48, 0x12, 0xf9, 0x02, 0xb6, 0x67, 0xc4, 0x9c, 0x04, 0xbb, 0xca, 0x88, 0xca, 0x53, 0xe8, 0xeb, 0xe8, - 0x2f, 0x55, 0xaf, 0xab, 0xf3, 0x6a, 0xbb, 0x67, 0xcd, 0x14, 0xc8, 0xf0, 0x8d, 0xc3, 0x2a, 0xba, 0x9d, 0x21, 0xbe, - 0xd8, 0x26, 0xb6, 0x72, 0xf5, 0x4d, 0xbb, 0x35, 0x59, 0xc0, 0xe6, 0xa6, 0x60, 0x15, 0xd3, 0xd0, 0xbe, 0xc0, 0xf4, - 0x19, 0xfc, 0x59, 0x15, 0xab, 0x07, 0xc9, 0x50, 0x7e, 0x12, 0xe1, 0x2f, 0x9c, 0xa1, 0x1f, 0x65, 0xb5, 0x01, 0x39, - 0x7d, 0x92, 0x93, 0x20, 0x7d, 0x31, 0x2e, 0x9b, 0x48, 0x80, 0xcd, 0x80, 0xbf, 0xbf, 0xb0, 0xba, 0x0d, 0x22, 0xaf, - 0x79, 0x62, 0x6a, 0xc1, 0x38, 0xce, 0xe9, 0xf6, 0xb0, 0xc2, 0xbf, 0x16, 0xd5, 0xac, 0x48, 0x4d, 0xbb, 0x92, 0x15, - 0x03, 0x1b, 0x8b, 0xec, 0x40, 0x26, 0xc0, 0x99, 0xdf, 0xa4, 0x36, 0xaf, 0x77, 0x8e, 0x45, 0xee, 0x1b, 0x7e, 0xb3, - 0xdf, 0x16, 0x44, 0xb6, 0x41, 0x94, 0x5d, 0x89, 0x13, 0x19, 0x38, 0x78, 0x2b, 0xb2, 0xfa, 0x25, 0x4c, 0xe6, 0x86, - 0xb7, 0xcd, 0xd5, 0xd2, 0xe3, 0xd2, 0x3a, 0xb8, 0x32, 0x86, 0x77, 0xcc, 0x22, 0xee, 0x47, 0x29, 0xe5, 0x29, 0x39, - 0x86, 0x58, 0xf0, 0x3a, 0x6c, 0xdb, 0x2d, 0x41, 0xf2, 0x18, 0xbf, 0xa5, 0x4a, 0x90, 0xde, 0x87, 0x42, 0x95, 0x4b, - 0xfd, 0x7d, 0x2d, 0x15, 0x78, 0xda, 0xed, 0xbf, 0x39, 0xd8, 0xb3, 0xc4, 0xc6, 0xde, 0xdd, 0x82, 0xd7, 0x5d, 0xf2, - 0x8e, 0x45, 0xc6, 0x46, 0x28, 0x32, 0x36, 0x2c, 0x91, 0xe7, 0x25, 0x52, 0x67, 0xb7, 0x04, 0xd6, 0xb6, 0xc5, 0xd2, - 0x91, 0x08, 0xeb, 0xcd, 0xc0, 0x83, 0x88, 0xf1, 0x33, 0x66, 0x5b, 0xd8, 0xb5, 0x85, 0x0b, 0x6f, 0xab, 0xe4, 0x17, - 0x65, 0x33, 0xf0, 0x54, 0x05, 0x01, 0x41, 0xd3, 0x33, 0x95, 0x07, 0x23, 0x87, 0xd2, 0x69, 0xb1, 0xab, 0xad, 0x8b, - 0xc5, 0xf1, 0x0c, 0xc4, 0x92, 0xca, 0x5d, 0x79, 0x2f, 0x3b, 0xec, 0xd2, 0x54, 0xfd, 0xa3, 0x72, 0x5d, 0x94, 0x72, - 0xda, 0xe9, 0xef, 0x46, 0xd2, 0x06, 0xc2, 0xbd, 0x5c, 0xc0, 0x66, 0x06, 0xd5, 0x87, 0x86, 0x86, 0x1f, 0x67, 0x5b, - 0x67, 0xec, 0xb8, 0x15, 0xcd, 0xe3, 0x2a, 0x24, 0x88, 0x1a, 0xb1, 0xbf, 0xab, 0x94, 0xa3, 0x4c, 0xf5, 0x94, 0x8f, - 0x91, 0x91, 0xdc, 0x81, 0x84, 0x24, 0x86, 0x2d, 0x65, 0xbc, 0x91, 0x0c, 0x49, 0x58, 0x0c, 0x00, 0x96, 0xf8, 0x59, - 0xc5, 0x25, 0xa5, 0x66, 0x28, 0xed, 0xfe, 0x5f, 0xff, 0xf7, 0xff, 0x91, 0xa1, 0x46, 0xa0, 0x2d, 0x80, 0x85, 0xd9, - 0x31, 0xd5, 0xa9, 0x23, 0x3b, 0x07, 0xe7, 0x34, 0x1e, 0xb7, 0xa6, 0x51, 0x32, 0x01, 0x08, 0x0a, 0x26, 0xee, 0x14, - 0xc8, 0x7a, 0xe0, 0x0a, 0x09, 0x96, 0x79, 0x62, 0x2f, 0xc1, 0xab, 0x17, 0xe1, 0xb2, 0xfd, 0xae, 0xdc, 0x59, 0x95, - 0xb3, 0x4c, 0x0c, 0x6e, 0x64, 0xd2, 0x1a, 0x3c, 0x58, 0xcb, 0xa6, 0x55, 0xbf, 0x13, 0x4a, 0x0a, 0x13, 0x56, 0x4b, - 0xa5, 0x85, 0x96, 0xfa, 0x70, 0xe4, 0x5f, 0xff, 0xe9, 0xbf, 0xfc, 0x0f, 0xf5, 0x8a, 0x67, 0x1e, 0x7f, 0xfd, 0xc7, - 0xbf, 0xff, 0x7f, 0xff, 0xf7, 0xbf, 0x62, 0xa6, 0xb2, 0x3c, 0x17, 0xa1, 0xad, 0x65, 0x55, 0x87, 0x22, 0x62, 0x8f, - 0x59, 0x95, 0x13, 0x52, 0x4f, 0xb9, 0xdd, 0xa7, 0x09, 0x89, 0x41, 0x25, 0x74, 0xc4, 0xe7, 0x94, 0xa2, 0x4d, 0x54, - 0xbb, 0x86, 0x7c, 0xb0, 0x94, 0x16, 0x1d, 0xf5, 0xdb, 0x3b, 0x6d, 0xbb, 0x5a, 0xde, 0xbe, 0xd1, 0x77, 0x0b, 0x17, - 0xe6, 0x56, 0x89, 0x39, 0xbe, 0x5e, 0xb6, 0xa5, 0x0a, 0x6d, 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x73, 0x5e, 0xe2, - 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0x95, 0x6b, 0x7d, 0x7a, 0xbf, 0x2c, 0x00, 0xd1, 0x09, 0x2e, 0x8d, 0x08, 0xa0, 0xd1, - 0x79, 0x6a, 0x0b, 0xad, 0x95, 0xe4, 0xa2, 0xa4, 0x51, 0x84, 0x87, 0x73, 0xff, 0xd1, 0xdf, 0x96, 0x7f, 0x9e, 0xa1, - 0x95, 0x60, 0x39, 0xb3, 0xe8, 0x5c, 0xfa, 0x3d, 0x0f, 0xda, 0xed, 0xf9, 0xb9, 0xbb, 0xac, 0x66, 0xf0, 0xae, 0x9a, - 0x8c, 0x82, 0x6e, 0xe6, 0x80, 0x74, 0x10, 0xab, 0xe3, 0x7b, 0x60, 0xea, 0xb7, 0x31, 0x1c, 0x54, 0x96, 0x7f, 0x5a, - 0x52, 0x88, 0x29, 0xfe, 0x0d, 0x0f, 0x4c, 0x65, 0x34, 0x0e, 0x4a, 0x0c, 0x2c, 0x96, 0x46, 0xaf, 0xae, 0xe8, 0x35, - 0xed, 0xac, 0xa6, 0xac, 0x98, 0x07, 0xbe, 0xe6, 0x51, 0xed, 0x7d, 0x3c, 0x7c, 0x9d, 0x76, 0xbc, 0x69, 0x77, 0xa9, - 0x87, 0xe7, 0x3c, 0x9b, 0x99, 0x27, 0xbc, 0x2c, 0x62, 0x23, 0x36, 0x51, 0x51, 0x4c, 0x59, 0x2f, 0x4e, 0x6f, 0xcb, - 0x2f, 0x70, 0xbb, 0x01, 0x6d, 0xb3, 0x88, 0x07, 0xc4, 0xb4, 0x3d, 0xf3, 0x0c, 0x38, 0xc2, 0xd3, 0xf5, 0x6c, 0x69, - 0xcc, 0xd5, 0x13, 0x4d, 0x31, 0x56, 0x58, 0x4f, 0x07, 0x2a, 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0x42, 0x0d, 0xbf, 0xca, - 0xa3, 0xd5, 0x77, 0x35, 0x1f, 0x5d, 0x8a, 0x66, 0x70, 0x8b, 0xd7, 0xd6, 0x0b, 0x35, 0x29, 0x6a, 0x3f, 0x80, 0xf5, - 0x43, 0x60, 0xda, 0xcd, 0x56, 0x54, 0x88, 0xad, 0xde, 0x85, 0xbf, 0x6a, 0x7b, 0x3c, 0x9a, 0xcf, 0xa9, 0xa1, 0x0b, - 0xdc, 0x48, 0x76, 0x35, 0x4a, 0x0a, 0x4a, 0x1b, 0x10, 0xa7, 0xf4, 0xb2, 0x8d, 0x64, 0x5b, 0xf1, 0x24, 0xcf, 0xef, - 0xe9, 0x57, 0x8c, 0xff, 0x7f, 0x2a, 0xa5, 0xd0, 0x17, 0x78, 0x7c, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, + 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x28, 0x58, 0x5d, 0x05, 0x5c, 0x81, 0x10, 0x49, 0x95, 0xaa, 0xca, 0xa0, 0x40, 0x5e, + 0xd5, 0x62, 0x57, 0xd9, 0xb5, 0xb9, 0xa4, 0xb2, 0xaf, 0x2d, 0xeb, 0x4a, 0x10, 0x99, 0x14, 0xe1, 0x02, 0x01, 0x1a, + 0x48, 0x6a, 0x31, 0x85, 0x3e, 0xfd, 0xd4, 0x4f, 0x7d, 0xce, 0x6c, 0xfd, 0xd0, 0x0f, 0xd3, 0xa7, 0xfb, 0x61, 0x3e, + 0x62, 0x9e, 0xfb, 0x53, 0xee, 0x0f, 0x4c, 0x7f, 0xc2, 0x44, 0x44, 0x2e, 0x48, 0x80, 0xa4, 0x24, 0xbb, 0x7d, 0xe7, + 0x78, 0x11, 0x90, 0x6b, 0x44, 0x64, 0x64, 0x6c, 0x19, 0x09, 0xee, 0xde, 0x1b, 0x65, 0x43, 0x7e, 0x35, 0x63, 0xd6, + 0x84, 0x4f, 0x93, 0xfe, 0xae, 0xfc, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, 0x78, + 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, 0x53, + 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, 0xc7, + 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, 0xfe, + 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, 0xc4, + 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, 0x8b, + 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, 0x4f, + 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, 0x69, + 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf3, 0xb8, 0x17, 0xbb, 0x61, 0x9f, 0x5b, 0x71, 0x6a, 0xb1, 0xc1, 0x0b, 0x46, 0x25, + 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, 0x7c, + 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xb0, 0x43, 0x7e, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, 0x8c, + 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbf, 0xbe, 0x76, 0x78, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, 0x51, + 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xfc, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, 0x99, + 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xee, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, 0xe9, + 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, 0x28, + 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, 0x0c, + 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, 0xc0, + 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, 0x90, + 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, 0xbe, + 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, 0x58, + 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, 0xc6, + 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdf, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, 0xb3, + 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, 0x05, + 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, 0x41, + 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xac, 0x04, + 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0x60, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, 0x9c, + 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x06, 0x9a, 0x38, 0xd0, 0xb6, 0x68, 0xb4, 0xf5, 0x04, 0xe2, 0x35, 0x12, 0xb9, 0x1e, + 0xf3, 0x25, 0xf9, 0xf6, 0xaf, 0xd2, 0x61, 0x7d, 0x6c, 0xa8, 0x2c, 0x79, 0xb6, 0xcf, 0xf3, 0x38, 0x3d, 0x03, 0x20, + 0xe4, 0x4c, 0x66, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x2c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, 0x7a, + 0xd8, 0x61, 0x88, 0xa4, 0x07, 0x06, 0x63, 0x03, 0x16, 0xb0, 0x4d, 0xdb, 0xf6, 0xbe, 0x73, 0xbd, 0x2b, 0xe4, 0x20, + 0xdf, 0xf7, 0x89, 0x7d, 0x45, 0xe7, 0x38, 0xec, 0x20, 0xd0, 0x7e, 0xc2, 0xd2, 0x33, 0x3e, 0x19, 0xb0, 0xc3, 0xf6, + 0x51, 0xc0, 0x01, 0xaa, 0xd1, 0x7c, 0xc8, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, + 0xf7, 0x08, 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, 0x70, + 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, 0x37, + 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0xe7, 0xc8, 0x43, + 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0x98, 0xbf, 0xcc, 0xc7, + 0x21, 0xf7, 0xa7, 0xd1, 0x0c, 0xb1, 0x61, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, + 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, 0x39, + 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, + 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, 0x73, + 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, 0xd5, + 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, 0xc0, + 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x87, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, 0x19, + 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xf2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, 0xd0, + 0x9f, 0x81, 0x0c, 0xec, 0xa1, 0xe0, 0xfa, 0x4a, 0x4a, 0x9d, 0x88, 0x29, 0x0c, 0x81, 0x00, 0x43, 0x94, 0x20, 0x92, + 0x06, 0xef, 0xb3, 0xe4, 0x6a, 0x1c, 0x27, 0xc9, 0xfe, 0x7c, 0x36, 0xcb, 0x72, 0xee, 0x7d, 0x1d, 0x2e, 0x78, 0x56, + 0xe1, 0x4a, 0x9b, 0xbc, 0xb8, 0x88, 0x39, 0x12, 0xd4, 0x5d, 0x0c, 0x23, 0x58, 0xea, 0xa7, 0x59, 0x96, 0xb0, 0x28, + 0x05, 0x34, 0xd8, 0xc0, 0xb6, 0x83, 0x74, 0x9e, 0x24, 0xbd, 0x53, 0x18, 0xf6, 0x53, 0x8f, 0xaa, 0x85, 0xc4, 0x0f, + 0xe8, 0x79, 0x2f, 0xcf, 0xa3, 0x2b, 0x68, 0x88, 0x6d, 0x80, 0x17, 0x61, 0xb5, 0xbe, 0xda, 0x7f, 0xf7, 0xd6, 0x17, + 0x8c, 0x1f, 0x8f, 0xaf, 0x00, 0xd0, 0xb2, 0x92, 0x9a, 0xe3, 0x3c, 0x9b, 0x36, 0xa6, 0x46, 0x3a, 0xc4, 0x21, 0xeb, + 0xad, 0x01, 0x21, 0xa6, 0x91, 0x61, 0x95, 0x98, 0x09, 0xc1, 0x5b, 0xe2, 0x67, 0x59, 0x89, 0x7b, 0x60, 0x80, 0x0f, + 0x81, 0x28, 0x86, 0x29, 0x6f, 0x86, 0x96, 0xe7, 0x57, 0x8b, 0x38, 0x24, 0x38, 0x67, 0xa8, 0x7f, 0x11, 0xc6, 0x61, + 0x04, 0xb3, 0x2f, 0xc4, 0x80, 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xa2, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x0e, + 0xdb, 0xe8, 0xfa, 0x9a, 0xc1, 0x8b, 0xeb, 0x7d, 0x13, 0x2e, 0x22, 0x85, 0x0f, 0x6a, 0x28, 0xdc, 0x5f, 0x81, 0x90, + 0x13, 0xa8, 0xc9, 0xce, 0x41, 0x0f, 0x02, 0x9c, 0x5f, 0x83, 0xfa, 0x1b, 0x27, 0x08, 0xc5, 0xbd, 0x8e, 0x07, 0x1a, + 0xf4, 0xd9, 0x24, 0x4a, 0xcf, 0xd8, 0x28, 0x98, 0xb0, 0x52, 0x4a, 0xde, 0x3d, 0x0b, 0xd6, 0x18, 0xd8, 0xa9, 0xb0, + 0x5e, 0x1e, 0xbc, 0x79, 0x2d, 0x57, 0xae, 0x26, 0x8c, 0x61, 0x91, 0xe6, 0xa0, 0x56, 0x41, 0x6c, 0x4b, 0x71, 0xfc, + 0x82, 0x2b, 0xe9, 0x2d, 0x4a, 0xe2, 0xe2, 0xe3, 0x0c, 0x4c, 0x0c, 0xf6, 0x1e, 0x86, 0x81, 0xe9, 0x43, 0x98, 0x8a, + 0xca, 0x61, 0x3e, 0x51, 0x31, 0xd2, 0x45, 0xd0, 0x59, 0x60, 0x2a, 0x5e, 0x33, 0xc7, 0x2d, 0x81, 0x55, 0x79, 0x3c, + 0xb4, 0xa2, 0xd1, 0xe8, 0x55, 0x1a, 0xf3, 0x38, 0x4a, 0xe2, 0x5f, 0x88, 0x92, 0x0b, 0xe4, 0x31, 0xde, 0x93, 0x8b, + 0x00, 0xb8, 0x53, 0x8f, 0xc4, 0x55, 0x42, 0xf6, 0x1e, 0x11, 0x43, 0x48, 0xcb, 0x24, 0x3c, 0x3c, 0x92, 0xe0, 0x25, + 0xfe, 0x6c, 0x5e, 0x4c, 0x90, 0xb0, 0x72, 0x60, 0x14, 0xe4, 0xd9, 0x69, 0xc1, 0xf2, 0x73, 0x36, 0xd2, 0x1c, 0x50, + 0x00, 0x56, 0xd4, 0x1c, 0x8c, 0x17, 0x9a, 0xd1, 0x51, 0x3a, 0x94, 0xc1, 0x50, 0x3d, 0x53, 0xcc, 0x32, 0xc9, 0xcc, + 0xda, 0xc2, 0xd1, 0x52, 0xc0, 0x11, 0x46, 0x85, 0x94, 0x04, 0x79, 0xa8, 0x30, 0x9c, 0x80, 0x14, 0x02, 0xad, 0x60, + 0x6e, 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, + 0xca, 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x8d, 0xd0, 0x85, 0x3e, 0xb6, 0x20, 0x36, 0xf0, + 0xf5, 0xca, 0x03, 0x61, 0x25, 0xde, 0x15, 0x22, 0xde, 0x1a, 0xb0, 0x71, 0x62, 0xe4, 0x27, 0xef, 0x1e, 0xf7, 0xd3, + 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, 0x67, + 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, 0xcb, + 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, 0x5d, + 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, 0x85, + 0x4d, 0x41, 0x80, 0x1e, 0xb2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, 0xac, + 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, 0x2b, + 0x90, 0x93, 0x6f, 0x66, 0x27, 0x84, 0x95, 0xb9, 0xd7, 0xd7, 0xdf, 0xa8, 0x41, 0xaa, 0xa5, 0xd4, 0x36, 0x50, 0x63, + 0x4d, 0x6c, 0xd5, 0x64, 0x64, 0xbb, 0x52, 0xa1, 0xde, 0xeb, 0xf4, 0x6a, 0x7c, 0x00, 0x7b, 0xae, 0xad, 0x59, 0xba, + 0x32, 0xb6, 0xdf, 0x2b, 0x9a, 0xbe, 0x13, 0x23, 0x93, 0x35, 0xca, 0x6e, 0xe7, 0x1e, 0xb5, 0xe3, 0xa1, 0xed, 0x52, + 0x5d, 0x25, 0x18, 0xe6, 0x75, 0xc1, 0xd0, 0x84, 0x7a, 0xa6, 0xbb, 0xd8, 0x9a, 0xa9, 0x58, 0xa8, 0xd6, 0x5a, 0x39, + 0x10, 0x3c, 0x3c, 0x04, 0xe3, 0x64, 0xa5, 0x7f, 0xf0, 0x36, 0x9a, 0x32, 0xa4, 0xa8, 0xb7, 0xae, 0x81, 0x74, 0x20, + 0xa0, 0xc9, 0x51, 0x53, 0xbd, 0x71, 0x57, 0x58, 0x4d, 0xf5, 0xfd, 0x15, 0x83, 0x15, 0x01, 0xf6, 0x75, 0xb9, 0x62, + 0x89, 0x48, 0x6f, 0x0a, 0x2e, 0xd1, 0xf4, 0x11, 0x65, 0x62, 0x4d, 0x48, 0xc1, 0x03, 0xf2, 0xb0, 0xfc, 0x8d, 0x85, + 0x93, 0xad, 0x98, 0xc2, 0x91, 0xa3, 0x4c, 0x01, 0x3a, 0x93, 0x12, 0x00, 0x71, 0x49, 0x7f, 0x6b, 0x1b, 0x0b, 0xc9, + 0xb6, 0x8f, 0x7c, 0xe0, 0x8f, 0x93, 0x88, 0x3b, 0x9d, 0xad, 0xb6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, + 0xf7, 0x15, 0x2a, 0x8c, 0xbc, 0x05, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe2, 0x31, 0x77, 0x12, 0x54, 0x22, 0x6e, 0xc9, + 0x12, 0x50, 0x32, 0x7a, 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, + 0x0b, 0x2a, 0x08, 0x0c, 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x25, 0x8b, 0x32, 0x1e, + 0xc4, 0xcb, 0x85, 0xa0, 0x86, 0x7d, 0x9e, 0xbd, 0xce, 0x2e, 0x58, 0xfe, 0x2c, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, + 0x49, 0x4f, 0x02, 0x9d, 0xf5, 0x14, 0xaf, 0x9c, 0x13, 0xd2, 0xb0, 0x10, 0xd3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, + 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, 0xe2, + 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, 0xe9, + 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, + 0x8b, 0xbc, 0xb8, 0xe7, 0x34, 0xd4, 0x11, 0x40, 0x31, 0xad, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, + 0x8d, 0xbc, 0xaa, 0x89, 0x80, 0x38, 0x1d, 0xb1, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, + 0x81, 0x84, 0x57, 0x08, 0x80, 0x79, 0xe2, 0x4f, 0xb2, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xfa, 0x3a, 0x16, 0xfe, + 0x22, 0x32, 0x40, 0xce, 0xa6, 0xd9, 0x39, 0x5b, 0x01, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, + 0x54, 0xcb, 0x2c, 0x89, 0x87, 0x4c, 0x6b, 0xa9, 0xa9, 0x0f, 0x06, 0x1d, 0xbb, 0x04, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, + 0xdf, 0xf6, 0x3a, 0x6e, 0x29, 0x08, 0xbe, 0x58, 0xa2, 0xe8, 0x0d, 0xfa, 0x51, 0x9a, 0xe0, 0xab, 0x64, 0x01, 0x77, + 0x0d, 0xa5, 0xc8, 0x85, 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, + 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, + 0x5a, 0x89, 0x54, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, + 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, + 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, + 0xb6, 0x51, 0xc0, 0x21, 0x5b, 0x62, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0xdc, + 0xc0, 0x72, 0x5c, 0x49, 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8a, 0x8b, 0xf5, 0x24, + 0xf8, 0x5d, 0xc1, 0x7c, 0x6e, 0xcc, 0x74, 0x2b, 0xa4, 0x5a, 0xc2, 0x49, 0x33, 0x58, 0x83, 0x26, 0x8d, 0x07, 0x25, + 0x6a, 0xbe, 0x46, 0x43, 0x85, 0x38, 0xfe, 0x4c, 0x54, 0xa1, 0x09, 0x86, 0x60, 0xe4, 0x5e, 0x21, 0x19, 0x2e, 0x5b, + 0x16, 0x2d, 0x52, 0xa6, 0xc6, 0xa4, 0x52, 0x35, 0xcb, 0x65, 0x60, 0x60, 0xd1, 0x6e, 0xf5, 0xa5, 0x25, 0xae, 0x44, + 0x6e, 0x1a, 0x6a, 0x61, 0x52, 0x28, 0x6f, 0xc2, 0xc9, 0xd1, 0xef, 0x52, 0xd6, 0xbb, 0x89, 0x4f, 0xae, 0xf0, 0xc9, + 0x7d, 0xc3, 0x87, 0x32, 0x79, 0xbb, 0x18, 0x14, 0xc1, 0xd7, 0xb5, 0x4a, 0xb4, 0x4f, 0x7d, 0x14, 0xcc, 0xae, 0x16, + 0xba, 0x20, 0x50, 0x24, 0x9b, 0xa4, 0x03, 0xc9, 0x6f, 0x28, 0x36, 0x2a, 0xcf, 0x28, 0x73, 0xc5, 0x06, 0xa9, 0x79, + 0xa5, 0x99, 0x97, 0xba, 0x0d, 0xfb, 0xbd, 0x2c, 0x25, 0x9d, 0xb8, 0xa0, 0x4c, 0xec, 0xdd, 0x44, 0x1b, 0x2f, 0x0d, + 0x33, 0x61, 0xfd, 0x0a, 0x63, 0xa7, 0x46, 0xa1, 0x54, 0x8a, 0x40, 0x1c, 0x1b, 0x5f, 0x2b, 0xcb, 0x20, 0xf3, 0x57, + 0xd8, 0x53, 0x00, 0x4a, 0x02, 0x8b, 0xaf, 0xa9, 0xe4, 0x45, 0x61, 0x9d, 0x8e, 0xf7, 0x88, 0x8e, 0x95, 0x08, 0xad, + 0x89, 0x7c, 0xad, 0xcf, 0x62, 0xbf, 0xe6, 0x12, 0x9a, 0x94, 0xcc, 0x07, 0x79, 0x60, 0xab, 0x40, 0x44, 0xa5, 0xdb, + 0x92, 0x41, 0x42, 0x0e, 0xe9, 0x32, 0xd1, 0x6b, 0x23, 0x19, 0xb4, 0x4e, 0x85, 0x44, 0x4b, 0x8f, 0xc2, 0xc8, 0x41, + 0xc7, 0x9d, 0xd6, 0x62, 0x89, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, + 0x0e, 0xa0, 0x03, 0x62, 0x7f, 0x89, 0xf5, 0x56, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0xd7, 0xd7, 0x13, 0xe4, 0x07, + 0x61, 0xf0, 0xc2, 0x9a, 0x0d, 0x94, 0xec, 0xdd, 0x7b, 0x8d, 0xad, 0xc8, 0xfe, 0xac, 0x4a, 0x2a, 0x4f, 0xa1, 0xc6, + 0xb9, 0xf5, 0x75, 0x62, 0x66, 0x68, 0x51, 0x55, 0xec, 0x1b, 0x52, 0x7d, 0x5f, 0x29, 0xec, 0x0a, 0xe5, 0x7d, 0x39, + 0x74, 0xec, 0xba, 0x6e, 0x90, 0x93, 0xf3, 0x72, 0x6f, 0x95, 0x0b, 0x79, 0xff, 0xbe, 0xe9, 0x33, 0x9d, 0xeb, 0xe1, + 0x9f, 0x39, 0xa8, 0x9c, 0x8b, 0xab, 0x94, 0x2c, 0x98, 0x67, 0x4a, 0x1d, 0x2d, 0x39, 0xa0, 0xed, 0x1e, 0x7a, 0xda, + 0xd1, 0x45, 0x14, 0x73, 0x4b, 0x8f, 0x22, 0x3c, 0x6d, 0x94, 0x4f, 0xd2, 0xe8, 0x00, 0xbc, 0xd0, 0x84, 0x24, 0x27, + 0xdc, 0xb4, 0x45, 0x8b, 0xe1, 0x84, 0x61, 0x08, 0x5c, 0xd9, 0x13, 0xa6, 0xec, 0xb9, 0x87, 0x78, 0x8b, 0x81, 0xd9, + 0x6a, 0xd8, 0xcb, 0x66, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, 0x04, 0xb2, 0x6d, 0xaa, 0xea, 0xca, 0xc6, 0xbb, 0x14, 0x91, + 0x18, 0x61, 0x5b, 0x35, 0xb6, 0xb4, 0xf5, 0x7b, 0x0d, 0xf7, 0xba, 0x72, 0xcc, 0x6b, 0x4a, 0xb5, 0xa1, 0x87, 0x95, + 0x9b, 0xc3, 0x4c, 0x47, 0x5e, 0xac, 0xa0, 0xdb, 0x13, 0x41, 0x21, 0x70, 0x22, 0xb4, 0x3d, 0xa8, 0xb8, 0x81, 0x48, + 0xc9, 0x95, 0x56, 0xcd, 0xe6, 0xc9, 0x48, 0x02, 0x0b, 0x2e, 0x2c, 0x97, 0x7c, 0x74, 0x11, 0x27, 0x49, 0x55, 0xfa, + 0xbb, 0x0a, 0x78, 0x31, 0xec, 0x6d, 0xa2, 0x5d, 0x60, 0x34, 0x57, 0x20, 0xb8, 0xda, 0x08, 0xfb, 0xe8, 0xb8, 0xd5, + 0xba, 0x8b, 0x88, 0x23, 0x37, 0xa3, 0x11, 0x50, 0x8f, 0x11, 0x56, 0xcd, 0xda, 0x7b, 0x2f, 0x30, 0xa4, 0x66, 0xe0, + 0x83, 0xea, 0x8c, 0x8a, 0x7f, 0x95, 0x3d, 0xf5, 0x2b, 0xd1, 0xbb, 0x55, 0x75, 0x35, 0x03, 0x2a, 0x2a, 0xf0, 0x61, + 0x86, 0x58, 0xda, 0x2a, 0x10, 0x90, 0xeb, 0x61, 0x51, 0x0a, 0x98, 0xa4, 0xc1, 0x82, 0x52, 0x60, 0xad, 0x95, 0xdd, + 0xeb, 0xdb, 0x82, 0x39, 0x14, 0x0a, 0x17, 0xfd, 0x9f, 0x65, 0xd3, 0x19, 0x5a, 0x66, 0x0d, 0xa6, 0x86, 0x06, 0x1f, + 0x1b, 0xf5, 0xe5, 0x8a, 0xb2, 0x5a, 0x1f, 0xda, 0x91, 0x35, 0x7e, 0xd2, 0x8e, 0x32, 0x38, 0x54, 0x73, 0x5d, 0x54, + 0xb7, 0x9b, 0x9b, 0x22, 0x66, 0x15, 0x8f, 0xfb, 0xa4, 0xb7, 0xb5, 0x35, 0xe9, 0x69, 0x1a, 0x90, 0x4c, 0x92, 0x0c, + 0x6f, 0x32, 0x40, 0x59, 0x11, 0x67, 0x51, 0x36, 0xc8, 0xb7, 0x28, 0x4b, 0x5c, 0xbf, 0x1f, 0x7a, 0x7b, 0x35, 0xcf, + 0xda, 0xdb, 0x5b, 0xef, 0x22, 0x57, 0x75, 0xd2, 0x83, 0x3c, 0x3c, 0x82, 0xa2, 0x25, 0x9b, 0x32, 0x5c, 0x4c, 0xb3, + 0x11, 0x0b, 0x6c, 0xe8, 0x9e, 0xda, 0xa5, 0xdc, 0x34, 0x11, 0x6c, 0x8e, 0x88, 0x39, 0x8b, 0x0f, 0xf5, 0x48, 0x6a, + 0xb0, 0x07, 0x2c, 0xa0, 0xcd, 0x85, 0xaf, 0xc2, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x03, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, + 0x05, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, 0x7d, 0x35, 0xf8, 0x2a, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x1d, 0xbf, + 0xed, 0x77, 0x6c, 0x15, 0x11, 0xfb, 0xc9, 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x00, 0x4d, 0x56, 0x78, 0x43, + 0x16, 0xfe, 0x34, 0xf8, 0x49, 0xb9, 0xd4, 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe1, 0x79, 0xa4, 0xed, + 0x2d, 0x44, 0x05, 0xc6, 0x15, 0x29, 0x2e, 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xc6, 0xc6, 0xc2, + 0x79, 0x13, 0xf1, 0x89, 0x9f, 0x47, 0xe9, 0x28, 0x9b, 0x3a, 0xee, 0xa6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0xe7, + 0x6e, 0xb9, 0x71, 0x02, 0x7e, 0x40, 0x68, 0x0f, 0xec, 0xcd, 0x63, 0xef, 0x80, 0x85, 0x27, 0xbb, 0x1b, 0x8b, 0x11, + 0x2b, 0xfb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7f, 0x29, 0xc1, 0x00, 0x76, + 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0xfb, 0x9e, + 0x76, 0x56, 0xef, 0xdf, 0xaf, 0xd4, 0x7c, 0x55, 0xea, 0xcd, 0x59, 0x58, 0xf3, 0xd4, 0xbd, 0x97, 0x74, 0xb4, 0x52, + 0xdf, 0xc8, 0x73, 0x46, 0x4a, 0x73, 0xd9, 0x4e, 0x70, 0x8c, 0x2d, 0xbe, 0x7a, 0x5b, 0x1f, 0x8a, 0x28, 0x85, 0x1f, + 0x83, 0xf5, 0x12, 0x81, 0xfa, 0x06, 0x07, 0xc7, 0x3b, 0x08, 0xb7, 0x76, 0x9d, 0x41, 0xe0, 0xdc, 0x6b, 0xb5, 0xae, + 0x7f, 0xdc, 0x3a, 0xfc, 0x73, 0xd4, 0xfa, 0x65, 0xaf, 0xf5, 0xc3, 0x91, 0x7b, 0xed, 0xfc, 0xb8, 0x35, 0x38, 0x94, + 0x6f, 0x87, 0x7f, 0xee, 0xff, 0x58, 0x1c, 0xfd, 0x41, 0x14, 0x6e, 0xb8, 0xee, 0xd6, 0x99, 0x37, 0x63, 0xe1, 0x56, + 0xab, 0xd5, 0x87, 0xa7, 0x33, 0x78, 0xc2, 0xbf, 0x17, 0xf0, 0xe7, 0xfa, 0xd0, 0xfa, 0x4f, 0x3f, 0xa6, 0xff, 0xf9, + 0xc7, 0xfc, 0x08, 0xc7, 0x3c, 0xfc, 0xf3, 0x8f, 0x85, 0xfd, 0xa0, 0x1f, 0x6e, 0x1d, 0x6d, 0xba, 0x8e, 0xae, 0xf9, + 0x43, 0x58, 0x3d, 0x42, 0xab, 0xc3, 0x3f, 0xcb, 0x37, 0xfb, 0xc1, 0xc9, 0x6e, 0x3f, 0x3c, 0xba, 0x76, 0xec, 0xeb, + 0x07, 0xee, 0xb5, 0xeb, 0x5e, 0x6f, 0xe0, 0x3c, 0xe7, 0x30, 0xfa, 0x03, 0xf8, 0x3b, 0x86, 0xbf, 0x36, 0xfc, 0x9d, + 0xc2, 0xdf, 0x3f, 0x43, 0x37, 0x11, 0x7f, 0xbb, 0xa6, 0x58, 0xc8, 0x35, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, + 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0x71, 0xbc, 0x01, 0x8b, 0x8e, 0x9c, + 0xb3, 0x11, 0x30, 0x4f, 0x44, 0x0e, 0x8a, 0x80, 0x8b, 0xb3, 0xd5, 0x02, 0x0f, 0x57, 0xbd, 0x61, 0xb8, 0xc1, 0x1c, + 0x30, 0x0a, 0xde, 0x32, 0x7c, 0xe8, 0xba, 0xde, 0x0b, 0x79, 0x66, 0x88, 0xfb, 0x5c, 0xb0, 0x56, 0x9a, 0x09, 0x93, + 0xc6, 0x76, 0xbd, 0xd9, 0x8a, 0x4a, 0xd8, 0xd6, 0xe9, 0x19, 0xd4, 0x9d, 0x8a, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, + 0xb7, 0xe4, 0x1b, 0xe3, 0x10, 0x78, 0xc9, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xa7, 0x0c, 0x66, + 0x58, 0x32, 0x11, 0x39, 0x29, 0x4d, 0x61, 0xd9, 0xc2, 0xe4, 0xef, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, + 0x64, 0x9b, 0x96, 0xfe, 0x1d, 0xa6, 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xeb, 0x70, + 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, 0x9f, 0xf3, 0x1e, 0xd5, 0x18, 0xfc, 0x2b, 0xc3, 0x0c, 0x9e, 0x98, 0x0f, 0x43, + 0x34, 0x8b, 0x52, 0x07, 0xb7, 0x52, 0x14, 0xf7, 0xaf, 0x70, 0x67, 0xa4, 0xa5, 0xb7, 0x1f, 0xaa, 0x1d, 0x73, 0x90, + 0x33, 0xf6, 0x5d, 0x94, 0x7c, 0x62, 0xb9, 0x73, 0xe9, 0x75, 0xba, 0x9f, 0x53, 0x67, 0x0f, 0x6d, 0xb3, 0x0f, 0xd5, + 0x31, 0x9a, 0x32, 0x0b, 0xd4, 0x11, 0x61, 0xab, 0xe3, 0xe5, 0x18, 0xd5, 0x42, 0x12, 0x14, 0x5e, 0x16, 0x76, 0x89, + 0xc3, 0xed, 0xdd, 0xe2, 0xfc, 0xac, 0x6f, 0x07, 0xb6, 0x0d, 0x16, 0xff, 0x01, 0x85, 0xad, 0x84, 0x61, 0x01, 0x06, + 0xd9, 0x6e, 0xdc, 0xe3, 0x9b, 0x9b, 0x55, 0xc0, 0x09, 0x0f, 0xd2, 0xa9, 0x7b, 0xe2, 0x45, 0xde, 0x24, 0x84, 0x01, + 0x87, 0xd0, 0x0c, 0xbb, 0xf4, 0x86, 0xbb, 0xb1, 0x9c, 0x06, 0x63, 0x21, 0x7e, 0x12, 0x15, 0xfc, 0x15, 0xc6, 0x23, + 0xc2, 0x21, 0x1a, 0xfb, 0x3e, 0xbb, 0x64, 0x43, 0x65, 0x67, 0x00, 0xa1, 0x22, 0xb7, 0xe7, 0x0e, 0x43, 0xa3, 0x19, + 0xcc, 0x1d, 0x86, 0x07, 0x03, 0x1b, 0xf6, 0x12, 0xec, 0xca, 0x30, 0x3a, 0xec, 0x1c, 0x0d, 0xd2, 0x70, 0xc6, 0x02, + 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0xea, 0x1e, 0x0d, 0x9c, 0x29, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x86, 0x11, + 0x8a, 0x22, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0xce, 0x1c, 0x7b, 0x77, 0xcb, 0xde, 0xc4, 0x52, 0xcf, 0x06, 0xf6, 0x82, + 0xb9, 0xc3, 0x0b, 0xd7, 0xec, 0xbc, 0x7d, 0x84, 0xa0, 0x62, 0x21, 0x4e, 0x7e, 0x31, 0xb0, 0xfb, 0x62, 0xea, 0x36, + 0x0c, 0x9a, 0xca, 0xe5, 0xc7, 0x15, 0x3d, 0x20, 0x54, 0x55, 0x57, 0x05, 0x1d, 0x94, 0x75, 0x03, 0x67, 0x62, 0x22, + 0xd1, 0xc2, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, 0x30, 0xa9, 0xd1, 0x6d, 0xfb, 0x68, 0x70, 0x11, 0x3c, 0xb0, + 0x1f, 0xa8, 0x97, 0x31, 0x20, 0xc3, 0xc4, 0xf4, 0x63, 0x90, 0x76, 0xf8, 0xf7, 0x9c, 0x01, 0x92, 0x17, 0x54, 0x34, + 0x93, 0x45, 0x67, 0x58, 0x74, 0x10, 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xa3, 0x90, 0x60, 0xbf, 0x7f, + 0x1f, 0x96, 0x66, 0xb3, 0x73, 0x84, 0xe7, 0x0d, 0x39, 0x2f, 0xbe, 0x8b, 0x39, 0xa8, 0x84, 0xad, 0xbe, 0xed, 0x0e, + 0x6c, 0x0b, 0x97, 0xb6, 0x97, 0x6d, 0x86, 0x82, 0xc2, 0xf1, 0xe6, 0x01, 0x0b, 0x26, 0xfd, 0xb0, 0x3d, 0x70, 0x72, + 0x19, 0x6e, 0xc4, 0x73, 0x4b, 0x21, 0xc1, 0xdb, 0xde, 0x04, 0x04, 0x3a, 0x72, 0xee, 0x86, 0xbd, 0xa9, 0x0a, 0xa1, + 0xe8, 0x78, 0x73, 0xe4, 0x06, 0x31, 0xfc, 0x71, 0x5a, 0xc8, 0x34, 0x13, 0xdd, 0x57, 0x6b, 0x66, 0x37, 0x18, 0x29, + 0x8b, 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, + 0xb1, 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, + 0x47, 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf3, 0x0c, 0x09, 0xc5, 0x4b, 0xed, 0x86, 0x09, + 0x73, 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, + 0xbd, 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, + 0xe1, 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, + 0x02, 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x71, 0xe9, 0xda, + 0xa3, 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, + 0xbf, 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, + 0x60, 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, + 0x46, 0xe0, 0x39, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, + 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, + 0xdc, 0x82, 0x18, 0x87, 0x1b, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, + 0x8a, 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, + 0x52, 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, + 0x36, 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x39, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, + 0xf4, 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, + 0xa2, 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xb9, 0xf9, 0x52, 0xcc, 0x86, 0xbb, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, + 0xd1, 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x4b, 0xcc, 0xd9, 0x6f, 0x83, 0x0d, + 0x5e, 0xcb, 0x3b, 0x40, 0xfb, 0x8e, 0x4d, 0x67, 0xfc, 0x6a, 0x9f, 0x14, 0x7d, 0x20, 0xd3, 0x06, 0xc4, 0xd9, 0x79, + 0xbb, 0x17, 0xef, 0xf2, 0x5e, 0x0c, 0x52, 0x3d, 0x57, 0x2c, 0x86, 0x7b, 0xd5, 0x7b, 0x8f, 0x51, 0x4a, 0x93, 0x99, + 0xbc, 0x1a, 0x7a, 0x5d, 0x89, 0xde, 0xe6, 0x26, 0x20, 0xd8, 0x33, 0xba, 0x72, 0xd1, 0xb5, 0x2c, 0x05, 0x4d, 0x00, + 0xa2, 0x27, 0x75, 0x96, 0x23, 0x8e, 0xc3, 0x6c, 0x36, 0x28, 0x1e, 0x31, 0x77, 0xe5, 0xa8, 0x38, 0x26, 0x76, 0x97, + 0x09, 0x3b, 0x80, 0x19, 0x71, 0x79, 0xab, 0x23, 0xa2, 0xc3, 0xa2, 0xbf, 0x8e, 0x6f, 0x1f, 0x7b, 0x6c, 0xb3, 0xe3, + 0x82, 0x06, 0xa9, 0x8d, 0xf5, 0xb8, 0x1a, 0x0b, 0xea, 0xc3, 0x63, 0x4d, 0xa5, 0xb2, 0xd8, 0xdc, 0x2c, 0xeb, 0x47, + 0xb5, 0x6a, 0x07, 0xd7, 0x4e, 0x53, 0x2e, 0x9b, 0xd9, 0x20, 0x1c, 0x88, 0x98, 0x40, 0x81, 0x96, 0x56, 0x56, 0x0c, + 0x30, 0xa4, 0x2c, 0x47, 0xf9, 0x14, 0x32, 0x2f, 0x2e, 0x4b, 0x9d, 0xfa, 0xf2, 0x4c, 0x06, 0x1d, 0xf1, 0xd4, 0x93, + 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x0b, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, + 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, 0x0c, 0xda, 0xfe, 0x59, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x8f, + 0x02, 0xaa, 0x9f, 0x4b, 0x09, 0x36, 0x09, 0x3f, 0x02, 0x1b, 0x55, 0x8e, 0x27, 0x09, 0xc2, 0xe7, 0x71, 0xce, 0xc8, + 0x53, 0xd8, 0x90, 0x30, 0x4b, 0xd3, 0x36, 0x52, 0xed, 0x22, 0x33, 0x08, 0xe5, 0xc2, 0xfc, 0x13, 0xe3, 0xec, 0x22, + 0x0b, 0x97, 0x5a, 0x83, 0xf9, 0xf1, 0xce, 0x04, 0x28, 0xbb, 0xbe, 0xce, 0x84, 0x8f, 0x1b, 0x91, 0xbd, 0xa1, 0x2b, + 0x26, 0x03, 0x85, 0x54, 0xe0, 0x44, 0x64, 0xf1, 0xd0, 0x19, 0x0a, 0x8d, 0x70, 0x40, 0xa7, 0xc8, 0xb9, 0x6b, 0x6c, + 0xfa, 0x7c, 0xa0, 0x7d, 0xa3, 0x34, 0x74, 0x12, 0x10, 0x02, 0x02, 0x77, 0xc3, 0x9a, 0x4a, 0x07, 0x69, 0x90, 0x50, + 0x29, 0xfa, 0x39, 0x80, 0x7f, 0x18, 0x49, 0x0a, 0x80, 0xfd, 0x50, 0x8d, 0x14, 0x51, 0x96, 0x05, 0x2e, 0x00, 0xcd, + 0xb5, 0x8f, 0x2b, 0xe1, 0x0b, 0x03, 0x15, 0xa6, 0xa7, 0x59, 0x79, 0x29, 0x94, 0xc8, 0xd3, 0x15, 0x29, 0x6b, 0x24, + 0x93, 0xcf, 0xd1, 0xe1, 0x53, 0xde, 0xf5, 0x5b, 0x89, 0x87, 0x2e, 0x78, 0x0e, 0xcb, 0xaa, 0x9e, 0xdf, 0x84, 0x9c, + 0x9c, 0x6b, 0xd0, 0x15, 0x52, 0xe8, 0x2f, 0x39, 0xc9, 0x7b, 0x6f, 0xfc, 0xaa, 0x96, 0x1a, 0x43, 0xd9, 0xc7, 0x55, + 0xcd, 0xb0, 0xbc, 0x9c, 0x55, 0x61, 0x0a, 0x02, 0x6e, 0xc1, 0x92, 0x60, 0x21, 0x35, 0x04, 0x58, 0xd8, 0x1e, 0x69, + 0xa5, 0x20, 0x2f, 0x75, 0x78, 0xe7, 0x39, 0x58, 0x01, 0xc6, 0xa1, 0x96, 0x4a, 0xa6, 0x91, 0xc4, 0x97, 0x4a, 0x14, + 0x98, 0x72, 0x7f, 0x08, 0x7e, 0x6a, 0xf3, 0xa4, 0xeb, 0xd2, 0xf5, 0xe3, 0x29, 0xa6, 0xf6, 0x10, 0xe8, 0xb1, 0x77, + 0x0f, 0x4c, 0x89, 0xba, 0x0e, 0x2b, 0x88, 0x43, 0xb3, 0x9a, 0x66, 0x01, 0x33, 0xa6, 0x0d, 0x5a, 0xb2, 0x0d, 0xb6, + 0x5c, 0x0e, 0xf6, 0x91, 0xd8, 0x9e, 0xd5, 0x0a, 0x08, 0x5d, 0x83, 0x06, 0x86, 0xdc, 0xa5, 0x42, 0x0b, 0xf3, 0x5e, + 0x97, 0x8a, 0x70, 0x7f, 0x0e, 0xb8, 0xb4, 0x82, 0x33, 0x2f, 0xa3, 0x81, 0xf7, 0xe3, 0xd3, 0x04, 0x13, 0x5f, 0x10, + 0x2b, 0xb0, 0x83, 0x83, 0x4e, 0xb3, 0x29, 0x70, 0x2a, 0x2e, 0x52, 0x06, 0xcb, 0x8a, 0x52, 0x1b, 0xfe, 0x48, 0x91, + 0xad, 0xbb, 0x3c, 0xd2, 0x5d, 0x88, 0x05, 0xb0, 0xd3, 0x2f, 0x18, 0xf9, 0x96, 0xf5, 0x32, 0x60, 0x70, 0xae, 0x35, + 0x0e, 0x02, 0xbf, 0xb9, 0x99, 0x1c, 0x95, 0x29, 0xb1, 0x5d, 0x93, 0xd5, 0x05, 0xe4, 0x98, 0x04, 0xd8, 0xc0, 0x1d, + 0x84, 0xa5, 0xb2, 0xc7, 0x8b, 0x72, 0x8a, 0xcb, 0xa5, 0x2c, 0xe4, 0xe6, 0x79, 0x35, 0xcd, 0xe7, 0x56, 0x9a, 0x4d, + 0xc7, 0x5b, 0xf1, 0x45, 0xc1, 0x3f, 0x70, 0x62, 0x69, 0xd5, 0x53, 0x6a, 0x85, 0x47, 0x99, 0x5b, 0xb2, 0x4e, 0x49, + 0xad, 0xae, 0x1b, 0xa8, 0x46, 0x78, 0x9a, 0x86, 0x8d, 0x40, 0x88, 0x09, 0x2e, 0x7e, 0xdb, 0x64, 0x62, 0xda, 0x5b, + 0x42, 0xea, 0x08, 0xbb, 0x87, 0x72, 0x82, 0xbb, 0x9a, 0x67, 0x5f, 0x86, 0xb3, 0xf5, 0xcc, 0xbd, 0x67, 0x30, 0xf7, + 0xd3, 0x90, 0x1b, 0x8c, 0x1e, 0xcb, 0x84, 0x1f, 0x19, 0xfb, 0xc8, 0x55, 0xd5, 0xb3, 0xb3, 0xb0, 0x12, 0x59, 0xe2, + 0xc9, 0x38, 0xea, 0x30, 0x4e, 0x45, 0x6b, 0x82, 0xec, 0xfa, 0xba, 0x30, 0xf7, 0x02, 0x05, 0x4d, 0x3d, 0x5e, 0x8f, + 0xd3, 0x56, 0xec, 0x6c, 0x44, 0x22, 0xf7, 0xde, 0xd4, 0x22, 0x91, 0x15, 0x9f, 0xe3, 0x48, 0x6b, 0x0e, 0x72, 0x9f, + 0x9d, 0x2d, 0x6f, 0x52, 0xa1, 0x5b, 0x34, 0xda, 0xc6, 0x1e, 0xd5, 0x07, 0x92, 0x7a, 0x46, 0x05, 0x56, 0x35, 0xf6, + 0xfd, 0xfb, 0x1d, 0x91, 0x6e, 0xa9, 0x14, 0x1b, 0x2c, 0x2d, 0x8c, 0x66, 0x8c, 0x82, 0x41, 0x49, 0x91, 0x81, 0x1a, + 0xe5, 0x6b, 0x04, 0xc3, 0x1e, 0x35, 0x00, 0xc5, 0xb9, 0xba, 0xfa, 0x69, 0x29, 0xd9, 0x42, 0x40, 0xe2, 0x2e, 0x18, + 0x88, 0x35, 0xc1, 0xcc, 0xc8, 0x27, 0x1f, 0x81, 0xf3, 0x06, 0x0c, 0x1d, 0x03, 0xf0, 0x0b, 0xc4, 0xa6, 0x07, 0x13, + 0xdb, 0x26, 0xa2, 0xe8, 0xb3, 0x81, 0x97, 0x00, 0xec, 0xac, 0x0a, 0x8d, 0x7e, 0xa8, 0x52, 0xc0, 0x90, 0x0d, 0xdc, + 0x80, 0x55, 0x61, 0xb9, 0xbd, 0x97, 0xe0, 0x36, 0xc0, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xb3, 0x0b, + 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0x41, 0xa3, 0x5e, 0x51, 0x42, 0xd4, 0xee, 0x63, 0xed, 0x4b, 0x8c, 0xb0, 0x88, + 0xf7, 0x37, 0xf8, 0xae, 0xc7, 0x2d, 0xf7, 0x34, 0x5a, 0x84, 0xe9, 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, + 0xbd, 0xdc, 0x17, 0xb1, 0xe0, 0x0a, 0x47, 0x56, 0x85, 0x14, 0x1b, 0x48, 0xd2, 0xd3, 0x1e, 0x1d, 0xb0, 0x6f, 0x34, + 0x7b, 0x01, 0x65, 0x3e, 0x56, 0xa4, 0x92, 0x90, 0xd2, 0xec, 0x86, 0x48, 0x12, 0xd6, 0x8a, 0x3c, 0x75, 0xde, 0x77, + 0xb4, 0xcf, 0xad, 0x24, 0x82, 0x11, 0x9c, 0x84, 0xe9, 0x58, 0x79, 0xd0, 0x14, 0xe0, 0x2a, 0x3a, 0x62, 0xfa, 0x26, + 0x20, 0xbf, 0x19, 0xc8, 0xed, 0xa5, 0xe4, 0xda, 0x5c, 0xc3, 0xf0, 0x0c, 0x09, 0x56, 0x45, 0x22, 0xf0, 0x88, 0x1a, + 0x70, 0xcc, 0x57, 0x79, 0x1e, 0x60, 0xc2, 0xd7, 0xf6, 0x26, 0x00, 0x94, 0x93, 0xab, 0xe2, 0x2c, 0x05, 0xba, 0x01, + 0xcb, 0xd5, 0x71, 0x6a, 0x54, 0x24, 0x2e, 0x6e, 0x4c, 0x57, 0xb7, 0xf4, 0xa7, 0x68, 0x39, 0x93, 0x21, 0xa6, 0x83, + 0x20, 0x20, 0x53, 0x9f, 0x32, 0x47, 0xc8, 0x5c, 0x61, 0x7d, 0xce, 0x9c, 0xda, 0xd4, 0x3d, 0x46, 0xdd, 0x3c, 0x49, + 0x2d, 0x5e, 0xa7, 0x4d, 0x29, 0x11, 0x93, 0x12, 0xf3, 0x54, 0xa4, 0x62, 0x33, 0x25, 0xee, 0xdc, 0xfa, 0x46, 0x0b, + 0x69, 0xa3, 0x9d, 0x8a, 0x1c, 0x6c, 0x56, 0xc9, 0x7b, 0x02, 0xe3, 0xa5, 0x20, 0x7c, 0x89, 0x8c, 0xb5, 0x98, 0x33, + 0xc7, 0x44, 0xb0, 0x7a, 0x31, 0x15, 0xf9, 0x07, 0x47, 0xa7, 0xd9, 0x1b, 0xf4, 0x20, 0xf5, 0x06, 0x12, 0xb3, 0x26, + 0xbe, 0x0b, 0x69, 0xa8, 0x23, 0x04, 0x2a, 0xa3, 0x5a, 0xa6, 0xe3, 0xc4, 0x2a, 0x7c, 0x23, 0xf8, 0xea, 0xbd, 0x3e, + 0xce, 0x37, 0x9e, 0x1b, 0xab, 0x11, 0xc4, 0xe0, 0x2d, 0xe4, 0x47, 0x9e, 0x14, 0xe1, 0x40, 0xb8, 0x7c, 0x73, 0xb3, + 0x97, 0xef, 0xf2, 0x2a, 0x44, 0x52, 0xc1, 0x18, 0x63, 0x46, 0x31, 0xee, 0x89, 0x9a, 0x5a, 0xcc, 0x61, 0x60, 0xd9, + 0x3a, 0xcc, 0xf1, 0x00, 0x00, 0x5a, 0x9a, 0xd2, 0xab, 0xa6, 0x42, 0xe5, 0x79, 0x2e, 0xe1, 0x53, 0x1d, 0xa2, 0xaa, + 0xc6, 0xef, 0x57, 0x67, 0xa0, 0x10, 0xdc, 0xf7, 0x3a, 0x1e, 0x1e, 0x42, 0xc0, 0x2a, 0x0a, 0x59, 0xa0, 0x37, 0x68, + 0xaf, 0x4a, 0x84, 0x62, 0xe6, 0x64, 0x3d, 0x66, 0x38, 0xa9, 0x60, 0x0b, 0x95, 0xb0, 0x54, 0x5a, 0xe0, 0x57, 0x1b, + 0xa1, 0x79, 0xca, 0xb8, 0xf7, 0xa6, 0xc2, 0x19, 0xf4, 0x07, 0xf3, 0x96, 0x19, 0xf5, 0xfd, 0xd2, 0x89, 0x4c, 0x05, + 0x26, 0x6e, 0x66, 0xa9, 0xfd, 0x7e, 0x59, 0xa5, 0xfd, 0xbc, 0x42, 0xee, 0x73, 0xd2, 0x7c, 0x9d, 0x3b, 0x68, 0x3e, + 0x19, 0xee, 0x57, 0xca, 0x0f, 0x2d, 0x8c, 0x9a, 0xf2, 0xcb, 0xeb, 0xca, 0xaf, 0xf0, 0x54, 0x78, 0xab, 0xdf, 0x45, + 0xa1, 0x8b, 0xfa, 0x1c, 0x0c, 0x21, 0xfd, 0x08, 0xae, 0xa1, 0xc1, 0x83, 0x22, 0x59, 0x2c, 0xd6, 0x2e, 0x88, 0xeb, + 0x63, 0x4e, 0xb5, 0x43, 0x19, 0x63, 0xc4, 0xd3, 0x92, 0x83, 0x24, 0x83, 0x83, 0xf1, 0x1b, 0x18, 0x10, 0x93, 0x92, + 0x90, 0x0e, 0xa1, 0xb3, 0x32, 0x13, 0x51, 0xb9, 0x8b, 0xb7, 0x1b, 0x97, 0x35, 0x85, 0x22, 0xec, 0x04, 0x33, 0x95, + 0x52, 0x41, 0x20, 0x4d, 0xbe, 0x7b, 0x9d, 0x5a, 0x30, 0xb4, 0x70, 0x4d, 0x05, 0xe4, 0xb5, 0x5d, 0x0f, 0x9a, 0x7c, + 0xa4, 0x18, 0xfa, 0x2a, 0x35, 0xe2, 0x65, 0x06, 0x5f, 0xc3, 0xe6, 0xaf, 0x89, 0x92, 0x3c, 0x64, 0x22, 0xf6, 0x0a, + 0x3e, 0x11, 0xb2, 0x29, 0xd8, 0x99, 0x40, 0x3f, 0xb4, 0x2b, 0x7b, 0xe9, 0x6e, 0x51, 0xb9, 0xb4, 0x68, 0x6c, 0x25, + 0x6a, 0xd6, 0xfc, 0x30, 0xde, 0x4c, 0x61, 0x3f, 0x7b, 0x94, 0x40, 0x40, 0x9a, 0xca, 0x49, 0xaa, 0x79, 0x0f, 0xd3, + 0x23, 0x00, 0x09, 0x76, 0x3f, 0x81, 0x85, 0x7e, 0x53, 0x62, 0x82, 0x45, 0xd5, 0xd8, 0x6d, 0x06, 0x5a, 0x73, 0x46, + 0x9a, 0x6f, 0x86, 0x5a, 0x7b, 0x53, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x66, 0x71, 0x98, 0x6e, 0x76, 0x8e, + 0x0c, 0xc1, 0x85, 0xc7, 0xff, 0x49, 0x89, 0x69, 0x20, 0xb9, 0xd4, 0x8d, 0x9f, 0x50, 0x87, 0xe1, 0xff, 0x16, 0xa4, + 0x80, 0x07, 0xb5, 0xd5, 0x58, 0x72, 0xee, 0x15, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, + 0x89, 0x62, 0x9e, 0x13, 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, + 0xca, 0xcf, 0xe8, 0x48, 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x0b, 0x30, 0xcd, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, + 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0x59, 0x83, + 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, 0x55, 0x60, 0x40, + 0xb9, 0xd3, 0x34, 0xac, 0x84, 0xb8, 0x44, 0x85, 0x59, 0xc5, 0xf9, 0xe3, 0x3a, 0xaf, 0x9b, 0x96, 0x25, 0x06, 0xe5, + 0x67, 0xae, 0xe1, 0xc6, 0xf7, 0x1a, 0xf9, 0xe3, 0x7b, 0x2f, 0x41, 0xb7, 0x13, 0x69, 0xef, 0xdf, 0xcf, 0xef, 0x91, + 0x85, 0x86, 0xf7, 0xc2, 0x66, 0xd0, 0x16, 0xe9, 0x92, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, + 0x30, 0x03, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, + 0xe4, 0xc5, 0x3a, 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x00, 0xfa, 0x15, 0x95, 0xc5, 0x06, 0x72, + 0x71, 0x53, 0xd6, 0x7a, 0x45, 0xa3, 0xd1, 0x8d, 0x5d, 0x58, 0x5d, 0x81, 0x4f, 0xa2, 0x74, 0x94, 0x88, 0x49, 0xcc, + 0xa4, 0xca, 0x15, 0xb9, 0x36, 0xba, 0x97, 0xb6, 0x68, 0x5e, 0x0a, 0x09, 0x5e, 0x11, 0xb8, 0x21, 0xf4, 0x95, 0xbe, + 0x5c, 0x6d, 0xa0, 0xe0, 0x51, 0x7b, 0x73, 0x11, 0x4c, 0x4c, 0x3c, 0x66, 0x48, 0x4d, 0xbf, 0x0e, 0xa7, 0x56, 0x16, + 0x4b, 0x0e, 0xbf, 0xce, 0x19, 0x6b, 0x28, 0x00, 0xe2, 0x93, 0x47, 0xeb, 0xdd, 0xa4, 0x37, 0x4a, 0x3b, 0x28, 0x8d, + 0x10, 0xdf, 0x55, 0xf8, 0xba, 0x0b, 0xc5, 0x57, 0xae, 0xba, 0xf7, 0x75, 0xcc, 0x8c, 0x0b, 0x46, 0x2f, 0xf9, 0x34, + 0x69, 0x5c, 0xbb, 0xa1, 0xbb, 0x3a, 0xdf, 0x7b, 0x5f, 0xca, 0xbc, 0x85, 0x63, 0x60, 0x93, 0x63, 0xe6, 0xbc, 0xf4, + 0xde, 0x1a, 0x27, 0xca, 0x3f, 0x98, 0x47, 0xbc, 0x72, 0x98, 0x55, 0x27, 0xc9, 0x3f, 0x0c, 0x7e, 0x08, 0xd6, 0xb7, + 0x34, 0x4e, 0x90, 0xbb, 0xea, 0x04, 0x99, 0x28, 0xb7, 0xa1, 0x37, 0xdc, 0xde, 0x5d, 0x05, 0x82, 0x38, 0x15, 0xd3, + 0x47, 0xe5, 0xb8, 0x7e, 0xb4, 0x40, 0xa5, 0x22, 0xe2, 0x73, 0x95, 0xbb, 0xb2, 0x36, 0x35, 0xd4, 0xe3, 0x3a, 0x99, + 0x85, 0xa6, 0x59, 0x91, 0x4b, 0xd9, 0xf4, 0x18, 0x99, 0x66, 0xa7, 0xda, 0xfc, 0xee, 0xda, 0x43, 0x3a, 0x86, 0xe6, + 0x62, 0xad, 0x16, 0xdc, 0xef, 0x2a, 0x0a, 0xef, 0x7a, 0xb1, 0x91, 0xca, 0x50, 0xb3, 0x1e, 0x45, 0x1f, 0xc7, 0x6d, + 0xe6, 0xf2, 0x28, 0xfb, 0xb3, 0x06, 0x80, 0xe9, 0x08, 0x8b, 0xee, 0xa6, 0x67, 0xec, 0x09, 0xf4, 0xf4, 0x44, 0x06, + 0x89, 0xde, 0xe8, 0x7c, 0xd5, 0x2a, 0xb1, 0x74, 0x05, 0x81, 0xdd, 0x1b, 0x32, 0x56, 0x25, 0xed, 0x96, 0xeb, 0x97, + 0xf3, 0x7c, 0x9e, 0xf3, 0xa5, 0x3c, 0x9f, 0x9a, 0x45, 0x77, 0xaf, 0xed, 0xde, 0x9c, 0x1a, 0x2a, 0xe6, 0x5a, 0xdd, + 0xe4, 0x37, 0x4c, 0xd7, 0xc1, 0x50, 0x8b, 0x20, 0xb3, 0xda, 0x55, 0x2f, 0xca, 0x72, 0xa3, 0x9e, 0xc9, 0xb1, 0x21, + 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0xf7, 0x8d, 0x6d, 0x21, 0xdb, 0xbc, 0xbc, 0x1a, 0xe5, 0x40, + 0x69, 0xb9, 0xbf, 0x4c, 0x18, 0xbe, 0xbf, 0xbe, 0xfe, 0x5e, 0xc8, 0xa9, 0xaa, 0xa3, 0xb7, 0x78, 0xad, 0x7b, 0x06, + 0x1b, 0xa5, 0x72, 0x22, 0x2e, 0xd8, 0xea, 0xc1, 0x9b, 0xbb, 0x57, 0xc0, 0x72, 0x01, 0xd8, 0x5d, 0x30, 0xa7, 0x31, + 0x54, 0xb5, 0x81, 0xbf, 0x5c, 0x3d, 0xd8, 0xaa, 0x3d, 0xfc, 0xe5, 0xe0, 0xcb, 0xe0, 0xc6, 0xc6, 0xc6, 0x36, 0xde, + 0xae, 0x25, 0x82, 0xbc, 0xc1, 0x03, 0x7d, 0xbc, 0xfa, 0x28, 0x68, 0xb9, 0x4a, 0x6c, 0x0f, 0x1c, 0x0a, 0x5b, 0x83, + 0x7c, 0x93, 0x32, 0x69, 0x38, 0x2f, 0x78, 0x36, 0x95, 0x33, 0x14, 0xf2, 0x9a, 0x8f, 0x83, 0xb6, 0x23, 0xfc, 0x1b, + 0x38, 0xb5, 0xe3, 0xe5, 0xc5, 0x27, 0xe8, 0x03, 0x9e, 0xae, 0x94, 0xa6, 0x22, 0x4e, 0x29, 0xb7, 0xe8, 0x72, 0x9d, + 0x07, 0x23, 0xc5, 0xc5, 0x04, 0x95, 0x8e, 0xbb, 0xb8, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, + 0x44, 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, + 0xd7, 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, + 0xe7, 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, + 0x52, 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, + 0x2d, 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, + 0xc4, 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, + 0xd6, 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, + 0xe2, 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0xe7, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, + 0x68, 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, + 0x57, 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, + 0x30, 0x93, 0xa6, 0xbc, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, + 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0xe1, 0x03, 0xb9, 0xd4, 0x92, 0xbf, + 0xcc, 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, + 0x51, 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x25, 0x7f, 0x8e, 0xa9, + 0x83, 0x59, 0xa9, 0xdd, 0xb4, 0xd8, 0x24, 0x79, 0xcf, 0x0c, 0x48, 0xae, 0xbe, 0x86, 0x87, 0xc6, 0x2f, 0x5e, 0x99, + 0x53, 0xc2, 0x17, 0x65, 0x2c, 0x2d, 0x8d, 0xb9, 0xf4, 0xdf, 0xca, 0xfb, 0xb4, 0x12, 0xb0, 0x57, 0x20, 0xa6, 0x0c, + 0x5c, 0x62, 0xe3, 0x82, 0xa4, 0xbc, 0x96, 0xa7, 0xec, 0xbe, 0x86, 0xf2, 0x5d, 0x32, 0xe9, 0x2a, 0x95, 0xb5, 0xc6, + 0xaa, 0xfb, 0x79, 0xce, 0xf2, 0xab, 0x7d, 0x86, 0xb9, 0xc9, 0x68, 0x90, 0x2d, 0x99, 0xd9, 0x94, 0x5f, 0xed, 0xdd, + 0xf8, 0x95, 0x87, 0x92, 0x0e, 0xd5, 0x2a, 0xdd, 0xbc, 0x74, 0xc3, 0x31, 0x6e, 0xdc, 0x70, 0x04, 0xb0, 0x31, 0xec, + 0x54, 0x91, 0x5a, 0xe7, 0xbf, 0x2f, 0x87, 0x9f, 0x68, 0xaf, 0x1d, 0xe9, 0x5d, 0x77, 0xb4, 0x32, 0x3d, 0xfd, 0x06, + 0x54, 0x8d, 0x2c, 0xa1, 0x9b, 0x50, 0xc5, 0x64, 0x24, 0x4a, 0x4c, 0x57, 0x29, 0x8f, 0xfa, 0x1a, 0x71, 0x0e, 0xe2, + 0x86, 0xf2, 0x17, 0xff, 0x14, 0x5e, 0x9d, 0x04, 0x68, 0x44, 0x2d, 0xc6, 0x59, 0xca, 0x5b, 0xe3, 0x68, 0x1a, 0x27, + 0x57, 0xc1, 0x3c, 0x6e, 0x4d, 0xb3, 0x34, 0x2b, 0x66, 0xc0, 0x95, 0x5e, 0x71, 0x05, 0x36, 0xfc, 0xb4, 0x35, 0x8f, + 0xbd, 0x97, 0x2c, 0x39, 0x67, 0x3c, 0x1e, 0x46, 0x9e, 0xbd, 0x97, 0x83, 0x78, 0xb0, 0xde, 0x46, 0x79, 0x9e, 0x5d, + 0xd8, 0xde, 0x87, 0xec, 0x14, 0x98, 0xd6, 0x7b, 0x77, 0x79, 0x75, 0xc6, 0x52, 0xef, 0xe3, 0xe9, 0x3c, 0xe5, 0x73, + 0xaf, 0x88, 0xd2, 0xa2, 0x55, 0xb0, 0x3c, 0x1e, 0x83, 0x9a, 0x48, 0xb2, 0xbc, 0x85, 0xf9, 0xcf, 0x53, 0x16, 0x24, + 0xf1, 0xd9, 0x84, 0x5b, 0xa3, 0x28, 0xff, 0xd4, 0x6b, 0xb5, 0x66, 0x79, 0x3c, 0x8d, 0xf2, 0xab, 0x16, 0xb5, 0x08, + 0x3e, 0x6b, 0x6f, 0x47, 0x9f, 0x8f, 0x1f, 0xf6, 0x78, 0x0e, 0x7d, 0x63, 0xa4, 0x62, 0x00, 0xc2, 0xc7, 0xda, 0xde, + 0x69, 0x4f, 0x8b, 0x7b, 0xe2, 0x44, 0x29, 0x4a, 0x79, 0x79, 0xe2, 0x5d, 0x31, 0x80, 0xdb, 0x3f, 0xe5, 0xa9, 0x07, + 0xbe, 0x1c, 0xcf, 0xd2, 0xc5, 0x70, 0x9e, 0x17, 0x30, 0xc0, 0x2c, 0x8b, 0x53, 0xce, 0xf2, 0xde, 0x69, 0x96, 0x03, + 0xd9, 0x5a, 0x79, 0x34, 0x8a, 0xe7, 0x45, 0xf0, 0x70, 0x76, 0xd9, 0x43, 0x5b, 0xe1, 0x2c, 0xcf, 0xe6, 0xe9, 0x48, + 0xce, 0x15, 0xa7, 0xb0, 0x31, 0x62, 0x6e, 0x56, 0xd0, 0x97, 0x50, 0x00, 0xbe, 0x94, 0x45, 0x79, 0xeb, 0x0c, 0x3b, + 0xa3, 0xa1, 0xdf, 0x1e, 0xb1, 0x33, 0x2f, 0x3f, 0x3b, 0x8d, 0x9c, 0x4e, 0xf7, 0xb1, 0xa7, 0xfe, 0xf3, 0x77, 0x5c, + 0x30, 0xdc, 0x57, 0x16, 0x77, 0xda, 0xed, 0xbf, 0x71, 0x7b, 0x8d, 0x59, 0x08, 0xa0, 0xa0, 0x33, 0xbb, 0xb4, 0x8a, + 0x2c, 0x81, 0xf5, 0x59, 0xd5, 0xb3, 0x37, 0x03, 0xbf, 0x29, 0x4e, 0xcf, 0x82, 0xee, 0xec, 0xb2, 0x44, 0xec, 0x02, + 0x91, 0x90, 0x29, 0x91, 0x94, 0x6f, 0x8b, 0xdf, 0x0a, 0xf1, 0x93, 0xd5, 0x10, 0x77, 0x15, 0xc4, 0x15, 0xd5, 0x5b, + 0x23, 0xd8, 0x07, 0x44, 0xfe, 0x4e, 0x21, 0x00, 0x99, 0x80, 0x13, 0x98, 0x2b, 0x38, 0xe8, 0xe5, 0x37, 0x83, 0xd1, + 0x5d, 0x0d, 0xc6, 0x93, 0xdb, 0xc0, 0xc8, 0xd3, 0xd1, 0xa2, 0xbe, 0xae, 0x1d, 0x70, 0x4e, 0x7b, 0x13, 0x86, 0xfc, + 0x14, 0x74, 0xf1, 0xf9, 0x22, 0x1e, 0xf1, 0x89, 0x78, 0x24, 0x76, 0xbe, 0x10, 0x75, 0x3b, 0xed, 0xb6, 0x78, 0x2f, + 0x40, 0xa1, 0x05, 0x1d, 0x1f, 0x1b, 0x00, 0x13, 0x7d, 0xb1, 0xee, 0x23, 0x36, 0xdf, 0xdd, 0xfa, 0xa5, 0x1a, 0x8f, + 0xa9, 0xbc, 0x41, 0xa1, 0x22, 0xd4, 0x37, 0x5b, 0x30, 0xe3, 0x2d, 0xef, 0x77, 0xf4, 0x41, 0xd5, 0xe0, 0x3b, 0x46, + 0x5a, 0x2f, 0xe0, 0x9e, 0x99, 0x0b, 0xd4, 0x4b, 0xfb, 0x18, 0x92, 0x6a, 0xb5, 0x5c, 0xd0, 0x1b, 0x0c, 0x43, 0x48, + 0x74, 0x20, 0xe8, 0xe4, 0x83, 0x82, 0xbe, 0xa9, 0x91, 0xb9, 0x41, 0xe1, 0x64, 0x2e, 0x6c, 0xf9, 0x4c, 0xcb, 0x75, + 0x50, 0xd2, 0xe0, 0x65, 0x7f, 0xc1, 0x64, 0x03, 0x90, 0xde, 0x95, 0xa4, 0xe5, 0xd5, 0xd1, 0x93, 0x72, 0xf9, 0xb2, + 0x21, 0x51, 0x0e, 0x7c, 0x7d, 0x3e, 0x41, 0xbf, 0x5b, 0x7f, 0x28, 0xc6, 0x48, 0xa9, 0xd9, 0xb2, 0xdd, 0x01, 0xd3, + 0x59, 0x59, 0x98, 0x7d, 0xc6, 0x4a, 0x1c, 0xe5, 0x2b, 0xb0, 0xa4, 0x31, 0xf4, 0xfa, 0x73, 0x28, 0xdc, 0x34, 0xe5, + 0xa4, 0x6d, 0xdc, 0x74, 0xfd, 0x1f, 0x56, 0x3c, 0xa6, 0x6c, 0x67, 0x15, 0x1b, 0x07, 0xd7, 0xe5, 0x78, 0x28, 0xae, + 0x1d, 0x16, 0x98, 0x2d, 0xfe, 0xdb, 0x3d, 0x09, 0x47, 0xa3, 0x55, 0x64, 0xf3, 0x7c, 0x48, 0xa1, 0xc1, 0xe5, 0x10, + 0x83, 0x4d, 0x1a, 0xde, 0xf6, 0x98, 0x56, 0x2c, 0xe8, 0x77, 0xd7, 0xbe, 0xaa, 0xc0, 0xe9, 0xd4, 0x45, 0x5c, 0x6a, + 0x90, 0x61, 0x15, 0x05, 0x36, 0xea, 0xca, 0x11, 0x25, 0xd8, 0xd1, 0x85, 0x4f, 0x7f, 0x9e, 0xc6, 0x20, 0x5a, 0x8f, + 0xe3, 0x11, 0x5d, 0x74, 0x89, 0x47, 0x74, 0xf2, 0xd1, 0xa2, 0x4c, 0x27, 0x0c, 0xa5, 0x43, 0x81, 0x24, 0x38, 0x3e, + 0xcb, 0xcc, 0x19, 0xbb, 0x65, 0xe3, 0xe9, 0x85, 0xa1, 0x9b, 0x47, 0xd9, 0x34, 0x8a, 0xd3, 0x00, 0x3f, 0x48, 0xe2, + 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0x5f, 0x45, 0xfb, 0x8e, 0xeb, 0xff, 0x04, 0x82, 0x8b, 0xfa, 0x97, 0xd2, 0xf1, + 0xd3, 0x70, 0xa9, 0x73, 0xe5, 0x7a, 0x29, 0x08, 0x3b, 0xae, 0x8c, 0x64, 0x46, 0x81, 0x95, 0x5d, 0x4e, 0x7f, 0x06, + 0xad, 0x4e, 0xa0, 0xae, 0xfe, 0x9b, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, + 0xf3, 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, + 0x56, 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, + 0x5b, 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xe1, 0x55, 0xa7, 0x7a, 0xd6, 0x96, 0x62, 0xef, 0xe1, + 0xc9, 0xae, 0x10, 0x52, 0x16, 0xb1, 0x6e, 0x68, 0x83, 0xd4, 0xb0, 0xad, 0x3f, 0x0e, 0x81, 0xce, 0x9f, 0x42, 0x7b, + 0x63, 0xe1, 0xa8, 0xbb, 0x00, 0x39, 0xcc, 0xb5, 0x27, 0x14, 0x35, 0x7d, 0x44, 0xc0, 0xee, 0x6f, 0x2c, 0x78, 0xb9, + 0xbb, 0x25, 0x7a, 0xf7, 0x4f, 0xca, 0x82, 0x74, 0xaa, 0x19, 0xfb, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, 0x1c, + 0xe3, 0xb8, 0xb9, 0xb6, 0x13, 0x45, 0x90, 0x5b, 0x32, 0x6e, 0x81, 0x19, 0x56, 0x51, 0x0e, 0x62, 0x44, 0xe7, 0xd0, + 0x14, 0x22, 0x6d, 0xa4, 0xb7, 0x0c, 0xc5, 0x09, 0x42, 0x30, 0xd8, 0x58, 0xc4, 0x65, 0xb8, 0xb1, 0x60, 0xe9, 0x30, + 0x1b, 0xb1, 0x8f, 0x1f, 0x5e, 0xe1, 0x35, 0x89, 0x2c, 0x45, 0x79, 0x9a, 0xb9, 0xe5, 0x09, 0x18, 0x58, 0x08, 0x69, + 0xae, 0xbe, 0x52, 0x03, 0xc0, 0x88, 0x58, 0x91, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, 0x1c, + 0x59, 0x2c, 0x00, 0x13, 0x94, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, 0x9a, + 0x23, 0x1a, 0x15, 0xaa, 0x98, 0x55, 0x64, 0xa2, 0x3b, 0x8a, 0xcf, 0x35, 0x39, 0x29, 0xc5, 0xba, 0xbf, 0x9b, 0x44, + 0xa7, 0x2c, 0x81, 0x21, 0x81, 0xaf, 0xda, 0x30, 0x92, 0x78, 0xb5, 0x76, 0xe3, 0x74, 0x36, 0x97, 0x5f, 0x0b, 0x83, + 0x89, 0x3b, 0x78, 0x80, 0x8b, 0x97, 0x19, 0x06, 0xea, 0x44, 0x32, 0x90, 0x03, 0x00, 0x88, 0x74, 0x18, 0x82, 0xd0, + 0x55, 0xac, 0x02, 0xa5, 0xf1, 0x68, 0xb9, 0x0c, 0xf6, 0xf7, 0x0c, 0x4b, 0x53, 0x78, 0x9e, 0xc6, 0x29, 0x3e, 0x16, + 0xf8, 0x18, 0x5d, 0xe2, 0x63, 0x06, 0x8f, 0x1a, 0xf7, 0xbc, 0xb4, 0xff, 0xaa, 0xab, 0x92, 0xc9, 0x15, 0xb0, 0x34, + 0x01, 0xb2, 0xeb, 0x6b, 0x50, 0x5b, 0x9a, 0x04, 0xbb, 0x5b, 0x40, 0x2c, 0xe4, 0x1e, 0xf1, 0xed, 0x18, 0x66, 0x92, + 0x91, 0x15, 0xb3, 0x96, 0x28, 0xb7, 0xc8, 0x38, 0x08, 0xc1, 0x77, 0xcc, 0x9d, 0x86, 0x0d, 0xe4, 0xc9, 0x2c, 0x99, + 0x67, 0xf8, 0xe2, 0xda, 0x96, 0xf8, 0xb8, 0x87, 0x20, 0x0a, 0x3d, 0x22, 0x86, 0xba, 0x8c, 0xcb, 0xcf, 0xf6, 0xc4, + 0xa1, 0x8d, 0xb3, 0x80, 0x19, 0x8a, 0xca, 0x8c, 0x47, 0x71, 0x22, 0x1a, 0xaf, 0xc0, 0xa7, 0x91, 0xee, 0x48, 0xe8, + 0xec, 0x6e, 0x55, 0xb0, 0x01, 0xf0, 0x4a, 0x22, 0x88, 0x54, 0x4e, 0x5b, 0x94, 0x53, 0x0a, 0x80, 0xdc, 0xe6, 0xd5, + 0x27, 0x9d, 0x80, 0x29, 0xc0, 0x88, 0x1e, 0x1d, 0xd3, 0x6c, 0x83, 0x21, 0x12, 0x0b, 0x67, 0x6c, 0x6c, 0x5d, 0xfb, + 0x2f, 0xff, 0xfc, 0x0f, 0xb6, 0x27, 0x40, 0xcc, 0xc6, 0x63, 0x90, 0x72, 0xd6, 0xba, 0x86, 0xff, 0xeb, 0x1f, 0xff, + 0xef, 0xff, 0xf9, 0xaf, 0xba, 0x6d, 0x0a, 0x4d, 0x4f, 0x02, 0x71, 0xb4, 0xa0, 0x49, 0x4a, 0x29, 0x9e, 0xf6, 0x38, + 0x4a, 0x57, 0x80, 0x74, 0x08, 0x54, 0x9a, 0x31, 0x36, 0xf2, 0x6c, 0x0b, 0x34, 0x81, 0x78, 0x3e, 0x4e, 0xd8, 0x39, + 0x93, 0x1f, 0x96, 0xd1, 0x83, 0xe8, 0xca, 0x21, 0x58, 0x30, 0x5c, 0xde, 0x79, 0x95, 0xdb, 0x40, 0xd1, 0x52, 0x52, + 0xbc, 0x4e, 0x30, 0xcf, 0x36, 0x06, 0x6d, 0xce, 0xd1, 0xae, 0x0f, 0xeb, 0x81, 0x4a, 0xb5, 0x6d, 0x01, 0x2f, 0x99, + 0xbd, 0xab, 0x20, 0x5e, 0x82, 0xeb, 0x34, 0xc7, 0xa6, 0x29, 0x2b, 0x8a, 0x55, 0x60, 0x01, 0x4d, 0x3c, 0xbb, 0x6a, + 0x62, 0xd7, 0x3a, 0x00, 0x00, 0xdd, 0x9d, 0x1d, 0x31, 0x2d, 0x54, 0xb0, 0xf1, 0x18, 0x36, 0x38, 0xea, 0xb6, 0x84, + 0xe3, 0xb1, 0x45, 0xd8, 0xb7, 0xdf, 0x82, 0x2c, 0xb1, 0xc1, 0x3f, 0x74, 0xf5, 0x01, 0x34, 0x4d, 0xaf, 0x84, 0x9d, + 0x31, 0x87, 0xe8, 0x6c, 0x0c, 0xa3, 0x9f, 0x0c, 0xa4, 0xb2, 0xe1, 0xa7, 0x55, 0x8c, 0xb1, 0x96, 0x11, 0xfe, 0xfd, + 0x5f, 0xfe, 0xf1, 0xbf, 0xc1, 0xd8, 0xd4, 0x6f, 0x3d, 0x17, 0x40, 0xab, 0xff, 0x09, 0xad, 0xe6, 0xe9, 0x2d, 0xed, + 0xfe, 0xf2, 0xf7, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x29, 0xe0, 0x13, 0x82, 0x68, 0x88, 0xb6, 0xe9, 0xaf, 0x02, 0xa9, + 0x36, 0xc8, 0xda, 0x99, 0xfe, 0x09, 0xc1, 0x2e, 0x78, 0x36, 0xbb, 0x11, 0x1c, 0x84, 0x7a, 0x98, 0x64, 0x05, 0xd3, + 0xf0, 0x08, 0x7d, 0xf2, 0xeb, 0x00, 0xa2, 0xb9, 0x66, 0xb0, 0x6b, 0x0b, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xd5, 0x38, + 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, + 0xda, 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, + 0x52, 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, + 0x48, 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, + 0x24, 0xd2, 0xba, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, + 0x9f, 0x87, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, + 0x12, 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, + 0x97, 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, + 0x0c, 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, + 0x7f, 0x83, 0x97, 0x1d, 0x2d, 0xec, 0x8d, 0x96, 0x42, 0x41, 0x86, 0x0d, 0x27, 0xc3, 0x46, 0x6a, 0x54, 0xd3, 0xa6, + 0x40, 0xc7, 0x2f, 0x5b, 0x6d, 0x3b, 0x1c, 0x63, 0xf7, 0x9a, 0xf6, 0xe7, 0x52, 0xfb, 0xc7, 0xd2, 0xde, 0x97, 0xda, + 0x1f, 0x3f, 0x69, 0xd3, 0xd0, 0xfe, 0xf1, 0x5a, 0xed, 0x8f, 0x94, 0x1b, 0xe0, 0xc8, 0xa1, 0xbd, 0x89, 0xd1, 0x2d, + 0xc3, 0xd6, 0xe0, 0x68, 0x67, 0x0d, 0x27, 0x6c, 0xf8, 0x49, 0x9a, 0x59, 0x84, 0x00, 0x86, 0x77, 0xb4, 0x31, 0x29, + 0x30, 0x00, 0x93, 0xe1, 0xa4, 0xd4, 0x9b, 0x1e, 0x1f, 0x8d, 0x09, 0xb8, 0xbb, 0x18, 0x33, 0x14, 0xfd, 0xb0, 0x66, + 0x5f, 0xb1, 0x72, 0x0b, 0xc7, 0x11, 0x1b, 0x46, 0x3c, 0x03, 0x66, 0x5b, 0x38, 0xd8, 0x89, 0xb7, 0x10, 0xc1, 0xc2, + 0xc0, 0x7e, 0xff, 0x6e, 0xff, 0xc0, 0xf6, 0x4e, 0xb3, 0xd1, 0x55, 0x60, 0x83, 0x33, 0x06, 0xd6, 0x94, 0xeb, 0xf3, + 0x09, 0x4b, 0x1d, 0xe5, 0xf9, 0x64, 0x09, 0xb8, 0x9a, 0xd9, 0x99, 0xf8, 0xb6, 0x45, 0xf3, 0xa0, 0x03, 0x08, 0x4b, + 0x1f, 0xbf, 0xec, 0xef, 0x72, 0xf1, 0x5d, 0x58, 0x9e, 0xe3, 0x63, 0x1f, 0x53, 0x3d, 0x76, 0xb7, 0xe0, 0x01, 0x5f, + 0xf6, 0x51, 0xef, 0xd1, 0xdb, 0xc6, 0x62, 0xc9, 0x6d, 0x18, 0xe0, 0x10, 0x93, 0xbe, 0x40, 0xa1, 0xa0, 0x56, 0x27, + 0x01, 0x22, 0x06, 0x8f, 0x30, 0xd6, 0x96, 0x1a, 0x17, 0x21, 0x54, 0xfd, 0xb5, 0xe3, 0x52, 0xd9, 0xad, 0x34, 0xef, + 0x08, 0xcd, 0x52, 0x72, 0x5c, 0xb0, 0xf7, 0x48, 0x97, 0x08, 0x53, 0x87, 0x8a, 0xd6, 0x41, 0xa0, 0x6b, 0x2a, 0x73, + 0x45, 0x74, 0x30, 0x80, 0x21, 0x33, 0x57, 0x00, 0x02, 0x7f, 0x09, 0xed, 0x13, 0xf3, 0xfb, 0x6f, 0xe2, 0x53, 0x4d, + 0x9a, 0x38, 0x87, 0x7f, 0xf2, 0xae, 0x98, 0x77, 0x75, 0x42, 0x2d, 0x55, 0xb0, 0x01, 0xa3, 0x60, 0x18, 0x94, 0x69, + 0xab, 0xa8, 0x12, 0xd8, 0x69, 0x49, 0x34, 0x2b, 0x58, 0xa0, 0x1e, 0x64, 0xdc, 0x01, 0xc3, 0x17, 0xcb, 0x81, 0x1e, + 0xd3, 0x9e, 0x2b, 0xf9, 0x64, 0x61, 0x06, 0x26, 0x1e, 0xb5, 0xdb, 0x3d, 0xbc, 0x54, 0xd1, 0x8a, 0xc0, 0x3a, 0x48, + 0x83, 0x84, 0x8d, 0x79, 0xc9, 0xf1, 0xd6, 0xfe, 0x42, 0x45, 0x82, 0xfc, 0xee, 0x4e, 0xce, 0xa6, 0x96, 0x8f, 0xff, + 0xbf, 0x6d, 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, + 0x0d, 0x19, 0x46, 0xc9, 0x4a, 0x9e, 0x83, 0xbc, 0xf7, 0x78, 0x6e, 0xb6, 0x03, 0x39, 0xbd, 0x14, 0x2a, 0x5b, 0x0e, + 0xd6, 0x6c, 0xbb, 0xd2, 0x3f, 0x5a, 0x6e, 0xac, 0x22, 0x5e, 0xf5, 0xb7, 0x25, 0x0a, 0x19, 0xb1, 0xb9, 0x52, 0xa8, + 0xa8, 0x85, 0xe8, 0x61, 0xe2, 0xb4, 0x1c, 0xb5, 0xbb, 0xd5, 0x62, 0x2e, 0x49, 0x5c, 0x1c, 0x92, 0xb8, 0x20, 0xf1, + 0x77, 0xb4, 0x10, 0x73, 0x0f, 0xa3, 0x64, 0xe8, 0x20, 0x00, 0x56, 0xcb, 0x7a, 0x02, 0xd4, 0x74, 0x55, 0xe4, 0xc8, + 0x7f, 0x8c, 0xc4, 0x2d, 0x85, 0xb0, 0x5c, 0x41, 0xa5, 0x93, 0xa3, 0xb2, 0xec, 0x31, 0xe6, 0x1c, 0x7e, 0x90, 0x97, + 0x40, 0xc4, 0xdd, 0x5f, 0xfd, 0xfd, 0xc4, 0x76, 0xe9, 0x1e, 0x79, 0x3f, 0x1b, 0x1f, 0xa5, 0xb3, 0x15, 0xb3, 0xdb, + 0x1e, 0x2c, 0x83, 0xd9, 0x53, 0x7e, 0x42, 0xf2, 0xa6, 0xbe, 0x26, 0x9b, 0x53, 0xff, 0x9f, 0x43, 0x1c, 0xe1, 0x8d, + 0x63, 0xa3, 0x89, 0x4e, 0x23, 0x5f, 0xb5, 0x88, 0x3f, 0x6d, 0xec, 0x2a, 0x8e, 0x40, 0xbe, 0x5e, 0x17, 0xc9, 0xfa, + 0xe6, 0xf6, 0x48, 0x56, 0x71, 0xc7, 0x48, 0xd6, 0x37, 0xbf, 0x73, 0x24, 0xeb, 0x6b, 0x33, 0x92, 0x85, 0x02, 0xfa, + 0xd5, 0xaf, 0x89, 0x36, 0xe5, 0xd9, 0x45, 0x11, 0x76, 0x64, 0xe6, 0x04, 0xc8, 0x3a, 0x0c, 0x3b, 0xfd, 0xf5, 0x23, + 0x4c, 0x30, 0x51, 0x23, 0xbe, 0x44, 0x01, 0x25, 0x91, 0xec, 0x09, 0x6a, 0x45, 0x86, 0x73, 0xda, 0x3a, 0xab, 0xb2, + 0xf5, 0x50, 0x5d, 0x23, 0x03, 0xd7, 0xd7, 0xd5, 0xa1, 0xb6, 0xae, 0x0a, 0xf8, 0x04, 0xf4, 0x1d, 0x58, 0xdd, 0xb1, + 0xbb, 0xa9, 0xd2, 0xf9, 0xcc, 0x11, 0x7a, 0xea, 0x94, 0x46, 0x30, 0xd1, 0xc2, 0xfe, 0x2f, 0x87, 0x9d, 0xde, 0x76, + 0x67, 0x0a, 0xbd, 0x41, 0x81, 0xc3, 0x5b, 0xbb, 0xb7, 0xbd, 0x8d, 0x6f, 0x17, 0xea, 0xad, 0x8b, 0x6f, 0xb1, 0x7a, + 0xdb, 0xc1, 0xb7, 0xa1, 0x7a, 0x7b, 0x84, 0x6f, 0x23, 0xf5, 0xf6, 0x18, 0xdf, 0xce, 0xed, 0xf2, 0x90, 0x6b, 0xe0, + 0x1e, 0x03, 0x5f, 0x91, 0x37, 0x13, 0xa8, 0x32, 0xd8, 0xf4, 0x78, 0xfd, 0x32, 0x3a, 0x0b, 0x62, 0x4f, 0x78, 0x97, + 0x41, 0xee, 0x5d, 0x80, 0xc6, 0x09, 0x28, 0xdb, 0xf0, 0x39, 0x7e, 0x87, 0x03, 0x9c, 0xa4, 0x83, 0x78, 0xca, 0xd4, + 0x07, 0x89, 0x15, 0xd6, 0x60, 0xc0, 0x1e, 0xb6, 0x8f, 0xca, 0x9e, 0x5e, 0x27, 0x11, 0xcf, 0x52, 0xd9, 0x1c, 0xb4, + 0x72, 0x55, 0x9d, 0x98, 0xae, 0xa5, 0x57, 0x78, 0x8d, 0xfe, 0x32, 0xe2, 0x11, 0x63, 0x30, 0xcc, 0x5a, 0x97, 0xe0, + 0xc1, 0xae, 0xd4, 0x69, 0x08, 0x91, 0xd6, 0x69, 0x84, 0x93, 0x7e, 0x3b, 0x88, 0xce, 0xf4, 0xf3, 0x1b, 0xb0, 0xb4, + 0xa3, 0x33, 0xd9, 0x72, 0xbd, 0x0e, 0x23, 0x10, 0x4d, 0xfd, 0xa5, 0x80, 0x20, 0x53, 0x0c, 0x96, 0x06, 0x3d, 0x69, + 0xa9, 0xbf, 0x90, 0x3a, 0x75, 0x8d, 0x46, 0xd3, 0xd7, 0x8b, 0x80, 0xa2, 0x55, 0xc1, 0x2e, 0x18, 0xfc, 0x54, 0x2a, + 0x28, 0x0c, 0x15, 0x58, 0x20, 0xaa, 0xd7, 0xa8, 0x32, 0x1d, 0x6c, 0x58, 0xab, 0xd0, 0x2c, 0xa5, 0xcb, 0xcc, 0xd3, + 0x1d, 0x7d, 0xb4, 0xb3, 0x2c, 0x5e, 0x3f, 0xeb, 0x0c, 0xf1, 0x1f, 0x29, 0xbc, 0x3f, 0x1b, 0x8f, 0xc7, 0x37, 0xea, + 0xb6, 0xcf, 0x46, 0x63, 0xd6, 0x65, 0x3b, 0x3d, 0x8c, 0xfc, 0xb7, 0xa4, 0x38, 0xed, 0x94, 0x44, 0xbb, 0xc5, 0xdd, + 0x1a, 0xa3, 0xe4, 0x05, 0x75, 0x77, 0x77, 0x25, 0x58, 0x02, 0x55, 0x16, 0x20, 0xfc, 0xcf, 0xe2, 0x34, 0x68, 0x97, + 0xfe, 0xb9, 0xd4, 0x1a, 0x9f, 0x3d, 0x79, 0xf2, 0xa4, 0xf4, 0x47, 0xea, 0xad, 0x3d, 0x1a, 0x95, 0xfe, 0x70, 0xa1, + 0xd1, 0x68, 0xb7, 0xc7, 0xe3, 0xd2, 0x8f, 0x55, 0xc1, 0x76, 0x77, 0x38, 0xda, 0xee, 0x96, 0xfe, 0x85, 0xd1, 0xa2, + 0xf4, 0x99, 0x7c, 0xcb, 0xd9, 0xa8, 0x76, 0x7c, 0xf0, 0xb8, 0x0d, 0x95, 0x82, 0xd1, 0x16, 0xe8, 0x5d, 0x8a, 0xc7, + 0x20, 0x9a, 0xf3, 0x0c, 0x0c, 0xbb, 0xb2, 0x57, 0x80, 0x7c, 0x1e, 0x4b, 0x09, 0x2f, 0xbe, 0xf7, 0x8b, 0x52, 0xfd, + 0x95, 0x29, 0xd5, 0x91, 0x99, 0x49, 0x9a, 0x17, 0xa4, 0x0d, 0x9a, 0xd5, 0xc8, 0x59, 0x54, 0xfd, 0x2a, 0x2c, 0x2a, + 0x61, 0x8f, 0xd2, 0x06, 0x5b, 0x0a, 0x19, 0xff, 0xc3, 0x3a, 0x19, 0xff, 0xfd, 0xed, 0x32, 0xfe, 0xf4, 0x6e, 0x22, + 0xfe, 0xfb, 0xdf, 0x59, 0xc4, 0xff, 0x60, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0xc0, 0x74, 0x26, 0x9b, 0xf9, 0x34, 0xbb, + 0x6c, 0xe1, 0x96, 0xc8, 0x6d, 0x92, 0x9e, 0xd3, 0x3b, 0x09, 0xff, 0x15, 0xf9, 0x60, 0x6a, 0x30, 0xe3, 0xe3, 0xc1, + 0x3c, 0x3b, 0x3b, 0x4b, 0x98, 0x92, 0xf1, 0x46, 0x05, 0x99, 0xe3, 0xef, 0xd2, 0xd0, 0x7e, 0x07, 0x9e, 0xb1, 0x51, + 0x32, 0x1e, 0x43, 0xd1, 0x78, 0x6c, 0xab, 0x7c, 0x69, 0x90, 0x67, 0xd4, 0xea, 0x6d, 0xad, 0x84, 0x5a, 0x7d, 0xf1, + 0x85, 0x59, 0x66, 0x16, 0xc8, 0x90, 0x9e, 0x69, 0x8c, 0xc8, 0x9a, 0x51, 0x5c, 0xe0, 0x1e, 0xac, 0x3e, 0x76, 0x8c, + 0xf6, 0xce, 0x14, 0x94, 0x4a, 0x3c, 0xc4, 0x73, 0x91, 0xe6, 0x87, 0x65, 0x44, 0x6e, 0xfb, 0x32, 0x72, 0xd5, 0xf9, + 0xb7, 0xf1, 0x0d, 0xc3, 0xea, 0xcc, 0x1b, 0x16, 0x5f, 0xe6, 0xb7, 0x3c, 0xbd, 0x7a, 0x35, 0x72, 0xf6, 0xc0, 0x1a, + 0x8e, 0x8b, 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, + 0xec, 0x19, 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, + 0x92, 0x6e, 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xe2, 0x79, 0x88, + 0x98, 0x61, 0x54, 0xaa, 0x33, 0x10, 0x20, 0xdc, 0x0c, 0x3f, 0xd1, 0x24, 0x86, 0x50, 0x07, 0x05, 0x15, 0xf5, 0xae, + 0xaf, 0xcd, 0x2f, 0x85, 0xd6, 0xbe, 0x2a, 0xd9, 0xe0, 0x01, 0x86, 0x9f, 0xf8, 0x45, 0x6d, 0x90, 0xcd, 0xb9, 0xe3, + 0x50, 0x2b, 0xc7, 0x2d, 0xbd, 0x9d, 0x76, 0x1b, 0x54, 0x8c, 0x2f, 0xbe, 0x03, 0xe5, 0xe8, 0xce, 0x12, 0xdf, 0x75, + 0xe7, 0x12, 0x4b, 0xdf, 0x65, 0xd3, 0x24, 0xc6, 0x0f, 0xc7, 0x08, 0x44, 0x8d, 0xbb, 0x43, 0x6a, 0x11, 0x9b, 0xef, + 0xbe, 0xf2, 0x1d, 0x0d, 0xc2, 0xba, 0xab, 0x38, 0x58, 0xe6, 0xd6, 0xd6, 0x0b, 0xb1, 0xad, 0xb0, 0x6a, 0x96, 0xc1, + 0xb9, 0x45, 0x67, 0x16, 0x17, 0x46, 0x00, 0xbf, 0xb6, 0x0d, 0x4a, 0x15, 0xc1, 0x17, 0x61, 0xf8, 0x3d, 0x0c, 0x36, + 0x0b, 0xc7, 0x5b, 0x01, 0x5d, 0x77, 0x79, 0x0d, 0xc8, 0xd1, 0x19, 0xd6, 0x8c, 0xae, 0xaa, 0x54, 0x41, 0x69, 0x1e, + 0xc1, 0x18, 0xc8, 0x50, 0x24, 0x1d, 0xd6, 0x38, 0x15, 0x7a, 0x0b, 0xa6, 0x21, 0x01, 0xac, 0xfd, 0x3a, 0x74, 0x6b, + 0x6c, 0x05, 0xb6, 0x90, 0x16, 0xa0, 0xf4, 0xb0, 0x43, 0xdf, 0xaa, 0x81, 0x9e, 0x2e, 0x07, 0xe0, 0x6f, 0x74, 0xf2, + 0x4e, 0xfc, 0xe2, 0xc2, 0x83, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, + 0x86, 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, + 0x41, 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, + 0xdf, 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, + 0xd5, 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0xff, 0x8c, 0xcc, 0x85, 0x66, 0x31, 0x1d, 0xc0, 0xdf, + 0x05, 0xb2, 0x20, 0x1a, 0xe3, 0x17, 0x16, 0xef, 0xd2, 0xf2, 0x94, 0xb2, 0x5f, 0x17, 0xa8, 0xd6, 0x83, 0xce, 0x13, + 0xf0, 0xf6, 0xee, 0x3c, 0xfc, 0xcd, 0xe8, 0x97, 0x92, 0x46, 0xea, 0x12, 0xb3, 0x6d, 0xf7, 0x50, 0x5e, 0x24, 0xd1, + 0x15, 0x38, 0x9d, 0x64, 0x63, 0x9c, 0x62, 0xf4, 0xb8, 0x37, 0xcb, 0x64, 0x26, 0x49, 0xce, 0x12, 0xfa, 0x19, 0x13, + 0xb9, 0x14, 0xdb, 0x8f, 0x66, 0x97, 0x6a, 0x35, 0x3a, 0x8d, 0x0c, 0x91, 0xdf, 0x35, 0x11, 0x64, 0x7d, 0xe6, 0x49, + 0x3d, 0x99, 0x61, 0x07, 0x60, 0x10, 0x86, 0x4d, 0x2b, 0x17, 0x50, 0xb5, 0xa1, 0xc4, 0x48, 0x85, 0xa9, 0x06, 0xb2, + 0xfc, 0x6d, 0x50, 0x95, 0x51, 0xc1, 0x7a, 0xf8, 0xa9, 0xcb, 0x18, 0x5c, 0x5b, 0x69, 0x3c, 0x4d, 0xe3, 0xd1, 0x28, + 0x61, 0x3d, 0x65, 0x1f, 0x59, 0x9d, 0x47, 0x98, 0x49, 0x62, 0x2e, 0x59, 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, + 0xa7, 0x60, 0xaf, 0xe1, 0xf7, 0x2a, 0x57, 0x92, 0x53, 0xa6, 0x58, 0xb4, 0x2b, 0xe2, 0xd1, 0x73, 0x1d, 0x97, 0x1d, + 0x30, 0x16, 0x69, 0xc1, 0xdb, 0x3d, 0x9e, 0xcd, 0x82, 0xd6, 0x76, 0x1d, 0x11, 0xac, 0xd2, 0x28, 0x78, 0x2b, 0xd0, + 0xf2, 0xd0, 0x3a, 0x10, 0x5a, 0xce, 0xf2, 0x3b, 0xb2, 0x8c, 0x06, 0xc0, 0x6f, 0x22, 0xea, 0xa2, 0xb2, 0x8e, 0xcc, + 0x5f, 0x67, 0xb7, 0x7c, 0xbe, 0x7a, 0xb7, 0x7c, 0xae, 0x76, 0xcb, 0xcd, 0x1c, 0xfb, 0xd9, 0xb8, 0x83, 0xff, 0xf4, + 0x2a, 0x84, 0x60, 0x55, 0x80, 0x1c, 0x16, 0xda, 0xc5, 0xad, 0x2e, 0xfc, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x8f, 0x0f, + 0x16, 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xaf, 0x5d, 0xab, 0xea, 0x3c, 0xc4, 0x3a, 0xec, 0xb5, 0xb3, 0x5c, 0xd7, 0xbd, + 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0xb8, 0x6a, 0xd1, 0xe9, 0x29, 0x94, 0x8e, 0xb3, 0xe1, 0xbc, + 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0xba, 0x31, 0x8e, 0xea, 0x2a, 0xd2, 0x92, 0xd4, 0x08, 0x0b, 0xbd, + 0x4e, 0x41, 0x01, 0x8c, 0xc9, 0x9c, 0xae, 0xff, 0x70, 0xc5, 0x26, 0xf8, 0xff, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0x8f, + 0x12, 0xe3, 0x46, 0x22, 0xfc, 0x2a, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb2, 0x1a, 0xdc, 0x43, 0x35, 0xd3, 0x91, 0x52, + 0x0a, 0x52, 0xef, 0x80, 0x17, 0x10, 0xcd, 0x13, 0x7e, 0xf3, 0xa8, 0xeb, 0x38, 0x63, 0x69, 0xd4, 0x1b, 0x04, 0x7a, + 0xd5, 0xf6, 0x8e, 0x52, 0xfa, 0xb3, 0xcf, 0x1f, 0xe2, 0x3f, 0x22, 0x70, 0x76, 0x5a, 0xf9, 0x46, 0x22, 0x36, 0x80, + 0xbe, 0xd1, 0xb4, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x5d, 0x5b, 0xa3, 0xb1, 0x7e, 0xa7, 0xe6, 0xd2, 0x2a, + 0xfd, 0x55, 0xad, 0x7f, 0xdd, 0xe0, 0x77, 0x6c, 0x3b, 0x14, 0x0e, 0x41, 0xbd, 0xad, 0x8c, 0x07, 0x2e, 0x35, 0x56, + 0x14, 0xbf, 0x6b, 0xfb, 0xca, 0x24, 0xa6, 0x1e, 0xd3, 0xf0, 0x54, 0x3b, 0x91, 0xf2, 0xf0, 0x1e, 0x7b, 0x08, 0x3f, + 0xf2, 0x4b, 0x16, 0x3e, 0xc0, 0xaf, 0xb1, 0x59, 0x97, 0xd3, 0x24, 0x05, 0xb3, 0x6a, 0xc2, 0xf9, 0x2c, 0xd8, 0xda, + 0xba, 0xb8, 0xb8, 0xf0, 0x2f, 0xb6, 0xfd, 0x2c, 0x3f, 0xdb, 0xea, 0xb6, 0xdb, 0x6d, 0xfc, 0x88, 0x96, 0x6d, 0x9d, + 0xc7, 0xec, 0xe2, 0x29, 0xb8, 0x1f, 0xf6, 0x63, 0xeb, 0x89, 0xf5, 0x78, 0xdb, 0xda, 0x79, 0x64, 0x5b, 0xa4, 0x00, + 0xa0, 0x64, 0xdb, 0xb6, 0x84, 0x02, 0x08, 0x6d, 0x28, 0xee, 0xef, 0x9e, 0x29, 0x1b, 0x0e, 0x2f, 0x29, 0x08, 0x0b, + 0x09, 0xfc, 0xb7, 0xec, 0x13, 0xab, 0x6f, 0x75, 0x51, 0xd6, 0x92, 0x6a, 0x44, 0xbd, 0xe2, 0x7e, 0x1f, 0x46, 0xb3, + 0x80, 0xd8, 0xc8, 0x2c, 0xc4, 0x30, 0x99, 0x28, 0xa5, 0x29, 0xd0, 0x2e, 0x3d, 0x85, 0x27, 0xcc, 0x6a, 0xb3, 0xe0, + 0xf9, 0x4d, 0xf7, 0x31, 0xe8, 0xb8, 0xf3, 0xd6, 0xc3, 0x61, 0xbb, 0xd5, 0xb1, 0x3a, 0xad, 0xae, 0xff, 0xd8, 0xea, + 0x8a, 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, + 0xfd, 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, + 0xb8, 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, + 0xd0, 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, + 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0xef, 0x7c, 0xfb, + 0xc9, 0x10, 0x34, 0x82, 0x85, 0xff, 0xc1, 0x3f, 0x93, 0x9d, 0xee, 0x50, 0xbc, 0xb4, 0xb1, 0xfe, 0xdb, 0xce, 0xe3, + 0x02, 0x9a, 0xe2, 0x3f, 0xbf, 0x68, 0x13, 0x1a, 0x0d, 0x78, 0x73, 0xdc, 0x87, 0x40, 0xa3, 0x27, 0x93, 0xae, 0xff, + 0xf9, 0xf9, 0x63, 0xff, 0xc9, 0xa4, 0xf3, 0xf8, 0x5b, 0xf1, 0x96, 0x00, 0x05, 0x3f, 0xc7, 0xff, 0xbe, 0xdd, 0x6e, + 0x4f, 0x5a, 0x1d, 0xff, 0xc9, 0xf9, 0xb6, 0xbf, 0x9d, 0xb4, 0x1e, 0xf9, 0x4f, 0xf0, 0xbf, 0x6a, 0xb8, 0x49, 0x36, + 0x65, 0xb6, 0x85, 0xeb, 0xdd, 0xf0, 0x7b, 0xcd, 0x39, 0xba, 0x0f, 0xad, 0x9d, 0x87, 0x2f, 0x9f, 0xc0, 0x1a, 0x4d, + 0x3a, 0x5d, 0xf8, 0xff, 0xba, 0xc7, 0x6f, 0x91, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x7a, 0xb1, 0x22, 0x1c, 0x7d, 0xd0, + 0xed, 0x81, 0xf7, 0xa7, 0x75, 0x01, 0x10, 0xc6, 0x6f, 0x0d, 0x80, 0x70, 0x7e, 0xb7, 0x08, 0x08, 0xfd, 0xda, 0xc0, + 0xef, 0x18, 0x01, 0xf9, 0x53, 0x33, 0xc8, 0x7d, 0xc9, 0x96, 0x02, 0x1d, 0x4d, 0x67, 0xed, 0x2d, 0x73, 0x0e, 0xbf, + 0x64, 0x47, 0x98, 0x4a, 0x0f, 0xad, 0x39, 0x37, 0xe3, 0x41, 0x19, 0x6e, 0xe4, 0x4b, 0x26, 0x76, 0x72, 0xc1, 0xd7, + 0x10, 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, + 0x29, 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, + 0xd3, 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, + 0x34, 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, + 0xa6, 0xdf, 0xcf, 0x8a, 0x79, 0x82, 0x97, 0xa6, 0xbd, 0xa1, 0xf8, 0x80, 0x2c, 0x3c, 0xca, 0xbb, 0x86, 0x98, 0xc2, + 0xfe, 0x0d, 0xa6, 0xdf, 0xab, 0xb3, 0x83, 0x29, 0xc6, 0x11, 0xde, 0xb0, 0x51, 0x1c, 0x39, 0xb6, 0x33, 0x83, 0x8d, + 0x0c, 0xb3, 0xb4, 0x6a, 0xb9, 0xef, 0x94, 0xf6, 0xee, 0xda, 0xea, 0xa7, 0x99, 0x72, 0xfc, 0xd4, 0x5d, 0x78, 0x28, + 0xe3, 0x8e, 0xb6, 0x74, 0x0c, 0x60, 0x7c, 0x55, 0x92, 0xa3, 0x0e, 0xa8, 0x8c, 0x09, 0x5b, 0x58, 0x13, 0x1d, 0xbf, + 0x0b, 0xde, 0x05, 0x15, 0xe3, 0xa7, 0xc3, 0xbe, 0x77, 0x5a, 0xdb, 0x60, 0xed, 0x18, 0xdd, 0xf4, 0x40, 0x47, 0xfa, + 0x97, 0x7e, 0xf4, 0xaf, 0xd1, 0xd5, 0x2f, 0x0c, 0xd8, 0x82, 0x23, 0x3e, 0x13, 0xb8, 0xdb, 0xf4, 0x89, 0x06, 0x99, + 0x50, 0x82, 0x17, 0xe6, 0xa0, 0xcc, 0x31, 0x7f, 0x95, 0x4c, 0x7c, 0x9a, 0x4c, 0xfc, 0x00, 0x61, 0x59, 0x35, 0x61, + 0xd5, 0xcf, 0x7f, 0x20, 0x05, 0x99, 0xa7, 0x67, 0x23, 0xea, 0x61, 0x86, 0x07, 0xfe, 0xad, 0x8a, 0xd5, 0x83, 0x8c, + 0x58, 0x81, 0x17, 0x8f, 0xbf, 0xe9, 0x42, 0x7f, 0x96, 0xe2, 0x61, 0x22, 0xca, 0xd1, 0x28, 0xad, 0x86, 0xaa, 0xe2, + 0x5e, 0xc5, 0xd3, 0xab, 0x03, 0xf9, 0x41, 0x03, 0x1b, 0x43, 0xd0, 0x74, 0xf4, 0x50, 0x7d, 0x4c, 0x6d, 0x13, 0xf4, + 0x1e, 0xfd, 0xc4, 0x29, 0x65, 0x0f, 0xa0, 0x6a, 0xc3, 0xfb, 0x04, 0x96, 0x74, 0x81, 0x42, 0x5b, 0x28, 0xb6, 0x11, + 0x3b, 0x8f, 0x87, 0x52, 0x3f, 0x79, 0x96, 0xbc, 0x07, 0xd5, 0x22, 0xba, 0x87, 0x1d, 0x4f, 0x04, 0x01, 0xe0, 0x05, + 0xd5, 0x73, 0x98, 0x66, 0x76, 0xff, 0x41, 0x6f, 0x1d, 0x65, 0xf1, 0xf7, 0x56, 0x0f, 0xc1, 0xe9, 0xfc, 0xdb, 0xf0, + 0x01, 0xfe, 0xe2, 0xea, 0x83, 0x23, 0xdb, 0xf5, 0x49, 0xba, 0x3f, 0xa8, 0x7e, 0x76, 0x15, 0x45, 0xdb, 0x26, 0x28, + 0x62, 0xef, 0xae, 0x1a, 0x59, 0x6a, 0xdf, 0xee, 0x4e, 0xa5, 0x7d, 0xe1, 0xd9, 0x10, 0xb7, 0xa0, 0x09, 0xba, 0xfe, + 0x8e, 0x21, 0xd3, 0xcf, 0x5b, 0xf8, 0xb7, 0x26, 0xd5, 0x1f, 0x42, 0x03, 0x25, 0xd6, 0x5f, 0x43, 0xf3, 0x6d, 0xa1, + 0x41, 0xa0, 0xdf, 0x0f, 0x24, 0x73, 0x85, 0xbc, 0xad, 0xf3, 0xf8, 0x8a, 0xd3, 0x30, 0x91, 0x69, 0x61, 0x7b, 0x46, + 0xe0, 0x4c, 0x6c, 0x39, 0x19, 0x16, 0x7a, 0x0e, 0x7d, 0x1d, 0xfd, 0x8d, 0xf2, 0x55, 0x75, 0x5e, 0x4d, 0x04, 0xac, + 0x98, 0x02, 0x37, 0x6d, 0xe3, 0xc4, 0xad, 0x27, 0x92, 0xb8, 0xf5, 0x47, 0x4e, 0xd6, 0x73, 0xab, 0xcc, 0xf6, 0x76, + 0x8d, 0xfd, 0xcf, 0xe9, 0x3b, 0xaa, 0x34, 0xc9, 0xab, 0x51, 0xd9, 0x9c, 0x1f, 0x6c, 0x16, 0xfc, 0xd1, 0xc9, 0xea, + 0x0a, 0x8f, 0xbc, 0x9b, 0x8b, 0xf9, 0x14, 0xa3, 0x38, 0xa7, 0x2b, 0xdf, 0x0a, 0xf4, 0x5a, 0x54, 0xb5, 0xa2, 0x12, + 0x89, 0x00, 0x56, 0x0c, 0x6c, 0x2c, 0xb2, 0x03, 0x99, 0xf5, 0x67, 0x7e, 0x48, 0xdc, 0xbc, 0x93, 0x3b, 0x12, 0x09, + 0x7f, 0xf8, 0x43, 0x0b, 0xb6, 0xa0, 0x8f, 0x0d, 0xa2, 0x74, 0xed, 0x2e, 0x21, 0x03, 0x0b, 0x71, 0xad, 0x7e, 0x39, + 0xcb, 0x94, 0x2e, 0xb6, 0x49, 0x68, 0x3d, 0x2e, 0x91, 0xd0, 0x95, 0x74, 0x3a, 0x65, 0x11, 0xf7, 0xa3, 0x94, 0x92, + 0xb3, 0x1c, 0x43, 0x06, 0x79, 0x1d, 0xb6, 0xed, 0x96, 0x20, 0xf8, 0x8c, 0x9f, 0x16, 0x13, 0x9b, 0xd9, 0x87, 0x42, + 0xfd, 0x59, 0xab, 0x7a, 0xa2, 0xf5, 0xa4, 0xdb, 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, + 0xe4, 0x9e, 0x8b, 0x3c, 0x95, 0x50, 0xe4, 0xa9, 0x58, 0x22, 0xbb, 0x4d, 0x24, 0x26, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, + 0xa5, 0x43, 0x11, 0x57, 0x9c, 0x82, 0x0b, 0x13, 0xe3, 0xc7, 0xe7, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x29, + 0x3f, 0xca, 0x68, 0xe1, 0xa9, 0x8a, 0x42, 0x82, 0xa9, 0xc1, 0x54, 0xf6, 0x8f, 0x1c, 0x4a, 0x27, 0x1d, 0x2f, 0xb7, + 0x2e, 0xe6, 0xa7, 0x53, 0x10, 0x82, 0x2a, 0x63, 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x26, + 0x55, 0x1f, 0x06, 0x6f, 0xfc, 0x88, 0xaa, 0xc0, 0x5e, 0x0a, 0x7d, 0x4c, 0x38, 0x99, 0x6c, 0x1b, 0x09, 0x27, 0x46, + 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x83, 0xac, 0xa2, 0x3d, 0x28, 0x94, + 0x01, 0x25, 0x8f, 0x8b, 0x4b, 0x1b, 0x12, 0x60, 0x58, 0x41, 0x80, 0x49, 0xea, 0x77, 0x8b, 0xce, 0xb5, 0xed, 0x9d, + 0xb6, 0xca, 0xc9, 0x85, 0x32, 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0xb6, 0x3b, 0xe9, 0xf4, 0x77, 0x23, 0x69, + 0x39, 0xa2, 0xf0, 0x28, 0x40, 0x7a, 0x40, 0x67, 0x34, 0xcf, 0xfc, 0x38, 0xdb, 0xba, 0x60, 0xa7, 0xad, 0x68, 0x16, + 0x57, 0x81, 0x54, 0xb4, 0x23, 0xf4, 0x94, 0x59, 0x35, 0x13, 0x3e, 0x46, 0x0d, 0x24, 0x49, 0x70, 0x97, 0x32, 0x4a, + 0x4b, 0xe6, 0x37, 0xb0, 0x10, 0x50, 0x98, 0xe4, 0xba, 0x8a, 0xe6, 0x4a, 0x75, 0x5a, 0xda, 0xfd, 0xbf, 0xfc, 0xf3, + 0xff, 0x96, 0x01, 0x5a, 0xa0, 0x4a, 0x47, 0x8d, 0xd5, 0x20, 0x74, 0xb9, 0x8b, 0xf9, 0x4d, 0xd5, 0x11, 0x2e, 0xbb, + 0x04, 0x4f, 0x3f, 0x1e, 0xb5, 0x26, 0x51, 0x32, 0x06, 0xc0, 0xd6, 0x12, 0xc8, 0xcc, 0x7e, 0x90, 0x50, 0xd7, 0x8b, + 0x90, 0x05, 0x7f, 0x53, 0x96, 0xb5, 0xca, 0x6e, 0xa7, 0xdd, 0x6a, 0xe4, 0x5c, 0x1b, 0x1b, 0xaa, 0x96, 0x77, 0xad, + 0x7e, 0x95, 0x4c, 0x0a, 0x35, 0x56, 0x4b, 0xba, 0x86, 0x96, 0xfa, 0xa4, 0xe9, 0xdf, 0xff, 0xe5, 0x1f, 0xfe, 0x87, + 0x7a, 0xc5, 0x03, 0xa4, 0xbf, 0xfc, 0xd3, 0xdf, 0x61, 0x7e, 0xb3, 0xa5, 0x0f, 0x99, 0x48, 0x4e, 0x58, 0xd5, 0x09, + 0x93, 0x10, 0x18, 0x56, 0xe5, 0xd1, 0xd5, 0x93, 0xb3, 0xf7, 0x69, 0x42, 0xda, 0x6c, 0x12, 0x3a, 0xda, 0xb4, 0x65, + 0xc5, 0x23, 0x35, 0x92, 0x13, 0x2f, 0x42, 0x25, 0xd2, 0xfb, 0x4e, 0x99, 0x4f, 0xbe, 0x5e, 0x8d, 0x85, 0x0a, 0xff, + 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x97, 0x5f, 0xe0, 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0xf1, 0x6a, 0x7d, 0x7a, 0x3f, + 0xcd, 0x01, 0xfe, 0x31, 0x52, 0x5c, 0x04, 0x19, 0xe9, 0xcc, 0xb9, 0x85, 0x06, 0x5d, 0x72, 0x55, 0xd2, 0x28, 0xc2, + 0x0b, 0x7c, 0xf8, 0xe4, 0x6f, 0xca, 0x3f, 0x4e, 0xd1, 0x6c, 0xb2, 0x9c, 0x69, 0x74, 0x29, 0x7d, 0xc3, 0x47, 0xed, + 0xf6, 0xec, 0xd2, 0x5d, 0x54, 0x33, 0x78, 0xeb, 0x26, 0xa3, 0xc0, 0xa4, 0x39, 0x20, 0x1d, 0x56, 0xeb, 0x18, 0x28, + 0xb8, 0x43, 0x6d, 0x0c, 0x99, 0x95, 0xe5, 0x1f, 0x16, 0x14, 0x86, 0x8b, 0x7f, 0xc1, 0x43, 0x65, 0x19, 0xb1, 0x84, + 0x12, 0x03, 0x8b, 0x85, 0xd1, 0xab, 0x2b, 0x7a, 0x4d, 0x3a, 0xcb, 0x39, 0x41, 0xe6, 0xa1, 0xb8, 0x79, 0x9c, 0xfd, + 0x10, 0x0f, 0xa8, 0x27, 0x1d, 0x6f, 0xd2, 0x5d, 0xe8, 0xe1, 0x39, 0xcf, 0xa6, 0xe6, 0x29, 0x38, 0x8b, 0xd8, 0x90, + 0x8d, 0x55, 0xa4, 0x57, 0xd6, 0x8b, 0x13, 0xee, 0x72, 0xb2, 0xbd, 0x62, 0x2e, 0x09, 0x12, 0x9d, 0x7e, 0x03, 0x3c, + 0x9f, 0xe1, 0x06, 0x04, 0xfa, 0x67, 0x11, 0x0f, 0x88, 0x5f, 0x7b, 0xe6, 0x59, 0x7a, 0x84, 0x52, 0x26, 0x5b, 0x18, + 0xf0, 0xf4, 0x44, 0x53, 0x8c, 0xb9, 0xd6, 0x73, 0xb2, 0x4a, 0x9f, 0xba, 0x9b, 0x43, 0x89, 0x90, 0xcd, 0xb7, 0xf2, + 0x88, 0xfa, 0x69, 0x2d, 0xd6, 0x21, 0x55, 0x4c, 0xd7, 0xf5, 0x56, 0xd6, 0x0b, 0x4d, 0x2d, 0x6a, 0xbf, 0x05, 0x03, + 0x8c, 0xc0, 0xb4, 0x9b, 0xad, 0xa8, 0x10, 0x5b, 0x3d, 0x0d, 0xbf, 0xd5, 0x7e, 0x4d, 0x34, 0x9b, 0x51, 0x43, 0x17, + 0x98, 0x98, 0xac, 0x51, 0x94, 0x1d, 0x94, 0x7e, 0x21, 0xb2, 0x1d, 0x64, 0x1b, 0xb9, 0x11, 0xc4, 0x93, 0xcc, 0x83, + 0xa0, 0xdf, 0xb7, 0xff, 0x7f, 0x47, 0x48, 0x09, 0x5d, 0xf5, 0x7e, 0x00, 0x00}; } // namespace web_server } // namespace esphome From 74daca668ec141069914ee526060966ebd3646c6 Mon Sep 17 00:00:00 2001 From: Dion Hulse Date: Thu, 22 Jun 2023 07:58:49 +1000 Subject: [PATCH 0124/2607] Add configuration option to disable the log UI. (#4419) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/web_server/__init__.py | 3 +++ esphome/components/web_server/web_server.cpp | 21 +++++++++++--------- esphome/components/web_server/web_server.h | 9 +++++++++ esphome/const.py | 1 + 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 130c082277..25c0254f90 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_PASSWORD, CONF_INCLUDE_INTERNAL, CONF_OTA, + CONF_LOG, CONF_VERSION, CONF_LOCAL, ) @@ -71,6 +72,7 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean, cv.Optional(CONF_OTA, default=True): cv.boolean, + cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), @@ -132,6 +134,7 @@ async def to_code(config): cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL])) cg.add(var.set_allow_ota(config[CONF_OTA])) + cg.add(var.set_expose_log(config[CONF_LOG])) if CONF_AUTH in config: cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME])) cg.add(paren.set_auth_password(config[CONF_AUTH][CONF_PASSWORD])) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index b3a2dfdb66..eb1858a09c 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -102,6 +102,16 @@ void WebServer::set_css_include(const char *css_include) { this->css_include_ = void WebServer::set_js_include(const char *js_include) { this->js_include_ = js_include; } #endif +std::string WebServer::get_config_json() { + return json::build_json([this](JsonObject root) { + root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name(); + root["comment"] = App.get_comment(); + root["ota"] = this->allow_ota_; + root["log"] = this->expose_log_; + root["lang"] = "en"; + }); +} + void WebServer::setup() { ESP_LOGCONFIG(TAG, "Setting up web server..."); this->setup_controller(this->include_internal_); @@ -109,20 +119,13 @@ void WebServer::setup() { this->events_.onConnect([this](AsyncEventSourceClient *client) { // Configure reconnect timeout and send config - - client->send(json::build_json([this](JsonObject root) { - root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name(); - root["comment"] = App.get_comment(); - root["ota"] = this->allow_ota_; - root["lang"] = "en"; - }).c_str(), - "ping", millis(), 30000); + client->send(this->get_config_json().c_str(), "ping", millis(), 30000); this->entities_iterator_.begin(this->include_internal_); }); #ifdef USE_LOGGER - if (logger::global_logger != nullptr) { + if (logger::global_logger != nullptr && this->expose_log_) { logger::global_logger->add_on_log_callback( [this](int level, const char *tag, const char *message) { this->events_.send(message, "log", millis()); }); } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index a664bb5a12..83ebba205f 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -99,6 +99,11 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { * @param allow_ota. */ void set_allow_ota(bool allow_ota) { this->allow_ota_ = allow_ota; } + /** Set whether or not the webserver should expose the Log. + * + * @param expose_log. + */ + void set_expose_log(bool expose_log) { this->expose_log_ = expose_log; } // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -114,6 +119,9 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { /// Handle an index request under '/'. void handle_index_request(AsyncWebServerRequest *request); + /// Return the webserver configuration as JSON. + std::string get_config_json(); + #ifdef USE_WEBSERVER_CSS_INCLUDE /// Handle included css request under '/0.css'. void handle_css_request(AsyncWebServerRequest *request); @@ -274,6 +282,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { #endif bool include_internal_{false}; bool allow_ota_{true}; + bool expose_log_{true}; #ifdef USE_ESP32 std::deque> to_schedule_; SemaphoreHandle_t to_schedule_lock_; diff --git a/esphome/const.py b/esphome/const.py index 32231d5c83..e698ffcc64 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -368,6 +368,7 @@ CONF_LINE_TYPE = "line_type" CONF_LOADED_INTEGRATIONS = "loaded_integrations" CONF_LOCAL = "local" CONF_LOCK_ACTION = "lock_action" +CONF_LOG = "log" CONF_LOG_TOPIC = "log_topic" CONF_LOGGER = "logger" CONF_LOGS = "logs" From c455a5dd6a7e87503ffb5a65a762ac912278a3ff Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:12:25 +1200 Subject: [PATCH 0125/2607] Update webserver and captive portal pages to 67c48ee9 (#4986) --- .../components/captive_portal/captive_index.h | 190 ++- esphome/components/web_server/server_index.h | 1169 +++++++++-------- 2 files changed, 684 insertions(+), 675 deletions(-) diff --git a/esphome/components/captive_portal/captive_index.h b/esphome/components/captive_portal/captive_index.h index bf2e6e6e8b..56071f3d2a 100644 --- a/esphome/components/captive_portal/captive_index.h +++ b/esphome/components/captive_portal/captive_index.h @@ -6,102 +6,100 @@ namespace esphome { namespace captive_portal { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xdd, 0x58, 0x09, 0x6f, 0xdc, 0x36, 0x16, 0xfe, 0x2b, - 0xac, 0x92, 0x74, 0x34, 0x8d, 0xc5, 0xd1, 0x31, 0x97, 0x35, 0xd2, 0x14, 0x89, 0x37, 0x45, 0x0b, 0x24, 0x69, 0x00, - 0xbb, 0x5d, 0x14, 0x69, 0x00, 0x73, 0x24, 0x6a, 0xc4, 0x58, 0xa2, 0x54, 0x91, 0x9a, 0x23, 0x83, 0xd9, 0xdf, 0xde, - 0x47, 0x52, 0x73, 0x38, 0x6b, 0x2f, 0x90, 0x62, 0x8b, 0xa2, 0x4d, 0x6c, 0x9a, 0xc7, 0x3b, 0x3f, 0xf2, 0xf1, 0x3d, - 0x2a, 0xfa, 0x2a, 0xad, 0x12, 0xb9, 0xad, 0x29, 0xca, 0x65, 0x59, 0xcc, 0x23, 0xd5, 0xa2, 0x82, 0xf0, 0x65, 0x4c, - 0x39, 0x8c, 0x28, 0x49, 0xe7, 0x51, 0x49, 0x25, 0x41, 0x49, 0x4e, 0x1a, 0x41, 0x65, 0xfc, 0xd3, 0xcd, 0x77, 0xce, - 0x14, 0x0d, 0xe6, 0x51, 0xc1, 0xf8, 0x1d, 0x6a, 0x68, 0x11, 0xb3, 0xa4, 0xe2, 0x28, 0x6f, 0x68, 0x16, 0xa7, 0x44, - 0x92, 0x90, 0x95, 0x64, 0x49, 0x15, 0x81, 0x66, 0xe3, 0xa4, 0xa4, 0xf1, 0x8a, 0xd1, 0x75, 0x5d, 0x35, 0x12, 0x01, - 0xa5, 0xa4, 0x5c, 0xc6, 0xd6, 0x9a, 0xa5, 0x32, 0x8f, 0x53, 0xba, 0x62, 0x09, 0x75, 0xf4, 0xe0, 0x82, 0x71, 0x26, - 0x19, 0x29, 0x1c, 0x91, 0x90, 0x82, 0xc6, 0xde, 0x45, 0x2b, 0x68, 0xa3, 0x07, 0x64, 0x01, 0x63, 0x5e, 0x59, 0x20, - 0x52, 0x24, 0x0d, 0xab, 0x25, 0x52, 0xf6, 0xc6, 0x65, 0x95, 0xb6, 0x05, 0x9d, 0x67, 0x2d, 0x4f, 0x24, 0x03, 0x0b, - 0x84, 0xcd, 0xfb, 0xbb, 0x82, 0x4a, 0x44, 0xe3, 0x37, 0x44, 0xe6, 0xb8, 0x24, 0x1b, 0xdb, 0x74, 0x18, 0xb7, 0xfd, - 0x6f, 0x6c, 0xfe, 0xdc, 0x73, 0xdd, 0xfe, 0x85, 0x6e, 0xdc, 0xfe, 0x00, 0xfe, 0xce, 0x1a, 0x2a, 0xdb, 0x86, 0x23, - 0x62, 0xdf, 0x46, 0x35, 0x50, 0xa2, 0x34, 0xb6, 0x4a, 0xcf, 0xc7, 0xae, 0x3b, 0x45, 0xde, 0x25, 0xf6, 0x47, 0x8e, - 0xe7, 0xe1, 0xc0, 0xf1, 0x46, 0xc9, 0xc4, 0x19, 0x21, 0x6f, 0x08, 0x8d, 0xef, 0xe3, 0x11, 0x72, 0x3f, 0x59, 0x28, - 0x63, 0x45, 0x11, 0x5b, 0xbc, 0xe2, 0xd4, 0x42, 0x42, 0x36, 0xd5, 0x1d, 0x8d, 0xad, 0xa4, 0x6d, 0x1a, 0xf0, 0xee, - 0xaa, 0x2a, 0xaa, 0x06, 0xac, 0xfd, 0x95, 0xa3, 0x7b, 0xff, 0xbe, 0x58, 0x87, 0x6c, 0x08, 0x17, 0x59, 0xd5, 0x94, - 0xb1, 0xa5, 0x41, 0xb1, 0x9f, 0xee, 0xe8, 0x1e, 0xa9, 0xa6, 0x7f, 0xb6, 0xe8, 0x54, 0x0d, 0x5b, 0x32, 0x1e, 0x5b, - 0x9e, 0x8f, 0xbc, 0x29, 0xe8, 0xbd, 0xed, 0xef, 0x8f, 0xa0, 0x10, 0x05, 0x4a, 0xe7, 0x66, 0x65, 0xbf, 0xbf, 0x8d, - 0xc4, 0x6a, 0x89, 0x36, 0x65, 0xc1, 0x45, 0x6c, 0xe5, 0x52, 0xd6, 0xe1, 0x60, 0xb0, 0x5e, 0xaf, 0xf1, 0x3a, 0xc0, - 0x55, 0xb3, 0x1c, 0xf8, 0xae, 0xeb, 0x0e, 0x80, 0xc2, 0x42, 0x66, 0x7f, 0x2c, 0x7f, 0x68, 0xa1, 0x9c, 0xb2, 0x65, - 0x2e, 0x75, 0x7f, 0xfe, 0x74, 0xc7, 0xf7, 0x91, 0xa2, 0x98, 0xdf, 0x7e, 0x38, 0xd3, 0xd2, 0x9c, 0x69, 0xe1, 0xdf, - 0x12, 0xdb, 0x3a, 0xb8, 0xda, 0x7b, 0xa3, 0x8c, 0x9a, 0x10, 0x1f, 0xf9, 0xc8, 0xd5, 0xff, 0x7d, 0x47, 0xf5, 0xbb, - 0x91, 0xf3, 0xd9, 0x08, 0x9d, 0x8d, 0xe0, 0xaf, 0x02, 0xd0, 0x2f, 0xc7, 0xce, 0xe5, 0x91, 0xdf, 0x53, 0xeb, 0x2b, - 0xcf, 0x3d, 0x4d, 0x28, 0xa6, 0xef, 0xc7, 0xe7, 0x63, 0xc7, 0xff, 0x59, 0x11, 0x68, 0xf4, 0x8f, 0x5c, 0x8e, 0x9f, - 0x7b, 0x3f, 0x8f, 0xc9, 0x08, 0x8d, 0xba, 0x99, 0x91, 0xa3, 0xfa, 0xc7, 0x91, 0xd6, 0x85, 0x46, 0x2b, 0x20, 0x2b, - 0x9d, 0xb1, 0x33, 0x22, 0x01, 0x0a, 0x3a, 0xab, 0xa0, 0x07, 0xd3, 0x63, 0xe0, 0x3e, 0x9b, 0x73, 0x82, 0x4f, 0xbd, - 0xc1, 0xdc, 0xea, 0x87, 0x96, 0x75, 0x82, 0xa1, 0x3a, 0x87, 0x01, 0x7f, 0xac, 0xe0, 0xdc, 0x59, 0x56, 0x7f, 0x6f, - 0x7d, 0x2b, 0xc8, 0x8a, 0x5a, 0x71, 0x1c, 0x43, 0xa8, 0xb5, 0x25, 0x9c, 0x10, 0x5c, 0x54, 0x09, 0x51, 0x2c, 0x58, - 0x50, 0xd2, 0x24, 0xf9, 0xd7, 0x5f, 0xdb, 0xc7, 0xa5, 0x25, 0x95, 0xaf, 0x0a, 0xaa, 0xba, 0xe2, 0xe5, 0xf6, 0x86, - 0x2c, 0xdf, 0x42, 0x00, 0xd9, 0x16, 0x11, 0x2c, 0xa5, 0x56, 0xff, 0xbd, 0xfb, 0x01, 0x0b, 0xb9, 0x2d, 0x28, 0x4e, - 0x99, 0xa8, 0x0b, 0xb2, 0x8d, 0xad, 0x05, 0xc8, 0xba, 0xb3, 0xfa, 0x17, 0x19, 0x95, 0x49, 0x6e, 0x5b, 0x03, 0x08, - 0xb1, 0x8c, 0x2d, 0xf1, 0x47, 0x51, 0x71, 0xab, 0x8f, 0x65, 0x4e, 0xb9, 0x6d, 0x1f, 0x2c, 0x54, 0xf6, 0x71, 0xbd, - 0x64, 0x3f, 0xb4, 0x74, 0xb4, 0x41, 0x32, 0xa9, 0x42, 0x0e, 0xab, 0xe0, 0xbd, 0x38, 0xce, 0x2e, 0xaa, 0x74, 0xfb, - 0x88, 0x79, 0xb9, 0x67, 0x6c, 0x63, 0x9c, 0xd3, 0xe6, 0x86, 0x6e, 0xe0, 0xb8, 0xfc, 0x9b, 0x7d, 0xc7, 0xd0, 0x5b, - 0x2a, 0xd7, 0x55, 0x73, 0x27, 0x42, 0x64, 0x3d, 0x37, 0xe2, 0x66, 0x26, 0x42, 0x39, 0x26, 0xb5, 0xc0, 0xa2, 0x80, - 0xf0, 0xb7, 0xbd, 0x3e, 0xc4, 0x6a, 0x7d, 0xdf, 0x14, 0x83, 0xe2, 0x6d, 0x94, 0xb2, 0x15, 0x4a, 0x0a, 0x22, 0xe0, - 0xb8, 0x72, 0x23, 0xcb, 0x42, 0x87, 0xb8, 0xaa, 0x78, 0x02, 0xfc, 0x77, 0xb1, 0xf5, 0x00, 0x76, 0x2f, 0xb7, 0x3f, - 0xa4, 0x76, 0x4f, 0x00, 0x6a, 0xbd, 0x3e, 0x5e, 0x91, 0xa2, 0xa5, 0x28, 0x46, 0x32, 0x67, 0xe2, 0x64, 0xe2, 0xec, - 0x51, 0xb6, 0x5a, 0xdc, 0x01, 0x57, 0x06, 0xcb, 0xc2, 0xee, 0x5b, 0xc7, 0x38, 0x8e, 0x88, 0xb9, 0xe5, 0xac, 0x27, - 0xd6, 0x67, 0x36, 0x39, 0x05, 0xcd, 0xa4, 0x75, 0x16, 0xf0, 0x4f, 0x77, 0x70, 0x1b, 0xe1, 0x06, 0xf4, 0xf7, 0xf7, - 0xa7, 0xd9, 0x48, 0xd4, 0x84, 0x7f, 0xce, 0xaa, 0x6c, 0xd4, 0x81, 0x85, 0x55, 0x4f, 0x45, 0x17, 0x10, 0x9d, 0x74, - 0x0e, 0xc8, 0xb1, 0xff, 0x74, 0x07, 0x71, 0xa6, 0x8e, 0xce, 0xdd, 0x49, 0x68, 0x34, 0x00, 0x84, 0xe6, 0xb7, 0xfb, - 0x7e, 0xff, 0xe4, 0xce, 0x6f, 0x2d, 0x6d, 0xb6, 0xd7, 0xb4, 0xa0, 0x89, 0xac, 0x1a, 0xdb, 0x7a, 0x02, 0x9a, 0xe0, - 0x24, 0x68, 0xbf, 0xbf, 0xbf, 0x79, 0xf3, 0x3a, 0xae, 0x6c, 0xda, 0xbf, 0x78, 0x8c, 0x5a, 0xdd, 0xea, 0xef, 0xe1, - 0x56, 0xff, 0x4f, 0xdc, 0x53, 0xf7, 0x7a, 0xef, 0x03, 0xb0, 0x1a, 0xaf, 0x4f, 0x97, 0xbb, 0xba, 0x00, 0x9e, 0xc3, - 0x25, 0x72, 0x61, 0x3d, 0x17, 0xb6, 0x33, 0x1e, 0xf5, 0x41, 0x3d, 0xfc, 0x80, 0xe9, 0xfa, 0x7a, 0x86, 0x6b, 0x5a, - 0x1d, 0xd1, 0xf9, 0x37, 0xbb, 0x45, 0xb5, 0x71, 0x04, 0xfb, 0xc4, 0xf8, 0x32, 0x64, 0x3c, 0xa7, 0x0d, 0x93, 0x7b, - 0x30, 0x17, 0x6e, 0xfa, 0xba, 0x95, 0xbb, 0x9a, 0xa4, 0xa9, 0x5a, 0x19, 0xd5, 0x9b, 0x59, 0x06, 0x79, 0x41, 0x51, - 0xd2, 0xd0, 0xa3, 0xe5, 0xde, 0xac, 0xeb, 0x2b, 0x28, 0xbc, 0x1c, 0x3d, 0xdb, 0xab, 0x83, 0xb7, 0x93, 0xb0, 0x65, - 0x0e, 0x29, 0xd8, 0x92, 0x87, 0x09, 0xd8, 0x4d, 0x1b, 0xc3, 0x94, 0x91, 0x92, 0x15, 0xdb, 0x50, 0xc0, 0x65, 0xe8, - 0x40, 0xc2, 0x60, 0xd9, 0x7e, 0xd1, 0x4a, 0x59, 0x71, 0xd0, 0xdd, 0xa4, 0xb4, 0x09, 0xdd, 0x99, 0xe9, 0x38, 0x0d, - 0x49, 0x59, 0x2b, 0x42, 0x1c, 0x34, 0xb4, 0x9c, 0x2d, 0x48, 0x72, 0xb7, 0x6c, 0xaa, 0x96, 0xa7, 0x4e, 0xa2, 0x6e, - 0xeb, 0xf0, 0x89, 0x97, 0x91, 0x80, 0x26, 0xb3, 0x6e, 0x94, 0x65, 0xd9, 0x0c, 0x90, 0xa0, 0x8e, 0xb9, 0xfc, 0x42, - 0x1f, 0x0f, 0x15, 0xdb, 0x99, 0x99, 0xd8, 0x57, 0x13, 0xc6, 0x46, 0x48, 0x25, 0xcf, 0x66, 0x07, 0x77, 0xdc, 0x19, - 0xa4, 0x01, 0x01, 0x42, 0x6a, 0x88, 0x7f, 0x30, 0x73, 0x5f, 0x12, 0xc6, 0xcf, 0xad, 0x57, 0x67, 0x65, 0xd6, 0x85, - 0x2f, 0xc0, 0xa2, 0xd5, 0xe8, 0x20, 0x9e, 0x41, 0xa2, 0x32, 0xb9, 0x30, 0xf4, 0xc7, 0x6e, 0xbd, 0xd9, 0xe3, 0xee, - 0x8c, 0xec, 0x0e, 0xd4, 0x59, 0x41, 0x37, 0xb3, 0x8f, 0xad, 0x90, 0x2c, 0xdb, 0x3a, 0x5d, 0x2e, 0x0d, 0xe1, 0xbc, - 0x40, 0x0e, 0x5d, 0x00, 0x29, 0xa5, 0x7c, 0xa6, 0x75, 0x38, 0x4c, 0xd2, 0x52, 0x74, 0x38, 0x1d, 0xc5, 0xe8, 0x53, - 0x7a, 0x5f, 0xd6, 0xff, 0xa2, 0x56, 0xc7, 0x71, 0x57, 0x92, 0x06, 0x72, 0x8b, 0xb3, 0xa8, 0x00, 0xd3, 0x32, 0x74, - 0x26, 0xb0, 0x57, 0xdd, 0x94, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xfa, 0x6e, 0x3a, 0xe0, 0xed, 0xd5, 0x1b, 0x24, 0xaa, - 0x82, 0xa5, 0x1d, 0x9d, 0x26, 0x41, 0xee, 0x11, 0x1e, 0x0f, 0xb6, 0x1b, 0xa9, 0xb9, 0x03, 0xd4, 0xc3, 0x6c, 0x4a, - 0x3c, 0xf7, 0x81, 0x1d, 0x49, 0xb3, 0xcc, 0x5f, 0x64, 0x47, 0xa4, 0x54, 0xaa, 0xdd, 0xb3, 0xee, 0x54, 0xf8, 0x43, - 0x10, 0x70, 0xd8, 0x1b, 0xe8, 0xef, 0x99, 0x8e, 0x8b, 0xdd, 0x99, 0x14, 0x7d, 0x52, 0xc3, 0xb6, 0x29, 0xec, 0x87, - 0x4e, 0xee, 0xb3, 0xe0, 0xea, 0x94, 0x09, 0x7b, 0x8f, 0x67, 0xc2, 0x1e, 0x52, 0xb5, 0xcb, 0xcb, 0x6a, 0x13, 0xf7, - 0x74, 0x4e, 0x1a, 0xc2, 0x4f, 0xef, 0x59, 0xf0, 0x0a, 0xf8, 0xff, 0x2f, 0x29, 0xee, 0x0f, 0xa7, 0xb7, 0x2f, 0x48, - 0x6d, 0x5f, 0x98, 0xd5, 0x8c, 0x77, 0xca, 0x79, 0xe8, 0x41, 0xfa, 0x62, 0x58, 0xb0, 0xa5, 0xf7, 0x67, 0x40, 0xfb, - 0xdf, 0x38, 0x06, 0x2f, 0xbc, 0x29, 0xbe, 0x44, 0xba, 0x31, 0x10, 0xe1, 0x60, 0x8a, 0x26, 0x57, 0x43, 0x3c, 0xf4, - 0x90, 0xaa, 0x9a, 0xc6, 0x68, 0x82, 0xa7, 0x40, 0x30, 0xc6, 0xc1, 0x04, 0x26, 0x90, 0xef, 0xe1, 0xd1, 0x6b, 0x3f, - 0xc0, 0xe3, 0x11, 0x50, 0xf9, 0x2e, 0x0e, 0x7c, 0x64, 0x68, 0xc7, 0xd8, 0x07, 0x71, 0x8a, 0x24, 0x28, 0x01, 0xe8, - 0x24, 0xc0, 0xee, 0x04, 0xc4, 0x8d, 0xb1, 0x7b, 0x89, 0xa7, 0x63, 0x34, 0xc5, 0x13, 0x80, 0x0e, 0x0f, 0x47, 0x85, - 0x33, 0xc2, 0x1e, 0x4c, 0x07, 0x63, 0x32, 0xc5, 0xc3, 0x00, 0xe9, 0xc6, 0xc0, 0x31, 0x01, 0x11, 0x0e, 0x76, 0xbd, - 0xd7, 0x01, 0xf6, 0x27, 0xa0, 0x77, 0x38, 0x7c, 0x01, 0x62, 0x2f, 0x87, 0xc8, 0xb4, 0x06, 0x5e, 0x50, 0x30, 0x7a, - 0x0c, 0x34, 0xff, 0x9f, 0x0b, 0x1a, 0x40, 0xe2, 0xa1, 0x00, 0x5f, 0x42, 0xec, 0x7a, 0x8a, 0xdf, 0xb4, 0x06, 0x37, - 0xcf, 0x43, 0xee, 0x1f, 0xc6, 0x2c, 0xf8, 0xe7, 0x62, 0xe6, 0x29, 0x04, 0xa0, 0x0b, 0xba, 0x41, 0x0e, 0xd2, 0x8d, - 0xd1, 0x0d, 0xcc, 0xd3, 0xab, 0x4b, 0x34, 0x05, 0xae, 0xf1, 0x14, 0x5d, 0xa2, 0x91, 0x42, 0x17, 0xd8, 0x87, 0x86, - 0xc9, 0x01, 0xa6, 0x2f, 0x84, 0x71, 0xf8, 0x37, 0x86, 0xf1, 0x31, 0x9f, 0xfe, 0xc6, 0x2e, 0xfd, 0x15, 0x57, 0x10, - 0x94, 0x63, 0xba, 0x0c, 0x8b, 0x06, 0xe6, 0x15, 0xaf, 0xaa, 0x28, 0x78, 0x94, 0x43, 0x35, 0x02, 0xef, 0x7a, 0x0f, - 0xb1, 0x34, 0xce, 0xbd, 0xf9, 0xbd, 0x2a, 0x1d, 0x28, 0xbd, 0x79, 0xa4, 0xd3, 0xf9, 0xfc, 0x26, 0xa7, 0xe8, 0xd5, - 0xf5, 0x3b, 0x78, 0x08, 0x16, 0x05, 0xe2, 0xd5, 0x1a, 0xde, 0x9b, 0x5b, 0x24, 0x2b, 0xf5, 0x82, 0xe7, 0x50, 0x2a, - 0xaa, 0x2e, 0x3c, 0x20, 0x50, 0x57, 0x2c, 0x60, 0x8c, 0xa3, 0x45, 0x33, 0x7f, 0x57, 0x50, 0x22, 0x28, 0x5a, 0xb2, - 0x15, 0x45, 0x4c, 0x42, 0x1d, 0x50, 0x52, 0x24, 0x99, 0x6a, 0x8e, 0x8c, 0x9a, 0xee, 0x6d, 0x25, 0x69, 0x88, 0xae, - 0xaa, 0x7a, 0xab, 0x85, 0x24, 0x39, 0xe1, 0x4b, 0x9a, 0x1e, 0x84, 0x29, 0xea, 0x6d, 0xd5, 0x36, 0xe8, 0x97, 0x17, - 0x6f, 0x5e, 0xab, 0x87, 0x36, 0x45, 0x4e, 0xa7, 0x6c, 0x23, 0xd1, 0x8f, 0x37, 0x2f, 0x50, 0x5b, 0xc3, 0xa6, 0x53, - 0x63, 0x5b, 0xb5, 0xa2, 0xcd, 0x1a, 0x2a, 0x4b, 0xaa, 0x48, 0x40, 0xb9, 0xa0, 0x52, 0x42, 0xa1, 0x21, 0x30, 0x94, - 0xce, 0xda, 0x13, 0x53, 0x75, 0x83, 0xbb, 0x20, 0x7e, 0xde, 0x95, 0xd7, 0x51, 0x1e, 0x18, 0xd7, 0xaf, 0x3b, 0x6a, - 0x70, 0x3d, 0x98, 0x47, 0xea, 0x39, 0x8d, 0x88, 0x7e, 0x84, 0xc4, 0x83, 0x35, 0xcb, 0x98, 0x7a, 0xb8, 0xcd, 0x23, - 0x5d, 0x8f, 0x2a, 0x09, 0xaa, 0x24, 0x32, 0x5f, 0x34, 0x74, 0xaf, 0xa0, 0x7c, 0x09, 0xaf, 0x64, 0xd8, 0x70, 0xa8, - 0x50, 0x12, 0x9a, 0x57, 0x05, 0x54, 0x40, 0xf1, 0xf5, 0xf5, 0x0f, 0xff, 0x52, 0x9f, 0x3f, 0xc0, 0xcf, 0x13, 0x27, - 0x3c, 0x29, 0x0c, 0xa3, 0xea, 0x74, 0x7c, 0xe3, 0xa1, 0xf9, 0x90, 0x51, 0xc3, 0x7b, 0x00, 0xfc, 0x4e, 0xef, 0x49, - 0x79, 0x77, 0x98, 0xec, 0x24, 0xe9, 0x5f, 0x5d, 0xd9, 0x1a, 0x26, 0xd1, 0x2e, 0x4a, 0x26, 0xe7, 0xd7, 0x60, 0x60, - 0x34, 0x30, 0x0b, 0xe0, 0x9c, 0x72, 0xc0, 0xd0, 0xe6, 0x1d, 0x0f, 0xec, 0xa8, 0x42, 0xec, 0x27, 0x8d, 0x98, 0xd9, - 0x60, 0xed, 0x65, 0x49, 0x65, 0x5e, 0xa5, 0xf1, 0xbb, 0x1f, 0xaf, 0x6f, 0x8e, 0x1e, 0x77, 0xb0, 0x52, 0x9e, 0x98, - 0x0f, 0x2c, 0x6d, 0x21, 0x59, 0x4d, 0x1a, 0xa9, 0xc5, 0x3a, 0x2a, 0xce, 0x0e, 0x1e, 0xe9, 0x75, 0xbd, 0x33, 0xda, - 0xa9, 0x8e, 0x71, 0x30, 0x47, 0x0f, 0xd9, 0x78, 0xd0, 0xfd, 0x99, 0x95, 0x03, 0x73, 0x14, 0x07, 0xe6, 0x5c, 0x0e, - 0xf4, 0xe7, 0xa7, 0xdf, 0x01, 0xf1, 0x69, 0xfc, 0xac, 0x8e, 0x12, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x5b, 0x8f, 0xdb, 0x36, 0x16, 0x7e, 0xef, + 0xaf, 0xe0, 0x2a, 0x49, 0x2d, 0x37, 0x23, 0xea, 0x66, 0xf9, 0x2a, 0xa9, 0x48, 0xb2, 0x29, 0x5a, 0x20, 0x69, 0x03, + 0xcc, 0xb4, 0xfb, 0x10, 0x04, 0x18, 0x5a, 0xa2, 0x2c, 0x66, 0x24, 0x4a, 0x15, 0xe9, 0x5b, 0x0c, 0xef, 0x6f, 0xdf, + 0x43, 0x52, 0xf6, 0x38, 0xb3, 0x99, 0x05, 0x52, 0xec, 0x62, 0xd1, 0x4e, 0x26, 0x1c, 0x92, 0x3a, 0xd7, 0x4f, 0x3c, + 0x17, 0x2a, 0xfe, 0x5b, 0xde, 0x64, 0x72, 0xdf, 0x52, 0x54, 0xca, 0xba, 0x4a, 0x63, 0x35, 0xa2, 0x8a, 0xf0, 0x55, + 0x42, 0x39, 0xac, 0x28, 0xc9, 0xd3, 0xb8, 0xa6, 0x92, 0xa0, 0xac, 0x24, 0x9d, 0xa0, 0x32, 0xf9, 0xf5, 0xe6, 0x07, + 0x67, 0x8a, 0xdc, 0x34, 0xae, 0x18, 0xbf, 0x43, 0x1d, 0xad, 0x12, 0x96, 0x35, 0x1c, 0x95, 0x1d, 0x2d, 0x92, 0x9c, + 0x48, 0x32, 0x67, 0x35, 0x59, 0x51, 0x45, 0xa0, 0xd9, 0x38, 0xa9, 0x69, 0xb2, 0x61, 0x74, 0xdb, 0x36, 0x9d, 0x44, + 0x40, 0x29, 0x29, 0x97, 0x89, 0xb5, 0x65, 0xb9, 0x2c, 0x93, 0x9c, 0x6e, 0x58, 0x46, 0x1d, 0xbd, 0xb8, 0x62, 0x9c, + 0x49, 0x46, 0x2a, 0x47, 0x64, 0xa4, 0xa2, 0x89, 0x7f, 0xb5, 0x16, 0xb4, 0xd3, 0x0b, 0xb2, 0x84, 0x35, 0x6f, 0x2c, + 0x10, 0x29, 0xb2, 0x8e, 0xb5, 0x12, 0x29, 0x7b, 0x93, 0xba, 0xc9, 0xd7, 0x15, 0x4d, 0x5d, 0x97, 0x08, 0xb0, 0x4b, + 0xb8, 0x8c, 0xe7, 0x74, 0x87, 0xa7, 0xb3, 0x68, 0x32, 0x9e, 0xe6, 0x13, 0xfc, 0x51, 0x7c, 0x03, 0x9e, 0xad, 0x6b, + 0x50, 0x87, 0xab, 0x26, 0x23, 0x92, 0x35, 0x1c, 0x0b, 0x4a, 0xba, 0xac, 0x4c, 0x92, 0xc4, 0xfa, 0x5e, 0x90, 0x0d, + 0xb5, 0xbe, 0xfd, 0xd6, 0x3e, 0x13, 0xad, 0xa8, 0x7c, 0x5d, 0x51, 0x35, 0x15, 0x2f, 0xf7, 0x37, 0x64, 0xf5, 0x33, + 0x58, 0x6e, 0x5b, 0x44, 0xb0, 0x9c, 0x5a, 0xc3, 0xf7, 0xde, 0x07, 0x2c, 0xe4, 0xbe, 0xa2, 0x38, 0x67, 0xa2, 0xad, + 0xc8, 0x3e, 0xb1, 0x96, 0x20, 0xf5, 0xce, 0x1a, 0x2e, 0x8a, 0x35, 0xcf, 0x94, 0x70, 0x24, 0x6c, 0x3a, 0x3c, 0x54, + 0x14, 0xcc, 0x4b, 0xde, 0x12, 0x59, 0xe2, 0x9a, 0xec, 0x6c, 0x33, 0x61, 0xdc, 0x0e, 0xbe, 0xb3, 0xe9, 0x73, 0xdf, + 0xf3, 0x86, 0x57, 0x7a, 0xf0, 0x86, 0x2e, 0xfc, 0x5d, 0x74, 0x54, 0xae, 0x3b, 0x8e, 0x88, 0x7d, 0x1b, 0xb7, 0x40, + 0x89, 0xf2, 0xc4, 0xaa, 0xfd, 0x00, 0x7b, 0xde, 0x14, 0xf9, 0x33, 0x1c, 0x44, 0x8e, 0xef, 0xe3, 0xd0, 0xf1, 0xa3, + 0x6c, 0xe2, 0x44, 0xc8, 0x1f, 0xc1, 0x10, 0x04, 0x38, 0x42, 0xde, 0x27, 0x0b, 0x15, 0xac, 0xaa, 0x12, 0x8b, 0x37, + 0x9c, 0x5a, 0x48, 0xc8, 0xae, 0xb9, 0xa3, 0x89, 0x95, 0xad, 0xbb, 0x0e, 0xec, 0x7f, 0xd5, 0x54, 0x4d, 0x07, 0x70, + 0x7d, 0x83, 0x3e, 0xfb, 0xf9, 0x6a, 0x15, 0xb2, 0x23, 0x5c, 0x14, 0x4d, 0x57, 0x27, 0x96, 0x7e, 0x29, 0xf6, 0xd3, + 0x83, 0x3c, 0x22, 0x35, 0x0c, 0x2f, 0x1e, 0x3a, 0x4d, 0xc7, 0x56, 0x8c, 0x27, 0x96, 0x1f, 0x20, 0x7f, 0x0a, 0x6a, + 0x6f, 0x87, 0xc7, 0x33, 0x26, 0x44, 0x61, 0xd2, 0x7b, 0xd9, 0xd8, 0xef, 0x6f, 0x63, 0xb1, 0x59, 0xa1, 0x5d, 0x5d, + 0x71, 0x91, 0x58, 0xa5, 0x94, 0xed, 0xdc, 0x75, 0xb7, 0xdb, 0x2d, 0xde, 0x86, 0xb8, 0xe9, 0x56, 0x6e, 0xe0, 0x79, + 0x9e, 0x0b, 0x14, 0x16, 0x32, 0xe7, 0xc3, 0x0a, 0x46, 0x16, 0x2a, 0x29, 0x5b, 0x95, 0x52, 0xcf, 0xd3, 0xa7, 0x07, + 0x7a, 0x8c, 0x15, 0x45, 0x7a, 0xfb, 0xe1, 0x42, 0x4b, 0x77, 0xa1, 0x85, 0x7e, 0x7f, 0x81, 0xe6, 0xe0, 0xad, 0x32, + 0x6a, 0x42, 0x02, 0x14, 0x20, 0x4f, 0xff, 0x0b, 0x1c, 0x35, 0xef, 0x57, 0xce, 0x83, 0x15, 0xba, 0x58, 0xc1, 0x5f, + 0xc0, 0x2f, 0xa8, 0xc7, 0xce, 0xec, 0xcc, 0xee, 0xab, 0xc7, 0x1b, 0xdf, 0xbb, 0xdf, 0x50, 0x3c, 0x3f, 0x8e, 0x2f, + 0xd7, 0x4e, 0xf0, 0x9b, 0x22, 0x50, 0xd8, 0x9f, 0x99, 0x9c, 0xa0, 0xf4, 0x7f, 0x1b, 0x93, 0x08, 0x45, 0xfd, 0x4e, + 0xe4, 0xa8, 0xf9, 0x79, 0xa5, 0x34, 0xa1, 0x68, 0x03, 0x54, 0xb5, 0x33, 0x76, 0x22, 0x12, 0xa2, 0xb0, 0x37, 0x09, + 0x66, 0xb0, 0x3d, 0x06, 0xe6, 0x8b, 0x3d, 0x27, 0xfc, 0x34, 0x50, 0x30, 0xcf, 0x2d, 0xeb, 0x1e, 0x83, 0xe6, 0x12, + 0x03, 0xfc, 0xb1, 0x81, 0x33, 0x67, 0x59, 0x80, 0x11, 0x95, 0x59, 0x69, 0x5b, 0x2e, 0x44, 0x5e, 0xc1, 0x56, 0x10, + 0x15, 0x0d, 0xb7, 0x86, 0x58, 0x96, 0x94, 0xdb, 0x27, 0x56, 0xc5, 0x48, 0xf5, 0x13, 0xfb, 0xe1, 0x13, 0x39, 0x3c, + 0x9c, 0xe3, 0x43, 0x32, 0x09, 0x71, 0x28, 0xb1, 0x8a, 0xe8, 0xab, 0xf3, 0xee, 0xb2, 0xc9, 0xf7, 0x8f, 0x84, 0x4e, + 0xe9, 0x9b, 0xb8, 0x61, 0x9c, 0xd3, 0xee, 0x86, 0xee, 0xe0, 0x1d, 0xfe, 0x83, 0xfd, 0xc0, 0xd0, 0xcf, 0x54, 0x6e, + 0x9b, 0xee, 0x4e, 0xcc, 0x91, 0xf5, 0xdc, 0x88, 0x5b, 0xa8, 0xa8, 0x61, 0x20, 0x9b, 0xb4, 0x02, 0x8b, 0x0a, 0x72, + 0x82, 0xed, 0x0f, 0x21, 0x7e, 0xda, 0x7b, 0x4b, 0xf8, 0xc9, 0xb9, 0xdb, 0x38, 0x67, 0x1b, 0x94, 0x55, 0x10, 0xf5, + 0x70, 0xfc, 0x8d, 0x28, 0x0b, 0xf5, 0x47, 0xbd, 0xe1, 0x19, 0x70, 0xdf, 0x25, 0xd6, 0x17, 0xa2, 0xfa, 0xe5, 0xfe, + 0xa7, 0xdc, 0x1e, 0x08, 0x88, 0xe7, 0xc1, 0x10, 0x6f, 0x48, 0xb5, 0xa6, 0x28, 0x41, 0xb2, 0x64, 0xe2, 0xde, 0xc0, + 0xc5, 0xa3, 0x6c, 0xad, 0xb8, 0x03, 0xae, 0x02, 0x1e, 0x0b, 0x7b, 0x68, 0x9d, 0x22, 0x2b, 0x26, 0x26, 0xef, 0x59, + 0x4f, 0xac, 0x07, 0x16, 0x39, 0x15, 0x2d, 0xa4, 0x75, 0x1f, 0x81, 0x4f, 0x0f, 0xc2, 0xe6, 0xb8, 0x03, 0xed, 0xc3, + 0xe3, 0x79, 0x33, 0x16, 0x2d, 0xe1, 0x0f, 0x19, 0x95, 0x81, 0xea, 0xa0, 0x43, 0xb2, 0x82, 0x99, 0x3a, 0xed, 0x40, + 0x74, 0x56, 0xe8, 0x92, 0xd3, 0xf4, 0xe9, 0xa1, 0x03, 0x89, 0x2a, 0x07, 0x9d, 0x25, 0xc6, 0x2e, 0x40, 0x93, 0xde, + 0x1e, 0x87, 0xf7, 0x7e, 0xfc, 0xbe, 0xa6, 0xdd, 0xfe, 0x9a, 0x56, 0x34, 0x93, 0x4d, 0x67, 0x5b, 0x4f, 0x40, 0x0b, + 0xbc, 0x7e, 0xed, 0xf0, 0x8f, 0x37, 0x6f, 0xdf, 0x24, 0x8d, 0xcd, 0x86, 0x57, 0x8f, 0x51, 0xab, 0x0c, 0xff, 0x1e, + 0x32, 0xfc, 0x3f, 0x93, 0x81, 0xca, 0xf1, 0x83, 0x0f, 0xc0, 0xaa, 0xfd, 0xbd, 0xbd, 0x4f, 0xf4, 0x2a, 0x18, 0x9f, + 0x43, 0x40, 0x5f, 0x29, 0x0f, 0x9d, 0x71, 0x34, 0x3c, 0x82, 0x7e, 0xb0, 0x00, 0xec, 0xd6, 0xb9, 0x1a, 0x72, 0xb6, + 0x4a, 0x9b, 0xe9, 0x77, 0x87, 0x65, 0xb3, 0x73, 0x04, 0xfb, 0xc4, 0xf8, 0x6a, 0xce, 0x78, 0x49, 0x3b, 0x26, 0x8f, + 0x60, 0x2e, 0xa4, 0xfd, 0x76, 0x2d, 0x0f, 0x2d, 0xc9, 0x73, 0xf5, 0x24, 0x6a, 0x77, 0x8b, 0x02, 0x8a, 0x84, 0xa2, + 0xa4, 0x73, 0x9f, 0xd6, 0x47, 0xf3, 0x5c, 0xe7, 0x83, 0xf9, 0x2c, 0x7a, 0x76, 0x54, 0x07, 0xee, 0x20, 0xe1, 0x65, + 0x39, 0xa4, 0x62, 0x2b, 0x3e, 0xcf, 0xc0, 0x70, 0xda, 0x19, 0xa6, 0x82, 0xd4, 0xac, 0xda, 0xcf, 0x05, 0x64, 0x26, + 0x07, 0xaa, 0x07, 0x2b, 0x8e, 0xcb, 0xb5, 0x94, 0x0d, 0x07, 0xdd, 0x5d, 0x4e, 0xbb, 0xb9, 0xb7, 0x30, 0x13, 0xa7, + 0x23, 0x39, 0x5b, 0x8b, 0x39, 0x0e, 0x3b, 0x5a, 0x2f, 0x96, 0x24, 0xbb, 0x5b, 0x75, 0xcd, 0x9a, 0xe7, 0x4e, 0xa6, + 0x32, 0xe7, 0xfc, 0x89, 0x5f, 0x90, 0x90, 0x66, 0x8b, 0x7e, 0x55, 0x14, 0xc5, 0x02, 0xa0, 0xa0, 0x8e, 0xc9, 0x44, + 0xf3, 0x00, 0x8f, 0x14, 0xdb, 0x85, 0x99, 0x38, 0x50, 0x1b, 0xc6, 0x46, 0x48, 0xeb, 0xcf, 0x16, 0x27, 0x77, 0xbc, + 0x05, 0xa4, 0x64, 0x01, 0x42, 0x5a, 0x88, 0x47, 0x30, 0xf3, 0x58, 0x13, 0xc6, 0x2f, 0xad, 0x57, 0xc7, 0x64, 0xd1, + 0x97, 0x14, 0x80, 0x45, 0xab, 0xd1, 0x85, 0x65, 0x01, 0x45, 0xc3, 0x14, 0xc6, 0x79, 0x30, 0xf6, 0xda, 0xdd, 0x11, + 0xf7, 0x07, 0xe4, 0x70, 0xa2, 0x2e, 0x2a, 0xba, 0x5b, 0x7c, 0x5c, 0x0b, 0xc9, 0x8a, 0xbd, 0xd3, 0x17, 0xd6, 0x39, + 0x1c, 0x16, 0x28, 0xa8, 0x4b, 0x20, 0xa5, 0x94, 0x2f, 0xb4, 0x0e, 0x87, 0x49, 0x5a, 0x8b, 0x1e, 0xa7, 0xb3, 0x18, + 0x7d, 0x40, 0x3f, 0x97, 0xf5, 0x9f, 0xa8, 0xd5, 0x59, 0x3c, 0xd4, 0xa4, 0x83, 0x44, 0xef, 0x2c, 0x1b, 0xc0, 0xb4, + 0x9e, 0x3b, 0x13, 0x78, 0x57, 0xfd, 0x96, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xba, 0x5e, 0x9e, 0xf0, 0xf6, 0xdb, 0x1d, + 0x12, 0x4d, 0xc5, 0xf2, 0x9e, 0x4e, 0x93, 0x20, 0xef, 0x0c, 0x8f, 0x0f, 0xaf, 0x1b, 0xa9, 0xbd, 0x13, 0xd4, 0xa3, + 0x62, 0x4a, 0x7c, 0xef, 0x0b, 0x6f, 0x24, 0x2f, 0x8a, 0x60, 0x59, 0x9c, 0x91, 0x52, 0x65, 0xef, 0xc8, 0xfa, 0x53, + 0x11, 0x8c, 0x40, 0xc0, 0xe9, 0xdd, 0xc0, 0xfc, 0xc8, 0x74, 0x58, 0x1c, 0x2e, 0xa4, 0xe8, 0xa3, 0x3a, 0x5f, 0x77, + 0x95, 0x6d, 0x7d, 0xe1, 0xe8, 0x3e, 0x0b, 0x5f, 0xdd, 0x97, 0xa5, 0xc1, 0xe3, 0x65, 0x69, 0x80, 0x54, 0x23, 0xf3, + 0xb2, 0xd9, 0x25, 0x03, 0x5d, 0x20, 0x46, 0xf0, 0x3b, 0x78, 0x16, 0xbe, 0x06, 0xfe, 0xff, 0x4a, 0xbd, 0xf9, 0xc3, + 0xc5, 0xe6, 0x2b, 0x2a, 0xcd, 0x57, 0x56, 0x19, 0xe3, 0x9d, 0x72, 0x1e, 0x66, 0x50, 0x4e, 0x18, 0x16, 0x6c, 0xe5, + 0xff, 0x2f, 0xa0, 0xfd, 0x77, 0x1c, 0xc3, 0x17, 0xfe, 0x14, 0xcf, 0x90, 0x1e, 0x0c, 0x44, 0x38, 0x9c, 0xa2, 0xc9, + 0xab, 0x11, 0x1e, 0xf9, 0x48, 0xb5, 0x30, 0x63, 0x34, 0x81, 0x7e, 0x0f, 0xf9, 0x63, 0x1c, 0x4e, 0x60, 0x03, 0x05, + 0x3e, 0x8e, 0xde, 0x04, 0x21, 0x1e, 0x47, 0x40, 0x15, 0x78, 0x38, 0x0c, 0x90, 0xa1, 0x1d, 0xe3, 0x00, 0xc4, 0x29, + 0x92, 0xb0, 0x06, 0xa0, 0xb3, 0x10, 0x7b, 0x13, 0x10, 0x37, 0xc6, 0xde, 0x0c, 0x4f, 0xc7, 0x68, 0x8a, 0x27, 0x00, + 0x1d, 0x1e, 0x45, 0x95, 0x13, 0x61, 0x1f, 0xb6, 0xc3, 0x31, 0x99, 0xe2, 0x51, 0x88, 0xf4, 0x60, 0xe0, 0x98, 0x80, + 0x08, 0x07, 0x7b, 0xfe, 0x9b, 0x10, 0x07, 0x13, 0xd0, 0x3b, 0x1a, 0xbd, 0x00, 0xb1, 0xb3, 0x11, 0x32, 0xa3, 0x81, + 0x17, 0x14, 0x44, 0x8f, 0x81, 0x16, 0xfc, 0x75, 0x41, 0x03, 0x48, 0x7c, 0x14, 0xe2, 0x19, 0xc4, 0xae, 0xaf, 0xf8, + 0xcd, 0x68, 0x70, 0xf3, 0x7d, 0xe4, 0xfd, 0x61, 0xcc, 0xc2, 0xbf, 0x2e, 0x66, 0xbe, 0x42, 0x00, 0xa6, 0xa0, 0x1b, + 0xe4, 0x20, 0x3d, 0x18, 0xdd, 0xc0, 0x3c, 0x7d, 0x35, 0x43, 0x53, 0xe0, 0x1a, 0x4f, 0xd1, 0x0c, 0x45, 0x0a, 0x5d, + 0x60, 0x1f, 0x19, 0x26, 0x07, 0x98, 0xbe, 0x12, 0xc6, 0xd1, 0x9f, 0x18, 0xc6, 0xc7, 0x7c, 0xfa, 0x13, 0xbb, 0xf4, + 0xff, 0x48, 0x41, 0xd0, 0x8e, 0xe9, 0x36, 0x2c, 0x76, 0xcd, 0x95, 0x5e, 0x75, 0x51, 0x70, 0x43, 0x87, 0x6e, 0x04, + 0x2e, 0xf9, 0x3e, 0x62, 0x79, 0x52, 0xfa, 0xe9, 0x67, 0xdd, 0x39, 0x50, 0xfa, 0x69, 0xac, 0xcb, 0x79, 0x7a, 0x53, + 0x52, 0xf4, 0xfa, 0xfa, 0x1d, 0xdc, 0xca, 0xaa, 0x0a, 0xf1, 0x66, 0x0b, 0x97, 0xbf, 0x3d, 0x92, 0x8d, 0xba, 0xce, + 0x73, 0xe8, 0x15, 0xd5, 0x14, 0xee, 0x0d, 0xa8, 0x6f, 0x16, 0x30, 0xc6, 0xf1, 0xb2, 0x4b, 0xdf, 0x55, 0x94, 0x08, + 0x8a, 0x56, 0x6c, 0x43, 0x11, 0x93, 0xd0, 0x07, 0xd4, 0x14, 0x49, 0xa6, 0x86, 0x33, 0xa3, 0xa6, 0x83, 0x9e, 0x56, + 0x2b, 0x31, 0xdd, 0x30, 0x58, 0x02, 0x62, 0xd2, 0xbe, 0xed, 0x8d, 0xcb, 0xd0, 0x58, 0x75, 0x4d, 0xa5, 0x84, 0x8e, + 0x41, 0x59, 0x15, 0xa6, 0xb1, 0xba, 0x76, 0x22, 0xa2, 0x2f, 0x06, 0x89, 0xbb, 0x65, 0x05, 0x53, 0x97, 0xf9, 0x34, + 0xd6, 0xad, 0xa2, 0x92, 0xa0, 0xba, 0x15, 0xf3, 0xe5, 0x41, 0xcf, 0x2a, 0xca, 0x57, 0x70, 0x9b, 0x84, 0x77, 0x01, + 0xcd, 0x43, 0x46, 0xcb, 0xa6, 0x82, 0xe6, 0x24, 0xb9, 0xbe, 0xfe, 0xe9, 0xef, 0xea, 0x33, 0x85, 0x32, 0xe1, 0xcc, + 0x09, 0x7d, 0xbe, 0x61, 0x54, 0x93, 0x9e, 0x6f, 0x3c, 0x32, 0x1f, 0x1c, 0x5a, 0xe8, 0xd3, 0xc1, 0xbf, 0xfc, 0x33, + 0x29, 0xef, 0x4e, 0x9b, 0xbd, 0x24, 0xfd, 0x5f, 0x37, 0x9d, 0x86, 0x49, 0xac, 0x97, 0x35, 0x93, 0xe9, 0x35, 0x18, + 0x18, 0xbb, 0xe6, 0x01, 0x38, 0xa7, 0x1c, 0x30, 0xb4, 0x65, 0xcf, 0x03, 0x60, 0xff, 0x72, 0xf3, 0x02, 0xfd, 0xda, + 0xc2, 0x09, 0xa6, 0x06, 0x7b, 0xed, 0x65, 0x4d, 0x65, 0xd9, 0xe4, 0xc9, 0xbb, 0x5f, 0xae, 0x6f, 0xce, 0x1e, 0xaf, + 0x35, 0x11, 0xa2, 0x3c, 0x33, 0x1f, 0x42, 0xd6, 0x95, 0x64, 0x2d, 0xe9, 0xa4, 0x16, 0xeb, 0xa8, 0x10, 0x38, 0x79, + 0xa4, 0x9f, 0x17, 0xac, 0xa2, 0xc6, 0xa9, 0x9e, 0xd1, 0x4d, 0xd1, 0x97, 0x6c, 0x3c, 0xe9, 0x7e, 0x60, 0xa5, 0x6b, + 0x4e, 0x89, 0x6b, 0x8e, 0x8c, 0xab, 0x3f, 0x13, 0xfd, 0x0b, 0x65, 0x37, 0xa3, 0x8e, 0x36, 0x12, 0x00, 0x00}; } // namespace captive_portal } // namespace esphome diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 8eaaaf4581..4e6e136f8c 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,585 +6,596 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xdb, 0xc8, 0x92, 0xe0, 0xf3, - 0x9c, 0xd3, 0x7f, 0x30, 0x2f, 0x30, 0x4a, 0x6d, 0x03, 0x57, 0x20, 0x44, 0x52, 0x96, 0xed, 0x02, 0x05, 0xf2, 0xca, - 0x4b, 0x5d, 0xbb, 0xca, 0x5b, 0x59, 0xb2, 0x6b, 0x51, 0xb1, 0x2c, 0x88, 0x4c, 0x8a, 0x28, 0x83, 0x00, 0x0b, 0x48, - 0x6a, 0x29, 0x0a, 0x7d, 0xfa, 0xa9, 0x9f, 0xe6, 0x9c, 0x59, 0x1f, 0xfa, 0x65, 0x4e, 0xf7, 0xc3, 0x7c, 0xc4, 0x3c, - 0xf7, 0xa7, 0xdc, 0x1f, 0x98, 0xfe, 0x84, 0x89, 0x88, 0x5c, 0x90, 0x00, 0xa9, 0xc5, 0xd5, 0xd5, 0x7d, 0xbc, 0x08, - 0xc8, 0x35, 0x22, 0x32, 0x32, 0xb6, 0x8c, 0x84, 0x76, 0xef, 0x8c, 0xb3, 0x11, 0xbf, 0x98, 0x33, 0x6b, 0xca, 0x67, - 0x49, 0x7f, 0x57, 0xfe, 0xcf, 0xa2, 0x71, 0x7f, 0x37, 0x89, 0xd3, 0x4f, 0x56, 0xce, 0x92, 0x30, 0x1e, 0x65, 0xa9, - 0x35, 0xcd, 0xd9, 0x24, 0x1c, 0x47, 0x3c, 0x0a, 0xe2, 0x59, 0x74, 0xc2, 0xac, 0xad, 0xfe, 0xee, 0x8c, 0xf1, 0xc8, - 0x1a, 0x4d, 0xa3, 0xbc, 0x60, 0x3c, 0x7c, 0x7f, 0xf0, 0x55, 0xeb, 0x51, 0x7f, 0xb7, 0x18, 0xe5, 0xf1, 0x9c, 0x5b, - 0x38, 0x64, 0x38, 0xcb, 0xc6, 0x8b, 0x84, 0xf5, 0x4f, 0xa3, 0xdc, 0x7a, 0xc6, 0xc2, 0x37, 0xc7, 0xbf, 0xb0, 0x11, - 0xf7, 0xc7, 0x6c, 0x12, 0xa7, 0xec, 0x6d, 0x9e, 0xcd, 0x59, 0xce, 0x2f, 0xbc, 0xfd, 0xf5, 0x15, 0x31, 0x2b, 0xbc, - 0x4f, 0xba, 0xea, 0x84, 0xf1, 0x37, 0x67, 0xa9, 0xea, 0xf3, 0x94, 0x89, 0x49, 0xb2, 0xbc, 0xf0, 0x8a, 0x2b, 0xda, - 0xec, 0x5f, 0xcc, 0x8e, 0xb3, 0xa4, 0xf0, 0x9e, 0xe8, 0xfa, 0x79, 0x9e, 0xf1, 0x0c, 0xc1, 0xf2, 0xa7, 0x51, 0x61, - 0xb4, 0xf4, 0xde, 0xac, 0x69, 0x32, 0x97, 0x95, 0x2f, 0x8a, 0x67, 0xe9, 0x62, 0xc6, 0xf2, 0xe8, 0x38, 0x61, 0x5e, - 0xcc, 0x42, 0x87, 0x79, 0xdc, 0x8b, 0xdd, 0xb0, 0xcf, 0xad, 0x38, 0xb5, 0xd8, 0xe0, 0x19, 0xa3, 0x92, 0x25, 0xd3, - 0xad, 0x82, 0x3b, 0x6d, 0x0f, 0xc8, 0x35, 0x89, 0x4f, 0x16, 0xfa, 0xfd, 0x2c, 0x8f, 0xb9, 0x7a, 0x3e, 0x8d, 0x92, - 0x05, 0x0b, 0xe2, 0xd2, 0x0d, 0xd8, 0x21, 0x1f, 0x86, 0xb1, 0xf7, 0x84, 0x06, 0x85, 0x21, 0x97, 0x93, 0x2c, 0x77, - 0x90, 0x56, 0x31, 0x8e, 0xcd, 0x2f, 0x2f, 0x1d, 0x1e, 0x2e, 0x4b, 0xd7, 0x7d, 0xc2, 0xfc, 0x51, 0x94, 0x24, 0x0e, - 0x4e, 0x7c, 0xf7, 0x6e, 0x8c, 0x33, 0xc6, 0x1e, 0x3f, 0x8c, 0x87, 0x6e, 0x2f, 0x9e, 0x38, 0x05, 0x73, 0xab, 0x7e, - 0xd9, 0xc4, 0x2a, 0x98, 0xc3, 0x5d, 0xf7, 0xcd, 0xd5, 0x7d, 0x72, 0xc6, 0x17, 0x39, 0xc0, 0x5e, 0x7a, 0x6f, 0xd4, - 0xcc, 0xfb, 0x58, 0xff, 0x89, 0x3a, 0xf6, 0x00, 0xf6, 0x82, 0x5b, 0x1f, 0xc2, 0xb3, 0x38, 0x1d, 0x67, 0x67, 0xfe, - 0xfe, 0x34, 0x82, 0x1f, 0xef, 0xb2, 0x8c, 0xdf, 0xbd, 0xeb, 0x9c, 0x66, 0xf1, 0xd8, 0x6a, 0x87, 0xa1, 0x59, 0x79, - 0xf1, 0x64, 0x7f, 0xff, 0xf2, 0xb2, 0x51, 0xe0, 0xa7, 0x11, 0x8f, 0x4f, 0x99, 0xe8, 0x0c, 0x00, 0xd8, 0xf0, 0x73, - 0xce, 0xd9, 0x78, 0x9f, 0x5f, 0x24, 0x50, 0xca, 0x18, 0x2f, 0x6c, 0xc0, 0xf1, 0x69, 0x36, 0x02, 0xb2, 0xa5, 0x06, - 0xe1, 0xa1, 0x69, 0xce, 0xe6, 0x49, 0x34, 0x62, 0x58, 0x0f, 0x23, 0x55, 0x3d, 0xaa, 0x46, 0xde, 0x57, 0xa1, 0x58, - 0x5e, 0xc7, 0xf5, 0x72, 0x16, 0xa6, 0xec, 0xcc, 0x7a, 0x15, 0xcd, 0x7b, 0xa3, 0x24, 0x2a, 0x0a, 0x2b, 0x63, 0x4b, - 0x42, 0x21, 0x5f, 0x8c, 0x80, 0x41, 0x08, 0xc1, 0x25, 0x90, 0x89, 0x4f, 0xe3, 0xc2, 0xff, 0xb8, 0x31, 0x2a, 0x8a, - 0x77, 0xac, 0x58, 0x24, 0x7c, 0x23, 0x84, 0xb5, 0xe0, 0x77, 0xc2, 0xf0, 0x2b, 0x97, 0x4f, 0xf3, 0xec, 0xcc, 0x7a, - 0x96, 0xe7, 0xd0, 0xdc, 0x86, 0x29, 0x45, 0x03, 0x2b, 0x2e, 0xac, 0x34, 0xe3, 0x96, 0x1e, 0x0c, 0x17, 0xd0, 0xb7, - 0xde, 0x17, 0xcc, 0x3a, 0x5a, 0xa4, 0x45, 0x34, 0x61, 0xd0, 0xf4, 0xc8, 0xca, 0x72, 0xeb, 0x08, 0x06, 0x3d, 0x82, - 0x25, 0x2b, 0x38, 0xec, 0x1a, 0xdf, 0x76, 0x7b, 0x34, 0x17, 0x14, 0x1e, 0xb0, 0x73, 0x1e, 0xb2, 0x12, 0x18, 0xd3, - 0x2a, 0x34, 0x1a, 0x8e, 0xbb, 0x4c, 0xa0, 0x80, 0x85, 0x39, 0x43, 0x96, 0x75, 0xcc, 0xc6, 0x7a, 0x71, 0x3e, 0xdc, - 0xbd, 0xab, 0x69, 0x0d, 0x34, 0x71, 0xa0, 0x6d, 0xd1, 0x68, 0xeb, 0x09, 0xc4, 0x6b, 0x24, 0x72, 0x3d, 0xe6, 0x4b, - 0xf2, 0xed, 0x5f, 0xa4, 0xa3, 0xfa, 0xd8, 0x50, 0x59, 0xf2, 0x6c, 0x9f, 0xe7, 0x71, 0x7a, 0x02, 0x40, 0xc8, 0x99, - 0xcc, 0x26, 0x65, 0x29, 0x16, 0xff, 0x2d, 0x0b, 0x59, 0xd8, 0xc7, 0xd1, 0x33, 0xe6, 0xd8, 0x05, 0xf5, 0xb0, 0xc3, - 0x10, 0x49, 0x0f, 0x0c, 0xc6, 0x06, 0x2c, 0x60, 0x9b, 0xb6, 0xed, 0x7d, 0xe5, 0x7a, 0x17, 0xc8, 0x41, 0xbe, 0xef, - 0x13, 0xfb, 0x8a, 0xce, 0x71, 0xd8, 0x41, 0xa0, 0xfd, 0x84, 0xa5, 0x27, 0x7c, 0x3a, 0x60, 0x87, 0xed, 0x61, 0xc0, - 0x01, 0xaa, 0xf1, 0x62, 0xc4, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, 0x77, 0x08, - 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x63, 0x96, 0x1b, 0x70, 0xe8, 0x66, - 0xbd, 0xda, 0x0a, 0x2e, 0x60, 0x85, 0xa0, 0x9f, 0x35, 0x59, 0xa4, 0x23, 0x1e, 0x83, 0xe0, 0xb2, 0x37, 0x01, 0x5c, - 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0x67, 0xe8, 0x21, 0x94, 0x9a, - 0xf8, 0x12, 0xf1, 0x18, 0x10, 0x2c, 0xbd, 0xf7, 0x4c, 0x6f, 0xcf, 0x0f, 0x03, 0xe6, 0xaf, 0xf2, 0x71, 0xc8, 0xfd, - 0x59, 0x34, 0x47, 0x6c, 0x18, 0xf1, 0x40, 0x94, 0x8e, 0x10, 0xba, 0xda, 0xba, 0x20, 0xc5, 0xfc, 0x8a, 0x05, 0x5c, - 0x20, 0x08, 0xec, 0xd9, 0x67, 0xd1, 0x68, 0x0a, 0x5b, 0xbc, 0x22, 0xdc, 0x58, 0x6d, 0x87, 0x51, 0xce, 0x22, 0xce, - 0x9e, 0x25, 0x0c, 0xdf, 0x70, 0x05, 0xa0, 0xa7, 0x0d, 0xbc, 0xae, 0xf6, 0x5d, 0x12, 0xf3, 0xd7, 0x19, 0xcc, 0xd3, - 0x13, 0x4c, 0x02, 0x5c, 0x9c, 0xc3, 0x26, 0x47, 0x16, 0xd9, 0xe3, 0xb0, 0x5a, 0xc7, 0x0b, 0x0e, 0xeb, 0x96, 0x62, - 0x0b, 0x1b, 0xa8, 0xed, 0xc5, 0x3e, 0x07, 0x22, 0x3e, 0xc9, 0x52, 0x0e, 0xc3, 0x01, 0xbc, 0x9a, 0x83, 0xfc, 0x68, - 0x3e, 0x67, 0xe9, 0xf8, 0xc9, 0x34, 0x4e, 0xc6, 0x40, 0x8d, 0x12, 0xf0, 0x4d, 0x59, 0x08, 0x78, 0x02, 0x32, 0xc1, - 0xf5, 0x18, 0xd1, 0xf2, 0x21, 0x23, 0xf3, 0xd0, 0xb6, 0x7b, 0x28, 0x81, 0x24, 0x16, 0x28, 0x83, 0x68, 0xe1, 0xde, - 0x81, 0xe8, 0x2f, 0x5c, 0xbe, 0x19, 0xc6, 0x7a, 0x19, 0x25, 0x81, 0xdf, 0xa2, 0xa4, 0x01, 0xfa, 0x33, 0x90, 0x81, - 0x3d, 0x14, 0x5c, 0xdf, 0x49, 0xa9, 0x93, 0x30, 0x85, 0x21, 0x10, 0x60, 0x84, 0x12, 0x44, 0xd2, 0xe0, 0x6d, 0x96, - 0x5c, 0x4c, 0xe2, 0x24, 0xd9, 0x5f, 0xcc, 0xe7, 0x59, 0xce, 0xbd, 0xaf, 0xc3, 0x25, 0xcf, 0x2a, 0x5c, 0x69, 0x93, - 0x17, 0x67, 0x31, 0x47, 0x82, 0xba, 0xcb, 0x51, 0x04, 0x4b, 0xfd, 0x38, 0xcb, 0x12, 0x16, 0xa5, 0x80, 0x06, 0x1b, - 0xd8, 0x76, 0x90, 0x2e, 0x92, 0xa4, 0x77, 0x0c, 0xc3, 0x7e, 0xea, 0x51, 0xb5, 0x90, 0xf8, 0x01, 0x3d, 0xef, 0xe5, - 0x79, 0x74, 0x01, 0x0d, 0xb1, 0x0d, 0xf0, 0x22, 0xac, 0xd6, 0xd7, 0xfb, 0x6f, 0x5e, 0xfb, 0x82, 0xf1, 0xe3, 0xc9, - 0x05, 0x00, 0x5a, 0x56, 0x52, 0x73, 0x92, 0x67, 0xb3, 0xc6, 0xd4, 0x48, 0x87, 0x38, 0x64, 0xbd, 0x2b, 0x40, 0x88, - 0x69, 0x64, 0x58, 0x25, 0x66, 0x42, 0xf0, 0x9a, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, 0x43, 0x20, 0x8a, 0x61, - 0xca, 0xeb, 0xa1, 0xe5, 0xf9, 0xc5, 0x32, 0x0e, 0x09, 0xce, 0x39, 0xea, 0x5f, 0x84, 0x71, 0x14, 0xc1, 0xec, 0x4b, - 0x31, 0x60, 0xa9, 0x20, 0x8e, 0xcb, 0xd2, 0x8b, 0x34, 0x13, 0xa3, 0xc4, 0x43, 0x81, 0xc2, 0x61, 0x1b, 0x5d, 0x5e, - 0x32, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x65, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, 0x02, 0x35, 0xd9, - 0x29, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x10, 0xb5, 0x93, 0x04, 0xa1, 0xb8, 0xd3, 0xf1, 0x40, 0x83, 0x3e, 0x99, 0x46, - 0xe9, 0x09, 0x1b, 0x07, 0x11, 0x2b, 0xa5, 0xe4, 0xdd, 0xb3, 0x60, 0x8d, 0x81, 0x9d, 0x0a, 0xeb, 0xf9, 0xc1, 0xab, - 0x97, 0x72, 0xe5, 0x6a, 0xc2, 0x18, 0x16, 0x69, 0x01, 0x6a, 0x15, 0xc4, 0xb6, 0x14, 0xc7, 0xcf, 0xb8, 0x92, 0xde, - 0xa2, 0x24, 0x2e, 0xde, 0xcf, 0xc1, 0xc4, 0x60, 0x6f, 0x61, 0x18, 0x98, 0x3e, 0x84, 0xa9, 0xa8, 0x1c, 0xe6, 0x13, - 0x15, 0x63, 0x5d, 0x04, 0x9d, 0x05, 0xa6, 0xe2, 0x35, 0x73, 0xdc, 0x12, 0x58, 0x95, 0xc7, 0x23, 0x2b, 0x1a, 0x8f, - 0x5f, 0xa4, 0x31, 0x8f, 0xa3, 0x24, 0xfe, 0x8d, 0x28, 0xb9, 0x44, 0x1e, 0xe3, 0x3d, 0xb9, 0x08, 0x80, 0x3b, 0xf5, - 0x48, 0x5c, 0x25, 0x64, 0xef, 0x10, 0x31, 0x84, 0xb4, 0x4c, 0xc2, 0xc3, 0xa1, 0x04, 0x2f, 0xf1, 0xe7, 0x8b, 0x62, - 0x8a, 0x84, 0x95, 0x03, 0xa3, 0x20, 0xcf, 0x8e, 0x0b, 0x96, 0x9f, 0xb2, 0xb1, 0xe6, 0x80, 0x02, 0xb0, 0xa2, 0xe6, - 0x60, 0xbc, 0xd0, 0x8c, 0x8e, 0xd2, 0xa1, 0x0c, 0x86, 0xea, 0x99, 0x62, 0x96, 0x49, 0x66, 0xd6, 0x16, 0x8e, 0x96, - 0x02, 0x8e, 0x30, 0x2a, 0xa4, 0x24, 0xc8, 0x43, 0x85, 0xe1, 0x14, 0xa4, 0x10, 0x68, 0x05, 0x73, 0x9b, 0x2b, 0x4d, - 0xf6, 0x6c, 0x41, 0x2a, 0x21, 0x87, 0x8e, 0xb0, 0x91, 0x09, 0xd2, 0xdc, 0x85, 0x5d, 0x05, 0x52, 0x5e, 0x82, 0x2b, - 0xa4, 0x88, 0x32, 0x73, 0x90, 0x01, 0xc2, 0x6f, 0x84, 0x2e, 0xf4, 0xb1, 0x05, 0xb1, 0x81, 0xaf, 0x57, 0x1e, 0x08, - 0x2b, 0xf1, 0xae, 0x10, 0xf1, 0xae, 0x00, 0x1b, 0x27, 0x46, 0x7e, 0xf2, 0xee, 0x70, 0x3f, 0xcd, 0xf6, 0x46, 0x23, - 0x56, 0x14, 0x19, 0xc0, 0x76, 0x87, 0xda, 0x5f, 0x65, 0x68, 0x01, 0x25, 0x5d, 0x2d, 0xeb, 0xec, 0x82, 0x34, 0xb8, - 0xa9, 0x56, 0x94, 0x4e, 0x0f, 0xec, 0x8f, 0x1f, 0x41, 0x66, 0x7b, 0x92, 0x0c, 0x40, 0xf5, 0x55, 0xc3, 0x4f, 0xd8, - 0x33, 0x75, 0xca, 0xac, 0xb5, 0x2f, 0x9d, 0x3a, 0x48, 0x1e, 0x0c, 0xeb, 0x96, 0xc6, 0x82, 0xae, 0x1d, 0x1a, 0x57, - 0x43, 0x2a, 0xc8, 0xe5, 0x09, 0xa9, 0x6c, 0x63, 0x19, 0xc1, 0x6a, 0x2b, 0x3d, 0x22, 0xbd, 0xc2, 0xa6, 0x20, 0x40, - 0x0f, 0xd9, 0xb0, 0x27, 0xeb, 0xc3, 0x5c, 0x50, 0x2e, 0x67, 0xbf, 0x2e, 0x58, 0xc1, 0x05, 0xeb, 0xc2, 0xb8, 0x05, - 0x8c, 0x5b, 0xae, 0x58, 0x87, 0x35, 0xdb, 0x71, 0x1d, 0x6c, 0x6f, 0xe6, 0xa8, 0xc7, 0x0a, 0xe4, 0xe4, 0xeb, 0xd9, - 0x09, 0x61, 0x65, 0xee, 0xe5, 0xe5, 0x37, 0x6a, 0x90, 0x6a, 0x29, 0xb5, 0x0d, 0xd4, 0x58, 0x13, 0x5b, 0x35, 0x19, - 0xdb, 0xae, 0x54, 0xa8, 0x77, 0x3a, 0xbd, 0x1a, 0x1f, 0xc0, 0x9e, 0x6b, 0x6b, 0x96, 0xae, 0x8c, 0xed, 0xb7, 0x8a, - 0xa6, 0x6f, 0xc4, 0xc8, 0x64, 0x8d, 0xb2, 0x9b, 0xb9, 0x47, 0xed, 0x78, 0x68, 0xbb, 0x52, 0x57, 0x09, 0x86, 0x45, - 0x5d, 0x30, 0x34, 0xa1, 0x9e, 0xeb, 0x2e, 0xb6, 0x66, 0x2a, 0x16, 0xaa, 0xb5, 0x56, 0x0e, 0x04, 0x0f, 0x0f, 0xc1, - 0x38, 0x59, 0xeb, 0x1f, 0xbc, 0x8e, 0x66, 0x0c, 0x29, 0xea, 0x5d, 0xd5, 0x40, 0x3a, 0x10, 0xd0, 0x64, 0xd8, 0x54, - 0x6f, 0xdc, 0x15, 0x56, 0x53, 0x7d, 0x7f, 0xc5, 0x60, 0x45, 0x80, 0x7d, 0x5d, 0xae, 0x59, 0x22, 0xd2, 0x9b, 0x82, - 0x4b, 0x34, 0x7d, 0x44, 0x99, 0x58, 0x13, 0x52, 0xf0, 0x80, 0x3c, 0x2c, 0x7f, 0x63, 0xe1, 0x64, 0x2b, 0xa6, 0x70, - 0xe4, 0x28, 0x53, 0x80, 0xce, 0xa4, 0x04, 0x40, 0x5c, 0xd2, 0xcf, 0xda, 0xc6, 0x42, 0xb2, 0xed, 0x23, 0x1f, 0xf8, - 0x93, 0x24, 0xe2, 0x4e, 0x67, 0xab, 0xed, 0x02, 0x1f, 0x82, 0x10, 0x07, 0x1d, 0x01, 0xe6, 0x7d, 0x85, 0x0a, 0x43, - 0x54, 0x62, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe3, 0x09, 0x77, 0x52, 0x54, 0x22, 0x6e, 0xc9, 0x12, 0x50, 0x32, 0x7a, - 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, 0x0b, 0x2a, 0x08, 0x0c, - 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x15, 0x8b, 0x32, 0x1e, 0xc4, 0xab, 0x85, 0xa0, - 0x86, 0x7d, 0x9e, 0xbd, 0xcc, 0xce, 0x58, 0xfe, 0x24, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, 0x49, 0x4f, 0x02, 0x9d, - 0xf5, 0x14, 0xaf, 0x9c, 0x12, 0xd2, 0xb0, 0x10, 0xb3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, - 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x65, 0x9d, 0xb7, 0x60, 0x84, 0xb9, 0xe2, 0xd6, 0xfa, 0x8e, 0x75, - 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x79, 0x59, 0x19, 0xe9, 0xa0, 0x4c, 0xb5, 0x34, - 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, 0x8b, 0xbc, 0xb8, 0xe7, - 0x34, 0xd4, 0x11, 0x40, 0x31, 0xab, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, 0x8d, 0xbc, 0xaa, 0x89, - 0x80, 0x38, 0x1d, 0xb3, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, 0x83, 0x84, 0x57, 0x08, - 0x80, 0x79, 0xe2, 0x4f, 0xb3, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xf2, 0x32, 0x16, 0xfe, 0x22, 0x32, 0x40, 0xce, - 0x66, 0xd9, 0x29, 0x5b, 0x03, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, 0x54, 0xcb, 0x3c, 0x89, - 0x47, 0x4c, 0x6b, 0xa9, 0x99, 0x0f, 0x06, 0x1d, 0x3b, 0x07, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, 0xdf, 0xf6, 0x3a, 0x6e, - 0x29, 0x08, 0xbe, 0x5c, 0xa1, 0xe8, 0x35, 0xfa, 0x51, 0x9a, 0xe0, 0xeb, 0x64, 0x01, 0x77, 0x0d, 0xa5, 0xc8, 0x85, - 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x63, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, 0xdb, 0xf6, 0x9d, 0x26, - 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, 0x5a, 0x89, 0x54, 0x0d, - 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x41, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, 0xef, 0x99, 0x04, 0x73, - 0x1d, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x02, 0xcb, 0x73, 0x1c, 0x8d, 0x3e, 0x69, 0x70, - 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, 0xb6, 0x51, 0xc0, 0x21, - 0x5b, 0x61, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0x5c, 0xc3, 0x72, 0x5c, 0x49, - 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8e, 0x8b, 0xab, 0x49, 0xf0, 0x87, 0x82, 0xf9, - 0xd4, 0x98, 0xe9, 0x46, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, 0xd4, 0x7c, 0x83, 0x86, - 0x0a, 0x71, 0xfc, 0x89, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, 0x2a, 0x5a, 0xa4, 0x4c, - 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, 0xdc, 0x34, 0xd4, 0xc2, - 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, 0xfb, 0x86, 0x0f, 0x65, - 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, 0x74, 0x41, 0xa0, 0x48, - 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, 0x4a, 0x33, 0x2f, 0x75, - 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x71, 0x41, 0x99, 0xd8, 0xbb, 0x8e, 0x36, 0x5e, 0x1a, 0x66, 0xc2, 0xfa, 0x15, - 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, 0xb1, 0xa7, 0x00, 0x94, - 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x10, 0x1d, 0x2b, 0x11, 0x5a, 0x13, 0xf9, 0x5a, 0x9f, - 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, 0x25, 0x83, 0x84, 0x1c, - 0xd2, 0x55, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x0e, 0xc3, 0xc8, 0x41, 0xc7, 0x9d, 0xd6, 0x62, - 0x85, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, 0x0e, 0xa0, 0x03, 0x62, - 0x7f, 0x85, 0xf5, 0xd6, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0x97, 0x97, 0x11, 0xf2, 0x83, 0x30, 0x78, 0x61, 0xcd, - 0x06, 0x4a, 0xf6, 0xee, 0xbd, 0xc4, 0x56, 0x64, 0x7f, 0x56, 0x25, 0x95, 0xa7, 0x50, 0xe3, 0xdc, 0xfa, 0x3a, 0x31, - 0x33, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, 0x76, 0x5d, 0x37, - 0xc8, 0xc9, 0x79, 0xb9, 0xb3, 0xce, 0x85, 0xbc, 0x7b, 0xd7, 0xf4, 0x99, 0x4e, 0xf5, 0xf0, 0x4f, 0x1c, 0x54, 0xce, - 0xc5, 0x45, 0x4a, 0x16, 0xcc, 0x13, 0xa5, 0x8e, 0x56, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, 0x2c, 0x8a, 0xb9, - 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, 0xda, 0xa2, 0xc5, - 0x68, 0xca, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x41, 0xbc, 0xc5, 0xc0, 0x6c, 0x3d, 0xec, 0x65, 0xb3, - 0x7b, 0xcd, 0xfc, 0x87, 0x35, 0x02, 0xd9, 0x36, 0x53, 0x75, 0x65, 0xe3, 0x5d, 0x8a, 0x48, 0x8c, 0xb0, 0xad, 0x1b, - 0x5b, 0xda, 0xfa, 0xbd, 0x86, 0x7b, 0x5d, 0x39, 0xe6, 0x35, 0xa5, 0xda, 0xd0, 0xc3, 0xca, 0xcd, 0x61, 0xa6, 0x23, - 0x2f, 0x56, 0xd0, 0xed, 0x89, 0xa0, 0x10, 0x38, 0x11, 0xda, 0x1e, 0x54, 0xdc, 0x40, 0xa4, 0xe4, 0x4a, 0xab, 0x66, - 0x8b, 0x64, 0x2c, 0x81, 0x05, 0x17, 0x96, 0x4b, 0x3e, 0x3a, 0x8b, 0x93, 0xa4, 0x2a, 0xfd, 0x43, 0x05, 0xbc, 0x18, - 0xf6, 0x26, 0xd1, 0x2e, 0x30, 0x5a, 0x28, 0x10, 0x5c, 0x6d, 0x84, 0xbd, 0x77, 0xdc, 0x6a, 0xdd, 0x45, 0xc4, 0x91, - 0x9b, 0xd1, 0x08, 0xa8, 0xc7, 0x08, 0xab, 0x66, 0xed, 0xbd, 0x67, 0x18, 0x52, 0x33, 0xf0, 0x41, 0x75, 0x46, 0xc5, - 0x9f, 0x65, 0x4f, 0x7d, 0x26, 0x7a, 0x37, 0xaa, 0xae, 0x66, 0x40, 0x45, 0x05, 0x3e, 0xcc, 0x10, 0x4b, 0x5b, 0x05, - 0x02, 0x72, 0x3d, 0x2c, 0x4a, 0x01, 0x93, 0x34, 0x58, 0x50, 0x0a, 0xac, 0xb5, 0xb2, 0x7b, 0x79, 0x53, 0x30, 0x87, - 0x42, 0xe1, 0xa2, 0xff, 0x93, 0x6c, 0x36, 0x47, 0xcb, 0xac, 0xc1, 0xd4, 0xd0, 0xe0, 0x7d, 0xa3, 0xbe, 0x5c, 0x53, - 0x56, 0xeb, 0x43, 0x3b, 0xb2, 0xc6, 0x4f, 0xda, 0x51, 0x06, 0x87, 0x6a, 0xa1, 0x8b, 0xea, 0x76, 0x73, 0x53, 0xc4, - 0xac, 0xe3, 0x71, 0x9f, 0xf4, 0xb6, 0xb6, 0x26, 0x3d, 0x4d, 0x03, 0x92, 0x49, 0x92, 0xe1, 0x4d, 0x06, 0x28, 0x2b, - 0xe2, 0x2c, 0xcb, 0x06, 0xf9, 0x96, 0x65, 0x89, 0xeb, 0xf7, 0x6d, 0x6f, 0xaf, 0xe6, 0x59, 0x7b, 0x7b, 0x57, 0xbb, - 0xc8, 0x55, 0x9d, 0xf4, 0x20, 0x0f, 0x87, 0x50, 0xb4, 0x62, 0x53, 0x86, 0xcb, 0x59, 0x36, 0x66, 0x81, 0x0d, 0xdd, - 0x53, 0xbb, 0x94, 0x9b, 0x26, 0x81, 0xcd, 0x91, 0x30, 0x67, 0xf9, 0xae, 0x1e, 0x49, 0x0d, 0xf6, 0x80, 0x05, 0xb4, - 0xb9, 0xf0, 0x5d, 0x78, 0x92, 0x64, 0xc7, 0x51, 0x72, 0x20, 0x14, 0x78, 0xad, 0xe5, 0x07, 0x70, 0x19, 0xc9, 0x62, - 0x35, 0x94, 0xd4, 0x77, 0x83, 0xef, 0x82, 0x9b, 0x7b, 0x54, 0xde, 0x8a, 0xdd, 0xf1, 0xdb, 0x7e, 0xc7, 0x56, 0x11, - 0xb1, 0x97, 0xe6, 0x74, 0xa0, 0x71, 0x0a, 0xa0, 0xcc, 0x01, 0x68, 0xb2, 0xc2, 0x9b, 0xb2, 0xf0, 0xe5, 0xe0, 0xa5, - 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, 0x8a, 0x0a, 0x8c, 0x2b, - 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0xf7, 0x31, 0x3c, 0x82, 0x66, 0x1b, 0x1b, 0x4b, 0xe7, 0x55, 0xc4, 0xa7, 0x7e, - 0x1e, 0xa5, 0xe3, 0x6c, 0xe6, 0xb8, 0x9b, 0xb6, 0xed, 0xfa, 0x05, 0x79, 0x22, 0x5f, 0xba, 0xe5, 0xc6, 0x91, 0x37, - 0x62, 0xa1, 0x3d, 0xb0, 0x37, 0x3f, 0x7a, 0x07, 0x2c, 0x3c, 0xda, 0xdd, 0x58, 0x8e, 0x58, 0xd9, 0x3f, 0xf2, 0xce, - 0x75, 0xcc, 0xdd, 0x7b, 0x8b, 0x52, 0x06, 0x7a, 0x85, 0xfd, 0x73, 0x09, 0x06, 0xb0, 0x1b, 0xc5, 0xdf, 0x41, 0xca, - 0xbd, 0xa7, 0x03, 0x11, 0x19, 0xa7, 0xbd, 0xbc, 0xb4, 0x33, 0x8a, 0x18, 0xd8, 0x77, 0xb4, 0xb3, 0x7a, 0xf7, 0x6e, - 0xa5, 0xe6, 0xab, 0x52, 0xf0, 0x3e, 0xc2, 0x9a, 0xa7, 0xee, 0x3d, 0xa7, 0xa3, 0x95, 0xfa, 0x46, 0x1e, 0x33, 0x52, - 0x9a, 0xab, 0x76, 0x82, 0x63, 0x6c, 0xf1, 0xf5, 0xdb, 0xfa, 0x50, 0x44, 0x29, 0xfc, 0x18, 0xac, 0x97, 0x08, 0xd4, - 0x37, 0x38, 0x38, 0xde, 0x41, 0xb8, 0xb5, 0xeb, 0x0c, 0x02, 0xe7, 0x4e, 0xab, 0x75, 0xf9, 0xd3, 0xd6, 0xe1, 0xcf, - 0x51, 0xeb, 0xb7, 0xbd, 0xd6, 0x8f, 0x43, 0xf7, 0xd2, 0xf9, 0x69, 0x6b, 0x70, 0x28, 0xdf, 0x0e, 0x7f, 0xee, 0xff, - 0x54, 0x0c, 0xff, 0x24, 0x0a, 0x37, 0x5c, 0x77, 0xeb, 0xc4, 0x5b, 0xb0, 0x70, 0xab, 0xd5, 0xea, 0xc3, 0xd3, 0x1c, - 0x9e, 0xf0, 0xe7, 0x19, 0xfc, 0xb8, 0x3c, 0xb4, 0xfe, 0xd3, 0x4f, 0xe9, 0xdf, 0xfc, 0x94, 0x0f, 0x71, 0xcc, 0xc3, - 0x9f, 0x7f, 0x2a, 0xec, 0x7b, 0xfd, 0x70, 0x6b, 0xb8, 0xe9, 0x3a, 0xba, 0xe6, 0x4f, 0x61, 0xf5, 0x08, 0xad, 0x0e, - 0x7f, 0x96, 0x6f, 0xf6, 0xbd, 0xa3, 0xdd, 0x7e, 0x38, 0xbc, 0x74, 0xec, 0xcb, 0x7b, 0xee, 0xa5, 0xeb, 0x5e, 0x6e, - 0xe0, 0x3c, 0x27, 0x30, 0xfa, 0x3d, 0xf8, 0x79, 0x0a, 0x3f, 0x6d, 0xf8, 0x39, 0x81, 0x9f, 0x3f, 0x43, 0x37, 0x11, - 0x7f, 0xbb, 0xa4, 0x58, 0xc8, 0x25, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, - 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0xf9, 0x71, 0x03, 0x16, 0x1d, 0x39, 0x67, 0x23, 0x60, 0x9e, 0x88, 0x1c, - 0x14, 0x01, 0x17, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xe3, 0x70, 0x83, 0x39, 0x60, 0x14, 0xbc, 0x66, 0xf8, 0xd0, - 0x75, 0xbd, 0x67, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, 0xed, 0x7a, 0xf3, 0x35, 0x95, - 0xb0, 0xad, 0xd3, 0x13, 0xa8, 0x9b, 0x89, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, 0xb7, 0xe4, 0x2b, 0xe3, 0x10, 0x78, - 0xc5, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xc7, 0x0c, 0x66, 0x58, 0x31, 0x11, 0x39, 0x29, 0x4d, - 0x61, 0xd9, 0xc2, 0xe4, 0x6f, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, 0x64, 0x9b, 0x96, 0xfe, 0x2d, 0xa6, - 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xed, 0x70, 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, - 0x9f, 0xf3, 0x16, 0xd5, 0x18, 0xfc, 0x95, 0x61, 0x06, 0x4f, 0xcc, 0x87, 0x21, 0x9a, 0x65, 0xa9, 0x83, 0x5b, 0x29, - 0x8a, 0xfb, 0x17, 0xb8, 0x33, 0xd2, 0xd2, 0xdb, 0x0f, 0xd5, 0x8e, 0x39, 0xc8, 0x19, 0xfb, 0x2e, 0x4a, 0x3e, 0xb1, - 0xdc, 0x39, 0xf7, 0x3a, 0xdd, 0x2f, 0xa9, 0xb3, 0x87, 0xb6, 0xd9, 0xbb, 0xea, 0x18, 0x4d, 0x99, 0x05, 0xea, 0x88, - 0xb0, 0xd5, 0xf1, 0x72, 0x8c, 0x6a, 0x21, 0x09, 0x0a, 0x2f, 0x0b, 0xbb, 0xc4, 0xe1, 0xf6, 0x6e, 0x71, 0x7a, 0xd2, - 0xb7, 0x03, 0xdb, 0x06, 0x8b, 0xff, 0x80, 0xc2, 0x56, 0xc2, 0xb0, 0x00, 0x83, 0x6c, 0x37, 0xee, 0xf1, 0xcd, 0xcd, - 0x2a, 0xe0, 0x84, 0x07, 0xe9, 0xd4, 0x3d, 0xf1, 0x22, 0x6f, 0x1a, 0xc2, 0x80, 0x23, 0x68, 0x86, 0x5d, 0x7a, 0xa3, - 0xdd, 0x58, 0x4e, 0x83, 0xb1, 0x10, 0x3f, 0x89, 0x0a, 0xfe, 0x02, 0xe3, 0x11, 0xe1, 0x08, 0x8d, 0x7d, 0x9f, 0x9d, - 0xb3, 0x91, 0xb2, 0x33, 0x80, 0x50, 0x91, 0xdb, 0x73, 0x47, 0xa1, 0xd1, 0x0c, 0xe6, 0x0e, 0xc3, 0x83, 0x81, 0x0d, - 0x7b, 0x09, 0x76, 0x65, 0x18, 0x1d, 0x76, 0x86, 0x83, 0x34, 0x5c, 0xb0, 0x40, 0xd3, 0x56, 0x16, 0xcd, 0x6b, 0x45, - 0xdd, 0xe1, 0xc0, 0x99, 0x80, 0x91, 0x0e, 0xb6, 0xb8, 0x83, 0x6f, 0x18, 0xa1, 0x28, 0xc2, 0x77, 0xec, 0xe4, 0xd9, - 0xf9, 0xdc, 0xb1, 0x77, 0xb7, 0xec, 0x4d, 0x2c, 0xf5, 0x6c, 0x60, 0x2f, 0x98, 0x3b, 0x3c, 0x73, 0xcd, 0xce, 0xdb, - 0x43, 0x04, 0x15, 0x0b, 0x71, 0xf2, 0xb3, 0x81, 0xdd, 0x17, 0x53, 0xb7, 0x61, 0xd0, 0x54, 0x2e, 0x3f, 0xae, 0xe8, - 0x01, 0xa1, 0xaa, 0xba, 0x2a, 0xe8, 0xa0, 0xac, 0x1b, 0x38, 0x53, 0x13, 0x89, 0x16, 0x4e, 0x26, 0xa9, 0x00, 0x0e, - 0x0f, 0x36, 0x83, 0x49, 0x8d, 0x6e, 0xdb, 0xc3, 0xc1, 0x59, 0x70, 0xcf, 0xbe, 0xa7, 0x5e, 0x4e, 0x59, 0x70, 0xc2, - 0xc4, 0xf4, 0xa7, 0x20, 0xed, 0xf0, 0xe7, 0x09, 0x03, 0x24, 0xcf, 0xa8, 0x68, 0x21, 0x8b, 0xe6, 0x58, 0x74, 0x10, - 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xe3, 0x90, 0x60, 0xbf, 0x7b, 0x17, 0x96, 0x66, 0xb3, 0x33, 0xc4, - 0xf3, 0x86, 0x9c, 0x17, 0xdf, 0xc5, 0x1c, 0x54, 0xc2, 0x56, 0xdf, 0x76, 0x07, 0xb6, 0x85, 0x4b, 0xdb, 0xcb, 0x36, - 0x43, 0x41, 0xe1, 0x78, 0xf3, 0x80, 0x05, 0xd3, 0x7e, 0xd8, 0x1e, 0x38, 0xb9, 0x50, 0x1d, 0x09, 0x9e, 0x5b, 0x0a, - 0x09, 0xde, 0xf6, 0xa6, 0x20, 0xd0, 0x91, 0x73, 0x37, 0xec, 0x4d, 0x55, 0x08, 0x45, 0x1f, 0x37, 0xc7, 0x6e, 0x10, - 0xc3, 0x0f, 0xa7, 0x85, 0x4c, 0x33, 0xd5, 0x7d, 0xb5, 0x66, 0x76, 0x83, 0xb1, 0xb2, 0xc8, 0x93, 0x30, 0xdb, 0x74, - 0x30, 0x42, 0x0b, 0x92, 0x76, 0x77, 0x00, 0x30, 0x6c, 0x3a, 0x8a, 0xd3, 0xb6, 0x14, 0xab, 0x29, 0xfb, 0xfc, 0x50, - 0x2f, 0xc7, 0x94, 0x0d, 0xa6, 0xcc, 0xaf, 0xb4, 0x0f, 0x80, 0x15, 0x24, 0x5e, 0x3e, 0x54, 0x67, 0x5e, 0xcf, 0x6b, - 0xe7, 0x5b, 0x4b, 0x25, 0x8a, 0x98, 0x67, 0x48, 0x28, 0x5e, 0x6a, 0x37, 0x4c, 0x98, 0xdb, 0x73, 0x24, 0x86, 0x66, - 0xf9, 0xb0, 0x0d, 0x4c, 0xaf, 0x02, 0xec, 0xa9, 0xb9, 0x2d, 0x92, 0xb0, 0x6a, 0xee, 0x1d, 0x02, 0x6b, 0x0f, 0x81, - 0x87, 0x68, 0x1b, 0xf5, 0x54, 0x34, 0x9f, 0x25, 0xe1, 0xf3, 0xc6, 0x71, 0x71, 0x84, 0x27, 0x42, 0xfb, 0xfe, 0x68, - 0x91, 0x83, 0x3c, 0xe0, 0xaf, 0xc1, 0x32, 0x08, 0x65, 0x53, 0x74, 0xf4, 0xf0, 0x08, 0xd8, 0x23, 0xc4, 0x1b, 0x61, - 0x73, 0xa3, 0x1a, 0x2d, 0x4a, 0x32, 0x5e, 0xe8, 0x60, 0xb8, 0xc7, 0xa5, 0x6b, 0x8f, 0x82, 0x41, 0x9e, 0x18, 0x3b, - 0x78, 0xe6, 0xef, 0x8f, 0xb0, 0x1a, 0x27, 0x28, 0xdc, 0x92, 0x76, 0x5b, 0x25, 0xfe, 0xf6, 0xfd, 0x14, 0x24, 0x38, - 0xd6, 0x81, 0x9f, 0x75, 0xf7, 0x6e, 0x22, 0x91, 0xda, 0x4d, 0x7b, 0x74, 0x12, 0x81, 0xf1, 0xe0, 0xdc, 0x4f, 0xa1, - 0x1a, 0x49, 0x44, 0x45, 0x39, 0x5a, 0xa0, 0xe6, 0xa9, 0x5a, 0x05, 0xdf, 0xa1, 0x19, 0x81, 0xe7, 0x18, 0xb6, 0x26, - 0x3f, 0x55, 0x37, 0x16, 0xb1, 0x7c, 0xd7, 0xa5, 0xa3, 0x2d, 0x3c, 0x80, 0x14, 0x8c, 0x26, 0x18, 0xc6, 0xa5, 0xa0, - 0x64, 0xc5, 0x7f, 0x1f, 0x8d, 0x58, 0xf9, 0xf4, 0x30, 0xdb, 0xdc, 0x1c, 0x8a, 0x73, 0x0b, 0x62, 0x1c, 0x6e, 0x44, - 0x57, 0xe3, 0x0a, 0x80, 0xfa, 0x74, 0x4e, 0x5c, 0x0f, 0x4c, 0x2b, 0xd6, 0x74, 0x29, 0xf6, 0xc9, 0x61, 0x06, 0xa0, - 0xe0, 0x96, 0x73, 0xe8, 0x0f, 0xfe, 0x3c, 0x04, 0xf7, 0xd8, 0xff, 0x93, 0xbb, 0xa5, 0x04, 0x4d, 0x4f, 0x9e, 0x29, - 0x2e, 0xe9, 0x8c, 0xb5, 0xe3, 0x51, 0x6c, 0x34, 0x28, 0xbc, 0x14, 0x30, 0x00, 0x6d, 0x0e, 0x32, 0xa1, 0xe2, 0x20, - 0xe4, 0xa8, 0xc0, 0xf6, 0x71, 0xf3, 0x73, 0xdc, 0xd9, 0x4f, 0xc1, 0xc2, 0x1b, 0xe8, 0xb7, 0x97, 0xf0, 0xf6, 0x67, - 0xfd, 0xf6, 0x0b, 0x0b, 0x7e, 0x29, 0x65, 0xe8, 0xbe, 0x36, 0xc5, 0x03, 0x35, 0x45, 0x29, 0x96, 0xc8, 0xa0, 0x21, - 0x73, 0xf3, 0x95, 0x98, 0x0d, 0x77, 0x4b, 0x20, 0x86, 0x12, 0x5d, 0xb9, 0xcf, 0xa3, 0x13, 0x24, 0xae, 0x6b, 0x92, - 0xc2, 0xc8, 0x25, 0x30, 0x11, 0xae, 0xf8, 0x96, 0x98, 0xb3, 0xdf, 0x06, 0x1b, 0xbc, 0x96, 0x77, 0x80, 0xf6, 0x1d, - 0x9b, 0xcd, 0xf9, 0xc5, 0x3e, 0x29, 0xfa, 0x40, 0xa6, 0x0d, 0x88, 0xb3, 0xf3, 0x76, 0x2f, 0xde, 0xe5, 0xbd, 0x18, - 0xa4, 0x7a, 0xae, 0x58, 0x0c, 0xf7, 0xaa, 0xf7, 0x16, 0xa3, 0x94, 0x26, 0x33, 0x79, 0x35, 0xf4, 0xba, 0x12, 0xbd, - 0xcd, 0x4d, 0x40, 0xb0, 0x67, 0x74, 0xe5, 0xa2, 0x6b, 0x59, 0x0a, 0x9a, 0x00, 0x44, 0x8f, 0xea, 0x2c, 0x47, 0x1c, - 0x87, 0xd9, 0x6c, 0x50, 0x3c, 0x62, 0xee, 0xda, 0x51, 0x71, 0x4c, 0xec, 0x2e, 0x13, 0x76, 0x00, 0x33, 0xe2, 0xf2, - 0x56, 0x47, 0x44, 0x87, 0x45, 0x7f, 0x1d, 0xdf, 0xfe, 0xe8, 0xb1, 0xcd, 0x8e, 0x0b, 0x1a, 0xa4, 0x36, 0xd6, 0xc3, - 0x6a, 0x2c, 0xa8, 0x0f, 0x3f, 0x6a, 0x2a, 0x95, 0xc5, 0xe6, 0x66, 0x59, 0x3f, 0xaa, 0x55, 0x3b, 0xb8, 0x76, 0x9a, - 0x72, 0xde, 0xcc, 0x06, 0xe1, 0x40, 0xc4, 0x04, 0x0a, 0xb4, 0xb4, 0xb2, 0x62, 0x80, 0x21, 0x65, 0x39, 0xca, 0xa7, - 0x90, 0x79, 0x71, 0x59, 0xea, 0xd4, 0x17, 0x19, 0x8f, 0x0c, 0xf1, 0xd4, 0x93, 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, - 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x33, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, - 0x0c, 0xda, 0xfe, 0x49, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x87, 0x01, 0xd5, 0x2f, 0xa4, 0x04, 0x9b, - 0x86, 0xef, 0x81, 0x8d, 0x2a, 0xc7, 0x93, 0x04, 0xe1, 0xd3, 0x38, 0x67, 0xe4, 0x29, 0x6c, 0x48, 0x98, 0xa5, 0x69, - 0x1b, 0xa9, 0x76, 0x91, 0x19, 0x84, 0x72, 0x51, 0xf0, 0x1a, 0x67, 0x17, 0x59, 0xb8, 0xd2, 0x1a, 0xcc, 0x8f, 0x37, - 0x26, 0x40, 0xd9, 0xe5, 0x65, 0x26, 0x7c, 0xdc, 0x88, 0xec, 0x0d, 0x5d, 0x31, 0x1d, 0x28, 0xa4, 0x02, 0x27, 0x22, - 0x8b, 0x87, 0xce, 0x50, 0x68, 0x84, 0x03, 0x3a, 0x45, 0xce, 0x5d, 0x63, 0xd3, 0xe7, 0x03, 0xed, 0x1b, 0xa5, 0xa1, - 0x93, 0x80, 0x10, 0x10, 0xb8, 0x1b, 0xd6, 0x54, 0x3a, 0x48, 0x83, 0x84, 0x4a, 0xd1, 0xcf, 0x01, 0xfc, 0xc3, 0x48, - 0x52, 0x00, 0xec, 0x87, 0x6a, 0xa4, 0x88, 0xb2, 0x2c, 0x70, 0x01, 0x68, 0xae, 0x7d, 0x5c, 0x09, 0x5f, 0x18, 0xa8, - 0x30, 0x3d, 0xcd, 0xca, 0x4b, 0xa1, 0x44, 0x1e, 0xaf, 0x49, 0x59, 0x23, 0x99, 0x7c, 0x8a, 0x0e, 0x9f, 0xf2, 0xae, - 0x5f, 0x4b, 0x3c, 0x74, 0xc1, 0x53, 0x58, 0x56, 0xf5, 0xfc, 0x2a, 0xe4, 0xe4, 0x5c, 0x83, 0xae, 0x90, 0x42, 0x7f, - 0xc5, 0x49, 0xde, 0x7b, 0xe5, 0x57, 0xb5, 0xd4, 0x18, 0xca, 0xde, 0xaf, 0x6b, 0x86, 0xe5, 0xe5, 0xbc, 0x0a, 0x53, - 0x10, 0x70, 0x4b, 0x96, 0x04, 0x4b, 0xa9, 0x21, 0xc0, 0xc2, 0xf6, 0x48, 0x2b, 0x05, 0x79, 0xa9, 0xc3, 0x3b, 0x4f, - 0xc1, 0x0a, 0x30, 0x0e, 0xb5, 0x54, 0x32, 0x8d, 0x24, 0xbe, 0x54, 0xa2, 0xc0, 0x94, 0xfb, 0x23, 0xf0, 0x53, 0x9b, - 0x27, 0x5d, 0xe7, 0xae, 0x1f, 0xcf, 0x30, 0xb5, 0x87, 0x40, 0x8f, 0xbd, 0x3b, 0x60, 0x4a, 0xd4, 0x75, 0x58, 0x41, - 0x1c, 0x9a, 0xd5, 0x34, 0x0b, 0x98, 0x31, 0x6d, 0xd0, 0x92, 0x6d, 0xb0, 0xe5, 0x72, 0xb0, 0x8f, 0xc4, 0xf6, 0xac, - 0x56, 0x40, 0xe8, 0x1a, 0x34, 0x30, 0xe4, 0x2e, 0x15, 0x5a, 0x98, 0xf7, 0xba, 0x54, 0x84, 0xfb, 0x73, 0xc0, 0xa5, - 0x15, 0x9c, 0x79, 0x19, 0x0d, 0xbc, 0x1f, 0x1f, 0x27, 0x98, 0xf8, 0x82, 0x58, 0x81, 0x1d, 0x1c, 0x74, 0x9a, 0x4d, - 0x81, 0x53, 0x71, 0x91, 0x32, 0x58, 0x56, 0x94, 0xda, 0xf0, 0x43, 0x8a, 0x6c, 0xdd, 0xe5, 0x81, 0xee, 0x42, 0x2c, - 0x80, 0x9d, 0x7e, 0xc3, 0xc8, 0xb7, 0xac, 0x97, 0x01, 0x83, 0x53, 0xad, 0x71, 0x10, 0xf8, 0xcd, 0xcd, 0x64, 0x58, - 0xa6, 0xc4, 0x76, 0x4d, 0x56, 0x17, 0x90, 0xc3, 0x50, 0x4d, 0xdc, 0x41, 0x58, 0x2a, 0x7b, 0xbc, 0x28, 0x67, 0xb8, - 0x5c, 0xca, 0x42, 0x6e, 0x9e, 0x57, 0xd3, 0x7c, 0x6e, 0xa5, 0xd9, 0x74, 0xbc, 0x15, 0x5f, 0x14, 0xfc, 0x03, 0x27, - 0x96, 0x56, 0x3d, 0xa5, 0x56, 0x78, 0x94, 0xb9, 0x25, 0xeb, 0x94, 0xd4, 0xea, 0xba, 0x81, 0x6a, 0x84, 0xa7, 0x69, - 0xd8, 0x08, 0x84, 0x98, 0xe0, 0xe2, 0xd7, 0x4d, 0x26, 0xa6, 0xbd, 0x25, 0xa4, 0x8e, 0xb0, 0x7b, 0x28, 0x27, 0xb8, - 0xab, 0x79, 0xf6, 0x79, 0x38, 0xbf, 0x9a, 0xb9, 0xf7, 0x0c, 0xe6, 0x7e, 0x1c, 0x72, 0x83, 0xd1, 0x63, 0x99, 0xf0, - 0x23, 0x63, 0x1f, 0xb9, 0xaa, 0x7a, 0x72, 0x12, 0x56, 0x22, 0x4b, 0x3c, 0x19, 0x47, 0x1d, 0xc6, 0xa9, 0x68, 0x4d, - 0x90, 0x5d, 0x5e, 0x16, 0xe6, 0x5e, 0xa0, 0xa0, 0xa9, 0xc7, 0xeb, 0x71, 0xda, 0x8a, 0x9d, 0x8d, 0x48, 0xe4, 0xde, - 0xab, 0x5a, 0x24, 0xb2, 0xe2, 0x73, 0x1c, 0xe9, 0x8a, 0x83, 0xdc, 0x27, 0x27, 0xab, 0x9b, 0x54, 0xe8, 0x16, 0x8d, - 0xb6, 0xb1, 0x47, 0xf5, 0x81, 0xa4, 0x9e, 0x51, 0x81, 0x55, 0x8d, 0x7d, 0xf7, 0x6e, 0x47, 0xa4, 0x5b, 0x2a, 0xc5, - 0x06, 0x4b, 0x0b, 0xa3, 0x19, 0xa3, 0x60, 0x50, 0x52, 0x64, 0xa0, 0x46, 0xf9, 0x15, 0x82, 0x61, 0x8f, 0x1a, 0x80, - 0xe2, 0x5c, 0x5f, 0xfd, 0xb8, 0x94, 0x6c, 0x21, 0x20, 0x71, 0x97, 0x0c, 0xc4, 0x9a, 0x60, 0x66, 0xe4, 0x93, 0xf7, - 0xc0, 0x79, 0x03, 0x86, 0x0e, 0x01, 0xf8, 0x05, 0x62, 0xd3, 0x83, 0x89, 0x6d, 0x13, 0x51, 0xf4, 0xd9, 0xc0, 0x73, - 0x00, 0x76, 0x5e, 0x85, 0x46, 0xdf, 0x55, 0x29, 0x60, 0xc8, 0x06, 0x6e, 0xc0, 0xaa, 0xb0, 0xdc, 0xde, 0x73, 0x70, - 0x1b, 0xe0, 0xf5, 0x99, 0x6c, 0xbe, 0x81, 0x79, 0x82, 0xd5, 0xd9, 0x85, 0x5f, 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, - 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x39, 0x46, 0x58, 0xc4, 0xfb, 0x2b, 0x7c, 0xd7, 0xe3, 0x96, 0x7b, - 0x1a, 0x2d, 0xc2, 0x74, 0x95, 0x34, 0x06, 0x25, 0xeb, 0x7e, 0x32, 0xe2, 0x5e, 0xee, 0x8b, 0x58, 0x70, 0x85, 0x23, - 0xab, 0x42, 0x8a, 0x0d, 0x24, 0xe9, 0x69, 0x8f, 0x0e, 0xd8, 0x37, 0x9a, 0xbd, 0x80, 0x32, 0xef, 0x2b, 0x52, 0x49, - 0x48, 0x69, 0x76, 0x43, 0x24, 0x09, 0x6b, 0x45, 0x9e, 0x3a, 0xef, 0x3b, 0xda, 0xe7, 0x56, 0x12, 0xc1, 0x08, 0x4e, - 0xc2, 0x74, 0xac, 0x3c, 0x68, 0x0a, 0x70, 0x15, 0x1d, 0x31, 0x7d, 0x13, 0x90, 0xdf, 0x0c, 0xe4, 0xf6, 0x4a, 0x72, - 0x6d, 0xae, 0x61, 0x78, 0x82, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x8d, 0x09, 0xc9, 0xeb, 0x3c, 0x0f, 0x30, 0xe1, - 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x56, 0x02, 0xdd, 0x80, 0xe5, 0xfa, 0x38, 0x35, 0x2a, 0x12, 0x17, - 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x33, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, 0xa9, 0x8f, 0x99, 0x23, 0x64, - 0xae, 0xb0, 0x3e, 0xe7, 0x4e, 0x6d, 0xea, 0x1e, 0xa3, 0x6e, 0x9e, 0xa4, 0x16, 0xaf, 0xd3, 0xa6, 0x94, 0x88, 0x49, - 0x89, 0x39, 0x13, 0xa9, 0xd8, 0x4c, 0x89, 0x3b, 0xb7, 0xbe, 0xd1, 0x42, 0xda, 0x68, 0x33, 0x91, 0x83, 0xcd, 0x2a, - 0x79, 0x4f, 0x60, 0x3c, 0x17, 0x84, 0x2f, 0x91, 0xb1, 0x96, 0x63, 0xe6, 0x98, 0x08, 0x56, 0x2f, 0xa6, 0x22, 0x7f, - 0xe7, 0xe8, 0x34, 0x7b, 0x83, 0x1e, 0xa4, 0xde, 0x40, 0x62, 0xd6, 0xc4, 0x77, 0x21, 0x0d, 0x75, 0x84, 0x40, 0x65, - 0x54, 0xcb, 0x74, 0x9c, 0x58, 0x85, 0x6f, 0x04, 0x5f, 0xbd, 0xd5, 0xc7, 0xf9, 0xc6, 0x73, 0x63, 0x35, 0x82, 0x18, - 0xbc, 0x85, 0x7c, 0xe8, 0x49, 0x11, 0x0e, 0x84, 0xcb, 0x37, 0x37, 0x7b, 0xf9, 0x2e, 0xaf, 0x42, 0x24, 0x15, 0x8c, - 0x31, 0x66, 0x14, 0xe3, 0x9e, 0xa8, 0xa9, 0xc5, 0x1c, 0x06, 0x96, 0xad, 0xc3, 0x1c, 0x0f, 0x00, 0xa0, 0xa5, 0x29, - 0xbd, 0x6a, 0x2a, 0x54, 0x9e, 0xe7, 0x12, 0x3e, 0xd5, 0x21, 0xaa, 0x6a, 0xfc, 0x76, 0x7d, 0x06, 0x0a, 0xc1, 0x7d, - 0xa7, 0xe3, 0xe1, 0x21, 0x04, 0xac, 0xa2, 0x90, 0x05, 0x7a, 0x83, 0xf6, 0xaa, 0x44, 0x28, 0x66, 0x4e, 0xd6, 0x63, - 0x86, 0x93, 0x0a, 0xb6, 0x50, 0x09, 0x4b, 0xa5, 0x05, 0x7e, 0xb5, 0x11, 0x9a, 0xa7, 0x8c, 0x7b, 0xaf, 0x2a, 0x9c, - 0x41, 0x7f, 0x30, 0x6f, 0x95, 0x51, 0xdf, 0xae, 0x9c, 0xc8, 0x54, 0x60, 0xe2, 0x66, 0x96, 0xda, 0xef, 0x97, 0x75, - 0xda, 0xcf, 0x2b, 0xe4, 0x3e, 0x27, 0xcd, 0xd7, 0xb9, 0x85, 0xe6, 0x93, 0xe1, 0x7e, 0xa5, 0xfc, 0xd0, 0xc2, 0xa8, - 0x29, 0xbf, 0xbc, 0xae, 0xfc, 0x0a, 0x4f, 0x85, 0xb7, 0xfa, 0x5d, 0x14, 0xba, 0xa8, 0xcf, 0xc1, 0x10, 0xd2, 0x8f, - 0xe0, 0x1a, 0x1a, 0x3c, 0x28, 0x92, 0xc5, 0x62, 0xed, 0x82, 0xb8, 0x3e, 0xe6, 0x54, 0x3b, 0x94, 0x31, 0x46, 0x3c, - 0x2d, 0x39, 0x48, 0x32, 0x38, 0x18, 0xbf, 0x81, 0x01, 0x31, 0x29, 0x09, 0xe9, 0x10, 0x3a, 0x6b, 0x33, 0x11, 0x95, - 0xbb, 0x78, 0xb3, 0x71, 0x59, 0x53, 0x28, 0xc2, 0x4e, 0x30, 0x53, 0x29, 0x15, 0x04, 0xd2, 0xe4, 0xbb, 0xd3, 0xa9, - 0x05, 0x43, 0x0b, 0xd7, 0x54, 0x40, 0x5e, 0xdb, 0xf5, 0xa0, 0xc9, 0x7b, 0x8a, 0xa1, 0xaf, 0x53, 0x23, 0x5e, 0x66, - 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x26, 0x62, 0xaf, 0xe0, 0x13, 0x21, 0x9b, 0x82, 0x9d, 0x09, 0xf4, - 0x43, 0xbb, 0xb2, 0x97, 0xee, 0x16, 0x95, 0x4b, 0x8b, 0xc6, 0x56, 0xa2, 0x66, 0xcd, 0x0f, 0xe3, 0xcd, 0x14, 0xf6, - 0xb3, 0x47, 0x09, 0x04, 0xa4, 0xa9, 0x9c, 0xa4, 0x9a, 0xf7, 0x30, 0x1d, 0x02, 0x48, 0xb0, 0xfb, 0x09, 0x2c, 0xf4, - 0x9b, 0x12, 0x13, 0x2c, 0xaa, 0xc6, 0x6e, 0x73, 0xd0, 0x9a, 0x73, 0xd2, 0x7c, 0x73, 0xd4, 0xda, 0x9b, 0xca, 0x7a, - 0xc6, 0xec, 0x00, 0xdb, 0x76, 0x37, 0x8b, 0xc3, 0x74, 0xb3, 0x33, 0x34, 0x04, 0x17, 0x1e, 0xff, 0x27, 0x25, 0xa6, - 0x81, 0xe4, 0x52, 0x37, 0x7e, 0x42, 0x1d, 0x86, 0xff, 0x2d, 0x49, 0x01, 0x0f, 0x6a, 0xab, 0xb1, 0xe2, 0xdc, 0x2b, - 0x8e, 0x92, 0xcb, 0xaa, 0xda, 0xd5, 0x12, 0x34, 0x74, 0x23, 0x19, 0x13, 0xc5, 0x3c, 0x27, 0x00, 0x46, 0xb1, 0xf9, - 0x53, 0xa6, 0x93, 0xbc, 0x7f, 0x59, 0x9b, 0xda, 0xed, 0xfb, 0x7e, 0x94, 0x9f, 0xd0, 0x91, 0x8a, 0xca, 0xe6, 0x24, - 0xe6, 0xdf, 0x16, 0x60, 0x9a, 0x13, 0x1f, 0xea, 0xb9, 0x86, 0xa1, 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0x97, 0xbf, - 0x77, 0xb6, 0xfb, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0xb9, 0x02, 0x5f, 0xc0, 0x32, 0xb8, 0x25, 0xfd, 0xf4, 0xa6, - 0xbf, 0x0a, 0x3e, 0x63, 0xff, 0x0b, 0x40, 0xab, 0x02, 0x03, 0xca, 0x9d, 0xa6, 0x61, 0x25, 0xc4, 0x25, 0x2a, 0xcc, - 0x2a, 0xce, 0x1f, 0xd7, 0x79, 0xdd, 0xb4, 0x2c, 0x31, 0x28, 0x3f, 0x77, 0x0d, 0x37, 0xbe, 0xd7, 0xc8, 0x1f, 0xdf, - 0x7b, 0x0e, 0xba, 0x9d, 0x48, 0x7b, 0xf7, 0x6e, 0x7e, 0x87, 0x2c, 0x34, 0xbc, 0x17, 0x36, 0x87, 0xb6, 0x48, 0x97, - 0x5c, 0x3d, 0x63, 0x31, 0xde, 0x16, 0xa1, 0x32, 0x7c, 0xc0, 0x82, 0x39, 0x60, 0x08, 0x1e, 0x3b, 0x95, 0xc9, 0x67, - 0xd8, 0x68, 0x8a, 0x5d, 0x73, 0x61, 0xf0, 0x81, 0xaa, 0x2c, 0x24, 0x2f, 0xd6, 0xc9, 0xf6, 0xec, 0x14, 0x9e, 0x5f, - 0xc6, 0x05, 0x50, 0x07, 0xd0, 0xaf, 0xa8, 0x2c, 0x36, 0x90, 0x8b, 0x9b, 0xb2, 0xd6, 0x2b, 0x1a, 0x8f, 0xaf, 0xed, - 0xc2, 0xea, 0x0a, 0x7c, 0x1a, 0xa5, 0xe3, 0x44, 0x4c, 0x62, 0x26, 0x55, 0xae, 0xc9, 0xb5, 0xd1, 0xbd, 0xb4, 0x45, - 0xf3, 0x5c, 0x48, 0xf0, 0x8a, 0xc0, 0x0d, 0xa1, 0xaf, 0xf4, 0xe5, 0x7a, 0x03, 0x05, 0x8f, 0xda, 0x9b, 0x8b, 0x60, - 0x62, 0xe2, 0x31, 0x43, 0x6a, 0xfa, 0x75, 0x38, 0x15, 0xdf, 0xfc, 0xb6, 0xe2, 0xf0, 0xeb, 0x9c, 0xb1, 0x86, 0x02, - 0x20, 0x3e, 0x79, 0x70, 0xb5, 0x9b, 0xf4, 0x4a, 0x69, 0x07, 0xa5, 0x11, 0xe2, 0xdb, 0x0a, 0x5f, 0x77, 0xa9, 0xf8, - 0xca, 0x55, 0xf7, 0xbe, 0x8e, 0x99, 0x71, 0xc1, 0xe8, 0x39, 0x9f, 0x25, 0x8d, 0x6b, 0x37, 0x74, 0x57, 0xe7, 0x47, - 0xef, 0x07, 0x99, 0xb7, 0x70, 0x0c, 0x6c, 0x72, 0xcc, 0x9c, 0xe7, 0xde, 0x6b, 0xe3, 0x44, 0xf9, 0x5b, 0xf3, 0x88, - 0x57, 0x0e, 0xb3, 0xee, 0x24, 0xf9, 0xdb, 0xc1, 0xb7, 0xc1, 0xd5, 0x2d, 0x8d, 0x13, 0xe4, 0xae, 0x3a, 0x41, 0x26, - 0xca, 0xcd, 0xf4, 0x86, 0xdb, 0xbb, 0xad, 0x40, 0x10, 0xa7, 0x62, 0xfa, 0xa8, 0x1c, 0xd7, 0x8f, 0x16, 0xa8, 0x54, - 0x44, 0x7c, 0xaa, 0x72, 0x57, 0xae, 0x4c, 0x0d, 0xf5, 0xb8, 0x4e, 0x66, 0xa1, 0x69, 0xd6, 0xe4, 0x52, 0x36, 0x3d, - 0x46, 0xa6, 0xd9, 0xa9, 0x36, 0xbf, 0x7b, 0xe5, 0x21, 0x1d, 0x43, 0x73, 0xb1, 0x56, 0x0b, 0xee, 0x77, 0x15, 0x85, - 0x77, 0xbd, 0xd8, 0x48, 0x65, 0xa8, 0x59, 0x8f, 0xa2, 0x8f, 0xe3, 0x36, 0x73, 0x79, 0x94, 0xfd, 0x59, 0x03, 0xc0, - 0x74, 0x84, 0x45, 0x77, 0xd3, 0x33, 0xf6, 0x04, 0x7a, 0x7a, 0x22, 0x83, 0x44, 0xaf, 0x74, 0xbe, 0x6a, 0x95, 0x58, - 0xba, 0x86, 0xc0, 0xee, 0x35, 0x19, 0xab, 0x92, 0x76, 0xab, 0xf5, 0xab, 0x79, 0x3e, 0x4f, 0xf9, 0x4a, 0x9e, 0x4f, - 0xcd, 0xa2, 0xbb, 0xd3, 0x76, 0xaf, 0x4f, 0x0d, 0x15, 0x73, 0xad, 0x6f, 0xf2, 0x3b, 0xa6, 0xeb, 0x60, 0xa8, 0x45, - 0x90, 0x59, 0xed, 0xaa, 0x67, 0x65, 0x39, 0xab, 0x67, 0x72, 0xcc, 0x84, 0x6f, 0x2a, 0xdd, 0x21, 0xba, 0x61, 0xaa, - 0x66, 0xfa, 0xb1, 0xb1, 0x2d, 0x64, 0x9b, 0xe7, 0x17, 0xe3, 0x1c, 0x28, 0x2d, 0xf7, 0x97, 0x09, 0xc3, 0x8f, 0x97, - 0x97, 0x3f, 0x0a, 0x39, 0x55, 0x75, 0xf4, 0x96, 0x2f, 0x75, 0xcf, 0x60, 0x56, 0x2a, 0x27, 0xe2, 0x23, 0x5b, 0x3f, - 0x78, 0x73, 0xf7, 0x0a, 0x58, 0x3e, 0x02, 0x76, 0x1f, 0x99, 0xd3, 0x18, 0xaa, 0xda, 0xc0, 0x3f, 0xac, 0x1f, 0x6c, - 0xdd, 0x1e, 0xfe, 0x61, 0xf0, 0x43, 0x70, 0x6d, 0x63, 0x63, 0x1b, 0x6f, 0xd7, 0x12, 0x41, 0x5e, 0xe1, 0x81, 0x3e, - 0x5e, 0x7d, 0x14, 0xb4, 0x5c, 0x27, 0xb6, 0x07, 0x0e, 0x85, 0xad, 0x41, 0xbe, 0x49, 0x99, 0x34, 0x5a, 0x14, 0x3c, - 0x9b, 0xc9, 0x19, 0x0a, 0x79, 0xcd, 0xc7, 0x41, 0xdb, 0x11, 0xfe, 0x06, 0x4e, 0xed, 0x78, 0x79, 0xf9, 0x09, 0xfa, - 0x80, 0xa7, 0x2b, 0xa5, 0xa9, 0x88, 0x53, 0xca, 0x2d, 0xba, 0x5a, 0xe7, 0xc1, 0x48, 0x71, 0x31, 0x45, 0xa5, 0xe3, - 0x2e, 0xaf, 0x9d, 0x8d, 0x9c, 0xfe, 0x12, 0xaf, 0x2e, 0xd2, 0xe5, 0x23, 0x91, 0xad, 0x5a, 0x7a, 0x2f, 0xf4, 0xe9, - 0xb6, 0x3d, 0x63, 0x7c, 0x9a, 0x8d, 0xe9, 0x60, 0xc6, 0xc7, 0x89, 0xf0, 0xfa, 0xc4, 0x58, 0xdf, 0x2d, 0x02, 0xd3, - 0xcd, 0xb1, 0xc9, 0x0f, 0xc7, 0xeb, 0xcd, 0x66, 0x8d, 0x3b, 0x78, 0xe3, 0x3c, 0x71, 0x96, 0x25, 0x46, 0x54, 0x96, - 0x1a, 0x1e, 0xd0, 0x0a, 0x71, 0xf3, 0x9e, 0x09, 0x8c, 0xcb, 0x2e, 0x48, 0x6a, 0xbb, 0x81, 0xc0, 0xc5, 0x9e, 0xc4, - 0x2c, 0x19, 0xdb, 0x1e, 0x94, 0x07, 0xfa, 0x62, 0x34, 0xdd, 0x02, 0xa6, 0xe5, 0xb5, 0xb3, 0xb3, 0xd4, 0xf6, 0xaa, - 0xa9, 0x02, 0x98, 0x25, 0xcb, 0xe3, 0x13, 0x64, 0xdd, 0x6f, 0xa0, 0x8b, 0x18, 0x30, 0x36, 0xae, 0xcc, 0xb9, 0xcb, - 0x75, 0x2b, 0xe2, 0x1b, 0x4d, 0xa4, 0x49, 0x7d, 0x48, 0x7d, 0x87, 0x61, 0xad, 0xae, 0x72, 0x90, 0xc0, 0x3d, 0xf2, - 0x6e, 0x89, 0x4b, 0x4f, 0x9f, 0x59, 0x4c, 0xaa, 0xf4, 0x2d, 0x75, 0x2d, 0xae, 0x19, 0xf6, 0x8a, 0x07, 0x60, 0x7f, - 0x60, 0xdc, 0x22, 0x16, 0xf1, 0x76, 0x5e, 0x4b, 0x61, 0x6d, 0xcc, 0x81, 0xe6, 0x86, 0x1b, 0xbc, 0x60, 0xd5, 0x9a, - 0x81, 0x19, 0x66, 0x9c, 0x91, 0xfc, 0x66, 0xdc, 0xab, 0x9a, 0x38, 0x72, 0x15, 0x40, 0xf4, 0x2d, 0xe9, 0x92, 0x1c, - 0x5e, 0xc9, 0x72, 0xd5, 0x19, 0xf2, 0xaf, 0xb0, 0xce, 0x7a, 0x71, 0x02, 0x66, 0xd2, 0x94, 0x97, 0x98, 0x98, 0x22, - 0x2e, 0x37, 0xcb, 0x98, 0xa7, 0xe9, 0xb3, 0x68, 0x07, 0x27, 0x37, 0x12, 0x38, 0x62, 0xdf, 0x58, 0x86, 0x66, 0xc2, - 0x46, 0x4c, 0xa4, 0x51, 0x29, 0x25, 0x7c, 0x20, 0x97, 0x5a, 0xf2, 0x97, 0xb9, 0xbc, 0xfa, 0x72, 0x9b, 0xe0, 0x80, - 0xbc, 0x06, 0x96, 0x43, 0xe3, 0xb8, 0x65, 0x20, 0x11, 0x8b, 0x01, 0x31, 0x6a, 0x55, 0xae, 0x26, 0xa3, 0x3a, 0x99, - 0xaf, 0x90, 0x0b, 0x15, 0x79, 0x70, 0x4b, 0xa0, 0xe4, 0xcf, 0x31, 0x75, 0x30, 0x2b, 0xb5, 0x9b, 0x16, 0x9b, 0x24, - 0xef, 0x99, 0x01, 0xc9, 0xf5, 0xd7, 0xf0, 0xd0, 0xf8, 0xc5, 0x2b, 0x73, 0x4a, 0xf8, 0xa2, 0x8c, 0xa5, 0xa5, 0x31, - 0x97, 0xfe, 0x83, 0xbc, 0x4f, 0x2b, 0x01, 0xfb, 0x15, 0xc4, 0x94, 0x81, 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, - 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x2b, 0x26, 0x5d, 0xa5, 0xb2, 0xae, 0xb0, 0xea, 0x7e, 0x5d, 0xb0, 0xfc, 0x62, 0x9f, - 0x61, 0x6e, 0x32, 0x1a, 0x64, 0x2b, 0x66, 0x36, 0xe5, 0x57, 0x7b, 0xd7, 0x7e, 0xe5, 0xa1, 0xa4, 0x43, 0xb5, 0x4a, - 0x37, 0xaf, 0xdc, 0x70, 0x8c, 0x1b, 0x37, 0x1c, 0x01, 0x6c, 0x0c, 0x3b, 0x55, 0xa4, 0xd6, 0xf9, 0xef, 0xab, 0xe1, - 0x27, 0xda, 0x6b, 0x43, 0xbd, 0xeb, 0x86, 0x6b, 0xd3, 0xd3, 0xaf, 0x41, 0xd5, 0xc8, 0x12, 0xba, 0x0e, 0x55, 0x4c, - 0x46, 0xa2, 0xc4, 0x74, 0x95, 0xf2, 0xa8, 0xaf, 0x11, 0xe7, 0x20, 0x6e, 0x28, 0x7f, 0xf1, 0x2f, 0xe1, 0xc5, 0x51, - 0x80, 0x46, 0xd4, 0x72, 0x92, 0xa5, 0xbc, 0x35, 0x89, 0x66, 0x71, 0x72, 0x11, 0x2c, 0xe2, 0xd6, 0x2c, 0x4b, 0xb3, - 0x62, 0x0e, 0x5c, 0xe9, 0x15, 0x17, 0x60, 0xc3, 0xcf, 0x5a, 0x8b, 0xd8, 0x7b, 0xce, 0x92, 0x53, 0xc6, 0xe3, 0x51, - 0xe4, 0xd9, 0x7b, 0x39, 0x88, 0x07, 0xeb, 0x75, 0x94, 0xe7, 0xd9, 0x99, 0xed, 0xbd, 0xcb, 0x8e, 0x81, 0x69, 0xbd, - 0x37, 0xe7, 0x17, 0x27, 0x2c, 0xf5, 0xde, 0x1f, 0x2f, 0x52, 0xbe, 0xf0, 0x8a, 0x28, 0x2d, 0x5a, 0x05, 0xcb, 0xe3, - 0x09, 0xa8, 0x89, 0x24, 0xcb, 0x5b, 0x98, 0xff, 0x3c, 0x63, 0x41, 0x12, 0x9f, 0x4c, 0xb9, 0x35, 0x8e, 0xf2, 0x4f, - 0xbd, 0x56, 0x6b, 0x9e, 0xc7, 0xb3, 0x28, 0xbf, 0x68, 0x51, 0x8b, 0xe0, 0x8b, 0xf6, 0x76, 0xf4, 0xe5, 0xe4, 0x7e, - 0x8f, 0xe7, 0xd0, 0x37, 0x46, 0x2a, 0x06, 0x20, 0x7c, 0xac, 0xed, 0x9d, 0xf6, 0xac, 0xb8, 0x23, 0x4e, 0x94, 0xa2, - 0x94, 0x97, 0x47, 0xde, 0x19, 0x03, 0xb8, 0xfd, 0x63, 0x9e, 0x7a, 0xe0, 0xcb, 0xf1, 0x2c, 0x5d, 0x8e, 0x16, 0x79, - 0x01, 0x03, 0xcc, 0xb3, 0x38, 0xe5, 0x2c, 0xef, 0x1d, 0x67, 0x39, 0x90, 0xad, 0x95, 0x47, 0xe3, 0x78, 0x51, 0x04, - 0xf7, 0xe7, 0xe7, 0x3d, 0xb4, 0x15, 0x4e, 0xf2, 0x6c, 0x91, 0x8e, 0xe5, 0x5c, 0x71, 0x0a, 0x1b, 0x23, 0xe6, 0x66, - 0x05, 0x7d, 0x09, 0x05, 0xe0, 0x4b, 0x59, 0x94, 0xb7, 0x4e, 0xb0, 0x33, 0x1a, 0xfa, 0xed, 0x31, 0x3b, 0xf1, 0xf2, - 0x93, 0xe3, 0xc8, 0xe9, 0x74, 0x1f, 0x7a, 0xea, 0x9f, 0xbf, 0xe3, 0x82, 0xe1, 0xbe, 0xb6, 0xb8, 0xd3, 0x6e, 0xff, - 0xad, 0xdb, 0x6b, 0xcc, 0x42, 0x00, 0x05, 0x9d, 0xf9, 0xb9, 0x55, 0x64, 0x09, 0xac, 0xcf, 0xba, 0x9e, 0xbd, 0x39, - 0xf8, 0x4d, 0x71, 0x7a, 0x12, 0x74, 0xe7, 0xe7, 0x25, 0x62, 0x17, 0x88, 0x84, 0x4c, 0x89, 0xa4, 0x7c, 0x5b, 0xfe, - 0x5e, 0x88, 0x1f, 0xad, 0x87, 0xb8, 0xab, 0x20, 0xae, 0xa8, 0xde, 0x1a, 0xc3, 0x3e, 0x20, 0xf2, 0x77, 0x0a, 0x01, - 0xc8, 0x14, 0x9c, 0xc0, 0x5c, 0xc1, 0x41, 0x2f, 0xbf, 0x1b, 0x8c, 0xee, 0x7a, 0x30, 0x1e, 0xdd, 0x04, 0x46, 0x9e, - 0x8e, 0x97, 0xf5, 0x75, 0xed, 0x80, 0x73, 0xda, 0x9b, 0x32, 0xe4, 0xa7, 0xa0, 0x8b, 0xcf, 0x67, 0xf1, 0x98, 0x4f, - 0xc5, 0x23, 0xb1, 0xf3, 0x99, 0xa8, 0xdb, 0x69, 0xb7, 0xc5, 0x7b, 0x01, 0x0a, 0x2d, 0xe8, 0xf8, 0xd8, 0x00, 0x98, - 0xe8, 0xab, 0xab, 0x3e, 0x62, 0xf3, 0xdd, 0x8d, 0x5f, 0xaa, 0xf1, 0x2e, 0x54, 0xde, 0xa0, 0x50, 0x11, 0xea, 0x9b, - 0x2d, 0x98, 0xf1, 0x96, 0xf7, 0x3b, 0xfa, 0xa0, 0x6a, 0xf0, 0x1d, 0x23, 0xad, 0x17, 0x70, 0xcf, 0xcc, 0x05, 0xea, - 0xa5, 0x7d, 0x0c, 0x49, 0xb5, 0x5a, 0x2e, 0xe8, 0x0d, 0x86, 0x21, 0x24, 0x3a, 0x10, 0x74, 0xf2, 0x41, 0x41, 0xdf, - 0xd4, 0xc8, 0xdc, 0xa0, 0x70, 0x32, 0x17, 0xb6, 0x7c, 0xa6, 0xe5, 0x3a, 0x28, 0x69, 0xf0, 0xb2, 0xbf, 0x62, 0xb2, - 0x01, 0x48, 0xef, 0x4a, 0xd2, 0x7e, 0xaf, 0x4f, 0x9e, 0x94, 0xc7, 0x97, 0x8d, 0x88, 0x70, 0xe0, 0xea, 0xf3, 0x29, - 0xba, 0xdd, 0xfa, 0x3b, 0x31, 0x46, 0x46, 0xcd, 0x96, 0xed, 0x0e, 0x98, 0x4e, 0xca, 0xc2, 0xe4, 0x33, 0x56, 0xe2, - 0x28, 0x5f, 0xb3, 0xf0, 0x7b, 0x0c, 0xbc, 0xb2, 0x50, 0x78, 0x69, 0xca, 0x47, 0x9b, 0x5d, 0x77, 0xfb, 0x1f, 0x16, - 0x3c, 0xa6, 0x64, 0xe7, 0xc3, 0xe1, 0xbf, 0xc1, 0x67, 0x70, 0x34, 0x06, 0x45, 0xb6, 0xc8, 0x47, 0x14, 0x04, 0x5c, - 0x0d, 0x26, 0xd8, 0xa4, 0xcb, 0x6d, 0x8f, 0x69, 0x15, 0x82, 0x1e, 0x76, 0xed, 0xfb, 0x09, 0x9c, 0xce, 0x57, 0xc4, - 0xf5, 0x05, 0x19, 0x40, 0x51, 0x10, 0xa2, 0x56, 0x1c, 0x53, 0x2a, 0x1d, 0x5d, 0xed, 0xf4, 0x17, 0x69, 0x0c, 0x42, - 0xf4, 0x63, 0x3c, 0xa6, 0x2b, 0x2d, 0xf1, 0x98, 0xce, 0x38, 0x5a, 0x94, 0xd3, 0x84, 0x41, 0x73, 0x28, 0x90, 0xb4, - 0xc5, 0x67, 0x99, 0x23, 0x63, 0xb7, 0x6c, 0x3c, 0xa7, 0x30, 0xb4, 0xf0, 0x38, 0x9b, 0x45, 0x71, 0x1a, 0xe0, 0xa7, - 0x47, 0x3c, 0x3d, 0x62, 0x80, 0x5d, 0x3c, 0xf8, 0xa9, 0xc8, 0xdc, 0x71, 0xfd, 0x5f, 0x40, 0x44, 0x51, 0xff, 0x52, - 0xba, 0x78, 0x1a, 0x2e, 0x75, 0x82, 0x5c, 0x2f, 0x05, 0xb1, 0xc6, 0x95, 0x39, 0xcc, 0x28, 0x84, 0xb2, 0xcb, 0xe9, - 0xc7, 0xa0, 0xd5, 0x09, 0x3a, 0xda, 0x2b, 0xae, 0x5d, 0x74, 0x15, 0x69, 0x32, 0xf2, 0xb2, 0x24, 0xc1, 0xa0, 0x9f, - 0x05, 0x9c, 0xd5, 0xbb, 0x86, 0xd5, 0x93, 0x2c, 0x8f, 0xb1, 0xa1, 0x93, 0xd4, 0xa9, 0x01, 0x41, 0xc7, 0x0c, 0x57, - 0x4c, 0xe5, 0x96, 0x11, 0x31, 0xe1, 0x63, 0x92, 0x0d, 0xf5, 0x6b, 0x4a, 0x78, 0x25, 0xa9, 0x9e, 0x5d, 0xa5, 0xb3, - 0xa4, 0x8f, 0x76, 0x85, 0x30, 0xb1, 0x88, 0xc7, 0x42, 0x1b, 0x76, 0xb7, 0x6d, 0xfd, 0x79, 0x04, 0x54, 0xfa, 0x14, - 0xda, 0x1b, 0x4b, 0x47, 0xe5, 0xec, 0xe7, 0x30, 0xd7, 0x9e, 0x50, 0xa8, 0x74, 0xd9, 0xdf, 0xee, 0x6f, 0x2c, 0x79, - 0xb9, 0xbb, 0x25, 0x7a, 0xf7, 0x8f, 0xca, 0x82, 0x74, 0x9f, 0x19, 0xa3, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, - 0x06, 0xe3, 0xb8, 0xb9, 0xb6, 0xe7, 0x44, 0x30, 0x5a, 0xb2, 0x5d, 0x81, 0x99, 0x50, 0x51, 0x0e, 0xdb, 0x5d, 0xe7, - 0xba, 0x14, 0x22, 0xbd, 0xa3, 0xb7, 0x0a, 0xc5, 0x11, 0x42, 0x30, 0xd8, 0x58, 0xc6, 0x65, 0xb8, 0xb1, 0x64, 0xe9, - 0x28, 0x1b, 0xb3, 0xf7, 0xef, 0x5e, 0xe0, 0x75, 0x86, 0x2c, 0x45, 0xb9, 0x97, 0xb9, 0xe5, 0x11, 0x18, 0x42, 0x08, - 0x69, 0xae, 0xbe, 0x26, 0x03, 0xc0, 0x88, 0x98, 0x8e, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, - 0x1c, 0x4e, 0x2c, 0x00, 0x53, 0x91, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, - 0x9a, 0x23, 0x1a, 0x15, 0xaa, 0x98, 0xfd, 0x63, 0xa2, 0x3b, 0x8e, 0x4f, 0x35, 0x39, 0x29, 0x15, 0xba, 0xbf, 0x9b, - 0x44, 0xc7, 0x2c, 0x81, 0x21, 0x8b, 0xcb, 0xcb, 0x36, 0x8c, 0x24, 0x5e, 0xad, 0xdd, 0x38, 0x9d, 0x2f, 0xe4, 0x57, - 0xbd, 0x60, 0xe2, 0x0e, 0x1e, 0xb4, 0xe2, 0xa5, 0x83, 0x81, 0x3a, 0x39, 0x0c, 0xe4, 0x00, 0x00, 0x22, 0x1d, 0x5a, - 0x20, 0x74, 0x15, 0xab, 0x40, 0x69, 0x3c, 0x5e, 0x2d, 0x83, 0xdd, 0x39, 0xc7, 0xd2, 0x14, 0x9e, 0x67, 0x71, 0x8a, - 0x8f, 0x05, 0x3e, 0x46, 0xe7, 0xf8, 0x98, 0xc1, 0xa3, 0xc6, 0x3d, 0x2f, 0xed, 0x7f, 0xd7, 0x55, 0xc9, 0xe4, 0x0a, - 0x58, 0x9a, 0x00, 0xd9, 0xe5, 0x25, 0xa8, 0x17, 0x4d, 0x82, 0xdd, 0x2d, 0x20, 0x16, 0x72, 0x8f, 0xf8, 0xc6, 0x0b, - 0x33, 0xc9, 0xc8, 0x8a, 0x79, 0x4b, 0x94, 0x5b, 0xa4, 0xc4, 0x43, 0xf0, 0xf1, 0x72, 0xa7, 0x61, 0xab, 0x78, 0x32, - 0x9b, 0xe5, 0x09, 0xbe, 0xb8, 0xb6, 0x25, 0x3e, 0xc2, 0x21, 0x88, 0x42, 0x8f, 0x88, 0xa1, 0x2e, 0xe3, 0xf2, 0xf3, - 0x3a, 0x71, 0x68, 0xe3, 0x2c, 0x60, 0x2e, 0xa2, 0xd2, 0xe1, 0x51, 0x9c, 0x88, 0xc6, 0x6b, 0xf0, 0x69, 0xa4, 0x25, - 0x12, 0x3a, 0xbb, 0x5b, 0x15, 0x6c, 0x00, 0xfc, 0x48, 0x5c, 0xea, 0x76, 0x44, 0xca, 0xa5, 0x2d, 0xca, 0xe9, 0xa8, - 0x5e, 0x6e, 0x73, 0x19, 0x48, 0x16, 0xa1, 0x79, 0x8d, 0x2a, 0xa5, 0x48, 0xda, 0x93, 0x28, 0x5d, 0xd7, 0x14, 0xa0, - 0x9f, 0x33, 0x36, 0xf6, 0x6c, 0x0b, 0xe4, 0xab, 0x78, 0xfe, 0x98, 0xb0, 0x53, 0x26, 0x3f, 0xcc, 0xa2, 0x07, 0xd1, - 0x95, 0x23, 0xb0, 0x00, 0xb8, 0xbc, 0x33, 0x2a, 0xd9, 0x53, 0xe1, 0x28, 0x29, 0x51, 0x47, 0xc4, 0xb3, 0x8d, 0x41, - 0x9b, 0x73, 0xb4, 0xeb, 0xc3, 0x7a, 0xa0, 0x93, 0x6c, 0x5b, 0xc0, 0x4b, 0x66, 0xe3, 0xcd, 0xc8, 0xc1, 0x00, 0xc7, - 0x39, 0x36, 0x4d, 0x59, 0x51, 0xac, 0x03, 0x0b, 0x9c, 0x60, 0xcf, 0xae, 0x9a, 0xd8, 0xb5, 0x0e, 0x00, 0x40, 0x77, - 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x32, 0x81, 0x8d, 0x87, 0x1a, 0x23, 0xe1, 0x18, 0xf6, 0x0f, 0xfb, 0xf6, 0x6b, - 0xd8, 0xe3, 0x36, 0xf8, 0x57, 0xae, 0x3e, 0xc0, 0xa5, 0xe9, 0x95, 0x10, 0x32, 0xe6, 0x10, 0x9d, 0x8d, 0x61, 0xf4, - 0x93, 0x81, 0x54, 0x36, 0xfa, 0xb4, 0x06, 0x27, 0xe0, 0xc2, 0x0d, 0x11, 0x40, 0x6e, 0xc8, 0x56, 0xfb, 0x5f, 0xff, - 0xe9, 0x7f, 0xfd, 0x37, 0x18, 0x9b, 0xfa, 0xb9, 0xa5, 0x75, 0x75, 0xab, 0xff, 0x09, 0xad, 0x16, 0xe9, 0x0d, 0xed, - 0xfe, 0xfa, 0x0f, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x23, 0x90, 0x59, 0x04, 0xd1, 0x08, 0x6d, 0xbb, 0xcf, 0x02, 0xa9, - 0x36, 0xc8, 0x95, 0x33, 0xfd, 0x23, 0x82, 0x5d, 0xf0, 0x6c, 0x7e, 0x2d, 0x38, 0x08, 0xf5, 0x28, 0xc9, 0x0a, 0xa6, - 0xe1, 0x11, 0x72, 0xfe, 0xf3, 0x00, 0xa2, 0xb9, 0xe6, 0xb0, 0x9b, 0x0a, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xdd, 0x38, - 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0x5c, 0x02, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x8f, 0x5b, 0xff, 0x78, - 0xd9, 0xfa, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x48, 0x8d, 0x00, 0x3f, 0x41, 0x38, 0x7e, 0xd4, 0xcf, 0xd1, - 0xb9, 0x7e, 0x46, 0x01, 0x2a, 0x26, 0x00, 0x3d, 0x38, 0x43, 0x13, 0xc7, 0x9c, 0x41, 0x64, 0x37, 0x54, 0xee, 0xb1, - 0x91, 0x24, 0x23, 0x84, 0xe4, 0x47, 0xcc, 0x25, 0xc5, 0x9b, 0x43, 0x8b, 0x9c, 0x7d, 0x4c, 0xb2, 0x33, 0x8c, 0xb9, - 0x21, 0x91, 0xae, 0xaa, 0x2f, 0xff, 0xe5, 0x9f, 0x7d, 0xff, 0x5f, 0xfe, 0xf9, 0x8a, 0x06, 0x53, 0xd8, 0x13, 0x60, - 0x24, 0xf3, 0x50, 0xd3, 0xb9, 0x81, 0xd6, 0xfa, 0x41, 0x11, 0xcf, 0xf5, 0x35, 0x12, 0x71, 0x2c, 0x95, 0x78, 0xcb, - 0x47, 0x42, 0x5b, 0x33, 0xc5, 0xcd, 0xb3, 0x20, 0x64, 0x57, 0x4c, 0x83, 0x55, 0x37, 0xcc, 0x73, 0xe4, 0x06, 0xd7, - 0xd0, 0xe5, 0x33, 0x31, 0x5e, 0x0f, 0xc6, 0x8d, 0x10, 0x78, 0xa0, 0x65, 0x84, 0x1e, 0x7a, 0x22, 0xb4, 0x48, 0x20, - 0x96, 0x41, 0xea, 0x94, 0x1a, 0x40, 0x9e, 0x75, 0x40, 0x13, 0x50, 0x93, 0xb8, 0xd2, 0xe1, 0x64, 0x06, 0x1d, 0xe7, - 0xfd, 0x57, 0x78, 0x59, 0xd0, 0xc2, 0xde, 0xa8, 0xc1, 0x0b, 0x32, 0x38, 0x38, 0x19, 0x1c, 0x52, 0xd3, 0x99, 0xba, - 0x1e, 0x1d, 0xa7, 0x6c, 0xbd, 0x4e, 0xff, 0x88, 0xdd, 0x6b, 0x5a, 0x99, 0x4b, 0xad, 0x1c, 0x4b, 0x2b, 0x5a, 0x6a, - 0x65, 0xfc, 0x24, 0x4c, 0x43, 0x2b, 0xc7, 0x57, 0x6a, 0x65, 0xa4, 0xdc, 0x00, 0x47, 0x0e, 0xed, 0x4d, 0x8c, 0x0e, - 0x19, 0x36, 0x00, 0x47, 0xfb, 0x67, 0x34, 0x65, 0xa3, 0x4f, 0xd2, 0xfc, 0x21, 0x04, 0x30, 0x3c, 0xa2, 0x8d, 0x3c, - 0x81, 0x01, 0xa8, 0xf2, 0xa3, 0x52, 0x6f, 0x7a, 0x7c, 0x34, 0x26, 0xe0, 0xee, 0x72, 0xc2, 0x50, 0xf4, 0xc3, 0x9a, - 0x7d, 0xcd, 0xca, 0x2d, 0x1c, 0x47, 0x6c, 0x18, 0xf1, 0x0c, 0x98, 0x6d, 0xe1, 0x60, 0x47, 0xde, 0x52, 0x04, 0xdb, - 0x02, 0xfb, 0xed, 0x9b, 0xfd, 0x03, 0xdb, 0x3b, 0xce, 0xc6, 0x17, 0x81, 0x0d, 0xde, 0x0c, 0x58, 0x39, 0xae, 0xcf, - 0xa7, 0x2c, 0x75, 0x94, 0x3f, 0x91, 0x25, 0xe0, 0xaa, 0x65, 0x27, 0xe2, 0xdb, 0x10, 0xcd, 0x83, 0x02, 0x20, 0x2c, - 0x7d, 0x3c, 0xb2, 0xbf, 0xcb, 0xc5, 0x77, 0x55, 0x79, 0x8e, 0x8f, 0x7d, 0x4c, 0x95, 0xd8, 0xdd, 0x82, 0x07, 0x7c, - 0xd9, 0x47, 0xbd, 0xa7, 0xdf, 0x04, 0xb0, 0x85, 0x78, 0xdf, 0xc2, 0xf6, 0x5b, 0xaa, 0x2f, 0x42, 0xd1, 0x97, 0xdc, - 0xa6, 0x4d, 0xfe, 0xca, 0x66, 0xa4, 0xb1, 0xc7, 0x68, 0x12, 0x92, 0xc9, 0x0f, 0x24, 0xe1, 0x63, 0x5d, 0x22, 0xcc, - 0x0c, 0xa3, 0x88, 0x46, 0xa9, 0x8c, 0x02, 0x59, 0x85, 0x13, 0x92, 0x19, 0x29, 0x26, 0x83, 0x9f, 0x04, 0xfe, 0x91, - 0xf9, 0x1d, 0x34, 0xf1, 0xc9, 0x22, 0x8d, 0xe4, 0xe1, 0x5f, 0xbc, 0x33, 0xe6, 0x5d, 0x1c, 0x51, 0x4b, 0xe5, 0x74, - 0x63, 0x34, 0x08, 0x83, 0x13, 0x6d, 0x15, 0x5d, 0x01, 0x3b, 0x28, 0x89, 0xe6, 0x05, 0x0b, 0xd4, 0x83, 0xf4, 0xbf, - 0xd1, 0x8d, 0x5f, 0x0d, 0x78, 0x98, 0xf6, 0x52, 0xc9, 0xa7, 0x4b, 0xd3, 0x41, 0x7f, 0x00, 0x0e, 0x3a, 0x5e, 0x2e, - 0x68, 0x45, 0xa0, 0xe5, 0xd3, 0x20, 0x61, 0x13, 0x5e, 0x72, 0xbc, 0xbd, 0xbe, 0x54, 0x11, 0x11, 0xbf, 0xbb, 0x03, - 0x4e, 0xbb, 0xe5, 0xe3, 0xff, 0x37, 0x8d, 0x3d, 0x0e, 0x52, 0x70, 0xb2, 0xe9, 0x3a, 0x0b, 0x5e, 0x15, 0x04, 0x88, - 0xcc, 0xf7, 0xa5, 0x31, 0xd1, 0x88, 0x61, 0xb4, 0xa8, 0xe4, 0x39, 0xc8, 0x6d, 0x8f, 0xe7, 0x66, 0x3b, 0x90, 0xb7, - 0x2b, 0x21, 0xa3, 0xd5, 0xa0, 0xc5, 0xb6, 0x2b, 0xfd, 0x8f, 0xd5, 0xc6, 0x2a, 0xf2, 0x53, 0x7f, 0x5b, 0xa1, 0x90, - 0x11, 0xa3, 0x2a, 0x85, 0xaa, 0x59, 0x8a, 0x1e, 0x26, 0x4e, 0xab, 0xd1, 0xab, 0x1b, 0x2d, 0xd2, 0x92, 0xb6, 0xfd, - 0x21, 0x6d, 0x7b, 0x12, 0x63, 0xc3, 0xa5, 0x98, 0x7b, 0x14, 0x25, 0x23, 0x07, 0x01, 0xb0, 0x5a, 0xd6, 0x23, 0xa0, - 0xa6, 0xab, 0x22, 0x28, 0xfe, 0x43, 0x24, 0x6e, 0x29, 0x84, 0xde, 0x1a, 0x2a, 0x1d, 0x0d, 0xcb, 0xb2, 0x77, 0xc1, - 0x9c, 0xc3, 0xdf, 0xe4, 0x65, 0x08, 0x71, 0x07, 0x56, 0x7f, 0x47, 0xb0, 0x5d, 0xba, 0x43, 0x8f, 0x31, 0xe3, 0xeb, - 0x6c, 0xb6, 0xe2, 0x68, 0xdb, 0xeb, 0x52, 0x3c, 0x01, 0x7b, 0xbf, 0x72, 0x6c, 0x34, 0x62, 0xa9, 0xea, 0xa2, 0x45, - 0x1c, 0x66, 0x53, 0x47, 0x11, 0xcd, 0xff, 0xe6, 0xaa, 0xa0, 0xcc, 0xb7, 0x37, 0x07, 0x65, 0xf8, 0x2d, 0x83, 0x32, - 0xdf, 0xfe, 0xc1, 0x41, 0x99, 0x6f, 0xcc, 0xa0, 0x0c, 0xca, 0xca, 0x17, 0x9f, 0x13, 0x39, 0xc9, 0xb3, 0xb3, 0x22, - 0xec, 0xc8, 0x24, 0x00, 0x10, 0x3b, 0xff, 0x31, 0x21, 0x14, 0x98, 0xa8, 0x11, 0x40, 0xa1, 0x88, 0x89, 0xc8, 0x5b, - 0x04, 0x09, 0x2f, 0xe3, 0x15, 0x6d, 0x9d, 0x20, 0xd8, 0xba, 0xaf, 0x6e, 0x44, 0x81, 0x77, 0xe8, 0xea, 0xb0, 0x51, - 0x57, 0x45, 0x34, 0x02, 0xfa, 0xa4, 0xa9, 0xee, 0xd8, 0xdd, 0x54, 0x99, 0x69, 0xe6, 0x08, 0x3d, 0x75, 0xe0, 0x20, - 0x38, 0x68, 0x69, 0xff, 0xe7, 0xc3, 0x4e, 0x6f, 0xbb, 0x33, 0x83, 0xde, 0xa0, 0x4b, 0xe1, 0xad, 0xdd, 0xdb, 0xde, - 0xc6, 0xb7, 0x33, 0xf5, 0xd6, 0xc5, 0xb7, 0x58, 0xbd, 0xed, 0xe0, 0xdb, 0x48, 0xbd, 0x3d, 0xc0, 0xb7, 0xb1, 0x7a, - 0x7b, 0x88, 0x6f, 0xa7, 0x76, 0x79, 0xc8, 0x35, 0x70, 0x0f, 0x81, 0xb1, 0xc8, 0xb1, 0x08, 0x54, 0x19, 0xec, 0x5b, - 0xbc, 0x49, 0x18, 0x9d, 0x04, 0xb1, 0x27, 0x1c, 0xb0, 0x20, 0xf7, 0xce, 0x40, 0xf8, 0x07, 0x94, 0x38, 0xf7, 0x14, - 0x3f, 0x29, 0x01, 0xfe, 0xca, 0x41, 0x3c, 0x63, 0xea, 0xdb, 0xba, 0x0a, 0x6b, 0xb0, 0x25, 0x0f, 0xdb, 0xc3, 0xb2, - 0xa7, 0xd7, 0x49, 0x04, 0x6c, 0x54, 0x62, 0x02, 0xad, 0x5c, 0x55, 0x27, 0xa6, 0x6b, 0xe9, 0x15, 0xbe, 0x42, 0x95, - 0x18, 0x2e, 0xfb, 0x04, 0x6c, 0xa4, 0xd6, 0x39, 0x38, 0x79, 0x6b, 0xd5, 0x0b, 0x42, 0xa4, 0x15, 0x0a, 0xe1, 0xa4, - 0xdf, 0x0e, 0xa2, 0x13, 0xfd, 0xfc, 0x0a, 0x8c, 0xde, 0xe8, 0x84, 0xdd, 0xa4, 0x6a, 0x08, 0x44, 0x53, 0xcd, 0x28, - 0x20, 0xc8, 0x2a, 0x82, 0xa5, 0x41, 0x67, 0x53, 0xaa, 0x19, 0xa4, 0x4e, 0x5d, 0xf1, 0xd0, 0xf4, 0xf5, 0x22, 0xa0, - 0x68, 0x55, 0xb0, 0x0b, 0xb6, 0x37, 0x95, 0x0a, 0x0a, 0x43, 0x05, 0x16, 0x5c, 0xab, 0x8d, 0xb4, 0x3f, 0x7e, 0xa5, - 0x4e, 0xb2, 0x94, 0x3a, 0x32, 0x0f, 0x2a, 0xf4, 0x29, 0xc5, 0xaa, 0x84, 0xfc, 0xa2, 0x33, 0xc2, 0x3f, 0x52, 0xfe, - 0x7e, 0x31, 0x99, 0x4c, 0xae, 0x55, 0x4f, 0x5f, 0x8c, 0x27, 0xac, 0xcb, 0x76, 0x7a, 0x18, 0xc4, 0x6e, 0x49, 0x89, - 0xd8, 0x29, 0x89, 0x76, 0xcb, 0xdb, 0x35, 0x46, 0xe1, 0x09, 0x1a, 0xeb, 0xf6, 0x7a, 0xac, 0x04, 0xaa, 0x2c, 0x41, - 0x7e, 0x9f, 0xc4, 0x69, 0xd0, 0x2e, 0xfd, 0x53, 0x29, 0xf8, 0xbf, 0x78, 0xf4, 0xe8, 0x51, 0xe9, 0x8f, 0xd5, 0x5b, - 0x7b, 0x3c, 0x2e, 0xfd, 0xd1, 0x52, 0xa3, 0xd1, 0x6e, 0x4f, 0x26, 0xa5, 0x1f, 0xab, 0x82, 0xed, 0xee, 0x68, 0xbc, - 0xdd, 0x2d, 0xfd, 0x33, 0xa3, 0x45, 0xe9, 0x33, 0xf9, 0x96, 0xb3, 0x71, 0x2d, 0x12, 0xfe, 0xb0, 0x0d, 0x95, 0x82, - 0xd1, 0x96, 0xe8, 0xe8, 0x89, 0xc7, 0x20, 0x5a, 0xf0, 0x0c, 0x6c, 0x2c, 0xe0, 0x6d, 0x10, 0xd0, 0x13, 0x29, 0xde, - 0xc5, 0xa7, 0x6b, 0x51, 0xa8, 0xbf, 0x30, 0x65, 0x3a, 0x32, 0x33, 0xc9, 0x73, 0x4e, 0xaa, 0xa0, 0x59, 0x8d, 0x9c, - 0x45, 0xd5, 0x2f, 0x42, 0x5e, 0x49, 0x7b, 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xaf, 0x92, 0xf1, 0x3f, 0xdc, - 0x2c, 0xe3, 0x8f, 0x6f, 0x27, 0xe2, 0x7f, 0xf8, 0x83, 0x45, 0xfc, 0x8f, 0xa6, 0x88, 0x17, 0x42, 0x6c, 0x0f, 0xac, - 0x58, 0x32, 0x5f, 0x8f, 0xb3, 0xf3, 0x16, 0x6e, 0x89, 0xdc, 0x26, 0xe9, 0xb9, 0x71, 0x2b, 0xe1, 0xbf, 0x26, 0xb5, - 0x49, 0x0d, 0x66, 0x7c, 0x07, 0x97, 0x67, 0x27, 0x27, 0x09, 0x53, 0x32, 0xde, 0xa8, 0x20, 0xcb, 0xf8, 0x4d, 0x1a, - 0xda, 0x6f, 0xc0, 0x49, 0x35, 0x4a, 0x26, 0x13, 0x28, 0x9a, 0x4c, 0x6c, 0x95, 0xfa, 0x0b, 0xf2, 0x8c, 0x5a, 0xbd, - 0xae, 0x95, 0x50, 0xab, 0xaf, 0xbe, 0x32, 0xcb, 0xcc, 0x02, 0x19, 0xf5, 0x32, 0xed, 0x09, 0x59, 0x33, 0x8e, 0x0b, - 0xdc, 0x83, 0xd5, 0x77, 0x7b, 0xd1, 0x64, 0x99, 0x81, 0x52, 0x89, 0x47, 0xf8, 0x41, 0x98, 0xe6, 0x37, 0x52, 0x44, - 0x9a, 0xf6, 0x2a, 0x72, 0xd5, 0x51, 0xae, 0xf1, 0x39, 0xbe, 0xea, 0xf8, 0x16, 0x16, 0x5f, 0xa6, 0x6a, 0x3c, 0xbe, - 0x78, 0x31, 0x76, 0xf6, 0xc0, 0x94, 0x8d, 0x8b, 0x37, 0x69, 0x23, 0x05, 0x4e, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, - 0x20, 0x58, 0x75, 0x17, 0xa0, 0xaa, 0xec, 0x19, 0x9d, 0x64, 0xa6, 0x14, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, - 0x93, 0xba, 0x90, 0xbe, 0xcb, 0x2e, 0xf2, 0x47, 0x4e, 0xe5, 0x07, 0xbc, 0xe9, 0xf4, 0x61, 0x29, 0xf5, 0x87, 0xcc, - 0x2c, 0xa8, 0x7a, 0x62, 0xc0, 0x5f, 0xcc, 0x30, 0x2e, 0x55, 0x90, 0x1f, 0x08, 0x37, 0xc7, 0xaf, 0x0d, 0x89, 0x21, - 0x54, 0x2c, 0xbd, 0xa2, 0xde, 0xe5, 0xa5, 0xf9, 0xd1, 0xcb, 0xda, 0x07, 0x12, 0x1b, 0x3c, 0xc0, 0xf0, 0x6b, 0xb5, - 0xa8, 0x0d, 0xb2, 0x05, 0x77, 0x1c, 0x6a, 0xe5, 0xb8, 0xa5, 0xb7, 0xd3, 0x6e, 0x83, 0x8a, 0xf1, 0xc5, 0x27, 0x8d, - 0x1c, 0xdd, 0x59, 0xe2, 0x7b, 0x55, 0xe8, 0x7e, 0xe5, 0x13, 0x63, 0x9a, 0xc4, 0xf8, 0x0d, 0x14, 0x81, 0xa8, 0x71, - 0x0d, 0x46, 0x2d, 0x62, 0xf3, 0xdd, 0x57, 0x6e, 0x9c, 0x41, 0x58, 0x77, 0x1d, 0x07, 0xcb, 0x34, 0xd1, 0x7a, 0x21, - 0xb6, 0x15, 0x56, 0xcd, 0x2a, 0x38, 0x37, 0xe8, 0xcc, 0xe2, 0xcc, 0x88, 0x71, 0xd7, 0xb6, 0x41, 0xa9, 0x82, 0xdc, - 0x22, 0x52, 0xbd, 0x87, 0xf1, 0x58, 0xe1, 0x03, 0x2b, 0xa0, 0xeb, 0xde, 0xa7, 0x01, 0x39, 0xfa, 0xa5, 0x9a, 0xd1, - 0x55, 0x95, 0x2a, 0x28, 0xcd, 0x53, 0x0a, 0x03, 0x19, 0x0a, 0x36, 0xc3, 0x1a, 0xa7, 0x42, 0x6f, 0xc1, 0x34, 0x24, - 0x80, 0xb5, 0x53, 0x86, 0x9e, 0x89, 0xad, 0xc0, 0x16, 0xd2, 0x02, 0x94, 0x1e, 0x76, 0xe8, 0x5b, 0x35, 0xd0, 0xd3, - 0xd5, 0x18, 0xf5, 0x75, 0x7e, 0xda, 0xc5, 0x91, 0x5f, 0x9c, 0x79, 0xf0, 0xcf, 0xfa, 0xd3, 0x12, 0xa4, 0xfc, 0xf1, - 0xa7, 0x98, 0x83, 0x51, 0x3d, 0x6f, 0x61, 0x24, 0x84, 0x42, 0xa6, 0x52, 0x1d, 0xd2, 0xa9, 0xaa, 0xb8, 0xfd, 0xd4, - 0x5b, 0x14, 0xe8, 0xce, 0x91, 0xdf, 0x12, 0xa4, 0x59, 0xca, 0x7a, 0xf5, 0xd3, 0x73, 0xd3, 0x75, 0x50, 0xc4, 0x1a, - 0x2e, 0x33, 0x74, 0xff, 0xf8, 0x05, 0xb8, 0x7f, 0x42, 0x8d, 0xb6, 0x95, 0xdf, 0xd0, 0x5e, 0xdb, 0x3e, 0x90, 0xb4, - 0xdd, 0x24, 0x6b, 0x21, 0x5f, 0xf5, 0x8f, 0xae, 0xf2, 0x6f, 0x6e, 0x3a, 0x4b, 0xc6, 0xf8, 0xac, 0xfa, 0x67, 0x1c, - 0xc2, 0x37, 0x8b, 0xe9, 0x2c, 0xf9, 0x36, 0x90, 0x05, 0xd1, 0x04, 0x3f, 0x16, 0x78, 0x9b, 0x96, 0xc7, 0x94, 0xc8, - 0xb9, 0x44, 0xb5, 0x1e, 0x74, 0x1e, 0x81, 0xc3, 0x76, 0xeb, 0xe1, 0xaf, 0x47, 0xbf, 0x94, 0x34, 0x52, 0xf7, 0x71, - 0x6d, 0xbb, 0x87, 0xf2, 0x22, 0x89, 0x2e, 0xc0, 0x6f, 0x24, 0x1b, 0xe3, 0x18, 0x03, 0xb9, 0xbd, 0x79, 0x26, 0x93, - 0x22, 0x72, 0x96, 0xd0, 0x6f, 0xe4, 0x90, 0x4b, 0xb1, 0xfd, 0x60, 0x7e, 0xae, 0x56, 0xa3, 0xd3, 0x48, 0x76, 0xf8, - 0x43, 0x73, 0x1a, 0xae, 0x4e, 0xa2, 0xa8, 0x9f, 0xcb, 0xef, 0x00, 0x0c, 0xc2, 0xb0, 0x69, 0xe5, 0x02, 0xaa, 0x36, - 0x94, 0x18, 0x59, 0x1d, 0xd5, 0x40, 0x96, 0xbf, 0x0d, 0xaa, 0x32, 0x2a, 0x58, 0x0f, 0xbf, 0xda, 0x18, 0x83, 0x77, - 0x2a, 0x8d, 0xa7, 0x59, 0x3c, 0x1e, 0x27, 0xac, 0xa7, 0xec, 0x23, 0xab, 0xf3, 0x00, 0x93, 0x22, 0xcc, 0x25, 0xab, - 0xaf, 0x8a, 0x41, 0x3c, 0x4d, 0xa7, 0xe8, 0x18, 0xec, 0x35, 0xfc, 0xf4, 0xe2, 0x5a, 0x72, 0xca, 0x6c, 0x81, 0x76, - 0x45, 0x3c, 0x7a, 0xae, 0xe3, 0xb2, 0x03, 0xc6, 0x22, 0x2d, 0x78, 0xbb, 0xc7, 0xb3, 0x79, 0xd0, 0xda, 0xae, 0x23, - 0x82, 0x55, 0x1a, 0x05, 0x6f, 0x0d, 0x5a, 0x1e, 0x5a, 0x07, 0x42, 0xcb, 0x59, 0x7e, 0x47, 0x96, 0xd1, 0x00, 0xf8, - 0x79, 0x3f, 0x5d, 0x54, 0xd6, 0x91, 0xf9, 0xf7, 0xd9, 0x2d, 0x5f, 0xae, 0xdf, 0x2d, 0x5f, 0xaa, 0xdd, 0x72, 0x3d, - 0xc7, 0x7e, 0x31, 0xe9, 0xe0, 0x9f, 0x5e, 0x85, 0x10, 0xac, 0x0a, 0x90, 0xc3, 0x42, 0xbb, 0xb8, 0xd5, 0x85, 0xff, - 0x68, 0xe8, 0xb6, 0x87, 0x7f, 0x7c, 0xb0, 0x00, 0xdb, 0x16, 0x16, 0xe2, 0xbf, 0x76, 0xad, 0xaa, 0x73, 0x1f, 0xeb, - 0xb0, 0xd7, 0xce, 0x6a, 0x5d, 0xf7, 0xfa, 0x4d, 0x0b, 0xf2, 0x8a, 0x3b, 0x81, 0x12, 0xc6, 0xe0, 0xaa, 0x45, 0xc7, - 0xc7, 0x50, 0x3a, 0xc9, 0x46, 0x8b, 0xe2, 0xef, 0x24, 0xfc, 0x92, 0x88, 0xd7, 0x6e, 0xe9, 0xc6, 0x38, 0xaa, 0xab, - 0xc8, 0xb0, 0x51, 0x23, 0x2c, 0xf5, 0x3a, 0x05, 0x05, 0x30, 0x26, 0x73, 0xba, 0xfe, 0xfd, 0x35, 0x9b, 0xe0, 0x3f, - 0x64, 0x6d, 0xd6, 0x22, 0xf3, 0x6f, 0x25, 0xc6, 0xb5, 0x44, 0xf8, 0x2c, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb4, 0x1e, - 0xdc, 0x43, 0x35, 0xd3, 0x50, 0x29, 0x05, 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0x16, 0x09, 0xbf, 0x7e, 0xd4, 0xab, 0x38, - 0x63, 0x65, 0xd4, 0x6b, 0x04, 0x7a, 0xd5, 0xf6, 0x96, 0x52, 0xfa, 0x8b, 0x2f, 0xef, 0xe3, 0x1f, 0x11, 0xfb, 0x3a, - 0xae, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, 0x68, 0xa3, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x6d, 0x5b, 0xa3, - 0xb1, 0x7e, 0xab, 0xe6, 0xd2, 0x2a, 0xfd, 0xac, 0xd6, 0x9f, 0x37, 0xf8, 0x2d, 0xdb, 0x8e, 0x84, 0x43, 0x50, 0x6f, - 0x2b, 0x7f, 0x3b, 0xca, 0x4a, 0x63, 0x45, 0xf1, 0xdb, 0xb6, 0xaf, 0x4c, 0x62, 0xea, 0xb1, 0x11, 0x1e, 0x6b, 0x27, - 0x52, 0x9e, 0x6f, 0x63, 0x0f, 0xe1, 0x47, 0xfe, 0x85, 0x85, 0xf7, 0xf0, 0xc3, 0x62, 0xd6, 0xf9, 0x2c, 0x49, 0xc1, - 0xac, 0x9a, 0x72, 0x3e, 0x0f, 0xb6, 0xb6, 0xce, 0xce, 0xce, 0xfc, 0xb3, 0x6d, 0x3f, 0xcb, 0x4f, 0xb6, 0xba, 0xed, - 0x76, 0x1b, 0xbf, 0x07, 0x65, 0x5b, 0xa7, 0x31, 0x3b, 0x7b, 0x0c, 0xee, 0x87, 0xfd, 0xd0, 0x7a, 0x64, 0x3d, 0xdc, - 0xb6, 0x76, 0x1e, 0xd8, 0x16, 0x29, 0x00, 0x28, 0xd9, 0xb6, 0x2d, 0xa1, 0x00, 0x42, 0x1b, 0x8a, 0xfb, 0xbb, 0x27, - 0xca, 0x86, 0xc3, 0x7c, 0x7b, 0x61, 0x21, 0x81, 0xff, 0x96, 0x7d, 0x62, 0xf5, 0xad, 0x2e, 0xca, 0x5a, 0x52, 0x8d, - 0xa8, 0x57, 0xdc, 0xef, 0xa3, 0x68, 0x1e, 0x10, 0x1b, 0x99, 0x85, 0x18, 0x26, 0x13, 0xa5, 0x34, 0x05, 0xda, 0xa5, - 0xc7, 0xf0, 0x84, 0x19, 0x5a, 0x16, 0x3c, 0xbf, 0xea, 0x3e, 0x04, 0x1d, 0x77, 0xda, 0xba, 0x3f, 0x6a, 0xb7, 0x3a, - 0x56, 0xa7, 0xd5, 0xf5, 0x1f, 0x5a, 0x5d, 0xf1, 0x3f, 0xc8, 0xc8, 0x6d, 0xab, 0x03, 0x4f, 0xdb, 0x16, 0xbc, 0x9f, - 0xde, 0x17, 0xe9, 0x17, 0x91, 0xbd, 0xd5, 0xdf, 0xc5, 0x5f, 0x8f, 0x04, 0x48, 0x7d, 0x69, 0x8b, 0x5f, 0xe8, 0x66, - 0x7f, 0x61, 0x96, 0x76, 0x1e, 0xad, 0x2d, 0xee, 0x3e, 0x5c, 0x5b, 0xbc, 0xfd, 0x60, 0x6d, 0xf1, 0xfd, 0x9d, 0x7a, - 0xf1, 0xd6, 0x89, 0xa8, 0xd2, 0x72, 0x21, 0xb4, 0x67, 0x11, 0x30, 0xca, 0xb9, 0xd3, 0x01, 0x38, 0xdb, 0x56, 0x0b, - 0x7f, 0x3c, 0xec, 0xba, 0xba, 0xd7, 0x31, 0xf6, 0xd2, 0x58, 0x3e, 0x7c, 0x04, 0x58, 0x3e, 0xef, 0x3e, 0x18, 0x61, - 0x3b, 0x42, 0x14, 0xfe, 0x9d, 0x6e, 0x3f, 0x1a, 0x81, 0x46, 0xb0, 0xf0, 0x1f, 0xfc, 0x99, 0xee, 0x74, 0x47, 0xe2, - 0xa5, 0x8d, 0xf5, 0x1f, 0x3a, 0x0f, 0x0b, 0x68, 0x8a, 0x7f, 0x7e, 0xd3, 0x26, 0x34, 0x1a, 0xf0, 0xe6, 0xb8, 0xf7, - 0x81, 0x46, 0x8f, 0xa6, 0x5d, 0xff, 0xcb, 0xd3, 0x87, 0xfe, 0xa3, 0x69, 0xe7, 0xe1, 0x07, 0xf1, 0x96, 0x00, 0x05, - 0xbf, 0xc4, 0x7f, 0x1f, 0xb6, 0xdb, 0xd3, 0x56, 0xc7, 0x7f, 0x74, 0xba, 0xed, 0x6f, 0x27, 0xad, 0x07, 0xfe, 0x23, - 0xfc, 0x57, 0x0d, 0x37, 0xcd, 0x66, 0xcc, 0xb6, 0x70, 0xbd, 0x1b, 0x7e, 0xaf, 0x39, 0x47, 0xf7, 0xbe, 0xb5, 0x73, - 0xff, 0xf9, 0x23, 0x58, 0xa3, 0x69, 0xa7, 0x0b, 0xff, 0x5f, 0xf5, 0xf8, 0x01, 0x09, 0x2f, 0x07, 0x8e, 0x18, 0x66, - 0xca, 0x2a, 0xc2, 0xd1, 0xb7, 0xc9, 0xee, 0x79, 0xdf, 0x5f, 0x15, 0x00, 0x61, 0xfc, 0xe6, 0x20, 0x37, 0xbf, 0x5d, - 0x04, 0x84, 0x3e, 0x9c, 0xff, 0x07, 0x46, 0x40, 0xbe, 0x6f, 0x06, 0xb9, 0xcf, 0x57, 0xf3, 0x03, 0x9b, 0xce, 0xda, - 0x6b, 0xe6, 0x1c, 0xfe, 0x85, 0x0d, 0x31, 0x2b, 0x1c, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0xe7, 0x32, - 0xea, 0x5f, 0xf0, 0x2b, 0x08, 0x12, 0xdf, 0x4c, 0x90, 0x5f, 0x6f, 0x47, 0x8f, 0xf8, 0x0f, 0xa6, 0x47, 0xc1, 0x0d, - 0x7a, 0xd4, 0x22, 0xee, 0x14, 0x31, 0x20, 0x47, 0x7f, 0x9f, 0xde, 0x9d, 0xef, 0xf1, 0xab, 0x62, 0x5b, 0x0c, 0x4b, - 0x0a, 0x5b, 0xe4, 0x24, 0xbe, 0xfb, 0x9c, 0x13, 0x02, 0x91, 0x38, 0x1d, 0xda, 0x32, 0x08, 0x33, 0xc7, 0xcf, 0xef, - 0xaa, 0x97, 0x53, 0x71, 0x39, 0x27, 0xa4, 0x9b, 0x75, 0x3b, 0x3a, 0x80, 0x83, 0xb9, 0xec, 0xe1, 0x32, 0xe3, 0x11, - 0xfe, 0x7e, 0x27, 0x1e, 0xf3, 0x04, 0xef, 0xfd, 0xca, 0x3b, 0x72, 0x98, 0x7a, 0xfd, 0x2d, 0xa6, 0x8d, 0xab, 0x83, - 0x82, 0x19, 0x06, 0x0d, 0x5e, 0xb1, 0x71, 0x1c, 0x39, 0xb6, 0x33, 0x87, 0x5d, 0x0b, 0x63, 0xb6, 0x6a, 0x39, 0xdb, - 0x94, 0xae, 0xed, 0xda, 0xea, 0x57, 0x0a, 0xe5, 0xf8, 0x89, 0xb6, 0xf0, 0x50, 0x06, 0x19, 0x6d, 0xe9, 0x05, 0xc0, - 0xf8, 0xaa, 0x24, 0x47, 0x81, 0x5f, 0x59, 0x0e, 0xb6, 0x30, 0x1d, 0x3a, 0x7e, 0x17, 0x5c, 0x09, 0x2a, 0xc6, 0x4f, - 0x5e, 0xfd, 0xe0, 0xb4, 0xb6, 0xc1, 0xb4, 0x31, 0xba, 0xe9, 0x81, 0x86, 0x2b, 0xa1, 0x24, 0x11, 0x20, 0x68, 0x94, - 0x7a, 0xfa, 0x77, 0xac, 0x55, 0x21, 0xa3, 0xe2, 0xf1, 0xc5, 0x81, 0xbc, 0xd6, 0x6e, 0x63, 0xf4, 0x96, 0xa2, 0xf6, - 0xd5, 0x27, 0xb5, 0x36, 0x41, 0x65, 0xd0, 0x2f, 0xba, 0xa4, 0x33, 0x70, 0xd4, 0x0a, 0x98, 0x55, 0x6e, 0x49, 0xef, - 0x21, 0xb4, 0x85, 0x4e, 0x18, 0xb3, 0xd3, 0x78, 0x24, 0x45, 0xbb, 0x67, 0xc9, 0xdb, 0x30, 0x2d, 0xc2, 0x22, 0xec, - 0x78, 0xc2, 0x7f, 0x86, 0x17, 0xd4, 0x6c, 0x61, 0x9a, 0xd9, 0xfd, 0x7b, 0x3d, 0x0d, 0x49, 0x3d, 0x21, 0xdf, 0xc6, - 0xdf, 0xba, 0x79, 0x08, 0xfe, 0xda, 0xdf, 0x85, 0xf7, 0xf0, 0xf7, 0x6e, 0xde, 0x1b, 0xda, 0xae, 0x4f, 0x82, 0xf1, - 0x5e, 0xf5, 0xcb, 0x37, 0x51, 0x2a, 0x6c, 0x82, 0x0e, 0xf3, 0x6e, 0xab, 0xcc, 0xa4, 0xe2, 0xea, 0xee, 0x54, 0x8a, - 0x0b, 0x9e, 0x0d, 0x49, 0x05, 0x42, 0xb4, 0xeb, 0xef, 0x18, 0xe2, 0xf0, 0xb4, 0x85, 0x3f, 0x6b, 0x02, 0xf1, 0x3e, - 0x34, 0x50, 0x12, 0xf1, 0x25, 0x34, 0xdf, 0x16, 0xc2, 0x17, 0xfa, 0xfd, 0x48, 0xe2, 0x4a, 0x88, 0xaa, 0x3a, 0xc7, - 0xac, 0x39, 0x48, 0x12, 0xf9, 0x02, 0xb6, 0x67, 0xc4, 0x9c, 0x04, 0xbb, 0xca, 0x88, 0xca, 0x53, 0xe8, 0xeb, 0xe8, - 0x2f, 0x55, 0xaf, 0xab, 0xf3, 0x6a, 0xbb, 0x67, 0xcd, 0x14, 0xc8, 0xf0, 0x8d, 0xc3, 0x2a, 0xba, 0x9d, 0x21, 0xbe, - 0xd8, 0x26, 0xb6, 0x72, 0xf5, 0x4d, 0xbb, 0x35, 0x59, 0xc0, 0xe6, 0xa6, 0x60, 0x15, 0xd3, 0xd0, 0xbe, 0xc0, 0xf4, - 0x19, 0xfc, 0x59, 0x15, 0xab, 0x07, 0xc9, 0x50, 0x7e, 0x12, 0xe1, 0x2f, 0x9c, 0xa1, 0x1f, 0x65, 0xb5, 0x01, 0x39, - 0x7d, 0x92, 0x93, 0x20, 0x7d, 0x31, 0x2e, 0x9b, 0x48, 0x80, 0xcd, 0x80, 0xbf, 0xbf, 0xb0, 0xba, 0x0d, 0x22, 0xaf, - 0x79, 0x62, 0x6a, 0xc1, 0x38, 0xce, 0xe9, 0xf6, 0xb0, 0xc2, 0xbf, 0x16, 0xd5, 0xac, 0x48, 0x4d, 0xbb, 0x92, 0x15, - 0x03, 0x1b, 0x8b, 0xec, 0x40, 0x26, 0xc0, 0x99, 0xdf, 0xa4, 0x36, 0xaf, 0x77, 0x8e, 0x45, 0xee, 0x1b, 0x7e, 0xb3, - 0xdf, 0x16, 0x44, 0xb6, 0x41, 0x94, 0x5d, 0x89, 0x13, 0x19, 0x38, 0x78, 0x2b, 0xb2, 0xfa, 0x25, 0x4c, 0xe6, 0x86, - 0xb7, 0xcd, 0xd5, 0xd2, 0xe3, 0xd2, 0x3a, 0xb8, 0x32, 0x86, 0x77, 0xcc, 0x22, 0xee, 0x47, 0x29, 0xe5, 0x29, 0x39, - 0x86, 0x58, 0xf0, 0x3a, 0x6c, 0xdb, 0x2d, 0x41, 0xf2, 0x18, 0xbf, 0xa5, 0x4a, 0x90, 0xde, 0x87, 0x42, 0x95, 0x4b, - 0xfd, 0x7d, 0x2d, 0x15, 0x78, 0xda, 0xed, 0xbf, 0x39, 0xd8, 0xb3, 0xc4, 0xc6, 0xde, 0xdd, 0x82, 0xd7, 0x5d, 0xf2, - 0x8e, 0x45, 0xc6, 0x46, 0x28, 0x32, 0x36, 0x2c, 0x91, 0xe7, 0x25, 0x52, 0x67, 0xb7, 0x04, 0xd6, 0xb6, 0xc5, 0xd2, - 0x91, 0x08, 0xeb, 0xcd, 0xc0, 0x83, 0x88, 0xf1, 0x33, 0x66, 0x5b, 0xd8, 0xb5, 0x85, 0x0b, 0x6f, 0xab, 0xe4, 0x17, - 0x65, 0x33, 0xf0, 0x54, 0x05, 0x01, 0x41, 0xd3, 0x33, 0x95, 0x07, 0x23, 0x87, 0xd2, 0x69, 0xb1, 0xab, 0xad, 0x8b, - 0xc5, 0xf1, 0x0c, 0xc4, 0x92, 0xca, 0x5d, 0x79, 0x2f, 0x3b, 0xec, 0xd2, 0x54, 0xfd, 0xa3, 0x72, 0x5d, 0x94, 0x72, - 0xda, 0xe9, 0xef, 0x46, 0xd2, 0x06, 0xc2, 0xbd, 0x5c, 0xc0, 0x66, 0x06, 0xd5, 0x87, 0x86, 0x86, 0x1f, 0x67, 0x5b, - 0x67, 0xec, 0xb8, 0x15, 0xcd, 0xe3, 0x2a, 0x24, 0x88, 0x1a, 0xb1, 0xbf, 0xab, 0x94, 0xa3, 0x4c, 0xf5, 0x94, 0x8f, - 0x91, 0x91, 0xdc, 0x81, 0x84, 0x24, 0x86, 0x2d, 0x65, 0xbc, 0x91, 0x0c, 0x49, 0x58, 0x0c, 0x00, 0x96, 0xf8, 0x59, - 0xc5, 0x25, 0xa5, 0x66, 0x28, 0xed, 0xfe, 0x5f, 0xff, 0xf7, 0xff, 0x91, 0xa1, 0x46, 0xa0, 0x2d, 0x80, 0x85, 0xd9, - 0x31, 0xd5, 0xa9, 0x23, 0x3b, 0x07, 0xe7, 0x34, 0x1e, 0xb7, 0xa6, 0x51, 0x32, 0x01, 0x08, 0x0a, 0x26, 0xee, 0x14, - 0xc8, 0x7a, 0xe0, 0x0a, 0x09, 0x96, 0x79, 0x62, 0x2f, 0xc1, 0xab, 0x17, 0xe1, 0xb2, 0xfd, 0xae, 0xdc, 0x59, 0x95, - 0xb3, 0x4c, 0x0c, 0x6e, 0x64, 0xd2, 0x1a, 0x3c, 0x58, 0xcb, 0xa6, 0x55, 0xbf, 0x13, 0x4a, 0x0a, 0x13, 0x56, 0x4b, - 0xa5, 0x85, 0x96, 0xfa, 0x70, 0xe4, 0x5f, 0xff, 0xe9, 0xbf, 0xfc, 0x0f, 0xf5, 0x8a, 0x67, 0x1e, 0x7f, 0xfd, 0xc7, - 0xbf, 0xff, 0x7f, 0xff, 0xf7, 0xbf, 0x62, 0xa6, 0xb2, 0x3c, 0x17, 0xa1, 0xad, 0x65, 0x55, 0x87, 0x22, 0x62, 0x8f, - 0x59, 0x95, 0x13, 0x52, 0x4f, 0xb9, 0xdd, 0xa7, 0x09, 0x89, 0x41, 0x25, 0x74, 0xc4, 0xe7, 0x94, 0xa2, 0x4d, 0x54, - 0xbb, 0x86, 0x7c, 0xb0, 0x94, 0x16, 0x1d, 0xf5, 0xdb, 0x3b, 0x6d, 0xbb, 0x5a, 0xde, 0xbe, 0xd1, 0x77, 0x0b, 0x17, - 0xe6, 0x56, 0x89, 0x39, 0xbe, 0x5e, 0xb6, 0xa5, 0x0a, 0x6d, 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x73, 0x5e, 0xe2, - 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0x95, 0x6b, 0x7d, 0x7a, 0xbf, 0x2c, 0x00, 0xd1, 0x09, 0x2e, 0x8d, 0x08, 0xa0, 0xd1, - 0x79, 0x6a, 0x0b, 0xad, 0x95, 0xe4, 0xa2, 0xa4, 0x51, 0x84, 0x87, 0x73, 0xff, 0xd1, 0xdf, 0x96, 0x7f, 0x9e, 0xa1, - 0x95, 0x60, 0x39, 0xb3, 0xe8, 0x5c, 0xfa, 0x3d, 0x0f, 0xda, 0xed, 0xf9, 0xb9, 0xbb, 0xac, 0x66, 0xf0, 0xae, 0x9a, - 0x8c, 0x82, 0x6e, 0xe6, 0x80, 0x74, 0x10, 0xab, 0xe3, 0x7b, 0x60, 0xea, 0xb7, 0x31, 0x1c, 0x54, 0x96, 0x7f, 0x5a, - 0x52, 0x88, 0x29, 0xfe, 0x0d, 0x0f, 0x4c, 0x65, 0x34, 0x0e, 0x4a, 0x0c, 0x2c, 0x96, 0x46, 0xaf, 0xae, 0xe8, 0x35, - 0xed, 0xac, 0xa6, 0xac, 0x98, 0x07, 0xbe, 0xe6, 0x51, 0xed, 0x7d, 0x3c, 0x7c, 0x9d, 0x76, 0xbc, 0x69, 0x77, 0xa9, - 0x87, 0xe7, 0x3c, 0x9b, 0x99, 0x27, 0xbc, 0x2c, 0x62, 0x23, 0x36, 0x51, 0x51, 0x4c, 0x59, 0x2f, 0x4e, 0x6f, 0xcb, - 0x2f, 0x70, 0xbb, 0x01, 0x6d, 0xb3, 0x88, 0x07, 0xc4, 0xb4, 0x3d, 0xf3, 0x0c, 0x38, 0xc2, 0xd3, 0xf5, 0x6c, 0x69, - 0xcc, 0xd5, 0x13, 0x4d, 0x31, 0x56, 0x58, 0x4f, 0x07, 0x2a, 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0x42, 0x0d, 0xbf, 0xca, - 0xa3, 0xd5, 0x77, 0x35, 0x1f, 0x5d, 0x8a, 0x66, 0x70, 0x8b, 0xd7, 0xd6, 0x0b, 0x35, 0x29, 0x6a, 0x3f, 0x80, 0xf5, - 0x43, 0x60, 0xda, 0xcd, 0x56, 0x54, 0x88, 0xad, 0xde, 0x85, 0xbf, 0x6a, 0x7b, 0x3c, 0x9a, 0xcf, 0xa9, 0xa1, 0x0b, - 0xdc, 0x48, 0x76, 0x35, 0x4a, 0x0a, 0x4a, 0x1b, 0x10, 0xa7, 0xf4, 0xb2, 0x8d, 0x64, 0x5b, 0xf1, 0x24, 0xcf, 0xef, - 0xe9, 0x57, 0x8c, 0xff, 0x7f, 0x2a, 0xa5, 0xd0, 0x17, 0x78, 0x7c, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, + 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x28, 0x58, 0x5d, 0x05, 0x5c, 0x81, 0x10, 0x49, 0x95, 0xaa, 0xca, 0xa0, 0x40, 0x5e, + 0xd5, 0x62, 0x57, 0xd9, 0xb5, 0xb9, 0xa4, 0xb2, 0xaf, 0x2d, 0xeb, 0x4a, 0x10, 0x99, 0x14, 0xe1, 0x02, 0x01, 0x1a, + 0x48, 0x6a, 0x31, 0x85, 0x3e, 0xfd, 0xd4, 0x4f, 0x7d, 0xce, 0x6c, 0xfd, 0xd0, 0x0f, 0xd3, 0xa7, 0xfb, 0x61, 0x3e, + 0x62, 0x9e, 0xfb, 0x53, 0xee, 0x0f, 0x4c, 0x7f, 0xc2, 0x44, 0x44, 0x2e, 0x48, 0x80, 0xa4, 0x24, 0xbb, 0x7d, 0xe7, + 0x78, 0x11, 0x90, 0x6b, 0x44, 0x64, 0x64, 0x6c, 0x19, 0x09, 0xee, 0xde, 0x1b, 0x65, 0x43, 0x7e, 0x35, 0x63, 0xd6, + 0x84, 0x4f, 0x93, 0xfe, 0xae, 0xfc, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, 0x78, + 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, 0x53, + 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, 0xc7, + 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, 0xfe, + 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, 0xc4, + 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, 0x8b, + 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, 0x4f, + 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, 0x69, + 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf3, 0xb8, 0x17, 0xbb, 0x61, 0x9f, 0x5b, 0x71, 0x6a, 0xb1, 0xc1, 0x0b, 0x46, 0x25, + 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, 0x7c, + 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xb0, 0x43, 0x7e, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, 0x8c, + 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbf, 0xbe, 0x76, 0x78, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, 0x51, + 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xfc, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, 0x99, + 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xee, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, 0xe9, + 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, 0x28, + 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, 0x0c, + 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, 0xc0, + 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, 0x90, + 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, 0xbe, + 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, 0x58, + 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, 0xc6, + 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdf, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, 0xb3, + 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, 0x05, + 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, 0x41, + 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xac, 0x04, + 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0x60, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, 0x9c, + 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x06, 0x9a, 0x38, 0xd0, 0xb6, 0x68, 0xb4, 0xf5, 0x04, 0xe2, 0x35, 0x12, 0xb9, 0x1e, + 0xf3, 0x25, 0xf9, 0xf6, 0xaf, 0xd2, 0x61, 0x7d, 0x6c, 0xa8, 0x2c, 0x79, 0xb6, 0xcf, 0xf3, 0x38, 0x3d, 0x03, 0x20, + 0xe4, 0x4c, 0x66, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x2c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, 0x7a, + 0xd8, 0x61, 0x88, 0xa4, 0x07, 0x06, 0x63, 0x03, 0x16, 0xb0, 0x4d, 0xdb, 0xf6, 0xbe, 0x73, 0xbd, 0x2b, 0xe4, 0x20, + 0xdf, 0xf7, 0x89, 0x7d, 0x45, 0xe7, 0x38, 0xec, 0x20, 0xd0, 0x7e, 0xc2, 0xd2, 0x33, 0x3e, 0x19, 0xb0, 0xc3, 0xf6, + 0x51, 0xc0, 0x01, 0xaa, 0xd1, 0x7c, 0xc8, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, + 0xf7, 0x08, 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, 0x70, + 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, 0x37, + 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0xe7, 0xc8, 0x43, + 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0x98, 0xbf, 0xcc, 0xc7, + 0x21, 0xf7, 0xa7, 0xd1, 0x0c, 0xb1, 0x61, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, + 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, 0x39, + 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, + 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, 0x73, + 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, 0xd5, + 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, 0xc0, + 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x87, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, 0x19, + 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xf2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, 0xd0, + 0x9f, 0x81, 0x0c, 0xec, 0xa1, 0xe0, 0xfa, 0x4a, 0x4a, 0x9d, 0x88, 0x29, 0x0c, 0x81, 0x00, 0x43, 0x94, 0x20, 0x92, + 0x06, 0xef, 0xb3, 0xe4, 0x6a, 0x1c, 0x27, 0xc9, 0xfe, 0x7c, 0x36, 0xcb, 0x72, 0xee, 0x7d, 0x1d, 0x2e, 0x78, 0x56, + 0xe1, 0x4a, 0x9b, 0xbc, 0xb8, 0x88, 0x39, 0x12, 0xd4, 0x5d, 0x0c, 0x23, 0x58, 0xea, 0xa7, 0x59, 0x96, 0xb0, 0x28, + 0x05, 0x34, 0xd8, 0xc0, 0xb6, 0x83, 0x74, 0x9e, 0x24, 0xbd, 0x53, 0x18, 0xf6, 0x53, 0x8f, 0xaa, 0x85, 0xc4, 0x0f, + 0xe8, 0x79, 0x2f, 0xcf, 0xa3, 0x2b, 0x68, 0x88, 0x6d, 0x80, 0x17, 0x61, 0xb5, 0xbe, 0xda, 0x7f, 0xf7, 0xd6, 0x17, + 0x8c, 0x1f, 0x8f, 0xaf, 0x00, 0xd0, 0xb2, 0x92, 0x9a, 0xe3, 0x3c, 0x9b, 0x36, 0xa6, 0x46, 0x3a, 0xc4, 0x21, 0xeb, + 0xad, 0x01, 0x21, 0xa6, 0x91, 0x61, 0x95, 0x98, 0x09, 0xc1, 0x5b, 0xe2, 0x67, 0x59, 0x89, 0x7b, 0x60, 0x80, 0x0f, + 0x81, 0x28, 0x86, 0x29, 0x6f, 0x86, 0x96, 0xe7, 0x57, 0x8b, 0x38, 0x24, 0x38, 0x67, 0xa8, 0x7f, 0x11, 0xc6, 0x61, + 0x04, 0xb3, 0x2f, 0xc4, 0x80, 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xa2, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x0e, + 0xdb, 0xe8, 0xfa, 0x9a, 0xc1, 0x8b, 0xeb, 0x7d, 0x13, 0x2e, 0x22, 0x85, 0x0f, 0x6a, 0x28, 0xdc, 0x5f, 0x81, 0x90, + 0x13, 0xa8, 0xc9, 0xce, 0x41, 0x0f, 0x02, 0x9c, 0x5f, 0x83, 0xfa, 0x1b, 0x27, 0x08, 0xc5, 0xbd, 0x8e, 0x07, 0x1a, + 0xf4, 0xd9, 0x24, 0x4a, 0xcf, 0xd8, 0x28, 0x98, 0xb0, 0x52, 0x4a, 0xde, 0x3d, 0x0b, 0xd6, 0x18, 0xd8, 0xa9, 0xb0, + 0x5e, 0x1e, 0xbc, 0x79, 0x2d, 0x57, 0xae, 0x26, 0x8c, 0x61, 0x91, 0xe6, 0xa0, 0x56, 0x41, 0x6c, 0x4b, 0x71, 0xfc, + 0x82, 0x2b, 0xe9, 0x2d, 0x4a, 0xe2, 0xe2, 0xe3, 0x0c, 0x4c, 0x0c, 0xf6, 0x1e, 0x86, 0x81, 0xe9, 0x43, 0x98, 0x8a, + 0xca, 0x61, 0x3e, 0x51, 0x31, 0xd2, 0x45, 0xd0, 0x59, 0x60, 0x2a, 0x5e, 0x33, 0xc7, 0x2d, 0x81, 0x55, 0x79, 0x3c, + 0xb4, 0xa2, 0xd1, 0xe8, 0x55, 0x1a, 0xf3, 0x38, 0x4a, 0xe2, 0x5f, 0x88, 0x92, 0x0b, 0xe4, 0x31, 0xde, 0x93, 0x8b, + 0x00, 0xb8, 0x53, 0x8f, 0xc4, 0x55, 0x42, 0xf6, 0x1e, 0x11, 0x43, 0x48, 0xcb, 0x24, 0x3c, 0x3c, 0x92, 0xe0, 0x25, + 0xfe, 0x6c, 0x5e, 0x4c, 0x90, 0xb0, 0x72, 0x60, 0x14, 0xe4, 0xd9, 0x69, 0xc1, 0xf2, 0x73, 0x36, 0xd2, 0x1c, 0x50, + 0x00, 0x56, 0xd4, 0x1c, 0x8c, 0x17, 0x9a, 0xd1, 0x51, 0x3a, 0x94, 0xc1, 0x50, 0x3d, 0x53, 0xcc, 0x32, 0xc9, 0xcc, + 0xda, 0xc2, 0xd1, 0x52, 0xc0, 0x11, 0x46, 0x85, 0x94, 0x04, 0x79, 0xa8, 0x30, 0x9c, 0x80, 0x14, 0x02, 0xad, 0x60, + 0x6e, 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, + 0xca, 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x8d, 0xd0, 0x85, 0x3e, 0xb6, 0x20, 0x36, 0xf0, + 0xf5, 0xca, 0x03, 0x61, 0x25, 0xde, 0x15, 0x22, 0xde, 0x1a, 0xb0, 0x71, 0x62, 0xe4, 0x27, 0xef, 0x1e, 0xf7, 0xd3, + 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, 0x67, + 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, 0xcb, + 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, 0x5d, + 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, 0x85, + 0x4d, 0x41, 0x80, 0x1e, 0xb2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, 0xac, + 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, 0x2b, + 0x90, 0x93, 0x6f, 0x66, 0x27, 0x84, 0x95, 0xb9, 0xd7, 0xd7, 0xdf, 0xa8, 0x41, 0xaa, 0xa5, 0xd4, 0x36, 0x50, 0x63, + 0x4d, 0x6c, 0xd5, 0x64, 0x64, 0xbb, 0x52, 0xa1, 0xde, 0xeb, 0xf4, 0x6a, 0x7c, 0x00, 0x7b, 0xae, 0xad, 0x59, 0xba, + 0x32, 0xb6, 0xdf, 0x2b, 0x9a, 0xbe, 0x13, 0x23, 0x93, 0x35, 0xca, 0x6e, 0xe7, 0x1e, 0xb5, 0xe3, 0xa1, 0xed, 0x52, + 0x5d, 0x25, 0x18, 0xe6, 0x75, 0xc1, 0xd0, 0x84, 0x7a, 0xa6, 0xbb, 0xd8, 0x9a, 0xa9, 0x58, 0xa8, 0xd6, 0x5a, 0x39, + 0x10, 0x3c, 0x3c, 0x04, 0xe3, 0x64, 0xa5, 0x7f, 0xf0, 0x36, 0x9a, 0x32, 0xa4, 0xa8, 0xb7, 0xae, 0x81, 0x74, 0x20, + 0xa0, 0xc9, 0x51, 0x53, 0xbd, 0x71, 0x57, 0x58, 0x4d, 0xf5, 0xfd, 0x15, 0x83, 0x15, 0x01, 0xf6, 0x75, 0xb9, 0x62, + 0x89, 0x48, 0x6f, 0x0a, 0x2e, 0xd1, 0xf4, 0x11, 0x65, 0x62, 0x4d, 0x48, 0xc1, 0x03, 0xf2, 0xb0, 0xfc, 0x8d, 0x85, + 0x93, 0xad, 0x98, 0xc2, 0x91, 0xa3, 0x4c, 0x01, 0x3a, 0x93, 0x12, 0x00, 0x71, 0x49, 0x7f, 0x6b, 0x1b, 0x0b, 0xc9, + 0xb6, 0x8f, 0x7c, 0xe0, 0x8f, 0x93, 0x88, 0x3b, 0x9d, 0xad, 0xb6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, + 0xf7, 0x15, 0x2a, 0x8c, 0xbc, 0x05, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe2, 0x31, 0x77, 0x12, 0x54, 0x22, 0x6e, 0xc9, + 0x12, 0x50, 0x32, 0x7a, 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, + 0x0b, 0x2a, 0x08, 0x0c, 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x25, 0x8b, 0x32, 0x1e, + 0xc4, 0xcb, 0x85, 0xa0, 0x86, 0x7d, 0x9e, 0xbd, 0xce, 0x2e, 0x58, 0xfe, 0x2c, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, + 0x49, 0x4f, 0x02, 0x9d, 0xf5, 0x14, 0xaf, 0x9c, 0x13, 0xd2, 0xb0, 0x10, 0xd3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, + 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, 0xe2, + 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, 0xe9, + 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, + 0x8b, 0xbc, 0xb8, 0xe7, 0x34, 0xd4, 0x11, 0x40, 0x31, 0xad, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, + 0x8d, 0xbc, 0xaa, 0x89, 0x80, 0x38, 0x1d, 0xb1, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, + 0x81, 0x84, 0x57, 0x08, 0x80, 0x79, 0xe2, 0x4f, 0xb2, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xfa, 0x3a, 0x16, 0xfe, + 0x22, 0x32, 0x40, 0xce, 0xa6, 0xd9, 0x39, 0x5b, 0x01, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, + 0x54, 0xcb, 0x2c, 0x89, 0x87, 0x4c, 0x6b, 0xa9, 0xa9, 0x0f, 0x06, 0x1d, 0xbb, 0x04, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, + 0xdf, 0xf6, 0x3a, 0x6e, 0x29, 0x08, 0xbe, 0x58, 0xa2, 0xe8, 0x0d, 0xfa, 0x51, 0x9a, 0xe0, 0xab, 0x64, 0x01, 0x77, + 0x0d, 0xa5, 0xc8, 0x85, 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, + 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, + 0x5a, 0x89, 0x54, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, + 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, + 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, + 0xb6, 0x51, 0xc0, 0x21, 0x5b, 0x62, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0xdc, + 0xc0, 0x72, 0x5c, 0x49, 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8a, 0x8b, 0xf5, 0x24, + 0xf8, 0x5d, 0xc1, 0x7c, 0x6e, 0xcc, 0x74, 0x2b, 0xa4, 0x5a, 0xc2, 0x49, 0x33, 0x58, 0x83, 0x26, 0x8d, 0x07, 0x25, + 0x6a, 0xbe, 0x46, 0x43, 0x85, 0x38, 0xfe, 0x4c, 0x54, 0xa1, 0x09, 0x86, 0x60, 0xe4, 0x5e, 0x21, 0x19, 0x2e, 0x5b, + 0x16, 0x2d, 0x52, 0xa6, 0xc6, 0xa4, 0x52, 0x35, 0xcb, 0x65, 0x60, 0x60, 0xd1, 0x6e, 0xf5, 0xa5, 0x25, 0xae, 0x44, + 0x6e, 0x1a, 0x6a, 0x61, 0x52, 0x28, 0x6f, 0xc2, 0xc9, 0xd1, 0xef, 0x52, 0xd6, 0xbb, 0x89, 0x4f, 0xae, 0xf0, 0xc9, + 0x7d, 0xc3, 0x87, 0x32, 0x79, 0xbb, 0x18, 0x14, 0xc1, 0xd7, 0xb5, 0x4a, 0xb4, 0x4f, 0x7d, 0x14, 0xcc, 0xae, 0x16, + 0xba, 0x20, 0x50, 0x24, 0x9b, 0xa4, 0x03, 0xc9, 0x6f, 0x28, 0x36, 0x2a, 0xcf, 0x28, 0x73, 0xc5, 0x06, 0xa9, 0x79, + 0xa5, 0x99, 0x97, 0xba, 0x0d, 0xfb, 0xbd, 0x2c, 0x25, 0x9d, 0xb8, 0xa0, 0x4c, 0xec, 0xdd, 0x44, 0x1b, 0x2f, 0x0d, + 0x33, 0x61, 0xfd, 0x0a, 0x63, 0xa7, 0x46, 0xa1, 0x54, 0x8a, 0x40, 0x1c, 0x1b, 0x5f, 0x2b, 0xcb, 0x20, 0xf3, 0x57, + 0xd8, 0x53, 0x00, 0x4a, 0x02, 0x8b, 0xaf, 0xa9, 0xe4, 0x45, 0x61, 0x9d, 0x8e, 0xf7, 0x88, 0x8e, 0x95, 0x08, 0xad, + 0x89, 0x7c, 0xad, 0xcf, 0x62, 0xbf, 0xe6, 0x12, 0x9a, 0x94, 0xcc, 0x07, 0x79, 0x60, 0xab, 0x40, 0x44, 0xa5, 0xdb, + 0x92, 0x41, 0x42, 0x0e, 0xe9, 0x32, 0xd1, 0x6b, 0x23, 0x19, 0xb4, 0x4e, 0x85, 0x44, 0x4b, 0x8f, 0xc2, 0xc8, 0x41, + 0xc7, 0x9d, 0xd6, 0x62, 0x89, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, + 0x0e, 0xa0, 0x03, 0x62, 0x7f, 0x89, 0xf5, 0x56, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0xd7, 0xd7, 0x13, 0xe4, 0x07, + 0x61, 0xf0, 0xc2, 0x9a, 0x0d, 0x94, 0xec, 0xdd, 0x7b, 0x8d, 0xad, 0xc8, 0xfe, 0xac, 0x4a, 0x2a, 0x4f, 0xa1, 0xc6, + 0xb9, 0xf5, 0x75, 0x62, 0x66, 0x68, 0x51, 0x55, 0xec, 0x1b, 0x52, 0x7d, 0x5f, 0x29, 0xec, 0x0a, 0xe5, 0x7d, 0x39, + 0x74, 0xec, 0xba, 0x6e, 0x90, 0x93, 0xf3, 0x72, 0x6f, 0x95, 0x0b, 0x79, 0xff, 0xbe, 0xe9, 0x33, 0x9d, 0xeb, 0xe1, + 0x9f, 0x39, 0xa8, 0x9c, 0x8b, 0xab, 0x94, 0x2c, 0x98, 0x67, 0x4a, 0x1d, 0x2d, 0x39, 0xa0, 0xed, 0x1e, 0x7a, 0xda, + 0xd1, 0x45, 0x14, 0x73, 0x4b, 0x8f, 0x22, 0x3c, 0x6d, 0x94, 0x4f, 0xd2, 0xe8, 0x00, 0xbc, 0xd0, 0x84, 0x24, 0x27, + 0xdc, 0xb4, 0x45, 0x8b, 0xe1, 0x84, 0x61, 0x08, 0x5c, 0xd9, 0x13, 0xa6, 0xec, 0xb9, 0x87, 0x78, 0x8b, 0x81, 0xd9, + 0x6a, 0xd8, 0xcb, 0x66, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, 0x04, 0xb2, 0x6d, 0xaa, 0xea, 0xca, 0xc6, 0xbb, 0x14, 0x91, + 0x18, 0x61, 0x5b, 0x35, 0xb6, 0xb4, 0xf5, 0x7b, 0x0d, 0xf7, 0xba, 0x72, 0xcc, 0x6b, 0x4a, 0xb5, 0xa1, 0x87, 0x95, + 0x9b, 0xc3, 0x4c, 0x47, 0x5e, 0xac, 0xa0, 0xdb, 0x13, 0x41, 0x21, 0x70, 0x22, 0xb4, 0x3d, 0xa8, 0xb8, 0x81, 0x48, + 0xc9, 0x95, 0x56, 0xcd, 0xe6, 0xc9, 0x48, 0x02, 0x0b, 0x2e, 0x2c, 0x97, 0x7c, 0x74, 0x11, 0x27, 0x49, 0x55, 0xfa, + 0xbb, 0x0a, 0x78, 0x31, 0xec, 0x6d, 0xa2, 0x5d, 0x60, 0x34, 0x57, 0x20, 0xb8, 0xda, 0x08, 0xfb, 0xe8, 0xb8, 0xd5, + 0xba, 0x8b, 0x88, 0x23, 0x37, 0xa3, 0x11, 0x50, 0x8f, 0x11, 0x56, 0xcd, 0xda, 0x7b, 0x2f, 0x30, 0xa4, 0x66, 0xe0, + 0x83, 0xea, 0x8c, 0x8a, 0x7f, 0x95, 0x3d, 0xf5, 0x2b, 0xd1, 0xbb, 0x55, 0x75, 0x35, 0x03, 0x2a, 0x2a, 0xf0, 0x61, + 0x86, 0x58, 0xda, 0x2a, 0x10, 0x90, 0xeb, 0x61, 0x51, 0x0a, 0x98, 0xa4, 0xc1, 0x82, 0x52, 0x60, 0xad, 0x95, 0xdd, + 0xeb, 0xdb, 0x82, 0x39, 0x14, 0x0a, 0x17, 0xfd, 0x9f, 0x65, 0xd3, 0x19, 0x5a, 0x66, 0x0d, 0xa6, 0x86, 0x06, 0x1f, + 0x1b, 0xf5, 0xe5, 0x8a, 0xb2, 0x5a, 0x1f, 0xda, 0x91, 0x35, 0x7e, 0xd2, 0x8e, 0x32, 0x38, 0x54, 0x73, 0x5d, 0x54, + 0xb7, 0x9b, 0x9b, 0x22, 0x66, 0x15, 0x8f, 0xfb, 0xa4, 0xb7, 0xb5, 0x35, 0xe9, 0x69, 0x1a, 0x90, 0x4c, 0x92, 0x0c, + 0x6f, 0x32, 0x40, 0x59, 0x11, 0x67, 0x51, 0x36, 0xc8, 0xb7, 0x28, 0x4b, 0x5c, 0xbf, 0x1f, 0x7a, 0x7b, 0x35, 0xcf, + 0xda, 0xdb, 0x5b, 0xef, 0x22, 0x57, 0x75, 0xd2, 0x83, 0x3c, 0x3c, 0x82, 0xa2, 0x25, 0x9b, 0x32, 0x5c, 0x4c, 0xb3, + 0x11, 0x0b, 0x6c, 0xe8, 0x9e, 0xda, 0xa5, 0xdc, 0x34, 0x11, 0x6c, 0x8e, 0x88, 0x39, 0x8b, 0x0f, 0xf5, 0x48, 0x6a, + 0xb0, 0x07, 0x2c, 0xa0, 0xcd, 0x85, 0xaf, 0xc2, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x03, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, + 0x05, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, 0x7d, 0x35, 0xf8, 0x2a, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x1d, 0xbf, + 0xed, 0x77, 0x6c, 0x15, 0x11, 0xfb, 0xc9, 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x00, 0x4d, 0x56, 0x78, 0x43, + 0x16, 0xfe, 0x34, 0xf8, 0x49, 0xb9, 0xd4, 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe1, 0x79, 0xa4, 0xed, + 0x2d, 0x44, 0x05, 0xc6, 0x15, 0x29, 0x2e, 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xc6, 0xc6, 0xc2, + 0x79, 0x13, 0xf1, 0x89, 0x9f, 0x47, 0xe9, 0x28, 0x9b, 0x3a, 0xee, 0xa6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0xe7, + 0x6e, 0xb9, 0x71, 0x02, 0x7e, 0x40, 0x68, 0x0f, 0xec, 0xcd, 0x63, 0xef, 0x80, 0x85, 0x27, 0xbb, 0x1b, 0x8b, 0x11, + 0x2b, 0xfb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7f, 0x29, 0xc1, 0x00, 0x76, + 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0xfb, 0x9e, + 0x76, 0x56, 0xef, 0xdf, 0xaf, 0xd4, 0x7c, 0x55, 0xea, 0xcd, 0x59, 0x58, 0xf3, 0xd4, 0xbd, 0x97, 0x74, 0xb4, 0x52, + 0xdf, 0xc8, 0x73, 0x46, 0x4a, 0x73, 0xd9, 0x4e, 0x70, 0x8c, 0x2d, 0xbe, 0x7a, 0x5b, 0x1f, 0x8a, 0x28, 0x85, 0x1f, + 0x83, 0xf5, 0x12, 0x81, 0xfa, 0x06, 0x07, 0xc7, 0x3b, 0x08, 0xb7, 0x76, 0x9d, 0x41, 0xe0, 0xdc, 0x6b, 0xb5, 0xae, + 0x7f, 0xdc, 0x3a, 0xfc, 0x73, 0xd4, 0xfa, 0x65, 0xaf, 0xf5, 0xc3, 0x91, 0x7b, 0xed, 0xfc, 0xb8, 0x35, 0x38, 0x94, + 0x6f, 0x87, 0x7f, 0xee, 0xff, 0x58, 0x1c, 0xfd, 0x41, 0x14, 0x6e, 0xb8, 0xee, 0xd6, 0x99, 0x37, 0x63, 0xe1, 0x56, + 0xab, 0xd5, 0x87, 0xa7, 0x33, 0x78, 0xc2, 0xbf, 0x17, 0xf0, 0xe7, 0xfa, 0xd0, 0xfa, 0x4f, 0x3f, 0xa6, 0xff, 0xf9, + 0xc7, 0xfc, 0x08, 0xc7, 0x3c, 0xfc, 0xf3, 0x8f, 0x85, 0xfd, 0xa0, 0x1f, 0x6e, 0x1d, 0x6d, 0xba, 0x8e, 0xae, 0xf9, + 0x43, 0x58, 0x3d, 0x42, 0xab, 0xc3, 0x3f, 0xcb, 0x37, 0xfb, 0xc1, 0xc9, 0x6e, 0x3f, 0x3c, 0xba, 0x76, 0xec, 0xeb, + 0x07, 0xee, 0xb5, 0xeb, 0x5e, 0x6f, 0xe0, 0x3c, 0xe7, 0x30, 0xfa, 0x03, 0xf8, 0x3b, 0x86, 0xbf, 0x36, 0xfc, 0x9d, + 0xc2, 0xdf, 0x3f, 0x43, 0x37, 0x11, 0x7f, 0xbb, 0xa6, 0x58, 0xc8, 0x35, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, + 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0x71, 0xbc, 0x01, 0x8b, 0x8e, 0x9c, + 0xb3, 0x11, 0x30, 0x4f, 0x44, 0x0e, 0x8a, 0x80, 0x8b, 0xb3, 0xd5, 0x02, 0x0f, 0x57, 0xbd, 0x61, 0xb8, 0xc1, 0x1c, + 0x30, 0x0a, 0xde, 0x32, 0x7c, 0xe8, 0xba, 0xde, 0x0b, 0x79, 0x66, 0x88, 0xfb, 0x5c, 0xb0, 0x56, 0x9a, 0x09, 0x93, + 0xc6, 0x76, 0xbd, 0xd9, 0x8a, 0x4a, 0xd8, 0xd6, 0xe9, 0x19, 0xd4, 0x9d, 0x8a, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, + 0xb7, 0xe4, 0x1b, 0xe3, 0x10, 0x78, 0xc9, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xa7, 0x0c, 0x66, + 0x58, 0x32, 0x11, 0x39, 0x29, 0x4d, 0x61, 0xd9, 0xc2, 0xe4, 0xef, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, + 0x64, 0x9b, 0x96, 0xfe, 0x1d, 0xa6, 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xeb, 0x70, + 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, 0x9f, 0xf3, 0x1e, 0xd5, 0x18, 0xfc, 0x2b, 0xc3, 0x0c, 0x9e, 0x98, 0x0f, 0x43, + 0x34, 0x8b, 0x52, 0x07, 0xb7, 0x52, 0x14, 0xf7, 0xaf, 0x70, 0x67, 0xa4, 0xa5, 0xb7, 0x1f, 0xaa, 0x1d, 0x73, 0x90, + 0x33, 0xf6, 0x5d, 0x94, 0x7c, 0x62, 0xb9, 0x73, 0xe9, 0x75, 0xba, 0x9f, 0x53, 0x67, 0x0f, 0x6d, 0xb3, 0x0f, 0xd5, + 0x31, 0x9a, 0x32, 0x0b, 0xd4, 0x11, 0x61, 0xab, 0xe3, 0xe5, 0x18, 0xd5, 0x42, 0x12, 0x14, 0x5e, 0x16, 0x76, 0x89, + 0xc3, 0xed, 0xdd, 0xe2, 0xfc, 0xac, 0x6f, 0x07, 0xb6, 0x0d, 0x16, 0xff, 0x01, 0x85, 0xad, 0x84, 0x61, 0x01, 0x06, + 0xd9, 0x6e, 0xdc, 0xe3, 0x9b, 0x9b, 0x55, 0xc0, 0x09, 0x0f, 0xd2, 0xa9, 0x7b, 0xe2, 0x45, 0xde, 0x24, 0x84, 0x01, + 0x87, 0xd0, 0x0c, 0xbb, 0xf4, 0x86, 0xbb, 0xb1, 0x9c, 0x06, 0x63, 0x21, 0x7e, 0x12, 0x15, 0xfc, 0x15, 0xc6, 0x23, + 0xc2, 0x21, 0x1a, 0xfb, 0x3e, 0xbb, 0x64, 0x43, 0x65, 0x67, 0x00, 0xa1, 0x22, 0xb7, 0xe7, 0x0e, 0x43, 0xa3, 0x19, + 0xcc, 0x1d, 0x86, 0x07, 0x03, 0x1b, 0xf6, 0x12, 0xec, 0xca, 0x30, 0x3a, 0xec, 0x1c, 0x0d, 0xd2, 0x70, 0xc6, 0x02, + 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0xea, 0x1e, 0x0d, 0x9c, 0x29, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x86, 0x11, + 0x8a, 0x22, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0xce, 0x1c, 0x7b, 0x77, 0xcb, 0xde, 0xc4, 0x52, 0xcf, 0x06, 0xf6, 0x82, + 0xb9, 0xc3, 0x0b, 0xd7, 0xec, 0xbc, 0x7d, 0x84, 0xa0, 0x62, 0x21, 0x4e, 0x7e, 0x31, 0xb0, 0xfb, 0x62, 0xea, 0x36, + 0x0c, 0x9a, 0xca, 0xe5, 0xc7, 0x15, 0x3d, 0x20, 0x54, 0x55, 0x57, 0x05, 0x1d, 0x94, 0x75, 0x03, 0x67, 0x62, 0x22, + 0xd1, 0xc2, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, 0x30, 0xa9, 0xd1, 0x6d, 0xfb, 0x68, 0x70, 0x11, 0x3c, 0xb0, + 0x1f, 0xa8, 0x97, 0x31, 0x20, 0xc3, 0xc4, 0xf4, 0x63, 0x90, 0x76, 0xf8, 0xf7, 0x9c, 0x01, 0x92, 0x17, 0x54, 0x34, + 0x93, 0x45, 0x67, 0x58, 0x74, 0x10, 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xa3, 0x90, 0x60, 0xbf, 0x7f, + 0x1f, 0x96, 0x66, 0xb3, 0x73, 0x84, 0xe7, 0x0d, 0x39, 0x2f, 0xbe, 0x8b, 0x39, 0xa8, 0x84, 0xad, 0xbe, 0xed, 0x0e, + 0x6c, 0x0b, 0x97, 0xb6, 0x97, 0x6d, 0x86, 0x82, 0xc2, 0xf1, 0xe6, 0x01, 0x0b, 0x26, 0xfd, 0xb0, 0x3d, 0x70, 0x72, + 0x19, 0x6e, 0xc4, 0x73, 0x4b, 0x21, 0xc1, 0xdb, 0xde, 0x04, 0x04, 0x3a, 0x72, 0xee, 0x86, 0xbd, 0xa9, 0x0a, 0xa1, + 0xe8, 0x78, 0x73, 0xe4, 0x06, 0x31, 0xfc, 0x71, 0x5a, 0xc8, 0x34, 0x13, 0xdd, 0x57, 0x6b, 0x66, 0x37, 0x18, 0x29, + 0x8b, 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, + 0xb1, 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, + 0x47, 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf3, 0x0c, 0x09, 0xc5, 0x4b, 0xed, 0x86, 0x09, + 0x73, 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, + 0xbd, 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, + 0xe1, 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, + 0x02, 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x71, 0xe9, 0xda, + 0xa3, 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, + 0xbf, 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, + 0x60, 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, + 0x46, 0xe0, 0x39, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, + 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, + 0xdc, 0x82, 0x18, 0x87, 0x1b, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, + 0x8a, 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, + 0x52, 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, + 0x36, 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x39, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, + 0xf4, 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, + 0xa2, 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xb9, 0xf9, 0x52, 0xcc, 0x86, 0xbb, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, + 0xd1, 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x4b, 0xcc, 0xd9, 0x6f, 0x83, 0x0d, + 0x5e, 0xcb, 0x3b, 0x40, 0xfb, 0x8e, 0x4d, 0x67, 0xfc, 0x6a, 0x9f, 0x14, 0x7d, 0x20, 0xd3, 0x06, 0xc4, 0xd9, 0x79, + 0xbb, 0x17, 0xef, 0xf2, 0x5e, 0x0c, 0x52, 0x3d, 0x57, 0x2c, 0x86, 0x7b, 0xd5, 0x7b, 0x8f, 0x51, 0x4a, 0x93, 0x99, + 0xbc, 0x1a, 0x7a, 0x5d, 0x89, 0xde, 0xe6, 0x26, 0x20, 0xd8, 0x33, 0xba, 0x72, 0xd1, 0xb5, 0x2c, 0x05, 0x4d, 0x00, + 0xa2, 0x27, 0x75, 0x96, 0x23, 0x8e, 0xc3, 0x6c, 0x36, 0x28, 0x1e, 0x31, 0x77, 0xe5, 0xa8, 0x38, 0x26, 0x76, 0x97, + 0x09, 0x3b, 0x80, 0x19, 0x71, 0x79, 0xab, 0x23, 0xa2, 0xc3, 0xa2, 0xbf, 0x8e, 0x6f, 0x1f, 0x7b, 0x6c, 0xb3, 0xe3, + 0x82, 0x06, 0xa9, 0x8d, 0xf5, 0xb8, 0x1a, 0x0b, 0xea, 0xc3, 0x63, 0x4d, 0xa5, 0xb2, 0xd8, 0xdc, 0x2c, 0xeb, 0x47, + 0xb5, 0x6a, 0x07, 0xd7, 0x4e, 0x53, 0x2e, 0x9b, 0xd9, 0x20, 0x1c, 0x88, 0x98, 0x40, 0x81, 0x96, 0x56, 0x56, 0x0c, + 0x30, 0xa4, 0x2c, 0x47, 0xf9, 0x14, 0x32, 0x2f, 0x2e, 0x4b, 0x9d, 0xfa, 0xf2, 0x4c, 0x06, 0x1d, 0xf1, 0xd4, 0x93, + 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x0b, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, + 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, 0x0c, 0xda, 0xfe, 0x59, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x8f, + 0x02, 0xaa, 0x9f, 0x4b, 0x09, 0x36, 0x09, 0x3f, 0x02, 0x1b, 0x55, 0x8e, 0x27, 0x09, 0xc2, 0xe7, 0x71, 0xce, 0xc8, + 0x53, 0xd8, 0x90, 0x30, 0x4b, 0xd3, 0x36, 0x52, 0xed, 0x22, 0x33, 0x08, 0xe5, 0xc2, 0xfc, 0x13, 0xe3, 0xec, 0x22, + 0x0b, 0x97, 0x5a, 0x83, 0xf9, 0xf1, 0xce, 0x04, 0x28, 0xbb, 0xbe, 0xce, 0x84, 0x8f, 0x1b, 0x91, 0xbd, 0xa1, 0x2b, + 0x26, 0x03, 0x85, 0x54, 0xe0, 0x44, 0x64, 0xf1, 0xd0, 0x19, 0x0a, 0x8d, 0x70, 0x40, 0xa7, 0xc8, 0xb9, 0x6b, 0x6c, + 0xfa, 0x7c, 0xa0, 0x7d, 0xa3, 0x34, 0x74, 0x12, 0x10, 0x02, 0x02, 0x77, 0xc3, 0x9a, 0x4a, 0x07, 0x69, 0x90, 0x50, + 0x29, 0xfa, 0x39, 0x80, 0x7f, 0x18, 0x49, 0x0a, 0x80, 0xfd, 0x50, 0x8d, 0x14, 0x51, 0x96, 0x05, 0x2e, 0x00, 0xcd, + 0xb5, 0x8f, 0x2b, 0xe1, 0x0b, 0x03, 0x15, 0xa6, 0xa7, 0x59, 0x79, 0x29, 0x94, 0xc8, 0xd3, 0x15, 0x29, 0x6b, 0x24, + 0x93, 0xcf, 0xd1, 0xe1, 0x53, 0xde, 0xf5, 0x5b, 0x89, 0x87, 0x2e, 0x78, 0x0e, 0xcb, 0xaa, 0x9e, 0xdf, 0x84, 0x9c, + 0x9c, 0x6b, 0xd0, 0x15, 0x52, 0xe8, 0x2f, 0x39, 0xc9, 0x7b, 0x6f, 0xfc, 0xaa, 0x96, 0x1a, 0x43, 0xd9, 0xc7, 0x55, + 0xcd, 0xb0, 0xbc, 0x9c, 0x55, 0x61, 0x0a, 0x02, 0x6e, 0xc1, 0x92, 0x60, 0x21, 0x35, 0x04, 0x58, 0xd8, 0x1e, 0x69, + 0xa5, 0x20, 0x2f, 0x75, 0x78, 0xe7, 0x39, 0x58, 0x01, 0xc6, 0xa1, 0x96, 0x4a, 0xa6, 0x91, 0xc4, 0x97, 0x4a, 0x14, + 0x98, 0x72, 0x7f, 0x08, 0x7e, 0x6a, 0xf3, 0xa4, 0xeb, 0xd2, 0xf5, 0xe3, 0x29, 0xa6, 0xf6, 0x10, 0xe8, 0xb1, 0x77, + 0x0f, 0x4c, 0x89, 0xba, 0x0e, 0x2b, 0x88, 0x43, 0xb3, 0x9a, 0x66, 0x01, 0x33, 0xa6, 0x0d, 0x5a, 0xb2, 0x0d, 0xb6, + 0x5c, 0x0e, 0xf6, 0x91, 0xd8, 0x9e, 0xd5, 0x0a, 0x08, 0x5d, 0x83, 0x06, 0x86, 0xdc, 0xa5, 0x42, 0x0b, 0xf3, 0x5e, + 0x97, 0x8a, 0x70, 0x7f, 0x0e, 0xb8, 0xb4, 0x82, 0x33, 0x2f, 0xa3, 0x81, 0xf7, 0xe3, 0xd3, 0x04, 0x13, 0x5f, 0x10, + 0x2b, 0xb0, 0x83, 0x83, 0x4e, 0xb3, 0x29, 0x70, 0x2a, 0x2e, 0x52, 0x06, 0xcb, 0x8a, 0x52, 0x1b, 0xfe, 0x48, 0x91, + 0xad, 0xbb, 0x3c, 0xd2, 0x5d, 0x88, 0x05, 0xb0, 0xd3, 0x2f, 0x18, 0xf9, 0x96, 0xf5, 0x32, 0x60, 0x70, 0xae, 0x35, + 0x0e, 0x02, 0xbf, 0xb9, 0x99, 0x1c, 0x95, 0x29, 0xb1, 0x5d, 0x93, 0xd5, 0x05, 0xe4, 0x98, 0x04, 0xd8, 0xc0, 0x1d, + 0x84, 0xa5, 0xb2, 0xc7, 0x8b, 0x72, 0x8a, 0xcb, 0xa5, 0x2c, 0xe4, 0xe6, 0x79, 0x35, 0xcd, 0xe7, 0x56, 0x9a, 0x4d, + 0xc7, 0x5b, 0xf1, 0x45, 0xc1, 0x3f, 0x70, 0x62, 0x69, 0xd5, 0x53, 0x6a, 0x85, 0x47, 0x99, 0x5b, 0xb2, 0x4e, 0x49, + 0xad, 0xae, 0x1b, 0xa8, 0x46, 0x78, 0x9a, 0x86, 0x8d, 0x40, 0x88, 0x09, 0x2e, 0x7e, 0xdb, 0x64, 0x62, 0xda, 0x5b, + 0x42, 0xea, 0x08, 0xbb, 0x87, 0x72, 0x82, 0xbb, 0x9a, 0x67, 0x5f, 0x86, 0xb3, 0xf5, 0xcc, 0xbd, 0x67, 0x30, 0xf7, + 0xd3, 0x90, 0x1b, 0x8c, 0x1e, 0xcb, 0x84, 0x1f, 0x19, 0xfb, 0xc8, 0x55, 0xd5, 0xb3, 0xb3, 0xb0, 0x12, 0x59, 0xe2, + 0xc9, 0x38, 0xea, 0x30, 0x4e, 0x45, 0x6b, 0x82, 0xec, 0xfa, 0xba, 0x30, 0xf7, 0x02, 0x05, 0x4d, 0x3d, 0x5e, 0x8f, + 0xd3, 0x56, 0xec, 0x6c, 0x44, 0x22, 0xf7, 0xde, 0xd4, 0x22, 0x91, 0x15, 0x9f, 0xe3, 0x48, 0x6b, 0x0e, 0x72, 0x9f, + 0x9d, 0x2d, 0x6f, 0x52, 0xa1, 0x5b, 0x34, 0xda, 0xc6, 0x1e, 0xd5, 0x07, 0x92, 0x7a, 0x46, 0x05, 0x56, 0x35, 0xf6, + 0xfd, 0xfb, 0x1d, 0x91, 0x6e, 0xa9, 0x14, 0x1b, 0x2c, 0x2d, 0x8c, 0x66, 0x8c, 0x82, 0x41, 0x49, 0x91, 0x81, 0x1a, + 0xe5, 0x6b, 0x04, 0xc3, 0x1e, 0x35, 0x00, 0xc5, 0xb9, 0xba, 0xfa, 0x69, 0x29, 0xd9, 0x42, 0x40, 0xe2, 0x2e, 0x18, + 0x88, 0x35, 0xc1, 0xcc, 0xc8, 0x27, 0x1f, 0x81, 0xf3, 0x06, 0x0c, 0x1d, 0x03, 0xf0, 0x0b, 0xc4, 0xa6, 0x07, 0x13, + 0xdb, 0x26, 0xa2, 0xe8, 0xb3, 0x81, 0x97, 0x00, 0xec, 0xac, 0x0a, 0x8d, 0x7e, 0xa8, 0x52, 0xc0, 0x90, 0x0d, 0xdc, + 0x80, 0x55, 0x61, 0xb9, 0xbd, 0x97, 0xe0, 0x36, 0xc0, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xb3, 0x0b, + 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0x41, 0xa3, 0x5e, 0x51, 0x42, 0xd4, 0xee, 0x63, 0xed, 0x4b, 0x8c, 0xb0, 0x88, + 0xf7, 0x37, 0xf8, 0xae, 0xc7, 0x2d, 0xf7, 0x34, 0x5a, 0x84, 0xe9, 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, + 0xbd, 0xdc, 0x17, 0xb1, 0xe0, 0x0a, 0x47, 0x56, 0x85, 0x14, 0x1b, 0x48, 0xd2, 0xd3, 0x1e, 0x1d, 0xb0, 0x6f, 0x34, + 0x7b, 0x01, 0x65, 0x3e, 0x56, 0xa4, 0x92, 0x90, 0xd2, 0xec, 0x86, 0x48, 0x12, 0xd6, 0x8a, 0x3c, 0x75, 0xde, 0x77, + 0xb4, 0xcf, 0xad, 0x24, 0x82, 0x11, 0x9c, 0x84, 0xe9, 0x58, 0x79, 0xd0, 0x14, 0xe0, 0x2a, 0x3a, 0x62, 0xfa, 0x26, + 0x20, 0xbf, 0x19, 0xc8, 0xed, 0xa5, 0xe4, 0xda, 0x5c, 0xc3, 0xf0, 0x0c, 0x09, 0x56, 0x45, 0x22, 0xf0, 0x88, 0x1a, + 0x70, 0xcc, 0x57, 0x79, 0x1e, 0x60, 0xc2, 0xd7, 0xf6, 0x26, 0x00, 0x94, 0x93, 0xab, 0xe2, 0x2c, 0x05, 0xba, 0x01, + 0xcb, 0xd5, 0x71, 0x6a, 0x54, 0x24, 0x2e, 0x6e, 0x4c, 0x57, 0xb7, 0xf4, 0xa7, 0x68, 0x39, 0x93, 0x21, 0xa6, 0x83, + 0x20, 0x20, 0x53, 0x9f, 0x32, 0x47, 0xc8, 0x5c, 0x61, 0x7d, 0xce, 0x9c, 0xda, 0xd4, 0x3d, 0x46, 0xdd, 0x3c, 0x49, + 0x2d, 0x5e, 0xa7, 0x4d, 0x29, 0x11, 0x93, 0x12, 0xf3, 0x54, 0xa4, 0x62, 0x33, 0x25, 0xee, 0xdc, 0xfa, 0x46, 0x0b, + 0x69, 0xa3, 0x9d, 0x8a, 0x1c, 0x6c, 0x56, 0xc9, 0x7b, 0x02, 0xe3, 0xa5, 0x20, 0x7c, 0x89, 0x8c, 0xb5, 0x98, 0x33, + 0xc7, 0x44, 0xb0, 0x7a, 0x31, 0x15, 0xf9, 0x07, 0x47, 0xa7, 0xd9, 0x1b, 0xf4, 0x20, 0xf5, 0x06, 0x12, 0xb3, 0x26, + 0xbe, 0x0b, 0x69, 0xa8, 0x23, 0x04, 0x2a, 0xa3, 0x5a, 0xa6, 0xe3, 0xc4, 0x2a, 0x7c, 0x23, 0xf8, 0xea, 0xbd, 0x3e, + 0xce, 0x37, 0x9e, 0x1b, 0xab, 0x11, 0xc4, 0xe0, 0x2d, 0xe4, 0x47, 0x9e, 0x14, 0xe1, 0x40, 0xb8, 0x7c, 0x73, 0xb3, + 0x97, 0xef, 0xf2, 0x2a, 0x44, 0x52, 0xc1, 0x18, 0x63, 0x46, 0x31, 0xee, 0x89, 0x9a, 0x5a, 0xcc, 0x61, 0x60, 0xd9, + 0x3a, 0xcc, 0xf1, 0x00, 0x00, 0x5a, 0x9a, 0xd2, 0xab, 0xa6, 0x42, 0xe5, 0x79, 0x2e, 0xe1, 0x53, 0x1d, 0xa2, 0xaa, + 0xc6, 0xef, 0x57, 0x67, 0xa0, 0x10, 0xdc, 0xf7, 0x3a, 0x1e, 0x1e, 0x42, 0xc0, 0x2a, 0x0a, 0x59, 0xa0, 0x37, 0x68, + 0xaf, 0x4a, 0x84, 0x62, 0xe6, 0x64, 0x3d, 0x66, 0x38, 0xa9, 0x60, 0x0b, 0x95, 0xb0, 0x54, 0x5a, 0xe0, 0x57, 0x1b, + 0xa1, 0x79, 0xca, 0xb8, 0xf7, 0xa6, 0xc2, 0x19, 0xf4, 0x07, 0xf3, 0x96, 0x19, 0xf5, 0xfd, 0xd2, 0x89, 0x4c, 0x05, + 0x26, 0x6e, 0x66, 0xa9, 0xfd, 0x7e, 0x59, 0xa5, 0xfd, 0xbc, 0x42, 0xee, 0x73, 0xd2, 0x7c, 0x9d, 0x3b, 0x68, 0x3e, + 0x19, 0xee, 0x57, 0xca, 0x0f, 0x2d, 0x8c, 0x9a, 0xf2, 0xcb, 0xeb, 0xca, 0xaf, 0xf0, 0x54, 0x78, 0xab, 0xdf, 0x45, + 0xa1, 0x8b, 0xfa, 0x1c, 0x0c, 0x21, 0xfd, 0x08, 0xae, 0xa1, 0xc1, 0x83, 0x22, 0x59, 0x2c, 0xd6, 0x2e, 0x88, 0xeb, + 0x63, 0x4e, 0xb5, 0x43, 0x19, 0x63, 0xc4, 0xd3, 0x92, 0x83, 0x24, 0x83, 0x83, 0xf1, 0x1b, 0x18, 0x10, 0x93, 0x92, + 0x90, 0x0e, 0xa1, 0xb3, 0x32, 0x13, 0x51, 0xb9, 0x8b, 0xb7, 0x1b, 0x97, 0x35, 0x85, 0x22, 0xec, 0x04, 0x33, 0x95, + 0x52, 0x41, 0x20, 0x4d, 0xbe, 0x7b, 0x9d, 0x5a, 0x30, 0xb4, 0x70, 0x4d, 0x05, 0xe4, 0xb5, 0x5d, 0x0f, 0x9a, 0x7c, + 0xa4, 0x18, 0xfa, 0x2a, 0x35, 0xe2, 0x65, 0x06, 0x5f, 0xc3, 0xe6, 0xaf, 0x89, 0x92, 0x3c, 0x64, 0x22, 0xf6, 0x0a, + 0x3e, 0x11, 0xb2, 0x29, 0xd8, 0x99, 0x40, 0x3f, 0xb4, 0x2b, 0x7b, 0xe9, 0x6e, 0x51, 0xb9, 0xb4, 0x68, 0x6c, 0x25, + 0x6a, 0xd6, 0xfc, 0x30, 0xde, 0x4c, 0x61, 0x3f, 0x7b, 0x94, 0x40, 0x40, 0x9a, 0xca, 0x49, 0xaa, 0x79, 0x0f, 0xd3, + 0x23, 0x00, 0x09, 0x76, 0x3f, 0x81, 0x85, 0x7e, 0x53, 0x62, 0x82, 0x45, 0xd5, 0xd8, 0x6d, 0x06, 0x5a, 0x73, 0x46, + 0x9a, 0x6f, 0x86, 0x5a, 0x7b, 0x53, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x66, 0x71, 0x98, 0x6e, 0x76, 0x8e, + 0x0c, 0xc1, 0x85, 0xc7, 0xff, 0x49, 0x89, 0x69, 0x20, 0xb9, 0xd4, 0x8d, 0x9f, 0x50, 0x87, 0xe1, 0xff, 0x16, 0xa4, + 0x80, 0x07, 0xb5, 0xd5, 0x58, 0x72, 0xee, 0x15, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, + 0x89, 0x62, 0x9e, 0x13, 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, + 0xca, 0xcf, 0xe8, 0x48, 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x0b, 0x30, 0xcd, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, + 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0x59, 0x83, + 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, 0x55, 0x60, 0x40, + 0xb9, 0xd3, 0x34, 0xac, 0x84, 0xb8, 0x44, 0x85, 0x59, 0xc5, 0xf9, 0xe3, 0x3a, 0xaf, 0x9b, 0x96, 0x25, 0x06, 0xe5, + 0x67, 0xae, 0xe1, 0xc6, 0xf7, 0x1a, 0xf9, 0xe3, 0x7b, 0x2f, 0x41, 0xb7, 0x13, 0x69, 0xef, 0xdf, 0xcf, 0xef, 0x91, + 0x85, 0x86, 0xf7, 0xc2, 0x66, 0xd0, 0x16, 0xe9, 0x92, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, + 0x30, 0x03, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, + 0xe4, 0xc5, 0x3a, 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x00, 0xfa, 0x15, 0x95, 0xc5, 0x06, 0x72, + 0x71, 0x53, 0xd6, 0x7a, 0x45, 0xa3, 0xd1, 0x8d, 0x5d, 0x58, 0x5d, 0x81, 0x4f, 0xa2, 0x74, 0x94, 0x88, 0x49, 0xcc, + 0xa4, 0xca, 0x15, 0xb9, 0x36, 0xba, 0x97, 0xb6, 0x68, 0x5e, 0x0a, 0x09, 0x5e, 0x11, 0xb8, 0x21, 0xf4, 0x95, 0xbe, + 0x5c, 0x6d, 0xa0, 0xe0, 0x51, 0x7b, 0x73, 0x11, 0x4c, 0x4c, 0x3c, 0x66, 0x48, 0x4d, 0xbf, 0x0e, 0xa7, 0x56, 0x16, + 0x4b, 0x0e, 0xbf, 0xce, 0x19, 0x6b, 0x28, 0x00, 0xe2, 0x93, 0x47, 0xeb, 0xdd, 0xa4, 0x37, 0x4a, 0x3b, 0x28, 0x8d, + 0x10, 0xdf, 0x55, 0xf8, 0xba, 0x0b, 0xc5, 0x57, 0xae, 0xba, 0xf7, 0x75, 0xcc, 0x8c, 0x0b, 0x46, 0x2f, 0xf9, 0x34, + 0x69, 0x5c, 0xbb, 0xa1, 0xbb, 0x3a, 0xdf, 0x7b, 0x5f, 0xca, 0xbc, 0x85, 0x63, 0x60, 0x93, 0x63, 0xe6, 0xbc, 0xf4, + 0xde, 0x1a, 0x27, 0xca, 0x3f, 0x98, 0x47, 0xbc, 0x72, 0x98, 0x55, 0x27, 0xc9, 0x3f, 0x0c, 0x7e, 0x08, 0xd6, 0xb7, + 0x34, 0x4e, 0x90, 0xbb, 0xea, 0x04, 0x99, 0x28, 0xb7, 0xa1, 0x37, 0xdc, 0xde, 0x5d, 0x05, 0x82, 0x38, 0x15, 0xd3, + 0x47, 0xe5, 0xb8, 0x7e, 0xb4, 0x40, 0xa5, 0x22, 0xe2, 0x73, 0x95, 0xbb, 0xb2, 0x36, 0x35, 0xd4, 0xe3, 0x3a, 0x99, + 0x85, 0xa6, 0x59, 0x91, 0x4b, 0xd9, 0xf4, 0x18, 0x99, 0x66, 0xa7, 0xda, 0xfc, 0xee, 0xda, 0x43, 0x3a, 0x86, 0xe6, + 0x62, 0xad, 0x16, 0xdc, 0xef, 0x2a, 0x0a, 0xef, 0x7a, 0xb1, 0x91, 0xca, 0x50, 0xb3, 0x1e, 0x45, 0x1f, 0xc7, 0x6d, + 0xe6, 0xf2, 0x28, 0xfb, 0xb3, 0x06, 0x80, 0xe9, 0x08, 0x8b, 0xee, 0xa6, 0x67, 0xec, 0x09, 0xf4, 0xf4, 0x44, 0x06, + 0x89, 0xde, 0xe8, 0x7c, 0xd5, 0x2a, 0xb1, 0x74, 0x05, 0x81, 0xdd, 0x1b, 0x32, 0x56, 0x25, 0xed, 0x96, 0xeb, 0x97, + 0xf3, 0x7c, 0x9e, 0xf3, 0xa5, 0x3c, 0x9f, 0x9a, 0x45, 0x77, 0xaf, 0xed, 0xde, 0x9c, 0x1a, 0x2a, 0xe6, 0x5a, 0xdd, + 0xe4, 0x37, 0x4c, 0xd7, 0xc1, 0x50, 0x8b, 0x20, 0xb3, 0xda, 0x55, 0x2f, 0xca, 0x72, 0xa3, 0x9e, 0xc9, 0xb1, 0x21, + 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0xf7, 0x8d, 0x6d, 0x21, 0xdb, 0xbc, 0xbc, 0x1a, 0xe5, 0x40, + 0x69, 0xb9, 0xbf, 0x4c, 0x18, 0xbe, 0xbf, 0xbe, 0xfe, 0x5e, 0xc8, 0xa9, 0xaa, 0xa3, 0xb7, 0x78, 0xad, 0x7b, 0x06, + 0x1b, 0xa5, 0x72, 0x22, 0x2e, 0xd8, 0xea, 0xc1, 0x9b, 0xbb, 0x57, 0xc0, 0x72, 0x01, 0xd8, 0x5d, 0x30, 0xa7, 0x31, + 0x54, 0xb5, 0x81, 0xbf, 0x5c, 0x3d, 0xd8, 0xaa, 0x3d, 0xfc, 0xe5, 0xe0, 0xcb, 0xe0, 0xc6, 0xc6, 0xc6, 0x36, 0xde, + 0xae, 0x25, 0x82, 0xbc, 0xc1, 0x03, 0x7d, 0xbc, 0xfa, 0x28, 0x68, 0xb9, 0x4a, 0x6c, 0x0f, 0x1c, 0x0a, 0x5b, 0x83, + 0x7c, 0x93, 0x32, 0x69, 0x38, 0x2f, 0x78, 0x36, 0x95, 0x33, 0x14, 0xf2, 0x9a, 0x8f, 0x83, 0xb6, 0x23, 0xfc, 0x1b, + 0x38, 0xb5, 0xe3, 0xe5, 0xc5, 0x27, 0xe8, 0x03, 0x9e, 0xae, 0x94, 0xa6, 0x22, 0x4e, 0x29, 0xb7, 0xe8, 0x72, 0x9d, + 0x07, 0x23, 0xc5, 0xc5, 0x04, 0x95, 0x8e, 0xbb, 0xb8, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, + 0x44, 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, + 0xd7, 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, + 0xe7, 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, + 0x52, 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, + 0x2d, 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, + 0xc4, 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, + 0xd6, 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, + 0xe2, 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0xe7, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, + 0x68, 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, + 0x57, 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, + 0x30, 0x93, 0xa6, 0xbc, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, + 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0xe1, 0x03, 0xb9, 0xd4, 0x92, 0xbf, + 0xcc, 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, + 0x51, 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x25, 0x7f, 0x8e, 0xa9, + 0x83, 0x59, 0xa9, 0xdd, 0xb4, 0xd8, 0x24, 0x79, 0xcf, 0x0c, 0x48, 0xae, 0xbe, 0x86, 0x87, 0xc6, 0x2f, 0x5e, 0x99, + 0x53, 0xc2, 0x17, 0x65, 0x2c, 0x2d, 0x8d, 0xb9, 0xf4, 0xdf, 0xca, 0xfb, 0xb4, 0x12, 0xb0, 0x57, 0x20, 0xa6, 0x0c, + 0x5c, 0x62, 0xe3, 0x82, 0xa4, 0xbc, 0x96, 0xa7, 0xec, 0xbe, 0x86, 0xf2, 0x5d, 0x32, 0xe9, 0x2a, 0x95, 0xb5, 0xc6, + 0xaa, 0xfb, 0x79, 0xce, 0xf2, 0xab, 0x7d, 0x86, 0xb9, 0xc9, 0x68, 0x90, 0x2d, 0x99, 0xd9, 0x94, 0x5f, 0xed, 0xdd, + 0xf8, 0x95, 0x87, 0x92, 0x0e, 0xd5, 0x2a, 0xdd, 0xbc, 0x74, 0xc3, 0x31, 0x6e, 0xdc, 0x70, 0x04, 0xb0, 0x31, 0xec, + 0x54, 0x91, 0x5a, 0xe7, 0xbf, 0x2f, 0x87, 0x9f, 0x68, 0xaf, 0x1d, 0xe9, 0x5d, 0x77, 0xb4, 0x32, 0x3d, 0xfd, 0x06, + 0x54, 0x8d, 0x2c, 0xa1, 0x9b, 0x50, 0xc5, 0x64, 0x24, 0x4a, 0x4c, 0x57, 0x29, 0x8f, 0xfa, 0x1a, 0x71, 0x0e, 0xe2, + 0x86, 0xf2, 0x17, 0xff, 0x14, 0x5e, 0x9d, 0x04, 0x68, 0x44, 0x2d, 0xc6, 0x59, 0xca, 0x5b, 0xe3, 0x68, 0x1a, 0x27, + 0x57, 0xc1, 0x3c, 0x6e, 0x4d, 0xb3, 0x34, 0x2b, 0x66, 0xc0, 0x95, 0x5e, 0x71, 0x05, 0x36, 0xfc, 0xb4, 0x35, 0x8f, + 0xbd, 0x97, 0x2c, 0x39, 0x67, 0x3c, 0x1e, 0x46, 0x9e, 0xbd, 0x97, 0x83, 0x78, 0xb0, 0xde, 0x46, 0x79, 0x9e, 0x5d, + 0xd8, 0xde, 0x87, 0xec, 0x14, 0x98, 0xd6, 0x7b, 0x77, 0x79, 0x75, 0xc6, 0x52, 0xef, 0xe3, 0xe9, 0x3c, 0xe5, 0x73, + 0xaf, 0x88, 0xd2, 0xa2, 0x55, 0xb0, 0x3c, 0x1e, 0x83, 0x9a, 0x48, 0xb2, 0xbc, 0x85, 0xf9, 0xcf, 0x53, 0x16, 0x24, + 0xf1, 0xd9, 0x84, 0x5b, 0xa3, 0x28, 0xff, 0xd4, 0x6b, 0xb5, 0x66, 0x79, 0x3c, 0x8d, 0xf2, 0xab, 0x16, 0xb5, 0x08, + 0x3e, 0x6b, 0x6f, 0x47, 0x9f, 0x8f, 0x1f, 0xf6, 0x78, 0x0e, 0x7d, 0x63, 0xa4, 0x62, 0x00, 0xc2, 0xc7, 0xda, 0xde, + 0x69, 0x4f, 0x8b, 0x7b, 0xe2, 0x44, 0x29, 0x4a, 0x79, 0x79, 0xe2, 0x5d, 0x31, 0x80, 0xdb, 0x3f, 0xe5, 0xa9, 0x07, + 0xbe, 0x1c, 0xcf, 0xd2, 0xc5, 0x70, 0x9e, 0x17, 0x30, 0xc0, 0x2c, 0x8b, 0x53, 0xce, 0xf2, 0xde, 0x69, 0x96, 0x03, + 0xd9, 0x5a, 0x79, 0x34, 0x8a, 0xe7, 0x45, 0xf0, 0x70, 0x76, 0xd9, 0x43, 0x5b, 0xe1, 0x2c, 0xcf, 0xe6, 0xe9, 0x48, + 0xce, 0x15, 0xa7, 0xb0, 0x31, 0x62, 0x6e, 0x56, 0xd0, 0x97, 0x50, 0x00, 0xbe, 0x94, 0x45, 0x79, 0xeb, 0x0c, 0x3b, + 0xa3, 0xa1, 0xdf, 0x1e, 0xb1, 0x33, 0x2f, 0x3f, 0x3b, 0x8d, 0x9c, 0x4e, 0xf7, 0xb1, 0xa7, 0xfe, 0xf3, 0x77, 0x5c, + 0x30, 0xdc, 0x57, 0x16, 0x77, 0xda, 0xed, 0xbf, 0x71, 0x7b, 0x8d, 0x59, 0x08, 0xa0, 0xa0, 0x33, 0xbb, 0xb4, 0x8a, + 0x2c, 0x81, 0xf5, 0x59, 0xd5, 0xb3, 0x37, 0x03, 0xbf, 0x29, 0x4e, 0xcf, 0x82, 0xee, 0xec, 0xb2, 0x44, 0xec, 0x02, + 0x91, 0x90, 0x29, 0x91, 0x94, 0x6f, 0x8b, 0xdf, 0x0a, 0xf1, 0x93, 0xd5, 0x10, 0x77, 0x15, 0xc4, 0x15, 0xd5, 0x5b, + 0x23, 0xd8, 0x07, 0x44, 0xfe, 0x4e, 0x21, 0x00, 0x99, 0x80, 0x13, 0x98, 0x2b, 0x38, 0xe8, 0xe5, 0x37, 0x83, 0xd1, + 0x5d, 0x0d, 0xc6, 0x93, 0xdb, 0xc0, 0xc8, 0xd3, 0xd1, 0xa2, 0xbe, 0xae, 0x1d, 0x70, 0x4e, 0x7b, 0x13, 0x86, 0xfc, + 0x14, 0x74, 0xf1, 0xf9, 0x22, 0x1e, 0xf1, 0x89, 0x78, 0x24, 0x76, 0xbe, 0x10, 0x75, 0x3b, 0xed, 0xb6, 0x78, 0x2f, + 0x40, 0xa1, 0x05, 0x1d, 0x1f, 0x1b, 0x00, 0x13, 0x7d, 0xb1, 0xee, 0x23, 0x36, 0xdf, 0xdd, 0xfa, 0xa5, 0x1a, 0x8f, + 0xa9, 0xbc, 0x41, 0xa1, 0x22, 0xd4, 0x37, 0x5b, 0x30, 0xe3, 0x2d, 0xef, 0x77, 0xf4, 0x41, 0xd5, 0xe0, 0x3b, 0x46, + 0x5a, 0x2f, 0xe0, 0x9e, 0x99, 0x0b, 0xd4, 0x4b, 0xfb, 0x18, 0x92, 0x6a, 0xb5, 0x5c, 0xd0, 0x1b, 0x0c, 0x43, 0x48, + 0x74, 0x20, 0xe8, 0xe4, 0x83, 0x82, 0xbe, 0xa9, 0x91, 0xb9, 0x41, 0xe1, 0x64, 0x2e, 0x6c, 0xf9, 0x4c, 0xcb, 0x75, + 0x50, 0xd2, 0xe0, 0x65, 0x7f, 0xc1, 0x64, 0x03, 0x90, 0xde, 0x95, 0xa4, 0xe5, 0xd5, 0xd1, 0x93, 0x72, 0xf9, 0xb2, + 0x21, 0x51, 0x0e, 0x7c, 0x7d, 0x3e, 0x41, 0xbf, 0x5b, 0x7f, 0x28, 0xc6, 0x48, 0xa9, 0xd9, 0xb2, 0xdd, 0x01, 0xd3, + 0x59, 0x59, 0x98, 0x7d, 0xc6, 0x4a, 0x1c, 0xe5, 0x2b, 0xb0, 0xa4, 0x31, 0xf4, 0xfa, 0x73, 0x28, 0xdc, 0x34, 0xe5, + 0xa4, 0x6d, 0xdc, 0x74, 0xfd, 0x1f, 0x56, 0x3c, 0xa6, 0x6c, 0x67, 0x15, 0x1b, 0x07, 0xd7, 0xe5, 0x78, 0x28, 0xae, + 0x1d, 0x16, 0x98, 0x2d, 0xfe, 0xdb, 0x3d, 0x09, 0x47, 0xa3, 0x55, 0x64, 0xf3, 0x7c, 0x48, 0xa1, 0xc1, 0xe5, 0x10, + 0x83, 0x4d, 0x1a, 0xde, 0xf6, 0x98, 0x56, 0x2c, 0xe8, 0x77, 0xd7, 0xbe, 0xaa, 0xc0, 0xe9, 0xd4, 0x45, 0x5c, 0x6a, + 0x90, 0x61, 0x15, 0x05, 0x36, 0xea, 0xca, 0x11, 0x25, 0xd8, 0xd1, 0x85, 0x4f, 0x7f, 0x9e, 0xc6, 0x20, 0x5a, 0x8f, + 0xe3, 0x11, 0x5d, 0x74, 0x89, 0x47, 0x74, 0xf2, 0xd1, 0xa2, 0x4c, 0x27, 0x0c, 0xa5, 0x43, 0x81, 0x24, 0x38, 0x3e, + 0xcb, 0xcc, 0x19, 0xbb, 0x65, 0xe3, 0xe9, 0x85, 0xa1, 0x9b, 0x47, 0xd9, 0x34, 0x8a, 0xd3, 0x00, 0x3f, 0x48, 0xe2, + 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0x5f, 0x45, 0xfb, 0x8e, 0xeb, 0xff, 0x04, 0x82, 0x8b, 0xfa, 0x97, 0xd2, 0xf1, + 0xd3, 0x70, 0xa9, 0x73, 0xe5, 0x7a, 0x29, 0x08, 0x3b, 0xae, 0x8c, 0x64, 0x46, 0x81, 0x95, 0x5d, 0x4e, 0x7f, 0x06, + 0xad, 0x4e, 0xa0, 0xae, 0xfe, 0x9b, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, + 0xf3, 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, + 0x56, 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, + 0x5b, 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xe1, 0x55, 0xa7, 0x7a, 0xd6, 0x96, 0x62, 0xef, 0xe1, + 0xc9, 0xae, 0x10, 0x52, 0x16, 0xb1, 0x6e, 0x68, 0x83, 0xd4, 0xb0, 0xad, 0x3f, 0x0e, 0x81, 0xce, 0x9f, 0x42, 0x7b, + 0x63, 0xe1, 0xa8, 0xbb, 0x00, 0x39, 0xcc, 0xb5, 0x27, 0x14, 0x35, 0x7d, 0x44, 0xc0, 0xee, 0x6f, 0x2c, 0x78, 0xb9, + 0xbb, 0x25, 0x7a, 0xf7, 0x4f, 0xca, 0x82, 0x74, 0xaa, 0x19, 0xfb, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, 0x1c, + 0xe3, 0xb8, 0xb9, 0xb6, 0x13, 0x45, 0x90, 0x5b, 0x32, 0x6e, 0x81, 0x19, 0x56, 0x51, 0x0e, 0x62, 0x44, 0xe7, 0xd0, + 0x14, 0x22, 0x6d, 0xa4, 0xb7, 0x0c, 0xc5, 0x09, 0x42, 0x30, 0xd8, 0x58, 0xc4, 0x65, 0xb8, 0xb1, 0x60, 0xe9, 0x30, + 0x1b, 0xb1, 0x8f, 0x1f, 0x5e, 0xe1, 0x35, 0x89, 0x2c, 0x45, 0x79, 0x9a, 0xb9, 0xe5, 0x09, 0x18, 0x58, 0x08, 0x69, + 0xae, 0xbe, 0x52, 0x03, 0xc0, 0x88, 0x58, 0x91, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, 0x1c, + 0x59, 0x2c, 0x00, 0x13, 0x94, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, 0x9a, + 0x23, 0x1a, 0x15, 0xaa, 0x98, 0x55, 0x64, 0xa2, 0x3b, 0x8a, 0xcf, 0x35, 0x39, 0x29, 0xc5, 0xba, 0xbf, 0x9b, 0x44, + 0xa7, 0x2c, 0x81, 0x21, 0x81, 0xaf, 0xda, 0x30, 0x92, 0x78, 0xb5, 0x76, 0xe3, 0x74, 0x36, 0x97, 0x5f, 0x0b, 0x83, + 0x89, 0x3b, 0x78, 0x80, 0x8b, 0x97, 0x19, 0x06, 0xea, 0x44, 0x32, 0x90, 0x03, 0x00, 0x88, 0x74, 0x18, 0x82, 0xd0, + 0x55, 0xac, 0x02, 0xa5, 0xf1, 0x68, 0xb9, 0x0c, 0xf6, 0xf7, 0x0c, 0x4b, 0x53, 0x78, 0x9e, 0xc6, 0x29, 0x3e, 0x16, + 0xf8, 0x18, 0x5d, 0xe2, 0x63, 0x06, 0x8f, 0x1a, 0xf7, 0xbc, 0xb4, 0xff, 0xaa, 0xab, 0x92, 0xc9, 0x15, 0xb0, 0x34, + 0x01, 0xb2, 0xeb, 0x6b, 0x50, 0x5b, 0x9a, 0x04, 0xbb, 0x5b, 0x40, 0x2c, 0xe4, 0x1e, 0xf1, 0xed, 0x18, 0x66, 0x92, + 0x91, 0x15, 0xb3, 0x96, 0x28, 0xb7, 0xc8, 0x38, 0x08, 0xc1, 0x77, 0xcc, 0x9d, 0x86, 0x0d, 0xe4, 0xc9, 0x2c, 0x99, + 0x67, 0xf8, 0xe2, 0xda, 0x96, 0xf8, 0xb8, 0x87, 0x20, 0x0a, 0x3d, 0x22, 0x86, 0xba, 0x8c, 0xcb, 0xcf, 0xf6, 0xc4, + 0xa1, 0x8d, 0xb3, 0x80, 0x19, 0x8a, 0xca, 0x8c, 0x47, 0x71, 0x22, 0x1a, 0xaf, 0xc0, 0xa7, 0x91, 0xee, 0x48, 0xe8, + 0xec, 0x6e, 0x55, 0xb0, 0x01, 0xf0, 0x4a, 0x22, 0x88, 0x54, 0x4e, 0x5b, 0x94, 0x53, 0x0a, 0x80, 0xdc, 0xe6, 0xd5, + 0x27, 0x9d, 0x80, 0x29, 0xc0, 0x88, 0x1e, 0x1d, 0xd3, 0x6c, 0x83, 0x21, 0x12, 0x0b, 0x67, 0x6c, 0x6c, 0x5d, 0xfb, + 0x2f, 0xff, 0xfc, 0x0f, 0xb6, 0x27, 0x40, 0xcc, 0xc6, 0x63, 0x90, 0x72, 0xd6, 0xba, 0x86, 0xff, 0xeb, 0x1f, 0xff, + 0xef, 0xff, 0xf9, 0xaf, 0xba, 0x6d, 0x0a, 0x4d, 0x4f, 0x02, 0x71, 0xb4, 0xa0, 0x49, 0x4a, 0x29, 0x9e, 0xf6, 0x38, + 0x4a, 0x57, 0x80, 0x74, 0x08, 0x54, 0x9a, 0x31, 0x36, 0xf2, 0x6c, 0x0b, 0x34, 0x81, 0x78, 0x3e, 0x4e, 0xd8, 0x39, + 0x93, 0x1f, 0x96, 0xd1, 0x83, 0xe8, 0xca, 0x21, 0x58, 0x30, 0x5c, 0xde, 0x79, 0x95, 0xdb, 0x40, 0xd1, 0x52, 0x52, + 0xbc, 0x4e, 0x30, 0xcf, 0x36, 0x06, 0x6d, 0xce, 0xd1, 0xae, 0x0f, 0xeb, 0x81, 0x4a, 0xb5, 0x6d, 0x01, 0x2f, 0x99, + 0xbd, 0xab, 0x20, 0x5e, 0x82, 0xeb, 0x34, 0xc7, 0xa6, 0x29, 0x2b, 0x8a, 0x55, 0x60, 0x01, 0x4d, 0x3c, 0xbb, 0x6a, + 0x62, 0xd7, 0x3a, 0x00, 0x00, 0xdd, 0x9d, 0x1d, 0x31, 0x2d, 0x54, 0xb0, 0xf1, 0x18, 0x36, 0x38, 0xea, 0xb6, 0x84, + 0xe3, 0xb1, 0x45, 0xd8, 0xb7, 0xdf, 0x82, 0x2c, 0xb1, 0xc1, 0x3f, 0x74, 0xf5, 0x01, 0x34, 0x4d, 0xaf, 0x84, 0x9d, + 0x31, 0x87, 0xe8, 0x6c, 0x0c, 0xa3, 0x9f, 0x0c, 0xa4, 0xb2, 0xe1, 0xa7, 0x55, 0x8c, 0xb1, 0x96, 0x11, 0xfe, 0xfd, + 0x5f, 0xfe, 0xf1, 0xbf, 0xc1, 0xd8, 0xd4, 0x6f, 0x3d, 0x17, 0x40, 0xab, 0xff, 0x09, 0xad, 0xe6, 0xe9, 0x2d, 0xed, + 0xfe, 0xf2, 0xf7, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x29, 0xe0, 0x13, 0x82, 0x68, 0x88, 0xb6, 0xe9, 0xaf, 0x02, 0xa9, + 0x36, 0xc8, 0xda, 0x99, 0xfe, 0x09, 0xc1, 0x2e, 0x78, 0x36, 0xbb, 0x11, 0x1c, 0x84, 0x7a, 0x98, 0x64, 0x05, 0xd3, + 0xf0, 0x08, 0x7d, 0xf2, 0xeb, 0x00, 0xa2, 0xb9, 0x66, 0xb0, 0x6b, 0x0b, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xd5, 0x38, + 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, + 0xda, 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, + 0x52, 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, + 0x48, 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, + 0x24, 0xd2, 0xba, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, + 0x9f, 0x87, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, + 0x12, 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, + 0x97, 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, + 0x0c, 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, + 0x7f, 0x83, 0x97, 0x1d, 0x2d, 0xec, 0x8d, 0x96, 0x42, 0x41, 0x86, 0x0d, 0x27, 0xc3, 0x46, 0x6a, 0x54, 0xd3, 0xa6, + 0x40, 0xc7, 0x2f, 0x5b, 0x6d, 0x3b, 0x1c, 0x63, 0xf7, 0x9a, 0xf6, 0xe7, 0x52, 0xfb, 0xc7, 0xd2, 0xde, 0x97, 0xda, + 0x1f, 0x3f, 0x69, 0xd3, 0xd0, 0xfe, 0xf1, 0x5a, 0xed, 0x8f, 0x94, 0x1b, 0xe0, 0xc8, 0xa1, 0xbd, 0x89, 0xd1, 0x2d, + 0xc3, 0xd6, 0xe0, 0x68, 0x67, 0x0d, 0x27, 0x6c, 0xf8, 0x49, 0x9a, 0x59, 0x84, 0x00, 0x86, 0x77, 0xb4, 0x31, 0x29, + 0x30, 0x00, 0x93, 0xe1, 0xa4, 0xd4, 0x9b, 0x1e, 0x1f, 0x8d, 0x09, 0xb8, 0xbb, 0x18, 0x33, 0x14, 0xfd, 0xb0, 0x66, + 0x5f, 0xb1, 0x72, 0x0b, 0xc7, 0x11, 0x1b, 0x46, 0x3c, 0x03, 0x66, 0x5b, 0x38, 0xd8, 0x89, 0xb7, 0x10, 0xc1, 0xc2, + 0xc0, 0x7e, 0xff, 0x6e, 0xff, 0xc0, 0xf6, 0x4e, 0xb3, 0xd1, 0x55, 0x60, 0x83, 0x33, 0x06, 0xd6, 0x94, 0xeb, 0xf3, + 0x09, 0x4b, 0x1d, 0xe5, 0xf9, 0x64, 0x09, 0xb8, 0x9a, 0xd9, 0x99, 0xf8, 0xb6, 0x45, 0xf3, 0xa0, 0x03, 0x08, 0x4b, + 0x1f, 0xbf, 0xec, 0xef, 0x72, 0xf1, 0x5d, 0x58, 0x9e, 0xe3, 0x63, 0x1f, 0x53, 0x3d, 0x76, 0xb7, 0xe0, 0x01, 0x5f, + 0xf6, 0x51, 0xef, 0xd1, 0xdb, 0xc6, 0x62, 0xc9, 0x6d, 0x18, 0xe0, 0x10, 0x93, 0xbe, 0x40, 0xa1, 0xa0, 0x56, 0x27, + 0x01, 0x22, 0x06, 0x8f, 0x30, 0xd6, 0x96, 0x1a, 0x17, 0x21, 0x54, 0xfd, 0xb5, 0xe3, 0x52, 0xd9, 0xad, 0x34, 0xef, + 0x08, 0xcd, 0x52, 0x72, 0x5c, 0xb0, 0xf7, 0x48, 0x97, 0x08, 0x53, 0x87, 0x8a, 0xd6, 0x41, 0xa0, 0x6b, 0x2a, 0x73, + 0x45, 0x74, 0x30, 0x80, 0x21, 0x33, 0x57, 0x00, 0x02, 0x7f, 0x09, 0xed, 0x13, 0xf3, 0xfb, 0x6f, 0xe2, 0x53, 0x4d, + 0x9a, 0x38, 0x87, 0x7f, 0xf2, 0xae, 0x98, 0x77, 0x75, 0x42, 0x2d, 0x55, 0xb0, 0x01, 0xa3, 0x60, 0x18, 0x94, 0x69, + 0xab, 0xa8, 0x12, 0xd8, 0x69, 0x49, 0x34, 0x2b, 0x58, 0xa0, 0x1e, 0x64, 0xdc, 0x01, 0xc3, 0x17, 0xcb, 0x81, 0x1e, + 0xd3, 0x9e, 0x2b, 0xf9, 0x64, 0x61, 0x06, 0x26, 0x1e, 0xb5, 0xdb, 0x3d, 0xbc, 0x54, 0xd1, 0x8a, 0xc0, 0x3a, 0x48, + 0x83, 0x84, 0x8d, 0x79, 0xc9, 0xf1, 0xd6, 0xfe, 0x42, 0x45, 0x82, 0xfc, 0xee, 0x4e, 0xce, 0xa6, 0x96, 0x8f, 0xff, + 0xbf, 0x6d, 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, + 0x0d, 0x19, 0x46, 0xc9, 0x4a, 0x9e, 0x83, 0xbc, 0xf7, 0x78, 0x6e, 0xb6, 0x03, 0x39, 0xbd, 0x14, 0x2a, 0x5b, 0x0e, + 0xd6, 0x6c, 0xbb, 0xd2, 0x3f, 0x5a, 0x6e, 0xac, 0x22, 0x5e, 0xf5, 0xb7, 0x25, 0x0a, 0x19, 0xb1, 0xb9, 0x52, 0xa8, + 0xa8, 0x85, 0xe8, 0x61, 0xe2, 0xb4, 0x1c, 0xb5, 0xbb, 0xd5, 0x62, 0x2e, 0x49, 0x5c, 0x1c, 0x92, 0xb8, 0x20, 0xf1, + 0x77, 0xb4, 0x10, 0x73, 0x0f, 0xa3, 0x64, 0xe8, 0x20, 0x00, 0x56, 0xcb, 0x7a, 0x02, 0xd4, 0x74, 0x55, 0xe4, 0xc8, + 0x7f, 0x8c, 0xc4, 0x2d, 0x85, 0xb0, 0x5c, 0x41, 0xa5, 0x93, 0xa3, 0xb2, 0xec, 0x31, 0xe6, 0x1c, 0x7e, 0x90, 0x97, + 0x40, 0xc4, 0xdd, 0x5f, 0xfd, 0xfd, 0xc4, 0x76, 0xe9, 0x1e, 0x79, 0x3f, 0x1b, 0x1f, 0xa5, 0xb3, 0x15, 0xb3, 0xdb, + 0x1e, 0x2c, 0x83, 0xd9, 0x53, 0x7e, 0x42, 0xf2, 0xa6, 0xbe, 0x26, 0x9b, 0x53, 0xff, 0x9f, 0x43, 0x1c, 0xe1, 0x8d, + 0x63, 0xa3, 0x89, 0x4e, 0x23, 0x5f, 0xb5, 0x88, 0x3f, 0x6d, 0xec, 0x2a, 0x8e, 0x40, 0xbe, 0x5e, 0x17, 0xc9, 0xfa, + 0xe6, 0xf6, 0x48, 0x56, 0x71, 0xc7, 0x48, 0xd6, 0x37, 0xbf, 0x73, 0x24, 0xeb, 0x6b, 0x33, 0x92, 0x85, 0x02, 0xfa, + 0xd5, 0xaf, 0x89, 0x36, 0xe5, 0xd9, 0x45, 0x11, 0x76, 0x64, 0xe6, 0x04, 0xc8, 0x3a, 0x0c, 0x3b, 0xfd, 0xf5, 0x23, + 0x4c, 0x30, 0x51, 0x23, 0xbe, 0x44, 0x01, 0x25, 0x91, 0xec, 0x09, 0x6a, 0x45, 0x86, 0x73, 0xda, 0x3a, 0xab, 0xb2, + 0xf5, 0x50, 0x5d, 0x23, 0x03, 0xd7, 0xd7, 0xd5, 0xa1, 0xb6, 0xae, 0x0a, 0xf8, 0x04, 0xf4, 0x1d, 0x58, 0xdd, 0xb1, + 0xbb, 0xa9, 0xd2, 0xf9, 0xcc, 0x11, 0x7a, 0xea, 0x94, 0x46, 0x30, 0xd1, 0xc2, 0xfe, 0x2f, 0x87, 0x9d, 0xde, 0x76, + 0x67, 0x0a, 0xbd, 0x41, 0x81, 0xc3, 0x5b, 0xbb, 0xb7, 0xbd, 0x8d, 0x6f, 0x17, 0xea, 0xad, 0x8b, 0x6f, 0xb1, 0x7a, + 0xdb, 0xc1, 0xb7, 0xa1, 0x7a, 0x7b, 0x84, 0x6f, 0x23, 0xf5, 0xf6, 0x18, 0xdf, 0xce, 0xed, 0xf2, 0x90, 0x6b, 0xe0, + 0x1e, 0x03, 0x5f, 0x91, 0x37, 0x13, 0xa8, 0x32, 0xd8, 0xf4, 0x78, 0xfd, 0x32, 0x3a, 0x0b, 0x62, 0x4f, 0x78, 0x97, + 0x41, 0xee, 0x5d, 0x80, 0xc6, 0x09, 0x28, 0xdb, 0xf0, 0x39, 0x7e, 0x87, 0x03, 0x9c, 0xa4, 0x83, 0x78, 0xca, 0xd4, + 0x07, 0x89, 0x15, 0xd6, 0x60, 0xc0, 0x1e, 0xb6, 0x8f, 0xca, 0x9e, 0x5e, 0x27, 0x11, 0xcf, 0x52, 0xd9, 0x1c, 0xb4, + 0x72, 0x55, 0x9d, 0x98, 0xae, 0xa5, 0x57, 0x78, 0x8d, 0xfe, 0x32, 0xe2, 0x11, 0x63, 0x30, 0xcc, 0x5a, 0x97, 0xe0, + 0xc1, 0xae, 0xd4, 0x69, 0x08, 0x91, 0xd6, 0x69, 0x84, 0x93, 0x7e, 0x3b, 0x88, 0xce, 0xf4, 0xf3, 0x1b, 0xb0, 0xb4, + 0xa3, 0x33, 0xd9, 0x72, 0xbd, 0x0e, 0x23, 0x10, 0x4d, 0xfd, 0xa5, 0x80, 0x20, 0x53, 0x0c, 0x96, 0x06, 0x3d, 0x69, + 0xa9, 0xbf, 0x90, 0x3a, 0x75, 0x8d, 0x46, 0xd3, 0xd7, 0x8b, 0x80, 0xa2, 0x55, 0xc1, 0x2e, 0x18, 0xfc, 0x54, 0x2a, + 0x28, 0x0c, 0x15, 0x58, 0x20, 0xaa, 0xd7, 0xa8, 0x32, 0x1d, 0x6c, 0x58, 0xab, 0xd0, 0x2c, 0xa5, 0xcb, 0xcc, 0xd3, + 0x1d, 0x7d, 0xb4, 0xb3, 0x2c, 0x5e, 0x3f, 0xeb, 0x0c, 0xf1, 0x1f, 0x29, 0xbc, 0x3f, 0x1b, 0x8f, 0xc7, 0x37, 0xea, + 0xb6, 0xcf, 0x46, 0x63, 0xd6, 0x65, 0x3b, 0x3d, 0x8c, 0xfc, 0xb7, 0xa4, 0x38, 0xed, 0x94, 0x44, 0xbb, 0xc5, 0xdd, + 0x1a, 0xa3, 0xe4, 0x05, 0x75, 0x77, 0x77, 0x25, 0x58, 0x02, 0x55, 0x16, 0x20, 0xfc, 0xcf, 0xe2, 0x34, 0x68, 0x97, + 0xfe, 0xb9, 0xd4, 0x1a, 0x9f, 0x3d, 0x79, 0xf2, 0xa4, 0xf4, 0x47, 0xea, 0xad, 0x3d, 0x1a, 0x95, 0xfe, 0x70, 0xa1, + 0xd1, 0x68, 0xb7, 0xc7, 0xe3, 0xd2, 0x8f, 0x55, 0xc1, 0x76, 0x77, 0x38, 0xda, 0xee, 0x96, 0xfe, 0x85, 0xd1, 0xa2, + 0xf4, 0x99, 0x7c, 0xcb, 0xd9, 0xa8, 0x76, 0x7c, 0xf0, 0xb8, 0x0d, 0x95, 0x82, 0xd1, 0x16, 0xe8, 0x5d, 0x8a, 0xc7, + 0x20, 0x9a, 0xf3, 0x0c, 0x0c, 0xbb, 0xb2, 0x57, 0x80, 0x7c, 0x1e, 0x4b, 0x09, 0x2f, 0xbe, 0xf7, 0x8b, 0x52, 0xfd, + 0x95, 0x29, 0xd5, 0x91, 0x99, 0x49, 0x9a, 0x17, 0xa4, 0x0d, 0x9a, 0xd5, 0xc8, 0x59, 0x54, 0xfd, 0x2a, 0x2c, 0x2a, + 0x61, 0x8f, 0xd2, 0x06, 0x5b, 0x0a, 0x19, 0xff, 0xc3, 0x3a, 0x19, 0xff, 0xfd, 0xed, 0x32, 0xfe, 0xf4, 0x6e, 0x22, + 0xfe, 0xfb, 0xdf, 0x59, 0xc4, 0xff, 0x60, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0xc0, 0x74, 0x26, 0x9b, 0xf9, 0x34, 0xbb, + 0x6c, 0xe1, 0x96, 0xc8, 0x6d, 0x92, 0x9e, 0xd3, 0x3b, 0x09, 0xff, 0x15, 0xf9, 0x60, 0x6a, 0x30, 0xe3, 0xe3, 0xc1, + 0x3c, 0x3b, 0x3b, 0x4b, 0x98, 0x92, 0xf1, 0x46, 0x05, 0x99, 0xe3, 0xef, 0xd2, 0xd0, 0x7e, 0x07, 0x9e, 0xb1, 0x51, + 0x32, 0x1e, 0x43, 0xd1, 0x78, 0x6c, 0xab, 0x7c, 0x69, 0x90, 0x67, 0xd4, 0xea, 0x6d, 0xad, 0x84, 0x5a, 0x7d, 0xf1, + 0x85, 0x59, 0x66, 0x16, 0xc8, 0x90, 0x9e, 0x69, 0x8c, 0xc8, 0x9a, 0x51, 0x5c, 0xe0, 0x1e, 0xac, 0x3e, 0x76, 0x8c, + 0xf6, 0xce, 0x14, 0x94, 0x4a, 0x3c, 0xc4, 0x73, 0x91, 0xe6, 0x87, 0x65, 0x44, 0x6e, 0xfb, 0x32, 0x72, 0xd5, 0xf9, + 0xb7, 0xf1, 0x0d, 0xc3, 0xea, 0xcc, 0x1b, 0x16, 0x5f, 0xe6, 0xb7, 0x3c, 0xbd, 0x7a, 0x35, 0x72, 0xf6, 0xc0, 0x1a, + 0x8e, 0x8b, 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, + 0xec, 0x19, 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, + 0x92, 0x6e, 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xe2, 0x79, 0x88, + 0x98, 0x61, 0x54, 0xaa, 0x33, 0x10, 0x20, 0xdc, 0x0c, 0x3f, 0xd1, 0x24, 0x86, 0x50, 0x07, 0x05, 0x15, 0xf5, 0xae, + 0xaf, 0xcd, 0x2f, 0x85, 0xd6, 0xbe, 0x2a, 0xd9, 0xe0, 0x01, 0x86, 0x9f, 0xf8, 0x45, 0x6d, 0x90, 0xcd, 0xb9, 0xe3, + 0x50, 0x2b, 0xc7, 0x2d, 0xbd, 0x9d, 0x76, 0x1b, 0x54, 0x8c, 0x2f, 0xbe, 0x03, 0xe5, 0xe8, 0xce, 0x12, 0xdf, 0x75, + 0xe7, 0x12, 0x4b, 0xdf, 0x65, 0xd3, 0x24, 0xc6, 0x0f, 0xc7, 0x08, 0x44, 0x8d, 0xbb, 0x43, 0x6a, 0x11, 0x9b, 0xef, + 0xbe, 0xf2, 0x1d, 0x0d, 0xc2, 0xba, 0xab, 0x38, 0x58, 0xe6, 0xd6, 0xd6, 0x0b, 0xb1, 0xad, 0xb0, 0x6a, 0x96, 0xc1, + 0xb9, 0x45, 0x67, 0x16, 0x17, 0x46, 0x00, 0xbf, 0xb6, 0x0d, 0x4a, 0x15, 0xc1, 0x17, 0x61, 0xf8, 0x3d, 0x0c, 0x36, + 0x0b, 0xc7, 0x5b, 0x01, 0x5d, 0x77, 0x79, 0x0d, 0xc8, 0xd1, 0x19, 0xd6, 0x8c, 0xae, 0xaa, 0x54, 0x41, 0x69, 0x1e, + 0xc1, 0x18, 0xc8, 0x50, 0x24, 0x1d, 0xd6, 0x38, 0x15, 0x7a, 0x0b, 0xa6, 0x21, 0x01, 0xac, 0xfd, 0x3a, 0x74, 0x6b, + 0x6c, 0x05, 0xb6, 0x90, 0x16, 0xa0, 0xf4, 0xb0, 0x43, 0xdf, 0xaa, 0x81, 0x9e, 0x2e, 0x07, 0xe0, 0x6f, 0x74, 0xf2, + 0x4e, 0xfc, 0xe2, 0xc2, 0x83, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, + 0x86, 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, + 0x41, 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, + 0xdf, 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, + 0xd5, 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0xff, 0x8c, 0xcc, 0x85, 0x66, 0x31, 0x1d, 0xc0, 0xdf, + 0x05, 0xb2, 0x20, 0x1a, 0xe3, 0x17, 0x16, 0xef, 0xd2, 0xf2, 0x94, 0xb2, 0x5f, 0x17, 0xa8, 0xd6, 0x83, 0xce, 0x13, + 0xf0, 0xf6, 0xee, 0x3c, 0xfc, 0xcd, 0xe8, 0x97, 0x92, 0x46, 0xea, 0x12, 0xb3, 0x6d, 0xf7, 0x50, 0x5e, 0x24, 0xd1, + 0x15, 0x38, 0x9d, 0x64, 0x63, 0x9c, 0x62, 0xf4, 0xb8, 0x37, 0xcb, 0x64, 0x26, 0x49, 0xce, 0x12, 0xfa, 0x19, 0x13, + 0xb9, 0x14, 0xdb, 0x8f, 0x66, 0x97, 0x6a, 0x35, 0x3a, 0x8d, 0x0c, 0x91, 0xdf, 0x35, 0x11, 0x64, 0x7d, 0xe6, 0x49, + 0x3d, 0x99, 0x61, 0x07, 0x60, 0x10, 0x86, 0x4d, 0x2b, 0x17, 0x50, 0xb5, 0xa1, 0xc4, 0x48, 0x85, 0xa9, 0x06, 0xb2, + 0xfc, 0x6d, 0x50, 0x95, 0x51, 0xc1, 0x7a, 0xf8, 0xa9, 0xcb, 0x18, 0x5c, 0x5b, 0x69, 0x3c, 0x4d, 0xe3, 0xd1, 0x28, + 0x61, 0x3d, 0x65, 0x1f, 0x59, 0x9d, 0x47, 0x98, 0x49, 0x62, 0x2e, 0x59, 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, + 0xa7, 0x60, 0xaf, 0xe1, 0xf7, 0x2a, 0x57, 0x92, 0x53, 0xa6, 0x58, 0xb4, 0x2b, 0xe2, 0xd1, 0x73, 0x1d, 0x97, 0x1d, + 0x30, 0x16, 0x69, 0xc1, 0xdb, 0x3d, 0x9e, 0xcd, 0x82, 0xd6, 0x76, 0x1d, 0x11, 0xac, 0xd2, 0x28, 0x78, 0x2b, 0xd0, + 0xf2, 0xd0, 0x3a, 0x10, 0x5a, 0xce, 0xf2, 0x3b, 0xb2, 0x8c, 0x06, 0xc0, 0x6f, 0x22, 0xea, 0xa2, 0xb2, 0x8e, 0xcc, + 0x5f, 0x67, 0xb7, 0x7c, 0xbe, 0x7a, 0xb7, 0x7c, 0xae, 0x76, 0xcb, 0xcd, 0x1c, 0xfb, 0xd9, 0xb8, 0x83, 0xff, 0xf4, + 0x2a, 0x84, 0x60, 0x55, 0x80, 0x1c, 0x16, 0xda, 0xc5, 0xad, 0x2e, 0xfc, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x8f, 0x0f, + 0x16, 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xaf, 0x5d, 0xab, 0xea, 0x3c, 0xc4, 0x3a, 0xec, 0xb5, 0xb3, 0x5c, 0xd7, 0xbd, + 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0xb8, 0x6a, 0xd1, 0xe9, 0x29, 0x94, 0x8e, 0xb3, 0xe1, 0xbc, + 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0xba, 0x31, 0x8e, 0xea, 0x2a, 0xd2, 0x92, 0xd4, 0x08, 0x0b, 0xbd, + 0x4e, 0x41, 0x01, 0x8c, 0xc9, 0x9c, 0xae, 0xff, 0x70, 0xc5, 0x26, 0xf8, 0xff, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0x8f, + 0x12, 0xe3, 0x46, 0x22, 0xfc, 0x2a, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb2, 0x1a, 0xdc, 0x43, 0x35, 0xd3, 0x91, 0x52, + 0x0a, 0x52, 0xef, 0x80, 0x17, 0x10, 0xcd, 0x13, 0x7e, 0xf3, 0xa8, 0xeb, 0x38, 0x63, 0x69, 0xd4, 0x1b, 0x04, 0x7a, + 0xd5, 0xf6, 0x8e, 0x52, 0xfa, 0xb3, 0xcf, 0x1f, 0xe2, 0x3f, 0x22, 0x70, 0x76, 0x5a, 0xf9, 0x46, 0x22, 0x36, 0x80, + 0xbe, 0xd1, 0xb4, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x5d, 0x5b, 0xa3, 0xb1, 0x7e, 0xa7, 0xe6, 0xd2, 0x2a, + 0xfd, 0x55, 0xad, 0x7f, 0xdd, 0xe0, 0x77, 0x6c, 0x3b, 0x14, 0x0e, 0x41, 0xbd, 0xad, 0x8c, 0x07, 0x2e, 0x35, 0x56, + 0x14, 0xbf, 0x6b, 0xfb, 0xca, 0x24, 0xa6, 0x1e, 0xd3, 0xf0, 0x54, 0x3b, 0x91, 0xf2, 0xf0, 0x1e, 0x7b, 0x08, 0x3f, + 0xf2, 0x4b, 0x16, 0x3e, 0xc0, 0xaf, 0xb1, 0x59, 0x97, 0xd3, 0x24, 0x05, 0xb3, 0x6a, 0xc2, 0xf9, 0x2c, 0xd8, 0xda, + 0xba, 0xb8, 0xb8, 0xf0, 0x2f, 0xb6, 0xfd, 0x2c, 0x3f, 0xdb, 0xea, 0xb6, 0xdb, 0x6d, 0xfc, 0x88, 0x96, 0x6d, 0x9d, + 0xc7, 0xec, 0xe2, 0x29, 0xb8, 0x1f, 0xf6, 0x63, 0xeb, 0x89, 0xf5, 0x78, 0xdb, 0xda, 0x79, 0x64, 0x5b, 0xa4, 0x00, + 0xa0, 0x64, 0xdb, 0xb6, 0x84, 0x02, 0x08, 0x6d, 0x28, 0xee, 0xef, 0x9e, 0x29, 0x1b, 0x0e, 0x2f, 0x29, 0x08, 0x0b, + 0x09, 0xfc, 0xb7, 0xec, 0x13, 0xab, 0x6f, 0x75, 0x51, 0xd6, 0x92, 0x6a, 0x44, 0xbd, 0xe2, 0x7e, 0x1f, 0x46, 0xb3, + 0x80, 0xd8, 0xc8, 0x2c, 0xc4, 0x30, 0x99, 0x28, 0xa5, 0x29, 0xd0, 0x2e, 0x3d, 0x85, 0x27, 0xcc, 0x6a, 0xb3, 0xe0, + 0xf9, 0x4d, 0xf7, 0x31, 0xe8, 0xb8, 0xf3, 0xd6, 0xc3, 0x61, 0xbb, 0xd5, 0xb1, 0x3a, 0xad, 0xae, 0xff, 0xd8, 0xea, + 0x8a, 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, + 0xfd, 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, + 0xb8, 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, + 0xd0, 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, + 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0xef, 0x7c, 0xfb, + 0xc9, 0x10, 0x34, 0x82, 0x85, 0xff, 0xc1, 0x3f, 0x93, 0x9d, 0xee, 0x50, 0xbc, 0xb4, 0xb1, 0xfe, 0xdb, 0xce, 0xe3, + 0x02, 0x9a, 0xe2, 0x3f, 0xbf, 0x68, 0x13, 0x1a, 0x0d, 0x78, 0x73, 0xdc, 0x87, 0x40, 0xa3, 0x27, 0x93, 0xae, 0xff, + 0xf9, 0xf9, 0x63, 0xff, 0xc9, 0xa4, 0xf3, 0xf8, 0x5b, 0xf1, 0x96, 0x00, 0x05, 0x3f, 0xc7, 0xff, 0xbe, 0xdd, 0x6e, + 0x4f, 0x5a, 0x1d, 0xff, 0xc9, 0xf9, 0xb6, 0xbf, 0x9d, 0xb4, 0x1e, 0xf9, 0x4f, 0xf0, 0xbf, 0x6a, 0xb8, 0x49, 0x36, + 0x65, 0xb6, 0x85, 0xeb, 0xdd, 0xf0, 0x7b, 0xcd, 0x39, 0xba, 0x0f, 0xad, 0x9d, 0x87, 0x2f, 0x9f, 0xc0, 0x1a, 0x4d, + 0x3a, 0x5d, 0xf8, 0xff, 0xba, 0xc7, 0x6f, 0x91, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x7a, 0xb1, 0x22, 0x1c, 0x7d, 0xd0, + 0xed, 0x81, 0xf7, 0xa7, 0x75, 0x01, 0x10, 0xc6, 0x6f, 0x0d, 0x80, 0x70, 0x7e, 0xb7, 0x08, 0x08, 0xfd, 0xda, 0xc0, + 0xef, 0x18, 0x01, 0xf9, 0x53, 0x33, 0xc8, 0x7d, 0xc9, 0x96, 0x02, 0x1d, 0x4d, 0x67, 0xed, 0x2d, 0x73, 0x0e, 0xbf, + 0x64, 0x47, 0x98, 0x4a, 0x0f, 0xad, 0x39, 0x37, 0xe3, 0x41, 0x19, 0x6e, 0xe4, 0x4b, 0x26, 0x76, 0x72, 0xc1, 0xd7, + 0x10, 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, + 0x29, 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, + 0xd3, 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, + 0x34, 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, + 0xa6, 0xdf, 0xcf, 0x8a, 0x79, 0x82, 0x97, 0xa6, 0xbd, 0xa1, 0xf8, 0x80, 0x2c, 0x3c, 0xca, 0xbb, 0x86, 0x98, 0xc2, + 0xfe, 0x0d, 0xa6, 0xdf, 0xab, 0xb3, 0x83, 0x29, 0xc6, 0x11, 0xde, 0xb0, 0x51, 0x1c, 0x39, 0xb6, 0x33, 0x83, 0x8d, + 0x0c, 0xb3, 0xb4, 0x6a, 0xb9, 0xef, 0x94, 0xf6, 0xee, 0xda, 0xea, 0xa7, 0x99, 0x72, 0xfc, 0xd4, 0x5d, 0x78, 0x28, + 0xe3, 0x8e, 0xb6, 0x74, 0x0c, 0x60, 0x7c, 0x55, 0x92, 0xa3, 0x0e, 0xa8, 0x8c, 0x09, 0x5b, 0x58, 0x13, 0x1d, 0xbf, + 0x0b, 0xde, 0x05, 0x15, 0xe3, 0xa7, 0xc3, 0xbe, 0x77, 0x5a, 0xdb, 0x60, 0xed, 0x18, 0xdd, 0xf4, 0x40, 0x47, 0xfa, + 0x97, 0x7e, 0xf4, 0xaf, 0xd1, 0xd5, 0x2f, 0x0c, 0xd8, 0x82, 0x23, 0x3e, 0x13, 0xb8, 0xdb, 0xf4, 0x89, 0x06, 0x99, + 0x50, 0x82, 0x17, 0xe6, 0xa0, 0xcc, 0x31, 0x7f, 0x95, 0x4c, 0x7c, 0x9a, 0x4c, 0xfc, 0x00, 0x61, 0x59, 0x35, 0x61, + 0xd5, 0xcf, 0x7f, 0x20, 0x05, 0x99, 0xa7, 0x67, 0x23, 0xea, 0x61, 0x86, 0x07, 0xfe, 0xad, 0x8a, 0xd5, 0x83, 0x8c, + 0x58, 0x81, 0x17, 0x8f, 0xbf, 0xe9, 0x42, 0x7f, 0x96, 0xe2, 0x61, 0x22, 0xca, 0xd1, 0x28, 0xad, 0x86, 0xaa, 0xe2, + 0x5e, 0xc5, 0xd3, 0xab, 0x03, 0xf9, 0x41, 0x03, 0x1b, 0x43, 0xd0, 0x74, 0xf4, 0x50, 0x7d, 0x4c, 0x6d, 0x13, 0xf4, + 0x1e, 0xfd, 0xc4, 0x29, 0x65, 0x0f, 0xa0, 0x6a, 0xc3, 0xfb, 0x04, 0x96, 0x74, 0x81, 0x42, 0x5b, 0x28, 0xb6, 0x11, + 0x3b, 0x8f, 0x87, 0x52, 0x3f, 0x79, 0x96, 0xbc, 0x07, 0xd5, 0x22, 0xba, 0x87, 0x1d, 0x4f, 0x04, 0x01, 0xe0, 0x05, + 0xd5, 0x73, 0x98, 0x66, 0x76, 0xff, 0x41, 0x6f, 0x1d, 0x65, 0xf1, 0xf7, 0x56, 0x0f, 0xc1, 0xe9, 0xfc, 0xdb, 0xf0, + 0x01, 0xfe, 0xe2, 0xea, 0x83, 0x23, 0xdb, 0xf5, 0x49, 0xba, 0x3f, 0xa8, 0x7e, 0x76, 0x15, 0x45, 0xdb, 0x26, 0x28, + 0x62, 0xef, 0xae, 0x1a, 0x59, 0x6a, 0xdf, 0xee, 0x4e, 0xa5, 0x7d, 0xe1, 0xd9, 0x10, 0xb7, 0xa0, 0x09, 0xba, 0xfe, + 0x8e, 0x21, 0xd3, 0xcf, 0x5b, 0xf8, 0xb7, 0x26, 0xd5, 0x1f, 0x42, 0x03, 0x25, 0xd6, 0x5f, 0x43, 0xf3, 0x6d, 0xa1, + 0x41, 0xa0, 0xdf, 0x0f, 0x24, 0x73, 0x85, 0xbc, 0xad, 0xf3, 0xf8, 0x8a, 0xd3, 0x30, 0x91, 0x69, 0x61, 0x7b, 0x46, + 0xe0, 0x4c, 0x6c, 0x39, 0x19, 0x16, 0x7a, 0x0e, 0x7d, 0x1d, 0xfd, 0x8d, 0xf2, 0x55, 0x75, 0x5e, 0x4d, 0x04, 0xac, + 0x98, 0x02, 0x37, 0x6d, 0xe3, 0xc4, 0xad, 0x27, 0x92, 0xb8, 0xf5, 0x47, 0x4e, 0xd6, 0x73, 0xab, 0xcc, 0xf6, 0x76, + 0x8d, 0xfd, 0xcf, 0xe9, 0x3b, 0xaa, 0x34, 0xc9, 0xab, 0x51, 0xd9, 0x9c, 0x1f, 0x6c, 0x16, 0xfc, 0xd1, 0xc9, 0xea, + 0x0a, 0x8f, 0xbc, 0x9b, 0x8b, 0xf9, 0x14, 0xa3, 0x38, 0xa7, 0x2b, 0xdf, 0x0a, 0xf4, 0x5a, 0x54, 0xb5, 0xa2, 0x12, + 0x89, 0x00, 0x56, 0x0c, 0x6c, 0x2c, 0xb2, 0x03, 0x99, 0xf5, 0x67, 0x7e, 0x48, 0xdc, 0xbc, 0x93, 0x3b, 0x12, 0x09, + 0x7f, 0xf8, 0x43, 0x0b, 0xb6, 0xa0, 0x8f, 0x0d, 0xa2, 0x74, 0xed, 0x2e, 0x21, 0x03, 0x0b, 0x71, 0xad, 0x7e, 0x39, + 0xcb, 0x94, 0x2e, 0xb6, 0x49, 0x68, 0x3d, 0x2e, 0x91, 0xd0, 0x95, 0x74, 0x3a, 0x65, 0x11, 0xf7, 0xa3, 0x94, 0x92, + 0xb3, 0x1c, 0x43, 0x06, 0x79, 0x1d, 0xb6, 0xed, 0x96, 0x20, 0xf8, 0x8c, 0x9f, 0x16, 0x13, 0x9b, 0xd9, 0x87, 0x42, + 0xfd, 0x59, 0xab, 0x7a, 0xa2, 0xf5, 0xa4, 0xdb, 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, + 0xe4, 0x9e, 0x8b, 0x3c, 0x95, 0x50, 0xe4, 0xa9, 0x58, 0x22, 0xbb, 0x4d, 0x24, 0x26, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, + 0xa5, 0x43, 0x11, 0x57, 0x9c, 0x82, 0x0b, 0x13, 0xe3, 0xc7, 0xe7, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x29, + 0x3f, 0xca, 0x68, 0xe1, 0xa9, 0x8a, 0x42, 0x82, 0xa9, 0xc1, 0x54, 0xf6, 0x8f, 0x1c, 0x4a, 0x27, 0x1d, 0x2f, 0xb7, + 0x2e, 0xe6, 0xa7, 0x53, 0x10, 0x82, 0x2a, 0x63, 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x26, + 0x55, 0x1f, 0x06, 0x6f, 0xfc, 0x88, 0xaa, 0xc0, 0x5e, 0x0a, 0x7d, 0x4c, 0x38, 0x99, 0x6c, 0x1b, 0x09, 0x27, 0x46, + 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x83, 0xac, 0xa2, 0x3d, 0x28, 0x94, + 0x01, 0x25, 0x8f, 0x8b, 0x4b, 0x1b, 0x12, 0x60, 0x58, 0x41, 0x80, 0x49, 0xea, 0x77, 0x8b, 0xce, 0xb5, 0xed, 0x9d, + 0xb6, 0xca, 0xc9, 0x85, 0x32, 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0xb6, 0x3b, 0xe9, 0xf4, 0x77, 0x23, 0x69, + 0x39, 0xa2, 0xf0, 0x28, 0x40, 0x7a, 0x40, 0x67, 0x34, 0xcf, 0xfc, 0x38, 0xdb, 0xba, 0x60, 0xa7, 0xad, 0x68, 0x16, + 0x57, 0x81, 0x54, 0xb4, 0x23, 0xf4, 0x94, 0x59, 0x35, 0x13, 0x3e, 0x46, 0x0d, 0x24, 0x49, 0x70, 0x97, 0x32, 0x4a, + 0x4b, 0xe6, 0x37, 0xb0, 0x10, 0x50, 0x98, 0xe4, 0xba, 0x8a, 0xe6, 0x4a, 0x75, 0x5a, 0xda, 0xfd, 0xbf, 0xfc, 0xf3, + 0xff, 0x96, 0x01, 0x5a, 0xa0, 0x4a, 0x47, 0x8d, 0xd5, 0x20, 0x74, 0xb9, 0x8b, 0xf9, 0x4d, 0xd5, 0x11, 0x2e, 0xbb, + 0x04, 0x4f, 0x3f, 0x1e, 0xb5, 0x26, 0x51, 0x32, 0x06, 0xc0, 0xd6, 0x12, 0xc8, 0xcc, 0x7e, 0x90, 0x50, 0xd7, 0x8b, + 0x90, 0x05, 0x7f, 0x53, 0x96, 0xb5, 0xca, 0x6e, 0xa7, 0xdd, 0x6a, 0xe4, 0x5c, 0x1b, 0x1b, 0xaa, 0x96, 0x77, 0xad, + 0x7e, 0x95, 0x4c, 0x0a, 0x35, 0x56, 0x4b, 0xba, 0x86, 0x96, 0xfa, 0xa4, 0xe9, 0xdf, 0xff, 0xe5, 0x1f, 0xfe, 0x87, + 0x7a, 0xc5, 0x03, 0xa4, 0xbf, 0xfc, 0xd3, 0xdf, 0x61, 0x7e, 0xb3, 0xa5, 0x0f, 0x99, 0x48, 0x4e, 0x58, 0xd5, 0x09, + 0x93, 0x10, 0x18, 0x56, 0xe5, 0xd1, 0xd5, 0x93, 0xb3, 0xf7, 0x69, 0x42, 0xda, 0x6c, 0x12, 0x3a, 0xda, 0xb4, 0x65, + 0xc5, 0x23, 0x35, 0x92, 0x13, 0x2f, 0x42, 0x25, 0xd2, 0xfb, 0x4e, 0x99, 0x4f, 0xbe, 0x5e, 0x8d, 0x85, 0x0a, 0xff, + 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x97, 0x5f, 0xe0, 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0xf1, 0x6a, 0x7d, 0x7a, 0x3f, + 0xcd, 0x01, 0xfe, 0x31, 0x52, 0x5c, 0x04, 0x19, 0xe9, 0xcc, 0xb9, 0x85, 0x06, 0x5d, 0x72, 0x55, 0xd2, 0x28, 0xc2, + 0x0b, 0x7c, 0xf8, 0xe4, 0x6f, 0xca, 0x3f, 0x4e, 0xd1, 0x6c, 0xb2, 0x9c, 0x69, 0x74, 0x29, 0x7d, 0xc3, 0x47, 0xed, + 0xf6, 0xec, 0xd2, 0x5d, 0x54, 0x33, 0x78, 0xeb, 0x26, 0xa3, 0xc0, 0xa4, 0x39, 0x20, 0x1d, 0x56, 0xeb, 0x18, 0x28, + 0xb8, 0x43, 0x6d, 0x0c, 0x99, 0x95, 0xe5, 0x1f, 0x16, 0x14, 0x86, 0x8b, 0x7f, 0xc1, 0x43, 0x65, 0x19, 0xb1, 0x84, + 0x12, 0x03, 0x8b, 0x85, 0xd1, 0xab, 0x2b, 0x7a, 0x4d, 0x3a, 0xcb, 0x39, 0x41, 0xe6, 0xa1, 0xb8, 0x79, 0x9c, 0xfd, + 0x10, 0x0f, 0xa8, 0x27, 0x1d, 0x6f, 0xd2, 0x5d, 0xe8, 0xe1, 0x39, 0xcf, 0xa6, 0xe6, 0x29, 0x38, 0x8b, 0xd8, 0x90, + 0x8d, 0x55, 0xa4, 0x57, 0xd6, 0x8b, 0x13, 0xee, 0x72, 0xb2, 0xbd, 0x62, 0x2e, 0x09, 0x12, 0x9d, 0x7e, 0x03, 0x3c, + 0x9f, 0xe1, 0x06, 0x04, 0xfa, 0x67, 0x11, 0x0f, 0x88, 0x5f, 0x7b, 0xe6, 0x59, 0x7a, 0x84, 0x52, 0x26, 0x5b, 0x18, + 0xf0, 0xf4, 0x44, 0x53, 0x8c, 0xb9, 0xd6, 0x73, 0xb2, 0x4a, 0x9f, 0xba, 0x9b, 0x43, 0x89, 0x90, 0xcd, 0xb7, 0xf2, + 0x88, 0xfa, 0x69, 0x2d, 0xd6, 0x21, 0x55, 0x4c, 0xd7, 0xf5, 0x56, 0xd6, 0x0b, 0x4d, 0x2d, 0x6a, 0xbf, 0x05, 0x03, + 0x8c, 0xc0, 0xb4, 0x9b, 0xad, 0xa8, 0x10, 0x5b, 0x3d, 0x0d, 0xbf, 0xd5, 0x7e, 0x4d, 0x34, 0x9b, 0x51, 0x43, 0x17, + 0x98, 0x98, 0xac, 0x51, 0x94, 0x1d, 0x94, 0x7e, 0x21, 0xb2, 0x1d, 0x64, 0x1b, 0xb9, 0x11, 0xc4, 0x93, 0xcc, 0x83, + 0xa0, 0xdf, 0xb7, 0xff, 0x7f, 0x47, 0x48, 0x09, 0x5d, 0xf5, 0x7e, 0x00, 0x00}; } // namespace web_server } // namespace esphome From 7ef8d67831b11122f3b579c972a0045e748d4974 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:31:23 +1200 Subject: [PATCH 0126/2607] Bump version to 2023.6.0b6 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e698ffcc64..2197b34034 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b5" +__version__ = "2023.6.0b6" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 314c1c8b5cc98acba1a4f8185b1aec6d47920754 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 22 Jun 2023 01:45:41 +0200 Subject: [PATCH 0127/2607] Migrate VOC sensors that use ppb to use volatile_organic_compounds_parts device class (#4982) --- esphome/components/airthings_wave_base/__init__.py | 2 ++ esphome/components/ccs811/sensor.py | 4 ++-- esphome/components/sgp30/sensor.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py index 3ff55fc6b0..c935ce108a 100644 --- a/esphome/components/airthings_wave_base/__init__.py +++ b/esphome/components/airthings_wave_base/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_TVOC, CONF_PRESSURE, CONF_TEMPERATURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, UNIT_PARTS_PER_BILLION, ICON_RADIATOR, ) @@ -53,6 +54,7 @@ BASE_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), } diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index cb5c1108ba..af3e6574ab 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -6,7 +6,7 @@ from esphome.const import ( ICON_RADIATOR, ICON_RESTART, DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, @@ -43,7 +43,7 @@ CONFIG_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 0029e2c515..6f8ed42d25 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_TVOC, ICON_RADIATOR, DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, @@ -49,7 +49,7 @@ CONFIG_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ECO2_BASELINE): sensor.sensor_schema( From f72b07eb0e1b431128aa6f6b231aadfb1d335376 Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Wed, 21 Jun 2023 20:48:17 -0300 Subject: [PATCH 0128/2607] dashboard: Adds "compressed=1" to /download.bin endpoint. (...) (#4966) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/dashboard/dashboard.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 8d8eb74b4b..22bbe0aae9 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -3,6 +3,7 @@ import binascii import codecs import collections import functools +import gzip import hashlib import hmac import json @@ -485,6 +486,7 @@ class DownloadBinaryRequestHandler(BaseHandler): @bind_config def get(self, configuration=None): type = self.get_argument("type", "firmware.bin") + compressed = self.get_argument("compressed", "0") == "1" storage_path = ext_storage_path(settings.config_dir, configuration) storage_json = StorageJSON.load(storage_path) @@ -534,6 +536,8 @@ class DownloadBinaryRequestHandler(BaseHandler): self.send_error(404) return + filename = filename + ".gz" if compressed else filename + self.set_header("Content-Type", "application/octet-stream") self.set_header("Content-Disposition", f'attachment; filename="{filename}"') self.set_header("Cache-Control", "no-cache") @@ -543,9 +547,20 @@ class DownloadBinaryRequestHandler(BaseHandler): with open(path, "rb") as f: while True: - data = f.read(16384) + # For a 528KB image used as benchmark: + # - using 256KB blocks resulted in the smallest file size. + # - blocks larger than 256KB didn't improve the size of compressed file. + # - blocks smaller than 256KB hindered compression, making the output file larger. + + # Read file in blocks of 256KB. + data = f.read(256 * 1024) + if not data: break + + if compressed: + data = gzip.compress(data, 9) + self.write(data) self.finish() From 244a2125929fa8c77c1a64b7a7558d185edabadf Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 20 Jun 2023 19:53:44 -0400 Subject: [PATCH 0129/2607] airthings_wave: refactor to eliminate code duplication (#4910) --- CODEOWNERS | 1 + .../airthings_wave_base/__init__.py | 81 ++++++++++++ .../airthings_wave_base.cpp | 83 ++++++++++++ .../airthings_wave_base/airthings_wave_base.h | 50 ++++++++ .../airthings_wave_mini.cpp | 102 ++++----------- .../airthings_wave_mini/airthings_wave_mini.h | 34 +---- .../components/airthings_wave_mini/sensor.py | 74 ++--------- .../airthings_wave_plus.cpp | 118 +++++------------- .../airthings_wave_plus/airthings_wave_plus.h | 31 +---- .../components/airthings_wave_plus/sensor.py | 108 +++++----------- tests/test2.yaml | 6 +- 11 files changed, 317 insertions(+), 371 deletions(-) create mode 100644 esphome/components/airthings_wave_base/__init__.py create mode 100644 esphome/components/airthings_wave_base/airthings_wave_base.cpp create mode 100644 esphome/components/airthings_wave_base/airthings_wave_base.h diff --git a/CODEOWNERS b/CODEOWNERS index c6cbf3c2ab..b4ed234e22 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -17,6 +17,7 @@ esphome/components/adc/* @esphome/core esphome/components/adc128s102/* @DeerMaximum esphome/components/addressable_light/* @justfalter esphome/components/airthings_ble/* @jeromelaban +esphome/components/airthings_wave_base/* @jeromelaban @ncareau esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban esphome/components/alarm_control_panel/* @grahambrown11 diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py new file mode 100644 index 0000000000..3ff55fc6b0 --- /dev/null +++ b/esphome/components/airthings_wave_base/__init__.py @@ -0,0 +1,81 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, ble_client + +from esphome.const import ( + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, + UNIT_PERCENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, + CONF_HUMIDITY, + CONF_TVOC, + CONF_PRESSURE, + CONF_TEMPERATURE, + UNIT_PARTS_PER_BILLION, + ICON_RADIATOR, +) + +CODEOWNERS = ["@ncareau", "@jeromelaban"] + +DEPENDENCIES = ["ble_client"] + +airthings_wave_base_ns = cg.esphome_ns.namespace("airthings_wave_base") +AirthingsWaveBase = airthings_wave_base_ns.class_( + "AirthingsWaveBase", cg.PollingComponent, ble_client.BLEClientNode +) + + +BASE_SCHEMA = ( + sensor.SENSOR_SCHEMA.extend( + { + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + accuracy_decimals=0, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TVOC): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_BILLION, + icon=ICON_RADIATOR, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("5min")) + .extend(ble_client.BLE_CLIENT_SCHEMA) +) + + +async def wave_base_to_code(var, config): + await cg.register_component(var, config) + + await ble_client.register_ble_node(var, config) + + if CONF_HUMIDITY in config: + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + cg.add(var.set_humidity(sens)) + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature(sens)) + if CONF_PRESSURE in config: + sens = await sensor.new_sensor(config[CONF_PRESSURE]) + cg.add(var.set_pressure(sens)) + if CONF_TVOC in config: + sens = await sensor.new_sensor(config[CONF_TVOC]) + cg.add(var.set_tvoc(sens)) diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.cpp b/esphome/components/airthings_wave_base/airthings_wave_base.cpp new file mode 100644 index 0000000000..349d8d58eb --- /dev/null +++ b/esphome/components/airthings_wave_base/airthings_wave_base.cpp @@ -0,0 +1,83 @@ +#include "airthings_wave_base.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace airthings_wave_base { + +static const char *const TAG = "airthings_wave_base"; + +void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) { + switch (event) { + case ESP_GATTC_OPEN_EVT: { + if (param->open.status == ESP_GATT_OK) { + ESP_LOGI(TAG, "Connected successfully!"); + } + break; + } + + case ESP_GATTC_DISCONNECT_EVT: { + ESP_LOGW(TAG, "Disconnected!"); + break; + } + + case ESP_GATTC_SEARCH_CMPL_EVT: { + this->handle_ = 0; + auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); + if (chr == nullptr) { + ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), + this->sensors_data_characteristic_uuid_.to_string().c_str()); + break; + } + this->handle_ = chr->handle; + this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; + + this->request_read_values_(); + break; + } + + case ESP_GATTC_READ_CHAR_EVT: { + if (param->read.conn_id != this->parent()->get_conn_id()) + break; + if (param->read.status != ESP_GATT_OK) { + ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); + break; + } + if (param->read.handle == this->handle_) { + this->read_sensors(param->read.value, param->read.value_len); + } + break; + } + + default: + break; + } +} + +bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } + +void AirthingsWaveBase::update() { + if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { + if (!this->parent()->enabled) { + ESP_LOGW(TAG, "Reconnecting to device"); + this->parent()->set_enabled(true); + this->parent()->connect(); + } else { + ESP_LOGW(TAG, "Connection in progress"); + } + } +} + +void AirthingsWaveBase::request_read_values_() { + auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, + ESP_GATT_AUTH_REQ_NONE); + if (status) { + ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); + } +} + +} // namespace airthings_wave_base +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.h b/esphome/components/airthings_wave_base/airthings_wave_base.h new file mode 100644 index 0000000000..68c0b3497d --- /dev/null +++ b/esphome/components/airthings_wave_base/airthings_wave_base.h @@ -0,0 +1,50 @@ +#pragma once + +#ifdef USE_ESP32 + +#include +#include +#include +#include "esphome/components/ble_client/ble_client.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace airthings_wave_base { + +class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientNode { + public: + AirthingsWaveBase() = default; + + void update() override; + + void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) override; + + void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } + void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } + void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } + void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } + + protected: + bool is_valid_voc_value_(uint16_t voc); + + virtual void read_sensors(uint8_t *value, uint16_t value_len) = 0; + void request_read_values_(); + + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *humidity_sensor_{nullptr}; + sensor::Sensor *pressure_sensor_{nullptr}; + sensor::Sensor *tvoc_sensor_{nullptr}; + + uint16_t handle_; + esp32_ble_tracker::ESPBTUUID service_uuid_; + esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; +}; + +} // namespace airthings_wave_base +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp index 40873ec005..331a13434f 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp @@ -7,105 +7,47 @@ namespace airthings_wave_mini { static const char *const TAG = "airthings_wave_mini"; -void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) { - switch (event) { - case ESP_GATTC_OPEN_EVT: { - if (param->open.status == ESP_GATT_OK) { - ESP_LOGI(TAG, "Connected successfully!"); - } - break; - } - - case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGW(TAG, "Disconnected!"); - break; - } - - case ESP_GATTC_SEARCH_CMPL_EVT: { - this->handle_ = 0; - auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); - if (chr == nullptr) { - ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), - sensors_data_characteristic_uuid_.to_string().c_str()); - break; - } - this->handle_ = chr->handle; - this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; - - request_read_values_(); - break; - } - - case ESP_GATTC_READ_CHAR_EVT: { - if (param->read.conn_id != this->parent()->get_conn_id()) - break; - if (param->read.status != ESP_GATT_OK) { - ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); - break; - } - if (param->read.handle == this->handle_) { - read_sensors_(param->read.value, param->read.value_len); - } - break; - } - - default: - break; - } -} - -void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) { +void AirthingsWaveMini::read_sensors(uint8_t *raw_value, uint16_t value_len) { auto *value = (WaveMiniReadings *) raw_value; if (sizeof(WaveMiniReadings) <= value_len) { - this->humidity_sensor_->publish_state(value->humidity / 100.0f); - this->pressure_sensor_->publish_state(value->pressure / 50.0f); - this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); - if (is_valid_voc_value_(value->voc)) { + if (this->humidity_sensor_ != nullptr) { + this->humidity_sensor_->publish_state(value->humidity / 100.0f); + } + + if (this->pressure_sensor_ != nullptr) { + this->pressure_sensor_->publish_state(value->pressure / 50.0f); + } + + if (this->temperature_sensor_ != nullptr) { + this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); + } + + if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } // This instance must not stay connected // so other clients can connect to it (e.g. the // mobile app). - parent()->set_enabled(false); - } -} - -bool AirthingsWaveMini::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } - -void AirthingsWaveMini::update() { - if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { - if (!parent()->enabled) { - ESP_LOGW(TAG, "Reconnecting to device"); - parent()->set_enabled(true); - parent()->connect(); - } else { - ESP_LOGW(TAG, "Connection in progress"); - } - } -} - -void AirthingsWaveMini::request_read_values_() { - auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, - ESP_GATT_AUTH_REQ_NONE); - if (status) { - ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); + this->parent()->set_enabled(false); } } void AirthingsWaveMini::dump_config() { + // these really don't belong here, but there doesn't seem to be a + // practical way to have the base class use LOG_SENSOR and include + // the TAG from this component LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); } -AirthingsWaveMini::AirthingsWaveMini() - : PollingComponent(10000), - service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), - sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} +AirthingsWaveMini::AirthingsWaveMini() { + this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); +} } // namespace airthings_wave_mini } // namespace esphome diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.h b/esphome/components/airthings_wave_mini/airthings_wave_mini.h index 128774f9cb..ec4fd23e60 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.h +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.h @@ -2,14 +2,7 @@ #ifdef USE_ESP32 -#include -#include -#include -#include "esphome/components/ble_client/ble_client.h" -#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" -#include "esphome/components/sensor/sensor.h" -#include "esphome/core/component.h" -#include "esphome/core/log.h" +#include "esphome/components/airthings_wave_base/airthings_wave_base.h" namespace esphome { namespace airthings_wave_mini { @@ -17,35 +10,14 @@ namespace airthings_wave_mini { static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba"; -class AirthingsWaveMini : public PollingComponent, public ble_client::BLEClientNode { +class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase { public: AirthingsWaveMini(); void dump_config() override; - void update() override; - - void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) override; - - void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } - void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } - void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } - void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } protected: - bool is_valid_voc_value_(uint16_t voc); - - void read_sensors_(uint8_t *value, uint16_t value_len); - void request_read_values_(); - - sensor::Sensor *temperature_sensor_{nullptr}; - sensor::Sensor *humidity_sensor_{nullptr}; - sensor::Sensor *pressure_sensor_{nullptr}; - sensor::Sensor *tvoc_sensor_{nullptr}; - - uint16_t handle_; - esp32_ble_tracker::ESPBTUUID service_uuid_; - esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; + void read_sensors(uint8_t *value, uint16_t value_len) override; struct WaveMiniReadings { uint16_t unused01; diff --git a/esphome/components/airthings_wave_mini/sensor.py b/esphome/components/airthings_wave_mini/sensor.py index d38354fa84..0f4fd1a13a 100644 --- a/esphome/components/airthings_wave_mini/sensor.py +++ b/esphome/components/airthings_wave_mini/sensor.py @@ -1,82 +1,28 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor, ble_client +from esphome.components import airthings_wave_base from esphome.const import ( - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, - STATE_CLASS_MEASUREMENT, - UNIT_PERCENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, CONF_ID, - CONF_HUMIDITY, - CONF_TVOC, - CONF_PRESSURE, - CONF_TEMPERATURE, - UNIT_PARTS_PER_BILLION, - ICON_RADIATOR, ) -DEPENDENCIES = ["ble_client"] +DEPENDENCIES = airthings_wave_base.DEPENDENCIES + +AUTO_LOAD = ["airthings_wave_base"] airthings_wave_mini_ns = cg.esphome_ns.namespace("airthings_wave_mini") AirthingsWaveMini = airthings_wave_mini_ns.class_( - "AirthingsWaveMini", cg.PollingComponent, ble_client.BLEClientNode + "AirthingsWaveMini", airthings_wave_base.AirthingsWaveBase ) -CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(AirthingsWaveMini), - cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - unit_of_measurement=UNIT_PERCENT, - device_class=DEVICE_CLASS_HUMIDITY, - state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=2, - ), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=2, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=2, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TVOC): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - } - ) - .extend(cv.polling_component_schema("5min")) - .extend(ble_client.BLE_CLIENT_SCHEMA), +CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AirthingsWaveMini), + } ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - - await ble_client.register_ble_node(var, config) - - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) - cg.add(var.set_humidity(sens)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) - cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - sens = await sensor.new_sensor(config[CONF_PRESSURE]) - cg.add(var.set_pressure(sens)) - if CONF_TVOC in config: - sens = await sensor.new_sensor(config[CONF_TVOC]) - cg.add(var.set_tvoc(sens)) + await airthings_wave_base.wave_base_to_code(var, config) diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index 11f86307fe..acd3a4316d 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -7,55 +7,7 @@ namespace airthings_wave_plus { static const char *const TAG = "airthings_wave_plus"; -void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) { - switch (event) { - case ESP_GATTC_OPEN_EVT: { - if (param->open.status == ESP_GATT_OK) { - ESP_LOGI(TAG, "Connected successfully!"); - } - break; - } - - case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGW(TAG, "Disconnected!"); - break; - } - - case ESP_GATTC_SEARCH_CMPL_EVT: { - this->handle_ = 0; - auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); - if (chr == nullptr) { - ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), - sensors_data_characteristic_uuid_.to_string().c_str()); - break; - } - this->handle_ = chr->handle; - this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; - - request_read_values_(); - break; - } - - case ESP_GATTC_READ_CHAR_EVT: { - if (param->read.conn_id != this->parent()->get_conn_id()) - break; - if (param->read.status != ESP_GATT_OK) { - ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); - break; - } - if (param->read.handle == this->handle_) { - read_sensors_(param->read.value, param->read.value_len); - } - break; - } - - default: - break; - } -} - -void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { +void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { auto *value = (WavePlusReadings *) raw_value; if (sizeof(WavePlusReadings) <= value_len) { @@ -64,26 +16,38 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { if (value->version == 1) { ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); - this->humidity_sensor_->publish_state(value->humidity / 2.0f); - if (is_valid_radon_value_(value->radon)) { + if (this->humidity_sensor_ != nullptr) { + this->humidity_sensor_->publish_state(value->humidity / 2.0f); + } + + if ((this->radon_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon)) { this->radon_sensor_->publish_state(value->radon); } - if (is_valid_radon_value_(value->radon_lt)) { + + if ((this->radon_long_term_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon_lt)) { this->radon_long_term_sensor_->publish_state(value->radon_lt); } - this->temperature_sensor_->publish_state(value->temperature / 100.0f); - this->pressure_sensor_->publish_state(value->pressure / 50.0f); - if (is_valid_co2_value_(value->co2)) { + + if (this->temperature_sensor_ != nullptr) { + this->temperature_sensor_->publish_state(value->temperature / 100.0f); + } + + if (this->pressure_sensor_ != nullptr) { + this->pressure_sensor_->publish_state(value->pressure / 50.0f); + } + + if ((this->co2_sensor_ != nullptr) && this->is_valid_co2_value_(value->co2)) { this->co2_sensor_->publish_state(value->co2); } - if (is_valid_voc_value_(value->voc)) { + + if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } // This instance must not stay connected // so other clients can connect to it (e.g. the // mobile app). - parent()->set_enabled(false); + this->parent()->set_enabled(false); } else { ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); } @@ -92,44 +56,26 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } -bool AirthingsWavePlus::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } - bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } -void AirthingsWavePlus::update() { - if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { - if (!parent()->enabled) { - ESP_LOGW(TAG, "Reconnecting to device"); - parent()->set_enabled(true); - parent()->connect(); - } else { - ESP_LOGW(TAG, "Connection in progress"); - } - } -} - -void AirthingsWavePlus::request_read_values_() { - auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, - ESP_GATT_AUTH_REQ_NONE); - if (status) { - ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); - } -} - void AirthingsWavePlus::dump_config() { + // these really don't belong here, but there doesn't seem to be a + // practical way to have the base class use LOG_SENSOR and include + // the TAG from this component LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); - LOG_SENSOR(" ", "Radon", this->radon_sensor_); - LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); - LOG_SENSOR(" ", "CO2", this->co2_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); + + LOG_SENSOR(" ", "Radon", this->radon_sensor_); + LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); + LOG_SENSOR(" ", "CO2", this->co2_sensor_); } -AirthingsWavePlus::AirthingsWavePlus() - : PollingComponent(10000), - service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), - sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} +AirthingsWavePlus::AirthingsWavePlus() { + this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); +} } // namespace airthings_wave_plus } // namespace esphome diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.h b/esphome/components/airthings_wave_plus/airthings_wave_plus.h index 9dd6ed92d5..4acfb9279a 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.h +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.h @@ -2,14 +2,7 @@ #ifdef USE_ESP32 -#include -#include -#include -#include "esphome/components/ble_client/ble_client.h" -#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" -#include "esphome/components/sensor/sensor.h" -#include "esphome/core/component.h" -#include "esphome/core/log.h" +#include "esphome/components/airthings_wave_base/airthings_wave_base.h" namespace esphome { namespace airthings_wave_plus { @@ -17,43 +10,25 @@ namespace airthings_wave_plus { static const char *const SERVICE_UUID = "b42e1c08-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e2a68-ade7-11e4-89d3-123b93f75cba"; -class AirthingsWavePlus : public PollingComponent, public ble_client::BLEClientNode { +class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { public: AirthingsWavePlus(); void dump_config() override; - void update() override; - void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) override; - - void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } - void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } - void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } - void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } protected: bool is_valid_radon_value_(uint16_t radon); - bool is_valid_voc_value_(uint16_t voc); bool is_valid_co2_value_(uint16_t co2); - void read_sensors_(uint8_t *value, uint16_t value_len); - void request_read_values_(); + void read_sensors(uint8_t *value, uint16_t value_len) override; - sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *radon_sensor_{nullptr}; sensor::Sensor *radon_long_term_sensor_{nullptr}; - sensor::Sensor *humidity_sensor_{nullptr}; - sensor::Sensor *pressure_sensor_{nullptr}; sensor::Sensor *co2_sensor_{nullptr}; - sensor::Sensor *tvoc_sensor_{nullptr}; - - uint16_t handle_; - esp32_ble_tracker::ESPBTUUID service_uuid_; - esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; struct WavePlusReadings { uint8_t version; diff --git a/esphome/components/airthings_wave_plus/sensor.py b/esphome/components/airthings_wave_plus/sensor.py index 727fbe15fb..a5903b1d42 100644 --- a/esphome/components/airthings_wave_plus/sensor.py +++ b/esphome/components/airthings_wave_plus/sensor.py @@ -1,116 +1,64 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor, ble_client +from esphome.components import sensor, airthings_wave_base from esphome.const import ( DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, STATE_CLASS_MEASUREMENT, - UNIT_PERCENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, ICON_RADIOACTIVE, CONF_ID, CONF_RADON, CONF_RADON_LONG_TERM, - CONF_HUMIDITY, - CONF_TVOC, CONF_CO2, - CONF_PRESSURE, - CONF_TEMPERATURE, UNIT_BECQUEREL_PER_CUBIC_METER, UNIT_PARTS_PER_MILLION, - UNIT_PARTS_PER_BILLION, - ICON_RADIATOR, ) -DEPENDENCIES = ["ble_client"] +DEPENDENCIES = airthings_wave_base.DEPENDENCIES + +AUTO_LOAD = ["airthings_wave_base"] airthings_wave_plus_ns = cg.esphome_ns.namespace("airthings_wave_plus") AirthingsWavePlus = airthings_wave_plus_ns.class_( - "AirthingsWavePlus", cg.PollingComponent, ble_client.BLEClientNode + "AirthingsWavePlus", airthings_wave_base.AirthingsWaveBase ) -CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(AirthingsWavePlus), - cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - unit_of_measurement=UNIT_PERCENT, - device_class=DEVICE_CLASS_HUMIDITY, - state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=0, - ), - cv.Optional(CONF_RADON): sensor.sensor_schema( - unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, - icon=ICON_RADIOACTIVE, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( - unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, - icon=ICON_RADIOACTIVE, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=2, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_CO2): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_MILLION, - accuracy_decimals=0, - device_class=DEVICE_CLASS_CARBON_DIOXIDE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_TVOC): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, - accuracy_decimals=0, - state_class=STATE_CLASS_MEASUREMENT, - ), - } - ) - .extend(cv.polling_component_schema("5min")) - .extend(ble_client.BLE_CLIENT_SCHEMA), +CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AirthingsWavePlus), + cv.Optional(CONF_RADON): sensor.sensor_schema( + unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, + icon=ICON_RADIOACTIVE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( + unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, + icon=ICON_RADIOACTIVE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CO2): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + accuracy_decimals=0, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) + await airthings_wave_base.wave_base_to_code(var, config) - await ble_client.register_ble_node(var, config) - - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) - cg.add(var.set_humidity(sens)) if CONF_RADON in config: sens = await sensor.new_sensor(config[CONF_RADON]) cg.add(var.set_radon(sens)) if CONF_RADON_LONG_TERM in config: sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) cg.add(var.set_radon_long_term(sens)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) - cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - sens = await sensor.new_sensor(config[CONF_PRESSURE]) - cg.add(var.set_pressure(sens)) if CONF_CO2 in config: sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2(sens)) - if CONF_TVOC in config: - sens = await sensor.new_sensor(config[CONF_TVOC]) - cg.add(var.set_tvoc(sens)) diff --git a/tests/test2.yaml b/tests/test2.yaml index fa4b97c7c1..aa3e467816 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -312,7 +312,8 @@ sensor: id: freezer_temp_source reference_voltage: 3.19 number: 0 - - platform: airthings_wave_plus + - id: airthingswp + platform: airthings_wave_plus ble_client_id: airthings01 update_interval: 5min temperature: @@ -329,7 +330,8 @@ sensor: name: Wave Plus CO2 tvoc: name: Wave Plus VOC - - platform: airthings_wave_mini + - id: airthingswm + platform: airthings_wave_mini ble_client_id: airthingsmini01 update_interval: 5min temperature: From cd773a1decb5af2724c79e7272f291c5538bd82e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 22 Jun 2023 01:45:41 +0200 Subject: [PATCH 0130/2607] Migrate VOC sensors that use ppb to use volatile_organic_compounds_parts device class (#4982) --- esphome/components/airthings_wave_base/__init__.py | 2 ++ esphome/components/ccs811/sensor.py | 4 ++-- esphome/components/sgp30/sensor.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py index 3ff55fc6b0..c935ce108a 100644 --- a/esphome/components/airthings_wave_base/__init__.py +++ b/esphome/components/airthings_wave_base/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_TVOC, CONF_PRESSURE, CONF_TEMPERATURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, UNIT_PARTS_PER_BILLION, ICON_RADIATOR, ) @@ -53,6 +54,7 @@ BASE_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), } diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index cb5c1108ba..af3e6574ab 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -6,7 +6,7 @@ from esphome.const import ( ICON_RADIATOR, ICON_RESTART, DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, @@ -43,7 +43,7 @@ CONFIG_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 0029e2c515..6f8ed42d25 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_TVOC, ICON_RADIATOR, DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, @@ -49,7 +49,7 @@ CONFIG_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_BILLION, icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ECO2_BASELINE): sensor.sensor_schema( From ef8180c8a87313f5f656cbce77011c62c76e4f81 Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Wed, 21 Jun 2023 20:48:17 -0300 Subject: [PATCH 0131/2607] dashboard: Adds "compressed=1" to /download.bin endpoint. (...) (#4966) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/dashboard/dashboard.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 8d8eb74b4b..22bbe0aae9 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -3,6 +3,7 @@ import binascii import codecs import collections import functools +import gzip import hashlib import hmac import json @@ -485,6 +486,7 @@ class DownloadBinaryRequestHandler(BaseHandler): @bind_config def get(self, configuration=None): type = self.get_argument("type", "firmware.bin") + compressed = self.get_argument("compressed", "0") == "1" storage_path = ext_storage_path(settings.config_dir, configuration) storage_json = StorageJSON.load(storage_path) @@ -534,6 +536,8 @@ class DownloadBinaryRequestHandler(BaseHandler): self.send_error(404) return + filename = filename + ".gz" if compressed else filename + self.set_header("Content-Type", "application/octet-stream") self.set_header("Content-Disposition", f'attachment; filename="{filename}"') self.set_header("Cache-Control", "no-cache") @@ -543,9 +547,20 @@ class DownloadBinaryRequestHandler(BaseHandler): with open(path, "rb") as f: while True: - data = f.read(16384) + # For a 528KB image used as benchmark: + # - using 256KB blocks resulted in the smallest file size. + # - blocks larger than 256KB didn't improve the size of compressed file. + # - blocks smaller than 256KB hindered compression, making the output file larger. + + # Read file in blocks of 256KB. + data = f.read(256 * 1024) + if not data: break + + if compressed: + data = gzip.compress(data, 9) + self.write(data) self.finish() From a2734330e14835b8e02959592610dd3d36255e45 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 22 Jun 2023 11:50:46 +1200 Subject: [PATCH 0132/2607] Bump version to 2023.6.0b7 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 2197b34034..71d136b97f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b6" +__version__ = "2023.6.0b7" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From ceca91d1e77ee20013ab6dc8e5d4b66d2b5ebdc0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:39:10 +1200 Subject: [PATCH 0133/2607] Bump version to 2023.6.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 71d136b97f..f49cff3b61 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0b7" +__version__ = "2023.6.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 52d7d2cae7a41100116b2e089cf2b6576808ad24 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 22 Jun 2023 06:09:00 +0200 Subject: [PATCH 0134/2607] Make ethernet_info work with esp-idf framework (#4976) --- .../components/ethernet_info/ethernet_info_text_sensor.cpp | 4 ++-- esphome/components/ethernet_info/ethernet_info_text_sensor.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp index e69872c290..f841875396 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp @@ -1,7 +1,7 @@ #include "ethernet_info_text_sensor.h" #include "esphome/core/log.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#ifdef USE_ESP32 namespace esphome { namespace ethernet_info { @@ -13,4 +13,4 @@ void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IP } // namespace ethernet_info } // namespace esphome -#endif // USE_ESP32_FRAMEWORK_ARDUINO +#endif // USE_ESP32 diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.h b/esphome/components/ethernet_info/ethernet_info_text_sensor.h index aad8f362b5..2d46fe18eb 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.h +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.h @@ -4,7 +4,7 @@ #include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/ethernet/ethernet_component.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#ifdef USE_ESP32 namespace esphome { namespace ethernet_info { @@ -30,4 +30,4 @@ class IPAddressEthernetInfo : public PollingComponent, public text_sensor::TextS } // namespace ethernet_info } // namespace esphome -#endif // USE_ESP32_FRAMEWORK_ARDUINO +#endif // USE_ESP32 From 85608a8ab7f20762dcc45e27876874cb0bbf8a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 22 Jun 2023 21:18:29 +0200 Subject: [PATCH 0135/2607] display: fix white screen on binary displays (#4991) --- esphome/components/display/display_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 8d37d6536a..86e8624d33 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -12,7 +12,7 @@ namespace display { static const char *const TAG = "display"; -const Color COLOR_OFF(0, 0, 0, 255); +const Color COLOR_OFF(0, 0, 0, 0); const Color COLOR_ON(255, 255, 255, 255); void DisplayBuffer::init_internal_(uint32_t buffer_length) { From df9fcf9850dc9aabe121cfe1e6cf7d18444d34b6 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 22 Jun 2023 06:09:00 +0200 Subject: [PATCH 0136/2607] Make ethernet_info work with esp-idf framework (#4976) --- .../components/ethernet_info/ethernet_info_text_sensor.cpp | 4 ++-- esphome/components/ethernet_info/ethernet_info_text_sensor.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp index e69872c290..f841875396 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp @@ -1,7 +1,7 @@ #include "ethernet_info_text_sensor.h" #include "esphome/core/log.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#ifdef USE_ESP32 namespace esphome { namespace ethernet_info { @@ -13,4 +13,4 @@ void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IP } // namespace ethernet_info } // namespace esphome -#endif // USE_ESP32_FRAMEWORK_ARDUINO +#endif // USE_ESP32 diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.h b/esphome/components/ethernet_info/ethernet_info_text_sensor.h index aad8f362b5..2d46fe18eb 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.h +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.h @@ -4,7 +4,7 @@ #include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/ethernet/ethernet_component.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#ifdef USE_ESP32 namespace esphome { namespace ethernet_info { @@ -30,4 +30,4 @@ class IPAddressEthernetInfo : public PollingComponent, public text_sensor::TextS } // namespace ethernet_info } // namespace esphome -#endif // USE_ESP32_FRAMEWORK_ARDUINO +#endif // USE_ESP32 From a90d266017fd10e1c927865fbed7b3c7f987d589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 22 Jun 2023 21:18:29 +0200 Subject: [PATCH 0137/2607] display: fix white screen on binary displays (#4991) --- esphome/components/display/display_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 672c6a22b0..791f7350e6 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -16,7 +16,7 @@ namespace display { static const char *const TAG = "display"; -const Color COLOR_OFF(0, 0, 0, 255); +const Color COLOR_OFF(0, 0, 0, 0); const Color COLOR_ON(255, 255, 255, 255); void Rect::expand(int16_t horizontal, int16_t vertical) { From dec6f044996657864491383e10b442944cbb2298 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 23 Jun 2023 07:34:55 +1200 Subject: [PATCH 0138/2607] Bump version to 2023.6.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f49cff3b61..e06862072a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.0" +__version__ = "2023.6.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From fc0e1a3cb9c401819284774ba27fccd0de061524 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 22 Jun 2023 18:03:31 -0700 Subject: [PATCH 0139/2607] remove unused static declarations (#4993) --- esphome/core/time.cpp | 20 ++++++++++---------- esphome/core/time.h | 4 ---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index c03506fd2a..bc5bfa173e 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -2,6 +2,16 @@ namespace esphome { +static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } + +static uint8_t days_in_month(uint8_t month, uint16_t year) { + static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + uint8_t days = DAYS_IN_MONTH[month]; + if (month == 2 && is_leap_year(year)) + return 29; + return days; +} + size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { struct tm c_tm = this->to_c_tm(); return ::strftime(buffer, buffer_len, format, &c_tm); @@ -158,14 +168,4 @@ template bool increment_time_value(T ¤t, uint16_t begin, uint1 return false; } -static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } - -static uint8_t days_in_month(uint8_t month, uint16_t year) { - static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - uint8_t days = DAYS_IN_MONTH[month]; - if (month == 2 && is_leap_year(year)) - return 29; - return days; -} - } // namespace esphome diff --git a/esphome/core/time.h b/esphome/core/time.h index e1bdc8c839..e16e449f0b 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -8,10 +8,6 @@ namespace esphome { template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end); -static bool is_leap_year(uint32_t year); - -static uint8_t days_in_month(uint8_t month, uint16_t year); - /// A more user-friendly version of struct tm from time.h struct ESPTime { /** seconds after the minute [0-60] From eb145757e5240e60044305d7b57ce3b73c9d7f87 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:42:37 +1200 Subject: [PATCH 0140/2607] Fix rp2040 pio tool download (#4994) --- esphome/components/rp2040/__init__.py | 24 ++++------ esphome/components/rp2040/build_pio.py.script | 47 +++++++++++++++++++ esphome/components/rp2040_pio/__init__.py | 40 ++++++++++++++++ .../components/rp2040_pio_led_strip/light.py | 7 +-- 4 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 esphome/components/rp2040/build_pio.py.script create mode 100644 esphome/components/rp2040_pio/__init__.py diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index ad66ce6d18..030d586626 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -16,8 +16,7 @@ from esphome.const import ( KEY_TARGET_PLATFORM, ) from esphome.core import CORE, coroutine_with_priority, EsphomeError -from esphome.helpers import mkdir_p, write_file -import esphome.platformio_api as api +from esphome.helpers import mkdir_p, write_file, copy_file_if_changed from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns @@ -193,25 +192,20 @@ def generate_pio_files() -> bool: pio_path = CORE.relative_build_path(f"src/pio/{key}.pio") mkdir_p(os.path.dirname(pio_path)) write_file(pio_path, data) - _LOGGER.info("Assembling PIO assembly code") - retval = api.run_platformio_cli( - "pkg", - "exec", - "--package", - "earlephilhower/tool-pioasm-rp2040-earlephilhower", - "--", - "pioasm", - pio_path, - pio_path + ".h", - ) includes.append(f"pio/{key}.pio.h") - if retval != 0: - raise EsphomeError("PIO assembly failed") write_file( CORE.relative_build_path("src/pio_includes.h"), "#pragma once\n" + "\n".join([f'#include "{include}"' for include in includes]), ) + + dir = os.path.dirname(__file__) + build_pio_file = os.path.join(dir, "build_pio.py.script") + copy_file_if_changed( + build_pio_file, + CORE.relative_build_path("build_pio.py"), + ) + return True diff --git a/esphome/components/rp2040/build_pio.py.script b/esphome/components/rp2040/build_pio.py.script new file mode 100644 index 0000000000..c3e0767ed6 --- /dev/null +++ b/esphome/components/rp2040/build_pio.py.script @@ -0,0 +1,47 @@ +""" +Custom pioasm compiler script for platformio. +(c) 2022 by P.Z. + +Sourced 2023/06/23 from https://gist.github.com/hexeguitar/f4533bc697c956ac1245b6843e2ef438 + +Modified by jesserockz 2023/06/23 +""" + +from os.path import join +import glob +import sys + +import subprocess + +# pylint: disable=E0602 +Import("env") # noqa + +from SCons.Script import ARGUMENTS + + +platform = env.PioPlatform() +PROJ_SRC = env["PROJECT_SRC_DIR"] +PIO_FILES = glob.glob(join(PROJ_SRC, "**", "*.pio"), recursive=True) + +verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0"))) + + +if PIO_FILES: + if verbose: + print("==============================================") + print("PIO ASSEMBLY COMPILER") + try: + PIOASM_DIR = platform.get_package_dir("tool-pioasm-rp2040-earlephilhower") + except: + print("tool-pioasm-rp2040-earlephilhower not supported on your system!") + sys.exit() + + PIOASM_EXE = join(PIOASM_DIR, "pioasm") + if verbose: + print("PIO files found:") + for filename in PIO_FILES: + if verbose: + print(f" {filename}") + subprocess.run([PIOASM_EXE, "-o", "c-sdk", filename, f"{filename}.h"]) + if verbose: + print("==============================================") diff --git a/esphome/components/rp2040_pio/__init__.py b/esphome/components/rp2040_pio/__init__.py new file mode 100644 index 0000000000..af884d5ac2 --- /dev/null +++ b/esphome/components/rp2040_pio/__init__.py @@ -0,0 +1,40 @@ +import platform + +import esphome.codegen as cg + + +DEPENDENCIES = ["rp2040"] + + +PIOASM_REPO_VERSION = "1.5.0-b" +PIOASM_REPO_BASE = f"https://github.com/earlephilhower/pico-quick-toolchain/releases/download/{PIOASM_REPO_VERSION}" +PIOASM_VERSION = "pioasm-2e6142b.230216" +PIOASM_DOWNLOADS = { + "linux": { + "aarch64": f"aarch64-linux-gnu.{PIOASM_VERSION}.tar.gz", + "armv7l": f"arm-linux-gnueabihf.{PIOASM_VERSION}.tar.gz", + "x86_64": f"x86_64-linux-gnu.{PIOASM_VERSION}.tar.gz", + }, + "windows": { + "amd64": f"x86_64-w64-mingw32.{PIOASM_VERSION}.zip", + }, + "darwin": { + "x86_64": f"x86_64-apple-darwin14.{PIOASM_VERSION}.tar.gz", + "arm64": f"x86_64-apple-darwin14.{PIOASM_VERSION}.tar.gz", + }, +} + + +async def to_code(config): + # cg.add_platformio_option( + # "platform_packages", + # [ + # "earlephilhower/tool-pioasm-rp2040-earlephilhower", + # ], + # ) + file = PIOASM_DOWNLOADS[platform.system().lower()][platform.machine().lower()] + cg.add_platformio_option( + "platform_packages", + [f"earlephilhower/tool-pioasm-rp2040-earlephilhower@{PIOASM_REPO_BASE}/{file}"], + ) + cg.add_platformio_option("extra_scripts", ["pre:build_pio.py"]) diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index a2ba72318f..6c51b57e97 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -127,6 +127,7 @@ def time_to_cycles(time_us): CONF_PIO = "pio" +AUTO_LOAD = ["rp2040_pio"] CODEOWNERS = ["@Papa-DMan"] DEPENDENCIES = ["rp2040"] @@ -265,9 +266,3 @@ async def to_code(config): time_to_cycles(config[CONF_BIT1_LOW]), ), ) - cg.add_platformio_option( - "platform_packages", - [ - "earlephilhower/tool-pioasm-rp2040-earlephilhower", - ], - ) From 595ac84779cc0401912289b8db054523f252125c Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 22 Jun 2023 18:03:31 -0700 Subject: [PATCH 0141/2607] remove unused static declarations (#4993) --- esphome/core/time.cpp | 20 ++++++++++---------- esphome/core/time.h | 4 ---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index c03506fd2a..bc5bfa173e 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -2,6 +2,16 @@ namespace esphome { +static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } + +static uint8_t days_in_month(uint8_t month, uint16_t year) { + static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + uint8_t days = DAYS_IN_MONTH[month]; + if (month == 2 && is_leap_year(year)) + return 29; + return days; +} + size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { struct tm c_tm = this->to_c_tm(); return ::strftime(buffer, buffer_len, format, &c_tm); @@ -158,14 +168,4 @@ template bool increment_time_value(T ¤t, uint16_t begin, uint1 return false; } -static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } - -static uint8_t days_in_month(uint8_t month, uint16_t year) { - static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - uint8_t days = DAYS_IN_MONTH[month]; - if (month == 2 && is_leap_year(year)) - return 29; - return days; -} - } // namespace esphome diff --git a/esphome/core/time.h b/esphome/core/time.h index e1bdc8c839..e16e449f0b 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -8,10 +8,6 @@ namespace esphome { template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end); -static bool is_leap_year(uint32_t year); - -static uint8_t days_in_month(uint8_t month, uint16_t year); - /// A more user-friendly version of struct tm from time.h struct ESPTime { /** seconds after the minute [0-60] From fbfb4e2a73320630a2518b6c1e8b2ed5e07e8d9e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:42:37 +1200 Subject: [PATCH 0142/2607] Fix rp2040 pio tool download (#4994) --- esphome/components/rp2040/__init__.py | 24 ++++------ esphome/components/rp2040/build_pio.py.script | 47 +++++++++++++++++++ esphome/components/rp2040_pio/__init__.py | 40 ++++++++++++++++ .../components/rp2040_pio_led_strip/light.py | 7 +-- 4 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 esphome/components/rp2040/build_pio.py.script create mode 100644 esphome/components/rp2040_pio/__init__.py diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index ad66ce6d18..030d586626 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -16,8 +16,7 @@ from esphome.const import ( KEY_TARGET_PLATFORM, ) from esphome.core import CORE, coroutine_with_priority, EsphomeError -from esphome.helpers import mkdir_p, write_file -import esphome.platformio_api as api +from esphome.helpers import mkdir_p, write_file, copy_file_if_changed from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns @@ -193,25 +192,20 @@ def generate_pio_files() -> bool: pio_path = CORE.relative_build_path(f"src/pio/{key}.pio") mkdir_p(os.path.dirname(pio_path)) write_file(pio_path, data) - _LOGGER.info("Assembling PIO assembly code") - retval = api.run_platformio_cli( - "pkg", - "exec", - "--package", - "earlephilhower/tool-pioasm-rp2040-earlephilhower", - "--", - "pioasm", - pio_path, - pio_path + ".h", - ) includes.append(f"pio/{key}.pio.h") - if retval != 0: - raise EsphomeError("PIO assembly failed") write_file( CORE.relative_build_path("src/pio_includes.h"), "#pragma once\n" + "\n".join([f'#include "{include}"' for include in includes]), ) + + dir = os.path.dirname(__file__) + build_pio_file = os.path.join(dir, "build_pio.py.script") + copy_file_if_changed( + build_pio_file, + CORE.relative_build_path("build_pio.py"), + ) + return True diff --git a/esphome/components/rp2040/build_pio.py.script b/esphome/components/rp2040/build_pio.py.script new file mode 100644 index 0000000000..c3e0767ed6 --- /dev/null +++ b/esphome/components/rp2040/build_pio.py.script @@ -0,0 +1,47 @@ +""" +Custom pioasm compiler script for platformio. +(c) 2022 by P.Z. + +Sourced 2023/06/23 from https://gist.github.com/hexeguitar/f4533bc697c956ac1245b6843e2ef438 + +Modified by jesserockz 2023/06/23 +""" + +from os.path import join +import glob +import sys + +import subprocess + +# pylint: disable=E0602 +Import("env") # noqa + +from SCons.Script import ARGUMENTS + + +platform = env.PioPlatform() +PROJ_SRC = env["PROJECT_SRC_DIR"] +PIO_FILES = glob.glob(join(PROJ_SRC, "**", "*.pio"), recursive=True) + +verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0"))) + + +if PIO_FILES: + if verbose: + print("==============================================") + print("PIO ASSEMBLY COMPILER") + try: + PIOASM_DIR = platform.get_package_dir("tool-pioasm-rp2040-earlephilhower") + except: + print("tool-pioasm-rp2040-earlephilhower not supported on your system!") + sys.exit() + + PIOASM_EXE = join(PIOASM_DIR, "pioasm") + if verbose: + print("PIO files found:") + for filename in PIO_FILES: + if verbose: + print(f" {filename}") + subprocess.run([PIOASM_EXE, "-o", "c-sdk", filename, f"{filename}.h"]) + if verbose: + print("==============================================") diff --git a/esphome/components/rp2040_pio/__init__.py b/esphome/components/rp2040_pio/__init__.py new file mode 100644 index 0000000000..af884d5ac2 --- /dev/null +++ b/esphome/components/rp2040_pio/__init__.py @@ -0,0 +1,40 @@ +import platform + +import esphome.codegen as cg + + +DEPENDENCIES = ["rp2040"] + + +PIOASM_REPO_VERSION = "1.5.0-b" +PIOASM_REPO_BASE = f"https://github.com/earlephilhower/pico-quick-toolchain/releases/download/{PIOASM_REPO_VERSION}" +PIOASM_VERSION = "pioasm-2e6142b.230216" +PIOASM_DOWNLOADS = { + "linux": { + "aarch64": f"aarch64-linux-gnu.{PIOASM_VERSION}.tar.gz", + "armv7l": f"arm-linux-gnueabihf.{PIOASM_VERSION}.tar.gz", + "x86_64": f"x86_64-linux-gnu.{PIOASM_VERSION}.tar.gz", + }, + "windows": { + "amd64": f"x86_64-w64-mingw32.{PIOASM_VERSION}.zip", + }, + "darwin": { + "x86_64": f"x86_64-apple-darwin14.{PIOASM_VERSION}.tar.gz", + "arm64": f"x86_64-apple-darwin14.{PIOASM_VERSION}.tar.gz", + }, +} + + +async def to_code(config): + # cg.add_platformio_option( + # "platform_packages", + # [ + # "earlephilhower/tool-pioasm-rp2040-earlephilhower", + # ], + # ) + file = PIOASM_DOWNLOADS[platform.system().lower()][platform.machine().lower()] + cg.add_platformio_option( + "platform_packages", + [f"earlephilhower/tool-pioasm-rp2040-earlephilhower@{PIOASM_REPO_BASE}/{file}"], + ) + cg.add_platformio_option("extra_scripts", ["pre:build_pio.py"]) diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index a2ba72318f..6c51b57e97 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -127,6 +127,7 @@ def time_to_cycles(time_us): CONF_PIO = "pio" +AUTO_LOAD = ["rp2040_pio"] CODEOWNERS = ["@Papa-DMan"] DEPENDENCIES = ["rp2040"] @@ -265,9 +266,3 @@ async def to_code(config): time_to_cycles(config[CONF_BIT1_LOW]), ), ) - cg.add_platformio_option( - "platform_packages", - [ - "earlephilhower/tool-pioasm-rp2040-earlephilhower", - ], - ) From 39948db59af9e2467ecab13822124586da5c7388 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 23 Jun 2023 17:17:43 +1200 Subject: [PATCH 0143/2607] Bump version to 2023.6.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e06862072a..48e62b9b86 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.1" +__version__ = "2023.6.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 8a1c49a4ae629a6411a8442c26528db66607e38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Sun, 25 Jun 2023 00:56:29 +0200 Subject: [PATCH 0144/2607] display: move `Image`, `Font` and `Animation` code into components (#4967) * display: move `Font` to `components/font` * display: move `Animation` to `components/animation` * display: move `Image` to `components/image` --- esphome/components/animation/__init__.py | 13 ++++++++----- .../{display => animation}/animation.cpp | 7 ++++--- .../components/{display => animation}/animation.h | 10 +++++----- esphome/components/font/__init__.py | 9 +++++---- esphome/components/{display => font}/font.cpp | 12 +++++++----- esphome/components/{display => font}/font.h | 14 +++++++------- esphome/components/graph/graph.cpp | 1 - esphome/components/graph/graph.h | 10 +++++----- esphome/components/image/__init__.py | 8 +++++--- esphome/components/{display => image}/image.cpp | 6 +++--- esphome/components/{display => image}/image.h | 12 ++++++------ 11 files changed, 55 insertions(+), 47 deletions(-) rename esphome/components/{display => animation}/animation.cpp (94%) rename esphome/components/{display => animation}/animation.h (89%) rename esphome/components/{display => font}/font.cpp (91%) rename esphome/components/{display => font}/font.h (79%) rename esphome/components/{display => image}/image.cpp (97%) rename esphome/components/{display => image}/image.h (79%) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 8a39ec5a87..82e724fa00 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -1,7 +1,7 @@ import logging from esphome import automation, core -from esphome.components import display, font +from esphome.components import font import esphome.components.image as espImage from esphome.components.image import CONF_USE_TRANSPARENCY import esphome.config_validation as cv @@ -18,6 +18,7 @@ from esphome.core import CORE, HexInt _LOGGER = logging.getLogger(__name__) +AUTO_LOAD = ["image"] CODEOWNERS = ["@syndlex"] DEPENDENCIES = ["display"] MULTI_CONF = True @@ -27,16 +28,18 @@ CONF_START_FRAME = "start_frame" CONF_END_FRAME = "end_frame" CONF_FRAME = "frame" -Animation_ = display.display_ns.class_("Animation", espImage.Image_) +animation_ns = cg.esphome_ns.namespace("animation") + +Animation_ = animation_ns.class_("Animation", espImage.Image_) # Actions -NextFrameAction = display.display_ns.class_( +NextFrameAction = animation_ns.class_( "AnimationNextFrameAction", automation.Action, cg.Parented.template(Animation_) ) -PrevFrameAction = display.display_ns.class_( +PrevFrameAction = animation_ns.class_( "AnimationPrevFrameAction", automation.Action, cg.Parented.template(Animation_) ) -SetFrameAction = display.display_ns.class_( +SetFrameAction = animation_ns.class_( "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_) ) diff --git a/esphome/components/display/animation.cpp b/esphome/components/animation/animation.cpp similarity index 94% rename from esphome/components/display/animation.cpp rename to esphome/components/animation/animation.cpp index d68084b68d..7e0efa97e0 100644 --- a/esphome/components/display/animation.cpp +++ b/esphome/components/animation/animation.cpp @@ -3,9 +3,10 @@ #include "esphome/core/hal.h" namespace esphome { -namespace display { +namespace animation { -Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type) +Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, + image::ImageType type) : Image(data_start, width, height, type), animation_data_start_(data_start), current_frame_(0), @@ -65,5 +66,5 @@ void Animation::update_data_start_() { this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; } -} // namespace display +} // namespace animation } // namespace esphome diff --git a/esphome/components/display/animation.h b/esphome/components/animation/animation.h similarity index 89% rename from esphome/components/display/animation.h rename to esphome/components/animation/animation.h index 3371cd9e71..272c5153d1 100644 --- a/esphome/components/display/animation.h +++ b/esphome/components/animation/animation.h @@ -1,14 +1,14 @@ #pragma once -#include "image.h" +#include "esphome/components/image/image.h" #include "esphome/core/automation.h" namespace esphome { -namespace display { +namespace animation { -class Animation : public Image { +class Animation : public image::Image { public: - Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type); + Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type); uint32_t get_animation_frame_count() const; int get_current_frame() const; @@ -63,5 +63,5 @@ template class AnimationSetFrameAction : public Action { Animation *parent_; }; -} // namespace display +} // namespace animation } // namespace esphome diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index aa165ebaa5..7a314bb032 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -7,7 +7,6 @@ import re import requests from esphome import core -from esphome.components import display import esphome.config_validation as cv import esphome.codegen as cg from esphome.helpers import copy_file_if_changed @@ -29,9 +28,11 @@ DOMAIN = "font" DEPENDENCIES = ["display"] MULTI_CONF = True -Font = display.display_ns.class_("Font") -Glyph = display.display_ns.class_("Glyph") -GlyphData = display.display_ns.struct("GlyphData") +font_ns = cg.esphome_ns.namespace("font") + +Font = font_ns.class_("Font") +Glyph = font_ns.class_("Glyph") +GlyphData = font_ns.struct("GlyphData") def validate_glyphs(value): diff --git a/esphome/components/display/font.cpp b/esphome/components/font/font.cpp similarity index 91% rename from esphome/components/display/font.cpp rename to esphome/components/font/font.cpp index 0a5881b48b..fcb2bb1750 100644 --- a/esphome/components/display/font.cpp +++ b/esphome/components/font/font.cpp @@ -2,13 +2,15 @@ #include "esphome/core/hal.h" #include "esphome/core/log.h" +#include "esphome/core/color.h" +#include "esphome/components/display/display_buffer.h" namespace esphome { -namespace display { +namespace font { -static const char *const TAG = "display"; +static const char *const TAG = "font"; -void Glyph::draw(int x_at, int y_start, DisplayBuffer *display, Color color) const { +void Glyph::draw(int x_at, int y_start, display::DisplayBuffer *display, Color color) const { int scan_x1, scan_y1, scan_width, scan_height; this->scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height); @@ -116,7 +118,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in *x_offset = min_x; *width = x - min_x; } -void Font::print(int x_start, int y_start, DisplayBuffer *display, Color color, const char *text) { +void Font::print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) { int i = 0; int x_at = x_start; while (text[i] != '\0') { @@ -143,5 +145,5 @@ void Font::print(int x_start, int y_start, DisplayBuffer *display, Color color, } } -} // namespace display +} // namespace font } // namespace esphome diff --git a/esphome/components/display/font.h b/esphome/components/font/font.h similarity index 79% rename from esphome/components/display/font.h rename to esphome/components/font/font.h index 5ba6685a1c..d88ebd9be6 100644 --- a/esphome/components/display/font.h +++ b/esphome/components/font/font.h @@ -1,12 +1,12 @@ #pragma once #include "esphome/core/datatypes.h" -#include "display_buffer.h" +#include "esphome/core/color.h" +#include "esphome/components/display/display_buffer.h" namespace esphome { -namespace display { +namespace font { -class DisplayBuffer; class Font; struct GlyphData { @@ -22,7 +22,7 @@ class Glyph { public: Glyph(const GlyphData *data) : glyph_data_(data) {} - void draw(int x, int y, DisplayBuffer *display, Color color) const; + void draw(int x, int y, display::DisplayBuffer *display, Color color) const; const char *get_char() const; @@ -38,7 +38,7 @@ class Glyph { const GlyphData *glyph_data_; }; -class Font : public BaseFont { +class Font : public display::BaseFont { public: /** Construct the font with the given glyphs. * @@ -50,7 +50,7 @@ class Font : public BaseFont { int match_next_glyph(const char *str, int *match_length); - void print(int x_start, int y_start, DisplayBuffer *display, Color color, const char *text) override; + void print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) override; void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override; inline int get_baseline() { return this->baseline_; } inline int get_height() { return this->height_; } @@ -63,5 +63,5 @@ class Font : public BaseFont { int height_; }; -} // namespace display +} // namespace font } // namespace esphome diff --git a/esphome/components/graph/graph.cpp b/esphome/components/graph/graph.cpp index 88850f4b92..c229f17dd8 100644 --- a/esphome/components/graph/graph.cpp +++ b/esphome/components/graph/graph.cpp @@ -1,6 +1,5 @@ #include "graph.h" #include "esphome/components/display/display_buffer.h" -#include "esphome/components/display/font.h" #include "esphome/core/color.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" diff --git a/esphome/components/graph/graph.h b/esphome/components/graph/graph.h index 69c1167f54..87c21fd7d1 100644 --- a/esphome/components/graph/graph.h +++ b/esphome/components/graph/graph.h @@ -11,7 +11,7 @@ namespace esphome { // forward declare DisplayBuffer namespace display { class DisplayBuffer; -class Font; +class BaseFont; } // namespace display namespace graph { @@ -45,8 +45,8 @@ enum ValuePositionType { class GraphLegend { public: void init(Graph *g); - void set_name_font(display::Font *font) { this->font_label_ = font; } - void set_value_font(display::Font *font) { this->font_value_ = font; } + void set_name_font(display::BaseFont *font) { this->font_label_ = font; } + void set_value_font(display::BaseFont *font) { this->font_value_ = font; } void set_width(uint32_t width) { this->width_ = width; } void set_height(uint32_t height) { this->height_ = height; } void set_border(bool val) { this->border_ = val; } @@ -63,8 +63,8 @@ class GraphLegend { ValuePositionType values_{VALUE_POSITION_TYPE_AUTO}; bool units_{true}; DirectionType direction_{DIRECTION_TYPE_AUTO}; - display::Font *font_label_{nullptr}; - display::Font *font_value_{nullptr}; + display::BaseFont *font_label_{nullptr}; + display::BaseFont *font_value_{nullptr}; // Calculated values Graph *parent_{nullptr}; // (x0) (xs,ys) (xs,ys) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index e7cf492c7b..392efb18a2 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -6,7 +6,7 @@ import re import requests from esphome import core -from esphome.components import display, font +from esphome.components import font import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( @@ -28,7 +28,9 @@ DOMAIN = "image" DEPENDENCIES = ["display"] MULTI_CONF = True -ImageType = display.display_ns.enum("ImageType") +image_ns = cg.esphome_ns.namespace("image") + +ImageType = image_ns.enum("ImageType") IMAGE_TYPE = { "BINARY": ImageType.IMAGE_TYPE_BINARY, "TRANSPARENT_BINARY": ImageType.IMAGE_TYPE_BINARY, @@ -46,7 +48,7 @@ MDI_DOWNLOAD_TIMEOUT = 30 # seconds SOURCE_LOCAL = "local" SOURCE_MDI = "mdi" -Image_ = display.display_ns.class_("Image") +Image_ = image_ns.class_("Image") def _compute_local_icon_path(value) -> Path: diff --git a/esphome/components/display/image.cpp b/esphome/components/image/image.cpp similarity index 97% rename from esphome/components/display/image.cpp rename to esphome/components/image/image.cpp index 33c26ef127..66a085ebe2 100644 --- a/esphome/components/display/image.cpp +++ b/esphome/components/image/image.cpp @@ -3,9 +3,9 @@ #include "esphome/core/hal.h" namespace esphome { -namespace display { +namespace image { -void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) { +void Image::draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) { switch (type_) { case IMAGE_TYPE_BINARY: { for (int img_x = 0; img_x < width_; img_x++) { @@ -130,5 +130,5 @@ ImageType Image::get_type() const { return this->type_; } Image::Image(const uint8_t *data_start, int width, int height, ImageType type) : width_(width), height_(height), type_(type), data_start_(data_start) {} -} // namespace display +} // namespace image } // namespace esphome diff --git a/esphome/components/display/image.h b/esphome/components/image/image.h similarity index 79% rename from esphome/components/display/image.h rename to esphome/components/image/image.h index b16828a5be..b0853d360d 100644 --- a/esphome/components/display/image.h +++ b/esphome/components/image/image.h @@ -1,9 +1,9 @@ #pragma once #include "esphome/core/color.h" -#include "display_buffer.h" +#include "esphome/components/display/display_buffer.h" namespace esphome { -namespace display { +namespace image { enum ImageType { IMAGE_TYPE_BINARY = 0, @@ -31,15 +31,15 @@ inline int image_type_to_bpp(ImageType type) { inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } -class Image : public BaseImage { +class Image : public display::BaseImage { public: Image(const uint8_t *data_start, int width, int height, ImageType type); - Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const; + Color get_pixel(int x, int y, Color color_on = display::COLOR_ON, Color color_off = display::COLOR_OFF) const; int get_width() const override; int get_height() const override; ImageType get_type() const; - void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override; + void draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) override; void set_transparency(bool transparent) { transparent_ = transparent; } bool has_transparency() const { return transparent_; } @@ -58,5 +58,5 @@ class Image : public BaseImage { bool transparent_; }; -} // namespace display +} // namespace image } // namespace esphome From 2a2d20a7fc10ea7d27382a7372225b72e0139b34 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Sun, 25 Jun 2023 18:38:36 -0300 Subject: [PATCH 0145/2607] support empty schemas and one platform components (#4999) --- script/build_language_schema.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/script/build_language_schema.py b/script/build_language_schema.py index dd8eccde93..c6fcf5eb64 100644 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -461,8 +461,10 @@ def merge(source, destination): def is_platform_schema(schema_name): # added mostly because of schema_name == "microphone.MICROPHONE_SCHEMA" + # and "alarm_control_panel" # which is shrunk because there is only one component of the schema (i2s_audio) - return schema_name == "microphone.MICROPHONE_SCHEMA" + component = schema_name.split(".")[0] + return component in components and components[component].is_platform_component def shrink(): @@ -530,6 +532,10 @@ def shrink(): elif not key_s: for target in paths: target_s = get_arr_path_schema(target) + if S_SCHEMA not in target_s: + # an empty schema like speaker.SPEAKER_SCHEMA + target_s[S_EXTENDS].remove(x) + continue assert target_s[S_SCHEMA][S_EXTENDS] == [x] target_s.pop(S_SCHEMA) target_s.pop(S_TYPE) # undefined From ef84937fd62f1f81b535cd8af7a8690f87d312a9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:27:03 +1200 Subject: [PATCH 0146/2607] Update webserver to 56d73b5 (#5007) --- esphome/components/web_server/server_index.h | 1179 +++++++++--------- 1 file changed, 590 insertions(+), 589 deletions(-) diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 4e6e136f8c..2dbb839c5e 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,596 +6,597 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, - 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x28, 0x58, 0x5d, 0x05, 0x5c, 0x81, 0x10, 0x49, 0x95, 0xaa, 0xca, 0xa0, 0x40, 0x5e, - 0xd5, 0x62, 0x57, 0xd9, 0xb5, 0xb9, 0xa4, 0xb2, 0xaf, 0x2d, 0xeb, 0x4a, 0x10, 0x99, 0x14, 0xe1, 0x02, 0x01, 0x1a, - 0x48, 0x6a, 0x31, 0x85, 0x3e, 0xfd, 0xd4, 0x4f, 0x7d, 0xce, 0x6c, 0xfd, 0xd0, 0x0f, 0xd3, 0xa7, 0xfb, 0x61, 0x3e, - 0x62, 0x9e, 0xfb, 0x53, 0xee, 0x0f, 0x4c, 0x7f, 0xc2, 0x44, 0x44, 0x2e, 0x48, 0x80, 0xa4, 0x24, 0xbb, 0x7d, 0xe7, - 0x78, 0x11, 0x90, 0x6b, 0x44, 0x64, 0x64, 0x6c, 0x19, 0x09, 0xee, 0xde, 0x1b, 0x65, 0x43, 0x7e, 0x35, 0x63, 0xd6, - 0x84, 0x4f, 0x93, 0xfe, 0xae, 0xfc, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, 0x78, - 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, 0x53, - 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, 0xc7, - 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, 0xfe, - 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, 0xc4, - 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, 0x8b, - 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, 0x4f, - 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, 0x69, - 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf3, 0xb8, 0x17, 0xbb, 0x61, 0x9f, 0x5b, 0x71, 0x6a, 0xb1, 0xc1, 0x0b, 0x46, 0x25, - 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, 0x7c, - 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xb0, 0x43, 0x7e, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, 0x8c, - 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbf, 0xbe, 0x76, 0x78, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, 0x51, - 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xfc, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, 0x99, - 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xee, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, 0xe9, - 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, 0x28, - 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, 0x0c, - 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, 0xc0, - 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, 0x90, - 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, 0xbe, - 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, 0x58, - 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, 0xc6, - 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdf, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, 0xb3, - 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, 0x05, - 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, 0x41, - 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xac, 0x04, - 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0x60, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, 0x9c, - 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x06, 0x9a, 0x38, 0xd0, 0xb6, 0x68, 0xb4, 0xf5, 0x04, 0xe2, 0x35, 0x12, 0xb9, 0x1e, - 0xf3, 0x25, 0xf9, 0xf6, 0xaf, 0xd2, 0x61, 0x7d, 0x6c, 0xa8, 0x2c, 0x79, 0xb6, 0xcf, 0xf3, 0x38, 0x3d, 0x03, 0x20, - 0xe4, 0x4c, 0x66, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x2c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, 0x7a, - 0xd8, 0x61, 0x88, 0xa4, 0x07, 0x06, 0x63, 0x03, 0x16, 0xb0, 0x4d, 0xdb, 0xf6, 0xbe, 0x73, 0xbd, 0x2b, 0xe4, 0x20, - 0xdf, 0xf7, 0x89, 0x7d, 0x45, 0xe7, 0x38, 0xec, 0x20, 0xd0, 0x7e, 0xc2, 0xd2, 0x33, 0x3e, 0x19, 0xb0, 0xc3, 0xf6, - 0x51, 0xc0, 0x01, 0xaa, 0xd1, 0x7c, 0xc8, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, - 0xf7, 0x08, 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, 0x70, - 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, 0x37, - 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0xe7, 0xc8, 0x43, - 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0x98, 0xbf, 0xcc, 0xc7, - 0x21, 0xf7, 0xa7, 0xd1, 0x0c, 0xb1, 0x61, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, - 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, 0x39, - 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, - 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, 0x73, - 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, 0xd5, - 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, 0xc0, - 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x87, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, 0x19, - 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xf2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, 0xd0, - 0x9f, 0x81, 0x0c, 0xec, 0xa1, 0xe0, 0xfa, 0x4a, 0x4a, 0x9d, 0x88, 0x29, 0x0c, 0x81, 0x00, 0x43, 0x94, 0x20, 0x92, - 0x06, 0xef, 0xb3, 0xe4, 0x6a, 0x1c, 0x27, 0xc9, 0xfe, 0x7c, 0x36, 0xcb, 0x72, 0xee, 0x7d, 0x1d, 0x2e, 0x78, 0x56, - 0xe1, 0x4a, 0x9b, 0xbc, 0xb8, 0x88, 0x39, 0x12, 0xd4, 0x5d, 0x0c, 0x23, 0x58, 0xea, 0xa7, 0x59, 0x96, 0xb0, 0x28, - 0x05, 0x34, 0xd8, 0xc0, 0xb6, 0x83, 0x74, 0x9e, 0x24, 0xbd, 0x53, 0x18, 0xf6, 0x53, 0x8f, 0xaa, 0x85, 0xc4, 0x0f, - 0xe8, 0x79, 0x2f, 0xcf, 0xa3, 0x2b, 0x68, 0x88, 0x6d, 0x80, 0x17, 0x61, 0xb5, 0xbe, 0xda, 0x7f, 0xf7, 0xd6, 0x17, - 0x8c, 0x1f, 0x8f, 0xaf, 0x00, 0xd0, 0xb2, 0x92, 0x9a, 0xe3, 0x3c, 0x9b, 0x36, 0xa6, 0x46, 0x3a, 0xc4, 0x21, 0xeb, - 0xad, 0x01, 0x21, 0xa6, 0x91, 0x61, 0x95, 0x98, 0x09, 0xc1, 0x5b, 0xe2, 0x67, 0x59, 0x89, 0x7b, 0x60, 0x80, 0x0f, - 0x81, 0x28, 0x86, 0x29, 0x6f, 0x86, 0x96, 0xe7, 0x57, 0x8b, 0x38, 0x24, 0x38, 0x67, 0xa8, 0x7f, 0x11, 0xc6, 0x61, - 0x04, 0xb3, 0x2f, 0xc4, 0x80, 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xa2, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x0e, - 0xdb, 0xe8, 0xfa, 0x9a, 0xc1, 0x8b, 0xeb, 0x7d, 0x13, 0x2e, 0x22, 0x85, 0x0f, 0x6a, 0x28, 0xdc, 0x5f, 0x81, 0x90, - 0x13, 0xa8, 0xc9, 0xce, 0x41, 0x0f, 0x02, 0x9c, 0x5f, 0x83, 0xfa, 0x1b, 0x27, 0x08, 0xc5, 0xbd, 0x8e, 0x07, 0x1a, - 0xf4, 0xd9, 0x24, 0x4a, 0xcf, 0xd8, 0x28, 0x98, 0xb0, 0x52, 0x4a, 0xde, 0x3d, 0x0b, 0xd6, 0x18, 0xd8, 0xa9, 0xb0, - 0x5e, 0x1e, 0xbc, 0x79, 0x2d, 0x57, 0xae, 0x26, 0x8c, 0x61, 0x91, 0xe6, 0xa0, 0x56, 0x41, 0x6c, 0x4b, 0x71, 0xfc, - 0x82, 0x2b, 0xe9, 0x2d, 0x4a, 0xe2, 0xe2, 0xe3, 0x0c, 0x4c, 0x0c, 0xf6, 0x1e, 0x86, 0x81, 0xe9, 0x43, 0x98, 0x8a, - 0xca, 0x61, 0x3e, 0x51, 0x31, 0xd2, 0x45, 0xd0, 0x59, 0x60, 0x2a, 0x5e, 0x33, 0xc7, 0x2d, 0x81, 0x55, 0x79, 0x3c, - 0xb4, 0xa2, 0xd1, 0xe8, 0x55, 0x1a, 0xf3, 0x38, 0x4a, 0xe2, 0x5f, 0x88, 0x92, 0x0b, 0xe4, 0x31, 0xde, 0x93, 0x8b, - 0x00, 0xb8, 0x53, 0x8f, 0xc4, 0x55, 0x42, 0xf6, 0x1e, 0x11, 0x43, 0x48, 0xcb, 0x24, 0x3c, 0x3c, 0x92, 0xe0, 0x25, - 0xfe, 0x6c, 0x5e, 0x4c, 0x90, 0xb0, 0x72, 0x60, 0x14, 0xe4, 0xd9, 0x69, 0xc1, 0xf2, 0x73, 0x36, 0xd2, 0x1c, 0x50, - 0x00, 0x56, 0xd4, 0x1c, 0x8c, 0x17, 0x9a, 0xd1, 0x51, 0x3a, 0x94, 0xc1, 0x50, 0x3d, 0x53, 0xcc, 0x32, 0xc9, 0xcc, - 0xda, 0xc2, 0xd1, 0x52, 0xc0, 0x11, 0x46, 0x85, 0x94, 0x04, 0x79, 0xa8, 0x30, 0x9c, 0x80, 0x14, 0x02, 0xad, 0x60, - 0x6e, 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, - 0xca, 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x8d, 0xd0, 0x85, 0x3e, 0xb6, 0x20, 0x36, 0xf0, - 0xf5, 0xca, 0x03, 0x61, 0x25, 0xde, 0x15, 0x22, 0xde, 0x1a, 0xb0, 0x71, 0x62, 0xe4, 0x27, 0xef, 0x1e, 0xf7, 0xd3, - 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, 0x67, - 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, 0xcb, - 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, 0x5d, - 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, 0x85, - 0x4d, 0x41, 0x80, 0x1e, 0xb2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, 0xac, - 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, 0x2b, - 0x90, 0x93, 0x6f, 0x66, 0x27, 0x84, 0x95, 0xb9, 0xd7, 0xd7, 0xdf, 0xa8, 0x41, 0xaa, 0xa5, 0xd4, 0x36, 0x50, 0x63, - 0x4d, 0x6c, 0xd5, 0x64, 0x64, 0xbb, 0x52, 0xa1, 0xde, 0xeb, 0xf4, 0x6a, 0x7c, 0x00, 0x7b, 0xae, 0xad, 0x59, 0xba, - 0x32, 0xb6, 0xdf, 0x2b, 0x9a, 0xbe, 0x13, 0x23, 0x93, 0x35, 0xca, 0x6e, 0xe7, 0x1e, 0xb5, 0xe3, 0xa1, 0xed, 0x52, - 0x5d, 0x25, 0x18, 0xe6, 0x75, 0xc1, 0xd0, 0x84, 0x7a, 0xa6, 0xbb, 0xd8, 0x9a, 0xa9, 0x58, 0xa8, 0xd6, 0x5a, 0x39, - 0x10, 0x3c, 0x3c, 0x04, 0xe3, 0x64, 0xa5, 0x7f, 0xf0, 0x36, 0x9a, 0x32, 0xa4, 0xa8, 0xb7, 0xae, 0x81, 0x74, 0x20, - 0xa0, 0xc9, 0x51, 0x53, 0xbd, 0x71, 0x57, 0x58, 0x4d, 0xf5, 0xfd, 0x15, 0x83, 0x15, 0x01, 0xf6, 0x75, 0xb9, 0x62, - 0x89, 0x48, 0x6f, 0x0a, 0x2e, 0xd1, 0xf4, 0x11, 0x65, 0x62, 0x4d, 0x48, 0xc1, 0x03, 0xf2, 0xb0, 0xfc, 0x8d, 0x85, - 0x93, 0xad, 0x98, 0xc2, 0x91, 0xa3, 0x4c, 0x01, 0x3a, 0x93, 0x12, 0x00, 0x71, 0x49, 0x7f, 0x6b, 0x1b, 0x0b, 0xc9, - 0xb6, 0x8f, 0x7c, 0xe0, 0x8f, 0x93, 0x88, 0x3b, 0x9d, 0xad, 0xb6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, - 0xf7, 0x15, 0x2a, 0x8c, 0xbc, 0x05, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe2, 0x31, 0x77, 0x12, 0x54, 0x22, 0x6e, 0xc9, - 0x12, 0x50, 0x32, 0x7a, 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, - 0x0b, 0x2a, 0x08, 0x0c, 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x25, 0x8b, 0x32, 0x1e, - 0xc4, 0xcb, 0x85, 0xa0, 0x86, 0x7d, 0x9e, 0xbd, 0xce, 0x2e, 0x58, 0xfe, 0x2c, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, - 0x49, 0x4f, 0x02, 0x9d, 0xf5, 0x14, 0xaf, 0x9c, 0x13, 0xd2, 0xb0, 0x10, 0xd3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, - 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, 0xe2, - 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, 0xe9, - 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, - 0x8b, 0xbc, 0xb8, 0xe7, 0x34, 0xd4, 0x11, 0x40, 0x31, 0xad, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, - 0x8d, 0xbc, 0xaa, 0x89, 0x80, 0x38, 0x1d, 0xb1, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, - 0x81, 0x84, 0x57, 0x08, 0x80, 0x79, 0xe2, 0x4f, 0xb2, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xfa, 0x3a, 0x16, 0xfe, - 0x22, 0x32, 0x40, 0xce, 0xa6, 0xd9, 0x39, 0x5b, 0x01, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, - 0x54, 0xcb, 0x2c, 0x89, 0x87, 0x4c, 0x6b, 0xa9, 0xa9, 0x0f, 0x06, 0x1d, 0xbb, 0x04, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, - 0xdf, 0xf6, 0x3a, 0x6e, 0x29, 0x08, 0xbe, 0x58, 0xa2, 0xe8, 0x0d, 0xfa, 0x51, 0x9a, 0xe0, 0xab, 0x64, 0x01, 0x77, - 0x0d, 0xa5, 0xc8, 0x85, 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xdb, 0x76, 0xe3, 0x46, 0x92, 0xe0, 0xf3, + 0x9e, 0xb3, 0x7f, 0xb0, 0x2f, 0x28, 0x58, 0x53, 0x05, 0xb4, 0x40, 0x88, 0xa4, 0x4a, 0x55, 0x65, 0x50, 0x20, 0x5b, + 0x75, 0xb1, 0xab, 0xec, 0xba, 0xb9, 0xa4, 0xb2, 0xdb, 0x96, 0xd5, 0x12, 0x44, 0x26, 0x45, 0xb8, 0x40, 0x80, 0x06, + 0x92, 0xba, 0x98, 0xc2, 0x9c, 0x79, 0x9a, 0xa7, 0x39, 0x67, 0x6f, 0xf3, 0x30, 0x0f, 0x3b, 0x67, 0xe6, 0x61, 0x3f, + 0x62, 0x9f, 0xe7, 0x53, 0xfa, 0x07, 0x76, 0x3e, 0x61, 0x23, 0x22, 0x2f, 0x48, 0x80, 0xa4, 0x24, 0x7b, 0xdc, 0x7b, + 0xdc, 0xd5, 0x02, 0xf2, 0x1a, 0x11, 0x19, 0x19, 0xb7, 0x8c, 0x04, 0x77, 0xef, 0x8d, 0xb2, 0x21, 0xbf, 0x9a, 0x31, + 0x6b, 0xc2, 0xa7, 0x49, 0x7f, 0x57, 0xfe, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, + 0x78, 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, + 0x53, 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, + 0xc7, 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, + 0xfe, 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, + 0xc4, 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, + 0x8b, 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, + 0x4f, 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, + 0x69, 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf7, 0x98, 0x17, 0xbb, 0x61, 0x9f, 0x59, 0x71, 0x6a, 0xf1, 0xc1, 0x0b, 0x46, + 0x25, 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, + 0x7c, 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xf0, 0x43, 0x76, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, + 0x8c, 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbb, 0xbe, 0x76, 0x58, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, + 0x51, 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xec, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, + 0x99, 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xe6, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, + 0xe9, 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, + 0x28, 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, + 0x0c, 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, + 0xc0, 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, + 0x90, 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, + 0xbe, 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, + 0x58, 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, + 0xc6, 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdd, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, + 0xb3, 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, + 0x05, 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, + 0x41, 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xbc, + 0x04, 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0xe0, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, + 0x9c, 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0xa2, 0xd1, 0xd6, 0xe3, 0x84, 0x78, 0x8d, 0x44, 0xae, + 0xc7, 0x7d, 0x49, 0xbe, 0xfd, 0xab, 0x74, 0x58, 0x1f, 0x1b, 0x2a, 0x4b, 0x9e, 0xed, 0xf3, 0x3c, 0x4e, 0xcf, 0x00, + 0x08, 0xc5, 0x06, 0x46, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x3c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, + 0x7a, 0xd8, 0x00, 0x08, 0x90, 0x1e, 0x18, 0x8c, 0x0f, 0x78, 0xc0, 0x37, 0x6d, 0xdb, 0xfb, 0xce, 0xf5, 0xae, 0x90, + 0x83, 0x7c, 0xdf, 0x27, 0xf6, 0x15, 0x9d, 0xe3, 0xb0, 0x83, 0x40, 0xfb, 0x09, 0x4b, 0xcf, 0xf8, 0x64, 0xc0, 0x0f, + 0xdb, 0x47, 0x01, 0x03, 0xa8, 0x46, 0xf3, 0x21, 0x73, 0x90, 0x1f, 0xbd, 0x1c, 0xb7, 0xcf, 0xa6, 0x03, 0x53, 0xe0, + 0xc2, 0xdc, 0x23, 0x1c, 0x6b, 0x4b, 0xe3, 0x2a, 0xd8, 0x14, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, + 0x70, 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, + 0x37, 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0xe4, 0x87, 0xf9, 0x66, 0xe7, 0xc8, + 0x43, 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0xb8, 0xbf, 0xcc, + 0xc7, 0x21, 0xf3, 0xa7, 0xd1, 0x0c, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, + 0x2b, 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, + 0x39, 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, + 0x9b, 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, + 0x73, 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, + 0xd5, 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, + 0xc0, 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x85, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, + 0x19, 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xb2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, + 0xd0, 0x1f, 0x08, 0xc1, 0x7b, 0x28, 0xb8, 0xbe, 0x92, 0x52, 0x27, 0x62, 0x0a, 0x43, 0x20, 0xc0, 0x10, 0x25, 0x88, + 0xa4, 0xc1, 0xfb, 0x2c, 0xb9, 0x1a, 0xc7, 0x49, 0xb2, 0x3f, 0x9f, 0xcd, 0xb2, 0x9c, 0x7b, 0x5f, 0x87, 0x0b, 0x9e, + 0x55, 0xb8, 0xd2, 0x26, 0x2f, 0x2e, 0x62, 0x8e, 0x04, 0x75, 0x17, 0xc3, 0x08, 0x96, 0xfa, 0x69, 0x96, 0x25, 0x2c, + 0x4a, 0x01, 0x0d, 0x3e, 0xb0, 0xed, 0x20, 0x9d, 0x27, 0x49, 0xef, 0x14, 0x86, 0xfd, 0xd4, 0xa3, 0x6a, 0x21, 0xf1, + 0x03, 0x7a, 0xde, 0xcb, 0xf3, 0xe8, 0x0a, 0x1a, 0x62, 0x1b, 0x60, 0x2f, 0x58, 0xad, 0xaf, 0xf6, 0xdf, 0xbd, 0xf5, + 0x05, 0xe3, 0xc7, 0xe3, 0x2b, 0x00, 0xb4, 0xac, 0xa4, 0xe6, 0x38, 0xcf, 0xa6, 0x8d, 0xa9, 0x91, 0x0e, 0x71, 0xc8, + 0x7b, 0x6b, 0x40, 0x88, 0x69, 0x64, 0x58, 0x25, 0x6e, 0x42, 0xf0, 0x96, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, + 0x43, 0x20, 0x8a, 0x61, 0xca, 0x5b, 0xa0, 0xcd, 0xaf, 0x16, 0x71, 0x48, 0x70, 0xce, 0x50, 0xff, 0x22, 0x8c, 0xc3, + 0x08, 0x66, 0x5f, 0x88, 0x01, 0x4b, 0x05, 0x71, 0x5c, 0x96, 0xde, 0x44, 0x33, 0x31, 0x4a, 0x3c, 0x14, 0x28, 0x2c, + 0x0c, 0x41, 0xc1, 0x70, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x45, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, + 0x02, 0x35, 0xd9, 0x39, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x50, 0x7f, 0xe3, 0x04, 0xa1, 0xb8, 0xd7, 0xf1, 0x40, 0x83, + 0x3e, 0x9b, 0x44, 0xe9, 0x19, 0x1b, 0x05, 0x13, 0x56, 0x4a, 0xc9, 0xbb, 0x67, 0xc1, 0x1a, 0x03, 0x3b, 0x15, 0xd6, + 0xcb, 0x83, 0x37, 0xaf, 0xe5, 0xca, 0xd5, 0x84, 0x31, 0x2c, 0xd2, 0x1c, 0xd4, 0x2a, 0x88, 0x6d, 0x29, 0x8e, 0x5f, + 0x70, 0x25, 0xbd, 0x45, 0x49, 0x5c, 0x7c, 0x9c, 0x81, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, + 0x39, 0xcc, 0x27, 0x2a, 0x46, 0xba, 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x6b, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x87, + 0x56, 0x34, 0x1a, 0xbd, 0x4a, 0x63, 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x81, 0x3c, 0xc6, 0x7a, 0x72, 0x11, + 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, 0xc8, 0xde, 0x23, 0x62, 0x08, 0x69, 0x99, 0x84, 0x87, 0x47, 0x12, 0xbc, 0xc4, + 0x9f, 0xcd, 0x8b, 0x09, 0x12, 0x56, 0x0e, 0x8c, 0x82, 0x3c, 0x3b, 0x2d, 0x58, 0x7e, 0xce, 0x46, 0x9a, 0x03, 0x0a, + 0xc0, 0x8a, 0x9a, 0x83, 0xf1, 0x42, 0x33, 0x3a, 0x4a, 0x87, 0x72, 0x18, 0xaa, 0x67, 0x8a, 0x59, 0x26, 0x99, 0x59, + 0x5b, 0x38, 0x5a, 0x0a, 0x38, 0xc2, 0xa8, 0x90, 0x92, 0x20, 0x0f, 0x15, 0x86, 0x13, 0x90, 0x42, 0xcc, 0xad, 0x6d, + 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, 0xca, + 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x0d, 0xe9, 0x42, 0x50, 0x26, 0xd0, 0x82, 0x21, 0x1b, + 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0xef, 0x1e, 0xf3, + 0xd3, 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, + 0x67, 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, + 0xcb, 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, + 0x5d, 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, + 0x85, 0x4d, 0x41, 0x80, 0x1e, 0xf2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, + 0xac, 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, + 0x2b, 0x90, 0x93, 0x6f, 0x66, 0x27, 0xb2, 0x27, 0xdc, 0xeb, 0xeb, 0x6f, 0xd4, 0x20, 0xd5, 0x52, 0x6a, 0x1b, 0xa8, + 0xb1, 0x26, 0xb6, 0x6a, 0x32, 0xb2, 0x5d, 0xa9, 0x50, 0xef, 0x75, 0x7a, 0x35, 0x3e, 0x80, 0x3d, 0xd7, 0xd6, 0x2c, + 0x5d, 0x19, 0xdb, 0xef, 0x15, 0x4d, 0xdf, 0x89, 0x91, 0xc9, 0x1a, 0xe5, 0xb7, 0x73, 0x8f, 0xda, 0xf1, 0xd0, 0x76, + 0xa9, 0xae, 0x12, 0x0c, 0xf3, 0xba, 0x60, 0x68, 0x42, 0x3d, 0xd3, 0x5d, 0x6c, 0xcd, 0x54, 0x3c, 0x54, 0x6b, 0xad, + 0x1c, 0x08, 0x16, 0x1e, 0x82, 0x71, 0xb2, 0xd2, 0x3f, 0x78, 0x1b, 0x4d, 0x19, 0x52, 0xd4, 0x5b, 0xd7, 0x40, 0x3a, + 0x10, 0xd0, 0xe4, 0xa8, 0xa9, 0xde, 0x98, 0x2b, 0xac, 0xa6, 0xfa, 0xfe, 0x8a, 0xc1, 0x8a, 0x00, 0xfb, 0xba, 0x5c, + 0xb1, 0x44, 0xa4, 0x37, 0x05, 0x97, 0x68, 0xfa, 0x88, 0x32, 0xb1, 0x26, 0xa4, 0xe0, 0x01, 0x79, 0x58, 0xfe, 0xc6, + 0xc2, 0xa9, 0x56, 0x0a, 0x47, 0x86, 0x32, 0x05, 0xe8, 0x4c, 0x4a, 0x00, 0xc4, 0x25, 0xfd, 0xad, 0x6d, 0x2c, 0x24, + 0xdb, 0x3e, 0xf2, 0x81, 0x3f, 0x4e, 0x22, 0xee, 0x74, 0xb6, 0xda, 0x2e, 0xf0, 0x21, 0x08, 0x71, 0xd0, 0x11, 0x60, + 0xde, 0x57, 0xa8, 0x70, 0xf2, 0x16, 0x5c, 0xe6, 0x83, 0x51, 0x34, 0x89, 0xc7, 0xdc, 0x49, 0x50, 0x89, 0xb8, 0x25, + 0x4b, 0x40, 0xc9, 0xe8, 0x7d, 0x05, 0xca, 0x82, 0x09, 0xe9, 0x22, 0xaa, 0x95, 0x40, 0x63, 0x0a, 0x52, 0x92, 0x52, + 0xa4, 0x05, 0x15, 0x04, 0x86, 0x50, 0xe9, 0x29, 0x8e, 0x02, 0xfd, 0x16, 0x0f, 0xc4, 0xa0, 0xc1, 0x92, 0x45, 0x19, + 0x0f, 0xe2, 0xe5, 0x42, 0x50, 0xc3, 0x3e, 0xcf, 0x5e, 0x67, 0x17, 0x2c, 0x7f, 0x16, 0x21, 0xec, 0x81, 0xe8, 0x5e, + 0x82, 0xa4, 0x27, 0x81, 0xce, 0x7b, 0x8a, 0x57, 0xce, 0x09, 0x69, 0x58, 0x88, 0x69, 0x8c, 0x8a, 0x10, 0xec, 0x16, + 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xae, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, + 0xe2, 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, + 0xe9, 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0x08, 0xc4, 0x96, 0x70, 0x4b, 0x50, 0x46, 0x68, 0x78, 0xe5, 0x59, 0x92, 0x18, + 0xba, 0xc8, 0x8b, 0x7b, 0x4e, 0x43, 0x1d, 0x01, 0x14, 0xd3, 0x9a, 0x46, 0x1a, 0xb0, 0x40, 0x57, 0xa0, 0x52, 0x52, + 0xda, 0xc8, 0xab, 0xd6, 0x46, 0x40, 0x9c, 0x8e, 0x58, 0x2e, 0x1c, 0x34, 0xa9, 0x43, 0x61, 0xc2, 0x14, 0x18, 0x9a, + 0x8d, 0x40, 0xc2, 0x2b, 0x04, 0xc0, 0x3c, 0xf1, 0x27, 0x59, 0xc1, 0x75, 0x9d, 0x09, 0x7d, 0x7c, 0x7d, 0x1d, 0x0b, + 0x7f, 0x11, 0x19, 0x20, 0x67, 0xd3, 0xec, 0x9c, 0xad, 0x80, 0xba, 0xa7, 0x06, 0x33, 0x41, 0x36, 0x86, 0x01, 0x25, + 0x0a, 0xaa, 0x65, 0x96, 0xc4, 0x60, 0xe9, 0xeb, 0x06, 0x3e, 0x18, 0x74, 0xec, 0x12, 0x65, 0x84, 0xdb, 0xef, 0xf7, + 0xdb, 0x5e, 0xc7, 0x2d, 0x05, 0xc1, 0x17, 0x4b, 0x14, 0xbd, 0x41, 0x3f, 0x4a, 0x13, 0x7c, 0x95, 0x2c, 0x60, 0xae, + 0xa1, 0x14, 0x39, 0xe9, 0x26, 0xe6, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, - 0x5a, 0x89, 0x54, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, - 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, - 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, - 0xb6, 0x51, 0xc0, 0x21, 0x5b, 0x62, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0xdc, - 0xc0, 0x72, 0x5c, 0x49, 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8a, 0x8b, 0xf5, 0x24, - 0xf8, 0x5d, 0xc1, 0x7c, 0x6e, 0xcc, 0x74, 0x2b, 0xa4, 0x5a, 0xc2, 0x49, 0x33, 0x58, 0x83, 0x26, 0x8d, 0x07, 0x25, - 0x6a, 0xbe, 0x46, 0x43, 0x85, 0x38, 0xfe, 0x4c, 0x54, 0xa1, 0x09, 0x86, 0x60, 0xe4, 0x5e, 0x21, 0x19, 0x2e, 0x5b, - 0x16, 0x2d, 0x52, 0xa6, 0xc6, 0xa4, 0x52, 0x35, 0xcb, 0x65, 0x60, 0x60, 0xd1, 0x6e, 0xf5, 0xa5, 0x25, 0xae, 0x44, - 0x6e, 0x1a, 0x6a, 0x61, 0x52, 0x28, 0x6f, 0xc2, 0xc9, 0xd1, 0xef, 0x52, 0xd6, 0xbb, 0x89, 0x4f, 0xae, 0xf0, 0xc9, - 0x7d, 0xc3, 0x87, 0x32, 0x79, 0xbb, 0x18, 0x14, 0xc1, 0xd7, 0xb5, 0x4a, 0xb4, 0x4f, 0x7d, 0x14, 0xcc, 0xae, 0x16, - 0xba, 0x20, 0x50, 0x24, 0x9b, 0xa4, 0x03, 0xc9, 0x6f, 0x28, 0x36, 0x2a, 0xcf, 0x28, 0x73, 0xc5, 0x06, 0xa9, 0x79, - 0xa5, 0x99, 0x97, 0xba, 0x0d, 0xfb, 0xbd, 0x2c, 0x25, 0x9d, 0xb8, 0xa0, 0x4c, 0xec, 0xdd, 0x44, 0x1b, 0x2f, 0x0d, - 0x33, 0x61, 0xfd, 0x0a, 0x63, 0xa7, 0x46, 0xa1, 0x54, 0x8a, 0x40, 0x1c, 0x1b, 0x5f, 0x2b, 0xcb, 0x20, 0xf3, 0x57, - 0xd8, 0x53, 0x00, 0x4a, 0x02, 0x8b, 0xaf, 0xa9, 0xe4, 0x45, 0x61, 0x9d, 0x8e, 0xf7, 0x88, 0x8e, 0x95, 0x08, 0xad, - 0x89, 0x7c, 0xad, 0xcf, 0x62, 0xbf, 0xe6, 0x12, 0x9a, 0x94, 0xcc, 0x07, 0x79, 0x60, 0xab, 0x40, 0x44, 0xa5, 0xdb, - 0x92, 0x41, 0x42, 0x0e, 0xe9, 0x32, 0xd1, 0x6b, 0x23, 0x19, 0xb4, 0x4e, 0x85, 0x44, 0x4b, 0x8f, 0xc2, 0xc8, 0x41, - 0xc7, 0x9d, 0xd6, 0x62, 0x89, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, - 0x0e, 0xa0, 0x03, 0x62, 0x7f, 0x89, 0xf5, 0x56, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0xd7, 0xd7, 0x13, 0xe4, 0x07, - 0x61, 0xf0, 0xc2, 0x9a, 0x0d, 0x94, 0xec, 0xdd, 0x7b, 0x8d, 0xad, 0xc8, 0xfe, 0xac, 0x4a, 0x2a, 0x4f, 0xa1, 0xc6, - 0xb9, 0xf5, 0x75, 0x62, 0x66, 0x68, 0x51, 0x55, 0xec, 0x1b, 0x52, 0x7d, 0x5f, 0x29, 0xec, 0x0a, 0xe5, 0x7d, 0x39, - 0x74, 0xec, 0xba, 0x6e, 0x90, 0x93, 0xf3, 0x72, 0x6f, 0x95, 0x0b, 0x79, 0xff, 0xbe, 0xe9, 0x33, 0x9d, 0xeb, 0xe1, - 0x9f, 0x39, 0xa8, 0x9c, 0x8b, 0xab, 0x94, 0x2c, 0x98, 0x67, 0x4a, 0x1d, 0x2d, 0x39, 0xa0, 0xed, 0x1e, 0x7a, 0xda, - 0xd1, 0x45, 0x14, 0x73, 0x4b, 0x8f, 0x22, 0x3c, 0x6d, 0x94, 0x4f, 0xd2, 0xe8, 0x00, 0xbc, 0xd0, 0x84, 0x24, 0x27, - 0xdc, 0xb4, 0x45, 0x8b, 0xe1, 0x84, 0x61, 0x08, 0x5c, 0xd9, 0x13, 0xa6, 0xec, 0xb9, 0x87, 0x78, 0x8b, 0x81, 0xd9, - 0x6a, 0xd8, 0xcb, 0x66, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, 0x04, 0xb2, 0x6d, 0xaa, 0xea, 0xca, 0xc6, 0xbb, 0x14, 0x91, - 0x18, 0x61, 0x5b, 0x35, 0xb6, 0xb4, 0xf5, 0x7b, 0x0d, 0xf7, 0xba, 0x72, 0xcc, 0x6b, 0x4a, 0xb5, 0xa1, 0x87, 0x95, - 0x9b, 0xc3, 0x4c, 0x47, 0x5e, 0xac, 0xa0, 0xdb, 0x13, 0x41, 0x21, 0x70, 0x22, 0xb4, 0x3d, 0xa8, 0xb8, 0x81, 0x48, - 0xc9, 0x95, 0x56, 0xcd, 0xe6, 0xc9, 0x48, 0x02, 0x0b, 0x2e, 0x2c, 0x97, 0x7c, 0x74, 0x11, 0x27, 0x49, 0x55, 0xfa, - 0xbb, 0x0a, 0x78, 0x31, 0xec, 0x6d, 0xa2, 0x5d, 0x60, 0x34, 0x57, 0x20, 0xb8, 0xda, 0x08, 0xfb, 0xe8, 0xb8, 0xd5, - 0xba, 0x8b, 0x88, 0x23, 0x37, 0xa3, 0x11, 0x50, 0x8f, 0x11, 0x56, 0xcd, 0xda, 0x7b, 0x2f, 0x30, 0xa4, 0x66, 0xe0, - 0x83, 0xea, 0x8c, 0x8a, 0x7f, 0x95, 0x3d, 0xf5, 0x2b, 0xd1, 0xbb, 0x55, 0x75, 0x35, 0x03, 0x2a, 0x2a, 0xf0, 0x61, - 0x86, 0x58, 0xda, 0x2a, 0x10, 0x90, 0xeb, 0x61, 0x51, 0x0a, 0x98, 0xa4, 0xc1, 0x82, 0x52, 0x60, 0xad, 0x95, 0xdd, - 0xeb, 0xdb, 0x82, 0x39, 0x14, 0x0a, 0x17, 0xfd, 0x9f, 0x65, 0xd3, 0x19, 0x5a, 0x66, 0x0d, 0xa6, 0x86, 0x06, 0x1f, - 0x1b, 0xf5, 0xe5, 0x8a, 0xb2, 0x5a, 0x1f, 0xda, 0x91, 0x35, 0x7e, 0xd2, 0x8e, 0x32, 0x38, 0x54, 0x73, 0x5d, 0x54, - 0xb7, 0x9b, 0x9b, 0x22, 0x66, 0x15, 0x8f, 0xfb, 0xa4, 0xb7, 0xb5, 0x35, 0xe9, 0x69, 0x1a, 0x90, 0x4c, 0x92, 0x0c, - 0x6f, 0x32, 0x40, 0x59, 0x11, 0x67, 0x51, 0x36, 0xc8, 0xb7, 0x28, 0x4b, 0x5c, 0xbf, 0x1f, 0x7a, 0x7b, 0x35, 0xcf, - 0xda, 0xdb, 0x5b, 0xef, 0x22, 0x57, 0x75, 0xd2, 0x83, 0x3c, 0x3c, 0x82, 0xa2, 0x25, 0x9b, 0x32, 0x5c, 0x4c, 0xb3, - 0x11, 0x0b, 0x6c, 0xe8, 0x9e, 0xda, 0xa5, 0xdc, 0x34, 0x11, 0x6c, 0x8e, 0x88, 0x39, 0x8b, 0x0f, 0xf5, 0x48, 0x6a, - 0xb0, 0x07, 0x2c, 0xa0, 0xcd, 0x85, 0xaf, 0xc2, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x03, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, - 0x05, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, 0x7d, 0x35, 0xf8, 0x2a, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x1d, 0xbf, - 0xed, 0x77, 0x6c, 0x15, 0x11, 0xfb, 0xc9, 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x00, 0x4d, 0x56, 0x78, 0x43, - 0x16, 0xfe, 0x34, 0xf8, 0x49, 0xb9, 0xd4, 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe1, 0x79, 0xa4, 0xed, - 0x2d, 0x44, 0x05, 0xc6, 0x15, 0x29, 0x2e, 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xc6, 0xc6, 0xc2, - 0x79, 0x13, 0xf1, 0x89, 0x9f, 0x47, 0xe9, 0x28, 0x9b, 0x3a, 0xee, 0xa6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0xe7, - 0x6e, 0xb9, 0x71, 0x02, 0x7e, 0x40, 0x68, 0x0f, 0xec, 0xcd, 0x63, 0xef, 0x80, 0x85, 0x27, 0xbb, 0x1b, 0x8b, 0x11, - 0x2b, 0xfb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7f, 0x29, 0xc1, 0x00, 0x76, - 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0xfb, 0x9e, - 0x76, 0x56, 0xef, 0xdf, 0xaf, 0xd4, 0x7c, 0x55, 0xea, 0xcd, 0x59, 0x58, 0xf3, 0xd4, 0xbd, 0x97, 0x74, 0xb4, 0x52, - 0xdf, 0xc8, 0x73, 0x46, 0x4a, 0x73, 0xd9, 0x4e, 0x70, 0x8c, 0x2d, 0xbe, 0x7a, 0x5b, 0x1f, 0x8a, 0x28, 0x85, 0x1f, - 0x83, 0xf5, 0x12, 0x81, 0xfa, 0x06, 0x07, 0xc7, 0x3b, 0x08, 0xb7, 0x76, 0x9d, 0x41, 0xe0, 0xdc, 0x6b, 0xb5, 0xae, - 0x7f, 0xdc, 0x3a, 0xfc, 0x73, 0xd4, 0xfa, 0x65, 0xaf, 0xf5, 0xc3, 0x91, 0x7b, 0xed, 0xfc, 0xb8, 0x35, 0x38, 0x94, - 0x6f, 0x87, 0x7f, 0xee, 0xff, 0x58, 0x1c, 0xfd, 0x41, 0x14, 0x6e, 0xb8, 0xee, 0xd6, 0x99, 0x37, 0x63, 0xe1, 0x56, - 0xab, 0xd5, 0x87, 0xa7, 0x33, 0x78, 0xc2, 0xbf, 0x17, 0xf0, 0xe7, 0xfa, 0xd0, 0xfa, 0x4f, 0x3f, 0xa6, 0xff, 0xf9, - 0xc7, 0xfc, 0x08, 0xc7, 0x3c, 0xfc, 0xf3, 0x8f, 0x85, 0xfd, 0xa0, 0x1f, 0x6e, 0x1d, 0x6d, 0xba, 0x8e, 0xae, 0xf9, - 0x43, 0x58, 0x3d, 0x42, 0xab, 0xc3, 0x3f, 0xcb, 0x37, 0xfb, 0xc1, 0xc9, 0x6e, 0x3f, 0x3c, 0xba, 0x76, 0xec, 0xeb, - 0x07, 0xee, 0xb5, 0xeb, 0x5e, 0x6f, 0xe0, 0x3c, 0xe7, 0x30, 0xfa, 0x03, 0xf8, 0x3b, 0x86, 0xbf, 0x36, 0xfc, 0x9d, - 0xc2, 0xdf, 0x3f, 0x43, 0x37, 0x11, 0x7f, 0xbb, 0xa6, 0x58, 0xc8, 0x35, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, - 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0x71, 0xbc, 0x01, 0x8b, 0x8e, 0x9c, - 0xb3, 0x11, 0x30, 0x4f, 0x44, 0x0e, 0x8a, 0x80, 0x8b, 0xb3, 0xd5, 0x02, 0x0f, 0x57, 0xbd, 0x61, 0xb8, 0xc1, 0x1c, - 0x30, 0x0a, 0xde, 0x32, 0x7c, 0xe8, 0xba, 0xde, 0x0b, 0x79, 0x66, 0x88, 0xfb, 0x5c, 0xb0, 0x56, 0x9a, 0x09, 0x93, - 0xc6, 0x76, 0xbd, 0xd9, 0x8a, 0x4a, 0xd8, 0xd6, 0xe9, 0x19, 0xd4, 0x9d, 0x8a, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, - 0xb7, 0xe4, 0x1b, 0xe3, 0x10, 0x78, 0xc9, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xa7, 0x0c, 0x66, - 0x58, 0x32, 0x11, 0x39, 0x29, 0x4d, 0x61, 0xd9, 0xc2, 0xe4, 0xef, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, - 0x64, 0x9b, 0x96, 0xfe, 0x1d, 0xa6, 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xeb, 0x70, - 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, 0x9f, 0xf3, 0x1e, 0xd5, 0x18, 0xfc, 0x2b, 0xc3, 0x0c, 0x9e, 0x98, 0x0f, 0x43, - 0x34, 0x8b, 0x52, 0x07, 0xb7, 0x52, 0x14, 0xf7, 0xaf, 0x70, 0x67, 0xa4, 0xa5, 0xb7, 0x1f, 0xaa, 0x1d, 0x73, 0x90, - 0x33, 0xf6, 0x5d, 0x94, 0x7c, 0x62, 0xb9, 0x73, 0xe9, 0x75, 0xba, 0x9f, 0x53, 0x67, 0x0f, 0x6d, 0xb3, 0x0f, 0xd5, - 0x31, 0x9a, 0x32, 0x0b, 0xd4, 0x11, 0x61, 0xab, 0xe3, 0xe5, 0x18, 0xd5, 0x42, 0x12, 0x14, 0x5e, 0x16, 0x76, 0x89, - 0xc3, 0xed, 0xdd, 0xe2, 0xfc, 0xac, 0x6f, 0x07, 0xb6, 0x0d, 0x16, 0xff, 0x01, 0x85, 0xad, 0x84, 0x61, 0x01, 0x06, - 0xd9, 0x6e, 0xdc, 0xe3, 0x9b, 0x9b, 0x55, 0xc0, 0x09, 0x0f, 0xd2, 0xa9, 0x7b, 0xe2, 0x45, 0xde, 0x24, 0x84, 0x01, - 0x87, 0xd0, 0x0c, 0xbb, 0xf4, 0x86, 0xbb, 0xb1, 0x9c, 0x06, 0x63, 0x21, 0x7e, 0x12, 0x15, 0xfc, 0x15, 0xc6, 0x23, - 0xc2, 0x21, 0x1a, 0xfb, 0x3e, 0xbb, 0x64, 0x43, 0x65, 0x67, 0x00, 0xa1, 0x22, 0xb7, 0xe7, 0x0e, 0x43, 0xa3, 0x19, - 0xcc, 0x1d, 0x86, 0x07, 0x03, 0x1b, 0xf6, 0x12, 0xec, 0xca, 0x30, 0x3a, 0xec, 0x1c, 0x0d, 0xd2, 0x70, 0xc6, 0x02, - 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0xea, 0x1e, 0x0d, 0x9c, 0x29, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x86, 0x11, - 0x8a, 0x22, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0xce, 0x1c, 0x7b, 0x77, 0xcb, 0xde, 0xc4, 0x52, 0xcf, 0x06, 0xf6, 0x82, - 0xb9, 0xc3, 0x0b, 0xd7, 0xec, 0xbc, 0x7d, 0x84, 0xa0, 0x62, 0x21, 0x4e, 0x7e, 0x31, 0xb0, 0xfb, 0x62, 0xea, 0x36, - 0x0c, 0x9a, 0xca, 0xe5, 0xc7, 0x15, 0x3d, 0x20, 0x54, 0x55, 0x57, 0x05, 0x1d, 0x94, 0x75, 0x03, 0x67, 0x62, 0x22, - 0xd1, 0xc2, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, 0x30, 0xa9, 0xd1, 0x6d, 0xfb, 0x68, 0x70, 0x11, 0x3c, 0xb0, - 0x1f, 0xa8, 0x97, 0x31, 0x20, 0xc3, 0xc4, 0xf4, 0x63, 0x90, 0x76, 0xf8, 0xf7, 0x9c, 0x01, 0x92, 0x17, 0x54, 0x34, - 0x93, 0x45, 0x67, 0x58, 0x74, 0x10, 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xa3, 0x90, 0x60, 0xbf, 0x7f, - 0x1f, 0x96, 0x66, 0xb3, 0x73, 0x84, 0xe7, 0x0d, 0x39, 0x2f, 0xbe, 0x8b, 0x39, 0xa8, 0x84, 0xad, 0xbe, 0xed, 0x0e, - 0x6c, 0x0b, 0x97, 0xb6, 0x97, 0x6d, 0x86, 0x82, 0xc2, 0xf1, 0xe6, 0x01, 0x0b, 0x26, 0xfd, 0xb0, 0x3d, 0x70, 0x72, - 0x19, 0x6e, 0xc4, 0x73, 0x4b, 0x21, 0xc1, 0xdb, 0xde, 0x04, 0x04, 0x3a, 0x72, 0xee, 0x86, 0xbd, 0xa9, 0x0a, 0xa1, - 0xe8, 0x78, 0x73, 0xe4, 0x06, 0x31, 0xfc, 0x71, 0x5a, 0xc8, 0x34, 0x13, 0xdd, 0x57, 0x6b, 0x66, 0x37, 0x18, 0x29, - 0x8b, 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, - 0xb1, 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, - 0x47, 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf3, 0x0c, 0x09, 0xc5, 0x4b, 0xed, 0x86, 0x09, - 0x73, 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, - 0xbd, 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, - 0xe1, 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, - 0x02, 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x71, 0xe9, 0xda, - 0xa3, 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, - 0xbf, 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, - 0x60, 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, - 0x46, 0xe0, 0x39, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, - 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, - 0xdc, 0x82, 0x18, 0x87, 0x1b, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, - 0x8a, 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, - 0x52, 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, - 0x36, 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x39, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, - 0xf4, 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, - 0xa2, 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xb9, 0xf9, 0x52, 0xcc, 0x86, 0xbb, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, - 0xd1, 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x4b, 0xcc, 0xd9, 0x6f, 0x83, 0x0d, - 0x5e, 0xcb, 0x3b, 0x40, 0xfb, 0x8e, 0x4d, 0x67, 0xfc, 0x6a, 0x9f, 0x14, 0x7d, 0x20, 0xd3, 0x06, 0xc4, 0xd9, 0x79, - 0xbb, 0x17, 0xef, 0xf2, 0x5e, 0x0c, 0x52, 0x3d, 0x57, 0x2c, 0x86, 0x7b, 0xd5, 0x7b, 0x8f, 0x51, 0x4a, 0x93, 0x99, - 0xbc, 0x1a, 0x7a, 0x5d, 0x89, 0xde, 0xe6, 0x26, 0x20, 0xd8, 0x33, 0xba, 0x72, 0xd1, 0xb5, 0x2c, 0x05, 0x4d, 0x00, - 0xa2, 0x27, 0x75, 0x96, 0x23, 0x8e, 0xc3, 0x6c, 0x36, 0x28, 0x1e, 0x31, 0x77, 0xe5, 0xa8, 0x38, 0x26, 0x76, 0x97, - 0x09, 0x3b, 0x80, 0x19, 0x71, 0x79, 0xab, 0x23, 0xa2, 0xc3, 0xa2, 0xbf, 0x8e, 0x6f, 0x1f, 0x7b, 0x6c, 0xb3, 0xe3, - 0x82, 0x06, 0xa9, 0x8d, 0xf5, 0xb8, 0x1a, 0x0b, 0xea, 0xc3, 0x63, 0x4d, 0xa5, 0xb2, 0xd8, 0xdc, 0x2c, 0xeb, 0x47, - 0xb5, 0x6a, 0x07, 0xd7, 0x4e, 0x53, 0x2e, 0x9b, 0xd9, 0x20, 0x1c, 0x88, 0x98, 0x40, 0x81, 0x96, 0x56, 0x56, 0x0c, - 0x30, 0xa4, 0x2c, 0x47, 0xf9, 0x14, 0x32, 0x2f, 0x2e, 0x4b, 0x9d, 0xfa, 0xf2, 0x4c, 0x06, 0x1d, 0xf1, 0xd4, 0x93, - 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x0b, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, - 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, 0x0c, 0xda, 0xfe, 0x59, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x8f, - 0x02, 0xaa, 0x9f, 0x4b, 0x09, 0x36, 0x09, 0x3f, 0x02, 0x1b, 0x55, 0x8e, 0x27, 0x09, 0xc2, 0xe7, 0x71, 0xce, 0xc8, - 0x53, 0xd8, 0x90, 0x30, 0x4b, 0xd3, 0x36, 0x52, 0xed, 0x22, 0x33, 0x08, 0xe5, 0xc2, 0xfc, 0x13, 0xe3, 0xec, 0x22, - 0x0b, 0x97, 0x5a, 0x83, 0xf9, 0xf1, 0xce, 0x04, 0x28, 0xbb, 0xbe, 0xce, 0x84, 0x8f, 0x1b, 0x91, 0xbd, 0xa1, 0x2b, - 0x26, 0x03, 0x85, 0x54, 0xe0, 0x44, 0x64, 0xf1, 0xd0, 0x19, 0x0a, 0x8d, 0x70, 0x40, 0xa7, 0xc8, 0xb9, 0x6b, 0x6c, - 0xfa, 0x7c, 0xa0, 0x7d, 0xa3, 0x34, 0x74, 0x12, 0x10, 0x02, 0x02, 0x77, 0xc3, 0x9a, 0x4a, 0x07, 0x69, 0x90, 0x50, - 0x29, 0xfa, 0x39, 0x80, 0x7f, 0x18, 0x49, 0x0a, 0x80, 0xfd, 0x50, 0x8d, 0x14, 0x51, 0x96, 0x05, 0x2e, 0x00, 0xcd, - 0xb5, 0x8f, 0x2b, 0xe1, 0x0b, 0x03, 0x15, 0xa6, 0xa7, 0x59, 0x79, 0x29, 0x94, 0xc8, 0xd3, 0x15, 0x29, 0x6b, 0x24, - 0x93, 0xcf, 0xd1, 0xe1, 0x53, 0xde, 0xf5, 0x5b, 0x89, 0x87, 0x2e, 0x78, 0x0e, 0xcb, 0xaa, 0x9e, 0xdf, 0x84, 0x9c, - 0x9c, 0x6b, 0xd0, 0x15, 0x52, 0xe8, 0x2f, 0x39, 0xc9, 0x7b, 0x6f, 0xfc, 0xaa, 0x96, 0x1a, 0x43, 0xd9, 0xc7, 0x55, - 0xcd, 0xb0, 0xbc, 0x9c, 0x55, 0x61, 0x0a, 0x02, 0x6e, 0xc1, 0x92, 0x60, 0x21, 0x35, 0x04, 0x58, 0xd8, 0x1e, 0x69, - 0xa5, 0x20, 0x2f, 0x75, 0x78, 0xe7, 0x39, 0x58, 0x01, 0xc6, 0xa1, 0x96, 0x4a, 0xa6, 0x91, 0xc4, 0x97, 0x4a, 0x14, - 0x98, 0x72, 0x7f, 0x08, 0x7e, 0x6a, 0xf3, 0xa4, 0xeb, 0xd2, 0xf5, 0xe3, 0x29, 0xa6, 0xf6, 0x10, 0xe8, 0xb1, 0x77, - 0x0f, 0x4c, 0x89, 0xba, 0x0e, 0x2b, 0x88, 0x43, 0xb3, 0x9a, 0x66, 0x01, 0x33, 0xa6, 0x0d, 0x5a, 0xb2, 0x0d, 0xb6, - 0x5c, 0x0e, 0xf6, 0x91, 0xd8, 0x9e, 0xd5, 0x0a, 0x08, 0x5d, 0x83, 0x06, 0x86, 0xdc, 0xa5, 0x42, 0x0b, 0xf3, 0x5e, - 0x97, 0x8a, 0x70, 0x7f, 0x0e, 0xb8, 0xb4, 0x82, 0x33, 0x2f, 0xa3, 0x81, 0xf7, 0xe3, 0xd3, 0x04, 0x13, 0x5f, 0x10, - 0x2b, 0xb0, 0x83, 0x83, 0x4e, 0xb3, 0x29, 0x70, 0x2a, 0x2e, 0x52, 0x06, 0xcb, 0x8a, 0x52, 0x1b, 0xfe, 0x48, 0x91, - 0xad, 0xbb, 0x3c, 0xd2, 0x5d, 0x88, 0x05, 0xb0, 0xd3, 0x2f, 0x18, 0xf9, 0x96, 0xf5, 0x32, 0x60, 0x70, 0xae, 0x35, - 0x0e, 0x02, 0xbf, 0xb9, 0x99, 0x1c, 0x95, 0x29, 0xb1, 0x5d, 0x93, 0xd5, 0x05, 0xe4, 0x98, 0x04, 0xd8, 0xc0, 0x1d, - 0x84, 0xa5, 0xb2, 0xc7, 0x8b, 0x72, 0x8a, 0xcb, 0xa5, 0x2c, 0xe4, 0xe6, 0x79, 0x35, 0xcd, 0xe7, 0x56, 0x9a, 0x4d, - 0xc7, 0x5b, 0xf1, 0x45, 0xc1, 0x3f, 0x70, 0x62, 0x69, 0xd5, 0x53, 0x6a, 0x85, 0x47, 0x99, 0x5b, 0xb2, 0x4e, 0x49, - 0xad, 0xae, 0x1b, 0xa8, 0x46, 0x78, 0x9a, 0x86, 0x8d, 0x40, 0x88, 0x09, 0x2e, 0x7e, 0xdb, 0x64, 0x62, 0xda, 0x5b, - 0x42, 0xea, 0x08, 0xbb, 0x87, 0x72, 0x82, 0xbb, 0x9a, 0x67, 0x5f, 0x86, 0xb3, 0xf5, 0xcc, 0xbd, 0x67, 0x30, 0xf7, - 0xd3, 0x90, 0x1b, 0x8c, 0x1e, 0xcb, 0x84, 0x1f, 0x19, 0xfb, 0xc8, 0x55, 0xd5, 0xb3, 0xb3, 0xb0, 0x12, 0x59, 0xe2, - 0xc9, 0x38, 0xea, 0x30, 0x4e, 0x45, 0x6b, 0x82, 0xec, 0xfa, 0xba, 0x30, 0xf7, 0x02, 0x05, 0x4d, 0x3d, 0x5e, 0x8f, - 0xd3, 0x56, 0xec, 0x6c, 0x44, 0x22, 0xf7, 0xde, 0xd4, 0x22, 0x91, 0x15, 0x9f, 0xe3, 0x48, 0x6b, 0x0e, 0x72, 0x9f, - 0x9d, 0x2d, 0x6f, 0x52, 0xa1, 0x5b, 0x34, 0xda, 0xc6, 0x1e, 0xd5, 0x07, 0x92, 0x7a, 0x46, 0x05, 0x56, 0x35, 0xf6, - 0xfd, 0xfb, 0x1d, 0x91, 0x6e, 0xa9, 0x14, 0x1b, 0x2c, 0x2d, 0x8c, 0x66, 0x8c, 0x82, 0x41, 0x49, 0x91, 0x81, 0x1a, - 0xe5, 0x6b, 0x04, 0xc3, 0x1e, 0x35, 0x00, 0xc5, 0xb9, 0xba, 0xfa, 0x69, 0x29, 0xd9, 0x42, 0x40, 0xe2, 0x2e, 0x18, - 0x88, 0x35, 0xc1, 0xcc, 0xc8, 0x27, 0x1f, 0x81, 0xf3, 0x06, 0x0c, 0x1d, 0x03, 0xf0, 0x0b, 0xc4, 0xa6, 0x07, 0x13, - 0xdb, 0x26, 0xa2, 0xe8, 0xb3, 0x81, 0x97, 0x00, 0xec, 0xac, 0x0a, 0x8d, 0x7e, 0xa8, 0x52, 0xc0, 0x90, 0x0d, 0xdc, - 0x80, 0x55, 0x61, 0xb9, 0xbd, 0x97, 0xe0, 0x36, 0xc0, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xb3, 0x0b, - 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0x41, 0xa3, 0x5e, 0x51, 0x42, 0xd4, 0xee, 0x63, 0xed, 0x4b, 0x8c, 0xb0, 0x88, - 0xf7, 0x37, 0xf8, 0xae, 0xc7, 0x2d, 0xf7, 0x34, 0x5a, 0x84, 0xe9, 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, - 0xbd, 0xdc, 0x17, 0xb1, 0xe0, 0x0a, 0x47, 0x56, 0x85, 0x14, 0x1b, 0x48, 0xd2, 0xd3, 0x1e, 0x1d, 0xb0, 0x6f, 0x34, - 0x7b, 0x01, 0x65, 0x3e, 0x56, 0xa4, 0x92, 0x90, 0xd2, 0xec, 0x86, 0x48, 0x12, 0xd6, 0x8a, 0x3c, 0x75, 0xde, 0x77, - 0xb4, 0xcf, 0xad, 0x24, 0x82, 0x11, 0x9c, 0x84, 0xe9, 0x58, 0x79, 0xd0, 0x14, 0xe0, 0x2a, 0x3a, 0x62, 0xfa, 0x26, - 0x20, 0xbf, 0x19, 0xc8, 0xed, 0xa5, 0xe4, 0xda, 0x5c, 0xc3, 0xf0, 0x0c, 0x09, 0x56, 0x45, 0x22, 0xf0, 0x88, 0x1a, - 0x70, 0xcc, 0x57, 0x79, 0x1e, 0x60, 0xc2, 0xd7, 0xf6, 0x26, 0x00, 0x94, 0x93, 0xab, 0xe2, 0x2c, 0x05, 0xba, 0x01, - 0xcb, 0xd5, 0x71, 0x6a, 0x54, 0x24, 0x2e, 0x6e, 0x4c, 0x57, 0xb7, 0xf4, 0xa7, 0x68, 0x39, 0x93, 0x21, 0xa6, 0x83, - 0x20, 0x20, 0x53, 0x9f, 0x32, 0x47, 0xc8, 0x5c, 0x61, 0x7d, 0xce, 0x9c, 0xda, 0xd4, 0x3d, 0x46, 0xdd, 0x3c, 0x49, - 0x2d, 0x5e, 0xa7, 0x4d, 0x29, 0x11, 0x93, 0x12, 0xf3, 0x54, 0xa4, 0x62, 0x33, 0x25, 0xee, 0xdc, 0xfa, 0x46, 0x0b, - 0x69, 0xa3, 0x9d, 0x8a, 0x1c, 0x6c, 0x56, 0xc9, 0x7b, 0x02, 0xe3, 0xa5, 0x20, 0x7c, 0x89, 0x8c, 0xb5, 0x98, 0x33, - 0xc7, 0x44, 0xb0, 0x7a, 0x31, 0x15, 0xf9, 0x07, 0x47, 0xa7, 0xd9, 0x1b, 0xf4, 0x20, 0xf5, 0x06, 0x12, 0xb3, 0x26, - 0xbe, 0x0b, 0x69, 0xa8, 0x23, 0x04, 0x2a, 0xa3, 0x5a, 0xa6, 0xe3, 0xc4, 0x2a, 0x7c, 0x23, 0xf8, 0xea, 0xbd, 0x3e, - 0xce, 0x37, 0x9e, 0x1b, 0xab, 0x11, 0xc4, 0xe0, 0x2d, 0xe4, 0x47, 0x9e, 0x14, 0xe1, 0x40, 0xb8, 0x7c, 0x73, 0xb3, - 0x97, 0xef, 0xf2, 0x2a, 0x44, 0x52, 0xc1, 0x18, 0x63, 0x46, 0x31, 0xee, 0x89, 0x9a, 0x5a, 0xcc, 0x61, 0x60, 0xd9, - 0x3a, 0xcc, 0xf1, 0x00, 0x00, 0x5a, 0x9a, 0xd2, 0xab, 0xa6, 0x42, 0xe5, 0x79, 0x2e, 0xe1, 0x53, 0x1d, 0xa2, 0xaa, - 0xc6, 0xef, 0x57, 0x67, 0xa0, 0x10, 0xdc, 0xf7, 0x3a, 0x1e, 0x1e, 0x42, 0xc0, 0x2a, 0x0a, 0x59, 0xa0, 0x37, 0x68, - 0xaf, 0x4a, 0x84, 0x62, 0xe6, 0x64, 0x3d, 0x66, 0x38, 0xa9, 0x60, 0x0b, 0x95, 0xb0, 0x54, 0x5a, 0xe0, 0x57, 0x1b, - 0xa1, 0x79, 0xca, 0xb8, 0xf7, 0xa6, 0xc2, 0x19, 0xf4, 0x07, 0xf3, 0x96, 0x19, 0xf5, 0xfd, 0xd2, 0x89, 0x4c, 0x05, - 0x26, 0x6e, 0x66, 0xa9, 0xfd, 0x7e, 0x59, 0xa5, 0xfd, 0xbc, 0x42, 0xee, 0x73, 0xd2, 0x7c, 0x9d, 0x3b, 0x68, 0x3e, - 0x19, 0xee, 0x57, 0xca, 0x0f, 0x2d, 0x8c, 0x9a, 0xf2, 0xcb, 0xeb, 0xca, 0xaf, 0xf0, 0x54, 0x78, 0xab, 0xdf, 0x45, - 0xa1, 0x8b, 0xfa, 0x1c, 0x0c, 0x21, 0xfd, 0x08, 0xae, 0xa1, 0xc1, 0x83, 0x22, 0x59, 0x2c, 0xd6, 0x2e, 0x88, 0xeb, - 0x63, 0x4e, 0xb5, 0x43, 0x19, 0x63, 0xc4, 0xd3, 0x92, 0x83, 0x24, 0x83, 0x83, 0xf1, 0x1b, 0x18, 0x10, 0x93, 0x92, - 0x90, 0x0e, 0xa1, 0xb3, 0x32, 0x13, 0x51, 0xb9, 0x8b, 0xb7, 0x1b, 0x97, 0x35, 0x85, 0x22, 0xec, 0x04, 0x33, 0x95, - 0x52, 0x41, 0x20, 0x4d, 0xbe, 0x7b, 0x9d, 0x5a, 0x30, 0xb4, 0x70, 0x4d, 0x05, 0xe4, 0xb5, 0x5d, 0x0f, 0x9a, 0x7c, - 0xa4, 0x18, 0xfa, 0x2a, 0x35, 0xe2, 0x65, 0x06, 0x5f, 0xc3, 0xe6, 0xaf, 0x89, 0x92, 0x3c, 0x64, 0x22, 0xf6, 0x0a, - 0x3e, 0x11, 0xb2, 0x29, 0xd8, 0x99, 0x40, 0x3f, 0xb4, 0x2b, 0x7b, 0xe9, 0x6e, 0x51, 0xb9, 0xb4, 0x68, 0x6c, 0x25, - 0x6a, 0xd6, 0xfc, 0x30, 0xde, 0x4c, 0x61, 0x3f, 0x7b, 0x94, 0x40, 0x40, 0x9a, 0xca, 0x49, 0xaa, 0x79, 0x0f, 0xd3, - 0x23, 0x00, 0x09, 0x76, 0x3f, 0x81, 0x85, 0x7e, 0x53, 0x62, 0x82, 0x45, 0xd5, 0xd8, 0x6d, 0x06, 0x5a, 0x73, 0x46, - 0x9a, 0x6f, 0x86, 0x5a, 0x7b, 0x53, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x66, 0x71, 0x98, 0x6e, 0x76, 0x8e, - 0x0c, 0xc1, 0x85, 0xc7, 0xff, 0x49, 0x89, 0x69, 0x20, 0xb9, 0xd4, 0x8d, 0x9f, 0x50, 0x87, 0xe1, 0xff, 0x16, 0xa4, - 0x80, 0x07, 0xb5, 0xd5, 0x58, 0x72, 0xee, 0x15, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, - 0x89, 0x62, 0x9e, 0x13, 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, - 0xca, 0xcf, 0xe8, 0x48, 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x0b, 0x30, 0xcd, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, - 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0x59, 0x83, - 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, 0x55, 0x60, 0x40, - 0xb9, 0xd3, 0x34, 0xac, 0x84, 0xb8, 0x44, 0x85, 0x59, 0xc5, 0xf9, 0xe3, 0x3a, 0xaf, 0x9b, 0x96, 0x25, 0x06, 0xe5, - 0x67, 0xae, 0xe1, 0xc6, 0xf7, 0x1a, 0xf9, 0xe3, 0x7b, 0x2f, 0x41, 0xb7, 0x13, 0x69, 0xef, 0xdf, 0xcf, 0xef, 0x91, - 0x85, 0x86, 0xf7, 0xc2, 0x66, 0xd0, 0x16, 0xe9, 0x92, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, - 0x30, 0x03, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, - 0xe4, 0xc5, 0x3a, 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x00, 0xfa, 0x15, 0x95, 0xc5, 0x06, 0x72, - 0x71, 0x53, 0xd6, 0x7a, 0x45, 0xa3, 0xd1, 0x8d, 0x5d, 0x58, 0x5d, 0x81, 0x4f, 0xa2, 0x74, 0x94, 0x88, 0x49, 0xcc, - 0xa4, 0xca, 0x15, 0xb9, 0x36, 0xba, 0x97, 0xb6, 0x68, 0x5e, 0x0a, 0x09, 0x5e, 0x11, 0xb8, 0x21, 0xf4, 0x95, 0xbe, - 0x5c, 0x6d, 0xa0, 0xe0, 0x51, 0x7b, 0x73, 0x11, 0x4c, 0x4c, 0x3c, 0x66, 0x48, 0x4d, 0xbf, 0x0e, 0xa7, 0x56, 0x16, - 0x4b, 0x0e, 0xbf, 0xce, 0x19, 0x6b, 0x28, 0x00, 0xe2, 0x93, 0x47, 0xeb, 0xdd, 0xa4, 0x37, 0x4a, 0x3b, 0x28, 0x8d, - 0x10, 0xdf, 0x55, 0xf8, 0xba, 0x0b, 0xc5, 0x57, 0xae, 0xba, 0xf7, 0x75, 0xcc, 0x8c, 0x0b, 0x46, 0x2f, 0xf9, 0x34, - 0x69, 0x5c, 0xbb, 0xa1, 0xbb, 0x3a, 0xdf, 0x7b, 0x5f, 0xca, 0xbc, 0x85, 0x63, 0x60, 0x93, 0x63, 0xe6, 0xbc, 0xf4, - 0xde, 0x1a, 0x27, 0xca, 0x3f, 0x98, 0x47, 0xbc, 0x72, 0x98, 0x55, 0x27, 0xc9, 0x3f, 0x0c, 0x7e, 0x08, 0xd6, 0xb7, - 0x34, 0x4e, 0x90, 0xbb, 0xea, 0x04, 0x99, 0x28, 0xb7, 0xa1, 0x37, 0xdc, 0xde, 0x5d, 0x05, 0x82, 0x38, 0x15, 0xd3, - 0x47, 0xe5, 0xb8, 0x7e, 0xb4, 0x40, 0xa5, 0x22, 0xe2, 0x73, 0x95, 0xbb, 0xb2, 0x36, 0x35, 0xd4, 0xe3, 0x3a, 0x99, - 0x85, 0xa6, 0x59, 0x91, 0x4b, 0xd9, 0xf4, 0x18, 0x99, 0x66, 0xa7, 0xda, 0xfc, 0xee, 0xda, 0x43, 0x3a, 0x86, 0xe6, - 0x62, 0xad, 0x16, 0xdc, 0xef, 0x2a, 0x0a, 0xef, 0x7a, 0xb1, 0x91, 0xca, 0x50, 0xb3, 0x1e, 0x45, 0x1f, 0xc7, 0x6d, - 0xe6, 0xf2, 0x28, 0xfb, 0xb3, 0x06, 0x80, 0xe9, 0x08, 0x8b, 0xee, 0xa6, 0x67, 0xec, 0x09, 0xf4, 0xf4, 0x44, 0x06, - 0x89, 0xde, 0xe8, 0x7c, 0xd5, 0x2a, 0xb1, 0x74, 0x05, 0x81, 0xdd, 0x1b, 0x32, 0x56, 0x25, 0xed, 0x96, 0xeb, 0x97, - 0xf3, 0x7c, 0x9e, 0xf3, 0xa5, 0x3c, 0x9f, 0x9a, 0x45, 0x77, 0xaf, 0xed, 0xde, 0x9c, 0x1a, 0x2a, 0xe6, 0x5a, 0xdd, - 0xe4, 0x37, 0x4c, 0xd7, 0xc1, 0x50, 0x8b, 0x20, 0xb3, 0xda, 0x55, 0x2f, 0xca, 0x72, 0xa3, 0x9e, 0xc9, 0xb1, 0x21, - 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0xf7, 0x8d, 0x6d, 0x21, 0xdb, 0xbc, 0xbc, 0x1a, 0xe5, 0x40, - 0x69, 0xb9, 0xbf, 0x4c, 0x18, 0xbe, 0xbf, 0xbe, 0xfe, 0x5e, 0xc8, 0xa9, 0xaa, 0xa3, 0xb7, 0x78, 0xad, 0x7b, 0x06, - 0x1b, 0xa5, 0x72, 0x22, 0x2e, 0xd8, 0xea, 0xc1, 0x9b, 0xbb, 0x57, 0xc0, 0x72, 0x01, 0xd8, 0x5d, 0x30, 0xa7, 0x31, - 0x54, 0xb5, 0x81, 0xbf, 0x5c, 0x3d, 0xd8, 0xaa, 0x3d, 0xfc, 0xe5, 0xe0, 0xcb, 0xe0, 0xc6, 0xc6, 0xc6, 0x36, 0xde, - 0xae, 0x25, 0x82, 0xbc, 0xc1, 0x03, 0x7d, 0xbc, 0xfa, 0x28, 0x68, 0xb9, 0x4a, 0x6c, 0x0f, 0x1c, 0x0a, 0x5b, 0x83, - 0x7c, 0x93, 0x32, 0x69, 0x38, 0x2f, 0x78, 0x36, 0x95, 0x33, 0x14, 0xf2, 0x9a, 0x8f, 0x83, 0xb6, 0x23, 0xfc, 0x1b, - 0x38, 0xb5, 0xe3, 0xe5, 0xc5, 0x27, 0xe8, 0x03, 0x9e, 0xae, 0x94, 0xa6, 0x22, 0x4e, 0x29, 0xb7, 0xe8, 0x72, 0x9d, - 0x07, 0x23, 0xc5, 0xc5, 0x04, 0x95, 0x8e, 0xbb, 0xb8, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, - 0x44, 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, - 0xd7, 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, - 0xe7, 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, - 0x52, 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, - 0x2d, 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, - 0xc4, 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, - 0xd6, 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, - 0xe2, 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0xe7, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, - 0x68, 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, - 0x57, 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, - 0x30, 0x93, 0xa6, 0xbc, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, - 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0xe1, 0x03, 0xb9, 0xd4, 0x92, 0xbf, - 0xcc, 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, - 0x51, 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x25, 0x7f, 0x8e, 0xa9, - 0x83, 0x59, 0xa9, 0xdd, 0xb4, 0xd8, 0x24, 0x79, 0xcf, 0x0c, 0x48, 0xae, 0xbe, 0x86, 0x87, 0xc6, 0x2f, 0x5e, 0x99, - 0x53, 0xc2, 0x17, 0x65, 0x2c, 0x2d, 0x8d, 0xb9, 0xf4, 0xdf, 0xca, 0xfb, 0xb4, 0x12, 0xb0, 0x57, 0x20, 0xa6, 0x0c, - 0x5c, 0x62, 0xe3, 0x82, 0xa4, 0xbc, 0x96, 0xa7, 0xec, 0xbe, 0x86, 0xf2, 0x5d, 0x32, 0xe9, 0x2a, 0x95, 0xb5, 0xc6, - 0xaa, 0xfb, 0x79, 0xce, 0xf2, 0xab, 0x7d, 0x86, 0xb9, 0xc9, 0x68, 0x90, 0x2d, 0x99, 0xd9, 0x94, 0x5f, 0xed, 0xdd, - 0xf8, 0x95, 0x87, 0x92, 0x0e, 0xd5, 0x2a, 0xdd, 0xbc, 0x74, 0xc3, 0x31, 0x6e, 0xdc, 0x70, 0x04, 0xb0, 0x31, 0xec, - 0x54, 0x91, 0x5a, 0xe7, 0xbf, 0x2f, 0x87, 0x9f, 0x68, 0xaf, 0x1d, 0xe9, 0x5d, 0x77, 0xb4, 0x32, 0x3d, 0xfd, 0x06, - 0x54, 0x8d, 0x2c, 0xa1, 0x9b, 0x50, 0xc5, 0x64, 0x24, 0x4a, 0x4c, 0x57, 0x29, 0x8f, 0xfa, 0x1a, 0x71, 0x0e, 0xe2, - 0x86, 0xf2, 0x17, 0xff, 0x14, 0x5e, 0x9d, 0x04, 0x68, 0x44, 0x2d, 0xc6, 0x59, 0xca, 0x5b, 0xe3, 0x68, 0x1a, 0x27, - 0x57, 0xc1, 0x3c, 0x6e, 0x4d, 0xb3, 0x34, 0x2b, 0x66, 0xc0, 0x95, 0x5e, 0x71, 0x05, 0x36, 0xfc, 0xb4, 0x35, 0x8f, - 0xbd, 0x97, 0x2c, 0x39, 0x67, 0x3c, 0x1e, 0x46, 0x9e, 0xbd, 0x97, 0x83, 0x78, 0xb0, 0xde, 0x46, 0x79, 0x9e, 0x5d, - 0xd8, 0xde, 0x87, 0xec, 0x14, 0x98, 0xd6, 0x7b, 0x77, 0x79, 0x75, 0xc6, 0x52, 0xef, 0xe3, 0xe9, 0x3c, 0xe5, 0x73, - 0xaf, 0x88, 0xd2, 0xa2, 0x55, 0xb0, 0x3c, 0x1e, 0x83, 0x9a, 0x48, 0xb2, 0xbc, 0x85, 0xf9, 0xcf, 0x53, 0x16, 0x24, - 0xf1, 0xd9, 0x84, 0x5b, 0xa3, 0x28, 0xff, 0xd4, 0x6b, 0xb5, 0x66, 0x79, 0x3c, 0x8d, 0xf2, 0xab, 0x16, 0xb5, 0x08, - 0x3e, 0x6b, 0x6f, 0x47, 0x9f, 0x8f, 0x1f, 0xf6, 0x78, 0x0e, 0x7d, 0x63, 0xa4, 0x62, 0x00, 0xc2, 0xc7, 0xda, 0xde, - 0x69, 0x4f, 0x8b, 0x7b, 0xe2, 0x44, 0x29, 0x4a, 0x79, 0x79, 0xe2, 0x5d, 0x31, 0x80, 0xdb, 0x3f, 0xe5, 0xa9, 0x07, - 0xbe, 0x1c, 0xcf, 0xd2, 0xc5, 0x70, 0x9e, 0x17, 0x30, 0xc0, 0x2c, 0x8b, 0x53, 0xce, 0xf2, 0xde, 0x69, 0x96, 0x03, - 0xd9, 0x5a, 0x79, 0x34, 0x8a, 0xe7, 0x45, 0xf0, 0x70, 0x76, 0xd9, 0x43, 0x5b, 0xe1, 0x2c, 0xcf, 0xe6, 0xe9, 0x48, - 0xce, 0x15, 0xa7, 0xb0, 0x31, 0x62, 0x6e, 0x56, 0xd0, 0x97, 0x50, 0x00, 0xbe, 0x94, 0x45, 0x79, 0xeb, 0x0c, 0x3b, - 0xa3, 0xa1, 0xdf, 0x1e, 0xb1, 0x33, 0x2f, 0x3f, 0x3b, 0x8d, 0x9c, 0x4e, 0xf7, 0xb1, 0xa7, 0xfe, 0xf3, 0x77, 0x5c, - 0x30, 0xdc, 0x57, 0x16, 0x77, 0xda, 0xed, 0xbf, 0x71, 0x7b, 0x8d, 0x59, 0x08, 0xa0, 0xa0, 0x33, 0xbb, 0xb4, 0x8a, - 0x2c, 0x81, 0xf5, 0x59, 0xd5, 0xb3, 0x37, 0x03, 0xbf, 0x29, 0x4e, 0xcf, 0x82, 0xee, 0xec, 0xb2, 0x44, 0xec, 0x02, - 0x91, 0x90, 0x29, 0x91, 0x94, 0x6f, 0x8b, 0xdf, 0x0a, 0xf1, 0x93, 0xd5, 0x10, 0x77, 0x15, 0xc4, 0x15, 0xd5, 0x5b, - 0x23, 0xd8, 0x07, 0x44, 0xfe, 0x4e, 0x21, 0x00, 0x99, 0x80, 0x13, 0x98, 0x2b, 0x38, 0xe8, 0xe5, 0x37, 0x83, 0xd1, - 0x5d, 0x0d, 0xc6, 0x93, 0xdb, 0xc0, 0xc8, 0xd3, 0xd1, 0xa2, 0xbe, 0xae, 0x1d, 0x70, 0x4e, 0x7b, 0x13, 0x86, 0xfc, - 0x14, 0x74, 0xf1, 0xf9, 0x22, 0x1e, 0xf1, 0x89, 0x78, 0x24, 0x76, 0xbe, 0x10, 0x75, 0x3b, 0xed, 0xb6, 0x78, 0x2f, - 0x40, 0xa1, 0x05, 0x1d, 0x1f, 0x1b, 0x00, 0x13, 0x7d, 0xb1, 0xee, 0x23, 0x36, 0xdf, 0xdd, 0xfa, 0xa5, 0x1a, 0x8f, - 0xa9, 0xbc, 0x41, 0xa1, 0x22, 0xd4, 0x37, 0x5b, 0x30, 0xe3, 0x2d, 0xef, 0x77, 0xf4, 0x41, 0xd5, 0xe0, 0x3b, 0x46, - 0x5a, 0x2f, 0xe0, 0x9e, 0x99, 0x0b, 0xd4, 0x4b, 0xfb, 0x18, 0x92, 0x6a, 0xb5, 0x5c, 0xd0, 0x1b, 0x0c, 0x43, 0x48, - 0x74, 0x20, 0xe8, 0xe4, 0x83, 0x82, 0xbe, 0xa9, 0x91, 0xb9, 0x41, 0xe1, 0x64, 0x2e, 0x6c, 0xf9, 0x4c, 0xcb, 0x75, - 0x50, 0xd2, 0xe0, 0x65, 0x7f, 0xc1, 0x64, 0x03, 0x90, 0xde, 0x95, 0xa4, 0xe5, 0xd5, 0xd1, 0x93, 0x72, 0xf9, 0xb2, - 0x21, 0x51, 0x0e, 0x7c, 0x7d, 0x3e, 0x41, 0xbf, 0x5b, 0x7f, 0x28, 0xc6, 0x48, 0xa9, 0xd9, 0xb2, 0xdd, 0x01, 0xd3, - 0x59, 0x59, 0x98, 0x7d, 0xc6, 0x4a, 0x1c, 0xe5, 0x2b, 0xb0, 0xa4, 0x31, 0xf4, 0xfa, 0x73, 0x28, 0xdc, 0x34, 0xe5, - 0xa4, 0x6d, 0xdc, 0x74, 0xfd, 0x1f, 0x56, 0x3c, 0xa6, 0x6c, 0x67, 0x15, 0x1b, 0x07, 0xd7, 0xe5, 0x78, 0x28, 0xae, - 0x1d, 0x16, 0x98, 0x2d, 0xfe, 0xdb, 0x3d, 0x09, 0x47, 0xa3, 0x55, 0x64, 0xf3, 0x7c, 0x48, 0xa1, 0xc1, 0xe5, 0x10, - 0x83, 0x4d, 0x1a, 0xde, 0xf6, 0x98, 0x56, 0x2c, 0xe8, 0x77, 0xd7, 0xbe, 0xaa, 0xc0, 0xe9, 0xd4, 0x45, 0x5c, 0x6a, - 0x90, 0x61, 0x15, 0x05, 0x36, 0xea, 0xca, 0x11, 0x25, 0xd8, 0xd1, 0x85, 0x4f, 0x7f, 0x9e, 0xc6, 0x20, 0x5a, 0x8f, - 0xe3, 0x11, 0x5d, 0x74, 0x89, 0x47, 0x74, 0xf2, 0xd1, 0xa2, 0x4c, 0x27, 0x0c, 0xa5, 0x43, 0x81, 0x24, 0x38, 0x3e, - 0xcb, 0xcc, 0x19, 0xbb, 0x65, 0xe3, 0xe9, 0x85, 0xa1, 0x9b, 0x47, 0xd9, 0x34, 0x8a, 0xd3, 0x00, 0x3f, 0x48, 0xe2, - 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0x5f, 0x45, 0xfb, 0x8e, 0xeb, 0xff, 0x04, 0x82, 0x8b, 0xfa, 0x97, 0xd2, 0xf1, - 0xd3, 0x70, 0xa9, 0x73, 0xe5, 0x7a, 0x29, 0x08, 0x3b, 0xae, 0x8c, 0x64, 0x46, 0x81, 0x95, 0x5d, 0x4e, 0x7f, 0x06, - 0xad, 0x4e, 0xa0, 0xae, 0xfe, 0x9b, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, - 0xf3, 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, - 0x56, 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, - 0x5b, 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xe1, 0x55, 0xa7, 0x7a, 0xd6, 0x96, 0x62, 0xef, 0xe1, - 0xc9, 0xae, 0x10, 0x52, 0x16, 0xb1, 0x6e, 0x68, 0x83, 0xd4, 0xb0, 0xad, 0x3f, 0x0e, 0x81, 0xce, 0x9f, 0x42, 0x7b, - 0x63, 0xe1, 0xa8, 0xbb, 0x00, 0x39, 0xcc, 0xb5, 0x27, 0x14, 0x35, 0x7d, 0x44, 0xc0, 0xee, 0x6f, 0x2c, 0x78, 0xb9, - 0xbb, 0x25, 0x7a, 0xf7, 0x4f, 0xca, 0x82, 0x74, 0xaa, 0x19, 0xfb, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, 0x1c, - 0xe3, 0xb8, 0xb9, 0xb6, 0x13, 0x45, 0x90, 0x5b, 0x32, 0x6e, 0x81, 0x19, 0x56, 0x51, 0x0e, 0x62, 0x44, 0xe7, 0xd0, - 0x14, 0x22, 0x6d, 0xa4, 0xb7, 0x0c, 0xc5, 0x09, 0x42, 0x30, 0xd8, 0x58, 0xc4, 0x65, 0xb8, 0xb1, 0x60, 0xe9, 0x30, - 0x1b, 0xb1, 0x8f, 0x1f, 0x5e, 0xe1, 0x35, 0x89, 0x2c, 0x45, 0x79, 0x9a, 0xb9, 0xe5, 0x09, 0x18, 0x58, 0x08, 0x69, - 0xae, 0xbe, 0x52, 0x03, 0xc0, 0x88, 0x58, 0x91, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, 0x1c, - 0x59, 0x2c, 0x00, 0x13, 0x94, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, 0x9a, - 0x23, 0x1a, 0x15, 0xaa, 0x98, 0x55, 0x64, 0xa2, 0x3b, 0x8a, 0xcf, 0x35, 0x39, 0x29, 0xc5, 0xba, 0xbf, 0x9b, 0x44, - 0xa7, 0x2c, 0x81, 0x21, 0x81, 0xaf, 0xda, 0x30, 0x92, 0x78, 0xb5, 0x76, 0xe3, 0x74, 0x36, 0x97, 0x5f, 0x0b, 0x83, - 0x89, 0x3b, 0x78, 0x80, 0x8b, 0x97, 0x19, 0x06, 0xea, 0x44, 0x32, 0x90, 0x03, 0x00, 0x88, 0x74, 0x18, 0x82, 0xd0, - 0x55, 0xac, 0x02, 0xa5, 0xf1, 0x68, 0xb9, 0x0c, 0xf6, 0xf7, 0x0c, 0x4b, 0x53, 0x78, 0x9e, 0xc6, 0x29, 0x3e, 0x16, - 0xf8, 0x18, 0x5d, 0xe2, 0x63, 0x06, 0x8f, 0x1a, 0xf7, 0xbc, 0xb4, 0xff, 0xaa, 0xab, 0x92, 0xc9, 0x15, 0xb0, 0x34, - 0x01, 0xb2, 0xeb, 0x6b, 0x50, 0x5b, 0x9a, 0x04, 0xbb, 0x5b, 0x40, 0x2c, 0xe4, 0x1e, 0xf1, 0xed, 0x18, 0x66, 0x92, - 0x91, 0x15, 0xb3, 0x96, 0x28, 0xb7, 0xc8, 0x38, 0x08, 0xc1, 0x77, 0xcc, 0x9d, 0x86, 0x0d, 0xe4, 0xc9, 0x2c, 0x99, - 0x67, 0xf8, 0xe2, 0xda, 0x96, 0xf8, 0xb8, 0x87, 0x20, 0x0a, 0x3d, 0x22, 0x86, 0xba, 0x8c, 0xcb, 0xcf, 0xf6, 0xc4, - 0xa1, 0x8d, 0xb3, 0x80, 0x19, 0x8a, 0xca, 0x8c, 0x47, 0x71, 0x22, 0x1a, 0xaf, 0xc0, 0xa7, 0x91, 0xee, 0x48, 0xe8, - 0xec, 0x6e, 0x55, 0xb0, 0x01, 0xf0, 0x4a, 0x22, 0x88, 0x54, 0x4e, 0x5b, 0x94, 0x53, 0x0a, 0x80, 0xdc, 0xe6, 0xd5, - 0x27, 0x9d, 0x80, 0x29, 0xc0, 0x88, 0x1e, 0x1d, 0xd3, 0x6c, 0x83, 0x21, 0x12, 0x0b, 0x67, 0x6c, 0x6c, 0x5d, 0xfb, - 0x2f, 0xff, 0xfc, 0x0f, 0xb6, 0x27, 0x40, 0xcc, 0xc6, 0x63, 0x90, 0x72, 0xd6, 0xba, 0x86, 0xff, 0xeb, 0x1f, 0xff, - 0xef, 0xff, 0xf9, 0xaf, 0xba, 0x6d, 0x0a, 0x4d, 0x4f, 0x02, 0x71, 0xb4, 0xa0, 0x49, 0x4a, 0x29, 0x9e, 0xf6, 0x38, - 0x4a, 0x57, 0x80, 0x74, 0x08, 0x54, 0x9a, 0x31, 0x36, 0xf2, 0x6c, 0x0b, 0x34, 0x81, 0x78, 0x3e, 0x4e, 0xd8, 0x39, - 0x93, 0x1f, 0x96, 0xd1, 0x83, 0xe8, 0xca, 0x21, 0x58, 0x30, 0x5c, 0xde, 0x79, 0x95, 0xdb, 0x40, 0xd1, 0x52, 0x52, - 0xbc, 0x4e, 0x30, 0xcf, 0x36, 0x06, 0x6d, 0xce, 0xd1, 0xae, 0x0f, 0xeb, 0x81, 0x4a, 0xb5, 0x6d, 0x01, 0x2f, 0x99, - 0xbd, 0xab, 0x20, 0x5e, 0x82, 0xeb, 0x34, 0xc7, 0xa6, 0x29, 0x2b, 0x8a, 0x55, 0x60, 0x01, 0x4d, 0x3c, 0xbb, 0x6a, - 0x62, 0xd7, 0x3a, 0x00, 0x00, 0xdd, 0x9d, 0x1d, 0x31, 0x2d, 0x54, 0xb0, 0xf1, 0x18, 0x36, 0x38, 0xea, 0xb6, 0x84, - 0xe3, 0xb1, 0x45, 0xd8, 0xb7, 0xdf, 0x82, 0x2c, 0xb1, 0xc1, 0x3f, 0x74, 0xf5, 0x01, 0x34, 0x4d, 0xaf, 0x84, 0x9d, - 0x31, 0x87, 0xe8, 0x6c, 0x0c, 0xa3, 0x9f, 0x0c, 0xa4, 0xb2, 0xe1, 0xa7, 0x55, 0x8c, 0xb1, 0x96, 0x11, 0xfe, 0xfd, - 0x5f, 0xfe, 0xf1, 0xbf, 0xc1, 0xd8, 0xd4, 0x6f, 0x3d, 0x17, 0x40, 0xab, 0xff, 0x09, 0xad, 0xe6, 0xe9, 0x2d, 0xed, - 0xfe, 0xf2, 0xf7, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x29, 0xe0, 0x13, 0x82, 0x68, 0x88, 0xb6, 0xe9, 0xaf, 0x02, 0xa9, - 0x36, 0xc8, 0xda, 0x99, 0xfe, 0x09, 0xc1, 0x2e, 0x78, 0x36, 0xbb, 0x11, 0x1c, 0x84, 0x7a, 0x98, 0x64, 0x05, 0xd3, - 0xf0, 0x08, 0x7d, 0xf2, 0xeb, 0x00, 0xa2, 0xb9, 0x66, 0xb0, 0x6b, 0x0b, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xd5, 0x38, - 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, - 0xda, 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, - 0x52, 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, - 0x48, 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, - 0x24, 0xd2, 0xba, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, - 0x9f, 0x87, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, - 0x12, 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, - 0x97, 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, - 0x0c, 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, - 0x7f, 0x83, 0x97, 0x1d, 0x2d, 0xec, 0x8d, 0x96, 0x42, 0x41, 0x86, 0x0d, 0x27, 0xc3, 0x46, 0x6a, 0x54, 0xd3, 0xa6, - 0x40, 0xc7, 0x2f, 0x5b, 0x6d, 0x3b, 0x1c, 0x63, 0xf7, 0x9a, 0xf6, 0xe7, 0x52, 0xfb, 0xc7, 0xd2, 0xde, 0x97, 0xda, - 0x1f, 0x3f, 0x69, 0xd3, 0xd0, 0xfe, 0xf1, 0x5a, 0xed, 0x8f, 0x94, 0x1b, 0xe0, 0xc8, 0xa1, 0xbd, 0x89, 0xd1, 0x2d, - 0xc3, 0xd6, 0xe0, 0x68, 0x67, 0x0d, 0x27, 0x6c, 0xf8, 0x49, 0x9a, 0x59, 0x84, 0x00, 0x86, 0x77, 0xb4, 0x31, 0x29, - 0x30, 0x00, 0x93, 0xe1, 0xa4, 0xd4, 0x9b, 0x1e, 0x1f, 0x8d, 0x09, 0xb8, 0xbb, 0x18, 0x33, 0x14, 0xfd, 0xb0, 0x66, - 0x5f, 0xb1, 0x72, 0x0b, 0xc7, 0x11, 0x1b, 0x46, 0x3c, 0x03, 0x66, 0x5b, 0x38, 0xd8, 0x89, 0xb7, 0x10, 0xc1, 0xc2, - 0xc0, 0x7e, 0xff, 0x6e, 0xff, 0xc0, 0xf6, 0x4e, 0xb3, 0xd1, 0x55, 0x60, 0x83, 0x33, 0x06, 0xd6, 0x94, 0xeb, 0xf3, - 0x09, 0x4b, 0x1d, 0xe5, 0xf9, 0x64, 0x09, 0xb8, 0x9a, 0xd9, 0x99, 0xf8, 0xb6, 0x45, 0xf3, 0xa0, 0x03, 0x08, 0x4b, - 0x1f, 0xbf, 0xec, 0xef, 0x72, 0xf1, 0x5d, 0x58, 0x9e, 0xe3, 0x63, 0x1f, 0x53, 0x3d, 0x76, 0xb7, 0xe0, 0x01, 0x5f, - 0xf6, 0x51, 0xef, 0xd1, 0xdb, 0xc6, 0x62, 0xc9, 0x6d, 0x18, 0xe0, 0x10, 0x93, 0xbe, 0x40, 0xa1, 0xa0, 0x56, 0x27, - 0x01, 0x22, 0x06, 0x8f, 0x30, 0xd6, 0x96, 0x1a, 0x17, 0x21, 0x54, 0xfd, 0xb5, 0xe3, 0x52, 0xd9, 0xad, 0x34, 0xef, - 0x08, 0xcd, 0x52, 0x72, 0x5c, 0xb0, 0xf7, 0x48, 0x97, 0x08, 0x53, 0x87, 0x8a, 0xd6, 0x41, 0xa0, 0x6b, 0x2a, 0x73, - 0x45, 0x74, 0x30, 0x80, 0x21, 0x33, 0x57, 0x00, 0x02, 0x7f, 0x09, 0xed, 0x13, 0xf3, 0xfb, 0x6f, 0xe2, 0x53, 0x4d, - 0x9a, 0x38, 0x87, 0x7f, 0xf2, 0xae, 0x98, 0x77, 0x75, 0x42, 0x2d, 0x55, 0xb0, 0x01, 0xa3, 0x60, 0x18, 0x94, 0x69, - 0xab, 0xa8, 0x12, 0xd8, 0x69, 0x49, 0x34, 0x2b, 0x58, 0xa0, 0x1e, 0x64, 0xdc, 0x01, 0xc3, 0x17, 0xcb, 0x81, 0x1e, - 0xd3, 0x9e, 0x2b, 0xf9, 0x64, 0x61, 0x06, 0x26, 0x1e, 0xb5, 0xdb, 0x3d, 0xbc, 0x54, 0xd1, 0x8a, 0xc0, 0x3a, 0x48, - 0x83, 0x84, 0x8d, 0x79, 0xc9, 0xf1, 0xd6, 0xfe, 0x42, 0x45, 0x82, 0xfc, 0xee, 0x4e, 0xce, 0xa6, 0x96, 0x8f, 0xff, - 0xbf, 0x6d, 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, - 0x0d, 0x19, 0x46, 0xc9, 0x4a, 0x9e, 0x83, 0xbc, 0xf7, 0x78, 0x6e, 0xb6, 0x03, 0x39, 0xbd, 0x14, 0x2a, 0x5b, 0x0e, - 0xd6, 0x6c, 0xbb, 0xd2, 0x3f, 0x5a, 0x6e, 0xac, 0x22, 0x5e, 0xf5, 0xb7, 0x25, 0x0a, 0x19, 0xb1, 0xb9, 0x52, 0xa8, - 0xa8, 0x85, 0xe8, 0x61, 0xe2, 0xb4, 0x1c, 0xb5, 0xbb, 0xd5, 0x62, 0x2e, 0x49, 0x5c, 0x1c, 0x92, 0xb8, 0x20, 0xf1, - 0x77, 0xb4, 0x10, 0x73, 0x0f, 0xa3, 0x64, 0xe8, 0x20, 0x00, 0x56, 0xcb, 0x7a, 0x02, 0xd4, 0x74, 0x55, 0xe4, 0xc8, - 0x7f, 0x8c, 0xc4, 0x2d, 0x85, 0xb0, 0x5c, 0x41, 0xa5, 0x93, 0xa3, 0xb2, 0xec, 0x31, 0xe6, 0x1c, 0x7e, 0x90, 0x97, - 0x40, 0xc4, 0xdd, 0x5f, 0xfd, 0xfd, 0xc4, 0x76, 0xe9, 0x1e, 0x79, 0x3f, 0x1b, 0x1f, 0xa5, 0xb3, 0x15, 0xb3, 0xdb, - 0x1e, 0x2c, 0x83, 0xd9, 0x53, 0x7e, 0x42, 0xf2, 0xa6, 0xbe, 0x26, 0x9b, 0x53, 0xff, 0x9f, 0x43, 0x1c, 0xe1, 0x8d, - 0x63, 0xa3, 0x89, 0x4e, 0x23, 0x5f, 0xb5, 0x88, 0x3f, 0x6d, 0xec, 0x2a, 0x8e, 0x40, 0xbe, 0x5e, 0x17, 0xc9, 0xfa, - 0xe6, 0xf6, 0x48, 0x56, 0x71, 0xc7, 0x48, 0xd6, 0x37, 0xbf, 0x73, 0x24, 0xeb, 0x6b, 0x33, 0x92, 0x85, 0x02, 0xfa, - 0xd5, 0xaf, 0x89, 0x36, 0xe5, 0xd9, 0x45, 0x11, 0x76, 0x64, 0xe6, 0x04, 0xc8, 0x3a, 0x0c, 0x3b, 0xfd, 0xf5, 0x23, - 0x4c, 0x30, 0x51, 0x23, 0xbe, 0x44, 0x01, 0x25, 0x91, 0xec, 0x09, 0x6a, 0x45, 0x86, 0x73, 0xda, 0x3a, 0xab, 0xb2, - 0xf5, 0x50, 0x5d, 0x23, 0x03, 0xd7, 0xd7, 0xd5, 0xa1, 0xb6, 0xae, 0x0a, 0xf8, 0x04, 0xf4, 0x1d, 0x58, 0xdd, 0xb1, - 0xbb, 0xa9, 0xd2, 0xf9, 0xcc, 0x11, 0x7a, 0xea, 0x94, 0x46, 0x30, 0xd1, 0xc2, 0xfe, 0x2f, 0x87, 0x9d, 0xde, 0x76, - 0x67, 0x0a, 0xbd, 0x41, 0x81, 0xc3, 0x5b, 0xbb, 0xb7, 0xbd, 0x8d, 0x6f, 0x17, 0xea, 0xad, 0x8b, 0x6f, 0xb1, 0x7a, - 0xdb, 0xc1, 0xb7, 0xa1, 0x7a, 0x7b, 0x84, 0x6f, 0x23, 0xf5, 0xf6, 0x18, 0xdf, 0xce, 0xed, 0xf2, 0x90, 0x6b, 0xe0, - 0x1e, 0x03, 0x5f, 0x91, 0x37, 0x13, 0xa8, 0x32, 0xd8, 0xf4, 0x78, 0xfd, 0x32, 0x3a, 0x0b, 0x62, 0x4f, 0x78, 0x97, - 0x41, 0xee, 0x5d, 0x80, 0xc6, 0x09, 0x28, 0xdb, 0xf0, 0x39, 0x7e, 0x87, 0x03, 0x9c, 0xa4, 0x83, 0x78, 0xca, 0xd4, - 0x07, 0x89, 0x15, 0xd6, 0x60, 0xc0, 0x1e, 0xb6, 0x8f, 0xca, 0x9e, 0x5e, 0x27, 0x11, 0xcf, 0x52, 0xd9, 0x1c, 0xb4, - 0x72, 0x55, 0x9d, 0x98, 0xae, 0xa5, 0x57, 0x78, 0x8d, 0xfe, 0x32, 0xe2, 0x11, 0x63, 0x30, 0xcc, 0x5a, 0x97, 0xe0, - 0xc1, 0xae, 0xd4, 0x69, 0x08, 0x91, 0xd6, 0x69, 0x84, 0x93, 0x7e, 0x3b, 0x88, 0xce, 0xf4, 0xf3, 0x1b, 0xb0, 0xb4, - 0xa3, 0x33, 0xd9, 0x72, 0xbd, 0x0e, 0x23, 0x10, 0x4d, 0xfd, 0xa5, 0x80, 0x20, 0x53, 0x0c, 0x96, 0x06, 0x3d, 0x69, - 0xa9, 0xbf, 0x90, 0x3a, 0x75, 0x8d, 0x46, 0xd3, 0xd7, 0x8b, 0x80, 0xa2, 0x55, 0xc1, 0x2e, 0x18, 0xfc, 0x54, 0x2a, - 0x28, 0x0c, 0x15, 0x58, 0x20, 0xaa, 0xd7, 0xa8, 0x32, 0x1d, 0x6c, 0x58, 0xab, 0xd0, 0x2c, 0xa5, 0xcb, 0xcc, 0xd3, - 0x1d, 0x7d, 0xb4, 0xb3, 0x2c, 0x5e, 0x3f, 0xeb, 0x0c, 0xf1, 0x1f, 0x29, 0xbc, 0x3f, 0x1b, 0x8f, 0xc7, 0x37, 0xea, - 0xb6, 0xcf, 0x46, 0x63, 0xd6, 0x65, 0x3b, 0x3d, 0x8c, 0xfc, 0xb7, 0xa4, 0x38, 0xed, 0x94, 0x44, 0xbb, 0xc5, 0xdd, - 0x1a, 0xa3, 0xe4, 0x05, 0x75, 0x77, 0x77, 0x25, 0x58, 0x02, 0x55, 0x16, 0x20, 0xfc, 0xcf, 0xe2, 0x34, 0x68, 0x97, - 0xfe, 0xb9, 0xd4, 0x1a, 0x9f, 0x3d, 0x79, 0xf2, 0xa4, 0xf4, 0x47, 0xea, 0xad, 0x3d, 0x1a, 0x95, 0xfe, 0x70, 0xa1, - 0xd1, 0x68, 0xb7, 0xc7, 0xe3, 0xd2, 0x8f, 0x55, 0xc1, 0x76, 0x77, 0x38, 0xda, 0xee, 0x96, 0xfe, 0x85, 0xd1, 0xa2, - 0xf4, 0x99, 0x7c, 0xcb, 0xd9, 0xa8, 0x76, 0x7c, 0xf0, 0xb8, 0x0d, 0x95, 0x82, 0xd1, 0x16, 0xe8, 0x5d, 0x8a, 0xc7, - 0x20, 0x9a, 0xf3, 0x0c, 0x0c, 0xbb, 0xb2, 0x57, 0x80, 0x7c, 0x1e, 0x4b, 0x09, 0x2f, 0xbe, 0xf7, 0x8b, 0x52, 0xfd, - 0x95, 0x29, 0xd5, 0x91, 0x99, 0x49, 0x9a, 0x17, 0xa4, 0x0d, 0x9a, 0xd5, 0xc8, 0x59, 0x54, 0xfd, 0x2a, 0x2c, 0x2a, - 0x61, 0x8f, 0xd2, 0x06, 0x5b, 0x0a, 0x19, 0xff, 0xc3, 0x3a, 0x19, 0xff, 0xfd, 0xed, 0x32, 0xfe, 0xf4, 0x6e, 0x22, - 0xfe, 0xfb, 0xdf, 0x59, 0xc4, 0xff, 0x60, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0xc0, 0x74, 0x26, 0x9b, 0xf9, 0x34, 0xbb, - 0x6c, 0xe1, 0x96, 0xc8, 0x6d, 0x92, 0x9e, 0xd3, 0x3b, 0x09, 0xff, 0x15, 0xf9, 0x60, 0x6a, 0x30, 0xe3, 0xe3, 0xc1, - 0x3c, 0x3b, 0x3b, 0x4b, 0x98, 0x92, 0xf1, 0x46, 0x05, 0x99, 0xe3, 0xef, 0xd2, 0xd0, 0x7e, 0x07, 0x9e, 0xb1, 0x51, - 0x32, 0x1e, 0x43, 0xd1, 0x78, 0x6c, 0xab, 0x7c, 0x69, 0x90, 0x67, 0xd4, 0xea, 0x6d, 0xad, 0x84, 0x5a, 0x7d, 0xf1, - 0x85, 0x59, 0x66, 0x16, 0xc8, 0x90, 0x9e, 0x69, 0x8c, 0xc8, 0x9a, 0x51, 0x5c, 0xe0, 0x1e, 0xac, 0x3e, 0x76, 0x8c, - 0xf6, 0xce, 0x14, 0x94, 0x4a, 0x3c, 0xc4, 0x73, 0x91, 0xe6, 0x87, 0x65, 0x44, 0x6e, 0xfb, 0x32, 0x72, 0xd5, 0xf9, - 0xb7, 0xf1, 0x0d, 0xc3, 0xea, 0xcc, 0x1b, 0x16, 0x5f, 0xe6, 0xb7, 0x3c, 0xbd, 0x7a, 0x35, 0x72, 0xf6, 0xc0, 0x1a, - 0x8e, 0x8b, 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, - 0xec, 0x19, 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, - 0x92, 0x6e, 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xe2, 0x79, 0x88, - 0x98, 0x61, 0x54, 0xaa, 0x33, 0x10, 0x20, 0xdc, 0x0c, 0x3f, 0xd1, 0x24, 0x86, 0x50, 0x07, 0x05, 0x15, 0xf5, 0xae, - 0xaf, 0xcd, 0x2f, 0x85, 0xd6, 0xbe, 0x2a, 0xd9, 0xe0, 0x01, 0x86, 0x9f, 0xf8, 0x45, 0x6d, 0x90, 0xcd, 0xb9, 0xe3, - 0x50, 0x2b, 0xc7, 0x2d, 0xbd, 0x9d, 0x76, 0x1b, 0x54, 0x8c, 0x2f, 0xbe, 0x03, 0xe5, 0xe8, 0xce, 0x12, 0xdf, 0x75, - 0xe7, 0x12, 0x4b, 0xdf, 0x65, 0xd3, 0x24, 0xc6, 0x0f, 0xc7, 0x08, 0x44, 0x8d, 0xbb, 0x43, 0x6a, 0x11, 0x9b, 0xef, - 0xbe, 0xf2, 0x1d, 0x0d, 0xc2, 0xba, 0xab, 0x38, 0x58, 0xe6, 0xd6, 0xd6, 0x0b, 0xb1, 0xad, 0xb0, 0x6a, 0x96, 0xc1, - 0xb9, 0x45, 0x67, 0x16, 0x17, 0x46, 0x00, 0xbf, 0xb6, 0x0d, 0x4a, 0x15, 0xc1, 0x17, 0x61, 0xf8, 0x3d, 0x0c, 0x36, - 0x0b, 0xc7, 0x5b, 0x01, 0x5d, 0x77, 0x79, 0x0d, 0xc8, 0xd1, 0x19, 0xd6, 0x8c, 0xae, 0xaa, 0x54, 0x41, 0x69, 0x1e, - 0xc1, 0x18, 0xc8, 0x50, 0x24, 0x1d, 0xd6, 0x38, 0x15, 0x7a, 0x0b, 0xa6, 0x21, 0x01, 0xac, 0xfd, 0x3a, 0x74, 0x6b, - 0x6c, 0x05, 0xb6, 0x90, 0x16, 0xa0, 0xf4, 0xb0, 0x43, 0xdf, 0xaa, 0x81, 0x9e, 0x2e, 0x07, 0xe0, 0x6f, 0x74, 0xf2, - 0x4e, 0xfc, 0xe2, 0xc2, 0x83, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, - 0x86, 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, - 0x41, 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, - 0xdf, 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, - 0xd5, 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0xff, 0x8c, 0xcc, 0x85, 0x66, 0x31, 0x1d, 0xc0, 0xdf, - 0x05, 0xb2, 0x20, 0x1a, 0xe3, 0x17, 0x16, 0xef, 0xd2, 0xf2, 0x94, 0xb2, 0x5f, 0x17, 0xa8, 0xd6, 0x83, 0xce, 0x13, - 0xf0, 0xf6, 0xee, 0x3c, 0xfc, 0xcd, 0xe8, 0x97, 0x92, 0x46, 0xea, 0x12, 0xb3, 0x6d, 0xf7, 0x50, 0x5e, 0x24, 0xd1, - 0x15, 0x38, 0x9d, 0x64, 0x63, 0x9c, 0x62, 0xf4, 0xb8, 0x37, 0xcb, 0x64, 0x26, 0x49, 0xce, 0x12, 0xfa, 0x19, 0x13, - 0xb9, 0x14, 0xdb, 0x8f, 0x66, 0x97, 0x6a, 0x35, 0x3a, 0x8d, 0x0c, 0x91, 0xdf, 0x35, 0x11, 0x64, 0x7d, 0xe6, 0x49, - 0x3d, 0x99, 0x61, 0x07, 0x60, 0x10, 0x86, 0x4d, 0x2b, 0x17, 0x50, 0xb5, 0xa1, 0xc4, 0x48, 0x85, 0xa9, 0x06, 0xb2, - 0xfc, 0x6d, 0x50, 0x95, 0x51, 0xc1, 0x7a, 0xf8, 0xa9, 0xcb, 0x18, 0x5c, 0x5b, 0x69, 0x3c, 0x4d, 0xe3, 0xd1, 0x28, - 0x61, 0x3d, 0x65, 0x1f, 0x59, 0x9d, 0x47, 0x98, 0x49, 0x62, 0x2e, 0x59, 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, - 0xa7, 0x60, 0xaf, 0xe1, 0xf7, 0x2a, 0x57, 0x92, 0x53, 0xa6, 0x58, 0xb4, 0x2b, 0xe2, 0xd1, 0x73, 0x1d, 0x97, 0x1d, - 0x30, 0x16, 0x69, 0xc1, 0xdb, 0x3d, 0x9e, 0xcd, 0x82, 0xd6, 0x76, 0x1d, 0x11, 0xac, 0xd2, 0x28, 0x78, 0x2b, 0xd0, - 0xf2, 0xd0, 0x3a, 0x10, 0x5a, 0xce, 0xf2, 0x3b, 0xb2, 0x8c, 0x06, 0xc0, 0x6f, 0x22, 0xea, 0xa2, 0xb2, 0x8e, 0xcc, - 0x5f, 0x67, 0xb7, 0x7c, 0xbe, 0x7a, 0xb7, 0x7c, 0xae, 0x76, 0xcb, 0xcd, 0x1c, 0xfb, 0xd9, 0xb8, 0x83, 0xff, 0xf4, - 0x2a, 0x84, 0x60, 0x55, 0x80, 0x1c, 0x16, 0xda, 0xc5, 0xad, 0x2e, 0xfc, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x8f, 0x0f, - 0x16, 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xaf, 0x5d, 0xab, 0xea, 0x3c, 0xc4, 0x3a, 0xec, 0xb5, 0xb3, 0x5c, 0xd7, 0xbd, - 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0xb8, 0x6a, 0xd1, 0xe9, 0x29, 0x94, 0x8e, 0xb3, 0xe1, 0xbc, - 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0xba, 0x31, 0x8e, 0xea, 0x2a, 0xd2, 0x92, 0xd4, 0x08, 0x0b, 0xbd, - 0x4e, 0x41, 0x01, 0x8c, 0xc9, 0x9c, 0xae, 0xff, 0x70, 0xc5, 0x26, 0xf8, 0xff, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0x8f, - 0x12, 0xe3, 0x46, 0x22, 0xfc, 0x2a, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb2, 0x1a, 0xdc, 0x43, 0x35, 0xd3, 0x91, 0x52, - 0x0a, 0x52, 0xef, 0x80, 0x17, 0x10, 0xcd, 0x13, 0x7e, 0xf3, 0xa8, 0xeb, 0x38, 0x63, 0x69, 0xd4, 0x1b, 0x04, 0x7a, - 0xd5, 0xf6, 0x8e, 0x52, 0xfa, 0xb3, 0xcf, 0x1f, 0xe2, 0x3f, 0x22, 0x70, 0x76, 0x5a, 0xf9, 0x46, 0x22, 0x36, 0x80, - 0xbe, 0xd1, 0xb4, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x5d, 0x5b, 0xa3, 0xb1, 0x7e, 0xa7, 0xe6, 0xd2, 0x2a, - 0xfd, 0x55, 0xad, 0x7f, 0xdd, 0xe0, 0x77, 0x6c, 0x3b, 0x14, 0x0e, 0x41, 0xbd, 0xad, 0x8c, 0x07, 0x2e, 0x35, 0x56, - 0x14, 0xbf, 0x6b, 0xfb, 0xca, 0x24, 0xa6, 0x1e, 0xd3, 0xf0, 0x54, 0x3b, 0x91, 0xf2, 0xf0, 0x1e, 0x7b, 0x08, 0x3f, - 0xf2, 0x4b, 0x16, 0x3e, 0xc0, 0xaf, 0xb1, 0x59, 0x97, 0xd3, 0x24, 0x05, 0xb3, 0x6a, 0xc2, 0xf9, 0x2c, 0xd8, 0xda, - 0xba, 0xb8, 0xb8, 0xf0, 0x2f, 0xb6, 0xfd, 0x2c, 0x3f, 0xdb, 0xea, 0xb6, 0xdb, 0x6d, 0xfc, 0x88, 0x96, 0x6d, 0x9d, - 0xc7, 0xec, 0xe2, 0x29, 0xb8, 0x1f, 0xf6, 0x63, 0xeb, 0x89, 0xf5, 0x78, 0xdb, 0xda, 0x79, 0x64, 0x5b, 0xa4, 0x00, - 0xa0, 0x64, 0xdb, 0xb6, 0x84, 0x02, 0x08, 0x6d, 0x28, 0xee, 0xef, 0x9e, 0x29, 0x1b, 0x0e, 0x2f, 0x29, 0x08, 0x0b, - 0x09, 0xfc, 0xb7, 0xec, 0x13, 0xab, 0x6f, 0x75, 0x51, 0xd6, 0x92, 0x6a, 0x44, 0xbd, 0xe2, 0x7e, 0x1f, 0x46, 0xb3, - 0x80, 0xd8, 0xc8, 0x2c, 0xc4, 0x30, 0x99, 0x28, 0xa5, 0x29, 0xd0, 0x2e, 0x3d, 0x85, 0x27, 0xcc, 0x6a, 0xb3, 0xe0, - 0xf9, 0x4d, 0xf7, 0x31, 0xe8, 0xb8, 0xf3, 0xd6, 0xc3, 0x61, 0xbb, 0xd5, 0xb1, 0x3a, 0xad, 0xae, 0xff, 0xd8, 0xea, - 0x8a, 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, - 0xfd, 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, - 0xb8, 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, - 0xd0, 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, - 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0xef, 0x7c, 0xfb, - 0xc9, 0x10, 0x34, 0x82, 0x85, 0xff, 0xc1, 0x3f, 0x93, 0x9d, 0xee, 0x50, 0xbc, 0xb4, 0xb1, 0xfe, 0xdb, 0xce, 0xe3, - 0x02, 0x9a, 0xe2, 0x3f, 0xbf, 0x68, 0x13, 0x1a, 0x0d, 0x78, 0x73, 0xdc, 0x87, 0x40, 0xa3, 0x27, 0x93, 0xae, 0xff, - 0xf9, 0xf9, 0x63, 0xff, 0xc9, 0xa4, 0xf3, 0xf8, 0x5b, 0xf1, 0x96, 0x00, 0x05, 0x3f, 0xc7, 0xff, 0xbe, 0xdd, 0x6e, - 0x4f, 0x5a, 0x1d, 0xff, 0xc9, 0xf9, 0xb6, 0xbf, 0x9d, 0xb4, 0x1e, 0xf9, 0x4f, 0xf0, 0xbf, 0x6a, 0xb8, 0x49, 0x36, - 0x65, 0xb6, 0x85, 0xeb, 0xdd, 0xf0, 0x7b, 0xcd, 0x39, 0xba, 0x0f, 0xad, 0x9d, 0x87, 0x2f, 0x9f, 0xc0, 0x1a, 0x4d, - 0x3a, 0x5d, 0xf8, 0xff, 0xba, 0xc7, 0x6f, 0x91, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x7a, 0xb1, 0x22, 0x1c, 0x7d, 0xd0, - 0xed, 0x81, 0xf7, 0xa7, 0x75, 0x01, 0x10, 0xc6, 0x6f, 0x0d, 0x80, 0x70, 0x7e, 0xb7, 0x08, 0x08, 0xfd, 0xda, 0xc0, - 0xef, 0x18, 0x01, 0xf9, 0x53, 0x33, 0xc8, 0x7d, 0xc9, 0x96, 0x02, 0x1d, 0x4d, 0x67, 0xed, 0x2d, 0x73, 0x0e, 0xbf, - 0x64, 0x47, 0x98, 0x4a, 0x0f, 0xad, 0x39, 0x37, 0xe3, 0x41, 0x19, 0x6e, 0xe4, 0x4b, 0x26, 0x76, 0x72, 0xc1, 0xd7, - 0x10, 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, - 0x29, 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, - 0xd3, 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, - 0x34, 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, - 0xa6, 0xdf, 0xcf, 0x8a, 0x79, 0x82, 0x97, 0xa6, 0xbd, 0xa1, 0xf8, 0x80, 0x2c, 0x3c, 0xca, 0xbb, 0x86, 0x98, 0xc2, - 0xfe, 0x0d, 0xa6, 0xdf, 0xab, 0xb3, 0x83, 0x29, 0xc6, 0x11, 0xde, 0xb0, 0x51, 0x1c, 0x39, 0xb6, 0x33, 0x83, 0x8d, - 0x0c, 0xb3, 0xb4, 0x6a, 0xb9, 0xef, 0x94, 0xf6, 0xee, 0xda, 0xea, 0xa7, 0x99, 0x72, 0xfc, 0xd4, 0x5d, 0x78, 0x28, - 0xe3, 0x8e, 0xb6, 0x74, 0x0c, 0x60, 0x7c, 0x55, 0x92, 0xa3, 0x0e, 0xa8, 0x8c, 0x09, 0x5b, 0x58, 0x13, 0x1d, 0xbf, - 0x0b, 0xde, 0x05, 0x15, 0xe3, 0xa7, 0xc3, 0xbe, 0x77, 0x5a, 0xdb, 0x60, 0xed, 0x18, 0xdd, 0xf4, 0x40, 0x47, 0xfa, - 0x97, 0x7e, 0xf4, 0xaf, 0xd1, 0xd5, 0x2f, 0x0c, 0xd8, 0x82, 0x23, 0x3e, 0x13, 0xb8, 0xdb, 0xf4, 0x89, 0x06, 0x99, - 0x50, 0x82, 0x17, 0xe6, 0xa0, 0xcc, 0x31, 0x7f, 0x95, 0x4c, 0x7c, 0x9a, 0x4c, 0xfc, 0x00, 0x61, 0x59, 0x35, 0x61, - 0xd5, 0xcf, 0x7f, 0x20, 0x05, 0x99, 0xa7, 0x67, 0x23, 0xea, 0x61, 0x86, 0x07, 0xfe, 0xad, 0x8a, 0xd5, 0x83, 0x8c, - 0x58, 0x81, 0x17, 0x8f, 0xbf, 0xe9, 0x42, 0x7f, 0x96, 0xe2, 0x61, 0x22, 0xca, 0xd1, 0x28, 0xad, 0x86, 0xaa, 0xe2, - 0x5e, 0xc5, 0xd3, 0xab, 0x03, 0xf9, 0x41, 0x03, 0x1b, 0x43, 0xd0, 0x74, 0xf4, 0x50, 0x7d, 0x4c, 0x6d, 0x13, 0xf4, - 0x1e, 0xfd, 0xc4, 0x29, 0x65, 0x0f, 0xa0, 0x6a, 0xc3, 0xfb, 0x04, 0x96, 0x74, 0x81, 0x42, 0x5b, 0x28, 0xb6, 0x11, - 0x3b, 0x8f, 0x87, 0x52, 0x3f, 0x79, 0x96, 0xbc, 0x07, 0xd5, 0x22, 0xba, 0x87, 0x1d, 0x4f, 0x04, 0x01, 0xe0, 0x05, - 0xd5, 0x73, 0x98, 0x66, 0x76, 0xff, 0x41, 0x6f, 0x1d, 0x65, 0xf1, 0xf7, 0x56, 0x0f, 0xc1, 0xe9, 0xfc, 0xdb, 0xf0, - 0x01, 0xfe, 0xe2, 0xea, 0x83, 0x23, 0xdb, 0xf5, 0x49, 0xba, 0x3f, 0xa8, 0x7e, 0x76, 0x15, 0x45, 0xdb, 0x26, 0x28, - 0x62, 0xef, 0xae, 0x1a, 0x59, 0x6a, 0xdf, 0xee, 0x4e, 0xa5, 0x7d, 0xe1, 0xd9, 0x10, 0xb7, 0xa0, 0x09, 0xba, 0xfe, - 0x8e, 0x21, 0xd3, 0xcf, 0x5b, 0xf8, 0xb7, 0x26, 0xd5, 0x1f, 0x42, 0x03, 0x25, 0xd6, 0x5f, 0x43, 0xf3, 0x6d, 0xa1, - 0x41, 0xa0, 0xdf, 0x0f, 0x24, 0x73, 0x85, 0xbc, 0xad, 0xf3, 0xf8, 0x8a, 0xd3, 0x30, 0x91, 0x69, 0x61, 0x7b, 0x46, - 0xe0, 0x4c, 0x6c, 0x39, 0x19, 0x16, 0x7a, 0x0e, 0x7d, 0x1d, 0xfd, 0x8d, 0xf2, 0x55, 0x75, 0x5e, 0x4d, 0x04, 0xac, - 0x98, 0x02, 0x37, 0x6d, 0xe3, 0xc4, 0xad, 0x27, 0x92, 0xb8, 0xf5, 0x47, 0x4e, 0xd6, 0x73, 0xab, 0xcc, 0xf6, 0x76, - 0x8d, 0xfd, 0xcf, 0xe9, 0x3b, 0xaa, 0x34, 0xc9, 0xab, 0x51, 0xd9, 0x9c, 0x1f, 0x6c, 0x16, 0xfc, 0xd1, 0xc9, 0xea, - 0x0a, 0x8f, 0xbc, 0x9b, 0x8b, 0xf9, 0x14, 0xa3, 0x38, 0xa7, 0x2b, 0xdf, 0x0a, 0xf4, 0x5a, 0x54, 0xb5, 0xa2, 0x12, - 0x89, 0x00, 0x56, 0x0c, 0x6c, 0x2c, 0xb2, 0x03, 0x99, 0xf5, 0x67, 0x7e, 0x48, 0xdc, 0xbc, 0x93, 0x3b, 0x12, 0x09, - 0x7f, 0xf8, 0x43, 0x0b, 0xb6, 0xa0, 0x8f, 0x0d, 0xa2, 0x74, 0xed, 0x2e, 0x21, 0x03, 0x0b, 0x71, 0xad, 0x7e, 0x39, - 0xcb, 0x94, 0x2e, 0xb6, 0x49, 0x68, 0x3d, 0x2e, 0x91, 0xd0, 0x95, 0x74, 0x3a, 0x65, 0x11, 0xf7, 0xa3, 0x94, 0x92, - 0xb3, 0x1c, 0x43, 0x06, 0x79, 0x1d, 0xb6, 0xed, 0x96, 0x20, 0xf8, 0x8c, 0x9f, 0x16, 0x13, 0x9b, 0xd9, 0x87, 0x42, - 0xfd, 0x59, 0xab, 0x7a, 0xa2, 0xf5, 0xa4, 0xdb, 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, - 0xe4, 0x9e, 0x8b, 0x3c, 0x95, 0x50, 0xe4, 0xa9, 0x58, 0x22, 0xbb, 0x4d, 0x24, 0x26, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, - 0xa5, 0x43, 0x11, 0x57, 0x9c, 0x82, 0x0b, 0x13, 0xe3, 0xc7, 0xe7, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x29, - 0x3f, 0xca, 0x68, 0xe1, 0xa9, 0x8a, 0x42, 0x82, 0xa9, 0xc1, 0x54, 0xf6, 0x8f, 0x1c, 0x4a, 0x27, 0x1d, 0x2f, 0xb7, - 0x2e, 0xe6, 0xa7, 0x53, 0x10, 0x82, 0x2a, 0x63, 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x26, - 0x55, 0x1f, 0x06, 0x6f, 0xfc, 0x88, 0xaa, 0xc0, 0x5e, 0x0a, 0x7d, 0x4c, 0x38, 0x99, 0x6c, 0x1b, 0x09, 0x27, 0x46, - 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x83, 0xac, 0xa2, 0x3d, 0x28, 0x94, - 0x01, 0x25, 0x8f, 0x8b, 0x4b, 0x1b, 0x12, 0x60, 0x58, 0x41, 0x80, 0x49, 0xea, 0x77, 0x8b, 0xce, 0xb5, 0xed, 0x9d, - 0xb6, 0xca, 0xc9, 0x85, 0x32, 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0xb6, 0x3b, 0xe9, 0xf4, 0x77, 0x23, 0x69, - 0x39, 0xa2, 0xf0, 0x28, 0x40, 0x7a, 0x40, 0x67, 0x34, 0xcf, 0xfc, 0x38, 0xdb, 0xba, 0x60, 0xa7, 0xad, 0x68, 0x16, - 0x57, 0x81, 0x54, 0xb4, 0x23, 0xf4, 0x94, 0x59, 0x35, 0x13, 0x3e, 0x46, 0x0d, 0x24, 0x49, 0x70, 0x97, 0x32, 0x4a, - 0x4b, 0xe6, 0x37, 0xb0, 0x10, 0x50, 0x98, 0xe4, 0xba, 0x8a, 0xe6, 0x4a, 0x75, 0x5a, 0xda, 0xfd, 0xbf, 0xfc, 0xf3, - 0xff, 0x96, 0x01, 0x5a, 0xa0, 0x4a, 0x47, 0x8d, 0xd5, 0x20, 0x74, 0xb9, 0x8b, 0xf9, 0x4d, 0xd5, 0x11, 0x2e, 0xbb, - 0x04, 0x4f, 0x3f, 0x1e, 0xb5, 0x26, 0x51, 0x32, 0x06, 0xc0, 0xd6, 0x12, 0xc8, 0xcc, 0x7e, 0x90, 0x50, 0xd7, 0x8b, - 0x90, 0x05, 0x7f, 0x53, 0x96, 0xb5, 0xca, 0x6e, 0xa7, 0xdd, 0x6a, 0xe4, 0x5c, 0x1b, 0x1b, 0xaa, 0x96, 0x77, 0xad, - 0x7e, 0x95, 0x4c, 0x0a, 0x35, 0x56, 0x4b, 0xba, 0x86, 0x96, 0xfa, 0xa4, 0xe9, 0xdf, 0xff, 0xe5, 0x1f, 0xfe, 0x87, - 0x7a, 0xc5, 0x03, 0xa4, 0xbf, 0xfc, 0xd3, 0xdf, 0x61, 0x7e, 0xb3, 0xa5, 0x0f, 0x99, 0x48, 0x4e, 0x58, 0xd5, 0x09, - 0x93, 0x10, 0x18, 0x56, 0xe5, 0xd1, 0xd5, 0x93, 0xb3, 0xf7, 0x69, 0x42, 0xda, 0x6c, 0x12, 0x3a, 0xda, 0xb4, 0x65, - 0xc5, 0x23, 0x35, 0x92, 0x13, 0x2f, 0x42, 0x25, 0xd2, 0xfb, 0x4e, 0x99, 0x4f, 0xbe, 0x5e, 0x8d, 0x85, 0x0a, 0xff, - 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x97, 0x5f, 0xe0, 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0xf1, 0x6a, 0x7d, 0x7a, 0x3f, - 0xcd, 0x01, 0xfe, 0x31, 0x52, 0x5c, 0x04, 0x19, 0xe9, 0xcc, 0xb9, 0x85, 0x06, 0x5d, 0x72, 0x55, 0xd2, 0x28, 0xc2, - 0x0b, 0x7c, 0xf8, 0xe4, 0x6f, 0xca, 0x3f, 0x4e, 0xd1, 0x6c, 0xb2, 0x9c, 0x69, 0x74, 0x29, 0x7d, 0xc3, 0x47, 0xed, - 0xf6, 0xec, 0xd2, 0x5d, 0x54, 0x33, 0x78, 0xeb, 0x26, 0xa3, 0xc0, 0xa4, 0x39, 0x20, 0x1d, 0x56, 0xeb, 0x18, 0x28, - 0xb8, 0x43, 0x6d, 0x0c, 0x99, 0x95, 0xe5, 0x1f, 0x16, 0x14, 0x86, 0x8b, 0x7f, 0xc1, 0x43, 0x65, 0x19, 0xb1, 0x84, - 0x12, 0x03, 0x8b, 0x85, 0xd1, 0xab, 0x2b, 0x7a, 0x4d, 0x3a, 0xcb, 0x39, 0x41, 0xe6, 0xa1, 0xb8, 0x79, 0x9c, 0xfd, - 0x10, 0x0f, 0xa8, 0x27, 0x1d, 0x6f, 0xd2, 0x5d, 0xe8, 0xe1, 0x39, 0xcf, 0xa6, 0xe6, 0x29, 0x38, 0x8b, 0xd8, 0x90, - 0x8d, 0x55, 0xa4, 0x57, 0xd6, 0x8b, 0x13, 0xee, 0x72, 0xb2, 0xbd, 0x62, 0x2e, 0x09, 0x12, 0x9d, 0x7e, 0x03, 0x3c, - 0x9f, 0xe1, 0x06, 0x04, 0xfa, 0x67, 0x11, 0x0f, 0x88, 0x5f, 0x7b, 0xe6, 0x59, 0x7a, 0x84, 0x52, 0x26, 0x5b, 0x18, - 0xf0, 0xf4, 0x44, 0x53, 0x8c, 0xb9, 0xd6, 0x73, 0xb2, 0x4a, 0x9f, 0xba, 0x9b, 0x43, 0x89, 0x90, 0xcd, 0xb7, 0xf2, - 0x88, 0xfa, 0x69, 0x2d, 0xd6, 0x21, 0x55, 0x4c, 0xd7, 0xf5, 0x56, 0xd6, 0x0b, 0x4d, 0x2d, 0x6a, 0xbf, 0x05, 0x03, - 0x8c, 0xc0, 0xb4, 0x9b, 0xad, 0xa8, 0x10, 0x5b, 0x3d, 0x0d, 0xbf, 0xd5, 0x7e, 0x4d, 0x34, 0x9b, 0x51, 0x43, 0x17, - 0x98, 0x98, 0xac, 0x51, 0x94, 0x1d, 0x94, 0x7e, 0x21, 0xb2, 0x1d, 0x64, 0x1b, 0xb9, 0x11, 0xc4, 0x93, 0xcc, 0x83, - 0xa0, 0xdf, 0xb7, 0xff, 0x7f, 0x47, 0x48, 0x09, 0x5d, 0xf5, 0x7e, 0x00, 0x00}; + 0xd9, 0xf4, 0x58, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, + 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0x60, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, + 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xde, 0x6b, 0xb2, 0x81, 0xd3, 0x28, 0x09, 0x0d, 0x71, 0x65, 0xe2, 0xad, 0x24, 0x74, + 0x6d, 0xa3, 0x80, 0x43, 0xb6, 0xc4, 0xf6, 0xcd, 0x85, 0x6e, 0x72, 0xbb, 0x64, 0x0f, 0xe5, 0x3f, 0x55, 0x5c, 0xb2, + 0x9e, 0xe5, 0x98, 0x92, 0x06, 0x4c, 0x31, 0x1e, 0x2c, 0x4d, 0x03, 0x12, 0xe0, 0xbb, 0x72, 0x14, 0x17, 0xeb, 0x49, + 0xf0, 0xbb, 0x82, 0xf9, 0xdc, 0x98, 0xe9, 0x56, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, + 0xd4, 0x7c, 0x8d, 0x86, 0x0a, 0x71, 0xfc, 0x99, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, + 0x2c, 0x5a, 0xa4, 0x4c, 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, + 0xdc, 0x34, 0xd4, 0xc2, 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, + 0xfb, 0x86, 0x0f, 0x65, 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, + 0x74, 0x41, 0xa0, 0x48, 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, + 0x4a, 0x33, 0x2f, 0x75, 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x31, 0x41, 0x99, 0xd8, 0xbb, 0x89, 0x36, 0x5e, 0x1a, + 0x66, 0xc2, 0xfa, 0x15, 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, + 0xb0, 0xa7, 0x00, 0x94, 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x11, 0x1d, 0x2b, 0x11, 0x5a, + 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, + 0x25, 0x83, 0x84, 0x1c, 0xd2, 0x65, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x1e, 0x85, 0x11, 0x8a, + 0x0d, 0xb1, 0x16, 0x4b, 0x84, 0x6c, 0xda, 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0xe6, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, + 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x9e, 0x00, 0x3f, 0x48, + 0x83, 0x17, 0xd6, 0x6c, 0xa0, 0x64, 0xef, 0xde, 0x6b, 0x6c, 0x45, 0xf6, 0x67, 0x55, 0x52, 0x79, 0x0a, 0x35, 0xce, + 0xad, 0xaf, 0x53, 0x2d, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, + 0x76, 0x5d, 0x37, 0xc8, 0xc9, 0x79, 0xb9, 0xb7, 0xca, 0x85, 0xbc, 0x7f, 0xdf, 0xf4, 0x99, 0xce, 0xf5, 0xf0, 0xcf, + 0x1c, 0x54, 0xce, 0xc5, 0x55, 0x4a, 0x16, 0xcc, 0x33, 0xa5, 0x8e, 0x96, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, + 0x22, 0x8a, 0xb9, 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, + 0xda, 0xa2, 0xc5, 0x70, 0xc2, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x43, 0xbc, 0xe5, 0xc0, 0xab, 0x61, + 0x2f, 0x9b, 0xdd, 0x6b, 0xe6, 0x3f, 0xac, 0x11, 0xc8, 0xb6, 0xa9, 0xaa, 0x2b, 0x1b, 0xef, 0x52, 0x44, 0x62, 0x84, + 0x6d, 0xd5, 0xd8, 0xd2, 0xd6, 0xef, 0x35, 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x86, 0x1e, 0x56, 0x6e, 0x0e, + 0x37, 0x1d, 0x79, 0xb1, 0x82, 0x6e, 0x4f, 0x04, 0x85, 0xc0, 0x89, 0x50, 0xf6, 0xa0, 0xe6, 0x06, 0x22, 0x25, 0x53, + 0x5a, 0x35, 0x9b, 0x27, 0x23, 0x09, 0x2c, 0xb8, 0xb0, 0x4c, 0xf2, 0xd1, 0x45, 0x9c, 0x24, 0x55, 0xe9, 0xef, 0x2a, + 0xe0, 0xc5, 0xb0, 0xb7, 0x89, 0x76, 0x81, 0xd1, 0x5c, 0x81, 0xe0, 0x6a, 0x23, 0xec, 0xa3, 0xe3, 0x56, 0xeb, 0x2e, + 0x22, 0x8e, 0xcc, 0x8c, 0x46, 0x7c, 0x44, 0x1b, 0xb2, 0x64, 0x9a, 0xb5, 0xf7, 0x5e, 0x60, 0x48, 0xcd, 0xc0, 0x07, + 0xd5, 0x19, 0x15, 0xff, 0x2a, 0x7b, 0xea, 0x57, 0xa2, 0x77, 0xab, 0xea, 0x6a, 0x06, 0x54, 0x54, 0xe0, 0xc3, 0x0c, + 0xb1, 0xb4, 0x55, 0x20, 0x20, 0xd7, 0xc3, 0x3a, 0xdc, 0xad, 0x91, 0x06, 0x0b, 0x4a, 0x81, 0xb5, 0x56, 0x76, 0xaf, + 0x6f, 0x0b, 0xe6, 0x50, 0x28, 0x5c, 0xf4, 0x7f, 0x96, 0x4d, 0x67, 0x68, 0x99, 0x35, 0x98, 0x1a, 0x1a, 0x7c, 0x6c, + 0xd4, 0x97, 0x2b, 0xca, 0x6a, 0x7d, 0x68, 0x47, 0xd6, 0xf8, 0x49, 0x3b, 0xca, 0xe0, 0x50, 0xcd, 0x75, 0x51, 0xdd, + 0x6e, 0x6e, 0x8a, 0x98, 0x55, 0x3c, 0xee, 0x93, 0xde, 0xd6, 0xd6, 0xa4, 0xa7, 0x69, 0x40, 0x32, 0x49, 0x32, 0xbc, + 0xc9, 0x00, 0x65, 0x45, 0x9c, 0x45, 0xd9, 0x20, 0xdf, 0xa2, 0x2c, 0x71, 0xfd, 0x7e, 0xe8, 0xed, 0xd5, 0x3c, 0x6b, + 0x6f, 0x6f, 0xbd, 0x8b, 0x5c, 0xd5, 0x49, 0x0f, 0xf2, 0xf0, 0x08, 0x8a, 0x96, 0x6c, 0xca, 0x70, 0x31, 0xcd, 0x46, + 0x2c, 0xb0, 0xa1, 0x7b, 0x6a, 0x97, 0x72, 0xd3, 0x44, 0xc0, 0x3d, 0x11, 0x73, 0x16, 0x1f, 0xea, 0x91, 0xd4, 0x60, + 0x0f, 0x58, 0x40, 0x9b, 0x0b, 0x5f, 0x85, 0x67, 0x49, 0x76, 0x1a, 0x25, 0x07, 0x42, 0x81, 0xd7, 0x5a, 0x7e, 0x0b, + 0x2e, 0x23, 0x59, 0xac, 0x86, 0x92, 0xfa, 0x6a, 0xf0, 0x55, 0x70, 0x7b, 0x8f, 0xca, 0x5b, 0xb1, 0x3b, 0x7e, 0xdb, + 0xef, 0xd8, 0x2a, 0x22, 0xf6, 0x93, 0x39, 0x1d, 0x68, 0x9c, 0x02, 0x28, 0x73, 0x00, 0x9a, 0xac, 0xf0, 0x86, 0x2c, + 0xfc, 0x69, 0xf0, 0x93, 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, + 0x88, 0x0a, 0x8c, 0x2b, 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0x77, 0x1c, 0x9e, 0x40, 0xb3, 0x8d, 0x8d, 0x85, 0xf3, + 0x26, 0xe2, 0x13, 0x3f, 0x8f, 0xd2, 0x51, 0x36, 0x75, 0xdc, 0x4d, 0xdb, 0x76, 0xfd, 0x82, 0x3c, 0x91, 0xcf, 0xdd, + 0x72, 0xe3, 0x04, 0xfc, 0x80, 0xd0, 0x1e, 0xd8, 0x9b, 0xc7, 0xde, 0x01, 0x0b, 0x4f, 0x76, 0x37, 0x16, 0x23, 0x56, + 0xf6, 0x4f, 0xbc, 0x4b, 0x1d, 0x73, 0xf7, 0xde, 0xa3, 0x94, 0x81, 0x5e, 0x61, 0xff, 0x52, 0x82, 0x01, 0xec, 0x46, + 0xf1, 0x77, 0x90, 0x72, 0x1f, 0xe9, 0x40, 0x44, 0xc6, 0x69, 0xaf, 0xaf, 0xed, 0x8c, 0x22, 0x06, 0xf6, 0x3d, 0xed, + 0xac, 0xde, 0xbf, 0x5f, 0xa9, 0xf9, 0xaa, 0xd4, 0x9b, 0xb3, 0xb0, 0xe6, 0xa9, 0x7b, 0x2f, 0xe9, 0x68, 0xa5, 0xbe, + 0x91, 0xe7, 0x8c, 0x94, 0xe6, 0xb2, 0x9d, 0xe0, 0x18, 0x5b, 0x7c, 0xf5, 0xb6, 0x3e, 0x14, 0x51, 0x0a, 0x3f, 0x06, + 0xeb, 0x25, 0x02, 0xf5, 0x0d, 0x0e, 0x8e, 0x77, 0x10, 0x6e, 0xed, 0x3a, 0x83, 0xc0, 0xb9, 0xd7, 0x6a, 0x5d, 0xff, + 0xb8, 0x75, 0xf8, 0xe7, 0xa8, 0xf5, 0xcb, 0x5e, 0xeb, 0x87, 0x23, 0xf7, 0xda, 0xf9, 0x71, 0x6b, 0x70, 0x28, 0xdf, + 0x0e, 0xff, 0xdc, 0xff, 0xb1, 0x38, 0xfa, 0x83, 0x28, 0xdc, 0x70, 0xdd, 0xad, 0x33, 0x6f, 0xc6, 0xc2, 0xad, 0x56, + 0xab, 0x0f, 0x4f, 0x67, 0xf0, 0x84, 0x7f, 0x2f, 0xe0, 0xcf, 0xf5, 0xa1, 0xf5, 0x9f, 0x7e, 0x4c, 0xff, 0xf3, 0x8f, + 0xf9, 0x11, 0x8e, 0x79, 0xf8, 0xe7, 0x1f, 0x0b, 0xfb, 0x41, 0x3f, 0xdc, 0x3a, 0xda, 0x74, 0x1d, 0x5d, 0xf3, 0x87, + 0xb0, 0x7a, 0x84, 0x56, 0x87, 0x7f, 0x96, 0x6f, 0xf6, 0x83, 0x93, 0xdd, 0x7e, 0x78, 0x74, 0xed, 0xd8, 0xd7, 0x0f, + 0xdc, 0x6b, 0xd7, 0xbd, 0xde, 0xc0, 0x79, 0xce, 0x61, 0xf4, 0x07, 0xf0, 0x77, 0x0c, 0x7f, 0x6d, 0xf8, 0x3b, 0x85, + 0xbf, 0x7f, 0x86, 0x6e, 0x22, 0xfe, 0x76, 0x4d, 0xb1, 0x90, 0x6b, 0x3c, 0xb0, 0x88, 0x60, 0x15, 0xdc, 0x8d, 0xad, + 0xd8, 0xdb, 0x20, 0xa2, 0xc1, 0x3e, 0xf4, 0x7d, 0x1f, 0xc3, 0xa4, 0xce, 0xe2, 0x78, 0x03, 0x16, 0x1d, 0x39, 0x67, + 0x23, 0xe0, 0x9e, 0x88, 0x1c, 0x14, 0x01, 0x13, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xc3, 0x70, 0x83, 0x39, 0x60, + 0x14, 0xbc, 0x65, 0xf8, 0xd0, 0x75, 0xbd, 0x17, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, + 0xed, 0x7a, 0xb3, 0x15, 0x95, 0xb0, 0xad, 0xd3, 0x33, 0xa8, 0x3b, 0x15, 0x27, 0x8c, 0xdf, 0xb1, 0xe8, 0x13, 0x6e, + 0xc9, 0x37, 0xc6, 0x21, 0xf0, 0x92, 0x25, 0xdf, 0x34, 0x1a, 0x0d, 0x1b, 0x51, 0xb8, 0x63, 0x4f, 0x19, 0xcc, 0xb0, + 0x64, 0x22, 0x32, 0x52, 0x9a, 0xc2, 0xb2, 0x85, 0xc9, 0xdf, 0x47, 0x39, 0xdf, 0xa8, 0x0c, 0xdb, 0xb0, 0x66, 0xc9, + 0x36, 0x2d, 0xfd, 0x3b, 0x4c, 0x81, 0xa6, 0x25, 0x9d, 0x7f, 0x98, 0xe3, 0x87, 0x29, 0xa1, 0xf5, 0xd6, 0x61, 0xe0, + 0xa1, 0x17, 0x20, 0x77, 0x44, 0x3f, 0xe7, 0x3d, 0xaa, 0x31, 0xf8, 0x9f, 0x0c, 0x33, 0x78, 0x62, 0x3e, 0x0c, 0xd1, + 0x2c, 0x4a, 0x1d, 0xdc, 0x4a, 0x51, 0xdc, 0xbf, 0xc2, 0x9d, 0x91, 0x96, 0xde, 0x7e, 0xa8, 0x76, 0xcc, 0x41, 0xce, + 0xd8, 0x77, 0x51, 0xf2, 0x89, 0xe5, 0xce, 0xa5, 0xd7, 0xe9, 0x7e, 0x4e, 0x9d, 0x3d, 0xb4, 0xcd, 0x3e, 0x54, 0xc7, + 0x68, 0xda, 0x2c, 0x90, 0x47, 0x84, 0xad, 0x8e, 0x97, 0x63, 0x54, 0x0b, 0x49, 0x50, 0x78, 0x59, 0xd8, 0x25, 0x0e, + 0xb7, 0x77, 0x8b, 0xf3, 0xb3, 0xbe, 0x1d, 0xd8, 0x36, 0x58, 0xfc, 0x07, 0x14, 0xb6, 0x12, 0x86, 0x45, 0xbb, 0xc7, + 0x76, 0xe3, 0x1e, 0xdb, 0xdc, 0xac, 0x02, 0x4e, 0x78, 0x90, 0x4e, 0xdd, 0x13, 0x2f, 0xf2, 0x26, 0x21, 0x0c, 0x38, + 0x84, 0x66, 0xd8, 0xa5, 0x37, 0xdc, 0x8d, 0xe5, 0x34, 0x18, 0x0b, 0xf1, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, + 0x0e, 0xd1, 0xd8, 0xf7, 0xd9, 0x25, 0x1b, 0x2a, 0x3b, 0x03, 0x08, 0x15, 0xb9, 0x3d, 0x77, 0x18, 0x1a, 0xcd, 0x60, + 0xee, 0x30, 0x3c, 0x18, 0xd8, 0xb0, 0x97, 0x60, 0x57, 0x86, 0xd1, 0x61, 0xe7, 0x68, 0x90, 0x86, 0x33, 0x16, 0x68, + 0xda, 0xca, 0xa2, 0xb3, 0x5a, 0x51, 0xf7, 0x68, 0xe0, 0x4c, 0x99, 0xcf, 0xc1, 0x16, 0x77, 0xf0, 0x0d, 0x23, 0x14, + 0x45, 0xf8, 0x81, 0x9d, 0xbd, 0xb8, 0x9c, 0x39, 0xf6, 0xee, 0x96, 0xbd, 0x89, 0xa5, 0x9e, 0x0d, 0xec, 0x05, 0x73, + 0x87, 0x17, 0xae, 0xd9, 0x79, 0xfb, 0x08, 0x41, 0xc5, 0x42, 0x9c, 0xfc, 0x62, 0x60, 0xf7, 0xc5, 0xd4, 0x6d, 0x18, + 0x34, 0x95, 0xcb, 0x8f, 0x2b, 0x7a, 0x40, 0xa8, 0xaa, 0xae, 0x0a, 0x3a, 0x28, 0xeb, 0x06, 0xce, 0xc4, 0x44, 0xa2, + 0x85, 0x93, 0x49, 0x2a, 0x80, 0xc3, 0x83, 0xcd, 0x60, 0x52, 0xa3, 0xdb, 0xf6, 0xd1, 0xe0, 0x22, 0x78, 0x60, 0x3f, + 0x50, 0x2f, 0x63, 0x40, 0x86, 0x89, 0xe9, 0xc7, 0xa0, 0x45, 0xf0, 0xef, 0x39, 0x03, 0x24, 0x2f, 0xa8, 0x68, 0x26, + 0x8b, 0xce, 0xb0, 0xe8, 0x20, 0x40, 0x50, 0xbd, 0x42, 0x5b, 0x7f, 0x62, 0x4d, 0x46, 0x21, 0xc1, 0x0e, 0xb6, 0xd0, + 0x21, 0xdb, 0xec, 0x1c, 0xe1, 0x79, 0x43, 0xce, 0x8b, 0xef, 0x62, 0x0e, 0x2a, 0x61, 0xab, 0x6f, 0xbb, 0x03, 0xdb, + 0xc2, 0xa5, 0xed, 0x65, 0x9b, 0xa1, 0xa0, 0x70, 0xbc, 0x79, 0xc0, 0x82, 0x49, 0x3f, 0x6c, 0x0f, 0x9c, 0x5c, 0x86, + 0x1b, 0xf1, 0xdc, 0x52, 0x48, 0xf0, 0xb6, 0x37, 0x01, 0x81, 0x8e, 0x9c, 0xbb, 0x61, 0x6f, 0xaa, 0x42, 0x28, 0x3a, + 0xde, 0x1c, 0xb9, 0x41, 0x0c, 0x7f, 0x9c, 0x16, 0x32, 0xcd, 0x44, 0xf7, 0x55, 0x9a, 0x19, 0x90, 0x18, 0x29, 0x8b, + 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, 0xb1, + 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, 0x47, + 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf7, 0x0c, 0x09, 0xc5, 0x4a, 0xed, 0x86, 0x09, 0x73, + 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, 0xbd, + 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, 0xe1, + 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, 0x02, + 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x31, 0xe9, 0xda, 0xa3, + 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, 0xbf, + 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, 0x60, + 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, 0x46, + 0xe0, 0x19, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, + 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, 0xdc, + 0x82, 0x18, 0x87, 0x19, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, 0x8a, + 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, 0x52, + 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, 0x36, + 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x19, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, 0xf4, + 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, 0xa2, + 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xbb, 0xf9, 0x52, 0xcc, 0x86, 0xb9, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, 0xd1, + 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x8b, 0xf4, 0x64, 0xfd, 0x36, 0xd8, 0xe0, + 0xb5, 0xbc, 0x03, 0xb4, 0xef, 0xd8, 0x74, 0xc6, 0xaf, 0xf6, 0x49, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0xb7, + 0x7b, 0xf1, 0x2e, 0xeb, 0xc5, 0x20, 0xd5, 0x73, 0xc5, 0x62, 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, + 0xab, 0xa1, 0xd7, 0x95, 0xe8, 0x6d, 0x6e, 0x02, 0x82, 0x3d, 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, + 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, 0x11, 0x73, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, + 0xb0, 0x03, 0x98, 0x11, 0x97, 0xb7, 0x3a, 0x22, 0x3a, 0x2c, 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0x37, 0x3b, 0x2e, + 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, 0xd6, 0x54, 0x2a, 0x8b, 0xcd, 0xcd, 0xb2, 0x7e, 0x54, + 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0xb2, 0x99, 0x0d, 0xc2, 0x81, 0x88, 0x09, 0x14, 0x68, 0x69, 0x65, 0xc5, 0x00, + 0x43, 0xca, 0x72, 0x94, 0x4f, 0x21, 0xf7, 0xe2, 0xb2, 0xd4, 0xa9, 0x2f, 0xcf, 0x64, 0xd0, 0x11, 0x4f, 0x3d, 0xc9, + 0x58, 0x01, 0x05, 0xeb, 0xa5, 0x5e, 0x42, 0x4b, 0x04, 0x98, 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, + 0x2c, 0x51, 0xc6, 0x67, 0x11, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, 0x62, 0x5f, 0x85, 0x32, 0x3a, 0x8a, 0xc3, 0xfc, 0x28, + 0xa0, 0xfa, 0xb9, 0x94, 0x60, 0x93, 0xf0, 0x23, 0xb0, 0x51, 0xe5, 0x78, 0x92, 0x20, 0x7c, 0x1e, 0xe7, 0x8c, 0x3c, + 0x85, 0x0d, 0x09, 0xb3, 0x34, 0x6d, 0x23, 0xd5, 0x2e, 0x32, 0x83, 0x50, 0x2e, 0xcc, 0x3f, 0x31, 0xce, 0x2e, 0xb2, + 0x70, 0xa9, 0x35, 0x98, 0x1f, 0xef, 0x4c, 0x80, 0xb2, 0xeb, 0xeb, 0x4c, 0xf8, 0xb8, 0x11, 0xd9, 0x1b, 0xba, 0x62, + 0x32, 0x50, 0x48, 0x05, 0x4e, 0x44, 0x16, 0x0f, 0x9d, 0xa1, 0xd0, 0x08, 0x07, 0x74, 0x8a, 0x9c, 0xbb, 0xc6, 0xa6, + 0xcf, 0x07, 0xda, 0x37, 0x4a, 0x43, 0x27, 0x01, 0x21, 0x20, 0x70, 0x37, 0xac, 0xa9, 0x74, 0x90, 0x06, 0x09, 0x95, + 0xa2, 0x9f, 0x03, 0xf8, 0x87, 0x91, 0xa4, 0x00, 0xd8, 0x0f, 0xd5, 0x48, 0x11, 0x65, 0x59, 0xe0, 0x02, 0xd0, 0x5c, + 0xfb, 0xb8, 0x12, 0xbe, 0x30, 0x50, 0x61, 0x7a, 0x9a, 0x95, 0x95, 0x42, 0x89, 0x3c, 0x5d, 0x91, 0xb2, 0x46, 0x32, + 0xf9, 0x1c, 0x1d, 0x3e, 0xe5, 0x5d, 0xbf, 0x95, 0x78, 0xe8, 0x82, 0xe7, 0xb0, 0xac, 0xea, 0xf9, 0x4d, 0xc8, 0xc8, + 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xf7, 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, + 0x0c, 0xcb, 0xcb, 0x59, 0x15, 0xa6, 0x20, 0xe0, 0x16, 0x2c, 0x09, 0x16, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, + 0x0a, 0xf2, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0x99, 0xd4, 0x04, + 0x4c, 0xb9, 0x3f, 0x04, 0x3f, 0xb5, 0x79, 0xd2, 0x75, 0xe9, 0xfa, 0xf1, 0x14, 0x53, 0x7b, 0x08, 0xf4, 0xd8, 0xbb, + 0x07, 0xa6, 0x44, 0x5d, 0x87, 0x15, 0xc4, 0xa1, 0x59, 0x4d, 0xb3, 0x80, 0x19, 0xd3, 0x06, 0x2d, 0xd9, 0x06, 0x5b, + 0x2e, 0x07, 0xfb, 0x48, 0x6c, 0xcf, 0x6a, 0x05, 0x84, 0xae, 0x41, 0x03, 0x43, 0xee, 0x52, 0xa1, 0x85, 0x59, 0xaf, + 0x4b, 0x45, 0xb8, 0x3f, 0x07, 0x4c, 0x5a, 0xc1, 0x99, 0x97, 0xd1, 0xc0, 0xfb, 0xf1, 0x69, 0x82, 0x89, 0x2f, 0x88, + 0x15, 0xd8, 0xc1, 0x41, 0xa7, 0xd9, 0x14, 0x38, 0x15, 0x17, 0x29, 0x83, 0x65, 0x45, 0xa9, 0x0d, 0x7f, 0xa4, 0xc8, + 0xd6, 0x5d, 0x1e, 0xe9, 0x2e, 0xc4, 0x02, 0xd8, 0xe9, 0x17, 0x8c, 0x7c, 0xcb, 0x7a, 0x19, 0x30, 0x38, 0xd7, 0x1a, + 0x07, 0x81, 0xdf, 0xdc, 0x4c, 0x8e, 0xca, 0x94, 0xd8, 0xae, 0xc9, 0xea, 0x02, 0x72, 0x4c, 0x02, 0x6c, 0xe0, 0x0e, + 0xc2, 0x52, 0xd9, 0xe3, 0x45, 0x39, 0xc5, 0xe5, 0x52, 0x16, 0x72, 0x33, 0x1d, 0x8b, 0xe6, 0x73, 0x2b, 0xcd, 0xa6, + 0xe3, 0xad, 0xf8, 0xa2, 0xe0, 0x1f, 0x38, 0xb1, 0xb4, 0xea, 0x29, 0xb5, 0xc2, 0xa3, 0xcc, 0x2d, 0x59, 0xa7, 0xa4, + 0x56, 0xd7, 0x0d, 0x54, 0x23, 0x3c, 0x4d, 0xc3, 0x46, 0x20, 0xc4, 0x04, 0x17, 0xbf, 0x6d, 0x32, 0x31, 0xed, 0x2d, + 0x21, 0x75, 0x84, 0xdd, 0x43, 0x39, 0xc1, 0x5d, 0xcd, 0xb3, 0x2f, 0xc3, 0xd9, 0x7a, 0xe6, 0xde, 0x33, 0x98, 0xfb, + 0x69, 0xc8, 0x0c, 0x46, 0x8f, 0x65, 0xc2, 0x8f, 0x8c, 0x7d, 0xe4, 0xaa, 0xea, 0xd9, 0x59, 0x58, 0x89, 0x2c, 0xf1, + 0x64, 0x1c, 0x75, 0x18, 0xa7, 0xa2, 0x35, 0x41, 0x76, 0x7d, 0x5d, 0x98, 0x7b, 0x81, 0x82, 0xa6, 0x1e, 0xab, 0xc7, + 0x69, 0x2b, 0x76, 0x36, 0x22, 0x91, 0x7b, 0x6f, 0x6a, 0x91, 0xc8, 0x8a, 0xcf, 0x71, 0xa4, 0x35, 0x07, 0xb9, 0xcf, + 0xce, 0x96, 0x37, 0xa9, 0xd0, 0x2d, 0x1a, 0x6d, 0x63, 0x8f, 0xea, 0x03, 0x49, 0x3d, 0xa3, 0x02, 0xab, 0x1a, 0xfb, + 0xfe, 0xfd, 0x8e, 0x48, 0xb7, 0x54, 0x8a, 0x0d, 0x43, 0x5a, 0x21, 0x33, 0x46, 0xc1, 0xa0, 0xa4, 0xc8, 0x40, 0x8d, + 0xf2, 0x35, 0x82, 0x61, 0x8f, 0x1a, 0x80, 0xe2, 0x5c, 0x5d, 0xfd, 0xb4, 0x94, 0x6c, 0x21, 0x20, 0x01, 0xd9, 0x84, + 0x62, 0x8d, 0x98, 0x19, 0xf9, 0xe4, 0x23, 0x70, 0xde, 0x80, 0xa3, 0x63, 0x00, 0x7e, 0x81, 0xd8, 0xf4, 0x60, 0x62, + 0xdb, 0x44, 0x14, 0x7d, 0x36, 0xf0, 0x12, 0x80, 0x9d, 0x55, 0xa1, 0xd1, 0x0f, 0x55, 0x0a, 0x18, 0xb2, 0x81, 0x1b, + 0xf0, 0x2a, 0x2c, 0xb7, 0xf7, 0x12, 0xda, 0xc1, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xd8, 0x9d, 0x5f, + 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x25, 0x23, 0x18, 0xf1, 0xfd, + 0x0d, 0x65, 0x1d, 0xaa, 0x71, 0xcb, 0x3d, 0x8d, 0x16, 0x61, 0xba, 0x4c, 0x1a, 0x83, 0x92, 0x75, 0x3f, 0x19, 0x71, + 0x2f, 0xf7, 0x45, 0x2c, 0xb8, 0xc2, 0xd1, 0x08, 0x9b, 0x37, 0x90, 0xa4, 0xa7, 0x3d, 0x3a, 0x60, 0xdf, 0x68, 0xf6, + 0x02, 0xca, 0x7c, 0xac, 0x48, 0x25, 0x21, 0xa5, 0xd9, 0x0d, 0x91, 0x24, 0xac, 0x15, 0x79, 0xea, 0xbc, 0xef, 0x68, + 0x9f, 0x5b, 0x49, 0x04, 0x23, 0x38, 0x89, 0xd3, 0x95, 0x07, 0x4d, 0x01, 0xae, 0xa2, 0x23, 0xa6, 0x6f, 0x82, 0xf2, + 0x1b, 0xe4, 0xf6, 0x52, 0x72, 0x6d, 0xae, 0x61, 0x78, 0x86, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x0d, 0x38, 0xe6, + 0xab, 0x3c, 0x0f, 0x30, 0xe1, 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x96, 0x02, 0xdd, 0x80, 0xe5, 0xea, + 0x38, 0x35, 0x2a, 0x12, 0x17, 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x53, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, + 0xa9, 0x4f, 0x99, 0x23, 0x64, 0xae, 0xb0, 0x3e, 0x67, 0x4e, 0x6d, 0xea, 0x1e, 0xa7, 0x6e, 0x9e, 0xa4, 0x16, 0xab, + 0xd3, 0xa6, 0x94, 0x88, 0x49, 0x89, 0x79, 0x2a, 0x53, 0xb1, 0x95, 0xb8, 0x73, 0xeb, 0x1b, 0x2d, 0xa4, 0x8d, 0x76, + 0x2a, 0x73, 0xb0, 0xb5, 0xbc, 0x17, 0xa2, 0xfd, 0x25, 0x11, 0x9e, 0x95, 0xc8, 0x58, 0x8b, 0x39, 0x73, 0x4c, 0x04, + 0xab, 0x17, 0x53, 0x91, 0x7f, 0x70, 0x74, 0x9a, 0xbd, 0x41, 0x0f, 0x52, 0x6f, 0x20, 0x31, 0x6b, 0xe2, 0xbb, 0x90, + 0x86, 0x3a, 0x42, 0xa0, 0x32, 0xaa, 0x65, 0x3a, 0x4e, 0x2c, 0x15, 0x97, 0xe4, 0xab, 0xf7, 0xfa, 0x38, 0xdf, 0x78, + 0x6e, 0xac, 0x46, 0x10, 0x83, 0xb7, 0x90, 0x1f, 0x79, 0x52, 0x84, 0x03, 0xe1, 0xf2, 0xcd, 0xcd, 0x5e, 0xbe, 0xcb, + 0xaa, 0x10, 0x49, 0x05, 0x63, 0x8c, 0x19, 0xc5, 0xb8, 0x27, 0x6a, 0x6a, 0x31, 0x07, 0x54, 0x65, 0xeb, 0x30, 0xc7, + 0x03, 0x00, 0x68, 0x69, 0x4a, 0x2f, 0xb3, 0xad, 0x3a, 0xcf, 0x25, 0x7c, 0x8c, 0x3c, 0x14, 0xd9, 0xf8, 0xfd, 0x9a, + 0x0c, 0x14, 0x84, 0xfb, 0x5e, 0xc7, 0xc3, 0xc4, 0x38, 0x58, 0x45, 0x21, 0x0b, 0xf4, 0x06, 0xed, 0x55, 0x89, 0x50, + 0xdc, 0x9c, 0xac, 0xc7, 0x0d, 0x27, 0x15, 0x6c, 0xa1, 0x12, 0x96, 0x4a, 0x0b, 0xfc, 0x6a, 0x23, 0x34, 0x4f, 0x19, + 0xf7, 0xde, 0x54, 0x38, 0x83, 0xfe, 0xe0, 0xde, 0x32, 0xa3, 0xbe, 0x5f, 0x3a, 0x91, 0xa9, 0xc0, 0xc4, 0xcd, 0x2c, + 0xb5, 0xdf, 0x2f, 0xab, 0xb4, 0x9f, 0x57, 0xc8, 0x7d, 0x4e, 0x9a, 0xaf, 0x73, 0x07, 0xcd, 0x27, 0xc3, 0xfd, 0x4a, + 0xf9, 0xa1, 0x85, 0x51, 0x53, 0x7e, 0x79, 0x5d, 0xf9, 0x15, 0x9e, 0x0a, 0x6f, 0xf5, 0xbb, 0x28, 0x74, 0x51, 0x9f, + 0x83, 0x21, 0xa4, 0x1f, 0xc1, 0x35, 0x34, 0x78, 0x50, 0x24, 0x8b, 0xc5, 0xda, 0x05, 0x71, 0x7d, 0xcc, 0xa9, 0x76, + 0x28, 0x63, 0x8c, 0x78, 0x5a, 0x72, 0x90, 0x64, 0x70, 0x30, 0x7e, 0x03, 0x03, 0x62, 0x52, 0x12, 0xd2, 0x21, 0x74, + 0x56, 0x66, 0x22, 0x2a, 0x77, 0xf1, 0x76, 0xe3, 0xb2, 0xa6, 0x50, 0x84, 0x9d, 0x60, 0xa6, 0x52, 0x2a, 0x08, 0xa4, + 0xc9, 0x77, 0xaf, 0x53, 0x0b, 0x86, 0x82, 0x68, 0x30, 0x14, 0x90, 0xd7, 0x76, 0x3d, 0x68, 0xf2, 0x51, 0x1c, 0x3c, + 0xaf, 0x50, 0x23, 0x5e, 0x66, 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x2e, 0x62, 0xaf, 0xe0, 0x13, 0x21, + 0x9b, 0xf2, 0xb0, 0x00, 0xfa, 0xa1, 0x5d, 0xd9, 0x4b, 0x77, 0x8b, 0xca, 0xa5, 0x45, 0x63, 0x2b, 0x51, 0xb3, 0xe6, + 0x87, 0xf1, 0x66, 0x7a, 0x04, 0x53, 0x53, 0x02, 0x01, 0x69, 0x2a, 0x27, 0xa9, 0xe6, 0x3d, 0x4c, 0x8f, 0x00, 0x24, + 0xd8, 0xfd, 0x04, 0x16, 0xfa, 0x4d, 0x89, 0x09, 0x16, 0x55, 0x63, 0xb7, 0x19, 0x68, 0xcd, 0x19, 0x69, 0xbe, 0x19, + 0x42, 0xb8, 0xa9, 0xac, 0x67, 0xcc, 0x0e, 0xb0, 0x6d, 0x77, 0xb3, 0x38, 0x4c, 0x37, 0x3b, 0x47, 0x86, 0xe0, 0xc2, + 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x5c, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, + 0xd1, 0x74, 0xee, 0x35, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, 0x89, 0x62, 0x9e, 0x13, + 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, 0xca, 0xcf, 0xe8, 0x48, + 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x4b, 0x30, 0x8d, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, 0x00, 0x5f, 0xd9, 0x50, + 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x72, 0x36, 0xc1, 0x02, 0x0d, 0xba, 0xac, 0xc1, 0x17, 0xb0, 0x0c, 0xee, + 0x48, 0x3f, 0x05, 0xdf, 0x4f, 0xeb, 0xe0, 0x33, 0xf6, 0xbf, 0x00, 0xb4, 0x2a, 0x30, 0xa0, 0xdc, 0x69, 0x1a, 0x56, + 0x42, 0x5c, 0xa2, 0xc2, 0xac, 0xe2, 0xfc, 0x71, 0x9d, 0xd7, 0x4d, 0xcb, 0x12, 0x83, 0xf2, 0x33, 0xd7, 0x70, 0xe3, + 0x7b, 0x8d, 0xfc, 0xf1, 0xbd, 0x97, 0xa0, 0xdb, 0x89, 0xb4, 0xf7, 0xef, 0xe7, 0xf7, 0xc8, 0x42, 0x03, 0x3f, 0x2c, + 0x9a, 0x41, 0x5b, 0xbc, 0x08, 0x90, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, 0x30, 0x03, 0x0c, + 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, 0xe4, 0xc5, 0x3a, + 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x20, 0xfa, 0x9a, 0xca, 0x62, 0x03, 0xb9, 0xb8, 0x29, 0x6b, + 0xbd, 0xa2, 0xd1, 0xe8, 0xc6, 0x2e, 0xbc, 0xae, 0xc0, 0x27, 0x51, 0x3a, 0x4a, 0xc4, 0x24, 0x66, 0x52, 0xe5, 0x8a, + 0x5c, 0x1b, 0xdd, 0x4b, 0x5b, 0x34, 0x2f, 0x85, 0x04, 0xaf, 0x08, 0xdc, 0x10, 0xfa, 0x4a, 0x5f, 0xae, 0x36, 0x50, + 0xf0, 0xa8, 0xbd, 0xb9, 0x08, 0x26, 0x26, 0x1e, 0x37, 0xa4, 0xa6, 0x5f, 0x87, 0x53, 0x2b, 0x8b, 0x25, 0x87, 0x5f, + 0xe7, 0x8c, 0x35, 0x14, 0x00, 0xf1, 0xc9, 0xa3, 0xf5, 0x6e, 0xd2, 0x1b, 0xa5, 0x1d, 0x94, 0x46, 0x88, 0xef, 0x2a, + 0x7c, 0xdd, 0x85, 0xe2, 0x2b, 0x57, 0xdd, 0xfb, 0x3a, 0x66, 0xc6, 0x05, 0xa3, 0x97, 0x7c, 0x9a, 0x34, 0xae, 0xdd, + 0xd0, 0x5d, 0x9d, 0xef, 0xbd, 0x2f, 0x65, 0xde, 0xc2, 0x31, 0xb0, 0xc9, 0x31, 0x73, 0x5e, 0x7a, 0x6f, 0x8d, 0x13, + 0xe5, 0x1f, 0xcc, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0x1f, 0x06, 0x3f, 0x04, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, + 0x5d, 0x75, 0x82, 0x4c, 0x94, 0xdb, 0xd0, 0x1b, 0x6e, 0xef, 0xae, 0x02, 0x41, 0x9c, 0x8a, 0xe9, 0xa3, 0x72, 0x5c, + 0x3f, 0x5a, 0xa0, 0x52, 0x11, 0xf1, 0xb9, 0xca, 0x5d, 0x59, 0x9b, 0x1a, 0xea, 0x31, 0x9d, 0xcc, 0x42, 0xd3, 0xac, + 0xc8, 0xa5, 0x6c, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, + 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, 0x7a, 0x14, 0x7d, 0x1c, 0xb7, 0x99, 0xcb, 0xa3, + 0xec, 0xcf, 0x1a, 0x00, 0xa6, 0x23, 0x2c, 0xba, 0x9b, 0x9e, 0xb1, 0x27, 0xd0, 0xd3, 0x13, 0x19, 0x24, 0x7a, 0xa3, + 0xf3, 0x55, 0xab, 0xc4, 0xd2, 0x15, 0x04, 0x76, 0x6f, 0xc8, 0x58, 0x95, 0xb4, 0x5b, 0xae, 0x5f, 0xce, 0xf3, 0x79, + 0xce, 0x97, 0xf2, 0x7c, 0x6a, 0x16, 0xdd, 0xbd, 0xb6, 0x7b, 0x73, 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, + 0x5d, 0x07, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, 0x8d, 0x7a, 0x26, 0xc7, 0x86, 0xf0, 0x4d, 0xa5, + 0x3b, 0x44, 0x37, 0x4c, 0xd5, 0x4c, 0xdf, 0x37, 0xb6, 0x85, 0x6c, 0xf3, 0xf2, 0x6a, 0x94, 0x03, 0xa5, 0xe5, 0xfe, + 0x32, 0x61, 0xf8, 0xfe, 0xfa, 0xfa, 0x7b, 0x21, 0xa7, 0xaa, 0x8e, 0xde, 0xe2, 0xb5, 0xee, 0x19, 0x6c, 0x94, 0xca, + 0x89, 0xb8, 0x60, 0xab, 0x07, 0x6f, 0xee, 0x5e, 0x01, 0xcb, 0x05, 0xec, 0xda, 0x0b, 0xe6, 0x34, 0x86, 0xaa, 0x36, + 0xf0, 0x97, 0xab, 0x07, 0x5b, 0xb5, 0x87, 0xbf, 0x1c, 0x7c, 0x19, 0xdc, 0xd8, 0xd8, 0xd8, 0xc6, 0xdb, 0xb5, 0x44, + 0x90, 0x37, 0x78, 0xa0, 0x8f, 0x57, 0x1f, 0x05, 0x2d, 0x57, 0x88, 0x6d, 0x36, 0x70, 0x28, 0x6c, 0x0d, 0xf2, 0x4d, + 0xca, 0xa4, 0xe1, 0xbc, 0xe0, 0xd9, 0x54, 0xce, 0x50, 0xc8, 0x6b, 0x3e, 0x0e, 0xda, 0x8e, 0xf0, 0xbf, 0xc0, 0xa9, + 0x1d, 0x2f, 0x2f, 0x3e, 0x41, 0x1f, 0xf0, 0x74, 0xa5, 0x34, 0xa5, 0x38, 0xa5, 0x0a, 0xea, 0x2c, 0xd7, 0x79, 0x30, + 0x52, 0x5c, 0x4c, 0x60, 0x71, 0xc1, 0x65, 0xb9, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, 0x44, + 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, 0xd7, + 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, 0xe7, + 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, 0x52, + 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, 0x2d, + 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, 0xc4, + 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, 0xd6, + 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, 0xe2, + 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0x67, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, 0x68, + 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, 0x57, + 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, 0x70, + 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, 0xc0, + 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0x61, 0x03, 0xb9, 0xd4, 0x92, 0xbf, 0xcc, + 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, 0x51, + 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x2f, 0x54, 0xe4, 0x98, 0x3a, + 0x98, 0x95, 0xda, 0x4d, 0x8b, 0x4d, 0x92, 0xf7, 0xcc, 0x80, 0xe4, 0xea, 0x6b, 0x78, 0x68, 0xfc, 0x32, 0xbc, 0xa1, + 0xe8, 0xe9, 0x18, 0x21, 0xa7, 0xa5, 0x31, 0x97, 0xfe, 0x5b, 0x79, 0x9f, 0x56, 0x02, 0xf6, 0x0a, 0xc4, 0x94, 0x81, + 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x4b, 0x26, 0x5d, 0xa5, 0xb2, 0xd6, 0x58, + 0x75, 0x3f, 0xcf, 0x59, 0x7e, 0xb5, 0xcf, 0x30, 0x37, 0x19, 0x0d, 0xb2, 0x25, 0x33, 0x9b, 0xf2, 0xab, 0xbd, 0x1b, + 0xbf, 0xf2, 0x50, 0xd2, 0xa1, 0x5a, 0xa5, 0x9b, 0x97, 0x6e, 0x38, 0xc6, 0x8d, 0x1b, 0x8e, 0x00, 0x36, 0x86, 0x9d, + 0x2a, 0x52, 0xeb, 0xfc, 0xf7, 0xa5, 0xf0, 0x93, 0xd8, 0x6b, 0x47, 0x7a, 0xd7, 0x1d, 0xad, 0x4c, 0x4f, 0xbf, 0x01, + 0x55, 0x23, 0x4b, 0xe8, 0x26, 0x54, 0x31, 0x19, 0x89, 0x12, 0xd3, 0x55, 0xca, 0xa3, 0xbe, 0x46, 0x9c, 0x83, 0xb8, + 0xa1, 0xfc, 0xc5, 0x3f, 0x85, 0x57, 0x27, 0x01, 0x1a, 0x51, 0x8b, 0x71, 0x96, 0xf2, 0xd6, 0x38, 0x9a, 0xc6, 0xc9, + 0x55, 0x30, 0x8f, 0x5b, 0xd3, 0x2c, 0xcd, 0x8a, 0x19, 0x70, 0xa5, 0x57, 0x5c, 0x81, 0x0d, 0x3f, 0x6d, 0xcd, 0x63, + 0xef, 0x25, 0x4b, 0xce, 0x19, 0x8f, 0x87, 0x91, 0x67, 0xef, 0xe5, 0x20, 0x1e, 0xac, 0xb7, 0x51, 0x9e, 0x67, 0x17, + 0xb6, 0xf7, 0x21, 0x3b, 0x05, 0xa6, 0xf5, 0xde, 0x5d, 0x5e, 0x9d, 0xb1, 0xd4, 0xfb, 0x78, 0x3a, 0x4f, 0xf9, 0xdc, + 0x2b, 0xa2, 0xb4, 0x68, 0x15, 0x2c, 0x8f, 0xc7, 0xa0, 0x26, 0x92, 0x2c, 0x6f, 0x61, 0xfe, 0xf3, 0x94, 0x05, 0x49, + 0x7c, 0x36, 0xe1, 0xd6, 0x28, 0xca, 0x3f, 0xf5, 0x5a, 0xad, 0x59, 0x1e, 0x4f, 0xa3, 0xfc, 0xaa, 0x45, 0x2d, 0x82, + 0xcf, 0xda, 0xdb, 0xd1, 0xe7, 0xe3, 0x87, 0x3d, 0x9e, 0x43, 0xdf, 0x18, 0xa9, 0x18, 0x80, 0xf0, 0xb1, 0xb6, 0x77, + 0xda, 0xd3, 0xe2, 0x9e, 0x38, 0x51, 0x8a, 0x52, 0x5e, 0x9e, 0x78, 0x57, 0x0c, 0xe0, 0xf6, 0x4f, 0x79, 0xea, 0x81, + 0x2f, 0xc7, 0xb3, 0x74, 0x31, 0x9c, 0xe7, 0x05, 0x0c, 0x30, 0xcb, 0xe2, 0x94, 0xb3, 0xbc, 0x77, 0x9a, 0xe5, 0x40, + 0xb6, 0x56, 0x1e, 0x8d, 0xe2, 0x79, 0x11, 0x3c, 0x9c, 0x5d, 0xf6, 0xd0, 0x56, 0x38, 0xcb, 0xb3, 0x79, 0x3a, 0x92, + 0x73, 0xc5, 0x29, 0x6c, 0x8c, 0x98, 0x9b, 0x15, 0xf4, 0x25, 0x14, 0x80, 0x2f, 0x65, 0x51, 0xde, 0x3a, 0xc3, 0xce, + 0x68, 0xe8, 0xb7, 0x47, 0xec, 0xcc, 0xcb, 0xcf, 0x4e, 0x23, 0xa7, 0xd3, 0x7d, 0xec, 0xa9, 0x7f, 0xfe, 0x8e, 0x0b, + 0x86, 0xfb, 0xca, 0xe2, 0x4e, 0xbb, 0xfd, 0x37, 0x6e, 0xaf, 0x31, 0x0b, 0x01, 0x14, 0x74, 0x66, 0x97, 0x56, 0x91, + 0x25, 0xb0, 0x3e, 0xab, 0x7a, 0xf6, 0x66, 0xe0, 0x37, 0xc5, 0xe9, 0x59, 0xd0, 0x9d, 0x5d, 0x96, 0x88, 0x5d, 0x20, + 0x12, 0x32, 0x25, 0x92, 0xf2, 0x6d, 0xf1, 0x5b, 0x21, 0x7e, 0xb2, 0x1a, 0xe2, 0xae, 0x82, 0xb8, 0xa2, 0x7a, 0x6b, + 0x04, 0xfb, 0x80, 0xc8, 0xdf, 0x29, 0x04, 0x20, 0x13, 0x70, 0x02, 0x73, 0x05, 0x07, 0xbd, 0xfc, 0x66, 0x30, 0xba, + 0xab, 0xc1, 0x78, 0x72, 0x1b, 0x18, 0x79, 0x3a, 0x5a, 0xd4, 0xd7, 0xb5, 0x03, 0xce, 0x69, 0x6f, 0xc2, 0x90, 0x9f, + 0x82, 0x2e, 0x3e, 0x5f, 0xc4, 0x23, 0x3e, 0x11, 0x8f, 0xc4, 0xce, 0x17, 0xa2, 0x6e, 0xa7, 0xdd, 0x16, 0xef, 0x05, + 0x28, 0xb4, 0xa0, 0xe3, 0x63, 0x03, 0x60, 0xa2, 0x2f, 0xd6, 0x7d, 0xc4, 0xe6, 0xbb, 0x5b, 0xbf, 0x54, 0xe3, 0x31, + 0x95, 0x37, 0x28, 0x54, 0x84, 0xfa, 0x66, 0x0b, 0x66, 0xbc, 0xe5, 0xfd, 0x8e, 0x3e, 0xa8, 0x1a, 0x7c, 0xc7, 0x48, + 0xeb, 0x05, 0xcc, 0x33, 0x73, 0x81, 0x7a, 0x69, 0x1f, 0x43, 0x52, 0xad, 0x96, 0x0b, 0x7a, 0x83, 0x63, 0x08, 0x89, + 0x0e, 0x04, 0x9d, 0x7c, 0x50, 0xd0, 0x37, 0x35, 0x32, 0x37, 0x28, 0x9c, 0xcc, 0x85, 0x2d, 0x9f, 0x69, 0xb9, 0x0e, + 0x4a, 0x1a, 0xbc, 0xec, 0x2f, 0x98, 0x6c, 0x00, 0xd2, 0xbb, 0x92, 0xb4, 0xbc, 0x3a, 0x7a, 0x52, 0x2e, 0x5f, 0x36, + 0x24, 0xca, 0x81, 0xaf, 0xcf, 0x27, 0xe8, 0x77, 0xeb, 0xab, 0xeb, 0x46, 0x4a, 0xcd, 0x96, 0xed, 0x0e, 0xb8, 0xce, + 0xca, 0xc2, 0xec, 0x33, 0x5e, 0xe2, 0x28, 0x5f, 0x81, 0x9c, 0xc5, 0xd0, 0xeb, 0xcf, 0xa1, 0x70, 0xd3, 0x94, 0x93, + 0xb6, 0x71, 0xd3, 0xf5, 0x7f, 0x58, 0xf1, 0x98, 0xb2, 0x9d, 0x55, 0x6c, 0x1c, 0x5c, 0x97, 0xe3, 0xa1, 0xb8, 0x76, + 0x58, 0x60, 0xb6, 0xf8, 0x6f, 0xf7, 0x24, 0x1c, 0x8d, 0x56, 0x91, 0xcd, 0xf3, 0x21, 0x26, 0xfd, 0xaf, 0x08, 0x31, + 0xd8, 0xa4, 0xe1, 0x6d, 0x8f, 0x6b, 0xc5, 0xc2, 0x30, 0x7f, 0xc2, 0xfc, 0xaa, 0x02, 0xa3, 0x53, 0x17, 0x71, 0xa9, + 0x41, 0x86, 0x55, 0x14, 0xd8, 0xa8, 0x2b, 0x47, 0x94, 0x60, 0x47, 0x17, 0x3e, 0xfd, 0x79, 0x1a, 0x83, 0x68, 0x3d, + 0x8e, 0x47, 0x74, 0xd1, 0x25, 0x1e, 0xd1, 0xc9, 0x47, 0x8b, 0x32, 0x9d, 0x30, 0x94, 0x0e, 0x05, 0x92, 0xe0, 0xf8, + 0x2c, 0x33, 0x67, 0xec, 0x96, 0x8d, 0xa7, 0x17, 0x86, 0x6e, 0x1e, 0x65, 0xd3, 0x28, 0x4e, 0x03, 0xfc, 0x20, 0x89, + 0xa7, 0x47, 0x0c, 0xb0, 0x8b, 0x07, 0x7f, 0x15, 0xed, 0x3b, 0xae, 0xff, 0x13, 0x08, 0x2e, 0xea, 0x5f, 0x4a, 0xc7, + 0x4f, 0xc3, 0xa5, 0xce, 0x95, 0xeb, 0xa5, 0x20, 0xec, 0xb8, 0xce, 0x6d, 0xa7, 0xc0, 0xca, 0x2e, 0xa3, 0x3f, 0x83, + 0x56, 0x27, 0xe8, 0xb8, 0xcb, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, 0xf3, + 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, 0x56, + 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, 0x5b, + 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xc5, 0x18, 0xb8, 0xaf, 0x65, 0x6d, 0x29, 0xf6, 0x1e, 0x9e, + 0xec, 0x0a, 0x21, 0x65, 0x11, 0xeb, 0x86, 0x36, 0x48, 0x0d, 0xdb, 0xfa, 0xe3, 0x10, 0xe8, 0xfc, 0x29, 0xb4, 0x37, + 0x16, 0x8e, 0xba, 0x0b, 0x90, 0xc3, 0x5c, 0x7b, 0x42, 0x51, 0xd3, 0x47, 0x04, 0xec, 0xfe, 0xc6, 0x82, 0x95, 0xbb, + 0x5b, 0xa2, 0x77, 0xff, 0xa4, 0x2c, 0x48, 0xa7, 0x9a, 0xb1, 0xbf, 0x6a, 0x0a, 0x51, 0x07, 0xc3, 0x52, 0xc6, 0x31, + 0x8e, 0x9b, 0x6b, 0x3b, 0x51, 0x04, 0xb9, 0x25, 0xe3, 0x16, 0x98, 0x61, 0x15, 0xe5, 0x20, 0x46, 0x74, 0x0e, 0x4d, + 0x21, 0xd2, 0x46, 0x7a, 0xcb, 0x50, 0x9c, 0x20, 0x04, 0x83, 0x8d, 0x45, 0x5c, 0x86, 0xf0, 0x94, 0x0e, 0xb3, 0x11, + 0xfb, 0xf8, 0xe1, 0x15, 0x5e, 0x93, 0xc8, 0x52, 0x94, 0xa7, 0x99, 0x5b, 0x9e, 0x80, 0x81, 0x85, 0x90, 0xe6, 0xea, + 0x2b, 0x35, 0x00, 0x8c, 0x88, 0x15, 0x59, 0x34, 0x2a, 0x82, 0xc2, 0x4b, 0xdb, 0x1a, 0x08, 0x08, 0xc1, 0x91, 0xc5, + 0x02, 0x30, 0x41, 0xa9, 0x17, 0x07, 0xfc, 0x44, 0xeb, 0x3e, 0x0c, 0xb4, 0xbb, 0x25, 0x1a, 0x01, 0xae, 0x39, 0xa2, + 0x51, 0xa1, 0x8a, 0x59, 0x45, 0x26, 0xba, 0xa3, 0xf8, 0x5c, 0x93, 0x93, 0x52, 0xac, 0xfb, 0xbb, 0x49, 0x74, 0xca, + 0x12, 0x18, 0x12, 0xf8, 0xaa, 0x0d, 0x23, 0x89, 0x57, 0x6b, 0x37, 0x4e, 0x67, 0x73, 0xf9, 0xb5, 0x30, 0x98, 0xb8, + 0x83, 0x07, 0xb8, 0x78, 0x99, 0x61, 0xa0, 0x4e, 0x24, 0x03, 0x39, 0x00, 0x80, 0x48, 0x87, 0x21, 0x08, 0x5d, 0xc5, + 0x2a, 0x50, 0x1a, 0x8f, 0x96, 0xcb, 0x60, 0x7f, 0xcf, 0xb0, 0x34, 0x85, 0xe7, 0x69, 0x9c, 0xe2, 0x63, 0x81, 0x8f, + 0xd1, 0x25, 0x3e, 0x66, 0xf0, 0xa8, 0x71, 0xcf, 0x4b, 0xfb, 0xaf, 0xba, 0x2a, 0x99, 0x5c, 0x01, 0x4b, 0x13, 0x20, + 0xbb, 0xbe, 0x06, 0xb5, 0xa5, 0x49, 0xb0, 0xbb, 0x05, 0xc4, 0x42, 0xee, 0x11, 0xdf, 0x8e, 0xe1, 0x26, 0x19, 0x59, + 0x31, 0x6b, 0x89, 0x72, 0x8b, 0x8c, 0x83, 0x10, 0x7c, 0xc7, 0xdc, 0x69, 0xd8, 0x40, 0x9e, 0xcc, 0x92, 0x79, 0x86, + 0x2f, 0xae, 0x6d, 0x89, 0x8f, 0x7b, 0x08, 0xa2, 0xd0, 0x23, 0x62, 0xa8, 0xcb, 0x98, 0xfc, 0x6c, 0x4f, 0x1c, 0xda, + 0x38, 0x0b, 0x98, 0xa1, 0xe8, 0x85, 0xf2, 0x28, 0x4e, 0x44, 0xe3, 0x15, 0xf8, 0x34, 0xd2, 0x1d, 0x09, 0x9d, 0xdd, + 0xad, 0x0a, 0x36, 0x00, 0x5e, 0x49, 0x04, 0x4e, 0x19, 0x37, 0xb6, 0x28, 0xa7, 0x14, 0x00, 0xb9, 0xcd, 0xab, 0x4f, + 0x3a, 0x01, 0x53, 0x80, 0x11, 0x3d, 0x3a, 0xa6, 0xd9, 0x06, 0x43, 0x20, 0x16, 0xcd, 0xd8, 0xd8, 0xba, 0xf6, 0x5f, + 0xfe, 0xf9, 0x1f, 0x6c, 0x4f, 0x80, 0x98, 0x8d, 0xc7, 0x20, 0xe5, 0xac, 0x75, 0x0d, 0xff, 0xd7, 0x3f, 0xfe, 0xdf, + 0xff, 0xf3, 0x5f, 0x75, 0xdb, 0x14, 0x9a, 0x9e, 0x04, 0xe2, 0x68, 0x41, 0x93, 0x94, 0x52, 0x3c, 0xed, 0x71, 0x94, + 0xae, 0x00, 0xe9, 0x10, 0xb3, 0x18, 0x19, 0x1b, 0x79, 0xb6, 0x05, 0x9a, 0x40, 0x3c, 0x1f, 0x27, 0xec, 0x9c, 0xc9, + 0x0f, 0xcb, 0xe8, 0x41, 0x74, 0xe5, 0x10, 0x2c, 0x18, 0x2e, 0xef, 0xbc, 0xca, 0x6d, 0xa0, 0x68, 0x29, 0x29, 0x5e, + 0x27, 0x98, 0x67, 0x1b, 0x83, 0x36, 0xe7, 0x68, 0xd7, 0x87, 0xf5, 0x40, 0xa5, 0xda, 0xb6, 0x80, 0x97, 0xcc, 0xde, + 0x95, 0x10, 0x37, 0xe1, 0x3a, 0xcd, 0xb1, 0x69, 0xca, 0x8a, 0x62, 0x15, 0x58, 0x40, 0x13, 0xcf, 0xae, 0x9a, 0xd8, + 0xb5, 0x0e, 0x00, 0x40, 0x77, 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x3c, 0x86, 0x0d, 0x8e, 0xba, 0x2d, 0xe1, 0x18, + 0x84, 0x0f, 0xfb, 0xf6, 0x5b, 0x90, 0x25, 0x78, 0xa7, 0xc5, 0xd5, 0x9f, 0xf4, 0xa2, 0xe9, 0x95, 0xb0, 0x33, 0xe6, + 0x10, 0x9d, 0x8d, 0x61, 0xf4, 0x93, 0x81, 0x54, 0x36, 0xfc, 0xb4, 0x8a, 0x31, 0xd6, 0x32, 0xc2, 0xbf, 0xff, 0xcb, + 0x3f, 0xfe, 0x37, 0x18, 0x9b, 0xfa, 0xad, 0xe7, 0x02, 0x68, 0xf5, 0x3f, 0xa1, 0xd5, 0x3c, 0xbd, 0xa5, 0xdd, 0x5f, + 0xfe, 0xfe, 0xbf, 0x43, 0x33, 0xba, 0x28, 0x05, 0x7c, 0x42, 0x10, 0x0d, 0xd1, 0x36, 0xfd, 0x55, 0x20, 0xd5, 0x06, + 0x59, 0x3b, 0xd3, 0x3f, 0x21, 0xd8, 0x05, 0xcf, 0x66, 0x37, 0x82, 0x83, 0x50, 0x0f, 0x93, 0xac, 0x60, 0x1a, 0x1e, + 0xa1, 0x4f, 0x7e, 0x1d, 0x40, 0x34, 0xd7, 0x0c, 0x76, 0x6d, 0x61, 0xe9, 0x71, 0xc4, 0x0a, 0xad, 0xdc, 0x84, 0xf5, + 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, 0xda, + 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, 0x52, + 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, 0x48, + 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, 0x22, + 0xd2, 0x9a, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, 0x9f, + 0x85, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, 0x12, + 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, 0x97, + 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, 0x0c, + 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, 0x7f, + 0x83, 0x97, 0x1d, 0x91, 0x78, 0x64, 0x29, 0x14, 0x64, 0xd8, 0x30, 0x32, 0x6c, 0xa4, 0x46, 0x35, 0x6d, 0x0a, 0x74, + 0xfc, 0xb2, 0xd5, 0xb6, 0xc3, 0x31, 0x76, 0xaf, 0x69, 0x7f, 0x26, 0xb5, 0x7f, 0x2c, 0xed, 0x7d, 0xa9, 0xfd, 0xf1, + 0x93, 0x36, 0x0d, 0xed, 0x1f, 0xaf, 0xd5, 0xfe, 0x48, 0xb9, 0x01, 0x8e, 0x1c, 0xda, 0x9b, 0x18, 0xdd, 0x32, 0x6c, + 0x0d, 0xd4, 0xc4, 0x83, 0xe1, 0x84, 0x0d, 0x3f, 0x49, 0x33, 0x8b, 0x10, 0xc0, 0x40, 0x94, 0x36, 0x26, 0x05, 0x06, + 0x60, 0x32, 0x9c, 0x94, 0x7a, 0xd3, 0xe3, 0xa3, 0x31, 0x01, 0x73, 0x17, 0x63, 0x86, 0xa2, 0x1f, 0xd6, 0xec, 0x2b, + 0x56, 0x6e, 0xe1, 0x38, 0x62, 0xc3, 0x88, 0x67, 0xc0, 0x6c, 0x0b, 0x07, 0x3b, 0xf1, 0x16, 0x22, 0x58, 0x18, 0xd8, + 0xef, 0xdf, 0xed, 0x1f, 0xd8, 0xde, 0x69, 0x36, 0xba, 0x0a, 0x6c, 0x70, 0xc6, 0xc0, 0x9a, 0x72, 0x7d, 0x3e, 0x61, + 0xa9, 0xa3, 0x3c, 0x9f, 0x2c, 0x61, 0xe0, 0x00, 0x9e, 0x89, 0x6f, 0x5b, 0x34, 0x0f, 0x3a, 0x80, 0xb0, 0xf4, 0xf1, + 0xcb, 0xfe, 0x2e, 0x17, 0xdf, 0x85, 0xe5, 0x39, 0x3e, 0xf6, 0x31, 0xd5, 0x63, 0x77, 0x0b, 0x1e, 0xf0, 0x65, 0x1f, + 0xf5, 0x1e, 0xbd, 0x6d, 0x2c, 0x96, 0xdc, 0x86, 0x01, 0x0e, 0x31, 0xe9, 0x0b, 0x14, 0x0a, 0x6a, 0x75, 0x12, 0x20, + 0x62, 0xf0, 0x08, 0x63, 0x6d, 0xa9, 0x71, 0x11, 0x42, 0xd5, 0x5f, 0x3b, 0x2e, 0x95, 0xdd, 0x4a, 0xf3, 0x8e, 0xb0, + 0x01, 0x39, 0x2e, 0xd8, 0x7b, 0xa4, 0x4b, 0x84, 0xa9, 0x43, 0x45, 0xeb, 0x20, 0xd0, 0x35, 0x95, 0xb9, 0x22, 0x3a, + 0x18, 0xc0, 0x90, 0x99, 0x2b, 0x00, 0x81, 0xbf, 0x84, 0xf6, 0x89, 0xf9, 0xfd, 0x37, 0xf1, 0xa9, 0x26, 0x4d, 0x9c, + 0xc3, 0x3f, 0x79, 0x57, 0xcc, 0xbb, 0x3a, 0xa1, 0x96, 0x2a, 0xd8, 0x80, 0x51, 0x30, 0x0c, 0xca, 0xb4, 0x55, 0x54, + 0x09, 0xec, 0xb4, 0x24, 0x9a, 0x15, 0x2c, 0x50, 0x0f, 0x32, 0xee, 0x80, 0xe1, 0x8b, 0xe5, 0x40, 0x8f, 0x69, 0xcf, + 0x95, 0x7c, 0xb2, 0x30, 0x03, 0x13, 0x8f, 0xda, 0xed, 0x1e, 0x5e, 0xaa, 0x68, 0x45, 0x60, 0x1d, 0xa4, 0x41, 0xc2, + 0xc6, 0xbc, 0xe4, 0x78, 0x6b, 0x7f, 0xa1, 0x22, 0x41, 0x7e, 0x77, 0x27, 0x67, 0x53, 0xcb, 0xc7, 0xff, 0xbf, 0x6d, + 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, 0x0d, 0x19, + 0x46, 0xc9, 0x4a, 0x0e, 0xce, 0x37, 0x88, 0x9b, 0xdc, 0x6c, 0x07, 0x72, 0x7a, 0x29, 0x54, 0xb6, 0x1c, 0xac, 0xd9, + 0x76, 0xa5, 0x7f, 0xb4, 0xdc, 0x58, 0x45, 0xbc, 0xea, 0x6f, 0x4b, 0x14, 0x32, 0x62, 0x73, 0xa5, 0x50, 0x51, 0x0b, + 0xd1, 0xc3, 0xc4, 0x69, 0x39, 0x6a, 0x77, 0xab, 0xc5, 0x5c, 0x92, 0xb8, 0x38, 0x24, 0x71, 0x41, 0xe2, 0xef, 0x68, + 0x21, 0xe6, 0x1e, 0x46, 0xc9, 0xd0, 0x41, 0x00, 0xac, 0x96, 0xf5, 0x04, 0xa8, 0xe9, 0xaa, 0xc8, 0x91, 0xff, 0x18, + 0x89, 0x5b, 0x0a, 0x61, 0xb9, 0x82, 0x4a, 0x27, 0x47, 0x65, 0xd9, 0x63, 0xcc, 0x39, 0xfc, 0x20, 0x2f, 0x81, 0x88, + 0xbb, 0xbf, 0xfa, 0xfb, 0x89, 0xed, 0xd2, 0x3d, 0xf2, 0x7e, 0x36, 0x3e, 0x4a, 0x67, 0x2b, 0x66, 0xb7, 0x3d, 0x58, + 0x06, 0xb3, 0xa7, 0xfc, 0x84, 0xe4, 0x4d, 0x7d, 0x4d, 0x36, 0xa7, 0xfe, 0x3f, 0x87, 0x38, 0xc2, 0x1b, 0xc7, 0x46, + 0x13, 0x9d, 0x46, 0xbe, 0x6a, 0x11, 0x7f, 0xda, 0xd8, 0x55, 0x1c, 0x81, 0x7c, 0xbd, 0x2e, 0x92, 0xf5, 0xcd, 0xed, + 0x91, 0xac, 0xe2, 0x8e, 0x91, 0xac, 0x6f, 0x7e, 0xe7, 0x48, 0xd6, 0xd7, 0x66, 0x24, 0x0b, 0x05, 0xf4, 0xab, 0x5f, + 0x13, 0x6d, 0xca, 0xb3, 0x8b, 0x22, 0xec, 0xc8, 0xcc, 0x09, 0x90, 0x75, 0x18, 0x76, 0xfa, 0xeb, 0x47, 0x98, 0x60, + 0xa2, 0x46, 0x7c, 0x89, 0x02, 0x4a, 0x22, 0xd9, 0x13, 0xd4, 0x8a, 0x0c, 0xe7, 0xb4, 0x75, 0x56, 0x65, 0xeb, 0xa1, + 0xba, 0x46, 0x06, 0xae, 0xaf, 0xab, 0x43, 0x6d, 0x5d, 0x15, 0xf0, 0x09, 0xe8, 0x3b, 0xb0, 0xba, 0x63, 0x77, 0x53, + 0xa5, 0xf3, 0x99, 0x23, 0xf4, 0xd4, 0x29, 0x8d, 0x60, 0xa2, 0x85, 0xfd, 0x5f, 0x0e, 0x3b, 0xbd, 0xed, 0xce, 0x14, + 0x7a, 0x83, 0x02, 0x87, 0xb7, 0x76, 0x6f, 0x7b, 0x1b, 0xdf, 0x2e, 0xd4, 0x5b, 0x17, 0xdf, 0x62, 0xf5, 0xb6, 0x83, + 0x6f, 0x43, 0xf5, 0xf6, 0x08, 0xdf, 0x46, 0xea, 0xed, 0x31, 0xbe, 0x9d, 0xdb, 0xe5, 0x21, 0xd3, 0xc0, 0x3d, 0x06, + 0xbe, 0x22, 0x6f, 0x26, 0x50, 0x65, 0xb0, 0xe9, 0xf1, 0xc3, 0x08, 0xd1, 0x59, 0x10, 0x7b, 0xc2, 0xbb, 0x0c, 0x72, + 0xef, 0x02, 0x34, 0x4e, 0x40, 0xd9, 0x86, 0xcf, 0xf1, 0x3b, 0x1c, 0xe0, 0x24, 0x1d, 0xc4, 0x53, 0xa6, 0x3e, 0x48, + 0xac, 0xb0, 0x06, 0x03, 0xf6, 0xb0, 0x7d, 0x54, 0xf6, 0xf4, 0x3a, 0x89, 0x78, 0x96, 0xca, 0xe6, 0xa0, 0x95, 0xab, + 0xea, 0xc4, 0x74, 0x2d, 0xbd, 0xc2, 0x6b, 0xf4, 0x97, 0x11, 0x8f, 0x18, 0x83, 0x61, 0xd6, 0xba, 0x04, 0x0f, 0x76, + 0xa5, 0x4e, 0x43, 0x88, 0xb4, 0x4e, 0x23, 0x9c, 0xf4, 0xdb, 0x41, 0x74, 0xa6, 0x9f, 0xdf, 0x80, 0xa5, 0x1d, 0x9d, + 0xc9, 0x96, 0xeb, 0x75, 0x18, 0x81, 0x68, 0xea, 0x2f, 0x05, 0x04, 0x99, 0x62, 0xb0, 0x34, 0xe8, 0x49, 0x4b, 0xfd, + 0x85, 0xd4, 0xa9, 0x6b, 0x34, 0x9a, 0xbe, 0x5e, 0x04, 0x14, 0xad, 0x0a, 0x76, 0xc1, 0xe0, 0xa7, 0x52, 0x41, 0x61, + 0xa8, 0xc0, 0x02, 0x51, 0xbd, 0x46, 0x95, 0xe9, 0x60, 0xc3, 0x5a, 0x85, 0x66, 0x29, 0x5d, 0x66, 0x9e, 0xee, 0xe8, + 0xa3, 0x9d, 0x65, 0xf1, 0xfa, 0x59, 0x67, 0x88, 0xff, 0x49, 0xe1, 0xfd, 0xd9, 0x78, 0x3c, 0xbe, 0x51, 0xb7, 0x7d, + 0x36, 0x1a, 0xb3, 0x2e, 0xdb, 0xe9, 0x61, 0xe4, 0xbf, 0x25, 0xc5, 0x69, 0xa7, 0x24, 0xda, 0x2d, 0xee, 0xd6, 0x18, + 0x25, 0x2f, 0xa8, 0xbb, 0xbb, 0x2b, 0xc1, 0x12, 0xa8, 0xb2, 0x00, 0xe1, 0x7f, 0x16, 0xa7, 0x41, 0xbb, 0xf4, 0xcf, + 0xa5, 0xd6, 0xf8, 0xec, 0xc9, 0x93, 0x27, 0xa5, 0x3f, 0x52, 0x6f, 0xed, 0xd1, 0xa8, 0xf4, 0x87, 0x0b, 0x8d, 0x46, + 0xbb, 0x3d, 0x1e, 0x97, 0x7e, 0xac, 0x0a, 0xb6, 0xbb, 0xc3, 0xd1, 0x76, 0xb7, 0xf4, 0x2f, 0x8c, 0x16, 0xa5, 0xcf, + 0xe4, 0x5b, 0xce, 0x46, 0xb5, 0xe3, 0x83, 0xc7, 0x6d, 0xa8, 0x14, 0x8c, 0xb6, 0x40, 0xef, 0x52, 0x3c, 0x06, 0xd1, + 0x9c, 0x67, 0x60, 0xd8, 0x95, 0xbd, 0x02, 0xe4, 0xf3, 0x58, 0x4a, 0x78, 0xf1, 0xbd, 0x5f, 0x94, 0xea, 0xaf, 0x4c, + 0xa9, 0x8e, 0xcc, 0x4c, 0xd2, 0xbc, 0x20, 0x6d, 0xd0, 0xac, 0x46, 0xce, 0xa2, 0xea, 0x57, 0x61, 0x51, 0x09, 0x7b, + 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xd6, 0xc9, 0xf8, 0xef, 0x6f, 0x97, 0xf1, 0xa7, 0x77, 0x13, 0xf1, 0xdf, + 0xff, 0xce, 0x22, 0xfe, 0x07, 0x53, 0xc4, 0x0b, 0x21, 0xb6, 0x07, 0xa6, 0x33, 0xd9, 0xcc, 0xa7, 0xd9, 0x65, 0x0b, + 0xb7, 0x44, 0x6e, 0x93, 0xf4, 0x9c, 0xde, 0x49, 0xf8, 0xaf, 0xc8, 0x07, 0x53, 0x83, 0x19, 0x1f, 0x0f, 0xe6, 0xd9, + 0xd9, 0x59, 0xc2, 0x94, 0x8c, 0x37, 0x2a, 0xc8, 0x1c, 0x7f, 0x97, 0x86, 0xf6, 0x3b, 0xf4, 0x8c, 0xab, 0x92, 0xf1, + 0x18, 0x8a, 0xc6, 0x63, 0x5b, 0xe5, 0x4b, 0x83, 0x3c, 0xa3, 0x56, 0x6f, 0x6b, 0x25, 0xd4, 0xea, 0x8b, 0x2f, 0xcc, + 0x32, 0xb3, 0x40, 0x86, 0xf4, 0x4c, 0x63, 0x44, 0xd6, 0x8c, 0xe2, 0x02, 0xf7, 0x60, 0xf5, 0xb1, 0x63, 0xb4, 0x77, + 0xa6, 0xa0, 0x54, 0xe2, 0x21, 0x9e, 0x8b, 0x34, 0x3f, 0x2c, 0x23, 0x72, 0xdb, 0x97, 0x91, 0xab, 0xce, 0xbf, 0x8d, + 0x6f, 0x18, 0x56, 0x67, 0xde, 0xb0, 0xf8, 0x32, 0xbf, 0xe5, 0xe9, 0xd5, 0xab, 0x91, 0xb3, 0x87, 0x97, 0x7f, 0x8b, + 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, 0xec, 0x19, + 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, 0x92, 0x6e, + 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xd2, 0x79, 0x08, 0xcd, 0x30, + 0x2a, 0xd5, 0x19, 0x08, 0x10, 0x6e, 0x86, 0x9f, 0x68, 0x12, 0x43, 0xa8, 0x83, 0x82, 0x8a, 0x7a, 0xd7, 0xd7, 0xe6, + 0x97, 0x42, 0x6b, 0x5f, 0x95, 0x6c, 0xf0, 0x00, 0xc7, 0x4f, 0xfc, 0xa2, 0x36, 0xc8, 0xe6, 0xdc, 0xc1, 0x33, 0x80, + 0x05, 0x1e, 0x31, 0x78, 0x3b, 0xed, 0x36, 0xa8, 0x18, 0x5f, 0x7c, 0x07, 0xca, 0xd1, 0x9d, 0x05, 0xbe, 0x6c, 0xdd, + 0xb9, 0xc4, 0xd2, 0x77, 0xd9, 0x2a, 0x12, 0xdf, 0xbf, 0x2f, 0x11, 0x35, 0xee, 0x0e, 0xa9, 0x45, 0x6c, 0xbe, 0xfb, + 0xca, 0x77, 0x34, 0x08, 0xeb, 0xae, 0xe2, 0x60, 0x99, 0x5b, 0x5b, 0x2f, 0xc4, 0xb6, 0xc2, 0xaa, 0x59, 0x06, 0xe7, + 0x16, 0x9d, 0x59, 0x5c, 0x18, 0x01, 0xfc, 0xda, 0x36, 0x28, 0x55, 0x04, 0x5f, 0x84, 0xe1, 0xf7, 0xd0, 0xc5, 0x15, + 0x8e, 0xb7, 0x02, 0xba, 0xe1, 0xf2, 0x56, 0x90, 0xa3, 0x33, 0xac, 0x19, 0x5d, 0x55, 0xa9, 0x82, 0xd2, 0x3c, 0x82, + 0x31, 0x90, 0xa1, 0x48, 0x3a, 0xac, 0x71, 0x2a, 0xf4, 0x16, 0x4c, 0x43, 0x02, 0x58, 0xfb, 0x75, 0xe8, 0xd6, 0xd8, + 0x0a, 0x6c, 0x21, 0x2d, 0x40, 0xe9, 0x61, 0x87, 0xbe, 0x55, 0x03, 0x3d, 0x5d, 0x0e, 0xc0, 0xdf, 0xe8, 0xe4, 0x9d, + 0xf8, 0xc5, 0x85, 0x07, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, 0x86, + 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, 0x41, + 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, 0xdf, + 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, 0xd5, + 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0x7f, 0x46, 0xe6, 0x42, 0xb3, 0x98, 0x0e, 0xe0, 0xef, 0x02, + 0x59, 0x10, 0x8d, 0xf1, 0x0b, 0x8b, 0x77, 0x69, 0x79, 0x4a, 0xd9, 0xaf, 0x0b, 0x54, 0xeb, 0x41, 0xe7, 0x09, 0x78, + 0x7b, 0x77, 0x1e, 0xfe, 0x66, 0xf4, 0x4b, 0x49, 0x23, 0x75, 0x89, 0xd9, 0xb6, 0x7b, 0x28, 0x2f, 0x92, 0xe8, 0x0a, + 0x9c, 0x4e, 0xb2, 0x31, 0x4e, 0x31, 0x7a, 0xdc, 0x9b, 0x65, 0x32, 0x93, 0x24, 0x67, 0x09, 0xfd, 0x8c, 0x89, 0x5c, + 0x8a, 0xed, 0x47, 0xb3, 0x4b, 0xb5, 0x1a, 0x9d, 0x46, 0x86, 0xc8, 0xef, 0x9a, 0x08, 0xb2, 0x3e, 0xf3, 0xa4, 0x9e, + 0xcc, 0xb0, 0x03, 0x30, 0x08, 0xc3, 0xa6, 0x95, 0x0b, 0xa8, 0xda, 0x50, 0x62, 0xa4, 0xc2, 0x54, 0x03, 0x59, 0xfe, + 0x36, 0xa8, 0xca, 0xa8, 0x60, 0x3d, 0xfc, 0xd4, 0x65, 0x0c, 0xae, 0xad, 0x34, 0x9e, 0xa6, 0xf1, 0x68, 0x94, 0xb0, + 0x9e, 0xb2, 0x8f, 0xac, 0xce, 0x23, 0xcc, 0x24, 0x31, 0x97, 0xac, 0xbe, 0x2a, 0x06, 0xf1, 0x34, 0x9d, 0xa2, 0x53, + 0xb0, 0xd7, 0xf0, 0x7b, 0x95, 0x2b, 0xc9, 0x29, 0x53, 0x2c, 0xda, 0x15, 0xf1, 0xe8, 0xb9, 0x8e, 0xcb, 0x0e, 0x18, + 0x8b, 0xb4, 0xe0, 0xed, 0x1e, 0xcf, 0x66, 0x41, 0x6b, 0xbb, 0x8e, 0x08, 0x56, 0x69, 0x14, 0xbc, 0x15, 0x68, 0x79, + 0x68, 0x1d, 0x08, 0x2d, 0x67, 0xf9, 0x1d, 0x59, 0x46, 0x03, 0xe0, 0x37, 0x11, 0x75, 0x51, 0x59, 0x47, 0xe6, 0xaf, + 0xb3, 0x5b, 0x3e, 0x5f, 0xbd, 0x5b, 0x3e, 0x57, 0xbb, 0xe5, 0x66, 0x8e, 0xfd, 0x6c, 0xdc, 0xc1, 0xff, 0x7a, 0x15, + 0x42, 0xb0, 0x2a, 0x40, 0x0e, 0x0b, 0xed, 0xe2, 0x56, 0x17, 0xfe, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x9f, 0x0f, 0x16, + 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xd7, 0xae, 0x55, 0x75, 0x1e, 0x62, 0x1d, 0xf6, 0xda, 0x59, 0xae, 0xeb, 0xde, 0xbc, + 0x69, 0x41, 0x5e, 0x71, 0x27, 0x50, 0xc2, 0x18, 0x5c, 0xb5, 0xe8, 0xf4, 0x14, 0x4a, 0xc7, 0xd9, 0x70, 0x5e, 0xfc, + 0xad, 0x84, 0x5f, 0x12, 0xf1, 0xc6, 0x2d, 0xdd, 0x18, 0x47, 0x75, 0x15, 0x69, 0x49, 0x6a, 0x84, 0x85, 0x5e, 0xa7, + 0xa0, 0x00, 0xc6, 0x64, 0x4e, 0xd7, 0x7f, 0xb8, 0x62, 0x13, 0xfc, 0x7f, 0x59, 0x9b, 0x95, 0xc8, 0xfc, 0x47, 0x89, + 0x71, 0x23, 0x11, 0x7e, 0x15, 0x0d, 0xcc, 0x35, 0x6c, 0x3f, 0x59, 0x0d, 0xee, 0xa1, 0x9a, 0xe9, 0x48, 0x29, 0x05, + 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0xe6, 0x09, 0xbf, 0x79, 0xd4, 0x75, 0x9c, 0xb1, 0x34, 0xea, 0x0d, 0x02, 0xbd, 0x6a, + 0x7b, 0x47, 0x29, 0xfd, 0xd9, 0xe7, 0x0f, 0xf1, 0x3f, 0x11, 0x38, 0x3b, 0xad, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, + 0x68, 0x5a, 0x73, 0x7e, 0x84, 0x06, 0x27, 0xff, 0xe7, 0xae, 0xad, 0xd1, 0x58, 0xbf, 0x53, 0x73, 0x69, 0x95, 0xfe, + 0xaa, 0xd6, 0xbf, 0x6e, 0xf0, 0x3b, 0xb6, 0x1d, 0x0a, 0x87, 0xa0, 0xde, 0x56, 0xc6, 0x03, 0x97, 0x1a, 0x2b, 0x8a, + 0xdf, 0xb5, 0x7d, 0x65, 0x12, 0x53, 0x8f, 0x69, 0x78, 0xaa, 0x9d, 0x48, 0x79, 0x78, 0x8f, 0x3d, 0x84, 0x1f, 0xf9, + 0x25, 0x0b, 0x1f, 0xe0, 0xd7, 0xd8, 0xac, 0xcb, 0x69, 0x92, 0x82, 0x59, 0x35, 0xe1, 0x7c, 0x16, 0x6c, 0x6d, 0x5d, + 0x5c, 0x5c, 0xf8, 0x17, 0xdb, 0x7e, 0x96, 0x9f, 0x6d, 0x75, 0xdb, 0xed, 0x36, 0x7e, 0x44, 0xcb, 0xb6, 0xce, 0x63, + 0x76, 0xf1, 0x14, 0xdc, 0x0f, 0xfb, 0xb1, 0xf5, 0xc4, 0x7a, 0xbc, 0x6d, 0xed, 0x3c, 0xb2, 0x2d, 0x52, 0x00, 0x50, + 0xb2, 0x6d, 0x5b, 0x42, 0x01, 0x84, 0x36, 0x14, 0xf7, 0x77, 0xcf, 0x94, 0x0d, 0x87, 0x97, 0x14, 0x84, 0x85, 0x04, + 0xfe, 0x5b, 0xf6, 0x89, 0xd5, 0xb7, 0xba, 0x28, 0x6b, 0x49, 0x35, 0xa2, 0x5e, 0x71, 0xbf, 0x0f, 0xa3, 0x59, 0x40, + 0x6c, 0x64, 0x16, 0x62, 0x98, 0x4c, 0x94, 0xd2, 0x14, 0x68, 0x97, 0x9e, 0xc2, 0x13, 0x66, 0xb5, 0x59, 0xf0, 0xfc, + 0xa6, 0xfb, 0x18, 0x74, 0xdc, 0x79, 0xeb, 0xe1, 0xb0, 0xdd, 0xea, 0x58, 0x9d, 0x56, 0xd7, 0x7f, 0x6c, 0x75, 0xc5, + 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, 0xfd, + 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, 0xb8, + 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, 0xd0, + 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, 0xd8, + 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0x77, 0xbe, 0xfd, 0x64, + 0x08, 0x1a, 0xc1, 0xc2, 0x7f, 0xf0, 0xdf, 0x64, 0xa7, 0x3b, 0x14, 0x2f, 0x6d, 0xac, 0xff, 0xb6, 0xf3, 0xb8, 0x80, + 0xa6, 0xf8, 0xdf, 0x2f, 0xda, 0x84, 0x46, 0x03, 0xde, 0x1c, 0xf7, 0x21, 0xd0, 0xe8, 0xc9, 0xa4, 0xeb, 0x7f, 0x7e, + 0xfe, 0xd8, 0x7f, 0x32, 0xe9, 0x3c, 0xfe, 0x56, 0xbc, 0x25, 0x40, 0xc1, 0xcf, 0xf1, 0xdf, 0xb7, 0xdb, 0xed, 0x49, + 0xab, 0xe3, 0x3f, 0x39, 0xdf, 0xf6, 0xb7, 0x93, 0xd6, 0x23, 0xff, 0x09, 0xfe, 0xab, 0x86, 0x9b, 0x64, 0x53, 0x66, + 0x5b, 0xb8, 0xde, 0x0d, 0xbf, 0xd7, 0x9c, 0xa3, 0xfb, 0xd0, 0xda, 0x79, 0xf8, 0xf2, 0x09, 0xac, 0xd1, 0xa4, 0xd3, + 0x85, 0xff, 0x5f, 0xf7, 0xf8, 0x2d, 0x12, 0x5e, 0x0e, 0x1c, 0x31, 0x4c, 0x2f, 0x56, 0x84, 0xa3, 0x0f, 0xba, 0x3d, + 0xf0, 0xfe, 0xb4, 0x2e, 0x00, 0xc2, 0xf8, 0xad, 0x01, 0x10, 0xce, 0xef, 0x16, 0x01, 0xa1, 0x5f, 0x1b, 0xf8, 0x1d, + 0x23, 0x20, 0x7f, 0x6a, 0x06, 0xb9, 0x2f, 0xd9, 0x52, 0xa0, 0xa3, 0xe9, 0xac, 0xbd, 0x65, 0xce, 0xe1, 0x97, 0xf8, + 0xe3, 0x06, 0x65, 0x0f, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0x97, 0xf2, 0xe2, 0x43, 0xc1, 0xd7, 0x10, + 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, 0x29, + 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, 0xd3, + 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, 0x34, + 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, 0xa6, + 0xdf, 0xcf, 0x8a, 0x79, 0xc2, 0x30, 0x9d, 0x66, 0x28, 0x3e, 0x20, 0x0b, 0x8f, 0xf2, 0xae, 0x21, 0xa6, 0xb0, 0x7f, + 0x83, 0xe9, 0xf7, 0xea, 0xec, 0x60, 0x8a, 0x71, 0x84, 0x37, 0x6c, 0x14, 0x47, 0x8e, 0xed, 0xcc, 0x60, 0x23, 0xc3, + 0x2c, 0xad, 0x5a, 0xee, 0x3b, 0xa5, 0xbd, 0xbb, 0xb6, 0xfa, 0x69, 0xa6, 0x1c, 0x3f, 0x75, 0x17, 0x1e, 0xca, 0xb8, + 0xa3, 0x2d, 0x1d, 0x03, 0x18, 0x5f, 0x95, 0xe4, 0xa8, 0x03, 0x2a, 0x63, 0xc2, 0x16, 0xd6, 0x44, 0xc7, 0xef, 0x82, + 0x77, 0x41, 0xc5, 0xf8, 0xe9, 0xb0, 0xef, 0x9d, 0xd6, 0x36, 0x58, 0x3b, 0x46, 0x37, 0x3d, 0xd0, 0x91, 0xfe, 0xa5, + 0x1f, 0xfd, 0x6b, 0x74, 0xf5, 0x0b, 0x03, 0xb6, 0xe0, 0x88, 0xcf, 0x04, 0xee, 0xb6, 0xf8, 0x44, 0x83, 0x48, 0x28, + 0xc1, 0x0b, 0x73, 0x50, 0xe6, 0x98, 0xbf, 0x4a, 0x26, 0x3e, 0x4d, 0x26, 0x7e, 0x80, 0xb0, 0xac, 0x9a, 0x70, 0x77, + 0x41, 0x67, 0x23, 0xf8, 0x23, 0x9a, 0x98, 0x68, 0x8a, 0xa1, 0xf2, 0xd0, 0xa0, 0x29, 0xbe, 0xbb, 0x35, 0x22, 0x73, + 0x4f, 0x03, 0x44, 0x04, 0x0e, 0xe5, 0xdf, 0xaa, 0x58, 0x3d, 0xc8, 0xa0, 0x16, 0x38, 0xfa, 0xf8, 0xb3, 0x2f, 0xf4, + 0x67, 0x29, 0x64, 0x26, 0x02, 0x21, 0x8d, 0xd2, 0x6a, 0xa8, 0x2a, 0x34, 0x56, 0x3c, 0xbd, 0x3a, 0x90, 0xdf, 0x3c, + 0xb0, 0x31, 0x4a, 0x4d, 0xa7, 0x13, 0xd5, 0xf7, 0xd6, 0x36, 0x41, 0x35, 0xd2, 0xaf, 0xa0, 0x52, 0x82, 0x01, 0x6a, + 0x3f, 0xbc, 0x72, 0x60, 0x49, 0x2f, 0x29, 0xb4, 0x85, 0xee, 0x1b, 0xb1, 0xf3, 0x78, 0x28, 0x55, 0x98, 0x67, 0xc9, + 0xab, 0x52, 0x2d, 0x5a, 0x9a, 0xb0, 0xe3, 0x89, 0x38, 0x01, 0xbc, 0xa0, 0x06, 0x0f, 0xd3, 0xcc, 0xee, 0x3f, 0xe8, + 0xad, 0x23, 0x3e, 0xfe, 0x24, 0xeb, 0x21, 0xf8, 0xa5, 0x7f, 0x1b, 0x3e, 0xc0, 0x1f, 0x65, 0x7d, 0x70, 0x64, 0xbb, + 0x3e, 0x29, 0x80, 0x07, 0xd5, 0x2f, 0xb3, 0xa2, 0xf4, 0xdb, 0x04, 0x5d, 0xed, 0xdd, 0x55, 0x69, 0x4b, 0x05, 0xdd, + 0xdd, 0xa9, 0x14, 0x34, 0x3c, 0x1b, 0x12, 0x19, 0x94, 0x45, 0xd7, 0xdf, 0x31, 0xc4, 0xfe, 0x79, 0x0b, 0xff, 0xd6, + 0x04, 0xff, 0x43, 0x68, 0xa0, 0x24, 0xff, 0x6b, 0x68, 0xbe, 0x2d, 0x94, 0x0c, 0xf4, 0xfb, 0x81, 0xc4, 0xb2, 0x10, + 0xc9, 0xf5, 0x6d, 0xb0, 0xe2, 0xc0, 0x4c, 0x24, 0x63, 0xd8, 0x9e, 0x11, 0x5b, 0x13, 0xbb, 0x52, 0x46, 0x8e, 0x9e, + 0x43, 0x5f, 0x47, 0x7f, 0xc6, 0x7c, 0x55, 0x9d, 0x57, 0x93, 0x12, 0x2b, 0xa6, 0xc0, 0x7d, 0xdd, 0x38, 0x94, 0xeb, + 0x89, 0x3c, 0x6f, 0xfd, 0x1d, 0x94, 0xf5, 0x0c, 0x2d, 0x13, 0xc2, 0x5d, 0x43, 0x44, 0x30, 0xfa, 0xd4, 0x2a, 0x4d, + 0xf2, 0x6a, 0x54, 0x36, 0xe7, 0x07, 0xb3, 0x06, 0x7f, 0x97, 0xb2, 0xba, 0xe5, 0x23, 0xaf, 0xef, 0x62, 0xca, 0xc5, + 0x28, 0xce, 0xe9, 0x56, 0xb8, 0x02, 0xbd, 0x16, 0x78, 0xad, 0xa8, 0x44, 0x52, 0x82, 0x15, 0x03, 0x1b, 0x8b, 0xec, + 0x40, 0x26, 0x06, 0x9a, 0xdf, 0x1a, 0x37, 0xaf, 0xed, 0x8e, 0x44, 0x4e, 0x20, 0xfe, 0x16, 0x83, 0x2d, 0xe8, 0x63, + 0x83, 0xb4, 0x5d, 0xbb, 0x4b, 0xc8, 0x06, 0x43, 0x5c, 0xab, 0x1f, 0xd7, 0x32, 0x05, 0x90, 0x6d, 0x12, 0x5a, 0x8f, + 0x4b, 0x24, 0x74, 0x25, 0x9d, 0x4e, 0x59, 0xc4, 0xfd, 0x28, 0xa5, 0xfc, 0x2d, 0xc7, 0x10, 0x53, 0x5e, 0x87, 0x6d, + 0xbb, 0x25, 0xc8, 0x46, 0xe3, 0xd7, 0xc7, 0xe4, 0xee, 0x86, 0x42, 0xfd, 0xe5, 0xab, 0x7a, 0x2e, 0xf6, 0xa4, 0xdb, + 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, 0xe4, 0xc1, 0x8b, 0x54, 0x96, 0x50, 0xa4, 0xb2, + 0x58, 0x22, 0x01, 0x4e, 0xe4, 0x2e, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, 0xa5, 0x43, 0x11, 0x7a, 0x9c, 0x82, 0x97, 0x13, + 0xe3, 0xf7, 0xe9, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x59, 0x41, 0xca, 0xae, 0xe1, 0xa9, 0x0a, 0x54, 0x82, + 0x35, 0xc2, 0x54, 0x82, 0x90, 0x1c, 0x4a, 0xe7, 0x25, 0x2f, 0xb7, 0x2e, 0xe6, 0xa7, 0x53, 0x90, 0x93, 0x2a, 0xa9, + 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x49, 0x55, 0xdf, 0x0e, 0x6f, 0xfc, 0xce, 0xaa, 0xc0, + 0x5e, 0xea, 0x05, 0xcc, 0x49, 0x99, 0x6c, 0x1b, 0x39, 0x29, 0x46, 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, + 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x9b, 0xad, 0x5a, 0x4e, 0x0e, 0x28, 0xbf, 0x5c, 0xdc, 0xeb, 0x90, 0x00, 0xc3, 0x0a, + 0x02, 0x4c, 0xd2, 0x04, 0xb0, 0xe8, 0xe8, 0xdb, 0xde, 0x69, 0xab, 0xb4, 0x5d, 0x28, 0xc3, 0x0d, 0x29, 0xba, 0x18, + 0x93, 0xd4, 0xc2, 0xbf, 0x93, 0x4e, 0x7f, 0x37, 0x92, 0xc6, 0x25, 0x0a, 0x8f, 0x02, 0xa4, 0x07, 0x74, 0x46, 0x0b, + 0xce, 0x8f, 0xb3, 0xad, 0x0b, 0x76, 0xda, 0x8a, 0x66, 0x71, 0x15, 0x6b, 0x45, 0x53, 0x43, 0x4f, 0x99, 0x55, 0x33, + 0xe1, 0x63, 0xd4, 0x40, 0x92, 0x04, 0x77, 0x29, 0x03, 0xb9, 0x64, 0xa1, 0x03, 0x0b, 0x01, 0x85, 0x49, 0xae, 0xab, + 0x80, 0xaf, 0xd4, 0xb8, 0xa5, 0xdd, 0xff, 0xcb, 0x3f, 0xff, 0x6f, 0x19, 0xc3, 0x05, 0xaa, 0x74, 0xd4, 0x58, 0x0d, + 0x42, 0x97, 0xbb, 0x98, 0x02, 0x55, 0x9d, 0xf2, 0xb2, 0xcb, 0xd6, 0x59, 0x1e, 0x8f, 0x5a, 0x93, 0x28, 0x19, 0x03, + 0x60, 0x6b, 0x09, 0x64, 0x26, 0x48, 0x48, 0xa8, 0xeb, 0x45, 0xc8, 0x82, 0xbf, 0x29, 0x11, 0x5b, 0x25, 0xc0, 0xd3, + 0x6e, 0x35, 0xd3, 0xb2, 0xab, 0x0d, 0x55, 0x4b, 0xcd, 0x56, 0x3f, 0x5c, 0xa6, 0x84, 0x5a, 0x2d, 0x2f, 0x1b, 0x5a, + 0xea, 0xc3, 0xa8, 0x7f, 0xff, 0x97, 0x7f, 0xf8, 0x1f, 0xea, 0x15, 0xcf, 0x98, 0xfe, 0xf2, 0x4f, 0x7f, 0x87, 0x29, + 0xd0, 0x96, 0x3e, 0x87, 0x22, 0x39, 0x61, 0x55, 0x87, 0x50, 0x42, 0x60, 0x58, 0x95, 0xd3, 0x57, 0xcf, 0xdf, 0xde, + 0xa7, 0x09, 0x69, 0xb3, 0x49, 0xe8, 0x68, 0xd3, 0x96, 0x15, 0x8f, 0xd4, 0x48, 0x4e, 0xbc, 0x08, 0x95, 0x48, 0xef, + 0x3b, 0x25, 0x47, 0xf9, 0x7a, 0x35, 0x16, 0x2a, 0x42, 0x88, 0x25, 0x65, 0x55, 0x6e, 0x61, 0xe8, 0x7e, 0x81, 0xaf, + 0x41, 0xd7, 0x28, 0xa6, 0xc5, 0xab, 0xf5, 0xe9, 0xfd, 0x34, 0x07, 0xf8, 0xc7, 0x48, 0x71, 0x11, 0x87, 0xa4, 0x63, + 0xe9, 0x16, 0xda, 0x7c, 0xc9, 0x55, 0x49, 0xa3, 0x08, 0x47, 0xf1, 0xe1, 0x93, 0xbf, 0x29, 0xff, 0x38, 0x45, 0xcb, + 0xca, 0x72, 0xa6, 0xd1, 0xa5, 0x74, 0x1f, 0x1f, 0xb5, 0xdb, 0xb3, 0x4b, 0x77, 0x51, 0xcd, 0xe0, 0xad, 0x9b, 0x8c, + 0x62, 0x97, 0xe6, 0x80, 0x74, 0x9e, 0xad, 0xc3, 0xa4, 0xe0, 0x31, 0xb5, 0x31, 0xaa, 0x56, 0x96, 0x7f, 0x58, 0x50, + 0xa4, 0x2e, 0xfe, 0x05, 0xcf, 0x9d, 0x65, 0x50, 0x13, 0x4a, 0x0c, 0x2c, 0x16, 0x46, 0xaf, 0xae, 0xe8, 0x35, 0xe9, + 0x2c, 0xa7, 0x0d, 0x99, 0xe7, 0xe6, 0xe6, 0x89, 0xf7, 0x43, 0x3c, 0xc3, 0x9e, 0x74, 0xbc, 0x49, 0x77, 0xa1, 0x87, + 0xe7, 0x3c, 0x9b, 0x9a, 0x07, 0xe5, 0x2c, 0x62, 0x43, 0x36, 0x56, 0xc1, 0x60, 0x59, 0x2f, 0x0e, 0xc1, 0xcb, 0xc9, + 0xf6, 0x8a, 0xb9, 0x24, 0x48, 0x74, 0x40, 0x0e, 0xf0, 0x7c, 0x86, 0x1b, 0x10, 0xe8, 0x9f, 0x45, 0x3c, 0x20, 0x7e, + 0xed, 0x99, 0xc7, 0xed, 0x11, 0x4a, 0x99, 0x6c, 0x61, 0xc0, 0xd3, 0x13, 0x4d, 0x31, 0x2c, 0x5b, 0x4f, 0xdb, 0x2a, + 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0xa2, 0x3a, 0xdf, 0xca, 0x53, 0xec, 0xa7, 0xb5, 0x70, 0x88, 0x54, 0x31, 0x5d, 0xd7, + 0x5b, 0x59, 0x2f, 0x34, 0xb5, 0xa8, 0xfd, 0x16, 0x0c, 0x30, 0x02, 0xd3, 0x6e, 0xb6, 0xa2, 0x42, 0x6c, 0xf5, 0x34, + 0xfc, 0x56, 0xbb, 0x3e, 0xd1, 0x6c, 0x46, 0x0d, 0x5d, 0x60, 0x62, 0x32, 0x58, 0x51, 0x76, 0x50, 0x86, 0x86, 0x48, + 0x88, 0x90, 0x6d, 0xe4, 0x46, 0x10, 0x4f, 0x32, 0x55, 0x02, 0x7f, 0x72, 0xa2, 0xff, 0xff, 0x00, 0x69, 0x5b, 0x88, + 0x58, 0x18, 0x7f, 0x00, 0x00}; } // namespace web_server } // namespace esphome From d9398a91d1dac8e95e7a7e135a24be50e124bc5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Vl=C3=A9rick?= Date: Mon, 26 Jun 2023 22:09:52 +0200 Subject: [PATCH 0147/2607] update dsmr to 0.7 (#5011) --- esphome/components/dsmr/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index f4f8305ba6..af41b2aa6f 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -84,7 +84,7 @@ async def to_code(config): cg.add_build_flag("-DDSMR_GAS_MBUS_ID=" + str(config[CONF_GAS_MBUS_ID])) # DSMR Parser - cg.add_library("glmnet/Dsmr", "0.5") + cg.add_library("glmnet/Dsmr", "0.7") # Crypto cg.add_library("rweather/Crypto", "0.4.0") diff --git a/platformio.ini b/platformio.ini index ab16d47c6f..868880e1d7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -62,7 +62,7 @@ lib_deps = fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps freekode/TM1651@1.0.1 ; tm1651 - glmnet/Dsmr@0.5 ; dsmr + glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr dudanov/MideaUART@1.1.8 ; midea tonia/HeatpumpIR@1.0.20 ; heatpumpir From bd9a4ff8dedc397eca8159e6c809eeff7f43efb0 Mon Sep 17 00:00:00 2001 From: jerome992 <35580081+jerome992@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:35:20 +0200 Subject: [PATCH 0148/2607] add water delivered to dsmr component (#4237) Co-authored-by: Jerome --- esphome/components/dsmr/__init__.py | 3 +++ esphome/components/dsmr/sensor.py | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index af41b2aa6f..d3d20ca2a7 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -19,6 +19,7 @@ CONF_CRC_CHECK = "crc_check" CONF_DECRYPTION_KEY = "decryption_key" CONF_DSMR_ID = "dsmr_id" CONF_GAS_MBUS_ID = "gas_mbus_id" +CONF_WATER_MBUS_ID = "water_mbus_id" CONF_MAX_TELEGRAM_LENGTH = "max_telegram_length" CONF_REQUEST_INTERVAL = "request_interval" CONF_REQUEST_PIN = "request_pin" @@ -53,6 +54,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DECRYPTION_KEY): _validate_key, cv.Optional(CONF_CRC_CHECK, default=True): cv.boolean, cv.Optional(CONF_GAS_MBUS_ID, default=1): cv.int_, + cv.Optional(CONF_WATER_MBUS_ID, default=2): cv.int_, cv.Optional(CONF_MAX_TELEGRAM_LENGTH, default=1500): cv.int_, cv.Optional(CONF_REQUEST_PIN): pins.gpio_output_pin_schema, cv.Optional( @@ -82,6 +84,7 @@ async def to_code(config): cg.add(var.set_receive_timeout(config[CONF_RECEIVE_TIMEOUT].total_milliseconds)) cg.add_build_flag("-DDSMR_GAS_MBUS_ID=" + str(config[CONF_GAS_MBUS_ID])) + cg.add_build_flag("-DDSMR_WATER_MBUS_ID=" + str(config[CONF_WATER_MBUS_ID])) # DSMR Parser cg.add_library("glmnet/Dsmr", "0.7") diff --git a/esphome/components/dsmr/sensor.py b/esphome/components/dsmr/sensor.py index 0b0439baa4..2e2050ecab 100644 --- a/esphome/components/dsmr/sensor.py +++ b/esphome/components/dsmr/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_GAS, DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, + DEVICE_CLASS_WATER, STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, UNIT_AMPERE, @@ -236,6 +237,12 @@ CONFIG_SCHEMA = cv.Schema( device_class=DEVICE_CLASS_GAS, state_class=STATE_CLASS_TOTAL_INCREASING, ), + cv.Optional("water_delivered"): sensor.sensor_schema( + unit_of_measurement=UNIT_CUBIC_METER, + accuracy_decimals=3, + device_class=DEVICE_CLASS_WATER, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), } ).extend(cv.COMPONENT_SCHEMA) From 8f4abf6a63dc2b674a0173d858ed5dace2688469 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:34:31 +1200 Subject: [PATCH 0149/2607] Update sync workflow (#5017) --- .github/workflows/sync-device-classes.yml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 896a0369ac..7067300826 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -6,14 +6,12 @@ on: schedule: - cron: '45 6 * * *' -permissions: - contents: write - pull-requests: write jobs: sync: name: Sync Device Classes runs-on: ubuntu-latest + if: github.repository == 'esphome/esphome' steps: - name: Checkout uses: actions/checkout@v3 @@ -38,15 +36,6 @@ jobs: run: | python ./script/sync-device_class.py - - name: Get PR template - id: pr-template-body - run: | - body=$(cat .github/PULL_REQUEST_TEMPLATE.md) - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - echo "$body" >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Commit changes uses: peter-evans/create-pull-request@v5 with: @@ -56,5 +45,5 @@ jobs: branch: sync/device-classes delete-branch: true title: "Synchronise Device Classes from Home Assistant" - body: ${{ steps.pr-template-body.outputs.body }} + body-path: .github/PULL_REQUEST_TEMPLATE.md token: ${{ secrets.DEVICE_CLASS_SYNC_TOKEN }} From 9d21cccac13b366d63fd2eede5acafedaf34427a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:40:08 +1200 Subject: [PATCH 0150/2607] Bump aioesphomeapi from 14.1.0 to 15.0.0 (#5012) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a2ef604446..d4b96ada64 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6 click==8.1.3 esphome-dashboard==20230621.0 -aioesphomeapi==14.1.0 +aioesphomeapi==15.0.0 zeroconf==0.69.0 # esp-idf requires this, but doesn't bundle it by default From 8ce98dd15a519d5472372d22e5648f7fde9295c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:41:02 +1200 Subject: [PATCH 0151/2607] Bump pyupgrade from 3.4.0 to 3.7.0 (#4971) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 617d6f5d9f..9d2eb2908f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - --branch=release - --branch=beta - repo: https://github.com/asottile/pyupgrade - rev: v3.4.0 + rev: v3.7.0 hooks: - id: pyupgrade args: [--py39-plus] diff --git a/requirements_test.txt b/requirements_test.txt index 66ce075f91..4f3a32456b 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ pylint==2.17.4 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating black==23.3.0 # also change in .pre-commit-config.yaml when updating -pyupgrade==3.4.0 # also change in .pre-commit-config.yaml when updating +pyupgrade==3.7.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests From 108fabe18f1c3a3853d714abbd65a01c07d2f0d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:41:39 +1200 Subject: [PATCH 0152/2607] Bump pytest from 7.3.2 to 7.4.0 (#5000) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 4f3a32456b..23131fd64b 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.7.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==7.3.2 +pytest==7.4.0 pytest-cov==4.1.0 pytest-mock==3.10.0 pytest-asyncio==0.21.0 From 9a149a7aba4b55b1715ea286bdc35fefda8398f1 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Wed, 28 Jun 2023 10:19:36 +1200 Subject: [PATCH 0153/2607] Synchronise Device Classes from Home Assistant (#5018) --- esphome/components/button/__init__.py | 2 ++ esphome/const.py | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 55f2fe794a..a999c6d91e 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_MQTT_ID, DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ) @@ -24,6 +25,7 @@ IS_PLATFORM_COMPONENT = True DEVICE_CLASSES = [ DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ] diff --git a/esphome/const.py b/esphome/const.py index c8b85fcdeb..3145255e20 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -968,6 +968,7 @@ DEVICE_CLASS_GAS = "gas" DEVICE_CLASS_GATE = "gate" DEVICE_CLASS_HEAT = "heat" DEVICE_CLASS_HUMIDITY = "humidity" +DEVICE_CLASS_IDENTIFY = "identify" DEVICE_CLASS_ILLUMINANCE = "illuminance" DEVICE_CLASS_IRRADIANCE = "irradiance" DEVICE_CLASS_LIGHT = "light" From c82be2cd60a660034a01f1157558844b2bfb903c Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Tue, 27 Jun 2023 20:13:14 -0300 Subject: [PATCH 0154/2607] Fixes compressed downloads (#5014) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/dashboard/dashboard.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 22bbe0aae9..dd800f534c 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -546,22 +546,11 @@ class DownloadBinaryRequestHandler(BaseHandler): return with open(path, "rb") as f: - while True: - # For a 528KB image used as benchmark: - # - using 256KB blocks resulted in the smallest file size. - # - blocks larger than 256KB didn't improve the size of compressed file. - # - blocks smaller than 256KB hindered compression, making the output file larger. + data = f.read() + if compressed: + data = gzip.compress(data, 9) + self.write(data) - # Read file in blocks of 256KB. - data = f.read(256 * 1024) - - if not data: - break - - if compressed: - data = gzip.compress(data, 9) - - self.write(data) self.finish() From 68119ddcd4a8cd6c5a09fb83507c423a9d307ba5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:34:08 +1200 Subject: [PATCH 0155/2607] Attempt to fix script parameters (#4627) --- esphome/components/script/__init__.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py index 6337d89bcd..78b23e7b5e 100644 --- a/esphome/components/script/__init__.py +++ b/esphome/components/script/__init__.py @@ -33,6 +33,7 @@ SCRIPT_MODES = { PARAMETER_TYPE_TRANSLATIONS = { "string": "std::string", + "boolean": "bool", } @@ -149,6 +150,16 @@ async def to_code(config): ), ) async def script_execute_action_to_code(config, action_id, template_arg, args): + def convert(type: str): + def converter(value): + if type == "std::string": + return value + if type == "bool": + return cg.RawExpression(str(value).lower()) + return cg.RawExpression(str(value)) + + return converter + async def get_ordered_args(config, script_params): config_args = config.copy() config_args.pop(CONF_ID) @@ -160,7 +171,9 @@ async def script_execute_action_to_code(config, action_id, template_arg, args): raise EsphomeError( f"Missing parameter: '{name}' in script.execute {config[CONF_ID]}" ) - arg = await cg.templatable(config_args[name], args, type) + arg = await cg.templatable( + config_args[name], args, type, convert(str(type)) + ) script_args.append(arg) return script_args From 951157dc263787a68e7a69690fe89797001c6449 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:35:35 +1200 Subject: [PATCH 0156/2607] Add CONFIG_BT_BLE_42_FEATURES_SUPPORTED for ble (#5008) --- esphome/components/esp32_ble/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index f508cecb87..b4cb595da0 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -55,3 +55,4 @@ async def to_code(config): if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) + add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) From ac5246e21dbf4d119b380f1621bf418b0523a631 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 12:22:14 +1200 Subject: [PATCH 0157/2607] Remove yaml test cache (#5019) --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 105f0f12b8..7775a996fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -241,12 +241,6 @@ jobs: with: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - - name: Cache platformio - uses: actions/cache@v3.3.1 - with: - path: ~/.platformio - # yamllint disable-line rule:line-length - key: platformio-test${{ matrix.file }}-${{ hashFiles('platformio.ini') }} - name: Run esphome compile tests/test${{ matrix.file }}.yaml run: | . venv/bin/activate From 604d4eec792b277e1a979aeaa34f2c6ef629d53d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:27:03 +1200 Subject: [PATCH 0158/2607] Update webserver to 56d73b5 (#5007) --- esphome/components/web_server/server_index.h | 1179 +++++++++--------- 1 file changed, 590 insertions(+), 589 deletions(-) diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 4e6e136f8c..2dbb839c5e 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,596 +6,597 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, - 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x28, 0x58, 0x5d, 0x05, 0x5c, 0x81, 0x10, 0x49, 0x95, 0xaa, 0xca, 0xa0, 0x40, 0x5e, - 0xd5, 0x62, 0x57, 0xd9, 0xb5, 0xb9, 0xa4, 0xb2, 0xaf, 0x2d, 0xeb, 0x4a, 0x10, 0x99, 0x14, 0xe1, 0x02, 0x01, 0x1a, - 0x48, 0x6a, 0x31, 0x85, 0x3e, 0xfd, 0xd4, 0x4f, 0x7d, 0xce, 0x6c, 0xfd, 0xd0, 0x0f, 0xd3, 0xa7, 0xfb, 0x61, 0x3e, - 0x62, 0x9e, 0xfb, 0x53, 0xee, 0x0f, 0x4c, 0x7f, 0xc2, 0x44, 0x44, 0x2e, 0x48, 0x80, 0xa4, 0x24, 0xbb, 0x7d, 0xe7, - 0x78, 0x11, 0x90, 0x6b, 0x44, 0x64, 0x64, 0x6c, 0x19, 0x09, 0xee, 0xde, 0x1b, 0x65, 0x43, 0x7e, 0x35, 0x63, 0xd6, - 0x84, 0x4f, 0x93, 0xfe, 0xae, 0xfc, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, 0x78, - 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, 0x53, - 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, 0xc7, - 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, 0xfe, - 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, 0xc4, - 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, 0x8b, - 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, 0x4f, - 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, 0x69, - 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf3, 0xb8, 0x17, 0xbb, 0x61, 0x9f, 0x5b, 0x71, 0x6a, 0xb1, 0xc1, 0x0b, 0x46, 0x25, - 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, 0x7c, - 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xb0, 0x43, 0x7e, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, 0x8c, - 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbf, 0xbe, 0x76, 0x78, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, 0x51, - 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xfc, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, 0x99, - 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xee, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, 0xe9, - 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, 0x28, - 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, 0x0c, - 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, 0xc0, - 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, 0x90, - 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, 0xbe, - 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, 0x58, - 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, 0xc6, - 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdf, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, 0xb3, - 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, 0x05, - 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, 0x41, - 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xac, 0x04, - 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0x60, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, 0x9c, - 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x06, 0x9a, 0x38, 0xd0, 0xb6, 0x68, 0xb4, 0xf5, 0x04, 0xe2, 0x35, 0x12, 0xb9, 0x1e, - 0xf3, 0x25, 0xf9, 0xf6, 0xaf, 0xd2, 0x61, 0x7d, 0x6c, 0xa8, 0x2c, 0x79, 0xb6, 0xcf, 0xf3, 0x38, 0x3d, 0x03, 0x20, - 0xe4, 0x4c, 0x66, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x2c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, 0x7a, - 0xd8, 0x61, 0x88, 0xa4, 0x07, 0x06, 0x63, 0x03, 0x16, 0xb0, 0x4d, 0xdb, 0xf6, 0xbe, 0x73, 0xbd, 0x2b, 0xe4, 0x20, - 0xdf, 0xf7, 0x89, 0x7d, 0x45, 0xe7, 0x38, 0xec, 0x20, 0xd0, 0x7e, 0xc2, 0xd2, 0x33, 0x3e, 0x19, 0xb0, 0xc3, 0xf6, - 0x51, 0xc0, 0x01, 0xaa, 0xd1, 0x7c, 0xc8, 0x1c, 0xe4, 0x47, 0x2f, 0xc7, 0xed, 0xb3, 0xe9, 0xc0, 0x14, 0xb8, 0x30, - 0xf7, 0x08, 0xc7, 0xda, 0xd2, 0xb8, 0x8a, 0x45, 0x15, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, 0x70, - 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, 0x37, - 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0x64, 0x87, 0xf9, 0x66, 0xe7, 0xc8, 0x43, - 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0x98, 0xbf, 0xcc, 0xc7, - 0x21, 0xf7, 0xa7, 0xd1, 0x0c, 0xb1, 0x61, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, - 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, 0x39, - 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, - 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, 0x73, - 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, 0xd5, - 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, 0xc0, - 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x87, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, 0x19, - 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xf2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, 0xd0, - 0x9f, 0x81, 0x0c, 0xec, 0xa1, 0xe0, 0xfa, 0x4a, 0x4a, 0x9d, 0x88, 0x29, 0x0c, 0x81, 0x00, 0x43, 0x94, 0x20, 0x92, - 0x06, 0xef, 0xb3, 0xe4, 0x6a, 0x1c, 0x27, 0xc9, 0xfe, 0x7c, 0x36, 0xcb, 0x72, 0xee, 0x7d, 0x1d, 0x2e, 0x78, 0x56, - 0xe1, 0x4a, 0x9b, 0xbc, 0xb8, 0x88, 0x39, 0x12, 0xd4, 0x5d, 0x0c, 0x23, 0x58, 0xea, 0xa7, 0x59, 0x96, 0xb0, 0x28, - 0x05, 0x34, 0xd8, 0xc0, 0xb6, 0x83, 0x74, 0x9e, 0x24, 0xbd, 0x53, 0x18, 0xf6, 0x53, 0x8f, 0xaa, 0x85, 0xc4, 0x0f, - 0xe8, 0x79, 0x2f, 0xcf, 0xa3, 0x2b, 0x68, 0x88, 0x6d, 0x80, 0x17, 0x61, 0xb5, 0xbe, 0xda, 0x7f, 0xf7, 0xd6, 0x17, - 0x8c, 0x1f, 0x8f, 0xaf, 0x00, 0xd0, 0xb2, 0x92, 0x9a, 0xe3, 0x3c, 0x9b, 0x36, 0xa6, 0x46, 0x3a, 0xc4, 0x21, 0xeb, - 0xad, 0x01, 0x21, 0xa6, 0x91, 0x61, 0x95, 0x98, 0x09, 0xc1, 0x5b, 0xe2, 0x67, 0x59, 0x89, 0x7b, 0x60, 0x80, 0x0f, - 0x81, 0x28, 0x86, 0x29, 0x6f, 0x86, 0x96, 0xe7, 0x57, 0x8b, 0x38, 0x24, 0x38, 0x67, 0xa8, 0x7f, 0x11, 0xc6, 0x61, - 0x04, 0xb3, 0x2f, 0xc4, 0x80, 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xa2, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x0e, - 0xdb, 0xe8, 0xfa, 0x9a, 0xc1, 0x8b, 0xeb, 0x7d, 0x13, 0x2e, 0x22, 0x85, 0x0f, 0x6a, 0x28, 0xdc, 0x5f, 0x81, 0x90, - 0x13, 0xa8, 0xc9, 0xce, 0x41, 0x0f, 0x02, 0x9c, 0x5f, 0x83, 0xfa, 0x1b, 0x27, 0x08, 0xc5, 0xbd, 0x8e, 0x07, 0x1a, - 0xf4, 0xd9, 0x24, 0x4a, 0xcf, 0xd8, 0x28, 0x98, 0xb0, 0x52, 0x4a, 0xde, 0x3d, 0x0b, 0xd6, 0x18, 0xd8, 0xa9, 0xb0, - 0x5e, 0x1e, 0xbc, 0x79, 0x2d, 0x57, 0xae, 0x26, 0x8c, 0x61, 0x91, 0xe6, 0xa0, 0x56, 0x41, 0x6c, 0x4b, 0x71, 0xfc, - 0x82, 0x2b, 0xe9, 0x2d, 0x4a, 0xe2, 0xe2, 0xe3, 0x0c, 0x4c, 0x0c, 0xf6, 0x1e, 0x86, 0x81, 0xe9, 0x43, 0x98, 0x8a, - 0xca, 0x61, 0x3e, 0x51, 0x31, 0xd2, 0x45, 0xd0, 0x59, 0x60, 0x2a, 0x5e, 0x33, 0xc7, 0x2d, 0x81, 0x55, 0x79, 0x3c, - 0xb4, 0xa2, 0xd1, 0xe8, 0x55, 0x1a, 0xf3, 0x38, 0x4a, 0xe2, 0x5f, 0x88, 0x92, 0x0b, 0xe4, 0x31, 0xde, 0x93, 0x8b, - 0x00, 0xb8, 0x53, 0x8f, 0xc4, 0x55, 0x42, 0xf6, 0x1e, 0x11, 0x43, 0x48, 0xcb, 0x24, 0x3c, 0x3c, 0x92, 0xe0, 0x25, - 0xfe, 0x6c, 0x5e, 0x4c, 0x90, 0xb0, 0x72, 0x60, 0x14, 0xe4, 0xd9, 0x69, 0xc1, 0xf2, 0x73, 0x36, 0xd2, 0x1c, 0x50, - 0x00, 0x56, 0xd4, 0x1c, 0x8c, 0x17, 0x9a, 0xd1, 0x51, 0x3a, 0x94, 0xc1, 0x50, 0x3d, 0x53, 0xcc, 0x32, 0xc9, 0xcc, - 0xda, 0xc2, 0xd1, 0x52, 0xc0, 0x11, 0x46, 0x85, 0x94, 0x04, 0x79, 0xa8, 0x30, 0x9c, 0x80, 0x14, 0x02, 0xad, 0x60, - 0x6e, 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, - 0xca, 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x8d, 0xd0, 0x85, 0x3e, 0xb6, 0x20, 0x36, 0xf0, - 0xf5, 0xca, 0x03, 0x61, 0x25, 0xde, 0x15, 0x22, 0xde, 0x1a, 0xb0, 0x71, 0x62, 0xe4, 0x27, 0xef, 0x1e, 0xf7, 0xd3, - 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, 0x67, - 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, 0xcb, - 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, 0x5d, - 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, 0x85, - 0x4d, 0x41, 0x80, 0x1e, 0xb2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, 0xac, - 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, 0x2b, - 0x90, 0x93, 0x6f, 0x66, 0x27, 0x84, 0x95, 0xb9, 0xd7, 0xd7, 0xdf, 0xa8, 0x41, 0xaa, 0xa5, 0xd4, 0x36, 0x50, 0x63, - 0x4d, 0x6c, 0xd5, 0x64, 0x64, 0xbb, 0x52, 0xa1, 0xde, 0xeb, 0xf4, 0x6a, 0x7c, 0x00, 0x7b, 0xae, 0xad, 0x59, 0xba, - 0x32, 0xb6, 0xdf, 0x2b, 0x9a, 0xbe, 0x13, 0x23, 0x93, 0x35, 0xca, 0x6e, 0xe7, 0x1e, 0xb5, 0xe3, 0xa1, 0xed, 0x52, - 0x5d, 0x25, 0x18, 0xe6, 0x75, 0xc1, 0xd0, 0x84, 0x7a, 0xa6, 0xbb, 0xd8, 0x9a, 0xa9, 0x58, 0xa8, 0xd6, 0x5a, 0x39, - 0x10, 0x3c, 0x3c, 0x04, 0xe3, 0x64, 0xa5, 0x7f, 0xf0, 0x36, 0x9a, 0x32, 0xa4, 0xa8, 0xb7, 0xae, 0x81, 0x74, 0x20, - 0xa0, 0xc9, 0x51, 0x53, 0xbd, 0x71, 0x57, 0x58, 0x4d, 0xf5, 0xfd, 0x15, 0x83, 0x15, 0x01, 0xf6, 0x75, 0xb9, 0x62, - 0x89, 0x48, 0x6f, 0x0a, 0x2e, 0xd1, 0xf4, 0x11, 0x65, 0x62, 0x4d, 0x48, 0xc1, 0x03, 0xf2, 0xb0, 0xfc, 0x8d, 0x85, - 0x93, 0xad, 0x98, 0xc2, 0x91, 0xa3, 0x4c, 0x01, 0x3a, 0x93, 0x12, 0x00, 0x71, 0x49, 0x7f, 0x6b, 0x1b, 0x0b, 0xc9, - 0xb6, 0x8f, 0x7c, 0xe0, 0x8f, 0x93, 0x88, 0x3b, 0x9d, 0xad, 0xb6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, - 0xf7, 0x15, 0x2a, 0x8c, 0xbc, 0x05, 0x97, 0xfb, 0x60, 0x14, 0x4d, 0xe2, 0x31, 0x77, 0x12, 0x54, 0x22, 0x6e, 0xc9, - 0x12, 0x50, 0x32, 0x7a, 0x5f, 0x81, 0x94, 0xe0, 0x42, 0xba, 0x88, 0x6a, 0x2d, 0xd0, 0x14, 0xa4, 0x24, 0xa5, 0x48, - 0x0b, 0x2a, 0x08, 0x0c, 0xa1, 0xd2, 0x53, 0x1c, 0x05, 0xfa, 0x2d, 0x1e, 0x88, 0x41, 0x83, 0x25, 0x8b, 0x32, 0x1e, - 0xc4, 0xcb, 0x85, 0xa0, 0x86, 0x7d, 0x9e, 0xbd, 0xce, 0x2e, 0x58, 0xfe, 0x2c, 0x42, 0xd8, 0x03, 0xd1, 0xbd, 0x04, - 0x49, 0x4f, 0x02, 0x9d, 0xf5, 0x14, 0xaf, 0x9c, 0x13, 0xd2, 0xb0, 0x10, 0xd3, 0x18, 0x15, 0x21, 0x68, 0x39, 0xa2, - 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xa6, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, 0xe2, - 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, 0xe9, - 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0xcb, 0x49, 0x6c, 0x09, 0xb7, 0x04, 0x65, 0x84, 0x86, 0x57, 0x9e, 0x25, 0x89, 0xa1, - 0x8b, 0xbc, 0xb8, 0xe7, 0x34, 0xd4, 0x11, 0x40, 0x31, 0xad, 0x69, 0xa4, 0x01, 0x0f, 0x74, 0x05, 0x2a, 0x25, 0xa5, - 0x8d, 0xbc, 0xaa, 0x89, 0x80, 0x38, 0x1d, 0xb1, 0x5c, 0x38, 0x68, 0x52, 0x87, 0xc2, 0x84, 0x29, 0x30, 0x34, 0x1b, - 0x81, 0x84, 0x57, 0x08, 0x80, 0x79, 0xe2, 0x4f, 0xb2, 0x82, 0xeb, 0x3a, 0x13, 0xfa, 0xf8, 0xfa, 0x3a, 0x16, 0xfe, - 0x22, 0x32, 0x40, 0xce, 0xa6, 0xd9, 0x39, 0x5b, 0x01, 0x75, 0x4f, 0x0d, 0x66, 0x82, 0x6c, 0x0c, 0x03, 0x4a, 0x14, - 0x54, 0xcb, 0x2c, 0x89, 0x87, 0x4c, 0x6b, 0xa9, 0xa9, 0x0f, 0x06, 0x1d, 0xbb, 0x04, 0x19, 0xc1, 0xdc, 0x7e, 0xbf, - 0xdf, 0xf6, 0x3a, 0x6e, 0x29, 0x08, 0xbe, 0x58, 0xa2, 0xe8, 0x0d, 0xfa, 0x51, 0x9a, 0xe0, 0xab, 0x64, 0x01, 0x77, - 0x0d, 0xa5, 0xc8, 0x85, 0x9f, 0xe4, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xdb, 0x76, 0xe3, 0x46, 0x92, 0xe0, 0xf3, + 0x9e, 0xb3, 0x7f, 0xb0, 0x2f, 0x28, 0x58, 0x53, 0x05, 0xb4, 0x40, 0x88, 0xa4, 0x4a, 0x55, 0x65, 0x50, 0x20, 0x5b, + 0x75, 0xb1, 0xab, 0xec, 0xba, 0xb9, 0xa4, 0xb2, 0xdb, 0x96, 0xd5, 0x12, 0x44, 0x26, 0x45, 0xb8, 0x40, 0x80, 0x06, + 0x92, 0xba, 0x98, 0xc2, 0x9c, 0x79, 0x9a, 0xa7, 0x39, 0x67, 0x6f, 0xf3, 0x30, 0x0f, 0x3b, 0x67, 0xe6, 0x61, 0x3f, + 0x62, 0x9f, 0xe7, 0x53, 0xfa, 0x07, 0x76, 0x3e, 0x61, 0x23, 0x22, 0x2f, 0x48, 0x80, 0xa4, 0x24, 0x7b, 0xdc, 0x7b, + 0xdc, 0xd5, 0x02, 0xf2, 0x1a, 0x11, 0x19, 0x19, 0xb7, 0x8c, 0x04, 0x77, 0xef, 0x8d, 0xb2, 0x21, 0xbf, 0x9a, 0x31, + 0x6b, 0xc2, 0xa7, 0x49, 0x7f, 0x57, 0xfe, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, + 0x78, 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, + 0x53, 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, + 0xc7, 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, + 0xfe, 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, + 0xc4, 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, + 0x8b, 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, + 0x4f, 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, + 0x69, 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf7, 0x98, 0x17, 0xbb, 0x61, 0x9f, 0x59, 0x71, 0x6a, 0xf1, 0xc1, 0x0b, 0x46, + 0x25, 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, + 0x7c, 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xf0, 0x43, 0x76, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, + 0x8c, 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbb, 0xbe, 0x76, 0x58, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, + 0x51, 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xec, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, + 0x99, 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xe6, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, + 0xe9, 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, + 0x28, 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, + 0x0c, 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, + 0xc0, 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, + 0x90, 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, + 0xbe, 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, + 0x58, 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, + 0xc6, 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdd, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, + 0xb3, 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, + 0x05, 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, + 0x41, 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xbc, + 0x04, 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0xe0, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, + 0x9c, 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0xa2, 0xd1, 0xd6, 0xe3, 0x84, 0x78, 0x8d, 0x44, 0xae, + 0xc7, 0x7d, 0x49, 0xbe, 0xfd, 0xab, 0x74, 0x58, 0x1f, 0x1b, 0x2a, 0x4b, 0x9e, 0xed, 0xf3, 0x3c, 0x4e, 0xcf, 0x00, + 0x08, 0xc5, 0x06, 0x46, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x3c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, + 0x7a, 0xd8, 0x00, 0x08, 0x90, 0x1e, 0x18, 0x8c, 0x0f, 0x78, 0xc0, 0x37, 0x6d, 0xdb, 0xfb, 0xce, 0xf5, 0xae, 0x90, + 0x83, 0x7c, 0xdf, 0x27, 0xf6, 0x15, 0x9d, 0xe3, 0xb0, 0x83, 0x40, 0xfb, 0x09, 0x4b, 0xcf, 0xf8, 0x64, 0xc0, 0x0f, + 0xdb, 0x47, 0x01, 0x03, 0xa8, 0x46, 0xf3, 0x21, 0x73, 0x90, 0x1f, 0xbd, 0x1c, 0xb7, 0xcf, 0xa6, 0x03, 0x53, 0xe0, + 0xc2, 0xdc, 0x23, 0x1c, 0x6b, 0x4b, 0xe3, 0x2a, 0xd8, 0x14, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, + 0x70, 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, + 0x37, 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0xe4, 0x87, 0xf9, 0x66, 0xe7, 0xc8, + 0x43, 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0xb8, 0xbf, 0xcc, + 0xc7, 0x21, 0xf3, 0xa7, 0xd1, 0x0c, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, + 0x2b, 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, + 0x39, 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, + 0x9b, 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, + 0x73, 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, + 0xd5, 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, + 0xc0, 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x85, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, + 0x19, 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xb2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, + 0xd0, 0x1f, 0x08, 0xc1, 0x7b, 0x28, 0xb8, 0xbe, 0x92, 0x52, 0x27, 0x62, 0x0a, 0x43, 0x20, 0xc0, 0x10, 0x25, 0x88, + 0xa4, 0xc1, 0xfb, 0x2c, 0xb9, 0x1a, 0xc7, 0x49, 0xb2, 0x3f, 0x9f, 0xcd, 0xb2, 0x9c, 0x7b, 0x5f, 0x87, 0x0b, 0x9e, + 0x55, 0xb8, 0xd2, 0x26, 0x2f, 0x2e, 0x62, 0x8e, 0x04, 0x75, 0x17, 0xc3, 0x08, 0x96, 0xfa, 0x69, 0x96, 0x25, 0x2c, + 0x4a, 0x01, 0x0d, 0x3e, 0xb0, 0xed, 0x20, 0x9d, 0x27, 0x49, 0xef, 0x14, 0x86, 0xfd, 0xd4, 0xa3, 0x6a, 0x21, 0xf1, + 0x03, 0x7a, 0xde, 0xcb, 0xf3, 0xe8, 0x0a, 0x1a, 0x62, 0x1b, 0x60, 0x2f, 0x58, 0xad, 0xaf, 0xf6, 0xdf, 0xbd, 0xf5, + 0x05, 0xe3, 0xc7, 0xe3, 0x2b, 0x00, 0xb4, 0xac, 0xa4, 0xe6, 0x38, 0xcf, 0xa6, 0x8d, 0xa9, 0x91, 0x0e, 0x71, 0xc8, + 0x7b, 0x6b, 0x40, 0x88, 0x69, 0x64, 0x58, 0x25, 0x6e, 0x42, 0xf0, 0x96, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, + 0x43, 0x20, 0x8a, 0x61, 0xca, 0x5b, 0xa0, 0xcd, 0xaf, 0x16, 0x71, 0x48, 0x70, 0xce, 0x50, 0xff, 0x22, 0x8c, 0xc3, + 0x08, 0x66, 0x5f, 0x88, 0x01, 0x4b, 0x05, 0x71, 0x5c, 0x96, 0xde, 0x44, 0x33, 0x31, 0x4a, 0x3c, 0x14, 0x28, 0x2c, + 0x0c, 0x41, 0xc1, 0x70, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x45, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, + 0x02, 0x35, 0xd9, 0x39, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x50, 0x7f, 0xe3, 0x04, 0xa1, 0xb8, 0xd7, 0xf1, 0x40, 0x83, + 0x3e, 0x9b, 0x44, 0xe9, 0x19, 0x1b, 0x05, 0x13, 0x56, 0x4a, 0xc9, 0xbb, 0x67, 0xc1, 0x1a, 0x03, 0x3b, 0x15, 0xd6, + 0xcb, 0x83, 0x37, 0xaf, 0xe5, 0xca, 0xd5, 0x84, 0x31, 0x2c, 0xd2, 0x1c, 0xd4, 0x2a, 0x88, 0x6d, 0x29, 0x8e, 0x5f, + 0x70, 0x25, 0xbd, 0x45, 0x49, 0x5c, 0x7c, 0x9c, 0x81, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, + 0x39, 0xcc, 0x27, 0x2a, 0x46, 0xba, 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x6b, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x87, + 0x56, 0x34, 0x1a, 0xbd, 0x4a, 0x63, 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x81, 0x3c, 0xc6, 0x7a, 0x72, 0x11, + 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, 0xc8, 0xde, 0x23, 0x62, 0x08, 0x69, 0x99, 0x84, 0x87, 0x47, 0x12, 0xbc, 0xc4, + 0x9f, 0xcd, 0x8b, 0x09, 0x12, 0x56, 0x0e, 0x8c, 0x82, 0x3c, 0x3b, 0x2d, 0x58, 0x7e, 0xce, 0x46, 0x9a, 0x03, 0x0a, + 0xc0, 0x8a, 0x9a, 0x83, 0xf1, 0x42, 0x33, 0x3a, 0x4a, 0x87, 0x72, 0x18, 0xaa, 0x67, 0x8a, 0x59, 0x26, 0x99, 0x59, + 0x5b, 0x38, 0x5a, 0x0a, 0x38, 0xc2, 0xa8, 0x90, 0x92, 0x20, 0x0f, 0x15, 0x86, 0x13, 0x90, 0x42, 0xcc, 0xad, 0x6d, + 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, 0xca, + 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x0d, 0xe9, 0x42, 0x50, 0x26, 0xd0, 0x82, 0x21, 0x1b, + 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0xef, 0x1e, 0xf3, + 0xd3, 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, + 0x67, 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, + 0xcb, 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, + 0x5d, 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, + 0x85, 0x4d, 0x41, 0x80, 0x1e, 0xf2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, + 0xac, 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, + 0x2b, 0x90, 0x93, 0x6f, 0x66, 0x27, 0xb2, 0x27, 0xdc, 0xeb, 0xeb, 0x6f, 0xd4, 0x20, 0xd5, 0x52, 0x6a, 0x1b, 0xa8, + 0xb1, 0x26, 0xb6, 0x6a, 0x32, 0xb2, 0x5d, 0xa9, 0x50, 0xef, 0x75, 0x7a, 0x35, 0x3e, 0x80, 0x3d, 0xd7, 0xd6, 0x2c, + 0x5d, 0x19, 0xdb, 0xef, 0x15, 0x4d, 0xdf, 0x89, 0x91, 0xc9, 0x1a, 0xe5, 0xb7, 0x73, 0x8f, 0xda, 0xf1, 0xd0, 0x76, + 0xa9, 0xae, 0x12, 0x0c, 0xf3, 0xba, 0x60, 0x68, 0x42, 0x3d, 0xd3, 0x5d, 0x6c, 0xcd, 0x54, 0x3c, 0x54, 0x6b, 0xad, + 0x1c, 0x08, 0x16, 0x1e, 0x82, 0x71, 0xb2, 0xd2, 0x3f, 0x78, 0x1b, 0x4d, 0x19, 0x52, 0xd4, 0x5b, 0xd7, 0x40, 0x3a, + 0x10, 0xd0, 0xe4, 0xa8, 0xa9, 0xde, 0x98, 0x2b, 0xac, 0xa6, 0xfa, 0xfe, 0x8a, 0xc1, 0x8a, 0x00, 0xfb, 0xba, 0x5c, + 0xb1, 0x44, 0xa4, 0x37, 0x05, 0x97, 0x68, 0xfa, 0x88, 0x32, 0xb1, 0x26, 0xa4, 0xe0, 0x01, 0x79, 0x58, 0xfe, 0xc6, + 0xc2, 0xa9, 0x56, 0x0a, 0x47, 0x86, 0x32, 0x05, 0xe8, 0x4c, 0x4a, 0x00, 0xc4, 0x25, 0xfd, 0xad, 0x6d, 0x2c, 0x24, + 0xdb, 0x3e, 0xf2, 0x81, 0x3f, 0x4e, 0x22, 0xee, 0x74, 0xb6, 0xda, 0x2e, 0xf0, 0x21, 0x08, 0x71, 0xd0, 0x11, 0x60, + 0xde, 0x57, 0xa8, 0x70, 0xf2, 0x16, 0x5c, 0xe6, 0x83, 0x51, 0x34, 0x89, 0xc7, 0xdc, 0x49, 0x50, 0x89, 0xb8, 0x25, + 0x4b, 0x40, 0xc9, 0xe8, 0x7d, 0x05, 0xca, 0x82, 0x09, 0xe9, 0x22, 0xaa, 0x95, 0x40, 0x63, 0x0a, 0x52, 0x92, 0x52, + 0xa4, 0x05, 0x15, 0x04, 0x86, 0x50, 0xe9, 0x29, 0x8e, 0x02, 0xfd, 0x16, 0x0f, 0xc4, 0xa0, 0xc1, 0x92, 0x45, 0x19, + 0x0f, 0xe2, 0xe5, 0x42, 0x50, 0xc3, 0x3e, 0xcf, 0x5e, 0x67, 0x17, 0x2c, 0x7f, 0x16, 0x21, 0xec, 0x81, 0xe8, 0x5e, + 0x82, 0xa4, 0x27, 0x81, 0xce, 0x7b, 0x8a, 0x57, 0xce, 0x09, 0x69, 0x58, 0x88, 0x69, 0x8c, 0x8a, 0x10, 0xec, 0x16, + 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xae, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, + 0xe2, 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, + 0xe9, 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0x08, 0xc4, 0x96, 0x70, 0x4b, 0x50, 0x46, 0x68, 0x78, 0xe5, 0x59, 0x92, 0x18, + 0xba, 0xc8, 0x8b, 0x7b, 0x4e, 0x43, 0x1d, 0x01, 0x14, 0xd3, 0x9a, 0x46, 0x1a, 0xb0, 0x40, 0x57, 0xa0, 0x52, 0x52, + 0xda, 0xc8, 0xab, 0xd6, 0x46, 0x40, 0x9c, 0x8e, 0x58, 0x2e, 0x1c, 0x34, 0xa9, 0x43, 0x61, 0xc2, 0x14, 0x18, 0x9a, + 0x8d, 0x40, 0xc2, 0x2b, 0x04, 0xc0, 0x3c, 0xf1, 0x27, 0x59, 0xc1, 0x75, 0x9d, 0x09, 0x7d, 0x7c, 0x7d, 0x1d, 0x0b, + 0x7f, 0x11, 0x19, 0x20, 0x67, 0xd3, 0xec, 0x9c, 0xad, 0x80, 0xba, 0xa7, 0x06, 0x33, 0x41, 0x36, 0x86, 0x01, 0x25, + 0x0a, 0xaa, 0x65, 0x96, 0xc4, 0x60, 0xe9, 0xeb, 0x06, 0x3e, 0x18, 0x74, 0xec, 0x12, 0x65, 0x84, 0xdb, 0xef, 0xf7, + 0xdb, 0x5e, 0xc7, 0x2d, 0x05, 0xc1, 0x17, 0x4b, 0x14, 0xbd, 0x41, 0x3f, 0x4a, 0x13, 0x7c, 0x95, 0x2c, 0x60, 0xae, + 0xa1, 0x14, 0x39, 0xe9, 0x26, 0xe6, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, - 0x5a, 0x89, 0x54, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, - 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0xe0, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, - 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xb2, 0x37, 0xd9, 0xc0, 0x69, 0x94, 0x84, 0x86, 0xb8, 0x32, 0xf1, 0x56, 0x12, 0xba, - 0xb6, 0x51, 0xc0, 0x21, 0x5b, 0x62, 0xfb, 0xe6, 0x42, 0x37, 0xb9, 0x5d, 0xb2, 0x87, 0xf2, 0x9f, 0x34, 0x97, 0xdc, - 0xc0, 0x72, 0x5c, 0x49, 0x03, 0xae, 0x18, 0x0f, 0x96, 0xa6, 0x01, 0x09, 0xf0, 0x5d, 0x39, 0x8a, 0x8b, 0xf5, 0x24, - 0xf8, 0x5d, 0xc1, 0x7c, 0x6e, 0xcc, 0x74, 0x2b, 0xa4, 0x5a, 0xc2, 0x49, 0x33, 0x58, 0x83, 0x26, 0x8d, 0x07, 0x25, - 0x6a, 0xbe, 0x46, 0x43, 0x85, 0x38, 0xfe, 0x4c, 0x54, 0xa1, 0x09, 0x86, 0x60, 0xe4, 0x5e, 0x21, 0x19, 0x2e, 0x5b, - 0x16, 0x2d, 0x52, 0xa6, 0xc6, 0xa4, 0x52, 0x35, 0xcb, 0x65, 0x60, 0x60, 0xd1, 0x6e, 0xf5, 0xa5, 0x25, 0xae, 0x44, - 0x6e, 0x1a, 0x6a, 0x61, 0x52, 0x28, 0x6f, 0xc2, 0xc9, 0xd1, 0xef, 0x52, 0xd6, 0xbb, 0x89, 0x4f, 0xae, 0xf0, 0xc9, - 0x7d, 0xc3, 0x87, 0x32, 0x79, 0xbb, 0x18, 0x14, 0xc1, 0xd7, 0xb5, 0x4a, 0xb4, 0x4f, 0x7d, 0x14, 0xcc, 0xae, 0x16, - 0xba, 0x20, 0x50, 0x24, 0x9b, 0xa4, 0x03, 0xc9, 0x6f, 0x28, 0x36, 0x2a, 0xcf, 0x28, 0x73, 0xc5, 0x06, 0xa9, 0x79, - 0xa5, 0x99, 0x97, 0xba, 0x0d, 0xfb, 0xbd, 0x2c, 0x25, 0x9d, 0xb8, 0xa0, 0x4c, 0xec, 0xdd, 0x44, 0x1b, 0x2f, 0x0d, - 0x33, 0x61, 0xfd, 0x0a, 0x63, 0xa7, 0x46, 0xa1, 0x54, 0x8a, 0x40, 0x1c, 0x1b, 0x5f, 0x2b, 0xcb, 0x20, 0xf3, 0x57, - 0xd8, 0x53, 0x00, 0x4a, 0x02, 0x8b, 0xaf, 0xa9, 0xe4, 0x45, 0x61, 0x9d, 0x8e, 0xf7, 0x88, 0x8e, 0x95, 0x08, 0xad, - 0x89, 0x7c, 0xad, 0xcf, 0x62, 0xbf, 0xe6, 0x12, 0x9a, 0x94, 0xcc, 0x07, 0x79, 0x60, 0xab, 0x40, 0x44, 0xa5, 0xdb, - 0x92, 0x41, 0x42, 0x0e, 0xe9, 0x32, 0xd1, 0x6b, 0x23, 0x19, 0xb4, 0x4e, 0x85, 0x44, 0x4b, 0x8f, 0xc2, 0xc8, 0x41, - 0xc7, 0x9d, 0xd6, 0x62, 0x89, 0x90, 0x4d, 0x7b, 0x93, 0x58, 0x11, 0x9d, 0xd3, 0x1c, 0x4d, 0x38, 0x53, 0xa7, 0x3b, - 0x0e, 0xa0, 0x03, 0x62, 0x7f, 0x89, 0xf5, 0x56, 0x9a, 0x9d, 0xae, 0x5f, 0x39, 0x7c, 0xd7, 0xd7, 0x13, 0xe4, 0x07, - 0x61, 0xf0, 0xc2, 0x9a, 0x0d, 0x94, 0xec, 0xdd, 0x7b, 0x8d, 0xad, 0xc8, 0xfe, 0xac, 0x4a, 0x2a, 0x4f, 0xa1, 0xc6, - 0xb9, 0xf5, 0x75, 0x62, 0x66, 0x68, 0x51, 0x55, 0xec, 0x1b, 0x52, 0x7d, 0x5f, 0x29, 0xec, 0x0a, 0xe5, 0x7d, 0x39, - 0x74, 0xec, 0xba, 0x6e, 0x90, 0x93, 0xf3, 0x72, 0x6f, 0x95, 0x0b, 0x79, 0xff, 0xbe, 0xe9, 0x33, 0x9d, 0xeb, 0xe1, - 0x9f, 0x39, 0xa8, 0x9c, 0x8b, 0xab, 0x94, 0x2c, 0x98, 0x67, 0x4a, 0x1d, 0x2d, 0x39, 0xa0, 0xed, 0x1e, 0x7a, 0xda, - 0xd1, 0x45, 0x14, 0x73, 0x4b, 0x8f, 0x22, 0x3c, 0x6d, 0x94, 0x4f, 0xd2, 0xe8, 0x00, 0xbc, 0xd0, 0x84, 0x24, 0x27, - 0xdc, 0xb4, 0x45, 0x8b, 0xe1, 0x84, 0x61, 0x08, 0x5c, 0xd9, 0x13, 0xa6, 0xec, 0xb9, 0x87, 0x78, 0x8b, 0x81, 0xd9, - 0x6a, 0xd8, 0xcb, 0x66, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, 0x04, 0xb2, 0x6d, 0xaa, 0xea, 0xca, 0xc6, 0xbb, 0x14, 0x91, - 0x18, 0x61, 0x5b, 0x35, 0xb6, 0xb4, 0xf5, 0x7b, 0x0d, 0xf7, 0xba, 0x72, 0xcc, 0x6b, 0x4a, 0xb5, 0xa1, 0x87, 0x95, - 0x9b, 0xc3, 0x4c, 0x47, 0x5e, 0xac, 0xa0, 0xdb, 0x13, 0x41, 0x21, 0x70, 0x22, 0xb4, 0x3d, 0xa8, 0xb8, 0x81, 0x48, - 0xc9, 0x95, 0x56, 0xcd, 0xe6, 0xc9, 0x48, 0x02, 0x0b, 0x2e, 0x2c, 0x97, 0x7c, 0x74, 0x11, 0x27, 0x49, 0x55, 0xfa, - 0xbb, 0x0a, 0x78, 0x31, 0xec, 0x6d, 0xa2, 0x5d, 0x60, 0x34, 0x57, 0x20, 0xb8, 0xda, 0x08, 0xfb, 0xe8, 0xb8, 0xd5, - 0xba, 0x8b, 0x88, 0x23, 0x37, 0xa3, 0x11, 0x50, 0x8f, 0x11, 0x56, 0xcd, 0xda, 0x7b, 0x2f, 0x30, 0xa4, 0x66, 0xe0, - 0x83, 0xea, 0x8c, 0x8a, 0x7f, 0x95, 0x3d, 0xf5, 0x2b, 0xd1, 0xbb, 0x55, 0x75, 0x35, 0x03, 0x2a, 0x2a, 0xf0, 0x61, - 0x86, 0x58, 0xda, 0x2a, 0x10, 0x90, 0xeb, 0x61, 0x51, 0x0a, 0x98, 0xa4, 0xc1, 0x82, 0x52, 0x60, 0xad, 0x95, 0xdd, - 0xeb, 0xdb, 0x82, 0x39, 0x14, 0x0a, 0x17, 0xfd, 0x9f, 0x65, 0xd3, 0x19, 0x5a, 0x66, 0x0d, 0xa6, 0x86, 0x06, 0x1f, - 0x1b, 0xf5, 0xe5, 0x8a, 0xb2, 0x5a, 0x1f, 0xda, 0x91, 0x35, 0x7e, 0xd2, 0x8e, 0x32, 0x38, 0x54, 0x73, 0x5d, 0x54, - 0xb7, 0x9b, 0x9b, 0x22, 0x66, 0x15, 0x8f, 0xfb, 0xa4, 0xb7, 0xb5, 0x35, 0xe9, 0x69, 0x1a, 0x90, 0x4c, 0x92, 0x0c, - 0x6f, 0x32, 0x40, 0x59, 0x11, 0x67, 0x51, 0x36, 0xc8, 0xb7, 0x28, 0x4b, 0x5c, 0xbf, 0x1f, 0x7a, 0x7b, 0x35, 0xcf, - 0xda, 0xdb, 0x5b, 0xef, 0x22, 0x57, 0x75, 0xd2, 0x83, 0x3c, 0x3c, 0x82, 0xa2, 0x25, 0x9b, 0x32, 0x5c, 0x4c, 0xb3, - 0x11, 0x0b, 0x6c, 0xe8, 0x9e, 0xda, 0xa5, 0xdc, 0x34, 0x11, 0x6c, 0x8e, 0x88, 0x39, 0x8b, 0x0f, 0xf5, 0x48, 0x6a, - 0xb0, 0x07, 0x2c, 0xa0, 0xcd, 0x85, 0xaf, 0xc2, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x03, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, - 0x05, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, 0x7d, 0x35, 0xf8, 0x2a, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x1d, 0xbf, - 0xed, 0x77, 0x6c, 0x15, 0x11, 0xfb, 0xc9, 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x00, 0x4d, 0x56, 0x78, 0x43, - 0x16, 0xfe, 0x34, 0xf8, 0x49, 0xb9, 0xd4, 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe1, 0x79, 0xa4, 0xed, - 0x2d, 0x44, 0x05, 0xc6, 0x15, 0x29, 0x2e, 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xc6, 0xc6, 0xc2, - 0x79, 0x13, 0xf1, 0x89, 0x9f, 0x47, 0xe9, 0x28, 0x9b, 0x3a, 0xee, 0xa6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0xe7, - 0x6e, 0xb9, 0x71, 0x02, 0x7e, 0x40, 0x68, 0x0f, 0xec, 0xcd, 0x63, 0xef, 0x80, 0x85, 0x27, 0xbb, 0x1b, 0x8b, 0x11, - 0x2b, 0xfb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7f, 0x29, 0xc1, 0x00, 0x76, - 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0xfb, 0x9e, - 0x76, 0x56, 0xef, 0xdf, 0xaf, 0xd4, 0x7c, 0x55, 0xea, 0xcd, 0x59, 0x58, 0xf3, 0xd4, 0xbd, 0x97, 0x74, 0xb4, 0x52, - 0xdf, 0xc8, 0x73, 0x46, 0x4a, 0x73, 0xd9, 0x4e, 0x70, 0x8c, 0x2d, 0xbe, 0x7a, 0x5b, 0x1f, 0x8a, 0x28, 0x85, 0x1f, - 0x83, 0xf5, 0x12, 0x81, 0xfa, 0x06, 0x07, 0xc7, 0x3b, 0x08, 0xb7, 0x76, 0x9d, 0x41, 0xe0, 0xdc, 0x6b, 0xb5, 0xae, - 0x7f, 0xdc, 0x3a, 0xfc, 0x73, 0xd4, 0xfa, 0x65, 0xaf, 0xf5, 0xc3, 0x91, 0x7b, 0xed, 0xfc, 0xb8, 0x35, 0x38, 0x94, - 0x6f, 0x87, 0x7f, 0xee, 0xff, 0x58, 0x1c, 0xfd, 0x41, 0x14, 0x6e, 0xb8, 0xee, 0xd6, 0x99, 0x37, 0x63, 0xe1, 0x56, - 0xab, 0xd5, 0x87, 0xa7, 0x33, 0x78, 0xc2, 0xbf, 0x17, 0xf0, 0xe7, 0xfa, 0xd0, 0xfa, 0x4f, 0x3f, 0xa6, 0xff, 0xf9, - 0xc7, 0xfc, 0x08, 0xc7, 0x3c, 0xfc, 0xf3, 0x8f, 0x85, 0xfd, 0xa0, 0x1f, 0x6e, 0x1d, 0x6d, 0xba, 0x8e, 0xae, 0xf9, - 0x43, 0x58, 0x3d, 0x42, 0xab, 0xc3, 0x3f, 0xcb, 0x37, 0xfb, 0xc1, 0xc9, 0x6e, 0x3f, 0x3c, 0xba, 0x76, 0xec, 0xeb, - 0x07, 0xee, 0xb5, 0xeb, 0x5e, 0x6f, 0xe0, 0x3c, 0xe7, 0x30, 0xfa, 0x03, 0xf8, 0x3b, 0x86, 0xbf, 0x36, 0xfc, 0x9d, - 0xc2, 0xdf, 0x3f, 0x43, 0x37, 0x11, 0x7f, 0xbb, 0xa6, 0x58, 0xc8, 0x35, 0x1e, 0x58, 0x44, 0xb0, 0x0a, 0xee, 0xc6, - 0x56, 0xec, 0x6d, 0x10, 0xd1, 0x60, 0x1f, 0xfa, 0xbe, 0x8f, 0x61, 0x52, 0x67, 0x71, 0xbc, 0x01, 0x8b, 0x8e, 0x9c, - 0xb3, 0x11, 0x30, 0x4f, 0x44, 0x0e, 0x8a, 0x80, 0x8b, 0xb3, 0xd5, 0x02, 0x0f, 0x57, 0xbd, 0x61, 0xb8, 0xc1, 0x1c, - 0x30, 0x0a, 0xde, 0x32, 0x7c, 0xe8, 0xba, 0xde, 0x0b, 0x79, 0x66, 0x88, 0xfb, 0x5c, 0xb0, 0x56, 0x9a, 0x09, 0x93, - 0xc6, 0x76, 0xbd, 0xd9, 0x8a, 0x4a, 0xd8, 0xd6, 0xe9, 0x19, 0xd4, 0x9d, 0x8a, 0x83, 0xb6, 0xef, 0x58, 0xf4, 0x09, - 0xb7, 0xe4, 0x1b, 0xe3, 0x10, 0x78, 0xc9, 0x92, 0x6f, 0x1a, 0x8d, 0x86, 0x8d, 0x28, 0xdc, 0xb1, 0xa7, 0x0c, 0x66, - 0x58, 0x32, 0x11, 0x39, 0x29, 0x4d, 0x61, 0xd9, 0xc2, 0xe4, 0xef, 0xa3, 0x9c, 0x6f, 0x54, 0x86, 0x6d, 0x58, 0xb3, - 0x64, 0x9b, 0x96, 0xfe, 0x1d, 0xa6, 0x40, 0xd3, 0x92, 0xce, 0x3f, 0xcc, 0xf1, 0xc3, 0x94, 0xd0, 0x7a, 0xeb, 0x70, - 0xf0, 0xd0, 0x0b, 0x90, 0x3b, 0xa2, 0x9f, 0xf3, 0x1e, 0xd5, 0x18, 0xfc, 0x2b, 0xc3, 0x0c, 0x9e, 0x98, 0x0f, 0x43, - 0x34, 0x8b, 0x52, 0x07, 0xb7, 0x52, 0x14, 0xf7, 0xaf, 0x70, 0x67, 0xa4, 0xa5, 0xb7, 0x1f, 0xaa, 0x1d, 0x73, 0x90, - 0x33, 0xf6, 0x5d, 0x94, 0x7c, 0x62, 0xb9, 0x73, 0xe9, 0x75, 0xba, 0x9f, 0x53, 0x67, 0x0f, 0x6d, 0xb3, 0x0f, 0xd5, - 0x31, 0x9a, 0x32, 0x0b, 0xd4, 0x11, 0x61, 0xab, 0xe3, 0xe5, 0x18, 0xd5, 0x42, 0x12, 0x14, 0x5e, 0x16, 0x76, 0x89, - 0xc3, 0xed, 0xdd, 0xe2, 0xfc, 0xac, 0x6f, 0x07, 0xb6, 0x0d, 0x16, 0xff, 0x01, 0x85, 0xad, 0x84, 0x61, 0x01, 0x06, - 0xd9, 0x6e, 0xdc, 0xe3, 0x9b, 0x9b, 0x55, 0xc0, 0x09, 0x0f, 0xd2, 0xa9, 0x7b, 0xe2, 0x45, 0xde, 0x24, 0x84, 0x01, - 0x87, 0xd0, 0x0c, 0xbb, 0xf4, 0x86, 0xbb, 0xb1, 0x9c, 0x06, 0x63, 0x21, 0x7e, 0x12, 0x15, 0xfc, 0x15, 0xc6, 0x23, - 0xc2, 0x21, 0x1a, 0xfb, 0x3e, 0xbb, 0x64, 0x43, 0x65, 0x67, 0x00, 0xa1, 0x22, 0xb7, 0xe7, 0x0e, 0x43, 0xa3, 0x19, - 0xcc, 0x1d, 0x86, 0x07, 0x03, 0x1b, 0xf6, 0x12, 0xec, 0xca, 0x30, 0x3a, 0xec, 0x1c, 0x0d, 0xd2, 0x70, 0xc6, 0x02, - 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0xea, 0x1e, 0x0d, 0x9c, 0x29, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x86, 0x11, - 0x8a, 0x22, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0xce, 0x1c, 0x7b, 0x77, 0xcb, 0xde, 0xc4, 0x52, 0xcf, 0x06, 0xf6, 0x82, - 0xb9, 0xc3, 0x0b, 0xd7, 0xec, 0xbc, 0x7d, 0x84, 0xa0, 0x62, 0x21, 0x4e, 0x7e, 0x31, 0xb0, 0xfb, 0x62, 0xea, 0x36, - 0x0c, 0x9a, 0xca, 0xe5, 0xc7, 0x15, 0x3d, 0x20, 0x54, 0x55, 0x57, 0x05, 0x1d, 0x94, 0x75, 0x03, 0x67, 0x62, 0x22, - 0xd1, 0xc2, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, 0x30, 0xa9, 0xd1, 0x6d, 0xfb, 0x68, 0x70, 0x11, 0x3c, 0xb0, - 0x1f, 0xa8, 0x97, 0x31, 0x20, 0xc3, 0xc4, 0xf4, 0x63, 0x90, 0x76, 0xf8, 0xf7, 0x9c, 0x01, 0x92, 0x17, 0x54, 0x34, - 0x93, 0x45, 0x67, 0x58, 0x74, 0x10, 0x20, 0xa8, 0x5e, 0xa1, 0xad, 0x3f, 0xb1, 0x26, 0xa3, 0x90, 0x60, 0xbf, 0x7f, - 0x1f, 0x96, 0x66, 0xb3, 0x73, 0x84, 0xe7, 0x0d, 0x39, 0x2f, 0xbe, 0x8b, 0x39, 0xa8, 0x84, 0xad, 0xbe, 0xed, 0x0e, - 0x6c, 0x0b, 0x97, 0xb6, 0x97, 0x6d, 0x86, 0x82, 0xc2, 0xf1, 0xe6, 0x01, 0x0b, 0x26, 0xfd, 0xb0, 0x3d, 0x70, 0x72, - 0x19, 0x6e, 0xc4, 0x73, 0x4b, 0x21, 0xc1, 0xdb, 0xde, 0x04, 0x04, 0x3a, 0x72, 0xee, 0x86, 0xbd, 0xa9, 0x0a, 0xa1, - 0xe8, 0x78, 0x73, 0xe4, 0x06, 0x31, 0xfc, 0x71, 0x5a, 0xc8, 0x34, 0x13, 0xdd, 0x57, 0x6b, 0x66, 0x37, 0x18, 0x29, - 0x8b, 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, - 0xb1, 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, - 0x47, 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf3, 0x0c, 0x09, 0xc5, 0x4b, 0xed, 0x86, 0x09, - 0x73, 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, - 0xbd, 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, - 0xe1, 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, - 0x02, 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x71, 0xe9, 0xda, - 0xa3, 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, - 0xbf, 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, - 0x60, 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, - 0x46, 0xe0, 0x39, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, - 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, - 0xdc, 0x82, 0x18, 0x87, 0x1b, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, - 0x8a, 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, - 0x52, 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, - 0x36, 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x39, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, - 0xf4, 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, - 0xa2, 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xb9, 0xf9, 0x52, 0xcc, 0x86, 0xbb, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, - 0xd1, 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x4b, 0xcc, 0xd9, 0x6f, 0x83, 0x0d, - 0x5e, 0xcb, 0x3b, 0x40, 0xfb, 0x8e, 0x4d, 0x67, 0xfc, 0x6a, 0x9f, 0x14, 0x7d, 0x20, 0xd3, 0x06, 0xc4, 0xd9, 0x79, - 0xbb, 0x17, 0xef, 0xf2, 0x5e, 0x0c, 0x52, 0x3d, 0x57, 0x2c, 0x86, 0x7b, 0xd5, 0x7b, 0x8f, 0x51, 0x4a, 0x93, 0x99, - 0xbc, 0x1a, 0x7a, 0x5d, 0x89, 0xde, 0xe6, 0x26, 0x20, 0xd8, 0x33, 0xba, 0x72, 0xd1, 0xb5, 0x2c, 0x05, 0x4d, 0x00, - 0xa2, 0x27, 0x75, 0x96, 0x23, 0x8e, 0xc3, 0x6c, 0x36, 0x28, 0x1e, 0x31, 0x77, 0xe5, 0xa8, 0x38, 0x26, 0x76, 0x97, - 0x09, 0x3b, 0x80, 0x19, 0x71, 0x79, 0xab, 0x23, 0xa2, 0xc3, 0xa2, 0xbf, 0x8e, 0x6f, 0x1f, 0x7b, 0x6c, 0xb3, 0xe3, - 0x82, 0x06, 0xa9, 0x8d, 0xf5, 0xb8, 0x1a, 0x0b, 0xea, 0xc3, 0x63, 0x4d, 0xa5, 0xb2, 0xd8, 0xdc, 0x2c, 0xeb, 0x47, - 0xb5, 0x6a, 0x07, 0xd7, 0x4e, 0x53, 0x2e, 0x9b, 0xd9, 0x20, 0x1c, 0x88, 0x98, 0x40, 0x81, 0x96, 0x56, 0x56, 0x0c, - 0x30, 0xa4, 0x2c, 0x47, 0xf9, 0x14, 0x32, 0x2f, 0x2e, 0x4b, 0x9d, 0xfa, 0xf2, 0x4c, 0x06, 0x1d, 0xf1, 0xd4, 0x93, - 0x8c, 0x15, 0x50, 0xb0, 0x5e, 0xea, 0x25, 0xb4, 0x44, 0x80, 0xf9, 0x0b, 0x95, 0x43, 0x23, 0x2c, 0x90, 0x28, 0x34, - 0xcc, 0x12, 0x65, 0x7c, 0x16, 0x61, 0x0c, 0xda, 0xfe, 0x59, 0x2d, 0xf6, 0x55, 0x28, 0xa3, 0xa3, 0x38, 0xcc, 0x8f, - 0x02, 0xaa, 0x9f, 0x4b, 0x09, 0x36, 0x09, 0x3f, 0x02, 0x1b, 0x55, 0x8e, 0x27, 0x09, 0xc2, 0xe7, 0x71, 0xce, 0xc8, - 0x53, 0xd8, 0x90, 0x30, 0x4b, 0xd3, 0x36, 0x52, 0xed, 0x22, 0x33, 0x08, 0xe5, 0xc2, 0xfc, 0x13, 0xe3, 0xec, 0x22, - 0x0b, 0x97, 0x5a, 0x83, 0xf9, 0xf1, 0xce, 0x04, 0x28, 0xbb, 0xbe, 0xce, 0x84, 0x8f, 0x1b, 0x91, 0xbd, 0xa1, 0x2b, - 0x26, 0x03, 0x85, 0x54, 0xe0, 0x44, 0x64, 0xf1, 0xd0, 0x19, 0x0a, 0x8d, 0x70, 0x40, 0xa7, 0xc8, 0xb9, 0x6b, 0x6c, - 0xfa, 0x7c, 0xa0, 0x7d, 0xa3, 0x34, 0x74, 0x12, 0x10, 0x02, 0x02, 0x77, 0xc3, 0x9a, 0x4a, 0x07, 0x69, 0x90, 0x50, - 0x29, 0xfa, 0x39, 0x80, 0x7f, 0x18, 0x49, 0x0a, 0x80, 0xfd, 0x50, 0x8d, 0x14, 0x51, 0x96, 0x05, 0x2e, 0x00, 0xcd, - 0xb5, 0x8f, 0x2b, 0xe1, 0x0b, 0x03, 0x15, 0xa6, 0xa7, 0x59, 0x79, 0x29, 0x94, 0xc8, 0xd3, 0x15, 0x29, 0x6b, 0x24, - 0x93, 0xcf, 0xd1, 0xe1, 0x53, 0xde, 0xf5, 0x5b, 0x89, 0x87, 0x2e, 0x78, 0x0e, 0xcb, 0xaa, 0x9e, 0xdf, 0x84, 0x9c, - 0x9c, 0x6b, 0xd0, 0x15, 0x52, 0xe8, 0x2f, 0x39, 0xc9, 0x7b, 0x6f, 0xfc, 0xaa, 0x96, 0x1a, 0x43, 0xd9, 0xc7, 0x55, - 0xcd, 0xb0, 0xbc, 0x9c, 0x55, 0x61, 0x0a, 0x02, 0x6e, 0xc1, 0x92, 0x60, 0x21, 0x35, 0x04, 0x58, 0xd8, 0x1e, 0x69, - 0xa5, 0x20, 0x2f, 0x75, 0x78, 0xe7, 0x39, 0x58, 0x01, 0xc6, 0xa1, 0x96, 0x4a, 0xa6, 0x91, 0xc4, 0x97, 0x4a, 0x14, - 0x98, 0x72, 0x7f, 0x08, 0x7e, 0x6a, 0xf3, 0xa4, 0xeb, 0xd2, 0xf5, 0xe3, 0x29, 0xa6, 0xf6, 0x10, 0xe8, 0xb1, 0x77, - 0x0f, 0x4c, 0x89, 0xba, 0x0e, 0x2b, 0x88, 0x43, 0xb3, 0x9a, 0x66, 0x01, 0x33, 0xa6, 0x0d, 0x5a, 0xb2, 0x0d, 0xb6, - 0x5c, 0x0e, 0xf6, 0x91, 0xd8, 0x9e, 0xd5, 0x0a, 0x08, 0x5d, 0x83, 0x06, 0x86, 0xdc, 0xa5, 0x42, 0x0b, 0xf3, 0x5e, - 0x97, 0x8a, 0x70, 0x7f, 0x0e, 0xb8, 0xb4, 0x82, 0x33, 0x2f, 0xa3, 0x81, 0xf7, 0xe3, 0xd3, 0x04, 0x13, 0x5f, 0x10, - 0x2b, 0xb0, 0x83, 0x83, 0x4e, 0xb3, 0x29, 0x70, 0x2a, 0x2e, 0x52, 0x06, 0xcb, 0x8a, 0x52, 0x1b, 0xfe, 0x48, 0x91, - 0xad, 0xbb, 0x3c, 0xd2, 0x5d, 0x88, 0x05, 0xb0, 0xd3, 0x2f, 0x18, 0xf9, 0x96, 0xf5, 0x32, 0x60, 0x70, 0xae, 0x35, - 0x0e, 0x02, 0xbf, 0xb9, 0x99, 0x1c, 0x95, 0x29, 0xb1, 0x5d, 0x93, 0xd5, 0x05, 0xe4, 0x98, 0x04, 0xd8, 0xc0, 0x1d, - 0x84, 0xa5, 0xb2, 0xc7, 0x8b, 0x72, 0x8a, 0xcb, 0xa5, 0x2c, 0xe4, 0xe6, 0x79, 0x35, 0xcd, 0xe7, 0x56, 0x9a, 0x4d, - 0xc7, 0x5b, 0xf1, 0x45, 0xc1, 0x3f, 0x70, 0x62, 0x69, 0xd5, 0x53, 0x6a, 0x85, 0x47, 0x99, 0x5b, 0xb2, 0x4e, 0x49, - 0xad, 0xae, 0x1b, 0xa8, 0x46, 0x78, 0x9a, 0x86, 0x8d, 0x40, 0x88, 0x09, 0x2e, 0x7e, 0xdb, 0x64, 0x62, 0xda, 0x5b, - 0x42, 0xea, 0x08, 0xbb, 0x87, 0x72, 0x82, 0xbb, 0x9a, 0x67, 0x5f, 0x86, 0xb3, 0xf5, 0xcc, 0xbd, 0x67, 0x30, 0xf7, - 0xd3, 0x90, 0x1b, 0x8c, 0x1e, 0xcb, 0x84, 0x1f, 0x19, 0xfb, 0xc8, 0x55, 0xd5, 0xb3, 0xb3, 0xb0, 0x12, 0x59, 0xe2, - 0xc9, 0x38, 0xea, 0x30, 0x4e, 0x45, 0x6b, 0x82, 0xec, 0xfa, 0xba, 0x30, 0xf7, 0x02, 0x05, 0x4d, 0x3d, 0x5e, 0x8f, - 0xd3, 0x56, 0xec, 0x6c, 0x44, 0x22, 0xf7, 0xde, 0xd4, 0x22, 0x91, 0x15, 0x9f, 0xe3, 0x48, 0x6b, 0x0e, 0x72, 0x9f, - 0x9d, 0x2d, 0x6f, 0x52, 0xa1, 0x5b, 0x34, 0xda, 0xc6, 0x1e, 0xd5, 0x07, 0x92, 0x7a, 0x46, 0x05, 0x56, 0x35, 0xf6, - 0xfd, 0xfb, 0x1d, 0x91, 0x6e, 0xa9, 0x14, 0x1b, 0x2c, 0x2d, 0x8c, 0x66, 0x8c, 0x82, 0x41, 0x49, 0x91, 0x81, 0x1a, - 0xe5, 0x6b, 0x04, 0xc3, 0x1e, 0x35, 0x00, 0xc5, 0xb9, 0xba, 0xfa, 0x69, 0x29, 0xd9, 0x42, 0x40, 0xe2, 0x2e, 0x18, - 0x88, 0x35, 0xc1, 0xcc, 0xc8, 0x27, 0x1f, 0x81, 0xf3, 0x06, 0x0c, 0x1d, 0x03, 0xf0, 0x0b, 0xc4, 0xa6, 0x07, 0x13, - 0xdb, 0x26, 0xa2, 0xe8, 0xb3, 0x81, 0x97, 0x00, 0xec, 0xac, 0x0a, 0x8d, 0x7e, 0xa8, 0x52, 0xc0, 0x90, 0x0d, 0xdc, - 0x80, 0x55, 0x61, 0xb9, 0xbd, 0x97, 0xe0, 0x36, 0xc0, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xb3, 0x0b, - 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0x41, 0xa3, 0x5e, 0x51, 0x42, 0xd4, 0xee, 0x63, 0xed, 0x4b, 0x8c, 0xb0, 0x88, - 0xf7, 0x37, 0xf8, 0xae, 0xc7, 0x2d, 0xf7, 0x34, 0x5a, 0x84, 0xe9, 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, - 0xbd, 0xdc, 0x17, 0xb1, 0xe0, 0x0a, 0x47, 0x56, 0x85, 0x14, 0x1b, 0x48, 0xd2, 0xd3, 0x1e, 0x1d, 0xb0, 0x6f, 0x34, - 0x7b, 0x01, 0x65, 0x3e, 0x56, 0xa4, 0x92, 0x90, 0xd2, 0xec, 0x86, 0x48, 0x12, 0xd6, 0x8a, 0x3c, 0x75, 0xde, 0x77, - 0xb4, 0xcf, 0xad, 0x24, 0x82, 0x11, 0x9c, 0x84, 0xe9, 0x58, 0x79, 0xd0, 0x14, 0xe0, 0x2a, 0x3a, 0x62, 0xfa, 0x26, - 0x20, 0xbf, 0x19, 0xc8, 0xed, 0xa5, 0xe4, 0xda, 0x5c, 0xc3, 0xf0, 0x0c, 0x09, 0x56, 0x45, 0x22, 0xf0, 0x88, 0x1a, - 0x70, 0xcc, 0x57, 0x79, 0x1e, 0x60, 0xc2, 0xd7, 0xf6, 0x26, 0x00, 0x94, 0x93, 0xab, 0xe2, 0x2c, 0x05, 0xba, 0x01, - 0xcb, 0xd5, 0x71, 0x6a, 0x54, 0x24, 0x2e, 0x6e, 0x4c, 0x57, 0xb7, 0xf4, 0xa7, 0x68, 0x39, 0x93, 0x21, 0xa6, 0x83, - 0x20, 0x20, 0x53, 0x9f, 0x32, 0x47, 0xc8, 0x5c, 0x61, 0x7d, 0xce, 0x9c, 0xda, 0xd4, 0x3d, 0x46, 0xdd, 0x3c, 0x49, - 0x2d, 0x5e, 0xa7, 0x4d, 0x29, 0x11, 0x93, 0x12, 0xf3, 0x54, 0xa4, 0x62, 0x33, 0x25, 0xee, 0xdc, 0xfa, 0x46, 0x0b, - 0x69, 0xa3, 0x9d, 0x8a, 0x1c, 0x6c, 0x56, 0xc9, 0x7b, 0x02, 0xe3, 0xa5, 0x20, 0x7c, 0x89, 0x8c, 0xb5, 0x98, 0x33, - 0xc7, 0x44, 0xb0, 0x7a, 0x31, 0x15, 0xf9, 0x07, 0x47, 0xa7, 0xd9, 0x1b, 0xf4, 0x20, 0xf5, 0x06, 0x12, 0xb3, 0x26, - 0xbe, 0x0b, 0x69, 0xa8, 0x23, 0x04, 0x2a, 0xa3, 0x5a, 0xa6, 0xe3, 0xc4, 0x2a, 0x7c, 0x23, 0xf8, 0xea, 0xbd, 0x3e, - 0xce, 0x37, 0x9e, 0x1b, 0xab, 0x11, 0xc4, 0xe0, 0x2d, 0xe4, 0x47, 0x9e, 0x14, 0xe1, 0x40, 0xb8, 0x7c, 0x73, 0xb3, - 0x97, 0xef, 0xf2, 0x2a, 0x44, 0x52, 0xc1, 0x18, 0x63, 0x46, 0x31, 0xee, 0x89, 0x9a, 0x5a, 0xcc, 0x61, 0x60, 0xd9, - 0x3a, 0xcc, 0xf1, 0x00, 0x00, 0x5a, 0x9a, 0xd2, 0xab, 0xa6, 0x42, 0xe5, 0x79, 0x2e, 0xe1, 0x53, 0x1d, 0xa2, 0xaa, - 0xc6, 0xef, 0x57, 0x67, 0xa0, 0x10, 0xdc, 0xf7, 0x3a, 0x1e, 0x1e, 0x42, 0xc0, 0x2a, 0x0a, 0x59, 0xa0, 0x37, 0x68, - 0xaf, 0x4a, 0x84, 0x62, 0xe6, 0x64, 0x3d, 0x66, 0x38, 0xa9, 0x60, 0x0b, 0x95, 0xb0, 0x54, 0x5a, 0xe0, 0x57, 0x1b, - 0xa1, 0x79, 0xca, 0xb8, 0xf7, 0xa6, 0xc2, 0x19, 0xf4, 0x07, 0xf3, 0x96, 0x19, 0xf5, 0xfd, 0xd2, 0x89, 0x4c, 0x05, - 0x26, 0x6e, 0x66, 0xa9, 0xfd, 0x7e, 0x59, 0xa5, 0xfd, 0xbc, 0x42, 0xee, 0x73, 0xd2, 0x7c, 0x9d, 0x3b, 0x68, 0x3e, - 0x19, 0xee, 0x57, 0xca, 0x0f, 0x2d, 0x8c, 0x9a, 0xf2, 0xcb, 0xeb, 0xca, 0xaf, 0xf0, 0x54, 0x78, 0xab, 0xdf, 0x45, - 0xa1, 0x8b, 0xfa, 0x1c, 0x0c, 0x21, 0xfd, 0x08, 0xae, 0xa1, 0xc1, 0x83, 0x22, 0x59, 0x2c, 0xd6, 0x2e, 0x88, 0xeb, - 0x63, 0x4e, 0xb5, 0x43, 0x19, 0x63, 0xc4, 0xd3, 0x92, 0x83, 0x24, 0x83, 0x83, 0xf1, 0x1b, 0x18, 0x10, 0x93, 0x92, - 0x90, 0x0e, 0xa1, 0xb3, 0x32, 0x13, 0x51, 0xb9, 0x8b, 0xb7, 0x1b, 0x97, 0x35, 0x85, 0x22, 0xec, 0x04, 0x33, 0x95, - 0x52, 0x41, 0x20, 0x4d, 0xbe, 0x7b, 0x9d, 0x5a, 0x30, 0xb4, 0x70, 0x4d, 0x05, 0xe4, 0xb5, 0x5d, 0x0f, 0x9a, 0x7c, - 0xa4, 0x18, 0xfa, 0x2a, 0x35, 0xe2, 0x65, 0x06, 0x5f, 0xc3, 0xe6, 0xaf, 0x89, 0x92, 0x3c, 0x64, 0x22, 0xf6, 0x0a, - 0x3e, 0x11, 0xb2, 0x29, 0xd8, 0x99, 0x40, 0x3f, 0xb4, 0x2b, 0x7b, 0xe9, 0x6e, 0x51, 0xb9, 0xb4, 0x68, 0x6c, 0x25, - 0x6a, 0xd6, 0xfc, 0x30, 0xde, 0x4c, 0x61, 0x3f, 0x7b, 0x94, 0x40, 0x40, 0x9a, 0xca, 0x49, 0xaa, 0x79, 0x0f, 0xd3, - 0x23, 0x00, 0x09, 0x76, 0x3f, 0x81, 0x85, 0x7e, 0x53, 0x62, 0x82, 0x45, 0xd5, 0xd8, 0x6d, 0x06, 0x5a, 0x73, 0x46, - 0x9a, 0x6f, 0x86, 0x5a, 0x7b, 0x53, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x66, 0x71, 0x98, 0x6e, 0x76, 0x8e, - 0x0c, 0xc1, 0x85, 0xc7, 0xff, 0x49, 0x89, 0x69, 0x20, 0xb9, 0xd4, 0x8d, 0x9f, 0x50, 0x87, 0xe1, 0xff, 0x16, 0xa4, - 0x80, 0x07, 0xb5, 0xd5, 0x58, 0x72, 0xee, 0x15, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, - 0x89, 0x62, 0x9e, 0x13, 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, - 0xca, 0xcf, 0xe8, 0x48, 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x0b, 0x30, 0xcd, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, - 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x92, 0x28, 0x82, 0x05, 0x1a, 0x74, 0x59, 0x83, - 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, 0x55, 0x60, 0x40, - 0xb9, 0xd3, 0x34, 0xac, 0x84, 0xb8, 0x44, 0x85, 0x59, 0xc5, 0xf9, 0xe3, 0x3a, 0xaf, 0x9b, 0x96, 0x25, 0x06, 0xe5, - 0x67, 0xae, 0xe1, 0xc6, 0xf7, 0x1a, 0xf9, 0xe3, 0x7b, 0x2f, 0x41, 0xb7, 0x13, 0x69, 0xef, 0xdf, 0xcf, 0xef, 0x91, - 0x85, 0x86, 0xf7, 0xc2, 0x66, 0xd0, 0x16, 0xe9, 0x92, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, - 0x30, 0x03, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, - 0xe4, 0xc5, 0x3a, 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x00, 0xfa, 0x15, 0x95, 0xc5, 0x06, 0x72, - 0x71, 0x53, 0xd6, 0x7a, 0x45, 0xa3, 0xd1, 0x8d, 0x5d, 0x58, 0x5d, 0x81, 0x4f, 0xa2, 0x74, 0x94, 0x88, 0x49, 0xcc, - 0xa4, 0xca, 0x15, 0xb9, 0x36, 0xba, 0x97, 0xb6, 0x68, 0x5e, 0x0a, 0x09, 0x5e, 0x11, 0xb8, 0x21, 0xf4, 0x95, 0xbe, - 0x5c, 0x6d, 0xa0, 0xe0, 0x51, 0x7b, 0x73, 0x11, 0x4c, 0x4c, 0x3c, 0x66, 0x48, 0x4d, 0xbf, 0x0e, 0xa7, 0x56, 0x16, - 0x4b, 0x0e, 0xbf, 0xce, 0x19, 0x6b, 0x28, 0x00, 0xe2, 0x93, 0x47, 0xeb, 0xdd, 0xa4, 0x37, 0x4a, 0x3b, 0x28, 0x8d, - 0x10, 0xdf, 0x55, 0xf8, 0xba, 0x0b, 0xc5, 0x57, 0xae, 0xba, 0xf7, 0x75, 0xcc, 0x8c, 0x0b, 0x46, 0x2f, 0xf9, 0x34, - 0x69, 0x5c, 0xbb, 0xa1, 0xbb, 0x3a, 0xdf, 0x7b, 0x5f, 0xca, 0xbc, 0x85, 0x63, 0x60, 0x93, 0x63, 0xe6, 0xbc, 0xf4, - 0xde, 0x1a, 0x27, 0xca, 0x3f, 0x98, 0x47, 0xbc, 0x72, 0x98, 0x55, 0x27, 0xc9, 0x3f, 0x0c, 0x7e, 0x08, 0xd6, 0xb7, - 0x34, 0x4e, 0x90, 0xbb, 0xea, 0x04, 0x99, 0x28, 0xb7, 0xa1, 0x37, 0xdc, 0xde, 0x5d, 0x05, 0x82, 0x38, 0x15, 0xd3, - 0x47, 0xe5, 0xb8, 0x7e, 0xb4, 0x40, 0xa5, 0x22, 0xe2, 0x73, 0x95, 0xbb, 0xb2, 0x36, 0x35, 0xd4, 0xe3, 0x3a, 0x99, - 0x85, 0xa6, 0x59, 0x91, 0x4b, 0xd9, 0xf4, 0x18, 0x99, 0x66, 0xa7, 0xda, 0xfc, 0xee, 0xda, 0x43, 0x3a, 0x86, 0xe6, - 0x62, 0xad, 0x16, 0xdc, 0xef, 0x2a, 0x0a, 0xef, 0x7a, 0xb1, 0x91, 0xca, 0x50, 0xb3, 0x1e, 0x45, 0x1f, 0xc7, 0x6d, - 0xe6, 0xf2, 0x28, 0xfb, 0xb3, 0x06, 0x80, 0xe9, 0x08, 0x8b, 0xee, 0xa6, 0x67, 0xec, 0x09, 0xf4, 0xf4, 0x44, 0x06, - 0x89, 0xde, 0xe8, 0x7c, 0xd5, 0x2a, 0xb1, 0x74, 0x05, 0x81, 0xdd, 0x1b, 0x32, 0x56, 0x25, 0xed, 0x96, 0xeb, 0x97, - 0xf3, 0x7c, 0x9e, 0xf3, 0xa5, 0x3c, 0x9f, 0x9a, 0x45, 0x77, 0xaf, 0xed, 0xde, 0x9c, 0x1a, 0x2a, 0xe6, 0x5a, 0xdd, - 0xe4, 0x37, 0x4c, 0xd7, 0xc1, 0x50, 0x8b, 0x20, 0xb3, 0xda, 0x55, 0x2f, 0xca, 0x72, 0xa3, 0x9e, 0xc9, 0xb1, 0x21, - 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0xf7, 0x8d, 0x6d, 0x21, 0xdb, 0xbc, 0xbc, 0x1a, 0xe5, 0x40, - 0x69, 0xb9, 0xbf, 0x4c, 0x18, 0xbe, 0xbf, 0xbe, 0xfe, 0x5e, 0xc8, 0xa9, 0xaa, 0xa3, 0xb7, 0x78, 0xad, 0x7b, 0x06, - 0x1b, 0xa5, 0x72, 0x22, 0x2e, 0xd8, 0xea, 0xc1, 0x9b, 0xbb, 0x57, 0xc0, 0x72, 0x01, 0xd8, 0x5d, 0x30, 0xa7, 0x31, - 0x54, 0xb5, 0x81, 0xbf, 0x5c, 0x3d, 0xd8, 0xaa, 0x3d, 0xfc, 0xe5, 0xe0, 0xcb, 0xe0, 0xc6, 0xc6, 0xc6, 0x36, 0xde, - 0xae, 0x25, 0x82, 0xbc, 0xc1, 0x03, 0x7d, 0xbc, 0xfa, 0x28, 0x68, 0xb9, 0x4a, 0x6c, 0x0f, 0x1c, 0x0a, 0x5b, 0x83, - 0x7c, 0x93, 0x32, 0x69, 0x38, 0x2f, 0x78, 0x36, 0x95, 0x33, 0x14, 0xf2, 0x9a, 0x8f, 0x83, 0xb6, 0x23, 0xfc, 0x1b, - 0x38, 0xb5, 0xe3, 0xe5, 0xc5, 0x27, 0xe8, 0x03, 0x9e, 0xae, 0x94, 0xa6, 0x22, 0x4e, 0x29, 0xb7, 0xe8, 0x72, 0x9d, - 0x07, 0x23, 0xc5, 0xc5, 0x04, 0x95, 0x8e, 0xbb, 0xb8, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, - 0x44, 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, - 0xd7, 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, - 0xe7, 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, - 0x52, 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, - 0x2d, 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, - 0xc4, 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, - 0xd6, 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, - 0xe2, 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0xe7, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, - 0x68, 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, - 0x57, 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, - 0x30, 0x93, 0xa6, 0xbc, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, - 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0xe1, 0x03, 0xb9, 0xd4, 0x92, 0xbf, - 0xcc, 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, - 0x51, 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x25, 0x7f, 0x8e, 0xa9, - 0x83, 0x59, 0xa9, 0xdd, 0xb4, 0xd8, 0x24, 0x79, 0xcf, 0x0c, 0x48, 0xae, 0xbe, 0x86, 0x87, 0xc6, 0x2f, 0x5e, 0x99, - 0x53, 0xc2, 0x17, 0x65, 0x2c, 0x2d, 0x8d, 0xb9, 0xf4, 0xdf, 0xca, 0xfb, 0xb4, 0x12, 0xb0, 0x57, 0x20, 0xa6, 0x0c, - 0x5c, 0x62, 0xe3, 0x82, 0xa4, 0xbc, 0x96, 0xa7, 0xec, 0xbe, 0x86, 0xf2, 0x5d, 0x32, 0xe9, 0x2a, 0x95, 0xb5, 0xc6, - 0xaa, 0xfb, 0x79, 0xce, 0xf2, 0xab, 0x7d, 0x86, 0xb9, 0xc9, 0x68, 0x90, 0x2d, 0x99, 0xd9, 0x94, 0x5f, 0xed, 0xdd, - 0xf8, 0x95, 0x87, 0x92, 0x0e, 0xd5, 0x2a, 0xdd, 0xbc, 0x74, 0xc3, 0x31, 0x6e, 0xdc, 0x70, 0x04, 0xb0, 0x31, 0xec, - 0x54, 0x91, 0x5a, 0xe7, 0xbf, 0x2f, 0x87, 0x9f, 0x68, 0xaf, 0x1d, 0xe9, 0x5d, 0x77, 0xb4, 0x32, 0x3d, 0xfd, 0x06, - 0x54, 0x8d, 0x2c, 0xa1, 0x9b, 0x50, 0xc5, 0x64, 0x24, 0x4a, 0x4c, 0x57, 0x29, 0x8f, 0xfa, 0x1a, 0x71, 0x0e, 0xe2, - 0x86, 0xf2, 0x17, 0xff, 0x14, 0x5e, 0x9d, 0x04, 0x68, 0x44, 0x2d, 0xc6, 0x59, 0xca, 0x5b, 0xe3, 0x68, 0x1a, 0x27, - 0x57, 0xc1, 0x3c, 0x6e, 0x4d, 0xb3, 0x34, 0x2b, 0x66, 0xc0, 0x95, 0x5e, 0x71, 0x05, 0x36, 0xfc, 0xb4, 0x35, 0x8f, - 0xbd, 0x97, 0x2c, 0x39, 0x67, 0x3c, 0x1e, 0x46, 0x9e, 0xbd, 0x97, 0x83, 0x78, 0xb0, 0xde, 0x46, 0x79, 0x9e, 0x5d, - 0xd8, 0xde, 0x87, 0xec, 0x14, 0x98, 0xd6, 0x7b, 0x77, 0x79, 0x75, 0xc6, 0x52, 0xef, 0xe3, 0xe9, 0x3c, 0xe5, 0x73, - 0xaf, 0x88, 0xd2, 0xa2, 0x55, 0xb0, 0x3c, 0x1e, 0x83, 0x9a, 0x48, 0xb2, 0xbc, 0x85, 0xf9, 0xcf, 0x53, 0x16, 0x24, - 0xf1, 0xd9, 0x84, 0x5b, 0xa3, 0x28, 0xff, 0xd4, 0x6b, 0xb5, 0x66, 0x79, 0x3c, 0x8d, 0xf2, 0xab, 0x16, 0xb5, 0x08, - 0x3e, 0x6b, 0x6f, 0x47, 0x9f, 0x8f, 0x1f, 0xf6, 0x78, 0x0e, 0x7d, 0x63, 0xa4, 0x62, 0x00, 0xc2, 0xc7, 0xda, 0xde, - 0x69, 0x4f, 0x8b, 0x7b, 0xe2, 0x44, 0x29, 0x4a, 0x79, 0x79, 0xe2, 0x5d, 0x31, 0x80, 0xdb, 0x3f, 0xe5, 0xa9, 0x07, - 0xbe, 0x1c, 0xcf, 0xd2, 0xc5, 0x70, 0x9e, 0x17, 0x30, 0xc0, 0x2c, 0x8b, 0x53, 0xce, 0xf2, 0xde, 0x69, 0x96, 0x03, - 0xd9, 0x5a, 0x79, 0x34, 0x8a, 0xe7, 0x45, 0xf0, 0x70, 0x76, 0xd9, 0x43, 0x5b, 0xe1, 0x2c, 0xcf, 0xe6, 0xe9, 0x48, - 0xce, 0x15, 0xa7, 0xb0, 0x31, 0x62, 0x6e, 0x56, 0xd0, 0x97, 0x50, 0x00, 0xbe, 0x94, 0x45, 0x79, 0xeb, 0x0c, 0x3b, - 0xa3, 0xa1, 0xdf, 0x1e, 0xb1, 0x33, 0x2f, 0x3f, 0x3b, 0x8d, 0x9c, 0x4e, 0xf7, 0xb1, 0xa7, 0xfe, 0xf3, 0x77, 0x5c, - 0x30, 0xdc, 0x57, 0x16, 0x77, 0xda, 0xed, 0xbf, 0x71, 0x7b, 0x8d, 0x59, 0x08, 0xa0, 0xa0, 0x33, 0xbb, 0xb4, 0x8a, - 0x2c, 0x81, 0xf5, 0x59, 0xd5, 0xb3, 0x37, 0x03, 0xbf, 0x29, 0x4e, 0xcf, 0x82, 0xee, 0xec, 0xb2, 0x44, 0xec, 0x02, - 0x91, 0x90, 0x29, 0x91, 0x94, 0x6f, 0x8b, 0xdf, 0x0a, 0xf1, 0x93, 0xd5, 0x10, 0x77, 0x15, 0xc4, 0x15, 0xd5, 0x5b, - 0x23, 0xd8, 0x07, 0x44, 0xfe, 0x4e, 0x21, 0x00, 0x99, 0x80, 0x13, 0x98, 0x2b, 0x38, 0xe8, 0xe5, 0x37, 0x83, 0xd1, - 0x5d, 0x0d, 0xc6, 0x93, 0xdb, 0xc0, 0xc8, 0xd3, 0xd1, 0xa2, 0xbe, 0xae, 0x1d, 0x70, 0x4e, 0x7b, 0x13, 0x86, 0xfc, - 0x14, 0x74, 0xf1, 0xf9, 0x22, 0x1e, 0xf1, 0x89, 0x78, 0x24, 0x76, 0xbe, 0x10, 0x75, 0x3b, 0xed, 0xb6, 0x78, 0x2f, - 0x40, 0xa1, 0x05, 0x1d, 0x1f, 0x1b, 0x00, 0x13, 0x7d, 0xb1, 0xee, 0x23, 0x36, 0xdf, 0xdd, 0xfa, 0xa5, 0x1a, 0x8f, - 0xa9, 0xbc, 0x41, 0xa1, 0x22, 0xd4, 0x37, 0x5b, 0x30, 0xe3, 0x2d, 0xef, 0x77, 0xf4, 0x41, 0xd5, 0xe0, 0x3b, 0x46, - 0x5a, 0x2f, 0xe0, 0x9e, 0x99, 0x0b, 0xd4, 0x4b, 0xfb, 0x18, 0x92, 0x6a, 0xb5, 0x5c, 0xd0, 0x1b, 0x0c, 0x43, 0x48, - 0x74, 0x20, 0xe8, 0xe4, 0x83, 0x82, 0xbe, 0xa9, 0x91, 0xb9, 0x41, 0xe1, 0x64, 0x2e, 0x6c, 0xf9, 0x4c, 0xcb, 0x75, - 0x50, 0xd2, 0xe0, 0x65, 0x7f, 0xc1, 0x64, 0x03, 0x90, 0xde, 0x95, 0xa4, 0xe5, 0xd5, 0xd1, 0x93, 0x72, 0xf9, 0xb2, - 0x21, 0x51, 0x0e, 0x7c, 0x7d, 0x3e, 0x41, 0xbf, 0x5b, 0x7f, 0x28, 0xc6, 0x48, 0xa9, 0xd9, 0xb2, 0xdd, 0x01, 0xd3, - 0x59, 0x59, 0x98, 0x7d, 0xc6, 0x4a, 0x1c, 0xe5, 0x2b, 0xb0, 0xa4, 0x31, 0xf4, 0xfa, 0x73, 0x28, 0xdc, 0x34, 0xe5, - 0xa4, 0x6d, 0xdc, 0x74, 0xfd, 0x1f, 0x56, 0x3c, 0xa6, 0x6c, 0x67, 0x15, 0x1b, 0x07, 0xd7, 0xe5, 0x78, 0x28, 0xae, - 0x1d, 0x16, 0x98, 0x2d, 0xfe, 0xdb, 0x3d, 0x09, 0x47, 0xa3, 0x55, 0x64, 0xf3, 0x7c, 0x48, 0xa1, 0xc1, 0xe5, 0x10, - 0x83, 0x4d, 0x1a, 0xde, 0xf6, 0x98, 0x56, 0x2c, 0xe8, 0x77, 0xd7, 0xbe, 0xaa, 0xc0, 0xe9, 0xd4, 0x45, 0x5c, 0x6a, - 0x90, 0x61, 0x15, 0x05, 0x36, 0xea, 0xca, 0x11, 0x25, 0xd8, 0xd1, 0x85, 0x4f, 0x7f, 0x9e, 0xc6, 0x20, 0x5a, 0x8f, - 0xe3, 0x11, 0x5d, 0x74, 0x89, 0x47, 0x74, 0xf2, 0xd1, 0xa2, 0x4c, 0x27, 0x0c, 0xa5, 0x43, 0x81, 0x24, 0x38, 0x3e, - 0xcb, 0xcc, 0x19, 0xbb, 0x65, 0xe3, 0xe9, 0x85, 0xa1, 0x9b, 0x47, 0xd9, 0x34, 0x8a, 0xd3, 0x00, 0x3f, 0x48, 0xe2, - 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0x5f, 0x45, 0xfb, 0x8e, 0xeb, 0xff, 0x04, 0x82, 0x8b, 0xfa, 0x97, 0xd2, 0xf1, - 0xd3, 0x70, 0xa9, 0x73, 0xe5, 0x7a, 0x29, 0x08, 0x3b, 0xae, 0x8c, 0x64, 0x46, 0x81, 0x95, 0x5d, 0x4e, 0x7f, 0x06, - 0xad, 0x4e, 0xa0, 0xae, 0xfe, 0x9b, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, - 0xf3, 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, - 0x56, 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, - 0x5b, 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xe1, 0x55, 0xa7, 0x7a, 0xd6, 0x96, 0x62, 0xef, 0xe1, - 0xc9, 0xae, 0x10, 0x52, 0x16, 0xb1, 0x6e, 0x68, 0x83, 0xd4, 0xb0, 0xad, 0x3f, 0x0e, 0x81, 0xce, 0x9f, 0x42, 0x7b, - 0x63, 0xe1, 0xa8, 0xbb, 0x00, 0x39, 0xcc, 0xb5, 0x27, 0x14, 0x35, 0x7d, 0x44, 0xc0, 0xee, 0x6f, 0x2c, 0x78, 0xb9, - 0xbb, 0x25, 0x7a, 0xf7, 0x4f, 0xca, 0x82, 0x74, 0xaa, 0x19, 0xfb, 0xab, 0xa6, 0x10, 0x75, 0x30, 0x2c, 0x65, 0x1c, - 0xe3, 0xb8, 0xb9, 0xb6, 0x13, 0x45, 0x90, 0x5b, 0x32, 0x6e, 0x81, 0x19, 0x56, 0x51, 0x0e, 0x62, 0x44, 0xe7, 0xd0, - 0x14, 0x22, 0x6d, 0xa4, 0xb7, 0x0c, 0xc5, 0x09, 0x42, 0x30, 0xd8, 0x58, 0xc4, 0x65, 0xb8, 0xb1, 0x60, 0xe9, 0x30, - 0x1b, 0xb1, 0x8f, 0x1f, 0x5e, 0xe1, 0x35, 0x89, 0x2c, 0x45, 0x79, 0x9a, 0xb9, 0xe5, 0x09, 0x18, 0x58, 0x08, 0x69, - 0xae, 0xbe, 0x52, 0x03, 0xc0, 0x88, 0x58, 0x91, 0x45, 0xa3, 0x22, 0x28, 0xac, 0xb4, 0xad, 0x81, 0x80, 0x10, 0x1c, - 0x59, 0x2c, 0x00, 0x13, 0x94, 0x7a, 0x31, 0xc0, 0x4f, 0xb4, 0xee, 0xc3, 0x40, 0xbb, 0x5b, 0xa2, 0x11, 0xe0, 0x9a, - 0x23, 0x1a, 0x15, 0xaa, 0x98, 0x55, 0x64, 0xa2, 0x3b, 0x8a, 0xcf, 0x35, 0x39, 0x29, 0xc5, 0xba, 0xbf, 0x9b, 0x44, - 0xa7, 0x2c, 0x81, 0x21, 0x81, 0xaf, 0xda, 0x30, 0x92, 0x78, 0xb5, 0x76, 0xe3, 0x74, 0x36, 0x97, 0x5f, 0x0b, 0x83, - 0x89, 0x3b, 0x78, 0x80, 0x8b, 0x97, 0x19, 0x06, 0xea, 0x44, 0x32, 0x90, 0x03, 0x00, 0x88, 0x74, 0x18, 0x82, 0xd0, - 0x55, 0xac, 0x02, 0xa5, 0xf1, 0x68, 0xb9, 0x0c, 0xf6, 0xf7, 0x0c, 0x4b, 0x53, 0x78, 0x9e, 0xc6, 0x29, 0x3e, 0x16, - 0xf8, 0x18, 0x5d, 0xe2, 0x63, 0x06, 0x8f, 0x1a, 0xf7, 0xbc, 0xb4, 0xff, 0xaa, 0xab, 0x92, 0xc9, 0x15, 0xb0, 0x34, - 0x01, 0xb2, 0xeb, 0x6b, 0x50, 0x5b, 0x9a, 0x04, 0xbb, 0x5b, 0x40, 0x2c, 0xe4, 0x1e, 0xf1, 0xed, 0x18, 0x66, 0x92, - 0x91, 0x15, 0xb3, 0x96, 0x28, 0xb7, 0xc8, 0x38, 0x08, 0xc1, 0x77, 0xcc, 0x9d, 0x86, 0x0d, 0xe4, 0xc9, 0x2c, 0x99, - 0x67, 0xf8, 0xe2, 0xda, 0x96, 0xf8, 0xb8, 0x87, 0x20, 0x0a, 0x3d, 0x22, 0x86, 0xba, 0x8c, 0xcb, 0xcf, 0xf6, 0xc4, - 0xa1, 0x8d, 0xb3, 0x80, 0x19, 0x8a, 0xca, 0x8c, 0x47, 0x71, 0x22, 0x1a, 0xaf, 0xc0, 0xa7, 0x91, 0xee, 0x48, 0xe8, - 0xec, 0x6e, 0x55, 0xb0, 0x01, 0xf0, 0x4a, 0x22, 0x88, 0x54, 0x4e, 0x5b, 0x94, 0x53, 0x0a, 0x80, 0xdc, 0xe6, 0xd5, - 0x27, 0x9d, 0x80, 0x29, 0xc0, 0x88, 0x1e, 0x1d, 0xd3, 0x6c, 0x83, 0x21, 0x12, 0x0b, 0x67, 0x6c, 0x6c, 0x5d, 0xfb, - 0x2f, 0xff, 0xfc, 0x0f, 0xb6, 0x27, 0x40, 0xcc, 0xc6, 0x63, 0x90, 0x72, 0xd6, 0xba, 0x86, 0xff, 0xeb, 0x1f, 0xff, - 0xef, 0xff, 0xf9, 0xaf, 0xba, 0x6d, 0x0a, 0x4d, 0x4f, 0x02, 0x71, 0xb4, 0xa0, 0x49, 0x4a, 0x29, 0x9e, 0xf6, 0x38, - 0x4a, 0x57, 0x80, 0x74, 0x08, 0x54, 0x9a, 0x31, 0x36, 0xf2, 0x6c, 0x0b, 0x34, 0x81, 0x78, 0x3e, 0x4e, 0xd8, 0x39, - 0x93, 0x1f, 0x96, 0xd1, 0x83, 0xe8, 0xca, 0x21, 0x58, 0x30, 0x5c, 0xde, 0x79, 0x95, 0xdb, 0x40, 0xd1, 0x52, 0x52, - 0xbc, 0x4e, 0x30, 0xcf, 0x36, 0x06, 0x6d, 0xce, 0xd1, 0xae, 0x0f, 0xeb, 0x81, 0x4a, 0xb5, 0x6d, 0x01, 0x2f, 0x99, - 0xbd, 0xab, 0x20, 0x5e, 0x82, 0xeb, 0x34, 0xc7, 0xa6, 0x29, 0x2b, 0x8a, 0x55, 0x60, 0x01, 0x4d, 0x3c, 0xbb, 0x6a, - 0x62, 0xd7, 0x3a, 0x00, 0x00, 0xdd, 0x9d, 0x1d, 0x31, 0x2d, 0x54, 0xb0, 0xf1, 0x18, 0x36, 0x38, 0xea, 0xb6, 0x84, - 0xe3, 0xb1, 0x45, 0xd8, 0xb7, 0xdf, 0x82, 0x2c, 0xb1, 0xc1, 0x3f, 0x74, 0xf5, 0x01, 0x34, 0x4d, 0xaf, 0x84, 0x9d, - 0x31, 0x87, 0xe8, 0x6c, 0x0c, 0xa3, 0x9f, 0x0c, 0xa4, 0xb2, 0xe1, 0xa7, 0x55, 0x8c, 0xb1, 0x96, 0x11, 0xfe, 0xfd, - 0x5f, 0xfe, 0xf1, 0xbf, 0xc1, 0xd8, 0xd4, 0x6f, 0x3d, 0x17, 0x40, 0xab, 0xff, 0x09, 0xad, 0xe6, 0xe9, 0x2d, 0xed, - 0xfe, 0xf2, 0xf7, 0xff, 0x1d, 0x9a, 0xd1, 0x45, 0x29, 0xe0, 0x13, 0x82, 0x68, 0x88, 0xb6, 0xe9, 0xaf, 0x02, 0xa9, - 0x36, 0xc8, 0xda, 0x99, 0xfe, 0x09, 0xc1, 0x2e, 0x78, 0x36, 0xbb, 0x11, 0x1c, 0x84, 0x7a, 0x98, 0x64, 0x05, 0xd3, - 0xf0, 0x08, 0x7d, 0xf2, 0xeb, 0x00, 0xa2, 0xb9, 0x66, 0xb0, 0x6b, 0x0b, 0x4b, 0x8f, 0x23, 0x56, 0x68, 0xd5, 0x38, - 0x8d, 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, - 0xda, 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, - 0x52, 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, - 0x48, 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, - 0x24, 0xd2, 0xba, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, - 0x9f, 0x87, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, - 0x12, 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, - 0x97, 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, - 0x0c, 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, - 0x7f, 0x83, 0x97, 0x1d, 0x2d, 0xec, 0x8d, 0x96, 0x42, 0x41, 0x86, 0x0d, 0x27, 0xc3, 0x46, 0x6a, 0x54, 0xd3, 0xa6, - 0x40, 0xc7, 0x2f, 0x5b, 0x6d, 0x3b, 0x1c, 0x63, 0xf7, 0x9a, 0xf6, 0xe7, 0x52, 0xfb, 0xc7, 0xd2, 0xde, 0x97, 0xda, - 0x1f, 0x3f, 0x69, 0xd3, 0xd0, 0xfe, 0xf1, 0x5a, 0xed, 0x8f, 0x94, 0x1b, 0xe0, 0xc8, 0xa1, 0xbd, 0x89, 0xd1, 0x2d, - 0xc3, 0xd6, 0xe0, 0x68, 0x67, 0x0d, 0x27, 0x6c, 0xf8, 0x49, 0x9a, 0x59, 0x84, 0x00, 0x86, 0x77, 0xb4, 0x31, 0x29, - 0x30, 0x00, 0x93, 0xe1, 0xa4, 0xd4, 0x9b, 0x1e, 0x1f, 0x8d, 0x09, 0xb8, 0xbb, 0x18, 0x33, 0x14, 0xfd, 0xb0, 0x66, - 0x5f, 0xb1, 0x72, 0x0b, 0xc7, 0x11, 0x1b, 0x46, 0x3c, 0x03, 0x66, 0x5b, 0x38, 0xd8, 0x89, 0xb7, 0x10, 0xc1, 0xc2, - 0xc0, 0x7e, 0xff, 0x6e, 0xff, 0xc0, 0xf6, 0x4e, 0xb3, 0xd1, 0x55, 0x60, 0x83, 0x33, 0x06, 0xd6, 0x94, 0xeb, 0xf3, - 0x09, 0x4b, 0x1d, 0xe5, 0xf9, 0x64, 0x09, 0xb8, 0x9a, 0xd9, 0x99, 0xf8, 0xb6, 0x45, 0xf3, 0xa0, 0x03, 0x08, 0x4b, - 0x1f, 0xbf, 0xec, 0xef, 0x72, 0xf1, 0x5d, 0x58, 0x9e, 0xe3, 0x63, 0x1f, 0x53, 0x3d, 0x76, 0xb7, 0xe0, 0x01, 0x5f, - 0xf6, 0x51, 0xef, 0xd1, 0xdb, 0xc6, 0x62, 0xc9, 0x6d, 0x18, 0xe0, 0x10, 0x93, 0xbe, 0x40, 0xa1, 0xa0, 0x56, 0x27, - 0x01, 0x22, 0x06, 0x8f, 0x30, 0xd6, 0x96, 0x1a, 0x17, 0x21, 0x54, 0xfd, 0xb5, 0xe3, 0x52, 0xd9, 0xad, 0x34, 0xef, - 0x08, 0xcd, 0x52, 0x72, 0x5c, 0xb0, 0xf7, 0x48, 0x97, 0x08, 0x53, 0x87, 0x8a, 0xd6, 0x41, 0xa0, 0x6b, 0x2a, 0x73, - 0x45, 0x74, 0x30, 0x80, 0x21, 0x33, 0x57, 0x00, 0x02, 0x7f, 0x09, 0xed, 0x13, 0xf3, 0xfb, 0x6f, 0xe2, 0x53, 0x4d, - 0x9a, 0x38, 0x87, 0x7f, 0xf2, 0xae, 0x98, 0x77, 0x75, 0x42, 0x2d, 0x55, 0xb0, 0x01, 0xa3, 0x60, 0x18, 0x94, 0x69, - 0xab, 0xa8, 0x12, 0xd8, 0x69, 0x49, 0x34, 0x2b, 0x58, 0xa0, 0x1e, 0x64, 0xdc, 0x01, 0xc3, 0x17, 0xcb, 0x81, 0x1e, - 0xd3, 0x9e, 0x2b, 0xf9, 0x64, 0x61, 0x06, 0x26, 0x1e, 0xb5, 0xdb, 0x3d, 0xbc, 0x54, 0xd1, 0x8a, 0xc0, 0x3a, 0x48, - 0x83, 0x84, 0x8d, 0x79, 0xc9, 0xf1, 0xd6, 0xfe, 0x42, 0x45, 0x82, 0xfc, 0xee, 0x4e, 0xce, 0xa6, 0x96, 0x8f, 0xff, - 0xbf, 0x6d, 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, - 0x0d, 0x19, 0x46, 0xc9, 0x4a, 0x9e, 0x83, 0xbc, 0xf7, 0x78, 0x6e, 0xb6, 0x03, 0x39, 0xbd, 0x14, 0x2a, 0x5b, 0x0e, - 0xd6, 0x6c, 0xbb, 0xd2, 0x3f, 0x5a, 0x6e, 0xac, 0x22, 0x5e, 0xf5, 0xb7, 0x25, 0x0a, 0x19, 0xb1, 0xb9, 0x52, 0xa8, - 0xa8, 0x85, 0xe8, 0x61, 0xe2, 0xb4, 0x1c, 0xb5, 0xbb, 0xd5, 0x62, 0x2e, 0x49, 0x5c, 0x1c, 0x92, 0xb8, 0x20, 0xf1, - 0x77, 0xb4, 0x10, 0x73, 0x0f, 0xa3, 0x64, 0xe8, 0x20, 0x00, 0x56, 0xcb, 0x7a, 0x02, 0xd4, 0x74, 0x55, 0xe4, 0xc8, - 0x7f, 0x8c, 0xc4, 0x2d, 0x85, 0xb0, 0x5c, 0x41, 0xa5, 0x93, 0xa3, 0xb2, 0xec, 0x31, 0xe6, 0x1c, 0x7e, 0x90, 0x97, - 0x40, 0xc4, 0xdd, 0x5f, 0xfd, 0xfd, 0xc4, 0x76, 0xe9, 0x1e, 0x79, 0x3f, 0x1b, 0x1f, 0xa5, 0xb3, 0x15, 0xb3, 0xdb, - 0x1e, 0x2c, 0x83, 0xd9, 0x53, 0x7e, 0x42, 0xf2, 0xa6, 0xbe, 0x26, 0x9b, 0x53, 0xff, 0x9f, 0x43, 0x1c, 0xe1, 0x8d, - 0x63, 0xa3, 0x89, 0x4e, 0x23, 0x5f, 0xb5, 0x88, 0x3f, 0x6d, 0xec, 0x2a, 0x8e, 0x40, 0xbe, 0x5e, 0x17, 0xc9, 0xfa, - 0xe6, 0xf6, 0x48, 0x56, 0x71, 0xc7, 0x48, 0xd6, 0x37, 0xbf, 0x73, 0x24, 0xeb, 0x6b, 0x33, 0x92, 0x85, 0x02, 0xfa, - 0xd5, 0xaf, 0x89, 0x36, 0xe5, 0xd9, 0x45, 0x11, 0x76, 0x64, 0xe6, 0x04, 0xc8, 0x3a, 0x0c, 0x3b, 0xfd, 0xf5, 0x23, - 0x4c, 0x30, 0x51, 0x23, 0xbe, 0x44, 0x01, 0x25, 0x91, 0xec, 0x09, 0x6a, 0x45, 0x86, 0x73, 0xda, 0x3a, 0xab, 0xb2, - 0xf5, 0x50, 0x5d, 0x23, 0x03, 0xd7, 0xd7, 0xd5, 0xa1, 0xb6, 0xae, 0x0a, 0xf8, 0x04, 0xf4, 0x1d, 0x58, 0xdd, 0xb1, - 0xbb, 0xa9, 0xd2, 0xf9, 0xcc, 0x11, 0x7a, 0xea, 0x94, 0x46, 0x30, 0xd1, 0xc2, 0xfe, 0x2f, 0x87, 0x9d, 0xde, 0x76, - 0x67, 0x0a, 0xbd, 0x41, 0x81, 0xc3, 0x5b, 0xbb, 0xb7, 0xbd, 0x8d, 0x6f, 0x17, 0xea, 0xad, 0x8b, 0x6f, 0xb1, 0x7a, - 0xdb, 0xc1, 0xb7, 0xa1, 0x7a, 0x7b, 0x84, 0x6f, 0x23, 0xf5, 0xf6, 0x18, 0xdf, 0xce, 0xed, 0xf2, 0x90, 0x6b, 0xe0, - 0x1e, 0x03, 0x5f, 0x91, 0x37, 0x13, 0xa8, 0x32, 0xd8, 0xf4, 0x78, 0xfd, 0x32, 0x3a, 0x0b, 0x62, 0x4f, 0x78, 0x97, - 0x41, 0xee, 0x5d, 0x80, 0xc6, 0x09, 0x28, 0xdb, 0xf0, 0x39, 0x7e, 0x87, 0x03, 0x9c, 0xa4, 0x83, 0x78, 0xca, 0xd4, - 0x07, 0x89, 0x15, 0xd6, 0x60, 0xc0, 0x1e, 0xb6, 0x8f, 0xca, 0x9e, 0x5e, 0x27, 0x11, 0xcf, 0x52, 0xd9, 0x1c, 0xb4, - 0x72, 0x55, 0x9d, 0x98, 0xae, 0xa5, 0x57, 0x78, 0x8d, 0xfe, 0x32, 0xe2, 0x11, 0x63, 0x30, 0xcc, 0x5a, 0x97, 0xe0, - 0xc1, 0xae, 0xd4, 0x69, 0x08, 0x91, 0xd6, 0x69, 0x84, 0x93, 0x7e, 0x3b, 0x88, 0xce, 0xf4, 0xf3, 0x1b, 0xb0, 0xb4, - 0xa3, 0x33, 0xd9, 0x72, 0xbd, 0x0e, 0x23, 0x10, 0x4d, 0xfd, 0xa5, 0x80, 0x20, 0x53, 0x0c, 0x96, 0x06, 0x3d, 0x69, - 0xa9, 0xbf, 0x90, 0x3a, 0x75, 0x8d, 0x46, 0xd3, 0xd7, 0x8b, 0x80, 0xa2, 0x55, 0xc1, 0x2e, 0x18, 0xfc, 0x54, 0x2a, - 0x28, 0x0c, 0x15, 0x58, 0x20, 0xaa, 0xd7, 0xa8, 0x32, 0x1d, 0x6c, 0x58, 0xab, 0xd0, 0x2c, 0xa5, 0xcb, 0xcc, 0xd3, - 0x1d, 0x7d, 0xb4, 0xb3, 0x2c, 0x5e, 0x3f, 0xeb, 0x0c, 0xf1, 0x1f, 0x29, 0xbc, 0x3f, 0x1b, 0x8f, 0xc7, 0x37, 0xea, - 0xb6, 0xcf, 0x46, 0x63, 0xd6, 0x65, 0x3b, 0x3d, 0x8c, 0xfc, 0xb7, 0xa4, 0x38, 0xed, 0x94, 0x44, 0xbb, 0xc5, 0xdd, - 0x1a, 0xa3, 0xe4, 0x05, 0x75, 0x77, 0x77, 0x25, 0x58, 0x02, 0x55, 0x16, 0x20, 0xfc, 0xcf, 0xe2, 0x34, 0x68, 0x97, - 0xfe, 0xb9, 0xd4, 0x1a, 0x9f, 0x3d, 0x79, 0xf2, 0xa4, 0xf4, 0x47, 0xea, 0xad, 0x3d, 0x1a, 0x95, 0xfe, 0x70, 0xa1, - 0xd1, 0x68, 0xb7, 0xc7, 0xe3, 0xd2, 0x8f, 0x55, 0xc1, 0x76, 0x77, 0x38, 0xda, 0xee, 0x96, 0xfe, 0x85, 0xd1, 0xa2, - 0xf4, 0x99, 0x7c, 0xcb, 0xd9, 0xa8, 0x76, 0x7c, 0xf0, 0xb8, 0x0d, 0x95, 0x82, 0xd1, 0x16, 0xe8, 0x5d, 0x8a, 0xc7, - 0x20, 0x9a, 0xf3, 0x0c, 0x0c, 0xbb, 0xb2, 0x57, 0x80, 0x7c, 0x1e, 0x4b, 0x09, 0x2f, 0xbe, 0xf7, 0x8b, 0x52, 0xfd, - 0x95, 0x29, 0xd5, 0x91, 0x99, 0x49, 0x9a, 0x17, 0xa4, 0x0d, 0x9a, 0xd5, 0xc8, 0x59, 0x54, 0xfd, 0x2a, 0x2c, 0x2a, - 0x61, 0x8f, 0xd2, 0x06, 0x5b, 0x0a, 0x19, 0xff, 0xc3, 0x3a, 0x19, 0xff, 0xfd, 0xed, 0x32, 0xfe, 0xf4, 0x6e, 0x22, - 0xfe, 0xfb, 0xdf, 0x59, 0xc4, 0xff, 0x60, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0xc0, 0x74, 0x26, 0x9b, 0xf9, 0x34, 0xbb, - 0x6c, 0xe1, 0x96, 0xc8, 0x6d, 0x92, 0x9e, 0xd3, 0x3b, 0x09, 0xff, 0x15, 0xf9, 0x60, 0x6a, 0x30, 0xe3, 0xe3, 0xc1, - 0x3c, 0x3b, 0x3b, 0x4b, 0x98, 0x92, 0xf1, 0x46, 0x05, 0x99, 0xe3, 0xef, 0xd2, 0xd0, 0x7e, 0x07, 0x9e, 0xb1, 0x51, - 0x32, 0x1e, 0x43, 0xd1, 0x78, 0x6c, 0xab, 0x7c, 0x69, 0x90, 0x67, 0xd4, 0xea, 0x6d, 0xad, 0x84, 0x5a, 0x7d, 0xf1, - 0x85, 0x59, 0x66, 0x16, 0xc8, 0x90, 0x9e, 0x69, 0x8c, 0xc8, 0x9a, 0x51, 0x5c, 0xe0, 0x1e, 0xac, 0x3e, 0x76, 0x8c, - 0xf6, 0xce, 0x14, 0x94, 0x4a, 0x3c, 0xc4, 0x73, 0x91, 0xe6, 0x87, 0x65, 0x44, 0x6e, 0xfb, 0x32, 0x72, 0xd5, 0xf9, - 0xb7, 0xf1, 0x0d, 0xc3, 0xea, 0xcc, 0x1b, 0x16, 0x5f, 0xe6, 0xb7, 0x3c, 0xbd, 0x7a, 0x35, 0x72, 0xf6, 0xc0, 0x1a, - 0x8e, 0x8b, 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, - 0xec, 0x19, 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, - 0x92, 0x6e, 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xe2, 0x79, 0x88, - 0x98, 0x61, 0x54, 0xaa, 0x33, 0x10, 0x20, 0xdc, 0x0c, 0x3f, 0xd1, 0x24, 0x86, 0x50, 0x07, 0x05, 0x15, 0xf5, 0xae, - 0xaf, 0xcd, 0x2f, 0x85, 0xd6, 0xbe, 0x2a, 0xd9, 0xe0, 0x01, 0x86, 0x9f, 0xf8, 0x45, 0x6d, 0x90, 0xcd, 0xb9, 0xe3, - 0x50, 0x2b, 0xc7, 0x2d, 0xbd, 0x9d, 0x76, 0x1b, 0x54, 0x8c, 0x2f, 0xbe, 0x03, 0xe5, 0xe8, 0xce, 0x12, 0xdf, 0x75, - 0xe7, 0x12, 0x4b, 0xdf, 0x65, 0xd3, 0x24, 0xc6, 0x0f, 0xc7, 0x08, 0x44, 0x8d, 0xbb, 0x43, 0x6a, 0x11, 0x9b, 0xef, - 0xbe, 0xf2, 0x1d, 0x0d, 0xc2, 0xba, 0xab, 0x38, 0x58, 0xe6, 0xd6, 0xd6, 0x0b, 0xb1, 0xad, 0xb0, 0x6a, 0x96, 0xc1, - 0xb9, 0x45, 0x67, 0x16, 0x17, 0x46, 0x00, 0xbf, 0xb6, 0x0d, 0x4a, 0x15, 0xc1, 0x17, 0x61, 0xf8, 0x3d, 0x0c, 0x36, - 0x0b, 0xc7, 0x5b, 0x01, 0x5d, 0x77, 0x79, 0x0d, 0xc8, 0xd1, 0x19, 0xd6, 0x8c, 0xae, 0xaa, 0x54, 0x41, 0x69, 0x1e, - 0xc1, 0x18, 0xc8, 0x50, 0x24, 0x1d, 0xd6, 0x38, 0x15, 0x7a, 0x0b, 0xa6, 0x21, 0x01, 0xac, 0xfd, 0x3a, 0x74, 0x6b, - 0x6c, 0x05, 0xb6, 0x90, 0x16, 0xa0, 0xf4, 0xb0, 0x43, 0xdf, 0xaa, 0x81, 0x9e, 0x2e, 0x07, 0xe0, 0x6f, 0x74, 0xf2, - 0x4e, 0xfc, 0xe2, 0xc2, 0x83, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, - 0x86, 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, - 0x41, 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, - 0xdf, 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, - 0xd5, 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0xff, 0x8c, 0xcc, 0x85, 0x66, 0x31, 0x1d, 0xc0, 0xdf, - 0x05, 0xb2, 0x20, 0x1a, 0xe3, 0x17, 0x16, 0xef, 0xd2, 0xf2, 0x94, 0xb2, 0x5f, 0x17, 0xa8, 0xd6, 0x83, 0xce, 0x13, - 0xf0, 0xf6, 0xee, 0x3c, 0xfc, 0xcd, 0xe8, 0x97, 0x92, 0x46, 0xea, 0x12, 0xb3, 0x6d, 0xf7, 0x50, 0x5e, 0x24, 0xd1, - 0x15, 0x38, 0x9d, 0x64, 0x63, 0x9c, 0x62, 0xf4, 0xb8, 0x37, 0xcb, 0x64, 0x26, 0x49, 0xce, 0x12, 0xfa, 0x19, 0x13, - 0xb9, 0x14, 0xdb, 0x8f, 0x66, 0x97, 0x6a, 0x35, 0x3a, 0x8d, 0x0c, 0x91, 0xdf, 0x35, 0x11, 0x64, 0x7d, 0xe6, 0x49, - 0x3d, 0x99, 0x61, 0x07, 0x60, 0x10, 0x86, 0x4d, 0x2b, 0x17, 0x50, 0xb5, 0xa1, 0xc4, 0x48, 0x85, 0xa9, 0x06, 0xb2, - 0xfc, 0x6d, 0x50, 0x95, 0x51, 0xc1, 0x7a, 0xf8, 0xa9, 0xcb, 0x18, 0x5c, 0x5b, 0x69, 0x3c, 0x4d, 0xe3, 0xd1, 0x28, - 0x61, 0x3d, 0x65, 0x1f, 0x59, 0x9d, 0x47, 0x98, 0x49, 0x62, 0x2e, 0x59, 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, - 0xa7, 0x60, 0xaf, 0xe1, 0xf7, 0x2a, 0x57, 0x92, 0x53, 0xa6, 0x58, 0xb4, 0x2b, 0xe2, 0xd1, 0x73, 0x1d, 0x97, 0x1d, - 0x30, 0x16, 0x69, 0xc1, 0xdb, 0x3d, 0x9e, 0xcd, 0x82, 0xd6, 0x76, 0x1d, 0x11, 0xac, 0xd2, 0x28, 0x78, 0x2b, 0xd0, - 0xf2, 0xd0, 0x3a, 0x10, 0x5a, 0xce, 0xf2, 0x3b, 0xb2, 0x8c, 0x06, 0xc0, 0x6f, 0x22, 0xea, 0xa2, 0xb2, 0x8e, 0xcc, - 0x5f, 0x67, 0xb7, 0x7c, 0xbe, 0x7a, 0xb7, 0x7c, 0xae, 0x76, 0xcb, 0xcd, 0x1c, 0xfb, 0xd9, 0xb8, 0x83, 0xff, 0xf4, - 0x2a, 0x84, 0x60, 0x55, 0x80, 0x1c, 0x16, 0xda, 0xc5, 0xad, 0x2e, 0xfc, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x8f, 0x0f, - 0x16, 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xaf, 0x5d, 0xab, 0xea, 0x3c, 0xc4, 0x3a, 0xec, 0xb5, 0xb3, 0x5c, 0xd7, 0xbd, - 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0xb8, 0x6a, 0xd1, 0xe9, 0x29, 0x94, 0x8e, 0xb3, 0xe1, 0xbc, - 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0xba, 0x31, 0x8e, 0xea, 0x2a, 0xd2, 0x92, 0xd4, 0x08, 0x0b, 0xbd, - 0x4e, 0x41, 0x01, 0x8c, 0xc9, 0x9c, 0xae, 0xff, 0x70, 0xc5, 0x26, 0xf8, 0xff, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0x8f, - 0x12, 0xe3, 0x46, 0x22, 0xfc, 0x2a, 0x1a, 0x98, 0x6b, 0xd8, 0x7e, 0xb2, 0x1a, 0xdc, 0x43, 0x35, 0xd3, 0x91, 0x52, - 0x0a, 0x52, 0xef, 0x80, 0x17, 0x10, 0xcd, 0x13, 0x7e, 0xf3, 0xa8, 0xeb, 0x38, 0x63, 0x69, 0xd4, 0x1b, 0x04, 0x7a, - 0xd5, 0xf6, 0x8e, 0x52, 0xfa, 0xb3, 0xcf, 0x1f, 0xe2, 0x3f, 0x22, 0x70, 0x76, 0x5a, 0xf9, 0x46, 0x22, 0x36, 0x80, - 0xbe, 0xd1, 0xb4, 0xe6, 0xfc, 0x08, 0x0d, 0x4e, 0xfe, 0xcf, 0x5d, 0x5b, 0xa3, 0xb1, 0x7e, 0xa7, 0xe6, 0xd2, 0x2a, - 0xfd, 0x55, 0xad, 0x7f, 0xdd, 0xe0, 0x77, 0x6c, 0x3b, 0x14, 0x0e, 0x41, 0xbd, 0xad, 0x8c, 0x07, 0x2e, 0x35, 0x56, - 0x14, 0xbf, 0x6b, 0xfb, 0xca, 0x24, 0xa6, 0x1e, 0xd3, 0xf0, 0x54, 0x3b, 0x91, 0xf2, 0xf0, 0x1e, 0x7b, 0x08, 0x3f, - 0xf2, 0x4b, 0x16, 0x3e, 0xc0, 0xaf, 0xb1, 0x59, 0x97, 0xd3, 0x24, 0x05, 0xb3, 0x6a, 0xc2, 0xf9, 0x2c, 0xd8, 0xda, - 0xba, 0xb8, 0xb8, 0xf0, 0x2f, 0xb6, 0xfd, 0x2c, 0x3f, 0xdb, 0xea, 0xb6, 0xdb, 0x6d, 0xfc, 0x88, 0x96, 0x6d, 0x9d, - 0xc7, 0xec, 0xe2, 0x29, 0xb8, 0x1f, 0xf6, 0x63, 0xeb, 0x89, 0xf5, 0x78, 0xdb, 0xda, 0x79, 0x64, 0x5b, 0xa4, 0x00, - 0xa0, 0x64, 0xdb, 0xb6, 0x84, 0x02, 0x08, 0x6d, 0x28, 0xee, 0xef, 0x9e, 0x29, 0x1b, 0x0e, 0x2f, 0x29, 0x08, 0x0b, - 0x09, 0xfc, 0xb7, 0xec, 0x13, 0xab, 0x6f, 0x75, 0x51, 0xd6, 0x92, 0x6a, 0x44, 0xbd, 0xe2, 0x7e, 0x1f, 0x46, 0xb3, - 0x80, 0xd8, 0xc8, 0x2c, 0xc4, 0x30, 0x99, 0x28, 0xa5, 0x29, 0xd0, 0x2e, 0x3d, 0x85, 0x27, 0xcc, 0x6a, 0xb3, 0xe0, - 0xf9, 0x4d, 0xf7, 0x31, 0xe8, 0xb8, 0xf3, 0xd6, 0xc3, 0x61, 0xbb, 0xd5, 0xb1, 0x3a, 0xad, 0xae, 0xff, 0xd8, 0xea, - 0x8a, 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, - 0xfd, 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, - 0xb8, 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, - 0xd0, 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, - 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0xef, 0x7c, 0xfb, - 0xc9, 0x10, 0x34, 0x82, 0x85, 0xff, 0xc1, 0x3f, 0x93, 0x9d, 0xee, 0x50, 0xbc, 0xb4, 0xb1, 0xfe, 0xdb, 0xce, 0xe3, - 0x02, 0x9a, 0xe2, 0x3f, 0xbf, 0x68, 0x13, 0x1a, 0x0d, 0x78, 0x73, 0xdc, 0x87, 0x40, 0xa3, 0x27, 0x93, 0xae, 0xff, - 0xf9, 0xf9, 0x63, 0xff, 0xc9, 0xa4, 0xf3, 0xf8, 0x5b, 0xf1, 0x96, 0x00, 0x05, 0x3f, 0xc7, 0xff, 0xbe, 0xdd, 0x6e, - 0x4f, 0x5a, 0x1d, 0xff, 0xc9, 0xf9, 0xb6, 0xbf, 0x9d, 0xb4, 0x1e, 0xf9, 0x4f, 0xf0, 0xbf, 0x6a, 0xb8, 0x49, 0x36, - 0x65, 0xb6, 0x85, 0xeb, 0xdd, 0xf0, 0x7b, 0xcd, 0x39, 0xba, 0x0f, 0xad, 0x9d, 0x87, 0x2f, 0x9f, 0xc0, 0x1a, 0x4d, - 0x3a, 0x5d, 0xf8, 0xff, 0xba, 0xc7, 0x6f, 0x91, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x7a, 0xb1, 0x22, 0x1c, 0x7d, 0xd0, - 0xed, 0x81, 0xf7, 0xa7, 0x75, 0x01, 0x10, 0xc6, 0x6f, 0x0d, 0x80, 0x70, 0x7e, 0xb7, 0x08, 0x08, 0xfd, 0xda, 0xc0, - 0xef, 0x18, 0x01, 0xf9, 0x53, 0x33, 0xc8, 0x7d, 0xc9, 0x96, 0x02, 0x1d, 0x4d, 0x67, 0xed, 0x2d, 0x73, 0x0e, 0xbf, - 0x64, 0x47, 0x98, 0x4a, 0x0f, 0xad, 0x39, 0x37, 0xe3, 0x41, 0x19, 0x6e, 0xe4, 0x4b, 0x26, 0x76, 0x72, 0xc1, 0xd7, - 0x10, 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, - 0x29, 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, - 0xd3, 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, - 0x34, 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, - 0xa6, 0xdf, 0xcf, 0x8a, 0x79, 0x82, 0x97, 0xa6, 0xbd, 0xa1, 0xf8, 0x80, 0x2c, 0x3c, 0xca, 0xbb, 0x86, 0x98, 0xc2, - 0xfe, 0x0d, 0xa6, 0xdf, 0xab, 0xb3, 0x83, 0x29, 0xc6, 0x11, 0xde, 0xb0, 0x51, 0x1c, 0x39, 0xb6, 0x33, 0x83, 0x8d, - 0x0c, 0xb3, 0xb4, 0x6a, 0xb9, 0xef, 0x94, 0xf6, 0xee, 0xda, 0xea, 0xa7, 0x99, 0x72, 0xfc, 0xd4, 0x5d, 0x78, 0x28, - 0xe3, 0x8e, 0xb6, 0x74, 0x0c, 0x60, 0x7c, 0x55, 0x92, 0xa3, 0x0e, 0xa8, 0x8c, 0x09, 0x5b, 0x58, 0x13, 0x1d, 0xbf, - 0x0b, 0xde, 0x05, 0x15, 0xe3, 0xa7, 0xc3, 0xbe, 0x77, 0x5a, 0xdb, 0x60, 0xed, 0x18, 0xdd, 0xf4, 0x40, 0x47, 0xfa, - 0x97, 0x7e, 0xf4, 0xaf, 0xd1, 0xd5, 0x2f, 0x0c, 0xd8, 0x82, 0x23, 0x3e, 0x13, 0xb8, 0xdb, 0xf4, 0x89, 0x06, 0x99, - 0x50, 0x82, 0x17, 0xe6, 0xa0, 0xcc, 0x31, 0x7f, 0x95, 0x4c, 0x7c, 0x9a, 0x4c, 0xfc, 0x00, 0x61, 0x59, 0x35, 0x61, - 0xd5, 0xcf, 0x7f, 0x20, 0x05, 0x99, 0xa7, 0x67, 0x23, 0xea, 0x61, 0x86, 0x07, 0xfe, 0xad, 0x8a, 0xd5, 0x83, 0x8c, - 0x58, 0x81, 0x17, 0x8f, 0xbf, 0xe9, 0x42, 0x7f, 0x96, 0xe2, 0x61, 0x22, 0xca, 0xd1, 0x28, 0xad, 0x86, 0xaa, 0xe2, - 0x5e, 0xc5, 0xd3, 0xab, 0x03, 0xf9, 0x41, 0x03, 0x1b, 0x43, 0xd0, 0x74, 0xf4, 0x50, 0x7d, 0x4c, 0x6d, 0x13, 0xf4, - 0x1e, 0xfd, 0xc4, 0x29, 0x65, 0x0f, 0xa0, 0x6a, 0xc3, 0xfb, 0x04, 0x96, 0x74, 0x81, 0x42, 0x5b, 0x28, 0xb6, 0x11, - 0x3b, 0x8f, 0x87, 0x52, 0x3f, 0x79, 0x96, 0xbc, 0x07, 0xd5, 0x22, 0xba, 0x87, 0x1d, 0x4f, 0x04, 0x01, 0xe0, 0x05, - 0xd5, 0x73, 0x98, 0x66, 0x76, 0xff, 0x41, 0x6f, 0x1d, 0x65, 0xf1, 0xf7, 0x56, 0x0f, 0xc1, 0xe9, 0xfc, 0xdb, 0xf0, - 0x01, 0xfe, 0xe2, 0xea, 0x83, 0x23, 0xdb, 0xf5, 0x49, 0xba, 0x3f, 0xa8, 0x7e, 0x76, 0x15, 0x45, 0xdb, 0x26, 0x28, - 0x62, 0xef, 0xae, 0x1a, 0x59, 0x6a, 0xdf, 0xee, 0x4e, 0xa5, 0x7d, 0xe1, 0xd9, 0x10, 0xb7, 0xa0, 0x09, 0xba, 0xfe, - 0x8e, 0x21, 0xd3, 0xcf, 0x5b, 0xf8, 0xb7, 0x26, 0xd5, 0x1f, 0x42, 0x03, 0x25, 0xd6, 0x5f, 0x43, 0xf3, 0x6d, 0xa1, - 0x41, 0xa0, 0xdf, 0x0f, 0x24, 0x73, 0x85, 0xbc, 0xad, 0xf3, 0xf8, 0x8a, 0xd3, 0x30, 0x91, 0x69, 0x61, 0x7b, 0x46, - 0xe0, 0x4c, 0x6c, 0x39, 0x19, 0x16, 0x7a, 0x0e, 0x7d, 0x1d, 0xfd, 0x8d, 0xf2, 0x55, 0x75, 0x5e, 0x4d, 0x04, 0xac, - 0x98, 0x02, 0x37, 0x6d, 0xe3, 0xc4, 0xad, 0x27, 0x92, 0xb8, 0xf5, 0x47, 0x4e, 0xd6, 0x73, 0xab, 0xcc, 0xf6, 0x76, - 0x8d, 0xfd, 0xcf, 0xe9, 0x3b, 0xaa, 0x34, 0xc9, 0xab, 0x51, 0xd9, 0x9c, 0x1f, 0x6c, 0x16, 0xfc, 0xd1, 0xc9, 0xea, - 0x0a, 0x8f, 0xbc, 0x9b, 0x8b, 0xf9, 0x14, 0xa3, 0x38, 0xa7, 0x2b, 0xdf, 0x0a, 0xf4, 0x5a, 0x54, 0xb5, 0xa2, 0x12, - 0x89, 0x00, 0x56, 0x0c, 0x6c, 0x2c, 0xb2, 0x03, 0x99, 0xf5, 0x67, 0x7e, 0x48, 0xdc, 0xbc, 0x93, 0x3b, 0x12, 0x09, - 0x7f, 0xf8, 0x43, 0x0b, 0xb6, 0xa0, 0x8f, 0x0d, 0xa2, 0x74, 0xed, 0x2e, 0x21, 0x03, 0x0b, 0x71, 0xad, 0x7e, 0x39, - 0xcb, 0x94, 0x2e, 0xb6, 0x49, 0x68, 0x3d, 0x2e, 0x91, 0xd0, 0x95, 0x74, 0x3a, 0x65, 0x11, 0xf7, 0xa3, 0x94, 0x92, - 0xb3, 0x1c, 0x43, 0x06, 0x79, 0x1d, 0xb6, 0xed, 0x96, 0x20, 0xf8, 0x8c, 0x9f, 0x16, 0x13, 0x9b, 0xd9, 0x87, 0x42, - 0xfd, 0x59, 0xab, 0x7a, 0xa2, 0xf5, 0xa4, 0xdb, 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, - 0xe4, 0x9e, 0x8b, 0x3c, 0x95, 0x50, 0xe4, 0xa9, 0x58, 0x22, 0xbb, 0x4d, 0x24, 0x26, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, - 0xa5, 0x43, 0x11, 0x57, 0x9c, 0x82, 0x0b, 0x13, 0xe3, 0xc7, 0xe7, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x29, - 0x3f, 0xca, 0x68, 0xe1, 0xa9, 0x8a, 0x42, 0x82, 0xa9, 0xc1, 0x54, 0xf6, 0x8f, 0x1c, 0x4a, 0x27, 0x1d, 0x2f, 0xb7, - 0x2e, 0xe6, 0xa7, 0x53, 0x10, 0x82, 0x2a, 0x63, 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x26, - 0x55, 0x1f, 0x06, 0x6f, 0xfc, 0x88, 0xaa, 0xc0, 0x5e, 0x0a, 0x7d, 0x4c, 0x38, 0x99, 0x6c, 0x1b, 0x09, 0x27, 0x46, - 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x83, 0xac, 0xa2, 0x3d, 0x28, 0x94, - 0x01, 0x25, 0x8f, 0x8b, 0x4b, 0x1b, 0x12, 0x60, 0x58, 0x41, 0x80, 0x49, 0xea, 0x77, 0x8b, 0xce, 0xb5, 0xed, 0x9d, - 0xb6, 0xca, 0xc9, 0x85, 0x32, 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0xb6, 0x3b, 0xe9, 0xf4, 0x77, 0x23, 0x69, - 0x39, 0xa2, 0xf0, 0x28, 0x40, 0x7a, 0x40, 0x67, 0x34, 0xcf, 0xfc, 0x38, 0xdb, 0xba, 0x60, 0xa7, 0xad, 0x68, 0x16, - 0x57, 0x81, 0x54, 0xb4, 0x23, 0xf4, 0x94, 0x59, 0x35, 0x13, 0x3e, 0x46, 0x0d, 0x24, 0x49, 0x70, 0x97, 0x32, 0x4a, - 0x4b, 0xe6, 0x37, 0xb0, 0x10, 0x50, 0x98, 0xe4, 0xba, 0x8a, 0xe6, 0x4a, 0x75, 0x5a, 0xda, 0xfd, 0xbf, 0xfc, 0xf3, - 0xff, 0x96, 0x01, 0x5a, 0xa0, 0x4a, 0x47, 0x8d, 0xd5, 0x20, 0x74, 0xb9, 0x8b, 0xf9, 0x4d, 0xd5, 0x11, 0x2e, 0xbb, - 0x04, 0x4f, 0x3f, 0x1e, 0xb5, 0x26, 0x51, 0x32, 0x06, 0xc0, 0xd6, 0x12, 0xc8, 0xcc, 0x7e, 0x90, 0x50, 0xd7, 0x8b, - 0x90, 0x05, 0x7f, 0x53, 0x96, 0xb5, 0xca, 0x6e, 0xa7, 0xdd, 0x6a, 0xe4, 0x5c, 0x1b, 0x1b, 0xaa, 0x96, 0x77, 0xad, - 0x7e, 0x95, 0x4c, 0x0a, 0x35, 0x56, 0x4b, 0xba, 0x86, 0x96, 0xfa, 0xa4, 0xe9, 0xdf, 0xff, 0xe5, 0x1f, 0xfe, 0x87, - 0x7a, 0xc5, 0x03, 0xa4, 0xbf, 0xfc, 0xd3, 0xdf, 0x61, 0x7e, 0xb3, 0xa5, 0x0f, 0x99, 0x48, 0x4e, 0x58, 0xd5, 0x09, - 0x93, 0x10, 0x18, 0x56, 0xe5, 0xd1, 0xd5, 0x93, 0xb3, 0xf7, 0x69, 0x42, 0xda, 0x6c, 0x12, 0x3a, 0xda, 0xb4, 0x65, - 0xc5, 0x23, 0x35, 0x92, 0x13, 0x2f, 0x42, 0x25, 0xd2, 0xfb, 0x4e, 0x99, 0x4f, 0xbe, 0x5e, 0x8d, 0x85, 0x0a, 0xff, - 0x61, 0x49, 0x59, 0x95, 0x5b, 0x18, 0x97, 0x5f, 0xe0, 0x6b, 0xd0, 0x35, 0x8a, 0x69, 0xf1, 0x6a, 0x7d, 0x7a, 0x3f, - 0xcd, 0x01, 0xfe, 0x31, 0x52, 0x5c, 0x04, 0x19, 0xe9, 0xcc, 0xb9, 0x85, 0x06, 0x5d, 0x72, 0x55, 0xd2, 0x28, 0xc2, - 0x0b, 0x7c, 0xf8, 0xe4, 0x6f, 0xca, 0x3f, 0x4e, 0xd1, 0x6c, 0xb2, 0x9c, 0x69, 0x74, 0x29, 0x7d, 0xc3, 0x47, 0xed, - 0xf6, 0xec, 0xd2, 0x5d, 0x54, 0x33, 0x78, 0xeb, 0x26, 0xa3, 0xc0, 0xa4, 0x39, 0x20, 0x1d, 0x56, 0xeb, 0x18, 0x28, - 0xb8, 0x43, 0x6d, 0x0c, 0x99, 0x95, 0xe5, 0x1f, 0x16, 0x14, 0x86, 0x8b, 0x7f, 0xc1, 0x43, 0x65, 0x19, 0xb1, 0x84, - 0x12, 0x03, 0x8b, 0x85, 0xd1, 0xab, 0x2b, 0x7a, 0x4d, 0x3a, 0xcb, 0x39, 0x41, 0xe6, 0xa1, 0xb8, 0x79, 0x9c, 0xfd, - 0x10, 0x0f, 0xa8, 0x27, 0x1d, 0x6f, 0xd2, 0x5d, 0xe8, 0xe1, 0x39, 0xcf, 0xa6, 0xe6, 0x29, 0x38, 0x8b, 0xd8, 0x90, - 0x8d, 0x55, 0xa4, 0x57, 0xd6, 0x8b, 0x13, 0xee, 0x72, 0xb2, 0xbd, 0x62, 0x2e, 0x09, 0x12, 0x9d, 0x7e, 0x03, 0x3c, - 0x9f, 0xe1, 0x06, 0x04, 0xfa, 0x67, 0x11, 0x0f, 0x88, 0x5f, 0x7b, 0xe6, 0x59, 0x7a, 0x84, 0x52, 0x26, 0x5b, 0x18, - 0xf0, 0xf4, 0x44, 0x53, 0x8c, 0xb9, 0xd6, 0x73, 0xb2, 0x4a, 0x9f, 0xba, 0x9b, 0x43, 0x89, 0x90, 0xcd, 0xb7, 0xf2, - 0x88, 0xfa, 0x69, 0x2d, 0xd6, 0x21, 0x55, 0x4c, 0xd7, 0xf5, 0x56, 0xd6, 0x0b, 0x4d, 0x2d, 0x6a, 0xbf, 0x05, 0x03, - 0x8c, 0xc0, 0xb4, 0x9b, 0xad, 0xa8, 0x10, 0x5b, 0x3d, 0x0d, 0xbf, 0xd5, 0x7e, 0x4d, 0x34, 0x9b, 0x51, 0x43, 0x17, - 0x98, 0x98, 0xac, 0x51, 0x94, 0x1d, 0x94, 0x7e, 0x21, 0xb2, 0x1d, 0x64, 0x1b, 0xb9, 0x11, 0xc4, 0x93, 0xcc, 0x83, - 0xa0, 0xdf, 0xb7, 0xff, 0x7f, 0x47, 0x48, 0x09, 0x5d, 0xf5, 0x7e, 0x00, 0x00}; + 0xd9, 0xf4, 0x58, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, + 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0x60, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, + 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xde, 0x6b, 0xb2, 0x81, 0xd3, 0x28, 0x09, 0x0d, 0x71, 0x65, 0xe2, 0xad, 0x24, 0x74, + 0x6d, 0xa3, 0x80, 0x43, 0xb6, 0xc4, 0xf6, 0xcd, 0x85, 0x6e, 0x72, 0xbb, 0x64, 0x0f, 0xe5, 0x3f, 0x55, 0x5c, 0xb2, + 0x9e, 0xe5, 0x98, 0x92, 0x06, 0x4c, 0x31, 0x1e, 0x2c, 0x4d, 0x03, 0x12, 0xe0, 0xbb, 0x72, 0x14, 0x17, 0xeb, 0x49, + 0xf0, 0xbb, 0x82, 0xf9, 0xdc, 0x98, 0xe9, 0x56, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, + 0xd4, 0x7c, 0x8d, 0x86, 0x0a, 0x71, 0xfc, 0x99, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, + 0x2c, 0x5a, 0xa4, 0x4c, 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, + 0xdc, 0x34, 0xd4, 0xc2, 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, + 0xfb, 0x86, 0x0f, 0x65, 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, + 0x74, 0x41, 0xa0, 0x48, 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, + 0x4a, 0x33, 0x2f, 0x75, 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x31, 0x41, 0x99, 0xd8, 0xbb, 0x89, 0x36, 0x5e, 0x1a, + 0x66, 0xc2, 0xfa, 0x15, 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, + 0xb0, 0xa7, 0x00, 0x94, 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x11, 0x1d, 0x2b, 0x11, 0x5a, + 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, + 0x25, 0x83, 0x84, 0x1c, 0xd2, 0x65, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x1e, 0x85, 0x11, 0x8a, + 0x0d, 0xb1, 0x16, 0x4b, 0x84, 0x6c, 0xda, 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0xe6, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, + 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x9e, 0x00, 0x3f, 0x48, + 0x83, 0x17, 0xd6, 0x6c, 0xa0, 0x64, 0xef, 0xde, 0x6b, 0x6c, 0x45, 0xf6, 0x67, 0x55, 0x52, 0x79, 0x0a, 0x35, 0xce, + 0xad, 0xaf, 0x53, 0x2d, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, + 0x76, 0x5d, 0x37, 0xc8, 0xc9, 0x79, 0xb9, 0xb7, 0xca, 0x85, 0xbc, 0x7f, 0xdf, 0xf4, 0x99, 0xce, 0xf5, 0xf0, 0xcf, + 0x1c, 0x54, 0xce, 0xc5, 0x55, 0x4a, 0x16, 0xcc, 0x33, 0xa5, 0x8e, 0x96, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, + 0x22, 0x8a, 0xb9, 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, + 0xda, 0xa2, 0xc5, 0x70, 0xc2, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x43, 0xbc, 0xe5, 0xc0, 0xab, 0x61, + 0x2f, 0x9b, 0xdd, 0x6b, 0xe6, 0x3f, 0xac, 0x11, 0xc8, 0xb6, 0xa9, 0xaa, 0x2b, 0x1b, 0xef, 0x52, 0x44, 0x62, 0x84, + 0x6d, 0xd5, 0xd8, 0xd2, 0xd6, 0xef, 0x35, 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x86, 0x1e, 0x56, 0x6e, 0x0e, + 0x37, 0x1d, 0x79, 0xb1, 0x82, 0x6e, 0x4f, 0x04, 0x85, 0xc0, 0x89, 0x50, 0xf6, 0xa0, 0xe6, 0x06, 0x22, 0x25, 0x53, + 0x5a, 0x35, 0x9b, 0x27, 0x23, 0x09, 0x2c, 0xb8, 0xb0, 0x4c, 0xf2, 0xd1, 0x45, 0x9c, 0x24, 0x55, 0xe9, 0xef, 0x2a, + 0xe0, 0xc5, 0xb0, 0xb7, 0x89, 0x76, 0x81, 0xd1, 0x5c, 0x81, 0xe0, 0x6a, 0x23, 0xec, 0xa3, 0xe3, 0x56, 0xeb, 0x2e, + 0x22, 0x8e, 0xcc, 0x8c, 0x46, 0x7c, 0x44, 0x1b, 0xb2, 0x64, 0x9a, 0xb5, 0xf7, 0x5e, 0x60, 0x48, 0xcd, 0xc0, 0x07, + 0xd5, 0x19, 0x15, 0xff, 0x2a, 0x7b, 0xea, 0x57, 0xa2, 0x77, 0xab, 0xea, 0x6a, 0x06, 0x54, 0x54, 0xe0, 0xc3, 0x0c, + 0xb1, 0xb4, 0x55, 0x20, 0x20, 0xd7, 0xc3, 0x3a, 0xdc, 0xad, 0x91, 0x06, 0x0b, 0x4a, 0x81, 0xb5, 0x56, 0x76, 0xaf, + 0x6f, 0x0b, 0xe6, 0x50, 0x28, 0x5c, 0xf4, 0x7f, 0x96, 0x4d, 0x67, 0x68, 0x99, 0x35, 0x98, 0x1a, 0x1a, 0x7c, 0x6c, + 0xd4, 0x97, 0x2b, 0xca, 0x6a, 0x7d, 0x68, 0x47, 0xd6, 0xf8, 0x49, 0x3b, 0xca, 0xe0, 0x50, 0xcd, 0x75, 0x51, 0xdd, + 0x6e, 0x6e, 0x8a, 0x98, 0x55, 0x3c, 0xee, 0x93, 0xde, 0xd6, 0xd6, 0xa4, 0xa7, 0x69, 0x40, 0x32, 0x49, 0x32, 0xbc, + 0xc9, 0x00, 0x65, 0x45, 0x9c, 0x45, 0xd9, 0x20, 0xdf, 0xa2, 0x2c, 0x71, 0xfd, 0x7e, 0xe8, 0xed, 0xd5, 0x3c, 0x6b, + 0x6f, 0x6f, 0xbd, 0x8b, 0x5c, 0xd5, 0x49, 0x0f, 0xf2, 0xf0, 0x08, 0x8a, 0x96, 0x6c, 0xca, 0x70, 0x31, 0xcd, 0x46, + 0x2c, 0xb0, 0xa1, 0x7b, 0x6a, 0x97, 0x72, 0xd3, 0x44, 0xc0, 0x3d, 0x11, 0x73, 0x16, 0x1f, 0xea, 0x91, 0xd4, 0x60, + 0x0f, 0x58, 0x40, 0x9b, 0x0b, 0x5f, 0x85, 0x67, 0x49, 0x76, 0x1a, 0x25, 0x07, 0x42, 0x81, 0xd7, 0x5a, 0x7e, 0x0b, + 0x2e, 0x23, 0x59, 0xac, 0x86, 0x92, 0xfa, 0x6a, 0xf0, 0x55, 0x70, 0x7b, 0x8f, 0xca, 0x5b, 0xb1, 0x3b, 0x7e, 0xdb, + 0xef, 0xd8, 0x2a, 0x22, 0xf6, 0x93, 0x39, 0x1d, 0x68, 0x9c, 0x02, 0x28, 0x73, 0x00, 0x9a, 0xac, 0xf0, 0x86, 0x2c, + 0xfc, 0x69, 0xf0, 0x93, 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, + 0x88, 0x0a, 0x8c, 0x2b, 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0x77, 0x1c, 0x9e, 0x40, 0xb3, 0x8d, 0x8d, 0x85, 0xf3, + 0x26, 0xe2, 0x13, 0x3f, 0x8f, 0xd2, 0x51, 0x36, 0x75, 0xdc, 0x4d, 0xdb, 0x76, 0xfd, 0x82, 0x3c, 0x91, 0xcf, 0xdd, + 0x72, 0xe3, 0x04, 0xfc, 0x80, 0xd0, 0x1e, 0xd8, 0x9b, 0xc7, 0xde, 0x01, 0x0b, 0x4f, 0x76, 0x37, 0x16, 0x23, 0x56, + 0xf6, 0x4f, 0xbc, 0x4b, 0x1d, 0x73, 0xf7, 0xde, 0xa3, 0x94, 0x81, 0x5e, 0x61, 0xff, 0x52, 0x82, 0x01, 0xec, 0x46, + 0xf1, 0x77, 0x90, 0x72, 0x1f, 0xe9, 0x40, 0x44, 0xc6, 0x69, 0xaf, 0xaf, 0xed, 0x8c, 0x22, 0x06, 0xf6, 0x3d, 0xed, + 0xac, 0xde, 0xbf, 0x5f, 0xa9, 0xf9, 0xaa, 0xd4, 0x9b, 0xb3, 0xb0, 0xe6, 0xa9, 0x7b, 0x2f, 0xe9, 0x68, 0xa5, 0xbe, + 0x91, 0xe7, 0x8c, 0x94, 0xe6, 0xb2, 0x9d, 0xe0, 0x18, 0x5b, 0x7c, 0xf5, 0xb6, 0x3e, 0x14, 0x51, 0x0a, 0x3f, 0x06, + 0xeb, 0x25, 0x02, 0xf5, 0x0d, 0x0e, 0x8e, 0x77, 0x10, 0x6e, 0xed, 0x3a, 0x83, 0xc0, 0xb9, 0xd7, 0x6a, 0x5d, 0xff, + 0xb8, 0x75, 0xf8, 0xe7, 0xa8, 0xf5, 0xcb, 0x5e, 0xeb, 0x87, 0x23, 0xf7, 0xda, 0xf9, 0x71, 0x6b, 0x70, 0x28, 0xdf, + 0x0e, 0xff, 0xdc, 0xff, 0xb1, 0x38, 0xfa, 0x83, 0x28, 0xdc, 0x70, 0xdd, 0xad, 0x33, 0x6f, 0xc6, 0xc2, 0xad, 0x56, + 0xab, 0x0f, 0x4f, 0x67, 0xf0, 0x84, 0x7f, 0x2f, 0xe0, 0xcf, 0xf5, 0xa1, 0xf5, 0x9f, 0x7e, 0x4c, 0xff, 0xf3, 0x8f, + 0xf9, 0x11, 0x8e, 0x79, 0xf8, 0xe7, 0x1f, 0x0b, 0xfb, 0x41, 0x3f, 0xdc, 0x3a, 0xda, 0x74, 0x1d, 0x5d, 0xf3, 0x87, + 0xb0, 0x7a, 0x84, 0x56, 0x87, 0x7f, 0x96, 0x6f, 0xf6, 0x83, 0x93, 0xdd, 0x7e, 0x78, 0x74, 0xed, 0xd8, 0xd7, 0x0f, + 0xdc, 0x6b, 0xd7, 0xbd, 0xde, 0xc0, 0x79, 0xce, 0x61, 0xf4, 0x07, 0xf0, 0x77, 0x0c, 0x7f, 0x6d, 0xf8, 0x3b, 0x85, + 0xbf, 0x7f, 0x86, 0x6e, 0x22, 0xfe, 0x76, 0x4d, 0xb1, 0x90, 0x6b, 0x3c, 0xb0, 0x88, 0x60, 0x15, 0xdc, 0x8d, 0xad, + 0xd8, 0xdb, 0x20, 0xa2, 0xc1, 0x3e, 0xf4, 0x7d, 0x1f, 0xc3, 0xa4, 0xce, 0xe2, 0x78, 0x03, 0x16, 0x1d, 0x39, 0x67, + 0x23, 0xe0, 0x9e, 0x88, 0x1c, 0x14, 0x01, 0x13, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xc3, 0x70, 0x83, 0x39, 0x60, + 0x14, 0xbc, 0x65, 0xf8, 0xd0, 0x75, 0xbd, 0x17, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, + 0xed, 0x7a, 0xb3, 0x15, 0x95, 0xb0, 0xad, 0xd3, 0x33, 0xa8, 0x3b, 0x15, 0x27, 0x8c, 0xdf, 0xb1, 0xe8, 0x13, 0x6e, + 0xc9, 0x37, 0xc6, 0x21, 0xf0, 0x92, 0x25, 0xdf, 0x34, 0x1a, 0x0d, 0x1b, 0x51, 0xb8, 0x63, 0x4f, 0x19, 0xcc, 0xb0, + 0x64, 0x22, 0x32, 0x52, 0x9a, 0xc2, 0xb2, 0x85, 0xc9, 0xdf, 0x47, 0x39, 0xdf, 0xa8, 0x0c, 0xdb, 0xb0, 0x66, 0xc9, + 0x36, 0x2d, 0xfd, 0x3b, 0x4c, 0x81, 0xa6, 0x25, 0x9d, 0x7f, 0x98, 0xe3, 0x87, 0x29, 0xa1, 0xf5, 0xd6, 0x61, 0xe0, + 0xa1, 0x17, 0x20, 0x77, 0x44, 0x3f, 0xe7, 0x3d, 0xaa, 0x31, 0xf8, 0x9f, 0x0c, 0x33, 0x78, 0x62, 0x3e, 0x0c, 0xd1, + 0x2c, 0x4a, 0x1d, 0xdc, 0x4a, 0x51, 0xdc, 0xbf, 0xc2, 0x9d, 0x91, 0x96, 0xde, 0x7e, 0xa8, 0x76, 0xcc, 0x41, 0xce, + 0xd8, 0x77, 0x51, 0xf2, 0x89, 0xe5, 0xce, 0xa5, 0xd7, 0xe9, 0x7e, 0x4e, 0x9d, 0x3d, 0xb4, 0xcd, 0x3e, 0x54, 0xc7, + 0x68, 0xda, 0x2c, 0x90, 0x47, 0x84, 0xad, 0x8e, 0x97, 0x63, 0x54, 0x0b, 0x49, 0x50, 0x78, 0x59, 0xd8, 0x25, 0x0e, + 0xb7, 0x77, 0x8b, 0xf3, 0xb3, 0xbe, 0x1d, 0xd8, 0x36, 0x58, 0xfc, 0x07, 0x14, 0xb6, 0x12, 0x86, 0x45, 0xbb, 0xc7, + 0x76, 0xe3, 0x1e, 0xdb, 0xdc, 0xac, 0x02, 0x4e, 0x78, 0x90, 0x4e, 0xdd, 0x13, 0x2f, 0xf2, 0x26, 0x21, 0x0c, 0x38, + 0x84, 0x66, 0xd8, 0xa5, 0x37, 0xdc, 0x8d, 0xe5, 0x34, 0x18, 0x0b, 0xf1, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, + 0x0e, 0xd1, 0xd8, 0xf7, 0xd9, 0x25, 0x1b, 0x2a, 0x3b, 0x03, 0x08, 0x15, 0xb9, 0x3d, 0x77, 0x18, 0x1a, 0xcd, 0x60, + 0xee, 0x30, 0x3c, 0x18, 0xd8, 0xb0, 0x97, 0x60, 0x57, 0x86, 0xd1, 0x61, 0xe7, 0x68, 0x90, 0x86, 0x33, 0x16, 0x68, + 0xda, 0xca, 0xa2, 0xb3, 0x5a, 0x51, 0xf7, 0x68, 0xe0, 0x4c, 0x99, 0xcf, 0xc1, 0x16, 0x77, 0xf0, 0x0d, 0x23, 0x14, + 0x45, 0xf8, 0x81, 0x9d, 0xbd, 0xb8, 0x9c, 0x39, 0xf6, 0xee, 0x96, 0xbd, 0x89, 0xa5, 0x9e, 0x0d, 0xec, 0x05, 0x73, + 0x87, 0x17, 0xae, 0xd9, 0x79, 0xfb, 0x08, 0x41, 0xc5, 0x42, 0x9c, 0xfc, 0x62, 0x60, 0xf7, 0xc5, 0xd4, 0x6d, 0x18, + 0x34, 0x95, 0xcb, 0x8f, 0x2b, 0x7a, 0x40, 0xa8, 0xaa, 0xae, 0x0a, 0x3a, 0x28, 0xeb, 0x06, 0xce, 0xc4, 0x44, 0xa2, + 0x85, 0x93, 0x49, 0x2a, 0x80, 0xc3, 0x83, 0xcd, 0x60, 0x52, 0xa3, 0xdb, 0xf6, 0xd1, 0xe0, 0x22, 0x78, 0x60, 0x3f, + 0x50, 0x2f, 0x63, 0x40, 0x86, 0x89, 0xe9, 0xc7, 0xa0, 0x45, 0xf0, 0xef, 0x39, 0x03, 0x24, 0x2f, 0xa8, 0x68, 0x26, + 0x8b, 0xce, 0xb0, 0xe8, 0x20, 0x40, 0x50, 0xbd, 0x42, 0x5b, 0x7f, 0x62, 0x4d, 0x46, 0x21, 0xc1, 0x0e, 0xb6, 0xd0, + 0x21, 0xdb, 0xec, 0x1c, 0xe1, 0x79, 0x43, 0xce, 0x8b, 0xef, 0x62, 0x0e, 0x2a, 0x61, 0xab, 0x6f, 0xbb, 0x03, 0xdb, + 0xc2, 0xa5, 0xed, 0x65, 0x9b, 0xa1, 0xa0, 0x70, 0xbc, 0x79, 0xc0, 0x82, 0x49, 0x3f, 0x6c, 0x0f, 0x9c, 0x5c, 0x86, + 0x1b, 0xf1, 0xdc, 0x52, 0x48, 0xf0, 0xb6, 0x37, 0x01, 0x81, 0x8e, 0x9c, 0xbb, 0x61, 0x6f, 0xaa, 0x42, 0x28, 0x3a, + 0xde, 0x1c, 0xb9, 0x41, 0x0c, 0x7f, 0x9c, 0x16, 0x32, 0xcd, 0x44, 0xf7, 0x55, 0x9a, 0x19, 0x90, 0x18, 0x29, 0x8b, + 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, 0xb1, + 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, 0x47, + 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf7, 0x0c, 0x09, 0xc5, 0x4a, 0xed, 0x86, 0x09, 0x73, + 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, 0xbd, + 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, 0xe1, + 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, 0x02, + 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x31, 0xe9, 0xda, 0xa3, + 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, 0xbf, + 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, 0x60, + 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, 0x46, + 0xe0, 0x19, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, + 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, 0xdc, + 0x82, 0x18, 0x87, 0x19, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, 0x8a, + 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, 0x52, + 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, 0x36, + 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x19, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, 0xf4, + 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, 0xa2, + 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xbb, 0xf9, 0x52, 0xcc, 0x86, 0xb9, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, 0xd1, + 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x8b, 0xf4, 0x64, 0xfd, 0x36, 0xd8, 0xe0, + 0xb5, 0xbc, 0x03, 0xb4, 0xef, 0xd8, 0x74, 0xc6, 0xaf, 0xf6, 0x49, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0xb7, + 0x7b, 0xf1, 0x2e, 0xeb, 0xc5, 0x20, 0xd5, 0x73, 0xc5, 0x62, 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, + 0xab, 0xa1, 0xd7, 0x95, 0xe8, 0x6d, 0x6e, 0x02, 0x82, 0x3d, 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, + 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, 0x11, 0x73, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, + 0xb0, 0x03, 0x98, 0x11, 0x97, 0xb7, 0x3a, 0x22, 0x3a, 0x2c, 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0x37, 0x3b, 0x2e, + 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, 0xd6, 0x54, 0x2a, 0x8b, 0xcd, 0xcd, 0xb2, 0x7e, 0x54, + 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0xb2, 0x99, 0x0d, 0xc2, 0x81, 0x88, 0x09, 0x14, 0x68, 0x69, 0x65, 0xc5, 0x00, + 0x43, 0xca, 0x72, 0x94, 0x4f, 0x21, 0xf7, 0xe2, 0xb2, 0xd4, 0xa9, 0x2f, 0xcf, 0x64, 0xd0, 0x11, 0x4f, 0x3d, 0xc9, + 0x58, 0x01, 0x05, 0xeb, 0xa5, 0x5e, 0x42, 0x4b, 0x04, 0x98, 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, + 0x2c, 0x51, 0xc6, 0x67, 0x11, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, 0x62, 0x5f, 0x85, 0x32, 0x3a, 0x8a, 0xc3, 0xfc, 0x28, + 0xa0, 0xfa, 0xb9, 0x94, 0x60, 0x93, 0xf0, 0x23, 0xb0, 0x51, 0xe5, 0x78, 0x92, 0x20, 0x7c, 0x1e, 0xe7, 0x8c, 0x3c, + 0x85, 0x0d, 0x09, 0xb3, 0x34, 0x6d, 0x23, 0xd5, 0x2e, 0x32, 0x83, 0x50, 0x2e, 0xcc, 0x3f, 0x31, 0xce, 0x2e, 0xb2, + 0x70, 0xa9, 0x35, 0x98, 0x1f, 0xef, 0x4c, 0x80, 0xb2, 0xeb, 0xeb, 0x4c, 0xf8, 0xb8, 0x11, 0xd9, 0x1b, 0xba, 0x62, + 0x32, 0x50, 0x48, 0x05, 0x4e, 0x44, 0x16, 0x0f, 0x9d, 0xa1, 0xd0, 0x08, 0x07, 0x74, 0x8a, 0x9c, 0xbb, 0xc6, 0xa6, + 0xcf, 0x07, 0xda, 0x37, 0x4a, 0x43, 0x27, 0x01, 0x21, 0x20, 0x70, 0x37, 0xac, 0xa9, 0x74, 0x90, 0x06, 0x09, 0x95, + 0xa2, 0x9f, 0x03, 0xf8, 0x87, 0x91, 0xa4, 0x00, 0xd8, 0x0f, 0xd5, 0x48, 0x11, 0x65, 0x59, 0xe0, 0x02, 0xd0, 0x5c, + 0xfb, 0xb8, 0x12, 0xbe, 0x30, 0x50, 0x61, 0x7a, 0x9a, 0x95, 0x95, 0x42, 0x89, 0x3c, 0x5d, 0x91, 0xb2, 0x46, 0x32, + 0xf9, 0x1c, 0x1d, 0x3e, 0xe5, 0x5d, 0xbf, 0x95, 0x78, 0xe8, 0x82, 0xe7, 0xb0, 0xac, 0xea, 0xf9, 0x4d, 0xc8, 0xc8, + 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xf7, 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, + 0x0c, 0xcb, 0xcb, 0x59, 0x15, 0xa6, 0x20, 0xe0, 0x16, 0x2c, 0x09, 0x16, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, + 0x0a, 0xf2, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0x99, 0xd4, 0x04, + 0x4c, 0xb9, 0x3f, 0x04, 0x3f, 0xb5, 0x79, 0xd2, 0x75, 0xe9, 0xfa, 0xf1, 0x14, 0x53, 0x7b, 0x08, 0xf4, 0xd8, 0xbb, + 0x07, 0xa6, 0x44, 0x5d, 0x87, 0x15, 0xc4, 0xa1, 0x59, 0x4d, 0xb3, 0x80, 0x19, 0xd3, 0x06, 0x2d, 0xd9, 0x06, 0x5b, + 0x2e, 0x07, 0xfb, 0x48, 0x6c, 0xcf, 0x6a, 0x05, 0x84, 0xae, 0x41, 0x03, 0x43, 0xee, 0x52, 0xa1, 0x85, 0x59, 0xaf, + 0x4b, 0x45, 0xb8, 0x3f, 0x07, 0x4c, 0x5a, 0xc1, 0x99, 0x97, 0xd1, 0xc0, 0xfb, 0xf1, 0x69, 0x82, 0x89, 0x2f, 0x88, + 0x15, 0xd8, 0xc1, 0x41, 0xa7, 0xd9, 0x14, 0x38, 0x15, 0x17, 0x29, 0x83, 0x65, 0x45, 0xa9, 0x0d, 0x7f, 0xa4, 0xc8, + 0xd6, 0x5d, 0x1e, 0xe9, 0x2e, 0xc4, 0x02, 0xd8, 0xe9, 0x17, 0x8c, 0x7c, 0xcb, 0x7a, 0x19, 0x30, 0x38, 0xd7, 0x1a, + 0x07, 0x81, 0xdf, 0xdc, 0x4c, 0x8e, 0xca, 0x94, 0xd8, 0xae, 0xc9, 0xea, 0x02, 0x72, 0x4c, 0x02, 0x6c, 0xe0, 0x0e, + 0xc2, 0x52, 0xd9, 0xe3, 0x45, 0x39, 0xc5, 0xe5, 0x52, 0x16, 0x72, 0x33, 0x1d, 0x8b, 0xe6, 0x73, 0x2b, 0xcd, 0xa6, + 0xe3, 0xad, 0xf8, 0xa2, 0xe0, 0x1f, 0x38, 0xb1, 0xb4, 0xea, 0x29, 0xb5, 0xc2, 0xa3, 0xcc, 0x2d, 0x59, 0xa7, 0xa4, + 0x56, 0xd7, 0x0d, 0x54, 0x23, 0x3c, 0x4d, 0xc3, 0x46, 0x20, 0xc4, 0x04, 0x17, 0xbf, 0x6d, 0x32, 0x31, 0xed, 0x2d, + 0x21, 0x75, 0x84, 0xdd, 0x43, 0x39, 0xc1, 0x5d, 0xcd, 0xb3, 0x2f, 0xc3, 0xd9, 0x7a, 0xe6, 0xde, 0x33, 0x98, 0xfb, + 0x69, 0xc8, 0x0c, 0x46, 0x8f, 0x65, 0xc2, 0x8f, 0x8c, 0x7d, 0xe4, 0xaa, 0xea, 0xd9, 0x59, 0x58, 0x89, 0x2c, 0xf1, + 0x64, 0x1c, 0x75, 0x18, 0xa7, 0xa2, 0x35, 0x41, 0x76, 0x7d, 0x5d, 0x98, 0x7b, 0x81, 0x82, 0xa6, 0x1e, 0xab, 0xc7, + 0x69, 0x2b, 0x76, 0x36, 0x22, 0x91, 0x7b, 0x6f, 0x6a, 0x91, 0xc8, 0x8a, 0xcf, 0x71, 0xa4, 0x35, 0x07, 0xb9, 0xcf, + 0xce, 0x96, 0x37, 0xa9, 0xd0, 0x2d, 0x1a, 0x6d, 0x63, 0x8f, 0xea, 0x03, 0x49, 0x3d, 0xa3, 0x02, 0xab, 0x1a, 0xfb, + 0xfe, 0xfd, 0x8e, 0x48, 0xb7, 0x54, 0x8a, 0x0d, 0x43, 0x5a, 0x21, 0x33, 0x46, 0xc1, 0xa0, 0xa4, 0xc8, 0x40, 0x8d, + 0xf2, 0x35, 0x82, 0x61, 0x8f, 0x1a, 0x80, 0xe2, 0x5c, 0x5d, 0xfd, 0xb4, 0x94, 0x6c, 0x21, 0x20, 0x01, 0xd9, 0x84, + 0x62, 0x8d, 0x98, 0x19, 0xf9, 0xe4, 0x23, 0x70, 0xde, 0x80, 0xa3, 0x63, 0x00, 0x7e, 0x81, 0xd8, 0xf4, 0x60, 0x62, + 0xdb, 0x44, 0x14, 0x7d, 0x36, 0xf0, 0x12, 0x80, 0x9d, 0x55, 0xa1, 0xd1, 0x0f, 0x55, 0x0a, 0x18, 0xb2, 0x81, 0x1b, + 0xf0, 0x2a, 0x2c, 0xb7, 0xf7, 0x12, 0xda, 0xc1, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xd8, 0x9d, 0x5f, + 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x25, 0x23, 0x18, 0xf1, 0xfd, + 0x0d, 0x65, 0x1d, 0xaa, 0x71, 0xcb, 0x3d, 0x8d, 0x16, 0x61, 0xba, 0x4c, 0x1a, 0x83, 0x92, 0x75, 0x3f, 0x19, 0x71, + 0x2f, 0xf7, 0x45, 0x2c, 0xb8, 0xc2, 0xd1, 0x08, 0x9b, 0x37, 0x90, 0xa4, 0xa7, 0x3d, 0x3a, 0x60, 0xdf, 0x68, 0xf6, + 0x02, 0xca, 0x7c, 0xac, 0x48, 0x25, 0x21, 0xa5, 0xd9, 0x0d, 0x91, 0x24, 0xac, 0x15, 0x79, 0xea, 0xbc, 0xef, 0x68, + 0x9f, 0x5b, 0x49, 0x04, 0x23, 0x38, 0x89, 0xd3, 0x95, 0x07, 0x4d, 0x01, 0xae, 0xa2, 0x23, 0xa6, 0x6f, 0x82, 0xf2, + 0x1b, 0xe4, 0xf6, 0x52, 0x72, 0x6d, 0xae, 0x61, 0x78, 0x86, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x0d, 0x38, 0xe6, + 0xab, 0x3c, 0x0f, 0x30, 0xe1, 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x96, 0x02, 0xdd, 0x80, 0xe5, 0xea, + 0x38, 0x35, 0x2a, 0x12, 0x17, 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x53, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, + 0xa9, 0x4f, 0x99, 0x23, 0x64, 0xae, 0xb0, 0x3e, 0x67, 0x4e, 0x6d, 0xea, 0x1e, 0xa7, 0x6e, 0x9e, 0xa4, 0x16, 0xab, + 0xd3, 0xa6, 0x94, 0x88, 0x49, 0x89, 0x79, 0x2a, 0x53, 0xb1, 0x95, 0xb8, 0x73, 0xeb, 0x1b, 0x2d, 0xa4, 0x8d, 0x76, + 0x2a, 0x73, 0xb0, 0xb5, 0xbc, 0x17, 0xa2, 0xfd, 0x25, 0x11, 0x9e, 0x95, 0xc8, 0x58, 0x8b, 0x39, 0x73, 0x4c, 0x04, + 0xab, 0x17, 0x53, 0x91, 0x7f, 0x70, 0x74, 0x9a, 0xbd, 0x41, 0x0f, 0x52, 0x6f, 0x20, 0x31, 0x6b, 0xe2, 0xbb, 0x90, + 0x86, 0x3a, 0x42, 0xa0, 0x32, 0xaa, 0x65, 0x3a, 0x4e, 0x2c, 0x15, 0x97, 0xe4, 0xab, 0xf7, 0xfa, 0x38, 0xdf, 0x78, + 0x6e, 0xac, 0x46, 0x10, 0x83, 0xb7, 0x90, 0x1f, 0x79, 0x52, 0x84, 0x03, 0xe1, 0xf2, 0xcd, 0xcd, 0x5e, 0xbe, 0xcb, + 0xaa, 0x10, 0x49, 0x05, 0x63, 0x8c, 0x19, 0xc5, 0xb8, 0x27, 0x6a, 0x6a, 0x31, 0x07, 0x54, 0x65, 0xeb, 0x30, 0xc7, + 0x03, 0x00, 0x68, 0x69, 0x4a, 0x2f, 0xb3, 0xad, 0x3a, 0xcf, 0x25, 0x7c, 0x8c, 0x3c, 0x14, 0xd9, 0xf8, 0xfd, 0x9a, + 0x0c, 0x14, 0x84, 0xfb, 0x5e, 0xc7, 0xc3, 0xc4, 0x38, 0x58, 0x45, 0x21, 0x0b, 0xf4, 0x06, 0xed, 0x55, 0x89, 0x50, + 0xdc, 0x9c, 0xac, 0xc7, 0x0d, 0x27, 0x15, 0x6c, 0xa1, 0x12, 0x96, 0x4a, 0x0b, 0xfc, 0x6a, 0x23, 0x34, 0x4f, 0x19, + 0xf7, 0xde, 0x54, 0x38, 0x83, 0xfe, 0xe0, 0xde, 0x32, 0xa3, 0xbe, 0x5f, 0x3a, 0x91, 0xa9, 0xc0, 0xc4, 0xcd, 0x2c, + 0xb5, 0xdf, 0x2f, 0xab, 0xb4, 0x9f, 0x57, 0xc8, 0x7d, 0x4e, 0x9a, 0xaf, 0x73, 0x07, 0xcd, 0x27, 0xc3, 0xfd, 0x4a, + 0xf9, 0xa1, 0x85, 0x51, 0x53, 0x7e, 0x79, 0x5d, 0xf9, 0x15, 0x9e, 0x0a, 0x6f, 0xf5, 0xbb, 0x28, 0x74, 0x51, 0x9f, + 0x83, 0x21, 0xa4, 0x1f, 0xc1, 0x35, 0x34, 0x78, 0x50, 0x24, 0x8b, 0xc5, 0xda, 0x05, 0x71, 0x7d, 0xcc, 0xa9, 0x76, + 0x28, 0x63, 0x8c, 0x78, 0x5a, 0x72, 0x90, 0x64, 0x70, 0x30, 0x7e, 0x03, 0x03, 0x62, 0x52, 0x12, 0xd2, 0x21, 0x74, + 0x56, 0x66, 0x22, 0x2a, 0x77, 0xf1, 0x76, 0xe3, 0xb2, 0xa6, 0x50, 0x84, 0x9d, 0x60, 0xa6, 0x52, 0x2a, 0x08, 0xa4, + 0xc9, 0x77, 0xaf, 0x53, 0x0b, 0x86, 0x82, 0x68, 0x30, 0x14, 0x90, 0xd7, 0x76, 0x3d, 0x68, 0xf2, 0x51, 0x1c, 0x3c, + 0xaf, 0x50, 0x23, 0x5e, 0x66, 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x2e, 0x62, 0xaf, 0xe0, 0x13, 0x21, + 0x9b, 0xf2, 0xb0, 0x00, 0xfa, 0xa1, 0x5d, 0xd9, 0x4b, 0x77, 0x8b, 0xca, 0xa5, 0x45, 0x63, 0x2b, 0x51, 0xb3, 0xe6, + 0x87, 0xf1, 0x66, 0x7a, 0x04, 0x53, 0x53, 0x02, 0x01, 0x69, 0x2a, 0x27, 0xa9, 0xe6, 0x3d, 0x4c, 0x8f, 0x00, 0x24, + 0xd8, 0xfd, 0x04, 0x16, 0xfa, 0x4d, 0x89, 0x09, 0x16, 0x55, 0x63, 0xb7, 0x19, 0x68, 0xcd, 0x19, 0x69, 0xbe, 0x19, + 0x42, 0xb8, 0xa9, 0xac, 0x67, 0xcc, 0x0e, 0xb0, 0x6d, 0x77, 0xb3, 0x38, 0x4c, 0x37, 0x3b, 0x47, 0x86, 0xe0, 0xc2, + 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x5c, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, + 0xd1, 0x74, 0xee, 0x35, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, 0x89, 0x62, 0x9e, 0x13, + 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, 0xca, 0xcf, 0xe8, 0x48, + 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x4b, 0x30, 0x8d, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, 0x00, 0x5f, 0xd9, 0x50, + 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x72, 0x36, 0xc1, 0x02, 0x0d, 0xba, 0xac, 0xc1, 0x17, 0xb0, 0x0c, 0xee, + 0x48, 0x3f, 0x05, 0xdf, 0x4f, 0xeb, 0xe0, 0x33, 0xf6, 0xbf, 0x00, 0xb4, 0x2a, 0x30, 0xa0, 0xdc, 0x69, 0x1a, 0x56, + 0x42, 0x5c, 0xa2, 0xc2, 0xac, 0xe2, 0xfc, 0x71, 0x9d, 0xd7, 0x4d, 0xcb, 0x12, 0x83, 0xf2, 0x33, 0xd7, 0x70, 0xe3, + 0x7b, 0x8d, 0xfc, 0xf1, 0xbd, 0x97, 0xa0, 0xdb, 0x89, 0xb4, 0xf7, 0xef, 0xe7, 0xf7, 0xc8, 0x42, 0x03, 0x3f, 0x2c, + 0x9a, 0x41, 0x5b, 0xbc, 0x08, 0x90, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, 0x30, 0x03, 0x0c, + 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, 0xe4, 0xc5, 0x3a, + 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x20, 0xfa, 0x9a, 0xca, 0x62, 0x03, 0xb9, 0xb8, 0x29, 0x6b, + 0xbd, 0xa2, 0xd1, 0xe8, 0xc6, 0x2e, 0xbc, 0xae, 0xc0, 0x27, 0x51, 0x3a, 0x4a, 0xc4, 0x24, 0x66, 0x52, 0xe5, 0x8a, + 0x5c, 0x1b, 0xdd, 0x4b, 0x5b, 0x34, 0x2f, 0x85, 0x04, 0xaf, 0x08, 0xdc, 0x10, 0xfa, 0x4a, 0x5f, 0xae, 0x36, 0x50, + 0xf0, 0xa8, 0xbd, 0xb9, 0x08, 0x26, 0x26, 0x1e, 0x37, 0xa4, 0xa6, 0x5f, 0x87, 0x53, 0x2b, 0x8b, 0x25, 0x87, 0x5f, + 0xe7, 0x8c, 0x35, 0x14, 0x00, 0xf1, 0xc9, 0xa3, 0xf5, 0x6e, 0xd2, 0x1b, 0xa5, 0x1d, 0x94, 0x46, 0x88, 0xef, 0x2a, + 0x7c, 0xdd, 0x85, 0xe2, 0x2b, 0x57, 0xdd, 0xfb, 0x3a, 0x66, 0xc6, 0x05, 0xa3, 0x97, 0x7c, 0x9a, 0x34, 0xae, 0xdd, + 0xd0, 0x5d, 0x9d, 0xef, 0xbd, 0x2f, 0x65, 0xde, 0xc2, 0x31, 0xb0, 0xc9, 0x31, 0x73, 0x5e, 0x7a, 0x6f, 0x8d, 0x13, + 0xe5, 0x1f, 0xcc, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0x1f, 0x06, 0x3f, 0x04, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, + 0x5d, 0x75, 0x82, 0x4c, 0x94, 0xdb, 0xd0, 0x1b, 0x6e, 0xef, 0xae, 0x02, 0x41, 0x9c, 0x8a, 0xe9, 0xa3, 0x72, 0x5c, + 0x3f, 0x5a, 0xa0, 0x52, 0x11, 0xf1, 0xb9, 0xca, 0x5d, 0x59, 0x9b, 0x1a, 0xea, 0x31, 0x9d, 0xcc, 0x42, 0xd3, 0xac, + 0xc8, 0xa5, 0x6c, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, + 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, 0x7a, 0x14, 0x7d, 0x1c, 0xb7, 0x99, 0xcb, 0xa3, + 0xec, 0xcf, 0x1a, 0x00, 0xa6, 0x23, 0x2c, 0xba, 0x9b, 0x9e, 0xb1, 0x27, 0xd0, 0xd3, 0x13, 0x19, 0x24, 0x7a, 0xa3, + 0xf3, 0x55, 0xab, 0xc4, 0xd2, 0x15, 0x04, 0x76, 0x6f, 0xc8, 0x58, 0x95, 0xb4, 0x5b, 0xae, 0x5f, 0xce, 0xf3, 0x79, + 0xce, 0x97, 0xf2, 0x7c, 0x6a, 0x16, 0xdd, 0xbd, 0xb6, 0x7b, 0x73, 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, + 0x5d, 0x07, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, 0x8d, 0x7a, 0x26, 0xc7, 0x86, 0xf0, 0x4d, 0xa5, + 0x3b, 0x44, 0x37, 0x4c, 0xd5, 0x4c, 0xdf, 0x37, 0xb6, 0x85, 0x6c, 0xf3, 0xf2, 0x6a, 0x94, 0x03, 0xa5, 0xe5, 0xfe, + 0x32, 0x61, 0xf8, 0xfe, 0xfa, 0xfa, 0x7b, 0x21, 0xa7, 0xaa, 0x8e, 0xde, 0xe2, 0xb5, 0xee, 0x19, 0x6c, 0x94, 0xca, + 0x89, 0xb8, 0x60, 0xab, 0x07, 0x6f, 0xee, 0x5e, 0x01, 0xcb, 0x05, 0xec, 0xda, 0x0b, 0xe6, 0x34, 0x86, 0xaa, 0x36, + 0xf0, 0x97, 0xab, 0x07, 0x5b, 0xb5, 0x87, 0xbf, 0x1c, 0x7c, 0x19, 0xdc, 0xd8, 0xd8, 0xd8, 0xc6, 0xdb, 0xb5, 0x44, + 0x90, 0x37, 0x78, 0xa0, 0x8f, 0x57, 0x1f, 0x05, 0x2d, 0x57, 0x88, 0x6d, 0x36, 0x70, 0x28, 0x6c, 0x0d, 0xf2, 0x4d, + 0xca, 0xa4, 0xe1, 0xbc, 0xe0, 0xd9, 0x54, 0xce, 0x50, 0xc8, 0x6b, 0x3e, 0x0e, 0xda, 0x8e, 0xf0, 0xbf, 0xc0, 0xa9, + 0x1d, 0x2f, 0x2f, 0x3e, 0x41, 0x1f, 0xf0, 0x74, 0xa5, 0x34, 0xa5, 0x38, 0xa5, 0x0a, 0xea, 0x2c, 0xd7, 0x79, 0x30, + 0x52, 0x5c, 0x4c, 0x60, 0x71, 0xc1, 0x65, 0xb9, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, 0x44, + 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, 0xd7, + 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, 0xe7, + 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, 0x52, + 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, 0x2d, + 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, 0xc4, + 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, 0xd6, + 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, 0xe2, + 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0x67, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, 0x68, + 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, 0x57, + 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, 0x70, + 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, 0xc0, + 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0x61, 0x03, 0xb9, 0xd4, 0x92, 0xbf, 0xcc, + 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, 0x51, + 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x2f, 0x54, 0xe4, 0x98, 0x3a, + 0x98, 0x95, 0xda, 0x4d, 0x8b, 0x4d, 0x92, 0xf7, 0xcc, 0x80, 0xe4, 0xea, 0x6b, 0x78, 0x68, 0xfc, 0x32, 0xbc, 0xa1, + 0xe8, 0xe9, 0x18, 0x21, 0xa7, 0xa5, 0x31, 0x97, 0xfe, 0x5b, 0x79, 0x9f, 0x56, 0x02, 0xf6, 0x0a, 0xc4, 0x94, 0x81, + 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x4b, 0x26, 0x5d, 0xa5, 0xb2, 0xd6, 0x58, + 0x75, 0x3f, 0xcf, 0x59, 0x7e, 0xb5, 0xcf, 0x30, 0x37, 0x19, 0x0d, 0xb2, 0x25, 0x33, 0x9b, 0xf2, 0xab, 0xbd, 0x1b, + 0xbf, 0xf2, 0x50, 0xd2, 0xa1, 0x5a, 0xa5, 0x9b, 0x97, 0x6e, 0x38, 0xc6, 0x8d, 0x1b, 0x8e, 0x00, 0x36, 0x86, 0x9d, + 0x2a, 0x52, 0xeb, 0xfc, 0xf7, 0xa5, 0xf0, 0x93, 0xd8, 0x6b, 0x47, 0x7a, 0xd7, 0x1d, 0xad, 0x4c, 0x4f, 0xbf, 0x01, + 0x55, 0x23, 0x4b, 0xe8, 0x26, 0x54, 0x31, 0x19, 0x89, 0x12, 0xd3, 0x55, 0xca, 0xa3, 0xbe, 0x46, 0x9c, 0x83, 0xb8, + 0xa1, 0xfc, 0xc5, 0x3f, 0x85, 0x57, 0x27, 0x01, 0x1a, 0x51, 0x8b, 0x71, 0x96, 0xf2, 0xd6, 0x38, 0x9a, 0xc6, 0xc9, + 0x55, 0x30, 0x8f, 0x5b, 0xd3, 0x2c, 0xcd, 0x8a, 0x19, 0x70, 0xa5, 0x57, 0x5c, 0x81, 0x0d, 0x3f, 0x6d, 0xcd, 0x63, + 0xef, 0x25, 0x4b, 0xce, 0x19, 0x8f, 0x87, 0x91, 0x67, 0xef, 0xe5, 0x20, 0x1e, 0xac, 0xb7, 0x51, 0x9e, 0x67, 0x17, + 0xb6, 0xf7, 0x21, 0x3b, 0x05, 0xa6, 0xf5, 0xde, 0x5d, 0x5e, 0x9d, 0xb1, 0xd4, 0xfb, 0x78, 0x3a, 0x4f, 0xf9, 0xdc, + 0x2b, 0xa2, 0xb4, 0x68, 0x15, 0x2c, 0x8f, 0xc7, 0xa0, 0x26, 0x92, 0x2c, 0x6f, 0x61, 0xfe, 0xf3, 0x94, 0x05, 0x49, + 0x7c, 0x36, 0xe1, 0xd6, 0x28, 0xca, 0x3f, 0xf5, 0x5a, 0xad, 0x59, 0x1e, 0x4f, 0xa3, 0xfc, 0xaa, 0x45, 0x2d, 0x82, + 0xcf, 0xda, 0xdb, 0xd1, 0xe7, 0xe3, 0x87, 0x3d, 0x9e, 0x43, 0xdf, 0x18, 0xa9, 0x18, 0x80, 0xf0, 0xb1, 0xb6, 0x77, + 0xda, 0xd3, 0xe2, 0x9e, 0x38, 0x51, 0x8a, 0x52, 0x5e, 0x9e, 0x78, 0x57, 0x0c, 0xe0, 0xf6, 0x4f, 0x79, 0xea, 0x81, + 0x2f, 0xc7, 0xb3, 0x74, 0x31, 0x9c, 0xe7, 0x05, 0x0c, 0x30, 0xcb, 0xe2, 0x94, 0xb3, 0xbc, 0x77, 0x9a, 0xe5, 0x40, + 0xb6, 0x56, 0x1e, 0x8d, 0xe2, 0x79, 0x11, 0x3c, 0x9c, 0x5d, 0xf6, 0xd0, 0x56, 0x38, 0xcb, 0xb3, 0x79, 0x3a, 0x92, + 0x73, 0xc5, 0x29, 0x6c, 0x8c, 0x98, 0x9b, 0x15, 0xf4, 0x25, 0x14, 0x80, 0x2f, 0x65, 0x51, 0xde, 0x3a, 0xc3, 0xce, + 0x68, 0xe8, 0xb7, 0x47, 0xec, 0xcc, 0xcb, 0xcf, 0x4e, 0x23, 0xa7, 0xd3, 0x7d, 0xec, 0xa9, 0x7f, 0xfe, 0x8e, 0x0b, + 0x86, 0xfb, 0xca, 0xe2, 0x4e, 0xbb, 0xfd, 0x37, 0x6e, 0xaf, 0x31, 0x0b, 0x01, 0x14, 0x74, 0x66, 0x97, 0x56, 0x91, + 0x25, 0xb0, 0x3e, 0xab, 0x7a, 0xf6, 0x66, 0xe0, 0x37, 0xc5, 0xe9, 0x59, 0xd0, 0x9d, 0x5d, 0x96, 0x88, 0x5d, 0x20, + 0x12, 0x32, 0x25, 0x92, 0xf2, 0x6d, 0xf1, 0x5b, 0x21, 0x7e, 0xb2, 0x1a, 0xe2, 0xae, 0x82, 0xb8, 0xa2, 0x7a, 0x6b, + 0x04, 0xfb, 0x80, 0xc8, 0xdf, 0x29, 0x04, 0x20, 0x13, 0x70, 0x02, 0x73, 0x05, 0x07, 0xbd, 0xfc, 0x66, 0x30, 0xba, + 0xab, 0xc1, 0x78, 0x72, 0x1b, 0x18, 0x79, 0x3a, 0x5a, 0xd4, 0xd7, 0xb5, 0x03, 0xce, 0x69, 0x6f, 0xc2, 0x90, 0x9f, + 0x82, 0x2e, 0x3e, 0x5f, 0xc4, 0x23, 0x3e, 0x11, 0x8f, 0xc4, 0xce, 0x17, 0xa2, 0x6e, 0xa7, 0xdd, 0x16, 0xef, 0x05, + 0x28, 0xb4, 0xa0, 0xe3, 0x63, 0x03, 0x60, 0xa2, 0x2f, 0xd6, 0x7d, 0xc4, 0xe6, 0xbb, 0x5b, 0xbf, 0x54, 0xe3, 0x31, + 0x95, 0x37, 0x28, 0x54, 0x84, 0xfa, 0x66, 0x0b, 0x66, 0xbc, 0xe5, 0xfd, 0x8e, 0x3e, 0xa8, 0x1a, 0x7c, 0xc7, 0x48, + 0xeb, 0x05, 0xcc, 0x33, 0x73, 0x81, 0x7a, 0x69, 0x1f, 0x43, 0x52, 0xad, 0x96, 0x0b, 0x7a, 0x83, 0x63, 0x08, 0x89, + 0x0e, 0x04, 0x9d, 0x7c, 0x50, 0xd0, 0x37, 0x35, 0x32, 0x37, 0x28, 0x9c, 0xcc, 0x85, 0x2d, 0x9f, 0x69, 0xb9, 0x0e, + 0x4a, 0x1a, 0xbc, 0xec, 0x2f, 0x98, 0x6c, 0x00, 0xd2, 0xbb, 0x92, 0xb4, 0xbc, 0x3a, 0x7a, 0x52, 0x2e, 0x5f, 0x36, + 0x24, 0xca, 0x81, 0xaf, 0xcf, 0x27, 0xe8, 0x77, 0xeb, 0xab, 0xeb, 0x46, 0x4a, 0xcd, 0x96, 0xed, 0x0e, 0xb8, 0xce, + 0xca, 0xc2, 0xec, 0x33, 0x5e, 0xe2, 0x28, 0x5f, 0x81, 0x9c, 0xc5, 0xd0, 0xeb, 0xcf, 0xa1, 0x70, 0xd3, 0x94, 0x93, + 0xb6, 0x71, 0xd3, 0xf5, 0x7f, 0x58, 0xf1, 0x98, 0xb2, 0x9d, 0x55, 0x6c, 0x1c, 0x5c, 0x97, 0xe3, 0xa1, 0xb8, 0x76, + 0x58, 0x60, 0xb6, 0xf8, 0x6f, 0xf7, 0x24, 0x1c, 0x8d, 0x56, 0x91, 0xcd, 0xf3, 0x21, 0x26, 0xfd, 0xaf, 0x08, 0x31, + 0xd8, 0xa4, 0xe1, 0x6d, 0x8f, 0x6b, 0xc5, 0xc2, 0x30, 0x7f, 0xc2, 0xfc, 0xaa, 0x02, 0xa3, 0x53, 0x17, 0x71, 0xa9, + 0x41, 0x86, 0x55, 0x14, 0xd8, 0xa8, 0x2b, 0x47, 0x94, 0x60, 0x47, 0x17, 0x3e, 0xfd, 0x79, 0x1a, 0x83, 0x68, 0x3d, + 0x8e, 0x47, 0x74, 0xd1, 0x25, 0x1e, 0xd1, 0xc9, 0x47, 0x8b, 0x32, 0x9d, 0x30, 0x94, 0x0e, 0x05, 0x92, 0xe0, 0xf8, + 0x2c, 0x33, 0x67, 0xec, 0x96, 0x8d, 0xa7, 0x17, 0x86, 0x6e, 0x1e, 0x65, 0xd3, 0x28, 0x4e, 0x03, 0xfc, 0x20, 0x89, + 0xa7, 0x47, 0x0c, 0xb0, 0x8b, 0x07, 0x7f, 0x15, 0xed, 0x3b, 0xae, 0xff, 0x13, 0x08, 0x2e, 0xea, 0x5f, 0x4a, 0xc7, + 0x4f, 0xc3, 0xa5, 0xce, 0x95, 0xeb, 0xa5, 0x20, 0xec, 0xb8, 0xce, 0x6d, 0xa7, 0xc0, 0xca, 0x2e, 0xa3, 0x3f, 0x83, + 0x56, 0x27, 0xe8, 0xb8, 0xcb, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, 0xf3, + 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, 0x56, + 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, 0x5b, + 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xc5, 0x18, 0xb8, 0xaf, 0x65, 0x6d, 0x29, 0xf6, 0x1e, 0x9e, + 0xec, 0x0a, 0x21, 0x65, 0x11, 0xeb, 0x86, 0x36, 0x48, 0x0d, 0xdb, 0xfa, 0xe3, 0x10, 0xe8, 0xfc, 0x29, 0xb4, 0x37, + 0x16, 0x8e, 0xba, 0x0b, 0x90, 0xc3, 0x5c, 0x7b, 0x42, 0x51, 0xd3, 0x47, 0x04, 0xec, 0xfe, 0xc6, 0x82, 0x95, 0xbb, + 0x5b, 0xa2, 0x77, 0xff, 0xa4, 0x2c, 0x48, 0xa7, 0x9a, 0xb1, 0xbf, 0x6a, 0x0a, 0x51, 0x07, 0xc3, 0x52, 0xc6, 0x31, + 0x8e, 0x9b, 0x6b, 0x3b, 0x51, 0x04, 0xb9, 0x25, 0xe3, 0x16, 0x98, 0x61, 0x15, 0xe5, 0x20, 0x46, 0x74, 0x0e, 0x4d, + 0x21, 0xd2, 0x46, 0x7a, 0xcb, 0x50, 0x9c, 0x20, 0x04, 0x83, 0x8d, 0x45, 0x5c, 0x86, 0xf0, 0x94, 0x0e, 0xb3, 0x11, + 0xfb, 0xf8, 0xe1, 0x15, 0x5e, 0x93, 0xc8, 0x52, 0x94, 0xa7, 0x99, 0x5b, 0x9e, 0x80, 0x81, 0x85, 0x90, 0xe6, 0xea, + 0x2b, 0x35, 0x00, 0x8c, 0x88, 0x15, 0x59, 0x34, 0x2a, 0x82, 0xc2, 0x4b, 0xdb, 0x1a, 0x08, 0x08, 0xc1, 0x91, 0xc5, + 0x02, 0x30, 0x41, 0xa9, 0x17, 0x07, 0xfc, 0x44, 0xeb, 0x3e, 0x0c, 0xb4, 0xbb, 0x25, 0x1a, 0x01, 0xae, 0x39, 0xa2, + 0x51, 0xa1, 0x8a, 0x59, 0x45, 0x26, 0xba, 0xa3, 0xf8, 0x5c, 0x93, 0x93, 0x52, 0xac, 0xfb, 0xbb, 0x49, 0x74, 0xca, + 0x12, 0x18, 0x12, 0xf8, 0xaa, 0x0d, 0x23, 0x89, 0x57, 0x6b, 0x37, 0x4e, 0x67, 0x73, 0xf9, 0xb5, 0x30, 0x98, 0xb8, + 0x83, 0x07, 0xb8, 0x78, 0x99, 0x61, 0xa0, 0x4e, 0x24, 0x03, 0x39, 0x00, 0x80, 0x48, 0x87, 0x21, 0x08, 0x5d, 0xc5, + 0x2a, 0x50, 0x1a, 0x8f, 0x96, 0xcb, 0x60, 0x7f, 0xcf, 0xb0, 0x34, 0x85, 0xe7, 0x69, 0x9c, 0xe2, 0x63, 0x81, 0x8f, + 0xd1, 0x25, 0x3e, 0x66, 0xf0, 0xa8, 0x71, 0xcf, 0x4b, 0xfb, 0xaf, 0xba, 0x2a, 0x99, 0x5c, 0x01, 0x4b, 0x13, 0x20, + 0xbb, 0xbe, 0x06, 0xb5, 0xa5, 0x49, 0xb0, 0xbb, 0x05, 0xc4, 0x42, 0xee, 0x11, 0xdf, 0x8e, 0xe1, 0x26, 0x19, 0x59, + 0x31, 0x6b, 0x89, 0x72, 0x8b, 0x8c, 0x83, 0x10, 0x7c, 0xc7, 0xdc, 0x69, 0xd8, 0x40, 0x9e, 0xcc, 0x92, 0x79, 0x86, + 0x2f, 0xae, 0x6d, 0x89, 0x8f, 0x7b, 0x08, 0xa2, 0xd0, 0x23, 0x62, 0xa8, 0xcb, 0x98, 0xfc, 0x6c, 0x4f, 0x1c, 0xda, + 0x38, 0x0b, 0x98, 0xa1, 0xe8, 0x85, 0xf2, 0x28, 0x4e, 0x44, 0xe3, 0x15, 0xf8, 0x34, 0xd2, 0x1d, 0x09, 0x9d, 0xdd, + 0xad, 0x0a, 0x36, 0x00, 0x5e, 0x49, 0x04, 0x4e, 0x19, 0x37, 0xb6, 0x28, 0xa7, 0x14, 0x00, 0xb9, 0xcd, 0xab, 0x4f, + 0x3a, 0x01, 0x53, 0x80, 0x11, 0x3d, 0x3a, 0xa6, 0xd9, 0x06, 0x43, 0x20, 0x16, 0xcd, 0xd8, 0xd8, 0xba, 0xf6, 0x5f, + 0xfe, 0xf9, 0x1f, 0x6c, 0x4f, 0x80, 0x98, 0x8d, 0xc7, 0x20, 0xe5, 0xac, 0x75, 0x0d, 0xff, 0xd7, 0x3f, 0xfe, 0xdf, + 0xff, 0xf3, 0x5f, 0x75, 0xdb, 0x14, 0x9a, 0x9e, 0x04, 0xe2, 0x68, 0x41, 0x93, 0x94, 0x52, 0x3c, 0xed, 0x71, 0x94, + 0xae, 0x00, 0xe9, 0x10, 0xb3, 0x18, 0x19, 0x1b, 0x79, 0xb6, 0x05, 0x9a, 0x40, 0x3c, 0x1f, 0x27, 0xec, 0x9c, 0xc9, + 0x0f, 0xcb, 0xe8, 0x41, 0x74, 0xe5, 0x10, 0x2c, 0x18, 0x2e, 0xef, 0xbc, 0xca, 0x6d, 0xa0, 0x68, 0x29, 0x29, 0x5e, + 0x27, 0x98, 0x67, 0x1b, 0x83, 0x36, 0xe7, 0x68, 0xd7, 0x87, 0xf5, 0x40, 0xa5, 0xda, 0xb6, 0x80, 0x97, 0xcc, 0xde, + 0x95, 0x10, 0x37, 0xe1, 0x3a, 0xcd, 0xb1, 0x69, 0xca, 0x8a, 0x62, 0x15, 0x58, 0x40, 0x13, 0xcf, 0xae, 0x9a, 0xd8, + 0xb5, 0x0e, 0x00, 0x40, 0x77, 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x3c, 0x86, 0x0d, 0x8e, 0xba, 0x2d, 0xe1, 0x18, + 0x84, 0x0f, 0xfb, 0xf6, 0x5b, 0x90, 0x25, 0x78, 0xa7, 0xc5, 0xd5, 0x9f, 0xf4, 0xa2, 0xe9, 0x95, 0xb0, 0x33, 0xe6, + 0x10, 0x9d, 0x8d, 0x61, 0xf4, 0x93, 0x81, 0x54, 0x36, 0xfc, 0xb4, 0x8a, 0x31, 0xd6, 0x32, 0xc2, 0xbf, 0xff, 0xcb, + 0x3f, 0xfe, 0x37, 0x18, 0x9b, 0xfa, 0xad, 0xe7, 0x02, 0x68, 0xf5, 0x3f, 0xa1, 0xd5, 0x3c, 0xbd, 0xa5, 0xdd, 0x5f, + 0xfe, 0xfe, 0xbf, 0x43, 0x33, 0xba, 0x28, 0x05, 0x7c, 0x42, 0x10, 0x0d, 0xd1, 0x36, 0xfd, 0x55, 0x20, 0xd5, 0x06, + 0x59, 0x3b, 0xd3, 0x3f, 0x21, 0xd8, 0x05, 0xcf, 0x66, 0x37, 0x82, 0x83, 0x50, 0x0f, 0x93, 0xac, 0x60, 0x1a, 0x1e, + 0xa1, 0x4f, 0x7e, 0x1d, 0x40, 0x34, 0xd7, 0x0c, 0x76, 0x6d, 0x61, 0xe9, 0x71, 0xc4, 0x0a, 0xad, 0xdc, 0x84, 0xf5, + 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, 0xda, + 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, 0x52, + 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, 0x48, + 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, 0x22, + 0xd2, 0x9a, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, 0x9f, + 0x85, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, 0x12, + 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, 0x97, + 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, 0x0c, + 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, 0x7f, + 0x83, 0x97, 0x1d, 0x91, 0x78, 0x64, 0x29, 0x14, 0x64, 0xd8, 0x30, 0x32, 0x6c, 0xa4, 0x46, 0x35, 0x6d, 0x0a, 0x74, + 0xfc, 0xb2, 0xd5, 0xb6, 0xc3, 0x31, 0x76, 0xaf, 0x69, 0x7f, 0x26, 0xb5, 0x7f, 0x2c, 0xed, 0x7d, 0xa9, 0xfd, 0xf1, + 0x93, 0x36, 0x0d, 0xed, 0x1f, 0xaf, 0xd5, 0xfe, 0x48, 0xb9, 0x01, 0x8e, 0x1c, 0xda, 0x9b, 0x18, 0xdd, 0x32, 0x6c, + 0x0d, 0xd4, 0xc4, 0x83, 0xe1, 0x84, 0x0d, 0x3f, 0x49, 0x33, 0x8b, 0x10, 0xc0, 0x40, 0x94, 0x36, 0x26, 0x05, 0x06, + 0x60, 0x32, 0x9c, 0x94, 0x7a, 0xd3, 0xe3, 0xa3, 0x31, 0x01, 0x73, 0x17, 0x63, 0x86, 0xa2, 0x1f, 0xd6, 0xec, 0x2b, + 0x56, 0x6e, 0xe1, 0x38, 0x62, 0xc3, 0x88, 0x67, 0xc0, 0x6c, 0x0b, 0x07, 0x3b, 0xf1, 0x16, 0x22, 0x58, 0x18, 0xd8, + 0xef, 0xdf, 0xed, 0x1f, 0xd8, 0xde, 0x69, 0x36, 0xba, 0x0a, 0x6c, 0x70, 0xc6, 0xc0, 0x9a, 0x72, 0x7d, 0x3e, 0x61, + 0xa9, 0xa3, 0x3c, 0x9f, 0x2c, 0x61, 0xe0, 0x00, 0x9e, 0x89, 0x6f, 0x5b, 0x34, 0x0f, 0x3a, 0x80, 0xb0, 0xf4, 0xf1, + 0xcb, 0xfe, 0x2e, 0x17, 0xdf, 0x85, 0xe5, 0x39, 0x3e, 0xf6, 0x31, 0xd5, 0x63, 0x77, 0x0b, 0x1e, 0xf0, 0x65, 0x1f, + 0xf5, 0x1e, 0xbd, 0x6d, 0x2c, 0x96, 0xdc, 0x86, 0x01, 0x0e, 0x31, 0xe9, 0x0b, 0x14, 0x0a, 0x6a, 0x75, 0x12, 0x20, + 0x62, 0xf0, 0x08, 0x63, 0x6d, 0xa9, 0x71, 0x11, 0x42, 0xd5, 0x5f, 0x3b, 0x2e, 0x95, 0xdd, 0x4a, 0xf3, 0x8e, 0xb0, + 0x01, 0x39, 0x2e, 0xd8, 0x7b, 0xa4, 0x4b, 0x84, 0xa9, 0x43, 0x45, 0xeb, 0x20, 0xd0, 0x35, 0x95, 0xb9, 0x22, 0x3a, + 0x18, 0xc0, 0x90, 0x99, 0x2b, 0x00, 0x81, 0xbf, 0x84, 0xf6, 0x89, 0xf9, 0xfd, 0x37, 0xf1, 0xa9, 0x26, 0x4d, 0x9c, + 0xc3, 0x3f, 0x79, 0x57, 0xcc, 0xbb, 0x3a, 0xa1, 0x96, 0x2a, 0xd8, 0x80, 0x51, 0x30, 0x0c, 0xca, 0xb4, 0x55, 0x54, + 0x09, 0xec, 0xb4, 0x24, 0x9a, 0x15, 0x2c, 0x50, 0x0f, 0x32, 0xee, 0x80, 0xe1, 0x8b, 0xe5, 0x40, 0x8f, 0x69, 0xcf, + 0x95, 0x7c, 0xb2, 0x30, 0x03, 0x13, 0x8f, 0xda, 0xed, 0x1e, 0x5e, 0xaa, 0x68, 0x45, 0x60, 0x1d, 0xa4, 0x41, 0xc2, + 0xc6, 0xbc, 0xe4, 0x78, 0x6b, 0x7f, 0xa1, 0x22, 0x41, 0x7e, 0x77, 0x27, 0x67, 0x53, 0xcb, 0xc7, 0xff, 0xbf, 0x6d, + 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, 0x0d, 0x19, + 0x46, 0xc9, 0x4a, 0x0e, 0xce, 0x37, 0x88, 0x9b, 0xdc, 0x6c, 0x07, 0x72, 0x7a, 0x29, 0x54, 0xb6, 0x1c, 0xac, 0xd9, + 0x76, 0xa5, 0x7f, 0xb4, 0xdc, 0x58, 0x45, 0xbc, 0xea, 0x6f, 0x4b, 0x14, 0x32, 0x62, 0x73, 0xa5, 0x50, 0x51, 0x0b, + 0xd1, 0xc3, 0xc4, 0x69, 0x39, 0x6a, 0x77, 0xab, 0xc5, 0x5c, 0x92, 0xb8, 0x38, 0x24, 0x71, 0x41, 0xe2, 0xef, 0x68, + 0x21, 0xe6, 0x1e, 0x46, 0xc9, 0xd0, 0x41, 0x00, 0xac, 0x96, 0xf5, 0x04, 0xa8, 0xe9, 0xaa, 0xc8, 0x91, 0xff, 0x18, + 0x89, 0x5b, 0x0a, 0x61, 0xb9, 0x82, 0x4a, 0x27, 0x47, 0x65, 0xd9, 0x63, 0xcc, 0x39, 0xfc, 0x20, 0x2f, 0x81, 0x88, + 0xbb, 0xbf, 0xfa, 0xfb, 0x89, 0xed, 0xd2, 0x3d, 0xf2, 0x7e, 0x36, 0x3e, 0x4a, 0x67, 0x2b, 0x66, 0xb7, 0x3d, 0x58, + 0x06, 0xb3, 0xa7, 0xfc, 0x84, 0xe4, 0x4d, 0x7d, 0x4d, 0x36, 0xa7, 0xfe, 0x3f, 0x87, 0x38, 0xc2, 0x1b, 0xc7, 0x46, + 0x13, 0x9d, 0x46, 0xbe, 0x6a, 0x11, 0x7f, 0xda, 0xd8, 0x55, 0x1c, 0x81, 0x7c, 0xbd, 0x2e, 0x92, 0xf5, 0xcd, 0xed, + 0x91, 0xac, 0xe2, 0x8e, 0x91, 0xac, 0x6f, 0x7e, 0xe7, 0x48, 0xd6, 0xd7, 0x66, 0x24, 0x0b, 0x05, 0xf4, 0xab, 0x5f, + 0x13, 0x6d, 0xca, 0xb3, 0x8b, 0x22, 0xec, 0xc8, 0xcc, 0x09, 0x90, 0x75, 0x18, 0x76, 0xfa, 0xeb, 0x47, 0x98, 0x60, + 0xa2, 0x46, 0x7c, 0x89, 0x02, 0x4a, 0x22, 0xd9, 0x13, 0xd4, 0x8a, 0x0c, 0xe7, 0xb4, 0x75, 0x56, 0x65, 0xeb, 0xa1, + 0xba, 0x46, 0x06, 0xae, 0xaf, 0xab, 0x43, 0x6d, 0x5d, 0x15, 0xf0, 0x09, 0xe8, 0x3b, 0xb0, 0xba, 0x63, 0x77, 0x53, + 0xa5, 0xf3, 0x99, 0x23, 0xf4, 0xd4, 0x29, 0x8d, 0x60, 0xa2, 0x85, 0xfd, 0x5f, 0x0e, 0x3b, 0xbd, 0xed, 0xce, 0x14, + 0x7a, 0x83, 0x02, 0x87, 0xb7, 0x76, 0x6f, 0x7b, 0x1b, 0xdf, 0x2e, 0xd4, 0x5b, 0x17, 0xdf, 0x62, 0xf5, 0xb6, 0x83, + 0x6f, 0x43, 0xf5, 0xf6, 0x08, 0xdf, 0x46, 0xea, 0xed, 0x31, 0xbe, 0x9d, 0xdb, 0xe5, 0x21, 0xd3, 0xc0, 0x3d, 0x06, + 0xbe, 0x22, 0x6f, 0x26, 0x50, 0x65, 0xb0, 0xe9, 0xf1, 0xc3, 0x08, 0xd1, 0x59, 0x10, 0x7b, 0xc2, 0xbb, 0x0c, 0x72, + 0xef, 0x02, 0x34, 0x4e, 0x40, 0xd9, 0x86, 0xcf, 0xf1, 0x3b, 0x1c, 0xe0, 0x24, 0x1d, 0xc4, 0x53, 0xa6, 0x3e, 0x48, + 0xac, 0xb0, 0x06, 0x03, 0xf6, 0xb0, 0x7d, 0x54, 0xf6, 0xf4, 0x3a, 0x89, 0x78, 0x96, 0xca, 0xe6, 0xa0, 0x95, 0xab, + 0xea, 0xc4, 0x74, 0x2d, 0xbd, 0xc2, 0x6b, 0xf4, 0x97, 0x11, 0x8f, 0x18, 0x83, 0x61, 0xd6, 0xba, 0x04, 0x0f, 0x76, + 0xa5, 0x4e, 0x43, 0x88, 0xb4, 0x4e, 0x23, 0x9c, 0xf4, 0xdb, 0x41, 0x74, 0xa6, 0x9f, 0xdf, 0x80, 0xa5, 0x1d, 0x9d, + 0xc9, 0x96, 0xeb, 0x75, 0x18, 0x81, 0x68, 0xea, 0x2f, 0x05, 0x04, 0x99, 0x62, 0xb0, 0x34, 0xe8, 0x49, 0x4b, 0xfd, + 0x85, 0xd4, 0xa9, 0x6b, 0x34, 0x9a, 0xbe, 0x5e, 0x04, 0x14, 0xad, 0x0a, 0x76, 0xc1, 0xe0, 0xa7, 0x52, 0x41, 0x61, + 0xa8, 0xc0, 0x02, 0x51, 0xbd, 0x46, 0x95, 0xe9, 0x60, 0xc3, 0x5a, 0x85, 0x66, 0x29, 0x5d, 0x66, 0x9e, 0xee, 0xe8, + 0xa3, 0x9d, 0x65, 0xf1, 0xfa, 0x59, 0x67, 0x88, 0xff, 0x49, 0xe1, 0xfd, 0xd9, 0x78, 0x3c, 0xbe, 0x51, 0xb7, 0x7d, + 0x36, 0x1a, 0xb3, 0x2e, 0xdb, 0xe9, 0x61, 0xe4, 0xbf, 0x25, 0xc5, 0x69, 0xa7, 0x24, 0xda, 0x2d, 0xee, 0xd6, 0x18, + 0x25, 0x2f, 0xa8, 0xbb, 0xbb, 0x2b, 0xc1, 0x12, 0xa8, 0xb2, 0x00, 0xe1, 0x7f, 0x16, 0xa7, 0x41, 0xbb, 0xf4, 0xcf, + 0xa5, 0xd6, 0xf8, 0xec, 0xc9, 0x93, 0x27, 0xa5, 0x3f, 0x52, 0x6f, 0xed, 0xd1, 0xa8, 0xf4, 0x87, 0x0b, 0x8d, 0x46, + 0xbb, 0x3d, 0x1e, 0x97, 0x7e, 0xac, 0x0a, 0xb6, 0xbb, 0xc3, 0xd1, 0x76, 0xb7, 0xf4, 0x2f, 0x8c, 0x16, 0xa5, 0xcf, + 0xe4, 0x5b, 0xce, 0x46, 0xb5, 0xe3, 0x83, 0xc7, 0x6d, 0xa8, 0x14, 0x8c, 0xb6, 0x40, 0xef, 0x52, 0x3c, 0x06, 0xd1, + 0x9c, 0x67, 0x60, 0xd8, 0x95, 0xbd, 0x02, 0xe4, 0xf3, 0x58, 0x4a, 0x78, 0xf1, 0xbd, 0x5f, 0x94, 0xea, 0xaf, 0x4c, + 0xa9, 0x8e, 0xcc, 0x4c, 0xd2, 0xbc, 0x20, 0x6d, 0xd0, 0xac, 0x46, 0xce, 0xa2, 0xea, 0x57, 0x61, 0x51, 0x09, 0x7b, + 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xd6, 0xc9, 0xf8, 0xef, 0x6f, 0x97, 0xf1, 0xa7, 0x77, 0x13, 0xf1, 0xdf, + 0xff, 0xce, 0x22, 0xfe, 0x07, 0x53, 0xc4, 0x0b, 0x21, 0xb6, 0x07, 0xa6, 0x33, 0xd9, 0xcc, 0xa7, 0xd9, 0x65, 0x0b, + 0xb7, 0x44, 0x6e, 0x93, 0xf4, 0x9c, 0xde, 0x49, 0xf8, 0xaf, 0xc8, 0x07, 0x53, 0x83, 0x19, 0x1f, 0x0f, 0xe6, 0xd9, + 0xd9, 0x59, 0xc2, 0x94, 0x8c, 0x37, 0x2a, 0xc8, 0x1c, 0x7f, 0x97, 0x86, 0xf6, 0x3b, 0xf4, 0x8c, 0xab, 0x92, 0xf1, + 0x18, 0x8a, 0xc6, 0x63, 0x5b, 0xe5, 0x4b, 0x83, 0x3c, 0xa3, 0x56, 0x6f, 0x6b, 0x25, 0xd4, 0xea, 0x8b, 0x2f, 0xcc, + 0x32, 0xb3, 0x40, 0x86, 0xf4, 0x4c, 0x63, 0x44, 0xd6, 0x8c, 0xe2, 0x02, 0xf7, 0x60, 0xf5, 0xb1, 0x63, 0xb4, 0x77, + 0xa6, 0xa0, 0x54, 0xe2, 0x21, 0x9e, 0x8b, 0x34, 0x3f, 0x2c, 0x23, 0x72, 0xdb, 0x97, 0x91, 0xab, 0xce, 0xbf, 0x8d, + 0x6f, 0x18, 0x56, 0x67, 0xde, 0xb0, 0xf8, 0x32, 0xbf, 0xe5, 0xe9, 0xd5, 0xab, 0x91, 0xb3, 0x87, 0x97, 0x7f, 0x8b, + 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, 0xec, 0x19, + 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, 0x92, 0x6e, + 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xd2, 0x79, 0x08, 0xcd, 0x30, + 0x2a, 0xd5, 0x19, 0x08, 0x10, 0x6e, 0x86, 0x9f, 0x68, 0x12, 0x43, 0xa8, 0x83, 0x82, 0x8a, 0x7a, 0xd7, 0xd7, 0xe6, + 0x97, 0x42, 0x6b, 0x5f, 0x95, 0x6c, 0xf0, 0x00, 0xc7, 0x4f, 0xfc, 0xa2, 0x36, 0xc8, 0xe6, 0xdc, 0xc1, 0x33, 0x80, + 0x05, 0x1e, 0x31, 0x78, 0x3b, 0xed, 0x36, 0xa8, 0x18, 0x5f, 0x7c, 0x07, 0xca, 0xd1, 0x9d, 0x05, 0xbe, 0x6c, 0xdd, + 0xb9, 0xc4, 0xd2, 0x77, 0xd9, 0x2a, 0x12, 0xdf, 0xbf, 0x2f, 0x11, 0x35, 0xee, 0x0e, 0xa9, 0x45, 0x6c, 0xbe, 0xfb, + 0xca, 0x77, 0x34, 0x08, 0xeb, 0xae, 0xe2, 0x60, 0x99, 0x5b, 0x5b, 0x2f, 0xc4, 0xb6, 0xc2, 0xaa, 0x59, 0x06, 0xe7, + 0x16, 0x9d, 0x59, 0x5c, 0x18, 0x01, 0xfc, 0xda, 0x36, 0x28, 0x55, 0x04, 0x5f, 0x84, 0xe1, 0xf7, 0xd0, 0xc5, 0x15, + 0x8e, 0xb7, 0x02, 0xba, 0xe1, 0xf2, 0x56, 0x90, 0xa3, 0x33, 0xac, 0x19, 0x5d, 0x55, 0xa9, 0x82, 0xd2, 0x3c, 0x82, + 0x31, 0x90, 0xa1, 0x48, 0x3a, 0xac, 0x71, 0x2a, 0xf4, 0x16, 0x4c, 0x43, 0x02, 0x58, 0xfb, 0x75, 0xe8, 0xd6, 0xd8, + 0x0a, 0x6c, 0x21, 0x2d, 0x40, 0xe9, 0x61, 0x87, 0xbe, 0x55, 0x03, 0x3d, 0x5d, 0x0e, 0xc0, 0xdf, 0xe8, 0xe4, 0x9d, + 0xf8, 0xc5, 0x85, 0x07, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, 0x86, + 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, 0x41, + 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, 0xdf, + 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, 0xd5, + 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0x7f, 0x46, 0xe6, 0x42, 0xb3, 0x98, 0x0e, 0xe0, 0xef, 0x02, + 0x59, 0x10, 0x8d, 0xf1, 0x0b, 0x8b, 0x77, 0x69, 0x79, 0x4a, 0xd9, 0xaf, 0x0b, 0x54, 0xeb, 0x41, 0xe7, 0x09, 0x78, + 0x7b, 0x77, 0x1e, 0xfe, 0x66, 0xf4, 0x4b, 0x49, 0x23, 0x75, 0x89, 0xd9, 0xb6, 0x7b, 0x28, 0x2f, 0x92, 0xe8, 0x0a, + 0x9c, 0x4e, 0xb2, 0x31, 0x4e, 0x31, 0x7a, 0xdc, 0x9b, 0x65, 0x32, 0x93, 0x24, 0x67, 0x09, 0xfd, 0x8c, 0x89, 0x5c, + 0x8a, 0xed, 0x47, 0xb3, 0x4b, 0xb5, 0x1a, 0x9d, 0x46, 0x86, 0xc8, 0xef, 0x9a, 0x08, 0xb2, 0x3e, 0xf3, 0xa4, 0x9e, + 0xcc, 0xb0, 0x03, 0x30, 0x08, 0xc3, 0xa6, 0x95, 0x0b, 0xa8, 0xda, 0x50, 0x62, 0xa4, 0xc2, 0x54, 0x03, 0x59, 0xfe, + 0x36, 0xa8, 0xca, 0xa8, 0x60, 0x3d, 0xfc, 0xd4, 0x65, 0x0c, 0xae, 0xad, 0x34, 0x9e, 0xa6, 0xf1, 0x68, 0x94, 0xb0, + 0x9e, 0xb2, 0x8f, 0xac, 0xce, 0x23, 0xcc, 0x24, 0x31, 0x97, 0xac, 0xbe, 0x2a, 0x06, 0xf1, 0x34, 0x9d, 0xa2, 0x53, + 0xb0, 0xd7, 0xf0, 0x7b, 0x95, 0x2b, 0xc9, 0x29, 0x53, 0x2c, 0xda, 0x15, 0xf1, 0xe8, 0xb9, 0x8e, 0xcb, 0x0e, 0x18, + 0x8b, 0xb4, 0xe0, 0xed, 0x1e, 0xcf, 0x66, 0x41, 0x6b, 0xbb, 0x8e, 0x08, 0x56, 0x69, 0x14, 0xbc, 0x15, 0x68, 0x79, + 0x68, 0x1d, 0x08, 0x2d, 0x67, 0xf9, 0x1d, 0x59, 0x46, 0x03, 0xe0, 0x37, 0x11, 0x75, 0x51, 0x59, 0x47, 0xe6, 0xaf, + 0xb3, 0x5b, 0x3e, 0x5f, 0xbd, 0x5b, 0x3e, 0x57, 0xbb, 0xe5, 0x66, 0x8e, 0xfd, 0x6c, 0xdc, 0xc1, 0xff, 0x7a, 0x15, + 0x42, 0xb0, 0x2a, 0x40, 0x0e, 0x0b, 0xed, 0xe2, 0x56, 0x17, 0xfe, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x9f, 0x0f, 0x16, + 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xd7, 0xae, 0x55, 0x75, 0x1e, 0x62, 0x1d, 0xf6, 0xda, 0x59, 0xae, 0xeb, 0xde, 0xbc, + 0x69, 0x41, 0x5e, 0x71, 0x27, 0x50, 0xc2, 0x18, 0x5c, 0xb5, 0xe8, 0xf4, 0x14, 0x4a, 0xc7, 0xd9, 0x70, 0x5e, 0xfc, + 0xad, 0x84, 0x5f, 0x12, 0xf1, 0xc6, 0x2d, 0xdd, 0x18, 0x47, 0x75, 0x15, 0x69, 0x49, 0x6a, 0x84, 0x85, 0x5e, 0xa7, + 0xa0, 0x00, 0xc6, 0x64, 0x4e, 0xd7, 0x7f, 0xb8, 0x62, 0x13, 0xfc, 0x7f, 0x59, 0x9b, 0x95, 0xc8, 0xfc, 0x47, 0x89, + 0x71, 0x23, 0x11, 0x7e, 0x15, 0x0d, 0xcc, 0x35, 0x6c, 0x3f, 0x59, 0x0d, 0xee, 0xa1, 0x9a, 0xe9, 0x48, 0x29, 0x05, + 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0xe6, 0x09, 0xbf, 0x79, 0xd4, 0x75, 0x9c, 0xb1, 0x34, 0xea, 0x0d, 0x02, 0xbd, 0x6a, + 0x7b, 0x47, 0x29, 0xfd, 0xd9, 0xe7, 0x0f, 0xf1, 0x3f, 0x11, 0x38, 0x3b, 0xad, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, + 0x68, 0x5a, 0x73, 0x7e, 0x84, 0x06, 0x27, 0xff, 0xe7, 0xae, 0xad, 0xd1, 0x58, 0xbf, 0x53, 0x73, 0x69, 0x95, 0xfe, + 0xaa, 0xd6, 0xbf, 0x6e, 0xf0, 0x3b, 0xb6, 0x1d, 0x0a, 0x87, 0xa0, 0xde, 0x56, 0xc6, 0x03, 0x97, 0x1a, 0x2b, 0x8a, + 0xdf, 0xb5, 0x7d, 0x65, 0x12, 0x53, 0x8f, 0x69, 0x78, 0xaa, 0x9d, 0x48, 0x79, 0x78, 0x8f, 0x3d, 0x84, 0x1f, 0xf9, + 0x25, 0x0b, 0x1f, 0xe0, 0xd7, 0xd8, 0xac, 0xcb, 0x69, 0x92, 0x82, 0x59, 0x35, 0xe1, 0x7c, 0x16, 0x6c, 0x6d, 0x5d, + 0x5c, 0x5c, 0xf8, 0x17, 0xdb, 0x7e, 0x96, 0x9f, 0x6d, 0x75, 0xdb, 0xed, 0x36, 0x7e, 0x44, 0xcb, 0xb6, 0xce, 0x63, + 0x76, 0xf1, 0x14, 0xdc, 0x0f, 0xfb, 0xb1, 0xf5, 0xc4, 0x7a, 0xbc, 0x6d, 0xed, 0x3c, 0xb2, 0x2d, 0x52, 0x00, 0x50, + 0xb2, 0x6d, 0x5b, 0x42, 0x01, 0x84, 0x36, 0x14, 0xf7, 0x77, 0xcf, 0x94, 0x0d, 0x87, 0x97, 0x14, 0x84, 0x85, 0x04, + 0xfe, 0x5b, 0xf6, 0x89, 0xd5, 0xb7, 0xba, 0x28, 0x6b, 0x49, 0x35, 0xa2, 0x5e, 0x71, 0xbf, 0x0f, 0xa3, 0x59, 0x40, + 0x6c, 0x64, 0x16, 0x62, 0x98, 0x4c, 0x94, 0xd2, 0x14, 0x68, 0x97, 0x9e, 0xc2, 0x13, 0x66, 0xb5, 0x59, 0xf0, 0xfc, + 0xa6, 0xfb, 0x18, 0x74, 0xdc, 0x79, 0xeb, 0xe1, 0xb0, 0xdd, 0xea, 0x58, 0x9d, 0x56, 0xd7, 0x7f, 0x6c, 0x75, 0xc5, + 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, 0xfd, + 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, 0xb8, + 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, 0xd0, + 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, 0xd8, + 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0x77, 0xbe, 0xfd, 0x64, + 0x08, 0x1a, 0xc1, 0xc2, 0x7f, 0xf0, 0xdf, 0x64, 0xa7, 0x3b, 0x14, 0x2f, 0x6d, 0xac, 0xff, 0xb6, 0xf3, 0xb8, 0x80, + 0xa6, 0xf8, 0xdf, 0x2f, 0xda, 0x84, 0x46, 0x03, 0xde, 0x1c, 0xf7, 0x21, 0xd0, 0xe8, 0xc9, 0xa4, 0xeb, 0x7f, 0x7e, + 0xfe, 0xd8, 0x7f, 0x32, 0xe9, 0x3c, 0xfe, 0x56, 0xbc, 0x25, 0x40, 0xc1, 0xcf, 0xf1, 0xdf, 0xb7, 0xdb, 0xed, 0x49, + 0xab, 0xe3, 0x3f, 0x39, 0xdf, 0xf6, 0xb7, 0x93, 0xd6, 0x23, 0xff, 0x09, 0xfe, 0xab, 0x86, 0x9b, 0x64, 0x53, 0x66, + 0x5b, 0xb8, 0xde, 0x0d, 0xbf, 0xd7, 0x9c, 0xa3, 0xfb, 0xd0, 0xda, 0x79, 0xf8, 0xf2, 0x09, 0xac, 0xd1, 0xa4, 0xd3, + 0x85, 0xff, 0x5f, 0xf7, 0xf8, 0x2d, 0x12, 0x5e, 0x0e, 0x1c, 0x31, 0x4c, 0x2f, 0x56, 0x84, 0xa3, 0x0f, 0xba, 0x3d, + 0xf0, 0xfe, 0xb4, 0x2e, 0x00, 0xc2, 0xf8, 0xad, 0x01, 0x10, 0xce, 0xef, 0x16, 0x01, 0xa1, 0x5f, 0x1b, 0xf8, 0x1d, + 0x23, 0x20, 0x7f, 0x6a, 0x06, 0xb9, 0x2f, 0xd9, 0x52, 0xa0, 0xa3, 0xe9, 0xac, 0xbd, 0x65, 0xce, 0xe1, 0x97, 0xf8, + 0xe3, 0x06, 0x65, 0x0f, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0x97, 0xf2, 0xe2, 0x43, 0xc1, 0xd7, 0x10, + 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, 0x29, + 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, 0xd3, + 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, 0x34, + 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, 0xa6, + 0xdf, 0xcf, 0x8a, 0x79, 0xc2, 0x30, 0x9d, 0x66, 0x28, 0x3e, 0x20, 0x0b, 0x8f, 0xf2, 0xae, 0x21, 0xa6, 0xb0, 0x7f, + 0x83, 0xe9, 0xf7, 0xea, 0xec, 0x60, 0x8a, 0x71, 0x84, 0x37, 0x6c, 0x14, 0x47, 0x8e, 0xed, 0xcc, 0x60, 0x23, 0xc3, + 0x2c, 0xad, 0x5a, 0xee, 0x3b, 0xa5, 0xbd, 0xbb, 0xb6, 0xfa, 0x69, 0xa6, 0x1c, 0x3f, 0x75, 0x17, 0x1e, 0xca, 0xb8, + 0xa3, 0x2d, 0x1d, 0x03, 0x18, 0x5f, 0x95, 0xe4, 0xa8, 0x03, 0x2a, 0x63, 0xc2, 0x16, 0xd6, 0x44, 0xc7, 0xef, 0x82, + 0x77, 0x41, 0xc5, 0xf8, 0xe9, 0xb0, 0xef, 0x9d, 0xd6, 0x36, 0x58, 0x3b, 0x46, 0x37, 0x3d, 0xd0, 0x91, 0xfe, 0xa5, + 0x1f, 0xfd, 0x6b, 0x74, 0xf5, 0x0b, 0x03, 0xb6, 0xe0, 0x88, 0xcf, 0x04, 0xee, 0xb6, 0xf8, 0x44, 0x83, 0x48, 0x28, + 0xc1, 0x0b, 0x73, 0x50, 0xe6, 0x98, 0xbf, 0x4a, 0x26, 0x3e, 0x4d, 0x26, 0x7e, 0x80, 0xb0, 0xac, 0x9a, 0x70, 0x77, + 0x41, 0x67, 0x23, 0xf8, 0x23, 0x9a, 0x98, 0x68, 0x8a, 0xa1, 0xf2, 0xd0, 0xa0, 0x29, 0xbe, 0xbb, 0x35, 0x22, 0x73, + 0x4f, 0x03, 0x44, 0x04, 0x0e, 0xe5, 0xdf, 0xaa, 0x58, 0x3d, 0xc8, 0xa0, 0x16, 0x38, 0xfa, 0xf8, 0xb3, 0x2f, 0xf4, + 0x67, 0x29, 0x64, 0x26, 0x02, 0x21, 0x8d, 0xd2, 0x6a, 0xa8, 0x2a, 0x34, 0x56, 0x3c, 0xbd, 0x3a, 0x90, 0xdf, 0x3c, + 0xb0, 0x31, 0x4a, 0x4d, 0xa7, 0x13, 0xd5, 0xf7, 0xd6, 0x36, 0x41, 0x35, 0xd2, 0xaf, 0xa0, 0x52, 0x82, 0x01, 0x6a, + 0x3f, 0xbc, 0x72, 0x60, 0x49, 0x2f, 0x29, 0xb4, 0x85, 0xee, 0x1b, 0xb1, 0xf3, 0x78, 0x28, 0x55, 0x98, 0x67, 0xc9, + 0xab, 0x52, 0x2d, 0x5a, 0x9a, 0xb0, 0xe3, 0x89, 0x38, 0x01, 0xbc, 0xa0, 0x06, 0x0f, 0xd3, 0xcc, 0xee, 0x3f, 0xe8, + 0xad, 0x23, 0x3e, 0xfe, 0x24, 0xeb, 0x21, 0xf8, 0xa5, 0x7f, 0x1b, 0x3e, 0xc0, 0x1f, 0x65, 0x7d, 0x70, 0x64, 0xbb, + 0x3e, 0x29, 0x80, 0x07, 0xd5, 0x2f, 0xb3, 0xa2, 0xf4, 0xdb, 0x04, 0x5d, 0xed, 0xdd, 0x55, 0x69, 0x4b, 0x05, 0xdd, + 0xdd, 0xa9, 0x14, 0x34, 0x3c, 0x1b, 0x12, 0x19, 0x94, 0x45, 0xd7, 0xdf, 0x31, 0xc4, 0xfe, 0x79, 0x0b, 0xff, 0xd6, + 0x04, 0xff, 0x43, 0x68, 0xa0, 0x24, 0xff, 0x6b, 0x68, 0xbe, 0x2d, 0x94, 0x0c, 0xf4, 0xfb, 0x81, 0xc4, 0xb2, 0x10, + 0xc9, 0xf5, 0x6d, 0xb0, 0xe2, 0xc0, 0x4c, 0x24, 0x63, 0xd8, 0x9e, 0x11, 0x5b, 0x13, 0xbb, 0x52, 0x46, 0x8e, 0x9e, + 0x43, 0x5f, 0x47, 0x7f, 0xc6, 0x7c, 0x55, 0x9d, 0x57, 0x93, 0x12, 0x2b, 0xa6, 0xc0, 0x7d, 0xdd, 0x38, 0x94, 0xeb, + 0x89, 0x3c, 0x6f, 0xfd, 0x1d, 0x94, 0xf5, 0x0c, 0x2d, 0x13, 0xc2, 0x5d, 0x43, 0x44, 0x30, 0xfa, 0xd4, 0x2a, 0x4d, + 0xf2, 0x6a, 0x54, 0x36, 0xe7, 0x07, 0xb3, 0x06, 0x7f, 0x97, 0xb2, 0xba, 0xe5, 0x23, 0xaf, 0xef, 0x62, 0xca, 0xc5, + 0x28, 0xce, 0xe9, 0x56, 0xb8, 0x02, 0xbd, 0x16, 0x78, 0xad, 0xa8, 0x44, 0x52, 0x82, 0x15, 0x03, 0x1b, 0x8b, 0xec, + 0x40, 0x26, 0x06, 0x9a, 0xdf, 0x1a, 0x37, 0xaf, 0xed, 0x8e, 0x44, 0x4e, 0x20, 0xfe, 0x16, 0x83, 0x2d, 0xe8, 0x63, + 0x83, 0xb4, 0x5d, 0xbb, 0x4b, 0xc8, 0x06, 0x43, 0x5c, 0xab, 0x1f, 0xd7, 0x32, 0x05, 0x90, 0x6d, 0x12, 0x5a, 0x8f, + 0x4b, 0x24, 0x74, 0x25, 0x9d, 0x4e, 0x59, 0xc4, 0xfd, 0x28, 0xa5, 0xfc, 0x2d, 0xc7, 0x10, 0x53, 0x5e, 0x87, 0x6d, + 0xbb, 0x25, 0xc8, 0x46, 0xe3, 0xd7, 0xc7, 0xe4, 0xee, 0x86, 0x42, 0xfd, 0xe5, 0xab, 0x7a, 0x2e, 0xf6, 0xa4, 0xdb, + 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, 0xe4, 0xc1, 0x8b, 0x54, 0x96, 0x50, 0xa4, 0xb2, + 0x58, 0x22, 0x01, 0x4e, 0xe4, 0x2e, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, 0xa5, 0x43, 0x11, 0x7a, 0x9c, 0x82, 0x97, 0x13, + 0xe3, 0xf7, 0xe9, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x59, 0x41, 0xca, 0xae, 0xe1, 0xa9, 0x0a, 0x54, 0x82, + 0x35, 0xc2, 0x54, 0x82, 0x90, 0x1c, 0x4a, 0xe7, 0x25, 0x2f, 0xb7, 0x2e, 0xe6, 0xa7, 0x53, 0x90, 0x93, 0x2a, 0xa9, + 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x49, 0x55, 0xdf, 0x0e, 0x6f, 0xfc, 0xce, 0xaa, 0xc0, + 0x5e, 0xea, 0x05, 0xcc, 0x49, 0x99, 0x6c, 0x1b, 0x39, 0x29, 0x46, 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, + 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x9b, 0xad, 0x5a, 0x4e, 0x0e, 0x28, 0xbf, 0x5c, 0xdc, 0xeb, 0x90, 0x00, 0xc3, 0x0a, + 0x02, 0x4c, 0xd2, 0x04, 0xb0, 0xe8, 0xe8, 0xdb, 0xde, 0x69, 0xab, 0xb4, 0x5d, 0x28, 0xc3, 0x0d, 0x29, 0xba, 0x18, + 0x93, 0xd4, 0xc2, 0xbf, 0x93, 0x4e, 0x7f, 0x37, 0x92, 0xc6, 0x25, 0x0a, 0x8f, 0x02, 0xa4, 0x07, 0x74, 0x46, 0x0b, + 0xce, 0x8f, 0xb3, 0xad, 0x0b, 0x76, 0xda, 0x8a, 0x66, 0x71, 0x15, 0x6b, 0x45, 0x53, 0x43, 0x4f, 0x99, 0x55, 0x33, + 0xe1, 0x63, 0xd4, 0x40, 0x92, 0x04, 0x77, 0x29, 0x03, 0xb9, 0x64, 0xa1, 0x03, 0x0b, 0x01, 0x85, 0x49, 0xae, 0xab, + 0x80, 0xaf, 0xd4, 0xb8, 0xa5, 0xdd, 0xff, 0xcb, 0x3f, 0xff, 0x6f, 0x19, 0xc3, 0x05, 0xaa, 0x74, 0xd4, 0x58, 0x0d, + 0x42, 0x97, 0xbb, 0x98, 0x02, 0x55, 0x9d, 0xf2, 0xb2, 0xcb, 0xd6, 0x59, 0x1e, 0x8f, 0x5a, 0x93, 0x28, 0x19, 0x03, + 0x60, 0x6b, 0x09, 0x64, 0x26, 0x48, 0x48, 0xa8, 0xeb, 0x45, 0xc8, 0x82, 0xbf, 0x29, 0x11, 0x5b, 0x25, 0xc0, 0xd3, + 0x6e, 0x35, 0xd3, 0xb2, 0xab, 0x0d, 0x55, 0x4b, 0xcd, 0x56, 0x3f, 0x5c, 0xa6, 0x84, 0x5a, 0x2d, 0x2f, 0x1b, 0x5a, + 0xea, 0xc3, 0xa8, 0x7f, 0xff, 0x97, 0x7f, 0xf8, 0x1f, 0xea, 0x15, 0xcf, 0x98, 0xfe, 0xf2, 0x4f, 0x7f, 0x87, 0x29, + 0xd0, 0x96, 0x3e, 0x87, 0x22, 0x39, 0x61, 0x55, 0x87, 0x50, 0x42, 0x60, 0x58, 0x95, 0xd3, 0x57, 0xcf, 0xdf, 0xde, + 0xa7, 0x09, 0x69, 0xb3, 0x49, 0xe8, 0x68, 0xd3, 0x96, 0x15, 0x8f, 0xd4, 0x48, 0x4e, 0xbc, 0x08, 0x95, 0x48, 0xef, + 0x3b, 0x25, 0x47, 0xf9, 0x7a, 0x35, 0x16, 0x2a, 0x42, 0x88, 0x25, 0x65, 0x55, 0x6e, 0x61, 0xe8, 0x7e, 0x81, 0xaf, + 0x41, 0xd7, 0x28, 0xa6, 0xc5, 0xab, 0xf5, 0xe9, 0xfd, 0x34, 0x07, 0xf8, 0xc7, 0x48, 0x71, 0x11, 0x87, 0xa4, 0x63, + 0xe9, 0x16, 0xda, 0x7c, 0xc9, 0x55, 0x49, 0xa3, 0x08, 0x47, 0xf1, 0xe1, 0x93, 0xbf, 0x29, 0xff, 0x38, 0x45, 0xcb, + 0xca, 0x72, 0xa6, 0xd1, 0xa5, 0x74, 0x1f, 0x1f, 0xb5, 0xdb, 0xb3, 0x4b, 0x77, 0x51, 0xcd, 0xe0, 0xad, 0x9b, 0x8c, + 0x62, 0x97, 0xe6, 0x80, 0x74, 0x9e, 0xad, 0xc3, 0xa4, 0xe0, 0x31, 0xb5, 0x31, 0xaa, 0x56, 0x96, 0x7f, 0x58, 0x50, + 0xa4, 0x2e, 0xfe, 0x05, 0xcf, 0x9d, 0x65, 0x50, 0x13, 0x4a, 0x0c, 0x2c, 0x16, 0x46, 0xaf, 0xae, 0xe8, 0x35, 0xe9, + 0x2c, 0xa7, 0x0d, 0x99, 0xe7, 0xe6, 0xe6, 0x89, 0xf7, 0x43, 0x3c, 0xc3, 0x9e, 0x74, 0xbc, 0x49, 0x77, 0xa1, 0x87, + 0xe7, 0x3c, 0x9b, 0x9a, 0x07, 0xe5, 0x2c, 0x62, 0x43, 0x36, 0x56, 0xc1, 0x60, 0x59, 0x2f, 0x0e, 0xc1, 0xcb, 0xc9, + 0xf6, 0x8a, 0xb9, 0x24, 0x48, 0x74, 0x40, 0x0e, 0xf0, 0x7c, 0x86, 0x1b, 0x10, 0xe8, 0x9f, 0x45, 0x3c, 0x20, 0x7e, + 0xed, 0x99, 0xc7, 0xed, 0x11, 0x4a, 0x99, 0x6c, 0x61, 0xc0, 0xd3, 0x13, 0x4d, 0x31, 0x2c, 0x5b, 0x4f, 0xdb, 0x2a, + 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0xa2, 0x3a, 0xdf, 0xca, 0x53, 0xec, 0xa7, 0xb5, 0x70, 0x88, 0x54, 0x31, 0x5d, 0xd7, + 0x5b, 0x59, 0x2f, 0x34, 0xb5, 0xa8, 0xfd, 0x16, 0x0c, 0x30, 0x02, 0xd3, 0x6e, 0xb6, 0xa2, 0x42, 0x6c, 0xf5, 0x34, + 0xfc, 0x56, 0xbb, 0x3e, 0xd1, 0x6c, 0x46, 0x0d, 0x5d, 0x60, 0x62, 0x32, 0x58, 0x51, 0x76, 0x50, 0x86, 0x86, 0x48, + 0x88, 0x90, 0x6d, 0xe4, 0x46, 0x10, 0x4f, 0x32, 0x55, 0x02, 0x7f, 0x72, 0xa2, 0xff, 0xff, 0x00, 0x69, 0x5b, 0x88, + 0x58, 0x18, 0x7f, 0x00, 0x00}; } // namespace web_server } // namespace esphome From 70de2f527824a5cd7d22b6627f7e15884a32723b Mon Sep 17 00:00:00 2001 From: esphomebot Date: Wed, 28 Jun 2023 10:19:36 +1200 Subject: [PATCH 0159/2607] Synchronise Device Classes from Home Assistant (#5018) --- esphome/components/button/__init__.py | 2 ++ esphome/const.py | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 55f2fe794a..a999c6d91e 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_MQTT_ID, DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ) @@ -24,6 +25,7 @@ IS_PLATFORM_COMPONENT = True DEVICE_CLASSES = [ DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ] diff --git a/esphome/const.py b/esphome/const.py index 48e62b9b86..3036d13801 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -968,6 +968,7 @@ DEVICE_CLASS_GAS = "gas" DEVICE_CLASS_GATE = "gate" DEVICE_CLASS_HEAT = "heat" DEVICE_CLASS_HUMIDITY = "humidity" +DEVICE_CLASS_IDENTIFY = "identify" DEVICE_CLASS_ILLUMINANCE = "illuminance" DEVICE_CLASS_IRRADIANCE = "irradiance" DEVICE_CLASS_LIGHT = "light" From 832ba38f1b0c58b7117a3a7c6db9c011a310592a Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Tue, 27 Jun 2023 20:13:14 -0300 Subject: [PATCH 0160/2607] Fixes compressed downloads (#5014) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/dashboard/dashboard.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 22bbe0aae9..dd800f534c 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -546,22 +546,11 @@ class DownloadBinaryRequestHandler(BaseHandler): return with open(path, "rb") as f: - while True: - # For a 528KB image used as benchmark: - # - using 256KB blocks resulted in the smallest file size. - # - blocks larger than 256KB didn't improve the size of compressed file. - # - blocks smaller than 256KB hindered compression, making the output file larger. + data = f.read() + if compressed: + data = gzip.compress(data, 9) + self.write(data) - # Read file in blocks of 256KB. - data = f.read(256 * 1024) - - if not data: - break - - if compressed: - data = gzip.compress(data, 9) - - self.write(data) self.finish() From abc8e903c11d479f1832296d1eac7cd6c1592ee3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:35:35 +1200 Subject: [PATCH 0161/2607] Add CONFIG_BT_BLE_42_FEATURES_SUPPORTED for ble (#5008) --- esphome/components/esp32_ble/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index f508cecb87..b4cb595da0 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -55,3 +55,4 @@ async def to_code(config): if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) + add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) From d34c074b92796c41ec6f10c9a7bccda3fdc95c5f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Jun 2023 12:35:16 +1200 Subject: [PATCH 0162/2607] Bump version to 2023.6.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 3036d13801..0d5b211c18 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.2" +__version__ = "2023.6.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 807621402daa2be70cf75f0b2a63d164dcb14aaa Mon Sep 17 00:00:00 2001 From: Ryan DeShone Date: Wed, 28 Jun 2023 19:42:39 -0400 Subject: [PATCH 0163/2607] [SCD30] Disable negative temperature offset (#4850) --- esphome/components/scd30/scd30.cpp | 19 ++++++++++++------- esphome/components/scd30/sensor.py | 5 ++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index 01abca0a1f..3eeca23800 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -42,13 +42,18 @@ void SCD30Component::setup() { ESP_LOGD(TAG, "SCD30 Firmware v%0d.%02d", (uint16_t(raw_firmware_version[0]) >> 8), uint16_t(raw_firmware_version[0] & 0xFF)); - if (this->temperature_offset_ != 0) { - if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t) (temperature_offset_ * 100.0))) { - ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); - this->error_code_ = MEASUREMENT_INIT_FAILED; - this->mark_failed(); - return; - } + uint16_t temp_offset; + if (this->temperature_offset_ > 0) { + temp_offset = (this->temperature_offset_ * 100); + } else { + temp_offset = 0; + } + + if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, temp_offset)) { + ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); + this->error_code_ = MEASUREMENT_INIT_FAILED; + this->mark_failed(); + return; } #ifdef USE_ESP32 // According ESP32 clock stretching is typically 30ms and up to 150ms "due to diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index 1ddf0f1e85..f72b43fd37 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -68,7 +68,10 @@ CONFIG_SCHEMA = ( cv.int_range(min=0, max=0xFFFF, max_included=False), ), cv.Optional(CONF_AMBIENT_PRESSURE_COMPENSATION, default=0): cv.pressure, - cv.Optional(CONF_TEMPERATURE_OFFSET): cv.temperature, + cv.Optional(CONF_TEMPERATURE_OFFSET): cv.All( + cv.temperature, + cv.float_range(min=0, max=655.35), + ), cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.All( cv.positive_time_period_seconds, cv.Range( From 0e93b8ee0da72eaf1af48244adff7d5dd441be3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:44:10 +1200 Subject: [PATCH 0164/2607] Bump esptool from 4.6 to 4.6.2 (#4949) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d4b96ada64..c6564d55e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile -esptool==4.6 +esptool==4.6.2 click==8.1.3 esphome-dashboard==20230621.0 aioesphomeapi==15.0.0 From c5eb3941b9d1367383038ef2bf30702a18d16c52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:44:23 +1200 Subject: [PATCH 0165/2607] Bump pytest-mock from 3.10.0 to 3.11.1 (#4977) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 23131fd64b..75f29ac8dd 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -7,7 +7,7 @@ pre-commit # Unit tests pytest==7.4.0 pytest-cov==4.1.0 -pytest-mock==3.10.0 +pytest-mock==3.11.1 pytest-asyncio==0.21.0 asyncmock==0.4.2 hypothesis==5.49.0 From cf98c497d5618384e771742e794becae0fd41e95 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 3 Jul 2023 02:35:53 +0400 Subject: [PATCH 0166/2607] binary_sensor removed unused filter (#5039) --- esphome/components/binary_sensor/filter.cpp | 9 --------- esphome/components/binary_sensor/filter.h | 8 -------- 2 files changed, 17 deletions(-) diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index 53c2daf42d..836c341574 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -114,15 +114,6 @@ LambdaFilter::LambdaFilter(std::function(bool)> f) : f_(std::move optional LambdaFilter::new_value(bool value, bool is_initial) { return this->f_(value); } -optional UniqueFilter::new_value(bool value, bool is_initial) { - if (this->last_value_.has_value() && *this->last_value_ == value) { - return {}; - } else { - this->last_value_ = value; - return value; - } -} - } // namespace binary_sensor } // namespace esphome diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index 64a33f6e34..0f0ab6875f 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -105,14 +105,6 @@ class LambdaFilter : public Filter { std::function(bool)> f_; }; -class UniqueFilter : public Filter { - public: - optional new_value(bool value, bool is_initial) override; - - protected: - optional last_value_{}; -}; - } // namespace binary_sensor } // namespace esphome From 099dc8d1d2f44f81d55f70d4f64bebc5b0948546 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Tue, 4 Jul 2023 04:18:51 +0400 Subject: [PATCH 0167/2607] fix template binary_sensor publish_initial_state option (#5033) --- .../binary_sensor/template_binary_sensor.cpp | 16 +++++++++++++--- .../binary_sensor/template_binary_sensor.h | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.cpp b/esphome/components/template/binary_sensor/template_binary_sensor.cpp index 66ff4be4c4..fce11f63d6 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.cpp +++ b/esphome/components/template/binary_sensor/template_binary_sensor.cpp @@ -6,11 +6,21 @@ namespace template_ { static const char *const TAG = "template.binary_sensor"; -void TemplateBinarySensor::loop() { - if (!this->f_.has_value()) +void TemplateBinarySensor::setup() { + if (!this->publish_initial_state_) return; - auto s = (*this->f_)(); + if (this->f_ != nullptr) { + this->publish_initial_state(*this->f_()); + } else { + this->publish_initial_state(false); + } +} +void TemplateBinarySensor::loop() { + if (this->f_ == nullptr) + return; + + auto s = this->f_(); if (s.has_value()) { this->publish_state(*s); } diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.h b/esphome/components/template/binary_sensor/template_binary_sensor.h index a28929b122..5e5624d82e 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.h +++ b/esphome/components/template/binary_sensor/template_binary_sensor.h @@ -10,13 +10,14 @@ class TemplateBinarySensor : public Component, public binary_sensor::BinarySenso public: void set_template(std::function()> &&f) { this->f_ = f; } + void setup() override; void loop() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::HARDWARE; } protected: - optional()>> f_{}; + std::function()> f_{nullptr}; }; } // namespace template_ From 5b2176562bf3b1e86fee1cdc274d4f1ba7d8f89e Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Tue, 4 Jul 2023 04:25:48 +0400 Subject: [PATCH 0168/2607] binary_sensor filters templatable delays (#5029) --- esphome/components/binary_sensor/__init__.py | 76 ++++++++++++++------ esphome/components/binary_sensor/filter.cpp | 11 ++- esphome/components/binary_sensor/filter.h | 21 +++--- tests/test1.yaml | 7 ++ 4 files changed, 79 insertions(+), 36 deletions(-) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index f4a5c95b12..41b4c5a0d7 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -95,6 +95,14 @@ DEVICE_CLASSES = [ IS_PLATFORM_COMPONENT = True +CONF_TIME_OFF = "time_off" +CONF_TIME_ON = "time_on" + +DEFAULT_DELAY = "1s" +DEFAULT_TIME_OFF = "100ms" +DEFAULT_TIME_ON = "900ms" + + binary_sensor_ns = cg.esphome_ns.namespace("binary_sensor") BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.EntityBase) BinarySensorInitiallyOff = binary_sensor_ns.class_( @@ -138,47 +146,75 @@ FILTER_REGISTRY = Registry() validate_filters = cv.validate_registry("filter", FILTER_REGISTRY) -@FILTER_REGISTRY.register("invert", InvertFilter, {}) +def register_filter(name, filter_type, schema): + return FILTER_REGISTRY.register(name, filter_type, schema) + + +@register_filter("invert", InvertFilter, {}) async def invert_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id) -@FILTER_REGISTRY.register( - "delayed_on_off", DelayedOnOffFilter, cv.positive_time_period_milliseconds +@register_filter( + "delayed_on_off", + DelayedOnOffFilter, + cv.Any( + cv.templatable(cv.positive_time_period_milliseconds), + cv.Schema( + { + cv.Required(CONF_TIME_ON): cv.templatable( + cv.positive_time_period_milliseconds + ), + cv.Required(CONF_TIME_OFF): cv.templatable( + cv.positive_time_period_milliseconds + ), + } + ), + msg="'delayed_on_off' filter requires either a delay time to be used for both " + "turn-on and turn-off delays, or two parameters 'time_on' and 'time_off' if " + "different delay times are required.", + ), ) async def delayed_on_off_filter_to_code(config, filter_id): - var = cg.new_Pvariable(filter_id, config) + var = cg.new_Pvariable(filter_id) await cg.register_component(var, {}) + if isinstance(config, dict): + template_ = await cg.templatable(config[CONF_TIME_ON], [], cg.uint32) + cg.add(var.set_on_delay(template_)) + template_ = await cg.templatable(config[CONF_TIME_OFF], [], cg.uint32) + cg.add(var.set_off_delay(template_)) + else: + template_ = await cg.templatable(config, [], cg.uint32) + cg.add(var.set_on_delay(template_)) + cg.add(var.set_off_delay(template_)) return var -@FILTER_REGISTRY.register( - "delayed_on", DelayedOnFilter, cv.positive_time_period_milliseconds +@register_filter( + "delayed_on", DelayedOnFilter, cv.templatable(cv.positive_time_period_milliseconds) ) async def delayed_on_filter_to_code(config, filter_id): - var = cg.new_Pvariable(filter_id, config) + var = cg.new_Pvariable(filter_id) await cg.register_component(var, {}) + template_ = await cg.templatable(config, [], cg.uint32) + cg.add(var.set_delay(template_)) return var -@FILTER_REGISTRY.register( - "delayed_off", DelayedOffFilter, cv.positive_time_period_milliseconds +@register_filter( + "delayed_off", + DelayedOffFilter, + cv.templatable(cv.positive_time_period_milliseconds), ) async def delayed_off_filter_to_code(config, filter_id): - var = cg.new_Pvariable(filter_id, config) + var = cg.new_Pvariable(filter_id) await cg.register_component(var, {}) + template_ = await cg.templatable(config, [], cg.uint32) + cg.add(var.set_delay(template_)) return var -CONF_TIME_OFF = "time_off" -CONF_TIME_ON = "time_on" - -DEFAULT_DELAY = "1s" -DEFAULT_TIME_OFF = "100ms" -DEFAULT_TIME_ON = "900ms" - - -@FILTER_REGISTRY.register( +@register_filter( "autorepeat", AutorepeatFilter, cv.All( @@ -215,7 +251,7 @@ async def autorepeat_filter_to_code(config, filter_id): return var -@FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) +@register_filter("lambda", LambdaFilter, cv.returning_lambda) async def lambda_filter_to_code(config, filter_id): lambda_ = await cg.process_lambda( config, [(bool, "x")], return_type=cg.optional.template(bool) diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index 836c341574..46957383c3 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -26,22 +26,20 @@ void Filter::input(bool value, bool is_initial) { } } -DelayedOnOffFilter::DelayedOnOffFilter(uint32_t delay) : delay_(delay) {} optional DelayedOnOffFilter::new_value(bool value, bool is_initial) { if (value) { - this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(true, is_initial); }); + this->set_timeout("ON_OFF", this->on_delay_.value(), [this, is_initial]() { this->output(true, is_initial); }); } else { - this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(false, is_initial); }); + this->set_timeout("ON_OFF", this->off_delay_.value(), [this, is_initial]() { this->output(false, is_initial); }); } return {}; } float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -DelayedOnFilter::DelayedOnFilter(uint32_t delay) : delay_(delay) {} optional DelayedOnFilter::new_value(bool value, bool is_initial) { if (value) { - this->set_timeout("ON", this->delay_, [this, is_initial]() { this->output(true, is_initial); }); + this->set_timeout("ON", this->delay_.value(), [this, is_initial]() { this->output(true, is_initial); }); return {}; } else { this->cancel_timeout("ON"); @@ -51,10 +49,9 @@ optional DelayedOnFilter::new_value(bool value, bool is_initial) { float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -DelayedOffFilter::DelayedOffFilter(uint32_t delay) : delay_(delay) {} optional DelayedOffFilter::new_value(bool value, bool is_initial) { if (!value) { - this->set_timeout("OFF", this->delay_, [this, is_initial]() { this->output(false, is_initial); }); + this->set_timeout("OFF", this->delay_.value(), [this, is_initial]() { this->output(false, is_initial); }); return {}; } else { this->cancel_timeout("OFF"); diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index 0f0ab6875f..9514cb3fe2 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -1,5 +1,6 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" @@ -29,38 +30,40 @@ class Filter { class DelayedOnOffFilter : public Filter, public Component { public: - explicit DelayedOnOffFilter(uint32_t delay); - optional new_value(bool value, bool is_initial) override; float get_setup_priority() const override; + template void set_on_delay(T delay) { this->on_delay_ = delay; } + template void set_off_delay(T delay) { this->off_delay_ = delay; } + protected: - uint32_t delay_; + TemplatableValue on_delay_{}; + TemplatableValue off_delay_{}; }; class DelayedOnFilter : public Filter, public Component { public: - explicit DelayedOnFilter(uint32_t delay); - optional new_value(bool value, bool is_initial) override; float get_setup_priority() const override; + template void set_delay(T delay) { this->delay_ = delay; } + protected: - uint32_t delay_; + TemplatableValue delay_{}; }; class DelayedOffFilter : public Filter, public Component { public: - explicit DelayedOffFilter(uint32_t delay); - optional new_value(bool value, bool is_initial) override; float get_setup_priority() const override; + template void set_delay(T delay) { this->delay_ = delay; } + protected: - uint32_t delay_; + TemplatableValue delay_{}; }; class InvertFilter : public Filter { diff --git a/tests/test1.yaml b/tests/test1.yaml index f8928430f4..05ba07d1d8 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1355,8 +1355,15 @@ binary_sensor: device_class: window filters: - invert: + - delayed_on_off: 40ms + - delayed_on_off: + time_on: 10s + time_off: !lambda "return 1000;" - delayed_on: 40ms - delayed_off: 40ms + - delayed_on_off: !lambda "return 10;" + - delayed_on: !lambda "return 1000;" + - delayed_off: !lambda "return 0;" on_press: then: - lambda: >- From 4cc0f3fd535d9a51916d234982d8bd23b9d54e52 Mon Sep 17 00:00:00 2001 From: Graham Brown Date: Tue, 4 Jul 2023 02:28:19 +0200 Subject: [PATCH 0169/2607] Add alarm to reserved ids (#5042) --- esphome/config_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 0a6b2dfbb0..cf0b1d3aca 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -108,6 +108,7 @@ ROOT_CONFIG_PATH = object() RESERVED_IDS = [ # C++ keywords http://en.cppreference.com/w/cpp/keyword + "alarm", "alignas", "alignof", "and", From 63d3a0e8b3196c752ba6d16e6e57c15304a80893 Mon Sep 17 00:00:00 2001 From: guillempages Date: Tue, 4 Jul 2023 02:43:03 +0200 Subject: [PATCH 0170/2607] Improve the gamma settings for the S3-Box-lite display (#5046) --- esphome/components/ili9xxx/ili9xxx_init.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index a17e6b127c..15fbf92659 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -218,12 +218,12 @@ static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control 0xF2, 1, 0x00, // 3Gamma Function Disable ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected - ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, - 0x0E, 0x09, 0x00, - ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, - 0x31, 0x36, 0x0F, + ILI9XXX_GMCTRP1 , 14, 0xF0, 0x09, 0x0B, 0x06, 0x04, 0x15, // Set Gamma + 0x2F, 0x54, 0x42, 0x3C, 0x17, 0x14, + 0x18, 0x1B, + ILI9XXX_GMCTRN1 , 14, 0xE0, 0x09, 0x0B, 0x06, 0x04, 0x03, // Set Gamma + 0x2B, 0x43, 0x42, 0x3B, 0x16, 0x14, + 0x17, 0x1B, ILI9XXX_SLPOUT , 0x80, // Exit Sleep ILI9XXX_DISPON , 0x80, // Display on 0x00 // End of list From 25b9bde0a59f2fd4016b9ed56b30fbd633c0f8d2 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 4 Jul 2023 02:48:05 +0200 Subject: [PATCH 0171/2607] Prepare ethernet to work with esp idf 5.0 (#5037) --- .../components/ethernet/esp_eth_phy_jl1101.c | 16 ++++++++++++++ .../ethernet/ethernet_component.cpp | 21 +++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/esphome/components/ethernet/esp_eth_phy_jl1101.c b/esphome/components/ethernet/esp_eth_phy_jl1101.c index 6011795033..de2a6f4f35 100644 --- a/esphome/components/ethernet/esp_eth_phy_jl1101.c +++ b/esphome/components/ethernet/esp_eth_phy_jl1101.c @@ -19,7 +19,11 @@ #include #include "esp_log.h" #include "esp_eth.h" +#if ESP_IDF_VERSION_MAJOR >= 5 +#include "esp_eth_phy_802_3.h" +#else #include "eth_phy_regs_struct.h" +#endif #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" @@ -170,7 +174,11 @@ static esp_err_t jl1101_reset_hw(esp_eth_phy_t *phy) { return ESP_OK; } +#if ESP_IDF_VERSION_MAJOR >= 5 +static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *nego_state) { +#else static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy) { +#endif phy_jl1101_t *jl1101 = __containerof(phy, phy_jl1101_t, parent); esp_eth_mediator_t *eth = jl1101->eth; /* in case any link status has changed, let's assume we're in link down status */ @@ -285,7 +293,11 @@ static esp_err_t jl1101_init(esp_eth_phy_t *phy) { esp_eth_mediator_t *eth = jl1101->eth; // Detect PHY address if (jl1101->addr == ESP_ETH_PHY_ADDR_AUTO) { +#if ESP_IDF_VERSION_MAJOR >= 5 + PHY_CHECK(esp_eth_phy_802_3_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); +#else PHY_CHECK(esp_eth_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); +#endif } /* Power on Ethernet PHY */ PHY_CHECK(jl1101_pwrctl(phy, true) == ESP_OK, "power control failed", err); @@ -324,7 +336,11 @@ esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config) { jl1101->parent.init = jl1101_init; jl1101->parent.deinit = jl1101_deinit; jl1101->parent.set_mediator = jl1101_set_mediator; +#if ESP_IDF_VERSION_MAJOR >= 5 + jl1101->parent.autonego_ctrl = jl1101_negotiate; +#else jl1101->parent.negotiate = jl1101_negotiate; +#endif jl1101->parent.get_link = jl1101_get_link; jl1101->parent.pwrctl = jl1101_pwrctl; jl1101->parent.get_addr = jl1101_get_addr; diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 0487ea5498..fc1068f2a8 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -41,18 +41,27 @@ void EthernetComponent::setup() { this->eth_netif_ = esp_netif_new(&cfg); // Init MAC and PHY configs to default - eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); - phy_config.phy_addr = this->phy_addr_; phy_config.reset_gpio_num = this->power_pin_; + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); +#if ESP_IDF_VERSION_MAJOR >= 5 + eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); + esp32_emac_config.smi_mdc_gpio_num = this->mdc_pin_; + esp32_emac_config.smi_mdio_gpio_num = this->mdio_pin_; + esp32_emac_config.clock_config.rmii.clock_mode = this->clk_mode_; + esp32_emac_config.clock_config.rmii.clock_gpio = this->clk_gpio_; + + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); +#else mac_config.smi_mdc_gpio_num = this->mdc_pin_; mac_config.smi_mdio_gpio_num = this->mdio_pin_; mac_config.clock_config.rmii.clock_mode = this->clk_mode_; mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); +#endif switch (this->type_) { case ETHERNET_TYPE_LAN8720: { @@ -76,7 +85,11 @@ void EthernetComponent::setup() { break; } case ETHERNET_TYPE_KSZ8081: { +#if ESP_IDF_VERSION_MAJOR >= 5 + this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); +#else this->phy_ = esp_eth_phy_new_ksz8081(&phy_config); +#endif break; } default: { @@ -221,13 +234,13 @@ void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base return; } - ESP_LOGV(TAG, "[Ethernet event] %s (num=%d)", event_name, event); + ESP_LOGV(TAG, "[Ethernet event] %s (num=%" PRId32 ")", event_name, event); } void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { global_eth_component->connected_ = true; - ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%d)", event_id); + ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%" PRId32 ")", event_id); } void EthernetComponent::start_connect_() { From 87c0f48095a37a8f7edd5e762460bb47ff2fa4bf Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 4 Jul 2023 02:49:27 +0200 Subject: [PATCH 0172/2607] Prepare debug and logger component to work with idf 5.0 (#5036) --- esphome/components/debug/debug_component.cpp | 6 ++++-- esphome/core/scheduler.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 9843fa1c99..9b7e256147 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -5,6 +5,7 @@ #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/version.h" +#include #ifdef USE_ESP32 @@ -13,6 +14,7 @@ #if ESP_IDF_VERSION_MAJOR >= 4 #include +#include #else #include #endif @@ -61,7 +63,7 @@ void DebugComponent::dump_config() { device_info += ESPHOME_VERSION; this->free_heap_ = get_free_heap(); - ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); + ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); #ifdef USE_ARDUINO const char *flash_mode; @@ -289,7 +291,7 @@ void DebugComponent::loop() { uint32_t new_free_heap = get_free_heap(); if (new_free_heap < this->free_heap_ / 2) { this->free_heap_ = new_free_heap; - ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); + ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); this->status_momentary_warning("heap", 1000); } diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index 7c76c8490b..ab60f83ba5 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -29,7 +29,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u if (timeout == SCHEDULER_DONT_RUN) return; - ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout); + ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%" PRIu32 ")", name.c_str(), timeout); auto item = make_unique(); item->component = component; @@ -60,7 +60,7 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name, if (interval != 0) offset = (random_uint32() % interval) / 2; - ESP_LOGVV(TAG, "set_interval(name='%s', interval=%u, offset=%u)", name.c_str(), interval, offset); + ESP_LOGVV(TAG, "set_interval(name='%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", name.c_str(), interval, offset); auto item = make_unique(); item->component = component; @@ -108,8 +108,8 @@ void HOT Scheduler::set_retry(Component *component, const std::string &name, uin if (initial_wait_time == SCHEDULER_DONT_RUN) return; - ESP_LOGVV(TAG, "set_retry(name='%s', initial_wait_time=%u, max_attempts=%u, backoff_factor=%0.1f)", name.c_str(), - initial_wait_time, max_attempts, backoff_increase_factor); + ESP_LOGVV(TAG, "set_retry(name='%s', initial_wait_time=%" PRIu32 ", max_attempts=%u, backoff_factor=%0.1f)", + name.c_str(), initial_wait_time, max_attempts, backoff_increase_factor); if (backoff_increase_factor < 0.0001) { ESP_LOGE(TAG, @@ -222,8 +222,8 @@ void HOT Scheduler::call() { } #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE - ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", item->get_type_str(), - item->name.c_str(), item->interval, item->last_execution, now); + ESP_LOGVV(TAG, "Running %s '%s' with interval=%" PRIu32 " last_execution=%" PRIu32 " (now=%" PRIu32 ")", + item->get_type_str(), item->name.c_str(), item->interval, item->last_execution, now); #endif // Warning: During callback(), a lot of stuff can happen, including: From 2e2ac5307158a775092969b7e3d1658b17a530f7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 3 Jul 2023 19:52:42 -0500 Subject: [PATCH 0173/2607] Advertise noise is enabled (#5034) --- esphome/components/mdns/mdns_component.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index cdb9aa8e74..581758cf2d 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -57,6 +57,10 @@ void MDNSComponent::compile_records_() { service.txt_records.push_back({"network", "ethernet"}); #endif +#ifdef USE_API_NOISE + service.txt_records.push_back({"api_encryption", "Noise_NNpsk0_25519_ChaChaPoly_SHA256"}); +#endif + #ifdef ESPHOME_PROJECT_NAME service.txt_records.push_back({"project_name", ESPHOME_PROJECT_NAME}); service.txt_records.push_back({"project_version", ESPHOME_PROJECT_VERSION}); From e74ab00b3e116fd05fdbc280b8b4e06e4176214b Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 4 Jul 2023 02:55:04 +0200 Subject: [PATCH 0174/2607] Mopeka std fixes (#5041) Co-authored-by: Your Name --- .../mopeka_std_check/mopeka_std_check.cpp | 32 +++++++++---------- tests/test2.yaml | 13 ++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.cpp b/esphome/components/mopeka_std_check/mopeka_std_check.cpp index ae7b646b9d..67e749c68b 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.cpp +++ b/esphome/components/mopeka_std_check/mopeka_std_check.cpp @@ -54,16 +54,16 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) const auto &manu_datas = device.get_manufacturer_datas(); if (manu_datas.size() != 1) { - ESP_LOGE(TAG, "%s: Unexpected manu_datas size (%d)", device.address_str().c_str(), manu_datas.size()); + ESP_LOGE(TAG, "[%s] Unexpected manu_datas size (%d)", device.address_str().c_str(), manu_datas.size()); return false; } const auto &manu_data = manu_datas[0]; - ESP_LOGVV(TAG, "%s: Manufacturer data: %s", device.address_str().c_str(), format_hex_pretty(manu_data.data).c_str()); + ESP_LOGVV(TAG, "[%s] Manufacturer data: %s", device.address_str().c_str(), format_hex_pretty(manu_data.data).c_str()); if (manu_data.data.size() != MANUFACTURER_DATA_LENGTH) { - ESP_LOGE(TAG, "%s: Unexpected manu_data size (%d)", device.address_str().c_str(), manu_data.data.size()); + ESP_LOGE(TAG, "[%s] Unexpected manu_data size (%d)", device.address_str().c_str(), manu_data.data.size()); return false; } @@ -72,20 +72,20 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) const u_int8_t hardware_id = mopeka_data->data_1 & 0xCF; if (static_cast(hardware_id) != STANDARD && static_cast(hardware_id) != XL) { - ESP_LOGE(TAG, "%s: Unsupported Sensor Type (0x%X)", device.address_str().c_str(), hardware_id); + ESP_LOGE(TAG, "[%s] Unsupported Sensor Type (0x%X)", device.address_str().c_str(), hardware_id); return false; } - ESP_LOGVV(TAG, "%s: Sensor slow update rate: %d", device.address_str().c_str(), mopeka_data->slow_update_rate); - ESP_LOGVV(TAG, "%s: Sensor sync pressed: %d", device.address_str().c_str(), mopeka_data->sync_pressed); + ESP_LOGVV(TAG, "[%s] Sensor slow update rate: %d", device.address_str().c_str(), mopeka_data->slow_update_rate); + ESP_LOGVV(TAG, "[%s] Sensor sync pressed: %d", device.address_str().c_str(), mopeka_data->sync_pressed); for (u_int8_t i = 0; i < 3; i++) { - ESP_LOGVV(TAG, "%s: %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 1, + ESP_LOGVV(TAG, "[%s] %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 1, mopeka_data->val[i].value_0, mopeka_data->val[i].time_0); - ESP_LOGVV(TAG, "%s: %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 2, + ESP_LOGVV(TAG, "[%s] %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 2, mopeka_data->val[i].value_1, mopeka_data->val[i].time_1); - ESP_LOGVV(TAG, "%s: %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 3, + ESP_LOGVV(TAG, "[%s] %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 3, mopeka_data->val[i].value_2, mopeka_data->val[i].time_2); - ESP_LOGVV(TAG, "%s: %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 4, + ESP_LOGVV(TAG, "[%s] %u. Sensor data %u time %u.", device.address_str().c_str(), (i * 4) + 4, mopeka_data->val[i].value_3, mopeka_data->val[i].time_3); } @@ -146,19 +146,19 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) // This value is better than a previous one. best_value = measurements_value[i]; best_time = measurement_time; - // Reset measurement_time or next values. - measurement_time = 0; } + // Reset measurement_time or next values. + measurement_time = 0; } } } - ESP_LOGV(TAG, "%s: Found %u values with best data %u time %u.", device.address_str().c_str(), + ESP_LOGV(TAG, "[%s] Found %u values with best data %u time %u.", device.address_str().c_str(), number_of_usable_values, best_value, best_time); - if (number_of_usable_values < 2 || best_value < 2 || best_time < 2) { + if (number_of_usable_values < 1 || best_value < 2 || best_time < 2) { // At least two measurement values must be present. - ESP_LOGW(TAG, "%s: Poor read quality. Setting distance to 0.", device.address_str().c_str()); + ESP_LOGW(TAG, "[%s] Poor read quality. Setting distance to 0.", device.address_str().c_str()); if (this->distance_ != nullptr) { this->distance_->publish_state(0); } @@ -167,7 +167,7 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) } } else { float lpg_speed_of_sound = this->get_lpg_speed_of_sound_(temp_in_c); - ESP_LOGV(TAG, "%s: Speed of sound in current fluid %f m/s", device.address_str().c_str(), lpg_speed_of_sound); + ESP_LOGV(TAG, "[%s] Speed of sound in current fluid %f m/s", device.address_str().c_str(), lpg_speed_of_sound); uint32_t distance_value = lpg_speed_of_sound * best_time / 100.0f; diff --git a/tests/test2.yaml b/tests/test2.yaml index aa3e467816..675fae6cf3 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -397,6 +397,19 @@ sensor: name: MICS-4514 C2H5OH ammonia: name: MICS-4514 NH3 + - platform: mopeka_std_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level time: - platform: homeassistant From a74abb8ea84d2ba2ad32ef7443abba737a6268c7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 3 Jul 2023 19:57:44 -0500 Subject: [PATCH 0175/2607] Adjust signature for on_disconnect (#5009) --- esphome/components/api/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/api/client.py b/esphome/components/api/client.py index c777c3be9d..819055ccf4 100644 --- a/esphome/components/api/client.py +++ b/esphome/components/api/client.py @@ -47,7 +47,7 @@ async def async_run_logs(config, address): except APIConnectionError: cli.disconnect() - async def on_disconnect(): + async def on_disconnect(expected_disconnect: bool) -> None: _LOGGER.warning("Disconnected from API") zc = zeroconf.Zeroconf() From d64d1650e39a8bc5b2555a26ede2f0b07a965000 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Jul 2023 13:45:06 +1200 Subject: [PATCH 0176/2607] Update webserver to ea86d81 (#5023) --- esphome/components/web_server/server_index.h | 1185 +++++++++--------- 1 file changed, 594 insertions(+), 591 deletions(-) diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 2dbb839c5e..180dffab67 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,597 +6,600 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xdb, 0x76, 0xe3, 0x46, 0x92, 0xe0, 0xf3, - 0x9e, 0xb3, 0x7f, 0xb0, 0x2f, 0x28, 0x58, 0x53, 0x05, 0xb4, 0x40, 0x88, 0xa4, 0x4a, 0x55, 0x65, 0x50, 0x20, 0x5b, - 0x75, 0xb1, 0xab, 0xec, 0xba, 0xb9, 0xa4, 0xb2, 0xdb, 0x96, 0xd5, 0x12, 0x44, 0x26, 0x45, 0xb8, 0x40, 0x80, 0x06, - 0x92, 0xba, 0x98, 0xc2, 0x9c, 0x79, 0x9a, 0xa7, 0x39, 0x67, 0x6f, 0xf3, 0x30, 0x0f, 0x3b, 0x67, 0xe6, 0x61, 0x3f, - 0x62, 0x9f, 0xe7, 0x53, 0xfa, 0x07, 0x76, 0x3e, 0x61, 0x23, 0x22, 0x2f, 0x48, 0x80, 0xa4, 0x24, 0x7b, 0xdc, 0x7b, - 0xdc, 0xd5, 0x02, 0xf2, 0x1a, 0x11, 0x19, 0x19, 0xb7, 0x8c, 0x04, 0x77, 0xef, 0x8d, 0xb2, 0x21, 0xbf, 0x9a, 0x31, - 0x6b, 0xc2, 0xa7, 0x49, 0x7f, 0x57, 0xfe, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, - 0x78, 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, - 0x53, 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, - 0xc7, 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, - 0xfe, 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, - 0xc4, 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, - 0x8b, 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, - 0x4f, 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, - 0x69, 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf7, 0x98, 0x17, 0xbb, 0x61, 0x9f, 0x59, 0x71, 0x6a, 0xf1, 0xc1, 0x0b, 0x46, - 0x25, 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, - 0x7c, 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xf0, 0x43, 0x76, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, - 0x8c, 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbb, 0xbe, 0x76, 0x58, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, - 0x51, 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xec, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, - 0x99, 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xe6, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, - 0xe9, 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, - 0x28, 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, - 0x0c, 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, - 0xc0, 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, - 0x90, 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, - 0xbe, 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, - 0x58, 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, - 0xc6, 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdd, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, - 0xb3, 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, - 0x05, 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, - 0x41, 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xbc, - 0x04, 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0xe0, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, - 0x9c, 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0xa2, 0xd1, 0xd6, 0xe3, 0x84, 0x78, 0x8d, 0x44, 0xae, - 0xc7, 0x7d, 0x49, 0xbe, 0xfd, 0xab, 0x74, 0x58, 0x1f, 0x1b, 0x2a, 0x4b, 0x9e, 0xed, 0xf3, 0x3c, 0x4e, 0xcf, 0x00, - 0x08, 0xc5, 0x06, 0x46, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x3c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, - 0x7a, 0xd8, 0x00, 0x08, 0x90, 0x1e, 0x18, 0x8c, 0x0f, 0x78, 0xc0, 0x37, 0x6d, 0xdb, 0xfb, 0xce, 0xf5, 0xae, 0x90, - 0x83, 0x7c, 0xdf, 0x27, 0xf6, 0x15, 0x9d, 0xe3, 0xb0, 0x83, 0x40, 0xfb, 0x09, 0x4b, 0xcf, 0xf8, 0x64, 0xc0, 0x0f, - 0xdb, 0x47, 0x01, 0x03, 0xa8, 0x46, 0xf3, 0x21, 0x73, 0x90, 0x1f, 0xbd, 0x1c, 0xb7, 0xcf, 0xa6, 0x03, 0x53, 0xe0, - 0xc2, 0xdc, 0x23, 0x1c, 0x6b, 0x4b, 0xe3, 0x2a, 0xd8, 0x14, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, - 0x70, 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, - 0x37, 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0xe4, 0x87, 0xf9, 0x66, 0xe7, 0xc8, - 0x43, 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0xb8, 0xbf, 0xcc, - 0xc7, 0x21, 0xf3, 0xa7, 0xd1, 0x0c, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, - 0x2b, 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, - 0x39, 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, - 0x9b, 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, - 0x73, 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, - 0xd5, 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, - 0xc0, 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x85, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, - 0x19, 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xb2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, - 0xd0, 0x1f, 0x08, 0xc1, 0x7b, 0x28, 0xb8, 0xbe, 0x92, 0x52, 0x27, 0x62, 0x0a, 0x43, 0x20, 0xc0, 0x10, 0x25, 0x88, - 0xa4, 0xc1, 0xfb, 0x2c, 0xb9, 0x1a, 0xc7, 0x49, 0xb2, 0x3f, 0x9f, 0xcd, 0xb2, 0x9c, 0x7b, 0x5f, 0x87, 0x0b, 0x9e, - 0x55, 0xb8, 0xd2, 0x26, 0x2f, 0x2e, 0x62, 0x8e, 0x04, 0x75, 0x17, 0xc3, 0x08, 0x96, 0xfa, 0x69, 0x96, 0x25, 0x2c, - 0x4a, 0x01, 0x0d, 0x3e, 0xb0, 0xed, 0x20, 0x9d, 0x27, 0x49, 0xef, 0x14, 0x86, 0xfd, 0xd4, 0xa3, 0x6a, 0x21, 0xf1, - 0x03, 0x7a, 0xde, 0xcb, 0xf3, 0xe8, 0x0a, 0x1a, 0x62, 0x1b, 0x60, 0x2f, 0x58, 0xad, 0xaf, 0xf6, 0xdf, 0xbd, 0xf5, - 0x05, 0xe3, 0xc7, 0xe3, 0x2b, 0x00, 0xb4, 0xac, 0xa4, 0xe6, 0x38, 0xcf, 0xa6, 0x8d, 0xa9, 0x91, 0x0e, 0x71, 0xc8, - 0x7b, 0x6b, 0x40, 0x88, 0x69, 0x64, 0x58, 0x25, 0x6e, 0x42, 0xf0, 0x96, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, - 0x43, 0x20, 0x8a, 0x61, 0xca, 0x5b, 0xa0, 0xcd, 0xaf, 0x16, 0x71, 0x48, 0x70, 0xce, 0x50, 0xff, 0x22, 0x8c, 0xc3, - 0x08, 0x66, 0x5f, 0x88, 0x01, 0x4b, 0x05, 0x71, 0x5c, 0x96, 0xde, 0x44, 0x33, 0x31, 0x4a, 0x3c, 0x14, 0x28, 0x2c, - 0x0c, 0x41, 0xc1, 0x70, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x45, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, - 0x02, 0x35, 0xd9, 0x39, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x50, 0x7f, 0xe3, 0x04, 0xa1, 0xb8, 0xd7, 0xf1, 0x40, 0x83, - 0x3e, 0x9b, 0x44, 0xe9, 0x19, 0x1b, 0x05, 0x13, 0x56, 0x4a, 0xc9, 0xbb, 0x67, 0xc1, 0x1a, 0x03, 0x3b, 0x15, 0xd6, - 0xcb, 0x83, 0x37, 0xaf, 0xe5, 0xca, 0xd5, 0x84, 0x31, 0x2c, 0xd2, 0x1c, 0xd4, 0x2a, 0x88, 0x6d, 0x29, 0x8e, 0x5f, - 0x70, 0x25, 0xbd, 0x45, 0x49, 0x5c, 0x7c, 0x9c, 0x81, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, - 0x39, 0xcc, 0x27, 0x2a, 0x46, 0xba, 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x6b, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x87, - 0x56, 0x34, 0x1a, 0xbd, 0x4a, 0x63, 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x81, 0x3c, 0xc6, 0x7a, 0x72, 0x11, - 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, 0xc8, 0xde, 0x23, 0x62, 0x08, 0x69, 0x99, 0x84, 0x87, 0x47, 0x12, 0xbc, 0xc4, - 0x9f, 0xcd, 0x8b, 0x09, 0x12, 0x56, 0x0e, 0x8c, 0x82, 0x3c, 0x3b, 0x2d, 0x58, 0x7e, 0xce, 0x46, 0x9a, 0x03, 0x0a, - 0xc0, 0x8a, 0x9a, 0x83, 0xf1, 0x42, 0x33, 0x3a, 0x4a, 0x87, 0x72, 0x18, 0xaa, 0x67, 0x8a, 0x59, 0x26, 0x99, 0x59, - 0x5b, 0x38, 0x5a, 0x0a, 0x38, 0xc2, 0xa8, 0x90, 0x92, 0x20, 0x0f, 0x15, 0x86, 0x13, 0x90, 0x42, 0xcc, 0xad, 0x6d, - 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, 0xca, - 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x0d, 0xe9, 0x42, 0x50, 0x26, 0xd0, 0x82, 0x21, 0x1b, - 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0xef, 0x1e, 0xf3, - 0xd3, 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, - 0x67, 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, - 0xcb, 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, - 0x5d, 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, - 0x85, 0x4d, 0x41, 0x80, 0x1e, 0xf2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, - 0xac, 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, - 0x2b, 0x90, 0x93, 0x6f, 0x66, 0x27, 0xb2, 0x27, 0xdc, 0xeb, 0xeb, 0x6f, 0xd4, 0x20, 0xd5, 0x52, 0x6a, 0x1b, 0xa8, - 0xb1, 0x26, 0xb6, 0x6a, 0x32, 0xb2, 0x5d, 0xa9, 0x50, 0xef, 0x75, 0x7a, 0x35, 0x3e, 0x80, 0x3d, 0xd7, 0xd6, 0x2c, - 0x5d, 0x19, 0xdb, 0xef, 0x15, 0x4d, 0xdf, 0x89, 0x91, 0xc9, 0x1a, 0xe5, 0xb7, 0x73, 0x8f, 0xda, 0xf1, 0xd0, 0x76, - 0xa9, 0xae, 0x12, 0x0c, 0xf3, 0xba, 0x60, 0x68, 0x42, 0x3d, 0xd3, 0x5d, 0x6c, 0xcd, 0x54, 0x3c, 0x54, 0x6b, 0xad, - 0x1c, 0x08, 0x16, 0x1e, 0x82, 0x71, 0xb2, 0xd2, 0x3f, 0x78, 0x1b, 0x4d, 0x19, 0x52, 0xd4, 0x5b, 0xd7, 0x40, 0x3a, - 0x10, 0xd0, 0xe4, 0xa8, 0xa9, 0xde, 0x98, 0x2b, 0xac, 0xa6, 0xfa, 0xfe, 0x8a, 0xc1, 0x8a, 0x00, 0xfb, 0xba, 0x5c, - 0xb1, 0x44, 0xa4, 0x37, 0x05, 0x97, 0x68, 0xfa, 0x88, 0x32, 0xb1, 0x26, 0xa4, 0xe0, 0x01, 0x79, 0x58, 0xfe, 0xc6, - 0xc2, 0xa9, 0x56, 0x0a, 0x47, 0x86, 0x32, 0x05, 0xe8, 0x4c, 0x4a, 0x00, 0xc4, 0x25, 0xfd, 0xad, 0x6d, 0x2c, 0x24, - 0xdb, 0x3e, 0xf2, 0x81, 0x3f, 0x4e, 0x22, 0xee, 0x74, 0xb6, 0xda, 0x2e, 0xf0, 0x21, 0x08, 0x71, 0xd0, 0x11, 0x60, - 0xde, 0x57, 0xa8, 0x70, 0xf2, 0x16, 0x5c, 0xe6, 0x83, 0x51, 0x34, 0x89, 0xc7, 0xdc, 0x49, 0x50, 0x89, 0xb8, 0x25, - 0x4b, 0x40, 0xc9, 0xe8, 0x7d, 0x05, 0xca, 0x82, 0x09, 0xe9, 0x22, 0xaa, 0x95, 0x40, 0x63, 0x0a, 0x52, 0x92, 0x52, - 0xa4, 0x05, 0x15, 0x04, 0x86, 0x50, 0xe9, 0x29, 0x8e, 0x02, 0xfd, 0x16, 0x0f, 0xc4, 0xa0, 0xc1, 0x92, 0x45, 0x19, - 0x0f, 0xe2, 0xe5, 0x42, 0x50, 0xc3, 0x3e, 0xcf, 0x5e, 0x67, 0x17, 0x2c, 0x7f, 0x16, 0x21, 0xec, 0x81, 0xe8, 0x5e, - 0x82, 0xa4, 0x27, 0x81, 0xce, 0x7b, 0x8a, 0x57, 0xce, 0x09, 0x69, 0x58, 0x88, 0x69, 0x8c, 0x8a, 0x10, 0xec, 0x16, - 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xae, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, - 0xe2, 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, - 0xe9, 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0x08, 0xc4, 0x96, 0x70, 0x4b, 0x50, 0x46, 0x68, 0x78, 0xe5, 0x59, 0x92, 0x18, - 0xba, 0xc8, 0x8b, 0x7b, 0x4e, 0x43, 0x1d, 0x01, 0x14, 0xd3, 0x9a, 0x46, 0x1a, 0xb0, 0x40, 0x57, 0xa0, 0x52, 0x52, - 0xda, 0xc8, 0xab, 0xd6, 0x46, 0x40, 0x9c, 0x8e, 0x58, 0x2e, 0x1c, 0x34, 0xa9, 0x43, 0x61, 0xc2, 0x14, 0x18, 0x9a, - 0x8d, 0x40, 0xc2, 0x2b, 0x04, 0xc0, 0x3c, 0xf1, 0x27, 0x59, 0xc1, 0x75, 0x9d, 0x09, 0x7d, 0x7c, 0x7d, 0x1d, 0x0b, - 0x7f, 0x11, 0x19, 0x20, 0x67, 0xd3, 0xec, 0x9c, 0xad, 0x80, 0xba, 0xa7, 0x06, 0x33, 0x41, 0x36, 0x86, 0x01, 0x25, - 0x0a, 0xaa, 0x65, 0x96, 0xc4, 0x60, 0xe9, 0xeb, 0x06, 0x3e, 0x18, 0x74, 0xec, 0x12, 0x65, 0x84, 0xdb, 0xef, 0xf7, - 0xdb, 0x5e, 0xc7, 0x2d, 0x05, 0xc1, 0x17, 0x4b, 0x14, 0xbd, 0x41, 0x3f, 0x4a, 0x13, 0x7c, 0x95, 0x2c, 0x60, 0xae, - 0xa1, 0x14, 0x39, 0xe9, 0x26, 0xe6, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, - 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, - 0xd9, 0xf4, 0x58, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, - 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0x60, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, - 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xde, 0x6b, 0xb2, 0x81, 0xd3, 0x28, 0x09, 0x0d, 0x71, 0x65, 0xe2, 0xad, 0x24, 0x74, - 0x6d, 0xa3, 0x80, 0x43, 0xb6, 0xc4, 0xf6, 0xcd, 0x85, 0x6e, 0x72, 0xbb, 0x64, 0x0f, 0xe5, 0x3f, 0x55, 0x5c, 0xb2, - 0x9e, 0xe5, 0x98, 0x92, 0x06, 0x4c, 0x31, 0x1e, 0x2c, 0x4d, 0x03, 0x12, 0xe0, 0xbb, 0x72, 0x14, 0x17, 0xeb, 0x49, - 0xf0, 0xbb, 0x82, 0xf9, 0xdc, 0x98, 0xe9, 0x56, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, - 0xd4, 0x7c, 0x8d, 0x86, 0x0a, 0x71, 0xfc, 0x99, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, - 0x2c, 0x5a, 0xa4, 0x4c, 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, - 0xdc, 0x34, 0xd4, 0xc2, 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, - 0xfb, 0x86, 0x0f, 0x65, 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, - 0x74, 0x41, 0xa0, 0x48, 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, - 0x4a, 0x33, 0x2f, 0x75, 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x31, 0x41, 0x99, 0xd8, 0xbb, 0x89, 0x36, 0x5e, 0x1a, - 0x66, 0xc2, 0xfa, 0x15, 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, - 0xb0, 0xa7, 0x00, 0x94, 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x11, 0x1d, 0x2b, 0x11, 0x5a, - 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, - 0x25, 0x83, 0x84, 0x1c, 0xd2, 0x65, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x1e, 0x85, 0x11, 0x8a, - 0x0d, 0xb1, 0x16, 0x4b, 0x84, 0x6c, 0xda, 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0xe6, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, - 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x9e, 0x00, 0x3f, 0x48, - 0x83, 0x17, 0xd6, 0x6c, 0xa0, 0x64, 0xef, 0xde, 0x6b, 0x6c, 0x45, 0xf6, 0x67, 0x55, 0x52, 0x79, 0x0a, 0x35, 0xce, - 0xad, 0xaf, 0x53, 0x2d, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, - 0x76, 0x5d, 0x37, 0xc8, 0xc9, 0x79, 0xb9, 0xb7, 0xca, 0x85, 0xbc, 0x7f, 0xdf, 0xf4, 0x99, 0xce, 0xf5, 0xf0, 0xcf, - 0x1c, 0x54, 0xce, 0xc5, 0x55, 0x4a, 0x16, 0xcc, 0x33, 0xa5, 0x8e, 0x96, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, - 0x22, 0x8a, 0xb9, 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, - 0xda, 0xa2, 0xc5, 0x70, 0xc2, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x43, 0xbc, 0xe5, 0xc0, 0xab, 0x61, - 0x2f, 0x9b, 0xdd, 0x6b, 0xe6, 0x3f, 0xac, 0x11, 0xc8, 0xb6, 0xa9, 0xaa, 0x2b, 0x1b, 0xef, 0x52, 0x44, 0x62, 0x84, - 0x6d, 0xd5, 0xd8, 0xd2, 0xd6, 0xef, 0x35, 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x86, 0x1e, 0x56, 0x6e, 0x0e, - 0x37, 0x1d, 0x79, 0xb1, 0x82, 0x6e, 0x4f, 0x04, 0x85, 0xc0, 0x89, 0x50, 0xf6, 0xa0, 0xe6, 0x06, 0x22, 0x25, 0x53, - 0x5a, 0x35, 0x9b, 0x27, 0x23, 0x09, 0x2c, 0xb8, 0xb0, 0x4c, 0xf2, 0xd1, 0x45, 0x9c, 0x24, 0x55, 0xe9, 0xef, 0x2a, - 0xe0, 0xc5, 0xb0, 0xb7, 0x89, 0x76, 0x81, 0xd1, 0x5c, 0x81, 0xe0, 0x6a, 0x23, 0xec, 0xa3, 0xe3, 0x56, 0xeb, 0x2e, - 0x22, 0x8e, 0xcc, 0x8c, 0x46, 0x7c, 0x44, 0x1b, 0xb2, 0x64, 0x9a, 0xb5, 0xf7, 0x5e, 0x60, 0x48, 0xcd, 0xc0, 0x07, - 0xd5, 0x19, 0x15, 0xff, 0x2a, 0x7b, 0xea, 0x57, 0xa2, 0x77, 0xab, 0xea, 0x6a, 0x06, 0x54, 0x54, 0xe0, 0xc3, 0x0c, - 0xb1, 0xb4, 0x55, 0x20, 0x20, 0xd7, 0xc3, 0x3a, 0xdc, 0xad, 0x91, 0x06, 0x0b, 0x4a, 0x81, 0xb5, 0x56, 0x76, 0xaf, - 0x6f, 0x0b, 0xe6, 0x50, 0x28, 0x5c, 0xf4, 0x7f, 0x96, 0x4d, 0x67, 0x68, 0x99, 0x35, 0x98, 0x1a, 0x1a, 0x7c, 0x6c, - 0xd4, 0x97, 0x2b, 0xca, 0x6a, 0x7d, 0x68, 0x47, 0xd6, 0xf8, 0x49, 0x3b, 0xca, 0xe0, 0x50, 0xcd, 0x75, 0x51, 0xdd, - 0x6e, 0x6e, 0x8a, 0x98, 0x55, 0x3c, 0xee, 0x93, 0xde, 0xd6, 0xd6, 0xa4, 0xa7, 0x69, 0x40, 0x32, 0x49, 0x32, 0xbc, - 0xc9, 0x00, 0x65, 0x45, 0x9c, 0x45, 0xd9, 0x20, 0xdf, 0xa2, 0x2c, 0x71, 0xfd, 0x7e, 0xe8, 0xed, 0xd5, 0x3c, 0x6b, - 0x6f, 0x6f, 0xbd, 0x8b, 0x5c, 0xd5, 0x49, 0x0f, 0xf2, 0xf0, 0x08, 0x8a, 0x96, 0x6c, 0xca, 0x70, 0x31, 0xcd, 0x46, - 0x2c, 0xb0, 0xa1, 0x7b, 0x6a, 0x97, 0x72, 0xd3, 0x44, 0xc0, 0x3d, 0x11, 0x73, 0x16, 0x1f, 0xea, 0x91, 0xd4, 0x60, - 0x0f, 0x58, 0x40, 0x9b, 0x0b, 0x5f, 0x85, 0x67, 0x49, 0x76, 0x1a, 0x25, 0x07, 0x42, 0x81, 0xd7, 0x5a, 0x7e, 0x0b, - 0x2e, 0x23, 0x59, 0xac, 0x86, 0x92, 0xfa, 0x6a, 0xf0, 0x55, 0x70, 0x7b, 0x8f, 0xca, 0x5b, 0xb1, 0x3b, 0x7e, 0xdb, - 0xef, 0xd8, 0x2a, 0x22, 0xf6, 0x93, 0x39, 0x1d, 0x68, 0x9c, 0x02, 0x28, 0x73, 0x00, 0x9a, 0xac, 0xf0, 0x86, 0x2c, - 0xfc, 0x69, 0xf0, 0x93, 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, - 0x88, 0x0a, 0x8c, 0x2b, 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0x77, 0x1c, 0x9e, 0x40, 0xb3, 0x8d, 0x8d, 0x85, 0xf3, - 0x26, 0xe2, 0x13, 0x3f, 0x8f, 0xd2, 0x51, 0x36, 0x75, 0xdc, 0x4d, 0xdb, 0x76, 0xfd, 0x82, 0x3c, 0x91, 0xcf, 0xdd, - 0x72, 0xe3, 0x04, 0xfc, 0x80, 0xd0, 0x1e, 0xd8, 0x9b, 0xc7, 0xde, 0x01, 0x0b, 0x4f, 0x76, 0x37, 0x16, 0x23, 0x56, - 0xf6, 0x4f, 0xbc, 0x4b, 0x1d, 0x73, 0xf7, 0xde, 0xa3, 0x94, 0x81, 0x5e, 0x61, 0xff, 0x52, 0x82, 0x01, 0xec, 0x46, - 0xf1, 0x77, 0x90, 0x72, 0x1f, 0xe9, 0x40, 0x44, 0xc6, 0x69, 0xaf, 0xaf, 0xed, 0x8c, 0x22, 0x06, 0xf6, 0x3d, 0xed, - 0xac, 0xde, 0xbf, 0x5f, 0xa9, 0xf9, 0xaa, 0xd4, 0x9b, 0xb3, 0xb0, 0xe6, 0xa9, 0x7b, 0x2f, 0xe9, 0x68, 0xa5, 0xbe, - 0x91, 0xe7, 0x8c, 0x94, 0xe6, 0xb2, 0x9d, 0xe0, 0x18, 0x5b, 0x7c, 0xf5, 0xb6, 0x3e, 0x14, 0x51, 0x0a, 0x3f, 0x06, - 0xeb, 0x25, 0x02, 0xf5, 0x0d, 0x0e, 0x8e, 0x77, 0x10, 0x6e, 0xed, 0x3a, 0x83, 0xc0, 0xb9, 0xd7, 0x6a, 0x5d, 0xff, - 0xb8, 0x75, 0xf8, 0xe7, 0xa8, 0xf5, 0xcb, 0x5e, 0xeb, 0x87, 0x23, 0xf7, 0xda, 0xf9, 0x71, 0x6b, 0x70, 0x28, 0xdf, - 0x0e, 0xff, 0xdc, 0xff, 0xb1, 0x38, 0xfa, 0x83, 0x28, 0xdc, 0x70, 0xdd, 0xad, 0x33, 0x6f, 0xc6, 0xc2, 0xad, 0x56, - 0xab, 0x0f, 0x4f, 0x67, 0xf0, 0x84, 0x7f, 0x2f, 0xe0, 0xcf, 0xf5, 0xa1, 0xf5, 0x9f, 0x7e, 0x4c, 0xff, 0xf3, 0x8f, - 0xf9, 0x11, 0x8e, 0x79, 0xf8, 0xe7, 0x1f, 0x0b, 0xfb, 0x41, 0x3f, 0xdc, 0x3a, 0xda, 0x74, 0x1d, 0x5d, 0xf3, 0x87, - 0xb0, 0x7a, 0x84, 0x56, 0x87, 0x7f, 0x96, 0x6f, 0xf6, 0x83, 0x93, 0xdd, 0x7e, 0x78, 0x74, 0xed, 0xd8, 0xd7, 0x0f, - 0xdc, 0x6b, 0xd7, 0xbd, 0xde, 0xc0, 0x79, 0xce, 0x61, 0xf4, 0x07, 0xf0, 0x77, 0x0c, 0x7f, 0x6d, 0xf8, 0x3b, 0x85, - 0xbf, 0x7f, 0x86, 0x6e, 0x22, 0xfe, 0x76, 0x4d, 0xb1, 0x90, 0x6b, 0x3c, 0xb0, 0x88, 0x60, 0x15, 0xdc, 0x8d, 0xad, - 0xd8, 0xdb, 0x20, 0xa2, 0xc1, 0x3e, 0xf4, 0x7d, 0x1f, 0xc3, 0xa4, 0xce, 0xe2, 0x78, 0x03, 0x16, 0x1d, 0x39, 0x67, - 0x23, 0xe0, 0x9e, 0x88, 0x1c, 0x14, 0x01, 0x13, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xc3, 0x70, 0x83, 0x39, 0x60, - 0x14, 0xbc, 0x65, 0xf8, 0xd0, 0x75, 0xbd, 0x17, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, - 0xed, 0x7a, 0xb3, 0x15, 0x95, 0xb0, 0xad, 0xd3, 0x33, 0xa8, 0x3b, 0x15, 0x27, 0x8c, 0xdf, 0xb1, 0xe8, 0x13, 0x6e, - 0xc9, 0x37, 0xc6, 0x21, 0xf0, 0x92, 0x25, 0xdf, 0x34, 0x1a, 0x0d, 0x1b, 0x51, 0xb8, 0x63, 0x4f, 0x19, 0xcc, 0xb0, - 0x64, 0x22, 0x32, 0x52, 0x9a, 0xc2, 0xb2, 0x85, 0xc9, 0xdf, 0x47, 0x39, 0xdf, 0xa8, 0x0c, 0xdb, 0xb0, 0x66, 0xc9, - 0x36, 0x2d, 0xfd, 0x3b, 0x4c, 0x81, 0xa6, 0x25, 0x9d, 0x7f, 0x98, 0xe3, 0x87, 0x29, 0xa1, 0xf5, 0xd6, 0x61, 0xe0, - 0xa1, 0x17, 0x20, 0x77, 0x44, 0x3f, 0xe7, 0x3d, 0xaa, 0x31, 0xf8, 0x9f, 0x0c, 0x33, 0x78, 0x62, 0x3e, 0x0c, 0xd1, - 0x2c, 0x4a, 0x1d, 0xdc, 0x4a, 0x51, 0xdc, 0xbf, 0xc2, 0x9d, 0x91, 0x96, 0xde, 0x7e, 0xa8, 0x76, 0xcc, 0x41, 0xce, - 0xd8, 0x77, 0x51, 0xf2, 0x89, 0xe5, 0xce, 0xa5, 0xd7, 0xe9, 0x7e, 0x4e, 0x9d, 0x3d, 0xb4, 0xcd, 0x3e, 0x54, 0xc7, - 0x68, 0xda, 0x2c, 0x90, 0x47, 0x84, 0xad, 0x8e, 0x97, 0x63, 0x54, 0x0b, 0x49, 0x50, 0x78, 0x59, 0xd8, 0x25, 0x0e, - 0xb7, 0x77, 0x8b, 0xf3, 0xb3, 0xbe, 0x1d, 0xd8, 0x36, 0x58, 0xfc, 0x07, 0x14, 0xb6, 0x12, 0x86, 0x45, 0xbb, 0xc7, - 0x76, 0xe3, 0x1e, 0xdb, 0xdc, 0xac, 0x02, 0x4e, 0x78, 0x90, 0x4e, 0xdd, 0x13, 0x2f, 0xf2, 0x26, 0x21, 0x0c, 0x38, - 0x84, 0x66, 0xd8, 0xa5, 0x37, 0xdc, 0x8d, 0xe5, 0x34, 0x18, 0x0b, 0xf1, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, - 0x0e, 0xd1, 0xd8, 0xf7, 0xd9, 0x25, 0x1b, 0x2a, 0x3b, 0x03, 0x08, 0x15, 0xb9, 0x3d, 0x77, 0x18, 0x1a, 0xcd, 0x60, - 0xee, 0x30, 0x3c, 0x18, 0xd8, 0xb0, 0x97, 0x60, 0x57, 0x86, 0xd1, 0x61, 0xe7, 0x68, 0x90, 0x86, 0x33, 0x16, 0x68, - 0xda, 0xca, 0xa2, 0xb3, 0x5a, 0x51, 0xf7, 0x68, 0xe0, 0x4c, 0x99, 0xcf, 0xc1, 0x16, 0x77, 0xf0, 0x0d, 0x23, 0x14, - 0x45, 0xf8, 0x81, 0x9d, 0xbd, 0xb8, 0x9c, 0x39, 0xf6, 0xee, 0x96, 0xbd, 0x89, 0xa5, 0x9e, 0x0d, 0xec, 0x05, 0x73, - 0x87, 0x17, 0xae, 0xd9, 0x79, 0xfb, 0x08, 0x41, 0xc5, 0x42, 0x9c, 0xfc, 0x62, 0x60, 0xf7, 0xc5, 0xd4, 0x6d, 0x18, - 0x34, 0x95, 0xcb, 0x8f, 0x2b, 0x7a, 0x40, 0xa8, 0xaa, 0xae, 0x0a, 0x3a, 0x28, 0xeb, 0x06, 0xce, 0xc4, 0x44, 0xa2, - 0x85, 0x93, 0x49, 0x2a, 0x80, 0xc3, 0x83, 0xcd, 0x60, 0x52, 0xa3, 0xdb, 0xf6, 0xd1, 0xe0, 0x22, 0x78, 0x60, 0x3f, - 0x50, 0x2f, 0x63, 0x40, 0x86, 0x89, 0xe9, 0xc7, 0xa0, 0x45, 0xf0, 0xef, 0x39, 0x03, 0x24, 0x2f, 0xa8, 0x68, 0x26, - 0x8b, 0xce, 0xb0, 0xe8, 0x20, 0x40, 0x50, 0xbd, 0x42, 0x5b, 0x7f, 0x62, 0x4d, 0x46, 0x21, 0xc1, 0x0e, 0xb6, 0xd0, - 0x21, 0xdb, 0xec, 0x1c, 0xe1, 0x79, 0x43, 0xce, 0x8b, 0xef, 0x62, 0x0e, 0x2a, 0x61, 0xab, 0x6f, 0xbb, 0x03, 0xdb, - 0xc2, 0xa5, 0xed, 0x65, 0x9b, 0xa1, 0xa0, 0x70, 0xbc, 0x79, 0xc0, 0x82, 0x49, 0x3f, 0x6c, 0x0f, 0x9c, 0x5c, 0x86, - 0x1b, 0xf1, 0xdc, 0x52, 0x48, 0xf0, 0xb6, 0x37, 0x01, 0x81, 0x8e, 0x9c, 0xbb, 0x61, 0x6f, 0xaa, 0x42, 0x28, 0x3a, - 0xde, 0x1c, 0xb9, 0x41, 0x0c, 0x7f, 0x9c, 0x16, 0x32, 0xcd, 0x44, 0xf7, 0x55, 0x9a, 0x19, 0x90, 0x18, 0x29, 0x8b, - 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, 0xb1, - 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, 0x47, - 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf7, 0x0c, 0x09, 0xc5, 0x4a, 0xed, 0x86, 0x09, 0x73, - 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, 0xbd, - 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, 0xe1, - 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, 0x02, - 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x31, 0xe9, 0xda, 0xa3, - 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, 0xbf, - 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, 0x60, - 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, 0x46, - 0xe0, 0x19, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, - 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, 0xdc, - 0x82, 0x18, 0x87, 0x19, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, 0x8a, - 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, 0x52, - 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, 0x36, - 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x19, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, 0xf4, - 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, 0xa2, - 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xbb, 0xf9, 0x52, 0xcc, 0x86, 0xb9, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, 0xd1, - 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x8b, 0xf4, 0x64, 0xfd, 0x36, 0xd8, 0xe0, - 0xb5, 0xbc, 0x03, 0xb4, 0xef, 0xd8, 0x74, 0xc6, 0xaf, 0xf6, 0x49, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0xb7, - 0x7b, 0xf1, 0x2e, 0xeb, 0xc5, 0x20, 0xd5, 0x73, 0xc5, 0x62, 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, - 0xab, 0xa1, 0xd7, 0x95, 0xe8, 0x6d, 0x6e, 0x02, 0x82, 0x3d, 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, - 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, 0x11, 0x73, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, - 0xb0, 0x03, 0x98, 0x11, 0x97, 0xb7, 0x3a, 0x22, 0x3a, 0x2c, 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0x37, 0x3b, 0x2e, - 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, 0xd6, 0x54, 0x2a, 0x8b, 0xcd, 0xcd, 0xb2, 0x7e, 0x54, - 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0xb2, 0x99, 0x0d, 0xc2, 0x81, 0x88, 0x09, 0x14, 0x68, 0x69, 0x65, 0xc5, 0x00, - 0x43, 0xca, 0x72, 0x94, 0x4f, 0x21, 0xf7, 0xe2, 0xb2, 0xd4, 0xa9, 0x2f, 0xcf, 0x64, 0xd0, 0x11, 0x4f, 0x3d, 0xc9, - 0x58, 0x01, 0x05, 0xeb, 0xa5, 0x5e, 0x42, 0x4b, 0x04, 0x98, 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, - 0x2c, 0x51, 0xc6, 0x67, 0x11, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, 0x62, 0x5f, 0x85, 0x32, 0x3a, 0x8a, 0xc3, 0xfc, 0x28, - 0xa0, 0xfa, 0xb9, 0x94, 0x60, 0x93, 0xf0, 0x23, 0xb0, 0x51, 0xe5, 0x78, 0x92, 0x20, 0x7c, 0x1e, 0xe7, 0x8c, 0x3c, - 0x85, 0x0d, 0x09, 0xb3, 0x34, 0x6d, 0x23, 0xd5, 0x2e, 0x32, 0x83, 0x50, 0x2e, 0xcc, 0x3f, 0x31, 0xce, 0x2e, 0xb2, - 0x70, 0xa9, 0x35, 0x98, 0x1f, 0xef, 0x4c, 0x80, 0xb2, 0xeb, 0xeb, 0x4c, 0xf8, 0xb8, 0x11, 0xd9, 0x1b, 0xba, 0x62, - 0x32, 0x50, 0x48, 0x05, 0x4e, 0x44, 0x16, 0x0f, 0x9d, 0xa1, 0xd0, 0x08, 0x07, 0x74, 0x8a, 0x9c, 0xbb, 0xc6, 0xa6, - 0xcf, 0x07, 0xda, 0x37, 0x4a, 0x43, 0x27, 0x01, 0x21, 0x20, 0x70, 0x37, 0xac, 0xa9, 0x74, 0x90, 0x06, 0x09, 0x95, - 0xa2, 0x9f, 0x03, 0xf8, 0x87, 0x91, 0xa4, 0x00, 0xd8, 0x0f, 0xd5, 0x48, 0x11, 0x65, 0x59, 0xe0, 0x02, 0xd0, 0x5c, - 0xfb, 0xb8, 0x12, 0xbe, 0x30, 0x50, 0x61, 0x7a, 0x9a, 0x95, 0x95, 0x42, 0x89, 0x3c, 0x5d, 0x91, 0xb2, 0x46, 0x32, - 0xf9, 0x1c, 0x1d, 0x3e, 0xe5, 0x5d, 0xbf, 0x95, 0x78, 0xe8, 0x82, 0xe7, 0xb0, 0xac, 0xea, 0xf9, 0x4d, 0xc8, 0xc8, - 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xf7, 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, - 0x0c, 0xcb, 0xcb, 0x59, 0x15, 0xa6, 0x20, 0xe0, 0x16, 0x2c, 0x09, 0x16, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, - 0x0a, 0xf2, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0x99, 0xd4, 0x04, - 0x4c, 0xb9, 0x3f, 0x04, 0x3f, 0xb5, 0x79, 0xd2, 0x75, 0xe9, 0xfa, 0xf1, 0x14, 0x53, 0x7b, 0x08, 0xf4, 0xd8, 0xbb, - 0x07, 0xa6, 0x44, 0x5d, 0x87, 0x15, 0xc4, 0xa1, 0x59, 0x4d, 0xb3, 0x80, 0x19, 0xd3, 0x06, 0x2d, 0xd9, 0x06, 0x5b, - 0x2e, 0x07, 0xfb, 0x48, 0x6c, 0xcf, 0x6a, 0x05, 0x84, 0xae, 0x41, 0x03, 0x43, 0xee, 0x52, 0xa1, 0x85, 0x59, 0xaf, - 0x4b, 0x45, 0xb8, 0x3f, 0x07, 0x4c, 0x5a, 0xc1, 0x99, 0x97, 0xd1, 0xc0, 0xfb, 0xf1, 0x69, 0x82, 0x89, 0x2f, 0x88, - 0x15, 0xd8, 0xc1, 0x41, 0xa7, 0xd9, 0x14, 0x38, 0x15, 0x17, 0x29, 0x83, 0x65, 0x45, 0xa9, 0x0d, 0x7f, 0xa4, 0xc8, - 0xd6, 0x5d, 0x1e, 0xe9, 0x2e, 0xc4, 0x02, 0xd8, 0xe9, 0x17, 0x8c, 0x7c, 0xcb, 0x7a, 0x19, 0x30, 0x38, 0xd7, 0x1a, - 0x07, 0x81, 0xdf, 0xdc, 0x4c, 0x8e, 0xca, 0x94, 0xd8, 0xae, 0xc9, 0xea, 0x02, 0x72, 0x4c, 0x02, 0x6c, 0xe0, 0x0e, - 0xc2, 0x52, 0xd9, 0xe3, 0x45, 0x39, 0xc5, 0xe5, 0x52, 0x16, 0x72, 0x33, 0x1d, 0x8b, 0xe6, 0x73, 0x2b, 0xcd, 0xa6, - 0xe3, 0xad, 0xf8, 0xa2, 0xe0, 0x1f, 0x38, 0xb1, 0xb4, 0xea, 0x29, 0xb5, 0xc2, 0xa3, 0xcc, 0x2d, 0x59, 0xa7, 0xa4, - 0x56, 0xd7, 0x0d, 0x54, 0x23, 0x3c, 0x4d, 0xc3, 0x46, 0x20, 0xc4, 0x04, 0x17, 0xbf, 0x6d, 0x32, 0x31, 0xed, 0x2d, - 0x21, 0x75, 0x84, 0xdd, 0x43, 0x39, 0xc1, 0x5d, 0xcd, 0xb3, 0x2f, 0xc3, 0xd9, 0x7a, 0xe6, 0xde, 0x33, 0x98, 0xfb, - 0x69, 0xc8, 0x0c, 0x46, 0x8f, 0x65, 0xc2, 0x8f, 0x8c, 0x7d, 0xe4, 0xaa, 0xea, 0xd9, 0x59, 0x58, 0x89, 0x2c, 0xf1, - 0x64, 0x1c, 0x75, 0x18, 0xa7, 0xa2, 0x35, 0x41, 0x76, 0x7d, 0x5d, 0x98, 0x7b, 0x81, 0x82, 0xa6, 0x1e, 0xab, 0xc7, - 0x69, 0x2b, 0x76, 0x36, 0x22, 0x91, 0x7b, 0x6f, 0x6a, 0x91, 0xc8, 0x8a, 0xcf, 0x71, 0xa4, 0x35, 0x07, 0xb9, 0xcf, - 0xce, 0x96, 0x37, 0xa9, 0xd0, 0x2d, 0x1a, 0x6d, 0x63, 0x8f, 0xea, 0x03, 0x49, 0x3d, 0xa3, 0x02, 0xab, 0x1a, 0xfb, - 0xfe, 0xfd, 0x8e, 0x48, 0xb7, 0x54, 0x8a, 0x0d, 0x43, 0x5a, 0x21, 0x33, 0x46, 0xc1, 0xa0, 0xa4, 0xc8, 0x40, 0x8d, - 0xf2, 0x35, 0x82, 0x61, 0x8f, 0x1a, 0x80, 0xe2, 0x5c, 0x5d, 0xfd, 0xb4, 0x94, 0x6c, 0x21, 0x20, 0x01, 0xd9, 0x84, - 0x62, 0x8d, 0x98, 0x19, 0xf9, 0xe4, 0x23, 0x70, 0xde, 0x80, 0xa3, 0x63, 0x00, 0x7e, 0x81, 0xd8, 0xf4, 0x60, 0x62, - 0xdb, 0x44, 0x14, 0x7d, 0x36, 0xf0, 0x12, 0x80, 0x9d, 0x55, 0xa1, 0xd1, 0x0f, 0x55, 0x0a, 0x18, 0xb2, 0x81, 0x1b, - 0xf0, 0x2a, 0x2c, 0xb7, 0xf7, 0x12, 0xda, 0xc1, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xd8, 0x9d, 0x5f, - 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x25, 0x23, 0x18, 0xf1, 0xfd, - 0x0d, 0x65, 0x1d, 0xaa, 0x71, 0xcb, 0x3d, 0x8d, 0x16, 0x61, 0xba, 0x4c, 0x1a, 0x83, 0x92, 0x75, 0x3f, 0x19, 0x71, - 0x2f, 0xf7, 0x45, 0x2c, 0xb8, 0xc2, 0xd1, 0x08, 0x9b, 0x37, 0x90, 0xa4, 0xa7, 0x3d, 0x3a, 0x60, 0xdf, 0x68, 0xf6, - 0x02, 0xca, 0x7c, 0xac, 0x48, 0x25, 0x21, 0xa5, 0xd9, 0x0d, 0x91, 0x24, 0xac, 0x15, 0x79, 0xea, 0xbc, 0xef, 0x68, - 0x9f, 0x5b, 0x49, 0x04, 0x23, 0x38, 0x89, 0xd3, 0x95, 0x07, 0x4d, 0x01, 0xae, 0xa2, 0x23, 0xa6, 0x6f, 0x82, 0xf2, - 0x1b, 0xe4, 0xf6, 0x52, 0x72, 0x6d, 0xae, 0x61, 0x78, 0x86, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x0d, 0x38, 0xe6, - 0xab, 0x3c, 0x0f, 0x30, 0xe1, 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x96, 0x02, 0xdd, 0x80, 0xe5, 0xea, - 0x38, 0x35, 0x2a, 0x12, 0x17, 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x53, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, - 0xa9, 0x4f, 0x99, 0x23, 0x64, 0xae, 0xb0, 0x3e, 0x67, 0x4e, 0x6d, 0xea, 0x1e, 0xa7, 0x6e, 0x9e, 0xa4, 0x16, 0xab, - 0xd3, 0xa6, 0x94, 0x88, 0x49, 0x89, 0x79, 0x2a, 0x53, 0xb1, 0x95, 0xb8, 0x73, 0xeb, 0x1b, 0x2d, 0xa4, 0x8d, 0x76, - 0x2a, 0x73, 0xb0, 0xb5, 0xbc, 0x17, 0xa2, 0xfd, 0x25, 0x11, 0x9e, 0x95, 0xc8, 0x58, 0x8b, 0x39, 0x73, 0x4c, 0x04, - 0xab, 0x17, 0x53, 0x91, 0x7f, 0x70, 0x74, 0x9a, 0xbd, 0x41, 0x0f, 0x52, 0x6f, 0x20, 0x31, 0x6b, 0xe2, 0xbb, 0x90, - 0x86, 0x3a, 0x42, 0xa0, 0x32, 0xaa, 0x65, 0x3a, 0x4e, 0x2c, 0x15, 0x97, 0xe4, 0xab, 0xf7, 0xfa, 0x38, 0xdf, 0x78, - 0x6e, 0xac, 0x46, 0x10, 0x83, 0xb7, 0x90, 0x1f, 0x79, 0x52, 0x84, 0x03, 0xe1, 0xf2, 0xcd, 0xcd, 0x5e, 0xbe, 0xcb, - 0xaa, 0x10, 0x49, 0x05, 0x63, 0x8c, 0x19, 0xc5, 0xb8, 0x27, 0x6a, 0x6a, 0x31, 0x07, 0x54, 0x65, 0xeb, 0x30, 0xc7, - 0x03, 0x00, 0x68, 0x69, 0x4a, 0x2f, 0xb3, 0xad, 0x3a, 0xcf, 0x25, 0x7c, 0x8c, 0x3c, 0x14, 0xd9, 0xf8, 0xfd, 0x9a, - 0x0c, 0x14, 0x84, 0xfb, 0x5e, 0xc7, 0xc3, 0xc4, 0x38, 0x58, 0x45, 0x21, 0x0b, 0xf4, 0x06, 0xed, 0x55, 0x89, 0x50, - 0xdc, 0x9c, 0xac, 0xc7, 0x0d, 0x27, 0x15, 0x6c, 0xa1, 0x12, 0x96, 0x4a, 0x0b, 0xfc, 0x6a, 0x23, 0x34, 0x4f, 0x19, - 0xf7, 0xde, 0x54, 0x38, 0x83, 0xfe, 0xe0, 0xde, 0x32, 0xa3, 0xbe, 0x5f, 0x3a, 0x91, 0xa9, 0xc0, 0xc4, 0xcd, 0x2c, - 0xb5, 0xdf, 0x2f, 0xab, 0xb4, 0x9f, 0x57, 0xc8, 0x7d, 0x4e, 0x9a, 0xaf, 0x73, 0x07, 0xcd, 0x27, 0xc3, 0xfd, 0x4a, - 0xf9, 0xa1, 0x85, 0x51, 0x53, 0x7e, 0x79, 0x5d, 0xf9, 0x15, 0x9e, 0x0a, 0x6f, 0xf5, 0xbb, 0x28, 0x74, 0x51, 0x9f, - 0x83, 0x21, 0xa4, 0x1f, 0xc1, 0x35, 0x34, 0x78, 0x50, 0x24, 0x8b, 0xc5, 0xda, 0x05, 0x71, 0x7d, 0xcc, 0xa9, 0x76, - 0x28, 0x63, 0x8c, 0x78, 0x5a, 0x72, 0x90, 0x64, 0x70, 0x30, 0x7e, 0x03, 0x03, 0x62, 0x52, 0x12, 0xd2, 0x21, 0x74, - 0x56, 0x66, 0x22, 0x2a, 0x77, 0xf1, 0x76, 0xe3, 0xb2, 0xa6, 0x50, 0x84, 0x9d, 0x60, 0xa6, 0x52, 0x2a, 0x08, 0xa4, - 0xc9, 0x77, 0xaf, 0x53, 0x0b, 0x86, 0x82, 0x68, 0x30, 0x14, 0x90, 0xd7, 0x76, 0x3d, 0x68, 0xf2, 0x51, 0x1c, 0x3c, - 0xaf, 0x50, 0x23, 0x5e, 0x66, 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x2e, 0x62, 0xaf, 0xe0, 0x13, 0x21, - 0x9b, 0xf2, 0xb0, 0x00, 0xfa, 0xa1, 0x5d, 0xd9, 0x4b, 0x77, 0x8b, 0xca, 0xa5, 0x45, 0x63, 0x2b, 0x51, 0xb3, 0xe6, - 0x87, 0xf1, 0x66, 0x7a, 0x04, 0x53, 0x53, 0x02, 0x01, 0x69, 0x2a, 0x27, 0xa9, 0xe6, 0x3d, 0x4c, 0x8f, 0x00, 0x24, - 0xd8, 0xfd, 0x04, 0x16, 0xfa, 0x4d, 0x89, 0x09, 0x16, 0x55, 0x63, 0xb7, 0x19, 0x68, 0xcd, 0x19, 0x69, 0xbe, 0x19, - 0x42, 0xb8, 0xa9, 0xac, 0x67, 0xcc, 0x0e, 0xb0, 0x6d, 0x77, 0xb3, 0x38, 0x4c, 0x37, 0x3b, 0x47, 0x86, 0xe0, 0xc2, - 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x5c, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, - 0xd1, 0x74, 0xee, 0x35, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, 0x89, 0x62, 0x9e, 0x13, - 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, 0xca, 0xcf, 0xe8, 0x48, - 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x4b, 0x30, 0x8d, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, 0x00, 0x5f, 0xd9, 0x50, - 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x72, 0x36, 0xc1, 0x02, 0x0d, 0xba, 0xac, 0xc1, 0x17, 0xb0, 0x0c, 0xee, - 0x48, 0x3f, 0x05, 0xdf, 0x4f, 0xeb, 0xe0, 0x33, 0xf6, 0xbf, 0x00, 0xb4, 0x2a, 0x30, 0xa0, 0xdc, 0x69, 0x1a, 0x56, - 0x42, 0x5c, 0xa2, 0xc2, 0xac, 0xe2, 0xfc, 0x71, 0x9d, 0xd7, 0x4d, 0xcb, 0x12, 0x83, 0xf2, 0x33, 0xd7, 0x70, 0xe3, - 0x7b, 0x8d, 0xfc, 0xf1, 0xbd, 0x97, 0xa0, 0xdb, 0x89, 0xb4, 0xf7, 0xef, 0xe7, 0xf7, 0xc8, 0x42, 0x03, 0x3f, 0x2c, - 0x9a, 0x41, 0x5b, 0xbc, 0x08, 0x90, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, 0x30, 0x03, 0x0c, - 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, 0xe4, 0xc5, 0x3a, - 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x20, 0xfa, 0x9a, 0xca, 0x62, 0x03, 0xb9, 0xb8, 0x29, 0x6b, - 0xbd, 0xa2, 0xd1, 0xe8, 0xc6, 0x2e, 0xbc, 0xae, 0xc0, 0x27, 0x51, 0x3a, 0x4a, 0xc4, 0x24, 0x66, 0x52, 0xe5, 0x8a, - 0x5c, 0x1b, 0xdd, 0x4b, 0x5b, 0x34, 0x2f, 0x85, 0x04, 0xaf, 0x08, 0xdc, 0x10, 0xfa, 0x4a, 0x5f, 0xae, 0x36, 0x50, - 0xf0, 0xa8, 0xbd, 0xb9, 0x08, 0x26, 0x26, 0x1e, 0x37, 0xa4, 0xa6, 0x5f, 0x87, 0x53, 0x2b, 0x8b, 0x25, 0x87, 0x5f, - 0xe7, 0x8c, 0x35, 0x14, 0x00, 0xf1, 0xc9, 0xa3, 0xf5, 0x6e, 0xd2, 0x1b, 0xa5, 0x1d, 0x94, 0x46, 0x88, 0xef, 0x2a, - 0x7c, 0xdd, 0x85, 0xe2, 0x2b, 0x57, 0xdd, 0xfb, 0x3a, 0x66, 0xc6, 0x05, 0xa3, 0x97, 0x7c, 0x9a, 0x34, 0xae, 0xdd, - 0xd0, 0x5d, 0x9d, 0xef, 0xbd, 0x2f, 0x65, 0xde, 0xc2, 0x31, 0xb0, 0xc9, 0x31, 0x73, 0x5e, 0x7a, 0x6f, 0x8d, 0x13, - 0xe5, 0x1f, 0xcc, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0x1f, 0x06, 0x3f, 0x04, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, - 0x5d, 0x75, 0x82, 0x4c, 0x94, 0xdb, 0xd0, 0x1b, 0x6e, 0xef, 0xae, 0x02, 0x41, 0x9c, 0x8a, 0xe9, 0xa3, 0x72, 0x5c, - 0x3f, 0x5a, 0xa0, 0x52, 0x11, 0xf1, 0xb9, 0xca, 0x5d, 0x59, 0x9b, 0x1a, 0xea, 0x31, 0x9d, 0xcc, 0x42, 0xd3, 0xac, - 0xc8, 0xa5, 0x6c, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, - 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, 0x7a, 0x14, 0x7d, 0x1c, 0xb7, 0x99, 0xcb, 0xa3, - 0xec, 0xcf, 0x1a, 0x00, 0xa6, 0x23, 0x2c, 0xba, 0x9b, 0x9e, 0xb1, 0x27, 0xd0, 0xd3, 0x13, 0x19, 0x24, 0x7a, 0xa3, - 0xf3, 0x55, 0xab, 0xc4, 0xd2, 0x15, 0x04, 0x76, 0x6f, 0xc8, 0x58, 0x95, 0xb4, 0x5b, 0xae, 0x5f, 0xce, 0xf3, 0x79, - 0xce, 0x97, 0xf2, 0x7c, 0x6a, 0x16, 0xdd, 0xbd, 0xb6, 0x7b, 0x73, 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, - 0x5d, 0x07, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, 0x8d, 0x7a, 0x26, 0xc7, 0x86, 0xf0, 0x4d, 0xa5, - 0x3b, 0x44, 0x37, 0x4c, 0xd5, 0x4c, 0xdf, 0x37, 0xb6, 0x85, 0x6c, 0xf3, 0xf2, 0x6a, 0x94, 0x03, 0xa5, 0xe5, 0xfe, - 0x32, 0x61, 0xf8, 0xfe, 0xfa, 0xfa, 0x7b, 0x21, 0xa7, 0xaa, 0x8e, 0xde, 0xe2, 0xb5, 0xee, 0x19, 0x6c, 0x94, 0xca, - 0x89, 0xb8, 0x60, 0xab, 0x07, 0x6f, 0xee, 0x5e, 0x01, 0xcb, 0x05, 0xec, 0xda, 0x0b, 0xe6, 0x34, 0x86, 0xaa, 0x36, - 0xf0, 0x97, 0xab, 0x07, 0x5b, 0xb5, 0x87, 0xbf, 0x1c, 0x7c, 0x19, 0xdc, 0xd8, 0xd8, 0xd8, 0xc6, 0xdb, 0xb5, 0x44, - 0x90, 0x37, 0x78, 0xa0, 0x8f, 0x57, 0x1f, 0x05, 0x2d, 0x57, 0x88, 0x6d, 0x36, 0x70, 0x28, 0x6c, 0x0d, 0xf2, 0x4d, - 0xca, 0xa4, 0xe1, 0xbc, 0xe0, 0xd9, 0x54, 0xce, 0x50, 0xc8, 0x6b, 0x3e, 0x0e, 0xda, 0x8e, 0xf0, 0xbf, 0xc0, 0xa9, - 0x1d, 0x2f, 0x2f, 0x3e, 0x41, 0x1f, 0xf0, 0x74, 0xa5, 0x34, 0xa5, 0x38, 0xa5, 0x0a, 0xea, 0x2c, 0xd7, 0x79, 0x30, - 0x52, 0x5c, 0x4c, 0x60, 0x71, 0xc1, 0x65, 0xb9, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, 0x44, - 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, 0xd7, - 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, 0xe7, - 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, 0x52, - 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, 0x2d, - 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, 0xc4, - 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, 0xd6, - 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, 0xe2, - 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0x67, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, 0x68, - 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, 0x57, - 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, 0x70, - 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, 0xc0, - 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0x61, 0x03, 0xb9, 0xd4, 0x92, 0xbf, 0xcc, - 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, 0x51, - 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x2f, 0x54, 0xe4, 0x98, 0x3a, - 0x98, 0x95, 0xda, 0x4d, 0x8b, 0x4d, 0x92, 0xf7, 0xcc, 0x80, 0xe4, 0xea, 0x6b, 0x78, 0x68, 0xfc, 0x32, 0xbc, 0xa1, - 0xe8, 0xe9, 0x18, 0x21, 0xa7, 0xa5, 0x31, 0x97, 0xfe, 0x5b, 0x79, 0x9f, 0x56, 0x02, 0xf6, 0x0a, 0xc4, 0x94, 0x81, - 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x4b, 0x26, 0x5d, 0xa5, 0xb2, 0xd6, 0x58, - 0x75, 0x3f, 0xcf, 0x59, 0x7e, 0xb5, 0xcf, 0x30, 0x37, 0x19, 0x0d, 0xb2, 0x25, 0x33, 0x9b, 0xf2, 0xab, 0xbd, 0x1b, - 0xbf, 0xf2, 0x50, 0xd2, 0xa1, 0x5a, 0xa5, 0x9b, 0x97, 0x6e, 0x38, 0xc6, 0x8d, 0x1b, 0x8e, 0x00, 0x36, 0x86, 0x9d, - 0x2a, 0x52, 0xeb, 0xfc, 0xf7, 0xa5, 0xf0, 0x93, 0xd8, 0x6b, 0x47, 0x7a, 0xd7, 0x1d, 0xad, 0x4c, 0x4f, 0xbf, 0x01, - 0x55, 0x23, 0x4b, 0xe8, 0x26, 0x54, 0x31, 0x19, 0x89, 0x12, 0xd3, 0x55, 0xca, 0xa3, 0xbe, 0x46, 0x9c, 0x83, 0xb8, - 0xa1, 0xfc, 0xc5, 0x3f, 0x85, 0x57, 0x27, 0x01, 0x1a, 0x51, 0x8b, 0x71, 0x96, 0xf2, 0xd6, 0x38, 0x9a, 0xc6, 0xc9, - 0x55, 0x30, 0x8f, 0x5b, 0xd3, 0x2c, 0xcd, 0x8a, 0x19, 0x70, 0xa5, 0x57, 0x5c, 0x81, 0x0d, 0x3f, 0x6d, 0xcd, 0x63, - 0xef, 0x25, 0x4b, 0xce, 0x19, 0x8f, 0x87, 0x91, 0x67, 0xef, 0xe5, 0x20, 0x1e, 0xac, 0xb7, 0x51, 0x9e, 0x67, 0x17, - 0xb6, 0xf7, 0x21, 0x3b, 0x05, 0xa6, 0xf5, 0xde, 0x5d, 0x5e, 0x9d, 0xb1, 0xd4, 0xfb, 0x78, 0x3a, 0x4f, 0xf9, 0xdc, - 0x2b, 0xa2, 0xb4, 0x68, 0x15, 0x2c, 0x8f, 0xc7, 0xa0, 0x26, 0x92, 0x2c, 0x6f, 0x61, 0xfe, 0xf3, 0x94, 0x05, 0x49, - 0x7c, 0x36, 0xe1, 0xd6, 0x28, 0xca, 0x3f, 0xf5, 0x5a, 0xad, 0x59, 0x1e, 0x4f, 0xa3, 0xfc, 0xaa, 0x45, 0x2d, 0x82, - 0xcf, 0xda, 0xdb, 0xd1, 0xe7, 0xe3, 0x87, 0x3d, 0x9e, 0x43, 0xdf, 0x18, 0xa9, 0x18, 0x80, 0xf0, 0xb1, 0xb6, 0x77, - 0xda, 0xd3, 0xe2, 0x9e, 0x38, 0x51, 0x8a, 0x52, 0x5e, 0x9e, 0x78, 0x57, 0x0c, 0xe0, 0xf6, 0x4f, 0x79, 0xea, 0x81, - 0x2f, 0xc7, 0xb3, 0x74, 0x31, 0x9c, 0xe7, 0x05, 0x0c, 0x30, 0xcb, 0xe2, 0x94, 0xb3, 0xbc, 0x77, 0x9a, 0xe5, 0x40, - 0xb6, 0x56, 0x1e, 0x8d, 0xe2, 0x79, 0x11, 0x3c, 0x9c, 0x5d, 0xf6, 0xd0, 0x56, 0x38, 0xcb, 0xb3, 0x79, 0x3a, 0x92, - 0x73, 0xc5, 0x29, 0x6c, 0x8c, 0x98, 0x9b, 0x15, 0xf4, 0x25, 0x14, 0x80, 0x2f, 0x65, 0x51, 0xde, 0x3a, 0xc3, 0xce, - 0x68, 0xe8, 0xb7, 0x47, 0xec, 0xcc, 0xcb, 0xcf, 0x4e, 0x23, 0xa7, 0xd3, 0x7d, 0xec, 0xa9, 0x7f, 0xfe, 0x8e, 0x0b, - 0x86, 0xfb, 0xca, 0xe2, 0x4e, 0xbb, 0xfd, 0x37, 0x6e, 0xaf, 0x31, 0x0b, 0x01, 0x14, 0x74, 0x66, 0x97, 0x56, 0x91, - 0x25, 0xb0, 0x3e, 0xab, 0x7a, 0xf6, 0x66, 0xe0, 0x37, 0xc5, 0xe9, 0x59, 0xd0, 0x9d, 0x5d, 0x96, 0x88, 0x5d, 0x20, - 0x12, 0x32, 0x25, 0x92, 0xf2, 0x6d, 0xf1, 0x5b, 0x21, 0x7e, 0xb2, 0x1a, 0xe2, 0xae, 0x82, 0xb8, 0xa2, 0x7a, 0x6b, - 0x04, 0xfb, 0x80, 0xc8, 0xdf, 0x29, 0x04, 0x20, 0x13, 0x70, 0x02, 0x73, 0x05, 0x07, 0xbd, 0xfc, 0x66, 0x30, 0xba, - 0xab, 0xc1, 0x78, 0x72, 0x1b, 0x18, 0x79, 0x3a, 0x5a, 0xd4, 0xd7, 0xb5, 0x03, 0xce, 0x69, 0x6f, 0xc2, 0x90, 0x9f, - 0x82, 0x2e, 0x3e, 0x5f, 0xc4, 0x23, 0x3e, 0x11, 0x8f, 0xc4, 0xce, 0x17, 0xa2, 0x6e, 0xa7, 0xdd, 0x16, 0xef, 0x05, - 0x28, 0xb4, 0xa0, 0xe3, 0x63, 0x03, 0x60, 0xa2, 0x2f, 0xd6, 0x7d, 0xc4, 0xe6, 0xbb, 0x5b, 0xbf, 0x54, 0xe3, 0x31, - 0x95, 0x37, 0x28, 0x54, 0x84, 0xfa, 0x66, 0x0b, 0x66, 0xbc, 0xe5, 0xfd, 0x8e, 0x3e, 0xa8, 0x1a, 0x7c, 0xc7, 0x48, - 0xeb, 0x05, 0xcc, 0x33, 0x73, 0x81, 0x7a, 0x69, 0x1f, 0x43, 0x52, 0xad, 0x96, 0x0b, 0x7a, 0x83, 0x63, 0x08, 0x89, - 0x0e, 0x04, 0x9d, 0x7c, 0x50, 0xd0, 0x37, 0x35, 0x32, 0x37, 0x28, 0x9c, 0xcc, 0x85, 0x2d, 0x9f, 0x69, 0xb9, 0x0e, - 0x4a, 0x1a, 0xbc, 0xec, 0x2f, 0x98, 0x6c, 0x00, 0xd2, 0xbb, 0x92, 0xb4, 0xbc, 0x3a, 0x7a, 0x52, 0x2e, 0x5f, 0x36, - 0x24, 0xca, 0x81, 0xaf, 0xcf, 0x27, 0xe8, 0x77, 0xeb, 0xab, 0xeb, 0x46, 0x4a, 0xcd, 0x96, 0xed, 0x0e, 0xb8, 0xce, - 0xca, 0xc2, 0xec, 0x33, 0x5e, 0xe2, 0x28, 0x5f, 0x81, 0x9c, 0xc5, 0xd0, 0xeb, 0xcf, 0xa1, 0x70, 0xd3, 0x94, 0x93, - 0xb6, 0x71, 0xd3, 0xf5, 0x7f, 0x58, 0xf1, 0x98, 0xb2, 0x9d, 0x55, 0x6c, 0x1c, 0x5c, 0x97, 0xe3, 0xa1, 0xb8, 0x76, - 0x58, 0x60, 0xb6, 0xf8, 0x6f, 0xf7, 0x24, 0x1c, 0x8d, 0x56, 0x91, 0xcd, 0xf3, 0x21, 0x26, 0xfd, 0xaf, 0x08, 0x31, - 0xd8, 0xa4, 0xe1, 0x6d, 0x8f, 0x6b, 0xc5, 0xc2, 0x30, 0x7f, 0xc2, 0xfc, 0xaa, 0x02, 0xa3, 0x53, 0x17, 0x71, 0xa9, - 0x41, 0x86, 0x55, 0x14, 0xd8, 0xa8, 0x2b, 0x47, 0x94, 0x60, 0x47, 0x17, 0x3e, 0xfd, 0x79, 0x1a, 0x83, 0x68, 0x3d, - 0x8e, 0x47, 0x74, 0xd1, 0x25, 0x1e, 0xd1, 0xc9, 0x47, 0x8b, 0x32, 0x9d, 0x30, 0x94, 0x0e, 0x05, 0x92, 0xe0, 0xf8, - 0x2c, 0x33, 0x67, 0xec, 0x96, 0x8d, 0xa7, 0x17, 0x86, 0x6e, 0x1e, 0x65, 0xd3, 0x28, 0x4e, 0x03, 0xfc, 0x20, 0x89, - 0xa7, 0x47, 0x0c, 0xb0, 0x8b, 0x07, 0x7f, 0x15, 0xed, 0x3b, 0xae, 0xff, 0x13, 0x08, 0x2e, 0xea, 0x5f, 0x4a, 0xc7, - 0x4f, 0xc3, 0xa5, 0xce, 0x95, 0xeb, 0xa5, 0x20, 0xec, 0xb8, 0xce, 0x6d, 0xa7, 0xc0, 0xca, 0x2e, 0xa3, 0x3f, 0x83, - 0x56, 0x27, 0xe8, 0xb8, 0xcb, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, 0xf3, - 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, 0x56, - 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, 0x5b, - 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xc5, 0x18, 0xb8, 0xaf, 0x65, 0x6d, 0x29, 0xf6, 0x1e, 0x9e, - 0xec, 0x0a, 0x21, 0x65, 0x11, 0xeb, 0x86, 0x36, 0x48, 0x0d, 0xdb, 0xfa, 0xe3, 0x10, 0xe8, 0xfc, 0x29, 0xb4, 0x37, - 0x16, 0x8e, 0xba, 0x0b, 0x90, 0xc3, 0x5c, 0x7b, 0x42, 0x51, 0xd3, 0x47, 0x04, 0xec, 0xfe, 0xc6, 0x82, 0x95, 0xbb, - 0x5b, 0xa2, 0x77, 0xff, 0xa4, 0x2c, 0x48, 0xa7, 0x9a, 0xb1, 0xbf, 0x6a, 0x0a, 0x51, 0x07, 0xc3, 0x52, 0xc6, 0x31, - 0x8e, 0x9b, 0x6b, 0x3b, 0x51, 0x04, 0xb9, 0x25, 0xe3, 0x16, 0x98, 0x61, 0x15, 0xe5, 0x20, 0x46, 0x74, 0x0e, 0x4d, - 0x21, 0xd2, 0x46, 0x7a, 0xcb, 0x50, 0x9c, 0x20, 0x04, 0x83, 0x8d, 0x45, 0x5c, 0x86, 0xf0, 0x94, 0x0e, 0xb3, 0x11, - 0xfb, 0xf8, 0xe1, 0x15, 0x5e, 0x93, 0xc8, 0x52, 0x94, 0xa7, 0x99, 0x5b, 0x9e, 0x80, 0x81, 0x85, 0x90, 0xe6, 0xea, - 0x2b, 0x35, 0x00, 0x8c, 0x88, 0x15, 0x59, 0x34, 0x2a, 0x82, 0xc2, 0x4b, 0xdb, 0x1a, 0x08, 0x08, 0xc1, 0x91, 0xc5, - 0x02, 0x30, 0x41, 0xa9, 0x17, 0x07, 0xfc, 0x44, 0xeb, 0x3e, 0x0c, 0xb4, 0xbb, 0x25, 0x1a, 0x01, 0xae, 0x39, 0xa2, - 0x51, 0xa1, 0x8a, 0x59, 0x45, 0x26, 0xba, 0xa3, 0xf8, 0x5c, 0x93, 0x93, 0x52, 0xac, 0xfb, 0xbb, 0x49, 0x74, 0xca, - 0x12, 0x18, 0x12, 0xf8, 0xaa, 0x0d, 0x23, 0x89, 0x57, 0x6b, 0x37, 0x4e, 0x67, 0x73, 0xf9, 0xb5, 0x30, 0x98, 0xb8, - 0x83, 0x07, 0xb8, 0x78, 0x99, 0x61, 0xa0, 0x4e, 0x24, 0x03, 0x39, 0x00, 0x80, 0x48, 0x87, 0x21, 0x08, 0x5d, 0xc5, - 0x2a, 0x50, 0x1a, 0x8f, 0x96, 0xcb, 0x60, 0x7f, 0xcf, 0xb0, 0x34, 0x85, 0xe7, 0x69, 0x9c, 0xe2, 0x63, 0x81, 0x8f, - 0xd1, 0x25, 0x3e, 0x66, 0xf0, 0xa8, 0x71, 0xcf, 0x4b, 0xfb, 0xaf, 0xba, 0x2a, 0x99, 0x5c, 0x01, 0x4b, 0x13, 0x20, - 0xbb, 0xbe, 0x06, 0xb5, 0xa5, 0x49, 0xb0, 0xbb, 0x05, 0xc4, 0x42, 0xee, 0x11, 0xdf, 0x8e, 0xe1, 0x26, 0x19, 0x59, - 0x31, 0x6b, 0x89, 0x72, 0x8b, 0x8c, 0x83, 0x10, 0x7c, 0xc7, 0xdc, 0x69, 0xd8, 0x40, 0x9e, 0xcc, 0x92, 0x79, 0x86, - 0x2f, 0xae, 0x6d, 0x89, 0x8f, 0x7b, 0x08, 0xa2, 0xd0, 0x23, 0x62, 0xa8, 0xcb, 0x98, 0xfc, 0x6c, 0x4f, 0x1c, 0xda, - 0x38, 0x0b, 0x98, 0xa1, 0xe8, 0x85, 0xf2, 0x28, 0x4e, 0x44, 0xe3, 0x15, 0xf8, 0x34, 0xd2, 0x1d, 0x09, 0x9d, 0xdd, - 0xad, 0x0a, 0x36, 0x00, 0x5e, 0x49, 0x04, 0x4e, 0x19, 0x37, 0xb6, 0x28, 0xa7, 0x14, 0x00, 0xb9, 0xcd, 0xab, 0x4f, - 0x3a, 0x01, 0x53, 0x80, 0x11, 0x3d, 0x3a, 0xa6, 0xd9, 0x06, 0x43, 0x20, 0x16, 0xcd, 0xd8, 0xd8, 0xba, 0xf6, 0x5f, - 0xfe, 0xf9, 0x1f, 0x6c, 0x4f, 0x80, 0x98, 0x8d, 0xc7, 0x20, 0xe5, 0xac, 0x75, 0x0d, 0xff, 0xd7, 0x3f, 0xfe, 0xdf, - 0xff, 0xf3, 0x5f, 0x75, 0xdb, 0x14, 0x9a, 0x9e, 0x04, 0xe2, 0x68, 0x41, 0x93, 0x94, 0x52, 0x3c, 0xed, 0x71, 0x94, - 0xae, 0x00, 0xe9, 0x10, 0xb3, 0x18, 0x19, 0x1b, 0x79, 0xb6, 0x05, 0x9a, 0x40, 0x3c, 0x1f, 0x27, 0xec, 0x9c, 0xc9, - 0x0f, 0xcb, 0xe8, 0x41, 0x74, 0xe5, 0x10, 0x2c, 0x18, 0x2e, 0xef, 0xbc, 0xca, 0x6d, 0xa0, 0x68, 0x29, 0x29, 0x5e, - 0x27, 0x98, 0x67, 0x1b, 0x83, 0x36, 0xe7, 0x68, 0xd7, 0x87, 0xf5, 0x40, 0xa5, 0xda, 0xb6, 0x80, 0x97, 0xcc, 0xde, - 0x95, 0x10, 0x37, 0xe1, 0x3a, 0xcd, 0xb1, 0x69, 0xca, 0x8a, 0x62, 0x15, 0x58, 0x40, 0x13, 0xcf, 0xae, 0x9a, 0xd8, - 0xb5, 0x0e, 0x00, 0x40, 0x77, 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x3c, 0x86, 0x0d, 0x8e, 0xba, 0x2d, 0xe1, 0x18, - 0x84, 0x0f, 0xfb, 0xf6, 0x5b, 0x90, 0x25, 0x78, 0xa7, 0xc5, 0xd5, 0x9f, 0xf4, 0xa2, 0xe9, 0x95, 0xb0, 0x33, 0xe6, - 0x10, 0x9d, 0x8d, 0x61, 0xf4, 0x93, 0x81, 0x54, 0x36, 0xfc, 0xb4, 0x8a, 0x31, 0xd6, 0x32, 0xc2, 0xbf, 0xff, 0xcb, - 0x3f, 0xfe, 0x37, 0x18, 0x9b, 0xfa, 0xad, 0xe7, 0x02, 0x68, 0xf5, 0x3f, 0xa1, 0xd5, 0x3c, 0xbd, 0xa5, 0xdd, 0x5f, - 0xfe, 0xfe, 0xbf, 0x43, 0x33, 0xba, 0x28, 0x05, 0x7c, 0x42, 0x10, 0x0d, 0xd1, 0x36, 0xfd, 0x55, 0x20, 0xd5, 0x06, - 0x59, 0x3b, 0xd3, 0x3f, 0x21, 0xd8, 0x05, 0xcf, 0x66, 0x37, 0x82, 0x83, 0x50, 0x0f, 0x93, 0xac, 0x60, 0x1a, 0x1e, - 0xa1, 0x4f, 0x7e, 0x1d, 0x40, 0x34, 0xd7, 0x0c, 0x76, 0x6d, 0x61, 0xe9, 0x71, 0xc4, 0x0a, 0xad, 0xdc, 0x84, 0xf5, - 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, 0xda, - 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, 0x52, - 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, 0x48, - 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, 0x22, - 0xd2, 0x9a, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, 0x9f, - 0x85, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, 0x12, - 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, 0x97, - 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, 0x0c, - 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, 0x7f, - 0x83, 0x97, 0x1d, 0x91, 0x78, 0x64, 0x29, 0x14, 0x64, 0xd8, 0x30, 0x32, 0x6c, 0xa4, 0x46, 0x35, 0x6d, 0x0a, 0x74, - 0xfc, 0xb2, 0xd5, 0xb6, 0xc3, 0x31, 0x76, 0xaf, 0x69, 0x7f, 0x26, 0xb5, 0x7f, 0x2c, 0xed, 0x7d, 0xa9, 0xfd, 0xf1, - 0x93, 0x36, 0x0d, 0xed, 0x1f, 0xaf, 0xd5, 0xfe, 0x48, 0xb9, 0x01, 0x8e, 0x1c, 0xda, 0x9b, 0x18, 0xdd, 0x32, 0x6c, - 0x0d, 0xd4, 0xc4, 0x83, 0xe1, 0x84, 0x0d, 0x3f, 0x49, 0x33, 0x8b, 0x10, 0xc0, 0x40, 0x94, 0x36, 0x26, 0x05, 0x06, - 0x60, 0x32, 0x9c, 0x94, 0x7a, 0xd3, 0xe3, 0xa3, 0x31, 0x01, 0x73, 0x17, 0x63, 0x86, 0xa2, 0x1f, 0xd6, 0xec, 0x2b, - 0x56, 0x6e, 0xe1, 0x38, 0x62, 0xc3, 0x88, 0x67, 0xc0, 0x6c, 0x0b, 0x07, 0x3b, 0xf1, 0x16, 0x22, 0x58, 0x18, 0xd8, - 0xef, 0xdf, 0xed, 0x1f, 0xd8, 0xde, 0x69, 0x36, 0xba, 0x0a, 0x6c, 0x70, 0xc6, 0xc0, 0x9a, 0x72, 0x7d, 0x3e, 0x61, - 0xa9, 0xa3, 0x3c, 0x9f, 0x2c, 0x61, 0xe0, 0x00, 0x9e, 0x89, 0x6f, 0x5b, 0x34, 0x0f, 0x3a, 0x80, 0xb0, 0xf4, 0xf1, - 0xcb, 0xfe, 0x2e, 0x17, 0xdf, 0x85, 0xe5, 0x39, 0x3e, 0xf6, 0x31, 0xd5, 0x63, 0x77, 0x0b, 0x1e, 0xf0, 0x65, 0x1f, - 0xf5, 0x1e, 0xbd, 0x6d, 0x2c, 0x96, 0xdc, 0x86, 0x01, 0x0e, 0x31, 0xe9, 0x0b, 0x14, 0x0a, 0x6a, 0x75, 0x12, 0x20, - 0x62, 0xf0, 0x08, 0x63, 0x6d, 0xa9, 0x71, 0x11, 0x42, 0xd5, 0x5f, 0x3b, 0x2e, 0x95, 0xdd, 0x4a, 0xf3, 0x8e, 0xb0, - 0x01, 0x39, 0x2e, 0xd8, 0x7b, 0xa4, 0x4b, 0x84, 0xa9, 0x43, 0x45, 0xeb, 0x20, 0xd0, 0x35, 0x95, 0xb9, 0x22, 0x3a, - 0x18, 0xc0, 0x90, 0x99, 0x2b, 0x00, 0x81, 0xbf, 0x84, 0xf6, 0x89, 0xf9, 0xfd, 0x37, 0xf1, 0xa9, 0x26, 0x4d, 0x9c, - 0xc3, 0x3f, 0x79, 0x57, 0xcc, 0xbb, 0x3a, 0xa1, 0x96, 0x2a, 0xd8, 0x80, 0x51, 0x30, 0x0c, 0xca, 0xb4, 0x55, 0x54, - 0x09, 0xec, 0xb4, 0x24, 0x9a, 0x15, 0x2c, 0x50, 0x0f, 0x32, 0xee, 0x80, 0xe1, 0x8b, 0xe5, 0x40, 0x8f, 0x69, 0xcf, - 0x95, 0x7c, 0xb2, 0x30, 0x03, 0x13, 0x8f, 0xda, 0xed, 0x1e, 0x5e, 0xaa, 0x68, 0x45, 0x60, 0x1d, 0xa4, 0x41, 0xc2, - 0xc6, 0xbc, 0xe4, 0x78, 0x6b, 0x7f, 0xa1, 0x22, 0x41, 0x7e, 0x77, 0x27, 0x67, 0x53, 0xcb, 0xc7, 0xff, 0xbf, 0x6d, - 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, 0x0d, 0x19, - 0x46, 0xc9, 0x4a, 0x0e, 0xce, 0x37, 0x88, 0x9b, 0xdc, 0x6c, 0x07, 0x72, 0x7a, 0x29, 0x54, 0xb6, 0x1c, 0xac, 0xd9, - 0x76, 0xa5, 0x7f, 0xb4, 0xdc, 0x58, 0x45, 0xbc, 0xea, 0x6f, 0x4b, 0x14, 0x32, 0x62, 0x73, 0xa5, 0x50, 0x51, 0x0b, - 0xd1, 0xc3, 0xc4, 0x69, 0x39, 0x6a, 0x77, 0xab, 0xc5, 0x5c, 0x92, 0xb8, 0x38, 0x24, 0x71, 0x41, 0xe2, 0xef, 0x68, - 0x21, 0xe6, 0x1e, 0x46, 0xc9, 0xd0, 0x41, 0x00, 0xac, 0x96, 0xf5, 0x04, 0xa8, 0xe9, 0xaa, 0xc8, 0x91, 0xff, 0x18, - 0x89, 0x5b, 0x0a, 0x61, 0xb9, 0x82, 0x4a, 0x27, 0x47, 0x65, 0xd9, 0x63, 0xcc, 0x39, 0xfc, 0x20, 0x2f, 0x81, 0x88, - 0xbb, 0xbf, 0xfa, 0xfb, 0x89, 0xed, 0xd2, 0x3d, 0xf2, 0x7e, 0x36, 0x3e, 0x4a, 0x67, 0x2b, 0x66, 0xb7, 0x3d, 0x58, - 0x06, 0xb3, 0xa7, 0xfc, 0x84, 0xe4, 0x4d, 0x7d, 0x4d, 0x36, 0xa7, 0xfe, 0x3f, 0x87, 0x38, 0xc2, 0x1b, 0xc7, 0x46, - 0x13, 0x9d, 0x46, 0xbe, 0x6a, 0x11, 0x7f, 0xda, 0xd8, 0x55, 0x1c, 0x81, 0x7c, 0xbd, 0x2e, 0x92, 0xf5, 0xcd, 0xed, - 0x91, 0xac, 0xe2, 0x8e, 0x91, 0xac, 0x6f, 0x7e, 0xe7, 0x48, 0xd6, 0xd7, 0x66, 0x24, 0x0b, 0x05, 0xf4, 0xab, 0x5f, - 0x13, 0x6d, 0xca, 0xb3, 0x8b, 0x22, 0xec, 0xc8, 0xcc, 0x09, 0x90, 0x75, 0x18, 0x76, 0xfa, 0xeb, 0x47, 0x98, 0x60, - 0xa2, 0x46, 0x7c, 0x89, 0x02, 0x4a, 0x22, 0xd9, 0x13, 0xd4, 0x8a, 0x0c, 0xe7, 0xb4, 0x75, 0x56, 0x65, 0xeb, 0xa1, - 0xba, 0x46, 0x06, 0xae, 0xaf, 0xab, 0x43, 0x6d, 0x5d, 0x15, 0xf0, 0x09, 0xe8, 0x3b, 0xb0, 0xba, 0x63, 0x77, 0x53, - 0xa5, 0xf3, 0x99, 0x23, 0xf4, 0xd4, 0x29, 0x8d, 0x60, 0xa2, 0x85, 0xfd, 0x5f, 0x0e, 0x3b, 0xbd, 0xed, 0xce, 0x14, - 0x7a, 0x83, 0x02, 0x87, 0xb7, 0x76, 0x6f, 0x7b, 0x1b, 0xdf, 0x2e, 0xd4, 0x5b, 0x17, 0xdf, 0x62, 0xf5, 0xb6, 0x83, - 0x6f, 0x43, 0xf5, 0xf6, 0x08, 0xdf, 0x46, 0xea, 0xed, 0x31, 0xbe, 0x9d, 0xdb, 0xe5, 0x21, 0xd3, 0xc0, 0x3d, 0x06, - 0xbe, 0x22, 0x6f, 0x26, 0x50, 0x65, 0xb0, 0xe9, 0xf1, 0xc3, 0x08, 0xd1, 0x59, 0x10, 0x7b, 0xc2, 0xbb, 0x0c, 0x72, - 0xef, 0x02, 0x34, 0x4e, 0x40, 0xd9, 0x86, 0xcf, 0xf1, 0x3b, 0x1c, 0xe0, 0x24, 0x1d, 0xc4, 0x53, 0xa6, 0x3e, 0x48, - 0xac, 0xb0, 0x06, 0x03, 0xf6, 0xb0, 0x7d, 0x54, 0xf6, 0xf4, 0x3a, 0x89, 0x78, 0x96, 0xca, 0xe6, 0xa0, 0x95, 0xab, - 0xea, 0xc4, 0x74, 0x2d, 0xbd, 0xc2, 0x6b, 0xf4, 0x97, 0x11, 0x8f, 0x18, 0x83, 0x61, 0xd6, 0xba, 0x04, 0x0f, 0x76, - 0xa5, 0x4e, 0x43, 0x88, 0xb4, 0x4e, 0x23, 0x9c, 0xf4, 0xdb, 0x41, 0x74, 0xa6, 0x9f, 0xdf, 0x80, 0xa5, 0x1d, 0x9d, - 0xc9, 0x96, 0xeb, 0x75, 0x18, 0x81, 0x68, 0xea, 0x2f, 0x05, 0x04, 0x99, 0x62, 0xb0, 0x34, 0xe8, 0x49, 0x4b, 0xfd, - 0x85, 0xd4, 0xa9, 0x6b, 0x34, 0x9a, 0xbe, 0x5e, 0x04, 0x14, 0xad, 0x0a, 0x76, 0xc1, 0xe0, 0xa7, 0x52, 0x41, 0x61, - 0xa8, 0xc0, 0x02, 0x51, 0xbd, 0x46, 0x95, 0xe9, 0x60, 0xc3, 0x5a, 0x85, 0x66, 0x29, 0x5d, 0x66, 0x9e, 0xee, 0xe8, - 0xa3, 0x9d, 0x65, 0xf1, 0xfa, 0x59, 0x67, 0x88, 0xff, 0x49, 0xe1, 0xfd, 0xd9, 0x78, 0x3c, 0xbe, 0x51, 0xb7, 0x7d, - 0x36, 0x1a, 0xb3, 0x2e, 0xdb, 0xe9, 0x61, 0xe4, 0xbf, 0x25, 0xc5, 0x69, 0xa7, 0x24, 0xda, 0x2d, 0xee, 0xd6, 0x18, - 0x25, 0x2f, 0xa8, 0xbb, 0xbb, 0x2b, 0xc1, 0x12, 0xa8, 0xb2, 0x00, 0xe1, 0x7f, 0x16, 0xa7, 0x41, 0xbb, 0xf4, 0xcf, - 0xa5, 0xd6, 0xf8, 0xec, 0xc9, 0x93, 0x27, 0xa5, 0x3f, 0x52, 0x6f, 0xed, 0xd1, 0xa8, 0xf4, 0x87, 0x0b, 0x8d, 0x46, - 0xbb, 0x3d, 0x1e, 0x97, 0x7e, 0xac, 0x0a, 0xb6, 0xbb, 0xc3, 0xd1, 0x76, 0xb7, 0xf4, 0x2f, 0x8c, 0x16, 0xa5, 0xcf, - 0xe4, 0x5b, 0xce, 0x46, 0xb5, 0xe3, 0x83, 0xc7, 0x6d, 0xa8, 0x14, 0x8c, 0xb6, 0x40, 0xef, 0x52, 0x3c, 0x06, 0xd1, - 0x9c, 0x67, 0x60, 0xd8, 0x95, 0xbd, 0x02, 0xe4, 0xf3, 0x58, 0x4a, 0x78, 0xf1, 0xbd, 0x5f, 0x94, 0xea, 0xaf, 0x4c, - 0xa9, 0x8e, 0xcc, 0x4c, 0xd2, 0xbc, 0x20, 0x6d, 0xd0, 0xac, 0x46, 0xce, 0xa2, 0xea, 0x57, 0x61, 0x51, 0x09, 0x7b, - 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xd6, 0xc9, 0xf8, 0xef, 0x6f, 0x97, 0xf1, 0xa7, 0x77, 0x13, 0xf1, 0xdf, - 0xff, 0xce, 0x22, 0xfe, 0x07, 0x53, 0xc4, 0x0b, 0x21, 0xb6, 0x07, 0xa6, 0x33, 0xd9, 0xcc, 0xa7, 0xd9, 0x65, 0x0b, - 0xb7, 0x44, 0x6e, 0x93, 0xf4, 0x9c, 0xde, 0x49, 0xf8, 0xaf, 0xc8, 0x07, 0x53, 0x83, 0x19, 0x1f, 0x0f, 0xe6, 0xd9, - 0xd9, 0x59, 0xc2, 0x94, 0x8c, 0x37, 0x2a, 0xc8, 0x1c, 0x7f, 0x97, 0x86, 0xf6, 0x3b, 0xf4, 0x8c, 0xab, 0x92, 0xf1, - 0x18, 0x8a, 0xc6, 0x63, 0x5b, 0xe5, 0x4b, 0x83, 0x3c, 0xa3, 0x56, 0x6f, 0x6b, 0x25, 0xd4, 0xea, 0x8b, 0x2f, 0xcc, - 0x32, 0xb3, 0x40, 0x86, 0xf4, 0x4c, 0x63, 0x44, 0xd6, 0x8c, 0xe2, 0x02, 0xf7, 0x60, 0xf5, 0xb1, 0x63, 0xb4, 0x77, - 0xa6, 0xa0, 0x54, 0xe2, 0x21, 0x9e, 0x8b, 0x34, 0x3f, 0x2c, 0x23, 0x72, 0xdb, 0x97, 0x91, 0xab, 0xce, 0xbf, 0x8d, - 0x6f, 0x18, 0x56, 0x67, 0xde, 0xb0, 0xf8, 0x32, 0xbf, 0xe5, 0xe9, 0xd5, 0xab, 0x91, 0xb3, 0x87, 0x97, 0x7f, 0x8b, - 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, 0xec, 0x19, - 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, 0x92, 0x6e, - 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xd2, 0x79, 0x08, 0xcd, 0x30, - 0x2a, 0xd5, 0x19, 0x08, 0x10, 0x6e, 0x86, 0x9f, 0x68, 0x12, 0x43, 0xa8, 0x83, 0x82, 0x8a, 0x7a, 0xd7, 0xd7, 0xe6, - 0x97, 0x42, 0x6b, 0x5f, 0x95, 0x6c, 0xf0, 0x00, 0xc7, 0x4f, 0xfc, 0xa2, 0x36, 0xc8, 0xe6, 0xdc, 0xc1, 0x33, 0x80, - 0x05, 0x1e, 0x31, 0x78, 0x3b, 0xed, 0x36, 0xa8, 0x18, 0x5f, 0x7c, 0x07, 0xca, 0xd1, 0x9d, 0x05, 0xbe, 0x6c, 0xdd, - 0xb9, 0xc4, 0xd2, 0x77, 0xd9, 0x2a, 0x12, 0xdf, 0xbf, 0x2f, 0x11, 0x35, 0xee, 0x0e, 0xa9, 0x45, 0x6c, 0xbe, 0xfb, - 0xca, 0x77, 0x34, 0x08, 0xeb, 0xae, 0xe2, 0x60, 0x99, 0x5b, 0x5b, 0x2f, 0xc4, 0xb6, 0xc2, 0xaa, 0x59, 0x06, 0xe7, - 0x16, 0x9d, 0x59, 0x5c, 0x18, 0x01, 0xfc, 0xda, 0x36, 0x28, 0x55, 0x04, 0x5f, 0x84, 0xe1, 0xf7, 0xd0, 0xc5, 0x15, - 0x8e, 0xb7, 0x02, 0xba, 0xe1, 0xf2, 0x56, 0x90, 0xa3, 0x33, 0xac, 0x19, 0x5d, 0x55, 0xa9, 0x82, 0xd2, 0x3c, 0x82, - 0x31, 0x90, 0xa1, 0x48, 0x3a, 0xac, 0x71, 0x2a, 0xf4, 0x16, 0x4c, 0x43, 0x02, 0x58, 0xfb, 0x75, 0xe8, 0xd6, 0xd8, - 0x0a, 0x6c, 0x21, 0x2d, 0x40, 0xe9, 0x61, 0x87, 0xbe, 0x55, 0x03, 0x3d, 0x5d, 0x0e, 0xc0, 0xdf, 0xe8, 0xe4, 0x9d, - 0xf8, 0xc5, 0x85, 0x07, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, 0x86, - 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, 0x41, - 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, 0xdf, - 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, 0xd5, - 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0x7f, 0x46, 0xe6, 0x42, 0xb3, 0x98, 0x0e, 0xe0, 0xef, 0x02, - 0x59, 0x10, 0x8d, 0xf1, 0x0b, 0x8b, 0x77, 0x69, 0x79, 0x4a, 0xd9, 0xaf, 0x0b, 0x54, 0xeb, 0x41, 0xe7, 0x09, 0x78, - 0x7b, 0x77, 0x1e, 0xfe, 0x66, 0xf4, 0x4b, 0x49, 0x23, 0x75, 0x89, 0xd9, 0xb6, 0x7b, 0x28, 0x2f, 0x92, 0xe8, 0x0a, - 0x9c, 0x4e, 0xb2, 0x31, 0x4e, 0x31, 0x7a, 0xdc, 0x9b, 0x65, 0x32, 0x93, 0x24, 0x67, 0x09, 0xfd, 0x8c, 0x89, 0x5c, - 0x8a, 0xed, 0x47, 0xb3, 0x4b, 0xb5, 0x1a, 0x9d, 0x46, 0x86, 0xc8, 0xef, 0x9a, 0x08, 0xb2, 0x3e, 0xf3, 0xa4, 0x9e, - 0xcc, 0xb0, 0x03, 0x30, 0x08, 0xc3, 0xa6, 0x95, 0x0b, 0xa8, 0xda, 0x50, 0x62, 0xa4, 0xc2, 0x54, 0x03, 0x59, 0xfe, - 0x36, 0xa8, 0xca, 0xa8, 0x60, 0x3d, 0xfc, 0xd4, 0x65, 0x0c, 0xae, 0xad, 0x34, 0x9e, 0xa6, 0xf1, 0x68, 0x94, 0xb0, - 0x9e, 0xb2, 0x8f, 0xac, 0xce, 0x23, 0xcc, 0x24, 0x31, 0x97, 0xac, 0xbe, 0x2a, 0x06, 0xf1, 0x34, 0x9d, 0xa2, 0x53, - 0xb0, 0xd7, 0xf0, 0x7b, 0x95, 0x2b, 0xc9, 0x29, 0x53, 0x2c, 0xda, 0x15, 0xf1, 0xe8, 0xb9, 0x8e, 0xcb, 0x0e, 0x18, - 0x8b, 0xb4, 0xe0, 0xed, 0x1e, 0xcf, 0x66, 0x41, 0x6b, 0xbb, 0x8e, 0x08, 0x56, 0x69, 0x14, 0xbc, 0x15, 0x68, 0x79, - 0x68, 0x1d, 0x08, 0x2d, 0x67, 0xf9, 0x1d, 0x59, 0x46, 0x03, 0xe0, 0x37, 0x11, 0x75, 0x51, 0x59, 0x47, 0xe6, 0xaf, - 0xb3, 0x5b, 0x3e, 0x5f, 0xbd, 0x5b, 0x3e, 0x57, 0xbb, 0xe5, 0x66, 0x8e, 0xfd, 0x6c, 0xdc, 0xc1, 0xff, 0x7a, 0x15, - 0x42, 0xb0, 0x2a, 0x40, 0x0e, 0x0b, 0xed, 0xe2, 0x56, 0x17, 0xfe, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x9f, 0x0f, 0x16, - 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xd7, 0xae, 0x55, 0x75, 0x1e, 0x62, 0x1d, 0xf6, 0xda, 0x59, 0xae, 0xeb, 0xde, 0xbc, - 0x69, 0x41, 0x5e, 0x71, 0x27, 0x50, 0xc2, 0x18, 0x5c, 0xb5, 0xe8, 0xf4, 0x14, 0x4a, 0xc7, 0xd9, 0x70, 0x5e, 0xfc, - 0xad, 0x84, 0x5f, 0x12, 0xf1, 0xc6, 0x2d, 0xdd, 0x18, 0x47, 0x75, 0x15, 0x69, 0x49, 0x6a, 0x84, 0x85, 0x5e, 0xa7, - 0xa0, 0x00, 0xc6, 0x64, 0x4e, 0xd7, 0x7f, 0xb8, 0x62, 0x13, 0xfc, 0x7f, 0x59, 0x9b, 0x95, 0xc8, 0xfc, 0x47, 0x89, - 0x71, 0x23, 0x11, 0x7e, 0x15, 0x0d, 0xcc, 0x35, 0x6c, 0x3f, 0x59, 0x0d, 0xee, 0xa1, 0x9a, 0xe9, 0x48, 0x29, 0x05, - 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0xe6, 0x09, 0xbf, 0x79, 0xd4, 0x75, 0x9c, 0xb1, 0x34, 0xea, 0x0d, 0x02, 0xbd, 0x6a, - 0x7b, 0x47, 0x29, 0xfd, 0xd9, 0xe7, 0x0f, 0xf1, 0x3f, 0x11, 0x38, 0x3b, 0xad, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, - 0x68, 0x5a, 0x73, 0x7e, 0x84, 0x06, 0x27, 0xff, 0xe7, 0xae, 0xad, 0xd1, 0x58, 0xbf, 0x53, 0x73, 0x69, 0x95, 0xfe, - 0xaa, 0xd6, 0xbf, 0x6e, 0xf0, 0x3b, 0xb6, 0x1d, 0x0a, 0x87, 0xa0, 0xde, 0x56, 0xc6, 0x03, 0x97, 0x1a, 0x2b, 0x8a, - 0xdf, 0xb5, 0x7d, 0x65, 0x12, 0x53, 0x8f, 0x69, 0x78, 0xaa, 0x9d, 0x48, 0x79, 0x78, 0x8f, 0x3d, 0x84, 0x1f, 0xf9, - 0x25, 0x0b, 0x1f, 0xe0, 0xd7, 0xd8, 0xac, 0xcb, 0x69, 0x92, 0x82, 0x59, 0x35, 0xe1, 0x7c, 0x16, 0x6c, 0x6d, 0x5d, - 0x5c, 0x5c, 0xf8, 0x17, 0xdb, 0x7e, 0x96, 0x9f, 0x6d, 0x75, 0xdb, 0xed, 0x36, 0x7e, 0x44, 0xcb, 0xb6, 0xce, 0x63, - 0x76, 0xf1, 0x14, 0xdc, 0x0f, 0xfb, 0xb1, 0xf5, 0xc4, 0x7a, 0xbc, 0x6d, 0xed, 0x3c, 0xb2, 0x2d, 0x52, 0x00, 0x50, - 0xb2, 0x6d, 0x5b, 0x42, 0x01, 0x84, 0x36, 0x14, 0xf7, 0x77, 0xcf, 0x94, 0x0d, 0x87, 0x97, 0x14, 0x84, 0x85, 0x04, - 0xfe, 0x5b, 0xf6, 0x89, 0xd5, 0xb7, 0xba, 0x28, 0x6b, 0x49, 0x35, 0xa2, 0x5e, 0x71, 0xbf, 0x0f, 0xa3, 0x59, 0x40, - 0x6c, 0x64, 0x16, 0x62, 0x98, 0x4c, 0x94, 0xd2, 0x14, 0x68, 0x97, 0x9e, 0xc2, 0x13, 0x66, 0xb5, 0x59, 0xf0, 0xfc, - 0xa6, 0xfb, 0x18, 0x74, 0xdc, 0x79, 0xeb, 0xe1, 0xb0, 0xdd, 0xea, 0x58, 0x9d, 0x56, 0xd7, 0x7f, 0x6c, 0x75, 0xc5, - 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, 0xfd, - 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, 0xb8, - 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, 0xd0, - 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, 0xd8, - 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0x77, 0xbe, 0xfd, 0x64, - 0x08, 0x1a, 0xc1, 0xc2, 0x7f, 0xf0, 0xdf, 0x64, 0xa7, 0x3b, 0x14, 0x2f, 0x6d, 0xac, 0xff, 0xb6, 0xf3, 0xb8, 0x80, - 0xa6, 0xf8, 0xdf, 0x2f, 0xda, 0x84, 0x46, 0x03, 0xde, 0x1c, 0xf7, 0x21, 0xd0, 0xe8, 0xc9, 0xa4, 0xeb, 0x7f, 0x7e, - 0xfe, 0xd8, 0x7f, 0x32, 0xe9, 0x3c, 0xfe, 0x56, 0xbc, 0x25, 0x40, 0xc1, 0xcf, 0xf1, 0xdf, 0xb7, 0xdb, 0xed, 0x49, - 0xab, 0xe3, 0x3f, 0x39, 0xdf, 0xf6, 0xb7, 0x93, 0xd6, 0x23, 0xff, 0x09, 0xfe, 0xab, 0x86, 0x9b, 0x64, 0x53, 0x66, - 0x5b, 0xb8, 0xde, 0x0d, 0xbf, 0xd7, 0x9c, 0xa3, 0xfb, 0xd0, 0xda, 0x79, 0xf8, 0xf2, 0x09, 0xac, 0xd1, 0xa4, 0xd3, - 0x85, 0xff, 0x5f, 0xf7, 0xf8, 0x2d, 0x12, 0x5e, 0x0e, 0x1c, 0x31, 0x4c, 0x2f, 0x56, 0x84, 0xa3, 0x0f, 0xba, 0x3d, - 0xf0, 0xfe, 0xb4, 0x2e, 0x00, 0xc2, 0xf8, 0xad, 0x01, 0x10, 0xce, 0xef, 0x16, 0x01, 0xa1, 0x5f, 0x1b, 0xf8, 0x1d, - 0x23, 0x20, 0x7f, 0x6a, 0x06, 0xb9, 0x2f, 0xd9, 0x52, 0xa0, 0xa3, 0xe9, 0xac, 0xbd, 0x65, 0xce, 0xe1, 0x97, 0xf8, - 0xe3, 0x06, 0x65, 0x0f, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0x97, 0xf2, 0xe2, 0x43, 0xc1, 0xd7, 0x10, - 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, 0x29, - 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, 0xd3, - 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, 0x34, - 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, 0xa6, - 0xdf, 0xcf, 0x8a, 0x79, 0xc2, 0x30, 0x9d, 0x66, 0x28, 0x3e, 0x20, 0x0b, 0x8f, 0xf2, 0xae, 0x21, 0xa6, 0xb0, 0x7f, - 0x83, 0xe9, 0xf7, 0xea, 0xec, 0x60, 0x8a, 0x71, 0x84, 0x37, 0x6c, 0x14, 0x47, 0x8e, 0xed, 0xcc, 0x60, 0x23, 0xc3, - 0x2c, 0xad, 0x5a, 0xee, 0x3b, 0xa5, 0xbd, 0xbb, 0xb6, 0xfa, 0x69, 0xa6, 0x1c, 0x3f, 0x75, 0x17, 0x1e, 0xca, 0xb8, - 0xa3, 0x2d, 0x1d, 0x03, 0x18, 0x5f, 0x95, 0xe4, 0xa8, 0x03, 0x2a, 0x63, 0xc2, 0x16, 0xd6, 0x44, 0xc7, 0xef, 0x82, - 0x77, 0x41, 0xc5, 0xf8, 0xe9, 0xb0, 0xef, 0x9d, 0xd6, 0x36, 0x58, 0x3b, 0x46, 0x37, 0x3d, 0xd0, 0x91, 0xfe, 0xa5, - 0x1f, 0xfd, 0x6b, 0x74, 0xf5, 0x0b, 0x03, 0xb6, 0xe0, 0x88, 0xcf, 0x04, 0xee, 0xb6, 0xf8, 0x44, 0x83, 0x48, 0x28, - 0xc1, 0x0b, 0x73, 0x50, 0xe6, 0x98, 0xbf, 0x4a, 0x26, 0x3e, 0x4d, 0x26, 0x7e, 0x80, 0xb0, 0xac, 0x9a, 0x70, 0x77, - 0x41, 0x67, 0x23, 0xf8, 0x23, 0x9a, 0x98, 0x68, 0x8a, 0xa1, 0xf2, 0xd0, 0xa0, 0x29, 0xbe, 0xbb, 0x35, 0x22, 0x73, - 0x4f, 0x03, 0x44, 0x04, 0x0e, 0xe5, 0xdf, 0xaa, 0x58, 0x3d, 0xc8, 0xa0, 0x16, 0x38, 0xfa, 0xf8, 0xb3, 0x2f, 0xf4, - 0x67, 0x29, 0x64, 0x26, 0x02, 0x21, 0x8d, 0xd2, 0x6a, 0xa8, 0x2a, 0x34, 0x56, 0x3c, 0xbd, 0x3a, 0x90, 0xdf, 0x3c, - 0xb0, 0x31, 0x4a, 0x4d, 0xa7, 0x13, 0xd5, 0xf7, 0xd6, 0x36, 0x41, 0x35, 0xd2, 0xaf, 0xa0, 0x52, 0x82, 0x01, 0x6a, - 0x3f, 0xbc, 0x72, 0x60, 0x49, 0x2f, 0x29, 0xb4, 0x85, 0xee, 0x1b, 0xb1, 0xf3, 0x78, 0x28, 0x55, 0x98, 0x67, 0xc9, - 0xab, 0x52, 0x2d, 0x5a, 0x9a, 0xb0, 0xe3, 0x89, 0x38, 0x01, 0xbc, 0xa0, 0x06, 0x0f, 0xd3, 0xcc, 0xee, 0x3f, 0xe8, - 0xad, 0x23, 0x3e, 0xfe, 0x24, 0xeb, 0x21, 0xf8, 0xa5, 0x7f, 0x1b, 0x3e, 0xc0, 0x1f, 0x65, 0x7d, 0x70, 0x64, 0xbb, - 0x3e, 0x29, 0x80, 0x07, 0xd5, 0x2f, 0xb3, 0xa2, 0xf4, 0xdb, 0x04, 0x5d, 0xed, 0xdd, 0x55, 0x69, 0x4b, 0x05, 0xdd, - 0xdd, 0xa9, 0x14, 0x34, 0x3c, 0x1b, 0x12, 0x19, 0x94, 0x45, 0xd7, 0xdf, 0x31, 0xc4, 0xfe, 0x79, 0x0b, 0xff, 0xd6, - 0x04, 0xff, 0x43, 0x68, 0xa0, 0x24, 0xff, 0x6b, 0x68, 0xbe, 0x2d, 0x94, 0x0c, 0xf4, 0xfb, 0x81, 0xc4, 0xb2, 0x10, - 0xc9, 0xf5, 0x6d, 0xb0, 0xe2, 0xc0, 0x4c, 0x24, 0x63, 0xd8, 0x9e, 0x11, 0x5b, 0x13, 0xbb, 0x52, 0x46, 0x8e, 0x9e, - 0x43, 0x5f, 0x47, 0x7f, 0xc6, 0x7c, 0x55, 0x9d, 0x57, 0x93, 0x12, 0x2b, 0xa6, 0xc0, 0x7d, 0xdd, 0x38, 0x94, 0xeb, - 0x89, 0x3c, 0x6f, 0xfd, 0x1d, 0x94, 0xf5, 0x0c, 0x2d, 0x13, 0xc2, 0x5d, 0x43, 0x44, 0x30, 0xfa, 0xd4, 0x2a, 0x4d, - 0xf2, 0x6a, 0x54, 0x36, 0xe7, 0x07, 0xb3, 0x06, 0x7f, 0x97, 0xb2, 0xba, 0xe5, 0x23, 0xaf, 0xef, 0x62, 0xca, 0xc5, - 0x28, 0xce, 0xe9, 0x56, 0xb8, 0x02, 0xbd, 0x16, 0x78, 0xad, 0xa8, 0x44, 0x52, 0x82, 0x15, 0x03, 0x1b, 0x8b, 0xec, - 0x40, 0x26, 0x06, 0x9a, 0xdf, 0x1a, 0x37, 0xaf, 0xed, 0x8e, 0x44, 0x4e, 0x20, 0xfe, 0x16, 0x83, 0x2d, 0xe8, 0x63, - 0x83, 0xb4, 0x5d, 0xbb, 0x4b, 0xc8, 0x06, 0x43, 0x5c, 0xab, 0x1f, 0xd7, 0x32, 0x05, 0x90, 0x6d, 0x12, 0x5a, 0x8f, - 0x4b, 0x24, 0x74, 0x25, 0x9d, 0x4e, 0x59, 0xc4, 0xfd, 0x28, 0xa5, 0xfc, 0x2d, 0xc7, 0x10, 0x53, 0x5e, 0x87, 0x6d, - 0xbb, 0x25, 0xc8, 0x46, 0xe3, 0xd7, 0xc7, 0xe4, 0xee, 0x86, 0x42, 0xfd, 0xe5, 0xab, 0x7a, 0x2e, 0xf6, 0xa4, 0xdb, - 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, 0xe4, 0xc1, 0x8b, 0x54, 0x96, 0x50, 0xa4, 0xb2, - 0x58, 0x22, 0x01, 0x4e, 0xe4, 0x2e, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, 0xa5, 0x43, 0x11, 0x7a, 0x9c, 0x82, 0x97, 0x13, - 0xe3, 0xf7, 0xe9, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x59, 0x41, 0xca, 0xae, 0xe1, 0xa9, 0x0a, 0x54, 0x82, - 0x35, 0xc2, 0x54, 0x82, 0x90, 0x1c, 0x4a, 0xe7, 0x25, 0x2f, 0xb7, 0x2e, 0xe6, 0xa7, 0x53, 0x90, 0x93, 0x2a, 0xa9, - 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x49, 0x55, 0xdf, 0x0e, 0x6f, 0xfc, 0xce, 0xaa, 0xc0, - 0x5e, 0xea, 0x05, 0xcc, 0x49, 0x99, 0x6c, 0x1b, 0x39, 0x29, 0x46, 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, - 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x9b, 0xad, 0x5a, 0x4e, 0x0e, 0x28, 0xbf, 0x5c, 0xdc, 0xeb, 0x90, 0x00, 0xc3, 0x0a, - 0x02, 0x4c, 0xd2, 0x04, 0xb0, 0xe8, 0xe8, 0xdb, 0xde, 0x69, 0xab, 0xb4, 0x5d, 0x28, 0xc3, 0x0d, 0x29, 0xba, 0x18, - 0x93, 0xd4, 0xc2, 0xbf, 0x93, 0x4e, 0x7f, 0x37, 0x92, 0xc6, 0x25, 0x0a, 0x8f, 0x02, 0xa4, 0x07, 0x74, 0x46, 0x0b, - 0xce, 0x8f, 0xb3, 0xad, 0x0b, 0x76, 0xda, 0x8a, 0x66, 0x71, 0x15, 0x6b, 0x45, 0x53, 0x43, 0x4f, 0x99, 0x55, 0x33, - 0xe1, 0x63, 0xd4, 0x40, 0x92, 0x04, 0x77, 0x29, 0x03, 0xb9, 0x64, 0xa1, 0x03, 0x0b, 0x01, 0x85, 0x49, 0xae, 0xab, - 0x80, 0xaf, 0xd4, 0xb8, 0xa5, 0xdd, 0xff, 0xcb, 0x3f, 0xff, 0x6f, 0x19, 0xc3, 0x05, 0xaa, 0x74, 0xd4, 0x58, 0x0d, - 0x42, 0x97, 0xbb, 0x98, 0x02, 0x55, 0x9d, 0xf2, 0xb2, 0xcb, 0xd6, 0x59, 0x1e, 0x8f, 0x5a, 0x93, 0x28, 0x19, 0x03, - 0x60, 0x6b, 0x09, 0x64, 0x26, 0x48, 0x48, 0xa8, 0xeb, 0x45, 0xc8, 0x82, 0xbf, 0x29, 0x11, 0x5b, 0x25, 0xc0, 0xd3, - 0x6e, 0x35, 0xd3, 0xb2, 0xab, 0x0d, 0x55, 0x4b, 0xcd, 0x56, 0x3f, 0x5c, 0xa6, 0x84, 0x5a, 0x2d, 0x2f, 0x1b, 0x5a, - 0xea, 0xc3, 0xa8, 0x7f, 0xff, 0x97, 0x7f, 0xf8, 0x1f, 0xea, 0x15, 0xcf, 0x98, 0xfe, 0xf2, 0x4f, 0x7f, 0x87, 0x29, - 0xd0, 0x96, 0x3e, 0x87, 0x22, 0x39, 0x61, 0x55, 0x87, 0x50, 0x42, 0x60, 0x58, 0x95, 0xd3, 0x57, 0xcf, 0xdf, 0xde, - 0xa7, 0x09, 0x69, 0xb3, 0x49, 0xe8, 0x68, 0xd3, 0x96, 0x15, 0x8f, 0xd4, 0x48, 0x4e, 0xbc, 0x08, 0x95, 0x48, 0xef, - 0x3b, 0x25, 0x47, 0xf9, 0x7a, 0x35, 0x16, 0x2a, 0x42, 0x88, 0x25, 0x65, 0x55, 0x6e, 0x61, 0xe8, 0x7e, 0x81, 0xaf, - 0x41, 0xd7, 0x28, 0xa6, 0xc5, 0xab, 0xf5, 0xe9, 0xfd, 0x34, 0x07, 0xf8, 0xc7, 0x48, 0x71, 0x11, 0x87, 0xa4, 0x63, - 0xe9, 0x16, 0xda, 0x7c, 0xc9, 0x55, 0x49, 0xa3, 0x08, 0x47, 0xf1, 0xe1, 0x93, 0xbf, 0x29, 0xff, 0x38, 0x45, 0xcb, - 0xca, 0x72, 0xa6, 0xd1, 0xa5, 0x74, 0x1f, 0x1f, 0xb5, 0xdb, 0xb3, 0x4b, 0x77, 0x51, 0xcd, 0xe0, 0xad, 0x9b, 0x8c, - 0x62, 0x97, 0xe6, 0x80, 0x74, 0x9e, 0xad, 0xc3, 0xa4, 0xe0, 0x31, 0xb5, 0x31, 0xaa, 0x56, 0x96, 0x7f, 0x58, 0x50, - 0xa4, 0x2e, 0xfe, 0x05, 0xcf, 0x9d, 0x65, 0x50, 0x13, 0x4a, 0x0c, 0x2c, 0x16, 0x46, 0xaf, 0xae, 0xe8, 0x35, 0xe9, - 0x2c, 0xa7, 0x0d, 0x99, 0xe7, 0xe6, 0xe6, 0x89, 0xf7, 0x43, 0x3c, 0xc3, 0x9e, 0x74, 0xbc, 0x49, 0x77, 0xa1, 0x87, - 0xe7, 0x3c, 0x9b, 0x9a, 0x07, 0xe5, 0x2c, 0x62, 0x43, 0x36, 0x56, 0xc1, 0x60, 0x59, 0x2f, 0x0e, 0xc1, 0xcb, 0xc9, - 0xf6, 0x8a, 0xb9, 0x24, 0x48, 0x74, 0x40, 0x0e, 0xf0, 0x7c, 0x86, 0x1b, 0x10, 0xe8, 0x9f, 0x45, 0x3c, 0x20, 0x7e, - 0xed, 0x99, 0xc7, 0xed, 0x11, 0x4a, 0x99, 0x6c, 0x61, 0xc0, 0xd3, 0x13, 0x4d, 0x31, 0x2c, 0x5b, 0x4f, 0xdb, 0x2a, - 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0xa2, 0x3a, 0xdf, 0xca, 0x53, 0xec, 0xa7, 0xb5, 0x70, 0x88, 0x54, 0x31, 0x5d, 0xd7, - 0x5b, 0x59, 0x2f, 0x34, 0xb5, 0xa8, 0xfd, 0x16, 0x0c, 0x30, 0x02, 0xd3, 0x6e, 0xb6, 0xa2, 0x42, 0x6c, 0xf5, 0x34, - 0xfc, 0x56, 0xbb, 0x3e, 0xd1, 0x6c, 0x46, 0x0d, 0x5d, 0x60, 0x62, 0x32, 0x58, 0x51, 0x76, 0x50, 0x86, 0x86, 0x48, - 0x88, 0x90, 0x6d, 0xe4, 0x46, 0x10, 0x4f, 0x32, 0x55, 0x02, 0x7f, 0x72, 0xa2, 0xff, 0xff, 0x00, 0x69, 0x5b, 0x88, - 0x58, 0x18, 0x7f, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, + 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x10, 0x4a, 0xad, 0x02, 0xae, 0x40, 0x88, 0xa4, 0x6a, 0x33, 0x28, 0x90, 0x57, 0xb5, + 0xd8, 0x55, 0x76, 0x6d, 0x2e, 0xa9, 0xec, 0x6b, 0xcb, 0xb4, 0x04, 0x91, 0x49, 0x11, 0x2e, 0x10, 0xa0, 0x81, 0xa4, + 0x16, 0x53, 0xe8, 0x33, 0x4f, 0xf3, 0xd4, 0xe7, 0xcc, 0xd6, 0x0f, 0xfd, 0x30, 0x7d, 0xba, 0x1f, 0xe6, 0x23, 0xe6, + 0xb9, 0x3f, 0xe5, 0xfe, 0xc0, 0xf4, 0x27, 0x4c, 0x44, 0xe4, 0x82, 0x04, 0x17, 0x49, 0x5e, 0xba, 0xe7, 0xd8, 0x2a, + 0x12, 0xb9, 0x46, 0x44, 0x46, 0xc6, 0x96, 0x91, 0xe0, 0xde, 0xc6, 0x30, 0x1b, 0xf0, 0xab, 0x29, 0xb3, 0xc6, 0x7c, + 0x92, 0x74, 0xf7, 0xe4, 0xbf, 0x2c, 0x1a, 0x76, 0xf7, 0x92, 0x38, 0xfd, 0x64, 0xe5, 0x2c, 0x09, 0xe3, 0x41, 0x96, + 0x5a, 0xe3, 0x9c, 0x8d, 0xc2, 0x61, 0xc4, 0xa3, 0x20, 0x9e, 0x44, 0x67, 0xcc, 0xda, 0xe9, 0xee, 0x4d, 0x18, 0x8f, + 0xac, 0xc1, 0x38, 0xca, 0x0b, 0xc6, 0xc3, 0x8f, 0x87, 0x9f, 0x37, 0x9e, 0x74, 0xf7, 0x8a, 0x41, 0x1e, 0x4f, 0xb9, + 0x85, 0x43, 0x86, 0x93, 0x6c, 0x38, 0x4b, 0x58, 0xf7, 0x3c, 0xca, 0xad, 0x17, 0x3c, 0x7c, 0x77, 0xfa, 0x13, 0x1b, + 0x70, 0x7f, 0xc8, 0x46, 0x71, 0xca, 0xde, 0xe7, 0xd9, 0x94, 0xe5, 0xfc, 0xca, 0x3b, 0x58, 0x5d, 0x11, 0xb3, 0xc2, + 0x7b, 0xa6, 0xab, 0xce, 0x18, 0x7f, 0x77, 0x91, 0xaa, 0x3e, 0xcf, 0x99, 0x98, 0x24, 0xcb, 0x0b, 0xaf, 0x58, 0xd3, + 0xe6, 0xe0, 0x6a, 0x72, 0x9a, 0x25, 0x85, 0xf7, 0x49, 0xd7, 0x4f, 0xf3, 0x8c, 0x67, 0x08, 0x96, 0x3f, 0x8e, 0x0a, + 0xa3, 0xa5, 0xf7, 0x6e, 0x45, 0x93, 0xa9, 0xac, 0x7c, 0x55, 0xbc, 0x48, 0x67, 0x13, 0x96, 0x47, 0xa7, 0x09, 0xf3, + 0x72, 0x1e, 0x3a, 0xdc, 0x63, 0x5e, 0xec, 0x86, 0x5d, 0x66, 0xc5, 0xa9, 0xc5, 0x7b, 0x2f, 0x38, 0x95, 0xcc, 0x99, + 0x6e, 0x15, 0x6c, 0x34, 0x3d, 0x20, 0xd7, 0x28, 0x3e, 0x9b, 0xe9, 0xe7, 0x8b, 0x3c, 0xe6, 0xea, 0xfb, 0x79, 0x94, + 0xcc, 0x58, 0x10, 0x97, 0x6e, 0xc0, 0x8f, 0x58, 0x3f, 0x8c, 0xbd, 0x4f, 0x34, 0x28, 0x0c, 0x39, 0x1f, 0x65, 0xb9, + 0x83, 0xb4, 0x8a, 0x71, 0x6c, 0x76, 0x7d, 0xed, 0xb0, 0x70, 0x5e, 0xba, 0xee, 0x27, 0xee, 0x0f, 0xa2, 0x24, 0x71, + 0x70, 0xe2, 0xad, 0xad, 0x1c, 0x67, 0x8c, 0x3d, 0x76, 0x14, 0xf7, 0xdd, 0x4e, 0x3c, 0x72, 0x0a, 0xee, 0x56, 0xfd, + 0xb2, 0x91, 0x55, 0x70, 0x87, 0xb9, 0xee, 0xbb, 0xf5, 0x7d, 0x72, 0xc6, 0x67, 0x39, 0xc0, 0x5e, 0x7a, 0xef, 0xd4, + 0xcc, 0x07, 0x58, 0xff, 0x8c, 0x3a, 0x76, 0x00, 0xf6, 0x82, 0x5b, 0x9f, 0x87, 0x17, 0x71, 0x3a, 0xcc, 0x2e, 0xfc, + 0x83, 0x71, 0x04, 0x1f, 0x1f, 0xb2, 0x8c, 0x6f, 0x6d, 0x39, 0xe7, 0x59, 0x3c, 0xb4, 0x9a, 0x61, 0x68, 0x56, 0x5e, + 0x3d, 0x3b, 0x38, 0xb8, 0xbe, 0x5e, 0x28, 0xf0, 0xd3, 0x88, 0xc7, 0xe7, 0x4c, 0x74, 0x06, 0x00, 0x6c, 0xf8, 0x9c, + 0x72, 0x36, 0x3c, 0xe0, 0x57, 0x09, 0x94, 0x32, 0xc6, 0x0b, 0x1b, 0x70, 0x7c, 0x9e, 0x0d, 0x80, 0x6c, 0xa9, 0x41, + 0x78, 0x68, 0x9a, 0xb3, 0x69, 0x12, 0x0d, 0x18, 0xd6, 0xc3, 0x48, 0x55, 0x8f, 0xaa, 0x91, 0xf7, 0x6d, 0x28, 0x96, + 0xd7, 0x71, 0xbd, 0x94, 0x87, 0x29, 0xbb, 0xb0, 0xde, 0x44, 0xd3, 0xce, 0x20, 0x89, 0x8a, 0xc2, 0xca, 0xf8, 0x9c, + 0x50, 0xc8, 0x67, 0x03, 0x60, 0x10, 0x42, 0x70, 0x0e, 0x64, 0xe2, 0xe3, 0xb8, 0xf0, 0x8f, 0x37, 0x07, 0x45, 0xf1, + 0x81, 0x15, 0xb3, 0x84, 0x6f, 0x86, 0xb0, 0x16, 0x6c, 0x23, 0x0c, 0xbf, 0x75, 0xf9, 0x38, 0xcf, 0x2e, 0xac, 0x17, + 0x79, 0x0e, 0xcd, 0x6d, 0x98, 0x52, 0x34, 0xb0, 0xe2, 0xc2, 0x4a, 0x33, 0x6e, 0xe9, 0xc1, 0x70, 0x01, 0x7d, 0xeb, + 0x63, 0xc1, 0xac, 0x93, 0x59, 0x5a, 0x44, 0x23, 0x06, 0x4d, 0x4f, 0xac, 0x2c, 0xb7, 0x4e, 0x60, 0xd0, 0x13, 0x58, + 0xb2, 0x82, 0xc3, 0xae, 0xf1, 0x6d, 0xb7, 0x43, 0x73, 0x41, 0xe1, 0x21, 0xbb, 0xe4, 0x21, 0x2f, 0x81, 0x31, 0x61, + 0x55, 0x14, 0x1a, 0x8e, 0x3b, 0x4f, 0xa0, 0x00, 0xc0, 0x26, 0x96, 0x75, 0xcc, 0xc6, 0x7a, 0x71, 0x3e, 0xdf, 0xda, + 0xd2, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0x62, 0xa1, 0xad, 0x27, 0x10, 0xaf, 0x91, 0xc8, 0xf5, 0xb8, 0x2f, 0xc9, 0x77, + 0x70, 0x95, 0x0e, 0xea, 0x63, 0x43, 0x65, 0xc9, 0xb3, 0x03, 0x9e, 0xc7, 0xe9, 0x19, 0x00, 0xa1, 0xd8, 0xc0, 0x68, + 0x52, 0x96, 0x62, 0xf1, 0xdf, 0x03, 0xd4, 0x61, 0x17, 0x47, 0xcf, 0xb8, 0x63, 0x17, 0xd4, 0xc3, 0x06, 0x40, 0x80, + 0xf4, 0xc0, 0x60, 0xbc, 0xc7, 0x03, 0xbe, 0x6d, 0xdb, 0xde, 0xb7, 0xae, 0x77, 0x81, 0x1c, 0xe4, 0xfb, 0x3e, 0xb1, + 0xaf, 0xe8, 0x1c, 0x87, 0x2d, 0x04, 0xda, 0x4f, 0x58, 0x7a, 0xc6, 0xc7, 0x3d, 0x7e, 0xd4, 0xec, 0x07, 0x0c, 0xa0, + 0x1a, 0xce, 0x06, 0xcc, 0x41, 0x7e, 0xf4, 0x0a, 0xdc, 0x3e, 0xdb, 0x0e, 0x4c, 0x81, 0x0b, 0xb3, 0x41, 0x38, 0xd6, + 0x96, 0xc6, 0x55, 0xb0, 0x29, 0xc0, 0x90, 0xcf, 0x6d, 0xd8, 0x61, 0xa7, 0x2c, 0x37, 0xe0, 0xd0, 0xcd, 0x3a, 0xb5, + 0x15, 0x9c, 0xc1, 0x0a, 0x41, 0x3f, 0x6b, 0x34, 0x4b, 0x07, 0x3c, 0x06, 0xc1, 0x65, 0x6f, 0x03, 0xb8, 0x62, 0xe5, + 0xf4, 0xc2, 0xd9, 0x6e, 0xe9, 0x3a, 0xb1, 0xbb, 0xcd, 0x8f, 0x8a, 0xed, 0x56, 0xdf, 0x43, 0x28, 0x35, 0xf1, 0x25, + 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0xb9, 0xde, 0x9e, 0x9f, 0xf7, 0xb8, 0xbf, 0xcc, 0xc7, 0x21, 0xf3, 0x27, 0xd1, + 0x14, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x40, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, 0x16, 0x70, 0x81, 0x20, + 0xb0, 0x67, 0x5f, 0x44, 0x83, 0x31, 0x6c, 0xf1, 0x8a, 0x70, 0x43, 0xb5, 0x1d, 0x06, 0x39, 0x8b, 0x38, 0x7b, 0x91, + 0x30, 0x7c, 0xc2, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0x15, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, 0xc1, 0x3c, 0x1d, 0xc1, + 0x24, 0xc0, 0xc5, 0xc5, 0xd6, 0x56, 0x8c, 0x2c, 0xb2, 0xcf, 0x61, 0xb5, 0x4e, 0x67, 0x9c, 0x01, 0xbd, 0xb0, 0x85, + 0x0d, 0xd4, 0xf6, 0x62, 0x9f, 0x03, 0x11, 0x9f, 0x65, 0x29, 0x87, 0xe1, 0x00, 0x5e, 0xcd, 0x41, 0x7e, 0x34, 0x9d, + 0xb2, 0x74, 0xf8, 0x6c, 0x1c, 0x27, 0x43, 0xa0, 0x46, 0x09, 0xf8, 0x26, 0x3c, 0x04, 0x3c, 0x01, 0x99, 0xe0, 0x66, + 0x8c, 0x68, 0xf9, 0x90, 0x91, 0x59, 0x68, 0xdb, 0x1d, 0x94, 0x40, 0x12, 0x0b, 0x94, 0x41, 0xb4, 0x70, 0x1f, 0x40, + 0xf4, 0x17, 0x2e, 0xdb, 0x0e, 0x63, 0xbd, 0x8c, 0x92, 0xc0, 0xef, 0x51, 0xd2, 0x00, 0xfd, 0x81, 0x10, 0xbc, 0x83, + 0x82, 0xeb, 0x4b, 0x29, 0x75, 0x22, 0xae, 0x30, 0x04, 0x02, 0x0c, 0x50, 0x82, 0x48, 0x1a, 0xbc, 0xcf, 0x92, 0xab, + 0x51, 0x9c, 0x24, 0x07, 0xb3, 0xe9, 0x34, 0xcb, 0xb9, 0xf7, 0x55, 0x38, 0xe7, 0x59, 0x85, 0x2b, 0x6d, 0xf2, 0xe2, + 0x22, 0xe6, 0x48, 0x50, 0x77, 0x3e, 0x88, 0x60, 0xa9, 0x9f, 0x66, 0x59, 0xc2, 0xa2, 0x14, 0xd0, 0xe0, 0x3d, 0xdb, + 0x0e, 0xd2, 0x59, 0x92, 0x74, 0x4e, 0x61, 0xd8, 0x4f, 0x1d, 0xaa, 0x16, 0x12, 0x3f, 0xa0, 0xef, 0xfb, 0x79, 0x1e, + 0x5d, 0x41, 0x43, 0x6c, 0x03, 0xec, 0x05, 0xab, 0xf5, 0xe5, 0xc1, 0xbb, 0xb7, 0xbe, 0x60, 0xfc, 0x78, 0x74, 0x05, + 0x80, 0x96, 0x95, 0xd4, 0x1c, 0xe5, 0xd9, 0x64, 0x61, 0x6a, 0xa4, 0x43, 0x1c, 0xf2, 0xce, 0x1a, 0x10, 0x62, 0x1a, + 0x19, 0x56, 0x89, 0x9b, 0x10, 0xbc, 0x25, 0x7e, 0x96, 0x95, 0xb8, 0x07, 0x7a, 0xf8, 0x25, 0x10, 0xc5, 0x30, 0xe5, + 0x2d, 0xd0, 0xe6, 0x57, 0xf3, 0x38, 0x24, 0x38, 0xa7, 0xa8, 0x7f, 0x11, 0xc6, 0x41, 0x04, 0xb3, 0xcf, 0xc5, 0x80, + 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xac, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x16, 0x86, 0xa0, 0x60, 0x38, 0x3c, + 0xb8, 0xde, 0xd7, 0xe1, 0x3c, 0x52, 0xf8, 0xa0, 0x86, 0xc2, 0xfd, 0x15, 0x08, 0x39, 0x81, 0x9a, 0xec, 0x1c, 0xf4, + 0x20, 0xc0, 0xf9, 0x95, 0x07, 0xfa, 0x3f, 0x41, 0x28, 0x36, 0x5a, 0x1e, 0x68, 0xd0, 0x67, 0xe3, 0x28, 0x3d, 0x63, + 0xc3, 0x60, 0xcc, 0x4b, 0x29, 0x79, 0xf7, 0x2d, 0x58, 0x63, 0x60, 0xa7, 0xc2, 0x7a, 0x79, 0xf8, 0xe6, 0xb5, 0x5c, + 0xb9, 0x9a, 0x30, 0x86, 0x45, 0x9a, 0x81, 0x5a, 0x05, 0xb1, 0x2d, 0xc5, 0xf1, 0x0b, 0x2d, 0xbd, 0x45, 0x49, 0x5c, + 0x7c, 0x9c, 0x82, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, 0x39, 0xcc, 0x27, 0x2a, 0x86, 0xba, + 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x63, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x07, 0x56, 0x34, 0x1c, 0xbe, 0x4a, 0x63, + 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x8e, 0x3c, 0xc6, 0x3a, 0x72, 0x11, 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, + 0xc8, 0x6e, 0x10, 0x31, 0x84, 0xb4, 0x4c, 0xc2, 0xa3, 0xbe, 0x04, 0x2f, 0xf1, 0xa7, 0xb3, 0x62, 0x8c, 0x84, 0x95, + 0x03, 0xa3, 0x20, 0xcf, 0x4e, 0x0b, 0x96, 0x9f, 0xb3, 0xa1, 0xe6, 0x80, 0x02, 0xb0, 0xa2, 0xe6, 0x60, 0xbc, 0xd0, + 0x8c, 0x8e, 0xd2, 0xa1, 0x1c, 0x86, 0xea, 0x98, 0x62, 0x96, 0x49, 0x66, 0xd6, 0x16, 0x8e, 0x96, 0x02, 0x8e, 0x30, + 0x2a, 0xa4, 0x24, 0x28, 0x42, 0x85, 0xe1, 0x18, 0xa4, 0x10, 0x73, 0x6b, 0xdb, 0x5c, 0x69, 0xb2, 0x17, 0x33, 0x52, + 0x09, 0x05, 0x74, 0x84, 0x8d, 0x4c, 0x90, 0x16, 0x2e, 0xec, 0x2a, 0x90, 0xf2, 0x12, 0x5c, 0x21, 0x45, 0x94, 0x99, + 0x83, 0x0c, 0x10, 0x7e, 0x4d, 0xba, 0x90, 0xf9, 0xd8, 0x82, 0x21, 0x1b, 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, + 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0x6f, 0x83, 0xf9, 0x69, 0xb6, 0x3f, 0x18, 0xb0, 0xa2, 0xc8, + 0xf2, 0xad, 0xad, 0x0d, 0x6a, 0xbf, 0xce, 0xd0, 0x02, 0x4a, 0xba, 0x5a, 0xd6, 0xd9, 0x05, 0x69, 0x70, 0x53, 0xad, + 0x28, 0x9d, 0x1e, 0xd8, 0xc7, 0xc7, 0x20, 0xb3, 0x3d, 0x49, 0x06, 0xa0, 0xfa, 0xb2, 0xe1, 0x27, 0xec, 0x99, 0x3a, + 0x65, 0x56, 0xda, 0x97, 0x4e, 0x1d, 0x24, 0x0f, 0x86, 0x75, 0x4b, 0x63, 0x41, 0x57, 0x0e, 0x8d, 0xab, 0x21, 0x15, + 0xe4, 0xfc, 0x8c, 0x54, 0xb6, 0xb1, 0x8c, 0x60, 0xb5, 0x95, 0x1e, 0x91, 0x5e, 0x61, 0x93, 0x13, 0xa0, 0x47, 0xbc, + 0xdf, 0x91, 0xf5, 0x61, 0x21, 0x28, 0x97, 0xb3, 0x9f, 0x67, 0xac, 0xe0, 0x82, 0x75, 0x61, 0xdc, 0x1c, 0xc6, 0x2d, + 0x97, 0xac, 0xc3, 0x9a, 0xed, 0xb8, 0x0a, 0xb6, 0x77, 0x53, 0xd4, 0x63, 0x05, 0x72, 0xf2, 0xcd, 0xec, 0x44, 0xf6, + 0x84, 0x7b, 0x7d, 0xfd, 0xb5, 0x1a, 0xa4, 0x5a, 0x4a, 0x6d, 0x03, 0x2d, 0xac, 0x89, 0xad, 0x9a, 0x0c, 0x6d, 0x57, + 0x2a, 0xd4, 0x8d, 0x56, 0xa7, 0xc6, 0x07, 0xb0, 0xe7, 0x9a, 0x9a, 0xa5, 0x2b, 0x63, 0xfb, 0xbd, 0xa2, 0xe9, 0x3b, + 0x31, 0x32, 0x59, 0xa3, 0xfc, 0x76, 0xee, 0x51, 0x3b, 0x1e, 0xda, 0x2e, 0xd5, 0x55, 0x82, 0x61, 0x56, 0x17, 0x0c, + 0x8b, 0x50, 0x4f, 0x75, 0x17, 0x5b, 0x33, 0x15, 0x0f, 0xd5, 0x5a, 0x2b, 0x07, 0x82, 0x85, 0x47, 0x60, 0x9c, 0xac, + 0xf4, 0x0f, 0xde, 0x46, 0x13, 0x86, 0x14, 0xf5, 0xd6, 0x35, 0x90, 0x0e, 0x04, 0x34, 0xe9, 0x2f, 0xaa, 0x37, 0xe6, + 0x0a, 0xab, 0xa9, 0xbe, 0xbf, 0x62, 0xb0, 0x22, 0xc0, 0xbe, 0x2e, 0x57, 0x2c, 0x11, 0xe9, 0x4d, 0xc9, 0xce, 0x8a, + 0x3e, 0xa2, 0x4c, 0xac, 0x09, 0x29, 0x78, 0x40, 0x1e, 0x96, 0x7f, 0x61, 0xe1, 0x54, 0x2b, 0x85, 0x23, 0x43, 0x99, + 0x02, 0x74, 0x26, 0x25, 0x00, 0xe2, 0x92, 0x3e, 0x6b, 0x1b, 0x0b, 0xc9, 0x76, 0x80, 0x7c, 0xe0, 0x8f, 0x92, 0x88, + 0x3b, 0xad, 0x9d, 0xa6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, 0xf7, 0x15, 0x2a, 0x1c, 0x51, 0x89, 0x5d, + 0xe6, 0x83, 0x51, 0x34, 0x8e, 0x47, 0xdc, 0x49, 0x90, 0x79, 0xdc, 0x92, 0x25, 0xa0, 0x64, 0xf4, 0xbe, 0x02, 0x65, + 0xc1, 0x84, 0x74, 0x11, 0xd5, 0x4a, 0xa0, 0x31, 0x05, 0x29, 0x49, 0x29, 0xd2, 0x82, 0x0a, 0x02, 0x43, 0xa8, 0x74, + 0x14, 0x47, 0x81, 0x7e, 0x8b, 0x7b, 0x62, 0xd0, 0x60, 0xc9, 0xa2, 0x8c, 0x7b, 0xf1, 0x72, 0x21, 0xa8, 0x61, 0x9f, + 0x67, 0xaf, 0xb3, 0x0b, 0x96, 0x3f, 0x8b, 0x10, 0xf6, 0x40, 0x74, 0x2f, 0x41, 0xd2, 0x93, 0x40, 0xe7, 0x1d, 0xc5, + 0x2b, 0xe7, 0x84, 0x34, 0x2c, 0xc4, 0x24, 0x46, 0x45, 0x08, 0x76, 0x0b, 0xd1, 0x3e, 0xc5, 0x2d, 0x45, 0x7b, 0x0f, + 0x55, 0x09, 0xd7, 0xbc, 0xb5, 0xff, 0xba, 0xce, 0x5b, 0x30, 0xc2, 0x54, 0x71, 0x6b, 0x7d, 0xc7, 0x82, 0x7b, 0x21, + 0x74, 0xb3, 0x23, 0x79, 0xcb, 0x50, 0x66, 0xa0, 0x3f, 0xae, 0xaf, 0x2b, 0x23, 0x1d, 0x94, 0xa9, 0x96, 0xe6, 0x08, + 0x81, 0xd8, 0x12, 0x6e, 0x09, 0xca, 0x08, 0x0d, 0xaf, 0x3c, 0x4b, 0x12, 0x43, 0x17, 0x79, 0x71, 0xc7, 0x59, 0x50, + 0x47, 0x00, 0xc5, 0xa4, 0xa6, 0x91, 0x7a, 0x2c, 0xd0, 0x15, 0xa8, 0x94, 0x94, 0x36, 0xf2, 0xaa, 0xb5, 0x11, 0x10, + 0xa7, 0x43, 0x96, 0x0b, 0x07, 0x4d, 0xea, 0x50, 0x98, 0x30, 0x05, 0x86, 0x66, 0x43, 0xf4, 0x1c, 0x24, 0x02, 0x60, + 0x9e, 0xf8, 0xe3, 0xac, 0xe0, 0xba, 0xce, 0x84, 0x3e, 0xbe, 0xbe, 0x8e, 0x85, 0xbf, 0x88, 0x0c, 0x90, 0xb3, 0x49, + 0x76, 0xce, 0x56, 0x40, 0xdd, 0x51, 0x83, 0x99, 0x20, 0x1b, 0xc3, 0x80, 0x12, 0x05, 0xd5, 0x32, 0x4d, 0x62, 0xb0, + 0xf4, 0x75, 0x03, 0x1f, 0x0c, 0x3a, 0x76, 0x89, 0x32, 0xc2, 0xed, 0x76, 0xbb, 0x4d, 0xaf, 0xe5, 0x96, 0x82, 0xe0, + 0xf3, 0x25, 0x8a, 0xde, 0xa0, 0x1f, 0xa5, 0x09, 0xbe, 0x4a, 0x16, 0x30, 0xd7, 0x50, 0x8a, 0xc2, 0x4f, 0x62, 0x9e, + 0x14, 0xc4, 0xae, 0x37, 0x84, 0x41, 0x39, 0x53, 0x82, 0x1b, 0x4d, 0x5c, 0xb1, 0x6d, 0x3f, 0x68, 0xb2, 0x69, 0x76, + 0x52, 0x3b, 0x4c, 0x2d, 0x8c, 0x5c, 0xf3, 0x42, 0x7b, 0xc0, 0xe6, 0xf2, 0x90, 0x4d, 0x8f, 0xd5, 0xc0, 0xeb, 0x00, + 0xa1, 0xf0, 0x74, 0x9d, 0x25, 0x94, 0xaa, 0xce, 0x52, 0x88, 0xeb, 0x0d, 0xf4, 0x51, 0x81, 0xb9, 0x8a, 0x04, 0x07, + 0x52, 0x20, 0x30, 0xf4, 0xc8, 0xc4, 0x7a, 0x3d, 0x83, 0xe5, 0x39, 0x8d, 0x06, 0x9f, 0x34, 0xb8, 0x15, 0xef, 0x2d, + 0xb2, 0x81, 0xb3, 0x50, 0x12, 0x1a, 0xe2, 0xca, 0xc4, 0x5b, 0x49, 0xe8, 0xda, 0x46, 0x01, 0x87, 0x6c, 0x89, 0xed, + 0x17, 0x17, 0x7a, 0x91, 0xdb, 0x25, 0x7b, 0x28, 0xff, 0xa9, 0xe2, 0x92, 0xf5, 0x2c, 0xc7, 0x94, 0x34, 0x60, 0x8a, + 0xf1, 0x60, 0x69, 0x16, 0x20, 0x01, 0xbe, 0x2b, 0x87, 0x71, 0xb1, 0x9e, 0x04, 0x7f, 0x28, 0x98, 0xcf, 0x8d, 0x99, + 0x6e, 0x85, 0x54, 0x4b, 0x38, 0x69, 0x06, 0x6b, 0xd0, 0xa4, 0xf1, 0xa0, 0x44, 0xcd, 0x57, 0x68, 0xa8, 0x10, 0xc7, + 0x9f, 0x89, 0x2a, 0x34, 0xc1, 0x10, 0x8c, 0xc2, 0xcb, 0x25, 0xc3, 0xa5, 0xcb, 0xa2, 0x45, 0xca, 0xd4, 0x98, 0x54, + 0xaa, 0x66, 0xb9, 0x14, 0x0c, 0x2c, 0xda, 0xad, 0xbe, 0xb4, 0xc4, 0x95, 0xc8, 0xcd, 0x42, 0x2d, 0x4c, 0x72, 0xe5, + 0x4d, 0x38, 0x05, 0xfa, 0x5d, 0xca, 0x7a, 0x37, 0xf1, 0x29, 0x14, 0x3e, 0x85, 0x6f, 0xf8, 0x50, 0x26, 0x6f, 0xe7, + 0x3d, 0x30, 0xf7, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, 0x74, 0x41, 0xa0, 0x48, 0x36, 0xc9, 0x7a, + 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xea, 0x8a, 0x0d, 0x52, 0xf3, 0x4a, 0x53, 0x2f, 0x73, 0x17, 0xec, 0xf7, + 0xb2, 0x94, 0x74, 0x62, 0x82, 0x32, 0xb1, 0x77, 0x13, 0x6d, 0xbc, 0x2c, 0x4c, 0x85, 0xf5, 0x2b, 0x8c, 0x9d, 0x1a, + 0x85, 0x32, 0x29, 0x02, 0x71, 0x6c, 0x7c, 0xac, 0x2c, 0x83, 0xd4, 0x5f, 0x61, 0x4f, 0x01, 0x28, 0x09, 0x2c, 0xbe, + 0xa6, 0x92, 0x17, 0x85, 0x75, 0x3a, 0x6e, 0x10, 0x1d, 0x2b, 0x11, 0x5a, 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, + 0x25, 0x34, 0x29, 0x59, 0xf4, 0x8a, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, 0x25, 0xbd, 0x84, 0x1c, 0xd2, 0x65, 0xa2, + 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x09, 0x89, 0x96, 0xf5, 0xc3, 0x08, 0xc5, 0x86, 0x58, 0x8b, 0x25, 0x42, 0x2e, 0xda, + 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0x16, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, + 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x1e, 0x73, 0xd7, 0x91, 0x06, 0x2f, 0xac, 0x59, 0x4f, 0xc9, 0xde, + 0xfd, 0xd7, 0xd8, 0x8a, 0xec, 0xcf, 0xaa, 0xa4, 0xf2, 0x14, 0x6a, 0x9c, 0x5b, 0x5f, 0xa7, 0x5a, 0x68, 0x51, 0x55, + 0x1c, 0x18, 0x52, 0xfd, 0x40, 0x29, 0xec, 0x0a, 0xe5, 0x03, 0x39, 0x74, 0xec, 0xba, 0x6e, 0x50, 0x90, 0xf3, 0xb2, + 0xb1, 0xca, 0x85, 0xdc, 0xda, 0x32, 0x7d, 0xa6, 0x73, 0x3d, 0xfc, 0x33, 0x07, 0x95, 0x73, 0x71, 0x95, 0x92, 0x05, + 0xf3, 0x4c, 0xa9, 0xa3, 0x25, 0x07, 0xb4, 0xd9, 0x41, 0x4f, 0x3b, 0xba, 0x88, 0x62, 0x6e, 0xe9, 0x51, 0x84, 0xa7, + 0x8d, 0xf2, 0x49, 0x1a, 0x1d, 0x80, 0x17, 0x9a, 0x90, 0xe4, 0x84, 0x9b, 0xb6, 0x68, 0x31, 0x18, 0x33, 0x0c, 0x81, + 0x2b, 0x7b, 0xc2, 0x94, 0x3d, 0x1b, 0x88, 0xb7, 0x1c, 0x78, 0x35, 0xec, 0xe5, 0x62, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, + 0x04, 0xb2, 0x6d, 0xa2, 0xea, 0xca, 0x85, 0x67, 0x29, 0x22, 0x31, 0xc2, 0xb6, 0x6a, 0x6c, 0x69, 0xeb, 0x77, 0x16, + 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x05, 0x3d, 0xac, 0xdc, 0x1c, 0x6e, 0x3a, 0xf2, 0x62, 0x05, 0xdd, 0x8e, + 0x08, 0x0a, 0x81, 0x13, 0xa1, 0xec, 0x41, 0xcd, 0x0d, 0x44, 0x4a, 0xa6, 0xb4, 0x6a, 0x36, 0x4b, 0x86, 0x12, 0x58, + 0x70, 0x61, 0x99, 0xe4, 0xa3, 0x8b, 0x38, 0x49, 0xaa, 0xd2, 0x3f, 0x54, 0xc0, 0x8b, 0x61, 0x6f, 0x13, 0xed, 0x02, + 0xa3, 0x99, 0x02, 0xc1, 0xd5, 0x46, 0xd8, 0x47, 0xc7, 0xad, 0xd6, 0x5d, 0x44, 0x1c, 0x99, 0x19, 0x8d, 0xf8, 0x88, + 0x36, 0x64, 0xc9, 0x34, 0x6b, 0xef, 0xbf, 0xc0, 0x90, 0x9a, 0x81, 0x0f, 0xaa, 0x33, 0x2a, 0xfe, 0x55, 0xf6, 0xd4, + 0xaf, 0x44, 0xef, 0x56, 0xd5, 0xb5, 0x18, 0x50, 0x51, 0x81, 0x0f, 0x33, 0xc4, 0xd2, 0x54, 0x81, 0x80, 0x5c, 0x0f, + 0xeb, 0x70, 0xb7, 0x46, 0x1a, 0x2c, 0x28, 0x05, 0xd6, 0x5a, 0xd9, 0xbd, 0xbe, 0x2d, 0x98, 0x43, 0xa1, 0x70, 0xd1, + 0xff, 0x59, 0x36, 0x99, 0xa2, 0x65, 0xb6, 0xc0, 0xd4, 0xd0, 0xe0, 0xe3, 0x42, 0x7d, 0xb9, 0xa2, 0xac, 0xd6, 0x87, + 0x76, 0x64, 0x8d, 0x9f, 0xb4, 0xa3, 0x0c, 0x0e, 0xd5, 0x4c, 0x17, 0xd5, 0xed, 0xe6, 0x45, 0x11, 0xb3, 0x8a, 0xc7, + 0x7d, 0xd2, 0xdb, 0xda, 0x9a, 0xf4, 0x34, 0x0d, 0x48, 0x26, 0x49, 0x86, 0x37, 0x19, 0xa0, 0xac, 0x88, 0x33, 0x2f, + 0x17, 0xc8, 0x37, 0x2f, 0x4b, 0x5c, 0xbf, 0xef, 0x3b, 0xfb, 0x35, 0xcf, 0xda, 0xdb, 0x5f, 0xef, 0x22, 0x57, 0x75, + 0xd2, 0x83, 0x3c, 0xea, 0x43, 0xd1, 0x92, 0x4d, 0x19, 0xce, 0x27, 0xd9, 0x90, 0x05, 0x36, 0x74, 0x4f, 0xed, 0x52, + 0x6e, 0x9a, 0x08, 0x36, 0x07, 0xf8, 0x7f, 0xf3, 0x0f, 0xf5, 0x48, 0x6a, 0xb0, 0x0f, 0x2c, 0xa0, 0xcd, 0x85, 0x2f, + 0xc3, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x43, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, 0x01, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, + 0x7d, 0xd9, 0xfb, 0x32, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x2d, 0xbf, 0xe9, 0xb7, 0x6c, 0x15, 0x11, 0xfb, 0xc9, + 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x04, 0x4d, 0x56, 0x78, 0x03, 0x1e, 0xfe, 0xd4, 0xfb, 0x49, 0xb9, 0xd4, + 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe0, 0x79, 0xa4, 0xed, 0xcd, 0x45, 0x05, 0xc6, 0x15, 0x29, 0x2e, + 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xe6, 0xe6, 0xdc, 0x79, 0x13, 0xf1, 0xb1, 0x9f, 0x47, 0xe9, + 0x30, 0x9b, 0x38, 0xee, 0xb6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0x67, 0x6e, 0xb9, 0x79, 0xe2, 0x0d, 0x79, 0x68, + 0xf7, 0xec, 0xed, 0x63, 0xef, 0x90, 0x87, 0x27, 0x7b, 0x9b, 0xf3, 0x21, 0x2f, 0xbb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, + 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7b, 0x29, 0xc1, 0x00, 0x76, 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, + 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0x7b, 0x43, 0x3b, 0xab, 0x5b, 0x5b, 0x95, 0x9a, 0xaf, + 0x4a, 0xbd, 0x19, 0x0f, 0x6b, 0x9e, 0xba, 0xf7, 0x92, 0x8e, 0x56, 0xea, 0x1b, 0x79, 0x26, 0x82, 0x36, 0xcb, 0x76, + 0x82, 0x63, 0x6c, 0xf1, 0xd5, 0xdb, 0xfa, 0x48, 0x44, 0x29, 0xfc, 0x18, 0xac, 0x97, 0x08, 0xd4, 0x37, 0x38, 0x38, + 0xde, 0x61, 0xb8, 0xb3, 0xe7, 0xf4, 0x02, 0x67, 0xa3, 0xd1, 0xb8, 0xfe, 0x61, 0xe7, 0xe8, 0xc7, 0xa8, 0xf1, 0xcb, + 0x7e, 0xe3, 0xfb, 0xbe, 0x7b, 0xed, 0xfc, 0xb0, 0xd3, 0x3b, 0x92, 0x4f, 0x47, 0x3f, 0x76, 0x7f, 0x28, 0xfa, 0x7f, + 0x12, 0x85, 0x9b, 0xae, 0xbb, 0x73, 0xe6, 0x4d, 0x79, 0xb8, 0xd3, 0x68, 0x74, 0xe1, 0xdb, 0x19, 0x7c, 0xc3, 0xcf, + 0x53, 0xf8, 0xb8, 0x3e, 0xb2, 0xfe, 0xc3, 0x0f, 0xe9, 0x7f, 0xfc, 0x21, 0xef, 0xe3, 0x98, 0x47, 0x3f, 0xfe, 0x50, + 0xd8, 0xf7, 0xbb, 0xe1, 0x4e, 0x7f, 0xdb, 0x75, 0x74, 0xcd, 0x9f, 0xc2, 0xea, 0x2b, 0xb4, 0x3a, 0xfa, 0x51, 0x3e, + 0xd9, 0xf7, 0x4f, 0xf6, 0xba, 0x61, 0xff, 0xda, 0xb1, 0xaf, 0xef, 0xbb, 0xd7, 0xae, 0x7b, 0xbd, 0x89, 0xf3, 0x9c, + 0xc3, 0xe8, 0xf7, 0xe1, 0x73, 0x04, 0x9f, 0x36, 0x7c, 0x6e, 0xc2, 0xe7, 0x8f, 0xd0, 0x4d, 0xc4, 0xdf, 0xae, 0x29, + 0x16, 0x72, 0x8d, 0x07, 0x16, 0x11, 0xac, 0x82, 0xbb, 0xb9, 0x13, 0x7b, 0x13, 0x22, 0x1a, 0xec, 0x43, 0xdf, 0xf7, + 0x31, 0x4c, 0xea, 0xcc, 0x8f, 0x37, 0x61, 0xd1, 0x91, 0x73, 0x36, 0x03, 0xee, 0x89, 0xc8, 0x41, 0x11, 0x30, 0x71, + 0xb6, 0x5a, 0xe0, 0xe1, 0xaa, 0x37, 0x0c, 0x27, 0xdc, 0x01, 0xa3, 0xe0, 0x03, 0xc7, 0x2f, 0x6d, 0xd7, 0x7b, 0x21, + 0xcf, 0x0c, 0x71, 0x9f, 0x0b, 0xd6, 0x4a, 0x33, 0x61, 0xd2, 0xd8, 0xae, 0x37, 0x5d, 0x51, 0x09, 0xdb, 0x3a, 0x3d, + 0x83, 0xba, 0x63, 0x11, 0xa3, 0xfe, 0x96, 0x45, 0x9f, 0x70, 0x4b, 0xbe, 0x35, 0x0e, 0x81, 0x97, 0x2c, 0xf9, 0x45, + 0xa3, 0xd1, 0xb0, 0x11, 0x85, 0x3b, 0xf6, 0x94, 0xc1, 0x0c, 0x4b, 0x26, 0x22, 0x23, 0xa5, 0x29, 0x2c, 0x5b, 0x98, + 0xfc, 0x7d, 0x94, 0xf3, 0xcd, 0xca, 0xb0, 0x0d, 0xeb, 0x96, 0xec, 0x82, 0xa5, 0x7f, 0x87, 0x29, 0xd0, 0xb4, 0xa4, + 0xf3, 0x0f, 0x73, 0xfc, 0x30, 0x23, 0xb4, 0x3e, 0x38, 0x0c, 0x3c, 0xf4, 0x02, 0xe4, 0x8e, 0xe8, 0xe7, 0xbc, 0x47, + 0x35, 0x06, 0xff, 0xcb, 0x30, 0x83, 0x27, 0xe6, 0xc3, 0x10, 0xcd, 0xbc, 0xd4, 0xc1, 0xad, 0x0c, 0xc5, 0xfd, 0x2b, + 0xdc, 0x19, 0x59, 0xe9, 0x1d, 0x84, 0x6a, 0xc7, 0x1c, 0xe6, 0x8c, 0x7d, 0x1b, 0x25, 0x9f, 0x58, 0xee, 0x5c, 0x7a, + 0xad, 0xf6, 0x67, 0xd4, 0xd9, 0x43, 0xdb, 0xec, 0x4d, 0x75, 0x8c, 0xa6, 0xcd, 0x02, 0x79, 0x44, 0xd8, 0x68, 0x79, + 0x28, 0x31, 0x88, 0x04, 0xb9, 0x97, 0x86, 0x6d, 0xe2, 0x70, 0x7b, 0xaf, 0x38, 0x3f, 0xeb, 0xda, 0x81, 0x6d, 0x83, + 0xc5, 0x7f, 0x48, 0x61, 0x2b, 0x61, 0x58, 0x34, 0x3b, 0x6c, 0x2f, 0xee, 0xb0, 0xed, 0xed, 0x2a, 0xe0, 0x84, 0x07, + 0xe9, 0xd4, 0x3d, 0xf1, 0x22, 0x6f, 0x1c, 0xc2, 0x80, 0x03, 0x68, 0x86, 0x5d, 0x3a, 0x83, 0xbd, 0x58, 0x4e, 0x03, + 0xb2, 0x3e, 0xf3, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, 0x0e, 0xc0, 0xd8, 0xcf, 0x7c, 0x76, 0xc9, 0x06, 0xca, + 0xce, 0x00, 0x42, 0x45, 0x6e, 0xc7, 0x1d, 0x84, 0x46, 0x33, 0x98, 0x3b, 0x0c, 0x0f, 0x7b, 0x36, 0xec, 0x25, 0xd8, + 0x95, 0x61, 0x74, 0xd4, 0xea, 0xf7, 0xb2, 0x70, 0xca, 0x03, 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0x6a, 0xf7, 0x7b, + 0xce, 0x26, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x84, 0x11, 0x8a, 0x3c, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0x4e, 0x1d, + 0x7b, 0x6f, 0xc7, 0xde, 0xc6, 0x52, 0xcf, 0x06, 0xf6, 0x02, 0x0a, 0x86, 0xa7, 0xae, 0xd9, 0x79, 0xb7, 0x8f, 0xa0, + 0x62, 0x21, 0x4e, 0x7e, 0xda, 0xb3, 0xbb, 0x62, 0xea, 0x26, 0x0c, 0x9a, 0xc9, 0xe5, 0xc7, 0x15, 0x3d, 0x24, 0x54, + 0x55, 0x57, 0x05, 0x1d, 0x94, 0xb5, 0x03, 0x67, 0x6c, 0x22, 0xd1, 0xc0, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, + 0x30, 0xa9, 0xd1, 0x6d, 0xb7, 0xdf, 0x3b, 0x0d, 0xee, 0xdb, 0xf7, 0xd5, 0xc3, 0x08, 0x90, 0xe1, 0x62, 0xfa, 0x11, + 0x48, 0x3b, 0xfc, 0x3c, 0xe7, 0x80, 0xe4, 0x29, 0x15, 0x4d, 0x65, 0xd1, 0x19, 0x16, 0x1d, 0x06, 0x08, 0xaa, 0x97, + 0x6b, 0xeb, 0x4f, 0xac, 0xc9, 0x30, 0x24, 0xd8, 0xc1, 0x16, 0x3a, 0x62, 0xdb, 0xad, 0x3e, 0x9e, 0x37, 0xe4, 0xbc, + 0xf8, 0x36, 0xe6, 0xa0, 0x12, 0x76, 0xba, 0xb6, 0xdb, 0xb3, 0x2d, 0x5c, 0xda, 0x4e, 0xba, 0x1d, 0x0a, 0x0a, 0xc7, + 0xdb, 0x87, 0x3c, 0x18, 0x77, 0xc3, 0x66, 0xcf, 0x29, 0x64, 0xb8, 0x11, 0xcf, 0x2d, 0x85, 0x04, 0x6f, 0x7a, 0x63, + 0x10, 0xe8, 0xc8, 0xb9, 0x9b, 0xf6, 0xb6, 0x2a, 0x84, 0xa2, 0xe3, 0xed, 0xa1, 0x1b, 0xc4, 0xf0, 0xe1, 0x34, 0x90, + 0x69, 0xc6, 0xba, 0xaf, 0xd2, 0xcc, 0xcc, 0x0d, 0x86, 0xca, 0x22, 0x4f, 0xc2, 0x74, 0xdb, 0xc1, 0x08, 0x2d, 0x48, + 0xda, 0xbd, 0x1e, 0xc0, 0xb0, 0xed, 0x28, 0x4e, 0xdb, 0x51, 0xac, 0xa6, 0xec, 0xf3, 0x23, 0xbd, 0x1c, 0x03, 0xde, + 0x1b, 0xa8, 0xf3, 0x58, 0xd4, 0x3e, 0x00, 0x56, 0x90, 0x78, 0x45, 0x5f, 0x9d, 0x79, 0xbd, 0xac, 0x9d, 0x6f, 0xcd, + 0x95, 0x28, 0xe2, 0x9e, 0x21, 0xa1, 0x58, 0xa9, 0xdd, 0x30, 0x61, 0x6e, 0x4f, 0x91, 0x18, 0x9a, 0xe5, 0x43, 0xd8, + 0x63, 0xa1, 0x0a, 0xb0, 0x67, 0xe6, 0xb6, 0x48, 0xc2, 0xaa, 0xb9, 0x77, 0x04, 0xac, 0xdd, 0x0f, 0xdf, 0x08, 0x77, + 0xaa, 0xa3, 0xa2, 0xf9, 0x2c, 0x09, 0x5f, 0x2e, 0x1c, 0x17, 0x47, 0x78, 0x22, 0x74, 0xe0, 0x0f, 0x66, 0x39, 0xc8, + 0x03, 0xfe, 0x16, 0x2c, 0x83, 0x50, 0x36, 0x45, 0x47, 0x0f, 0x8f, 0x80, 0x3d, 0x42, 0x7c, 0x21, 0x6c, 0x6e, 0x54, + 0xa3, 0x45, 0x49, 0xc6, 0x0b, 0x1d, 0x0c, 0x77, 0x98, 0x74, 0xed, 0x51, 0x30, 0xc8, 0x13, 0x63, 0x07, 0xcf, 0xfc, + 0xfd, 0x01, 0x56, 0xe3, 0x04, 0x85, 0x5b, 0xd2, 0x6e, 0xab, 0xc4, 0xdf, 0x81, 0x9f, 0x82, 0x04, 0xc7, 0x3a, 0xf0, + 0xb3, 0xb6, 0xb6, 0x12, 0x89, 0xd4, 0x5e, 0xd6, 0xa1, 0x93, 0x08, 0x8c, 0x07, 0x17, 0x7e, 0x0a, 0xd5, 0x48, 0x22, + 0x2a, 0x22, 0x0b, 0xd4, 0x3c, 0x55, 0xab, 0xe0, 0x3b, 0x32, 0x23, 0xf0, 0x8c, 0x92, 0x5c, 0xd0, 0x50, 0xd4, 0x8d, + 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, + 0xb1, 0x11, 0x2b, 0x1f, 0x1f, 0xa5, 0xdb, 0xdb, 0x7d, 0x71, 0x6e, 0x41, 0x8c, 0xc3, 0x8c, 0xe8, 0x6a, 0x5c, 0x01, + 0x50, 0x9f, 0xce, 0x89, 0xeb, 0x81, 0x69, 0xc5, 0x9a, 0x2e, 0xc5, 0x3e, 0x39, 0xcc, 0x00, 0x14, 0xdc, 0x71, 0x8e, + 0xfc, 0xde, 0x9f, 0xfb, 0xe0, 0x1e, 0xfb, 0x7f, 0x72, 0x77, 0x94, 0xa0, 0xe9, 0xc8, 0x33, 0xc5, 0x39, 0x9d, 0xb1, + 0xb6, 0x3c, 0x8a, 0x8d, 0x06, 0x20, 0xf5, 0x00, 0x03, 0xd0, 0xe6, 0x20, 0x13, 0x2a, 0x0e, 0x42, 0x8e, 0x0a, 0x6c, + 0x1f, 0x37, 0x3f, 0xc3, 0x9d, 0xfd, 0x9c, 0x07, 0x60, 0xc1, 0xa8, 0xa7, 0xd7, 0xf0, 0xf4, 0x67, 0xfd, 0xf4, 0x13, + 0x0f, 0x7e, 0x29, 0x65, 0xe8, 0xbe, 0x36, 0xc5, 0x23, 0x35, 0x45, 0x29, 0x96, 0xc8, 0xa0, 0x21, 0x77, 0x97, 0x63, + 0x36, 0xcc, 0x2d, 0x81, 0x18, 0x4a, 0x74, 0x81, 0x8d, 0x16, 0x9d, 0x21, 0x71, 0x5d, 0x93, 0x14, 0x46, 0x2e, 0x81, + 0x89, 0x70, 0xc5, 0xb7, 0x48, 0x4f, 0xd6, 0x6d, 0xba, 0xf3, 0x5a, 0x5b, 0xb2, 0xef, 0xd8, 0x64, 0xca, 0xaf, 0x0e, + 0x48, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0x37, 0x3b, 0xf1, 0x1e, 0xeb, 0xc4, 0x20, 0xd5, 0x0b, 0xc5, 0x62, + 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, 0xab, 0xa1, 0xd7, 0x96, 0xe8, 0x6d, 0x6f, 0x03, 0x82, 0x1d, + 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, + 0x21, 0x77, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, 0xb0, 0x03, 0x98, 0x11, 0x97, 0x37, 0x5a, 0x22, 0x3a, 0x2c, + 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0xb7, 0x5b, 0x2e, 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, + 0xd6, 0x54, 0x2a, 0xf3, 0xed, 0xed, 0xb2, 0x7e, 0x54, 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0x72, 0x31, 0x1b, 0x84, + 0x03, 0x11, 0x13, 0x28, 0xd0, 0xd2, 0xca, 0x8a, 0x01, 0x86, 0x94, 0xe5, 0x28, 0x9f, 0x42, 0xee, 0xc5, 0x65, 0xa9, + 0x53, 0x5f, 0x9e, 0xc9, 0xa0, 0x23, 0x9e, 0x7a, 0x92, 0xb1, 0x02, 0xac, 0xe6, 0x65, 0x5e, 0x42, 0x4b, 0x04, 0x98, + 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, 0x2c, 0x51, 0xc6, 0x67, 0x1e, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, + 0x62, 0x5f, 0xb9, 0x32, 0x3a, 0xf2, 0xa3, 0xa2, 0x1f, 0x50, 0xfd, 0x4c, 0x4a, 0xb0, 0x71, 0xf8, 0x11, 0xd8, 0xa8, + 0x72, 0x3c, 0x49, 0x10, 0x3e, 0x8f, 0x73, 0x46, 0x9e, 0xc2, 0xa6, 0x84, 0x59, 0x9a, 0xb6, 0x91, 0x6a, 0x17, 0x99, + 0x41, 0x28, 0x17, 0xe6, 0x1f, 0x1b, 0x67, 0x17, 0x69, 0xb8, 0xd4, 0x1a, 0xcc, 0x8f, 0x77, 0x26, 0x40, 0xe9, 0xf5, + 0x75, 0x2a, 0x7c, 0xdc, 0x88, 0xec, 0x0d, 0x5d, 0x31, 0xee, 0x29, 0xa4, 0x02, 0x27, 0x22, 0x8b, 0x87, 0xce, 0x50, + 0x68, 0x84, 0x43, 0x3a, 0x45, 0x2e, 0x5c, 0x63, 0xd3, 0x17, 0x3d, 0xed, 0x1b, 0x65, 0xa1, 0x93, 0x80, 0x10, 0x10, + 0xb8, 0x1b, 0xd6, 0x54, 0xd6, 0xcb, 0x82, 0x84, 0x4a, 0xd1, 0xcf, 0x01, 0xfc, 0xc3, 0x48, 0x52, 0x00, 0xec, 0x87, + 0x6a, 0xa4, 0x88, 0xb2, 0x2c, 0x70, 0x01, 0x68, 0xae, 0x03, 0x5c, 0x09, 0x5f, 0x18, 0xa8, 0x30, 0x3d, 0xcd, 0xca, + 0x4a, 0xa1, 0x44, 0x9e, 0xae, 0x48, 0x59, 0x23, 0x99, 0x7c, 0x8e, 0x0e, 0x9f, 0xf2, 0xae, 0xdf, 0x4a, 0x3c, 0x74, + 0xc1, 0x73, 0x58, 0x56, 0xf5, 0xfd, 0x4d, 0xc8, 0xc8, 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xff, + 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, 0x0c, 0xcb, 0xcb, 0x69, 0x15, 0xa6, 0x20, 0xe0, 0xe6, 0x2c, + 0x09, 0xe6, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, 0x0a, 0x8a, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, + 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0xa9, 0x44, 0x81, 0x29, 0x0f, 0x06, 0xe0, 0xa7, 0x2e, 0x9e, 0x74, 0x5d, 0xba, + 0x7e, 0x3c, 0xc1, 0xd4, 0x1e, 0x02, 0x3d, 0xf6, 0x36, 0xc0, 0x94, 0xa8, 0xeb, 0xb0, 0x9c, 0x38, 0x34, 0xad, 0x69, + 0x16, 0x30, 0x63, 0x9a, 0xa0, 0x25, 0x9b, 0x60, 0xcb, 0x15, 0x60, 0x1f, 0x89, 0xed, 0x59, 0xad, 0x80, 0xd0, 0x35, + 0x68, 0x60, 0xc8, 0x5d, 0x2a, 0xb4, 0x30, 0xeb, 0xb4, 0xa9, 0x08, 0xf7, 0x67, 0x8f, 0x49, 0x2b, 0x38, 0xf5, 0x52, + 0x1a, 0xf8, 0x20, 0x3e, 0x4d, 0x30, 0xf1, 0x05, 0xb1, 0x02, 0x3b, 0x38, 0x68, 0x2d, 0x36, 0x05, 0x4e, 0xc5, 0x45, + 0x4a, 0x61, 0x59, 0x51, 0x6a, 0xc3, 0x87, 0x14, 0xd9, 0xba, 0xcb, 0x23, 0xdd, 0x85, 0x58, 0x00, 0x3b, 0xfd, 0xc2, + 0xa1, 0x83, 0xac, 0x97, 0x01, 0x83, 0x73, 0xad, 0x71, 0x10, 0xf8, 0xed, 0xed, 0xa4, 0x5f, 0x66, 0x48, 0xb9, 0x25, + 0x56, 0x17, 0x90, 0xe3, 0x76, 0x58, 0xc0, 0x1d, 0x84, 0xa5, 0xb2, 0xc7, 0xf3, 0x72, 0x82, 0xcb, 0xa5, 0x2c, 0xe4, + 0xc5, 0x74, 0x2c, 0x9a, 0xcf, 0xad, 0x34, 0x9b, 0x8e, 0xb7, 0xe2, 0x83, 0x82, 0xbf, 0xe7, 0xc4, 0xd2, 0xaa, 0xa7, + 0xd4, 0x0a, 0x8f, 0x32, 0xb7, 0x64, 0x9d, 0x92, 0x5a, 0x6d, 0x37, 0x50, 0x8d, 0xf0, 0x34, 0x0d, 0x1b, 0x81, 0x10, + 0x13, 0x5c, 0xfc, 0x61, 0x91, 0x89, 0x69, 0x6f, 0x09, 0xa9, 0x23, 0xec, 0x1e, 0xca, 0x09, 0x6e, 0x6b, 0x9e, 0x7d, + 0x19, 0x4e, 0xd7, 0x33, 0xf7, 0xbe, 0xc1, 0xdc, 0x4f, 0x43, 0x66, 0x30, 0x7a, 0x2c, 0x13, 0x7e, 0x64, 0xec, 0xa3, + 0x50, 0x55, 0xcf, 0xce, 0xc2, 0x4a, 0x64, 0x89, 0x6f, 0xc6, 0x51, 0x87, 0x71, 0x2a, 0x5a, 0x13, 0x64, 0xd7, 0xd7, + 0xb9, 0xb9, 0x17, 0x28, 0x68, 0xea, 0xb1, 0x7a, 0x9c, 0xb6, 0x62, 0x67, 0x23, 0x12, 0xb9, 0xff, 0xa6, 0x16, 0x89, + 0xac, 0xf8, 0x1c, 0x47, 0x5a, 0x73, 0x90, 0xfb, 0xec, 0x6c, 0x79, 0x93, 0x0a, 0xdd, 0xa2, 0xd1, 0x36, 0xf6, 0xa8, + 0x3e, 0x90, 0xd4, 0x33, 0x2a, 0xb0, 0xaa, 0xb1, 0xb7, 0xb6, 0x5a, 0x22, 0xdd, 0x52, 0x29, 0x36, 0x0c, 0x69, 0x85, + 0xcc, 0x18, 0x05, 0x83, 0x92, 0x22, 0x03, 0x35, 0xca, 0xd7, 0x08, 0x86, 0x7d, 0x6a, 0x00, 0x8a, 0x73, 0x75, 0xf5, + 0xd3, 0x52, 0xb2, 0x85, 0x80, 0x04, 0x64, 0x13, 0x8a, 0x35, 0x62, 0x66, 0xe4, 0x93, 0x8f, 0xc0, 0x79, 0x3d, 0x8e, + 0x8e, 0x01, 0xc8, 0x60, 0xb1, 0xe9, 0xc1, 0xc4, 0xb6, 0x89, 0x28, 0xfa, 0x6c, 0xe0, 0x25, 0x00, 0x3b, 0xad, 0x42, + 0xa3, 0x1f, 0xaa, 0x14, 0x30, 0x64, 0x03, 0x37, 0xe0, 0x55, 0x58, 0x6e, 0xff, 0x25, 0xb4, 0x83, 0xc7, 0x17, 0xb2, + 0xf9, 0x26, 0xe6, 0x09, 0x56, 0xb1, 0x3b, 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0xe1, 0x42, 0xbd, 0xa2, 0x84, 0xa8, + 0x3d, 0xc0, 0xda, 0x97, 0x9c, 0x60, 0xc4, 0xe7, 0x37, 0x94, 0x75, 0xa8, 0xc6, 0x2d, 0xf7, 0x35, 0x5a, 0x84, 0xe9, + 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, 0xbd, 0x3c, 0x10, 0xb1, 0xe0, 0x0a, 0x47, 0x23, 0x6c, 0xbe, 0x80, + 0x24, 0x7d, 0xdb, 0xa7, 0x03, 0xf6, 0xcd, 0xc5, 0x5e, 0x40, 0x99, 0x8f, 0x15, 0xa9, 0x24, 0xa4, 0x34, 0xbb, 0x21, + 0x92, 0x84, 0xb5, 0x22, 0x4f, 0x9d, 0x0f, 0x1c, 0xed, 0x73, 0x2b, 0x89, 0x60, 0x04, 0x27, 0x71, 0xba, 0xf2, 0x70, + 0x51, 0x80, 0xab, 0xe8, 0x88, 0xe9, 0x9b, 0xa0, 0xfc, 0x06, 0xb9, 0xbd, 0x94, 0x5c, 0x5b, 0x68, 0x18, 0x9e, 0x21, + 0xc1, 0xaa, 0x48, 0x04, 0x3a, 0x0a, 0x80, 0xe3, 0x4a, 0xcf, 0x03, 0x4c, 0xf8, 0xda, 0xde, 0x04, 0x80, 0x44, 0x56, + 0x90, 0xb3, 0x14, 0xe8, 0x06, 0x2c, 0x57, 0xc7, 0xa9, 0x51, 0x91, 0xb8, 0xb8, 0x31, 0x5d, 0xdd, 0xd2, 0x9f, 0xa0, + 0xe5, 0x4c, 0x86, 0x98, 0x0e, 0x82, 0x80, 0x4c, 0x7d, 0xca, 0x9d, 0x9c, 0xa6, 0x13, 0xd6, 0xe7, 0xd4, 0xa9, 0x4d, + 0xdd, 0xe1, 0xd4, 0xcd, 0x93, 0xd4, 0x62, 0x75, 0xda, 0x94, 0x12, 0x31, 0x29, 0x31, 0x8f, 0x65, 0x2a, 0xb6, 0x12, + 0x77, 0x6e, 0x7d, 0xa3, 0x85, 0xb4, 0xd1, 0x8e, 0x65, 0x0e, 0xb6, 0x96, 0xf7, 0x42, 0xb4, 0xbf, 0x24, 0xc2, 0xb3, + 0x12, 0x19, 0x6b, 0x3e, 0xe3, 0x8e, 0x89, 0x60, 0xf5, 0x60, 0x2a, 0xf2, 0x0f, 0x8e, 0x4e, 0xb3, 0x37, 0xe8, 0x41, + 0xea, 0x0d, 0x24, 0x66, 0x4d, 0x7c, 0xe7, 0xd2, 0x50, 0x47, 0x08, 0x54, 0x46, 0xb5, 0x4c, 0xc7, 0x89, 0xa5, 0xe2, + 0x92, 0x7c, 0xf5, 0x5e, 0x1f, 0xe7, 0x1b, 0xdf, 0x17, 0x56, 0x23, 0x88, 0xc1, 0x5b, 0x28, 0xfa, 0x9e, 0x14, 0xe1, + 0x39, 0x2c, 0xcf, 0xf6, 0x76, 0xa7, 0xd8, 0x63, 0x55, 0x88, 0xa4, 0x82, 0x31, 0xc6, 0x8c, 0x62, 0xdc, 0x13, 0x35, + 0xb5, 0x88, 0xc4, 0x96, 0xad, 0xc3, 0x02, 0x0f, 0x00, 0xa0, 0xa5, 0x29, 0xbd, 0xcc, 0xb6, 0xea, 0x3c, 0x97, 0xf0, + 0x31, 0xf2, 0x50, 0x64, 0xe3, 0xf7, 0x6b, 0x32, 0x50, 0x10, 0xee, 0x8d, 0x96, 0x87, 0x89, 0x71, 0xb0, 0x8a, 0x42, + 0x16, 0xe8, 0x0d, 0xda, 0xa9, 0x12, 0xa1, 0xb8, 0x39, 0x59, 0x87, 0x1b, 0x4e, 0x2a, 0xd8, 0x42, 0x25, 0x2c, 0x95, + 0x16, 0xf8, 0xd5, 0x46, 0x58, 0x3c, 0x65, 0xdc, 0x7f, 0x53, 0xe1, 0x0c, 0xfa, 0x83, 0x7b, 0xcb, 0x8c, 0xfa, 0x7e, + 0xe9, 0x44, 0xa6, 0x02, 0x13, 0x37, 0xb3, 0xd4, 0x7e, 0xbf, 0xac, 0xd2, 0x7e, 0x5e, 0x2e, 0xf7, 0x39, 0x69, 0xbe, + 0xd6, 0x1d, 0x34, 0x9f, 0x0c, 0xf7, 0x2b, 0xe5, 0x87, 0x16, 0x46, 0x4d, 0xf9, 0xd5, 0x97, 0x34, 0xcc, 0x3d, 0x15, + 0xde, 0xea, 0xb6, 0x51, 0xe8, 0xa2, 0x3e, 0x07, 0x43, 0x48, 0x7f, 0x05, 0xd7, 0xd0, 0xe0, 0x41, 0x91, 0x2c, 0x16, + 0x6b, 0x17, 0xc4, 0xf5, 0x31, 0xa7, 0xda, 0xa1, 0x8c, 0x31, 0xe2, 0x69, 0xc9, 0x41, 0x92, 0xc1, 0xc1, 0xf8, 0x0d, + 0x0c, 0x88, 0x49, 0x49, 0x48, 0x87, 0xd0, 0x59, 0x99, 0x89, 0xa8, 0xdc, 0xc5, 0xdb, 0x8d, 0xcb, 0x9a, 0x42, 0x11, + 0x76, 0x82, 0x99, 0x4a, 0xa9, 0x20, 0x90, 0x26, 0xdf, 0x46, 0xab, 0x16, 0x0c, 0x05, 0xd1, 0x60, 0x28, 0x20, 0x0f, + 0xd3, 0x55, 0xc2, 0x8d, 0x8f, 0xe2, 0xe0, 0x79, 0x85, 0x1a, 0xf1, 0x52, 0x83, 0xaf, 0x61, 0xf3, 0xd7, 0x44, 0x49, + 0x11, 0x72, 0x11, 0x7b, 0x05, 0x9f, 0x08, 0xd9, 0x94, 0x87, 0x39, 0xd0, 0x0f, 0xed, 0xca, 0x4e, 0xb6, 0x97, 0x57, + 0x2e, 0x2d, 0x1a, 0x5b, 0x89, 0x9a, 0xb5, 0x38, 0x8a, 0xb7, 0xb3, 0x3e, 0x4c, 0x4d, 0x09, 0x04, 0xa4, 0xa9, 0x9c, + 0xa4, 0x9a, 0xf7, 0x28, 0xeb, 0x03, 0x48, 0xb0, 0xfb, 0x09, 0x2c, 0xf4, 0x9b, 0x12, 0x13, 0x2c, 0xaa, 0xc6, 0x6e, + 0x53, 0xd0, 0x9a, 0x53, 0xd2, 0x7c, 0x53, 0x84, 0x70, 0x5b, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x76, 0x7e, + 0x94, 0x6d, 0xb7, 0xfa, 0x86, 0xe0, 0xc2, 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x42, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, + 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, 0xb1, 0xe8, 0xdc, 0x6b, 0x8e, 0x92, 0xcb, 0xaa, 0xda, 0xd5, 0x12, 0x34, + 0x74, 0x23, 0x19, 0x13, 0xc5, 0x3c, 0x27, 0x00, 0x46, 0xb1, 0xf9, 0x73, 0xae, 0x93, 0xbc, 0x7f, 0x59, 0x99, 0xda, + 0xed, 0xfb, 0x7e, 0x94, 0x9f, 0xd1, 0x91, 0x8a, 0xca, 0xe6, 0x24, 0xe6, 0xdf, 0x95, 0x60, 0x1a, 0x13, 0x1f, 0xe9, + 0xb9, 0xfa, 0xa1, 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x07, 0x72, 0x36, 0xc1, 0x02, 0x0b, + 0x74, 0x59, 0x83, 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, + 0x55, 0x60, 0x40, 0xf9, 0x70, 0xd1, 0xb0, 0x12, 0xe2, 0x12, 0x15, 0x66, 0x15, 0xe7, 0x8f, 0xeb, 0xbc, 0x6e, 0x5a, + 0x96, 0x18, 0x94, 0x9f, 0xba, 0x86, 0x1b, 0xdf, 0x59, 0xc8, 0x1f, 0xdf, 0x7f, 0x09, 0xba, 0x9d, 0x48, 0xbb, 0xb5, + 0x55, 0x6c, 0x90, 0x85, 0x86, 0xf7, 0xc2, 0xa6, 0xd0, 0x16, 0x2f, 0x02, 0x14, 0xea, 0x3b, 0x16, 0xe3, 0x6d, 0x11, + 0x2a, 0xc3, 0x2f, 0x58, 0x30, 0x05, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x1d, 0x36, 0x9a, 0x62, 0xd7, 0x42, 0x18, + 0x7c, 0x39, 0xa8, 0x4a, 0xc9, 0x8b, 0x75, 0xb2, 0xbd, 0x38, 0x87, 0xef, 0xaf, 0xe3, 0x02, 0xa8, 0x83, 0xe8, 0x6b, + 0x2a, 0x8b, 0x0d, 0xe4, 0xe2, 0xa6, 0xac, 0xf5, 0x8a, 0x86, 0xc3, 0x1b, 0xbb, 0xf0, 0xba, 0x02, 0x1f, 0x47, 0xe9, + 0x30, 0x11, 0x93, 0x98, 0x49, 0x95, 0x2b, 0x72, 0x6d, 0x74, 0x2f, 0x6d, 0xd1, 0xbc, 0x14, 0x12, 0xbc, 0x22, 0xf0, + 0x82, 0xd0, 0x57, 0xfa, 0x72, 0xb5, 0x81, 0x82, 0x47, 0xed, 0x8b, 0x8b, 0x60, 0x62, 0xe2, 0x71, 0x43, 0x6a, 0xfa, + 0x75, 0x38, 0xb5, 0xb2, 0x58, 0x72, 0xf8, 0x75, 0xce, 0xd8, 0x82, 0x02, 0x20, 0x3e, 0x79, 0xb4, 0xde, 0x4d, 0x7a, + 0xa3, 0xb4, 0x83, 0xd2, 0x08, 0xf1, 0x5d, 0x85, 0xaf, 0x3b, 0x57, 0x7c, 0xe5, 0xaa, 0x7b, 0x5f, 0x57, 0xdc, 0xb8, + 0x60, 0xf4, 0x92, 0x4f, 0x92, 0x85, 0x6b, 0x37, 0x74, 0x57, 0xe7, 0x3b, 0xef, 0x0b, 0x99, 0xb7, 0x70, 0x05, 0x76, + 0xfe, 0x15, 0x77, 0x5e, 0x7a, 0x1f, 0x8c, 0x13, 0xe5, 0xef, 0xcd, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0xef, + 0x7b, 0xdf, 0x07, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, 0x6d, 0x75, 0x82, 0x4c, 0x94, 0x1b, 0xe9, 0x0d, 0xb7, 0x7f, 0x57, + 0x81, 0x20, 0x4e, 0xc5, 0xf4, 0x51, 0x39, 0xae, 0x1f, 0x2d, 0x50, 0xa9, 0x88, 0xf8, 0x5c, 0xe5, 0xae, 0xac, 0x4d, + 0x0d, 0xf5, 0x98, 0x4e, 0x66, 0xa1, 0x69, 0x56, 0xe4, 0x52, 0x2e, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, + 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, + 0x7a, 0x14, 0x7d, 0x1c, 0x77, 0x31, 0x97, 0x47, 0xd9, 0x9f, 0x35, 0x00, 0x4c, 0x47, 0x58, 0x74, 0x37, 0x3d, 0x63, + 0x4f, 0xa0, 0xa7, 0x27, 0x32, 0x48, 0xf4, 0x56, 0xe7, 0xab, 0x56, 0x89, 0xa5, 0x2b, 0x08, 0xec, 0xde, 0x90, 0xb1, + 0x2a, 0x69, 0xb7, 0x5c, 0xbf, 0x9c, 0xe7, 0xf3, 0x9c, 0x2f, 0xe5, 0xf9, 0xd4, 0x2c, 0xba, 0x8d, 0xa6, 0x7b, 0x73, + 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, 0x5d, 0x0b, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, + 0x51, 0x3d, 0x93, 0x63, 0x24, 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0x77, 0x0b, 0xdb, 0x42, 0xb6, + 0x79, 0x79, 0x35, 0xcc, 0x81, 0xd2, 0x72, 0x7f, 0x99, 0x30, 0x7c, 0x77, 0x7d, 0xfd, 0x9d, 0x90, 0x53, 0x55, 0x47, + 0x6f, 0xfe, 0x5a, 0xf7, 0x0c, 0x46, 0xa5, 0x72, 0x22, 0x4e, 0xf9, 0xea, 0xc1, 0x17, 0x77, 0xaf, 0x80, 0xe5, 0x14, + 0xb0, 0x3b, 0xe5, 0xce, 0xc2, 0x50, 0xd5, 0x06, 0xfe, 0x62, 0xf5, 0x60, 0xab, 0xf6, 0xf0, 0x17, 0xbd, 0x2f, 0x82, + 0x1b, 0x1b, 0x1b, 0xdb, 0x78, 0xb7, 0x96, 0x08, 0xf2, 0x16, 0x0f, 0xf4, 0xf1, 0xea, 0xa3, 0xa0, 0xe5, 0x0a, 0xb1, + 0xcd, 0x7a, 0x0e, 0x85, 0xad, 0x41, 0xbe, 0x49, 0x99, 0x34, 0x98, 0x15, 0x3c, 0x9b, 0xc8, 0x19, 0x0a, 0x79, 0xcd, + 0xc7, 0x41, 0xdb, 0x11, 0xfe, 0x0f, 0x9c, 0xda, 0xf1, 0xf2, 0xfc, 0x13, 0xf4, 0x01, 0x4f, 0x57, 0x4a, 0x53, 0x8a, + 0x53, 0xaa, 0xa0, 0xce, 0x72, 0x9d, 0x07, 0x23, 0xc5, 0xc5, 0x18, 0x16, 0x17, 0x5c, 0x96, 0x1b, 0x67, 0x23, 0xa7, + 0xbf, 0xc4, 0xab, 0x8b, 0x74, 0xf9, 0x48, 0x64, 0xab, 0x96, 0xde, 0x2b, 0x7d, 0xba, 0x6d, 0x4f, 0x18, 0x1f, 0x67, + 0x43, 0x3a, 0x98, 0xf1, 0x71, 0x22, 0xbc, 0x3e, 0x31, 0xd4, 0x77, 0x8b, 0xc0, 0x74, 0x73, 0x6c, 0xf2, 0xc3, 0xf1, + 0x7a, 0xb3, 0x59, 0xe3, 0xf6, 0xde, 0x39, 0x9f, 0x9c, 0x79, 0x89, 0x11, 0x95, 0xb9, 0x86, 0x07, 0xb4, 0x42, 0xbc, + 0x78, 0xcf, 0x04, 0xc6, 0x65, 0x57, 0x24, 0xb5, 0xdd, 0x40, 0xe0, 0x62, 0x8f, 0x62, 0x96, 0x0c, 0x6d, 0x0f, 0xca, + 0x03, 0x7d, 0x31, 0x9a, 0x6e, 0x01, 0xd3, 0xf2, 0xda, 0xd9, 0x45, 0x6a, 0x7b, 0xd5, 0x54, 0x01, 0xcc, 0x92, 0xe5, + 0xf1, 0x19, 0xb2, 0xee, 0x57, 0xd0, 0x45, 0x0c, 0x18, 0x1b, 0x57, 0xe6, 0xdc, 0xf9, 0xaa, 0x15, 0xf1, 0x8d, 0x26, + 0xd2, 0xa4, 0x3e, 0xa2, 0xbe, 0xfd, 0xb0, 0x56, 0x57, 0x39, 0x48, 0xe0, 0x1e, 0x79, 0x77, 0xc4, 0xa5, 0xa3, 0xcf, + 0x2c, 0x36, 0xab, 0xf4, 0x2d, 0x75, 0x2d, 0x6e, 0x31, 0xec, 0x15, 0xf7, 0xc0, 0xfe, 0xc0, 0xb8, 0x45, 0x2c, 0xe2, + 0xed, 0xac, 0x96, 0xc2, 0xba, 0x30, 0x47, 0x8e, 0xb1, 0xf6, 0xe0, 0x15, 0xaf, 0xd6, 0x0c, 0xcc, 0x30, 0xe3, 0x8c, + 0xe4, 0x8d, 0x71, 0xaf, 0x6a, 0xd3, 0x91, 0xab, 0x00, 0xa2, 0x6f, 0x4e, 0x97, 0xe4, 0xf0, 0x4a, 0x96, 0xab, 0xce, + 0x90, 0x7f, 0x86, 0x75, 0xd6, 0x8b, 0x13, 0x70, 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, + 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0x85, 0x91, 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x2c, 0x26, 0x6c, 0xc4, 0x44, 0x1a, 0x95, + 0x52, 0xc2, 0x7a, 0x72, 0xa9, 0x25, 0x7f, 0x99, 0xcb, 0xab, 0x2f, 0xb7, 0x09, 0x0e, 0x28, 0x6a, 0x60, 0x39, 0x34, + 0x8e, 0x5b, 0x06, 0x12, 0xb1, 0x18, 0x10, 0xa3, 0x56, 0xe5, 0x72, 0x32, 0xaa, 0x93, 0xfa, 0x0a, 0xb9, 0x50, 0x91, + 0x07, 0xb7, 0x04, 0x4a, 0xfe, 0x02, 0x53, 0x07, 0xd3, 0x52, 0xbb, 0x69, 0xb1, 0x49, 0xf2, 0x8e, 0x19, 0x90, 0x5c, + 0x7d, 0x0d, 0x0f, 0x8d, 0x5f, 0x86, 0x37, 0x14, 0x3d, 0x1d, 0x23, 0xe4, 0xb4, 0x34, 0xe6, 0xd2, 0x7f, 0x23, 0xcf, + 0xbe, 0x24, 0x60, 0x3f, 0x83, 0x98, 0x32, 0x70, 0x89, 0x8d, 0x0b, 0x92, 0xf2, 0x5a, 0x9e, 0xb2, 0xfb, 0x16, 0x94, + 0xef, 0x92, 0x49, 0x57, 0xa9, 0xac, 0x35, 0x56, 0xdd, 0xcf, 0x33, 0x96, 0x5f, 0x1d, 0x30, 0xcc, 0x4d, 0x46, 0x83, + 0x6c, 0xc9, 0xcc, 0xa6, 0xfc, 0x6a, 0xef, 0xc6, 0xb7, 0x3c, 0x94, 0x74, 0xa8, 0x56, 0xe9, 0xe6, 0xa5, 0x1b, 0x8e, + 0xf1, 0xc2, 0x0d, 0xc7, 0xb8, 0x43, 0xe7, 0xca, 0x15, 0xa9, 0x75, 0xfe, 0xfb, 0x52, 0xf8, 0x49, 0xec, 0xb5, 0xbe, + 0xde, 0x75, 0xfd, 0x95, 0xe9, 0xe9, 0x37, 0xa0, 0x6a, 0x64, 0x09, 0xdd, 0x84, 0x2a, 0x26, 0x23, 0x51, 0x62, 0xba, + 0x4a, 0x79, 0xd4, 0xd7, 0x88, 0x0b, 0x10, 0x37, 0x94, 0xbf, 0xf8, 0x97, 0xf0, 0xe2, 0x24, 0x40, 0x23, 0x6a, 0x3e, + 0xca, 0x52, 0xde, 0x18, 0x45, 0x93, 0x38, 0xb9, 0x0a, 0x66, 0x71, 0x63, 0x92, 0xa5, 0x59, 0x31, 0x05, 0xae, 0xf4, + 0x8a, 0x2b, 0xb0, 0xe1, 0x27, 0x8d, 0x59, 0xec, 0xbd, 0x64, 0xc9, 0x39, 0xe3, 0xf1, 0x20, 0xf2, 0xec, 0xfd, 0x1c, + 0xc4, 0x83, 0xf5, 0x36, 0xca, 0xf3, 0xec, 0xc2, 0xf6, 0x3e, 0x64, 0xa7, 0xc0, 0xb4, 0xde, 0xbb, 0xcb, 0xab, 0x33, + 0x96, 0x7a, 0x1f, 0x4f, 0x67, 0x29, 0x9f, 0x79, 0x45, 0x94, 0x16, 0x8d, 0x82, 0xe5, 0xf1, 0x08, 0xd4, 0x44, 0x92, + 0xe5, 0x0d, 0xcc, 0x7f, 0x9e, 0xb0, 0x20, 0x89, 0xcf, 0xc6, 0xdc, 0x1a, 0x46, 0xf9, 0xa7, 0x4e, 0xa3, 0x31, 0xcd, + 0xe3, 0x49, 0x94, 0x5f, 0x35, 0xa8, 0x45, 0x70, 0xaf, 0xb9, 0x1b, 0x7d, 0x36, 0x7a, 0xd0, 0xe1, 0x39, 0xf4, 0x8d, + 0x91, 0x8a, 0x01, 0x08, 0x1f, 0x6b, 0xf7, 0x61, 0x73, 0x52, 0x6c, 0x88, 0x13, 0xa5, 0x28, 0xe5, 0xe5, 0x89, 0x77, + 0x01, 0xb6, 0xed, 0x89, 0x7f, 0xca, 0x53, 0x0f, 0x7c, 0x39, 0x9e, 0xa5, 0xf3, 0xc1, 0x2c, 0x2f, 0x60, 0x80, 0x69, + 0x16, 0xa7, 0x9c, 0xe5, 0x9d, 0xd3, 0x2c, 0x07, 0xb2, 0x35, 0xf2, 0x68, 0x18, 0xcf, 0x8a, 0xe0, 0xc1, 0xf4, 0xb2, + 0x83, 0xb6, 0xc2, 0x59, 0x9e, 0xcd, 0xd2, 0xa1, 0x9c, 0x2b, 0x4e, 0x61, 0x63, 0xc4, 0xdc, 0xac, 0xa0, 0x37, 0xa1, + 0x00, 0x7c, 0x29, 0x8b, 0xf2, 0xc6, 0x19, 0x76, 0x46, 0x43, 0xbf, 0x39, 0x64, 0x67, 0x5e, 0x7e, 0x76, 0x1a, 0x39, + 0xad, 0xf6, 0x63, 0x4f, 0xfd, 0xf9, 0x0f, 0x5d, 0x30, 0xdc, 0x57, 0x16, 0xb7, 0x9a, 0xcd, 0xbf, 0x71, 0x3b, 0x0b, + 0xb3, 0x10, 0x40, 0x41, 0x6b, 0x7a, 0x69, 0x15, 0x59, 0x02, 0xeb, 0xb3, 0xaa, 0x67, 0x67, 0x0a, 0x7e, 0x53, 0x9c, + 0x9e, 0x05, 0xed, 0xe9, 0x65, 0x89, 0xd8, 0x05, 0x22, 0x21, 0x53, 0x22, 0x29, 0x9f, 0xe6, 0xbf, 0x15, 0xe2, 0x27, + 0xab, 0x21, 0x6e, 0x2b, 0x88, 0x2b, 0xaa, 0x37, 0x86, 0xb0, 0x0f, 0x88, 0xfc, 0xad, 0x42, 0x00, 0x32, 0x06, 0x27, + 0x30, 0x57, 0x70, 0xd0, 0xc3, 0x6f, 0x06, 0xa3, 0xbd, 0x1a, 0x8c, 0x27, 0xb7, 0x81, 0x91, 0xa7, 0xc3, 0x79, 0x7d, + 0x5d, 0x5b, 0xe0, 0x9c, 0x76, 0xc6, 0x0c, 0xf9, 0x29, 0x68, 0xe3, 0xf7, 0x8b, 0x78, 0xc8, 0xc7, 0xe2, 0x2b, 0xb1, + 0xf3, 0x85, 0xa8, 0x7b, 0xd8, 0x6c, 0x8a, 0xe7, 0x02, 0x14, 0x5a, 0xd0, 0xf2, 0xb1, 0x01, 0x30, 0xd1, 0xe7, 0xeb, + 0x5e, 0x62, 0xf3, 0xed, 0xad, 0x6f, 0xaa, 0xf1, 0xb8, 0xca, 0x1b, 0x14, 0x2a, 0x42, 0xbd, 0xb3, 0x05, 0x33, 0xde, + 0x8a, 0x6e, 0x4b, 0x1f, 0x54, 0xf5, 0xbe, 0xe5, 0xa4, 0xf5, 0x02, 0xe6, 0x99, 0xb9, 0x40, 0x9d, 0xac, 0x8b, 0x21, + 0xa9, 0x46, 0xc3, 0x05, 0xbd, 0xc1, 0x31, 0x84, 0x44, 0x07, 0x82, 0x4e, 0xd1, 0xcb, 0xe9, 0x9d, 0x1a, 0xa9, 0x1b, + 0xe4, 0x4e, 0xea, 0xc2, 0x96, 0x4f, 0xb5, 0x5c, 0x2f, 0xb6, 0xb6, 0xc0, 0xcb, 0xfe, 0x9c, 0xcb, 0x06, 0x20, 0xbd, + 0x2b, 0x49, 0x6b, 0xbc, 0x87, 0x44, 0xb9, 0x7c, 0xd9, 0x80, 0x28, 0x07, 0xbe, 0x3e, 0x1f, 0xa3, 0xdf, 0xad, 0xaf, + 0xae, 0x1b, 0x29, 0x35, 0x3b, 0xb6, 0xdb, 0xe3, 0x3a, 0x2b, 0x0b, 0xb3, 0xcf, 0x78, 0x89, 0xa3, 0x7c, 0xc9, 0x43, + 0x1c, 0xd1, 0x7b, 0x15, 0x0a, 0x37, 0x4d, 0x39, 0x69, 0xa3, 0xbb, 0x3a, 0x69, 0xf0, 0x35, 0xa6, 0xcc, 0x67, 0x15, + 0x27, 0x07, 0x37, 0xe6, 0x78, 0x20, 0xae, 0x20, 0x16, 0x55, 0x96, 0x7d, 0x44, 0xd0, 0x0b, 0xbf, 0x0b, 0x94, 0x14, + 0x46, 0x2e, 0xbf, 0xe2, 0xbf, 0xc3, 0xe3, 0x70, 0x34, 0xfa, 0x45, 0x36, 0xcb, 0x07, 0x78, 0x39, 0x60, 0x45, 0x28, + 0xc2, 0x26, 0x4b, 0xc0, 0xf6, 0xb8, 0x56, 0x40, 0x0c, 0xf3, 0x2c, 0xcc, 0xb7, 0x2f, 0x30, 0x3a, 0x9d, 0x11, 0x97, + 0x1f, 0x64, 0xf8, 0x45, 0xa1, 0x84, 0x3a, 0x75, 0x48, 0x89, 0x78, 0x74, 0x31, 0xd4, 0x9f, 0xa5, 0x31, 0x88, 0xe0, + 0xe3, 0x78, 0x48, 0x17, 0x62, 0xe2, 0x21, 0x9d, 0x90, 0x34, 0x28, 0x23, 0x0a, 0x43, 0xee, 0x50, 0x20, 0x17, 0x06, + 0xbf, 0xcb, 0x0c, 0x1b, 0xbb, 0x61, 0xe3, 0x29, 0x87, 0xa1, 0xc3, 0x87, 0xd9, 0x24, 0x8a, 0xd3, 0x00, 0x5f, 0x5c, + 0xe2, 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0xa7, 0x5a, 0xa3, 0x96, 0xeb, 0xff, 0x04, 0x02, 0x8e, 0xfa, 0x63, 0x32, + 0x0b, 0x91, 0x55, 0x10, 0x31, 0x54, 0x64, 0xde, 0x57, 0x7a, 0xde, 0x33, 0xab, 0x55, 0xcc, 0xb4, 0xbe, 0x0e, 0xcd, + 0x85, 0xe5, 0xd2, 0x67, 0xd8, 0xf5, 0x52, 0x10, 0xac, 0x5c, 0xe7, 0xd1, 0x53, 0x10, 0x67, 0x8f, 0xd1, 0x47, 0xaf, + 0xd1, 0x0a, 0x5a, 0xda, 0x2f, 0xaf, 0x5d, 0xb5, 0x15, 0x89, 0x3a, 0xf2, 0xba, 0x26, 0xe1, 0xa1, 0xbf, 0x0b, 0x5c, + 0xab, 0x67, 0x8d, 0xaf, 0x27, 0x37, 0x1d, 0x46, 0xa7, 0xce, 0x52, 0xa7, 0x06, 0x04, 0x1d, 0x74, 0xac, 0x99, 0xca, + 0x2d, 0x2b, 0xbc, 0xb5, 0xf1, 0x67, 0x0b, 0xcd, 0x89, 0xaf, 0x1e, 0x90, 0x33, 0xd2, 0x2b, 0x9e, 0x56, 0xf0, 0x5d, + 0x29, 0x09, 0xb2, 0x78, 0x21, 0x7f, 0xa1, 0x99, 0x00, 0xe5, 0x4a, 0x1f, 0x64, 0x2f, 0xd4, 0x8a, 0x47, 0x26, 0x22, + 0xde, 0xab, 0x9b, 0x50, 0xd6, 0xd8, 0x32, 0x5c, 0xe8, 0x8b, 0x16, 0x5c, 0xc1, 0x8f, 0x06, 0xd3, 0x88, 0xe1, 0xbd, + 0x94, 0x93, 0xcd, 0xf9, 0x97, 0xbc, 0xdc, 0xd9, 0x9c, 0xab, 0x86, 0xe2, 0x7b, 0x3c, 0xc4, 0x4f, 0x06, 0xf2, 0x6b, + 0x2e, 0xac, 0xc7, 0xc0, 0x7e, 0xff, 0xee, 0xe0, 0xd0, 0xf6, 0x4e, 0xb3, 0xe1, 0x55, 0x60, 0xc3, 0xee, 0x64, 0x76, + 0xe9, 0xfa, 0x7c, 0xcc, 0x52, 0x47, 0xb1, 0x78, 0x96, 0x30, 0x90, 0x08, 0x67, 0xe2, 0xb2, 0xe3, 0xa2, 0xe7, 0x3b, + 0x3c, 0xd9, 0xa3, 0xb7, 0x21, 0x75, 0xf7, 0xb8, 0x78, 0x51, 0x18, 0xcf, 0xf1, 0x6b, 0x17, 0x63, 0xff, 0x7b, 0x3b, + 0xf0, 0x05, 0x1f, 0x0e, 0x70, 0xcf, 0xd0, 0xd3, 0xe6, 0x7c, 0x89, 0x93, 0x7a, 0x38, 0xc4, 0xb8, 0x2b, 0x50, 0x28, + 0xa8, 0xd5, 0x49, 0x30, 0x3c, 0x39, 0x29, 0xe1, 0x2b, 0x8c, 0xb5, 0xa3, 0xc6, 0x45, 0x08, 0x55, 0x7f, 0xcd, 0x5d, + 0xf2, 0x75, 0x3b, 0x38, 0x04, 0xce, 0x3b, 0xc4, 0x06, 0xc4, 0x5d, 0xd8, 0x7b, 0xa8, 0x4b, 0x68, 0xd3, 0x8a, 0xa2, + 0x75, 0x10, 0x88, 0x86, 0x15, 0xd3, 0x8b, 0x10, 0x61, 0xb5, 0xba, 0x0a, 0xa4, 0xa1, 0x09, 0xdd, 0x89, 0x8b, 0x9f, + 0x04, 0x19, 0x7c, 0x12, 0x1d, 0x4e, 0xcc, 0x37, 0x84, 0x88, 0xcb, 0xfc, 0x9a, 0x5a, 0x47, 0x7f, 0x01, 0xdb, 0xc3, + 0xbb, 0x38, 0xa1, 0x96, 0x4a, 0x1d, 0xa1, 0x9d, 0x84, 0x6a, 0xbb, 0xa9, 0xec, 0x0e, 0xd0, 0xfd, 0x49, 0x34, 0x2d, + 0x58, 0xa0, 0xbe, 0x48, 0xcd, 0x84, 0x0a, 0x6e, 0xd9, 0x14, 0x90, 0x79, 0x31, 0xcf, 0xd0, 0x60, 0x58, 0xb6, 0x53, + 0x40, 0xf4, 0x39, 0x8d, 0xc6, 0xa0, 0x71, 0x7a, 0xe6, 0x96, 0x7c, 0x3c, 0x37, 0xf5, 0xda, 0x23, 0xd0, 0x6b, 0x98, + 0x93, 0xd7, 0x00, 0x4f, 0xed, 0x2c, 0x0d, 0x12, 0x36, 0xe2, 0x25, 0xc7, 0x4b, 0x5f, 0x73, 0x65, 0x48, 0xf8, 0xed, + 0x87, 0xa0, 0xeb, 0x2c, 0x1f, 0xff, 0xbd, 0x79, 0x62, 0xe8, 0x18, 0xa4, 0xa0, 0x9b, 0x28, 0x0b, 0x14, 0x33, 0xec, + 0x01, 0x5c, 0xf3, 0x79, 0x6e, 0x4c, 0x34, 0x60, 0x68, 0x64, 0x95, 0x1c, 0x64, 0xf2, 0xd8, 0xe3, 0xb9, 0xd9, 0x2e, + 0x75, 0xe7, 0x4b, 0x18, 0x2c, 0xeb, 0xfa, 0x5d, 0xb7, 0x2c, 0xc8, 0x64, 0x5d, 0x6e, 0xac, 0x0c, 0xa6, 0xfa, 0xd3, + 0x12, 0xf9, 0x0c, 0xd3, 0xae, 0x14, 0xc1, 0xd2, 0xb9, 0xe8, 0x71, 0x17, 0x62, 0xd6, 0x8c, 0x4e, 0xcf, 0xec, 0xe1, + 0x96, 0x71, 0x3a, 0x9d, 0xf1, 0x23, 0x0a, 0xd4, 0xe6, 0x78, 0x9d, 0xa0, 0x3f, 0x17, 0x73, 0x83, 0x17, 0x3c, 0x70, + 0x10, 0x00, 0xab, 0x61, 0x3d, 0x01, 0x6a, 0xba, 0xca, 0xf0, 0xf0, 0x1f, 0x23, 0x71, 0x4b, 0x9f, 0x5a, 0xaf, 0xa0, + 0xd2, 0x09, 0x58, 0xdd, 0x1d, 0xce, 0x9d, 0xa3, 0x37, 0x8e, 0xdb, 0xf7, 0x5e, 0x19, 0x2f, 0x2f, 0xb1, 0xd5, 0x1e, + 0xb0, 0x3d, 0xa4, 0xf7, 0xca, 0x26, 0x26, 0x93, 0x53, 0xb3, 0x57, 0x21, 0x36, 0x7c, 0xeb, 0xd8, 0xac, 0x98, 0x36, + 0x84, 0x48, 0x6a, 0x10, 0x33, 0xda, 0xd8, 0x55, 0x05, 0x56, 0xbf, 0xe2, 0x73, 0x92, 0x36, 0x5c, 0xbf, 0x29, 0xe4, + 0x88, 0xf7, 0xcd, 0x5b, 0x2d, 0xb5, 0x80, 0x3a, 0xd4, 0xb9, 0x86, 0xe4, 0x83, 0x47, 0xf9, 0xd6, 0x1b, 0x25, 0x37, + 0x4e, 0xf6, 0xeb, 0x92, 0x0c, 0xf6, 0x59, 0xa9, 0xdf, 0xa8, 0x06, 0x5a, 0x18, 0xe7, 0x87, 0x8d, 0x24, 0xf7, 0xdd, + 0x53, 0xb2, 0x12, 0x55, 0x1c, 0x9c, 0xae, 0x2c, 0xaa, 0x13, 0x0d, 0xa1, 0x50, 0x63, 0x3c, 0x77, 0xad, 0x25, 0xdd, + 0x76, 0x2a, 0x59, 0x24, 0x6c, 0x4c, 0x8b, 0xf0, 0x08, 0x6d, 0x30, 0xfa, 0x6c, 0xeb, 0xcf, 0x03, 0x50, 0x7f, 0x9f, + 0x42, 0x7b, 0x73, 0xee, 0xb8, 0xab, 0xef, 0xcd, 0x29, 0xcf, 0x50, 0x49, 0x61, 0x23, 0x63, 0xb1, 0x26, 0x5c, 0xd1, + 0x41, 0xb5, 0xbb, 0x28, 0x3e, 0xf7, 0x76, 0xc4, 0x44, 0xb0, 0xdb, 0x8f, 0xe5, 0x8b, 0x9e, 0xb8, 0x29, 0x12, 0x91, + 0xbc, 0xa2, 0xdc, 0x22, 0x36, 0x09, 0xed, 0x5b, 0x79, 0xc7, 0xb6, 0x84, 0x94, 0x42, 0x40, 0x95, 0xc0, 0x02, 0xe0, + 0x75, 0x19, 0x93, 0xb0, 0xc7, 0x92, 0x0c, 0x36, 0xce, 0x05, 0x8a, 0x00, 0x03, 0x47, 0x3c, 0x8a, 0x13, 0xd1, 0x45, + 0x06, 0xf6, 0x94, 0x03, 0xa8, 0x31, 0xc2, 0x23, 0xf5, 0x3a, 0x2e, 0x75, 0x12, 0x12, 0x66, 0x7b, 0x3b, 0x15, 0xdc, + 0x84, 0x19, 0xed, 0x32, 0xf3, 0x00, 0xab, 0xc2, 0x50, 0xd4, 0x01, 0x71, 0xe9, 0xda, 0x0c, 0x02, 0x58, 0xa8, 0x60, + 0x87, 0x97, 0xaa, 0x2b, 0x2c, 0x02, 0x96, 0x1c, 0x13, 0x85, 0xc1, 0xc8, 0x63, 0x5c, 0x13, 0x36, 0x17, 0xd9, 0x8f, + 0x0a, 0xda, 0x74, 0x09, 0xda, 0xb4, 0x0e, 0xed, 0x09, 0x12, 0xbd, 0xb7, 0x39, 0x8f, 0xcb, 0x10, 0xbe, 0xa5, 0x83, + 0x6c, 0xc8, 0x3e, 0x7e, 0x78, 0x85, 0x77, 0x00, 0xa1, 0x3d, 0x38, 0x0b, 0x99, 0x5b, 0x9e, 0xc8, 0xc5, 0x31, 0x75, + 0x82, 0xd8, 0xdb, 0x16, 0xcd, 0x45, 0x74, 0x05, 0x8a, 0xf6, 0x04, 0xe4, 0x6c, 0x48, 0x05, 0x61, 0x98, 0x53, 0x2f, + 0x0e, 0x4b, 0x2a, 0x5a, 0x0b, 0x99, 0x2e, 0x1a, 0x21, 0x11, 0x68, 0x67, 0x56, 0x34, 0xc0, 0x9c, 0x59, 0x93, 0x0e, + 0xc3, 0xf8, 0x5c, 0x73, 0x1b, 0x5d, 0x20, 0xea, 0xee, 0x01, 0x43, 0xb3, 0x04, 0xc6, 0xcc, 0xaf, 0xaf, 0x9b, 0x30, + 0x94, 0x78, 0xb4, 0xf6, 0x48, 0x36, 0x88, 0x77, 0x61, 0xc2, 0xcc, 0x2d, 0x4c, 0x4f, 0xc2, 0xab, 0x7a, 0x3d, 0x95, + 0x6f, 0x13, 0xc8, 0x01, 0x00, 0x46, 0x3a, 0xea, 0x27, 0x3e, 0xd0, 0xe6, 0x0d, 0x94, 0xc6, 0xc3, 0xe5, 0x32, 0xb0, + 0x4a, 0xa7, 0x58, 0x9a, 0x5d, 0x5f, 0xb7, 0xe0, 0x71, 0x12, 0xa7, 0xf8, 0x04, 0x33, 0xd3, 0x0d, 0x38, 0x78, 0x04, + 0xd3, 0x1c, 0xd8, 0x16, 0x6a, 0xa2, 0x4b, 0xac, 0x49, 0x55, 0x4d, 0x74, 0x09, 0xf2, 0x48, 0x54, 0x69, 0xf2, 0x14, + 0xc8, 0x70, 0xff, 0x1f, 0x16, 0x34, 0x93, 0x8b, 0x67, 0x69, 0xd2, 0x01, 0x98, 0x20, 0x2d, 0x35, 0xf1, 0xf6, 0x76, + 0x80, 0xcc, 0xb0, 0x18, 0xd2, 0xfa, 0x91, 0x3b, 0xae, 0x7a, 0x8f, 0x91, 0x90, 0x64, 0x6e, 0x2d, 0x0d, 0x81, 0x8a, + 0xd0, 0x1a, 0x04, 0xdf, 0x62, 0x78, 0x4c, 0x9b, 0x03, 0xf4, 0xbc, 0xd4, 0xfe, 0x0b, 0xb2, 0xa6, 0xea, 0xe0, 0xd9, + 0x7f, 0xfd, 0xc7, 0xbf, 0xb3, 0x3d, 0xb1, 0xb9, 0xb2, 0xd1, 0x08, 0x4c, 0x65, 0xeb, 0x0e, 0x7d, 0xfe, 0xd7, 0xdf, + 0xff, 0xdf, 0xff, 0xf3, 0x5f, 0x75, 0xb7, 0x14, 0x7a, 0x9d, 0xc8, 0x83, 0x3f, 0x25, 0x1d, 0x0c, 0x30, 0x15, 0x1a, + 0xa3, 0x28, 0x5d, 0x87, 0xc3, 0x91, 0x89, 0x43, 0x31, 0x65, 0x6c, 0xe8, 0xd9, 0x96, 0xed, 0x2d, 0x95, 0x1e, 0x27, + 0xec, 0x9c, 0xc9, 0xb7, 0x9e, 0xad, 0x9a, 0x6a, 0x45, 0x8f, 0x01, 0x28, 0x34, 0x2e, 0xcf, 0x3f, 0x25, 0x6f, 0x9b, + 0xa8, 0x48, 0xa9, 0x52, 0xeb, 0x87, 0xb4, 0xab, 0x8b, 0x0b, 0xcf, 0x36, 0xa6, 0x5f, 0x0b, 0x57, 0x6f, 0x4d, 0x79, + 0xd0, 0xf4, 0x9a, 0xeb, 0x20, 0xf3, 0xc0, 0x8f, 0xb4, 0xed, 0xbe, 0xa2, 0x11, 0x85, 0x7b, 0xcc, 0x0b, 0xec, 0xeb, + 0x68, 0x75, 0x2b, 0xf6, 0xa7, 0x39, 0x0e, 0x95, 0xb2, 0xa2, 0xb8, 0x05, 0x79, 0x58, 0x3e, 0xcf, 0xae, 0x5a, 0xdb, + 0x6b, 0x46, 0x01, 0x14, 0xda, 0x0f, 0x1f, 0x0a, 0x70, 0x3d, 0x47, 0xbb, 0x90, 0x66, 0x63, 0x36, 0x1a, 0x81, 0x10, + 0x29, 0xdc, 0x2a, 0x1f, 0x74, 0x14, 0x27, 0x1c, 0xcf, 0xb3, 0xc3, 0xae, 0xfd, 0x16, 0x36, 0x06, 0x5e, 0x0f, 0x75, + 0xa5, 0x5f, 0xaf, 0x32, 0xfd, 0x94, 0xd0, 0x5d, 0x0d, 0x97, 0x18, 0xb2, 0x0e, 0x93, 0x9c, 0xe6, 0xfa, 0x5a, 0xf9, + 0xcb, 0xb5, 0xf2, 0x3a, 0x39, 0x33, 0x72, 0x88, 0x57, 0xef, 0x9b, 0xbb, 0xec, 0x8e, 0x7f, 0xfd, 0xa7, 0xbf, 0xff, + 0x6f, 0x00, 0x06, 0x8e, 0x73, 0xb7, 0xad, 0x01, 0x1d, 0xfe, 0x27, 0x74, 0x98, 0xa5, 0x77, 0xef, 0xf2, 0xd7, 0xff, + 0xf2, 0xdf, 0xa1, 0x07, 0x5d, 0x60, 0x86, 0x7d, 0xa4, 0x40, 0x1f, 0x60, 0xd8, 0xe8, 0x77, 0xc1, 0x5e, 0x1b, 0xf7, + 0x2e, 0x70, 0xfc, 0x03, 0xa2, 0x5a, 0xf0, 0x6c, 0x7a, 0x57, 0xb8, 0x11, 0xd3, 0x41, 0x92, 0x15, 0xcc, 0x04, 0x5c, + 0x58, 0x0a, 0xbf, 0x0f, 0x72, 0x82, 0x64, 0x0a, 0x12, 0xb4, 0xb0, 0xcc, 0xa1, 0x25, 0xaf, 0xdc, 0x28, 0x08, 0x57, + 0x32, 0x54, 0xc1, 0x38, 0x91, 0x82, 0xac, 0xb9, 0x1a, 0xd3, 0x88, 0xb2, 0x25, 0x5e, 0x22, 0xe9, 0xae, 0x25, 0x97, + 0xd0, 0x58, 0xb7, 0xcc, 0xbb, 0x62, 0x7f, 0x89, 0x69, 0xc5, 0x99, 0xd7, 0xf2, 0xf0, 0xb5, 0x12, 0x50, 0x5d, 0xc7, + 0x2b, 0x4a, 0xa3, 0xcb, 0x15, 0xa5, 0xa8, 0x04, 0x35, 0x6c, 0x60, 0xed, 0x4d, 0xc4, 0x4b, 0x2f, 0xf4, 0xeb, 0x2e, + 0x6a, 0xd0, 0x91, 0x2a, 0xc3, 0x53, 0xfc, 0xfa, 0x2b, 0x00, 0xe4, 0x50, 0x42, 0xad, 0x1d, 0xe3, 0xbd, 0x1a, 0xbc, + 0x45, 0x3d, 0xcb, 0x19, 0xec, 0x99, 0x0b, 0xf3, 0x68, 0xfe, 0xe6, 0xc6, 0x63, 0x10, 0x0f, 0x3d, 0xb0, 0x27, 0xf5, + 0xaa, 0xde, 0x38, 0x6e, 0xf9, 0x2f, 0xff, 0xec, 0xfb, 0xff, 0xf2, 0xcf, 0xb7, 0x36, 0xc5, 0x51, 0xc1, 0x65, 0xe7, + 0xd5, 0xb0, 0xeb, 0xa9, 0xbb, 0x7a, 0xa6, 0x3a, 0xb9, 0x57, 0xb7, 0x59, 0xa2, 0x3f, 0xd6, 0x2f, 0x91, 0x7f, 0xa9, + 0x50, 0x50, 0xdf, 0xfa, 0x2d, 0x80, 0x21, 0x5e, 0xb7, 0x42, 0x86, 0x8d, 0x7e, 0x17, 0x68, 0x27, 0x6e, 0x70, 0xa7, + 0x15, 0xf9, 0xed, 0x14, 0xbe, 0x0d, 0x87, 0xdf, 0x09, 0xbe, 0x48, 0x07, 0x06, 0xd0, 0x4e, 0xd4, 0x8d, 0xa9, 0x5a, + 0x57, 0xbc, 0x74, 0xd9, 0x5b, 0x2a, 0x91, 0x6a, 0x25, 0x68, 0xba, 0xdd, 0xe6, 0xd6, 0x96, 0x83, 0xdd, 0xdf, 0xe0, + 0x9b, 0x21, 0xf6, 0x4e, 0x73, 0x15, 0x03, 0xb9, 0x41, 0x34, 0xe0, 0x10, 0x75, 0xac, 0x68, 0xd0, 0x25, 0xb9, 0x80, + 0xa5, 0x98, 0x61, 0x8a, 0x60, 0x7a, 0x60, 0x0e, 0x0b, 0x7b, 0xed, 0x99, 0x70, 0x6c, 0x82, 0x45, 0xd6, 0x96, 0x0e, + 0x4f, 0x8d, 0xe8, 0x9e, 0x75, 0x48, 0xf4, 0xa2, 0xc6, 0xac, 0xb2, 0x97, 0xc9, 0x4b, 0x44, 0x03, 0xf1, 0x44, 0xbc, + 0x2b, 0xe3, 0xeb, 0x75, 0xf1, 0xf6, 0xef, 0x6f, 0x8f, 0xb7, 0xc7, 0x77, 0x8c, 0xb7, 0x7f, 0xff, 0x07, 0xc7, 0xdb, + 0xbf, 0x36, 0xe3, 0xed, 0xb8, 0x88, 0x3f, 0xdf, 0x29, 0x26, 0xae, 0x22, 0x95, 0xd9, 0x45, 0x11, 0xb6, 0xa4, 0xa5, + 0x04, 0x8e, 0x34, 0x06, 0xc4, 0xff, 0xed, 0xe3, 0xdb, 0x30, 0xd1, 0x42, 0x74, 0x9b, 0xc2, 0xd9, 0x92, 0x07, 0x99, + 0x0a, 0x26, 0x37, 0x75, 0xee, 0x77, 0xe3, 0x81, 0xba, 0xec, 0x0a, 0x2e, 0x8c, 0xab, 0x0f, 0x04, 0xda, 0x2a, 0xdc, + 0x1c, 0xd0, 0xdb, 0xaa, 0x75, 0xc7, 0xf6, 0xb6, 0x4a, 0x3a, 0x36, 0x47, 0xe8, 0xa8, 0xb3, 0x64, 0x71, 0x53, 0x72, + 0x6e, 0xff, 0xa7, 0xa3, 0x56, 0x67, 0xb7, 0x35, 0x81, 0xde, 0xc0, 0x87, 0xf0, 0xd4, 0xec, 0xec, 0xee, 0xe2, 0xd3, + 0x85, 0x7a, 0x6a, 0xe3, 0x53, 0xac, 0x9e, 0x1e, 0xe2, 0xd3, 0x40, 0x3d, 0x3d, 0xc2, 0xa7, 0xa1, 0x7a, 0x7a, 0x8c, + 0x4f, 0xe7, 0x76, 0x79, 0xc4, 0x34, 0x70, 0x8f, 0xdd, 0xbe, 0x27, 0x4c, 0x51, 0x55, 0xf6, 0xd8, 0x6b, 0x61, 0x40, + 0x3b, 0x3a, 0x0b, 0x62, 0x4f, 0x38, 0xd4, 0x41, 0xe1, 0x5d, 0x8c, 0x59, 0x1a, 0x50, 0x4e, 0xf4, 0x73, 0x7c, 0x5b, + 0x10, 0xd8, 0xc0, 0x87, 0xf1, 0x84, 0xa9, 0xd7, 0xa6, 0x2b, 0xac, 0x41, 0x25, 0x1f, 0x35, 0xfb, 0x65, 0x47, 0xaf, + 0x93, 0x88, 0x84, 0xab, 0xf4, 0x4e, 0x5a, 0xb9, 0xaa, 0x4e, 0x4c, 0xd7, 0xd0, 0x2b, 0xbc, 0x26, 0xa8, 0x6a, 0xf8, + 0x95, 0x23, 0x90, 0xcd, 0x8d, 0x4b, 0x70, 0x2c, 0x57, 0x06, 0x5a, 0x11, 0x22, 0x1d, 0x68, 0x25, 0x9c, 0xf4, 0xd3, + 0x61, 0x74, 0xa6, 0xbf, 0xbf, 0x01, 0xdb, 0x21, 0x3a, 0x93, 0x2d, 0xd7, 0x07, 0x56, 0x09, 0x44, 0x33, 0xa8, 0xaa, + 0x80, 0x40, 0xc7, 0x13, 0x97, 0x06, 0xc3, 0x04, 0x32, 0x56, 0x8a, 0xd4, 0xa9, 0x87, 0x59, 0x69, 0xfa, 0x7a, 0x11, + 0x50, 0xb4, 0x2a, 0xd8, 0x03, 0x13, 0x86, 0x4a, 0x05, 0x85, 0xa1, 0x02, 0x0b, 0x44, 0xf5, 0x9a, 0x70, 0xaa, 0x72, + 0xfd, 0xd6, 0x07, 0x55, 0x2d, 0x15, 0x4f, 0x35, 0xcf, 0xa0, 0xf5, 0x01, 0xf4, 0x72, 0x14, 0xef, 0x5e, 0x6b, 0x80, + 0xff, 0xc9, 0x18, 0xe1, 0xbd, 0xd1, 0x68, 0x74, 0x63, 0x7c, 0xf5, 0xde, 0x70, 0xc4, 0xda, 0xec, 0x61, 0x07, 0xcf, + 0x27, 0x1b, 0x32, 0x6a, 0xd7, 0x2a, 0x89, 0x76, 0xf3, 0xbb, 0x35, 0xc6, 0x00, 0x1f, 0x1f, 0xcf, 0xef, 0x1e, 0x6b, + 0x2d, 0x81, 0x2a, 0xf3, 0x09, 0x48, 0xc5, 0x38, 0x0d, 0x9a, 0xa5, 0x7f, 0x2e, 0x83, 0x93, 0xf7, 0x9e, 0x3c, 0x79, + 0x52, 0xfa, 0x43, 0xf5, 0xd4, 0x1c, 0x0e, 0x4b, 0x7f, 0x30, 0xd7, 0x68, 0x34, 0x9b, 0xa3, 0x51, 0xe9, 0xc7, 0xaa, + 0x60, 0xb7, 0x3d, 0x18, 0xee, 0xb6, 0x4b, 0xff, 0xc2, 0x68, 0x51, 0xfa, 0x4c, 0x3e, 0xe5, 0x6c, 0x58, 0x3b, 0xe4, + 0x7c, 0x0c, 0xde, 0xb6, 0x2f, 0x18, 0x6d, 0x8e, 0x86, 0xb6, 0xf8, 0x1a, 0x44, 0x33, 0x9e, 0xa1, 0x00, 0xee, 0x00, + 0x9f, 0x1f, 0x6d, 0xca, 0x6b, 0xcc, 0xe2, 0xad, 0xe4, 0x25, 0x6c, 0xa1, 0x9f, 0xcd, 0x60, 0x23, 0x32, 0x33, 0x05, + 0x19, 0x63, 0x15, 0x8b, 0xac, 0x55, 0x23, 0x67, 0x51, 0xf5, 0xcf, 0x61, 0x5c, 0xc5, 0x20, 0x51, 0xda, 0x60, 0x4b, + 0x91, 0x8c, 0xf3, 0xdd, 0x3a, 0x19, 0xff, 0xc5, 0xed, 0x32, 0xfe, 0xea, 0x6e, 0x22, 0xfe, 0x8b, 0x3f, 0x58, 0xc4, + 0x7f, 0x67, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0x79, 0x68, 0x0f, 0xc6, 0x6c, 0xf0, 0xe9, 0x34, 0xbb, 0x6c, 0xe0, 0x96, + 0xc8, 0x6d, 0x92, 0x9e, 0x93, 0xdf, 0x7a, 0x20, 0xaa, 0x06, 0x33, 0x5e, 0x71, 0x4e, 0x4a, 0xf2, 0x5d, 0x1a, 0xda, + 0xef, 0x94, 0xfd, 0x2e, 0x4a, 0x46, 0x23, 0x28, 0x1a, 0x8d, 0x6c, 0x75, 0x79, 0x03, 0xc4, 0x16, 0xb5, 0x7a, 0x5b, + 0x2b, 0xa1, 0x56, 0x9f, 0x7f, 0x6e, 0x96, 0x99, 0x05, 0x32, 0x64, 0x69, 0x86, 0x27, 0x65, 0xcd, 0x30, 0x2e, 0x70, + 0xab, 0xe1, 0x9b, 0xd7, 0x97, 0x5e, 0x69, 0x25, 0x02, 0xab, 0xcb, 0x00, 0x57, 0xf1, 0x55, 0xe3, 0xed, 0xa9, 0x55, + 0x84, 0x15, 0x16, 0x54, 0x66, 0xd6, 0x3d, 0xbd, 0x7a, 0x35, 0x74, 0xf6, 0xb9, 0x5b, 0xc6, 0xc5, 0xbb, 0x74, 0x21, + 0x63, 0x59, 0xc0, 0x18, 0x86, 0x26, 0x5a, 0x25, 0xcf, 0xce, 0xce, 0x92, 0xe5, 0x1c, 0x58, 0xd1, 0xbd, 0x57, 0xc3, + 0x37, 0x30, 0x3b, 0x4a, 0x5d, 0x46, 0x3f, 0x99, 0x21, 0x52, 0xfb, 0x28, 0x27, 0x5b, 0x1d, 0xed, 0xce, 0xa5, 0xfc, + 0x97, 0x49, 0x5f, 0x8c, 0x0e, 0x51, 0x69, 0xe0, 0x61, 0x59, 0xca, 0xcc, 0x5a, 0x20, 0xc4, 0x14, 0xdf, 0xff, 0x26, + 0x7a, 0xc6, 0xb7, 0x89, 0xf0, 0xe2, 0xc2, 0x88, 0x0b, 0xd6, 0x96, 0xab, 0x54, 0x81, 0x41, 0x11, 0xdd, 0xdb, 0xc7, + 0x10, 0xa5, 0x88, 0x11, 0x2a, 0x22, 0xda, 0x56, 0x8f, 0xbe, 0xca, 0x88, 0x65, 0x85, 0x21, 0x06, 0x33, 0xf5, 0x82, + 0xa8, 0x2a, 0x55, 0x50, 0x9a, 0x81, 0x6f, 0xaa, 0x11, 0xd4, 0xa2, 0x30, 0x1b, 0xc0, 0x9e, 0x0a, 0x31, 0x0a, 0xd3, + 0x90, 0x3c, 0xd8, 0x9c, 0x57, 0x2b, 0x0f, 0x5d, 0x25, 0xd8, 0x82, 0x79, 0x41, 0x06, 0x63, 0x87, 0xae, 0x55, 0x03, + 0x3d, 0x5d, 0x8a, 0xce, 0xdd, 0x7c, 0xee, 0x75, 0xe2, 0x17, 0x17, 0x1e, 0xfc, 0x59, 0x7f, 0x9a, 0x83, 0xd0, 0x39, + 0xfd, 0x14, 0xf3, 0x06, 0x8f, 0xa6, 0x0d, 0xb4, 0xee, 0x29, 0xc8, 0x23, 0xa5, 0x33, 0xe5, 0x6f, 0x88, 0x7b, 0x96, + 0x9d, 0x59, 0x81, 0xc7, 0x63, 0x64, 0xa3, 0x06, 0x69, 0x96, 0xb2, 0x4e, 0x3d, 0x4f, 0xc7, 0x3c, 0x6d, 0x51, 0xc4, + 0xea, 0xcf, 0x33, 0x3c, 0x4e, 0xe3, 0x57, 0x41, 0x53, 0x4a, 0xf5, 0xa6, 0x3a, 0x6a, 0x69, 0xae, 0x6c, 0x1f, 0x48, + 0xda, 0x6e, 0x93, 0xf2, 0xca, 0x97, 0x8f, 0x94, 0xd6, 0x1d, 0x09, 0xdd, 0x96, 0xb5, 0x82, 0xc1, 0x21, 0xf5, 0x67, + 0xa4, 0xfb, 0x2c, 0x16, 0x53, 0xd6, 0xca, 0x5d, 0x20, 0x0b, 0xa2, 0x11, 0xbe, 0x96, 0xf4, 0x2e, 0x2d, 0x4f, 0x29, + 0x65, 0x7c, 0x8e, 0x5a, 0x26, 0x68, 0x3d, 0x99, 0x5e, 0xde, 0x7d, 0xf8, 0x9b, 0xd1, 0x2f, 0x25, 0x8d, 0xd4, 0xcd, + 0x7f, 0xdb, 0xee, 0xe0, 0x3e, 0x48, 0xa2, 0xab, 0x20, 0x4e, 0x49, 0xe5, 0x9d, 0x62, 0x94, 0xa7, 0x33, 0xcd, 0x64, + 0xfa, 0x55, 0xce, 0x12, 0xfa, 0xed, 0x1f, 0xb9, 0x14, 0xbb, 0x8f, 0xa6, 0x97, 0x6a, 0x35, 0x5a, 0x0b, 0x69, 0x55, + 0x7f, 0x68, 0xf6, 0xd4, 0xfa, 0x74, 0xad, 0x7a, 0x06, 0xd0, 0x43, 0x80, 0x41, 0xe8, 0xd9, 0x46, 0x2e, 0xa0, 0x6a, + 0x42, 0x89, 0x91, 0x3f, 0x56, 0x0d, 0x64, 0xf9, 0xbb, 0x20, 0xb9, 0xa3, 0x82, 0x75, 0xf0, 0xfd, 0xb0, 0xf1, 0x20, + 0x4a, 0xa4, 0x2e, 0x9f, 0xc4, 0xc3, 0x61, 0xc2, 0x3a, 0x4a, 0x5d, 0x5b, 0xad, 0x47, 0x98, 0x7e, 0x65, 0x2e, 0x59, + 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, 0xa7, 0x60, 0x3e, 0xe0, 0x4b, 0x5e, 0x57, 0x92, 0x53, 0xe6, 0x25, 0x35, + 0x2b, 0xe2, 0xd1, 0xf7, 0x3a, 0x2e, 0x0f, 0xc1, 0x76, 0xa1, 0x05, 0x6f, 0x76, 0x78, 0x36, 0x0d, 0x1a, 0xbb, 0x75, + 0x44, 0xb0, 0x4a, 0xa3, 0xe0, 0xad, 0x40, 0xcb, 0x43, 0x65, 0x25, 0x04, 0xb4, 0xe5, 0xb7, 0x64, 0x19, 0x0d, 0x80, + 0x2f, 0x12, 0xd5, 0x45, 0x65, 0x1d, 0x99, 0x7f, 0x9b, 0xdd, 0xf2, 0xd9, 0xea, 0xdd, 0xf2, 0x99, 0xda, 0x2d, 0x37, + 0x73, 0xec, 0xbd, 0x51, 0x0b, 0xff, 0xeb, 0x54, 0x08, 0xc1, 0xaa, 0x00, 0x39, 0x2c, 0x34, 0xd3, 0x1a, 0x6d, 0xf8, + 0x87, 0x86, 0xc6, 0x18, 0x74, 0x13, 0xf3, 0xc9, 0xbc, 0xa6, 0x85, 0x85, 0xf8, 0xd7, 0xac, 0x55, 0xb5, 0x1e, 0x60, + 0x1d, 0xf6, 0x7a, 0xb8, 0x5c, 0xd7, 0xbe, 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0x78, 0x0e, 0xd1, + 0xe9, 0x29, 0x94, 0x8e, 0xb2, 0xc1, 0xac, 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0x7a, 0x61, 0x1c, 0xd5, + 0x55, 0xe4, 0xf2, 0xa9, 0x11, 0xe6, 0x7a, 0x9d, 0x82, 0x02, 0x18, 0x93, 0x39, 0x6d, 0xff, 0xc1, 0x8a, 0x4d, 0xf0, + 0xef, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0xbd, 0xc4, 0xb8, 0x91, 0x08, 0xbf, 0x8a, 0x06, 0xe6, 0x1a, 0x36, 0x9f, 0xac, + 0x06, 0xf7, 0x48, 0xcd, 0xd4, 0x57, 0x4a, 0x41, 0xea, 0x1d, 0x30, 0x4a, 0xa3, 0x59, 0xc2, 0x6f, 0x1e, 0x75, 0x1d, + 0x67, 0x2c, 0x8d, 0x7a, 0x83, 0x40, 0xaf, 0xda, 0xde, 0x51, 0x4a, 0xdf, 0xfb, 0xec, 0x01, 0xfe, 0x27, 0xd2, 0x05, + 0xae, 0x2a, 0x53, 0x5d, 0xb8, 0xaa, 0x68, 0xaa, 0x4f, 0x6a, 0xb6, 0xb8, 0xd0, 0xe0, 0x64, 0x8e, 0xdf, 0xb5, 0x35, + 0x1a, 0x95, 0x77, 0x6a, 0x2e, 0x8d, 0xac, 0x5f, 0xd5, 0xfa, 0xd7, 0x0d, 0x7e, 0xc7, 0xb6, 0x03, 0x61, 0xb8, 0xd6, + 0xdb, 0xca, 0xdf, 0x61, 0x5a, 0x6a, 0xac, 0x28, 0x4e, 0xed, 0x27, 0xe1, 0x95, 0xf6, 0x50, 0xc4, 0xb9, 0x12, 0x3a, + 0x29, 0x13, 0xe1, 0xa4, 0xfc, 0x85, 0x87, 0xf7, 0xf1, 0x85, 0x84, 0xd6, 0xe5, 0x24, 0x49, 0xc1, 0x48, 0x1a, 0x73, + 0x3e, 0x0d, 0x76, 0x76, 0x2e, 0x2e, 0x2e, 0xfc, 0x8b, 0x5d, 0x3f, 0xcb, 0xcf, 0x76, 0xda, 0xcd, 0x66, 0x13, 0xdf, + 0x23, 0x67, 0x5b, 0xe7, 0x31, 0xbb, 0x78, 0x0a, 0x76, 0xb0, 0xfd, 0xd8, 0x7a, 0x62, 0x3d, 0xde, 0xb5, 0x1e, 0x3e, + 0xb2, 0x2d, 0x12, 0xe7, 0x50, 0xb2, 0x6b, 0x5b, 0x42, 0x9c, 0x87, 0x36, 0x14, 0x77, 0xf7, 0xce, 0x94, 0x45, 0x86, + 0xf7, 0x74, 0x84, 0xbd, 0x03, 0xce, 0x41, 0xf6, 0x89, 0xd5, 0x37, 0xae, 0x28, 0x6b, 0x48, 0xa5, 0xa0, 0x1e, 0x71, + 0xf7, 0x0e, 0xa2, 0x69, 0x40, 0x4c, 0x61, 0x16, 0x62, 0x0c, 0x46, 0x94, 0xd2, 0x14, 0x68, 0x65, 0x9e, 0xc2, 0x37, + 0x4c, 0xec, 0xb4, 0xe0, 0xfb, 0x9b, 0xf6, 0x63, 0xd0, 0x58, 0xe7, 0x8d, 0x07, 0x83, 0x66, 0xa3, 0x65, 0xb5, 0x1a, + 0x6d, 0xff, 0xb1, 0xd5, 0x16, 0xff, 0x82, 0xc4, 0xdb, 0xb5, 0x5a, 0xf0, 0x6d, 0xd7, 0x82, 0xe7, 0xf3, 0x07, 0xe2, + 0x00, 0x3a, 0xb2, 0x77, 0xba, 0x7b, 0xf8, 0xb3, 0x6a, 0x80, 0xd4, 0x67, 0xb6, 0xf8, 0x21, 0x48, 0xfb, 0x9e, 0x59, + 0xda, 0x7a, 0xb2, 0xb2, 0xb8, 0xfd, 0x78, 0x65, 0xf1, 0xee, 0xa3, 0x95, 0xc5, 0x0f, 0x1e, 0xd6, 0x8b, 0x77, 0xce, + 0x44, 0x95, 0xde, 0xe5, 0xa1, 0x3d, 0x89, 0x60, 0xd9, 0x2f, 0x9d, 0x16, 0xc0, 0xd9, 0xb4, 0x1a, 0xf8, 0xf1, 0xb8, + 0xed, 0xea, 0x5e, 0xa7, 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfd, 0x68, 0x80, 0xed, 0x08, 0x51, + 0xf8, 0x3b, 0xdf, 0x7d, 0x32, 0x00, 0xf9, 0x6e, 0xe1, 0x1f, 0xfc, 0x37, 0x7e, 0xd8, 0x1e, 0x88, 0x87, 0x26, 0xd6, + 0x7f, 0xd3, 0x7a, 0x5c, 0x40, 0x53, 0xfc, 0xef, 0x17, 0x6d, 0x10, 0xa3, 0x39, 0x6e, 0x8e, 0xfb, 0x00, 0x68, 0xf4, + 0x64, 0xdc, 0xf6, 0x3f, 0x3b, 0x7f, 0xec, 0x3f, 0x19, 0xb7, 0x1e, 0x7f, 0x23, 0x9e, 0x12, 0xa0, 0xe0, 0x67, 0xf8, + 0xf7, 0xcd, 0x6e, 0x13, 0xbc, 0x4b, 0xff, 0xc9, 0xf9, 0xae, 0xbf, 0x9b, 0x34, 0x1e, 0xf9, 0x4f, 0xf0, 0xaf, 0x1a, + 0x6e, 0x9c, 0x4d, 0x98, 0x6d, 0xe1, 0x7a, 0x2f, 0x78, 0x5b, 0xe6, 0x1c, 0xed, 0x07, 0xd6, 0xc3, 0x07, 0x2f, 0x9f, + 0xc0, 0x1a, 0x8d, 0x5b, 0x6d, 0xf8, 0x77, 0xdd, 0xd7, 0x6f, 0x90, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x86, 0xbd, 0x22, + 0x1c, 0xbd, 0xd3, 0xf0, 0xbe, 0x07, 0x0e, 0xd4, 0x6a, 0xef, 0x9a, 0xb1, 0xdb, 0x23, 0xa8, 0xec, 0x6e, 0xee, 0x35, + 0x63, 0x7f, 0xac, 0x7b, 0xcd, 0xd9, 0x42, 0x04, 0xf5, 0x92, 0x2f, 0x79, 0xd1, 0x8b, 0xae, 0xd7, 0x07, 0xee, 0x1c, + 0xfd, 0x85, 0xf7, 0xf1, 0x36, 0x09, 0xb4, 0x8e, 0x99, 0x19, 0x6c, 0xc8, 0x70, 0x23, 0xe3, 0x8f, 0x2b, 0xd2, 0xdd, + 0x9f, 0x75, 0x04, 0xc9, 0x6f, 0x27, 0xc8, 0x37, 0x77, 0xa3, 0x47, 0xfe, 0x07, 0xd3, 0xa3, 0x30, 0xe9, 0x51, 0x0b, + 0xe7, 0x92, 0x3b, 0x4b, 0xee, 0xe8, 0x01, 0x3d, 0x3b, 0x98, 0x84, 0xbd, 0x6d, 0xef, 0x30, 0x2c, 0x2a, 0x6c, 0x71, + 0x88, 0xf0, 0xf4, 0xd7, 0xc4, 0x9f, 0xc5, 0x8d, 0x8b, 0xd0, 0x96, 0xbe, 0xff, 0x14, 0xdf, 0xdb, 0xad, 0x1e, 0xce, + 0xc5, 0xad, 0xbe, 0x90, 0xae, 0xe4, 0x3e, 0xd4, 0x71, 0x03, 0xbc, 0x04, 0x13, 0xce, 0x33, 0x1e, 0xe1, 0x0f, 0xc3, + 0x01, 0xb9, 0xe9, 0x27, 0xe4, 0x62, 0x9e, 0x30, 0x3c, 0x24, 0x1f, 0x88, 0x77, 0x28, 0xc3, 0x57, 0x79, 0xdd, 0x16, + 0x6f, 0x71, 0x7c, 0x8d, 0x37, 0x50, 0x54, 0x60, 0x7a, 0x82, 0x2e, 0xf5, 0x1b, 0x36, 0x8c, 0x23, 0xc7, 0x76, 0xa6, + 0xb0, 0x91, 0x61, 0x96, 0x46, 0xed, 0xfa, 0x07, 0xdd, 0xfc, 0x70, 0x6d, 0xf5, 0xeb, 0x64, 0x39, 0xbe, 0xed, 0x31, + 0x3c, 0x92, 0x41, 0x2d, 0x5b, 0x9a, 0xf9, 0x30, 0xbe, 0x2a, 0xc9, 0x51, 0xa2, 0x57, 0xa6, 0x81, 0x2d, 0x6c, 0x83, + 0x96, 0xdf, 0x06, 0x5f, 0x81, 0x8a, 0xf1, 0xed, 0x79, 0xdf, 0x39, 0x8d, 0x5d, 0xb0, 0x5d, 0x8c, 0x6e, 0x7a, 0xa0, + 0xbe, 0xfe, 0xb1, 0x2b, 0xfd, 0x83, 0x8c, 0xf5, 0x3b, 0x33, 0xb6, 0xe0, 0x88, 0x7b, 0x02, 0x77, 0x5b, 0xbc, 0xa5, + 0x84, 0xa8, 0x47, 0x77, 0x46, 0xa1, 0xcc, 0x31, 0x7f, 0x98, 0x4f, 0xbc, 0x9d, 0x4f, 0xfc, 0x06, 0x67, 0x59, 0x35, + 0xe1, 0xee, 0x9c, 0x02, 0xef, 0x98, 0x64, 0x8c, 0x57, 0x75, 0x31, 0x0e, 0x1b, 0x1a, 0x34, 0xc5, 0x67, 0xb7, 0x46, + 0x64, 0xee, 0x69, 0x80, 0x88, 0xc0, 0xa1, 0xfc, 0xac, 0x8a, 0xd5, 0x17, 0x19, 0x5d, 0x01, 0xb7, 0x1d, 0x7f, 0xf9, + 0x88, 0x3e, 0x96, 0x62, 0x37, 0xe2, 0xec, 0x60, 0xa1, 0xb4, 0x1a, 0xaa, 0x8a, 0xd1, 0x14, 0x4f, 0xaf, 0x0e, 0xe5, + 0x6b, 0x3f, 0x6c, 0x0c, 0x81, 0x52, 0xe8, 0xbb, 0x7a, 0xe5, 0xe0, 0x36, 0xa8, 0x46, 0xfa, 0x21, 0x60, 0xca, 0x60, + 0x42, 0xed, 0x87, 0xb7, 0x6e, 0x2c, 0xe9, 0xf3, 0x84, 0xb6, 0xd0, 0x7d, 0x43, 0x76, 0x1e, 0x0f, 0xa4, 0x0a, 0xf3, + 0x2c, 0x79, 0x5b, 0xb0, 0x41, 0x4b, 0x13, 0xb6, 0x3c, 0xe1, 0xf5, 0xc3, 0x03, 0xea, 0xe3, 0x30, 0xcd, 0xec, 0xee, + 0xfd, 0xce, 0x3a, 0xe2, 0xe3, 0xaf, 0x12, 0x1f, 0x81, 0x97, 0xf9, 0xb7, 0xe1, 0x7d, 0xfc, 0x5d, 0xe2, 0xfb, 0x7d, + 0xdb, 0xf5, 0x49, 0x01, 0xdc, 0xaf, 0x7e, 0x9c, 0x18, 0xa5, 0xdf, 0x36, 0xe8, 0x6a, 0xef, 0xae, 0x4a, 0x5b, 0x2a, + 0xe8, 0xf6, 0xc3, 0x4a, 0x41, 0xc3, 0x77, 0x43, 0x22, 0x83, 0xb2, 0x68, 0xfb, 0x0f, 0x0d, 0xb1, 0x7f, 0xde, 0xc0, + 0xcf, 0x9a, 0xe0, 0x7f, 0x00, 0x0d, 0x94, 0xe4, 0x7f, 0x0d, 0xcd, 0x77, 0x85, 0x92, 0x81, 0x7e, 0xdf, 0x93, 0x58, + 0x96, 0x22, 0xb9, 0xb6, 0x0d, 0x56, 0x9c, 0xc6, 0x88, 0x6c, 0x2c, 0xdb, 0x73, 0xf4, 0x2f, 0x1e, 0xc9, 0x5d, 0x29, + 0xe3, 0x40, 0xcf, 0xa1, 0xaf, 0xa3, 0xdf, 0xe4, 0xbf, 0xaa, 0xce, 0xab, 0x49, 0x89, 0x15, 0x53, 0xe0, 0xbe, 0x5e, + 0x38, 0xf1, 0xe9, 0x88, 0x2b, 0x0c, 0xfa, 0x55, 0x40, 0xeb, 0x19, 0x5a, 0xde, 0x75, 0x70, 0x0d, 0x11, 0xc1, 0xe8, + 0x6d, 0xc3, 0x34, 0xc9, 0xab, 0x61, 0xb9, 0x38, 0x3f, 0xa6, 0x83, 0xe5, 0x99, 0x71, 0xa7, 0x50, 0x46, 0xef, 0x30, + 0x59, 0x74, 0x18, 0xe7, 0xf4, 0x62, 0x04, 0x05, 0x7a, 0x2d, 0x02, 0x58, 0x51, 0x89, 0xa4, 0x04, 0x2b, 0x7a, 0x36, + 0x16, 0xd9, 0x81, 0x4d, 0xe1, 0x23, 0xdb, 0x7c, 0xdd, 0xbe, 0x79, 0x73, 0x9d, 0x38, 0x99, 0x12, 0xbb, 0x71, 0xaf, + 0x22, 0x7d, 0x6c, 0x90, 0xb6, 0x6b, 0x77, 0x09, 0xd9, 0x60, 0x88, 0x6b, 0xf5, 0xfb, 0x72, 0xa6, 0x00, 0xb2, 0x4d, + 0x42, 0xeb, 0x71, 0x89, 0x84, 0xae, 0xa4, 0xd3, 0x29, 0x8b, 0xb8, 0x1f, 0xa5, 0x22, 0x0b, 0xc1, 0x10, 0x53, 0x5e, + 0x8b, 0xed, 0xba, 0x25, 0xc8, 0x46, 0x23, 0x6f, 0x42, 0xee, 0x6e, 0x28, 0x54, 0x17, 0x3d, 0x18, 0xaf, 0xe5, 0xb3, + 0x8e, 0xdb, 0xdd, 0x77, 0x87, 0xfb, 0x96, 0xd8, 0x94, 0x7b, 0x3b, 0xf0, 0xb8, 0x47, 0xfe, 0xb8, 0x48, 0xde, 0x0f, + 0x45, 0xf2, 0xbe, 0x25, 0x6f, 0x71, 0x50, 0x86, 0xe3, 0x8e, 0x40, 0xdb, 0xb6, 0x58, 0x3a, 0x10, 0x81, 0xc4, 0x09, + 0xf8, 0x2c, 0x31, 0xbe, 0xa2, 0x71, 0x07, 0xbb, 0x36, 0x70, 0xc1, 0x80, 0x9b, 0x45, 0xd4, 0x51, 0xd9, 0x35, 0x3c, + 0x55, 0x61, 0x47, 0xb0, 0x46, 0x98, 0xca, 0x40, 0x94, 0x43, 0xe9, 0xe4, 0xc5, 0xe5, 0xd6, 0xc5, 0xec, 0x74, 0x02, + 0x72, 0x52, 0xe5, 0x10, 0x7e, 0x94, 0x1d, 0xf6, 0x68, 0xaa, 0xee, 0x49, 0x29, 0xe3, 0xa2, 0xea, 0xf5, 0xf9, 0x0b, + 0x3f, 0x35, 0x2c, 0xb0, 0x97, 0x7a, 0x01, 0xb3, 0xf0, 0xc7, 0xbb, 0x5d, 0x1d, 0x89, 0x34, 0xeb, 0x4a, 0x40, 0x7d, + 0xb7, 0x7b, 0x12, 0x4c, 0xe5, 0x78, 0xaf, 0xb3, 0xa5, 0x9f, 0x2d, 0xd6, 0x72, 0xb2, 0x47, 0xd9, 0xa9, 0xe2, 0x6a, + 0x93, 0x04, 0x18, 0x56, 0x10, 0x60, 0x92, 0x26, 0x80, 0x45, 0xe7, 0xaa, 0xf6, 0xc3, 0xa6, 0x4a, 0x78, 0x85, 0x32, + 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0x98, 0x3b, 0x6e, 0x75, 0xf7, 0x22, 0x69, 0x5c, 0xa2, 0xf0, 0x28, 0x40, + 0x7a, 0x40, 0x67, 0xb4, 0xe0, 0xfc, 0x38, 0xdb, 0xb9, 0x60, 0xa7, 0x8d, 0x68, 0x1a, 0x57, 0x91, 0x53, 0x34, 0x35, + 0xf4, 0x94, 0x59, 0x35, 0x13, 0x7e, 0x8d, 0x16, 0x90, 0x24, 0xc1, 0x5d, 0xca, 0xb0, 0x2c, 0x59, 0xe8, 0xc0, 0x42, + 0x40, 0x61, 0x92, 0xeb, 0x2a, 0x7c, 0x2b, 0x35, 0x6e, 0x69, 0x77, 0xff, 0xfa, 0x8f, 0xff, 0x5b, 0x46, 0x64, 0x81, + 0x2a, 0x2d, 0x35, 0xd6, 0x02, 0xa1, 0xcb, 0x3d, 0xba, 0xb5, 0xa2, 0x8f, 0x10, 0xd9, 0x25, 0xb8, 0xf6, 0xf1, 0xb0, + 0x31, 0x8e, 0x92, 0x11, 0x00, 0xb6, 0x96, 0x40, 0x66, 0x52, 0xb8, 0x84, 0xba, 0x5e, 0x84, 0x2c, 0xf8, 0x9b, 0xd2, + 0x9b, 0x55, 0x96, 0x2c, 0xed, 0x56, 0x33, 0xd9, 0xb9, 0xda, 0x50, 0xb5, 0x84, 0x67, 0xf5, 0xdb, 0x7d, 0x4a, 0xa8, + 0xd5, 0xf2, 0x9c, 0xa1, 0xa5, 0x3e, 0x02, 0xf9, 0xd7, 0x7f, 0xfa, 0xbb, 0xff, 0xa1, 0x1e, 0xf1, 0x64, 0xe3, 0xaf, + 0xff, 0xf0, 0x9f, 0x31, 0x1b, 0xd3, 0xd2, 0xa7, 0x1f, 0x24, 0x27, 0xac, 0xea, 0xe8, 0x43, 0x08, 0x0c, 0x0b, 0x53, + 0x9d, 0x26, 0x20, 0x06, 0xe3, 0x41, 0x3d, 0xf3, 0xf9, 0x80, 0x26, 0xa4, 0xcd, 0x26, 0xa1, 0xa3, 0x4d, 0x5b, 0x56, + 0x3c, 0x52, 0x23, 0x39, 0xf1, 0x22, 0x54, 0x22, 0xbd, 0xef, 0x74, 0xfb, 0xc3, 0xd7, 0xab, 0x31, 0x57, 0xf1, 0x3e, + 0x2c, 0x29, 0xab, 0x72, 0x0b, 0x03, 0xf1, 0x73, 0x7c, 0x0c, 0xda, 0x46, 0x31, 0x2d, 0x5e, 0xad, 0x4f, 0xe7, 0xa7, + 0x19, 0xc0, 0x3f, 0x42, 0x8a, 0x8b, 0xa8, 0x22, 0x9d, 0x79, 0x36, 0xd0, 0xe6, 0x4b, 0xae, 0x4a, 0x1a, 0x45, 0x38, + 0x8a, 0x0f, 0x9e, 0xfc, 0x4d, 0xf9, 0xe7, 0x09, 0x5a, 0x56, 0x96, 0x33, 0x89, 0x2e, 0xa5, 0xfb, 0xf8, 0xa8, 0xd9, + 0x9c, 0x5e, 0xba, 0xf3, 0x6a, 0x06, 0x6f, 0xdd, 0x64, 0x14, 0x89, 0x34, 0x07, 0xa4, 0xc3, 0x52, 0x1d, 0xf4, 0x04, + 0x8f, 0xa9, 0x89, 0x31, 0xb2, 0xb2, 0xfc, 0xd3, 0x9c, 0xe2, 0x6e, 0xf1, 0x2f, 0x78, 0xa8, 0x29, 0x43, 0x94, 0x50, + 0x62, 0x60, 0x31, 0x37, 0x7a, 0xb5, 0x45, 0xaf, 0x71, 0x6b, 0xf9, 0xea, 0x83, 0x79, 0x28, 0x6b, 0x1e, 0xa7, 0x3e, + 0xc0, 0x03, 0xd2, 0x71, 0xcb, 0x1b, 0xb7, 0xe7, 0x7a, 0x78, 0xce, 0xb3, 0x89, 0x79, 0x0a, 0xcb, 0x22, 0x36, 0x60, + 0x23, 0x15, 0xda, 0x95, 0xf5, 0xe2, 0x84, 0xb5, 0x1c, 0xef, 0xae, 0x98, 0x4b, 0x82, 0x44, 0xa7, 0xaf, 0x00, 0xcf, + 0x3d, 0xdc, 0x80, 0x40, 0xff, 0x2c, 0xe2, 0x01, 0xf1, 0x6b, 0xc7, 0x3c, 0xcb, 0x8d, 0x50, 0xca, 0x64, 0x73, 0x03, + 0x9e, 0x8e, 0x68, 0x8a, 0x41, 0xd6, 0xfa, 0xd5, 0x93, 0xd2, 0xa7, 0xee, 0xe6, 0x50, 0x22, 0x46, 0xf3, 0x8d, 0x3c, + 0x22, 0x7d, 0x5a, 0x0b, 0x6e, 0x48, 0x15, 0xd3, 0x76, 0xbd, 0x95, 0xf5, 0x42, 0x53, 0x8b, 0xda, 0x6f, 0xb8, 0x63, + 0x13, 0x98, 0xf6, 0x62, 0x2b, 0x2a, 0xc4, 0x56, 0x4f, 0xc3, 0x6f, 0xb4, 0xeb, 0x13, 0x4d, 0xa7, 0xd4, 0xd0, 0x05, + 0x26, 0x26, 0x83, 0x15, 0x65, 0x07, 0x1d, 0xff, 0x8b, 0xd3, 0x76, 0xd9, 0x46, 0x6e, 0x04, 0xf1, 0x4d, 0x9e, 0xc3, + 0xe3, 0xaf, 0xae, 0x74, 0xff, 0x1f, 0x1c, 0x1d, 0xa5, 0x5f, 0x1b, 0x82, 0x00, 0x00}; } // namespace web_server } // namespace esphome From c3ef12d5807bc58400a2a837ceda138b735013f6 Mon Sep 17 00:00:00 2001 From: Ryan DeShone Date: Wed, 28 Jun 2023 19:42:39 -0400 Subject: [PATCH 0177/2607] [SCD30] Disable negative temperature offset (#4850) --- esphome/components/scd30/scd30.cpp | 19 ++++++++++++------- esphome/components/scd30/sensor.py | 5 ++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index 01abca0a1f..3eeca23800 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -42,13 +42,18 @@ void SCD30Component::setup() { ESP_LOGD(TAG, "SCD30 Firmware v%0d.%02d", (uint16_t(raw_firmware_version[0]) >> 8), uint16_t(raw_firmware_version[0] & 0xFF)); - if (this->temperature_offset_ != 0) { - if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t) (temperature_offset_ * 100.0))) { - ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); - this->error_code_ = MEASUREMENT_INIT_FAILED; - this->mark_failed(); - return; - } + uint16_t temp_offset; + if (this->temperature_offset_ > 0) { + temp_offset = (this->temperature_offset_ * 100); + } else { + temp_offset = 0; + } + + if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, temp_offset)) { + ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); + this->error_code_ = MEASUREMENT_INIT_FAILED; + this->mark_failed(); + return; } #ifdef USE_ESP32 // According ESP32 clock stretching is typically 30ms and up to 150ms "due to diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index 1ddf0f1e85..f72b43fd37 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -68,7 +68,10 @@ CONFIG_SCHEMA = ( cv.int_range(min=0, max=0xFFFF, max_included=False), ), cv.Optional(CONF_AMBIENT_PRESSURE_COMPENSATION, default=0): cv.pressure, - cv.Optional(CONF_TEMPERATURE_OFFSET): cv.temperature, + cv.Optional(CONF_TEMPERATURE_OFFSET): cv.All( + cv.temperature, + cv.float_range(min=0, max=655.35), + ), cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.All( cv.positive_time_period_seconds, cv.Range( From e823067a6b1bd2eff4d579e5612da2c067353219 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Tue, 4 Jul 2023 04:18:51 +0400 Subject: [PATCH 0178/2607] fix template binary_sensor publish_initial_state option (#5033) --- .../binary_sensor/template_binary_sensor.cpp | 16 +++++++++++++--- .../binary_sensor/template_binary_sensor.h | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.cpp b/esphome/components/template/binary_sensor/template_binary_sensor.cpp index 66ff4be4c4..fce11f63d6 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.cpp +++ b/esphome/components/template/binary_sensor/template_binary_sensor.cpp @@ -6,11 +6,21 @@ namespace template_ { static const char *const TAG = "template.binary_sensor"; -void TemplateBinarySensor::loop() { - if (!this->f_.has_value()) +void TemplateBinarySensor::setup() { + if (!this->publish_initial_state_) return; - auto s = (*this->f_)(); + if (this->f_ != nullptr) { + this->publish_initial_state(*this->f_()); + } else { + this->publish_initial_state(false); + } +} +void TemplateBinarySensor::loop() { + if (this->f_ == nullptr) + return; + + auto s = this->f_(); if (s.has_value()) { this->publish_state(*s); } diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.h b/esphome/components/template/binary_sensor/template_binary_sensor.h index a28929b122..5e5624d82e 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.h +++ b/esphome/components/template/binary_sensor/template_binary_sensor.h @@ -10,13 +10,14 @@ class TemplateBinarySensor : public Component, public binary_sensor::BinarySenso public: void set_template(std::function()> &&f) { this->f_ = f; } + void setup() override; void loop() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::HARDWARE; } protected: - optional()>> f_{}; + std::function()> f_{nullptr}; }; } // namespace template_ From 36782f13bf0bec2d7c0c989b3a8100903fa224f3 Mon Sep 17 00:00:00 2001 From: Graham Brown Date: Tue, 4 Jul 2023 02:28:19 +0200 Subject: [PATCH 0179/2607] Add alarm to reserved ids (#5042) --- esphome/config_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 0a6b2dfbb0..cf0b1d3aca 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -108,6 +108,7 @@ ROOT_CONFIG_PATH = object() RESERVED_IDS = [ # C++ keywords http://en.cppreference.com/w/cpp/keyword + "alarm", "alignas", "alignof", "and", From 8df455f55b8251005e0d150b2ffbaca0fc8079eb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 3 Jul 2023 19:52:42 -0500 Subject: [PATCH 0180/2607] Advertise noise is enabled (#5034) --- esphome/components/mdns/mdns_component.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index cdb9aa8e74..581758cf2d 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -57,6 +57,10 @@ void MDNSComponent::compile_records_() { service.txt_records.push_back({"network", "ethernet"}); #endif +#ifdef USE_API_NOISE + service.txt_records.push_back({"api_encryption", "Noise_NNpsk0_25519_ChaChaPoly_SHA256"}); +#endif + #ifdef ESPHOME_PROJECT_NAME service.txt_records.push_back({"project_name", ESPHOME_PROJECT_NAME}); service.txt_records.push_back({"project_version", ESPHOME_PROJECT_VERSION}); From 8dd509ba53084f9177550d5ff577bc3d8e6825b0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Jul 2023 13:45:06 +1200 Subject: [PATCH 0181/2607] Update webserver to ea86d81 (#5023) --- esphome/components/web_server/server_index.h | 1185 +++++++++--------- 1 file changed, 594 insertions(+), 591 deletions(-) diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h index 2dbb839c5e..180dffab67 100644 --- a/esphome/components/web_server/server_index.h +++ b/esphome/components/web_server/server_index.h @@ -6,597 +6,600 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbd, 0x7d, 0xdb, 0x76, 0xe3, 0x46, 0x92, 0xe0, 0xf3, - 0x9e, 0xb3, 0x7f, 0xb0, 0x2f, 0x28, 0x58, 0x53, 0x05, 0xb4, 0x40, 0x88, 0xa4, 0x4a, 0x55, 0x65, 0x50, 0x20, 0x5b, - 0x75, 0xb1, 0xab, 0xec, 0xba, 0xb9, 0xa4, 0xb2, 0xdb, 0x96, 0xd5, 0x12, 0x44, 0x26, 0x45, 0xb8, 0x40, 0x80, 0x06, - 0x92, 0xba, 0x98, 0xc2, 0x9c, 0x79, 0x9a, 0xa7, 0x39, 0x67, 0x6f, 0xf3, 0x30, 0x0f, 0x3b, 0x67, 0xe6, 0x61, 0x3f, - 0x62, 0x9f, 0xe7, 0x53, 0xfa, 0x07, 0x76, 0x3e, 0x61, 0x23, 0x22, 0x2f, 0x48, 0x80, 0xa4, 0x24, 0x7b, 0xdc, 0x7b, - 0xdc, 0xd5, 0x02, 0xf2, 0x1a, 0x11, 0x19, 0x19, 0xb7, 0x8c, 0x04, 0x77, 0xef, 0x8d, 0xb2, 0x21, 0xbf, 0x9a, 0x31, - 0x6b, 0xc2, 0xa7, 0x49, 0x7f, 0x57, 0xfe, 0x3f, 0x8b, 0x46, 0xfd, 0xdd, 0x24, 0x4e, 0x3f, 0x59, 0x39, 0x4b, 0xc2, - 0x78, 0x98, 0xa5, 0xd6, 0x24, 0x67, 0xe3, 0x70, 0x14, 0xf1, 0x28, 0x88, 0xa7, 0xd1, 0x19, 0xb3, 0xb6, 0xfa, 0xbb, - 0x53, 0xc6, 0x23, 0x6b, 0x38, 0x89, 0xf2, 0x82, 0xf1, 0xf0, 0xe3, 0xc1, 0x17, 0xad, 0x27, 0xfd, 0xdd, 0x62, 0x98, - 0xc7, 0x33, 0x6e, 0xe1, 0x90, 0xe1, 0x34, 0x1b, 0xcd, 0x13, 0xd6, 0x3f, 0x8f, 0x72, 0xeb, 0x05, 0x0b, 0xdf, 0x9d, - 0xfe, 0xc4, 0x86, 0xdc, 0x1f, 0xb1, 0x71, 0x9c, 0xb2, 0xf7, 0x79, 0x36, 0x63, 0x39, 0xbf, 0xf2, 0xf6, 0x57, 0x57, - 0xc4, 0xac, 0xf0, 0x9e, 0xe9, 0xaa, 0x33, 0xc6, 0xdf, 0x5d, 0xa4, 0xaa, 0xcf, 0x73, 0x26, 0x26, 0xc9, 0xf2, 0xc2, - 0x8b, 0xd7, 0xb4, 0xd9, 0xbf, 0x9a, 0x9e, 0x66, 0x49, 0xe1, 0x7d, 0xd2, 0xf5, 0xb3, 0x3c, 0xe3, 0x19, 0x82, 0xe5, - 0x4f, 0xa2, 0xc2, 0x68, 0xe9, 0xbd, 0x5b, 0xd1, 0x64, 0x26, 0x2b, 0x5f, 0x15, 0x2f, 0xd2, 0xf9, 0x94, 0xe5, 0xd1, - 0x69, 0xc2, 0xbc, 0x9c, 0x85, 0x0e, 0xf7, 0x98, 0x17, 0xbb, 0x61, 0x9f, 0x59, 0x71, 0x6a, 0xf1, 0xc1, 0x0b, 0x46, - 0x25, 0x0b, 0xa6, 0x5b, 0x05, 0xf7, 0xda, 0x1e, 0x90, 0x6b, 0x1c, 0x9f, 0xcd, 0xf5, 0xfb, 0x45, 0x1e, 0x73, 0xf5, - 0x7c, 0x1e, 0x25, 0x73, 0x16, 0xc4, 0xa5, 0x1b, 0xf0, 0x43, 0x76, 0x14, 0xc6, 0xde, 0x27, 0x1a, 0x14, 0x86, 0x5c, - 0x8c, 0xb3, 0xdc, 0x41, 0x5a, 0xc5, 0x38, 0x36, 0xbb, 0xbe, 0x76, 0x58, 0xb8, 0x28, 0x5d, 0xf7, 0x13, 0xf3, 0x87, - 0x51, 0x92, 0x38, 0x38, 0xf1, 0xfd, 0xfb, 0x39, 0xce, 0x18, 0x7b, 0xec, 0x30, 0x3e, 0x72, 0x7b, 0xf1, 0xd8, 0x89, - 0x99, 0x5b, 0xf5, 0xcb, 0xc6, 0x56, 0xcc, 0x1c, 0xe6, 0xba, 0xef, 0xd6, 0xf7, 0xc9, 0x19, 0x9f, 0xe7, 0x00, 0x7b, - 0xe9, 0xbd, 0x53, 0x33, 0xef, 0x63, 0xfd, 0x33, 0xea, 0xd8, 0x03, 0xd8, 0x0b, 0x6e, 0x7d, 0x11, 0x5e, 0xc4, 0xe9, - 0x28, 0xbb, 0xf0, 0xf7, 0x27, 0x11, 0xfc, 0xf9, 0x90, 0x65, 0xfc, 0xfe, 0x7d, 0xe7, 0x3c, 0x8b, 0x47, 0x56, 0x3b, - 0x0c, 0xcd, 0xca, 0xab, 0x67, 0xfb, 0xfb, 0xd7, 0xd7, 0x8d, 0x02, 0x3f, 0x8d, 0x78, 0x7c, 0xce, 0x44, 0x67, 0x00, - 0xc0, 0x86, 0xbf, 0x33, 0xce, 0x46, 0xfb, 0xfc, 0x2a, 0x81, 0x52, 0xc6, 0x78, 0x61, 0x03, 0x8e, 0xcf, 0xb3, 0x21, - 0x90, 0x2d, 0x35, 0x08, 0x0f, 0x4d, 0x73, 0x36, 0x4b, 0xa2, 0x21, 0xc3, 0x7a, 0x18, 0xa9, 0xea, 0x51, 0x35, 0xf2, - 0xbe, 0x0b, 0xc5, 0xf2, 0x3a, 0xae, 0x97, 0xb1, 0x30, 0x65, 0x17, 0xd6, 0x9b, 0x68, 0xd6, 0x1b, 0x26, 0x51, 0x51, - 0x58, 0x29, 0x5b, 0x10, 0x0a, 0xf9, 0x7c, 0x08, 0x0c, 0x42, 0x08, 0x2e, 0x80, 0x4c, 0x7c, 0x12, 0x17, 0xfe, 0xf1, - 0xc6, 0xb0, 0x28, 0x3e, 0xb0, 0x62, 0x9e, 0xf0, 0x8d, 0x10, 0xd6, 0x82, 0xdd, 0x0b, 0xc3, 0xef, 0x5c, 0x3e, 0xc9, - 0xb3, 0x0b, 0xeb, 0x45, 0x9e, 0x43, 0x73, 0x1b, 0xa6, 0x14, 0x0d, 0xac, 0x18, 0xc6, 0xca, 0xb8, 0xa5, 0x07, 0xc3, - 0x05, 0xf4, 0xad, 0x8f, 0x05, 0xb3, 0x4e, 0xe6, 0x69, 0x11, 0x8d, 0x19, 0x34, 0x3d, 0xb1, 0xb2, 0xdc, 0x3a, 0x81, - 0x41, 0x4f, 0x60, 0xc9, 0x0a, 0x0e, 0xbb, 0xc6, 0xb7, 0xdd, 0x1e, 0xcd, 0x05, 0x85, 0x07, 0xec, 0x92, 0x87, 0xbc, - 0x04, 0xc6, 0xb4, 0x0a, 0x8d, 0x86, 0xe3, 0x2e, 0x12, 0x28, 0xe0, 0x61, 0xc6, 0x90, 0x65, 0x1d, 0xb3, 0xb1, 0x5e, - 0x9c, 0x2f, 0xee, 0xdf, 0xd7, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0xa2, 0xd1, 0xd6, 0xe3, 0x84, 0x78, 0x8d, 0x44, 0xae, - 0xc7, 0x7d, 0x49, 0xbe, 0xfd, 0xab, 0x74, 0x58, 0x1f, 0x1b, 0x2a, 0x4b, 0x9e, 0xed, 0xf3, 0x3c, 0x4e, 0xcf, 0x00, - 0x08, 0xc5, 0x06, 0x46, 0x93, 0xb2, 0x14, 0x8b, 0xff, 0x9e, 0x85, 0x3c, 0xec, 0xe3, 0xe8, 0x29, 0x73, 0xec, 0x82, - 0x7a, 0xd8, 0x00, 0x08, 0x90, 0x1e, 0x18, 0x8c, 0x0f, 0x78, 0xc0, 0x37, 0x6d, 0xdb, 0xfb, 0xce, 0xf5, 0xae, 0x90, - 0x83, 0x7c, 0xdf, 0x27, 0xf6, 0x15, 0x9d, 0xe3, 0xb0, 0x83, 0x40, 0xfb, 0x09, 0x4b, 0xcf, 0xf8, 0x64, 0xc0, 0x0f, - 0xdb, 0x47, 0x01, 0x03, 0xa8, 0x46, 0xf3, 0x21, 0x73, 0x90, 0x1f, 0xbd, 0x1c, 0xb7, 0xcf, 0xa6, 0x03, 0x53, 0xe0, - 0xc2, 0xdc, 0x23, 0x1c, 0x6b, 0x4b, 0xe3, 0x2a, 0xd8, 0x14, 0x60, 0xc8, 0xe7, 0x36, 0xec, 0xb0, 0x53, 0x96, 0x1b, - 0x70, 0xe8, 0x66, 0xbd, 0xda, 0x0a, 0xce, 0x61, 0x85, 0xa0, 0x9f, 0x35, 0x9e, 0xa7, 0x43, 0x1e, 0x83, 0xe0, 0xb2, - 0x37, 0x01, 0x5c, 0xb1, 0x72, 0x7a, 0xe1, 0x6c, 0xb7, 0x74, 0x9d, 0xd8, 0xdd, 0xe4, 0x87, 0xf9, 0x66, 0xe7, 0xc8, - 0x43, 0x28, 0x35, 0xf1, 0x25, 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0x99, 0xde, 0x9e, 0x5f, 0x0c, 0xb8, 0xbf, 0xcc, - 0xc7, 0x21, 0xf3, 0xa7, 0xd1, 0x0c, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x44, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, - 0x2b, 0x16, 0x70, 0x81, 0x20, 0xb0, 0x67, 0x5f, 0x44, 0xc3, 0x09, 0x6c, 0xf1, 0x8a, 0x70, 0x23, 0xb5, 0x1d, 0x86, - 0x39, 0x8b, 0x38, 0x7b, 0x91, 0x30, 0x7c, 0xc3, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0xe5, 0x6a, 0xdf, 0x25, 0x31, 0x7f, - 0x9b, 0xc1, 0x3c, 0x3d, 0xc1, 0x24, 0xc0, 0xc5, 0xf9, 0xfd, 0xfb, 0x31, 0xb2, 0xc8, 0x1e, 0x87, 0xd5, 0x3a, 0x9d, - 0x73, 0x58, 0xb7, 0x14, 0x5b, 0xd8, 0x40, 0x6d, 0x2f, 0xf6, 0x39, 0x10, 0xf1, 0x59, 0x96, 0x72, 0x18, 0x0e, 0xe0, - 0xd5, 0x1c, 0xe4, 0x47, 0xb3, 0x19, 0x4b, 0x47, 0xcf, 0x26, 0x71, 0x32, 0x02, 0x6a, 0x94, 0x80, 0x6f, 0xc2, 0x42, - 0xc0, 0x13, 0x90, 0x09, 0x6e, 0xc6, 0x88, 0x96, 0x0f, 0x19, 0x99, 0x85, 0xb6, 0xdd, 0x43, 0x09, 0x24, 0xb1, 0x40, - 0x19, 0x44, 0x0b, 0xf7, 0x01, 0x44, 0x7f, 0xe1, 0xb2, 0xcd, 0x30, 0xd6, 0xcb, 0x28, 0x09, 0xfc, 0x1e, 0x25, 0x0d, - 0xd0, 0x1f, 0x08, 0xc1, 0x7b, 0x28, 0xb8, 0xbe, 0x92, 0x52, 0x27, 0x62, 0x0a, 0x43, 0x20, 0xc0, 0x10, 0x25, 0x88, - 0xa4, 0xc1, 0xfb, 0x2c, 0xb9, 0x1a, 0xc7, 0x49, 0xb2, 0x3f, 0x9f, 0xcd, 0xb2, 0x9c, 0x7b, 0x5f, 0x87, 0x0b, 0x9e, - 0x55, 0xb8, 0xd2, 0x26, 0x2f, 0x2e, 0x62, 0x8e, 0x04, 0x75, 0x17, 0xc3, 0x08, 0x96, 0xfa, 0x69, 0x96, 0x25, 0x2c, - 0x4a, 0x01, 0x0d, 0x3e, 0xb0, 0xed, 0x20, 0x9d, 0x27, 0x49, 0xef, 0x14, 0x86, 0xfd, 0xd4, 0xa3, 0x6a, 0x21, 0xf1, - 0x03, 0x7a, 0xde, 0xcb, 0xf3, 0xe8, 0x0a, 0x1a, 0x62, 0x1b, 0x60, 0x2f, 0x58, 0xad, 0xaf, 0xf6, 0xdf, 0xbd, 0xf5, - 0x05, 0xe3, 0xc7, 0xe3, 0x2b, 0x00, 0xb4, 0xac, 0xa4, 0xe6, 0x38, 0xcf, 0xa6, 0x8d, 0xa9, 0x91, 0x0e, 0x71, 0xc8, - 0x7b, 0x6b, 0x40, 0x88, 0x69, 0x64, 0x58, 0x25, 0x6e, 0x42, 0xf0, 0x96, 0xf8, 0x59, 0x56, 0xe2, 0x1e, 0x18, 0xe0, - 0x43, 0x20, 0x8a, 0x61, 0xca, 0x5b, 0xa0, 0xcd, 0xaf, 0x16, 0x71, 0x48, 0x70, 0xce, 0x50, 0xff, 0x22, 0x8c, 0xc3, - 0x08, 0x66, 0x5f, 0x88, 0x01, 0x4b, 0x05, 0x71, 0x5c, 0x96, 0xde, 0x44, 0x33, 0x31, 0x4a, 0x3c, 0x14, 0x28, 0x2c, - 0x0c, 0x41, 0xc1, 0x70, 0x78, 0x71, 0xbd, 0x6f, 0xc2, 0x45, 0xa4, 0xf0, 0x41, 0x0d, 0x85, 0xfb, 0x2b, 0x10, 0x72, - 0x02, 0x35, 0xd9, 0x39, 0xe8, 0x41, 0x80, 0xf3, 0x6b, 0x50, 0x7f, 0xe3, 0x04, 0xa1, 0xb8, 0xd7, 0xf1, 0x40, 0x83, - 0x3e, 0x9b, 0x44, 0xe9, 0x19, 0x1b, 0x05, 0x13, 0x56, 0x4a, 0xc9, 0xbb, 0x67, 0xc1, 0x1a, 0x03, 0x3b, 0x15, 0xd6, - 0xcb, 0x83, 0x37, 0xaf, 0xe5, 0xca, 0xd5, 0x84, 0x31, 0x2c, 0xd2, 0x1c, 0xd4, 0x2a, 0x88, 0x6d, 0x29, 0x8e, 0x5f, - 0x70, 0x25, 0xbd, 0x45, 0x49, 0x5c, 0x7c, 0x9c, 0x81, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, - 0x39, 0xcc, 0x27, 0x2a, 0x46, 0xba, 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x6b, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x87, - 0x56, 0x34, 0x1a, 0xbd, 0x4a, 0x63, 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x81, 0x3c, 0xc6, 0x7a, 0x72, 0x11, - 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, 0xc8, 0xde, 0x23, 0x62, 0x08, 0x69, 0x99, 0x84, 0x87, 0x47, 0x12, 0xbc, 0xc4, - 0x9f, 0xcd, 0x8b, 0x09, 0x12, 0x56, 0x0e, 0x8c, 0x82, 0x3c, 0x3b, 0x2d, 0x58, 0x7e, 0xce, 0x46, 0x9a, 0x03, 0x0a, - 0xc0, 0x8a, 0x9a, 0x83, 0xf1, 0x42, 0x33, 0x3a, 0x4a, 0x87, 0x72, 0x18, 0xaa, 0x67, 0x8a, 0x59, 0x26, 0x99, 0x59, - 0x5b, 0x38, 0x5a, 0x0a, 0x38, 0xc2, 0xa8, 0x90, 0x92, 0x20, 0x0f, 0x15, 0x86, 0x13, 0x90, 0x42, 0xcc, 0xad, 0x6d, - 0x73, 0xa5, 0xc9, 0x5e, 0xcc, 0x49, 0x25, 0xe4, 0xd0, 0x11, 0x36, 0x32, 0x41, 0x9a, 0xbb, 0xb0, 0xab, 0x40, 0xca, - 0x4b, 0x70, 0x85, 0x14, 0x51, 0x66, 0x0e, 0x32, 0x40, 0xf8, 0x0d, 0xe9, 0x42, 0x50, 0x26, 0xd0, 0x82, 0x21, 0x1b, - 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0xef, 0x1e, 0xf3, - 0xd3, 0x6c, 0x6f, 0x38, 0x64, 0x45, 0x91, 0x01, 0x6c, 0xf7, 0xa8, 0xfd, 0x3a, 0x43, 0x0b, 0x28, 0xe9, 0x6a, 0x59, - 0x67, 0x17, 0xa4, 0xc1, 0x4d, 0xb5, 0xa2, 0x74, 0x7a, 0x60, 0x1f, 0x1f, 0x83, 0xcc, 0xf6, 0x24, 0x19, 0x80, 0xea, - 0xcb, 0x86, 0x9f, 0xb0, 0x67, 0xea, 0x94, 0x59, 0x69, 0x5f, 0x3a, 0x75, 0x90, 0x3c, 0x18, 0xd6, 0x2d, 0x8d, 0x05, - 0x5d, 0x39, 0x34, 0xae, 0x86, 0x54, 0x90, 0x8b, 0x33, 0x52, 0xd9, 0xc6, 0x32, 0x82, 0xd5, 0x56, 0x7a, 0x44, 0x7a, - 0x85, 0x4d, 0x41, 0x80, 0x1e, 0xf2, 0xa3, 0x9e, 0xac, 0x0f, 0x73, 0x41, 0xb9, 0x9c, 0xfd, 0x3c, 0x67, 0x05, 0x17, - 0xac, 0x0b, 0xe3, 0x82, 0xb9, 0x0a, 0x22, 0xb6, 0x69, 0x1d, 0xd6, 0x6c, 0xc7, 0x55, 0xb0, 0xbd, 0x9b, 0xa1, 0x1e, - 0x2b, 0x90, 0x93, 0x6f, 0x66, 0x27, 0xb2, 0x27, 0xdc, 0xeb, 0xeb, 0x6f, 0xd4, 0x20, 0xd5, 0x52, 0x6a, 0x1b, 0xa8, - 0xb1, 0x26, 0xb6, 0x6a, 0x32, 0xb2, 0x5d, 0xa9, 0x50, 0xef, 0x75, 0x7a, 0x35, 0x3e, 0x80, 0x3d, 0xd7, 0xd6, 0x2c, - 0x5d, 0x19, 0xdb, 0xef, 0x15, 0x4d, 0xdf, 0x89, 0x91, 0xc9, 0x1a, 0xe5, 0xb7, 0x73, 0x8f, 0xda, 0xf1, 0xd0, 0x76, - 0xa9, 0xae, 0x12, 0x0c, 0xf3, 0xba, 0x60, 0x68, 0x42, 0x3d, 0xd3, 0x5d, 0x6c, 0xcd, 0x54, 0x3c, 0x54, 0x6b, 0xad, - 0x1c, 0x08, 0x16, 0x1e, 0x82, 0x71, 0xb2, 0xd2, 0x3f, 0x78, 0x1b, 0x4d, 0x19, 0x52, 0xd4, 0x5b, 0xd7, 0x40, 0x3a, - 0x10, 0xd0, 0xe4, 0xa8, 0xa9, 0xde, 0x98, 0x2b, 0xac, 0xa6, 0xfa, 0xfe, 0x8a, 0xc1, 0x8a, 0x00, 0xfb, 0xba, 0x5c, - 0xb1, 0x44, 0xa4, 0x37, 0x05, 0x97, 0x68, 0xfa, 0x88, 0x32, 0xb1, 0x26, 0xa4, 0xe0, 0x01, 0x79, 0x58, 0xfe, 0xc6, - 0xc2, 0xa9, 0x56, 0x0a, 0x47, 0x86, 0x32, 0x05, 0xe8, 0x4c, 0x4a, 0x00, 0xc4, 0x25, 0xfd, 0xad, 0x6d, 0x2c, 0x24, - 0xdb, 0x3e, 0xf2, 0x81, 0x3f, 0x4e, 0x22, 0xee, 0x74, 0xb6, 0xda, 0x2e, 0xf0, 0x21, 0x08, 0x71, 0xd0, 0x11, 0x60, - 0xde, 0x57, 0xa8, 0x70, 0xf2, 0x16, 0x5c, 0xe6, 0x83, 0x51, 0x34, 0x89, 0xc7, 0xdc, 0x49, 0x50, 0x89, 0xb8, 0x25, - 0x4b, 0x40, 0xc9, 0xe8, 0x7d, 0x05, 0xca, 0x82, 0x09, 0xe9, 0x22, 0xaa, 0x95, 0x40, 0x63, 0x0a, 0x52, 0x92, 0x52, - 0xa4, 0x05, 0x15, 0x04, 0x86, 0x50, 0xe9, 0x29, 0x8e, 0x02, 0xfd, 0x16, 0x0f, 0xc4, 0xa0, 0xc1, 0x92, 0x45, 0x19, - 0x0f, 0xe2, 0xe5, 0x42, 0x50, 0xc3, 0x3e, 0xcf, 0x5e, 0x67, 0x17, 0x2c, 0x7f, 0x16, 0x21, 0xec, 0x81, 0xe8, 0x5e, - 0x82, 0xa4, 0x27, 0x81, 0xce, 0x7b, 0x8a, 0x57, 0xce, 0x09, 0x69, 0x58, 0x88, 0x69, 0x8c, 0x8a, 0x10, 0xec, 0x16, - 0xa2, 0x7d, 0x8a, 0x5b, 0x8a, 0xf6, 0x1e, 0xaa, 0x12, 0xae, 0x79, 0x6b, 0xef, 0x75, 0x9d, 0xb7, 0x60, 0x84, 0x99, - 0xe2, 0xd6, 0xfa, 0x8e, 0x75, 0x3d, 0xa9, 0x9b, 0x1d, 0xc9, 0x5b, 0x86, 0x32, 0x03, 0xfd, 0x71, 0x7d, 0x5d, 0x19, - 0xe9, 0xa0, 0x4c, 0xb5, 0x34, 0x47, 0x08, 0xc4, 0x96, 0x70, 0x4b, 0x50, 0x46, 0x68, 0x78, 0xe5, 0x59, 0x92, 0x18, - 0xba, 0xc8, 0x8b, 0x7b, 0x4e, 0x43, 0x1d, 0x01, 0x14, 0xd3, 0x9a, 0x46, 0x1a, 0xb0, 0x40, 0x57, 0xa0, 0x52, 0x52, - 0xda, 0xc8, 0xab, 0xd6, 0x46, 0x40, 0x9c, 0x8e, 0x58, 0x2e, 0x1c, 0x34, 0xa9, 0x43, 0x61, 0xc2, 0x14, 0x18, 0x9a, - 0x8d, 0x40, 0xc2, 0x2b, 0x04, 0xc0, 0x3c, 0xf1, 0x27, 0x59, 0xc1, 0x75, 0x9d, 0x09, 0x7d, 0x7c, 0x7d, 0x1d, 0x0b, - 0x7f, 0x11, 0x19, 0x20, 0x67, 0xd3, 0xec, 0x9c, 0xad, 0x80, 0xba, 0xa7, 0x06, 0x33, 0x41, 0x36, 0x86, 0x01, 0x25, - 0x0a, 0xaa, 0x65, 0x96, 0xc4, 0x60, 0xe9, 0xeb, 0x06, 0x3e, 0x18, 0x74, 0xec, 0x12, 0x65, 0x84, 0xdb, 0xef, 0xf7, - 0xdb, 0x5e, 0xc7, 0x2d, 0x05, 0xc1, 0x17, 0x4b, 0x14, 0xbd, 0x41, 0x3f, 0x4a, 0x13, 0x7c, 0x95, 0x2c, 0x60, 0xae, - 0xa1, 0x14, 0x39, 0xe9, 0x26, 0xe6, 0x49, 0x41, 0xec, 0x7a, 0x23, 0x18, 0x94, 0x33, 0x25, 0xb8, 0xd1, 0xc4, 0x15, - 0xdb, 0xf6, 0x83, 0x26, 0x9b, 0x66, 0x27, 0xb5, 0xc3, 0xd4, 0xc2, 0xc8, 0x35, 0x2f, 0xb4, 0x07, 0x6c, 0x2e, 0x0f, - 0xd9, 0xf4, 0x58, 0x0d, 0xbc, 0x0e, 0x10, 0x0a, 0x4f, 0xd7, 0x59, 0x42, 0xa9, 0xea, 0x2c, 0x85, 0xb8, 0xde, 0x40, - 0x1f, 0x99, 0x04, 0x73, 0x15, 0x09, 0xf6, 0xa5, 0x40, 0x60, 0xe8, 0x91, 0x89, 0xf5, 0x7a, 0x06, 0xcb, 0x73, 0x1a, - 0x0d, 0x3f, 0x69, 0x70, 0x2b, 0xde, 0x6b, 0xb2, 0x81, 0xd3, 0x28, 0x09, 0x0d, 0x71, 0x65, 0xe2, 0xad, 0x24, 0x74, - 0x6d, 0xa3, 0x80, 0x43, 0xb6, 0xc4, 0xf6, 0xcd, 0x85, 0x6e, 0x72, 0xbb, 0x64, 0x0f, 0xe5, 0x3f, 0x55, 0x5c, 0xb2, - 0x9e, 0xe5, 0x98, 0x92, 0x06, 0x4c, 0x31, 0x1e, 0x2c, 0x4d, 0x03, 0x12, 0xe0, 0xbb, 0x72, 0x14, 0x17, 0xeb, 0x49, - 0xf0, 0xbb, 0x82, 0xf9, 0xdc, 0x98, 0xe9, 0x56, 0x48, 0xb5, 0x84, 0x93, 0x66, 0xb0, 0x06, 0x4d, 0x1a, 0x0f, 0x4a, - 0xd4, 0x7c, 0x8d, 0x86, 0x0a, 0x71, 0xfc, 0x99, 0xa8, 0x42, 0x13, 0x0c, 0xc1, 0xc8, 0xbd, 0x42, 0x32, 0x5c, 0xb6, - 0x2c, 0x5a, 0xa4, 0x4c, 0x8d, 0x49, 0xa5, 0x6a, 0x96, 0xcb, 0xc0, 0xc0, 0xa2, 0xdd, 0xea, 0x4b, 0x4b, 0x5c, 0x89, - 0xdc, 0x34, 0xd4, 0xc2, 0xa4, 0x50, 0xde, 0x84, 0x93, 0xa3, 0xdf, 0xa5, 0xac, 0x77, 0x13, 0x9f, 0x5c, 0xe1, 0x93, - 0xfb, 0x86, 0x0f, 0x65, 0xf2, 0x76, 0x31, 0x28, 0x82, 0xaf, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, - 0x74, 0x41, 0xa0, 0x48, 0x36, 0x49, 0x07, 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xe6, 0x8a, 0x0d, 0x52, 0xf3, - 0x4a, 0x33, 0x2f, 0x75, 0x1b, 0xf6, 0x7b, 0x59, 0x4a, 0x3a, 0x31, 0x41, 0x99, 0xd8, 0xbb, 0x89, 0x36, 0x5e, 0x1a, - 0x66, 0xc2, 0xfa, 0x15, 0xc6, 0x4e, 0x8d, 0x42, 0xa9, 0x14, 0x81, 0x38, 0x36, 0xbe, 0x56, 0x96, 0x41, 0xe6, 0xaf, - 0xb0, 0xa7, 0x00, 0x94, 0x04, 0x16, 0x5f, 0x53, 0xc9, 0x8b, 0xc2, 0x3a, 0x1d, 0xef, 0x11, 0x1d, 0x2b, 0x11, 0x5a, - 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, 0x25, 0x34, 0x29, 0x99, 0x0f, 0xf2, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, - 0x25, 0x83, 0x84, 0x1c, 0xd2, 0x65, 0xa2, 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x0a, 0x89, 0x96, 0x1e, 0x85, 0x11, 0x8a, - 0x0d, 0xb1, 0x16, 0x4b, 0x84, 0x6c, 0xda, 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0xe6, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, - 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x9e, 0x00, 0x3f, 0x48, - 0x83, 0x17, 0xd6, 0x6c, 0xa0, 0x64, 0xef, 0xde, 0x6b, 0x6c, 0x45, 0xf6, 0x67, 0x55, 0x52, 0x79, 0x0a, 0x35, 0xce, - 0xad, 0xaf, 0x53, 0x2d, 0xb4, 0xa8, 0x2a, 0xf6, 0x0d, 0xa9, 0xbe, 0xaf, 0x14, 0x76, 0x85, 0xf2, 0xbe, 0x1c, 0x3a, - 0x76, 0x5d, 0x37, 0xc8, 0xc9, 0x79, 0xb9, 0xb7, 0xca, 0x85, 0xbc, 0x7f, 0xdf, 0xf4, 0x99, 0xce, 0xf5, 0xf0, 0xcf, - 0x1c, 0x54, 0xce, 0xc5, 0x55, 0x4a, 0x16, 0xcc, 0x33, 0xa5, 0x8e, 0x96, 0x1c, 0xd0, 0x76, 0x0f, 0x3d, 0xed, 0xe8, - 0x22, 0x8a, 0xb9, 0xa5, 0x47, 0x11, 0x9e, 0x36, 0xca, 0x27, 0x69, 0x74, 0x00, 0x5e, 0x68, 0x42, 0x92, 0x13, 0x6e, - 0xda, 0xa2, 0xc5, 0x70, 0xc2, 0x30, 0x04, 0xae, 0xec, 0x09, 0x53, 0xf6, 0xdc, 0x43, 0xbc, 0xe5, 0xc0, 0xab, 0x61, - 0x2f, 0x9b, 0xdd, 0x6b, 0xe6, 0x3f, 0xac, 0x11, 0xc8, 0xb6, 0xa9, 0xaa, 0x2b, 0x1b, 0xef, 0x52, 0x44, 0x62, 0x84, - 0x6d, 0xd5, 0xd8, 0xd2, 0xd6, 0xef, 0x35, 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x86, 0x1e, 0x56, 0x6e, 0x0e, - 0x37, 0x1d, 0x79, 0xb1, 0x82, 0x6e, 0x4f, 0x04, 0x85, 0xc0, 0x89, 0x50, 0xf6, 0xa0, 0xe6, 0x06, 0x22, 0x25, 0x53, - 0x5a, 0x35, 0x9b, 0x27, 0x23, 0x09, 0x2c, 0xb8, 0xb0, 0x4c, 0xf2, 0xd1, 0x45, 0x9c, 0x24, 0x55, 0xe9, 0xef, 0x2a, - 0xe0, 0xc5, 0xb0, 0xb7, 0x89, 0x76, 0x81, 0xd1, 0x5c, 0x81, 0xe0, 0x6a, 0x23, 0xec, 0xa3, 0xe3, 0x56, 0xeb, 0x2e, - 0x22, 0x8e, 0xcc, 0x8c, 0x46, 0x7c, 0x44, 0x1b, 0xb2, 0x64, 0x9a, 0xb5, 0xf7, 0x5e, 0x60, 0x48, 0xcd, 0xc0, 0x07, - 0xd5, 0x19, 0x15, 0xff, 0x2a, 0x7b, 0xea, 0x57, 0xa2, 0x77, 0xab, 0xea, 0x6a, 0x06, 0x54, 0x54, 0xe0, 0xc3, 0x0c, - 0xb1, 0xb4, 0x55, 0x20, 0x20, 0xd7, 0xc3, 0x3a, 0xdc, 0xad, 0x91, 0x06, 0x0b, 0x4a, 0x81, 0xb5, 0x56, 0x76, 0xaf, - 0x6f, 0x0b, 0xe6, 0x50, 0x28, 0x5c, 0xf4, 0x7f, 0x96, 0x4d, 0x67, 0x68, 0x99, 0x35, 0x98, 0x1a, 0x1a, 0x7c, 0x6c, - 0xd4, 0x97, 0x2b, 0xca, 0x6a, 0x7d, 0x68, 0x47, 0xd6, 0xf8, 0x49, 0x3b, 0xca, 0xe0, 0x50, 0xcd, 0x75, 0x51, 0xdd, - 0x6e, 0x6e, 0x8a, 0x98, 0x55, 0x3c, 0xee, 0x93, 0xde, 0xd6, 0xd6, 0xa4, 0xa7, 0x69, 0x40, 0x32, 0x49, 0x32, 0xbc, - 0xc9, 0x00, 0x65, 0x45, 0x9c, 0x45, 0xd9, 0x20, 0xdf, 0xa2, 0x2c, 0x71, 0xfd, 0x7e, 0xe8, 0xed, 0xd5, 0x3c, 0x6b, - 0x6f, 0x6f, 0xbd, 0x8b, 0x5c, 0xd5, 0x49, 0x0f, 0xf2, 0xf0, 0x08, 0x8a, 0x96, 0x6c, 0xca, 0x70, 0x31, 0xcd, 0x46, - 0x2c, 0xb0, 0xa1, 0x7b, 0x6a, 0x97, 0x72, 0xd3, 0x44, 0xc0, 0x3d, 0x11, 0x73, 0x16, 0x1f, 0xea, 0x91, 0xd4, 0x60, - 0x0f, 0x58, 0x40, 0x9b, 0x0b, 0x5f, 0x85, 0x67, 0x49, 0x76, 0x1a, 0x25, 0x07, 0x42, 0x81, 0xd7, 0x5a, 0x7e, 0x0b, - 0x2e, 0x23, 0x59, 0xac, 0x86, 0x92, 0xfa, 0x6a, 0xf0, 0x55, 0x70, 0x7b, 0x8f, 0xca, 0x5b, 0xb1, 0x3b, 0x7e, 0xdb, - 0xef, 0xd8, 0x2a, 0x22, 0xf6, 0x93, 0x39, 0x1d, 0x68, 0x9c, 0x02, 0x28, 0x73, 0x00, 0x9a, 0xac, 0xf0, 0x86, 0x2c, - 0xfc, 0x69, 0xf0, 0x93, 0x72, 0xa9, 0x33, 0x70, 0x21, 0xc0, 0xc9, 0x4f, 0x62, 0xde, 0xc2, 0xf3, 0x48, 0xdb, 0x5b, - 0x88, 0x0a, 0x8c, 0x2b, 0x52, 0x5c, 0xba, 0x54, 0xde, 0xa0, 0x77, 0x1c, 0x9e, 0x40, 0xb3, 0x8d, 0x8d, 0x85, 0xf3, - 0x26, 0xe2, 0x13, 0x3f, 0x8f, 0xd2, 0x51, 0x36, 0x75, 0xdc, 0x4d, 0xdb, 0x76, 0xfd, 0x82, 0x3c, 0x91, 0xcf, 0xdd, - 0x72, 0xe3, 0x04, 0xfc, 0x80, 0xd0, 0x1e, 0xd8, 0x9b, 0xc7, 0xde, 0x01, 0x0b, 0x4f, 0x76, 0x37, 0x16, 0x23, 0x56, - 0xf6, 0x4f, 0xbc, 0x4b, 0x1d, 0x73, 0xf7, 0xde, 0xa3, 0x94, 0x81, 0x5e, 0x61, 0xff, 0x52, 0x82, 0x01, 0xec, 0x46, - 0xf1, 0x77, 0x90, 0x72, 0x1f, 0xe9, 0x40, 0x44, 0xc6, 0x69, 0xaf, 0xaf, 0xed, 0x8c, 0x22, 0x06, 0xf6, 0x3d, 0xed, - 0xac, 0xde, 0xbf, 0x5f, 0xa9, 0xf9, 0xaa, 0xd4, 0x9b, 0xb3, 0xb0, 0xe6, 0xa9, 0x7b, 0x2f, 0xe9, 0x68, 0xa5, 0xbe, - 0x91, 0xe7, 0x8c, 0x94, 0xe6, 0xb2, 0x9d, 0xe0, 0x18, 0x5b, 0x7c, 0xf5, 0xb6, 0x3e, 0x14, 0x51, 0x0a, 0x3f, 0x06, - 0xeb, 0x25, 0x02, 0xf5, 0x0d, 0x0e, 0x8e, 0x77, 0x10, 0x6e, 0xed, 0x3a, 0x83, 0xc0, 0xb9, 0xd7, 0x6a, 0x5d, 0xff, - 0xb8, 0x75, 0xf8, 0xe7, 0xa8, 0xf5, 0xcb, 0x5e, 0xeb, 0x87, 0x23, 0xf7, 0xda, 0xf9, 0x71, 0x6b, 0x70, 0x28, 0xdf, - 0x0e, 0xff, 0xdc, 0xff, 0xb1, 0x38, 0xfa, 0x83, 0x28, 0xdc, 0x70, 0xdd, 0xad, 0x33, 0x6f, 0xc6, 0xc2, 0xad, 0x56, - 0xab, 0x0f, 0x4f, 0x67, 0xf0, 0x84, 0x7f, 0x2f, 0xe0, 0xcf, 0xf5, 0xa1, 0xf5, 0x9f, 0x7e, 0x4c, 0xff, 0xf3, 0x8f, - 0xf9, 0x11, 0x8e, 0x79, 0xf8, 0xe7, 0x1f, 0x0b, 0xfb, 0x41, 0x3f, 0xdc, 0x3a, 0xda, 0x74, 0x1d, 0x5d, 0xf3, 0x87, - 0xb0, 0x7a, 0x84, 0x56, 0x87, 0x7f, 0x96, 0x6f, 0xf6, 0x83, 0x93, 0xdd, 0x7e, 0x78, 0x74, 0xed, 0xd8, 0xd7, 0x0f, - 0xdc, 0x6b, 0xd7, 0xbd, 0xde, 0xc0, 0x79, 0xce, 0x61, 0xf4, 0x07, 0xf0, 0x77, 0x0c, 0x7f, 0x6d, 0xf8, 0x3b, 0x85, - 0xbf, 0x7f, 0x86, 0x6e, 0x22, 0xfe, 0x76, 0x4d, 0xb1, 0x90, 0x6b, 0x3c, 0xb0, 0x88, 0x60, 0x15, 0xdc, 0x8d, 0xad, - 0xd8, 0xdb, 0x20, 0xa2, 0xc1, 0x3e, 0xf4, 0x7d, 0x1f, 0xc3, 0xa4, 0xce, 0xe2, 0x78, 0x03, 0x16, 0x1d, 0x39, 0x67, - 0x23, 0xe0, 0x9e, 0x88, 0x1c, 0x14, 0x01, 0x13, 0x67, 0xab, 0x05, 0x1e, 0xae, 0x7a, 0xc3, 0x70, 0x83, 0x39, 0x60, - 0x14, 0xbc, 0x65, 0xf8, 0xd0, 0x75, 0xbd, 0x17, 0xf2, 0xcc, 0x10, 0xf7, 0xb9, 0x60, 0xad, 0x34, 0x13, 0x26, 0x8d, - 0xed, 0x7a, 0xb3, 0x15, 0x95, 0xb0, 0xad, 0xd3, 0x33, 0xa8, 0x3b, 0x15, 0x27, 0x8c, 0xdf, 0xb1, 0xe8, 0x13, 0x6e, - 0xc9, 0x37, 0xc6, 0x21, 0xf0, 0x92, 0x25, 0xdf, 0x34, 0x1a, 0x0d, 0x1b, 0x51, 0xb8, 0x63, 0x4f, 0x19, 0xcc, 0xb0, - 0x64, 0x22, 0x32, 0x52, 0x9a, 0xc2, 0xb2, 0x85, 0xc9, 0xdf, 0x47, 0x39, 0xdf, 0xa8, 0x0c, 0xdb, 0xb0, 0x66, 0xc9, - 0x36, 0x2d, 0xfd, 0x3b, 0x4c, 0x81, 0xa6, 0x25, 0x9d, 0x7f, 0x98, 0xe3, 0x87, 0x29, 0xa1, 0xf5, 0xd6, 0x61, 0xe0, - 0xa1, 0x17, 0x20, 0x77, 0x44, 0x3f, 0xe7, 0x3d, 0xaa, 0x31, 0xf8, 0x9f, 0x0c, 0x33, 0x78, 0x62, 0x3e, 0x0c, 0xd1, - 0x2c, 0x4a, 0x1d, 0xdc, 0x4a, 0x51, 0xdc, 0xbf, 0xc2, 0x9d, 0x91, 0x96, 0xde, 0x7e, 0xa8, 0x76, 0xcc, 0x41, 0xce, - 0xd8, 0x77, 0x51, 0xf2, 0x89, 0xe5, 0xce, 0xa5, 0xd7, 0xe9, 0x7e, 0x4e, 0x9d, 0x3d, 0xb4, 0xcd, 0x3e, 0x54, 0xc7, - 0x68, 0xda, 0x2c, 0x90, 0x47, 0x84, 0xad, 0x8e, 0x97, 0x63, 0x54, 0x0b, 0x49, 0x50, 0x78, 0x59, 0xd8, 0x25, 0x0e, - 0xb7, 0x77, 0x8b, 0xf3, 0xb3, 0xbe, 0x1d, 0xd8, 0x36, 0x58, 0xfc, 0x07, 0x14, 0xb6, 0x12, 0x86, 0x45, 0xbb, 0xc7, - 0x76, 0xe3, 0x1e, 0xdb, 0xdc, 0xac, 0x02, 0x4e, 0x78, 0x90, 0x4e, 0xdd, 0x13, 0x2f, 0xf2, 0x26, 0x21, 0x0c, 0x38, - 0x84, 0x66, 0xd8, 0xa5, 0x37, 0xdc, 0x8d, 0xe5, 0x34, 0x18, 0x0b, 0xf1, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, - 0x0e, 0xd1, 0xd8, 0xf7, 0xd9, 0x25, 0x1b, 0x2a, 0x3b, 0x03, 0x08, 0x15, 0xb9, 0x3d, 0x77, 0x18, 0x1a, 0xcd, 0x60, - 0xee, 0x30, 0x3c, 0x18, 0xd8, 0xb0, 0x97, 0x60, 0x57, 0x86, 0xd1, 0x61, 0xe7, 0x68, 0x90, 0x86, 0x33, 0x16, 0x68, - 0xda, 0xca, 0xa2, 0xb3, 0x5a, 0x51, 0xf7, 0x68, 0xe0, 0x4c, 0x99, 0xcf, 0xc1, 0x16, 0x77, 0xf0, 0x0d, 0x23, 0x14, - 0x45, 0xf8, 0x81, 0x9d, 0xbd, 0xb8, 0x9c, 0x39, 0xf6, 0xee, 0x96, 0xbd, 0x89, 0xa5, 0x9e, 0x0d, 0xec, 0x05, 0x73, - 0x87, 0x17, 0xae, 0xd9, 0x79, 0xfb, 0x08, 0x41, 0xc5, 0x42, 0x9c, 0xfc, 0x62, 0x60, 0xf7, 0xc5, 0xd4, 0x6d, 0x18, - 0x34, 0x95, 0xcb, 0x8f, 0x2b, 0x7a, 0x40, 0xa8, 0xaa, 0xae, 0x0a, 0x3a, 0x28, 0xeb, 0x06, 0xce, 0xc4, 0x44, 0xa2, - 0x85, 0x93, 0x49, 0x2a, 0x80, 0xc3, 0x83, 0xcd, 0x60, 0x52, 0xa3, 0xdb, 0xf6, 0xd1, 0xe0, 0x22, 0x78, 0x60, 0x3f, - 0x50, 0x2f, 0x63, 0x40, 0x86, 0x89, 0xe9, 0xc7, 0xa0, 0x45, 0xf0, 0xef, 0x39, 0x03, 0x24, 0x2f, 0xa8, 0x68, 0x26, - 0x8b, 0xce, 0xb0, 0xe8, 0x20, 0x40, 0x50, 0xbd, 0x42, 0x5b, 0x7f, 0x62, 0x4d, 0x46, 0x21, 0xc1, 0x0e, 0xb6, 0xd0, - 0x21, 0xdb, 0xec, 0x1c, 0xe1, 0x79, 0x43, 0xce, 0x8b, 0xef, 0x62, 0x0e, 0x2a, 0x61, 0xab, 0x6f, 0xbb, 0x03, 0xdb, - 0xc2, 0xa5, 0xed, 0x65, 0x9b, 0xa1, 0xa0, 0x70, 0xbc, 0x79, 0xc0, 0x82, 0x49, 0x3f, 0x6c, 0x0f, 0x9c, 0x5c, 0x86, - 0x1b, 0xf1, 0xdc, 0x52, 0x48, 0xf0, 0xb6, 0x37, 0x01, 0x81, 0x8e, 0x9c, 0xbb, 0x61, 0x6f, 0xaa, 0x42, 0x28, 0x3a, - 0xde, 0x1c, 0xb9, 0x41, 0x0c, 0x7f, 0x9c, 0x16, 0x32, 0xcd, 0x44, 0xf7, 0x55, 0x9a, 0x19, 0x90, 0x18, 0x29, 0x8b, - 0x3c, 0x09, 0xb3, 0x4d, 0x07, 0x23, 0xb4, 0x20, 0x69, 0x77, 0x07, 0x00, 0xc3, 0xa6, 0xa3, 0x38, 0x6d, 0x4b, 0xb1, - 0x9a, 0xb2, 0xcf, 0x0f, 0xf5, 0x72, 0x0c, 0xd9, 0x60, 0xc8, 0xfc, 0x4a, 0xfb, 0x00, 0x58, 0x41, 0xe2, 0xe5, 0x47, - 0xea, 0xcc, 0xeb, 0x65, 0xed, 0x7c, 0x6b, 0xa1, 0x44, 0x11, 0xf7, 0x0c, 0x09, 0xc5, 0x4a, 0xed, 0x86, 0x09, 0x73, - 0x7b, 0x86, 0xc4, 0xd0, 0x2c, 0x1f, 0xb6, 0x81, 0xe9, 0x55, 0x80, 0x3d, 0x35, 0xb7, 0x45, 0x12, 0x56, 0xcd, 0xbd, - 0x43, 0x60, 0xed, 0x23, 0xe0, 0x21, 0xda, 0x46, 0x3d, 0x15, 0xcd, 0x67, 0x49, 0xf8, 0xb2, 0x71, 0x5c, 0x1c, 0xe1, - 0x89, 0xd0, 0xbe, 0x3f, 0x9c, 0xe7, 0x20, 0x0f, 0xf8, 0x5b, 0xb0, 0x0c, 0x42, 0xd9, 0x14, 0x1d, 0x3d, 0x3c, 0x02, - 0xf6, 0x08, 0xf1, 0x46, 0xd8, 0xdc, 0xa8, 0x46, 0x8b, 0x92, 0x8c, 0x17, 0x3a, 0x18, 0xee, 0x31, 0xe9, 0xda, 0xa3, - 0x60, 0x90, 0x27, 0xc6, 0x0e, 0x9e, 0xf9, 0xfb, 0x43, 0xac, 0xc6, 0x09, 0x0a, 0xb7, 0xa4, 0xdd, 0x56, 0x89, 0xbf, - 0x7d, 0x3f, 0x05, 0x09, 0x8e, 0x75, 0xe0, 0x67, 0xdd, 0xbf, 0x9f, 0x48, 0xa4, 0x76, 0xd3, 0x1e, 0x9d, 0x44, 0x60, - 0x3c, 0x38, 0xf7, 0x53, 0xa8, 0x46, 0x12, 0x51, 0x51, 0x8e, 0x16, 0xa8, 0x79, 0xaa, 0x56, 0xc1, 0x77, 0x68, 0x46, - 0xe0, 0x19, 0x86, 0xad, 0xc9, 0x4f, 0xd5, 0x8d, 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, - 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, 0xb1, 0x11, 0x2b, 0x9f, 0x1c, 0x66, 0x9b, 0x9b, 0x47, 0xe2, 0xdc, - 0x82, 0x18, 0x87, 0x19, 0xd1, 0xd5, 0xb8, 0x02, 0xa0, 0x3e, 0x9d, 0x13, 0xd7, 0x03, 0xd3, 0x8a, 0x35, 0x5d, 0x8a, - 0x7d, 0x72, 0x98, 0x01, 0x28, 0xb8, 0xe5, 0x1c, 0xfa, 0x83, 0x3f, 0x1e, 0x81, 0x7b, 0xec, 0xff, 0xc1, 0xdd, 0x52, - 0x82, 0xa6, 0x27, 0xcf, 0x14, 0x17, 0x74, 0xc6, 0xda, 0xf1, 0x28, 0x36, 0x1a, 0x14, 0x5e, 0x0a, 0x18, 0x80, 0x36, - 0x07, 0x99, 0x50, 0x71, 0x10, 0x72, 0x54, 0x60, 0xfb, 0xb8, 0xf9, 0x19, 0xee, 0xec, 0xe7, 0x60, 0xe1, 0x0d, 0xf4, - 0xdb, 0x6b, 0x78, 0xfb, 0xa3, 0x7e, 0xfb, 0x89, 0x05, 0xbf, 0x94, 0x32, 0x74, 0x5f, 0x9b, 0xe2, 0x91, 0x9a, 0xa2, - 0x14, 0x4b, 0x64, 0xd0, 0x90, 0xbb, 0xf9, 0x52, 0xcc, 0x86, 0xb9, 0x25, 0x10, 0x43, 0x89, 0xae, 0xdc, 0xe7, 0xd1, - 0x19, 0x12, 0xd7, 0x35, 0x49, 0x61, 0xe4, 0x12, 0x98, 0x08, 0x57, 0x7c, 0x8b, 0xf4, 0x64, 0xfd, 0x36, 0xd8, 0xe0, - 0xb5, 0xbc, 0x03, 0xb4, 0xef, 0xd8, 0x74, 0xc6, 0xaf, 0xf6, 0x49, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0xb7, - 0x7b, 0xf1, 0x2e, 0xeb, 0xc5, 0x20, 0xd5, 0x73, 0xc5, 0x62, 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, - 0xab, 0xa1, 0xd7, 0x95, 0xe8, 0x6d, 0x6e, 0x02, 0x82, 0x3d, 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, - 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, 0x11, 0x73, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, - 0xb0, 0x03, 0x98, 0x11, 0x97, 0xb7, 0x3a, 0x22, 0x3a, 0x2c, 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0x37, 0x3b, 0x2e, - 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, 0xd6, 0x54, 0x2a, 0x8b, 0xcd, 0xcd, 0xb2, 0x7e, 0x54, - 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0xb2, 0x99, 0x0d, 0xc2, 0x81, 0x88, 0x09, 0x14, 0x68, 0x69, 0x65, 0xc5, 0x00, - 0x43, 0xca, 0x72, 0x94, 0x4f, 0x21, 0xf7, 0xe2, 0xb2, 0xd4, 0xa9, 0x2f, 0xcf, 0x64, 0xd0, 0x11, 0x4f, 0x3d, 0xc9, - 0x58, 0x01, 0x05, 0xeb, 0xa5, 0x5e, 0x42, 0x4b, 0x04, 0x98, 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, - 0x2c, 0x51, 0xc6, 0x67, 0x11, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, 0x62, 0x5f, 0x85, 0x32, 0x3a, 0x8a, 0xc3, 0xfc, 0x28, - 0xa0, 0xfa, 0xb9, 0x94, 0x60, 0x93, 0xf0, 0x23, 0xb0, 0x51, 0xe5, 0x78, 0x92, 0x20, 0x7c, 0x1e, 0xe7, 0x8c, 0x3c, - 0x85, 0x0d, 0x09, 0xb3, 0x34, 0x6d, 0x23, 0xd5, 0x2e, 0x32, 0x83, 0x50, 0x2e, 0xcc, 0x3f, 0x31, 0xce, 0x2e, 0xb2, - 0x70, 0xa9, 0x35, 0x98, 0x1f, 0xef, 0x4c, 0x80, 0xb2, 0xeb, 0xeb, 0x4c, 0xf8, 0xb8, 0x11, 0xd9, 0x1b, 0xba, 0x62, - 0x32, 0x50, 0x48, 0x05, 0x4e, 0x44, 0x16, 0x0f, 0x9d, 0xa1, 0xd0, 0x08, 0x07, 0x74, 0x8a, 0x9c, 0xbb, 0xc6, 0xa6, - 0xcf, 0x07, 0xda, 0x37, 0x4a, 0x43, 0x27, 0x01, 0x21, 0x20, 0x70, 0x37, 0xac, 0xa9, 0x74, 0x90, 0x06, 0x09, 0x95, - 0xa2, 0x9f, 0x03, 0xf8, 0x87, 0x91, 0xa4, 0x00, 0xd8, 0x0f, 0xd5, 0x48, 0x11, 0x65, 0x59, 0xe0, 0x02, 0xd0, 0x5c, - 0xfb, 0xb8, 0x12, 0xbe, 0x30, 0x50, 0x61, 0x7a, 0x9a, 0x95, 0x95, 0x42, 0x89, 0x3c, 0x5d, 0x91, 0xb2, 0x46, 0x32, - 0xf9, 0x1c, 0x1d, 0x3e, 0xe5, 0x5d, 0xbf, 0x95, 0x78, 0xe8, 0x82, 0xe7, 0xb0, 0xac, 0xea, 0xf9, 0x4d, 0xc8, 0xc8, - 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xf7, 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, - 0x0c, 0xcb, 0xcb, 0x59, 0x15, 0xa6, 0x20, 0xe0, 0x16, 0x2c, 0x09, 0x16, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, - 0x0a, 0xf2, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0x99, 0xd4, 0x04, - 0x4c, 0xb9, 0x3f, 0x04, 0x3f, 0xb5, 0x79, 0xd2, 0x75, 0xe9, 0xfa, 0xf1, 0x14, 0x53, 0x7b, 0x08, 0xf4, 0xd8, 0xbb, - 0x07, 0xa6, 0x44, 0x5d, 0x87, 0x15, 0xc4, 0xa1, 0x59, 0x4d, 0xb3, 0x80, 0x19, 0xd3, 0x06, 0x2d, 0xd9, 0x06, 0x5b, - 0x2e, 0x07, 0xfb, 0x48, 0x6c, 0xcf, 0x6a, 0x05, 0x84, 0xae, 0x41, 0x03, 0x43, 0xee, 0x52, 0xa1, 0x85, 0x59, 0xaf, - 0x4b, 0x45, 0xb8, 0x3f, 0x07, 0x4c, 0x5a, 0xc1, 0x99, 0x97, 0xd1, 0xc0, 0xfb, 0xf1, 0x69, 0x82, 0x89, 0x2f, 0x88, - 0x15, 0xd8, 0xc1, 0x41, 0xa7, 0xd9, 0x14, 0x38, 0x15, 0x17, 0x29, 0x83, 0x65, 0x45, 0xa9, 0x0d, 0x7f, 0xa4, 0xc8, - 0xd6, 0x5d, 0x1e, 0xe9, 0x2e, 0xc4, 0x02, 0xd8, 0xe9, 0x17, 0x8c, 0x7c, 0xcb, 0x7a, 0x19, 0x30, 0x38, 0xd7, 0x1a, - 0x07, 0x81, 0xdf, 0xdc, 0x4c, 0x8e, 0xca, 0x94, 0xd8, 0xae, 0xc9, 0xea, 0x02, 0x72, 0x4c, 0x02, 0x6c, 0xe0, 0x0e, - 0xc2, 0x52, 0xd9, 0xe3, 0x45, 0x39, 0xc5, 0xe5, 0x52, 0x16, 0x72, 0x33, 0x1d, 0x8b, 0xe6, 0x73, 0x2b, 0xcd, 0xa6, - 0xe3, 0xad, 0xf8, 0xa2, 0xe0, 0x1f, 0x38, 0xb1, 0xb4, 0xea, 0x29, 0xb5, 0xc2, 0xa3, 0xcc, 0x2d, 0x59, 0xa7, 0xa4, - 0x56, 0xd7, 0x0d, 0x54, 0x23, 0x3c, 0x4d, 0xc3, 0x46, 0x20, 0xc4, 0x04, 0x17, 0xbf, 0x6d, 0x32, 0x31, 0xed, 0x2d, - 0x21, 0x75, 0x84, 0xdd, 0x43, 0x39, 0xc1, 0x5d, 0xcd, 0xb3, 0x2f, 0xc3, 0xd9, 0x7a, 0xe6, 0xde, 0x33, 0x98, 0xfb, - 0x69, 0xc8, 0x0c, 0x46, 0x8f, 0x65, 0xc2, 0x8f, 0x8c, 0x7d, 0xe4, 0xaa, 0xea, 0xd9, 0x59, 0x58, 0x89, 0x2c, 0xf1, - 0x64, 0x1c, 0x75, 0x18, 0xa7, 0xa2, 0x35, 0x41, 0x76, 0x7d, 0x5d, 0x98, 0x7b, 0x81, 0x82, 0xa6, 0x1e, 0xab, 0xc7, - 0x69, 0x2b, 0x76, 0x36, 0x22, 0x91, 0x7b, 0x6f, 0x6a, 0x91, 0xc8, 0x8a, 0xcf, 0x71, 0xa4, 0x35, 0x07, 0xb9, 0xcf, - 0xce, 0x96, 0x37, 0xa9, 0xd0, 0x2d, 0x1a, 0x6d, 0x63, 0x8f, 0xea, 0x03, 0x49, 0x3d, 0xa3, 0x02, 0xab, 0x1a, 0xfb, - 0xfe, 0xfd, 0x8e, 0x48, 0xb7, 0x54, 0x8a, 0x0d, 0x43, 0x5a, 0x21, 0x33, 0x46, 0xc1, 0xa0, 0xa4, 0xc8, 0x40, 0x8d, - 0xf2, 0x35, 0x82, 0x61, 0x8f, 0x1a, 0x80, 0xe2, 0x5c, 0x5d, 0xfd, 0xb4, 0x94, 0x6c, 0x21, 0x20, 0x01, 0xd9, 0x84, - 0x62, 0x8d, 0x98, 0x19, 0xf9, 0xe4, 0x23, 0x70, 0xde, 0x80, 0xa3, 0x63, 0x00, 0x7e, 0x81, 0xd8, 0xf4, 0x60, 0x62, - 0xdb, 0x44, 0x14, 0x7d, 0x36, 0xf0, 0x12, 0x80, 0x9d, 0x55, 0xa1, 0xd1, 0x0f, 0x55, 0x0a, 0x18, 0xb2, 0x81, 0x1b, - 0xf0, 0x2a, 0x2c, 0xb7, 0xf7, 0x12, 0xda, 0xc1, 0xeb, 0x0b, 0xd9, 0x7c, 0x03, 0xf3, 0x04, 0xab, 0xd8, 0x9d, 0x5f, - 0x59, 0xd6, 0xe2, 0xdc, 0xe9, 0xa0, 0x51, 0xaf, 0x28, 0x21, 0x6a, 0xf7, 0xb1, 0xf6, 0x25, 0x23, 0x18, 0xf1, 0xfd, - 0x0d, 0x65, 0x1d, 0xaa, 0x71, 0xcb, 0x3d, 0x8d, 0x16, 0x61, 0xba, 0x4c, 0x1a, 0x83, 0x92, 0x75, 0x3f, 0x19, 0x71, - 0x2f, 0xf7, 0x45, 0x2c, 0xb8, 0xc2, 0xd1, 0x08, 0x9b, 0x37, 0x90, 0xa4, 0xa7, 0x3d, 0x3a, 0x60, 0xdf, 0x68, 0xf6, - 0x02, 0xca, 0x7c, 0xac, 0x48, 0x25, 0x21, 0xa5, 0xd9, 0x0d, 0x91, 0x24, 0xac, 0x15, 0x79, 0xea, 0xbc, 0xef, 0x68, - 0x9f, 0x5b, 0x49, 0x04, 0x23, 0x38, 0x89, 0xd3, 0x95, 0x07, 0x4d, 0x01, 0xae, 0xa2, 0x23, 0xa6, 0x6f, 0x82, 0xf2, - 0x1b, 0xe4, 0xf6, 0x52, 0x72, 0x6d, 0xae, 0x61, 0x78, 0x86, 0x04, 0xab, 0x22, 0x11, 0x78, 0x44, 0x0d, 0x38, 0xe6, - 0xab, 0x3c, 0x0f, 0x30, 0xe1, 0x6b, 0x7b, 0x13, 0x00, 0xca, 0xc9, 0x55, 0x71, 0x96, 0x02, 0xdd, 0x80, 0xe5, 0xea, - 0x38, 0x35, 0x2a, 0x12, 0x17, 0x37, 0xa6, 0xab, 0x5b, 0xfa, 0x53, 0xb4, 0x9c, 0xc9, 0x10, 0xd3, 0x41, 0x10, 0x90, - 0xa9, 0x4f, 0x99, 0x23, 0x64, 0xae, 0xb0, 0x3e, 0x67, 0x4e, 0x6d, 0xea, 0x1e, 0xa7, 0x6e, 0x9e, 0xa4, 0x16, 0xab, - 0xd3, 0xa6, 0x94, 0x88, 0x49, 0x89, 0x79, 0x2a, 0x53, 0xb1, 0x95, 0xb8, 0x73, 0xeb, 0x1b, 0x2d, 0xa4, 0x8d, 0x76, - 0x2a, 0x73, 0xb0, 0xb5, 0xbc, 0x17, 0xa2, 0xfd, 0x25, 0x11, 0x9e, 0x95, 0xc8, 0x58, 0x8b, 0x39, 0x73, 0x4c, 0x04, - 0xab, 0x17, 0x53, 0x91, 0x7f, 0x70, 0x74, 0x9a, 0xbd, 0x41, 0x0f, 0x52, 0x6f, 0x20, 0x31, 0x6b, 0xe2, 0xbb, 0x90, - 0x86, 0x3a, 0x42, 0xa0, 0x32, 0xaa, 0x65, 0x3a, 0x4e, 0x2c, 0x15, 0x97, 0xe4, 0xab, 0xf7, 0xfa, 0x38, 0xdf, 0x78, - 0x6e, 0xac, 0x46, 0x10, 0x83, 0xb7, 0x90, 0x1f, 0x79, 0x52, 0x84, 0x03, 0xe1, 0xf2, 0xcd, 0xcd, 0x5e, 0xbe, 0xcb, - 0xaa, 0x10, 0x49, 0x05, 0x63, 0x8c, 0x19, 0xc5, 0xb8, 0x27, 0x6a, 0x6a, 0x31, 0x07, 0x54, 0x65, 0xeb, 0x30, 0xc7, - 0x03, 0x00, 0x68, 0x69, 0x4a, 0x2f, 0xb3, 0xad, 0x3a, 0xcf, 0x25, 0x7c, 0x8c, 0x3c, 0x14, 0xd9, 0xf8, 0xfd, 0x9a, - 0x0c, 0x14, 0x84, 0xfb, 0x5e, 0xc7, 0xc3, 0xc4, 0x38, 0x58, 0x45, 0x21, 0x0b, 0xf4, 0x06, 0xed, 0x55, 0x89, 0x50, - 0xdc, 0x9c, 0xac, 0xc7, 0x0d, 0x27, 0x15, 0x6c, 0xa1, 0x12, 0x96, 0x4a, 0x0b, 0xfc, 0x6a, 0x23, 0x34, 0x4f, 0x19, - 0xf7, 0xde, 0x54, 0x38, 0x83, 0xfe, 0xe0, 0xde, 0x32, 0xa3, 0xbe, 0x5f, 0x3a, 0x91, 0xa9, 0xc0, 0xc4, 0xcd, 0x2c, - 0xb5, 0xdf, 0x2f, 0xab, 0xb4, 0x9f, 0x57, 0xc8, 0x7d, 0x4e, 0x9a, 0xaf, 0x73, 0x07, 0xcd, 0x27, 0xc3, 0xfd, 0x4a, - 0xf9, 0xa1, 0x85, 0x51, 0x53, 0x7e, 0x79, 0x5d, 0xf9, 0x15, 0x9e, 0x0a, 0x6f, 0xf5, 0xbb, 0x28, 0x74, 0x51, 0x9f, - 0x83, 0x21, 0xa4, 0x1f, 0xc1, 0x35, 0x34, 0x78, 0x50, 0x24, 0x8b, 0xc5, 0xda, 0x05, 0x71, 0x7d, 0xcc, 0xa9, 0x76, - 0x28, 0x63, 0x8c, 0x78, 0x5a, 0x72, 0x90, 0x64, 0x70, 0x30, 0x7e, 0x03, 0x03, 0x62, 0x52, 0x12, 0xd2, 0x21, 0x74, - 0x56, 0x66, 0x22, 0x2a, 0x77, 0xf1, 0x76, 0xe3, 0xb2, 0xa6, 0x50, 0x84, 0x9d, 0x60, 0xa6, 0x52, 0x2a, 0x08, 0xa4, - 0xc9, 0x77, 0xaf, 0x53, 0x0b, 0x86, 0x82, 0x68, 0x30, 0x14, 0x90, 0xd7, 0x76, 0x3d, 0x68, 0xf2, 0x51, 0x1c, 0x3c, - 0xaf, 0x50, 0x23, 0x5e, 0x66, 0xf0, 0x35, 0x6c, 0xfe, 0x9a, 0x28, 0xc9, 0x43, 0x2e, 0x62, 0xaf, 0xe0, 0x13, 0x21, - 0x9b, 0xf2, 0xb0, 0x00, 0xfa, 0xa1, 0x5d, 0xd9, 0x4b, 0x77, 0x8b, 0xca, 0xa5, 0x45, 0x63, 0x2b, 0x51, 0xb3, 0xe6, - 0x87, 0xf1, 0x66, 0x7a, 0x04, 0x53, 0x53, 0x02, 0x01, 0x69, 0x2a, 0x27, 0xa9, 0xe6, 0x3d, 0x4c, 0x8f, 0x00, 0x24, - 0xd8, 0xfd, 0x04, 0x16, 0xfa, 0x4d, 0x89, 0x09, 0x16, 0x55, 0x63, 0xb7, 0x19, 0x68, 0xcd, 0x19, 0x69, 0xbe, 0x19, - 0x42, 0xb8, 0xa9, 0xac, 0x67, 0xcc, 0x0e, 0xb0, 0x6d, 0x77, 0xb3, 0x38, 0x4c, 0x37, 0x3b, 0x47, 0x86, 0xe0, 0xc2, - 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x5c, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, - 0xd1, 0x74, 0xee, 0x35, 0x47, 0xc9, 0x65, 0x55, 0xed, 0x6a, 0x09, 0x1a, 0xba, 0x91, 0x8c, 0x89, 0x62, 0x9e, 0x13, - 0x00, 0xa3, 0xd8, 0xfc, 0x39, 0xd3, 0x49, 0xde, 0xbf, 0xac, 0x4c, 0xed, 0xf6, 0x7d, 0x3f, 0xca, 0xcf, 0xe8, 0x48, - 0x45, 0x65, 0x73, 0x12, 0xf3, 0x6f, 0x4b, 0x30, 0x8d, 0x89, 0x0f, 0xf5, 0x5c, 0x47, 0xa1, 0x00, 0x5f, 0xd9, 0x50, - 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x87, 0x72, 0x36, 0xc1, 0x02, 0x0d, 0xba, 0xac, 0xc1, 0x17, 0xb0, 0x0c, 0xee, - 0x48, 0x3f, 0x05, 0xdf, 0x4f, 0xeb, 0xe0, 0x33, 0xf6, 0xbf, 0x00, 0xb4, 0x2a, 0x30, 0xa0, 0xdc, 0x69, 0x1a, 0x56, - 0x42, 0x5c, 0xa2, 0xc2, 0xac, 0xe2, 0xfc, 0x71, 0x9d, 0xd7, 0x4d, 0xcb, 0x12, 0x83, 0xf2, 0x33, 0xd7, 0x70, 0xe3, - 0x7b, 0x8d, 0xfc, 0xf1, 0xbd, 0x97, 0xa0, 0xdb, 0x89, 0xb4, 0xf7, 0xef, 0xe7, 0xf7, 0xc8, 0x42, 0x03, 0x3f, 0x2c, - 0x9a, 0x41, 0x5b, 0xbc, 0x08, 0x90, 0xab, 0x67, 0x2c, 0xc6, 0xdb, 0x22, 0x54, 0x86, 0x0f, 0x58, 0x30, 0x03, 0x0c, - 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x0c, 0x1b, 0x4d, 0xb1, 0x6b, 0x2e, 0x0c, 0x3e, 0x50, 0x95, 0x85, 0xe4, 0xc5, 0x3a, - 0xd9, 0x5e, 0x9c, 0xc3, 0xf3, 0xeb, 0xb8, 0x00, 0xea, 0x20, 0xfa, 0x9a, 0xca, 0x62, 0x03, 0xb9, 0xb8, 0x29, 0x6b, - 0xbd, 0xa2, 0xd1, 0xe8, 0xc6, 0x2e, 0xbc, 0xae, 0xc0, 0x27, 0x51, 0x3a, 0x4a, 0xc4, 0x24, 0x66, 0x52, 0xe5, 0x8a, - 0x5c, 0x1b, 0xdd, 0x4b, 0x5b, 0x34, 0x2f, 0x85, 0x04, 0xaf, 0x08, 0xdc, 0x10, 0xfa, 0x4a, 0x5f, 0xae, 0x36, 0x50, - 0xf0, 0xa8, 0xbd, 0xb9, 0x08, 0x26, 0x26, 0x1e, 0x37, 0xa4, 0xa6, 0x5f, 0x87, 0x53, 0x2b, 0x8b, 0x25, 0x87, 0x5f, - 0xe7, 0x8c, 0x35, 0x14, 0x00, 0xf1, 0xc9, 0xa3, 0xf5, 0x6e, 0xd2, 0x1b, 0xa5, 0x1d, 0x94, 0x46, 0x88, 0xef, 0x2a, - 0x7c, 0xdd, 0x85, 0xe2, 0x2b, 0x57, 0xdd, 0xfb, 0x3a, 0x66, 0xc6, 0x05, 0xa3, 0x97, 0x7c, 0x9a, 0x34, 0xae, 0xdd, - 0xd0, 0x5d, 0x9d, 0xef, 0xbd, 0x2f, 0x65, 0xde, 0xc2, 0x31, 0xb0, 0xc9, 0x31, 0x73, 0x5e, 0x7a, 0x6f, 0x8d, 0x13, - 0xe5, 0x1f, 0xcc, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0x1f, 0x06, 0x3f, 0x04, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, - 0x5d, 0x75, 0x82, 0x4c, 0x94, 0xdb, 0xd0, 0x1b, 0x6e, 0xef, 0xae, 0x02, 0x41, 0x9c, 0x8a, 0xe9, 0xa3, 0x72, 0x5c, - 0x3f, 0x5a, 0xa0, 0x52, 0x11, 0xf1, 0xb9, 0xca, 0x5d, 0x59, 0x9b, 0x1a, 0xea, 0x31, 0x9d, 0xcc, 0x42, 0xd3, 0xac, - 0xc8, 0xa5, 0x6c, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, - 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, 0x7a, 0x14, 0x7d, 0x1c, 0xb7, 0x99, 0xcb, 0xa3, - 0xec, 0xcf, 0x1a, 0x00, 0xa6, 0x23, 0x2c, 0xba, 0x9b, 0x9e, 0xb1, 0x27, 0xd0, 0xd3, 0x13, 0x19, 0x24, 0x7a, 0xa3, - 0xf3, 0x55, 0xab, 0xc4, 0xd2, 0x15, 0x04, 0x76, 0x6f, 0xc8, 0x58, 0x95, 0xb4, 0x5b, 0xae, 0x5f, 0xce, 0xf3, 0x79, - 0xce, 0x97, 0xf2, 0x7c, 0x6a, 0x16, 0xdd, 0xbd, 0xb6, 0x7b, 0x73, 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, - 0x5d, 0x07, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, 0x8d, 0x7a, 0x26, 0xc7, 0x86, 0xf0, 0x4d, 0xa5, - 0x3b, 0x44, 0x37, 0x4c, 0xd5, 0x4c, 0xdf, 0x37, 0xb6, 0x85, 0x6c, 0xf3, 0xf2, 0x6a, 0x94, 0x03, 0xa5, 0xe5, 0xfe, - 0x32, 0x61, 0xf8, 0xfe, 0xfa, 0xfa, 0x7b, 0x21, 0xa7, 0xaa, 0x8e, 0xde, 0xe2, 0xb5, 0xee, 0x19, 0x6c, 0x94, 0xca, - 0x89, 0xb8, 0x60, 0xab, 0x07, 0x6f, 0xee, 0x5e, 0x01, 0xcb, 0x05, 0xec, 0xda, 0x0b, 0xe6, 0x34, 0x86, 0xaa, 0x36, - 0xf0, 0x97, 0xab, 0x07, 0x5b, 0xb5, 0x87, 0xbf, 0x1c, 0x7c, 0x19, 0xdc, 0xd8, 0xd8, 0xd8, 0xc6, 0xdb, 0xb5, 0x44, - 0x90, 0x37, 0x78, 0xa0, 0x8f, 0x57, 0x1f, 0x05, 0x2d, 0x57, 0x88, 0x6d, 0x36, 0x70, 0x28, 0x6c, 0x0d, 0xf2, 0x4d, - 0xca, 0xa4, 0xe1, 0xbc, 0xe0, 0xd9, 0x54, 0xce, 0x50, 0xc8, 0x6b, 0x3e, 0x0e, 0xda, 0x8e, 0xf0, 0xbf, 0xc0, 0xa9, - 0x1d, 0x2f, 0x2f, 0x3e, 0x41, 0x1f, 0xf0, 0x74, 0xa5, 0x34, 0xa5, 0x38, 0xa5, 0x0a, 0xea, 0x2c, 0xd7, 0x79, 0x30, - 0x52, 0x5c, 0x4c, 0x60, 0x71, 0xc1, 0x65, 0xb9, 0x71, 0x36, 0x72, 0xfa, 0x4b, 0xbc, 0xba, 0x48, 0x97, 0x8f, 0x44, - 0xb6, 0x6a, 0xe9, 0xfd, 0xac, 0x4f, 0xb7, 0xed, 0x29, 0xe3, 0x93, 0x6c, 0x44, 0x07, 0x33, 0x3e, 0x4e, 0x84, 0xd7, - 0x27, 0x46, 0xfa, 0x6e, 0x11, 0x98, 0x6e, 0x8e, 0x4d, 0x7e, 0x38, 0x5e, 0x6f, 0x36, 0x6b, 0xdc, 0xc1, 0x3b, 0xe7, - 0x93, 0xb3, 0x28, 0x31, 0xa2, 0xb2, 0xd0, 0xf0, 0x80, 0x56, 0x88, 0x9b, 0xf7, 0x4c, 0x60, 0x5c, 0x76, 0x45, 0x52, - 0xdb, 0x0d, 0x04, 0x2e, 0xf6, 0x38, 0x66, 0xc9, 0xc8, 0xf6, 0xa0, 0x3c, 0xd0, 0x17, 0xa3, 0xe9, 0x16, 0x30, 0x2d, - 0xaf, 0x9d, 0x5d, 0xa4, 0xb6, 0x57, 0x4d, 0x15, 0xc0, 0x2c, 0x59, 0x1e, 0x9f, 0x21, 0xeb, 0x7e, 0x0d, 0x5d, 0xc4, - 0x80, 0xb1, 0x71, 0x65, 0xce, 0x5d, 0xac, 0x5a, 0x11, 0xdf, 0x68, 0x22, 0x4d, 0xea, 0x43, 0xea, 0x7b, 0x14, 0xd6, - 0xea, 0x2a, 0x07, 0x09, 0xdc, 0x23, 0xef, 0x8e, 0xb8, 0xf4, 0xf4, 0x99, 0xc5, 0xb8, 0x4a, 0xdf, 0x52, 0xd7, 0xe2, - 0x9a, 0x61, 0xaf, 0x78, 0x00, 0xf6, 0x07, 0xc6, 0x2d, 0x62, 0x11, 0x6f, 0x67, 0xb5, 0x14, 0xd6, 0xc6, 0x1c, 0x68, - 0x6e, 0xb8, 0xc1, 0xcf, 0xac, 0x5a, 0x33, 0x30, 0xc3, 0x8c, 0x33, 0x92, 0x0f, 0xc6, 0xbd, 0xaa, 0xb1, 0x23, 0x57, - 0x01, 0x44, 0xdf, 0x82, 0x2e, 0xc9, 0xe1, 0x95, 0x2c, 0x57, 0x9d, 0x21, 0xbf, 0x82, 0x75, 0xd6, 0x8b, 0x13, 0x70, - 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0xb9, 0x91, 0xc0, - 0x11, 0xfb, 0xc6, 0x32, 0x34, 0x13, 0x36, 0x62, 0x22, 0x8d, 0x4a, 0x29, 0x61, 0x03, 0xb9, 0xd4, 0x92, 0xbf, 0xcc, - 0xe5, 0xd5, 0x97, 0xdb, 0x04, 0x07, 0xe4, 0x35, 0xb0, 0x1c, 0x1a, 0xc7, 0x2d, 0x03, 0x89, 0x58, 0x0c, 0x88, 0x51, - 0xab, 0x72, 0x39, 0x19, 0xd5, 0xc9, 0x7c, 0x85, 0x5c, 0xa8, 0xc8, 0x83, 0x5b, 0x02, 0x2f, 0x54, 0xe4, 0x98, 0x3a, - 0x98, 0x95, 0xda, 0x4d, 0x8b, 0x4d, 0x92, 0xf7, 0xcc, 0x80, 0xe4, 0xea, 0x6b, 0x78, 0x68, 0xfc, 0x32, 0xbc, 0xa1, - 0xe8, 0xe9, 0x18, 0x21, 0xa7, 0xa5, 0x31, 0x97, 0xfe, 0x5b, 0x79, 0x9f, 0x56, 0x02, 0xf6, 0x0a, 0xc4, 0x94, 0x81, - 0x4b, 0x6c, 0x5c, 0x90, 0x94, 0xd7, 0xf2, 0x94, 0xdd, 0xd7, 0x50, 0xbe, 0x4b, 0x26, 0x5d, 0xa5, 0xb2, 0xd6, 0x58, - 0x75, 0x3f, 0xcf, 0x59, 0x7e, 0xb5, 0xcf, 0x30, 0x37, 0x19, 0x0d, 0xb2, 0x25, 0x33, 0x9b, 0xf2, 0xab, 0xbd, 0x1b, - 0xbf, 0xf2, 0x50, 0xd2, 0xa1, 0x5a, 0xa5, 0x9b, 0x97, 0x6e, 0x38, 0xc6, 0x8d, 0x1b, 0x8e, 0x00, 0x36, 0x86, 0x9d, - 0x2a, 0x52, 0xeb, 0xfc, 0xf7, 0xa5, 0xf0, 0x93, 0xd8, 0x6b, 0x47, 0x7a, 0xd7, 0x1d, 0xad, 0x4c, 0x4f, 0xbf, 0x01, - 0x55, 0x23, 0x4b, 0xe8, 0x26, 0x54, 0x31, 0x19, 0x89, 0x12, 0xd3, 0x55, 0xca, 0xa3, 0xbe, 0x46, 0x9c, 0x83, 0xb8, - 0xa1, 0xfc, 0xc5, 0x3f, 0x85, 0x57, 0x27, 0x01, 0x1a, 0x51, 0x8b, 0x71, 0x96, 0xf2, 0xd6, 0x38, 0x9a, 0xc6, 0xc9, - 0x55, 0x30, 0x8f, 0x5b, 0xd3, 0x2c, 0xcd, 0x8a, 0x19, 0x70, 0xa5, 0x57, 0x5c, 0x81, 0x0d, 0x3f, 0x6d, 0xcd, 0x63, - 0xef, 0x25, 0x4b, 0xce, 0x19, 0x8f, 0x87, 0x91, 0x67, 0xef, 0xe5, 0x20, 0x1e, 0xac, 0xb7, 0x51, 0x9e, 0x67, 0x17, - 0xb6, 0xf7, 0x21, 0x3b, 0x05, 0xa6, 0xf5, 0xde, 0x5d, 0x5e, 0x9d, 0xb1, 0xd4, 0xfb, 0x78, 0x3a, 0x4f, 0xf9, 0xdc, - 0x2b, 0xa2, 0xb4, 0x68, 0x15, 0x2c, 0x8f, 0xc7, 0xa0, 0x26, 0x92, 0x2c, 0x6f, 0x61, 0xfe, 0xf3, 0x94, 0x05, 0x49, - 0x7c, 0x36, 0xe1, 0xd6, 0x28, 0xca, 0x3f, 0xf5, 0x5a, 0xad, 0x59, 0x1e, 0x4f, 0xa3, 0xfc, 0xaa, 0x45, 0x2d, 0x82, - 0xcf, 0xda, 0xdb, 0xd1, 0xe7, 0xe3, 0x87, 0x3d, 0x9e, 0x43, 0xdf, 0x18, 0xa9, 0x18, 0x80, 0xf0, 0xb1, 0xb6, 0x77, - 0xda, 0xd3, 0xe2, 0x9e, 0x38, 0x51, 0x8a, 0x52, 0x5e, 0x9e, 0x78, 0x57, 0x0c, 0xe0, 0xf6, 0x4f, 0x79, 0xea, 0x81, - 0x2f, 0xc7, 0xb3, 0x74, 0x31, 0x9c, 0xe7, 0x05, 0x0c, 0x30, 0xcb, 0xe2, 0x94, 0xb3, 0xbc, 0x77, 0x9a, 0xe5, 0x40, - 0xb6, 0x56, 0x1e, 0x8d, 0xe2, 0x79, 0x11, 0x3c, 0x9c, 0x5d, 0xf6, 0xd0, 0x56, 0x38, 0xcb, 0xb3, 0x79, 0x3a, 0x92, - 0x73, 0xc5, 0x29, 0x6c, 0x8c, 0x98, 0x9b, 0x15, 0xf4, 0x25, 0x14, 0x80, 0x2f, 0x65, 0x51, 0xde, 0x3a, 0xc3, 0xce, - 0x68, 0xe8, 0xb7, 0x47, 0xec, 0xcc, 0xcb, 0xcf, 0x4e, 0x23, 0xa7, 0xd3, 0x7d, 0xec, 0xa9, 0x7f, 0xfe, 0x8e, 0x0b, - 0x86, 0xfb, 0xca, 0xe2, 0x4e, 0xbb, 0xfd, 0x37, 0x6e, 0xaf, 0x31, 0x0b, 0x01, 0x14, 0x74, 0x66, 0x97, 0x56, 0x91, - 0x25, 0xb0, 0x3e, 0xab, 0x7a, 0xf6, 0x66, 0xe0, 0x37, 0xc5, 0xe9, 0x59, 0xd0, 0x9d, 0x5d, 0x96, 0x88, 0x5d, 0x20, - 0x12, 0x32, 0x25, 0x92, 0xf2, 0x6d, 0xf1, 0x5b, 0x21, 0x7e, 0xb2, 0x1a, 0xe2, 0xae, 0x82, 0xb8, 0xa2, 0x7a, 0x6b, - 0x04, 0xfb, 0x80, 0xc8, 0xdf, 0x29, 0x04, 0x20, 0x13, 0x70, 0x02, 0x73, 0x05, 0x07, 0xbd, 0xfc, 0x66, 0x30, 0xba, - 0xab, 0xc1, 0x78, 0x72, 0x1b, 0x18, 0x79, 0x3a, 0x5a, 0xd4, 0xd7, 0xb5, 0x03, 0xce, 0x69, 0x6f, 0xc2, 0x90, 0x9f, - 0x82, 0x2e, 0x3e, 0x5f, 0xc4, 0x23, 0x3e, 0x11, 0x8f, 0xc4, 0xce, 0x17, 0xa2, 0x6e, 0xa7, 0xdd, 0x16, 0xef, 0x05, - 0x28, 0xb4, 0xa0, 0xe3, 0x63, 0x03, 0x60, 0xa2, 0x2f, 0xd6, 0x7d, 0xc4, 0xe6, 0xbb, 0x5b, 0xbf, 0x54, 0xe3, 0x31, - 0x95, 0x37, 0x28, 0x54, 0x84, 0xfa, 0x66, 0x0b, 0x66, 0xbc, 0xe5, 0xfd, 0x8e, 0x3e, 0xa8, 0x1a, 0x7c, 0xc7, 0x48, - 0xeb, 0x05, 0xcc, 0x33, 0x73, 0x81, 0x7a, 0x69, 0x1f, 0x43, 0x52, 0xad, 0x96, 0x0b, 0x7a, 0x83, 0x63, 0x08, 0x89, - 0x0e, 0x04, 0x9d, 0x7c, 0x50, 0xd0, 0x37, 0x35, 0x32, 0x37, 0x28, 0x9c, 0xcc, 0x85, 0x2d, 0x9f, 0x69, 0xb9, 0x0e, - 0x4a, 0x1a, 0xbc, 0xec, 0x2f, 0x98, 0x6c, 0x00, 0xd2, 0xbb, 0x92, 0xb4, 0xbc, 0x3a, 0x7a, 0x52, 0x2e, 0x5f, 0x36, - 0x24, 0xca, 0x81, 0xaf, 0xcf, 0x27, 0xe8, 0x77, 0xeb, 0xab, 0xeb, 0x46, 0x4a, 0xcd, 0x96, 0xed, 0x0e, 0xb8, 0xce, - 0xca, 0xc2, 0xec, 0x33, 0x5e, 0xe2, 0x28, 0x5f, 0x81, 0x9c, 0xc5, 0xd0, 0xeb, 0xcf, 0xa1, 0x70, 0xd3, 0x94, 0x93, - 0xb6, 0x71, 0xd3, 0xf5, 0x7f, 0x58, 0xf1, 0x98, 0xb2, 0x9d, 0x55, 0x6c, 0x1c, 0x5c, 0x97, 0xe3, 0xa1, 0xb8, 0x76, - 0x58, 0x60, 0xb6, 0xf8, 0x6f, 0xf7, 0x24, 0x1c, 0x8d, 0x56, 0x91, 0xcd, 0xf3, 0x21, 0x26, 0xfd, 0xaf, 0x08, 0x31, - 0xd8, 0xa4, 0xe1, 0x6d, 0x8f, 0x6b, 0xc5, 0xc2, 0x30, 0x7f, 0xc2, 0xfc, 0xaa, 0x02, 0xa3, 0x53, 0x17, 0x71, 0xa9, - 0x41, 0x86, 0x55, 0x14, 0xd8, 0xa8, 0x2b, 0x47, 0x94, 0x60, 0x47, 0x17, 0x3e, 0xfd, 0x79, 0x1a, 0x83, 0x68, 0x3d, - 0x8e, 0x47, 0x74, 0xd1, 0x25, 0x1e, 0xd1, 0xc9, 0x47, 0x8b, 0x32, 0x9d, 0x30, 0x94, 0x0e, 0x05, 0x92, 0xe0, 0xf8, - 0x2c, 0x33, 0x67, 0xec, 0x96, 0x8d, 0xa7, 0x17, 0x86, 0x6e, 0x1e, 0x65, 0xd3, 0x28, 0x4e, 0x03, 0xfc, 0x20, 0x89, - 0xa7, 0x47, 0x0c, 0xb0, 0x8b, 0x07, 0x7f, 0x15, 0xed, 0x3b, 0xae, 0xff, 0x13, 0x08, 0x2e, 0xea, 0x5f, 0x4a, 0xc7, - 0x4f, 0xc3, 0xa5, 0xce, 0x95, 0xeb, 0xa5, 0x20, 0xec, 0xb8, 0xce, 0x6d, 0xa7, 0xc0, 0xca, 0x2e, 0xa3, 0x3f, 0x83, - 0x56, 0x27, 0xe8, 0xb8, 0xcb, 0x2b, 0x60, 0x5c, 0x0c, 0xa8, 0x56, 0x85, 0x4a, 0xe4, 0x1b, 0xcc, 0x21, 0xf9, 0xf3, - 0xfa, 0x5a, 0x7f, 0x3c, 0xa0, 0x71, 0x81, 0x56, 0xa4, 0xdf, 0xc8, 0x4b, 0x98, 0x84, 0x85, 0x7e, 0x16, 0x98, 0x56, - 0xef, 0x1a, 0x5b, 0x4f, 0x6e, 0x25, 0x8c, 0x39, 0x9d, 0xa5, 0x4e, 0x0d, 0x0d, 0x3a, 0xbe, 0x58, 0x33, 0x95, 0x5b, - 0x46, 0xc4, 0xdc, 0x4f, 0x49, 0xe6, 0xd4, 0xaf, 0x3f, 0xc5, 0x18, 0xb8, 0xaf, 0x65, 0x6d, 0x29, 0xf6, 0x1e, 0x9e, - 0xec, 0x0a, 0x21, 0x65, 0x11, 0xeb, 0x86, 0x36, 0x48, 0x0d, 0xdb, 0xfa, 0xe3, 0x10, 0xe8, 0xfc, 0x29, 0xb4, 0x37, - 0x16, 0x8e, 0xba, 0x0b, 0x90, 0xc3, 0x5c, 0x7b, 0x42, 0x51, 0xd3, 0x47, 0x04, 0xec, 0xfe, 0xc6, 0x82, 0x95, 0xbb, - 0x5b, 0xa2, 0x77, 0xff, 0xa4, 0x2c, 0x48, 0xa7, 0x9a, 0xb1, 0xbf, 0x6a, 0x0a, 0x51, 0x07, 0xc3, 0x52, 0xc6, 0x31, - 0x8e, 0x9b, 0x6b, 0x3b, 0x51, 0x04, 0xb9, 0x25, 0xe3, 0x16, 0x98, 0x61, 0x15, 0xe5, 0x20, 0x46, 0x74, 0x0e, 0x4d, - 0x21, 0xd2, 0x46, 0x7a, 0xcb, 0x50, 0x9c, 0x20, 0x04, 0x83, 0x8d, 0x45, 0x5c, 0x86, 0xf0, 0x94, 0x0e, 0xb3, 0x11, - 0xfb, 0xf8, 0xe1, 0x15, 0x5e, 0x93, 0xc8, 0x52, 0x94, 0xa7, 0x99, 0x5b, 0x9e, 0x80, 0x81, 0x85, 0x90, 0xe6, 0xea, - 0x2b, 0x35, 0x00, 0x8c, 0x88, 0x15, 0x59, 0x34, 0x2a, 0x82, 0xc2, 0x4b, 0xdb, 0x1a, 0x08, 0x08, 0xc1, 0x91, 0xc5, - 0x02, 0x30, 0x41, 0xa9, 0x17, 0x07, 0xfc, 0x44, 0xeb, 0x3e, 0x0c, 0xb4, 0xbb, 0x25, 0x1a, 0x01, 0xae, 0x39, 0xa2, - 0x51, 0xa1, 0x8a, 0x59, 0x45, 0x26, 0xba, 0xa3, 0xf8, 0x5c, 0x93, 0x93, 0x52, 0xac, 0xfb, 0xbb, 0x49, 0x74, 0xca, - 0x12, 0x18, 0x12, 0xf8, 0xaa, 0x0d, 0x23, 0x89, 0x57, 0x6b, 0x37, 0x4e, 0x67, 0x73, 0xf9, 0xb5, 0x30, 0x98, 0xb8, - 0x83, 0x07, 0xb8, 0x78, 0x99, 0x61, 0xa0, 0x4e, 0x24, 0x03, 0x39, 0x00, 0x80, 0x48, 0x87, 0x21, 0x08, 0x5d, 0xc5, - 0x2a, 0x50, 0x1a, 0x8f, 0x96, 0xcb, 0x60, 0x7f, 0xcf, 0xb0, 0x34, 0x85, 0xe7, 0x69, 0x9c, 0xe2, 0x63, 0x81, 0x8f, - 0xd1, 0x25, 0x3e, 0x66, 0xf0, 0xa8, 0x71, 0xcf, 0x4b, 0xfb, 0xaf, 0xba, 0x2a, 0x99, 0x5c, 0x01, 0x4b, 0x13, 0x20, - 0xbb, 0xbe, 0x06, 0xb5, 0xa5, 0x49, 0xb0, 0xbb, 0x05, 0xc4, 0x42, 0xee, 0x11, 0xdf, 0x8e, 0xe1, 0x26, 0x19, 0x59, - 0x31, 0x6b, 0x89, 0x72, 0x8b, 0x8c, 0x83, 0x10, 0x7c, 0xc7, 0xdc, 0x69, 0xd8, 0x40, 0x9e, 0xcc, 0x92, 0x79, 0x86, - 0x2f, 0xae, 0x6d, 0x89, 0x8f, 0x7b, 0x08, 0xa2, 0xd0, 0x23, 0x62, 0xa8, 0xcb, 0x98, 0xfc, 0x6c, 0x4f, 0x1c, 0xda, - 0x38, 0x0b, 0x98, 0xa1, 0xe8, 0x85, 0xf2, 0x28, 0x4e, 0x44, 0xe3, 0x15, 0xf8, 0x34, 0xd2, 0x1d, 0x09, 0x9d, 0xdd, - 0xad, 0x0a, 0x36, 0x00, 0x5e, 0x49, 0x04, 0x4e, 0x19, 0x37, 0xb6, 0x28, 0xa7, 0x14, 0x00, 0xb9, 0xcd, 0xab, 0x4f, - 0x3a, 0x01, 0x53, 0x80, 0x11, 0x3d, 0x3a, 0xa6, 0xd9, 0x06, 0x43, 0x20, 0x16, 0xcd, 0xd8, 0xd8, 0xba, 0xf6, 0x5f, - 0xfe, 0xf9, 0x1f, 0x6c, 0x4f, 0x80, 0x98, 0x8d, 0xc7, 0x20, 0xe5, 0xac, 0x75, 0x0d, 0xff, 0xd7, 0x3f, 0xfe, 0xdf, - 0xff, 0xf3, 0x5f, 0x75, 0xdb, 0x14, 0x9a, 0x9e, 0x04, 0xe2, 0x68, 0x41, 0x93, 0x94, 0x52, 0x3c, 0xed, 0x71, 0x94, - 0xae, 0x00, 0xe9, 0x10, 0xb3, 0x18, 0x19, 0x1b, 0x79, 0xb6, 0x05, 0x9a, 0x40, 0x3c, 0x1f, 0x27, 0xec, 0x9c, 0xc9, - 0x0f, 0xcb, 0xe8, 0x41, 0x74, 0xe5, 0x10, 0x2c, 0x18, 0x2e, 0xef, 0xbc, 0xca, 0x6d, 0xa0, 0x68, 0x29, 0x29, 0x5e, - 0x27, 0x98, 0x67, 0x1b, 0x83, 0x36, 0xe7, 0x68, 0xd7, 0x87, 0xf5, 0x40, 0xa5, 0xda, 0xb6, 0x80, 0x97, 0xcc, 0xde, - 0x95, 0x10, 0x37, 0xe1, 0x3a, 0xcd, 0xb1, 0x69, 0xca, 0x8a, 0x62, 0x15, 0x58, 0x40, 0x13, 0xcf, 0xae, 0x9a, 0xd8, - 0xb5, 0x0e, 0x00, 0x40, 0x77, 0x67, 0x47, 0x4c, 0x0b, 0x15, 0x6c, 0x3c, 0x86, 0x0d, 0x8e, 0xba, 0x2d, 0xe1, 0x18, - 0x84, 0x0f, 0xfb, 0xf6, 0x5b, 0x90, 0x25, 0x78, 0xa7, 0xc5, 0xd5, 0x9f, 0xf4, 0xa2, 0xe9, 0x95, 0xb0, 0x33, 0xe6, - 0x10, 0x9d, 0x8d, 0x61, 0xf4, 0x93, 0x81, 0x54, 0x36, 0xfc, 0xb4, 0x8a, 0x31, 0xd6, 0x32, 0xc2, 0xbf, 0xff, 0xcb, - 0x3f, 0xfe, 0x37, 0x18, 0x9b, 0xfa, 0xad, 0xe7, 0x02, 0x68, 0xf5, 0x3f, 0xa1, 0xd5, 0x3c, 0xbd, 0xa5, 0xdd, 0x5f, - 0xfe, 0xfe, 0xbf, 0x43, 0x33, 0xba, 0x28, 0x05, 0x7c, 0x42, 0x10, 0x0d, 0xd1, 0x36, 0xfd, 0x55, 0x20, 0xd5, 0x06, - 0x59, 0x3b, 0xd3, 0x3f, 0x21, 0xd8, 0x05, 0xcf, 0x66, 0x37, 0x82, 0x83, 0x50, 0x0f, 0x93, 0xac, 0x60, 0x1a, 0x1e, - 0xa1, 0x4f, 0x7e, 0x1d, 0x40, 0x34, 0xd7, 0x0c, 0x76, 0x6d, 0x61, 0xe9, 0x71, 0xc4, 0x0a, 0xad, 0xdc, 0x84, 0xf5, - 0x05, 0x2c, 0x18, 0x27, 0x74, 0x28, 0xdc, 0x03, 0x4b, 0x26, 0x9e, 0xe0, 0x81, 0x04, 0x9c, 0x5b, 0xff, 0xf8, 0xda, - 0xea, 0xc1, 0x34, 0xc3, 0x89, 0xb1, 0x44, 0x84, 0x4b, 0x8d, 0x00, 0x7f, 0x41, 0x08, 0x1f, 0xeb, 0xe7, 0xe8, 0x52, - 0x3f, 0xa3, 0xa0, 0x16, 0x13, 0x80, 0xbe, 0x9d, 0xa2, 0x31, 0x66, 0xce, 0x20, 0xb2, 0x33, 0x2a, 0xf7, 0xde, 0x48, - 0xf2, 0x11, 0xc2, 0xf8, 0x18, 0x73, 0x61, 0xf1, 0xe6, 0xd3, 0x3c, 0x67, 0xc7, 0x49, 0x76, 0x81, 0x31, 0x43, 0x22, - 0xd2, 0x9a, 0xfa, 0xf2, 0xdf, 0xfe, 0xd5, 0xf7, 0xff, 0xed, 0x5f, 0xd7, 0x34, 0x98, 0xc0, 0x9e, 0x00, 0x23, 0x9f, - 0x85, 0x9a, 0xce, 0x0d, 0xb4, 0x56, 0x0f, 0x8a, 0x78, 0xae, 0xae, 0x91, 0x88, 0x63, 0xa9, 0xc4, 0x5b, 0x3e, 0x12, - 0xda, 0x9a, 0x29, 0x6e, 0x9f, 0x05, 0x21, 0x5b, 0x33, 0x0d, 0x56, 0xdd, 0x32, 0xcf, 0x89, 0x1b, 0xdc, 0x40, 0x97, - 0x5f, 0x89, 0xf1, 0x6a, 0x30, 0x6e, 0x85, 0xc0, 0x03, 0x6d, 0x26, 0xf4, 0xdd, 0x33, 0xa1, 0xad, 0x02, 0xb1, 0x0c, - 0x52, 0x77, 0xd5, 0x00, 0xf2, 0xac, 0x03, 0x9a, 0x80, 0x9a, 0xc4, 0x95, 0xad, 0x40, 0xe6, 0xd6, 0x69, 0xde, 0x7f, - 0x83, 0x97, 0x1d, 0x91, 0x78, 0x64, 0x29, 0x14, 0x64, 0xd8, 0x30, 0x32, 0x6c, 0xa4, 0x46, 0x35, 0x6d, 0x0a, 0x74, - 0xfc, 0xb2, 0xd5, 0xb6, 0xc3, 0x31, 0x76, 0xaf, 0x69, 0x7f, 0x26, 0xb5, 0x7f, 0x2c, 0xed, 0x7d, 0xa9, 0xfd, 0xf1, - 0x93, 0x36, 0x0d, 0xed, 0x1f, 0xaf, 0xd5, 0xfe, 0x48, 0xb9, 0x01, 0x8e, 0x1c, 0xda, 0x9b, 0x18, 0xdd, 0x32, 0x6c, - 0x0d, 0xd4, 0xc4, 0x83, 0xe1, 0x84, 0x0d, 0x3f, 0x49, 0x33, 0x8b, 0x10, 0xc0, 0x40, 0x94, 0x36, 0x26, 0x05, 0x06, - 0x60, 0x32, 0x9c, 0x94, 0x7a, 0xd3, 0xe3, 0xa3, 0x31, 0x01, 0x73, 0x17, 0x63, 0x86, 0xa2, 0x1f, 0xd6, 0xec, 0x2b, - 0x56, 0x6e, 0xe1, 0x38, 0x62, 0xc3, 0x88, 0x67, 0xc0, 0x6c, 0x0b, 0x07, 0x3b, 0xf1, 0x16, 0x22, 0x58, 0x18, 0xd8, - 0xef, 0xdf, 0xed, 0x1f, 0xd8, 0xde, 0x69, 0x36, 0xba, 0x0a, 0x6c, 0x70, 0xc6, 0xc0, 0x9a, 0x72, 0x7d, 0x3e, 0x61, - 0xa9, 0xa3, 0x3c, 0x9f, 0x2c, 0x61, 0xe0, 0x00, 0x9e, 0x89, 0x6f, 0x5b, 0x34, 0x0f, 0x3a, 0x80, 0xb0, 0xf4, 0xf1, - 0xcb, 0xfe, 0x2e, 0x17, 0xdf, 0x85, 0xe5, 0x39, 0x3e, 0xf6, 0x31, 0xd5, 0x63, 0x77, 0x0b, 0x1e, 0xf0, 0x65, 0x1f, - 0xf5, 0x1e, 0xbd, 0x6d, 0x2c, 0x96, 0xdc, 0x86, 0x01, 0x0e, 0x31, 0xe9, 0x0b, 0x14, 0x0a, 0x6a, 0x75, 0x12, 0x20, - 0x62, 0xf0, 0x08, 0x63, 0x6d, 0xa9, 0x71, 0x11, 0x42, 0xd5, 0x5f, 0x3b, 0x2e, 0x95, 0xdd, 0x4a, 0xf3, 0x8e, 0xb0, - 0x01, 0x39, 0x2e, 0xd8, 0x7b, 0xa4, 0x4b, 0x84, 0xa9, 0x43, 0x45, 0xeb, 0x20, 0xd0, 0x35, 0x95, 0xb9, 0x22, 0x3a, - 0x18, 0xc0, 0x90, 0x99, 0x2b, 0x00, 0x81, 0xbf, 0x84, 0xf6, 0x89, 0xf9, 0xfd, 0x37, 0xf1, 0xa9, 0x26, 0x4d, 0x9c, - 0xc3, 0x3f, 0x79, 0x57, 0xcc, 0xbb, 0x3a, 0xa1, 0x96, 0x2a, 0xd8, 0x80, 0x51, 0x30, 0x0c, 0xca, 0xb4, 0x55, 0x54, - 0x09, 0xec, 0xb4, 0x24, 0x9a, 0x15, 0x2c, 0x50, 0x0f, 0x32, 0xee, 0x80, 0xe1, 0x8b, 0xe5, 0x40, 0x8f, 0x69, 0xcf, - 0x95, 0x7c, 0xb2, 0x30, 0x03, 0x13, 0x8f, 0xda, 0xed, 0x1e, 0x5e, 0xaa, 0x68, 0x45, 0x60, 0x1d, 0xa4, 0x41, 0xc2, - 0xc6, 0xbc, 0xe4, 0x78, 0x6b, 0x7f, 0xa1, 0x22, 0x41, 0x7e, 0x77, 0x27, 0x67, 0x53, 0xcb, 0xc7, 0xff, 0xbf, 0x6d, - 0xec, 0x51, 0x90, 0xf2, 0x49, 0x8b, 0xae, 0xf1, 0xe0, 0x15, 0x49, 0x80, 0xc8, 0x7c, 0x5f, 0x18, 0x13, 0x0d, 0x19, - 0x46, 0xc9, 0x4a, 0x0e, 0xce, 0x37, 0x88, 0x9b, 0xdc, 0x6c, 0x07, 0x72, 0x7a, 0x29, 0x54, 0xb6, 0x1c, 0xac, 0xd9, - 0x76, 0xa5, 0x7f, 0xb4, 0xdc, 0x58, 0x45, 0xbc, 0xea, 0x6f, 0x4b, 0x14, 0x32, 0x62, 0x73, 0xa5, 0x50, 0x51, 0x0b, - 0xd1, 0xc3, 0xc4, 0x69, 0x39, 0x6a, 0x77, 0xab, 0xc5, 0x5c, 0x92, 0xb8, 0x38, 0x24, 0x71, 0x41, 0xe2, 0xef, 0x68, - 0x21, 0xe6, 0x1e, 0x46, 0xc9, 0xd0, 0x41, 0x00, 0xac, 0x96, 0xf5, 0x04, 0xa8, 0xe9, 0xaa, 0xc8, 0x91, 0xff, 0x18, - 0x89, 0x5b, 0x0a, 0x61, 0xb9, 0x82, 0x4a, 0x27, 0x47, 0x65, 0xd9, 0x63, 0xcc, 0x39, 0xfc, 0x20, 0x2f, 0x81, 0x88, - 0xbb, 0xbf, 0xfa, 0xfb, 0x89, 0xed, 0xd2, 0x3d, 0xf2, 0x7e, 0x36, 0x3e, 0x4a, 0x67, 0x2b, 0x66, 0xb7, 0x3d, 0x58, - 0x06, 0xb3, 0xa7, 0xfc, 0x84, 0xe4, 0x4d, 0x7d, 0x4d, 0x36, 0xa7, 0xfe, 0x3f, 0x87, 0x38, 0xc2, 0x1b, 0xc7, 0x46, - 0x13, 0x9d, 0x46, 0xbe, 0x6a, 0x11, 0x7f, 0xda, 0xd8, 0x55, 0x1c, 0x81, 0x7c, 0xbd, 0x2e, 0x92, 0xf5, 0xcd, 0xed, - 0x91, 0xac, 0xe2, 0x8e, 0x91, 0xac, 0x6f, 0x7e, 0xe7, 0x48, 0xd6, 0xd7, 0x66, 0x24, 0x0b, 0x05, 0xf4, 0xab, 0x5f, - 0x13, 0x6d, 0xca, 0xb3, 0x8b, 0x22, 0xec, 0xc8, 0xcc, 0x09, 0x90, 0x75, 0x18, 0x76, 0xfa, 0xeb, 0x47, 0x98, 0x60, - 0xa2, 0x46, 0x7c, 0x89, 0x02, 0x4a, 0x22, 0xd9, 0x13, 0xd4, 0x8a, 0x0c, 0xe7, 0xb4, 0x75, 0x56, 0x65, 0xeb, 0xa1, - 0xba, 0x46, 0x06, 0xae, 0xaf, 0xab, 0x43, 0x6d, 0x5d, 0x15, 0xf0, 0x09, 0xe8, 0x3b, 0xb0, 0xba, 0x63, 0x77, 0x53, - 0xa5, 0xf3, 0x99, 0x23, 0xf4, 0xd4, 0x29, 0x8d, 0x60, 0xa2, 0x85, 0xfd, 0x5f, 0x0e, 0x3b, 0xbd, 0xed, 0xce, 0x14, - 0x7a, 0x83, 0x02, 0x87, 0xb7, 0x76, 0x6f, 0x7b, 0x1b, 0xdf, 0x2e, 0xd4, 0x5b, 0x17, 0xdf, 0x62, 0xf5, 0xb6, 0x83, - 0x6f, 0x43, 0xf5, 0xf6, 0x08, 0xdf, 0x46, 0xea, 0xed, 0x31, 0xbe, 0x9d, 0xdb, 0xe5, 0x21, 0xd3, 0xc0, 0x3d, 0x06, - 0xbe, 0x22, 0x6f, 0x26, 0x50, 0x65, 0xb0, 0xe9, 0xf1, 0xc3, 0x08, 0xd1, 0x59, 0x10, 0x7b, 0xc2, 0xbb, 0x0c, 0x72, - 0xef, 0x02, 0x34, 0x4e, 0x40, 0xd9, 0x86, 0xcf, 0xf1, 0x3b, 0x1c, 0xe0, 0x24, 0x1d, 0xc4, 0x53, 0xa6, 0x3e, 0x48, - 0xac, 0xb0, 0x06, 0x03, 0xf6, 0xb0, 0x7d, 0x54, 0xf6, 0xf4, 0x3a, 0x89, 0x78, 0x96, 0xca, 0xe6, 0xa0, 0x95, 0xab, - 0xea, 0xc4, 0x74, 0x2d, 0xbd, 0xc2, 0x6b, 0xf4, 0x97, 0x11, 0x8f, 0x18, 0x83, 0x61, 0xd6, 0xba, 0x04, 0x0f, 0x76, - 0xa5, 0x4e, 0x43, 0x88, 0xb4, 0x4e, 0x23, 0x9c, 0xf4, 0xdb, 0x41, 0x74, 0xa6, 0x9f, 0xdf, 0x80, 0xa5, 0x1d, 0x9d, - 0xc9, 0x96, 0xeb, 0x75, 0x18, 0x81, 0x68, 0xea, 0x2f, 0x05, 0x04, 0x99, 0x62, 0xb0, 0x34, 0xe8, 0x49, 0x4b, 0xfd, - 0x85, 0xd4, 0xa9, 0x6b, 0x34, 0x9a, 0xbe, 0x5e, 0x04, 0x14, 0xad, 0x0a, 0x76, 0xc1, 0xe0, 0xa7, 0x52, 0x41, 0x61, - 0xa8, 0xc0, 0x02, 0x51, 0xbd, 0x46, 0x95, 0xe9, 0x60, 0xc3, 0x5a, 0x85, 0x66, 0x29, 0x5d, 0x66, 0x9e, 0xee, 0xe8, - 0xa3, 0x9d, 0x65, 0xf1, 0xfa, 0x59, 0x67, 0x88, 0xff, 0x49, 0xe1, 0xfd, 0xd9, 0x78, 0x3c, 0xbe, 0x51, 0xb7, 0x7d, - 0x36, 0x1a, 0xb3, 0x2e, 0xdb, 0xe9, 0x61, 0xe4, 0xbf, 0x25, 0xc5, 0x69, 0xa7, 0x24, 0xda, 0x2d, 0xee, 0xd6, 0x18, - 0x25, 0x2f, 0xa8, 0xbb, 0xbb, 0x2b, 0xc1, 0x12, 0xa8, 0xb2, 0x00, 0xe1, 0x7f, 0x16, 0xa7, 0x41, 0xbb, 0xf4, 0xcf, - 0xa5, 0xd6, 0xf8, 0xec, 0xc9, 0x93, 0x27, 0xa5, 0x3f, 0x52, 0x6f, 0xed, 0xd1, 0xa8, 0xf4, 0x87, 0x0b, 0x8d, 0x46, - 0xbb, 0x3d, 0x1e, 0x97, 0x7e, 0xac, 0x0a, 0xb6, 0xbb, 0xc3, 0xd1, 0x76, 0xb7, 0xf4, 0x2f, 0x8c, 0x16, 0xa5, 0xcf, - 0xe4, 0x5b, 0xce, 0x46, 0xb5, 0xe3, 0x83, 0xc7, 0x6d, 0xa8, 0x14, 0x8c, 0xb6, 0x40, 0xef, 0x52, 0x3c, 0x06, 0xd1, - 0x9c, 0x67, 0x60, 0xd8, 0x95, 0xbd, 0x02, 0xe4, 0xf3, 0x58, 0x4a, 0x78, 0xf1, 0xbd, 0x5f, 0x94, 0xea, 0xaf, 0x4c, - 0xa9, 0x8e, 0xcc, 0x4c, 0xd2, 0xbc, 0x20, 0x6d, 0xd0, 0xac, 0x46, 0xce, 0xa2, 0xea, 0x57, 0x61, 0x51, 0x09, 0x7b, - 0x94, 0x36, 0xd8, 0x52, 0xc8, 0xf8, 0x1f, 0xd6, 0xc9, 0xf8, 0xef, 0x6f, 0x97, 0xf1, 0xa7, 0x77, 0x13, 0xf1, 0xdf, - 0xff, 0xce, 0x22, 0xfe, 0x07, 0x53, 0xc4, 0x0b, 0x21, 0xb6, 0x07, 0xa6, 0x33, 0xd9, 0xcc, 0xa7, 0xd9, 0x65, 0x0b, - 0xb7, 0x44, 0x6e, 0x93, 0xf4, 0x9c, 0xde, 0x49, 0xf8, 0xaf, 0xc8, 0x07, 0x53, 0x83, 0x19, 0x1f, 0x0f, 0xe6, 0xd9, - 0xd9, 0x59, 0xc2, 0x94, 0x8c, 0x37, 0x2a, 0xc8, 0x1c, 0x7f, 0x97, 0x86, 0xf6, 0x3b, 0xf4, 0x8c, 0xab, 0x92, 0xf1, - 0x18, 0x8a, 0xc6, 0x63, 0x5b, 0xe5, 0x4b, 0x83, 0x3c, 0xa3, 0x56, 0x6f, 0x6b, 0x25, 0xd4, 0xea, 0x8b, 0x2f, 0xcc, - 0x32, 0xb3, 0x40, 0x86, 0xf4, 0x4c, 0x63, 0x44, 0xd6, 0x8c, 0xe2, 0x02, 0xf7, 0x60, 0xf5, 0xb1, 0x63, 0xb4, 0x77, - 0xa6, 0xa0, 0x54, 0xe2, 0x21, 0x9e, 0x8b, 0x34, 0x3f, 0x2c, 0x23, 0x72, 0xdb, 0x97, 0x91, 0xab, 0xce, 0xbf, 0x8d, - 0x6f, 0x18, 0x56, 0x67, 0xde, 0xb0, 0xf8, 0x32, 0xbf, 0xe5, 0xe9, 0xd5, 0xab, 0x91, 0xb3, 0x87, 0x97, 0x7f, 0x8b, - 0x77, 0x69, 0x23, 0x6f, 0x50, 0x80, 0x1d, 0x86, 0x26, 0xa6, 0xa5, 0x20, 0x58, 0x75, 0x81, 0xa2, 0xaa, 0xec, 0x19, - 0x9d, 0x64, 0x7a, 0x19, 0x0e, 0x39, 0xa8, 0x91, 0x25, 0x30, 0x07, 0x93, 0xba, 0x90, 0x3e, 0x66, 0x2f, 0x92, 0x6e, - 0xce, 0xe5, 0x57, 0xcf, 0xe9, 0x70, 0x66, 0x21, 0xf5, 0x87, 0x4c, 0xc7, 0xa8, 0x7a, 0xd2, 0x79, 0x08, 0xcd, 0x30, - 0x2a, 0xd5, 0x19, 0x08, 0x10, 0x6e, 0x86, 0x9f, 0x68, 0x12, 0x43, 0xa8, 0x83, 0x82, 0x8a, 0x7a, 0xd7, 0xd7, 0xe6, - 0x97, 0x42, 0x6b, 0x5f, 0x95, 0x6c, 0xf0, 0x00, 0xc7, 0x4f, 0xfc, 0xa2, 0x36, 0xc8, 0xe6, 0xdc, 0xc1, 0x33, 0x80, - 0x05, 0x1e, 0x31, 0x78, 0x3b, 0xed, 0x36, 0xa8, 0x18, 0x5f, 0x7c, 0x07, 0xca, 0xd1, 0x9d, 0x05, 0xbe, 0x6c, 0xdd, - 0xb9, 0xc4, 0xd2, 0x77, 0xd9, 0x2a, 0x12, 0xdf, 0xbf, 0x2f, 0x11, 0x35, 0xee, 0x0e, 0xa9, 0x45, 0x6c, 0xbe, 0xfb, - 0xca, 0x77, 0x34, 0x08, 0xeb, 0xae, 0xe2, 0x60, 0x99, 0x5b, 0x5b, 0x2f, 0xc4, 0xb6, 0xc2, 0xaa, 0x59, 0x06, 0xe7, - 0x16, 0x9d, 0x59, 0x5c, 0x18, 0x01, 0xfc, 0xda, 0x36, 0x28, 0x55, 0x04, 0x5f, 0x84, 0xe1, 0xf7, 0xd0, 0xc5, 0x15, - 0x8e, 0xb7, 0x02, 0xba, 0xe1, 0xf2, 0x56, 0x90, 0xa3, 0x33, 0xac, 0x19, 0x5d, 0x55, 0xa9, 0x82, 0xd2, 0x3c, 0x82, - 0x31, 0x90, 0xa1, 0x48, 0x3a, 0xac, 0x71, 0x2a, 0xf4, 0x16, 0x4c, 0x43, 0x02, 0x58, 0xfb, 0x75, 0xe8, 0xd6, 0xd8, - 0x0a, 0x6c, 0x21, 0x2d, 0x40, 0xe9, 0x61, 0x87, 0xbe, 0x55, 0x03, 0x3d, 0x5d, 0x0e, 0xc0, 0xdf, 0xe8, 0xe4, 0x9d, - 0xf8, 0xc5, 0x85, 0x07, 0xff, 0xac, 0x3f, 0x2c, 0x40, 0xca, 0x9f, 0x7e, 0x8a, 0x39, 0xd8, 0xd4, 0xb3, 0x16, 0x86, - 0x5f, 0x28, 0x4e, 0x2b, 0xd5, 0x21, 0x1d, 0x45, 0x8b, 0x2b, 0x63, 0xbd, 0x79, 0x81, 0xbe, 0x20, 0x39, 0x3d, 0x41, - 0x9a, 0xa5, 0xac, 0x57, 0x4f, 0x39, 0x30, 0xfd, 0x0e, 0x45, 0xac, 0xa3, 0x45, 0x86, 0xbe, 0x23, 0xbf, 0x02, 0xdf, - 0x51, 0xa8, 0xd1, 0xb6, 0x72, 0x3a, 0xda, 0x2b, 0xdb, 0x07, 0x92, 0xb6, 0x9b, 0x64, 0x2d, 0xe4, 0xcb, 0xce, 0xd5, - 0x3a, 0xe7, 0xe8, 0xb6, 0x03, 0x78, 0x0c, 0x0a, 0xab, 0x7f, 0x46, 0xe6, 0x42, 0xb3, 0x98, 0x0e, 0xe0, 0xef, 0x02, - 0x59, 0x10, 0x8d, 0xf1, 0x0b, 0x8b, 0x77, 0x69, 0x79, 0x4a, 0xd9, 0xaf, 0x0b, 0x54, 0xeb, 0x41, 0xe7, 0x09, 0x78, - 0x7b, 0x77, 0x1e, 0xfe, 0x66, 0xf4, 0x4b, 0x49, 0x23, 0x75, 0x89, 0xd9, 0xb6, 0x7b, 0x28, 0x2f, 0x92, 0xe8, 0x0a, - 0x9c, 0x4e, 0xb2, 0x31, 0x4e, 0x31, 0x7a, 0xdc, 0x9b, 0x65, 0x32, 0x93, 0x24, 0x67, 0x09, 0xfd, 0x8c, 0x89, 0x5c, - 0x8a, 0xed, 0x47, 0xb3, 0x4b, 0xb5, 0x1a, 0x9d, 0x46, 0x86, 0xc8, 0xef, 0x9a, 0x08, 0xb2, 0x3e, 0xf3, 0xa4, 0x9e, - 0xcc, 0xb0, 0x03, 0x30, 0x08, 0xc3, 0xa6, 0x95, 0x0b, 0xa8, 0xda, 0x50, 0x62, 0xa4, 0xc2, 0x54, 0x03, 0x59, 0xfe, - 0x36, 0xa8, 0xca, 0xa8, 0x60, 0x3d, 0xfc, 0xd4, 0x65, 0x0c, 0xae, 0xad, 0x34, 0x9e, 0xa6, 0xf1, 0x68, 0x94, 0xb0, - 0x9e, 0xb2, 0x8f, 0xac, 0xce, 0x23, 0xcc, 0x24, 0x31, 0x97, 0xac, 0xbe, 0x2a, 0x06, 0xf1, 0x34, 0x9d, 0xa2, 0x53, - 0xb0, 0xd7, 0xf0, 0x7b, 0x95, 0x2b, 0xc9, 0x29, 0x53, 0x2c, 0xda, 0x15, 0xf1, 0xe8, 0xb9, 0x8e, 0xcb, 0x0e, 0x18, - 0x8b, 0xb4, 0xe0, 0xed, 0x1e, 0xcf, 0x66, 0x41, 0x6b, 0xbb, 0x8e, 0x08, 0x56, 0x69, 0x14, 0xbc, 0x15, 0x68, 0x79, - 0x68, 0x1d, 0x08, 0x2d, 0x67, 0xf9, 0x1d, 0x59, 0x46, 0x03, 0xe0, 0x37, 0x11, 0x75, 0x51, 0x59, 0x47, 0xe6, 0xaf, - 0xb3, 0x5b, 0x3e, 0x5f, 0xbd, 0x5b, 0x3e, 0x57, 0xbb, 0xe5, 0x66, 0x8e, 0xfd, 0x6c, 0xdc, 0xc1, 0xff, 0x7a, 0x15, - 0x42, 0xb0, 0x2a, 0x40, 0x0e, 0x0b, 0xed, 0xe2, 0x56, 0x17, 0xfe, 0x8f, 0x86, 0x6e, 0x7b, 0xf8, 0x9f, 0x0f, 0x16, - 0x60, 0xdb, 0xc2, 0x42, 0xfc, 0xd7, 0xae, 0x55, 0x75, 0x1e, 0x62, 0x1d, 0xf6, 0xda, 0x59, 0xae, 0xeb, 0xde, 0xbc, - 0x69, 0x41, 0x5e, 0x71, 0x27, 0x50, 0xc2, 0x18, 0x5c, 0xb5, 0xe8, 0xf4, 0x14, 0x4a, 0xc7, 0xd9, 0x70, 0x5e, 0xfc, - 0xad, 0x84, 0x5f, 0x12, 0xf1, 0xc6, 0x2d, 0xdd, 0x18, 0x47, 0x75, 0x15, 0x69, 0x49, 0x6a, 0x84, 0x85, 0x5e, 0xa7, - 0xa0, 0x00, 0xc6, 0x64, 0x4e, 0xd7, 0x7f, 0xb8, 0x62, 0x13, 0xfc, 0x7f, 0x59, 0x9b, 0x95, 0xc8, 0xfc, 0x47, 0x89, - 0x71, 0x23, 0x11, 0x7e, 0x15, 0x0d, 0xcc, 0x35, 0x6c, 0x3f, 0x59, 0x0d, 0xee, 0xa1, 0x9a, 0xe9, 0x48, 0x29, 0x05, - 0xa9, 0x77, 0xc0, 0x0b, 0x88, 0xe6, 0x09, 0xbf, 0x79, 0xd4, 0x75, 0x9c, 0xb1, 0x34, 0xea, 0x0d, 0x02, 0xbd, 0x6a, - 0x7b, 0x47, 0x29, 0xfd, 0xd9, 0xe7, 0x0f, 0xf1, 0x3f, 0x11, 0x38, 0x3b, 0xad, 0x7c, 0x23, 0x11, 0x1b, 0x40, 0xdf, - 0x68, 0x5a, 0x73, 0x7e, 0x84, 0x06, 0x27, 0xff, 0xe7, 0xae, 0xad, 0xd1, 0x58, 0xbf, 0x53, 0x73, 0x69, 0x95, 0xfe, - 0xaa, 0xd6, 0xbf, 0x6e, 0xf0, 0x3b, 0xb6, 0x1d, 0x0a, 0x87, 0xa0, 0xde, 0x56, 0xc6, 0x03, 0x97, 0x1a, 0x2b, 0x8a, - 0xdf, 0xb5, 0x7d, 0x65, 0x12, 0x53, 0x8f, 0x69, 0x78, 0xaa, 0x9d, 0x48, 0x79, 0x78, 0x8f, 0x3d, 0x84, 0x1f, 0xf9, - 0x25, 0x0b, 0x1f, 0xe0, 0xd7, 0xd8, 0xac, 0xcb, 0x69, 0x92, 0x82, 0x59, 0x35, 0xe1, 0x7c, 0x16, 0x6c, 0x6d, 0x5d, - 0x5c, 0x5c, 0xf8, 0x17, 0xdb, 0x7e, 0x96, 0x9f, 0x6d, 0x75, 0xdb, 0xed, 0x36, 0x7e, 0x44, 0xcb, 0xb6, 0xce, 0x63, - 0x76, 0xf1, 0x14, 0xdc, 0x0f, 0xfb, 0xb1, 0xf5, 0xc4, 0x7a, 0xbc, 0x6d, 0xed, 0x3c, 0xb2, 0x2d, 0x52, 0x00, 0x50, - 0xb2, 0x6d, 0x5b, 0x42, 0x01, 0x84, 0x36, 0x14, 0xf7, 0x77, 0xcf, 0x94, 0x0d, 0x87, 0x97, 0x14, 0x84, 0x85, 0x04, - 0xfe, 0x5b, 0xf6, 0x89, 0xd5, 0xb7, 0xba, 0x28, 0x6b, 0x49, 0x35, 0xa2, 0x5e, 0x71, 0xbf, 0x0f, 0xa3, 0x59, 0x40, - 0x6c, 0x64, 0x16, 0x62, 0x98, 0x4c, 0x94, 0xd2, 0x14, 0x68, 0x97, 0x9e, 0xc2, 0x13, 0x66, 0xb5, 0x59, 0xf0, 0xfc, - 0xa6, 0xfb, 0x18, 0x74, 0xdc, 0x79, 0xeb, 0xe1, 0xb0, 0xdd, 0xea, 0x58, 0x9d, 0x56, 0xd7, 0x7f, 0x6c, 0x75, 0xc5, - 0xff, 0x83, 0x8c, 0xdc, 0xb6, 0x3a, 0xf0, 0xb4, 0x6d, 0xc1, 0xfb, 0xf9, 0x43, 0x91, 0x5b, 0x12, 0xd9, 0x5b, 0xfd, - 0x5d, 0xfc, 0x4d, 0x29, 0x40, 0xea, 0x73, 0x5b, 0xfc, 0x0a, 0x9e, 0xfd, 0x99, 0x59, 0xda, 0x79, 0xb2, 0xb2, 0xb8, - 0xfb, 0x78, 0x65, 0xf1, 0xf6, 0xa3, 0x95, 0xc5, 0x0f, 0x77, 0xea, 0xc5, 0x5b, 0x67, 0xa2, 0x4a, 0xcb, 0x85, 0xd0, - 0x9e, 0x46, 0xc0, 0x28, 0x97, 0x4e, 0x07, 0xe0, 0x6c, 0x5b, 0x2d, 0xfc, 0xf3, 0xb8, 0xeb, 0xea, 0x5e, 0xa7, 0xd8, - 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfb, 0x68, 0x88, 0xed, 0x08, 0x51, 0xf8, 0x77, 0xbe, 0xfd, 0x64, - 0x08, 0x1a, 0xc1, 0xc2, 0x7f, 0xf0, 0xdf, 0x64, 0xa7, 0x3b, 0x14, 0x2f, 0x6d, 0xac, 0xff, 0xb6, 0xf3, 0xb8, 0x80, - 0xa6, 0xf8, 0xdf, 0x2f, 0xda, 0x84, 0x46, 0x03, 0xde, 0x1c, 0xf7, 0x21, 0xd0, 0xe8, 0xc9, 0xa4, 0xeb, 0x7f, 0x7e, - 0xfe, 0xd8, 0x7f, 0x32, 0xe9, 0x3c, 0xfe, 0x56, 0xbc, 0x25, 0x40, 0xc1, 0xcf, 0xf1, 0xdf, 0xb7, 0xdb, 0xed, 0x49, - 0xab, 0xe3, 0x3f, 0x39, 0xdf, 0xf6, 0xb7, 0x93, 0xd6, 0x23, 0xff, 0x09, 0xfe, 0xab, 0x86, 0x9b, 0x64, 0x53, 0x66, - 0x5b, 0xb8, 0xde, 0x0d, 0xbf, 0xd7, 0x9c, 0xa3, 0xfb, 0xd0, 0xda, 0x79, 0xf8, 0xf2, 0x09, 0xac, 0xd1, 0xa4, 0xd3, - 0x85, 0xff, 0x5f, 0xf7, 0xf8, 0x2d, 0x12, 0x5e, 0x0e, 0x1c, 0x31, 0x4c, 0x2f, 0x56, 0x84, 0xa3, 0x0f, 0xba, 0x3d, - 0xf0, 0xfe, 0xb4, 0x2e, 0x00, 0xc2, 0xf8, 0xad, 0x01, 0x10, 0xce, 0xef, 0x16, 0x01, 0xa1, 0x5f, 0x1b, 0xf8, 0x1d, - 0x23, 0x20, 0x7f, 0x6a, 0x06, 0xb9, 0x2f, 0xd9, 0x52, 0xa0, 0xa3, 0xe9, 0xac, 0xbd, 0x65, 0xce, 0xe1, 0x97, 0xf8, - 0xe3, 0x06, 0x65, 0x0f, 0x5a, 0x73, 0x6e, 0xc6, 0x83, 0x32, 0xdc, 0xc8, 0x97, 0xf2, 0xe2, 0x43, 0xc1, 0xd7, 0x10, - 0x24, 0xbe, 0x9d, 0x20, 0xdf, 0xde, 0x8d, 0x1e, 0xf1, 0xef, 0x4c, 0x8f, 0x82, 0x1b, 0xf4, 0xa8, 0x45, 0xdc, 0x29, - 0x62, 0x40, 0x8e, 0xfe, 0x3e, 0xbd, 0x3b, 0x9c, 0xbe, 0xc5, 0xb6, 0xc5, 0xb0, 0xa8, 0xb0, 0x45, 0xce, 0xe6, 0xd3, - 0x5f, 0x73, 0x44, 0x20, 0xd2, 0xcd, 0x43, 0x5b, 0x46, 0x61, 0x66, 0xf8, 0xd1, 0x62, 0xf5, 0x72, 0x2e, 0xae, 0x34, - 0x85, 0x74, 0x1f, 0x71, 0x47, 0x47, 0x70, 0xf0, 0x06, 0x40, 0xb8, 0xc8, 0x78, 0x84, 0xbf, 0x8a, 0x05, 0xe4, 0xa6, - 0xdf, 0xcf, 0x8a, 0x79, 0xc2, 0x30, 0x9d, 0x66, 0x28, 0x3e, 0x20, 0x0b, 0x8f, 0xf2, 0xae, 0x21, 0xa6, 0xb0, 0x7f, - 0x83, 0xe9, 0xf7, 0xea, 0xec, 0x60, 0x8a, 0x71, 0x84, 0x37, 0x6c, 0x14, 0x47, 0x8e, 0xed, 0xcc, 0x60, 0x23, 0xc3, - 0x2c, 0xad, 0x5a, 0xee, 0x3b, 0xa5, 0xbd, 0xbb, 0xb6, 0xfa, 0x69, 0xa6, 0x1c, 0x3f, 0x75, 0x17, 0x1e, 0xca, 0xb8, - 0xa3, 0x2d, 0x1d, 0x03, 0x18, 0x5f, 0x95, 0xe4, 0xa8, 0x03, 0x2a, 0x63, 0xc2, 0x16, 0xd6, 0x44, 0xc7, 0xef, 0x82, - 0x77, 0x41, 0xc5, 0xf8, 0xe9, 0xb0, 0xef, 0x9d, 0xd6, 0x36, 0x58, 0x3b, 0x46, 0x37, 0x3d, 0xd0, 0x91, 0xfe, 0xa5, - 0x1f, 0xfd, 0x6b, 0x74, 0xf5, 0x0b, 0x03, 0xb6, 0xe0, 0x88, 0xcf, 0x04, 0xee, 0xb6, 0xf8, 0x44, 0x83, 0x48, 0x28, - 0xc1, 0x0b, 0x73, 0x50, 0xe6, 0x98, 0xbf, 0x4a, 0x26, 0x3e, 0x4d, 0x26, 0x7e, 0x80, 0xb0, 0xac, 0x9a, 0x70, 0x77, - 0x41, 0x67, 0x23, 0xf8, 0x23, 0x9a, 0x98, 0x68, 0x8a, 0xa1, 0xf2, 0xd0, 0xa0, 0x29, 0xbe, 0xbb, 0x35, 0x22, 0x73, - 0x4f, 0x03, 0x44, 0x04, 0x0e, 0xe5, 0xdf, 0xaa, 0x58, 0x3d, 0xc8, 0xa0, 0x16, 0x38, 0xfa, 0xf8, 0xb3, 0x2f, 0xf4, - 0x67, 0x29, 0x64, 0x26, 0x02, 0x21, 0x8d, 0xd2, 0x6a, 0xa8, 0x2a, 0x34, 0x56, 0x3c, 0xbd, 0x3a, 0x90, 0xdf, 0x3c, - 0xb0, 0x31, 0x4a, 0x4d, 0xa7, 0x13, 0xd5, 0xf7, 0xd6, 0x36, 0x41, 0x35, 0xd2, 0xaf, 0xa0, 0x52, 0x82, 0x01, 0x6a, - 0x3f, 0xbc, 0x72, 0x60, 0x49, 0x2f, 0x29, 0xb4, 0x85, 0xee, 0x1b, 0xb1, 0xf3, 0x78, 0x28, 0x55, 0x98, 0x67, 0xc9, - 0xab, 0x52, 0x2d, 0x5a, 0x9a, 0xb0, 0xe3, 0x89, 0x38, 0x01, 0xbc, 0xa0, 0x06, 0x0f, 0xd3, 0xcc, 0xee, 0x3f, 0xe8, - 0xad, 0x23, 0x3e, 0xfe, 0x24, 0xeb, 0x21, 0xf8, 0xa5, 0x7f, 0x1b, 0x3e, 0xc0, 0x1f, 0x65, 0x7d, 0x70, 0x64, 0xbb, - 0x3e, 0x29, 0x80, 0x07, 0xd5, 0x2f, 0xb3, 0xa2, 0xf4, 0xdb, 0x04, 0x5d, 0xed, 0xdd, 0x55, 0x69, 0x4b, 0x05, 0xdd, - 0xdd, 0xa9, 0x14, 0x34, 0x3c, 0x1b, 0x12, 0x19, 0x94, 0x45, 0xd7, 0xdf, 0x31, 0xc4, 0xfe, 0x79, 0x0b, 0xff, 0xd6, - 0x04, 0xff, 0x43, 0x68, 0xa0, 0x24, 0xff, 0x6b, 0x68, 0xbe, 0x2d, 0x94, 0x0c, 0xf4, 0xfb, 0x81, 0xc4, 0xb2, 0x10, - 0xc9, 0xf5, 0x6d, 0xb0, 0xe2, 0xc0, 0x4c, 0x24, 0x63, 0xd8, 0x9e, 0x11, 0x5b, 0x13, 0xbb, 0x52, 0x46, 0x8e, 0x9e, - 0x43, 0x5f, 0x47, 0x7f, 0xc6, 0x7c, 0x55, 0x9d, 0x57, 0x93, 0x12, 0x2b, 0xa6, 0xc0, 0x7d, 0xdd, 0x38, 0x94, 0xeb, - 0x89, 0x3c, 0x6f, 0xfd, 0x1d, 0x94, 0xf5, 0x0c, 0x2d, 0x13, 0xc2, 0x5d, 0x43, 0x44, 0x30, 0xfa, 0xd4, 0x2a, 0x4d, - 0xf2, 0x6a, 0x54, 0x36, 0xe7, 0x07, 0xb3, 0x06, 0x7f, 0x97, 0xb2, 0xba, 0xe5, 0x23, 0xaf, 0xef, 0x62, 0xca, 0xc5, - 0x28, 0xce, 0xe9, 0x56, 0xb8, 0x02, 0xbd, 0x16, 0x78, 0xad, 0xa8, 0x44, 0x52, 0x82, 0x15, 0x03, 0x1b, 0x8b, 0xec, - 0x40, 0x26, 0x06, 0x9a, 0xdf, 0x1a, 0x37, 0xaf, 0xed, 0x8e, 0x44, 0x4e, 0x20, 0xfe, 0x16, 0x83, 0x2d, 0xe8, 0x63, - 0x83, 0xb4, 0x5d, 0xbb, 0x4b, 0xc8, 0x06, 0x43, 0x5c, 0xab, 0x1f, 0xd7, 0x32, 0x05, 0x90, 0x6d, 0x12, 0x5a, 0x8f, - 0x4b, 0x24, 0x74, 0x25, 0x9d, 0x4e, 0x59, 0xc4, 0xfd, 0x28, 0xa5, 0xfc, 0x2d, 0xc7, 0x10, 0x53, 0x5e, 0x87, 0x6d, - 0xbb, 0x25, 0xc8, 0x46, 0xe3, 0xd7, 0xc7, 0xe4, 0xee, 0x86, 0x42, 0xfd, 0xe5, 0xab, 0x7a, 0x2e, 0xf6, 0xa4, 0xdb, - 0x7f, 0x77, 0xb0, 0x67, 0x89, 0x4d, 0xb9, 0xbb, 0x05, 0xaf, 0xbb, 0xe4, 0xc1, 0x8b, 0x54, 0x96, 0x50, 0xa4, 0xb2, - 0x58, 0x22, 0x01, 0x4e, 0xe4, 0x2e, 0x6f, 0x09, 0xb4, 0x6d, 0x8b, 0xa5, 0x43, 0x11, 0x7a, 0x9c, 0x82, 0x97, 0x13, - 0xe3, 0xf7, 0xe9, 0xb6, 0xb0, 0x6b, 0x0b, 0x17, 0xcc, 0x56, 0x59, 0x41, 0xca, 0xae, 0xe1, 0xa9, 0x0a, 0x54, 0x82, - 0x35, 0xc2, 0x54, 0x82, 0x90, 0x1c, 0x4a, 0xe7, 0x25, 0x2f, 0xb7, 0x2e, 0xe6, 0xa7, 0x53, 0x90, 0x93, 0x2a, 0xa9, - 0xe7, 0xa3, 0xec, 0xb0, 0x4b, 0x53, 0xf5, 0x4f, 0x4a, 0x19, 0x49, 0x55, 0xdf, 0x0e, 0x6f, 0xfc, 0xce, 0xaa, 0xc0, - 0x5e, 0xea, 0x05, 0xcc, 0x49, 0x99, 0x6c, 0x1b, 0x39, 0x29, 0x46, 0x5d, 0x09, 0xa8, 0x6f, 0xf7, 0x4f, 0x82, 0x99, - 0x1c, 0xef, 0x75, 0xb6, 0xf4, 0x9b, 0xad, 0x5a, 0x4e, 0x0e, 0x28, 0xbf, 0x5c, 0xdc, 0xeb, 0x90, 0x00, 0xc3, 0x0a, - 0x02, 0x4c, 0xd2, 0x04, 0xb0, 0xe8, 0xe8, 0xdb, 0xde, 0x69, 0xab, 0xb4, 0x5d, 0x28, 0xc3, 0x0d, 0x29, 0xba, 0x18, - 0x93, 0xd4, 0xc2, 0xbf, 0x93, 0x4e, 0x7f, 0x37, 0x92, 0xc6, 0x25, 0x0a, 0x8f, 0x02, 0xa4, 0x07, 0x74, 0x46, 0x0b, - 0xce, 0x8f, 0xb3, 0xad, 0x0b, 0x76, 0xda, 0x8a, 0x66, 0x71, 0x15, 0x6b, 0x45, 0x53, 0x43, 0x4f, 0x99, 0x55, 0x33, - 0xe1, 0x63, 0xd4, 0x40, 0x92, 0x04, 0x77, 0x29, 0x03, 0xb9, 0x64, 0xa1, 0x03, 0x0b, 0x01, 0x85, 0x49, 0xae, 0xab, - 0x80, 0xaf, 0xd4, 0xb8, 0xa5, 0xdd, 0xff, 0xcb, 0x3f, 0xff, 0x6f, 0x19, 0xc3, 0x05, 0xaa, 0x74, 0xd4, 0x58, 0x0d, - 0x42, 0x97, 0xbb, 0x98, 0x02, 0x55, 0x9d, 0xf2, 0xb2, 0xcb, 0xd6, 0x59, 0x1e, 0x8f, 0x5a, 0x93, 0x28, 0x19, 0x03, - 0x60, 0x6b, 0x09, 0x64, 0x26, 0x48, 0x48, 0xa8, 0xeb, 0x45, 0xc8, 0x82, 0xbf, 0x29, 0x11, 0x5b, 0x25, 0xc0, 0xd3, - 0x6e, 0x35, 0xd3, 0xb2, 0xab, 0x0d, 0x55, 0x4b, 0xcd, 0x56, 0x3f, 0x5c, 0xa6, 0x84, 0x5a, 0x2d, 0x2f, 0x1b, 0x5a, - 0xea, 0xc3, 0xa8, 0x7f, 0xff, 0x97, 0x7f, 0xf8, 0x1f, 0xea, 0x15, 0xcf, 0x98, 0xfe, 0xf2, 0x4f, 0x7f, 0x87, 0x29, - 0xd0, 0x96, 0x3e, 0x87, 0x22, 0x39, 0x61, 0x55, 0x87, 0x50, 0x42, 0x60, 0x58, 0x95, 0xd3, 0x57, 0xcf, 0xdf, 0xde, - 0xa7, 0x09, 0x69, 0xb3, 0x49, 0xe8, 0x68, 0xd3, 0x96, 0x15, 0x8f, 0xd4, 0x48, 0x4e, 0xbc, 0x08, 0x95, 0x48, 0xef, - 0x3b, 0x25, 0x47, 0xf9, 0x7a, 0x35, 0x16, 0x2a, 0x42, 0x88, 0x25, 0x65, 0x55, 0x6e, 0x61, 0xe8, 0x7e, 0x81, 0xaf, - 0x41, 0xd7, 0x28, 0xa6, 0xc5, 0xab, 0xf5, 0xe9, 0xfd, 0x34, 0x07, 0xf8, 0xc7, 0x48, 0x71, 0x11, 0x87, 0xa4, 0x63, - 0xe9, 0x16, 0xda, 0x7c, 0xc9, 0x55, 0x49, 0xa3, 0x08, 0x47, 0xf1, 0xe1, 0x93, 0xbf, 0x29, 0xff, 0x38, 0x45, 0xcb, - 0xca, 0x72, 0xa6, 0xd1, 0xa5, 0x74, 0x1f, 0x1f, 0xb5, 0xdb, 0xb3, 0x4b, 0x77, 0x51, 0xcd, 0xe0, 0xad, 0x9b, 0x8c, - 0x62, 0x97, 0xe6, 0x80, 0x74, 0x9e, 0xad, 0xc3, 0xa4, 0xe0, 0x31, 0xb5, 0x31, 0xaa, 0x56, 0x96, 0x7f, 0x58, 0x50, - 0xa4, 0x2e, 0xfe, 0x05, 0xcf, 0x9d, 0x65, 0x50, 0x13, 0x4a, 0x0c, 0x2c, 0x16, 0x46, 0xaf, 0xae, 0xe8, 0x35, 0xe9, - 0x2c, 0xa7, 0x0d, 0x99, 0xe7, 0xe6, 0xe6, 0x89, 0xf7, 0x43, 0x3c, 0xc3, 0x9e, 0x74, 0xbc, 0x49, 0x77, 0xa1, 0x87, - 0xe7, 0x3c, 0x9b, 0x9a, 0x07, 0xe5, 0x2c, 0x62, 0x43, 0x36, 0x56, 0xc1, 0x60, 0x59, 0x2f, 0x0e, 0xc1, 0xcb, 0xc9, - 0xf6, 0x8a, 0xb9, 0x24, 0x48, 0x74, 0x40, 0x0e, 0xf0, 0x7c, 0x86, 0x1b, 0x10, 0xe8, 0x9f, 0x45, 0x3c, 0x20, 0x7e, - 0xed, 0x99, 0xc7, 0xed, 0x11, 0x4a, 0x99, 0x6c, 0x61, 0xc0, 0xd3, 0x13, 0x4d, 0x31, 0x2c, 0x5b, 0x4f, 0xdb, 0x2a, - 0x7d, 0xea, 0x6e, 0x0e, 0x25, 0xa2, 0x3a, 0xdf, 0xca, 0x53, 0xec, 0xa7, 0xb5, 0x70, 0x88, 0x54, 0x31, 0x5d, 0xd7, - 0x5b, 0x59, 0x2f, 0x34, 0xb5, 0xa8, 0xfd, 0x16, 0x0c, 0x30, 0x02, 0xd3, 0x6e, 0xb6, 0xa2, 0x42, 0x6c, 0xf5, 0x34, - 0xfc, 0x56, 0xbb, 0x3e, 0xd1, 0x6c, 0x46, 0x0d, 0x5d, 0x60, 0x62, 0x32, 0x58, 0x51, 0x76, 0x50, 0x86, 0x86, 0x48, - 0x88, 0x90, 0x6d, 0xe4, 0x46, 0x10, 0x4f, 0x32, 0x55, 0x02, 0x7f, 0x72, 0xa2, 0xff, 0xff, 0x00, 0x69, 0x5b, 0x88, - 0x58, 0x18, 0x7f, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, + 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x10, 0x4a, 0xad, 0x02, 0xae, 0x40, 0x88, 0xa4, 0x6a, 0x33, 0x28, 0x90, 0x57, 0xb5, + 0xd8, 0x55, 0x76, 0x6d, 0x2e, 0xa9, 0xec, 0x6b, 0xcb, 0xb4, 0x04, 0x91, 0x49, 0x11, 0x2e, 0x10, 0xa0, 0x81, 0xa4, + 0x16, 0x53, 0xe8, 0x33, 0x4f, 0xf3, 0xd4, 0xe7, 0xcc, 0xd6, 0x0f, 0xfd, 0x30, 0x7d, 0xba, 0x1f, 0xe6, 0x23, 0xe6, + 0xb9, 0x3f, 0xe5, 0xfe, 0xc0, 0xf4, 0x27, 0x4c, 0x44, 0xe4, 0x82, 0x04, 0x17, 0x49, 0x5e, 0xba, 0xe7, 0xd8, 0x2a, + 0x12, 0xb9, 0x46, 0x44, 0x46, 0xc6, 0x96, 0x91, 0xe0, 0xde, 0xc6, 0x30, 0x1b, 0xf0, 0xab, 0x29, 0xb3, 0xc6, 0x7c, + 0x92, 0x74, 0xf7, 0xe4, 0xbf, 0x2c, 0x1a, 0x76, 0xf7, 0x92, 0x38, 0xfd, 0x64, 0xe5, 0x2c, 0x09, 0xe3, 0x41, 0x96, + 0x5a, 0xe3, 0x9c, 0x8d, 0xc2, 0x61, 0xc4, 0xa3, 0x20, 0x9e, 0x44, 0x67, 0xcc, 0xda, 0xe9, 0xee, 0x4d, 0x18, 0x8f, + 0xac, 0xc1, 0x38, 0xca, 0x0b, 0xc6, 0xc3, 0x8f, 0x87, 0x9f, 0x37, 0x9e, 0x74, 0xf7, 0x8a, 0x41, 0x1e, 0x4f, 0xb9, + 0x85, 0x43, 0x86, 0x93, 0x6c, 0x38, 0x4b, 0x58, 0xf7, 0x3c, 0xca, 0xad, 0x17, 0x3c, 0x7c, 0x77, 0xfa, 0x13, 0x1b, + 0x70, 0x7f, 0xc8, 0x46, 0x71, 0xca, 0xde, 0xe7, 0xd9, 0x94, 0xe5, 0xfc, 0xca, 0x3b, 0x58, 0x5d, 0x11, 0xb3, 0xc2, + 0x7b, 0xa6, 0xab, 0xce, 0x18, 0x7f, 0x77, 0x91, 0xaa, 0x3e, 0xcf, 0x99, 0x98, 0x24, 0xcb, 0x0b, 0xaf, 0x58, 0xd3, + 0xe6, 0xe0, 0x6a, 0x72, 0x9a, 0x25, 0x85, 0xf7, 0x49, 0xd7, 0x4f, 0xf3, 0x8c, 0x67, 0x08, 0x96, 0x3f, 0x8e, 0x0a, + 0xa3, 0xa5, 0xf7, 0x6e, 0x45, 0x93, 0xa9, 0xac, 0x7c, 0x55, 0xbc, 0x48, 0x67, 0x13, 0x96, 0x47, 0xa7, 0x09, 0xf3, + 0x72, 0x1e, 0x3a, 0xdc, 0x63, 0x5e, 0xec, 0x86, 0x5d, 0x66, 0xc5, 0xa9, 0xc5, 0x7b, 0x2f, 0x38, 0x95, 0xcc, 0x99, + 0x6e, 0x15, 0x6c, 0x34, 0x3d, 0x20, 0xd7, 0x28, 0x3e, 0x9b, 0xe9, 0xe7, 0x8b, 0x3c, 0xe6, 0xea, 0xfb, 0x79, 0x94, + 0xcc, 0x58, 0x10, 0x97, 0x6e, 0xc0, 0x8f, 0x58, 0x3f, 0x8c, 0xbd, 0x4f, 0x34, 0x28, 0x0c, 0x39, 0x1f, 0x65, 0xb9, + 0x83, 0xb4, 0x8a, 0x71, 0x6c, 0x76, 0x7d, 0xed, 0xb0, 0x70, 0x5e, 0xba, 0xee, 0x27, 0xee, 0x0f, 0xa2, 0x24, 0x71, + 0x70, 0xe2, 0xad, 0xad, 0x1c, 0x67, 0x8c, 0x3d, 0x76, 0x14, 0xf7, 0xdd, 0x4e, 0x3c, 0x72, 0x0a, 0xee, 0x56, 0xfd, + 0xb2, 0x91, 0x55, 0x70, 0x87, 0xb9, 0xee, 0xbb, 0xf5, 0x7d, 0x72, 0xc6, 0x67, 0x39, 0xc0, 0x5e, 0x7a, 0xef, 0xd4, + 0xcc, 0x07, 0x58, 0xff, 0x8c, 0x3a, 0x76, 0x00, 0xf6, 0x82, 0x5b, 0x9f, 0x87, 0x17, 0x71, 0x3a, 0xcc, 0x2e, 0xfc, + 0x83, 0x71, 0x04, 0x1f, 0x1f, 0xb2, 0x8c, 0x6f, 0x6d, 0x39, 0xe7, 0x59, 0x3c, 0xb4, 0x9a, 0x61, 0x68, 0x56, 0x5e, + 0x3d, 0x3b, 0x38, 0xb8, 0xbe, 0x5e, 0x28, 0xf0, 0xd3, 0x88, 0xc7, 0xe7, 0x4c, 0x74, 0x06, 0x00, 0x6c, 0xf8, 0x9c, + 0x72, 0x36, 0x3c, 0xe0, 0x57, 0x09, 0x94, 0x32, 0xc6, 0x0b, 0x1b, 0x70, 0x7c, 0x9e, 0x0d, 0x80, 0x6c, 0xa9, 0x41, + 0x78, 0x68, 0x9a, 0xb3, 0x69, 0x12, 0x0d, 0x18, 0xd6, 0xc3, 0x48, 0x55, 0x8f, 0xaa, 0x91, 0xf7, 0x6d, 0x28, 0x96, + 0xd7, 0x71, 0xbd, 0x94, 0x87, 0x29, 0xbb, 0xb0, 0xde, 0x44, 0xd3, 0xce, 0x20, 0x89, 0x8a, 0xc2, 0xca, 0xf8, 0x9c, + 0x50, 0xc8, 0x67, 0x03, 0x60, 0x10, 0x42, 0x70, 0x0e, 0x64, 0xe2, 0xe3, 0xb8, 0xf0, 0x8f, 0x37, 0x07, 0x45, 0xf1, + 0x81, 0x15, 0xb3, 0x84, 0x6f, 0x86, 0xb0, 0x16, 0x6c, 0x23, 0x0c, 0xbf, 0x75, 0xf9, 0x38, 0xcf, 0x2e, 0xac, 0x17, + 0x79, 0x0e, 0xcd, 0x6d, 0x98, 0x52, 0x34, 0xb0, 0xe2, 0xc2, 0x4a, 0x33, 0x6e, 0xe9, 0xc1, 0x70, 0x01, 0x7d, 0xeb, + 0x63, 0xc1, 0xac, 0x93, 0x59, 0x5a, 0x44, 0x23, 0x06, 0x4d, 0x4f, 0xac, 0x2c, 0xb7, 0x4e, 0x60, 0xd0, 0x13, 0x58, + 0xb2, 0x82, 0xc3, 0xae, 0xf1, 0x6d, 0xb7, 0x43, 0x73, 0x41, 0xe1, 0x21, 0xbb, 0xe4, 0x21, 0x2f, 0x81, 0x31, 0x61, + 0x55, 0x14, 0x1a, 0x8e, 0x3b, 0x4f, 0xa0, 0x00, 0xc0, 0x26, 0x96, 0x75, 0xcc, 0xc6, 0x7a, 0x71, 0x3e, 0xdf, 0xda, + 0xd2, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0x62, 0xa1, 0xad, 0x27, 0x10, 0xaf, 0x91, 0xc8, 0xf5, 0xb8, 0x2f, 0xc9, 0x77, + 0x70, 0x95, 0x0e, 0xea, 0x63, 0x43, 0x65, 0xc9, 0xb3, 0x03, 0x9e, 0xc7, 0xe9, 0x19, 0x00, 0xa1, 0xd8, 0xc0, 0x68, + 0x52, 0x96, 0x62, 0xf1, 0xdf, 0x03, 0xd4, 0x61, 0x17, 0x47, 0xcf, 0xb8, 0x63, 0x17, 0xd4, 0xc3, 0x06, 0x40, 0x80, + 0xf4, 0xc0, 0x60, 0xbc, 0xc7, 0x03, 0xbe, 0x6d, 0xdb, 0xde, 0xb7, 0xae, 0x77, 0x81, 0x1c, 0xe4, 0xfb, 0x3e, 0xb1, + 0xaf, 0xe8, 0x1c, 0x87, 0x2d, 0x04, 0xda, 0x4f, 0x58, 0x7a, 0xc6, 0xc7, 0x3d, 0x7e, 0xd4, 0xec, 0x07, 0x0c, 0xa0, + 0x1a, 0xce, 0x06, 0xcc, 0x41, 0x7e, 0xf4, 0x0a, 0xdc, 0x3e, 0xdb, 0x0e, 0x4c, 0x81, 0x0b, 0xb3, 0x41, 0x38, 0xd6, + 0x96, 0xc6, 0x55, 0xb0, 0x29, 0xc0, 0x90, 0xcf, 0x6d, 0xd8, 0x61, 0xa7, 0x2c, 0x37, 0xe0, 0xd0, 0xcd, 0x3a, 0xb5, + 0x15, 0x9c, 0xc1, 0x0a, 0x41, 0x3f, 0x6b, 0x34, 0x4b, 0x07, 0x3c, 0x06, 0xc1, 0x65, 0x6f, 0x03, 0xb8, 0x62, 0xe5, + 0xf4, 0xc2, 0xd9, 0x6e, 0xe9, 0x3a, 0xb1, 0xbb, 0xcd, 0x8f, 0x8a, 0xed, 0x56, 0xdf, 0x43, 0x28, 0x35, 0xf1, 0x25, + 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0xb9, 0xde, 0x9e, 0x9f, 0xf7, 0xb8, 0xbf, 0xcc, 0xc7, 0x21, 0xf3, 0x27, 0xd1, + 0x14, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x40, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, 0x16, 0x70, 0x81, 0x20, + 0xb0, 0x67, 0x5f, 0x44, 0x83, 0x31, 0x6c, 0xf1, 0x8a, 0x70, 0x43, 0xb5, 0x1d, 0x06, 0x39, 0x8b, 0x38, 0x7b, 0x91, + 0x30, 0x7c, 0xc2, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0x15, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, 0xc1, 0x3c, 0x1d, 0xc1, + 0x24, 0xc0, 0xc5, 0xc5, 0xd6, 0x56, 0x8c, 0x2c, 0xb2, 0xcf, 0x61, 0xb5, 0x4e, 0x67, 0x9c, 0x01, 0xbd, 0xb0, 0x85, + 0x0d, 0xd4, 0xf6, 0x62, 0x9f, 0x03, 0x11, 0x9f, 0x65, 0x29, 0x87, 0xe1, 0x00, 0x5e, 0xcd, 0x41, 0x7e, 0x34, 0x9d, + 0xb2, 0x74, 0xf8, 0x6c, 0x1c, 0x27, 0x43, 0xa0, 0x46, 0x09, 0xf8, 0x26, 0x3c, 0x04, 0x3c, 0x01, 0x99, 0xe0, 0x66, + 0x8c, 0x68, 0xf9, 0x90, 0x91, 0x59, 0x68, 0xdb, 0x1d, 0x94, 0x40, 0x12, 0x0b, 0x94, 0x41, 0xb4, 0x70, 0x1f, 0x40, + 0xf4, 0x17, 0x2e, 0xdb, 0x0e, 0x63, 0xbd, 0x8c, 0x92, 0xc0, 0xef, 0x51, 0xd2, 0x00, 0xfd, 0x81, 0x10, 0xbc, 0x83, + 0x82, 0xeb, 0x4b, 0x29, 0x75, 0x22, 0xae, 0x30, 0x04, 0x02, 0x0c, 0x50, 0x82, 0x48, 0x1a, 0xbc, 0xcf, 0x92, 0xab, + 0x51, 0x9c, 0x24, 0x07, 0xb3, 0xe9, 0x34, 0xcb, 0xb9, 0xf7, 0x55, 0x38, 0xe7, 0x59, 0x85, 0x2b, 0x6d, 0xf2, 0xe2, + 0x22, 0xe6, 0x48, 0x50, 0x77, 0x3e, 0x88, 0x60, 0xa9, 0x9f, 0x66, 0x59, 0xc2, 0xa2, 0x14, 0xd0, 0xe0, 0x3d, 0xdb, + 0x0e, 0xd2, 0x59, 0x92, 0x74, 0x4e, 0x61, 0xd8, 0x4f, 0x1d, 0xaa, 0x16, 0x12, 0x3f, 0xa0, 0xef, 0xfb, 0x79, 0x1e, + 0x5d, 0x41, 0x43, 0x6c, 0x03, 0xec, 0x05, 0xab, 0xf5, 0xe5, 0xc1, 0xbb, 0xb7, 0xbe, 0x60, 0xfc, 0x78, 0x74, 0x05, + 0x80, 0x96, 0x95, 0xd4, 0x1c, 0xe5, 0xd9, 0x64, 0x61, 0x6a, 0xa4, 0x43, 0x1c, 0xf2, 0xce, 0x1a, 0x10, 0x62, 0x1a, + 0x19, 0x56, 0x89, 0x9b, 0x10, 0xbc, 0x25, 0x7e, 0x96, 0x95, 0xb8, 0x07, 0x7a, 0xf8, 0x25, 0x10, 0xc5, 0x30, 0xe5, + 0x2d, 0xd0, 0xe6, 0x57, 0xf3, 0x38, 0x24, 0x38, 0xa7, 0xa8, 0x7f, 0x11, 0xc6, 0x41, 0x04, 0xb3, 0xcf, 0xc5, 0x80, + 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xac, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x16, 0x86, 0xa0, 0x60, 0x38, 0x3c, + 0xb8, 0xde, 0xd7, 0xe1, 0x3c, 0x52, 0xf8, 0xa0, 0x86, 0xc2, 0xfd, 0x15, 0x08, 0x39, 0x81, 0x9a, 0xec, 0x1c, 0xf4, + 0x20, 0xc0, 0xf9, 0x95, 0x07, 0xfa, 0x3f, 0x41, 0x28, 0x36, 0x5a, 0x1e, 0x68, 0xd0, 0x67, 0xe3, 0x28, 0x3d, 0x63, + 0xc3, 0x60, 0xcc, 0x4b, 0x29, 0x79, 0xf7, 0x2d, 0x58, 0x63, 0x60, 0xa7, 0xc2, 0x7a, 0x79, 0xf8, 0xe6, 0xb5, 0x5c, + 0xb9, 0x9a, 0x30, 0x86, 0x45, 0x9a, 0x81, 0x5a, 0x05, 0xb1, 0x2d, 0xc5, 0xf1, 0x0b, 0x2d, 0xbd, 0x45, 0x49, 0x5c, + 0x7c, 0x9c, 0x82, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, 0x39, 0xcc, 0x27, 0x2a, 0x86, 0xba, + 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x63, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x07, 0x56, 0x34, 0x1c, 0xbe, 0x4a, 0x63, + 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x8e, 0x3c, 0xc6, 0x3a, 0x72, 0x11, 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, + 0xc8, 0x6e, 0x10, 0x31, 0x84, 0xb4, 0x4c, 0xc2, 0xa3, 0xbe, 0x04, 0x2f, 0xf1, 0xa7, 0xb3, 0x62, 0x8c, 0x84, 0x95, + 0x03, 0xa3, 0x20, 0xcf, 0x4e, 0x0b, 0x96, 0x9f, 0xb3, 0xa1, 0xe6, 0x80, 0x02, 0xb0, 0xa2, 0xe6, 0x60, 0xbc, 0xd0, + 0x8c, 0x8e, 0xd2, 0xa1, 0x1c, 0x86, 0xea, 0x98, 0x62, 0x96, 0x49, 0x66, 0xd6, 0x16, 0x8e, 0x96, 0x02, 0x8e, 0x30, + 0x2a, 0xa4, 0x24, 0x28, 0x42, 0x85, 0xe1, 0x18, 0xa4, 0x10, 0x73, 0x6b, 0xdb, 0x5c, 0x69, 0xb2, 0x17, 0x33, 0x52, + 0x09, 0x05, 0x74, 0x84, 0x8d, 0x4c, 0x90, 0x16, 0x2e, 0xec, 0x2a, 0x90, 0xf2, 0x12, 0x5c, 0x21, 0x45, 0x94, 0x99, + 0x83, 0x0c, 0x10, 0x7e, 0x4d, 0xba, 0x90, 0xf9, 0xd8, 0x82, 0x21, 0x1b, 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, + 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0x6f, 0x83, 0xf9, 0x69, 0xb6, 0x3f, 0x18, 0xb0, 0xa2, 0xc8, + 0xf2, 0xad, 0xad, 0x0d, 0x6a, 0xbf, 0xce, 0xd0, 0x02, 0x4a, 0xba, 0x5a, 0xd6, 0xd9, 0x05, 0x69, 0x70, 0x53, 0xad, + 0x28, 0x9d, 0x1e, 0xd8, 0xc7, 0xc7, 0x20, 0xb3, 0x3d, 0x49, 0x06, 0xa0, 0xfa, 0xb2, 0xe1, 0x27, 0xec, 0x99, 0x3a, + 0x65, 0x56, 0xda, 0x97, 0x4e, 0x1d, 0x24, 0x0f, 0x86, 0x75, 0x4b, 0x63, 0x41, 0x57, 0x0e, 0x8d, 0xab, 0x21, 0x15, + 0xe4, 0xfc, 0x8c, 0x54, 0xb6, 0xb1, 0x8c, 0x60, 0xb5, 0x95, 0x1e, 0x91, 0x5e, 0x61, 0x93, 0x13, 0xa0, 0x47, 0xbc, + 0xdf, 0x91, 0xf5, 0x61, 0x21, 0x28, 0x97, 0xb3, 0x9f, 0x67, 0xac, 0xe0, 0x82, 0x75, 0x61, 0xdc, 0x1c, 0xc6, 0x2d, + 0x97, 0xac, 0xc3, 0x9a, 0xed, 0xb8, 0x0a, 0xb6, 0x77, 0x53, 0xd4, 0x63, 0x05, 0x72, 0xf2, 0xcd, 0xec, 0x44, 0xf6, + 0x84, 0x7b, 0x7d, 0xfd, 0xb5, 0x1a, 0xa4, 0x5a, 0x4a, 0x6d, 0x03, 0x2d, 0xac, 0x89, 0xad, 0x9a, 0x0c, 0x6d, 0x57, + 0x2a, 0xd4, 0x8d, 0x56, 0xa7, 0xc6, 0x07, 0xb0, 0xe7, 0x9a, 0x9a, 0xa5, 0x2b, 0x63, 0xfb, 0xbd, 0xa2, 0xe9, 0x3b, + 0x31, 0x32, 0x59, 0xa3, 0xfc, 0x76, 0xee, 0x51, 0x3b, 0x1e, 0xda, 0x2e, 0xd5, 0x55, 0x82, 0x61, 0x56, 0x17, 0x0c, + 0x8b, 0x50, 0x4f, 0x75, 0x17, 0x5b, 0x33, 0x15, 0x0f, 0xd5, 0x5a, 0x2b, 0x07, 0x82, 0x85, 0x47, 0x60, 0x9c, 0xac, + 0xf4, 0x0f, 0xde, 0x46, 0x13, 0x86, 0x14, 0xf5, 0xd6, 0x35, 0x90, 0x0e, 0x04, 0x34, 0xe9, 0x2f, 0xaa, 0x37, 0xe6, + 0x0a, 0xab, 0xa9, 0xbe, 0xbf, 0x62, 0xb0, 0x22, 0xc0, 0xbe, 0x2e, 0x57, 0x2c, 0x11, 0xe9, 0x4d, 0xc9, 0xce, 0x8a, + 0x3e, 0xa2, 0x4c, 0xac, 0x09, 0x29, 0x78, 0x40, 0x1e, 0x96, 0x7f, 0x61, 0xe1, 0x54, 0x2b, 0x85, 0x23, 0x43, 0x99, + 0x02, 0x74, 0x26, 0x25, 0x00, 0xe2, 0x92, 0x3e, 0x6b, 0x1b, 0x0b, 0xc9, 0x76, 0x80, 0x7c, 0xe0, 0x8f, 0x92, 0x88, + 0x3b, 0xad, 0x9d, 0xa6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, 0xf7, 0x15, 0x2a, 0x1c, 0x51, 0x89, 0x5d, + 0xe6, 0x83, 0x51, 0x34, 0x8e, 0x47, 0xdc, 0x49, 0x90, 0x79, 0xdc, 0x92, 0x25, 0xa0, 0x64, 0xf4, 0xbe, 0x02, 0x65, + 0xc1, 0x84, 0x74, 0x11, 0xd5, 0x4a, 0xa0, 0x31, 0x05, 0x29, 0x49, 0x29, 0xd2, 0x82, 0x0a, 0x02, 0x43, 0xa8, 0x74, + 0x14, 0x47, 0x81, 0x7e, 0x8b, 0x7b, 0x62, 0xd0, 0x60, 0xc9, 0xa2, 0x8c, 0x7b, 0xf1, 0x72, 0x21, 0xa8, 0x61, 0x9f, + 0x67, 0xaf, 0xb3, 0x0b, 0x96, 0x3f, 0x8b, 0x10, 0xf6, 0x40, 0x74, 0x2f, 0x41, 0xd2, 0x93, 0x40, 0xe7, 0x1d, 0xc5, + 0x2b, 0xe7, 0x84, 0x34, 0x2c, 0xc4, 0x24, 0x46, 0x45, 0x08, 0x76, 0x0b, 0xd1, 0x3e, 0xc5, 0x2d, 0x45, 0x7b, 0x0f, + 0x55, 0x09, 0xd7, 0xbc, 0xb5, 0xff, 0xba, 0xce, 0x5b, 0x30, 0xc2, 0x54, 0x71, 0x6b, 0x7d, 0xc7, 0x82, 0x7b, 0x21, + 0x74, 0xb3, 0x23, 0x79, 0xcb, 0x50, 0x66, 0xa0, 0x3f, 0xae, 0xaf, 0x2b, 0x23, 0x1d, 0x94, 0xa9, 0x96, 0xe6, 0x08, + 0x81, 0xd8, 0x12, 0x6e, 0x09, 0xca, 0x08, 0x0d, 0xaf, 0x3c, 0x4b, 0x12, 0x43, 0x17, 0x79, 0x71, 0xc7, 0x59, 0x50, + 0x47, 0x00, 0xc5, 0xa4, 0xa6, 0x91, 0x7a, 0x2c, 0xd0, 0x15, 0xa8, 0x94, 0x94, 0x36, 0xf2, 0xaa, 0xb5, 0x11, 0x10, + 0xa7, 0x43, 0x96, 0x0b, 0x07, 0x4d, 0xea, 0x50, 0x98, 0x30, 0x05, 0x86, 0x66, 0x43, 0xf4, 0x1c, 0x24, 0x02, 0x60, + 0x9e, 0xf8, 0xe3, 0xac, 0xe0, 0xba, 0xce, 0x84, 0x3e, 0xbe, 0xbe, 0x8e, 0x85, 0xbf, 0x88, 0x0c, 0x90, 0xb3, 0x49, + 0x76, 0xce, 0x56, 0x40, 0xdd, 0x51, 0x83, 0x99, 0x20, 0x1b, 0xc3, 0x80, 0x12, 0x05, 0xd5, 0x32, 0x4d, 0x62, 0xb0, + 0xf4, 0x75, 0x03, 0x1f, 0x0c, 0x3a, 0x76, 0x89, 0x32, 0xc2, 0xed, 0x76, 0xbb, 0x4d, 0xaf, 0xe5, 0x96, 0x82, 0xe0, + 0xf3, 0x25, 0x8a, 0xde, 0xa0, 0x1f, 0xa5, 0x09, 0xbe, 0x4a, 0x16, 0x30, 0xd7, 0x50, 0x8a, 0xc2, 0x4f, 0x62, 0x9e, + 0x14, 0xc4, 0xae, 0x37, 0x84, 0x41, 0x39, 0x53, 0x82, 0x1b, 0x4d, 0x5c, 0xb1, 0x6d, 0x3f, 0x68, 0xb2, 0x69, 0x76, + 0x52, 0x3b, 0x4c, 0x2d, 0x8c, 0x5c, 0xf3, 0x42, 0x7b, 0xc0, 0xe6, 0xf2, 0x90, 0x4d, 0x8f, 0xd5, 0xc0, 0xeb, 0x00, + 0xa1, 0xf0, 0x74, 0x9d, 0x25, 0x94, 0xaa, 0xce, 0x52, 0x88, 0xeb, 0x0d, 0xf4, 0x51, 0x81, 0xb9, 0x8a, 0x04, 0x07, + 0x52, 0x20, 0x30, 0xf4, 0xc8, 0xc4, 0x7a, 0x3d, 0x83, 0xe5, 0x39, 0x8d, 0x06, 0x9f, 0x34, 0xb8, 0x15, 0xef, 0x2d, + 0xb2, 0x81, 0xb3, 0x50, 0x12, 0x1a, 0xe2, 0xca, 0xc4, 0x5b, 0x49, 0xe8, 0xda, 0x46, 0x01, 0x87, 0x6c, 0x89, 0xed, + 0x17, 0x17, 0x7a, 0x91, 0xdb, 0x25, 0x7b, 0x28, 0xff, 0xa9, 0xe2, 0x92, 0xf5, 0x2c, 0xc7, 0x94, 0x34, 0x60, 0x8a, + 0xf1, 0x60, 0x69, 0x16, 0x20, 0x01, 0xbe, 0x2b, 0x87, 0x71, 0xb1, 0x9e, 0x04, 0x7f, 0x28, 0x98, 0xcf, 0x8d, 0x99, + 0x6e, 0x85, 0x54, 0x4b, 0x38, 0x69, 0x06, 0x6b, 0xd0, 0xa4, 0xf1, 0xa0, 0x44, 0xcd, 0x57, 0x68, 0xa8, 0x10, 0xc7, + 0x9f, 0x89, 0x2a, 0x34, 0xc1, 0x10, 0x8c, 0xc2, 0xcb, 0x25, 0xc3, 0xa5, 0xcb, 0xa2, 0x45, 0xca, 0xd4, 0x98, 0x54, + 0xaa, 0x66, 0xb9, 0x14, 0x0c, 0x2c, 0xda, 0xad, 0xbe, 0xb4, 0xc4, 0x95, 0xc8, 0xcd, 0x42, 0x2d, 0x4c, 0x72, 0xe5, + 0x4d, 0x38, 0x05, 0xfa, 0x5d, 0xca, 0x7a, 0x37, 0xf1, 0x29, 0x14, 0x3e, 0x85, 0x6f, 0xf8, 0x50, 0x26, 0x6f, 0xe7, + 0x3d, 0x30, 0xf7, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, 0x74, 0x41, 0xa0, 0x48, 0x36, 0xc9, 0x7a, + 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xea, 0x8a, 0x0d, 0x52, 0xf3, 0x4a, 0x53, 0x2f, 0x73, 0x17, 0xec, 0xf7, + 0xb2, 0x94, 0x74, 0x62, 0x82, 0x32, 0xb1, 0x77, 0x13, 0x6d, 0xbc, 0x2c, 0x4c, 0x85, 0xf5, 0x2b, 0x8c, 0x9d, 0x1a, + 0x85, 0x32, 0x29, 0x02, 0x71, 0x6c, 0x7c, 0xac, 0x2c, 0x83, 0xd4, 0x5f, 0x61, 0x4f, 0x01, 0x28, 0x09, 0x2c, 0xbe, + 0xa6, 0x92, 0x17, 0x85, 0x75, 0x3a, 0x6e, 0x10, 0x1d, 0x2b, 0x11, 0x5a, 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, + 0x25, 0x34, 0x29, 0x59, 0xf4, 0x8a, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, 0x25, 0xbd, 0x84, 0x1c, 0xd2, 0x65, 0xa2, + 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x09, 0x89, 0x96, 0xf5, 0xc3, 0x08, 0xc5, 0x86, 0x58, 0x8b, 0x25, 0x42, 0x2e, 0xda, + 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0x16, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, + 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x1e, 0x73, 0xd7, 0x91, 0x06, 0x2f, 0xac, 0x59, 0x4f, 0xc9, 0xde, + 0xfd, 0xd7, 0xd8, 0x8a, 0xec, 0xcf, 0xaa, 0xa4, 0xf2, 0x14, 0x6a, 0x9c, 0x5b, 0x5f, 0xa7, 0x5a, 0x68, 0x51, 0x55, + 0x1c, 0x18, 0x52, 0xfd, 0x40, 0x29, 0xec, 0x0a, 0xe5, 0x03, 0x39, 0x74, 0xec, 0xba, 0x6e, 0x50, 0x90, 0xf3, 0xb2, + 0xb1, 0xca, 0x85, 0xdc, 0xda, 0x32, 0x7d, 0xa6, 0x73, 0x3d, 0xfc, 0x33, 0x07, 0x95, 0x73, 0x71, 0x95, 0x92, 0x05, + 0xf3, 0x4c, 0xa9, 0xa3, 0x25, 0x07, 0xb4, 0xd9, 0x41, 0x4f, 0x3b, 0xba, 0x88, 0x62, 0x6e, 0xe9, 0x51, 0x84, 0xa7, + 0x8d, 0xf2, 0x49, 0x1a, 0x1d, 0x80, 0x17, 0x9a, 0x90, 0xe4, 0x84, 0x9b, 0xb6, 0x68, 0x31, 0x18, 0x33, 0x0c, 0x81, + 0x2b, 0x7b, 0xc2, 0x94, 0x3d, 0x1b, 0x88, 0xb7, 0x1c, 0x78, 0x35, 0xec, 0xe5, 0x62, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, + 0x04, 0xb2, 0x6d, 0xa2, 0xea, 0xca, 0x85, 0x67, 0x29, 0x22, 0x31, 0xc2, 0xb6, 0x6a, 0x6c, 0x69, 0xeb, 0x77, 0x16, + 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x05, 0x3d, 0xac, 0xdc, 0x1c, 0x6e, 0x3a, 0xf2, 0x62, 0x05, 0xdd, 0x8e, + 0x08, 0x0a, 0x81, 0x13, 0xa1, 0xec, 0x41, 0xcd, 0x0d, 0x44, 0x4a, 0xa6, 0xb4, 0x6a, 0x36, 0x4b, 0x86, 0x12, 0x58, + 0x70, 0x61, 0x99, 0xe4, 0xa3, 0x8b, 0x38, 0x49, 0xaa, 0xd2, 0x3f, 0x54, 0xc0, 0x8b, 0x61, 0x6f, 0x13, 0xed, 0x02, + 0xa3, 0x99, 0x02, 0xc1, 0xd5, 0x46, 0xd8, 0x47, 0xc7, 0xad, 0xd6, 0x5d, 0x44, 0x1c, 0x99, 0x19, 0x8d, 0xf8, 0x88, + 0x36, 0x64, 0xc9, 0x34, 0x6b, 0xef, 0xbf, 0xc0, 0x90, 0x9a, 0x81, 0x0f, 0xaa, 0x33, 0x2a, 0xfe, 0x55, 0xf6, 0xd4, + 0xaf, 0x44, 0xef, 0x56, 0xd5, 0xb5, 0x18, 0x50, 0x51, 0x81, 0x0f, 0x33, 0xc4, 0xd2, 0x54, 0x81, 0x80, 0x5c, 0x0f, + 0xeb, 0x70, 0xb7, 0x46, 0x1a, 0x2c, 0x28, 0x05, 0xd6, 0x5a, 0xd9, 0xbd, 0xbe, 0x2d, 0x98, 0x43, 0xa1, 0x70, 0xd1, + 0xff, 0x59, 0x36, 0x99, 0xa2, 0x65, 0xb6, 0xc0, 0xd4, 0xd0, 0xe0, 0xe3, 0x42, 0x7d, 0xb9, 0xa2, 0xac, 0xd6, 0x87, + 0x76, 0x64, 0x8d, 0x9f, 0xb4, 0xa3, 0x0c, 0x0e, 0xd5, 0x4c, 0x17, 0xd5, 0xed, 0xe6, 0x45, 0x11, 0xb3, 0x8a, 0xc7, + 0x7d, 0xd2, 0xdb, 0xda, 0x9a, 0xf4, 0x34, 0x0d, 0x48, 0x26, 0x49, 0x86, 0x37, 0x19, 0xa0, 0xac, 0x88, 0x33, 0x2f, + 0x17, 0xc8, 0x37, 0x2f, 0x4b, 0x5c, 0xbf, 0xef, 0x3b, 0xfb, 0x35, 0xcf, 0xda, 0xdb, 0x5f, 0xef, 0x22, 0x57, 0x75, + 0xd2, 0x83, 0x3c, 0xea, 0x43, 0xd1, 0x92, 0x4d, 0x19, 0xce, 0x27, 0xd9, 0x90, 0x05, 0x36, 0x74, 0x4f, 0xed, 0x52, + 0x6e, 0x9a, 0x08, 0x36, 0x07, 0xf8, 0x7f, 0xf3, 0x0f, 0xf5, 0x48, 0x6a, 0xb0, 0x0f, 0x2c, 0xa0, 0xcd, 0x85, 0x2f, + 0xc3, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x43, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, 0x01, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, + 0x7d, 0xd9, 0xfb, 0x32, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x2d, 0xbf, 0xe9, 0xb7, 0x6c, 0x15, 0x11, 0xfb, 0xc9, + 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x04, 0x4d, 0x56, 0x78, 0x03, 0x1e, 0xfe, 0xd4, 0xfb, 0x49, 0xb9, 0xd4, + 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe0, 0x79, 0xa4, 0xed, 0xcd, 0x45, 0x05, 0xc6, 0x15, 0x29, 0x2e, + 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xe6, 0xe6, 0xdc, 0x79, 0x13, 0xf1, 0xb1, 0x9f, 0x47, 0xe9, + 0x30, 0x9b, 0x38, 0xee, 0xb6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0x67, 0x6e, 0xb9, 0x79, 0xe2, 0x0d, 0x79, 0x68, + 0xf7, 0xec, 0xed, 0x63, 0xef, 0x90, 0x87, 0x27, 0x7b, 0x9b, 0xf3, 0x21, 0x2f, 0xbb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, + 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7b, 0x29, 0xc1, 0x00, 0x76, 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, + 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0x7b, 0x43, 0x3b, 0xab, 0x5b, 0x5b, 0x95, 0x9a, 0xaf, + 0x4a, 0xbd, 0x19, 0x0f, 0x6b, 0x9e, 0xba, 0xf7, 0x92, 0x8e, 0x56, 0xea, 0x1b, 0x79, 0x26, 0x82, 0x36, 0xcb, 0x76, + 0x82, 0x63, 0x6c, 0xf1, 0xd5, 0xdb, 0xfa, 0x48, 0x44, 0x29, 0xfc, 0x18, 0xac, 0x97, 0x08, 0xd4, 0x37, 0x38, 0x38, + 0xde, 0x61, 0xb8, 0xb3, 0xe7, 0xf4, 0x02, 0x67, 0xa3, 0xd1, 0xb8, 0xfe, 0x61, 0xe7, 0xe8, 0xc7, 0xa8, 0xf1, 0xcb, + 0x7e, 0xe3, 0xfb, 0xbe, 0x7b, 0xed, 0xfc, 0xb0, 0xd3, 0x3b, 0x92, 0x4f, 0x47, 0x3f, 0x76, 0x7f, 0x28, 0xfa, 0x7f, + 0x12, 0x85, 0x9b, 0xae, 0xbb, 0x73, 0xe6, 0x4d, 0x79, 0xb8, 0xd3, 0x68, 0x74, 0xe1, 0xdb, 0x19, 0x7c, 0xc3, 0xcf, + 0x53, 0xf8, 0xb8, 0x3e, 0xb2, 0xfe, 0xc3, 0x0f, 0xe9, 0x7f, 0xfc, 0x21, 0xef, 0xe3, 0x98, 0x47, 0x3f, 0xfe, 0x50, + 0xd8, 0xf7, 0xbb, 0xe1, 0x4e, 0x7f, 0xdb, 0x75, 0x74, 0xcd, 0x9f, 0xc2, 0xea, 0x2b, 0xb4, 0x3a, 0xfa, 0x51, 0x3e, + 0xd9, 0xf7, 0x4f, 0xf6, 0xba, 0x61, 0xff, 0xda, 0xb1, 0xaf, 0xef, 0xbb, 0xd7, 0xae, 0x7b, 0xbd, 0x89, 0xf3, 0x9c, + 0xc3, 0xe8, 0xf7, 0xe1, 0x73, 0x04, 0x9f, 0x36, 0x7c, 0x6e, 0xc2, 0xe7, 0x8f, 0xd0, 0x4d, 0xc4, 0xdf, 0xae, 0x29, + 0x16, 0x72, 0x8d, 0x07, 0x16, 0x11, 0xac, 0x82, 0xbb, 0xb9, 0x13, 0x7b, 0x13, 0x22, 0x1a, 0xec, 0x43, 0xdf, 0xf7, + 0x31, 0x4c, 0xea, 0xcc, 0x8f, 0x37, 0x61, 0xd1, 0x91, 0x73, 0x36, 0x03, 0xee, 0x89, 0xc8, 0x41, 0x11, 0x30, 0x71, + 0xb6, 0x5a, 0xe0, 0xe1, 0xaa, 0x37, 0x0c, 0x27, 0xdc, 0x01, 0xa3, 0xe0, 0x03, 0xc7, 0x2f, 0x6d, 0xd7, 0x7b, 0x21, + 0xcf, 0x0c, 0x71, 0x9f, 0x0b, 0xd6, 0x4a, 0x33, 0x61, 0xd2, 0xd8, 0xae, 0x37, 0x5d, 0x51, 0x09, 0xdb, 0x3a, 0x3d, + 0x83, 0xba, 0x63, 0x11, 0xa3, 0xfe, 0x96, 0x45, 0x9f, 0x70, 0x4b, 0xbe, 0x35, 0x0e, 0x81, 0x97, 0x2c, 0xf9, 0x45, + 0xa3, 0xd1, 0xb0, 0x11, 0x85, 0x3b, 0xf6, 0x94, 0xc1, 0x0c, 0x4b, 0x26, 0x22, 0x23, 0xa5, 0x29, 0x2c, 0x5b, 0x98, + 0xfc, 0x7d, 0x94, 0xf3, 0xcd, 0xca, 0xb0, 0x0d, 0xeb, 0x96, 0xec, 0x82, 0xa5, 0x7f, 0x87, 0x29, 0xd0, 0xb4, 0xa4, + 0xf3, 0x0f, 0x73, 0xfc, 0x30, 0x23, 0xb4, 0x3e, 0x38, 0x0c, 0x3c, 0xf4, 0x02, 0xe4, 0x8e, 0xe8, 0xe7, 0xbc, 0x47, + 0x35, 0x06, 0xff, 0xcb, 0x30, 0x83, 0x27, 0xe6, 0xc3, 0x10, 0xcd, 0xbc, 0xd4, 0xc1, 0xad, 0x0c, 0xc5, 0xfd, 0x2b, + 0xdc, 0x19, 0x59, 0xe9, 0x1d, 0x84, 0x6a, 0xc7, 0x1c, 0xe6, 0x8c, 0x7d, 0x1b, 0x25, 0x9f, 0x58, 0xee, 0x5c, 0x7a, + 0xad, 0xf6, 0x67, 0xd4, 0xd9, 0x43, 0xdb, 0xec, 0x4d, 0x75, 0x8c, 0xa6, 0xcd, 0x02, 0x79, 0x44, 0xd8, 0x68, 0x79, + 0x28, 0x31, 0x88, 0x04, 0xb9, 0x97, 0x86, 0x6d, 0xe2, 0x70, 0x7b, 0xaf, 0x38, 0x3f, 0xeb, 0xda, 0x81, 0x6d, 0x83, + 0xc5, 0x7f, 0x48, 0x61, 0x2b, 0x61, 0x58, 0x34, 0x3b, 0x6c, 0x2f, 0xee, 0xb0, 0xed, 0xed, 0x2a, 0xe0, 0x84, 0x07, + 0xe9, 0xd4, 0x3d, 0xf1, 0x22, 0x6f, 0x1c, 0xc2, 0x80, 0x03, 0x68, 0x86, 0x5d, 0x3a, 0x83, 0xbd, 0x58, 0x4e, 0x03, + 0xb2, 0x3e, 0xf3, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, 0x0e, 0xc0, 0xd8, 0xcf, 0x7c, 0x76, 0xc9, 0x06, 0xca, + 0xce, 0x00, 0x42, 0x45, 0x6e, 0xc7, 0x1d, 0x84, 0x46, 0x33, 0x98, 0x3b, 0x0c, 0x0f, 0x7b, 0x36, 0xec, 0x25, 0xd8, + 0x95, 0x61, 0x74, 0xd4, 0xea, 0xf7, 0xb2, 0x70, 0xca, 0x03, 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0x6a, 0xf7, 0x7b, + 0xce, 0x26, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x84, 0x11, 0x8a, 0x3c, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0x4e, 0x1d, + 0x7b, 0x6f, 0xc7, 0xde, 0xc6, 0x52, 0xcf, 0x06, 0xf6, 0x02, 0x0a, 0x86, 0xa7, 0xae, 0xd9, 0x79, 0xb7, 0x8f, 0xa0, + 0x62, 0x21, 0x4e, 0x7e, 0xda, 0xb3, 0xbb, 0x62, 0xea, 0x26, 0x0c, 0x9a, 0xc9, 0xe5, 0xc7, 0x15, 0x3d, 0x24, 0x54, + 0x55, 0x57, 0x05, 0x1d, 0x94, 0xb5, 0x03, 0x67, 0x6c, 0x22, 0xd1, 0xc0, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, + 0x30, 0xa9, 0xd1, 0x6d, 0xb7, 0xdf, 0x3b, 0x0d, 0xee, 0xdb, 0xf7, 0xd5, 0xc3, 0x08, 0x90, 0xe1, 0x62, 0xfa, 0x11, + 0x48, 0x3b, 0xfc, 0x3c, 0xe7, 0x80, 0xe4, 0x29, 0x15, 0x4d, 0x65, 0xd1, 0x19, 0x16, 0x1d, 0x06, 0x08, 0xaa, 0x97, + 0x6b, 0xeb, 0x4f, 0xac, 0xc9, 0x30, 0x24, 0xd8, 0xc1, 0x16, 0x3a, 0x62, 0xdb, 0xad, 0x3e, 0x9e, 0x37, 0xe4, 0xbc, + 0xf8, 0x36, 0xe6, 0xa0, 0x12, 0x76, 0xba, 0xb6, 0xdb, 0xb3, 0x2d, 0x5c, 0xda, 0x4e, 0xba, 0x1d, 0x0a, 0x0a, 0xc7, + 0xdb, 0x87, 0x3c, 0x18, 0x77, 0xc3, 0x66, 0xcf, 0x29, 0x64, 0xb8, 0x11, 0xcf, 0x2d, 0x85, 0x04, 0x6f, 0x7a, 0x63, + 0x10, 0xe8, 0xc8, 0xb9, 0x9b, 0xf6, 0xb6, 0x2a, 0x84, 0xa2, 0xe3, 0xed, 0xa1, 0x1b, 0xc4, 0xf0, 0xe1, 0x34, 0x90, + 0x69, 0xc6, 0xba, 0xaf, 0xd2, 0xcc, 0xcc, 0x0d, 0x86, 0xca, 0x22, 0x4f, 0xc2, 0x74, 0xdb, 0xc1, 0x08, 0x2d, 0x48, + 0xda, 0xbd, 0x1e, 0xc0, 0xb0, 0xed, 0x28, 0x4e, 0xdb, 0x51, 0xac, 0xa6, 0xec, 0xf3, 0x23, 0xbd, 0x1c, 0x03, 0xde, + 0x1b, 0xa8, 0xf3, 0x58, 0xd4, 0x3e, 0x00, 0x56, 0x90, 0x78, 0x45, 0x5f, 0x9d, 0x79, 0xbd, 0xac, 0x9d, 0x6f, 0xcd, + 0x95, 0x28, 0xe2, 0x9e, 0x21, 0xa1, 0x58, 0xa9, 0xdd, 0x30, 0x61, 0x6e, 0x4f, 0x91, 0x18, 0x9a, 0xe5, 0x43, 0xd8, + 0x63, 0xa1, 0x0a, 0xb0, 0x67, 0xe6, 0xb6, 0x48, 0xc2, 0xaa, 0xb9, 0x77, 0x04, 0xac, 0xdd, 0x0f, 0xdf, 0x08, 0x77, + 0xaa, 0xa3, 0xa2, 0xf9, 0x2c, 0x09, 0x5f, 0x2e, 0x1c, 0x17, 0x47, 0x78, 0x22, 0x74, 0xe0, 0x0f, 0x66, 0x39, 0xc8, + 0x03, 0xfe, 0x16, 0x2c, 0x83, 0x50, 0x36, 0x45, 0x47, 0x0f, 0x8f, 0x80, 0x3d, 0x42, 0x7c, 0x21, 0x6c, 0x6e, 0x54, + 0xa3, 0x45, 0x49, 0xc6, 0x0b, 0x1d, 0x0c, 0x77, 0x98, 0x74, 0xed, 0x51, 0x30, 0xc8, 0x13, 0x63, 0x07, 0xcf, 0xfc, + 0xfd, 0x01, 0x56, 0xe3, 0x04, 0x85, 0x5b, 0xd2, 0x6e, 0xab, 0xc4, 0xdf, 0x81, 0x9f, 0x82, 0x04, 0xc7, 0x3a, 0xf0, + 0xb3, 0xb6, 0xb6, 0x12, 0x89, 0xd4, 0x5e, 0xd6, 0xa1, 0x93, 0x08, 0x8c, 0x07, 0x17, 0x7e, 0x0a, 0xd5, 0x48, 0x22, + 0x2a, 0x22, 0x0b, 0xd4, 0x3c, 0x55, 0xab, 0xe0, 0x3b, 0x32, 0x23, 0xf0, 0x8c, 0x92, 0x5c, 0xd0, 0x50, 0xd4, 0x8d, + 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, + 0xb1, 0x11, 0x2b, 0x1f, 0x1f, 0xa5, 0xdb, 0xdb, 0x7d, 0x71, 0x6e, 0x41, 0x8c, 0xc3, 0x8c, 0xe8, 0x6a, 0x5c, 0x01, + 0x50, 0x9f, 0xce, 0x89, 0xeb, 0x81, 0x69, 0xc5, 0x9a, 0x2e, 0xc5, 0x3e, 0x39, 0xcc, 0x00, 0x14, 0xdc, 0x71, 0x8e, + 0xfc, 0xde, 0x9f, 0xfb, 0xe0, 0x1e, 0xfb, 0x7f, 0x72, 0x77, 0x94, 0xa0, 0xe9, 0xc8, 0x33, 0xc5, 0x39, 0x9d, 0xb1, + 0xb6, 0x3c, 0x8a, 0x8d, 0x06, 0x20, 0xf5, 0x00, 0x03, 0xd0, 0xe6, 0x20, 0x13, 0x2a, 0x0e, 0x42, 0x8e, 0x0a, 0x6c, + 0x1f, 0x37, 0x3f, 0xc3, 0x9d, 0xfd, 0x9c, 0x07, 0x60, 0xc1, 0xa8, 0xa7, 0xd7, 0xf0, 0xf4, 0x67, 0xfd, 0xf4, 0x13, + 0x0f, 0x7e, 0x29, 0x65, 0xe8, 0xbe, 0x36, 0xc5, 0x23, 0x35, 0x45, 0x29, 0x96, 0xc8, 0xa0, 0x21, 0x77, 0x97, 0x63, + 0x36, 0xcc, 0x2d, 0x81, 0x18, 0x4a, 0x74, 0x81, 0x8d, 0x16, 0x9d, 0x21, 0x71, 0x5d, 0x93, 0x14, 0x46, 0x2e, 0x81, + 0x89, 0x70, 0xc5, 0xb7, 0x48, 0x4f, 0xd6, 0x6d, 0xba, 0xf3, 0x5a, 0x5b, 0xb2, 0xef, 0xd8, 0x64, 0xca, 0xaf, 0x0e, + 0x48, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0x37, 0x3b, 0xf1, 0x1e, 0xeb, 0xc4, 0x20, 0xd5, 0x0b, 0xc5, 0x62, + 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, 0xab, 0xa1, 0xd7, 0x96, 0xe8, 0x6d, 0x6f, 0x03, 0x82, 0x1d, + 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, + 0x21, 0x77, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, 0xb0, 0x03, 0x98, 0x11, 0x97, 0x37, 0x5a, 0x22, 0x3a, 0x2c, + 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0xb7, 0x5b, 0x2e, 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, + 0xd6, 0x54, 0x2a, 0xf3, 0xed, 0xed, 0xb2, 0x7e, 0x54, 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0x72, 0x31, 0x1b, 0x84, + 0x03, 0x11, 0x13, 0x28, 0xd0, 0xd2, 0xca, 0x8a, 0x01, 0x86, 0x94, 0xe5, 0x28, 0x9f, 0x42, 0xee, 0xc5, 0x65, 0xa9, + 0x53, 0x5f, 0x9e, 0xc9, 0xa0, 0x23, 0x9e, 0x7a, 0x92, 0xb1, 0x02, 0xac, 0xe6, 0x65, 0x5e, 0x42, 0x4b, 0x04, 0x98, + 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, 0x2c, 0x51, 0xc6, 0x67, 0x1e, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, + 0x62, 0x5f, 0xb9, 0x32, 0x3a, 0xf2, 0xa3, 0xa2, 0x1f, 0x50, 0xfd, 0x4c, 0x4a, 0xb0, 0x71, 0xf8, 0x11, 0xd8, 0xa8, + 0x72, 0x3c, 0x49, 0x10, 0x3e, 0x8f, 0x73, 0x46, 0x9e, 0xc2, 0xa6, 0x84, 0x59, 0x9a, 0xb6, 0x91, 0x6a, 0x17, 0x99, + 0x41, 0x28, 0x17, 0xe6, 0x1f, 0x1b, 0x67, 0x17, 0x69, 0xb8, 0xd4, 0x1a, 0xcc, 0x8f, 0x77, 0x26, 0x40, 0xe9, 0xf5, + 0x75, 0x2a, 0x7c, 0xdc, 0x88, 0xec, 0x0d, 0x5d, 0x31, 0xee, 0x29, 0xa4, 0x02, 0x27, 0x22, 0x8b, 0x87, 0xce, 0x50, + 0x68, 0x84, 0x43, 0x3a, 0x45, 0x2e, 0x5c, 0x63, 0xd3, 0x17, 0x3d, 0xed, 0x1b, 0x65, 0xa1, 0x93, 0x80, 0x10, 0x10, + 0xb8, 0x1b, 0xd6, 0x54, 0xd6, 0xcb, 0x82, 0x84, 0x4a, 0xd1, 0xcf, 0x01, 0xfc, 0xc3, 0x48, 0x52, 0x00, 0xec, 0x87, + 0x6a, 0xa4, 0x88, 0xb2, 0x2c, 0x70, 0x01, 0x68, 0xae, 0x03, 0x5c, 0x09, 0x5f, 0x18, 0xa8, 0x30, 0x3d, 0xcd, 0xca, + 0x4a, 0xa1, 0x44, 0x9e, 0xae, 0x48, 0x59, 0x23, 0x99, 0x7c, 0x8e, 0x0e, 0x9f, 0xf2, 0xae, 0xdf, 0x4a, 0x3c, 0x74, + 0xc1, 0x73, 0x58, 0x56, 0xf5, 0xfd, 0x4d, 0xc8, 0xc8, 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xff, + 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, 0x0c, 0xcb, 0xcb, 0x69, 0x15, 0xa6, 0x20, 0xe0, 0xe6, 0x2c, + 0x09, 0xe6, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, 0x0a, 0x8a, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, + 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0xa9, 0x44, 0x81, 0x29, 0x0f, 0x06, 0xe0, 0xa7, 0x2e, 0x9e, 0x74, 0x5d, 0xba, + 0x7e, 0x3c, 0xc1, 0xd4, 0x1e, 0x02, 0x3d, 0xf6, 0x36, 0xc0, 0x94, 0xa8, 0xeb, 0xb0, 0x9c, 0x38, 0x34, 0xad, 0x69, + 0x16, 0x30, 0x63, 0x9a, 0xa0, 0x25, 0x9b, 0x60, 0xcb, 0x15, 0x60, 0x1f, 0x89, 0xed, 0x59, 0xad, 0x80, 0xd0, 0x35, + 0x68, 0x60, 0xc8, 0x5d, 0x2a, 0xb4, 0x30, 0xeb, 0xb4, 0xa9, 0x08, 0xf7, 0x67, 0x8f, 0x49, 0x2b, 0x38, 0xf5, 0x52, + 0x1a, 0xf8, 0x20, 0x3e, 0x4d, 0x30, 0xf1, 0x05, 0xb1, 0x02, 0x3b, 0x38, 0x68, 0x2d, 0x36, 0x05, 0x4e, 0xc5, 0x45, + 0x4a, 0x61, 0x59, 0x51, 0x6a, 0xc3, 0x87, 0x14, 0xd9, 0xba, 0xcb, 0x23, 0xdd, 0x85, 0x58, 0x00, 0x3b, 0xfd, 0xc2, + 0xa1, 0x83, 0xac, 0x97, 0x01, 0x83, 0x73, 0xad, 0x71, 0x10, 0xf8, 0xed, 0xed, 0xa4, 0x5f, 0x66, 0x48, 0xb9, 0x25, + 0x56, 0x17, 0x90, 0xe3, 0x76, 0x58, 0xc0, 0x1d, 0x84, 0xa5, 0xb2, 0xc7, 0xf3, 0x72, 0x82, 0xcb, 0xa5, 0x2c, 0xe4, + 0xc5, 0x74, 0x2c, 0x9a, 0xcf, 0xad, 0x34, 0x9b, 0x8e, 0xb7, 0xe2, 0x83, 0x82, 0xbf, 0xe7, 0xc4, 0xd2, 0xaa, 0xa7, + 0xd4, 0x0a, 0x8f, 0x32, 0xb7, 0x64, 0x9d, 0x92, 0x5a, 0x6d, 0x37, 0x50, 0x8d, 0xf0, 0x34, 0x0d, 0x1b, 0x81, 0x10, + 0x13, 0x5c, 0xfc, 0x61, 0x91, 0x89, 0x69, 0x6f, 0x09, 0xa9, 0x23, 0xec, 0x1e, 0xca, 0x09, 0x6e, 0x6b, 0x9e, 0x7d, + 0x19, 0x4e, 0xd7, 0x33, 0xf7, 0xbe, 0xc1, 0xdc, 0x4f, 0x43, 0x66, 0x30, 0x7a, 0x2c, 0x13, 0x7e, 0x64, 0xec, 0xa3, + 0x50, 0x55, 0xcf, 0xce, 0xc2, 0x4a, 0x64, 0x89, 0x6f, 0xc6, 0x51, 0x87, 0x71, 0x2a, 0x5a, 0x13, 0x64, 0xd7, 0xd7, + 0xb9, 0xb9, 0x17, 0x28, 0x68, 0xea, 0xb1, 0x7a, 0x9c, 0xb6, 0x62, 0x67, 0x23, 0x12, 0xb9, 0xff, 0xa6, 0x16, 0x89, + 0xac, 0xf8, 0x1c, 0x47, 0x5a, 0x73, 0x90, 0xfb, 0xec, 0x6c, 0x79, 0x93, 0x0a, 0xdd, 0xa2, 0xd1, 0x36, 0xf6, 0xa8, + 0x3e, 0x90, 0xd4, 0x33, 0x2a, 0xb0, 0xaa, 0xb1, 0xb7, 0xb6, 0x5a, 0x22, 0xdd, 0x52, 0x29, 0x36, 0x0c, 0x69, 0x85, + 0xcc, 0x18, 0x05, 0x83, 0x92, 0x22, 0x03, 0x35, 0xca, 0xd7, 0x08, 0x86, 0x7d, 0x6a, 0x00, 0x8a, 0x73, 0x75, 0xf5, + 0xd3, 0x52, 0xb2, 0x85, 0x80, 0x04, 0x64, 0x13, 0x8a, 0x35, 0x62, 0x66, 0xe4, 0x93, 0x8f, 0xc0, 0x79, 0x3d, 0x8e, + 0x8e, 0x01, 0xc8, 0x60, 0xb1, 0xe9, 0xc1, 0xc4, 0xb6, 0x89, 0x28, 0xfa, 0x6c, 0xe0, 0x25, 0x00, 0x3b, 0xad, 0x42, + 0xa3, 0x1f, 0xaa, 0x14, 0x30, 0x64, 0x03, 0x37, 0xe0, 0x55, 0x58, 0x6e, 0xff, 0x25, 0xb4, 0x83, 0xc7, 0x17, 0xb2, + 0xf9, 0x26, 0xe6, 0x09, 0x56, 0xb1, 0x3b, 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0xe1, 0x42, 0xbd, 0xa2, 0x84, 0xa8, + 0x3d, 0xc0, 0xda, 0x97, 0x9c, 0x60, 0xc4, 0xe7, 0x37, 0x94, 0x75, 0xa8, 0xc6, 0x2d, 0xf7, 0x35, 0x5a, 0x84, 0xe9, + 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, 0xbd, 0x3c, 0x10, 0xb1, 0xe0, 0x0a, 0x47, 0x23, 0x6c, 0xbe, 0x80, + 0x24, 0x7d, 0xdb, 0xa7, 0x03, 0xf6, 0xcd, 0xc5, 0x5e, 0x40, 0x99, 0x8f, 0x15, 0xa9, 0x24, 0xa4, 0x34, 0xbb, 0x21, + 0x92, 0x84, 0xb5, 0x22, 0x4f, 0x9d, 0x0f, 0x1c, 0xed, 0x73, 0x2b, 0x89, 0x60, 0x04, 0x27, 0x71, 0xba, 0xf2, 0x70, + 0x51, 0x80, 0xab, 0xe8, 0x88, 0xe9, 0x9b, 0xa0, 0xfc, 0x06, 0xb9, 0xbd, 0x94, 0x5c, 0x5b, 0x68, 0x18, 0x9e, 0x21, + 0xc1, 0xaa, 0x48, 0x04, 0x3a, 0x0a, 0x80, 0xe3, 0x4a, 0xcf, 0x03, 0x4c, 0xf8, 0xda, 0xde, 0x04, 0x80, 0x44, 0x56, + 0x90, 0xb3, 0x14, 0xe8, 0x06, 0x2c, 0x57, 0xc7, 0xa9, 0x51, 0x91, 0xb8, 0xb8, 0x31, 0x5d, 0xdd, 0xd2, 0x9f, 0xa0, + 0xe5, 0x4c, 0x86, 0x98, 0x0e, 0x82, 0x80, 0x4c, 0x7d, 0xca, 0x9d, 0x9c, 0xa6, 0x13, 0xd6, 0xe7, 0xd4, 0xa9, 0x4d, + 0xdd, 0xe1, 0xd4, 0xcd, 0x93, 0xd4, 0x62, 0x75, 0xda, 0x94, 0x12, 0x31, 0x29, 0x31, 0x8f, 0x65, 0x2a, 0xb6, 0x12, + 0x77, 0x6e, 0x7d, 0xa3, 0x85, 0xb4, 0xd1, 0x8e, 0x65, 0x0e, 0xb6, 0x96, 0xf7, 0x42, 0xb4, 0xbf, 0x24, 0xc2, 0xb3, + 0x12, 0x19, 0x6b, 0x3e, 0xe3, 0x8e, 0x89, 0x60, 0xf5, 0x60, 0x2a, 0xf2, 0x0f, 0x8e, 0x4e, 0xb3, 0x37, 0xe8, 0x41, + 0xea, 0x0d, 0x24, 0x66, 0x4d, 0x7c, 0xe7, 0xd2, 0x50, 0x47, 0x08, 0x54, 0x46, 0xb5, 0x4c, 0xc7, 0x89, 0xa5, 0xe2, + 0x92, 0x7c, 0xf5, 0x5e, 0x1f, 0xe7, 0x1b, 0xdf, 0x17, 0x56, 0x23, 0x88, 0xc1, 0x5b, 0x28, 0xfa, 0x9e, 0x14, 0xe1, + 0x39, 0x2c, 0xcf, 0xf6, 0x76, 0xa7, 0xd8, 0x63, 0x55, 0x88, 0xa4, 0x82, 0x31, 0xc6, 0x8c, 0x62, 0xdc, 0x13, 0x35, + 0xb5, 0x88, 0xc4, 0x96, 0xad, 0xc3, 0x02, 0x0f, 0x00, 0xa0, 0xa5, 0x29, 0xbd, 0xcc, 0xb6, 0xea, 0x3c, 0x97, 0xf0, + 0x31, 0xf2, 0x50, 0x64, 0xe3, 0xf7, 0x6b, 0x32, 0x50, 0x10, 0xee, 0x8d, 0x96, 0x87, 0x89, 0x71, 0xb0, 0x8a, 0x42, + 0x16, 0xe8, 0x0d, 0xda, 0xa9, 0x12, 0xa1, 0xb8, 0x39, 0x59, 0x87, 0x1b, 0x4e, 0x2a, 0xd8, 0x42, 0x25, 0x2c, 0x95, + 0x16, 0xf8, 0xd5, 0x46, 0x58, 0x3c, 0x65, 0xdc, 0x7f, 0x53, 0xe1, 0x0c, 0xfa, 0x83, 0x7b, 0xcb, 0x8c, 0xfa, 0x7e, + 0xe9, 0x44, 0xa6, 0x02, 0x13, 0x37, 0xb3, 0xd4, 0x7e, 0xbf, 0xac, 0xd2, 0x7e, 0x5e, 0x2e, 0xf7, 0x39, 0x69, 0xbe, + 0xd6, 0x1d, 0x34, 0x9f, 0x0c, 0xf7, 0x2b, 0xe5, 0x87, 0x16, 0x46, 0x4d, 0xf9, 0xd5, 0x97, 0x34, 0xcc, 0x3d, 0x15, + 0xde, 0xea, 0xb6, 0x51, 0xe8, 0xa2, 0x3e, 0x07, 0x43, 0x48, 0x7f, 0x05, 0xd7, 0xd0, 0xe0, 0x41, 0x91, 0x2c, 0x16, + 0x6b, 0x17, 0xc4, 0xf5, 0x31, 0xa7, 0xda, 0xa1, 0x8c, 0x31, 0xe2, 0x69, 0xc9, 0x41, 0x92, 0xc1, 0xc1, 0xf8, 0x0d, + 0x0c, 0x88, 0x49, 0x49, 0x48, 0x87, 0xd0, 0x59, 0x99, 0x89, 0xa8, 0xdc, 0xc5, 0xdb, 0x8d, 0xcb, 0x9a, 0x42, 0x11, + 0x76, 0x82, 0x99, 0x4a, 0xa9, 0x20, 0x90, 0x26, 0xdf, 0x46, 0xab, 0x16, 0x0c, 0x05, 0xd1, 0x60, 0x28, 0x20, 0x0f, + 0xd3, 0x55, 0xc2, 0x8d, 0x8f, 0xe2, 0xe0, 0x79, 0x85, 0x1a, 0xf1, 0x52, 0x83, 0xaf, 0x61, 0xf3, 0xd7, 0x44, 0x49, + 0x11, 0x72, 0x11, 0x7b, 0x05, 0x9f, 0x08, 0xd9, 0x94, 0x87, 0x39, 0xd0, 0x0f, 0xed, 0xca, 0x4e, 0xb6, 0x97, 0x57, + 0x2e, 0x2d, 0x1a, 0x5b, 0x89, 0x9a, 0xb5, 0x38, 0x8a, 0xb7, 0xb3, 0x3e, 0x4c, 0x4d, 0x09, 0x04, 0xa4, 0xa9, 0x9c, + 0xa4, 0x9a, 0xf7, 0x28, 0xeb, 0x03, 0x48, 0xb0, 0xfb, 0x09, 0x2c, 0xf4, 0x9b, 0x12, 0x13, 0x2c, 0xaa, 0xc6, 0x6e, + 0x53, 0xd0, 0x9a, 0x53, 0xd2, 0x7c, 0x53, 0x84, 0x70, 0x5b, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x76, 0x7e, + 0x94, 0x6d, 0xb7, 0xfa, 0x86, 0xe0, 0xc2, 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x42, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, + 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, 0xb1, 0xe8, 0xdc, 0x6b, 0x8e, 0x92, 0xcb, 0xaa, 0xda, 0xd5, 0x12, 0x34, + 0x74, 0x23, 0x19, 0x13, 0xc5, 0x3c, 0x27, 0x00, 0x46, 0xb1, 0xf9, 0x73, 0xae, 0x93, 0xbc, 0x7f, 0x59, 0x99, 0xda, + 0xed, 0xfb, 0x7e, 0x94, 0x9f, 0xd1, 0x91, 0x8a, 0xca, 0xe6, 0x24, 0xe6, 0xdf, 0x95, 0x60, 0x1a, 0x13, 0x1f, 0xe9, + 0xb9, 0xfa, 0xa1, 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x07, 0x72, 0x36, 0xc1, 0x02, 0x0b, + 0x74, 0x59, 0x83, 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, + 0x55, 0x60, 0x40, 0xf9, 0x70, 0xd1, 0xb0, 0x12, 0xe2, 0x12, 0x15, 0x66, 0x15, 0xe7, 0x8f, 0xeb, 0xbc, 0x6e, 0x5a, + 0x96, 0x18, 0x94, 0x9f, 0xba, 0x86, 0x1b, 0xdf, 0x59, 0xc8, 0x1f, 0xdf, 0x7f, 0x09, 0xba, 0x9d, 0x48, 0xbb, 0xb5, + 0x55, 0x6c, 0x90, 0x85, 0x86, 0xf7, 0xc2, 0xa6, 0xd0, 0x16, 0x2f, 0x02, 0x14, 0xea, 0x3b, 0x16, 0xe3, 0x6d, 0x11, + 0x2a, 0xc3, 0x2f, 0x58, 0x30, 0x05, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x1d, 0x36, 0x9a, 0x62, 0xd7, 0x42, 0x18, + 0x7c, 0x39, 0xa8, 0x4a, 0xc9, 0x8b, 0x75, 0xb2, 0xbd, 0x38, 0x87, 0xef, 0xaf, 0xe3, 0x02, 0xa8, 0x83, 0xe8, 0x6b, + 0x2a, 0x8b, 0x0d, 0xe4, 0xe2, 0xa6, 0xac, 0xf5, 0x8a, 0x86, 0xc3, 0x1b, 0xbb, 0xf0, 0xba, 0x02, 0x1f, 0x47, 0xe9, + 0x30, 0x11, 0x93, 0x98, 0x49, 0x95, 0x2b, 0x72, 0x6d, 0x74, 0x2f, 0x6d, 0xd1, 0xbc, 0x14, 0x12, 0xbc, 0x22, 0xf0, + 0x82, 0xd0, 0x57, 0xfa, 0x72, 0xb5, 0x81, 0x82, 0x47, 0xed, 0x8b, 0x8b, 0x60, 0x62, 0xe2, 0x71, 0x43, 0x6a, 0xfa, + 0x75, 0x38, 0xb5, 0xb2, 0x58, 0x72, 0xf8, 0x75, 0xce, 0xd8, 0x82, 0x02, 0x20, 0x3e, 0x79, 0xb4, 0xde, 0x4d, 0x7a, + 0xa3, 0xb4, 0x83, 0xd2, 0x08, 0xf1, 0x5d, 0x85, 0xaf, 0x3b, 0x57, 0x7c, 0xe5, 0xaa, 0x7b, 0x5f, 0x57, 0xdc, 0xb8, + 0x60, 0xf4, 0x92, 0x4f, 0x92, 0x85, 0x6b, 0x37, 0x74, 0x57, 0xe7, 0x3b, 0xef, 0x0b, 0x99, 0xb7, 0x70, 0x05, 0x76, + 0xfe, 0x15, 0x77, 0x5e, 0x7a, 0x1f, 0x8c, 0x13, 0xe5, 0xef, 0xcd, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0xef, + 0x7b, 0xdf, 0x07, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, 0x6d, 0x75, 0x82, 0x4c, 0x94, 0x1b, 0xe9, 0x0d, 0xb7, 0x7f, 0x57, + 0x81, 0x20, 0x4e, 0xc5, 0xf4, 0x51, 0x39, 0xae, 0x1f, 0x2d, 0x50, 0xa9, 0x88, 0xf8, 0x5c, 0xe5, 0xae, 0xac, 0x4d, + 0x0d, 0xf5, 0x98, 0x4e, 0x66, 0xa1, 0x69, 0x56, 0xe4, 0x52, 0x2e, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, + 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, + 0x7a, 0x14, 0x7d, 0x1c, 0x77, 0x31, 0x97, 0x47, 0xd9, 0x9f, 0x35, 0x00, 0x4c, 0x47, 0x58, 0x74, 0x37, 0x3d, 0x63, + 0x4f, 0xa0, 0xa7, 0x27, 0x32, 0x48, 0xf4, 0x56, 0xe7, 0xab, 0x56, 0x89, 0xa5, 0x2b, 0x08, 0xec, 0xde, 0x90, 0xb1, + 0x2a, 0x69, 0xb7, 0x5c, 0xbf, 0x9c, 0xe7, 0xf3, 0x9c, 0x2f, 0xe5, 0xf9, 0xd4, 0x2c, 0xba, 0x8d, 0xa6, 0x7b, 0x73, + 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, 0x5d, 0x0b, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, + 0x51, 0x3d, 0x93, 0x63, 0x24, 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0x77, 0x0b, 0xdb, 0x42, 0xb6, + 0x79, 0x79, 0x35, 0xcc, 0x81, 0xd2, 0x72, 0x7f, 0x99, 0x30, 0x7c, 0x77, 0x7d, 0xfd, 0x9d, 0x90, 0x53, 0x55, 0x47, + 0x6f, 0xfe, 0x5a, 0xf7, 0x0c, 0x46, 0xa5, 0x72, 0x22, 0x4e, 0xf9, 0xea, 0xc1, 0x17, 0x77, 0xaf, 0x80, 0xe5, 0x14, + 0xb0, 0x3b, 0xe5, 0xce, 0xc2, 0x50, 0xd5, 0x06, 0xfe, 0x62, 0xf5, 0x60, 0xab, 0xf6, 0xf0, 0x17, 0xbd, 0x2f, 0x82, + 0x1b, 0x1b, 0x1b, 0xdb, 0x78, 0xb7, 0x96, 0x08, 0xf2, 0x16, 0x0f, 0xf4, 0xf1, 0xea, 0xa3, 0xa0, 0xe5, 0x0a, 0xb1, + 0xcd, 0x7a, 0x0e, 0x85, 0xad, 0x41, 0xbe, 0x49, 0x99, 0x34, 0x98, 0x15, 0x3c, 0x9b, 0xc8, 0x19, 0x0a, 0x79, 0xcd, + 0xc7, 0x41, 0xdb, 0x11, 0xfe, 0x0f, 0x9c, 0xda, 0xf1, 0xf2, 0xfc, 0x13, 0xf4, 0x01, 0x4f, 0x57, 0x4a, 0x53, 0x8a, + 0x53, 0xaa, 0xa0, 0xce, 0x72, 0x9d, 0x07, 0x23, 0xc5, 0xc5, 0x18, 0x16, 0x17, 0x5c, 0x96, 0x1b, 0x67, 0x23, 0xa7, + 0xbf, 0xc4, 0xab, 0x8b, 0x74, 0xf9, 0x48, 0x64, 0xab, 0x96, 0xde, 0x2b, 0x7d, 0xba, 0x6d, 0x4f, 0x18, 0x1f, 0x67, + 0x43, 0x3a, 0x98, 0xf1, 0x71, 0x22, 0xbc, 0x3e, 0x31, 0xd4, 0x77, 0x8b, 0xc0, 0x74, 0x73, 0x6c, 0xf2, 0xc3, 0xf1, + 0x7a, 0xb3, 0x59, 0xe3, 0xf6, 0xde, 0x39, 0x9f, 0x9c, 0x79, 0x89, 0x11, 0x95, 0xb9, 0x86, 0x07, 0xb4, 0x42, 0xbc, + 0x78, 0xcf, 0x04, 0xc6, 0x65, 0x57, 0x24, 0xb5, 0xdd, 0x40, 0xe0, 0x62, 0x8f, 0x62, 0x96, 0x0c, 0x6d, 0x0f, 0xca, + 0x03, 0x7d, 0x31, 0x9a, 0x6e, 0x01, 0xd3, 0xf2, 0xda, 0xd9, 0x45, 0x6a, 0x7b, 0xd5, 0x54, 0x01, 0xcc, 0x92, 0xe5, + 0xf1, 0x19, 0xb2, 0xee, 0x57, 0xd0, 0x45, 0x0c, 0x18, 0x1b, 0x57, 0xe6, 0xdc, 0xf9, 0xaa, 0x15, 0xf1, 0x8d, 0x26, + 0xd2, 0xa4, 0x3e, 0xa2, 0xbe, 0xfd, 0xb0, 0x56, 0x57, 0x39, 0x48, 0xe0, 0x1e, 0x79, 0x77, 0xc4, 0xa5, 0xa3, 0xcf, + 0x2c, 0x36, 0xab, 0xf4, 0x2d, 0x75, 0x2d, 0x6e, 0x31, 0xec, 0x15, 0xf7, 0xc0, 0xfe, 0xc0, 0xb8, 0x45, 0x2c, 0xe2, + 0xed, 0xac, 0x96, 0xc2, 0xba, 0x30, 0x47, 0x8e, 0xb1, 0xf6, 0xe0, 0x15, 0xaf, 0xd6, 0x0c, 0xcc, 0x30, 0xe3, 0x8c, + 0xe4, 0x8d, 0x71, 0xaf, 0x6a, 0xd3, 0x91, 0xab, 0x00, 0xa2, 0x6f, 0x4e, 0x97, 0xe4, 0xf0, 0x4a, 0x96, 0xab, 0xce, + 0x90, 0x7f, 0x86, 0x75, 0xd6, 0x8b, 0x13, 0x70, 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, + 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0x85, 0x91, 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x2c, 0x26, 0x6c, 0xc4, 0x44, 0x1a, 0x95, + 0x52, 0xc2, 0x7a, 0x72, 0xa9, 0x25, 0x7f, 0x99, 0xcb, 0xab, 0x2f, 0xb7, 0x09, 0x0e, 0x28, 0x6a, 0x60, 0x39, 0x34, + 0x8e, 0x5b, 0x06, 0x12, 0xb1, 0x18, 0x10, 0xa3, 0x56, 0xe5, 0x72, 0x32, 0xaa, 0x93, 0xfa, 0x0a, 0xb9, 0x50, 0x91, + 0x07, 0xb7, 0x04, 0x4a, 0xfe, 0x02, 0x53, 0x07, 0xd3, 0x52, 0xbb, 0x69, 0xb1, 0x49, 0xf2, 0x8e, 0x19, 0x90, 0x5c, + 0x7d, 0x0d, 0x0f, 0x8d, 0x5f, 0x86, 0x37, 0x14, 0x3d, 0x1d, 0x23, 0xe4, 0xb4, 0x34, 0xe6, 0xd2, 0x7f, 0x23, 0xcf, + 0xbe, 0x24, 0x60, 0x3f, 0x83, 0x98, 0x32, 0x70, 0x89, 0x8d, 0x0b, 0x92, 0xf2, 0x5a, 0x9e, 0xb2, 0xfb, 0x16, 0x94, + 0xef, 0x92, 0x49, 0x57, 0xa9, 0xac, 0x35, 0x56, 0xdd, 0xcf, 0x33, 0x96, 0x5f, 0x1d, 0x30, 0xcc, 0x4d, 0x46, 0x83, + 0x6c, 0xc9, 0xcc, 0xa6, 0xfc, 0x6a, 0xef, 0xc6, 0xb7, 0x3c, 0x94, 0x74, 0xa8, 0x56, 0xe9, 0xe6, 0xa5, 0x1b, 0x8e, + 0xf1, 0xc2, 0x0d, 0xc7, 0xb8, 0x43, 0xe7, 0xca, 0x15, 0xa9, 0x75, 0xfe, 0xfb, 0x52, 0xf8, 0x49, 0xec, 0xb5, 0xbe, + 0xde, 0x75, 0xfd, 0x95, 0xe9, 0xe9, 0x37, 0xa0, 0x6a, 0x64, 0x09, 0xdd, 0x84, 0x2a, 0x26, 0x23, 0x51, 0x62, 0xba, + 0x4a, 0x79, 0xd4, 0xd7, 0x88, 0x0b, 0x10, 0x37, 0x94, 0xbf, 0xf8, 0x97, 0xf0, 0xe2, 0x24, 0x40, 0x23, 0x6a, 0x3e, + 0xca, 0x52, 0xde, 0x18, 0x45, 0x93, 0x38, 0xb9, 0x0a, 0x66, 0x71, 0x63, 0x92, 0xa5, 0x59, 0x31, 0x05, 0xae, 0xf4, + 0x8a, 0x2b, 0xb0, 0xe1, 0x27, 0x8d, 0x59, 0xec, 0xbd, 0x64, 0xc9, 0x39, 0xe3, 0xf1, 0x20, 0xf2, 0xec, 0xfd, 0x1c, + 0xc4, 0x83, 0xf5, 0x36, 0xca, 0xf3, 0xec, 0xc2, 0xf6, 0x3e, 0x64, 0xa7, 0xc0, 0xb4, 0xde, 0xbb, 0xcb, 0xab, 0x33, + 0x96, 0x7a, 0x1f, 0x4f, 0x67, 0x29, 0x9f, 0x79, 0x45, 0x94, 0x16, 0x8d, 0x82, 0xe5, 0xf1, 0x08, 0xd4, 0x44, 0x92, + 0xe5, 0x0d, 0xcc, 0x7f, 0x9e, 0xb0, 0x20, 0x89, 0xcf, 0xc6, 0xdc, 0x1a, 0x46, 0xf9, 0xa7, 0x4e, 0xa3, 0x31, 0xcd, + 0xe3, 0x49, 0x94, 0x5f, 0x35, 0xa8, 0x45, 0x70, 0xaf, 0xb9, 0x1b, 0x7d, 0x36, 0x7a, 0xd0, 0xe1, 0x39, 0xf4, 0x8d, + 0x91, 0x8a, 0x01, 0x08, 0x1f, 0x6b, 0xf7, 0x61, 0x73, 0x52, 0x6c, 0x88, 0x13, 0xa5, 0x28, 0xe5, 0xe5, 0x89, 0x77, + 0x01, 0xb6, 0xed, 0x89, 0x7f, 0xca, 0x53, 0x0f, 0x7c, 0x39, 0x9e, 0xa5, 0xf3, 0xc1, 0x2c, 0x2f, 0x60, 0x80, 0x69, + 0x16, 0xa7, 0x9c, 0xe5, 0x9d, 0xd3, 0x2c, 0x07, 0xb2, 0x35, 0xf2, 0x68, 0x18, 0xcf, 0x8a, 0xe0, 0xc1, 0xf4, 0xb2, + 0x83, 0xb6, 0xc2, 0x59, 0x9e, 0xcd, 0xd2, 0xa1, 0x9c, 0x2b, 0x4e, 0x61, 0x63, 0xc4, 0xdc, 0xac, 0xa0, 0x37, 0xa1, + 0x00, 0x7c, 0x29, 0x8b, 0xf2, 0xc6, 0x19, 0x76, 0x46, 0x43, 0xbf, 0x39, 0x64, 0x67, 0x5e, 0x7e, 0x76, 0x1a, 0x39, + 0xad, 0xf6, 0x63, 0x4f, 0xfd, 0xf9, 0x0f, 0x5d, 0x30, 0xdc, 0x57, 0x16, 0xb7, 0x9a, 0xcd, 0xbf, 0x71, 0x3b, 0x0b, + 0xb3, 0x10, 0x40, 0x41, 0x6b, 0x7a, 0x69, 0x15, 0x59, 0x02, 0xeb, 0xb3, 0xaa, 0x67, 0x67, 0x0a, 0x7e, 0x53, 0x9c, + 0x9e, 0x05, 0xed, 0xe9, 0x65, 0x89, 0xd8, 0x05, 0x22, 0x21, 0x53, 0x22, 0x29, 0x9f, 0xe6, 0xbf, 0x15, 0xe2, 0x27, + 0xab, 0x21, 0x6e, 0x2b, 0x88, 0x2b, 0xaa, 0x37, 0x86, 0xb0, 0x0f, 0x88, 0xfc, 0xad, 0x42, 0x00, 0x32, 0x06, 0x27, + 0x30, 0x57, 0x70, 0xd0, 0xc3, 0x6f, 0x06, 0xa3, 0xbd, 0x1a, 0x8c, 0x27, 0xb7, 0x81, 0x91, 0xa7, 0xc3, 0x79, 0x7d, + 0x5d, 0x5b, 0xe0, 0x9c, 0x76, 0xc6, 0x0c, 0xf9, 0x29, 0x68, 0xe3, 0xf7, 0x8b, 0x78, 0xc8, 0xc7, 0xe2, 0x2b, 0xb1, + 0xf3, 0x85, 0xa8, 0x7b, 0xd8, 0x6c, 0x8a, 0xe7, 0x02, 0x14, 0x5a, 0xd0, 0xf2, 0xb1, 0x01, 0x30, 0xd1, 0xe7, 0xeb, + 0x5e, 0x62, 0xf3, 0xed, 0xad, 0x6f, 0xaa, 0xf1, 0xb8, 0xca, 0x1b, 0x14, 0x2a, 0x42, 0xbd, 0xb3, 0x05, 0x33, 0xde, + 0x8a, 0x6e, 0x4b, 0x1f, 0x54, 0xf5, 0xbe, 0xe5, 0xa4, 0xf5, 0x02, 0xe6, 0x99, 0xb9, 0x40, 0x9d, 0xac, 0x8b, 0x21, + 0xa9, 0x46, 0xc3, 0x05, 0xbd, 0xc1, 0x31, 0x84, 0x44, 0x07, 0x82, 0x4e, 0xd1, 0xcb, 0xe9, 0x9d, 0x1a, 0xa9, 0x1b, + 0xe4, 0x4e, 0xea, 0xc2, 0x96, 0x4f, 0xb5, 0x5c, 0x2f, 0xb6, 0xb6, 0xc0, 0xcb, 0xfe, 0x9c, 0xcb, 0x06, 0x20, 0xbd, + 0x2b, 0x49, 0x6b, 0xbc, 0x87, 0x44, 0xb9, 0x7c, 0xd9, 0x80, 0x28, 0x07, 0xbe, 0x3e, 0x1f, 0xa3, 0xdf, 0xad, 0xaf, + 0xae, 0x1b, 0x29, 0x35, 0x3b, 0xb6, 0xdb, 0xe3, 0x3a, 0x2b, 0x0b, 0xb3, 0xcf, 0x78, 0x89, 0xa3, 0x7c, 0xc9, 0x43, + 0x1c, 0xd1, 0x7b, 0x15, 0x0a, 0x37, 0x4d, 0x39, 0x69, 0xa3, 0xbb, 0x3a, 0x69, 0xf0, 0x35, 0xa6, 0xcc, 0x67, 0x15, + 0x27, 0x07, 0x37, 0xe6, 0x78, 0x20, 0xae, 0x20, 0x16, 0x55, 0x96, 0x7d, 0x44, 0xd0, 0x0b, 0xbf, 0x0b, 0x94, 0x14, + 0x46, 0x2e, 0xbf, 0xe2, 0xbf, 0xc3, 0xe3, 0x70, 0x34, 0xfa, 0x45, 0x36, 0xcb, 0x07, 0x78, 0x39, 0x60, 0x45, 0x28, + 0xc2, 0x26, 0x4b, 0xc0, 0xf6, 0xb8, 0x56, 0x40, 0x0c, 0xf3, 0x2c, 0xcc, 0xb7, 0x2f, 0x30, 0x3a, 0x9d, 0x11, 0x97, + 0x1f, 0x64, 0xf8, 0x45, 0xa1, 0x84, 0x3a, 0x75, 0x48, 0x89, 0x78, 0x74, 0x31, 0xd4, 0x9f, 0xa5, 0x31, 0x88, 0xe0, + 0xe3, 0x78, 0x48, 0x17, 0x62, 0xe2, 0x21, 0x9d, 0x90, 0x34, 0x28, 0x23, 0x0a, 0x43, 0xee, 0x50, 0x20, 0x17, 0x06, + 0xbf, 0xcb, 0x0c, 0x1b, 0xbb, 0x61, 0xe3, 0x29, 0x87, 0xa1, 0xc3, 0x87, 0xd9, 0x24, 0x8a, 0xd3, 0x00, 0x5f, 0x5c, + 0xe2, 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0xa7, 0x5a, 0xa3, 0x96, 0xeb, 0xff, 0x04, 0x02, 0x8e, 0xfa, 0x63, 0x32, + 0x0b, 0x91, 0x55, 0x10, 0x31, 0x54, 0x64, 0xde, 0x57, 0x7a, 0xde, 0x33, 0xab, 0x55, 0xcc, 0xb4, 0xbe, 0x0e, 0xcd, + 0x85, 0xe5, 0xd2, 0x67, 0xd8, 0xf5, 0x52, 0x10, 0xac, 0x5c, 0xe7, 0xd1, 0x53, 0x10, 0x67, 0x8f, 0xd1, 0x47, 0xaf, + 0xd1, 0x0a, 0x5a, 0xda, 0x2f, 0xaf, 0x5d, 0xb5, 0x15, 0x89, 0x3a, 0xf2, 0xba, 0x26, 0xe1, 0xa1, 0xbf, 0x0b, 0x5c, + 0xab, 0x67, 0x8d, 0xaf, 0x27, 0x37, 0x1d, 0x46, 0xa7, 0xce, 0x52, 0xa7, 0x06, 0x04, 0x1d, 0x74, 0xac, 0x99, 0xca, + 0x2d, 0x2b, 0xbc, 0xb5, 0xf1, 0x67, 0x0b, 0xcd, 0x89, 0xaf, 0x1e, 0x90, 0x33, 0xd2, 0x2b, 0x9e, 0x56, 0xf0, 0x5d, + 0x29, 0x09, 0xb2, 0x78, 0x21, 0x7f, 0xa1, 0x99, 0x00, 0xe5, 0x4a, 0x1f, 0x64, 0x2f, 0xd4, 0x8a, 0x47, 0x26, 0x22, + 0xde, 0xab, 0x9b, 0x50, 0xd6, 0xd8, 0x32, 0x5c, 0xe8, 0x8b, 0x16, 0x5c, 0xc1, 0x8f, 0x06, 0xd3, 0x88, 0xe1, 0xbd, + 0x94, 0x93, 0xcd, 0xf9, 0x97, 0xbc, 0xdc, 0xd9, 0x9c, 0xab, 0x86, 0xe2, 0x7b, 0x3c, 0xc4, 0x4f, 0x06, 0xf2, 0x6b, + 0x2e, 0xac, 0xc7, 0xc0, 0x7e, 0xff, 0xee, 0xe0, 0xd0, 0xf6, 0x4e, 0xb3, 0xe1, 0x55, 0x60, 0xc3, 0xee, 0x64, 0x76, + 0xe9, 0xfa, 0x7c, 0xcc, 0x52, 0x47, 0xb1, 0x78, 0x96, 0x30, 0x90, 0x08, 0x67, 0xe2, 0xb2, 0xe3, 0xa2, 0xe7, 0x3b, + 0x3c, 0xd9, 0xa3, 0xb7, 0x21, 0x75, 0xf7, 0xb8, 0x78, 0x51, 0x18, 0xcf, 0xf1, 0x6b, 0x17, 0x63, 0xff, 0x7b, 0x3b, + 0xf0, 0x05, 0x1f, 0x0e, 0x70, 0xcf, 0xd0, 0xd3, 0xe6, 0x7c, 0x89, 0x93, 0x7a, 0x38, 0xc4, 0xb8, 0x2b, 0x50, 0x28, + 0xa8, 0xd5, 0x49, 0x30, 0x3c, 0x39, 0x29, 0xe1, 0x2b, 0x8c, 0xb5, 0xa3, 0xc6, 0x45, 0x08, 0x55, 0x7f, 0xcd, 0x5d, + 0xf2, 0x75, 0x3b, 0x38, 0x04, 0xce, 0x3b, 0xc4, 0x06, 0xc4, 0x5d, 0xd8, 0x7b, 0xa8, 0x4b, 0x68, 0xd3, 0x8a, 0xa2, + 0x75, 0x10, 0x88, 0x86, 0x15, 0xd3, 0x8b, 0x10, 0x61, 0xb5, 0xba, 0x0a, 0xa4, 0xa1, 0x09, 0xdd, 0x89, 0x8b, 0x9f, + 0x04, 0x19, 0x7c, 0x12, 0x1d, 0x4e, 0xcc, 0x37, 0x84, 0x88, 0xcb, 0xfc, 0x9a, 0x5a, 0x47, 0x7f, 0x01, 0xdb, 0xc3, + 0xbb, 0x38, 0xa1, 0x96, 0x4a, 0x1d, 0xa1, 0x9d, 0x84, 0x6a, 0xbb, 0xa9, 0xec, 0x0e, 0xd0, 0xfd, 0x49, 0x34, 0x2d, + 0x58, 0xa0, 0xbe, 0x48, 0xcd, 0x84, 0x0a, 0x6e, 0xd9, 0x14, 0x90, 0x79, 0x31, 0xcf, 0xd0, 0x60, 0x58, 0xb6, 0x53, + 0x40, 0xf4, 0x39, 0x8d, 0xc6, 0xa0, 0x71, 0x7a, 0xe6, 0x96, 0x7c, 0x3c, 0x37, 0xf5, 0xda, 0x23, 0xd0, 0x6b, 0x98, + 0x93, 0xd7, 0x00, 0x4f, 0xed, 0x2c, 0x0d, 0x12, 0x36, 0xe2, 0x25, 0xc7, 0x4b, 0x5f, 0x73, 0x65, 0x48, 0xf8, 0xed, + 0x87, 0xa0, 0xeb, 0x2c, 0x1f, 0xff, 0xbd, 0x79, 0x62, 0xe8, 0x18, 0xa4, 0xa0, 0x9b, 0x28, 0x0b, 0x14, 0x33, 0xec, + 0x01, 0x5c, 0xf3, 0x79, 0x6e, 0x4c, 0x34, 0x60, 0x68, 0x64, 0x95, 0x1c, 0x64, 0xf2, 0xd8, 0xe3, 0xb9, 0xd9, 0x2e, + 0x75, 0xe7, 0x4b, 0x18, 0x2c, 0xeb, 0xfa, 0x5d, 0xb7, 0x2c, 0xc8, 0x64, 0x5d, 0x6e, 0xac, 0x0c, 0xa6, 0xfa, 0xd3, + 0x12, 0xf9, 0x0c, 0xd3, 0xae, 0x14, 0xc1, 0xd2, 0xb9, 0xe8, 0x71, 0x17, 0x62, 0xd6, 0x8c, 0x4e, 0xcf, 0xec, 0xe1, + 0x96, 0x71, 0x3a, 0x9d, 0xf1, 0x23, 0x0a, 0xd4, 0xe6, 0x78, 0x9d, 0xa0, 0x3f, 0x17, 0x73, 0x83, 0x17, 0x3c, 0x70, + 0x10, 0x00, 0xab, 0x61, 0x3d, 0x01, 0x6a, 0xba, 0xca, 0xf0, 0xf0, 0x1f, 0x23, 0x71, 0x4b, 0x9f, 0x5a, 0xaf, 0xa0, + 0xd2, 0x09, 0x58, 0xdd, 0x1d, 0xce, 0x9d, 0xa3, 0x37, 0x8e, 0xdb, 0xf7, 0x5e, 0x19, 0x2f, 0x2f, 0xb1, 0xd5, 0x1e, + 0xb0, 0x3d, 0xa4, 0xf7, 0xca, 0x26, 0x26, 0x93, 0x53, 0xb3, 0x57, 0x21, 0x36, 0x7c, 0xeb, 0xd8, 0xac, 0x98, 0x36, + 0x84, 0x48, 0x6a, 0x10, 0x33, 0xda, 0xd8, 0x55, 0x05, 0x56, 0xbf, 0xe2, 0x73, 0x92, 0x36, 0x5c, 0xbf, 0x29, 0xe4, + 0x88, 0xf7, 0xcd, 0x5b, 0x2d, 0xb5, 0x80, 0x3a, 0xd4, 0xb9, 0x86, 0xe4, 0x83, 0x47, 0xf9, 0xd6, 0x1b, 0x25, 0x37, + 0x4e, 0xf6, 0xeb, 0x92, 0x0c, 0xf6, 0x59, 0xa9, 0xdf, 0xa8, 0x06, 0x5a, 0x18, 0xe7, 0x87, 0x8d, 0x24, 0xf7, 0xdd, + 0x53, 0xb2, 0x12, 0x55, 0x1c, 0x9c, 0xae, 0x2c, 0xaa, 0x13, 0x0d, 0xa1, 0x50, 0x63, 0x3c, 0x77, 0xad, 0x25, 0xdd, + 0x76, 0x2a, 0x59, 0x24, 0x6c, 0x4c, 0x8b, 0xf0, 0x08, 0x6d, 0x30, 0xfa, 0x6c, 0xeb, 0xcf, 0x03, 0x50, 0x7f, 0x9f, + 0x42, 0x7b, 0x73, 0xee, 0xb8, 0xab, 0xef, 0xcd, 0x29, 0xcf, 0x50, 0x49, 0x61, 0x23, 0x63, 0xb1, 0x26, 0x5c, 0xd1, + 0x41, 0xb5, 0xbb, 0x28, 0x3e, 0xf7, 0x76, 0xc4, 0x44, 0xb0, 0xdb, 0x8f, 0xe5, 0x8b, 0x9e, 0xb8, 0x29, 0x12, 0x91, + 0xbc, 0xa2, 0xdc, 0x22, 0x36, 0x09, 0xed, 0x5b, 0x79, 0xc7, 0xb6, 0x84, 0x94, 0x42, 0x40, 0x95, 0xc0, 0x02, 0xe0, + 0x75, 0x19, 0x93, 0xb0, 0xc7, 0x92, 0x0c, 0x36, 0xce, 0x05, 0x8a, 0x00, 0x03, 0x47, 0x3c, 0x8a, 0x13, 0xd1, 0x45, + 0x06, 0xf6, 0x94, 0x03, 0xa8, 0x31, 0xc2, 0x23, 0xf5, 0x3a, 0x2e, 0x75, 0x12, 0x12, 0x66, 0x7b, 0x3b, 0x15, 0xdc, + 0x84, 0x19, 0xed, 0x32, 0xf3, 0x00, 0xab, 0xc2, 0x50, 0xd4, 0x01, 0x71, 0xe9, 0xda, 0x0c, 0x02, 0x58, 0xa8, 0x60, + 0x87, 0x97, 0xaa, 0x2b, 0x2c, 0x02, 0x96, 0x1c, 0x13, 0x85, 0xc1, 0xc8, 0x63, 0x5c, 0x13, 0x36, 0x17, 0xd9, 0x8f, + 0x0a, 0xda, 0x74, 0x09, 0xda, 0xb4, 0x0e, 0xed, 0x09, 0x12, 0xbd, 0xb7, 0x39, 0x8f, 0xcb, 0x10, 0xbe, 0xa5, 0x83, + 0x6c, 0xc8, 0x3e, 0x7e, 0x78, 0x85, 0x77, 0x00, 0xa1, 0x3d, 0x38, 0x0b, 0x99, 0x5b, 0x9e, 0xc8, 0xc5, 0x31, 0x75, + 0x82, 0xd8, 0xdb, 0x16, 0xcd, 0x45, 0x74, 0x05, 0x8a, 0xf6, 0x04, 0xe4, 0x6c, 0x48, 0x05, 0x61, 0x98, 0x53, 0x2f, + 0x0e, 0x4b, 0x2a, 0x5a, 0x0b, 0x99, 0x2e, 0x1a, 0x21, 0x11, 0x68, 0x67, 0x56, 0x34, 0xc0, 0x9c, 0x59, 0x93, 0x0e, + 0xc3, 0xf8, 0x5c, 0x73, 0x1b, 0x5d, 0x20, 0xea, 0xee, 0x01, 0x43, 0xb3, 0x04, 0xc6, 0xcc, 0xaf, 0xaf, 0x9b, 0x30, + 0x94, 0x78, 0xb4, 0xf6, 0x48, 0x36, 0x88, 0x77, 0x61, 0xc2, 0xcc, 0x2d, 0x4c, 0x4f, 0xc2, 0xab, 0x7a, 0x3d, 0x95, + 0x6f, 0x13, 0xc8, 0x01, 0x00, 0x46, 0x3a, 0xea, 0x27, 0x3e, 0xd0, 0xe6, 0x0d, 0x94, 0xc6, 0xc3, 0xe5, 0x32, 0xb0, + 0x4a, 0xa7, 0x58, 0x9a, 0x5d, 0x5f, 0xb7, 0xe0, 0x71, 0x12, 0xa7, 0xf8, 0x04, 0x33, 0xd3, 0x0d, 0x38, 0x78, 0x04, + 0xd3, 0x1c, 0xd8, 0x16, 0x6a, 0xa2, 0x4b, 0xac, 0x49, 0x55, 0x4d, 0x74, 0x09, 0xf2, 0x48, 0x54, 0x69, 0xf2, 0x14, + 0xc8, 0x70, 0xff, 0x1f, 0x16, 0x34, 0x93, 0x8b, 0x67, 0x69, 0xd2, 0x01, 0x98, 0x20, 0x2d, 0x35, 0xf1, 0xf6, 0x76, + 0x80, 0xcc, 0xb0, 0x18, 0xd2, 0xfa, 0x91, 0x3b, 0xae, 0x7a, 0x8f, 0x91, 0x90, 0x64, 0x6e, 0x2d, 0x0d, 0x81, 0x8a, + 0xd0, 0x1a, 0x04, 0xdf, 0x62, 0x78, 0x4c, 0x9b, 0x03, 0xf4, 0xbc, 0xd4, 0xfe, 0x0b, 0xb2, 0xa6, 0xea, 0xe0, 0xd9, + 0x7f, 0xfd, 0xc7, 0xbf, 0xb3, 0x3d, 0xb1, 0xb9, 0xb2, 0xd1, 0x08, 0x4c, 0x65, 0xeb, 0x0e, 0x7d, 0xfe, 0xd7, 0xdf, + 0xff, 0xdf, 0xff, 0xf3, 0x5f, 0x75, 0xb7, 0x14, 0x7a, 0x9d, 0xc8, 0x83, 0x3f, 0x25, 0x1d, 0x0c, 0x30, 0x15, 0x1a, + 0xa3, 0x28, 0x5d, 0x87, 0xc3, 0x91, 0x89, 0x43, 0x31, 0x65, 0x6c, 0xe8, 0xd9, 0x96, 0xed, 0x2d, 0x95, 0x1e, 0x27, + 0xec, 0x9c, 0xc9, 0xb7, 0x9e, 0xad, 0x9a, 0x6a, 0x45, 0x8f, 0x01, 0x28, 0x34, 0x2e, 0xcf, 0x3f, 0x25, 0x6f, 0x9b, + 0xa8, 0x48, 0xa9, 0x52, 0xeb, 0x87, 0xb4, 0xab, 0x8b, 0x0b, 0xcf, 0x36, 0xa6, 0x5f, 0x0b, 0x57, 0x6f, 0x4d, 0x79, + 0xd0, 0xf4, 0x9a, 0xeb, 0x20, 0xf3, 0xc0, 0x8f, 0xb4, 0xed, 0xbe, 0xa2, 0x11, 0x85, 0x7b, 0xcc, 0x0b, 0xec, 0xeb, + 0x68, 0x75, 0x2b, 0xf6, 0xa7, 0x39, 0x0e, 0x95, 0xb2, 0xa2, 0xb8, 0x05, 0x79, 0x58, 0x3e, 0xcf, 0xae, 0x5a, 0xdb, + 0x6b, 0x46, 0x01, 0x14, 0xda, 0x0f, 0x1f, 0x0a, 0x70, 0x3d, 0x47, 0xbb, 0x90, 0x66, 0x63, 0x36, 0x1a, 0x81, 0x10, + 0x29, 0xdc, 0x2a, 0x1f, 0x74, 0x14, 0x27, 0x1c, 0xcf, 0xb3, 0xc3, 0xae, 0xfd, 0x16, 0x36, 0x06, 0x5e, 0x0f, 0x75, + 0xa5, 0x5f, 0xaf, 0x32, 0xfd, 0x94, 0xd0, 0x5d, 0x0d, 0x97, 0x18, 0xb2, 0x0e, 0x93, 0x9c, 0xe6, 0xfa, 0x5a, 0xf9, + 0xcb, 0xb5, 0xf2, 0x3a, 0x39, 0x33, 0x72, 0x88, 0x57, 0xef, 0x9b, 0xbb, 0xec, 0x8e, 0x7f, 0xfd, 0xa7, 0xbf, 0xff, + 0x6f, 0x00, 0x06, 0x8e, 0x73, 0xb7, 0xad, 0x01, 0x1d, 0xfe, 0x27, 0x74, 0x98, 0xa5, 0x77, 0xef, 0xf2, 0xd7, 0xff, + 0xf2, 0xdf, 0xa1, 0x07, 0x5d, 0x60, 0x86, 0x7d, 0xa4, 0x40, 0x1f, 0x60, 0xd8, 0xe8, 0x77, 0xc1, 0x5e, 0x1b, 0xf7, + 0x2e, 0x70, 0xfc, 0x03, 0xa2, 0x5a, 0xf0, 0x6c, 0x7a, 0x57, 0xb8, 0x11, 0xd3, 0x41, 0x92, 0x15, 0xcc, 0x04, 0x5c, + 0x58, 0x0a, 0xbf, 0x0f, 0x72, 0x82, 0x64, 0x0a, 0x12, 0xb4, 0xb0, 0xcc, 0xa1, 0x25, 0xaf, 0xdc, 0x28, 0x08, 0x57, + 0x32, 0x54, 0xc1, 0x38, 0x91, 0x82, 0xac, 0xb9, 0x1a, 0xd3, 0x88, 0xb2, 0x25, 0x5e, 0x22, 0xe9, 0xae, 0x25, 0x97, + 0xd0, 0x58, 0xb7, 0xcc, 0xbb, 0x62, 0x7f, 0x89, 0x69, 0xc5, 0x99, 0xd7, 0xf2, 0xf0, 0xb5, 0x12, 0x50, 0x5d, 0xc7, + 0x2b, 0x4a, 0xa3, 0xcb, 0x15, 0xa5, 0xa8, 0x04, 0x35, 0x6c, 0x60, 0xed, 0x4d, 0xc4, 0x4b, 0x2f, 0xf4, 0xeb, 0x2e, + 0x6a, 0xd0, 0x91, 0x2a, 0xc3, 0x53, 0xfc, 0xfa, 0x2b, 0x00, 0xe4, 0x50, 0x42, 0xad, 0x1d, 0xe3, 0xbd, 0x1a, 0xbc, + 0x45, 0x3d, 0xcb, 0x19, 0xec, 0x99, 0x0b, 0xf3, 0x68, 0xfe, 0xe6, 0xc6, 0x63, 0x10, 0x0f, 0x3d, 0xb0, 0x27, 0xf5, + 0xaa, 0xde, 0x38, 0x6e, 0xf9, 0x2f, 0xff, 0xec, 0xfb, 0xff, 0xf2, 0xcf, 0xb7, 0x36, 0xc5, 0x51, 0xc1, 0x65, 0xe7, + 0xd5, 0xb0, 0xeb, 0xa9, 0xbb, 0x7a, 0xa6, 0x3a, 0xb9, 0x57, 0xb7, 0x59, 0xa2, 0x3f, 0xd6, 0x2f, 0x91, 0x7f, 0xa9, + 0x50, 0x50, 0xdf, 0xfa, 0x2d, 0x80, 0x21, 0x5e, 0xb7, 0x42, 0x86, 0x8d, 0x7e, 0x17, 0x68, 0x27, 0x6e, 0x70, 0xa7, + 0x15, 0xf9, 0xed, 0x14, 0xbe, 0x0d, 0x87, 0xdf, 0x09, 0xbe, 0x48, 0x07, 0x06, 0xd0, 0x4e, 0xd4, 0x8d, 0xa9, 0x5a, + 0x57, 0xbc, 0x74, 0xd9, 0x5b, 0x2a, 0x91, 0x6a, 0x25, 0x68, 0xba, 0xdd, 0xe6, 0xd6, 0x96, 0x83, 0xdd, 0xdf, 0xe0, + 0x9b, 0x21, 0xf6, 0x4e, 0x73, 0x15, 0x03, 0xb9, 0x41, 0x34, 0xe0, 0x10, 0x75, 0xac, 0x68, 0xd0, 0x25, 0xb9, 0x80, + 0xa5, 0x98, 0x61, 0x8a, 0x60, 0x7a, 0x60, 0x0e, 0x0b, 0x7b, 0xed, 0x99, 0x70, 0x6c, 0x82, 0x45, 0xd6, 0x96, 0x0e, + 0x4f, 0x8d, 0xe8, 0x9e, 0x75, 0x48, 0xf4, 0xa2, 0xc6, 0xac, 0xb2, 0x97, 0xc9, 0x4b, 0x44, 0x03, 0xf1, 0x44, 0xbc, + 0x2b, 0xe3, 0xeb, 0x75, 0xf1, 0xf6, 0xef, 0x6f, 0x8f, 0xb7, 0xc7, 0x77, 0x8c, 0xb7, 0x7f, 0xff, 0x07, 0xc7, 0xdb, + 0xbf, 0x36, 0xe3, 0xed, 0xb8, 0x88, 0x3f, 0xdf, 0x29, 0x26, 0xae, 0x22, 0x95, 0xd9, 0x45, 0x11, 0xb6, 0xa4, 0xa5, + 0x04, 0x8e, 0x34, 0x06, 0xc4, 0xff, 0xed, 0xe3, 0xdb, 0x30, 0xd1, 0x42, 0x74, 0x9b, 0xc2, 0xd9, 0x92, 0x07, 0x99, + 0x0a, 0x26, 0x37, 0x75, 0xee, 0x77, 0xe3, 0x81, 0xba, 0xec, 0x0a, 0x2e, 0x8c, 0xab, 0x0f, 0x04, 0xda, 0x2a, 0xdc, + 0x1c, 0xd0, 0xdb, 0xaa, 0x75, 0xc7, 0xf6, 0xb6, 0x4a, 0x3a, 0x36, 0x47, 0xe8, 0xa8, 0xb3, 0x64, 0x71, 0x53, 0x72, + 0x6e, 0xff, 0xa7, 0xa3, 0x56, 0x67, 0xb7, 0x35, 0x81, 0xde, 0xc0, 0x87, 0xf0, 0xd4, 0xec, 0xec, 0xee, 0xe2, 0xd3, + 0x85, 0x7a, 0x6a, 0xe3, 0x53, 0xac, 0x9e, 0x1e, 0xe2, 0xd3, 0x40, 0x3d, 0x3d, 0xc2, 0xa7, 0xa1, 0x7a, 0x7a, 0x8c, + 0x4f, 0xe7, 0x76, 0x79, 0xc4, 0x34, 0x70, 0x8f, 0xdd, 0xbe, 0x27, 0x4c, 0x51, 0x55, 0xf6, 0xd8, 0x6b, 0x61, 0x40, + 0x3b, 0x3a, 0x0b, 0x62, 0x4f, 0x38, 0xd4, 0x41, 0xe1, 0x5d, 0x8c, 0x59, 0x1a, 0x50, 0x4e, 0xf4, 0x73, 0x7c, 0x5b, + 0x10, 0xd8, 0xc0, 0x87, 0xf1, 0x84, 0xa9, 0xd7, 0xa6, 0x2b, 0xac, 0x41, 0x25, 0x1f, 0x35, 0xfb, 0x65, 0x47, 0xaf, + 0x93, 0x88, 0x84, 0xab, 0xf4, 0x4e, 0x5a, 0xb9, 0xaa, 0x4e, 0x4c, 0xd7, 0xd0, 0x2b, 0xbc, 0x26, 0xa8, 0x6a, 0xf8, + 0x95, 0x23, 0x90, 0xcd, 0x8d, 0x4b, 0x70, 0x2c, 0x57, 0x06, 0x5a, 0x11, 0x22, 0x1d, 0x68, 0x25, 0x9c, 0xf4, 0xd3, + 0x61, 0x74, 0xa6, 0xbf, 0xbf, 0x01, 0xdb, 0x21, 0x3a, 0x93, 0x2d, 0xd7, 0x07, 0x56, 0x09, 0x44, 0x33, 0xa8, 0xaa, + 0x80, 0x40, 0xc7, 0x13, 0x97, 0x06, 0xc3, 0x04, 0x32, 0x56, 0x8a, 0xd4, 0xa9, 0x87, 0x59, 0x69, 0xfa, 0x7a, 0x11, + 0x50, 0xb4, 0x2a, 0xd8, 0x03, 0x13, 0x86, 0x4a, 0x05, 0x85, 0xa1, 0x02, 0x0b, 0x44, 0xf5, 0x9a, 0x70, 0xaa, 0x72, + 0xfd, 0xd6, 0x07, 0x55, 0x2d, 0x15, 0x4f, 0x35, 0xcf, 0xa0, 0xf5, 0x01, 0xf4, 0x72, 0x14, 0xef, 0x5e, 0x6b, 0x80, + 0xff, 0xc9, 0x18, 0xe1, 0xbd, 0xd1, 0x68, 0x74, 0x63, 0x7c, 0xf5, 0xde, 0x70, 0xc4, 0xda, 0xec, 0x61, 0x07, 0xcf, + 0x27, 0x1b, 0x32, 0x6a, 0xd7, 0x2a, 0x89, 0x76, 0xf3, 0xbb, 0x35, 0xc6, 0x00, 0x1f, 0x1f, 0xcf, 0xef, 0x1e, 0x6b, + 0x2d, 0x81, 0x2a, 0xf3, 0x09, 0x48, 0xc5, 0x38, 0x0d, 0x9a, 0xa5, 0x7f, 0x2e, 0x83, 0x93, 0xf7, 0x9e, 0x3c, 0x79, + 0x52, 0xfa, 0x43, 0xf5, 0xd4, 0x1c, 0x0e, 0x4b, 0x7f, 0x30, 0xd7, 0x68, 0x34, 0x9b, 0xa3, 0x51, 0xe9, 0xc7, 0xaa, + 0x60, 0xb7, 0x3d, 0x18, 0xee, 0xb6, 0x4b, 0xff, 0xc2, 0x68, 0x51, 0xfa, 0x4c, 0x3e, 0xe5, 0x6c, 0x58, 0x3b, 0xe4, + 0x7c, 0x0c, 0xde, 0xb6, 0x2f, 0x18, 0x6d, 0x8e, 0x86, 0xb6, 0xf8, 0x1a, 0x44, 0x33, 0x9e, 0xa1, 0x00, 0xee, 0x00, + 0x9f, 0x1f, 0x6d, 0xca, 0x6b, 0xcc, 0xe2, 0xad, 0xe4, 0x25, 0x6c, 0xa1, 0x9f, 0xcd, 0x60, 0x23, 0x32, 0x33, 0x05, + 0x19, 0x63, 0x15, 0x8b, 0xac, 0x55, 0x23, 0x67, 0x51, 0xf5, 0xcf, 0x61, 0x5c, 0xc5, 0x20, 0x51, 0xda, 0x60, 0x4b, + 0x91, 0x8c, 0xf3, 0xdd, 0x3a, 0x19, 0xff, 0xc5, 0xed, 0x32, 0xfe, 0xea, 0x6e, 0x22, 0xfe, 0x8b, 0x3f, 0x58, 0xc4, + 0x7f, 0x67, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0x79, 0x68, 0x0f, 0xc6, 0x6c, 0xf0, 0xe9, 0x34, 0xbb, 0x6c, 0xe0, 0x96, + 0xc8, 0x6d, 0x92, 0x9e, 0x93, 0xdf, 0x7a, 0x20, 0xaa, 0x06, 0x33, 0x5e, 0x71, 0x4e, 0x4a, 0xf2, 0x5d, 0x1a, 0xda, + 0xef, 0x94, 0xfd, 0x2e, 0x4a, 0x46, 0x23, 0x28, 0x1a, 0x8d, 0x6c, 0x75, 0x79, 0x03, 0xc4, 0x16, 0xb5, 0x7a, 0x5b, + 0x2b, 0xa1, 0x56, 0x9f, 0x7f, 0x6e, 0x96, 0x99, 0x05, 0x32, 0x64, 0x69, 0x86, 0x27, 0x65, 0xcd, 0x30, 0x2e, 0x70, + 0xab, 0xe1, 0x9b, 0xd7, 0x97, 0x5e, 0x69, 0x25, 0x02, 0xab, 0xcb, 0x00, 0x57, 0xf1, 0x55, 0xe3, 0xed, 0xa9, 0x55, + 0x84, 0x15, 0x16, 0x54, 0x66, 0xd6, 0x3d, 0xbd, 0x7a, 0x35, 0x74, 0xf6, 0xb9, 0x5b, 0xc6, 0xc5, 0xbb, 0x74, 0x21, + 0x63, 0x59, 0xc0, 0x18, 0x86, 0x26, 0x5a, 0x25, 0xcf, 0xce, 0xce, 0x92, 0xe5, 0x1c, 0x58, 0xd1, 0xbd, 0x57, 0xc3, + 0x37, 0x30, 0x3b, 0x4a, 0x5d, 0x46, 0x3f, 0x99, 0x21, 0x52, 0xfb, 0x28, 0x27, 0x5b, 0x1d, 0xed, 0xce, 0xa5, 0xfc, + 0x97, 0x49, 0x5f, 0x8c, 0x0e, 0x51, 0x69, 0xe0, 0x61, 0x59, 0xca, 0xcc, 0x5a, 0x20, 0xc4, 0x14, 0xdf, 0xff, 0x26, + 0x7a, 0xc6, 0xb7, 0x89, 0xf0, 0xe2, 0xc2, 0x88, 0x0b, 0xd6, 0x96, 0xab, 0x54, 0x81, 0x41, 0x11, 0xdd, 0xdb, 0xc7, + 0x10, 0xa5, 0x88, 0x11, 0x2a, 0x22, 0xda, 0x56, 0x8f, 0xbe, 0xca, 0x88, 0x65, 0x85, 0x21, 0x06, 0x33, 0xf5, 0x82, + 0xa8, 0x2a, 0x55, 0x50, 0x9a, 0x81, 0x6f, 0xaa, 0x11, 0xd4, 0xa2, 0x30, 0x1b, 0xc0, 0x9e, 0x0a, 0x31, 0x0a, 0xd3, + 0x90, 0x3c, 0xd8, 0x9c, 0x57, 0x2b, 0x0f, 0x5d, 0x25, 0xd8, 0x82, 0x79, 0x41, 0x06, 0x63, 0x87, 0xae, 0x55, 0x03, + 0x3d, 0x5d, 0x8a, 0xce, 0xdd, 0x7c, 0xee, 0x75, 0xe2, 0x17, 0x17, 0x1e, 0xfc, 0x59, 0x7f, 0x9a, 0x83, 0xd0, 0x39, + 0xfd, 0x14, 0xf3, 0x06, 0x8f, 0xa6, 0x0d, 0xb4, 0xee, 0x29, 0xc8, 0x23, 0xa5, 0x33, 0xe5, 0x6f, 0x88, 0x7b, 0x96, + 0x9d, 0x59, 0x81, 0xc7, 0x63, 0x64, 0xa3, 0x06, 0x69, 0x96, 0xb2, 0x4e, 0x3d, 0x4f, 0xc7, 0x3c, 0x6d, 0x51, 0xc4, + 0xea, 0xcf, 0x33, 0x3c, 0x4e, 0xe3, 0x57, 0x41, 0x53, 0x4a, 0xf5, 0xa6, 0x3a, 0x6a, 0x69, 0xae, 0x6c, 0x1f, 0x48, + 0xda, 0x6e, 0x93, 0xf2, 0xca, 0x97, 0x8f, 0x94, 0xd6, 0x1d, 0x09, 0xdd, 0x96, 0xb5, 0x82, 0xc1, 0x21, 0xf5, 0x67, + 0xa4, 0xfb, 0x2c, 0x16, 0x53, 0xd6, 0xca, 0x5d, 0x20, 0x0b, 0xa2, 0x11, 0xbe, 0x96, 0xf4, 0x2e, 0x2d, 0x4f, 0x29, + 0x65, 0x7c, 0x8e, 0x5a, 0x26, 0x68, 0x3d, 0x99, 0x5e, 0xde, 0x7d, 0xf8, 0x9b, 0xd1, 0x2f, 0x25, 0x8d, 0xd4, 0xcd, + 0x7f, 0xdb, 0xee, 0xe0, 0x3e, 0x48, 0xa2, 0xab, 0x20, 0x4e, 0x49, 0xe5, 0x9d, 0x62, 0x94, 0xa7, 0x33, 0xcd, 0x64, + 0xfa, 0x55, 0xce, 0x12, 0xfa, 0xed, 0x1f, 0xb9, 0x14, 0xbb, 0x8f, 0xa6, 0x97, 0x6a, 0x35, 0x5a, 0x0b, 0x69, 0x55, + 0x7f, 0x68, 0xf6, 0xd4, 0xfa, 0x74, 0xad, 0x7a, 0x06, 0xd0, 0x43, 0x80, 0x41, 0xe8, 0xd9, 0x46, 0x2e, 0xa0, 0x6a, + 0x42, 0x89, 0x91, 0x3f, 0x56, 0x0d, 0x64, 0xf9, 0xbb, 0x20, 0xb9, 0xa3, 0x82, 0x75, 0xf0, 0xfd, 0xb0, 0xf1, 0x20, + 0x4a, 0xa4, 0x2e, 0x9f, 0xc4, 0xc3, 0x61, 0xc2, 0x3a, 0x4a, 0x5d, 0x5b, 0xad, 0x47, 0x98, 0x7e, 0x65, 0x2e, 0x59, + 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, 0xa7, 0x60, 0x3e, 0xe0, 0x4b, 0x5e, 0x57, 0x92, 0x53, 0xe6, 0x25, 0x35, + 0x2b, 0xe2, 0xd1, 0xf7, 0x3a, 0x2e, 0x0f, 0xc1, 0x76, 0xa1, 0x05, 0x6f, 0x76, 0x78, 0x36, 0x0d, 0x1a, 0xbb, 0x75, + 0x44, 0xb0, 0x4a, 0xa3, 0xe0, 0xad, 0x40, 0xcb, 0x43, 0x65, 0x25, 0x04, 0xb4, 0xe5, 0xb7, 0x64, 0x19, 0x0d, 0x80, + 0x2f, 0x12, 0xd5, 0x45, 0x65, 0x1d, 0x99, 0x7f, 0x9b, 0xdd, 0xf2, 0xd9, 0xea, 0xdd, 0xf2, 0x99, 0xda, 0x2d, 0x37, + 0x73, 0xec, 0xbd, 0x51, 0x0b, 0xff, 0xeb, 0x54, 0x08, 0xc1, 0xaa, 0x00, 0x39, 0x2c, 0x34, 0xd3, 0x1a, 0x6d, 0xf8, + 0x87, 0x86, 0xc6, 0x18, 0x74, 0x13, 0xf3, 0xc9, 0xbc, 0xa6, 0x85, 0x85, 0xf8, 0xd7, 0xac, 0x55, 0xb5, 0x1e, 0x60, + 0x1d, 0xf6, 0x7a, 0xb8, 0x5c, 0xd7, 0xbe, 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0x78, 0x0e, 0xd1, + 0xe9, 0x29, 0x94, 0x8e, 0xb2, 0xc1, 0xac, 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0x7a, 0x61, 0x1c, 0xd5, + 0x55, 0xe4, 0xf2, 0xa9, 0x11, 0xe6, 0x7a, 0x9d, 0x82, 0x02, 0x18, 0x93, 0x39, 0x6d, 0xff, 0xc1, 0x8a, 0x4d, 0xf0, + 0xef, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0xbd, 0xc4, 0xb8, 0x91, 0x08, 0xbf, 0x8a, 0x06, 0xe6, 0x1a, 0x36, 0x9f, 0xac, + 0x06, 0xf7, 0x48, 0xcd, 0xd4, 0x57, 0x4a, 0x41, 0xea, 0x1d, 0x30, 0x4a, 0xa3, 0x59, 0xc2, 0x6f, 0x1e, 0x75, 0x1d, + 0x67, 0x2c, 0x8d, 0x7a, 0x83, 0x40, 0xaf, 0xda, 0xde, 0x51, 0x4a, 0xdf, 0xfb, 0xec, 0x01, 0xfe, 0x27, 0xd2, 0x05, + 0xae, 0x2a, 0x53, 0x5d, 0xb8, 0xaa, 0x68, 0xaa, 0x4f, 0x6a, 0xb6, 0xb8, 0xd0, 0xe0, 0x64, 0x8e, 0xdf, 0xb5, 0x35, + 0x1a, 0x95, 0x77, 0x6a, 0x2e, 0x8d, 0xac, 0x5f, 0xd5, 0xfa, 0xd7, 0x0d, 0x7e, 0xc7, 0xb6, 0x03, 0x61, 0xb8, 0xd6, + 0xdb, 0xca, 0xdf, 0x61, 0x5a, 0x6a, 0xac, 0x28, 0x4e, 0xed, 0x27, 0xe1, 0x95, 0xf6, 0x50, 0xc4, 0xb9, 0x12, 0x3a, + 0x29, 0x13, 0xe1, 0xa4, 0xfc, 0x85, 0x87, 0xf7, 0xf1, 0x85, 0x84, 0xd6, 0xe5, 0x24, 0x49, 0xc1, 0x48, 0x1a, 0x73, + 0x3e, 0x0d, 0x76, 0x76, 0x2e, 0x2e, 0x2e, 0xfc, 0x8b, 0x5d, 0x3f, 0xcb, 0xcf, 0x76, 0xda, 0xcd, 0x66, 0x13, 0xdf, + 0x23, 0x67, 0x5b, 0xe7, 0x31, 0xbb, 0x78, 0x0a, 0x76, 0xb0, 0xfd, 0xd8, 0x7a, 0x62, 0x3d, 0xde, 0xb5, 0x1e, 0x3e, + 0xb2, 0x2d, 0x12, 0xe7, 0x50, 0xb2, 0x6b, 0x5b, 0x42, 0x9c, 0x87, 0x36, 0x14, 0x77, 0xf7, 0xce, 0x94, 0x45, 0x86, + 0xf7, 0x74, 0x84, 0xbd, 0x03, 0xce, 0x41, 0xf6, 0x89, 0xd5, 0x37, 0xae, 0x28, 0x6b, 0x48, 0xa5, 0xa0, 0x1e, 0x71, + 0xf7, 0x0e, 0xa2, 0x69, 0x40, 0x4c, 0x61, 0x16, 0x62, 0x0c, 0x46, 0x94, 0xd2, 0x14, 0x68, 0x65, 0x9e, 0xc2, 0x37, + 0x4c, 0xec, 0xb4, 0xe0, 0xfb, 0x9b, 0xf6, 0x63, 0xd0, 0x58, 0xe7, 0x8d, 0x07, 0x83, 0x66, 0xa3, 0x65, 0xb5, 0x1a, + 0x6d, 0xff, 0xb1, 0xd5, 0x16, 0xff, 0x82, 0xc4, 0xdb, 0xb5, 0x5a, 0xf0, 0x6d, 0xd7, 0x82, 0xe7, 0xf3, 0x07, 0xe2, + 0x00, 0x3a, 0xb2, 0x77, 0xba, 0x7b, 0xf8, 0xb3, 0x6a, 0x80, 0xd4, 0x67, 0xb6, 0xf8, 0x21, 0x48, 0xfb, 0x9e, 0x59, + 0xda, 0x7a, 0xb2, 0xb2, 0xb8, 0xfd, 0x78, 0x65, 0xf1, 0xee, 0xa3, 0x95, 0xc5, 0x0f, 0x1e, 0xd6, 0x8b, 0x77, 0xce, + 0x44, 0x95, 0xde, 0xe5, 0xa1, 0x3d, 0x89, 0x60, 0xd9, 0x2f, 0x9d, 0x16, 0xc0, 0xd9, 0xb4, 0x1a, 0xf8, 0xf1, 0xb8, + 0xed, 0xea, 0x5e, 0xa7, 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfd, 0x68, 0x80, 0xed, 0x08, 0x51, + 0xf8, 0x3b, 0xdf, 0x7d, 0x32, 0x00, 0xf9, 0x6e, 0xe1, 0x1f, 0xfc, 0x37, 0x7e, 0xd8, 0x1e, 0x88, 0x87, 0x26, 0xd6, + 0x7f, 0xd3, 0x7a, 0x5c, 0x40, 0x53, 0xfc, 0xef, 0x17, 0x6d, 0x10, 0xa3, 0x39, 0x6e, 0x8e, 0xfb, 0x00, 0x68, 0xf4, + 0x64, 0xdc, 0xf6, 0x3f, 0x3b, 0x7f, 0xec, 0x3f, 0x19, 0xb7, 0x1e, 0x7f, 0x23, 0x9e, 0x12, 0xa0, 0xe0, 0x67, 0xf8, + 0xf7, 0xcd, 0x6e, 0x13, 0xbc, 0x4b, 0xff, 0xc9, 0xf9, 0xae, 0xbf, 0x9b, 0x34, 0x1e, 0xf9, 0x4f, 0xf0, 0xaf, 0x1a, + 0x6e, 0x9c, 0x4d, 0x98, 0x6d, 0xe1, 0x7a, 0x2f, 0x78, 0x5b, 0xe6, 0x1c, 0xed, 0x07, 0xd6, 0xc3, 0x07, 0x2f, 0x9f, + 0xc0, 0x1a, 0x8d, 0x5b, 0x6d, 0xf8, 0x77, 0xdd, 0xd7, 0x6f, 0x90, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x86, 0xbd, 0x22, + 0x1c, 0xbd, 0xd3, 0xf0, 0xbe, 0x07, 0x0e, 0xd4, 0x6a, 0xef, 0x9a, 0xb1, 0xdb, 0x23, 0xa8, 0xec, 0x6e, 0xee, 0x35, + 0x63, 0x7f, 0xac, 0x7b, 0xcd, 0xd9, 0x42, 0x04, 0xf5, 0x92, 0x2f, 0x79, 0xd1, 0x8b, 0xae, 0xd7, 0x07, 0xee, 0x1c, + 0xfd, 0x85, 0xf7, 0xf1, 0x36, 0x09, 0xb4, 0x8e, 0x99, 0x19, 0x6c, 0xc8, 0x70, 0x23, 0xe3, 0x8f, 0x2b, 0xd2, 0xdd, + 0x9f, 0x75, 0x04, 0xc9, 0x6f, 0x27, 0xc8, 0x37, 0x77, 0xa3, 0x47, 0xfe, 0x07, 0xd3, 0xa3, 0x30, 0xe9, 0x51, 0x0b, + 0xe7, 0x92, 0x3b, 0x4b, 0xee, 0xe8, 0x01, 0x3d, 0x3b, 0x98, 0x84, 0xbd, 0x6d, 0xef, 0x30, 0x2c, 0x2a, 0x6c, 0x71, + 0x88, 0xf0, 0xf4, 0xd7, 0xc4, 0x9f, 0xc5, 0x8d, 0x8b, 0xd0, 0x96, 0xbe, 0xff, 0x14, 0xdf, 0xdb, 0xad, 0x1e, 0xce, + 0xc5, 0xad, 0xbe, 0x90, 0xae, 0xe4, 0x3e, 0xd4, 0x71, 0x03, 0xbc, 0x04, 0x13, 0xce, 0x33, 0x1e, 0xe1, 0x0f, 0xc3, + 0x01, 0xb9, 0xe9, 0x27, 0xe4, 0x62, 0x9e, 0x30, 0x3c, 0x24, 0x1f, 0x88, 0x77, 0x28, 0xc3, 0x57, 0x79, 0xdd, 0x16, + 0x6f, 0x71, 0x7c, 0x8d, 0x37, 0x50, 0x54, 0x60, 0x7a, 0x82, 0x2e, 0xf5, 0x1b, 0x36, 0x8c, 0x23, 0xc7, 0x76, 0xa6, + 0xb0, 0x91, 0x61, 0x96, 0x46, 0xed, 0xfa, 0x07, 0xdd, 0xfc, 0x70, 0x6d, 0xf5, 0xeb, 0x64, 0x39, 0xbe, 0xed, 0x31, + 0x3c, 0x92, 0x41, 0x2d, 0x5b, 0x9a, 0xf9, 0x30, 0xbe, 0x2a, 0xc9, 0x51, 0xa2, 0x57, 0xa6, 0x81, 0x2d, 0x6c, 0x83, + 0x96, 0xdf, 0x06, 0x5f, 0x81, 0x8a, 0xf1, 0xed, 0x79, 0xdf, 0x39, 0x8d, 0x5d, 0xb0, 0x5d, 0x8c, 0x6e, 0x7a, 0xa0, + 0xbe, 0xfe, 0xb1, 0x2b, 0xfd, 0x83, 0x8c, 0xf5, 0x3b, 0x33, 0xb6, 0xe0, 0x88, 0x7b, 0x02, 0x77, 0x5b, 0xbc, 0xa5, + 0x84, 0xa8, 0x47, 0x77, 0x46, 0xa1, 0xcc, 0x31, 0x7f, 0x98, 0x4f, 0xbc, 0x9d, 0x4f, 0xfc, 0x06, 0x67, 0x59, 0x35, + 0xe1, 0xee, 0x9c, 0x02, 0xef, 0x98, 0x64, 0x8c, 0x57, 0x75, 0x31, 0x0e, 0x1b, 0x1a, 0x34, 0xc5, 0x67, 0xb7, 0x46, + 0x64, 0xee, 0x69, 0x80, 0x88, 0xc0, 0xa1, 0xfc, 0xac, 0x8a, 0xd5, 0x17, 0x19, 0x5d, 0x01, 0xb7, 0x1d, 0x7f, 0xf9, + 0x88, 0x3e, 0x96, 0x62, 0x37, 0xe2, 0xec, 0x60, 0xa1, 0xb4, 0x1a, 0xaa, 0x8a, 0xd1, 0x14, 0x4f, 0xaf, 0x0e, 0xe5, + 0x6b, 0x3f, 0x6c, 0x0c, 0x81, 0x52, 0xe8, 0xbb, 0x7a, 0xe5, 0xe0, 0x36, 0xa8, 0x46, 0xfa, 0x21, 0x60, 0xca, 0x60, + 0x42, 0xed, 0x87, 0xb7, 0x6e, 0x2c, 0xe9, 0xf3, 0x84, 0xb6, 0xd0, 0x7d, 0x43, 0x76, 0x1e, 0x0f, 0xa4, 0x0a, 0xf3, + 0x2c, 0x79, 0x5b, 0xb0, 0x41, 0x4b, 0x13, 0xb6, 0x3c, 0xe1, 0xf5, 0xc3, 0x03, 0xea, 0xe3, 0x30, 0xcd, 0xec, 0xee, + 0xfd, 0xce, 0x3a, 0xe2, 0xe3, 0xaf, 0x12, 0x1f, 0x81, 0x97, 0xf9, 0xb7, 0xe1, 0x7d, 0xfc, 0x5d, 0xe2, 0xfb, 0x7d, + 0xdb, 0xf5, 0x49, 0x01, 0xdc, 0xaf, 0x7e, 0x9c, 0x18, 0xa5, 0xdf, 0x36, 0xe8, 0x6a, 0xef, 0xae, 0x4a, 0x5b, 0x2a, + 0xe8, 0xf6, 0xc3, 0x4a, 0x41, 0xc3, 0x77, 0x43, 0x22, 0x83, 0xb2, 0x68, 0xfb, 0x0f, 0x0d, 0xb1, 0x7f, 0xde, 0xc0, + 0xcf, 0x9a, 0xe0, 0x7f, 0x00, 0x0d, 0x94, 0xe4, 0x7f, 0x0d, 0xcd, 0x77, 0x85, 0x92, 0x81, 0x7e, 0xdf, 0x93, 0x58, + 0x96, 0x22, 0xb9, 0xb6, 0x0d, 0x56, 0x9c, 0xc6, 0x88, 0x6c, 0x2c, 0xdb, 0x73, 0xf4, 0x2f, 0x1e, 0xc9, 0x5d, 0x29, + 0xe3, 0x40, 0xcf, 0xa1, 0xaf, 0xa3, 0xdf, 0xe4, 0xbf, 0xaa, 0xce, 0xab, 0x49, 0x89, 0x15, 0x53, 0xe0, 0xbe, 0x5e, + 0x38, 0xf1, 0xe9, 0x88, 0x2b, 0x0c, 0xfa, 0x55, 0x40, 0xeb, 0x19, 0x5a, 0xde, 0x75, 0x70, 0x0d, 0x11, 0xc1, 0xe8, + 0x6d, 0xc3, 0x34, 0xc9, 0xab, 0x61, 0xb9, 0x38, 0x3f, 0xa6, 0x83, 0xe5, 0x99, 0x71, 0xa7, 0x50, 0x46, 0xef, 0x30, + 0x59, 0x74, 0x18, 0xe7, 0xf4, 0x62, 0x04, 0x05, 0x7a, 0x2d, 0x02, 0x58, 0x51, 0x89, 0xa4, 0x04, 0x2b, 0x7a, 0x36, + 0x16, 0xd9, 0x81, 0x4d, 0xe1, 0x23, 0xdb, 0x7c, 0xdd, 0xbe, 0x79, 0x73, 0x9d, 0x38, 0x99, 0x12, 0xbb, 0x71, 0xaf, + 0x22, 0x7d, 0x6c, 0x90, 0xb6, 0x6b, 0x77, 0x09, 0xd9, 0x60, 0x88, 0x6b, 0xf5, 0xfb, 0x72, 0xa6, 0x00, 0xb2, 0x4d, + 0x42, 0xeb, 0x71, 0x89, 0x84, 0xae, 0xa4, 0xd3, 0x29, 0x8b, 0xb8, 0x1f, 0xa5, 0x22, 0x0b, 0xc1, 0x10, 0x53, 0x5e, + 0x8b, 0xed, 0xba, 0x25, 0xc8, 0x46, 0x23, 0x6f, 0x42, 0xee, 0x6e, 0x28, 0x54, 0x17, 0x3d, 0x18, 0xaf, 0xe5, 0xb3, + 0x8e, 0xdb, 0xdd, 0x77, 0x87, 0xfb, 0x96, 0xd8, 0x94, 0x7b, 0x3b, 0xf0, 0xb8, 0x47, 0xfe, 0xb8, 0x48, 0xde, 0x0f, + 0x45, 0xf2, 0xbe, 0x25, 0x6f, 0x71, 0x50, 0x86, 0xe3, 0x8e, 0x40, 0xdb, 0xb6, 0x58, 0x3a, 0x10, 0x81, 0xc4, 0x09, + 0xf8, 0x2c, 0x31, 0xbe, 0xa2, 0x71, 0x07, 0xbb, 0x36, 0x70, 0xc1, 0x80, 0x9b, 0x45, 0xd4, 0x51, 0xd9, 0x35, 0x3c, + 0x55, 0x61, 0x47, 0xb0, 0x46, 0x98, 0xca, 0x40, 0x94, 0x43, 0xe9, 0xe4, 0xc5, 0xe5, 0xd6, 0xc5, 0xec, 0x74, 0x02, + 0x72, 0x52, 0xe5, 0x10, 0x7e, 0x94, 0x1d, 0xf6, 0x68, 0xaa, 0xee, 0x49, 0x29, 0xe3, 0xa2, 0xea, 0xf5, 0xf9, 0x0b, + 0x3f, 0x35, 0x2c, 0xb0, 0x97, 0x7a, 0x01, 0xb3, 0xf0, 0xc7, 0xbb, 0x5d, 0x1d, 0x89, 0x34, 0xeb, 0x4a, 0x40, 0x7d, + 0xb7, 0x7b, 0x12, 0x4c, 0xe5, 0x78, 0xaf, 0xb3, 0xa5, 0x9f, 0x2d, 0xd6, 0x72, 0xb2, 0x47, 0xd9, 0xa9, 0xe2, 0x6a, + 0x93, 0x04, 0x18, 0x56, 0x10, 0x60, 0x92, 0x26, 0x80, 0x45, 0xe7, 0xaa, 0xf6, 0xc3, 0xa6, 0x4a, 0x78, 0x85, 0x32, + 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0x98, 0x3b, 0x6e, 0x75, 0xf7, 0x22, 0x69, 0x5c, 0xa2, 0xf0, 0x28, 0x40, + 0x7a, 0x40, 0x67, 0xb4, 0xe0, 0xfc, 0x38, 0xdb, 0xb9, 0x60, 0xa7, 0x8d, 0x68, 0x1a, 0x57, 0x91, 0x53, 0x34, 0x35, + 0xf4, 0x94, 0x59, 0x35, 0x13, 0x7e, 0x8d, 0x16, 0x90, 0x24, 0xc1, 0x5d, 0xca, 0xb0, 0x2c, 0x59, 0xe8, 0xc0, 0x42, + 0x40, 0x61, 0x92, 0xeb, 0x2a, 0x7c, 0x2b, 0x35, 0x6e, 0x69, 0x77, 0xff, 0xfa, 0x8f, 0xff, 0x5b, 0x46, 0x64, 0x81, + 0x2a, 0x2d, 0x35, 0xd6, 0x02, 0xa1, 0xcb, 0x3d, 0xba, 0xb5, 0xa2, 0x8f, 0x10, 0xd9, 0x25, 0xb8, 0xf6, 0xf1, 0xb0, + 0x31, 0x8e, 0x92, 0x11, 0x00, 0xb6, 0x96, 0x40, 0x66, 0x52, 0xb8, 0x84, 0xba, 0x5e, 0x84, 0x2c, 0xf8, 0x9b, 0xd2, + 0x9b, 0x55, 0x96, 0x2c, 0xed, 0x56, 0x33, 0xd9, 0xb9, 0xda, 0x50, 0xb5, 0x84, 0x67, 0xf5, 0xdb, 0x7d, 0x4a, 0xa8, + 0xd5, 0xf2, 0x9c, 0xa1, 0xa5, 0x3e, 0x02, 0xf9, 0xd7, 0x7f, 0xfa, 0xbb, 0xff, 0xa1, 0x1e, 0xf1, 0x64, 0xe3, 0xaf, + 0xff, 0xf0, 0x9f, 0x31, 0x1b, 0xd3, 0xd2, 0xa7, 0x1f, 0x24, 0x27, 0xac, 0xea, 0xe8, 0x43, 0x08, 0x0c, 0x0b, 0x53, + 0x9d, 0x26, 0x20, 0x06, 0xe3, 0x41, 0x3d, 0xf3, 0xf9, 0x80, 0x26, 0xa4, 0xcd, 0x26, 0xa1, 0xa3, 0x4d, 0x5b, 0x56, + 0x3c, 0x52, 0x23, 0x39, 0xf1, 0x22, 0x54, 0x22, 0xbd, 0xef, 0x74, 0xfb, 0xc3, 0xd7, 0xab, 0x31, 0x57, 0xf1, 0x3e, + 0x2c, 0x29, 0xab, 0x72, 0x0b, 0x03, 0xf1, 0x73, 0x7c, 0x0c, 0xda, 0x46, 0x31, 0x2d, 0x5e, 0xad, 0x4f, 0xe7, 0xa7, + 0x19, 0xc0, 0x3f, 0x42, 0x8a, 0x8b, 0xa8, 0x22, 0x9d, 0x79, 0x36, 0xd0, 0xe6, 0x4b, 0xae, 0x4a, 0x1a, 0x45, 0x38, + 0x8a, 0x0f, 0x9e, 0xfc, 0x4d, 0xf9, 0xe7, 0x09, 0x5a, 0x56, 0x96, 0x33, 0x89, 0x2e, 0xa5, 0xfb, 0xf8, 0xa8, 0xd9, + 0x9c, 0x5e, 0xba, 0xf3, 0x6a, 0x06, 0x6f, 0xdd, 0x64, 0x14, 0x89, 0x34, 0x07, 0xa4, 0xc3, 0x52, 0x1d, 0xf4, 0x04, + 0x8f, 0xa9, 0x89, 0x31, 0xb2, 0xb2, 0xfc, 0xd3, 0x9c, 0xe2, 0x6e, 0xf1, 0x2f, 0x78, 0xa8, 0x29, 0x43, 0x94, 0x50, + 0x62, 0x60, 0x31, 0x37, 0x7a, 0xb5, 0x45, 0xaf, 0x71, 0x6b, 0xf9, 0xea, 0x83, 0x79, 0x28, 0x6b, 0x1e, 0xa7, 0x3e, + 0xc0, 0x03, 0xd2, 0x71, 0xcb, 0x1b, 0xb7, 0xe7, 0x7a, 0x78, 0xce, 0xb3, 0x89, 0x79, 0x0a, 0xcb, 0x22, 0x36, 0x60, + 0x23, 0x15, 0xda, 0x95, 0xf5, 0xe2, 0x84, 0xb5, 0x1c, 0xef, 0xae, 0x98, 0x4b, 0x82, 0x44, 0xa7, 0xaf, 0x00, 0xcf, + 0x3d, 0xdc, 0x80, 0x40, 0xff, 0x2c, 0xe2, 0x01, 0xf1, 0x6b, 0xc7, 0x3c, 0xcb, 0x8d, 0x50, 0xca, 0x64, 0x73, 0x03, + 0x9e, 0x8e, 0x68, 0x8a, 0x41, 0xd6, 0xfa, 0xd5, 0x93, 0xd2, 0xa7, 0xee, 0xe6, 0x50, 0x22, 0x46, 0xf3, 0x8d, 0x3c, + 0x22, 0x7d, 0x5a, 0x0b, 0x6e, 0x48, 0x15, 0xd3, 0x76, 0xbd, 0x95, 0xf5, 0x42, 0x53, 0x8b, 0xda, 0x6f, 0xb8, 0x63, + 0x13, 0x98, 0xf6, 0x62, 0x2b, 0x2a, 0xc4, 0x56, 0x4f, 0xc3, 0x6f, 0xb4, 0xeb, 0x13, 0x4d, 0xa7, 0xd4, 0xd0, 0x05, + 0x26, 0x26, 0x83, 0x15, 0x65, 0x07, 0x1d, 0xff, 0x8b, 0xd3, 0x76, 0xd9, 0x46, 0x6e, 0x04, 0xf1, 0x4d, 0x9e, 0xc3, + 0xe3, 0xaf, 0xae, 0x74, 0xff, 0x1f, 0x1c, 0x1d, 0xa5, 0x5f, 0x1b, 0x82, 0x00, 0x00}; } // namespace web_server } // namespace esphome From 98277f6cebfd03c5cc00517727fd1839f1338162 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:03:58 +1200 Subject: [PATCH 0182/2607] Bump version to 2023.6.4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 0d5b211c18..d8eda3fd63 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.3" +__version__ = "2023.6.4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From fd9cca565bc0a702b60d856fc86d6055b7e76140 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:02:53 +1200 Subject: [PATCH 0183/2607] Log component long time message at warning level (#5048) --- esphome/core/component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 49ef8ecde7..ae85d55498 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -201,8 +201,8 @@ WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() { uint32_t now = millis(); if (now - started_ > 50) { const char *src = component_ == nullptr ? "" : component_->get_component_source(); - ESP_LOGV(TAG, "Component %s took a long time for an operation (%.2f s).", src, (now - started_) / 1e3f); - ESP_LOGV(TAG, "Components should block for at most 20-30ms."); + ESP_LOGW(TAG, "Component %s took a long time for an operation (%.2f s).", src, (now - started_) / 1e3f); + ESP_LOGW(TAG, "Components should block for at most 20-30ms."); ; } } From 45c72f1f2220e2e9cd63e0fac40f74b0a46c7670 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:26:31 +1200 Subject: [PATCH 0184/2607] Log start of i2c setup (#5049) --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index 51688322f6..24c1860e6f 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -14,6 +14,7 @@ namespace i2c { static const char *const TAG = "i2c.idf"; void IDFI2CBus::setup() { + ESP_LOGCONFIG(TAG, "Setting up I2C bus..."); static i2c_port_t next_port = 0; port_ = next_port++; From fc3d558d479ec4a3a7a8118979b4bee92d4d2cfc Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 5 Jul 2023 00:28:12 +0200 Subject: [PATCH 0185/2607] Initial debug component support for rp2040 (#5056) --- esphome/components/debug/__init__.py | 1 - esphome/components/debug/debug_component.cpp | 13 ++++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/esphome/components/debug/__init__.py b/esphome/components/debug/__init__.py index 9742b3b19e..1955b5d22c 100644 --- a/esphome/components/debug/__init__.py +++ b/esphome/components/debug/__init__.py @@ -38,7 +38,6 @@ CONFIG_SCHEMA = cv.All( ), } ).extend(cv.polling_component_schema("60s")), - cv.only_on(["esp32", "esp8266"]), ) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 9b7e256147..8b6a97068b 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -22,8 +22,12 @@ #endif // USE_ESP32 #ifdef USE_ARDUINO +#ifdef USE_RP2040 +#include +#else #include #endif +#endif namespace esphome { namespace debug { @@ -35,6 +39,8 @@ static uint32_t get_free_heap() { return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) #elif defined(USE_ESP32) return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +#elif defined(USE_RP2040) + return rp2040.getFreeHeap(); #endif } @@ -65,7 +71,7 @@ void DebugComponent::dump_config() { this->free_heap_ = get_free_heap(); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); -#ifdef USE_ARDUINO +#if defined(USE_ARDUINO) && !defined(USE_RP2040) const char *flash_mode; switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) case FM_QIO: @@ -274,6 +280,11 @@ void DebugComponent::dump_config() { reset_reason = ESP.getResetReason().c_str(); #endif +#ifdef USE_RP2040 + ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu()); + device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); +#endif // USE_RP2040 + #ifdef USE_TEXT_SENSOR if (this->device_info_ != nullptr) { if (device_info.length() > 255) From 22a1134f0ee87ee3c462abfcac9d38d4dc15fba8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 5 Jul 2023 10:31:58 +1200 Subject: [PATCH 0186/2607] Fix when idf component has broken symlinks (#5058) --- esphome/components/esp32/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 3ca140f0d4..903031c77a 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -547,6 +547,8 @@ def copy_files(): CORE.relative_build_path(f"components/{name}"), dirs_exist_ok=True, ignore=shutil.ignore_patterns(".git", ".github"), + symlinks=True, + ignore_dangling_symlinks=True, ) dir = os.path.dirname(__file__) From fe0404a084fbbf068c502a1816548884c674289f Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 5 Jul 2023 00:33:46 +0200 Subject: [PATCH 0187/2607] Some tests wasn't running (locally) (#5050) --- script/test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script/test b/script/test index 36be9118ed..36a58cd75a 100755 --- a/script/test +++ b/script/test @@ -9,6 +9,9 @@ set -x esphome compile tests/test1.yaml esphome compile tests/test2.yaml esphome compile tests/test3.yaml +esphome compile tests/test3.1.yaml esphome compile tests/test4.yaml esphome compile tests/test5.yaml +esphome compile tests/test6.yaml +esphome compile tests/test7.yaml esphome compile tests/test8.yaml From 5bf2fa5c56be1dc6c121a8e6153ae954aaa133e4 Mon Sep 17 00:00:00 2001 From: lnicolas83 Date: Wed, 5 Jul 2023 02:21:26 +0200 Subject: [PATCH 0188/2607] [ILI9xxx] Add ili9488_a (alternative gamma configuration for ILI9488) (#5027) * Add ili9488_a * Fix clang-tidy --- esphome/components/ili9xxx/display.py | 1 + .../components/ili9xxx/ili9xxx_display.cpp | 11 ++++++ esphome/components/ili9xxx/ili9xxx_display.h | 6 ++++ esphome/components/ili9xxx/ili9xxx_init.h | 34 +++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 29603eb30f..89676ddb9a 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -43,6 +43,7 @@ MODELS = { "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI), "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), + "ILI9488_A": ili9XXX_ns.class_("ILI9XXXILI9488A", ili9XXXSPI), "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), "S3BOX": ili9XXX_ns.class_("ILI9XXXS3Box", ili9XXXSPI), "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 6fc6da3cdb..82217f8e40 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -411,6 +411,17 @@ void ILI9XXXILI9488::initialize() { this->is_18bitdisplay_ = true; } // 40_TFT display +void ILI9XXXILI9488A::initialize() { + this->init_lcd_(INITCMD_ILI9488_A); + if (this->width_ == 0) { + this->width_ = 480; + } + if (this->height_ == 0) { + this->height_ = 320; + } + this->is_18bitdisplay_ = true; +} +// 40_TFT display void ILI9XXXST7796::initialize() { this->init_lcd_(INITCMD_ST7796); if (this->width_ == 0) { diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index dc7bfdc6eb..9133c66a5b 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -128,6 +128,12 @@ class ILI9XXXILI9488 : public ILI9XXXDisplay { void initialize() override; }; +//----------- ILI9XXX_35_TFT origin colors rotated display -------------- +class ILI9XXXILI9488A : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + //----------- ILI9XXX_35_TFT rotated display -------------- class ILI9XXXST7796 : public ILI9XXXDisplay { protected: diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 15fbf92659..1856fb06ab 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -139,6 +139,40 @@ static const uint8_t PROGMEM INITCMD_ILI9488[] = { + // 5 frames + //ILI9XXX_ETMOD, 1, 0xC6, // + + + ILI9XXX_SLPOUT, 0x80, // Exit sleep mode + //ILI9XXX_INVON , 0, + ILI9XXX_DISPON, 0x80, // Set display on + 0x00 // end +}; + +static const uint8_t PROGMEM INITCMD_ILI9488_A[] = { + ILI9XXX_GMCTRP1,15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F, + ILI9XXX_GMCTRN1,15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F, + + ILI9XXX_PWCTR1, 2, 0x17, 0x15, // VRH1 VRH2 + ILI9XXX_PWCTR2, 1, 0x41, // VGH, VGL + ILI9XXX_VMCTR1, 3, 0x00, 0x12, 0x80, // nVM VCM_REG VCM_REG_EN + + ILI9XXX_IFMODE, 1, 0x00, + ILI9XXX_FRMCTR1, 1, 0xA0, // Frame rate = 60Hz + ILI9XXX_INVCTR, 1, 0x02, // Display Inversion Control = 2dot + + ILI9XXX_DFUNCTR, 2, 0x02, 0x02, // Nomal scan + + 0xE9, 1, 0x00, // Set Image Functio. Disable 24 bit data + + ILI9XXX_ADJCTL3, 4, 0xA9, 0x51, 0x2C, 0x82, // Adjust Control 3 + + ILI9XXX_MADCTL, 1, 0x28, + //ILI9XXX_PIXFMT, 1, 0x55, // Interface Pixel Format = 16bit + ILI9XXX_PIXFMT, 1, 0x66, //ILI9488 only supports 18-bit pixel format in 4/3 wire SPI mode + + + // 5 frames //ILI9XXX_ETMOD, 1, 0xC6, // From a326dcaf0ef71ca56ab567414ca26990f9c48ec3 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 5 Jul 2023 09:53:14 +0200 Subject: [PATCH 0189/2607] [ili9xxx] Allow config of spi data rate. (#4701) * Allow 80MHz ili9xxx display. * python foo. * update based on feedback. * Change python --------- Co-authored-by: Your Name --- esphome/components/ili9xxx/display.py | 5 +++++ esphome/components/ili9xxx/ili9xxx_display.h | 6 +++++- esphome/components/spi/__init__.py | 16 ++++++++++++++++ esphome/components/spi/spi.h | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 89676ddb9a..6021da5eeb 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_PAGES, CONF_RESET_PIN, CONF_DIMENSIONS, + CONF_DATA_RATE, ) DEPENDENCIES = ["spi"] @@ -98,6 +99,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( cv.file_ ), + cv.Optional(CONF_DATA_RATE, default="40MHz"): spi.SPI_DATA_RATE_SCHEMA, } ) .extend(cv.polling_component_schema("1s")) @@ -176,3 +178,6 @@ async def to_code(config): if rhs is not None: prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) + + spi_data_rate = str(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]]) + cg.add_define("ILI9XXXDisplay_DATA_RATE", cg.RawExpression(spi_data_rate)) diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 9133c66a5b..15b08e6c76 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -15,10 +15,14 @@ enum ILI9XXXColorMode { BITS_16 = 0x10, }; +#ifndef ILI9XXXDisplay_DATA_RATE +#define ILI9XXXDisplay_DATA_RATE spi::DATA_RATE_40MHZ +#endif // ILI9XXXDisplay_DATA_RATE + class ILI9XXXDisplay : public PollingComponent, public display::DisplayBuffer, public spi::SPIDevice { + spi::CLOCK_PHASE_LEADING, ILI9XXXDisplay_DATA_RATE> { public: void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index e0fc9efb42..1528a05734 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -16,6 +16,22 @@ CODEOWNERS = ["@esphome/core"] spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") +SPIDataRate = spi_ns.enum("SPIDataRate") + +SPI_DATA_RATE_OPTIONS = { + 80e6: SPIDataRate.DATA_RATE_80MHZ, + 40e6: SPIDataRate.DATA_RATE_40MHZ, + 20e6: SPIDataRate.DATA_RATE_20MHZ, + 10e6: SPIDataRate.DATA_RATE_10MHZ, + 5e6: SPIDataRate.DATA_RATE_5MHZ, + 2e6: SPIDataRate.DATA_RATE_2MHZ, + 1e6: SPIDataRate.DATA_RATE_1MHZ, + 2e5: SPIDataRate.DATA_RATE_200KHZ, + 75e3: SPIDataRate.DATA_RATE_75KHZ, + 1e3: SPIDataRate.DATA_RATE_1KHZ, +} +SPI_DATA_RATE_SCHEMA = cv.All(cv.frequency, cv.enum(SPI_DATA_RATE_OPTIONS)) + MULTI_CONF = True CONF_FORCE_SW = "force_sw" diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index bacdad723b..f19518caae 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -67,6 +67,7 @@ enum SPIDataRate : uint32_t { DATA_RATE_10MHZ = 10000000, DATA_RATE_20MHZ = 20000000, DATA_RATE_40MHZ = 40000000, + DATA_RATE_80MHZ = 80000000, }; class SPIComponent : public Component { From 979f0147997080d4fdd178abb4b3e80795297aa9 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 5 Jul 2023 12:05:27 +0200 Subject: [PATCH 0190/2607] Make scheduler debuging work with idf >= 5 (#5052) --- esphome/core/scheduler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index ab60f83ba5..012c9af3c6 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -154,16 +154,16 @@ void HOT Scheduler::call() { if (now - last_print > 2000) { last_print = now; std::vector> old_items; - ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now); + ESP_LOGVV(TAG, "Items: count=%u, now=%" PRIu32, this->items_.size(), now); while (!this->empty_()) { this->lock_.lock(); auto item = std::move(this->items_[0]); this->pop_raw_(); this->lock_.unlock(); - ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u (%u)", item->get_type_str(), - item->name.c_str(), item->interval, item->last_execution, item->last_execution_major, - item->next_execution(), item->next_execution_major()); + ESP_LOGVV(TAG, " %s '%s' interval=%" PRIu32 " last_execution=%" PRIu32 " (%u) next=%" PRIu32 " (%u)", + item->get_type_str(), item->name.c_str(), item->interval, item->last_execution, + item->last_execution_major, item->next_execution(), item->next_execution_major()); old_items.push_back(std::move(item)); } From 301a78f983777ceb3dc71ab994c28886bb12c2dd Mon Sep 17 00:00:00 2001 From: Tobias Oort Date: Wed, 5 Jul 2023 21:32:00 +0200 Subject: [PATCH 0191/2607] Adds 1.54" e-ink display (gdew0154m09) support to waveshare_epaper component (#4939) * Added GDEW0154M09 in waveshare_epaper component * noop change - trigger workflow * Make linter happy * Update test4.yaml * linter doing linty things * revert the newline removal. * revert to prove unstable test * add code back into test. * no partial updates supported yet - removed from test. * Update esphome/components/waveshare_epaper/waveshare_epaper.cpp Co-authored-by: Keith Burzinski --------- Co-authored-by: Keith Burzinski --- .../components/waveshare_epaper/display.py | 2 + .../waveshare_epaper/waveshare_epaper.cpp | 140 ++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 40 +++++ tests/test4.yaml | 8 + 4 files changed, 190 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index d0276f119a..11deab5310 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -63,6 +63,7 @@ WaveshareEPaper7P5InHDB = waveshare_epaper_ns.class_( WaveshareEPaper2P13InDKE = waveshare_epaper_ns.class_( "WaveshareEPaper2P13InDKE", WaveshareEPaper ) +GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper) WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel") WaveshareEPaperTypeBModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeBModel") @@ -91,6 +92,7 @@ MODELS = { "7.50inv2alt": ("b", WaveshareEPaper7P5InV2alt), "7.50in-hd-b": ("b", WaveshareEPaper7P5InHDB), "2.13in-ttgo-dke": ("c", WaveshareEPaper2P13InDKE), + "1.54in-m5coreink-m09": ("c", GDEW0154M09), } diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 42f5bc54e3..d64a5500dd 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -763,6 +763,146 @@ void GDEY029T94::dump_config() { LOG_UPDATE_INTERVAL(this); } +// ======================================================== +// Good Display 1.54in black/white/grey GDEW0154M09 +// As used in M5Stack Core Ink +// Datasheet: +// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEW0154M09-200709.pdf +// - https://github.com/m5stack/M5Core-Ink +// Reference code from GoodDisplay: +// - https://github.com/GoodDisplay/E-paper-Display-Library-of-GoodDisplay/ +// -> /Monochrome_E-paper-Display/1.54inch_JD79653_GDEW0154M09_200x200/ESP32-Arduino%20IDE/GDEW0154M09_Arduino.ino +// M5Stack Core Ink spec: +// - https://docs.m5stack.com/en/core/coreink +// ======================================================== + +void GDEW0154M09::initialize() { + this->init_internal_(); + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->lastbuff_ = allocator.allocate(this->get_buffer_length_()); + if (this->lastbuff_ != nullptr) { + memset(this->lastbuff_, 0xff, sizeof(uint8_t) * this->get_buffer_length_()); + } + this->clear_(); +} + +void GDEW0154M09::reset_() { + // RST is inverse from other einks in this project + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(false); + delay(10); + this->reset_pin_->digital_write(true); + delay(10); + } +} + +void GDEW0154M09::init_internal_() { + this->reset_(); + + // clang-format off + // 200x200 resolution: 11 + // LUT from OTP: 0 + // B/W mode (doesn't work): 1 + // scan-up: 1 + // shift-right: 1 + // booster ON: 1 + // no soft reset: 1 + const uint8_t panel_setting_1 = 0b11011111; + + // VCOM status off 0 + // Temp sensing default 1 + // VGL Power Off Floating 1 + // NORG expect refresh 1 + // VCOM Off on displ off 0 + const uint8_t panel_setting_2 = 0b01110; + + const uint8_t wf_t0154_cz_b3_list[] = { + 11, // 11 commands in list + CMD_PSR_PANEL_SETTING, 2, panel_setting_1, panel_setting_2, + CMD_UNDOCUMENTED_0x4D, 1, 0x55, + CMD_UNDOCUMENTED_0xAA, 1, 0x0f, + CMD_UNDOCUMENTED_0xE9, 1, 0x02, + CMD_UNDOCUMENTED_0xB6, 1, 0x11, + CMD_UNDOCUMENTED_0xF3, 1, 0x0a, + CMD_TRES_RESOLUTION_SETTING, 3, 0xc8, 0x00, 0xc8, + CMD_TCON_TCONSETTING, 1, 0x00, + CMD_CDI_VCOM_DATA_INTERVAL, 1, 0xd7, + CMD_PWS_POWER_SAVING, 1, 0x00, + CMD_PON_POWER_ON, 0 + }; + // clang-format on + + this->write_init_list_(wf_t0154_cz_b3_list); + delay(100); // NOLINT + this->wait_until_idle_(); +} + +void GDEW0154M09::write_init_list_(const uint8_t *list) { + uint8_t list_limit = list[0]; + uint8_t *start_ptr = ((uint8_t *) list + 1); + for (uint8_t i = 0; i < list_limit; i++) { + this->command(*(start_ptr + 0)); + for (uint8_t dnum = 0; dnum < *(start_ptr + 1); dnum++) { + this->data(*(start_ptr + 2 + dnum)); + } + start_ptr += (*(start_ptr + 1) + 2); + } +} + +void GDEW0154M09::clear_() { + uint32_t pixsize = this->get_buffer_length_(); + for (uint8_t j = 0; j < 2; j++) { + this->command(CMD_DTM1_DATA_START_TRANS); + for (int count = 0; count < pixsize; count++) { + this->data(0x00); + } + this->command(CMD_DTM2_DATA_START_TRANS2); + for (int count = 0; count < pixsize; count++) { + this->data(0xff); + } + this->command(CMD_DISPLAY_REFRESH); + delay(10); + this->wait_until_idle_(); + } +} + +void HOT GDEW0154M09::display() { + this->init_internal_(); + // "Mode 0 display" for now + this->command(CMD_DTM1_DATA_START_TRANS); + for (int i = 0; i < this->get_buffer_length_(); i++) { + this->data(0xff); + } + this->command(CMD_DTM2_DATA_START_TRANS2); // write 'new' data to SRAM + for (int i = 0; i < this->get_buffer_length_(); i++) { + this->data(this->buffer_[i]); + } + this->command(CMD_DISPLAY_REFRESH); + delay(10); + this->wait_until_idle_(); + this->deep_sleep(); +} + +void GDEW0154M09::deep_sleep() { + // COMMAND DEEP SLEEP + this->command(CMD_POF_POWER_OFF); + this->wait_until_idle_(); + delay(1000); // NOLINT + this->command(CMD_DSLP_DEEP_SLEEP); + this->data(DATA_DSLP_DEEP_SLEEP); +} + +int GDEW0154M09::get_width_internal() { return 200; } +int GDEW0154M09::get_height_internal() { return 200; } +void GDEW0154M09::dump_config() { + LOG_DISPLAY("", "M5Stack CoreInk E-Paper (Good Display)", this); + ESP_LOGCONFIG(TAG, " Model: 1.54in Greyscale GDEW0154M09"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + static const uint8_t LUT_VCOM_DC_4_2[] = { 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 1cb46bdb9d..a84a1d4541 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -170,6 +170,46 @@ class GDEY029T94 : public WaveshareEPaper { int get_height_internal() override; }; +class GDEW0154M09 : public WaveshareEPaper { + public: + void initialize() override; + void display() override; + void dump_config() override; + void deep_sleep() override; + + protected: + int get_width_internal() override; + int get_height_internal() override; + + private: + static const uint8_t CMD_DTM1_DATA_START_TRANS = 0x10; + static const uint8_t CMD_DTM2_DATA_START_TRANS2 = 0x13; + static const uint8_t CMD_DISPLAY_REFRESH = 0x12; + static const uint8_t CMD_AUTO_SEQ = 0x17; + static const uint8_t DATA_AUTO_PON_DSR_POF_DSLP = 0xA7; + static const uint8_t CMD_PSR_PANEL_SETTING = 0x00; + static const uint8_t CMD_UNDOCUMENTED_0x4D = 0x4D; // NOLINT + static const uint8_t CMD_UNDOCUMENTED_0xAA = 0xaa; // NOLINT + static const uint8_t CMD_UNDOCUMENTED_0xE9 = 0xe9; // NOLINT + static const uint8_t CMD_UNDOCUMENTED_0xB6 = 0xb6; // NOLINT + static const uint8_t CMD_UNDOCUMENTED_0xF3 = 0xf3; // NOLINT + static const uint8_t CMD_TRES_RESOLUTION_SETTING = 0x61; + static const uint8_t CMD_TCON_TCONSETTING = 0x60; + static const uint8_t CMD_CDI_VCOM_DATA_INTERVAL = 0x50; + static const uint8_t CMD_POF_POWER_OFF = 0x02; + static const uint8_t CMD_DSLP_DEEP_SLEEP = 0x07; + static const uint8_t DATA_DSLP_DEEP_SLEEP = 0xA5; + static const uint8_t CMD_PWS_POWER_SAVING = 0xe3; + static const uint8_t CMD_PON_POWER_ON = 0x04; + static const uint8_t CMD_PTL_PARTIAL_WINDOW = 0x90; + + uint8_t *lastbuff_ = nullptr; + void reset_(); + void clear_(); + void write_init_list_(const uint8_t *list); + void init_internal_(); +}; + class WaveshareEPaper2P9InB : public WaveshareEPaper { public: void initialize() override; diff --git a/tests/test4.yaml b/tests/test4.yaml index 3c9f9f610c..2a8cb02413 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -504,6 +504,14 @@ display: full_update_every: 30 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: GPIO23 + dc_pin: GPIO23 + busy_pin: GPIO23 + reset_pin: GPIO23 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: inkplate6 id: inkplate_display greyscale: false From 677b2c6618fbaf6551efab88060a05013f32d566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Wed, 5 Jul 2023 21:33:26 +0200 Subject: [PATCH 0192/2607] display: split `DisplayBuffer` and `Display` (#5001) --- esphome/components/display/display.cpp | 343 +++++++++++ esphome/components/display/display.h | 575 ++++++++++++++++++ esphome/components/display/display_buffer.cpp | 339 +---------- esphome/components/display/display_buffer.h | 547 +---------------- esphome/components/font/font.cpp | 4 +- esphome/components/font/font.h | 4 +- esphome/components/graph/graph.cpp | 6 +- esphome/components/graph/graph.h | 8 +- esphome/components/image/image.cpp | 2 +- esphome/components/image/image.h | 2 +- esphome/components/qr_code/qr_code.cpp | 4 +- esphome/components/qr_code/qr_code.h | 4 +- .../components/touchscreen/touchscreen.cpp | 11 + esphome/components/touchscreen/touchscreen.h | 11 +- script/ci-custom.py | 2 +- 15 files changed, 960 insertions(+), 902 deletions(-) create mode 100644 esphome/components/display/display.cpp create mode 100644 esphome/components/display/display.h diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp new file mode 100644 index 0000000000..410ff58de3 --- /dev/null +++ b/esphome/components/display/display.cpp @@ -0,0 +1,343 @@ +#include "display.h" + +#include + +#include "esphome/core/log.h" + +namespace esphome { +namespace display { + +static const char *const TAG = "display"; + +const Color COLOR_OFF(0, 0, 0, 0); +const Color COLOR_ON(255, 255, 255, 255); + +void Display::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); } +void Display::clear() { this->fill(COLOR_OFF); } +void Display::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; } +void HOT Display::line(int x1, int y1, int x2, int y2, Color color) { + const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1; + const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1; + int32_t err = dx + dy; + + while (true) { + this->draw_pixel_at(x1, y1, color); + if (x1 == x2 && y1 == y2) + break; + int32_t e2 = 2 * err; + if (e2 >= dy) { + err += dy; + x1 += sx; + } + if (e2 <= dx) { + err += dx; + y1 += sy; + } + } +} +void HOT Display::horizontal_line(int x, int y, int width, Color color) { + // Future: Could be made more efficient by manipulating buffer directly in certain rotations. + for (int i = x; i < x + width; i++) + this->draw_pixel_at(i, y, color); +} +void HOT Display::vertical_line(int x, int y, int height, Color color) { + // Future: Could be made more efficient by manipulating buffer directly in certain rotations. + for (int i = y; i < y + height; i++) + this->draw_pixel_at(x, i, color); +} +void Display::rectangle(int x1, int y1, int width, int height, Color color) { + this->horizontal_line(x1, y1, width, color); + this->horizontal_line(x1, y1 + height - 1, width, color); + this->vertical_line(x1, y1, height, color); + this->vertical_line(x1 + width - 1, y1, height, color); +} +void Display::filled_rectangle(int x1, int y1, int width, int height, Color color) { + // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses. + for (int i = y1; i < y1 + height; i++) { + this->horizontal_line(x1, i, width, color); + } +} +void HOT Display::circle(int center_x, int center_xy, int radius, Color color) { + int dx = -radius; + int dy = 0; + int err = 2 - 2 * radius; + int e2; + + do { + this->draw_pixel_at(center_x - dx, center_xy + dy, color); + this->draw_pixel_at(center_x + dx, center_xy + dy, color); + this->draw_pixel_at(center_x + dx, center_xy - dy, color); + this->draw_pixel_at(center_x - dx, center_xy - dy, color); + e2 = err; + if (e2 < dy) { + err += ++dy * 2 + 1; + if (-dx == dy && e2 <= dx) { + e2 = 0; + } + } + if (e2 > dx) { + err += ++dx * 2 + 1; + } + } while (dx <= 0); +} +void Display::filled_circle(int center_x, int center_y, int radius, Color color) { + int dx = -int32_t(radius); + int dy = 0; + int err = 2 - 2 * radius; + int e2; + + do { + this->draw_pixel_at(center_x - dx, center_y + dy, color); + this->draw_pixel_at(center_x + dx, center_y + dy, color); + this->draw_pixel_at(center_x + dx, center_y - dy, color); + this->draw_pixel_at(center_x - dx, center_y - dy, color); + int hline_width = 2 * (-dx) + 1; + this->horizontal_line(center_x + dx, center_y + dy, hline_width, color); + this->horizontal_line(center_x + dx, center_y - dy, hline_width, color); + e2 = err; + if (e2 < dy) { + err += ++dy * 2 + 1; + if (-dx == dy && e2 <= dx) { + e2 = 0; + } + } + if (e2 > dx) { + err += ++dx * 2 + 1; + } + } while (dx <= 0); +} + +void Display::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) { + int x_start, y_start; + int width, height; + this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height); + font->print(x_start, y_start, this, color, text); +} +void Display::vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg) { + char buffer[256]; + int ret = vsnprintf(buffer, sizeof(buffer), format, arg); + if (ret > 0) + this->print(x, y, font, color, align, buffer); +} + +void Display::image(int x, int y, BaseImage *image, Color color_on, Color color_off) { + this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off); +} + +void Display::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) { + auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT))); + auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT))); + + switch (x_align) { + case ImageAlign::RIGHT: + x -= image->get_width(); + break; + case ImageAlign::CENTER_HORIZONTAL: + x -= image->get_width() / 2; + break; + case ImageAlign::LEFT: + default: + break; + } + + switch (y_align) { + case ImageAlign::BOTTOM: + y -= image->get_height(); + break; + case ImageAlign::CENTER_VERTICAL: + y -= image->get_height() / 2; + break; + case ImageAlign::TOP: + default: + break; + } + + image->draw(x, y, this, color_on, color_off); +} + +#ifdef USE_GRAPH +void Display::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); } +void Display::legend(int x, int y, graph::Graph *graph, Color color_on) { graph->draw_legend(this, x, y, color_on); } +#endif // USE_GRAPH + +#ifdef USE_QR_CODE +void Display::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) { + qr_code->draw(this, x, y, color_on, scale); +} +#endif // USE_QR_CODE + +void Display::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, + int *width, int *height) { + int x_offset, baseline; + font->measure(text, width, &x_offset, &baseline, height); + + auto x_align = TextAlign(int(align) & 0x18); + auto y_align = TextAlign(int(align) & 0x07); + + switch (x_align) { + case TextAlign::RIGHT: + *x1 = x - *width; + break; + case TextAlign::CENTER_HORIZONTAL: + *x1 = x - (*width) / 2; + break; + case TextAlign::LEFT: + default: + // LEFT + *x1 = x; + break; + } + + switch (y_align) { + case TextAlign::BOTTOM: + *y1 = y - *height; + break; + case TextAlign::BASELINE: + *y1 = y - baseline; + break; + case TextAlign::CENTER_VERTICAL: + *y1 = y - (*height) / 2; + break; + case TextAlign::TOP: + default: + *y1 = y; + break; + } +} +void Display::print(int x, int y, BaseFont *font, Color color, const char *text) { + this->print(x, y, font, color, TextAlign::TOP_LEFT, text); +} +void Display::print(int x, int y, BaseFont *font, TextAlign align, const char *text) { + this->print(x, y, font, COLOR_ON, align, text); +} +void Display::print(int x, int y, BaseFont *font, const char *text) { + this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text); +} +void Display::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) { + va_list arg; + va_start(arg, format); + this->vprintf_(x, y, font, color, align, format, arg); + va_end(arg); +} +void Display::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) { + va_list arg; + va_start(arg, format); + this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg); + va_end(arg); +} +void Display::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) { + va_list arg; + va_start(arg, format); + this->vprintf_(x, y, font, COLOR_ON, align, format, arg); + va_end(arg); +} +void Display::printf(int x, int y, BaseFont *font, const char *format, ...) { + va_list arg; + va_start(arg, format); + this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg); + va_end(arg); +} +void Display::set_writer(display_writer_t &&writer) { this->writer_ = writer; } +void Display::set_pages(std::vector pages) { + for (auto *page : pages) + page->set_parent(this); + + for (uint32_t i = 0; i < pages.size() - 1; i++) { + pages[i]->set_next(pages[i + 1]); + pages[i + 1]->set_prev(pages[i]); + } + pages[0]->set_prev(pages[pages.size() - 1]); + pages[pages.size() - 1]->set_next(pages[0]); + this->show_page(pages[0]); +} +void Display::show_page(DisplayPage *page) { + this->previous_page_ = this->page_; + this->page_ = page; + if (this->previous_page_ != this->page_) { + for (auto *t : on_page_change_triggers_) + t->process(this->previous_page_, this->page_); + } +} +void Display::show_next_page() { this->page_->show_next(); } +void Display::show_prev_page() { this->page_->show_prev(); } +void Display::do_update_() { + if (this->auto_clear_enabled_) { + this->clear(); + } + if (this->page_ != nullptr) { + this->page_->get_writer()(*this); + } else if (this->writer_.has_value()) { + (*this->writer_)(*this); + } + // remove all not ended clipping regions + while (is_clipping()) { + end_clipping(); + } +} +void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { + if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) + this->trigger(from, to); +} +void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) { + char buffer[64]; + size_t ret = time.strftime(buffer, sizeof(buffer), format); + if (ret > 0) + this->print(x, y, font, color, align, buffer); +} +void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) { + this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); +} +void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) { + this->strftime(x, y, font, COLOR_ON, align, format, time); +} +void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) { + this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time); +} + +void Display::start_clipping(Rect rect) { + if (!this->clipping_rectangle_.empty()) { + Rect r = this->clipping_rectangle_.back(); + rect.shrink(r); + } + this->clipping_rectangle_.push_back(rect); +} +void Display::end_clipping() { + if (this->clipping_rectangle_.empty()) { + ESP_LOGE(TAG, "clear: Clipping is not set."); + } else { + this->clipping_rectangle_.pop_back(); + } +} +void Display::extend_clipping(Rect add_rect) { + if (this->clipping_rectangle_.empty()) { + ESP_LOGE(TAG, "add: Clipping is not set."); + } else { + this->clipping_rectangle_.back().extend(add_rect); + } +} +void Display::shrink_clipping(Rect add_rect) { + if (this->clipping_rectangle_.empty()) { + ESP_LOGE(TAG, "add: Clipping is not set."); + } else { + this->clipping_rectangle_.back().shrink(add_rect); + } +} +Rect Display::get_clipping() { + if (this->clipping_rectangle_.empty()) { + return Rect(); + } else { + return this->clipping_rectangle_.back(); + } +} + +DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} +void DisplayPage::show() { this->parent_->show_page(this); } +void DisplayPage::show_next() { this->next_->show(); } +void DisplayPage::show_prev() { this->prev_->show(); } +void DisplayPage::set_parent(Display *parent) { this->parent_ = parent; } +void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; } +void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; } +const display_writer_t &DisplayPage::get_writer() const { return this->writer_; } + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h new file mode 100644 index 0000000000..2f6fb563cc --- /dev/null +++ b/esphome/components/display/display.h @@ -0,0 +1,575 @@ +#pragma once + +#include +#include + +#include "rect.h" + +#include "esphome/core/color.h" +#include "esphome/core/automation.h" +#include "esphome/core/time.h" + +#ifdef USE_GRAPH +#include "esphome/components/graph/graph.h" +#endif + +#ifdef USE_QR_CODE +#include "esphome/components/qr_code/qr_code.h" +#endif + +namespace esphome { +namespace display { + +/** TextAlign is used to tell the display class how to position a piece of text. By default + * the coordinates you enter for the print*() functions take the upper left corner of the text + * as the "anchor" point. You can customize this behavior to, for example, make the coordinates + * refer to the *center* of the text. + * + * All text alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis + * these options are allowed: + * + * - LEFT (x-coordinate of anchor point is on left) + * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the text) + * - RIGHT (x-coordinate of anchor point is on right) + * + * For the Y-Axis alignment these options are allowed: + * + * - TOP (y-coordinate of anchor is on the top of the text) + * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the text) + * - BASELINE (y-coordinate of anchor is on the baseline of the text) + * - BOTTOM (y-coordinate of anchor is on the bottom of the text) + * + * These options are then combined to create combined TextAlignment options like: + * - TOP_LEFT (default) + * - CENTER (anchor point is in the middle of the text bounds) + * - ... + */ +enum class TextAlign { + TOP = 0x00, + CENTER_VERTICAL = 0x01, + BASELINE = 0x02, + BOTTOM = 0x04, + + LEFT = 0x00, + CENTER_HORIZONTAL = 0x08, + RIGHT = 0x10, + + TOP_LEFT = TOP | LEFT, + TOP_CENTER = TOP | CENTER_HORIZONTAL, + TOP_RIGHT = TOP | RIGHT, + + CENTER_LEFT = CENTER_VERTICAL | LEFT, + CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, + CENTER_RIGHT = CENTER_VERTICAL | RIGHT, + + BASELINE_LEFT = BASELINE | LEFT, + BASELINE_CENTER = BASELINE | CENTER_HORIZONTAL, + BASELINE_RIGHT = BASELINE | RIGHT, + + BOTTOM_LEFT = BOTTOM | LEFT, + BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, + BOTTOM_RIGHT = BOTTOM | RIGHT, +}; + +/** ImageAlign is used to tell the display class how to position a image. By default + * the coordinates you enter for the image() functions take the upper left corner of the image + * as the "anchor" point. You can customize this behavior to, for example, make the coordinates + * refer to the *center* of the image. + * + * All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis + * these options are allowed: + * + * - LEFT (x-coordinate of anchor point is on left) + * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image) + * - RIGHT (x-coordinate of anchor point is on right) + * + * For the Y-Axis alignment these options are allowed: + * + * - TOP (y-coordinate of anchor is on the top of the image) + * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image) + * - BOTTOM (y-coordinate of anchor is on the bottom of the image) + * + * These options are then combined to create combined TextAlignment options like: + * - TOP_LEFT (default) + * - CENTER (anchor point is in the middle of the image bounds) + * - ... + */ +enum class ImageAlign { + TOP = 0x00, + CENTER_VERTICAL = 0x01, + BOTTOM = 0x02, + + LEFT = 0x00, + CENTER_HORIZONTAL = 0x04, + RIGHT = 0x08, + + TOP_LEFT = TOP | LEFT, + TOP_CENTER = TOP | CENTER_HORIZONTAL, + TOP_RIGHT = TOP | RIGHT, + + CENTER_LEFT = CENTER_VERTICAL | LEFT, + CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, + CENTER_RIGHT = CENTER_VERTICAL | RIGHT, + + BOTTOM_LEFT = BOTTOM | LEFT, + BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, + BOTTOM_RIGHT = BOTTOM | RIGHT, + + HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT, + VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM +}; + +enum DisplayType { + DISPLAY_TYPE_BINARY = 1, + DISPLAY_TYPE_GRAYSCALE = 2, + DISPLAY_TYPE_COLOR = 3, +}; + +enum DisplayRotation { + DISPLAY_ROTATION_0_DEGREES = 0, + DISPLAY_ROTATION_90_DEGREES = 90, + DISPLAY_ROTATION_180_DEGREES = 180, + DISPLAY_ROTATION_270_DEGREES = 270, +}; + +class Display; +class DisplayBuffer; +class DisplayPage; +class DisplayOnPageChangeTrigger; + +using display_writer_t = std::function; +using display_buffer_writer_t = std::function; + +#define LOG_DISPLAY(prefix, type, obj) \ + if ((obj) != nullptr) { \ + ESP_LOGCONFIG(TAG, prefix type); \ + ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \ + ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \ + } + +/// Turn the pixel OFF. +extern const Color COLOR_OFF; +/// Turn the pixel ON. +extern const Color COLOR_ON; + +class BaseImage { + public: + virtual void draw(int x, int y, Display *display, Color color_on, Color color_off) = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; +}; + +class BaseFont { + public: + virtual void print(int x, int y, Display *display, Color color, const char *text) = 0; + virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0; +}; + +class Display { + public: + /// Fill the entire screen with the given color. + virtual void fill(Color color); + /// Clear the entire screen by filling it with OFF pixels. + void clear(); + + /// Get the width of the image in pixels with rotation applied. + virtual int get_width() = 0; + /// Get the height of the image in pixels with rotation applied. + virtual int get_height() = 0; + + /// Set a single pixel at the specified coordinates to default color. + inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); } + + /// Set a single pixel at the specified coordinates to the given color. + virtual void draw_pixel_at(int x, int y, Color color) = 0; + + /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. + void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON); + + /// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color. + void horizontal_line(int x, int y, int width, Color color = COLOR_ON); + + /// Draw a vertical line from the point [x,y] to [x,y+width] with the given color. + void vertical_line(int x, int y, int height, Color color = COLOR_ON); + + /// Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at + /// [x1+width,y1+height]. + void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); + + /// Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,y1+height]. + void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); + + /// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color. + void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON); + + /// Fill a circle centered around [center_x,center_y] with the radius radius with the given color. + void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON); + + /** Print `text` with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param align The alignment of the text. + * @param text The text to draw. + */ + void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text); + + /** Print `text` with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param text The text to draw. + */ + void print(int x, int y, BaseFont *font, Color color, const char *text); + + /** Print `text` with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param align The alignment of the text. + * @param text The text to draw. + */ + void print(int x, int y, BaseFont *font, TextAlign align, const char *text); + + /** Print `text` with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param text The text to draw. + */ + void print(int x, int y, BaseFont *font, const char *text); + + /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param align The alignment of the text. + * @param format The format to use. + * @param ... The arguments to use for the text formatting. + */ + void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) + __attribute__((format(printf, 7, 8))); + + /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param format The format to use. + * @param ... The arguments to use for the text formatting. + */ + void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7))); + + /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param align The alignment of the text. + * @param format The format to use. + * @param ... The arguments to use for the text formatting. + */ + void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) + __attribute__((format(printf, 6, 7))); + + /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param format The format to use. + * @param ... The arguments to use for the text formatting. + */ + void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6))); + + /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param align The alignment of the text. + * @param format The strftime format to use. + * @param time The time to format. + */ + void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) + __attribute__((format(strftime, 7, 0))); + + /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param format The strftime format to use. + * @param time The time to format. + */ + void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) + __attribute__((format(strftime, 6, 0))); + + /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param align The alignment of the text. + * @param format The strftime format to use. + * @param time The time to format. + */ + void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) + __attribute__((format(strftime, 6, 0))); + + /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param font The font to draw the text with. + * @param format The strftime format to use. + * @param time The time to format. + */ + void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0))); + + /** Draw the `image` with the top-left corner at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param image The image to draw. + * @param color_on The color to replace in binary images for the on bits. + * @param color_off The color to replace in binary images for the off bits. + */ + void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + + /** Draw the `image` at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param image The image to draw. + * @param align The alignment of the image. + * @param color_on The color to replace in binary images for the on bits. + * @param color_off The color to replace in binary images for the off bits. + */ + void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); + +#ifdef USE_GRAPH + /** Draw the `graph` with the top-left corner at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param graph The graph id to draw + * @param color_on The color to replace in binary images for the on bits. + */ + void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); + + /** Draw the `legend` for graph with the top-left corner at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param graph The graph id for which the legend applies to + * @param graph The graph id for which the legend applies to + * @param graph The graph id for which the legend applies to + * @param name_font The font used for the trace name + * @param value_font The font used for the trace value and units + * @param color_on The color of the border + */ + void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); +#endif // USE_GRAPH + +#ifdef USE_QR_CODE + /** Draw the `qr_code` with the top-left corner at [x,y] to the screen. + * + * @param x The x coordinate of the upper left corner. + * @param y The y coordinate of the upper left corner. + * @param qr_code The qr_code to draw + * @param color_on The color to replace in binary images for the on bits. + */ + void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1); +#endif + + /** Get the text bounds of the given string. + * + * @param x The x coordinate to place the string at, can be 0 if only interested in dimensions. + * @param y The y coordinate to place the string at, can be 0 if only interested in dimensions. + * @param text The text to measure. + * @param font The font to measure the text bounds with. + * @param align The alignment of the text. Set to TextAlign::TOP_LEFT if only interested in dimensions. + * @param x1 A pointer to store the returned x coordinate of the upper left corner in. + * @param y1 A pointer to store the returned y coordinate of the upper left corner in. + * @param width A pointer to store the returned text width in. + * @param height A pointer to store the returned text height in. + */ + void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width, + int *height); + + /// Internal method to set the display writer lambda. + void set_writer(display_writer_t &&writer); + void set_writer(const display_buffer_writer_t &writer) { + // Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef` + this->set_writer([writer](Display &display) { return writer((display::DisplayBuffer &) display); }); + } + + void show_page(DisplayPage *page); + void show_next_page(); + void show_prev_page(); + + void set_pages(std::vector pages); + + const DisplayPage *get_active_page() const { return this->page_; } + + void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); } + + /// Internal method to set the display rotation with. + void set_rotation(DisplayRotation rotation); + + // Internal method to set display auto clearing. + void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; } + + DisplayRotation get_rotation() const { return this->rotation_; } + + /** Get the type of display that the buffer corresponds to. In case of dynamically configurable displays, + * returns the type the display is currently configured to. + */ + virtual DisplayType get_display_type() = 0; + + /** Set the clipping rectangle for further drawing + * + * @param[in] rect: Pointer to Rect for clipping (or NULL for entire screen) + * + * return true if success, false if error + */ + void start_clipping(Rect rect); + void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) { + start_clipping(Rect(left, top, right - left, bottom - top)); + }; + + /** Add a rectangular region to the invalidation region + * - This is usually called when an element has been modified + * + * @param[in] rect: Rectangle to add to the invalidation region + */ + void extend_clipping(Rect rect); + void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) { + this->extend_clipping(Rect(left, top, right - left, bottom - top)); + }; + + /** substract a rectangular region to the invalidation region + * - This is usually called when an element has been modified + * + * @param[in] rect: Rectangle to add to the invalidation region + */ + void shrink_clipping(Rect rect); + void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { + this->shrink_clipping(Rect(left, top, right - left, bottom - top)); + }; + + /** Reset the invalidation region + */ + void end_clipping(); + + /** Get the current the clipping rectangle + * + * return rect for active clipping region + */ + Rect get_clipping(); + + bool is_clipping() const { return !this->clipping_rectangle_.empty(); } + + protected: + void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg); + + void do_update_(); + + DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES}; + optional writer_{}; + DisplayPage *page_{nullptr}; + DisplayPage *previous_page_{nullptr}; + std::vector on_page_change_triggers_; + bool auto_clear_enabled_{true}; + std::vector clipping_rectangle_; +}; + +class DisplayPage { + public: + DisplayPage(display_writer_t writer); + // Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef` + DisplayPage(const display_buffer_writer_t &writer) + : DisplayPage([writer](Display &display) { return writer((display::DisplayBuffer &) display); }) {} + void show(); + void show_next(); + void show_prev(); + void set_parent(Display *parent); + void set_prev(DisplayPage *prev); + void set_next(DisplayPage *next); + const display_writer_t &get_writer() const; + + protected: + Display *parent_; + display_writer_t writer_; + DisplayPage *prev_{nullptr}; + DisplayPage *next_{nullptr}; +}; + +template class DisplayPageShowAction : public Action { + public: + TEMPLATABLE_VALUE(DisplayPage *, page) + + void play(Ts... x) override { + auto *page = this->page_.value(x...); + if (page != nullptr) { + page->show(); + } + } +}; + +template class DisplayPageShowNextAction : public Action { + public: + DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {} + + void play(Ts... x) override { this->buffer_->show_next_page(); } + + Display *buffer_; +}; + +template class DisplayPageShowPrevAction : public Action { + public: + DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {} + + void play(Ts... x) override { this->buffer_->show_prev_page(); } + + Display *buffer_; +}; + +template class DisplayIsDisplayingPageCondition : public Condition { + public: + DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {} + + void set_page(DisplayPage *page) { this->page_ = page; } + bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; } + + protected: + Display *parent_; + DisplayPage *page_; +}; + +class DisplayOnPageChangeTrigger : public Trigger { + public: + explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); } + void process(DisplayPage *from, DisplayPage *to); + void set_from(DisplayPage *p) { this->from_ = p; } + void set_to(DisplayPage *p) { this->to_ = p; } + + protected: + DisplayPage *from_{nullptr}; + DisplayPage *to_{nullptr}; +}; + +} // namespace display +} // namespace esphome diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 86e8624d33..3af1b63e01 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -1,10 +1,8 @@ #include "display_buffer.h" #include + #include "esphome/core/application.h" -#include "esphome/core/color.h" -#include "esphome/core/hal.h" -#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { @@ -12,9 +10,6 @@ namespace display { static const char *const TAG = "display"; -const Color COLOR_OFF(0, 0, 0, 0); -const Color COLOR_ON(255, 255, 255, 255); - void DisplayBuffer::init_internal_(uint32_t buffer_length) { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); this->buffer_ = allocator.allocate(buffer_length); @@ -25,8 +20,6 @@ void DisplayBuffer::init_internal_(uint32_t buffer_length) { this->clear(); } -void DisplayBuffer::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); } -void DisplayBuffer::clear() { this->fill(COLOR_OFF); } int DisplayBuffer::get_width() { switch (this->rotation_) { case DISPLAY_ROTATION_90_DEGREES: @@ -38,6 +31,7 @@ int DisplayBuffer::get_width() { return this->get_width_internal(); } } + int DisplayBuffer::get_height() { switch (this->rotation_) { case DISPLAY_ROTATION_0_DEGREES: @@ -49,7 +43,7 @@ int DisplayBuffer::get_height() { return this->get_width_internal(); } } -void DisplayBuffer::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; } + void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) { if (!this->get_clipping().inside(x, y)) return; // NOLINT @@ -73,333 +67,6 @@ void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) { this->draw_absolute_pixel_internal(x, y, color); App.feed_wdt(); } -void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, Color color) { - const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1; - const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1; - int32_t err = dx + dy; - - while (true) { - this->draw_pixel_at(x1, y1, color); - if (x1 == x2 && y1 == y2) - break; - int32_t e2 = 2 * err; - if (e2 >= dy) { - err += dy; - x1 += sx; - } - if (e2 <= dx) { - err += dx; - y1 += sy; - } - } -} -void HOT DisplayBuffer::horizontal_line(int x, int y, int width, Color color) { - // Future: Could be made more efficient by manipulating buffer directly in certain rotations. - for (int i = x; i < x + width; i++) - this->draw_pixel_at(i, y, color); -} -void HOT DisplayBuffer::vertical_line(int x, int y, int height, Color color) { - // Future: Could be made more efficient by manipulating buffer directly in certain rotations. - for (int i = y; i < y + height; i++) - this->draw_pixel_at(x, i, color); -} -void DisplayBuffer::rectangle(int x1, int y1, int width, int height, Color color) { - this->horizontal_line(x1, y1, width, color); - this->horizontal_line(x1, y1 + height - 1, width, color); - this->vertical_line(x1, y1, height, color); - this->vertical_line(x1 + width - 1, y1, height, color); -} -void DisplayBuffer::filled_rectangle(int x1, int y1, int width, int height, Color color) { - // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses. - for (int i = y1; i < y1 + height; i++) { - this->horizontal_line(x1, i, width, color); - } -} -void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, Color color) { - int dx = -radius; - int dy = 0; - int err = 2 - 2 * radius; - int e2; - - do { - this->draw_pixel_at(center_x - dx, center_xy + dy, color); - this->draw_pixel_at(center_x + dx, center_xy + dy, color); - this->draw_pixel_at(center_x + dx, center_xy - dy, color); - this->draw_pixel_at(center_x - dx, center_xy - dy, color); - e2 = err; - if (e2 < dy) { - err += ++dy * 2 + 1; - if (-dx == dy && e2 <= dx) { - e2 = 0; - } - } - if (e2 > dx) { - err += ++dx * 2 + 1; - } - } while (dx <= 0); -} -void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, Color color) { - int dx = -int32_t(radius); - int dy = 0; - int err = 2 - 2 * radius; - int e2; - - do { - this->draw_pixel_at(center_x - dx, center_y + dy, color); - this->draw_pixel_at(center_x + dx, center_y + dy, color); - this->draw_pixel_at(center_x + dx, center_y - dy, color); - this->draw_pixel_at(center_x - dx, center_y - dy, color); - int hline_width = 2 * (-dx) + 1; - this->horizontal_line(center_x + dx, center_y + dy, hline_width, color); - this->horizontal_line(center_x + dx, center_y - dy, hline_width, color); - e2 = err; - if (e2 < dy) { - err += ++dy * 2 + 1; - if (-dx == dy && e2 <= dx) { - e2 = 0; - } - } - if (e2 > dx) { - err += ++dx * 2 + 1; - } - } while (dx <= 0); -} - -void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) { - int x_start, y_start; - int width, height; - this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height); - font->print(x_start, y_start, this, color, text); -} -void DisplayBuffer::vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, - va_list arg) { - char buffer[256]; - int ret = vsnprintf(buffer, sizeof(buffer), format, arg); - if (ret > 0) - this->print(x, y, font, color, align, buffer); -} - -void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) { - this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off); -} - -void DisplayBuffer::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) { - auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT))); - auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT))); - - switch (x_align) { - case ImageAlign::RIGHT: - x -= image->get_width(); - break; - case ImageAlign::CENTER_HORIZONTAL: - x -= image->get_width() / 2; - break; - case ImageAlign::LEFT: - default: - break; - } - - switch (y_align) { - case ImageAlign::BOTTOM: - y -= image->get_height(); - break; - case ImageAlign::CENTER_VERTICAL: - y -= image->get_height() / 2; - break; - case ImageAlign::TOP: - default: - break; - } - - image->draw(x, y, this, color_on, color_off); -} - -#ifdef USE_GRAPH -void DisplayBuffer::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); } -void DisplayBuffer::legend(int x, int y, graph::Graph *graph, Color color_on) { - graph->draw_legend(this, x, y, color_on); -} -#endif // USE_GRAPH - -#ifdef USE_QR_CODE -void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) { - qr_code->draw(this, x, y, color_on, scale); -} -#endif // USE_QR_CODE - -void DisplayBuffer::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, - int *width, int *height) { - int x_offset, baseline; - font->measure(text, width, &x_offset, &baseline, height); - - auto x_align = TextAlign(int(align) & 0x18); - auto y_align = TextAlign(int(align) & 0x07); - - switch (x_align) { - case TextAlign::RIGHT: - *x1 = x - *width; - break; - case TextAlign::CENTER_HORIZONTAL: - *x1 = x - (*width) / 2; - break; - case TextAlign::LEFT: - default: - // LEFT - *x1 = x; - break; - } - - switch (y_align) { - case TextAlign::BOTTOM: - *y1 = y - *height; - break; - case TextAlign::BASELINE: - *y1 = y - baseline; - break; - case TextAlign::CENTER_VERTICAL: - *y1 = y - (*height) / 2; - break; - case TextAlign::TOP: - default: - *y1 = y; - break; - } -} -void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, const char *text) { - this->print(x, y, font, color, TextAlign::TOP_LEFT, text); -} -void DisplayBuffer::print(int x, int y, BaseFont *font, TextAlign align, const char *text) { - this->print(x, y, font, COLOR_ON, align, text); -} -void DisplayBuffer::print(int x, int y, BaseFont *font, const char *text) { - this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text); -} -void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) { - va_list arg; - va_start(arg, format); - this->vprintf_(x, y, font, color, align, format, arg); - va_end(arg); -} -void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) { - va_list arg; - va_start(arg, format); - this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg); - va_end(arg); -} -void DisplayBuffer::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) { - va_list arg; - va_start(arg, format); - this->vprintf_(x, y, font, COLOR_ON, align, format, arg); - va_end(arg); -} -void DisplayBuffer::printf(int x, int y, BaseFont *font, const char *format, ...) { - va_list arg; - va_start(arg, format); - this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg); - va_end(arg); -} -void DisplayBuffer::set_writer(display_writer_t &&writer) { this->writer_ = writer; } -void DisplayBuffer::set_pages(std::vector pages) { - for (auto *page : pages) - page->set_parent(this); - - for (uint32_t i = 0; i < pages.size() - 1; i++) { - pages[i]->set_next(pages[i + 1]); - pages[i + 1]->set_prev(pages[i]); - } - pages[0]->set_prev(pages[pages.size() - 1]); - pages[pages.size() - 1]->set_next(pages[0]); - this->show_page(pages[0]); -} -void DisplayBuffer::show_page(DisplayPage *page) { - this->previous_page_ = this->page_; - this->page_ = page; - if (this->previous_page_ != this->page_) { - for (auto *t : on_page_change_triggers_) - t->process(this->previous_page_, this->page_); - } -} -void DisplayBuffer::show_next_page() { this->page_->show_next(); } -void DisplayBuffer::show_prev_page() { this->page_->show_prev(); } -void DisplayBuffer::do_update_() { - if (this->auto_clear_enabled_) { - this->clear(); - } - if (this->page_ != nullptr) { - this->page_->get_writer()(*this); - } else if (this->writer_.has_value()) { - (*this->writer_)(*this); - } - // remove all not ended clipping regions - while (is_clipping()) { - end_clipping(); - } -} -void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { - if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) - this->trigger(from, to); -} -void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, - ESPTime time) { - char buffer[64]; - size_t ret = time.strftime(buffer, sizeof(buffer), format); - if (ret > 0) - this->print(x, y, font, color, align, buffer); -} -void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) { - this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); -} -void DisplayBuffer::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) { - this->strftime(x, y, font, COLOR_ON, align, format, time); -} -void DisplayBuffer::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) { - this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time); -} - -void DisplayBuffer::start_clipping(Rect rect) { - if (!this->clipping_rectangle_.empty()) { - Rect r = this->clipping_rectangle_.back(); - rect.shrink(r); - } - this->clipping_rectangle_.push_back(rect); -} -void DisplayBuffer::end_clipping() { - if (this->clipping_rectangle_.empty()) { - ESP_LOGE(TAG, "clear: Clipping is not set."); - } else { - this->clipping_rectangle_.pop_back(); - } -} -void DisplayBuffer::extend_clipping(Rect add_rect) { - if (this->clipping_rectangle_.empty()) { - ESP_LOGE(TAG, "add: Clipping is not set."); - } else { - this->clipping_rectangle_.back().extend(add_rect); - } -} -void DisplayBuffer::shrink_clipping(Rect add_rect) { - if (this->clipping_rectangle_.empty()) { - ESP_LOGE(TAG, "add: Clipping is not set."); - } else { - this->clipping_rectangle_.back().shrink(add_rect); - } -} -Rect DisplayBuffer::get_clipping() { - if (this->clipping_rectangle_.empty()) { - return Rect(); - } else { - return this->clipping_rectangle_.back(); - } -} - -DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} -void DisplayPage::show() { this->parent_->show_page(this); } -void DisplayPage::show_next() { this->next_->show(); } -void DisplayPage::show_prev() { this->prev_->show(); } -void DisplayPage::set_parent(DisplayBuffer *parent) { this->parent_ = parent; } -void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; } -void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; } -const display_writer_t &DisplayPage::get_writer() const { return this->writer_; } } // namespace display } // namespace esphome diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 1a62da2323..869d97613a 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -2,568 +2,35 @@ #include #include -#include "rect.h" + +#include "display.h" #include "display_color_utils.h" -#include "esphome/core/automation.h" + #include "esphome/core/component.h" #include "esphome/core/defines.h" -#include "esphome/core/time.h" - -#ifdef USE_GRAPH -#include "esphome/components/graph/graph.h" -#endif - -#ifdef USE_QR_CODE -#include "esphome/components/qr_code/qr_code.h" -#endif namespace esphome { namespace display { -/** TextAlign is used to tell the display class how to position a piece of text. By default - * the coordinates you enter for the print*() functions take the upper left corner of the text - * as the "anchor" point. You can customize this behavior to, for example, make the coordinates - * refer to the *center* of the text. - * - * All text alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis - * these options are allowed: - * - * - LEFT (x-coordinate of anchor point is on left) - * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the text) - * - RIGHT (x-coordinate of anchor point is on right) - * - * For the Y-Axis alignment these options are allowed: - * - * - TOP (y-coordinate of anchor is on the top of the text) - * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the text) - * - BASELINE (y-coordinate of anchor is on the baseline of the text) - * - BOTTOM (y-coordinate of anchor is on the bottom of the text) - * - * These options are then combined to create combined TextAlignment options like: - * - TOP_LEFT (default) - * - CENTER (anchor point is in the middle of the text bounds) - * - ... - */ -enum class TextAlign { - TOP = 0x00, - CENTER_VERTICAL = 0x01, - BASELINE = 0x02, - BOTTOM = 0x04, - - LEFT = 0x00, - CENTER_HORIZONTAL = 0x08, - RIGHT = 0x10, - - TOP_LEFT = TOP | LEFT, - TOP_CENTER = TOP | CENTER_HORIZONTAL, - TOP_RIGHT = TOP | RIGHT, - - CENTER_LEFT = CENTER_VERTICAL | LEFT, - CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, - CENTER_RIGHT = CENTER_VERTICAL | RIGHT, - - BASELINE_LEFT = BASELINE | LEFT, - BASELINE_CENTER = BASELINE | CENTER_HORIZONTAL, - BASELINE_RIGHT = BASELINE | RIGHT, - - BOTTOM_LEFT = BOTTOM | LEFT, - BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, - BOTTOM_RIGHT = BOTTOM | RIGHT, -}; - -/** ImageAlign is used to tell the display class how to position a image. By default - * the coordinates you enter for the image() functions take the upper left corner of the image - * as the "anchor" point. You can customize this behavior to, for example, make the coordinates - * refer to the *center* of the image. - * - * All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis - * these options are allowed: - * - * - LEFT (x-coordinate of anchor point is on left) - * - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image) - * - RIGHT (x-coordinate of anchor point is on right) - * - * For the Y-Axis alignment these options are allowed: - * - * - TOP (y-coordinate of anchor is on the top of the image) - * - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image) - * - BOTTOM (y-coordinate of anchor is on the bottom of the image) - * - * These options are then combined to create combined TextAlignment options like: - * - TOP_LEFT (default) - * - CENTER (anchor point is in the middle of the image bounds) - * - ... - */ -enum class ImageAlign { - TOP = 0x00, - CENTER_VERTICAL = 0x01, - BOTTOM = 0x02, - - LEFT = 0x00, - CENTER_HORIZONTAL = 0x04, - RIGHT = 0x08, - - TOP_LEFT = TOP | LEFT, - TOP_CENTER = TOP | CENTER_HORIZONTAL, - TOP_RIGHT = TOP | RIGHT, - - CENTER_LEFT = CENTER_VERTICAL | LEFT, - CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL, - CENTER_RIGHT = CENTER_VERTICAL | RIGHT, - - BOTTOM_LEFT = BOTTOM | LEFT, - BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL, - BOTTOM_RIGHT = BOTTOM | RIGHT, - - HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT, - VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM -}; - -enum DisplayType { - DISPLAY_TYPE_BINARY = 1, - DISPLAY_TYPE_GRAYSCALE = 2, - DISPLAY_TYPE_COLOR = 3, -}; - -enum DisplayRotation { - DISPLAY_ROTATION_0_DEGREES = 0, - DISPLAY_ROTATION_90_DEGREES = 90, - DISPLAY_ROTATION_180_DEGREES = 180, - DISPLAY_ROTATION_270_DEGREES = 270, -}; - -class DisplayBuffer; -class DisplayPage; -class DisplayOnPageChangeTrigger; - -using display_writer_t = std::function; - -#define LOG_DISPLAY(prefix, type, obj) \ - if ((obj) != nullptr) { \ - ESP_LOGCONFIG(TAG, prefix type); \ - ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \ - ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \ - } - -/// Turn the pixel OFF. -extern const Color COLOR_OFF; -/// Turn the pixel ON. -extern const Color COLOR_ON; - -class BaseImage { +class DisplayBuffer : public Display { public: - virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; -}; - -class BaseFont { - public: - virtual void print(int x, int y, DisplayBuffer *display, Color color, const char *text) = 0; - virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0; -}; - -class DisplayBuffer { - public: - /// Fill the entire screen with the given color. - virtual void fill(Color color); - /// Clear the entire screen by filling it with OFF pixels. - void clear(); - /// Get the width of the image in pixels with rotation applied. - int get_width(); + int get_width() override; /// Get the height of the image in pixels with rotation applied. - int get_height(); + int get_height() override; /// Set a single pixel at the specified coordinates to the given color. - void draw_pixel_at(int x, int y, Color color = COLOR_ON); - - /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. - void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON); - - /// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color. - void horizontal_line(int x, int y, int width, Color color = COLOR_ON); - - /// Draw a vertical line from the point [x,y] to [x,y+width] with the given color. - void vertical_line(int x, int y, int height, Color color = COLOR_ON); - - /// Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at - /// [x1+width,y1+height]. - void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); - - /// Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,y1+height]. - void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); - - /// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color. - void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON); - - /// Fill a circle centered around [center_x,center_y] with the radius radius with the given color. - void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON); - - /** Print `text` with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param align The alignment of the text. - * @param text The text to draw. - */ - void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text); - - /** Print `text` with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param text The text to draw. - */ - void print(int x, int y, BaseFont *font, Color color, const char *text); - - /** Print `text` with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param align The alignment of the text. - * @param text The text to draw. - */ - void print(int x, int y, BaseFont *font, TextAlign align, const char *text); - - /** Print `text` with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param text The text to draw. - */ - void print(int x, int y, BaseFont *font, const char *text); - - /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param align The alignment of the text. - * @param format The format to use. - * @param ... The arguments to use for the text formatting. - */ - void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) - __attribute__((format(printf, 7, 8))); - - /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param format The format to use. - * @param ... The arguments to use for the text formatting. - */ - void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7))); - - /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param align The alignment of the text. - * @param format The format to use. - * @param ... The arguments to use for the text formatting. - */ - void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) - __attribute__((format(printf, 6, 7))); - - /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param format The format to use. - * @param ... The arguments to use for the text formatting. - */ - void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6))); - - /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param align The alignment of the text. - * @param format The strftime format to use. - * @param time The time to format. - */ - void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) - __attribute__((format(strftime, 7, 0))); - - /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param color The color to draw the text with. - * @param format The strftime format to use. - * @param time The time to format. - */ - void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) - __attribute__((format(strftime, 6, 0))); - - /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. - * - * @param x The x coordinate of the text alignment anchor point. - * @param y The y coordinate of the text alignment anchor point. - * @param font The font to draw the text with. - * @param align The alignment of the text. - * @param format The strftime format to use. - * @param time The time to format. - */ - void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) - __attribute__((format(strftime, 6, 0))); - - /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param font The font to draw the text with. - * @param format The strftime format to use. - * @param time The time to format. - */ - void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0))); - - /** Draw the `image` with the top-left corner at [x,y] to the screen. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param image The image to draw. - * @param color_on The color to replace in binary images for the on bits. - * @param color_off The color to replace in binary images for the off bits. - */ - void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); - - /** Draw the `image` at [x,y] to the screen. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param image The image to draw. - * @param align The alignment of the image. - * @param color_on The color to replace in binary images for the on bits. - * @param color_off The color to replace in binary images for the off bits. - */ - void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF); - -#ifdef USE_GRAPH - /** Draw the `graph` with the top-left corner at [x,y] to the screen. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param graph The graph id to draw - * @param color_on The color to replace in binary images for the on bits. - */ - void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); - - /** Draw the `legend` for graph with the top-left corner at [x,y] to the screen. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param graph The graph id for which the legend applies to - * @param graph The graph id for which the legend applies to - * @param graph The graph id for which the legend applies to - * @param name_font The font used for the trace name - * @param value_font The font used for the trace value and units - * @param color_on The color of the border - */ - void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); -#endif // USE_GRAPH - -#ifdef USE_QR_CODE - /** Draw the `qr_code` with the top-left corner at [x,y] to the screen. - * - * @param x The x coordinate of the upper left corner. - * @param y The y coordinate of the upper left corner. - * @param qr_code The qr_code to draw - * @param color_on The color to replace in binary images for the on bits. - */ - void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1); -#endif - - /** Get the text bounds of the given string. - * - * @param x The x coordinate to place the string at, can be 0 if only interested in dimensions. - * @param y The y coordinate to place the string at, can be 0 if only interested in dimensions. - * @param text The text to measure. - * @param font The font to measure the text bounds with. - * @param align The alignment of the text. Set to TextAlign::TOP_LEFT if only interested in dimensions. - * @param x1 A pointer to store the returned x coordinate of the upper left corner in. - * @param y1 A pointer to store the returned y coordinate of the upper left corner in. - * @param width A pointer to store the returned text width in. - * @param height A pointer to store the returned text height in. - */ - void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width, - int *height); - - /// Internal method to set the display writer lambda. - void set_writer(display_writer_t &&writer); - - void show_page(DisplayPage *page); - void show_next_page(); - void show_prev_page(); - - void set_pages(std::vector pages); - - const DisplayPage *get_active_page() const { return this->page_; } - - void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); } - - /// Internal method to set the display rotation with. - void set_rotation(DisplayRotation rotation); - - // Internal method to set display auto clearing. - void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; } + void draw_pixel_at(int x, int y, Color color) override; virtual int get_height_internal() = 0; virtual int get_width_internal() = 0; - DisplayRotation get_rotation() const { return this->rotation_; } - - /** Get the type of display that the buffer corresponds to. In case of dynamically configurable displays, - * returns the type the display is currently configured to. - */ - virtual DisplayType get_display_type() = 0; - - /** Set the clipping rectangle for further drawing - * - * @param[in] rect: Pointer to Rect for clipping (or NULL for entire screen) - * - * return true if success, false if error - */ - void start_clipping(Rect rect); - void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) { - start_clipping(Rect(left, top, right - left, bottom - top)); - }; - - /** Add a rectangular region to the invalidation region - * - This is usually called when an element has been modified - * - * @param[in] rect: Rectangle to add to the invalidation region - */ - void extend_clipping(Rect rect); - void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) { - this->extend_clipping(Rect(left, top, right - left, bottom - top)); - }; - - /** substract a rectangular region to the invalidation region - * - This is usually called when an element has been modified - * - * @param[in] rect: Rectangle to add to the invalidation region - */ - void shrink_clipping(Rect rect); - void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { - this->shrink_clipping(Rect(left, top, right - left, bottom - top)); - }; - - /** Reset the invalidation region - */ - void end_clipping(); - - /** Get the current the clipping rectangle - * - * return rect for active clipping region - */ - Rect get_clipping(); - - bool is_clipping() const { return !this->clipping_rectangle_.empty(); } protected: - void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg); - virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; void init_internal_(uint32_t buffer_length); - void do_update_(); - uint8_t *buffer_{nullptr}; - DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES}; - optional writer_{}; - DisplayPage *page_{nullptr}; - DisplayPage *previous_page_{nullptr}; - std::vector on_page_change_triggers_; - bool auto_clear_enabled_{true}; - std::vector clipping_rectangle_; -}; - -class DisplayPage { - public: - DisplayPage(display_writer_t writer); - void show(); - void show_next(); - void show_prev(); - void set_parent(DisplayBuffer *parent); - void set_prev(DisplayPage *prev); - void set_next(DisplayPage *next); - const display_writer_t &get_writer() const; - - protected: - DisplayBuffer *parent_; - display_writer_t writer_; - DisplayPage *prev_{nullptr}; - DisplayPage *next_{nullptr}; -}; - -template class DisplayPageShowAction : public Action { - public: - TEMPLATABLE_VALUE(DisplayPage *, page) - - void play(Ts... x) override { - auto *page = this->page_.value(x...); - if (page != nullptr) { - page->show(); - } - } -}; - -template class DisplayPageShowNextAction : public Action { - public: - DisplayPageShowNextAction(DisplayBuffer *buffer) : buffer_(buffer) {} - - void play(Ts... x) override { this->buffer_->show_next_page(); } - - DisplayBuffer *buffer_; -}; - -template class DisplayPageShowPrevAction : public Action { - public: - DisplayPageShowPrevAction(DisplayBuffer *buffer) : buffer_(buffer) {} - - void play(Ts... x) override { this->buffer_->show_prev_page(); } - - DisplayBuffer *buffer_; -}; - -template class DisplayIsDisplayingPageCondition : public Condition { - public: - DisplayIsDisplayingPageCondition(DisplayBuffer *parent) : parent_(parent) {} - - void set_page(DisplayPage *page) { this->page_ = page; } - bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; } - - protected: - DisplayBuffer *parent_; - DisplayPage *page_; -}; - -class DisplayOnPageChangeTrigger : public Trigger { - public: - explicit DisplayOnPageChangeTrigger(DisplayBuffer *parent) { parent->add_on_page_change_trigger(this); } - void process(DisplayPage *from, DisplayPage *to); - void set_from(DisplayPage *p) { this->from_ = p; } - void set_to(DisplayPage *p) { this->to_ = p; } - - protected: - DisplayPage *from_{nullptr}; - DisplayPage *to_{nullptr}; }; } // namespace display diff --git a/esphome/components/font/font.cpp b/esphome/components/font/font.cpp index fcb2bb1750..ef5b2b788d 100644 --- a/esphome/components/font/font.cpp +++ b/esphome/components/font/font.cpp @@ -10,7 +10,7 @@ namespace font { static const char *const TAG = "font"; -void Glyph::draw(int x_at, int y_start, display::DisplayBuffer *display, Color color) const { +void Glyph::draw(int x_at, int y_start, display::Display *display, Color color) const { int scan_x1, scan_y1, scan_width, scan_height; this->scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height); @@ -118,7 +118,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in *x_offset = min_x; *width = x - min_x; } -void Font::print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) { +void Font::print(int x_start, int y_start, display::Display *display, Color color, const char *text) { int i = 0; int x_at = x_start; while (text[i] != '\0') { diff --git a/esphome/components/font/font.h b/esphome/components/font/font.h index d88ebd9be6..03171a6126 100644 --- a/esphome/components/font/font.h +++ b/esphome/components/font/font.h @@ -22,7 +22,7 @@ class Glyph { public: Glyph(const GlyphData *data) : glyph_data_(data) {} - void draw(int x, int y, display::DisplayBuffer *display, Color color) const; + void draw(int x, int y, display::Display *display, Color color) const; const char *get_char() const; @@ -50,7 +50,7 @@ class Font : public display::BaseFont { int match_next_glyph(const char *str, int *match_length); - void print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) override; + void print(int x_start, int y_start, display::Display *display, Color color, const char *text) override; void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override; inline int get_baseline() { return this->baseline_; } inline int get_height() { return this->height_; } diff --git a/esphome/components/graph/graph.cpp b/esphome/components/graph/graph.cpp index c229f17dd8..294e16dbb1 100644 --- a/esphome/components/graph/graph.cpp +++ b/esphome/components/graph/graph.cpp @@ -1,5 +1,5 @@ #include "graph.h" -#include "esphome/components/display/display_buffer.h" +#include "esphome/components/display/display.h" #include "esphome/core/color.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" @@ -56,7 +56,7 @@ void GraphTrace::init(Graph *g) { this->data_.set_update_time_ms(g->get_duration() * 1000 / g->get_width()); } -void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color) { +void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color color) { /// Plot border if (this->border_) { buff->horizontal_line(x_offset, y_offset, this->width_, color); @@ -303,7 +303,7 @@ void GraphLegend::init(Graph *g) { } } -void Graph::draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color) { +void Graph::draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color) { if (!legend_) return; diff --git a/esphome/components/graph/graph.h b/esphome/components/graph/graph.h index 87c21fd7d1..339a6f6d94 100644 --- a/esphome/components/graph/graph.h +++ b/esphome/components/graph/graph.h @@ -8,9 +8,9 @@ namespace esphome { -// forward declare DisplayBuffer +// forward declare Display namespace display { -class DisplayBuffer; +class Display; class BaseFont; } // namespace display @@ -133,8 +133,8 @@ class GraphTrace { class Graph : public Component { public: - void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color); - void draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color); + void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color); + void draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color); void setup() override; float get_setup_priority() const override { return setup_priority::PROCESSOR; } diff --git a/esphome/components/image/image.cpp b/esphome/components/image/image.cpp index 66a085ebe2..0ddb8110cb 100644 --- a/esphome/components/image/image.cpp +++ b/esphome/components/image/image.cpp @@ -5,7 +5,7 @@ namespace esphome { namespace image { -void Image::draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) { +void Image::draw(int x, int y, display::Display *display, Color color_on, Color color_off) { switch (type_) { case IMAGE_TYPE_BINARY: { for (int img_x = 0; img_x < width_; img_x++) { diff --git a/esphome/components/image/image.h b/esphome/components/image/image.h index b0853d360d..4e869f5204 100644 --- a/esphome/components/image/image.h +++ b/esphome/components/image/image.h @@ -39,7 +39,7 @@ class Image : public display::BaseImage { int get_height() const override; ImageType get_type() const; - void draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) override; + void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override; void set_transparency(bool transparent) { transparent_ = transparent; } bool has_transparency() const { return transparent_; } diff --git a/esphome/components/qr_code/qr_code.cpp b/esphome/components/qr_code/qr_code.cpp index a2efbdb804..aecf7628dc 100644 --- a/esphome/components/qr_code/qr_code.cpp +++ b/esphome/components/qr_code/qr_code.cpp @@ -1,5 +1,5 @@ #include "qr_code.h" -#include "esphome/components/display/display_buffer.h" +#include "esphome/components/display/display.h" #include "esphome/core/color.h" #include "esphome/core/log.h" @@ -33,7 +33,7 @@ void QrCode::generate_qr_code() { } } -void QrCode::draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale) { +void QrCode::draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale) { ESP_LOGV(TAG, "Drawing QR code at (%d, %d)", x_offset, y_offset); if (this->needs_update_) { diff --git a/esphome/components/qr_code/qr_code.h b/esphome/components/qr_code/qr_code.h index 58f3a70321..d88e0aa09a 100644 --- a/esphome/components/qr_code/qr_code.h +++ b/esphome/components/qr_code/qr_code.h @@ -9,13 +9,13 @@ namespace esphome { // forward declare DisplayBuffer namespace display { -class DisplayBuffer; +class Display; } // namespace display namespace qr_code { class QrCode : public Component { public: - void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale); + void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale); void dump_config() override; diff --git a/esphome/components/touchscreen/touchscreen.cpp b/esphome/components/touchscreen/touchscreen.cpp index 9b337fc02c..2eaa736171 100644 --- a/esphome/components/touchscreen/touchscreen.cpp +++ b/esphome/components/touchscreen/touchscreen.cpp @@ -7,6 +7,17 @@ namespace touchscreen { static const char *const TAG = "touchscreen"; +void Touchscreen::set_display(display::Display *display) { + this->display_ = display; + this->display_width_ = display->get_width(); + this->display_height_ = display->get_height(); + this->rotation_ = static_cast(display->get_rotation()); + + if (this->rotation_ == ROTATE_90_DEGREES || this->rotation_ == ROTATE_270_DEGREES) { + std::swap(this->display_width_, this->display_height_); + } +} + void Touchscreen::send_touch_(TouchPoint tp) { ESP_LOGV(TAG, "Touch (x=%d, y=%d)", tp.x, tp.y); this->touch_trigger_.trigger(tp); diff --git a/esphome/components/touchscreen/touchscreen.h b/esphome/components/touchscreen/touchscreen.h index 0597759894..24b3191880 100644 --- a/esphome/components/touchscreen/touchscreen.h +++ b/esphome/components/touchscreen/touchscreen.h @@ -31,13 +31,8 @@ enum TouchRotation { class Touchscreen { public: - void set_display(display::DisplayBuffer *display) { - this->display_ = display; - this->display_width_ = display->get_width_internal(); - this->display_height_ = display->get_height_internal(); - this->rotation_ = static_cast(display->get_rotation()); - } - display::DisplayBuffer *get_display() const { return this->display_; } + void set_display(display::Display *display); + display::Display *get_display() const { return this->display_; } Trigger *get_touch_trigger() { return &this->touch_trigger_; } @@ -49,7 +44,7 @@ class Touchscreen { uint16_t display_width_; uint16_t display_height_; - display::DisplayBuffer *display_; + display::Display *display_; TouchRotation rotation_; Trigger touch_trigger_; std::vector touch_listeners_; diff --git a/script/ci-custom.py b/script/ci-custom.py index 44ed83f392..a731e2e5b8 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -607,7 +607,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/button/button.h", "esphome/components/climate/climate.h", "esphome/components/cover/cover.h", - "esphome/components/display/display_buffer.h", + "esphome/components/display/display.h", "esphome/components/fan/fan.h", "esphome/components/i2c/i2c.h", "esphome/components/lock/lock.h", From f9fc438de8800428cb19230345861cd2d7c09adc Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 6 Jul 2023 03:58:04 +0200 Subject: [PATCH 0193/2607] Fixed ili9xxx_display update() method (#5013) There was an obsolete `if` statement left over from an other implementation. --- esphome/components/ili9xxx/ili9xxx_display.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 82217f8e40..750f629db2 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -152,12 +152,10 @@ void ILI9XXXDisplay::update() { this->need_update_ = true; return; } + this->prossing_update_ = true; do { - this->prossing_update_ = true; this->need_update_ = false; - if (!this->need_update_) { - this->do_update_(); - } + this->do_update_(); } while (this->need_update_); this->prossing_update_ = false; this->display_(); From e6834f25ed7355f6f9c27155e8da761da433e06f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Jul 2023 11:08:46 -1000 Subject: [PATCH 0194/2607] Fix bulk and single Bluetooth parser coexistence (#5073) --- .../bluetooth_proxy/bluetooth_connection.cpp | 4 ++ .../bluetooth_proxy/bluetooth_connection.h | 1 + .../bluetooth_proxy/bluetooth_proxy.cpp | 8 ++++ .../bluetooth_proxy/bluetooth_proxy.h | 1 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 42 +++++++++++++++---- .../esp32_ble_tracker/esp32_ble_tracker.h | 17 +++++--- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 26304325c1..97a25262cb 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -275,6 +275,10 @@ esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enabl return ESP_OK; } +esp32_ble_tracker::AdvertisementParserType BluetoothConnection::get_advertisement_parser_type() { + return this->proxy_->get_advertisement_parser_type(); +} + } // namespace bluetooth_proxy } // namespace esphome diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.h b/esphome/components/bluetooth_proxy/bluetooth_connection.h index 8b13f4d1c2..e6ab3cbccc 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.h +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.h @@ -14,6 +14,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase { bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; + esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override; esp_err_t read_characteristic(uint16_t handle); esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index b633fe2430..f188439d0e 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -198,6 +198,12 @@ void BluetoothProxy::loop() { } } +esp32_ble_tracker::AdvertisementParserType BluetoothProxy::get_advertisement_parser_type() { + if (this->raw_advertisements_) + return esp32_ble_tracker::AdvertisementParserType::RAW_ADVERTISEMENTS; + return esp32_ble_tracker::AdvertisementParserType::PARSED_ADVERTISEMENTS; +} + BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool reserve) { for (auto *connection : this->connections_) { if (connection->get_address() == address) @@ -435,6 +441,7 @@ void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection } this->api_connection_ = api_connection; this->raw_advertisements_ = flags & BluetoothProxySubscriptionFlag::SUBSCRIPTION_RAW_ADVERTISEMENTS; + this->parent_->recalculate_advertisement_parser_types(); } void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connection) { @@ -444,6 +451,7 @@ void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connecti } this->api_connection_ = nullptr; this->raw_advertisements_ = false; + this->parent_->recalculate_advertisement_parser_types(); } void BluetoothProxy::send_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) { diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index 97b6396b55..35a37f934a 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -51,6 +51,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) override; void dump_config() override; void loop() override; + esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override; void register_connection(BluetoothConnection *connection) { this->connections_.push_back(connection); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 0f6c4117d2..1569ea0dd5 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -107,16 +107,16 @@ void ESP32BLETracker::loop() { ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); } - bool bulk_parsed = false; - - for (auto *listener : this->listeners_) { - bulk_parsed |= listener->parse_devices(this->scan_result_buffer_, this->scan_result_index_); - } - for (auto *client : this->clients_) { - bulk_parsed |= client->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + if (this->raw_advertisements_) { + for (auto *listener : this->listeners_) { + listener->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } + for (auto *client : this->clients_) { + client->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } } - if (!bulk_parsed) { + if (this->parse_advertisements_) { for (size_t i = 0; i < index; i++) { ESPBTDevice device; device.parse_scan_rst(this->scan_result_buffer_[i]); @@ -284,6 +284,32 @@ void ESP32BLETracker::end_of_scan_() { void ESP32BLETracker::register_client(ESPBTClient *client) { client->app_id = ++this->app_id_; this->clients_.push_back(client); + this->recalculate_advertisement_parser_types(); +} + +void ESP32BLETracker::register_listener(ESPBTDeviceListener *listener) { + listener->set_parent(this); + this->listeners_.push_back(listener); + this->recalculate_advertisement_parser_types(); +} + +void ESP32BLETracker::recalculate_advertisement_parser_types() { + this->raw_advertisements_ = false; + this->parse_advertisements_ = false; + for (auto *listener : this->listeners_) { + if (listener->get_advertisement_parser_type() == AdvertisementParserType::PARSED_ADVERTISEMENTS) { + this->parse_advertisements_ = true; + } else { + this->raw_advertisements_ = true; + } + } + for (auto *client : this->clients_) { + if (client->get_advertisement_parser_type() == AdvertisementParserType::PARSED_ADVERTISEMENTS) { + this->parse_advertisements_ = true; + } else { + this->raw_advertisements_ = true; + } + } } void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 43e88fbf2b..6efdded3ff 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -27,6 +27,11 @@ using namespace esp32_ble; using adv_data_t = std::vector; +enum AdvertisementParserType { + PARSED_ADVERTISEMENTS, + RAW_ADVERTISEMENTS, +}; + struct ServiceData { ESPBTUUID uuid; adv_data_t data; @@ -116,6 +121,9 @@ class ESPBTDeviceListener { virtual bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) { return false; }; + virtual AdvertisementParserType get_advertisement_parser_type() { + return AdvertisementParserType::PARSED_ADVERTISEMENTS; + }; void set_parent(ESP32BLETracker *parent) { parent_ = parent; } protected: @@ -184,12 +192,9 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv void loop() override; - void register_listener(ESPBTDeviceListener *listener) { - listener->set_parent(this); - this->listeners_.push_back(listener); - } - + void register_listener(ESPBTDeviceListener *listener); void register_client(ESPBTClient *client); + void recalculate_advertisement_parser_types(); void print_bt_device_info(const ESPBTDevice &device); @@ -231,6 +236,8 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv bool scan_continuous_; bool scan_active_; bool scanner_idle_; + bool raw_advertisements_{false}; + bool parse_advertisements_{false}; SemaphoreHandle_t scan_result_lock_; SemaphoreHandle_t scan_end_lock_; size_t scan_result_index_{0}; From 8739552c0b24005ae990067cd854ecbf63fcb71c Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 9 Jul 2023 17:55:02 -0400 Subject: [PATCH 0195/2607] binary_sensor: Validate max_length for on_click/on_double_click (#5068) --- esphome/components/binary_sensor/__init__.py | 58 +++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 41b4c5a0d7..95e35a45f2 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -359,6 +359,18 @@ def validate_multi_click_timing(value): validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") +def validate_click_timing(value): + for v in value: + min_length = v.get(CONF_MIN_LENGTH) + max_length = v.get(CONF_MAX_LENGTH) + if max_length < min_length: + raise cv.Invalid( + f"Max length ({max_length}) must be larger than min length ({min_length})." + ) + + return value + + BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( { cv.GenerateID(): cv.declare_id(BinarySensor), @@ -378,27 +390,33 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger), } ), - cv.Optional(CONF_ON_CLICK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, - } + cv.Optional(CONF_ON_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } + ), + validate_click_timing, ), - cv.Optional(CONF_ON_DOUBLE_CLICK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, - } + cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } + ), + validate_click_timing, ), cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation( { From 8bf8892ab34cc3f5688ab006312652c0161c847a Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 10 Jul 2023 00:02:42 +0200 Subject: [PATCH 0196/2607] [Ethernet] ksz8081rna support (#4739) Co-authored-by: Your Name --- esphome/components/ethernet/__init__.py | 1 + .../ethernet/ethernet_component.cpp | 44 ++++++++++++++++++- .../components/ethernet/ethernet_component.h | 3 ++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index bedc0a4c30..6f0f3741dd 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -35,6 +35,7 @@ ETHERNET_TYPES = { "IP101": EthernetType.ETHERNET_TYPE_IP101, "JL1101": EthernetType.ETHERNET_TYPE_JL1101, "KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081, + "KSZ8081RNA": EthernetType.ETHERNET_TYPE_KSZ8081RNA, } emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index fc1068f2a8..3b5804abdd 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -84,7 +84,8 @@ void EthernetComponent::setup() { this->phy_ = esp_eth_phy_new_jl1101(&phy_config); break; } - case ETHERNET_TYPE_KSZ8081: { + case ETHERNET_TYPE_KSZ8081: + case ETHERNET_TYPE_KSZ8081RNA: { #if ESP_IDF_VERSION_MAJOR >= 5 this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); #else @@ -102,6 +103,12 @@ void EthernetComponent::setup() { this->eth_handle_ = nullptr; err = esp_eth_driver_install(ð_config, &this->eth_handle_); ESPHL_ERROR_CHECK(err, "ETH driver install error"); + + if (this->type_ == ETHERNET_TYPE_KSZ8081RNA && this->clk_mode_ == EMAC_CLK_OUT) { + // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide. + this->ksz8081_set_clock_reference_(mac); + } + /* attach Ethernet driver to TCP/IP stack */ err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_)); ESPHL_ERROR_CHECK(err, "ETH netif attach error"); @@ -184,6 +191,10 @@ void EthernetComponent::dump_config() { eth_type = "KSZ8081"; break; + case ETHERNET_TYPE_KSZ8081RNA: + eth_type = "KSZ8081RNA"; + break; + default: eth_type = "Unknown"; break; @@ -385,6 +396,37 @@ bool EthernetComponent::powerdown() { return true; } +void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { +#define KSZ80XX_PC2R_REG_ADDR (0x1F) + + esp_err_t err; + + uint32_t phy_control_2; + err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2)); + ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); + ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); + + /* + * Bit 7 is `RMII Reference Clock Select`. Default is `0`. + * KSZ8081RNA: + * 0 - clock input to XI (Pin 8) is 25 MHz for RMII – 25 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. + * KSZ8081RND: + * 0 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII – 25 MHz clock mode. + */ + if ((phy_control_2 & (1 << 7)) != (1 << 7)) { + phy_control_2 |= 1 << 7; + err = mac->write_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, phy_control_2); + ESPHL_ERROR_CHECK(err, "Write PHY Control 2 failed"); + err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2)); + ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); + ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); + } + +#undef KSZ80XX_PC2R_REG_ADDR +} + } // namespace ethernet } // namespace esphome diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 918e47212f..f6b67f3f82 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -21,6 +21,7 @@ enum EthernetType { ETHERNET_TYPE_IP101, ETHERNET_TYPE_JL1101, ETHERNET_TYPE_KSZ8081, + ETHERNET_TYPE_KSZ8081RNA, }; struct ManualIP { @@ -67,6 +68,8 @@ class EthernetComponent : public Component { void start_connect_(); void dump_connect_params_(); + /// @brief Set `RMII Reference Clock Select` bit for KSZ8081. + void ksz8081_set_clock_reference_(esp_eth_mac_t *mac); std::string use_address_; uint8_t phy_addr_{0}; From 8ca9115dc8efd1274e441aa65d7249f12ba4d2df Mon Sep 17 00:00:00 2001 From: Trevor North Date: Sun, 9 Jul 2023 23:03:54 +0100 Subject: [PATCH 0197/2607] Improve BME680 BSEC sensor device classes (#4859) --- esphome/components/bme680_bsec/sensor.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 8d00012150..3bd082481e 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -6,8 +6,10 @@ from esphome.const import ( CONF_HUMIDITY, CONF_PRESSURE, CONF_TEMPERATURE, + DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, @@ -17,8 +19,6 @@ from esphome.const import ( UNIT_PERCENT, ICON_GAS_CYLINDER, ICON_GAUGE, - ICON_THERMOMETER, - ICON_WATER_PERCENT, ) from . import ( BME680BSECComponent, @@ -35,7 +35,6 @@ CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" UNIT_IAQ = "IAQ" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" -ICON_TEST_TUBE = "mdi:test-tube" TYPES = [ CONF_TEMPERATURE, @@ -53,7 +52,6 @@ CONFIG_SCHEMA = cv.Schema( cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, - icon=ICON_THERMOMETER, accuracy_decimals=1, device_class=DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, @@ -62,16 +60,14 @@ CONFIG_SCHEMA = cv.Schema( ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( unit_of_measurement=UNIT_HECTOPASCAL, - icon=ICON_GAUGE, accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, + device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, state_class=STATE_CLASS_MEASUREMENT, ).extend( {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, - icon=ICON_WATER_PERCENT, accuracy_decimals=1, device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, @@ -97,14 +93,14 @@ CONFIG_SCHEMA = cv.Schema( ), cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema( unit_of_measurement=UNIT_PARTS_PER_MILLION, - icon=ICON_TEST_TUBE, accuracy_decimals=1, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema( unit_of_measurement=UNIT_PARTS_PER_MILLION, - icon=ICON_TEST_TUBE, accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), } From 62aee36f82bf0b88c61dbed0ebb067abfd0c3798 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Jul 2023 11:08:46 -1000 Subject: [PATCH 0198/2607] Fix bulk and single Bluetooth parser coexistence (#5073) --- .../bluetooth_proxy/bluetooth_connection.cpp | 4 ++ .../bluetooth_proxy/bluetooth_connection.h | 1 + .../bluetooth_proxy/bluetooth_proxy.cpp | 8 ++++ .../bluetooth_proxy/bluetooth_proxy.h | 1 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 42 +++++++++++++++---- .../esp32_ble_tracker/esp32_ble_tracker.h | 17 +++++--- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 26304325c1..97a25262cb 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -275,6 +275,10 @@ esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enabl return ESP_OK; } +esp32_ble_tracker::AdvertisementParserType BluetoothConnection::get_advertisement_parser_type() { + return this->proxy_->get_advertisement_parser_type(); +} + } // namespace bluetooth_proxy } // namespace esphome diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.h b/esphome/components/bluetooth_proxy/bluetooth_connection.h index 8b13f4d1c2..e6ab3cbccc 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.h +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.h @@ -14,6 +14,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase { bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; + esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override; esp_err_t read_characteristic(uint16_t handle); esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index b633fe2430..f188439d0e 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -198,6 +198,12 @@ void BluetoothProxy::loop() { } } +esp32_ble_tracker::AdvertisementParserType BluetoothProxy::get_advertisement_parser_type() { + if (this->raw_advertisements_) + return esp32_ble_tracker::AdvertisementParserType::RAW_ADVERTISEMENTS; + return esp32_ble_tracker::AdvertisementParserType::PARSED_ADVERTISEMENTS; +} + BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool reserve) { for (auto *connection : this->connections_) { if (connection->get_address() == address) @@ -435,6 +441,7 @@ void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection } this->api_connection_ = api_connection; this->raw_advertisements_ = flags & BluetoothProxySubscriptionFlag::SUBSCRIPTION_RAW_ADVERTISEMENTS; + this->parent_->recalculate_advertisement_parser_types(); } void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connection) { @@ -444,6 +451,7 @@ void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connecti } this->api_connection_ = nullptr; this->raw_advertisements_ = false; + this->parent_->recalculate_advertisement_parser_types(); } void BluetoothProxy::send_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) { diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index 97b6396b55..35a37f934a 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -51,6 +51,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) override; void dump_config() override; void loop() override; + esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override; void register_connection(BluetoothConnection *connection) { this->connections_.push_back(connection); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 0f6c4117d2..1569ea0dd5 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -107,16 +107,16 @@ void ESP32BLETracker::loop() { ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); } - bool bulk_parsed = false; - - for (auto *listener : this->listeners_) { - bulk_parsed |= listener->parse_devices(this->scan_result_buffer_, this->scan_result_index_); - } - for (auto *client : this->clients_) { - bulk_parsed |= client->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + if (this->raw_advertisements_) { + for (auto *listener : this->listeners_) { + listener->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } + for (auto *client : this->clients_) { + client->parse_devices(this->scan_result_buffer_, this->scan_result_index_); + } } - if (!bulk_parsed) { + if (this->parse_advertisements_) { for (size_t i = 0; i < index; i++) { ESPBTDevice device; device.parse_scan_rst(this->scan_result_buffer_[i]); @@ -284,6 +284,32 @@ void ESP32BLETracker::end_of_scan_() { void ESP32BLETracker::register_client(ESPBTClient *client) { client->app_id = ++this->app_id_; this->clients_.push_back(client); + this->recalculate_advertisement_parser_types(); +} + +void ESP32BLETracker::register_listener(ESPBTDeviceListener *listener) { + listener->set_parent(this); + this->listeners_.push_back(listener); + this->recalculate_advertisement_parser_types(); +} + +void ESP32BLETracker::recalculate_advertisement_parser_types() { + this->raw_advertisements_ = false; + this->parse_advertisements_ = false; + for (auto *listener : this->listeners_) { + if (listener->get_advertisement_parser_type() == AdvertisementParserType::PARSED_ADVERTISEMENTS) { + this->parse_advertisements_ = true; + } else { + this->raw_advertisements_ = true; + } + } + for (auto *client : this->clients_) { + if (client->get_advertisement_parser_type() == AdvertisementParserType::PARSED_ADVERTISEMENTS) { + this->parse_advertisements_ = true; + } else { + this->raw_advertisements_ = true; + } + } } void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 43e88fbf2b..6efdded3ff 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -27,6 +27,11 @@ using namespace esp32_ble; using adv_data_t = std::vector; +enum AdvertisementParserType { + PARSED_ADVERTISEMENTS, + RAW_ADVERTISEMENTS, +}; + struct ServiceData { ESPBTUUID uuid; adv_data_t data; @@ -116,6 +121,9 @@ class ESPBTDeviceListener { virtual bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) { return false; }; + virtual AdvertisementParserType get_advertisement_parser_type() { + return AdvertisementParserType::PARSED_ADVERTISEMENTS; + }; void set_parent(ESP32BLETracker *parent) { parent_ = parent; } protected: @@ -184,12 +192,9 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv void loop() override; - void register_listener(ESPBTDeviceListener *listener) { - listener->set_parent(this); - this->listeners_.push_back(listener); - } - + void register_listener(ESPBTDeviceListener *listener); void register_client(ESPBTClient *client); + void recalculate_advertisement_parser_types(); void print_bt_device_info(const ESPBTDevice &device); @@ -231,6 +236,8 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv bool scan_continuous_; bool scan_active_; bool scanner_idle_; + bool raw_advertisements_{false}; + bool parse_advertisements_{false}; SemaphoreHandle_t scan_result_lock_; SemaphoreHandle_t scan_end_lock_; size_t scan_result_index_{0}; From d7bfdd0efce65920404d2e947f1dfd2a63b00b78 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 9 Jul 2023 17:55:02 -0400 Subject: [PATCH 0199/2607] binary_sensor: Validate max_length for on_click/on_double_click (#5068) --- esphome/components/binary_sensor/__init__.py | 58 +++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index f4a5c95b12..eaf11c056a 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -323,6 +323,18 @@ def validate_multi_click_timing(value): validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") +def validate_click_timing(value): + for v in value: + min_length = v.get(CONF_MIN_LENGTH) + max_length = v.get(CONF_MAX_LENGTH) + if max_length < min_length: + raise cv.Invalid( + f"Max length ({max_length}) must be larger than min length ({min_length})." + ) + + return value + + BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( { cv.GenerateID(): cv.declare_id(BinarySensor), @@ -342,27 +354,33 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger), } ), - cv.Optional(CONF_ON_CLICK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, - } + cv.Optional(CONF_ON_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } + ), + validate_click_timing, ), - cv.Optional(CONF_ON_DOUBLE_CLICK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, - } + cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } + ), + validate_click_timing, ), cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation( { From a77cf1beec9454b21568cc6ef4413ebafb04e5f9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:24:49 +1200 Subject: [PATCH 0200/2607] Bump version to 2023.6.5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d8eda3fd63..ea660723e4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.6.4" +__version__ = "2023.6.5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From c5aacdd68250a0c55136ec49c114aed14b2cad5b Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 10 Jul 2023 01:30:39 +0200 Subject: [PATCH 0201/2607] Update RP2040 Aruino framwork and platform to latest (#5025) --- esphome/components/rp2040/__init__.py | 8 ++++---- platformio.ini | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 030d586626..dafafc531c 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -62,19 +62,19 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/earlephilhower/arduino-pico/releases # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 6, 4) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 3, 0) # The platformio/raspberrypi version to use for arduino frameworks # - https://github.com/platformio/platform-raspberrypi/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 7, 0) +ARDUINO_PLATFORM_VERSION = cv.Version(1, 9, 0) def _arduino_check_versions(value): value = value.copy() lookups = { - "dev": (cv.Version(2, 6, 4), "https://github.com/earlephilhower/arduino-pico"), - "latest": (cv.Version(2, 6, 4), None), + "dev": (cv.Version(3, 3, 0), "https://github.com/earlephilhower/arduino-pico"), + "latest": (cv.Version(3, 3, 0), None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), } diff --git a/platformio.ini b/platformio.ini index 868880e1d7..b970ef7a69 100644 --- a/platformio.ini +++ b/platformio.ini @@ -157,7 +157,7 @@ board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/2.6.2/rp2040-2.6.2.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.3.0/rp2040-3.3.0.zip framework = arduino lib_deps = From ddde1ee31ef96476c7a7d1c8b8fe306aa4d2e503 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 10 Jul 2023 01:34:43 +0200 Subject: [PATCH 0202/2607] Allow pillow versions over 10 (#5071) --- esphome/components/font/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 7a314bb032..29150afe3f 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -3,6 +3,7 @@ from pathlib import Path import hashlib import os import re +from packaging import version import requests @@ -69,7 +70,7 @@ def validate_pillow_installed(value): "(pip install pillow)" ) from err - if PIL.__version__[0] < "4": + if version.parse(PIL.__version__) < version.parse("4.0.0"): raise cv.Invalid( "Please update your pillow installation to at least 4.0.x. " "(pip install -U pillow)" From 98fd092053bef74a6349cc92f70d5602217efeb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Tue, 11 Jul 2023 06:38:28 +0900 Subject: [PATCH 0203/2607] display: rename `DisplayBufferRef` to `DisplayRef` (#5002) --- esphome/components/addressable_light/display.py | 2 +- esphome/components/display/__init__.py | 5 +++-- esphome/components/display/display.h | 9 --------- esphome/components/ili9xxx/display.py | 2 +- esphome/components/inkplate6/display.py | 2 +- esphome/components/pcd8544/display.py | 2 +- esphome/components/ssd1306_base/__init__.py | 2 +- esphome/components/ssd1322_base/__init__.py | 2 +- esphome/components/ssd1325_base/__init__.py | 2 +- esphome/components/ssd1327_base/__init__.py | 2 +- esphome/components/ssd1331_base/__init__.py | 2 +- esphome/components/ssd1351_base/__init__.py | 2 +- esphome/components/st7735/display.py | 2 +- esphome/components/st7789v/display.py | 2 +- esphome/components/waveshare_epaper/display.py | 2 +- 15 files changed, 16 insertions(+), 24 deletions(-) diff --git a/esphome/components/addressable_light/display.py b/esphome/components/addressable_light/display.py index 0684bf8dfc..5fdd84ac2d 100644 --- a/esphome/components/addressable_light/display.py +++ b/esphome/components/addressable_light/display.py @@ -58,6 +58,6 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index 0d403f99f0..b7a8508fc8 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -18,10 +18,11 @@ from esphome.core import coroutine_with_priority IS_PLATFORM_COMPONENT = True display_ns = cg.esphome_ns.namespace("display") +Display = display_ns.class_("Display") DisplayBuffer = display_ns.class_("DisplayBuffer") DisplayPage = display_ns.class_("DisplayPage") DisplayPagePtr = DisplayPage.operator("ptr") -DisplayBufferRef = DisplayBuffer.operator("ref") +DisplayRef = Display.operator("ref") DisplayPageShowAction = display_ns.class_("DisplayPageShowAction", automation.Action) DisplayPageShowNextAction = display_ns.class_( "DisplayPageShowNextAction", automation.Action @@ -96,7 +97,7 @@ async def setup_display_core_(var, config): pages = [] for conf in config[CONF_PAGES]: lambda_ = await cg.process_lambda( - conf[CONF_LAMBDA], [(DisplayBufferRef, "it")], return_type=cg.void + conf[CONF_LAMBDA], [(DisplayRef, "it")], return_type=cg.void ) page = cg.new_Pvariable(conf[CONF_ID], lambda_) pages.append(page) diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 2f6fb563cc..08d8c70e0d 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -133,12 +133,10 @@ enum DisplayRotation { }; class Display; -class DisplayBuffer; class DisplayPage; class DisplayOnPageChangeTrigger; using display_writer_t = std::function; -using display_buffer_writer_t = std::function; #define LOG_DISPLAY(prefix, type, obj) \ if ((obj) != nullptr) { \ @@ -411,10 +409,6 @@ class Display { /// Internal method to set the display writer lambda. void set_writer(display_writer_t &&writer); - void set_writer(const display_buffer_writer_t &writer) { - // Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef` - this->set_writer([writer](Display &display) { return writer((display::DisplayBuffer &) display); }); - } void show_page(DisplayPage *page); void show_next_page(); @@ -499,9 +493,6 @@ class Display { class DisplayPage { public: DisplayPage(display_writer_t writer); - // Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef` - DisplayPage(const display_buffer_writer_t &writer) - : DisplayPage([writer](Display &display) { return writer((display::DisplayBuffer &) display); }) {} void show(); void show_next(); void show_prev(); diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 6021da5eeb..0435460b6a 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -121,7 +121,7 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index a17f37c920..7534731175 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -115,7 +115,7 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py index d0184a58d3..b4c8f432cf 100644 --- a/esphome/components/pcd8544/display.py +++ b/esphome/components/pcd8544/display.py @@ -52,6 +52,6 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1306_base/__init__.py b/esphome/components/ssd1306_base/__init__.py index 48143b9e1a..f4abd845c8 100644 --- a/esphome/components/ssd1306_base/__init__.py +++ b/esphome/components/ssd1306_base/__init__.py @@ -96,6 +96,6 @@ async def setup_ssd1306(var, config): cg.add(var.init_invert(config[CONF_INVERT])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1322_base/__init__.py b/esphome/components/ssd1322_base/__init__.py index 434caf4e35..97fb0d2a74 100644 --- a/esphome/components/ssd1322_base/__init__.py +++ b/esphome/components/ssd1322_base/__init__.py @@ -46,6 +46,6 @@ async def setup_ssd1322(var, config): cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1325_base/__init__.py b/esphome/components/ssd1325_base/__init__.py index 68be287d2a..1a6f7fb519 100644 --- a/esphome/components/ssd1325_base/__init__.py +++ b/esphome/components/ssd1325_base/__init__.py @@ -50,6 +50,6 @@ async def setup_ssd1325(var, config): cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1327_base/__init__.py b/esphome/components/ssd1327_base/__init__.py index eada66a6e3..af2eb3489d 100644 --- a/esphome/components/ssd1327_base/__init__.py +++ b/esphome/components/ssd1327_base/__init__.py @@ -37,6 +37,6 @@ async def setup_ssd1327(var, config): cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1331_base/__init__.py b/esphome/components/ssd1331_base/__init__.py index 067f55a252..169c0eed1a 100644 --- a/esphome/components/ssd1331_base/__init__.py +++ b/esphome/components/ssd1331_base/__init__.py @@ -28,6 +28,6 @@ async def setup_ssd1331(var, config): cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1351_base/__init__.py b/esphome/components/ssd1351_base/__init__.py index 555d6c5e2e..2988dd4bf3 100644 --- a/esphome/components/ssd1351_base/__init__.py +++ b/esphome/components/ssd1351_base/__init__.py @@ -38,6 +38,6 @@ async def setup_ssd1351(var, config): cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/st7735/display.py b/esphome/components/st7735/display.py index ae31f604a5..652d31662d 100644 --- a/esphome/components/st7735/display.py +++ b/esphome/components/st7735/display.py @@ -77,7 +77,7 @@ async def setup_st7735(var, config): cg.add(var.set_reset_pin(reset)) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index a81101f2d1..16c1e790bd 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -121,7 +121,7 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 11deab5310..6113fe943c 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -153,7 +153,7 @@ async def to_code(config): if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) if CONF_RESET_PIN in config: From a39181592155a15ae908fff657f7e26e0cdba935 Mon Sep 17 00:00:00 2001 From: kahrendt Date: Tue, 11 Jul 2023 00:24:18 -0400 Subject: [PATCH 0204/2607] Add Zio Ultrasonic Distance Sensor Component (#5059) --- CODEOWNERS | 1 + esphome/components/zio_ultrasonic/__init__.py | 0 esphome/components/zio_ultrasonic/sensor.py | 34 +++++++++++++++++++ .../zio_ultrasonic/zio_ultrasonic.cpp | 31 +++++++++++++++++ .../zio_ultrasonic/zio_ultrasonic.h | 22 ++++++++++++ tests/test1.yaml | 4 +++ 6 files changed, 92 insertions(+) create mode 100644 esphome/components/zio_ultrasonic/__init__.py create mode 100644 esphome/components/zio_ultrasonic/sensor.py create mode 100644 esphome/components/zio_ultrasonic/zio_ultrasonic.cpp create mode 100644 esphome/components/zio_ultrasonic/zio_ultrasonic.h diff --git a/CODEOWNERS b/CODEOWNERS index 94813f73dd..ca2c259624 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -321,3 +321,4 @@ esphome/components/xiaomi_mhoc401/* @vevsvevs esphome/components/xiaomi_rtcgq02lm/* @jesserockz esphome/components/xl9535/* @mreditor97 esphome/components/xpt2046/* @nielsnl68 @numo68 +esphome/components/zio_ultrasonic/* @kahrendt diff --git a/esphome/components/zio_ultrasonic/__init__.py b/esphome/components/zio_ultrasonic/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/zio_ultrasonic/sensor.py b/esphome/components/zio_ultrasonic/sensor.py new file mode 100644 index 0000000000..c5eed14e64 --- /dev/null +++ b/esphome/components/zio_ultrasonic/sensor.py @@ -0,0 +1,34 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + DEVICE_CLASS_DISTANCE, + STATE_CLASS_MEASUREMENT, +) + +DEPENDENCIES = ["i2c"] +CODEOWNERS = ["@kahrendt"] + +zio_ultrasonic_ns = cg.esphome_ns.namespace("zio_ultrasonic") + +ZioUltrasonicComponent = zio_ultrasonic_ns.class_( + "ZioUltrasonicComponent", cg.PollingComponent, i2c.I2CDevice, sensor.Sensor +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + ZioUltrasonicComponent, + unit_of_measurement="mm", + accuracy_decimals=0, + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x00)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/zio_ultrasonic/zio_ultrasonic.cpp b/esphome/components/zio_ultrasonic/zio_ultrasonic.cpp new file mode 100644 index 0000000000..565bbe9b4f --- /dev/null +++ b/esphome/components/zio_ultrasonic/zio_ultrasonic.cpp @@ -0,0 +1,31 @@ + +#include "zio_ultrasonic.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace zio_ultrasonic { + +static const char *const TAG = "zio_ultrasonic"; + +void ZioUltrasonicComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Zio Ultrasonic Sensor:"); + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Sensor:", this); +} + +void ZioUltrasonicComponent::update() { + uint16_t distance; + + // Read an unsigned two byte integerfrom register 0x01 which gives distance in mm + if (!this->read_byte_16(0x01, &distance)) { + ESP_LOGE(TAG, "Error reading data from Zio Ultrasonic"); + this->publish_state(NAN); + } else { + this->publish_state(distance); + } +} + +} // namespace zio_ultrasonic +} // namespace esphome diff --git a/esphome/components/zio_ultrasonic/zio_ultrasonic.h b/esphome/components/zio_ultrasonic/zio_ultrasonic.h new file mode 100644 index 0000000000..84c8d44c65 --- /dev/null +++ b/esphome/components/zio_ultrasonic/zio_ultrasonic.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +static const char *const TAG = "Zio Ultrasonic"; + +namespace esphome { +namespace zio_ultrasonic { + +class ZioUltrasonicComponent : public i2c::I2CDevice, public PollingComponent, public sensor::Sensor { + public: + float get_setup_priority() const override { return setup_priority::DATA; } + + void dump_config() override; + + void update() override; +}; + +} // namespace zio_ultrasonic +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 05ba07d1d8..21379e807c 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1310,6 +1310,10 @@ sensor: fault_count: 1 polarity: active_high function: comparator + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s + i2c_id: i2c_bus esp32_touch: setup_mode: false From f3cdcc008a01133dcf576ffe6bb712bca49fd05b Mon Sep 17 00:00:00 2001 From: jan-hofmeier <37298146+jan-hofmeier@users.noreply.github.com> Date: Tue, 11 Jul 2023 07:12:43 +0200 Subject: [PATCH 0205/2607] Add Alpha3 pump component (#3787) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/alpha3/__init__.py | 1 + esphome/components/alpha3/alpha3.cpp | 189 ++++++++++++++++++++++++++ esphome/components/alpha3/alpha3.h | 73 ++++++++++ esphome/components/alpha3/sensor.py | 85 ++++++++++++ esphome/const.py | 4 + tests/test1.yaml | 11 ++ 7 files changed, 364 insertions(+) create mode 100644 esphome/components/alpha3/__init__.py create mode 100644 esphome/components/alpha3/alpha3.cpp create mode 100644 esphome/components/alpha3/alpha3.h create mode 100644 esphome/components/alpha3/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index ca2c259624..68a8eb6d18 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -21,6 +21,7 @@ esphome/components/airthings_wave_base/* @jeromelaban @ncareau esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban esphome/components/alarm_control_panel/* @grahambrown11 +esphome/components/alpha3/* @jan-hofmeier esphome/components/am43/* @buxtronix esphome/components/am43/cover/* @buxtronix esphome/components/am43/sensor/* @buxtronix diff --git a/esphome/components/alpha3/__init__.py b/esphome/components/alpha3/__init__.py new file mode 100644 index 0000000000..7cd320c80f --- /dev/null +++ b/esphome/components/alpha3/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@jan-hofmeier"] diff --git a/esphome/components/alpha3/alpha3.cpp b/esphome/components/alpha3/alpha3.cpp new file mode 100644 index 0000000000..17899c31cb --- /dev/null +++ b/esphome/components/alpha3/alpha3.cpp @@ -0,0 +1,189 @@ +#include "alpha3.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include //gives ntohl + +#ifdef USE_ESP32 + +namespace esphome { +namespace alpha3 { + +static const char *const TAG = "alpha3"; + +void Alpha3::dump_config() { + ESP_LOGCONFIG(TAG, "ALPHA3"); + LOG_SENSOR(" ", "Flow", this->flow_sensor_); + LOG_SENSOR(" ", "Head", this->head_sensor_); + LOG_SENSOR(" ", "Power", this->power_sensor_); + LOG_SENSOR(" ", "Current", this->current_sensor_); + LOG_SENSOR(" ", "Speed", this->speed_sensor_); + LOG_SENSOR(" ", "Voltage", this->voltage_sensor_); +} + +void Alpha3::setup() {} + +void Alpha3::extract_publish_sensor_value_(const uint8_t *response, int16_t length, int16_t response_offset, + int16_t value_offset, sensor::Sensor *sensor, float factor) { + if (sensor == nullptr) + return; + // we need to handle cases where a value is split over two packets + const int16_t value_length = 4; // 32bit float + // offset inside current response packet + auto rel_offset = value_offset - response_offset; + if (rel_offset <= -value_length) + return; // aready passed the value completly + if (rel_offset >= length) + return; // value not in this packet + + auto start_offset = std::max(0, rel_offset); + auto end_offset = std::min((int16_t) (rel_offset + value_length), length); + auto copy_length = end_offset - start_offset; + auto buffer_offset = std::max(-rel_offset, 0); + std::memcpy(this->buffer_ + buffer_offset, response + start_offset, copy_length); + + if (rel_offset + value_length <= length) { + // we have the whole value + void *buffer = this->buffer_; // to prevent warnings when casting the pointer + *((int32_t *) buffer) = ntohl(*((int32_t *) buffer)); // values are big endian + float fvalue = *((float *) buffer); + sensor->publish_state(fvalue * factor); + } +} + +bool Alpha3::is_current_response_type_(const uint8_t *response_type) { + return !std::memcmp(this->response_type_, response_type, GENI_RESPONSE_TYPE_LENGTH); +} + +void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) { + if (this->response_offset_ >= this->response_length_) { + ESP_LOGD(TAG, "[%s] GENI response begin", this->parent_->address_str().c_str()); + if (length < GENI_RESPONSE_HEADER_LENGTH) { + ESP_LOGW(TAG, "[%s] response to short", this->parent_->address_str().c_str()); + return; + } + if (response[0] != 36 || response[2] != 248 || response[3] != 231 || response[4] != 10) { + ESP_LOGW(TAG, "[%s] response bytes %d %d %d %d %d don't match GENI HEADER", this->parent_->address_str().c_str(), + response[0], response[1], response[2], response[3], response[4]); + return; + } + this->response_length_ = response[1] - GENI_RESPONSE_HEADER_LENGTH + 2; // maybe 2 byte checksum + this->response_offset_ = -GENI_RESPONSE_HEADER_LENGTH; + std::memcpy(this->response_type_, response + 5, GENI_RESPONSE_TYPE_LENGTH); + } + + auto extract_publish_sensor_value = [response, length, this](int16_t value_offset, sensor::Sensor *sensor, + float factor) { + this->extract_publish_sensor_value_(response, length, this->response_offset_, value_offset, sensor, factor); + }; + + if (this->is_current_response_type_(GENI_RESPONSE_TYPE_FLOW_HEAD)) { + ESP_LOGD(TAG, "[%s] FLOW HEAD Response", this->parent_->address_str().c_str()); + extract_publish_sensor_value(GENI_RESPONSE_FLOW_OFFSET, this->flow_sensor_, 3600.0F); + extract_publish_sensor_value(GENI_RESPONSE_HEAD_OFFSET, this->head_sensor_, .0001F); + } else if (this->is_current_response_type_(GENI_RESPONSE_TYPE_POWER)) { + ESP_LOGD(TAG, "[%s] POWER Response", this->parent_->address_str().c_str()); + extract_publish_sensor_value(GENI_RESPONSE_POWER_OFFSET, this->power_sensor_, 1.0F); + extract_publish_sensor_value(GENI_RESPONSE_CURRENT_OFFSET, this->current_sensor_, 1.0F); + extract_publish_sensor_value(GENI_RESPONSE_MOTOR_SPEED_OFFSET, this->speed_sensor_, 1.0F); + extract_publish_sensor_value(GENI_RESPONSE_VOLTAGE_AC_OFFSET, this->voltage_sensor_, 1.0F); + } else { + ESP_LOGW(TAG, "unkown GENI response Type %d %d %d %d %d %d %d %d", this->response_type_[0], this->response_type_[1], + this->response_type_[2], this->response_type_[3], this->response_type_[4], this->response_type_[5], + this->response_type_[6], this->response_type_[7]); + } + this->response_offset_ += length; +} + +void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { + switch (event) { + case ESP_GATTC_OPEN_EVT: { + this->response_offset_ = 0; + this->response_length_ = 0; + ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str()); + break; + } + case ESP_GATTC_CONNECT_EVT: { + if (std::memcmp(param->connect.remote_bda, this->parent_->get_remote_bda(), 6) != 0) + return; + auto ret = esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT); + if (ret) { + ESP_LOGW(TAG, "esp_ble_set_encryption failed, status=%x", ret); + } + break; + } + case ESP_GATTC_DISCONNECT_EVT: { + this->node_state = espbt::ClientState::IDLE; + if (this->flow_sensor_ != nullptr) + this->flow_sensor_->publish_state(NAN); + if (this->head_sensor_ != nullptr) + this->head_sensor_->publish_state(NAN); + if (this->power_sensor_ != nullptr) + this->power_sensor_->publish_state(NAN); + if (this->current_sensor_ != nullptr) + this->current_sensor_->publish_state(NAN); + if (this->speed_sensor_ != nullptr) + this->speed_sensor_->publish_state(NAN); + if (this->speed_sensor_ != nullptr) + this->voltage_sensor_->publish_state(NAN); + break; + } + case ESP_GATTC_SEARCH_CMPL_EVT: { + auto *chr = this->parent_->get_characteristic(ALPHA3_GENI_SERVICE_UUID, ALPHA3_GENI_CHARACTERISTIC_UUID); + if (chr == nullptr) { + ESP_LOGE(TAG, "[%s] No GENI service found at device, not an Alpha3..?", this->parent_->address_str().c_str()); + break; + } + auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(), + chr->handle); + if (status) { + ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status); + } + this->geni_handle_ = chr->handle; + break; + } + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + this->node_state = espbt::ClientState::ESTABLISHED; + this->update(); + break; + } + case ESP_GATTC_NOTIFY_EVT: { + if (param->notify.handle == this->geni_handle_) { + this->handle_geni_response_(param->notify.value, param->notify.value_len); + } + break; + } + default: + break; + } +} + +void Alpha3::send_request_(uint8_t *request, size_t len) { + auto status = + esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->geni_handle_, len, + request, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); + if (status) + ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); +} + +void Alpha3::update() { + if (this->node_state != espbt::ClientState::ESTABLISHED) { + ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str().c_str()); + return; + } + + if (this->flow_sensor_ != nullptr || this->head_sensor_ != nullptr) { + uint8_t geni_request_flow_head[] = {39, 7, 231, 248, 10, 3, 93, 1, 33, 82, 31}; + this->send_request_(geni_request_flow_head, sizeof(geni_request_flow_head)); + delay(25); // need to wait between requests + } + if (this->power_sensor_ != nullptr || this->current_sensor_ != nullptr || this->speed_sensor_ != nullptr || + this->voltage_sensor_ != nullptr) { + uint8_t geni_request_power[] = {39, 7, 231, 248, 10, 3, 87, 0, 69, 138, 205}; + this->send_request_(geni_request_power, sizeof(geni_request_power)); + delay(25); // need to wait between requests + } +} +} // namespace alpha3 +} // namespace esphome + +#endif diff --git a/esphome/components/alpha3/alpha3.h b/esphome/components/alpha3/alpha3.h new file mode 100644 index 0000000000..325c70a538 --- /dev/null +++ b/esphome/components/alpha3/alpha3.h @@ -0,0 +1,73 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/ble_client/ble_client.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/sensor/sensor.h" + +#ifdef USE_ESP32 + +#include + +namespace esphome { +namespace alpha3 { + +namespace espbt = esphome::esp32_ble_tracker; + +static const espbt::ESPBTUUID ALPHA3_GENI_SERVICE_UUID = espbt::ESPBTUUID::from_uint16(0xfe5d); +static const espbt::ESPBTUUID ALPHA3_GENI_CHARACTERISTIC_UUID = + espbt::ESPBTUUID::from_raw({static_cast(0xa9), 0x7b, static_cast(0xb8), static_cast(0x85), 0x0, + 0x1a, 0x28, static_cast(0xaa), 0x2a, 0x43, 0x6e, 0x3, static_cast(0xd1), + static_cast(0xff), static_cast(0x9c), static_cast(0x85)}); +static const int16_t GENI_RESPONSE_HEADER_LENGTH = 13; +static const size_t GENI_RESPONSE_TYPE_LENGTH = 8; + +static const uint8_t GENI_RESPONSE_TYPE_FLOW_HEAD[GENI_RESPONSE_TYPE_LENGTH] = {31, 0, 1, 48, 1, 0, 0, 24}; +static const int16_t GENI_RESPONSE_FLOW_OFFSET = 0; +static const int16_t GENI_RESPONSE_HEAD_OFFSET = 4; + +static const uint8_t GENI_RESPONSE_TYPE_POWER[GENI_RESPONSE_TYPE_LENGTH] = {44, 0, 1, 0, 1, 0, 0, 37}; +static const int16_t GENI_RESPONSE_VOLTAGE_AC_OFFSET = 0; +static const int16_t GENI_RESPONSE_VOLTAGE_DC_OFFSET = 4; +static const int16_t GENI_RESPONSE_CURRENT_OFFSET = 8; +static const int16_t GENI_RESPONSE_POWER_OFFSET = 12; +static const int16_t GENI_RESPONSE_MOTOR_POWER_OFFSET = 16; // not sure +static const int16_t GENI_RESPONSE_MOTOR_SPEED_OFFSET = 20; + +class Alpha3 : public esphome::ble_client::BLEClientNode, public PollingComponent { + public: + void setup() override; + void update() override; + void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; } + void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; } + void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; } + void set_current_sensor(sensor::Sensor *sensor) { this->current_sensor_ = sensor; } + void set_speed_sensor(sensor::Sensor *sensor) { this->speed_sensor_ = sensor; } + void set_voltage_sensor(sensor::Sensor *sensor) { this->voltage_sensor_ = sensor; } + + protected: + sensor::Sensor *flow_sensor_{nullptr}; + sensor::Sensor *head_sensor_{nullptr}; + sensor::Sensor *power_sensor_{nullptr}; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *speed_sensor_{nullptr}; + sensor::Sensor *voltage_sensor_{nullptr}; + uint16_t geni_handle_; + int16_t response_length_; + int16_t response_offset_; + uint8_t response_type_[GENI_RESPONSE_TYPE_LENGTH]; + uint8_t buffer_[4]; + void extract_publish_sensor_value_(const uint8_t *response, int16_t length, int16_t response_offset, + int16_t value_offset, sensor::Sensor *sensor, float factor); + void handle_geni_response_(const uint8_t *response, uint16_t length); + void send_request_(uint8_t *request, size_t len); + bool is_current_response_type_(const uint8_t *response_type); +}; +} // namespace alpha3 +} // namespace esphome + +#endif diff --git a/esphome/components/alpha3/sensor.py b/esphome/components/alpha3/sensor.py new file mode 100644 index 0000000000..ba4ca16a5a --- /dev/null +++ b/esphome/components/alpha3/sensor.py @@ -0,0 +1,85 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, ble_client +from esphome.const import ( + CONF_ID, + CONF_CURRENT, + CONF_FLOW, + CONF_HEAD, + CONF_POWER, + CONF_SPEED, + CONF_VOLTAGE, + UNIT_AMPERE, + UNIT_VOLT, + UNIT_WATT, + UNIT_METER, + UNIT_CUBIC_METER_PER_HOUR, + UNIT_REVOLUTIONS_PER_MINUTE, +) + +alpha3_ns = cg.esphome_ns.namespace("alpha3") +Alpha3 = alpha3_ns.class_("Alpha3", ble_client.BLEClientNode, cg.PollingComponent) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(Alpha3), + cv.Optional(CONF_FLOW): sensor.sensor_schema( + unit_of_measurement=UNIT_CUBIC_METER_PER_HOUR, + accuracy_decimals=2, + ), + cv.Optional(CONF_HEAD): sensor.sensor_schema( + unit_of_measurement=UNIT_METER, + accuracy_decimals=2, + ), + cv.Optional(CONF_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + accuracy_decimals=2, + ), + cv.Optional(CONF_CURRENT): sensor.sensor_schema( + unit_of_measurement=UNIT_AMPERE, + accuracy_decimals=2, + ), + cv.Optional(CONF_SPEED): sensor.sensor_schema( + unit_of_measurement=UNIT_REVOLUTIONS_PER_MINUTE, + accuracy_decimals=2, + ), + cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=2, + ), + } + ) + .extend(ble_client.BLE_CLIENT_SCHEMA) + .extend(cv.polling_component_schema("15s")) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await ble_client.register_ble_node(var, config) + + if CONF_FLOW in config: + sens = await sensor.new_sensor(config[CONF_FLOW]) + cg.add(var.set_flow_sensor(sens)) + + if CONF_HEAD in config: + sens = await sensor.new_sensor(config[CONF_HEAD]) + cg.add(var.set_head_sensor(sens)) + + if CONF_POWER in config: + sens = await sensor.new_sensor(config[CONF_POWER]) + cg.add(var.set_power_sensor(sens)) + + if CONF_CURRENT in config: + sens = await sensor.new_sensor(config[CONF_CURRENT]) + cg.add(var.set_current_sensor(sens)) + + if CONF_SPEED in config: + sens = await sensor.new_sensor(config[CONF_SPEED]) + cg.add(var.set_speed_sensor(sens)) + + if CONF_VOLTAGE in config: + sens = await sensor.new_sensor(config[CONF_VOLTAGE]) + cg.add(var.set_voltage_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index 3145255e20..3442c392c7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -262,6 +262,7 @@ CONF_FINGER_ID = "finger_id" CONF_FINGERPRINT_COUNT = "fingerprint_count" CONF_FLASH_LENGTH = "flash_length" CONF_FLASH_TRANSITION_LENGTH = "flash_transition_length" +CONF_FLOW = "flow" CONF_FLOW_CONTROL_PIN = "flow_control_pin" CONF_FOR = "for" CONF_FORCE_UPDATE = "force_update" @@ -286,6 +287,7 @@ CONF_GPIO = "gpio" CONF_GREEN = "green" CONF_GROUP = "group" CONF_HARDWARE_UART = "hardware_uart" +CONF_HEAD = "head" CONF_HEARTBEAT = "heartbeat" CONF_HEAT_ACTION = "heat_action" CONF_HEAT_DEADBAND = "heat_deadband" @@ -891,6 +893,7 @@ UNIT_CENTIMETER = "cm" UNIT_COUNT_DECILITRE = "/dL" UNIT_COUNTS_PER_CUBIC_METER = "#/m³" UNIT_CUBIC_METER = "m³" +UNIT_CUBIC_METER_PER_HOUR = "m³/h" UNIT_DECIBEL = "dB" UNIT_DECIBEL_MILLIWATT = "dBm" UNIT_DEGREE_PER_SECOND = "°/s" @@ -928,6 +931,7 @@ UNIT_PERCENT = "%" UNIT_PH = "pH" UNIT_PULSES = "pulses" UNIT_PULSES_PER_MINUTE = "pulses/min" +UNIT_REVOLUTIONS_PER_MINUTE = "RPM" UNIT_SECOND = "s" UNIT_STEPS = "steps" UNIT_VOLT = "V" diff --git a/tests/test1.yaml b/tests/test1.yaml index 21379e807c..9d279b5e40 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -325,6 +325,7 @@ ble_client: accept: True - mac_address: C4:4F:33:11:22:33 id: my_bedjet_ble_client + bedjet: - ble_client_id: my_bedjet_ble_client id: my_bedjet_client @@ -1269,6 +1270,16 @@ sensor: pressure: name: "MPL3115A2 Pressure" update_interval: 10s + - platform: alpha3 + ble_client_id: ble_foo + flow: + name: "Radiator Pump Flow" + head: + name: "Radiator Pump Head" + power: + name: "Radiator Pump Power" + speed: + name: "Radiator Pump Speed" - platform: ld2410 moving_distance: name: "Moving distance (cm)" From 74139985c9c6c5ede69c7c629b48f0526284bc0f Mon Sep 17 00:00:00 2001 From: KoenBreeman <121864590+KoenBreeman@users.noreply.github.com> Date: Tue, 11 Jul 2023 23:19:28 +0200 Subject: [PATCH 0206/2607] RTC implementation of pcf8563 (#4998) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/pcf8563/__init__.py | 0 esphome/components/pcf8563/pcf8563.cpp | 109 ++++++++++++++++++++++ esphome/components/pcf8563/pcf8563.h | 124 +++++++++++++++++++++++++ esphome/components/pcf8563/time.py | 62 +++++++++++++ tests/test5.yaml | 1 + 6 files changed, 297 insertions(+) create mode 100644 esphome/components/pcf8563/__init__.py create mode 100644 esphome/components/pcf8563/pcf8563.cpp create mode 100644 esphome/components/pcf8563/pcf8563.h create mode 100644 esphome/components/pcf8563/time.py diff --git a/CODEOWNERS b/CODEOWNERS index 68a8eb6d18..82612fbd4a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -201,6 +201,7 @@ esphome/components/output/* @esphome/core esphome/components/pca6416a/* @Mat931 esphome/components/pca9554/* @hwstar esphome/components/pcf85063/* @brogon +esphome/components/pcf8563/* @KoenBreeman esphome/components/pid/* @OttoWinter esphome/components/pipsolar/* @andreashergert1984 esphome/components/pm1006/* @habbie diff --git a/esphome/components/pcf8563/__init__.py b/esphome/components/pcf8563/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/pcf8563/pcf8563.cpp b/esphome/components/pcf8563/pcf8563.cpp new file mode 100644 index 0000000000..f2a82735c5 --- /dev/null +++ b/esphome/components/pcf8563/pcf8563.cpp @@ -0,0 +1,109 @@ +#include "pcf8563.h" +#include "esphome/core/log.h" + +// Datasheet: +// - https://nl.mouser.com/datasheet/2/302/PCF8563-1127619.pdf + +namespace esphome { +namespace pcf8563 { + +static const char *const TAG = "PCF8563"; + +void PCF8563Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up PCF8563..."); + if (!this->read_rtc_()) { + this->mark_failed(); + } +} + +void PCF8563Component::update() { this->read_time(); } + +void PCF8563Component::dump_config() { + ESP_LOGCONFIG(TAG, "PCF8563:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with PCF8563 failed!"); + } + ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); +} + +float PCF8563Component::get_setup_priority() const { return setup_priority::DATA; } + +void PCF8563Component::read_time() { + if (!this->read_rtc_()) { + return; + } + if (pcf8563_.reg.stop) { + ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); + return; + } + ESPTime rtc_time{ + .second = uint8_t(pcf8563_.reg.second + 10 * pcf8563_.reg.second_10), + .minute = uint8_t(pcf8563_.reg.minute + 10u * pcf8563_.reg.minute_10), + .hour = uint8_t(pcf8563_.reg.hour + 10u * pcf8563_.reg.hour_10), + .day_of_week = uint8_t(pcf8563_.reg.weekday), + .day_of_month = uint8_t(pcf8563_.reg.day + 10u * pcf8563_.reg.day_10), + .day_of_year = 1, // ignored by recalc_timestamp_utc(false) + .month = uint8_t(pcf8563_.reg.month + 10u * pcf8563_.reg.month_10), + .year = uint16_t(pcf8563_.reg.year + 10u * pcf8563_.reg.year_10 + 2000), + .is_dst = false, // not used + .timestamp = 0, // overwritten by recalc_timestamp_utc(false) + }; + rtc_time.recalc_timestamp_utc(false); + if (!rtc_time.is_valid()) { + ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); + return; + } + time::RealTimeClock::synchronize_epoch_(rtc_time.timestamp); +} + +void PCF8563Component::write_time() { + auto now = time::RealTimeClock::utcnow(); + if (!now.is_valid()) { + ESP_LOGE(TAG, "Invalid system time, not syncing to RTC."); + return; + } + pcf8563_.reg.year = (now.year - 2000) % 10; + pcf8563_.reg.year_10 = (now.year - 2000) / 10 % 10; + pcf8563_.reg.month = now.month % 10; + pcf8563_.reg.month_10 = now.month / 10; + pcf8563_.reg.day = now.day_of_month % 10; + pcf8563_.reg.day_10 = now.day_of_month / 10; + pcf8563_.reg.weekday = now.day_of_week; + pcf8563_.reg.hour = now.hour % 10; + pcf8563_.reg.hour_10 = now.hour / 10; + pcf8563_.reg.minute = now.minute % 10; + pcf8563_.reg.minute_10 = now.minute / 10; + pcf8563_.reg.second = now.second % 10; + pcf8563_.reg.second_10 = now.second / 10; + pcf8563_.reg.stop = false; + + this->write_rtc_(); +} + +bool PCF8563Component::read_rtc_() { + if (!this->read_bytes(0, this->pcf8563_.raw, sizeof(this->pcf8563_.raw))) { + ESP_LOGE(TAG, "Can't read I2C data."); + return false; + } + ESP_LOGD(TAG, "Read %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u STOP:%s CLKOUT:%0u", pcf8563_.reg.hour_10, + pcf8563_.reg.hour, pcf8563_.reg.minute_10, pcf8563_.reg.minute, pcf8563_.reg.second_10, pcf8563_.reg.second, + pcf8563_.reg.year_10, pcf8563_.reg.year, pcf8563_.reg.month_10, pcf8563_.reg.month, pcf8563_.reg.day_10, + pcf8563_.reg.day, ONOFF(!pcf8563_.reg.stop), pcf8563_.reg.clkout_enabled); + + return true; +} + +bool PCF8563Component::write_rtc_() { + if (!this->write_bytes(0, this->pcf8563_.raw, sizeof(this->pcf8563_.raw))) { + ESP_LOGE(TAG, "Can't write I2C data."); + return false; + } + ESP_LOGD(TAG, "Write %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u OSC:%s CLKOUT:%0u", pcf8563_.reg.hour_10, + pcf8563_.reg.hour, pcf8563_.reg.minute_10, pcf8563_.reg.minute, pcf8563_.reg.second_10, pcf8563_.reg.second, + pcf8563_.reg.year_10, pcf8563_.reg.year, pcf8563_.reg.month_10, pcf8563_.reg.month, pcf8563_.reg.day_10, + pcf8563_.reg.day, ONOFF(!pcf8563_.reg.stop), pcf8563_.reg.clkout_enabled); + return true; +} +} // namespace pcf8563 +} // namespace esphome diff --git a/esphome/components/pcf8563/pcf8563.h b/esphome/components/pcf8563/pcf8563.h new file mode 100644 index 0000000000..b6832efe72 --- /dev/null +++ b/esphome/components/pcf8563/pcf8563.h @@ -0,0 +1,124 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/time/real_time_clock.h" + +namespace esphome { +namespace pcf8563 { + +class PCF8563Component : public time::RealTimeClock, public i2c::I2CDevice { + public: + void setup() override; + void update() override; + void dump_config() override; + float get_setup_priority() const override; + void read_time(); + void write_time(); + + protected: + bool read_rtc_(); + bool write_rtc_(); + union PCF8563Reg { + struct { + // Control_1 register + bool : 3; + bool power_on_reset : 1; + bool : 1; + bool stop : 1; + bool : 1; + bool ext_test : 1; + + // Control_2 register + bool time_int : 1; + bool alarm_int : 1; + bool timer_flag : 1; + bool alarm_flag : 1; + bool timer_int_timer_pulse : 1; + bool : 3; + + // Seconds register + uint8_t second : 4; + uint8_t second_10 : 3; + bool clock_int : 1; + + // Minutes register + uint8_t minute : 4; + uint8_t minute_10 : 3; + uint8_t : 1; + + // Hours register + uint8_t hour : 4; + uint8_t hour_10 : 2; + uint8_t : 2; + + // Days register + uint8_t day : 4; + uint8_t day_10 : 2; + uint8_t : 2; + + // Weekdays register + uint8_t weekday : 3; + uint8_t unused_3 : 5; + + // Months register + uint8_t month : 4; + uint8_t month_10 : 1; + uint8_t : 2; + uint8_t century : 1; + + // Years register + uint8_t year : 4; + uint8_t year_10 : 4; + + // Minute Alarm register + uint8_t minute_alarm : 4; + uint8_t minute_alarm_10 : 3; + bool minute_alarm_enabled : 1; + + // Hour Alarm register + uint8_t hour_alarm : 4; + uint8_t hour_alarm_10 : 2; + uint8_t : 1; + bool hour_alarm_enabled : 1; + + // Day Alarm register + uint8_t day_alarm : 4; + uint8_t day_alarm_10 : 2; + uint8_t : 1; + bool day_alarm_enabled : 1; + + // Weekday Alarm register + uint8_t weekday_alarm : 3; + uint8_t : 4; + bool weekday_alarm_enabled : 1; + + // CLKout control register + uint8_t frequency_output : 2; + uint8_t : 5; + uint8_t clkout_enabled : 1; + + // Timer control register + uint8_t timer_source_frequency : 2; + uint8_t : 5; + uint8_t timer_enabled : 1; + + // Timer register + uint8_t countdown_period : 8; + + } reg; + mutable uint8_t raw[sizeof(reg)]; + } pcf8563_; +}; + +template class WriteAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->write_time(); } +}; + +template class ReadAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->read_time(); } +}; +} // namespace pcf8563 +} // namespace esphome diff --git a/esphome/components/pcf8563/time.py b/esphome/components/pcf8563/time.py new file mode 100644 index 0000000000..2e6456a72d --- /dev/null +++ b/esphome/components/pcf8563/time.py @@ -0,0 +1,62 @@ +import esphome.config_validation as cv +import esphome.codegen as cg +from esphome import automation +from esphome.components import i2c, time +from esphome.const import CONF_ID + +CODEOWNERS = ["@KoenBreeman"] + +DEPENDENCIES = ["i2c"] + + +pcf8563_ns = cg.esphome_ns.namespace("pcf8563") +pcf8563Component = pcf8563_ns.class_( + "PCF8563Component", time.RealTimeClock, i2c.I2CDevice +) +WriteAction = pcf8563_ns.class_("WriteAction", automation.Action) +ReadAction = pcf8563_ns.class_("ReadAction", automation.Action) + + +CONFIG_SCHEMA = time.TIME_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(pcf8563Component), + } +).extend(i2c.i2c_device_schema(0xA3)) + + +@automation.register_action( + "pcf8563.write_time", + WriteAction, + automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(pcf8563Component), + } + ), +) +async def pcf8563_write_time_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var + + +@automation.register_action( + "pcf8563.read_time", + ReadAction, + automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(pcf8563Component), + } + ), +) +async def pcf8563_read_time_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await time.register_time(var, config) diff --git a/tests/test5.yaml b/tests/test5.yaml index cb4b559b06..a2530d799a 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -590,6 +590,7 @@ display: time: - platform: pcf85063 + - platform: pcf8563 text_sensor: - platform: ezo_pmp From 7a551081ee5e08bf71bc52c2c30168992192bb89 Mon Sep 17 00:00:00 2001 From: dentra Date: Wed, 12 Jul 2023 03:08:03 +0300 Subject: [PATCH 0207/2607] web server esp idf suppport (#3500) * initial web_server_idf implementation * initial web_server_idf implementation * fix lint errors * fix lint errors * add captive_portal support * fix lint errors * fix lint errors * add url decode * Increase the max supported size of headers section in HTTP request * add ota support * add mulipart form data support (ota required) * make linter happy * make linter happy * make linter happy * fix review marks * add DefaultHeaders support * add DefaultHeaders support * unify file names * using std::isnan * parse multipart requests only when ota enabled * parse multipart requests only when ota enabled * parse multipart requests only when ota enabled * parse multipart requests only when ota enabled * parse multipart requests only when ota enabled * drop multipart request support * drop multipart request support * drop multipart request support * OTA is disabled by default * fail when OTA enabled on IDF framework * changing file permissions to remove execute bit * return back PGM_P and strncpy_P macro * temp web_server fix to be compat with 2022.12 * fix config handling w/o web_server * fix compilation with "local" * fully remove all idf ota * merge with esphome 2023.6 * add core/hal to web_server_base * Update esphome/components/web_server_base/__init__.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update __init__.py * Update __init__.py --------- Co-authored-by: Keith Burzinski Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/captive_portal/__init__.py | 12 +- .../captive_portal/captive_portal.cpp | 8 +- .../captive_portal/captive_portal.h | 12 +- esphome/components/web_server/__init__.py | 12 +- .../components/web_server/list_entities.cpp | 4 - esphome/components/web_server/list_entities.h | 4 - esphome/components/web_server/web_server.cpp | 136 ++++--- esphome/components/web_server/web_server.h | 4 - .../components/web_server_base/__init__.py | 23 +- .../web_server_base/web_server_base.cpp | 25 +- .../web_server_base/web_server_base.h | 9 +- esphome/components/web_server_idf/__init__.py | 14 + .../web_server_idf/web_server_idf.cpp | 374 ++++++++++++++++++ .../web_server_idf/web_server_idf.h | 277 +++++++++++++ script/build_codeowners.py | 2 + 16 files changed, 814 insertions(+), 103 deletions(-) create mode 100644 esphome/components/web_server_idf/__init__.py create mode 100644 esphome/components/web_server_idf/web_server_idf.cpp create mode 100644 esphome/components/web_server_idf/web_server_idf.h diff --git a/CODEOWNERS b/CODEOWNERS index 82612fbd4a..8ebf51ceeb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -312,6 +312,7 @@ esphome/components/version/* @esphome/core esphome/components/voice_assistant/* @jesserockz esphome/components/wake_on_lan/* @willwill2will54 esphome/components/web_server_base/* @OttoWinter +esphome/components/web_server_idf/* @dentra esphome/components/whirlpool/* @glmnet esphome/components/whynter/* @aeonsablaze esphome/components/wiegand/* @ssieb diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index ff5266e84f..db4a17f6f7 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -21,7 +21,6 @@ CONFIG_SCHEMA = cv.All( ), } ).extend(cv.COMPONENT_SCHEMA), - cv.only_with_arduino, cv.only_on(["esp32", "esp8266"]), ) @@ -34,8 +33,9 @@ async def to_code(config): await cg.register_component(var, config) cg.add_define("USE_CAPTIVE_PORTAL") - if CORE.is_esp32: - cg.add_library("DNSServer", None) - cg.add_library("WiFi", None) - if CORE.is_esp8266: - cg.add_library("DNSServer", None) + if CORE.using_arduino: + if CORE.is_esp32: + cg.add_library("DNSServer", None) + cg.add_library("WiFi", None) + if CORE.is_esp8266: + cg.add_library("DNSServer", None) diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 3bfdea0ab5..74c6606fc0 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "captive_portal.h" #include "esphome/core/log.h" #include "esphome/core/application.h" @@ -46,10 +44,12 @@ void CaptivePortal::start() { this->base_->add_ota_handler(); } +#ifdef USE_ARDUINO this->dns_server_ = make_unique(); this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError); network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip(); this->dns_server_->start(53, "*", (uint32_t) ip); +#endif this->base_->get_server()->onNotFound([this](AsyncWebServerRequest *req) { if (!this->active_ || req->host().c_str() == wifi::global_wifi_component->wifi_soft_ap_ip().str()) { @@ -67,7 +67,7 @@ void CaptivePortal::start() { void CaptivePortal::handleRequest(AsyncWebServerRequest *req) { if (req->url() == "/") { - AsyncWebServerResponse *response = req->beginResponse_P(200, "text/html", INDEX_GZ, sizeof(INDEX_GZ)); + auto *response = req->beginResponse_P(200, "text/html", INDEX_GZ, sizeof(INDEX_GZ)); response->addHeader("Content-Encoding", "gzip"); req->send(response); return; @@ -91,5 +91,3 @@ CaptivePortal *global_captive_portal = nullptr; // NOLINT(cppcoreguidelines-avo } // namespace captive_portal } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/captive_portal/captive_portal.h b/esphome/components/captive_portal/captive_portal.h index c2aada171f..df45d40d12 100644 --- a/esphome/components/captive_portal/captive_portal.h +++ b/esphome/components/captive_portal/captive_portal.h @@ -1,9 +1,9 @@ #pragma once -#ifdef USE_ARDUINO - #include +#ifdef USE_ARDUINO #include +#endif #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" @@ -18,18 +18,22 @@ class CaptivePortal : public AsyncWebHandler, public Component { CaptivePortal(web_server_base::WebServerBase *base); void setup() override; void dump_config() override; +#ifdef USE_ARDUINO void loop() override { if (this->dns_server_ != nullptr) this->dns_server_->processNextRequest(); } +#endif float get_setup_priority() const override; void start(); bool is_active() const { return this->active_; } void end() { this->active_ = false; this->base_->deinit(); +#ifdef USE_ARDUINO this->dns_server_->stop(); this->dns_server_ = nullptr; +#endif } bool canHandle(AsyncWebServerRequest *request) override { @@ -58,12 +62,12 @@ class CaptivePortal : public AsyncWebHandler, public Component { web_server_base::WebServerBase *base_; bool initialized_{false}; bool active_{false}; +#ifdef USE_ARDUINO std::unique_ptr dns_server_{nullptr}; +#endif }; extern CaptivePortal *global_captive_portal; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace captive_portal } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 25c0254f90..ab54ae8582 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -47,6 +47,12 @@ def validate_local(config): return config +def validate_ota(config): + if CORE.using_esp_idf and config[CONF_OTA]: + raise cv.Invalid("Enabling 'ota' is not supported for IDF framework yet") + return config + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -71,15 +77,17 @@ CONFIG_SCHEMA = cv.All( web_server_base.WebServerBase ), cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean, - cv.Optional(CONF_OTA, default=True): cv.boolean, + cv.SplitDefault( + CONF_OTA, esp8266=True, esp32_arduino=True, esp32_idf=False + ): cv.boolean, cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), - cv.only_with_arduino, cv.only_on(["esp32", "esp8266"]), default_url, validate_local, + validate_ota, ) diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index ce7b4be7f3..016dd37dd9 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "list_entities.h" #include "esphome/core/application.h" #include "esphome/core/log.h" @@ -103,5 +101,3 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont } // namespace web_server } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index 8ddca15edf..1569c8ac57 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -1,7 +1,5 @@ #pragma once -#ifdef USE_ARDUINO - #include "esphome/core/component.h" #include "esphome/core/component_iterator.h" #include "esphome/core/defines.h" @@ -59,5 +57,3 @@ class ListEntitiesIterator : public ComponentIterator { } // namespace web_server } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index eb1858a09c..01057fead6 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "web_server.h" #include "esphome/components/json/json_util.h" @@ -9,7 +7,9 @@ #include "esphome/core/log.h" #include "esphome/core/util.h" +#ifdef USE_ARDUINO #include "StreamString.h" +#endif #include @@ -181,7 +181,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("")); #endif if (strlen(this->css_url_) > 0) { - stream->print(F("print(F(R"(print(this->css_url_); stream->print(F("\">")); } @@ -381,7 +381,7 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail start_config) { return json::build_json([obj, value, start_config](JsonObject root) { std::string state; - if (isnan(value)) { + if (std::isnan(value)) { state = "NA"; } else { state = value_accuracy_to_string(value, obj->get_accuracy_decimals()); @@ -524,11 +524,8 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc request->send(200); } else if (match.method == "turn_on") { auto call = obj->turn_on(); - if (request->hasParam("speed")) { - String speed = request->getParam("speed")->value(); - } if (request->hasParam("speed_level")) { - String speed_level = request->getParam("speed_level")->value(); + auto speed_level = request->getParam("speed_level")->value(); auto val = parse_number(speed_level.c_str()); if (!val.has_value()) { ESP_LOGW(TAG, "Can't convert '%s' to number!", speed_level.c_str()); @@ -537,7 +534,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc call.set_speed(*val); } if (request->hasParam("oscillation")) { - String speed = request->getParam("oscillation")->value(); + auto speed = request->getParam("oscillation")->value(); auto val = parse_on_off(speed.c_str()); switch (val) { case PARSE_ON: @@ -585,29 +582,54 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa request->send(200); } else if (match.method == "turn_on") { auto call = obj->turn_on(); - if (request->hasParam("brightness")) - call.set_brightness(request->getParam("brightness")->value().toFloat() / 255.0f); - if (request->hasParam("r")) - call.set_red(request->getParam("r")->value().toFloat() / 255.0f); - if (request->hasParam("g")) - call.set_green(request->getParam("g")->value().toFloat() / 255.0f); - if (request->hasParam("b")) - call.set_blue(request->getParam("b")->value().toFloat() / 255.0f); - if (request->hasParam("white_value")) - call.set_white(request->getParam("white_value")->value().toFloat() / 255.0f); - if (request->hasParam("color_temp")) - call.set_color_temperature(request->getParam("color_temp")->value().toFloat()); - + if (request->hasParam("brightness")) { + auto brightness = parse_number(request->getParam("brightness")->value().c_str()); + if (brightness.has_value()) { + call.set_brightness(*brightness / 255.0f); + } + } + if (request->hasParam("r")) { + auto r = parse_number(request->getParam("r")->value().c_str()); + if (r.has_value()) { + call.set_red(*r / 255.0f); + } + } + if (request->hasParam("g")) { + auto g = parse_number(request->getParam("g")->value().c_str()); + if (g.has_value()) { + call.set_green(*g / 255.0f); + } + } + if (request->hasParam("b")) { + auto b = parse_number(request->getParam("b")->value().c_str()); + if (b.has_value()) { + call.set_blue(*b / 255.0f); + } + } + if (request->hasParam("white_value")) { + auto white_value = parse_number(request->getParam("white_value")->value().c_str()); + if (white_value.has_value()) { + call.set_white(*white_value / 255.0f); + } + } + if (request->hasParam("color_temp")) { + auto color_temp = parse_number(request->getParam("color_temp")->value().c_str()); + if (color_temp.has_value()) { + call.set_color_temperature(*color_temp); + } + } if (request->hasParam("flash")) { - float length_s = request->getParam("flash")->value().toFloat(); - call.set_flash_length(static_cast(length_s * 1000)); + auto flash = parse_number(request->getParam("flash")->value().c_str()); + if (flash.has_value()) { + call.set_flash_length(*flash * 1000); + } } - if (request->hasParam("transition")) { - float length_s = request->getParam("transition")->value().toFloat(); - call.set_transition_length(static_cast(length_s * 1000)); + auto transition = parse_number(request->getParam("transition")->value().c_str()); + if (transition.has_value()) { + call.set_transition_length(*transition * 1000); + } } - if (request->hasParam("effect")) { const char *effect = request->getParam("effect")->value().c_str(); call.set_effect(effect); @@ -618,8 +640,10 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa } else if (match.method == "turn_off") { auto call = obj->turn_off(); if (request->hasParam("transition")) { - auto length = (uint32_t) request->getParam("transition")->value().toFloat() * 1000; - call.set_transition_length(length); + auto transition = parse_number(request->getParam("transition")->value().c_str()); + if (transition.has_value()) { + call.set_transition_length(*transition * 1000); + } } this->schedule_([call]() mutable { call.perform(); }); request->send(200); @@ -681,10 +705,18 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa return; } - if (request->hasParam("position")) - call.set_position(request->getParam("position")->value().toFloat()); - if (request->hasParam("tilt")) - call.set_tilt(request->getParam("tilt")->value().toFloat()); + if (request->hasParam("position")) { + auto position = parse_number(request->getParam("position")->value().c_str()); + if (position.has_value()) { + call.set_position(*position); + } + } + if (request->hasParam("tilt")) { + auto tilt = parse_number(request->getParam("tilt")->value().c_str()); + if (tilt.has_value()) { + call.set_tilt(*tilt); + } + } this->schedule_([call]() mutable { call.perform(); }); request->send(200); @@ -725,10 +757,9 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM auto call = obj->make_call(); if (request->hasParam("value")) { - String value = request->getParam("value")->value(); - optional value_f = parse_number(value.c_str()); - if (value_f.has_value()) - call.set_value(*value_f); + auto value = parse_number(request->getParam("value")->value().c_str()); + if (value.has_value()) + call.set_value(*value); } this->schedule_([call]() mutable { call.perform(); }); @@ -747,7 +778,7 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail root["step"] = obj->traits.get_step(); root["mode"] = (int) obj->traits.get_mode(); } - if (isnan(value)) { + if (std::isnan(value)) { root["value"] = "\"NaN\""; root["state"] = "NA"; } else { @@ -784,7 +815,7 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM auto call = obj->make_call(); if (request->hasParam("option")) { - String option = request->getParam("option")->value(); + auto option = request->getParam("option")->value(); call.set_option(option.c_str()); // NOLINT(clang-diagnostic-deprecated-declarations) } @@ -834,29 +865,26 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url auto call = obj->make_call(); if (request->hasParam("mode")) { - String mode = request->getParam("mode")->value(); + auto mode = request->getParam("mode")->value(); call.set_mode(mode.c_str()); } if (request->hasParam("target_temperature_high")) { - String value = request->getParam("target_temperature_high")->value(); - optional value_f = parse_number(value.c_str()); - if (value_f.has_value()) - call.set_target_temperature_high(*value_f); + auto target_temperature_high = parse_number(request->getParam("target_temperature_high")->value().c_str()); + if (target_temperature_high.has_value()) + call.set_target_temperature_high(*target_temperature_high); } if (request->hasParam("target_temperature_low")) { - String value = request->getParam("target_temperature_low")->value(); - optional value_f = parse_number(value.c_str()); - if (value_f.has_value()) - call.set_target_temperature_low(*value_f); + auto target_temperature_low = parse_number(request->getParam("target_temperature_low")->value().c_str()); + if (target_temperature_low.has_value()) + call.set_target_temperature_low(*target_temperature_low); } if (request->hasParam("target_temperature")) { - String value = request->getParam("target_temperature")->value(); - optional value_f = parse_number(value.c_str()); - if (value_f.has_value()) - call.set_target_temperature(*value_f); + auto target_temperature = parse_number(request->getParam("target_temperature")->value().c_str()); + if (target_temperature.has_value()) + call.set_target_temperature(*target_temperature); } this->schedule_([call]() mutable { call.perform(); }); @@ -1231,5 +1259,3 @@ void WebServer::schedule_(std::function &&f) { } // namespace web_server } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 83ebba205f..788e30ccf2 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -1,7 +1,5 @@ #pragma once -#ifdef USE_ARDUINO - #include "list_entities.h" #include "esphome/components/web_server_base/web_server_base.h" @@ -291,5 +289,3 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { } // namespace web_server } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 14fb033a56..87f23a990a 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -5,7 +5,15 @@ from esphome.core import coroutine_with_priority, CORE CODEOWNERS = ["@OttoWinter"] DEPENDENCIES = ["network"] -AUTO_LOAD = ["async_tcp"] + + +def AUTO_LOAD(): + if CORE.using_arduino: + return ["async_tcp"] + if CORE.using_esp_idf: + return ["web_server_idf"] + return [] + web_server_base_ns = cg.esphome_ns.namespace("web_server_base") WebServerBase = web_server_base_ns.class_("WebServerBase", cg.Component) @@ -23,9 +31,10 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - if CORE.is_esp32: - cg.add_library("WiFi", None) - cg.add_library("FS", None) - cg.add_library("Update", None) - # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json - cg.add_library("esphome/ESPAsyncWebServer-esphome", "2.1.0") + if CORE.using_arduino: + if CORE.is_esp32: + cg.add_library("WiFi", None) + cg.add_library("FS", None) + cg.add_library("Update", None) + # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json + cg.add_library("esphome/ESPAsyncWebServer-esphome", "2.1.0") diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp index 3c269b28b8..997ce0798a 100644 --- a/esphome/components/web_server_base/web_server_base.cpp +++ b/esphome/components/web_server_base/web_server_base.cpp @@ -1,16 +1,17 @@ -#ifdef USE_ARDUINO - #include "web_server_base.h" #include "esphome/core/log.h" #include "esphome/core/application.h" -#include +#include "esphome/core/helpers.h" +#ifdef USE_ARDUINO +#include #ifdef USE_ESP32 #include #endif #ifdef USE_ESP8266 #include #endif +#endif namespace esphome { namespace web_server_base { @@ -24,18 +25,22 @@ void WebServerBase::add_handler(AsyncWebHandler *handler) { handler = new internal::AuthMiddlewareHandler(handler, &credentials_); } this->handlers_.push_back(handler); - if (this->server_ != nullptr) + if (this->server_ != nullptr) { this->server_->addHandler(handler); + } } void report_ota_error() { +#ifdef USE_ARDUINO StreamString ss; Update.printError(ss); ESP_LOGW(TAG, "OTA Update failed! Error: %s", ss.c_str()); +#endif } void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) { +#ifdef USE_ARDUINO bool success; if (index == 0) { ESP_LOGI(TAG, "OTA Update Start: %s", filename.c_str()); @@ -45,9 +50,10 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin // NOLINTNEXTLINE(readability-static-accessed-through-instance) success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); #endif -#ifdef USE_ESP32 - if (Update.isRunning()) +#ifdef USE_ESP32_FRAMEWORK_ARDUINO + if (Update.isRunning()) { Update.abort(); + } success = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH); #endif if (!success) { @@ -85,8 +91,10 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin report_ota_error(); } } +#endif } void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { +#ifdef USE_ARDUINO AsyncWebServerResponse *response; if (!Update.hasError()) { response = request->beginResponse(200, "text/plain", "Update Successful!"); @@ -98,10 +106,13 @@ void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { } response->addHeader("Connection", "close"); request->send(response); +#endif } void WebServerBase::add_ota_handler() { +#ifdef USE_ARDUINO this->add_handler(new OTARequestHandler(this)); // NOLINT +#endif } float WebServerBase::get_setup_priority() const { // Before WiFi (captive portal) @@ -110,5 +121,3 @@ float WebServerBase::get_setup_priority() const { } // namespace web_server_base } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index ae286b1e22..c312126472 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -1,14 +1,17 @@ #pragma once -#ifdef USE_ARDUINO - #include #include #include #include "esphome/core/component.h" +#ifdef USE_ARDUINO #include +#elif USE_ESP_IDF +#include "esphome/core/hal.h" +#include "esphome/components/web_server_idf/web_server_idf.h" +#endif namespace esphome { namespace web_server_base { @@ -141,5 +144,3 @@ class OTARequestHandler : public AsyncWebHandler { } // namespace web_server_base } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/web_server_idf/__init__.py b/esphome/components/web_server_idf/__init__.py new file mode 100644 index 0000000000..bd3db24bc6 --- /dev/null +++ b/esphome/components/web_server_idf/__init__.py @@ -0,0 +1,14 @@ +import esphome.config_validation as cv +from esphome.components.esp32 import add_idf_sdkconfig_option + +CODEOWNERS = ["@dentra"] + +CONFIG_SCHEMA = cv.All( + cv.Schema({}), + cv.only_with_esp_idf, +) + + +async def to_code(config): + # Increase the maximum supported size of headers section in HTTP request packet to be processed by the server + add_idf_sdkconfig_option("CONFIG_HTTPD_MAX_REQ_HDR_LEN", 1024) diff --git a/esphome/components/web_server_idf/web_server_idf.cpp b/esphome/components/web_server_idf/web_server_idf.cpp new file mode 100644 index 0000000000..444e682460 --- /dev/null +++ b/esphome/components/web_server_idf/web_server_idf.cpp @@ -0,0 +1,374 @@ +#ifdef USE_ESP_IDF + +#include + +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +#include "esp_tls_crypto.h" + +#include "web_server_idf.h" + +namespace esphome { +namespace web_server_idf { + +#ifndef HTTPD_409 +#define HTTPD_409 "409 Conflict" +#endif + +#define CRLF_STR "\r\n" +#define CRLF_LEN (sizeof(CRLF_STR) - 1) + +static const char *const TAG = "web_server_idf"; + +void AsyncWebServer::end() { + if (this->server_) { + httpd_stop(this->server_); + this->server_ = nullptr; + } +} + +void AsyncWebServer::begin() { + if (this->server_) { + this->end(); + } + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.server_port = this->port_; + config.uri_match_fn = [](const char * /*unused*/, const char * /*unused*/, size_t /*unused*/) { return true; }; + if (httpd_start(&this->server_, &config) == ESP_OK) { + const httpd_uri_t handler_get = { + .uri = "", + .method = HTTP_GET, + .handler = AsyncWebServer::request_handler, + .user_ctx = this, + }; + httpd_register_uri_handler(this->server_, &handler_get); + + const httpd_uri_t handler_post = { + .uri = "", + .method = HTTP_POST, + .handler = AsyncWebServer::request_handler, + .user_ctx = this, + }; + httpd_register_uri_handler(this->server_, &handler_post); + } +} + +esp_err_t AsyncWebServer::request_handler(httpd_req_t *r) { + ESP_LOGV(TAG, "Enter AsyncWebServer::request_handler. method=%u, uri=%s", r->method, r->uri); + AsyncWebServerRequest req(r); + auto *server = static_cast(r->user_ctx); + for (auto *handler : server->handlers_) { + if (handler->canHandle(&req)) { + // At now process only basic requests. + // OTA requires multipart request support and handleUpload for it + handler->handleRequest(&req); + return ESP_OK; + } + } + if (server->on_not_found_) { + server->on_not_found_(&req); + return ESP_OK; + } + return ESP_ERR_NOT_FOUND; +} + +AsyncWebServerRequest::~AsyncWebServerRequest() { + delete this->rsp_; + for (const auto &pair : this->params_) { + delete pair.second; // NOLINT(cppcoreguidelines-owning-memory) + } +} + +optional AsyncWebServerRequest::get_header(const char *name) const { + size_t buf_len = httpd_req_get_hdr_value_len(*this, name); + if (buf_len == 0) { + return {}; + } + auto buf = std::unique_ptr(new char[++buf_len]); + if (!buf) { + ESP_LOGE(TAG, "No enough memory for get header %s", name); + return {}; + } + if (httpd_req_get_hdr_value_str(*this, name, buf.get(), buf_len) != ESP_OK) { + return {}; + } + return {buf.get()}; +} + +std::string AsyncWebServerRequest::url() const { + auto *str = strchr(this->req_->uri, '?'); + if (str == nullptr) { + return this->req_->uri; + } + return std::string(this->req_->uri, str - this->req_->uri); +} + +std::string AsyncWebServerRequest::host() const { return this->get_header("Host").value(); } + +void AsyncWebServerRequest::send(AsyncWebServerResponse *response) { + httpd_resp_send(*this, response->get_content_data(), response->get_content_size()); +} + +void AsyncWebServerRequest::send(int code, const char *content_type, const char *content) { + this->init_response_(nullptr, code, content_type); + if (content) { + httpd_resp_send(*this, content, HTTPD_RESP_USE_STRLEN); + } else { + httpd_resp_send(*this, nullptr, 0); + } +} + +void AsyncWebServerRequest::redirect(const std::string &url) { + httpd_resp_set_status(*this, "302 Found"); + httpd_resp_set_hdr(*this, "Location", url.c_str()); + httpd_resp_send(*this, nullptr, 0); +} + +void AsyncWebServerRequest::init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type) { + httpd_resp_set_status(*this, code == 200 ? HTTPD_200 + : code == 404 ? HTTPD_404 + : code == 409 ? HTTPD_409 + : to_string(code).c_str()); + + if (content_type && *content_type) { + httpd_resp_set_type(*this, content_type); + } + httpd_resp_set_hdr(*this, "Accept-Ranges", "none"); + + for (const auto &pair : DefaultHeaders::Instance().headers_) { + httpd_resp_set_hdr(*this, pair.first.c_str(), pair.second.c_str()); + } + + delete this->rsp_; + this->rsp_ = rsp; +} + +bool AsyncWebServerRequest::authenticate(const char *username, const char *password) const { + if (username == nullptr || password == nullptr || *username == 0) { + return true; + } + auto auth = this->get_header("Authorization"); + if (!auth.has_value()) { + return false; + } + + auto *auth_str = auth.value().c_str(); + + const auto auth_prefix_len = sizeof("Basic ") - 1; + if (strncmp("Basic ", auth_str, auth_prefix_len) != 0) { + ESP_LOGW(TAG, "Only Basic authorization supported yet"); + return false; + } + + std::string user_info; + user_info += username; + user_info += ':'; + user_info += password; + + size_t n = 0, out; + esp_crypto_base64_encode(nullptr, 0, &n, reinterpret_cast(user_info.c_str()), user_info.size()); + + auto digest = std::unique_ptr(new char[n + 1]); + esp_crypto_base64_encode(reinterpret_cast(digest.get()), n, &out, + reinterpret_cast(user_info.c_str()), user_info.size()); + + return strncmp(digest.get(), auth_str + auth_prefix_len, auth.value().size() - auth_prefix_len) == 0; +} + +void AsyncWebServerRequest::requestAuthentication(const char *realm) const { + httpd_resp_set_hdr(*this, "Connection", "keep-alive"); + auto auth_val = str_sprintf("Basic realm=\"%s\"", realm ? realm : "Login Required"); + httpd_resp_set_hdr(*this, "WWW-Authenticate", auth_val.c_str()); + httpd_resp_send_err(*this, HTTPD_401_UNAUTHORIZED, nullptr); +} + +static std::string url_decode(const std::string &in) { + std::string out; + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) { + if (in[i] == '%') { + ++i; + if (i + 1 < in.size()) { + auto c = parse_hex(&in[i], 2); + if (c.has_value()) { + out += static_cast(*c); + ++i; + } else { + out += '%'; + out += in[i++]; + out += in[i]; + } + } else { + out += '%'; + out += in[i]; + } + } else if (in[i] == '+') { + out += ' '; + } else { + out += in[i]; + } + } + return out; +} + +AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) { + auto find = this->params_.find(name); + if (find != this->params_.end()) { + return find->second; + } + + auto query_len = httpd_req_get_url_query_len(this->req_); + if (query_len == 0) { + return nullptr; + } + + auto query_str = std::unique_ptr(new char[++query_len]); + if (!query_str) { + ESP_LOGE(TAG, "No enough memory for get query param"); + return nullptr; + } + + auto res = httpd_req_get_url_query_str(*this, query_str.get(), query_len); + if (res != ESP_OK) { + ESP_LOGW(TAG, "Can't get query for request: %s", esp_err_to_name(res)); + return nullptr; + } + + auto query_val = std::unique_ptr(new char[query_len]); + if (!query_val) { + ESP_LOGE(TAG, "No enough memory for get query param value"); + return nullptr; + } + + res = httpd_query_key_value(query_str.get(), name.c_str(), query_val.get(), query_len); + if (res != ESP_OK) { + this->params_.insert({name, nullptr}); + return nullptr; + } + query_str.release(); + auto decoded = url_decode(query_val.get()); + query_val.release(); + auto *param = new AsyncWebParameter(decoded); // NOLINT(cppcoreguidelines-owning-memory) + this->params_.insert(std::make_pair(name, param)); + return param; +} + +void AsyncWebServerResponse::addHeader(const char *name, const char *value) { + httpd_resp_set_hdr(*this->req_, name, value); +} + +void AsyncResponseStream::print(float value) { this->print(to_string(value)); } + +void AsyncResponseStream::printf(const char *fmt, ...) { + std::string str; + va_list args; + + va_start(args, fmt); + size_t length = vsnprintf(nullptr, 0, fmt, args); + va_end(args); + + str.resize(length); + va_start(args, fmt); + vsnprintf(&str[0], length + 1, fmt, args); + va_end(args); + + this->print(str); +} + +AsyncEventSource::~AsyncEventSource() { + for (auto *ses : this->sessions_) { + delete ses; // NOLINT(cppcoreguidelines-owning-memory) + } +} + +void AsyncEventSource::handleRequest(AsyncWebServerRequest *request) { + auto *rsp = new AsyncEventSourceResponse(request, this); // NOLINT(cppcoreguidelines-owning-memory) + if (this->on_connect_) { + this->on_connect_(rsp); + } + this->sessions_.insert(rsp); +} + +void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) { + for (auto *ses : this->sessions_) { + ses->send(message, event, id, reconnect); + } +} + +AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *request, AsyncEventSource *server) + : server_(server) { + httpd_req_t *req = *request; + + httpd_resp_set_status(req, HTTPD_200); + httpd_resp_set_type(req, "text/event-stream"); + httpd_resp_set_hdr(req, "Cache-Control", "no-cache"); + httpd_resp_set_hdr(req, "Connection", "keep-alive"); + + httpd_resp_send_chunk(req, CRLF_STR, CRLF_LEN); + + req->sess_ctx = this; + req->free_ctx = AsyncEventSourceResponse::destroy; + + this->hd_ = req->handle; + this->fd_ = httpd_req_to_sockfd(req); +} + +void AsyncEventSourceResponse::destroy(void *ptr) { + auto *rsp = static_cast(ptr); + rsp->server_->sessions_.erase(rsp); + delete rsp; // NOLINT(cppcoreguidelines-owning-memory) +} + +void AsyncEventSourceResponse::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) { + if (this->fd_ == 0) { + return; + } + + std::string ev; + + if (reconnect) { + ev.append("retry: ", sizeof("retry: ") - 1); + ev.append(to_string(reconnect)); + ev.append(CRLF_STR, CRLF_LEN); + } + + if (id) { + ev.append("id: ", sizeof("id: ") - 1); + ev.append(to_string(id)); + ev.append(CRLF_STR, CRLF_LEN); + } + + if (event && *event) { + ev.append("event: ", sizeof("event: ") - 1); + ev.append(event); + ev.append(CRLF_STR, CRLF_LEN); + } + + if (message && *message) { + ev.append("data: ", sizeof("data: ") - 1); + ev.append(message); + ev.append(CRLF_STR, CRLF_LEN); + } + + if (ev.empty()) { + return; + } + + ev.append(CRLF_STR, CRLF_LEN); + + // Sending chunked content prelude + auto cs = str_snprintf("%x" CRLF_STR, 4 * sizeof(ev.size()) + CRLF_LEN, ev.size()); + httpd_socket_send(this->hd_, this->fd_, cs.c_str(), cs.size(), 0); + + // Sendiing content chunk + httpd_socket_send(this->hd_, this->fd_, ev.c_str(), ev.size(), 0); + + // Indicate end of chunk + httpd_socket_send(this->hd_, this->fd_, CRLF_STR, CRLF_LEN, 0); +} + +} // namespace web_server_idf +} // namespace esphome + +#endif // !defined(USE_ESP_IDF) diff --git a/esphome/components/web_server_idf/web_server_idf.h b/esphome/components/web_server_idf/web_server_idf.h new file mode 100644 index 0000000000..f3cecca16f --- /dev/null +++ b/esphome/components/web_server_idf/web_server_idf.h @@ -0,0 +1,277 @@ +#pragma once +#ifdef USE_ESP_IDF + +#include + +#include +#include +#include +#include +#include + +namespace esphome { +namespace web_server_idf { + +#define F(string_literal) (string_literal) +#define PGM_P const char * +#define strncpy_P strncpy + +using String = std::string; + +class AsyncWebParameter { + public: + AsyncWebParameter(std::string value) : value_(std::move(value)) {} + const std::string &value() const { return this->value_; } + + protected: + std::string value_; +}; + +class AsyncWebServerRequest; + +class AsyncWebServerResponse { + public: + AsyncWebServerResponse(const AsyncWebServerRequest *req) : req_(req) {} + virtual ~AsyncWebServerResponse() {} + + // NOLINTNEXTLINE(readability-identifier-naming) + void addHeader(const char *name, const char *value); + + virtual const char *get_content_data() const = 0; + virtual size_t get_content_size() const = 0; + + protected: + const AsyncWebServerRequest *req_; +}; + +class AsyncWebServerResponseEmpty : public AsyncWebServerResponse { + public: + AsyncWebServerResponseEmpty(const AsyncWebServerRequest *req) : AsyncWebServerResponse(req) {} + + const char *get_content_data() const override { return nullptr; }; + size_t get_content_size() const override { return 0; }; +}; + +class AsyncWebServerResponseContent : public AsyncWebServerResponse { + public: + AsyncWebServerResponseContent(const AsyncWebServerRequest *req, std::string content) + : AsyncWebServerResponse(req), content_(std::move(content)) {} + + const char *get_content_data() const override { return this->content_.c_str(); }; + size_t get_content_size() const override { return this->content_.size(); }; + + protected: + std::string content_; +}; + +class AsyncResponseStream : public AsyncWebServerResponse { + public: + AsyncResponseStream(const AsyncWebServerRequest *req) : AsyncWebServerResponse(req) {} + + const char *get_content_data() const override { return this->content_.c_str(); }; + size_t get_content_size() const override { return this->content_.size(); }; + + void print(const char *str) { this->content_.append(str); } + void print(const std::string &str) { this->content_.append(str); } + void print(float value); + void printf(const char *fmt, ...) __attribute__((format(printf, 2, 3))); + + protected: + std::string content_; +}; + +class AsyncWebServerResponseProgmem : public AsyncWebServerResponse { + public: + AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size) + : AsyncWebServerResponse(req), data_(data), size_(size) {} + + const char *get_content_data() const override { return reinterpret_cast(this->data_); }; + size_t get_content_size() const override { return this->size_; }; + + protected: + const uint8_t *data_; + const size_t size_; +}; + +class AsyncWebServerRequest { + // FIXME friend class AsyncWebServerResponse; + friend class AsyncWebServer; + + public: + ~AsyncWebServerRequest(); + + http_method method() const { return static_cast(this->req_->method); } + std::string url() const; + std::string host() const; + // NOLINTNEXTLINE(readability-identifier-naming) + size_t contentLength() const { return this->req_->content_len; } + + bool authenticate(const char *username, const char *password) const; + // NOLINTNEXTLINE(readability-identifier-naming) + void requestAuthentication(const char *realm = nullptr) const; + + void redirect(const std::string &url); + + void send(AsyncWebServerResponse *response); + void send(int code, const char *content_type = nullptr, const char *content = nullptr); + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncWebServerResponse *beginResponse(int code, const char *content_type) { + auto *res = new AsyncWebServerResponseEmpty(this); // NOLINT(cppcoreguidelines-owning-memory) + this->init_response_(res, 200, content_type); + return res; + } + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncWebServerResponse *beginResponse(int code, const char *content_type, const std::string &content) { + auto *res = new AsyncWebServerResponseContent(this, content); // NOLINT(cppcoreguidelines-owning-memory) + this->init_response_(res, code, content_type); + return res; + } + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncWebServerResponse *beginResponse_P(int code, const char *content_type, const uint8_t *data, + const size_t data_size) { + auto *res = new AsyncWebServerResponseProgmem(this, data, data_size); // NOLINT(cppcoreguidelines-owning-memory) + this->init_response_(res, code, content_type); + return res; + } + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncResponseStream *beginResponseStream(const char *content_type) { + auto *res = new AsyncResponseStream(this); // NOLINT(cppcoreguidelines-owning-memory) + this->init_response_(res, 200, content_type); + return res; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + bool hasParam(const std::string &name) { return this->getParam(name) != nullptr; } + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncWebParameter *getParam(const std::string &name); + + // NOLINTNEXTLINE(readability-identifier-naming) + bool hasArg(const char *name) { return this->hasParam(name); } + std::string arg(const std::string &name) { + auto *param = this->getParam(name); + if (param) { + return param->value(); + } + return {}; + } + + operator httpd_req_t *() const { return this->req_; } + optional get_header(const char *name) const; + + protected: + httpd_req_t *req_; + AsyncWebServerResponse *rsp_{}; + std::map params_; + AsyncWebServerRequest(httpd_req_t *req) : req_(req) {} + void init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type); +}; + +class AsyncWebHandler; + +class AsyncWebServer { + public: + AsyncWebServer(uint16_t port) : port_(port){}; + ~AsyncWebServer() { this->end(); } + + // NOLINTNEXTLINE(readability-identifier-naming) + void onNotFound(std::function fn) { on_not_found_ = std::move(fn); } + + void begin(); + void end(); + + // NOLINTNEXTLINE(readability-identifier-naming) + AsyncWebHandler &addHandler(AsyncWebHandler *handler) { + this->handlers_.push_back(handler); + return *handler; + } + + protected: + uint16_t port_{}; + httpd_handle_t server_{}; + static esp_err_t request_handler(httpd_req_t *r); + std::vector handlers_; + std::function on_not_found_{}; +}; + +class AsyncWebHandler { + public: + virtual ~AsyncWebHandler() {} + // NOLINTNEXTLINE(readability-identifier-naming) + virtual bool canHandle(AsyncWebServerRequest *request) { return false; } + // NOLINTNEXTLINE(readability-identifier-naming) + virtual void handleRequest(AsyncWebServerRequest *request) {} + // NOLINTNEXTLINE(readability-identifier-naming) + virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data, + size_t len, bool final) {} + // NOLINTNEXTLINE(readability-identifier-naming) + virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {} + // NOLINTNEXTLINE(readability-identifier-naming) + virtual bool isRequestHandlerTrivial() { return true; } +}; + +class AsyncEventSource; + +class AsyncEventSourceResponse { + friend class AsyncEventSource; + + public: + void send(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0); + + protected: + AsyncEventSourceResponse(const AsyncWebServerRequest *request, AsyncEventSource *server); + static void destroy(void *p); + AsyncEventSource *server_; + httpd_handle_t hd_{}; + int fd_{}; +}; + +using AsyncEventSourceClient = AsyncEventSourceResponse; + +class AsyncEventSource : public AsyncWebHandler { + friend class AsyncEventSourceResponse; + using connect_handler_t = std::function; + + public: + AsyncEventSource(std::string url) : url_(std::move(url)) {} + ~AsyncEventSource() override; + + // NOLINTNEXTLINE(readability-identifier-naming) + bool canHandle(AsyncWebServerRequest *request) override { + return request->method() == HTTP_GET && request->url() == this->url_; + } + // NOLINTNEXTLINE(readability-identifier-naming) + void handleRequest(AsyncWebServerRequest *request) override; + // NOLINTNEXTLINE(readability-identifier-naming) + void onConnect(connect_handler_t cb) { this->on_connect_ = std::move(cb); } + + void send(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0); + + protected: + std::string url_; + std::set sessions_; + connect_handler_t on_connect_{}; +}; + +class DefaultHeaders { + friend class AsyncWebServerRequest; + + public: + // NOLINTNEXTLINE(readability-identifier-naming) + void addHeader(const char *name, const char *value) { this->headers_.emplace_back(name, value); } + + // NOLINTNEXTLINE(readability-identifier-naming) + static DefaultHeaders &Instance() { + static DefaultHeaders instance; + return instance; + } + + protected: + std::vector> headers_; +}; + +} // namespace web_server_idf +} // namespace esphome + +using namespace esphome::web_server_idf; // NOLINT(google-global-names-in-headers) + +#endif // !defined(USE_ESP_IDF) diff --git a/script/build_codeowners.py b/script/build_codeowners.py index 2ee7521b91..22f3c1b4bc 100755 --- a/script/build_codeowners.py +++ b/script/build_codeowners.py @@ -7,6 +7,7 @@ from collections import defaultdict from esphome.helpers import write_file_if_changed from esphome.config import get_component, get_platform from esphome.core import CORE +from esphome.const import KEY_CORE, KEY_TARGET_FRAMEWORK parser = argparse.ArgumentParser() parser.add_argument( @@ -38,6 +39,7 @@ parts = [BASE] # Fake some directory so that get_component works CORE.config_path = str(root) +CORE.data[KEY_CORE] = {KEY_TARGET_FRAMEWORK: None} codeowners = defaultdict(list) From 5f531ac9b03f03d9c4f45cd05360b45bc57dc724 Mon Sep 17 00:00:00 2001 From: Stefan Rado Date: Wed, 12 Jul 2023 03:19:19 +0200 Subject: [PATCH 0208/2607] Add TT21100 touchscreen component (#4793) Co-authored-by: Rajan Patel Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../touchscreen_binary_sensor.cpp | 5 + .../binary_sensor/touchscreen_binary_sensor.h | 2 +- esphome/components/tt21100/__init__.py | 5 + .../tt21100/binary_sensor/__init__.py | 31 ++++ .../tt21100/binary_sensor/tt21100_button.cpp | 27 +++ .../tt21100/binary_sensor/tt21100_button.h | 28 +++ .../tt21100/touchscreen/__init__.py | 44 +++++ .../tt21100/touchscreen/tt21100.cpp | 175 ++++++++++++++++++ .../components/tt21100/touchscreen/tt21100.h | 49 +++++ tests/test8.yaml | 27 ++- 11 files changed, 392 insertions(+), 2 deletions(-) create mode 100644 esphome/components/tt21100/__init__.py create mode 100644 esphome/components/tt21100/binary_sensor/__init__.py create mode 100644 esphome/components/tt21100/binary_sensor/tt21100_button.cpp create mode 100644 esphome/components/tt21100/binary_sensor/tt21100_button.h create mode 100644 esphome/components/tt21100/touchscreen/__init__.py create mode 100644 esphome/components/tt21100/touchscreen/tt21100.cpp create mode 100644 esphome/components/tt21100/touchscreen/tt21100.h diff --git a/CODEOWNERS b/CODEOWNERS index 8ebf51ceeb..a2ddc84226 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -296,6 +296,7 @@ esphome/components/tof10120/* @wstrzalka esphome/components/toshiba/* @kbx81 esphome/components/touchscreen/* @jesserockz esphome/components/tsl2591/* @wjcarpenter +esphome/components/tt21100/* @kroimon esphome/components/tuya/binary_sensor/* @jesserockz esphome/components/tuya/climate/* @jesserockz esphome/components/tuya/number/* @frankiboy1 diff --git a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp index 583392cce3..66df78b62a 100644 --- a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +++ b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp @@ -3,6 +3,11 @@ namespace esphome { namespace touchscreen { +void TouchscreenBinarySensor::setup() { + this->parent_->register_listener(this); + this->publish_initial_state(false); +} + void TouchscreenBinarySensor::touch(TouchPoint tp) { bool touched = (tp.x >= this->x_min_ && tp.x <= this->x_max_ && tp.y >= this->y_min_ && tp.y <= this->y_max_); diff --git a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h index 701468aa1e..b56ae562b1 100644 --- a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +++ b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h @@ -14,7 +14,7 @@ class TouchscreenBinarySensor : public binary_sensor::BinarySensor, public TouchListener, public Parented { public: - void setup() override { this->parent_->register_listener(this); } + void setup() override; /// Set the touch screen area where the button will detect the touch. void set_area(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) { diff --git a/esphome/components/tt21100/__init__.py b/esphome/components/tt21100/__init__.py new file mode 100644 index 0000000000..a309d34beb --- /dev/null +++ b/esphome/components/tt21100/__init__.py @@ -0,0 +1,5 @@ +import esphome.codegen as cg + +CODEOWNERS = ["@kroimon"] + +tt21100_ns = cg.esphome_ns.namespace("tt21100") diff --git a/esphome/components/tt21100/binary_sensor/__init__.py b/esphome/components/tt21100/binary_sensor/__init__.py new file mode 100644 index 0000000000..d5423a01b2 --- /dev/null +++ b/esphome/components/tt21100/binary_sensor/__init__.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import CONF_INDEX + +from .. import tt21100_ns +from ..touchscreen import TT21100Touchscreen, TT21100ButtonListener + +CONF_TT21100_ID = "tt21100_id" + +TT21100Button = tt21100_ns.class_( + "TT21100Button", + binary_sensor.BinarySensor, + cg.Component, + TT21100ButtonListener, + cg.Parented.template(TT21100Touchscreen), +) + +CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TT21100Button).extend( + { + cv.GenerateID(CONF_TT21100_ID): cv.use_id(TT21100Touchscreen), + cv.Required(CONF_INDEX): cv.int_range(min=0, max=3), + } +) + + +async def to_code(config): + var = await binary_sensor.new_binary_sensor(config) + await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_TT21100_ID]) + cg.add(var.set_index(config[CONF_INDEX])) diff --git a/esphome/components/tt21100/binary_sensor/tt21100_button.cpp b/esphome/components/tt21100/binary_sensor/tt21100_button.cpp new file mode 100644 index 0000000000..2d5ac22a83 --- /dev/null +++ b/esphome/components/tt21100/binary_sensor/tt21100_button.cpp @@ -0,0 +1,27 @@ +#include "tt21100_button.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace tt21100 { + +static const char *const TAG = "tt21100.binary_sensor"; + +void TT21100Button::setup() { + this->parent_->register_button_listener(this); + this->publish_initial_state(false); +} + +void TT21100Button::dump_config() { + LOG_BINARY_SENSOR("", "TT21100 Button", this); + ESP_LOGCONFIG(TAG, " Index: %u", this->index_); +} + +void TT21100Button::update_button(uint8_t index, uint16_t state) { + if (index != this->index_) + return; + + this->publish_state(state > 0); +} + +} // namespace tt21100 +} // namespace esphome diff --git a/esphome/components/tt21100/binary_sensor/tt21100_button.h b/esphome/components/tt21100/binary_sensor/tt21100_button.h new file mode 100644 index 0000000000..90b55bb75a --- /dev/null +++ b/esphome/components/tt21100/binary_sensor/tt21100_button.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/tt21100/touchscreen/tt21100.h" +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace tt21100 { + +class TT21100Button : public binary_sensor::BinarySensor, + public Component, + public TT21100ButtonListener, + public Parented { + public: + void setup() override; + void dump_config() override; + + void set_index(uint8_t index) { this->index_ = index; } + + void update_button(uint8_t index, uint16_t state) override; + + protected: + uint8_t index_; +}; + +} // namespace tt21100 +} // namespace esphome diff --git a/esphome/components/tt21100/touchscreen/__init__.py b/esphome/components/tt21100/touchscreen/__init__.py new file mode 100644 index 0000000000..d96d389e69 --- /dev/null +++ b/esphome/components/tt21100/touchscreen/__init__.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +import esphome.config_validation as cv + +from esphome import pins +from esphome.components import i2c, touchscreen +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN + +from .. import tt21100_ns + +DEPENDENCIES = ["i2c"] + +TT21100Touchscreen = tt21100_ns.class_( + "TT21100Touchscreen", + touchscreen.Touchscreen, + cg.Component, + i2c.I2CDevice, +) +TT21100ButtonListener = tt21100_ns.class_("TT21100ButtonListener") + +CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(TT21100Touchscreen), + cv.Required(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + } + ) + .extend(i2c.i2c_device_schema(0x24)) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await touchscreen.register_touchscreen(var, config) + + interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) + cg.add(var.set_interrupt_pin(interrupt_pin)) + + if CONF_RESET_PIN in config: + rts_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) + cg.add(var.set_reset_pin(rts_pin)) diff --git a/esphome/components/tt21100/touchscreen/tt21100.cpp b/esphome/components/tt21100/touchscreen/tt21100.cpp new file mode 100644 index 0000000000..28a8c2d754 --- /dev/null +++ b/esphome/components/tt21100/touchscreen/tt21100.cpp @@ -0,0 +1,175 @@ +#include "tt21100.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace tt21100 { + +static const char *const TAG = "tt21100"; + +static const uint8_t MAX_BUTTONS = 4; +static const uint8_t MAX_TOUCH_POINTS = 5; +static const uint8_t MAX_DATA_LEN = (7 + MAX_TOUCH_POINTS * 10); // 7 Header + (Points * 10 data bytes) + +struct TT21100ButtonReport { + uint16_t length; // Always 14 (0x000E) + uint8_t report_id; // Always 0x03 + uint16_t timestamp; // Number in units of 100 us + uint8_t btn_value; // Only use bit 0..3 + uint16_t btn_signal[MAX_BUTTONS]; +} __attribute__((packed)); + +struct TT21100TouchRecord { + uint8_t : 5; + uint8_t touch_type : 3; + uint8_t tip : 1; + uint8_t event_id : 2; + uint8_t touch_id : 5; + uint16_t x; + uint16_t y; + uint8_t pressure; + uint16_t major_axis_length; + uint8_t orientation; +} __attribute__((packed)); + +struct TT21100TouchReport { + uint16_t length; + uint8_t report_id; + uint16_t timestamp; + uint8_t : 2; + uint8_t large_object : 1; + uint8_t record_num : 5; + uint8_t report_counter : 2; + uint8_t : 3; + uint8_t noise_effect : 3; + TT21100TouchRecord touch_record[MAX_TOUCH_POINTS]; +} __attribute__((packed)); + +void TT21100TouchscreenStore::gpio_intr(TT21100TouchscreenStore *store) { store->touch = true; } + +float TT21100Touchscreen::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; } + +void TT21100Touchscreen::setup() { + ESP_LOGCONFIG(TAG, "Setting up TT21100 Touchscreen..."); + + // Register interrupt pin + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->interrupt_pin_->setup(); + this->store_.pin = this->interrupt_pin_->to_isr(); + this->interrupt_pin_->attach_interrupt(TT21100TouchscreenStore::gpio_intr, &this->store_, + gpio::INTERRUPT_FALLING_EDGE); + + // Perform reset if necessary + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_(); + } + + // Update display dimensions if they were updated during display setup + this->display_width_ = this->display_->get_width(); + this->display_height_ = this->display_->get_height(); + this->rotation_ = static_cast(this->display_->get_rotation()); + + // Trigger initial read to activate the interrupt + this->store_.touch = true; +} + +void TT21100Touchscreen::loop() { + if (!this->store_.touch) + return; + this->store_.touch = false; + + // Read report length + uint16_t data_len; + this->read((uint8_t *) &data_len, sizeof(data_len)); + + // Read report data + uint8_t data[MAX_DATA_LEN]; + if (data_len > 0 && data_len < sizeof(data)) { + this->read(data, data_len); + + if (data_len == 14) { + // Button event + auto *report = (TT21100ButtonReport *) data; + + ESP_LOGV(TAG, "Button report: Len=%d, ID=%d, Time=%5u, Value=[%u], Signal=[%04X][%04X][%04X][%04X]", + report->length, report->report_id, report->timestamp, report->btn_value, report->btn_signal[0], + report->btn_signal[1], report->btn_signal[2], report->btn_signal[3]); + + for (uint8_t i = 0; i < 4; i++) { + for (auto *listener : this->button_listeners_) + listener->update_button(i, report->btn_signal[i]); + } + + } else if (data_len >= 7) { + // Touch point event + auto *report = (TT21100TouchReport *) data; + + ESP_LOGV(TAG, + "Touch report: Len=%d, ID=%d, Time=%5u, LargeObject=%u, RecordNum=%u, RecordCounter=%u, NoiseEffect=%u", + report->length, report->report_id, report->timestamp, report->large_object, report->record_num, + report->report_counter, report->noise_effect); + + uint8_t touch_count = (data_len - (sizeof(*report) - sizeof(report->touch_record))) / sizeof(TT21100TouchRecord); + + if (touch_count == 0) { + for (auto *listener : this->touch_listeners_) + listener->release(); + return; + } + + for (int i = 0; i < touch_count; i++) { + auto *touch = &report->touch_record[i]; + + ESP_LOGV(TAG, + "Touch %d: Type=%u, Tip=%u, EventId=%u, TouchId=%u, X=%u, Y=%u, Pressure=%u, MajorAxisLen=%u, " + "Orientation=%u", + i, touch->touch_type, touch->tip, touch->event_id, touch->touch_id, touch->x, touch->y, + touch->pressure, touch->major_axis_length, touch->orientation); + + TouchPoint tp; + switch (this->rotation_) { + case ROTATE_0_DEGREES: + // Origin is top right, so mirror X by default + tp.x = this->display_width_ - touch->x; + tp.y = touch->y; + break; + case ROTATE_90_DEGREES: + tp.x = touch->y; + tp.y = touch->x; + break; + case ROTATE_180_DEGREES: + tp.x = touch->x; + tp.y = this->display_height_ - touch->y; + break; + case ROTATE_270_DEGREES: + tp.x = this->display_height_ - touch->y; + tp.y = this->display_width_ - touch->x; + break; + } + tp.id = touch->tip; + tp.state = touch->pressure; + + this->defer([this, tp]() { this->send_touch_(tp); }); + } + } + } +} + +void TT21100Touchscreen::reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(false); + delay(10); + this->reset_pin_->digital_write(true); + delay(10); + } +} + +void TT21100Touchscreen::dump_config() { + ESP_LOGCONFIG(TAG, "TT21100 Touchscreen:"); + LOG_I2C_DEVICE(this); + LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); +} + +} // namespace tt21100 +} // namespace esphome diff --git a/esphome/components/tt21100/touchscreen/tt21100.h b/esphome/components/tt21100/touchscreen/tt21100.h new file mode 100644 index 0000000000..306360975f --- /dev/null +++ b/esphome/components/tt21100/touchscreen/tt21100.h @@ -0,0 +1,49 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/touchscreen/touchscreen.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace tt21100 { + +using namespace touchscreen; + +struct TT21100TouchscreenStore { + volatile bool touch; + ISRInternalGPIOPin pin; + + static void gpio_intr(TT21100TouchscreenStore *store); +}; + +class TT21100ButtonListener { + public: + virtual void update_button(uint8_t index, uint16_t state) = 0; +}; + +class TT21100Touchscreen : public Touchscreen, public Component, public i2c::I2CDevice { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override; + + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } + + void register_button_listener(TT21100ButtonListener *listener) { this->button_listeners_.push_back(listener); } + + protected: + void reset_(); + + TT21100TouchscreenStore store_; + + InternalGPIOPin *interrupt_pin_; + GPIOPin *reset_pin_{nullptr}; + + std::vector button_listeners_; +}; + +} // namespace tt21100 +} // namespace esphome diff --git a/tests/test8.yaml b/tests/test8.yaml index 2430a0d1e6..8d031b033f 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -18,10 +18,35 @@ light: - platform: neopixelbus type: GRB variant: WS2812 - pin: 33 + pin: GPIO38 num_leds: 1 id: neopixel method: esp32_rmt name: neopixel-enable internal: false restore_mode: ALWAYS_OFF + +spi: + clk_pin: GPIO7 + mosi_pin: GPIO6 + +display: + - platform: ili9xxx + model: ili9342 + cs_pin: GPIO5 + dc_pin: GPIO4 + reset_pin: GPIO48 + +i2c: + scl: GPIO18 + sda: GPIO8 + +touchscreen: + - platform: tt21100 + interrupt_pin: GPIO3 + reset_pin: GPIO48 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 From 6ecc1c14d26657304dd3648468960236044a3ab0 Mon Sep 17 00:00:00 2001 From: kswt Date: Wed, 12 Jul 2023 04:28:48 +0300 Subject: [PATCH 0209/2607] tuya_light: fix float->int conversion while setting color temperature (#5067) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: kswt --- esphome/components/tuya/light/tuya_light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/tuya/light/tuya_light.cpp b/esphome/components/tuya/light/tuya_light.cpp index 7b7a974de2..66931767b2 100644 --- a/esphome/components/tuya/light/tuya_light.cpp +++ b/esphome/components/tuya/light/tuya_light.cpp @@ -168,7 +168,7 @@ void TuyaLight::write_state(light::LightState *state) { if (brightness > 0.0f || !color_interlock_) { if (this->color_temperature_id_.has_value()) { - uint32_t color_temp_int = static_cast(color_temperature * this->color_temperature_max_value_); + uint32_t color_temp_int = static_cast(roundf(color_temperature * this->color_temperature_max_value_)); if (this->color_temperature_invert_) { color_temp_int = this->color_temperature_max_value_ - color_temp_int; } From 8a9352939a55ebef4c13cfb55c2d27470f78002c Mon Sep 17 00:00:00 2001 From: Stefan Klug Date: Wed, 12 Jul 2023 03:29:38 +0200 Subject: [PATCH 0210/2607] Fix typo in mpu6050.cpp (#5086) --- esphome/components/mpu6050/mpu6050.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/mpu6050/mpu6050.cpp b/esphome/components/mpu6050/mpu6050.cpp index 51e3ec2383..64fcd3a2a8 100644 --- a/esphome/components/mpu6050/mpu6050.cpp +++ b/esphome/components/mpu6050/mpu6050.cpp @@ -77,7 +77,7 @@ void MPU6050Component::setup() { accel_config &= 0b11100111; accel_config |= (MPU6050_RANGE_2G << 3); ESP_LOGV(TAG, " Output accel_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_config)); - if (!this->write_byte(MPU6050_REGISTER_GYRO_CONFIG, gyro_config)) { + if (!this->write_byte(MPU6050_REGISTER_ACCEL_CONFIG, accel_config)) { this->mark_failed(); return; } From cf65bd8ad742f3fe8f6801f89d1a579b0b2d6715 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 11 Jul 2023 21:38:52 -0400 Subject: [PATCH 0211/2607] airthings_wave: Battery level reporting (#4979) --- CODEOWNERS | 2 +- .../airthings_wave_base/__init__.py | 60 ++++--- .../airthings_wave_base.cpp | 150 ++++++++++++++++-- .../airthings_wave_base/airthings_wave_base.h | 48 +++++- .../airthings_wave_mini.cpp | 14 +- .../airthings_wave_mini/airthings_wave_mini.h | 5 +- .../airthings_wave_plus.cpp | 14 +- .../airthings_wave_plus/airthings_wave_plus.h | 5 +- .../components/airthings_wave_plus/sensor.py | 12 +- tests/test2.yaml | 6 + 10 files changed, 258 insertions(+), 58 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a2ddc84226..641911e84f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -17,7 +17,7 @@ esphome/components/adc/* @esphome/core esphome/components/adc128s102/* @DeerMaximum esphome/components/addressable_light/* @justfalter esphome/components/airthings_ble/* @jeromelaban -esphome/components/airthings_wave_base/* @jeromelaban @ncareau +esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban esphome/components/alarm_control_panel/* @grahambrown11 diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py index c935ce108a..d9b97f1c8d 100644 --- a/esphome/components/airthings_wave_base/__init__.py +++ b/esphome/components/airthings_wave_base/__init__.py @@ -3,26 +3,31 @@ import esphome.config_validation as cv from esphome.components import sensor, ble_client from esphome.const import ( - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, - STATE_CLASS_MEASUREMENT, - UNIT_PERCENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, + CONF_BATTERY_VOLTAGE, CONF_HUMIDITY, - CONF_TVOC, CONF_PRESSURE, CONF_TEMPERATURE, + CONF_TVOC, + DEVICE_CLASS_VOLTAGE, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, UNIT_PARTS_PER_BILLION, - ICON_RADIATOR, + UNIT_PERCENT, + UNIT_VOLT, ) -CODEOWNERS = ["@ncareau", "@jeromelaban"] +CODEOWNERS = ["@ncareau", "@jeromelaban", "@kpfleming"] DEPENDENCIES = ["ble_client"] +CONF_BATTERY_UPDATE_INTERVAL = "battery_update_interval" + airthings_wave_base_ns = cg.esphome_ns.namespace("airthings_wave_base") AirthingsWaveBase = airthings_wave_base_ns.class_( "AirthingsWaveBase", cg.PollingComponent, ble_client.BLEClientNode @@ -34,9 +39,9 @@ BASE_SCHEMA = ( { cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=0, device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=0, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, @@ -52,11 +57,21 @@ BASE_SCHEMA = ( ), cv.Optional(CONF_TVOC): sensor.sensor_schema( unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, accuracy_decimals=0, device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional( + CONF_BATTERY_UPDATE_INTERVAL, + default="24h", + ): cv.update_interval, } ) .extend(cv.polling_component_schema("5min")) @@ -69,15 +84,20 @@ async def wave_base_to_code(var, config): await ble_client.register_ble_node(var, config) - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + if config_humidity := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(config_humidity) cg.add(var.set_humidity(sens)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + if config_temperature := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(config_temperature) cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - sens = await sensor.new_sensor(config[CONF_PRESSURE]) + if config_pressure := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(config_pressure) cg.add(var.set_pressure(sens)) - if CONF_TVOC in config: - sens = await sensor.new_sensor(config[CONF_TVOC]) + if config_tvoc := config.get(CONF_TVOC): + sens = await sensor.new_sensor(config_tvoc) cg.add(var.set_tvoc(sens)) + if config_battery_voltage := config.get(CONF_BATTERY_VOLTAGE): + sens = await sensor.new_sensor(config_battery_voltage) + cg.add(var.set_battery_voltage(sens)) + if config_battery_update_interval := config.get(CONF_BATTERY_UPDATE_INTERVAL): + cg.add(var.set_battery_update_interval(config_battery_update_interval)) diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.cpp b/esphome/components/airthings_wave_base/airthings_wave_base.cpp index 349d8d58eb..eff466f413 100644 --- a/esphome/components/airthings_wave_base/airthings_wave_base.cpp +++ b/esphome/components/airthings_wave_base/airthings_wave_base.cpp @@ -1,5 +1,8 @@ #include "airthings_wave_base.h" +// All information related to reading battery information came from the sensors.airthings_wave +// project by Sverre Hamre (https://github.com/sverrham/sensor.airthings_wave) + #ifdef USE_ESP32 namespace esphome { @@ -18,22 +21,26 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt } case ESP_GATTC_DISCONNECT_EVT: { + this->handle_ = 0; + this->acp_handle_ = 0; + this->cccd_handle_ = 0; ESP_LOGW(TAG, "Disconnected!"); break; } case ESP_GATTC_SEARCH_CMPL_EVT: { - this->handle_ = 0; - auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); - if (chr == nullptr) { - ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), - this->sensors_data_characteristic_uuid_.to_string().c_str()); - break; + if (this->request_read_values_()) { + if (!this->read_battery_next_update_) { + this->node_state = espbt::ClientState::ESTABLISHED; + } else { + // delay setting node_state to ESTABLISHED until confirmation of the notify registration + this->request_battery_(); + } } - this->handle_ = chr->handle; - this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; - this->request_read_values_(); + // ensure that the client will be disconnected even if no responses arrive + this->set_response_timeout_(); + break; } @@ -50,6 +57,20 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt break; } + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + this->node_state = espbt::ClientState::ESTABLISHED; + break; + } + + case ESP_GATTC_NOTIFY_EVT: { + if (param->notify.conn_id != this->parent()->get_conn_id()) + break; + if (param->notify.handle == this->acp_handle_) { + this->read_battery_(param->notify.value, param->notify.value_len); + } + break; + } + default: break; } @@ -58,7 +79,7 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } void AirthingsWaveBase::update() { - if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { + if (this->node_state != espbt::ClientState::ESTABLISHED) { if (!this->parent()->enabled) { ESP_LOGW(TAG, "Reconnecting to device"); this->parent()->set_enabled(true); @@ -69,12 +90,119 @@ void AirthingsWaveBase::update() { } } -void AirthingsWaveBase::request_read_values_() { +bool AirthingsWaveBase::request_read_values_() { + auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); + if (chr == nullptr) { + ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), + this->sensors_data_characteristic_uuid_.to_string().c_str()); + return false; + } + + this->handle_ = chr->handle; + auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, ESP_GATT_AUTH_REQ_NONE); if (status) { ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); + return false; } + + this->response_pending_(); + return true; +} + +bool AirthingsWaveBase::request_battery_() { + uint8_t battery_command = ACCESS_CONTROL_POINT_COMMAND; + uint8_t cccd_value[2] = {1, 0}; + + auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->access_control_point_characteristic_uuid_); + if (chr == nullptr) { + ESP_LOGW(TAG, "No access control point characteristic found at service %s char %s", + this->service_uuid_.to_string().c_str(), + this->access_control_point_characteristic_uuid_.to_string().c_str()); + return false; + } + + auto *descr = this->parent()->get_descriptor(this->service_uuid_, this->access_control_point_characteristic_uuid_, + CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_UUID); + if (descr == nullptr) { + ESP_LOGW(TAG, "No CCC descriptor found at service %s char %s", this->service_uuid_.to_string().c_str(), + this->access_control_point_characteristic_uuid_.to_string().c_str()); + return false; + } + + auto reg_status = + esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(), this->parent()->get_remote_bda(), chr->handle); + if (reg_status) { + ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", reg_status); + return false; + } + + this->acp_handle_ = chr->handle; + this->cccd_handle_ = descr->handle; + + auto descr_status = + esp_ble_gattc_write_char_descr(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->cccd_handle_, + 2, cccd_value, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE); + if (descr_status) { + ESP_LOGW(TAG, "Error sending CCC descriptor write request, status=%d", descr_status); + return false; + } + + auto chr_status = + esp_ble_gattc_write_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->acp_handle_, 1, + &battery_command, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE); + if (chr_status) { + ESP_LOGW(TAG, "Error sending read request for battery, status=%d", chr_status); + return false; + } + + this->response_pending_(); + return true; +} + +void AirthingsWaveBase::read_battery_(uint8_t *raw_value, uint16_t value_len) { + auto *value = (AccessControlPointResponse *) (&raw_value[2]); + + if ((value_len >= (sizeof(AccessControlPointResponse) + 2)) && (raw_value[0] == ACCESS_CONTROL_POINT_COMMAND)) { + ESP_LOGD(TAG, "Battery received: %u mV", (unsigned int) value->battery); + + if (this->battery_voltage_ != nullptr) { + float voltage = value->battery / 1000.0f; + + this->battery_voltage_->publish_state(voltage); + } + + // read the battery again at the configured update interval + if (this->battery_update_interval_ != this->update_interval_) { + this->read_battery_next_update_ = false; + this->set_timeout("battery", this->battery_update_interval_, + [this]() { this->read_battery_next_update_ = true; }); + } + } + + this->response_received_(); +} + +void AirthingsWaveBase::response_pending_() { + this->responses_pending_++; + this->set_response_timeout_(); +} + +void AirthingsWaveBase::response_received_() { + if (--this->responses_pending_ == 0) { + // This instance must not stay connected + // so other clients can connect to it (e.g. the + // mobile app). + this->parent()->set_enabled(false); + } +} + +void AirthingsWaveBase::set_response_timeout_() { + this->set_timeout("response_timeout", 30 * 1000, [this]() { + this->responses_pending_ = 1; + this->response_received_(); + }); } } // namespace airthings_wave_base diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.h b/esphome/components/airthings_wave_base/airthings_wave_base.h index 68c0b3497d..1dc2e1f71f 100644 --- a/esphome/components/airthings_wave_base/airthings_wave_base.h +++ b/esphome/components/airthings_wave_base/airthings_wave_base.h @@ -1,5 +1,8 @@ #pragma once +// All information related to reading battery levels came from the sensors.airthings_wave +// project by Sverre Hamre (https://github.com/sverrham/sensor.airthings_wave) + #ifdef USE_ESP32 #include @@ -14,6 +17,11 @@ namespace esphome { namespace airthings_wave_base { +namespace espbt = esphome::esp32_ble_tracker; + +static const uint8_t ACCESS_CONTROL_POINT_COMMAND = 0x6d; +static const auto CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_UUID = espbt::ESPBTUUID::from_uint16(0x2902); + class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientNode { public: AirthingsWaveBase() = default; @@ -27,21 +35,53 @@ class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientN void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } + void set_battery_voltage(sensor::Sensor *voltage) { + battery_voltage_ = voltage; + this->read_battery_next_update_ = true; + } + void set_battery_update_interval(uint32_t interval) { battery_update_interval_ = interval; } protected: bool is_valid_voc_value_(uint16_t voc); - virtual void read_sensors(uint8_t *value, uint16_t value_len) = 0; - void request_read_values_(); + bool request_read_values_(); + virtual void read_sensors(uint8_t *raw_value, uint16_t value_len) = 0; sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; sensor::Sensor *pressure_sensor_{nullptr}; sensor::Sensor *tvoc_sensor_{nullptr}; + sensor::Sensor *battery_voltage_{nullptr}; uint16_t handle_; - esp32_ble_tracker::ESPBTUUID service_uuid_; - esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; + espbt::ESPBTUUID service_uuid_; + espbt::ESPBTUUID sensors_data_characteristic_uuid_; + + uint16_t acp_handle_{0}; + uint16_t cccd_handle_{0}; + espbt::ESPBTUUID access_control_point_characteristic_uuid_; + + uint8_t responses_pending_{0}; + void response_pending_(); + void response_received_(); + void set_response_timeout_(); + + // default to *not* reading battery voltage from the device; the + // set_* function for the battery sensor will set this to 'true' + bool read_battery_next_update_{false}; + bool request_battery_(); + void read_battery_(uint8_t *raw_value, uint16_t value_len); + uint32_t battery_update_interval_{}; + + struct AccessControlPointResponse { + uint32_t unused1; + uint8_t unused2; + uint8_t illuminance; + uint8_t unused3[10]; + uint16_t unused4[4]; + uint16_t battery; + uint16_t unused5; + }; }; } // namespace airthings_wave_base diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp index 331a13434f..873826d06c 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.cpp @@ -26,12 +26,9 @@ void AirthingsWaveMini::read_sensors(uint8_t *raw_value, uint16_t value_len) { if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } - - // This instance must not stay connected - // so other clients can connect to it (e.g. the - // mobile app). - this->parent()->set_enabled(false); } + + this->response_received_(); } void AirthingsWaveMini::dump_config() { @@ -42,11 +39,14 @@ void AirthingsWaveMini::dump_config() { LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); + LOG_SENSOR(" ", "Battery Voltage", this->battery_voltage_); } AirthingsWaveMini::AirthingsWaveMini() { - this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); - this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); + this->service_uuid_ = espbt::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = espbt::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); + this->access_control_point_characteristic_uuid_ = + espbt::ESPBTUUID::from_raw(ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID); } } // namespace airthings_wave_mini diff --git a/esphome/components/airthings_wave_mini/airthings_wave_mini.h b/esphome/components/airthings_wave_mini/airthings_wave_mini.h index ec4fd23e60..825ddbdc69 100644 --- a/esphome/components/airthings_wave_mini/airthings_wave_mini.h +++ b/esphome/components/airthings_wave_mini/airthings_wave_mini.h @@ -7,8 +7,11 @@ namespace esphome { namespace airthings_wave_mini { +namespace espbt = esphome::esp32_ble_tracker; + static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba"; +static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID = "b42e3ef4-ade7-11e4-89d3-123b93f75cba"; class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase { public: @@ -17,7 +20,7 @@ class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase { void dump_config() override; protected: - void read_sensors(uint8_t *value, uint16_t value_len) override; + void read_sensors(uint8_t *raw_value, uint16_t value_len) override; struct WaveMiniReadings { uint16_t unused01; diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index acd3a4316d..e44d5fbcaa 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -43,15 +43,12 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } - - // This instance must not stay connected - // so other clients can connect to it (e.g. the - // mobile app). - this->parent()->set_enabled(false); } else { ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); } } + + this->response_received_(); } bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } @@ -66,6 +63,7 @@ void AirthingsWavePlus::dump_config() { LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_); + LOG_SENSOR(" ", "Battery Voltage", this->battery_voltage_); LOG_SENSOR(" ", "Radon", this->radon_sensor_); LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); @@ -73,8 +71,10 @@ void AirthingsWavePlus::dump_config() { } AirthingsWavePlus::AirthingsWavePlus() { - this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); - this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); + this->service_uuid_ = espbt::ESPBTUUID::from_raw(SERVICE_UUID); + this->sensors_data_characteristic_uuid_ = espbt::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); + this->access_control_point_characteristic_uuid_ = + espbt::ESPBTUUID::from_raw(ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID); } } // namespace airthings_wave_plus diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.h b/esphome/components/airthings_wave_plus/airthings_wave_plus.h index 4acfb9279a..23c8cbb166 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.h +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.h @@ -7,8 +7,11 @@ namespace esphome { namespace airthings_wave_plus { +namespace espbt = esphome::esp32_ble_tracker; + static const char *const SERVICE_UUID = "b42e1c08-ade7-11e4-89d3-123b93f75cba"; static const char *const CHARACTERISTIC_UUID = "b42e2a68-ade7-11e4-89d3-123b93f75cba"; +static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID = "b42e2d06-ade7-11e4-89d3-123b93f75cba"; class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { public: @@ -24,7 +27,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { bool is_valid_radon_value_(uint16_t radon); bool is_valid_co2_value_(uint16_t co2); - void read_sensors(uint8_t *value, uint16_t value_len) override; + void read_sensors(uint8_t *raw_value, uint16_t value_len) override; sensor::Sensor *radon_sensor_{nullptr}; sensor::Sensor *radon_long_term_sensor_{nullptr}; diff --git a/esphome/components/airthings_wave_plus/sensor.py b/esphome/components/airthings_wave_plus/sensor.py index a5903b1d42..643a2bfb68 100644 --- a/esphome/components/airthings_wave_plus/sensor.py +++ b/esphome/components/airthings_wave_plus/sensor.py @@ -53,12 +53,12 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await airthings_wave_base.wave_base_to_code(var, config) - if CONF_RADON in config: - sens = await sensor.new_sensor(config[CONF_RADON]) + if config_radon := config.get(CONF_RADON): + sens = await sensor.new_sensor(config_radon) cg.add(var.set_radon(sens)) - if CONF_RADON_LONG_TERM in config: - sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) + if config_radon_long_term := config.get(CONF_RADON_LONG_TERM): + sens = await sensor.new_sensor(config_radon_long_term) cg.add(var.set_radon_long_term(sens)) - if CONF_CO2 in config: - sens = await sensor.new_sensor(config[CONF_CO2]) + if config_co2 := config.get(CONF_CO2): + sens = await sensor.new_sensor(config_co2) cg.add(var.set_co2(sens)) diff --git a/tests/test2.yaml b/tests/test2.yaml index 675fae6cf3..31fd840f5c 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -316,6 +316,7 @@ sensor: platform: airthings_wave_plus ble_client_id: airthings01 update_interval: 5min + battery_update_interval: 12h temperature: name: Wave Plus Temperature radon: @@ -330,10 +331,13 @@ sensor: name: Wave Plus CO2 tvoc: name: Wave Plus VOC + battery_voltage: + name: Wave Plus Battery Voltage - id: airthingswm platform: airthings_wave_mini ble_client_id: airthingsmini01 update_interval: 5min + battery_update_interval: 12h temperature: name: Wave Mini Temperature humidity: @@ -342,6 +346,8 @@ sensor: name: Wave Mini Pressure tvoc: name: Wave Mini VOC + battery_voltage: + name: Wave Mini Battery Voltage - platform: ina260 address: 0x40 current: From e0fd8cd8508eb95acd786a57bb7b5fb2b3c9efd3 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 12 Jul 2023 04:02:53 +0100 Subject: [PATCH 0212/2607] Add support for Grove tb6612 fng (#4797) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../components/grove_i2c_motor/__init__.py | 152 +++++++++++++ .../grove_i2c_motor/grove_i2c_motor.cpp | 171 ++++++++++++++ .../grove_i2c_motor/grove_i2c_motor.h | 208 ++++++++++++++++++ tests/test3.1.yaml | 15 ++ 5 files changed, 547 insertions(+) create mode 100644 esphome/components/grove_i2c_motor/__init__.py create mode 100644 esphome/components/grove_i2c_motor/grove_i2c_motor.cpp create mode 100644 esphome/components/grove_i2c_motor/grove_i2c_motor.h diff --git a/CODEOWNERS b/CODEOWNERS index 641911e84f..d9303523df 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -103,6 +103,7 @@ esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core esphome/components/gps/* @coogle esphome/components/graph/* @synco +esphome/components/grove_i2c_motor/* @max246 esphome/components/growatt_solar/* @leeuwte esphome/components/haier/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal diff --git a/esphome/components/grove_i2c_motor/__init__.py b/esphome/components/grove_i2c_motor/__init__.py new file mode 100644 index 0000000000..f7888f7293 --- /dev/null +++ b/esphome/components/grove_i2c_motor/__init__.py @@ -0,0 +1,152 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import i2c + +from esphome.const import ( + CONF_ID, + CONF_CHANNEL, + CONF_SPEED, + CONF_DIRECTION, +) + +DEPENDENCIES = ["i2c"] + +CODEOWNERS = ["@max246"] + +grove_i2c_motor_ns = cg.esphome_ns.namespace("grove_i2c_motor") +GROVE_TB6612FNG = grove_i2c_motor_ns.class_( + "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice +) +GROVETB6612FNGMotorRunAction = grove_i2c_motor_ns.class_( + "GROVETB6612FNGMotorRunAction", automation.Action +) +GROVETB6612FNGMotorBrakeAction = grove_i2c_motor_ns.class_( + "GROVETB6612FNGMotorBrakeAction", automation.Action +) +GROVETB6612FNGMotorStopAction = grove_i2c_motor_ns.class_( + "GROVETB6612FNGMotorStopAction", automation.Action +) +GROVETB6612FNGMotorStandbyAction = grove_i2c_motor_ns.class_( + "GROVETB6612FNGMotorStandbyAction", automation.Action +) +GROVETB6612FNGMotorNoStandbyAction = grove_i2c_motor_ns.class_( + "GROVETB6612FNGMotorNoStandbyAction", automation.Action +) + +DIRECTION_TYPE = { + "FORWARD": 1, + "BACKWARD": 2, +} + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(GROVE_TB6612FNG), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x14)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +@automation.register_action( + "grove_i2c_motor.run", + GROVETB6612FNGMotorRunAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + cv.Required(CONF_CHANNEL): cv.templatable(cv.int_range(min=0, max=1)), + cv.Required(CONF_SPEED): cv.templatable(cv.int_range(min=0, max=255)), + cv.Required(CONF_DIRECTION): cv.enum(DIRECTION_TYPE, upper=True), + } + ), +) +async def grove_i2c_motor_run_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + template_channel = await cg.templatable(config[CONF_CHANNEL], args, int) + template_speed = await cg.templatable(config[CONF_SPEED], args, cg.uint16) + template_speed = ( + template_speed if config[CONF_DIRECTION] == "FORWARD" else -template_speed + ) + cg.add(var.set_channel(template_channel)) + cg.add(var.set_speed(template_speed)) + return var + + +@automation.register_action( + "grove_i2c_motor.break", + GROVETB6612FNGMotorBrakeAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + cv.Required(CONF_CHANNEL): cv.templatable(cv.int_range(min=0, max=1)), + } + ), +) +async def grove_i2c_motor_break_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + template_channel = await cg.templatable(config[CONF_CHANNEL], args, int) + cg.add(var.set_channel(template_channel)) + return var + + +@automation.register_action( + "grove_i2c_motor.stop", + GROVETB6612FNGMotorStopAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + cv.Required(CONF_CHANNEL): cv.templatable(cv.int_range(min=0, max=1)), + } + ), +) +async def grove_i2c_motor_stop_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + template_channel = await cg.templatable(config[CONF_CHANNEL], args, int) + cg.add(var.set_channel(template_channel)) + return var + + +@automation.register_action( + "grove_i2c_motor.standby", + GROVETB6612FNGMotorStandbyAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + } + ), +) +async def grove_i2c_motor_standby_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + return var + + +@automation.register_action( + "grove_i2c_motor.no_standby", + GROVETB6612FNGMotorNoStandbyAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + } + ), +) +async def grove_i2c_motor_no_standby_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + return var diff --git a/esphome/components/grove_i2c_motor/grove_i2c_motor.cpp b/esphome/components/grove_i2c_motor/grove_i2c_motor.cpp new file mode 100644 index 0000000000..669114aec0 --- /dev/null +++ b/esphome/components/grove_i2c_motor/grove_i2c_motor.cpp @@ -0,0 +1,171 @@ +#include "grove_i2c_motor.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace grove_i2c_motor { + +static const char *const TAG = "GroveMotorDriveTB6612FNG"; + +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_BRAKE = 0x00; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_STOP = 0x01; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_CW = 0x02; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_CCW = 0x03; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_STANDBY = 0x04; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_NOT_STANDBY = 0x05; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_RUN = 0x06; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_STOP = 0x07; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_KEEP_RUN = 0x08; +static const uint8_t GROVE_MOTOR_DRIVER_I2C_CMD_SET_ADDR = 0x11; + +void GroveMotorDriveTB6612FNG::dump_config() { + ESP_LOGCONFIG(TAG, "GroveMotorDriveTB6612FNG:"); + LOG_I2C_DEVICE(this); +} + +void GroveMotorDriveTB6612FNG::setup() { + ESP_LOGCONFIG(TAG, "Setting up Grove Motor Drive TB6612FNG ..."); + if (!this->standby()) { + this->mark_failed(); + return; + } +} + +bool GroveMotorDriveTB6612FNG::standby() { + uint8_t status = 0; + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STANDBY, &status, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Set standby failed!"); + this->status_set_warning(); + return false; + } + return true; +} + +bool GroveMotorDriveTB6612FNG::not_standby() { + uint8_t status = 0; + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_NOT_STANDBY, &status, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Set not standby failed!"); + this->status_set_warning(); + return false; + } + return true; +} + +void GroveMotorDriveTB6612FNG::set_i2c_addr(uint8_t addr) { + if (addr == 0x00 || addr >= 0x80) { + return; + } + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_SET_ADDR, &addr, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Set new i2c address failed!"); + this->status_set_warning(); + return; + } + this->set_i2c_address(addr); +} + +void GroveMotorDriveTB6612FNG::dc_motor_run(uint8_t channel, int16_t speed) { + speed = clamp(speed, -255, 255); + + buffer_[0] = channel; + if (speed >= 0) { + buffer_[1] = speed; + } else { + buffer_[1] = (uint8_t) (-speed); + } + + if (speed >= 0) { + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_CW, buffer_, 2) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Run motor failed!"); + this->status_set_warning(); + return; + } + } else { + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_CCW, buffer_, 2) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Run motor failed!"); + this->status_set_warning(); + return; + } + } +} + +void GroveMotorDriveTB6612FNG::dc_motor_brake(uint8_t channel) { + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_BRAKE, &channel, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Break motor failed!"); + this->status_set_warning(); + return; + } +} + +void GroveMotorDriveTB6612FNG::dc_motor_stop(uint8_t channel) { + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STOP, &channel, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Stop dc motor failed!"); + this->status_set_warning(); + return; + } +} + +void GroveMotorDriveTB6612FNG::stepper_run(StepperModeTypeT mode, int16_t steps, uint16_t rpm) { + uint8_t cw = 0; + // 0.1ms_per_step + uint16_t ms_per_step = 0; + + if (steps > 0) { + cw = 1; + } + // stop + else if (steps == 0) { + this->stepper_stop(); + return; + } else if (steps == INT16_MIN) { + steps = INT16_MAX; + } else { + steps = -steps; + } + + rpm = clamp(rpm, 1, 300); + + ms_per_step = (uint16_t) (3000.0 / (float) rpm); + buffer_[0] = mode; + buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw + buffer_[2] = steps; + buffer_[3] = (steps >> 8); + buffer_[4] = ms_per_step; + buffer_[5] = (ms_per_step >> 8); + + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_RUN, buffer_, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Run stepper failed!"); + this->status_set_warning(); + return; + } +} + +void GroveMotorDriveTB6612FNG::stepper_stop() { + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_STOP, nullptr, 1) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Send stop stepper failed!"); + this->status_set_warning(); + return; + } +} + +void GroveMotorDriveTB6612FNG::stepper_keep_run(StepperModeTypeT mode, uint16_t rpm, bool is_cw) { + // 4=>infinite ccw 5=>infinite cw + uint8_t cw = (is_cw) ? 5 : 4; + // 0.1ms_per_step + uint16_t ms_per_step = 0; + + rpm = clamp(rpm, 1, 300); + ms_per_step = (uint16_t) (3000.0 / (float) rpm); + + buffer_[0] = mode; + buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw + buffer_[2] = ms_per_step; + buffer_[3] = (ms_per_step >> 8); + + if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_KEEP_RUN, buffer_, 4) != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Write stepper keep run failed"); + this->status_set_warning(); + return; + } +} +} // namespace grove_i2c_motor +} // namespace esphome diff --git a/esphome/components/grove_i2c_motor/grove_i2c_motor.h b/esphome/components/grove_i2c_motor/grove_i2c_motor.h new file mode 100644 index 0000000000..8a0db77e70 --- /dev/null +++ b/esphome/components/grove_i2c_motor/grove_i2c_motor.h @@ -0,0 +1,208 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/automation.h" +//#include "esphome/core/helpers.h" + +/* + Grove_Motor_Driver_TB6612FNG.h + A library for the Grove - Motor Driver(TB6612FNG) + Copyright (c) 2018 seeed technology co., ltd. + Website : www.seeed.cc + Author : Jerry Yip + Create Time: 2018-06 + Version : 0.1 + Change Log : + The MIT License (MIT) + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +namespace esphome { +namespace grove_i2c_motor { + +enum MotorChannelTypeT { + MOTOR_CHA = 0, + MOTOR_CHB = 1, +}; + +enum StepperModeTypeT { + FULL_STEP = 0, + WAVE_DRIVE = 1, + HALF_STEP = 2, + MICRO_STEPPING = 3, +}; + +class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + + /************************************************************* + Description + Enter standby mode. Normally you don't need to call this, except that + you have called notStandby() before. + Parameter + Null. + Return + True/False. + *************************************************************/ + bool standby(); + + /************************************************************* + Description + Exit standby mode. Motor driver does't do any action at this mode. + Parameter + Null. + Return + True/False. + *************************************************************/ + bool not_standby(); + + /************************************************************* + Description + Set an new I2C address. + Parameter + addr: 0x01~0x7f + Return + Null. + *************************************************************/ + void set_i2c_addr(uint8_t addr); + + /************************************************************* + Description + Drive a motor. + Parameter + chl: MOTOR_CHA or MOTOR_CHB + speed: -255~255, if speed > 0, motor moves clockwise. + Note that there is always a starting speed(a starting voltage) for motor. + If the input voltage is 5V, the starting speed should larger than 100 or + smaller than -100. + Return + Null. + *************************************************************/ + void dc_motor_run(uint8_t channel, int16_t speed); + + /************************************************************* + Description + Brake, stop the motor immediately + Parameter + chl: MOTOR_CHA or MOTOR_CHB + Return + Null. + *************************************************************/ + void dc_motor_brake(uint8_t channel); + + /************************************************************* + Description + Stop the motor slowly. + Parameter + chl: MOTOR_CHA or MOTOR_CHB + Return + Null. + *************************************************************/ + void dc_motor_stop(uint8_t channel); + + /************************************************************* + Description + Drive a stepper. + Parameter + mode: 4 driver mode: FULL_STEP,WAVE_DRIVE, HALF_STEP, MICRO_STEPPING, + for more information: https://en.wikipedia.org/wiki/Stepper_motor#/media/File:Drive.png + steps: The number of steps to run, range from -32768 to 32767. + When steps = 0, the stepper stops. + When steps > 0, the stepper runs clockwise. When steps < 0, the stepper runs anticlockwise. + rpm: Revolutions per minute, the speed of a stepper, range from 1 to 300. + Note that high rpm will lead to step lose, so rpm should not be larger than 150. + Return + Null. + *************************************************************/ + void stepper_run(StepperModeTypeT mode, int16_t steps, uint16_t rpm); + + /************************************************************* + Description + Stop a stepper. + Parameter + Null. + Return + Null. + *************************************************************/ + void stepper_stop(); + + // keeps moving(direction same as the last move, default to clockwise) + /************************************************************* + Description + Keep a stepper running. + Parameter + mode: 4 driver mode: FULL_STEP,WAVE_DRIVE, HALF_STEP, MICRO_STEPPING, + for more information: https://en.wikipedia.org/wiki/Stepper_motor#/media/File:Drive.png + rpm: Revolutions per minute, the speed of a stepper, range from 1 to 300. + Note that high rpm will lead to step lose, so rpm should not be larger than 150. + is_cw: Set the running direction, true for clockwise and false for anti-clockwise. + Return + Null. + *************************************************************/ + void stepper_keep_run(StepperModeTypeT mode, uint16_t rpm, bool is_cw); + + private: + uint8_t buffer_[16]; +}; + +template +class GROVETB6612FNGMotorRunAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, channel) + TEMPLATABLE_VALUE(uint16_t, speed) + + void play(Ts... x) override { + auto channel = this->channel_.value(x...); + auto speed = this->speed_.value(x...); + this->parent_->dc_motor_run(channel, speed); + } +}; + +template +class GROVETB6612FNGMotorBrakeAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, channel) + + void play(Ts... x) override { this->parent_->dc_motor_brake(this->channel_.value(x...)); } +}; + +template +class GROVETB6612FNGMotorStopAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, channel) + + void play(Ts... x) override { this->parent_->dc_motor_stop(this->channel_.value(x...)); } +}; + +template +class GROVETB6612FNGMotorStandbyAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->standby(); } +}; + +template +class GROVETB6612FNGMotorNoStandbyAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->not_standby(); } +}; + +} // namespace grove_i2c_motor +} // namespace esphome diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 0daf4e9671..a003c804c9 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -303,6 +303,10 @@ sm2135: rgb_current: 20mA cw_current: 60mA +grove_i2c_motor: + id: test_motor + address: 0x14 + switch: - platform: template name: mpr121_toggle @@ -353,6 +357,17 @@ switch: Content-Type: application/json body: Some data verify_ssl: false + - platform: template + name: open_vent + id: open_vent + optimistic: True + on_turn_on: + then: + - grove_i2c_motor.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor custom_component: From ec37dece1294b117ed0833772bbc0d1bfdeb8951 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:12:48 +1000 Subject: [PATCH 0213/2607] Add MCP2515 12MHz xtal support (#5089) --- esphome/components/mcp2515/canbus.py | 1 + esphome/components/mcp2515/mcp2515.cpp | 98 ++++++++++++++++++++--- esphome/components/mcp2515/mcp2515.h | 2 +- esphome/components/mcp2515/mcp2515_defs.h | 56 +++++++++++++ 4 files changed, 143 insertions(+), 14 deletions(-) diff --git a/esphome/components/mcp2515/canbus.py b/esphome/components/mcp2515/canbus.py index c410c1af69..4353cd7bc6 100644 --- a/esphome/components/mcp2515/canbus.py +++ b/esphome/components/mcp2515/canbus.py @@ -16,6 +16,7 @@ McpMode = mcp2515_ns.enum("CANCTRL_REQOP_MODE") CAN_CLOCK = { "8MHZ": CanClock.MCP_8MHZ, + "12MHZ": CanClock.MCP_12MHZ, "16MHZ": CanClock.MCP_16MHZ, "20MHZ": CanClock.MCP_20MHZ, } diff --git a/esphome/components/mcp2515/mcp2515.cpp b/esphome/components/mcp2515/mcp2515.cpp index b90b4de66d..fe4a68b583 100644 --- a/esphome/components/mcp2515/mcp2515.cpp +++ b/esphome/components/mcp2515/mcp2515.cpp @@ -16,11 +16,14 @@ const struct MCP2515::RxBnRegs MCP2515::RXB[N_RXBUFFERS] = {{MCP_RXB0CTRL, MCP_R bool MCP2515::setup_internal() { this->spi_setup(); - if (this->reset_() == canbus::ERROR_FAIL) + if (this->reset_() != canbus::ERROR_OK) return false; - this->set_bitrate_(this->bit_rate_, this->mcp_clock_); - this->set_mode_(this->mcp_mode_); - ESP_LOGV(TAG, "setup done"); + if (this->set_bitrate_(this->bit_rate_, this->mcp_clock_) != canbus::ERROR_OK) + return false; + if (this->set_mode_(this->mcp_mode_) != canbus::ERROR_OK) + return false; + uint8_t err_flags = this->get_error_flags_(); + ESP_LOGD(TAG, "mcp2515 setup done, error_flags = %02X", err_flags); return true; } @@ -38,7 +41,7 @@ canbus::Error MCP2515::reset_() { set_registers_(MCP_TXB0CTRL, zeros, 14); set_registers_(MCP_TXB1CTRL, zeros, 14); set_registers_(MCP_TXB2CTRL, zeros, 14); - ESP_LOGD(TAG, "reset() CLEARED TXB registers"); + ESP_LOGV(TAG, "reset() CLEARED TXB registers"); set_register_(MCP_RXB0CTRL, 0); set_register_(MCP_RXB1CTRL, 0); @@ -114,16 +117,12 @@ canbus::Error MCP2515::set_mode_(const CanctrlReqopMode mode) { modify_register_(MCP_CANCTRL, CANCTRL_REQOP, mode); uint32_t end_time = millis() + 10; - bool mode_match = false; while (millis() < end_time) { - uint8_t new_mode = read_register_(MCP_CANSTAT); - new_mode &= CANSTAT_OPMOD; - mode_match = new_mode == mode; - if (mode_match) { - break; - } + if ((read_register_(MCP_CANSTAT) & CANSTAT_OPMOD) == mode) + return canbus::ERROR_OK; } - return mode_match ? canbus::ERROR_OK : canbus::ERROR_FAIL; + ESP_LOGE(TAG, "Failed to set mode"); + return canbus::ERROR_FAIL; } canbus::Error MCP2515::set_clk_out_(const CanClkOut divisor) { @@ -451,6 +450,78 @@ canbus::Error MCP2515::set_bitrate_(canbus::CanSpeed can_speed, CanClock can_clo } break; + case (MCP_12MHZ): + switch (can_speed) { + case (canbus::CAN_5KBPS): // 5Kbps + cfg1 = MCP_12MHZ_5KBPS_CFG1; + cfg2 = MCP_12MHZ_5KBPS_CFG2; + cfg3 = MCP_12MHZ_5KBPS_CFG3; + break; + case (canbus::CAN_10KBPS): // 10Kbps + cfg1 = MCP_12MHZ_10KBPS_CFG1; + cfg2 = MCP_12MHZ_10KBPS_CFG2; + cfg3 = MCP_12MHZ_10KBPS_CFG3; + break; + case (canbus::CAN_20KBPS): // 20Kbps + cfg1 = MCP_12MHZ_20KBPS_CFG1; + cfg2 = MCP_12MHZ_20KBPS_CFG2; + cfg3 = MCP_12MHZ_20KBPS_CFG3; + break; + case (canbus::CAN_33KBPS): // 33.333Kbps + cfg1 = MCP_12MHZ_33K3BPS_CFG1; + cfg2 = MCP_12MHZ_33K3BPS_CFG2; + cfg3 = MCP_12MHZ_33K3BPS_CFG3; + break; + case (canbus::CAN_40KBPS): // 40Kbps + cfg1 = MCP_12MHZ_40KBPS_CFG1; + cfg2 = MCP_12MHZ_40KBPS_CFG2; + cfg3 = MCP_12MHZ_40KBPS_CFG3; + break; + case (canbus::CAN_50KBPS): // 50Kbps + cfg2 = MCP_12MHZ_50KBPS_CFG2; + cfg3 = MCP_12MHZ_50KBPS_CFG3; + break; + case (canbus::CAN_80KBPS): // 80Kbps + cfg1 = MCP_12MHZ_80KBPS_CFG1; + cfg2 = MCP_12MHZ_80KBPS_CFG2; + cfg3 = MCP_12MHZ_80KBPS_CFG3; + break; + case (canbus::CAN_100KBPS): // 100Kbps + cfg1 = MCP_12MHZ_100KBPS_CFG1; + cfg2 = MCP_12MHZ_100KBPS_CFG2; + cfg3 = MCP_12MHZ_100KBPS_CFG3; + break; + case (canbus::CAN_125KBPS): // 125Kbps + cfg1 = MCP_12MHZ_125KBPS_CFG1; + cfg2 = MCP_12MHZ_125KBPS_CFG2; + cfg3 = MCP_12MHZ_125KBPS_CFG3; + break; + case (canbus::CAN_200KBPS): // 200Kbps + cfg1 = MCP_12MHZ_200KBPS_CFG1; + cfg2 = MCP_12MHZ_200KBPS_CFG2; + cfg3 = MCP_12MHZ_200KBPS_CFG3; + break; + case (canbus::CAN_250KBPS): // 250Kbps + cfg1 = MCP_12MHZ_250KBPS_CFG1; + cfg2 = MCP_12MHZ_250KBPS_CFG2; + cfg3 = MCP_12MHZ_250KBPS_CFG3; + break; + case (canbus::CAN_500KBPS): // 500Kbps + cfg1 = MCP_12MHZ_500KBPS_CFG1; + cfg2 = MCP_12MHZ_500KBPS_CFG2; + cfg3 = MCP_12MHZ_500KBPS_CFG3; + break; + case (canbus::CAN_1000KBPS): // 1Mbps + cfg1 = MCP_12MHZ_1000KBPS_CFG1; + cfg2 = MCP_12MHZ_1000KBPS_CFG2; + cfg3 = MCP_12MHZ_1000KBPS_CFG3; + break; + default: + set = 0; + break; + } + break; + case (MCP_16MHZ): switch (can_speed) { case (canbus::CAN_5KBPS): // 5Kbps @@ -602,6 +673,7 @@ canbus::Error MCP2515::set_bitrate_(canbus::CanSpeed can_speed, CanClock can_clo set_register_(MCP_CNF3, cfg3); // NOLINT return canbus::ERROR_OK; } else { + ESP_LOGE(TAG, "Invalid frequency/bitrate combination: %d/%d", can_clock, can_speed); return canbus::ERROR_FAIL; } } diff --git a/esphome/components/mcp2515/mcp2515.h b/esphome/components/mcp2515/mcp2515.h index 3b9797a78a..c77480ce7d 100644 --- a/esphome/components/mcp2515/mcp2515.h +++ b/esphome/components/mcp2515/mcp2515.h @@ -11,7 +11,7 @@ static const uint32_t SPI_CLOCK = 10000000; // 10MHz static const int N_TXBUFFERS = 3; static const int N_RXBUFFERS = 2; -enum CanClock { MCP_20MHZ, MCP_16MHZ, MCP_8MHZ }; +enum CanClock { MCP_20MHZ, MCP_16MHZ, MCP_12MHZ, MCP_8MHZ }; enum MASK { MASK0, MASK1 }; enum RXF { RXF0 = 0, RXF1 = 1, RXF2 = 2, RXF3 = 3, RXF4 = 4, RXF5 = 5 }; enum RXBn { RXB0 = 0, RXB1 = 1 }; diff --git a/esphome/components/mcp2515/mcp2515_defs.h b/esphome/components/mcp2515/mcp2515_defs.h index 454c760c6d..2f5cf2a238 100644 --- a/esphome/components/mcp2515/mcp2515_defs.h +++ b/esphome/components/mcp2515/mcp2515_defs.h @@ -207,6 +207,62 @@ static const uint8_t MCP_8MHZ_5KBPS_CFG1 = 0x1F; static const uint8_t MCP_8MHZ_5KBPS_CFG2 = 0xBF; static const uint8_t MCP_8MHZ_5KBPS_CFG3 = 0x87; +/* + * Speed 12M + */ + +static const uint8_t MCP_12MHZ_1000KBPS_CFG1 = 0x00; +static const uint8_t MCP_12MHZ_1000KBPS_CFG2 = 0x88; +static const uint8_t MCP_12MHZ_1000KBPS_CFG3 = 0x81; + +static const uint8_t MCP_12MHZ_500KBPS_CFG1 = 0x00; +static const uint8_t MCP_12MHZ_500KBPS_CFG2 = 0x9B; +static const uint8_t MCP_12MHZ_500KBPS_CFG3 = 0x82; + +static const uint8_t MCP_12MHZ_250KBPS_CFG1 = 0x01; +static const uint8_t MCP_12MHZ_250KBPS_CFG2 = 0x9B; +static const uint8_t MCP_12MHZ_250KBPS_CFG3 = 0x82; + +static const uint8_t MCP_12MHZ_200KBPS_CFG1 = 0x01; +static const uint8_t MCP_12MHZ_200KBPS_CFG2 = 0xA4; +static const uint8_t MCP_12MHZ_200KBPS_CFG3 = 0x83; + +static const uint8_t MCP_12MHZ_125KBPS_CFG1 = 0x03; +static const uint8_t MCP_12MHZ_125KBPS_CFG2 = 0x9B; +static const uint8_t MCP_12MHZ_125KBPS_CFG3 = 0x82; + +static const uint8_t MCP_12MHZ_100KBPS_CFG1 = 0x03; +static const uint8_t MCP_12MHZ_100KBPS_CFG2 = 0xA4; +static const uint8_t MCP_12MHZ_100KBPS_CFG3 = 0x83; + +static const uint8_t MCP_12MHZ_80KBPS_CFG1 = 0x04; +static const uint8_t MCP_12MHZ_80KBPS_CFG2 = 0xA4; +static const uint8_t MCP_12MHZ_80KBPS_CFG3 = 0x83; + +static const uint8_t MCP_12MHZ_50KBPS_CFG1 = 0x07; +static const uint8_t MCP_12MHZ_50KBPS_CFG2 = 0xA4; +static const uint8_t MCP_12MHZ_50KBPS_CFG3 = 0x83; + +static const uint8_t MCP_12MHZ_40KBPS_CFG1 = 0x09; +static const uint8_t MCP_12MHZ_40KBPS_CFG2 = 0xA4; +static const uint8_t MCP_12MHZ_40KBPS_CFG3 = 0x83; + +static const uint8_t MCP_12MHZ_33K3BPS_CFG1 = 0x08; +static const uint8_t MCP_12MHZ_33K3BPS_CFG2 = 0xB6; +static const uint8_t MCP_12MHZ_33K3BPS_CFG3 = 0x84; + +static const uint8_t MCP_12MHZ_20KBPS_CFG1 = 0x0E; +static const uint8_t MCP_12MHZ_20KBPS_CFG2 = 0xB6; +static const uint8_t MCP_12MHZ_20KBPS_CFG3 = 0x84; + +static const uint8_t MCP_12MHZ_10KBPS_CFG1 = 0x31; +static const uint8_t MCP_12MHZ_10KBPS_CFG2 = 0x9B; +static const uint8_t MCP_12MHZ_10KBPS_CFG3 = 0x82; + +static const uint8_t MCP_12MHZ_5KBPS_CFG1 = 0x3B; +static const uint8_t MCP_12MHZ_5KBPS_CFG2 = 0xB6; +static const uint8_t MCP_12MHZ_5KBPS_CFG3 = 0x84; + /* * speed 16M */ From 6d9dbf9e54dc66ac3d8bf0592ddb89a015eb8576 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:22:52 +1000 Subject: [PATCH 0214/2607] Correct message for standard transmission. (#5088) --- esphome/components/canbus/canbus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/canbus/canbus.cpp b/esphome/components/canbus/canbus.cpp index 3fe0d50f06..6316c77ff4 100644 --- a/esphome/components/canbus/canbus.cpp +++ b/esphome/components/canbus/canbus.cpp @@ -30,7 +30,7 @@ void Canbus::send_data(uint32_t can_id, bool use_extended_id, bool remote_transm if (use_extended_id) { ESP_LOGD(TAG, "send extended id=0x%08x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); } else { - ESP_LOGD(TAG, "send extended id=0x%03x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); + ESP_LOGD(TAG, "send standard id=0x%03x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); } if (size > CAN_MAX_DATA_LENGTH) size = CAN_MAX_DATA_LENGTH; From 7e52d4f5d64380ef0cf0a8467615122856f925c0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:28:20 +1200 Subject: [PATCH 0215/2607] Restrict pillow to versions before 10.0.0 (#5090) --- requirements_optional.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_optional.txt b/requirements_optional.txt index df6b3b387e..8bbf0a6809 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,3 +1,3 @@ -pillow>4.0.0 +pillow>4.0.0,<10.0.0 cairosvg>=2.2.0 cryptography>=2.0.0,<4 From c85f70a236192b5ff8c5c14930509a1938f30b8f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:02:37 +1200 Subject: [PATCH 0216/2607] Bump esphome-dashboard to 20230711.0 (#5085) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c6564d55e0..618fc94e0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.3 -esphome-dashboard==20230621.0 +esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 zeroconf==0.69.0 From bbf3d382e8be1a9039f1fc51eb4fd888eb08ee9b Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Wed, 12 Jul 2023 08:12:40 +0400 Subject: [PATCH 0217/2607] added uart final validate data bits (#5079) --- esphome/components/uart/__init__.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index ed60a9f880..aea59d9d8b 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -246,6 +246,7 @@ def final_validate_device_schema( baud_rate: Optional[int] = None, require_tx: bool = False, require_rx: bool = False, + data_bits: Optional[int] = None, parity: Optional[str] = None, stop_bits: Optional[int] = None, ): @@ -268,6 +269,13 @@ def final_validate_device_schema( return validator + def validate_data_bits(value): + if value != data_bits: + raise cv.Invalid( + f"Component {name} requires {data_bits} data bits for the uart bus" + ) + return value + def validate_parity(value): if value != parity: raise cv.Invalid( @@ -278,7 +286,7 @@ def final_validate_device_schema( def validate_stop_bits(value): if value != stop_bits: raise cv.Invalid( - f"Component {name} requires stop bits {stop_bits} for the uart bus" + f"Component {name} requires {stop_bits} stop bits for the uart bus" ) return value @@ -304,6 +312,8 @@ def final_validate_device_schema( ] = validate_pin(CONF_RX_PIN, device) if baud_rate is not None: hub_schema[cv.Required(CONF_BAUD_RATE)] = validate_baud_rate + if data_bits is not None: + hub_schema[cv.Required(CONF_DATA_BITS)] = validate_data_bits if parity is not None: hub_schema[cv.Required(CONF_PARITY)] = validate_parity if stop_bits is not None: From 8c5978599aa67d358a85e5201ee77b85975b0116 Mon Sep 17 00:00:00 2001 From: danieltwagner Date: Wed, 12 Jul 2023 01:10:22 -0400 Subject: [PATCH 0218/2607] Add support for ATM90E26 (#4366) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/atm90e26/__init__.py | 1 + esphome/components/atm90e26/atm90e26.cpp | 235 +++++++++++++++++++++ esphome/components/atm90e26/atm90e26.h | 72 +++++++ esphome/components/atm90e26/atm90e26_reg.h | 70 ++++++ esphome/components/atm90e26/sensor.py | 157 ++++++++++++++ tests/test1.yaml | 19 ++ 7 files changed, 555 insertions(+) create mode 100644 esphome/components/atm90e26/__init__.py create mode 100644 esphome/components/atm90e26/atm90e26.cpp create mode 100644 esphome/components/atm90e26/atm90e26.h create mode 100644 esphome/components/atm90e26/atm90e26_reg.h create mode 100644 esphome/components/atm90e26/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index d9303523df..f5dc9a17f4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -32,6 +32,7 @@ esphome/components/api/* @OttoWinter esphome/components/as7341/* @mrgnr esphome/components/async_tcp/* @OttoWinter esphome/components/atc_mithermometer/* @ahpohl +esphome/components/atm90e26/* @danieltwagner esphome/components/b_parasite/* @rbaron esphome/components/ballu/* @bazuchan esphome/components/bang_bang/* @OttoWinter diff --git a/esphome/components/atm90e26/__init__.py b/esphome/components/atm90e26/__init__.py new file mode 100644 index 0000000000..ac441a9c2d --- /dev/null +++ b/esphome/components/atm90e26/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@danieltwagner"] diff --git a/esphome/components/atm90e26/atm90e26.cpp b/esphome/components/atm90e26/atm90e26.cpp new file mode 100644 index 0000000000..42a52c4ccf --- /dev/null +++ b/esphome/components/atm90e26/atm90e26.cpp @@ -0,0 +1,235 @@ +#include "atm90e26.h" +#include "atm90e26_reg.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace atm90e26 { + +static const char *const TAG = "atm90e26"; + +void ATM90E26Component::update() { + if (this->read16_(ATM90E26_REGISTER_FUNCEN) != 0x0030) { + this->status_set_warning(); + return; + } + + if (this->voltage_sensor_ != nullptr) { + this->voltage_sensor_->publish_state(this->get_line_voltage_()); + } + if (this->current_sensor_ != nullptr) { + this->current_sensor_->publish_state(this->get_line_current_()); + } + if (this->power_sensor_ != nullptr) { + this->power_sensor_->publish_state(this->get_active_power_()); + } + if (this->reactive_power_sensor_ != nullptr) { + this->reactive_power_sensor_->publish_state(this->get_reactive_power_()); + } + if (this->power_factor_sensor_ != nullptr) { + this->power_factor_sensor_->publish_state(this->get_power_factor_()); + } + if (this->forward_active_energy_sensor_ != nullptr) { + this->forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_()); + } + if (this->reverse_active_energy_sensor_ != nullptr) { + this->reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_()); + } + if (this->freq_sensor_ != nullptr) { + this->freq_sensor_->publish_state(this->get_frequency_()); + } + this->status_clear_warning(); +} + +void ATM90E26Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up ATM90E26 Component..."); + this->spi_setup(); + + uint16_t mmode = 0x422; // default values for everything but L/N line current gains + mmode |= (gain_pga_ & 0x7) << 13; + mmode |= (n_line_gain_ & 0x3) << 11; + + this->write16_(ATM90E26_REGISTER_SOFTRESET, 0x789A); // Perform soft reset + this->write16_(ATM90E26_REGISTER_FUNCEN, + 0x0030); // Voltage sag irq=1, report on warnout pin=1, energy dir change irq=0 + uint16_t read = this->read16_(ATM90E26_REGISTER_LASTDATA); + if (read != 0x0030) { + ESP_LOGW(TAG, "Could not initialize ATM90E26 IC, check SPI settings: %d", read); + this->mark_failed(); + return; + } + // TODO: 100 * * sqrt(2) * / (4 * gain_voltage/32768) + this->write16_(ATM90E26_REGISTER_SAGTH, 0x17DD); // Voltage sag threshhold 0x1F2F + + // Set metering calibration values + this->write16_(ATM90E26_REGISTER_CALSTART, 0x5678); // CAL Metering calibration startup command + + // Configure + this->write16_(ATM90E26_REGISTER_MMODE, mmode); // Metering Mode Configuration (see above) + + this->write16_(ATM90E26_REGISTER_PLCONSTH, (pl_const_ >> 16)); // PL Constant MSB + this->write16_(ATM90E26_REGISTER_PLCONSTL, pl_const_ & 0xFFFF); // PL Constant LSB + + // Calibrate this to be 1 pulse per Wh + this->write16_(ATM90E26_REGISTER_LGAIN, gain_metering_); // L Line Calibration Gain (active power metering) + this->write16_(ATM90E26_REGISTER_LPHI, 0x0000); // L Line Calibration Angle + this->write16_(ATM90E26_REGISTER_NGAIN, 0x0000); // N Line Calibration Gain + this->write16_(ATM90E26_REGISTER_NPHI, 0x0000); // N Line Calibration Angle + this->write16_(ATM90E26_REGISTER_PSTARTTH, 0x08BD); // Active Startup Power Threshold (default) = 2237 + this->write16_(ATM90E26_REGISTER_PNOLTH, 0x0000); // Active No-Load Power Threshold + this->write16_(ATM90E26_REGISTER_QSTARTTH, 0x0AEC); // Reactive Startup Power Threshold (default) = 2796 + this->write16_(ATM90E26_REGISTER_QNOLTH, 0x0000); // Reactive No-Load Power Threshold + + // Compute Checksum for the registers we set above + // low byte = sum of all bytes + uint16_t cs = + ((mmode >> 8) + (mmode & 0xFF) + (pl_const_ >> 24) + ((pl_const_ >> 16) & 0xFF) + ((pl_const_ >> 8) & 0xFF) + + (pl_const_ & 0xFF) + (gain_metering_ >> 8) + (gain_metering_ & 0xFF) + 0x08 + 0xBD + 0x0A + 0xEC) & + 0xFF; + // high byte = XOR of all bytes + cs |= ((mmode >> 8) ^ (mmode & 0xFF) ^ (pl_const_ >> 24) ^ ((pl_const_ >> 16) & 0xFF) ^ ((pl_const_ >> 8) & 0xFF) ^ + (pl_const_ & 0xFF) ^ (gain_metering_ >> 8) ^ (gain_metering_ & 0xFF) ^ 0x08 ^ 0xBD ^ 0x0A ^ 0xEC) + << 8; + + this->write16_(ATM90E26_REGISTER_CS1, cs); + ESP_LOGVV(TAG, "Set CS1 to: 0x%04X", cs); + + // Set measurement calibration values + this->write16_(ATM90E26_REGISTER_ADJSTART, 0x5678); // Measurement calibration startup command, registers 31-3A + this->write16_(ATM90E26_REGISTER_UGAIN, gain_voltage_); // Voltage RMS gain + this->write16_(ATM90E26_REGISTER_IGAINL, gain_ct_); // L line current RMS gain + this->write16_(ATM90E26_REGISTER_IGAINN, 0x7530); // N Line Current RMS Gain + this->write16_(ATM90E26_REGISTER_UOFFSET, 0x0000); // Voltage Offset + this->write16_(ATM90E26_REGISTER_IOFFSETL, 0x0000); // L Line Current Offset + this->write16_(ATM90E26_REGISTER_IOFFSETN, 0x0000); // N Line Current Offse + this->write16_(ATM90E26_REGISTER_POFFSETL, 0x0000); // L Line Active Power Offset + this->write16_(ATM90E26_REGISTER_QOFFSETL, 0x0000); // L Line Reactive Power Offset + this->write16_(ATM90E26_REGISTER_POFFSETN, 0x0000); // N Line Active Power Offset + this->write16_(ATM90E26_REGISTER_QOFFSETN, 0x0000); // N Line Reactive Power Offset + + // Compute Checksum for the registers we set above + cs = ((gain_voltage_ >> 8) + (gain_voltage_ & 0xFF) + (gain_ct_ >> 8) + (gain_ct_ & 0xFF) + 0x75 + 0x30) & 0xFF; + cs |= ((gain_voltage_ >> 8) ^ (gain_voltage_ & 0xFF) ^ (gain_ct_ >> 8) ^ (gain_ct_ & 0xFF) ^ 0x75 ^ 0x30) << 8; + this->write16_(ATM90E26_REGISTER_CS2, cs); + ESP_LOGVV(TAG, "Set CS2 to: 0x%04X", cs); + + this->write16_(ATM90E26_REGISTER_CALSTART, + 0x8765); // Checks correctness of 21-2B registers and starts normal metering if ok + this->write16_(ATM90E26_REGISTER_ADJSTART, + 0x8765); // Checks correctness of 31-3A registers and starts normal measurement if ok + + uint16_t sys_status = this->read16_(ATM90E26_REGISTER_SYSSTATUS); + if (sys_status & 0xC000) { // Checksum 1 Error + + ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS1 was incorrect, expected: 0x%04X", + this->read16_(ATM90E26_REGISTER_CS1)); + this->mark_failed(); + } + if (sys_status & 0x3000) { // Checksum 2 Error + ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS2 was incorrect, expected: 0x%04X", + this->read16_(ATM90E26_REGISTER_CS2)); + this->mark_failed(); + } +} + +void ATM90E26Component::dump_config() { + ESP_LOGCONFIG("", "ATM90E26:"); + LOG_PIN(" CS Pin: ", this->cs_); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with ATM90E26 failed!"); + } + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Voltage A", this->voltage_sensor_); + LOG_SENSOR(" ", "Current A", this->current_sensor_); + LOG_SENSOR(" ", "Power A", this->power_sensor_); + LOG_SENSOR(" ", "Reactive Power A", this->reactive_power_sensor_); + LOG_SENSOR(" ", "PF A", this->power_factor_sensor_); + LOG_SENSOR(" ", "Active Forward Energy A", this->forward_active_energy_sensor_); + LOG_SENSOR(" ", "Active Reverse Energy A", this->reverse_active_energy_sensor_); + LOG_SENSOR(" ", "Frequency", this->freq_sensor_); +} +float ATM90E26Component::get_setup_priority() const { return setup_priority::DATA; } + +uint16_t ATM90E26Component::read16_(uint8_t a_register) { + uint8_t data[2]; + uint16_t output; + + this->enable(); + delayMicroseconds(4); + this->write_byte(a_register | 0x80); + delayMicroseconds(4); + this->read_array(data, 2); + this->disable(); + + output = (uint16_t(data[0] & 0xFF) << 8) | (data[1] & 0xFF); + ESP_LOGVV(TAG, "read16_ 0x%04X output 0x%04X", a_register, output); + return output; +} + +void ATM90E26Component::write16_(uint8_t a_register, uint16_t val) { + ESP_LOGVV(TAG, "write16_ 0x%04X val 0x%04X", a_register, val); + this->enable(); + delayMicroseconds(4); + this->write_byte(a_register & 0x7F); + delayMicroseconds(4); + this->write_byte((val >> 8) & 0xFF); + this->write_byte(val & 0xFF); + this->disable(); +} + +float ATM90E26Component::get_line_current_() { + uint16_t current = this->read16_(ATM90E26_REGISTER_IRMS); + return current / 1000.0f; +} + +float ATM90E26Component::get_line_voltage_() { + uint16_t voltage = this->read16_(ATM90E26_REGISTER_URMS); + return voltage / 100.0f; +} + +float ATM90E26Component::get_active_power_() { + int16_t val = this->read16_(ATM90E26_REGISTER_PMEAN); // two's complement + return (float) val; +} + +float ATM90E26Component::get_reactive_power_() { + int16_t val = this->read16_(ATM90E26_REGISTER_QMEAN); // two's complement + return (float) val; +} + +float ATM90E26Component::get_power_factor_() { + uint16_t val = this->read16_(ATM90E26_REGISTER_POWERF); // signed + if (val & 0x8000) { + return -(val & 0x7FF) / 1000.0f; + } else { + return val / 1000.0f; + } +} + +float ATM90E26Component::get_forward_active_energy_() { + uint16_t val = this->read16_(ATM90E26_REGISTER_APENERGY); + if ((UINT32_MAX - this->cumulative_forward_active_energy_) > val) { + this->cumulative_forward_active_energy_ += val; + } else { + this->cumulative_forward_active_energy_ = val; + } + // The register holds thenths of pulses, we want to output Wh + return (this->cumulative_forward_active_energy_ * 100.0f / meter_constant_); +} + +float ATM90E26Component::get_reverse_active_energy_() { + uint16_t val = this->read16_(ATM90E26_REGISTER_ANENERGY); + if (UINT32_MAX - this->cumulative_reverse_active_energy_ > val) { + this->cumulative_reverse_active_energy_ += val; + } else { + this->cumulative_reverse_active_energy_ = val; + } + return (this->cumulative_reverse_active_energy_ * 100.0f / meter_constant_); +} + +float ATM90E26Component::get_frequency_() { + uint16_t freq = this->read16_(ATM90E26_REGISTER_FREQ); + return freq / 100.0f; +} + +} // namespace atm90e26 +} // namespace esphome diff --git a/esphome/components/atm90e26/atm90e26.h b/esphome/components/atm90e26/atm90e26.h new file mode 100644 index 0000000000..3c098d7e91 --- /dev/null +++ b/esphome/components/atm90e26/atm90e26.h @@ -0,0 +1,72 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace atm90e26 { + +class ATM90E26Component : public PollingComponent, + public spi::SPIDevice { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + + void set_voltage_sensor(sensor::Sensor *obj) { this->voltage_sensor_ = obj; } + void set_current_sensor(sensor::Sensor *obj) { this->current_sensor_ = obj; } + void set_power_sensor(sensor::Sensor *obj) { this->power_sensor_ = obj; } + void set_reactive_power_sensor(sensor::Sensor *obj) { this->reactive_power_sensor_ = obj; } + void set_forward_active_energy_sensor(sensor::Sensor *obj) { this->forward_active_energy_sensor_ = obj; } + void set_reverse_active_energy_sensor(sensor::Sensor *obj) { this->reverse_active_energy_sensor_ = obj; } + void set_power_factor_sensor(sensor::Sensor *obj) { this->power_factor_sensor_ = obj; } + void set_freq_sensor(sensor::Sensor *freq_sensor) { freq_sensor_ = freq_sensor; } + void set_line_freq(int freq) { line_freq_ = freq; } + void set_meter_constant(float val) { meter_constant_ = val; } + void set_pl_const(uint32_t pl_const) { pl_const_ = pl_const; } + void set_gain_metering(uint16_t gain) { this->gain_metering_ = gain; } + void set_gain_voltage(uint16_t gain) { this->gain_voltage_ = gain; } + void set_gain_ct(uint16_t gain) { this->gain_ct_ = gain; } + void set_gain_pga(uint16_t gain) { gain_pga_ = gain; } + void set_n_line_gain(uint16_t gain) { n_line_gain_ = gain; } + + protected: + uint16_t read16_(uint8_t a_register); + int read32_(uint8_t addr_h, uint8_t addr_l); + void write16_(uint8_t a_register, uint16_t val); + + float get_line_voltage_(); + float get_line_current_(); + float get_active_power_(); + float get_reactive_power_(); + float get_power_factor_(); + float get_forward_active_energy_(); + float get_reverse_active_energy_(); + float get_frequency_(); + float get_chip_temperature_(); + + sensor::Sensor *freq_sensor_{nullptr}; + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *power_sensor_{nullptr}; + sensor::Sensor *reactive_power_sensor_{nullptr}; + sensor::Sensor *power_factor_sensor_{nullptr}; + sensor::Sensor *forward_active_energy_sensor_{nullptr}; + sensor::Sensor *reverse_active_energy_sensor_{nullptr}; + uint32_t cumulative_forward_active_energy_{0}; + uint32_t cumulative_reverse_active_energy_{0}; + uint16_t gain_metering_{7481}; + uint16_t gain_voltage_{26400}; + uint16_t gain_ct_{31251}; + uint16_t gain_pga_{0x4}; + uint16_t n_line_gain_{0x2}; + int line_freq_{60}; + float meter_constant_{3200.0f}; + uint32_t pl_const_{1429876}; +}; + +} // namespace atm90e26 +} // namespace esphome diff --git a/esphome/components/atm90e26/atm90e26_reg.h b/esphome/components/atm90e26/atm90e26_reg.h new file mode 100644 index 0000000000..0a925f424e --- /dev/null +++ b/esphome/components/atm90e26/atm90e26_reg.h @@ -0,0 +1,70 @@ +#pragma once + +namespace esphome { +namespace atm90e26 { + +/* Status and Special Register */ +static const uint8_t ATM90E26_REGISTER_SOFTRESET = 0x00; // Software Reset +static const uint8_t ATM90E26_REGISTER_SYSSTATUS = 0x01; // System Status +static const uint8_t ATM90E26_REGISTER_FUNCEN = 0x02; // Function Enable +static const uint8_t ATM90E26_REGISTER_SAGTH = 0x03; // Voltage Sag Threshold +static const uint8_t ATM90E26_REGISTER_SMALLPMOD = 0x04; // Small-Power Mode +static const uint8_t ATM90E26_REGISTER_LASTDATA = 0x06; // Last Read/Write SPI/UART Value + +/* Metering Calibration and Configuration Register */ +static const uint8_t ATM90E26_REGISTER_LSB = 0x08; // RMS/Power 16-bit LSB +static const uint8_t ATM90E26_REGISTER_CALSTART = 0x20; // Calibration Start Command +static const uint8_t ATM90E26_REGISTER_PLCONSTH = 0x21; // High Word of PL_Constant +static const uint8_t ATM90E26_REGISTER_PLCONSTL = 0x22; // Low Word of PL_Constant +static const uint8_t ATM90E26_REGISTER_LGAIN = 0x23; // L Line Calibration Gain +static const uint8_t ATM90E26_REGISTER_LPHI = 0x24; // L Line Calibration Angle +static const uint8_t ATM90E26_REGISTER_NGAIN = 0x25; // N Line Calibration Gain +static const uint8_t ATM90E26_REGISTER_NPHI = 0x26; // N Line Calibration Angle +static const uint8_t ATM90E26_REGISTER_PSTARTTH = 0x27; // Active Startup Power Threshold +static const uint8_t ATM90E26_REGISTER_PNOLTH = 0x28; // Active No-Load Power Threshold +static const uint8_t ATM90E26_REGISTER_QSTARTTH = 0x29; // Reactive Startup Power Threshold +static const uint8_t ATM90E26_REGISTER_QNOLTH = 0x2A; // Reactive No-Load Power Threshold +static const uint8_t ATM90E26_REGISTER_MMODE = 0x2B; // Metering Mode Configuration +static const uint8_t ATM90E26_REGISTER_CS1 = 0x2C; // Checksum 1 + +/* Measurement Calibration Register */ +static const uint8_t ATM90E26_REGISTER_ADJSTART = 0x30; // Measurement Calibration Start Command +static const uint8_t ATM90E26_REGISTER_UGAIN = 0x31; // Voltage RMS Gain +static const uint8_t ATM90E26_REGISTER_IGAINL = 0x32; // L Line Current RMS Gain +static const uint8_t ATM90E26_REGISTER_IGAINN = 0x33; // N Line Current RMS Gain +static const uint8_t ATM90E26_REGISTER_UOFFSET = 0x34; // Voltage Offset +static const uint8_t ATM90E26_REGISTER_IOFFSETL = 0x35; // L Line Current Offset +static const uint8_t ATM90E26_REGISTER_IOFFSETN = 0x36; // N Line Current Offse +static const uint8_t ATM90E26_REGISTER_POFFSETL = 0x37; // L Line Active Power Offset +static const uint8_t ATM90E26_REGISTER_QOFFSETL = 0x38; // L Line Reactive Power Offset +static const uint8_t ATM90E26_REGISTER_POFFSETN = 0x39; // N Line Active Power Offset +static const uint8_t ATM90E26_REGISTER_QOFFSETN = 0x3A; // N Line Reactive Power Offset +static const uint8_t ATM90E26_REGISTER_CS2 = 0x3B; // Checksum 2 + +/* Energy Register */ +static const uint8_t ATM90E26_REGISTER_APENERGY = 0x40; // Forward Active Energy +static const uint8_t ATM90E26_REGISTER_ANENERGY = 0x41; // Reverse Active Energy +static const uint8_t ATM90E26_REGISTER_ATENERGY = 0x42; // Absolute Active Energy +static const uint8_t ATM90E26_REGISTER_RPENERGY = 0x43; // Forward (Inductive) Reactive Energy +static const uint8_t ATM90E26_REGISTER_RNENERG = 0x44; // Reverse (Capacitive) Reactive Energy +static const uint8_t ATM90E26_REGISTER_RTENERGY = 0x45; // Absolute Reactive Energy +static const uint8_t ATM90E26_REGISTER_ENSTATUS = 0x46; // Metering Status + +/* Measurement Register */ +static const uint8_t ATM90E26_REGISTER_IRMS = 0x48; // L Line Current RMS +static const uint8_t ATM90E26_REGISTER_URMS = 0x49; // Voltage RMS +static const uint8_t ATM90E26_REGISTER_PMEAN = 0x4A; // L Line Mean Active Power +static const uint8_t ATM90E26_REGISTER_QMEAN = 0x4B; // L Line Mean Reactive Power +static const uint8_t ATM90E26_REGISTER_FREQ = 0x4C; // Voltage Frequency +static const uint8_t ATM90E26_REGISTER_POWERF = 0x4D; // L Line Power Factor +static const uint8_t ATM90E26_REGISTER_PANGLE = 0x4E; // Phase Angle between Voltage and L Line Current +static const uint8_t ATM90E26_REGISTER_SMEAN = 0x4F; // L Line Mean Apparent Power +static const uint8_t ATM90E26_REGISTER_IRMS2 = 0x68; // N Line Current rms +static const uint8_t ATM90E26_REGISTER_PMEAN2 = 0x6A; // N Line Mean Active Power +static const uint8_t ATM90E26_REGISTER_QMEAN2 = 0x6B; // N Line Mean Reactive Power +static const uint8_t ATM90E26_REGISTER_POWERF2 = 0x6D; // N Line Power Factor +static const uint8_t ATM90E26_REGISTER_PANGLE2 = 0x6E; // Phase Angle between Voltage and N Line Current +static const uint8_t ATM90E26_REGISTER_SMEAN2 = 0x6F; // N Line Mean Apparent Power + +} // namespace atm90e26 +} // namespace esphome diff --git a/esphome/components/atm90e26/sensor.py b/esphome/components/atm90e26/sensor.py new file mode 100644 index 0000000000..a0d97ab5ae --- /dev/null +++ b/esphome/components/atm90e26/sensor.py @@ -0,0 +1,157 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, spi +from esphome.const import ( + CONF_ID, + CONF_REACTIVE_POWER, + CONF_VOLTAGE, + CONF_CURRENT, + CONF_POWER, + CONF_POWER_FACTOR, + CONF_FREQUENCY, + CONF_FORWARD_ACTIVE_ENERGY, + CONF_REVERSE_ACTIVE_ENERGY, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_POWER_FACTOR, + DEVICE_CLASS_VOLTAGE, + ICON_LIGHTBULB, + ICON_CURRENT_AC, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + UNIT_HERTZ, + UNIT_VOLT, + UNIT_AMPERE, + UNIT_WATT, + UNIT_VOLT_AMPS_REACTIVE, + UNIT_WATT_HOURS, +) + +CONF_LINE_FREQUENCY = "line_frequency" +CONF_METER_CONSTANT = "meter_constant" +CONF_PL_CONST = "pl_const" +CONF_GAIN_PGA = "gain_pga" +CONF_GAIN_METERING = "gain_metering" +CONF_GAIN_VOLTAGE = "gain_voltage" +CONF_GAIN_CT = "gain_ct" +LINE_FREQS = { + "50HZ": 50, + "60HZ": 60, +} +PGA_GAINS = { + "1X": 0x4, + "4X": 0x0, + "8X": 0x1, + "16X": 0x2, + "24X": 0x3, +} + +atm90e26_ns = cg.esphome_ns.namespace("atm90e26") +ATM90E26Component = atm90e26_ns.class_( + "ATM90E26Component", cg.PollingComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ATM90E26Component), + cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=2, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CURRENT): sensor.sensor_schema( + unit_of_measurement=UNIT_AMPERE, + accuracy_decimals=2, + device_class=DEVICE_CLASS_CURRENT, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + accuracy_decimals=2, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE, + icon=ICON_LIGHTBULB, + accuracy_decimals=2, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema( + accuracy_decimals=2, + device_class=DEVICE_CLASS_POWER_FACTOR, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT_HOURS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), + cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT_HOURS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), + cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( + unit_of_measurement=UNIT_HERTZ, + icon=ICON_CURRENT_AC, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True), + cv.Required(CONF_METER_CONSTANT): cv.positive_float, + cv.Optional(CONF_PL_CONST, default=1429876): cv.uint32_t, + cv.Optional(CONF_GAIN_METERING, default=7481): cv.uint16_t, + cv.Optional(CONF_GAIN_VOLTAGE, default=26400): cv.int_range( + min=0, max=32767 + ), + cv.Optional(CONF_GAIN_CT, default=31251): cv.uint16_t, + cv.Optional(CONF_GAIN_PGA, default="1X"): cv.enum(PGA_GAINS, upper=True), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(spi.spi_device_schema()) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + + if CONF_VOLTAGE in config: + sens = await sensor.new_sensor(config[CONF_VOLTAGE]) + cg.add(var.set_voltage_sensor(sens)) + if CONF_CURRENT in config: + sens = await sensor.new_sensor(config[CONF_CURRENT]) + cg.add(var.set_current_sensor(sens)) + if CONF_POWER in config: + sens = await sensor.new_sensor(config[CONF_POWER]) + cg.add(var.set_power_sensor(sens)) + if CONF_REACTIVE_POWER in config: + sens = await sensor.new_sensor(config[CONF_REACTIVE_POWER]) + cg.add(var.set_reactive_power_sensor(sens)) + if CONF_POWER_FACTOR in config: + sens = await sensor.new_sensor(config[CONF_POWER_FACTOR]) + cg.add(var.set_power_factor_sensor(sens)) + if CONF_FORWARD_ACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_FORWARD_ACTIVE_ENERGY]) + cg.add(var.set_forward_active_energy_sensor(sens)) + if CONF_REVERSE_ACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_REVERSE_ACTIVE_ENERGY]) + cg.add(var.set_reverse_active_energy_sensor(sens)) + if CONF_FREQUENCY in config: + sens = await sensor.new_sensor(config[CONF_FREQUENCY]) + cg.add(var.set_freq_sensor(sens)) + cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) + cg.add(var.set_meter_constant(config[CONF_METER_CONSTANT])) + cg.add(var.set_pl_const(config[CONF_PL_CONST])) + cg.add(var.set_gain_metering(config[CONF_GAIN_METERING])) + cg.add(var.set_gain_voltage(config[CONF_GAIN_VOLTAGE])) + cg.add(var.set_gain_ct(config[CONF_GAIN_CT])) + cg.add(var.set_gain_pga(config[CONF_GAIN_PGA])) diff --git a/tests/test1.yaml b/tests/test1.yaml index 9d279b5e40..d0c9801933 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -483,6 +483,25 @@ sensor: nir: name: NIR i2c_id: i2c_bus + - platform: atm90e26 + cs_pin: 5 + voltage: + name: Line Voltage + current: + name: CT Amps + power: + name: Active Watts + power_factor: + name: Power Factor + frequency: + name: Line Frequency + line_frequency: 50Hz + meter_constant: 1000 + pl_const: 1429876 + gain_pga: 1X + gain_metering: 7481 + gain_voltage: 26400 + gain_ct: 31251 - platform: atm90e32 cs_pin: 5 phase_a: From 119bbba2549cb5574e1bb17ae87bec3be8075d0a Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 12 Jul 2023 21:13:50 +0100 Subject: [PATCH 0219/2607] Grove amend name (#5093) --- CODEOWNERS | 2 +- .../__init__.py | 34 +++++++++---------- .../grove_tb6612fng.cpp} | 6 ++-- .../grove_tb6612fng.h} | 4 +-- tests/test3.1.yaml | 4 +-- 5 files changed, 25 insertions(+), 25 deletions(-) rename esphome/components/{grove_i2c_motor => grove_tb6612fng}/__init__.py (80%) rename esphome/components/{grove_i2c_motor/grove_i2c_motor.cpp => grove_tb6612fng/grove_tb6612fng.cpp} (98%) rename esphome/components/{grove_i2c_motor/grove_i2c_motor.h => grove_tb6612fng/grove_tb6612fng.h} (99%) diff --git a/CODEOWNERS b/CODEOWNERS index f5dc9a17f4..cce94d4ccb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -104,7 +104,7 @@ esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core esphome/components/gps/* @coogle esphome/components/graph/* @synco -esphome/components/grove_i2c_motor/* @max246 +esphome/components/grove_tb6612fng/* @max246 esphome/components/growatt_solar/* @leeuwte esphome/components/haier/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal diff --git a/esphome/components/grove_i2c_motor/__init__.py b/esphome/components/grove_tb6612fng/__init__.py similarity index 80% rename from esphome/components/grove_i2c_motor/__init__.py rename to esphome/components/grove_tb6612fng/__init__.py index f7888f7293..75610ce9d3 100644 --- a/esphome/components/grove_i2c_motor/__init__.py +++ b/esphome/components/grove_tb6612fng/__init__.py @@ -14,23 +14,23 @@ DEPENDENCIES = ["i2c"] CODEOWNERS = ["@max246"] -grove_i2c_motor_ns = cg.esphome_ns.namespace("grove_i2c_motor") -GROVE_TB6612FNG = grove_i2c_motor_ns.class_( +grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng") +GROVE_TB6612FNG = grove_tb6612fng_ns.class_( "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice ) -GROVETB6612FNGMotorRunAction = grove_i2c_motor_ns.class_( +GROVETB6612FNGMotorRunAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorRunAction", automation.Action ) -GROVETB6612FNGMotorBrakeAction = grove_i2c_motor_ns.class_( +GROVETB6612FNGMotorBrakeAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorBrakeAction", automation.Action ) -GROVETB6612FNGMotorStopAction = grove_i2c_motor_ns.class_( +GROVETB6612FNGMotorStopAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorStopAction", automation.Action ) -GROVETB6612FNGMotorStandbyAction = grove_i2c_motor_ns.class_( +GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorStandbyAction", automation.Action ) -GROVETB6612FNGMotorNoStandbyAction = grove_i2c_motor_ns.class_( +GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorNoStandbyAction", automation.Action ) @@ -57,7 +57,7 @@ async def to_code(config): @automation.register_action( - "grove_i2c_motor.run", + "grove_tb6612fng.run", GROVETB6612FNGMotorRunAction, cv.Schema( { @@ -68,7 +68,7 @@ async def to_code(config): } ), ) -async def grove_i2c_motor_run_to_code(config, action_id, template_arg, args): +async def grove_tb6612fng_run_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) @@ -83,7 +83,7 @@ async def grove_i2c_motor_run_to_code(config, action_id, template_arg, args): @automation.register_action( - "grove_i2c_motor.break", + "grove_tb6612fng.break", GROVETB6612FNGMotorBrakeAction, cv.Schema( { @@ -92,7 +92,7 @@ async def grove_i2c_motor_run_to_code(config, action_id, template_arg, args): } ), ) -async def grove_i2c_motor_break_to_code(config, action_id, template_arg, args): +async def grove_tb6612fng_break_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) @@ -102,7 +102,7 @@ async def grove_i2c_motor_break_to_code(config, action_id, template_arg, args): @automation.register_action( - "grove_i2c_motor.stop", + "grove_tb6612fng.stop", GROVETB6612FNGMotorStopAction, cv.Schema( { @@ -111,7 +111,7 @@ async def grove_i2c_motor_break_to_code(config, action_id, template_arg, args): } ), ) -async def grove_i2c_motor_stop_to_code(config, action_id, template_arg, args): +async def grove_tb6612fng_stop_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) @@ -121,7 +121,7 @@ async def grove_i2c_motor_stop_to_code(config, action_id, template_arg, args): @automation.register_action( - "grove_i2c_motor.standby", + "grove_tb6612fng.standby", GROVETB6612FNGMotorStandbyAction, cv.Schema( { @@ -129,7 +129,7 @@ async def grove_i2c_motor_stop_to_code(config, action_id, template_arg, args): } ), ) -async def grove_i2c_motor_standby_to_code(config, action_id, template_arg, args): +async def grove_tb6612fng_standby_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) @@ -137,7 +137,7 @@ async def grove_i2c_motor_standby_to_code(config, action_id, template_arg, args) @automation.register_action( - "grove_i2c_motor.no_standby", + "grove_tb6612fng.no_standby", GROVETB6612FNGMotorNoStandbyAction, cv.Schema( { @@ -145,7 +145,7 @@ async def grove_i2c_motor_standby_to_code(config, action_id, template_arg, args) } ), ) -async def grove_i2c_motor_no_standby_to_code(config, action_id, template_arg, args): +async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) diff --git a/esphome/components/grove_i2c_motor/grove_i2c_motor.cpp b/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp similarity index 98% rename from esphome/components/grove_i2c_motor/grove_i2c_motor.cpp rename to esphome/components/grove_tb6612fng/grove_tb6612fng.cpp index 669114aec0..621b7968a4 100644 --- a/esphome/components/grove_i2c_motor/grove_i2c_motor.cpp +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp @@ -1,9 +1,9 @@ -#include "grove_i2c_motor.h" +#include "grove_tb6612fng.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" namespace esphome { -namespace grove_i2c_motor { +namespace grove_tb6612fng { static const char *const TAG = "GroveMotorDriveTB6612FNG"; @@ -167,5 +167,5 @@ void GroveMotorDriveTB6612FNG::stepper_keep_run(StepperModeTypeT mode, uint16_t return; } } -} // namespace grove_i2c_motor +} // namespace grove_tb6612fng } // namespace esphome diff --git a/esphome/components/grove_i2c_motor/grove_i2c_motor.h b/esphome/components/grove_tb6612fng/grove_tb6612fng.h similarity index 99% rename from esphome/components/grove_i2c_motor/grove_i2c_motor.h rename to esphome/components/grove_tb6612fng/grove_tb6612fng.h index 8a0db77e70..ccdab6472a 100644 --- a/esphome/components/grove_i2c_motor/grove_i2c_motor.h +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.h @@ -34,7 +34,7 @@ */ namespace esphome { -namespace grove_i2c_motor { +namespace grove_tb6612fng { enum MotorChannelTypeT { MOTOR_CHA = 0, @@ -204,5 +204,5 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action, public Parented void play(Ts... x) override { this->parent_->not_standby(); } }; -} // namespace grove_i2c_motor +} // namespace grove_tb6612fng } // namespace esphome diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index a003c804c9..5f1d3ff28f 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -303,7 +303,7 @@ sm2135: rgb_current: 20mA cw_current: 60mA -grove_i2c_motor: +grove_tb6612fng: id: test_motor address: 0x14 @@ -363,7 +363,7 @@ switch: optimistic: True on_turn_on: then: - - grove_i2c_motor.run: + - grove_tb6612fng.run: channel: 1 speed: 255 direction: BACKWARD From e4a640844ccdf9f9df6aff8adbfdd022a947699a Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Wed, 12 Jul 2023 22:24:49 +0200 Subject: [PATCH 0220/2607] Fixing colon for tm1637 display if inverted set true (#5072) --- esphome/components/tm1637/tm1637.cpp | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 434c6e65f3..8d7630bd1d 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -300,6 +300,7 @@ uint8_t TM1637Display::read_byte_() { uint8_t TM1637Display::print(uint8_t start_pos, const char *str) { // ESP_LOGV(TAG, "Print at %d: %s", start_pos, str); uint8_t pos = start_pos; + bool use_dot = false; for (; *str != '\0'; str++) { uint8_t data = TM1637_UNKNOWN_CHAR; if (*str >= ' ' && *str <= '~') @@ -312,14 +313,14 @@ uint8_t TM1637Display::print(uint8_t start_pos, const char *str) { // XABCDEFG, but TM1637 is // XGFEDCBA if (this->inverted_) { // XABCDEFG > XGCBAFED - data = ((data & 0x80) ? 0x80 : 0) | // no move X - ((data & 0x40) ? 0x8 : 0) | // A - ((data & 0x20) ? 0x10 : 0) | // B - ((data & 0x10) ? 0x20 : 0) | // C - ((data & 0x8) ? 0x1 : 0) | // D - ((data & 0x4) ? 0x2 : 0) | // E - ((data & 0x2) ? 0x4 : 0) | // F - ((data & 0x1) ? 0x40 : 0); // G + data = ((data & 0x80) || use_dot ? 0x80 : 0) | // no move X + ((data & 0x40) ? 0x8 : 0) | // A + ((data & 0x20) ? 0x10 : 0) | // B + ((data & 0x10) ? 0x20 : 0) | // C + ((data & 0x8) ? 0x1 : 0) | // D + ((data & 0x4) ? 0x2 : 0) | // E + ((data & 0x2) ? 0x4 : 0) | // F + ((data & 0x1) ? 0x40 : 0); // G } else { // XABCDEFG > XGFEDCBA data = ((data & 0x80) ? 0x80 : 0) | // no move X @@ -331,18 +332,18 @@ uint8_t TM1637Display::print(uint8_t start_pos, const char *str) { ((data & 0x2) ? 0x20 : 0) | // F ((data & 0x1) ? 0x40 : 0); // G } - if (*str == '.') { - if (pos != start_pos) - pos--; - this->buffer_[pos] |= 0b10000000; + use_dot = *str == '.'; + if (use_dot) { + if ((!this->inverted_) && (pos != start_pos)) { + this->buffer_[pos - 1] |= 0b10000000; + } } else { if (pos >= 6) { ESP_LOGE(TAG, "String is too long for the display!"); break; } - this->buffer_[pos] = data; + this->buffer_[pos++] = data; } - pos++; } return pos - start_pos; } From eb859e83f82b48fc2ed311f889dcb90164373e40 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 13 Jul 2023 00:44:30 +0400 Subject: [PATCH 0221/2607] Fix use of optional (#5091) --- .../template/binary_sensor/template_binary_sensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.cpp b/esphome/components/template/binary_sensor/template_binary_sensor.cpp index fce11f63d6..5ce8894a8a 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.cpp +++ b/esphome/components/template/binary_sensor/template_binary_sensor.cpp @@ -11,7 +11,7 @@ void TemplateBinarySensor::setup() { return; if (this->f_ != nullptr) { - this->publish_initial_state(*this->f_()); + this->publish_initial_state(this->f_().value_or(false)); } else { this->publish_initial_state(false); } From a539197bc475e52146597298b7446878a61e9312 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 13 Jul 2023 00:48:16 +0400 Subject: [PATCH 0222/2607] New 'Duty Time' sensor component (#5069) --- CODEOWNERS | 1 + esphome/components/duty_time/__init__.py | 1 + .../components/duty_time/duty_time_sensor.cpp | 103 +++++++++++++++ .../components/duty_time/duty_time_sensor.h | 88 +++++++++++++ esphome/components/duty_time/sensor.py | 121 ++++++++++++++++++ tests/test2.yaml | 23 ++++ 6 files changed, 337 insertions(+) create mode 100644 esphome/components/duty_time/__init__.py create mode 100644 esphome/components/duty_time/duty_time_sensor.cpp create mode 100644 esphome/components/duty_time/duty_time_sensor.h create mode 100644 esphome/components/duty_time/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index cce94d4ccb..122dc71b48 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -78,6 +78,7 @@ esphome/components/display_menu_base/* @numo68 esphome/components/dps310/* @kbx81 esphome/components/ds1307/* @badbadc0ffee esphome/components/dsmr/* @glmnet @zuidwijk +esphome/components/duty_time/* @dudanov esphome/components/ee895/* @Stock-M esphome/components/ektf2232/* @jesserockz esphome/components/ens210/* @itn3rd77 diff --git a/esphome/components/duty_time/__init__.py b/esphome/components/duty_time/__init__.py new file mode 100644 index 0000000000..b708cee80b --- /dev/null +++ b/esphome/components/duty_time/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@dudanov"] diff --git a/esphome/components/duty_time/duty_time_sensor.cpp b/esphome/components/duty_time/duty_time_sensor.cpp new file mode 100644 index 0000000000..045cbcceac --- /dev/null +++ b/esphome/components/duty_time/duty_time_sensor.cpp @@ -0,0 +1,103 @@ +#include "duty_time_sensor.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace duty_time_sensor { + +static const char *const TAG = "duty_time_sensor"; + +void DutyTimeSensor::set_sensor(binary_sensor::BinarySensor *const sensor) { + sensor->add_on_state_callback([this](bool state) { this->process_state_(state); }); +} + +void DutyTimeSensor::start() { + if (!this->last_state_) + this->process_state_(true); +} + +void DutyTimeSensor::stop() { + if (this->last_state_) + this->process_state_(false); +} + +void DutyTimeSensor::update() { + if (this->last_state_) + this->process_state_(true); +} + +void DutyTimeSensor::loop() { + if (this->func_ == nullptr) + return; + + const bool state = this->func_(); + + if (state != this->last_state_) + this->process_state_(state); +} + +void DutyTimeSensor::setup() { + uint32_t seconds = 0; + + if (this->restore_) { + this->pref_ = global_preferences->make_preference(this->get_object_id_hash()); + this->pref_.load(&seconds); + } + + this->set_value_(seconds); +} + +void DutyTimeSensor::set_value_(const uint32_t sec) { + this->last_time_ = 0; + if (this->last_state_) + this->last_time_ = millis(); // last time with 0 ms correction + this->publish_and_save_(sec, 0); +} + +void DutyTimeSensor::process_state_(const bool state) { + const uint32_t now = millis(); + + if (this->last_state_) { + // update or falling edge + const uint32_t tm = now - this->last_time_; + const uint32_t ms = tm % 1000; + + this->publish_and_save_(this->total_sec_ + tm / 1000, ms); + this->last_time_ = now - ms; // store time with ms correction + + if (!state) { + // falling edge + this->last_time_ = ms; // temporary store ms correction only + this->last_state_ = false; + + if (this->last_duty_time_sensor_ != nullptr) { + const uint32_t turn_on_ms = now - this->edge_time_; + this->last_duty_time_sensor_->publish_state(turn_on_ms * 1e-3f); + } + } + + } else if (state) { + // rising edge + this->last_time_ = now - this->last_time_; // store time with ms correction + this->edge_time_ = now; // store turn-on start time + this->last_state_ = true; + } +} + +void DutyTimeSensor::publish_and_save_(const uint32_t sec, const uint32_t ms) { + this->total_sec_ = sec; + this->publish_state(sec + ms * 1e-3f); + + if (this->restore_) + this->pref_.save(&sec); +} + +void DutyTimeSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Duty Time:"); + ESP_LOGCONFIG(TAG, " Update Interval: %dms", this->get_update_interval()); + ESP_LOGCONFIG(TAG, " Restore: %s", ONOFF(this->restore_)); + LOG_SENSOR(" ", "Duty Time Sensor:", this); + LOG_SENSOR(" ", "Last Duty Time Sensor:", this->last_duty_time_sensor_); +} + +} // namespace duty_time_sensor +} // namespace esphome diff --git a/esphome/components/duty_time/duty_time_sensor.h b/esphome/components/duty_time/duty_time_sensor.h new file mode 100644 index 0000000000..27fa383847 --- /dev/null +++ b/esphome/components/duty_time/duty_time_sensor.h @@ -0,0 +1,88 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace duty_time_sensor { + +class DutyTimeSensor : public sensor::Sensor, public PollingComponent { + public: + void setup() override; + void update() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + void start(); + void stop(); + bool is_running() const { return this->last_state_; } + void reset() { this->set_value_(0); } + + void set_lambda(std::function &&func) { this->func_ = func; } + void set_sensor(binary_sensor::BinarySensor *sensor); + void set_last_duty_time_sensor(sensor::Sensor *sensor) { this->last_duty_time_sensor_ = sensor; } + void set_restore(bool restore) { this->restore_ = restore; } + + protected: + void set_value_(uint32_t sec); + void process_state_(bool state); + void publish_and_save_(uint32_t sec, uint32_t ms); + + std::function func_{nullptr}; + sensor::Sensor *last_duty_time_sensor_{nullptr}; + ESPPreferenceObject pref_; + + uint32_t total_sec_; + uint32_t last_time_; + uint32_t edge_time_; + bool last_state_{false}; + bool restore_; +}; + +template class StartAction : public Action { + public: + explicit StartAction(DutyTimeSensor *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->start(); } + + protected: + DutyTimeSensor *parent_; +}; + +template class StopAction : public Action { + public: + explicit StopAction(DutyTimeSensor *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->stop(); } + + protected: + DutyTimeSensor *parent_; +}; + +template class ResetAction : public Action { + public: + explicit ResetAction(DutyTimeSensor *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->reset(); } + + protected: + DutyTimeSensor *parent_; +}; + +template class RunningCondition : public Condition { + public: + explicit RunningCondition(DutyTimeSensor *parent, bool state) : parent_(parent), state_(state) {} + + bool check(Ts... x) override { return this->parent_->is_running() == this->state_; } + + protected: + DutyTimeSensor *parent_; + bool state_; +}; + +} // namespace duty_time_sensor +} // namespace esphome diff --git a/esphome/components/duty_time/sensor.py b/esphome/components/duty_time/sensor.py new file mode 100644 index 0000000000..5f8582d481 --- /dev/null +++ b/esphome/components/duty_time/sensor.py @@ -0,0 +1,121 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.automation import ( + Action, + Condition, + maybe_simple_id, + register_action, + register_condition, +) +from esphome.components import binary_sensor, sensor +from esphome.const import ( + CONF_ID, + CONF_SENSOR, + CONF_RESTORE, + CONF_LAMBDA, + UNIT_SECOND, + STATE_CLASS_TOTAL, + STATE_CLASS_TOTAL_INCREASING, + DEVICE_CLASS_DURATION, + ENTITY_CATEGORY_DIAGNOSTIC, +) + +CONF_LAST_TIME = "last_time" + +duty_time_sensor_ns = cg.esphome_ns.namespace("duty_time_sensor") +DutyTimeSensor = duty_time_sensor_ns.class_( + "DutyTimeSensor", sensor.Sensor, cg.PollingComponent +) +StartAction = duty_time_sensor_ns.class_("StartAction", Action) +StopAction = duty_time_sensor_ns.class_("StopAction", Action) +ResetAction = duty_time_sensor_ns.class_("ResetAction", Action) +SetAction = duty_time_sensor_ns.class_("SetAction", Action) +RunningCondition = duty_time_sensor_ns.class_("RunningCondition", Condition) + + +CONFIG_SCHEMA = cv.All( + sensor.sensor_schema( + DutyTimeSensor, + unit_of_measurement=UNIT_SECOND, + icon="mdi:timer-play-outline", + accuracy_decimals=3, + state_class=STATE_CLASS_TOTAL_INCREASING, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ) + .extend( + { + cv.Optional(CONF_SENSOR): cv.use_id(binary_sensor.BinarySensor), + cv.Optional(CONF_LAMBDA): cv.lambda_, + cv.Optional(CONF_RESTORE, default=False): cv.boolean, + cv.Optional(CONF_LAST_TIME): sensor.sensor_schema( + unit_of_measurement=UNIT_SECOND, + icon="mdi:timer-marker-outline", + accuracy_decimals=3, + state_class=STATE_CLASS_TOTAL, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ) + .extend(cv.polling_component_schema("60s")), + cv.has_at_most_one_key(CONF_SENSOR, CONF_LAMBDA), +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + cg.add(var.set_restore(config[CONF_RESTORE])) + if CONF_SENSOR in config: + sens = await cg.get_variable(config[CONF_SENSOR]) + cg.add(var.set_sensor(sens)) + if CONF_LAMBDA in config: + lambda_ = await cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.bool_) + cg.add(var.set_lambda(lambda_)) + if CONF_LAST_TIME in config: + sens = await sensor.new_sensor(config[CONF_LAST_TIME]) + cg.add(var.set_last_duty_time_sensor(sens)) + + +# AUTOMATIONS + +DUTY_TIME_ID_SCHEMA = maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(DutyTimeSensor), + } +) + + +@register_action("sensor.duty_time.start", StartAction, DUTY_TIME_ID_SCHEMA) +async def sensor_runtime_start_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@register_action("sensor.duty_time.stop", StopAction, DUTY_TIME_ID_SCHEMA) +async def sensor_runtime_stop_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@register_action("sensor.duty_time.reset", ResetAction, DUTY_TIME_ID_SCHEMA) +async def sensor_runtime_reset_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@register_condition( + "sensor.duty_time.is_running", RunningCondition, DUTY_TIME_ID_SCHEMA +) +async def duty_time_is_running_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, True) + + +@register_condition( + "sensor.duty_time.is_not_running", RunningCondition, DUTY_TIME_ID_SCHEMA +) +async def duty_time_is_not_running_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, False) diff --git a/tests/test2.yaml b/tests/test2.yaml index 31fd840f5c..291dc240dc 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -416,6 +416,18 @@ sensor: name: Propane test distance battery_level: name: Propane test battery level + - platform: duty_time + id: duty_time1 + name: Test Duty Time + restore: true + last_time: + name: Test Last Duty Time Sensor + sensor: ha_hello_world_binary + - platform: duty_time + id: duty_time2 + name: Test Duty Time 2 + restore: false + lambda: "return true;" time: - platform: homeassistant @@ -423,6 +435,17 @@ time: - at: "16:00:00" then: - logger.log: It's 16:00 + - if: + condition: + - sensor.duty_time.is_running: duty_time2 + then: + - sensor.duty_time.start: duty_time1 + - if: + condition: + - sensor.duty_time.is_not_running: duty_time1 + then: + - sensor.duty_time.stop: duty_time2 + - sensor.duty_time.reset: duty_time1 esp32_touch: setup_mode: true From 9344d85414d26b5b2ff51624dfd6ceb6b8ecd01c Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Thu, 13 Jul 2023 06:27:45 +0930 Subject: [PATCH 0223/2607] Fix PIDController::in_deadband() to give correct result when error is zero (#5078) --- esphome/components/pid/pid_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/pid/pid_controller.cpp b/esphome/components/pid/pid_controller.cpp index afc2d91000..30f6038325 100644 --- a/esphome/components/pid/pid_controller.cpp +++ b/esphome/components/pid/pid_controller.cpp @@ -29,7 +29,7 @@ float PIDController::update(float setpoint, float process_value) { bool PIDController::in_deadband() { // return (fabs(error) < deadband_threshold); float err = -error_; - return ((err > 0 && err < threshold_high_) || (err < 0 && err > threshold_low_)); + return (threshold_low_ < err && err < threshold_high_); } void PIDController::calculate_proportional_term_() { From 844cf316e2410c1f92d67ab32cc549c6064ef12a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jul 2023 09:38:24 +1200 Subject: [PATCH 0224/2607] Edit error message for pillow install to add version restrictions (#5094) --- esphome/components/font/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 29150afe3f..52f877d986 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -67,13 +67,18 @@ def validate_pillow_installed(value): except ImportError as err: raise cv.Invalid( "Please install the pillow python package to use this feature. " - "(pip install pillow)" + '(pip install pillow">4.0.0,<10.0.0")' ) from err if version.parse(PIL.__version__) < version.parse("4.0.0"): raise cv.Invalid( "Please update your pillow installation to at least 4.0.x. " - "(pip install -U pillow)" + '(pip install pillow">4.0.0,<10.0.0")' + ) + if version.parse(PIL.__version__) >= version.parse("10.0.0"): + raise cv.Invalid( + "Please downgrade your pillow installation to below 10.0.0. " + '(pip install pillow">4.0.0,<10.0.0")' ) return value From 76b438f79c6d3087d162a6eaaee29048c5105bb0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jul 2023 09:50:48 +1200 Subject: [PATCH 0225/2607] Bump version to 2023.7.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 3442c392c7..e74f23e9b4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0-dev" +__version__ = "2023.7.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 306ab0c56c34792df45c11b8cf0b4cdcfe6970c8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jul 2023 09:50:48 +1200 Subject: [PATCH 0226/2607] Bump version to 2023.8.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 3442c392c7..1c4ccdf3a4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0-dev" +__version__ = "2023.8.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From ac0549578197ae4c6c7a83a53e1b17a82bcfdb61 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:19:04 +1200 Subject: [PATCH 0227/2607] Dont do mqtt ip lookup if `use_address` has ip address (#5096) * Dont do mqtt ip lookup id `use_address` is in config * Fix after actually testing =) --- esphome/__main__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index c7c83ad83b..ecf0092b05 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -32,7 +32,7 @@ from esphome.const import ( SECRETS_FILES, ) from esphome.core import CORE, EsphomeError, coroutine -from esphome.helpers import indent +from esphome.helpers import indent, is_ip_address from esphome.util import ( run_external_command, run_external_process, @@ -308,8 +308,10 @@ def upload_program(config, args, host): password = ota_conf.get(CONF_PASSWORD, "") if ( - get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED] - ) and CONF_MQTT in config: + not is_ip_address(CORE.address) + and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) + and CONF_MQTT in config + ): from esphome import mqtt host = mqtt.get_esphome_device_ip( From f8df694aa302ba0f7f935241ea8f4e76c7ddd9f1 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 13 Jul 2023 02:32:05 +0200 Subject: [PATCH 0228/2607] Mk2 to prepare color.h for idf >= 5 (#5070) --- esphome/core/color.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/esphome/core/color.h b/esphome/core/color.h index 7062a2a8c8..45b2d4c871 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -57,21 +57,6 @@ struct Color { inline bool operator!=(uint32_t colorcode) { // NOLINT return this->raw_32 != colorcode; } - - inline Color &operator=(const Color &rhs) ALWAYS_INLINE { // NOLINT - this->r = rhs.r; - this->g = rhs.g; - this->b = rhs.b; - this->w = rhs.w; - return *this; - } - inline Color &operator=(uint32_t colorcode) ALWAYS_INLINE { - this->w = (colorcode >> 24) & 0xFF; - this->r = (colorcode >> 16) & 0xFF; - this->g = (colorcode >> 8) & 0xFF; - this->b = (colorcode >> 0) & 0xFF; - return *this; - } inline uint8_t &operator[](uint8_t x) ALWAYS_INLINE { return this->raw[x]; } inline Color operator*(uint8_t scale) const ALWAYS_INLINE { return Color(esp_scale8(this->red, scale), esp_scale8(this->green, scale), esp_scale8(this->blue, scale), From 1691c13b477271c45dcb29037702bc4fcaaa7924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Sat, 15 Jul 2023 05:30:19 +0900 Subject: [PATCH 0229/2607] display: Add helper methods to `Display::clip` and `Display::clamp_x/y_` (#5003) * display: `Rect` make most of methods `const` * display: add `clip` and `clamp_x/y_` methods for clipping to `Display` --- esphome/components/display/display.cpp | 45 +++++++++++++++++++++++--- esphome/components/display/display.h | 9 +++++- esphome/components/display/rect.cpp | 6 ++-- esphome/components/display/rect.h | 12 +++---- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 410ff58de3..22454aeddb 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -269,10 +269,7 @@ void Display::do_update_() { } else if (this->writer_.has_value()) { (*this->writer_)(*this); } - // remove all not ended clipping regions - while (is_clipping()) { - end_clipping(); - } + this->clear_clipping_(); } void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) @@ -322,13 +319,51 @@ void Display::shrink_clipping(Rect add_rect) { this->clipping_rectangle_.back().shrink(add_rect); } } -Rect Display::get_clipping() { +Rect Display::get_clipping() const { if (this->clipping_rectangle_.empty()) { return Rect(); } else { return this->clipping_rectangle_.back(); } } +void Display::clear_clipping_() { this->clipping_rectangle_.clear(); } +bool Display::clip(int x, int y) { + if (x < 0 || x >= this->get_width() || y < 0 || y >= this->get_height()) + return false; + if (!this->get_clipping().inside(x, y)) + return false; + return true; +} +bool Display::clamp_x_(int x, int w, int &min_x, int &max_x) { + min_x = std::max(x, 0); + max_x = std::min(x + w, this->get_width()); + + if (!this->clipping_rectangle_.empty()) { + const auto &rect = this->clipping_rectangle_.back(); + if (!rect.is_set()) + return false; + + min_x = std::max(min_x, (int) rect.x); + max_x = std::min(max_x, (int) rect.x2()); + } + + return min_x < max_x; +} +bool Display::clamp_y_(int y, int h, int &min_y, int &max_y) { + min_y = std::max(y, 0); + max_y = std::min(y + h, this->get_height()); + + if (!this->clipping_rectangle_.empty()) { + const auto &rect = this->clipping_rectangle_.back(); + if (!rect.is_set()) + return false; + + min_y = std::max(min_y, (int) rect.y); + max_y = std::min(max_y, (int) rect.y2()); + } + + return min_y < max_y; +} DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} void DisplayPage::show() { this->parent_->show_page(this); } diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 08d8c70e0d..350fd40f26 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -472,14 +472,21 @@ class Display { * * return rect for active clipping region */ - Rect get_clipping(); + Rect get_clipping() const; bool is_clipping() const { return !this->clipping_rectangle_.empty(); } + /** Check if pixel is within region of display. + */ + bool clip(int x, int y); + protected: + bool clamp_x_(int x, int w, int &min_x, int &max_x); + bool clamp_y_(int y, int h, int &min_y, int &max_y); void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg); void do_update_(); + void clear_clipping_(); DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES}; optional writer_{}; diff --git a/esphome/components/display/rect.cpp b/esphome/components/display/rect.cpp index 6e91c86c4f..34b611191f 100644 --- a/esphome/components/display/rect.cpp +++ b/esphome/components/display/rect.cpp @@ -60,11 +60,11 @@ void Rect::shrink(Rect rect) { } } -bool Rect::equal(Rect rect) { +bool Rect::equal(Rect rect) const { return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h); } -bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT +bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) const { // NOLINT if (!this->is_set()) { return true; } @@ -75,7 +75,7 @@ bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT } } -bool Rect::inside(Rect rect, bool absolute) { +bool Rect::inside(Rect rect, bool absolute) const { if (!this->is_set() || !rect.is_set()) { return true; } diff --git a/esphome/components/display/rect.h b/esphome/components/display/rect.h index 867a9c67c7..a728ddd132 100644 --- a/esphome/components/display/rect.h +++ b/esphome/components/display/rect.h @@ -16,19 +16,19 @@ class Rect { Rect() : x(VALUE_NO_SET), y(VALUE_NO_SET), w(VALUE_NO_SET), h(VALUE_NO_SET) {} // NOLINT inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE : x(x), y(y), w(w), h(h) {} - inline int16_t x2() { return this->x + this->w; }; ///< X coordinate of corner - inline int16_t y2() { return this->y + this->h; }; ///< Y coordinate of corner + inline int16_t x2() const { return this->x + this->w; }; ///< X coordinate of corner + inline int16_t y2() const { return this->y + this->h; }; ///< Y coordinate of corner - inline bool is_set() ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } + inline bool is_set() const ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } void expand(int16_t horizontal, int16_t vertical); void extend(Rect rect); void shrink(Rect rect); - bool inside(Rect rect, bool absolute = true); - bool inside(int16_t test_x, int16_t test_y, bool absolute = true); - bool equal(Rect rect); + bool inside(Rect rect, bool absolute = true) const; + bool inside(int16_t test_x, int16_t test_y, bool absolute = true) const; + bool equal(Rect rect) const; void info(const std::string &prefix = "rect info:"); }; From 3ac0165f000265b1653a708c020a9e5074c97f91 Mon Sep 17 00:00:00 2001 From: Pierre-Alexis Ciavaldini Date: Sun, 16 Jul 2023 21:42:01 +0200 Subject: [PATCH 0230/2607] ESP32 enable ADC2 when wifi is disabled (#4381) Co-authored-by: Keith Burzinski --- esphome/components/adc/__init__.py | 59 +++++++++++++++-- esphome/components/adc/adc_sensor.cpp | 93 ++++++++++++++++++--------- esphome/components/adc/adc_sensor.h | 20 ++++-- esphome/components/adc/sensor.py | 40 ++++++++++-- 4 files changed, 166 insertions(+), 46 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index cceaa594ef..99dad68501 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -24,6 +24,7 @@ ATTENUATION_MODES = { } adc1_channel_t = cg.global_ns.enum("adc1_channel_t") +adc2_channel_t = cg.global_ns.enum("adc2_channel_t") # From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h # pin to adc1 channel mapping @@ -78,6 +79,49 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = { }, } +ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = { + # TODO: add other variants + VARIANT_ESP32: { + 4: adc2_channel_t.ADC2_CHANNEL_0, + 0: adc2_channel_t.ADC2_CHANNEL_1, + 2: adc2_channel_t.ADC2_CHANNEL_2, + 15: adc2_channel_t.ADC2_CHANNEL_3, + 13: adc2_channel_t.ADC2_CHANNEL_4, + 12: adc2_channel_t.ADC2_CHANNEL_5, + 14: adc2_channel_t.ADC2_CHANNEL_6, + 27: adc2_channel_t.ADC2_CHANNEL_7, + 25: adc2_channel_t.ADC2_CHANNEL_8, + 26: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32S2: { + 11: adc2_channel_t.ADC2_CHANNEL_0, + 12: adc2_channel_t.ADC2_CHANNEL_1, + 13: adc2_channel_t.ADC2_CHANNEL_2, + 14: adc2_channel_t.ADC2_CHANNEL_3, + 15: adc2_channel_t.ADC2_CHANNEL_4, + 16: adc2_channel_t.ADC2_CHANNEL_5, + 17: adc2_channel_t.ADC2_CHANNEL_6, + 18: adc2_channel_t.ADC2_CHANNEL_7, + 19: adc2_channel_t.ADC2_CHANNEL_8, + 20: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32S3: { + 11: adc2_channel_t.ADC2_CHANNEL_0, + 12: adc2_channel_t.ADC2_CHANNEL_1, + 13: adc2_channel_t.ADC2_CHANNEL_2, + 14: adc2_channel_t.ADC2_CHANNEL_3, + 15: adc2_channel_t.ADC2_CHANNEL_4, + 16: adc2_channel_t.ADC2_CHANNEL_5, + 17: adc2_channel_t.ADC2_CHANNEL_6, + 18: adc2_channel_t.ADC2_CHANNEL_7, + 19: adc2_channel_t.ADC2_CHANNEL_8, + 20: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32C3: { + 5: adc2_channel_t.ADC2_CHANNEL_0, + }, +} + def validate_adc_pin(value): if str(value).upper() == "VCC": @@ -89,11 +133,18 @@ def validate_adc_pin(value): if CORE.is_esp32: value = pins.internal_gpio_input_pin_number(value) variant = get_esp32_variant() - if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL: + if ( + variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL + and variant not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL + ): raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported") - if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]: + if ( + value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant] + and value not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): raise cv.Invalid(f"{variant} doesn't support ADC on this pin") + return pins.internal_gpio_input_pin_schema(value) if CORE.is_esp8266: @@ -104,7 +155,7 @@ def validate_adc_pin(value): ) if value != 17: # A0 - raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.") + raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC") return pins.gpio_pin_schema( {CONF_ANALOG: True, CONF_INPUT: True}, internal=True )(value) @@ -112,7 +163,7 @@ def validate_adc_pin(value): if CORE.is_rp2040: value = pins.internal_gpio_input_pin_number(value) if value not in (26, 27, 28, 29): - raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.") + raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC") return pins.internal_gpio_input_pin_schema(value) raise NotImplementedError diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 9bfe0f5eed..bb6a7a8c85 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -20,20 +20,20 @@ namespace adc { static const char *const TAG = "adc"; -// 13bit for S2, and 12bit for all other esp32 variants +// 13-bit for S2, 12-bit for all other ESP32 variants #ifdef USE_ESP32 static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast(ADC_WIDTH_MAX - 1); #ifndef SOC_ADC_RTC_MAX_BITWIDTH #if USE_ESP32_VARIANT_ESP32S2 -static const int SOC_ADC_RTC_MAX_BITWIDTH = 13; +static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13; #else -static const int SOC_ADC_RTC_MAX_BITWIDTH = 12; +static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12; #endif #endif -static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) -static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) +static const int32_t ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) +static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) #endif #ifdef USE_RP2040 @@ -47,14 +47,21 @@ extern "C" #endif #ifdef USE_ESP32 - adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); - if (!autorange_) { - adc1_config_channel_atten(channel_, attenuation_); + if (channel1_ != ADC1_CHANNEL_MAX) { + adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); + if (!autorange_) { + adc1_config_channel_atten(channel1_, attenuation_); + } + } else if (channel2_ != ADC2_CHANNEL_MAX) { + if (!autorange_) { + adc2_config_channel_atten(channel2_, attenuation_); + } } // load characteristics for each attenuation - for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) { - auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, + for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) { + auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; + auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref &cal_characteristics_[i]); switch (cal_value) { @@ -136,9 +143,9 @@ void ADCSensor::update() { #ifdef USE_ESP8266 float ADCSensor::sample() { #ifdef USE_ADC_SENSOR_VCC - int raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) + int32_t raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) #else - int raw = analogRead(this->pin_->get_pin()); // NOLINT + int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT #endif if (output_raw_) { return raw; @@ -150,29 +157,53 @@ float ADCSensor::sample() { #ifdef USE_ESP32 float ADCSensor::sample() { if (!autorange_) { - int raw = adc1_get_raw(channel_); + int32_t raw = -1; + if (channel1_ != ADC1_CHANNEL_MAX) { + raw = adc1_get_raw(channel1_); + } else if (channel2_ != ADC2_CHANNEL_MAX) { + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw); + } + if (raw == -1) { return NAN; } if (output_raw_) { return raw; } - uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int) attenuation_]); + uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]); return mv / 1000.0f; } - int raw11, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11); - raw11 = adc1_get_raw(channel_); - if (raw11 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6); - raw6 = adc1_get_raw(channel_); - if (raw6 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5); - raw2 = adc1_get_raw(channel_); - if (raw2 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0); - raw0 = adc1_get_raw(channel_); + int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + + if (channel1_ != ADC1_CHANNEL_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); + raw11 = adc1_get_raw(channel1_); + if (raw11 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); + raw6 = adc1_get_raw(channel1_); + if (raw6 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5); + raw2 = adc1_get_raw(channel1_); + if (raw2 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0); + raw0 = adc1_get_raw(channel1_); + } + } + } + } else if (channel2_ != ADC2_CHANNEL_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11); + if (raw11 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); + if (raw6 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2); + if (raw2 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0); + } } } } @@ -181,10 +212,10 @@ float ADCSensor::sample() { return NAN; } - uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int) ADC_ATTEN_DB_11]); - uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int) ADC_ATTEN_DB_6]); - uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]); - uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]); + uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]); + uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); + uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); + uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) uint32_t c11 = std::min(raw11, ADC_HALF); @@ -212,7 +243,7 @@ float ADCSensor::sample() { adc_select_input(pin - 26); } - int raw = adc_read(); + int32_t raw = adc_read(); if (this->is_temperature_) { adc_set_temp_sensor_enabled(false); } diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 22cddde6f8..a905177790 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -19,16 +19,23 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_ESP32 /// Set the attenuation for this pin. Only available on the ESP32. void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; } - void set_channel(adc1_channel_t channel) { channel_ = channel; } + void set_channel1(adc1_channel_t channel) { + channel1_ = channel; + channel2_ = ADC2_CHANNEL_MAX; + } + void set_channel2(adc2_channel_t channel) { + channel2_ = channel; + channel1_ = ADC1_CHANNEL_MAX; + } void set_autorange(bool autorange) { autorange_ = autorange; } #endif - /// Update adc values. + /// Update ADC values void update() override; - /// Setup ADc + /// Setup ADC void setup() override; void dump_config() override; - /// `HARDWARE_LATE` setup priority. + /// `HARDWARE_LATE` setup priority float get_setup_priority() const override; void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; } void set_output_raw(bool output_raw) { output_raw_ = output_raw; } @@ -52,9 +59,10 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_ESP32 adc_atten_t attenuation_{ADC_ATTEN_DB_0}; - adc1_channel_t channel_{}; + adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; + adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; - esp_adc_cal_characteristics_t cal_characteristics_[(int) ADC_ATTEN_MAX] = {}; + esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {}; #endif }; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 4695e96570..a0eda1d659 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -1,5 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv +from esphome.core import CORE from esphome.components import sensor, voltage_sampler from esphome.components.esp32 import get_esp32_variant from esphome.const import ( @@ -8,15 +10,15 @@ from esphome.const import ( CONF_NUMBER, CONF_PIN, CONF_RAW, + CONF_WIFI, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) -from esphome.core import CORE - from . import ( ATTENUATION_MODES, ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, + ESP32_VARIANT_ADC2_PIN_TO_CHANNEL, validate_adc_pin, ) @@ -25,7 +27,23 @@ AUTO_LOAD = ["voltage_sampler"] def validate_config(config): if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": - raise cv.Invalid("Automatic attenuation cannot be used when raw output is set.") + raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") + + return config + + +def final_validate_config(config): + if CORE.is_esp32: + variant = get_esp32_variant() + if ( + CONF_WIFI in fv.full_config.get() + and config[CONF_PIN][CONF_NUMBER] + in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): + raise cv.Invalid( + f"{variant} doesn't support ADC on this pin when Wi-Fi is configured" + ) + return config @@ -55,6 +73,8 @@ CONFIG_SCHEMA = cv.All( validate_config, ) +FINAL_VALIDATE_SCHEMA = final_validate_config + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) @@ -81,5 +101,15 @@ async def to_code(config): if CORE.is_esp32: variant = get_esp32_variant() pin_num = config[CONF_PIN][CONF_NUMBER] - chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num] - cg.add(var.set_channel(chan)) + if ( + variant in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL + and pin_num in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant] + ): + chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num] + cg.add(var.set_channel1(chan)) + elif ( + variant in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL + and pin_num in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): + chan = ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant][pin_num] + cg.add(var.set_channel2(chan)) From 508392db6e0daa3cd227cab59b38d35dc2ea4488 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Sun, 16 Jul 2023 23:28:31 +0300 Subject: [PATCH 0231/2607] [Sprinkler] Resume fixes (#5100) --- esphome/components/sprinkler/sprinkler.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 095884997c..8afafcb5ce 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -954,10 +954,18 @@ void Sprinkler::pause() { } void Sprinkler::resume() { + if (this->standby()) { + ESP_LOGD(TAG, "resume called but standby is enabled; no action taken"); + return; + } + if (this->paused_valve_.has_value() && (this->resume_duration_.has_value())) { - ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0), - this->resume_duration_.value_or(0)); - this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value()); + // Resume only if valve has not been completed yet + if (!this->valve_cycle_complete_(this->paused_valve_.value())) { + ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0), + this->resume_duration_.value_or(0)); + this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value()); + } this->reset_resume(); } else { ESP_LOGD(TAG, "No valve to resume!"); From 8c6cddf1bb58d86436539b6ec0bb33b7e4c4817c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:11:43 +1200 Subject: [PATCH 0232/2607] Remove template switch restore_state (#5106) --- esphome/components/template/switch/__init__.py | 5 +++-- esphome/components/template/switch/template_switch.cpp | 5 ----- esphome/components/template/switch/template_switch.h | 2 -- tests/test1.yaml | 2 -- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py index e002c4e3d8..a221cbaa60 100644 --- a/esphome/components/template/switch/__init__.py +++ b/esphome/components/template/switch/__init__.py @@ -43,7 +43,9 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation( single=True ), - cv.Optional(CONF_RESTORE_STATE, default=False): cv.boolean, + cv.Optional(CONF_RESTORE_STATE): cv.invalid( + "The restore_state option has been removed in 2023.7.0. Use the restore_mode option instead" + ), } ) .extend(cv.COMPONENT_SCHEMA), @@ -70,7 +72,6 @@ async def to_code(config): ) cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE])) - cg.add(var.set_restore_state(config[CONF_RESTORE_STATE])) @automation.register_action( diff --git a/esphome/components/template/switch/template_switch.cpp b/esphome/components/template/switch/template_switch.cpp index 5db346b99f..b2a221669e 100644 --- a/esphome/components/template/switch/template_switch.cpp +++ b/esphome/components/template/switch/template_switch.cpp @@ -40,9 +40,6 @@ float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWA Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } void TemplateSwitch::setup() { - if (!this->restore_state_) - return; - optional initial_state = this->get_initial_state_with_restore_mode(); if (initial_state.has_value()) { @@ -57,10 +54,8 @@ void TemplateSwitch::setup() { } void TemplateSwitch::dump_config() { LOG_SWITCH("", "Template Switch", this); - ESP_LOGCONFIG(TAG, " Restore State: %s", YESNO(this->restore_state_)); ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); } -void TemplateSwitch::set_restore_state(bool restore_state) { this->restore_state_ = restore_state; } void TemplateSwitch::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; } } // namespace template_ diff --git a/esphome/components/template/switch/template_switch.h b/esphome/components/template/switch/template_switch.h index ef9b567451..bfe9ac25d6 100644 --- a/esphome/components/template/switch/template_switch.h +++ b/esphome/components/template/switch/template_switch.h @@ -15,7 +15,6 @@ class TemplateSwitch : public switch_::Switch, public Component { void dump_config() override; void set_state_lambda(std::function()> &&f); - void set_restore_state(bool restore_state); Trigger<> *get_turn_on_trigger() const; Trigger<> *get_turn_off_trigger() const; void set_optimistic(bool optimistic); @@ -35,7 +34,6 @@ class TemplateSwitch : public switch_::Switch, public Component { Trigger<> *turn_on_trigger_; Trigger<> *turn_off_trigger_; Trigger<> *prev_trigger_{nullptr}; - bool restore_state_{false}; }; } // namespace template_ diff --git a/tests/test1.yaml b/tests/test1.yaml index d0c9801933..bf099e2844 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2475,7 +2475,6 @@ switch: level: !lambda "return 0.5;" turn_off_action: - switch.turn_on: living_room_lights_off - restore_state: false on_turn_on: - switch.template.publish: id: livingroom_lights @@ -2511,7 +2510,6 @@ switch: } optimistic: true assumed_state: false - restore_state: true on_turn_off: - switch.template.publish: id: my_switch From ac81fae855c5c8be5b32d8a781123986a0283c5e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 17 Jul 2023 07:17:31 +1000 Subject: [PATCH 0233/2607] Add timeout filter (#5104) --- esphome/components/sensor/__init__.py | 10 ++++++++++ esphome/components/sensor/filter.cpp | 11 +++++++++++ esphome/components/sensor/filter.h | 12 ++++++++++++ tests/test3.1.yaml | 1 + 4 files changed, 34 insertions(+) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 06b96171a7..caaffd9701 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -217,6 +217,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter) MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) +TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component) DeltaFilter = sensor_ns.class_("DeltaFilter", Filter) @@ -536,6 +537,15 @@ async def heartbeat_filter_to_code(config, filter_id): return var +@FILTER_REGISTRY.register( + "timeout", TimeoutFilter, cv.positive_time_period_milliseconds +) +async def timeout_filter_to_code(config, filter_id): + var = cg.new_Pvariable(filter_id, config) + await cg.register_component(var, {}) + return var + + @FILTER_REGISTRY.register( "debounce", DebounceFilter, cv.positive_time_period_milliseconds ) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 472649ebdc..ccefa556b6 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -373,6 +373,17 @@ void OrFilter::initialize(Sensor *parent, Filter *next) { this->phi_.initialize(parent, nullptr); } +// TimeoutFilter +optional TimeoutFilter::new_value(float value) { + this->set_timeout("timeout", this->time_period_, [this]() { this->output(NAN); }); + this->output(value); + + return {}; +} + +TimeoutFilter::TimeoutFilter(uint32_t time_period) : time_period_(time_period) {} +float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; } + // DebounceFilter optional DebounceFilter::new_value(float value) { this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); }); diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 05934a26e8..296990f34f 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -313,6 +313,18 @@ class ThrottleFilter : public Filter { uint32_t min_time_between_inputs_; }; +class TimeoutFilter : public Filter, public Component { + public: + explicit TimeoutFilter(uint32_t time_period); + + optional new_value(float value) override; + + float get_setup_priority() const override; + + protected: + uint32_t time_period_; +}; + class DebounceFilter : public Filter, public Component { public: explicit DebounceFilter(uint32_t time_period); diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 5f1d3ff28f..104f4bbda8 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -86,6 +86,7 @@ sensor: - delta: 100 - throttle: 100ms - debounce: 500s + - timeout: 10min - calibrate_linear: - 0 -> 0 - 100 -> 100 From 899aa31df3394720db98cc49e5f920ae12e33284 Mon Sep 17 00:00:00 2001 From: Dave T <17680170+davet2001@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:19:08 +0100 Subject: [PATCH 0234/2607] Mark repo as safe directory to git config (#5102) --- script/setup | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/script/setup b/script/setup index e1b5941d0e..ba3b544352 100755 --- a/script/setup +++ b/script/setup @@ -10,6 +10,11 @@ if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ] && [ ! "$ESPHOME_NO_VENV" source venv/bin/activate fi +# Avoid unsafe git error when running inside devcontainer +if [ -n "$DEVCONTAINER" ];then + git config --global --add safe.directory "$PWD" +fi + pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt pip3 install setuptools wheel pip3 install --no-use-pep517 -e . From d7945de0013772a9f242afb8c7d843b9521e67ea Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:19:04 +1200 Subject: [PATCH 0235/2607] Dont do mqtt ip lookup if `use_address` has ip address (#5096) * Dont do mqtt ip lookup id `use_address` is in config * Fix after actually testing =) --- esphome/__main__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index c7c83ad83b..ecf0092b05 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -32,7 +32,7 @@ from esphome.const import ( SECRETS_FILES, ) from esphome.core import CORE, EsphomeError, coroutine -from esphome.helpers import indent +from esphome.helpers import indent, is_ip_address from esphome.util import ( run_external_command, run_external_process, @@ -308,8 +308,10 @@ def upload_program(config, args, host): password = ota_conf.get(CONF_PASSWORD, "") if ( - get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED] - ) and CONF_MQTT in config: + not is_ip_address(CORE.address) + and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) + and CONF_MQTT in config + ): from esphome import mqtt host = mqtt.get_esphome_device_ip( From 6bdc0c92fe2ac8b9bc4ca5ce23ee6aceac71c2a5 Mon Sep 17 00:00:00 2001 From: Pierre-Alexis Ciavaldini Date: Sun, 16 Jul 2023 21:42:01 +0200 Subject: [PATCH 0236/2607] ESP32 enable ADC2 when wifi is disabled (#4381) Co-authored-by: Keith Burzinski --- esphome/components/adc/__init__.py | 59 +++++++++++++++-- esphome/components/adc/adc_sensor.cpp | 93 ++++++++++++++++++--------- esphome/components/adc/adc_sensor.h | 20 ++++-- esphome/components/adc/sensor.py | 40 ++++++++++-- 4 files changed, 166 insertions(+), 46 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index cceaa594ef..99dad68501 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -24,6 +24,7 @@ ATTENUATION_MODES = { } adc1_channel_t = cg.global_ns.enum("adc1_channel_t") +adc2_channel_t = cg.global_ns.enum("adc2_channel_t") # From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h # pin to adc1 channel mapping @@ -78,6 +79,49 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = { }, } +ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = { + # TODO: add other variants + VARIANT_ESP32: { + 4: adc2_channel_t.ADC2_CHANNEL_0, + 0: adc2_channel_t.ADC2_CHANNEL_1, + 2: adc2_channel_t.ADC2_CHANNEL_2, + 15: adc2_channel_t.ADC2_CHANNEL_3, + 13: adc2_channel_t.ADC2_CHANNEL_4, + 12: adc2_channel_t.ADC2_CHANNEL_5, + 14: adc2_channel_t.ADC2_CHANNEL_6, + 27: adc2_channel_t.ADC2_CHANNEL_7, + 25: adc2_channel_t.ADC2_CHANNEL_8, + 26: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32S2: { + 11: adc2_channel_t.ADC2_CHANNEL_0, + 12: adc2_channel_t.ADC2_CHANNEL_1, + 13: adc2_channel_t.ADC2_CHANNEL_2, + 14: adc2_channel_t.ADC2_CHANNEL_3, + 15: adc2_channel_t.ADC2_CHANNEL_4, + 16: adc2_channel_t.ADC2_CHANNEL_5, + 17: adc2_channel_t.ADC2_CHANNEL_6, + 18: adc2_channel_t.ADC2_CHANNEL_7, + 19: adc2_channel_t.ADC2_CHANNEL_8, + 20: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32S3: { + 11: adc2_channel_t.ADC2_CHANNEL_0, + 12: adc2_channel_t.ADC2_CHANNEL_1, + 13: adc2_channel_t.ADC2_CHANNEL_2, + 14: adc2_channel_t.ADC2_CHANNEL_3, + 15: adc2_channel_t.ADC2_CHANNEL_4, + 16: adc2_channel_t.ADC2_CHANNEL_5, + 17: adc2_channel_t.ADC2_CHANNEL_6, + 18: adc2_channel_t.ADC2_CHANNEL_7, + 19: adc2_channel_t.ADC2_CHANNEL_8, + 20: adc2_channel_t.ADC2_CHANNEL_9, + }, + VARIANT_ESP32C3: { + 5: adc2_channel_t.ADC2_CHANNEL_0, + }, +} + def validate_adc_pin(value): if str(value).upper() == "VCC": @@ -89,11 +133,18 @@ def validate_adc_pin(value): if CORE.is_esp32: value = pins.internal_gpio_input_pin_number(value) variant = get_esp32_variant() - if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL: + if ( + variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL + and variant not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL + ): raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported") - if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]: + if ( + value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant] + and value not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): raise cv.Invalid(f"{variant} doesn't support ADC on this pin") + return pins.internal_gpio_input_pin_schema(value) if CORE.is_esp8266: @@ -104,7 +155,7 @@ def validate_adc_pin(value): ) if value != 17: # A0 - raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.") + raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC") return pins.gpio_pin_schema( {CONF_ANALOG: True, CONF_INPUT: True}, internal=True )(value) @@ -112,7 +163,7 @@ def validate_adc_pin(value): if CORE.is_rp2040: value = pins.internal_gpio_input_pin_number(value) if value not in (26, 27, 28, 29): - raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.") + raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC") return pins.internal_gpio_input_pin_schema(value) raise NotImplementedError diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 9bfe0f5eed..bb6a7a8c85 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -20,20 +20,20 @@ namespace adc { static const char *const TAG = "adc"; -// 13bit for S2, and 12bit for all other esp32 variants +// 13-bit for S2, 12-bit for all other ESP32 variants #ifdef USE_ESP32 static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast(ADC_WIDTH_MAX - 1); #ifndef SOC_ADC_RTC_MAX_BITWIDTH #if USE_ESP32_VARIANT_ESP32S2 -static const int SOC_ADC_RTC_MAX_BITWIDTH = 13; +static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13; #else -static const int SOC_ADC_RTC_MAX_BITWIDTH = 12; +static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12; #endif #endif -static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) -static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) +static const int32_t ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) +static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) #endif #ifdef USE_RP2040 @@ -47,14 +47,21 @@ extern "C" #endif #ifdef USE_ESP32 - adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); - if (!autorange_) { - adc1_config_channel_atten(channel_, attenuation_); + if (channel1_ != ADC1_CHANNEL_MAX) { + adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); + if (!autorange_) { + adc1_config_channel_atten(channel1_, attenuation_); + } + } else if (channel2_ != ADC2_CHANNEL_MAX) { + if (!autorange_) { + adc2_config_channel_atten(channel2_, attenuation_); + } } // load characteristics for each attenuation - for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) { - auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, + for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) { + auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; + auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref &cal_characteristics_[i]); switch (cal_value) { @@ -136,9 +143,9 @@ void ADCSensor::update() { #ifdef USE_ESP8266 float ADCSensor::sample() { #ifdef USE_ADC_SENSOR_VCC - int raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) + int32_t raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) #else - int raw = analogRead(this->pin_->get_pin()); // NOLINT + int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT #endif if (output_raw_) { return raw; @@ -150,29 +157,53 @@ float ADCSensor::sample() { #ifdef USE_ESP32 float ADCSensor::sample() { if (!autorange_) { - int raw = adc1_get_raw(channel_); + int32_t raw = -1; + if (channel1_ != ADC1_CHANNEL_MAX) { + raw = adc1_get_raw(channel1_); + } else if (channel2_ != ADC2_CHANNEL_MAX) { + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw); + } + if (raw == -1) { return NAN; } if (output_raw_) { return raw; } - uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int) attenuation_]); + uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]); return mv / 1000.0f; } - int raw11, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11); - raw11 = adc1_get_raw(channel_); - if (raw11 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6); - raw6 = adc1_get_raw(channel_); - if (raw6 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5); - raw2 = adc1_get_raw(channel_); - if (raw2 < ADC_MAX) { - adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0); - raw0 = adc1_get_raw(channel_); + int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + + if (channel1_ != ADC1_CHANNEL_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); + raw11 = adc1_get_raw(channel1_); + if (raw11 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); + raw6 = adc1_get_raw(channel1_); + if (raw6 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5); + raw2 = adc1_get_raw(channel1_); + if (raw2 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0); + raw0 = adc1_get_raw(channel1_); + } + } + } + } else if (channel2_ != ADC2_CHANNEL_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11); + if (raw11 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); + if (raw6 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2); + if (raw2 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0); + } } } } @@ -181,10 +212,10 @@ float ADCSensor::sample() { return NAN; } - uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int) ADC_ATTEN_DB_11]); - uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int) ADC_ATTEN_DB_6]); - uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]); - uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]); + uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]); + uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); + uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); + uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) uint32_t c11 = std::min(raw11, ADC_HALF); @@ -212,7 +243,7 @@ float ADCSensor::sample() { adc_select_input(pin - 26); } - int raw = adc_read(); + int32_t raw = adc_read(); if (this->is_temperature_) { adc_set_temp_sensor_enabled(false); } diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 22cddde6f8..a905177790 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -19,16 +19,23 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_ESP32 /// Set the attenuation for this pin. Only available on the ESP32. void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; } - void set_channel(adc1_channel_t channel) { channel_ = channel; } + void set_channel1(adc1_channel_t channel) { + channel1_ = channel; + channel2_ = ADC2_CHANNEL_MAX; + } + void set_channel2(adc2_channel_t channel) { + channel2_ = channel; + channel1_ = ADC1_CHANNEL_MAX; + } void set_autorange(bool autorange) { autorange_ = autorange; } #endif - /// Update adc values. + /// Update ADC values void update() override; - /// Setup ADc + /// Setup ADC void setup() override; void dump_config() override; - /// `HARDWARE_LATE` setup priority. + /// `HARDWARE_LATE` setup priority float get_setup_priority() const override; void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; } void set_output_raw(bool output_raw) { output_raw_ = output_raw; } @@ -52,9 +59,10 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_ESP32 adc_atten_t attenuation_{ADC_ATTEN_DB_0}; - adc1_channel_t channel_{}; + adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; + adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; - esp_adc_cal_characteristics_t cal_characteristics_[(int) ADC_ATTEN_MAX] = {}; + esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {}; #endif }; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 4695e96570..a0eda1d659 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -1,5 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv +from esphome.core import CORE from esphome.components import sensor, voltage_sampler from esphome.components.esp32 import get_esp32_variant from esphome.const import ( @@ -8,15 +10,15 @@ from esphome.const import ( CONF_NUMBER, CONF_PIN, CONF_RAW, + CONF_WIFI, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) -from esphome.core import CORE - from . import ( ATTENUATION_MODES, ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, + ESP32_VARIANT_ADC2_PIN_TO_CHANNEL, validate_adc_pin, ) @@ -25,7 +27,23 @@ AUTO_LOAD = ["voltage_sampler"] def validate_config(config): if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": - raise cv.Invalid("Automatic attenuation cannot be used when raw output is set.") + raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") + + return config + + +def final_validate_config(config): + if CORE.is_esp32: + variant = get_esp32_variant() + if ( + CONF_WIFI in fv.full_config.get() + and config[CONF_PIN][CONF_NUMBER] + in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): + raise cv.Invalid( + f"{variant} doesn't support ADC on this pin when Wi-Fi is configured" + ) + return config @@ -55,6 +73,8 @@ CONFIG_SCHEMA = cv.All( validate_config, ) +FINAL_VALIDATE_SCHEMA = final_validate_config + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) @@ -81,5 +101,15 @@ async def to_code(config): if CORE.is_esp32: variant = get_esp32_variant() pin_num = config[CONF_PIN][CONF_NUMBER] - chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num] - cg.add(var.set_channel(chan)) + if ( + variant in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL + and pin_num in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant] + ): + chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num] + cg.add(var.set_channel1(chan)) + elif ( + variant in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL + and pin_num in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant] + ): + chan = ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant][pin_num] + cg.add(var.set_channel2(chan)) From 74e062fdb30bacd6cfc872d0a2ef0fc277e80e79 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Sun, 16 Jul 2023 23:28:31 +0300 Subject: [PATCH 0237/2607] [Sprinkler] Resume fixes (#5100) --- esphome/components/sprinkler/sprinkler.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 095884997c..8afafcb5ce 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -954,10 +954,18 @@ void Sprinkler::pause() { } void Sprinkler::resume() { + if (this->standby()) { + ESP_LOGD(TAG, "resume called but standby is enabled; no action taken"); + return; + } + if (this->paused_valve_.has_value() && (this->resume_duration_.has_value())) { - ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0), - this->resume_duration_.value_or(0)); - this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value()); + // Resume only if valve has not been completed yet + if (!this->valve_cycle_complete_(this->paused_valve_.value())) { + ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0), + this->resume_duration_.value_or(0)); + this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value()); + } this->reset_resume(); } else { ESP_LOGD(TAG, "No valve to resume!"); From d57a5d1793a84a9351c0003668da5d0fb0e12060 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:11:43 +1200 Subject: [PATCH 0238/2607] Remove template switch restore_state (#5106) --- esphome/components/template/switch/__init__.py | 5 +++-- esphome/components/template/switch/template_switch.cpp | 5 ----- esphome/components/template/switch/template_switch.h | 2 -- tests/test1.yaml | 2 -- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py index e002c4e3d8..a221cbaa60 100644 --- a/esphome/components/template/switch/__init__.py +++ b/esphome/components/template/switch/__init__.py @@ -43,7 +43,9 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation( single=True ), - cv.Optional(CONF_RESTORE_STATE, default=False): cv.boolean, + cv.Optional(CONF_RESTORE_STATE): cv.invalid( + "The restore_state option has been removed in 2023.7.0. Use the restore_mode option instead" + ), } ) .extend(cv.COMPONENT_SCHEMA), @@ -70,7 +72,6 @@ async def to_code(config): ) cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE])) - cg.add(var.set_restore_state(config[CONF_RESTORE_STATE])) @automation.register_action( diff --git a/esphome/components/template/switch/template_switch.cpp b/esphome/components/template/switch/template_switch.cpp index 5db346b99f..b2a221669e 100644 --- a/esphome/components/template/switch/template_switch.cpp +++ b/esphome/components/template/switch/template_switch.cpp @@ -40,9 +40,6 @@ float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWA Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } void TemplateSwitch::setup() { - if (!this->restore_state_) - return; - optional initial_state = this->get_initial_state_with_restore_mode(); if (initial_state.has_value()) { @@ -57,10 +54,8 @@ void TemplateSwitch::setup() { } void TemplateSwitch::dump_config() { LOG_SWITCH("", "Template Switch", this); - ESP_LOGCONFIG(TAG, " Restore State: %s", YESNO(this->restore_state_)); ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); } -void TemplateSwitch::set_restore_state(bool restore_state) { this->restore_state_ = restore_state; } void TemplateSwitch::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; } } // namespace template_ diff --git a/esphome/components/template/switch/template_switch.h b/esphome/components/template/switch/template_switch.h index ef9b567451..bfe9ac25d6 100644 --- a/esphome/components/template/switch/template_switch.h +++ b/esphome/components/template/switch/template_switch.h @@ -15,7 +15,6 @@ class TemplateSwitch : public switch_::Switch, public Component { void dump_config() override; void set_state_lambda(std::function()> &&f); - void set_restore_state(bool restore_state); Trigger<> *get_turn_on_trigger() const; Trigger<> *get_turn_off_trigger() const; void set_optimistic(bool optimistic); @@ -35,7 +34,6 @@ class TemplateSwitch : public switch_::Switch, public Component { Trigger<> *turn_on_trigger_; Trigger<> *turn_off_trigger_; Trigger<> *prev_trigger_{nullptr}; - bool restore_state_{false}; }; } // namespace template_ diff --git a/tests/test1.yaml b/tests/test1.yaml index d0c9801933..bf099e2844 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2475,7 +2475,6 @@ switch: level: !lambda "return 0.5;" turn_off_action: - switch.turn_on: living_room_lights_off - restore_state: false on_turn_on: - switch.template.publish: id: livingroom_lights @@ -2511,7 +2510,6 @@ switch: } optimistic: true assumed_state: false - restore_state: true on_turn_off: - switch.template.publish: id: my_switch From c4b906574972b279c0f11023d648dead71306a0a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 17 Jul 2023 07:17:31 +1000 Subject: [PATCH 0239/2607] Add timeout filter (#5104) --- esphome/components/sensor/__init__.py | 10 ++++++++++ esphome/components/sensor/filter.cpp | 11 +++++++++++ esphome/components/sensor/filter.h | 12 ++++++++++++ tests/test3.1.yaml | 1 + 4 files changed, 34 insertions(+) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 06b96171a7..caaffd9701 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -217,6 +217,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter) MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) +TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component) DeltaFilter = sensor_ns.class_("DeltaFilter", Filter) @@ -536,6 +537,15 @@ async def heartbeat_filter_to_code(config, filter_id): return var +@FILTER_REGISTRY.register( + "timeout", TimeoutFilter, cv.positive_time_period_milliseconds +) +async def timeout_filter_to_code(config, filter_id): + var = cg.new_Pvariable(filter_id, config) + await cg.register_component(var, {}) + return var + + @FILTER_REGISTRY.register( "debounce", DebounceFilter, cv.positive_time_period_milliseconds ) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 472649ebdc..ccefa556b6 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -373,6 +373,17 @@ void OrFilter::initialize(Sensor *parent, Filter *next) { this->phi_.initialize(parent, nullptr); } +// TimeoutFilter +optional TimeoutFilter::new_value(float value) { + this->set_timeout("timeout", this->time_period_, [this]() { this->output(NAN); }); + this->output(value); + + return {}; +} + +TimeoutFilter::TimeoutFilter(uint32_t time_period) : time_period_(time_period) {} +float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; } + // DebounceFilter optional DebounceFilter::new_value(float value) { this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); }); diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 05934a26e8..296990f34f 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -313,6 +313,18 @@ class ThrottleFilter : public Filter { uint32_t min_time_between_inputs_; }; +class TimeoutFilter : public Filter, public Component { + public: + explicit TimeoutFilter(uint32_t time_period); + + optional new_value(float value) override; + + float get_setup_priority() const override; + + protected: + uint32_t time_period_; +}; + class DebounceFilter : public Filter, public Component { public: explicit DebounceFilter(uint32_t time_period); diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 5f1d3ff28f..104f4bbda8 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -86,6 +86,7 @@ sensor: - delta: 100 - throttle: 100ms - debounce: 500s + - timeout: 10min - calibrate_linear: - 0 -> 0 - 100 -> 100 From 68affce274d34eb05aa508f9b6c359101d55ec37 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:29:32 +1200 Subject: [PATCH 0240/2607] Bump version to 2023.7.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e74f23e9b4..8e0efaca09 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0b1" +__version__ = "2023.7.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 1617eba764584a88a11f1edb5550b1f70a82bbb2 Mon Sep 17 00:00:00 2001 From: bwynants Date: Mon, 17 Jul 2023 00:42:49 +0200 Subject: [PATCH 0241/2607] P1 values for capacity tariff in Belgium (#5081) --- esphome/components/dsmr/__init__.py | 2 +- esphome/components/dsmr/sensor.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index d3d20ca2a7..9f56dc3465 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -87,7 +87,7 @@ async def to_code(config): cg.add_build_flag("-DDSMR_WATER_MBUS_ID=" + str(config[CONF_WATER_MBUS_ID])) # DSMR Parser - cg.add_library("glmnet/Dsmr", "0.7") + cg.add_library("glmnet/Dsmr", "0.8") # Crypto cg.add_library("rweather/Crypto", "0.4.0") diff --git a/esphome/components/dsmr/sensor.py b/esphome/components/dsmr/sensor.py index 2e2050ecab..f2398d1908 100644 --- a/esphome/components/dsmr/sensor.py +++ b/esphome/components/dsmr/sensor.py @@ -243,6 +243,30 @@ CONFIG_SCHEMA = cv.Schema( device_class=DEVICE_CLASS_WATER, state_class=STATE_CLASS_TOTAL_INCREASING, ), + cv.Optional( + "active_energy_import_current_average_demand" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional( + "active_energy_import_maximum_demand_running_month" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional( + "active_energy_import_maximum_demand_last_13_months" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), } ).extend(cv.COMPONENT_SCHEMA) From 6738295475c5ea570a6b28efd03e7ccaf958cbeb Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 16 Jul 2023 15:43:57 -0700 Subject: [PATCH 0242/2607] airthings_wave: Silence compiler warnings (#5098) --- .../components/airthings_wave_base/airthings_wave_base.cpp | 2 +- .../components/airthings_wave_plus/airthings_wave_plus.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.cpp b/esphome/components/airthings_wave_base/airthings_wave_base.cpp index eff466f413..16789ff454 100644 --- a/esphome/components/airthings_wave_base/airthings_wave_base.cpp +++ b/esphome/components/airthings_wave_base/airthings_wave_base.cpp @@ -76,7 +76,7 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt } } -bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } +bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return voc <= 16383; } void AirthingsWaveBase::update() { if (this->node_state != espbt::ClientState::ESTABLISHED) { diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index e44d5fbcaa..a32128e992 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -51,9 +51,9 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { this->response_received_(); } -bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } +bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return radon <= 16383; } -bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } +bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return co2 <= 16383; } void AirthingsWavePlus::dump_config() { // these really don't belong here, but there doesn't seem to be a From 3cfe1e3083e70f07380a6550b32c2892b550fa0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:47:06 +1200 Subject: [PATCH 0243/2607] Bump click from 8.1.3 to 8.1.5 (#5099) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 618fc94e0b..d3b5ddee94 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6.2 -click==8.1.3 +click==8.1.5 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 zeroconf==0.69.0 From b0e286972d7af9bfaa95e5fe95fbae1191a055e6 Mon Sep 17 00:00:00 2001 From: PlainTechEnthusiast <135363826+PlainTechEnthusiast@users.noreply.github.com> Date: Mon, 17 Jul 2023 20:49:04 -0400 Subject: [PATCH 0244/2607] Sigma delta fix (#4911) --- .../sigma_delta_output/sigma_delta_output.cpp | 57 +++++++++++++++++++ .../sigma_delta_output/sigma_delta_output.h | 31 ++-------- 2 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 esphome/components/sigma_delta_output/sigma_delta_output.cpp diff --git a/esphome/components/sigma_delta_output/sigma_delta_output.cpp b/esphome/components/sigma_delta_output/sigma_delta_output.cpp new file mode 100644 index 0000000000..d386f8db1a --- /dev/null +++ b/esphome/components/sigma_delta_output/sigma_delta_output.cpp @@ -0,0 +1,57 @@ +#include "sigma_delta_output.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace sigma_delta_output { + +static const char *const TAG = "output.sigma_delta"; + +void SigmaDeltaOutput::setup() { + if (this->pin_) + this->pin_->setup(); +} + +void SigmaDeltaOutput::dump_config() { + ESP_LOGCONFIG(TAG, "Sigma Delta Output:"); + LOG_PIN(" Pin: ", this->pin_); + if (this->state_change_trigger_) { + ESP_LOGCONFIG(TAG, " State change automation configured"); + } + if (this->turn_on_trigger_) { + ESP_LOGCONFIG(TAG, " Turn on automation configured"); + } + if (this->turn_off_trigger_) { + ESP_LOGCONFIG(TAG, " Turn off automation configured"); + } + LOG_UPDATE_INTERVAL(this); + LOG_FLOAT_OUTPUT(this); +} + +void SigmaDeltaOutput::update() { + this->accum_ += this->state_; + const bool next_value = this->accum_ > 0; + + if (next_value) { + this->accum_ -= 1.; + } + + if (next_value != this->value_) { + this->value_ = next_value; + if (this->pin_) { + this->pin_->digital_write(next_value); + } + + if (this->state_change_trigger_) { + this->state_change_trigger_->trigger(next_value); + } + + if (next_value && this->turn_on_trigger_) { + this->turn_on_trigger_->trigger(); + } else if (!next_value && this->turn_off_trigger_) { + this->turn_off_trigger_->trigger(); + } + } +} + +} // namespace sigma_delta_output +} // namespace esphome diff --git a/esphome/components/sigma_delta_output/sigma_delta_output.h b/esphome/components/sigma_delta_output/sigma_delta_output.h index 5a5acd2dfb..8fd1e1f761 100644 --- a/esphome/components/sigma_delta_output/sigma_delta_output.h +++ b/esphome/components/sigma_delta_output/sigma_delta_output.h @@ -1,9 +1,12 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" +#include "esphome/core/hal.h" #include "esphome/components/output/float_output.h" namespace esphome { namespace sigma_delta_output { + class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput { public: Trigger<> *get_turn_on_trigger() { @@ -25,31 +28,9 @@ class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput { void set_pin(GPIOPin *pin) { this->pin_ = pin; }; void write_state(float state) override { this->state_ = state; } - void update() override { - this->accum_ += this->state_; - const bool next_value = this->accum_ > 0; - - if (next_value) { - this->accum_ -= 1.; - } - - if (next_value != this->value_) { - this->value_ = next_value; - if (this->pin_) { - this->pin_->digital_write(next_value); - } - - if (this->state_change_trigger_) { - this->state_change_trigger_->trigger(next_value); - } - - if (next_value && this->turn_on_trigger_) { - this->turn_on_trigger_->trigger(); - } else if (!next_value && this->turn_off_trigger_) { - this->turn_off_trigger_->trigger(); - } - } - } + void setup() override; + void dump_config() override; + void update() override; protected: GPIOPin *pin_{nullptr}; From 837c749cd7e6797fb175dfda0ce4b3ecf2066597 Mon Sep 17 00:00:00 2001 From: voed Date: Tue, 18 Jul 2023 03:50:32 +0300 Subject: [PATCH 0245/2607] [LD2410] Remove baud_rate check (#5112) --- esphome/components/ld2410/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/ld2410/__init__.py b/esphome/components/ld2410/__init__.py index be39cc2979..47c4cdb0bd 100644 --- a/esphome/components/ld2410/__init__.py +++ b/esphome/components/ld2410/__init__.py @@ -112,7 +112,6 @@ CONFIG_SCHEMA = cv.All( FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( "ld2410", - baud_rate=256000, require_tx=True, require_rx=True, parity="NONE", From 417d45939f3392d98c9f8cc15a201d71c4c397fd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:38:47 +1200 Subject: [PATCH 0246/2607] Fix silence detection flag on voice assistant (#5120) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_connection.cpp | 3 ++- esphome/components/api/api_connection.h | 2 +- esphome/components/api/api_pb2.cpp | 9 +++++++++ esphome/components/api/api_pb2.h | 1 + esphome/components/api/api_server.cpp | 6 +++--- esphome/components/api/api_server.h | 2 +- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- esphome/components/voice_assistant/voice_assistant.h | 6 +----- 9 files changed, 20 insertions(+), 12 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 0d68d9fe55..86685aa5e6 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1420,6 +1420,7 @@ message VoiceAssistantRequest { bool start = 1; string conversation_id = 2; + bool use_vad = 3; } message VoiceAssistantResponse { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 858ff0e525..a46efd80e5 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -907,12 +907,13 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ #endif #ifdef USE_VOICE_ASSISTANT -bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id) { +bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) { if (!this->voice_assistant_subscription_) return false; VoiceAssistantRequest msg; msg.start = start; msg.conversation_id = conversation_id; + msg.use_vad = use_vad; return this->send_voice_assistant_request(msg); } void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index c146adff02..acc4578661 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { this->voice_assistant_subscription_ = msg.subscribe; } - bool request_voice_assistant(bool start, const std::string &conversation_id); + bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad); void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 8c7f6d0c4a..3a2d980e57 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -6348,6 +6348,10 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) this->start = value.as_bool(); return true; } + case 3: { + this->use_vad = value.as_bool(); + return true; + } default: return false; } @@ -6365,6 +6369,7 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); buffer.encode_string(2, this->conversation_id); + buffer.encode_bool(3, this->use_vad); } #ifdef HAS_PROTO_MESSAGE_DUMP void VoiceAssistantRequest::dump_to(std::string &out) const { @@ -6377,6 +6382,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append(" conversation_id: "); out.append("'").append(this->conversation_id).append("'"); out.append("\n"); + + out.append(" use_vad: "); + out.append(YESNO(this->use_vad)); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 769f7aaff5..627165953d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1655,6 +1655,7 @@ class VoiceAssistantRequest : public ProtoMessage { public: bool start{false}; std::string conversation_id{}; + bool use_vad{false}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 87b5f9e63f..f70d45ecd0 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -323,16 +323,16 @@ void APIServer::on_shutdown() { } #ifdef USE_VOICE_ASSISTANT -bool APIServer::start_voice_assistant(const std::string &conversation_id) { +bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) { for (auto &c : this->clients_) { - if (c->request_voice_assistant(true, conversation_id)) + if (c->request_voice_assistant(true, conversation_id, use_vad)) return true; } return false; } void APIServer::stop_voice_assistant() { for (auto &c : this->clients_) { - if (c->request_voice_assistant(false, "")) + if (c->request_voice_assistant(false, "", false)) return; } } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index be124f42ff..9b40a5ef02 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -81,7 +81,7 @@ class APIServer : public Component, public Controller { #endif #ifdef USE_VOICE_ASSISTANT - bool start_voice_assistant(const std::string &conversation_id); + bool start_voice_assistant(const std::string &conversation_id, bool use_vad); void stop_voice_assistant(); #endif diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 44d640ff39..217ddb6354 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -130,7 +130,7 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { void VoiceAssistant::request_start(bool continuous) { ESP_LOGD(TAG, "Requesting start..."); - if (!api::global_api_server->start_voice_assistant(this->conversation_id_)) { + if (!api::global_api_server->start_voice_assistant(this->conversation_id_, this->silence_detection_)) { ESP_LOGW(TAG, "Could not request start."); this->error_trigger_->trigger("not-connected", "Could not request start."); this->continuous_ = false; diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index b103584509..e67baaee65 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -25,10 +25,9 @@ namespace voice_assistant { // Version 1: Initial version // Version 2: Adds raw speaker support -// Version 3: Adds continuous support +// Version 3: Unused/skip static const uint32_t INITIAL_VERSION = 1; static const uint32_t SPEAKER_SUPPORT = 2; -static const uint32_t SILENCE_DETECTION_SUPPORT = 3; class VoiceAssistant : public Component { public: @@ -48,9 +47,6 @@ class VoiceAssistant : public Component { uint32_t get_version() const { #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { - if (this->silence_detection_) { - return SILENCE_DETECTION_SUPPORT; - } return SPEAKER_SUPPORT; } #endif From 553132443fbf777664fb0959301d8788ad26e8c0 Mon Sep 17 00:00:00 2001 From: bwynants Date: Mon, 17 Jul 2023 00:42:49 +0200 Subject: [PATCH 0247/2607] P1 values for capacity tariff in Belgium (#5081) --- esphome/components/dsmr/__init__.py | 2 +- esphome/components/dsmr/sensor.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index d3d20ca2a7..9f56dc3465 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -87,7 +87,7 @@ async def to_code(config): cg.add_build_flag("-DDSMR_WATER_MBUS_ID=" + str(config[CONF_WATER_MBUS_ID])) # DSMR Parser - cg.add_library("glmnet/Dsmr", "0.7") + cg.add_library("glmnet/Dsmr", "0.8") # Crypto cg.add_library("rweather/Crypto", "0.4.0") diff --git a/esphome/components/dsmr/sensor.py b/esphome/components/dsmr/sensor.py index 2e2050ecab..f2398d1908 100644 --- a/esphome/components/dsmr/sensor.py +++ b/esphome/components/dsmr/sensor.py @@ -243,6 +243,30 @@ CONFIG_SCHEMA = cv.Schema( device_class=DEVICE_CLASS_WATER, state_class=STATE_CLASS_TOTAL_INCREASING, ), + cv.Optional( + "active_energy_import_current_average_demand" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional( + "active_energy_import_maximum_demand_running_month" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional( + "active_energy_import_maximum_demand_last_13_months" + ): sensor.sensor_schema( + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), } ).extend(cv.COMPONENT_SCHEMA) From f840eee1b7633333d3a23abc457c5cc38a419cef Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 16 Jul 2023 15:43:57 -0700 Subject: [PATCH 0248/2607] airthings_wave: Silence compiler warnings (#5098) --- .../components/airthings_wave_base/airthings_wave_base.cpp | 2 +- .../components/airthings_wave_plus/airthings_wave_plus.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/airthings_wave_base/airthings_wave_base.cpp b/esphome/components/airthings_wave_base/airthings_wave_base.cpp index eff466f413..16789ff454 100644 --- a/esphome/components/airthings_wave_base/airthings_wave_base.cpp +++ b/esphome/components/airthings_wave_base/airthings_wave_base.cpp @@ -76,7 +76,7 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt } } -bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } +bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return voc <= 16383; } void AirthingsWaveBase::update() { if (this->node_state != espbt::ClientState::ESTABLISHED) { diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index e44d5fbcaa..a32128e992 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -51,9 +51,9 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { this->response_received_(); } -bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } +bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return radon <= 16383; } -bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } +bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return co2 <= 16383; } void AirthingsWavePlus::dump_config() { // these really don't belong here, but there doesn't seem to be a From 036e14ab7fb72bb25be026f9c9099aaf3ac95856 Mon Sep 17 00:00:00 2001 From: PlainTechEnthusiast <135363826+PlainTechEnthusiast@users.noreply.github.com> Date: Mon, 17 Jul 2023 20:49:04 -0400 Subject: [PATCH 0249/2607] Sigma delta fix (#4911) --- .../sigma_delta_output/sigma_delta_output.cpp | 57 +++++++++++++++++++ .../sigma_delta_output/sigma_delta_output.h | 31 ++-------- 2 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 esphome/components/sigma_delta_output/sigma_delta_output.cpp diff --git a/esphome/components/sigma_delta_output/sigma_delta_output.cpp b/esphome/components/sigma_delta_output/sigma_delta_output.cpp new file mode 100644 index 0000000000..d386f8db1a --- /dev/null +++ b/esphome/components/sigma_delta_output/sigma_delta_output.cpp @@ -0,0 +1,57 @@ +#include "sigma_delta_output.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace sigma_delta_output { + +static const char *const TAG = "output.sigma_delta"; + +void SigmaDeltaOutput::setup() { + if (this->pin_) + this->pin_->setup(); +} + +void SigmaDeltaOutput::dump_config() { + ESP_LOGCONFIG(TAG, "Sigma Delta Output:"); + LOG_PIN(" Pin: ", this->pin_); + if (this->state_change_trigger_) { + ESP_LOGCONFIG(TAG, " State change automation configured"); + } + if (this->turn_on_trigger_) { + ESP_LOGCONFIG(TAG, " Turn on automation configured"); + } + if (this->turn_off_trigger_) { + ESP_LOGCONFIG(TAG, " Turn off automation configured"); + } + LOG_UPDATE_INTERVAL(this); + LOG_FLOAT_OUTPUT(this); +} + +void SigmaDeltaOutput::update() { + this->accum_ += this->state_; + const bool next_value = this->accum_ > 0; + + if (next_value) { + this->accum_ -= 1.; + } + + if (next_value != this->value_) { + this->value_ = next_value; + if (this->pin_) { + this->pin_->digital_write(next_value); + } + + if (this->state_change_trigger_) { + this->state_change_trigger_->trigger(next_value); + } + + if (next_value && this->turn_on_trigger_) { + this->turn_on_trigger_->trigger(); + } else if (!next_value && this->turn_off_trigger_) { + this->turn_off_trigger_->trigger(); + } + } +} + +} // namespace sigma_delta_output +} // namespace esphome diff --git a/esphome/components/sigma_delta_output/sigma_delta_output.h b/esphome/components/sigma_delta_output/sigma_delta_output.h index 5a5acd2dfb..8fd1e1f761 100644 --- a/esphome/components/sigma_delta_output/sigma_delta_output.h +++ b/esphome/components/sigma_delta_output/sigma_delta_output.h @@ -1,9 +1,12 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" +#include "esphome/core/hal.h" #include "esphome/components/output/float_output.h" namespace esphome { namespace sigma_delta_output { + class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput { public: Trigger<> *get_turn_on_trigger() { @@ -25,31 +28,9 @@ class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput { void set_pin(GPIOPin *pin) { this->pin_ = pin; }; void write_state(float state) override { this->state_ = state; } - void update() override { - this->accum_ += this->state_; - const bool next_value = this->accum_ > 0; - - if (next_value) { - this->accum_ -= 1.; - } - - if (next_value != this->value_) { - this->value_ = next_value; - if (this->pin_) { - this->pin_->digital_write(next_value); - } - - if (this->state_change_trigger_) { - this->state_change_trigger_->trigger(next_value); - } - - if (next_value && this->turn_on_trigger_) { - this->turn_on_trigger_->trigger(); - } else if (!next_value && this->turn_off_trigger_) { - this->turn_off_trigger_->trigger(); - } - } - } + void setup() override; + void dump_config() override; + void update() override; protected: GPIOPin *pin_{nullptr}; From 4449248c6f65a2ad4e70fbdc96e7f1db0cc3542c Mon Sep 17 00:00:00 2001 From: voed Date: Tue, 18 Jul 2023 03:50:32 +0300 Subject: [PATCH 0250/2607] [LD2410] Remove baud_rate check (#5112) --- esphome/components/ld2410/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/ld2410/__init__.py b/esphome/components/ld2410/__init__.py index be39cc2979..47c4cdb0bd 100644 --- a/esphome/components/ld2410/__init__.py +++ b/esphome/components/ld2410/__init__.py @@ -112,7 +112,6 @@ CONFIG_SCHEMA = cv.All( FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( "ld2410", - baud_rate=256000, require_tx=True, require_rx=True, parity="NONE", From 746488cabf2d4ac8db4b0d7883dc72dd8c5aa73c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:38:47 +1200 Subject: [PATCH 0251/2607] Fix silence detection flag on voice assistant (#5120) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_connection.cpp | 3 ++- esphome/components/api/api_connection.h | 2 +- esphome/components/api/api_pb2.cpp | 9 +++++++++ esphome/components/api/api_pb2.h | 1 + esphome/components/api/api_server.cpp | 6 +++--- esphome/components/api/api_server.h | 2 +- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- esphome/components/voice_assistant/voice_assistant.h | 6 +----- 9 files changed, 20 insertions(+), 12 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 0d68d9fe55..86685aa5e6 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1420,6 +1420,7 @@ message VoiceAssistantRequest { bool start = 1; string conversation_id = 2; + bool use_vad = 3; } message VoiceAssistantResponse { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 858ff0e525..a46efd80e5 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -907,12 +907,13 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ #endif #ifdef USE_VOICE_ASSISTANT -bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id) { +bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) { if (!this->voice_assistant_subscription_) return false; VoiceAssistantRequest msg; msg.start = start; msg.conversation_id = conversation_id; + msg.use_vad = use_vad; return this->send_voice_assistant_request(msg); } void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index c146adff02..acc4578661 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { this->voice_assistant_subscription_ = msg.subscribe; } - bool request_voice_assistant(bool start, const std::string &conversation_id); + bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad); void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 8c7f6d0c4a..3a2d980e57 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -6348,6 +6348,10 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) this->start = value.as_bool(); return true; } + case 3: { + this->use_vad = value.as_bool(); + return true; + } default: return false; } @@ -6365,6 +6369,7 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); buffer.encode_string(2, this->conversation_id); + buffer.encode_bool(3, this->use_vad); } #ifdef HAS_PROTO_MESSAGE_DUMP void VoiceAssistantRequest::dump_to(std::string &out) const { @@ -6377,6 +6382,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append(" conversation_id: "); out.append("'").append(this->conversation_id).append("'"); out.append("\n"); + + out.append(" use_vad: "); + out.append(YESNO(this->use_vad)); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 769f7aaff5..627165953d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1655,6 +1655,7 @@ class VoiceAssistantRequest : public ProtoMessage { public: bool start{false}; std::string conversation_id{}; + bool use_vad{false}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 87b5f9e63f..f70d45ecd0 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -323,16 +323,16 @@ void APIServer::on_shutdown() { } #ifdef USE_VOICE_ASSISTANT -bool APIServer::start_voice_assistant(const std::string &conversation_id) { +bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) { for (auto &c : this->clients_) { - if (c->request_voice_assistant(true, conversation_id)) + if (c->request_voice_assistant(true, conversation_id, use_vad)) return true; } return false; } void APIServer::stop_voice_assistant() { for (auto &c : this->clients_) { - if (c->request_voice_assistant(false, "")) + if (c->request_voice_assistant(false, "", false)) return; } } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index be124f42ff..9b40a5ef02 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -81,7 +81,7 @@ class APIServer : public Component, public Controller { #endif #ifdef USE_VOICE_ASSISTANT - bool start_voice_assistant(const std::string &conversation_id); + bool start_voice_assistant(const std::string &conversation_id, bool use_vad); void stop_voice_assistant(); #endif diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 44d640ff39..217ddb6354 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -130,7 +130,7 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { void VoiceAssistant::request_start(bool continuous) { ESP_LOGD(TAG, "Requesting start..."); - if (!api::global_api_server->start_voice_assistant(this->conversation_id_)) { + if (!api::global_api_server->start_voice_assistant(this->conversation_id_, this->silence_detection_)) { ESP_LOGW(TAG, "Could not request start."); this->error_trigger_->trigger("not-connected", "Could not request start."); this->continuous_ = false; diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index b103584509..e67baaee65 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -25,10 +25,9 @@ namespace voice_assistant { // Version 1: Initial version // Version 2: Adds raw speaker support -// Version 3: Adds continuous support +// Version 3: Unused/skip static const uint32_t INITIAL_VERSION = 1; static const uint32_t SPEAKER_SUPPORT = 2; -static const uint32_t SILENCE_DETECTION_SUPPORT = 3; class VoiceAssistant : public Component { public: @@ -48,9 +47,6 @@ class VoiceAssistant : public Component { uint32_t get_version() const { #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { - if (this->silence_detection_) { - return SILENCE_DETECTION_SUPPORT; - } return SPEAKER_SUPPORT; } #endif From f4a4956dd40f43e89a1aea3e8ecc64cb2558a622 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:41:24 +1200 Subject: [PATCH 0252/2607] Bump version to 2023.7.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8e0efaca09..8dd947b26b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0b2" +__version__ = "2023.7.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From f5e98eb86f584c455851d9bfc5ce3e470c39973b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jul 2023 12:59:51 +1200 Subject: [PATCH 0253/2607] Bump version to 2023.7.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8dd947b26b..f04e19c359 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0b3" +__version__ = "2023.7.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 2a7aa2fc0dc940b85738c3e2d8f57f9e507b85c4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jul 2023 14:07:42 +1200 Subject: [PATCH 0254/2607] bump pyyaml to 6.0.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 618fc94e0b..74c15c9213 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ voluptuous==0.13.1 -PyYAML==6.0 +PyYAML==6.0.1 paho-mqtt==1.6.1 colorama==0.4.6 tornado==6.3.2 From b82c7ad6081b8d0a29b6aa89acf97cd14c571181 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 14:30:12 +1200 Subject: [PATCH 0255/2607] Bump pyyaml from 6.0 to 6.0.1 (#5117) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d3b5ddee94..781ed03a49 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ voluptuous==0.13.1 -PyYAML==6.0 +PyYAML==6.0.1 paho-mqtt==1.6.1 colorama==0.4.6 tornado==6.3.2 From 973e78355fa9e8cdfed3a38f6ac6b5bda0e4c3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 19 Jul 2023 22:39:35 +0200 Subject: [PATCH 0256/2607] Dashboard: use Popen() on Windows (#5110) --- esphome/dashboard/dashboard.py | 60 +++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index dd800f534c..a3a44de9ed 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -25,6 +25,7 @@ import tornado.ioloop import tornado.iostream import tornado.netutil import tornado.process +import tornado.queues import tornado.web import tornado.websocket import yaml @@ -202,7 +203,11 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): def __init__(self, application, request, **kwargs): super().__init__(application, request, **kwargs) self._proc = None + self._queue = None self._is_closed = False + # Windows doesn't support non-blocking pipes, + # use Popen() with a reading thread instead + self._use_popen = os.name == "nt" @authenticated def on_message(self, message): @@ -224,13 +229,28 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): return command = self.build_command(json_message) _LOGGER.info("Running command '%s'", " ".join(shlex_quote(x) for x in command)) - self._proc = tornado.process.Subprocess( - command, - stdout=tornado.process.Subprocess.STREAM, - stderr=subprocess.STDOUT, - stdin=tornado.process.Subprocess.STREAM, - ) - self._proc.set_exit_callback(self._proc_on_exit) + + if self._use_popen: + self._queue = tornado.queues.Queue() + # pylint: disable=consider-using-with + self._proc = subprocess.Popen( + command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + stdout_thread = threading.Thread(target=self._stdout_thread) + stdout_thread.daemon = True + stdout_thread.start() + else: + self._proc = tornado.process.Subprocess( + command, + stdout=tornado.process.Subprocess.STREAM, + stderr=subprocess.STDOUT, + stdin=tornado.process.Subprocess.STREAM, + ) + self._proc.set_exit_callback(self._proc_on_exit) + tornado.ioloop.IOLoop.current().spawn_callback(self._redirect_stdout) @property @@ -252,7 +272,13 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): while True: try: - data = yield self._proc.stdout.read_until_regex(reg) + if self._use_popen: + data = yield self._queue.get() + if data is None: + self._proc_on_exit(self._proc.poll()) + break + else: + data = yield self._proc.stdout.read_until_regex(reg) except tornado.iostream.StreamClosedError: break data = codecs.decode(data, "utf8", "replace") @@ -260,6 +286,19 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): _LOGGER.debug("> stdout: %s", data) self.write_message({"event": "line", "data": data}) + def _stdout_thread(self): + if not self._use_popen: + return + while True: + data = self._proc.stdout.readline() + if data: + data = data.replace(b"\r", b"") + self._queue.put_nowait(data) + if self._proc.poll() is not None: + break + self._proc.wait(1.0) + self._queue.put_nowait(None) + def _proc_on_exit(self, returncode): if not self._is_closed: # Check if the proc was not forcibly closed @@ -270,7 +309,10 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): # Check if proc exists (if 'start' has been run) if self.is_process_active: _LOGGER.debug("Terminating process") - self._proc.proc.terminate() + if self._use_popen: + self._proc.terminate() + else: + self._proc.proc.terminate() # Shutdown proc on WS close self._is_closed = True From de626c0f5fe0887a3a08402140c3da65ee2a1518 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 20 Jul 2023 12:37:29 +1200 Subject: [PATCH 0257/2607] ignore components folder in root (#5130) --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 71b66b2499..d180b58259 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,6 @@ tests/.esphome/ sdkconfig.* !sdkconfig.defaults -.tests/ \ No newline at end of file +.tests/ + +/components From d2381556401723e0cd87b6292dde34a0a4f46f29 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 20 Jul 2023 12:37:42 +1200 Subject: [PATCH 0258/2607] Add size getter to CallbackManager (#5129) --- esphome/core/helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 05a7eaa4cc..63b6949fe9 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -475,6 +475,7 @@ template class CallbackManager { for (auto &cb : this->callbacks_) cb(args...); } + size_t size() const { return this->callbacks_.size(); } /// Call all callbacks in this manager. void operator()(Ts... args) { call(args...); } From 5eb12ac5fe1d3dcfa5f06da79a18b40d2b534565 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 20 Jul 2023 05:52:41 +0200 Subject: [PATCH 0259/2607] Make docker use pip installed pillow (#5074) --- docker/Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2d9a8a9ae4..e1f3c46a3e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -22,16 +22,22 @@ RUN \ python3=3.9.2-3 \ python3-pip=20.3.4-4+deb11u1 \ python3-setuptools=52.0.0-4 \ - python3-pil=8.1.2+dfsg-0.3+deb11u1 \ python3-cryptography=3.3.2-1 \ python3-venv=3.9.2-3 \ iputils-ping=3:20210202-1 \ git=1:2.30.2-1+deb11u2 \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ - libcairo2=1.16.0-5 \ - python3-cffi=1.14.5-1 \ - && rm -rf \ + python3-cffi=1.14.5-1; \ + if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ + apt-get install -y --no-install-recommends \ + build-essential=12.9 \ + python3-dev=3.9.2-3 \ + zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ + libjpeg-dev=1:2.0.6-4 \ + libcairo2=1.16.0-5; \ + fi; \ + rm -rf \ /tmp/* \ /var/{cache,log}/* \ /var/lib/apt/lists/* From 76c0d0912f88c6ea1ec9cb09a781d7177360ad3c Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 20 Jul 2023 05:54:25 +0200 Subject: [PATCH 0260/2607] Change datatype in e131 addressable light (#5127) --- esphome/components/e131/e131_addressable_light_effect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index 42eb0fc56b..6b6a726ef3 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -51,7 +51,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet if (universe < first_universe_ || universe > get_last_universe()) return false; - int output_offset = (universe - first_universe_) * get_lights_per_universe(); + int32_t output_offset = (universe - first_universe_) * get_lights_per_universe(); // limit amount of lights per universe and received int output_end = std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1)); From 89c5298bb936bd2436987384c40b38c2d845b206 Mon Sep 17 00:00:00 2001 From: Graham Brown Date: Thu, 20 Jul 2023 22:47:37 +0200 Subject: [PATCH 0261/2607] Streamer mode (#5119) --- esphome/__main__.py | 10 ++++++++-- esphome/dashboard/dashboard.py | 13 ++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index ecf0092b05..ca5fc1c008 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -365,10 +365,16 @@ def command_wizard(args): def command_config(args, config): - _LOGGER.info("Configuration is valid!") if not CORE.verbose: config = strip_default_ids(config) - safe_print(yaml_util.dump(config, args.show_secrets)) + output = yaml_util.dump(config, args.show_secrets) + # add the console decoration so the front-end can hide the secrets + if not args.show_secrets: + output = re.sub( + r"(password|key|psk|ssid)\:\s(.*)", r"\1: \\033[5m\2\\033[6m", output + ) + safe_print(output) + _LOGGER.info("Configuration is valid!") return 0 diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index a3a44de9ed..b33cb2df5e 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -93,6 +93,10 @@ class DashboardSettings: def using_auth(self): return self.using_password or self.using_ha_addon_auth + @property + def streamer_mode(self): + return get_bool_env("ESPHOME_STREAMER_MODE") + def check_password(self, username, password): if not self.using_auth: return True @@ -131,7 +135,7 @@ def template_args(): "docs_link": docs_link, "get_static_file_url": get_static_file_url, "relative_url": settings.relative_url, - "streamer_mode": get_bool_env("ESPHOME_STREAMER_MODE"), + "streamer_mode": settings.streamer_mode, "config_dir": settings.config_dir, } @@ -396,7 +400,10 @@ class EsphomeCompileHandler(EsphomeCommandWebSocket): class EsphomeValidateHandler(EsphomeCommandWebSocket): def build_command(self, json_message): config_file = settings.rel_path(json_message["configuration"]) - return ["esphome", "--dashboard", "config", config_file] + command = ["esphome", "--dashboard", "config", config_file] + if not settings.streamer_mode: + command.append("--show-secrets") + return command class EsphomeCleanMqttHandler(EsphomeCommandWebSocket): @@ -1147,7 +1154,7 @@ class JsonConfigRequestHandler(BaseHandler): self.send_error(404) return - args = ["esphome", "config", settings.rel_path(configuration), "--show-secrets"] + args = ["esphome", "config", filename, "--show-secrets"] rc, stdout, _ = run_system_command(*args) From 1c237aef772976a16a25d1e9c65d196d09f7b7f2 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Fri, 21 Jul 2023 05:35:44 +0200 Subject: [PATCH 0262/2607] Version bump for ESP32 IDF and Arduino (#5035) --- esphome/components/esp32/__init__.py | 10 +++++----- platformio.ini | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 903031c77a..f8e78794b2 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -163,23 +163,23 @@ RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5) # The platformio/espressif32 version to use for arduino frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 -ARDUINO_PLATFORM_VERSION = cv.Version(5, 3, 0) +ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) # The default/recommended esp-idf framework version # - https://github.com/espressif/esp-idf/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf -RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 4) +RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 5) # The platformio/espressif32 version to use for esp-idf frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 -ESP_IDF_PLATFORM_VERSION = cv.Version(5, 3, 0) +ESP_IDF_PLATFORM_VERSION = cv.Version(5, 4, 0) def _arduino_check_versions(value): value = value.copy() lookups = { "dev": (cv.Version(2, 1, 0), "https://github.com/espressif/arduino-esp32.git"), - "latest": (cv.Version(2, 0, 7), None), + "latest": (cv.Version(2, 0, 9), None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), } @@ -214,7 +214,7 @@ def _esp_idf_check_versions(value): value = value.copy() lookups = { "dev": (cv.Version(5, 1, 0), "https://github.com/espressif/esp-idf.git"), - "latest": (cv.Version(5, 0, 1), None), + "latest": (cv.Version(5, 1, 0), None), "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), } diff --git a/platformio.ini b/platformio.ini index b970ef7a69..8141c803f1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -104,7 +104,7 @@ extra_scripts = post:esphome/components/esp8266/post_build.py.script ; This are common settings for the ESP32 (all variants) using Arduino. [common:esp32-arduino] extends = common:arduino -platform = platformio/espressif32@5.3.0 +platform = platformio/espressif32@5.4.0 platform_packages = platformio/framework-arduinoespressif32@~3.20005.0 @@ -133,9 +133,9 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script ; This are common settings for the ESP32 (all variants) using IDF. [common:esp32-idf] extends = common:idf -platform = platformio/espressif32@5.3.0 +platform = platformio/espressif32@5.4.0 platform_packages = - platformio/framework-espidf@~3.40404.0 + platformio/framework-espidf@~3.40405.0 framework = espidf lib_deps = From c91b775b734c4b23ff83c52733273f89472eeff2 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Fri, 21 Jul 2023 22:17:48 +1200 Subject: [PATCH 0263/2607] Synchronise Device Classes from Home Assistant (#5136) --- esphome/components/number/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 73fbfd6e90..f45b8c024a 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -28,6 +28,7 @@ from esphome.const import ( DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY_STORAGE, @@ -81,6 +82,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY_STORAGE, From efd0dd4c3db8d98c47d251d93c8986b8ddf7beb5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 22 Jul 2023 20:24:40 +1200 Subject: [PATCH 0264/2607] Update known boards to 5.4.0 (#5134) --- esphome/components/esp32/boards.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index 30297654bc..61cb8cdc3f 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -1201,6 +1201,10 @@ BOARDS = { "name": "BPI-Bit", "variant": VARIANT_ESP32, }, + "bpi_leaf_s3": { + "name": "BPI-Leaf-S3", + "variant": VARIANT_ESP32S3, + }, "briki_abc_esp32": { "name": "Briki ABC (MBC-WB) - ESP32", "variant": VARIANT_ESP32, @@ -1217,6 +1221,10 @@ BOARDS = { "name": "Connaxio's Espoir", "variant": VARIANT_ESP32, }, + "cytron_maker_feather_aiot_s3": { + "name": "Cytron Maker Feather AIoT S3", + "variant": VARIANT_ESP32S3, + }, "d-duino-32": { "name": "D-duino-32", "variant": VARIANT_ESP32, @@ -1225,6 +1233,10 @@ BOARDS = { "name": "Deneyap Kart 1A", "variant": VARIANT_ESP32, }, + "deneyapkart1Av2": { + "name": "Deneyap Kart 1A v2", + "variant": VARIANT_ESP32S3, + }, "deneyapkartg": { "name": "Deneyap Kart G", "variant": VARIANT_ESP32C3, @@ -1237,6 +1249,10 @@ BOARDS = { "name": "Deneyap Mini", "variant": VARIANT_ESP32S2, }, + "deneyapminiv2": { + "name": "Deneyap Mini v2", + "variant": VARIANT_ESP32S2, + }, "denky32": { "name": "Denky32 (WROOM32)", "variant": VARIANT_ESP32, @@ -1265,6 +1281,10 @@ BOARDS = { "name": "Espressif ESP32-C3-DevKitM-1", "variant": VARIANT_ESP32C3, }, + "esp32-c3-m1i-kit": { + "name": "Ai-Thinker ESP-C3-M1-I-Kit", + "variant": VARIANT_ESP32C3, + }, "esp32cam": { "name": "AI Thinker ESP32-CAM", "variant": VARIANT_ESP32, @@ -1329,6 +1349,10 @@ BOARDS = { "name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)", "variant": VARIANT_ESP32S3, }, + "esp32-s3-korvo-2": { + "name": "Espressif ESP32-S3-Korvo-2", + "variant": VARIANT_ESP32S3, + }, "esp32thing": { "name": "SparkFun ESP32 Thing", "variant": VARIANT_ESP32, @@ -1637,6 +1661,10 @@ BOARDS = { "name": "Noduino Quantum", "variant": VARIANT_ESP32, }, + "redpill_esp32s3": { + "name": "Munich Labs RedPill ESP32-S3", + "variant": VARIANT_ESP32S3, + }, "seeed_xiao_esp32c3": { "name": "Seeed Studio XIAO ESP32C3", "variant": VARIANT_ESP32C3, From 80154b280e341cc6a28e4f25ca11b36e87433833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 22 Jul 2023 10:25:01 +0200 Subject: [PATCH 0265/2607] Init colorama in ESPHome main (#5111) --- esphome/log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/log.py b/esphome/log.py index e7ba0fdd82..b5d72e774c 100644 --- a/esphome/log.py +++ b/esphome/log.py @@ -71,6 +71,8 @@ def setup_log( ) -> None: import colorama + colorama.init() + if debug: log_level = logging.DEBUG CORE.verbose = True @@ -82,7 +84,6 @@ def setup_log( logging.getLogger("urllib3").setLevel(logging.WARNING) - colorama.init() logging.getLogger().handlers[0].setFormatter( ESPHomeLogFormatter(include_timestamp=include_timestamp) ) From 827b2def1e68a765a1a72ee4b64a4716d6b5e066 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Sun, 23 Jul 2023 00:15:37 +0400 Subject: [PATCH 0266/2607] Coolix IR protocol improvements (#5105) * coolix protocol * tests * 24-bit range * some DRY in coolix * added short condition * one more change * final prettify * v2023.8 --- esphome/components/coolix/coolix.cpp | 2 +- esphome/components/remote_base/__init__.py | 53 +++++++++---- .../remote_base/coolix_protocol.cpp | 76 +++++++++++++------ .../components/remote_base/coolix_protocol.h | 17 ++++- tests/test1.yaml | 27 ++++++- 5 files changed, 130 insertions(+), 45 deletions(-) diff --git a/esphome/components/coolix/coolix.cpp b/esphome/components/coolix/coolix.cpp index 738fd8d00d..6233014a96 100644 --- a/esphome/components/coolix/coolix.cpp +++ b/esphome/components/coolix/coolix.cpp @@ -114,7 +114,7 @@ bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteRecei if (!decoded.has_value()) return false; // Decoded remote state y 3 bytes long code. - uint32_t remote_state = *decoded; + uint32_t remote_state = (*decoded).second; ESP_LOGV(TAG, "Decoded 0x%06X", remote_state); if ((remote_state & 0xFF0000) != 0xB20000) return false; diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 2ef33f3711..0666b96d1e 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -17,6 +17,7 @@ from esphome.const import ( CONF_PROTOCOL, CONF_GROUP, CONF_DEVICE, + CONF_SECOND, CONF_STATE, CONF_CHANNEL, CONF_FAMILY, @@ -39,6 +40,7 @@ AUTO_LOAD = ["binary_sensor"] CONF_RECEIVER_ID = "receiver_id" CONF_TRANSMITTER_ID = "transmitter_id" +CONF_FIRST = "first" ns = remote_base_ns = cg.esphome_ns.namespace("remote_base") RemoteProtocol = ns.class_("RemoteProtocol") @@ -349,19 +351,48 @@ async def canalsatld_action(var, config, args): CoolixAction, CoolixDumper, ) = declare_protocol("Coolix") -COOLIX_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t}) -@register_binary_sensor("coolix", CoolixBinarySensor, COOLIX_SCHEMA) +COOLIX_BASE_SCHEMA = cv.Schema( + { + cv.Required(CONF_FIRST): cv.hex_int_range(0, 16777215), + cv.Optional(CONF_SECOND, default=0): cv.hex_int_range(0, 16777215), + cv.Optional(CONF_DATA): cv.invalid( + "'data' option has been removed in ESPHome 2023.8. " + "Use the 'first' and 'second' options instead." + ), + } +) + +COOLIX_SENSOR_SCHEMA = cv.Any(cv.hex_int_range(0, 16777215), COOLIX_BASE_SCHEMA) + + +@register_binary_sensor("coolix", CoolixBinarySensor, COOLIX_SENSOR_SCHEMA) def coolix_binary_sensor(var, config): - cg.add( - var.set_data( - cg.StructInitializer( - CoolixData, - ("data", config[CONF_DATA]), + if isinstance(config, dict): + cg.add( + var.set_data( + cg.StructInitializer( + CoolixData, + ("first", config[CONF_FIRST]), + ("second", config[CONF_SECOND]), + ) ) ) - ) + else: + cg.add( + var.set_data( + cg.StructInitializer(CoolixData, ("first", 0), ("second", config)) + ) + ) + + +@register_action("coolix", CoolixAction, COOLIX_BASE_SCHEMA) +async def coolix_action(var, config, args): + template_ = await cg.templatable(config[CONF_FIRST], args, cg.uint32) + cg.add(var.set_first(template_)) + template_ = await cg.templatable(config[CONF_SECOND], args, cg.uint32) + cg.add(var.set_second(template_)) @register_trigger("coolix", CoolixTrigger, CoolixData) @@ -374,12 +405,6 @@ def coolix_dumper(var, config): pass -@register_action("coolix", CoolixAction, COOLIX_SCHEMA) -async def coolix_action(var, config, args): - template_ = await cg.templatable(config[CONF_DATA], args, cg.uint32) - cg.add(var.set_data(template_)) - - # Dish DishData, DishBinarySensor, DishTrigger, DishAction, DishDumper = declare_protocol( "Dish" diff --git a/esphome/components/remote_base/coolix_protocol.cpp b/esphome/components/remote_base/coolix_protocol.cpp index 252b6f0e91..3c9dadcd1c 100644 --- a/esphome/components/remote_base/coolix_protocol.cpp +++ b/esphome/components/remote_base/coolix_protocol.cpp @@ -15,11 +15,21 @@ static const int32_t BIT_ZERO_SPACE_US = 1 * TICK_US; static const int32_t FOOTER_MARK_US = 1 * TICK_US; static const int32_t FOOTER_SPACE_US = 10 * TICK_US; -static void encode_data(RemoteTransmitData *dst, const CoolixData &src) { - // Break data into bytes, starting at the Most Significant - // Byte. Each byte then being sent normal, then followed inverted. +bool CoolixData::operator==(const CoolixData &other) const { + if (this->first == 0) + return this->second == other.first || this->second == other.second; + if (other.first == 0) + return other.second == this->first || other.second == this->second; + return this->first == other.first && this->second == other.second; +} + +static void encode_frame(RemoteTransmitData *dst, const uint32_t &src) { + // Append header + dst->item(HEADER_MARK_US, HEADER_SPACE_US); + // Break data into bytes, starting at the Most Significant + // Byte. Each byte then being sent normal, then followed inverted. for (unsigned shift = 16;; shift -= 8) { - // Grab a bytes worth of data. + // Grab a bytes worth of data const uint8_t byte = src >> shift; // Normal for (uint8_t mask = 1 << 7; mask; mask >>= 1) @@ -27,27 +37,33 @@ static void encode_data(RemoteTransmitData *dst, const CoolixData &src) { // Inverted for (uint8_t mask = 1 << 7; mask; mask >>= 1) dst->item(BIT_MARK_US, (byte & mask) ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US); - // Data end - if (shift == 0) + // End of frame + if (shift == 0) { + // Append footer + dst->mark(FOOTER_MARK_US); break; + } } } void CoolixProtocol::encode(RemoteTransmitData *dst, const CoolixData &data) { dst->set_carrier_frequency(38000); - dst->reserve(2 + 2 * 48 + 2 + 2 + 2 * 48 + 1); - dst->item(HEADER_MARK_US, HEADER_SPACE_US); - encode_data(dst, data); - dst->item(FOOTER_MARK_US, FOOTER_SPACE_US); - dst->item(HEADER_MARK_US, HEADER_SPACE_US); - encode_data(dst, data); - dst->mark(FOOTER_MARK_US); + dst->reserve(100 + 100 * data.has_second()); + encode_frame(dst, data.first); + if (data.has_second()) { + dst->space(FOOTER_SPACE_US); + encode_frame(dst, data.second); + } } -static bool decode_data(RemoteReceiveData &src, CoolixData &dst) { +static bool decode_frame(RemoteReceiveData &src, uint32_t &dst) { + // Checking for header + if (!src.expect_item(HEADER_MARK_US, HEADER_SPACE_US)) + return false; + // Reading data uint32_t data = 0; for (unsigned n = 3;; data <<= 8) { - // Read byte + // Reading byte for (uint32_t mask = 1 << 7; mask; mask >>= 1) { if (!src.expect_mark(BIT_MARK_US)) return false; @@ -57,13 +73,16 @@ static bool decode_data(RemoteReceiveData &src, CoolixData &dst) { return false; } } - // Check for inverse byte + // Checking for inverted byte for (uint32_t mask = 1 << 7; mask; mask >>= 1) { if (!src.expect_item(BIT_MARK_US, (data & mask) ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US)) return false; } - // Checking the end of reading + // End of frame if (--n == 0) { + // Checking for footer + if (!src.expect_mark(FOOTER_MARK_US)) + return false; dst = data; return true; } @@ -71,15 +90,24 @@ static bool decode_data(RemoteReceiveData &src, CoolixData &dst) { } optional CoolixProtocol::decode(RemoteReceiveData data) { - CoolixData first, second; - if (data.expect_item(HEADER_MARK_US, HEADER_SPACE_US) && decode_data(data, first) && - data.expect_item(FOOTER_MARK_US, FOOTER_SPACE_US) && data.expect_item(HEADER_MARK_US, HEADER_SPACE_US) && - decode_data(data, second) && data.expect_mark(FOOTER_MARK_US) && first == second) - return first; - return {}; + CoolixData result; + const auto size = data.size(); + if ((size != 200 && size != 100) || !decode_frame(data, result.first)) + return {}; + if (size == 100 || !data.expect_space(FOOTER_SPACE_US) || !decode_frame(data, result.second)) + result.second = 0; + return result; } -void CoolixProtocol::dump(const CoolixData &data) { ESP_LOGD(TAG, "Received Coolix: 0x%06X", data); } +void CoolixProtocol::dump(const CoolixData &data) { + if (data.is_strict()) { + ESP_LOGD(TAG, "Received Coolix: 0x%06X", data.first); + } else if (data.has_second()) { + ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X, 0x%06X]", data.first, data.second); + } else { + ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X]", data.first); + } +} } // namespace remote_base } // namespace esphome diff --git a/esphome/components/remote_base/coolix_protocol.h b/esphome/components/remote_base/coolix_protocol.h index 9ce3eabb0e..50ac839200 100644 --- a/esphome/components/remote_base/coolix_protocol.h +++ b/esphome/components/remote_base/coolix_protocol.h @@ -7,7 +7,16 @@ namespace esphome { namespace remote_base { -using CoolixData = uint32_t; +struct CoolixData { + CoolixData() {} + CoolixData(uint32_t a) : first(a), second(a) {} + CoolixData(uint32_t a, uint32_t b) : first(a), second(b) {} + bool operator==(const CoolixData &other) const; + bool is_strict() const { return this->first == this->second; } + bool has_second() const { return this->second != 0; } + uint32_t first; + uint32_t second; +}; class CoolixProtocol : public RemoteProtocol { public: @@ -19,10 +28,10 @@ class CoolixProtocol : public RemoteProtocol { DECLARE_REMOTE_PROTOCOL(Coolix) template class CoolixAction : public RemoteTransmitterActionBase { - TEMPLATABLE_VALUE(CoolixData, data) + TEMPLATABLE_VALUE(uint32_t, first) + TEMPLATABLE_VALUE(uint32_t, second) void encode(RemoteTransmitData *dst, Ts... x) override { - CoolixData data = this->data_.value(x...); - CoolixProtocol().encode(dst, data); + CoolixProtocol().encode(dst, {this->first_.value(x...), this->second_.value(x...)}); } }; diff --git a/tests/test1.yaml b/tests/test1.yaml index bf099e2844..67e675ef3a 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1594,6 +1594,18 @@ binary_sensor: -2267, 1709, ] + - platform: remote_receiver + name: Coolix Test 1 + coolix: 0xB21F98 + - platform: remote_receiver + name: Coolix Test 2 + coolix: + first: 0xB2E003 + - platform: remote_receiver + name: Coolix Test 3 + coolix: + first: 0xB2E003 + second: 0xB21F98 - platform: as3935 name: Storm Alert - platform: analog_threshold @@ -2265,8 +2277,16 @@ switch: - platform: template name: MIDEA_RAW turn_on_action: - remote_transmitter.transmit_midea: - code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF] + - remote_transmitter.transmit_coolix: + first: 0xB21F98 + - remote_transmitter.transmit_coolix: + first: 0xB21F98 + second: 0xB21F98 + - remote_transmitter.transmit_coolix: + first: !lambda "return 0xB21F98;" + second: !lambda "return 0xB21F98;" + - remote_transmitter.transmit_midea: + code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF] - platform: gpio name: "MCP23S08 Pin #0" pin: @@ -2846,6 +2866,9 @@ tm1651: remote_receiver: pin: GPIO32 dump: all + on_coolix: + then: + delay: !lambda "return x.first + x.second;" status_led: pin: GPIO2 From b0966532bfdeedb65dbbd66ecc0eee8d08606e5b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:22:46 +1200 Subject: [PATCH 0267/2607] Allow esp32 idf components to specify submodules and specific components (#5128) --- esphome/components/esp32/__init__.py | 53 ++++++++++++++++++++++------ esphome/components/esp32/const.py | 1 + esphome/components/mdns/__init__.py | 8 ++--- esphome/git.py | 18 ++++++++++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index f8e78794b2..7daaaf7433 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Union +from typing import Union, Optional from pathlib import Path import logging import os @@ -42,6 +42,7 @@ from .const import ( # noqa KEY_REFRESH, KEY_REPO, KEY_SDKCONFIG_OPTIONS, + KEY_SUBMODULES, KEY_VARIANT, VARIANT_ESP32C3, VARIANT_FRIENDLY, @@ -120,17 +121,28 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType): def add_idf_component( - name: str, repo: str, ref: str = None, path: str = None, refresh: TimePeriod = None + *, + name: str, + repo: str, + ref: str = None, + path: str = None, + refresh: TimePeriod = None, + components: Optional[list[str]] = None, + submodules: Optional[list[str]] = None, ): """Add an esp-idf component to the project.""" if not CORE.using_esp_idf: raise ValueError("Not an esp-idf project") + if components is None: + components = [] if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]: CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = { KEY_REPO: repo, KEY_REF: ref, KEY_PATH: path, KEY_REFRESH: refresh, + KEY_COMPONENTS: components, + KEY_SUBMODULES: submodules, } @@ -536,20 +548,41 @@ def copy_files(): ref=component[KEY_REF], refresh=component[KEY_REFRESH], domain="idf_components", + submodules=component[KEY_SUBMODULES], ) mkdir_p(CORE.relative_build_path("components")) component_dir = repo_dir if component[KEY_PATH] is not None: component_dir = component_dir / component[KEY_PATH] - shutil.copytree( - component_dir, - CORE.relative_build_path(f"components/{name}"), - dirs_exist_ok=True, - ignore=shutil.ignore_patterns(".git", ".github"), - symlinks=True, - ignore_dangling_symlinks=True, - ) + if component[KEY_COMPONENTS] == ["*"]: + shutil.copytree( + component_dir, + CORE.relative_build_path("components"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) + elif len(component[KEY_COMPONENTS]) > 0: + for comp in component[KEY_COMPONENTS]: + shutil.copytree( + component_dir / comp, + CORE.relative_build_path(f"components/{comp}"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) + else: + shutil.copytree( + component_dir, + CORE.relative_build_path(f"components/{name}"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) dir = os.path.dirname(__file__) post_build_file = os.path.join(dir, "post_build.py.script") diff --git a/esphome/components/esp32/const.py b/esphome/components/esp32/const.py index d13df01d3a..698310dacb 100644 --- a/esphome/components/esp32/const.py +++ b/esphome/components/esp32/const.py @@ -9,6 +9,7 @@ KEY_REPO = "repo" KEY_REF = "ref" KEY_REFRESH = "refresh" KEY_PATH = "path" +KEY_SUBMODULES = "submodules" VARIANT_ESP32 = "ESP32" VARIANT_ESP32S2 = "ESP32S2" diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index d9b36c7b09..e7d700d149 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -86,10 +86,10 @@ async def to_code(config): 5, 0, 0 ): add_idf_component( - "mdns", - "https://github.com/espressif/esp-protocols.git", - "mdns-v1.0.9", - "components/mdns", + name="mdns", + repo="https://github.com/espressif/esp-protocols.git", + ref="mdns-v1.0.9", + path="components/mdns", ) if config[CONF_DISABLED]: diff --git a/esphome/git.py b/esphome/git.py index a607325b73..dcc3e4d0c8 100644 --- a/esphome/git.py +++ b/esphome/git.py @@ -15,6 +15,7 @@ _LOGGER = logging.getLogger(__name__) def run_git_command(cmd, cwd=None) -> str: + _LOGGER.debug("Running git command: %s", " ".join(cmd)) try: ret = subprocess.run(cmd, cwd=cwd, capture_output=True, check=False) except FileNotFoundError as err: @@ -48,6 +49,7 @@ def clone_or_update( domain: str, username: str = None, password: str = None, + submodules: Optional[list[str]] = None, ) -> tuple[Path, Optional[Callable[[], None]]]: key = f"{url}@{ref}" @@ -74,6 +76,14 @@ def clone_or_update( run_git_command(["git", "fetch", "--", "origin", ref], str(repo_dir)) run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir)) + if submodules is not None: + _LOGGER.info( + "Initialising submodules (%s) for %s", ", ".join(submodules), key + ) + run_git_command( + ["git", "submodule", "update", "--init"] + submodules, str(repo_dir) + ) + else: # Check refresh needed file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD") @@ -97,6 +107,14 @@ def clone_or_update( # Hard reset to FETCH_HEAD (short-lived git ref corresponding to most recent fetch) run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir)) + if submodules is not None: + _LOGGER.info( + "Updating submodules (%s) for %s", ", ".join(submodules), key + ) + run_git_command( + ["git", "submodule", "update", "--init"] + submodules, str(repo_dir) + ) + def revert(): _LOGGER.info("Reverting changes to %s -> %s", key, old_sha) run_git_command(["git", "reset", "--hard", old_sha], str(repo_dir)) From 959d1944fddf0d8396fc217b4e3b11c39d2c479e Mon Sep 17 00:00:00 2001 From: esphomebot Date: Mon, 24 Jul 2023 19:17:18 +1200 Subject: [PATCH 0268/2607] Synchronise Device Classes from Home Assistant (#5147) --- esphome/components/number/__init__.py | 2 ++ esphome/components/sensor/__init__.py | 2 ++ esphome/const.py | 1 + 3 files changed, 5 insertions(+) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index f45b8c024a..e6ad545d70 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -43,6 +43,7 @@ from esphome.const import ( DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -97,6 +98,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index caaffd9701..2aebf7bb17 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -57,6 +57,7 @@ from esphome.const import ( DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -114,6 +115,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, diff --git a/esphome/const.py b/esphome/const.py index 1c4ccdf3a4..4977726361 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -988,6 +988,7 @@ DEVICE_CLASS_OCCUPANCY = "occupancy" DEVICE_CLASS_OPENING = "opening" DEVICE_CLASS_OUTLET = "outlet" DEVICE_CLASS_OZONE = "ozone" +DEVICE_CLASS_PH = "ph" DEVICE_CLASS_PLUG = "plug" DEVICE_CLASS_PM1 = "pm1" DEVICE_CLASS_PM10 = "pm10" From 3eff7e76aa42d440c2f89526bfdf47773dfbe0bb Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 27 Jul 2023 07:18:02 +0200 Subject: [PATCH 0269/2607] Prepare some components for idf >= 5 (#5061) --- .../components/airthings_ble/airthings_listener.cpp | 3 ++- esphome/components/bedjet/bedjet_hub.cpp | 7 ++++--- esphome/components/esp32_ble/ble_uuid.cpp | 3 ++- .../esp32_ble_tracker/esp32_ble_tracker.cpp | 3 ++- esphome/components/ina226/ina226.cpp | 3 ++- esphome/components/max31865/max31865.cpp | 6 ++++-- esphome/components/sen5x/sen5x.cpp | 13 +++++++------ esphome/components/uart/uart.cpp | 5 +++-- esphome/components/uart/uart_component_esp_idf.cpp | 7 ++++--- .../waveshare_epaper/waveshare_epaper.cpp | 3 ++- 10 files changed, 32 insertions(+), 21 deletions(-) diff --git a/esphome/components/airthings_ble/airthings_listener.cpp b/esphome/components/airthings_ble/airthings_listener.cpp index 951961cb1b..a36d614df5 100644 --- a/esphome/components/airthings_ble/airthings_listener.cpp +++ b/esphome/components/airthings_ble/airthings_listener.cpp @@ -1,5 +1,6 @@ #include "airthings_listener.h" #include "esphome/core/log.h" +#include #ifdef USE_ESP32 @@ -19,7 +20,7 @@ bool AirthingsListener::parse_device(const esp32_ble_tracker::ESPBTDevice &devic sn |= ((uint32_t) it.data[2] << 16); sn |= ((uint32_t) it.data[3] << 24); - ESP_LOGD(TAG, "Found AirThings device Serial:%u (MAC: %s)", sn, device.address_str().c_str()); + ESP_LOGD(TAG, "Found AirThings device Serial:%" PRIu32 " (MAC: %s)", sn, device.address_str().c_str()); return true; } } diff --git a/esphome/components/bedjet/bedjet_hub.cpp b/esphome/components/bedjet/bedjet_hub.cpp index c355953d94..7933a35a97 100644 --- a/esphome/components/bedjet/bedjet_hub.cpp +++ b/esphome/components/bedjet/bedjet_hub.cpp @@ -3,6 +3,7 @@ #include "bedjet_hub.h" #include "bedjet_child.h" #include "bedjet_const.h" +#include namespace esphome { namespace bedjet { @@ -373,7 +374,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga if (this->last_notify_ == 0 || delta > MIN_NOTIFY_THROTTLE || this->force_refresh_) { // Set reentrant flag to prevent processing multiple packets. this->processing_ = true; - ESP_LOGVV(TAG, "[%s] Decoding packet: last=%d, delta=%d, force=%s", this->get_name().c_str(), + ESP_LOGVV(TAG, "[%s] Decoding packet: last=%" PRId32 ", delta=%" PRId32 ", force=%s", this->get_name().c_str(), this->last_notify_, delta, this->force_refresh_ ? "y" : "n"); bool needs_extra = this->codec_->decode_notify(param->notify.value, param->notify.value_len); @@ -523,11 +524,11 @@ void BedJetHub::dispatch_status_() { ESP_LOGI(TAG, "[%s] Still waiting for first GATT notify event.", this->get_name().c_str()); } else if (diff > NOTIFY_WARN_THRESHOLD) { - ESP_LOGW(TAG, "[%s] Last GATT notify was %d seconds ago.", this->get_name().c_str(), diff / 1000); + ESP_LOGW(TAG, "[%s] Last GATT notify was %" PRId32 " seconds ago.", this->get_name().c_str(), diff / 1000); } if (this->timeout_ > 0 && diff > this->timeout_ && this->parent()->enabled) { - ESP_LOGW(TAG, "[%s] Timed out after %d sec. Retrying...", this->get_name().c_str(), this->timeout_); + ESP_LOGW(TAG, "[%s] Timed out after %" PRId32 " sec. Retrying...", this->get_name().c_str(), this->timeout_); // set_enabled(false) will only close the connection if state != IDLE. this->parent()->set_state(espbt::ClientState::CONNECTING); this->parent()->set_enabled(false); diff --git a/esphome/components/esp32_ble/ble_uuid.cpp b/esphome/components/esp32_ble/ble_uuid.cpp index a50d3dbd42..57c2f9df94 100644 --- a/esphome/components/esp32_ble/ble_uuid.cpp +++ b/esphome/components/esp32_ble/ble_uuid.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "esphome/core/log.h" namespace esphome { @@ -166,7 +167,7 @@ std::string ESPBTUUID::to_string() const { case ESP_UUID_LEN_16: return str_snprintf("0x%02X%02X", 6, this->uuid_.uuid.uuid16 >> 8, this->uuid_.uuid.uuid16 & 0xff); case ESP_UUID_LEN_32: - return str_snprintf("0x%02X%02X%02X%02X", 10, this->uuid_.uuid.uuid32 >> 24, + return str_snprintf("0x%02" PRIX32 "%02" PRIX32 "%02" PRIX32 "%02" PRIX32, 10, (this->uuid_.uuid.uuid32 >> 24), (this->uuid_.uuid.uuid32 >> 16 & 0xff), (this->uuid_.uuid.uuid32 >> 8 & 0xff), this->uuid_.uuid.uuid32 & 0xff); default: diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 1569ea0dd5..f67f29477d 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef USE_OTA #include "esphome/components/ota/ota_component.h" @@ -614,7 +615,7 @@ uint64_t ESPBTDevice::address_uint64() const { return esp32_ble::ble_addr_to_uin void ESP32BLETracker::dump_config() { ESP_LOGCONFIG(TAG, "BLE Tracker:"); - ESP_LOGCONFIG(TAG, " Scan Duration: %u s", this->scan_duration_); + ESP_LOGCONFIG(TAG, " Scan Duration: %" PRIu32 " s", this->scan_duration_); ESP_LOGCONFIG(TAG, " Scan Interval: %.1f ms", this->scan_interval_ * 0.625f); ESP_LOGCONFIG(TAG, " Scan Window: %.1f ms", this->scan_window_ * 0.625f); ESP_LOGCONFIG(TAG, " Scan Type: %s", this->scan_active_ ? "ACTIVE" : "PASSIVE"); diff --git a/esphome/components/ina226/ina226.cpp b/esphome/components/ina226/ina226.cpp index 2e30a5ac01..1fb859da66 100644 --- a/esphome/components/ina226/ina226.cpp +++ b/esphome/components/ina226/ina226.cpp @@ -1,6 +1,7 @@ #include "ina226.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include namespace esphome { namespace ina226 { @@ -68,7 +69,7 @@ void INA226Component::setup() { auto calibration = uint32_t(0.00512 / (lsb * this->shunt_resistance_ohm_ / 1000000.0f)); - ESP_LOGV(TAG, " Using LSB=%u calibration=%u", lsb, calibration); + ESP_LOGV(TAG, " Using LSB=%" PRIu32 " calibration=%" PRIu32, lsb, calibration); if (!this->write_byte_16(INA226_REGISTER_CALIBRATION, calibration)) { this->mark_failed(); diff --git a/esphome/components/max31865/max31865.cpp b/esphome/components/max31865/max31865.cpp index 152d7b340b..b48aa2fdd3 100644 --- a/esphome/components/max31865/max31865.cpp +++ b/esphome/components/max31865/max31865.cpp @@ -2,6 +2,7 @@ #include "esphome/core/log.h" #include +#include namespace esphome { namespace max31865 { @@ -45,14 +46,15 @@ void MAX31865Sensor::update() { config = this->read_register_(CONFIGURATION_REG); fault_detect_time = micros() - start_time; if ((fault_detect_time >= 6000) && (config & 0b00001100)) { - ESP_LOGE(TAG, "Fault detection incomplete (0x%02X) after %uμs (datasheet spec is 600μs max)! Aborting read.", + ESP_LOGE(TAG, + "Fault detection incomplete (0x%02X) after %" PRIu32 "μs (datasheet spec is 600μs max)! Aborting read.", config, fault_detect_time); this->publish_state(NAN); this->status_set_error(); return; } } while (config & 0b00001100); - ESP_LOGV(TAG, "Fault detection completed in %uμs.", fault_detect_time); + ESP_LOGV(TAG, "Fault detection completed in %" PRIu32 "μs.", fault_detect_time); // Start 1-shot conversion this->write_config_(0b11100000, 0b10100000); diff --git a/esphome/components/sen5x/sen5x.cpp b/esphome/components/sen5x/sen5x.cpp index ddce568c97..8b4dcda9ef 100644 --- a/esphome/components/sen5x/sen5x.cpp +++ b/esphome/components/sen5x/sen5x.cpp @@ -1,6 +1,7 @@ #include "sen5x.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" +#include namespace esphome { namespace sen5x { @@ -140,15 +141,15 @@ void SEN5XComponent::setup() { this->pref_ = global_preferences->make_preference(hash, true); if (this->pref_.load(&this->voc_baselines_storage_)) { - ESP_LOGI(TAG, "Loaded VOC baseline state0: 0x%04X, state1: 0x%04X", this->voc_baselines_storage_.state0, - voc_baselines_storage_.state1); + ESP_LOGI(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, + this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); } // Initialize storage timestamp this->seconds_since_last_store_ = 0; if (this->voc_baselines_storage_.state0 > 0 && this->voc_baselines_storage_.state1 > 0) { - ESP_LOGI(TAG, "Setting VOC baseline from save state0: 0x%04X, state1: 0x%04X", + ESP_LOGI(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); uint16_t states[4]; @@ -252,7 +253,7 @@ void SEN5XComponent::dump_config() { ESP_LOGCONFIG(TAG, " Firmware version: %d", this->firmware_version_); ESP_LOGCONFIG(TAG, " Serial number %02d.%02d.%02d", serial_number_[0], serial_number_[1], serial_number_[2]); if (this->auto_cleaning_interval_.has_value()) { - ESP_LOGCONFIG(TAG, " Auto cleaning interval %d seconds", auto_cleaning_interval_.value()); + ESP_LOGCONFIG(TAG, " Auto cleaning interval %" PRId32 " seconds", auto_cleaning_interval_.value()); } if (this->acceleration_mode_.has_value()) { switch (this->acceleration_mode_.value()) { @@ -302,8 +303,8 @@ void SEN5XComponent::update() { this->voc_baselines_storage_.state1 = state1; if (this->pref_.save(&this->voc_baselines_storage_)) { - ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04X ,state1: 0x%04X", this->voc_baselines_storage_.state0, - voc_baselines_storage_.state1); + ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 " ,state1: 0x%04" PRIX32, + this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); } else { ESP_LOGW(TAG, "Could not store VOC baselines"); } diff --git a/esphome/components/uart/uart.cpp b/esphome/components/uart/uart.cpp index 22a22e2772..9834462ff9 100644 --- a/esphome/components/uart/uart.cpp +++ b/esphome/components/uart/uart.cpp @@ -3,6 +3,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/application.h" #include "esphome/core/defines.h" +#include namespace esphome { namespace uart { @@ -12,8 +13,8 @@ static const char *const TAG = "uart"; void UARTDevice::check_uart_settings(uint32_t baud_rate, uint8_t stop_bits, UARTParityOptions parity, uint8_t data_bits) { if (this->parent_->get_baud_rate() != baud_rate) { - ESP_LOGE(TAG, " Invalid baud_rate: Integration requested baud_rate %u but you have %u!", baud_rate, - this->parent_->get_baud_rate()); + ESP_LOGE(TAG, " Invalid baud_rate: Integration requested baud_rate %" PRIu32 " but you have %" PRIu32 "!", + baud_rate, this->parent_->get_baud_rate()); } if (this->parent_->get_stop_bits() != stop_bits) { ESP_LOGE(TAG, " Invalid stop bits: Integration requested stop_bits %u but you have %u!", stop_bits, diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 1560409772..ae772fa8f8 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -5,6 +5,7 @@ #include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include #ifdef USE_LOGGER #include "esphome/components/logger/logger.h" @@ -125,7 +126,7 @@ void IDFUARTComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } - ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); + ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_); ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); @@ -150,7 +151,7 @@ bool IDFUARTComponent::peek_byte(uint8_t *data) { if (this->has_peek_) { *data = this->peek_byte_; } else { - int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_RATE_MS); + int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS); if (len == 0) { *data = 0; } else { @@ -174,7 +175,7 @@ bool IDFUARTComponent::read_array(uint8_t *data, size_t len) { this->has_peek_ = false; } if (length_to_read > 0) - uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_RATE_MS); + uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS); xSemaphoreGive(this->lock_); #ifdef USE_UART_DEBUGGER for (size_t i = 0; i < len; i++) { diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index d64a5500dd..a3b1ec7d7b 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -2,6 +2,7 @@ #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include namespace esphome { namespace waveshare_epaper { @@ -250,7 +251,7 @@ void WaveshareEPaperTypeA::dump_config() { ESP_LOGCONFIG(TAG, " Model: 2.9inV2"); break; } - ESP_LOGCONFIG(TAG, " Full Update Every: %u", this->full_update_every_); + ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_); LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Busy Pin: ", this->busy_pin_); From cd72a2ed7eff504089adcf5fc8d37c9ddfdaf86c Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Sun, 30 Jul 2023 23:44:56 +0400 Subject: [PATCH 0270/2607] Bump clang-tidy from 11 to 14 (#5160) --- .clang-tidy | 15 +++++++++++++-- .github/workflows/ci.yml | 2 +- esphome/components/logger/logger.cpp | 2 +- .../components/matrix_keypad/matrix_keypad.cpp | 6 ++++-- esphome/components/remote_base/midea_protocol.h | 2 -- esphome/components/ssd1322_spi/ssd1322_spi.cpp | 3 +-- esphome/components/ssd1325_spi/ssd1325_spi.cpp | 3 +-- esphome/components/ssd1327_spi/ssd1327_spi.cpp | 3 +-- esphome/components/ssd1331_spi/ssd1331_spi.cpp | 3 +-- esphome/components/ssd1351_spi/ssd1351_spi.cpp | 3 +-- esphome/components/tlc5947/tlc5947.cpp | 3 +-- .../vbus/binary_sensor/vbus_binary_sensor.cpp | 3 ++- esphome/components/vbus/sensor/vbus_sensor.cpp | 3 ++- .../components/voice_assistant/voice_assistant.h | 1 - .../wifi/wifi_component_esp32_arduino.cpp | 2 +- .../components/wifi/wifi_component_esp_idf.cpp | 2 +- script/clang-tidy | 12 ++++++------ 17 files changed, 37 insertions(+), 31 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index c9b77b5720..946f2950d8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,9 +5,12 @@ Checks: >- -altera-*, -android-*, -boost-*, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, -bugprone-narrowing-conversions, -bugprone-signed-char-misuse, -cert-dcl50-cpp, + -cert-err33-c, -cert-err58-cpp, -cert-oop57-cpp, -cert-str34-c, @@ -15,6 +18,7 @@ Checks: >- -clang-analyzer-osx.*, -clang-diagnostic-delete-abstract-non-virtual-dtor, -clang-diagnostic-delete-non-abstract-non-virtual-dtor, + -clang-diagnostic-ignored-optimization-argument, -clang-diagnostic-shadow-field, -clang-diagnostic-unused-const-variable, -clang-diagnostic-unused-parameter, @@ -25,6 +29,7 @@ Checks: >- -cppcoreguidelines-macro-usage, -cppcoreguidelines-narrowing-conversions, -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-prefer-member-initializer, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, @@ -36,6 +41,7 @@ Checks: >- -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-special-member-functions, + -cppcoreguidelines-virtual-class-destructor, -fuchsia-multiple-inheritance, -fuchsia-overloaded-operator, -fuchsia-statically-constructed-objects, @@ -68,6 +74,7 @@ Checks: >- -modernize-use-nodiscard, -mpi-*, -objc-*, + -readability-container-data-pointer, -readability-convert-member-functions-to-static, -readability-else-after-return, -readability-function-cognitive-complexity, @@ -82,8 +89,6 @@ WarningsAsErrors: '*' AnalyzeTemporaryDtors: false FormatStyle: google CheckOptions: - - key: google-readability-braces-around-statements.ShortStatementLines - value: '1' - key: google-readability-function-size.StatementThreshold value: '800' - key: google-runtime-int.TypeSuffix @@ -158,3 +163,9 @@ CheckOptions: value: '' - key: readability-qualified-auto.AddConstToQualified value: 0 + - key: readability-identifier-length.MinimumVariableNameLength + value: 0 + - key: readability-identifier-length.MinimumParameterNameLength + value: 0 + - key: readability-identifier-length.MinimumLoopCounterNameLength + value: 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7775a996fc..ba46936952 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,7 +305,7 @@ jobs: key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} - name: Install clang-tidy - run: sudo apt-get install clang-tidy-11 + run: sudo apt-get install clang-tidy-14 - name: Register problem matchers run: | diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 8fd39265fd..ca4cc64007 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -125,7 +125,7 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { #elif defined(USE_ESP32_VARIANT_ESP32S3) uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG #else - /* DISABLES CODE */ (false) + /* DISABLES CODE */ (false) // NOLINT #endif ) { puts(msg); diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index f4e7bf4d23..4f8962a782 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -89,11 +89,13 @@ void MatrixKeypad::loop() { void MatrixKeypad::dump_config() { ESP_LOGCONFIG(TAG, "Matrix Keypad:"); ESP_LOGCONFIG(TAG, " Rows:"); - for (auto &pin : this->rows_) + for (auto &pin : this->rows_) { LOG_PIN(" Pin: ", pin); + } ESP_LOGCONFIG(TAG, " Cols:"); - for (auto &pin : this->columns_) + for (auto &pin : this->columns_) { LOG_PIN(" Pin: ", pin); + } } void MatrixKeypad::register_listener(MatrixKeypadListener *listener) { this->listeners_.push_back(listener); } diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index a7f5636b06..d81a50241b 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -22,8 +22,6 @@ class MideaData { MideaData(const std::vector &data) { std::copy_n(data.begin(), std::min(data.size(), this->data_.size()), this->data_.begin()); } - // Default copy constructor - MideaData(const MideaData &) = default; uint8_t *data() { return this->data_.data(); } const uint8_t *data() const { return this->data_.data(); } diff --git a/esphome/components/ssd1322_spi/ssd1322_spi.cpp b/esphome/components/ssd1322_spi/ssd1322_spi.cpp index 50c46c4d02..a841c5606e 100644 --- a/esphome/components/ssd1322_spi/ssd1322_spi.cpp +++ b/esphome/components/ssd1322_spi/ssd1322_spi.cpp @@ -21,8 +21,7 @@ void SPISSD1322::setup() { void SPISSD1322::dump_config() { LOG_DISPLAY("", "SPI SSD1322", this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); - if (this->cs_) - LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); ESP_LOGCONFIG(TAG, " Initial Brightness: %.2f", this->brightness_); diff --git a/esphome/components/ssd1325_spi/ssd1325_spi.cpp b/esphome/components/ssd1325_spi/ssd1325_spi.cpp index 98f48b8538..8a95bfeae3 100644 --- a/esphome/components/ssd1325_spi/ssd1325_spi.cpp +++ b/esphome/components/ssd1325_spi/ssd1325_spi.cpp @@ -21,8 +21,7 @@ void SPISSD1325::setup() { void SPISSD1325::dump_config() { LOG_DISPLAY("", "SPI SSD1325", this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); - if (this->cs_) - LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); ESP_LOGCONFIG(TAG, " Initial Brightness: %.2f", this->brightness_); diff --git a/esphome/components/ssd1327_spi/ssd1327_spi.cpp b/esphome/components/ssd1327_spi/ssd1327_spi.cpp index 1dd2b73e66..c6ae377119 100644 --- a/esphome/components/ssd1327_spi/ssd1327_spi.cpp +++ b/esphome/components/ssd1327_spi/ssd1327_spi.cpp @@ -21,8 +21,7 @@ void SPISSD1327::setup() { void SPISSD1327::dump_config() { LOG_DISPLAY("", "SPI SSD1327", this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); - if (this->cs_) - LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); ESP_LOGCONFIG(TAG, " Initial Brightness: %.2f", this->brightness_); diff --git a/esphome/components/ssd1331_spi/ssd1331_spi.cpp b/esphome/components/ssd1331_spi/ssd1331_spi.cpp index ff42c74b9f..88116f6c00 100644 --- a/esphome/components/ssd1331_spi/ssd1331_spi.cpp +++ b/esphome/components/ssd1331_spi/ssd1331_spi.cpp @@ -20,8 +20,7 @@ void SPISSD1331::setup() { } void SPISSD1331::dump_config() { LOG_DISPLAY("", "SPI SSD1331", this); - if (this->cs_) - LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); ESP_LOGCONFIG(TAG, " Initial Brightness: %.2f", this->brightness_); diff --git a/esphome/components/ssd1351_spi/ssd1351_spi.cpp b/esphome/components/ssd1351_spi/ssd1351_spi.cpp index 9599c6e644..b71b8f4f88 100644 --- a/esphome/components/ssd1351_spi/ssd1351_spi.cpp +++ b/esphome/components/ssd1351_spi/ssd1351_spi.cpp @@ -21,8 +21,7 @@ void SPISSD1351::setup() { void SPISSD1351::dump_config() { LOG_DISPLAY("", "SPI SSD1351", this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); - if (this->cs_) - LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); ESP_LOGCONFIG(TAG, " Initial Brightness: %.2f", this->brightness_); diff --git a/esphome/components/tlc5947/tlc5947.cpp b/esphome/components/tlc5947/tlc5947.cpp index a7e08c8341..8f3f60f087 100644 --- a/esphome/components/tlc5947/tlc5947.cpp +++ b/esphome/components/tlc5947/tlc5947.cpp @@ -27,8 +27,7 @@ void TLC5947::dump_config() { LOG_PIN(" Data Pin: ", this->data_pin_); LOG_PIN(" Clock Pin: ", this->clock_pin_); LOG_PIN(" LAT Pin: ", this->lat_pin_); - if (this->outenable_pin_ != nullptr) - LOG_PIN(" OE Pin: ", this->outenable_pin_); + LOG_PIN(" OE Pin: ", this->outenable_pin_); ESP_LOGCONFIG(TAG, " Number of chips: %u", this->num_chips_); } diff --git a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp index 087d049a57..4ccd149935 100644 --- a/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp +++ b/esphome/components/vbus/binary_sensor/vbus_binary_sensor.cpp @@ -147,8 +147,9 @@ void VBusCustomBSensor::dump_config() { ESP_LOGCONFIG(TAG, " Command: 0x%04x", this->command_); } ESP_LOGCONFIG(TAG, " Binary Sensors:"); - for (VBusCustomSubBSensor *bsensor : this->bsensors_) + for (VBusCustomSubBSensor *bsensor : this->bsensors_) { LOG_BINARY_SENSOR(" ", "-", bsensor); + } } void VBusCustomBSensor::handle_message(std::vector &message) { diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 5b4f57f73d..e81c0486d4 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -232,8 +232,9 @@ void VBusCustomSensor::dump_config() { ESP_LOGCONFIG(TAG, " Command: 0x%04x", this->command_); } ESP_LOGCONFIG(TAG, " Sensors:"); - for (VBusCustomSubSensor *sensor : this->sensors_) + for (VBusCustomSubSensor *sensor : this->sensors_) { LOG_SENSOR(" ", "-", sensor); + } } void VBusCustomSensor::handle_message(std::vector &message) { diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index e67baaee65..75c17965bc 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -6,7 +6,6 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" -#include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include "esphome/components/api/api_pb2.h" diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index f35f5dfc43..3628eca78d 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -220,7 +220,7 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { esp_err_t err; esp_wifi_get_config(WIFI_IF_STA, ¤t_conf); - if (memcmp(¤t_conf, &conf, sizeof(wifi_config_t)) != 0) { + if (memcmp(¤t_conf, &conf, sizeof(wifi_config_t)) != 0) { // NOLINT err = esp_wifi_disconnect(); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_wifi_disconnect failed! %d", err); diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 744fc755fe..a2bbc8ae09 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -333,7 +333,7 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // can continue } - if (memcmp(¤t_conf, &conf, sizeof(wifi_config_t)) != 0) { + if (memcmp(¤t_conf, &conf, sizeof(wifi_config_t)) != 0) { // NOLINT err = esp_wifi_disconnect(); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_wifi_disconnect failed: %s", esp_err_to_name(err)); diff --git a/script/clang-tidy b/script/clang-tidy index 5d2cba6eb5..d8dd033d29 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -113,7 +113,7 @@ def clang_options(idedata): def run_tidy(args, options, tmpdir, queue, lock, failed_files): while True: path = queue.get() - invocation = ["clang-tidy-11"] + invocation = ["clang-tidy-14"] if tmpdir is not None: invocation.append("--export-fixes") @@ -194,14 +194,14 @@ def main(): args = parser.parse_args() try: - get_output("clang-tidy-11", "-version") + get_output("clang-tidy-14", "-version") except: print( """ - Oops. It looks like clang-tidy-11 is not installed. + Oops. It looks like clang-tidy-14 is not installed. - Please check you can run "clang-tidy-11 -version" in your terminal and install - clang-tidy (v11) if necessary. + Please check you can run "clang-tidy-14 -version" in your terminal and install + clang-tidy (v14) if necessary. Note you can also upload your code as a pull request on GitHub and see the CI check output to apply clang-tidy. @@ -272,7 +272,7 @@ def main(): if args.fix and failed_files: print("Applying fixes ...") try: - subprocess.call(["clang-apply-replacements-11", tmpdir]) + subprocess.call(["clang-apply-replacements-14", tmpdir]) except: print("Error applying fixes.\n", file=sys.stderr) raise From a120a455bfa47da44643a881ae2ac7a4bd224cb5 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Sun, 30 Jul 2023 23:52:01 +0400 Subject: [PATCH 0271/2607] climate triggers Climate and ClimateCall references (#5028) --- esphome/components/climate/__init__.py | 16 ++++++++++++---- esphome/components/climate/automation.h | 8 ++++---- esphome/components/climate/climate.cpp | 8 ++++---- esphome/components/climate/climate.h | 8 ++++---- esphome/components/mqtt/mqtt_climate.cpp | 2 +- esphome/core/controller.cpp | 2 +- tests/test1.yaml | 9 +++++++-- 7 files changed, 33 insertions(+), 20 deletions(-) diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index bf167fe837..85242eb344 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -127,8 +127,12 @@ def single_visual_temperature(value): # Actions ControlAction = climate_ns.class_("ControlAction", automation.Action) -StateTrigger = climate_ns.class_("StateTrigger", automation.Trigger.template()) -ControlTrigger = climate_ns.class_("ControlTrigger", automation.Trigger.template()) +StateTrigger = climate_ns.class_( + "StateTrigger", automation.Trigger.template(Climate.operator("ref")) +) +ControlTrigger = climate_ns.class_( + "ControlTrigger", automation.Trigger.template(ClimateCall.operator("ref")) +) VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any( single_visual_temperature, @@ -322,11 +326,15 @@ async def setup_climate_core_(var, config): for conf in config.get(CONF_ON_STATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - await automation.build_automation(trigger, [], conf) + await automation.build_automation( + trigger, [(Climate.operator("ref"), "x")], conf + ) for conf in config.get(CONF_ON_CONTROL, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - await automation.build_automation(trigger, [], conf) + await automation.build_automation( + trigger, [(ClimateCall.operator("ref"), "x")], conf + ) async def register_climate(var, config): diff --git a/esphome/components/climate/automation.h b/esphome/components/climate/automation.h index 9b06563eb4..382871e1e7 100644 --- a/esphome/components/climate/automation.h +++ b/esphome/components/climate/automation.h @@ -42,17 +42,17 @@ template class ControlAction : public Action { Climate *climate_; }; -class ControlTrigger : public Trigger<> { +class ControlTrigger : public Trigger { public: ControlTrigger(Climate *climate) { - climate->add_on_control_callback([this]() { this->trigger(); }); + climate->add_on_control_callback([this](ClimateCall &x) { this->trigger(x); }); } }; -class StateTrigger : public Trigger<> { +class StateTrigger : public Trigger { public: StateTrigger(Climate *climate) { - climate->add_on_state_callback([this]() { this->trigger(); }); + climate->add_on_state_callback([this](Climate &x) { this->trigger(x); }); } }; diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index a032596eb3..1680601279 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -7,6 +7,7 @@ namespace climate { static const char *const TAG = "climate"; void ClimateCall::perform() { + this->parent_->control_callback_.call(*this); ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str()); this->validate_(); if (this->mode_.has_value()) { @@ -44,7 +45,6 @@ void ClimateCall::perform() { if (this->target_temperature_high_.has_value()) { ESP_LOGD(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_); } - this->parent_->control_callback_.call(); this->parent_->control(*this); } void ClimateCall::validate_() { @@ -300,11 +300,11 @@ ClimateCall &ClimateCall::set_swing_mode(optional swing_mode) return *this; } -void Climate::add_on_state_callback(std::function &&callback) { +void Climate::add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } -void Climate::add_on_control_callback(std::function &&callback) { +void Climate::add_on_control_callback(std::function &&callback) { this->control_callback_.add(std::move(callback)); } @@ -408,7 +408,7 @@ void Climate::publish_state() { } // Send state to frontend - this->state_callback_.call(); + this->state_callback_.call(*this); // Save state this->save_state_(); } diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index 656e1c4852..f90db3f52a 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -198,7 +198,7 @@ class Climate : public EntityBase { * * @param callback The callback to call. */ - void add_on_state_callback(std::function &&callback); + void add_on_state_callback(std::function &&callback); /** * Add a callback for the climate device configuration; each time the configuration parameters of a climate device @@ -206,7 +206,7 @@ class Climate : public EntityBase { * * @param callback The callback to call. */ - void add_on_control_callback(std::function &&callback); + void add_on_control_callback(std::function &&callback); /** Make a climate device control call, this is used to control the climate device, see the ClimateCall description * for more info. @@ -273,8 +273,8 @@ class Climate : public EntityBase { void dump_traits_(const char *tag); - CallbackManager state_callback_{}; - CallbackManager control_callback_{}; + CallbackManager state_callback_{}; + CallbackManager control_callback_{}; ESPPreferenceObject rtc_; optional visual_min_temperature_override_{}; optional visual_max_temperature_override_{}; diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index d63885fa04..44c490c308 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -216,7 +216,7 @@ void MQTTClimateComponent::setup() { }); } - this->device_->add_on_state_callback([this]() { this->publish_state_(); }); + this->device_->add_on_state_callback([this](Climate & /*unused*/) { this->publish_state_(); }); } MQTTClimateComponent::MQTTClimateComponent(Climate *device) : device_(device) {} bool MQTTClimateComponent::send_initial_state() { return this->publish_state_(); } diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index 2ce471ead0..18d427b40c 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -50,7 +50,7 @@ void Controller::setup_controller(bool include_internal) { #ifdef USE_CLIMATE for (auto *obj : App.get_climates()) { if (include_internal || !obj->is_internal()) - obj->add_on_state_callback([this, obj]() { this->on_climate_update(obj); }); + obj->add_on_state_callback([this, obj](climate::Climate & /*unused*/) { this->on_climate_update(obj); }); } #endif #ifdef USE_NUMBER diff --git a/tests/test1.yaml b/tests/test1.yaml index 67e675ef3a..90c62c6b73 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2200,9 +2200,14 @@ climate: use_fahrenheit: true - platform: midea on_control: - logger.log: Control message received! + - logger.log: Control message received! + - lambda: |- + x.set_mode(CLIMATE_MODE_FAN_ONLY); on_state: - logger.log: State changed! + - logger.log: State changed! + - lambda: |- + if (x.mode == CLIMATE_MODE_FAN_ONLY) + id(binary_sensor1).publish_state(true); id: midea_unit uart_id: uart_0 name: Midea Climate From 794a4bd9a1944796c110e7f5d4b8c90cf48e8f15 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 31 Jul 2023 00:07:33 +0400 Subject: [PATCH 0272/2607] remote_base changes (#5124) --- .../remote_base/pronto_protocol.cpp | 9 +- .../components/remote_base/pronto_protocol.h | 2 +- esphome/components/remote_base/raw_protocol.h | 8 +- .../components/remote_base/remote_base.cpp | 96 ++++++++- esphome/components/remote_base/remote_base.h | 194 ++++-------------- .../remote_transmitter/remote_transmitter.h | 2 +- 6 files changed, 147 insertions(+), 164 deletions(-) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 4951b12bb1..81ac176666 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -187,11 +187,10 @@ std::string ProntoProtocol::dump_duration_(uint32_t duration, uint16_t timebase, return dump_number_((duration + timebase / 2) / timebase, end); } -std::string ProntoProtocol::compensate_and_dump_sequence_(std::vector *data, uint16_t timebase) { +std::string ProntoProtocol::compensate_and_dump_sequence_(const RawTimings &data, uint16_t timebase) { std::string out; - for (std::vector::size_type i = 0; i < data->size() - 1; i++) { - int32_t t_length = data->at(i); + for (int32_t t_length : data) { uint32_t t_duration; if (t_length > 0) { // Mark @@ -212,12 +211,12 @@ optional ProntoProtocol::decode(RemoteReceiveData src) { ProntoData out; uint16_t frequency = 38000U; - std::vector *data = src.get_raw_data(); + auto &data = src.get_raw_data(); std::string prontodata; prontodata += dump_number_(frequency > 0 ? LEARNED_TOKEN : LEARNED_NON_MODULATED_TOKEN); prontodata += dump_number_(to_frequency_code_(frequency)); - prontodata += dump_number_((data->size() + 1) / 2); + prontodata += dump_number_((data.size() + 1) / 2); prontodata += dump_number_(0); uint16_t timebase = to_timebase_(frequency); prontodata += compensate_and_dump_sequence_(data, timebase); diff --git a/esphome/components/remote_base/pronto_protocol.h b/esphome/components/remote_base/pronto_protocol.h index 8c491257d3..8b2163af12 100644 --- a/esphome/components/remote_base/pronto_protocol.h +++ b/esphome/components/remote_base/pronto_protocol.h @@ -27,7 +27,7 @@ class ProntoProtocol : public RemoteProtocol { std::string dump_digit_(uint8_t x); std::string dump_number_(uint16_t number, bool end = false); std::string dump_duration_(uint32_t duration, uint16_t timebase, bool end = false); - std::string compensate_and_dump_sequence_(std::vector *data, uint16_t timebase); + std::string compensate_and_dump_sequence_(const RawTimings &data, uint16_t timebase); public: void encode(RemoteTransmitData *dst, const ProntoData &data) override; diff --git a/esphome/components/remote_base/raw_protocol.h b/esphome/components/remote_base/raw_protocol.h index dc22282d1c..494903daa8 100644 --- a/esphome/components/remote_base/raw_protocol.h +++ b/esphome/components/remote_base/raw_protocol.h @@ -31,17 +31,17 @@ class RawBinarySensor : public RemoteReceiverBinarySensorBase { size_t len_; }; -class RawTrigger : public Trigger>, public Component, public RemoteReceiverListener { +class RawTrigger : public Trigger, public Component, public RemoteReceiverListener { protected: bool on_receive(RemoteReceiveData src) override { - this->trigger(*src.get_raw_data()); + this->trigger(src.get_raw_data()); return false; } }; template class RawAction : public RemoteTransmitterActionBase { public: - void set_code_template(std::function(Ts...)> func) { this->code_func_ = func; } + void set_code_template(std::function func) { this->code_func_ = func; } void set_code_static(const int32_t *code, size_t len) { this->code_static_ = code; this->code_static_len_ = len; @@ -65,7 +65,7 @@ template class RawAction : public RemoteTransmitterActionBase(Ts...)> code_func_{}; + std::function code_func_{nullptr}; const int32_t *code_static_{nullptr}; int32_t code_static_len_{0}; }; diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index 97ee027b84..7fe5e47ee7 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -24,11 +24,105 @@ void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { } #endif +/* RemoteReceiveData */ + +bool RemoteReceiveData::peek_mark(uint32_t length, uint32_t offset) const { + if (!this->is_valid(offset)) + return false; + const int32_t value = this->peek(offset); + const int32_t lo = this->lower_bound_(length); + const int32_t hi = this->upper_bound_(length); + return value >= 0 && lo <= value && value <= hi; +} + +bool RemoteReceiveData::peek_space(uint32_t length, uint32_t offset) const { + if (!this->is_valid(offset)) + return false; + const int32_t value = this->peek(offset); + const int32_t lo = this->lower_bound_(length); + const int32_t hi = this->upper_bound_(length); + return value <= 0 && lo <= -value && -value <= hi; +} + +bool RemoteReceiveData::peek_space_at_least(uint32_t length, uint32_t offset) const { + if (!this->is_valid(offset)) + return false; + const int32_t value = this->peek(offset); + const int32_t lo = this->lower_bound_(length); + return value <= 0 && lo <= -value; +} + +bool RemoteReceiveData::expect_mark(uint32_t length) { + if (!this->peek_mark(length)) + return false; + this->advance(); + return true; +} + +bool RemoteReceiveData::expect_space(uint32_t length) { + if (!this->peek_space(length)) + return false; + this->advance(); + return true; +} + +bool RemoteReceiveData::expect_item(uint32_t mark, uint32_t space) { + if (!this->peek_item(mark, space)) + return false; + this->advance(2); + return true; +} + +bool RemoteReceiveData::expect_pulse_with_gap(uint32_t mark, uint32_t space) { + if (!this->peek_space_at_least(space, 1) || !this->peek_mark(mark)) + return false; + this->advance(2); + return true; +} + +/* RemoteReceiverBinarySensorBase */ + +bool RemoteReceiverBinarySensorBase::on_receive(RemoteReceiveData src) { + if (!this->matches(src)) + return false; + this->publish_state(true); + yield(); + this->publish_state(false); + return true; +} + +/* RemoteReceiverBase */ + +void RemoteReceiverBase::register_dumper(RemoteReceiverDumperBase *dumper) { + if (dumper->is_secondary()) { + this->secondary_dumpers_.push_back(dumper); + } else { + this->dumpers_.push_back(dumper); + } +} + +void RemoteReceiverBase::call_listeners_() { + for (auto *listener : this->listeners_) + listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_)); +} + +void RemoteReceiverBase::call_dumpers_() { + bool success = false; + for (auto *dumper : this->dumpers_) { + if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_))) + success = true; + } + if (!success) { + for (auto *dumper : this->secondary_dumpers_) + dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_)); + } +} + void RemoteReceiverBinarySensorBase::dump_config() { LOG_BINARY_SENSOR("", "Remote Receiver Binary Sensor", this); } void RemoteTransmitterBase::send_(uint32_t send_times, uint32_t send_wait) { #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE - const std::vector &vec = this->temp_.get_data(); + const auto &vec = this->temp_.get_data(); char buffer[256]; uint32_t buffer_offset = 0; buffer_offset += sprintf(buffer, "Sending times=%u wait=%ums: ", send_times, send_wait); diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index fdb6d45e5f..a456007655 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -15,146 +15,65 @@ namespace esphome { namespace remote_base { +using RawTimings = std::vector; + class RemoteTransmitData { public: void mark(uint32_t length) { this->data_.push_back(length); } - void space(uint32_t length) { this->data_.push_back(-length); } - void item(uint32_t mark, uint32_t space) { this->mark(mark); this->space(space); } - void reserve(uint32_t len) { this->data_.reserve(len); } - void set_carrier_frequency(uint32_t carrier_frequency) { this->carrier_frequency_ = carrier_frequency; } - uint32_t get_carrier_frequency() const { return this->carrier_frequency_; } - - const std::vector &get_data() const { return this->data_; } - - void set_data(const std::vector &data) { - this->data_.clear(); - this->data_.reserve(data.size()); - for (auto dat : data) - this->data_.push_back(dat); - } - + const RawTimings &get_data() const { return this->data_; } + void set_data(const RawTimings &data) { this->data_ = data; } void reset() { this->data_.clear(); this->carrier_frequency_ = 0; } - std::vector::iterator begin() { return this->data_.begin(); } - - std::vector::iterator end() { return this->data_.end(); } - protected: - std::vector data_{}; + RawTimings data_{}; uint32_t carrier_frequency_{0}; }; class RemoteReceiveData { public: - RemoteReceiveData(std::vector *data, uint8_t tolerance) : data_(data), tolerance_(tolerance) {} + explicit RemoteReceiveData(const RawTimings &data, uint8_t tolerance) + : data_(data), index_(0), tolerance_(tolerance) {} - bool peek_mark(uint32_t length, uint32_t offset = 0) { - if (int32_t(this->index_ + offset) >= this->size()) - return false; - int32_t value = this->peek(offset); - const int32_t lo = this->lower_bound_(length); - const int32_t hi = this->upper_bound_(length); - return value >= 0 && lo <= value && value <= hi; + const RawTimings &get_raw_data() const { return this->data_; } + uint32_t get_index() const { return index_; } + int32_t operator[](uint32_t index) const { return this->data_[index]; } + int32_t size() const { return this->data_.size(); } + bool is_valid(uint32_t offset) const { return this->index_ + offset < this->data_.size(); } + int32_t peek(uint32_t offset = 0) const { return this->data_[this->index_ + offset]; } + bool peek_mark(uint32_t length, uint32_t offset = 0) const; + bool peek_space(uint32_t length, uint32_t offset = 0) const; + bool peek_space_at_least(uint32_t length, uint32_t offset = 0) const; + bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) const { + return this->peek_space(space, offset + 1) && this->peek_mark(mark, offset); } - bool peek_space(uint32_t length, uint32_t offset = 0) { - if (int32_t(this->index_ + offset) >= this->size()) - return false; - int32_t value = this->peek(offset); - const int32_t lo = this->lower_bound_(length); - const int32_t hi = this->upper_bound_(length); - return value <= 0 && lo <= -value && -value <= hi; - } - - bool peek_space_at_least(uint32_t length, uint32_t offset = 0) { - if (int32_t(this->index_ + offset) >= this->size()) - return false; - int32_t value = this->pos(this->index_ + offset); - const int32_t lo = this->lower_bound_(length); - return value <= 0 && lo <= -value; - } - - bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) { - return this->peek_mark(mark, offset) && this->peek_space(space, offset + 1); - } - - int32_t peek(uint32_t offset = 0) { return (*this)[this->index_ + offset]; } - + bool expect_mark(uint32_t length); + bool expect_space(uint32_t length); + bool expect_item(uint32_t mark, uint32_t space); + bool expect_pulse_with_gap(uint32_t mark, uint32_t space); void advance(uint32_t amount = 1) { this->index_ += amount; } - - bool expect_mark(uint32_t length) { - if (this->peek_mark(length)) { - this->advance(); - return true; - } - return false; - } - - bool expect_space(uint32_t length) { - if (this->peek_space(length)) { - this->advance(); - return true; - } - return false; - } - - bool expect_item(uint32_t mark, uint32_t space) { - if (this->peek_item(mark, space)) { - this->advance(2); - return true; - } - return false; - } - - bool expect_pulse_with_gap(uint32_t mark, uint32_t space) { - if (this->peek_mark(mark, 0) && this->peek_space_at_least(space, 1)) { - this->advance(2); - return true; - } - return false; - } - - uint32_t get_index() { return index_; } - void reset() { this->index_ = 0; } - int32_t pos(uint32_t index) const { return (*this->data_)[index]; } - - int32_t operator[](uint32_t index) const { return this->pos(index); } - - int32_t size() const { return this->data_->size(); } - - std::vector *get_raw_data() { return this->data_; } - protected: - int32_t lower_bound_(uint32_t length) { return int32_t(100 - this->tolerance_) * length / 100U; } - int32_t upper_bound_(uint32_t length) { return int32_t(100 + this->tolerance_) * length / 100U; } + int32_t lower_bound_(uint32_t length) const { return int32_t(100 - this->tolerance_) * length / 100U; } + int32_t upper_bound_(uint32_t length) const { return int32_t(100 + this->tolerance_) * length / 100U; } - uint32_t index_{0}; - std::vector *data_; + const RawTimings &data_; + uint32_t index_; uint8_t tolerance_; }; -template class RemoteProtocol { - public: - virtual void encode(RemoteTransmitData *dst, const T &data) = 0; - - virtual optional decode(RemoteReceiveData src) = 0; - - virtual void dump(const T &data) = 0; -}; - class RemoteComponentBase { public: explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){}; @@ -196,7 +115,6 @@ class RemoteTransmitterBase : public RemoteComponentBase { RemoteTransmitData *get_data() { return &this->parent_->temp_; } void set_send_times(uint32_t send_times) { send_times_ = send_times; } void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; } - void perform() { this->parent_->send_(this->send_times_, this->send_wait_); } protected: @@ -234,51 +152,22 @@ class RemoteReceiverBase : public RemoteComponentBase { public: RemoteReceiverBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {} void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); } - void register_dumper(RemoteReceiverDumperBase *dumper) { - if (dumper->is_secondary()) { - this->secondary_dumpers_.push_back(dumper); - } else { - this->dumpers_.push_back(dumper); - } - } + void register_dumper(RemoteReceiverDumperBase *dumper); void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; } protected: - bool call_listeners_() { - bool success = false; - for (auto *listener : this->listeners_) { - auto data = RemoteReceiveData(&this->temp_, this->tolerance_); - if (listener->on_receive(data)) - success = true; - } - return success; - } - void call_dumpers_() { - bool success = false; - for (auto *dumper : this->dumpers_) { - auto data = RemoteReceiveData(&this->temp_, this->tolerance_); - if (dumper->dump(data)) - success = true; - } - if (!success) { - for (auto *dumper : this->secondary_dumpers_) { - auto data = RemoteReceiveData(&this->temp_, this->tolerance_); - dumper->dump(data); - } - } - } + void call_listeners_(); + void call_dumpers_(); void call_listeners_dumpers_() { - if (this->call_listeners_()) - return; - // If a listener handled, then do not dump + this->call_listeners_(); this->call_dumpers_(); } std::vector listeners_; std::vector dumpers_; std::vector secondary_dumpers_; - std::vector temp_; - uint8_t tolerance_{25}; + RawTimings temp_; + uint8_t tolerance_; }; class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff, @@ -288,15 +177,16 @@ class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitial explicit RemoteReceiverBinarySensorBase() {} void dump_config() override; virtual bool matches(RemoteReceiveData src) = 0; - bool on_receive(RemoteReceiveData src) override { - if (this->matches(src)) { - this->publish_state(true); - yield(); - this->publish_state(false); - return true; - } - return false; - } + bool on_receive(RemoteReceiveData src) override; +}; + +/* TEMPLATES */ + +template class RemoteProtocol { + public: + virtual void encode(RemoteTransmitData *dst, const T &data) = 0; + virtual optional decode(RemoteReceiveData src) = 0; + virtual void dump(const T &data) = 0; }; template class RemoteReceiverBinarySensor : public RemoteReceiverBinarySensorBase { diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index 560d83802e..a20df0cc62 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -48,7 +48,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, esp_err_t error_code_{ESP_OK}; bool inverted_{false}; #endif - uint8_t carrier_duty_percent_{50}; + uint8_t carrier_duty_percent_; }; } // namespace remote_transmitter From cd46a69f2cf4ab8eb6560758a6d71d1a95ec3d45 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Sun, 30 Jul 2023 21:09:09 +0000 Subject: [PATCH 0273/2607] Add 'map_linear' and 'clamp' sensor filters (#5040) --- esphome/components/sensor/__init__.py | 106 ++++++++++++++++++++++---- esphome/components/sensor/filter.cpp | 20 ++++- esphome/components/sensor/filter.h | 16 +++- tests/test1.yaml | 10 ++- tests/test3.1.yaml | 8 +- 5 files changed, 137 insertions(+), 23 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 2aebf7bb17..bbcc730943 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -31,6 +31,9 @@ from esphome.const import ( CONF_MQTT_ID, CONF_FORCE_UPDATE, CONF_VALUE, + CONF_MIN_VALUE, + CONF_MAX_VALUE, + CONF_METHOD, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, DEVICE_CLASS_ATMOSPHERIC_PRESSURE, @@ -227,6 +230,7 @@ OrFilter = sensor_ns.class_("OrFilter", Filter) CalibrateLinearFilter = sensor_ns.class_("CalibrateLinearFilter", Filter) CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter) SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter) +ClampFilter = sensor_ns.class_("ClampFilter", Filter) validate_unit_of_measurement = cv.string_strict validate_accuracy_decimals = cv.int_ @@ -557,30 +561,60 @@ async def debounce_filter_to_code(config, filter_id): return var -def validate_not_all_from_same(config): - if all(conf[CONF_FROM] == config[0][CONF_FROM] for conf in config): - raise cv.Invalid( - "The 'from' values of the calibrate_linear filter cannot all point " - "to the same value! Please add more values to the filter." - ) +CONF_DATAPOINTS = "datapoints" + + +def validate_calibrate_linear(config): + datapoints = config[CONF_DATAPOINTS] + if config[CONF_METHOD] == "exact": + for i in range(len(datapoints) - 1): + if datapoints[i][CONF_FROM] > datapoints[i + 1][CONF_FROM]: + raise cv.Invalid( + "The 'from' values of the calibrate_linear filter must be sorted in ascending order." + ) + for i in range(len(datapoints) - 1): + if datapoints[i][CONF_FROM] == datapoints[i + 1][CONF_FROM]: + raise cv.Invalid( + "The 'from' values of the calibrate_linear filter must not contain duplicates." + ) + elif config[CONF_METHOD] == "least_squares": + if all(conf[CONF_FROM] == datapoints[0][CONF_FROM] for conf in datapoints): + raise cv.Invalid( + "The 'from' values of the calibrate_linear filter cannot all point " + "to the same value! Please add more values to the filter." + ) return config @FILTER_REGISTRY.register( "calibrate_linear", CalibrateLinearFilter, - cv.All( - cv.ensure_list(validate_datapoint), cv.Length(min=2), validate_not_all_from_same + cv.maybe_simple_value( + { + cv.Required(CONF_DATAPOINTS): cv.All( + cv.ensure_list(validate_datapoint), cv.Length(min=2) + ), + cv.Optional(CONF_METHOD, default="least_squares"): cv.one_of( + "least_squares", "exact", lower=True + ), + }, + validate_calibrate_linear, + key=CONF_DATAPOINTS, ), ) async def calibrate_linear_filter_to_code(config, filter_id): - x = [conf[CONF_FROM] for conf in config] - y = [conf[CONF_TO] for conf in config] - k, b = fit_linear(x, y) - return cg.new_Pvariable(filter_id, k, b) + x = [conf[CONF_FROM] for conf in config[CONF_DATAPOINTS]] + y = [conf[CONF_TO] for conf in config[CONF_DATAPOINTS]] + + linear_functions = [] + if config[CONF_METHOD] == "least_squares": + k, b = fit_linear(x, y) + linear_functions = [[k, b, float("NaN")]] + elif config[CONF_METHOD] == "exact": + linear_functions = map_linear(x, y) + return cg.new_Pvariable(filter_id, linear_functions) -CONF_DATAPOINTS = "datapoints" CONF_DEGREE = "degree" @@ -619,6 +653,36 @@ async def calibrate_polynomial_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id, res) +def validate_clamp(config): + if not math.isfinite(config[CONF_MIN_VALUE]) and not math.isfinite( + config[CONF_MAX_VALUE] + ): + raise cv.Invalid("Either 'min_value' or 'max_value' must be set to a number.") + if config[CONF_MIN_VALUE] > config[CONF_MAX_VALUE]: + raise cv.Invalid("The 'min_value' must not be larger than the 'max_value'.") + return config + + +CLAMP_SCHEMA = cv.All( + cv.Schema( + { + cv.Optional(CONF_MIN_VALUE, default="NaN"): cv.float_, + cv.Optional(CONF_MAX_VALUE, default="NaN"): cv.float_, + } + ), + validate_clamp, +) + + +@FILTER_REGISTRY.register("clamp", ClampFilter, CLAMP_SCHEMA) +async def clamp_filter_to_code(config, filter_id): + return cg.new_Pvariable( + filter_id, + config[CONF_MIN_VALUE], + config[CONF_MAX_VALUE], + ) + + async def build_filters(config): return await cg.build_registry_list(FILTER_REGISTRY, config) @@ -730,6 +794,22 @@ def fit_linear(x, y): return k, b +def map_linear(x, y): + assert len(x) == len(y) + f = [] + for i in range(len(x) - 1): + slope = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) + bias = y[i] - (slope * x[i]) + next_x = x[i + 1] + if i == len(x) - 2: + next_x = float("NaN") + if f and f[-1][0] == slope and f[-1][1] == bias: + f[-1][2] = next_x + else: + f.append([slope, bias, next_x]) + return f + + def _mat_copy(m): return [list(row) for row in m] diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index ccefa556b6..cd5ab5f9cd 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -416,8 +416,13 @@ void HeartbeatFilter::setup() { } float HeartbeatFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -optional CalibrateLinearFilter::new_value(float value) { return value * this->slope_ + this->bias_; } -CalibrateLinearFilter::CalibrateLinearFilter(float slope, float bias) : slope_(slope), bias_(bias) {} +optional CalibrateLinearFilter::new_value(float value) { + for (std::array f : this->linear_functions_) { + if (!std::isfinite(f[2]) || value < f[2]) + return (value * f[0]) + f[1]; + } + return NAN; +} optional CalibratePolynomialFilter::new_value(float value) { float res = 0.0f; @@ -429,5 +434,16 @@ optional CalibratePolynomialFilter::new_value(float value) { return res; } +ClampFilter::ClampFilter(float min, float max) : min_(min), max_(max) {} +optional ClampFilter::new_value(float value) { + if (std::isfinite(value)) { + if (std::isfinite(this->min_) && value < this->min_) + return this->min_; + if (std::isfinite(this->max_) && value > this->max_) + return this->max_; + } + return value; +} + } // namespace sensor } // namespace esphome diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 296990f34f..0141b73267 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -390,12 +390,12 @@ class OrFilter : public Filter { class CalibrateLinearFilter : public Filter { public: - CalibrateLinearFilter(float slope, float bias); + CalibrateLinearFilter(std::vector> linear_functions) + : linear_functions_(std::move(linear_functions)) {} optional new_value(float value) override; protected: - float slope_; - float bias_; + std::vector> linear_functions_; }; class CalibratePolynomialFilter : public Filter { @@ -407,5 +407,15 @@ class CalibratePolynomialFilter : public Filter { std::vector coefficients_; }; +class ClampFilter : public Filter { + public: + ClampFilter(float min, float max); + optional new_value(float value) override; + + protected: + float min_{NAN}; + float max_{NAN}; +}; + } // namespace sensor } // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 90c62c6b73..a00b886ac1 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -379,9 +379,13 @@ sensor: - offset: 2.0 - multiply: 1.2 - calibrate_linear: - - 0.0 -> 0.0 - - 40.0 -> 45.0 - - 100.0 -> 102.5 + datapoints: + - 0.0 -> 0.0 + - 40.0 -> 45.0 + - 100.0 -> 102.5 + - clamp: + min_value: -100 + max_value: 100 - filter_out: 42.0 - filter_out: nan - median: diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 104f4bbda8..42c1e1e1ab 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -88,8 +88,12 @@ sensor: - debounce: 500s - timeout: 10min - calibrate_linear: - - 0 -> 0 - - 100 -> 100 + method: exact + datapoints: + - -1 -> 3 + - 0.0 -> 1.0 + - 1.0 -> 2.0 + - 2.0 -> 3.0 - calibrate_polynomial: degree: 3 datapoints: From 08a41d9bd6102b9632a90ea84e3957dcb8e05b6f Mon Sep 17 00:00:00 2001 From: mullerdavid Date: Sun, 30 Jul 2023 23:10:46 +0200 Subject: [PATCH 0274/2607] Adding Inkplate 6 v2 model variant (#5165) --- esphome/components/inkplate6/display.py | 1 + esphome/components/inkplate6/inkplate.cpp | 66 ++++++++++++++++------- esphome/components/inkplate6/inkplate.h | 48 +++++++++++++---- 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index 7534731175..f05169ea2e 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -48,6 +48,7 @@ MODELS = { "inkplate_6": InkplateModel.INKPLATE_6, "inkplate_10": InkplateModel.INKPLATE_10, "inkplate_6_plus": InkplateModel.INKPLATE_6_PLUS, + "inkplate_6_v2": InkplateModel.INKPLATE_6_V2, } CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/inkplate6/inkplate.cpp b/esphome/components/inkplate6/inkplate.cpp index e6fb9b773c..92a226de87 100644 --- a/esphome/components/inkplate6/inkplate.cpp +++ b/esphome/components/inkplate6/inkplate.cpp @@ -69,9 +69,9 @@ void Inkplate6::initialize_() { if (this->buffer_ != nullptr) allocator.deallocate(this->buffer_, buffer_size); if (this->glut_ != nullptr) - allocator32.deallocate(this->glut_, 256 * (this->model_ == INKPLATE_6_PLUS ? 9 : 8)); + allocator32.deallocate(this->glut_, 256 * 9); if (this->glut2_ != nullptr) - allocator32.deallocate(this->glut2_, 256 * (this->model_ == INKPLATE_6_PLUS ? 9 : 8)); + allocator32.deallocate(this->glut2_, 256 * 9); this->buffer_ = allocator.allocate(buffer_size); if (this->buffer_ == nullptr) { @@ -80,7 +80,7 @@ void Inkplate6::initialize_() { return; } if (this->greyscale_) { - uint8_t glut_size = (this->model_ == INKPLATE_6_PLUS ? 9 : 8); + uint8_t glut_size = 9; this->glut_ = allocator32.allocate(256 * glut_size); if (this->glut_ == nullptr) { @@ -95,12 +95,14 @@ void Inkplate6::initialize_() { return; } + const auto *const waveform3_bit = waveform3BitAll[this->model_]; + for (int i = 0; i < glut_size; i++) { for (uint32_t j = 0; j < 256; j++) { - uint8_t z = (waveform3Bit[j & 0x07][i] << 2) | (waveform3Bit[(j >> 4) & 0x07][i]); + uint8_t z = (waveform3_bit[j & 0x07][i] << 2) | (waveform3_bit[(j >> 4) & 0x07][i]); this->glut_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) | (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25); - z = ((waveform3Bit[j & 0x07][i] << 2) | (waveform3Bit[(j >> 4) & 0x07][i])) << 4; + z = ((waveform3_bit[j & 0x07][i] << 2) | (waveform3_bit[(j >> 4) & 0x07][i])) << 4; this->glut2_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) | (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25); } @@ -339,13 +341,16 @@ void Inkplate6::display1b_() { clean_fast_(1, 21); clean_fast_(2, 1); clean_fast_(0, 12); + clean_fast_(2, 1); } uint32_t clock = (1 << this->cl_pin_->get_pin()); uint32_t data_mask = this->get_data_pin_mask_(); ESP_LOGV(TAG, "Display1b start loops (%ums)", millis() - start_time); - for (int k = 0; k < 4; k++) { + int rep = (this->model_ == INKPLATE_6_V2) ? 5 : 4; + + for (int k = 0; k < rep; k++) { buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1]; vscan_start_(); for (int i = 0, im = this->get_height_internal(); i < im; i++) { @@ -365,8 +370,11 @@ void Inkplate6::display1b_() { GPIO.out_w1ts = this->pin_lut_[data] | clock; GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = data_mask | clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; + } vscan_end_(); } delayMicroseconds(230); @@ -392,8 +400,11 @@ void Inkplate6::display1b_() { GPIO.out_w1ts = this->pin_lut_[data] | clock; GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = data_mask | clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; + } vscan_end_(); } delayMicroseconds(230); @@ -415,8 +426,11 @@ void Inkplate6::display1b_() { GPIO.out_w1ts = send | clock; GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = send | clock; - GPIO.out_w1tc = data_mask | clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; + } vscan_end_(); } delayMicroseconds(230); @@ -450,13 +464,14 @@ void Inkplate6::display3b_() { clean_fast_(1, 21); clean_fast_(2, 1); clean_fast_(0, 12); + clean_fast_(2, 1); } uint32_t clock = (1 << this->cl_pin_->get_pin()); uint32_t data_mask = this->get_data_pin_mask_(); uint32_t pos; uint32_t data; - uint8_t glut_size = this->model_ == INKPLATE_6_PLUS ? 9 : 8; + uint8_t glut_size = 9; for (int k = 0; k < glut_size; k++) { pos = this->get_buffer_length_(); vscan_start_(); @@ -479,8 +494,11 @@ void Inkplate6::display3b_() { GPIO.out_w1ts = data | clock; GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = data_mask | clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; + } vscan_end_(); } delayMicroseconds(230); @@ -517,10 +535,12 @@ bool Inkplate6::partial_update_() { } ESP_LOGV(TAG, "Partial update buffer built after (%ums)", millis() - start_time); + int rep = (this->model_ == INKPLATE_6_V2) ? 6 : 5; + eink_on_(); uint32_t clock = (1 << this->cl_pin_->get_pin()); uint32_t data_mask = this->get_data_pin_mask_(); - for (int k = 0; k < 5; k++) { + for (int k = 0; k < rep; k++) { vscan_start_(); const uint8_t *data_ptr = &this->partial_buffer_2_[(this->get_buffer_length_() * 2) - 1]; for (int i = 0; i < this->get_height_internal(); i++) { @@ -531,8 +551,11 @@ bool Inkplate6::partial_update_() { GPIO.out_w1ts = this->pin_lut_[data] | clock; GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = data_mask | clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; + } vscan_end_(); } delayMicroseconds(230); @@ -634,8 +657,11 @@ void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) { GPIO.out_w1ts = clock; GPIO.out_w1tc = clock; } - GPIO.out_w1ts = send | clock; - GPIO.out_w1tc = clock; + // New Inkplate6 panel doesn't need last clock + if (this->model_ != INKPLATE_6_V2) { + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = clock; + } vscan_end_(); } delayMicroseconds(230); diff --git a/esphome/components/inkplate6/inkplate.h b/esphome/components/inkplate6/inkplate.h index e650b57631..565bd74710 100644 --- a/esphome/components/inkplate6/inkplate.h +++ b/esphome/components/inkplate6/inkplate.h @@ -14,6 +14,7 @@ enum InkplateModel : uint8_t { INKPLATE_6 = 0, INKPLATE_10 = 1, INKPLATE_6_PLUS = 2, + INKPLATE_6_V2 = 3, }; class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice { @@ -28,13 +29,42 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public const uint8_t pixelMaskLUT[8] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; const uint8_t pixelMaskGLUT[2] = {0x0F, 0xF0}; - const uint8_t waveform3Bit[8][8] = {{0, 1, 1, 0, 0, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0}, {1, 1, 1, 2, 2, 1, 0, 0}, - {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, {2, 2, 1, 1, 2, 1, 2, 0}, - {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}}; - const uint8_t waveform3Bit6Plus[8][9] = {{0, 0, 0, 0, 0, 2, 1, 1, 0}, {0, 0, 2, 1, 1, 1, 2, 1, 0}, - {0, 2, 2, 2, 1, 1, 2, 1, 0}, {0, 0, 2, 2, 2, 1, 2, 1, 0}, - {0, 0, 0, 0, 2, 2, 2, 1, 0}, {0, 0, 2, 1, 2, 1, 1, 2, 0}, - {0, 0, 2, 2, 2, 1, 1, 2, 0}, {0, 0, 0, 0, 2, 2, 2, 2, 0}}; + const uint8_t waveform3BitAll[4][8][9] = {// INKPLATE_6 + {{0, 1, 1, 0, 0, 1, 1, 0, 0}, + {0, 1, 2, 1, 1, 2, 1, 0, 0}, + {1, 1, 1, 2, 2, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 2, 0, 0}, + {2, 1, 1, 1, 2, 1, 2, 0, 0}, + {2, 2, 1, 1, 2, 1, 2, 0, 0}, + {1, 1, 1, 2, 1, 2, 2, 0, 0}, + {0, 0, 0, 0, 0, 0, 2, 0, 0}}, + // INKPLATE_10 + {{0, 0, 0, 0, 0, 0, 0, 1, 0}, + {0, 0, 0, 2, 2, 2, 1, 1, 0}, + {0, 0, 2, 1, 1, 2, 2, 1, 0}, + {0, 1, 2, 2, 1, 2, 2, 1, 0}, + {0, 0, 2, 1, 2, 2, 2, 1, 0}, + {0, 2, 2, 2, 2, 2, 2, 1, 0}, + {0, 0, 0, 0, 0, 2, 1, 2, 0}, + {0, 0, 0, 2, 2, 2, 2, 2, 0}}, + // INKPLATE_6_PLUS + {{0, 0, 0, 0, 0, 2, 1, 1, 0}, + {0, 0, 2, 1, 1, 1, 2, 1, 0}, + {0, 2, 2, 2, 1, 1, 2, 1, 0}, + {0, 0, 2, 2, 2, 1, 2, 1, 0}, + {0, 0, 0, 0, 2, 2, 2, 1, 0}, + {0, 0, 2, 1, 2, 1, 1, 2, 0}, + {0, 0, 2, 2, 2, 1, 1, 2, 0}, + {0, 0, 0, 0, 2, 2, 2, 2, 0}}, + // INKPLATE_6_V2 + {{1, 0, 1, 0, 1, 1, 1, 0, 0}, + {0, 0, 0, 1, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 2, 1, 0, 0}, + {1, 1, 1, 2, 2, 1, 1, 0, 0}, + {1, 1, 1, 1, 2, 2, 1, 0, 0}, + {0, 1, 1, 1, 2, 2, 1, 0, 0}, + {0, 0, 0, 0, 1, 1, 2, 0, 0}, + {0, 0, 0, 0, 0, 1, 2, 0, 0}}}; void set_greyscale(bool greyscale) { this->greyscale_ = greyscale; @@ -111,7 +141,7 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public void pins_as_outputs_(); int get_width_internal() override { - if (this->model_ == INKPLATE_6) { + if (this->model_ == INKPLATE_6 || this->model_ == INKPLATE_6_V2) { return 800; } else if (this->model_ == INKPLATE_10) { return 1200; @@ -122,7 +152,7 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public } int get_height_internal() override { - if (this->model_ == INKPLATE_6) { + if (this->model_ == INKPLATE_6 || this->model_ == INKPLATE_6_V2) { return 600; } else if (this->model_ == INKPLATE_10) { return 825; From 56630bb7177bb67570291c8731ca8c87c22236ef Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 30 Jul 2023 16:19:06 -0500 Subject: [PATCH 0275/2607] Swap ADC back to use 'int' because C3 (#5151) --- esphome/components/adc/adc_sensor.cpp | 10 +++++----- esphome/components/adc/adc_sensor.h | 2 +- tests/test7.yaml | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index bb6a7a8c85..665ecfd6b5 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -32,8 +32,8 @@ static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12; #endif #endif -static const int32_t ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) -static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) +static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) +static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) #endif #ifdef USE_RP2040 @@ -59,7 +59,7 @@ extern "C" } // load characteristics for each attenuation - for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) { + for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) { auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref @@ -157,7 +157,7 @@ float ADCSensor::sample() { #ifdef USE_ESP32 float ADCSensor::sample() { if (!autorange_) { - int32_t raw = -1; + int raw = -1; if (channel1_ != ADC1_CHANNEL_MAX) { raw = adc1_get_raw(channel1_); } else if (channel2_ != ADC2_CHANNEL_MAX) { @@ -174,7 +174,7 @@ float ADCSensor::sample() { return mv / 1000.0f; } - int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; if (channel1_ != ADC1_CHANNEL_MAX) { adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index a905177790..7d9c8959da 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -62,7 +62,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; - esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {}; + esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; #endif }; diff --git a/tests/test7.yaml b/tests/test7.yaml index 10e1b035ab..8d48c9a601 100644 --- a/tests/test7.yaml +++ b/tests/test7.yaml @@ -31,3 +31,11 @@ logger: http_request: useragent: esphome/tagreader timeout: 10s + +sensor: + - platform: adc + id: adc_sensor_p4 + name: ADC pin 4 + pin: 4 + attenuation: 11db + update_interval: 1s From fdb20e4a30d45323c94427bc7144f2c115d39727 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Mon, 31 Jul 2023 00:23:30 +0300 Subject: [PATCH 0276/2607] wifi: handle WIFI_REASON_ROAMING reason in event (#5153) --- esphome/components/wifi/wifi_component_esp_idf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index a2bbc8ae09..e9d74116cf 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -569,6 +569,8 @@ const char *get_disconnect_reason_str(uint8_t reason) { return "Handshake Failed"; case WIFI_REASON_CONNECTION_FAIL: return "Connection Failed"; + case WIFI_REASON_ROAMING: + return "Station Roaming"; case WIFI_REASON_UNSPECIFIED: default: return "Unspecified"; @@ -631,7 +633,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { if (it.reason == WIFI_REASON_NO_AP_FOUND) { ESP_LOGW(TAG, "Event: Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf); s_sta_connect_not_found = true; - + } else if (it.reason == WIFI_REASON_ROAMING) { + ESP_LOGI(TAG, "Event: Disconnected ssid='%s' reason='Station Roaming'", buf); + return; } else { ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason)); From 9ff0471274404bb5dfa549279dd90224c7e13641 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 31 Jul 2023 01:30:11 +0400 Subject: [PATCH 0277/2607] duty_time: fix build without binary_sensor. Parented in automations. (#5156) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/duty_time/duty_time_sensor.cpp | 2 + .../components/duty_time/duty_time_sensor.h | 40 ++++++------------- esphome/components/duty_time/sensor.py | 28 ++++++++----- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/esphome/components/duty_time/duty_time_sensor.cpp b/esphome/components/duty_time/duty_time_sensor.cpp index 045cbcceac..1101c4d41e 100644 --- a/esphome/components/duty_time/duty_time_sensor.cpp +++ b/esphome/components/duty_time/duty_time_sensor.cpp @@ -6,9 +6,11 @@ namespace duty_time_sensor { static const char *const TAG = "duty_time_sensor"; +#ifdef USE_BINARY_SENSOR void DutyTimeSensor::set_sensor(binary_sensor::BinarySensor *const sensor) { sensor->add_on_state_callback([this](bool state) { this->process_state_(state); }); } +#endif void DutyTimeSensor::start() { if (!this->last_state_) diff --git a/esphome/components/duty_time/duty_time_sensor.h b/esphome/components/duty_time/duty_time_sensor.h index 27fa383847..1ec2f7b94f 100644 --- a/esphome/components/duty_time/duty_time_sensor.h +++ b/esphome/components/duty_time/duty_time_sensor.h @@ -3,8 +3,10 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/preferences.h" -#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/sensor/sensor.h" +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif namespace esphome { namespace duty_time_sensor { @@ -22,8 +24,10 @@ class DutyTimeSensor : public sensor::Sensor, public PollingComponent { bool is_running() const { return this->last_state_; } void reset() { this->set_value_(0); } - void set_lambda(std::function &&func) { this->func_ = func; } +#ifdef USE_BINARY_SENSOR void set_sensor(binary_sensor::BinarySensor *sensor); +#endif + void set_lambda(std::function &&func) { this->func_ = func; } void set_last_duty_time_sensor(sensor::Sensor *sensor) { this->last_duty_time_sensor_ = sensor; } void set_restore(bool restore) { this->restore_ = restore; } @@ -43,44 +47,26 @@ class DutyTimeSensor : public sensor::Sensor, public PollingComponent { bool restore_; }; -template class StartAction : public Action { - public: - explicit StartAction(DutyTimeSensor *parent) : parent_(parent) {} +template class BaseAction : public Action, public Parented {}; +template class StartAction : public BaseAction { void play(Ts... x) override { this->parent_->start(); } - - protected: - DutyTimeSensor *parent_; }; -template class StopAction : public Action { - public: - explicit StopAction(DutyTimeSensor *parent) : parent_(parent) {} - +template class StopAction : public BaseAction { void play(Ts... x) override { this->parent_->stop(); } - - protected: - DutyTimeSensor *parent_; }; -template class ResetAction : public Action { - public: - explicit ResetAction(DutyTimeSensor *parent) : parent_(parent) {} - +template class ResetAction : public BaseAction { void play(Ts... x) override { this->parent_->reset(); } - - protected: - DutyTimeSensor *parent_; }; -template class RunningCondition : public Condition { +template class RunningCondition : public Condition, public Parented { public: - explicit RunningCondition(DutyTimeSensor *parent, bool state) : parent_(parent), state_(state) {} - - bool check(Ts... x) override { return this->parent_->is_running() == this->state_; } + explicit RunningCondition(DutyTimeSensor *parent, bool state) : Parented(parent), state_(state) {} protected: - DutyTimeSensor *parent_; + bool check(Ts... x) override { return this->parent_->is_running() == this->state_; } bool state_; }; diff --git a/esphome/components/duty_time/sensor.py b/esphome/components/duty_time/sensor.py index 5f8582d481..556cd459a5 100644 --- a/esphome/components/duty_time/sensor.py +++ b/esphome/components/duty_time/sensor.py @@ -26,11 +26,14 @@ duty_time_sensor_ns = cg.esphome_ns.namespace("duty_time_sensor") DutyTimeSensor = duty_time_sensor_ns.class_( "DutyTimeSensor", sensor.Sensor, cg.PollingComponent ) -StartAction = duty_time_sensor_ns.class_("StartAction", Action) -StopAction = duty_time_sensor_ns.class_("StopAction", Action) -ResetAction = duty_time_sensor_ns.class_("ResetAction", Action) -SetAction = duty_time_sensor_ns.class_("SetAction", Action) -RunningCondition = duty_time_sensor_ns.class_("RunningCondition", Condition) +BaseAction = duty_time_sensor_ns.class_("BaseAction", Action, cg.Parented) +StartAction = duty_time_sensor_ns.class_("StartAction", BaseAction) +StopAction = duty_time_sensor_ns.class_("StopAction", BaseAction) +ResetAction = duty_time_sensor_ns.class_("ResetAction", BaseAction) +SetAction = duty_time_sensor_ns.class_("SetAction", BaseAction) +RunningCondition = duty_time_sensor_ns.class_( + "RunningCondition", Condition, cg.Parented +) CONFIG_SCHEMA = cv.All( @@ -89,20 +92,23 @@ DUTY_TIME_ID_SCHEMA = maybe_simple_id( @register_action("sensor.duty_time.start", StartAction, DUTY_TIME_ID_SCHEMA) async def sensor_runtime_start_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var @register_action("sensor.duty_time.stop", StopAction, DUTY_TIME_ID_SCHEMA) async def sensor_runtime_stop_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var @register_action("sensor.duty_time.reset", ResetAction, DUTY_TIME_ID_SCHEMA) async def sensor_runtime_reset_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var @register_condition( From ccb3d3d30878a99c46f4d018e89fbb4f0fda99e3 Mon Sep 17 00:00:00 2001 From: cvwillegen Date: Sun, 30 Jul 2023 23:32:09 +0200 Subject: [PATCH 0278/2607] Slightly lower template switch setup priority (#5163) --- esphome/components/template/switch/template_switch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/template/switch/template_switch.cpp b/esphome/components/template/switch/template_switch.cpp index b2a221669e..fa236f6364 100644 --- a/esphome/components/template/switch/template_switch.cpp +++ b/esphome/components/template/switch/template_switch.cpp @@ -36,7 +36,7 @@ void TemplateSwitch::write_state(bool state) { void TemplateSwitch::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } bool TemplateSwitch::assumed_state() { return this->assumed_state_; } void TemplateSwitch::set_state_lambda(std::function()> &&f) { this->f_ = f; } -float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE; } +float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE - 2.0f; } Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } void TemplateSwitch::setup() { From 9aa5ee3372f3a4fb024862901954174a2a390c12 Mon Sep 17 00:00:00 2001 From: PlainTechEnthusiast <135363826+PlainTechEnthusiast@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:40:55 -0400 Subject: [PATCH 0279/2607] update "Can't convert" warning to match others in homeassistant_sensor (#5162) --- .../components/homeassistant/sensor/homeassistant_sensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp index f5e73c8854..35e660f7c1 100644 --- a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp +++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp @@ -12,7 +12,7 @@ void HomeassistantSensor::setup() { this->entity_id_, this->attribute_, [this](const std::string &state) { auto val = parse_number(state); if (!val.has_value()) { - ESP_LOGW(TAG, "Can't convert '%s' to number!", state.c_str()); + ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_.c_str(), state.c_str()); this->publish_state(NAN); return; } From 98bf4276000e39f22f4b2977fe7ba4d05609a25c Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Sun, 30 Jul 2023 21:45:56 +0000 Subject: [PATCH 0280/2607] Add standardized CRC helper functions (#4798) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/pipsolar/pipsolar.cpp | 46 ++--------- esphome/components/sml/constants.h | 23 ------ esphome/components/sml/sml.cpp | 24 ++---- esphome/components/sml/sml.h | 3 - esphome/core/helpers.cpp | 100 ++++++++++++++++++++--- esphome/core/helpers.h | 5 +- 6 files changed, 104 insertions(+), 97 deletions(-) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index c9d1ed00f6..62e4fbd341 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -1,5 +1,6 @@ #include "pipsolar.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" namespace esphome { namespace pipsolar { @@ -768,7 +769,7 @@ uint8_t Pipsolar::check_incoming_length_(uint8_t length) { uint8_t Pipsolar::check_incoming_crc_() { uint16_t crc16; - crc16 = cal_crc_half_(read_buffer_, read_pos_ - 3); + crc16 = crc16be(read_buffer_, read_pos_ - 3); ESP_LOGD(TAG, "checking crc on incoming message"); if (((uint8_t) ((crc16) >> 8)) == read_buffer_[read_pos_ - 3] && ((uint8_t) ((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) { @@ -797,7 +798,7 @@ uint8_t Pipsolar::send_next_command_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = cal_crc_half_(byte_command, length); + crc16 = crc16be(byte_command, length); this->write_str(command); // checksum this->write(((uint8_t) ((crc16) >> 8))); // highbyte @@ -824,8 +825,8 @@ void Pipsolar::send_next_poll_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = cal_crc_half_(this->used_polling_commands_[this->last_polling_command_].command, - this->used_polling_commands_[this->last_polling_command_].length); + crc16 = crc16be(this->used_polling_commands_[this->last_polling_command_].command, + this->used_polling_commands_[this->last_polling_command_].length); this->write_array(this->used_polling_commands_[this->last_polling_command_].command, this->used_polling_commands_[this->last_polling_command_].length); // checksum @@ -892,42 +893,5 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll } } -uint16_t Pipsolar::cal_crc_half_(uint8_t *msg, uint8_t len) { - uint16_t crc; - - uint8_t da; - uint8_t *ptr; - uint8_t b_crc_hign; - uint8_t b_crc_low; - - uint16_t crc_ta[16] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef}; - - ptr = msg; - crc = 0; - - while (len-- != 0) { - da = ((uint8_t) (crc >> 8)) >> 4; - crc <<= 4; - crc ^= crc_ta[da ^ (*ptr >> 4)]; - da = ((uint8_t) (crc >> 8)) >> 4; - crc <<= 4; - crc ^= crc_ta[da ^ (*ptr & 0x0f)]; - ptr++; - } - - b_crc_low = crc; - b_crc_hign = (uint8_t) (crc >> 8); - - if (b_crc_low == 0x28 || b_crc_low == 0x0d || b_crc_low == 0x0a) - b_crc_low++; - if (b_crc_hign == 0x28 || b_crc_hign == 0x0d || b_crc_hign == 0x0a) - b_crc_hign++; - - crc = ((uint16_t) b_crc_hign) << 8; - crc += b_crc_low; - return (crc); -} - } // namespace pipsolar } // namespace esphome diff --git a/esphome/components/sml/constants.h b/esphome/components/sml/constants.h index 22114fd233..08a124ccad 100644 --- a/esphome/components/sml/constants.h +++ b/esphome/components/sml/constants.h @@ -17,32 +17,9 @@ enum SmlType : uint8_t { enum SmlMessageType : uint16_t { SML_PUBLIC_OPEN_RES = 0x0101, SML_GET_LIST_RES = 0x701 }; -enum Crc16CheckResult : uint8_t { CHECK_CRC16_FAILED, CHECK_CRC16_X25_SUCCESS, CHECK_CRC16_KERMIT_SUCCESS }; - // masks with two-bit mapping 0x1b -> 0b01; 0x01 -> 0b10; 0x1a -> 0b11 const uint16_t START_MASK = 0x55aa; // 0x1b 1b 1b 1b 1b 01 01 01 01 const uint16_t END_MASK = 0x0157; // 0x1b 1b 1b 1b 1a -const uint16_t CRC16_X25_TABLE[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, - 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, - 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, - 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, - 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, - 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, - 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, - 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, - 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, - 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, - 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, - 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, - 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, - 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, - 0x3de3, 0x2c6a, 0x1ef1, 0x0f78}; - } // namespace sml } // namespace esphome diff --git a/esphome/components/sml/sml.cpp b/esphome/components/sml/sml.cpp index c6fe7d64cd..87dc25c220 100644 --- a/esphome/components/sml/sml.cpp +++ b/esphome/components/sml/sml.cpp @@ -1,5 +1,6 @@ #include "sml.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #include "sml_parser.h" namespace esphome { @@ -99,12 +100,15 @@ bool check_sml_data(const bytes &buffer) { } uint16_t crc_received = (buffer.at(buffer.size() - 2) << 8) | buffer.at(buffer.size() - 1); - if (crc_received == calc_crc16_x25(buffer.begin(), buffer.end() - 2, 0x6e23)) { + uint16_t crc_calculated = crc16(buffer.data(), buffer.size(), 0x6e23, 0x8408, true, true); + crc_calculated = (crc_calculated >> 8) | (crc_calculated << 8); + if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/X25."); return true; } - if (crc_received == calc_crc16_kermit(buffer.begin(), buffer.end() - 2, 0xed50)) { + crc_calculated = crc16(buffer.data(), buffer.size(), 0xed50, 0x8408); + if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/KERMIT."); return true; } @@ -113,22 +117,6 @@ bool check_sml_data(const bytes &buffer) { return false; } -uint16_t calc_crc16_p1021(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum) { - for (auto it = begin; it != end; it++) { - crcsum = (crcsum >> 8) ^ CRC16_X25_TABLE[(crcsum & 0xff) ^ *it]; - } - return crcsum; -} - -uint16_t calc_crc16_x25(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum = 0) { - crcsum = calc_crc16_p1021(begin, end, crcsum ^ 0xffff) ^ 0xffff; - return (crcsum >> 8) | ((crcsum & 0xff) << 8); -} - -uint16_t calc_crc16_kermit(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum = 0) { - return calc_crc16_p1021(begin, end, crcsum); -} - uint8_t get_code(uint8_t byte) { switch (byte) { case 0x1b: diff --git a/esphome/components/sml/sml.h b/esphome/components/sml/sml.h index ac7befb043..ebc8b17d7f 100644 --- a/esphome/components/sml/sml.h +++ b/esphome/components/sml/sml.h @@ -38,9 +38,6 @@ class Sml : public Component, public uart::UARTDevice { }; bool check_sml_data(const bytes &buffer); -uint16_t calc_crc16_p1021(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum); -uint16_t calc_crc16_x25(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum); -uint16_t calc_crc16_kermit(bytes::const_iterator begin, bytes::const_iterator end, uint16_t crcsum); uint8_t get_code(uint8_t byte); } // namespace sml diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 4c6ee84dde..0bc762fd0d 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -34,6 +34,9 @@ #include #include #endif +#ifdef USE_ESP32 +#include "esp32/rom/crc.h" +#endif #ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC #include "esp_efuse.h" @@ -44,6 +47,23 @@ namespace esphome { static const char *const TAG = "helpers"; +static const uint16_t CRC16_A001_LE_LUT_L[] = {0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440}; +static const uint16_t CRC16_A001_LE_LUT_H[] = {0x0000, 0xcc01, 0xd801, 0x1400, 0xf001, 0x3c00, 0x2800, 0xe401, + 0xa001, 0x6c00, 0x7800, 0xb401, 0x5000, 0x9c01, 0x8801, 0x4400}; + +#ifndef USE_ESP32 +static const uint16_t CRC16_8408_LE_LUT_L[] = {0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7}; +static const uint16_t CRC16_8408_LE_LUT_H[] = {0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f}; + +static const uint16_t CRC16_1021_BE_LUT_L[] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef}; +static const uint16_t CRC16_1021_BE_LUT_H[] = {0x0000, 0x1231, 0x2462, 0x3653, 0x48c4, 0x5af5, 0x6ca6, 0x7e97, + 0x9188, 0x83b9, 0xb5ea, 0xa7db, 0xd94c, 0xcb7d, 0xfd2e, 0xef1f}; +#endif + // STL backports #if _GLIBCXX_RELEASE < 7 @@ -76,21 +96,79 @@ uint8_t crc8(uint8_t *data, uint8_t len) { } return crc; } -uint16_t crc16(const uint8_t *data, uint8_t len) { - uint16_t crc = 0xFFFF; - while (len--) { - crc ^= *data++; - for (uint8_t i = 0; i < 8; i++) { - if ((crc & 0x01) != 0) { - crc >>= 1; - crc ^= 0xA001; - } else { - crc >>= 1; + +uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t reverse_poly, bool refin, bool refout) { +#ifdef USE_ESP32 + if (reverse_poly == 0x8408) { + crc = crc16_le(refin ? crc : (crc ^ 0xffff), data, len); + return refout ? crc : (crc ^ 0xffff); + } +#endif + if (refin) { + crc ^= 0xffff; + } +#ifndef USE_ESP32 + if (reverse_poly == 0x8408) { + while (len--) { + uint8_t combo = crc ^ (uint8_t) *data++; + crc = (crc >> 8) ^ CRC16_8408_LE_LUT_L[combo & 0x0F] ^ CRC16_8408_LE_LUT_H[combo >> 4]; + } + } else +#endif + if (reverse_poly == 0xa001) { + while (len--) { + uint8_t combo = crc ^ (uint8_t) *data++; + crc = (crc >> 8) ^ CRC16_A001_LE_LUT_L[combo & 0x0F] ^ CRC16_A001_LE_LUT_H[combo >> 4]; + } + } else { + while (len--) { + crc ^= *data++; + for (uint8_t i = 0; i < 8; i++) { + if (crc & 0x0001) { + crc = (crc >> 1) ^ reverse_poly; + } else { + crc >>= 1; + } } } } - return crc; + return refout ? (crc ^ 0xffff) : crc; } + +uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t poly, bool refin, bool refout) { +#ifdef USE_ESP32 + if (poly == 0x1021) { + crc = crc16_be(refin ? crc : (crc ^ 0xffff), data, len); + return refout ? crc : (crc ^ 0xffff); + } +#endif + if (refin) { + crc ^= 0xffff; + } +#ifndef USE_ESP32 + if (poly == 0x1021) { + while (len--) { + uint8_t combo = (crc >> 8) ^ *data++; + crc = (crc << 8) ^ CRC16_1021_BE_LUT_L[combo & 0x0F] ^ CRC16_1021_BE_LUT_H[combo >> 4]; + } + } else { +#endif + while (len--) { + crc ^= (((uint16_t) *data++) << 8); + for (uint8_t i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc = (crc << 1) ^ poly; + } else { + crc <<= 1; + } + } + } +#ifndef USE_ESP32 + } +#endif + return refout ? (crc ^ 0xffff) : crc; +} + uint32_t fnv1_hash(const std::string &str) { uint32_t hash = 2166136261UL; for (char c : str) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 63b6949fe9..115073de80 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -155,7 +155,10 @@ template T remap(U value, U min, U max, T min_out, T max uint8_t crc8(uint8_t *data, uint8_t len); /// Calculate a CRC-16 checksum of \p data with size \p len. -uint16_t crc16(const uint8_t *data, uint8_t len); +uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc = 0xffff, uint16_t reverse_poly = 0xa001, + bool refin = false, bool refout = false); +uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc = 0, uint16_t poly = 0x1021, bool refin = false, + bool refout = false); /// Calculate a FNV-1 hash of \p str. uint32_t fnv1_hash(const std::string &str); From c418eecf839b527f61f05a4b2b1e8128df8933e0 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 31 Jul 2023 00:20:55 +0200 Subject: [PATCH 0281/2607] Enable IPv6 for ESP32 Arduino, wifi and ethernet (#4865) --- .../ethernet/ethernet_component.cpp | 46 +++++++++++++++++++ .../components/ethernet/ethernet_component.h | 7 +++ esphome/components/network/__init__.py | 18 +++++--- .../wifi/wifi_component_esp32_arduino.cpp | 10 ++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 3b5804abdd..d9004a913b 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -118,6 +118,10 @@ void EthernetComponent::setup() { ESPHL_ERROR_CHECK(err, "ETH event handler register error"); err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &EthernetComponent::got_ip_event_handler, nullptr); ESPHL_ERROR_CHECK(err, "GOT IP event handler register error"); +#if LWIP_IPV6 + err = esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &EthernetComponent::got_ip6_event_handler, nullptr); + ESPHL_ERROR_CHECK(err, "GOT IP6 event handler register error"); +#endif /* LWIP_IPV6 */ /* start Ethernet driver state machine */ err = esp_eth_start(this->eth_handle_); @@ -160,6 +164,20 @@ void EthernetComponent::loop() { this->state_ = EthernetComponentState::CONNECTING; this->start_connect_(); } +#if LWIP_IPV6 + else if (this->got_ipv6_) { + esp_ip6_addr_t ip6_addr; + if (esp_netif_get_ip6_global(this->eth_netif_, &ip6_addr) == 0 && + esp_netif_ip6_get_addr_type(&ip6_addr) == ESP_IP6_ADDR_IS_GLOBAL) { + ESP_LOGCONFIG(TAG, "IPv6 Addr (Global): " IPV6STR, IPV62STR(ip6_addr)); + } else { + esp_netif_get_ip6_linklocal(this->eth_netif_, &ip6_addr); + ESP_LOGCONFIG(TAG, " IPv6: " IPV6STR, IPV62STR(ip6_addr)); + } + + this->got_ipv6_ = false; + } +#endif /* LWIP_IPV6 */ break; } } @@ -254,6 +272,15 @@ void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_b ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%" PRId32 ")", event_id); } +#if LWIP_IPV6 +void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, + void *event_data) { + ESP_LOGV(TAG, "[Ethernet event] ETH Got IP6 (num=%d)", event_id); + global_eth_component->got_ipv6_ = true; + global_eth_component->ipv6_count_ += 1; +} +#endif /* LWIP_IPV6 */ + void EthernetComponent::start_connect_() { this->connect_begin_ = millis(); this->status_set_warning(); @@ -316,6 +343,12 @@ void EthernetComponent::start_connect_() { if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) { ESPHL_ERROR_CHECK(err, "DHCPC start error"); } +#if LWIP_IPV6 + err = esp_netif_create_ip6_linklocal(this->eth_netif_); + if (err != ESP_OK) { + ESPHL_ERROR_CHECK(err, "IPv6 local failed"); + } +#endif /* LWIP_IPV6 */ } this->connect_begin_ = millis(); @@ -343,6 +376,19 @@ void EthernetComponent::dump_connect_params_() { ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); #endif +#if LWIP_IPV6 + if (this->ipv6_count_ > 0) { + esp_ip6_addr_t ip6_addr; + esp_netif_get_ip6_linklocal(this->eth_netif_, &ip6_addr); + ESP_LOGCONFIG(TAG, " IPv6: " IPV6STR, IPV62STR(ip6_addr)); + + if (esp_netif_get_ip6_global(this->eth_netif_, &ip6_addr) == 0 && + esp_netif_ip6_get_addr_type(&ip6_addr) == ESP_IP6_ADDR_IS_GLOBAL) { + ESP_LOGCONFIG(TAG, "IPv6 Addr (Global): " IPV6STR, IPV62STR(ip6_addr)); + } + } +#endif /* LWIP_IPV6 */ + esp_err_t err; uint8_t mac[6]; diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index f6b67f3f82..1bd4786b44 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -65,6 +65,9 @@ class EthernetComponent : public Component { protected: static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); +#if LWIP_IPV6 + static void got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); +#endif /* LWIP_IPV6 */ void start_connect_(); void dump_connect_params_(); @@ -83,6 +86,10 @@ class EthernetComponent : public Component { bool started_{false}; bool connected_{false}; +#if LWIP_IPV6 + bool got_ipv6_{false}; + uint8_t ipv6_count_{0}; +#endif /* LWIP_IPV6 */ EthernetComponentState state_{EthernetComponentState::STOPPED}; uint32_t connect_begin_; esp_netif_t *eth_netif_{nullptr}; diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96cfc51ff5..cd29734f42 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -1,3 +1,4 @@ +from esphome.core import CORE import esphome.codegen as cg import esphome.config_validation as cv from esphome.components.esp32 import add_idf_sdkconfig_option @@ -14,8 +15,8 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.SplitDefault(CONF_ENABLE_IPV6, esp32_idf=False): cv.All( - cv.only_with_esp_idf, cv.boolean + cv.SplitDefault(CONF_ENABLE_IPV6, esp32=False): cv.All( + cv.only_on_esp32, cv.boolean ), } ) @@ -23,7 +24,12 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): if CONF_ENABLE_IPV6 in config: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] - ) + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) + else: + if config[CONF_ENABLE_IPV6]: + cg.add_build_flag("-DCONFIG_LWIP_IPV6") + cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 3628eca78d..995e5e587e 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -485,6 +485,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ buf[it.ssid_len] = '\0'; ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); +#if LWIP_IPV6 + WiFi.enableIpV6(); +#endif /* LWIP_IPV6 */ break; } @@ -547,6 +550,13 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ s_sta_connecting = false; break; } +#if LWIP_IPV6 + case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: { + auto it = info.got_ip6.ip6_info; + ESP_LOGV(TAG, "Got IPv6 address=" IPV6STR, IPV62STR(it.ip)); + break; + } +#endif /* LWIP_IPV6 */ case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: { ESP_LOGV(TAG, "Event: Lost IP"); break; From bf732f2a2b093e94551d25bb427e1b369c7bdd38 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 30 Jul 2023 15:23:52 -0700 Subject: [PATCH 0282/2607] Increase maximum number of BLE notifications (#5155) --- esphome/components/esp32_ble_tracker/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 30589f1a3f..8ba77c7db7 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -263,6 +263,7 @@ async def to_code(config): # Match arduino CONFIG_BTU_TASK_STACK_SIZE # https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866 add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192) + add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9) cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts cg.add_define("USE_ESP32_BLE_CLIENT") From 9a661999044a4f90be4699f2d0b57d9ff8e492e3 Mon Sep 17 00:00:00 2001 From: Joris S <100357138+Jorre05@users.noreply.github.com> Date: Mon, 31 Jul 2023 00:30:21 +0200 Subject: [PATCH 0283/2607] invert min_rssi check (#5150) --- esphome/components/ble_presence/binary_sensor.py | 2 +- esphome/components/ble_presence/ble_presence_device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index d54b7678e1..75366ce864 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, cv.Optional(CONF_IBEACON_UUID): cv.uuid, cv.Optional(CONF_MIN_RSSI): cv.All( - cv.decibel, cv.int_range(min=-90, max=-30) + cv.decibel, cv.int_range(min=-100, max=-30) ), } ) diff --git a/esphome/components/ble_presence/ble_presence_device.h b/esphome/components/ble_presence/ble_presence_device.h index 953ea460a8..1be9adeb30 100644 --- a/esphome/components/ble_presence/ble_presence_device.h +++ b/esphome/components/ble_presence/ble_presence_device.h @@ -51,7 +51,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff, this->found_ = false; } bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override { - if (this->check_minimum_rssi_ && this->minimum_rssi_ <= device.get_rssi()) { + if (this->check_minimum_rssi_ && this->minimum_rssi_ > device.get_rssi()) { return false; } switch (this->match_by_) { From f0f09d371440400919a7cfa44ebb097842bc9e99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jul 2023 10:32:55 +1200 Subject: [PATCH 0284/2607] Bump zeroconf from 0.69.0 to 0.71.4 (#5148) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 781ed03a49..d5ca30a387 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.5 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.69.0 +zeroconf==0.71.4 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 7dd56fb0fa0e981e1af7143bc4fc369fec2fecf9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jul 2023 23:28:26 +0000 Subject: [PATCH 0285/2607] Bump black from 23.3.0 to 23.7.0 (#5126) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9d2eb2908f..c7f55ed804 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.7.0 hooks: - id: black args: diff --git a/requirements_test.txt b/requirements_test.txt index 75f29ac8dd..e343347436 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.17.4 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating -black==23.3.0 # also change in .pre-commit-config.yaml when updating +black==23.7.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.7.0 # also change in .pre-commit-config.yaml when updating pre-commit From 869981cfe48dfea81c540d0187712e1466a2180f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:16:46 +1200 Subject: [PATCH 0286/2607] Bump pylint from 2.17.4 to 2.17.5 (#5172) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index e343347436..ac1446daf4 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==2.17.4 +pylint==2.17.5 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating black==23.7.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.7.0 # also change in .pre-commit-config.yaml when updating From 17be6b106b7dd3baa5d1fad865318b4a940545db Mon Sep 17 00:00:00 2001 From: Maxime Michel Date: Tue, 1 Aug 2023 02:03:34 +0200 Subject: [PATCH 0287/2607] Fix graininess & streaks for 7.50inV2alt Waveshare e-paper (#5168) --- .../components/waveshare_epaper/waveshare_epaper.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index a3b1ec7d7b..5dd573f1b8 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1493,11 +1493,10 @@ void WaveshareEPaper7P5InV2alt::initialize() { this->command(0x01); // 1-0=11: internal power - this->data(0x17); - + this->data(0x07); this->data(0x17); // VGH&VGL this->data(0x3F); // VSH - this->data(0x3F); // VSL + this->data(0x26); // VSL this->data(0x11); // VSHR // VCOM DC Setting @@ -1511,10 +1510,6 @@ void WaveshareEPaper7P5InV2alt::initialize() { this->data(0x2F); this->data(0x17); - // OSC Setting - this->command(0x30); - this->data(0x06); // 2-0=100: N=4 ; 5-3=111: M=7 ; 3C=50Hz 3A=100HZ - // POWER ON this->command(0x04); @@ -1536,7 +1531,7 @@ void WaveshareEPaper7P5InV2alt::initialize() { // COMMAND VCOM AND DATA INTERVAL SETTING this->command(0x50); this->data(0x10); - this->data(0x07); + this->data(0x00); // COMMAND TCON SETTING this->command(0x60); this->data(0x22); From 73db164fb13807ce8bbf0431035041fc293dede7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 19 Jul 2023 22:39:35 +0200 Subject: [PATCH 0288/2607] Dashboard: use Popen() on Windows (#5110) --- esphome/dashboard/dashboard.py | 60 +++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index dd800f534c..a3a44de9ed 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -25,6 +25,7 @@ import tornado.ioloop import tornado.iostream import tornado.netutil import tornado.process +import tornado.queues import tornado.web import tornado.websocket import yaml @@ -202,7 +203,11 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): def __init__(self, application, request, **kwargs): super().__init__(application, request, **kwargs) self._proc = None + self._queue = None self._is_closed = False + # Windows doesn't support non-blocking pipes, + # use Popen() with a reading thread instead + self._use_popen = os.name == "nt" @authenticated def on_message(self, message): @@ -224,13 +229,28 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): return command = self.build_command(json_message) _LOGGER.info("Running command '%s'", " ".join(shlex_quote(x) for x in command)) - self._proc = tornado.process.Subprocess( - command, - stdout=tornado.process.Subprocess.STREAM, - stderr=subprocess.STDOUT, - stdin=tornado.process.Subprocess.STREAM, - ) - self._proc.set_exit_callback(self._proc_on_exit) + + if self._use_popen: + self._queue = tornado.queues.Queue() + # pylint: disable=consider-using-with + self._proc = subprocess.Popen( + command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + stdout_thread = threading.Thread(target=self._stdout_thread) + stdout_thread.daemon = True + stdout_thread.start() + else: + self._proc = tornado.process.Subprocess( + command, + stdout=tornado.process.Subprocess.STREAM, + stderr=subprocess.STDOUT, + stdin=tornado.process.Subprocess.STREAM, + ) + self._proc.set_exit_callback(self._proc_on_exit) + tornado.ioloop.IOLoop.current().spawn_callback(self._redirect_stdout) @property @@ -252,7 +272,13 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): while True: try: - data = yield self._proc.stdout.read_until_regex(reg) + if self._use_popen: + data = yield self._queue.get() + if data is None: + self._proc_on_exit(self._proc.poll()) + break + else: + data = yield self._proc.stdout.read_until_regex(reg) except tornado.iostream.StreamClosedError: break data = codecs.decode(data, "utf8", "replace") @@ -260,6 +286,19 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): _LOGGER.debug("> stdout: %s", data) self.write_message({"event": "line", "data": data}) + def _stdout_thread(self): + if not self._use_popen: + return + while True: + data = self._proc.stdout.readline() + if data: + data = data.replace(b"\r", b"") + self._queue.put_nowait(data) + if self._proc.poll() is not None: + break + self._proc.wait(1.0) + self._queue.put_nowait(None) + def _proc_on_exit(self, returncode): if not self._is_closed: # Check if the proc was not forcibly closed @@ -270,7 +309,10 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): # Check if proc exists (if 'start' has been run) if self.is_process_active: _LOGGER.debug("Terminating process") - self._proc.proc.terminate() + if self._use_popen: + self._proc.terminate() + else: + self._proc.proc.terminate() # Shutdown proc on WS close self._is_closed = True From 3843d21dbf4d2869b1a5fcb6d5c0bb8952f931fc Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 30 Jul 2023 16:19:06 -0500 Subject: [PATCH 0289/2607] Swap ADC back to use 'int' because C3 (#5151) --- esphome/components/adc/adc_sensor.cpp | 10 +++++----- esphome/components/adc/adc_sensor.h | 2 +- tests/test7.yaml | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index bb6a7a8c85..665ecfd6b5 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -32,8 +32,8 @@ static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12; #endif #endif -static const int32_t ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) -static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) +static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit) +static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) #endif #ifdef USE_RP2040 @@ -59,7 +59,7 @@ extern "C" } // load characteristics for each attenuation - for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) { + for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) { auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref @@ -157,7 +157,7 @@ float ADCSensor::sample() { #ifdef USE_ESP32 float ADCSensor::sample() { if (!autorange_) { - int32_t raw = -1; + int raw = -1; if (channel1_ != ADC1_CHANNEL_MAX) { raw = adc1_get_raw(channel1_); } else if (channel2_ != ADC2_CHANNEL_MAX) { @@ -174,7 +174,7 @@ float ADCSensor::sample() { return mv / 1000.0f; } - int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; if (channel1_ != ADC1_CHANNEL_MAX) { adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index a905177790..7d9c8959da 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -62,7 +62,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; - esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {}; + esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; #endif }; diff --git a/tests/test7.yaml b/tests/test7.yaml index 10e1b035ab..8d48c9a601 100644 --- a/tests/test7.yaml +++ b/tests/test7.yaml @@ -31,3 +31,11 @@ logger: http_request: useragent: esphome/tagreader timeout: 10s + +sensor: + - platform: adc + id: adc_sensor_p4 + name: ADC pin 4 + pin: 4 + attenuation: 11db + update_interval: 1s From 9b19c45735d6135e5dd4b968429f665a562a9a13 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Mon, 31 Jul 2023 00:23:30 +0300 Subject: [PATCH 0290/2607] wifi: handle WIFI_REASON_ROAMING reason in event (#5153) --- esphome/components/wifi/wifi_component_esp_idf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 744fc755fe..086a80cad0 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -569,6 +569,8 @@ const char *get_disconnect_reason_str(uint8_t reason) { return "Handshake Failed"; case WIFI_REASON_CONNECTION_FAIL: return "Connection Failed"; + case WIFI_REASON_ROAMING: + return "Station Roaming"; case WIFI_REASON_UNSPECIFIED: default: return "Unspecified"; @@ -631,7 +633,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { if (it.reason == WIFI_REASON_NO_AP_FOUND) { ESP_LOGW(TAG, "Event: Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf); s_sta_connect_not_found = true; - + } else if (it.reason == WIFI_REASON_ROAMING) { + ESP_LOGI(TAG, "Event: Disconnected ssid='%s' reason='Station Roaming'", buf); + return; } else { ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason)); From 91e920c498dfbd15a94b56ca44a431a337b194ef Mon Sep 17 00:00:00 2001 From: cvwillegen Date: Sun, 30 Jul 2023 23:32:09 +0200 Subject: [PATCH 0291/2607] Slightly lower template switch setup priority (#5163) --- esphome/components/template/switch/template_switch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/template/switch/template_switch.cpp b/esphome/components/template/switch/template_switch.cpp index b2a221669e..fa236f6364 100644 --- a/esphome/components/template/switch/template_switch.cpp +++ b/esphome/components/template/switch/template_switch.cpp @@ -36,7 +36,7 @@ void TemplateSwitch::write_state(bool state) { void TemplateSwitch::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } bool TemplateSwitch::assumed_state() { return this->assumed_state_; } void TemplateSwitch::set_state_lambda(std::function()> &&f) { this->f_ = f; } -float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE; } +float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE - 2.0f; } Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } void TemplateSwitch::setup() { From 2a12ec09fb0d93bdf46271f1bda0a7aa85662ec7 Mon Sep 17 00:00:00 2001 From: PlainTechEnthusiast <135363826+PlainTechEnthusiast@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:40:55 -0400 Subject: [PATCH 0292/2607] update "Can't convert" warning to match others in homeassistant_sensor (#5162) --- .../components/homeassistant/sensor/homeassistant_sensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp index f5e73c8854..35e660f7c1 100644 --- a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp +++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp @@ -12,7 +12,7 @@ void HomeassistantSensor::setup() { this->entity_id_, this->attribute_, [this](const std::string &state) { auto val = parse_number(state); if (!val.has_value()) { - ESP_LOGW(TAG, "Can't convert '%s' to number!", state.c_str()); + ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_.c_str(), state.c_str()); this->publish_state(NAN); return; } From dec044ad8b4083219015dff939304ed7fc348a5b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 30 Jul 2023 15:23:52 -0700 Subject: [PATCH 0293/2607] Increase maximum number of BLE notifications (#5155) --- esphome/components/esp32_ble_tracker/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 30589f1a3f..8ba77c7db7 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -263,6 +263,7 @@ async def to_code(config): # Match arduino CONFIG_BTU_TASK_STACK_SIZE # https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866 add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192) + add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9) cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts cg.add_define("USE_ESP32_BLE_CLIENT") From c63cdae84fb1dc348bcdecfaa05f428c0ddbccf8 Mon Sep 17 00:00:00 2001 From: Joris S <100357138+Jorre05@users.noreply.github.com> Date: Mon, 31 Jul 2023 00:30:21 +0200 Subject: [PATCH 0294/2607] invert min_rssi check (#5150) --- esphome/components/ble_presence/binary_sensor.py | 2 +- esphome/components/ble_presence/ble_presence_device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index d54b7678e1..75366ce864 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, cv.Optional(CONF_IBEACON_UUID): cv.uuid, cv.Optional(CONF_MIN_RSSI): cv.All( - cv.decibel, cv.int_range(min=-90, max=-30) + cv.decibel, cv.int_range(min=-100, max=-30) ), } ) diff --git a/esphome/components/ble_presence/ble_presence_device.h b/esphome/components/ble_presence/ble_presence_device.h index 953ea460a8..1be9adeb30 100644 --- a/esphome/components/ble_presence/ble_presence_device.h +++ b/esphome/components/ble_presence/ble_presence_device.h @@ -51,7 +51,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff, this->found_ = false; } bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override { - if (this->check_minimum_rssi_ && this->minimum_rssi_ <= device.get_rssi()) { + if (this->check_minimum_rssi_ && this->minimum_rssi_ > device.get_rssi()) { return false; } switch (this->match_by_) { From b3d5a4dfdba90301ef24aea3f20d769c5008a795 Mon Sep 17 00:00:00 2001 From: Maxime Michel Date: Tue, 1 Aug 2023 02:03:34 +0200 Subject: [PATCH 0295/2607] Fix graininess & streaks for 7.50inV2alt Waveshare e-paper (#5168) --- .../components/waveshare_epaper/waveshare_epaper.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index d64a5500dd..d17f8230de 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1492,11 +1492,10 @@ void WaveshareEPaper7P5InV2alt::initialize() { this->command(0x01); // 1-0=11: internal power - this->data(0x17); - + this->data(0x07); this->data(0x17); // VGH&VGL this->data(0x3F); // VSH - this->data(0x3F); // VSL + this->data(0x26); // VSL this->data(0x11); // VSHR // VCOM DC Setting @@ -1510,10 +1509,6 @@ void WaveshareEPaper7P5InV2alt::initialize() { this->data(0x2F); this->data(0x17); - // OSC Setting - this->command(0x30); - this->data(0x06); // 2-0=100: N=4 ; 5-3=111: M=7 ; 3C=50Hz 3A=100HZ - // POWER ON this->command(0x04); @@ -1535,7 +1530,7 @@ void WaveshareEPaper7P5InV2alt::initialize() { // COMMAND VCOM AND DATA INTERVAL SETTING this->command(0x50); this->data(0x10); - this->data(0x07); + this->data(0x00); // COMMAND TCON SETTING this->command(0x60); this->data(0x22); From 956e19be7de7fd73fc16f30d123414fc92eee91c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:08:36 +1200 Subject: [PATCH 0296/2607] Bump version to 2023.7.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f04e19c359..139555f19b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.7.0" +__version__ = "2023.7.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From cb8ca433d9a57769502a1e6adc66b0a0f0b1077e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 07:57:51 +1200 Subject: [PATCH 0297/2607] Bump pyupgrade from 3.7.0 to 3.9.0 (#5083) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c7f55ed804..60053a14a1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - --branch=release - --branch=beta - repo: https://github.com/asottile/pyupgrade - rev: v3.7.0 + rev: v3.9.0 hooks: - id: pyupgrade args: [--py39-plus] diff --git a/requirements_test.txt b/requirements_test.txt index ac1446daf4..fd1f45abc8 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ pylint==2.17.5 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating black==23.7.0 # also change in .pre-commit-config.yaml when updating -pyupgrade==3.7.0 # also change in .pre-commit-config.yaml when updating +pyupgrade==3.9.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests From 8c66de239191fe4e5eed9a5defe49e31a094442e Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Wed, 2 Aug 2023 01:06:23 +0200 Subject: [PATCH 0298/2607] Vertical and horizontal airflow actions fix for Haier climate (#5164) Co-authored-by: Pavlo Dudnytskyi --- esphome/components/haier/climate.py | 9 +++++++-- esphome/components/haier/hon_climate.cpp | 12 ++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index 12b76084ba..c518282bfa 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -54,18 +54,23 @@ HonClimate = haier_ns.class_("HonClimate", HaierClimateBase) Smartair2Climate = haier_ns.class_("Smartair2Climate", HaierClimateBase) -AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection") +AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection", True) AIRFLOW_VERTICAL_DIRECTION_OPTIONS = { + "HEALTH_UP": AirflowVerticalDirection.HEALTH_UP, + "MAX_UP": AirflowVerticalDirection.MAX_UP, "UP": AirflowVerticalDirection.UP, "CENTER": AirflowVerticalDirection.CENTER, "DOWN": AirflowVerticalDirection.DOWN, + "HEALTH_DOWN": AirflowVerticalDirection.HEALTH_DOWN, } -AirflowHorizontalDirection = haier_ns.enum("AirflowHorizontalDirection") +AirflowHorizontalDirection = haier_ns.enum("AirflowHorizontalDirection", True) AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS = { + "MAX_LEFT": AirflowHorizontalDirection.MAX_LEFT, "LEFT": AirflowHorizontalDirection.LEFT, "CENTER": AirflowHorizontalDirection.CENTER, "RIGHT": AirflowHorizontalDirection.RIGHT, + "MAX_RIGHT": AirflowHorizontalDirection.MAX_RIGHT, } SUPPORTED_SWING_MODES_OPTIONS = { diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 3016cda397..3950b34724 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -81,22 +81,14 @@ void HonClimate::set_outdoor_temperature_sensor(esphome::sensor::Sensor *sensor) AirflowVerticalDirection HonClimate::get_vertical_airflow() const { return this->vertical_direction_; }; void HonClimate::set_vertical_airflow(AirflowVerticalDirection direction) { - if (direction > AirflowVerticalDirection::DOWN) { - this->vertical_direction_ = AirflowVerticalDirection::CENTER; - } else { - this->vertical_direction_ = direction; - } + this->vertical_direction_ = direction; this->set_force_send_control_(true); } AirflowHorizontalDirection HonClimate::get_horizontal_airflow() const { return this->horizontal_direction_; } void HonClimate::set_horizontal_airflow(AirflowHorizontalDirection direction) { - if (direction > AirflowHorizontalDirection::RIGHT) { - this->horizontal_direction_ = AirflowHorizontalDirection::CENTER; - } else { - this->horizontal_direction_ = direction; - } + this->horizontal_direction_ = direction; this->set_force_send_control_(true); } From e02aaedc42bb0d82afaab877b841a73ef1e02483 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:21:30 +1200 Subject: [PATCH 0299/2607] Microphone add is_stopped (#5183) --- esphome/components/microphone/microphone.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index 5b16a67c00..ac3db3ec0f 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -22,6 +22,7 @@ class Microphone { } bool is_running() const { return this->state_ == STATE_RUNNING; } + bool is_stopped() const { return this->state_ == STATE_STOPPED; } protected: State state_{STATE_STOPPED}; From 581cb642ff19534f898b0b78344051f93900a8b5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:24:02 +1200 Subject: [PATCH 0300/2607] Add get_board function to esp32 module (#5184) --- esphome/components/esp32/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 7daaaf7433..aa9f8cd66e 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -81,6 +81,10 @@ def get_esp32_variant(core_obj=None): return (core_obj or CORE).data[KEY_ESP32][KEY_VARIANT] +def get_board(core_obj=None): + return (core_obj or CORE).data[KEY_ESP32][KEY_BOARD] + + def only_on_variant(*, supported=None, unsupported=None): """Config validator for features only available on some ESP32 variants.""" if supported is not None and not isinstance(supported, list): From ce8091c14e409a4327fa30921c9039f009ad984b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:24:52 +1200 Subject: [PATCH 0301/2607] Speaker return bytes written and do not wait for queue (#5182) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 12 ++++++------ .../components/i2s_audio/speaker/i2s_audio_speaker.h | 2 +- esphome/components/speaker/speaker.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 5ae597dc7c..43bc005136 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -185,7 +185,7 @@ void I2SAudioSpeaker::loop() { } } -bool I2SAudioSpeaker::play(const uint8_t *data, size_t length) { +size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length) { if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) { this->start(); } @@ -197,13 +197,13 @@ bool I2SAudioSpeaker::play(const uint8_t *data, size_t length) { size_t to_send_length = std::min(remaining, BUFFER_SIZE); event.len = to_send_length; memcpy(event.data, data + index, to_send_length); - if (xQueueSend(this->buffer_queue_, &event, 100 / portTICK_PERIOD_MS) == pdTRUE) { - remaining -= to_send_length; - index += to_send_length; + if (xQueueSend(this->buffer_queue_, &event, 0) != pdTRUE) { + return index; } - App.feed_wdt(); + remaining -= to_send_length; + index += to_send_length; } - return true; + return index; } } // namespace i2s_audio diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 4f1d2172d7..f2e83142b3 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -54,7 +54,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud void start(); void stop() override; - bool play(const uint8_t *data, size_t length) override; + size_t play(const uint8_t *data, size_t length) override; protected: void start_(); diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 5dfabfa40e..53f97da5ac 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -12,8 +12,8 @@ enum State : uint8_t { class Speaker { public: - virtual bool play(const uint8_t *data, size_t length) = 0; - virtual bool play(const std::vector &data) { return this->play(data.data(), data.size()); } + virtual size_t play(const uint8_t *data, size_t length) = 0; + virtual size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } virtual void stop() = 0; From f81c556b63fe8949ffbe5cd8e3896ec5e8040fe3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:25:26 +1200 Subject: [PATCH 0302/2607] Update components "if x in config" (#5181) --- esphome/components/a4988/stepper.py | 4 +- esphome/components/adc/sensor.py | 10 ++--- .../components/addressable_light/display.py | 8 ++-- esphome/components/ade7953/sensor.py | 4 +- esphome/components/aht10/sensor.py | 8 ++-- .../alarm_control_panel/__init__.py | 12 ++--- esphome/components/alpha3/sensor.py | 24 +++++----- esphome/components/am2320/sensor.py | 8 ++-- esphome/components/am43/sensor/__init__.py | 8 ++-- esphome/components/animation/__init__.py | 12 ++--- esphome/components/api/__init__.py | 5 +-- esphome/components/as3935/sensor.py | 14 +++--- esphome/components/as7341/sensor.py | 4 +- .../components/atc_mithermometer/sensor.py | 20 ++++----- esphome/components/atm90e26/sensor.py | 32 +++++++------- esphome/components/atm90e32/sensor.py | 38 ++++++++-------- esphome/components/b_parasite/sensor.py | 4 +- esphome/components/bang_bang/climate.py | 11 +++-- esphome/components/bedjet/__init__.py | 8 ++-- esphome/components/binary/fan/__init__.py | 8 ++-- esphome/components/binary_sensor/__init__.py | 20 ++++----- esphome/components/bl0939/sensor.py | 40 +++++++---------- esphome/components/bl0940/sensor.py | 30 +++++-------- esphome/components/bl0942/sensor.py | 25 +++++------ .../components/ble_client/sensor/__init__.py | 32 ++++---------- .../ble_client/text_sensor/__init__.py | 28 +++--------- .../components/ble_presence/binary_sensor.py | 42 +++++++----------- esphome/components/ble_rssi/sensor.py | 38 +++++++--------- esphome/components/bme280/sensor.py | 21 ++++----- esphome/components/bme680/sensor.py | 26 +++++------ esphome/components/bme680_bsec/sensor.py | 11 ++--- esphome/components/bme680_bsec/text_sensor.py | 5 +-- esphome/components/bmp085/sensor.py | 10 ++--- esphome/components/bmp280/sensor.py | 14 +++--- esphome/components/bmp3xx/sensor.py | 18 ++++---- esphome/components/button/__init__.py | 8 ++-- esphome/components/canbus/__init__.py | 9 ++-- esphome/components/cap1188/__init__.py | 4 +- esphome/components/ccs811/sensor.py | 16 +++---- esphome/components/climate_ir/__init__.py | 8 ++-- esphome/components/cs5460a/sensor.py | 15 +++---- esphome/components/cse7766/sensor.py | 20 ++++----- esphome/components/current_based/cover.py | 44 +++++++++---------- esphome/components/cwww/light.py | 12 ++--- 44 files changed, 325 insertions(+), 413 deletions(-) diff --git a/esphome/components/a4988/stepper.py b/esphome/components/a4988/stepper.py index 7f53856c7b..744e9dc1cc 100644 --- a/esphome/components/a4988/stepper.py +++ b/esphome/components/a4988/stepper.py @@ -28,6 +28,6 @@ async def to_code(config): dir_pin = await cg.gpio_pin_expression(config[CONF_DIR_PIN]) cg.add(var.set_dir_pin(dir_pin)) - if CONF_SLEEP_PIN in config: - sleep_pin = await cg.gpio_pin_expression(config[CONF_SLEEP_PIN]) + if sleep_pin_config := config.get(CONF_SLEEP_PIN): + sleep_pin = await cg.gpio_pin_expression(sleep_pin_config) cg.add(var.set_sleep_pin(sleep_pin)) diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index a0eda1d659..99d3652698 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -89,14 +89,14 @@ async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) - if CONF_RAW in config: - cg.add(var.set_output_raw(config[CONF_RAW])) + if raw := config.get(CONF_RAW): + cg.add(var.set_output_raw(raw)) - if CONF_ATTENUATION in config: - if config[CONF_ATTENUATION] == "auto": + if attenuation := config.get(CONF_ATTENUATION): + if attenuation == "auto": cg.add(var.set_autorange(cg.global_ns.true)) else: - cg.add(var.set_attenuation(config[CONF_ATTENUATION])) + cg.add(var.set_attenuation(attenuation)) if CORE.is_esp32: variant = get_esp32_variant() diff --git a/esphome/components/addressable_light/display.py b/esphome/components/addressable_light/display.py index 5fdd84ac2d..2f9b8cf455 100644 --- a/esphome/components/addressable_light/display.py +++ b/esphome/components/addressable_light/display.py @@ -48,16 +48,16 @@ async def to_code(config): await cg.register_component(var, config) await display.register_display(var, config) - if CONF_PIXEL_MAPPER in config: + if pixel_mapper := config.get(CONF_PIXEL_MAPPER): pixel_mapper_template_ = await cg.process_lambda( - config[CONF_PIXEL_MAPPER], + pixel_mapper, [(int, "x"), (int, "y")], return_type=cg.int_, ) cg.add(var.set_pixel_mapper(pixel_mapper_template_)) - if CONF_LAMBDA in config: + if lambda_config := config.get(CONF_LAMBDA): lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void + lambda_config, [(display.DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ade7953/sensor.py b/esphome/components/ade7953/sensor.py index d02f466091..878f2f8e2d 100644 --- a/esphome/components/ade7953/sensor.py +++ b/esphome/components/ade7953/sensor.py @@ -72,8 +72,8 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_IRQ_PIN in config: - irq_pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN]) + if irq_pin_config := config.get(CONF_IRQ_PIN): + irq_pin = await cg.gpio_pin_expression(irq_pin_config) cg.add(var.set_irq_pin(irq_pin)) for key in [ diff --git a/esphome/components/aht10/sensor.py b/esphome/components/aht10/sensor.py index 654d645966..a52773b6d7 100644 --- a/esphome/components/aht10/sensor.py +++ b/esphome/components/aht10/sensor.py @@ -45,10 +45,10 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + if temperature := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature) cg.add(var.set_temperature_sensor(sens)) - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + if humidity := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 963d5ae719..0839e49875 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -99,8 +99,8 @@ async def register_alarm_control_panel(var, config): async def alarm_action_arm_away_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_CODE in config: - templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + if code_config := config.get(CONF_CODE): + templatable_ = await cg.templatable(code_config, args, cg.std_string) cg.add(var.set_code(templatable_)) return var @@ -111,8 +111,8 @@ async def alarm_action_arm_away_to_code(config, action_id, template_arg, args): async def alarm_action_arm_home_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_CODE in config: - templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + if code_config := config.get(CONF_CODE): + templatable_ = await cg.templatable(code_config, args, cg.std_string) cg.add(var.set_code(templatable_)) return var @@ -123,8 +123,8 @@ async def alarm_action_arm_home_to_code(config, action_id, template_arg, args): async def alarm_action_disarm_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_CODE in config: - templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + if code_config := config.get(CONF_CODE): + templatable_ = await cg.templatable(code_config, args, cg.std_string) cg.add(var.set_code(templatable_)) return var diff --git a/esphome/components/alpha3/sensor.py b/esphome/components/alpha3/sensor.py index ba4ca16a5a..55a5d7c620 100644 --- a/esphome/components/alpha3/sensor.py +++ b/esphome/components/alpha3/sensor.py @@ -60,26 +60,26 @@ async def to_code(config): await cg.register_component(var, config) await ble_client.register_ble_node(var, config) - if CONF_FLOW in config: - sens = await sensor.new_sensor(config[CONF_FLOW]) + if flow_config := config.get(CONF_FLOW): + sens = await sensor.new_sensor(flow_config) cg.add(var.set_flow_sensor(sens)) - if CONF_HEAD in config: - sens = await sensor.new_sensor(config[CONF_HEAD]) + if head_config := config.get(CONF_HEAD): + sens = await sensor.new_sensor(head_config) cg.add(var.set_head_sensor(sens)) - if CONF_POWER in config: - sens = await sensor.new_sensor(config[CONF_POWER]) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) - if CONF_CURRENT in config: - sens = await sensor.new_sensor(config[CONF_CURRENT]) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_SPEED in config: - sens = await sensor.new_sensor(config[CONF_SPEED]) + if speed_config := config.get(CONF_SPEED): + sens = await sensor.new_sensor(speed_config) cg.add(var.set_speed_sensor(sens)) - if CONF_VOLTAGE in config: - sens = await sensor.new_sensor(config[CONF_VOLTAGE]) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) diff --git a/esphome/components/am2320/sensor.py b/esphome/components/am2320/sensor.py index 088978a8f1..ccd37d02c2 100644 --- a/esphome/components/am2320/sensor.py +++ b/esphome/components/am2320/sensor.py @@ -47,10 +47,10 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature_sensor(sens)) - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/am43/sensor/__init__.py b/esphome/components/am43/sensor/__init__.py index 01588f2299..df068546cd 100644 --- a/esphome/components/am43/sensor/__init__.py +++ b/esphome/components/am43/sensor/__init__.py @@ -44,10 +44,10 @@ async def to_code(config): await cg.register_component(var, config) await ble_client.register_ble_node(var, config) - if CONF_BATTERY_LEVEL in config: - sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + if battery_level_config := config.get(CONF_BATTERY_LEVEL): + sens = await sensor.new_sensor(battery_level_config) cg.add(var.set_battery(sens)) - if CONF_ILLUMINANCE in config: - sens = await sensor.new_sensor(config[CONF_ILLUMINANCE]) + if illuminance_config := config.get(CONF_ILLUMINANCE): + sens = await sensor.new_sensor(illuminance_config) cg.add(var.set_illuminance(sens)) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 82e724fa00..7fc1e0dcd0 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -115,8 +115,8 @@ async def animation_action_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_FRAME in config: - template_ = await cg.templatable(config[CONF_FRAME], args, cg.uint16) + if frame := config.get(CONF_FRAME): + template_ = await cg.templatable(frame, args, cg.uint16) cg.add(var.set_frame(template_)) return var @@ -289,8 +289,8 @@ async def to_code(config): espImage.IMAGE_TYPE[config[CONF_TYPE]], ) cg.add(var.set_transparency(transparent)) - if CONF_LOOP in config: - start = config[CONF_LOOP][CONF_START_FRAME] - end = config[CONF_LOOP].get(CONF_END_FRAME, frames) - count = config[CONF_LOOP].get(CONF_REPEAT, -1) + if loop_config := config.get(CONF_LOOP): + start = loop_config[CONF_START_FRAME] + end = loop_config.get(CONF_END_FRAME, frames) + count = loop_config.get(CONF_REPEAT, -1) cg.add(var.set_loop(start, end, count)) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 6b2e7fd06b..1076ebc707 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -116,9 +116,8 @@ async def to_code(config): cg.add(var.register_user_service(trigger)) await automation.build_automation(trigger, func_args, conf) - if CONF_ENCRYPTION in config: - conf = config[CONF_ENCRYPTION] - decoded = base64.b64decode(conf[CONF_KEY]) + if encryption_config := config.get(CONF_ENCRYPTION): + decoded = base64.b64decode(encryption_config[CONF_KEY]) cg.add(var.set_noise_psk(list(decoded))) cg.add_define("USE_API_NOISE") cg.add_library("esphome/noise-c", "0.1.4") diff --git a/esphome/components/as3935/sensor.py b/esphome/components/as3935/sensor.py index 5a3967ed7e..ff78b8a050 100644 --- a/esphome/components/as3935/sensor.py +++ b/esphome/components/as3935/sensor.py @@ -31,12 +31,10 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): hub = await cg.get_variable(config[CONF_AS3935_ID]) - if CONF_DISTANCE in config: - conf = config[CONF_DISTANCE] - distance_sensor = await sensor.new_sensor(conf) - cg.add(hub.set_distance_sensor(distance_sensor)) + if distance_config := config.get(CONF_DISTANCE): + sens = await sensor.new_sensor(distance_config) + cg.add(hub.set_distance_sensor(sens)) - if CONF_LIGHTNING_ENERGY in config: - conf = config[CONF_LIGHTNING_ENERGY] - lightning_energy_sensor = await sensor.new_sensor(conf) - cg.add(hub.set_energy_sensor(lightning_energy_sensor)) + if lightning_energy_config := config.get(CONF_LIGHTNING_ENERGY): + sens = await sensor.new_sensor(lightning_energy_config) + cg.add(hub.set_energy_sensor(sens)) diff --git a/esphome/components/as7341/sensor.py b/esphome/components/as7341/sensor.py index 2424087c35..de60444aed 100644 --- a/esphome/components/as7341/sensor.py +++ b/esphome/components/as7341/sensor.py @@ -107,6 +107,6 @@ async def to_code(config): cg.add(var.set_astep(config[CONF_ASTEP])) for conf_id, set_sensor_func in SENSORS.items(): - if conf_id in config: - sens = await sensor.new_sensor(config[conf_id]) + if sens_config := config.get(conf_id): + sens = await sensor.new_sensor(sens_config) cg.add(getattr(var, set_sensor_func)(sens)) diff --git a/esphome/components/atc_mithermometer/sensor.py b/esphome/components/atc_mithermometer/sensor.py index 7baab51944..e86afa500d 100644 --- a/esphome/components/atc_mithermometer/sensor.py +++ b/esphome/components/atc_mithermometer/sensor.py @@ -83,18 +83,18 @@ async def to_code(config): cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) - if CONF_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature(sens)) - if CONF_HUMIDITY in config: - sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) cg.add(var.set_humidity(sens)) - if CONF_BATTERY_LEVEL in config: - sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + if battery_level_config := config.get(CONF_BATTERY_LEVEL): + sens = await sensor.new_sensor(battery_level_config) cg.add(var.set_battery_level(sens)) - if CONF_BATTERY_VOLTAGE in config: - sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE]) + if battery_voltage_config := config.get(CONF_BATTERY_VOLTAGE): + sens = await sensor.new_sensor(battery_voltage_config) cg.add(var.set_battery_voltage(sens)) - if CONF_SIGNAL_STRENGTH in config: - sens = await sensor.new_sensor(config[CONF_SIGNAL_STRENGTH]) + if signal_strength_config := config.get(CONF_SIGNAL_STRENGTH): + sens = await sensor.new_sensor(signal_strength_config) cg.add(var.set_signal_strength(sens)) diff --git a/esphome/components/atm90e26/sensor.py b/esphome/components/atm90e26/sensor.py index a0d97ab5ae..a702e23cf0 100644 --- a/esphome/components/atm90e26/sensor.py +++ b/esphome/components/atm90e26/sensor.py @@ -124,29 +124,29 @@ async def to_code(config): await cg.register_component(var, config) await spi.register_spi_device(var, config) - if CONF_VOLTAGE in config: - sens = await sensor.new_sensor(config[CONF_VOLTAGE]) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT in config: - sens = await sensor.new_sensor(config[CONF_CURRENT]) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_POWER in config: - sens = await sensor.new_sensor(config[CONF_POWER]) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) - if CONF_REACTIVE_POWER in config: - sens = await sensor.new_sensor(config[CONF_REACTIVE_POWER]) + if reactive_power_config := config.get(CONF_REACTIVE_POWER): + sens = await sensor.new_sensor(reactive_power_config) cg.add(var.set_reactive_power_sensor(sens)) - if CONF_POWER_FACTOR in config: - sens = await sensor.new_sensor(config[CONF_POWER_FACTOR]) + if power_factor_config := config.get(CONF_POWER_FACTOR): + sens = await sensor.new_sensor(power_factor_config) cg.add(var.set_power_factor_sensor(sens)) - if CONF_FORWARD_ACTIVE_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_FORWARD_ACTIVE_ENERGY]) + if forward_active_energy_config := config.get(CONF_FORWARD_ACTIVE_ENERGY): + sens = await sensor.new_sensor(forward_active_energy_config) cg.add(var.set_forward_active_energy_sensor(sens)) - if CONF_REVERSE_ACTIVE_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_REVERSE_ACTIVE_ENERGY]) + if reverse_active_energy_config := config.get(CONF_REVERSE_ACTIVE_ENERGY): + sens = await sensor.new_sensor(reverse_active_energy_config) cg.add(var.set_reverse_active_energy_sensor(sens)) - if CONF_FREQUENCY in config: - sens = await sensor.new_sensor(config[CONF_FREQUENCY]) + if frequency_config := config.get(CONF_FREQUENCY): + sens = await sensor.new_sensor(frequency_config) cg.add(var.set_freq_sensor(sens)) cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) cg.add(var.set_meter_constant(config[CONF_METER_CONSTANT])) diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index 9c876bb62c..6cc0f6ac3e 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -151,33 +151,35 @@ async def to_code(config): conf = config[phase] cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE])) cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT])) - if CONF_VOLTAGE in conf: - sens = await sensor.new_sensor(conf[CONF_VOLTAGE]) + if voltage_config := conf.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(i, sens)) - if CONF_CURRENT in conf: - sens = await sensor.new_sensor(conf[CONF_CURRENT]) + if current_config := conf.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(i, sens)) - if CONF_POWER in conf: - sens = await sensor.new_sensor(conf[CONF_POWER]) + if power_config := conf.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(i, sens)) - if CONF_REACTIVE_POWER in conf: - sens = await sensor.new_sensor(conf[CONF_REACTIVE_POWER]) + if reactive_power_config := conf.get(CONF_REACTIVE_POWER): + sens = await sensor.new_sensor(reactive_power_config) cg.add(var.set_reactive_power_sensor(i, sens)) - if CONF_POWER_FACTOR in conf: - sens = await sensor.new_sensor(conf[CONF_POWER_FACTOR]) + if power_factor_config := conf.get(CONF_POWER_FACTOR): + sens = await sensor.new_sensor(power_factor_config) cg.add(var.set_power_factor_sensor(i, sens)) - if CONF_FORWARD_ACTIVE_ENERGY in conf: - sens = await sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY]) + if forward_active_energy_config := conf.get(CONF_FORWARD_ACTIVE_ENERGY): + sens = await sensor.new_sensor(forward_active_energy_config) cg.add(var.set_forward_active_energy_sensor(i, sens)) - if CONF_REVERSE_ACTIVE_ENERGY in conf: - sens = await sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY]) + if reverse_active_energy_config := conf.get(CONF_REVERSE_ACTIVE_ENERGY): + sens = await sensor.new_sensor(reverse_active_energy_config) cg.add(var.set_reverse_active_energy_sensor(i, sens)) - if CONF_FREQUENCY in config: - sens = await sensor.new_sensor(config[CONF_FREQUENCY]) + + if frequency_config := config.get(CONF_FREQUENCY): + sens = await sensor.new_sensor(frequency_config) cg.add(var.set_freq_sensor(sens)) - if CONF_CHIP_TEMPERATURE in config: - sens = await sensor.new_sensor(config[CONF_CHIP_TEMPERATURE]) + if chip_temperature_config := config.get(CONF_CHIP_TEMPERATURE): + sens = await sensor.new_sensor(chip_temperature_config) cg.add(var.set_chip_temperature_sensor(sens)) + cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES])) cg.add(var.set_pga_gain(config[CONF_GAIN_PGA])) diff --git a/esphome/components/b_parasite/sensor.py b/esphome/components/b_parasite/sensor.py index 1b65bf7f1d..86eef29b14 100644 --- a/esphome/components/b_parasite/sensor.py +++ b/esphome/components/b_parasite/sensor.py @@ -87,6 +87,6 @@ async def to_code(config): (CONF_MOISTURE, var.set_soil_moisture), (CONF_ILLUMINANCE, var.set_illuminance), ]: - if config_key in config: - sens = await sensor.new_sensor(config[config_key]) + if sensor_config := config.get(config_key): + sens = await sensor.new_sensor(sensor_config) cg.add(setter(sens)) diff --git a/esphome/components/bang_bang/climate.py b/esphome/components/bang_bang/climate.py index 5c935987de..ac0c328000 100644 --- a/esphome/components/bang_bang/climate.py +++ b/esphome/components/bang_bang/climate.py @@ -57,19 +57,18 @@ async def to_code(config): var.get_idle_trigger(), [], config[CONF_IDLE_ACTION] ) - if CONF_COOL_ACTION in config: + if cool_action_config := config.get(CONF_COOL_ACTION): await automation.build_automation( - var.get_cool_trigger(), [], config[CONF_COOL_ACTION] + var.get_cool_trigger(), [], cool_action_config ) cg.add(var.set_supports_cool(True)) - if CONF_HEAT_ACTION in config: + if heat_action_config := config.get(CONF_HEAT_ACTION): await automation.build_automation( - var.get_heat_trigger(), [], config[CONF_HEAT_ACTION] + var.get_heat_trigger(), [], heat_action_config ) cg.add(var.set_supports_heat(True)) - if CONF_AWAY_CONFIG in config: - away = config[CONF_AWAY_CONFIG] + if away := config.get(CONF_AWAY_CONFIG): away_config = BangBangClimateTargetTempConfig( away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW], away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH], diff --git a/esphome/components/bedjet/__init__.py b/esphome/components/bedjet/__init__.py index 1697c549b3..4ff3c34075 100644 --- a/esphome/components/bedjet/__init__.py +++ b/esphome/components/bedjet/__init__.py @@ -45,8 +45,8 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_client.register_ble_node(var, config) - if CONF_TIME_ID in config: - time_ = await cg.get_variable(config[CONF_TIME_ID]) + if time_id := config.get(CONF_TIME_ID): + time_ = await cg.get_variable(time_id) cg.add(var.set_time_id(time_)) - if CONF_RECEIVE_TIMEOUT in config: - cg.add(var.set_status_timeout(config[CONF_RECEIVE_TIMEOUT])) + if receive_timeout := config.get(CONF_RECEIVE_TIMEOUT): + cg.add(var.set_status_timeout(receive_timeout)) diff --git a/esphome/components/binary/fan/__init__.py b/esphome/components/binary/fan/__init__.py index 6edfa885c9..73d6b9339f 100644 --- a/esphome/components/binary/fan/__init__.py +++ b/esphome/components/binary/fan/__init__.py @@ -29,10 +29,10 @@ async def to_code(config): output_ = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(output_)) - if CONF_OSCILLATION_OUTPUT in config: - oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT]) + if oscillation_output_id := config.get(CONF_OSCILLATION_OUTPUT): + oscillation_output = await cg.get_variable(oscillation_output_id) cg.add(var.set_oscillating(oscillation_output)) - if CONF_DIRECTION_OUTPUT in config: - direction_output = await cg.get_variable(config[CONF_DIRECTION_OUTPUT]) + if direction_output_id := config.get(CONF_DIRECTION_OUTPUT): + direction_output = await cg.get_variable(direction_output_id) cg.add(var.set_direction(direction_output)) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 95e35a45f2..fee6b6b434 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -467,14 +467,14 @@ def binary_sensor_schema( async def setup_binary_sensor_core_(var, config): await setup_entity(var, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) - if CONF_PUBLISH_INITIAL_STATE in config: - cg.add(var.set_publish_initial_state(config[CONF_PUBLISH_INITIAL_STATE])) - if CONF_INVERTED in config: - cg.add(var.set_inverted(config[CONF_INVERTED])) - if CONF_FILTERS in config: - filters = await cg.build_registry_list(FILTER_REGISTRY, config[CONF_FILTERS]) + if device_class := config.get(CONF_DEVICE_CLASS): + cg.add(var.set_device_class(device_class)) + if publish_initial_state := config.get(CONF_PUBLISH_INITIAL_STATE): + cg.add(var.set_publish_initial_state(publish_initial_state)) + if inverted := config.get(CONF_INVERTED): + cg.add(var.set_inverted(inverted)) + if filters_config := config.get(CONF_FILTERS): + filters = await cg.build_registry_list(FILTER_REGISTRY, filters_config) cg.add(var.add_filters(filters)) for conf in config.get(CONF_ON_PRESS, []): @@ -518,8 +518,8 @@ async def setup_binary_sensor_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(bool, "x")], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if mqtt_id := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/bl0939/sensor.py b/esphome/components/bl0939/sensor.py index 4c6e3ea4d9..2a85b34567 100644 --- a/esphome/components/bl0939/sensor.py +++ b/esphome/components/bl0939/sensor.py @@ -93,35 +93,27 @@ async def to_code(config): await cg.register_component(var, config) await uart.register_uart_device(var, config) - if CONF_VOLTAGE in config: - conf = config[CONF_VOLTAGE] - sens = await sensor.new_sensor(conf) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT_1 in config: - conf = config[CONF_CURRENT_1] - sens = await sensor.new_sensor(conf) + if current_1_config := config.get(CONF_CURRENT_1): + sens = await sensor.new_sensor(current_1_config) cg.add(var.set_current_sensor_1(sens)) - if CONF_CURRENT_2 in config: - conf = config[CONF_CURRENT_2] - sens = await sensor.new_sensor(conf) + if current_2_config := config.get(CONF_CURRENT_2): + sens = await sensor.new_sensor(current_2_config) cg.add(var.set_current_sensor_2(sens)) - if CONF_ACTIVE_POWER_1 in config: - conf = config[CONF_ACTIVE_POWER_1] - sens = await sensor.new_sensor(conf) + if active_power_1_config := config.get(CONF_ACTIVE_POWER_1): + sens = await sensor.new_sensor(active_power_1_config) cg.add(var.set_power_sensor_1(sens)) - if CONF_ACTIVE_POWER_2 in config: - conf = config[CONF_ACTIVE_POWER_2] - sens = await sensor.new_sensor(conf) + if active_power_2_config := config.get(CONF_ACTIVE_POWER_2): + sens = await sensor.new_sensor(active_power_2_config) cg.add(var.set_power_sensor_2(sens)) - if CONF_ENERGY_1 in config: - conf = config[CONF_ENERGY_1] - sens = await sensor.new_sensor(conf) + if energy_1_config := config.get(CONF_ENERGY_1): + sens = await sensor.new_sensor(energy_1_config) cg.add(var.set_energy_sensor_1(sens)) - if CONF_ENERGY_2 in config: - conf = config[CONF_ENERGY_2] - sens = await sensor.new_sensor(conf) + if energy_2_config := config.get(CONF_ENERGY_2): + sens = await sensor.new_sensor(energy_2_config) cg.add(var.set_energy_sensor_2(sens)) - if CONF_ENERGY_TOTAL in config: - conf = config[CONF_ENERGY_TOTAL] - sens = await sensor.new_sensor(conf) + if energy_total_config := config.get(CONF_ENERGY_TOTAL): + sens = await sensor.new_sensor(energy_total_config) cg.add(var.set_energy_sensor_sum(sens)) diff --git a/esphome/components/bl0940/sensor.py b/esphome/components/bl0940/sensor.py index 9f516a8691..702230e020 100644 --- a/esphome/components/bl0940/sensor.py +++ b/esphome/components/bl0940/sensor.py @@ -79,27 +79,21 @@ async def to_code(config): await cg.register_component(var, config) await uart.register_uart_device(var, config) - if CONF_VOLTAGE in config: - conf = config[CONF_VOLTAGE] - sens = await sensor.new_sensor(conf) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT in config: - conf = config[CONF_CURRENT] - sens = await sensor.new_sensor(conf) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_POWER in config: - conf = config[CONF_POWER] - sens = await sensor.new_sensor(conf) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) - if CONF_ENERGY in config: - conf = config[CONF_ENERGY] - sens = await sensor.new_sensor(conf) + if energy_config := config.get(CONF_ENERGY): + sens = await sensor.new_sensor(energy_config) cg.add(var.set_energy_sensor(sens)) - if CONF_INTERNAL_TEMPERATURE in config: - conf = config[CONF_INTERNAL_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if internal_temperature_config := config.get(CONF_INTERNAL_TEMPERATURE): + sens = await sensor.new_sensor(internal_temperature_config) cg.add(var.set_internal_temperature_sensor(sens)) - if CONF_EXTERNAL_TEMPERATURE in config: - conf = config[CONF_EXTERNAL_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if external_temperature_config := config.get(CONF_EXTERNAL_TEMPERATURE): + sens = await sensor.new_sensor(external_temperature_config) cg.add(var.set_external_temperature_sensor(sens)) diff --git a/esphome/components/bl0942/sensor.py b/esphome/components/bl0942/sensor.py index f23375b309..663eea0c4d 100644 --- a/esphome/components/bl0942/sensor.py +++ b/esphome/components/bl0942/sensor.py @@ -71,23 +71,18 @@ async def to_code(config): await cg.register_component(var, config) await uart.register_uart_device(var, config) - if CONF_VOLTAGE in config: - conf = config[CONF_VOLTAGE] - sens = await sensor.new_sensor(conf) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT in config: - conf = config[CONF_CURRENT] - sens = await sensor.new_sensor(conf) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_POWER in config: - conf = config[CONF_POWER] - sens = await sensor.new_sensor(conf) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) - if CONF_ENERGY in config: - conf = config[CONF_ENERGY] - sens = await sensor.new_sensor(conf) + if energy_config := config.get(CONF_ENERGY): + sens = await sensor.new_sensor(energy_config) cg.add(var.set_energy_sensor(sens)) - if CONF_FREQUENCY in config: - conf = config[CONF_FREQUENCY] - sens = await sensor.new_sensor(conf) + if frequency_config := config.get(CONF_FREQUENCY): + sens = await sensor.new_sensor(frequency_config) cg.add(var.set_frequency_sensor(sens)) diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py index c9bf2995b1..d0b27c30a9 100644 --- a/esphome/components/ble_client/sensor/__init__.py +++ b/esphome/components/ble_client/sensor/__init__.py @@ -129,32 +129,18 @@ async def characteristic_sensor_to_code(config): ) cg.add(var.set_char_uuid128(uuid128)) - if CONF_DESCRIPTOR_UUID in config: - if len(config[CONF_DESCRIPTOR_UUID]) == len(esp32_ble_tracker.bt_uuid16_format): - cg.add( - var.set_descr_uuid16( - esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID]) - ) - ) - elif len(config[CONF_DESCRIPTOR_UUID]) == len( - esp32_ble_tracker.bt_uuid32_format - ): - cg.add( - var.set_descr_uuid32( - esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID]) - ) - ) - elif len(config[CONF_DESCRIPTOR_UUID]) == len( - esp32_ble_tracker.bt_uuid128_format - ): - uuid128 = esp32_ble_tracker.as_reversed_hex_array( - config[CONF_DESCRIPTOR_UUID] - ) + if descriptor_uuid := config.get(CONF_DESCRIPTOR_UUID): + if len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid16_format): + cg.add(var.set_descr_uuid16(esp32_ble_tracker.as_hex(descriptor_uuid))) + elif len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid32_format): + cg.add(var.set_descr_uuid32(esp32_ble_tracker.as_hex(descriptor_uuid))) + elif len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid128_format): + uuid128 = esp32_ble_tracker.as_reversed_hex_array(descriptor_uuid) cg.add(var.set_descr_uuid128(uuid128)) - if CONF_LAMBDA in config: + if lambda_config := config.get(CONF_LAMBDA): lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(adv_data_t_const_ref, "x")], return_type=cg.float_ + lambda_config, [(adv_data_t_const_ref, "x")], return_type=cg.float_ ) cg.add(var.set_data_to_value(lambda_)) diff --git a/esphome/components/ble_client/text_sensor/__init__.py b/esphome/components/ble_client/text_sensor/__init__.py index 66f00c551b..7a93c4e4ae 100644 --- a/esphome/components/ble_client/text_sensor/__init__.py +++ b/esphome/components/ble_client/text_sensor/__init__.py @@ -88,27 +88,13 @@ async def to_code(config): ) cg.add(var.set_char_uuid128(uuid128)) - if CONF_DESCRIPTOR_UUID in config: - if len(config[CONF_DESCRIPTOR_UUID]) == len(esp32_ble_tracker.bt_uuid16_format): - cg.add( - var.set_descr_uuid16( - esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID]) - ) - ) - elif len(config[CONF_DESCRIPTOR_UUID]) == len( - esp32_ble_tracker.bt_uuid32_format - ): - cg.add( - var.set_descr_uuid32( - esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID]) - ) - ) - elif len(config[CONF_DESCRIPTOR_UUID]) == len( - esp32_ble_tracker.bt_uuid128_format - ): - uuid128 = esp32_ble_tracker.as_reversed_hex_array( - config[CONF_DESCRIPTOR_UUID] - ) + if descriptor_uuid := config: + if len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid16_format): + cg.add(var.set_descr_uuid16(esp32_ble_tracker.as_hex(descriptor_uuid))) + elif len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid32_format): + cg.add(var.set_descr_uuid32(esp32_ble_tracker.as_hex(descriptor_uuid))) + elif len(descriptor_uuid) == len(esp32_ble_tracker.bt_uuid128_format): + uuid128 = esp32_ble_tracker.as_reversed_hex_array(descriptor_uuid) cg.add(var.set_descr_uuid128(uuid128)) await cg.register_component(var, config) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index 75366ce864..2320d45287 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -55,35 +55,27 @@ async def to_code(config): await cg.register_component(var, config) await esp32_ble_tracker.register_ble_device(var, config) - if CONF_MIN_RSSI in config: - cg.add(var.set_minimum_rssi(config[CONF_MIN_RSSI])) + if min_rssi := config.get(CONF_MIN_RSSI): + cg.add(var.set_minimum_rssi(min_rssi)) - if CONF_MAC_ADDRESS in config: - cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + if mac_address := config.get(CONF_MAC_ADDRESS): + cg.add(var.set_address(mac_address.as_hex)) - if CONF_SERVICE_UUID in config: - if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format): - cg.add( - var.set_service_uuid16( - esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]) - ) - ) - elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid32_format): - cg.add( - var.set_service_uuid32( - esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]) - ) - ) - elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid128_format): - uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID]) + if service_uuid := config.get(CONF_SERVICE_UUID): + if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format): + cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid))) + elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid32_format): + cg.add(var.set_service_uuid32(esp32_ble_tracker.as_hex(service_uuid))) + elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid128_format): + uuid128 = esp32_ble_tracker.as_reversed_hex_array(service_uuid) cg.add(var.set_service_uuid128(uuid128)) - if CONF_IBEACON_UUID in config: - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(config[CONF_IBEACON_UUID])) + if ibeacon_uuid := config.get(CONF_IBEACON_UUID): + ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) - if CONF_IBEACON_MAJOR in config: - cg.add(var.set_ibeacon_major(config[CONF_IBEACON_MAJOR])) + if ibeacon_major := config.get(CONF_IBEACON_MAJOR): + cg.add(var.set_ibeacon_major(ibeacon_major)) - if CONF_IBEACON_MINOR in config: - cg.add(var.set_ibeacon_minor(config[CONF_IBEACON_MINOR])) + if ibeacon_minor := config.get(CONF_IBEACON_MINOR): + cg.add(var.set_ibeacon_minor(ibeacon_minor)) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 7c7bfc58a7..014843ab60 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -57,32 +57,24 @@ async def to_code(config): await cg.register_component(var, config) await esp32_ble_tracker.register_ble_device(var, config) - if CONF_MAC_ADDRESS in config: - cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + if mac_address := config.get(CONF_MAC_ADDRESS): + cg.add(var.set_address(mac_address.as_hex)) - if CONF_SERVICE_UUID in config: - if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format): - cg.add( - var.set_service_uuid16( - esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]) - ) - ) - elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid32_format): - cg.add( - var.set_service_uuid32( - esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]) - ) - ) - elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid128_format): - uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID]) + if service_uuid := config.get(CONF_SERVICE_UUID): + if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format): + cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid))) + elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid32_format): + cg.add(var.set_service_uuid32(esp32_ble_tracker.as_hex(service_uuid))) + elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid128_format): + uuid128 = esp32_ble_tracker.as_reversed_hex_array(service_uuid) cg.add(var.set_service_uuid128(uuid128)) - if CONF_IBEACON_UUID in config: - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(config[CONF_IBEACON_UUID])) + if ibeacon_uuid := config.get(CONF_IBEACON_UUID): + ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) - if CONF_IBEACON_MAJOR in config: - cg.add(var.set_ibeacon_major(config[CONF_IBEACON_MAJOR])) + if ibeacon_major := config.get(CONF_IBEACON_MAJOR): + cg.add(var.set_ibeacon_major(ibeacon_major)) - if CONF_IBEACON_MINOR in config: - cg.add(var.set_ibeacon_minor(config[CONF_IBEACON_MINOR])) + if ibeacon_minor := config.get(CONF_IBEACON_MINOR): + cg.add(var.set_ibeacon_minor(ibeacon_minor)) diff --git a/esphome/components/bme280/sensor.py b/esphome/components/bme280/sensor.py index dcb842d879..35744a436d 100644 --- a/esphome/components/bme280/sensor.py +++ b/esphome/components/bme280/sensor.py @@ -98,22 +98,19 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - conf = config[CONF_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) - if CONF_PRESSURE in config: - conf = config[CONF_PRESSURE] - sens = await sensor.new_sensor(conf) + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) - if CONF_HUMIDITY in config: - conf = config[CONF_HUMIDITY] - sens = await sensor.new_sensor(conf) + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) cg.add(var.set_humidity_sensor(sens)) - cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_humidity_oversampling(humidity_config[CONF_OVERSAMPLING])) cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py index 76472c7562..586b454697 100644 --- a/esphome/components/bme680/sensor.py +++ b/esphome/components/bme680/sensor.py @@ -130,27 +130,23 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - conf = config[CONF_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) - if CONF_PRESSURE in config: - conf = config[CONF_PRESSURE] - sens = await sensor.new_sensor(conf) + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) - if CONF_HUMIDITY in config: - conf = config[CONF_HUMIDITY] - sens = await sensor.new_sensor(conf) + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) cg.add(var.set_humidity_sensor(sens)) - cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_humidity_oversampling(humidity_config[CONF_OVERSAMPLING])) - if CONF_GAS_RESISTANCE in config: - conf = config[CONF_GAS_RESISTANCE] - sens = await sensor.new_sensor(conf) + if gas_resistance_config := config.get(CONF_GAS_RESISTANCE): + sens = await sensor.new_sensor(gas_resistance_config) cg.add(var.set_gas_resistance_sensor(sens)) cg.add(var.set_iir_filter(IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]])) diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 3bd082481e..43b068b926 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -108,12 +108,13 @@ CONFIG_SCHEMA = cv.Schema( async def setup_conf(config, key, hub): - if key in config: - conf = config[key] - sens = await sensor.new_sensor(conf) + if sensor_config := config.get(key): + sens = await sensor.new_sensor(sensor_config) cg.add(getattr(hub, f"set_{key}_sensor")(sens)) - if CONF_SAMPLE_RATE in conf: - cg.add(getattr(hub, f"set_{key}_sample_rate")(conf[CONF_SAMPLE_RATE])) + if CONF_SAMPLE_RATE in sensor_config: + cg.add( + getattr(hub, f"set_{key}_sample_rate")(sensor_config[CONF_SAMPLE_RATE]) + ) async def to_code(config): diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index 2d93c90818..3494ba0cac 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -21,9 +21,8 @@ CONFIG_SCHEMA = cv.Schema( async def setup_conf(config, key, hub): - if key in config: - conf = config[key] - sens = await text_sensor.new_text_sensor(conf) + if sensor_config := config.get(key): + sens = await text_sensor.new_text_sensor(sensor_config) cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) diff --git a/esphome/components/bmp085/sensor.py b/esphome/components/bmp085/sensor.py index 52f554120a..83f5a0c821 100644 --- a/esphome/components/bmp085/sensor.py +++ b/esphome/components/bmp085/sensor.py @@ -47,12 +47,10 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - conf = config[CONF_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature(sens)) - if CONF_PRESSURE in config: - conf = config[CONF_PRESSURE] - sens = await sensor.new_sensor(conf) + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) cg.add(var.set_pressure(sens)) diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index e80511a509..a23bc0766a 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -83,16 +83,14 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - if CONF_TEMPERATURE in config: - conf = config[CONF_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) - if CONF_PRESSURE in config: - conf = config[CONF_PRESSURE] - sens = await sensor.new_sensor(conf) + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) + cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) diff --git a/esphome/components/bmp3xx/sensor.py b/esphome/components/bmp3xx/sensor.py index f0da1c3c24..6f90173c7b 100644 --- a/esphome/components/bmp3xx/sensor.py +++ b/esphome/components/bmp3xx/sensor.py @@ -87,14 +87,16 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER])) - if CONF_TEMPERATURE in config: - conf = config[CONF_TEMPERATURE] - sens = await sensor.new_sensor(conf) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling_config(conf[CONF_OVERSAMPLING])) + cg.add( + var.set_temperature_oversampling_config( + temperature_config[CONF_OVERSAMPLING] + ) + ) - if CONF_PRESSURE in config: - conf = config[CONF_PRESSURE] - sens = await sensor.new_sensor(conf) + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling_config(conf[CONF_OVERSAMPLING])) + cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING])) diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index a999c6d91e..5dcbf7ad01 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -85,11 +85,11 @@ async def setup_button_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) + if device_class := config.get(CONF_DEVICE_CLASS): + cg.add(var.set_device_class(device_class)) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if mqtt_id := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/canbus/__init__.py b/esphome/components/canbus/__init__.py index 1dbd743c75..efa55b220e 100644 --- a/esphome/components/canbus/__init__.py +++ b/esphome/components/canbus/__init__.py @@ -17,11 +17,10 @@ CONF_ON_FRAME = "on_frame" def validate_id(config): - if CONF_CAN_ID in config: - id_value = config[CONF_CAN_ID] + if can_id := config.get(CONF_CAN_ID): id_ext = config[CONF_USE_EXTENDED_ID] if not id_ext: - if id_value > 0x7FF: + if can_id > 0x7FF: raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") return config @@ -145,8 +144,8 @@ async def canbus_action_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_CANBUS_ID]) - if CONF_CAN_ID in config: - can_id = await cg.templatable(config[CONF_CAN_ID], args, cg.uint32) + if can_id := config.get(CONF_CAN_ID): + can_id = await cg.templatable(can_id, args, cg.uint32) cg.add(var.set_can_id(can_id)) use_extended_id = await cg.templatable( config[CONF_USE_EXTENDED_ID], args, cg.uint32 diff --git a/esphome/components/cap1188/__init__.py b/esphome/components/cap1188/__init__.py index 80794c5146..74be9df186 100644 --- a/esphome/components/cap1188/__init__.py +++ b/esphome/components/cap1188/__init__.py @@ -37,8 +37,8 @@ async def to_code(config): cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) cg.add(var.set_allow_multiple_touches(config[CONF_ALLOW_MULTIPLE_TOUCHES])) - if CONF_RESET_PIN in config: - pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) + if reset_pin_config := config.get(CONF_RESET_PIN): + pin = await cg.gpio_pin_expression(reset_pin_config) cg.add(var.set_reset_pin(pin)) await cg.register_component(var, config) diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index af3e6574ab..4133255b15 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -69,16 +69,16 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_TVOC]) cg.add(var.set_tvoc(sens)) - if CONF_VERSION in config: - sens = await text_sensor.new_text_sensor(config[CONF_VERSION]) + if version_config := config.get(CONF_VERSION): + sens = await text_sensor.new_text_sensor(version_config) cg.add(var.set_version(sens)) - if CONF_BASELINE in config: - cg.add(var.set_baseline(config[CONF_BASELINE])) + if baseline := config.get(CONF_BASELINE): + cg.add(var.set_baseline(baseline)) - if CONF_TEMPERATURE in config: - sens = await cg.get_variable(config[CONF_TEMPERATURE]) + if temperature_id := config.get(CONF_TEMPERATURE): + sens = await cg.get_variable(temperature_id) cg.add(var.set_temperature(sens)) - if CONF_HUMIDITY in config: - sens = await cg.get_variable(config[CONF_HUMIDITY]) + if humidity_id := config.get(CONF_HUMIDITY): + sens = await cg.get_variable(humidity_id) cg.add(var.set_humidity(sens)) diff --git a/esphome/components/climate_ir/__init__.py b/esphome/components/climate_ir/__init__.py index 1389ebfc6d..0cf1339971 100644 --- a/esphome/components/climate_ir/__init__.py +++ b/esphome/components/climate_ir/__init__.py @@ -44,11 +44,11 @@ async def register_climate_ir(var, config): cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) - if CONF_SENSOR in config: - sens = await cg.get_variable(config[CONF_SENSOR]) + if sensor_id := config.get(CONF_SENSOR): + sens = await cg.get_variable(sensor_id) cg.add(var.set_sensor(sens)) - if CONF_RECEIVER_ID in config: - receiver = await cg.get_variable(config[CONF_RECEIVER_ID]) + if receiver_id := config.get(CONF_RECEIVER_ID): + receiver = await cg.get_variable(receiver_id) cg.add(receiver.register_listener(var)) transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) diff --git a/esphome/components/cs5460a/sensor.py b/esphome/components/cs5460a/sensor.py index d6e3c2ba48..c27fc5fc3c 100644 --- a/esphome/components/cs5460a/sensor.py +++ b/esphome/components/cs5460a/sensor.py @@ -113,17 +113,14 @@ async def to_code(config): cg.add(var.set_hpf_enable(config[CONF_CURRENT_HPF], config[CONF_VOLTAGE_HPF])) cg.add(var.set_pulse_energy_wh(config[CONF_PULSE_ENERGY])) - if CONF_VOLTAGE in config: - conf = config[CONF_VOLTAGE] - sens = await sensor.new_sensor(conf) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT in config: - conf = config[CONF_CURRENT] - sens = await sensor.new_sensor(conf) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_POWER in config: - conf = config[CONF_POWER] - sens = await sensor.new_sensor(conf) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index 2f48aff0aa..d98b351287 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -69,19 +69,15 @@ async def to_code(config): await cg.register_component(var, config) await uart.register_uart_device(var, config) - if CONF_VOLTAGE in config: - conf = config[CONF_VOLTAGE] - sens = await sensor.new_sensor(conf) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) cg.add(var.set_voltage_sensor(sens)) - if CONF_CURRENT in config: - conf = config[CONF_CURRENT] - sens = await sensor.new_sensor(conf) + if current_config := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) cg.add(var.set_current_sensor(sens)) - if CONF_POWER in config: - conf = config[CONF_POWER] - sens = await sensor.new_sensor(conf) + if power_config := config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) cg.add(var.set_power_sensor(sens)) - if CONF_ENERGY in config: - conf = config[CONF_ENERGY] - sens = await sensor.new_sensor(conf) + if energy_config := config.get(CONF_ENERGY): + sens = await sensor.new_sensor(energy_config) cg.add(var.set_energy_sensor(sens)) diff --git a/esphome/components/current_based/cover.py b/esphome/components/current_based/cover.py index eb77a90aff..41732305a1 100644 --- a/esphome/components/current_based/cover.py +++ b/esphome/components/current_based/cover.py @@ -66,59 +66,57 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield cover.register_cover(var, config) + await cg.register_component(var, config) + await cover.register_cover(var, config) - yield automation.build_automation( + await automation.build_automation( var.get_stop_trigger(), [], config[CONF_STOP_ACTION] ) # OPEN - bin = yield cg.get_variable(config[CONF_OPEN_SENSOR]) + bin = await cg.get_variable(config[CONF_OPEN_SENSOR]) cg.add(var.set_open_sensor(bin)) cg.add( var.set_open_moving_current_threshold( config[CONF_OPEN_MOVING_CURRENT_THRESHOLD] ) ) - if CONF_OPEN_OBSTACLE_CURRENT_THRESHOLD in config: - cg.add( - var.set_open_obstacle_current_threshold( - config[CONF_OPEN_OBSTACLE_CURRENT_THRESHOLD] - ) - ) + if open_obsticle_current_threshold := config.get( + CONF_OPEN_OBSTACLE_CURRENT_THRESHOLD + ): + cg.add(var.set_open_obstacle_current_threshold(open_obsticle_current_threshold)) cg.add(var.set_open_duration(config[CONF_OPEN_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_open_trigger(), [], config[CONF_OPEN_ACTION] ) # CLOSE - bin = yield cg.get_variable(config[CONF_CLOSE_SENSOR]) + bin = await cg.get_variable(config[CONF_CLOSE_SENSOR]) cg.add(var.set_close_sensor(bin)) cg.add( var.set_close_moving_current_threshold( config[CONF_CLOSE_MOVING_CURRENT_THRESHOLD] ) ) - if CONF_CLOSE_OBSTACLE_CURRENT_THRESHOLD in config: + if close_obsticle_current_threshold := config.get( + CONF_CLOSE_OBSTACLE_CURRENT_THRESHOLD + ): cg.add( - var.set_close_obstacle_current_threshold( - config[CONF_CLOSE_OBSTACLE_CURRENT_THRESHOLD] - ) + var.set_close_obstacle_current_threshold(close_obsticle_current_threshold) ) cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] ) cg.add(var.set_obstacle_rollback(config[CONF_OBSTACLE_ROLLBACK])) - if CONF_MAX_DURATION in config: - cg.add(var.set_max_duration(config[CONF_MAX_DURATION])) + if max_duration := config.get(CONF_MAX_DURATION): + cg.add(var.set_max_duration(max_duration)) cg.add(var.set_malfunction_detection(config[CONF_MALFUNCTION_DETECTION])) - if CONF_MALFUNCTION_ACTION in config: - yield automation.build_automation( - var.get_malfunction_trigger(), [], config[CONF_MALFUNCTION_ACTION] + if malfunction_action := config.get(CONF_MALFUNCTION_ACTION): + await automation.build_automation( + var.get_malfunction_trigger(), [], malfunction_action ) cg.add(var.set_start_sensing_delay(config[CONF_START_SENSING_DELAY])) diff --git a/esphome/components/cwww/light.py b/esphome/components/cwww/light.py index fc204b2f3b..c88a6b0054 100644 --- a/esphome/components/cwww/light.py +++ b/esphome/components/cwww/light.py @@ -37,16 +37,12 @@ async def to_code(config): cwhite = await cg.get_variable(config[CONF_COLD_WHITE]) cg.add(var.set_cold_white(cwhite)) - if CONF_COLD_WHITE_COLOR_TEMPERATURE in config: - cg.add( - var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]) - ) + if cold_white_color_temperature := config.get(CONF_COLD_WHITE_COLOR_TEMPERATURE): + cg.add(var.set_cold_white_temperature(cold_white_color_temperature)) wwhite = await cg.get_variable(config[CONF_WARM_WHITE]) cg.add(var.set_warm_white(wwhite)) - if CONF_WARM_WHITE_COLOR_TEMPERATURE in config: - cg.add( - var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE]) - ) + if warm_white_color_temperature := config.get(CONF_WARM_WHITE_COLOR_TEMPERATURE): + cg.add(var.set_warm_white_temperature(warm_white_color_temperature)) cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) From dfffa67c0fa6d693df28100c31df05043412af0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:35:16 +1200 Subject: [PATCH 0303/2607] Bump click from 8.1.5 to 8.1.6 (#5179) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d5ca30a387..3160fe42de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.7 # When updating platformio, also update Dockerfile esptool==4.6.2 -click==8.1.5 +click==8.1.6 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 zeroconf==0.71.4 From 0ae3fcb0b741648648ec784fc89ab5104d702ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Mon, 7 Aug 2023 01:41:44 +0200 Subject: [PATCH 0304/2607] PWM Output on RP2040 for high frequencies (#5204) --- esphome/components/rp2040_pwm/rp2040_pwm.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/rp2040_pwm/rp2040_pwm.cpp b/esphome/components/rp2040_pwm/rp2040_pwm.cpp index 3c5591885e..170af59905 100644 --- a/esphome/components/rp2040_pwm/rp2040_pwm.cpp +++ b/esphome/components/rp2040_pwm/rp2040_pwm.cpp @@ -27,8 +27,12 @@ void RP2040PWM::setup_pwm_() { uint32_t clock = clock_get_hz(clk_sys); float divider = ceil(clock / (4096 * this->frequency_)) / 16.0f; + if (divider < 1.0f) { + divider = 1.0f; + } uint16_t wrap = clock / divider / this->frequency_ - 1; this->wrap_ = wrap; + ESP_LOGD(TAG, "divider=%.5f, wrap=%d, clock=%d", divider, wrap, clock); pwm_config_set_clkdiv(&config, divider); pwm_config_set_wrap(&config, wrap); From 00f9af70a92da04894e0d349a01d26dc9887c62c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 7 Aug 2023 11:48:23 +1200 Subject: [PATCH 0305/2607] Fix some configs after #5181 (#5209) --- esphome/components/adc/sensor.py | 3 +-- esphome/components/animation/__init__.py | 2 +- esphome/components/bedjet/__init__.py | 2 +- esphome/components/binary_sensor/__init__.py | 2 +- .../components/ble_presence/binary_sensor.py | 4 ++-- esphome/components/ble_rssi/sensor.py | 4 ++-- esphome/components/canbus/__init__.py | 10 +++++----- esphome/components/ccs811/sensor.py | 2 +- esphome/components/current_based/cover.py | 20 ++++++++++++------- 9 files changed, 27 insertions(+), 22 deletions(-) diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 99d3652698..c1ae22214d 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -89,8 +89,7 @@ async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) - if raw := config.get(CONF_RAW): - cg.add(var.set_output_raw(raw)) + cg.add(var.set_output_raw(config[CONF_RAW])) if attenuation := config.get(CONF_ATTENUATION): if attenuation == "auto": diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 7fc1e0dcd0..52e14f0a43 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -115,7 +115,7 @@ async def animation_action_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if frame := config.get(CONF_FRAME): + if (frame := config.get(CONF_FRAME)) is not None: template_ = await cg.templatable(frame, args, cg.uint16) cg.add(var.set_frame(template_)) return var diff --git a/esphome/components/bedjet/__init__.py b/esphome/components/bedjet/__init__.py index 4ff3c34075..395a5f25e4 100644 --- a/esphome/components/bedjet/__init__.py +++ b/esphome/components/bedjet/__init__.py @@ -48,5 +48,5 @@ async def to_code(config): if time_id := config.get(CONF_TIME_ID): time_ = await cg.get_variable(time_id) cg.add(var.set_time_id(time_)) - if receive_timeout := config.get(CONF_RECEIVE_TIMEOUT): + if (receive_timeout := config.get(CONF_RECEIVE_TIMEOUT)) is not None: cg.add(var.set_status_timeout(receive_timeout)) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index fee6b6b434..babe46e082 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -467,7 +467,7 @@ def binary_sensor_schema( async def setup_binary_sensor_core_(var, config): await setup_entity(var, config) - if device_class := config.get(CONF_DEVICE_CLASS): + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: cg.add(var.set_device_class(device_class)) if publish_initial_state := config.get(CONF_PUBLISH_INITIAL_STATE): cg.add(var.set_publish_initial_state(publish_initial_state)) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index 2320d45287..81878391bb 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -74,8 +74,8 @@ async def to_code(config): ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) - if ibeacon_major := config.get(CONF_IBEACON_MAJOR): + if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: cg.add(var.set_ibeacon_major(ibeacon_major)) - if ibeacon_minor := config.get(CONF_IBEACON_MINOR): + if (ibeacon_minor := config.get(CONF_IBEACON_MINOR)) is not None: cg.add(var.set_ibeacon_minor(ibeacon_minor)) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 014843ab60..4246d311ab 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -73,8 +73,8 @@ async def to_code(config): ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) - if ibeacon_major := config.get(CONF_IBEACON_MAJOR): + if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: cg.add(var.set_ibeacon_major(ibeacon_major)) - if ibeacon_minor := config.get(CONF_IBEACON_MINOR): + if (ibeacon_minor := config.get(CONF_IBEACON_MINOR)) is not None: cg.add(var.set_ibeacon_minor(ibeacon_minor)) diff --git a/esphome/components/canbus/__init__.py b/esphome/components/canbus/__init__.py index efa55b220e..c5a9924644 100644 --- a/esphome/components/canbus/__init__.py +++ b/esphome/components/canbus/__init__.py @@ -17,11 +17,11 @@ CONF_ON_FRAME = "on_frame" def validate_id(config): - if can_id := config.get(CONF_CAN_ID): - id_ext = config[CONF_USE_EXTENDED_ID] - if not id_ext: - if can_id > 0x7FF: - raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") + can_id = config[CONF_CAN_ID] + id_ext = config[CONF_USE_EXTENDED_ID] + if not id_ext: + if can_id > 0x7FF: + raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") return config diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index 4133255b15..66d9274fe8 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -73,7 +73,7 @@ async def to_code(config): sens = await text_sensor.new_text_sensor(version_config) cg.add(var.set_version(sens)) - if baseline := config.get(CONF_BASELINE): + if (baseline := config.get(CONF_BASELINE)) is not None: cg.add(var.set_baseline(baseline)) if temperature_id := config.get(CONF_TEMPERATURE): diff --git a/esphome/components/current_based/cover.py b/esphome/components/current_based/cover.py index 41732305a1..1fa4eaa03f 100644 --- a/esphome/components/current_based/cover.py +++ b/esphome/components/current_based/cover.py @@ -83,10 +83,13 @@ async def to_code(config): config[CONF_OPEN_MOVING_CURRENT_THRESHOLD] ) ) - if open_obsticle_current_threshold := config.get( - CONF_OPEN_OBSTACLE_CURRENT_THRESHOLD - ): + if ( + open_obsticle_current_threshold := config.get( + CONF_OPEN_OBSTACLE_CURRENT_THRESHOLD + ) + ) is not None: cg.add(var.set_open_obstacle_current_threshold(open_obsticle_current_threshold)) + cg.add(var.set_open_duration(config[CONF_OPEN_DURATION])) await automation.build_automation( var.get_open_trigger(), [], config[CONF_OPEN_ACTION] @@ -100,19 +103,22 @@ async def to_code(config): config[CONF_CLOSE_MOVING_CURRENT_THRESHOLD] ) ) - if close_obsticle_current_threshold := config.get( - CONF_CLOSE_OBSTACLE_CURRENT_THRESHOLD - ): + if ( + close_obsticle_current_threshold := config.get( + CONF_CLOSE_OBSTACLE_CURRENT_THRESHOLD + ) + ) is not None: cg.add( var.set_close_obstacle_current_threshold(close_obsticle_current_threshold) ) + cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) await automation.build_automation( var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] ) cg.add(var.set_obstacle_rollback(config[CONF_OBSTACLE_ROLLBACK])) - if max_duration := config.get(CONF_MAX_DURATION): + if (max_duration := config.get(CONF_MAX_DURATION)) is not None: cg.add(var.set_max_duration(max_duration)) cg.add(var.set_malfunction_detection(config[CONF_MALFUNCTION_DETECTION])) if malfunction_action := config.get(CONF_MALFUNCTION_ACTION): From 62fed4c1eb1079f29e72e1a80b749a8dafe43f8e Mon Sep 17 00:00:00 2001 From: arno1801 <120399978+arno1801@users.noreply.github.com> Date: Sun, 6 Aug 2023 19:59:17 -0400 Subject: [PATCH 0306/2607] Improved compensation sgp30 (#5208) --- esphome/components/sgp30/sgp30.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/esphome/components/sgp30/sgp30.cpp b/esphome/components/sgp30/sgp30.cpp index a6572620c4..25a3c1ab8f 100644 --- a/esphome/components/sgp30/sgp30.cpp +++ b/esphome/components/sgp30/sgp30.cpp @@ -181,9 +181,18 @@ void SGP30Component::send_env_data_() { ESP_LOGD(TAG, "External compensation data received: Temperature %0.2f°C", temperature); } - float absolute_humidity = - 216.7f * (((humidity / 100) * 6.112f * std::exp((17.62f * temperature) / (243.12f + temperature))) / - (273.15f + temperature)); + float absolute_humidity; + if (temperature < 0) { + absolute_humidity = + 216.67f * + ((humidity * 0.061121f * std::exp((23.036f - temperature / 333.7f) * (temperature / (279.82f + temperature)))) / + (273.15f + temperature)); + } else { + absolute_humidity = + 216.67f * + ((humidity * 0.061121f * std::exp((18.678f - temperature / 234.5f) * (temperature / (257.14f + temperature)))) / + (273.15f + temperature)); + } uint8_t humidity_full = uint8_t(std::floor(absolute_humidity)); uint8_t humidity_dec = uint8_t(std::floor((absolute_humidity - std::floor(absolute_humidity)) * 256)); ESP_LOGD(TAG, "Calculated Absolute humidity: %0.3f g/m³ (0x%04X)", absolute_humidity, From 1495fada9049cefe6d9fac3a9df6b10e19b630a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Cirne?= Date: Mon, 7 Aug 2023 01:22:18 +0100 Subject: [PATCH 0307/2607] Add support for a01nyub (#4863) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/a01nyub/__init__.py | 1 + esphome/components/a01nyub/a01nyub.cpp | 57 ++++++++++++++++++++++++++ esphome/components/a01nyub/a01nyub.h | 27 ++++++++++++ esphome/components/a01nyub/sensor.py | 41 ++++++++++++++++++ tests/test4.yaml | 18 ++++++-- 6 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 esphome/components/a01nyub/__init__.py create mode 100644 esphome/components/a01nyub/a01nyub.cpp create mode 100644 esphome/components/a01nyub/a01nyub.h create mode 100644 esphome/components/a01nyub/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 122dc71b48..17d1462405 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -11,6 +11,7 @@ esphome/*.py @esphome/core esphome/core/* @esphome/core # Integrations +esphome/components/a01nyub/* @MrSuicideParrot esphome/components/absolute_humidity/* @DAVe3283 esphome/components/ac_dimmer/* @glmnet esphome/components/adc/* @esphome/core diff --git a/esphome/components/a01nyub/__init__.py b/esphome/components/a01nyub/__init__.py new file mode 100644 index 0000000000..4c84847fb6 --- /dev/null +++ b/esphome/components/a01nyub/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@MrSuicideParrot"] diff --git a/esphome/components/a01nyub/a01nyub.cpp b/esphome/components/a01nyub/a01nyub.cpp new file mode 100644 index 0000000000..75cb276f84 --- /dev/null +++ b/esphome/components/a01nyub/a01nyub.cpp @@ -0,0 +1,57 @@ +// Datasheet https://wiki.dfrobot.com/A01NYUB%20Waterproof%20Ultrasonic%20Sensor%20SKU:%20SEN0313 + +#include "a01nyub.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace a01nyub { + +static const char *const TAG = "a01nyub.sensor"; +static const uint8_t MAX_DATA_LENGTH_BYTES = 4; + +void A01nyubComponent::loop() { + uint8_t data; + while (this->available() > 0) { + if (this->read_byte(&data)) { + buffer_.push_back(data); + this->check_buffer_(); + } + } +} + +void A01nyubComponent::check_buffer_() { + if (this->buffer_.size() >= MAX_DATA_LENGTH_BYTES) { + size_t i; + for (i = 0; i < this->buffer_.size(); i++) { + // Look for the first packet + if (this->buffer_[i] == 0xFF) { + if (i + 1 + 3 < this->buffer_.size()) { // Packet is not complete + return; // Wait for completion + } + + uint8_t checksum = (this->buffer_[i] + this->buffer_[i + 1] + this->buffer_[i + 2]) & 0xFF; + if (this->buffer_[i + 3] == checksum) { + float distance = (this->buffer_[i + 1] << 8) + this->buffer_[i + 2]; + if (distance > 280) { + float meters = distance / 1000.0; + ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters); + this->publish_state(meters); + } else { + ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str()); + } + } + break; + } + } + this->buffer_.clear(); + } +} + +void A01nyubComponent::dump_config() { + ESP_LOGCONFIG(TAG, "A01nyub Sensor:"); + LOG_SENSOR(" ", "Distance", this); +} + +} // namespace a01nyub +} // namespace esphome diff --git a/esphome/components/a01nyub/a01nyub.h b/esphome/components/a01nyub/a01nyub.h new file mode 100644 index 0000000000..6b22e9bcad --- /dev/null +++ b/esphome/components/a01nyub/a01nyub.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" + +namespace esphome { +namespace a01nyub { + +class A01nyubComponent : public sensor::Sensor, public Component, public uart::UARTDevice { + public: + // Nothing really public. + + // ========== INTERNAL METHODS ========== + void loop() override; + void dump_config() override; + + protected: + void check_buffer_(); + + std::vector buffer_; +}; + +} // namespace a01nyub +} // namespace esphome diff --git a/esphome/components/a01nyub/sensor.py b/esphome/components/a01nyub/sensor.py new file mode 100644 index 0000000000..b57daa0357 --- /dev/null +++ b/esphome/components/a01nyub/sensor.py @@ -0,0 +1,41 @@ +import esphome.codegen as cg +from esphome.components import sensor, uart +from esphome.const import ( + STATE_CLASS_MEASUREMENT, + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, + DEVICE_CLASS_DISTANCE, +) + +CODEOWNERS = ["@MrSuicideParrot"] +DEPENDENCIES = ["uart"] + +a01nyub_ns = cg.esphome_ns.namespace("a01nyub") +A01nyubComponent = a01nyub_ns.class_( + "A01nyubComponent", sensor.Sensor, cg.Component, uart.UARTDevice +) + +CONFIG_SCHEMA = sensor.sensor_schema( + A01nyubComponent, + unit_of_measurement=UNIT_METER, + icon=ICON_ARROW_EXPAND_VERTICAL, + accuracy_decimals=3, + state_class=STATE_CLASS_MEASUREMENT, + device_class=DEVICE_CLASS_DISTANCE, +).extend(uart.UART_DEVICE_SCHEMA) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "a01nyub", + baud_rate=9600, + require_tx=False, + require_rx=True, + data_bits=8, + parity=None, + stop_bits=1, +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/tests/test4.yaml b/tests/test4.yaml index 2a8cb02413..54caebf1fe 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -34,9 +34,14 @@ spi: miso_pin: GPIO23 uart: - tx_pin: GPIO22 - rx_pin: GPIO23 - baud_rate: 115200 + - id: uart115200 + tx_pin: GPIO22 + rx_pin: GPIO23 + baud_rate: 115200 + - id: uart9600 + tx_pin: GPIO22 + rx_pin: GPIO23 + baud_rate: 9600 ota: safe_mode: true @@ -58,6 +63,7 @@ time: tuya: time_id: sntp_time + uart_id: uart115200 status_pin: number: 14 inverted: true @@ -73,6 +79,7 @@ select: pipsolar: id: inverter0 + uart_id: uart115200 sx1509: - id: sx1509_hub @@ -229,6 +236,7 @@ sensor: name: inverter0_pv_charging_power - platform: hrxl_maxsonar_wr name: Rainwater Tank Level + uart_id: uart115200 filters: - sliding_window_moving_average: window_size: 12 @@ -257,6 +265,10 @@ sensor: name: Ufire Temperature ph: name: Ufire pH + - platform: a01nyub + id: a01nyub_sensor + name: "a01nyub Distance" + uart_id: uart9600 # # platform sensor.apds9960 requires component apds9960 From 3a07121784c3c69c5966d0ae23ac9fd677703b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozubal?= Date: Mon, 7 Aug 2023 03:46:31 +0200 Subject: [PATCH 0308/2607] Change device name in MQTT discovery messages to friendly names (#5205) --- esphome/components/mqtt/mqtt_component.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index b663d7751d..1c7d9f86dd 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -132,9 +132,14 @@ bool MQTTComponent::send_discovery_() { if (discovery_info.object_id_generator == MQTT_DEVICE_NAME_OBJECT_ID_GENERATOR) root[MQTT_OBJECT_ID] = node_name + "_" + this->get_default_object_id_(); + std::string node_friendly_name = App.get_friendly_name(); + if (node_friendly_name.empty()) { + node_friendly_name = node_name; + } + JsonObject device_info = root.createNestedObject(MQTT_DEVICE); device_info[MQTT_DEVICE_IDENTIFIERS] = get_mac_address(); - device_info[MQTT_DEVICE_NAME] = node_name; + device_info[MQTT_DEVICE_NAME] = node_friendly_name; device_info[MQTT_DEVICE_SW_VERSION] = "esphome v" ESPHOME_VERSION " " + App.get_compilation_time(); device_info[MQTT_DEVICE_MODEL] = ESPHOME_BOARD; device_info[MQTT_DEVICE_MANUFACTURER] = "espressif"; From fd08f1e23d5efb4f4ff3e23d9125fbd82732cf61 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Aug 2023 20:54:25 -0500 Subject: [PATCH 0309/2607] Add ESP32-S2/S3 capacitive touch support (#5116) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32_touch/__init__.py | 235 +++++++++++++++++- .../components/esp32_touch/binary_sensor.py | 75 +----- .../components/esp32_touch/esp32_touch.cpp | 206 +++++++++++++-- esphome/components/esp32_touch/esp32_touch.h | 99 +++++--- 4 files changed, 484 insertions(+), 131 deletions(-) diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index 3c9bef9665..0180d18104 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -12,25 +12,112 @@ from esphome.const import ( ) from esphome.core import TimePeriod from esphome.components import esp32 +from esphome.components.esp32 import get_esp32_variant, gpio +from esphome.components.esp32.const import ( + VARIANT_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) AUTO_LOAD = ["binary_sensor"] DEPENDENCIES = ["esp32"] +CONF_DEBOUNCE_COUNT = "debounce_count" +CONF_DENOISE_GRADE = "denoise_grade" +CONF_DENOISE_CAP_LEVEL = "denoise_cap_level" +CONF_FILTER_MODE = "filter_mode" +CONF_NOISE_THRESHOLD = "noise_threshold" +CONF_JITTER_STEP = "jitter_step" +CONF_SMOOTH_MODE = "smooth_mode" +CONF_WATERPROOF_GUARD_RING = "waterproof_guard_ring" +CONF_WATERPROOF_SHIELD_DRIVER = "waterproof_shield_driver" + esp32_touch_ns = cg.esphome_ns.namespace("esp32_touch") ESP32TouchComponent = esp32_touch_ns.class_("ESP32TouchComponent", cg.Component) +TOUCH_PADS = { + VARIANT_ESP32: { + 4: cg.global_ns.TOUCH_PAD_NUM0, + 0: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 15: cg.global_ns.TOUCH_PAD_NUM3, + 13: cg.global_ns.TOUCH_PAD_NUM4, + 12: cg.global_ns.TOUCH_PAD_NUM5, + 14: cg.global_ns.TOUCH_PAD_NUM6, + 27: cg.global_ns.TOUCH_PAD_NUM7, + 33: cg.global_ns.TOUCH_PAD_NUM8, + 32: cg.global_ns.TOUCH_PAD_NUM9, + }, + VARIANT_ESP32S2: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, + VARIANT_ESP32S3: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, +} -def validate_voltage(values): - def validator(value): - if isinstance(value, float) and value.is_integer(): - value = int(value) - value = cv.string(value) - if not value.endswith("V"): - value += "V" - return cv.one_of(*values)(value) - return validator +TOUCH_PAD_DENOISE_GRADE = { + "BIT12": cg.global_ns.TOUCH_PAD_DENOISE_BIT12, + "BIT10": cg.global_ns.TOUCH_PAD_DENOISE_BIT10, + "BIT8": cg.global_ns.TOUCH_PAD_DENOISE_BIT8, + "BIT4": cg.global_ns.TOUCH_PAD_DENOISE_BIT4, +} +TOUCH_PAD_DENOISE_CAP_LEVEL = { + "L0": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L0, + "L1": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L1, + "L2": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L2, + "L3": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L3, + "L4": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L4, + "L5": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L5, + "L6": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L6, + "L7": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L7, +} + +TOUCH_PAD_FILTER_MODE = { + "IIR_4": cg.global_ns.TOUCH_PAD_FILTER_IIR_4, + "IIR_8": cg.global_ns.TOUCH_PAD_FILTER_IIR_8, + "IIR_16": cg.global_ns.TOUCH_PAD_FILTER_IIR_16, + "IIR_32": cg.global_ns.TOUCH_PAD_FILTER_IIR_32, + "IIR_64": cg.global_ns.TOUCH_PAD_FILTER_IIR_64, + "IIR_128": cg.global_ns.TOUCH_PAD_FILTER_IIR_128, + "IIR_256": cg.global_ns.TOUCH_PAD_FILTER_IIR_256, + "JITTER": cg.global_ns.TOUCH_PAD_FILTER_JITTER, +} + +TOUCH_PAD_SMOOTH_MODE = { + "OFF": cg.global_ns.TOUCH_PAD_SMOOTH_OFF, + "IIR_2": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_2, + "IIR_4": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_4, + "IIR_8": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_8, +} LOW_VOLTAGE_REFERENCE = { "0.5V": cg.global_ns.TOUCH_LVOLT_0V5, @@ -50,15 +137,74 @@ VOLTAGE_ATTENUATION = { "0.5V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V5, "0V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V, } +TOUCH_PAD_WATERPROOF_SHIELD_DRIVER = { + "L0": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L0, + "L1": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L1, + "L2": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L2, + "L3": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L3, + "L4": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L4, + "L5": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L5, + "L6": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L6, + "L7": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L7, +} + + +def validate_touch_pad(value): + value = gpio.validate_gpio_pin(value) + variant = get_esp32_variant() + if variant not in TOUCH_PADS: + raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") + + pads = TOUCH_PADS[variant] + if value not in pads: + raise cv.Invalid(f"Pin {value} does not support touch pads.") + return cv.enum(pads)(value) + + +def validate_variant_vars(config): + if get_esp32_variant() == VARIANT_ESP32: + variant_vars = { + CONF_DEBOUNCE_COUNT, + CONF_DENOISE_GRADE, + CONF_DENOISE_CAP_LEVEL, + CONF_FILTER_MODE, + CONF_NOISE_THRESHOLD, + CONF_JITTER_STEP, + CONF_SMOOTH_MODE, + CONF_WATERPROOF_GUARD_RING, + CONF_WATERPROOF_SHIELD_DRIVER, + } + for vvar in variant_vars: + if vvar in config: + raise cv.Invalid(f"{vvar} is not valid on {VARIANT_ESP32}") + elif ( + get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3 + ) and CONF_IIR_FILTER in config: + raise cv.Invalid( + f"{CONF_IIR_FILTER} is not valid on {VARIANT_ESP32S2} or {VARIANT_ESP32S3}" + ) + + return config + + +def validate_voltage(values): + def validator(value): + if isinstance(value, float) and value.is_integer(): + value = int(value) + value = cv.string(value) + if not value.endswith("V"): + value += "V" + return cv.one_of(*values)(value) + + return validator + CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32TouchComponent), cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean, - cv.Optional( - CONF_IIR_FILTER, default="0ms" - ): cv.positive_time_period_milliseconds, + # common options cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All( cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906)) ), @@ -74,13 +220,47 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage( VOLTAGE_ATTENUATION ), + # ESP32 only + cv.Optional(CONF_IIR_FILTER): cv.positive_time_period_milliseconds, + # ESP32-S2/S3 only + cv.Optional(CONF_DEBOUNCE_COUNT): cv.int_range(min=0, max=7), + cv.Optional(CONF_FILTER_MODE): cv.enum( + TOUCH_PAD_FILTER_MODE, upper=True, space="_" + ), + cv.Optional(CONF_NOISE_THRESHOLD): cv.int_range(min=0, max=3), + cv.Optional(CONF_JITTER_STEP): cv.int_range(min=0, max=15), + cv.Optional(CONF_SMOOTH_MODE): cv.enum( + TOUCH_PAD_SMOOTH_MODE, upper=True, space="_" + ), + cv.Optional(CONF_DENOISE_GRADE): cv.enum( + TOUCH_PAD_DENOISE_GRADE, upper=True, space="_" + ), + cv.Optional(CONF_DENOISE_CAP_LEVEL): cv.enum( + TOUCH_PAD_DENOISE_CAP_LEVEL, upper=True, space="_" + ), + cv.Optional(CONF_WATERPROOF_GUARD_RING): validate_touch_pad, + cv.Optional(CONF_WATERPROOF_SHIELD_DRIVER): cv.enum( + TOUCH_PAD_WATERPROOF_SHIELD_DRIVER, upper=True, space="_" + ), } ).extend(cv.COMPONENT_SCHEMA), + cv.has_none_or_all_keys(CONF_DENOISE_GRADE, CONF_DENOISE_CAP_LEVEL), + cv.has_none_or_all_keys( + CONF_DEBOUNCE_COUNT, + CONF_FILTER_MODE, + CONF_NOISE_THRESHOLD, + CONF_JITTER_STEP, + CONF_SMOOTH_MODE, + ), + cv.has_none_or_all_keys(CONF_WATERPROOF_GUARD_RING, CONF_WATERPROOF_SHIELD_DRIVER), esp32.only_on_variant( supported=[ esp32.const.VARIANT_ESP32, + esp32.const.VARIANT_ESP32S2, + esp32.const.VARIANT_ESP32S3, ] ), + validate_variant_vars, ) @@ -89,7 +269,6 @@ async def to_code(config): await cg.register_component(touch, config) cg.add(touch.set_setup_mode(config[CONF_SETUP_MODE])) - cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) sleep_duration = int(round(config[CONF_SLEEP_DURATION].total_microseconds * 0.15)) cg.add(touch.set_sleep_duration(sleep_duration)) @@ -114,3 +293,33 @@ async def to_code(config): VOLTAGE_ATTENUATION[config[CONF_VOLTAGE_ATTENUATION]] ) ) + + if get_esp32_variant() == VARIANT_ESP32: + if CONF_IIR_FILTER in config: + cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) + + if get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3: + if CONF_FILTER_MODE in config: + cg.add(touch.set_filter_mode(config[CONF_FILTER_MODE])) + if CONF_DEBOUNCE_COUNT in config: + cg.add(touch.set_debounce_count(config[CONF_DEBOUNCE_COUNT])) + if CONF_NOISE_THRESHOLD in config: + cg.add(touch.set_noise_threshold(config[CONF_NOISE_THRESHOLD])) + if CONF_JITTER_STEP in config: + cg.add(touch.set_jitter_step(config[CONF_JITTER_STEP])) + if CONF_SMOOTH_MODE in config: + cg.add(touch.set_smooth_level(config[CONF_SMOOTH_MODE])) + if CONF_DENOISE_GRADE in config: + cg.add(touch.set_denoise_grade(config[CONF_DENOISE_GRADE])) + if CONF_DENOISE_CAP_LEVEL in config: + cg.add(touch.set_denoise_cap(config[CONF_DENOISE_CAP_LEVEL])) + if CONF_WATERPROOF_GUARD_RING in config: + cg.add( + touch.set_waterproof_guard_ring_pad(config[CONF_WATERPROOF_GUARD_RING]) + ) + if CONF_WATERPROOF_SHIELD_DRIVER in config: + cg.add( + touch.set_waterproof_shield_driver( + config[CONF_WATERPROOF_SHIELD_DRIVER] + ) + ) diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py index 2cdf1343c3..e9322b3080 100644 --- a/esphome/components/esp32_touch/binary_sensor.py +++ b/esphome/components/esp32_touch/binary_sensor.py @@ -1,87 +1,18 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.core import CORE from esphome.components import binary_sensor from esphome.const import ( CONF_PIN, CONF_THRESHOLD, CONF_ID, ) -from esphome.components.esp32 import gpio -from esphome.components.esp32.const import ( - KEY_ESP32, - KEY_VARIANT, - VARIANT_ESP32, - VARIANT_ESP32S2, - VARIANT_ESP32S3, -) -from . import esp32_touch_ns, ESP32TouchComponent +from . import esp32_touch_ns, ESP32TouchComponent, validate_touch_pad DEPENDENCIES = ["esp32_touch", "esp32"] CONF_ESP32_TOUCH_ID = "esp32_touch_id" CONF_WAKEUP_THRESHOLD = "wakeup_threshold" -TOUCH_PADS = { - VARIANT_ESP32: { - 4: cg.global_ns.TOUCH_PAD_NUM0, - 0: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 15: cg.global_ns.TOUCH_PAD_NUM3, - 13: cg.global_ns.TOUCH_PAD_NUM4, - 12: cg.global_ns.TOUCH_PAD_NUM5, - 14: cg.global_ns.TOUCH_PAD_NUM6, - 27: cg.global_ns.TOUCH_PAD_NUM7, - 33: cg.global_ns.TOUCH_PAD_NUM8, - 32: cg.global_ns.TOUCH_PAD_NUM9, - }, - VARIANT_ESP32S2: { - 1: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 3: cg.global_ns.TOUCH_PAD_NUM3, - 4: cg.global_ns.TOUCH_PAD_NUM4, - 5: cg.global_ns.TOUCH_PAD_NUM5, - 6: cg.global_ns.TOUCH_PAD_NUM6, - 7: cg.global_ns.TOUCH_PAD_NUM7, - 8: cg.global_ns.TOUCH_PAD_NUM8, - 9: cg.global_ns.TOUCH_PAD_NUM9, - 10: cg.global_ns.TOUCH_PAD_NUM10, - 11: cg.global_ns.TOUCH_PAD_NUM11, - 12: cg.global_ns.TOUCH_PAD_NUM12, - 13: cg.global_ns.TOUCH_PAD_NUM13, - 14: cg.global_ns.TOUCH_PAD_NUM14, - }, - VARIANT_ESP32S3: { - 1: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 3: cg.global_ns.TOUCH_PAD_NUM3, - 4: cg.global_ns.TOUCH_PAD_NUM4, - 5: cg.global_ns.TOUCH_PAD_NUM5, - 6: cg.global_ns.TOUCH_PAD_NUM6, - 7: cg.global_ns.TOUCH_PAD_NUM7, - 8: cg.global_ns.TOUCH_PAD_NUM8, - 9: cg.global_ns.TOUCH_PAD_NUM9, - 10: cg.global_ns.TOUCH_PAD_NUM10, - 11: cg.global_ns.TOUCH_PAD_NUM11, - 12: cg.global_ns.TOUCH_PAD_NUM12, - 13: cg.global_ns.TOUCH_PAD_NUM13, - 14: cg.global_ns.TOUCH_PAD_NUM14, - }, -} - - -def validate_touch_pad(value): - value = gpio.validate_gpio_pin(value) - variant = CORE.data[KEY_ESP32][KEY_VARIANT] - if variant not in TOUCH_PADS: - raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") - - pads = TOUCH_PADS[variant] - if value not in pads: - raise cv.Invalid(f"Pin {value} does not support touch pads.") - return cv.enum(pads)(value) - - ESP32TouchBinarySensor = esp32_touch_ns.class_( "ESP32TouchBinarySensor", binary_sensor.BinarySensor ) @@ -90,8 +21,8 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(ESP32TouchBinarySensor).exten { cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_id(ESP32TouchComponent), cv.Required(CONF_PIN): validate_touch_pad, - cv.Required(CONF_THRESHOLD): cv.uint16_t, - cv.Optional(CONF_WAKEUP_THRESHOLD, default=0): cv.uint16_t, + cv.Required(CONF_THRESHOLD): cv.uint32_t, + cv.Optional(CONF_WAKEUP_THRESHOLD, default=0): cv.uint32_t, } ) diff --git a/esphome/components/esp32_touch/esp32_touch.cpp b/esphome/components/esp32_touch/esp32_touch.cpp index 0e3d3d9fd5..e43c3b844c 100644 --- a/esphome/components/esp32_touch/esp32_touch.cpp +++ b/esphome/components/esp32_touch/esp32_touch.cpp @@ -5,6 +5,8 @@ #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include + namespace esphome { namespace esp32_touch { @@ -13,18 +15,58 @@ static const char *const TAG = "esp32_touch"; void ESP32TouchComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up ESP32 Touch Hub..."); touch_pad_init(); +// set up and enable/start filtering based on ESP32 variant +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + if (this->filter_configured_()) { + touch_filter_config_t filter_info = { + .mode = this->filter_mode_, + .debounce_cnt = this->debounce_count_, + .noise_thr = this->noise_threshold_, + .jitter_step = this->jitter_step_, + .smh_lvl = this->smooth_level_, + }; + touch_pad_filter_set_config(&filter_info); + touch_pad_filter_enable(); + } + if (this->denoise_configured_()) { + touch_pad_denoise_t denoise = { + .grade = this->grade_, + .cap_level = this->cap_level_, + }; + touch_pad_denoise_set_config(&denoise); + touch_pad_denoise_enable(); + } + + if (this->waterproof_configured_()) { + touch_pad_waterproof_t waterproof = { + .guard_ring_pad = this->waterproof_guard_ring_pad_, + .shield_driver = this->waterproof_shield_driver_, + }; + touch_pad_waterproof_set_config(&waterproof); + touch_pad_waterproof_enable(); + } +#else if (this->iir_filter_enabled_()) { touch_pad_filter_start(this->iir_filter_); } +#endif touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); for (auto *child : this->children_) { +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_pad_config(child->get_touch_pad()); +#else // Disable interrupt threshold touch_pad_config(child->get_touch_pad(), 0); +#endif } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + touch_pad_fsm_start(); +#endif } void ESP32TouchComponent::dump_config() { @@ -92,38 +134,168 @@ void ESP32TouchComponent::dump_config() { } ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + if (this->filter_configured_()) { + const char *filter_mode_s; + switch (this->filter_mode_) { + case TOUCH_PAD_FILTER_IIR_4: + filter_mode_s = "IIR_4"; + break; + case TOUCH_PAD_FILTER_IIR_8: + filter_mode_s = "IIR_8"; + break; + case TOUCH_PAD_FILTER_IIR_16: + filter_mode_s = "IIR_16"; + break; + case TOUCH_PAD_FILTER_IIR_32: + filter_mode_s = "IIR_32"; + break; + case TOUCH_PAD_FILTER_IIR_64: + filter_mode_s = "IIR_64"; + break; + case TOUCH_PAD_FILTER_IIR_128: + filter_mode_s = "IIR_128"; + break; + case TOUCH_PAD_FILTER_IIR_256: + filter_mode_s = "IIR_256"; + break; + case TOUCH_PAD_FILTER_JITTER: + filter_mode_s = "JITTER"; + break; + default: + filter_mode_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Filter mode: %s", filter_mode_s); + ESP_LOGCONFIG(TAG, " Debounce count: %" PRIu32, this->debounce_count_); + ESP_LOGCONFIG(TAG, " Noise threshold coefficient: %" PRIu32, this->noise_threshold_); + ESP_LOGCONFIG(TAG, " Jitter filter step size: %" PRIu32, this->jitter_step_); + const char *smooth_level_s; + switch (this->smooth_level_) { + case TOUCH_PAD_SMOOTH_OFF: + smooth_level_s = "OFF"; + break; + case TOUCH_PAD_SMOOTH_IIR_2: + smooth_level_s = "IIR_2"; + break; + case TOUCH_PAD_SMOOTH_IIR_4: + smooth_level_s = "IIR_4"; + break; + case TOUCH_PAD_SMOOTH_IIR_8: + smooth_level_s = "IIR_8"; + break; + default: + smooth_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Smooth level: %s", smooth_level_s); + } + + if (this->denoise_configured_()) { + const char *grade_s; + switch (this->grade_) { + case TOUCH_PAD_DENOISE_BIT12: + grade_s = "BIT12"; + break; + case TOUCH_PAD_DENOISE_BIT10: + grade_s = "BIT10"; + break; + case TOUCH_PAD_DENOISE_BIT8: + grade_s = "BIT8"; + break; + case TOUCH_PAD_DENOISE_BIT4: + grade_s = "BIT4"; + break; + default: + grade_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise grade: %s", grade_s); + + const char *cap_level_s; + switch (this->cap_level_) { + case TOUCH_PAD_DENOISE_CAP_L0: + cap_level_s = "L0"; + break; + case TOUCH_PAD_DENOISE_CAP_L1: + cap_level_s = "L1"; + break; + case TOUCH_PAD_DENOISE_CAP_L2: + cap_level_s = "L2"; + break; + case TOUCH_PAD_DENOISE_CAP_L3: + cap_level_s = "L3"; + break; + case TOUCH_PAD_DENOISE_CAP_L4: + cap_level_s = "L4"; + break; + case TOUCH_PAD_DENOISE_CAP_L5: + cap_level_s = "L5"; + break; + case TOUCH_PAD_DENOISE_CAP_L6: + cap_level_s = "L6"; + break; + case TOUCH_PAD_DENOISE_CAP_L7: + cap_level_s = "L7"; + break; + default: + cap_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise capacitance level: %s", cap_level_s); + } +#else if (this->iir_filter_enabled_()) { - ESP_LOGCONFIG(TAG, " IIR Filter: %ums", this->iir_filter_); + ESP_LOGCONFIG(TAG, " IIR Filter: %" PRIu32 "ms", this->iir_filter_); } else { ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); } +#endif + if (this->setup_mode_) { - ESP_LOGCONFIG(TAG, " Setup Mode ENABLED!"); + ESP_LOGCONFIG(TAG, " Setup Mode ENABLED"); } for (auto *child : this->children_) { LOG_BINARY_SENSOR(" ", "Touch Pad", child); - ESP_LOGCONFIG(TAG, " Pad: T%d", child->get_touch_pad()); - ESP_LOGCONFIG(TAG, " Threshold: %u", child->get_threshold()); + ESP_LOGCONFIG(TAG, " Pad: T%" PRIu32, (uint32_t) child->get_touch_pad()); + ESP_LOGCONFIG(TAG, " Threshold: %" PRIu32, child->get_threshold()); } } +uint32_t ESP32TouchComponent::component_touch_pad_read(touch_pad_t tp) { +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + uint32_t value = 0; + if (this->filter_configured_()) { + touch_pad_filter_read_smooth(tp, &value); + } else { + touch_pad_read_raw_data(tp, &value); + } +#else + uint16_t value = 0; + if (this->iir_filter_enabled_()) { + touch_pad_read_filtered(tp, &value); + } else { + touch_pad_read(tp, &value); + } +#endif + return value; +} + void ESP32TouchComponent::loop() { const uint32_t now = millis(); bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250; for (auto *child : this->children_) { - uint16_t value; - if (this->iir_filter_enabled_()) { - touch_pad_read_filtered(child->get_touch_pad(), &value); - } else { - touch_pad_read(child->get_touch_pad(), &value); - } - - child->value_ = value; - child->publish_state(value < child->get_threshold()); + child->value_ = this->component_touch_pad_read(child->get_touch_pad()); +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) + child->publish_state(child->value_ < child->get_threshold()); +#else + child->publish_state(child->value_ > child->get_threshold()); +#endif if (should_print) { - ESP_LOGD(TAG, "Touch Pad '%s' (T%u): %u", child->get_name().c_str(), child->get_touch_pad(), value); + ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), + (uint32_t) child->get_touch_pad(), child->value_); } App.feed_wdt(); @@ -138,10 +310,12 @@ void ESP32TouchComponent::loop() { void ESP32TouchComponent::on_shutdown() { bool is_wakeup_source = false; +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) if (this->iir_filter_enabled_()) { touch_pad_filter_stop(); touch_pad_filter_delete(); } +#endif for (auto *child : this->children_) { if (child->get_wakeup_threshold() != 0) { @@ -151,8 +325,10 @@ void ESP32TouchComponent::on_shutdown() { touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); } +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) // No filter available when using as wake-up source. touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold()); +#endif } } @@ -161,7 +337,7 @@ void ESP32TouchComponent::on_shutdown() { } } -ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold) +ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} } // namespace esp32_touch diff --git a/esphome/components/esp32_touch/esp32_touch.h b/esphome/components/esp32_touch/esp32_touch.h index c954a14654..0ba7ed6255 100644 --- a/esphome/components/esp32_touch/esp32_touch.h +++ b/esphome/components/esp32_touch/esp32_touch.h @@ -21,25 +21,37 @@ class ESP32TouchBinarySensor; class ESP32TouchComponent : public Component { public: - void register_touch_pad(ESP32TouchBinarySensor *pad) { children_.push_back(pad); } - - void set_setup_mode(bool setup_mode) { setup_mode_ = setup_mode; } - - void set_iir_filter(uint32_t iir_filter) { iir_filter_ = iir_filter; } - - void set_sleep_duration(uint16_t sleep_duration) { sleep_cycle_ = sleep_duration; } - - void set_measurement_duration(uint16_t meas_cycle) { meas_cycle_ = meas_cycle; } + void register_touch_pad(ESP32TouchBinarySensor *pad) { this->children_.push_back(pad); } + void set_setup_mode(bool setup_mode) { this->setup_mode_ = setup_mode; } + void set_sleep_duration(uint16_t sleep_duration) { this->sleep_cycle_ = sleep_duration; } + void set_measurement_duration(uint16_t meas_cycle) { this->meas_cycle_ = meas_cycle; } void set_low_voltage_reference(touch_low_volt_t low_voltage_reference) { - low_voltage_reference_ = low_voltage_reference; + this->low_voltage_reference_ = low_voltage_reference; } - void set_high_voltage_reference(touch_high_volt_t high_voltage_reference) { - high_voltage_reference_ = high_voltage_reference; + this->high_voltage_reference_ = high_voltage_reference; } + void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) { + this->voltage_attenuation_ = voltage_attenuation; + } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + void set_filter_mode(touch_filter_mode_t filter_mode) { this->filter_mode_ = filter_mode; } + void set_debounce_count(uint32_t debounce_count) { this->debounce_count_ = debounce_count; } + void set_noise_threshold(uint32_t noise_threshold) { this->noise_threshold_ = noise_threshold; } + void set_jitter_step(uint32_t jitter_step) { this->jitter_step_ = jitter_step; } + void set_smooth_level(touch_smooth_mode_t smooth_level) { this->smooth_level_ = smooth_level; } + void set_denoise_grade(touch_pad_denoise_grade_t denoise_grade) { this->grade_ = denoise_grade; } + void set_denoise_cap(touch_pad_denoise_cap_t cap_level) { this->cap_level_ = cap_level; } + void set_waterproof_guard_ring_pad(touch_pad_t pad) { this->waterproof_guard_ring_pad_ = pad; } + void set_waterproof_shield_driver(touch_pad_shield_driver_t drive_capability) { + this->waterproof_shield_driver_ = drive_capability; + } +#else + void set_iir_filter(uint32_t iir_filter) { this->iir_filter_ = iir_filter; } +#endif - void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) { voltage_attenuation_ = voltage_attenuation; } + uint32_t component_touch_pad_read(touch_pad_t tp); void setup() override; void dump_config() override; @@ -49,38 +61,63 @@ class ESP32TouchComponent : public Component { void on_shutdown() override; protected: - /// Is the IIR filter enabled? - bool iir_filter_enabled_() const { return iir_filter_ > 0; } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + bool filter_configured_() const { + return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX); + } + bool denoise_configured_() const { + return (this->grade_ != TOUCH_PAD_DENOISE_MAX) && (this->cap_level_ != TOUCH_PAD_DENOISE_CAP_MAX); + } + bool waterproof_configured_() const { + return (this->waterproof_guard_ring_pad_ != TOUCH_PAD_MAX) && + (this->waterproof_shield_driver_ != TOUCH_PAD_SHIELD_DRV_MAX); + } +#else + bool iir_filter_enabled_() const { return this->iir_filter_ > 0; } +#endif - uint16_t sleep_cycle_{}; - uint16_t meas_cycle_{65535}; - touch_low_volt_t low_voltage_reference_{}; - touch_high_volt_t high_voltage_reference_{}; - touch_volt_atten_t voltage_attenuation_{}; std::vector children_; bool setup_mode_{false}; - uint32_t setup_mode_last_log_print_{}; + uint32_t setup_mode_last_log_print_{0}; + // common parameters + uint16_t sleep_cycle_{4095}; + uint16_t meas_cycle_{65535}; + touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5}; + touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7}; + touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V}; +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX}; + uint32_t debounce_count_{0}; + uint32_t noise_threshold_{0}; + uint32_t jitter_step_{0}; + touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX}; + touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX}; + touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX}; + touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX}; + touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX}; +#else uint32_t iir_filter_{0}; +#endif }; /// Simple helper class to expose a touch pad value as a binary sensor. class ESP32TouchBinarySensor : public binary_sensor::BinarySensor { public: - ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold); + ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold); - touch_pad_t get_touch_pad() const { return touch_pad_; } - uint16_t get_threshold() const { return threshold_; } - void set_threshold(uint16_t threshold) { threshold_ = threshold; } - uint16_t get_value() const { return value_; } - uint16_t get_wakeup_threshold() const { return wakeup_threshold_; } + touch_pad_t get_touch_pad() const { return this->touch_pad_; } + uint32_t get_threshold() const { return this->threshold_; } + void set_threshold(uint32_t threshold) { this->threshold_ = threshold; } + uint32_t get_value() const { return this->value_; } + uint32_t get_wakeup_threshold() const { return this->wakeup_threshold_; } protected: friend ESP32TouchComponent; - touch_pad_t touch_pad_; - uint16_t threshold_; - uint16_t value_; - const uint16_t wakeup_threshold_; + touch_pad_t touch_pad_{TOUCH_PAD_MAX}; + uint32_t threshold_{0}; + uint32_t value_{0}; + const uint32_t wakeup_threshold_{0}; }; } // namespace esp32_touch From c541fa1763c7082d10c3c205dca4c16db2586daf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:55:38 +1200 Subject: [PATCH 0310/2607] Bump zeroconf from 0.71.4 to 0.74.0 (#5199) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3160fe42de..2bb1e81fbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.6 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.71.4 +zeroconf==0.74.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 40697fea9623fd6e37cf76adba1310d589acd46d Mon Sep 17 00:00:00 2001 From: Lucas Prim Date: Mon, 7 Aug 2023 16:31:09 -0300 Subject: [PATCH 0311/2607] Implemented Waveshare 7.5in B V3 (#5210) --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.cpp | 151 ++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 34 ++++ 3 files changed, 189 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 6113fe943c..eb0faadc02 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -51,6 +51,9 @@ WaveshareEPaper7P5InBC = waveshare_epaper_ns.class_( WaveshareEPaper7P5InBV2 = waveshare_epaper_ns.class_( "WaveshareEPaper7P5InBV2", WaveshareEPaper ) +WaveshareEPaper7P5InBV3 = waveshare_epaper_ns.class_( + "WaveshareEPaper7P5InBV3", WaveshareEPaper +) WaveshareEPaper7P5InV2 = waveshare_epaper_ns.class_( "WaveshareEPaper7P5InV2", WaveshareEPaper ) @@ -87,6 +90,7 @@ MODELS = { "5.83inv2": ("b", WaveshareEPaper5P8InV2), "7.50in": ("b", WaveshareEPaper7P5In), "7.50in-bv2": ("b", WaveshareEPaper7P5InBV2), + "7.50in-bv3": ("b", WaveshareEPaper7P5InBV3), "7.50in-bc": ("b", WaveshareEPaper7P5InBC), "7.50inv2": ("b", WaveshareEPaper7P5InV2), "7.50inv2alt": ("b", WaveshareEPaper7P5InV2alt), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 5dd573f1b8..73c2680add 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1328,6 +1328,157 @@ void WaveshareEPaper7P5InBV2::dump_config() { LOG_PIN(" Busy Pin: ", this->busy_pin_); LOG_UPDATE_INTERVAL(this); } + +bool WaveshareEPaper7P5InBV3::wait_until_idle_() { + if (this->busy_pin_ == nullptr) { + return true; + } + + const uint32_t start = millis(); + while (this->busy_pin_->digital_read()) { + this->command(0x71); + if (millis() - start > this->idle_timeout_()) { + ESP_LOGI(TAG, "Timeout while displaying image!"); + return false; + } + delay(10); + } + delay(200); // NOLINT + return true; +}; +void WaveshareEPaper7P5InBV3::initialize() { + this->reset_(); + + // COMMAND POWER SETTING + this->command(0x01); + + // 1-0=11: internal power + this->data(0x07); + this->data(0x17); // VGH&VGL + this->data(0x3F); // VSH + this->data(0x26); // VSL + this->data(0x11); // VSHR + + // VCOM DC Setting + this->command(0x82); + this->data(0x24); // VCOM + + // Booster Setting + this->command(0x06); + this->data(0x27); + this->data(0x27); + this->data(0x2F); + this->data(0x17); + + // POWER ON + this->command(0x04); + + delay(100); // NOLINT + this->wait_until_idle_(); + // COMMAND PANEL SETTING + this->command(0x00); + this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f + + // COMMAND RESOLUTION SETTING + this->command(0x61); + this->data(0x03); // source 800 + this->data(0x20); + this->data(0x01); // gate 480 + this->data(0xE0); + // COMMAND ...? + this->command(0x15); + this->data(0x00); + // COMMAND VCOM AND DATA INTERVAL SETTING + this->command(0x50); + this->data(0x10); + this->data(0x00); + // COMMAND TCON SETTING + this->command(0x60); + this->data(0x22); + // Resolution setting + this->command(0x65); + this->data(0x00); + this->data(0x00); // 800*480 + this->data(0x00); + this->data(0x00); + + this->wait_until_idle_(); + + uint8_t lut_vcom_7_i_n5_v2[] = { + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + uint8_t lut_ww_7_i_n5_v2[] = { + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + uint8_t lut_bw_7_i_n5_v2[] = { + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + uint8_t lut_wb_7_i_n5_v2[] = { + 0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + uint8_t lut_bb_7_i_n5_v2[] = { + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + uint8_t count; + this->command(0x20); // VCOM + for (count = 0; count < 42; count++) + this->data(lut_vcom_7_i_n5_v2[count]); + + this->command(0x21); // LUTBW + for (count = 0; count < 42; count++) + this->data(lut_ww_7_i_n5_v2[count]); + + this->command(0x22); // LUTBW + for (count = 0; count < 42; count++) + this->data(lut_bw_7_i_n5_v2[count]); + + this->command(0x23); // LUTWB + for (count = 0; count < 42; count++) + this->data(lut_wb_7_i_n5_v2[count]); + + this->command(0x24); // LUTBB + for (count = 0; count < 42; count++) + this->data(lut_bb_7_i_n5_v2[count]); + + this->command(0x10); + for (uint32_t i = 0; i < 800 * 480 / 8; i++) { + this->data(0xFF); + } +}; +void HOT WaveshareEPaper7P5InBV3::display() { + uint32_t buf_len = this->get_buffer_length_(); + + this->command(0x13); // Start Transmission + delay(2); + for (uint32_t i = 0; i < buf_len; i++) { + this->data(~(this->buffer_[i])); + } + + this->command(0x12); // Display Refresh + delay(100); // NOLINT + this->wait_until_idle_(); +} +int WaveshareEPaper7P5InBV3::get_width_internal() { return 800; } +int WaveshareEPaper7P5InBV3::get_height_internal() { return 480; } +void WaveshareEPaper7P5InBV3::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper", this); + ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + void WaveshareEPaper7P5In::initialize() { // COMMAND POWER SETTING this->command(0x01); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index a84a1d4541..315af9ea82 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -413,6 +413,40 @@ class WaveshareEPaper7P5InBV2 : public WaveshareEPaper { int get_height_internal() override; }; +class WaveshareEPaper7P5InBV3 : public WaveshareEPaper { + public: + bool wait_until_idle_(); + + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + this->command(0x02); // Power off + this->wait_until_idle_(); + this->command(0x07); // Deep sleep + this->data(0xA5); + } + + protected: + int get_width_internal() override; + + int get_height_internal() override; + + void reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(true); + delay(200); // NOLINT + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + delay(200); // NOLINT + } + }; +}; + class WaveshareEPaper7P5InBC : public WaveshareEPaper { public: void initialize() override; From 93b7ca77ca2863e3a454bf4d0087f60eff39c149 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Tue, 8 Aug 2023 06:14:20 +1000 Subject: [PATCH 0312/2607] Refactor `pulse_meter` to better handle higher frequencies (#4231) --- .../pulse_meter/pulse_meter_sensor.cpp | 204 +++++++----------- .../pulse_meter/pulse_meter_sensor.h | 47 ++-- 2 files changed, 103 insertions(+), 148 deletions(-) diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index d0c627313c..7eef18e5e0 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -1,4 +1,5 @@ #include "pulse_meter_sensor.h" +#include #include "esphome/core/log.h" namespace esphome { @@ -9,66 +10,58 @@ static const char *const TAG = "pulse_meter"; void PulseMeterSensor::setup() { this->pin_->setup(); this->isr_pin_ = pin_->to_isr(); - this->pin_->attach_interrupt(PulseMeterSensor::gpio_intr, this, gpio::INTERRUPT_ANY_EDGE); - this->last_detected_edge_us_ = 0; - this->last_valid_edge_us_ = 0; - this->pulse_width_us_ = 0; - this->sensor_is_high_ = this->isr_pin_.digital_read(); - this->has_valid_edge_ = false; - this->pending_state_change_ = NONE; + if (this->filter_mode_ == FILTER_EDGE) { + this->pin_->attach_interrupt(PulseMeterSensor::edge_intr, this, gpio::INTERRUPT_RISING_EDGE); + } else if (this->filter_mode_ == FILTER_PULSE) { + this->pin_->attach_interrupt(PulseMeterSensor::pulse_intr, this, gpio::INTERRUPT_ANY_EDGE); + } } -// In PULSE mode we set a flag (pending_state_change_) for every interrupt -// that constitutes a state change. In the loop() method we check if a time -// interval greater than the internal_filter time has passed without any -// interrupts. void PulseMeterSensor::loop() { - // Get a snapshot of the needed volatile sensor values, to make sure they are not - // modified by the ISR while we are in the loop() method. If they are changed - // after we the variable "now" has been set, overflow will occur in the - // subsequent arithmetic - const bool has_valid_edge = this->has_valid_edge_; - const uint32_t last_detected_edge_us = this->last_detected_edge_us_; - const uint32_t last_valid_edge_us = this->last_valid_edge_us_; - // Get the current time after the snapshot of saved times - const uint32_t now = micros(); + // Reset the count in get before we pass it back to the ISR as set + this->get_->count_ = 0; - this->handle_state_change_(now, last_detected_edge_us, last_valid_edge_us, has_valid_edge); + // Swap out set and get to get the latest state from the ISR + // The ISR could interrupt on any of these lines and the results would be consistent + auto *temp = this->set_; + this->set_ = this->get_; + this->get_ = temp; - // If we've exceeded our timeout interval without receiving any pulses, assume 0 pulses/min until - // we get at least two valid pulses. - const uint32_t time_since_valid_edge_us = now - last_detected_edge_us; - if ((has_valid_edge) && (time_since_valid_edge_us > this->timeout_us_)) { - ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); - - this->last_valid_edge_us_ = 0; - this->pulse_width_us_ = 0; - this->has_valid_edge_ = false; - this->last_detected_edge_us_ = 0; - } - - // We quantize our pulse widths to 1 ms to avoid unnecessary jitter - const uint32_t pulse_width_ms = this->pulse_width_us_ / 1000; - if (this->pulse_width_dedupe_.next(pulse_width_ms)) { - if (pulse_width_ms == 0) { - // Treat 0 pulse width as 0 pulses/min (normally because we've not detected any pulses for a while) - this->publish_state(0); - } else { - // Calculate pulses/min from the pulse width in ms - this->publish_state((60.0f * 1000.0f) / pulse_width_ms); - } - } - - if (this->total_sensor_ != nullptr) { - const uint32_t total = this->total_pulses_; - if (this->total_dedupe_.next(total)) { + // Check if we detected a pulse this loop + if (this->get_->count_ > 0) { + // Keep a running total of pulses if a total sensor is configured + if (this->total_sensor_ != nullptr) { + this->total_pulses_ += this->get_->count_; + const uint32_t total = this->total_pulses_; this->total_sensor_->publish_state(total); } + + // We need to detect at least two edges to have a valid pulse width + if (!this->initialized_) { + this->initialized_ = true; + } else { + uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; + float pulse_width_us = delta_us / float(this->get_->count_); + this->publish_state((60.0f * 1000000.0f) / pulse_width_us); + } + + this->last_processed_edge_us_ = this->get_->last_detected_edge_us_; + } + // No detected edges this loop + else { + const uint32_t now = micros(); + const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_; + + if (this->initialized_ && time_since_valid_edge_us > this->timeout_us_) { + ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); + this->initialized_ = false; + this->publish_state(0.0f); + } } } -void PulseMeterSensor::set_total_pulses(uint32_t pulses) { this->total_pulses_ = pulses; } +float PulseMeterSensor::get_setup_priority() const { return setup_priority::DATA; } void PulseMeterSensor::dump_config() { LOG_SENSOR("", "Pulse Meter", this); @@ -81,96 +74,49 @@ void PulseMeterSensor::dump_config() { ESP_LOGCONFIG(TAG, " Assuming 0 pulses/min after not receiving a pulse for %us", this->timeout_us_ / 1000000); } -void IRAM_ATTR PulseMeterSensor::gpio_intr(PulseMeterSensor *sensor) { +void IRAM_ATTR PulseMeterSensor::edge_intr(PulseMeterSensor *sensor) { + // This is an interrupt handler - we can't call any virtual method from this method + // Get the current time before we do anything else so the measurements are consistent + const uint32_t now = micros(); + + if ((now - sensor->last_edge_candidate_us_) >= sensor->filter_us_) { + sensor->last_edge_candidate_us_ = now; + sensor->set_->last_detected_edge_us_ = now; + sensor->set_->count_++; + } +} + +void IRAM_ATTR PulseMeterSensor::pulse_intr(PulseMeterSensor *sensor) { // This is an interrupt handler - we can't call any virtual method from this method // Get the current time before we do anything else so the measurements are consistent const uint32_t now = micros(); const bool pin_val = sensor->isr_pin_.digital_read(); - if (sensor->filter_mode_ == FILTER_EDGE) { - // We only look at rising edges - if (!pin_val) { - return; + // A pulse occurred faster than we can detect + if (sensor->last_pin_val_ == pin_val) { + // If we haven't reached the filter length yet we need to reset our last_intr_ to now + // otherwise we can consider this noise as the "pulse" was certainly less than filter_us_ + if (now - sensor->last_intr_ < sensor->filter_us_) { + sensor->last_intr_ = now; } - // Check to see if we should filter this edge out - if ((now - sensor->last_detected_edge_us_) >= sensor->filter_us_) { - // Don't measure the first valid pulse (we need at least two pulses to measure the width) - if (sensor->has_valid_edge_) { - sensor->pulse_width_us_ = (now - sensor->last_valid_edge_us_); - } - sensor->total_pulses_++; - sensor->last_valid_edge_us_ = now; - sensor->has_valid_edge_ = true; - } - sensor->last_detected_edge_us_ = now; } else { - // Filter Mode is PULSE - const uint32_t delta_t_us = now - sensor->last_detected_edge_us_; - // We need to check if we have missed to handle a state change in the - // loop() function. This can happen when the filter_us value is less than - // the loop() interval, which is ~50-60ms - // The section below is essentially a modified repeat of the - // handle_state_change method. Ideally i would refactor and call the - // method here as well. However functions called in ISRs need to meet - // strict criteria and I don't think the methos would meet them. - if (sensor->pending_state_change_ != NONE && (delta_t_us > sensor->filter_us_)) { - // We have missed to handle a state change in the loop function. - sensor->sensor_is_high_ = sensor->pending_state_change_ == TO_HIGH; - if (sensor->sensor_is_high_) { - // We need to handle a pulse that would have been missed by the loop function - sensor->total_pulses_++; - if (sensor->has_valid_edge_) { - sensor->pulse_width_us_ = sensor->last_detected_edge_us_ - sensor->last_valid_edge_us_; - sensor->has_valid_edge_ = true; - sensor->last_valid_edge_us_ = sensor->last_detected_edge_us_; - } + // Check if the last interrupt was long enough in the past + if (now - sensor->last_intr_ > sensor->filter_us_) { + // High pulse of filter length now falling (therefore last_intr_ was the rising edge) + if (!sensor->in_pulse_ && sensor->last_pin_val_) { + sensor->last_edge_candidate_us_ = sensor->last_intr_; + sensor->in_pulse_ = true; } - } // End of checking for and handling of change in state - - // Ignore false edges that may be caused by bouncing and exit the ISR ASAP - if (pin_val == sensor->sensor_is_high_) { - sensor->pending_state_change_ = NONE; - return; - } - sensor->pending_state_change_ = pin_val ? TO_HIGH : TO_LOW; - sensor->last_detected_edge_us_ = now; - } -} - -void PulseMeterSensor::handle_state_change_(uint32_t now, uint32_t last_detected_edge_us, uint32_t last_valid_edge_us, - bool has_valid_edge) { - if (this->pending_state_change_ == NONE) { - return; - } - - const bool pin_val = this->isr_pin_.digital_read(); - if (pin_val == this->sensor_is_high_) { - // Most likely caused by high frequency bouncing. Theoretically we should - // expect interrupts of alternating state. Here we are registering an - // interrupt with no change in state. Another interrupt will likely trigger - // just after this one and have an alternate state. - this->pending_state_change_ = NONE; - return; - } - - if ((now - last_detected_edge_us) > this->filter_us_) { - this->sensor_is_high_ = pin_val; - ESP_LOGVV(TAG, "State is now %s", pin_val ? "high" : "low"); - - // Increment with valid rising edges only - if (pin_val) { - this->total_pulses_++; - ESP_LOGVV(TAG, "Incremented pulses to %u", this->total_pulses_); - - if (has_valid_edge) { - this->pulse_width_us_ = last_detected_edge_us - last_valid_edge_us; - ESP_LOGVV(TAG, "Set pulse width to %u", this->pulse_width_us_); + // Low pulse of filter length now rising (therefore last_intr_ was the falling edge) + else if (sensor->in_pulse_ && !sensor->last_pin_val_) { + sensor->set_->last_detected_edge_us_ = sensor->last_edge_candidate_us_; + sensor->set_->count_++; + sensor->in_pulse_ = false; } - this->has_valid_edge_ = true; - this->last_valid_edge_us_ = last_detected_edge_us; - ESP_LOGVV(TAG, "last_valid_edge_us_ is now %u", this->last_valid_edge_us_); } - this->pending_state_change_ = NONE; + + sensor->last_intr_ = now; + sensor->last_pin_val_ = pin_val; } } diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index 47af6e2398..ddd42c2ed5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -17,41 +17,50 @@ class PulseMeterSensor : public sensor::Sensor, public Component { void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; } void set_filter_us(uint32_t filter) { this->filter_us_ = filter; } - void set_filter_mode(InternalFilterMode mode) { this->filter_mode_ = mode; } void set_timeout_us(uint32_t timeout) { this->timeout_us_ = timeout; } void set_total_sensor(sensor::Sensor *sensor) { this->total_sensor_ = sensor; } - - void set_total_pulses(uint32_t pulses); + void set_filter_mode(InternalFilterMode mode) { this->filter_mode_ = mode; } + void set_total_pulses(uint32_t pulses) { this->total_pulses_ = pulses; } void setup() override; void loop() override; - float get_setup_priority() const override { return setup_priority::DATA; } + float get_setup_priority() const override; void dump_config() override; protected: - enum StateChange { TO_LOW = 0, TO_HIGH, NONE }; - - static void gpio_intr(PulseMeterSensor *sensor); - void handle_state_change_(uint32_t now, uint32_t last_detected_edge_us, uint32_t last_valid_edge_us, - bool has_valid_edge); + static void edge_intr(PulseMeterSensor *sensor); + static void pulse_intr(PulseMeterSensor *sensor); InternalGPIOPin *pin_{nullptr}; - ISRInternalGPIOPin isr_pin_; uint32_t filter_us_ = 0; uint32_t timeout_us_ = 1000000UL * 60UL * 5UL; sensor::Sensor *total_sensor_{nullptr}; InternalFilterMode filter_mode_{FILTER_EDGE}; - Deduplicator pulse_width_dedupe_; - Deduplicator total_dedupe_; + // Variables used in the loop + bool initialized_ = false; + uint32_t total_pulses_ = 0; + uint32_t last_processed_edge_us_ = 0; - volatile uint32_t last_detected_edge_us_ = 0; - volatile uint32_t last_valid_edge_us_ = 0; - volatile uint32_t pulse_width_us_ = 0; - volatile uint32_t total_pulses_ = 0; - volatile bool sensor_is_high_ = false; - volatile bool has_valid_edge_ = false; - volatile StateChange pending_state_change_{NONE}; + // This struct (and the two pointers) are used to pass data between the ISR and loop. + // These two pointers are exchanged each loop. + // Therefore you can't use data in the pointer to loop receives to set values in the pointer to loop sends. + // As a result it's easiest if you only use these pointers to send data from the ISR to the loop. + // (except for resetting the values) + struct State { + uint32_t last_detected_edge_us_ = 0; + uint32_t count_ = 0; + }; + State state_[2]; + volatile State *set_ = state_; + volatile State *get_ = state_ + 1; + + // Only use these variables in the ISR + ISRInternalGPIOPin isr_pin_; + uint32_t last_edge_candidate_us_ = 0; + uint32_t last_intr_ = 0; + bool in_pulse_ = false; + bool last_pin_val_ = false; }; } // namespace pulse_meter From 9980b9972fcac080a1eb1987107484644e7a8d1d Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 7 Aug 2023 23:16:42 +0200 Subject: [PATCH 0313/2607] Change MQTT client for ESP32 Arduino (#5157) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mqtt/__init__.py | 4 ++-- ..._backend_idf.cpp => mqtt_backend_esp32.cpp} | 17 +++++++++-------- ...mqtt_backend_idf.h => mqtt_backend_esp32.h} | 4 ++-- ...ackend_arduino.h => mqtt_backend_esp8266.h} | 6 +++--- esphome/components/mqtt/mqtt_client.cpp | 6 +++--- esphome/components/mqtt/mqtt_client.h | 18 +++++++++--------- platformio.ini | 2 +- 7 files changed, 29 insertions(+), 28 deletions(-) rename esphome/components/mqtt/{mqtt_backend_idf.cpp => mqtt_backend_esp32.cpp} (93%) rename esphome/components/mqtt/{mqtt_backend_idf.h => mqtt_backend_esp32.h} (98%) rename esphome/components/mqtt/{mqtt_backend_arduino.h => mqtt_backend_esp8266.h} (96%) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 7207eaddc1..102c070eb6 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -271,8 +271,8 @@ def exp_mqtt_message(config): async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - # Add required libraries for arduino - if CORE.using_arduino: + # Add required libraries for ESP8266 + if CORE.is_esp8266: # https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json cg.add_library("ottowinter/AsyncMqttClient-esphome", "0.8.6") diff --git a/esphome/components/mqtt/mqtt_backend_idf.cpp b/esphome/components/mqtt/mqtt_backend_esp32.cpp similarity index 93% rename from esphome/components/mqtt/mqtt_backend_idf.cpp rename to esphome/components/mqtt/mqtt_backend_esp32.cpp index 7a7aca3fa6..2d4e6802f2 100644 --- a/esphome/components/mqtt/mqtt_backend_idf.cpp +++ b/esphome/components/mqtt/mqtt_backend_esp32.cpp @@ -1,7 +1,7 @@ -#ifdef USE_ESP_IDF +#ifdef USE_ESP32 #include -#include "mqtt_backend_idf.h" +#include "mqtt_backend_esp32.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" @@ -10,7 +10,7 @@ namespace mqtt { static const char *const TAG = "mqtt.idf"; -bool MQTTBackendIDF::initialize_() { +bool MQTTBackendESP32::initialize_() { #if ESP_IDF_VERSION_MAJOR < 5 mqtt_cfg_.user_context = (void *) this; mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE; @@ -95,7 +95,7 @@ bool MQTTBackendIDF::initialize_() { } } -void MQTTBackendIDF::loop() { +void MQTTBackendESP32::loop() { // process new events // handle only 1 message per loop iteration if (!mqtt_events_.empty()) { @@ -105,7 +105,7 @@ void MQTTBackendIDF::loop() { } } -void MQTTBackendIDF::mqtt_event_handler_(const Event &event) { +void MQTTBackendESP32::mqtt_event_handler_(const Event &event) { ESP_LOGV(TAG, "Event dispatched from event loop event_id=%d", event.event_id); switch (event.event_id) { case MQTT_EVENT_BEFORE_CONNECT: @@ -166,8 +166,9 @@ void MQTTBackendIDF::mqtt_event_handler_(const Event &event) { } /// static - Dispatch event to instance method -void MQTTBackendIDF::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { - MQTTBackendIDF *instance = static_cast(handler_args); +void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, + void *event_data) { + MQTTBackendESP32 *instance = static_cast(handler_args); // queue event to decouple processing if (instance) { auto event = *static_cast(event_data); @@ -177,4 +178,4 @@ void MQTTBackendIDF::mqtt_event_handler(void *handler_args, esp_event_base_t bas } // namespace mqtt } // namespace esphome -#endif // USE_ESP_IDF +#endif // USE_ESP32 diff --git a/esphome/components/mqtt/mqtt_backend_idf.h b/esphome/components/mqtt/mqtt_backend_esp32.h similarity index 98% rename from esphome/components/mqtt/mqtt_backend_idf.h rename to esphome/components/mqtt/mqtt_backend_esp32.h index 9c7a5f80e9..a4ee96ca59 100644 --- a/esphome/components/mqtt/mqtt_backend_idf.h +++ b/esphome/components/mqtt/mqtt_backend_esp32.h @@ -1,6 +1,6 @@ #pragma once -#ifdef USE_ESP_IDF +#ifdef USE_ESP32 #include #include @@ -41,7 +41,7 @@ struct Event { error_handle(*event.error_handle) {} }; -class MQTTBackendIDF final : public MQTTBackend { +class MQTTBackendESP32 final : public MQTTBackend { public: static const size_t MQTT_BUFFER_SIZE = 4096; diff --git a/esphome/components/mqtt/mqtt_backend_arduino.h b/esphome/components/mqtt/mqtt_backend_esp8266.h similarity index 96% rename from esphome/components/mqtt/mqtt_backend_arduino.h rename to esphome/components/mqtt/mqtt_backend_esp8266.h index 6399ec88e0..2d91877e9d 100644 --- a/esphome/components/mqtt/mqtt_backend_arduino.h +++ b/esphome/components/mqtt/mqtt_backend_esp8266.h @@ -1,6 +1,6 @@ #pragma once -#ifdef USE_ARDUINO +#ifdef USE_ESP8266 #include "mqtt_backend.h" #include @@ -8,7 +8,7 @@ namespace esphome { namespace mqtt { -class MQTTBackendArduino final : public MQTTBackend { +class MQTTBackendESP8266 final : public MQTTBackend { public: void set_keep_alive(uint16_t keep_alive) final { mqtt_client_.setKeepAlive(keep_alive); } void set_client_id(const char *client_id) final { mqtt_client_.setClientId(client_id); } @@ -71,4 +71,4 @@ class MQTTBackendArduino final : public MQTTBackend { } // namespace mqtt } // namespace esphome -#endif // defined(USE_ARDUINO) +#endif // defined(USE_ESP8266) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index cb5d306976..d3f759c072 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -556,8 +556,8 @@ static bool topic_match(const char *message, const char *subscription) { } void MQTTClientComponent::on_message(const std::string &topic, const std::string &payload) { -#ifdef USE_ARDUINO - // on Arduino, this is called in lwIP/AsyncTCP task; some components do not like running +#ifdef USE_ESP8266 + // on ESP8266, this is called in lwIP/AsyncTCP task; some components do not like running // from a different task. this->defer([this, topic, payload]() { #endif @@ -565,7 +565,7 @@ void MQTTClientComponent::on_message(const std::string &topic, const std::string if (topic_match(topic.c_str(), subscription.topic.c_str())) subscription.callback(topic, payload); } -#ifdef USE_ARDUINO +#ifdef USE_ESP8266 }); #endif } diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 83ed3cc645..00eb3fdd40 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -9,10 +9,10 @@ #include "esphome/core/log.h" #include "esphome/components/json/json_util.h" #include "esphome/components/network/ip_address.h" -#if defined(USE_ESP_IDF) -#include "mqtt_backend_idf.h" -#elif defined(USE_ARDUINO) -#include "mqtt_backend_arduino.h" +#if defined(USE_ESP32) +#include "mqtt_backend_esp32.h" +#elif defined(USE_ESP8266) +#include "mqtt_backend_esp8266.h" #endif #include "lwip/ip_addr.h" @@ -142,7 +142,7 @@ class MQTTClientComponent : public Component { */ void add_ssl_fingerprint(const std::array &fingerprint); #endif -#ifdef USE_ESP_IDF +#ifdef USE_ESP32 void set_ca_certificate(const char *cert) { this->mqtt_backend_.set_ca_certificate(cert); } void set_skip_cert_cn_check(bool skip_check) { this->mqtt_backend_.set_skip_cert_cn_check(skip_check); } #endif @@ -296,10 +296,10 @@ class MQTTClientComponent : public Component { int log_level_{ESPHOME_LOG_LEVEL}; std::vector subscriptions_; -#if defined(USE_ESP_IDF) - MQTTBackendIDF mqtt_backend_; -#elif defined(USE_ARDUINO) - MQTTBackendArduino mqtt_backend_; +#if defined(USE_ESP32) + MQTTBackendESP32 mqtt_backend_; +#elif defined(USE_ESP8266) + MQTTBackendESP8266 mqtt_backend_; #endif MQTTClientState state_{MQTT_CLIENT_DISCONNECTED}; diff --git a/platformio.ini b/platformio.ini index 8141c803f1..ba149ce99e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -57,7 +57,6 @@ lib_deps = ${common.lib_deps} SPI ; spi (Arduino built-in) Wire ; i2c (Arduino built-int) - ottowinter/AsyncMqttClient-esphome@0.8.6 ; mqtt esphome/ESPAsyncWebServer-esphome@2.1.0 ; web_server_base fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps @@ -89,6 +88,7 @@ lib_deps = ${common:arduino.lib_deps} ESP8266WiFi ; wifi (Arduino built-in) Update ; ota (Arduino built-in) + ottowinter/AsyncMqttClient-esphome@0.8.6 ; mqtt esphome/ESPAsyncTCP-esphome@1.2.3 ; async_tcp ESP8266HTTPClient ; http_request (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in) From 0b1b25191dea6f7a145170d8db26691b668f1326 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 8 Aug 2023 09:45:56 +1200 Subject: [PATCH 0314/2607] Add read interface to microphone (#5131) --- .../microphone/i2s_audio_microphone.cpp | 49 +++++++++---------- .../microphone/i2s_audio_microphone.h | 3 +- esphome/components/microphone/microphone.h | 1 + 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 9c661c3ac2..cf0628d638 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -16,14 +16,6 @@ static const char *const TAG = "i2s_audio.microphone"; void I2SAudioMicrophone::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone..."); - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->buffer_ = allocator.allocate(BUFFER_SIZE); - if (this->buffer_ == nullptr) { - ESP_LOGE(TAG, "Failed to allocate buffer!"); - this->mark_failed(); - return; - } - #if SOC_I2S_SUPPORTS_ADC if (this->adc_) { if (this->parent_->get_port() != I2S_NUM_0) { @@ -110,37 +102,38 @@ void I2SAudioMicrophone::stop_() { this->high_freq_.stop(); } -void I2SAudioMicrophone::read_() { +size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t bytes_read = 0; - esp_err_t err = - i2s_read(this->parent_->get_port(), this->buffer_, BUFFER_SIZE, &bytes_read, (100 / portTICK_PERIOD_MS)); + esp_err_t err = i2s_read(this->parent_->get_port(), buf, len, &bytes_read, (100 / portTICK_PERIOD_MS)); if (err != ESP_OK) { ESP_LOGW(TAG, "Error reading from I2S microphone: %s", esp_err_to_name(err)); this->status_set_warning(); - return; + return 0; } this->status_clear_warning(); - - std::vector samples; - size_t samples_read = 0; if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { - samples_read = bytes_read / sizeof(int16_t); - } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { - samples_read = bytes_read / sizeof(int32_t); - } else { - ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); - return; - } - samples.resize(samples_read); - if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { - memcpy(samples.data(), this->buffer_, bytes_read); + return bytes_read; } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { + std::vector samples; + size_t samples_read = bytes_read / sizeof(int32_t); + samples.resize(samples_read); for (size_t i = 0; i < samples_read; i++) { - int32_t temp = reinterpret_cast(this->buffer_)[i] >> 14; + int32_t temp = reinterpret_cast(buf)[i] >> 14; samples[i] = clamp(temp, INT16_MIN, INT16_MAX); } + memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); + return samples_read * sizeof(int16_t); + } else { + ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); + return 0; } +} +void I2SAudioMicrophone::read_() { + std::vector samples; + samples.resize(BUFFER_SIZE); + size_t bytes_read = this->read(samples.data(), BUFFER_SIZE / sizeof(int16_t)); + samples.resize(bytes_read / sizeof(int16_t)); this->data_callbacks_.call(samples); } @@ -152,7 +145,9 @@ void I2SAudioMicrophone::loop() { this->start_(); break; case microphone::STATE_RUNNING: - this->read_(); + if (this->data_callbacks_.size() > 0) { + this->read_(); + } break; case microphone::STATE_STOPPING: this->stop_(); diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 0cb87d42fd..dc6b70047a 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -21,6 +21,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub void set_din_pin(int8_t pin) { this->din_pin_ = pin; } void set_pdm(bool pdm) { this->pdm_ = pdm; } + size_t read(int16_t *buf, size_t len) override; + #if SOC_I2S_SUPPORTS_ADC void set_adc_channel(adc1_channel_t channel) { this->adc_channel_ = channel; @@ -42,7 +44,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub bool adc_{false}; #endif bool pdm_{false}; - uint8_t *buffer_; i2s_channel_fmt_t channel_; i2s_bits_per_sample_t bits_per_sample_; diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index ac3db3ec0f..e01a10e15c 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -20,6 +20,7 @@ class Microphone { void add_data_callback(std::function &)> &&data_callback) { this->data_callbacks_.add(std::move(data_callback)); } + virtual size_t read(int16_t *buf, size_t len) = 0; bool is_running() const { return this->state_ == STATE_RUNNING; } bool is_stopped() const { return this->state_ == STATE_STOPPED; } From 9876d5276ca3220db812f1ca91f37db336bd569c Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Tue, 8 Aug 2023 00:51:22 +0300 Subject: [PATCH 0315/2607] i2c: fix build on ESP-IDF >= 5.1 (#5200) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index 24c1860e6f..e2c7e7ddcb 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -15,8 +15,19 @@ static const char *const TAG = "i2c.idf"; void IDFI2CBus::setup() { ESP_LOGCONFIG(TAG, "Setting up I2C bus..."); - static i2c_port_t next_port = 0; - port_ = next_port++; + static i2c_port_t next_port = I2C_NUM_0; + port_ = next_port; +#if I2C_NUM_MAX > 1 + next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX; +#else + next_port = I2C_NUM_MAX; +#endif + + if (port_ == I2C_NUM_MAX) { + ESP_LOGE(TAG, "Too many I2C buses configured"); + this->mark_failed(); + return; + } recover_(); From e4cf7b86fa33a1b440c106fbae7ab3a096c2fa2b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 8 Aug 2023 10:22:10 +1200 Subject: [PATCH 0316/2607] Add socket define for rp2040 dev (#4968) --- esphome/core/defines.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 638dd39364..8d4d7e3f22 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -103,6 +103,11 @@ #endif +#ifdef USE_RP2040 +#define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 3, 0) +#define USE_SOCKET_IMPL_LWIP_TCP +#endif + #ifdef USE_HOST #define USE_SOCKET_IMPL_BSD_SOCKETS #endif From f4ac176d771981a23bcf8c9bebdca6d1d5f17289 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Tue, 8 Aug 2023 01:45:50 +0300 Subject: [PATCH 0317/2607] core: read ESP32 MAC address from eFuse if IEEE802.15.4 is supported (#5176) --- esphome/core/helpers.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 0bc762fd0d..c65928556a 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -38,7 +38,7 @@ #include "esp32/rom/crc.h" #endif -#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC +#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) #include "esp_efuse.h" #include "esp_efuse_table.h" #endif @@ -540,7 +540,9 @@ bool HighFrequencyLoopRequester::is_high_frequency() { return num_requests > 0; void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) #if defined(USE_ESP32) -#if defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) +#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) + // When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default + // returns the 802.15.4 EUI-64 address. Read directly from eFuse instead. // On some devices, the MAC address that is burnt into EFuse does not // match the CRC that goes along with it. For those devices, this // work-around reads and uses the MAC address as-is from EFuse, From 4e7011c25defe99ecde2e6bc8f67bffe0d037cd2 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Tue, 8 Aug 2023 02:18:06 +0300 Subject: [PATCH 0318/2607] esp32_ble_beacon: enable CONFIG_BT_BLE_42_FEATURES_SUPPORTED (#5211) --- esphome/components/esp32_ble_beacon/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index 311919dcd4..9aac48cbb2 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -72,3 +72,4 @@ async def to_code(config): if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) + add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) From 1d5f088740da0e20b3e59d2fe84caacc2730d406 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 11:21:51 +1200 Subject: [PATCH 0319/2607] Bump pytest-asyncio from 0.21.0 to 0.21.1 (#5187) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index fd1f45abc8..e67c57323e 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -8,7 +8,7 @@ pre-commit pytest==7.4.0 pytest-cov==4.1.0 pytest-mock==3.11.1 -pytest-asyncio==0.21.0 +pytest-asyncio==0.21.1 asyncmock==0.4.2 hypothesis==5.49.0 From ffd2cb9814dd5e424a0771a076c113a5cee9d74e Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Tue, 8 Aug 2023 02:47:57 +0300 Subject: [PATCH 0320/2607] ledc: check SOC_LEDC_SUPPORT_APB_CLOCK (#5212) --- esphome/components/ledc/ledc_output.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index d6241dd5b0..dfb84c1e76 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -17,7 +17,11 @@ #define CLOCK_FREQUENCY 40e6f #endif #else +#ifdef SOC_LEDC_SUPPORT_APB_CLOCK #define DEFAULT_CLK LEDC_USE_APB_CLK +#else +#define DEFAULT_CLK LEDC_AUTO_CLK +#endif #endif static const uint8_t SETUP_ATTEMPT_COUNT_MAX = 5; From a6b89e4e8a93de0b8edc3a4ef8db62a119a2a662 Mon Sep 17 00:00:00 2001 From: Francesco Ciocchetti <2085772+primeroz@users.noreply.github.com> Date: Tue, 8 Aug 2023 01:57:40 +0200 Subject: [PATCH 0321/2607] Add arm night to alarm control panel (#5186) --- .../alarm_control_panel/__init__.py | 13 ++++++++++++ .../alarm_control_panel_call.cpp | 5 +++++ .../alarm_control_panel_state.cpp | 2 +- .../alarm_control_panel/automation.h | 20 +++++++++++++++++++ .../template/alarm_control_panel/__init__.py | 15 ++++++++++++++ .../template_alarm_control_panel.cpp | 16 +++++++++++++++ .../template_alarm_control_panel.h | 12 +++++++++++ tests/test3.yaml | 2 ++ 8 files changed, 84 insertions(+), 1 deletion(-) diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 0839e49875..52f8ac7894 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -31,6 +31,7 @@ ClearedTrigger = alarm_control_panel_ns.class_( ) ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) +ArmNightAction = alarm_control_panel_ns.class_("ArmNightAction", automation.Action) DisarmAction = alarm_control_panel_ns.class_("DisarmAction", automation.Action) PendingAction = alarm_control_panel_ns.class_("PendingAction", automation.Action) TriggeredAction = alarm_control_panel_ns.class_("TriggeredAction", automation.Action) @@ -117,6 +118,18 @@ async def alarm_action_arm_home_to_code(config, action_id, template_arg, args): return var +@automation.register_action( + "alarm_control_panel.arm_night", ArmNightAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA +) +async def alarm_action_arm_night_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if CONF_CODE in config: + templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) + cg.add(var.set_code(templatable_)) + return var + + @automation.register_action( "alarm_control_panel.disarm", DisarmAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA ) diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp index eb50c4f4b5..b1d2b2a097 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp +++ b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp @@ -85,6 +85,11 @@ void AlarmControlPanelCall::validate_() { this->state_.reset(); return; } + if (state == ACP_STATE_ARMED_NIGHT && (this->parent_->get_supported_features() & ACP_FEAT_ARM_NIGHT) == 0) { + ESP_LOGW(TAG, "Cannot arm night when not supported"); + this->state_.reset(); + return; + } } } diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp b/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp index 231e7228e1..abe6f51995 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp +++ b/esphome/components/alarm_control_panel/alarm_control_panel_state.cpp @@ -12,7 +12,7 @@ const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState stat case ACP_STATE_ARMED_AWAY: return LOG_STR("ARMED_AWAY"); case ACP_STATE_ARMED_NIGHT: - return LOG_STR("NIGHT"); + return LOG_STR("ARMED_NIGHT"); case ACP_STATE_ARMED_VACATION: return LOG_STR("ARMED_VACATION"); case ACP_STATE_ARMED_CUSTOM_BYPASS: diff --git a/esphome/components/alarm_control_panel/automation.h b/esphome/components/alarm_control_panel/automation.h index 4368129609..81ac584f71 100644 --- a/esphome/components/alarm_control_panel/automation.h +++ b/esphome/components/alarm_control_panel/automation.h @@ -67,6 +67,26 @@ template class ArmHomeAction : public Action { AlarmControlPanel *alarm_control_panel_; }; +template class ArmNightAction : public Action { + public: + explicit ArmNightAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} + + TEMPLATABLE_VALUE(std::string, code) + + void play(Ts... x) override { + auto call = this->alarm_control_panel_->make_call(); + auto code = this->code_.optional_value(x...); + if (code.has_value()) { + call.set_code(code.value()); + } + call.arm_night(); + call.perform(); + } + + protected: + AlarmControlPanel *alarm_control_panel_; +}; + template class DisarmAction : public Action { public: explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} diff --git a/esphome/components/template/alarm_control_panel/__init__.py b/esphome/components/template/alarm_control_panel/__init__.py index 5156a0832a..27b7e92b4f 100644 --- a/esphome/components/template/alarm_control_panel/__init__.py +++ b/esphome/components/template/alarm_control_panel/__init__.py @@ -16,18 +16,22 @@ CODEOWNERS = ["@grahambrown11"] CONF_CODES = "codes" CONF_BYPASS_ARMED_HOME = "bypass_armed_home" +CONF_BYPASS_ARMED_NIGHT = "bypass_armed_night" CONF_REQUIRES_CODE_TO_ARM = "requires_code_to_arm" CONF_ARMING_HOME_TIME = "arming_home_time" +CONF_ARMING_NIGHT_TIME = "arming_night_time" CONF_ARMING_AWAY_TIME = "arming_away_time" CONF_PENDING_TIME = "pending_time" CONF_TRIGGER_TIME = "trigger_time" FLAG_NORMAL = "normal" FLAG_BYPASS_ARMED_HOME = "bypass_armed_home" +FLAG_BYPASS_ARMED_NIGHT = "bypass_armed_night" BinarySensorFlags = { FLAG_NORMAL: 1 << 0, FLAG_BYPASS_ARMED_HOME: 1 << 1, + FLAG_BYPASS_ARMED_NIGHT: 1 << 2, } TemplateAlarmControlPanel = template_ns.class_( @@ -55,6 +59,7 @@ TEMPLATE_ALARM_CONTROL_PANEL_BINARY_SENSOR_SCHEMA = cv.maybe_simple_value( { cv.Required(CONF_INPUT): cv.use_id(binary_sensor.BinarySensor), cv.Optional(CONF_BYPASS_ARMED_HOME, default=False): cv.boolean, + cv.Optional(CONF_BYPASS_ARMED_NIGHT, default=False): cv.boolean, }, key=CONF_INPUT, ) @@ -66,6 +71,7 @@ TEMPLATE_ALARM_CONTROL_PANEL_SCHEMA = ( cv.Optional(CONF_CODES): cv.ensure_list(cv.string_strict), cv.Optional(CONF_REQUIRES_CODE_TO_ARM): cv.boolean, cv.Optional(CONF_ARMING_HOME_TIME): cv.positive_time_period_milliseconds, + cv.Optional(CONF_ARMING_NIGHT_TIME): cv.positive_time_period_milliseconds, cv.Optional( CONF_ARMING_AWAY_TIME, default="0s" ): cv.positive_time_period_milliseconds, @@ -110,14 +116,23 @@ async def to_code(config): cg.add(var.set_arming_home_time(config[CONF_ARMING_HOME_TIME])) supports_arm_home = True + supports_arm_night = False + if CONF_ARMING_NIGHT_TIME in config: + cg.add(var.set_arming_night_time(config[CONF_ARMING_NIGHT_TIME])) + supports_arm_night = True + for sensor in config.get(CONF_BINARY_SENSORS, []): bs = await cg.get_variable(sensor[CONF_INPUT]) flags = BinarySensorFlags[FLAG_NORMAL] if sensor[CONF_BYPASS_ARMED_HOME]: flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_HOME] supports_arm_home = True + if sensor[CONF_BYPASS_ARMED_NIGHT]: + flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_NIGHT] + supports_arm_night = True cg.add(var.add_sensor(bs, flags)) cg.add(var.set_supports_arm_home(supports_arm_home)) + cg.add(var.set_supports_arm_night(supports_arm_night)) cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp index 1c54998e42..da56976b56 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp @@ -29,6 +29,8 @@ void TemplateAlarmControlPanel::dump_config() { ESP_LOGCONFIG(TAG, " Arming Away Time: %us", (this->arming_away_time_ / 1000)); if (this->arming_home_time_ != 0) ESP_LOGCONFIG(TAG, " Arming Home Time: %us", (this->arming_home_time_ / 1000)); + if (this->arming_night_time_ != 0) + ESP_LOGCONFIG(TAG, " Arming Night Time: %us", (this->arming_night_time_ / 1000)); ESP_LOGCONFIG(TAG, " Pending Time: %us", (this->pending_time_ / 1000)); ESP_LOGCONFIG(TAG, " Trigger Time: %us", (this->trigger_time_ / 1000)); ESP_LOGCONFIG(TAG, " Supported Features: %u", this->get_supported_features()); @@ -38,6 +40,8 @@ void TemplateAlarmControlPanel::dump_config() { ESP_LOGCONFIG(TAG, " Name: %s", sensor_pair.first->get_name().c_str()); ESP_LOGCONFIG(TAG, " Armed home bypass: %s", TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); + ESP_LOGCONFIG(TAG, " Armed night bypass: %s", + TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)); } #endif } @@ -69,6 +73,9 @@ void TemplateAlarmControlPanel::loop() { if (this->desired_state_ == ACP_STATE_ARMED_HOME) { delay = this->arming_home_time_; } + if (this->desired_state_ == ACP_STATE_ARMED_NIGHT) { + delay = this->arming_night_time_; + } if ((millis() - this->last_update_) > delay) { this->publish_state(this->desired_state_); } @@ -95,6 +102,10 @@ void TemplateAlarmControlPanel::loop() { (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)) { continue; } + if (this->current_state_ == ACP_STATE_ARMED_NIGHT && + (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)) { + continue; + } trigger = true; break; } @@ -129,6 +140,9 @@ uint32_t TemplateAlarmControlPanel::get_supported_features() const { if (this->supports_arm_home_) { features |= ACP_FEAT_ARM_HOME; } + if (this->supports_arm_night_) { + features |= ACP_FEAT_ARM_NIGHT; + } return features; } @@ -158,6 +172,8 @@ void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) { this->arm_(call.get_code(), ACP_STATE_ARMED_AWAY, this->arming_away_time_); } else if (call.get_state() == ACP_STATE_ARMED_HOME) { this->arm_(call.get_code(), ACP_STATE_ARMED_HOME, this->arming_home_time_); + } else if (call.get_state() == ACP_STATE_ARMED_NIGHT) { + this->arm_(call.get_code(), ACP_STATE_ARMED_NIGHT, this->arming_night_time_); } else if (call.get_state() == ACP_STATE_DISARMED) { if (!this->is_code_valid_(call.get_code())) { ESP_LOGW(TAG, "Not disarming code doesn't match"); diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h index 4065356ba8..ebd8696692 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h @@ -19,6 +19,7 @@ namespace template_ { enum BinarySensorFlags : uint16_t { BINARY_SENSOR_MODE_NORMAL = 1 << 0, BINARY_SENSOR_MODE_BYPASS_ARMED_HOME = 1 << 1, + BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT = 1 << 2, }; #endif @@ -71,6 +72,12 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, */ void set_arming_home_time(uint32_t time) { this->arming_home_time_ = time; } + /** set the delay before arming night + * + * @param time The milliseconds + */ + void set_arming_night_time(uint32_t time) { this->arming_night_time_ = time; } + /** set the delay before triggering * * @param time The milliseconds @@ -85,6 +92,8 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, void set_supports_arm_home(bool supports_arm_home) { supports_arm_home_ = supports_arm_home; } + void set_supports_arm_night(bool supports_arm_night) { supports_arm_night_ = supports_arm_night; } + protected: void control(const alarm_control_panel::AlarmControlPanelCall &call) override; #ifdef USE_BINARY_SENSOR @@ -97,6 +106,8 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, uint32_t arming_away_time_; // the arming home delay uint32_t arming_home_time_{0}; + // the arming night delay + uint32_t arming_night_time_{0}; // the trigger delay uint32_t pending_time_; // the time in trigger @@ -106,6 +117,7 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, // requires a code to arm bool requires_code_to_arm_ = false; bool supports_arm_home_ = false; + bool supports_arm_night_ = false; // check if the code is valid bool is_code_valid_(optional code); diff --git a/tests/test3.yaml b/tests/test3.yaml index f7b66a748e..3ab1d561b3 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -1194,12 +1194,14 @@ alarm_control_panel: - "1234" requires_code_to_arm: true arming_home_time: 1s + arming_night_time: 1s arming_away_time: 15s pending_time: 15s trigger_time: 30s binary_sensors: - input: bin1 bypass_armed_home: true + bypass_armed_night: true on_state: then: - lambda: !lambda |- From 689bbf2419c9b5c4a4800e13f0d0dd002ff48688 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 23:59:46 +0000 Subject: [PATCH 0322/2607] Bump pyupgrade from 3.9.0 to 3.10.1 (#5189) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60053a14a1..cf86d354b7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - --branch=release - --branch=beta - repo: https://github.com/asottile/pyupgrade - rev: v3.9.0 + rev: v3.10.1 hooks: - id: pyupgrade args: [--py39-plus] diff --git a/requirements_test.txt b/requirements_test.txt index e67c57323e..7ab6742b02 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ pylint==2.17.5 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating black==23.7.0 # also change in .pre-commit-config.yaml when updating -pyupgrade==3.9.0 # also change in .pre-commit-config.yaml when updating +pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests From f3329fdc8c341906fa21a958d6aec979afabebfb Mon Sep 17 00:00:00 2001 From: Rudd-O Date: Tue, 8 Aug 2023 00:32:34 +0000 Subject: [PATCH 0323/2607] Add KMeterISO component. (#5170) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/kmeteriso/__init__.py | 0 esphome/components/kmeteriso/kmeteriso.cpp | 82 ++++++++++++++++++++++ esphome/components/kmeteriso/kmeteriso.h | 34 +++++++++ esphome/components/kmeteriso/sensor.py | 55 +++++++++++++++ tests/test1.yaml | 7 ++ 5 files changed, 178 insertions(+) create mode 100644 esphome/components/kmeteriso/__init__.py create mode 100644 esphome/components/kmeteriso/kmeteriso.cpp create mode 100644 esphome/components/kmeteriso/kmeteriso.h create mode 100644 esphome/components/kmeteriso/sensor.py diff --git a/esphome/components/kmeteriso/__init__.py b/esphome/components/kmeteriso/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/kmeteriso/kmeteriso.cpp b/esphome/components/kmeteriso/kmeteriso.cpp new file mode 100644 index 0000000000..0276ab3f67 --- /dev/null +++ b/esphome/components/kmeteriso/kmeteriso.cpp @@ -0,0 +1,82 @@ +#include "kmeteriso.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace kmeteriso { + +static const char *const TAG = "kmeteriso.sensor"; + +static const uint8_t KMETER_ERROR_STATUS_REG = 0x20; +static const uint8_t KMETER_TEMP_VAL_REG = 0x00; +static const uint8_t KMETER_INTERNAL_TEMP_VAL_REG = 0x10; +static const uint8_t KMETER_FIRMWARE_VERSION_REG = 0xFE; + +void KMeterISOComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up KMeterISO..."); + this->error_code_ = NONE; + + // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries + // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component. + if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) { + this->component_state_ &= ~COMPONENT_STATE_MASK; + this->component_state_ |= COMPONENT_STATE_CONSTRUCTION; + } + + auto err = this->bus_->writev(this->address_, nullptr, 0); + if (err == esphome::i2c::ERROR_OK) { + ESP_LOGCONFIG(TAG, "Could write to the address %d.", this->address_); + } else { + ESP_LOGCONFIG(TAG, "Could not write to the address %d.", this->address_); + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + uint8_t read_buf[4] = {1}; + if (!this->read_bytes(KMETER_ERROR_STATUS_REG, read_buf, 1)) { + ESP_LOGCONFIG(TAG, "Could not read from the device."); + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + if (read_buf[0] != 0) { + ESP_LOGCONFIG(TAG, "The device is not ready."); + this->error_code_ = STATUS_FAILED; + this->mark_failed(); + return; + } + ESP_LOGCONFIG(TAG, "The device was successfully setup."); +} + +float KMeterISOComponent::get_setup_priority() const { return setup_priority::DATA; } + +void KMeterISOComponent::update() { + uint8_t read_buf[4]; + + if (this->temperature_sensor_ != nullptr) { + if (!this->read_bytes(KMETER_TEMP_VAL_REG, read_buf, 4)) { + ESP_LOGW(TAG, "Error reading temperature."); + } else { + int32_t temp = encode_uint32(read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + float temp_f = temp / 100.0; + ESP_LOGV(TAG, "Got temperature=%.2f °C", temp_f); + this->temperature_sensor_->publish_state(temp_f); + } + } + + if (this->internal_temperature_sensor_ != nullptr) { + if (!this->read_bytes(KMETER_INTERNAL_TEMP_VAL_REG, read_buf, 4)) { + ESP_LOGW(TAG, "Error reading internal temperature."); + return; + } else { + int32_t internal_temp = encode_uint32(read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + float internal_temp_f = internal_temp / 100.0; + ESP_LOGV(TAG, "Got internal temperature=%.2f °C", internal_temp_f); + this->internal_temperature_sensor_->publish_state(internal_temp_f); + } + } +} + +} // namespace kmeteriso +} // namespace esphome diff --git a/esphome/components/kmeteriso/kmeteriso.h b/esphome/components/kmeteriso/kmeteriso.h new file mode 100644 index 0000000000..c8bed662b0 --- /dev/null +++ b/esphome/components/kmeteriso/kmeteriso.h @@ -0,0 +1,34 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/i2c/i2c_bus.h" + +namespace esphome { +namespace kmeteriso { + +/// This class implements support for the KMeterISO thermocouple sensor. +class KMeterISOComponent : public PollingComponent, public i2c::I2CDevice { + public: + void set_temperature_sensor(sensor::Sensor *t) { this->temperature_sensor_ = t; } + void set_internal_temperature_sensor(sensor::Sensor *t) { this->internal_temperature_sensor_ = t; } + + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + void setup() override; + float get_setup_priority() const override; + void update() override; + + protected: + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *internal_temperature_sensor_{nullptr}; + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + STATUS_FAILED, + } error_code_{NONE}; +}; + +} // namespace kmeteriso +} // namespace esphome diff --git a/esphome/components/kmeteriso/sensor.py b/esphome/components/kmeteriso/sensor.py new file mode 100644 index 0000000000..e730e446ae --- /dev/null +++ b/esphome/components/kmeteriso/sensor.py @@ -0,0 +1,55 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + CONF_TEMPERATURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + ENTITY_CATEGORY_DIAGNOSTIC, +) + +CONF_INTERNAL_TEMPERATURE = "internal_temperature" +DEPENDENCIES = ["i2c"] + +kmeteriso_ns = cg.esphome_ns.namespace("kmeteriso") + +KMeterISOComponent = kmeteriso_ns.class_( + "KMeterISOComponent", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(KMeterISOComponent), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x66)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + if internal_temperature_config := config.get(CONF_INTERNAL_TEMPERATURE): + sens = await sensor.new_sensor(internal_temperature_config) + cg.add(var.set_internal_temperature_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index a00b886ac1..2419634570 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -792,6 +792,13 @@ sensor: name: INA3221 Channel 1 Shunt Voltage update_interval: 15s i2c_id: i2c_bus + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Ttemperature + update_interval: 15s + i2c_id: i2c_bus - platform: kalman_combinator name: Kalman-filtered temperature process_std_dev: 0.00139 From cd514b140ee6349c51a2f5a61c34a8a443cfa447 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:31:49 +1200 Subject: [PATCH 0324/2607] Bump platformio from 6.1.7 to 6.1.9 (#5066) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- requirements.txt | 2 +- script/clang-tidy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 2bb1e81fbc..6330a0996e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ tornado==6.3.2 tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.7 # When updating platformio, also update Dockerfile +platformio==6.1.9 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.6 esphome-dashboard==20230711.0 diff --git a/script/clang-tidy b/script/clang-tidy index d8dd033d29..b025221fa8 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -72,7 +72,7 @@ def clang_options(idedata): # copy compiler flags, except those clang doesn't understand. cmd.extend( flag - for flag in idedata["cxx_flags"].split(" ") + for flag in idedata["cxx_flags"] if flag not in ( "-free", From a8fa4b56f93f8da897948f2832793edc3b1adf3a Mon Sep 17 00:00:00 2001 From: kahrendt Date: Tue, 8 Aug 2023 01:05:08 -0400 Subject: [PATCH 0325/2607] New component: Add support for bmp581 pressure and temperature sensors (#4657) --- CODEOWNERS | 1 + esphome/components/bmp581/__init__.py | 0 esphome/components/bmp581/bmp581.cpp | 596 ++++++++++++++++++++++++++ esphome/components/bmp581/bmp581.h | 222 ++++++++++ esphome/components/bmp581/sensor.py | 163 +++++++ tests/test1.yaml | 8 + 6 files changed, 990 insertions(+) create mode 100644 esphome/components/bmp581/__init__.py create mode 100644 esphome/components/bmp581/bmp581.cpp create mode 100644 esphome/components/bmp581/bmp581.h create mode 100644 esphome/components/bmp581/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 17d1462405..cda8a2f0f5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -49,6 +49,7 @@ esphome/components/ble_client/* @buxtronix esphome/components/bluetooth_proxy/* @jesserockz esphome/components/bme680_bsec/* @trvrnrth esphome/components/bmp3xx/* @martgras +esphome/components/bmp581/* @kahrendt esphome/components/bp1658cj/* @Cossid esphome/components/bp5758d/* @Cossid esphome/components/button/* @esphome/core diff --git a/esphome/components/bmp581/__init__.py b/esphome/components/bmp581/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/bmp581/bmp581.cpp b/esphome/components/bmp581/bmp581.cpp new file mode 100644 index 0000000000..0308da0bcb --- /dev/null +++ b/esphome/components/bmp581/bmp581.cpp @@ -0,0 +1,596 @@ +/* + * Adds support for Bosch's BMP581 high accuracy pressure and temperature sensor + * - Component structure based on ESPHome's BMP3XX component (as of March, 2023) + * - Implementation is easier as the sensor itself automatically compensates pressure for the temperature + * - Temperature and pressure data is converted via simple divison operations in this component + * - IIR filter level can independently be applied to temperature and pressure measurements + * - Bosch's BMP5-Sensor-API was consulted to verify that sensor configuration is done correctly + * - Copyright (c) 2022 Bosch Sensortec Gmbh, SPDX-License-Identifier: BSD-3-Clause + * - This component uses forced power mode only so measurements are synchronized by the host + * - All datasheet page references refer to Bosch Document Number BST-BMP581-DS004-04 (revision number 1.4) + */ + +#include "bmp581.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace bmp581 { + +static const char *const TAG = "bmp581"; + +static const LogString *oversampling_to_str(Oversampling oversampling) { + switch (oversampling) { + case Oversampling::OVERSAMPLING_NONE: + return LOG_STR("None"); + case Oversampling::OVERSAMPLING_X2: + return LOG_STR("2x"); + case Oversampling::OVERSAMPLING_X4: + return LOG_STR("4x"); + case Oversampling::OVERSAMPLING_X8: + return LOG_STR("8x"); + case Oversampling::OVERSAMPLING_X16: + return LOG_STR("16x"); + case Oversampling::OVERSAMPLING_X32: + return LOG_STR("32x"); + case Oversampling::OVERSAMPLING_X64: + return LOG_STR("64x"); + case Oversampling::OVERSAMPLING_X128: + return LOG_STR("128x"); + default: + return LOG_STR(""); + } +} + +static const LogString *iir_filter_to_str(IIRFilter filter) { + switch (filter) { + case IIRFilter::IIR_FILTER_OFF: + return LOG_STR("OFF"); + case IIRFilter::IIR_FILTER_2: + return LOG_STR("2x"); + case IIRFilter::IIR_FILTER_4: + return LOG_STR("4x"); + case IIRFilter::IIR_FILTER_8: + return LOG_STR("8x"); + case IIRFilter::IIR_FILTER_16: + return LOG_STR("16x"); + case IIRFilter::IIR_FILTER_32: + return LOG_STR("32x"); + case IIRFilter::IIR_FILTER_64: + return LOG_STR("64x"); + case IIRFilter::IIR_FILTER_128: + return LOG_STR("128x"); + default: + return LOG_STR(""); + } +} + +void BMP581Component::dump_config() { + ESP_LOGCONFIG(TAG, "BMP581:"); + + switch (this->error_code_) { + case NONE: + break; + case ERROR_COMMUNICATION_FAILED: + ESP_LOGE(TAG, " Communication with BMP581 failed!"); + break; + case ERROR_WRONG_CHIP_ID: + ESP_LOGE(TAG, " BMP581 has wrong chip ID - please verify you are using a BMP 581"); + break; + case ERROR_SENSOR_RESET: + ESP_LOGE(TAG, " BMP581 failed to reset"); + break; + case ERROR_SENSOR_STATUS: + ESP_LOGE(TAG, " BMP581 sensor status failed, there were NVM problems"); + break; + case ERROR_PRIME_IIR_FAILED: + ESP_LOGE(TAG, " BMP581's IIR Filter failed to prime with an initial measurement"); + break; + default: + ESP_LOGE(TAG, " BMP581 error code %d", (int) this->error_code_); + break; + } + + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); + + ESP_LOGCONFIG(TAG, " Measurement conversion time: %ums", this->conversion_time_); + + if (this->temperature_sensor_) { + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_temperature_level_))); + ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_))); + } + + if (this->pressure_sensor_) { + LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); + ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_pressure_level_))); + ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_))); + } +} + +void BMP581Component::setup() { + /* + * Setup goes through several stages, which follows the post-power-up procedure (page 18 of datasheet) and then sets + * configured options + * 1) Soft reboot + * 2) Verify ASIC chip ID matches BMP581 + * 3) Verify sensor status (check if NVM is okay) + * 4) Enable data ready interrupt + * 5) Write oversampling settings and set internal configuration values + * 6) Configure and prime IIR Filter(s), if enabled + */ + + this->error_code_ = NONE; + ESP_LOGCONFIG(TAG, "Setting up BMP581..."); + + //////////////////// + // 1) Soft reboot // + //////////////////// + + // Power-On-Reboot bit is asserted if sensor successfully reset + if (!this->reset_()) { + ESP_LOGE(TAG, "BMP581 failed to reset"); + + this->error_code_ = ERROR_SENSOR_RESET; + this->mark_failed(); + + return; + } + + /////////////////////////////////////////// + // 2) Verify ASIC chip ID matches BMP581 // + /////////////////////////////////////////// + + uint8_t chip_id; + + // read chip id from sensor + if (!this->read_byte(BMP581_CHIP_ID, &chip_id)) { + ESP_LOGE(TAG, "Failed to read chip id"); + + this->error_code_ = ERROR_COMMUNICATION_FAILED; + this->mark_failed(); + + return; + } + + // verify id + if (chip_id != BMP581_ASIC_ID) { + ESP_LOGE(TAG, "Unknown chip ID, is this a BMP581?"); + + this->error_code_ = ERROR_WRONG_CHIP_ID; + this->mark_failed(); + + return; + } + + //////////////////////////////////////////////////// + // 3) Verify sensor status (check if NVM is okay) // + //////////////////////////////////////////////////// + + if (!this->read_byte(BMP581_STATUS, &this->status_.reg)) { + ESP_LOGE(TAG, "Failed to read status register"); + + this->error_code_ = ERROR_COMMUNICATION_FAILED; + this->mark_failed(); + + return; + } + + // verify status_nvm_rdy bit (it is asserted if boot was successful) + if (!(this->status_.bit.status_nvm_rdy)) { + ESP_LOGE(TAG, "NVM not ready after boot"); + + this->error_code_ = ERROR_SENSOR_STATUS; + this->mark_failed(); + + return; + } + + // verify status_nvm_err bit (it is asserted if an error is detected) + if (this->status_.bit.status_nvm_err) { + ESP_LOGE(TAG, "NVM error detected on boot"); + + this->error_code_ = ERROR_SENSOR_STATUS; + this->mark_failed(); + + return; + } + + //////////////////////////////////// + // 4) Enable data ready interrupt // + //////////////////////////////////// + + // enable the data ready interrupt source + if (!this->write_interrupt_source_settings_(true)) { + ESP_LOGE(TAG, "Failed to write interrupt source register"); + + this->error_code_ = ERROR_COMMUNICATION_FAILED; + this->mark_failed(); + + return; + } + + ////////////////////////////////////////////////////////////////////////// + // 5) Write oversampling settings and set internal configuration values // + ////////////////////////////////////////////////////////////////////////// + + // configure pressure readings, if sensor is defined + // otherwise, disable pressure oversampling + if (this->pressure_sensor_) { + this->osr_config_.bit.press_en = true; + } else { + this->pressure_oversampling_ = OVERSAMPLING_NONE; + } + + // write oversampling settings + if (!this->write_oversampling_settings_(this->temperature_oversampling_, this->pressure_oversampling_)) { + ESP_LOGE(TAG, "Failed to write oversampling register"); + + this->error_code_ = ERROR_COMMUNICATION_FAILED; + this->mark_failed(); + + return; + } + + // set output data rate to 4 Hz=0x19 (page 65 of datasheet) + // - ?shouldn't? matter as this component only uses FORCED_MODE - datasheet is ambiguous + // - If in NORMAL_MODE or NONSTOP_MODE, then this would still allow deep standby to save power + // - will be written to BMP581 at next requested measurement + this->odr_config_.bit.odr = 0x19; + + /////////////////////////////////////////////////////// + /// 6) Configure and prime IIR Filter(s), if enabled // + /////////////////////////////////////////////////////// + + if ((this->iir_temperature_level_ != IIR_FILTER_OFF) || (this->iir_pressure_level_ != IIR_FILTER_OFF)) { + if (!this->write_iir_settings_(this->iir_temperature_level_, this->iir_pressure_level_)) { + ESP_LOGE(TAG, "Failed to write IIR configuration registers"); + + this->error_code_ = ERROR_COMMUNICATION_FAILED; + this->mark_failed(); + + return; + } + + if (!this->prime_iir_filter_()) { + ESP_LOGE(TAG, "Failed to prime the IIR filter with an intiial measurement"); + + this->error_code_ = ERROR_PRIME_IIR_FAILED; + this->mark_failed(); + + return; + } + } +} + +void BMP581Component::update() { + /* + * Each update goes through several stages + * 0) Verify either a temperature or pressure sensor is defined before proceeding + * 1) Request a measurement + * 2) Wait for measurement to finish (based on oversampling rates) + * 3) Read data registers for temperature and pressure, if applicable + * 4) Publish measurements to sensor(s), if applicable + */ + + //////////////////////////////////////////////////////////////////////////////////// + // 0) Verify either a temperature or pressure sensor is defined before proceeding // + //////////////////////////////////////////////////////////////////////////////////// + + if ((!this->temperature_sensor_) && (!this->pressure_sensor_)) { + return; + } + + ////////////////////////////// + // 1) Request a measurement // + ////////////////////////////// + + ESP_LOGVV(TAG, "Requesting a measurement from sensor"); + + if (!this->start_measurement_()) { + ESP_LOGW(TAG, "Failed to request forced measurement of sensor"); + this->status_set_warning(); + + return; + } + + ////////////////////////////////////////////////////////////////////// + // 2) Wait for measurement to finish (based on oversampling rates) // + ////////////////////////////////////////////////////////////////////// + + ESP_LOGVV(TAG, "Measurement is expected to take %d ms to complete", this->conversion_time_); + + this->set_timeout("measurement", this->conversion_time_, [this]() { + float temperature = 0.0; + float pressure = 0.0; + + //////////////////////////////////////////////////////////////////////// + // 3) Read data registers for temperature and pressure, if applicable // + //////////////////////////////////////////////////////////////////////// + + if (this->pressure_sensor_) { + if (!this->read_temperature_and_pressure_(temperature, pressure)) { + ESP_LOGW(TAG, "Failed to read temperature and pressure measurements, skipping update"); + this->status_set_warning(); + + return; + } + } else { + if (!this->read_temperature_(temperature)) { + ESP_LOGW(TAG, "Failed to read temperature measurement, skipping update"); + this->status_set_warning(); + + return; + } + } + + ///////////////////////////////////////////////////////// + // 4) Publish measurements to sensor(s), if applicable // + ///////////////////////////////////////////////////////// + + if (this->temperature_sensor_) { + this->temperature_sensor_->publish_state(temperature); + } + + if (this->pressure_sensor_) { + this->pressure_sensor_->publish_state(pressure); + } + + this->status_clear_warning(); + }); +} + +bool BMP581Component::check_data_readiness_() { + // - verifies component is not internally in standby mode + // - reads interrupt status register + // - checks if data ready bit is asserted + // - If true, then internally sets component to standby mode if in forced mode + // - returns data readiness state + + if (this->odr_config_.bit.pwr_mode == STANDBY_MODE) { + ESP_LOGD(TAG, "Data is not ready, sensor is in standby mode"); + return false; + } + + uint8_t status; + + if (!this->read_byte(BMP581_INT_STATUS, &status)) { + ESP_LOGE(TAG, "Failed to read interrupt status register"); + return false; + } + + this->int_status_.reg = status; + + if (this->int_status_.bit.drdy_data_reg) { + // If in forced mode, then set internal record of the power mode to STANDBY_MODE + // - sensor automatically returns to standby mode after completing a forced measurement + if (this->odr_config_.bit.pwr_mode == FORCED_MODE) { + this->odr_config_.bit.pwr_mode = STANDBY_MODE; + } + + return true; + } + + return false; +} + +bool BMP581Component::prime_iir_filter_() { + // - temporarily disables oversampling for a fast initial measurement; avoids slowing down ESPHome's startup process + // - enables IIR filter flushing with forced measurements + // - forces a measurement; flushing the IIR filter and priming it with a current value + // - disables IIR filter flushing with forced measurements + // - reverts to internally configured oversampling rates + // - returns success of all register writes/priming + + // store current internal oversampling settings to revert to after priming + Oversampling current_temperature_oversampling = (Oversampling) this->osr_config_.bit.osr_t; + Oversampling current_pressure_oversampling = (Oversampling) this->osr_config_.bit.osr_p; + + // temporarily disables oversampling for temperature and pressure for a fast priming measurement + if (!this->write_oversampling_settings_(OVERSAMPLING_NONE, OVERSAMPLING_NONE)) { + ESP_LOGE(TAG, "Failed to write oversampling register"); + + return false; + } + + // flush the IIR filter with forced measurements (we will only flush once) + this->dsp_config_.bit.iir_flush_forced_en = true; + if (!this->write_byte(BMP581_DSP, this->dsp_config_.reg)) { + ESP_LOGE(TAG, "Failed to write IIR source register"); + + return false; + } + + // forces an intial measurement + // - this measurements flushes the IIR filter reflecting written DSP settings + // - flushing with this initial reading avoids having the internal previous data aquisition being 0, which + // (I)nfinitely affects future values + if (!this->start_measurement_()) { + ESP_LOGE(TAG, "Failed to request a forced measurement"); + + return false; + } + + // wait for priming measurement to complete + // - with oversampling disabled, the conversion time for a single measurement for pressure and temperature is + // ceilf(1.05*(1.0+1.0)) = 3ms + // - see page 12 of datasheet for details + delay(3); + + if (!this->check_data_readiness_()) { + ESP_LOGE(TAG, "IIR priming measurement was not ready"); + + return false; + } + + // disable IIR filter flushings on future forced measurements + this->dsp_config_.bit.iir_flush_forced_en = false; + if (!this->write_byte(BMP581_DSP, this->dsp_config_.reg)) { + ESP_LOGE(TAG, "Failed to write IIR source register"); + + return false; + } + + // revert oversampling rates to original settings + return this->write_oversampling_settings_(current_temperature_oversampling, current_pressure_oversampling); +} + +bool BMP581Component::read_temperature_(float &temperature) { + // - verifies data is ready to be read + // - reads in 3 bytes of temperature data + // - returns whether successful, where the the variable parameter contains + // - the measured temperature (in degrees Celsius) + + if (!this->check_data_readiness_()) { + ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); + this->status_set_warning(); + + return false; + } + + uint8_t data[3]; + if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 3)) { + ESP_LOGW(TAG, "Failed to read sensor's measurement data"); + this->status_set_warning(); + + return false; + } + + // temperature MSB is in data[2], LSB is in data[1], XLSB in data[0] + int32_t raw_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0]; + temperature = (float) (raw_temp / 65536.0); // convert measurement to degrees Celsius (page 22 of datasheet) + + return true; +} + +bool BMP581Component::read_temperature_and_pressure_(float &temperature, float &pressure) { + // - verifies data is ready to be read + // - reads in 6 bytes of temperature data (3 for temeperature, 3 for pressure) + // - returns whether successful, where the variable parameters contain + // - the measured temperature (in degrees Celsius) + // - the measured pressure (in Pa) + + if (!this->check_data_readiness_()) { + ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); + this->status_set_warning(); + + return false; + } + + uint8_t data[6]; + if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 6)) { + ESP_LOGW(TAG, "Failed to read sensor's measurement data"); + this->status_set_warning(); + + return false; + } + + // temperature MSB is in data[2], LSB is in data[1], XLSB in data[0] + int32_t raw_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0]; + temperature = (float) (raw_temp / 65536.0); // convert measurement to degrees Celsius (page 22 of datasheet) + + // pressure MSB is in data[5], LSB is in data[4], XLSB in data[3] + int32_t raw_press = (int32_t) data[5] << 16 | (int32_t) data[4] << 8 | (int32_t) data[3]; + pressure = (float) (raw_press / 64.0); // Divide by 2^6=64 for Pa (page 22 of datasheet) + + return true; +} + +bool BMP581Component::reset_() { + // - writes reset command to the command register + // - waits for sensor to complete reset + // - returns the Power-On-Reboot interrupt status, which is asserted if successful + + // writes reset command to BMP's command register + if (!this->write_byte(BMP581_COMMAND, RESET_COMMAND)) { + ESP_LOGE(TAG, "Failed to write reset command"); + + return false; + } + + // t_{soft_res} = 2ms (page 11 of datasheet); time it takes to enter standby mode + // - round up to 3 ms + delay(3); + + // read interrupt status register + if (!this->read_byte(BMP581_INT_STATUS, &this->int_status_.reg)) { + ESP_LOGE(TAG, "Failed to read interrupt status register"); + + return false; + } + + // Power-On-Reboot bit is asserted if sensor successfully reset + return this->int_status_.bit.por; +} + +bool BMP581Component::start_measurement_() { + // - only pushes the sensor into FORCED_MODE for a reading if already in STANDBY_MODE + // - returns whether a measurement is in progress or has been initiated + + if (this->odr_config_.bit.pwr_mode == STANDBY_MODE) { + return this->write_power_mode_(FORCED_MODE); + } else { + return true; + } +} + +bool BMP581Component::write_iir_settings_(IIRFilter temperature_iir, IIRFilter pressure_iir) { + // - ensures data registers store filtered values + // - sets IIR filter levels on sensor + // - matches other default settings on sensor + // - writes configuration to the two relevant registers + // - returns success or failure of write to the registers + + // If the temperature/pressure IIR filter is configured, then ensure data registers store the filtered measurement + this->dsp_config_.bit.shdw_sel_iir_t = (temperature_iir != IIR_FILTER_OFF); + this->dsp_config_.bit.shdw_sel_iir_p = (pressure_iir != IIR_FILTER_OFF); + + // set temperature and pressure IIR filter level to configured values + this->iir_config_.bit.set_iir_t = temperature_iir; + this->iir_config_.bit.set_iir_p = pressure_iir; + + // enable pressure and temperature compensation (page 61 of datasheet) + // - ?only relevant if IIR filter is applied?; the datasheet is ambiguous + // - matches BMP's default setting + this->dsp_config_.bit.comp_pt_en = 0x3; + + // BMP581_DSP register and BMP581_DSP_IIR registers are successive + // - allows us to write the IIR configuration with one command to both registers + uint8_t register_data[2] = {this->dsp_config_.reg, this->iir_config_.reg}; + return this->write_bytes(BMP581_DSP, register_data, sizeof(register_data)); +} + +bool BMP581Component::write_interrupt_source_settings_(bool data_ready_enable) { + // - updates component's internal setting + // - returns success or failure of write to interrupt source register + + this->int_source_.bit.drdy_data_reg_en = data_ready_enable; + + // write interrupt source register + return this->write_byte(BMP581_INT_SOURCE, this->int_source_.reg); +} + +bool BMP581Component::write_oversampling_settings_(Oversampling temperature_oversampling, + Oversampling pressure_oversampling) { + // - updates component's internal setting + // - returns success or failure of write to Over-Sampling Rate register + + this->osr_config_.bit.osr_t = temperature_oversampling; + this->osr_config_.bit.osr_p = pressure_oversampling; + + return this->write_byte(BMP581_OSR, this->osr_config_.reg); +} + +bool BMP581Component::write_power_mode_(OperationMode mode) { + // - updates the component's internal power mode + // - returns success or failure of write to Output Data Rate register + + this->odr_config_.bit.pwr_mode = mode; + + // write odr register + return this->write_byte(BMP581_ODR, this->odr_config_.reg); +} + +} // namespace bmp581 +} // namespace esphome diff --git a/esphome/components/bmp581/bmp581.h b/esphome/components/bmp581/bmp581.h new file mode 100644 index 0000000000..7327be44ae --- /dev/null +++ b/esphome/components/bmp581/bmp581.h @@ -0,0 +1,222 @@ +// All datasheet page references refer to Bosch Document Number BST-BMP581-DS004-04 (revision number 1.4) + +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace bmp581 { + +static const uint8_t BMP581_ASIC_ID = 0x50; // BMP581's ASIC chip ID (page 51 of datasheet) +static const uint8_t RESET_COMMAND = 0xB6; // Soft reset command + +// BMP581 Register Addresses +enum { + BMP581_CHIP_ID = 0x01, // read chip ID + BMP581_INT_SOURCE = 0x15, // write interrupt sources + BMP581_MEASUREMENT_DATA = + 0x1D, // read measurement registers, 0x1D-0x1F are temperature XLSB to MSB and 0x20-0x22 are pressure XLSB to MSB + BMP581_INT_STATUS = 0x27, // read interrupt statuses + BMP581_STATUS = 0x28, // read sensor status + BMP581_DSP = 0x30, // write sensor configuration + BMP581_DSP_IIR = 0x31, // write IIR filter configuration + BMP581_OSR = 0x36, // write oversampling configuration + BMP581_ODR = 0x37, // write data rate and power mode configuration + BMP581_COMMAND = 0x7E // write sensor command +}; + +// BMP581 Power mode operations +enum OperationMode { + STANDBY_MODE = 0x0, // no active readings + NORMAL_MODE = 0x1, // read continuously at ODR configured rate and standby between + FORCED_MODE = 0x2, // read sensor once (only reading mode used by this component) + NONSTOP_MODE = 0x3 // read continuously with no standby +}; + +// Temperature and pressure sensors can be oversampled to reduce noise +enum Oversampling { + OVERSAMPLING_NONE = 0x0, + OVERSAMPLING_X2 = 0x1, + OVERSAMPLING_X4 = 0x2, + OVERSAMPLING_X8 = 0x3, + OVERSAMPLING_X16 = 0x4, + OVERSAMPLING_X32 = 0x5, + OVERSAMPLING_X64 = 0x6, + OVERSAMPLING_X128 = 0x7 +}; + +// Infinite Impulse Response filter reduces noise caused by ambient disturbances +enum IIRFilter { + IIR_FILTER_OFF = 0x0, + IIR_FILTER_2 = 0x1, + IIR_FILTER_4 = 0x2, + IIR_FILTER_8 = 0x3, + IIR_FILTER_16 = 0x4, + IIR_FILTER_32 = 0x5, + IIR_FILTER_64 = 0x6, + IIR_FILTER_128 = 0x7 +}; + +class BMP581Component : public PollingComponent, public i2c::I2CDevice { + public: + float get_setup_priority() const override { return setup_priority::DATA; } + + void dump_config() override; + + void setup() override; + void update() override; + + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } + void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; } + + void set_temperature_oversampling_config(Oversampling temperature_oversampling) { + this->temperature_oversampling_ = temperature_oversampling; + } + void set_pressure_oversampling_config(Oversampling pressure_oversampling) { + this->pressure_oversampling_ = pressure_oversampling; + } + + void set_temperature_iir_filter_config(IIRFilter iir_temperature_level) { + this->iir_temperature_level_ = iir_temperature_level; + } + void set_pressure_iir_filter_config(IIRFilter iir_pressure_level) { this->iir_pressure_level_ = iir_pressure_level; } + + void set_conversion_time(uint8_t conversion_time) { this->conversion_time_ = conversion_time; } + + protected: + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *pressure_sensor_{nullptr}; + + Oversampling temperature_oversampling_; + Oversampling pressure_oversampling_; + + IIRFilter iir_temperature_level_; + IIRFilter iir_pressure_level_; + + // Stores the sensors conversion time needed for a measurement based on oversampling settings and datasheet (page 12) + // Computed in Python during codegen + uint8_t conversion_time_; + + // Checks if the BMP581 has measurement data ready by checking the sensor's interrupts + bool check_data_readiness_(); + + // Flushes the IIR filter and primes an initial reading + bool prime_iir_filter_(); + + // Reads temperature data from sensor and converts data to measurement in degrees Celsius + bool read_temperature_(float &temperature); + // Reads temperature and pressure data from sensor and converts data to measurements in degrees Celsius and Pa + bool read_temperature_and_pressure_(float &temperature, float &pressure); + + // Soft resets the BMP581 + bool reset_(); + + // Initiates a measurement on sensor by switching to FORCED_MODE + bool start_measurement_(); + + // Writes the IIR filter configuration to the DSP and DSP_IIR registers + bool write_iir_settings_(IIRFilter temperature_iir, IIRFilter pressure_iir); + + // Writes whether to enable the data ready interrupt to the interrupt source register + bool write_interrupt_source_settings_(bool data_ready_enable); + + // Writes the oversampling settings to the OSR register + bool write_oversampling_settings_(Oversampling temperature_oversampling, Oversampling pressure_oversampling); + + // Sets the power mode on the BMP581 by writing to the ODR register + bool write_power_mode_(OperationMode mode); + + enum ErrorCode { + NONE = 0, + ERROR_COMMUNICATION_FAILED, + ERROR_WRONG_CHIP_ID, + ERROR_SENSOR_STATUS, + ERROR_SENSOR_RESET, + ERROR_PRIME_IIR_FAILED + } error_code_{NONE}; + + // BMP581's interrupt source register (address 0x15) to configure which interrupts are enabled (page 54 of datasheet) + union { + struct { + uint8_t drdy_data_reg_en : 1; // Data ready interrupt enable + uint8_t fifo_full_en : 1; // FIFO full interrupt enable + uint8_t fifo_ths_en : 1; // FIFO threshold/watermark interrupt enable + uint8_t oor_p_en : 1; // Pressure data out-of-range interrupt enable + } bit; + uint8_t reg; + } int_source_ = {.reg = 0}; + + // BMP581's interrupt status register (address 0x27) to determine ensor's current state (page 58 of datasheet) + union { + struct { + uint8_t drdy_data_reg : 1; // Data ready + uint8_t fifo_full : 1; // FIFO full + uint8_t fifo_ths : 1; // FIFO fhreshold/watermark + uint8_t oor_p : 1; // Pressure data out-of-range + uint8_t por : 1; // Power-On-Reset complete + } bit; + uint8_t reg; + } int_status_ = {.reg = 0}; + + // BMP581's status register (address 0x28) to determine if sensor has setup correctly (page 58 of datasheet) + union { + struct { + uint8_t status_core_rdy : 1; + uint8_t status_nvm_rdy : 1; // asserted if NVM is ready of operations + uint8_t status_nvm_err : 1; // asserted if NVM error + uint8_t status_nvm_cmd_err : 1; // asserted if boot command error + uint8_t status_boot_err_corrected : 1; // asserted if a boot error has been corrected + uint8_t : 2; + uint8_t st_crack_pass : 1; // asserted if crack check has executed without detecting a crack + } bit; + uint8_t reg; + } status_ = {.reg = 0}; + + // BMP581's dsp register (address 0x30) to configure data registers iir selection (page 61 of datasheet) + union { + struct { + uint8_t comp_pt_en : 2; // enable temperature and pressure compensation + uint8_t iir_flush_forced_en : 1; // IIR filter is flushed in forced mode + uint8_t shdw_sel_iir_t : 1; // temperature data register value selected before or after iir + uint8_t fifo_sel_iir_t : 1; // FIFO temperature data register value secected before or after iir + uint8_t shdw_sel_iir_p : 1; // pressure data register value selected before or after iir + uint8_t fifo_sel_iir_p : 1; // FIFO pressure data register value selected before or after iir + uint8_t oor_sel_iir_p : 1; // pressure out-of-range value selected before or after iir + } bit; + uint8_t reg; + } dsp_config_ = {.reg = 0}; + + // BMP581's iir register (address 0x31) to configure iir filtering(page 62 of datasheet) + union { + struct { + uint8_t set_iir_t : 3; // Temperature IIR filter coefficient + uint8_t set_iir_p : 3; // Pressure IIR filter coefficient + } bit; + uint8_t reg; + } iir_config_ = {.reg = 0}; + + // BMP581's OSR register (address 0x36) to configure Over-Sampling Rates (page 64 of datasheet) + union { + struct { + uint8_t osr_t : 3; // Temperature oversampling + uint8_t osr_p : 3; // Pressure oversampling + uint8_t press_en : 1; // Enables pressure measurement + } bit; + uint8_t reg; + } osr_config_ = {.reg = 0}; + + // BMP581's odr register (address 0x37) to configure output data rate and power mode (page 64 of datasheet) + union { + struct { + uint8_t pwr_mode : 2; // power mode of sensor + uint8_t odr : 5; // output data rate + uint8_t deep_dis : 1; // deep standby disabled if asserted + } bit; + uint8_t reg; + } odr_config_ = {.reg = 0}; +}; + +} // namespace bmp581 +} // namespace esphome diff --git a/esphome/components/bmp581/sensor.py b/esphome/components/bmp581/sensor.py new file mode 100644 index 0000000000..1e0350075a --- /dev/null +++ b/esphome/components/bmp581/sensor.py @@ -0,0 +1,163 @@ +import math +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + CONF_IIR_FILTER, + CONF_OVERSAMPLING, + CONF_PRESSURE, + CONF_TEMPERATURE, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PASCAL, +) + +CODEOWNERS = ["@kahrendt"] +DEPENDENCIES = ["i2c"] + +bmp581_ns = cg.esphome_ns.namespace("bmp581") + +Oversampling = bmp581_ns.enum("Oversampling") +OVERSAMPLING_OPTIONS = { + "NONE": Oversampling.OVERSAMPLING_NONE, + "2X": Oversampling.OVERSAMPLING_X2, + "4X": Oversampling.OVERSAMPLING_X4, + "8X": Oversampling.OVERSAMPLING_X8, + "16X": Oversampling.OVERSAMPLING_X16, + "32X": Oversampling.OVERSAMPLING_X32, + "64X": Oversampling.OVERSAMPLING_X64, + "128X": Oversampling.OVERSAMPLING_X128, +} + +IIRFilter = bmp581_ns.enum("IIRFilter") +IIR_FILTER_OPTIONS = { + "OFF": IIRFilter.IIR_FILTER_OFF, + "2X": IIRFilter.IIR_FILTER_2, + "4X": IIRFilter.IIR_FILTER_4, + "8X": IIRFilter.IIR_FILTER_8, + "16X": IIRFilter.IIR_FILTER_16, + "32X": IIRFilter.IIR_FILTER_32, + "64X": IIRFilter.IIR_FILTER_64, + "128X": IIRFilter.IIR_FILTER_128, +} + +BMP581Component = bmp581_ns.class_( + "BMP581Component", cg.PollingComponent, i2c.I2CDevice +) + + +def compute_measurement_conversion_time(config): + # - adds up sensor conversion time based on temperature and pressure oversampling rates given in datasheet + # - returns a rounded up time in ms + + # Page 12 of datasheet + PRESSURE_OVERSAMPLING_CONVERSION_TIMES = { + "NONE": 1.0, + "2X": 1.7, + "4X": 2.9, + "8X": 5.4, + "16X": 10.4, + "32X": 20.4, + "64X": 40.4, + "128X": 80.4, + } + + # Page 12 of datasheet + TEMPERATURE_OVERSAMPLING_CONVERSION_TIMES = { + "NONE": 1.0, + "2X": 1.1, + "4X": 1.5, + "8X": 2.1, + "16X": 3.3, + "32X": 5.8, + "64X": 10.8, + "128X": 20.8, + } + + pressure_conversion_time = ( + 0.0 # No conversion time necessary without a pressure sensor + ) + if pressure_config := config.get(CONF_PRESSURE): + pressure_conversion_time = PRESSURE_OVERSAMPLING_CONVERSION_TIMES[ + pressure_config.get(CONF_OVERSAMPLING) + ] + + temperature_conversion_time = ( + 1.0 # BMP581 always samples the temperature even if only reading pressure + ) + if temperature_config := config.get(CONF_TEMPERATURE): + temperature_conversion_time = TEMPERATURE_OVERSAMPLING_CONVERSION_TIMES[ + temperature_config.get(CONF_OVERSAMPLING) + ] + + # Datasheet indicates a 5% possible error in each conversion time listed + return math.ceil(1.05 * (pressure_conversion_time + temperature_conversion_time)) + + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(BMP581Component), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="NONE"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( + IIR_FILTER_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_PASCAL, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( + IIR_FILTER_OPTIONS, upper=True + ), + } + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x46)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + cg.add( + var.set_temperature_oversampling_config( + temperature_config[CONF_OVERSAMPLING] + ) + ) + cg.add( + var.set_temperature_iir_filter_config(temperature_config[CONF_IIR_FILTER]) + ) + + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) + cg.add(var.set_pressure_sensor(sens)) + cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING])) + cg.add(var.set_pressure_iir_filter_config(pressure_config[CONF_IIR_FILTER])) + + cg.add(var.set_conversion_time(compute_measurement_conversion_time(config))) diff --git a/tests/test1.yaml b/tests/test1.yaml index 2419634570..254abe2b01 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1355,6 +1355,14 @@ sensor: name: "Distance" update_interval: 60s i2c_id: i2c_bus + - platform: bmp581 + i2c_id: i2c_bus + temperature: + name: "BMP581 Temperature" + iir_filter: 2x + pressure: + name: "BMP581 Pressure" + oversampling: 128x esp32_touch: setup_mode: false From 0ed0bdc65515dc685f70474fb781de3cc39acda8 Mon Sep 17 00:00:00 2001 From: Greg Cormier Date: Thu, 10 Aug 2023 01:04:22 -0400 Subject: [PATCH 0326/2607] New PM sensor Panasonic SN-GCJA5 (#4988) --- CODEOWNERS | 1 + esphome/components/gcja5/__init__.py | 1 + esphome/components/gcja5/gcja5.cpp | 119 +++++++++++++++++++++++++++ esphome/components/gcja5/gcja5.h | 52 ++++++++++++ esphome/components/gcja5/sensor.py | 118 ++++++++++++++++++++++++++ tests/test1.yaml | 22 +++++ 6 files changed, 313 insertions(+) create mode 100644 esphome/components/gcja5/__init__.py create mode 100644 esphome/components/gcja5/gcja5.cpp create mode 100644 esphome/components/gcja5/gcja5.h create mode 100644 esphome/components/gcja5/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index cda8a2f0f5..408caee4f2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -102,6 +102,7 @@ esphome/components/fastled_base/* @OttoWinter esphome/components/feedback/* @ianchi esphome/components/fingerprint_grow/* @OnFreund @loongyh esphome/components/fs3000/* @kahrendt +esphome/components/gcja5/* @gcormier esphome/components/globals/* @esphome/core esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core diff --git a/esphome/components/gcja5/__init__.py b/esphome/components/gcja5/__init__.py new file mode 100644 index 0000000000..122ffaf6ed --- /dev/null +++ b/esphome/components/gcja5/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@gcormier"] diff --git a/esphome/components/gcja5/gcja5.cpp b/esphome/components/gcja5/gcja5.cpp new file mode 100644 index 0000000000..7f980ca0ad --- /dev/null +++ b/esphome/components/gcja5/gcja5.cpp @@ -0,0 +1,119 @@ +/* From snooping with a logic analyzer, the I2C on this sensor is broken. I was only able + * to receive 1's as a response from the sensor. I was able to get the UART working. + * + * The datasheet says the values should be divided by 1000, but this must only be for the I2C + * implementation. Comparing UART values with another sensor, there is no need to divide by 1000. + */ +#include "gcja5.h" +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace gcja5 { + +static const char *const TAG = "gcja5"; + +void GCJA5Component::setup() { ESP_LOGCONFIG(TAG, "Setting up gcja5..."); } + +void GCJA5Component::loop() { + const uint32_t now = millis(); + if (now - this->last_transmission_ >= 500) { + // last transmission too long ago. Reset RX index. + this->rx_message_.clear(); + } + + if (this->available() == 0) { + return; + } + + // There must now be data waiting + this->last_transmission_ = now; + uint8_t val; + while (this->available() != 0) { + this->read_byte(&val); + this->rx_message_.push_back(val); + + // check if rx_message_ has 32 bytes of data + if (this->rx_message_.size() == 32) { + this->parse_data_(); + + if (this->have_good_data_) { + if (this->pm_1_0_sensor_ != nullptr) + this->pm_1_0_sensor_->publish_state(get_32_bit_uint_(1)); + if (this->pm_2_5_sensor_ != nullptr) + this->pm_2_5_sensor_->publish_state(get_32_bit_uint_(5)); + if (this->pm_10_0_sensor_ != nullptr) + this->pm_10_0_sensor_->publish_state(get_32_bit_uint_(9)); + if (this->pmc_0_3_sensor_ != nullptr) + this->pmc_0_3_sensor_->publish_state(get_16_bit_uint_(13)); + if (this->pmc_0_5_sensor_ != nullptr) + this->pmc_0_5_sensor_->publish_state(get_16_bit_uint_(15)); + if (this->pmc_1_0_sensor_ != nullptr) + this->pmc_1_0_sensor_->publish_state(get_16_bit_uint_(17)); + if (this->pmc_2_5_sensor_ != nullptr) + this->pmc_2_5_sensor_->publish_state(get_16_bit_uint_(21)); + if (this->pmc_5_0_sensor_ != nullptr) + this->pmc_5_0_sensor_->publish_state(get_16_bit_uint_(23)); + if (this->pmc_10_0_sensor_ != nullptr) + this->pmc_10_0_sensor_->publish_state(get_16_bit_uint_(25)); + } else { + this->status_set_warning(); + ESP_LOGV(TAG, "Have 32 bytes but not good data. Skipping."); + } + + this->rx_message_.clear(); + } + } +} + +bool GCJA5Component::calculate_checksum_() { + uint8_t crc = 0; + + for (uint8_t i = 1; i < 30; i++) + crc = crc ^ this->rx_message_[i]; + + ESP_LOGVV(TAG, "Checksum packet was (0x%02X), calculated checksum was (0x%02X)", this->rx_message_[30], crc); + + return (crc == this->rx_message_[30]); +} + +uint32_t GCJA5Component::get_32_bit_uint_(uint8_t start_index) { + return (((uint32_t) this->rx_message_[start_index + 3]) << 24) | + (((uint32_t) this->rx_message_[start_index + 2]) << 16) | + (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]); +} + +uint16_t GCJA5Component::get_16_bit_uint_(uint8_t start_index) { + return (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]); +} + +void GCJA5Component::parse_data_() { + ESP_LOGVV(TAG, "GCJA5 Data: "); + for (uint8_t i = 0; i < 32; i++) { + ESP_LOGVV(TAG, " %u: 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", i + 1, BYTE_TO_BINARY(this->rx_message_[i]), + this->rx_message_[i]); + } + + if (this->rx_message_[0] != 0x02 || this->rx_message_[31] != 0x03 || !this->calculate_checksum_()) { + ESP_LOGVV(TAG, "Discarding bad packet - failed checks."); + return; + } else + ESP_LOGVV(TAG, "Good packet found."); + + this->have_good_data_ = true; + uint8_t status = this->rx_message_[29]; + if (!this->first_status_log_) { + this->first_status_log_ = true; + + ESP_LOGI(TAG, "GCJA5 Status"); + ESP_LOGI(TAG, "Overall Status : %i", (status >> 6) & 0x03); + ESP_LOGI(TAG, "PD Status : %i", (status >> 4) & 0x03); + ESP_LOGI(TAG, "LD Status : %i", (status >> 2) & 0x03); + ESP_LOGI(TAG, "Fan Status : %i", (status >> 0) & 0x03); + } +} + +void GCJA5Component::dump_config() { ; } + +} // namespace gcja5 +} // namespace esphome diff --git a/esphome/components/gcja5/gcja5.h b/esphome/components/gcja5/gcja5.h new file mode 100644 index 0000000000..7593c90323 --- /dev/null +++ b/esphome/components/gcja5/gcja5.h @@ -0,0 +1,52 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" + +namespace esphome { +namespace gcja5 { + +class GCJA5Component : public Component, public uart::UARTDevice { + public: + void setup() override; + void dump_config() override; + void loop() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + void set_pm_1_0_sensor(sensor::Sensor *pm_1_0) { pm_1_0_sensor_ = pm_1_0; } + void set_pm_2_5_sensor(sensor::Sensor *pm_2_5) { pm_2_5_sensor_ = pm_2_5; } + void set_pm_10_0_sensor(sensor::Sensor *pm_10_0) { pm_10_0_sensor_ = pm_10_0; } + + void set_pmc_0_3_sensor(sensor::Sensor *pmc_0_3) { pmc_0_3_sensor_ = pmc_0_3; } + void set_pmc_0_5_sensor(sensor::Sensor *pmc_0_5) { pmc_0_5_sensor_ = pmc_0_5; } + void set_pmc_1_0_sensor(sensor::Sensor *pmc_1_0) { pmc_1_0_sensor_ = pmc_1_0; } + void set_pmc_2_5_sensor(sensor::Sensor *pmc_2_5) { pmc_2_5_sensor_ = pmc_2_5; } + void set_pmc_5_0_sensor(sensor::Sensor *pmc_5_0) { pmc_5_0_sensor_ = pmc_5_0; } + void set_pmc_10_0_sensor(sensor::Sensor *pmc_10_0) { pmc_10_0_sensor_ = pmc_10_0; } + + protected: + void parse_data_(); + bool calculate_checksum_(); + + uint32_t get_32_bit_uint_(uint8_t start_index); + uint16_t get_16_bit_uint_(uint8_t start_index); + uint32_t last_transmission_{0}; + std::vector rx_message_; + + bool have_good_data_{false}; + bool first_status_log_{false}; + sensor::Sensor *pm_1_0_sensor_{nullptr}; + sensor::Sensor *pm_2_5_sensor_{nullptr}; + sensor::Sensor *pm_10_0_sensor_{nullptr}; + + sensor::Sensor *pmc_0_3_sensor_{nullptr}; + sensor::Sensor *pmc_0_5_sensor_{nullptr}; + sensor::Sensor *pmc_1_0_sensor_{nullptr}; + sensor::Sensor *pmc_2_5_sensor_{nullptr}; + sensor::Sensor *pmc_5_0_sensor_{nullptr}; + sensor::Sensor *pmc_10_0_sensor_{nullptr}; +}; + +} // namespace gcja5 +} // namespace esphome diff --git a/esphome/components/gcja5/sensor.py b/esphome/components/gcja5/sensor.py new file mode 100644 index 0000000000..5bcdc572ff --- /dev/null +++ b/esphome/components/gcja5/sensor.py @@ -0,0 +1,118 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart, sensor +from esphome.const import ( + CONF_ID, + CONF_PM_1_0, + CONF_PM_2_5, + CONF_PM_10_0, + CONF_PMC_0_5, + CONF_PMC_1_0, + CONF_PMC_2_5, + CONF_PMC_10_0, + UNIT_MICROGRAMS_PER_CUBIC_METER, + ICON_CHEMICAL_WEAPON, + ICON_COUNTER, + DEVICE_CLASS_PM1, + DEVICE_CLASS_PM10, + DEVICE_CLASS_PM25, + STATE_CLASS_MEASUREMENT, +) + +CODEOWNERS = ["@gcormier"] +DEPENDENCIES = ["uart"] + +gcja5_ns = cg.esphome_ns.namespace("gcja5") + +GCJA5Component = gcja5_ns.class_("GCJA5Component", cg.PollingComponent, uart.UARTDevice) + +CONF_PMC_0_3 = "pmc_0_3" +CONF_PMC_5_0 = "pmc_5_0" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(GCJA5Component), + cv.Optional(CONF_PM_1_0): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_CHEMICAL_WEAPON, + accuracy_decimals=2, + device_class=DEVICE_CLASS_PM1, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PM_2_5): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_CHEMICAL_WEAPON, + accuracy_decimals=2, + device_class=DEVICE_CLASS_PM25, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PM_10_0): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_CHEMICAL_WEAPON, + accuracy_decimals=2, + device_class=DEVICE_CLASS_PM10, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_0_3): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_0_5): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_1_0): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_2_5): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_5_0): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PMC_10_0): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_COUNTER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + } +).extend(uart.UART_DEVICE_SCHEMA) +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "gcja5", baud_rate=9600, require_rx=True, parity="EVEN" +) +TYPES = { + CONF_PM_1_0: "set_pm_1_0_sensor", + CONF_PM_2_5: "set_pm_2_5_sensor", + CONF_PM_10_0: "set_pm_10_0_sensor", + CONF_PMC_0_3: "set_pmc_0_3_sensor", + CONF_PMC_0_5: "set_pmc_0_5_sensor", + CONF_PMC_1_0: "set_pmc_1_0_sensor", + CONF_PMC_2_5: "set_pmc_2_5_sensor", + CONF_PMC_5_0: "set_pmc_5_0_sensor", + CONF_PMC_10_0: "set_pmc_10_0_sensor", +} + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + for key, funcName in TYPES.items(): + if key in config: + sens = await sensor.new_sensor(config[key]) + cg.add(getattr(var, funcName)(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 254abe2b01..5c9b83a915 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -228,6 +228,10 @@ uart: baud_rate: 256000 parity: NONE stop_bits: 1 + - id: gcja5_uart + rx_pin: GPIO10 + parity: EVEN + baud_rate: 9600 ota: safe_mode: true @@ -341,6 +345,24 @@ mcp23s17: deviceaddress: 1 sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" + uart_id: gcja5_uart - platform: internal_temperature name: Internal Temperature - platform: ble_client From 5b0b9da0b961c054e15751d3b571d6ef0e7a4125 Mon Sep 17 00:00:00 2001 From: matthias882 <30553262+matthias882@users.noreply.github.com> Date: Thu, 10 Aug 2023 07:05:01 +0200 Subject: [PATCH 0327/2607] Daly BMS improvements (#3388) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Samuel Sieb --- esphome/components/daly_bms/__init__.py | 1 - esphome/components/daly_bms/binary_sensor.py | 5 +- esphome/components/daly_bms/daly_bms.cpp | 241 ++++++++++++------- esphome/components/daly_bms/daly_bms.h | 140 +++++------ esphome/components/daly_bms/sensor.py | 5 +- esphome/components/daly_bms/text_sensor.py | 5 +- 6 files changed, 217 insertions(+), 180 deletions(-) diff --git a/esphome/components/daly_bms/__init__.py b/esphome/components/daly_bms/__init__.py index ce0cf5216a..2cc2c512f3 100644 --- a/esphome/components/daly_bms/__init__.py +++ b/esphome/components/daly_bms/__init__.py @@ -5,7 +5,6 @@ from esphome.const import CONF_ID, CONF_ADDRESS CODEOWNERS = ["@s1lvi0"] DEPENDENCIES = ["uart"] -AUTO_LOAD = ["sensor", "text_sensor", "binary_sensor"] CONF_BMS_DALY_ID = "bms_daly_id" diff --git a/esphome/components/daly_bms/binary_sensor.py b/esphome/components/daly_bms/binary_sensor.py index 7b252b5e89..724f19315b 100644 --- a/esphome/components/daly_bms/binary_sensor.py +++ b/esphome/components/daly_bms/binary_sensor.py @@ -27,9 +27,8 @@ CONFIG_SCHEMA = cv.All( async def setup_conf(config, key, hub): - if key in config: - conf = config[key] - var = await binary_sensor.new_binary_sensor(conf) + if sensor_config := config.get(key): + var = await binary_sensor.new_binary_sensor(sensor_config) cg.add(getattr(hub, f"set_{key}_binary_sensor")(var)) diff --git a/esphome/components/daly_bms/daly_bms.cpp b/esphome/components/daly_bms/daly_bms.cpp index 3b41723327..8f6fc0fb57 100644 --- a/esphome/components/daly_bms/daly_bms.cpp +++ b/esphome/components/daly_bms/daly_bms.cpp @@ -1,6 +1,6 @@ #include "daly_bms.h" -#include "esphome/core/log.h" #include +#include "esphome/core/log.h" namespace esphome { namespace daly_bms { @@ -19,7 +19,7 @@ static const uint8_t DALY_REQUEST_STATUS = 0x94; static const uint8_t DALY_REQUEST_CELL_VOLTAGE = 0x95; static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96; -void DalyBmsComponent::setup() {} +void DalyBmsComponent::setup() { this->next_request_ = 1; } void DalyBmsComponent::dump_config() { ESP_LOGCONFIG(TAG, "Daly BMS:"); @@ -27,20 +27,78 @@ void DalyBmsComponent::dump_config() { } void DalyBmsComponent::update() { - this->request_data_(DALY_REQUEST_BATTERY_LEVEL); - this->request_data_(DALY_REQUEST_MIN_MAX_VOLTAGE); - this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE); - this->request_data_(DALY_REQUEST_MOS); - this->request_data_(DALY_REQUEST_STATUS); - this->request_data_(DALY_REQUEST_CELL_VOLTAGE); - this->request_data_(DALY_REQUEST_TEMPERATURE); + this->trigger_next_ = true; + this->next_request_ = 0; +} - std::vector get_battery_level_data; - int available_data = this->available(); - if (available_data >= DALY_FRAME_SIZE) { - get_battery_level_data.resize(available_data); - this->read_array(get_battery_level_data.data(), available_data); - this->decode_data_(get_battery_level_data); +void DalyBmsComponent::loop() { + const uint32_t now = millis(); + if (this->receiving_ && (now - this->last_transmission_ >= 200)) { + // last transmission too long ago. Reset RX index. + ESP_LOGW(TAG, "Last transmission too long ago. Reset RX index."); + this->data_.clear(); + this->receiving_ = false; + } + if ((now - this->last_transmission_ >= 250) && !this->trigger_next_) { + // last transmittion longer than 0.25s ago -> trigger next request + this->last_transmission_ = now; + this->trigger_next_ = true; + } + if (available()) + this->last_transmission_ = now; + while (available()) { + uint8_t c; + read_byte(&c); + if (!this->receiving_) { + if (c != 0xa5) + continue; + this->receiving_ = true; + } + this->data_.push_back(c); + if (this->data_.size() == 4) + this->data_count_ = c; + if ((this->data_.size() > 4) and (data_.size() == this->data_count_ + 5)) { + this->decode_data_(this->data_); + this->data_.clear(); + this->receiving_ = false; + } + } + + if (this->trigger_next_) { + this->trigger_next_ = false; + switch (this->next_request_) { + case 0: + this->request_data_(DALY_REQUEST_BATTERY_LEVEL); + this->next_request_ = 1; + break; + case 1: + this->request_data_(DALY_REQUEST_MIN_MAX_VOLTAGE); + this->next_request_ = 2; + break; + case 2: + this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE); + this->next_request_ = 3; + break; + case 3: + this->request_data_(DALY_REQUEST_MOS); + this->next_request_ = 4; + break; + case 4: + this->request_data_(DALY_REQUEST_STATUS); + this->next_request_ = 5; + break; + case 5: + this->request_data_(DALY_REQUEST_CELL_VOLTAGE); + this->next_request_ = 6; + break; + case 6: + this->request_data_(DALY_REQUEST_TEMPERATURE); + this->next_request_ = 7; + break; + case 7: + default: + break; + } } } @@ -49,21 +107,23 @@ float DalyBmsComponent::get_setup_priority() const { return setup_priority::DATA void DalyBmsComponent::request_data_(uint8_t data_id) { uint8_t request_message[DALY_FRAME_SIZE]; - request_message[0] = 0xA5; // Start Flag - request_message[1] = addr_; // Communication Module Address - request_message[2] = data_id; // Data ID - request_message[3] = 0x08; // Data Length (Fixed) - request_message[4] = 0x00; // Empty Data - request_message[5] = 0x00; // | - request_message[6] = 0x00; // | - request_message[7] = 0x00; // | - request_message[8] = 0x00; // | - request_message[9] = 0x00; // | - request_message[10] = 0x00; // | - request_message[11] = 0x00; // Empty Data + request_message[0] = 0xA5; // Start Flag + request_message[1] = this->addr_; // Communication Module Address + request_message[2] = data_id; // Data ID + request_message[3] = 0x08; // Data Length (Fixed) + request_message[4] = 0x00; // Empty Data + request_message[5] = 0x00; // | + request_message[6] = 0x00; // | + request_message[7] = 0x00; // | + request_message[8] = 0x00; // | + request_message[9] = 0x00; // | + request_message[10] = 0x00; // | + request_message[11] = 0x00; // Empty Data + request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] + request_message[3]); // Checksum (Lower byte of the other bytes sum) + ESP_LOGV(TAG, "Request datapacket Nr %x", data_id); this->write_array(request_message, sizeof(request_message)); this->flush(); } @@ -82,6 +142,7 @@ void DalyBmsComponent::decode_data_(std::vector data) { if (checksum == it[12]) { switch (it[2]) { +#ifdef USE_SENSOR case DALY_REQUEST_BATTERY_LEVEL: if (this->voltage_sensor_) { this->voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 10); @@ -95,36 +156,37 @@ void DalyBmsComponent::decode_data_(std::vector data) { break; case DALY_REQUEST_MIN_MAX_VOLTAGE: - if (this->max_cell_voltage_) { - this->max_cell_voltage_->publish_state((float) encode_uint16(it[4], it[5]) / 1000); + if (this->max_cell_voltage_sensor_) { + this->max_cell_voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 1000); } - if (this->max_cell_voltage_number_) { - this->max_cell_voltage_number_->publish_state(it[6]); + if (this->max_cell_voltage_number_sensor_) { + this->max_cell_voltage_number_sensor_->publish_state(it[6]); } - if (this->min_cell_voltage_) { - this->min_cell_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->min_cell_voltage_sensor_) { + this->min_cell_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->min_cell_voltage_number_) { - this->min_cell_voltage_number_->publish_state(it[9]); + if (this->min_cell_voltage_number_sensor_) { + this->min_cell_voltage_number_sensor_->publish_state(it[9]); } break; case DALY_REQUEST_MIN_MAX_TEMPERATURE: - if (this->max_temperature_) { - this->max_temperature_->publish_state(it[4] - DALY_TEMPERATURE_OFFSET); + if (this->max_temperature_sensor_) { + this->max_temperature_sensor_->publish_state(it[4] - DALY_TEMPERATURE_OFFSET); } - if (this->max_temperature_probe_number_) { - this->max_temperature_probe_number_->publish_state(it[5]); + if (this->max_temperature_probe_number_sensor_) { + this->max_temperature_probe_number_sensor_->publish_state(it[5]); } - if (this->min_temperature_) { - this->min_temperature_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET); + if (this->min_temperature_sensor_) { + this->min_temperature_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET); } - if (this->min_temperature_probe_number_) { - this->min_temperature_probe_number_->publish_state(it[7]); + if (this->min_temperature_probe_number_sensor_) { + this->min_temperature_probe_number_sensor_->publish_state(it[7]); } break; - +#endif case DALY_REQUEST_MOS: +#ifdef USE_TEXT_SENSOR if (this->status_text_sensor_ != nullptr) { switch (it[4]) { case 0: @@ -140,20 +202,27 @@ void DalyBmsComponent::decode_data_(std::vector data) { break; } } - if (this->charging_mos_enabled_) { - this->charging_mos_enabled_->publish_state(it[5]); +#endif +#ifdef USE_BINARY_SENSOR + if (this->charging_mos_enabled_binary_sensor_) { + this->charging_mos_enabled_binary_sensor_->publish_state(it[5]); } - if (this->discharging_mos_enabled_) { - this->discharging_mos_enabled_->publish_state(it[6]); + if (this->discharging_mos_enabled_binary_sensor_) { + this->discharging_mos_enabled_binary_sensor_->publish_state(it[6]); } - if (this->remaining_capacity_) { - this->remaining_capacity_->publish_state((float) encode_uint32(it[8], it[9], it[10], it[11]) / 1000); +#endif +#ifdef USE_SENSOR + if (this->remaining_capacity_sensor_) { + this->remaining_capacity_sensor_->publish_state((float) encode_uint32(it[8], it[9], it[10], it[11]) / + 1000); } +#endif break; +#ifdef USE_SENSOR case DALY_REQUEST_STATUS: - if (this->cells_number_) { - this->cells_number_->publish_state(it[4]); + if (this->cells_number_sensor_) { + this->cells_number_sensor_->publish_state(it[4]); } break; @@ -171,71 +240,73 @@ void DalyBmsComponent::decode_data_(std::vector data) { case DALY_REQUEST_CELL_VOLTAGE: switch (it[4]) { case 1: - if (this->cell_1_voltage_) { - this->cell_1_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_1_voltage_sensor_) { + this->cell_1_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } - if (this->cell_2_voltage_) { - this->cell_2_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->cell_2_voltage_sensor_) { + this->cell_2_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->cell_3_voltage_) { - this->cell_3_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); + if (this->cell_3_voltage_sensor_) { + this->cell_3_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); } break; case 2: - if (this->cell_4_voltage_) { - this->cell_4_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_4_voltage_sensor_) { + this->cell_4_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } - if (this->cell_5_voltage_) { - this->cell_5_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->cell_5_voltage_sensor_) { + this->cell_5_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->cell_6_voltage_) { - this->cell_6_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); + if (this->cell_6_voltage_sensor_) { + this->cell_6_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); } break; case 3: - if (this->cell_7_voltage_) { - this->cell_7_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_7_voltage_sensor_) { + this->cell_7_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } - if (this->cell_8_voltage_) { - this->cell_8_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->cell_8_voltage_sensor_) { + this->cell_8_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->cell_9_voltage_) { - this->cell_9_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); + if (this->cell_9_voltage_sensor_) { + this->cell_9_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); } break; case 4: - if (this->cell_10_voltage_) { - this->cell_10_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_10_voltage_sensor_) { + this->cell_10_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } - if (this->cell_11_voltage_) { - this->cell_11_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->cell_11_voltage_sensor_) { + this->cell_11_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->cell_12_voltage_) { - this->cell_12_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); + if (this->cell_12_voltage_sensor_) { + this->cell_12_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); } break; case 5: - if (this->cell_13_voltage_) { - this->cell_13_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_13_voltage_sensor_) { + this->cell_13_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } - if (this->cell_14_voltage_) { - this->cell_14_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + if (this->cell_14_voltage_sensor_) { + this->cell_14_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); } - if (this->cell_15_voltage_) { - this->cell_15_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); + if (this->cell_15_voltage_sensor_) { + this->cell_15_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000); } break; case 6: - if (this->cell_16_voltage_) { - this->cell_16_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); + if (this->cell_16_voltage_sensor_) { + this->cell_16_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); } break; } break; - +#endif default: break; } + } else { + ESP_LOGW(TAG, "Checksum-Error on Packet %x", it[4]); } std::advance(it, DALY_FRAME_SIZE); } else { diff --git a/esphome/components/daly_bms/daly_bms.h b/esphome/components/daly_bms/daly_bms.h index d4fe84fe46..52ea30ecde 100644 --- a/esphome/components/daly_bms/daly_bms.h +++ b/esphome/components/daly_bms/daly_bms.h @@ -1,9 +1,16 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_TEXT_SENSOR #include "esphome/components/text_sensor/text_sensor.h" +#endif +#ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" +#endif #include "esphome/components/uart/uart.h" #include @@ -15,60 +22,53 @@ class DalyBmsComponent : public PollingComponent, public uart::UARTDevice { public: DalyBmsComponent() = default; - // SENSORS - void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } - void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; } - void set_battery_level_sensor(sensor::Sensor *battery_level_sensor) { battery_level_sensor_ = battery_level_sensor; } - void set_max_cell_voltage_sensor(sensor::Sensor *max_cell_voltage) { max_cell_voltage_ = max_cell_voltage; } - void set_max_cell_voltage_number_sensor(sensor::Sensor *max_cell_voltage_number) { - max_cell_voltage_number_ = max_cell_voltage_number; - } - void set_min_cell_voltage_sensor(sensor::Sensor *min_cell_voltage) { min_cell_voltage_ = min_cell_voltage; } - void set_min_cell_voltage_number_sensor(sensor::Sensor *min_cell_voltage_number) { - min_cell_voltage_number_ = min_cell_voltage_number; - } - void set_max_temperature_sensor(sensor::Sensor *max_temperature) { max_temperature_ = max_temperature; } - void set_max_temperature_probe_number_sensor(sensor::Sensor *max_temperature_probe_number) { - max_temperature_probe_number_ = max_temperature_probe_number; - } - void set_min_temperature_sensor(sensor::Sensor *min_temperature) { min_temperature_ = min_temperature; } - void set_min_temperature_probe_number_sensor(sensor::Sensor *min_temperature_probe_number) { - min_temperature_probe_number_ = min_temperature_probe_number; - } - void set_remaining_capacity_sensor(sensor::Sensor *remaining_capacity) { remaining_capacity_ = remaining_capacity; } - void set_cells_number_sensor(sensor::Sensor *cells_number) { cells_number_ = cells_number; } - void set_temperature_1_sensor(sensor::Sensor *temperature_1_sensor) { temperature_1_sensor_ = temperature_1_sensor; } - void set_temperature_2_sensor(sensor::Sensor *temperature_2_sensor) { temperature_2_sensor_ = temperature_2_sensor; } - void set_cell_1_voltage_sensor(sensor::Sensor *cell_1_voltage) { cell_1_voltage_ = cell_1_voltage; } - void set_cell_2_voltage_sensor(sensor::Sensor *cell_2_voltage) { cell_2_voltage_ = cell_2_voltage; } - void set_cell_3_voltage_sensor(sensor::Sensor *cell_3_voltage) { cell_3_voltage_ = cell_3_voltage; } - void set_cell_4_voltage_sensor(sensor::Sensor *cell_4_voltage) { cell_4_voltage_ = cell_4_voltage; } - void set_cell_5_voltage_sensor(sensor::Sensor *cell_5_voltage) { cell_5_voltage_ = cell_5_voltage; } - void set_cell_6_voltage_sensor(sensor::Sensor *cell_6_voltage) { cell_6_voltage_ = cell_6_voltage; } - void set_cell_7_voltage_sensor(sensor::Sensor *cell_7_voltage) { cell_7_voltage_ = cell_7_voltage; } - void set_cell_8_voltage_sensor(sensor::Sensor *cell_8_voltage) { cell_8_voltage_ = cell_8_voltage; } - void set_cell_9_voltage_sensor(sensor::Sensor *cell_9_voltage) { cell_9_voltage_ = cell_9_voltage; } - void set_cell_10_voltage_sensor(sensor::Sensor *cell_10_voltage) { cell_10_voltage_ = cell_10_voltage; } - void set_cell_11_voltage_sensor(sensor::Sensor *cell_11_voltage) { cell_11_voltage_ = cell_11_voltage; } - void set_cell_12_voltage_sensor(sensor::Sensor *cell_12_voltage) { cell_12_voltage_ = cell_12_voltage; } - void set_cell_13_voltage_sensor(sensor::Sensor *cell_13_voltage) { cell_13_voltage_ = cell_13_voltage; } - void set_cell_14_voltage_sensor(sensor::Sensor *cell_14_voltage) { cell_14_voltage_ = cell_14_voltage; } - void set_cell_15_voltage_sensor(sensor::Sensor *cell_15_voltage) { cell_15_voltage_ = cell_15_voltage; } - void set_cell_16_voltage_sensor(sensor::Sensor *cell_16_voltage) { cell_16_voltage_ = cell_16_voltage; } +#ifdef USE_SENSOR + SUB_SENSOR(voltage) + SUB_SENSOR(current) + SUB_SENSOR(battery_level) + SUB_SENSOR(max_cell_voltage) + SUB_SENSOR(max_cell_voltage_number) + SUB_SENSOR(min_cell_voltage) + SUB_SENSOR(min_cell_voltage_number) + SUB_SENSOR(max_temperature) + SUB_SENSOR(max_temperature_probe_number) + SUB_SENSOR(min_temperature) + SUB_SENSOR(min_temperature_probe_number) + SUB_SENSOR(remaining_capacity) + SUB_SENSOR(cells_number) + SUB_SENSOR(temperature_1) + SUB_SENSOR(temperature_2) + SUB_SENSOR(cell_1_voltage) + SUB_SENSOR(cell_2_voltage) + SUB_SENSOR(cell_3_voltage) + SUB_SENSOR(cell_4_voltage) + SUB_SENSOR(cell_5_voltage) + SUB_SENSOR(cell_6_voltage) + SUB_SENSOR(cell_7_voltage) + SUB_SENSOR(cell_8_voltage) + SUB_SENSOR(cell_9_voltage) + SUB_SENSOR(cell_10_voltage) + SUB_SENSOR(cell_11_voltage) + SUB_SENSOR(cell_12_voltage) + SUB_SENSOR(cell_13_voltage) + SUB_SENSOR(cell_14_voltage) + SUB_SENSOR(cell_15_voltage) + SUB_SENSOR(cell_16_voltage) +#endif - // TEXT_SENSORS - void set_status_text_sensor(text_sensor::TextSensor *status_text_sensor) { status_text_sensor_ = status_text_sensor; } - // BINARY_SENSORS - void set_charging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *charging_mos_enabled) { - charging_mos_enabled_ = charging_mos_enabled; - } - void set_discharging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *discharging_mos_enabled) { - discharging_mos_enabled_ = discharging_mos_enabled; - } +#ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(status) +#endif + +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(charging_mos_enabled) + SUB_BINARY_SENSOR(discharging_mos_enabled) +#endif void setup() override; void dump_config() override; void update() override; + void loop() override; float get_setup_priority() const override; void set_address(uint8_t address) { this->addr_ = address; } @@ -79,42 +79,12 @@ class DalyBmsComponent : public PollingComponent, public uart::UARTDevice { uint8_t addr_; - sensor::Sensor *voltage_sensor_{nullptr}; - sensor::Sensor *current_sensor_{nullptr}; - sensor::Sensor *battery_level_sensor_{nullptr}; - sensor::Sensor *max_cell_voltage_{nullptr}; - sensor::Sensor *max_cell_voltage_number_{nullptr}; - sensor::Sensor *min_cell_voltage_{nullptr}; - sensor::Sensor *min_cell_voltage_number_{nullptr}; - sensor::Sensor *max_temperature_{nullptr}; - sensor::Sensor *max_temperature_probe_number_{nullptr}; - sensor::Sensor *min_temperature_{nullptr}; - sensor::Sensor *min_temperature_probe_number_{nullptr}; - sensor::Sensor *remaining_capacity_{nullptr}; - sensor::Sensor *cells_number_{nullptr}; - sensor::Sensor *temperature_1_sensor_{nullptr}; - sensor::Sensor *temperature_2_sensor_{nullptr}; - sensor::Sensor *cell_1_voltage_{nullptr}; - sensor::Sensor *cell_2_voltage_{nullptr}; - sensor::Sensor *cell_3_voltage_{nullptr}; - sensor::Sensor *cell_4_voltage_{nullptr}; - sensor::Sensor *cell_5_voltage_{nullptr}; - sensor::Sensor *cell_6_voltage_{nullptr}; - sensor::Sensor *cell_7_voltage_{nullptr}; - sensor::Sensor *cell_8_voltage_{nullptr}; - sensor::Sensor *cell_9_voltage_{nullptr}; - sensor::Sensor *cell_10_voltage_{nullptr}; - sensor::Sensor *cell_11_voltage_{nullptr}; - sensor::Sensor *cell_12_voltage_{nullptr}; - sensor::Sensor *cell_13_voltage_{nullptr}; - sensor::Sensor *cell_14_voltage_{nullptr}; - sensor::Sensor *cell_15_voltage_{nullptr}; - sensor::Sensor *cell_16_voltage_{nullptr}; - - text_sensor::TextSensor *status_text_sensor_{nullptr}; - - binary_sensor::BinarySensor *charging_mos_enabled_{nullptr}; - binary_sensor::BinarySensor *discharging_mos_enabled_{nullptr}; + std::vector data_; + bool receiving_{false}; + uint8_t data_count_; + uint32_t last_transmission_{0}; + bool trigger_next_; + uint8_t next_request_; }; } // namespace daly_bms diff --git a/esphome/components/daly_bms/sensor.py b/esphome/components/daly_bms/sensor.py index 2274a2153a..c447fbd8a2 100644 --- a/esphome/components/daly_bms/sensor.py +++ b/esphome/components/daly_bms/sensor.py @@ -218,9 +218,8 @@ CONFIG_SCHEMA = cv.All( async def setup_conf(config, key, hub): - if key in config: - conf = config[key] - sens = await sensor.new_sensor(conf) + if sensor_config := config.get(key): + sens = await sensor.new_sensor(sensor_config) cg.add(getattr(hub, f"set_{key}_sensor")(sens)) diff --git a/esphome/components/daly_bms/text_sensor.py b/esphome/components/daly_bms/text_sensor.py index 9f23e5f373..fcd5ee531b 100644 --- a/esphome/components/daly_bms/text_sensor.py +++ b/esphome/components/daly_bms/text_sensor.py @@ -23,9 +23,8 @@ CONFIG_SCHEMA = cv.All( async def setup_conf(config, key, hub): - if key in config: - conf = config[key] - sens = await text_sensor.new_text_sensor(conf) + if sensor_config := config.get(key): + sens = await text_sensor.new_text_sensor(sensor_config) cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) From f457269a68d1353ef3c822bd0d66dcbe591b8dcb Mon Sep 17 00:00:00 2001 From: Francesco Ciocchetti <2085772+primeroz@users.noreply.github.com> Date: Thu, 10 Aug 2023 07:09:21 +0200 Subject: [PATCH 0328/2607] Add missing `on_(arming|pending|armed_home|armed_night|armed_away|disarmed)` triggers to alarm_control_panel (#5219) --- .../alarm_control_panel/__init__.py | 72 +++++++++++++++++++ .../alarm_control_panel.cpp | 37 ++++++++++ .../alarm_control_panel/alarm_control_panel.h | 48 +++++++++++++ .../alarm_control_panel/automation.h | 42 +++++++++++ tests/test3.yaml | 39 ++++++++++ 5 files changed, 238 insertions(+) diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 52f8ac7894..d9cafb4f30 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -16,6 +16,12 @@ IS_PLATFORM_COMPONENT = True CONF_ON_TRIGGERED = "on_triggered" CONF_ON_CLEARED = "on_cleared" +CONF_ON_ARMING = "on_arming" +CONF_ON_PENDING = "on_pending" +CONF_ON_ARMED_HOME = "on_armed_home" +CONF_ON_ARMED_NIGHT = "on_armed_night" +CONF_ON_ARMED_AWAY = "on_armed_away" +CONF_ON_DISARMED = "on_disarmed" alarm_control_panel_ns = cg.esphome_ns.namespace("alarm_control_panel") AlarmControlPanel = alarm_control_panel_ns.class_("AlarmControlPanel", cg.EntityBase) @@ -29,6 +35,24 @@ TriggeredTrigger = alarm_control_panel_ns.class_( ClearedTrigger = alarm_control_panel_ns.class_( "ClearedTrigger", automation.Trigger.template() ) +ArmingTrigger = alarm_control_panel_ns.class_( + "ArmingTrigger", automation.Trigger.template() +) +PendingTrigger = alarm_control_panel_ns.class_( + "PendingTrigger", automation.Trigger.template() +) +ArmedHomeTrigger = alarm_control_panel_ns.class_( + "ArmedHomeTrigger", automation.Trigger.template() +) +ArmedNightTrigger = alarm_control_panel_ns.class_( + "ArmedNightTrigger", automation.Trigger.template() +) +ArmedAwayTrigger = alarm_control_panel_ns.class_( + "ArmedAwayTrigger", automation.Trigger.template() +) +DisarmedTrigger = alarm_control_panel_ns.class_( + "DisarmedTrigger", automation.Trigger.template() +) ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) ArmNightAction = alarm_control_panel_ns.class_("ArmNightAction", automation.Action) @@ -52,6 +76,36 @@ ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger), } ), + cv.Optional(CONF_ON_ARMING): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger), + } + ), + cv.Optional(CONF_ON_PENDING): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger), + } + ), + cv.Optional(CONF_ON_DISARMED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger), + } + ), cv.Optional(CONF_ON_CLEARED): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger), @@ -82,6 +136,24 @@ async def setup_alarm_control_panel_core_(var, config): for conf in config.get(CONF_ON_TRIGGERED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ARMING, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_PENDING, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ARMED_HOME, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ARMED_NIGHT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ARMED_AWAY, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_DISARMED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_CLEARED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/alarm_control_panel/alarm_control_panel.cpp b/esphome/components/alarm_control_panel/alarm_control_panel.cpp index 74c9a502df..9dc083c004 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel.cpp +++ b/esphome/components/alarm_control_panel/alarm_control_panel.cpp @@ -36,7 +36,20 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) { this->state_callback_.call(); if (state == ACP_STATE_TRIGGERED) { this->triggered_callback_.call(); + } else if (state == ACP_STATE_ARMING) { + this->arming_callback_.call(); + } else if (state == ACP_STATE_PENDING) { + this->pending_callback_.call(); + } else if (state == ACP_STATE_ARMED_HOME) { + this->armed_home_callback_.call(); + } else if (state == ACP_STATE_ARMED_NIGHT) { + this->armed_night_callback_.call(); + } else if (state == ACP_STATE_ARMED_AWAY) { + this->armed_away_callback_.call(); + } else if (state == ACP_STATE_DISARMED) { + this->disarmed_callback_.call(); } + if (prev_state == ACP_STATE_TRIGGERED) { this->cleared_callback_.call(); } @@ -55,6 +68,30 @@ void AlarmControlPanel::add_on_triggered_callback(std::function &&callba this->triggered_callback_.add(std::move(callback)); } +void AlarmControlPanel::add_on_arming_callback(std::function &&callback) { + this->arming_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_armed_home_callback(std::function &&callback) { + this->armed_home_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_armed_night_callback(std::function &&callback) { + this->armed_night_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_armed_away_callback(std::function &&callback) { + this->armed_away_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_pending_callback(std::function &&callback) { + this->pending_callback_.add(std::move(callback)); +} + +void AlarmControlPanel::add_on_disarmed_callback(std::function &&callback) { + this->disarmed_callback_.add(std::move(callback)); +} + void AlarmControlPanel::add_on_cleared_callback(std::function &&callback) { this->cleared_callback_.add(std::move(callback)); } diff --git a/esphome/components/alarm_control_panel/alarm_control_panel.h b/esphome/components/alarm_control_panel/alarm_control_panel.h index 4f15ccb45a..dc0b92df76 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel.h +++ b/esphome/components/alarm_control_panel/alarm_control_panel.h @@ -47,6 +47,42 @@ class AlarmControlPanel : public EntityBase { */ void add_on_triggered_callback(std::function &&callback); + /** Add a callback for when the state of the alarm_control_panel chanes to arming + * + * @param callback The callback function + */ + void add_on_arming_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel changes to pending + * + * @param callback The callback function + */ + void add_on_pending_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel changes to armed_home + * + * @param callback The callback function + */ + void add_on_armed_home_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel changes to armed_night + * + * @param callback The callback function + */ + void add_on_armed_night_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel changes to armed_away + * + * @param callback The callback function + */ + void add_on_armed_away_callback(std::function &&callback); + + /** Add a callback for when the state of the alarm_control_panel changes to disarmed + * + * @param callback The callback function + */ + void add_on_disarmed_callback(std::function &&callback); + /** Add a callback for when the state of the alarm_control_panel clears from triggered * * @param callback The callback function @@ -128,6 +164,18 @@ class AlarmControlPanel : public EntityBase { CallbackManager state_callback_{}; // trigger callback CallbackManager triggered_callback_{}; + // arming callback + CallbackManager arming_callback_{}; + // pending callback + CallbackManager pending_callback_{}; + // armed_home callback + CallbackManager armed_home_callback_{}; + // armed_night callback + CallbackManager armed_night_callback_{}; + // armed_away callback + CallbackManager armed_away_callback_{}; + // disarmed callback + CallbackManager disarmed_callback_{}; // clear callback CallbackManager cleared_callback_{}; }; diff --git a/esphome/components/alarm_control_panel/automation.h b/esphome/components/alarm_control_panel/automation.h index 81ac584f71..8538020c53 100644 --- a/esphome/components/alarm_control_panel/automation.h +++ b/esphome/components/alarm_control_panel/automation.h @@ -20,6 +20,48 @@ class TriggeredTrigger : public Trigger<> { } }; +class ArmingTrigger : public Trigger<> { + public: + explicit ArmingTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_arming_callback([this]() { this->trigger(); }); + } +}; + +class PendingTrigger : public Trigger<> { + public: + explicit PendingTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_pending_callback([this]() { this->trigger(); }); + } +}; + +class ArmedHomeTrigger : public Trigger<> { + public: + explicit ArmedHomeTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_armed_home_callback([this]() { this->trigger(); }); + } +}; + +class ArmedNightTrigger : public Trigger<> { + public: + explicit ArmedNightTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_armed_night_callback([this]() { this->trigger(); }); + } +}; + +class ArmedAwayTrigger : public Trigger<> { + public: + explicit ArmedAwayTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_armed_away_callback([this]() { this->trigger(); }); + } +}; + +class DisarmedTrigger : public Trigger<> { + public: + explicit DisarmedTrigger(AlarmControlPanel *alarm_control_panel) { + alarm_control_panel->add_on_disarmed_callback([this]() { this->trigger(); }); + } +}; + class ClearedTrigger : public Trigger<> { public: explicit ClearedTrigger(AlarmControlPanel *alarm_control_panel) { diff --git a/tests/test3.yaml b/tests/test3.yaml index 3ab1d561b3..5bda0afb1b 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -1206,3 +1206,42 @@ alarm_control_panel: then: - lambda: !lambda |- ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); + - platform: template + id: alarmcontrolpanel2 + name: Alarm Panel + codes: + - "1234" + requires_code_to_arm: true + arming_home_time: 1s + arming_night_time: 1s + arming_away_time: 15s + pending_time: 15s + trigger_time: 30s + binary_sensors: + - input: bin1 + bypass_armed_home: true + bypass_armed_night: true + on_disarmed: + then: + - logger.log: "### DISARMED ###" + on_pending: + then: + - logger.log: "### PENDING ###" + on_arming: + then: + - logger.log: "### ARMING ###" + on_armed_home: + then: + - logger.log: "### ARMED HOME ###" + on_armed_night: + then: + - logger.log: "### ARMED NIGHT ###" + on_armed_away: + then: + - logger.log: "### ARMED AWAY ###" + on_triggered: + then: + - logger.log: "### TRIGGERED ###" + on_cleared: + then: + - logger.log: "### CLEARED ###" From b56c606523c1e34ade52ac0117aa42167ad02be4 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 9 Aug 2023 22:11:03 -0700 Subject: [PATCH 0329/2607] add value option to timeout filter (#5222) Co-authored-by: Samuel Sieb --- esphome/components/sensor/__init__.py | 14 +++++++++++--- esphome/components/sensor/filter.cpp | 4 ++-- esphome/components/sensor/filter.h | 4 +++- tests/test3.1.yaml | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index bbcc730943..8f7d581b2d 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -23,6 +23,7 @@ from esphome.const import ( CONF_SEND_EVERY, CONF_SEND_FIRST_AT, CONF_STATE_CLASS, + CONF_TIMEOUT, CONF_TO, CONF_TRIGGER_ID, CONF_TYPE, @@ -543,11 +544,18 @@ async def heartbeat_filter_to_code(config, filter_id): return var -@FILTER_REGISTRY.register( - "timeout", TimeoutFilter, cv.positive_time_period_milliseconds +TIMEOUT_SCHEMA = cv.maybe_simple_value( + { + cv.Required(CONF_TIMEOUT): cv.positive_time_period_milliseconds, + cv.Optional(CONF_VALUE, default="nan"): cv.float_, + }, + key=CONF_TIMEOUT, ) + + +@FILTER_REGISTRY.register("timeout", TimeoutFilter, TIMEOUT_SCHEMA) async def timeout_filter_to_code(config, filter_id): - var = cg.new_Pvariable(filter_id, config) + var = cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], config[CONF_VALUE]) await cg.register_component(var, {}) return var diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index cd5ab5f9cd..6323023d50 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -375,13 +375,13 @@ void OrFilter::initialize(Sensor *parent, Filter *next) { // TimeoutFilter optional TimeoutFilter::new_value(float value) { - this->set_timeout("timeout", this->time_period_, [this]() { this->output(NAN); }); + this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_); }); this->output(value); return {}; } -TimeoutFilter::TimeoutFilter(uint32_t time_period) : time_period_(time_period) {} +TimeoutFilter::TimeoutFilter(uint32_t time_period, float new_value) : time_period_(time_period), value_(new_value) {} float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; } // DebounceFilter diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 0141b73267..46aeefac56 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -315,7 +315,8 @@ class ThrottleFilter : public Filter { class TimeoutFilter : public Filter, public Component { public: - explicit TimeoutFilter(uint32_t time_period); + explicit TimeoutFilter(uint32_t time_period, float new_value); + void set_value(float new_value) { this->value_ = new_value; } optional new_value(float value) override; @@ -323,6 +324,7 @@ class TimeoutFilter : public Filter, public Component { protected: uint32_t time_period_; + float value_; }; class DebounceFilter : public Filter, public Component { diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 42c1e1e1ab..46bc014204 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -87,6 +87,9 @@ sensor: - throttle: 100ms - debounce: 500s - timeout: 10min + - timeout: + timeout: 10min + value: 0 - calibrate_linear: method: exact datapoints: From 8e7e8da4a3dada0761b4b90e33f5535878cb599e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 10 Aug 2023 00:11:57 -0500 Subject: [PATCH 0330/2607] Tweak Color init because IDF 5+ (#5221) --- esphome/components/color/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 9a85eace75..4a55beef38 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -82,5 +82,5 @@ async def to_code(config): cg.new_variable( config[CONF_ID], - cg.StructInitializer(ColorStruct, ("r", r), ("g", g), ("b", b), ("w", w)), + cg.ArrayInitializer(r, g, b, w), ) From 02ed2c0ebeaa975e1d869b05f1b0fd669e02e5b7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 10 Aug 2023 17:30:26 +1200 Subject: [PATCH 0331/2607] Bump version to 2023.8.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4977726361..6b442dd633 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0-dev" +__version__ = "2023.8.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From db9dc110220cdd54f7da42de61a1bdf371698655 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 10 Aug 2023 17:30:26 +1200 Subject: [PATCH 0332/2607] Bump version to 2023.9.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4977726361..373d6bd8c9 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0-dev" +__version__ = "2023.9.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 72e72d7d4b4556876817a0e4af5eef6536eb1c89 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:40:13 +1200 Subject: [PATCH 0333/2607] Fix duplicate --- esphome/components/sensor/__init__.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index c8cd2f9f7f..8f7d581b2d 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -560,15 +560,6 @@ async def timeout_filter_to_code(config, filter_id): return var -@FILTER_REGISTRY.register( - "timeout", TimeoutFilter, cv.positive_time_period_milliseconds -) -async def timeout_filter_to_code(config, filter_id): - var = cg.new_Pvariable(filter_id, config) - await cg.register_component(var, {}) - return var - - @FILTER_REGISTRY.register( "debounce", DebounceFilter, cv.positive_time_period_milliseconds ) From a84365659bb56f0ea9dbe61ba69914c579bda6a6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:20:58 +1200 Subject: [PATCH 0334/2607] Read string of bool env and match against well known values (#5232) --- esphome/helpers.py | 9 ++++++++- tests/unit_tests/test_helpers.py | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/helpers.py b/esphome/helpers.py index fd8893ad99..4012b2067f 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -144,7 +144,14 @@ def resolve_ip_address(host): def get_bool_env(var, default=False): - return bool(os.getenv(var, default)) + value = os.getenv(var, default) + if isinstance(value, str): + value = value.lower() + if value in ["1", "true"]: + return True + if value in ["0", "false"]: + return False + return bool(value) def get_str_env(var, default=None): diff --git a/tests/unit_tests/test_helpers.py b/tests/unit_tests/test_helpers.py index b98838024f..67fabd7af8 100644 --- a/tests/unit_tests/test_helpers.py +++ b/tests/unit_tests/test_helpers.py @@ -108,6 +108,10 @@ def test_is_ip_address__valid(value): ("FOO", None, False, False), ("FOO", None, True, True), ("FOO", "", False, False), + ("FOO", "False", False, False), + ("FOO", "True", False, True), + ("FOO", "FALSE", True, False), + ("FOO", "fAlSe", True, False), ("FOO", "Yes", False, True), ("FOO", "123", False, True), ), From 283d9a0f5fc579a0a36614bb7248fed16d7d2e75 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 10 Aug 2023 21:21:24 -0700 Subject: [PATCH 0335/2607] fix aeha data template (#5231) Co-authored-by: Samuel Sieb --- esphome/components/remote_base/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 0666b96d1e..24993e84d3 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1569,4 +1569,7 @@ def aeha_dumper(var, config): async def aeha_action(var, config, args): template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) - cg.add(var.set_data(config[CONF_DATA])) + template_ = await cg.templatable( + config[CONF_DATA], args, cg.std_vector.template(cg.uint8) + ) + cg.add(var.set_data(template_)) From 3eef80506bb2d7e0c4bed0fe8a6d49aca8975bea Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:21:44 +1200 Subject: [PATCH 0336/2607] Expose start to speaker interface (#5228) --- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h | 2 +- esphome/components/speaker/speaker.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index f2e83142b3..b075722e1b 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -51,7 +51,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud #endif void set_external_dac_channels(uint8_t channels) { this->external_dac_channels_ = channels; } - void start(); + void start() override; void stop() override; size_t play(const uint8_t *data, size_t length) override; diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 53f97da5ac..3f520e3c5e 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -13,8 +13,9 @@ enum State : uint8_t { class Speaker { public: virtual size_t play(const uint8_t *data, size_t length) = 0; - virtual size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } + size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } + virtual void start() = 0; virtual void stop() = 0; bool is_running() const { return this->state_ == STATE_RUNNING; } From 5cb21324a1f0045a2ea4cb8c395e9d7976f2279c Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Fri, 11 Aug 2023 07:51:53 +0200 Subject: [PATCH 0337/2607] New features added for Haier integration (#5196) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/haier/climate.py | 74 ++++++- esphome/components/haier/haier_base.cpp | 75 +++++-- esphome/components/haier/haier_base.h | 43 ++-- esphome/components/haier/hon_climate.cpp | 144 ++++++------- esphome/components/haier/hon_climate.h | 5 +- esphome/components/haier/hon_packet.h | 16 +- .../components/haier/smartair2_climate.cpp | 204 +++++++++++++----- esphome/components/haier/smartair2_climate.h | 13 +- esphome/components/haier/smartair2_packet.h | 7 +- platformio.ini | 2 +- 10 files changed, 394 insertions(+), 189 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index c518282bfa..fec39d2967 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -14,7 +14,10 @@ from esphome.const import ( CONF_MIN_TEMPERATURE, CONF_PROTOCOL, CONF_SUPPORTED_MODES, + CONF_SUPPORTED_PRESETS, CONF_SUPPORTED_SWING_MODES, + CONF_TARGET_TEMPERATURE, + CONF_TEMPERATURE_STEP, CONF_VISUAL, CONF_WIFI, DEVICE_CLASS_TEMPERATURE, @@ -23,25 +26,29 @@ from esphome.const import ( UNIT_CELSIUS, ) from esphome.components.climate import ( - ClimateSwingMode, ClimateMode, + ClimatePreset, + ClimateSwingMode, + CONF_CURRENT_TEMPERATURE, ) _LOGGER = logging.getLogger(__name__) PROTOCOL_MIN_TEMPERATURE = 16.0 PROTOCOL_MAX_TEMPERATURE = 30.0 -PROTOCOL_TEMPERATURE_STEP = 1.0 +PROTOCOL_TARGET_TEMPERATURE_STEP = 1.0 +PROTOCOL_CURRENT_TEMPERATURE_STEP = 0.5 CODEOWNERS = ["@paveldn"] AUTO_LOAD = ["sensor"] DEPENDENCIES = ["climate", "uart"] CONF_WIFI_SIGNAL = "wifi_signal" +CONF_ANSWER_TIMEOUT = "answer_timeout" +CONF_DISPLAY = "display" CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_VERTICAL_AIRFLOW = "vertical_airflow" CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow" - PROTOCOL_HON = "HON" PROTOCOL_SMARTAIR2 = "SMARTAIR2" PROTOCOLS_SUPPORTED = [PROTOCOL_HON, PROTOCOL_SMARTAIR2] @@ -89,6 +96,17 @@ SUPPORTED_CLIMATE_MODES_OPTIONS = { "FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY, } +SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS = { + "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, + "COMFORT": ClimatePreset.CLIMATE_PRESET_COMFORT, +} + +SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS = { + "ECO": ClimatePreset.CLIMATE_PRESET_ECO, + "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, + "SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP, +} + def validate_visual(config): if CONF_VISUAL in config: @@ -109,10 +127,29 @@ def validate_visual(config): ) else: config[CONF_VISUAL][CONF_MAX_TEMPERATURE] = PROTOCOL_MAX_TEMPERATURE + if CONF_TEMPERATURE_STEP in visual_config: + temp_step = config[CONF_VISUAL][CONF_TEMPERATURE_STEP][ + CONF_TARGET_TEMPERATURE + ] + if ((int)(temp_step * 2)) / 2 != temp_step: + raise cv.Invalid( + f"Configured visual temperature step {temp_step} is wrong, it should be a multiple of 0.5" + ) + else: + config[CONF_VISUAL][CONF_TEMPERATURE_STEP] = ( + { + CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, + CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, + }, + ) else: config[CONF_VISUAL] = { CONF_MIN_TEMPERATURE: PROTOCOL_MIN_TEMPERATURE, CONF_MAX_TEMPERATURE: PROTOCOL_MAX_TEMPERATURE, + CONF_TEMPERATURE_STEP: { + CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, + CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, + }, } return config @@ -132,6 +169,11 @@ BASE_CONFIG_SCHEMA = ( "BOTH", ], ): cv.ensure_list(cv.enum(SUPPORTED_SWING_MODES_OPTIONS, upper=True)), + cv.Optional(CONF_WIFI_SIGNAL, default=False): cv.boolean, + cv.Optional(CONF_DISPLAY): cv.boolean, + cv.Optional( + CONF_ANSWER_TIMEOUT, + ): cv.positive_time_period_milliseconds, } ) .extend(uart.UART_DEVICE_SCHEMA) @@ -144,13 +186,26 @@ CONFIG_SCHEMA = cv.All( PROTOCOL_SMARTAIR2: BASE_CONFIG_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(Smartair2Climate), + cv.Optional( + CONF_SUPPORTED_PRESETS, + default=list( + SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS.keys() + ), + ): cv.ensure_list( + cv.enum(SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS, upper=True) + ), } ), PROTOCOL_HON: BASE_CONFIG_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(HonClimate), - cv.Optional(CONF_WIFI_SIGNAL, default=True): cv.boolean, cv.Optional(CONF_BEEPER, default=True): cv.boolean, + cv.Optional( + CONF_SUPPORTED_PRESETS, + default=list(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS.keys()), + ): cv.ensure_list( + cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True) + ), cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, icon=ICON_THERMOMETER, @@ -354,10 +409,11 @@ async def to_code(config): await uart.register_uart_device(var, config) await climate.register_climate(var, config) - if (CONF_WIFI_SIGNAL in config) and (config[CONF_WIFI_SIGNAL]): - cg.add(var.set_send_wifi(config[CONF_WIFI_SIGNAL])) + cg.add(var.set_send_wifi(config[CONF_WIFI_SIGNAL])) if CONF_BEEPER in config: cg.add(var.set_beeper_state(config[CONF_BEEPER])) + if CONF_DISPLAY in config: + cg.add(var.set_display_state(config[CONF_DISPLAY])) if CONF_OUTDOOR_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) cg.add(var.set_outdoor_temperature_sensor(sens)) @@ -365,5 +421,9 @@ async def to_code(config): cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES])) if CONF_SUPPORTED_SWING_MODES in config: cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES])) + if CONF_SUPPORTED_PRESETS in config: + cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS])) + if CONF_ANSWER_TIMEOUT in config: + cg.add(var.set_answer_timeout(config[CONF_ANSWER_TIMEOUT])) # https://github.com/paveldn/HaierProtocol - cg.add_library("pavlodn/HaierProtocol", "0.9.18") + cg.add_library("pavlodn/HaierProtocol", "0.9.20") diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index d9349cb8fe..5faee5207b 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -2,6 +2,9 @@ #include #include "esphome/components/climate/climate.h" #include "esphome/components/uart/uart.h" +#ifdef USE_WIFI +#include "esphome/components/wifi/wifi_component.h" +#endif #include "haier_base.h" using namespace esphome::climate; @@ -24,14 +27,15 @@ constexpr size_t NO_COMMAND = 0xFF; // Indicate that there is no command suppli const char *HaierClimateBase::phase_to_string_(ProtocolPhases phase) { static const char *phase_names[] = { "SENDING_INIT_1", - "WAITING_ANSWER_INIT_1", + "WAITING_INIT_1_ANSWER", "SENDING_INIT_2", - "WAITING_ANSWER_INIT_2", + "WAITING_INIT_2_ANSWER", "SENDING_FIRST_STATUS_REQUEST", "WAITING_FIRST_STATUS_ANSWER", "SENDING_ALARM_STATUS_REQUEST", "WAITING_ALARM_STATUS_ANSWER", "IDLE", + "UNKNOWN", "SENDING_STATUS_REQUEST", "WAITING_STATUS_ANSWER", "SENDING_UPDATE_SIGNAL_REQUEST", @@ -63,7 +67,8 @@ HaierClimateBase::HaierClimateBase() forced_publish_(false), forced_request_status_(false), first_control_attempt_(false), - reset_protocol_request_(false) { + reset_protocol_request_(false), + send_wifi_signal_(true) { this->traits_ = climate::ClimateTraits(); this->traits_.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, @@ -77,7 +82,7 @@ HaierClimateBase::HaierClimateBase() HaierClimateBase::~HaierClimateBase() {} -void HaierClimateBase::set_phase_(ProtocolPhases phase) { +void HaierClimateBase::set_phase(ProtocolPhases phase) { if (this->protocol_phase_ != phase) { #if (HAIER_LOG_LEVEL > 4) ESP_LOGV(TAG, "Phase transition: %s => %s", phase_to_string_(this->protocol_phase_), phase_to_string_(phase)); @@ -109,10 +114,27 @@ bool HaierClimateBase::is_control_message_interval_exceeded_(std::chrono::steady return this->check_timeout_(now, this->last_request_timestamp_, CONTROL_MESSAGES_INTERVAL_MS); } -bool HaierClimateBase::is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now) { +bool HaierClimateBase::is_protocol_initialisation_interval_exceeded_(std::chrono::steady_clock::time_point now) { return this->check_timeout_(now, this->last_request_timestamp_, PROTOCOL_INITIALIZATION_INTERVAL); } +#ifdef USE_WIFI +haier_protocol::HaierMessage HaierClimateBase::get_wifi_signal_message_(uint8_t message_type) { + static uint8_t wifi_status_data[4] = {0x00, 0x00, 0x00, 0x00}; + if (wifi::global_wifi_component->is_connected()) { + wifi_status_data[1] = 0; + int8_t rssi = wifi::global_wifi_component->wifi_rssi(); + wifi_status_data[3] = uint8_t((128 + rssi) / 1.28f); + ESP_LOGD(TAG, "WiFi signal is: %ddBm => %d%%", rssi, wifi_status_data[3]); + } else { + ESP_LOGD(TAG, "WiFi is not connected"); + wifi_status_data[1] = 1; + wifi_status_data[3] = 0; + } + return haier_protocol::HaierMessage(message_type, wifi_status_data, sizeof(wifi_status_data)); +} +#endif + bool HaierClimateBase::get_display_state() const { return this->display_status_; } void HaierClimateBase::set_display_state(bool state) { @@ -136,10 +158,15 @@ void HaierClimateBase::send_power_on_command() { this->action_request_ = ActionR void HaierClimateBase::send_power_off_command() { this->action_request_ = ActionRequest::TURN_POWER_OFF; } void HaierClimateBase::toggle_power() { this->action_request_ = ActionRequest::TOGGLE_POWER; } + void HaierClimateBase::set_supported_swing_modes(const std::set &modes) { this->traits_.set_supported_swing_modes(modes); - this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); // Always available - this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); // Always available + if (!modes.empty()) + this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); +} + +void HaierClimateBase::set_answer_timeout(uint32_t timeout) { + this->answer_timeout_ = std::chrono::milliseconds(timeout); } void HaierClimateBase::set_supported_modes(const std::set &modes) { @@ -148,6 +175,14 @@ void HaierClimateBase::set_supported_modes(const std::set this->traits_.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Always available } +void HaierClimateBase::set_supported_presets(const std::set &presets) { + this->traits_.set_supported_presets(presets); + if (!presets.empty()) + this->traits_.add_supported_preset(climate::CLIMATE_PRESET_NONE); +} + +void HaierClimateBase::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; } + haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(uint8_t request_message_type, uint8_t expected_request_message_type, uint8_t answer_message_type, @@ -155,9 +190,9 @@ haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(uint8_t reques ProtocolPhases expected_phase) { haier_protocol::HandlerError result = haier_protocol::HandlerError::HANDLER_OK; if ((expected_request_message_type != NO_COMMAND) && (request_message_type != expected_request_message_type)) - result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + result = haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; if ((expected_answer_message_type != NO_COMMAND) && (answer_message_type != expected_answer_message_type)) - result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + result = haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; if ((expected_phase != ProtocolPhases::UNKNOWN) && (expected_phase != this->protocol_phase_)) result = haier_protocol::HandlerError::UNEXPECTED_MESSAGE; if (is_message_invalid(answer_message_type)) @@ -172,9 +207,9 @@ haier_protocol::HandlerError HaierClimateBase::timeout_default_handler_(uint8_t ESP_LOGW(TAG, "Answer timeout for command %02X, phase %d", request_type, (int) this->protocol_phase_); #endif if (this->protocol_phase_ > ProtocolPhases::IDLE) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else { - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); } return haier_protocol::HandlerError::HANDLER_OK; } @@ -183,8 +218,8 @@ void HaierClimateBase::setup() { ESP_LOGI(TAG, "Haier initialization..."); // Set timestamp here to give AC time to boot this->last_request_timestamp_ = std::chrono::steady_clock::now(); - this->set_phase_(ProtocolPhases::SENDING_INIT_1); - this->set_answers_handlers(); + this->set_phase(ProtocolPhases::SENDING_INIT_1); + this->set_handlers(); this->haier_protocol_.set_default_timeout_handler( std::bind(&esphome::haier::HaierClimateBase::timeout_default_handler_, this, std::placeholders::_1)); } @@ -212,7 +247,7 @@ void HaierClimateBase::loop() { this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); return; } else { // No need to reset protocol if we didn't pass initialization phase @@ -229,7 +264,7 @@ void HaierClimateBase::loop() { this->process_pending_action(); } else if (this->hvac_settings_.valid || this->force_send_control_) { ESP_LOGV(TAG, "Control packet is pending..."); - this->set_phase_(ProtocolPhases::SENDING_CONTROL); + this->set_phase(ProtocolPhases::SENDING_CONTROL); } } this->process_phase(now); @@ -243,10 +278,10 @@ void HaierClimateBase::process_pending_action() { } switch (request) { case ActionRequest::TURN_POWER_ON: - this->set_phase_(ProtocolPhases::SENDING_POWER_ON_COMMAND); + this->set_phase(ProtocolPhases::SENDING_POWER_ON_COMMAND); break; case ActionRequest::TURN_POWER_OFF: - this->set_phase_(ProtocolPhases::SENDING_POWER_OFF_COMMAND); + this->set_phase(ProtocolPhases::SENDING_POWER_OFF_COMMAND); break; case ActionRequest::TOGGLE_POWER: case ActionRequest::NO_ACTION: @@ -303,7 +338,11 @@ void HaierClimateBase::set_force_send_control_(bool status) { } void HaierClimateBase::send_message_(const haier_protocol::HaierMessage &command, bool use_crc) { - this->haier_protocol_.send_message(command, use_crc); + if (this->answer_timeout_.has_value()) { + this->haier_protocol_.send_message(command, use_crc, this->answer_timeout_.value()); + } else { + this->haier_protocol_.send_message(command, use_crc); + } this->last_request_timestamp_ = std::chrono::steady_clock::now(); } diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index 046b59af96..b2446d6fb5 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -44,6 +44,7 @@ class HaierClimateBase : public esphome::Component, void reset_protocol() { this->reset_protocol_request_ = true; }; void set_supported_modes(const std::set &modes); void set_supported_swing_modes(const std::set &modes); + void set_supported_presets(const std::set &presets); size_t available() noexcept override { return esphome::uart::UARTDevice::available(); }; size_t read_array(uint8_t *data, size_t len) noexcept override { return esphome::uart::UARTDevice::read_array(data, len) ? len : 0; @@ -52,39 +53,41 @@ class HaierClimateBase : public esphome::Component, esphome::uart::UARTDevice::write_array(data, len); }; bool can_send_message() const { return haier_protocol_.get_outgoing_queue_size() == 0; }; + void set_answer_timeout(uint32_t timeout); + void set_send_wifi(bool send_wifi); protected: enum class ProtocolPhases { UNKNOWN = -1, // INITIALIZATION SENDING_INIT_1 = 0, - WAITING_ANSWER_INIT_1 = 1, + WAITING_INIT_1_ANSWER = 1, SENDING_INIT_2 = 2, - WAITING_ANSWER_INIT_2 = 3, + WAITING_INIT_2_ANSWER = 3, SENDING_FIRST_STATUS_REQUEST = 4, WAITING_FIRST_STATUS_ANSWER = 5, SENDING_ALARM_STATUS_REQUEST = 6, WAITING_ALARM_STATUS_ANSWER = 7, // FUNCTIONAL STATE IDLE = 8, - SENDING_STATUS_REQUEST = 9, - WAITING_STATUS_ANSWER = 10, - SENDING_UPDATE_SIGNAL_REQUEST = 11, - WAITING_UPDATE_SIGNAL_ANSWER = 12, - SENDING_SIGNAL_LEVEL = 13, - WAITING_SIGNAL_LEVEL_ANSWER = 14, - SENDING_CONTROL = 15, - WAITING_CONTROL_ANSWER = 16, - SENDING_POWER_ON_COMMAND = 17, - WAITING_POWER_ON_ANSWER = 18, - SENDING_POWER_OFF_COMMAND = 19, - WAITING_POWER_OFF_ANSWER = 20, + SENDING_STATUS_REQUEST = 10, + WAITING_STATUS_ANSWER = 11, + SENDING_UPDATE_SIGNAL_REQUEST = 12, + WAITING_UPDATE_SIGNAL_ANSWER = 13, + SENDING_SIGNAL_LEVEL = 14, + WAITING_SIGNAL_LEVEL_ANSWER = 15, + SENDING_CONTROL = 16, + WAITING_CONTROL_ANSWER = 17, + SENDING_POWER_ON_COMMAND = 18, + WAITING_POWER_ON_ANSWER = 19, + SENDING_POWER_OFF_COMMAND = 20, + WAITING_POWER_OFF_ANSWER = 21, NUM_PROTOCOL_PHASES }; #if (HAIER_LOG_LEVEL > 4) const char *phase_to_string_(ProtocolPhases phase); #endif - virtual void set_answers_handlers() = 0; + virtual void set_handlers() = 0; virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; virtual haier_protocol::HaierMessage get_control_message() = 0; virtual bool is_message_invalid(uint8_t message_type) = 0; @@ -99,14 +102,17 @@ class HaierClimateBase : public esphome::Component, // Helper functions void set_force_send_control_(bool status); void send_message_(const haier_protocol::HaierMessage &command, bool use_crc); - void set_phase_(ProtocolPhases phase); + virtual void set_phase(ProtocolPhases phase); bool check_timeout_(std::chrono::steady_clock::time_point now, std::chrono::steady_clock::time_point tpoint, size_t timeout); bool is_message_interval_exceeded_(std::chrono::steady_clock::time_point now); bool is_status_request_interval_exceeded_(std::chrono::steady_clock::time_point now); bool is_control_message_timeout_exceeded_(std::chrono::steady_clock::time_point now); bool is_control_message_interval_exceeded_(std::chrono::steady_clock::time_point now); - bool is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now); + bool is_protocol_initialisation_interval_exceeded_(std::chrono::steady_clock::time_point now); +#ifdef USE_WIFI + haier_protocol::HaierMessage get_wifi_signal_message_(uint8_t message_type); +#endif struct HvacSettings { esphome::optional mode; @@ -136,6 +142,9 @@ class HaierClimateBase : public esphome::Component, std::chrono::steady_clock::time_point last_valid_status_timestamp_; // For protocol timeout std::chrono::steady_clock::time_point last_status_request_; // To request AC status std::chrono::steady_clock::time_point control_request_timestamp_; // To send control message + optional answer_timeout_; // Message answer timeout + bool send_wifi_signal_; + std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level }; } // namespace haier diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 3950b34724..feb1e019d8 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -2,9 +2,6 @@ #include #include "esphome/components/climate/climate.h" #include "esphome/components/uart/uart.h" -#ifdef USE_WIFI -#include "esphome/components/wifi/wifi_component.h" -#endif #include "hon_climate.h" #include "hon_packet.h" @@ -58,14 +55,7 @@ HonClimate::HonClimate() hvac_functions_{false, false, false, false, false}, use_crc_(hvac_functions_[2]), active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - outdoor_sensor_(nullptr), - send_wifi_signal_(true) { - this->traits_.set_supported_presets({ - climate::CLIMATE_PRESET_NONE, - climate::CLIMATE_PRESET_ECO, - climate::CLIMATE_PRESET_BOOST, - climate::CLIMATE_PRESET_SLEEP, - }); + outdoor_sensor_(nullptr) { this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID; this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO; } @@ -121,17 +111,22 @@ void HonClimate::start_steri_cleaning() { } } -void HonClimate::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; } - haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size) { + // Should check this before preprocess + if (message_type == (uint8_t) hon_protocol::FrameType::INVALID) { + ESP_LOGW(TAG, "It looks like your ESPHome Haier climate configuration is wrong. You should use the smartAir2 " + "protocol instead of hOn"); + this->set_phase(ProtocolPhases::SENDING_INIT_1); + return haier_protocol::HandlerError::INVALID_ANSWER; + } haier_protocol::HandlerError result = this->answer_preprocess_( request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, message_type, - (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_1); + (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE, ProtocolPhases::WAITING_INIT_1_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { if (data_size < sizeof(hon_protocol::DeviceVersionAnswer)) { // Wrong structure - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; } // All OK @@ -152,11 +147,11 @@ haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(uint this->hvac_functions_[3] = (answr->functions[1] & 0x08) != 0; // multiple AC support this->hvac_functions_[4] = (answr->functions[1] & 0x20) != 0; // roles support this->hvac_hardware_info_available_ = true; - this->set_phase_(ProtocolPhases::SENDING_INIT_2); + this->set_phase(ProtocolPhases::SENDING_INIT_2); return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -165,13 +160,13 @@ haier_protocol::HandlerError HonClimate::get_device_id_answer_handler_(uint8_t r const uint8_t *data, size_t data_size) { haier_protocol::HandlerError result = this->answer_preprocess_( request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID, message_type, - (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_2); + (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID_RESPONSE, ProtocolPhases::WAITING_INIT_2_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -185,8 +180,8 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u result = this->process_status_message_(data, data_size); if (result != haier_protocol::HandlerError::HANDLER_OK) { ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); } else { if (data_size >= sizeof(hon_protocol::HaierPacketControl) + 2) { memcpy(this->last_status_message_.get(), data + 2, sizeof(hon_protocol::HaierPacketControl)); @@ -196,13 +191,13 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u } if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { ESP_LOGI(TAG, "First HVAC status received"); - this->set_phase_(ProtocolPhases::SENDING_ALARM_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_ALARM_STATUS_REQUEST); } else if ((this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) || (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_ON_ANSWER) || (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_OFF_ANSWER)) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); @@ -210,8 +205,8 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u } return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -225,10 +220,10 @@ haier_protocol::HandlerError HonClimate::get_management_information_answer_handl message_type, (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION_RESPONSE, ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { - this->set_phase_(ProtocolPhases::SENDING_SIGNAL_LEVEL); + this->set_phase(ProtocolPhases::SENDING_SIGNAL_LEVEL); return result; } else { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return result; } } @@ -239,7 +234,7 @@ haier_protocol::HandlerError HonClimate::report_network_status_answer_handler_(u haier_protocol::HandlerError result = this->answer_preprocess_(request_type, (uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, message_type, (uint8_t) hon_protocol::FrameType::CONFIRM, ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return result; } @@ -248,24 +243,24 @@ haier_protocol::HandlerError HonClimate::get_alarm_status_answer_handler_(uint8_ if (request_type == (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS) { if (message_type != (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS_RESPONSE) { // Unexpected answer to request - this->set_phase_(ProtocolPhases::IDLE); - return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + this->set_phase(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; } if (this->protocol_phase_ != ProtocolPhases::WAITING_ALARM_STATUS_ANSWER) { // Don't expect this answer now - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return haier_protocol::HandlerError::UNEXPECTED_MESSAGE; } memcpy(this->active_alarms_, data + 2, 8); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return haier_protocol::HandlerError::HANDLER_OK; } else { - this->set_phase_(ProtocolPhases::IDLE); - return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + this->set_phase(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; } } -void HonClimate::set_answers_handlers() { +void HonClimate::set_handlers() { // Set handlers this->haier_protocol_.set_answer_handler( (uint8_t) (hon_protocol::FrameType::GET_DEVICE_VERSION), @@ -311,7 +306,7 @@ void HonClimate::dump_config() { void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { switch (this->protocol_phase_) { case ProtocolPhases::SENDING_INIT_1: - if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { + if (this->can_send_message() && this->is_protocol_initialisation_interval_exceeded_(now)) { this->hvac_hardware_info_available_ = false; // Indicate device capabilities: // bit 0 - if 1 module support interactive mode @@ -323,24 +318,24 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST( (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, sizeof(module_capabilities)); this->send_message_(DEVICE_VERSION_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_1); + this->set_phase(ProtocolPhases::WAITING_INIT_1_ANSWER); } break; case ProtocolPhases::SENDING_INIT_2: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage DEVICEID_REQUEST((uint8_t) hon_protocol::FrameType::GET_DEVICE_ID); this->send_message_(DEVICEID_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_2); + this->set_phase(ProtocolPhases::WAITING_INIT_2_ANSWER); } break; case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: case ProtocolPhases::SENDING_STATUS_REQUEST: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage STATUS_REQUEST( - (uint8_t) hon_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcomandsControl::GET_USER_DATA); + (uint8_t) hon_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::GET_USER_DATA); this->send_message_(STATUS_REQUEST, this->use_crc_); this->last_status_request_ = now; - this->set_phase_((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); + this->set_phase((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); } break; #ifdef USE_WIFI @@ -350,26 +345,14 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION); this->send_message_(UPDATE_SIGNAL_REQUEST, this->use_crc_); this->last_signal_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); } break; case ProtocolPhases::SENDING_SIGNAL_LEVEL: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { - static uint8_t wifi_status_data[4] = {0x00, 0x00, 0x00, 0x00}; - if (wifi::global_wifi_component->is_connected()) { - wifi_status_data[1] = 0; - int8_t rssi = wifi::global_wifi_component->wifi_rssi(); - wifi_status_data[3] = uint8_t((128 + rssi) / 1.28f); - ESP_LOGD(TAG, "WiFi signal is: %ddBm => %d%%", rssi, wifi_status_data[3]); - } else { - ESP_LOGD(TAG, "WiFi is not connected"); - wifi_status_data[1] = 1; - wifi_status_data[3] = 0; - } - haier_protocol::HaierMessage wifi_status_request((uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, - wifi_status_data, sizeof(wifi_status_data)); - this->send_message_(wifi_status_request, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + this->send_message_(this->get_wifi_signal_message_((uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS), + this->use_crc_); + this->set_phase(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); } break; case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: @@ -380,7 +363,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { case ProtocolPhases::SENDING_SIGNAL_LEVEL: case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); break; #endif case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: @@ -388,7 +371,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { static const haier_protocol::HaierMessage ALARM_STATUS_REQUEST( (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS); this->send_message_(ALARM_STATUS_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ALARM_STATUS_ANSWER); + this->set_phase(ProtocolPhases::WAITING_ALARM_STATUS_ANSWER); } break; case ProtocolPhases::SENDING_CONTROL: @@ -403,12 +386,12 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { this->hvac_settings_.reset(); this->forced_request_status_ = true; this->forced_publish_ = true; - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->can_send_message() && this->is_control_message_interval_exceeded_(now)) { haier_protocol::HaierMessage control_message = get_control_message(); this->send_message_(control_message, this->use_crc_); ESP_LOGI(TAG, "Control packet sent"); - this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_CONTROL_ANSWER); } break; case ProtocolPhases::SENDING_POWER_ON_COMMAND: @@ -418,17 +401,17 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { if (this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND) pwr_cmd_buf[1] = 0x01; haier_protocol::HaierMessage power_cmd((uint8_t) hon_protocol::FrameType::CONTROL, - ((uint16_t) hon_protocol::SubcomandsControl::SET_SINGLE_PARAMETER) + 1, + ((uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER) + 1, pwr_cmd_buf, sizeof(pwr_cmd_buf)); this->send_message_(power_cmd, this->use_crc_); - this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND - ? ProtocolPhases::WAITING_POWER_ON_ANSWER - : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + this->set_phase(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); } break; - case ProtocolPhases::WAITING_ANSWER_INIT_1: - case ProtocolPhases::WAITING_ANSWER_INIT_2: + case ProtocolPhases::WAITING_INIT_1_ANSWER: + case ProtocolPhases::WAITING_INIT_2_ANSWER: case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: case ProtocolPhases::WAITING_STATUS_ANSWER: @@ -438,14 +421,14 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { break; case ProtocolPhases::IDLE: { if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { - this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_STATUS_REQUEST); this->forced_request_status_ = false; } #ifdef USE_WIFI else if (this->send_wifi_signal_ && (std::chrono::duration_cast(now - this->last_signal_request_).count() > SIGNAL_LEVEL_UPDATE_INTERVAL_MS)) - this->set_phase_(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); + this->set_phase(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); #endif } break; default: @@ -456,7 +439,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { #else ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); #endif - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); break; } } @@ -551,11 +534,12 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { } } if (climate_control.target_temperature.has_value()) { - out_data->set_point = - climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + float target_temp = climate_control.target_temperature.value(); + out_data->set_point = ((int) target_temp) - 16; // set the temperature at our offset, subtract 16. + out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0; } if (out_data->ac_power == 0) { - // If AC is off - no presets alowed + // If AC is off - no presets allowed out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; @@ -631,7 +615,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { break; } return haier_protocol::HaierMessage((uint8_t) hon_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcomandsControl::SET_GROUP_PARAMETERS, + (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); } @@ -669,7 +653,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * { // Target temperature float old_target_temperature = this->target_temperature; - this->target_temperature = packet.control.set_point + 16.0f; + this->target_temperature = packet.control.set_point + 16.0f + ((packet.control.half_degree == 1) ? 0.5f : 0.0f); should_publish = should_publish || (old_target_temperature != this->target_temperature); } { @@ -747,7 +731,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * if (new_cleaning != this->cleaning_status_) { ESP_LOGD(TAG, "Cleaning status change: %d => %d", (uint8_t) this->cleaning_status_, (uint8_t) new_cleaning); if (new_cleaning == CleaningState::NO_CLEANING) { - // Turnuin AC off after cleaning + // Turning AC off after cleaning this->action_request_ = ActionRequest::TURN_POWER_OFF; } this->cleaning_status_ = new_cleaning; @@ -837,7 +821,7 @@ void HonClimate::process_pending_action() { case ActionRequest::START_SELF_CLEAN: case ActionRequest::START_STERI_CLEAN: // Will reset action with control message sending - this->set_phase_(ProtocolPhases::SENDING_CONTROL); + this->set_phase(ProtocolPhases::SENDING_CONTROL); break; default: HaierClimateBase::process_pending_action(); diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index ab913f44e2..cf566e3b8e 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -48,10 +48,9 @@ class HonClimate : public HaierClimateBase { CleaningState get_cleaning_status() const; void start_self_cleaning(); void start_steri_cleaning(); - void set_send_wifi(bool send_wifi); protected: - void set_answers_handlers() override; + void set_handlers() override; void process_phase(std::chrono::steady_clock::time_point now) override; haier_protocol::HaierMessage get_control_message() override; bool is_message_invalid(uint8_t message_type) override; @@ -87,8 +86,6 @@ class HonClimate : public HaierClimateBase { bool &use_crc_; uint8_t active_alarms_[8]; esphome::sensor::Sensor *outdoor_sensor_; - bool send_wifi_signal_; - std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level }; } // namespace haier diff --git a/esphome/components/haier/hon_packet.h b/esphome/components/haier/hon_packet.h index d572ce80d9..c6b32df200 100644 --- a/esphome/components/haier/hon_packet.h +++ b/esphome/components/haier/hon_packet.h @@ -53,12 +53,12 @@ struct HaierPacketControl { // 13 uint8_t : 8; // 14 - uint8_t ten_degree : 1; // 10 degree status - uint8_t display_status : 1; // If 0 disables AC's display - uint8_t half_degree : 1; // Use half degree - uint8_t intelegence_status : 1; // Intelligence status - uint8_t pmv_status : 1; // Comfort/PMV status - uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius + uint8_t ten_degree : 1; // 10 degree status + uint8_t display_status : 1; // If 0 disables AC's display + uint8_t half_degree : 1; // Use half degree + uint8_t intelligence_status : 1; // Intelligence status + uint8_t pmv_status : 1; // Comfort/PMV status + uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius uint8_t : 1; uint8_t steri_clean : 1; // 15 @@ -153,7 +153,7 @@ enum class FrameType : uint8_t { // <-> device, required) REPORT = 0x06, // Report frame (module <-> device, interactive, required) STOP_FAULT_ALARM = 0x09, // Stop fault alarm frame (module -> device, interactive, required) - SYSTEM_DOWNLIK = 0x11, // System downlink frame (module -> device, optional) + SYSTEM_DOWNLINK = 0x11, // System downlink frame (module -> device, optional) DEVICE_UPLINK = 0x12, // Device uplink frame (module <- device , interactive, optional) SYSTEM_QUERY = 0x13, // System query frame (module -> device, optional) SYSTEM_QUERY_RESPONSE = 0x14, // System query response frame (module <- device , optional) @@ -210,7 +210,7 @@ enum class FrameType : uint8_t { WAKE_UP = 0xFE, // Request to wake up (module <-> device, optional) }; -enum class SubcomandsControl : uint16_t { +enum class SubcommandsControl : uint16_t { GET_PARAMETERS = 0x4C01, // Request specific parameters (packet content: parameter ID1 + parameter ID2 + ...) GET_USER_DATA = 0x4D01, // Request all user data from device (packet content: None) GET_BIG_DATA = 0x4DFE, // Request big data information from device (packet content: None) diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 9c0fbac350..91b6bb0545 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -11,15 +11,10 @@ namespace esphome { namespace haier { static const char *const TAG = "haier.climate"; +constexpr size_t SIGNAL_LEVEL_UPDATE_INTERVAL_MS = 10000; Smartair2Climate::Smartair2Climate() - : last_status_message_(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]) { - this->traits_.set_supported_presets({ - climate::CLIMATE_PRESET_NONE, - climate::CLIMATE_PRESET_BOOST, - climate::CLIMATE_PRESET_COMFORT, - }); -} + : last_status_message_(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]), timeouts_counter_(0) {} haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size) { @@ -30,8 +25,8 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t result = this->process_status_message_(data, data_size); if (result != haier_protocol::HandlerError::HANDLER_OK) { ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); } else { if (data_size >= sizeof(smartair2_protocol::HaierPacketControl) + 2) { memcpy(this->last_status_message_.get(), data + 2, sizeof(smartair2_protocol::HaierPacketControl)); @@ -41,11 +36,11 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t } if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { ESP_LOGI(TAG, "First HVAC status received"); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); @@ -53,17 +48,82 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t } return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); return result; } } -void Smartair2Climate::set_answers_handlers() { +haier_protocol::HandlerError Smartair2Climate::get_device_version_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, + size_t data_size) { + if (request_type != (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION) + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; + if (ProtocolPhases::WAITING_INIT_1_ANSWER != this->protocol_phase_) + return haier_protocol::HandlerError::UNEXPECTED_MESSAGE; + // Invalid packet is expected answer + if ((message_type == (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE) && (data_size >= 39) && + ((data[37] & 0x04) != 0)) { + ESP_LOGW(TAG, "It looks like your ESPHome Haier climate configuration is wrong. You should use the hOn protocol " + "instead of smartAir2"); + } + this->set_phase(ProtocolPhases::SENDING_INIT_2); + return haier_protocol::HandlerError::HANDLER_OK; +} + +haier_protocol::HandlerError Smartair2Climate::report_network_status_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, + size_t data_size) { + haier_protocol::HandlerError result = this->answer_preprocess_( + request_type, (uint8_t) smartair2_protocol::FrameType::REPORT_NETWORK_STATUS, message_type, + (uint8_t) smartair2_protocol::FrameType::CONFIRM, ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + this->set_phase(ProtocolPhases::IDLE); + return result; +} + +haier_protocol::HandlerError Smartair2Climate::initial_messages_timeout_handler_(uint8_t message_type) { + if (this->protocol_phase_ >= ProtocolPhases::IDLE) + return HaierClimateBase::timeout_default_handler_(message_type); + this->timeouts_counter_++; + ESP_LOGI(TAG, "Answer timeout for command %02X, phase %d, timeout counter %d", message_type, + (int) this->protocol_phase_, this->timeouts_counter_); + if (this->timeouts_counter_ >= 3) { + ProtocolPhases new_phase = (ProtocolPhases) ((int) this->protocol_phase_ + 1); + if (new_phase >= ProtocolPhases::SENDING_ALARM_STATUS_REQUEST) + new_phase = ProtocolPhases::SENDING_INIT_1; + this->set_phase(new_phase); + } else { + // Returning to the previous state to try again + this->set_phase((ProtocolPhases) ((int) this->protocol_phase_ - 1)); + } + return haier_protocol::HandlerError::HANDLER_OK; +} + +void Smartair2Climate::set_handlers() { + // Set handlers + this->haier_protocol_.set_answer_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_VERSION), + std::bind(&Smartair2Climate::get_device_version_answer_handler_, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); this->haier_protocol_.set_answer_handler( (uint8_t) (smartair2_protocol::FrameType::CONTROL), std::bind(&Smartair2Climate::status_handler_, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (smartair2_protocol::FrameType::REPORT_NETWORK_STATUS), + std::bind(&Smartair2Climate::report_network_status_answer_handler_, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_ID), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_VERSION), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::CONTROL), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); } void Smartair2Climate::dump_config() { @@ -74,39 +134,60 @@ void Smartair2Climate::dump_config() { void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) { switch (this->protocol_phase_) { case ProtocolPhases::SENDING_INIT_1: - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); - break; - case ProtocolPhases::WAITING_ANSWER_INIT_1: - case ProtocolPhases::SENDING_INIT_2: - case ProtocolPhases::WAITING_ANSWER_INIT_2: - case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: - case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: - this->set_phase_(ProtocolPhases::SENDING_INIT_1); - break; - case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: - case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: - case ProtocolPhases::SENDING_SIGNAL_LEVEL: - case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: - this->set_phase_(ProtocolPhases::IDLE); - break; - case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: - if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { - static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, - 0x4D01); - this->send_message_(STATUS_REQUEST, false); - this->last_status_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_FIRST_STATUS_ANSWER); + if (this->can_send_message() && + (((this->timeouts_counter_ == 0) && (this->is_protocol_initialisation_interval_exceeded_(now))) || + ((this->timeouts_counter_ > 0) && (this->is_message_interval_exceeded_(now))))) { + // Indicate device capabilities: + // bit 0 - if 1 module support interactive mode + // bit 1 - if 1 module support controller-device mode + // bit 2 - if 1 module support crc + // bit 3 - if 1 module support multiple devices + // bit 4..bit 15 - not used + uint8_t module_capabilities[2] = {0b00000000, 0b00000111}; + static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST( + (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, + sizeof(module_capabilities)); + this->send_message_(DEVICE_VERSION_REQUEST, false); + this->set_phase(ProtocolPhases::WAITING_INIT_1_ANSWER); } break; + case ProtocolPhases::SENDING_INIT_2: + case ProtocolPhases::WAITING_INIT_2_ANSWER: + this->set_phase(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + break; + case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: case ProtocolPhases::SENDING_STATUS_REQUEST: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, 0x4D01); this->send_message_(STATUS_REQUEST, false); this->last_status_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_STATUS_ANSWER); + this->set_phase((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); } break; +#ifdef USE_WIFI + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + this->send_message_( + this->get_wifi_signal_message_((uint8_t) smartair2_protocol::FrameType::REPORT_NETWORK_STATUS), false); + this->last_signal_request_ = now; + this->set_phase(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + } + break; + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + break; +#else + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER this->set_phase(ProtocolPhases::IDLE); break; +#endif + case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: + case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: + this->set_phase(ProtocolPhases::SENDING_SIGNAL_LEVEL); + break; + case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: + case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: + this->set_phase(ProtocolPhases::SENDING_INIT_1); + break; case ProtocolPhases::SENDING_CONTROL: if (this->first_control_attempt_) { this->control_request_timestamp_ = now; @@ -119,14 +200,14 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) this->hvac_settings_.reset(); this->forced_request_status_ = true; this->forced_publish_ = true; - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->can_send_message() && this->is_control_message_interval_exceeded_( now)) // Using CONTROL_MESSAGES_INTERVAL_MS to speedup requests { haier_protocol::HaierMessage control_message = get_control_message(); this->send_message_(control_message, false); ESP_LOGI(TAG, "Control packet sent"); - this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_CONTROL_ANSWER); } break; case ProtocolPhases::SENDING_POWER_ON_COMMAND: @@ -136,11 +217,12 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) (uint8_t) smartair2_protocol::FrameType::CONTROL, this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND ? 0x4D02 : 0x4D03); this->send_message_(power_cmd, false); - this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND - ? ProtocolPhases::WAITING_POWER_ON_ANSWER - : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + this->set_phase(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); } break; + case ProtocolPhases::WAITING_INIT_1_ANSWER: case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: case ProtocolPhases::WAITING_STATUS_ANSWER: case ProtocolPhases::WAITING_CONTROL_ANSWER: @@ -149,14 +231,25 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) break; case ProtocolPhases::IDLE: { if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { - this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_STATUS_REQUEST); this->forced_request_status_ = false; } +#ifdef USE_WIFI + else if (this->send_wifi_signal_ && + (std::chrono::duration_cast(now - this->last_signal_request_).count() > + SIGNAL_LEVEL_UPDATE_INTERVAL_MS)) + this->set_phase(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); +#endif } break; default: // Shouldn't get here +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGE(TAG, "Wrong protocol handler state: %s (%d), resetting communication", + phase_to_string_(this->protocol_phase_), (int) this->protocol_phase_); +#else ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); +#endif + this->set_phase(ProtocolPhases::SENDING_INIT_1); break; } } @@ -256,11 +349,12 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() { } } if (climate_control.target_temperature.has_value()) { - out_data->set_point = - climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + float target_temp = climate_control.target_temperature.value(); + out_data->set_point = target_temp - 16; // set the temperature with offset 16 + out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0; } if (out_data->ac_power == 0) { - // If AC is off - no presets alowed + // If AC is off - no presets allowed out_data->turbo_mode = 0; out_data->quiet_mode = 0; } else if (climate_control.preset.has_value()) { @@ -312,7 +406,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin { // Target temperature float old_target_temperature = this->target_temperature; - this->target_temperature = packet.control.set_point + 16.0f; + this->target_temperature = packet.control.set_point + 16.0f + ((packet.control.half_degree == 1) ? 0.5f : 0.0f); should_publish = should_publish || (old_target_temperature != this->target_temperature); } { @@ -333,7 +427,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin } switch (packet.control.fan_mode) { case (uint8_t) smartair2_protocol::FanMode::FAN_AUTO: - // Somtimes AC reports in fan only mode that fan speed is auto + // Sometimes AC reports in fan only mode that fan speed is auto // but never accept this value back if (packet.control.ac_mode != (uint8_t) smartair2_protocol::ConditioningMode::FAN) { this->fan_mode = CLIMATE_FAN_AUTO; @@ -453,5 +547,15 @@ bool Smartair2Climate::is_message_invalid(uint8_t message_type) { return message_type == (uint8_t) smartair2_protocol::FrameType::INVALID; } +void Smartair2Climate::set_phase(HaierClimateBase::ProtocolPhases phase) { + int old_phase = (int) this->protocol_phase_; + int new_phase = (int) phase; + int min_p = std::min(old_phase, new_phase); + int max_p = std::max(old_phase, new_phase); + if ((min_p % 2 != 0) || (max_p - min_p > 1)) + this->timeouts_counter_ = 0; + HaierClimateBase::set_phase(phase); +} + } // namespace haier } // namespace esphome diff --git a/esphome/components/haier/smartair2_climate.h b/esphome/components/haier/smartair2_climate.h index c89d1f0be9..f173b10749 100644 --- a/esphome/components/haier/smartair2_climate.h +++ b/esphome/components/haier/smartair2_climate.h @@ -15,16 +15,25 @@ class Smartair2Climate : public HaierClimateBase { void dump_config() override; protected: - void set_answers_handlers() override; + void set_handlers() override; void process_phase(std::chrono::steady_clock::time_point now) override; haier_protocol::HaierMessage get_control_message() override; bool is_message_invalid(uint8_t message_type) override; - // Answers handlers + void set_phase(HaierClimateBase::ProtocolPhases phase) override; + // Answer and timeout handlers haier_protocol::HandlerError status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_device_id_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError report_network_status_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError initial_messages_timeout_handler_(uint8_t message_type); // Helper functions haier_protocol::HandlerError process_status_message_(const uint8_t *packet, uint8_t size); std::unique_ptr last_status_message_; + unsigned int timeouts_counter_; }; } // namespace haier diff --git a/esphome/components/haier/smartair2_packet.h b/esphome/components/haier/smartair2_packet.h index 8046516c5f..f791c21af2 100644 --- a/esphome/components/haier/smartair2_packet.h +++ b/esphome/components/haier/smartair2_packet.h @@ -53,8 +53,8 @@ struct HaierPacketControl { uint8_t : 2; uint8_t health_mode : 1; // Health mode on or off uint8_t compressor : 1; // Compressor on or off ??? - uint8_t : 1; - uint8_t ten_degree : 1; // 10 degree status (only work in heat mode) + uint8_t half_degree : 1; // Use half degree + uint8_t ten_degree : 1; // 10 degree status (only work in heat mode) uint8_t : 0; // 28 uint8_t : 8; @@ -88,6 +88,9 @@ enum class FrameType : uint8_t { INVALID = 0x03, CONFIRM = 0x05, GET_DEVICE_VERSION = 0x61, + GET_DEVICE_VERSION_RESPONSE = 0x62, + GET_DEVICE_ID = 0x70, + GET_DEVICE_ID_RESPONSE = 0x71, REPORT_NETWORK_STATUS = 0xF7, NO_COMMAND = 0xFF, }; diff --git a/platformio.ini b/platformio.ini index ba149ce99e..5da3b9f978 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,7 +39,7 @@ lib_deps = bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 - pavlodn/HaierProtocol@0.9.18 ; haier + pavlodn/HaierProtocol@0.9.20 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library build_flags = From 1269bf979166e6624a9e92b01de1a9e84cb8024e Mon Sep 17 00:00:00 2001 From: Steve Rodgers Date: Fri, 11 Aug 2023 17:50:33 -0700 Subject: [PATCH 0338/2607] pca9554 cache reads (#5137) --- esphome/components/pca9554/pca9554.cpp | 25 +++++++++++++++++++++++-- esphome/components/pca9554/pca9554.h | 6 ++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index 39093fcf54..74c64dffaa 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -26,7 +26,7 @@ void PCA9554Component::setup() { this->config_mask_ = 0; // Invert mask as the part sees a 1 as an input this->write_register_(CONFIG_REG, ~this->config_mask_); - // All ouputs low + // All outputs low this->output_mask_ = 0; this->write_register_(OUTPUT_REG, this->output_mask_); // Read the inputs @@ -34,6 +34,14 @@ void PCA9554Component::setup() { ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), this->status_has_error()); } + +void PCA9554Component::loop() { + // The read_inputs_() method will cache the input values from the chip. + this->read_inputs_(); + // Clear all the previously read flags. + this->was_previously_read_ = 0x00; +} + void PCA9554Component::dump_config() { ESP_LOGCONFIG(TAG, "PCA9554:"); LOG_I2C_DEVICE(this) @@ -43,7 +51,16 @@ void PCA9554Component::dump_config() { } bool PCA9554Component::digital_read(uint8_t pin) { - this->read_inputs_(); + // Note: We want to try and avoid doing any I2C bus read transactions here + // to conserve I2C bus bandwidth. So what we do is check to see if we + // have seen a read during the time esphome is running this loop. If we have, + // we do an I2C bus transaction to get the latest value. If we haven't + // we return a cached value which was read at the time loop() was called. + if (this->was_previously_read_ & (1 << pin)) + this->read_inputs_(); // Force a read of a new value + // Indicate we saw a read request for this pin in case a + // read happens later in the same loop. + this->was_previously_read_ |= (1 << pin); return this->input_mask_ & (1 << pin); } @@ -98,6 +115,10 @@ bool PCA9554Component::write_register_(uint8_t reg, uint8_t value) { float PCA9554Component::get_setup_priority() const { return setup_priority::IO; } +// Run our loop() method very early in the loop, so that we cache read values before +// before other components call our digital_read() method. +float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI + void PCA9554GPIOPin::setup() { pin_mode(flags_); } void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } diff --git a/esphome/components/pca9554/pca9554.h b/esphome/components/pca9554/pca9554.h index d1bfc36bec..c2aa5c30ed 100644 --- a/esphome/components/pca9554/pca9554.h +++ b/esphome/components/pca9554/pca9554.h @@ -13,6 +13,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { /// Check i2c availability and setup masks void setup() override; + /// Poll for input changes periodically + void loop() override; /// Helper function to read the value of a pin. bool digital_read(uint8_t pin); /// Helper function to write the value of a pin. @@ -22,6 +24,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { float get_setup_priority() const override; + float get_loop_priority() const override; + void dump_config() override; protected: @@ -35,6 +39,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { uint8_t output_mask_{0x00}; /// The state of the actual input pin states - 1 means HIGH, 0 means LOW uint8_t input_mask_{0x00}; + /// Flags to check if read previously during this loop + uint8_t was_previously_read_ = {0x00}; /// Storage for last I2C error seen esphome::i2c::ErrorCode last_error_; }; From 0daf4545a9036293b2035a90730704774cefcdb2 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 14 Aug 2023 01:06:04 +0400 Subject: [PATCH 0339/2607] fix midea: undo approved PR#4053 (#5233) --- esphome/components/remote_base/__init__.py | 18 +++++++---------- .../components/remote_base/midea_protocol.h | 20 +++++-------------- tests/test1.yaml | 2 ++ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 24993e84d3..9e46506b3c 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1488,11 +1488,9 @@ MideaData, MideaBinarySensor, MideaTrigger, MideaAction, MideaDumper = declare_p MideaAction = ns.class_("MideaAction", RemoteTransmitterActionBase) MIDEA_SCHEMA = cv.Schema( { - cv.Required(CONF_CODE): cv.templatable( - cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=5, max=5), - ) + cv.Required(CONF_CODE): cv.All( + [cv.Any(cv.hex_uint8_t, cv.uint8_t)], + cv.Length(min=5, max=5), ), } ) @@ -1519,12 +1517,10 @@ def midea_dumper(var, config): MIDEA_SCHEMA, ) async def midea_action(var, config, args): - code_ = config[CONF_CODE] - if cg.is_template(code_): - template_ = await cg.templatable(code_, args, cg.std_vector.template(cg.uint8)) - cg.add(var.set_code_template(template_)) - else: - cg.add(var.set_code_static(code_)) + template_ = await cg.templatable( + config[CONF_CODE], args, cg.std_vector.template(cg.uint8) + ) + cg.add(var.set_code(template_)) # AEHA diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index d81a50241b..f5db313579 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -1,11 +1,11 @@ #pragma once +#include +#include + #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "remote_base.h" -#include -#include -#include namespace esphome { namespace remote_base { @@ -84,23 +84,13 @@ using MideaDumper = RemoteReceiverDumper; template class MideaAction : public RemoteTransmitterActionBase { TEMPLATABLE_VALUE(std::vector, code) - void set_code_static(std::vector code) { code_static_ = std::move(code); } - void set_code_template(std::function(Ts...)> func) { this->code_func_ = func; } + void set_code(std::initializer_list code) { this->code_ = code; } void encode(RemoteTransmitData *dst, Ts... x) override { - MideaData data; - if (!this->code_static_.empty()) { - data = MideaData(this->code_static_); - } else { - data = MideaData(this->code_func_(x...)); - } + MideaData data(this->code_.value(x...)); data.finalize(); MideaProtocol().encode(dst, data); } - - protected: - std::function(Ts...)> code_func_{}; - std::vector code_static_{}; }; } // namespace remote_base diff --git a/tests/test1.yaml b/tests/test1.yaml index 5c9b83a915..4eb78515c9 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2333,6 +2333,8 @@ switch: second: !lambda "return 0xB21F98;" - remote_transmitter.transmit_midea: code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF] + - remote_transmitter.transmit_midea: + code: !lambda "return {0xA2, 0x08, 0xFF, 0xFF, 0xFF};" - platform: gpio name: "MCP23S08 Pin #0" pin: From 08013be6dd9136957878639a7d981d3dd0c09c70 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Sun, 13 Aug 2023 23:08:18 +0200 Subject: [PATCH 0340/2607] Fixing smartair2 protocol implementation if no Wi-Fi (#5238) --- esphome/components/haier/smartair2_climate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 91b6bb0545..8bee37dadf 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -178,7 +178,9 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) break; #else case ProtocolPhases::SENDING_SIGNAL_LEVEL: - case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER this->set_phase(ProtocolPhases::IDLE); break; + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + this->set_phase(ProtocolPhases::IDLE); + break; #endif case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: From 4c1af007ca9f90a64683b2dfd5c18eb209bfde6c Mon Sep 17 00:00:00 2001 From: Kjell Braden Date: Sun, 13 Aug 2023 23:09:51 +0200 Subject: [PATCH 0341/2607] tuya: add time sync callback only once to prevent memleak (#5234) --- esphome/components/tuya/tuya.cpp | 9 +++++++-- esphome/components/tuya/tuya.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 7e6b1d53fe..0fad151488 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -246,8 +246,13 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff #ifdef USE_TIME if (this->time_id_.has_value()) { this->send_local_time_(); - auto *time_id = *this->time_id_; - time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); + + if (!this->time_sync_callback_registered_) { + // tuya mcu supports time, so we let them know when our time changed + auto *time_id = *this->time_id_; + time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); + this->time_sync_callback_registered_ = true; + } } else { ESP_LOGW(TAG, "LOCAL_TIME_QUERY is not handled because time is not configured"); } diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index b9901dd5e7..26f6f65912 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -130,6 +130,7 @@ class Tuya : public Component, public uart::UARTDevice { #ifdef USE_TIME void send_local_time_(); optional time_id_{}; + bool time_sync_callback_registered_{false}; #endif TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; bool init_failed_{false}; From 2dd4aa7bf677073463a14ef8147c129ace19cf95 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:09:20 +1200 Subject: [PATCH 0342/2607] Fix duplicate tuya time warning (#5243) --- esphome/components/tuya/tuya.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 0fad151488..daf5080e7a 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -1,9 +1,9 @@ #include "tuya.h" #include "esphome/components/network/util.h" +#include "esphome/core/gpio.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/core/util.h" -#include "esphome/core/gpio.h" #ifdef USE_WIFI #include "esphome/components/wifi/wifi_component.h" @@ -253,12 +253,11 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); this->time_sync_callback_registered_ = true; } - } else { + } else +#endif + { ESP_LOGW(TAG, "LOCAL_TIME_QUERY is not handled because time is not configured"); } -#else - ESP_LOGE(TAG, "LOCAL_TIME_QUERY is not handled"); -#endif break; case TuyaCommandType::VACUUM_MAP_UPLOAD: this->send_command_( From 44a917929d5d3af8d803c8363e5031f56be42b7c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:20:58 +1200 Subject: [PATCH 0343/2607] Read string of bool env and match against well known values (#5232) --- esphome/helpers.py | 9 ++++++++- tests/unit_tests/test_helpers.py | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/helpers.py b/esphome/helpers.py index fd8893ad99..4012b2067f 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -144,7 +144,14 @@ def resolve_ip_address(host): def get_bool_env(var, default=False): - return bool(os.getenv(var, default)) + value = os.getenv(var, default) + if isinstance(value, str): + value = value.lower() + if value in ["1", "true"]: + return True + if value in ["0", "false"]: + return False + return bool(value) def get_str_env(var, default=None): diff --git a/tests/unit_tests/test_helpers.py b/tests/unit_tests/test_helpers.py index b98838024f..67fabd7af8 100644 --- a/tests/unit_tests/test_helpers.py +++ b/tests/unit_tests/test_helpers.py @@ -108,6 +108,10 @@ def test_is_ip_address__valid(value): ("FOO", None, False, False), ("FOO", None, True, True), ("FOO", "", False, False), + ("FOO", "False", False, False), + ("FOO", "True", False, True), + ("FOO", "FALSE", True, False), + ("FOO", "fAlSe", True, False), ("FOO", "Yes", False, True), ("FOO", "123", False, True), ), From 2fa79a2e2f606b42b33dccc49dae72e97a221a6b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 10 Aug 2023 21:21:24 -0700 Subject: [PATCH 0344/2607] fix aeha data template (#5231) Co-authored-by: Samuel Sieb --- esphome/components/remote_base/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 0666b96d1e..24993e84d3 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1569,4 +1569,7 @@ def aeha_dumper(var, config): async def aeha_action(var, config, args): template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) - cg.add(var.set_data(config[CONF_DATA])) + template_ = await cg.templatable( + config[CONF_DATA], args, cg.std_vector.template(cg.uint8) + ) + cg.add(var.set_data(template_)) From 351e7ea16b0a9af8d126b9019294f53c55d767c9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:21:44 +1200 Subject: [PATCH 0345/2607] Expose start to speaker interface (#5228) --- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h | 2 +- esphome/components/speaker/speaker.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index f2e83142b3..b075722e1b 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -51,7 +51,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud #endif void set_external_dac_channels(uint8_t channels) { this->external_dac_channels_ = channels; } - void start(); + void start() override; void stop() override; size_t play(const uint8_t *data, size_t length) override; diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 53f97da5ac..3f520e3c5e 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -13,8 +13,9 @@ enum State : uint8_t { class Speaker { public: virtual size_t play(const uint8_t *data, size_t length) = 0; - virtual size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } + size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } + virtual void start() = 0; virtual void stop() = 0; bool is_running() const { return this->state_ == STATE_RUNNING; } From 99a765dc0639f559e1a8fcdb9447869f7df78313 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Fri, 11 Aug 2023 07:51:53 +0200 Subject: [PATCH 0346/2607] New features added for Haier integration (#5196) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/haier/climate.py | 74 ++++++- esphome/components/haier/haier_base.cpp | 75 +++++-- esphome/components/haier/haier_base.h | 43 ++-- esphome/components/haier/hon_climate.cpp | 144 ++++++------- esphome/components/haier/hon_climate.h | 5 +- esphome/components/haier/hon_packet.h | 16 +- .../components/haier/smartair2_climate.cpp | 204 +++++++++++++----- esphome/components/haier/smartair2_climate.h | 13 +- esphome/components/haier/smartair2_packet.h | 7 +- platformio.ini | 2 +- 10 files changed, 394 insertions(+), 189 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index c518282bfa..fec39d2967 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -14,7 +14,10 @@ from esphome.const import ( CONF_MIN_TEMPERATURE, CONF_PROTOCOL, CONF_SUPPORTED_MODES, + CONF_SUPPORTED_PRESETS, CONF_SUPPORTED_SWING_MODES, + CONF_TARGET_TEMPERATURE, + CONF_TEMPERATURE_STEP, CONF_VISUAL, CONF_WIFI, DEVICE_CLASS_TEMPERATURE, @@ -23,25 +26,29 @@ from esphome.const import ( UNIT_CELSIUS, ) from esphome.components.climate import ( - ClimateSwingMode, ClimateMode, + ClimatePreset, + ClimateSwingMode, + CONF_CURRENT_TEMPERATURE, ) _LOGGER = logging.getLogger(__name__) PROTOCOL_MIN_TEMPERATURE = 16.0 PROTOCOL_MAX_TEMPERATURE = 30.0 -PROTOCOL_TEMPERATURE_STEP = 1.0 +PROTOCOL_TARGET_TEMPERATURE_STEP = 1.0 +PROTOCOL_CURRENT_TEMPERATURE_STEP = 0.5 CODEOWNERS = ["@paveldn"] AUTO_LOAD = ["sensor"] DEPENDENCIES = ["climate", "uart"] CONF_WIFI_SIGNAL = "wifi_signal" +CONF_ANSWER_TIMEOUT = "answer_timeout" +CONF_DISPLAY = "display" CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_VERTICAL_AIRFLOW = "vertical_airflow" CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow" - PROTOCOL_HON = "HON" PROTOCOL_SMARTAIR2 = "SMARTAIR2" PROTOCOLS_SUPPORTED = [PROTOCOL_HON, PROTOCOL_SMARTAIR2] @@ -89,6 +96,17 @@ SUPPORTED_CLIMATE_MODES_OPTIONS = { "FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY, } +SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS = { + "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, + "COMFORT": ClimatePreset.CLIMATE_PRESET_COMFORT, +} + +SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS = { + "ECO": ClimatePreset.CLIMATE_PRESET_ECO, + "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, + "SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP, +} + def validate_visual(config): if CONF_VISUAL in config: @@ -109,10 +127,29 @@ def validate_visual(config): ) else: config[CONF_VISUAL][CONF_MAX_TEMPERATURE] = PROTOCOL_MAX_TEMPERATURE + if CONF_TEMPERATURE_STEP in visual_config: + temp_step = config[CONF_VISUAL][CONF_TEMPERATURE_STEP][ + CONF_TARGET_TEMPERATURE + ] + if ((int)(temp_step * 2)) / 2 != temp_step: + raise cv.Invalid( + f"Configured visual temperature step {temp_step} is wrong, it should be a multiple of 0.5" + ) + else: + config[CONF_VISUAL][CONF_TEMPERATURE_STEP] = ( + { + CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, + CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, + }, + ) else: config[CONF_VISUAL] = { CONF_MIN_TEMPERATURE: PROTOCOL_MIN_TEMPERATURE, CONF_MAX_TEMPERATURE: PROTOCOL_MAX_TEMPERATURE, + CONF_TEMPERATURE_STEP: { + CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, + CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, + }, } return config @@ -132,6 +169,11 @@ BASE_CONFIG_SCHEMA = ( "BOTH", ], ): cv.ensure_list(cv.enum(SUPPORTED_SWING_MODES_OPTIONS, upper=True)), + cv.Optional(CONF_WIFI_SIGNAL, default=False): cv.boolean, + cv.Optional(CONF_DISPLAY): cv.boolean, + cv.Optional( + CONF_ANSWER_TIMEOUT, + ): cv.positive_time_period_milliseconds, } ) .extend(uart.UART_DEVICE_SCHEMA) @@ -144,13 +186,26 @@ CONFIG_SCHEMA = cv.All( PROTOCOL_SMARTAIR2: BASE_CONFIG_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(Smartair2Climate), + cv.Optional( + CONF_SUPPORTED_PRESETS, + default=list( + SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS.keys() + ), + ): cv.ensure_list( + cv.enum(SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS, upper=True) + ), } ), PROTOCOL_HON: BASE_CONFIG_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(HonClimate), - cv.Optional(CONF_WIFI_SIGNAL, default=True): cv.boolean, cv.Optional(CONF_BEEPER, default=True): cv.boolean, + cv.Optional( + CONF_SUPPORTED_PRESETS, + default=list(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS.keys()), + ): cv.ensure_list( + cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True) + ), cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, icon=ICON_THERMOMETER, @@ -354,10 +409,11 @@ async def to_code(config): await uart.register_uart_device(var, config) await climate.register_climate(var, config) - if (CONF_WIFI_SIGNAL in config) and (config[CONF_WIFI_SIGNAL]): - cg.add(var.set_send_wifi(config[CONF_WIFI_SIGNAL])) + cg.add(var.set_send_wifi(config[CONF_WIFI_SIGNAL])) if CONF_BEEPER in config: cg.add(var.set_beeper_state(config[CONF_BEEPER])) + if CONF_DISPLAY in config: + cg.add(var.set_display_state(config[CONF_DISPLAY])) if CONF_OUTDOOR_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) cg.add(var.set_outdoor_temperature_sensor(sens)) @@ -365,5 +421,9 @@ async def to_code(config): cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES])) if CONF_SUPPORTED_SWING_MODES in config: cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES])) + if CONF_SUPPORTED_PRESETS in config: + cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS])) + if CONF_ANSWER_TIMEOUT in config: + cg.add(var.set_answer_timeout(config[CONF_ANSWER_TIMEOUT])) # https://github.com/paveldn/HaierProtocol - cg.add_library("pavlodn/HaierProtocol", "0.9.18") + cg.add_library("pavlodn/HaierProtocol", "0.9.20") diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index d9349cb8fe..5faee5207b 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -2,6 +2,9 @@ #include #include "esphome/components/climate/climate.h" #include "esphome/components/uart/uart.h" +#ifdef USE_WIFI +#include "esphome/components/wifi/wifi_component.h" +#endif #include "haier_base.h" using namespace esphome::climate; @@ -24,14 +27,15 @@ constexpr size_t NO_COMMAND = 0xFF; // Indicate that there is no command suppli const char *HaierClimateBase::phase_to_string_(ProtocolPhases phase) { static const char *phase_names[] = { "SENDING_INIT_1", - "WAITING_ANSWER_INIT_1", + "WAITING_INIT_1_ANSWER", "SENDING_INIT_2", - "WAITING_ANSWER_INIT_2", + "WAITING_INIT_2_ANSWER", "SENDING_FIRST_STATUS_REQUEST", "WAITING_FIRST_STATUS_ANSWER", "SENDING_ALARM_STATUS_REQUEST", "WAITING_ALARM_STATUS_ANSWER", "IDLE", + "UNKNOWN", "SENDING_STATUS_REQUEST", "WAITING_STATUS_ANSWER", "SENDING_UPDATE_SIGNAL_REQUEST", @@ -63,7 +67,8 @@ HaierClimateBase::HaierClimateBase() forced_publish_(false), forced_request_status_(false), first_control_attempt_(false), - reset_protocol_request_(false) { + reset_protocol_request_(false), + send_wifi_signal_(true) { this->traits_ = climate::ClimateTraits(); this->traits_.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, @@ -77,7 +82,7 @@ HaierClimateBase::HaierClimateBase() HaierClimateBase::~HaierClimateBase() {} -void HaierClimateBase::set_phase_(ProtocolPhases phase) { +void HaierClimateBase::set_phase(ProtocolPhases phase) { if (this->protocol_phase_ != phase) { #if (HAIER_LOG_LEVEL > 4) ESP_LOGV(TAG, "Phase transition: %s => %s", phase_to_string_(this->protocol_phase_), phase_to_string_(phase)); @@ -109,10 +114,27 @@ bool HaierClimateBase::is_control_message_interval_exceeded_(std::chrono::steady return this->check_timeout_(now, this->last_request_timestamp_, CONTROL_MESSAGES_INTERVAL_MS); } -bool HaierClimateBase::is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now) { +bool HaierClimateBase::is_protocol_initialisation_interval_exceeded_(std::chrono::steady_clock::time_point now) { return this->check_timeout_(now, this->last_request_timestamp_, PROTOCOL_INITIALIZATION_INTERVAL); } +#ifdef USE_WIFI +haier_protocol::HaierMessage HaierClimateBase::get_wifi_signal_message_(uint8_t message_type) { + static uint8_t wifi_status_data[4] = {0x00, 0x00, 0x00, 0x00}; + if (wifi::global_wifi_component->is_connected()) { + wifi_status_data[1] = 0; + int8_t rssi = wifi::global_wifi_component->wifi_rssi(); + wifi_status_data[3] = uint8_t((128 + rssi) / 1.28f); + ESP_LOGD(TAG, "WiFi signal is: %ddBm => %d%%", rssi, wifi_status_data[3]); + } else { + ESP_LOGD(TAG, "WiFi is not connected"); + wifi_status_data[1] = 1; + wifi_status_data[3] = 0; + } + return haier_protocol::HaierMessage(message_type, wifi_status_data, sizeof(wifi_status_data)); +} +#endif + bool HaierClimateBase::get_display_state() const { return this->display_status_; } void HaierClimateBase::set_display_state(bool state) { @@ -136,10 +158,15 @@ void HaierClimateBase::send_power_on_command() { this->action_request_ = ActionR void HaierClimateBase::send_power_off_command() { this->action_request_ = ActionRequest::TURN_POWER_OFF; } void HaierClimateBase::toggle_power() { this->action_request_ = ActionRequest::TOGGLE_POWER; } + void HaierClimateBase::set_supported_swing_modes(const std::set &modes) { this->traits_.set_supported_swing_modes(modes); - this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); // Always available - this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); // Always available + if (!modes.empty()) + this->traits_.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); +} + +void HaierClimateBase::set_answer_timeout(uint32_t timeout) { + this->answer_timeout_ = std::chrono::milliseconds(timeout); } void HaierClimateBase::set_supported_modes(const std::set &modes) { @@ -148,6 +175,14 @@ void HaierClimateBase::set_supported_modes(const std::set this->traits_.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Always available } +void HaierClimateBase::set_supported_presets(const std::set &presets) { + this->traits_.set_supported_presets(presets); + if (!presets.empty()) + this->traits_.add_supported_preset(climate::CLIMATE_PRESET_NONE); +} + +void HaierClimateBase::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; } + haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(uint8_t request_message_type, uint8_t expected_request_message_type, uint8_t answer_message_type, @@ -155,9 +190,9 @@ haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(uint8_t reques ProtocolPhases expected_phase) { haier_protocol::HandlerError result = haier_protocol::HandlerError::HANDLER_OK; if ((expected_request_message_type != NO_COMMAND) && (request_message_type != expected_request_message_type)) - result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + result = haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; if ((expected_answer_message_type != NO_COMMAND) && (answer_message_type != expected_answer_message_type)) - result = haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + result = haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; if ((expected_phase != ProtocolPhases::UNKNOWN) && (expected_phase != this->protocol_phase_)) result = haier_protocol::HandlerError::UNEXPECTED_MESSAGE; if (is_message_invalid(answer_message_type)) @@ -172,9 +207,9 @@ haier_protocol::HandlerError HaierClimateBase::timeout_default_handler_(uint8_t ESP_LOGW(TAG, "Answer timeout for command %02X, phase %d", request_type, (int) this->protocol_phase_); #endif if (this->protocol_phase_ > ProtocolPhases::IDLE) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else { - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); } return haier_protocol::HandlerError::HANDLER_OK; } @@ -183,8 +218,8 @@ void HaierClimateBase::setup() { ESP_LOGI(TAG, "Haier initialization..."); // Set timestamp here to give AC time to boot this->last_request_timestamp_ = std::chrono::steady_clock::now(); - this->set_phase_(ProtocolPhases::SENDING_INIT_1); - this->set_answers_handlers(); + this->set_phase(ProtocolPhases::SENDING_INIT_1); + this->set_handlers(); this->haier_protocol_.set_default_timeout_handler( std::bind(&esphome::haier::HaierClimateBase::timeout_default_handler_, this, std::placeholders::_1)); } @@ -212,7 +247,7 @@ void HaierClimateBase::loop() { this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); return; } else { // No need to reset protocol if we didn't pass initialization phase @@ -229,7 +264,7 @@ void HaierClimateBase::loop() { this->process_pending_action(); } else if (this->hvac_settings_.valid || this->force_send_control_) { ESP_LOGV(TAG, "Control packet is pending..."); - this->set_phase_(ProtocolPhases::SENDING_CONTROL); + this->set_phase(ProtocolPhases::SENDING_CONTROL); } } this->process_phase(now); @@ -243,10 +278,10 @@ void HaierClimateBase::process_pending_action() { } switch (request) { case ActionRequest::TURN_POWER_ON: - this->set_phase_(ProtocolPhases::SENDING_POWER_ON_COMMAND); + this->set_phase(ProtocolPhases::SENDING_POWER_ON_COMMAND); break; case ActionRequest::TURN_POWER_OFF: - this->set_phase_(ProtocolPhases::SENDING_POWER_OFF_COMMAND); + this->set_phase(ProtocolPhases::SENDING_POWER_OFF_COMMAND); break; case ActionRequest::TOGGLE_POWER: case ActionRequest::NO_ACTION: @@ -303,7 +338,11 @@ void HaierClimateBase::set_force_send_control_(bool status) { } void HaierClimateBase::send_message_(const haier_protocol::HaierMessage &command, bool use_crc) { - this->haier_protocol_.send_message(command, use_crc); + if (this->answer_timeout_.has_value()) { + this->haier_protocol_.send_message(command, use_crc, this->answer_timeout_.value()); + } else { + this->haier_protocol_.send_message(command, use_crc); + } this->last_request_timestamp_ = std::chrono::steady_clock::now(); } diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index 046b59af96..b2446d6fb5 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -44,6 +44,7 @@ class HaierClimateBase : public esphome::Component, void reset_protocol() { this->reset_protocol_request_ = true; }; void set_supported_modes(const std::set &modes); void set_supported_swing_modes(const std::set &modes); + void set_supported_presets(const std::set &presets); size_t available() noexcept override { return esphome::uart::UARTDevice::available(); }; size_t read_array(uint8_t *data, size_t len) noexcept override { return esphome::uart::UARTDevice::read_array(data, len) ? len : 0; @@ -52,39 +53,41 @@ class HaierClimateBase : public esphome::Component, esphome::uart::UARTDevice::write_array(data, len); }; bool can_send_message() const { return haier_protocol_.get_outgoing_queue_size() == 0; }; + void set_answer_timeout(uint32_t timeout); + void set_send_wifi(bool send_wifi); protected: enum class ProtocolPhases { UNKNOWN = -1, // INITIALIZATION SENDING_INIT_1 = 0, - WAITING_ANSWER_INIT_1 = 1, + WAITING_INIT_1_ANSWER = 1, SENDING_INIT_2 = 2, - WAITING_ANSWER_INIT_2 = 3, + WAITING_INIT_2_ANSWER = 3, SENDING_FIRST_STATUS_REQUEST = 4, WAITING_FIRST_STATUS_ANSWER = 5, SENDING_ALARM_STATUS_REQUEST = 6, WAITING_ALARM_STATUS_ANSWER = 7, // FUNCTIONAL STATE IDLE = 8, - SENDING_STATUS_REQUEST = 9, - WAITING_STATUS_ANSWER = 10, - SENDING_UPDATE_SIGNAL_REQUEST = 11, - WAITING_UPDATE_SIGNAL_ANSWER = 12, - SENDING_SIGNAL_LEVEL = 13, - WAITING_SIGNAL_LEVEL_ANSWER = 14, - SENDING_CONTROL = 15, - WAITING_CONTROL_ANSWER = 16, - SENDING_POWER_ON_COMMAND = 17, - WAITING_POWER_ON_ANSWER = 18, - SENDING_POWER_OFF_COMMAND = 19, - WAITING_POWER_OFF_ANSWER = 20, + SENDING_STATUS_REQUEST = 10, + WAITING_STATUS_ANSWER = 11, + SENDING_UPDATE_SIGNAL_REQUEST = 12, + WAITING_UPDATE_SIGNAL_ANSWER = 13, + SENDING_SIGNAL_LEVEL = 14, + WAITING_SIGNAL_LEVEL_ANSWER = 15, + SENDING_CONTROL = 16, + WAITING_CONTROL_ANSWER = 17, + SENDING_POWER_ON_COMMAND = 18, + WAITING_POWER_ON_ANSWER = 19, + SENDING_POWER_OFF_COMMAND = 20, + WAITING_POWER_OFF_ANSWER = 21, NUM_PROTOCOL_PHASES }; #if (HAIER_LOG_LEVEL > 4) const char *phase_to_string_(ProtocolPhases phase); #endif - virtual void set_answers_handlers() = 0; + virtual void set_handlers() = 0; virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; virtual haier_protocol::HaierMessage get_control_message() = 0; virtual bool is_message_invalid(uint8_t message_type) = 0; @@ -99,14 +102,17 @@ class HaierClimateBase : public esphome::Component, // Helper functions void set_force_send_control_(bool status); void send_message_(const haier_protocol::HaierMessage &command, bool use_crc); - void set_phase_(ProtocolPhases phase); + virtual void set_phase(ProtocolPhases phase); bool check_timeout_(std::chrono::steady_clock::time_point now, std::chrono::steady_clock::time_point tpoint, size_t timeout); bool is_message_interval_exceeded_(std::chrono::steady_clock::time_point now); bool is_status_request_interval_exceeded_(std::chrono::steady_clock::time_point now); bool is_control_message_timeout_exceeded_(std::chrono::steady_clock::time_point now); bool is_control_message_interval_exceeded_(std::chrono::steady_clock::time_point now); - bool is_protocol_initialisation_interval_exceded_(std::chrono::steady_clock::time_point now); + bool is_protocol_initialisation_interval_exceeded_(std::chrono::steady_clock::time_point now); +#ifdef USE_WIFI + haier_protocol::HaierMessage get_wifi_signal_message_(uint8_t message_type); +#endif struct HvacSettings { esphome::optional mode; @@ -136,6 +142,9 @@ class HaierClimateBase : public esphome::Component, std::chrono::steady_clock::time_point last_valid_status_timestamp_; // For protocol timeout std::chrono::steady_clock::time_point last_status_request_; // To request AC status std::chrono::steady_clock::time_point control_request_timestamp_; // To send control message + optional answer_timeout_; // Message answer timeout + bool send_wifi_signal_; + std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level }; } // namespace haier diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 3950b34724..feb1e019d8 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -2,9 +2,6 @@ #include #include "esphome/components/climate/climate.h" #include "esphome/components/uart/uart.h" -#ifdef USE_WIFI -#include "esphome/components/wifi/wifi_component.h" -#endif #include "hon_climate.h" #include "hon_packet.h" @@ -58,14 +55,7 @@ HonClimate::HonClimate() hvac_functions_{false, false, false, false, false}, use_crc_(hvac_functions_[2]), active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - outdoor_sensor_(nullptr), - send_wifi_signal_(true) { - this->traits_.set_supported_presets({ - climate::CLIMATE_PRESET_NONE, - climate::CLIMATE_PRESET_ECO, - climate::CLIMATE_PRESET_BOOST, - climate::CLIMATE_PRESET_SLEEP, - }); + outdoor_sensor_(nullptr) { this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID; this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO; } @@ -121,17 +111,22 @@ void HonClimate::start_steri_cleaning() { } } -void HonClimate::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; } - haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size) { + // Should check this before preprocess + if (message_type == (uint8_t) hon_protocol::FrameType::INVALID) { + ESP_LOGW(TAG, "It looks like your ESPHome Haier climate configuration is wrong. You should use the smartAir2 " + "protocol instead of hOn"); + this->set_phase(ProtocolPhases::SENDING_INIT_1); + return haier_protocol::HandlerError::INVALID_ANSWER; + } haier_protocol::HandlerError result = this->answer_preprocess_( request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, message_type, - (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_1); + (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE, ProtocolPhases::WAITING_INIT_1_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { if (data_size < sizeof(hon_protocol::DeviceVersionAnswer)) { // Wrong structure - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; } // All OK @@ -152,11 +147,11 @@ haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(uint this->hvac_functions_[3] = (answr->functions[1] & 0x08) != 0; // multiple AC support this->hvac_functions_[4] = (answr->functions[1] & 0x20) != 0; // roles support this->hvac_hardware_info_available_ = true; - this->set_phase_(ProtocolPhases::SENDING_INIT_2); + this->set_phase(ProtocolPhases::SENDING_INIT_2); return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -165,13 +160,13 @@ haier_protocol::HandlerError HonClimate::get_device_id_answer_handler_(uint8_t r const uint8_t *data, size_t data_size) { haier_protocol::HandlerError result = this->answer_preprocess_( request_type, (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID, message_type, - (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID_RESPONSE, ProtocolPhases::WAITING_ANSWER_INIT_2); + (uint8_t) hon_protocol::FrameType::GET_DEVICE_ID_RESPONSE, ProtocolPhases::WAITING_INIT_2_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -185,8 +180,8 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u result = this->process_status_message_(data, data_size); if (result != haier_protocol::HandlerError::HANDLER_OK) { ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); } else { if (data_size >= sizeof(hon_protocol::HaierPacketControl) + 2) { memcpy(this->last_status_message_.get(), data + 2, sizeof(hon_protocol::HaierPacketControl)); @@ -196,13 +191,13 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u } if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { ESP_LOGI(TAG, "First HVAC status received"); - this->set_phase_(ProtocolPhases::SENDING_ALARM_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_ALARM_STATUS_REQUEST); } else if ((this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) || (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_ON_ANSWER) || (this->protocol_phase_ == ProtocolPhases::WAITING_POWER_OFF_ANSWER)) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); @@ -210,8 +205,8 @@ haier_protocol::HandlerError HonClimate::status_handler_(uint8_t request_type, u } return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_INIT_1); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_INIT_1); return result; } } @@ -225,10 +220,10 @@ haier_protocol::HandlerError HonClimate::get_management_information_answer_handl message_type, (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION_RESPONSE, ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); if (result == haier_protocol::HandlerError::HANDLER_OK) { - this->set_phase_(ProtocolPhases::SENDING_SIGNAL_LEVEL); + this->set_phase(ProtocolPhases::SENDING_SIGNAL_LEVEL); return result; } else { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return result; } } @@ -239,7 +234,7 @@ haier_protocol::HandlerError HonClimate::report_network_status_answer_handler_(u haier_protocol::HandlerError result = this->answer_preprocess_(request_type, (uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, message_type, (uint8_t) hon_protocol::FrameType::CONFIRM, ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return result; } @@ -248,24 +243,24 @@ haier_protocol::HandlerError HonClimate::get_alarm_status_answer_handler_(uint8_ if (request_type == (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS) { if (message_type != (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS_RESPONSE) { // Unexpected answer to request - this->set_phase_(ProtocolPhases::IDLE); - return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + this->set_phase(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; } if (this->protocol_phase_ != ProtocolPhases::WAITING_ALARM_STATUS_ANSWER) { // Don't expect this answer now - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return haier_protocol::HandlerError::UNEXPECTED_MESSAGE; } memcpy(this->active_alarms_, data + 2, 8); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); return haier_protocol::HandlerError::HANDLER_OK; } else { - this->set_phase_(ProtocolPhases::IDLE); - return haier_protocol::HandlerError::UNSUPORTED_MESSAGE; + this->set_phase(ProtocolPhases::IDLE); + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; } } -void HonClimate::set_answers_handlers() { +void HonClimate::set_handlers() { // Set handlers this->haier_protocol_.set_answer_handler( (uint8_t) (hon_protocol::FrameType::GET_DEVICE_VERSION), @@ -311,7 +306,7 @@ void HonClimate::dump_config() { void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { switch (this->protocol_phase_) { case ProtocolPhases::SENDING_INIT_1: - if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { + if (this->can_send_message() && this->is_protocol_initialisation_interval_exceeded_(now)) { this->hvac_hardware_info_available_ = false; // Indicate device capabilities: // bit 0 - if 1 module support interactive mode @@ -323,24 +318,24 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST( (uint8_t) hon_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, sizeof(module_capabilities)); this->send_message_(DEVICE_VERSION_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_1); + this->set_phase(ProtocolPhases::WAITING_INIT_1_ANSWER); } break; case ProtocolPhases::SENDING_INIT_2: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage DEVICEID_REQUEST((uint8_t) hon_protocol::FrameType::GET_DEVICE_ID); this->send_message_(DEVICEID_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ANSWER_INIT_2); + this->set_phase(ProtocolPhases::WAITING_INIT_2_ANSWER); } break; case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: case ProtocolPhases::SENDING_STATUS_REQUEST: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage STATUS_REQUEST( - (uint8_t) hon_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcomandsControl::GET_USER_DATA); + (uint8_t) hon_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::GET_USER_DATA); this->send_message_(STATUS_REQUEST, this->use_crc_); this->last_status_request_ = now; - this->set_phase_((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); + this->set_phase((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); } break; #ifdef USE_WIFI @@ -350,26 +345,14 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { (uint8_t) hon_protocol::FrameType::GET_MANAGEMENT_INFORMATION); this->send_message_(UPDATE_SIGNAL_REQUEST, this->use_crc_); this->last_signal_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER); } break; case ProtocolPhases::SENDING_SIGNAL_LEVEL: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { - static uint8_t wifi_status_data[4] = {0x00, 0x00, 0x00, 0x00}; - if (wifi::global_wifi_component->is_connected()) { - wifi_status_data[1] = 0; - int8_t rssi = wifi::global_wifi_component->wifi_rssi(); - wifi_status_data[3] = uint8_t((128 + rssi) / 1.28f); - ESP_LOGD(TAG, "WiFi signal is: %ddBm => %d%%", rssi, wifi_status_data[3]); - } else { - ESP_LOGD(TAG, "WiFi is not connected"); - wifi_status_data[1] = 1; - wifi_status_data[3] = 0; - } - haier_protocol::HaierMessage wifi_status_request((uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS, - wifi_status_data, sizeof(wifi_status_data)); - this->send_message_(wifi_status_request, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + this->send_message_(this->get_wifi_signal_message_((uint8_t) hon_protocol::FrameType::REPORT_NETWORK_STATUS), + this->use_crc_); + this->set_phase(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); } break; case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: @@ -380,7 +363,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { case ProtocolPhases::SENDING_SIGNAL_LEVEL: case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); break; #endif case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: @@ -388,7 +371,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { static const haier_protocol::HaierMessage ALARM_STATUS_REQUEST( (uint8_t) hon_protocol::FrameType::GET_ALARM_STATUS); this->send_message_(ALARM_STATUS_REQUEST, this->use_crc_); - this->set_phase_(ProtocolPhases::WAITING_ALARM_STATUS_ANSWER); + this->set_phase(ProtocolPhases::WAITING_ALARM_STATUS_ANSWER); } break; case ProtocolPhases::SENDING_CONTROL: @@ -403,12 +386,12 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { this->hvac_settings_.reset(); this->forced_request_status_ = true; this->forced_publish_ = true; - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->can_send_message() && this->is_control_message_interval_exceeded_(now)) { haier_protocol::HaierMessage control_message = get_control_message(); this->send_message_(control_message, this->use_crc_); ESP_LOGI(TAG, "Control packet sent"); - this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_CONTROL_ANSWER); } break; case ProtocolPhases::SENDING_POWER_ON_COMMAND: @@ -418,17 +401,17 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { if (this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND) pwr_cmd_buf[1] = 0x01; haier_protocol::HaierMessage power_cmd((uint8_t) hon_protocol::FrameType::CONTROL, - ((uint16_t) hon_protocol::SubcomandsControl::SET_SINGLE_PARAMETER) + 1, + ((uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER) + 1, pwr_cmd_buf, sizeof(pwr_cmd_buf)); this->send_message_(power_cmd, this->use_crc_); - this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND - ? ProtocolPhases::WAITING_POWER_ON_ANSWER - : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + this->set_phase(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); } break; - case ProtocolPhases::WAITING_ANSWER_INIT_1: - case ProtocolPhases::WAITING_ANSWER_INIT_2: + case ProtocolPhases::WAITING_INIT_1_ANSWER: + case ProtocolPhases::WAITING_INIT_2_ANSWER: case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: case ProtocolPhases::WAITING_STATUS_ANSWER: @@ -438,14 +421,14 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { break; case ProtocolPhases::IDLE: { if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { - this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_STATUS_REQUEST); this->forced_request_status_ = false; } #ifdef USE_WIFI else if (this->send_wifi_signal_ && (std::chrono::duration_cast(now - this->last_signal_request_).count() > SIGNAL_LEVEL_UPDATE_INTERVAL_MS)) - this->set_phase_(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); + this->set_phase(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); #endif } break; default: @@ -456,7 +439,7 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) { #else ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); #endif - this->set_phase_(ProtocolPhases::SENDING_INIT_1); + this->set_phase(ProtocolPhases::SENDING_INIT_1); break; } } @@ -551,11 +534,12 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { } } if (climate_control.target_temperature.has_value()) { - out_data->set_point = - climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + float target_temp = climate_control.target_temperature.value(); + out_data->set_point = ((int) target_temp) - 16; // set the temperature at our offset, subtract 16. + out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0; } if (out_data->ac_power == 0) { - // If AC is off - no presets alowed + // If AC is off - no presets allowed out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; @@ -631,7 +615,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { break; } return haier_protocol::HaierMessage((uint8_t) hon_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcomandsControl::SET_GROUP_PARAMETERS, + (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); } @@ -669,7 +653,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * { // Target temperature float old_target_temperature = this->target_temperature; - this->target_temperature = packet.control.set_point + 16.0f; + this->target_temperature = packet.control.set_point + 16.0f + ((packet.control.half_degree == 1) ? 0.5f : 0.0f); should_publish = should_publish || (old_target_temperature != this->target_temperature); } { @@ -747,7 +731,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * if (new_cleaning != this->cleaning_status_) { ESP_LOGD(TAG, "Cleaning status change: %d => %d", (uint8_t) this->cleaning_status_, (uint8_t) new_cleaning); if (new_cleaning == CleaningState::NO_CLEANING) { - // Turnuin AC off after cleaning + // Turning AC off after cleaning this->action_request_ = ActionRequest::TURN_POWER_OFF; } this->cleaning_status_ = new_cleaning; @@ -837,7 +821,7 @@ void HonClimate::process_pending_action() { case ActionRequest::START_SELF_CLEAN: case ActionRequest::START_STERI_CLEAN: // Will reset action with control message sending - this->set_phase_(ProtocolPhases::SENDING_CONTROL); + this->set_phase(ProtocolPhases::SENDING_CONTROL); break; default: HaierClimateBase::process_pending_action(); diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index ab913f44e2..cf566e3b8e 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -48,10 +48,9 @@ class HonClimate : public HaierClimateBase { CleaningState get_cleaning_status() const; void start_self_cleaning(); void start_steri_cleaning(); - void set_send_wifi(bool send_wifi); protected: - void set_answers_handlers() override; + void set_handlers() override; void process_phase(std::chrono::steady_clock::time_point now) override; haier_protocol::HaierMessage get_control_message() override; bool is_message_invalid(uint8_t message_type) override; @@ -87,8 +86,6 @@ class HonClimate : public HaierClimateBase { bool &use_crc_; uint8_t active_alarms_[8]; esphome::sensor::Sensor *outdoor_sensor_; - bool send_wifi_signal_; - std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level }; } // namespace haier diff --git a/esphome/components/haier/hon_packet.h b/esphome/components/haier/hon_packet.h index d572ce80d9..c6b32df200 100644 --- a/esphome/components/haier/hon_packet.h +++ b/esphome/components/haier/hon_packet.h @@ -53,12 +53,12 @@ struct HaierPacketControl { // 13 uint8_t : 8; // 14 - uint8_t ten_degree : 1; // 10 degree status - uint8_t display_status : 1; // If 0 disables AC's display - uint8_t half_degree : 1; // Use half degree - uint8_t intelegence_status : 1; // Intelligence status - uint8_t pmv_status : 1; // Comfort/PMV status - uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius + uint8_t ten_degree : 1; // 10 degree status + uint8_t display_status : 1; // If 0 disables AC's display + uint8_t half_degree : 1; // Use half degree + uint8_t intelligence_status : 1; // Intelligence status + uint8_t pmv_status : 1; // Comfort/PMV status + uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius uint8_t : 1; uint8_t steri_clean : 1; // 15 @@ -153,7 +153,7 @@ enum class FrameType : uint8_t { // <-> device, required) REPORT = 0x06, // Report frame (module <-> device, interactive, required) STOP_FAULT_ALARM = 0x09, // Stop fault alarm frame (module -> device, interactive, required) - SYSTEM_DOWNLIK = 0x11, // System downlink frame (module -> device, optional) + SYSTEM_DOWNLINK = 0x11, // System downlink frame (module -> device, optional) DEVICE_UPLINK = 0x12, // Device uplink frame (module <- device , interactive, optional) SYSTEM_QUERY = 0x13, // System query frame (module -> device, optional) SYSTEM_QUERY_RESPONSE = 0x14, // System query response frame (module <- device , optional) @@ -210,7 +210,7 @@ enum class FrameType : uint8_t { WAKE_UP = 0xFE, // Request to wake up (module <-> device, optional) }; -enum class SubcomandsControl : uint16_t { +enum class SubcommandsControl : uint16_t { GET_PARAMETERS = 0x4C01, // Request specific parameters (packet content: parameter ID1 + parameter ID2 + ...) GET_USER_DATA = 0x4D01, // Request all user data from device (packet content: None) GET_BIG_DATA = 0x4DFE, // Request big data information from device (packet content: None) diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 9c0fbac350..91b6bb0545 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -11,15 +11,10 @@ namespace esphome { namespace haier { static const char *const TAG = "haier.climate"; +constexpr size_t SIGNAL_LEVEL_UPDATE_INTERVAL_MS = 10000; Smartair2Climate::Smartair2Climate() - : last_status_message_(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]) { - this->traits_.set_supported_presets({ - climate::CLIMATE_PRESET_NONE, - climate::CLIMATE_PRESET_BOOST, - climate::CLIMATE_PRESET_COMFORT, - }); -} + : last_status_message_(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]), timeouts_counter_(0) {} haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size) { @@ -30,8 +25,8 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t result = this->process_status_message_(data, data_size); if (result != haier_protocol::HandlerError::HANDLER_OK) { ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result); - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); } else { if (data_size >= sizeof(smartair2_protocol::HaierPacketControl) + 2) { memcpy(this->last_status_message_.get(), data + 2, sizeof(smartair2_protocol::HaierPacketControl)); @@ -41,11 +36,11 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t } if (this->protocol_phase_ == ProtocolPhases::WAITING_FIRST_STATUS_ANSWER) { ESP_LOGI(TAG, "First HVAC status received"); - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_STATUS_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->protocol_phase_ == ProtocolPhases::WAITING_CONTROL_ANSWER) { - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); this->set_force_send_control_(false); if (this->hvac_settings_.valid) this->hvac_settings_.reset(); @@ -53,17 +48,82 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(uint8_t request_t } return result; } else { - this->set_phase_((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE - : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + this->set_phase((this->protocol_phase_ >= ProtocolPhases::IDLE) ? ProtocolPhases::IDLE + : ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); return result; } } -void Smartair2Climate::set_answers_handlers() { +haier_protocol::HandlerError Smartair2Climate::get_device_version_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, + size_t data_size) { + if (request_type != (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION) + return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE; + if (ProtocolPhases::WAITING_INIT_1_ANSWER != this->protocol_phase_) + return haier_protocol::HandlerError::UNEXPECTED_MESSAGE; + // Invalid packet is expected answer + if ((message_type == (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE) && (data_size >= 39) && + ((data[37] & 0x04) != 0)) { + ESP_LOGW(TAG, "It looks like your ESPHome Haier climate configuration is wrong. You should use the hOn protocol " + "instead of smartAir2"); + } + this->set_phase(ProtocolPhases::SENDING_INIT_2); + return haier_protocol::HandlerError::HANDLER_OK; +} + +haier_protocol::HandlerError Smartair2Climate::report_network_status_answer_handler_(uint8_t request_type, + uint8_t message_type, + const uint8_t *data, + size_t data_size) { + haier_protocol::HandlerError result = this->answer_preprocess_( + request_type, (uint8_t) smartair2_protocol::FrameType::REPORT_NETWORK_STATUS, message_type, + (uint8_t) smartair2_protocol::FrameType::CONFIRM, ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + this->set_phase(ProtocolPhases::IDLE); + return result; +} + +haier_protocol::HandlerError Smartair2Climate::initial_messages_timeout_handler_(uint8_t message_type) { + if (this->protocol_phase_ >= ProtocolPhases::IDLE) + return HaierClimateBase::timeout_default_handler_(message_type); + this->timeouts_counter_++; + ESP_LOGI(TAG, "Answer timeout for command %02X, phase %d, timeout counter %d", message_type, + (int) this->protocol_phase_, this->timeouts_counter_); + if (this->timeouts_counter_ >= 3) { + ProtocolPhases new_phase = (ProtocolPhases) ((int) this->protocol_phase_ + 1); + if (new_phase >= ProtocolPhases::SENDING_ALARM_STATUS_REQUEST) + new_phase = ProtocolPhases::SENDING_INIT_1; + this->set_phase(new_phase); + } else { + // Returning to the previous state to try again + this->set_phase((ProtocolPhases) ((int) this->protocol_phase_ - 1)); + } + return haier_protocol::HandlerError::HANDLER_OK; +} + +void Smartair2Climate::set_handlers() { + // Set handlers + this->haier_protocol_.set_answer_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_VERSION), + std::bind(&Smartair2Climate::get_device_version_answer_handler_, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); this->haier_protocol_.set_answer_handler( (uint8_t) (smartair2_protocol::FrameType::CONTROL), std::bind(&Smartair2Climate::status_handler_, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_answer_handler( + (uint8_t) (smartair2_protocol::FrameType::REPORT_NETWORK_STATUS), + std::bind(&Smartair2Climate::report_network_status_answer_handler_, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_ID), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::GET_DEVICE_VERSION), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); + this->haier_protocol_.set_timeout_handler( + (uint8_t) (smartair2_protocol::FrameType::CONTROL), + std::bind(&Smartair2Climate::initial_messages_timeout_handler_, this, std::placeholders::_1)); } void Smartair2Climate::dump_config() { @@ -74,39 +134,60 @@ void Smartair2Climate::dump_config() { void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) { switch (this->protocol_phase_) { case ProtocolPhases::SENDING_INIT_1: - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); - break; - case ProtocolPhases::WAITING_ANSWER_INIT_1: - case ProtocolPhases::SENDING_INIT_2: - case ProtocolPhases::WAITING_ANSWER_INIT_2: - case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: - case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: - this->set_phase_(ProtocolPhases::SENDING_INIT_1); - break; - case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: - case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: - case ProtocolPhases::SENDING_SIGNAL_LEVEL: - case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: - this->set_phase_(ProtocolPhases::IDLE); - break; - case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: - if (this->can_send_message() && this->is_protocol_initialisation_interval_exceded_(now)) { - static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, - 0x4D01); - this->send_message_(STATUS_REQUEST, false); - this->last_status_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_FIRST_STATUS_ANSWER); + if (this->can_send_message() && + (((this->timeouts_counter_ == 0) && (this->is_protocol_initialisation_interval_exceeded_(now))) || + ((this->timeouts_counter_ > 0) && (this->is_message_interval_exceeded_(now))))) { + // Indicate device capabilities: + // bit 0 - if 1 module support interactive mode + // bit 1 - if 1 module support controller-device mode + // bit 2 - if 1 module support crc + // bit 3 - if 1 module support multiple devices + // bit 4..bit 15 - not used + uint8_t module_capabilities[2] = {0b00000000, 0b00000111}; + static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST( + (uint8_t) smartair2_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, + sizeof(module_capabilities)); + this->send_message_(DEVICE_VERSION_REQUEST, false); + this->set_phase(ProtocolPhases::WAITING_INIT_1_ANSWER); } break; + case ProtocolPhases::SENDING_INIT_2: + case ProtocolPhases::WAITING_INIT_2_ANSWER: + this->set_phase(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); + break; + case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: case ProtocolPhases::SENDING_STATUS_REQUEST: if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { static const haier_protocol::HaierMessage STATUS_REQUEST((uint8_t) smartair2_protocol::FrameType::CONTROL, 0x4D01); this->send_message_(STATUS_REQUEST, false); this->last_status_request_ = now; - this->set_phase_(ProtocolPhases::WAITING_STATUS_ANSWER); + this->set_phase((ProtocolPhases) ((uint8_t) this->protocol_phase_ + 1)); } break; +#ifdef USE_WIFI + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { + this->send_message_( + this->get_wifi_signal_message_((uint8_t) smartair2_protocol::FrameType::REPORT_NETWORK_STATUS), false); + this->last_signal_request_ = now; + this->set_phase(ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER); + } + break; + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + break; +#else + case ProtocolPhases::SENDING_SIGNAL_LEVEL: + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER this->set_phase(ProtocolPhases::IDLE); break; +#endif + case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: + case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: + this->set_phase(ProtocolPhases::SENDING_SIGNAL_LEVEL); + break; + case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST: + case ProtocolPhases::WAITING_ALARM_STATUS_ANSWER: + this->set_phase(ProtocolPhases::SENDING_INIT_1); + break; case ProtocolPhases::SENDING_CONTROL: if (this->first_control_attempt_) { this->control_request_timestamp_ = now; @@ -119,14 +200,14 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) this->hvac_settings_.reset(); this->forced_request_status_ = true; this->forced_publish_ = true; - this->set_phase_(ProtocolPhases::IDLE); + this->set_phase(ProtocolPhases::IDLE); } else if (this->can_send_message() && this->is_control_message_interval_exceeded_( now)) // Using CONTROL_MESSAGES_INTERVAL_MS to speedup requests { haier_protocol::HaierMessage control_message = get_control_message(); this->send_message_(control_message, false); ESP_LOGI(TAG, "Control packet sent"); - this->set_phase_(ProtocolPhases::WAITING_CONTROL_ANSWER); + this->set_phase(ProtocolPhases::WAITING_CONTROL_ANSWER); } break; case ProtocolPhases::SENDING_POWER_ON_COMMAND: @@ -136,11 +217,12 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) (uint8_t) smartair2_protocol::FrameType::CONTROL, this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND ? 0x4D02 : 0x4D03); this->send_message_(power_cmd, false); - this->set_phase_(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND - ? ProtocolPhases::WAITING_POWER_ON_ANSWER - : ProtocolPhases::WAITING_POWER_OFF_ANSWER); + this->set_phase(this->protocol_phase_ == ProtocolPhases::SENDING_POWER_ON_COMMAND + ? ProtocolPhases::WAITING_POWER_ON_ANSWER + : ProtocolPhases::WAITING_POWER_OFF_ANSWER); } break; + case ProtocolPhases::WAITING_INIT_1_ANSWER: case ProtocolPhases::WAITING_FIRST_STATUS_ANSWER: case ProtocolPhases::WAITING_STATUS_ANSWER: case ProtocolPhases::WAITING_CONTROL_ANSWER: @@ -149,14 +231,25 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) break; case ProtocolPhases::IDLE: { if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) { - this->set_phase_(ProtocolPhases::SENDING_STATUS_REQUEST); + this->set_phase(ProtocolPhases::SENDING_STATUS_REQUEST); this->forced_request_status_ = false; } +#ifdef USE_WIFI + else if (this->send_wifi_signal_ && + (std::chrono::duration_cast(now - this->last_signal_request_).count() > + SIGNAL_LEVEL_UPDATE_INTERVAL_MS)) + this->set_phase(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST); +#endif } break; default: // Shouldn't get here +#if (HAIER_LOG_LEVEL > 4) + ESP_LOGE(TAG, "Wrong protocol handler state: %s (%d), resetting communication", + phase_to_string_(this->protocol_phase_), (int) this->protocol_phase_); +#else ESP_LOGE(TAG, "Wrong protocol handler state: %d, resetting communication", (int) this->protocol_phase_); - this->set_phase_(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST); +#endif + this->set_phase(ProtocolPhases::SENDING_INIT_1); break; } } @@ -256,11 +349,12 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() { } } if (climate_control.target_temperature.has_value()) { - out_data->set_point = - climate_control.target_temperature.value() - 16; // set the temperature at our offset, subtract 16. + float target_temp = climate_control.target_temperature.value(); + out_data->set_point = target_temp - 16; // set the temperature with offset 16 + out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0; } if (out_data->ac_power == 0) { - // If AC is off - no presets alowed + // If AC is off - no presets allowed out_data->turbo_mode = 0; out_data->quiet_mode = 0; } else if (climate_control.preset.has_value()) { @@ -312,7 +406,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin { // Target temperature float old_target_temperature = this->target_temperature; - this->target_temperature = packet.control.set_point + 16.0f; + this->target_temperature = packet.control.set_point + 16.0f + ((packet.control.half_degree == 1) ? 0.5f : 0.0f); should_publish = should_publish || (old_target_temperature != this->target_temperature); } { @@ -333,7 +427,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin } switch (packet.control.fan_mode) { case (uint8_t) smartair2_protocol::FanMode::FAN_AUTO: - // Somtimes AC reports in fan only mode that fan speed is auto + // Sometimes AC reports in fan only mode that fan speed is auto // but never accept this value back if (packet.control.ac_mode != (uint8_t) smartair2_protocol::ConditioningMode::FAN) { this->fan_mode = CLIMATE_FAN_AUTO; @@ -453,5 +547,15 @@ bool Smartair2Climate::is_message_invalid(uint8_t message_type) { return message_type == (uint8_t) smartair2_protocol::FrameType::INVALID; } +void Smartair2Climate::set_phase(HaierClimateBase::ProtocolPhases phase) { + int old_phase = (int) this->protocol_phase_; + int new_phase = (int) phase; + int min_p = std::min(old_phase, new_phase); + int max_p = std::max(old_phase, new_phase); + if ((min_p % 2 != 0) || (max_p - min_p > 1)) + this->timeouts_counter_ = 0; + HaierClimateBase::set_phase(phase); +} + } // namespace haier } // namespace esphome diff --git a/esphome/components/haier/smartair2_climate.h b/esphome/components/haier/smartair2_climate.h index c89d1f0be9..f173b10749 100644 --- a/esphome/components/haier/smartair2_climate.h +++ b/esphome/components/haier/smartair2_climate.h @@ -15,16 +15,25 @@ class Smartair2Climate : public HaierClimateBase { void dump_config() override; protected: - void set_answers_handlers() override; + void set_handlers() override; void process_phase(std::chrono::steady_clock::time_point now) override; haier_protocol::HaierMessage get_control_message() override; bool is_message_invalid(uint8_t message_type) override; - // Answers handlers + void set_phase(HaierClimateBase::ProtocolPhases phase) override; + // Answer and timeout handlers haier_protocol::HandlerError status_handler_(uint8_t request_type, uint8_t message_type, const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_device_version_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError get_device_id_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError report_network_status_answer_handler_(uint8_t request_type, uint8_t message_type, + const uint8_t *data, size_t data_size); + haier_protocol::HandlerError initial_messages_timeout_handler_(uint8_t message_type); // Helper functions haier_protocol::HandlerError process_status_message_(const uint8_t *packet, uint8_t size); std::unique_ptr last_status_message_; + unsigned int timeouts_counter_; }; } // namespace haier diff --git a/esphome/components/haier/smartair2_packet.h b/esphome/components/haier/smartair2_packet.h index 8046516c5f..f791c21af2 100644 --- a/esphome/components/haier/smartair2_packet.h +++ b/esphome/components/haier/smartair2_packet.h @@ -53,8 +53,8 @@ struct HaierPacketControl { uint8_t : 2; uint8_t health_mode : 1; // Health mode on or off uint8_t compressor : 1; // Compressor on or off ??? - uint8_t : 1; - uint8_t ten_degree : 1; // 10 degree status (only work in heat mode) + uint8_t half_degree : 1; // Use half degree + uint8_t ten_degree : 1; // 10 degree status (only work in heat mode) uint8_t : 0; // 28 uint8_t : 8; @@ -88,6 +88,9 @@ enum class FrameType : uint8_t { INVALID = 0x03, CONFIRM = 0x05, GET_DEVICE_VERSION = 0x61, + GET_DEVICE_VERSION_RESPONSE = 0x62, + GET_DEVICE_ID = 0x70, + GET_DEVICE_ID_RESPONSE = 0x71, REPORT_NETWORK_STATUS = 0xF7, NO_COMMAND = 0xFF, }; diff --git a/platformio.ini b/platformio.ini index ba149ce99e..5da3b9f978 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,7 +39,7 @@ lib_deps = bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 - pavlodn/HaierProtocol@0.9.18 ; haier + pavlodn/HaierProtocol@0.9.20 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library build_flags = From be6f95d43eaaa419ed65641965fb384ec94c3a5f Mon Sep 17 00:00:00 2001 From: Steve Rodgers Date: Fri, 11 Aug 2023 17:50:33 -0700 Subject: [PATCH 0347/2607] pca9554 cache reads (#5137) --- esphome/components/pca9554/pca9554.cpp | 25 +++++++++++++++++++++++-- esphome/components/pca9554/pca9554.h | 6 ++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index 39093fcf54..74c64dffaa 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -26,7 +26,7 @@ void PCA9554Component::setup() { this->config_mask_ = 0; // Invert mask as the part sees a 1 as an input this->write_register_(CONFIG_REG, ~this->config_mask_); - // All ouputs low + // All outputs low this->output_mask_ = 0; this->write_register_(OUTPUT_REG, this->output_mask_); // Read the inputs @@ -34,6 +34,14 @@ void PCA9554Component::setup() { ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), this->status_has_error()); } + +void PCA9554Component::loop() { + // The read_inputs_() method will cache the input values from the chip. + this->read_inputs_(); + // Clear all the previously read flags. + this->was_previously_read_ = 0x00; +} + void PCA9554Component::dump_config() { ESP_LOGCONFIG(TAG, "PCA9554:"); LOG_I2C_DEVICE(this) @@ -43,7 +51,16 @@ void PCA9554Component::dump_config() { } bool PCA9554Component::digital_read(uint8_t pin) { - this->read_inputs_(); + // Note: We want to try and avoid doing any I2C bus read transactions here + // to conserve I2C bus bandwidth. So what we do is check to see if we + // have seen a read during the time esphome is running this loop. If we have, + // we do an I2C bus transaction to get the latest value. If we haven't + // we return a cached value which was read at the time loop() was called. + if (this->was_previously_read_ & (1 << pin)) + this->read_inputs_(); // Force a read of a new value + // Indicate we saw a read request for this pin in case a + // read happens later in the same loop. + this->was_previously_read_ |= (1 << pin); return this->input_mask_ & (1 << pin); } @@ -98,6 +115,10 @@ bool PCA9554Component::write_register_(uint8_t reg, uint8_t value) { float PCA9554Component::get_setup_priority() const { return setup_priority::IO; } +// Run our loop() method very early in the loop, so that we cache read values before +// before other components call our digital_read() method. +float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI + void PCA9554GPIOPin::setup() { pin_mode(flags_); } void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } diff --git a/esphome/components/pca9554/pca9554.h b/esphome/components/pca9554/pca9554.h index d1bfc36bec..c2aa5c30ed 100644 --- a/esphome/components/pca9554/pca9554.h +++ b/esphome/components/pca9554/pca9554.h @@ -13,6 +13,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { /// Check i2c availability and setup masks void setup() override; + /// Poll for input changes periodically + void loop() override; /// Helper function to read the value of a pin. bool digital_read(uint8_t pin); /// Helper function to write the value of a pin. @@ -22,6 +24,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { float get_setup_priority() const override; + float get_loop_priority() const override; + void dump_config() override; protected: @@ -35,6 +39,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice { uint8_t output_mask_{0x00}; /// The state of the actual input pin states - 1 means HIGH, 0 means LOW uint8_t input_mask_{0x00}; + /// Flags to check if read previously during this loop + uint8_t was_previously_read_ = {0x00}; /// Storage for last I2C error seen esphome::i2c::ErrorCode last_error_; }; From 3717e34bbab1fa21861a282e8621894a2cad2c7e Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 14 Aug 2023 01:06:04 +0400 Subject: [PATCH 0348/2607] fix midea: undo approved PR#4053 (#5233) --- esphome/components/remote_base/__init__.py | 18 +++++++---------- .../components/remote_base/midea_protocol.h | 20 +++++-------------- tests/test1.yaml | 2 ++ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 24993e84d3..9e46506b3c 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1488,11 +1488,9 @@ MideaData, MideaBinarySensor, MideaTrigger, MideaAction, MideaDumper = declare_p MideaAction = ns.class_("MideaAction", RemoteTransmitterActionBase) MIDEA_SCHEMA = cv.Schema( { - cv.Required(CONF_CODE): cv.templatable( - cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=5, max=5), - ) + cv.Required(CONF_CODE): cv.All( + [cv.Any(cv.hex_uint8_t, cv.uint8_t)], + cv.Length(min=5, max=5), ), } ) @@ -1519,12 +1517,10 @@ def midea_dumper(var, config): MIDEA_SCHEMA, ) async def midea_action(var, config, args): - code_ = config[CONF_CODE] - if cg.is_template(code_): - template_ = await cg.templatable(code_, args, cg.std_vector.template(cg.uint8)) - cg.add(var.set_code_template(template_)) - else: - cg.add(var.set_code_static(code_)) + template_ = await cg.templatable( + config[CONF_CODE], args, cg.std_vector.template(cg.uint8) + ) + cg.add(var.set_code(template_)) # AEHA diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index d81a50241b..f5db313579 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -1,11 +1,11 @@ #pragma once +#include +#include + #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "remote_base.h" -#include -#include -#include namespace esphome { namespace remote_base { @@ -84,23 +84,13 @@ using MideaDumper = RemoteReceiverDumper; template class MideaAction : public RemoteTransmitterActionBase { TEMPLATABLE_VALUE(std::vector, code) - void set_code_static(std::vector code) { code_static_ = std::move(code); } - void set_code_template(std::function(Ts...)> func) { this->code_func_ = func; } + void set_code(std::initializer_list code) { this->code_ = code; } void encode(RemoteTransmitData *dst, Ts... x) override { - MideaData data; - if (!this->code_static_.empty()) { - data = MideaData(this->code_static_); - } else { - data = MideaData(this->code_func_(x...)); - } + MideaData data(this->code_.value(x...)); data.finalize(); MideaProtocol().encode(dst, data); } - - protected: - std::function(Ts...)> code_func_{}; - std::vector code_static_{}; }; } // namespace remote_base diff --git a/tests/test1.yaml b/tests/test1.yaml index 5c9b83a915..4eb78515c9 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2333,6 +2333,8 @@ switch: second: !lambda "return 0xB21F98;" - remote_transmitter.transmit_midea: code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF] + - remote_transmitter.transmit_midea: + code: !lambda "return {0xA2, 0x08, 0xFF, 0xFF, 0xFF};" - platform: gpio name: "MCP23S08 Pin #0" pin: From f26238e824d8df401eea8392633d7e1c3e042ed7 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Sun, 13 Aug 2023 23:08:18 +0200 Subject: [PATCH 0349/2607] Fixing smartair2 protocol implementation if no Wi-Fi (#5238) --- esphome/components/haier/smartair2_climate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 91b6bb0545..8bee37dadf 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -178,7 +178,9 @@ void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) break; #else case ProtocolPhases::SENDING_SIGNAL_LEVEL: - case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER this->set_phase(ProtocolPhases::IDLE); break; + case ProtocolPhases::WAITING_SIGNAL_LEVEL_ANSWER: + this->set_phase(ProtocolPhases::IDLE); + break; #endif case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST: case ProtocolPhases::WAITING_UPDATE_SIGNAL_ANSWER: From 3a899e28dc5016ed9be8575b864f968a9d28b85f Mon Sep 17 00:00:00 2001 From: Kjell Braden Date: Sun, 13 Aug 2023 23:09:51 +0200 Subject: [PATCH 0350/2607] tuya: add time sync callback only once to prevent memleak (#5234) --- esphome/components/tuya/tuya.cpp | 9 +++++++-- esphome/components/tuya/tuya.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 7e6b1d53fe..0fad151488 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -246,8 +246,13 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff #ifdef USE_TIME if (this->time_id_.has_value()) { this->send_local_time_(); - auto *time_id = *this->time_id_; - time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); + + if (!this->time_sync_callback_registered_) { + // tuya mcu supports time, so we let them know when our time changed + auto *time_id = *this->time_id_; + time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); + this->time_sync_callback_registered_ = true; + } } else { ESP_LOGW(TAG, "LOCAL_TIME_QUERY is not handled because time is not configured"); } diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index b9901dd5e7..26f6f65912 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -130,6 +130,7 @@ class Tuya : public Component, public uart::UARTDevice { #ifdef USE_TIME void send_local_time_(); optional time_id_{}; + bool time_sync_callback_registered_{false}; #endif TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; bool init_failed_{false}; From b05a3fbb55da3b655a3c8f7dce0948296299ec06 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:09:20 +1200 Subject: [PATCH 0351/2607] Fix duplicate tuya time warning (#5243) --- esphome/components/tuya/tuya.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 0fad151488..daf5080e7a 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -1,9 +1,9 @@ #include "tuya.h" #include "esphome/components/network/util.h" +#include "esphome/core/gpio.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/core/util.h" -#include "esphome/core/gpio.h" #ifdef USE_WIFI #include "esphome/components/wifi/wifi_component.h" @@ -253,12 +253,11 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); this->time_sync_callback_registered_ = true; } - } else { + } else +#endif + { ESP_LOGW(TAG, "LOCAL_TIME_QUERY is not handled because time is not configured"); } -#else - ESP_LOGE(TAG, "LOCAL_TIME_QUERY is not handled"); -#endif break; case TuyaCommandType::VACUUM_MAP_UPLOAD: this->send_command_( From 560e36a65c3df089856c9c77bea5f2133d467310 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 14 Aug 2023 11:09:49 +1200 Subject: [PATCH 0352/2607] Bump version to 2023.8.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 6b442dd633..1442ebde9d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0b1" +__version__ = "2023.8.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 3b2c61e813d576aca954118647d2b528178783f0 Mon Sep 17 00:00:00 2001 From: MrEditor97 Date: Mon, 14 Aug 2023 20:12:03 +0100 Subject: [PATCH 0353/2607] Updated my username in Code Owners (#5247) --- CODEOWNERS | 6 +++--- esphome/components/cap1188/__init__.py | 2 +- esphome/components/ina260/sensor.py | 2 +- esphome/components/mcp9600/sensor.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 408caee4f2..d815252ba3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -54,7 +54,7 @@ esphome/components/bp1658cj/* @Cossid esphome/components/bp5758d/* @Cossid esphome/components/button/* @esphome/core esphome/components/canbus/* @danielschramm @mvturnho -esphome/components/cap1188/* @MrEditor97 +esphome/components/cap1188/* @mreditor97 esphome/components/captive_portal/* @OttoWinter esphome/components/ccs811/* @habbie esphome/components/cd74hc4067/* @asoehlke @@ -132,7 +132,7 @@ esphome/components/i2s_audio/speaker/* @jesserockz esphome/components/ili9xxx/* @nielsnl68 esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core -esphome/components/ina260/* @MrEditor97 +esphome/components/ina260/* @mreditor97 esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkplate6/* @jesserockz esphome/components/integration/* @OttoWinter @@ -168,7 +168,7 @@ esphome/components/mcp2515/* @danielschramm @mvturnho esphome/components/mcp3204/* @rsumner esphome/components/mcp4728/* @berfenger esphome/components/mcp47a1/* @jesserockz -esphome/components/mcp9600/* @MrEditor97 +esphome/components/mcp9600/* @mreditor97 esphome/components/mcp9808/* @k7hpn esphome/components/md5/* @esphome/core esphome/components/mdns/* @esphome/core diff --git a/esphome/components/cap1188/__init__.py b/esphome/components/cap1188/__init__.py index 74be9df186..f22e6d6c9e 100644 --- a/esphome/components/cap1188/__init__.py +++ b/esphome/components/cap1188/__init__.py @@ -9,7 +9,7 @@ CONF_ALLOW_MULTIPLE_TOUCHES = "allow_multiple_touches" DEPENDENCIES = ["i2c"] AUTO_LOAD = ["binary_sensor", "output"] -CODEOWNERS = ["@MrEditor97"] +CODEOWNERS = ["@mreditor97"] cap1188_ns = cg.esphome_ns.namespace("cap1188") CONF_CAP1188_ID = "cap1188_id" diff --git a/esphome/components/ina260/sensor.py b/esphome/components/ina260/sensor.py index 048e713afa..732d15d9ca 100644 --- a/esphome/components/ina260/sensor.py +++ b/esphome/components/ina260/sensor.py @@ -16,7 +16,7 @@ from esphome.const import ( ) DEPENDENCIES = ["i2c"] -CODEOWNERS = ["@MrEditor97"] +CODEOWNERS = ["@mreditor97"] ina260_ns = cg.esphome_ns.namespace("ina260") INA260Component = ina260_ns.class_( diff --git a/esphome/components/mcp9600/sensor.py b/esphome/components/mcp9600/sensor.py index 392ee4e773..8557c7205e 100644 --- a/esphome/components/mcp9600/sensor.py +++ b/esphome/components/mcp9600/sensor.py @@ -13,7 +13,7 @@ CONF_HOT_JUNCTION = "hot_junction" CONF_COLD_JUNCTION = "cold_junction" DEPENDENCIES = ["i2c"] -CODEOWNERS = ["@MrEditor97"] +CODEOWNERS = ["@mreditor97"] mcp9600_ns = cg.esphome_ns.namespace("mcp9600") MCP9600Component = mcp9600_ns.class_( From e963eedb6405b6ae931d0b96570c3352908d63cf Mon Sep 17 00:00:00 2001 From: MrEditor97 Date: Mon, 14 Aug 2023 20:14:08 +0100 Subject: [PATCH 0354/2607] Change XL9535 `setup_priority` to IO (#5246) --- esphome/components/xl9535/xl9535.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/xl9535/xl9535.h b/esphome/components/xl9535/xl9535.h index 8f0a868c42..dd67990fa8 100644 --- a/esphome/components/xl9535/xl9535.h +++ b/esphome/components/xl9535/xl9535.h @@ -26,7 +26,7 @@ class XL9535Component : public Component, public i2c::I2CDevice { void setup() override; void dump_config() override; - float get_setup_priority() const override { return setup_priority::DATA; } + float get_setup_priority() const override { return setup_priority::IO; } }; class XL9535GPIOPin : public GPIOPin { From b9e9223fddfa47e8641c25d4e87a7c90866606f8 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 14 Aug 2023 23:21:22 +0400 Subject: [PATCH 0355/2607] rmt_base additional minor changes (#5245) --- esphome/components/remote_base/__init__.py | 21 +++++-------------- .../components/remote_base/midea_protocol.h | 1 - 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 9e46506b3c..e2d96c9472 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1488,10 +1488,7 @@ MideaData, MideaBinarySensor, MideaTrigger, MideaAction, MideaDumper = declare_p MideaAction = ns.class_("MideaAction", RemoteTransmitterActionBase) MIDEA_SCHEMA = cv.Schema( { - cv.Required(CONF_CODE): cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=5, max=5), - ), + cv.Required(CONF_CODE): cv.All([cv.hex_uint8_t], cv.Length(min=5, max=5)), } ) @@ -1511,15 +1508,10 @@ def midea_dumper(var, config): pass -@register_action( - "midea", - MideaAction, - MIDEA_SCHEMA, -) +@register_action("midea", MideaAction, MIDEA_SCHEMA) async def midea_action(var, config, args): - template_ = await cg.templatable( - config[CONF_CODE], args, cg.std_vector.template(cg.uint8) - ) + vec_ = cg.std_vector.template(cg.uint8) + template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_) cg.add(var.set_code(template_)) @@ -1530,10 +1522,7 @@ AEHAData, AEHABinarySensor, AEHATrigger, AEHAAction, AEHADumper = declare_protoc AEHA_SCHEMA = cv.Schema( { cv.Required(CONF_ADDRESS): cv.hex_uint16_t, - cv.Required(CONF_DATA): cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=2, max=35), - ), + cv.Required(CONF_DATA): cv.All([cv.hex_uint8_t], cv.Length(min=2, max=35)), } ) diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index f5db313579..6925686b34 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -84,7 +84,6 @@ using MideaDumper = RemoteReceiverDumper; template class MideaAction : public RemoteTransmitterActionBase { TEMPLATABLE_VALUE(std::vector, code) - void set_code(std::initializer_list code) { this->code_ = code; } void encode(RemoteTransmitData *dst, Ts... x) override { MideaData data(this->code_.value(x...)); From 6089526975ee74b73d5b4975b7b481f37d50ac58 Mon Sep 17 00:00:00 2001 From: mulder-fbi Date: Wed, 16 Aug 2023 00:52:56 +0200 Subject: [PATCH 0356/2607] Fix 24 bit signed integer parsing in sml parser (#5250) --- esphome/components/sml/sml_parser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index ff7da4cabd..91b320a30e 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -88,6 +88,11 @@ uint64_t bytes_to_uint(const bytes &buffer) { for (auto const value : buffer) { val = (val << 8) + value; } + // Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the + // 24 bit value is negative. + if (buffer.size() == 3 && buffer[0] & 0x80) { + val |= 0xFFFFFFFFFF000000; + } return val; } From 4a518e3e7adec588aad250f211b2f13ad03be98e Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Wed, 16 Aug 2023 03:11:44 +0400 Subject: [PATCH 0357/2607] remote_base: change dumpers log level (#5253) --- esphome/components/remote_base/aeha_protocol.cpp | 2 +- esphome/components/remote_base/canalsat_protocol.cpp | 4 ++-- esphome/components/remote_base/coolix_protocol.cpp | 6 +++--- esphome/components/remote_base/dish_protocol.cpp | 2 +- esphome/components/remote_base/drayton_protocol.cpp | 2 +- esphome/components/remote_base/jvc_protocol.cpp | 2 +- esphome/components/remote_base/lg_protocol.cpp | 2 +- esphome/components/remote_base/magiquest_protocol.cpp | 2 +- esphome/components/remote_base/midea_protocol.cpp | 2 +- esphome/components/remote_base/nec_protocol.cpp | 2 +- esphome/components/remote_base/nexa_protocol.cpp | 2 +- esphome/components/remote_base/panasonic_protocol.cpp | 2 +- esphome/components/remote_base/pioneer_protocol.cpp | 4 ++-- esphome/components/remote_base/pronto_protocol.cpp | 4 ++-- esphome/components/remote_base/raw_protocol.cpp | 4 ++-- esphome/components/remote_base/rc5_protocol.cpp | 2 +- esphome/components/remote_base/rc6_protocol.cpp | 2 +- esphome/components/remote_base/rc_switch_protocol.cpp | 2 +- esphome/components/remote_base/samsung36_protocol.cpp | 2 +- esphome/components/remote_base/samsung_protocol.cpp | 2 +- esphome/components/remote_base/sony_protocol.cpp | 2 +- esphome/components/remote_base/toshiba_ac_protocol.cpp | 4 ++-- 22 files changed, 29 insertions(+), 29 deletions(-) diff --git a/esphome/components/remote_base/aeha_protocol.cpp b/esphome/components/remote_base/aeha_protocol.cpp index ee1616ed6d..40bdadf634 100644 --- a/esphome/components/remote_base/aeha_protocol.cpp +++ b/esphome/components/remote_base/aeha_protocol.cpp @@ -96,7 +96,7 @@ std::string AEHAProtocol::format_data_(const std::vector &data) { void AEHAProtocol::dump(const AEHAData &data) { auto data_str = format_data_(data.data); - ESP_LOGD(TAG, "Received AEHA: address=0x%04X, data=[%s]", data.address, data_str.c_str()); + ESP_LOGI(TAG, "Received AEHA: address=0x%04X, data=[%s]", data.address, data_str.c_str()); } } // namespace remote_base diff --git a/esphome/components/remote_base/canalsat_protocol.cpp b/esphome/components/remote_base/canalsat_protocol.cpp index 1ea47750fd..bee3d57fd8 100644 --- a/esphome/components/remote_base/canalsat_protocol.cpp +++ b/esphome/components/remote_base/canalsat_protocol.cpp @@ -96,10 +96,10 @@ optional CanalSatBaseProtocol::decode(RemoteReceiveData src) { void CanalSatBaseProtocol::dump(const CanalSatData &data) { if (this->tag_ == CANALSATLD_TAG) { - ESP_LOGD(this->tag_, "Received CanalSatLD: device=0x%02X, address=0x%02X, command=0x%02X, repeat=0x%X", data.device, + ESP_LOGI(this->tag_, "Received CanalSatLD: device=0x%02X, address=0x%02X, command=0x%02X, repeat=0x%X", data.device, data.address, data.command, data.repeat); } else { - ESP_LOGD(this->tag_, "Received CanalSat: device=0x%02X, address=0x%02X, command=0x%02X, repeat=0x%X", data.device, + ESP_LOGI(this->tag_, "Received CanalSat: device=0x%02X, address=0x%02X, command=0x%02X, repeat=0x%X", data.device, data.address, data.command, data.repeat); } } diff --git a/esphome/components/remote_base/coolix_protocol.cpp b/esphome/components/remote_base/coolix_protocol.cpp index 3c9dadcd1c..295fccb762 100644 --- a/esphome/components/remote_base/coolix_protocol.cpp +++ b/esphome/components/remote_base/coolix_protocol.cpp @@ -101,11 +101,11 @@ optional CoolixProtocol::decode(RemoteReceiveData data) { void CoolixProtocol::dump(const CoolixData &data) { if (data.is_strict()) { - ESP_LOGD(TAG, "Received Coolix: 0x%06X", data.first); + ESP_LOGI(TAG, "Received Coolix: 0x%06X", data.first); } else if (data.has_second()) { - ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X, 0x%06X]", data.first, data.second); + ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06X, 0x%06X]", data.first, data.second); } else { - ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X]", data.first); + ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06X]", data.first); } } diff --git a/esphome/components/remote_base/dish_protocol.cpp b/esphome/components/remote_base/dish_protocol.cpp index 47bfdc5c58..754b6c3b12 100644 --- a/esphome/components/remote_base/dish_protocol.cpp +++ b/esphome/components/remote_base/dish_protocol.cpp @@ -87,7 +87,7 @@ optional DishProtocol::decode(RemoteReceiveData src) { } void DishProtocol::dump(const DishData &data) { - ESP_LOGD(TAG, "Received Dish: address=0x%02X, command=0x%02X", data.address, data.command); + ESP_LOGI(TAG, "Received Dish: address=0x%02X, command=0x%02X", data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/drayton_protocol.cpp b/esphome/components/remote_base/drayton_protocol.cpp index f5eae49058..56a3dec1e0 100644 --- a/esphome/components/remote_base/drayton_protocol.cpp +++ b/esphome/components/remote_base/drayton_protocol.cpp @@ -205,7 +205,7 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { return out; } void DraytonProtocol::dump(const DraytonData &data) { - ESP_LOGD(TAG, "Received Drayton: address=0x%04X (0x%04x), channel=0x%03x command=0x%03X", data.address, + ESP_LOGI(TAG, "Received Drayton: address=0x%04X (0x%04x), channel=0x%03x command=0x%03X", data.address, ((data.address << 1) & 0xffff), data.channel, data.command); } diff --git a/esphome/components/remote_base/jvc_protocol.cpp b/esphome/components/remote_base/jvc_protocol.cpp index 169b1d00bf..3d34cc614e 100644 --- a/esphome/components/remote_base/jvc_protocol.cpp +++ b/esphome/components/remote_base/jvc_protocol.cpp @@ -46,7 +46,7 @@ optional JVCProtocol::decode(RemoteReceiveData src) { } return out; } -void JVCProtocol::dump(const JVCData &data) { ESP_LOGD(TAG, "Received JVC: data=0x%04X", data.data); } +void JVCProtocol::dump(const JVCData &data) { ESP_LOGI(TAG, "Received JVC: data=0x%04X", data.data); } } // namespace remote_base } // namespace esphome diff --git a/esphome/components/remote_base/lg_protocol.cpp b/esphome/components/remote_base/lg_protocol.cpp index 8040b0f3fc..d7d3a5ac7d 100644 --- a/esphome/components/remote_base/lg_protocol.cpp +++ b/esphome/components/remote_base/lg_protocol.cpp @@ -51,7 +51,7 @@ optional LGProtocol::decode(RemoteReceiveData src) { return out; } void LGProtocol::dump(const LGData &data) { - ESP_LOGD(TAG, "Received LG: data=0x%08X, nbits=%d", data.data, data.nbits); + ESP_LOGI(TAG, "Received LG: data=0x%08X, nbits=%d", data.data, data.nbits); } } // namespace remote_base diff --git a/esphome/components/remote_base/magiquest_protocol.cpp b/esphome/components/remote_base/magiquest_protocol.cpp index 20b40ef201..76024b1eaf 100644 --- a/esphome/components/remote_base/magiquest_protocol.cpp +++ b/esphome/components/remote_base/magiquest_protocol.cpp @@ -76,7 +76,7 @@ optional MagiQuestProtocol::decode(RemoteReceiveData src) { return data; } void MagiQuestProtocol::dump(const MagiQuestData &data) { - ESP_LOGD(TAG, "Received MagiQuest: wand_id=0x%08X, magnitude=0x%04X", data.wand_id, data.magnitude); + ESP_LOGI(TAG, "Received MagiQuest: wand_id=0x%08X, magnitude=0x%04X", data.wand_id, data.magnitude); } } // namespace remote_base diff --git a/esphome/components/remote_base/midea_protocol.cpp b/esphome/components/remote_base/midea_protocol.cpp index f619d201bc..8006fe4048 100644 --- a/esphome/components/remote_base/midea_protocol.cpp +++ b/esphome/components/remote_base/midea_protocol.cpp @@ -70,7 +70,7 @@ optional MideaProtocol::decode(RemoteReceiveData src) { return {}; } -void MideaProtocol::dump(const MideaData &data) { ESP_LOGD(TAG, "Received Midea: %s", data.to_string().c_str()); } +void MideaProtocol::dump(const MideaData &data) { ESP_LOGI(TAG, "Received Midea: %s", data.to_string().c_str()); } } // namespace remote_base } // namespace esphome diff --git a/esphome/components/remote_base/nec_protocol.cpp b/esphome/components/remote_base/nec_protocol.cpp index ee3fec5992..d5c68784ee 100644 --- a/esphome/components/remote_base/nec_protocol.cpp +++ b/esphome/components/remote_base/nec_protocol.cpp @@ -67,7 +67,7 @@ optional NECProtocol::decode(RemoteReceiveData src) { return data; } void NECProtocol::dump(const NECData &data) { - ESP_LOGD(TAG, "Received NEC: address=0x%04X, command=0x%04X", data.address, data.command); + ESP_LOGI(TAG, "Received NEC: address=0x%04X, command=0x%04X", data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/nexa_protocol.cpp b/esphome/components/remote_base/nexa_protocol.cpp index a0066ea5d4..f4e7d14187 100644 --- a/esphome/components/remote_base/nexa_protocol.cpp +++ b/esphome/components/remote_base/nexa_protocol.cpp @@ -232,7 +232,7 @@ optional NexaProtocol::decode(RemoteReceiveData src) { } void NexaProtocol::dump(const NexaData &data) { - ESP_LOGD(TAG, "Received NEXA: device=0x%04X group=%d state=%d channel=%d level=%d", data.device, data.group, + ESP_LOGI(TAG, "Received NEXA: device=0x%04X group=%d state=%d channel=%d level=%d", data.device, data.group, data.state, data.channel, data.level); } diff --git a/esphome/components/remote_base/panasonic_protocol.cpp b/esphome/components/remote_base/panasonic_protocol.cpp index fe1060e935..460ca3b164 100644 --- a/esphome/components/remote_base/panasonic_protocol.cpp +++ b/esphome/components/remote_base/panasonic_protocol.cpp @@ -67,7 +67,7 @@ optional PanasonicProtocol::decode(RemoteReceiveData src) { return out; } void PanasonicProtocol::dump(const PanasonicData &data) { - ESP_LOGD(TAG, "Received Panasonic: address=0x%04X, command=0x%08X", data.address, data.command); + ESP_LOGI(TAG, "Received Panasonic: address=0x%04X, command=0x%08X", data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/pioneer_protocol.cpp b/esphome/components/remote_base/pioneer_protocol.cpp index 5c10eab48d..043565282d 100644 --- a/esphome/components/remote_base/pioneer_protocol.cpp +++ b/esphome/components/remote_base/pioneer_protocol.cpp @@ -146,9 +146,9 @@ optional PioneerProtocol::decode(RemoteReceiveData src) { } void PioneerProtocol::dump(const PioneerData &data) { if (data.rc_code_2 == 0) { - ESP_LOGD(TAG, "Received Pioneer: rc_code_X=0x%04X", data.rc_code_1); + ESP_LOGI(TAG, "Received Pioneer: rc_code_X=0x%04X", data.rc_code_1); } else { - ESP_LOGD(TAG, "Received Pioneer: rc_code_1=0x%04X, rc_code_2=0x%04X", data.rc_code_1, data.rc_code_2); + ESP_LOGI(TAG, "Received Pioneer: rc_code_1=0x%04X, rc_code_2=0x%04X", data.rc_code_1, data.rc_code_2); } } diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 81ac176666..4b6977e1a2 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -234,9 +234,9 @@ void ProntoProtocol::dump(const ProntoData &data) { first = data.data.substr(0, 229); rest = data.data.substr(230); } - ESP_LOGD(TAG, "Received Pronto: data=%s", first.c_str()); + ESP_LOGI(TAG, "Received Pronto: data=%s", first.c_str()); if (!rest.empty()) { - ESP_LOGD(TAG, "%s", rest.c_str()); + ESP_LOGI(TAG, "%s", rest.c_str()); } } diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp index 3446dcdbb8..9304aa3e3d 100644 --- a/esphome/components/remote_base/raw_protocol.cpp +++ b/esphome/components/remote_base/raw_protocol.cpp @@ -25,7 +25,7 @@ bool RawDumper::dump(RemoteReceiveData src) { if (written < 0 || written >= int(remaining_length)) { // write failed, flush... buffer[buffer_offset] = '\0'; - ESP_LOGD(TAG, "%s", buffer); + ESP_LOGI(TAG, "%s", buffer); buffer_offset = 0; written = sprintf(buffer, " "); if (i + 1 < src.size()) { @@ -38,7 +38,7 @@ bool RawDumper::dump(RemoteReceiveData src) { buffer_offset += written; } if (buffer_offset != 0) { - ESP_LOGD(TAG, "%s", buffer); + ESP_LOGI(TAG, "%s", buffer); } return true; } diff --git a/esphome/components/remote_base/rc5_protocol.cpp b/esphome/components/remote_base/rc5_protocol.cpp index cb6eed4c6c..08f2f2eaa3 100644 --- a/esphome/components/remote_base/rc5_protocol.cpp +++ b/esphome/components/remote_base/rc5_protocol.cpp @@ -83,7 +83,7 @@ optional RC5Protocol::decode(RemoteReceiveData src) { return out; } void RC5Protocol::dump(const RC5Data &data) { - ESP_LOGD(TAG, "Received RC5: address=0x%02X, command=0x%02X", data.address, data.command); + ESP_LOGI(TAG, "Received RC5: address=0x%02X, command=0x%02X", data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/rc6_protocol.cpp b/esphome/components/remote_base/rc6_protocol.cpp index ad12c7c208..fcb4da11a4 100644 --- a/esphome/components/remote_base/rc6_protocol.cpp +++ b/esphome/components/remote_base/rc6_protocol.cpp @@ -173,7 +173,7 @@ optional RC6Protocol::decode(RemoteReceiveData src) { } void RC6Protocol::dump(const RC6Data &data) { - ESP_LOGD(RC6_TAG, "Received RC6: mode=0x%X, address=0x%02X, command=0x%02X, toggle=0x%X", data.mode, data.address, + ESP_LOGI(RC6_TAG, "Received RC6: mode=0x%X, address=0x%02X, command=0x%02X, toggle=0x%X", data.mode, data.address, data.command, data.toggle); } diff --git a/esphome/components/remote_base/rc_switch_protocol.cpp b/esphome/components/remote_base/rc_switch_protocol.cpp index 5b6284a86f..1f38fdca67 100644 --- a/esphome/components/remote_base/rc_switch_protocol.cpp +++ b/esphome/components/remote_base/rc_switch_protocol.cpp @@ -258,7 +258,7 @@ bool RCSwitchDumper::dump(RemoteReceiveData src) { buffer[j] = (out_data & ((uint64_t) 1 << (out_nbits - j - 1))) ? '1' : '0'; buffer[out_nbits] = '\0'; - ESP_LOGD(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", i, buffer); + ESP_LOGI(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", i, buffer); // only send first decoded protocol return true; diff --git a/esphome/components/remote_base/samsung36_protocol.cpp b/esphome/components/remote_base/samsung36_protocol.cpp index 9ef8ade205..2396986670 100644 --- a/esphome/components/remote_base/samsung36_protocol.cpp +++ b/esphome/components/remote_base/samsung36_protocol.cpp @@ -96,7 +96,7 @@ optional Samsung36Protocol::decode(RemoteReceiveData src) { return out; } void Samsung36Protocol::dump(const Samsung36Data &data) { - ESP_LOGD(TAG, "Received Samsung36: address=0x%04X, command=0x%08X", data.address, data.command); + ESP_LOGI(TAG, "Received Samsung36: address=0x%04X, command=0x%08X", data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/samsung_protocol.cpp b/esphome/components/remote_base/samsung_protocol.cpp index 20e8285a03..2d6d5531e5 100644 --- a/esphome/components/remote_base/samsung_protocol.cpp +++ b/esphome/components/remote_base/samsung_protocol.cpp @@ -58,7 +58,7 @@ optional SamsungProtocol::decode(RemoteReceiveData src) { return out; } void SamsungProtocol::dump(const SamsungData &data) { - ESP_LOGD(TAG, "Received Samsung: data=0x%" PRIX64 ", nbits=%d", data.data, data.nbits); + ESP_LOGI(TAG, "Received Samsung: data=0x%" PRIX64 ", nbits=%d", data.data, data.nbits); } } // namespace remote_base diff --git a/esphome/components/remote_base/sony_protocol.cpp b/esphome/components/remote_base/sony_protocol.cpp index 8634cf7d61..bcd8e4c8cf 100644 --- a/esphome/components/remote_base/sony_protocol.cpp +++ b/esphome/components/remote_base/sony_protocol.cpp @@ -62,7 +62,7 @@ optional SonyProtocol::decode(RemoteReceiveData src) { return out; } void SonyProtocol::dump(const SonyData &data) { - ESP_LOGD(TAG, "Received Sony: data=0x%08X, nbits=%d", data.data, data.nbits); + ESP_LOGI(TAG, "Received Sony: data=0x%08X, nbits=%d", data.data, data.nbits); } } // namespace remote_base diff --git a/esphome/components/remote_base/toshiba_ac_protocol.cpp b/esphome/components/remote_base/toshiba_ac_protocol.cpp index 1a19f534f8..42241eea8c 100644 --- a/esphome/components/remote_base/toshiba_ac_protocol.cpp +++ b/esphome/components/remote_base/toshiba_ac_protocol.cpp @@ -105,9 +105,9 @@ optional ToshibaAcProtocol::decode(RemoteReceiveData src) { void ToshibaAcProtocol::dump(const ToshibaAcData &data) { if (data.rc_code_2 != 0) { - ESP_LOGD(TAG, "Received Toshiba AC: rc_code_1=0x%" PRIX64 ", rc_code_2=0x%" PRIX64, data.rc_code_1, data.rc_code_2); + ESP_LOGI(TAG, "Received Toshiba AC: rc_code_1=0x%" PRIX64 ", rc_code_2=0x%" PRIX64, data.rc_code_1, data.rc_code_2); } else { - ESP_LOGD(TAG, "Received Toshiba AC: rc_code_1=0x%" PRIX64, data.rc_code_1); + ESP_LOGI(TAG, "Received Toshiba AC: rc_code_1=0x%" PRIX64, data.rc_code_1); } } From 87629191b31fb96bf0df15d06657827c56862a34 Mon Sep 17 00:00:00 2001 From: Carson Full Date: Tue, 15 Aug 2023 18:13:43 -0500 Subject: [PATCH 0358/2607] Fix IDFI2CBus::writev ignoring stop parameter (#4840) Co-authored-by: Alexander Dimitrov --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index e2c7e7ddcb..5d35c1968b 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -202,11 +202,13 @@ ErrorCode IDFI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt, b return ERROR_UNKNOWN; } } - err = i2c_master_stop(cmd); - if (err != ESP_OK) { - ESP_LOGVV(TAG, "TX to %02X master stop failed: %s", address, esp_err_to_name(err)); - i2c_cmd_link_delete(cmd); - return ERROR_UNKNOWN; + if (stop) { + err = i2c_master_stop(cmd); + if (err != ESP_OK) { + ESP_LOGVV(TAG, "TX to %02X master stop failed: %s", address, esp_err_to_name(err)); + i2c_cmd_link_delete(cmd); + return ERROR_UNKNOWN; + } } err = i2c_master_cmd_begin(port_, cmd, 20 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); From 5cb5594288f65fe4639e442a0c3772ed7c96e578 Mon Sep 17 00:00:00 2001 From: Regev Brody Date: Wed, 16 Aug 2023 02:31:18 +0300 Subject: [PATCH 0359/2607] Add configuration flow abilites to the ld2410 component (#4434) --- CODEOWNERS | 2 +- esphome/components/ld2410/__init__.py | 188 +++--- esphome/components/ld2410/automation.h | 22 + esphome/components/ld2410/binary_sensor.py | 45 +- esphome/components/ld2410/button/__init__.py | 57 ++ .../components/ld2410/button/query_button.cpp | 9 + .../components/ld2410/button/query_button.h | 18 + .../components/ld2410/button/reset_button.cpp | 9 + .../components/ld2410/button/reset_button.h | 18 + .../ld2410/button/restart_button.cpp | 9 + .../components/ld2410/button/restart_button.h | 18 + esphome/components/ld2410/ld2410.cpp | 557 +++++++++++++++--- esphome/components/ld2410/ld2410.h | 207 +++++-- esphome/components/ld2410/number/__init__.py | 128 ++++ .../ld2410/number/gate_threshold_number.cpp | 14 + .../ld2410/number/gate_threshold_number.h | 19 + .../ld2410/number/light_threshold_number.cpp | 12 + .../ld2410/number/light_threshold_number.h | 18 + .../number/max_distance_timeout_number.cpp | 12 + .../number/max_distance_timeout_number.h | 18 + esphome/components/ld2410/select/__init__.py | 81 +++ .../ld2410/select/baud_rate_select.cpp | 12 + .../ld2410/select/baud_rate_select.h | 18 + .../select/distance_resolution_select.cpp | 12 + .../select/distance_resolution_select.h | 18 + .../select/light_out_control_select.cpp | 12 + .../ld2410/select/light_out_control_select.h | 18 + esphome/components/ld2410/sensor.py | 111 +++- esphome/components/ld2410/switch/__init__.py | 44 ++ .../ld2410/switch/bluetooth_switch.cpp | 12 + .../ld2410/switch/bluetooth_switch.h | 18 + .../ld2410/switch/engineering_mode_switch.cpp | 12 + .../ld2410/switch/engineering_mode_switch.h | 18 + esphome/components/ld2410/text_sensor.py | 33 ++ tests/test1.yaml | 149 ++++- 35 files changed, 1621 insertions(+), 327 deletions(-) create mode 100644 esphome/components/ld2410/automation.h create mode 100644 esphome/components/ld2410/button/__init__.py create mode 100644 esphome/components/ld2410/button/query_button.cpp create mode 100644 esphome/components/ld2410/button/query_button.h create mode 100644 esphome/components/ld2410/button/reset_button.cpp create mode 100644 esphome/components/ld2410/button/reset_button.h create mode 100644 esphome/components/ld2410/button/restart_button.cpp create mode 100644 esphome/components/ld2410/button/restart_button.h create mode 100644 esphome/components/ld2410/number/__init__.py create mode 100644 esphome/components/ld2410/number/gate_threshold_number.cpp create mode 100644 esphome/components/ld2410/number/gate_threshold_number.h create mode 100644 esphome/components/ld2410/number/light_threshold_number.cpp create mode 100644 esphome/components/ld2410/number/light_threshold_number.h create mode 100644 esphome/components/ld2410/number/max_distance_timeout_number.cpp create mode 100644 esphome/components/ld2410/number/max_distance_timeout_number.h create mode 100644 esphome/components/ld2410/select/__init__.py create mode 100644 esphome/components/ld2410/select/baud_rate_select.cpp create mode 100644 esphome/components/ld2410/select/baud_rate_select.h create mode 100644 esphome/components/ld2410/select/distance_resolution_select.cpp create mode 100644 esphome/components/ld2410/select/distance_resolution_select.h create mode 100644 esphome/components/ld2410/select/light_out_control_select.cpp create mode 100644 esphome/components/ld2410/select/light_out_control_select.h create mode 100644 esphome/components/ld2410/switch/__init__.py create mode 100644 esphome/components/ld2410/switch/bluetooth_switch.cpp create mode 100644 esphome/components/ld2410/switch/bluetooth_switch.h create mode 100644 esphome/components/ld2410/switch/engineering_mode_switch.cpp create mode 100644 esphome/components/ld2410/switch/engineering_mode_switch.h create mode 100644 esphome/components/ld2410/text_sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index d815252ba3..f50700c502 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -144,7 +144,7 @@ esphome/components/key_collector/* @ssieb esphome/components/key_provider/* @ssieb esphome/components/kuntze/* @ssieb esphome/components/lcd_menu/* @numo68 -esphome/components/ld2410/* @sebcaps +esphome/components/ld2410/* @regevbr @sebcaps esphome/components/ledc/* @OttoWinter esphome/components/light/* @esphome/core esphome/components/lilygo_t5_47/touchscreen/* @jesserockz diff --git a/esphome/components/ld2410/__init__.py b/esphome/components/ld2410/__init__.py index 47c4cdb0bd..2b30b65f46 100644 --- a/esphome/components/ld2410/__init__.py +++ b/esphome/components/ld2410/__init__.py @@ -1,113 +1,64 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import uart -from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome.const import CONF_ID, CONF_THROTTLE, CONF_TIMEOUT, CONF_PASSWORD from esphome import automation from esphome.automation import maybe_simple_id DEPENDENCIES = ["uart"] -CODEOWNERS = ["@sebcaps"] +CODEOWNERS = ["@sebcaps", "@regevbr"] MULTI_CONF = True ld2410_ns = cg.esphome_ns.namespace("ld2410") LD2410Component = ld2410_ns.class_("LD2410Component", cg.Component, uart.UARTDevice) -LD2410Restart = ld2410_ns.class_("LD2410Restart", automation.Action) + CONF_LD2410_ID = "ld2410_id" + CONF_MAX_MOVE_DISTANCE = "max_move_distance" CONF_MAX_STILL_DISTANCE = "max_still_distance" -CONF_G0_MOVE_THRESHOLD = "g0_move_threshold" -CONF_G0_STILL_THRESHOLD = "g0_still_threshold" -CONF_G1_MOVE_THRESHOLD = "g1_move_threshold" -CONF_G1_STILL_THRESHOLD = "g1_still_threshold" -CONF_G2_MOVE_THRESHOLD = "g2_move_threshold" -CONF_G2_STILL_THRESHOLD = "g2_still_threshold" -CONF_G3_MOVE_THRESHOLD = "g3_move_threshold" -CONF_G3_STILL_THRESHOLD = "g3_still_threshold" -CONF_G4_MOVE_THRESHOLD = "g4_move_threshold" -CONF_G4_STILL_THRESHOLD = "g4_still_threshold" -CONF_G5_MOVE_THRESHOLD = "g5_move_threshold" -CONF_G5_STILL_THRESHOLD = "g5_still_threshold" -CONF_G6_MOVE_THRESHOLD = "g6_move_threshold" -CONF_G6_STILL_THRESHOLD = "g6_still_threshold" -CONF_G7_MOVE_THRESHOLD = "g7_move_threshold" -CONF_G7_STILL_THRESHOLD = "g7_still_threshold" -CONF_G8_MOVE_THRESHOLD = "g8_move_threshold" -CONF_G8_STILL_THRESHOLD = "g8_still_threshold" +CONF_STILL_THRESHOLDS = [f"g{x}_still_threshold" for x in range(9)] +CONF_MOVE_THRESHOLDS = [f"g{x}_move_threshold" for x in range(9)] -DISTANCES = [0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6] +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(LD2410Component), + cv.Optional(CONF_THROTTLE, default="1000ms"): cv.All( + cv.positive_time_period_milliseconds, + cv.Range(min=cv.TimePeriod(milliseconds=1)), + ), + cv.Optional(CONF_MAX_MOVE_DISTANCE): cv.invalid( + f"The '{CONF_MAX_MOVE_DISTANCE}' option has been moved to the '{CONF_MAX_MOVE_DISTANCE}'" + f" number component" + ), + cv.Optional(CONF_MAX_STILL_DISTANCE): cv.invalid( + f"The '{CONF_MAX_STILL_DISTANCE}' option has been moved to the '{CONF_MAX_STILL_DISTANCE}'" + f" number component" + ), + cv.Optional(CONF_TIMEOUT): cv.invalid( + f"The '{CONF_TIMEOUT}' option has been moved to the '{CONF_TIMEOUT}'" + f" number component" + ), + } +) + +for i in range(9): + CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + cv.Schema( + { + cv.Optional(CONF_MOVE_THRESHOLDS[i]): cv.invalid( + f"The '{CONF_MOVE_THRESHOLDS[i]}' option has been moved to the '{CONF_MOVE_THRESHOLDS[i]}'" + f" number component" + ), + cv.Optional(CONF_STILL_THRESHOLDS[i]): cv.invalid( + f"The '{CONF_STILL_THRESHOLDS[i]}' option has been moved to the '{CONF_STILL_THRESHOLDS[i]}'" + f" number component" + ), + } + ) + ) CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(LD2410Component), - cv.Optional(CONF_MAX_MOVE_DISTANCE, default="4.5m"): cv.All( - cv.distance, cv.one_of(*DISTANCES, float=True) - ), - cv.Optional(CONF_MAX_STILL_DISTANCE, default="4.5m"): cv.All( - cv.distance, cv.one_of(*DISTANCES, float=True) - ), - cv.Optional(CONF_TIMEOUT, default="5s"): cv.All( - cv.positive_time_period_seconds, - cv.Range(max=cv.TimePeriod(seconds=32767)), - ), - cv.Optional(CONF_G0_MOVE_THRESHOLD, default=50): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G0_STILL_THRESHOLD, default=0): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G1_MOVE_THRESHOLD, default=50): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G1_STILL_THRESHOLD, default=0): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G2_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G2_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G3_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G3_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G4_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G4_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G5_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G5_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G6_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G6_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G7_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G7_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G8_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G8_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - } - ) - .extend(uart.UART_DEVICE_SCHEMA) - .extend(cv.COMPONENT_SCHEMA) + CONFIG_SCHEMA.extend(uart.UART_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) ) FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( @@ -123,31 +74,7 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) - cg.add(var.set_timeout(config[CONF_TIMEOUT])) - cg.add(var.set_max_move_distance(int(config[CONF_MAX_MOVE_DISTANCE] / 0.75))) - cg.add(var.set_max_still_distance(int(config[CONF_MAX_STILL_DISTANCE] / 0.75))) - cg.add( - var.set_range_config( - config[CONF_G0_MOVE_THRESHOLD], - config[CONF_G0_STILL_THRESHOLD], - config[CONF_G1_MOVE_THRESHOLD], - config[CONF_G1_STILL_THRESHOLD], - config[CONF_G2_MOVE_THRESHOLD], - config[CONF_G2_STILL_THRESHOLD], - config[CONF_G3_MOVE_THRESHOLD], - config[CONF_G3_STILL_THRESHOLD], - config[CONF_G4_MOVE_THRESHOLD], - config[CONF_G4_STILL_THRESHOLD], - config[CONF_G5_MOVE_THRESHOLD], - config[CONF_G5_STILL_THRESHOLD], - config[CONF_G6_MOVE_THRESHOLD], - config[CONF_G6_STILL_THRESHOLD], - config[CONF_G7_MOVE_THRESHOLD], - config[CONF_G7_STILL_THRESHOLD], - config[CONF_G8_MOVE_THRESHOLD], - config[CONF_G8_STILL_THRESHOLD], - ) - ) + cg.add(var.set_throttle(config[CONF_THROTTLE])) CALIBRATION_ACTION_SCHEMA = maybe_simple_id( @@ -155,3 +82,28 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id( cv.Required(CONF_ID): cv.use_id(LD2410Component), } ) + + +# Actions +BluetoothPasswordSetAction = ld2410_ns.class_( + "BluetoothPasswordSetAction", automation.Action +) + + +BLUETOOTH_PASSWORD_SET_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(LD2410Component), + cv.Required(CONF_PASSWORD): cv.templatable(cv.string_strict), + } +) + + +@automation.register_action( + "bluetooth_password.set", BluetoothPasswordSetAction, BLUETOOTH_PASSWORD_SET_SCHEMA +) +async def bluetooth_password_set_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable(config[CONF_PASSWORD], args, cg.std_string) + cg.add(var.set_password(template_)) + return var diff --git a/esphome/components/ld2410/automation.h b/esphome/components/ld2410/automation.h new file mode 100644 index 0000000000..7cb9855f84 --- /dev/null +++ b/esphome/components/ld2410/automation.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "ld2410.h" + +namespace esphome { +namespace ld2410 { + +template class BluetoothPasswordSetAction : public Action { + public: + explicit BluetoothPasswordSetAction(LD2410Component *ld2410_comp) : ld2410_comp_(ld2410_comp) {} + TEMPLATABLE_VALUE(std::string, password) + + void play(Ts... x) override { this->ld2410_comp_->set_bluetooth_password(this->password_.value(x...)); } + + protected: + LD2410Component *ld2410_comp_; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/binary_sensor.py b/esphome/components/ld2410/binary_sensor.py index 02f73d57b7..3057480d25 100644 --- a/esphome/components/ld2410/binary_sensor.py +++ b/esphome/components/ld2410/binary_sensor.py @@ -1,36 +1,55 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv -from esphome.const import DEVICE_CLASS_MOTION, DEVICE_CLASS_OCCUPANCY +from esphome.const import ( + DEVICE_CLASS_MOTION, + DEVICE_CLASS_OCCUPANCY, + DEVICE_CLASS_PRESENCE, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_MOTION_SENSOR, + ICON_ACCOUNT, +) from . import CONF_LD2410_ID, LD2410Component DEPENDENCIES = ["ld2410"] CONF_HAS_TARGET = "has_target" CONF_HAS_MOVING_TARGET = "has_moving_target" CONF_HAS_STILL_TARGET = "has_still_target" +CONF_OUT_PIN_PRESENCE_STATUS = "out_pin_presence_status" CONFIG_SCHEMA = { cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_OCCUPANCY + device_class=DEVICE_CLASS_OCCUPANCY, + icon=ICON_ACCOUNT, ), cv.Optional(CONF_HAS_MOVING_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_MOTION + device_class=DEVICE_CLASS_MOTION, + icon=ICON_MOTION_SENSOR, ), cv.Optional(CONF_HAS_STILL_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_OCCUPANCY + device_class=DEVICE_CLASS_OCCUPANCY, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_OUT_PIN_PRESENCE_STATUS): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PRESENCE, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_ACCOUNT, ), } async def to_code(config): ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) - if CONF_HAS_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_TARGET]) - cg.add(ld2410_component.set_target_sensor(sens)) - if CONF_HAS_MOVING_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_MOVING_TARGET]) - cg.add(ld2410_component.set_moving_target_sensor(sens)) - if CONF_HAS_STILL_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_STILL_TARGET]) - cg.add(ld2410_component.set_still_target_sensor(sens)) + if has_target_config := config.get(CONF_HAS_TARGET): + sens = await binary_sensor.new_binary_sensor(has_target_config) + cg.add(ld2410_component.set_target_binary_sensor(sens)) + if has_moving_target_config := config.get(CONF_HAS_MOVING_TARGET): + sens = await binary_sensor.new_binary_sensor(has_moving_target_config) + cg.add(ld2410_component.set_moving_target_binary_sensor(sens)) + if has_still_target_config := config.get(CONF_HAS_STILL_TARGET): + sens = await binary_sensor.new_binary_sensor(has_still_target_config) + cg.add(ld2410_component.set_still_target_binary_sensor(sens)) + if out_pin_presence_status_config := config.get(CONF_OUT_PIN_PRESENCE_STATUS): + sens = await binary_sensor.new_binary_sensor(out_pin_presence_status_config) + cg.add(ld2410_component.set_out_pin_presence_status_binary_sensor(sens)) diff --git a/esphome/components/ld2410/button/__init__.py b/esphome/components/ld2410/button/__init__.py new file mode 100644 index 0000000000..3567114c2c --- /dev/null +++ b/esphome/components/ld2410/button/__init__.py @@ -0,0 +1,57 @@ +import esphome.codegen as cg +from esphome.components import button +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_RESTART, + ENTITY_CATEGORY_DIAGNOSTIC, + ENTITY_CATEGORY_CONFIG, + ICON_RESTART, + ICON_RESTART_ALERT, + ICON_DATABASE, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +QueryButton = ld2410_ns.class_("QueryButton", button.Button) +ResetButton = ld2410_ns.class_("ResetButton", button.Button) +RestartButton = ld2410_ns.class_("RestartButton", button.Button) + +CONF_FACTORY_RESET = "factory_reset" +CONF_RESTART = "restart" +CONF_QUERY_PARAMS = "query_params" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_FACTORY_RESET): button.button_schema( + ResetButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RESTART_ALERT, + ), + cv.Optional(CONF_RESTART): button.button_schema( + RestartButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_RESTART, + ), + cv.Optional(CONF_QUERY_PARAMS): button.button_schema( + QueryButton, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_DATABASE, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if factory_reset_config := config.get(CONF_FACTORY_RESET): + b = await button.new_button(factory_reset_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_reset_button(b)) + if restart_config := config.get(CONF_RESTART): + b = await button.new_button(restart_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_restart_button(b)) + if query_params_config := config.get(CONF_QUERY_PARAMS): + b = await button.new_button(query_params_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_query_button(b)) diff --git a/esphome/components/ld2410/button/query_button.cpp b/esphome/components/ld2410/button/query_button.cpp new file mode 100644 index 0000000000..47ab416f5a --- /dev/null +++ b/esphome/components/ld2410/button/query_button.cpp @@ -0,0 +1,9 @@ +#include "query_button.h" + +namespace esphome { +namespace ld2410 { + +void QueryButton::press_action() { this->parent_->read_all_info(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/query_button.h b/esphome/components/ld2410/button/query_button.h new file mode 100644 index 0000000000..c7a47e32d8 --- /dev/null +++ b/esphome/components/ld2410/button/query_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class QueryButton : public button::Button, public Parented { + public: + QueryButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/reset_button.cpp b/esphome/components/ld2410/button/reset_button.cpp new file mode 100644 index 0000000000..f16c5faa79 --- /dev/null +++ b/esphome/components/ld2410/button/reset_button.cpp @@ -0,0 +1,9 @@ +#include "reset_button.h" + +namespace esphome { +namespace ld2410 { + +void ResetButton::press_action() { this->parent_->factory_reset(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/reset_button.h b/esphome/components/ld2410/button/reset_button.h new file mode 100644 index 0000000000..78dd92c9f5 --- /dev/null +++ b/esphome/components/ld2410/button/reset_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class ResetButton : public button::Button, public Parented { + public: + ResetButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/restart_button.cpp b/esphome/components/ld2410/button/restart_button.cpp new file mode 100644 index 0000000000..de0d36c1ef --- /dev/null +++ b/esphome/components/ld2410/button/restart_button.cpp @@ -0,0 +1,9 @@ +#include "restart_button.h" + +namespace esphome { +namespace ld2410 { + +void RestartButton::press_action() { this->parent_->restart_and_read_all_info(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/restart_button.h b/esphome/components/ld2410/button/restart_button.h new file mode 100644 index 0000000000..d00dc05a53 --- /dev/null +++ b/esphome/components/ld2410/button/restart_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class RestartButton : public button::Button, public Parented { + public: + RestartButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index 8e67ba54d7..c3b57815d6 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -1,5 +1,13 @@ #include "ld2410.h" +#include +#ifdef USE_NUMBER +#include "esphome/components/number/number.h" +#endif +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + #define highbyte(val) (uint8_t)((val) >> 8) #define lowbyte(val) (uint8_t)((val) &0xff) @@ -8,48 +16,97 @@ namespace ld2410 { static const char *const TAG = "ld2410"; +LD2410Component::LD2410Component() {} + void LD2410Component::dump_config() { ESP_LOGCONFIG(TAG, "LD2410:"); #ifdef USE_BINARY_SENSOR - LOG_BINARY_SENSOR(" ", "HasTargetSensor", this->target_binary_sensor_); - LOG_BINARY_SENSOR(" ", "MovingSensor", this->moving_binary_sensor_); - LOG_BINARY_SENSOR(" ", "StillSensor", this->still_binary_sensor_); + LOG_BINARY_SENSOR(" ", "TargetBinarySensor", this->target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "MovingTargetBinarySensor", this->moving_target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "StillTargetBinarySensor", this->still_target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "OutPinPresenceStatusBinarySensor", this->out_pin_presence_status_binary_sensor_); +#endif +#ifdef USE_SWITCH + LOG_SWITCH(" ", "EngineeringModeSwitch", this->engineering_mode_switch_); + LOG_SWITCH(" ", "BluetoothSwitch", this->bluetooth_switch_); +#endif +#ifdef USE_BUTTON + LOG_BUTTON(" ", "ResetButton", this->reset_button_); + LOG_BUTTON(" ", "RestartButton", this->restart_button_); + LOG_BUTTON(" ", "QueryButton", this->query_button_); #endif #ifdef USE_SENSOR - LOG_SENSOR(" ", "Moving Distance", this->moving_target_distance_sensor_); - LOG_SENSOR(" ", "Still Distance", this->still_target_distance_sensor_); - LOG_SENSOR(" ", "Moving Energy", this->moving_target_energy_sensor_); - LOG_SENSOR(" ", "Still Energy", this->still_target_energy_sensor_); - LOG_SENSOR(" ", "Detection Distance", this->detection_distance_sensor_); + LOG_SENSOR(" ", "LightSensor", this->light_sensor_); + LOG_SENSOR(" ", "MovingTargetDistanceSensor", this->moving_target_distance_sensor_); + LOG_SENSOR(" ", "StillTargetDistanceSensor", this->still_target_distance_sensor_); + LOG_SENSOR(" ", "MovingTargetEnergySensor", this->moving_target_energy_sensor_); + LOG_SENSOR(" ", "StillTargetEnergySensor", this->still_target_energy_sensor_); + LOG_SENSOR(" ", "DetectionDistanceSensor", this->detection_distance_sensor_); + for (sensor::Sensor *s : this->gate_still_sensors_) { + LOG_SENSOR(" ", "NthGateStillSesnsor", s); + } + for (sensor::Sensor *s : this->gate_move_sensors_) { + LOG_SENSOR(" ", "NthGateMoveSesnsor", s); + } #endif - this->set_config_mode_(true); - this->get_version_(); - this->set_config_mode_(false); - ESP_LOGCONFIG(TAG, " Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], - this->version_[3], this->version_[4], this->version_[5]); +#ifdef USE_TEXT_SENSOR + LOG_TEXT_SENSOR(" ", "VersionTextSensor", this->version_text_sensor_); + LOG_TEXT_SENSOR(" ", "MacTextSensor", this->mac_text_sensor_); +#endif +#ifdef USE_SELECT + LOG_SELECT(" ", "LightFunctionSelect", this->light_function_select_); + LOG_SELECT(" ", "OutPinLevelSelect", this->out_pin_level_select_); + LOG_SELECT(" ", "DistanceResolutionSelect", this->distance_resolution_select_); + LOG_SELECT(" ", "BaudRateSelect", this->baud_rate_select_); +#endif +#ifdef USE_NUMBER + LOG_NUMBER(" ", "LightThresholdNumber", this->light_threshold_number_); + LOG_NUMBER(" ", "MaxStillDistanceGateNumber", this->max_still_distance_gate_number_); + LOG_NUMBER(" ", "MaxMoveDistanceGateNumber", this->max_move_distance_gate_number_); + LOG_NUMBER(" ", "TimeoutNumber", this->timeout_number_); + for (number::Number *n : this->gate_still_threshold_numbers_) { + LOG_NUMBER(" ", "Still Thresholds Number", n); + } + for (number::Number *n : this->gate_move_threshold_numbers_) { + LOG_NUMBER(" ", "Move Thresholds Number", n); + } +#endif + this->read_all_info(); + ESP_LOGCONFIG(TAG, " Throttle_ : %ums", this->throttle_); + ESP_LOGCONFIG(TAG, " MAC Address : %s", const_cast(this->mac_.c_str())); + ESP_LOGCONFIG(TAG, " Firmware Version : %s", const_cast(this->version_.c_str())); } void LD2410Component::setup() { ESP_LOGCONFIG(TAG, "Setting up LD2410..."); - this->set_config_mode_(true); - this->set_max_distances_timeout_(this->max_move_distance_, this->max_still_distance_, this->timeout_); - // Configure Gates sensitivity - this->set_gate_threshold_(0, this->rg0_move_threshold_, this->rg0_still_threshold_); - this->set_gate_threshold_(1, this->rg1_move_threshold_, this->rg1_still_threshold_); - this->set_gate_threshold_(2, this->rg2_move_threshold_, this->rg2_still_threshold_); - this->set_gate_threshold_(3, this->rg3_move_threshold_, this->rg3_still_threshold_); - this->set_gate_threshold_(4, this->rg4_move_threshold_, this->rg4_still_threshold_); - this->set_gate_threshold_(5, this->rg5_move_threshold_, this->rg5_still_threshold_); - this->set_gate_threshold_(6, this->rg6_move_threshold_, this->rg6_still_threshold_); - this->set_gate_threshold_(7, this->rg7_move_threshold_, this->rg7_still_threshold_); - this->set_gate_threshold_(8, this->rg8_move_threshold_, this->rg8_still_threshold_); - this->get_version_(); - this->set_config_mode_(false); - ESP_LOGCONFIG(TAG, "Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], - this->version_[3], this->version_[4], this->version_[5]); + this->read_all_info(); + ESP_LOGCONFIG(TAG, "Mac Address : %s", const_cast(this->mac_.c_str())); + ESP_LOGCONFIG(TAG, "Firmware Version : %s", const_cast(this->version_.c_str())); ESP_LOGCONFIG(TAG, "LD2410 setup complete."); } +void LD2410Component::read_all_info() { + this->set_config_mode_(true); + this->get_version_(); + this->get_mac_(); + this->get_distance_resolution_(); + this->get_light_control_(); + this->query_parameters_(); + this->set_config_mode_(false); +#ifdef USE_SELECT + const auto baud_rate = std::to_string(this->parent_->get_baud_rate()); + if (this->baud_rate_select_ != nullptr && this->baud_rate_select_->state != baud_rate) { + this->baud_rate_select_->publish_state(baud_rate); + } +#endif +} + +void LD2410Component::restart_and_read_all_info() { + this->set_config_mode_(true); + this->restart_(); + this->set_timeout(1000, [this]() { this->read_all_info(); }); +} + void LD2410Component::loop() { const int max_line_length = 80; static uint8_t buffer[max_line_length]; @@ -59,9 +116,8 @@ void LD2410Component::loop() { } } -void LD2410Component::send_command_(uint8_t command, uint8_t *command_value, int command_value_len) { - // lastCommandSuccess->publish_state(false); - +void LD2410Component::send_command_(uint8_t command, const uint8_t *command_value, int command_value_len) { + ESP_LOGV(TAG, "Sending COMMAND %02X", command); // frame start bytes this->write_array(CMD_FRAME_HEADER, 4); // length bytes @@ -95,40 +151,43 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { if (buffer[7] != HEAD || buffer[len - 6] != END || buffer[len - 5] != CHECK) // Check constant values return; // data head=0xAA, data end=0x55, crc=0x00 - /* - Data Type: 6th - 0x01: Engineering mode - 0x02: Normal mode - */ - // char data_type = buffer[DATA_TYPES]; - /* - Target states: 9th - 0x00 = No target - 0x01 = Moving targets - 0x02 = Still targets - 0x03 = Moving+Still targets - */ -#ifdef USE_BINARY_SENSOR - char target_state = buffer[TARGET_STATES]; - if (this->target_binary_sensor_ != nullptr) { - this->target_binary_sensor_->publish_state(target_state != 0x00); - } -#endif - /* Reduce data update rate to prevent home assistant database size grow fast */ int32_t current_millis = millis(); - if (current_millis - last_periodic_millis < 1000) + if (current_millis - last_periodic_millis_ < this->throttle_) return; - last_periodic_millis = current_millis; + last_periodic_millis_ = current_millis; -#ifdef USE_BINARY_SENSOR - if (this->moving_binary_sensor_ != nullptr) { - this->moving_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + /* + Data Type: 7th + 0x01: Engineering mode + 0x02: Normal mode + */ + bool engineering_mode = buffer[DATA_TYPES] == 0x01; +#ifdef USE_SWITCH + if (this->engineering_mode_switch_ != nullptr && + current_millis - last_engineering_mode_change_millis_ > this->throttle_) { + this->engineering_mode_switch_->publish_state(engineering_mode); } - if (this->still_binary_sensor_ != nullptr) { - this->still_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); +#endif +#ifdef USE_BINARY_SENSOR + /* + Target states: 9th + 0x00 = No target + 0x01 = Moving targets + 0x02 = Still targets + 0x03 = Moving+Still targets + */ + char target_state = buffer[TARGET_STATES]; + if (this->target_binary_sensor_ != nullptr) { + this->target_binary_sensor_->publish_state(target_state != 0x00); + } + if (this->moving_target_binary_sensor_ != nullptr) { + this->moving_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + } + if (this->still_target_binary_sensor_ != nullptr) { + this->still_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); } #endif /* @@ -164,26 +223,126 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { if (this->detection_distance_sensor_->get_state() != new_detect_distance) this->detection_distance_sensor_->publish_state(new_detect_distance); } + if (engineering_mode) { + /* + Moving distance range: 18th byte + Still distance range: 19th byte + Moving enery: 20~28th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_move_sensors_.size(); i++) { + sensor::Sensor *s = this->gate_move_sensors_[i]; + if (s != nullptr) { + s->publish_state(buffer[MOVING_SENSOR_START + i]); + } + } + /* + Still energy: 29~37th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_still_sensors_.size(); i++) { + sensor::Sensor *s = this->gate_still_sensors_[i]; + if (s != nullptr) { + s->publish_state(buffer[STILL_SENSOR_START + i]); + } + } + /* + Light sensor: 38th bytes + */ + if (this->light_sensor_ != nullptr) { + int new_light_sensor = buffer[LIGHT_SENSOR]; + if (this->light_sensor_->get_state() != new_light_sensor) + this->light_sensor_->publish_state(new_light_sensor); + } + } else { + for (auto *s : this->gate_move_sensors_) { + if (s != nullptr && !std::isnan(s->get_state())) { + s->publish_state(NAN); + } + } + for (auto *s : this->gate_still_sensors_) { + if (s != nullptr && !std::isnan(s->get_state())) { + s->publish_state(NAN); + } + } + if (this->light_sensor_ != nullptr && !std::isnan(this->light_sensor_->get_state())) { + this->light_sensor_->publish_state(NAN); + } + } +#endif +#ifdef USE_BINARY_SENSOR + if (engineering_mode) { + if (this->out_pin_presence_status_binary_sensor_ != nullptr) { + this->out_pin_presence_status_binary_sensor_->publish_state(buffer[OUT_PIN_SENSOR] == 0x01); + } + } else { + if (this->out_pin_presence_status_binary_sensor_ != nullptr) { + this->out_pin_presence_status_binary_sensor_->publish_state(false); + } + } #endif } -void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { - ESP_LOGV(TAG, "Handling ACK DATA for COMMAND"); +const char VERSION_FMT[] = "%u.%02X.%02X%02X%02X%02X"; + +std::string format_version(uint8_t *buffer) { + std::string::size_type version_size = 256; + std::string version; + do { + version.resize(version_size + 1); + version_size = std::snprintf(&version[0], version.size(), VERSION_FMT, buffer[13], buffer[12], buffer[17], + buffer[16], buffer[15], buffer[14]); + } while (version_size + 1 > version.size()); + version.resize(version_size); + return version; +} + +const char MAC_FMT[] = "%02X:%02X:%02X:%02X:%02X:%02X"; + +const std::string UNKNOWN_MAC("unknown"); +const std::string NO_MAC("08:05:04:03:02:01"); + +std::string format_mac(uint8_t *buffer) { + std::string::size_type mac_size = 256; + std::string mac; + do { + mac.resize(mac_size + 1); + mac_size = std::snprintf(&mac[0], mac.size(), MAC_FMT, buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], + buffer[15]); + } while (mac_size + 1 > mac.size()); + mac.resize(mac_size); + if (mac == NO_MAC) { + return UNKNOWN_MAC; + } + return mac; +} + +#ifdef USE_NUMBER +std::function set_number_value(number::Number *n, float value) { + float normalized_value = value * 1.0; + if (n != nullptr && (!n->has_state() || n->state != normalized_value)) { + n->state = normalized_value; + return [n, normalized_value]() { n->publish_state(normalized_value); }; + } + return []() {}; +} +#endif + +bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { + ESP_LOGV(TAG, "Handling ACK DATA for COMMAND %02X", buffer[COMMAND]); if (len < 10) { ESP_LOGE(TAG, "Error with last command : incorrect length"); - return; + return true; } if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // check 4 frame start bytes ESP_LOGE(TAG, "Error with last command : incorrect Header"); - return; + return true; } if (buffer[COMMAND_STATUS] != 0x01) { ESP_LOGE(TAG, "Error with last command : status != 0x01"); - return; + return true; } if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) { ESP_LOGE(TAG, "Error with last command , last buffer was: %u , %u", buffer[8], buffer[9]); - return; + return true; } switch (buffer[COMMAND]) { @@ -193,49 +352,127 @@ void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { case lowbyte(CMD_DISABLE_CONF): ESP_LOGV(TAG, "Handled Disabled conf command"); break; + case lowbyte(CMD_SET_BAUD_RATE): + ESP_LOGV(TAG, "Handled baud rate change command"); +#ifdef USE_SELECT + if (this->baud_rate_select_ != nullptr) { + ESP_LOGE(TAG, "Change baud rate component config to %s and reinstall", this->baud_rate_select_->state.c_str()); + } +#endif + break; case lowbyte(CMD_VERSION): - ESP_LOGV(TAG, "FW Version is: %u.%u.%u%u%u%u", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15], - buffer[14]); - this->version_[0] = buffer[13]; - this->version_[1] = buffer[12]; - this->version_[2] = buffer[17]; - this->version_[3] = buffer[16]; - this->version_[4] = buffer[15]; - this->version_[5] = buffer[14]; - + this->version_ = format_version(buffer); + ESP_LOGV(TAG, "FW Version is: %s", const_cast(this->version_.c_str())); +#ifdef USE_TEXT_SENSOR + if (this->version_text_sensor_ != nullptr) { + this->version_text_sensor_->publish_state(this->version_); + } +#endif + break; + case lowbyte(CMD_QUERY_DISTANCE_RESOLUTION): { + std::string distance_resolution = + DISTANCE_RESOLUTION_INT_TO_ENUM.at(this->two_byte_to_int_(buffer[10], buffer[11])); + ESP_LOGV(TAG, "Distance resolution is: %s", const_cast(distance_resolution.c_str())); +#ifdef USE_SELECT + if (this->distance_resolution_select_ != nullptr && + this->distance_resolution_select_->state != distance_resolution) { + this->distance_resolution_select_->publish_state(distance_resolution); + } +#endif + } break; + case lowbyte(CMD_QUERY_LIGHT_CONTROL): { + this->light_function_ = LIGHT_FUNCTION_INT_TO_ENUM.at(buffer[10]); + this->light_threshold_ = buffer[11] * 1.0; + this->out_pin_level_ = OUT_PIN_LEVEL_INT_TO_ENUM.at(buffer[12]); + ESP_LOGV(TAG, "Light function is: %s", const_cast(this->light_function_.c_str())); + ESP_LOGV(TAG, "Light threshold is: %f", this->light_threshold_); + ESP_LOGV(TAG, "Out pin level is: %s", const_cast(this->out_pin_level_.c_str())); +#ifdef USE_SELECT + if (this->light_function_select_ != nullptr && this->light_function_select_->state != this->light_function_) { + this->light_function_select_->publish_state(this->light_function_); + } + if (this->out_pin_level_select_ != nullptr && this->out_pin_level_select_->state != this->out_pin_level_) { + this->out_pin_level_select_->publish_state(this->out_pin_level_); + } +#endif +#ifdef USE_NUMBER + if (this->light_threshold_number_ != nullptr && + (!this->light_threshold_number_->has_state() || + this->light_threshold_number_->state != this->light_threshold_)) { + this->light_threshold_number_->publish_state(this->light_threshold_); + } +#endif + } break; + case lowbyte(CMD_MAC): + if (len < 20) { + return false; + } + this->mac_ = format_mac(buffer); + ESP_LOGV(TAG, "MAC Address is: %s", const_cast(this->mac_.c_str())); +#ifdef USE_TEXT_SENSOR + if (this->mac_text_sensor_ != nullptr) { + this->mac_text_sensor_->publish_state(this->mac_); + } +#endif +#ifdef USE_SWITCH + if (this->bluetooth_switch_ != nullptr) { + this->bluetooth_switch_->publish_state(this->mac_ != UNKNOWN_MAC); + } +#endif break; case lowbyte(CMD_GATE_SENS): ESP_LOGV(TAG, "Handled sensitivity command"); break; + case lowbyte(CMD_BLUETOOTH): + ESP_LOGV(TAG, "Handled bluetooth command"); + break; + case lowbyte(CMD_SET_DISTANCE_RESOLUTION): + ESP_LOGV(TAG, "Handled set distance resolution command"); + break; + case lowbyte(CMD_SET_LIGHT_CONTROL): + ESP_LOGV(TAG, "Handled set light control command"); + break; + case lowbyte(CMD_BT_PASSWORD): + ESP_LOGV(TAG, "Handled set bluetooth password command"); + break; case lowbyte(CMD_QUERY): // Query parameters response { if (buffer[10] != 0xAA) - return; // value head=0xAA + return true; // value head=0xAA +#ifdef USE_NUMBER /* Moving distance range: 13th byte Still distance range: 14th byte */ - // TODO - // maxMovingDistanceRange->publish_state(buffer[12]); - // maxStillDistanceRange->publish_state(buffer[13]); + std::vector> updates; + updates.push_back(set_number_value(this->max_move_distance_gate_number_, buffer[12])); + updates.push_back(set_number_value(this->max_still_distance_gate_number_, buffer[13])); /* Moving Sensitivities: 15~23th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_move_threshold_numbers_.size(); i++) { + updates.push_back(set_number_value(this->gate_move_threshold_numbers_[i], buffer[14 + i])); + } + /* Still Sensitivities: 24~32th bytes */ - for (int i = 0; i < 9; i++) { - moving_sensitivities[i] = buffer[14 + i]; - } - for (int i = 0; i < 9; i++) { - still_sensitivities[i] = buffer[23 + i]; + for (std::vector::size_type i = 0; i != this->gate_still_threshold_numbers_.size(); i++) { + updates.push_back(set_number_value(this->gate_still_threshold_numbers_[i], buffer[23 + i])); } /* None Duration: 33~34th bytes */ - // noneDuration->publish_state(this->two_byte_to_int_(buffer[32], buffer[33])); + updates.push_back(set_number_value(this->timeout_number_, this->two_byte_to_int_(buffer[32], buffer[33]))); + for (auto &update : updates) { + update(); + } +#endif } break; default: break; } + + return true; } void LD2410Component::readline_(int readch, uint8_t *buffer, int len) { @@ -256,8 +493,11 @@ void LD2410Component::readline_(int readch, uint8_t *buffer, int len) { } else if (buffer[pos - 4] == 0x04 && buffer[pos - 3] == 0x03 && buffer[pos - 2] == 0x02 && buffer[pos - 1] == 0x01) { ESP_LOGV(TAG, "Will handle ACK Data"); - this->handle_ack_data_(buffer, pos); - pos = 0; // Reset position index ready for next time + if (this->handle_ack_data_(buffer, pos)) { + pos = 0; // Reset position index ready for next time + } else { + ESP_LOGV(TAG, "ACK Data incomplete"); + } } } } @@ -269,21 +509,85 @@ void LD2410Component::set_config_mode_(bool enable) { this->send_command_(cmd, enable ? cmd_value : nullptr, 2); } +void LD2410Component::set_bluetooth(bool enable) { + this->set_config_mode_(true); + uint8_t enable_cmd_value[2] = {0x01, 0x00}; + uint8_t disable_cmd_value[2] = {0x00, 0x00}; + this->send_command_(CMD_BLUETOOTH, enable ? enable_cmd_value : disable_cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::set_distance_resolution(const std::string &state) { + this->set_config_mode_(true); + uint8_t cmd_value[2] = {DISTANCE_RESOLUTION_ENUM_TO_INT.at(state), 0x00}; + this->send_command_(CMD_SET_DISTANCE_RESOLUTION, cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::set_baud_rate(const std::string &state) { + this->set_config_mode_(true); + uint8_t cmd_value[2] = {BAUD_RATE_ENUM_TO_INT.at(state), 0x00}; + this->send_command_(CMD_SET_BAUD_RATE, cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_(); }); +} + +void LD2410Component::set_bluetooth_password(const std::string &password) { + if (password.length() != 6) { + ESP_LOGE(TAG, "set_bluetooth_password(): invalid password length, must be exactly 6 chars '%s'", password.c_str()); + return; + } + this->set_config_mode_(true); + uint8_t cmd_value[6]; + std::copy(password.begin(), password.end(), std::begin(cmd_value)); + this->send_command_(CMD_BT_PASSWORD, cmd_value, 6); + this->set_config_mode_(false); +} + +void LD2410Component::set_engineering_mode(bool enable) { + this->set_config_mode_(true); + last_engineering_mode_change_millis_ = millis(); + uint8_t cmd = enable ? CMD_ENABLE_ENG : CMD_DISABLE_ENG; + this->send_command_(cmd, nullptr, 0); + this->set_config_mode_(false); +} + +void LD2410Component::factory_reset() { + this->set_config_mode_(true); + this->send_command_(CMD_RESET, nullptr, 0); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::restart_() { this->send_command_(CMD_RESTART, nullptr, 0); } + void LD2410Component::query_parameters_() { this->send_command_(CMD_QUERY, nullptr, 0); } void LD2410Component::get_version_() { this->send_command_(CMD_VERSION, nullptr, 0); } +void LD2410Component::get_mac_() { + uint8_t cmd_value[2] = {0x01, 0x00}; + this->send_command_(CMD_MAC, cmd_value, 2); +} +void LD2410Component::get_distance_resolution_() { this->send_command_(CMD_QUERY_DISTANCE_RESOLUTION, nullptr, 0); } -void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, - uint16_t timeout) { +void LD2410Component::get_light_control_() { this->send_command_(CMD_QUERY_LIGHT_CONTROL, nullptr, 0); } + +#ifdef USE_NUMBER +void LD2410Component::set_max_distances_timeout() { + if (!this->max_move_distance_gate_number_->has_state() || !this->max_still_distance_gate_number_->has_state() || + !this->timeout_number_->has_state()) { + return; + } + int max_moving_distance_gate_range = static_cast(this->max_move_distance_gate_number_->state); + int max_still_distance_gate_range = static_cast(this->max_still_distance_gate_number_->state); + int timeout = static_cast(this->timeout_number_->state); uint8_t value[18] = {0x00, 0x00, - lowbyte(max_moving_distance_range), - highbyte(max_moving_distance_range), + lowbyte(max_moving_distance_gate_range), + highbyte(max_moving_distance_gate_range), 0x00, 0x00, 0x01, 0x00, - lowbyte(max_still_distance_range), - highbyte(max_still_distance_range), + lowbyte(max_still_distance_gate_range), + highbyte(max_still_distance_gate_range), 0x00, 0x00, 0x02, @@ -292,10 +596,25 @@ void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_ran highbyte(timeout), 0x00, 0x00}; + this->set_config_mode_(true); this->send_command_(CMD_MAXDIST_DURATION, value, 18); + delay(50); // NOLINT this->query_parameters_(); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); + this->set_config_mode_(false); } -void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens) { + +void LD2410Component::set_gate_threshold(uint8_t gate) { + number::Number *motionsens = this->gate_move_threshold_numbers_[gate]; + number::Number *stillsens = this->gate_still_threshold_numbers_[gate]; + + if (!motionsens->has_state() || !stillsens->has_state()) { + return; + } + int motion = static_cast(motionsens->state); + int still = static_cast(stillsens->state); + + this->set_config_mode_(true); // reference // https://drive.google.com/drive/folders/1p4dhbEJA3YubyIjIIC7wwVsSo8x29Fq-?spm=a2g0o.detail.1000023.17.93465697yFwVxH // Send data: configure the motion sensitivity of distance gate 3 to 40, and the static sensitivity of 40 @@ -305,11 +624,57 @@ void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint // 28 00 00 00 (value) // 02 00 (still sensitivtiy) // 28 00 00 00 (value) - uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00, - 0x01, 0x00, lowbyte(motionsens), highbyte(motionsens), 0x00, 0x00, - 0x02, 0x00, lowbyte(stillsens), highbyte(stillsens), 0x00, 0x00}; + uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00, + 0x01, 0x00, lowbyte(motion), highbyte(motion), 0x00, 0x00, + 0x02, 0x00, lowbyte(still), highbyte(still), 0x00, 0x00}; this->send_command_(CMD_GATE_SENS, value, 18); + delay(50); // NOLINT + this->query_parameters_(); + this->set_config_mode_(false); } +void LD2410Component::set_gate_still_threshold_number(int gate, number::Number *n) { + this->gate_still_threshold_numbers_[gate] = n; +} + +void LD2410Component::set_gate_move_threshold_number(int gate, number::Number *n) { + this->gate_move_threshold_numbers_[gate] = n; +} +#endif + +void LD2410Component::set_light_out_control() { +#ifdef USE_NUMBER + if (this->light_threshold_number_ != nullptr && this->light_threshold_number_->has_state()) { + this->light_threshold_ = this->light_threshold_number_->state; + } +#endif +#ifdef USE_SELECT + if (this->light_function_select_ != nullptr && this->light_function_select_->has_state()) { + this->light_function_ = this->light_function_select_->state; + } + if (this->out_pin_level_select_ != nullptr && this->out_pin_level_select_->has_state()) { + this->out_pin_level_ = this->out_pin_level_select_->state; + } +#endif + if (this->light_function_.empty() || this->out_pin_level_.empty() || this->light_threshold_ < 0) { + return; + } + this->set_config_mode_(true); + uint8_t light_function = LIGHT_FUNCTION_ENUM_TO_INT.at(this->light_function_); + uint8_t light_threshold = static_cast(this->light_threshold_); + uint8_t out_pin_level = OUT_PIN_LEVEL_ENUM_TO_INT.at(this->out_pin_level_); + uint8_t value[4] = {light_function, light_threshold, out_pin_level, 0x00}; + this->send_command_(CMD_SET_LIGHT_CONTROL, value, 4); + delay(50); // NOLINT + this->get_light_control_(); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); + this->set_config_mode_(false); +} + +#ifdef USE_SENSOR +void LD2410Component::set_gate_move_sensor(int gate, sensor::Sensor *s) { this->gate_move_sensors_[gate] = s; } +void LD2410Component::set_gate_still_sensor(int gate, sensor::Sensor *s) { this->gate_still_sensors_[gate] = s; } +#endif + } // namespace ld2410 } // namespace esphome diff --git a/esphome/components/ld2410/ld2410.h b/esphome/components/ld2410/ld2410.h index 8edb83a8d5..8084d4c33e 100644 --- a/esphome/components/ld2410/ld2410.h +++ b/esphome/components/ld2410/ld2410.h @@ -7,10 +7,27 @@ #ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" #endif +#ifdef USE_NUMBER +#include "esphome/components/number/number.h" +#endif +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif +#ifdef USE_BUTTON +#include "esphome/components/button/button.h" +#endif +#ifdef USE_SELECT +#include "esphome/components/select/select.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif #include "esphome/components/uart/uart.h" #include "esphome/core/automation.h" #include "esphome/core/helpers.h" +#include + namespace esphome { namespace ld2410 { @@ -19,10 +36,63 @@ namespace ld2410 { // Commands static const uint8_t CMD_ENABLE_CONF = 0x00FF; static const uint8_t CMD_DISABLE_CONF = 0x00FE; +static const uint8_t CMD_ENABLE_ENG = 0x0062; +static const uint8_t CMD_DISABLE_ENG = 0x0063; static const uint8_t CMD_MAXDIST_DURATION = 0x0060; static const uint8_t CMD_QUERY = 0x0061; static const uint8_t CMD_GATE_SENS = 0x0064; static const uint8_t CMD_VERSION = 0x00A0; +static const uint8_t CMD_QUERY_DISTANCE_RESOLUTION = 0x00AB; +static const uint8_t CMD_SET_DISTANCE_RESOLUTION = 0x00AA; +static const uint8_t CMD_QUERY_LIGHT_CONTROL = 0x00AE; +static const uint8_t CMD_SET_LIGHT_CONTROL = 0x00AD; +static const uint8_t CMD_SET_BAUD_RATE = 0x00A1; +static const uint8_t CMD_BT_PASSWORD = 0x00A9; +static const uint8_t CMD_MAC = 0x00A5; +static const uint8_t CMD_RESET = 0x00A2; +static const uint8_t CMD_RESTART = 0x00A3; +static const uint8_t CMD_BLUETOOTH = 0x00A4; + +enum BaudRateStructure : uint8_t { + BAUD_RATE_9600 = 1, + BAUD_RATE_19200 = 2, + BAUD_RATE_38400 = 3, + BAUD_RATE_57600 = 4, + BAUD_RATE_115200 = 5, + BAUD_RATE_230400 = 6, + BAUD_RATE_256000 = 7, + BAUD_RATE_460800 = 8 +}; + +static const std::map BAUD_RATE_ENUM_TO_INT{ + {"9600", BAUD_RATE_9600}, {"19200", BAUD_RATE_19200}, {"38400", BAUD_RATE_38400}, + {"57600", BAUD_RATE_57600}, {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, + {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}}; + +enum DistanceResolutionStructure : uint8_t { DISTANCE_RESOLUTION_0_2 = 0x01, DISTANCE_RESOLUTION_0_75 = 0x00 }; + +static const std::map DISTANCE_RESOLUTION_ENUM_TO_INT{{"0.2m", DISTANCE_RESOLUTION_0_2}, + {"0.75m", DISTANCE_RESOLUTION_0_75}}; +static const std::map DISTANCE_RESOLUTION_INT_TO_ENUM{{DISTANCE_RESOLUTION_0_2, "0.2m"}, + {DISTANCE_RESOLUTION_0_75, "0.75m"}}; + +enum LightFunctionStructure : uint8_t { + LIGHT_FUNCTION_OFF = 0x00, + LIGHT_FUNCTION_BELOW = 0x01, + LIGHT_FUNCTION_ABOVE = 0x02 +}; + +static const std::map LIGHT_FUNCTION_ENUM_TO_INT{ + {"off", LIGHT_FUNCTION_OFF}, {"below", LIGHT_FUNCTION_BELOW}, {"above", LIGHT_FUNCTION_ABOVE}}; +static const std::map LIGHT_FUNCTION_INT_TO_ENUM{ + {LIGHT_FUNCTION_OFF, "off"}, {LIGHT_FUNCTION_BELOW, "below"}, {LIGHT_FUNCTION_ABOVE, "above"}}; + +enum OutPinLevelStructure : uint8_t { OUT_PIN_LEVEL_LOW = 0x00, OUT_PIN_LEVEL_HIGH = 0x01 }; + +static const std::map OUT_PIN_LEVEL_ENUM_TO_INT{{"low", OUT_PIN_LEVEL_LOW}, + {"high", OUT_PIN_LEVEL_HIGH}}; +static const std::map OUT_PIN_LEVEL_INT_TO_ENUM{{OUT_PIN_LEVEL_LOW, "low"}, + {OUT_PIN_LEVEL_HIGH, "high"}}; // Commands values static const uint8_t CMD_MAX_MOVE_VALUE = 0x0000; @@ -44,7 +114,7 @@ Target states: 9th byte Detect distance: 16~17th bytes */ enum PeriodicDataStructure : uint8_t { - DATA_TYPES = 5, + DATA_TYPES = 6, TARGET_STATES = 8, MOVING_TARGET_LOW = 9, MOVING_TARGET_HIGH = 10, @@ -54,6 +124,10 @@ enum PeriodicDataStructure : uint8_t { STILL_ENERGY = 14, DETECT_DISTANCE_LOW = 15, DETECT_DISTANCE_HIGH = 16, + MOVING_SENSOR_START = 19, + STILL_SENSOR_START = 28, + LIGHT_SENSOR = 37, + OUT_PIN_SENSOR = 38, }; enum PeriodicDataValue : uint8_t { HEAD = 0XAA, END = 0x55, CHECK = 0x00 }; @@ -66,80 +140,97 @@ class LD2410Component : public Component, public uart::UARTDevice { SUB_SENSOR(still_target_distance) SUB_SENSOR(moving_target_energy) SUB_SENSOR(still_target_energy) + SUB_SENSOR(light) SUB_SENSOR(detection_distance) #endif +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(target) + SUB_BINARY_SENSOR(moving_target) + SUB_BINARY_SENSOR(still_target) + SUB_BINARY_SENSOR(out_pin_presence_status) +#endif +#ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(version) + SUB_TEXT_SENSOR(mac) +#endif +#ifdef USE_SELECT + SUB_SELECT(distance_resolution) + SUB_SELECT(baud_rate) + SUB_SELECT(light_function) + SUB_SELECT(out_pin_level) +#endif +#ifdef USE_SWITCH + SUB_SWITCH(engineering_mode) + SUB_SWITCH(bluetooth) +#endif +#ifdef USE_BUTTON + SUB_BUTTON(reset) + SUB_BUTTON(restart) + SUB_BUTTON(query) +#endif +#ifdef USE_NUMBER + SUB_NUMBER(max_still_distance_gate) + SUB_NUMBER(max_move_distance_gate) + SUB_NUMBER(timeout) + SUB_NUMBER(light_threshold) +#endif public: + LD2410Component(); void setup() override; void dump_config() override; void loop() override; - -#ifdef USE_BINARY_SENSOR - void set_target_sensor(binary_sensor::BinarySensor *sens) { this->target_binary_sensor_ = sens; }; - void set_moving_target_sensor(binary_sensor::BinarySensor *sens) { this->moving_binary_sensor_ = sens; }; - void set_still_target_sensor(binary_sensor::BinarySensor *sens) { this->still_binary_sensor_ = sens; }; + void set_light_out_control(); +#ifdef USE_NUMBER + void set_gate_still_threshold_number(int gate, number::Number *n); + void set_gate_move_threshold_number(int gate, number::Number *n); + void set_max_distances_timeout(); + void set_gate_threshold(uint8_t gate); #endif - - void set_timeout(uint16_t value) { this->timeout_ = value; }; - void set_max_move_distance(uint8_t value) { this->max_move_distance_ = value; }; - void set_max_still_distance(uint8_t value) { this->max_still_distance_ = value; }; - void set_range_config(int rg0_move, int rg0_still, int rg1_move, int rg1_still, int rg2_move, int rg2_still, - int rg3_move, int rg3_still, int rg4_move, int rg4_still, int rg5_move, int rg5_still, - int rg6_move, int rg6_still, int rg7_move, int rg7_still, int rg8_move, int rg8_still) { - this->rg0_move_threshold_ = rg0_move; - this->rg0_still_threshold_ = rg0_still; - this->rg1_move_threshold_ = rg1_move; - this->rg1_still_threshold_ = rg1_still; - this->rg2_move_threshold_ = rg2_move; - this->rg2_still_threshold_ = rg2_still; - this->rg3_move_threshold_ = rg3_move; - this->rg3_still_threshold_ = rg3_still; - this->rg4_move_threshold_ = rg4_move; - this->rg4_still_threshold_ = rg4_still; - this->rg5_move_threshold_ = rg5_move; - this->rg5_still_threshold_ = rg5_still; - this->rg6_move_threshold_ = rg6_move; - this->rg6_still_threshold_ = rg6_still; - this->rg7_move_threshold_ = rg7_move; - this->rg7_still_threshold_ = rg7_still; - this->rg8_move_threshold_ = rg8_move; - this->rg8_still_threshold_ = rg8_still; - }; - int moving_sensitivities[9] = {0}; - int still_sensitivities[9] = {0}; - - int32_t last_periodic_millis = millis(); +#ifdef USE_SENSOR + void set_gate_move_sensor(int gate, sensor::Sensor *s); + void set_gate_still_sensor(int gate, sensor::Sensor *s); +#endif + void set_throttle(uint16_t value) { this->throttle_ = value; }; + void set_bluetooth_password(const std::string &password); + void set_engineering_mode(bool enable); + void read_all_info(); + void restart_and_read_all_info(); + void set_bluetooth(bool enable); + void set_distance_resolution(const std::string &state); + void set_baud_rate(const std::string &state); + void factory_reset(); protected: -#ifdef USE_BINARY_SENSOR - binary_sensor::BinarySensor *target_binary_sensor_{nullptr}; - binary_sensor::BinarySensor *moving_binary_sensor_{nullptr}; - binary_sensor::BinarySensor *still_binary_sensor_{nullptr}; -#endif - - std::vector rx_buffer_; int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } - void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); - - void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, - uint16_t timeout); - void set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens); + void send_command_(uint8_t command_str, const uint8_t *command_value, int command_value_len); void set_config_mode_(bool enable); void handle_periodic_data_(uint8_t *buffer, int len); - void handle_ack_data_(uint8_t *buffer, int len); + bool handle_ack_data_(uint8_t *buffer, int len); void readline_(int readch, uint8_t *buffer, int len); void query_parameters_(); void get_version_(); + void get_mac_(); + void get_distance_resolution_(); + void get_light_control_(); + void restart_(); - uint16_t timeout_; - uint8_t max_move_distance_; - uint8_t max_still_distance_; - - uint8_t version_[6]; - uint8_t rg0_move_threshold_, rg0_still_threshold_, rg1_move_threshold_, rg1_still_threshold_, rg2_move_threshold_, - rg2_still_threshold_, rg3_move_threshold_, rg3_still_threshold_, rg4_move_threshold_, rg4_still_threshold_, - rg5_move_threshold_, rg5_still_threshold_, rg6_move_threshold_, rg6_still_threshold_, rg7_move_threshold_, - rg7_still_threshold_, rg8_move_threshold_, rg8_still_threshold_; + int32_t last_periodic_millis_ = millis(); + int32_t last_engineering_mode_change_millis_ = millis(); + uint16_t throttle_; + std::string version_; + std::string mac_; + std::string out_pin_level_; + std::string light_function_; + float light_threshold_ = -1; +#ifdef USE_NUMBER + std::vector gate_still_threshold_numbers_ = std::vector(9); + std::vector gate_move_threshold_numbers_ = std::vector(9); +#endif +#ifdef USE_SENSOR + std::vector gate_still_sensors_ = std::vector(9); + std::vector gate_move_sensors_ = std::vector(9); +#endif }; } // namespace ld2410 diff --git a/esphome/components/ld2410/number/__init__.py b/esphome/components/ld2410/number/__init__.py new file mode 100644 index 0000000000..557b226dfe --- /dev/null +++ b/esphome/components/ld2410/number/__init__.py @@ -0,0 +1,128 @@ +import esphome.codegen as cg +from esphome.components import number +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_TIMEOUT, + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_SIGNAL_STRENGTH, + DEVICE_CLASS_ILLUMINANCE, + UNIT_SECOND, + UNIT_PERCENT, + ENTITY_CATEGORY_CONFIG, + ICON_MOTION_SENSOR, + ICON_TIMELAPSE, + ICON_LIGHTBULB, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +GateThresholdNumber = ld2410_ns.class_("GateThresholdNumber", number.Number) +LightThresholdNumber = ld2410_ns.class_("LightThresholdNumber", number.Number) +MaxDistanceTimeoutNumber = ld2410_ns.class_("MaxDistanceTimeoutNumber", number.Number) + +CONF_MAX_MOVE_DISTANCE_GATE = "max_move_distance_gate" +CONF_MAX_STILL_DISTANCE_GATE = "max_still_distance_gate" +CONF_LIGHT_THRESHOLD = "light_threshold" +CONF_STILL_THRESHOLD = "still_threshold" +CONF_MOVE_THRESHOLD = "move_threshold" + +TIMEOUT_GROUP = "timeout" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Inclusive(CONF_TIMEOUT, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + unit_of_measurement=UNIT_SECOND, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_TIMELAPSE, + ), + cv.Inclusive(CONF_MAX_MOVE_DISTANCE_GATE, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + device_class=DEVICE_CLASS_DISTANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Inclusive(CONF_MAX_STILL_DISTANCE_GATE, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + device_class=DEVICE_CLASS_DISTANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_LIGHT_THRESHOLD): number.number_schema( + LightThresholdNumber, + device_class=DEVICE_CLASS_ILLUMINANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_LIGHTBULB, + ), + } +) + +CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + { + cv.Optional(f"g{x}"): cv.Schema( + { + cv.Required(CONF_MOVE_THRESHOLD): number.number_schema( + GateThresholdNumber, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Required(CONF_STILL_THRESHOLD): number.number_schema( + GateThresholdNumber, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + } + ) + for x in range(9) + } +) + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if timeout_config := config.get(CONF_TIMEOUT): + n = await number.new_number( + timeout_config, min_value=0, max_value=65535, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_timeout_number(n)) + if max_move_distance_gate_config := config.get(CONF_MAX_MOVE_DISTANCE_GATE): + n = await number.new_number( + max_move_distance_gate_config, min_value=2, max_value=8, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_max_move_distance_gate_number(n)) + if max_still_distance_gate_config := config.get(CONF_MAX_STILL_DISTANCE_GATE): + n = await number.new_number( + max_still_distance_gate_config, min_value=2, max_value=8, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_max_still_distance_gate_number(n)) + if light_threshold_config := config.get(CONF_LIGHT_THRESHOLD): + n = await number.new_number( + light_threshold_config, min_value=0, max_value=255, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_light_threshold_number(n)) + for x in range(9): + if gate_conf := config.get(f"g{x}"): + move_config = gate_conf[CONF_MOVE_THRESHOLD] + n = cg.new_Pvariable(move_config[CONF_ID], x) + await number.register_number( + n, move_config, min_value=0, max_value=100, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_gate_move_threshold_number(x, n)) + + still_config = gate_conf[CONF_STILL_THRESHOLD] + n = cg.new_Pvariable(still_config[CONF_ID], x) + await number.register_number( + n, still_config, min_value=0, max_value=100, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_gate_still_threshold_number(x, n)) diff --git a/esphome/components/ld2410/number/gate_threshold_number.cpp b/esphome/components/ld2410/number/gate_threshold_number.cpp new file mode 100644 index 0000000000..5d040554d7 --- /dev/null +++ b/esphome/components/ld2410/number/gate_threshold_number.cpp @@ -0,0 +1,14 @@ +#include "gate_threshold_number.h" + +namespace esphome { +namespace ld2410 { + +GateThresholdNumber::GateThresholdNumber(uint8_t gate) : gate_(gate) {} + +void GateThresholdNumber::control(float value) { + this->publish_state(value); + this->parent_->set_gate_threshold(this->gate_); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/gate_threshold_number.h b/esphome/components/ld2410/number/gate_threshold_number.h new file mode 100644 index 0000000000..2806ecce63 --- /dev/null +++ b/esphome/components/ld2410/number/gate_threshold_number.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class GateThresholdNumber : public number::Number, public Parented { + public: + GateThresholdNumber(uint8_t gate); + + protected: + uint8_t gate_; + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/light_threshold_number.cpp b/esphome/components/ld2410/number/light_threshold_number.cpp new file mode 100644 index 0000000000..0ff35782cd --- /dev/null +++ b/esphome/components/ld2410/number/light_threshold_number.cpp @@ -0,0 +1,12 @@ +#include "light_threshold_number.h" + +namespace esphome { +namespace ld2410 { + +void LightThresholdNumber::control(float value) { + this->publish_state(value); + this->parent_->set_light_out_control(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/light_threshold_number.h b/esphome/components/ld2410/number/light_threshold_number.h new file mode 100644 index 0000000000..8f014373c0 --- /dev/null +++ b/esphome/components/ld2410/number/light_threshold_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class LightThresholdNumber : public number::Number, public Parented { + public: + LightThresholdNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/max_distance_timeout_number.cpp b/esphome/components/ld2410/number/max_distance_timeout_number.cpp new file mode 100644 index 0000000000..8a946f7ea9 --- /dev/null +++ b/esphome/components/ld2410/number/max_distance_timeout_number.cpp @@ -0,0 +1,12 @@ +#include "max_distance_timeout_number.h" + +namespace esphome { +namespace ld2410 { + +void MaxDistanceTimeoutNumber::control(float value) { + this->publish_state(value); + this->parent_->set_max_distances_timeout(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/max_distance_timeout_number.h b/esphome/components/ld2410/number/max_distance_timeout_number.h new file mode 100644 index 0000000000..7d91b4b5fe --- /dev/null +++ b/esphome/components/ld2410/number/max_distance_timeout_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class MaxDistanceTimeoutNumber : public number::Number, public Parented { + public: + MaxDistanceTimeoutNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/__init__.py b/esphome/components/ld2410/select/__init__.py new file mode 100644 index 0000000000..6c34a85ac6 --- /dev/null +++ b/esphome/components/ld2410/select/__init__.py @@ -0,0 +1,81 @@ +import esphome.codegen as cg +from esphome.components import select +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_CONFIG, + CONF_BAUD_RATE, + ICON_THERMOMETER, + ICON_SCALE, + ICON_LIGHTBULB, + ICON_RULER, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +BaudRateSelect = ld2410_ns.class_("BaudRateSelect", select.Select) +DistanceResolutionSelect = ld2410_ns.class_("DistanceResolutionSelect", select.Select) +LightOutControlSelect = ld2410_ns.class_("LightOutControlSelect", select.Select) + +CONF_DISTANCE_RESOLUTION = "distance_resolution" +CONF_LIGHT_FUNCTION = "light_function" +CONF_OUT_PIN_LEVEL = "out_pin_level" + + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_DISTANCE_RESOLUTION): select.select_schema( + DistanceResolutionSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RULER, + ), + cv.Optional(CONF_LIGHT_FUNCTION): select.select_schema( + LightOutControlSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_LIGHTBULB, + ), + cv.Optional(CONF_OUT_PIN_LEVEL): select.select_schema( + LightOutControlSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SCALE, + ), + cv.Optional(CONF_BAUD_RATE): select.select_schema( + BaudRateSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_THERMOMETER, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if distance_resolution_config := config.get(CONF_DISTANCE_RESOLUTION): + s = await select.new_select( + distance_resolution_config, options=["0.2m", "0.75m"] + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_distance_resolution_select(s)) + if out_pin_level_config := config.get(CONF_OUT_PIN_LEVEL): + s = await select.new_select(out_pin_level_config, options=["low", "high"]) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_out_pin_level_select(s)) + if light_function_config := config.get(CONF_LIGHT_FUNCTION): + s = await select.new_select( + light_function_config, options=["off", "below", "above"] + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_light_function_select(s)) + if baud_rate_config := config.get(CONF_BAUD_RATE): + s = await select.new_select( + baud_rate_config, + options=[ + "9600", + "19200", + "38400", + "57600", + "115200", + "230400", + "256000", + "460800", + ], + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_baud_rate_select(s)) diff --git a/esphome/components/ld2410/select/baud_rate_select.cpp b/esphome/components/ld2410/select/baud_rate_select.cpp new file mode 100644 index 0000000000..f4e0b90e2e --- /dev/null +++ b/esphome/components/ld2410/select/baud_rate_select.cpp @@ -0,0 +1,12 @@ +#include "baud_rate_select.h" + +namespace esphome { +namespace ld2410 { + +void BaudRateSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_baud_rate(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/baud_rate_select.h b/esphome/components/ld2410/select/baud_rate_select.h new file mode 100644 index 0000000000..3827b6a48a --- /dev/null +++ b/esphome/components/ld2410/select/baud_rate_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class BaudRateSelect : public select::Select, public Parented { + public: + BaudRateSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/distance_resolution_select.cpp b/esphome/components/ld2410/select/distance_resolution_select.cpp new file mode 100644 index 0000000000..eef34bda63 --- /dev/null +++ b/esphome/components/ld2410/select/distance_resolution_select.cpp @@ -0,0 +1,12 @@ +#include "distance_resolution_select.h" + +namespace esphome { +namespace ld2410 { + +void DistanceResolutionSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_distance_resolution(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/distance_resolution_select.h b/esphome/components/ld2410/select/distance_resolution_select.h new file mode 100644 index 0000000000..d6affb1020 --- /dev/null +++ b/esphome/components/ld2410/select/distance_resolution_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class DistanceResolutionSelect : public select::Select, public Parented { + public: + DistanceResolutionSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/light_out_control_select.cpp b/esphome/components/ld2410/select/light_out_control_select.cpp new file mode 100644 index 0000000000..ac23248a64 --- /dev/null +++ b/esphome/components/ld2410/select/light_out_control_select.cpp @@ -0,0 +1,12 @@ +#include "light_out_control_select.h" + +namespace esphome { +namespace ld2410 { + +void LightOutControlSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_light_out_control(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/light_out_control_select.h b/esphome/components/ld2410/select/light_out_control_select.h new file mode 100644 index 0000000000..5d72e1774e --- /dev/null +++ b/esphome/components/ld2410/select/light_out_control_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class LightOutControlSelect : public select::Select, public Parented { + public: + LightOutControlSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/sensor.py b/esphome/components/ld2410/sensor.py index b941263134..83361db58a 100644 --- a/esphome/components/ld2410/sensor.py +++ b/esphome/components/ld2410/sensor.py @@ -3,9 +3,15 @@ from esphome.components import sensor import esphome.config_validation as cv from esphome.const import ( DEVICE_CLASS_DISTANCE, - DEVICE_CLASS_ENERGY, UNIT_CENTIMETER, UNIT_PERCENT, + CONF_LIGHT, + DEVICE_CLASS_ILLUMINANCE, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_SIGNAL, + ICON_FLASH, + ICON_MOTION_SENSOR, + ICON_LIGHTBULB, ) from . import CONF_LD2410_ID, LD2410Component @@ -15,41 +21,88 @@ CONF_STILL_DISTANCE = "still_distance" CONF_MOVING_ENERGY = "moving_energy" CONF_STILL_ENERGY = "still_energy" CONF_DETECTION_DISTANCE = "detection_distance" +CONF_MOVE_ENERGY = "move_energy" -CONFIG_SCHEMA = { - cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), - cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), - cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), - cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema( - device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT - ), - cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( - device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT - ), - cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), -} +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_FLASH, + ), + cv.Optional(CONF_LIGHT): sensor.sensor_schema( + device_class=DEVICE_CLASS_ILLUMINANCE, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_LIGHTBULB, + ), + cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + } +) + +CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + { + cv.Optional(f"g{x}"): cv.Schema( + { + cv.Optional(CONF_MOVE_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_FLASH, + ), + } + ) + for x in range(9) + } +) async def to_code(config): ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) - if CONF_MOVING_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_MOVING_DISTANCE]) + if moving_distance_config := config.get(CONF_MOVING_DISTANCE): + sens = await sensor.new_sensor(moving_distance_config) cg.add(ld2410_component.set_moving_target_distance_sensor(sens)) - if CONF_STILL_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_STILL_DISTANCE]) + if still_distance_config := config.get(CONF_STILL_DISTANCE): + sens = await sensor.new_sensor(still_distance_config) cg.add(ld2410_component.set_still_target_distance_sensor(sens)) - if CONF_MOVING_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_MOVING_ENERGY]) + if moving_energy_config := config.get(CONF_MOVING_ENERGY): + sens = await sensor.new_sensor(moving_energy_config) cg.add(ld2410_component.set_moving_target_energy_sensor(sens)) - if CONF_STILL_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_STILL_ENERGY]) + if still_energy_config := config.get(CONF_STILL_ENERGY): + sens = await sensor.new_sensor(still_energy_config) cg.add(ld2410_component.set_still_target_energy_sensor(sens)) - if CONF_DETECTION_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_DETECTION_DISTANCE]) + if light_config := config.get(CONF_LIGHT): + sens = await sensor.new_sensor(light_config) + cg.add(ld2410_component.set_light_sensor(sens)) + if detection_distance_config := config.get(CONF_DETECTION_DISTANCE): + sens = await sensor.new_sensor(detection_distance_config) cg.add(ld2410_component.set_detection_distance_sensor(sens)) + for x in range(9): + if gate_conf := config.get(f"g{x}"): + if move_config := gate_conf.get(CONF_MOVE_ENERGY): + sens = await sensor.new_sensor(move_config) + cg.add(ld2410_component.set_gate_move_sensor(x, sens)) + if still_config := gate_conf.get(CONF_STILL_ENERGY): + sens = await sensor.new_sensor(still_config) + cg.add(ld2410_component.set_gate_still_sensor(x, sens)) diff --git a/esphome/components/ld2410/switch/__init__.py b/esphome/components/ld2410/switch/__init__.py new file mode 100644 index 0000000000..096cb5f67a --- /dev/null +++ b/esphome/components/ld2410/switch/__init__.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_SWITCH, + ICON_BLUETOOTH, + ENTITY_CATEGORY_CONFIG, + ICON_PULSE, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +BluetoothSwitch = ld2410_ns.class_("BluetoothSwitch", switch.Switch) +EngineeringModeSwitch = ld2410_ns.class_("EngineeringModeSwitch", switch.Switch) + +CONF_ENGINEERING_MODE = "engineering_mode" +CONF_BLUETOOTH = "bluetooth" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_ENGINEERING_MODE): switch.switch_schema( + EngineeringModeSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_PULSE, + ), + cv.Optional(CONF_BLUETOOTH): switch.switch_schema( + BluetoothSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_BLUETOOTH, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if engineering_mode_config := config.get(CONF_ENGINEERING_MODE): + s = await switch.new_switch(engineering_mode_config) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_engineering_mode_switch(s)) + if bluetooth_config := config.get(CONF_BLUETOOTH): + s = await switch.new_switch(bluetooth_config) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_bluetooth_switch(s)) diff --git a/esphome/components/ld2410/switch/bluetooth_switch.cpp b/esphome/components/ld2410/switch/bluetooth_switch.cpp new file mode 100644 index 0000000000..9bcee9b049 --- /dev/null +++ b/esphome/components/ld2410/switch/bluetooth_switch.cpp @@ -0,0 +1,12 @@ +#include "bluetooth_switch.h" + +namespace esphome { +namespace ld2410 { + +void BluetoothSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_bluetooth(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/bluetooth_switch.h b/esphome/components/ld2410/switch/bluetooth_switch.h new file mode 100644 index 0000000000..35ae1ec0c9 --- /dev/null +++ b/esphome/components/ld2410/switch/bluetooth_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class BluetoothSwitch : public switch_::Switch, public Parented { + public: + BluetoothSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/engineering_mode_switch.cpp b/esphome/components/ld2410/switch/engineering_mode_switch.cpp new file mode 100644 index 0000000000..967c87c887 --- /dev/null +++ b/esphome/components/ld2410/switch/engineering_mode_switch.cpp @@ -0,0 +1,12 @@ +#include "engineering_mode_switch.h" + +namespace esphome { +namespace ld2410 { + +void EngineeringModeSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_engineering_mode(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/engineering_mode_switch.h b/esphome/components/ld2410/switch/engineering_mode_switch.h new file mode 100644 index 0000000000..e521200cd6 --- /dev/null +++ b/esphome/components/ld2410/switch/engineering_mode_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class EngineeringModeSwitch : public switch_::Switch, public Parented { + public: + EngineeringModeSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/text_sensor.py b/esphome/components/ld2410/text_sensor.py new file mode 100644 index 0000000000..d64472a7d3 --- /dev/null +++ b/esphome/components/ld2410/text_sensor.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_DIAGNOSTIC, + CONF_VERSION, + CONF_MAC_ADDRESS, + ICON_BLUETOOTH, + ICON_CHIP, +) +from . import CONF_LD2410_ID, LD2410Component + +DEPENDENCIES = ["ld2410"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon=ICON_CHIP + ), + cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon=ICON_BLUETOOTH + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if version_config := config.get(CONF_VERSION): + sens = await text_sensor.new_text_sensor(version_config) + cg.add(ld2410_component.set_version_text_sensor(sens)) + if mac_address_config := config.get(CONF_MAC_ADDRESS): + sens = await text_sensor.new_text_sensor(mac_address_config) + cg.add(ld2410_component.set_mac_text_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 4eb78515c9..66caad961a 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -170,6 +170,9 @@ mqtt: id: uart_0 data: !lambda |- return {}; + - bluetooth_password.set: + id: my_ld2410 + password: abcdef on_connect: - light.turn_on: ${roomname}_lights - mqtt.publish: @@ -1333,16 +1336,64 @@ sensor: speed: name: "Radiator Pump Speed" - platform: ld2410 + light: + name: light moving_distance: name: "Moving distance (cm)" still_distance: name: "Still Distance (cm)" moving_energy: - name: "Move Energy" + name: "Move Energy (%)" still_energy: - name: "Still Energy" + name: "Still Energy (%)" detection_distance: - name: "Distance Detection" + name: "Distance Detection (cm)" + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + - platform: sen21231 name: "Person Sensor" i2c_id: i2c_bus @@ -1684,6 +1735,8 @@ binary_sensor: name: movement has_still_target: name: still + out_pin_presence_status: + name: out pin presence status pca9685: frequency: 500 @@ -2626,6 +2679,11 @@ switch: id: outlet_switch optimistic: true device_class: outlet + - platform: ld2410 + engineering_mode: + name: "control ld2410 engineering mode" + bluetooth: + name: "control ld2410 bluetooth" fan: - platform: binary @@ -3207,6 +3265,11 @@ text_sensor: tag_name: OPTARIF name: optarif teleinfo_id: myteleinfo + - platform: ld2410 + version: + name: "presenece sensor version" + mac_address: + name: "presenece sensor mac address" sn74hc595: - id: sn74hc595_hub @@ -3311,6 +3374,61 @@ number: step: 1 max_value: 10 optimistic: true + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + select: - platform: template @@ -3324,6 +3442,15 @@ select: - platform: copy source_id: test_select name: Test Select Copy + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level qr_code: - id: homepage_qr @@ -3386,19 +3513,17 @@ button: name: Midea Power Inverse on_press: midea_ac.power_toggle: + - platform: ld2410 + factory_reset: + name: "factory reset" + restart: + name: "restart" + query_params: + name: query params ld2410: id: my_ld2410 uart_id: ld2410_uart - timeout: 150s - max_move_distance: 6m - max_still_distance: 0.75m - g0_move_threshold: 10 - g0_still_threshold: 20 - g2_move_threshold: 20 - g2_still_threshold: 21 - g8_move_threshold: 80 - g8_still_threshold: 81 lcd_menu: display_id: my_lcd_gpio From 67b06a88b22bbd661f349e2fff442739d3606f90 Mon Sep 17 00:00:00 2001 From: MrEditor97 Date: Mon, 14 Aug 2023 20:14:08 +0100 Subject: [PATCH 0360/2607] Change XL9535 `setup_priority` to IO (#5246) --- esphome/components/xl9535/xl9535.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/xl9535/xl9535.h b/esphome/components/xl9535/xl9535.h index 8f0a868c42..dd67990fa8 100644 --- a/esphome/components/xl9535/xl9535.h +++ b/esphome/components/xl9535/xl9535.h @@ -26,7 +26,7 @@ class XL9535Component : public Component, public i2c::I2CDevice { void setup() override; void dump_config() override; - float get_setup_priority() const override { return setup_priority::DATA; } + float get_setup_priority() const override { return setup_priority::IO; } }; class XL9535GPIOPin : public GPIOPin { From afd26c6f1a57508d9936f4887641a59992be199a Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 14 Aug 2023 23:21:22 +0400 Subject: [PATCH 0361/2607] rmt_base additional minor changes (#5245) --- esphome/components/remote_base/__init__.py | 21 +++++-------------- .../components/remote_base/midea_protocol.h | 1 - 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 9e46506b3c..e2d96c9472 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1488,10 +1488,7 @@ MideaData, MideaBinarySensor, MideaTrigger, MideaAction, MideaDumper = declare_p MideaAction = ns.class_("MideaAction", RemoteTransmitterActionBase) MIDEA_SCHEMA = cv.Schema( { - cv.Required(CONF_CODE): cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=5, max=5), - ), + cv.Required(CONF_CODE): cv.All([cv.hex_uint8_t], cv.Length(min=5, max=5)), } ) @@ -1511,15 +1508,10 @@ def midea_dumper(var, config): pass -@register_action( - "midea", - MideaAction, - MIDEA_SCHEMA, -) +@register_action("midea", MideaAction, MIDEA_SCHEMA) async def midea_action(var, config, args): - template_ = await cg.templatable( - config[CONF_CODE], args, cg.std_vector.template(cg.uint8) - ) + vec_ = cg.std_vector.template(cg.uint8) + template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_) cg.add(var.set_code(template_)) @@ -1530,10 +1522,7 @@ AEHAData, AEHABinarySensor, AEHATrigger, AEHAAction, AEHADumper = declare_protoc AEHA_SCHEMA = cv.Schema( { cv.Required(CONF_ADDRESS): cv.hex_uint16_t, - cv.Required(CONF_DATA): cv.All( - [cv.Any(cv.hex_uint8_t, cv.uint8_t)], - cv.Length(min=2, max=35), - ), + cv.Required(CONF_DATA): cv.All([cv.hex_uint8_t], cv.Length(min=2, max=35)), } ) diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index f5db313579..6925686b34 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -84,7 +84,6 @@ using MideaDumper = RemoteReceiverDumper; template class MideaAction : public RemoteTransmitterActionBase { TEMPLATABLE_VALUE(std::vector, code) - void set_code(std::initializer_list code) { this->code_ = code; } void encode(RemoteTransmitData *dst, Ts... x) override { MideaData data(this->code_.value(x...)); From ff8a73c2d140ee1847c308fc6d0bd4f3f3109a62 Mon Sep 17 00:00:00 2001 From: mulder-fbi Date: Wed, 16 Aug 2023 00:52:56 +0200 Subject: [PATCH 0362/2607] Fix 24 bit signed integer parsing in sml parser (#5250) --- esphome/components/sml/sml_parser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index ff7da4cabd..91b320a30e 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -88,6 +88,11 @@ uint64_t bytes_to_uint(const bytes &buffer) { for (auto const value : buffer) { val = (val << 8) + value; } + // Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the + // 24 bit value is negative. + if (buffer.size() == 3 && buffer[0] & 0x80) { + val |= 0xFFFFFFFFFF000000; + } return val; } From 48e4cb5ae24145ca6da22f3206eb2dcb85ef71d0 Mon Sep 17 00:00:00 2001 From: Carson Full Date: Tue, 15 Aug 2023 18:13:43 -0500 Subject: [PATCH 0363/2607] Fix IDFI2CBus::writev ignoring stop parameter (#4840) Co-authored-by: Alexander Dimitrov --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index e2c7e7ddcb..5d35c1968b 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -202,11 +202,13 @@ ErrorCode IDFI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt, b return ERROR_UNKNOWN; } } - err = i2c_master_stop(cmd); - if (err != ESP_OK) { - ESP_LOGVV(TAG, "TX to %02X master stop failed: %s", address, esp_err_to_name(err)); - i2c_cmd_link_delete(cmd); - return ERROR_UNKNOWN; + if (stop) { + err = i2c_master_stop(cmd); + if (err != ESP_OK) { + ESP_LOGVV(TAG, "TX to %02X master stop failed: %s", address, esp_err_to_name(err)); + i2c_cmd_link_delete(cmd); + return ERROR_UNKNOWN; + } } err = i2c_master_cmd_begin(port_, cmd, 20 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); From 63fa922547fb904f61553dc226bdd949d62e4010 Mon Sep 17 00:00:00 2001 From: Regev Brody Date: Wed, 16 Aug 2023 02:31:18 +0300 Subject: [PATCH 0364/2607] Add configuration flow abilites to the ld2410 component (#4434) --- CODEOWNERS | 2 +- esphome/components/ld2410/__init__.py | 188 +++--- esphome/components/ld2410/automation.h | 22 + esphome/components/ld2410/binary_sensor.py | 45 +- esphome/components/ld2410/button/__init__.py | 57 ++ .../components/ld2410/button/query_button.cpp | 9 + .../components/ld2410/button/query_button.h | 18 + .../components/ld2410/button/reset_button.cpp | 9 + .../components/ld2410/button/reset_button.h | 18 + .../ld2410/button/restart_button.cpp | 9 + .../components/ld2410/button/restart_button.h | 18 + esphome/components/ld2410/ld2410.cpp | 557 +++++++++++++++--- esphome/components/ld2410/ld2410.h | 207 +++++-- esphome/components/ld2410/number/__init__.py | 128 ++++ .../ld2410/number/gate_threshold_number.cpp | 14 + .../ld2410/number/gate_threshold_number.h | 19 + .../ld2410/number/light_threshold_number.cpp | 12 + .../ld2410/number/light_threshold_number.h | 18 + .../number/max_distance_timeout_number.cpp | 12 + .../number/max_distance_timeout_number.h | 18 + esphome/components/ld2410/select/__init__.py | 81 +++ .../ld2410/select/baud_rate_select.cpp | 12 + .../ld2410/select/baud_rate_select.h | 18 + .../select/distance_resolution_select.cpp | 12 + .../select/distance_resolution_select.h | 18 + .../select/light_out_control_select.cpp | 12 + .../ld2410/select/light_out_control_select.h | 18 + esphome/components/ld2410/sensor.py | 111 +++- esphome/components/ld2410/switch/__init__.py | 44 ++ .../ld2410/switch/bluetooth_switch.cpp | 12 + .../ld2410/switch/bluetooth_switch.h | 18 + .../ld2410/switch/engineering_mode_switch.cpp | 12 + .../ld2410/switch/engineering_mode_switch.h | 18 + esphome/components/ld2410/text_sensor.py | 33 ++ tests/test1.yaml | 149 ++++- 35 files changed, 1621 insertions(+), 327 deletions(-) create mode 100644 esphome/components/ld2410/automation.h create mode 100644 esphome/components/ld2410/button/__init__.py create mode 100644 esphome/components/ld2410/button/query_button.cpp create mode 100644 esphome/components/ld2410/button/query_button.h create mode 100644 esphome/components/ld2410/button/reset_button.cpp create mode 100644 esphome/components/ld2410/button/reset_button.h create mode 100644 esphome/components/ld2410/button/restart_button.cpp create mode 100644 esphome/components/ld2410/button/restart_button.h create mode 100644 esphome/components/ld2410/number/__init__.py create mode 100644 esphome/components/ld2410/number/gate_threshold_number.cpp create mode 100644 esphome/components/ld2410/number/gate_threshold_number.h create mode 100644 esphome/components/ld2410/number/light_threshold_number.cpp create mode 100644 esphome/components/ld2410/number/light_threshold_number.h create mode 100644 esphome/components/ld2410/number/max_distance_timeout_number.cpp create mode 100644 esphome/components/ld2410/number/max_distance_timeout_number.h create mode 100644 esphome/components/ld2410/select/__init__.py create mode 100644 esphome/components/ld2410/select/baud_rate_select.cpp create mode 100644 esphome/components/ld2410/select/baud_rate_select.h create mode 100644 esphome/components/ld2410/select/distance_resolution_select.cpp create mode 100644 esphome/components/ld2410/select/distance_resolution_select.h create mode 100644 esphome/components/ld2410/select/light_out_control_select.cpp create mode 100644 esphome/components/ld2410/select/light_out_control_select.h create mode 100644 esphome/components/ld2410/switch/__init__.py create mode 100644 esphome/components/ld2410/switch/bluetooth_switch.cpp create mode 100644 esphome/components/ld2410/switch/bluetooth_switch.h create mode 100644 esphome/components/ld2410/switch/engineering_mode_switch.cpp create mode 100644 esphome/components/ld2410/switch/engineering_mode_switch.h create mode 100644 esphome/components/ld2410/text_sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 408caee4f2..b3ac833ee4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -144,7 +144,7 @@ esphome/components/key_collector/* @ssieb esphome/components/key_provider/* @ssieb esphome/components/kuntze/* @ssieb esphome/components/lcd_menu/* @numo68 -esphome/components/ld2410/* @sebcaps +esphome/components/ld2410/* @regevbr @sebcaps esphome/components/ledc/* @OttoWinter esphome/components/light/* @esphome/core esphome/components/lilygo_t5_47/touchscreen/* @jesserockz diff --git a/esphome/components/ld2410/__init__.py b/esphome/components/ld2410/__init__.py index 47c4cdb0bd..2b30b65f46 100644 --- a/esphome/components/ld2410/__init__.py +++ b/esphome/components/ld2410/__init__.py @@ -1,113 +1,64 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import uart -from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome.const import CONF_ID, CONF_THROTTLE, CONF_TIMEOUT, CONF_PASSWORD from esphome import automation from esphome.automation import maybe_simple_id DEPENDENCIES = ["uart"] -CODEOWNERS = ["@sebcaps"] +CODEOWNERS = ["@sebcaps", "@regevbr"] MULTI_CONF = True ld2410_ns = cg.esphome_ns.namespace("ld2410") LD2410Component = ld2410_ns.class_("LD2410Component", cg.Component, uart.UARTDevice) -LD2410Restart = ld2410_ns.class_("LD2410Restart", automation.Action) + CONF_LD2410_ID = "ld2410_id" + CONF_MAX_MOVE_DISTANCE = "max_move_distance" CONF_MAX_STILL_DISTANCE = "max_still_distance" -CONF_G0_MOVE_THRESHOLD = "g0_move_threshold" -CONF_G0_STILL_THRESHOLD = "g0_still_threshold" -CONF_G1_MOVE_THRESHOLD = "g1_move_threshold" -CONF_G1_STILL_THRESHOLD = "g1_still_threshold" -CONF_G2_MOVE_THRESHOLD = "g2_move_threshold" -CONF_G2_STILL_THRESHOLD = "g2_still_threshold" -CONF_G3_MOVE_THRESHOLD = "g3_move_threshold" -CONF_G3_STILL_THRESHOLD = "g3_still_threshold" -CONF_G4_MOVE_THRESHOLD = "g4_move_threshold" -CONF_G4_STILL_THRESHOLD = "g4_still_threshold" -CONF_G5_MOVE_THRESHOLD = "g5_move_threshold" -CONF_G5_STILL_THRESHOLD = "g5_still_threshold" -CONF_G6_MOVE_THRESHOLD = "g6_move_threshold" -CONF_G6_STILL_THRESHOLD = "g6_still_threshold" -CONF_G7_MOVE_THRESHOLD = "g7_move_threshold" -CONF_G7_STILL_THRESHOLD = "g7_still_threshold" -CONF_G8_MOVE_THRESHOLD = "g8_move_threshold" -CONF_G8_STILL_THRESHOLD = "g8_still_threshold" +CONF_STILL_THRESHOLDS = [f"g{x}_still_threshold" for x in range(9)] +CONF_MOVE_THRESHOLDS = [f"g{x}_move_threshold" for x in range(9)] -DISTANCES = [0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6] +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(LD2410Component), + cv.Optional(CONF_THROTTLE, default="1000ms"): cv.All( + cv.positive_time_period_milliseconds, + cv.Range(min=cv.TimePeriod(milliseconds=1)), + ), + cv.Optional(CONF_MAX_MOVE_DISTANCE): cv.invalid( + f"The '{CONF_MAX_MOVE_DISTANCE}' option has been moved to the '{CONF_MAX_MOVE_DISTANCE}'" + f" number component" + ), + cv.Optional(CONF_MAX_STILL_DISTANCE): cv.invalid( + f"The '{CONF_MAX_STILL_DISTANCE}' option has been moved to the '{CONF_MAX_STILL_DISTANCE}'" + f" number component" + ), + cv.Optional(CONF_TIMEOUT): cv.invalid( + f"The '{CONF_TIMEOUT}' option has been moved to the '{CONF_TIMEOUT}'" + f" number component" + ), + } +) + +for i in range(9): + CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + cv.Schema( + { + cv.Optional(CONF_MOVE_THRESHOLDS[i]): cv.invalid( + f"The '{CONF_MOVE_THRESHOLDS[i]}' option has been moved to the '{CONF_MOVE_THRESHOLDS[i]}'" + f" number component" + ), + cv.Optional(CONF_STILL_THRESHOLDS[i]): cv.invalid( + f"The '{CONF_STILL_THRESHOLDS[i]}' option has been moved to the '{CONF_STILL_THRESHOLDS[i]}'" + f" number component" + ), + } + ) + ) CONFIG_SCHEMA = cv.All( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(LD2410Component), - cv.Optional(CONF_MAX_MOVE_DISTANCE, default="4.5m"): cv.All( - cv.distance, cv.one_of(*DISTANCES, float=True) - ), - cv.Optional(CONF_MAX_STILL_DISTANCE, default="4.5m"): cv.All( - cv.distance, cv.one_of(*DISTANCES, float=True) - ), - cv.Optional(CONF_TIMEOUT, default="5s"): cv.All( - cv.positive_time_period_seconds, - cv.Range(max=cv.TimePeriod(seconds=32767)), - ), - cv.Optional(CONF_G0_MOVE_THRESHOLD, default=50): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G0_STILL_THRESHOLD, default=0): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G1_MOVE_THRESHOLD, default=50): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G1_STILL_THRESHOLD, default=0): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G2_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G2_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G3_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G3_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G4_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G4_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G5_MOVE_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G5_STILL_THRESHOLD, default=40): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G6_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G6_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G7_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G7_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G8_MOVE_THRESHOLD, default=30): cv.int_range( - min=0, max=100 - ), - cv.Optional(CONF_G8_STILL_THRESHOLD, default=15): cv.int_range( - min=0, max=100 - ), - } - ) - .extend(uart.UART_DEVICE_SCHEMA) - .extend(cv.COMPONENT_SCHEMA) + CONFIG_SCHEMA.extend(uart.UART_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) ) FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( @@ -123,31 +74,7 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) - cg.add(var.set_timeout(config[CONF_TIMEOUT])) - cg.add(var.set_max_move_distance(int(config[CONF_MAX_MOVE_DISTANCE] / 0.75))) - cg.add(var.set_max_still_distance(int(config[CONF_MAX_STILL_DISTANCE] / 0.75))) - cg.add( - var.set_range_config( - config[CONF_G0_MOVE_THRESHOLD], - config[CONF_G0_STILL_THRESHOLD], - config[CONF_G1_MOVE_THRESHOLD], - config[CONF_G1_STILL_THRESHOLD], - config[CONF_G2_MOVE_THRESHOLD], - config[CONF_G2_STILL_THRESHOLD], - config[CONF_G3_MOVE_THRESHOLD], - config[CONF_G3_STILL_THRESHOLD], - config[CONF_G4_MOVE_THRESHOLD], - config[CONF_G4_STILL_THRESHOLD], - config[CONF_G5_MOVE_THRESHOLD], - config[CONF_G5_STILL_THRESHOLD], - config[CONF_G6_MOVE_THRESHOLD], - config[CONF_G6_STILL_THRESHOLD], - config[CONF_G7_MOVE_THRESHOLD], - config[CONF_G7_STILL_THRESHOLD], - config[CONF_G8_MOVE_THRESHOLD], - config[CONF_G8_STILL_THRESHOLD], - ) - ) + cg.add(var.set_throttle(config[CONF_THROTTLE])) CALIBRATION_ACTION_SCHEMA = maybe_simple_id( @@ -155,3 +82,28 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id( cv.Required(CONF_ID): cv.use_id(LD2410Component), } ) + + +# Actions +BluetoothPasswordSetAction = ld2410_ns.class_( + "BluetoothPasswordSetAction", automation.Action +) + + +BLUETOOTH_PASSWORD_SET_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(LD2410Component), + cv.Required(CONF_PASSWORD): cv.templatable(cv.string_strict), + } +) + + +@automation.register_action( + "bluetooth_password.set", BluetoothPasswordSetAction, BLUETOOTH_PASSWORD_SET_SCHEMA +) +async def bluetooth_password_set_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable(config[CONF_PASSWORD], args, cg.std_string) + cg.add(var.set_password(template_)) + return var diff --git a/esphome/components/ld2410/automation.h b/esphome/components/ld2410/automation.h new file mode 100644 index 0000000000..7cb9855f84 --- /dev/null +++ b/esphome/components/ld2410/automation.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "ld2410.h" + +namespace esphome { +namespace ld2410 { + +template class BluetoothPasswordSetAction : public Action { + public: + explicit BluetoothPasswordSetAction(LD2410Component *ld2410_comp) : ld2410_comp_(ld2410_comp) {} + TEMPLATABLE_VALUE(std::string, password) + + void play(Ts... x) override { this->ld2410_comp_->set_bluetooth_password(this->password_.value(x...)); } + + protected: + LD2410Component *ld2410_comp_; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/binary_sensor.py b/esphome/components/ld2410/binary_sensor.py index 02f73d57b7..3057480d25 100644 --- a/esphome/components/ld2410/binary_sensor.py +++ b/esphome/components/ld2410/binary_sensor.py @@ -1,36 +1,55 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv -from esphome.const import DEVICE_CLASS_MOTION, DEVICE_CLASS_OCCUPANCY +from esphome.const import ( + DEVICE_CLASS_MOTION, + DEVICE_CLASS_OCCUPANCY, + DEVICE_CLASS_PRESENCE, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_MOTION_SENSOR, + ICON_ACCOUNT, +) from . import CONF_LD2410_ID, LD2410Component DEPENDENCIES = ["ld2410"] CONF_HAS_TARGET = "has_target" CONF_HAS_MOVING_TARGET = "has_moving_target" CONF_HAS_STILL_TARGET = "has_still_target" +CONF_OUT_PIN_PRESENCE_STATUS = "out_pin_presence_status" CONFIG_SCHEMA = { cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_OCCUPANCY + device_class=DEVICE_CLASS_OCCUPANCY, + icon=ICON_ACCOUNT, ), cv.Optional(CONF_HAS_MOVING_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_MOTION + device_class=DEVICE_CLASS_MOTION, + icon=ICON_MOTION_SENSOR, ), cv.Optional(CONF_HAS_STILL_TARGET): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_OCCUPANCY + device_class=DEVICE_CLASS_OCCUPANCY, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_OUT_PIN_PRESENCE_STATUS): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_PRESENCE, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_ACCOUNT, ), } async def to_code(config): ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) - if CONF_HAS_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_TARGET]) - cg.add(ld2410_component.set_target_sensor(sens)) - if CONF_HAS_MOVING_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_MOVING_TARGET]) - cg.add(ld2410_component.set_moving_target_sensor(sens)) - if CONF_HAS_STILL_TARGET in config: - sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_STILL_TARGET]) - cg.add(ld2410_component.set_still_target_sensor(sens)) + if has_target_config := config.get(CONF_HAS_TARGET): + sens = await binary_sensor.new_binary_sensor(has_target_config) + cg.add(ld2410_component.set_target_binary_sensor(sens)) + if has_moving_target_config := config.get(CONF_HAS_MOVING_TARGET): + sens = await binary_sensor.new_binary_sensor(has_moving_target_config) + cg.add(ld2410_component.set_moving_target_binary_sensor(sens)) + if has_still_target_config := config.get(CONF_HAS_STILL_TARGET): + sens = await binary_sensor.new_binary_sensor(has_still_target_config) + cg.add(ld2410_component.set_still_target_binary_sensor(sens)) + if out_pin_presence_status_config := config.get(CONF_OUT_PIN_PRESENCE_STATUS): + sens = await binary_sensor.new_binary_sensor(out_pin_presence_status_config) + cg.add(ld2410_component.set_out_pin_presence_status_binary_sensor(sens)) diff --git a/esphome/components/ld2410/button/__init__.py b/esphome/components/ld2410/button/__init__.py new file mode 100644 index 0000000000..3567114c2c --- /dev/null +++ b/esphome/components/ld2410/button/__init__.py @@ -0,0 +1,57 @@ +import esphome.codegen as cg +from esphome.components import button +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_RESTART, + ENTITY_CATEGORY_DIAGNOSTIC, + ENTITY_CATEGORY_CONFIG, + ICON_RESTART, + ICON_RESTART_ALERT, + ICON_DATABASE, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +QueryButton = ld2410_ns.class_("QueryButton", button.Button) +ResetButton = ld2410_ns.class_("ResetButton", button.Button) +RestartButton = ld2410_ns.class_("RestartButton", button.Button) + +CONF_FACTORY_RESET = "factory_reset" +CONF_RESTART = "restart" +CONF_QUERY_PARAMS = "query_params" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_FACTORY_RESET): button.button_schema( + ResetButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RESTART_ALERT, + ), + cv.Optional(CONF_RESTART): button.button_schema( + RestartButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_RESTART, + ), + cv.Optional(CONF_QUERY_PARAMS): button.button_schema( + QueryButton, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_DATABASE, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if factory_reset_config := config.get(CONF_FACTORY_RESET): + b = await button.new_button(factory_reset_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_reset_button(b)) + if restart_config := config.get(CONF_RESTART): + b = await button.new_button(restart_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_restart_button(b)) + if query_params_config := config.get(CONF_QUERY_PARAMS): + b = await button.new_button(query_params_config) + await cg.register_parented(b, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_query_button(b)) diff --git a/esphome/components/ld2410/button/query_button.cpp b/esphome/components/ld2410/button/query_button.cpp new file mode 100644 index 0000000000..47ab416f5a --- /dev/null +++ b/esphome/components/ld2410/button/query_button.cpp @@ -0,0 +1,9 @@ +#include "query_button.h" + +namespace esphome { +namespace ld2410 { + +void QueryButton::press_action() { this->parent_->read_all_info(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/query_button.h b/esphome/components/ld2410/button/query_button.h new file mode 100644 index 0000000000..c7a47e32d8 --- /dev/null +++ b/esphome/components/ld2410/button/query_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class QueryButton : public button::Button, public Parented { + public: + QueryButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/reset_button.cpp b/esphome/components/ld2410/button/reset_button.cpp new file mode 100644 index 0000000000..f16c5faa79 --- /dev/null +++ b/esphome/components/ld2410/button/reset_button.cpp @@ -0,0 +1,9 @@ +#include "reset_button.h" + +namespace esphome { +namespace ld2410 { + +void ResetButton::press_action() { this->parent_->factory_reset(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/reset_button.h b/esphome/components/ld2410/button/reset_button.h new file mode 100644 index 0000000000..78dd92c9f5 --- /dev/null +++ b/esphome/components/ld2410/button/reset_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class ResetButton : public button::Button, public Parented { + public: + ResetButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/restart_button.cpp b/esphome/components/ld2410/button/restart_button.cpp new file mode 100644 index 0000000000..de0d36c1ef --- /dev/null +++ b/esphome/components/ld2410/button/restart_button.cpp @@ -0,0 +1,9 @@ +#include "restart_button.h" + +namespace esphome { +namespace ld2410 { + +void RestartButton::press_action() { this->parent_->restart_and_read_all_info(); } + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/button/restart_button.h b/esphome/components/ld2410/button/restart_button.h new file mode 100644 index 0000000000..d00dc05a53 --- /dev/null +++ b/esphome/components/ld2410/button/restart_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class RestartButton : public button::Button, public Parented { + public: + RestartButton() = default; + + protected: + void press_action() override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index 8e67ba54d7..c3b57815d6 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -1,5 +1,13 @@ #include "ld2410.h" +#include +#ifdef USE_NUMBER +#include "esphome/components/number/number.h" +#endif +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + #define highbyte(val) (uint8_t)((val) >> 8) #define lowbyte(val) (uint8_t)((val) &0xff) @@ -8,48 +16,97 @@ namespace ld2410 { static const char *const TAG = "ld2410"; +LD2410Component::LD2410Component() {} + void LD2410Component::dump_config() { ESP_LOGCONFIG(TAG, "LD2410:"); #ifdef USE_BINARY_SENSOR - LOG_BINARY_SENSOR(" ", "HasTargetSensor", this->target_binary_sensor_); - LOG_BINARY_SENSOR(" ", "MovingSensor", this->moving_binary_sensor_); - LOG_BINARY_SENSOR(" ", "StillSensor", this->still_binary_sensor_); + LOG_BINARY_SENSOR(" ", "TargetBinarySensor", this->target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "MovingTargetBinarySensor", this->moving_target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "StillTargetBinarySensor", this->still_target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "OutPinPresenceStatusBinarySensor", this->out_pin_presence_status_binary_sensor_); +#endif +#ifdef USE_SWITCH + LOG_SWITCH(" ", "EngineeringModeSwitch", this->engineering_mode_switch_); + LOG_SWITCH(" ", "BluetoothSwitch", this->bluetooth_switch_); +#endif +#ifdef USE_BUTTON + LOG_BUTTON(" ", "ResetButton", this->reset_button_); + LOG_BUTTON(" ", "RestartButton", this->restart_button_); + LOG_BUTTON(" ", "QueryButton", this->query_button_); #endif #ifdef USE_SENSOR - LOG_SENSOR(" ", "Moving Distance", this->moving_target_distance_sensor_); - LOG_SENSOR(" ", "Still Distance", this->still_target_distance_sensor_); - LOG_SENSOR(" ", "Moving Energy", this->moving_target_energy_sensor_); - LOG_SENSOR(" ", "Still Energy", this->still_target_energy_sensor_); - LOG_SENSOR(" ", "Detection Distance", this->detection_distance_sensor_); + LOG_SENSOR(" ", "LightSensor", this->light_sensor_); + LOG_SENSOR(" ", "MovingTargetDistanceSensor", this->moving_target_distance_sensor_); + LOG_SENSOR(" ", "StillTargetDistanceSensor", this->still_target_distance_sensor_); + LOG_SENSOR(" ", "MovingTargetEnergySensor", this->moving_target_energy_sensor_); + LOG_SENSOR(" ", "StillTargetEnergySensor", this->still_target_energy_sensor_); + LOG_SENSOR(" ", "DetectionDistanceSensor", this->detection_distance_sensor_); + for (sensor::Sensor *s : this->gate_still_sensors_) { + LOG_SENSOR(" ", "NthGateStillSesnsor", s); + } + for (sensor::Sensor *s : this->gate_move_sensors_) { + LOG_SENSOR(" ", "NthGateMoveSesnsor", s); + } #endif - this->set_config_mode_(true); - this->get_version_(); - this->set_config_mode_(false); - ESP_LOGCONFIG(TAG, " Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], - this->version_[3], this->version_[4], this->version_[5]); +#ifdef USE_TEXT_SENSOR + LOG_TEXT_SENSOR(" ", "VersionTextSensor", this->version_text_sensor_); + LOG_TEXT_SENSOR(" ", "MacTextSensor", this->mac_text_sensor_); +#endif +#ifdef USE_SELECT + LOG_SELECT(" ", "LightFunctionSelect", this->light_function_select_); + LOG_SELECT(" ", "OutPinLevelSelect", this->out_pin_level_select_); + LOG_SELECT(" ", "DistanceResolutionSelect", this->distance_resolution_select_); + LOG_SELECT(" ", "BaudRateSelect", this->baud_rate_select_); +#endif +#ifdef USE_NUMBER + LOG_NUMBER(" ", "LightThresholdNumber", this->light_threshold_number_); + LOG_NUMBER(" ", "MaxStillDistanceGateNumber", this->max_still_distance_gate_number_); + LOG_NUMBER(" ", "MaxMoveDistanceGateNumber", this->max_move_distance_gate_number_); + LOG_NUMBER(" ", "TimeoutNumber", this->timeout_number_); + for (number::Number *n : this->gate_still_threshold_numbers_) { + LOG_NUMBER(" ", "Still Thresholds Number", n); + } + for (number::Number *n : this->gate_move_threshold_numbers_) { + LOG_NUMBER(" ", "Move Thresholds Number", n); + } +#endif + this->read_all_info(); + ESP_LOGCONFIG(TAG, " Throttle_ : %ums", this->throttle_); + ESP_LOGCONFIG(TAG, " MAC Address : %s", const_cast(this->mac_.c_str())); + ESP_LOGCONFIG(TAG, " Firmware Version : %s", const_cast(this->version_.c_str())); } void LD2410Component::setup() { ESP_LOGCONFIG(TAG, "Setting up LD2410..."); - this->set_config_mode_(true); - this->set_max_distances_timeout_(this->max_move_distance_, this->max_still_distance_, this->timeout_); - // Configure Gates sensitivity - this->set_gate_threshold_(0, this->rg0_move_threshold_, this->rg0_still_threshold_); - this->set_gate_threshold_(1, this->rg1_move_threshold_, this->rg1_still_threshold_); - this->set_gate_threshold_(2, this->rg2_move_threshold_, this->rg2_still_threshold_); - this->set_gate_threshold_(3, this->rg3_move_threshold_, this->rg3_still_threshold_); - this->set_gate_threshold_(4, this->rg4_move_threshold_, this->rg4_still_threshold_); - this->set_gate_threshold_(5, this->rg5_move_threshold_, this->rg5_still_threshold_); - this->set_gate_threshold_(6, this->rg6_move_threshold_, this->rg6_still_threshold_); - this->set_gate_threshold_(7, this->rg7_move_threshold_, this->rg7_still_threshold_); - this->set_gate_threshold_(8, this->rg8_move_threshold_, this->rg8_still_threshold_); - this->get_version_(); - this->set_config_mode_(false); - ESP_LOGCONFIG(TAG, "Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], - this->version_[3], this->version_[4], this->version_[5]); + this->read_all_info(); + ESP_LOGCONFIG(TAG, "Mac Address : %s", const_cast(this->mac_.c_str())); + ESP_LOGCONFIG(TAG, "Firmware Version : %s", const_cast(this->version_.c_str())); ESP_LOGCONFIG(TAG, "LD2410 setup complete."); } +void LD2410Component::read_all_info() { + this->set_config_mode_(true); + this->get_version_(); + this->get_mac_(); + this->get_distance_resolution_(); + this->get_light_control_(); + this->query_parameters_(); + this->set_config_mode_(false); +#ifdef USE_SELECT + const auto baud_rate = std::to_string(this->parent_->get_baud_rate()); + if (this->baud_rate_select_ != nullptr && this->baud_rate_select_->state != baud_rate) { + this->baud_rate_select_->publish_state(baud_rate); + } +#endif +} + +void LD2410Component::restart_and_read_all_info() { + this->set_config_mode_(true); + this->restart_(); + this->set_timeout(1000, [this]() { this->read_all_info(); }); +} + void LD2410Component::loop() { const int max_line_length = 80; static uint8_t buffer[max_line_length]; @@ -59,9 +116,8 @@ void LD2410Component::loop() { } } -void LD2410Component::send_command_(uint8_t command, uint8_t *command_value, int command_value_len) { - // lastCommandSuccess->publish_state(false); - +void LD2410Component::send_command_(uint8_t command, const uint8_t *command_value, int command_value_len) { + ESP_LOGV(TAG, "Sending COMMAND %02X", command); // frame start bytes this->write_array(CMD_FRAME_HEADER, 4); // length bytes @@ -95,40 +151,43 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { if (buffer[7] != HEAD || buffer[len - 6] != END || buffer[len - 5] != CHECK) // Check constant values return; // data head=0xAA, data end=0x55, crc=0x00 - /* - Data Type: 6th - 0x01: Engineering mode - 0x02: Normal mode - */ - // char data_type = buffer[DATA_TYPES]; - /* - Target states: 9th - 0x00 = No target - 0x01 = Moving targets - 0x02 = Still targets - 0x03 = Moving+Still targets - */ -#ifdef USE_BINARY_SENSOR - char target_state = buffer[TARGET_STATES]; - if (this->target_binary_sensor_ != nullptr) { - this->target_binary_sensor_->publish_state(target_state != 0x00); - } -#endif - /* Reduce data update rate to prevent home assistant database size grow fast */ int32_t current_millis = millis(); - if (current_millis - last_periodic_millis < 1000) + if (current_millis - last_periodic_millis_ < this->throttle_) return; - last_periodic_millis = current_millis; + last_periodic_millis_ = current_millis; -#ifdef USE_BINARY_SENSOR - if (this->moving_binary_sensor_ != nullptr) { - this->moving_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + /* + Data Type: 7th + 0x01: Engineering mode + 0x02: Normal mode + */ + bool engineering_mode = buffer[DATA_TYPES] == 0x01; +#ifdef USE_SWITCH + if (this->engineering_mode_switch_ != nullptr && + current_millis - last_engineering_mode_change_millis_ > this->throttle_) { + this->engineering_mode_switch_->publish_state(engineering_mode); } - if (this->still_binary_sensor_ != nullptr) { - this->still_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); +#endif +#ifdef USE_BINARY_SENSOR + /* + Target states: 9th + 0x00 = No target + 0x01 = Moving targets + 0x02 = Still targets + 0x03 = Moving+Still targets + */ + char target_state = buffer[TARGET_STATES]; + if (this->target_binary_sensor_ != nullptr) { + this->target_binary_sensor_->publish_state(target_state != 0x00); + } + if (this->moving_target_binary_sensor_ != nullptr) { + this->moving_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + } + if (this->still_target_binary_sensor_ != nullptr) { + this->still_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); } #endif /* @@ -164,26 +223,126 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { if (this->detection_distance_sensor_->get_state() != new_detect_distance) this->detection_distance_sensor_->publish_state(new_detect_distance); } + if (engineering_mode) { + /* + Moving distance range: 18th byte + Still distance range: 19th byte + Moving enery: 20~28th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_move_sensors_.size(); i++) { + sensor::Sensor *s = this->gate_move_sensors_[i]; + if (s != nullptr) { + s->publish_state(buffer[MOVING_SENSOR_START + i]); + } + } + /* + Still energy: 29~37th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_still_sensors_.size(); i++) { + sensor::Sensor *s = this->gate_still_sensors_[i]; + if (s != nullptr) { + s->publish_state(buffer[STILL_SENSOR_START + i]); + } + } + /* + Light sensor: 38th bytes + */ + if (this->light_sensor_ != nullptr) { + int new_light_sensor = buffer[LIGHT_SENSOR]; + if (this->light_sensor_->get_state() != new_light_sensor) + this->light_sensor_->publish_state(new_light_sensor); + } + } else { + for (auto *s : this->gate_move_sensors_) { + if (s != nullptr && !std::isnan(s->get_state())) { + s->publish_state(NAN); + } + } + for (auto *s : this->gate_still_sensors_) { + if (s != nullptr && !std::isnan(s->get_state())) { + s->publish_state(NAN); + } + } + if (this->light_sensor_ != nullptr && !std::isnan(this->light_sensor_->get_state())) { + this->light_sensor_->publish_state(NAN); + } + } +#endif +#ifdef USE_BINARY_SENSOR + if (engineering_mode) { + if (this->out_pin_presence_status_binary_sensor_ != nullptr) { + this->out_pin_presence_status_binary_sensor_->publish_state(buffer[OUT_PIN_SENSOR] == 0x01); + } + } else { + if (this->out_pin_presence_status_binary_sensor_ != nullptr) { + this->out_pin_presence_status_binary_sensor_->publish_state(false); + } + } #endif } -void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { - ESP_LOGV(TAG, "Handling ACK DATA for COMMAND"); +const char VERSION_FMT[] = "%u.%02X.%02X%02X%02X%02X"; + +std::string format_version(uint8_t *buffer) { + std::string::size_type version_size = 256; + std::string version; + do { + version.resize(version_size + 1); + version_size = std::snprintf(&version[0], version.size(), VERSION_FMT, buffer[13], buffer[12], buffer[17], + buffer[16], buffer[15], buffer[14]); + } while (version_size + 1 > version.size()); + version.resize(version_size); + return version; +} + +const char MAC_FMT[] = "%02X:%02X:%02X:%02X:%02X:%02X"; + +const std::string UNKNOWN_MAC("unknown"); +const std::string NO_MAC("08:05:04:03:02:01"); + +std::string format_mac(uint8_t *buffer) { + std::string::size_type mac_size = 256; + std::string mac; + do { + mac.resize(mac_size + 1); + mac_size = std::snprintf(&mac[0], mac.size(), MAC_FMT, buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], + buffer[15]); + } while (mac_size + 1 > mac.size()); + mac.resize(mac_size); + if (mac == NO_MAC) { + return UNKNOWN_MAC; + } + return mac; +} + +#ifdef USE_NUMBER +std::function set_number_value(number::Number *n, float value) { + float normalized_value = value * 1.0; + if (n != nullptr && (!n->has_state() || n->state != normalized_value)) { + n->state = normalized_value; + return [n, normalized_value]() { n->publish_state(normalized_value); }; + } + return []() {}; +} +#endif + +bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { + ESP_LOGV(TAG, "Handling ACK DATA for COMMAND %02X", buffer[COMMAND]); if (len < 10) { ESP_LOGE(TAG, "Error with last command : incorrect length"); - return; + return true; } if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // check 4 frame start bytes ESP_LOGE(TAG, "Error with last command : incorrect Header"); - return; + return true; } if (buffer[COMMAND_STATUS] != 0x01) { ESP_LOGE(TAG, "Error with last command : status != 0x01"); - return; + return true; } if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) { ESP_LOGE(TAG, "Error with last command , last buffer was: %u , %u", buffer[8], buffer[9]); - return; + return true; } switch (buffer[COMMAND]) { @@ -193,49 +352,127 @@ void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { case lowbyte(CMD_DISABLE_CONF): ESP_LOGV(TAG, "Handled Disabled conf command"); break; + case lowbyte(CMD_SET_BAUD_RATE): + ESP_LOGV(TAG, "Handled baud rate change command"); +#ifdef USE_SELECT + if (this->baud_rate_select_ != nullptr) { + ESP_LOGE(TAG, "Change baud rate component config to %s and reinstall", this->baud_rate_select_->state.c_str()); + } +#endif + break; case lowbyte(CMD_VERSION): - ESP_LOGV(TAG, "FW Version is: %u.%u.%u%u%u%u", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15], - buffer[14]); - this->version_[0] = buffer[13]; - this->version_[1] = buffer[12]; - this->version_[2] = buffer[17]; - this->version_[3] = buffer[16]; - this->version_[4] = buffer[15]; - this->version_[5] = buffer[14]; - + this->version_ = format_version(buffer); + ESP_LOGV(TAG, "FW Version is: %s", const_cast(this->version_.c_str())); +#ifdef USE_TEXT_SENSOR + if (this->version_text_sensor_ != nullptr) { + this->version_text_sensor_->publish_state(this->version_); + } +#endif + break; + case lowbyte(CMD_QUERY_DISTANCE_RESOLUTION): { + std::string distance_resolution = + DISTANCE_RESOLUTION_INT_TO_ENUM.at(this->two_byte_to_int_(buffer[10], buffer[11])); + ESP_LOGV(TAG, "Distance resolution is: %s", const_cast(distance_resolution.c_str())); +#ifdef USE_SELECT + if (this->distance_resolution_select_ != nullptr && + this->distance_resolution_select_->state != distance_resolution) { + this->distance_resolution_select_->publish_state(distance_resolution); + } +#endif + } break; + case lowbyte(CMD_QUERY_LIGHT_CONTROL): { + this->light_function_ = LIGHT_FUNCTION_INT_TO_ENUM.at(buffer[10]); + this->light_threshold_ = buffer[11] * 1.0; + this->out_pin_level_ = OUT_PIN_LEVEL_INT_TO_ENUM.at(buffer[12]); + ESP_LOGV(TAG, "Light function is: %s", const_cast(this->light_function_.c_str())); + ESP_LOGV(TAG, "Light threshold is: %f", this->light_threshold_); + ESP_LOGV(TAG, "Out pin level is: %s", const_cast(this->out_pin_level_.c_str())); +#ifdef USE_SELECT + if (this->light_function_select_ != nullptr && this->light_function_select_->state != this->light_function_) { + this->light_function_select_->publish_state(this->light_function_); + } + if (this->out_pin_level_select_ != nullptr && this->out_pin_level_select_->state != this->out_pin_level_) { + this->out_pin_level_select_->publish_state(this->out_pin_level_); + } +#endif +#ifdef USE_NUMBER + if (this->light_threshold_number_ != nullptr && + (!this->light_threshold_number_->has_state() || + this->light_threshold_number_->state != this->light_threshold_)) { + this->light_threshold_number_->publish_state(this->light_threshold_); + } +#endif + } break; + case lowbyte(CMD_MAC): + if (len < 20) { + return false; + } + this->mac_ = format_mac(buffer); + ESP_LOGV(TAG, "MAC Address is: %s", const_cast(this->mac_.c_str())); +#ifdef USE_TEXT_SENSOR + if (this->mac_text_sensor_ != nullptr) { + this->mac_text_sensor_->publish_state(this->mac_); + } +#endif +#ifdef USE_SWITCH + if (this->bluetooth_switch_ != nullptr) { + this->bluetooth_switch_->publish_state(this->mac_ != UNKNOWN_MAC); + } +#endif break; case lowbyte(CMD_GATE_SENS): ESP_LOGV(TAG, "Handled sensitivity command"); break; + case lowbyte(CMD_BLUETOOTH): + ESP_LOGV(TAG, "Handled bluetooth command"); + break; + case lowbyte(CMD_SET_DISTANCE_RESOLUTION): + ESP_LOGV(TAG, "Handled set distance resolution command"); + break; + case lowbyte(CMD_SET_LIGHT_CONTROL): + ESP_LOGV(TAG, "Handled set light control command"); + break; + case lowbyte(CMD_BT_PASSWORD): + ESP_LOGV(TAG, "Handled set bluetooth password command"); + break; case lowbyte(CMD_QUERY): // Query parameters response { if (buffer[10] != 0xAA) - return; // value head=0xAA + return true; // value head=0xAA +#ifdef USE_NUMBER /* Moving distance range: 13th byte Still distance range: 14th byte */ - // TODO - // maxMovingDistanceRange->publish_state(buffer[12]); - // maxStillDistanceRange->publish_state(buffer[13]); + std::vector> updates; + updates.push_back(set_number_value(this->max_move_distance_gate_number_, buffer[12])); + updates.push_back(set_number_value(this->max_still_distance_gate_number_, buffer[13])); /* Moving Sensitivities: 15~23th bytes + */ + for (std::vector::size_type i = 0; i != this->gate_move_threshold_numbers_.size(); i++) { + updates.push_back(set_number_value(this->gate_move_threshold_numbers_[i], buffer[14 + i])); + } + /* Still Sensitivities: 24~32th bytes */ - for (int i = 0; i < 9; i++) { - moving_sensitivities[i] = buffer[14 + i]; - } - for (int i = 0; i < 9; i++) { - still_sensitivities[i] = buffer[23 + i]; + for (std::vector::size_type i = 0; i != this->gate_still_threshold_numbers_.size(); i++) { + updates.push_back(set_number_value(this->gate_still_threshold_numbers_[i], buffer[23 + i])); } /* None Duration: 33~34th bytes */ - // noneDuration->publish_state(this->two_byte_to_int_(buffer[32], buffer[33])); + updates.push_back(set_number_value(this->timeout_number_, this->two_byte_to_int_(buffer[32], buffer[33]))); + for (auto &update : updates) { + update(); + } +#endif } break; default: break; } + + return true; } void LD2410Component::readline_(int readch, uint8_t *buffer, int len) { @@ -256,8 +493,11 @@ void LD2410Component::readline_(int readch, uint8_t *buffer, int len) { } else if (buffer[pos - 4] == 0x04 && buffer[pos - 3] == 0x03 && buffer[pos - 2] == 0x02 && buffer[pos - 1] == 0x01) { ESP_LOGV(TAG, "Will handle ACK Data"); - this->handle_ack_data_(buffer, pos); - pos = 0; // Reset position index ready for next time + if (this->handle_ack_data_(buffer, pos)) { + pos = 0; // Reset position index ready for next time + } else { + ESP_LOGV(TAG, "ACK Data incomplete"); + } } } } @@ -269,21 +509,85 @@ void LD2410Component::set_config_mode_(bool enable) { this->send_command_(cmd, enable ? cmd_value : nullptr, 2); } +void LD2410Component::set_bluetooth(bool enable) { + this->set_config_mode_(true); + uint8_t enable_cmd_value[2] = {0x01, 0x00}; + uint8_t disable_cmd_value[2] = {0x00, 0x00}; + this->send_command_(CMD_BLUETOOTH, enable ? enable_cmd_value : disable_cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::set_distance_resolution(const std::string &state) { + this->set_config_mode_(true); + uint8_t cmd_value[2] = {DISTANCE_RESOLUTION_ENUM_TO_INT.at(state), 0x00}; + this->send_command_(CMD_SET_DISTANCE_RESOLUTION, cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::set_baud_rate(const std::string &state) { + this->set_config_mode_(true); + uint8_t cmd_value[2] = {BAUD_RATE_ENUM_TO_INT.at(state), 0x00}; + this->send_command_(CMD_SET_BAUD_RATE, cmd_value, 2); + this->set_timeout(200, [this]() { this->restart_(); }); +} + +void LD2410Component::set_bluetooth_password(const std::string &password) { + if (password.length() != 6) { + ESP_LOGE(TAG, "set_bluetooth_password(): invalid password length, must be exactly 6 chars '%s'", password.c_str()); + return; + } + this->set_config_mode_(true); + uint8_t cmd_value[6]; + std::copy(password.begin(), password.end(), std::begin(cmd_value)); + this->send_command_(CMD_BT_PASSWORD, cmd_value, 6); + this->set_config_mode_(false); +} + +void LD2410Component::set_engineering_mode(bool enable) { + this->set_config_mode_(true); + last_engineering_mode_change_millis_ = millis(); + uint8_t cmd = enable ? CMD_ENABLE_ENG : CMD_DISABLE_ENG; + this->send_command_(cmd, nullptr, 0); + this->set_config_mode_(false); +} + +void LD2410Component::factory_reset() { + this->set_config_mode_(true); + this->send_command_(CMD_RESET, nullptr, 0); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); +} + +void LD2410Component::restart_() { this->send_command_(CMD_RESTART, nullptr, 0); } + void LD2410Component::query_parameters_() { this->send_command_(CMD_QUERY, nullptr, 0); } void LD2410Component::get_version_() { this->send_command_(CMD_VERSION, nullptr, 0); } +void LD2410Component::get_mac_() { + uint8_t cmd_value[2] = {0x01, 0x00}; + this->send_command_(CMD_MAC, cmd_value, 2); +} +void LD2410Component::get_distance_resolution_() { this->send_command_(CMD_QUERY_DISTANCE_RESOLUTION, nullptr, 0); } -void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, - uint16_t timeout) { +void LD2410Component::get_light_control_() { this->send_command_(CMD_QUERY_LIGHT_CONTROL, nullptr, 0); } + +#ifdef USE_NUMBER +void LD2410Component::set_max_distances_timeout() { + if (!this->max_move_distance_gate_number_->has_state() || !this->max_still_distance_gate_number_->has_state() || + !this->timeout_number_->has_state()) { + return; + } + int max_moving_distance_gate_range = static_cast(this->max_move_distance_gate_number_->state); + int max_still_distance_gate_range = static_cast(this->max_still_distance_gate_number_->state); + int timeout = static_cast(this->timeout_number_->state); uint8_t value[18] = {0x00, 0x00, - lowbyte(max_moving_distance_range), - highbyte(max_moving_distance_range), + lowbyte(max_moving_distance_gate_range), + highbyte(max_moving_distance_gate_range), 0x00, 0x00, 0x01, 0x00, - lowbyte(max_still_distance_range), - highbyte(max_still_distance_range), + lowbyte(max_still_distance_gate_range), + highbyte(max_still_distance_gate_range), 0x00, 0x00, 0x02, @@ -292,10 +596,25 @@ void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_ran highbyte(timeout), 0x00, 0x00}; + this->set_config_mode_(true); this->send_command_(CMD_MAXDIST_DURATION, value, 18); + delay(50); // NOLINT this->query_parameters_(); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); + this->set_config_mode_(false); } -void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens) { + +void LD2410Component::set_gate_threshold(uint8_t gate) { + number::Number *motionsens = this->gate_move_threshold_numbers_[gate]; + number::Number *stillsens = this->gate_still_threshold_numbers_[gate]; + + if (!motionsens->has_state() || !stillsens->has_state()) { + return; + } + int motion = static_cast(motionsens->state); + int still = static_cast(stillsens->state); + + this->set_config_mode_(true); // reference // https://drive.google.com/drive/folders/1p4dhbEJA3YubyIjIIC7wwVsSo8x29Fq-?spm=a2g0o.detail.1000023.17.93465697yFwVxH // Send data: configure the motion sensitivity of distance gate 3 to 40, and the static sensitivity of 40 @@ -305,11 +624,57 @@ void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint // 28 00 00 00 (value) // 02 00 (still sensitivtiy) // 28 00 00 00 (value) - uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00, - 0x01, 0x00, lowbyte(motionsens), highbyte(motionsens), 0x00, 0x00, - 0x02, 0x00, lowbyte(stillsens), highbyte(stillsens), 0x00, 0x00}; + uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00, + 0x01, 0x00, lowbyte(motion), highbyte(motion), 0x00, 0x00, + 0x02, 0x00, lowbyte(still), highbyte(still), 0x00, 0x00}; this->send_command_(CMD_GATE_SENS, value, 18); + delay(50); // NOLINT + this->query_parameters_(); + this->set_config_mode_(false); } +void LD2410Component::set_gate_still_threshold_number(int gate, number::Number *n) { + this->gate_still_threshold_numbers_[gate] = n; +} + +void LD2410Component::set_gate_move_threshold_number(int gate, number::Number *n) { + this->gate_move_threshold_numbers_[gate] = n; +} +#endif + +void LD2410Component::set_light_out_control() { +#ifdef USE_NUMBER + if (this->light_threshold_number_ != nullptr && this->light_threshold_number_->has_state()) { + this->light_threshold_ = this->light_threshold_number_->state; + } +#endif +#ifdef USE_SELECT + if (this->light_function_select_ != nullptr && this->light_function_select_->has_state()) { + this->light_function_ = this->light_function_select_->state; + } + if (this->out_pin_level_select_ != nullptr && this->out_pin_level_select_->has_state()) { + this->out_pin_level_ = this->out_pin_level_select_->state; + } +#endif + if (this->light_function_.empty() || this->out_pin_level_.empty() || this->light_threshold_ < 0) { + return; + } + this->set_config_mode_(true); + uint8_t light_function = LIGHT_FUNCTION_ENUM_TO_INT.at(this->light_function_); + uint8_t light_threshold = static_cast(this->light_threshold_); + uint8_t out_pin_level = OUT_PIN_LEVEL_ENUM_TO_INT.at(this->out_pin_level_); + uint8_t value[4] = {light_function, light_threshold, out_pin_level, 0x00}; + this->send_command_(CMD_SET_LIGHT_CONTROL, value, 4); + delay(50); // NOLINT + this->get_light_control_(); + this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); + this->set_config_mode_(false); +} + +#ifdef USE_SENSOR +void LD2410Component::set_gate_move_sensor(int gate, sensor::Sensor *s) { this->gate_move_sensors_[gate] = s; } +void LD2410Component::set_gate_still_sensor(int gate, sensor::Sensor *s) { this->gate_still_sensors_[gate] = s; } +#endif + } // namespace ld2410 } // namespace esphome diff --git a/esphome/components/ld2410/ld2410.h b/esphome/components/ld2410/ld2410.h index 8edb83a8d5..8084d4c33e 100644 --- a/esphome/components/ld2410/ld2410.h +++ b/esphome/components/ld2410/ld2410.h @@ -7,10 +7,27 @@ #ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" #endif +#ifdef USE_NUMBER +#include "esphome/components/number/number.h" +#endif +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif +#ifdef USE_BUTTON +#include "esphome/components/button/button.h" +#endif +#ifdef USE_SELECT +#include "esphome/components/select/select.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif #include "esphome/components/uart/uart.h" #include "esphome/core/automation.h" #include "esphome/core/helpers.h" +#include + namespace esphome { namespace ld2410 { @@ -19,10 +36,63 @@ namespace ld2410 { // Commands static const uint8_t CMD_ENABLE_CONF = 0x00FF; static const uint8_t CMD_DISABLE_CONF = 0x00FE; +static const uint8_t CMD_ENABLE_ENG = 0x0062; +static const uint8_t CMD_DISABLE_ENG = 0x0063; static const uint8_t CMD_MAXDIST_DURATION = 0x0060; static const uint8_t CMD_QUERY = 0x0061; static const uint8_t CMD_GATE_SENS = 0x0064; static const uint8_t CMD_VERSION = 0x00A0; +static const uint8_t CMD_QUERY_DISTANCE_RESOLUTION = 0x00AB; +static const uint8_t CMD_SET_DISTANCE_RESOLUTION = 0x00AA; +static const uint8_t CMD_QUERY_LIGHT_CONTROL = 0x00AE; +static const uint8_t CMD_SET_LIGHT_CONTROL = 0x00AD; +static const uint8_t CMD_SET_BAUD_RATE = 0x00A1; +static const uint8_t CMD_BT_PASSWORD = 0x00A9; +static const uint8_t CMD_MAC = 0x00A5; +static const uint8_t CMD_RESET = 0x00A2; +static const uint8_t CMD_RESTART = 0x00A3; +static const uint8_t CMD_BLUETOOTH = 0x00A4; + +enum BaudRateStructure : uint8_t { + BAUD_RATE_9600 = 1, + BAUD_RATE_19200 = 2, + BAUD_RATE_38400 = 3, + BAUD_RATE_57600 = 4, + BAUD_RATE_115200 = 5, + BAUD_RATE_230400 = 6, + BAUD_RATE_256000 = 7, + BAUD_RATE_460800 = 8 +}; + +static const std::map BAUD_RATE_ENUM_TO_INT{ + {"9600", BAUD_RATE_9600}, {"19200", BAUD_RATE_19200}, {"38400", BAUD_RATE_38400}, + {"57600", BAUD_RATE_57600}, {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, + {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}}; + +enum DistanceResolutionStructure : uint8_t { DISTANCE_RESOLUTION_0_2 = 0x01, DISTANCE_RESOLUTION_0_75 = 0x00 }; + +static const std::map DISTANCE_RESOLUTION_ENUM_TO_INT{{"0.2m", DISTANCE_RESOLUTION_0_2}, + {"0.75m", DISTANCE_RESOLUTION_0_75}}; +static const std::map DISTANCE_RESOLUTION_INT_TO_ENUM{{DISTANCE_RESOLUTION_0_2, "0.2m"}, + {DISTANCE_RESOLUTION_0_75, "0.75m"}}; + +enum LightFunctionStructure : uint8_t { + LIGHT_FUNCTION_OFF = 0x00, + LIGHT_FUNCTION_BELOW = 0x01, + LIGHT_FUNCTION_ABOVE = 0x02 +}; + +static const std::map LIGHT_FUNCTION_ENUM_TO_INT{ + {"off", LIGHT_FUNCTION_OFF}, {"below", LIGHT_FUNCTION_BELOW}, {"above", LIGHT_FUNCTION_ABOVE}}; +static const std::map LIGHT_FUNCTION_INT_TO_ENUM{ + {LIGHT_FUNCTION_OFF, "off"}, {LIGHT_FUNCTION_BELOW, "below"}, {LIGHT_FUNCTION_ABOVE, "above"}}; + +enum OutPinLevelStructure : uint8_t { OUT_PIN_LEVEL_LOW = 0x00, OUT_PIN_LEVEL_HIGH = 0x01 }; + +static const std::map OUT_PIN_LEVEL_ENUM_TO_INT{{"low", OUT_PIN_LEVEL_LOW}, + {"high", OUT_PIN_LEVEL_HIGH}}; +static const std::map OUT_PIN_LEVEL_INT_TO_ENUM{{OUT_PIN_LEVEL_LOW, "low"}, + {OUT_PIN_LEVEL_HIGH, "high"}}; // Commands values static const uint8_t CMD_MAX_MOVE_VALUE = 0x0000; @@ -44,7 +114,7 @@ Target states: 9th byte Detect distance: 16~17th bytes */ enum PeriodicDataStructure : uint8_t { - DATA_TYPES = 5, + DATA_TYPES = 6, TARGET_STATES = 8, MOVING_TARGET_LOW = 9, MOVING_TARGET_HIGH = 10, @@ -54,6 +124,10 @@ enum PeriodicDataStructure : uint8_t { STILL_ENERGY = 14, DETECT_DISTANCE_LOW = 15, DETECT_DISTANCE_HIGH = 16, + MOVING_SENSOR_START = 19, + STILL_SENSOR_START = 28, + LIGHT_SENSOR = 37, + OUT_PIN_SENSOR = 38, }; enum PeriodicDataValue : uint8_t { HEAD = 0XAA, END = 0x55, CHECK = 0x00 }; @@ -66,80 +140,97 @@ class LD2410Component : public Component, public uart::UARTDevice { SUB_SENSOR(still_target_distance) SUB_SENSOR(moving_target_energy) SUB_SENSOR(still_target_energy) + SUB_SENSOR(light) SUB_SENSOR(detection_distance) #endif +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(target) + SUB_BINARY_SENSOR(moving_target) + SUB_BINARY_SENSOR(still_target) + SUB_BINARY_SENSOR(out_pin_presence_status) +#endif +#ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(version) + SUB_TEXT_SENSOR(mac) +#endif +#ifdef USE_SELECT + SUB_SELECT(distance_resolution) + SUB_SELECT(baud_rate) + SUB_SELECT(light_function) + SUB_SELECT(out_pin_level) +#endif +#ifdef USE_SWITCH + SUB_SWITCH(engineering_mode) + SUB_SWITCH(bluetooth) +#endif +#ifdef USE_BUTTON + SUB_BUTTON(reset) + SUB_BUTTON(restart) + SUB_BUTTON(query) +#endif +#ifdef USE_NUMBER + SUB_NUMBER(max_still_distance_gate) + SUB_NUMBER(max_move_distance_gate) + SUB_NUMBER(timeout) + SUB_NUMBER(light_threshold) +#endif public: + LD2410Component(); void setup() override; void dump_config() override; void loop() override; - -#ifdef USE_BINARY_SENSOR - void set_target_sensor(binary_sensor::BinarySensor *sens) { this->target_binary_sensor_ = sens; }; - void set_moving_target_sensor(binary_sensor::BinarySensor *sens) { this->moving_binary_sensor_ = sens; }; - void set_still_target_sensor(binary_sensor::BinarySensor *sens) { this->still_binary_sensor_ = sens; }; + void set_light_out_control(); +#ifdef USE_NUMBER + void set_gate_still_threshold_number(int gate, number::Number *n); + void set_gate_move_threshold_number(int gate, number::Number *n); + void set_max_distances_timeout(); + void set_gate_threshold(uint8_t gate); #endif - - void set_timeout(uint16_t value) { this->timeout_ = value; }; - void set_max_move_distance(uint8_t value) { this->max_move_distance_ = value; }; - void set_max_still_distance(uint8_t value) { this->max_still_distance_ = value; }; - void set_range_config(int rg0_move, int rg0_still, int rg1_move, int rg1_still, int rg2_move, int rg2_still, - int rg3_move, int rg3_still, int rg4_move, int rg4_still, int rg5_move, int rg5_still, - int rg6_move, int rg6_still, int rg7_move, int rg7_still, int rg8_move, int rg8_still) { - this->rg0_move_threshold_ = rg0_move; - this->rg0_still_threshold_ = rg0_still; - this->rg1_move_threshold_ = rg1_move; - this->rg1_still_threshold_ = rg1_still; - this->rg2_move_threshold_ = rg2_move; - this->rg2_still_threshold_ = rg2_still; - this->rg3_move_threshold_ = rg3_move; - this->rg3_still_threshold_ = rg3_still; - this->rg4_move_threshold_ = rg4_move; - this->rg4_still_threshold_ = rg4_still; - this->rg5_move_threshold_ = rg5_move; - this->rg5_still_threshold_ = rg5_still; - this->rg6_move_threshold_ = rg6_move; - this->rg6_still_threshold_ = rg6_still; - this->rg7_move_threshold_ = rg7_move; - this->rg7_still_threshold_ = rg7_still; - this->rg8_move_threshold_ = rg8_move; - this->rg8_still_threshold_ = rg8_still; - }; - int moving_sensitivities[9] = {0}; - int still_sensitivities[9] = {0}; - - int32_t last_periodic_millis = millis(); +#ifdef USE_SENSOR + void set_gate_move_sensor(int gate, sensor::Sensor *s); + void set_gate_still_sensor(int gate, sensor::Sensor *s); +#endif + void set_throttle(uint16_t value) { this->throttle_ = value; }; + void set_bluetooth_password(const std::string &password); + void set_engineering_mode(bool enable); + void read_all_info(); + void restart_and_read_all_info(); + void set_bluetooth(bool enable); + void set_distance_resolution(const std::string &state); + void set_baud_rate(const std::string &state); + void factory_reset(); protected: -#ifdef USE_BINARY_SENSOR - binary_sensor::BinarySensor *target_binary_sensor_{nullptr}; - binary_sensor::BinarySensor *moving_binary_sensor_{nullptr}; - binary_sensor::BinarySensor *still_binary_sensor_{nullptr}; -#endif - - std::vector rx_buffer_; int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } - void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); - - void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, - uint16_t timeout); - void set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens); + void send_command_(uint8_t command_str, const uint8_t *command_value, int command_value_len); void set_config_mode_(bool enable); void handle_periodic_data_(uint8_t *buffer, int len); - void handle_ack_data_(uint8_t *buffer, int len); + bool handle_ack_data_(uint8_t *buffer, int len); void readline_(int readch, uint8_t *buffer, int len); void query_parameters_(); void get_version_(); + void get_mac_(); + void get_distance_resolution_(); + void get_light_control_(); + void restart_(); - uint16_t timeout_; - uint8_t max_move_distance_; - uint8_t max_still_distance_; - - uint8_t version_[6]; - uint8_t rg0_move_threshold_, rg0_still_threshold_, rg1_move_threshold_, rg1_still_threshold_, rg2_move_threshold_, - rg2_still_threshold_, rg3_move_threshold_, rg3_still_threshold_, rg4_move_threshold_, rg4_still_threshold_, - rg5_move_threshold_, rg5_still_threshold_, rg6_move_threshold_, rg6_still_threshold_, rg7_move_threshold_, - rg7_still_threshold_, rg8_move_threshold_, rg8_still_threshold_; + int32_t last_periodic_millis_ = millis(); + int32_t last_engineering_mode_change_millis_ = millis(); + uint16_t throttle_; + std::string version_; + std::string mac_; + std::string out_pin_level_; + std::string light_function_; + float light_threshold_ = -1; +#ifdef USE_NUMBER + std::vector gate_still_threshold_numbers_ = std::vector(9); + std::vector gate_move_threshold_numbers_ = std::vector(9); +#endif +#ifdef USE_SENSOR + std::vector gate_still_sensors_ = std::vector(9); + std::vector gate_move_sensors_ = std::vector(9); +#endif }; } // namespace ld2410 diff --git a/esphome/components/ld2410/number/__init__.py b/esphome/components/ld2410/number/__init__.py new file mode 100644 index 0000000000..557b226dfe --- /dev/null +++ b/esphome/components/ld2410/number/__init__.py @@ -0,0 +1,128 @@ +import esphome.codegen as cg +from esphome.components import number +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_TIMEOUT, + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_SIGNAL_STRENGTH, + DEVICE_CLASS_ILLUMINANCE, + UNIT_SECOND, + UNIT_PERCENT, + ENTITY_CATEGORY_CONFIG, + ICON_MOTION_SENSOR, + ICON_TIMELAPSE, + ICON_LIGHTBULB, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +GateThresholdNumber = ld2410_ns.class_("GateThresholdNumber", number.Number) +LightThresholdNumber = ld2410_ns.class_("LightThresholdNumber", number.Number) +MaxDistanceTimeoutNumber = ld2410_ns.class_("MaxDistanceTimeoutNumber", number.Number) + +CONF_MAX_MOVE_DISTANCE_GATE = "max_move_distance_gate" +CONF_MAX_STILL_DISTANCE_GATE = "max_still_distance_gate" +CONF_LIGHT_THRESHOLD = "light_threshold" +CONF_STILL_THRESHOLD = "still_threshold" +CONF_MOVE_THRESHOLD = "move_threshold" + +TIMEOUT_GROUP = "timeout" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Inclusive(CONF_TIMEOUT, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + unit_of_measurement=UNIT_SECOND, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_TIMELAPSE, + ), + cv.Inclusive(CONF_MAX_MOVE_DISTANCE_GATE, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + device_class=DEVICE_CLASS_DISTANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Inclusive(CONF_MAX_STILL_DISTANCE_GATE, TIMEOUT_GROUP): number.number_schema( + MaxDistanceTimeoutNumber, + device_class=DEVICE_CLASS_DISTANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_LIGHT_THRESHOLD): number.number_schema( + LightThresholdNumber, + device_class=DEVICE_CLASS_ILLUMINANCE, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_LIGHTBULB, + ), + } +) + +CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + { + cv.Optional(f"g{x}"): cv.Schema( + { + cv.Required(CONF_MOVE_THRESHOLD): number.number_schema( + GateThresholdNumber, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + cv.Required(CONF_STILL_THRESHOLD): number.number_schema( + GateThresholdNumber, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_MOTION_SENSOR, + ), + } + ) + for x in range(9) + } +) + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if timeout_config := config.get(CONF_TIMEOUT): + n = await number.new_number( + timeout_config, min_value=0, max_value=65535, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_timeout_number(n)) + if max_move_distance_gate_config := config.get(CONF_MAX_MOVE_DISTANCE_GATE): + n = await number.new_number( + max_move_distance_gate_config, min_value=2, max_value=8, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_max_move_distance_gate_number(n)) + if max_still_distance_gate_config := config.get(CONF_MAX_STILL_DISTANCE_GATE): + n = await number.new_number( + max_still_distance_gate_config, min_value=2, max_value=8, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_max_still_distance_gate_number(n)) + if light_threshold_config := config.get(CONF_LIGHT_THRESHOLD): + n = await number.new_number( + light_threshold_config, min_value=0, max_value=255, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_light_threshold_number(n)) + for x in range(9): + if gate_conf := config.get(f"g{x}"): + move_config = gate_conf[CONF_MOVE_THRESHOLD] + n = cg.new_Pvariable(move_config[CONF_ID], x) + await number.register_number( + n, move_config, min_value=0, max_value=100, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_gate_move_threshold_number(x, n)) + + still_config = gate_conf[CONF_STILL_THRESHOLD] + n = cg.new_Pvariable(still_config[CONF_ID], x) + await number.register_number( + n, still_config, min_value=0, max_value=100, step=1 + ) + await cg.register_parented(n, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_gate_still_threshold_number(x, n)) diff --git a/esphome/components/ld2410/number/gate_threshold_number.cpp b/esphome/components/ld2410/number/gate_threshold_number.cpp new file mode 100644 index 0000000000..5d040554d7 --- /dev/null +++ b/esphome/components/ld2410/number/gate_threshold_number.cpp @@ -0,0 +1,14 @@ +#include "gate_threshold_number.h" + +namespace esphome { +namespace ld2410 { + +GateThresholdNumber::GateThresholdNumber(uint8_t gate) : gate_(gate) {} + +void GateThresholdNumber::control(float value) { + this->publish_state(value); + this->parent_->set_gate_threshold(this->gate_); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/gate_threshold_number.h b/esphome/components/ld2410/number/gate_threshold_number.h new file mode 100644 index 0000000000..2806ecce63 --- /dev/null +++ b/esphome/components/ld2410/number/gate_threshold_number.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class GateThresholdNumber : public number::Number, public Parented { + public: + GateThresholdNumber(uint8_t gate); + + protected: + uint8_t gate_; + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/light_threshold_number.cpp b/esphome/components/ld2410/number/light_threshold_number.cpp new file mode 100644 index 0000000000..0ff35782cd --- /dev/null +++ b/esphome/components/ld2410/number/light_threshold_number.cpp @@ -0,0 +1,12 @@ +#include "light_threshold_number.h" + +namespace esphome { +namespace ld2410 { + +void LightThresholdNumber::control(float value) { + this->publish_state(value); + this->parent_->set_light_out_control(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/light_threshold_number.h b/esphome/components/ld2410/number/light_threshold_number.h new file mode 100644 index 0000000000..8f014373c0 --- /dev/null +++ b/esphome/components/ld2410/number/light_threshold_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class LightThresholdNumber : public number::Number, public Parented { + public: + LightThresholdNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/max_distance_timeout_number.cpp b/esphome/components/ld2410/number/max_distance_timeout_number.cpp new file mode 100644 index 0000000000..8a946f7ea9 --- /dev/null +++ b/esphome/components/ld2410/number/max_distance_timeout_number.cpp @@ -0,0 +1,12 @@ +#include "max_distance_timeout_number.h" + +namespace esphome { +namespace ld2410 { + +void MaxDistanceTimeoutNumber::control(float value) { + this->publish_state(value); + this->parent_->set_max_distances_timeout(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/number/max_distance_timeout_number.h b/esphome/components/ld2410/number/max_distance_timeout_number.h new file mode 100644 index 0000000000..7d91b4b5fe --- /dev/null +++ b/esphome/components/ld2410/number/max_distance_timeout_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class MaxDistanceTimeoutNumber : public number::Number, public Parented { + public: + MaxDistanceTimeoutNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/__init__.py b/esphome/components/ld2410/select/__init__.py new file mode 100644 index 0000000000..6c34a85ac6 --- /dev/null +++ b/esphome/components/ld2410/select/__init__.py @@ -0,0 +1,81 @@ +import esphome.codegen as cg +from esphome.components import select +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_CONFIG, + CONF_BAUD_RATE, + ICON_THERMOMETER, + ICON_SCALE, + ICON_LIGHTBULB, + ICON_RULER, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +BaudRateSelect = ld2410_ns.class_("BaudRateSelect", select.Select) +DistanceResolutionSelect = ld2410_ns.class_("DistanceResolutionSelect", select.Select) +LightOutControlSelect = ld2410_ns.class_("LightOutControlSelect", select.Select) + +CONF_DISTANCE_RESOLUTION = "distance_resolution" +CONF_LIGHT_FUNCTION = "light_function" +CONF_OUT_PIN_LEVEL = "out_pin_level" + + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_DISTANCE_RESOLUTION): select.select_schema( + DistanceResolutionSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RULER, + ), + cv.Optional(CONF_LIGHT_FUNCTION): select.select_schema( + LightOutControlSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_LIGHTBULB, + ), + cv.Optional(CONF_OUT_PIN_LEVEL): select.select_schema( + LightOutControlSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SCALE, + ), + cv.Optional(CONF_BAUD_RATE): select.select_schema( + BaudRateSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_THERMOMETER, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if distance_resolution_config := config.get(CONF_DISTANCE_RESOLUTION): + s = await select.new_select( + distance_resolution_config, options=["0.2m", "0.75m"] + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_distance_resolution_select(s)) + if out_pin_level_config := config.get(CONF_OUT_PIN_LEVEL): + s = await select.new_select(out_pin_level_config, options=["low", "high"]) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_out_pin_level_select(s)) + if light_function_config := config.get(CONF_LIGHT_FUNCTION): + s = await select.new_select( + light_function_config, options=["off", "below", "above"] + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_light_function_select(s)) + if baud_rate_config := config.get(CONF_BAUD_RATE): + s = await select.new_select( + baud_rate_config, + options=[ + "9600", + "19200", + "38400", + "57600", + "115200", + "230400", + "256000", + "460800", + ], + ) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_baud_rate_select(s)) diff --git a/esphome/components/ld2410/select/baud_rate_select.cpp b/esphome/components/ld2410/select/baud_rate_select.cpp new file mode 100644 index 0000000000..f4e0b90e2e --- /dev/null +++ b/esphome/components/ld2410/select/baud_rate_select.cpp @@ -0,0 +1,12 @@ +#include "baud_rate_select.h" + +namespace esphome { +namespace ld2410 { + +void BaudRateSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_baud_rate(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/baud_rate_select.h b/esphome/components/ld2410/select/baud_rate_select.h new file mode 100644 index 0000000000..3827b6a48a --- /dev/null +++ b/esphome/components/ld2410/select/baud_rate_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class BaudRateSelect : public select::Select, public Parented { + public: + BaudRateSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/distance_resolution_select.cpp b/esphome/components/ld2410/select/distance_resolution_select.cpp new file mode 100644 index 0000000000..eef34bda63 --- /dev/null +++ b/esphome/components/ld2410/select/distance_resolution_select.cpp @@ -0,0 +1,12 @@ +#include "distance_resolution_select.h" + +namespace esphome { +namespace ld2410 { + +void DistanceResolutionSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_distance_resolution(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/distance_resolution_select.h b/esphome/components/ld2410/select/distance_resolution_select.h new file mode 100644 index 0000000000..d6affb1020 --- /dev/null +++ b/esphome/components/ld2410/select/distance_resolution_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class DistanceResolutionSelect : public select::Select, public Parented { + public: + DistanceResolutionSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/light_out_control_select.cpp b/esphome/components/ld2410/select/light_out_control_select.cpp new file mode 100644 index 0000000000..ac23248a64 --- /dev/null +++ b/esphome/components/ld2410/select/light_out_control_select.cpp @@ -0,0 +1,12 @@ +#include "light_out_control_select.h" + +namespace esphome { +namespace ld2410 { + +void LightOutControlSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_light_out_control(); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/select/light_out_control_select.h b/esphome/components/ld2410/select/light_out_control_select.h new file mode 100644 index 0000000000..5d72e1774e --- /dev/null +++ b/esphome/components/ld2410/select/light_out_control_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class LightOutControlSelect : public select::Select, public Parented { + public: + LightOutControlSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/sensor.py b/esphome/components/ld2410/sensor.py index b941263134..83361db58a 100644 --- a/esphome/components/ld2410/sensor.py +++ b/esphome/components/ld2410/sensor.py @@ -3,9 +3,15 @@ from esphome.components import sensor import esphome.config_validation as cv from esphome.const import ( DEVICE_CLASS_DISTANCE, - DEVICE_CLASS_ENERGY, UNIT_CENTIMETER, UNIT_PERCENT, + CONF_LIGHT, + DEVICE_CLASS_ILLUMINANCE, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_SIGNAL, + ICON_FLASH, + ICON_MOTION_SENSOR, + ICON_LIGHTBULB, ) from . import CONF_LD2410_ID, LD2410Component @@ -15,41 +21,88 @@ CONF_STILL_DISTANCE = "still_distance" CONF_MOVING_ENERGY = "moving_energy" CONF_STILL_ENERGY = "still_energy" CONF_DETECTION_DISTANCE = "detection_distance" +CONF_MOVE_ENERGY = "move_energy" -CONFIG_SCHEMA = { - cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), - cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), - cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), - cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema( - device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT - ), - cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( - device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT - ), - cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema( - device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER - ), -} +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_FLASH, + ), + cv.Optional(CONF_LIGHT): sensor.sensor_schema( + device_class=DEVICE_CLASS_ILLUMINANCE, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_LIGHTBULB, + ), + cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_SIGNAL, + ), + } +) + +CONFIG_SCHEMA = CONFIG_SCHEMA.extend( + { + cv.Optional(f"g{x}"): cv.Schema( + { + cv.Optional(CONF_MOVE_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_MOTION_SENSOR, + ), + cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_FLASH, + ), + } + ) + for x in range(9) + } +) async def to_code(config): ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) - if CONF_MOVING_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_MOVING_DISTANCE]) + if moving_distance_config := config.get(CONF_MOVING_DISTANCE): + sens = await sensor.new_sensor(moving_distance_config) cg.add(ld2410_component.set_moving_target_distance_sensor(sens)) - if CONF_STILL_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_STILL_DISTANCE]) + if still_distance_config := config.get(CONF_STILL_DISTANCE): + sens = await sensor.new_sensor(still_distance_config) cg.add(ld2410_component.set_still_target_distance_sensor(sens)) - if CONF_MOVING_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_MOVING_ENERGY]) + if moving_energy_config := config.get(CONF_MOVING_ENERGY): + sens = await sensor.new_sensor(moving_energy_config) cg.add(ld2410_component.set_moving_target_energy_sensor(sens)) - if CONF_STILL_ENERGY in config: - sens = await sensor.new_sensor(config[CONF_STILL_ENERGY]) + if still_energy_config := config.get(CONF_STILL_ENERGY): + sens = await sensor.new_sensor(still_energy_config) cg.add(ld2410_component.set_still_target_energy_sensor(sens)) - if CONF_DETECTION_DISTANCE in config: - sens = await sensor.new_sensor(config[CONF_DETECTION_DISTANCE]) + if light_config := config.get(CONF_LIGHT): + sens = await sensor.new_sensor(light_config) + cg.add(ld2410_component.set_light_sensor(sens)) + if detection_distance_config := config.get(CONF_DETECTION_DISTANCE): + sens = await sensor.new_sensor(detection_distance_config) cg.add(ld2410_component.set_detection_distance_sensor(sens)) + for x in range(9): + if gate_conf := config.get(f"g{x}"): + if move_config := gate_conf.get(CONF_MOVE_ENERGY): + sens = await sensor.new_sensor(move_config) + cg.add(ld2410_component.set_gate_move_sensor(x, sens)) + if still_config := gate_conf.get(CONF_STILL_ENERGY): + sens = await sensor.new_sensor(still_config) + cg.add(ld2410_component.set_gate_still_sensor(x, sens)) diff --git a/esphome/components/ld2410/switch/__init__.py b/esphome/components/ld2410/switch/__init__.py new file mode 100644 index 0000000000..096cb5f67a --- /dev/null +++ b/esphome/components/ld2410/switch/__init__.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_SWITCH, + ICON_BLUETOOTH, + ENTITY_CATEGORY_CONFIG, + ICON_PULSE, +) +from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns + +BluetoothSwitch = ld2410_ns.class_("BluetoothSwitch", switch.Switch) +EngineeringModeSwitch = ld2410_ns.class_("EngineeringModeSwitch", switch.Switch) + +CONF_ENGINEERING_MODE = "engineering_mode" +CONF_BLUETOOTH = "bluetooth" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_ENGINEERING_MODE): switch.switch_schema( + EngineeringModeSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_PULSE, + ), + cv.Optional(CONF_BLUETOOTH): switch.switch_schema( + BluetoothSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_BLUETOOTH, + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if engineering_mode_config := config.get(CONF_ENGINEERING_MODE): + s = await switch.new_switch(engineering_mode_config) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_engineering_mode_switch(s)) + if bluetooth_config := config.get(CONF_BLUETOOTH): + s = await switch.new_switch(bluetooth_config) + await cg.register_parented(s, config[CONF_LD2410_ID]) + cg.add(ld2410_component.set_bluetooth_switch(s)) diff --git a/esphome/components/ld2410/switch/bluetooth_switch.cpp b/esphome/components/ld2410/switch/bluetooth_switch.cpp new file mode 100644 index 0000000000..9bcee9b049 --- /dev/null +++ b/esphome/components/ld2410/switch/bluetooth_switch.cpp @@ -0,0 +1,12 @@ +#include "bluetooth_switch.h" + +namespace esphome { +namespace ld2410 { + +void BluetoothSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_bluetooth(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/bluetooth_switch.h b/esphome/components/ld2410/switch/bluetooth_switch.h new file mode 100644 index 0000000000..35ae1ec0c9 --- /dev/null +++ b/esphome/components/ld2410/switch/bluetooth_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class BluetoothSwitch : public switch_::Switch, public Parented { + public: + BluetoothSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/engineering_mode_switch.cpp b/esphome/components/ld2410/switch/engineering_mode_switch.cpp new file mode 100644 index 0000000000..967c87c887 --- /dev/null +++ b/esphome/components/ld2410/switch/engineering_mode_switch.cpp @@ -0,0 +1,12 @@ +#include "engineering_mode_switch.h" + +namespace esphome { +namespace ld2410 { + +void EngineeringModeSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_engineering_mode(state); +} + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/switch/engineering_mode_switch.h b/esphome/components/ld2410/switch/engineering_mode_switch.h new file mode 100644 index 0000000000..e521200cd6 --- /dev/null +++ b/esphome/components/ld2410/switch/engineering_mode_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../ld2410.h" + +namespace esphome { +namespace ld2410 { + +class EngineeringModeSwitch : public switch_::Switch, public Parented { + public: + EngineeringModeSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/esphome/components/ld2410/text_sensor.py b/esphome/components/ld2410/text_sensor.py new file mode 100644 index 0000000000..d64472a7d3 --- /dev/null +++ b/esphome/components/ld2410/text_sensor.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_DIAGNOSTIC, + CONF_VERSION, + CONF_MAC_ADDRESS, + ICON_BLUETOOTH, + ICON_CHIP, +) +from . import CONF_LD2410_ID, LD2410Component + +DEPENDENCIES = ["ld2410"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon=ICON_CHIP + ), + cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon=ICON_BLUETOOTH + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if version_config := config.get(CONF_VERSION): + sens = await text_sensor.new_text_sensor(version_config) + cg.add(ld2410_component.set_version_text_sensor(sens)) + if mac_address_config := config.get(CONF_MAC_ADDRESS): + sens = await text_sensor.new_text_sensor(mac_address_config) + cg.add(ld2410_component.set_mac_text_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 4eb78515c9..66caad961a 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -170,6 +170,9 @@ mqtt: id: uart_0 data: !lambda |- return {}; + - bluetooth_password.set: + id: my_ld2410 + password: abcdef on_connect: - light.turn_on: ${roomname}_lights - mqtt.publish: @@ -1333,16 +1336,64 @@ sensor: speed: name: "Radiator Pump Speed" - platform: ld2410 + light: + name: light moving_distance: name: "Moving distance (cm)" still_distance: name: "Still Distance (cm)" moving_energy: - name: "Move Energy" + name: "Move Energy (%)" still_energy: - name: "Still Energy" + name: "Still Energy (%)" detection_distance: - name: "Distance Detection" + name: "Distance Detection (cm)" + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + - platform: sen21231 name: "Person Sensor" i2c_id: i2c_bus @@ -1684,6 +1735,8 @@ binary_sensor: name: movement has_still_target: name: still + out_pin_presence_status: + name: out pin presence status pca9685: frequency: 500 @@ -2626,6 +2679,11 @@ switch: id: outlet_switch optimistic: true device_class: outlet + - platform: ld2410 + engineering_mode: + name: "control ld2410 engineering mode" + bluetooth: + name: "control ld2410 bluetooth" fan: - platform: binary @@ -3207,6 +3265,11 @@ text_sensor: tag_name: OPTARIF name: optarif teleinfo_id: myteleinfo + - platform: ld2410 + version: + name: "presenece sensor version" + mac_address: + name: "presenece sensor mac address" sn74hc595: - id: sn74hc595_hub @@ -3311,6 +3374,61 @@ number: step: 1 max_value: 10 optimistic: true + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + select: - platform: template @@ -3324,6 +3442,15 @@ select: - platform: copy source_id: test_select name: Test Select Copy + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level qr_code: - id: homepage_qr @@ -3386,19 +3513,17 @@ button: name: Midea Power Inverse on_press: midea_ac.power_toggle: + - platform: ld2410 + factory_reset: + name: "factory reset" + restart: + name: "restart" + query_params: + name: query params ld2410: id: my_ld2410 uart_id: ld2410_uart - timeout: 150s - max_move_distance: 6m - max_still_distance: 0.75m - g0_move_threshold: 10 - g0_still_threshold: 20 - g2_move_threshold: 20 - g2_still_threshold: 21 - g8_move_threshold: 80 - g8_still_threshold: 81 lcd_menu: display_id: my_lcd_gpio From 532163738e82d0b392302abb74f5f6268cb6fb01 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 16 Aug 2023 11:49:08 +1200 Subject: [PATCH 0365/2607] Bump version to 2023.8.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 1442ebde9d..aff72531bb 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0b2" +__version__ = "2023.8.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 5f99ed943ae81892e62ea1a542e3d48c1e1cf100 Mon Sep 17 00:00:00 2001 From: Pierre Gordon <16200219+pierlon@users.noreply.github.com> Date: Wed, 16 Aug 2023 20:22:04 -0400 Subject: [PATCH 0366/2607] Add `libfreetype-dev` Debian package for armv7 Docker builds (#5262) --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e1f3c46a3e..4aaea9da89 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,7 +35,8 @@ RUN \ python3-dev=3.9.2-3 \ zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ libjpeg-dev=1:2.0.6-4 \ - libcairo2=1.16.0-5; \ + libcairo2=1.16.0-5 \ + libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ fi; \ rm -rf \ /tmp/* \ From 63fc16d8722ca913b6def0eda53fbb6d15197338 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 17 Aug 2023 02:22:37 +0200 Subject: [PATCH 0367/2607] Add delay before enabling ipv6 (#5256) --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 995e5e587e..5bfb6bb9a8 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -486,7 +486,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); #if LWIP_IPV6 - WiFi.enableIpV6(); + this->set_timeout(100, [] { WiFi.enableIpV6(); }); #endif /* LWIP_IPV6 */ break; From c5be5e6d12316035b70175bed1a2cae5be0dc41b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 12:23:44 +1200 Subject: [PATCH 0368/2607] Bump zeroconf from 0.74.0 to 0.80.0 (#5260) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6330a0996e..a1f73d930a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.6 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.74.0 +zeroconf==0.80.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From a27e72362ab5045bfc52616fb6d8fe8744e8155c Mon Sep 17 00:00:00 2001 From: Pierre Gordon <16200219+pierlon@users.noreply.github.com> Date: Wed, 16 Aug 2023 20:22:04 -0400 Subject: [PATCH 0369/2607] Add `libfreetype-dev` Debian package for armv7 Docker builds (#5262) --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e1f3c46a3e..4aaea9da89 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,7 +35,8 @@ RUN \ python3-dev=3.9.2-3 \ zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ libjpeg-dev=1:2.0.6-4 \ - libcairo2=1.16.0-5; \ + libcairo2=1.16.0-5 \ + libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ fi; \ rm -rf \ /tmp/* \ From cb66ce069e2f8d092095167403489a16fe408466 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 17 Aug 2023 02:22:37 +0200 Subject: [PATCH 0370/2607] Add delay before enabling ipv6 (#5256) --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 995e5e587e..5bfb6bb9a8 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -486,7 +486,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); #if LWIP_IPV6 - WiFi.enableIpV6(); + this->set_timeout(100, [] { WiFi.enableIpV6(); }); #endif /* LWIP_IPV6 */ break; From 7c129a4018305ba2525e2fdca5064412eca0b49a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 12:23:44 +1200 Subject: [PATCH 0371/2607] Bump zeroconf from 0.74.0 to 0.80.0 (#5260) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6330a0996e..a1f73d930a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.6 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.74.0 +zeroconf==0.80.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 2aaba1d2b855126cd32d601c1b9a04a37f6ee152 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 17 Aug 2023 13:04:32 +1200 Subject: [PATCH 0372/2607] Bump version to 2023.8.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index aff72531bb..ffac22fc58 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0b3" +__version__ = "2023.8.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7e4ee32b5404d83d6046721e5195b271df3396b1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:33:35 +1200 Subject: [PATCH 0373/2607] Bump version to 2023.8.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index ffac22fc58..f0a6efda94 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0b4" +__version__ = "2023.8.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 9fc50e8dbc287f1ea5bed9acbaff612cb196998f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:41:24 +0000 Subject: [PATCH 0374/2607] Bump click from 8.1.6 to 8.1.7 (#5272) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a1f73d930a..4a046014d6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.9 # When updating platformio, also update Dockerfile esptool==4.6.2 -click==8.1.6 +click==8.1.7 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 zeroconf==0.80.0 From 2b4ed0c2738cae095f5803d539d1a1d0d4a738a9 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:57:18 +0000 Subject: [PATCH 0375/2607] Fix checksum calculation for sml (#5271) --- esphome/components/sml/sml.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/sml/sml.cpp b/esphome/components/sml/sml.cpp index 87dc25c220..921623d4fd 100644 --- a/esphome/components/sml/sml.cpp +++ b/esphome/components/sml/sml.cpp @@ -100,14 +100,14 @@ bool check_sml_data(const bytes &buffer) { } uint16_t crc_received = (buffer.at(buffer.size() - 2) << 8) | buffer.at(buffer.size() - 1); - uint16_t crc_calculated = crc16(buffer.data(), buffer.size(), 0x6e23, 0x8408, true, true); + uint16_t crc_calculated = crc16(buffer.data(), buffer.size() - 2, 0x6e23, 0x8408, true, true); crc_calculated = (crc_calculated >> 8) | (crc_calculated << 8); if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/X25."); return true; } - crc_calculated = crc16(buffer.data(), buffer.size(), 0xed50, 0x8408); + crc_calculated = crc16(buffer.data(), buffer.size() - 2, 0xed50, 0x8408); if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/KERMIT."); return true; From 0af8d0b7eac67807749c16b2eea2b7d98debdd56 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 17 Aug 2023 22:02:57 +0200 Subject: [PATCH 0376/2607] Remove support for ESP-IDF version < 4 (#5261) --- esphome/components/debug/debug_component.cpp | 4 -- esphome/components/esp32/core.cpp | 12 +--- esphome/components/esp32_touch/esp32_touch.h | 4 -- .../components/socket/bsd_sockets_impl.cpp | 41 +----------- esphome/components/wifi/wifi_component.h | 4 -- .../wifi/wifi_component_esp32_arduino.cpp | 63 ------------------- .../wifi/wifi_component_esp_idf.cpp | 4 -- 7 files changed, 3 insertions(+), 129 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 8b6a97068b..baf537a12b 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -12,12 +12,8 @@ #include #include -#if ESP_IDF_VERSION_MAJOR >= 4 #include #include -#else -#include -#endif #endif // USE_ESP32 diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 512a8857b6..16aa93c232 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -10,9 +10,7 @@ #include #include -#if ESP_IDF_VERSION_MAJOR >= 4 #include -#endif #ifdef USE_ARDUINO #include @@ -55,15 +53,7 @@ void arch_init() { void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -uint32_t arch_get_cpu_cycle_count() { -#if ESP_IDF_VERSION_MAJOR >= 4 - return cpu_hal_get_cycle_count(); -#else - uint32_t ccount; - __asm__ __volatile__("esync; rsr %0,ccount" : "=a"(ccount)); - return ccount; -#endif -} +uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); } uint32_t arch_get_cpu_freq_hz() { return rtc_clk_apb_freq_get(); } #ifdef USE_ESP_IDF diff --git a/esphome/components/esp32_touch/esp32_touch.h b/esphome/components/esp32_touch/esp32_touch.h index 0ba7ed6255..0eac590ce7 100644 --- a/esphome/components/esp32_touch/esp32_touch.h +++ b/esphome/components/esp32_touch/esp32_touch.h @@ -8,11 +8,7 @@ #include -#if ESP_IDF_VERSION_MAJOR >= 4 #include -#else -#include -#endif namespace esphome { namespace esp32_touch { diff --git a/esphome/components/socket/bsd_sockets_impl.cpp b/esphome/components/socket/bsd_sockets_impl.cpp index 2dea4af277..5d44cd7689 100644 --- a/esphome/components/socket/bsd_sockets_impl.cpp +++ b/esphome/components/socket/bsd_sockets_impl.cpp @@ -87,25 +87,7 @@ class BSDSocketImpl : public Socket { int listen(int backlog) override { return ::listen(fd_, backlog); } ssize_t read(void *buf, size_t len) override { return ::read(fd_, buf, len); } ssize_t readv(const struct iovec *iov, int iovcnt) override { -#if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 4 - // esp-idf v3 doesn't have readv, emulate it - ssize_t ret = 0; - for (int i = 0; i < iovcnt; i++) { - ssize_t err = this->read(reinterpret_cast(iov[i].iov_base), iov[i].iov_len); - if (err == -1) { - if (ret != 0) { - // if we already read some don't return an error - break; - } - return err; - } - ret += err; - if (err != iov[i].iov_len) - break; - } - return ret; -#elif defined(USE_ESP32) - // ESP-IDF v4 only has symbol lwip_readv +#if defined(USE_ESP32) return ::lwip_readv(fd_, iov, iovcnt); #else return ::readv(fd_, iov, iovcnt); @@ -114,26 +96,7 @@ class BSDSocketImpl : public Socket { ssize_t write(const void *buf, size_t len) override { return ::write(fd_, buf, len); } ssize_t send(void *buf, size_t len, int flags) { return ::send(fd_, buf, len, flags); } ssize_t writev(const struct iovec *iov, int iovcnt) override { -#if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 4 - // esp-idf v3 doesn't have writev, emulate it - ssize_t ret = 0; - for (int i = 0; i < iovcnt; i++) { - ssize_t err = - this->send(reinterpret_cast(iov[i].iov_base), iov[i].iov_len, i == iovcnt - 1 ? 0 : MSG_MORE); - if (err == -1) { - if (ret != 0) { - // if we already wrote some don't return an error - break; - } - return err; - } - ret += err; - if (err != iov[i].iov_len) - break; - } - return ret; -#elif defined(USE_ESP32) - // ESP-IDF v4 only has symbol lwip_writev +#if defined(USE_ESP32) return ::lwip_writev(fd_, iov, iovcnt); #else return ::writev(fd_, iov, iovcnt); diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d39b062990..c17246fd00 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -324,11 +324,7 @@ class WiFiComponent : public Component { #endif #ifdef USE_ESP32_FRAMEWORK_ARDUINO -#if ESP_IDF_VERSION_MAJOR >= 4 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info); -#else - void wifi_event_callback_(system_event_id_t event, system_event_info_t info); -#endif void wifi_scan_done_callback_(); #endif #ifdef USE_ESP_IDF diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 5bfb6bb9a8..95f4e2ce92 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -203,12 +203,10 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // Units: AP beacon intervals. Defaults to 3 if set to 0. conf.sta.listen_interval = 0; -#if ESP_IDF_VERSION_MAJOR >= 4 // Protected Management Frame // Device will prefer to connect in PMF mode if other device also advertises PMF capability. conf.sta.pmf_cfg.capable = true; conf.sta.pmf_cfg.required = false; -#endif // note, we do our own filtering // The minimum rssi to accept in the fast scan mode @@ -314,11 +312,7 @@ const char *get_auth_mode_str(uint8_t mode) { } } -#if ESP_IDF_VERSION_MAJOR >= 4 using esphome_ip4_addr_t = esp_ip4_addr_t; -#else -using esphome_ip4_addr_t = ip4_addr_t; -#endif std::string format_ip4_addr(const esphome_ip4_addr_t &ip) { char buf[20]; @@ -404,8 +398,6 @@ const char *get_disconnect_reason_str(uint8_t reason) { } } -#if ESP_IDF_VERSION_MAJOR >= 4 - #define ESPHOME_EVENT_ID_WIFI_READY ARDUINO_EVENT_WIFI_READY #define ESPHOME_EVENT_ID_WIFI_SCAN_DONE ARDUINO_EVENT_WIFI_SCAN_DONE #define ESPHOME_EVENT_ID_WIFI_STA_START ARDUINO_EVENT_WIFI_STA_START @@ -426,28 +418,6 @@ const char *get_disconnect_reason_str(uint8_t reason) { using esphome_wifi_event_id_t = arduino_event_id_t; using esphome_wifi_event_info_t = arduino_event_info_t; -#else // ESP_IDF_VERSION_MAJOR >= 4 - -#define ESPHOME_EVENT_ID_WIFI_READY SYSTEM_EVENT_WIFI_READY -#define ESPHOME_EVENT_ID_WIFI_SCAN_DONE SYSTEM_EVENT_SCAN_DONE -#define ESPHOME_EVENT_ID_WIFI_STA_START SYSTEM_EVENT_STA_START -#define ESPHOME_EVENT_ID_WIFI_STA_STOP SYSTEM_EVENT_STA_STOP -#define ESPHOME_EVENT_ID_WIFI_STA_CONNECTED SYSTEM_EVENT_STA_CONNECTED -#define ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED -#define ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE SYSTEM_EVENT_STA_AUTHMODE_CHANGE -#define ESPHOME_EVENT_ID_WIFI_STA_GOT_IP SYSTEM_EVENT_STA_GOT_IP -#define ESPHOME_EVENT_ID_WIFI_STA_LOST_IP SYSTEM_EVENT_STA_LOST_IP -#define ESPHOME_EVENT_ID_WIFI_AP_START SYSTEM_EVENT_AP_START -#define ESPHOME_EVENT_ID_WIFI_AP_STOP SYSTEM_EVENT_AP_STOP -#define ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED SYSTEM_EVENT_AP_STACONNECTED -#define ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED SYSTEM_EVENT_AP_STADISCONNECTED -#define ESPHOME_EVENT_ID_WIFI_AP_STAIPASSIGNED SYSTEM_EVENT_AP_STAIPASSIGNED -#define ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED SYSTEM_EVENT_AP_PROBEREQRECVED -using esphome_wifi_event_id_t = system_event_id_t; -using esphome_wifi_event_info_t = system_event_info_t; - -#endif // !(ESP_IDF_VERSION_MAJOR >= 4) - void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_wifi_event_info_t info) { switch (event) { case ESPHOME_EVENT_ID_WIFI_READY: { @@ -455,11 +425,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_SCAN_DONE: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_scan_done; -#else - auto it = info.scan_done; -#endif ESP_LOGV(TAG, "Event: WiFi Scan Done status=%u number=%u scan_id=%u", it.status, it.number, it.scan_id); this->wifi_scan_done_callback_(); @@ -475,11 +441,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_STA_CONNECTED: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_sta_connected; -#else - auto it = info.connected; -#endif char buf[33]; memcpy(buf, it.ssid, it.ssid_len); buf[it.ssid_len] = '\0'; @@ -492,11 +454,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_sta_disconnected; -#else - auto it = info.disconnected; -#endif char buf[33]; memcpy(buf, it.ssid, it.ssid_len); buf[it.ssid_len] = '\0'; @@ -522,11 +480,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_sta_authmode_change; -#else - auto it = info.auth_change; -#endif ESP_LOGV(TAG, "Event: Authmode Change old=%s new=%s", get_auth_mode_str(it.old_mode), get_auth_mode_str(it.new_mode)); // Mitigate CVE-2020-12638 @@ -570,24 +524,14 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_sta_connected; auto &mac = it.bssid; -#else - auto it = info.sta_connected; - auto &mac = it.mac; -#endif ESP_LOGV(TAG, "Event: AP client connected MAC=%s", format_mac_addr(mac).c_str()); break; } case ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_sta_disconnected; auto &mac = it.bssid; -#else - auto it = info.sta_disconnected; - auto &mac = it.mac; -#endif ESP_LOGV(TAG, "Event: AP client disconnected MAC=%s", format_mac_addr(mac).c_str()); break; } @@ -596,11 +540,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } case ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED: { -#if ESP_IDF_VERSION_MAJOR >= 4 auto it = info.wifi_ap_probereqrecved; -#else - auto it = info.ap_probereqrecved; -#endif ESP_LOGVV(TAG, "Event: AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi); break; } @@ -742,10 +682,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.ssid)); } -#if ESP_IDF_VERSION_MAJOR >= 4 - // pairwise cipher of SoftAP, group cipher will be derived using this. conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP; -#endif esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf); if (err != ESP_OK) { diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index e9d74116cf..9041679ccf 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -312,12 +312,10 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // Units: AP beacon intervals. Defaults to 3 if set to 0. conf.sta.listen_interval = 0; -#if ESP_IDF_VERSION_MAJOR >= 4 // Protected Management Frame // Device will prefer to connect in PMF mode if other device also advertises PMF capability. conf.sta.pmf_cfg.capable = true; conf.sta.pmf_cfg.required = false; -#endif // note, we do our own filtering // The minimum rssi to accept in the fast scan mode @@ -838,10 +836,8 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password)); } -#if ESP_IDF_VERSION_MAJOR >= 4 // pairwise cipher of SoftAP, group cipher will be derived using this. conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP; -#endif esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf); if (err != ESP_OK) { From c11c4dad2f4721d52c3f7eb895c79154393f3570 Mon Sep 17 00:00:00 2001 From: SeByDocKy Date: Thu, 17 Aug 2023 22:03:39 +0200 Subject: [PATCH 0377/2607] Add pmwcs3 capacitive soil moisture & temperature sensor component (#4624) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/pmwcs3/__init__.py | 1 + esphome/components/pmwcs3/pmwcs3.cpp | 115 +++++++++++++++++++++ esphome/components/pmwcs3/pmwcs3.h | 70 +++++++++++++ esphome/components/pmwcs3/sensor.py | 140 ++++++++++++++++++++++++++ tests/test1.yaml | 10 ++ 6 files changed, 337 insertions(+) create mode 100644 esphome/components/pmwcs3/__init__.py create mode 100644 esphome/components/pmwcs3/pmwcs3.cpp create mode 100644 esphome/components/pmwcs3/pmwcs3.h create mode 100644 esphome/components/pmwcs3/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index f50700c502..0cea8d48ba 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -212,6 +212,7 @@ esphome/components/pid/* @OttoWinter esphome/components/pipsolar/* @andreashergert1984 esphome/components/pm1006/* @habbie esphome/components/pmsa003i/* @sjtrny +esphome/components/pmwcs3/* @SeByDocKy esphome/components/pn532/* @OttoWinter @jesserockz esphome/components/pn532_i2c/* @OttoWinter @jesserockz esphome/components/pn532_spi/* @OttoWinter @jesserockz diff --git a/esphome/components/pmwcs3/__init__.py b/esphome/components/pmwcs3/__init__.py new file mode 100644 index 0000000000..b04c30a005 --- /dev/null +++ b/esphome/components/pmwcs3/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@SeByDocKy"] diff --git a/esphome/components/pmwcs3/pmwcs3.cpp b/esphome/components/pmwcs3/pmwcs3.cpp new file mode 100644 index 0000000000..812018b52e --- /dev/null +++ b/esphome/components/pmwcs3/pmwcs3.cpp @@ -0,0 +1,115 @@ +#include "pmwcs3.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace pmwcs3 { + +static const uint8_t PMWCS3_I2C_ADDRESS = 0x63; +static const uint8_t PMWCS3_REG_READ_START = 0x01; +static const uint8_t PMWCS3_REG_READ_E25 = 0x02; +static const uint8_t PMWCS3_REG_READ_EC = 0x03; +static const uint8_t PMWCS3_REG_READ_TEMP = 0x04; +static const uint8_t PMWCS3_REG_READ_VWC = 0x05; +static const uint8_t PMWCS3_REG_CALIBRATE_AIR = 0x06; +static const uint8_t PMWCS3_REG_CALIBRATE_WATER = 0x07; +static const uint8_t PMWCS3_SET_I2C_ADDRESS = 0x08; +static const uint8_t PMWCS3_REG_GET_DATA = 0x09; +static const uint8_t PMWCS3_REG_CALIBRATE_EC = 0x10; +static const uint8_t PMWCS3_REG_CAP = 0x0A; +static const uint8_t PMWCS3_REG_RES = 0x0B; +static const uint8_t PMWCS3_REG_RC = 0x0C; +static const uint8_t PMWCS3_REG_RT = 0x0D; + +static const char *const TAG = "pmwcs3"; + +void PMWCS3Component::new_i2c_address(uint8_t address) { + if (!this->write_byte(PMWCS3_SET_I2C_ADDRESS, address)) { + this->status_set_warning(); + ESP_LOGW(TAG, "couldn't write the new I2C address %d", address); + return; + } + this->set_i2c_address(address); // Allows device to continue working until new firmware is written with new address. + ESP_LOGVV(TAG, "changed I2C address to %d", address); + this->status_clear_warning(); +} + +void PMWCS3Component::air_calibration() { + if (!this->write_bytes(PMWCS3_REG_CALIBRATE_AIR, nullptr, 0)) { + this->status_set_warning(); + ESP_LOGW(TAG, "couldn't start air calibration"); + return; + } + ESP_LOGW(TAG, "Start air calibration during the next 300s"); +} +void PMWCS3Component::water_calibration() { + if (!this->write_bytes(PMWCS3_REG_CALIBRATE_WATER, nullptr, 0)) { + this->status_set_warning(); + ESP_LOGW(TAG, "couldn't start water calibration"); + return; + } + ESP_LOGW(TAG, "Start water calibration during the next 300s"); +} + +void PMWCS3Component::setup() { ESP_LOGCONFIG(TAG, "Setting up PMWCS3..."); } + +void PMWCS3Component::update() { this->read_data_(); } + +float PMWCS3Component::get_setup_priority() const { return setup_priority::DATA; } + +void PMWCS3Component::dump_config() { + ESP_LOGCONFIG(TAG, "PMWCS3"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with PMWCS3 failed!"); + } + ESP_LOGI(TAG, "%s", this->is_failed() ? "FAILED" : "OK"); + + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "e25", this->e25_sensor_); + LOG_SENSOR(" ", "ec", this->ec_sensor_); + LOG_SENSOR(" ", "temperature", this->temperature_sensor_); + LOG_SENSOR(" ", "vwc", this->vwc_sensor_); +} +void PMWCS3Component::read_data_() { + uint8_t data[8]; + float e25, ec, temperature, vwc; + + /////// Super important !!!! first activate reading PMWCS3_REG_READ_START (if not, return always the same values) //// + + if (!this->write_bytes(PMWCS3_REG_READ_START, nullptr, 0)) { + this->status_set_warning(); + ESP_LOGVV(TAG, "Failed to write into REG_READ_START register !!!"); + return; + } + // NOLINT delay(100); + + if (!this->read_bytes(PMWCS3_REG_GET_DATA, (uint8_t *) &data, 8)) { + ESP_LOGVV(TAG, "Error reading PMWCS3_REG_GET_DATA registers"); + this->mark_failed(); + return; + } + if (this->e25_sensor_ != nullptr) { + e25 = ((data[1] << 8) | data[0]) / 100.0; + this->e25_sensor_->publish_state(e25); + ESP_LOGVV(TAG, "e25: data[0]=%d, data[1]=%d, result=%f", data[0], data[1], e25); + } + if (this->ec_sensor_ != nullptr) { + ec = ((data[3] << 8) | data[2]) / 10.0; + this->ec_sensor_->publish_state(ec); + ESP_LOGVV(TAG, "ec: data[2]=%d, data[3]=%d, result=%f", data[2], data[3], ec); + } + if (this->temperature_sensor_ != nullptr) { + temperature = ((data[5] << 8) | data[4]) / 100.0; + this->temperature_sensor_->publish_state(temperature); + ESP_LOGVV(TAG, "temp: data[4]=%d, data[5]=%d, result=%f", data[4], data[5], temperature); + } + if (this->vwc_sensor_ != nullptr) { + vwc = ((data[7] << 8) | data[6]) / 10.0; + this->vwc_sensor_->publish_state(vwc); + ESP_LOGVV(TAG, "vwc: data[6]=%d, data[7]=%d, result=%f", data[6], data[7], vwc); + } +} + +} // namespace pmwcs3 +} // namespace esphome diff --git a/esphome/components/pmwcs3/pmwcs3.h b/esphome/components/pmwcs3/pmwcs3.h new file mode 100644 index 0000000000..f3916bb868 --- /dev/null +++ b/esphome/components/pmwcs3/pmwcs3.h @@ -0,0 +1,70 @@ +#pragma once +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +// ref: +// https://github.com/tinovi/i2cArduino/blob/master/i2cArduino.h + +namespace esphome { +namespace pmwcs3 { + +class PMWCS3Component : public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void update() override; + void dump_config() override; + float get_setup_priority() const override; + + void set_e25_sensor(sensor::Sensor *e25_sensor) { e25_sensor_ = e25_sensor; } + void set_ec_sensor(sensor::Sensor *ec_sensor) { ec_sensor_ = ec_sensor; } + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } + void set_vwc_sensor(sensor::Sensor *vwc_sensor) { vwc_sensor_ = vwc_sensor; } + + void new_i2c_address(uint8_t newaddress); + void air_calibration(); + void water_calibration(); + + protected: + void read_data_(); + + sensor::Sensor *e25_sensor_{nullptr}; + sensor::Sensor *ec_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *vwc_sensor_{nullptr}; +}; + +template class PMWCS3AirCalibrationAction : public Action { + public: + PMWCS3AirCalibrationAction(PMWCS3Component *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->air_calibration(); } + + protected: + PMWCS3Component *parent_; +}; + +template class PMWCS3WaterCalibrationAction : public Action { + public: + PMWCS3WaterCalibrationAction(PMWCS3Component *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->water_calibration(); } + + protected: + PMWCS3Component *parent_; +}; + +template class PMWCS3NewI2cAddressAction : public Action { + public: + PMWCS3NewI2cAddressAction(PMWCS3Component *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(int, new_address) + + void play(Ts... x) override { this->parent_->new_i2c_address(this->new_address_.value(x...)); } + + protected: + PMWCS3Component *parent_; +}; + +} // namespace pmwcs3 +} // namespace esphome diff --git a/esphome/components/pmwcs3/sensor.py b/esphome/components/pmwcs3/sensor.py new file mode 100644 index 0000000000..81be327d14 --- /dev/null +++ b/esphome/components/pmwcs3/sensor.py @@ -0,0 +1,140 @@ +import esphome.codegen as cg +from esphome import automation +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + CONF_ADDRESS, + CONF_TEMPERATURE, + CONF_EC, + STATE_CLASS_MEASUREMENT, + ICON_THERMOMETER, +) + +CODEOWNERS = ["@SeByDocKy"] +DEPENDENCIES = ["i2c"] + +CONF_E25 = "e25" +CONF_VWC = "vwc" + +ICON_EPSILON = "mdi:epsilon" +ICON_SIGMA = "mdi:sigma-lower" +ICON_ALPHA = "mdi:alpha-h-circle-outline" + +pmwcs3_ns = cg.esphome_ns.namespace("pmwcs3") +PMWCS3Component = pmwcs3_ns.class_( + "PMWCS3Component", cg.PollingComponent, i2c.I2CDevice +) + +# Actions +PMWCS3AirCalibrationAction = pmwcs3_ns.class_( + "PMWCS3AirCalibrationAction", automation.Action +) +PMWCS3WaterCalibrationAction = pmwcs3_ns.class_( + "PMWCS3WaterCalibrationAction", automation.Action +) +PMWCS3NewI2cAddressAction = pmwcs3_ns.class_( + "PMWCS3NewI2cAddressAction", automation.Action +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(PMWCS3Component), + cv.Optional(CONF_E25): sensor.sensor_schema( + icon=ICON_EPSILON, + accuracy_decimals=3, + unit_of_measurement="dS/m", + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_EC): sensor.sensor_schema( + icon=ICON_SIGMA, + accuracy_decimals=2, + unit_of_measurement="mS/m", + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + icon=ICON_THERMOMETER, + accuracy_decimals=3, + unit_of_measurement="°C", + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_VWC): sensor.sensor_schema( + icon=ICON_ALPHA, + accuracy_decimals=3, + unit_of_measurement="cm3cm−3", + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x63)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if CONF_E25 in config: + sens = await sensor.new_sensor(config[CONF_E25]) + cg.add(var.set_e25_sensor(sens)) + + if CONF_EC in config: + sens = await sensor.new_sensor(config[CONF_EC]) + cg.add(var.set_ec_sensor(sens)) + + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature_sensor(sens)) + + if CONF_VWC in config: + sens = await sensor.new_sensor(config[CONF_VWC]) + cg.add(var.set_vwc_sensor(sens)) + + +# Actions +PMWCS3_CALIBRATION_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(PMWCS3Component), + } +) + + +@automation.register_action( + "pmwcs3.air_calibration", + PMWCS3AirCalibrationAction, + PMWCS3_CALIBRATION_SCHEMA, +) +@automation.register_action( + "pmwcs3.water_calibration", + PMWCS3WaterCalibrationAction, + PMWCS3_CALIBRATION_SCHEMA, +) +async def pmwcs3_calibration_to_code(config, action_id, template_arg, args): + parent = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, parent) + return var + + +PMWCS3_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(PMWCS3Component), + cv.Required(CONF_ADDRESS): cv.templatable(cv.i2c_address), + }, + key=CONF_ADDRESS, +) + + +@automation.register_action( + "pmwcs3.new_i2c_address", + PMWCS3NewI2cAddressAction, + PMWCS3_NEW_I2C_ADDRESS_SCHEMA, +) +async def pmwcs3newi2caddress_to_code(config, action_id, template_arg, args): + parent = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, parent) + address = await cg.templatable(config[CONF_ADDRESS], args, int) + cg.add(var.set_new_address(address)) + return var diff --git a/tests/test1.yaml b/tests/test1.yaml index 66caad961a..80cd9e3987 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -348,6 +348,16 @@ mcp23s17: deviceaddress: 1 sensor: + - platform: pmwcs3 + i2c_id: i2c_bus + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc - platform: gcja5 pm_1_0: name: "Particulate Matter <1.0µm Concentration" From 164d05fdcea31ea295e3ac98cd06966aacb236a1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 18 Aug 2023 06:05:25 +1000 Subject: [PATCH 0378/2607] Add manufacturer data config to BLE server (#5251) --- CODEOWNERS | 2 +- .../components/esp32_ble/ble_advertising.cpp | 37 ++++++++++++------- .../components/esp32_ble/ble_advertising.h | 2 +- .../components/esp32_ble_server/__init__.py | 6 ++- .../esp32_ble_server/ble_server.cpp | 8 ++++ .../components/esp32_ble_server/ble_server.h | 6 +++ tests/test2.yaml | 5 +++ 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 0cea8d48ba..49746cf013 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -87,7 +87,7 @@ esphome/components/ens210/* @itn3rd77 esphome/components/esp32/* @esphome/core esphome/components/esp32_ble/* @jesserockz esphome/components/esp32_ble_client/* @jesserockz -esphome/components/esp32_ble_server/* @jesserockz +esphome/components/esp32_ble_server/* @clydebarrow @jesserockz esphome/components/esp32_camera_web_server/* @ayufan esphome/components/esp32_can/* @Sympatron esphome/components/esp32_improv/* @jesserockz diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 2083bf5f08..072bb38c07 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -42,9 +42,15 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) { this->advertising_uuids_.end()); } -void BLEAdvertising::set_manufacturer_data(uint8_t *data, uint16_t size) { - this->advertising_data_.p_manufacturer_data = data; - this->advertising_data_.manufacturer_len = size; +void BLEAdvertising::set_manufacturer_data(const std::vector &data) { + delete[] this->advertising_data_.p_manufacturer_data; + this->advertising_data_.p_manufacturer_data = nullptr; + this->advertising_data_.manufacturer_len = data.size(); + if (!data.empty()) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + this->advertising_data_.p_manufacturer_data = new uint8_t[data.size()]; + memcpy(this->advertising_data_.p_manufacturer_data, data.data(), data.size()); + } } void BLEAdvertising::start() { @@ -74,16 +80,21 @@ void BLEAdvertising::start() { return; } - memcpy(&this->scan_response_data_, &this->advertising_data_, sizeof(esp_ble_adv_data_t)); - this->scan_response_data_.set_scan_rsp = true; - this->scan_response_data_.include_name = true; - this->scan_response_data_.include_txpower = true; - this->scan_response_data_.appearance = 0; - this->scan_response_data_.flag = 0; - err = esp_ble_gap_config_adv_data(&this->scan_response_data_); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err); - return; + if (this->scan_response_) { + memcpy(&this->scan_response_data_, &this->advertising_data_, sizeof(esp_ble_adv_data_t)); + this->scan_response_data_.set_scan_rsp = true; + this->scan_response_data_.include_name = true; + this->scan_response_data_.include_txpower = true; + this->scan_response_data_.min_interval = 0; + this->scan_response_data_.max_interval = 0; + this->scan_response_data_.manufacturer_len = 0; + this->scan_response_data_.appearance = 0; + this->scan_response_data_.flag = 0; + err = esp_ble_gap_config_adv_data(&this->scan_response_data_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err); + return; + } } if (this->advertising_data_.service_uuid_len > 0) { diff --git a/esphome/components/esp32_ble/ble_advertising.h b/esphome/components/esp32_ble/ble_advertising.h index 079bd6c14c..9e4e2b7701 100644 --- a/esphome/components/esp32_ble/ble_advertising.h +++ b/esphome/components/esp32_ble/ble_advertising.h @@ -20,7 +20,7 @@ class BLEAdvertising { void remove_service_uuid(ESPBTUUID uuid); void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; } void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } - void set_manufacturer_data(uint8_t *data, uint16_t size); + void set_manufacturer_data(const std::vector &data); void start(); void stop(); diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index 0ddfa62c1b..5e1ad71501 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -6,11 +6,12 @@ from esphome.core import CORE from esphome.components.esp32 import add_idf_sdkconfig_option AUTO_LOAD = ["esp32_ble"] -CODEOWNERS = ["@jesserockz"] +CODEOWNERS = ["@jesserockz", "@clydebarrow"] CONFLICTS_WITH = ["esp32_ble_beacon"] DEPENDENCIES = ["esp32"] CONF_MANUFACTURER = "manufacturer" +CONF_MANUFACTURER_DATA = "manufacturer_data" esp32_ble_server_ns = cg.esphome_ns.namespace("esp32_ble_server") BLEServer = esp32_ble_server_ns.class_( @@ -27,6 +28,7 @@ CONFIG_SCHEMA = cv.Schema( cv.GenerateID(): cv.declare_id(BLEServer), cv.GenerateID(esp32_ble.CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE), cv.Optional(CONF_MANUFACTURER, default="ESPHome"): cv.string, + cv.Optional(CONF_MANUFACTURER_DATA): cv.Schema([cv.hex_uint8_t]), cv.Optional(CONF_MODEL): cv.string, } ).extend(cv.COMPONENT_SCHEMA) @@ -42,6 +44,8 @@ async def to_code(config): cg.add(var.set_parent(parent)) cg.add(var.set_manufacturer(config[CONF_MANUFACTURER])) + if CONF_MANUFACTURER_DATA in config: + cg.add(var.set_manufacturer_data(config[CONF_MANUFACTURER_DATA])) if CONF_MODEL in config: cg.add(var.set_model(config[CONF_MODEL])) cg.add_define("USE_ESP32_BLE_SERVER") diff --git a/esphome/components/esp32_ble_server/ble_server.cpp b/esphome/components/esp32_ble_server/ble_server.cpp index 7cbf40c076..ca244aba95 100644 --- a/esphome/components/esp32_ble_server/ble_server.cpp +++ b/esphome/components/esp32_ble_server/ble_server.cpp @@ -68,6 +68,7 @@ void BLEServer::loop() { if (this->device_information_service_->is_running()) { this->state_ = RUNNING; this->can_proceed_ = true; + this->restart_advertising_(); ESP_LOGD(TAG, "BLE server setup successfully"); } else if (!this->device_information_service_->is_starting()) { this->device_information_service_->start(); @@ -77,6 +78,13 @@ void BLEServer::loop() { } } +void BLEServer::restart_advertising_() { + if (this->state_ == RUNNING) { + esp32_ble::global_ble->get_advertising()->set_manufacturer_data(this->manufacturer_data_); + esp32_ble::global_ble->get_advertising()->start(); + } +} + bool BLEServer::create_device_characteristics_() { if (this->model_.has_value()) { BLECharacteristic *model = diff --git a/esphome/components/esp32_ble_server/ble_server.h b/esphome/components/esp32_ble_server/ble_server.h index ac759f2dcd..14c88be1a2 100644 --- a/esphome/components/esp32_ble_server/ble_server.h +++ b/esphome/components/esp32_ble_server/ble_server.h @@ -45,6 +45,10 @@ class BLEServer : public Component, public GATTsEventHandler, public Parentedmanufacturer_ = manufacturer; } void set_model(const std::string &model) { this->model_ = model; } + void set_manufacturer_data(const std::vector &data) { + this->manufacturer_data_ = data; + this->restart_advertising_(); + } std::shared_ptr create_service(const uint8_t *uuid, bool advertise = false); std::shared_ptr create_service(uint16_t uuid, bool advertise = false); @@ -63,6 +67,7 @@ class BLEServer : public Component, public GATTsEventHandler, public Parentedclients_.insert(std::pair(conn_id, client)); @@ -73,6 +78,7 @@ class BLEServer : public Component, public GATTsEventHandler, public Parented model_; + std::vector manufacturer_data_; esp_gatt_if_t gatts_if_{0}; bool registered_{false}; diff --git a/tests/test2.yaml b/tests/test2.yaml index 291dc240dc..d1508632b3 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -768,3 +768,8 @@ switch: characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC value: !lambda |- return {0x13, 0x37}; + + +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] From c287e529a88e70dc7ec2fd8115a74d81e8c72fa3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 18 Aug 2023 08:06:21 +1200 Subject: [PATCH 0379/2607] Change haier from AUTO to HEAT_COOL (#5267) --- esphome/components/haier/climate.py | 2 +- esphome/components/haier/haier_base.cpp | 6 +++--- esphome/components/haier/hon_climate.cpp | 4 ++-- esphome/components/haier/smartair2_climate.cpp | 4 ++-- tests/test3.yaml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index fec39d2967..acb079c822 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -89,7 +89,7 @@ SUPPORTED_SWING_MODES_OPTIONS = { SUPPORTED_CLIMATE_MODES_OPTIONS = { "OFF": ClimateMode.CLIMATE_MODE_OFF, # always available - "AUTO": ClimateMode.CLIMATE_MODE_AUTO, # always available + "HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL, # always available "COOL": ClimateMode.CLIMATE_MODE_COOL, "HEAT": ClimateMode.CLIMATE_MODE_HEAT, "DRY": ClimateMode.CLIMATE_MODE_DRY, diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index 5faee5207b..22899b1a70 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -72,7 +72,7 @@ HaierClimateBase::HaierClimateBase() this->traits_ = climate::ClimateTraits(); this->traits_.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, - climate::CLIMATE_MODE_AUTO}); + climate::CLIMATE_MODE_HEAT_COOL}); this->traits_.set_supported_fan_modes( {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH}); this->traits_.set_supported_swing_modes({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, @@ -171,8 +171,8 @@ void HaierClimateBase::set_answer_timeout(uint32_t timeout) { void HaierClimateBase::set_supported_modes(const std::set &modes) { this->traits_.set_supported_modes(modes); - this->traits_.add_supported_mode(climate::CLIMATE_MODE_OFF); // Always available - this->traits_.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Always available + this->traits_.add_supported_mode(climate::CLIMATE_MODE_OFF); // Always available + this->traits_.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL); // Always available } void HaierClimateBase::set_supported_presets(const std::set &presets) { diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index feb1e019d8..d4944410f7 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -458,7 +458,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { case CLIMATE_MODE_OFF: out_data->ac_power = 0; break; - case CLIMATE_MODE_AUTO: + case CLIMATE_MODE_HEAT_COOL: out_data->ac_power = 1; out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::AUTO; out_data->fan_mode = this->other_modes_fan_speed_; @@ -758,7 +758,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * this->mode = CLIMATE_MODE_FAN_ONLY; break; case (uint8_t) hon_protocol::ConditioningMode::AUTO: - this->mode = CLIMATE_MODE_AUTO; + this->mode = CLIMATE_MODE_HEAT_COOL; break; } } diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 8bee37dadf..f29f840088 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -270,7 +270,7 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() { out_data->ac_power = 0; break; - case CLIMATE_MODE_AUTO: + case CLIMATE_MODE_HEAT_COOL: out_data->ac_power = 1; out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::AUTO; out_data->fan_mode = this->other_modes_fan_speed_; @@ -487,7 +487,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin this->mode = CLIMATE_MODE_FAN_ONLY; break; case (uint8_t) smartair2_protocol::ConditioningMode::AUTO: - this->mode = CLIMATE_MODE_AUTO; + this->mode = CLIMATE_MODE_HEAT_COOL; break; } } diff --git a/tests/test3.yaml b/tests/test3.yaml index 5bda0afb1b..471b7d97b6 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -957,7 +957,7 @@ climate: temperature_step: 1 °C supported_modes: - 'OFF' - - AUTO + - HEAT_COOL - COOL - HEAT - DRY From b566c78f001745cb65a94bbd6e3d4efc02dd3b45 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:57:18 +0000 Subject: [PATCH 0380/2607] Fix checksum calculation for sml (#5271) --- esphome/components/sml/sml.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/sml/sml.cpp b/esphome/components/sml/sml.cpp index 87dc25c220..921623d4fd 100644 --- a/esphome/components/sml/sml.cpp +++ b/esphome/components/sml/sml.cpp @@ -100,14 +100,14 @@ bool check_sml_data(const bytes &buffer) { } uint16_t crc_received = (buffer.at(buffer.size() - 2) << 8) | buffer.at(buffer.size() - 1); - uint16_t crc_calculated = crc16(buffer.data(), buffer.size(), 0x6e23, 0x8408, true, true); + uint16_t crc_calculated = crc16(buffer.data(), buffer.size() - 2, 0x6e23, 0x8408, true, true); crc_calculated = (crc_calculated >> 8) | (crc_calculated << 8); if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/X25."); return true; } - crc_calculated = crc16(buffer.data(), buffer.size(), 0xed50, 0x8408); + crc_calculated = crc16(buffer.data(), buffer.size() - 2, 0xed50, 0x8408); if (crc_received == crc_calculated) { ESP_LOGV(TAG, "Checksum verification successful with CRC16/KERMIT."); return true; From 0789657fd52aeacda56790504af4a91ea4034440 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 18 Aug 2023 08:06:21 +1200 Subject: [PATCH 0381/2607] Change haier from AUTO to HEAT_COOL (#5267) --- esphome/components/haier/climate.py | 2 +- esphome/components/haier/haier_base.cpp | 6 +++--- esphome/components/haier/hon_climate.cpp | 4 ++-- esphome/components/haier/smartair2_climate.cpp | 4 ++-- tests/test3.yaml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index fec39d2967..acb079c822 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -89,7 +89,7 @@ SUPPORTED_SWING_MODES_OPTIONS = { SUPPORTED_CLIMATE_MODES_OPTIONS = { "OFF": ClimateMode.CLIMATE_MODE_OFF, # always available - "AUTO": ClimateMode.CLIMATE_MODE_AUTO, # always available + "HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL, # always available "COOL": ClimateMode.CLIMATE_MODE_COOL, "HEAT": ClimateMode.CLIMATE_MODE_HEAT, "DRY": ClimateMode.CLIMATE_MODE_DRY, diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index 5faee5207b..22899b1a70 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -72,7 +72,7 @@ HaierClimateBase::HaierClimateBase() this->traits_ = climate::ClimateTraits(); this->traits_.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, - climate::CLIMATE_MODE_AUTO}); + climate::CLIMATE_MODE_HEAT_COOL}); this->traits_.set_supported_fan_modes( {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH}); this->traits_.set_supported_swing_modes({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, @@ -171,8 +171,8 @@ void HaierClimateBase::set_answer_timeout(uint32_t timeout) { void HaierClimateBase::set_supported_modes(const std::set &modes) { this->traits_.set_supported_modes(modes); - this->traits_.add_supported_mode(climate::CLIMATE_MODE_OFF); // Always available - this->traits_.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Always available + this->traits_.add_supported_mode(climate::CLIMATE_MODE_OFF); // Always available + this->traits_.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL); // Always available } void HaierClimateBase::set_supported_presets(const std::set &presets) { diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index feb1e019d8..d4944410f7 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -458,7 +458,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { case CLIMATE_MODE_OFF: out_data->ac_power = 0; break; - case CLIMATE_MODE_AUTO: + case CLIMATE_MODE_HEAT_COOL: out_data->ac_power = 1; out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::AUTO; out_data->fan_mode = this->other_modes_fan_speed_; @@ -758,7 +758,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * this->mode = CLIMATE_MODE_FAN_ONLY; break; case (uint8_t) hon_protocol::ConditioningMode::AUTO: - this->mode = CLIMATE_MODE_AUTO; + this->mode = CLIMATE_MODE_HEAT_COOL; break; } } diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 8bee37dadf..f29f840088 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -270,7 +270,7 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() { out_data->ac_power = 0; break; - case CLIMATE_MODE_AUTO: + case CLIMATE_MODE_HEAT_COOL: out_data->ac_power = 1; out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::AUTO; out_data->fan_mode = this->other_modes_fan_speed_; @@ -487,7 +487,7 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin this->mode = CLIMATE_MODE_FAN_ONLY; break; case (uint8_t) smartair2_protocol::ConditioningMode::AUTO: - this->mode = CLIMATE_MODE_AUTO; + this->mode = CLIMATE_MODE_HEAT_COOL; break; } } diff --git a/tests/test3.yaml b/tests/test3.yaml index 5bda0afb1b..471b7d97b6 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -957,7 +957,7 @@ climate: temperature_step: 1 °C supported_modes: - 'OFF' - - AUTO + - HEAT_COOL - COOL - HEAT - DRY From 427866420859957be626e86799ac2edae19b333c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 18 Aug 2023 08:12:42 +1200 Subject: [PATCH 0382/2607] Bump version to 2023.8.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f0a6efda94..b8c910cd9e 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.0" +__version__ = "2023.8.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From f16a24ddf460c48176391b06078a70bdedd974b1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 18 Aug 2023 19:13:46 +1200 Subject: [PATCH 0383/2607] Move libcairo to all architectures in docker (#5276) --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4aaea9da89..b942b650cb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -28,14 +28,14 @@ RUN \ git=1:2.30.2-1+deb11u2 \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ - python3-cffi=1.14.5-1; \ + python3-cffi=1.14.5-1 \ + libcairo2=1.16.0-5; \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ apt-get install -y --no-install-recommends \ build-essential=12.9 \ python3-dev=3.9.2-3 \ zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ libjpeg-dev=1:2.0.6-4 \ - libcairo2=1.16.0-5 \ libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ fi; \ rm -rf \ From c47c1a78675ace5a314cddf3ab059684f07d98d8 Mon Sep 17 00:00:00 2001 From: mwolter805 <24851651+mwolter805@users.noreply.github.com> Date: Sun, 20 Aug 2023 12:15:45 -0700 Subject: [PATCH 0384/2607] Resolve offline ESPs in dashboard when using ESPHOME_DASHBOARD_USE_PING=true (#5281) --- esphome/dashboard/dashboard.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index b33cb2df5e..eae004fa09 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -868,9 +868,6 @@ class PingStatusThread(threading.Thread): entries = _list_dashboard_entries() queue = collections.deque() for entry in entries: - if entry.no_mdns is True: - continue - if entry.address is None: PING_RESULT[entry.filename] = None continue From bfdcfa476664ea1dc4c14731a8c6a60dd0d7737c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 21 Aug 2023 06:57:02 +1000 Subject: [PATCH 0385/2607] Align SPI data rates in C++ code with Python (#5284) --- esphome/components/spi/__init__.py | 2 ++ esphome/components/spi/spi.h | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 1528a05734..57a4fa9f4e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -23,7 +23,9 @@ SPI_DATA_RATE_OPTIONS = { 40e6: SPIDataRate.DATA_RATE_40MHZ, 20e6: SPIDataRate.DATA_RATE_20MHZ, 10e6: SPIDataRate.DATA_RATE_10MHZ, + 8e6: SPIDataRate.DATA_RATE_8MHZ, 5e6: SPIDataRate.DATA_RATE_5MHZ, + 4e6: SPIDataRate.DATA_RATE_4MHZ, 2e6: SPIDataRate.DATA_RATE_2MHZ, 1e6: SPIDataRate.DATA_RATE_1MHZ, 2e5: SPIDataRate.DATA_RATE_200KHZ, diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index f19518caae..159d117533 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -63,6 +63,7 @@ enum SPIDataRate : uint32_t { DATA_RATE_1MHZ = 1000000, DATA_RATE_2MHZ = 2000000, DATA_RATE_4MHZ = 4000000, + DATA_RATE_5MHZ = 5000000, DATA_RATE_8MHZ = 8000000, DATA_RATE_10MHZ = 10000000, DATA_RATE_20MHZ = 20000000, From d19bf5d6ee585ec1033c04397dbcadb251d03c42 Mon Sep 17 00:00:00 2001 From: jayme-github Date: Sun, 20 Aug 2023 23:34:50 +0200 Subject: [PATCH 0386/2607] Add support for ESP32-{S2,S3,C3} to debug component (#4731) --- esphome/components/debug/debug_component.cpp | 75 +++++++++++++++++--- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index baf537a12b..5ee1960267 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -12,8 +12,16 @@ #include #include -#include #include +#if defined(USE_ESP32_VARIANT_ESP32) +#include +#elif defined(USE_ESP32_VARIANT_ESP32C3) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S2) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S3) +#include +#endif #endif // USE_ESP32 @@ -105,13 +113,19 @@ void DebugComponent::dump_config() { esp_chip_info_t info; esp_chip_info(&info); const char *model; - switch (info.model) { - case CHIP_ESP32: - model = "ESP32"; - break; - default: - model = "UNKNOWN"; - } +#if defined(USE_ESP32_VARIANT_ESP32) + model = "ESP32"; +#elif defined(USE_ESP32_VARIANT_ESP32C3) + model = "ESP32-C3"; +#elif defined(USE_ESP32_VARIANT_ESP32S2) + model = "ESP32-S2"; +#elif defined(USE_ESP32_VARIANT_ESP32S3) + model = "ESP32-S3"; +#elif defined(USE_ESP32_VARIANT_ESP32H2) + model = "ESP32-H2"; +#else + model = "UNKNOWN"; +#endif std::string features; if (info.features & CHIP_FEATURE_EMB_FLASH) { features += "EMB_FLASH,"; @@ -153,18 +167,26 @@ void DebugComponent::dump_config() { case POWERON_RESET: reset_reason = "Power On Reset"; break; +#if defined(USE_ESP32_VARIANT_ESP32) case SW_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_SYS_RESET: +#endif reset_reason = "Software Reset Digital Core"; break; +#if defined(USE_ESP32_VARIANT_ESP32) case OWDT_RESET: reset_reason = "Watch Dog Reset Digital Core"; break; +#endif case DEEPSLEEP_RESET: reset_reason = "Deep Sleep Reset Digital Core"; break; +#if defined(USE_ESP32_VARIANT_ESP32) case SDIO_RESET: reset_reason = "SLC Module Reset Digital Core"; break; +#endif case TG0WDT_SYS_RESET: reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; break; @@ -177,24 +199,61 @@ void DebugComponent::dump_config() { case INTRUSION_RESET: reset_reason = "Intrusion Reset CPU"; break; +#if defined(USE_ESP32_VARIANT_ESP32) case TGWDT_CPU_RESET: reset_reason = "Timer Group Reset CPU"; break; +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG0WDT_CPU_RESET: + reset_reason = "Timer Group 0 Reset CPU"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32) case SW_CPU_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_CPU_RESET: +#endif reset_reason = "Software Reset CPU"; break; case RTCWDT_CPU_RESET: reset_reason = "RTC Watch Dog Reset CPU"; break; +#if defined(USE_ESP32_VARIANT_ESP32) case EXT_CPU_RESET: reset_reason = "External CPU Reset"; break; +#endif case RTCWDT_BROWN_OUT_RESET: reset_reason = "Voltage Unstable Reset"; break; case RTCWDT_RTC_RESET: reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; break; +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG1WDT_CPU_RESET: + reset_reason = "Timer Group 1 Reset CPU"; + break; + case SUPER_WDT_RESET: + reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; + break; + case GLITCH_RTC_RESET: + reset_reason = "Glitch Reset Digital Core And RTC Module"; + break; + case EFUSE_RESET: + reset_reason = "eFuse Reset Digital Core"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) + case USB_UART_CHIP_RESET: + reset_reason = "USB UART Reset Digital Core"; + break; + case USB_JTAG_CHIP_RESET: + reset_reason = "USB JTAG Reset Digital Core"; + break; + case POWER_GLITCH_RESET: + reset_reason = "Power Glitch Reset Digital Core And RTC Module"; + break; +#endif default: reset_reason = "Unknown Reset Reason"; } From fe7893d1b3178912ad8e016d0ffba2bf6836928d Mon Sep 17 00:00:00 2001 From: Austin Date: Sun, 20 Aug 2023 17:42:03 -0400 Subject: [PATCH 0387/2607] Support for ESP32-C2 & ESP32-C6 (#4377) Co-authored-by: Stijn Tintel --- esphome/components/adc/__init__.py | 18 +++++++ esphome/components/deep_sleep/__init__.py | 4 ++ esphome/components/esp32/__init__.py | 1 - esphome/components/esp32/const.py | 6 +++ esphome/components/esp32/gpio.py | 12 +++++ esphome/components/esp32/gpio_esp32_c2.py | 37 ++++++++++++++ esphome/components/esp32/gpio_esp32_c6.py | 50 +++++++++++++++++++ .../components/esp32_rmt_led_strip/light.py | 1 + esphome/components/logger/__init__.py | 4 ++ esphome/components/logger/logger.cpp | 16 +++--- esphome/components/logger/logger.h | 5 +- esphome/components/spi/spi.cpp | 3 +- 12 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 esphome/components/esp32/gpio_esp32_c2.py create mode 100644 esphome/components/esp32/gpio_esp32_c6.py diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 99dad68501..015d6edd21 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -7,7 +7,9 @@ from esphome.core import CORE from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( VARIANT_ESP32, + VARIANT_ESP32C2, VARIANT_ESP32C3, + VARIANT_ESP32C6, VARIANT_ESP32H2, VARIANT_ESP32S2, VARIANT_ESP32S3, @@ -70,6 +72,22 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = { 3: adc1_channel_t.ADC1_CHANNEL_3, 4: adc1_channel_t.ADC1_CHANNEL_4, }, + VARIANT_ESP32C2: { + 0: adc1_channel_t.ADC1_CHANNEL_0, + 1: adc1_channel_t.ADC1_CHANNEL_1, + 2: adc1_channel_t.ADC1_CHANNEL_2, + 3: adc1_channel_t.ADC1_CHANNEL_3, + 4: adc1_channel_t.ADC1_CHANNEL_4, + }, + VARIANT_ESP32C6: { + 0: adc1_channel_t.ADC1_CHANNEL_0, + 1: adc1_channel_t.ADC1_CHANNEL_1, + 2: adc1_channel_t.ADC1_CHANNEL_2, + 3: adc1_channel_t.ADC1_CHANNEL_3, + 4: adc1_channel_t.ADC1_CHANNEL_4, + 5: adc1_channel_t.ADC1_CHANNEL_5, + 6: adc1_channel_t.ADC1_CHANNEL_6, + }, VARIANT_ESP32H2: { 0: adc1_channel_t.ADC1_CHANNEL_0, 1: adc1_channel_t.ADC1_CHANNEL_1, diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index bbd10d58c5..6e71f7bbf6 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -22,6 +22,8 @@ from esphome.components.esp32.const import ( VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3, + VARIANT_ESP32C2, + VARIANT_ESP32C6, ) WAKEUP_PINS = { @@ -94,6 +96,8 @@ WAKEUP_PINS = { 20, 21, ], + VARIANT_ESP32C2: [0, 1, 2, 3, 4, 5], + VARIANT_ESP32C6: [0, 1, 2, 3, 4, 5, 6, 7], } diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index aa9f8cd66e..d158528066 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -44,7 +44,6 @@ from .const import ( # noqa KEY_SDKCONFIG_OPTIONS, KEY_SUBMODULES, KEY_VARIANT, - VARIANT_ESP32C3, VARIANT_FRIENDLY, VARIANTS, ) diff --git a/esphome/components/esp32/const.py b/esphome/components/esp32/const.py index 698310dacb..9e997bdeb5 100644 --- a/esphome/components/esp32/const.py +++ b/esphome/components/esp32/const.py @@ -14,13 +14,17 @@ KEY_SUBMODULES = "submodules" VARIANT_ESP32 = "ESP32" VARIANT_ESP32S2 = "ESP32S2" VARIANT_ESP32S3 = "ESP32S3" +VARIANT_ESP32C2 = "ESP32C2" VARIANT_ESP32C3 = "ESP32C3" +VARIANT_ESP32C6 = "ESP32C6" VARIANT_ESP32H2 = "ESP32H2" VARIANTS = [ VARIANT_ESP32, VARIANT_ESP32S2, VARIANT_ESP32S3, + VARIANT_ESP32C2, VARIANT_ESP32C3, + VARIANT_ESP32C6, VARIANT_ESP32H2, ] @@ -28,7 +32,9 @@ VARIANT_FRIENDLY = { VARIANT_ESP32: "ESP32", VARIANT_ESP32S2: "ESP32-S2", VARIANT_ESP32S3: "ESP32-S3", + VARIANT_ESP32C2: "ESP32-C2", VARIANT_ESP32C3: "ESP32-C3", + VARIANT_ESP32C6: "ESP32-C6", VARIANT_ESP32H2: "ESP32-H2", } diff --git a/esphome/components/esp32/gpio.py b/esphome/components/esp32/gpio.py index 7848d1d552..6950cd58a0 100644 --- a/esphome/components/esp32/gpio.py +++ b/esphome/components/esp32/gpio.py @@ -26,6 +26,8 @@ from .const import ( VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3, + VARIANT_ESP32C2, + VARIANT_ESP32C6, VARIANT_ESP32H2, esp32_ns, ) @@ -35,6 +37,8 @@ from .gpio_esp32 import esp32_validate_gpio_pin, esp32_validate_supports from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports +from .gpio_esp32_c2 import esp32_c2_validate_gpio_pin, esp32_c2_validate_supports +from .gpio_esp32_c6 import esp32_c6_validate_gpio_pin, esp32_c6_validate_supports from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports @@ -95,6 +99,14 @@ _esp32_validations = { pin_validation=esp32_s3_validate_gpio_pin, usage_validation=esp32_s3_validate_supports, ), + VARIANT_ESP32C2: ESP32ValidationFunctions( + pin_validation=esp32_c2_validate_gpio_pin, + usage_validation=esp32_c2_validate_supports, + ), + VARIANT_ESP32C6: ESP32ValidationFunctions( + pin_validation=esp32_c6_validate_gpio_pin, + usage_validation=esp32_c6_validate_supports, + ), VARIANT_ESP32H2: ESP32ValidationFunctions( pin_validation=esp32_h2_validate_gpio_pin, usage_validation=esp32_h2_validate_supports, diff --git a/esphome/components/esp32/gpio_esp32_c2.py b/esphome/components/esp32/gpio_esp32_c2.py new file mode 100644 index 0000000000..c444f804a3 --- /dev/null +++ b/esphome/components/esp32/gpio_esp32_c2.py @@ -0,0 +1,37 @@ +import logging + +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER + +import esphome.config_validation as cv + +_ESP32C2_STRAPPING_PINS = {8, 9} + +_LOGGER = logging.getLogger(__name__) + + +def esp32_c2_validate_gpio_pin(value): + if value < 0 or value > 20: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-20)") + if value in _ESP32C2_STRAPPING_PINS: + _LOGGER.warning( + "GPIO%d is a Strapping PIN and should be avoided.\n" + "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" + "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", + value, + ) + + return value + + +def esp32_c2_validate_supports(value): + num = value[CONF_NUMBER] + mode = value[CONF_MODE] + is_input = mode[CONF_INPUT] + + if num < 0 or num > 20: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-20)") + + if is_input: + # All ESP32 pins support input mode + pass + return value diff --git a/esphome/components/esp32/gpio_esp32_c6.py b/esphome/components/esp32/gpio_esp32_c6.py new file mode 100644 index 0000000000..b26b6bc6b4 --- /dev/null +++ b/esphome/components/esp32/gpio_esp32_c6.py @@ -0,0 +1,50 @@ +import logging + +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER + +import esphome.config_validation as cv + +_ESP32C6_SPI_PSRAM_PINS = { + 24: "SPICS0", + 25: "SPIQ", + 26: "SPIWP", + 27: "VDD_SPI", + 28: "SPIHD", + 29: "SPICLK", + 30: "SPID", +} + +_ESP32C6_STRAPPING_PINS = {8, 9, 15} + +_LOGGER = logging.getLogger(__name__) + + +def esp32_c6_validate_gpio_pin(value): + if value < 0 or value > 23: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-23)") + if value in _ESP32C6_SPI_PSRAM_PINS: + raise cv.Invalid( + f"This pin cannot be used on ESP32-C6s and is already used by the SPI/PSRAM interface (function: {_ESP32C6_SPI_PSRAM_PINS[value]})" + ) + if value in _ESP32C6_STRAPPING_PINS: + _LOGGER.warning( + "GPIO%d is a Strapping PIN and should be avoided.\n" + "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" + "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", + value, + ) + + return value + + +def esp32_c6_validate_supports(value): + num = value[CONF_NUMBER] + mode = value[CONF_MODE] + is_input = mode[CONF_INPUT] + + if num < 0 or num > 23: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-23)") + if is_input: + # All ESP32 pins support input mode + pass + return value diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 3ca758c1e1..5b65ecdabf 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -63,6 +63,7 @@ RMT_CHANNELS = { esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3], esp32.const.VARIANT_ESP32C3: [0, 1], + esp32.const.VARIANT_ESP32C6: [0, 1], } diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index af96b03c8e..5c87bb9d91 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -28,6 +28,8 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32C3, VARIANT_ESP32S3, + VARIANT_ESP32C2, + VARIANT_ESP32C6, ) CODEOWNERS = ["@esphome/core"] @@ -74,6 +76,8 @@ UART_SELECTION_ESP32 = { VARIANT_ESP32S2: [UART0, UART1, USB_CDC], VARIANT_ESP32S3: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG], VARIANT_ESP32C3: [UART0, UART1, USB_SERIAL_JTAG], + VARIANT_ESP32C2: [UART0, UART1], + VARIANT_ESP32C6: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG], } UART_SELECTION_ESP8266 = [UART0, UART0_SWAP, UART1] diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index ca4cc64007..86ebb53764 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -120,7 +120,7 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { if ( #if defined(USE_ESP32_VARIANT_ESP32S2) uart_ == UART_SELECTION_USB_CDC -#elif defined(USE_ESP32_VARIANT_ESP32C3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) uart_ == UART_SELECTION_USB_SERIAL_JTAG #elif defined(USE_ESP32_VARIANT_ESP32S3) uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG @@ -191,8 +191,8 @@ void Logger::pre_setup() { Serial1.setDebugOutput(ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE); #endif break; -#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32S2) && \ - !defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) case UART_SELECTION_UART2: this->hw_serial_ = &Serial2; Serial2.begin(this->baud_rate_); @@ -215,7 +215,8 @@ void Logger::pre_setup() { case UART_SELECTION_UART1: uart_num_ = UART_NUM_1; break; -#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) case UART_SELECTION_UART2: uart_num_ = UART_NUM_2; break; @@ -225,11 +226,11 @@ void Logger::pre_setup() { uart_num_ = -1; break; #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) case UART_SELECTION_USB_SERIAL_JTAG: uart_num_ = -1; break; -#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 +#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 } if (uart_num_ >= 0) { uart_config_t uart_config{}; @@ -278,7 +279,8 @@ const char *const LOG_LEVELS[] = {"NONE", "ERROR", "WARN", "INFO", "CONFIG", "DE #ifdef USE_ESP32 const char *const UART_SELECTIONS[] = { "UART0", "UART1", -#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) "UART2", #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 #if defined(USE_ESP_IDF) diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index 54a5236cd8..47cde45c29 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -34,14 +34,15 @@ enum UARTSelection { UART_SELECTION_UART0 = 0, UART_SELECTION_UART1, #if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) UART_SELECTION_UART2, #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 #ifdef USE_ESP_IDF #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) UART_SELECTION_USB_CDC, #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) UART_SELECTION_USB_SERIAL_JTAG, #endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 #endif // USE_ESP_IDF diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index c9bb075fb5..33630897f6 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -76,7 +76,8 @@ void SPIComponent::setup() { if (spi_bus_num == 0) { this->hw_spi_ = &SPI; } else { -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C6) this->hw_spi_ = new SPIClass(FSPI); // NOLINT(cppcoreguidelines-owning-memory) #else this->hw_spi_ = new SPIClass(HSPI); // NOLINT(cppcoreguidelines-owning-memory) From da8afd36b26a23eed3d1863b4f94fcdad40366ea Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:16:14 +1200 Subject: [PATCH 0388/2607] Change htu21d sensors from required to optional (#5285) --- esphome/components/htu21d/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 37422f0329..2ed318f1c9 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -23,13 +23,13 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(HTU21DComponent), - cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, accuracy_decimals=1, device_class=DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Required(CONF_HUMIDITY): sensor.sensor_schema( + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, accuracy_decimals=1, device_class=DEVICE_CLASS_HUMIDITY, From 03ab23fec8c66680c38b1286b26c25f7805fd7e4 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:17:22 +1000 Subject: [PATCH 0389/2607] Reserve keyword "clock" (#5279) --- esphome/config_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index cf0b1d3aca..3720757828 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -125,6 +125,7 @@ RESERVED_IDS = [ "char16_t", "char32_t", "class", + "clock", "compl", "concept", "const", From 04433103853f0430e1e73a0817661f729bdd2792 Mon Sep 17 00:00:00 2001 From: Rob Deutsch Date: Mon, 21 Aug 2023 10:20:00 +1000 Subject: [PATCH 0390/2607] Bump arduino-heatpumpir to v1.0.23 (#5269) --- esphome/components/heatpumpir/climate.py | 3 ++- esphome/components/heatpumpir/heatpumpir.cpp | 1 + esphome/components/heatpumpir/heatpumpir.h | 1 + platformio.ini | 2 +- tests/test1.yaml | 7 +++++++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index cc8e75dcbd..a043b4a61b 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -33,6 +33,7 @@ PROTOCOLS = { "greeya": Protocol.PROTOCOL_GREEYAA, "greeyan": Protocol.PROTOCOL_GREEYAN, "greeyac": Protocol.PROTOCOL_GREEYAC, + "greeyt": Protocol.PROTOCOL_GREEYT, "hisense_aud": Protocol.PROTOCOL_HISENSE_AUD, "hitachi": Protocol.PROTOCOL_HITACHI, "hyundai": Protocol.PROTOCOL_HYUNDAI, @@ -115,7 +116,7 @@ def to_code(config): cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE])) cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) - cg.add_library("tonia/HeatpumpIR", "1.0.20") + cg.add_library("tonia/HeatpumpIR", "1.0.23") if CORE.is_esp8266 or CORE.is_esp32: cg.add_library("crankyoldgit/IRremoteESP8266", "2.7.12") diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index bed1dc76c0..5e7237b63c 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -27,6 +27,7 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_GREEYAA, []() { return new GreeYAAHeatpumpIR(); }}, // NOLINT {PROTOCOL_GREEYAN, []() { return new GreeYANHeatpumpIR(); }}, // NOLINT {PROTOCOL_GREEYAC, []() { return new GreeYACHeatpumpIR(); }}, // NOLINT + {PROTOCOL_GREEYT, []() { return new GreeYTHeatpumpIR(); }}, // NOLINT {PROTOCOL_HISENSE_AUD, []() { return new HisenseHeatpumpIR(); }}, // NOLINT {PROTOCOL_HITACHI, []() { return new HitachiHeatpumpIR(); }}, // NOLINT {PROTOCOL_HYUNDAI, []() { return new HyundaiHeatpumpIR(); }}, // NOLINT diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index c60b944111..e8b03b4c26 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -27,6 +27,7 @@ enum Protocol { PROTOCOL_GREEYAA, PROTOCOL_GREEYAN, PROTOCOL_GREEYAC, + PROTOCOL_GREEYT, PROTOCOL_HISENSE_AUD, PROTOCOL_HITACHI, PROTOCOL_HYUNDAI, diff --git a/platformio.ini b/platformio.ini index 5da3b9f978..6341d7bde5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -64,7 +64,7 @@ lib_deps = glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr dudanov/MideaUART@1.1.8 ; midea - tonia/HeatpumpIR@1.0.20 ; heatpumpir + tonia/HeatpumpIR@1.0.23 ; heatpumpir build_flags = ${common.build_flags} -DUSE_ARDUINO diff --git a/tests/test1.yaml b/tests/test1.yaml index 80cd9e3987..3a6cfa0c4b 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2299,6 +2299,13 @@ climate: name: HeatpumpIR Climate min_temperature: 18 max_temperature: 30 + - platform: heatpumpir + protocol: greeyt + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 - platform: midea_ir name: Midea IR use_fahrenheit: true From 5e19a3b892b4580cf5c9457dc227da483892e78e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 18 Aug 2023 19:13:46 +1200 Subject: [PATCH 0391/2607] Move libcairo to all architectures in docker (#5276) --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4aaea9da89..b942b650cb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -28,14 +28,14 @@ RUN \ git=1:2.30.2-1+deb11u2 \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ - python3-cffi=1.14.5-1; \ + python3-cffi=1.14.5-1 \ + libcairo2=1.16.0-5; \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ apt-get install -y --no-install-recommends \ build-essential=12.9 \ python3-dev=3.9.2-3 \ zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ libjpeg-dev=1:2.0.6-4 \ - libcairo2=1.16.0-5 \ libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ fi; \ rm -rf \ From e600784ebfed1ff2a64e28d6a1bb3979915c3d90 Mon Sep 17 00:00:00 2001 From: mwolter805 <24851651+mwolter805@users.noreply.github.com> Date: Sun, 20 Aug 2023 12:15:45 -0700 Subject: [PATCH 0392/2607] Resolve offline ESPs in dashboard when using ESPHOME_DASHBOARD_USE_PING=true (#5281) --- esphome/dashboard/dashboard.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index b33cb2df5e..eae004fa09 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -868,9 +868,6 @@ class PingStatusThread(threading.Thread): entries = _list_dashboard_entries() queue = collections.deque() for entry in entries: - if entry.no_mdns is True: - continue - if entry.address is None: PING_RESULT[entry.filename] = None continue From 02a71cb6a758e25a5587b587e205203df372150f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 21 Aug 2023 06:57:02 +1000 Subject: [PATCH 0393/2607] Align SPI data rates in C++ code with Python (#5284) --- esphome/components/spi/__init__.py | 2 ++ esphome/components/spi/spi.h | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 1528a05734..57a4fa9f4e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -23,7 +23,9 @@ SPI_DATA_RATE_OPTIONS = { 40e6: SPIDataRate.DATA_RATE_40MHZ, 20e6: SPIDataRate.DATA_RATE_20MHZ, 10e6: SPIDataRate.DATA_RATE_10MHZ, + 8e6: SPIDataRate.DATA_RATE_8MHZ, 5e6: SPIDataRate.DATA_RATE_5MHZ, + 4e6: SPIDataRate.DATA_RATE_4MHZ, 2e6: SPIDataRate.DATA_RATE_2MHZ, 1e6: SPIDataRate.DATA_RATE_1MHZ, 2e5: SPIDataRate.DATA_RATE_200KHZ, diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index f19518caae..159d117533 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -63,6 +63,7 @@ enum SPIDataRate : uint32_t { DATA_RATE_1MHZ = 1000000, DATA_RATE_2MHZ = 2000000, DATA_RATE_4MHZ = 4000000, + DATA_RATE_5MHZ = 5000000, DATA_RATE_8MHZ = 8000000, DATA_RATE_10MHZ = 10000000, DATA_RATE_20MHZ = 20000000, From e44a60e8141c90cbff263bdb0c3c6e6a7027fc22 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:16:14 +1200 Subject: [PATCH 0394/2607] Change htu21d sensors from required to optional (#5285) --- esphome/components/htu21d/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 37422f0329..2ed318f1c9 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -23,13 +23,13 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(HTU21DComponent), - cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, accuracy_decimals=1, device_class=DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Required(CONF_HUMIDITY): sensor.sensor_schema( + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, accuracy_decimals=1, device_class=DEVICE_CLASS_HUMIDITY, From d2bccbe8ac0d0ca62024f1faa7d22d7ae47907f5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:17:22 +1000 Subject: [PATCH 0395/2607] Reserve keyword "clock" (#5279) --- esphome/config_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index cf0b1d3aca..3720757828 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -125,6 +125,7 @@ RESERVED_IDS = [ "char16_t", "char32_t", "class", + "clock", "compl", "concept", "const", From 9fb8e9edef1ee65bf9b615ab69a5f61bcf2c4815 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:33:49 +1200 Subject: [PATCH 0396/2607] Bump version to 2023.8.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index b8c910cd9e..c22dde6986 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.1" +__version__ = "2023.8.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 2a48b810a4bed9853b899d5fa7e7efaf6f76ef2d Mon Sep 17 00:00:00 2001 From: Stefan Rado Date: Mon, 21 Aug 2023 02:35:13 +0200 Subject: [PATCH 0397/2607] Fix equality check when setting current-based cover position (#5167) --- esphome/components/current_based/current_based_cover.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/current_based/current_based_cover.cpp b/esphome/components/current_based/current_based_cover.cpp index ff5ad43997..17f67002a3 100644 --- a/esphome/components/current_based/current_based_cover.cpp +++ b/esphome/components/current_based/current_based_cover.cpp @@ -38,7 +38,7 @@ void CurrentBasedCover::control(const CoverCall &call) { } if (call.get_position().has_value()) { auto pos = *call.get_position(); - if (pos == this->position) { + if (fabsf(this->position - pos) < 0.01) { // already at target } else { auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; From f814b6d47c6de9cef53b374c65e3671d2e10a879 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 04:27:17 +0000 Subject: [PATCH 0398/2607] Bump platformio from 6.1.9 to 6.1.10 (#5237) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- docker/Dockerfile | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b942b650cb..a590445de9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -61,7 +61,7 @@ RUN \ # Ubuntu python3-pip is missing wheel pip3 install --no-cache-dir \ wheel==0.37.1 \ - platformio==6.1.7 \ + platformio==6.1.10 \ # Change some platformio settings && platformio settings set enable_telemetry No \ && platformio settings set check_platformio_interval 1000000 \ diff --git a/requirements.txt b/requirements.txt index 4a046014d6..dccb418e8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ tornado==6.3.2 tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.9 # When updating platformio, also update Dockerfile +platformio==6.1.10 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.7 esphome-dashboard==20230711.0 From 11ed2d5f1830a475dc7325f4c2e678b316bd14af Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 22 Aug 2023 23:13:38 +0100 Subject: [PATCH 0399/2607] Add Invert method for SSD1306 (#5292) --- esphome/components/ssd1306_base/ssd1306_base.cpp | 8 +++++++- esphome/components/ssd1306_base/ssd1306_base.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/ssd1306_base/ssd1306_base.cpp b/esphome/components/ssd1306_base/ssd1306_base.cpp index 730e1c8f35..3cacd473d1 100644 --- a/esphome/components/ssd1306_base/ssd1306_base.cpp +++ b/esphome/components/ssd1306_base/ssd1306_base.cpp @@ -132,7 +132,7 @@ void SSD1306::setup() { this->command(SSD1306_COMMAND_DISPLAY_ALL_ON_RESUME); // Inverse display mode (0xA6, 0xA7) - this->command(SSD1306_COMMAND_NORMAL_DISPLAY | this->invert_); + this->set_invert(this->invert_); // Disable scrolling mode (0x2E) this->command(SSD1306_COMMAND_DEACTIVATE_SCROLL); @@ -190,6 +190,12 @@ void SSD1306::update() { this->do_update_(); this->display(); } + +void SSD1306::set_invert(bool invert) { + this->invert_ = invert; + // Inverse display mode (0xA6, 0xA7) + this->command(SSD1306_COMMAND_NORMAL_DISPLAY | this->invert_); +} void SSD1306::set_contrast(float contrast) { // validation this->contrast_ = clamp(contrast, 0.0F, 1.0F); diff --git a/esphome/components/ssd1306_base/ssd1306_base.h b/esphome/components/ssd1306_base/ssd1306_base.h index 7402ae3af2..4b0e9bb80e 100644 --- a/esphome/components/ssd1306_base/ssd1306_base.h +++ b/esphome/components/ssd1306_base/ssd1306_base.h @@ -43,6 +43,7 @@ class SSD1306 : public PollingComponent, public display::DisplayBuffer { void init_offset_x(uint8_t offset_x) { this->offset_x_ = offset_x; } void init_offset_y(uint8_t offset_y) { this->offset_y_ = offset_y; } void init_invert(bool invert) { this->invert_ = invert; } + void set_invert(bool invert); bool is_on(); void turn_on(); void turn_off(); From b20bae23ccac3903239ca68bfb3a4add25b7b44d Mon Sep 17 00:00:00 2001 From: Sebastian Rasor <92653912+sebastianrasor@users.noreply.github.com> Date: Tue, 22 Aug 2023 20:01:34 -0500 Subject: [PATCH 0400/2607] Introduce cv.temperature_delta and fix problematic thermostat configuration behavior (#5297) --- esphome/components/thermostat/climate.py | 14 +++++++------- esphome/config_validation.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/esphome/components/thermostat/climate.py b/esphome/components/thermostat/climate.py index 9a57f6a337..cca46609db 100644 --- a/esphome/components/thermostat/climate.py +++ b/esphome/components/thermostat/climate.py @@ -591,11 +591,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature, cv.Optional( CONF_SET_POINT_MINIMUM_DIFFERENTIAL, default=0.5 - ): cv.temperature, - cv.Optional(CONF_COOL_DEADBAND, default=0.5): cv.temperature, - cv.Optional(CONF_COOL_OVERRUN, default=0.5): cv.temperature, - cv.Optional(CONF_HEAT_DEADBAND, default=0.5): cv.temperature, - cv.Optional(CONF_HEAT_OVERRUN, default=0.5): cv.temperature, + ): cv.temperature_delta, + cv.Optional(CONF_COOL_DEADBAND, default=0.5): cv.temperature_delta, + cv.Optional(CONF_COOL_OVERRUN, default=0.5): cv.temperature_delta, + cv.Optional(CONF_HEAT_DEADBAND, default=0.5): cv.temperature_delta, + cv.Optional(CONF_HEAT_OVERRUN, default=0.5): cv.temperature_delta, cv.Optional(CONF_MAX_COOLING_RUN_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MAX_HEATING_RUN_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MIN_COOLING_OFF_TIME): cv.positive_time_period_seconds, @@ -608,8 +608,8 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MIN_HEATING_OFF_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MIN_HEATING_RUN_TIME): cv.positive_time_period_seconds, cv.Required(CONF_MIN_IDLE_TIME): cv.positive_time_period_seconds, - cv.Optional(CONF_SUPPLEMENTAL_COOLING_DELTA): cv.temperature, - cv.Optional(CONF_SUPPLEMENTAL_HEATING_DELTA): cv.temperature, + cv.Optional(CONF_SUPPLEMENTAL_COOLING_DELTA): cv.temperature_delta, + cv.Optional(CONF_SUPPLEMENTAL_HEATING_DELTA): cv.temperature_delta, cv.Optional( CONF_FAN_ONLY_ACTION_USES_FAN_MODE_TIMER, default=False ): cv.boolean, diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 3720757828..ed87e98078 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -929,6 +929,27 @@ def temperature(value): raise err +def temperature_delta(value): + err = None + try: + return _temperature_c(value) + except Invalid as orig_err: + err = orig_err + + try: + return _temperature_k(value) + except Invalid: + pass + + try: + fahrenheit = _temperature_f(value) + return fahrenheit * (5 / 9) + except Invalid: + pass + + raise err + + _color_temperature_mireds = float_with_unit("Color Temperature", r"(mireds|Mireds)") _color_temperature_kelvin = float_with_unit("Color Temperature", r"(K|Kelvin)") From c4adb30ab2b355a28c6977088a68c59d95ea1c5e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 29 Aug 2023 00:11:58 -0500 Subject: [PATCH 0401/2607] Update PSRAM config params for IDF4+ (#5298) --- esphome/components/psram/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index ac6d034514..9399e51ded 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant from esphome.core import CORE from esphome.const import ( CONF_ID, @@ -21,7 +21,11 @@ async def to_code(config): cg.add_build_flag("-DBOARD_HAS_PSRAM") if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_ESP32_SPIRAM_SUPPORT", True) + add_idf_sdkconfig_option( + f"CONFIG_{get_esp32_variant().upper()}_SPIRAM_SUPPORT", True + ) + add_idf_sdkconfig_option("CONFIG_SPIRAM", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_USE", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_USE_CAPS_ALLOC", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_IGNORE_NOTFOUND", True) From 45879e3100c27c49ff103e70e9e4d12a8cdac713 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 29 Aug 2023 00:25:43 -0500 Subject: [PATCH 0402/2607] Fix legacy zeroconf record update method (#5294) --- esphome/zeroconf.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/esphome/zeroconf.py b/esphome/zeroconf.py index b0dddfd152..924d7253df 100644 --- a/esphome/zeroconf.py +++ b/esphome/zeroconf.py @@ -1,19 +1,19 @@ +import logging import socket import threading import time -from typing import Optional -import logging from dataclasses import dataclass +from typing import Optional from zeroconf import ( DNSAddress, DNSOutgoing, - DNSRecord, DNSQuestion, + RecordUpdate, RecordUpdateListener, - Zeroconf, ServiceBrowser, ServiceStateChange, + Zeroconf, current_time_millis, ) @@ -24,17 +24,28 @@ _LOGGER = logging.getLogger(__name__) class HostResolver(RecordUpdateListener): + """Resolve a host name to an IP address.""" + def __init__(self, name: str): self.name = name self.address: Optional[bytes] = None - def update_record(self, zc: Zeroconf, now: float, record: DNSRecord) -> None: - if record is None: - return - if record.type == _TYPE_A: - assert isinstance(record, DNSAddress) - if record.name == self.name: - self.address = record.address + def async_update_records( + self, zc: Zeroconf, now: float, records: list[RecordUpdate] + ) -> None: + """Update multiple records in one shot. + + This will run in zeroconf's event loop thread so it + must be thread-safe. + """ + for record_update in records: + record, _ = record_update + if record is None: + continue + if record.type == _TYPE_A: + assert isinstance(record, DNSAddress) + if record.name == self.name: + self.address = record.address def request(self, zc: Zeroconf, timeout: float) -> bool: now = time.time() From 45152ad55edf0d05500e28d5aaa590889b4c897a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 19:04:37 +1200 Subject: [PATCH 0403/2607] Bump zeroconf from 0.80.0 to 0.86.0 (#5308) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dccb418e8d..b23964828c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.80.0 +zeroconf==0.86.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 78cb0986914aa3763058f9f46175782ce4218bf2 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 29 Aug 2023 03:50:29 -0500 Subject: [PATCH 0404/2607] Add PSRAM mode and speed config (#5312) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/psram/__init__.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index 9399e51ded..f7a2ef7b92 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -4,6 +4,8 @@ from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant from esphome.core import CORE from esphome.const import ( CONF_ID, + CONF_MODE, + CONF_SPEED, ) CODEOWNERS = ["@esphome/core"] @@ -11,8 +13,26 @@ CODEOWNERS = ["@esphome/core"] psram_ns = cg.esphome_ns.namespace("psram") PsramComponent = psram_ns.class_("PsramComponent", cg.Component) +SPIRAM_MODES = { + "quad": "CONFIG_SPIRAM_MODE_QUAD", + "octal": "CONFIG_SPIRAM_MODE_OCT", +} + +SPIRAM_SPEEDS = { + 40e6: "CONFIG_SPIRAM_SPEED_40M", + 80e6: "CONFIG_SPIRAM_SPEED_80M", + 120e6: "CONFIG_SPIRAM_SPEED_120M", +} + CONFIG_SCHEMA = cv.All( - cv.Schema({cv.GenerateID(): cv.declare_id(PsramComponent)}), cv.only_on_esp32 + cv.Schema( + { + cv.GenerateID(): cv.declare_id(PsramComponent), + cv.Optional(CONF_MODE): cv.enum(SPIRAM_MODES, lower=True), + cv.Optional(CONF_SPEED): cv.All(cv.frequency, cv.one_of(*SPIRAM_SPEEDS)), + } + ), + cv.only_on_esp32, ) @@ -29,5 +49,10 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_SPIRAM_USE_CAPS_ALLOC", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_IGNORE_NOTFOUND", True) + if CONF_MODE in config: + add_idf_sdkconfig_option(f"{SPIRAM_MODES[config[CONF_MODE]]}", True) + if CONF_SPEED in config: + add_idf_sdkconfig_option(f"{SPIRAM_SPEEDS[config[CONF_SPEED]]}", True) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) From cdb67fc90e974cca8d463b7c466c3ca29225956e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 31 Aug 2023 19:12:25 +1000 Subject: [PATCH 0405/2607] Add extra SLPOUT for waking up some ST7789 chips (#5319) --- esphome/components/st7789v/st7789v.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index 0e7c9b9123..c1e3f07e38 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -19,6 +19,7 @@ void ST7789V::setup() { this->write_command_(ST7789_SLPOUT); // Sleep out delay(120); // NOLINT + this->write_command_(ST7789_SLPOUT); // this->write_command_(ST7789_NORON); // Normal display mode on From 01f6791d1c1fc2efd64575784663643f64c5f6bf Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 1 Sep 2023 09:43:24 +1000 Subject: [PATCH 0406/2607] 7789 controller fixes take 2 (#5320) * Fix 7789 clock mode and increase clock rate. * Reverse change from dev. * Speed up 8 bit color. * Tweak buffer size --- esphome/components/st7789v/st7789v.cpp | 17 +++++++++++++---- esphome/components/st7789v/st7789v.h | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index c1e3f07e38..f29182e634 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -5,6 +5,7 @@ namespace esphome { namespace st7789v { static const char *const TAG = "st7789v"; +static const size_t TEMP_BUFFER_SIZE = 128; void ST7789V::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI ST7789V..."); @@ -19,7 +20,6 @@ void ST7789V::setup() { this->write_command_(ST7789_SLPOUT); // Sleep out delay(120); // NOLINT - this->write_command_(ST7789_SLPOUT); // this->write_command_(ST7789_NORON); // Normal display mode on @@ -206,15 +206,23 @@ void ST7789V::write_display_data() { this->dc_pin_->digital_write(true); if (this->eightbitcolor_) { + uint8_t temp_buffer[TEMP_BUFFER_SIZE]; + size_t temp_index = 0; for (int line = 0; line < this->get_buffer_length_(); line = line + this->get_width_internal()) { for (int index = 0; index < this->get_width_internal(); ++index) { auto color = display::ColorUtil::color_to_565( display::ColorUtil::to_color(this->buffer_[index + line], display::ColorOrder::COLOR_ORDER_RGB, display::ColorBitness::COLOR_BITNESS_332, true)); - this->write_byte((color >> 8) & 0xff); - this->write_byte(color & 0xff); + temp_buffer[temp_index++] = (uint8_t) (color >> 8); + temp_buffer[temp_index++] = (uint8_t) color; + if (temp_index == TEMP_BUFFER_SIZE) { + this->write_array(temp_buffer, TEMP_BUFFER_SIZE); + temp_index = 0; + } } } + if (temp_index != 0) + this->write_array(temp_buffer, temp_index); } else { this->write_array(this->buffer_, this->get_buffer_length_()); } @@ -229,9 +237,10 @@ void ST7789V::init_reset_() { delay(1); // Trigger Reset this->reset_pin_->digital_write(false); - delay(10); + delay(1); // Wake up this->reset_pin_->digital_write(true); + delay(5); } } diff --git a/esphome/components/st7789v/st7789v.h b/esphome/components/st7789v/st7789v.h index ccbe50cf85..56132e8ea2 100644 --- a/esphome/components/st7789v/st7789v.h +++ b/esphome/components/st7789v/st7789v.h @@ -117,8 +117,8 @@ static const uint8_t ST7789_MADCTL_COLOR_ORDER = ST7789_MADCTL_BGR; class ST7789V : public PollingComponent, public display::DisplayBuffer, - public spi::SPIDevice { + public spi::SPIDevice { public: void set_model(ST7789VModel model); void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } From 3003485dc63e850c4e8cc4b67c3b87826265ea0b Mon Sep 17 00:00:00 2001 From: luka6000 Date: Fri, 1 Sep 2023 03:20:21 +0200 Subject: [PATCH 0407/2607] fix to PR # 3887 MQTT connection not using discovery: false (#5275) --- esphome/components/mqtt/mqtt_client.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index d3f759c072..1d804170f6 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -66,25 +66,28 @@ void MQTTClientComponent::setup() { } #endif - this->subscribe( - "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, - 2); + if (this->is_discovery_enabled()) { + this->subscribe( + "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, + 2); - std::string topic = "esphome/ping/"; - topic.append(App.get_name()); - this->subscribe( - topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); + std::string topic = "esphome/ping/"; + topic.append(App.get_name()); + this->subscribe( + topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); + } this->last_connected_ = millis(); this->start_dnslookup_(); } void MQTTClientComponent::send_device_info_() { - if (!this->is_connected()) { + if (!this->is_connected() or !this->is_discovery_enabled()) { return; } std::string topic = "esphome/discover/"; topic.append(App.get_name()); + this->publish_json( topic, [](JsonObject root) { From f14419bab589d911d55f845b21f7ba238cd79d07 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Fri, 1 Sep 2023 03:21:01 +0200 Subject: [PATCH 0408/2607] Bump Arduino Pico to 3.4.0 (#5321) --- esphome/components/rp2040/__init__.py | 6 +++--- platformio.ini | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index dafafc531c..9e9db02de1 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -62,7 +62,7 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/earlephilhower/arduino-pico/releases # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 3, 0) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 4, 0) # The platformio/raspberrypi version to use for arduino frameworks # - https://github.com/platformio/platform-raspberrypi/releases @@ -73,8 +73,8 @@ ARDUINO_PLATFORM_VERSION = cv.Version(1, 9, 0) def _arduino_check_versions(value): value = value.copy() lookups = { - "dev": (cv.Version(3, 3, 0), "https://github.com/earlephilhower/arduino-pico"), - "latest": (cv.Version(3, 3, 0), None), + "dev": (cv.Version(3, 4, 0), "https://github.com/earlephilhower/arduino-pico"), + "latest": (cv.Version(3, 4, 0), None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), } diff --git a/platformio.ini b/platformio.ini index 6341d7bde5..64c7bec6e8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -157,7 +157,7 @@ board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.3.0/rp2040-3.3.0.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.4.0/rp2040-3.4.0.zip framework = arduino lib_deps = From 19d53c6643df22823c2b20b05858f06e093c628f Mon Sep 17 00:00:00 2001 From: Daniel Dunn Date: Thu, 31 Aug 2023 20:02:26 -0600 Subject: [PATCH 0409/2607] Use gzip compression for the web server component's static resources (#5291) Co-authored-by: Daniel Dunn --- esphome/components/web_server/__init__.py | 10 ++++++++-- esphome/components/web_server/web_server.cpp | 3 +++ tests/test3.1.yaml | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index ab54ae8582..b1cf8a5de6 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -1,3 +1,4 @@ +import gzip import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import web_server_base @@ -109,9 +110,13 @@ def build_index_html(config) -> str: return html -def add_resource_as_progmem(resource_name: str, content: str) -> None: +def add_resource_as_progmem( + resource_name: str, content: str, compress: bool = True +) -> None: """Add a resource to progmem.""" content_encoded = content.encode("utf-8") + if compress: + content_encoded = gzip.compress(content_encoded) content_encoded_size = len(content_encoded) bytes_as_int = ", ".join(str(x) for x in content_encoded) uint8_t = f"const uint8_t ESPHOME_WEBSERVER_{resource_name}[{content_encoded_size}] PROGMEM = {{{bytes_as_int}}}" @@ -137,7 +142,8 @@ async def to_code(config): cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) cg.add_define("USE_WEBSERVER_VERSION", version) if version == 2: - add_resource_as_progmem("INDEX_HTML", build_index_html(config)) + # Don't compress the index HTML as the data sizes are almost the same. + add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) else: cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL])) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 01057fead6..e350e1b140 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -328,6 +328,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); + // No gzip header here because the HTML file is so small request->send(response); } #endif @@ -336,6 +337,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { void WebServer::handle_css_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, "text/css", ESPHOME_WEBSERVER_CSS_INCLUDE, ESPHOME_WEBSERVER_CSS_INCLUDE_SIZE); + response->addHeader("Content-Encoding", "gzip"); request->send(response); } #endif @@ -344,6 +346,7 @@ void WebServer::handle_css_request(AsyncWebServerRequest *request) { void WebServer::handle_js_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, "text/javascript", ESPHOME_WEBSERVER_JS_INCLUDE, ESPHOME_WEBSERVER_JS_INCLUDE_SIZE); + response->addHeader("Content-Encoding", "gzip"); request->send(response); } #endif diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 46bc014204..ea8dc337be 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -21,6 +21,10 @@ wifi: ssid: "MySSID" password: "password1" +web_server: + port: 80 + version: 2 + i2c: sda: 4 scl: 5 From 712634b30102026b950b416efac4b17aae249ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 14:03:10 +1200 Subject: [PATCH 0410/2607] Bump zeroconf from 0.86.0 to 0.88.0 (#5315) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b23964828c..715dbef4f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230711.0 aioesphomeapi==15.0.0 -zeroconf==0.86.0 +zeroconf==0.88.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From f8a03be2f1fbc641131679a6be628deab277e8fb Mon Sep 17 00:00:00 2001 From: Josh Barnard Date: Thu, 31 Aug 2023 22:10:42 -0700 Subject: [PATCH 0411/2607] Adding heating coil and fan icons, enum device_class (#5325) * Adding heating cool and fan icons. * Adding Enum device_class as well. --- esphome/const.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/const.py b/esphome/const.py index 373d6bd8c9..e0642247ab 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -842,6 +842,7 @@ ICON_COUNTER = "mdi:counter" ICON_CURRENT_AC = "mdi:current-ac" ICON_DATABASE = "mdi:database" ICON_EMPTY = "" +ICON_FAN = "mdi:fan" ICON_FINGERPRINT = "mdi:fingerprint" ICON_FLASH = "mdi:flash" ICON_FLASK = "mdi:flask" @@ -850,6 +851,7 @@ ICON_FLOWER = "mdi:flower" ICON_GAS_CYLINDER = "mdi:gas-cylinder" ICON_GAUGE = "mdi:gauge" ICON_GRAIN = "mdi:grain" +ICON_HEATING_COIL = "mdi:heating-coil" ICON_KEY_PLUS = "mdi:key-plus" ICON_LIGHTBULB = "mdi:lightbulb" ICON_MAGNET = "mdi:magnet" @@ -965,6 +967,7 @@ DEVICE_CLASS_DURATION = "duration" DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_ENERGY = "energy" DEVICE_CLASS_ENERGY_STORAGE = "energy_storage" +DEVICE_CLASS_ENUM = "enum" DEVICE_CLASS_FREQUENCY = "frequency" DEVICE_CLASS_GARAGE = "garage" DEVICE_CLASS_GARAGE_DOOR = "garage_door" From c3332e4a394b6fb4d1d44e321e168c1fc39fec09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 1 Sep 2023 08:17:33 +0200 Subject: [PATCH 0412/2607] Add dashboard API to get firmware binaries (#4675) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32/__init__.py | 17 ++++++ esphome/components/esp8266/__init__.py | 11 ++++ esphome/components/rp2040/__init__.py | 11 ++++ esphome/dashboard/dashboard.py | 80 ++++++++++++++++++-------- 4 files changed, 94 insertions(+), 25 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index d158528066..ee18315518 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -84,6 +84,23 @@ def get_board(core_obj=None): return (core_obj or CORE).data[KEY_ESP32][KEY_BOARD] +def get_download_types(storage_json): + return [ + { + "title": "Modern format", + "description": "For use with ESPHome Web and other tools.", + "file": "firmware-factory.bin", + "download": f"{storage_json.name}-factory.bin", + }, + { + "title": "Legacy format", + "description": "For use with ESPHome Flasher.", + "file": "firmware.bin", + "download": f"{storage_json.name}.bin", + }, + ] + + def only_on_variant(*, supported=None, unsupported=None): """Config validator for features only available on some ESP32 variants.""" if supported is not None and not isinstance(supported, list): diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 674f433d52..412c2d903f 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -50,6 +50,17 @@ def set_core_data(config): return config +def get_download_types(storage_json): + return [ + { + "title": "Standard format", + "description": "For flashing ESP8266.", + "file": "firmware.bin", + "download": f"{storage_json.name}.bin", + }, + ] + + def _format_framework_arduino_version(ver: cv.Version) -> str: # format the given arduino (https://github.com/esp8266/Arduino/releases) version to # a PIO platformio/framework-arduinoespressif8266 value diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 9e9db02de1..b31192f73f 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -42,6 +42,17 @@ def set_core_data(config): return config +def get_download_types(storage_json): + return [ + { + "title": "UF2 format", + "description": "For copying to RP2040 over USB.", + "file": "firmware.uf2", + "download": f"{storage_json.name}.uf2", + }, + ] + + def _format_framework_arduino_version(ver: cv.Version) -> str: # The most recent releases have not been uploaded to platformio so grabbing them directly from # the GitHub release is one path forward for now. diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index eae004fa09..c05e1fcfcc 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -530,11 +530,43 @@ class ImportRequestHandler(BaseHandler): self.finish() +class DownloadListRequestHandler(BaseHandler): + @authenticated + @bind_config + def get(self, configuration=None): + storage_path = ext_storage_path(settings.config_dir, configuration) + storage_json = StorageJSON.load(storage_path) + if storage_json is None: + self.send_error(404) + return + + from esphome.components.esp32 import get_download_types as esp32_types + from esphome.components.esp8266 import get_download_types as esp8266_types + from esphome.components.rp2040 import get_download_types as rp2040_types + + downloads = [] + platform = storage_json.target_platform.lower() + if platform == const.PLATFORM_RP2040: + downloads = rp2040_types(storage_json) + elif platform == const.PLATFORM_ESP8266: + downloads = esp8266_types(storage_json) + elif platform == const.PLATFORM_ESP32: + downloads = esp32_types(storage_json) + else: + self.send_error(418) + return + + self.set_status(200) + self.set_header("content-type", "application/json") + self.write(json.dumps(downloads)) + self.finish() + return + + class DownloadBinaryRequestHandler(BaseHandler): @authenticated @bind_config def get(self, configuration=None): - type = self.get_argument("type", "firmware.bin") compressed = self.get_argument("compressed", "0") == "1" storage_path = ext_storage_path(settings.config_dir, configuration) @@ -543,27 +575,22 @@ class DownloadBinaryRequestHandler(BaseHandler): self.send_error(404) return - if storage_json.target_platform.lower() == const.PLATFORM_RP2040: - filename = f"{storage_json.name}.uf2" - path = storage_json.firmware_bin_path.replace( - "firmware.bin", "firmware.uf2" - ) + # fallback to type=, but prioritize file= + file_name = self.get_argument("type", None) + file_name = self.get_argument("file", file_name) + if file_name is None: + self.send_error(400) + return + file_name = file_name.replace("..", "").lstrip("/") + # get requested download name, or build it based on filename + download_name = self.get_argument( + "download", + f"{storage_json.name}-{file_name}", + ) + path = os.path.dirname(storage_json.firmware_bin_path) + path = os.path.join(path, file_name) - elif storage_json.target_platform.lower() == const.PLATFORM_ESP8266: - filename = f"{storage_json.name}.bin" - path = storage_json.firmware_bin_path - - elif type == "firmware.bin": - filename = f"{storage_json.name}.bin" - path = storage_json.firmware_bin_path - - elif type == "firmware-factory.bin": - filename = f"{storage_json.name}-factory.bin" - path = storage_json.firmware_bin_path.replace( - "firmware.bin", "firmware-factory.bin" - ) - - else: + if not Path(path).is_file(): args = ["esphome", "idedata", settings.rel_path(configuration)] rc, stdout, _ = run_system_command(*args) @@ -575,9 +602,9 @@ class DownloadBinaryRequestHandler(BaseHandler): found = False for image in idedata.extra_flash_images: - if image.path.endswith(type): + if image.path.endswith(file_name): path = image.path - filename = type + download_name = file_name found = True break @@ -585,10 +612,12 @@ class DownloadBinaryRequestHandler(BaseHandler): self.send_error(404) return - filename = filename + ".gz" if compressed else filename + download_name = download_name + ".gz" if compressed else download_name self.set_header("Content-Type", "application/octet-stream") - self.set_header("Content-Disposition", f'attachment; filename="{filename}"') + self.set_header( + "Content-Disposition", f'attachment; filename="{download_name}"' + ) self.set_header("Cache-Control", "no-cache") if not Path(path).is_file(): self.send_error(404) @@ -1259,6 +1288,7 @@ def make_app(debug=get_bool_env(ENV_DEV)): (f"{rel}update-all", EsphomeUpdateAllHandler), (f"{rel}info", InfoRequestHandler), (f"{rel}edit", EditRequestHandler), + (f"{rel}downloads", DownloadListRequestHandler), (f"{rel}download.bin", DownloadBinaryRequestHandler), (f"{rel}serial-ports", SerialPortRequestHandler), (f"{rel}ping", PingRequestHandler), From bec53f97a251efa343796146796e6c4f2fb59ee1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 2 Sep 2023 08:41:52 +1200 Subject: [PATCH 0413/2607] Attempt to fix secret blurring (#5326) --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index ca5fc1c008..697adc03a3 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -371,7 +371,7 @@ def command_config(args, config): # add the console decoration so the front-end can hide the secrets if not args.show_secrets: output = re.sub( - r"(password|key|psk|ssid)\:\s(.*)", r"\1: \\033[5m\2\\033[6m", output + r"(password|key|psk|ssid)\: (.+)", r"\1: \\033[5m\2\\033[6m", output ) safe_print(output) _LOGGER.info("Configuration is valid!") From 211b3eddeaa5372e7fb3128fe7fc42653fa71ce2 Mon Sep 17 00:00:00 2001 From: kahrendt Date: Fri, 1 Sep 2023 16:55:59 -0400 Subject: [PATCH 0414/2607] Bugfix: disable channels after IO if multiple tca9548a I2C multiplexers are configured (#5317) --- esphome/components/tca9548a/tca9548a.cpp | 27 ++++++++++++++---------- esphome/components/tca9548a/tca9548a.h | 4 +++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/esphome/components/tca9548a/tca9548a.cpp b/esphome/components/tca9548a/tca9548a.cpp index caa3dd0655..770fd5e47c 100644 --- a/esphome/components/tca9548a/tca9548a.cpp +++ b/esphome/components/tca9548a/tca9548a.cpp @@ -7,23 +7,27 @@ namespace tca9548a { static const char *const TAG = "tca9548a"; i2c::ErrorCode TCA9548AChannel::readv(uint8_t address, i2c::ReadBuffer *buffers, size_t cnt) { - auto err = parent_->switch_to_channel(channel_); + auto err = this->parent_->switch_to_channel(channel_); if (err != i2c::ERROR_OK) return err; - return parent_->bus_->readv(address, buffers, cnt); + err = this->parent_->bus_->readv(address, buffers, cnt); + this->parent_->disable_all_channels(); + return err; } i2c::ErrorCode TCA9548AChannel::writev(uint8_t address, i2c::WriteBuffer *buffers, size_t cnt, bool stop) { - auto err = parent_->switch_to_channel(channel_); + auto err = this->parent_->switch_to_channel(channel_); if (err != i2c::ERROR_OK) return err; - return parent_->bus_->writev(address, buffers, cnt, stop); + err = this->parent_->bus_->writev(address, buffers, cnt, stop); + this->parent_->disable_all_channels(); + return err; } void TCA9548AComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up TCA9548A..."); uint8_t status = 0; if (this->read(&status, 1) != i2c::ERROR_OK) { - ESP_LOGI(TAG, "TCA9548A failed"); + ESP_LOGE(TAG, "TCA9548A failed"); this->mark_failed(); return; } @@ -37,15 +41,16 @@ void TCA9548AComponent::dump_config() { i2c::ErrorCode TCA9548AComponent::switch_to_channel(uint8_t channel) { if (this->is_failed()) return i2c::ERROR_NOT_INITIALIZED; - if (current_channel_ == channel) - return i2c::ERROR_OK; uint8_t channel_val = 1 << channel; - auto err = this->write(&channel_val, 1); - if (err == i2c::ERROR_OK) { - current_channel_ = channel; + return this->write(&channel_val, 1); +} + +void TCA9548AComponent::disable_all_channels() { + if (this->write(&TCA9548A_DISABLE_CHANNELS_COMMAND, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to disable all channels."); + this->status_set_error(); // couldn't disable channels, set error status } - return err; } } // namespace tca9548a diff --git a/esphome/components/tca9548a/tca9548a.h b/esphome/components/tca9548a/tca9548a.h index 02553f8cd0..08f1674d11 100644 --- a/esphome/components/tca9548a/tca9548a.h +++ b/esphome/components/tca9548a/tca9548a.h @@ -6,6 +6,8 @@ namespace esphome { namespace tca9548a { +static const uint8_t TCA9548A_DISABLE_CHANNELS_COMMAND = 0x00; + class TCA9548AComponent; class TCA9548AChannel : public i2c::I2CBus { public: @@ -28,10 +30,10 @@ class TCA9548AComponent : public Component, public i2c::I2CDevice { void update(); i2c::ErrorCode switch_to_channel(uint8_t channel); + void disable_all_channels(); protected: friend class TCA9548AChannel; - uint8_t current_channel_ = 255; }; } // namespace tca9548a } // namespace esphome From 2bb5f53b98fbbca09755d1715a8f6d066786fa25 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sat, 2 Sep 2023 08:10:08 +1000 Subject: [PATCH 0415/2607] Make uart error message go away (#5329) * Make error message in log go away. * Test for IDF version. --- esphome/components/logger/logger.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 86ebb53764..758e9c1f98 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -4,6 +4,7 @@ #ifdef USE_ESP_IDF #include #include "freertos/FreeRTOS.h" +#include "esp_idf_version.h" #endif // USE_ESP_IDF #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_ESP_IDF) @@ -239,6 +240,9 @@ void Logger::pre_setup() { uart_config.parity = UART_PARITY_DISABLE; uart_config.stop_bits = UART_STOP_BITS_1; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + uart_config.source_clk = UART_SCLK_DEFAULT; +#endif uart_param_config(uart_num_, &uart_config); const int uart_buffer_size = tx_buffer_size_; // Install UART driver using an event queue here From 2165960ba171e9b3d775622f0bc012ffc51fb295 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 2 Sep 2023 01:03:30 +0100 Subject: [PATCH 0416/2607] add heating functionality to SI7021 (#4828) * add heating functoinality * add test * add heat * fix * fix * fix * fix * fix * fix sensor * restore class * Update esphome/components/htu21d/sensor.py * Update esphome/components/htu21d/sensor.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/htu21d/sensor.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski --- esphome/components/htu21d/htu21d.cpp | 58 +++++++++++++++++++++++++++- esphome/components/htu21d/htu21d.h | 30 ++++++++++++++ esphome/components/htu21d/sensor.py | 56 +++++++++++++++++++++++++++ tests/test1.yaml | 2 + 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index a38ec73019..5030ac4d0f 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -11,7 +11,11 @@ static const uint8_t HTU21D_ADDRESS = 0x40; static const uint8_t HTU21D_REGISTER_RESET = 0xFE; static const uint8_t HTU21D_REGISTER_TEMPERATURE = 0xF3; static const uint8_t HTU21D_REGISTER_HUMIDITY = 0xF5; +static const uint8_t HTU21D_WRITERHT_REG_CMD = 0xE6; /**< Write RH/T User Register 1 */ static const uint8_t HTU21D_REGISTER_STATUS = 0xE7; +static const uint8_t HTU21D_WRITEHEATER_REG_CMD = 0x51; /**< Write Heater Control Register */ +static const uint8_t HTU21D_READHEATER_REG_CMD = 0x11; /**< Read Heater Control Register */ +static const uint8_t HTU21D_REG_HTRE_BIT = 0x02; /**< Control Register Heater Bit */ void HTU21DComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up HTU21D..."); @@ -62,14 +66,66 @@ void HTU21DComponent::update() { raw_humidity = i2c::i2ctohs(raw_humidity); float humidity = (float(raw_humidity & 0xFFFC)) * 125.0f / 65536.0f - 6.0f; - ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity); + + int8_t heater_level = this->get_heater_level(); + + ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%% Heater Level=%d", temperature, humidity, heater_level); if (this->temperature_ != nullptr) this->temperature_->publish_state(temperature); if (this->humidity_ != nullptr) this->humidity_->publish_state(humidity); + if (this->heater_ != nullptr) + this->heater_->publish_state(humidity); this->status_clear_warning(); } + +bool HTU21DComponent::is_heater_enabled() { + uint8_t raw_heater; + if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { + this->status_set_warning(); + return false; + } + raw_heater = i2c::i2ctohs(raw_heater); + return (bool) (((raw_heater) >> (HTU21D_REG_HTRE_BIT)) & 0x01); +} + +void HTU21DComponent::set_heater(bool status) { + uint8_t raw_heater; + if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + raw_heater = i2c::i2ctohs(raw_heater); + if (status) { + raw_heater |= (1 << (HTU21D_REG_HTRE_BIT)); + } else { + raw_heater &= ~(1 << (HTU21D_REG_HTRE_BIT)); + } + + if (this->write_register(HTU21D_WRITERHT_REG_CMD, &raw_heater, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } +} + +void HTU21DComponent::set_heater_level(uint8_t level) { + if (this->write_register(HTU21D_WRITEHEATER_REG_CMD, &level, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } +} + +int8_t HTU21DComponent::get_heater_level() { + int8_t raw_heater; + if (this->read_register(HTU21D_READHEATER_REG_CMD, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { + this->status_set_warning(); + return 0; + } + raw_heater = i2c::i2ctohs(raw_heater); + return raw_heater; +} + float HTU21DComponent::get_setup_priority() const { return setup_priority::DATA; } } // namespace htu21d diff --git a/esphome/components/htu21d/htu21d.h b/esphome/components/htu21d/htu21d.h index a408f06d01..a77a8e3ada 100644 --- a/esphome/components/htu21d/htu21d.h +++ b/esphome/components/htu21d/htu21d.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" +#include "esphome/core/automation.h" namespace esphome { namespace htu21d { @@ -11,6 +12,7 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { public: void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } + void set_heater(sensor::Sensor *heater) { heater_ = heater; } /// Setup (reset) the sensor and check connection. void setup() override; @@ -18,11 +20,39 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { /// Update the sensor values (temperature+humidity). void update() override; + bool is_heater_enabled(); + void set_heater(bool status); + void set_heater_level(uint8_t level); + int8_t get_heater_level(); + float get_setup_priority() const override; protected: sensor::Sensor *temperature_{nullptr}; sensor::Sensor *humidity_{nullptr}; + sensor::Sensor *heater_{nullptr}; +}; + +template class SetHeaterLevelAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, level) + + void play(Ts... x) override { + auto level = this->level_.value(x...); + + this->parent_->set_heater_level(level); + } +}; + +template class SetHeaterAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(bool, status) + + void play(Ts... x) override { + auto status = this->status_.value(x...); + + this->parent_->set_heater(status); + } }; } // namespace htu21d diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 2ed318f1c9..1f878230f8 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor +from esphome import automation from esphome.const import ( CONF_HUMIDITY, CONF_ID, @@ -10,6 +11,10 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, + CONF_HEATER, + UNIT_EMPTY, + CONF_LEVEL, + CONF_STATUS, ) DEPENDENCIES = ["i2c"] @@ -19,6 +24,10 @@ HTU21DComponent = htu21d_ns.class_( "HTU21DComponent", cg.PollingComponent, i2c.I2CDevice ) +SetHeaterLevelAction = htu21d_ns.class_("SetHeaterLevelAction", automation.Action) +SetHeaterAction = htu21d_ns.class_("SetHeaterAction", automation.Action) + + CONFIG_SCHEMA = ( cv.Schema( { @@ -35,6 +44,11 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_HEATER): sensor.sensor_schema( + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, + ), } ) .extend(cv.polling_component_schema("60s")) @@ -54,3 +68,45 @@ async def to_code(config): if CONF_HUMIDITY in config: sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) + + if CONF_HEATER in config: + sens = await sensor.new_sensor(config[CONF_HEATER]) + cg.add(var.set_heater(sens)) + + +@automation.register_action( + "htu21d.set_heater_level", + SetHeaterLevelAction, + cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(HTU21DComponent), + cv.Required(CONF_LEVEL): cv.templatable(cv.int_), + }, + key=CONF_LEVEL, + ), +) +async def set_heater_level_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + level_ = await cg.templatable(config[CONF_LEVEL], args, int) + cg.add(var.set_level(level_)) + return var + + +@automation.register_action( + "htu21d.set_heater", + SetHeaterAction, + cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(HTU21DComponent), + cv.Required(CONF_STATUS): cv.templatable(cv.boolean), + }, + key=CONF_STATUS, + ), +) +async def set_heater_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + status_ = await cg.templatable(config[CONF_LEVEL], args, bool) + cg.add(var.set_status(status_)) + return var diff --git a/tests/test1.yaml b/tests/test1.yaml index 3a6cfa0c4b..efca34247b 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -848,6 +848,8 @@ sensor: name: Living Room Temperature 6 humidity: name: Living Room Humidity 6 + heater: + name: Living Room Heater 6 update_interval: 15s i2c_id: i2c_bus - platform: max6675 From 5fdafc00e665f846a8b3e9b4b318df6c5ddca183 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Sat, 2 Sep 2023 09:54:03 +0000 Subject: [PATCH 0417/2607] Fix checksum calculation for pipsolar (#5299) --- esphome/components/pipsolar/pipsolar.cpp | 20 ++++++++++++++++---- esphome/components/pipsolar/pipsolar.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index 62e4fbd341..2cd1aeba44 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -769,7 +769,7 @@ uint8_t Pipsolar::check_incoming_length_(uint8_t length) { uint8_t Pipsolar::check_incoming_crc_() { uint16_t crc16; - crc16 = crc16be(read_buffer_, read_pos_ - 3); + crc16 = this->pipsolar_crc_(read_buffer_, read_pos_ - 3); ESP_LOGD(TAG, "checking crc on incoming message"); if (((uint8_t) ((crc16) >> 8)) == read_buffer_[read_pos_ - 3] && ((uint8_t) ((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) { @@ -798,7 +798,7 @@ uint8_t Pipsolar::send_next_command_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = crc16be(byte_command, length); + crc16 = this->pipsolar_crc_(byte_command, length); this->write_str(command); // checksum this->write(((uint8_t) ((crc16) >> 8))); // highbyte @@ -825,8 +825,8 @@ void Pipsolar::send_next_poll_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = crc16be(this->used_polling_commands_[this->last_polling_command_].command, - this->used_polling_commands_[this->last_polling_command_].length); + crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command, + this->used_polling_commands_[this->last_polling_command_].length); this->write_array(this->used_polling_commands_[this->last_polling_command_].command, this->used_polling_commands_[this->last_polling_command_].length); // checksum @@ -893,5 +893,17 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll } } +uint16_t Pipsolar::pipsolar_crc_(uint8_t *msg, uint8_t len) { + uint16_t crc = crc16be(msg, len); + uint8_t crc_low = crc & 0xff; + uint8_t crc_high = crc >> 8; + if (crc_low == 0x28 || crc_low == 0x0d || crc_low == 0x0a) + crc_low++; + if (crc_high == 0x28 || crc_high == 0x0d || crc_high == 0x0a) + crc_high++; + crc = (crc_high << 8) | crc_low; + return crc; +} + } // namespace pipsolar } // namespace esphome diff --git a/esphome/components/pipsolar/pipsolar.h b/esphome/components/pipsolar/pipsolar.h index 65fd3c670d..f20f44f095 100644 --- a/esphome/components/pipsolar/pipsolar.h +++ b/esphome/components/pipsolar/pipsolar.h @@ -193,7 +193,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { void empty_uart_buffer_(); uint8_t check_incoming_crc_(); uint8_t check_incoming_length_(uint8_t length); - uint16_t cal_crc_half_(uint8_t *msg, uint8_t len); + uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len); uint8_t send_next_command_(); void send_next_poll_(); void queue_command_(const char *command, uint8_t length); From 4ae582c3051ba06c811bdfaf89a15b00a19a571b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 4 Sep 2023 20:43:17 +1200 Subject: [PATCH 0418/2607] Bump esphome-dashboard to 20230904.0 (#5339) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 715dbef4f2..c52b8e1d8e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pyserial==3.5 platformio==6.1.10 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.7 -esphome-dashboard==20230711.0 +esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 zeroconf==0.88.0 From 3d9af2a67c3de1ff9761d099364c399f07a93803 Mon Sep 17 00:00:00 2001 From: croessi <87674139+croessi@users.noreply.github.com> Date: Mon, 4 Sep 2023 22:40:46 +0200 Subject: [PATCH 0419/2607] Added Handling for Nack "file not found" (#5338) --- esphome/components/dfplayer/dfplayer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/dfplayer/dfplayer.cpp b/esphome/components/dfplayer/dfplayer.cpp index a6339dc988..39a30d035e 100644 --- a/esphome/components/dfplayer/dfplayer.cpp +++ b/esphome/components/dfplayer/dfplayer.cpp @@ -101,6 +101,11 @@ void DFPlayer::loop() { ESP_LOGV(TAG, "Nack"); this->ack_set_is_playing_ = false; this->ack_reset_is_playing_ = false; + if (argument == 6) { + ESP_LOGV(TAG, "File not found"); + this->is_playing_ = false; + } + break; case 0x41: ESP_LOGV(TAG, "Ack ok"); this->is_playing_ |= this->ack_set_is_playing_; From aabe0091ccf1c666e1a6771c40614e8c310aec7f Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 4 Sep 2023 22:51:04 +0200 Subject: [PATCH 0420/2607] Prepare api and time for ESP-IDF >= 5 (#5332) --- esphome/components/api/api_pb2.cpp | 184 ++++++++++---------- esphome/components/time/real_time_clock.cpp | 2 +- 2 files changed, 94 insertions(+), 92 deletions(-) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 3a2d980e57..6149a970ee 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3,6 +3,8 @@ #include "api_pb2.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace api { @@ -522,12 +524,12 @@ void HelloRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" api_version_major: "); - sprintf(buffer, "%u", this->api_version_major); + sprintf(buffer, "%" PRIu32, this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%u", this->api_version_minor); + sprintf(buffer, "%" PRIu32, this->api_version_minor); out.append(buffer); out.append("\n"); out.append("}"); @@ -572,12 +574,12 @@ void HelloResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("HelloResponse {\n"); out.append(" api_version_major: "); - sprintf(buffer, "%u", this->api_version_major); + sprintf(buffer, "%" PRIu32, this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%u", this->api_version_minor); + sprintf(buffer, "%" PRIu32, this->api_version_minor); out.append(buffer); out.append("\n"); @@ -783,17 +785,17 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" webserver_port: "); - sprintf(buffer, "%u", this->webserver_port); + sprintf(buffer, "%" PRIu32, this->webserver_port); out.append(buffer); out.append("\n"); out.append(" legacy_bluetooth_proxy_version: "); - sprintf(buffer, "%u", this->legacy_bluetooth_proxy_version); + sprintf(buffer, "%" PRIu32, this->legacy_bluetooth_proxy_version); out.append(buffer); out.append("\n"); out.append(" bluetooth_proxy_feature_flags: "); - sprintf(buffer, "%u", this->bluetooth_proxy_feature_flags); + sprintf(buffer, "%" PRIu32, this->bluetooth_proxy_feature_flags); out.append(buffer); out.append("\n"); @@ -806,7 +808,7 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" voice_assistant_version: "); - sprintf(buffer, "%u", this->voice_assistant_version); + sprintf(buffer, "%" PRIu32, this->voice_assistant_version); out.append(buffer); out.append("\n"); out.append("}"); @@ -898,7 +900,7 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -966,7 +968,7 @@ void BinarySensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BinarySensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1069,7 +1071,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1159,7 +1161,7 @@ void CoverStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1242,7 +1244,7 @@ void CoverCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1362,7 +1364,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1387,7 +1389,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_speed_count: "); - sprintf(buffer, "%d", this->supported_speed_count); + sprintf(buffer, "%" PRId32, this->supported_speed_count); out.append(buffer); out.append("\n"); @@ -1454,7 +1456,7 @@ void FanStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1475,7 +1477,7 @@ void FanStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%d", this->speed_level); + sprintf(buffer, "%" PRId32, this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1555,7 +1557,7 @@ void FanCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1596,7 +1598,7 @@ void FanCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%d", this->speed_level); + sprintf(buffer, "%" PRId32, this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1710,7 +1712,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1864,7 +1866,7 @@ void LightStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2087,7 +2089,7 @@ void LightCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2185,7 +2187,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" transition_length: "); - sprintf(buffer, "%u", this->transition_length); + sprintf(buffer, "%" PRIu32, this->transition_length); out.append(buffer); out.append("\n"); @@ -2194,7 +2196,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" flash_length: "); - sprintf(buffer, "%u", this->flash_length); + sprintf(buffer, "%" PRIu32, this->flash_length); out.append(buffer); out.append("\n"); @@ -2302,7 +2304,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2323,7 +2325,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" accuracy_decimals: "); - sprintf(buffer, "%d", this->accuracy_decimals); + sprintf(buffer, "%" PRId32, this->accuracy_decimals); out.append(buffer); out.append("\n"); @@ -2387,7 +2389,7 @@ void SensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2476,7 +2478,7 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2539,7 +2541,7 @@ void SwitchStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2578,7 +2580,7 @@ void SwitchCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2652,7 +2654,7 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2718,7 +2720,7 @@ void TextSensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("TextSensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3025,7 +3027,7 @@ void GetTimeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("GetTimeResponse {\n"); out.append(" epoch_seconds: "); - sprintf(buffer, "%u", this->epoch_seconds); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); out.append(buffer); out.append("\n"); out.append("}"); @@ -3109,7 +3111,7 @@ void ListEntitiesServicesResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3203,7 +3205,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" legacy_int: "); - sprintf(buffer, "%d", this->legacy_int); + sprintf(buffer, "%" PRId32, this->legacy_int); out.append(buffer); out.append("\n"); @@ -3217,7 +3219,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" int_: "); - sprintf(buffer, "%d", this->int_); + sprintf(buffer, "%" PRId32, this->int_); out.append(buffer); out.append("\n"); @@ -3229,7 +3231,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { for (const auto &it : this->int_array) { out.append(" int_array: "); - sprintf(buffer, "%d", it); + sprintf(buffer, "%" PRId32, it); out.append(buffer); out.append("\n"); } @@ -3280,7 +3282,7 @@ void ExecuteServiceRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ExecuteServiceRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3356,7 +3358,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3422,7 +3424,7 @@ void CameraImageResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CameraImageResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3614,7 +3616,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3802,7 +3804,7 @@ void ClimateStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3990,7 +3992,7 @@ void ClimateCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4173,7 +4175,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4260,7 +4262,7 @@ void NumberStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4298,7 +4300,7 @@ void NumberCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4380,7 +4382,7 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4452,7 +4454,7 @@ void SelectStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4495,7 +4497,7 @@ void SelectCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4589,7 +4591,7 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4660,7 +4662,7 @@ void LockStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4715,7 +4717,7 @@ void LockCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4802,7 +4804,7 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4848,7 +4850,7 @@ void ButtonCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ButtonCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); out.append("}"); @@ -4923,7 +4925,7 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4992,7 +4994,7 @@ void MediaPlayerStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -5071,7 +5073,7 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -5120,7 +5122,7 @@ void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const __attribute__((unused)) char buffer[64]; out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); out.append(" flags: "); - sprintf(buffer, "%u", this->flags); + sprintf(buffer, "%" PRIu32, this->flags); out.append(buffer); out.append("\n"); out.append("}"); @@ -5167,7 +5169,7 @@ void BluetoothServiceData::dump_to(std::string &out) const { for (const auto &it : this->legacy_data) { out.append(" legacy_data: "); - sprintf(buffer, "%u", it); + sprintf(buffer, "%" PRIu32, it); out.append(buffer); out.append("\n"); } @@ -5247,7 +5249,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%d", this->rssi); + sprintf(buffer, "%" PRId32, this->rssi); out.append(buffer); out.append("\n"); @@ -5270,7 +5272,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { } out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5320,12 +5322,12 @@ void BluetoothLERawAdvertisement::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%d", this->rssi); + sprintf(buffer, "%" PRId32, this->rssi); out.append(buffer); out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); @@ -5408,7 +5410,7 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5456,12 +5458,12 @@ void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" mtu: "); - sprintf(buffer, "%u", this->mtu); + sprintf(buffer, "%" PRIu32, this->mtu); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -5521,7 +5523,7 @@ void BluetoothGATTDescriptor::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5577,12 +5579,12 @@ void BluetoothGATTCharacteristic::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append(" properties: "); - sprintf(buffer, "%u", this->properties); + sprintf(buffer, "%" PRIu32, this->properties); out.append(buffer); out.append("\n"); @@ -5639,7 +5641,7 @@ void BluetoothGATTService::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5746,7 +5748,7 @@ void BluetoothGATTReadRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5791,7 +5793,7 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5845,7 +5847,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5887,7 +5889,7 @@ void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5932,7 +5934,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5975,7 +5977,7 @@ void BluetoothGATTNotifyRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -6024,7 +6026,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -6063,12 +6065,12 @@ void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BluetoothConnectionsFreeResponse {\n"); out.append(" free: "); - sprintf(buffer, "%u", this->free); + sprintf(buffer, "%" PRIu32, this->free); out.append(buffer); out.append("\n"); out.append(" limit: "); - sprintf(buffer, "%u", this->limit); + sprintf(buffer, "%" PRIu32, this->limit); out.append(buffer); out.append("\n"); out.append("}"); @@ -6107,12 +6109,12 @@ void BluetoothGATTErrorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6146,7 +6148,7 @@ void BluetoothGATTWriteResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6180,7 +6182,7 @@ void BluetoothGATTNotifyResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6223,7 +6225,7 @@ void BluetoothDevicePairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6266,7 +6268,7 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6315,7 +6317,7 @@ void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6412,7 +6414,7 @@ void VoiceAssistantResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantResponse {\n"); out.append(" port: "); - sprintf(buffer, "%u", this->port); + sprintf(buffer, "%" PRIu32, this->port); out.append(buffer); out.append("\n"); @@ -6575,7 +6577,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -6600,7 +6602,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_features: "); - sprintf(buffer, "%u", this->supported_features); + sprintf(buffer, "%" PRIu32, this->supported_features); out.append(buffer); out.append("\n"); @@ -6643,7 +6645,7 @@ void AlarmControlPanelStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -6693,7 +6695,7 @@ void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 10fa9597b9..0573c7de9d 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -24,7 +24,7 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { struct timeval timev { .tv_sec = static_cast(epoch), .tv_usec = 0, }; - ESP_LOGVV(TAG, "Got epoch %u", epoch); + ESP_LOGVV(TAG, "Got epoch %" PRIu32, epoch); timezone tz = {0, 0}; int ret = settimeofday(&timev, &tz); if (ret == EINVAL) { From 22c0b0abaa548bd00938135acecc401a7a12aecf Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 4 Sep 2023 16:47:53 -0500 Subject: [PATCH 0421/2607] Tweak Improv serial to build in IDF 5 (#5331) --- esphome/components/improv_serial/improv_serial_component.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index fe19e2f085..1dd1c9cf6f 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -48,7 +48,7 @@ uint8_t ImprovSerialComponent::read_byte_() { this->hw_serial_->readBytes(&data, 1); #endif #ifdef USE_ESP_IDF - uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_RATE_MS); + uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS); #endif return data; } From a9630ac847a292bc6ad671356804deb809eb6dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 5 Sep 2023 00:16:08 +0200 Subject: [PATCH 0422/2607] Support for LibreTiny platform (RTL8710, BK7231 & other modules) (#3509) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kuba Szczodrzyński Co-authored-by: Sam Neirinck Co-authored-by: David Buezas Co-authored-by: Stroe Andrei Catalin Co-authored-by: Sam Neirinck Co-authored-by: Péter Sárközi Co-authored-by: Hajo Noerenberg --- CODEOWNERS | 4 + esphome/__main__.py | 21 +- esphome/components/adc/__init__.py | 9 +- esphome/components/adc/adc_sensor.cpp | 13 +- esphome/components/api/api_connection.cpp | 4 + esphome/components/async_tcp/__init__.py | 6 +- esphome/components/bk72xx/__init__.py | 51 + esphome/components/bk72xx/boards.py | 1264 +++++++++++++++ esphome/components/captive_portal/__init__.py | 4 +- esphome/components/debug/debug_component.cpp | 31 +- esphome/components/esp8266/gpio.py | 2 +- esphome/components/i2c/__init__.py | 37 +- esphome/components/json/json_util.cpp | 4 + esphome/components/libretiny/__init__.py | 336 ++++ esphome/components/libretiny/const.py | 90 ++ esphome/components/libretiny/core.cpp | 40 + esphome/components/libretiny/core.h | 11 + .../libretiny/generate_components.py | 329 ++++ esphome/components/libretiny/gpio.py | 216 +++ esphome/components/libretiny/gpio_arduino.cpp | 105 ++ esphome/components/libretiny/gpio_arduino.h | 36 + esphome/components/libretiny/lt_component.cpp | 29 + esphome/components/libretiny/lt_component.h | 36 + esphome/components/libretiny/preferences.cpp | 182 +++ esphome/components/libretiny/preferences.h | 13 + esphome/components/libretiny/text_sensor.py | 31 + esphome/components/libretiny_pwm/__init__.py | 1 + .../libretiny_pwm/libretiny_pwm.cpp | 53 + .../components/libretiny_pwm/libretiny_pwm.h | 55 + esphome/components/libretiny_pwm/output.py | 49 + esphome/components/logger/__init__.py | 34 +- esphome/components/logger/logger.cpp | 58 +- esphome/components/logger/logger.h | 16 +- esphome/components/md5/md5.h | 5 + esphome/components/mdns/mdns_component.cpp | 3 + esphome/components/mdns/mdns_libretiny.cpp | 43 + esphome/components/ota/__init__.py | 9 +- .../ota/ota_backend_arduino_libretiny.cpp | 46 + .../ota/ota_backend_arduino_libretiny.h | 24 + esphome/components/ota/ota_component.cpp | 4 + .../components/remote_receiver/__init__.py | 6 +- .../remote_receiver/remote_receiver.h | 4 +- .../remote_receiver_libretiny.cpp | 122 ++ .../remote_transmitter/remote_transmitter.h | 2 +- .../remote_transmitter_libretiny.cpp | 104 ++ esphome/components/rp2040/gpio.py | 3 +- esphome/components/rtl87xx/__init__.py | 51 + esphome/components/rtl87xx/boards.py | 1390 +++++++++++++++++ esphome/components/sntp/sntp_component.cpp | 4 +- esphome/components/socket/__init__.py | 11 +- esphome/components/socket/headers.h | 29 + .../components/socket/lwip_sockets_impl.cpp | 115 ++ esphome/components/spi/__init__.py | 1 + esphome/components/uart/__init__.py | 5 + .../uart/uart_component_libretiny.cpp | 168 ++ .../uart/uart_component_libretiny.h | 43 + esphome/components/web_server/__init__.py | 9 +- .../components/web_server_base/__init__.py | 2 +- .../web_server_base/web_server_base.cpp | 4 +- esphome/components/wifi/__init__.py | 7 +- esphome/components/wifi/wifi_component.h | 9 + .../wifi/wifi_component_libretiny.cpp | 467 ++++++ esphome/config_validation.py | 8 + esphome/const.py | 15 +- esphome/core/__init__.py | 14 + esphome/core/config.py | 2 +- esphome/core/defines.h | 4 + esphome/core/helpers.cpp | 15 +- esphome/core/helpers.h | 5 +- esphome/core/log.h | 3 + esphome/dashboard/dashboard.py | 9 + esphome/voluptuous_schema.py | 5 + esphome/wizard.py | 80 +- platformio.ini | 41 +- script/ci-custom.py | 6 +- tests/test9.1.yaml | 28 + tests/test9.yaml | 28 + tests/unit_tests/test_wizard.py | 51 +- 78 files changed, 6085 insertions(+), 89 deletions(-) create mode 100644 esphome/components/bk72xx/__init__.py create mode 100644 esphome/components/bk72xx/boards.py create mode 100644 esphome/components/libretiny/__init__.py create mode 100644 esphome/components/libretiny/const.py create mode 100644 esphome/components/libretiny/core.cpp create mode 100644 esphome/components/libretiny/core.h create mode 100644 esphome/components/libretiny/generate_components.py create mode 100644 esphome/components/libretiny/gpio.py create mode 100644 esphome/components/libretiny/gpio_arduino.cpp create mode 100644 esphome/components/libretiny/gpio_arduino.h create mode 100644 esphome/components/libretiny/lt_component.cpp create mode 100644 esphome/components/libretiny/lt_component.h create mode 100644 esphome/components/libretiny/preferences.cpp create mode 100644 esphome/components/libretiny/preferences.h create mode 100644 esphome/components/libretiny/text_sensor.py create mode 100644 esphome/components/libretiny_pwm/__init__.py create mode 100644 esphome/components/libretiny_pwm/libretiny_pwm.cpp create mode 100644 esphome/components/libretiny_pwm/libretiny_pwm.h create mode 100644 esphome/components/libretiny_pwm/output.py create mode 100644 esphome/components/mdns/mdns_libretiny.cpp create mode 100644 esphome/components/ota/ota_backend_arduino_libretiny.cpp create mode 100644 esphome/components/ota/ota_backend_arduino_libretiny.h create mode 100644 esphome/components/remote_receiver/remote_receiver_libretiny.cpp create mode 100644 esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp create mode 100644 esphome/components/rtl87xx/__init__.py create mode 100644 esphome/components/rtl87xx/boards.py create mode 100644 esphome/components/socket/lwip_sockets_impl.cpp create mode 100644 esphome/components/uart/uart_component_libretiny.cpp create mode 100644 esphome/components/uart/uart_component_libretiny.h create mode 100644 esphome/components/wifi/wifi_component_libretiny.cpp create mode 100644 tests/test9.1.yaml create mode 100644 tests/test9.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 49746cf013..1455643550 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -42,6 +42,7 @@ esphome/components/bedjet/climate/* @jhansche esphome/components/bedjet/fan/* @jhansche esphome/components/bh1750/* @OttoWinter esphome/components/binary_sensor/* @esphome/core +esphome/components/bk72xx/* @kuba2k2 esphome/components/bl0939/* @ziceva esphome/components/bl0940/* @tobias- esphome/components/bl0942/* @dbuezas @@ -146,6 +147,8 @@ esphome/components/kuntze/* @ssieb esphome/components/lcd_menu/* @numo68 esphome/components/ld2410/* @regevbr @sebcaps esphome/components/ledc/* @OttoWinter +esphome/components/libretiny/* @kuba2k2 +esphome/components/libretiny_pwm/* @kuba2k2 esphome/components/light/* @esphome/core esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core @@ -234,6 +237,7 @@ esphome/components/rgbct/* @jesserockz esphome/components/rp2040/* @jesserockz esphome/components/rp2040_pio_led_strip/* @Papa-DMan esphome/components/rp2040_pwm/* @jesserockz +esphome/components/rtl87xx/* @kuba2k2 esphome/components/rtttl/* @glmnet esphome/components/safe_mode/* @jsuanet @paulmonigatti esphome/components/scd4x/* @martgras @sjtrny diff --git a/esphome/__main__.py b/esphome/__main__.py index 697adc03a3..9b208c2280 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -26,6 +26,8 @@ from esphome.const import ( CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, CONF_SUBSTITUTIONS, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, @@ -278,20 +280,25 @@ def upload_using_esptool(config, port): return run_esptool(115200) +def upload_using_platformio(config, port): + from esphome import platformio_api + + upload_args = ["-t", "upload", "-t", "nobuild"] + if port is not None: + upload_args += ["--upload-port", port] + return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args) + + def upload_program(config, args, host): if get_port_type(host) == "SERIAL": if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266): return upload_using_esptool(config, host) if CORE.target_platform in (PLATFORM_RP2040): - from esphome import platformio_api + return upload_using_platformio(config, args.device) - upload_args = ["-t", "upload"] - if args.device is not None: - upload_args += ["--upload-port", args.device] - return platformio_api.run_platformio_cli_run( - config, CORE.verbose, *upload_args - ) + if CORE.target_platform in (PLATFORM_BK72XX, PLATFORM_RTL87XX): + return upload_using_platformio(config, host) return 1 # Unknown target platform diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 015d6edd21..ba72951777 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.const import CONF_INPUT +from esphome.const import CONF_ANALOG, CONF_INPUT from esphome.core import CORE from esphome.components.esp32 import get_esp32_variant @@ -166,8 +166,6 @@ def validate_adc_pin(value): return pins.internal_gpio_input_pin_schema(value) if CORE.is_esp8266: - from esphome.components.esp8266.gpio import CONF_ANALOG - value = pins.internal_gpio_pin_number({CONF_ANALOG: True, CONF_INPUT: True})( value ) @@ -184,4 +182,9 @@ def validate_adc_pin(value): raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC") return pins.internal_gpio_input_pin_schema(value) + if CORE.is_libretiny: + return pins.gpio_pin_schema( + {CONF_ANALOG: True, CONF_INPUT: True}, internal=True + )(value) + raise NotImplementedError diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 665ecfd6b5..0642cd7f3f 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -92,13 +92,13 @@ extern "C" void ADCSensor::dump_config() { LOG_SENSOR("", "ADC Sensor", this); -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) || defined(USE_LIBRETINY) #ifdef USE_ADC_SENSOR_VCC ESP_LOGCONFIG(TAG, " Pin: VCC"); #else LOG_PIN(" Pin: ", pin_); #endif -#endif // USE_ESP8266 +#endif // USE_ESP8266 || USE_LIBRETINY #ifdef USE_ESP32 LOG_PIN(" Pin: ", pin_); @@ -254,6 +254,15 @@ float ADCSensor::sample() { } #endif +#ifdef USE_LIBRETINY +float ADCSensor::sample() { + if (output_raw_) { + return analogRead(this->pin_->get_pin()); // NOLINT + } + return analogReadVoltage(this->pin_->get_pin()) / 1000.0f; // NOLINT +} +#endif // USE_LIBRETINY + #ifdef USE_ESP8266 std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } #endif diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index a46efd80e5..ceec53bb65 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1051,6 +1051,10 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.manufacturer = "Espressif"; #elif defined(USE_RP2040) resp.manufacturer = "Raspberry Pi"; +#elif defined(USE_BK72XX) + resp.manufacturer = "Beken"; +#elif defined(USE_RTL87XX) + resp.manufacturer = "Realtek"; #elif defined(USE_HOST) resp.manufacturer = "Host"; #endif diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index 1d127623f1..1677d4b9a8 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -8,15 +8,15 @@ CODEOWNERS = ["@OttoWinter"] CONFIG_SCHEMA = cv.All( cv.Schema({}), cv.only_with_arduino, - cv.only_on(["esp32", "esp8266"]), + cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), ) @coroutine_with_priority(200.0) async def to_code(config): - if CORE.is_esp32: + if CORE.is_esp32 or CORE.is_libretiny: # https://github.com/esphome/AsyncTCP/blob/master/library.json - cg.add_library("esphome/AsyncTCP-esphome", "1.2.2") + cg.add_library("esphome/AsyncTCP-esphome", "2.0.1") elif CORE.is_esp8266: # https://github.com/esphome/ESPAsyncTCP cg.add_library("esphome/ESPAsyncTCP-esphome", "1.2.3") diff --git a/esphome/components/bk72xx/__init__.py b/esphome/components/bk72xx/__init__.py new file mode 100644 index 0000000000..6737631ac7 --- /dev/null +++ b/esphome/components/bk72xx/__init__.py @@ -0,0 +1,51 @@ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. +# For custom pin validators, put validate_pin() or validate_usage() +# in gpio.py file in this directory. +# For changing schema/pin schema, put COMPONENT_SCHEMA or COMPONENT_PIN_SCHEMA +# in schema.py file in this directory. + +from esphome import pins +from esphome.components import libretiny +from esphome.components.libretiny.const import ( + COMPONENT_BK72XX, + KEY_COMPONENT_DATA, + KEY_LIBRETINY, + LibreTinyComponent, +) +from esphome.core import CORE + +from .boards import BK72XX_BOARDS, BK72XX_BOARD_PINS + +CODEOWNERS = ["@kuba2k2"] +AUTO_LOAD = ["libretiny"] + +COMPONENT_DATA = LibreTinyComponent( + name=COMPONENT_BK72XX, + boards=BK72XX_BOARDS, + board_pins=BK72XX_BOARD_PINS, + pin_validation=None, + usage_validation=None, +) + + +def _set_core_data(config): + CORE.data[KEY_LIBRETINY] = {} + CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA + return config + + +CONFIG_SCHEMA = libretiny.BASE_SCHEMA + +PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA + +CONFIG_SCHEMA.prepend_extra(_set_core_data) + + +async def to_code(config): + return await libretiny.component_to_code(config) + + +@pins.PIN_SCHEMA_REGISTRY.register("bk72xx", PIN_SCHEMA) +async def pin_to_code(config): + return await libretiny.gpio.component_pin_to_code(config) diff --git a/esphome/components/bk72xx/boards.py b/esphome/components/bk72xx/boards.py new file mode 100644 index 0000000000..8e3e8a97a2 --- /dev/null +++ b/esphome/components/bk72xx/boards.py @@ -0,0 +1,1264 @@ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. + +from esphome.components.libretiny.const import ( + FAMILY_BK7231N, + FAMILY_BK7231Q, + FAMILY_BK7231T, + FAMILY_BK7251, +) + +BK72XX_BOARDS = { + "cb1s": { + "name": "CB1S Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cb2l": { + "name": "CB2L Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cb2s": { + "name": "CB2S Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cb3l": { + "name": "CB3L Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cb3s": { + "name": "CB3S Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cb3se": { + "name": "CB3SE Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cblc5": { + "name": "CBLC5 Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "cbu": { + "name": "CBU Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "generic-bk7231n-qfn32-tuya": { + "name": "Generic - BK7231N (Tuya QFN32)", + "family": FAMILY_BK7231N, + }, + "generic-bk7231t-qfn32-tuya": { + "name": "Generic - BK7231T (Tuya QFN32)", + "family": FAMILY_BK7231T, + }, + "generic-bk7252": { + "name": "Generic - BK7252", + "family": FAMILY_BK7251, + }, + "lsc-lma35-t": { + "name": "LSC LMA35 BK7231T", + "family": FAMILY_BK7231T, + }, + "lsc-lma35": { + "name": "LSC LMA35 BK7231N", + "family": FAMILY_BK7231N, + }, + "wa2": { + "name": "WA2 Wi-Fi Module", + "family": FAMILY_BK7231Q, + }, + "wb1s": { + "name": "WB1S Wi-Fi Module", + "family": FAMILY_BK7231T, + }, + "wb2l-m1": { + "name": "WB2L_M1 Wi-Fi Module", + "family": FAMILY_BK7231N, + }, + "wb2l": { + "name": "WB2L Wi-Fi Module", + "family": FAMILY_BK7231T, + }, + "wb2s": { + "name": "WB2S Wi-Fi Module", + "family": FAMILY_BK7231T, + }, + "wb3l": { + "name": "WB3L Wi-Fi Module", + "family": FAMILY_BK7231T, + }, + "wb3s": { + "name": "WB3S Wi-Fi Module", + "family": FAMILY_BK7231T, + }, + "wblc5": { + "name": "WBLC5 Wi-Fi Module", + "family": FAMILY_BK7231T, + }, +} + +BK72XX_BOARD_PINS = { + "cb1s": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 11, + "D1": 10, + "D2": 6, + "D3": 7, + "D4": 0, + "D5": 9, + "D6": 8, + "D7": 1, + "D8": 24, + "D9": 26, + "D10": 23, + "D11": 20, + "D12": 21, + "D13": 22, + "A0": 23, + }, + "cb2l": { + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_TX": 0, + "P0": 0, + "P6": 6, + "P7": 7, + "P8": 8, + "P10": 10, + "P11": 11, + "P21": 21, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "SCL2": 0, + "SDA1": 21, + "TX1": 11, + "TX2": 0, + "D0": 8, + "D1": 7, + "D2": 6, + "D3": 26, + "D4": 24, + "D5": 10, + "D6": 0, + "D7": 11, + "D8": 21, + }, + "cb2s": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P10": 10, + "P11": 11, + "P21": 21, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 6, + "D1": 7, + "D2": 8, + "D3": 23, + "D4": 10, + "D5": 11, + "D6": 24, + "D7": 26, + "D8": 0, + "D9": 1, + "D10": 21, + "A0": 23, + }, + "cb3l": { + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P21": 21, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "SCK": 14, + "SCL2": 0, + "SDA1": 21, + "TX1": 11, + "TX2": 0, + "D0": 23, + "D1": 14, + "D2": 26, + "D3": 24, + "D4": 6, + "D5": 9, + "D6": 0, + "D7": 21, + "D8": 8, + "D9": 7, + "D10": 10, + "D11": 11, + "A0": 23, + }, + "cb3s": { + "WIRE1_SCL": 20, + "WIRE1_SDA_0": 21, + "WIRE1_SDA_1": 21, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "TX1": 11, + "TX2": 0, + "D0": 23, + "D1": 14, + "D2": 26, + "D3": 24, + "D4": 6, + "D5": 9, + "D6": 0, + "D7": 21, + "D8": 8, + "D9": 7, + "D10": 10, + "D11": 11, + "D12": 22, + "D13": 20, + "A0": 23, + }, + "cb3se": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "CS": 15, + "MISO": 17, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P15": 15, + "P16": 16, + "P17": 17, + "P20": 20, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 23, + "D1": 14, + "D2": 26, + "D3": 24, + "D4": 6, + "D5": 9, + "D6": 0, + "D7": 1, + "D8": 8, + "D9": 7, + "D10": 10, + "D11": 11, + "D12": 15, + "D13": 22, + "D14": 20, + "D15": 17, + "D16": 16, + "A0": 23, + }, + "cblc5": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "P0": 0, + "P1": 1, + "P6": 6, + "P10": 10, + "P11": 11, + "P21": 21, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 24, + "D1": 6, + "D2": 26, + "D3": 11, + "D4": 10, + "D5": 1, + "D6": 0, + "D7": 21, + }, + "cbu": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "CS": 15, + "MISO": 17, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P15": 15, + "P16": 16, + "P17": 17, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "P28": 28, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 14, + "D1": 16, + "D2": 20, + "D3": 22, + "D4": 23, + "D5": 1, + "D6": 0, + "D7": 8, + "D8": 7, + "D9": 6, + "D10": 26, + "D11": 24, + "D12": 11, + "D13": 10, + "D14": 28, + "D15": 9, + "D16": 17, + "D17": 15, + "D18": 21, + "A0": 23, + }, + "generic-bk7231n-qfn32-tuya": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "CS": 15, + "MISO": 17, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P15": 15, + "P16": 16, + "P17": 17, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "P28": 28, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 0, + "D1": 1, + "D2": 6, + "D3": 7, + "D4": 8, + "D5": 9, + "D6": 10, + "D7": 11, + "D8": 14, + "D9": 15, + "D10": 16, + "D11": 17, + "D12": 20, + "D13": 21, + "D14": 22, + "D15": 23, + "D16": 24, + "D17": 26, + "D18": 28, + "A0": 23, + }, + "generic-bk7231t-qfn32-tuya": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "CS": 15, + "MISO": 17, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P15": 15, + "P16": 16, + "P17": 17, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "P28": 28, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 0, + "D1": 1, + "D2": 6, + "D3": 7, + "D4": 8, + "D5": 9, + "D6": 10, + "D7": 11, + "D8": 14, + "D9": 15, + "D10": 16, + "D11": 17, + "D12": 20, + "D13": 21, + "D14": 22, + "D15": 23, + "D16": 24, + "D17": 26, + "D18": 28, + "A0": 23, + }, + "generic-bk7252": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_CTS": 12, + "SERIAL1_RTS": 13, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC1": 4, + "ADC2": 5, + "ADC3": 23, + "ADC4": 2, + "ADC5": 3, + "ADC6": 12, + "ADC7": 13, + "CS": 15, + "CTS1": 12, + "MISO": 17, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P2": 2, + "P3": 3, + "P4": 4, + "P5": 5, + "P6": 6, + "P7": 7, + "P10": 10, + "P11": 11, + "P12": 12, + "P13": 13, + "P14": 14, + "P15": 15, + "P16": 16, + "P17": 17, + "P18": 18, + "P19": 19, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P25": 25, + "P26": 26, + "P27": 27, + "P28": 28, + "P29": 29, + "P30": 30, + "P31": 31, + "P32": 32, + "P33": 33, + "P34": 34, + "P35": 35, + "P36": 36, + "P37": 37, + "P38": 38, + "P39": 39, + "PWM0": 6, + "PWM1": 7, + "PWM4": 24, + "PWM5": 26, + "RTS1": 13, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 0, + "D1": 1, + "D2": 2, + "D3": 3, + "D4": 4, + "D5": 5, + "D6": 6, + "D7": 7, + "D8": 10, + "D9": 11, + "D10": 12, + "D11": 13, + "D12": 14, + "D13": 15, + "D14": 16, + "D15": 17, + "D16": 18, + "D17": 19, + "D18": 20, + "D19": 21, + "D20": 22, + "D21": 23, + "D22": 24, + "D23": 25, + "D24": 26, + "D25": 27, + "D26": 28, + "D27": 29, + "D28": 30, + "D29": 31, + "D30": 32, + "D31": 33, + "D32": 34, + "D33": 35, + "D34": 36, + "D35": 37, + "D36": 38, + "D37": 39, + "A1": 4, + "A2": 5, + "A3": 23, + "A4": 3, + "A5": 2, + "A6": 12, + "A7": 13, + }, + "lsc-lma35-t": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P16": 16, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 26, + "D1": 14, + "D2": 16, + "D3": 24, + "D4": 22, + "D5": 0, + "D6": 23, + "D7": 8, + "D8": 9, + "D9": 21, + "D10": 6, + "D11": 7, + "D12": 10, + "D13": 11, + "D14": 1, + "A0": 23, + }, + "lsc-lma35": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P16": 16, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 26, + "D1": 14, + "D2": 16, + "D3": 24, + "D4": 22, + "D5": 0, + "D6": 23, + "D7": 8, + "D8": 9, + "D9": 21, + "D10": 6, + "D11": 7, + "D12": 10, + "D13": 11, + "D14": 1, + "A0": 23, + }, + "wa2": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_TX": 0, + "ADC1": 4, + "ADC3": 23, + "P0": 0, + "P4": 4, + "P6": 6, + "P7": 7, + "P8": 8, + "P10": 10, + "P11": 11, + "P18": 18, + "P19": 19, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM4": 18, + "PWM5": 19, + "RX1": 10, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "TX1": 11, + "TX2": 0, + "D0": 8, + "D1": 7, + "D2": 6, + "D3": 23, + "D4": 10, + "D5": 11, + "D6": 18, + "D7": 19, + "D8": 20, + "D9": 4, + "D10": 0, + "D11": 21, + "D12": 22, + "A0": 23, + }, + "wb1s": { + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL2": 0, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 11, + "D1": 10, + "D2": 26, + "D3": 24, + "D4": 0, + "D5": 8, + "D6": 7, + "D7": 1, + "D8": 9, + "D9": 6, + "D10": 23, + "A0": 23, + }, + "wb2l-m1": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P10": 10, + "P11": 11, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 8, + "D1": 7, + "D2": 6, + "D3": 26, + "D4": 24, + "D5": 10, + "D6": 11, + "D7": 1, + "D8": 0, + "D9": 20, + "D10": 21, + "D11": 23, + "D12": 22, + "A0": 23, + }, + "wb2l": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P10": 10, + "P11": 11, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 8, + "D1": 7, + "D2": 6, + "D3": 26, + "D4": 24, + "D5": 10, + "D6": 11, + "D7": 1, + "D8": 0, + "D9": 20, + "D10": 21, + "D11": 23, + "D12": 22, + "A0": 23, + }, + "wb2s": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 8, + "D1": 7, + "D2": 6, + "D3": 23, + "D4": 10, + "D5": 11, + "D6": 24, + "D7": 26, + "D8": 20, + "D9": 9, + "D10": 1, + "D11": 0, + "D12": 21, + "D13": 22, + "A0": 23, + }, + "wb3l": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "MOSI": 16, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P16": 16, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 23, + "D1": 14, + "D2": 26, + "D3": 24, + "D4": 6, + "D5": 9, + "D6": 0, + "D7": 16, + "D8": 8, + "D9": 7, + "D10": 10, + "D11": 11, + "D12": 22, + "D13": 21, + "D14": 20, + "D15": 1, + "A0": 23, + }, + "wb3s": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P7": 7, + "P8": 8, + "P9": 9, + "P10": 10, + "P11": 11, + "P14": 14, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM1": 7, + "PWM2": 8, + "PWM3": 9, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCK": 14, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 23, + "D1": 14, + "D2": 26, + "D3": 24, + "D4": 6, + "D5": 7, + "D6": 0, + "D7": 1, + "D8": 9, + "D9": 8, + "D10": 10, + "D11": 11, + "D12": 22, + "D13": 21, + "D14": 20, + "A0": 23, + }, + "wblc5": { + "WIRE1_SCL": 20, + "WIRE1_SDA": 21, + "WIRE2_SCL": 0, + "WIRE2_SDA": 1, + "SERIAL1_RX": 10, + "SERIAL1_TX": 11, + "SERIAL2_RX": 1, + "SERIAL2_TX": 0, + "ADC3": 23, + "P0": 0, + "P1": 1, + "P6": 6, + "P10": 10, + "P11": 11, + "P20": 20, + "P21": 21, + "P22": 22, + "P23": 23, + "P24": 24, + "P26": 26, + "PWM0": 6, + "PWM4": 24, + "PWM5": 26, + "RX1": 10, + "RX2": 1, + "SCL1": 20, + "SCL2": 0, + "SDA1": 21, + "SDA2": 1, + "TX1": 11, + "TX2": 0, + "D0": 24, + "D1": 6, + "D2": 26, + "D3": 10, + "D4": 11, + "D5": 1, + "D6": 0, + "D7": 20, + "D8": 21, + "D9": 22, + "D10": 23, + "A0": 23, + }, +} + +BOARDS = BK72XX_BOARDS diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index db4a17f6f7..6af741c6b3 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -21,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ), } ).extend(cv.COMPONENT_SCHEMA), - cv.only_on(["esp32", "esp8266"]), + cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), ) @@ -39,3 +39,5 @@ async def to_code(config): cg.add_library("WiFi", None) if CORE.is_esp8266: cg.add_library("DNSServer", None) + if CORE.is_libretiny: + cg.add_library("DNSServer", None) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 5ee1960267..52ee4b070e 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -28,7 +28,7 @@ #ifdef USE_ARDUINO #ifdef USE_RP2040 #include -#else +#elif defined(USE_ESP32) || defined(USE_ESP8266) #include #endif #endif @@ -45,6 +45,8 @@ static uint32_t get_free_heap() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); #elif defined(USE_RP2040) return rp2040.getFreeHeap(); +#elif defined(USE_LIBRETINY) + return lt_heap_get_free(); #endif } @@ -75,7 +77,7 @@ void DebugComponent::dump_config() { this->free_heap_ = get_free_heap(); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); -#if defined(USE_ARDUINO) && !defined(USE_RP2040) +#if defined(USE_ARDUINO) && (defined(USE_ESP32) || defined(USE_ESP8266)) const char *flash_mode; switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) case FM_QIO: @@ -107,7 +109,7 @@ void DebugComponent::dump_config() { device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT device_info += flash_mode; -#endif // USE_ARDUINO +#endif // USE_ARDUINO && (USE_ESP32 || USE_ESP8266) #ifdef USE_ESP32 esp_chip_info_t info; @@ -340,6 +342,27 @@ void DebugComponent::dump_config() { device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); #endif // USE_RP2040 +#ifdef USE_LIBRETINY + ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); + ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); + ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); + ESP_LOGD(TAG, "Board: %s", lt_get_board_code()); + ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024); + ESP_LOGD(TAG, "Reset Reason: %s", lt_get_reboot_reason_name(lt_get_reboot_reason())); + + device_info += "|Version: "; + device_info += LT_BANNER_STR + 10; + device_info += "|Reset Reason: "; + device_info += lt_get_reboot_reason_name(lt_get_reboot_reason()); + device_info += "|Chip Name: "; + device_info += lt_cpu_get_model_name(); + device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id()); + device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB"; + device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB"; + + reset_reason = lt_get_reboot_reason_name(lt_get_reboot_reason()); +#endif // USE_LIBRETINY + #ifdef USE_TEXT_SENSOR if (this->device_info_ != nullptr) { if (device_info.length() > 255) @@ -384,6 +407,8 @@ void DebugComponent::update() { this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); #elif defined(USE_ESP32) this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); +#elif defined(USE_LIBRETINY) + this->block_sensor_->publish_state(lt_heap_get_max_alloc()); #endif } diff --git a/esphome/components/esp8266/gpio.py b/esphome/components/esp8266/gpio.py index d4b2078524..e75578cc16 100644 --- a/esphome/components/esp8266/gpio.py +++ b/esphome/components/esp8266/gpio.py @@ -2,6 +2,7 @@ import logging from dataclasses import dataclass from esphome.const import ( + CONF_ANALOG, CONF_ID, CONF_INPUT, CONF_INVERTED, @@ -140,7 +141,6 @@ def validate_supports(value): return value -CONF_ANALOG = "analog" ESP8266_PIN_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(ESP8266GPIOPin), diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index a04e63e789..e38cfd23fa 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -42,23 +42,26 @@ pin_with_input_and_output_support = cv.All( ) -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): _bus_declare_type, - cv.Optional(CONF_SDA, default="SDA"): pin_with_input_and_output_support, - cv.SplitDefault(CONF_SDA_PULLUP_ENABLED, esp32_idf=True): cv.All( - cv.only_with_esp_idf, cv.boolean - ), - cv.Optional(CONF_SCL, default="SCL"): pin_with_input_and_output_support, - cv.SplitDefault(CONF_SCL_PULLUP_ENABLED, esp32_idf=True): cv.All( - cv.only_with_esp_idf, cv.boolean - ), - cv.Optional(CONF_FREQUENCY, default="50kHz"): cv.All( - cv.frequency, cv.Range(min=0, min_included=False) - ), - cv.Optional(CONF_SCAN, default=True): cv.boolean, - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): _bus_declare_type, + cv.Optional(CONF_SDA, default="SDA"): pin_with_input_and_output_support, + cv.SplitDefault(CONF_SDA_PULLUP_ENABLED, esp32_idf=True): cv.All( + cv.only_with_esp_idf, cv.boolean + ), + cv.Optional(CONF_SCL, default="SCL"): pin_with_input_and_output_support, + cv.SplitDefault(CONF_SCL_PULLUP_ENABLED, esp32_idf=True): cv.All( + cv.only_with_esp_idf, cv.boolean + ), + cv.Optional(CONF_FREQUENCY, default="50kHz"): cv.All( + cv.frequency, cv.Range(min=0, min_included=False) + ), + cv.Optional(CONF_SCAN, default=True): cv.boolean, + } + ).extend(cv.COMPONENT_SCHEMA), + cv.only_on(["esp32", "esp8266", "rp2040"]), +) @coroutine_with_priority(1.0) diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index f27d441804..bef494b64d 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -29,6 +29,8 @@ std::string build_json(const json_build_t &f) { const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); #elif defined(USE_RP2040) const size_t free_heap = rp2040.getFreeHeap(); +#elif defined(USE_LIBRETINY) + const size_t free_heap = lt_heap_get_free(); #endif size_t request_size = std::min(free_heap, (size_t) 512); @@ -71,6 +73,8 @@ void parse_json(const std::string &data, const json_parse_t &f) { const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); #elif defined(USE_RP2040) const size_t free_heap = rp2040.getFreeHeap(); +#elif defined(USE_LIBRETINY) + const size_t free_heap = lt_heap_get_free(); #endif bool pass = false; size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5)); diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py new file mode 100644 index 0000000000..c6c63b48c8 --- /dev/null +++ b/esphome/components/libretiny/__init__.py @@ -0,0 +1,336 @@ +import json +import logging +from os.path import dirname, isfile, join + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import ( + CONF_BOARD, + CONF_COMPONENT_ID, + CONF_DEBUG, + CONF_FAMILY, + CONF_FRAMEWORK, + CONF_ID, + CONF_NAME, + CONF_OPTIONS, + CONF_PROJECT, + CONF_SOURCE, + CONF_VERSION, + KEY_CORE, + KEY_FRAMEWORK_VERSION, + KEY_TARGET_FRAMEWORK, + KEY_TARGET_PLATFORM, + __version__, +) +from esphome.core import CORE + +from . import gpio # noqa +from .const import ( + CONF_GPIO_RECOVER, + CONF_LOGLEVEL, + CONF_SDK_SILENT, + CONF_UART_PORT, + FAMILIES, + FAMILY_COMPONENT, + FAMILY_FRIENDLY, + KEY_BOARD, + KEY_COMPONENT, + KEY_COMPONENT_DATA, + KEY_FAMILY, + KEY_LIBRETINY, + LT_DEBUG_MODULES, + LT_LOGLEVELS, + LibreTinyComponent, + LTComponent, +) + +_LOGGER = logging.getLogger(__name__) +CODEOWNERS = ["@kuba2k2"] +AUTO_LOAD = [] + + +def _detect_variant(value): + if KEY_LIBRETINY not in CORE.data: + raise cv.Invalid("Family component didn't populate core data properly!") + component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] + board = value[CONF_BOARD] + # read board-default family if not specified + if CONF_FAMILY not in value: + if board not in component.boards: + raise cv.Invalid( + "This board is unknown, please set the family manually. " + "Also, make sure the chosen chip component is correct.", + path=[CONF_BOARD], + ) + value = value.copy() + value[CONF_FAMILY] = component.boards[board][KEY_FAMILY] + # read component name matching this family + value[CONF_COMPONENT_ID] = FAMILY_COMPONENT[value[CONF_FAMILY]] + # make sure the chosen component matches the family + if value[CONF_COMPONENT_ID] != component.name: + raise cv.Invalid( + f"The chosen family doesn't belong to '{component.name}' component. The correct component is '{value[CONF_COMPONENT_ID]}'", + path=[CONF_FAMILY], + ) + # warn anyway if the board wasn't found + if board not in component.boards: + _LOGGER.warning( + "This board is unknown. Make sure the chosen chip component is correct.", + ) + return value + + +def _update_core_data(config): + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = config[CONF_COMPONENT_ID] + CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" + CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( + config[CONF_FRAMEWORK][CONF_VERSION] + ) + CORE.data[KEY_LIBRETINY][KEY_BOARD] = config[CONF_BOARD] + CORE.data[KEY_LIBRETINY][KEY_COMPONENT] = config[CONF_COMPONENT_ID] + CORE.data[KEY_LIBRETINY][KEY_FAMILY] = config[CONF_FAMILY] + return config + + +def get_libretiny_component(core_obj=None): + return (core_obj or CORE).data[KEY_LIBRETINY][KEY_COMPONENT] + + +def get_libretiny_family(core_obj=None): + return (core_obj or CORE).data[KEY_LIBRETINY][KEY_FAMILY] + + +def only_on_family(*, supported=None, unsupported=None): + """Config validator for features only available on some LibreTiny families.""" + if supported is not None and not isinstance(supported, list): + supported = [supported] + if unsupported is not None and not isinstance(unsupported, list): + unsupported = [unsupported] + + def validator_(obj): + family = get_libretiny_family() + if supported is not None and family not in supported: + raise cv.Invalid( + f"This feature is only available on {', '.join(supported)}" + ) + if unsupported is not None and family in unsupported: + raise cv.Invalid( + f"This feature is not available on {', '.join(unsupported)}" + ) + return obj + + return validator_ + + +def get_download_types(storage_json=None): + types = [ + { + "title": "UF2 package (recommended)", + "description": "For flashing via web_server OTA or with ltchiptool (UART)", + "file": "firmware.uf2", + "download": f"{storage_json.name}.uf2", + }, + ] + + build_dir = dirname(storage_json.firmware_bin_path) + outputs = join(build_dir, "firmware.json") + if not isfile(outputs): + return types + with open(outputs, encoding="utf-8") as f: + outputs = json.load(f) + for output in outputs: + if not output["public"]: + continue + suffix = output["filename"].partition(".")[2] + suffix = f"-{suffix}" if "." in suffix else f".{suffix}" + types.append( + { + "title": output["title"], + "description": output["description"], + "file": output["filename"], + "download": storage_json.name + suffix, + } + ) + return types + + +def _notify_old_style(config): + if config: + raise cv.Invalid( + "The LibreTiny component is now split between supported chip families.\n" + "Migrate your config file to include a chip-based configuration, " + "instead of the 'libretiny:' block.\n" + "For example 'bk72xx:' or 'rtl87xx:'." + ) + return config + + +# NOTE: Keep this in mind when updating the recommended version: +# * For all constants below, update platformio.ini (in this repo) +ARDUINO_VERSIONS = { + "dev": (cv.Version(0, 0, 0), "https://github.com/kuba2k2/libretiny.git"), + "latest": (cv.Version(0, 0, 0), None), + "recommended": (cv.Version(1, 3, 0), None), +} + + +def _check_framework_version(value): + value = value.copy() + + if value[CONF_VERSION] in ARDUINO_VERSIONS: + if CONF_SOURCE in value: + raise cv.Invalid( + "Framework version needs to be explicitly specified when custom source is used." + ) + + version, source = ARDUINO_VERSIONS[value[CONF_VERSION]] + else: + version = cv.Version.parse(cv.version_number(value[CONF_VERSION])) + source = value.get(CONF_SOURCE, None) + + value[CONF_VERSION] = str(version) + value[CONF_SOURCE] = source + + return value + + +def _check_debug_order(value): + debug = value[CONF_DEBUG] + if "NONE" in debug and "NONE" in debug[1:]: + raise cv.Invalid( + "'none' has to be specified before other modules, and only once", + path=[CONF_DEBUG], + ) + return value + + +FRAMEWORK_SCHEMA = cv.All( + cv.Schema( + { + cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, + cv.Optional(CONF_SOURCE): cv.string_strict, + cv.Optional(CONF_LOGLEVEL, default="warn"): ( + cv.one_of(*LT_LOGLEVELS, upper=True) + ), + cv.Optional(CONF_DEBUG, default=[]): cv.ensure_list( + cv.one_of("NONE", *LT_DEBUG_MODULES, upper=True) + ), + cv.Optional(CONF_SDK_SILENT, default="all"): ( + cv.one_of("all", "auto", "none", lower=True) + ), + cv.Optional(CONF_UART_PORT, default=None): cv.one_of(0, 1, 2, int=True), + cv.Optional(CONF_GPIO_RECOVER, default=True): cv.boolean, + cv.Optional(CONF_OPTIONS, default={}): { + cv.string_strict: cv.string, + }, + } + ), + _check_framework_version, + _check_debug_order, +) + +CONFIG_SCHEMA = cv.All(_notify_old_style) + +BASE_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(LTComponent), + cv.Required(CONF_BOARD): cv.string_strict, + cv.Optional(CONF_FAMILY): cv.one_of(*FAMILIES, upper=True), + cv.Optional(CONF_FRAMEWORK, default={}): FRAMEWORK_SCHEMA, + }, +) + +BASE_SCHEMA.add_extra(_detect_variant) +BASE_SCHEMA.add_extra(_update_core_data) + + +# pylint: disable=use-dict-literal +async def component_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + + # setup board config + cg.add_platformio_option("board", config[CONF_BOARD]) + cg.add_build_flag("-DUSE_LIBRETINY") + cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}") + cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}") + cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) + cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]]) + + # force using arduino framework + cg.add_platformio_option("framework", "arduino") + cg.add_build_flag("-DUSE_ARDUINO") + + # disable library compatibility checks + cg.add_platformio_option("lib_ldf_mode", "off") + # include in every file + cg.add_platformio_option("build_src_flags", "-include Arduino.h") + # dummy version code + cg.add_define("USE_ARDUINO_VERSION_CODE", cg.RawExpression("VERSION_CODE(0, 0, 0)")) + # decrease web server stack size (16k words -> 4k words) + cg.add_build_flag("-DCONFIG_ASYNC_TCP_STACK_SIZE=4096") + + # build framework version + # if platform version is a valid version constraint, prefix the default package + framework = config[CONF_FRAMEWORK] + cv.platformio_version_constraint(framework[CONF_VERSION]) + if str(framework[CONF_VERSION]) != "0.0.0": + cg.add_platformio_option("platform", f"libretiny @ {framework[CONF_VERSION]}") + elif framework[CONF_SOURCE]: + cg.add_platformio_option("platform", framework[CONF_SOURCE]) + else: + cg.add_platformio_option("platform", "libretiny") + + # apply LibreTiny options from framework: block + # setup LT logger to work nicely with ESPHome logger + lt_options = dict( + LT_LOGLEVEL="LT_LEVEL_" + framework[CONF_LOGLEVEL], + LT_LOGGER_CALLER=0, + LT_LOGGER_TASK=0, + LT_LOGGER_COLOR=1, + LT_USE_TIME=1, + ) + # enable/disable per-module debugging + for module in framework[CONF_DEBUG]: + if module == "NONE": + # disable all modules + for module in LT_DEBUG_MODULES: + lt_options[f"LT_DEBUG_{module}"] = 0 + else: + # enable one module + lt_options[f"LT_DEBUG_{module}"] = 1 + # set SDK silencing mode + if framework[CONF_SDK_SILENT] == "all": + lt_options["LT_UART_SILENT_ENABLED"] = 1 + lt_options["LT_UART_SILENT_ALL"] = 1 + elif framework[CONF_SDK_SILENT] == "auto": + lt_options["LT_UART_SILENT_ENABLED"] = 1 + lt_options["LT_UART_SILENT_ALL"] = 0 + else: + lt_options["LT_UART_SILENT_ENABLED"] = 0 + lt_options["LT_UART_SILENT_ALL"] = 0 + # set default UART port + if framework[CONF_UART_PORT] is not None: + lt_options["LT_UART_DEFAULT_PORT"] = framework[CONF_UART_PORT] + # add custom options + lt_options.update(framework[CONF_OPTIONS]) + + # apply ESPHome options from framework: block + cg.add_define("LT_GPIO_RECOVER", int(framework[CONF_GPIO_RECOVER])) + + # build PlatformIO compiler flags + for name, value in sorted(lt_options.items()): + cg.add_build_flag(f"-D{name}={value}") + + # custom output firmware name and version + if CONF_PROJECT in config: + cg.add_platformio_option( + "custom_fw_name", "esphome." + config[CONF_PROJECT][CONF_NAME] + ) + cg.add_platformio_option( + "custom_fw_version", config[CONF_PROJECT][CONF_VERSION] + ) + else: + cg.add_platformio_option("custom_fw_name", "esphome") + cg.add_platformio_option("custom_fw_version", __version__) + + await cg.register_component(var, config) diff --git a/esphome/components/libretiny/const.py b/esphome/components/libretiny/const.py new file mode 100644 index 0000000000..525d8b7786 --- /dev/null +++ b/esphome/components/libretiny/const.py @@ -0,0 +1,90 @@ +from dataclasses import dataclass +from typing import Callable + +import esphome.codegen as cg + + +@dataclass +class LibreTinyComponent: + name: str + boards: dict[str, dict[str, str]] + board_pins: dict[str, dict[str, int]] + pin_validation: Callable[[int], int] + usage_validation: Callable[[dict], dict] + + +CONF_LIBRETINY = "libretiny" +CONF_LOGLEVEL = "loglevel" +CONF_SDK_SILENT = "sdk_silent" +CONF_GPIO_RECOVER = "gpio_recover" +CONF_UART_PORT = "uart_port" + +LT_LOGLEVELS = [ + "VERBOSE", + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL", + "NONE", +] + +LT_DEBUG_MODULES = [ + "WIFI", + "CLIENT", + "SERVER", + "SSL", + "OTA", + "FDB", + "MDNS", + "LWIP", + "LWIP_ASSERT", +] + +KEY_LIBRETINY = "libretiny" +KEY_BOARD = "board" +KEY_COMPONENT = "component" +KEY_COMPONENT_DATA = "component_data" +KEY_FAMILY = "family" + +# COMPONENTS - auto-generated! Do not modify this block. +COMPONENT_BK72XX = "bk72xx" +COMPONENT_RTL87XX = "rtl87xx" +# COMPONENTS - end + +# FAMILIES - auto-generated! Do not modify this block. +FAMILY_BK7231N = "BK7231N" +FAMILY_BK7231Q = "BK7231Q" +FAMILY_BK7231T = "BK7231T" +FAMILY_BK7251 = "BK7251" +FAMILY_RTL8710B = "RTL8710B" +FAMILY_RTL8720C = "RTL8720C" +FAMILIES = [ + FAMILY_BK7231N, + FAMILY_BK7231Q, + FAMILY_BK7231T, + FAMILY_BK7251, + FAMILY_RTL8710B, + FAMILY_RTL8720C, +] +FAMILY_FRIENDLY = { + FAMILY_BK7231N: "BK7231N", + FAMILY_BK7231Q: "BK7231Q", + FAMILY_BK7231T: "BK7231T", + FAMILY_BK7251: "BK7251", + FAMILY_RTL8710B: "RTL8710B", + FAMILY_RTL8720C: "RTL8720C", +} +FAMILY_COMPONENT = { + FAMILY_BK7231N: COMPONENT_BK72XX, + FAMILY_BK7231Q: COMPONENT_BK72XX, + FAMILY_BK7231T: COMPONENT_BK72XX, + FAMILY_BK7251: COMPONENT_BK72XX, + FAMILY_RTL8710B: COMPONENT_RTL87XX, + FAMILY_RTL8720C: COMPONENT_RTL87XX, +} +# FAMILIES - end + +libretiny_ns = cg.esphome_ns.namespace("libretiny") +LTComponent = libretiny_ns.class_("LTComponent", cg.PollingComponent) diff --git a/esphome/components/libretiny/core.cpp b/esphome/components/libretiny/core.cpp new file mode 100644 index 0000000000..b22740f02a --- /dev/null +++ b/esphome/components/libretiny/core.cpp @@ -0,0 +1,40 @@ +#ifdef USE_LIBRETINY + +#include "core.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "preferences.h" + +void setup(); +void loop(); + +namespace esphome { + +void IRAM_ATTR HOT yield() { ::yield(); } +uint32_t IRAM_ATTR HOT millis() { return ::millis(); } +uint32_t IRAM_ATTR HOT micros() { return ::micros(); } +void IRAM_ATTR HOT delay(uint32_t ms) { ::delay(ms); } +void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { ::delayMicroseconds(us); } + +void arch_init() { + libretiny::setup_preferences(); + lt_wdt_enable(10000L); +#if LT_GPIO_RECOVER + lt_gpio_recover(); +#endif +} + +void arch_restart() { + lt_reboot(); + while (1) { + } +} +void IRAM_ATTR HOT arch_feed_wdt() { lt_wdt_feed(); } +uint32_t arch_get_cpu_cycle_count() { return lt_cpu_get_cycle_count(); } +uint32_t arch_get_cpu_freq_hz() { return lt_cpu_get_freq(); } +uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } + +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/core.h b/esphome/components/libretiny/core.h new file mode 100644 index 0000000000..9458df1f16 --- /dev/null +++ b/esphome/components/libretiny/core.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef USE_LIBRETINY + +#include + +namespace esphome { +namespace libretiny {} // namespace libretiny +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/generate_components.py b/esphome/components/libretiny/generate_components.py new file mode 100644 index 0000000000..ae55fd9e40 --- /dev/null +++ b/esphome/components/libretiny/generate_components.py @@ -0,0 +1,329 @@ +# Copyright (c) Kuba Szczodrzyński 2023-06-01. + +# pylint: skip-file +# flake8: noqa + +import json +import re +from pathlib import Path + +from black import FileMode, format_str +from ltchiptool import Board, Family +from ltchiptool.util.lvm import LVM + +BASE_CODE_INIT = """ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. +# For custom pin validators, put validate_pin() or validate_usage() +# in gpio.py file in this directory. +# For changing schema/pin schema, put COMPONENT_SCHEMA or COMPONENT_PIN_SCHEMA +# in schema.py file in this directory. + +from esphome import pins +from esphome.components import libretiny +from esphome.components.libretiny.const import ( + COMPONENT_{COMPONENT}, + KEY_COMPONENT_DATA, + KEY_LIBRETINY, + LibreTinyComponent, +) +from esphome.core import CORE + +{IMPORTS} + +CODEOWNERS = ["@kuba2k2"] +AUTO_LOAD = ["libretiny"] + +COMPONENT_DATA = LibreTinyComponent( + name=COMPONENT_{COMPONENT}, + boards={COMPONENT}_BOARDS, + board_pins={COMPONENT}_BOARD_PINS, + pin_validation={PIN_VALIDATION}, + usage_validation={USAGE_VALIDATION}, +) + + +def _set_core_data(config): + CORE.data[KEY_LIBRETINY] = {} + CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA + return config + + +CONFIG_SCHEMA = {SCHEMA} + +PIN_SCHEMA = {PIN_SCHEMA} + +CONFIG_SCHEMA.prepend_extra(_set_core_data) + + +async def to_code(config): + return await libretiny.component_to_code(config) + + +@pins.PIN_SCHEMA_REGISTRY.register("{COMPONENT_LOWER}", PIN_SCHEMA) +async def pin_to_code(config): + return await libretiny.gpio.component_pin_to_code(config) +""" + +BASE_CODE_BOARDS = """ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. + +from esphome.components.libretiny.const import {FAMILIES} + +{COMPONENT}_BOARDS = {BOARDS_JSON} + +{COMPONENT}_BOARD_PINS = {PINS_JSON} + +BOARDS = {COMPONENT}_BOARDS +""" + +# variable names in component extension code +VAR_SCHEMA = "COMPONENT_SCHEMA" +VAR_PIN_SCHEMA = "COMPONENT_PIN_SCHEMA" +VAR_GPIO_PIN = "validate_pin" +VAR_GPIO_USAGE = "validate_usage" + +# lines for code snippets +SCHEMA_BASE = "libretiny.BASE_SCHEMA" +SCHEMA_EXTRA = f"libretiny.BASE_SCHEMA.extend({VAR_SCHEMA})" +PIN_SCHEMA_BASE = "libretiny.gpio.BASE_PIN_SCHEMA" +PIN_SCHEMA_EXTRA = f"libretiny.BASE_PIN_SCHEMA.extend({VAR_PIN_SCHEMA})" + +# supported root components +COMPONENT_MAP = { + "rtl87xx": "realtek-amb", + "bk72xx": "beken-72xx", +} + + +def subst(code: str, key: str, value: str) -> str: + return code.replace(f"{{{key}}}", value) + + +def subst_all(code: str, value: str) -> str: + return re.sub(r"{.+?}", value, code) + + +def subst_many(code: str, *templates: tuple[str, str]) -> str: + while True: + prev_code = code + for key, value in templates: + code = subst(code, key, value) + if code == prev_code: + break + return code + + +def check_base_code(code: str) -> None: + code = subst_all(code, "DUMMY") + formatted = format_str(code, mode=FileMode()) + if code.strip() != formatted.strip(): + print(formatted) + raise RuntimeError("Base code is not formatted properly") + + +def write_component_code( + component_dir: Path, + component: str, +) -> None: + code = BASE_CODE_INIT + gpio_py = component_dir.joinpath("gpio.py") + schema_py = component_dir.joinpath("schema.py") + init_py = component_dir.joinpath("__init__.py") + + # gather all imports + imports = { + "gpio": set(), + "schema": set(), + "boards": {"{COMPONENT}_BOARDS", "{COMPONENT}_BOARD_PINS"}, + } + # substitution values + values = dict( + COMPONENT=component.upper(), + COMPONENT_LOWER=component.lower(), + SCHEMA=SCHEMA_BASE, + PIN_SCHEMA=PIN_SCHEMA_BASE, + PIN_VALIDATION="None", + USAGE_VALIDATION="None", + ) + + # parse gpio.py file to find custom validators + if gpio_py.is_file(): + gpio_code = gpio_py.read_text() + if VAR_GPIO_PIN in gpio_code: + values["PIN_VALIDATION"] = VAR_GPIO_PIN + imports["gpio"].add(VAR_GPIO_PIN) + + # parse schema.py file to find schema extension + if schema_py.is_file(): + schema_code = schema_py.read_text() + if VAR_SCHEMA in schema_code: + values["SCHEMA"] = SCHEMA_EXTRA + imports["schema"].add(VAR_SCHEMA) + if VAR_PIN_SCHEMA in schema_code: + values["PIN_SCHEMA"] = PIN_SCHEMA_EXTRA + imports["schema"].add(VAR_PIN_SCHEMA) + + # add import lines if needed + import_lines = "\n".join( + f"from .{m} import {', '.join(sorted(v))}" for m, v in imports.items() if v + ) + code = subst_many( + code, + ("IMPORTS", import_lines), + *values.items(), + ) + # format with black + code = format_str(code, mode=FileMode()) + # write back to file + init_py.write_text(code) + + +def write_component_boards( + component_dir: Path, + component: str, + boards: list[Board], +) -> list[Family]: + code = BASE_CODE_BOARDS + variants_dir = Path(LVM.path(), "boards", "variants") + boards_py = component_dir.joinpath("boards.py") + pin_regex = r"#define PIN_(\w+)\s+(\d+)" + pin_number_regex = r"0*(\d+)$" + + # families to import + families = set() + # found root families + root_families = [] + # substitution values + values = dict( + COMPONENT=component.upper(), + ) + # resulting JSON objects + boards_json = {} + pins_json = {} + + # go through all boards found for this root family + for board in boards: + family = "FAMILY_" + board.family.short_name + boards_json[board.name] = { + "name": board.title, + "family": family, + } + families.add(family) + if board.family not in root_families: + root_families.append(board.family) + + board_h = variants_dir.joinpath(f"{board.name}.h") + board_code = board_h.read_text() + board_pins = {} + for match in re.finditer(pin_regex, board_code): + pin_name = match[1] + pin_value = match[2] + board_pins[pin_name] = int(pin_value) + # trim leading zeroes in GPIO numbers + pin_name = re.sub(pin_number_regex, r"\1", pin_name) + board_pins[pin_name] = int(pin_value) + pins_json[board.name] = board_pins + + # make the JSONs format as non-inline + boards_json = json.dumps(boards_json).replace("}", ",}") + pins_json = json.dumps(pins_json).replace("}", ",}") + # remove quotes from family constants + for family in families: + boards_json = boards_json.replace(f'"{family}"', family) + code = subst_many( + code, + ("FAMILIES", ", ".join(sorted(families))), + ("BOARDS_JSON", boards_json), + ("PINS_JSON", pins_json), + *values.items(), + ) + # format with black + code = format_str(code, mode=FileMode()) + # write back to file + boards_py.write_text(code) + return root_families + + +def write_const( + components_dir: Path, + components: set[str], + families: dict[str, str], +) -> None: + const_py = components_dir.joinpath("libretiny").joinpath("const.py") + if not const_py.is_file(): + raise FileNotFoundError(const_py) + code = const_py.read_text() + components = sorted(components) + v2f = families + families = sorted(families) + + # regex for finding the component list block + comp_regex = r"(# COMPONENTS.+?\n)(.*?)(\n# COMPONENTS)" + # build component constants + comp_str = "\n".join(f'COMPONENT_{f} = "{f.lower()}"' for f in components) + # replace the 2nd regex group only + repl = lambda m: m.group(1) + comp_str + m.group(3) + code = re.sub(comp_regex, repl, code, flags=re.DOTALL | re.MULTILINE) + + # regex for finding the family list block + fam_regex = r"(# FAMILIES.+?\n)(.*?)(\n# FAMILIES)" + # build family constants + fam_defs = "\n".join(f'FAMILY_{v} = "{v}"' for v in families) + fam_list = ", ".join(f"FAMILY_{v}" for v in families) + fam_friendly = ", ".join(f'FAMILY_{v}: "{v}"' for v in families) + fam_component = ", ".join(f"FAMILY_{v}: COMPONENT_{v2f[v]}" for v in families) + fam_lines = [ + fam_defs, + "FAMILIES = [", + fam_list, + ",]", + "FAMILY_FRIENDLY = {", + fam_friendly, + ",}", + "FAMILY_COMPONENT = {", + fam_component, + ",}", + ] + var_str = "\n".join(fam_lines) + # replace the 2nd regex group only + repl = lambda m: m.group(1) + var_str + m.group(3) + code = re.sub(fam_regex, repl, code, flags=re.DOTALL | re.MULTILINE) + + # format with black + code = format_str(code, mode=FileMode()) + # write back to file + const_py.write_text(code) + + +if __name__ == "__main__": + # safety check if code is properly formatted + check_base_code(BASE_CODE_INIT) + # list all boards from ltchiptool + components_dir = Path(__file__).parent.parent + boards = [Board(b) for b in Board.get_list()] + # keep track of all supported root- and chip-families + components = set() + families = {} + # loop through supported components + for component, family_name in COMPONENT_MAP.items(): + family = Family.get(name=family_name) + # make family component directory + component_dir = components_dir.joinpath(component) + component_dir.mkdir(exist_ok=True) + # filter boards list + family_boards = [b for b in boards if family in b.family.inheritance] + # write __init__.py + write_component_code(component_dir, component) + # write boards.py + component_families = write_component_boards( + component_dir, component, family_boards + ) + # store current root component name + components.add(component.upper()) + # add all chip families + for family in component_families: + families[family.short_name] = component.upper() + # update libretiny/const.py + write_const(components_dir, components, families) diff --git a/esphome/components/libretiny/gpio.py b/esphome/components/libretiny/gpio.py new file mode 100644 index 0000000000..ba9bfffcc9 --- /dev/null +++ b/esphome/components/libretiny/gpio.py @@ -0,0 +1,216 @@ +import logging + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.const import ( + CONF_ANALOG, + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OPEN_DRAIN, + CONF_OUTPUT, + CONF_PULLDOWN, + CONF_PULLUP, +) +from esphome.core import CORE + +from .const import ( + KEY_BOARD, + KEY_COMPONENT_DATA, + KEY_LIBRETINY, + LibreTinyComponent, + libretiny_ns, +) + +_LOGGER = logging.getLogger(__name__) + +ArduinoInternalGPIOPin = libretiny_ns.class_( + "ArduinoInternalGPIOPin", cg.InternalGPIOPin +) + + +def _is_name_deprecated(value): + return value[0] in "DA" and value[1:].isnumeric() + + +def _lookup_board_pins(board): + component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] + board_pins = component.board_pins.get(board, {}) + # Resolve aliased board pins (shorthand when two boards have the same pin configuration) + while isinstance(board_pins, str): + board_pins = board_pins[board_pins] + return board_pins + + +def _lookup_pin(value): + board: str = CORE.data[KEY_LIBRETINY][KEY_BOARD] + board_pins = _lookup_board_pins(board) + + # check numeric pin values + if isinstance(value, int): + if value in board_pins.values() or not board_pins: + # accept if pin number present in board pins + # if board is not found, just accept all numeric values + return value + raise cv.Invalid(f"Pin number '{value}' is not usable for board {board}.") + + # check textual pin names + if isinstance(value, str): + if not board_pins: + # can't remap without known pin name + raise cv.Invalid( + f"Board {board} wasn't found. " + f"Use 'GPIO#' (numeric value) instead of '{value}'." + ) + + if value in board_pins: + # pin name found, remap to numeric value + if _is_name_deprecated(value): + number = board_pins[value] + # find all alternative pin names (except the deprecated) + names = ( + k + for k, v in board_pins.items() + if v == number and not _is_name_deprecated(k) + ) + # sort by shortest + # favor P# or PA# names + names = sorted( + names, + key=lambda x: len(x) - 99 if x[0] == "P" else len(x), + ) + _LOGGER.warning( + "Using D# and A# pin numbering is deprecated. " + "Please replace '%s' with one of: %s", + value, + ", ".join(names), + ) + return board_pins[value] + + # pin name not found and not numeric + raise cv.Invalid(f"Cannot resolve pin name '{value}' for board {board}.") + + # unknown type of the value + raise cv.Invalid(f"Unrecognized pin value '{value}'.") + + +def _translate_pin(value): + if isinstance(value, dict) or value is None: + raise cv.Invalid( + "This variable only supports pin numbers, not full pin schemas " + "(with inverted and mode)." + ) + if isinstance(value, int): + return value + try: + return int(value) + except ValueError: + pass + # translate GPIO* and P* to a number, if possible + # otherwise return unchanged value (i.e. pin PA05) + try: + if value.startswith("GPIO"): + value = int(value[4:]) + elif value.startswith("P"): + value = int(value[1:]) + except ValueError: + pass + return value + + +def validate_gpio_pin(value): + value = _translate_pin(value) + value = _lookup_pin(value) + + component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] + if component.pin_validation: + value = component.pin_validation(value) + + return value + + +def validate_gpio_usage(value): + mode = value[CONF_MODE] + is_analog = mode[CONF_ANALOG] + is_input = mode[CONF_INPUT] + is_output = mode[CONF_OUTPUT] + is_open_drain = mode[CONF_OPEN_DRAIN] + is_pullup = mode[CONF_PULLUP] + is_pulldown = mode[CONF_PULLDOWN] + + if is_open_drain and not is_output: + raise cv.Invalid( + "Open-drain only works with output mode", [CONF_MODE, CONF_OPEN_DRAIN] + ) + if is_analog and not is_input: + raise cv.Invalid("Analog pins must be an input", [CONF_MODE, CONF_ANALOG]) + if is_analog: + # expect analog pin numbers to be available as either ADC# or A# + number = value[CONF_NUMBER] + board: str = CORE.data[KEY_LIBRETINY][KEY_BOARD] + board_pins = _lookup_board_pins(board) + analog_pins = [ + v + for k, v in board_pins.items() + if k[0] == "A" and k[1:].isnumeric() or k[0:3] == "ADC" + ] + if number not in analog_pins: + raise cv.Invalid( + f"Pin '{number}' is not an analog pin", [CONF_MODE, CONF_ANALOG] + ) + + # (input, output, open_drain, pullup, pulldown) + supported_modes = { + # INPUT + (True, False, False, False, False), + # OUTPUT + (False, True, False, False, False), + # INPUT_PULLUP + (True, False, False, True, False), + # INPUT_PULLDOWN + (True, False, False, False, True), + # OUTPUT_OPEN_DRAIN + (False, True, True, False, False), + } + key = (is_input, is_output, is_open_drain, is_pullup, is_pulldown) + if key not in supported_modes: + raise cv.Invalid("This pin mode is not supported", [CONF_MODE]) + + component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] + if component.usage_validation: + value = component.usage_validation(value) + + return value + + +BASE_PIN_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(ArduinoInternalGPIOPin), + cv.Required(CONF_NUMBER): validate_gpio_pin, + cv.Optional(CONF_MODE, default={}): cv.Schema( + { + cv.Optional(CONF_ANALOG, default=False): cv.boolean, + cv.Optional(CONF_INPUT, default=False): cv.boolean, + cv.Optional(CONF_OUTPUT, default=False): cv.boolean, + cv.Optional(CONF_OPEN_DRAIN, default=False): cv.boolean, + cv.Optional(CONF_PULLUP, default=False): cv.boolean, + cv.Optional(CONF_PULLDOWN, default=False): cv.boolean, + } + ), + cv.Optional(CONF_INVERTED, default=False): cv.boolean, + }, +) + +BASE_PIN_SCHEMA.add_extra(validate_gpio_usage) + + +async def component_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/libretiny/gpio_arduino.cpp b/esphome/components/libretiny/gpio_arduino.cpp new file mode 100644 index 0000000000..7a1e014ea4 --- /dev/null +++ b/esphome/components/libretiny/gpio_arduino.cpp @@ -0,0 +1,105 @@ +#ifdef USE_LIBRETINY + +#include "gpio_arduino.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace libretiny { + +static const char *const TAG = "lt.gpio"; + +static int IRAM_ATTR flags_to_mode(gpio::Flags flags) { + if (flags == gpio::FLAG_INPUT) { + return INPUT; + } else if (flags == gpio::FLAG_OUTPUT) { + return OUTPUT; + } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { + return INPUT_PULLUP; + } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { + return INPUT_PULLDOWN; + } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { + return OUTPUT_OPEN_DRAIN; + } else { + return 0; + } +} + +struct ISRPinArg { + uint8_t pin; + bool inverted; +}; + +ISRInternalGPIOPin ArduinoInternalGPIOPin::to_isr() const { + auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory) + arg->pin = pin_; + arg->inverted = inverted_; + return ISRInternalGPIOPin((void *) arg); +} + +void ArduinoInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { + PinStatus arduino_mode = (PinStatus) 255; + switch (type) { + case gpio::INTERRUPT_RISING_EDGE: + arduino_mode = inverted_ ? FALLING : RISING; + break; + case gpio::INTERRUPT_FALLING_EDGE: + arduino_mode = inverted_ ? RISING : FALLING; + break; + case gpio::INTERRUPT_ANY_EDGE: + arduino_mode = CHANGE; + break; + case gpio::INTERRUPT_LOW_LEVEL: + arduino_mode = inverted_ ? HIGH : LOW; + break; + case gpio::INTERRUPT_HIGH_LEVEL: + arduino_mode = inverted_ ? LOW : HIGH; + break; + } + + attachInterruptParam(pin_, func, arduino_mode, arg); +} + +void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) { + pinMode(pin_, flags_to_mode(flags)); // NOLINT +} + +std::string ArduinoInternalGPIOPin::dump_summary() const { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%u", pin_); + return buffer; +} + +bool ArduinoInternalGPIOPin::digital_read() { + return bool(digitalRead(pin_)) ^ inverted_; // NOLINT +} +void ArduinoInternalGPIOPin::digital_write(bool value) { + digitalWrite(pin_, value ^ inverted_); // NOLINT +} +void ArduinoInternalGPIOPin::detach_interrupt() const { + detachInterrupt(pin_); // NOLINT +} + +} // namespace libretiny + +using namespace libretiny; + +bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { + auto *arg = reinterpret_cast(arg_); + return bool(digitalRead(arg->pin)) ^ arg->inverted; // NOLINT +} +void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { + auto *arg = reinterpret_cast(arg_); + digitalWrite(arg->pin, value ^ arg->inverted); // NOLINT +} +void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { + auto *arg = reinterpret_cast(arg_); + detachInterrupt(arg->pin); +} +void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { + auto *arg = reinterpret_cast(arg_); + pinMode(arg->pin, flags_to_mode(flags)); // NOLINT +} + +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/gpio_arduino.h b/esphome/components/libretiny/gpio_arduino.h new file mode 100644 index 0000000000..a43ed28c5e --- /dev/null +++ b/esphome/components/libretiny/gpio_arduino.h @@ -0,0 +1,36 @@ +#pragma once + +#ifdef USE_LIBRETINY +#include "esphome/core/hal.h" + +namespace esphome { +namespace libretiny { + +class ArduinoInternalGPIOPin : public InternalGPIOPin { + public: + void set_pin(uint8_t pin) { pin_ = pin; } + void set_inverted(bool inverted) { inverted_ = inverted; } + void set_flags(gpio::Flags flags) { flags_ = flags; } + + void setup() override { pin_mode(flags_); } + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + std::string dump_summary() const override; + void detach_interrupt() const override; + ISRInternalGPIOPin to_isr() const override; + uint8_t get_pin() const override { return pin_; } + bool is_inverted() const override { return inverted_; } + + protected: + void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override; + + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +} // namespace libretiny +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/lt_component.cpp b/esphome/components/libretiny/lt_component.cpp new file mode 100644 index 0000000000..ec4b60eaeb --- /dev/null +++ b/esphome/components/libretiny/lt_component.cpp @@ -0,0 +1,29 @@ +#include "lt_component.h" + +#ifdef USE_LIBRETINY + +#include "esphome/core/log.h" + +namespace esphome { +namespace libretiny { + +static const char *const TAG = "lt.component"; + +void LTComponent::dump_config() { + ESP_LOGCONFIG(TAG, "LibreTiny:"); + ESP_LOGCONFIG(TAG, " Version: %s", LT_BANNER_STR + 10); + ESP_LOGCONFIG(TAG, " Loglevel: %u", LT_LOGLEVEL); + +#ifdef USE_TEXT_SENSOR + if (this->version_ != nullptr) { + this->version_->publish_state(LT_BANNER_STR + 10); + } +#endif // USE_TEXT_SENSOR +} + +float LTComponent::get_setup_priority() const { return setup_priority::LATE; } + +} // namespace libretiny +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/lt_component.h b/esphome/components/libretiny/lt_component.h new file mode 100644 index 0000000000..3d4483ab5d --- /dev/null +++ b/esphome/components/libretiny/lt_component.h @@ -0,0 +1,36 @@ +#pragma once + +#ifdef USE_LIBRETINY + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" + +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif + +namespace esphome { +namespace libretiny { + +class LTComponent : public Component { + public: + float get_setup_priority() const override; + void dump_config() override; + +#ifdef USE_TEXT_SENSOR + void set_version_sensor(text_sensor::TextSensor *version) { version_ = version; } +#endif // USE_TEXT_SENSOR + + protected: +#ifdef USE_TEXT_SENSOR + text_sensor::TextSensor *version_{nullptr}; +#endif // USE_TEXT_SENSOR +}; + +} // namespace libretiny +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/preferences.cpp b/esphome/components/libretiny/preferences.cpp new file mode 100644 index 0000000000..ceeb30baf5 --- /dev/null +++ b/esphome/components/libretiny/preferences.cpp @@ -0,0 +1,182 @@ +#ifdef USE_LIBRETINY + +#include "esphome/core/preferences.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include +#include +#include +#include + +namespace esphome { +namespace libretiny { + +static const char *const TAG = "lt.preferences"; + +struct NVSData { + std::string key; + std::vector data; +}; + +static std::vector s_pending_save; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +class LibreTinyPreferenceBackend : public ESPPreferenceBackend { + public: + std::string key; + fdb_kvdb_t db; + fdb_blob_t blob; + + bool save(const uint8_t *data, size_t len) override { + // try find in pending saves and update that + for (auto &obj : s_pending_save) { + if (obj.key == key) { + obj.data.assign(data, data + len); + return true; + } + } + NVSData save{}; + save.key = key; + save.data.assign(data, data + len); + s_pending_save.emplace_back(save); + ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %d", key.c_str(), len); + return true; + } + + bool load(uint8_t *data, size_t len) override { + // try find in pending saves and load from that + for (auto &obj : s_pending_save) { + if (obj.key == key) { + if (obj.data.size() != len) { + // size mismatch + return false; + } + memcpy(data, obj.data.data(), len); + return true; + } + } + + fdb_blob_make(blob, data, len); + size_t actual_len = fdb_kv_get_blob(db, key.c_str(), blob); + if (actual_len != len) { + ESP_LOGVV(TAG, "NVS length does not match (%u!=%u)", actual_len, len); + return false; + } else { + ESP_LOGVV(TAG, "fdb_kv_get_blob: key: %s, len: %d", key.c_str(), len); + } + return true; + } +}; + +class LibreTinyPreferences : public ESPPreferences { + public: + struct fdb_kvdb db; + struct fdb_blob blob; + + void open() { + // + fdb_err_t err = fdb_kvdb_init(&db, "esphome", "kvs", NULL, NULL); + if (err != FDB_NO_ERR) { + LT_E("fdb_kvdb_init(...) failed: %d", err); + } else { + LT_I("Preferences initialized"); + } + } + + ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { + return make_preference(length, type); + } + + ESPPreferenceObject make_preference(size_t length, uint32_t type) override { + auto *pref = new LibreTinyPreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory) + pref->db = &db; + pref->blob = &blob; + + uint32_t keyval = type; + pref->key = str_sprintf("%u", keyval); + + return ESPPreferenceObject(pref); + } + + bool sync() override { + if (s_pending_save.empty()) + return true; + + ESP_LOGD(TAG, "Saving %d preferences to flash...", s_pending_save.size()); + // goal try write all pending saves even if one fails + int cached = 0, written = 0, failed = 0; + fdb_err_t last_err = FDB_NO_ERR; + std::string last_key{}; + + // go through vector from back to front (makes erase easier/more efficient) + for (ssize_t i = s_pending_save.size() - 1; i >= 0; i--) { + const auto &save = s_pending_save[i]; + ESP_LOGVV(TAG, "Checking if FDB data %s has changed", save.key.c_str()); + if (is_changed(&db, save)) { + ESP_LOGV(TAG, "sync: key: %s, len: %d", save.key.c_str(), save.data.size()); + fdb_blob_make(&blob, save.data.data(), save.data.size()); + fdb_err_t err = fdb_kv_set_blob(&db, save.key.c_str(), &blob); + if (err != FDB_NO_ERR) { + ESP_LOGV(TAG, "fdb_kv_set_blob('%s', len=%u) failed: %d", save.key.c_str(), save.data.size(), err); + failed++; + last_err = err; + last_key = save.key; + continue; + } + written++; + } else { + ESP_LOGD(TAG, "FDB data not changed; skipping %s len=%u", save.key.c_str(), save.data.size()); + cached++; + } + s_pending_save.erase(s_pending_save.begin() + i); + } + ESP_LOGD(TAG, "Saving %d preferences to flash: %d cached, %d written, %d failed", cached + written + failed, cached, + written, failed); + if (failed > 0) { + ESP_LOGE(TAG, "Error saving %d preferences to flash. Last error=%d for key=%s", failed, last_err, + last_key.c_str()); + } + + return failed == 0; + } + + bool is_changed(const fdb_kvdb_t db, const NVSData &to_save) { + NVSData stored_data{}; + struct fdb_kv kv; + fdb_kv_t kvp = fdb_kv_get_obj(db, to_save.key.c_str(), &kv); + if (kvp == nullptr) { + ESP_LOGV(TAG, "fdb_kv_get_obj('%s'): nullptr - the key might not be set yet", to_save.key.c_str()); + return true; + } + stored_data.data.reserve(kv.value_len); + fdb_blob_make(&blob, stored_data.data.data(), kv.value_len); + size_t actual_len = fdb_kv_get_blob(db, to_save.key.c_str(), &blob); + if (actual_len != kv.value_len) { + ESP_LOGV(TAG, "fdb_kv_get_blob('%s') len mismatch: %u != %u", to_save.key.c_str(), actual_len, kv.value_len); + return true; + } + return to_save.data != stored_data.data; + } + + bool reset() override { + ESP_LOGD(TAG, "Cleaning up preferences in flash..."); + s_pending_save.clear(); + + fdb_kv_set_default(&db); + fdb_kvdb_deinit(&db); + return true; + } +}; + +void setup_preferences() { + auto *prefs = new LibreTinyPreferences(); // NOLINT(cppcoreguidelines-owning-memory) + prefs->open(); + global_preferences = prefs; +} + +} // namespace libretiny + +ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/preferences.h b/esphome/components/libretiny/preferences.h new file mode 100644 index 0000000000..8ec3cd31b1 --- /dev/null +++ b/esphome/components/libretiny/preferences.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef USE_LIBRETINY + +namespace esphome { +namespace libretiny { + +void setup_preferences(); + +} // namespace libretiny +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/libretiny/text_sensor.py b/esphome/components/libretiny/text_sensor.py new file mode 100644 index 0000000000..df10ee7229 --- /dev/null +++ b/esphome/components/libretiny/text_sensor.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import ( + CONF_VERSION, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_CELLPHONE_ARROW_DOWN, +) + +from .const import CONF_LIBRETINY, LTComponent + +DEPENDENCIES = ["libretiny"] + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_LIBRETINY): cv.use_id(LTComponent), + cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( + icon=ICON_CELLPHONE_ARROW_DOWN, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } +) + + +async def to_code(config): + lt_component = await cg.get_variable(config[CONF_LIBRETINY]) + + if CONF_VERSION in config: + sens = await text_sensor.new_text_sensor(config[CONF_VERSION]) + cg.add(lt_component.set_version_sensor(sens)) diff --git a/esphome/components/libretiny_pwm/__init__.py b/esphome/components/libretiny_pwm/__init__.py new file mode 100644 index 0000000000..4db724f8ad --- /dev/null +++ b/esphome/components/libretiny_pwm/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@kuba2k2"] diff --git a/esphome/components/libretiny_pwm/libretiny_pwm.cpp b/esphome/components/libretiny_pwm/libretiny_pwm.cpp new file mode 100644 index 0000000000..92e4097c0e --- /dev/null +++ b/esphome/components/libretiny_pwm/libretiny_pwm.cpp @@ -0,0 +1,53 @@ +#include "libretiny_pwm.h" +#include "esphome/core/log.h" + +#ifdef USE_LIBRETINY + +namespace esphome { +namespace libretiny_pwm { + +static const char *const TAG = "libretiny.pwm"; + +void LibreTinyPWM::write_state(float state) { + if (!this->initialized_) { + ESP_LOGW(TAG, "LibreTinyPWM output hasn't been initialized yet!"); + return; + } + + if (this->pin_->is_inverted()) + state = 1.0f - state; + + this->duty_ = state; + const uint32_t max_duty = (uint32_t(1) << this->bit_depth_) - 1; + const float duty_rounded = roundf(state * max_duty); + auto duty = static_cast(duty_rounded); + + analogWrite(this->pin_->get_pin(), duty); // NOLINT +} + +void LibreTinyPWM::setup() { + this->update_frequency(this->frequency_); + this->turn_off(); +} + +void LibreTinyPWM::dump_config() { + ESP_LOGCONFIG(TAG, "PWM Output:"); + LOG_PIN(" Pin ", this->pin_); + ESP_LOGCONFIG(TAG, " Frequency: %.1f Hz", this->frequency_); +} + +void LibreTinyPWM::update_frequency(float frequency) { + this->frequency_ = frequency; + // force changing the frequency by removing PWM mode + this->pin_->pin_mode(gpio::FLAG_INPUT); + analogWriteResolution(this->bit_depth_); // NOLINT + analogWriteFrequency(frequency); // NOLINT + this->initialized_ = true; + // re-apply duty + this->write_state(this->duty_); +} + +} // namespace libretiny_pwm +} // namespace esphome + +#endif diff --git a/esphome/components/libretiny_pwm/libretiny_pwm.h b/esphome/components/libretiny_pwm/libretiny_pwm.h new file mode 100644 index 0000000000..42ce40ca39 --- /dev/null +++ b/esphome/components/libretiny_pwm/libretiny_pwm.h @@ -0,0 +1,55 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/automation.h" +#include "esphome/components/output/float_output.h" + +#ifdef USE_LIBRETINY + +namespace esphome { +namespace libretiny_pwm { + +class LibreTinyPWM : public output::FloatOutput, public Component { + public: + explicit LibreTinyPWM(InternalGPIOPin *pin) : pin_(pin) {} + + void set_frequency(float frequency) { this->frequency_ = frequency; } + /// Dynamically change frequency at runtime + void update_frequency(float frequency) override; + + /// Setup LibreTinyPWM. + void setup() override; + void dump_config() override; + /// HARDWARE setup priority + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + /// Override FloatOutput's write_state. + void write_state(float state) override; + + protected: + InternalGPIOPin *pin_; + uint8_t bit_depth_{10}; + float frequency_{}; + float duty_{0.0f}; + bool initialized_ = false; +}; + +template class SetFrequencyAction : public Action { + public: + SetFrequencyAction(LibreTinyPWM *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(float, frequency); + + void play(Ts... x) { + float freq = this->frequency_.value(x...); + this->parent_->update_frequency(freq); + } + + protected: + LibreTinyPWM *parent_; +}; + +} // namespace libretiny_pwm +} // namespace esphome + +#endif diff --git a/esphome/components/libretiny_pwm/output.py b/esphome/components/libretiny_pwm/output.py new file mode 100644 index 0000000000..e74bc8f129 --- /dev/null +++ b/esphome/components/libretiny_pwm/output.py @@ -0,0 +1,49 @@ +from esphome import pins, automation +from esphome.components import output +import esphome.config_validation as cv +import esphome.codegen as cg +from esphome.const import ( + CONF_FREQUENCY, + CONF_ID, + CONF_PIN, +) + +DEPENDENCIES = ["libretiny"] + +libretinypwm_ns = cg.esphome_ns.namespace("libretiny_pwm") +LibreTinyPWM = libretinypwm_ns.class_("LibreTinyPWM", output.FloatOutput, cg.Component) +SetFrequencyAction = libretinypwm_ns.class_("SetFrequencyAction", automation.Action) + +CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.declare_id(LibreTinyPWM), + cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_FREQUENCY, default="1kHz"): cv.frequency, + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + gpio = await cg.gpio_pin_expression(config[CONF_PIN]) + var = cg.new_Pvariable(config[CONF_ID], gpio) + await cg.register_component(var, config) + await output.register_output(var, config) + cg.add(var.set_frequency(config[CONF_FREQUENCY])) + + +@automation.register_action( + "output.libretiny_pwm.set_frequency", + SetFrequencyAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(LibreTinyPWM), + cv.Required(CONF_FREQUENCY): cv.templatable(cv.int_), + } + ), +) +async def libretiny_pwm_set_frequency_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable(config[CONF_FREQUENCY], args, float) + cg.add(var.set_frequency(template_)) + return var diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 5c87bb9d91..5225a227ec 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -17,6 +17,8 @@ from esphome.const import ( CONF_TAG, CONF_TRIGGER_ID, CONF_TX_BUFFER_SIZE, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, @@ -31,6 +33,11 @@ from esphome.components.esp32.const import ( VARIANT_ESP32C2, VARIANT_ESP32C6, ) +from esphome.components.libretiny import get_libretiny_component, get_libretiny_family +from esphome.components.libretiny.const import ( + COMPONENT_BK72XX, + COMPONENT_RTL87XX, +) CODEOWNERS = ["@esphome/core"] logger_ns = cg.esphome_ns.namespace("logger") @@ -70,6 +77,7 @@ UART2 = "UART2" UART0_SWAP = "UART0_SWAP" USB_SERIAL_JTAG = "USB_SERIAL_JTAG" USB_CDC = "USB_CDC" +DEFAULT = "DEFAULT" UART_SELECTION_ESP32 = { VARIANT_ESP32: [UART0, UART1, UART2], @@ -82,6 +90,11 @@ UART_SELECTION_ESP32 = { UART_SELECTION_ESP8266 = [UART0, UART0_SWAP, UART1] +UART_SELECTION_LIBRETINY = { + COMPONENT_BK72XX: [DEFAULT, UART1, UART2], + COMPONENT_RTL87XX: [DEFAULT, UART0, UART1, UART2], +} + ESP_IDF_UARTS = [USB_CDC, USB_SERIAL_JTAG] UART_SELECTION_RP2040 = [USB_CDC, UART0, UART1] @@ -93,6 +106,7 @@ HARDWARE_UART_TO_UART_SELECTION = { UART2: logger_ns.UART_SELECTION_UART2, USB_CDC: logger_ns.UART_SELECTION_USB_CDC, USB_SERIAL_JTAG: logger_ns.UART_SELECTION_USB_SERIAL_JTAG, + DEFAULT: logger_ns.UART_SELECTION_DEFAULT, } HARDWARE_UART_TO_SERIAL = { @@ -100,6 +114,7 @@ HARDWARE_UART_TO_SERIAL = { UART0_SWAP: cg.global_ns.Serial, UART1: cg.global_ns.Serial1, UART2: cg.global_ns.Serial2, + DEFAULT: cg.global_ns.Serial, } is_log_level = cv.one_of(*LOG_LEVELS, upper=True) @@ -116,6 +131,13 @@ def uart_selection(value): return cv.one_of(*UART_SELECTION_ESP8266, upper=True)(value) if CORE.is_rp2040: return cv.one_of(*UART_SELECTION_RP2040, upper=True)(value) + if CORE.is_libretiny: + family = get_libretiny_family() + if family in UART_SELECTION_LIBRETINY: + return cv.one_of(*UART_SELECTION_LIBRETINY[family], upper=True)(value) + component = get_libretiny_component() + if component in UART_SELECTION_LIBRETINY: + return cv.one_of(*UART_SELECTION_LIBRETINY[component], upper=True)(value) raise NotImplementedError @@ -148,8 +170,18 @@ CONFIG_SCHEMA = cv.All( esp8266=UART0, esp32=UART0, rp2040=USB_CDC, + bk72xx=DEFAULT, + rtl87xx=DEFAULT, ): cv.All( - cv.only_on([PLATFORM_ESP8266, PLATFORM_ESP32, PLATFORM_RP2040]), + cv.only_on( + [ + PLATFORM_ESP8266, + PLATFORM_ESP32, + PLATFORM_RP2040, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, + ] + ), uart_selection, ), cv.Optional(CONF_LEVEL, default="DEBUG"): is_log_level, diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 758e9c1f98..df4662024f 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -158,6 +158,7 @@ Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate this->tx_buffer_ = new char[this->tx_buffer_size_ + 1]; // NOLINT } +#ifndef USE_LIBRETINY void Logger::pre_setup() { if (this->baud_rate_ > 0) { #ifdef USE_ARDUINO @@ -266,12 +267,58 @@ void Logger::pre_setup() { ESP_LOGI(TAG, "Log initialized"); } +#else // USE_LIBRETINY +void Logger::pre_setup() { + if (this->baud_rate_ > 0) { + switch (this->uart_) { +#if LT_HW_UART0 + case UART_SELECTION_UART0: + this->hw_serial_ = &Serial0; + Serial0.begin(this->baud_rate_); + break; +#endif +#if LT_HW_UART1 + case UART_SELECTION_UART1: + this->hw_serial_ = &Serial1; + Serial1.begin(this->baud_rate_); + break; +#endif +#if LT_HW_UART2 + case UART_SELECTION_UART2: + this->hw_serial_ = &Serial2; + Serial2.begin(this->baud_rate_); + break; +#endif + default: + this->hw_serial_ = &Serial; + Serial.begin(this->baud_rate_); + if (this->uart_ != UART_SELECTION_DEFAULT) { + ESP_LOGW(TAG, " The chosen logger UART port is not available on this board." + "The default port was used instead."); + } + break; + } + + // change lt_log() port to match default Serial + if (this->uart_ == UART_SELECTION_DEFAULT) { + this->uart_ = (UARTSelection) (LT_UART_DEFAULT_SERIAL + 1); + lt_log_set_port(LT_UART_DEFAULT_SERIAL); + } else { + lt_log_set_port(this->uart_ - 1); + } + } + + global_logger = this; + ESP_LOGI(TAG, "Log initialized"); +} +#endif // USE_LIBRETINY + void Logger::set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; } void Logger::set_log_level(const std::string &tag, int log_level) { this->log_levels_.push_back(LogLevelOverride{tag, log_level}); } -#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) UARTSelection Logger::get_uart() const { return this->uart_; } #endif @@ -299,15 +346,18 @@ const char *const UART_SELECTIONS[] = { #endif // USE_ESP32 #ifdef USE_ESP8266 const char *const UART_SELECTIONS[] = {"UART0", "UART1", "UART0_SWAP"}; -#endif +#endif // USE_ESP8266 #ifdef USE_RP2040 const char *const UART_SELECTIONS[] = {"UART0", "UART1", "USB_CDC"}; -#endif // USE_ESP8266 +#endif // USE_RP2040 +#ifdef USE_LIBRETINY +const char *const UART_SELECTIONS[] = {"DEFAULT", "UART0", "UART1", "UART2"}; +#endif // USE_LIBRETINY void Logger::dump_config() { ESP_LOGCONFIG(TAG, "Logger:"); ESP_LOGCONFIG(TAG, " Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); ESP_LOGCONFIG(TAG, " Log Baud Rate: %" PRIu32, this->baud_rate_); -#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) ESP_LOGCONFIG(TAG, " Hardware UART: %s", UART_SELECTIONS[this->uart_]); #endif diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index 47cde45c29..4a7a43c7c2 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -25,12 +25,18 @@ namespace esphome { namespace logger { -#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) /** Enum for logging UART selection * * Advanced configuration (pin selection, etc) is not supported. */ enum UARTSelection { +#ifdef USE_LIBRETINY + UART_SELECTION_DEFAULT = 0, + UART_SELECTION_UART0, + UART_SELECTION_UART1, + UART_SELECTION_UART2, +#else UART_SELECTION_UART0 = 0, UART_SELECTION_UART1, #if defined(USE_ESP32) @@ -53,8 +59,9 @@ enum UARTSelection { #ifdef USE_RP2040 UART_SELECTION_USB_CDC, #endif // USE_RP2040 +#endif // USE_LIBRETINY }; -#endif // USE_ESP32 || USE_ESP8266 +#endif // USE_ESP32 || USE_ESP8266 || USE_RP2040 || USE_LIBRETINY class Logger : public Component { public: @@ -69,7 +76,7 @@ class Logger : public Component { #ifdef USE_ESP_IDF uart_port_t get_uart_num() const { return uart_num_; } #endif -#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; } /// Get the UART used by the logger. UARTSelection get_uart() const; @@ -146,6 +153,9 @@ class Logger : public Component { #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) UARTSelection uart_{UART_SELECTION_UART0}; #endif +#ifdef USE_LIBRETINY + UARTSelection uart_{UART_SELECTION_DEFAULT}; +#endif #ifdef USE_ARDUINO Stream *hw_serial_{nullptr}; #endif diff --git a/esphome/components/md5/md5.h b/esphome/components/md5/md5.h index 738a312267..4ec8a8a12c 100644 --- a/esphome/components/md5/md5.h +++ b/esphome/components/md5/md5.h @@ -22,6 +22,11 @@ #define MD5_CTX_TYPE br_md5_context #endif +#if defined(USE_LIBRETINY) +#include +#define MD5_CTX_TYPE LT_MD5_CTX_T +#endif + namespace esphome { namespace md5 { diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index 581758cf2d..e2e562670b 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -44,6 +44,9 @@ void MDNSComponent::compile_records_() { #endif #ifdef USE_RP2040 platform = "RP2040"; +#endif +#ifdef USE_LIBRETINY + platform = lt_cpu_get_model_name(); #endif if (platform != nullptr) { service.txt_records.push_back({"platform", platform}); diff --git a/esphome/components/mdns/mdns_libretiny.cpp b/esphome/components/mdns/mdns_libretiny.cpp new file mode 100644 index 0000000000..ccb79c88b9 --- /dev/null +++ b/esphome/components/mdns/mdns_libretiny.cpp @@ -0,0 +1,43 @@ +#ifdef USE_LIBRETINY + +#include "esphome/components/network/ip_address.h" +#include "esphome/components/network/util.h" +#include "esphome/core/log.h" +#include "mdns_component.h" + +#include + +namespace esphome { +namespace mdns { + +void MDNSComponent::setup() { + this->compile_records_(); + + MDNS.begin(this->hostname_.c_str()); + + for (const auto &service : this->services_) { + // Strip the leading underscore from the proto and service_type. While it is + // part of the wire protocol to have an underscore, and for example ESP-IDF + // expects the underscore to be there, the ESP8266 implementation always adds + // the underscore itself. + auto *proto = service.proto.c_str(); + while (*proto == '_') { + proto++; + } + auto *service_type = service.service_type.c_str(); + while (*service_type == '_') { + service_type++; + } + MDNS.addService(service_type, proto, service.port); + for (const auto &record : service.txt_records) { + MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str()); + } + } +} + +void MDNSComponent::on_shutdown() {} + +} // namespace mdns +} // namespace esphome + +#endif diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index a966157ffa..eb2a83272d 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -41,7 +41,14 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(OTAComponent), cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean, - cv.SplitDefault(CONF_PORT, esp8266=8266, esp32=3232, rp2040=2040): cv.port, + cv.SplitDefault( + CONF_PORT, + esp8266=8266, + esp32=3232, + rp2040=2040, + bk72xx=8892, + rtl87xx=8892, + ): cv.port, cv.Optional(CONF_PASSWORD): cv.string, cv.Optional( CONF_REBOOT_TIMEOUT, default="5min" diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp new file mode 100644 index 0000000000..dbf6c97988 --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -0,0 +1,46 @@ +#include "esphome/core/defines.h" +#ifdef USE_LIBRETINY + +#include "ota_backend_arduino_libretiny.h" +#include "ota_component.h" +#include "ota_backend.h" + +#include + +namespace esphome { +namespace ota { + +OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { + bool ret = Update.begin(image_size, U_FLASH); + if (ret) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + if (error == UPDATE_ERROR_SIZE) + return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + return OTA_RESPONSE_ERROR_UNKNOWN; +} + +void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } + +OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { + size_t written = Update.write(data, len); + if (written != len) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_OK; +} + +OTAResponseTypes ArduinoLibreTinyOTABackend::end() { + if (!Update.end()) + return OTA_RESPONSE_ERROR_UPDATE_END; + return OTA_RESPONSE_OK; +} + +void ArduinoLibreTinyOTABackend::abort() { Update.abort(); } + +} // namespace ota +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.h b/esphome/components/ota/ota_backend_arduino_libretiny.h new file mode 100644 index 0000000000..79656bb353 --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -0,0 +1,24 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_LIBRETINY + +#include "ota_component.h" +#include "ota_backend.h" + +namespace esphome { +namespace ota { + +class ArduinoLibreTinyOTABackend : public OTABackend { + public: + OTAResponseTypes begin(size_t image_size) override; + void set_update_md5(const char *md5) override; + OTAResponseTypes write(uint8_t *data, size_t len) override; + OTAResponseTypes end() override; + void abort() override; + bool supports_compression() override { return false; } +}; + +} // namespace ota +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index acf9e923b6..41cf333be9 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -3,6 +3,7 @@ #include "ota_backend_arduino_esp32.h" #include "ota_backend_arduino_esp8266.h" #include "ota_backend_arduino_rp2040.h" +#include "ota_backend_arduino_libretiny.h" #include "ota_backend_esp_idf.h" #include "esphome/core/log.h" @@ -39,6 +40,9 @@ std::unique_ptr make_ota_backend() { #ifdef USE_RP2040 return make_unique(); #endif // USE_RP2040 +#ifdef USE_LIBRETINY + return make_unique(); +#endif } OTAComponent::OTAComponent() { global_ota_component = this; } diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index d59ad5c7f1..5737957adb 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -31,7 +31,11 @@ CONFIG_SCHEMA = remote_base.validate_triggers( cv.percentage_int, cv.Range(min=0) ), cv.SplitDefault( - CONF_BUFFER_SIZE, esp32="10000b", esp8266="1000b" + CONF_BUFFER_SIZE, + esp32="10000b", + esp8266="1000b", + bk72xx="1000b", + rtl87xx="1000b", ): cv.validate_bytes, cv.Optional(CONF_FILTER, default="50us"): cv.All( cv.positive_time_period_microseconds, diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index 50153c105d..82c66e3cd0 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -6,7 +6,7 @@ namespace esphome { namespace remote_receiver { -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) || defined(USE_LIBRETINY) struct RemoteReceiverComponentStore { static void gpio_intr(RemoteReceiverComponentStore *arg); @@ -55,7 +55,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, esp_err_t error_code_{ESP_OK}; #endif -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) || defined(USE_LIBRETINY) RemoteReceiverComponentStore store_; HighFrequencyLoopRequester high_freq_; #endif diff --git a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp new file mode 100644 index 0000000000..ac85b6b520 --- /dev/null +++ b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp @@ -0,0 +1,122 @@ +#include "remote_receiver.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +#ifdef USE_LIBRETINY + +namespace esphome { +namespace remote_receiver { + +static const char *const TAG = "remote_receiver.libretiny"; + +void IRAM_ATTR HOT RemoteReceiverComponentStore::gpio_intr(RemoteReceiverComponentStore *arg) { + const uint32_t now = micros(); + // If the lhs is 1 (rising edge) we should write to an uneven index and vice versa + const uint32_t next = (arg->buffer_write_at + 1) % arg->buffer_size; + const bool level = arg->pin.digital_read(); + if (level != next % 2) + return; + + // If next is buffer_read, we have hit an overflow + if (next == arg->buffer_read_at) + return; + + const uint32_t last_change = arg->buffer[arg->buffer_write_at]; + const uint32_t time_since_change = now - last_change; + if (time_since_change <= arg->filter_us) + return; + + arg->buffer[arg->buffer_write_at = next] = now; +} + +void RemoteReceiverComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up Remote Receiver..."); + this->pin_->setup(); + auto &s = this->store_; + s.filter_us = this->filter_us_; + s.pin = this->pin_->to_isr(); + s.buffer_size = this->buffer_size_; + + this->high_freq_.start(); + if (s.buffer_size % 2 != 0) { + // Make sure divisible by two. This way, we know that every 0bxxx0 index is a space and every 0bxxx1 index is a mark + s.buffer_size++; + } + + s.buffer = new uint32_t[s.buffer_size]; + void *buf = (void *) s.buffer; + memset(buf, 0, s.buffer_size * sizeof(uint32_t)); + + // First index is a space. + if (this->pin_->digital_read()) { + s.buffer_write_at = s.buffer_read_at = 1; + } else { + s.buffer_write_at = s.buffer_read_at = 0; + } + this->pin_->attach_interrupt(RemoteReceiverComponentStore::gpio_intr, &this->store_, gpio::INTERRUPT_ANY_EDGE); +} +void RemoteReceiverComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Receiver:"); + LOG_PIN(" Pin: ", this->pin_); + if (this->pin_->digital_read()) { + ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " + "invert the signal using 'inverted: True' in the pin schema!"); + } + ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); + ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); + ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); + ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); +} + +void RemoteReceiverComponent::loop() { + auto &s = this->store_; + + // copy write at to local variables, as it's volatile + const uint32_t write_at = s.buffer_write_at; + const uint32_t dist = (s.buffer_size + write_at - s.buffer_read_at) % s.buffer_size; + // signals must at least one rising and one leading edge + if (dist <= 1) + return; + const uint32_t now = micros(); + if (now - s.buffer[write_at] < this->idle_us_) { + // The last change was fewer than the configured idle time ago. + return; + } + + ESP_LOGVV(TAG, "read_at=%u write_at=%u dist=%u now=%u end=%u", s.buffer_read_at, write_at, dist, now, + s.buffer[write_at]); + + // Skip first value, it's from the previous idle level + s.buffer_read_at = (s.buffer_read_at + 1) % s.buffer_size; + uint32_t prev = s.buffer_read_at; + s.buffer_read_at = (s.buffer_read_at + 1) % s.buffer_size; + const uint32_t reserve_size = 1 + (s.buffer_size + write_at - s.buffer_read_at) % s.buffer_size; + this->temp_.clear(); + this->temp_.reserve(reserve_size); + int32_t multiplier = s.buffer_read_at % 2 == 0 ? 1 : -1; + + for (uint32_t i = 0; prev != write_at; i++) { + int32_t delta = s.buffer[s.buffer_read_at] - s.buffer[prev]; + if (uint32_t(delta) >= this->idle_us_) { + // already found a space longer than idle. There must have been two pulses + break; + } + + ESP_LOGVV(TAG, " i=%u buffer[%u]=%u - buffer[%u]=%u -> %d", i, s.buffer_read_at, s.buffer[s.buffer_read_at], prev, + s.buffer[prev], multiplier * delta); + this->temp_.push_back(multiplier * delta); + prev = s.buffer_read_at; + s.buffer_read_at = (s.buffer_read_at + 1) % s.buffer_size; + multiplier *= -1; + } + s.buffer_read_at = (s.buffer_size + s.buffer_read_at - 1) % s.buffer_size; + this->temp_.push_back(this->idle_us_ * multiplier); + + this->call_listeners_dumpers_(); +} + +} // namespace remote_receiver +} // namespace esphome + +#endif diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index a20df0cc62..686a6ec09b 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -28,7 +28,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, protected: void send_internal(uint32_t send_times, uint32_t send_wait) override; -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) || defined(USE_LIBRETINY) void calculate_on_off_time_(uint32_t carrier_frequency, uint32_t *on_time_period, uint32_t *off_time_period); void mark_(uint32_t on_time, uint32_t off_time, uint32_t usec); diff --git a/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp new file mode 100644 index 0000000000..78bb280482 --- /dev/null +++ b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp @@ -0,0 +1,104 @@ +#include "remote_transmitter.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" + +#ifdef USE_LIBRETINY + +namespace esphome { +namespace remote_transmitter { + +static const char *const TAG = "remote_transmitter"; + +void RemoteTransmitterComponent::setup() { + this->pin_->setup(); + this->pin_->digital_write(false); +} + +void RemoteTransmitterComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Transmitter..."); + ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); + LOG_PIN(" Pin: ", this->pin_); +} + +void RemoteTransmitterComponent::calculate_on_off_time_(uint32_t carrier_frequency, uint32_t *on_time_period, + uint32_t *off_time_period) { + if (carrier_frequency == 0) { + *on_time_period = 0; + *off_time_period = 0; + return; + } + uint32_t period = (1000000UL + carrier_frequency / 2) / carrier_frequency; // round(1000000/freq) + period = std::max(uint32_t(1), period); + *on_time_period = (period * this->carrier_duty_percent_) / 100; + *off_time_period = period - *on_time_period; +} + +void RemoteTransmitterComponent::await_target_time_() { + const uint32_t current_time = micros(); + if (this->target_time_ == 0) { + this->target_time_ = current_time; + } else { + while (this->target_time_ > micros()) { + // busy loop that ensures micros is constantly called + } + } +} + +void RemoteTransmitterComponent::mark_(uint32_t on_time, uint32_t off_time, uint32_t usec) { + this->await_target_time_(); + this->pin_->digital_write(true); + + const uint32_t target = this->target_time_ + usec; + if (this->carrier_duty_percent_ < 100 && (on_time > 0 || off_time > 0)) { + while (true) { // Modulate with carrier frequency + this->target_time_ += on_time; + if (this->target_time_ >= target) + break; + this->await_target_time_(); + this->pin_->digital_write(false); + + this->target_time_ += off_time; + if (this->target_time_ >= target) + break; + this->await_target_time_(); + this->pin_->digital_write(true); + } + } + this->target_time_ = target; +} + +void RemoteTransmitterComponent::space_(uint32_t usec) { + this->await_target_time_(); + this->pin_->digital_write(false); + this->target_time_ += usec; +} + +void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { + ESP_LOGD(TAG, "Sending remote code..."); + uint32_t on_time, off_time; + this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); + this->target_time_ = 0; + for (uint32_t i = 0; i < send_times; i++) { + InterruptLock lock; + for (int32_t item : this->temp_.get_data()) { + if (item > 0) { + const auto length = uint32_t(item); + this->mark_(on_time, off_time, length); + } else { + const auto length = uint32_t(-item); + this->space_(length); + } + App.feed_wdt(); + } + this->await_target_time_(); // wait for duration of last pulse + this->pin_->digital_write(false); + + if (i + 1 < send_times) + this->target_time_ += send_wait; + } +} + +} // namespace remote_transmitter +} // namespace esphome + +#endif diff --git a/esphome/components/rp2040/gpio.py b/esphome/components/rp2040/gpio.py index 2340bed892..4823a6d22a 100644 --- a/esphome/components/rp2040/gpio.py +++ b/esphome/components/rp2040/gpio.py @@ -1,6 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import ( + CONF_ANALOG, CONF_ID, CONF_INPUT, CONF_INVERTED, @@ -76,8 +77,6 @@ def validate_supports(value): return value -CONF_ANALOG = "analog" - RP2040_PIN_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/components/rtl87xx/__init__.py b/esphome/components/rtl87xx/__init__.py new file mode 100644 index 0000000000..9060a7c4a6 --- /dev/null +++ b/esphome/components/rtl87xx/__init__.py @@ -0,0 +1,51 @@ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. +# For custom pin validators, put validate_pin() or validate_usage() +# in gpio.py file in this directory. +# For changing schema/pin schema, put COMPONENT_SCHEMA or COMPONENT_PIN_SCHEMA +# in schema.py file in this directory. + +from esphome import pins +from esphome.components import libretiny +from esphome.components.libretiny.const import ( + COMPONENT_RTL87XX, + KEY_COMPONENT_DATA, + KEY_LIBRETINY, + LibreTinyComponent, +) +from esphome.core import CORE + +from .boards import RTL87XX_BOARDS, RTL87XX_BOARD_PINS + +CODEOWNERS = ["@kuba2k2"] +AUTO_LOAD = ["libretiny"] + +COMPONENT_DATA = LibreTinyComponent( + name=COMPONENT_RTL87XX, + boards=RTL87XX_BOARDS, + board_pins=RTL87XX_BOARD_PINS, + pin_validation=None, + usage_validation=None, +) + + +def _set_core_data(config): + CORE.data[KEY_LIBRETINY] = {} + CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA + return config + + +CONFIG_SCHEMA = libretiny.BASE_SCHEMA + +PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA + +CONFIG_SCHEMA.prepend_extra(_set_core_data) + + +async def to_code(config): + return await libretiny.component_to_code(config) + + +@pins.PIN_SCHEMA_REGISTRY.register("rtl87xx", PIN_SCHEMA) +async def pin_to_code(config): + return await libretiny.gpio.component_pin_to_code(config) diff --git a/esphome/components/rtl87xx/boards.py b/esphome/components/rtl87xx/boards.py new file mode 100644 index 0000000000..6c29467f6e --- /dev/null +++ b/esphome/components/rtl87xx/boards.py @@ -0,0 +1,1390 @@ +# This file was auto-generated by libretiny/generate_components.py +# Do not modify its contents. + +from esphome.components.libretiny.const import FAMILY_RTL8710B, FAMILY_RTL8720C + +RTL87XX_BOARDS = { + "bw12": { + "name": "BW12", + "family": FAMILY_RTL8710B, + }, + "bw15": { + "name": "BW15", + "family": FAMILY_RTL8720C, + }, + "generic-rtl8710bn-2mb-468k": { + "name": "Generic - RTL8710BN (2M/468k)", + "family": FAMILY_RTL8710B, + }, + "generic-rtl8710bn-2mb-788k": { + "name": "Generic - RTL8710BN (2M/788k)", + "family": FAMILY_RTL8710B, + }, + "generic-rtl8710bx-4mb-980k": { + "name": "Generic - RTL8710BX (4M/980k)", + "family": FAMILY_RTL8710B, + }, + "generic-rtl8720cf-2mb-992k": { + "name": "Generic - RTL8720CF (2M/992k)", + "family": FAMILY_RTL8720C, + }, + "t102-v1.1": { + "name": "T102_V1.1", + "family": FAMILY_RTL8710B, + }, + "t103-v1.0": { + "name": "T103_V1.0", + "family": FAMILY_RTL8710B, + }, + "wr1": { + "name": "WR1 Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr1e": { + "name": "WR1E Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr2": { + "name": "WR2 Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr2e": { + "name": "WR2E Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr2l": { + "name": "WR2L Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr2le": { + "name": "WR2LE Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr3": { + "name": "WR3 Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr3e": { + "name": "WR3E Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr3l": { + "name": "WR3L Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr3le": { + "name": "WR3LE Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, + "wr3n": { + "name": "WR3N Wi-Fi Module", + "family": FAMILY_RTL8710B, + }, +} + +RTL87XX_BOARD_PINS = { + "bw12": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 30, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 22, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 5, + "D1": 29, + "D2": 0, + "D3": 19, + "D4": 22, + "D5": 30, + "D6": 14, + "D7": 12, + "D8": 15, + "D9": 18, + "D10": 23, + "A0": 19, + }, + "bw15": { + "SPI0_CS_0": 2, + "SPI0_CS_1": 15, + "SPI0_MISO": 20, + "SPI0_MOSI_0": 4, + "SPI0_MOSI_1": 19, + "SPI0_SCK_0": 16, + "SPI0_SCK_1": 3, + "WIRE0_SCL_0": 2, + "WIRE0_SCL_1": 15, + "WIRE0_SCL_2": 19, + "WIRE0_SDA_0": 20, + "WIRE0_SDA_1": 16, + "WIRE0_SDA_2": 3, + "SERIAL0_RX": 13, + "SERIAL0_TX": 14, + "SERIAL1_CTS": 4, + "SERIAL1_RX_0": 2, + "SERIAL1_RX_1": 0, + "SERIAL1_TX_0": 3, + "SERIAL1_TX_1": 1, + "SERIAL2_CTS": 19, + "SERIAL2_RTS": 20, + "SERIAL2_RX": 15, + "SERIAL2_TX": 16, + "CS0": 15, + "CTS1": 4, + "CTS2": 19, + "MISO0": 20, + "MOSI0": 19, + "PA00": 0, + "PA0": 0, + "PA01": 1, + "PA1": 1, + "PA02": 2, + "PA2": 2, + "PA03": 3, + "PA3": 3, + "PA04": 4, + "PA4": 4, + "PA13": 13, + "PA14": 14, + "PA15": 15, + "PA16": 16, + "PA17": 17, + "PA18": 18, + "PA19": 19, + "PA20": 20, + "PWM0": 0, + "PWM1": 1, + "PWM2": 14, + "PWM3": 3, + "PWM4": 16, + "PWM5": 17, + "PWM6": 18, + "PWM7": 13, + "RTS2": 20, + "RX0": 13, + "RX1": 0, + "RX2": 15, + "SCK0": 3, + "SCL0": 19, + "SDA0": 3, + "TX0": 14, + "TX1": 1, + "TX2": 16, + "D0": 17, + "D1": 18, + "D2": 2, + "D3": 15, + "D4": 4, + "D5": 19, + "D6": 20, + "D7": 16, + "D8": 0, + "D9": 3, + "D10": 1, + "D11": 13, + "D12": 14, + }, + "generic-rtl8710bn-2mb-468k": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "FCS": 6, + "FD0": 9, + "FD1": 7, + "FD2": 8, + "FD3": 11, + "FSCK": 10, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA06": 6, + "PA6": 6, + "PA07": 7, + "PA7": 7, + "PA08": 8, + "PA8": 8, + "PA09": 9, + "PA9": 9, + "PA10": 10, + "PA11": 11, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 30, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 0, + "D1": 5, + "D2": 6, + "D3": 7, + "D4": 8, + "D5": 9, + "D6": 10, + "D7": 11, + "D8": 12, + "D9": 14, + "D10": 15, + "D11": 18, + "D12": 19, + "D13": 22, + "D14": 23, + "D15": 29, + "D16": 30, + "A0": 19, + "A1": 41, + }, + "generic-rtl8710bn-2mb-788k": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "FCS": 6, + "FD0": 9, + "FD1": 7, + "FD2": 8, + "FD3": 11, + "FSCK": 10, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA06": 6, + "PA6": 6, + "PA07": 7, + "PA7": 7, + "PA08": 8, + "PA8": 8, + "PA09": 9, + "PA9": 9, + "PA10": 10, + "PA11": 11, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 30, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 0, + "D1": 5, + "D2": 6, + "D3": 7, + "D4": 8, + "D5": 9, + "D6": 10, + "D7": 11, + "D8": 12, + "D9": 14, + "D10": 15, + "D11": 18, + "D12": 19, + "D13": 22, + "D14": 23, + "D15": 29, + "D16": 30, + "A0": 19, + "A1": 41, + }, + "generic-rtl8710bx-4mb-980k": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "FCS": 6, + "FD0": 9, + "FD1": 7, + "FD2": 8, + "FD3": 11, + "FSCK": 10, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA06": 6, + "PA6": 6, + "PA07": 7, + "PA7": 7, + "PA08": 8, + "PA8": 8, + "PA09": 9, + "PA9": 9, + "PA10": 10, + "PA11": 11, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 30, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 0, + "D1": 5, + "D2": 6, + "D3": 7, + "D4": 8, + "D5": 9, + "D6": 10, + "D7": 11, + "D8": 12, + "D9": 14, + "D10": 15, + "D11": 18, + "D12": 19, + "D13": 22, + "D14": 23, + "D15": 29, + "D16": 30, + "A0": 19, + }, + "generic-rtl8720cf-2mb-992k": { + "SPI0_CS_0": 2, + "SPI0_CS_1": 7, + "SPI0_CS_2": 15, + "SPI0_MISO_0": 10, + "SPI0_MISO_1": 20, + "SPI0_MOSI_0": 4, + "SPI0_MOSI_1": 9, + "SPI0_MOSI_2": 19, + "SPI0_SCK_0": 3, + "SPI0_SCK_1": 8, + "SPI0_SCK_2": 16, + "WIRE0_SCL_0": 2, + "WIRE0_SCL_1": 11, + "WIRE0_SCL_2": 15, + "WIRE0_SCL_3": 19, + "WIRE0_SDA_0": 3, + "WIRE0_SDA_1": 12, + "WIRE0_SDA_2": 16, + "WIRE0_SDA_3": 20, + "SERIAL0_CTS": 10, + "SERIAL0_RTS": 9, + "SERIAL0_RX_0": 12, + "SERIAL0_RX_1": 13, + "SERIAL0_TX_0": 11, + "SERIAL0_TX_1": 14, + "SERIAL1_CTS": 4, + "SERIAL1_RX_0": 0, + "SERIAL1_RX_1": 2, + "SERIAL1_TX_0": 1, + "SERIAL1_TX_1": 3, + "SERIAL2_CTS": 19, + "SERIAL2_RTS": 20, + "SERIAL2_RX": 15, + "SERIAL2_TX": 16, + "CS0": 15, + "CTS0": 10, + "CTS1": 4, + "CTS2": 19, + "MISO0": 20, + "MOSI0": 19, + "PA00": 0, + "PA0": 0, + "PA01": 1, + "PA1": 1, + "PA02": 2, + "PA2": 2, + "PA03": 3, + "PA3": 3, + "PA04": 4, + "PA4": 4, + "PA07": 7, + "PA7": 7, + "PA08": 8, + "PA8": 8, + "PA09": 9, + "PA9": 9, + "PA10": 10, + "PA11": 11, + "PA12": 12, + "PA13": 13, + "PA14": 14, + "PA15": 15, + "PA16": 16, + "PA17": 17, + "PA18": 18, + "PA19": 19, + "PA20": 20, + "PA23": 23, + "PWM0": 20, + "PWM1": 12, + "PWM2": 14, + "PWM3": 15, + "PWM4": 16, + "PWM5": 17, + "PWM6": 18, + "PWM7": 23, + "RTS0": 9, + "RTS2": 20, + "RX0": 13, + "RX1": 2, + "RX2": 15, + "SCK0": 16, + "SCL0": 19, + "SDA0": 20, + "TX0": 14, + "TX1": 3, + "TX2": 16, + "D0": 0, + "D1": 1, + "D2": 2, + "D3": 3, + "D4": 4, + "D5": 7, + "D6": 8, + "D7": 9, + "D8": 10, + "D9": 11, + "D10": 12, + "D11": 13, + "D12": 14, + "D13": 15, + "D14": 16, + "D15": 17, + "D16": 18, + "D17": 19, + "D18": 20, + "D19": 23, + }, + "t102-v1.1": { + "WIRE0_SCL": 29, + "WIRE0_SDA": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 14, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 29, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 12, + "D1": 0, + "D2": 5, + "D3": 30, + "D4": 29, + "D5": 18, + "D6": 23, + "D7": 14, + "D8": 15, + }, + "t103-v1.0": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 19, + "D1": 14, + "D2": 15, + "D3": 0, + "D4": 22, + "D5": 29, + "D6": 30, + "D7": 5, + "D8": 12, + "D9": 18, + "D10": 23, + "A0": 19, + "A1": 41, + }, + "wr1": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 30, + "WIRE0_SDA_1": 19, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 14, + "PWM1": 15, + "PWM2": 0, + "PWM4": 29, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 22, + "SCL1": 18, + "SDA0": 19, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 23, + "D1": 18, + "D2": 14, + "D3": 15, + "D4": 30, + "D5": 0, + "D6": 5, + "D7": 29, + "D8": 19, + "D9": 22, + "A0": 19, + "A1": 41, + }, + "wr1e": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 30, + "WIRE0_SDA_1": 19, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 14, + "PWM1": 15, + "PWM3": 12, + "PWM4": 29, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 22, + "SCL1": 18, + "SDA0": 19, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 23, + "D1": 18, + "D2": 14, + "D3": 15, + "D4": 30, + "D5": 12, + "D6": 5, + "D7": 29, + "D8": 19, + "D9": 22, + "A0": 19, + "A1": 41, + }, + "wr2": { + "WIRE0_SCL": 29, + "WIRE0_SDA": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC2": 41, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 14, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 29, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 12, + "D1": 0, + "D2": 5, + "D4": 18, + "D5": 23, + "D6": 14, + "D7": 15, + "D8": 30, + "D9": 29, + "A1": 41, + }, + "wr2e": { + "WIRE0_SCL": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MOSI0": 23, + "MOSI1": 23, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 14, + "PWM1": 15, + "PWM3": 12, + "PWM4": 29, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 12, + "D1": 19, + "D2": 5, + "D3": 18, + "D4": 23, + "D5": 14, + "D6": 15, + "D7": 30, + "D8": 29, + "A0": 19, + "A1": 41, + }, + "wr2l": { + "ADC1": 19, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA19": 19, + "PWM0": 14, + "PWM1": 15, + "PWM3": 12, + "PWM4": 5, + "SDA0": 19, + "D0": 15, + "D1": 14, + "D2": 5, + "D3": 19, + "D4": 12, + "A0": 19, + }, + "wr2le": { + "MISO0": 22, + "MISO1": 22, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA22": 22, + "PWM0": 14, + "PWM1": 15, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "SCL0": 22, + "D0": 15, + "D1": 14, + "D2": 5, + "D3": 22, + "D4": 12, + }, + "wr3": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 22, + "D1": 19, + "D2": 14, + "D3": 15, + "D4": 0, + "D5": 29, + "D6": 30, + "D7": 5, + "D8": 12, + "D9": 18, + "D10": 23, + "A0": 19, + "A1": 41, + }, + "wr3e": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 30, + "WIRE0_SDA_1": 19, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 22, + "SCL1": 18, + "SDA0": 19, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 29, + "D1": 14, + "D2": 15, + "D3": 22, + "D4": 0, + "D5": 30, + "D6": 19, + "D7": 5, + "D8": 12, + "D9": 18, + "D10": 23, + "A0": 19, + "A1": 41, + }, + "wr3l": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 22, + "WIRE0_SCL_1": 29, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 22, + "D1": 19, + "D2": 14, + "D3": 15, + "D4": 0, + "D5": 29, + "D6": 30, + "D7": 5, + "D8": 12, + "D9": 18, + "D10": 23, + "A0": 19, + "A1": 41, + }, + "wr3le": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 30, + "WIRE0_SDA_1": 19, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "ADC2": 41, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 22, + "SCL1": 18, + "SDA0": 19, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 29, + "D1": 14, + "D2": 15, + "D3": 22, + "D4": 0, + "D5": 30, + "D6": 19, + "D7": 5, + "D8": 12, + "D9": 18, + "D10": 23, + "A0": 19, + "A1": 41, + }, + "wr3n": { + "WIRE0_SCL": 29, + "WIRE0_SDA": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC2": 41, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM0": 23, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 5, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL0": 29, + "SCL1": 18, + "SDA0": 30, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 29, + "D1": 14, + "D2": 15, + "D3": 0, + "D4": 30, + "D5": 5, + "D6": 12, + "D7": 18, + "D8": 23, + "A1": 41, + }, +} + +BOARDS = RTL87XX_BOARDS diff --git a/esphome/components/sntp/sntp_component.cpp b/esphome/components/sntp/sntp_component.cpp index 3af21a9b23..418eacd870 100644 --- a/esphome/components/sntp/sntp_component.cpp +++ b/esphome/components/sntp/sntp_component.cpp @@ -1,7 +1,7 @@ #include "sntp_component.h" #include "esphome/core/log.h" -#ifdef USE_ESP32 +#if defined(USE_ESP32) || defined(USE_LIBRETINY) #include "lwip/apps/sntp.h" #ifdef USE_ESP_IDF #include "esp_sntp.h" @@ -26,7 +26,7 @@ static const char *const TAG = "sntp"; void SNTPComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SNTP..."); -#ifdef USE_ESP32 +#if defined(USE_ESP32) || defined(USE_LIBRETINY) if (sntp_enabled()) { sntp_stop(); } diff --git a/esphome/components/socket/__init__.py b/esphome/components/socket/__init__.py index 1757ec4668..19952aeece 100644 --- a/esphome/components/socket/__init__.py +++ b/esphome/components/socket/__init__.py @@ -5,6 +5,7 @@ CODEOWNERS = ["@esphome/core"] CONF_IMPLEMENTATION = "implementation" IMPLEMENTATION_LWIP_TCP = "lwip_tcp" +IMPLEMENTATION_LWIP_SOCKETS = "lwip_sockets" IMPLEMENTATION_BSD_SOCKETS = "bsd_sockets" CONFIG_SCHEMA = cv.Schema( @@ -14,9 +15,15 @@ CONFIG_SCHEMA = cv.Schema( esp8266=IMPLEMENTATION_LWIP_TCP, esp32=IMPLEMENTATION_BSD_SOCKETS, rp2040=IMPLEMENTATION_LWIP_TCP, + bk72xx=IMPLEMENTATION_LWIP_SOCKETS, + rtl87xx=IMPLEMENTATION_LWIP_SOCKETS, host=IMPLEMENTATION_BSD_SOCKETS, ): cv.one_of( - IMPLEMENTATION_LWIP_TCP, IMPLEMENTATION_BSD_SOCKETS, lower=True, space="_" + IMPLEMENTATION_LWIP_TCP, + IMPLEMENTATION_LWIP_SOCKETS, + IMPLEMENTATION_BSD_SOCKETS, + lower=True, + space="_", ), } ) @@ -26,5 +33,7 @@ async def to_code(config): impl = config[CONF_IMPLEMENTATION] if impl == IMPLEMENTATION_LWIP_TCP: cg.add_define("USE_SOCKET_IMPL_LWIP_TCP") + elif impl == IMPLEMENTATION_LWIP_SOCKETS: + cg.add_define("USE_SOCKET_IMPL_LWIP_SOCKETS") elif impl == IMPLEMENTATION_BSD_SOCKETS: cg.add_define("USE_SOCKET_IMPL_BSD_SOCKETS") diff --git a/esphome/components/socket/headers.h b/esphome/components/socket/headers.h index 1922885ac0..032892072d 100644 --- a/esphome/components/socket/headers.h +++ b/esphome/components/socket/headers.h @@ -120,6 +120,35 @@ struct iovec { #endif // USE_SOCKET_IMPL_LWIP_TCP +#ifdef USE_SOCKET_IMPL_LWIP_SOCKETS + +// standard lwIP's compatibility macros will interfere +// with Socket class function names - disable the macros +// and use real function names instead +#undef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 0 + +#include "lwip/sockets.h" +#include + +#ifdef USE_ARDUINO +// arduino-esp32 declares a global var called INADDR_NONE which is replaced +// by the define +#ifdef INADDR_NONE +#undef INADDR_NONE +#endif +// not defined for ESP32 +using socklen_t = uint32_t; + +#define ESPHOME_INADDR_ANY ((uint32_t) 0x00000000UL) +#define ESPHOME_INADDR_NONE ((uint32_t) 0xFFFFFFFFUL) +#else // !USE_ESP32 +#define ESPHOME_INADDR_ANY INADDR_ANY +#define ESPHOME_INADDR_NONE INADDR_NONE +#endif + +#endif // USE_SOCKET_IMPL_LWIP_SOCKETS + #ifdef USE_SOCKET_IMPL_BSD_SOCKETS #include diff --git a/esphome/components/socket/lwip_sockets_impl.cpp b/esphome/components/socket/lwip_sockets_impl.cpp new file mode 100644 index 0000000000..eaf6ac2c6f --- /dev/null +++ b/esphome/components/socket/lwip_sockets_impl.cpp @@ -0,0 +1,115 @@ +#include "socket.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" + +#ifdef USE_SOCKET_IMPL_LWIP_SOCKETS + +#include + +namespace esphome { +namespace socket { + +std::string format_sockaddr(const struct sockaddr_storage &storage) { + if (storage.ss_family == AF_INET) { + const struct sockaddr_in *addr = reinterpret_cast(&storage); + char buf[INET_ADDRSTRLEN]; + const char *ret = lwip_inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)); + if (ret == nullptr) + return {}; + return std::string{buf}; + } +#if LWIP_IPV6 + else if (storage.ss_family == AF_INET6) { + const struct sockaddr_in6 *addr = reinterpret_cast(&storage); + char buf[INET6_ADDRSTRLEN]; + const char *ret = lwip_inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)); + if (ret == nullptr) + return {}; + return std::string{buf}; + } +#endif + return {}; +} + +class LwIPSocketImpl : public Socket { + public: + LwIPSocketImpl(int fd) : fd_(fd) {} + ~LwIPSocketImpl() override { + if (!closed_) { + close(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall) + } + } + std::unique_ptr accept(struct sockaddr *addr, socklen_t *addrlen) override { + int fd = lwip_accept(fd_, addr, addrlen); + if (fd == -1) + return {}; + return make_unique(fd); + } + int bind(const struct sockaddr *addr, socklen_t addrlen) override { return lwip_bind(fd_, addr, addrlen); } + int close() override { + int ret = lwip_close(fd_); + closed_ = true; + return ret; + } + int shutdown(int how) override { return lwip_shutdown(fd_, how); } + + int getpeername(struct sockaddr *addr, socklen_t *addrlen) override { return lwip_getpeername(fd_, addr, addrlen); } + std::string getpeername() override { + struct sockaddr_storage storage; + socklen_t len = sizeof(storage); + int err = this->getpeername((struct sockaddr *) &storage, &len); + if (err != 0) + return {}; + return format_sockaddr(storage); + } + int getsockname(struct sockaddr *addr, socklen_t *addrlen) override { return lwip_getsockname(fd_, addr, addrlen); } + std::string getsockname() override { + struct sockaddr_storage storage; + socklen_t len = sizeof(storage); + int err = this->getsockname((struct sockaddr *) &storage, &len); + if (err != 0) + return {}; + return format_sockaddr(storage); + } + int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override { + return lwip_getsockopt(fd_, level, optname, optval, optlen); + } + int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override { + return lwip_setsockopt(fd_, level, optname, optval, optlen); + } + int listen(int backlog) override { return lwip_listen(fd_, backlog); } + ssize_t read(void *buf, size_t len) override { return lwip_read(fd_, buf, len); } + ssize_t readv(const struct iovec *iov, int iovcnt) override { return lwip_readv(fd_, iov, iovcnt); } + ssize_t write(const void *buf, size_t len) override { return lwip_write(fd_, buf, len); } + ssize_t send(void *buf, size_t len, int flags) { return lwip_send(fd_, buf, len, flags); } + ssize_t writev(const struct iovec *iov, int iovcnt) override { return lwip_writev(fd_, iov, iovcnt); } + ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override { + return lwip_sendto(fd_, buf, len, flags, to, tolen); + } + int setblocking(bool blocking) override { + int fl = lwip_fcntl(fd_, F_GETFL, 0); + if (blocking) { + fl &= ~O_NONBLOCK; + } else { + fl |= O_NONBLOCK; + } + lwip_fcntl(fd_, F_SETFL, fl); + return 0; + } + + protected: + int fd_; + bool closed_ = false; +}; + +std::unique_ptr socket(int domain, int type, int protocol) { + int ret = lwip_socket(domain, type, protocol); + if (ret == -1) + return nullptr; + return std::unique_ptr{new LwIPSocketImpl(ret)}; +} + +} // namespace socket +} // namespace esphome + +#endif // USE_SOCKET_IMPL_LWIP_SOCKETS diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 57a4fa9f4e..a2ef956200 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -48,6 +48,7 @@ CONFIG_SCHEMA = cv.All( } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), + cv.only_on(["esp32", "esp8266", "rp2040"]), ) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index aea59d9d8b..36f2bb5851 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -42,6 +42,9 @@ ESP8266UartComponent = uart_ns.class_( "ESP8266UartComponent", UARTComponent, cg.Component ) RP2040UartComponent = uart_ns.class_("RP2040UartComponent", UARTComponent, cg.Component) +LibreTinyUARTComponent = uart_ns.class_( + "LibreTinyUARTComponent", UARTComponent, cg.Component +) UARTDevice = uart_ns.class_("UARTDevice") UARTWriteAction = uart_ns.class_("UARTWriteAction", automation.Action) @@ -92,6 +95,8 @@ def _uart_declare_type(value): return cv.declare_id(IDFUARTComponent)(value) if CORE.is_rp2040: return cv.declare_id(RP2040UartComponent)(value) + if CORE.is_libretiny: + return cv.declare_id(LibreTinyUARTComponent)(value) raise NotImplementedError diff --git a/esphome/components/uart/uart_component_libretiny.cpp b/esphome/components/uart/uart_component_libretiny.cpp new file mode 100644 index 0000000000..c5e299e9d1 --- /dev/null +++ b/esphome/components/uart/uart_component_libretiny.cpp @@ -0,0 +1,168 @@ +#ifdef USE_LIBRETINY + +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include "uart_component_libretiny.h" + +#ifdef USE_LOGGER +#include "esphome/components/logger/logger.h" +#endif + +#if LT_ARD_HAS_SOFTSERIAL +#include +#endif + +namespace esphome { +namespace uart { + +static const char *const TAG = "uart.lt"; + +static const char *UART_TYPE[] = { + "hardware", + "software", +}; + +uint16_t LibreTinyUARTComponent::get_config() { + uint16_t config = 0; + + switch (this->parity_) { + case UART_CONFIG_PARITY_NONE: + config |= SERIAL_PARITY_NONE; + break; + case UART_CONFIG_PARITY_EVEN: + config |= SERIAL_PARITY_EVEN; + break; + case UART_CONFIG_PARITY_ODD: + config |= SERIAL_PARITY_ODD; + break; + } + + config |= (this->data_bits_ - 4) << 8; + config |= 0x10 + (this->stop_bits_ - 1) * 0x20; + + return config; +} + +void LibreTinyUARTComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up UART..."); + + int8_t tx_pin = tx_pin_ == nullptr ? -1 : tx_pin_->get_pin(); + int8_t rx_pin = rx_pin_ == nullptr ? -1 : rx_pin_->get_pin(); + bool tx_inverted = tx_pin_ != nullptr && tx_pin_->is_inverted(); + bool rx_inverted = rx_pin_ != nullptr && rx_pin_->is_inverted(); + + if (false) + return; +#if LT_HW_UART0 + else if ((tx_pin == -1 || tx_pin == PIN_SERIAL0_TX) && (rx_pin == -1 || rx_pin == PIN_SERIAL0_RX)) { + this->serial_ = &Serial0; + this->hardware_idx_ = 0; + } +#endif +#if LT_HW_UART1 + else if ((tx_pin == -1 || tx_pin == PIN_SERIAL1_TX) && (rx_pin == -1 || rx_pin == PIN_SERIAL1_RX)) { + this->serial_ = &Serial1; + this->hardware_idx_ = 1; + } +#endif +#if LT_HW_UART2 + else if ((tx_pin == -1 || tx_pin == PIN_SERIAL2_TX) && (rx_pin == -1 || rx_pin == PIN_SERIAL2_RX)) { + this->serial_ = &Serial2; + this->hardware_idx_ = 2; + } +#endif + else { +#if LT_ARD_HAS_SOFTSERIAL + this->serial_ = new SoftwareSerial(rx_pin, tx_pin, rx_inverted || tx_inverted); +#else + this->serial_ = &Serial; + ESP_LOGE(TAG, " SoftwareSerial is not implemented for this chip. Only hardware pins are supported:"); +#if LT_HW_UART0 + ESP_LOGE(TAG, " TX=%u, RX=%u", PIN_SERIAL0_TX, PIN_SERIAL0_RX); +#endif +#if LT_HW_UART1 + ESP_LOGE(TAG, " TX=%u, RX=%u", PIN_SERIAL1_TX, PIN_SERIAL1_RX); +#endif +#if LT_HW_UART2 + ESP_LOGE(TAG, " TX=%u, RX=%u", PIN_SERIAL2_TX, PIN_SERIAL2_RX); +#endif + this->mark_failed(); + return; +#endif + } + + this->serial_->begin(this->baud_rate_, get_config()); +} + +void LibreTinyUARTComponent::dump_config() { + bool is_software = this->hardware_idx_ == -1; + ESP_LOGCONFIG(TAG, "UART Bus:"); + ESP_LOGCONFIG(TAG, " Type: %s", UART_TYPE[is_software]); + if (!is_software) { + ESP_LOGCONFIG(TAG, " Port number: %d", this->hardware_idx_); + } + LOG_PIN(" TX Pin: ", tx_pin_); + LOG_PIN(" RX Pin: ", rx_pin_); + if (this->rx_pin_ != nullptr) { + ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); + } + ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); + ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); + ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); + ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + this->check_logger_conflict(); +} + +void LibreTinyUARTComponent::write_array(const uint8_t *data, size_t len) { + this->serial_->write(data, len); +#ifdef USE_UART_DEBUGGER + for (size_t i = 0; i < len; i++) { + this->debug_callback_.call(UART_DIRECTION_TX, data[i]); + } +#endif +} + +bool LibreTinyUARTComponent::peek_byte(uint8_t *data) { + if (!this->check_read_timeout_()) + return false; + *data = this->serial_->peek(); + return true; +} + +bool LibreTinyUARTComponent::read_array(uint8_t *data, size_t len) { + if (!this->check_read_timeout_(len)) + return false; + this->serial_->readBytes(data, len); +#ifdef USE_UART_DEBUGGER + for (size_t i = 0; i < len; i++) { + this->debug_callback_.call(UART_DIRECTION_RX, data[i]); + } +#endif + return true; +} + +int LibreTinyUARTComponent::available() { return this->serial_->available(); } +void LibreTinyUARTComponent::flush() { + ESP_LOGVV(TAG, " Flushing..."); + this->serial_->flush(); +} + +void LibreTinyUARTComponent::check_logger_conflict() { +#ifdef USE_LOGGER + if (this->hardware_idx_ == -1 || logger::global_logger->get_baud_rate() == 0) { + return; + } + + if (this->serial_ == logger::global_logger->get_hw_serial()) { + ESP_LOGW(TAG, " You're using the same serial port for logging and the UART component. Please " + "disable logging over the serial port by setting logger->baud_rate to 0."); + } +#endif +} + +} // namespace uart +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/uart/uart_component_libretiny.h b/esphome/components/uart/uart_component_libretiny.h new file mode 100644 index 0000000000..00982fd297 --- /dev/null +++ b/esphome/components/uart/uart_component_libretiny.h @@ -0,0 +1,43 @@ +#pragma once + +#ifdef USE_LIBRETINY + +#include +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "uart_component.h" + +namespace esphome { +namespace uart { + +class LibreTinyUARTComponent : public UARTComponent, public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::BUS; } + + void write_array(const uint8_t *data, size_t len) override; + + bool peek_byte(uint8_t *data) override; + bool read_array(uint8_t *data, size_t len) override; + + int available() override; + void flush() override; + + uint16_t get_config(); + + HardwareSerial *get_hw_serial() { return this->serial_; } + int8_t get_hw_serial_number() { return this->hardware_idx_; } + + protected: + void check_logger_conflict() override; + + HardwareSerial *serial_{nullptr}; + int8_t hardware_idx_{-1}; +}; + +} // namespace uart +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index b1cf8a5de6..c6d9c31e93 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -79,13 +79,18 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean, cv.SplitDefault( - CONF_OTA, esp8266=True, esp32_arduino=True, esp32_idf=False + CONF_OTA, + esp8266=True, + esp32_arduino=True, + esp32_idf=False, + bk72xx=True, + rtl87xx=True, ): cv.boolean, cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), - cv.only_on(["esp32", "esp8266"]), + cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), default_url, validate_local, validate_ota, diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 87f23a990a..6491446bcc 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -37,4 +37,4 @@ async def to_code(config): cg.add_library("FS", None) cg.add_library("Update", None) # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json - cg.add_library("esphome/ESPAsyncWebServer-esphome", "2.1.0") + cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.1.0") diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp index 997ce0798a..f90c7e56a3 100644 --- a/esphome/components/web_server_base/web_server_base.cpp +++ b/esphome/components/web_server_base/web_server_base.cpp @@ -5,7 +5,7 @@ #ifdef USE_ARDUINO #include -#ifdef USE_ESP32 +#if defined(USE_ESP32) || defined(USE_LIBRETINY) #include #endif #ifdef USE_ESP8266 @@ -50,7 +50,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin // NOLINTNEXTLINE(readability-static-accessed-through-instance) success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); #endif -#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY) if (Update.isRunning()) { Update.abort(); } diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 068d015732..1baffcbfcc 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -272,7 +272,12 @@ CONFIG_SCHEMA = cv.All( CONF_REBOOT_TIMEOUT, default="15min" ): cv.positive_time_period_milliseconds, cv.SplitDefault( - CONF_POWER_SAVE_MODE, esp8266="none", esp32="light", rp2040="light" + CONF_POWER_SAVE_MODE, + esp8266="none", + esp32="light", + rp2040="light", + bk72xx="none", + rtl87xx="none", ): cv.enum(WIFI_POWER_SAVE_MODES, upper=True), cv.Optional(CONF_FAST_CONNECT, default=False): cv.boolean, cv.Optional(CONF_USE_ADDRESS): cv.string_strict, diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index c17246fd00..b418a5b353 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -15,6 +15,10 @@ #include #endif +#ifdef USE_LIBRETINY +#include +#endif + #ifdef USE_ESP8266 #include #include @@ -336,6 +340,11 @@ class WiFiComponent : public Component { void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result); #endif +#ifdef USE_LIBRETINY + void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info); + void wifi_scan_done_callback_(); +#endif + std::string use_address_; std::vector sta_; std::vector sta_priorities_; diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp new file mode 100644 index 0000000000..abad5aca9c --- /dev/null +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -0,0 +1,467 @@ +#include "wifi_component.h" + +#ifdef USE_LIBRETINY + +#include +#include +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/dns.h" + +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include "esphome/core/application.h" +#include "esphome/core/util.h" + +namespace esphome { +namespace wifi { + +static const char *const TAG = "wifi_lt"; + +static bool s_sta_connecting = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +bool WiFiComponent::wifi_mode_(optional sta, optional ap) { + uint8_t current_mode = WiFi.getMode(); + bool current_sta = current_mode & 0b01; + bool current_ap = current_mode & 0b10; + bool enable_sta = sta.value_or(current_sta); + bool enable_ap = ap.value_or(current_ap); + if (current_sta == enable_sta && current_ap == enable_ap) + return true; + + if (enable_sta && !current_sta) { + ESP_LOGV(TAG, "Enabling STA."); + } else if (!enable_sta && current_sta) { + ESP_LOGV(TAG, "Disabling STA."); + } + if (enable_ap && !current_ap) { + ESP_LOGV(TAG, "Enabling AP."); + } else if (!enable_ap && current_ap) { + ESP_LOGV(TAG, "Disabling AP."); + } + + uint8_t mode = 0; + if (enable_sta) + mode |= 0b01; + if (enable_ap) + mode |= 0b10; + bool ret = WiFi.mode(static_cast(mode)); + + if (!ret) { + ESP_LOGW(TAG, "Setting WiFi mode failed!"); + } + + return ret; +} +bool WiFiComponent::wifi_apply_output_power_(float output_power) { + int8_t val = static_cast(output_power * 4); + return WiFi.setTxPower(val); +} +bool WiFiComponent::wifi_sta_pre_setup_() { + if (!this->wifi_mode_(true, {})) + return false; + + WiFi.setAutoReconnect(false); + delay(10); + return true; +} +bool WiFiComponent::wifi_apply_power_save_() { return WiFi.setSleep(this->power_save_ != WIFI_POWER_SAVE_NONE); } +bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { + // enable STA + if (!this->wifi_mode_(true, {})) + return false; + + if (!manual_ip.has_value()) { + return true; + } + + WiFi.config(static_cast(manual_ip->static_ip), static_cast(manual_ip->gateway), + static_cast(manual_ip->subnet), static_cast(manual_ip->dns1), + static_cast(manual_ip->dns2)); + + return true; +} + +network::IPAddress WiFiComponent::wifi_sta_ip() { + if (!this->has_sta()) + return {}; + return {WiFi.localIP()}; +} + +bool WiFiComponent::wifi_apply_hostname_() { + // setting is done in SYSTEM_EVENT_STA_START callback too + WiFi.setHostname(App.get_name().c_str()); + return true; +} +bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { + // enable STA + if (!this->wifi_mode_(true, {})) + return false; + + String ssid = WiFi.SSID(); + if (ssid && strcmp(ssid.c_str(), ap.get_ssid().c_str()) != 0) { + WiFi.disconnect(); + } + + if (!this->wifi_sta_ip_config_(ap.get_manual_ip())) { + return false; + } + + this->wifi_apply_hostname_(); + + s_sta_connecting = true; + + WiFiStatus status = WiFi.begin(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(), + ap.get_channel().has_value() ? *ap.get_channel() : 0, + ap.get_bssid().has_value() ? ap.get_bssid()->data() : NULL); + if (status != WL_CONNECTED) { + ESP_LOGW(TAG, "esp_wifi_connect failed! %d", status); + return false; + } + + return true; +} +const char *get_auth_mode_str(uint8_t mode) { + switch (mode) { + case WIFI_AUTH_OPEN: + return "OPEN"; + case WIFI_AUTH_WEP: + return "WEP"; + case WIFI_AUTH_WPA_PSK: + return "WPA PSK"; + case WIFI_AUTH_WPA2_PSK: + return "WPA2 PSK"; + case WIFI_AUTH_WPA_WPA2_PSK: + return "WPA/WPA2 PSK"; + default: + return "UNKNOWN"; + } +} + +using esphome_ip4_addr_t = IPAddress; + +std::string format_ip4_addr(const esphome_ip4_addr_t &ip) { + char buf[20]; + uint32_t addr = ip; + sprintf(buf, "%u.%u.%u.%u", uint8_t(addr >> 0), uint8_t(addr >> 8), uint8_t(addr >> 16), uint8_t(addr >> 24)); + return buf; +} +const char *get_op_mode_str(uint8_t mode) { + switch (mode) { + case WIFI_OFF: + return "OFF"; + case WIFI_STA: + return "STA"; + case WIFI_AP: + return "AP"; + case WIFI_AP_STA: + return "AP+STA"; + default: + return "UNKNOWN"; + } +} +const char *get_disconnect_reason_str(uint8_t reason) { + switch (reason) { + case WIFI_REASON_AUTH_EXPIRE: + return "Auth Expired"; + case WIFI_REASON_AUTH_LEAVE: + return "Auth Leave"; + case WIFI_REASON_ASSOC_EXPIRE: + return "Association Expired"; + case WIFI_REASON_ASSOC_TOOMANY: + return "Too Many Associations"; + case WIFI_REASON_NOT_AUTHED: + return "Not Authenticated"; + case WIFI_REASON_NOT_ASSOCED: + return "Not Associated"; + case WIFI_REASON_ASSOC_LEAVE: + return "Association Leave"; + case WIFI_REASON_ASSOC_NOT_AUTHED: + return "Association not Authenticated"; + case WIFI_REASON_DISASSOC_PWRCAP_BAD: + return "Disassociate Power Cap Bad"; + case WIFI_REASON_DISASSOC_SUPCHAN_BAD: + return "Disassociate Supported Channel Bad"; + case WIFI_REASON_IE_INVALID: + return "IE Invalid"; + case WIFI_REASON_MIC_FAILURE: + return "Mic Failure"; + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + return "4-Way Handshake Timeout"; + case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: + return "Group Key Update Timeout"; + case WIFI_REASON_IE_IN_4WAY_DIFFERS: + return "IE In 4-Way Handshake Differs"; + case WIFI_REASON_GROUP_CIPHER_INVALID: + return "Group Cipher Invalid"; + case WIFI_REASON_PAIRWISE_CIPHER_INVALID: + return "Pairwise Cipher Invalid"; + case WIFI_REASON_AKMP_INVALID: + return "AKMP Invalid"; + case WIFI_REASON_UNSUPP_RSN_IE_VERSION: + return "Unsupported RSN IE version"; + case WIFI_REASON_INVALID_RSN_IE_CAP: + return "Invalid RSN IE Cap"; + case WIFI_REASON_802_1X_AUTH_FAILED: + return "802.1x Authentication Failed"; + case WIFI_REASON_CIPHER_SUITE_REJECTED: + return "Cipher Suite Rejected"; + case WIFI_REASON_BEACON_TIMEOUT: + return "Beacon Timeout"; + case WIFI_REASON_NO_AP_FOUND: + return "AP Not Found"; + case WIFI_REASON_AUTH_FAIL: + return "Authentication Failed"; + case WIFI_REASON_ASSOC_FAIL: + return "Association Failed"; + case WIFI_REASON_HANDSHAKE_TIMEOUT: + return "Handshake Failed"; + case WIFI_REASON_CONNECTION_FAIL: + return "Connection Failed"; + case WIFI_REASON_UNSPECIFIED: + default: + return "Unspecified"; + } +} + +#define ESPHOME_EVENT_ID_WIFI_READY ARDUINO_EVENT_WIFI_READY +#define ESPHOME_EVENT_ID_WIFI_SCAN_DONE ARDUINO_EVENT_WIFI_SCAN_DONE +#define ESPHOME_EVENT_ID_WIFI_STA_START ARDUINO_EVENT_WIFI_STA_START +#define ESPHOME_EVENT_ID_WIFI_STA_STOP ARDUINO_EVENT_WIFI_STA_STOP +#define ESPHOME_EVENT_ID_WIFI_STA_CONNECTED ARDUINO_EVENT_WIFI_STA_CONNECTED +#define ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED ARDUINO_EVENT_WIFI_STA_DISCONNECTED +#define ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE +#define ESPHOME_EVENT_ID_WIFI_STA_GOT_IP ARDUINO_EVENT_WIFI_STA_GOT_IP +#define ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6 ARDUINO_EVENT_WIFI_STA_GOT_IP6 +#define ESPHOME_EVENT_ID_WIFI_STA_LOST_IP ARDUINO_EVENT_WIFI_STA_LOST_IP +#define ESPHOME_EVENT_ID_WIFI_AP_START ARDUINO_EVENT_WIFI_AP_START +#define ESPHOME_EVENT_ID_WIFI_AP_STOP ARDUINO_EVENT_WIFI_AP_STOP +#define ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED ARDUINO_EVENT_WIFI_AP_STACONNECTED +#define ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED ARDUINO_EVENT_WIFI_AP_STADISCONNECTED +#define ESPHOME_EVENT_ID_WIFI_AP_STAIPASSIGNED ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED +#define ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED +#define ESPHOME_EVENT_ID_WIFI_AP_GOT_IP6 ARDUINO_EVENT_WIFI_AP_GOT_IP6 +using esphome_wifi_event_id_t = arduino_event_id_t; +using esphome_wifi_event_info_t = arduino_event_info_t; + +void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_wifi_event_info_t info) { + switch (event) { + case ESPHOME_EVENT_ID_WIFI_READY: { + ESP_LOGV(TAG, "Event: WiFi ready"); + break; + } + case ESPHOME_EVENT_ID_WIFI_SCAN_DONE: { + auto it = info.wifi_scan_done; + ESP_LOGV(TAG, "Event: WiFi Scan Done status=%u number=%u scan_id=%u", it.status, it.number, it.scan_id); + + this->wifi_scan_done_callback_(); + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_START: { + ESP_LOGV(TAG, "Event: WiFi STA start"); + WiFi.setHostname(App.get_name().c_str()); + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_STOP: { + ESP_LOGV(TAG, "Event: WiFi STA stop"); + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_CONNECTED: { + auto it = info.wifi_sta_connected; + char buf[33]; + memcpy(buf, it.ssid, it.ssid_len); + buf[it.ssid_len] = '\0'; + ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, + format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); + + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: { + auto it = info.wifi_sta_disconnected; + char buf[33]; + memcpy(buf, it.ssid, it.ssid_len); + buf[it.ssid_len] = '\0'; + if (it.reason == WIFI_REASON_NO_AP_FOUND) { + ESP_LOGW(TAG, "Event: Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf); + } else { + ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, + format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason)); + } + + uint8_t reason = it.reason; + if (reason == WIFI_REASON_AUTH_EXPIRE || reason == WIFI_REASON_BEACON_TIMEOUT || + reason == WIFI_REASON_NO_AP_FOUND || reason == WIFI_REASON_ASSOC_FAIL || + reason == WIFI_REASON_HANDSHAKE_TIMEOUT) { + WiFi.disconnect(); + this->error_from_callback_ = true; + } + + s_sta_connecting = false; + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE: { + auto it = info.wifi_sta_authmode_change; + ESP_LOGV(TAG, "Event: Authmode Change old=%s new=%s", get_auth_mode_str(it.old_mode), + get_auth_mode_str(it.new_mode)); + // Mitigate CVE-2020-12638 + // https://lbsfilm.at/blog/wpa2-authenticationmode-downgrade-in-espressif-microprocessors + if (it.old_mode != WIFI_AUTH_OPEN && it.new_mode == WIFI_AUTH_OPEN) { + ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting..."); + // we can't call retry_connect() from this context, so disconnect immediately + // and notify main thread with error_from_callback_ + WiFi.disconnect(); + this->error_from_callback_ = true; + } + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP: { + // auto it = info.got_ip.ip_info; + ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(WiFi.localIP()).c_str(), + format_ip4_addr(WiFi.gatewayIP()).c_str()); + s_sta_connecting = false; + break; + } + case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: { + ESP_LOGV(TAG, "Event: Lost IP"); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_START: { + ESP_LOGV(TAG, "Event: WiFi AP start"); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_STOP: { + ESP_LOGV(TAG, "Event: WiFi AP stop"); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED: { + auto it = info.wifi_sta_connected; + auto &mac = it.bssid; + ESP_LOGV(TAG, "Event: AP client connected MAC=%s", format_mac_addr(mac).c_str()); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED: { + auto it = info.wifi_sta_disconnected; + auto &mac = it.bssid; + ESP_LOGV(TAG, "Event: AP client disconnected MAC=%s", format_mac_addr(mac).c_str()); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_STAIPASSIGNED: { + ESP_LOGV(TAG, "Event: AP client assigned IP"); + break; + } + case ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED: { + auto it = info.wifi_ap_probereqrecved; + ESP_LOGVV(TAG, "Event: AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi); + break; + } + default: + break; + } +} +void WiFiComponent::wifi_pre_setup_() { + auto f = std::bind(&WiFiComponent::wifi_event_callback_, this, std::placeholders::_1, std::placeholders::_2); + WiFi.onEvent(f); + // Make sure WiFi is in clean state before anything starts + this->wifi_mode_(false, false); +} +WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { + auto status = WiFi.status(); + if (status == WL_CONNECTED) { + return WiFiSTAConnectStatus::CONNECTED; + } else if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { + return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; + } else if (status == WL_NO_SSID_AVAIL) { + return WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND; + } else if (s_sta_connecting) { + return WiFiSTAConnectStatus::CONNECTING; + } + return WiFiSTAConnectStatus::IDLE; +} +bool WiFiComponent::wifi_scan_start_(bool passive) { + // enable STA + if (!this->wifi_mode_(true, {})) + return false; + + // need to use WiFi because of WiFiScanClass allocations :( + int16_t err = WiFi.scanNetworks(true, true, passive, 200); + if (err != WIFI_SCAN_RUNNING) { + ESP_LOGV(TAG, "WiFi.scanNetworks failed! %d", err); + return false; + } + + return true; +} +void WiFiComponent::wifi_scan_done_callback_() { + this->scan_result_.clear(); + + int16_t num = WiFi.scanComplete(); + if (num < 0) + return; + + this->scan_result_.reserve(static_cast(num)); + for (int i = 0; i < num; i++) { + String ssid = WiFi.SSID(i); + wifi_auth_mode_t authmode = WiFi.encryptionType(i); + int32_t rssi = WiFi.RSSI(i); + uint8_t *bssid = WiFi.BSSID(i); + int32_t channel = WiFi.channel(i); + + WiFiScanResult scan({bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]}, std::string(ssid.c_str()), + channel, rssi, authmode != WIFI_AUTH_OPEN, ssid.length() == 0); + this->scan_result_.push_back(scan); + } + WiFi.scanDelete(); + this->scan_done_ = true; +} +bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { + // enable AP + if (!this->wifi_mode_({}, true)) + return false; + + if (manual_ip.has_value()) { + return WiFi.softAPConfig(static_cast(manual_ip->static_ip), static_cast(manual_ip->gateway), + static_cast(manual_ip->subnet)); + } else { + return WiFi.softAPConfig(IPAddress(192, 168, 4, 1), IPAddress(192, 168, 4, 1), IPAddress(255, 255, 255, 0)); + } +} +bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { + // enable AP + if (!this->wifi_mode_({}, true)) + return false; + + if (!this->wifi_ap_ip_config_(ap.get_manual_ip())) { + ESP_LOGV(TAG, "wifi_ap_ip_config_ failed!"); + return false; + } + + yield(); + + return WiFi.softAP(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(), + ap.get_channel().value_or(1), ap.get_hidden()); +} +network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {WiFi.softAPIP()}; } +bool WiFiComponent::wifi_disconnect_() { return WiFi.disconnect(); } + +bssid_t WiFiComponent::wifi_bssid() { + bssid_t bssid{}; + uint8_t *raw_bssid = WiFi.BSSID(); + if (raw_bssid != nullptr) { + for (size_t i = 0; i < bssid.size(); i++) + bssid[i] = raw_bssid[i]; + } + return bssid; +} +std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } +int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } +int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } +network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } +network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } +network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; } +void WiFiComponent::wifi_loop_() {} + +} // namespace wifi +} // namespace esphome + +#endif // USE_LIBRETINY diff --git a/esphome/config_validation.py b/esphome/config_validation.py index ed87e98078..b3f24d9d17 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1500,6 +1500,8 @@ class SplitDefault(Optional): esp32_arduino=vol.UNDEFINED, esp32_idf=vol.UNDEFINED, rp2040=vol.UNDEFINED, + bk72xx=vol.UNDEFINED, + rtl87xx=vol.UNDEFINED, host=vol.UNDEFINED, ): super().__init__(key) @@ -1511,6 +1513,8 @@ class SplitDefault(Optional): esp32_idf if esp32 is vol.UNDEFINED else esp32 ) self._rp2040_default = vol.default_factory(rp2040) + self._bk72xx_default = vol.default_factory(bk72xx) + self._rtl87xx_default = vol.default_factory(rtl87xx) self._host_default = vol.default_factory(host) @property @@ -1523,6 +1527,10 @@ class SplitDefault(Optional): return self._esp32_idf_default if CORE.is_rp2040: return self._rp2040_default + if CORE.is_bk72xx: + return self._bk72xx_default + if CORE.is_rtl87xx: + return self._rtl87xx_default if CORE.is_host: return self._host_default raise NotImplementedError diff --git a/esphome/const.py b/esphome/const.py index e0642247ab..d0575a6ebd 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -11,8 +11,19 @@ PLATFORM_ESP32 = "esp32" PLATFORM_ESP8266 = "esp8266" PLATFORM_RP2040 = "rp2040" PLATFORM_HOST = "host" +PLATFORM_BK72XX = "bk72xx" +PLATFORM_RTL87XX = "rtl87xx" +PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" -TARGET_PLATFORMS = [PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_HOST] +TARGET_PLATFORMS = [ + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, + PLATFORM_HOST, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, + PLATFORM_LIBRETINY_OLDSTYLE, +] SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"} @@ -37,6 +48,7 @@ CONF_ADVANCED = "advanced" CONF_AFTER = "after" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" +CONF_ANALOG = "analog" CONF_AND = "and" CONF_AP = "ap" CONF_APPARENT_POWER = "apparent_power" @@ -835,6 +847,7 @@ ICON_BRIEFCASE_DOWNLOAD = "mdi:briefcase-download" ICON_BRIGHTNESS_5 = "mdi:brightness-5" ICON_BRIGHTNESS_6 = "mdi:brightness-6" ICON_BUG = "mdi:bug" +ICON_CELLPHONE_ARROW_DOWN = "mdi:cellphone-arrow-down" ICON_CHECK_CIRCLE_OUTLINE = "mdi:check-circle-outline" ICON_CHEMICAL_WEAPON = "mdi:chemical-weapon" ICON_CHIP = "mdi:chip" diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 891936adc3..d9b1603894 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -584,6 +584,8 @@ class EsphomeCore: @property def firmware_bin(self): + if self.is_libretiny: + return self.relative_pioenvs_path(self.name, "firmware.uf2") return self.relative_pioenvs_path(self.name, "firmware.bin") @property @@ -602,6 +604,18 @@ class EsphomeCore: def is_rp2040(self): return self.target_platform == "rp2040" + @property + def is_bk72xx(self): + return self.target_platform == "bk72xx" + + @property + def is_rtl87xx(self): + return self.target_platform == "rtl87xx" + + @property + def is_libretiny(self): + return self.is_bk72xx or self.is_rtl87xx + @property def is_host(self): return self.target_platform == "host" diff --git a/esphome/core/config.py b/esphome/core/config.py index ef6553026e..a09252e4b4 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -380,7 +380,7 @@ async def to_code(config): cg.add_build_flag("-Wno-unused-but-set-variable") cg.add_build_flag("-Wno-sign-compare") - if CORE.using_arduino: + if CORE.using_arduino and not CORE.is_bk72xx: CORE.add_job(add_arduino_global_workaround) if config[CONF_INCLUDES]: diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 8d4d7e3f22..1e0df74eec 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -95,6 +95,10 @@ #define USE_HTTP_REQUEST_ESP8266_HTTPS #define USE_SOCKET_IMPL_LWIP_TCP +#ifdef USE_LIBRETINY +#define USE_SOCKET_IMPL_LWIP_SOCKETS +#endif + // Dummy firmware payload for shelly_dimmer #define USE_SHD_FIRMWARE_MAJOR_VERSION 56 #define USE_SHD_FIRMWARE_MINOR_VERSION 5 diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index c65928556a..714a1642f8 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -43,6 +43,10 @@ #include "esp_efuse_table.h" #endif +#ifdef USE_LIBRETINY +#include // for macAddress() +#endif + namespace esphome { static const char *const TAG = "helpers"; @@ -190,6 +194,8 @@ uint32_t random_uint32() { result |= rosc_hw->randombit; } return result; +#elif defined(USE_LIBRETINY) + return rand(); #elif defined(USE_HOST) std::random_device dev; std::mt19937 rng(dev()); @@ -216,6 +222,9 @@ bool random_bytes(uint8_t *data, size_t len) { *data++ = result; } return true; +#elif defined(USE_LIBRETINY) + lt_rand_bytes(data, len); + return true; #elif defined(USE_HOST) FILE *fp = fopen("/dev/urandom", "r"); if (fp == nullptr) { @@ -503,7 +512,7 @@ Mutex::Mutex() {} void Mutex::lock() {} bool Mutex::try_lock() { return true; } void Mutex::unlock() {} -#elif defined(USE_ESP32) +#elif defined(USE_ESP32) || defined(USE_LIBRETINY) Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); } void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); } bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; } @@ -513,7 +522,7 @@ void Mutex::unlock() { xSemaphoreGive(this->handle_); } #if defined(USE_ESP8266) IRAM_ATTR InterruptLock::InterruptLock() { state_ = xt_rsil(15); } IRAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(state_); } -#elif defined(USE_ESP32) +#elif defined(USE_ESP32) || defined(USE_LIBRETINY) // only affects the executing core // so should not be used as a mutex lock, only to get accurate timing IRAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); } @@ -555,6 +564,8 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame wifi_get_macaddr(STATION_IF, mac); #elif defined(USE_RP2040) && defined(USE_WIFI) WiFi.macAddress(mac); +#elif defined(USE_LIBRETINY) + WiFi.macAddress(mac); #endif } std::string get_mac_address() { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 115073de80..c3ed443bf0 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -17,6 +17,9 @@ #if defined(USE_ESP32) #include #include +#elif defined(USE_LIBRETINY) +#include +#include #endif #define HOT __attribute__((hot)) @@ -543,7 +546,7 @@ class Mutex { Mutex &operator=(const Mutex &) = delete; private: -#if defined(USE_ESP32) +#if defined(USE_ESP32) || defined(USE_LIBRETINY) SemaphoreHandle_t handle_; #endif }; diff --git a/esphome/core/log.h b/esphome/core/log.h index 6775aa5ac5..86af534f98 100644 --- a/esphome/core/log.h +++ b/esphome/core/log.h @@ -17,6 +17,9 @@ #ifdef USE_ESP32_FRAMEWORK_ARDUINO #include #endif +#ifdef USE_LIBRETINY +#include +#endif namespace esphome { diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index c05e1fcfcc..0d6ec8dc13 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -543,6 +543,7 @@ class DownloadListRequestHandler(BaseHandler): from esphome.components.esp32 import get_download_types as esp32_types from esphome.components.esp8266 import get_download_types as esp8266_types from esphome.components.rp2040 import get_download_types as rp2040_types + from esphome.components.libretiny import get_download_types as libretiny_types downloads = [] platform = storage_json.target_platform.lower() @@ -552,6 +553,10 @@ class DownloadListRequestHandler(BaseHandler): downloads = esp8266_types(storage_json) elif platform == const.PLATFORM_ESP32: downloads = esp32_types(storage_json) + elif platform == const.PLATFORM_BK72XX: + downloads = libretiny_types(storage_json) + elif platform == const.PLATFORM_RTL87XX: + downloads = libretiny_types(storage_json) else: self.send_error(418) return @@ -826,11 +831,15 @@ class BoardsRequestHandler(BaseHandler): from esphome.components.esp32.boards import BOARDS as ESP32_BOARDS from esphome.components.esp8266.boards import BOARDS as ESP8266_BOARDS from esphome.components.rp2040.boards import BOARDS as RP2040_BOARDS + from esphome.components.bk72xx.boards import BOARDS as BK72XX_BOARDS + from esphome.components.rtl87xx.boards import BOARDS as RTL87XX_BOARDS platform_to_boards = { "esp32": ESP32_BOARDS, "esp8266": ESP8266_BOARDS, "rp2040": RP2040_BOARDS, + "bk72xx": BK72XX_BOARDS, + "rtl87xx": RTL87XX_BOARDS, } # filter all ESP32 variants by requested platform if platform.startswith("esp32"): diff --git a/esphome/voluptuous_schema.py b/esphome/voluptuous_schema.py index 281ef10964..e2171cabed 100644 --- a/esphome/voluptuous_schema.py +++ b/esphome/voluptuous_schema.py @@ -203,6 +203,11 @@ class _Schema(vol.Schema): self._extra_schemas.append(validator) return self + def prepend_extra(self, validator): + validator = _Schema(validator) + self._extra_schemas.insert(0, validator) + return self + @schema_extractor_extended def extend(self, *schemas, **kwargs): extra = kwargs.pop("extra", None) diff --git a/esphome/wizard.py b/esphome/wizard.py index fd661af639..17a0882e1c 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -93,12 +93,24 @@ rp2040: platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git """ +BK72XX_CONFIG = """ +bk72xx: + board: {board} +""" + +RTL87XX_CONFIG = """ +rtl87xx: + board: {board} +""" + HARDWARE_BASE_CONFIGS = { "ESP8266": ESP8266_CONFIG, "ESP32": ESP32_CONFIG, "ESP32S2": ESP32S2_CONFIG, "ESP32C3": ESP32C3_CONFIG, "RP2040": RP2040_CONFIG, + "BK72XX": BK72XX_CONFIG, + "RTL87XX": RTL87XX_CONFIG, } @@ -156,7 +168,7 @@ def wizard_file(**kwargs): """ # pylint: disable=consider-using-f-string - if kwargs["platform"] in ["ESP8266", "ESP32"]: + if kwargs["platform"] in ["ESP8266", "ESP32", "BK72XX", "RTL87XX"]: config += """ # Enable fallback hotspot (captive portal) in case wifi connection fails ap: @@ -182,7 +194,10 @@ captive_portal: def wizard_write(path, **kwargs): from esphome.components.esp8266 import boards as esp8266_boards + from esphome.components.esp32 import boards as esp32_boards from esphome.components.rp2040 import boards as rp2040_boards + from esphome.components.bk72xx import boards as bk72xx_boards + from esphome.components.rtl87xx import boards as rtl87xx_boards name = kwargs["name"] board = kwargs["board"] @@ -192,12 +207,19 @@ def wizard_write(path, **kwargs): kwargs[key] = sanitize_double_quotes(kwargs[key]) if "platform" not in kwargs: - if board in esp8266_boards.ESP8266_BOARD_PINS: + if board in esp8266_boards.BOARDS: platform = "ESP8266" - elif board in rp2040_boards.RP2040_BOARD_PINS: - platform = "RP2040" - else: + elif board in esp32_boards.BOARDS: platform = "ESP32" + elif board in rp2040_boards.BOARDS: + platform = "RP2040" + elif board in bk72xx_boards.BOARDS: + platform = "BK72XX" + elif board in rtl87xx_boards.BOARDS: + platform = "RTL87XX" + else: + safe_print(color(Fore.RED, f'The board "{board}" is unknown.')) + return False kwargs["platform"] = platform hardware = kwargs["platform"] @@ -206,6 +228,8 @@ def wizard_write(path, **kwargs): storage_path = ext_storage_path(os.path.dirname(path), os.path.basename(path)) storage.save(storage_path) + return True + if get_bool_env(ENV_QUICKWIZARD): @@ -243,6 +267,8 @@ def strip_accents(value): def wizard(path): from esphome.components.esp32 import boards as esp32_boards from esphome.components.esp8266 import boards as esp8266_boards + from esphome.components.bk72xx import boards as bk72xx_boards + from esphome.components.rtl87xx import boards as rtl87xx_boards if not path.endswith(".yaml") and not path.endswith(".yml"): safe_print( @@ -262,7 +288,7 @@ def wizard(path): sleep(2.0) safe_print( "In 4 steps I'm going to guide you through creating a basic " - "configuration file for your custom ESP8266/ESP32 firmware. Yay!" + "configuration file for your custom firmware. Yay!" ) sleep(3.0) safe_print() @@ -305,16 +331,18 @@ def wizard(path): "Now I'd like to know what microcontroller you're using so that I can compile " "firmwares for it." ) + + wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "RTL87XX"] safe_print( - f"Are you using an {color(Fore.GREEN, 'ESP32')} or {color(Fore.GREEN, 'ESP8266')} platform? (Choose ESP8266 for Sonoff devices)" + "Please choose one of the supported microcontrollers " + "(Use ESP8266 for Sonoff devices)." ) while True: sleep(0.5) safe_print() - safe_print("Please enter either ESP32 or ESP8266.") - platform = input(color(Fore.BOLD_WHITE, "(ESP32/ESP8266): ")) + platform = input(color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ")) try: - platform = vol.All(vol.Upper, vol.Any("ESP32", "ESP8266"))(platform) + platform = vol.All(vol.Upper, vol.Any(*wizard_platforms))(platform.upper()) break except vol.Invalid: safe_print( @@ -328,10 +356,14 @@ def wizard(path): board_link = ( "http://docs.platformio.org/en/latest/platforms/espressif32.html#boards" ) - else: + elif platform == "ESP8266": board_link = ( "http://docs.platformio.org/en/latest/platforms/espressif8266.html#boards" ) + elif platform in ["BK72XX", "RTL87XX"]: + board_link = "https://docs.libretiny.eu/docs/status/supported/" + else: + raise NotImplementedError("Unknown platform!") safe_print(f"Next, I need to know what {color(Fore.GREEN, 'board')} you're using.") sleep(0.5) @@ -342,11 +374,24 @@ def wizard(path): # Don't sleep because user needs to copy link if platform == "ESP32": safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'nodemcu-32s')}\".") - boards = list(esp32_boards.ESP32_BOARD_PINS.keys()) - else: + boards_list = esp32_boards.BOARDS.items() + elif platform == "ESP8266": safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'nodemcuv2')}\".") - boards = list(esp8266_boards.ESP8266_BOARD_PINS.keys()) - safe_print(f"Options: {', '.join(sorted(boards))}") + boards_list = esp8266_boards.BOARDS.items() + elif platform == "BK72XX": + safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'cb2s')}\".") + boards_list = bk72xx_boards.BOARDS.items() + elif platform == "RTL87XX": + safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'wr3')}\".") + boards_list = rtl87xx_boards.BOARDS.items() + else: + raise NotImplementedError("Unknown platform!") + + boards = [] + safe_print("Options:") + for board_id, board_data in boards_list: + safe_print(f" - {board_id} - {board_data['name']}") + boards.append(board_id) while True: board = input(color(Fore.BOLD_WHITE, "(board): ")) @@ -420,7 +465,7 @@ def wizard(path): safe_print("Press ENTER for no password") password = input(color(Fore.BOLD_WHITE, "(password): ")) - wizard_write( + if not wizard_write( path=path, name=name, platform=platform, @@ -428,7 +473,8 @@ def wizard(path): ssid=ssid, psk=psk, password=password, - ) + ): + return 1 safe_print() safe_print( diff --git a/platformio.ini b/platformio.ini index 64c7bec6e8..ab9584d9b8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ ; It's *not* used during runtime. [platformio] -default_envs = esp8266-arduino, esp32-arduino, esp32-idf +default_envs = esp8266-arduino, esp32-arduino, esp32-idf, bk72xx-arduino ; Ideally, we want src_dir to be the root directory of the repository, to mimic the runtime build ; environment as best as possible. Unfortunately, the ESP-IDF toolchain really doesn't like this ; being the root directory. Instead, set esphome/ as the source directory, all our sources are in @@ -167,6 +167,16 @@ build_flags = -DUSE_RP2040 -DUSE_RP2040_FRAMEWORK_ARDUINO +; This are common settings for the LibreTiny (all variants) using Arduino. +[common:libretiny-arduino] +extends = common:arduino +platform = libretiny +framework = arduino +build_flags = + ${common:arduino.build_flags} + -DUSE_LIBRETINY +build_src_flags = -include Arduino.h + ; All the actual environments are defined below. ;;;;;;;; ESP8266 ;;;;;;;; @@ -339,6 +349,35 @@ build_flags = ${common:rp2040-arduino.build_flags} ${flags:runtime.build_flags} +;;;;;;;; LibreTiny ;;;;;;;; + +[env:bk72xx-arduino] +extends = common:libretiny-arduino +board = generic-bk7231n-qfn32-tuya +build_flags = + ${common:libretiny-arduino.build_flags} + ${flags:runtime.build_flags} + -DUSE_BK72XX + -DUSE_LIBRETINY_VARIANT_BK7231N + +[env:rtl87xxb-arduino] +extends = common:libretiny-arduino +board = generic-rtl8710bn-2mb-788k +build_flags = + ${common:libretiny-arduino.build_flags} + ${flags:runtime.build_flags} + -DUSE_RTL87XX + -DUSE_LIBRETINY_VARIANT_RTL8710B + +[env:rtl87xxc-arduino] +extends = common:libretiny-arduino +board = generic-rtl8720cf-2mb-992k +build_flags = + ${common:libretiny-arduino.build_flags} + ${flags:runtime.build_flags} + -DUSE_RTL87XX + -DUSE_LIBRETINY_VARIANT_RTL8720C + [env:host] extends = common platform = platformio/native diff --git a/script/ci-custom.py b/script/ci-custom.py index a731e2e5b8..da4da50d7e 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -512,7 +512,10 @@ def relative_py_search_text(fname, content): @lint_content_find_check( relative_py_search_text, include=["esphome/components/*.py"], - exclude=["esphome/components/web_server/__init__.py"], + exclude=[ + "esphome/components/libretiny/generate_components.py", + "esphome/components/web_server/__init__.py", + ], ) def lint_relative_py_import(fname): return ( @@ -536,6 +539,7 @@ def lint_relative_py_import(fname): "esphome/components/esp32/core.cpp", "esphome/components/esp8266/core.cpp", "esphome/components/rp2040/core.cpp", + "esphome/components/libretiny/core.cpp", "esphome/components/host/core.cpp", ], ) diff --git a/tests/test9.1.yaml b/tests/test9.1.yaml new file mode 100644 index 0000000000..f7455b7668 --- /dev/null +++ b/tests/test9.1.yaml @@ -0,0 +1,28 @@ +# Tests for rtl87xx boards using LibreTiny +--- +wifi: + ssid: "ssid" + +rtl87xx: + board: generic-rtl8710bn-2mb-788k + +esphome: + name: rtl87xx-test + +logger: + +ota: + +captive_portal: + +binary_sensor: + - platform: gpio + name: Home Button + pin: GPIO11 + +sensor: + - platform: adc + id: adc_sensor + name: ADC + pin: PA19 + update_interval: 1s diff --git a/tests/test9.yaml b/tests/test9.yaml new file mode 100644 index 0000000000..ccf5f4b5b0 --- /dev/null +++ b/tests/test9.yaml @@ -0,0 +1,28 @@ +# Tests for bk7xx boards using LibreTiny +--- +wifi: + ssid: "ssid" + +bk72xx: + board: cb2s + +esphome: + name: bk72xx-test + +logger: + +ota: + +captive_portal: + +binary_sensor: + - platform: gpio + name: Home Button + pin: GPIO24 + +sensor: + - platform: adc + id: adc_sensor + name: ADC + pin: GPIO23 + update_interval: 1s diff --git a/tests/unit_tests/test_wizard.py b/tests/unit_tests/test_wizard.py index 79a5894075..d94624d1e4 100644 --- a/tests/unit_tests/test_wizard.py +++ b/tests/unit_tests/test_wizard.py @@ -3,6 +3,9 @@ import esphome.wizard as wz import pytest from esphome.components.esp8266.boards import ESP8266_BOARD_PINS +from esphome.components.esp32.boards import ESP32_BOARD_PINS +from esphome.components.bk72xx.boards import BK72XX_BOARD_PINS +from esphome.components.rtl87xx.boards import RTL87XX_BOARD_PINS from unittest.mock import MagicMock @@ -140,11 +143,11 @@ def test_wizard_write_defaults_platform_from_board_esp32( default_config, tmp_path, monkeypatch ): """ - If the platform is not explicitly set, use "ESP32" if the board is not one of the ESP8266 boards + If the platform is not explicitly set, use "ESP32" if the board is one of the ESP32 boards """ # Given del default_config["platform"] - default_config["board"] = "foo" + default_config["board"] = [*ESP32_BOARD_PINS][0] monkeypatch.setattr(wz, "write_file", MagicMock()) @@ -156,6 +159,46 @@ def test_wizard_write_defaults_platform_from_board_esp32( assert "esp32:" in generated_config +def test_wizard_write_defaults_platform_from_board_bk72xx( + default_config, tmp_path, monkeypatch +): + """ + If the platform is not explicitly set, use "BK72XX" if the board is one of BK72XX boards + """ + # Given + del default_config["platform"] + default_config["board"] = [*BK72XX_BOARD_PINS][0] + + monkeypatch.setattr(wz, "write_file", MagicMock()) + + # When + wz.wizard_write(tmp_path, **default_config) + + # Then + generated_config = wz.write_file.call_args.args[1] + assert "bk72xx:" in generated_config + + +def test_wizard_write_defaults_platform_from_board_rtl87xx( + default_config, tmp_path, monkeypatch +): + """ + If the platform is not explicitly set, use "RTL87XX" if the board is one of RTL87XX boards + """ + # Given + del default_config["platform"] + default_config["board"] = [*RTL87XX_BOARD_PINS][0] + + monkeypatch.setattr(wz, "write_file", MagicMock()) + + # When + wz.wizard_write(tmp_path, **default_config) + + # Then + generated_config = wz.write_file.call_args.args[1] + assert "rtl87xx:" in generated_config + + def test_safe_print_step_prints_step_number_and_description(monkeypatch): """ The safe_print_step function prints the step number and the passed description @@ -186,7 +229,7 @@ def test_default_input_uses_default_if_no_input_supplied(monkeypatch): """ # Given - monkeypatch.setattr("builtins.input", lambda _: "") + monkeypatch.setattr("builtins.input", lambda _=None: "") default_string = "foobar" # When @@ -203,7 +246,7 @@ def test_default_input_uses_user_supplied_value(monkeypatch): # Given user_input = "A value" - monkeypatch.setattr("builtins.input", lambda _: user_input) + monkeypatch.setattr("builtins.input", lambda _=None: user_input) default_string = "foobar" # When From d382ca2401581579c8edceca52547f1ded3e8eda Mon Sep 17 00:00:00 2001 From: mkaiser <29856783+mkaiser@users.noreply.github.com> Date: Tue, 5 Sep 2023 00:27:58 +0200 Subject: [PATCH 0423/2607] Extend ESP32 CAN bit rates /bus speed support (#5280) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: mkaiser --- esphome/components/canbus/__init__.py | 6 ++- esphome/components/canbus/canbus.h | 5 +++ esphome/components/esp32_can/canbus.py | 51 +++++++++++++++++++++- esphome/components/esp32_can/esp32_can.cpp | 27 ++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/esphome/components/canbus/__init__.py b/esphome/components/canbus/__init__.py index c5a9924644..f49398858c 100644 --- a/esphome/components/canbus/__init__.py +++ b/esphome/components/canbus/__init__.py @@ -45,9 +45,13 @@ CanbusTrigger = canbus_ns.class_( CanSpeed = canbus_ns.enum("CAN_SPEED") CAN_SPEEDS = { + "1KBPS": CanSpeed.CAN_1KBPS, "5KBPS": CanSpeed.CAN_5KBPS, "10KBPS": CanSpeed.CAN_10KBPS, + "12K5BPS": CanSpeed.CAN_12K5BPS, + "16KBPS": CanSpeed.CAN_16KBPS, "20KBPS": CanSpeed.CAN_20KBPS, + "25KBPS": CanSpeed.CAN_25KBPS, "31K25BPS": CanSpeed.CAN_31K25BPS, "33KBPS": CanSpeed.CAN_33KBPS, "40KBPS": CanSpeed.CAN_40KBPS, @@ -60,9 +64,9 @@ CAN_SPEEDS = { "200KBPS": CanSpeed.CAN_200KBPS, "250KBPS": CanSpeed.CAN_250KBPS, "500KBPS": CanSpeed.CAN_500KBPS, + "800KBPS": CanSpeed.CAN_800KBPS, "1000KBPS": CanSpeed.CAN_1000KBPS, } - CANBUS_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(CanbusComponent), diff --git a/esphome/components/canbus/canbus.h b/esphome/components/canbus/canbus.h index 4a12742627..c0ccff4866 100644 --- a/esphome/components/canbus/canbus.h +++ b/esphome/components/canbus/canbus.h @@ -19,9 +19,13 @@ enum Error : uint8_t { }; enum CanSpeed : uint8_t { + CAN_1KBPS, CAN_5KBPS, CAN_10KBPS, + CAN_12K5BPS, + CAN_16KBPS, CAN_20KBPS, + CAN_25KBPS, CAN_31K25BPS, CAN_33KBPS, CAN_40KBPS, @@ -34,6 +38,7 @@ enum CanSpeed : uint8_t { CAN_200KBPS, CAN_250KBPS, CAN_500KBPS, + CAN_800KBPS, CAN_1000KBPS }; diff --git a/esphome/components/esp32_can/canbus.py b/esphome/components/esp32_can/canbus.py index 7761418c6a..74f331f30b 100644 --- a/esphome/components/esp32_can/canbus.py +++ b/esphome/components/esp32_can/canbus.py @@ -5,6 +5,15 @@ from esphome.components import canbus from esphome.const import CONF_ID, CONF_RX_PIN, CONF_TX_PIN from esphome.components.canbus import CanbusComponent, CanSpeed, CONF_BIT_RATE +from esphome.components.esp32 import get_esp32_variant +from esphome.components.esp32.const import ( + VARIANT_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, + VARIANT_ESP32C3, + VARIANT_ESP32H2, +) + CODEOWNERS = ["@Sympatron"] DEPENDENCIES = ["esp32"] @@ -12,19 +21,57 @@ esp32_can_ns = cg.esphome_ns.namespace("esp32_can") esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent) # Currently the driver only supports a subset of the bit rates defined in canbus -CAN_SPEEDS = { +# The supported bit rates differ between ESP32 variants. +# See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI) + +CAN_SPEEDS_ESP32 = { + "25KBPS": CanSpeed.CAN_25KBPS, "50KBPS": CanSpeed.CAN_50KBPS, "100KBPS": CanSpeed.CAN_100KBPS, "125KBPS": CanSpeed.CAN_125KBPS, "250KBPS": CanSpeed.CAN_250KBPS, "500KBPS": CanSpeed.CAN_500KBPS, + "800KBPS": CanSpeed.CAN_800KBPS, "1000KBPS": CanSpeed.CAN_1000KBPS, } +CAN_SPEEDS_ESP32_S2 = { + "1KBPS": CanSpeed.CAN_1KBPS, + "5KBPS": CanSpeed.CAN_5KBPS, + "10KBPS": CanSpeed.CAN_10KBPS, + "12K5BPS": CanSpeed.CAN_12K5BPS, + "16KBPS": CanSpeed.CAN_16KBPS, + "20KBPS": CanSpeed.CAN_20KBPS, + **CAN_SPEEDS_ESP32, +} + +CAN_SPEEDS_ESP32_S3 = {**CAN_SPEEDS_ESP32_S2} +CAN_SPEEDS_ESP32_C3 = {**CAN_SPEEDS_ESP32_S2} +CAN_SPEEDS_ESP32_H2 = {**CAN_SPEEDS_ESP32_S2} + +CAN_SPEEDS = { + VARIANT_ESP32: CAN_SPEEDS_ESP32, + VARIANT_ESP32S2: CAN_SPEEDS_ESP32_S2, + VARIANT_ESP32S3: CAN_SPEEDS_ESP32_S3, + VARIANT_ESP32C3: CAN_SPEEDS_ESP32_C3, + VARIANT_ESP32H2: CAN_SPEEDS_ESP32_H2, +} + + +def validate_bit_rate(value): + variant = get_esp32_variant() + if variant not in CAN_SPEEDS: + raise cv.Invalid(f"{variant} is not supported by component {esp32_can_ns}") + value = value.upper() + if value not in CAN_SPEEDS[variant]: + raise cv.Invalid(f"Bit rate {value} is not supported on {variant}") + return cv.enum(CAN_SPEEDS[variant])(value) + + CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(esp32_can), - cv.Optional(CONF_BIT_RATE, default="125KBPS"): cv.enum(CAN_SPEEDS, upper=True), + cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate, cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number, cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number, } diff --git a/esphome/components/esp32_can/esp32_can.cpp b/esphome/components/esp32_can/esp32_can.cpp index 3eb2d1f035..79e4b70f97 100644 --- a/esphome/components/esp32_can/esp32_can.cpp +++ b/esphome/components/esp32_can/esp32_can.cpp @@ -16,6 +16,30 @@ static const char *const TAG = "esp32_can"; static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config) { switch (bitrate) { +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C3) || \ + defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H6) + case canbus::CAN_1KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1KBITS(); + return true; + case canbus::CAN_5KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_5KBITS(); + return true; + case canbus::CAN_10KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_10KBITS(); + return true; + case canbus::CAN_12K5BPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_12_5KBITS(); + return true; + case canbus::CAN_16KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_16KBITS(); + return true; + case canbus::CAN_20KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_20KBITS(); + return true; +#endif + case canbus::CAN_25KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_25KBITS(); + return true; case canbus::CAN_50KBPS: *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_50KBITS(); return true; @@ -31,6 +55,9 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config case canbus::CAN_500KBPS: *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_500KBITS(); return true; + case canbus::CAN_800KBPS: + *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_800KBITS(); + return true; case canbus::CAN_1000KBPS: *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1MBITS(); return true; From 562f7c8718912de531780037ddb47199340b49d0 Mon Sep 17 00:00:00 2001 From: kahrendt Date: Mon, 4 Sep 2023 22:02:59 -0400 Subject: [PATCH 0424/2607] Debug component: add free PSRAM sensor (#5334) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/debug/debug_component.cpp | 10 ++++++ esphome/components/debug/debug_component.h | 6 ++++ esphome/components/debug/sensor.py | 32 +++++++++++++++----- tests/test1.yaml | 10 +++++- tests/test5.yaml | 14 +++++++++ tests/test8.yaml | 15 +++++++++ 6 files changed, 78 insertions(+), 9 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 52ee4b070e..67b07237b7 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -145,6 +145,10 @@ void DebugComponent::dump_config() { features += "BT,"; info.features &= ~CHIP_FEATURE_BT; } + if (info.features & CHIP_FEATURE_EMB_PSRAM) { + features += "EMB_PSRAM,"; + info.features &= ~CHIP_FEATURE_EMB_PSRAM; + } if (info.features) features += "Other:" + format_hex(info.features); ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, @@ -423,6 +427,12 @@ void DebugComponent::update() { this->loop_time_sensor_->publish_state(this->max_loop_time_); this->max_loop_time_ = 0; } + +#ifdef USE_ESP32 + if (this->psram_sensor_ != nullptr) { + this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + } +#endif // USE_ESP32 #endif // USE_SENSOR } diff --git a/esphome/components/debug/debug_component.h b/esphome/components/debug/debug_component.h index b80fda55eb..93e3ba4857 100644 --- a/esphome/components/debug/debug_component.h +++ b/esphome/components/debug/debug_component.h @@ -33,6 +33,9 @@ class DebugComponent : public PollingComponent { void set_fragmentation_sensor(sensor::Sensor *fragmentation_sensor) { fragmentation_sensor_ = fragmentation_sensor; } #endif void set_loop_time_sensor(sensor::Sensor *loop_time_sensor) { loop_time_sensor_ = loop_time_sensor; } +#ifdef USE_ESP32 + void set_psram_sensor(sensor::Sensor *psram_sensor) { this->psram_sensor_ = psram_sensor; } +#endif // USE_ESP32 #endif // USE_SENSOR protected: uint32_t free_heap_{}; @@ -47,6 +50,9 @@ class DebugComponent : public PollingComponent { sensor::Sensor *fragmentation_sensor_{nullptr}; #endif sensor::Sensor *loop_time_sensor_{nullptr}; +#ifdef USE_ESP32 + sensor::Sensor *psram_sensor_{nullptr}; +#endif // USE_ESP32 #endif // USE_SENSOR #ifdef USE_TEXT_SENSOR diff --git a/esphome/components/debug/sensor.py b/esphome/components/debug/sensor.py index f7ea07d138..061c2750e4 100644 --- a/esphome/components/debug/sensor.py +++ b/esphome/components/debug/sensor.py @@ -17,6 +17,8 @@ from . import CONF_DEBUG_ID, DebugComponent DEPENDENCIES = ["debug"] +CONF_PSRAM = "psram" + CONFIG_SCHEMA = { cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent), cv.Optional(CONF_FREE): sensor.sensor_schema( @@ -47,24 +49,38 @@ CONFIG_SCHEMA = { accuracy_decimals=0, entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ), + cv.Optional(CONF_PSRAM): cv.All( + cv.only_on_esp32, + cv.requires_component("psram"), + sensor.sensor_schema( + unit_of_measurement=UNIT_BYTES, + icon=ICON_COUNTER, + accuracy_decimals=0, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + ), } async def to_code(config): debug_component = await cg.get_variable(config[CONF_DEBUG_ID]) - if CONF_FREE in config: - sens = await sensor.new_sensor(config[CONF_FREE]) + if free_conf := config.get(CONF_FREE): + sens = await sensor.new_sensor(free_conf) cg.add(debug_component.set_free_sensor(sens)) - if CONF_BLOCK in config: - sens = await sensor.new_sensor(config[CONF_BLOCK]) + if block_conf := config.get(CONF_BLOCK): + sens = await sensor.new_sensor(block_conf) cg.add(debug_component.set_block_sensor(sens)) - if CONF_FRAGMENTATION in config: - sens = await sensor.new_sensor(config[CONF_FRAGMENTATION]) + if fragmentation_conf := config.get(CONF_FRAGMENTATION): + sens = await sensor.new_sensor(fragmentation_conf) cg.add(debug_component.set_fragmentation_sensor(sens)) - if CONF_LOOP_TIME in config: - sens = await sensor.new_sensor(config[CONF_LOOP_TIME]) + if loop_time_conf := config.get(CONF_LOOP_TIME): + sens = await sensor.new_sensor(loop_time_conf) cg.add(debug_component.set_loop_time_sensor(sens)) + + if psram_conf := config.get(CONF_PSRAM): + sens = await sensor.new_sensor(psram_conf) + cg.add(debug_component.set_psram_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index efca34247b..b78407069d 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1448,6 +1448,15 @@ sensor: pressure: name: "BMP581 Pressure" oversampling: 128x + - platform: debug + free: + name: "Heap Free" + block: + name: "Heap Max Block" + loop_time: + name: "Loop Time" + psram: + name: "PSRAM Free" esp32_touch: setup_mode: false @@ -3448,7 +3457,6 @@ number: still_threshold: name: g8 still threshold - select: - platform: template id: test_select diff --git a/tests/test5.yaml b/tests/test5.yaml index a2530d799a..a1cc3103d7 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -28,6 +28,10 @@ ota: logger: +debug: + +psram: + uart: - id: uart_1 tx_pin: 1 @@ -525,6 +529,16 @@ sensor: time: name: System Time + - platform: debug + free: + name: "Heap Free" + block: + name: "Heap Max Block" + loop_time: + name: "Loop Time" + psram: + name: "PSRAM Free" + - platform: vbus model: custom command: 0x100 diff --git a/tests/test8.yaml b/tests/test8.yaml index 8d031b033f..28c6e78b87 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -14,6 +14,10 @@ esphome: logger: +debug: + +psram: + light: - platform: neopixelbus type: GRB @@ -50,3 +54,14 @@ binary_sensor: - platform: tt21100 name: Home Button index: 1 + +sensor: + - platform: debug + free: + name: "Heap Free" + block: + name: "Max Block Free" + loop_time: + name: "Loop Time" + psram: + name: "PSRAM Free" From b11824b0587fd23317959bfbf02e3f1eb445cfc0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 5 Sep 2023 14:33:42 +1200 Subject: [PATCH 0425/2607] libretiny: fix uart_port framework config (#5343) --- esphome/components/libretiny/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index c6c63b48c8..ac294d3f65 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -218,7 +218,7 @@ FRAMEWORK_SCHEMA = cv.All( cv.Optional(CONF_SDK_SILENT, default="all"): ( cv.one_of("all", "auto", "none", lower=True) ), - cv.Optional(CONF_UART_PORT, default=None): cv.one_of(0, 1, 2, int=True), + cv.Optional(CONF_UART_PORT): cv.one_of(0, 1, 2, int=True), cv.Optional(CONF_GPIO_RECOVER, default=True): cv.boolean, cv.Optional(CONF_OPTIONS, default={}): { cv.string_strict: cv.string, @@ -309,8 +309,8 @@ async def component_to_code(config): lt_options["LT_UART_SILENT_ENABLED"] = 0 lt_options["LT_UART_SILENT_ALL"] = 0 # set default UART port - if framework[CONF_UART_PORT] is not None: - lt_options["LT_UART_DEFAULT_PORT"] = framework[CONF_UART_PORT] + if uart_port := framework.get(CONF_UART_PORT, None) is not None: + lt_options["LT_UART_DEFAULT_PORT"] = uart_port # add custom options lt_options.update(framework[CONF_OPTIONS]) From 343278b29108a1f4e331fda4116244dc9f5a35a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 18:11:46 +1200 Subject: [PATCH 0426/2607] Bump actions/checkout from 3 to 4 (#5341) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 22 +++++++++++----------- .github/workflows/release.yml | 6 +++--- .github/workflows/sync-device-classes.yml | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index eb3a5a945c..394379d675 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba46936952..1de5822960 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -60,7 +60,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Run yamllint uses: frenck/action-yamllint@v1.4.1 @@ -71,7 +71,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -92,7 +92,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -113,7 +113,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -134,7 +134,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -155,7 +155,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -176,7 +176,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -196,7 +196,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -235,7 +235,7 @@ jobs: file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8] steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -291,7 +291,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v3.5.2 + uses: actions/checkout@v4 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 74ff4d87f4..71a0cd2c78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: outputs: tag: ${{ steps.tag.outputs.tag }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get tag id: tag # yamllint disable rule:line-length @@ -43,7 +43,7 @@ jobs: if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -88,7 +88,7 @@ jobs: target: "lint" baseimg: "docker" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 7067300826..1759db962c 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -14,10 +14,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Checkout Home Assistant - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: home-assistant/core path: lib/home-assistant From 32b24726ed5bc9dfa18c8a8d3bb41c2f25d65144 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:01:28 +1000 Subject: [PATCH 0427/2607] Add Lilygo T-Embed to st7789v display config. (#5337) * Add Lilygo T-Embed to st7789v display config. * Move all configuration into the Python code. Add presets for TTGO. All preset configuration can be overridden. * Add Adafruit S2 pin presets * Add test * Add funhouse pins. Co-authored-by: Keith Burzinski * Keep ordering of options consistent * Remove unused declarations --------- Co-authored-by: Keith Burzinski --- esphome/components/st7789v/display.py | 133 ++++++++++++++++++------- esphome/components/st7789v/st7789v.cpp | 62 ++---------- esphome/components/st7789v/st7789v.h | 13 +-- tests/test2.yaml | 8 ++ 4 files changed, 112 insertions(+), 104 deletions(-) diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index 16c1e790bd..ad152bf356 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -12,6 +12,8 @@ from esphome.const import ( CONF_RESET_PIN, CONF_WIDTH, CONF_POWER_SUPPLY, + CONF_ROTATION, + CONF_CS_PIN, ) from . import st7789v_ns @@ -26,48 +28,106 @@ DEPENDENCIES = ["spi"] ST7789V = st7789v_ns.class_( "ST7789V", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer ) -ST7789VRef = ST7789V.operator("ref") -ST7789VModel = st7789v_ns.enum("ST7789VModel") + +MODEL_PRESETS = "model_presets" +REQUIRE_PS = "require_ps" + + +def model_spec(require_ps=False, presets=None): + if presets is None: + presets = {} + return {MODEL_PRESETS: presets, REQUIRE_PS: require_ps} + MODELS = { - "TTGO_TDISPLAY_135X240": ST7789VModel.ST7789V_MODEL_TTGO_TDISPLAY_135_240, - "ADAFRUIT_FUNHOUSE_240X240": ST7789VModel.ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240, - "ADAFRUIT_RR_280X240": ST7789VModel.ST7789V_MODEL_ADAFRUIT_RR_280_240, - "ADAFRUIT_S2_TFT_FEATHER_240X135": ST7789VModel.ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135, - "CUSTOM": ST7789VModel.ST7789V_MODEL_CUSTOM, + "TTGO_TDISPLAY_135X240": model_spec( + presets={ + CONF_HEIGHT: 240, + CONF_WIDTH: 135, + CONF_OFFSET_HEIGHT: 52, + CONF_OFFSET_WIDTH: 40, + CONF_CS_PIN: "GPIO5", + CONF_DC_PIN: "GPIO16", + CONF_RESET_PIN: "GPIO23", + CONF_BACKLIGHT_PIN: "GPIO4", + } + ), + "ADAFRUIT_FUNHOUSE_240X240": model_spec( + presets={ + CONF_HEIGHT: 240, + CONF_WIDTH: 240, + CONF_OFFSET_HEIGHT: 0, + CONF_OFFSET_WIDTH: 0, + CONF_CS_PIN: "GPIO40", + CONF_DC_PIN: "GPIO39", + CONF_RESET_PIN: "GPIO41", + } + ), + "ADAFRUIT_RR_280X240": model_spec( + presets={ + CONF_HEIGHT: 280, + CONF_WIDTH: 240, + CONF_OFFSET_HEIGHT: 0, + CONF_OFFSET_WIDTH: 20, + } + ), + "ADAFRUIT_S2_TFT_FEATHER_240X135": model_spec( + require_ps=True, + presets={ + CONF_HEIGHT: 240, + CONF_WIDTH: 135, + CONF_OFFSET_HEIGHT: 52, + CONF_OFFSET_WIDTH: 40, + CONF_CS_PIN: "GPIO7", + CONF_DC_PIN: "GPIO39", + CONF_RESET_PIN: "GPIO40", + CONF_BACKLIGHT_PIN: "GPIO45", + }, + ), + "LILYGO_T-EMBED_170X320": model_spec( + presets={ + CONF_HEIGHT: 320, + CONF_WIDTH: 170, + CONF_OFFSET_HEIGHT: 35, + CONF_OFFSET_WIDTH: 0, + CONF_ROTATION: 270, + CONF_CS_PIN: "GPIO10", + CONF_DC_PIN: "GPIO13", + CONF_RESET_PIN: "GPIO9", + CONF_BACKLIGHT_PIN: "GPIO15", + } + ), + "CUSTOM": model_spec(), } -ST7789V_MODEL = cv.enum(MODELS, upper=True, space="_") - def validate_st7789v(config): - if config[CONF_MODEL].upper() == "CUSTOM" and ( - CONF_HEIGHT not in config - or CONF_WIDTH not in config - or CONF_OFFSET_HEIGHT not in config - or CONF_OFFSET_WIDTH not in config - ): - raise cv.Invalid( - f'{CONF_HEIGHT}, {CONF_WIDTH}, {CONF_OFFSET_HEIGHT} and {CONF_OFFSET_WIDTH} must be specified when {CONF_MODEL} is "CUSTOM"' - ) + model_data = MODELS[config[CONF_MODEL]] + presets = model_data[MODEL_PRESETS] + for key, value in presets.items(): + if key not in config: + if key.endswith("pin"): + # All pins are output. + value = pins.gpio_output_pin_schema(value) + config[key] = value - if config[CONF_MODEL].upper() != "CUSTOM" and ( - CONF_HEIGHT in config - or CONF_WIDTH in config - or CONF_OFFSET_HEIGHT in config - or CONF_OFFSET_WIDTH in config - ): + if model_data[REQUIRE_PS] and CONF_POWER_SUPPLY not in config: raise cv.Invalid( - f'Do not specify {CONF_HEIGHT}, {CONF_WIDTH}, {CONF_OFFSET_HEIGHT} or {CONF_OFFSET_WIDTH} when using {CONF_MODEL} that is not "CUSTOM"' + f'{CONF_POWER_SUPPLY} must be specified when {CONF_MODEL} is {config[CONF_MODEL]}"' ) if ( - config[CONF_MODEL].upper() == "ADAFRUIT_S2_TFT_FEATHER_240X135" - and CONF_POWER_SUPPLY not in config + CONF_OFFSET_WIDTH not in config + or CONF_OFFSET_HEIGHT not in config + or CONF_HEIGHT not in config + or CONF_WIDTH not in config ): raise cv.Invalid( - f'{CONF_POWER_SUPPLY} must be specified when {CONF_MODEL} is "ADAFRUIT_S2_TFT_FEATHER_240X135"' + f"{CONF_HEIGHT}, {CONF_WIDTH}, {CONF_OFFSET_HEIGHT} and {CONF_OFFSET_WIDTH} must all be specified" ) + if CONF_DC_PIN not in config or CONF_RESET_PIN not in config: + raise cv.Invalid(f"both {CONF_DC_PIN} and {CONF_RESET_PIN} must be specified") + return config @@ -75,9 +135,9 @@ CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(ST7789V), - cv.Required(CONF_MODEL): ST7789V_MODEL, - cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, - cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_MODEL): cv.one_of(*MODELS.keys(), upper=True, space="_"), + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_DC_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_BACKLIGHT_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), cv.Optional(CONF_EIGHTBITCOLOR, default=False): cv.boolean, @@ -99,13 +159,12 @@ async def to_code(config): await display.register_display(var, config) await spi.register_spi_device(var, config) - cg.add(var.set_model(config[CONF_MODEL])) + cg.add(var.set_model_str(config[CONF_MODEL])) - if config[CONF_MODEL].upper() == "CUSTOM": - cg.add(var.set_height(config[CONF_HEIGHT])) - cg.add(var.set_width(config[CONF_WIDTH])) - cg.add(var.set_offset_height(config[CONF_OFFSET_HEIGHT])) - cg.add(var.set_offset_width(config[CONF_OFFSET_WIDTH])) + cg.add(var.set_height(config[CONF_HEIGHT])) + cg.add(var.set_width(config[CONF_WIDTH])) + cg.add(var.set_offset_height(config[CONF_OFFSET_HEIGHT])) + cg.add(var.set_offset_width(config[CONF_OFFSET_WIDTH])) cg.add(var.set_eightbitcolor(config[CONF_EIGHTBITCOLOR])) diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index f29182e634..a181723546 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -122,11 +122,11 @@ void ST7789V::setup() { void ST7789V::dump_config() { LOG_DISPLAY("", "SPI ST7789V", this); - ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); - if (this->model_ == ST7789V_MODEL_CUSTOM) { - ESP_LOGCONFIG(TAG, " Height Offset: %u", this->offset_height_); - ESP_LOGCONFIG(TAG, " Width Offset: %u", this->offset_width_); - } + ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_); + ESP_LOGCONFIG(TAG, " Height: %u", this->height_); + ESP_LOGCONFIG(TAG, " Width: %u", this->width_); + ESP_LOGCONFIG(TAG, " Height Offset: %u", this->offset_height_); + ESP_LOGCONFIG(TAG, " Width Offset: %u", this->offset_width_); ESP_LOGCONFIG(TAG, " 8-bit color mode: %s", YESNO(this->eightbitcolor_)); LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); @@ -145,42 +145,7 @@ void ST7789V::update() { this->write_display_data(); } -void ST7789V::set_model(ST7789VModel model) { - this->model_ = model; - - switch (this->model_) { - case ST7789V_MODEL_TTGO_TDISPLAY_135_240: - this->height_ = 240; - this->width_ = 135; - this->offset_height_ = 52; - this->offset_width_ = 40; - break; - - case ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240: - this->height_ = 240; - this->width_ = 240; - this->offset_height_ = 0; - this->offset_width_ = 0; - break; - - case ST7789V_MODEL_ADAFRUIT_RR_280_240: - this->height_ = 280; - this->width_ = 240; - this->offset_height_ = 0; - this->offset_width_ = 20; - break; - - case ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135: - this->height_ = 240; - this->width_ = 135; - this->offset_height_ = 52; - this->offset_width_ = 40; - break; - - default: - break; - } -} +void ST7789V::set_model_str(const char *model_str) { this->model_str_ = model_str; } void ST7789V::write_display_data() { uint16_t x1 = this->offset_height_; @@ -339,20 +304,5 @@ void HOT ST7789V::draw_absolute_pixel_internal(int x, int y, Color color) { } } -const char *ST7789V::model_str_() { - switch (this->model_) { - case ST7789V_MODEL_TTGO_TDISPLAY_135_240: - return "TTGO T-Display 135x240"; - case ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240: - return "Adafruit Funhouse 240x240"; - case ST7789V_MODEL_ADAFRUIT_RR_280_240: - return "Adafruit Round-Rectangular 280x240"; - case ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135: - return "Adafruit ESP32-S2 TFT Feather"; - default: - return "Custom"; - } -} - } // namespace st7789v } // namespace esphome diff --git a/esphome/components/st7789v/st7789v.h b/esphome/components/st7789v/st7789v.h index 56132e8ea2..22093301e2 100644 --- a/esphome/components/st7789v/st7789v.h +++ b/esphome/components/st7789v/st7789v.h @@ -10,14 +10,6 @@ namespace esphome { namespace st7789v { -enum ST7789VModel { - ST7789V_MODEL_TTGO_TDISPLAY_135_240, - ST7789V_MODEL_ADAFRUIT_FUNHOUSE_240_240, - ST7789V_MODEL_ADAFRUIT_RR_280_240, - ST7789V_MODEL_ADAFRUIT_S2_TFT_FEATHER_240_135, - ST7789V_MODEL_CUSTOM -}; - static const uint8_t ST7789_NOP = 0x00; // No Operation static const uint8_t ST7789_SWRESET = 0x01; // Software Reset static const uint8_t ST7789_RDDID = 0x04; // Read Display ID @@ -120,7 +112,7 @@ class ST7789V : public PollingComponent, public spi::SPIDevice { public: - void set_model(ST7789VModel model); + void set_model_str(const char *model_str); void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_backlight_pin(GPIOPin *backlight_pin) { this->backlight_pin_ = backlight_pin; } @@ -146,7 +138,6 @@ class ST7789V : public PollingComponent, display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } protected: - ST7789VModel model_{ST7789V_MODEL_TTGO_TDISPLAY_135_240}; GPIOPin *dc_pin_{nullptr}; GPIOPin *reset_pin_{nullptr}; GPIOPin *backlight_pin_{nullptr}; @@ -175,7 +166,7 @@ class ST7789V : public PollingComponent, void draw_absolute_pixel_internal(int x, int y, Color color) override; - const char *model_str_(); + const char *model_str_; }; } // namespace st7789v diff --git a/tests/test2.yaml b/tests/test2.yaml index d1508632b3..adc57f4f7e 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -710,6 +710,14 @@ interval: - logger.log: Interval Run display: + - platform: st7789v + model: LILYGO_T-EMBED_170X320 + height: 320 + width: 170 + offset_height: 35 + offset_width: 0 + dc_pin: GPIO13 + reset_pin: GPIO9 image: - id: binary_image From 97dcbe84da0c8ff9d6044e7d2d059c0161b5170a Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 5 Sep 2023 09:56:17 +0200 Subject: [PATCH 0428/2607] Disable IPv6 when config explicitly says false (#5310) --- .../ethernet/ethernet_component.cpp | 20 +++++++++---------- esphome/components/network/__init__.py | 1 + .../wifi/wifi_component_esp32_arduino.cpp | 8 ++++---- .../wifi/wifi_component_esp_idf.cpp | 14 ++++++------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index d9004a913b..59d2e4c4d6 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -118,10 +118,10 @@ void EthernetComponent::setup() { ESPHL_ERROR_CHECK(err, "ETH event handler register error"); err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &EthernetComponent::got_ip_event_handler, nullptr); ESPHL_ERROR_CHECK(err, "GOT IP event handler register error"); -#if LWIP_IPV6 +#if ENABLE_IPV6 err = esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &EthernetComponent::got_ip6_event_handler, nullptr); ESPHL_ERROR_CHECK(err, "GOT IP6 event handler register error"); -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ /* start Ethernet driver state machine */ err = esp_eth_start(this->eth_handle_); @@ -164,7 +164,7 @@ void EthernetComponent::loop() { this->state_ = EthernetComponentState::CONNECTING; this->start_connect_(); } -#if LWIP_IPV6 +#if ENABLE_IPV6 else if (this->got_ipv6_) { esp_ip6_addr_t ip6_addr; if (esp_netif_get_ip6_global(this->eth_netif_, &ip6_addr) == 0 && @@ -177,7 +177,7 @@ void EthernetComponent::loop() { this->got_ipv6_ = false; } -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ break; } } @@ -272,14 +272,14 @@ void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_b ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%" PRId32 ")", event_id); } -#if LWIP_IPV6 +#if ENABLE_IPV6 void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { ESP_LOGV(TAG, "[Ethernet event] ETH Got IP6 (num=%d)", event_id); global_eth_component->got_ipv6_ = true; global_eth_component->ipv6_count_ += 1; } -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ void EthernetComponent::start_connect_() { this->connect_begin_ = millis(); @@ -343,12 +343,12 @@ void EthernetComponent::start_connect_() { if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) { ESPHL_ERROR_CHECK(err, "DHCPC start error"); } -#if LWIP_IPV6 +#if ENABLE_IPV6 err = esp_netif_create_ip6_linklocal(this->eth_netif_); if (err != ESP_OK) { ESPHL_ERROR_CHECK(err, "IPv6 local failed"); } -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ } this->connect_begin_ = millis(); @@ -376,7 +376,7 @@ void EthernetComponent::dump_connect_params_() { ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); #endif -#if LWIP_IPV6 +#if ENABLE_IPV6 if (this->ipv6_count_ > 0) { esp_ip6_addr_t ip6_addr; esp_netif_get_ip6_linklocal(this->eth_netif_, &ip6_addr); @@ -387,7 +387,7 @@ void EthernetComponent::dump_connect_params_() { ESP_LOGCONFIG(TAG, "IPv6 Addr (Global): " IPV6STR, IPV62STR(ip6_addr)); } } -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ esp_err_t err; diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index cd29734f42..83778e0bf4 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -24,6 +24,7 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): if CONF_ENABLE_IPV6 in config: + cg.add_define("ENABLE_IPV6", config[CONF_ENABLE_IPV6]) if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) add_idf_sdkconfig_option( diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 95f4e2ce92..5b147b20c6 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -447,9 +447,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ buf[it.ssid_len] = '\0'; ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); -#if LWIP_IPV6 +#if ENABLE_IPV6 this->set_timeout(100, [] { WiFi.enableIpV6(); }); -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ break; } @@ -504,13 +504,13 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ s_sta_connecting = false; break; } -#if LWIP_IPV6 +#if ENABLE_IPV6 case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: { auto it = info.got_ip6.ip6_info; ESP_LOGV(TAG, "Got IPv6 address=" IPV6STR, IPV62STR(it.ip)); break; } -#endif /* LWIP_IPV6 */ +#endif /* ENABLE_IPV6 */ case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: { ESP_LOGV(TAG, "Event: Lost IP"); break; diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 9041679ccf..0ff9e932b2 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -58,9 +58,9 @@ struct IDFWiFiEvent { wifi_event_ap_probe_req_rx_t ap_probe_req_rx; wifi_event_bss_rssi_low_t bss_rssi_low; ip_event_got_ip_t ip_got_ip; -#if LWIP_IPV6 +#if ENABLE_IPV6 ip_event_got_ip6_t ip_got_ip6; -#endif +#endif /* ENABLE_IPV6 */ ip_event_ap_staipassigned_t ip_ap_staipassigned; } data; }; @@ -84,7 +84,7 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi memcpy(&event.data.sta_disconnected, event_data, sizeof(wifi_event_sta_disconnected_t)); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { memcpy(&event.data.ip_got_ip, event_data, sizeof(ip_event_got_ip_t)); -#if LWIP_IPV6 +#if ENABLE_IPV6 } else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) { memcpy(&event.data.ip_got_ip6, event_data, sizeof(ip_event_got_ip6_t)); #endif @@ -645,18 +645,18 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) { const auto &it = data->data.ip_got_ip; -#if LWIP_IPV6_AUTOCONFIG +#if ENABLE_IPV6 esp_netif_create_ip6_linklocal(s_sta_netif); -#endif +#endif /* ENABLE_IPV6 */ ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(it.ip_info.ip).c_str(), format_ip4_addr(it.ip_info.gw).c_str()); s_sta_got_ip = true; -#if LWIP_IPV6 +#if ENABLE_IPV6 } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) { const auto &it = data->data.ip_got_ip6; ESP_LOGV(TAG, "Event: Got IPv6 address=%s", format_ip6_addr(it.ip6_info.ip).c_str()); -#endif +#endif /* ENABLE_IPV6 */ } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) { ESP_LOGV(TAG, "Event: Lost IP"); From b7a16d5a5968122c9ec9e2937da826b4eb93b274 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 5 Sep 2023 05:35:20 -0500 Subject: [PATCH 0429/2607] Add defines.h to ethernet_component.h for ENABLE_IPV6 (#5344) --- esphome/components/ethernet/ethernet_component.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 1bd4786b44..11f50af966 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/hal.h" #include "esphome/components/network/ip_address.h" From e2d784a5b5dfbf8d6be7f09d3f38ba172272349c Mon Sep 17 00:00:00 2001 From: esphomebot Date: Wed, 6 Sep 2023 07:29:41 +1200 Subject: [PATCH 0430/2607] Synchronise Device Classes from Home Assistant (#5328) --- esphome/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d0575a6ebd..067fd23946 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -980,7 +980,6 @@ DEVICE_CLASS_DURATION = "duration" DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_ENERGY = "energy" DEVICE_CLASS_ENERGY_STORAGE = "energy_storage" -DEVICE_CLASS_ENUM = "enum" DEVICE_CLASS_FREQUENCY = "frequency" DEVICE_CLASS_GARAGE = "garage" DEVICE_CLASS_GARAGE_DOOR = "garage_door" From 35b5dadb99f1a22b9a8d3c5ff8603537cb7292e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 07:32:00 +1200 Subject: [PATCH 0431/2607] Bump pytest from 7.4.0 to 7.4.1 (#5342) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 7ab6742b02..e160c3e9e3 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==7.4.0 +pytest==7.4.1 pytest-cov==4.1.0 pytest-mock==3.11.1 pytest-asyncio==0.21.1 From 47735d1dae8d2e66eb8b755afc0de3d68d3020af Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Tue, 5 Sep 2023 21:37:01 +0200 Subject: [PATCH 0432/2607] Fixed default temperature step values for haier climate (#5330) --- esphome/components/haier/climate.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index acb079c822..d796f13581 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -136,12 +136,10 @@ def validate_visual(config): f"Configured visual temperature step {temp_step} is wrong, it should be a multiple of 0.5" ) else: - config[CONF_VISUAL][CONF_TEMPERATURE_STEP] = ( - { - CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, - CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, - }, - ) + config[CONF_VISUAL][CONF_TEMPERATURE_STEP] = { + CONF_TARGET_TEMPERATURE: PROTOCOL_TARGET_TEMPERATURE_STEP, + CONF_CURRENT_TEMPERATURE: PROTOCOL_CURRENT_TEMPERATURE_STEP, + } else: config[CONF_VISUAL] = { CONF_MIN_TEMPERATURE: PROTOCOL_MIN_TEMPERATURE, From ac5c6ec2883115e68cf31d51118f36cbdf8de011 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 5 Sep 2023 21:38:58 +0200 Subject: [PATCH 0433/2607] Add debug component to all tests (#5333) --- tests/test2.yaml | 2 ++ tests/test3.1.yaml | 2 ++ tests/test3.yaml | 2 ++ tests/test4.yaml | 2 ++ tests/test6.yaml | 2 ++ tests/test7.yaml | 2 ++ 6 files changed, 12 insertions(+) diff --git a/tests/test2.yaml b/tests/test2.yaml index adc57f4f7e..4928b8b877 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -55,6 +55,8 @@ ota: logger: level: DEBUG +debug: + deep_sleep: run_duration: default: 20s diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index ea8dc337be..16f31409d8 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -39,6 +39,8 @@ ota: logger: +debug: + sensor: - platform: apds9960 type: proximity diff --git a/tests/test3.yaml b/tests/test3.yaml index 471b7d97b6..abfd133c99 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -287,6 +287,8 @@ logger: level: DEBUG esp8266_store_log_strings_in_flash: true +debug: + improv_serial: next_url: https://esphome.io/?name={{device_name}}&version={{esphome_version}}&ip={{ip_address}} diff --git a/tests/test4.yaml b/tests/test4.yaml index 54caebf1fe..1175bb207c 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -50,6 +50,8 @@ ota: logger: level: DEBUG +debug: + web_server: ota: false auth: diff --git a/tests/test6.yaml b/tests/test6.yaml index 6224563a77..f048a4fa14 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -22,6 +22,8 @@ ota: logger: +debug: + binary_sensor: - platform: gpio pin: GPIO5 diff --git a/tests/test7.yaml b/tests/test7.yaml index 8d48c9a601..2355dd6feb 100644 --- a/tests/test7.yaml +++ b/tests/test7.yaml @@ -28,6 +28,8 @@ esphome: logger: +debug: + http_request: useragent: esphome/tagreader timeout: 10s From 82c1988a2d925f78e47036b8c002a2c78d9503ff Mon Sep 17 00:00:00 2001 From: JJ Date: Tue, 5 Sep 2023 14:59:23 -0700 Subject: [PATCH 0434/2607] Support MaxBotix XL in addition to HRXL (#4510) --- .../hrxl_maxsonar_wr/hrxl_maxsonar_wr.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/esphome/components/hrxl_maxsonar_wr/hrxl_maxsonar_wr.cpp b/esphome/components/hrxl_maxsonar_wr/hrxl_maxsonar_wr.cpp index bd1c82c96b..b56e96badc 100644 --- a/esphome/components/hrxl_maxsonar_wr/hrxl_maxsonar_wr.cpp +++ b/esphome/components/hrxl_maxsonar_wr/hrxl_maxsonar_wr.cpp @@ -1,9 +1,10 @@ // Official Datasheet: -// https://www.maxbotix.com/documents/HRXL-MaxSonar-WR_Datasheet.pdf +// HRXL: https://www.maxbotix.com/documents/HRXL-MaxSonar-WR_Datasheet.pdf +// XL: https://www.maxbotix.com/documents/XL-MaxSonar-WR_Datasheet.pdf // // This implementation is designed to work with the TTL Versions of the -// MaxBotix HRXL MaxSonar WR sensor series. The sensor's TTL Pin (5) should be -// wired to one of the ESP's input pins and configured as uart rx_pin. +// MaxBotix HRXL and XL MaxSonar WR sensor series. The sensor's TTL Pin (5) +// should be wired to one of the ESP's input pins and configured as uart rx_pin. #include "hrxl_maxsonar_wr.h" #include "esphome/core/log.h" @@ -17,8 +18,10 @@ static const uint8_t ASCII_NBSP = 0xFF; static const int MAX_DATA_LENGTH_BYTES = 6; /** - * The sensor outputs something like "R1234\r" at a fixed rate of 6 Hz. Where - * 1234 means a distance of 1,234 m. + * HRXL sensors output the format "R1234\r" at 6Hz + * The 1234 means 1234mm + * XL sensors output the format "R123\r" at 5 to 10Hz + * The 123 means 123cm */ void HrxlMaxsonarWrComponent::loop() { uint8_t data; @@ -42,9 +45,17 @@ void HrxlMaxsonarWrComponent::check_buffer_() { if (this->buffer_.back() == static_cast(ASCII_CR) || this->buffer_.length() >= MAX_DATA_LENGTH_BYTES) { ESP_LOGV(TAG, "Read from serial: %s", this->buffer_.c_str()); - if (this->buffer_.length() == MAX_DATA_LENGTH_BYTES && this->buffer_[0] == 'R' && - this->buffer_.back() == static_cast(ASCII_CR)) { - int millimeters = parse_number(this->buffer_.substr(1, MAX_DATA_LENGTH_BYTES - 2)).value_or(0); + size_t rpos = this->buffer_.find(static_cast(ASCII_CR)); + + if (this->buffer_.length() <= MAX_DATA_LENGTH_BYTES && this->buffer_[0] == 'R' && rpos != std::string::npos) { + std::string distance = this->buffer_.substr(1, rpos - 1); + int millimeters = parse_number(distance).value_or(0); + + // XL reports in cm instead of mm and reports 3 digits instead of 4 + if (distance.length() == 3) { + millimeters = millimeters * 10; + } + float meters = float(millimeters) / 1000.0; ESP_LOGV(TAG, "Distance from sensor: %d mm, %f m", millimeters, meters); this->publish_state(meters); From 74ab940aff7289b2183fe315cd5665e4ba1d36f1 Mon Sep 17 00:00:00 2001 From: JJ Date: Tue, 5 Sep 2023 15:09:22 -0700 Subject: [PATCH 0435/2607] Adding DFRobot Ozone Sensor Support (sen0321) (#4782) --- CODEOWNERS | 1 + esphome/components/sen0321/__init__.py | 1 + esphome/components/sen0321/sen0321.cpp | 36 ++++++++++++++++++++++++++ esphome/components/sen0321/sen0321.h | 35 +++++++++++++++++++++++++ esphome/components/sen0321/sensor.py | 34 ++++++++++++++++++++++++ tests/test1.yaml | 5 ++++ 6 files changed, 112 insertions(+) create mode 100644 esphome/components/sen0321/__init__.py create mode 100644 esphome/components/sen0321/sen0321.cpp create mode 100644 esphome/components/sen0321/sen0321.h create mode 100644 esphome/components/sen0321/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 1455643550..384db8098f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -246,6 +246,7 @@ esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdp3x/* @Azimath esphome/components/selec_meter/* @sourabhjaiswal esphome/components/select/* @esphome/core +esphome/components/sen0321/* @notjj esphome/components/sen21231/* @shreyaskarnik esphome/components/sen5x/* @martgras esphome/components/sensirion_common/* @martgras diff --git a/esphome/components/sen0321/__init__.py b/esphome/components/sen0321/__init__.py new file mode 100644 index 0000000000..458ffa67f9 --- /dev/null +++ b/esphome/components/sen0321/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@notjj"] diff --git a/esphome/components/sen0321/sen0321.cpp b/esphome/components/sen0321/sen0321.cpp new file mode 100644 index 0000000000..7801c8c389 --- /dev/null +++ b/esphome/components/sen0321/sen0321.cpp @@ -0,0 +1,36 @@ +#include "sen0321.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace sen0321_sensor { + +static const char *const TAG = "sen0321_sensor.sensor"; + +void Sen0321Sensor::setup() { + ESP_LOGCONFIG(TAG, "Setting up sen0321..."); + if (!this->write_byte(SENSOR_MODE_REGISTER, SENSOR_MODE_AUTO)) { + ESP_LOGW(TAG, "Error setting measurement mode."); + this->mark_failed(); + }; +} + +void Sen0321Sensor::update() { this->read_data_(); } + +void Sen0321Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "DF Robot Ozone Sensor sen0321:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with sen0321 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} + +void Sen0321Sensor::read_data_() { + uint8_t result[2]; + this->read_bytes(SENSOR_AUTO_READ_REG, result, (uint8_t) 2); + this->publish_state(((uint16_t) (result[0] << 8) + result[1])); +} + +} // namespace sen0321_sensor +} // namespace esphome diff --git a/esphome/components/sen0321/sen0321.h b/esphome/components/sen0321/sen0321.h new file mode 100644 index 0000000000..3bb3d5b015 --- /dev/null +++ b/esphome/components/sen0321/sen0321.h @@ -0,0 +1,35 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +// ref: +// https://github.com/DFRobot/DFRobot_OzoneSensor + +namespace esphome { +namespace sen0321_sensor { +// Sensor Mode +// While passive is supposedly supported, it does not appear to work reliably. +static const uint8_t SENSOR_MODE_REGISTER = 0x03; +static const uint8_t SENSOR_MODE_AUTO = 0x00; +static const uint8_t SENSOR_MODE_PASSIVE = 0x01; +static const uint8_t SET_REGISTER = 0x04; + +// Each register is 2 wide, so 0x07-0x08 for passive, or 0x09-0x0A for auto +// First register is high bits, next low. +static const uint8_t SENSOR_PASS_READ_REG = 0x07; +static const uint8_t SENSOR_AUTO_READ_REG = 0x09; + +class Sen0321Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void update() override; + void dump_config() override; + void setup() override; + + protected: + void read_data_(); +}; + +} // namespace sen0321_sensor +} // namespace esphome diff --git a/esphome/components/sen0321/sensor.py b/esphome/components/sen0321/sensor.py new file mode 100644 index 0000000000..ee613dc440 --- /dev/null +++ b/esphome/components/sen0321/sensor.py @@ -0,0 +1,34 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + ICON_CHEMICAL_WEAPON, + UNIT_PARTS_PER_BILLION, + STATE_CLASS_MEASUREMENT, +) + +CODEOWNERS = ["@notjj"] +DEPENDENCIES = ["i2c"] + +sen0321_sensor_ns = cg.esphome_ns.namespace("sen0321_sensor") +Sen0321Sensor = sen0321_sensor_ns.class_( + "Sen0321Sensor", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + Sen0321Sensor, + unit_of_measurement=UNIT_PARTS_PER_BILLION, + icon=ICON_CHEMICAL_WEAPON, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x73)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/tests/test1.yaml b/tests/test1.yaml index b78407069d..33782dbf53 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1081,6 +1081,11 @@ sensor: ambient_pressure_compensation: 961mBar temperature_offset: 4.2C i2c_id: i2c_bus + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s + i2c_id: i2c_bus - platform: sgp30 eco2: name: Workshop eCO2 From feba9ffdc453f978ce6530fa63dcae3ee6d82b19 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Wed, 6 Sep 2023 01:11:07 +0300 Subject: [PATCH 0436/2607] mdns: bump IDF mdns component to 1.2.0 (#5217) --- esphome/components/mdns/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index e7d700d149..fbe1e1a719 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -88,7 +88,7 @@ async def to_code(config): add_idf_component( name="mdns", repo="https://github.com/espressif/esp-protocols.git", - ref="mdns-v1.0.9", + ref="mdns-v1.2.0", path="components/mdns", ) From 2cabe59c228d1863cf3616fb6edb429c9909aef6 Mon Sep 17 00:00:00 2001 From: Sebastian Rasor <92653912+sebastianrasor@users.noreply.github.com> Date: Tue, 22 Aug 2023 20:01:34 -0500 Subject: [PATCH 0437/2607] Introduce cv.temperature_delta and fix problematic thermostat configuration behavior (#5297) --- esphome/components/thermostat/climate.py | 14 +++++++------- esphome/config_validation.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/esphome/components/thermostat/climate.py b/esphome/components/thermostat/climate.py index 9a57f6a337..cca46609db 100644 --- a/esphome/components/thermostat/climate.py +++ b/esphome/components/thermostat/climate.py @@ -591,11 +591,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature, cv.Optional( CONF_SET_POINT_MINIMUM_DIFFERENTIAL, default=0.5 - ): cv.temperature, - cv.Optional(CONF_COOL_DEADBAND, default=0.5): cv.temperature, - cv.Optional(CONF_COOL_OVERRUN, default=0.5): cv.temperature, - cv.Optional(CONF_HEAT_DEADBAND, default=0.5): cv.temperature, - cv.Optional(CONF_HEAT_OVERRUN, default=0.5): cv.temperature, + ): cv.temperature_delta, + cv.Optional(CONF_COOL_DEADBAND, default=0.5): cv.temperature_delta, + cv.Optional(CONF_COOL_OVERRUN, default=0.5): cv.temperature_delta, + cv.Optional(CONF_HEAT_DEADBAND, default=0.5): cv.temperature_delta, + cv.Optional(CONF_HEAT_OVERRUN, default=0.5): cv.temperature_delta, cv.Optional(CONF_MAX_COOLING_RUN_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MAX_HEATING_RUN_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MIN_COOLING_OFF_TIME): cv.positive_time_period_seconds, @@ -608,8 +608,8 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MIN_HEATING_OFF_TIME): cv.positive_time_period_seconds, cv.Optional(CONF_MIN_HEATING_RUN_TIME): cv.positive_time_period_seconds, cv.Required(CONF_MIN_IDLE_TIME): cv.positive_time_period_seconds, - cv.Optional(CONF_SUPPLEMENTAL_COOLING_DELTA): cv.temperature, - cv.Optional(CONF_SUPPLEMENTAL_HEATING_DELTA): cv.temperature, + cv.Optional(CONF_SUPPLEMENTAL_COOLING_DELTA): cv.temperature_delta, + cv.Optional(CONF_SUPPLEMENTAL_HEATING_DELTA): cv.temperature_delta, cv.Optional( CONF_FAN_ONLY_ACTION_USES_FAN_MODE_TIMER, default=False ): cv.boolean, diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 3720757828..ed87e98078 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -929,6 +929,27 @@ def temperature(value): raise err +def temperature_delta(value): + err = None + try: + return _temperature_c(value) + except Invalid as orig_err: + err = orig_err + + try: + return _temperature_k(value) + except Invalid: + pass + + try: + fahrenheit = _temperature_f(value) + return fahrenheit * (5 / 9) + except Invalid: + pass + + raise err + + _color_temperature_mireds = float_with_unit("Color Temperature", r"(mireds|Mireds)") _color_temperature_kelvin = float_with_unit("Color Temperature", r"(K|Kelvin)") From c146712b1644deba320195530330c2892793a90f Mon Sep 17 00:00:00 2001 From: luka6000 Date: Fri, 1 Sep 2023 03:20:21 +0200 Subject: [PATCH 0438/2607] fix to PR # 3887 MQTT connection not using discovery: false (#5275) --- esphome/components/mqtt/mqtt_client.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index d3f759c072..1d804170f6 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -66,25 +66,28 @@ void MQTTClientComponent::setup() { } #endif - this->subscribe( - "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, - 2); + if (this->is_discovery_enabled()) { + this->subscribe( + "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, + 2); - std::string topic = "esphome/ping/"; - topic.append(App.get_name()); - this->subscribe( - topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); + std::string topic = "esphome/ping/"; + topic.append(App.get_name()); + this->subscribe( + topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); + } this->last_connected_ = millis(); this->start_dnslookup_(); } void MQTTClientComponent::send_device_info_() { - if (!this->is_connected()) { + if (!this->is_connected() or !this->is_discovery_enabled()) { return; } std::string topic = "esphome/discover/"; topic.append(App.get_name()); + this->publish_json( topic, [](JsonObject root) { From 3f8bad3ed1748ed1eef8c378c079466054650bbb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 2 Sep 2023 08:41:52 +1200 Subject: [PATCH 0439/2607] Attempt to fix secret blurring (#5326) --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index ca5fc1c008..697adc03a3 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -371,7 +371,7 @@ def command_config(args, config): # add the console decoration so the front-end can hide the secrets if not args.show_secrets: output = re.sub( - r"(password|key|psk|ssid)\:\s(.*)", r"\1: \\033[5m\2\\033[6m", output + r"(password|key|psk|ssid)\: (.+)", r"\1: \\033[5m\2\\033[6m", output ) safe_print(output) _LOGGER.info("Configuration is valid!") From 619787e6d2f4dbf3c860d3b70657e1d62a3cf7a6 Mon Sep 17 00:00:00 2001 From: kahrendt Date: Fri, 1 Sep 2023 16:55:59 -0400 Subject: [PATCH 0440/2607] Bugfix: disable channels after IO if multiple tca9548a I2C multiplexers are configured (#5317) --- esphome/components/tca9548a/tca9548a.cpp | 27 ++++++++++++++---------- esphome/components/tca9548a/tca9548a.h | 4 +++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/esphome/components/tca9548a/tca9548a.cpp b/esphome/components/tca9548a/tca9548a.cpp index caa3dd0655..770fd5e47c 100644 --- a/esphome/components/tca9548a/tca9548a.cpp +++ b/esphome/components/tca9548a/tca9548a.cpp @@ -7,23 +7,27 @@ namespace tca9548a { static const char *const TAG = "tca9548a"; i2c::ErrorCode TCA9548AChannel::readv(uint8_t address, i2c::ReadBuffer *buffers, size_t cnt) { - auto err = parent_->switch_to_channel(channel_); + auto err = this->parent_->switch_to_channel(channel_); if (err != i2c::ERROR_OK) return err; - return parent_->bus_->readv(address, buffers, cnt); + err = this->parent_->bus_->readv(address, buffers, cnt); + this->parent_->disable_all_channels(); + return err; } i2c::ErrorCode TCA9548AChannel::writev(uint8_t address, i2c::WriteBuffer *buffers, size_t cnt, bool stop) { - auto err = parent_->switch_to_channel(channel_); + auto err = this->parent_->switch_to_channel(channel_); if (err != i2c::ERROR_OK) return err; - return parent_->bus_->writev(address, buffers, cnt, stop); + err = this->parent_->bus_->writev(address, buffers, cnt, stop); + this->parent_->disable_all_channels(); + return err; } void TCA9548AComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up TCA9548A..."); uint8_t status = 0; if (this->read(&status, 1) != i2c::ERROR_OK) { - ESP_LOGI(TAG, "TCA9548A failed"); + ESP_LOGE(TAG, "TCA9548A failed"); this->mark_failed(); return; } @@ -37,15 +41,16 @@ void TCA9548AComponent::dump_config() { i2c::ErrorCode TCA9548AComponent::switch_to_channel(uint8_t channel) { if (this->is_failed()) return i2c::ERROR_NOT_INITIALIZED; - if (current_channel_ == channel) - return i2c::ERROR_OK; uint8_t channel_val = 1 << channel; - auto err = this->write(&channel_val, 1); - if (err == i2c::ERROR_OK) { - current_channel_ = channel; + return this->write(&channel_val, 1); +} + +void TCA9548AComponent::disable_all_channels() { + if (this->write(&TCA9548A_DISABLE_CHANNELS_COMMAND, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to disable all channels."); + this->status_set_error(); // couldn't disable channels, set error status } - return err; } } // namespace tca9548a diff --git a/esphome/components/tca9548a/tca9548a.h b/esphome/components/tca9548a/tca9548a.h index 02553f8cd0..08f1674d11 100644 --- a/esphome/components/tca9548a/tca9548a.h +++ b/esphome/components/tca9548a/tca9548a.h @@ -6,6 +6,8 @@ namespace esphome { namespace tca9548a { +static const uint8_t TCA9548A_DISABLE_CHANNELS_COMMAND = 0x00; + class TCA9548AComponent; class TCA9548AChannel : public i2c::I2CBus { public: @@ -28,10 +30,10 @@ class TCA9548AComponent : public Component, public i2c::I2CDevice { void update(); i2c::ErrorCode switch_to_channel(uint8_t channel); + void disable_all_channels(); protected: friend class TCA9548AChannel; - uint8_t current_channel_ = 255; }; } // namespace tca9548a } // namespace esphome From 55df88d7ae14db3da6d5d3a93189314a0045c0cd Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Sat, 2 Sep 2023 09:54:03 +0000 Subject: [PATCH 0441/2607] Fix checksum calculation for pipsolar (#5299) --- esphome/components/pipsolar/pipsolar.cpp | 20 ++++++++++++++++---- esphome/components/pipsolar/pipsolar.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index 62e4fbd341..2cd1aeba44 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -769,7 +769,7 @@ uint8_t Pipsolar::check_incoming_length_(uint8_t length) { uint8_t Pipsolar::check_incoming_crc_() { uint16_t crc16; - crc16 = crc16be(read_buffer_, read_pos_ - 3); + crc16 = this->pipsolar_crc_(read_buffer_, read_pos_ - 3); ESP_LOGD(TAG, "checking crc on incoming message"); if (((uint8_t) ((crc16) >> 8)) == read_buffer_[read_pos_ - 3] && ((uint8_t) ((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) { @@ -798,7 +798,7 @@ uint8_t Pipsolar::send_next_command_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = crc16be(byte_command, length); + crc16 = this->pipsolar_crc_(byte_command, length); this->write_str(command); // checksum this->write(((uint8_t) ((crc16) >> 8))); // highbyte @@ -825,8 +825,8 @@ void Pipsolar::send_next_poll_() { this->command_start_millis_ = millis(); this->empty_uart_buffer_(); this->read_pos_ = 0; - crc16 = crc16be(this->used_polling_commands_[this->last_polling_command_].command, - this->used_polling_commands_[this->last_polling_command_].length); + crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command, + this->used_polling_commands_[this->last_polling_command_].length); this->write_array(this->used_polling_commands_[this->last_polling_command_].command, this->used_polling_commands_[this->last_polling_command_].length); // checksum @@ -893,5 +893,17 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll } } +uint16_t Pipsolar::pipsolar_crc_(uint8_t *msg, uint8_t len) { + uint16_t crc = crc16be(msg, len); + uint8_t crc_low = crc & 0xff; + uint8_t crc_high = crc >> 8; + if (crc_low == 0x28 || crc_low == 0x0d || crc_low == 0x0a) + crc_low++; + if (crc_high == 0x28 || crc_high == 0x0d || crc_high == 0x0a) + crc_high++; + crc = (crc_high << 8) | crc_low; + return crc; +} + } // namespace pipsolar } // namespace esphome diff --git a/esphome/components/pipsolar/pipsolar.h b/esphome/components/pipsolar/pipsolar.h index 65fd3c670d..f20f44f095 100644 --- a/esphome/components/pipsolar/pipsolar.h +++ b/esphome/components/pipsolar/pipsolar.h @@ -193,7 +193,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { void empty_uart_buffer_(); uint8_t check_incoming_crc_(); uint8_t check_incoming_length_(uint8_t length); - uint16_t cal_crc_half_(uint8_t *msg, uint8_t len); + uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len); uint8_t send_next_command_(); void send_next_poll_(); void queue_command_(const char *command, uint8_t length); From 150c9b5fa3f43ce28391e841764828a5d8b7d7ae Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:14:19 +1200 Subject: [PATCH 0442/2607] Bump version to 2023.8.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c22dde6986..bd4c48a704 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.8.2" +__version__ = "2023.8.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 76ebbfefd2d6f69d58f3ceaf0f2c0cc0b3705d8b Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 5 Sep 2023 23:33:49 +0100 Subject: [PATCH 0443/2607] Integration LightwaveRF switches (#4812) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/lightwaverf/LwRx.cpp | 427 ++++++++++++++++++ esphome/components/lightwaverf/LwRx.h | 142 ++++++ esphome/components/lightwaverf/LwTx.cpp | 208 +++++++++ esphome/components/lightwaverf/LwTx.h | 92 ++++ esphome/components/lightwaverf/__init__.py | 83 ++++ .../components/lightwaverf/lightwaverf.cpp | 67 +++ esphome/components/lightwaverf/lightwaverf.h | 70 +++ tests/test3.yaml | 4 + 9 files changed, 1094 insertions(+) create mode 100644 esphome/components/lightwaverf/LwRx.cpp create mode 100644 esphome/components/lightwaverf/LwRx.h create mode 100644 esphome/components/lightwaverf/LwTx.cpp create mode 100644 esphome/components/lightwaverf/LwTx.h create mode 100644 esphome/components/lightwaverf/__init__.py create mode 100644 esphome/components/lightwaverf/lightwaverf.cpp create mode 100644 esphome/components/lightwaverf/lightwaverf.h diff --git a/CODEOWNERS b/CODEOWNERS index 384db8098f..498cfcac01 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -150,6 +150,7 @@ esphome/components/ledc/* @OttoWinter esphome/components/libretiny/* @kuba2k2 esphome/components/libretiny_pwm/* @kuba2k2 esphome/components/light/* @esphome/core +esphome/components/lightwaverf/* @max246 esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core diff --git a/esphome/components/lightwaverf/LwRx.cpp b/esphome/components/lightwaverf/LwRx.cpp new file mode 100644 index 0000000000..2b1ad5e870 --- /dev/null +++ b/esphome/components/lightwaverf/LwRx.cpp @@ -0,0 +1,427 @@ +// LwRx.cpp +// +// LightwaveRF 434MHz receiver interface for Arduino +// +// Author: Bob Tidey (robert@tideys.net) + +#ifdef USE_ESP8266 + +#include "LwRx.h" +#include + +namespace esphome { +namespace lightwaverf { + +/** + Pin change interrupt routine that identifies 1 and 0 LightwaveRF bits + and constructs a message when a valid packet of data is received. +**/ + +void IRAM_ATTR LwRx::rx_process_bits(LwRx *args) { + uint8_t event = args->rx_pin_isr_.digital_read(); // start setting event to the current value + uint32_t curr = micros(); // the current time in microseconds + + uint16_t dur = (curr - args->rx_prev); // unsigned int + args->rx_prev = curr; + // set event based on input and duration of previous pulse + if (dur < 120) { // 120 very short + } else if (dur < 500) { // normal short pulse + event += 2; + } else if (dur < 2000) { // normal long pulse + event += 4; + } else if (dur > 5000) { // gap between messages + event += 6; + } else { // 2000 > 5000 + event = 8; // illegal gap + } + // state machine transitions + switch (args->rx_state) { + case RX_STATE_IDLE: + switch (event) { + case 7: // 1 after a message gap + args->rx_state = RX_STATE_MSGSTARTFOUND; + break; + } + break; + case RX_STATE_MSGSTARTFOUND: + switch (event) { + case 2: // 0 160->500 + // nothing to do wait for next positive edge + break; + case 3: // 1 160->500 + args->rx_num_bytes = 0; + args->rx_state = RX_STATE_BYTESTARTFOUND; + break; + default: + // not good start again + args->rx_state = RX_STATE_IDLE; + break; + } + break; + case RX_STATE_BYTESTARTFOUND: + switch (event) { + case 2: // 0 160->500 + // nothing to do wait for next positive edge + break; + case 3: // 1 160->500 + args->rx_state = RX_STATE_GETBYTE; + args->rx_num_bits = 0; + break; + case 5: // 0 500->1500 + args->rx_state = RX_STATE_GETBYTE; + // Starts with 0 so put this into uint8_t + args->rx_num_bits = 1; + args->rx_buf[args->rx_num_bytes] = 0; + break; + default: + // not good start again + args->rx_state = RX_STATE_IDLE; + break; + } + break; + case RX_STATE_GETBYTE: + switch (event) { + case 2: // 0 160->500 + // nothing to do wait for next positive edge but do stats + if (args->lwrx_stats_enable) { + args->lwrx_stats[RX_STAT_HIGH_MAX] = std::max(args->lwrx_stats[RX_STAT_HIGH_MAX], dur); + args->lwrx_stats[RX_STAT_HIGH_MIN] = std::min(args->lwrx_stats[RX_STAT_HIGH_MIN], dur); + args->lwrx_stats[RX_STAT_HIGH_AVE] = + args->lwrx_stats[RX_STAT_HIGH_AVE] - (args->lwrx_stats[RX_STAT_HIGH_AVE] >> 4) + dur; + } + break; + case 3: // 1 160->500 + // a single 1 + args->rx_buf[args->rx_num_bytes] = args->rx_buf[args->rx_num_bytes] << 1 | 1; + args->rx_num_bits++; + if (args->lwrx_stats_enable) { + args->lwrx_stats[RX_STAT_LOW1_MAX] = std::max(args->lwrx_stats[RX_STAT_LOW1_MAX], dur); + args->lwrx_stats[RX_STAT_LOW1_MIN] = std::min(args->lwrx_stats[RX_STAT_LOW1_MIN], dur); + args->lwrx_stats[RX_STAT_LOW1_AVE] = + args->lwrx_stats[RX_STAT_LOW1_AVE] - (args->lwrx_stats[RX_STAT_LOW1_AVE] >> 4) + dur; + } + break; + case 5: // 1 500->1500 + // a 1 followed by a 0 + args->rx_buf[args->rx_num_bytes] = args->rx_buf[args->rx_num_bytes] << 2 | 2; + args->rx_num_bits++; + args->rx_num_bits++; + if (args->lwrx_stats_enable) { + args->lwrx_stats[RX_STAT_LOW0_MAX] = std::max(args->lwrx_stats[RX_STAT_LOW0_MAX], dur); + args->lwrx_stats[RX_STAT_LOW0_MIN] = std::min(args->lwrx_stats[RX_STAT_LOW0_MIN], dur); + args->lwrx_stats[RX_STAT_LOW0_AVE] = + args->lwrx_stats[RX_STAT_LOW0_AVE] - (args->lwrx_stats[RX_STAT_LOW0_AVE] >> 4) + dur; + } + break; + default: + // not good start again + args->rx_state = RX_STATE_IDLE; + break; + } + if (args->rx_num_bits >= 8) { + args->rx_num_bytes++; + args->rx_num_bits = 0; + if (args->rx_num_bytes >= RX_MSGLEN) { + uint32_t curr_millis = millis(); + if (args->rx_repeats > 0) { + if ((curr_millis - args->rx_prevpkttime) / 100 > args->rx_timeout) { + args->rx_repeatcount = 1; + } else { + // Test message same as last one + int16_t i = RX_MSGLEN; // int + do { + i--; + } while ((i >= 0) && (args->rx_msg[i] == args->rx_buf[i])); + if (i < 0) { + args->rx_repeatcount++; + } else { + args->rx_repeatcount = 1; + } + } + } else { + args->rx_repeatcount = 0; + } + args->rx_prevpkttime = curr_millis; + // If last message hasn't been read it gets overwritten + memcpy(args->rx_msg, args->rx_buf, RX_MSGLEN); + if (args->rx_repeats == 0 || args->rx_repeatcount == args->rx_repeats) { + if (args->rx_pairtimeout != 0) { + if ((curr_millis - args->rx_pairstarttime) / 100 <= args->rx_pairtimeout) { + if (args->rx_msg[3] == RX_CMD_ON) { + args->rx_addpairfrommsg_(); + } else if (args->rx_msg[3] == RX_CMD_OFF) { + args->rx_remove_pair_(&args->rx_msg[2]); + } + } + } + if (args->rx_report_message_()) { + args->rx_msgcomplete = true; + } + args->rx_pairtimeout = 0; + } + // And cycle round for next one + args->rx_state = RX_STATE_IDLE; + } else { + args->rx_state = RX_STATE_BYTESTARTFOUND; + } + } + break; + } +} + +/** + Test if a message has arrived +**/ +bool LwRx::lwrx_message() { return (this->rx_msgcomplete); } + +/** + Set translate mode +**/ +void LwRx::lwrx_settranslate(bool rxtranslate) { this->rx_translate = rxtranslate; } +/** + Transfer a message to user buffer +**/ +bool LwRx::lwrx_getmessage(uint8_t *buf, uint8_t len) { + bool ret = true; + int16_t j = 0; // int + if (this->rx_msgcomplete && len <= RX_MSGLEN) { + for (uint8_t i = 0; ret && i < RX_MSGLEN; i++) { + if (this->rx_translate || (len != RX_MSGLEN)) { + j = this->rx_find_nibble_(this->rx_msg[i]); + if (j < 0) + ret = false; + } else { + j = this->rx_msg[i]; + } + switch (len) { + case 4: + if (i == 9) + buf[2] = j; + if (i == 2) + buf[3] = j; + case 2: + if (i == 3) + buf[0] = j; + if (i == 0) + buf[1] = j << 4; + if (i == 1) + buf[1] += j; + break; + case 10: + buf[i] = j; + break; + } + } + this->rx_msgcomplete = false; + } else { + ret = false; + } + return ret; +} + +/** + Return time in milliseconds since last packet received +**/ +uint32_t LwRx::lwrx_packetinterval() { return millis() - this->rx_prevpkttime; } + +/** + Set up repeat filtering of received messages +**/ +void LwRx::lwrx_setfilter(uint8_t repeats, uint8_t timeout) { + this->rx_repeats = repeats; + this->rx_timeout = timeout; +} + +/** + Add a pair to filter received messages + pairdata is device,dummy,5*addr,room + pairdata is held in translated form to make comparisons quicker +**/ +uint8_t LwRx::lwrx_addpair(const uint8_t *pairdata) { + if (this->rx_paircount < RX_MAXPAIRS) { + for (uint8_t i = 0; i < 8; i++) { + this->rx_pairs[rx_paircount][i] = RX_NIBBLE[pairdata[i]]; + } + this->rx_paircommit_(); + } + return this->rx_paircount; +} + +/** + Make a pair from next message successfully received +**/ +void LwRx::lwrx_makepair(uint8_t timeout) { + this->rx_pairtimeout = timeout; + this->rx_pairstarttime = millis(); +} + +/** + Get pair data (translated back to nibble form +**/ +uint8_t LwRx::lwrx_getpair(uint8_t *pairdata, uint8_t pairnumber) { + if (pairnumber < this->rx_paircount) { + int16_t j; // int + for (uint8_t i = 0; i < 8; i++) { + j = this->rx_find_nibble_(this->rx_pairs[pairnumber][i]); + if (j >= 0) + pairdata[i] = j; + } + } + return this->rx_paircount; +} + +/** + Clear all pairing +**/ +void LwRx::lwrx_clearpairing_() { rx_paircount = 0; } + +/** + Return stats on high and low pulses +**/ +bool LwRx::lwrx_getstats_(uint16_t *stats) { // unsigned int + if (this->lwrx_stats_enable) { + memcpy(stats, this->lwrx_stats, 2 * RX_STAT_COUNT); + return true; + } else { + return false; + } +} + +/** + Set stats mode +**/ +void LwRx::lwrx_setstatsenable_(bool rx_stats_enable) { + this->lwrx_stats_enable = rx_stats_enable; + if (!this->lwrx_stats_enable) { + // clear down stats when disabling + memcpy(this->lwrx_stats, LWRX_STATSDFLT, sizeof(LWRX_STATSDFLT)); + } +} +/** + Set pairs behaviour +**/ +void LwRx::lwrx_set_pair_mode(bool pair_enforce, bool pair_base_only) { + this->rx_pairEnforce = pair_enforce; + this->rx_pairBaseOnly = pair_base_only; +} + +/** + Set things up to receive LightWaveRF 434Mhz messages + pin must be 2 or 3 to trigger interrupts + !!! For Spark, any pin will work +**/ +void LwRx::lwrx_setup(InternalGPIOPin *pin) { + // rx_pin = pin; + pin->setup(); + this->rx_pin_isr_ = pin->to_isr(); + pin->attach_interrupt(&LwRx::rx_process_bits, this, gpio::INTERRUPT_ANY_EDGE); + + memcpy(this->lwrx_stats, LWRX_STATSDFLT, sizeof(LWRX_STATSDFLT)); +} + +/** + Check a message to see if it should be reported under pairing / mood / all off rules + returns -1 if none found +**/ +bool LwRx::rx_report_message_() { + if (this->rx_pairEnforce && this->rx_paircount == 0) { + return false; + } else { + bool all_devices; + // True if mood to device 15 or Off cmd with Allof paramater + all_devices = ((this->rx_msg[3] == RX_CMD_MOOD && this->rx_msg[2] == RX_DEV_15) || + (this->rx_msg[3] == RX_CMD_OFF && this->rx_msg[0] == RX_PAR0_ALLOFF)); + return (rx_check_pairs_(&this->rx_msg[2], all_devices) != -1); + } +} +/** + Find nibble from byte + returns -1 if none found +**/ +int16_t LwRx::rx_find_nibble_(uint8_t data) { // int + int16_t i = 15; // int + do { + if (RX_NIBBLE[i] == data) + break; + i--; + } while (i >= 0); + return i; +} + +/** + add pair from message buffer +**/ +void LwRx::rx_addpairfrommsg_() { + if (this->rx_paircount < RX_MAXPAIRS) { + memcpy(this->rx_pairs[this->rx_paircount], &this->rx_msg[2], 8); + this->rx_paircommit_(); + } +} + +/** + check and commit pair +**/ +void LwRx::rx_paircommit_() { + if (this->rx_paircount == 0 || this->rx_check_pairs_(this->rx_pairs[this->rx_paircount], false) < 0) { + this->rx_paircount++; + } +} + +/** + Check to see if message matches one of the pairs + if mode is pairBase only then ignore device and room + if allDevices is true then ignore the device number + Returns matching pair number, -1 if not found, -2 if no pairs defined +**/ +int16_t LwRx::rx_check_pairs_(const uint8_t *buf, bool all_devices) { // int + if (this->rx_paircount == 0) { + return -2; + } else { + int16_t pair = this->rx_paircount; // int + int16_t j = -1; // int + int16_t jstart, jend; // int + if (this->rx_pairBaseOnly) { + // skip room(8) and dev/cmd (0,1) + jstart = 7; + jend = 2; + } else { + // include room in comparison + jstart = 8; + // skip device comparison if allDevices true + jend = (all_devices) ? 2 : 0; + } + while (pair > 0 && j < 0) { + pair--; + j = jstart; + while (j > jend) { + j--; + if (j != 1) { + if (this->rx_pairs[pair][j] != buf[j]) { + j = -1; + } + } + } + } + return (j >= 0) ? pair : -1; + } +} + +/** + Remove an existing pair matching the buffer +**/ +void LwRx::rx_remove_pair_(uint8_t *buf) { + int16_t pair = this->rx_check_pairs_(buf, false); // int + if (pair >= 0) { + while (pair < this->rx_paircount - 1) { + for (uint8_t j = 0; j < 8; j++) { + this->rx_pairs[pair][j] = this->rx_pairs[pair + 1][j]; + } + pair++; + } + this->rx_paircount--; + } +} + +} // namespace lightwaverf +} // namespace esphome +#endif diff --git a/esphome/components/lightwaverf/LwRx.h b/esphome/components/lightwaverf/LwRx.h new file mode 100644 index 0000000000..7200f9a51c --- /dev/null +++ b/esphome/components/lightwaverf/LwRx.h @@ -0,0 +1,142 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace lightwaverf { + +// LwRx.h +// +// LightwaveRF 434MHz receiver for Arduino +// +// Author: Bob Tidey (robert@tideys.net) + +static const uint8_t RX_STAT_HIGH_AVE = 0; +static const uint8_t RX_STAT_HIGH_MAX = 1; +static const uint8_t RX_STAT_HIGH_MIN = 2; +static const uint8_t RX_STAT_LOW0_AVE = 3; +static const uint8_t RX_STAT_LOW0_MAX = 4; +static const uint8_t RX_STAT_LOW0_MIN = 5; +static const uint8_t RX_STAT_LOW1_AVE = 6; +static const uint8_t RX_STAT_LOW1_MAX = 7; +static const uint8_t RX_STAT_LOW1_MIN = 8; +static const uint8_t RX_STAT_COUNT = 9; + +// sets maximum number of pairings which can be held +static const uint8_t RX_MAXPAIRS = 10; + +static const uint8_t RX_NIBBLE[] = {0xF6, 0xEE, 0xED, 0xEB, 0xDE, 0xDD, 0xDB, 0xBE, + 0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77, 0x6F}; +static const uint8_t RX_CMD_OFF = 0xF6; // raw 0 +static const uint8_t RX_CMD_ON = 0xEE; // raw 1 +static const uint8_t RX_CMD_MOOD = 0xED; // raw 2 +static const uint8_t RX_PAR0_ALLOFF = 0x7D; // param 192-255 all off (12 in msb) +static const uint8_t RX_DEV_15 = 0x6F; // device 15 + +static const uint8_t RX_MSGLEN = 10; // expected length of rx message + +static const uint8_t RX_STATE_IDLE = 0; +static const uint8_t RX_STATE_MSGSTARTFOUND = 1; +static const uint8_t RX_STATE_BYTESTARTFOUND = 2; +static const uint8_t RX_STATE_GETBYTE = 3; + +// Gather stats for pulse widths (ave is x 16) +static const uint16_t LWRX_STATSDFLT[RX_STAT_COUNT] = {5000, 0, 5000, 20000, 0, 2500, 4000, 0, 500}; // usigned int + +class LwRx { + public: + // Seup must be called once, set up pin used to receive data + void lwrx_setup(InternalGPIOPin *pin); + + // Set translate to determine whether translating from nibbles to bytes in message + // Translate off only applies to 10char message returns + void lwrx_settranslate(bool translate); + + // Check to see whether message available + bool lwrx_message(); + + // Get a message, len controls format (2 cmd+param, 4 cmd+param+room+device),10 full message + bool lwrx_getmessage(uint8_t *buf, uint8_t len); + + // Setup repeat filter + void lwrx_setfilter(uint8_t repeats, uint8_t timeout); + + // Add pair, if no pairing set then all messages are received, returns number of pairs + uint8_t lwrx_addpair(const uint8_t *pairdata); + + // Get pair data into buffer for the pairnumber. Returns current paircount + // Use pairnumber 255 to just get current paircount + uint8_t lwrx_getpair(uint8_t *pairdata, uint8_t pairnumber); + + // Make a pair from next message received within timeout 100mSec + // This call returns immediately whilst message checking continues + void lwrx_makepair(uint8_t timeout); + + // Set pair mode controls + void lwrx_set_pair_mode(bool pair_enforce, bool pair_base_only); + + // Returns time from last packet received in msec + // Can be used to determine if Rx may be still receiving repeats + uint32_t lwrx_packetinterval(); + + static void rx_process_bits(LwRx *arg); + + // Pairing data + uint8_t rx_paircount = 0; + uint8_t rx_pairs[RX_MAXPAIRS][8]; + // set false to responds to all messages if no pairs set up + bool rx_pairEnforce = false; + // set false to use Address, Room and Device in pairs, true just the Address part + bool rx_pairBaseOnly = false; + + uint8_t rx_pairtimeout = 0; // 100msec units + + // Repeat filters + uint8_t rx_repeats = 2; // msg must be repeated at least this number of times + uint8_t rx_repeatcount = 0; + uint8_t rx_timeout = 20; // reset repeat window after this in 100mSecs + uint32_t rx_prevpkttime = 0; // last packet time in milliseconds + uint32_t rx_pairstarttime = 0; // last msg time in milliseconds + + // Receive mode constants and variables + uint8_t rx_msg[RX_MSGLEN]; // raw message received + uint8_t rx_buf[RX_MSGLEN]; // message buffer during reception + + uint32_t rx_prev; // time of previous interrupt in microseconds + + bool rx_msgcomplete = false; // set high when message available + bool rx_translate = true; // Set false to get raw data + + uint8_t rx_state = 0; + + uint8_t rx_num_bits = 0; // number of bits in the current uint8_t + uint8_t rx_num_bytes = 0; // number of bytes received + + uint16_t lwrx_stats[RX_STAT_COUNT]; // unsigned int + + bool lwrx_stats_enable = true; + + protected: + void lwrx_clearpairing_(); + + // Return stats on pulse timings + bool lwrx_getstats_(uint16_t *stats); + + // Enable collection of stats on pulse timings + void lwrx_setstatsenable_(bool rx_stats_enable); + + // internal support functions + bool rx_report_message_(); + int16_t rx_find_nibble_(uint8_t data); // int + void rx_addpairfrommsg_(); + void rx_paircommit_(); + void rx_remove_pair_(uint8_t *buf); + int16_t rx_check_pairs_(const uint8_t *buf, bool all_devices); // int + + ISRInternalGPIOPin rx_pin_isr_; + InternalGPIOPin *rx_pin_; +}; + +} // namespace lightwaverf +} // namespace esphome diff --git a/esphome/components/lightwaverf/LwTx.cpp b/esphome/components/lightwaverf/LwTx.cpp new file mode 100644 index 0000000000..2f46b04b2d --- /dev/null +++ b/esphome/components/lightwaverf/LwTx.cpp @@ -0,0 +1,208 @@ +// LwTx.cpp +// +// LightwaveRF 434MHz tx interface for Arduino +// +// Author: Bob Tidey (robert@tideys.net) +#ifdef USE_ESP8266 + +#include "LwTx.h" +#include +#include +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace lightwaverf { + +static const uint8_t TX_NIBBLE[] = {0xF6, 0xEE, 0xED, 0xEB, 0xDE, 0xDD, 0xDB, 0xBE, + 0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77, 0x6F}; + +static const uint8_t TX_STATE_IDLE = 0; +static const uint8_t TX_STATE_MSGSTART = 1; +static const uint8_t TX_STATE_BYTESTART = 2; +static const uint8_t TX_STATE_SENDBYTE = 3; +static const uint8_t TX_STATE_MSGEND = 4; +static const uint8_t TX_STATE_GAPSTART = 5; +static const uint8_t TX_STATE_GAPEND = 6; +/** + Set translate mode +**/ +void LwTx::lwtx_settranslate(bool txtranslate) { tx_translate = txtranslate; } + +static void IRAM_ATTR isr_t_xtimer(LwTx *arg) { + // Set low after toggle count interrupts + arg->tx_toggle_count--; + if (arg->tx_toggle_count == arg->tx_trail_count) { + // ESP_LOGD("lightwaverf.sensor", "timer") + arg->tx_pin->digital_write(arg->txoff); + } else if (arg->tx_toggle_count == 0) { + arg->tx_toggle_count = arg->tx_high_count; // default high pulse duration + switch (arg->tx_state) { + case TX_STATE_IDLE: + if (arg->tx_msg_active) { + arg->tx_repeat = 0; + arg->tx_state = TX_STATE_MSGSTART; + } + break; + case TX_STATE_MSGSTART: + arg->tx_pin->digital_write(arg->txon); + arg->tx_num_bytes = 0; + arg->tx_state = TX_STATE_BYTESTART; + break; + case TX_STATE_BYTESTART: + arg->tx_pin->digital_write(arg->txon); + arg->tx_bit_mask = 0x80; + arg->tx_state = TX_STATE_SENDBYTE; + break; + case TX_STATE_SENDBYTE: + if (arg->tx_buf[arg->tx_num_bytes] & arg->tx_bit_mask) { + arg->tx_pin->digital_write(arg->txon); + } else { + // toggle count for the 0 pulse + arg->tx_toggle_count = arg->tx_low_count; + } + arg->tx_bit_mask >>= 1; + if (arg->tx_bit_mask == 0) { + arg->tx_num_bytes++; + if (arg->tx_num_bytes >= esphome::lightwaverf::LwTx::TX_MSGLEN) { + arg->tx_state = TX_STATE_MSGEND; + } else { + arg->tx_state = TX_STATE_BYTESTART; + } + } + break; + case TX_STATE_MSGEND: + arg->tx_pin->digital_write(arg->txon); + arg->tx_state = TX_STATE_GAPSTART; + arg->tx_gap_repeat = arg->tx_gap_multiplier; + break; + case TX_STATE_GAPSTART: + arg->tx_toggle_count = arg->tx_gap_count; + if (arg->tx_gap_repeat == 0) { + arg->tx_state = TX_STATE_GAPEND; + } else { + arg->tx_gap_repeat--; + } + break; + case TX_STATE_GAPEND: + arg->tx_repeat++; + if (arg->tx_repeat >= arg->tx_repeats) { + // disable timer nterrupt + arg->lw_timer_stop(); + arg->tx_msg_active = false; + arg->tx_state = TX_STATE_IDLE; + } else { + arg->tx_state = TX_STATE_MSGSTART; + } + break; + } + } +} + +/** + Check for send free +**/ +bool LwTx::lwtx_free() { return !this->tx_msg_active; } + +/** + Send a LightwaveRF message (10 nibbles in bytes) +**/ +void LwTx::lwtx_send(const std::vector &msg) { + if (this->tx_translate) { + for (uint8_t i = 0; i < TX_MSGLEN; i++) { + this->tx_buf[i] = TX_NIBBLE[msg[i] & 0xF]; + ESP_LOGD("lightwaverf.sensor", "%x ", msg[i]); + } + } else { + // memcpy(tx_buf, msg, tx_msglen); + } + this->lw_timer_start(); + this->tx_msg_active = true; +} + +/** + Set 5 char address for future messages +**/ +void LwTx::lwtx_setaddr(const uint8_t *addr) { + for (uint8_t i = 0; i < 5; i++) { + this->tx_buf[i + 4] = TX_NIBBLE[addr[i] & 0xF]; + } +} + +/** + Send a LightwaveRF message (10 nibbles in bytes) +**/ +void LwTx::lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device) { + // enable timer 2 interrupts + this->tx_buf[0] = TX_NIBBLE[parameter >> 4]; + this->tx_buf[1] = TX_NIBBLE[parameter & 0xF]; + this->tx_buf[2] = TX_NIBBLE[device & 0xF]; + this->tx_buf[3] = TX_NIBBLE[command & 0xF]; + this->tx_buf[9] = TX_NIBBLE[room & 0xF]; + this->lw_timer_start(); + this->tx_msg_active = true; +} + +/** + Set things up to transmit LightWaveRF 434Mhz messages +**/ +void LwTx::lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec) { + pin->setup(); + tx_pin = pin; + + tx_pin->pin_mode(gpio::FLAG_OUTPUT); + tx_pin->digital_write(txoff); + + if (repeats > 0 && repeats < 40) { + this->tx_repeats = repeats; + } + if (inverted) { + this->txon = 0; + this->txoff = 1; + } else { + this->txon = 1; + this->txoff = 0; + } + + int period1 = 330; + /* + if (period > 32 && period < 1000) { + period1 = period; + } else { + // default 330 uSec + period1 = 330; + }*/ + this->espPeriod = 5 * period1; + timer1_isr_init(); +} + +void LwTx::lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count) { + this->tx_low_count = low_count; + this->tx_high_count = high_count; + this->tx_trail_count = trail_count; + this->tx_gap_count = gap_count; +} + +void LwTx::lwtx_set_gap_multiplier(uint8_t gap_multiplier) { this->tx_gap_multiplier = gap_multiplier; } + +void LwTx::lw_timer_start() { + { + InterruptLock lock; + static LwTx *arg = this; // NOLINT + timer1_attachInterrupt([] { isr_t_xtimer(arg); }); + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP); + timer1_write(this->espPeriod); + } +} + +void LwTx::lw_timer_stop() { + { + InterruptLock lock; + timer1_disable(); + timer1_detachInterrupt(); + } +} + +} // namespace lightwaverf +} // namespace esphome +#endif diff --git a/esphome/components/lightwaverf/LwTx.h b/esphome/components/lightwaverf/LwTx.h new file mode 100644 index 0000000000..719826640e --- /dev/null +++ b/esphome/components/lightwaverf/LwTx.h @@ -0,0 +1,92 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace lightwaverf { + +// LxTx.h +// +// LightwaveRF 434MHz tx interface for Arduino +// +// Author: Bob Tidey (robert@tideys.net) + +// Include basic library header and set default TX pin +static const uint8_t TX_PIN_DEFAULT = 13; + +class LwTx { + public: + // Sets up basic parameters must be called at least once + void lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec); + + // Allows changing basic tick counts from their defaults + void lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count); + + // Allws multiplying the gap period for creating very large gaps + void lwtx_set_gap_multiplier(uint8_t gap_multiplier); + + // determines whether incoming data or should be translated from nibble data + void lwtx_settranslate(bool txtranslate); + + // Checks whether tx is free to accept a new message + bool lwtx_free(); + + // Basic send of new 10 char message, not normally needed if setaddr and cmd are used. + void lwtx_send(const std::vector &msg); + + // Sets up 5 char address which will be used to form messages for lwtx_cmd + void lwtx_setaddr(const uint8_t *addr); + + // Send Command + void lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device); + + // Allows changing basic tick counts from their defaults + void lw_timer_start(); + + // Allws multiplying the gap period for creating very large gaps + void lw_timer_stop(); + + // These set the pulse durationlws in ticks. ESP uses 330uSec base tick, else use 140uSec + uint8_t tx_low_count = 3; // total number of ticks in a low (990 uSec) + uint8_t tx_high_count = 2; // total number of ticks in a high (660 uSec) + uint8_t tx_trail_count = 1; // tick count to set line low (330 uSec) + + uint8_t tx_toggle_count = 3; + + static const uint8_t TX_MSGLEN = 10; // the expected length of the message + + // Transmit mode constants and variables + uint8_t tx_repeats = 12; // Number of repeats of message sent + uint8_t txon = 1; + uint8_t txoff = 0; + bool tx_msg_active = false; // set true to activate message sending + bool tx_translate = true; // Set false to send raw data + + uint8_t tx_buf[TX_MSGLEN]; // the message buffer during reception + uint8_t tx_repeat = 0; // counter for repeats + uint8_t tx_state = 0; + uint16_t tx_gap_repeat = 0; // unsigned int + + // Use with low repeat counts + uint8_t tx_gap_count = 33; // Inter-message gap count (10.9 msec) + uint32_t espPeriod = 0; // Holds interrupt timer0 period + uint32_t espNext = 0; // Holds interrupt next count + + // Gap multiplier byte is used to multiply gap if longer periods are needed for experimentation + // If gap is 255 (35msec) then this to give a max of 9 seconds + // Used with low repeat counts to find if device times out + uint8_t tx_gap_multiplier = 0; // Gap extension byte + + uint8_t tx_bit_mask = 0; // bit mask in current byte + uint8_t tx_num_bytes = 0; // number of bytes sent + + InternalGPIOPin *tx_pin; + + protected: + uint32_t duty_on_; + uint32_t duty_off_; +}; + +} // namespace lightwaverf +} // namespace esphome diff --git a/esphome/components/lightwaverf/__init__.py b/esphome/components/lightwaverf/__init__.py new file mode 100644 index 0000000000..4e96dda663 --- /dev/null +++ b/esphome/components/lightwaverf/__init__.py @@ -0,0 +1,83 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome import automation + +from esphome.const import ( + CONF_READ_PIN, + CONF_ID, + CONF_NAME, + CONF_WRITE_PIN, + CONF_REPEAT, + CONF_INVERTED, + CONF_PULSE_LENGTH, + CONF_CODE, +) +from esphome.cpp_helpers import gpio_pin_expression + +CODEOWNERS = ["@max246"] + +lightwaverf_ns = cg.esphome_ns.namespace("lightwaverf") + + +LIGHTWAVERFComponent = lightwaverf_ns.class_( + "LightWaveRF", cg.Component, cg.PollingComponent +) +LightwaveRawAction = lightwaverf_ns.class_("SendRawAction", automation.Action) + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(LIGHTWAVERFComponent), + cv.Optional(CONF_READ_PIN, default=13): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_WRITE_PIN, default=14): pins.internal_gpio_input_pin_schema, + } +).extend(cv.polling_component_schema("1s")) + + +LIGHTWAVE_SEND_SCHEMA = cv.Any( + cv.int_range(min=1), + cv.Schema( + { + cv.GenerateID(): cv.use_id(LIGHTWAVERFComponent), + cv.Required(CONF_NAME): cv.string, + cv.Required(CONF_CODE): cv.All( + [cv.Any(cv.hex_uint8_t)], + cv.Length(min=10), + ), + cv.Optional(CONF_REPEAT, default=10): cv.int_, + cv.Optional(CONF_INVERTED, default=False): cv.boolean, + cv.Optional(CONF_PULSE_LENGTH, default=330): cv.int_, + } + ), +) + + +@automation.register_action( + "lightwaverf.send_raw", + LightwaveRawAction, + LIGHTWAVE_SEND_SCHEMA, +) +async def send_raw_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + repeats = await cg.templatable(config[CONF_REPEAT], args, int) + inverted = await cg.templatable(config[CONF_INVERTED], args, bool) + pulse_length = await cg.templatable(config[CONF_PULSE_LENGTH], args, int) + code = config[CONF_CODE] + + cg.add(var.set_repeats(repeats)) + cg.add(var.set_inverted(inverted)) + cg.add(var.set_pulse_length(pulse_length)) + cg.add(var.set_data(code)) + return var + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + pin_read = await gpio_pin_expression(config[CONF_READ_PIN]) + pin_write = await gpio_pin_expression(config[CONF_WRITE_PIN]) + cg.add(var.set_pin(pin_write, pin_read)) diff --git a/esphome/components/lightwaverf/lightwaverf.cpp b/esphome/components/lightwaverf/lightwaverf.cpp new file mode 100644 index 0000000000..89cbdae6e1 --- /dev/null +++ b/esphome/components/lightwaverf/lightwaverf.cpp @@ -0,0 +1,67 @@ +#include "esphome/core/log.h" + +#ifdef USE_ESP8266 + +#include "lightwaverf.h" + +namespace esphome { +namespace lightwaverf { + +static const char *const TAG = "lightwaverf.sensor"; + +static const uint8_t DEFAULT_REPEAT = 10; +static const bool DEFAULT_INVERT = false; +static const uint32_t DEFAULT_TICK = 330; + +void LightWaveRF::setup() { + ESP_LOGCONFIG(TAG, "Setting up Lightwave RF..."); + + this->lwtx_.lwtx_setup(pin_tx_, DEFAULT_REPEAT, DEFAULT_INVERT, DEFAULT_TICK); + this->lwrx_.lwrx_setup(pin_rx_); +} + +void LightWaveRF::update() { this->read_tx(); } + +void LightWaveRF::read_tx() { + if (this->lwrx_.lwrx_message()) { + this->lwrx_.lwrx_getmessage(msg_, msglen_); + print_msg_(msg_, msglen_); + } +} + +void LightWaveRF::send_rx(const std::vector &msg, uint8_t repeats, bool inverted, int u_sec) { + this->lwtx_.lwtx_setup(pin_tx_, repeats, inverted, u_sec); + + uint32_t timeout = 0; + if (this->lwtx_.lwtx_free()) { + this->lwtx_.lwtx_send(msg); + timeout = millis(); + ESP_LOGD(TAG, "[%i] msg start", timeout); + } + while (!this->lwtx_.lwtx_free() && millis() < (timeout + 1000)) { + delay(10); + } + timeout = millis() - timeout; + ESP_LOGD(TAG, "[%u] msg sent: %i", millis(), timeout); +} + +void LightWaveRF::print_msg_(uint8_t *msg, uint8_t len) { + char buffer[65]; + ESP_LOGD(TAG, " Received code (len:%i): ", len); + + for (int i = 0; i < len; i++) { + sprintf(&buffer[i * 6], "0x%02x, ", msg[i]); + } + ESP_LOGD(TAG, "[%s]", buffer); +} + +void LightWaveRF::dump_config() { + ESP_LOGCONFIG(TAG, "Lightwave RF:"); + LOG_PIN(" Pin TX: ", this->pin_tx_); + LOG_PIN(" Pin RX: ", this->pin_rx_); + LOG_UPDATE_INTERVAL(this); +} +} // namespace lightwaverf +} // namespace esphome + +#endif diff --git a/esphome/components/lightwaverf/lightwaverf.h b/esphome/components/lightwaverf/lightwaverf.h new file mode 100644 index 0000000000..b9f2abfcb3 --- /dev/null +++ b/esphome/components/lightwaverf/lightwaverf.h @@ -0,0 +1,70 @@ +#pragma once + +#ifdef USE_ESP8266 + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/automation.h" + +#include + +#include "LwRx.h" +#include "LwTx.h" + +namespace esphome { +namespace lightwaverf { + +#ifdef USE_ESP8266 + +class LightWaveRF : public PollingComponent { + public: + void set_pin(InternalGPIOPin *pin_tx, InternalGPIOPin *pin_rx) { + pin_tx_ = pin_tx; + pin_rx_ = pin_rx; + } + void update() override; + void setup() override; + void dump_config() override; + void read_tx(); + void send_rx(const std::vector &msg, uint8_t repeats, bool inverted, int u_sec); + + protected: + void print_msg_(uint8_t *msg, uint8_t len); + uint8_t msg_[10]; + uint8_t msglen_ = 10; + InternalGPIOPin *pin_tx_; + InternalGPIOPin *pin_rx_; + LwRx lwrx_; + LwTx lwtx_; +}; + +template class SendRawAction : public Action { + public: + SendRawAction(LightWaveRF *parent) : parent_(parent){}; + TEMPLATABLE_VALUE(int, repeat); + TEMPLATABLE_VALUE(int, inverted); + TEMPLATABLE_VALUE(int, pulse_length); + TEMPLATABLE_VALUE(std::vector, code); + + void set_repeats(const int &data) { repeat_ = data; } + void set_inverted(const int &data) { inverted_ = data; } + void set_pulse_length(const int &data) { pulse_length_ = data; } + void set_data(const std::vector &data) { code_ = data; } + + void play(Ts... x) { + int repeats = this->repeat_.value(x...); + int inverted = this->inverted_.value(x...); + int pulse_length = this->pulse_length_.value(x...); + std::vector msg = this->code_.value(x...); + + this->parent_->send_rx(msg, repeats, inverted, pulse_length); + } + + protected: + LightWaveRF *parent_; +}; + +#endif +} // namespace lightwaverf +} // namespace esphome +#endif diff --git a/tests/test3.yaml b/tests/test3.yaml index abfd133c99..5d30e415fb 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -1188,6 +1188,10 @@ qr_code: - id: homepage_qr value: https://esphome.io/index.html +lightwaverf: + read_pin: 13 + write_pin: 14 + alarm_control_panel: - platform: template id: alarmcontrolpanel1 From eff76d578b3391c568674cd41f820634c37c7a3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:44:47 +1200 Subject: [PATCH 0444/2607] Bump flake8 from 6.0.0 to 6.1.0 (#5171) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index e160c3e9e3..2d46d3dccd 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,5 +1,5 @@ pylint==2.17.5 -flake8==6.0.0 # also change in .pre-commit-config.yaml when updating +flake8==6.1.0 # also change in .pre-commit-config.yaml when updating black==23.7.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating pre-commit From e89c6494a6621a46685112fd658153611b9f72b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:45:17 +1200 Subject: [PATCH 0445/2607] Bump tornado from 6.3.2 to 6.3.3 (#5236) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c52b8e1d8e..9ec3a9c8f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ voluptuous==0.13.1 PyYAML==6.0.1 paho-mqtt==1.6.1 colorama==0.4.6 -tornado==6.3.2 +tornado==6.3.3 tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 From 6b0fb3dd065a7b443ea17ddef095e5ac3785a62d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 23:31:21 +0000 Subject: [PATCH 0446/2607] Bump platformio from 6.1.10 to 6.1.11 (#5323) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- docker/Dockerfile | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index a590445de9..bf64897af7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -61,7 +61,7 @@ RUN \ # Ubuntu python3-pip is missing wheel pip3 install --no-cache-dir \ wheel==0.37.1 \ - platformio==6.1.10 \ + platformio==6.1.11 \ # Change some platformio settings && platformio settings set enable_telemetry No \ && platformio settings set check_platformio_interval 1000000 \ diff --git a/requirements.txt b/requirements.txt index 9ec3a9c8f9..dcb7420d3f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ tornado==6.3.3 tzlocal==5.0.1 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.10 # When updating platformio, also update Dockerfile +platformio==6.1.11 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 From 8cac5ca90c59acb62283d3ae2a488c798069e2ee Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:32:14 +1200 Subject: [PATCH 0447/2607] Only run ci-docker when ci-docker workflow changes (#5347) --- .github/workflows/ci-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 394379d675..dbd0d573da 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -8,7 +8,7 @@ on: branches: [dev, beta, release] paths: - "docker/**" - - ".github/workflows/**" + - ".github/workflows/ci-docker.yml" - "requirements*.txt" - "platformio.ini" - "script/platformio_install_deps.py" @@ -16,7 +16,7 @@ on: pull_request: paths: - "docker/**" - - ".github/workflows/**" + - ".github/workflows/ci-docker.yml" - "requirements*.txt" - "platformio.ini" - "script/platformio_install_deps.py" From f2a6f1855376bbea403409f885dfd747d75ec6fd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 6 Sep 2023 17:02:21 +1200 Subject: [PATCH 0448/2607] esp32: Extra build customization (#5322) --- esphome/components/esp32/__init__.py | 46 +++++++++++++++++++++++----- esphome/components/esp32/const.py | 1 + 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index ee18315518..0b067dc78f 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -22,6 +22,7 @@ from esphome.const import ( CONF_IGNORE_EFUSE_MAC_CRC, KEY_CORE, KEY_FRAMEWORK_VERSION, + KEY_NAME, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, TYPE_GIT, @@ -37,6 +38,7 @@ from .const import ( # noqa KEY_BOARD, KEY_COMPONENTS, KEY_ESP32, + KEY_EXTRA_BUILD_FILES, KEY_PATH, KEY_REF, KEY_REFRESH, @@ -73,6 +75,8 @@ def set_core_data(config): ) CORE.data[KEY_ESP32][KEY_BOARD] = config[CONF_BOARD] CORE.data[KEY_ESP32][KEY_VARIANT] = config[CONF_VARIANT] + CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES] = {} + return config @@ -166,6 +170,24 @@ def add_idf_component( } +def add_extra_script(stage: str, filename: str, path: str): + """Add an extra script to the project.""" + key = f"{stage}:{filename}" + if add_extra_build_file(filename, path): + cg.add_platformio_option("extra_scripts", [key]) + + +def add_extra_build_file(filename: str, path: str) -> bool: + """Add an extra build file to the project.""" + if filename not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]: + CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES][filename] = { + KEY_NAME: filename, + KEY_PATH: path, + } + return True + return False + + def _format_framework_arduino_version(ver: cv.Version) -> str: # format the given arduino (https://github.com/espressif/arduino-esp32/releases) version to # a PIO platformio/framework-arduinoespressif32 value @@ -390,7 +412,11 @@ async def to_code(config): conf = config[CONF_FRAMEWORK] cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) - cg.add_platformio_option("extra_scripts", ["post:post_build.py"]) + add_extra_script( + "post", + "post_build2.py", + os.path.join(os.path.dirname(__file__), "post_build.py.script"), + ) if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: cg.add_platformio_option("framework", "espidf") @@ -604,9 +630,15 @@ def copy_files(): ignore_dangling_symlinks=True, ) - dir = os.path.dirname(__file__) - post_build_file = os.path.join(dir, "post_build.py.script") - copy_file_if_changed( - post_build_file, - CORE.relative_build_path("post_build.py"), - ) + for _, file in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES].items(): + if file[KEY_PATH].startswith("http"): + import requests + + mkdir_p(CORE.relative_build_path(os.path.dirname(file[KEY_NAME]))) + with open(CORE.relative_build_path(file[KEY_NAME]), "wb") as f: + f.write(requests.get(file[KEY_PATH], timeout=30).content) + else: + copy_file_if_changed( + file[KEY_PATH], + CORE.relative_build_path(file[KEY_NAME]), + ) diff --git a/esphome/components/esp32/const.py b/esphome/components/esp32/const.py index 9e997bdeb5..a86713e857 100644 --- a/esphome/components/esp32/const.py +++ b/esphome/components/esp32/const.py @@ -10,6 +10,7 @@ KEY_REF = "ref" KEY_REFRESH = "refresh" KEY_PATH = "path" KEY_SUBMODULES = "submodules" +KEY_EXTRA_BUILD_FILES = "extra_build_files" VARIANT_ESP32 = "ESP32" VARIANT_ESP32S2 = "ESP32S2" From 72f29b1283b925da3177bacd4b60ec0446291e81 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 7 Sep 2023 10:15:54 +1200 Subject: [PATCH 0449/2607] Allow upload command to flash file via serial (#5274) --- esphome/__main__.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 9b208c2280..9fac8cd605 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -218,14 +218,16 @@ def compile_program(args, config): return 0 if idedata is not None else 1 -def upload_using_esptool(config, port): +def upload_using_esptool(config, port, file): from esphome import platformio_api first_baudrate = config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get( "upload_speed", 460800 ) - def run_esptool(baud_rate): + if file is not None: + flash_images = [platformio_api.FlashImage(path=file, offset="0x0")] + else: idedata = platformio_api.get_idedata(config) firmware_offset = "0x10000" if CORE.is_esp32 else "0x0" @@ -236,12 +238,13 @@ def upload_using_esptool(config, port): *idedata.extra_flash_images, ] - mcu = "esp8266" - if CORE.is_esp32: - from esphome.components.esp32 import get_esp32_variant + mcu = "esp8266" + if CORE.is_esp32: + from esphome.components.esp32 import get_esp32_variant - mcu = get_esp32_variant().lower() + mcu = get_esp32_variant().lower() + def run_esptool(baud_rate): cmd = [ "esptool.py", "--before", @@ -292,7 +295,8 @@ def upload_using_platformio(config, port): def upload_program(config, args, host): if get_port_type(host) == "SERIAL": if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266): - return upload_using_esptool(config, host) + file = getattr(args, "file", None) + return upload_using_esptool(config, host, file) if CORE.target_platform in (PLATFORM_RP2040): return upload_using_platformio(config, args.device) From 87395d259ee53c8e50a2bbc29525bdeff0a97493 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:22:39 +1200 Subject: [PATCH 0450/2607] Allow "--device SERIAL" on cli to flash only via serial (#5351) --- esphome/__main__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/__main__.py b/esphome/__main__.py index 9fac8cd605..cf540f58ba 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -85,6 +85,8 @@ def choose_upload_log_host( options = [] for port in get_serial_ports(): options.append((f"{port.path} ({port.description})", port.path)) + if default == "SERIAL": + return choose_prompt(options, purpose=purpose) if (show_ota and "ota" in CORE.config) or (show_api and "api" in CORE.config): options.append((f"Over The Air ({CORE.address})", CORE.address)) if default == "OTA": From ab872b075a402d0180ab5087199b7e251b577f64 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 7 Sep 2023 04:48:44 -0500 Subject: [PATCH 0451/2607] Fix PN532 for IDF 5 and ultralight enhancements (#5352) --- esphome/components/nfc/nfc.cpp | 2 +- esphome/components/pn532/pn532.h | 8 +- .../pn532/pn532_mifare_ultralight.cpp | 119 ++++++++++-------- 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/esphome/components/nfc/nfc.cpp b/esphome/components/nfc/nfc.cpp index b7c7215028..7225e373b3 100644 --- a/esphome/components/nfc/nfc.cpp +++ b/esphome/components/nfc/nfc.cpp @@ -54,7 +54,7 @@ uint8_t get_mifare_classic_ndef_start_index(std::vector &data) { bool decode_mifare_classic_tlv(std::vector &data, uint32_t &message_length, uint8_t &message_start_index) { uint8_t i = get_mifare_classic_ndef_start_index(data); - if (i < 0 || data[i] != 0x03) { + if (data[i] != 0x03) { ESP_LOGE(TAG, "Error, Can't decode message length."); return false; } diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 73b349e328..8ae215dfd9 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -7,6 +7,7 @@ #include "esphome/components/nfc/nfc.h" #include "esphome/components/nfc/automation.h" +#include #include namespace esphome { @@ -74,10 +75,11 @@ class PN532 : public PollingComponent { bool write_mifare_classic_tag_(std::vector &uid, nfc::NdefMessage *message); std::unique_ptr read_mifare_ultralight_tag_(std::vector &uid); - bool read_mifare_ultralight_page_(uint8_t page_num, std::vector &data); - bool is_mifare_ultralight_formatted_(); + bool read_mifare_ultralight_bytes_(uint8_t start_page, uint16_t num_bytes, std::vector &data); + bool is_mifare_ultralight_formatted_(const std::vector &page_3_to_6); uint16_t read_mifare_ultralight_capacity_(); - bool find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index); + bool find_mifare_ultralight_ndef_(const std::vector &page_3_to_6, uint8_t &message_length, + uint8_t &message_start_index); bool write_mifare_ultralight_page_(uint8_t page_num, std::vector &write_data); bool write_mifare_ultralight_tag_(std::vector &uid, nfc::NdefMessage *message); bool clean_mifare_ultralight_(); diff --git a/esphome/components/pn532/pn532_mifare_ultralight.cpp b/esphome/components/pn532/pn532_mifare_ultralight.cpp index 1b91ae919e..b08a7336c7 100644 --- a/esphome/components/pn532/pn532_mifare_ultralight.cpp +++ b/esphome/components/pn532/pn532_mifare_ultralight.cpp @@ -9,93 +9,104 @@ namespace pn532 { static const char *const TAG = "pn532.mifare_ultralight"; std::unique_ptr PN532::read_mifare_ultralight_tag_(std::vector &uid) { - if (!this->is_mifare_ultralight_formatted_()) { - ESP_LOGD(TAG, "Not NDEF formatted"); + std::vector data; + // pages 3 to 6 contain various info we are interested in -- do one read to grab it all + if (!this->read_mifare_ultralight_bytes_(3, nfc::MIFARE_ULTRALIGHT_PAGE_SIZE * nfc::MIFARE_ULTRALIGHT_READ_SIZE, + data)) { + return make_unique(uid, nfc::NFC_FORUM_TYPE_2); + } + + if (!this->is_mifare_ultralight_formatted_(data)) { + ESP_LOGW(TAG, "Not NDEF formatted"); return make_unique(uid, nfc::NFC_FORUM_TYPE_2); } uint8_t message_length; uint8_t message_start_index; - if (!this->find_mifare_ultralight_ndef_(message_length, message_start_index)) { + if (!this->find_mifare_ultralight_ndef_(data, message_length, message_start_index)) { + ESP_LOGW(TAG, "Couldn't find NDEF message"); return make_unique(uid, nfc::NFC_FORUM_TYPE_2); } - ESP_LOGVV(TAG, "message length: %d, start: %d", message_length, message_start_index); + ESP_LOGVV(TAG, "NDEF message length: %u, start: %u", message_length, message_start_index); if (message_length == 0) { return make_unique(uid, nfc::NFC_FORUM_TYPE_2); } - std::vector data; - for (uint8_t page = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE; page < nfc::MIFARE_ULTRALIGHT_MAX_PAGE; page++) { - std::vector page_data; - if (!this->read_mifare_ultralight_page_(page, page_data)) { - ESP_LOGE(TAG, "Error reading page %d", page); + // we already read pages 3-6 earlier -- pick up where we left off so we're not re-reading pages + const uint8_t read_length = message_length + message_start_index > 12 ? message_length + message_start_index - 12 : 0; + if (read_length) { + if (!read_mifare_ultralight_bytes_(nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE + 3, read_length, data)) { + ESP_LOGE(TAG, "Error reading tag data"); return make_unique(uid, nfc::NFC_FORUM_TYPE_2); } - data.insert(data.end(), page_data.begin(), page_data.end()); - - if (data.size() >= (message_length + message_start_index)) - break; } - - data.erase(data.begin(), data.begin() + message_start_index); - data.erase(data.begin() + message_length, data.end()); + // we need to trim off page 3 as well as any bytes ahead of message_start_index + data.erase(data.begin(), data.begin() + message_start_index + nfc::MIFARE_ULTRALIGHT_PAGE_SIZE); return make_unique(uid, nfc::NFC_FORUM_TYPE_2, data); } -bool PN532::read_mifare_ultralight_page_(uint8_t page_num, std::vector &data) { - if (!this->write_command_({ - PN532_COMMAND_INDATAEXCHANGE, - 0x01, // One card - nfc::MIFARE_CMD_READ, - page_num, - })) { - return false; +bool PN532::read_mifare_ultralight_bytes_(uint8_t start_page, uint16_t num_bytes, std::vector &data) { + const uint8_t read_increment = nfc::MIFARE_ULTRALIGHT_READ_SIZE * nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; + std::vector response; + + for (uint8_t i = 0; i * read_increment < num_bytes; i++) { + if (!this->write_command_({ + PN532_COMMAND_INDATAEXCHANGE, + 0x01, // One card + nfc::MIFARE_CMD_READ, + uint8_t(i * nfc::MIFARE_ULTRALIGHT_READ_SIZE + start_page), + })) { + return false; + } + + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response) || response[0] != 0x00) { + return false; + } + uint16_t bytes_offset = (i + 1) * read_increment; + auto pages_in_end_itr = bytes_offset <= num_bytes ? response.end() : response.end() - (bytes_offset - num_bytes); + + if ((pages_in_end_itr > response.begin()) && (pages_in_end_itr <= response.end())) { + data.insert(data.end(), response.begin() + 1, pages_in_end_itr); + } } - if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) { - return false; - } - data.erase(data.begin()); - // We only want 1 page of data but the PN532 returns 4 at once. - data.erase(data.begin() + 4, data.end()); - - ESP_LOGVV(TAG, "Pages %d-%d: %s", page_num, page_num + 4, nfc::format_bytes(data).c_str()); + ESP_LOGVV(TAG, "Data read: %s", nfc::format_bytes(data).c_str()); return true; } -bool PN532::is_mifare_ultralight_formatted_() { - std::vector data; - if (this->read_mifare_ultralight_page_(4, data)) { - return !(data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF); - } - return true; +bool PN532::is_mifare_ultralight_formatted_(const std::vector &page_3_to_6) { + const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector + + return (page_3_to_6.size() > p4_offset + 3) && + !((page_3_to_6[p4_offset + 0] == 0xFF) && (page_3_to_6[p4_offset + 1] == 0xFF) && + (page_3_to_6[p4_offset + 2] == 0xFF) && (page_3_to_6[p4_offset + 3] == 0xFF)); } uint16_t PN532::read_mifare_ultralight_capacity_() { std::vector data; - if (this->read_mifare_ultralight_page_(3, data)) { + if (this->read_mifare_ultralight_bytes_(3, nfc::MIFARE_ULTRALIGHT_PAGE_SIZE, data)) { + ESP_LOGV(TAG, "Tag capacity is %u bytes", data[2] * 8U); return data[2] * 8U; } return 0; } -bool PN532::find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index) { - std::vector data; - for (int page = 4; page < 6; page++) { - std::vector page_data; - if (!this->read_mifare_ultralight_page_(page, page_data)) { - return false; - } - data.insert(data.end(), page_data.begin(), page_data.end()); +bool PN532::find_mifare_ultralight_ndef_(const std::vector &page_3_to_6, uint8_t &message_length, + uint8_t &message_start_index) { + const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector + + if (!(page_3_to_6.size() > p4_offset + 5)) { + return false; } - if (data[0] == 0x03) { - message_length = data[1]; + + if (page_3_to_6[p4_offset + 0] == 0x03) { + message_length = page_3_to_6[p4_offset + 1]; message_start_index = 2; return true; - } else if (data[5] == 0x03) { - message_length = data[6]; + } else if (page_3_to_6[p4_offset + 5] == 0x03) { + message_length = page_3_to_6[p4_offset + 6]; message_start_index = 7; return true; } @@ -111,7 +122,7 @@ bool PN532::write_mifare_ultralight_tag_(std::vector &uid, nfc::NdefMes uint32_t buffer_length = nfc::get_mifare_ultralight_buffer_size(message_length); if (buffer_length > capacity) { - ESP_LOGE(TAG, "Message length exceeds tag capacity %d > %d", buffer_length, capacity); + ESP_LOGE(TAG, "Message length exceeds tag capacity %" PRIu32 " > %" PRIu32, buffer_length, capacity); return false; } @@ -164,13 +175,13 @@ bool PN532::write_mifare_ultralight_page_(uint8_t page_num, std::vector }); data.insert(data.end(), write_data.begin(), write_data.end()); if (!this->write_command_(data)) { - ESP_LOGE(TAG, "Error writing page %d", page_num); + ESP_LOGE(TAG, "Error writing page %u", page_num); return false; } std::vector response; if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) { - ESP_LOGE(TAG, "Error writing page %d", page_num); + ESP_LOGE(TAG, "Error writing page %u", page_num); return false; } From ce171f5c002c229cd207c0858881d5a79fd12689 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 7 Sep 2023 04:49:12 -0500 Subject: [PATCH 0452/2607] Fix cpu_ll_get_cycle_count() deprecated warning (#5353) --- esphome/components/esp32/core.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 16aa93c232..48c8b2b04d 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -53,7 +53,11 @@ void arch_init() { void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } +#if ESP_IDF_VERSION_MAJOR >= 5 +uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } +#else uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); } +#endif uint32_t arch_get_cpu_freq_hz() { return rtc_clk_apb_freq_get(); } #ifdef USE_ESP_IDF From 5c26f95a4be6948adb4fc35252f297a6b17af4a8 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 8 Sep 2023 17:27:19 +1000 Subject: [PATCH 0453/2607] Refactor SPI code; Add ESP-IDF hardware support (#5311) * Checkpoint * Checkpoint * Checkpoint * Revert hal change * Checkpoint * Checkpoint * Checkpoint * Checkpoint * ESP-IDF working * clang-format * use bus_list * Add spi_device; fix 16 bit transfer. * Enable multi_conf; Fix LSB 16 bit transactions * Formatting fixes * Clang-format, codeowners * Add test * Formatting * clang tidy * clang-format * clang-tidy * clang-format * Checkpoint * Checkpoint * Checkpoint * Revert hal change * Checkpoint * Checkpoint * Checkpoint * Checkpoint * ESP-IDF working * clang-format * use bus_list * Add spi_device; fix 16 bit transfer. * Enable multi_conf; Fix LSB 16 bit transactions * Formatting fixes * Clang-format, codeowners * Add test * Formatting * clang tidy * clang-format * clang-tidy * clang-format * Clang-tidy * Clang-format * clang-tidy * clang-tidy * Fix ESP8266 * RP2040 * RP2040 * Avoid use of spi1 as id * Refactor SPI code. Add support for ESP-IDF hardware SPI * Force SW only for RP2040 * Break up large transfers * Add interface: option for spi. validate pins in python. * Can't use match/case with Python 3.9. Check for inverted pins. * Work around target_platform issue with * Remove debug code * Optimize write_array16 * Show errors in hex * Only one spi on ESP32Cx variants * Ensure bus is claimed before asserting /CS. * Check on init/deinit * Allow maximum rate write only SPI on GPIO MUXed pins. * Clang-format * Clang-tidy * Fix issue with reads. * Finger trouble... * Make comment about missing SPI on Cx variants * Pacify CI clang-format. Did not complain locally?? * Restore 8266 to its former SPI glory * Fix per clang-format * Move validation and choice of SPI into Python code. * Add test for interface: config * Fix issues found on self-review. --------- Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/spi/__init__.py | 200 ++++++- esphome/components/spi/spi.cpp | 296 +++------- esphome/components/spi/spi.h | 567 +++++++++++-------- esphome/components/spi/spi_arduino.cpp | 89 +++ esphome/components/spi/spi_esp_idf.cpp | 163 ++++++ esphome/components/spi_device/__init__.py | 49 ++ esphome/components/spi_device/spi_device.cpp | 30 + esphome/components/spi_device/spi_device.h | 22 + tests/test4.yaml | 1 + tests/test8.yaml | 9 + 11 files changed, 954 insertions(+), 473 deletions(-) create mode 100644 esphome/components/spi/spi_arduino.cpp create mode 100644 esphome/components/spi/spi_esp_idf.cpp create mode 100644 esphome/components/spi_device/__init__.py create mode 100644 esphome/components/spi_device/spi_device.cpp create mode 100644 esphome/components/spi_device/spi_device.h diff --git a/CODEOWNERS b/CODEOWNERS index 498cfcac01..ab4c5011f6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -270,6 +270,7 @@ esphome/components/socket/* @esphome/core esphome/components/sonoff_d1/* @anatoly-savchenkov esphome/components/speaker/* @jesserockz esphome/components/spi/* @esphome/core +esphome/components/spi_device/* @clydebarrow esphome/components/sprinkler/* @kbx81 esphome/components/sps30/* @martgras esphome/components/ssd1322_base/* @kbx81 diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index a2ef956200..79e7a5b034 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -1,6 +1,17 @@ +import re + import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv +from esphome.components.esp32.const import ( + KEY_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, +) from esphome import pins from esphome.const import ( CONF_CLK_PIN, @@ -9,6 +20,11 @@ from esphome.const import ( CONF_MOSI_PIN, CONF_SPI_ID, CONF_CS_PIN, + CONF_NUMBER, + CONF_INVERTED, + KEY_CORE, + KEY_TARGET_PLATFORM, + KEY_VARIANT, ) from esphome.core import coroutine_with_priority, CORE @@ -34,10 +50,147 @@ SPI_DATA_RATE_OPTIONS = { } SPI_DATA_RATE_SCHEMA = cv.All(cv.frequency, cv.enum(SPI_DATA_RATE_OPTIONS)) -MULTI_CONF = True CONF_FORCE_SW = "force_sw" +CONF_INTERFACE = "interface" +CONF_INTERFACE_INDEX = "interface_index" -CONFIG_SCHEMA = cv.All( + +def get_target_platform(): + return ( + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] + if KEY_TARGET_PLATFORM in CORE.data[KEY_CORE] + else "" + ) + + +def get_target_variant(): + return ( + CORE.data[KEY_ESP32][KEY_VARIANT] if KEY_VARIANT in CORE.data[KEY_ESP32] else "" + ) + + +# Get a list of available hardware interfaces based on target and variant. +# The returned value is a list of lists of names +def get_hw_interface_list(): + target_platform = get_target_platform() + if target_platform == "esp8266": + return [["spi", "hspi"]] + if target_platform == "esp32": + if get_target_variant() in [ + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, + ]: + return [["spi", "spi2"]] + return [["spi", "spi2"], ["spi3"]] + if target_platform == "rp2040": + return [["spi"]] + return [] + + +# Given an SPI name, return the index of it in the available list +def get_spi_index(name): + for i, ilist in enumerate(get_hw_interface_list()): + if name in ilist: + return i + # Should never get to here. + raise cv.Invalid(f"{name} is not an available SPI") + + +# Check that pins are suitable for HW spi +# TODO verify that the pins are internal +def validate_hw_pins(spi): + clk_pin = spi[CONF_CLK_PIN] + if clk_pin[CONF_INVERTED]: + return False + clk_pin_no = clk_pin[CONF_NUMBER] + sdo_pin_no = -1 + sdi_pin_no = -1 + if CONF_MOSI_PIN in spi: + sdo_pin = spi[CONF_MOSI_PIN] + if sdo_pin[CONF_INVERTED]: + return False + sdo_pin_no = sdo_pin[CONF_NUMBER] + if CONF_MISO_PIN in spi: + sdi_pin = spi[CONF_MISO_PIN] + if sdi_pin[CONF_INVERTED]: + return False + sdi_pin_no = sdi_pin[CONF_NUMBER] + + target_platform = get_target_platform() + if target_platform == "esp8266": + if clk_pin_no == 6: + return sdo_pin_no in (-1, 8) and sdi_pin_no in (-1, 7) + if clk_pin_no == 14: + return sdo_pin_no in (-1, 13) and sdi_pin_no in (-1, 12) + return False + + if target_platform == "esp32": + return clk_pin_no >= 0 + + return False + + +def validate_spi_config(config): + available = list(range(len(get_hw_interface_list()))) + for spi in config: + interface = spi[CONF_INTERFACE] + if spi[CONF_FORCE_SW]: + if interface == "any": + spi[CONF_INTERFACE] = interface = "software" + elif interface != "software": + raise cv.Invalid("force_sw is deprecated - use interface: software") + if interface == "software": + pass + elif interface == "any": + if not validate_hw_pins(spi): + spi[CONF_INTERFACE] = "software" + elif interface == "hardware": + if len(available) == 0: + raise cv.Invalid("No hardware interface available") + index = spi[CONF_INTERFACE_INDEX] = available[0] + available.remove(index) + else: + # Must be a specific name + index = spi[CONF_INTERFACE_INDEX] = get_spi_index(interface) + if index not in available: + raise cv.Invalid( + f"interface '{interface}' not available here (may be already assigned)" + ) + available.remove(index) + + # Second time around: + # Any specific names and any 'hardware' requests will have already been filled, + # so just need to assign remaining hardware to 'any' requests. + for spi in config: + if spi[CONF_INTERFACE] == "any" and len(available) != 0: + index = available[0] + spi[CONF_INTERFACE_INDEX] = index + available.remove(index) + if CONF_INTERFACE_INDEX in spi and not validate_hw_pins(spi): + raise cv.Invalid("Invalid pin selections for hardware SPI interface") + + return config + + +# Given an SPI index, convert to a string that represents the C++ object for it. +def get_spi_interface(index): + if CORE.using_esp_idf: + return ["SPI2_HOST", "SPI3_HOST"][index] + # Arduino code follows + platform = get_target_platform() + if platform == "rp2040": + return "&spi1" + if index == 0: + return "&SPI" + # Following code can't apply to C2, H2 or 8266 since they have only one SPI + if get_target_variant() in (VARIANT_ESP32S3, VARIANT_ESP32S2): + return "new SPIClass(FSPI)" + return "return new SPIClass(HSPI)" + + +SPI_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(SPIComponent), @@ -45,28 +198,47 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_FORCE_SW, default=False): cv.boolean, + cv.Optional(CONF_INTERFACE, default="any"): cv.one_of( + *sum(get_hw_interface_list(), ["software", "hardware", "any"]), + lower=True, + ), } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), cv.only_on(["esp32", "esp8266", "rp2040"]), ) +CONFIG_SCHEMA = cv.All( + cv.ensure_list(SPI_SCHEMA), + validate_spi_config, +) + @coroutine_with_priority(1.0) -async def to_code(config): +async def to_code(configs): cg.add_global(spi_ns.using) - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) + for spi in configs: + var = cg.new_Pvariable(spi[CONF_ID]) + await cg.register_component(var, spi) - clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) - cg.add(var.set_clk(clk)) - cg.add(var.set_force_sw(config[CONF_FORCE_SW])) - if CONF_MISO_PIN in config: - miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN]) - cg.add(var.set_miso(miso)) - if CONF_MOSI_PIN in config: - mosi = await cg.gpio_pin_expression(config[CONF_MOSI_PIN]) - cg.add(var.set_mosi(mosi)) + clk = await cg.gpio_pin_expression(spi[CONF_CLK_PIN]) + cg.add(var.set_clk(clk)) + if CONF_MISO_PIN in spi: + miso = await cg.gpio_pin_expression(spi[CONF_MISO_PIN]) + cg.add(var.set_miso(miso)) + if CONF_MOSI_PIN in spi: + mosi = await cg.gpio_pin_expression(spi[CONF_MOSI_PIN]) + cg.add(var.set_mosi(mosi)) + if CONF_INTERFACE_INDEX in spi: + index = spi[CONF_INTERFACE_INDEX] + cg.add(var.set_interface(cg.RawExpression(get_spi_interface(index)))) + cg.add( + var.set_interface_name( + re.sub( + r"\W", "", get_spi_interface(index).replace("new SPIClass", "") + ) + ) + ) if CORE.using_arduino: cg.add_library("SPI", None) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 33630897f6..935399500f 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -1,268 +1,116 @@ #include "spi.h" #include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/application.h" namespace esphome { namespace spi { -static const char *const TAG = "spi"; +const char *const TAG = "spi"; -void IRAM_ATTR HOT SPIComponent::disable() { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - this->hw_spi_->endTransaction(); - } -#endif // USE_SPI_ARDUINO_BACKEND - if (this->active_cs_) { - this->active_cs_->digital_write(true); - this->active_cs_ = nullptr; +SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + new SPIDelegateDummy(); +// https://bugs.llvm.org/show_bug.cgi?id=48040 + +bool SPIDelegate::is_ready() { return true; } + +GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +SPIDelegate *SPIComponent::register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, + GPIOPin *cs_pin) { + if (this->devices_.count(device) != 0) { + ESP_LOGE(TAG, "SPI device already registered"); + return this->devices_[device]; } + SPIDelegate *delegate = this->spi_bus_->get_delegate(data_rate, bit_order, mode, cs_pin); // NOLINT + this->devices_[device] = delegate; + return delegate; } + +void SPIComponent::unregister_device(SPIClient *device) { + if (this->devices_.count(device) == 0) { + esph_log_e(TAG, "SPI device not registered"); + return; + } + delete this->devices_[device]; // NOLINT + this->devices_.erase(device); +} + void SPIComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up SPI bus..."); - this->clk_->setup(); - this->clk_->digital_write(true); + ESP_LOGD(TAG, "Setting up SPI bus..."); -#ifdef USE_SPI_ARDUINO_BACKEND - bool use_hw_spi = !this->force_sw_; - const bool has_miso = this->miso_ != nullptr; - const bool has_mosi = this->mosi_ != nullptr; - int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1; - - if (!this->clk_->is_internal()) - use_hw_spi = false; - if (has_miso && !miso_->is_internal()) - use_hw_spi = false; - if (has_mosi && !mosi_->is_internal()) - use_hw_spi = false; - if (use_hw_spi) { - auto *clk_internal = (InternalGPIOPin *) clk_; - auto *miso_internal = (InternalGPIOPin *) miso_; - auto *mosi_internal = (InternalGPIOPin *) mosi_; - - if (clk_internal->is_inverted()) - use_hw_spi = false; - if (has_miso && miso_internal->is_inverted()) - use_hw_spi = false; - if (has_mosi && mosi_internal->is_inverted()) - use_hw_spi = false; - - if (use_hw_spi) { - clk_pin = clk_internal->get_pin(); - miso_pin = has_miso ? miso_internal->get_pin() : -1; - mosi_pin = has_mosi ? mosi_internal->get_pin() : -1; - } - } -#ifdef USE_ESP8266 - if (!(clk_pin == 6 && miso_pin == 7 && mosi_pin == 8) && - !(clk_pin == 14 && (!has_miso || miso_pin == 12) && (!has_mosi || mosi_pin == 13))) - use_hw_spi = false; - - if (use_hw_spi) { - this->hw_spi_ = &SPI; - this->hw_spi_->pins(clk_pin, miso_pin, mosi_pin, 0); - this->hw_spi_->begin(); + if (this->sdo_pin_ == nullptr) + this->sdo_pin_ = NullPin::NULL_PIN; + if (this->sdi_pin_ == nullptr) + this->sdi_pin_ = NullPin::NULL_PIN; + if (this->clk_pin_ == nullptr) { + ESP_LOGE(TAG, "No clock pin for SPI"); + this->mark_failed(); return; } -#endif // USE_ESP8266 -#ifdef USE_ESP32 - static uint8_t spi_bus_num = 0; - if (spi_bus_num >= 2) { - use_hw_spi = false; - } - if (use_hw_spi) { - if (spi_bus_num == 0) { - this->hw_spi_ = &SPI; - } else { -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ - defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C6) - this->hw_spi_ = new SPIClass(FSPI); // NOLINT(cppcoreguidelines-owning-memory) -#else - this->hw_spi_ = new SPIClass(HSPI); // NOLINT(cppcoreguidelines-owning-memory) -#endif // USE_ESP32_VARIANT + if (this->using_hw_) { + this->spi_bus_ = SPIComponent::get_bus(this->interface_, this->clk_pin_, this->sdo_pin_, this->sdi_pin_); + if (this->spi_bus_ == nullptr) { + ESP_LOGE(TAG, "Unable to allocate SPI interface"); + this->mark_failed(); } - spi_bus_num++; - this->hw_spi_->begin(clk_pin, miso_pin, mosi_pin); - return; - } -#endif // USE_ESP32 -#ifdef USE_RP2040 - static uint8_t spi_bus_num = 0; - if (spi_bus_num >= 2) { - use_hw_spi = false; - } - if (use_hw_spi) { - SPIClassRP2040 *spi; - if (spi_bus_num == 0) { - spi = &SPI; - } else { - spi = &SPI1; - } - spi_bus_num++; - - if (miso_pin != -1) - spi->setRX(miso_pin); - if (mosi_pin != -1) - spi->setTX(mosi_pin); - spi->setSCK(clk_pin); - this->hw_spi_ = spi; - this->hw_spi_->begin(); - return; - } -#endif // USE_RP2040 -#endif // USE_SPI_ARDUINO_BACKEND - - if (this->miso_ != nullptr) { - this->miso_->setup(); - } - if (this->mosi_ != nullptr) { - this->mosi_->setup(); - this->mosi_->digital_write(false); + } else { + this->spi_bus_ = new SPIBus(this->clk_pin_, this->sdo_pin_, this->sdi_pin_); // NOLINT + this->clk_pin_->setup(); + this->clk_pin_->digital_write(true); + this->sdo_pin_->setup(); + this->sdi_pin_->setup(); } } + void SPIComponent::dump_config() { ESP_LOGCONFIG(TAG, "SPI bus:"); - LOG_PIN(" CLK Pin: ", this->clk_); - LOG_PIN(" MISO Pin: ", this->miso_); - LOG_PIN(" MOSI Pin: ", this->mosi_); -#ifdef USE_SPI_ARDUINO_BACKEND - ESP_LOGCONFIG(TAG, " Using HW SPI: %s", YESNO(this->hw_spi_ != nullptr)); -#endif // USE_SPI_ARDUINO_BACKEND -} -float SPIComponent::get_setup_priority() const { return setup_priority::BUS; } - -void SPIComponent::cycle_clock_(bool value) { - uint32_t start = arch_get_cpu_cycle_count(); - while (start - arch_get_cpu_cycle_count() < this->wait_cycle_) - ; - this->clk_->digital_write(value); - start += this->wait_cycle_; - while (start - arch_get_cpu_cycle_count() < this->wait_cycle_) - ; + LOG_PIN(" CLK Pin: ", this->clk_pin_) + LOG_PIN(" SDI Pin: ", this->sdi_pin_) + LOG_PIN(" SDO Pin: ", this->sdo_pin_) + if (this->spi_bus_->is_hw()) { + ESP_LOGCONFIG(TAG, " Using HW SPI: %s", this->interface_name_); + } else { + ESP_LOGCONFIG(TAG, " Using software SPI"); + } } -// NOLINTNEXTLINE -#ifndef CLANG_TIDY -#pragma GCC optimize("unroll-loops") -// NOLINTNEXTLINE -#pragma GCC optimize("O2") -#endif // CLANG_TIDY +void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); } -template -uint8_t HOT SPIComponent::transfer_(uint8_t data) { +uint8_t SPIDelegateBitBash::transfer(uint8_t data) { // Clock starts out at idle level - this->clk_->digital_write(CLOCK_POLARITY); + this->clk_pin_->digital_write(clock_polarity_); uint8_t out_data = 0; for (uint8_t i = 0; i < 8; i++) { uint8_t shift; - if (BIT_ORDER == BIT_ORDER_MSB_FIRST) { + if (bit_order_ == BIT_ORDER_MSB_FIRST) { shift = 7 - i; } else { shift = i; } - if (CLOCK_PHASE == CLOCK_PHASE_LEADING) { + if (clock_phase_ == CLOCK_PHASE_LEADING) { // sampling on leading edge - if (WRITE) { - this->mosi_->digital_write(data & (1 << shift)); - } - - // SAMPLE! - this->cycle_clock_(!CLOCK_POLARITY); - - if (READ) { - out_data |= uint8_t(this->miso_->digital_read()) << shift; - } - - this->cycle_clock_(CLOCK_POLARITY); + this->sdo_pin_->digital_write(data & (1 << shift)); + this->cycle_clock_(); + out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift; + this->clk_pin_->digital_write(!this->clock_polarity_); + this->cycle_clock_(); + this->clk_pin_->digital_write(this->clock_polarity_); } else { // sampling on trailing edge - this->cycle_clock_(!CLOCK_POLARITY); - - if (WRITE) { - this->mosi_->digital_write(data & (1 << shift)); - } - - // SAMPLE! - this->cycle_clock_(CLOCK_POLARITY); - - if (READ) { - out_data |= uint8_t(this->miso_->digital_read()) << shift; - } + this->cycle_clock_(); + this->clk_pin_->digital_write(!this->clock_polarity_); + this->sdo_pin_->digital_write(data & (1 << shift)); + this->cycle_clock_(); + out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift; + this->clk_pin_->digital_write(this->clock_polarity_); } } - App.feed_wdt(); - return out_data; } -// Generate with (py3): -// -// from itertools import product -// bit_orders = ['BIT_ORDER_LSB_FIRST', 'BIT_ORDER_MSB_FIRST'] -// clock_pols = ['CLOCK_POLARITY_LOW', 'CLOCK_POLARITY_HIGH'] -// clock_phases = ['CLOCK_PHASE_LEADING', 'CLOCK_PHASE_TRAILING'] -// reads = [False, True] -// writes = [False, True] -// cpp_bool = {False: 'false', True: 'true'} -// for b, cpol, cph, r, w in product(bit_orders, clock_pols, clock_phases, reads, writes): -// if not r and not w: -// continue -// print(f"template uint8_t SPIComponent::transfer_<{b}, {cpol}, {cph}, {cpp_bool[r]}, {cpp_bool[w]}>(uint8_t -// data);") - -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); -template uint8_t SPIComponent::transfer_( - uint8_t data); - } // namespace spi } // namespace esphome diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 159d117533..2761c2d604 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -2,16 +2,34 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" #include +#include #ifdef USE_ARDUINO -#define USE_SPI_ARDUINO_BACKEND -#endif -#ifdef USE_SPI_ARDUINO_BACKEND #include + +#ifdef USE_RP2040 +using SPIInterface = SPIClassRP2040 *; +#else +using SPIInterface = SPIClass *; #endif +#endif + +#ifdef USE_ESP_IDF + +#include "driver/spi_master.h" + +using SPIInterface = spi_host_device_t; + +#endif // USE_ESP_IDF + +/** + * Implementation of SPI Controller mode. + */ namespace esphome { namespace spi { @@ -48,10 +66,19 @@ enum SPIClockPhase { /// The data is sampled on a trailing clock edge. (CPHA=1) CLOCK_PHASE_TRAILING, }; -/** The SPI clock signal data rate. This defines for what duration the clock signal is HIGH/LOW. - * So effectively the rate of bytes can be calculated using + +/** + * Modes mapping to clock phase and polarity. * - * effective_byte_rate = spi_data_rate / 16 + */ + +enum SPIMode { + MODE0 = 0, + MODE1 = 1, + MODE2 = 2, + MODE3 = 3, +}; +/** The SPI clock signal frequency, which determines the transfer bit rate/second. * * Implementations can use the pre-defined constants here, or use an integer in the template definition * to manually use a specific data rate. @@ -71,270 +98,340 @@ enum SPIDataRate : uint32_t { DATA_RATE_80MHZ = 80000000, }; -class SPIComponent : public Component { +/** + * A pin to replace those that don't exist. + */ +class NullPin : public GPIOPin { + friend class SPIComponent; + + friend class SPIDelegate; + + friend class Utility; + public: - void set_clk(GPIOPin *clk) { clk_ = clk; } - void set_miso(GPIOPin *miso) { miso_ = miso; } - void set_mosi(GPIOPin *mosi) { mosi_ = mosi; } - void set_force_sw(bool force_sw) { force_sw_ = force_sw; } + void setup() override {} - void setup() override; + void pin_mode(gpio::Flags flags) override {} - void dump_config() override; + bool digital_read() override { return false; } - template uint8_t read_byte() { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - return this->hw_spi_->transfer(0x00); - } -#endif // USE_SPI_ARDUINO_BACKEND - return this->transfer_(0x00); - } + void digital_write(bool value) override {} - template - void read_array(uint8_t *data, size_t length) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - this->hw_spi_->transfer(data, length); - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - for (size_t i = 0; i < length; i++) { - data[i] = this->read_byte(); - } - } - - template - void write_byte(uint8_t data) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { -#ifdef USE_RP2040 - this->hw_spi_->transfer(data); -#else - this->hw_spi_->write(data); -#endif - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - this->transfer_(data); - } - - template - void write_byte16(const uint16_t data) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { -#ifdef USE_RP2040 - this->hw_spi_->transfer16(data); -#else - this->hw_spi_->write16(data); -#endif - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - - this->write_byte(data >> 8); - this->write_byte(data); - } - - template - void write_array16(const uint16_t *data, size_t length) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - for (size_t i = 0; i < length; i++) { -#ifdef USE_RP2040 - this->hw_spi_->transfer16(data[i]); -#else - this->hw_spi_->write16(data[i]); -#endif - } - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - for (size_t i = 0; i < length; i++) { - this->write_byte16(data[i]); - } - } - - template - void write_array(const uint8_t *data, size_t length) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - auto *data_c = const_cast(data); -#ifdef USE_RP2040 - this->hw_spi_->transfer(data_c, length); -#else - this->hw_spi_->writeBytes(data_c, length); -#endif - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - for (size_t i = 0; i < length; i++) { - this->write_byte(data[i]); - } - } - - template - uint8_t transfer_byte(uint8_t data) { - if (this->miso_ != nullptr) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - return this->hw_spi_->transfer(data); - } else { -#endif // USE_SPI_ARDUINO_BACKEND - return this->transfer_(data); -#ifdef USE_SPI_ARDUINO_BACKEND - } -#endif // USE_SPI_ARDUINO_BACKEND - } - this->write_byte(data); - return 0; - } - - template - void transfer_array(uint8_t *data, size_t length) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - if (this->miso_ != nullptr) { - this->hw_spi_->transfer(data, length); - } else { -#ifdef USE_RP2040 - this->hw_spi_->transfer(data, length); -#else - this->hw_spi_->writeBytes(data, length); -#endif - } - return; - } -#endif // USE_SPI_ARDUINO_BACKEND - - if (this->miso_ != nullptr) { - for (size_t i = 0; i < length; i++) { - data[i] = this->transfer_byte(data[i]); - } - } else { - this->write_array(data, length); - } - } - - template - void enable(GPIOPin *cs) { -#ifdef USE_SPI_ARDUINO_BACKEND - if (this->hw_spi_ != nullptr) { - uint8_t data_mode = SPI_MODE0; - if (!CLOCK_POLARITY && CLOCK_PHASE) { - data_mode = SPI_MODE1; - } else if (CLOCK_POLARITY && !CLOCK_PHASE) { - data_mode = SPI_MODE2; - } else if (CLOCK_POLARITY && CLOCK_PHASE) { - data_mode = SPI_MODE3; - } -#ifdef USE_RP2040 - SPISettings settings(DATA_RATE, static_cast(BIT_ORDER), data_mode); -#else - SPISettings settings(DATA_RATE, BIT_ORDER, data_mode); -#endif - this->hw_spi_->beginTransaction(settings); - } else { -#endif // USE_SPI_ARDUINO_BACKEND - this->clk_->digital_write(CLOCK_POLARITY); - uint32_t cpu_freq_hz = arch_get_cpu_freq_hz(); - this->wait_cycle_ = uint32_t(cpu_freq_hz) / DATA_RATE / 2ULL; -#ifdef USE_SPI_ARDUINO_BACKEND - } -#endif // USE_SPI_ARDUINO_BACKEND - - if (cs != nullptr) { - this->active_cs_ = cs; - this->active_cs_->digital_write(false); - } - } - - void disable(); - - float get_setup_priority() const override; + std::string dump_summary() const override { return std::string(); } protected: - inline void cycle_clock_(bool value); - - template - uint8_t transfer_(uint8_t data); - - GPIOPin *clk_; - GPIOPin *miso_{nullptr}; - GPIOPin *mosi_{nullptr}; - GPIOPin *active_cs_{nullptr}; - bool force_sw_{false}; -#ifdef USE_SPI_ARDUINO_BACKEND - SPIClass *hw_spi_{nullptr}; -#endif // USE_SPI_ARDUINO_BACKEND - uint32_t wait_cycle_; + static GPIOPin *const NULL_PIN; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + // https://bugs.llvm.org/show_bug.cgi?id=48040 }; -template -class SPIDevice { +class Utility { public: - SPIDevice() = default; - SPIDevice(SPIComponent *parent, GPIOPin *cs) : parent_(parent), cs_(cs) {} + static int get_pin_no(GPIOPin *pin) { + if (pin == nullptr || !pin->is_internal()) + return -1; + if (((InternalGPIOPin *) pin)->is_inverted()) + return -1; + return ((InternalGPIOPin *) pin)->get_pin(); + } - void set_spi_parent(SPIComponent *parent) { parent_ = parent; } - void set_cs_pin(GPIOPin *cs) { cs_ = cs; } + static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase) { + if (polarity == CLOCK_POLARITY_HIGH) { + return phase == CLOCK_PHASE_LEADING ? MODE2 : MODE3; + } + return phase == CLOCK_PHASE_LEADING ? MODE0 : MODE1; + } - void spi_setup() { - if (this->cs_) { - this->cs_->setup(); - this->cs_->digital_write(true); + static SPIClockPhase get_phase(SPIMode mode) { + switch (mode) { + case MODE0: + case MODE2: + return CLOCK_PHASE_LEADING; + default: + return CLOCK_PHASE_TRAILING; } } - void enable() { this->parent_->template enable(this->cs_); } + static SPIClockPolarity get_polarity(SPIMode mode) { + switch (mode) { + case MODE0: + case MODE1: + return CLOCK_POLARITY_LOW; + default: + return CLOCK_POLARITY_HIGH; + } + } +}; - void disable() { this->parent_->disable(); } +class SPIDelegateDummy; - uint8_t read_byte() { return this->parent_->template read_byte(); } +// represents a device attached to an SPI bus, with a defined clock rate, mode and bit order. On Arduino this is +// a thin wrapper over SPIClass. +class SPIDelegate { + friend class SPIClient; - void read_array(uint8_t *data, size_t length) { - return this->parent_->template read_array(data, length); + public: + SPIDelegate() = default; + + SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) + : bit_order_(bit_order), data_rate_(data_rate), mode_(mode), cs_pin_(cs_pin) { + if (this->cs_pin_ == nullptr) + this->cs_pin_ = NullPin::NULL_PIN; + this->cs_pin_->setup(); + this->cs_pin_->digital_write(true); } - template std::array read_array() { - std::array data; - this->read_array(data.data(), N); - return data; + virtual ~SPIDelegate(){}; + + // enable CS if configured. + virtual void begin_transaction() { this->cs_pin_->digital_write(false); } + + // end the transaction + virtual void end_transaction() { this->cs_pin_->digital_write(true); } + + // transfer one byte, return the byte that was read. + virtual uint8_t transfer(uint8_t data) = 0; + + // transfer a buffer, replace the contents with read data + virtual void transfer(uint8_t *ptr, size_t length) { this->transfer(ptr, ptr, length); } + + virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length) { + for (size_t i = 0; i != length; i++) + rxbuf[i] = this->transfer(txbuf[i]); } - void write_byte(uint8_t data) { - return this->parent_->template write_byte(data); + // write 16 bits + virtual void write16(uint16_t data) { + if (this->bit_order_ == BIT_ORDER_MSB_FIRST) { + uint16_t buffer; + buffer = (data >> 8) | (data << 8); + this->write_array(reinterpret_cast(&buffer), 2); + } else { + this->write_array(reinterpret_cast(&data), 2); + } } - void write_byte16(uint16_t data) { - return this->parent_->template write_byte16(data); + virtual void write_array16(const uint16_t *data, size_t length) { + for (size_t i = 0; i != length; i++) { + this->write16(data[i]); + } } - void write_array16(const uint16_t *data, size_t length) { - this->parent_->template write_array16(data, length); + // write the contents of a buffer, ignore read data (buffer is unchanged.) + virtual void write_array(const uint8_t *ptr, size_t length) { + for (size_t i = 0; i != length; i++) + this->transfer(ptr[i]); } - void write_array(const uint8_t *data, size_t length) { - this->parent_->template write_array(data, length); + // read into a buffer, write nulls + virtual void read_array(uint8_t *ptr, size_t length) { + for (size_t i = 0; i != length; i++) + ptr[i] = this->transfer(0); } + // check if device is ready + virtual bool is_ready(); + + protected: + SPIBitOrder bit_order_{BIT_ORDER_MSB_FIRST}; + uint32_t data_rate_{1000000}; + SPIMode mode_{MODE0}; + GPIOPin *cs_pin_{NullPin::NULL_PIN}; + static SPIDelegate *const NULL_DELEGATE; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +}; + +/** + * A dummy SPIDelegate that complains if it's used. + */ + +class SPIDelegateDummy : public SPIDelegate { + public: + SPIDelegateDummy() = default; + + uint8_t transfer(uint8_t data) override { return 0; } + + void begin_transaction() override; +}; + +/** + * An implementation of SPI that relies only on software toggling of pins. + * + */ +class SPIDelegateBitBash : public SPIDelegate { + public: + SPIDelegateBitBash(uint32_t clock, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, GPIOPin *clk_pin, + GPIOPin *sdo_pin, GPIOPin *sdi_pin) + : SPIDelegate(clock, bit_order, mode, cs_pin), clk_pin_(clk_pin), sdo_pin_(sdo_pin), sdi_pin_(sdi_pin) { + // this calculation is pretty meaningless except at very low bit rates. + this->wait_cycle_ = uint32_t(arch_get_cpu_freq_hz()) / this->data_rate_ / 2ULL; + this->clock_polarity_ = Utility::get_polarity(this->mode_); + this->clock_phase_ = Utility::get_phase(this->mode_); + } + + uint8_t transfer(uint8_t data) override; + + protected: + GPIOPin *clk_pin_; + GPIOPin *sdo_pin_; + GPIOPin *sdi_pin_; + uint32_t last_transition_{0}; + uint32_t wait_cycle_; + SPIClockPolarity clock_polarity_; + SPIClockPhase clock_phase_; + + void HOT cycle_clock_() { + while (this->last_transition_ - arch_get_cpu_cycle_count() < this->wait_cycle_) + continue; + this->last_transition_ += this->wait_cycle_; + } +}; + +class SPIBus { + public: + SPIBus() = default; + + SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi) : clk_pin_(clk), sdo_pin_(sdo), sdi_pin_(sdi) {} + + virtual SPIDelegate *get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) { + return new SPIDelegateBitBash(data_rate, bit_order, mode, cs_pin, this->clk_pin_, this->sdo_pin_, this->sdi_pin_); + } + + virtual bool is_hw() { return false; } + + protected: + GPIOPin *clk_pin_{}; + GPIOPin *sdo_pin_{}; + GPIOPin *sdi_pin_{}; +}; + +class SPIClient; + +class SPIComponent : public Component { + public: + SPIDelegate *register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, + GPIOPin *cs_pin); + void unregister_device(SPIClient *device); + + void set_clk(GPIOPin *clk) { this->clk_pin_ = clk; } + + void set_miso(GPIOPin *sdi) { this->sdi_pin_ = sdi; } + + void set_mosi(GPIOPin *sdo) { this->sdo_pin_ = sdo; } + + void set_interface(SPIInterface interface) { + this->interface_ = interface; + this->using_hw_ = true; + } + + void set_interface_name(const char *name) { this->interface_name_ = name; } + + float get_setup_priority() const override { return setup_priority::BUS; } + + void setup() override; + void dump_config() override; + + protected: + GPIOPin *clk_pin_{nullptr}; + GPIOPin *sdi_pin_{nullptr}; + GPIOPin *sdo_pin_{nullptr}; + SPIInterface interface_{}; + bool using_hw_{false}; + const char *interface_name_{nullptr}; + SPIBus *spi_bus_{}; + std::map devices_; + + static SPIBus *get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi); +}; + +/** + * Base class for SPIDevice, un-templated. + */ +class SPIClient { + public: + SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate) + : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {} + + virtual void spi_setup() { + this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_); + } + + virtual void spi_teardown() { + this->parent_->unregister_device(this); + this->delegate_ = SPIDelegate::NULL_DELEGATE; + } + + bool spi_is_ready() { return this->delegate_->is_ready(); } + + protected: + SPIBitOrder bit_order_{BIT_ORDER_MSB_FIRST}; + SPIMode mode_{MODE0}; + uint32_t data_rate_{1000000}; + SPIComponent *parent_{nullptr}; + GPIOPin *cs_{nullptr}; + SPIDelegate *delegate_{SPIDelegate::NULL_DELEGATE}; +}; + +/** + * The SPIDevice is what components using the SPI will create. + * + * @tparam BIT_ORDER + * @tparam CLOCK_POLARITY + * @tparam CLOCK_PHASE + * @tparam DATA_RATE + */ +template +class SPIDevice : public SPIClient { + public: + SPIDevice() : SPIClient(BIT_ORDER, Utility::get_mode(CLOCK_POLARITY, CLOCK_PHASE), DATA_RATE) {} + + SPIDevice(SPIComponent *parent, GPIOPin *cs_pin) { + this->set_spi_parent(parent); + this->set_cs_pin(cs_pin); + } + + void spi_setup() override { SPIClient::spi_setup(); } + + void spi_teardown() override { SPIClient::spi_teardown(); } + + void set_spi_parent(SPIComponent *parent) { this->parent_ = parent; } + + void set_cs_pin(GPIOPin *cs) { this->cs_ = cs; } + + void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; } + + void set_bit_order(SPIBitOrder order) { + this->bit_order_ = order; + esph_log_d("spi.h", "bit order set to %d", order); + } + + void set_mode(SPIMode mode) { this->mode_ = mode; } + + uint8_t read_byte() { return this->delegate_->transfer(0); } + + void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); } + + void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); } + + void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); } + + uint8_t transfer_byte(uint8_t data) { return this->delegate_->transfer(data); } + + // the driver will byte-swap if required. + void write_byte16(uint16_t data) { this->delegate_->write16(data); } + + // avoid use of this if possible. It's inefficient and ugly. + void write_array16(const uint16_t *data, size_t length) { this->delegate_->write_array16(data, length); } + + void enable() { this->delegate_->begin_transaction(); } + + void disable() { this->delegate_->end_transaction(); } + + void write_array(const uint8_t *data, size_t length) { this->delegate_->write_array(data, length); } + template void write_array(const std::array &data) { this->write_array(data.data(), N); } void write_array(const std::vector &data) { this->write_array(data.data(), data.size()); } - uint8_t transfer_byte(uint8_t data) { - return this->parent_->template transfer_byte(data); - } - - void transfer_array(uint8_t *data, size_t length) { - this->parent_->template transfer_array(data, length); - } - template void transfer_array(std::array &data) { this->transfer_array(data.data(), N); } - - protected: - SPIComponent *parent_{nullptr}; - GPIOPin *cs_{nullptr}; }; } // namespace spi diff --git a/esphome/components/spi/spi_arduino.cpp b/esphome/components/spi/spi_arduino.cpp new file mode 100644 index 0000000000..40ed9e6062 --- /dev/null +++ b/esphome/components/spi/spi_arduino.cpp @@ -0,0 +1,89 @@ +#include "spi.h" +#include + +namespace esphome { +namespace spi { + +#ifdef USE_ARDUINO + +static const char *const TAG = "spi-esp-arduino"; +class SPIDelegateHw : public SPIDelegate { + public: + SPIDelegateHw(SPIInterface channel, uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) + : SPIDelegate(data_rate, bit_order, mode, cs_pin), channel_(channel) {} + + void begin_transaction() override { +#ifdef USE_RP2040 + SPISettings const settings(this->data_rate_, static_cast(this->bit_order_), this->mode_); +#else + SPISettings const settings(this->data_rate_, this->bit_order_, this->mode_); +#endif + this->channel_->beginTransaction(settings); + SPIDelegate::begin_transaction(); + } + + void transfer(uint8_t *ptr, size_t length) override { this->channel_->transfer(ptr, length); } + + void end_transaction() override { + this->channel_->endTransaction(); + SPIDelegate::end_transaction(); + } + + uint8_t transfer(uint8_t data) override { return this->channel_->transfer(data); } + + void write16(uint16_t data) override { this->channel_->transfer16(data); } + +#ifdef USE_RP2040 + void write_array(const uint8_t *ptr, size_t length) override { + // avoid overwriting the supplied buffer + uint8_t *rxbuf = new uint8_t[length]; // NOLINT(cppcoreguidelines-owning-memory) + memcpy(rxbuf, ptr, length); + this->channel_->transfer((void *) rxbuf, length); + delete[] rxbuf; // NOLINT(cppcoreguidelines-owning-memory) + } +#else + void write_array(const uint8_t *ptr, size_t length) override { this->channel_->writeBytes(ptr, length); } +#endif + + void read_array(uint8_t *ptr, size_t length) override { this->channel_->transfer(ptr, length); } + + protected: + SPIInterface channel_{}; +}; + +class SPIBusHw : public SPIBus { + public: + SPIBusHw(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, SPIInterface channel) : SPIBus(clk, sdo, sdi), channel_(channel) { +#ifdef USE_ESP8266 + channel->pins(Utility::get_pin_no(clk), Utility::get_pin_no(sdi), Utility::get_pin_no(sdo), -1); + channel->begin(); +#endif // USE_ESP8266 +#ifdef USE_ESP32 + channel->begin(Utility::get_pin_no(clk), Utility::get_pin_no(sdi), Utility::get_pin_no(sdo), -1); +#endif +#ifdef USE_RP2040 + if (Utility::get_pin_no(sdi) != -1) + channel->setRX(Utility::get_pin_no(sdi)); + if (Utility::get_pin_no(sdo) != -1) + channel->setTX(Utility::get_pin_no(sdo)); + channel->setSCK(Utility::get_pin_no(clk)); + channel->begin(); +#endif + } + + SPIDelegate *get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) override { + return new SPIDelegateHw(this->channel_, data_rate, bit_order, mode, cs_pin); + } + + protected: + SPIInterface channel_{}; + bool is_hw() override { return true; } +}; + +SPIBus *SPIComponent::get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi) { + return new SPIBusHw(clk, sdo, sdi, interface); +} + +#endif // USE_ARDUINO +} // namespace spi +} // namespace esphome diff --git a/esphome/components/spi/spi_esp_idf.cpp b/esphome/components/spi/spi_esp_idf.cpp new file mode 100644 index 0000000000..f9e4bfcca6 --- /dev/null +++ b/esphome/components/spi/spi_esp_idf.cpp @@ -0,0 +1,163 @@ +#include "spi.h" +#include + +namespace esphome { +namespace spi { + +#ifdef USE_ESP_IDF +static const char *const TAG = "spi-esp-idf"; +static const size_t MAX_TRANSFER_SIZE = 4092; // dictated by ESP-IDF API. + +class SPIDelegateHw : public SPIDelegate { + public: + SPIDelegateHw(SPIInterface channel, uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, + bool write_only) + : SPIDelegate(data_rate, bit_order, mode, cs_pin), channel_(channel), write_only_(write_only) { + spi_device_interface_config_t config = {}; + config.mode = static_cast(mode); + config.clock_speed_hz = static_cast(data_rate); + config.spics_io_num = -1; + config.flags = 0; + config.queue_size = 1; + config.pre_cb = nullptr; + config.post_cb = nullptr; + if (bit_order == BIT_ORDER_LSB_FIRST) + config.flags |= SPI_DEVICE_BIT_LSBFIRST; + if (write_only) + config.flags |= SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_NO_DUMMY; + esp_err_t const err = spi_bus_add_device(channel, &config, &this->handle_); + if (err != ESP_OK) + ESP_LOGE(TAG, "Add device failed - err %X", err); + } + + bool is_ready() override { return this->handle_ != nullptr; } + + void begin_transaction() override { + if (this->is_ready()) { + if (spi_device_acquire_bus(this->handle_, portMAX_DELAY) != ESP_OK) + ESP_LOGE(TAG, "Failed to acquire SPI bus"); + SPIDelegate::begin_transaction(); + } else { + ESP_LOGW(TAG, "spi_setup called before initialisation"); + } + } + + void end_transaction() override { + if (this->is_ready()) { + SPIDelegate::end_transaction(); + spi_device_release_bus(this->handle_); + } + } + + ~SPIDelegateHw() override { + esp_err_t const err = spi_bus_remove_device(this->handle_); + if (err != ESP_OK) + ESP_LOGE(TAG, "Remove device failed - err %X", err); + } + + // do a transfer. either txbuf or rxbuf (but not both) may be null. + // transfers above the maximum size will be split. + // TODO - make use of the queue for interrupt transfers to provide a (short) pipeline of blocks + // when splitting is required. + void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length) override { + if (rxbuf != nullptr && this->write_only_) { + ESP_LOGE(TAG, "Attempted read from write-only channel"); + return; + } + spi_transaction_t desc = {}; + desc.flags = 0; + while (length != 0) { + size_t const partial = std::min(length, MAX_TRANSFER_SIZE); + desc.length = partial * 8; + desc.rxlength = this->write_only_ ? 0 : partial * 8; + desc.tx_buffer = txbuf; + desc.rx_buffer = rxbuf; + esp_err_t const err = spi_device_transmit(this->handle_, &desc); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Transmit failed - err %X", err); + break; + } + length -= partial; + if (txbuf != nullptr) + txbuf += partial; + if (rxbuf != nullptr) + rxbuf += partial; + } + } + + void transfer(uint8_t *ptr, size_t length) override { this->transfer(ptr, ptr, length); } + + uint8_t transfer(uint8_t data) override { + uint8_t rxbuf; + this->transfer(&data, &rxbuf, 1); + return rxbuf; + } + + void write16(uint16_t data) override { + if (this->bit_order_ == BIT_ORDER_MSB_FIRST) { + uint16_t txbuf = SPI_SWAP_DATA_TX(data, 16); + this->transfer((uint8_t *) &txbuf, nullptr, 2); + } else { + this->transfer((uint8_t *) &data, nullptr, 2); + } + } + + void write_array(const uint8_t *ptr, size_t length) override { this->transfer(ptr, nullptr, length); } + + void write_array16(const uint16_t *data, size_t length) override { + if (this->bit_order_ == BIT_ORDER_LSB_FIRST) { + this->write_array((uint8_t *) data, length * 2); + } else { + uint16_t buffer[MAX_TRANSFER_SIZE / 2]; + while (length != 0) { + size_t const partial = std::min(length, MAX_TRANSFER_SIZE / 2); + for (size_t i = 0; i != partial; i++) { + buffer[i] = SPI_SWAP_DATA_TX(*data++, 16); + } + this->write_array((const uint8_t *) buffer, partial * 2); + length -= partial; + } + } + } + + void read_array(uint8_t *ptr, size_t length) override { this->transfer(nullptr, ptr, length); } + + protected: + SPIInterface channel_{}; + spi_device_handle_t handle_{}; + bool write_only_{false}; +}; + +class SPIBusHw : public SPIBus { + public: + SPIBusHw(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, SPIInterface channel) : SPIBus(clk, sdo, sdi), channel_(channel) { + spi_bus_config_t buscfg = {}; + buscfg.mosi_io_num = Utility::get_pin_no(sdo); + buscfg.miso_io_num = Utility::get_pin_no(sdi); + buscfg.sclk_io_num = Utility::get_pin_no(clk); + buscfg.quadwp_io_num = -1; + buscfg.quadhd_io_num = -1; + buscfg.max_transfer_sz = MAX_TRANSFER_SIZE; + auto err = spi_bus_initialize(channel, &buscfg, SPI_DMA_CH_AUTO); + if (err != ESP_OK) + ESP_LOGE(TAG, "Bus init failed - err %X", err); + } + + SPIDelegate *get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) override { + return new SPIDelegateHw(this->channel_, data_rate, bit_order, mode, cs_pin, + Utility::get_pin_no(this->sdi_pin_) == -1); + } + + protected: + SPIInterface channel_{}; + + bool is_hw() override { return true; } +}; + +SPIBus *SPIComponent::get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi) { + return new SPIBusHw(clk, sdo, sdi, interface); +} + +#endif +} // namespace spi +} // namespace esphome diff --git a/esphome/components/spi_device/__init__.py b/esphome/components/spi_device/__init__.py new file mode 100644 index 0000000000..428b5bfbda --- /dev/null +++ b/esphome/components/spi_device/__init__.py @@ -0,0 +1,49 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi +from esphome.const import CONF_ID, CONF_DATA_RATE, CONF_MODE + +DEPENDENCIES = ["spi"] +CODEOWNERS = ["@clydebarrow"] + +MULTI_CONF = True +spi_device_ns = cg.esphome_ns.namespace("spi_device") + +spi_device = spi_device_ns.class_("SPIDeviceComponent", cg.Component, spi.SPIDevice) + +Mode = spi.spi_ns.enum("SPIMode") +MODES = { + "0": Mode.MODE0, + "1": Mode.MODE1, + "2": Mode.MODE2, + "3": Mode.MODE3, + "MODE0": Mode.MODE0, + "MODE1": Mode.MODE1, + "MODE2": Mode.MODE2, + "MODE3": Mode.MODE3, +} + +BitOrder = spi.spi_ns.enum("SPIBitOrder") +ORDERS = { + "msb_first": BitOrder.BIT_ORDER_MSB_FIRST, + "lsb_first": BitOrder.BIT_ORDER_LSB_FIRST, +} +CONF_BIT_ORDER = "bit_order" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_ID): cv.declare_id(spi_device), + cv.Optional(CONF_DATA_RATE, default="1MHz"): spi.SPI_DATA_RATE_SCHEMA, + cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True), + cv.Optional(CONF_MODE, default="0"): cv.enum(MODES, upper=True), + } +).extend(spi.spi_device_schema(False)) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + cg.add(var.set_data_rate(config[CONF_DATA_RATE])) + cg.add(var.set_mode(config[CONF_MODE])) + cg.add(var.set_bit_order(config[CONF_BIT_ORDER])) + await spi.register_spi_device(var, config) diff --git a/esphome/components/spi_device/spi_device.cpp b/esphome/components/spi_device/spi_device.cpp new file mode 100644 index 0000000000..4e0b72ae60 --- /dev/null +++ b/esphome/components/spi_device/spi_device.cpp @@ -0,0 +1,30 @@ +#include "spi_device.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace spi_device { + +static const char *const TAG = "spi_device"; + +void SPIDeviceComponent::setup() { + ESP_LOGD(TAG, "Setting up SPIDevice..."); + this->spi_setup(); + ESP_LOGCONFIG(TAG, "SPIDevice started!"); +} + +void SPIDeviceComponent::dump_config() { + ESP_LOGCONFIG(TAG, "SPIDevice"); + LOG_PIN(" CS pin: ", this->cs_); + ESP_LOGCONFIG(TAG, " Mode: %d", this->mode_); + if (this->data_rate_ < 1000000) { + ESP_LOGCONFIG(TAG, " Data rate: %dkHz", this->data_rate_ / 1000); + } else { + ESP_LOGCONFIG(TAG, " Data rate: %dMHz", this->data_rate_ / 1000000); + } +} + +float SPIDeviceComponent::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace spi_device +} // namespace esphome diff --git a/esphome/components/spi_device/spi_device.h b/esphome/components/spi_device/spi_device.h new file mode 100644 index 0000000000..d8aef440a7 --- /dev/null +++ b/esphome/components/spi_device/spi_device.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace spi_device { + +class SPIDeviceComponent : public Component, + public spi::SPIDevice { + public: + void setup() override; + void dump_config() override; + + float get_setup_priority() const override; + + protected: +}; + +} // namespace spi_device +} // namespace esphome diff --git a/tests/test4.yaml b/tests/test4.yaml index 1175bb207c..341e613785 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -32,6 +32,7 @@ spi: clk_pin: GPIO21 mosi_pin: GPIO22 miso_pin: GPIO23 + interface: hardware uart: - id: uart115200 diff --git a/tests/test8.yaml b/tests/test8.yaml index 28c6e78b87..498da94483 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -31,8 +31,17 @@ light: restore_mode: ALWAYS_OFF spi: + id: spi_id_1 clk_pin: GPIO7 mosi_pin: GPIO6 + interface: any + +spi_device: + id: spidev + data_rate: 2MHz + spi_id: spi_id_1 + mode: 3 + bit_order: lsb_first display: - platform: ili9xxx From b19a7e006efda8c40010ccd381976577b3f00c0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Sep 2023 08:57:10 +1200 Subject: [PATCH 0454/2607] Bump actions/cache from 3.3.1 to 3.3.2 (#5367) Bumps [actions/cache](https://github.com/actions/cache) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.3.1...v3.3.2) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1de5822960..4214bc2c5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 with: path: venv # yamllint disable-line rule:line-length @@ -298,7 +298,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - name: Cache platformio - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 with: path: ~/.platformio # yamllint disable-line rule:line-length From 2fd6942de4bef6d2bc2fa556ec942ef558201379 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Sep 2023 08:57:35 +1200 Subject: [PATCH 0455/2607] Bump zeroconf from 0.88.0 to 0.102.0 (#5368) Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.88.0 to 0.102.0. - [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases) - [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md) - [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.88.0...0.102.0) --- updated-dependencies: - dependency-name: zeroconf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dcb7420d3f..9bce4a309d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.88.0 +zeroconf==0.102.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From d9523a0cbf556c3483d546ce42da808345af01f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20S=C3=A1rk=C3=B6zi?= Date: Fri, 8 Sep 2023 23:10:20 +0200 Subject: [PATCH 0456/2607] Fix repeat.count = 0 case (#5364) * Only play first action if count is non-zero * Add test to yaml * Update test5.yaml --- esphome/core/base_automation.h | 6 +++++- tests/test5.yaml | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index daa09b912e..a17b6a6f85 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -249,7 +249,11 @@ template class RepeatAction : public Action { void play_complex(Ts... x) override { this->num_running_++; this->var_ = std::make_tuple(x...); - this->then_.play(0, x...); + if (this->count_.value(x...) > 0) { + this->then_.play(0, x...); + } else { + this->play_next_tuple_(this->var_); + } } void play(Ts... x) override { /* ignore - see play_complex */ diff --git a/tests/test5.yaml b/tests/test5.yaml index a1cc3103d7..417f3bfecd 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -563,6 +563,13 @@ script: then: - logger.log: looping! + - id: zero_repeat_test + then: + - repeat: + count: !lambda "return 0;" + then: + - logger.log: shouldn't see mee! + switch: - platform: modbus_controller modbus_controller_id: modbus_controller_test From 9cf115a7526a51b8e951586f8b4488784afcf41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 8 Sep 2023 23:20:26 +0200 Subject: [PATCH 0457/2607] Fix dashboard download for ESP32 variants (#5355) --- esphome/dashboard/dashboard.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 0d6ec8dc13..cacd5e2db0 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -540,7 +540,10 @@ class DownloadListRequestHandler(BaseHandler): self.send_error(404) return - from esphome.components.esp32 import get_download_types as esp32_types + from esphome.components.esp32 import ( + get_download_types as esp32_types, + VARIANTS as ESP32_VARIANTS, + ) from esphome.components.esp8266 import get_download_types as esp8266_types from esphome.components.rp2040 import get_download_types as rp2040_types from esphome.components.libretiny import get_download_types as libretiny_types @@ -551,7 +554,7 @@ class DownloadListRequestHandler(BaseHandler): downloads = rp2040_types(storage_json) elif platform == const.PLATFORM_ESP8266: downloads = esp8266_types(storage_json) - elif platform == const.PLATFORM_ESP32: + elif platform.upper() in ESP32_VARIANTS: downloads = esp32_types(storage_json) elif platform == const.PLATFORM_BK72XX: downloads = libretiny_types(storage_json) From ccc30116ba5c31af3e2e71e1338c579e66433005 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Sep 2023 09:20:54 +1200 Subject: [PATCH 0458/2607] Bump pytest from 7.4.1 to 7.4.2 (#5357) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.1 to 7.4.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.1...7.4.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 2d46d3dccd..f17ccd220d 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==7.4.1 +pytest==7.4.2 pytest-cov==4.1.0 pytest-mock==3.11.1 pytest-asyncio==0.21.1 From 7bb67ae94b0399467a4f9752b5111b1c613f2643 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Sat, 9 Sep 2023 12:00:45 +0300 Subject: [PATCH 0459/2607] [ADC] Support measuring VCC on Raspberry Pico (W) (#5335) * [ADC] Support measuring VCC on Raspberry Pico (W) Added support for measuring VCC on Raspberry Pico (W) with ADC. GPIO pin is provided as `VCC`, same as with ESP8266. VSYS is the voltage being actually processed, and might have an offset from actual power supply voltage (e.g. USB on VBUS) due to voltage drop on Schottky diode between VSYS and VBUS on Rasberry Pico. The offset has experimentally been found to be ~0.25V on Pico W and ~0.1 on Pico, presumably due to different power consumption. Example usage: sensor: - platform: adc pin: VCC name: "VSYS" * + Added tests for VCC measuring on `rpipicow` board --- esphome/components/adc/__init__.py | 6 +++- esphome/components/adc/adc_sensor.cpp | 40 +++++++++++++++++++++++++-- tests/test6.yaml | 3 ++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index ba72951777..0b6ee145f2 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -5,6 +5,10 @@ from esphome.const import CONF_ANALOG, CONF_INPUT from esphome.core import CORE from esphome.components.esp32 import get_esp32_variant +from esphome.const import ( + PLATFORM_ESP8266, + PLATFORM_RP2040, +) from esphome.components.esp32.const import ( VARIANT_ESP32, VARIANT_ESP32C2, @@ -143,7 +147,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = { def validate_adc_pin(value): if str(value).upper() == "VCC": - return cv.only_on_esp8266("VCC") + return cv.only_on([PLATFORM_ESP8266, PLATFORM_RP2040])("VCC") if str(value).upper() == "TEMPERATURE": return cv.only_on_rp2040("TEMPERATURE") diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 0642cd7f3f..e69e6b9313 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -12,6 +12,9 @@ ADC_MODE(ADC_VCC) #endif #ifdef USE_RP2040 +#ifdef CYW43_USES_VSYS_PIN +#include "pico/cyw43_arch.h" +#endif #include #endif @@ -123,13 +126,19 @@ void ADCSensor::dump_config() { } } #endif // USE_ESP32 + #ifdef USE_RP2040 if (this->is_temperature_) { ESP_LOGCONFIG(TAG, " Pin: Temperature"); } else { +#ifdef USE_ADC_SENSOR_VCC + ESP_LOGCONFIG(TAG, " Pin: VCC"); +#else LOG_PIN(" Pin: ", pin_); +#endif // USE_ADC_SENSOR_VCC } -#endif +#endif // USE_RP2040 + LOG_UPDATE_INTERVAL(this); } @@ -238,7 +247,20 @@ float ADCSensor::sample() { delay(1); adc_select_input(4); } else { - uint8_t pin = this->pin_->get_pin(); + uint8_t pin; +#ifdef USE_ADC_SENSOR_VCC +#ifdef CYW43_USES_VSYS_PIN + // Measuring VSYS on Raspberry Pico W needs to be wrapped with + // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in + // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and + // VSYS ADC both share GPIO29 + cyw43_thread_enter(); +#endif // CYW43_USES_VSYS_PIN + pin = PICO_VSYS_PIN; +#else + pin = this->pin_->get_pin(); +#endif // USE_ADC_SENSOR_VCC + adc_gpio_init(pin); adc_select_input(pin - 26); } @@ -246,11 +268,23 @@ float ADCSensor::sample() { int32_t raw = adc_read(); if (this->is_temperature_) { adc_set_temp_sensor_enabled(false); + } else { +#ifdef USE_ADC_SENSOR_VCC +#ifdef CYW43_USES_VSYS_PIN + cyw43_thread_exit(); +#endif // CYW43_USES_VSYS_PIN +#endif // USE_ADC_SENSOR_VCC } + if (output_raw_) { return raw; } - return raw * 3.3f / 4096.0f; + float coeff = 1.0; +#ifdef USE_ADC_SENSOR_VCC + // As per Raspberry Pico (W) datasheet (section 2.1) the VSYS/3 is measured + coeff = 3.0; +#endif // USE_ADC_SENSOR_VCC + return raw * 3.3f / 4096.0f * coeff; } #endif diff --git a/tests/test6.yaml b/tests/test6.yaml index f048a4fa14..3d6a1ceb1f 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -62,3 +62,6 @@ switch: sensor: - platform: internal_temperature name: Internal Temperature + - platform: adc + pin: VCC + name: VSYS From 0c84224ca265c483db4de784061062f7e80d3852 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sat, 9 Sep 2023 19:19:54 -0400 Subject: [PATCH 0460/2607] Move CONF_PHASE_A/B/C constants to const.py. (#5304) --- esphome/components/atm90e32/sensor.py | 7 +++---- esphome/components/growatt_solar/sensor.py | 7 +++---- esphome/components/havells_solar/sensor.py | 6 +++--- esphome/const.py | 3 +++ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index 6cc0f6ac3e..af4d2ef412 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -6,6 +6,9 @@ from esphome.const import ( CONF_REACTIVE_POWER, CONF_VOLTAGE, CONF_CURRENT, + CONF_PHASE_A, + CONF_PHASE_B, + CONF_PHASE_C, CONF_POWER, CONF_POWER_FACTOR, CONF_FREQUENCY, @@ -31,10 +34,6 @@ from esphome.const import ( UNIT_WATT_HOURS, ) -CONF_PHASE_A = "phase_a" -CONF_PHASE_B = "phase_b" -CONF_PHASE_C = "phase_c" - CONF_LINE_FREQUENCY = "line_frequency" CONF_CHIP_TEMPERATURE = "chip_temperature" CONF_GAIN_PGA = "gain_pga" diff --git a/esphome/components/growatt_solar/sensor.py b/esphome/components/growatt_solar/sensor.py index f95d679c3e..0db15ae53e 100644 --- a/esphome/components/growatt_solar/sensor.py +++ b/esphome/components/growatt_solar/sensor.py @@ -6,6 +6,9 @@ from esphome.const import ( CONF_CURRENT, CONF_FREQUENCY, CONF_ID, + CONF_PHASE_A, + CONF_PHASE_B, + CONF_PHASE_C, CONF_VOLTAGE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, @@ -21,10 +24,6 @@ from esphome.const import ( UNIT_WATT, ) -CONF_PHASE_A = "phase_a" -CONF_PHASE_B = "phase_b" -CONF_PHASE_C = "phase_c" - CONF_ENERGY_PRODUCTION_DAY = "energy_production_day" CONF_TOTAL_ENERGY_PRODUCTION = "total_energy_production" CONF_TOTAL_GENERATION_TIME = "total_generation_time" diff --git a/esphome/components/havells_solar/sensor.py b/esphome/components/havells_solar/sensor.py index d7c8d544f9..66b72f9e3e 100644 --- a/esphome/components/havells_solar/sensor.py +++ b/esphome/components/havells_solar/sensor.py @@ -6,6 +6,9 @@ from esphome.const import ( CONF_CURRENT, CONF_FREQUENCY, CONF_ID, + CONF_PHASE_A, + CONF_PHASE_B, + CONF_PHASE_C, CONF_REACTIVE_POWER, CONF_VOLTAGE, DEVICE_CLASS_CURRENT, @@ -24,9 +27,6 @@ from esphome.const import ( UNIT_WATT, ) -CONF_PHASE_A = "phase_a" -CONF_PHASE_B = "phase_b" -CONF_PHASE_C = "phase_c" CONF_ENERGY_PRODUCTION_DAY = "energy_production_day" CONF_TOTAL_ENERGY_PRODUCTION = "total_energy_production" CONF_TOTAL_GENERATION_TIME = "total_generation_time" diff --git a/esphome/const.py b/esphome/const.py index 067fd23946..0e4e880c19 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -538,8 +538,11 @@ CONF_PAYLOAD_AVAILABLE = "payload_available" CONF_PAYLOAD_NOT_AVAILABLE = "payload_not_available" CONF_PERIOD = "period" CONF_PH = "ph" +CONF_PHASE_A = "phase_a" CONF_PHASE_ANGLE = "phase_angle" +CONF_PHASE_B = "phase_b" CONF_PHASE_BALANCER = "phase_balancer" +CONF_PHASE_C = "phase_c" CONF_PIN = "pin" CONF_PIN_A = "pin_a" CONF_PIN_B = "pin_b" From e66047e07212aa214542949da68049c914901d6a Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Sat, 9 Sep 2023 22:25:09 -0400 Subject: [PATCH 0461/2607] Add BMI160 support (#5143) * Add BMI160 support * BMI160: use set_timeout for delay * Add support for old compilers Fix "warning: missing terminating ' character" * Increase power-on delay to be more conservative * Add helper for reading little-endian data over i2c * Replace configuration names with globals Note: for testing with external components, you will need to comment out the import & define your own CONF_GYROSCOPE_X, etc, in this file * Improve icons * Fix tests & lint --- CODEOWNERS | 1 + esphome/components/bmi160/__init__.py | 1 + esphome/components/bmi160/bmi160.cpp | 270 ++++++++++++++++++++++++++ esphome/components/bmi160/bmi160.h | 44 +++++ esphome/components/bmi160/sensor.py | 102 ++++++++++ esphome/const.py | 6 + tests/test1.yaml | 17 ++ 7 files changed, 441 insertions(+) create mode 100644 esphome/components/bmi160/__init__.py create mode 100644 esphome/components/bmi160/bmi160.cpp create mode 100644 esphome/components/bmi160/bmi160.h create mode 100644 esphome/components/bmi160/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index ab4c5011f6..2658aebdc7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -49,6 +49,7 @@ esphome/components/bl0942/* @dbuezas esphome/components/ble_client/* @buxtronix esphome/components/bluetooth_proxy/* @jesserockz esphome/components/bme680_bsec/* @trvrnrth +esphome/components/bmi160/* @flaviut esphome/components/bmp3xx/* @martgras esphome/components/bmp581/* @kahrendt esphome/components/bp1658cj/* @Cossid diff --git a/esphome/components/bmi160/__init__.py b/esphome/components/bmi160/__init__.py new file mode 100644 index 0000000000..49b6d0252a --- /dev/null +++ b/esphome/components/bmi160/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@flaviut"] diff --git a/esphome/components/bmi160/bmi160.cpp b/esphome/components/bmi160/bmi160.cpp new file mode 100644 index 0000000000..69b4694345 --- /dev/null +++ b/esphome/components/bmi160/bmi160.cpp @@ -0,0 +1,270 @@ +#include "bmi160.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace bmi160 { + +static const char *const TAG = "bmi160"; + +const uint8_t BMI160_REGISTER_CHIPID = 0x00; + +const uint8_t BMI160_REGISTER_CMD = 0x7E; +enum class Cmd : uint8_t { + START_FOC = 0x03, + ACCL_SET_PMU_MODE = 0b00010000, // last 2 bits are mode + GYRO_SET_PMU_MODE = 0b00010100, // last 2 bits are mode + MAG_SET_PMU_MODE = 0b00011000, // last 2 bits are mode + PROG_NVM = 0xA0, + FIFO_FLUSH = 0xB0, + INT_RESET = 0xB1, + SOFT_RESET = 0xB6, + STEP_CNT_CLR = 0xB2, +}; +enum class GyroPmuMode : uint8_t { + SUSPEND = 0b00, + NORMAL = 0b01, + LOW_POWER = 0b10, +}; +enum class AcclPmuMode : uint8_t { + SUSPEND = 0b00, + NORMAL = 0b01, + FAST_STARTUP = 0b11, +}; +enum class MagPmuMode : uint8_t { + SUSPEND = 0b00, + NORMAL = 0b01, + LOW_POWER = 0b10, +}; + +const uint8_t BMI160_REGISTER_ACCEL_CONFIG = 0x40; +enum class AcclFilterMode : uint8_t { + POWER_SAVING = 0b00000000, + PERF = 0b10000000, +}; +enum class AcclBandwidth : uint8_t { + OSR4_AVG1 = 0b00000000, + OSR2_AVG2 = 0b00010000, + NORMAL_AVG4 = 0b00100000, + RES_AVG8 = 0b00110000, + RES_AVG16 = 0b01000000, + RES_AVG32 = 0b01010000, + RES_AVG64 = 0b01100000, + RES_AVG128 = 0b01110000, +}; +enum class AccelOutputDataRate : uint8_t { + HZ_25_32 = 0b0001, // 25/32 Hz + HZ_25_16 = 0b0010, // 25/16 Hz + HZ_25_8 = 0b0011, // 25/8 Hz + HZ_25_4 = 0b0100, // 25/4 Hz + HZ_25_2 = 0b0101, // 25/2 Hz + HZ_25 = 0b0110, // 25 Hz + HZ_50 = 0b0111, // 50 Hz + HZ_100 = 0b1000, // 100 Hz + HZ_200 = 0b1001, // 200 Hz + HZ_400 = 0b1010, // 400 Hz + HZ_800 = 0b1011, // 800 Hz + HZ_1600 = 0b1100, // 1600 Hz +}; +const uint8_t BMI160_REGISTER_ACCEL_RANGE = 0x41; +enum class AccelRange : uint8_t { + RANGE_2G = 0b0011, + RANGE_4G = 0b0101, + RANGE_8G = 0b1000, + RANGE_16G = 0b1100, +}; + +const uint8_t BMI160_REGISTER_GYRO_CONFIG = 0x42; +enum class GyroBandwidth : uint8_t { + OSR4 = 0x00, + OSR2 = 0x10, + NORMAL = 0x20, +}; +enum class GyroOuputDataRate : uint8_t { + HZ_25 = 0x06, + HZ_50 = 0x07, + HZ_100 = 0x08, + HZ_200 = 0x09, + HZ_400 = 0x0A, + HZ_800 = 0x0B, + HZ_1600 = 0x0C, + HZ_3200 = 0x0D, +}; +const uint8_t BMI160_REGISTER_GYRO_RANGE = 0x43; +enum class GyroRange : uint8_t { + RANGE_2000_DPS = 0x0, // ±2000 °/s + RANGE_1000_DPS = 0x1, + RANGE_500_DPS = 0x2, + RANGE_250_DPS = 0x3, + RANGE_125_DPS = 0x4, +}; + +const uint8_t BMI160_REGISTER_DATA_GYRO_X_LSB = 0x0C; +const uint8_t BMI160_REGISTER_DATA_GYRO_X_MSB = 0x0D; +const uint8_t BMI160_REGISTER_DATA_GYRO_Y_LSB = 0x0E; +const uint8_t BMI160_REGISTER_DATA_GYRO_Y_MSB = 0x0F; +const uint8_t BMI160_REGISTER_DATA_GYRO_Z_LSB = 0x10; +const uint8_t BMI160_REGISTER_DATA_GYRO_Z_MSB = 0x11; +const uint8_t BMI160_REGISTER_DATA_ACCEL_X_LSB = 0x12; +const uint8_t BMI160_REGISTER_DATA_ACCEL_X_MSB = 0x13; +const uint8_t BMI160_REGISTER_DATA_ACCEL_Y_LSB = 0x14; +const uint8_t BMI160_REGISTER_DATA_ACCEL_Y_MSB = 0x15; +const uint8_t BMI160_REGISTER_DATA_ACCEL_Z_LSB = 0x16; +const uint8_t BMI160_REGISTER_DATA_ACCEL_Z_MSB = 0x17; +const uint8_t BMI160_REGISTER_DATA_TEMP_LSB = 0x20; +const uint8_t BMI160_REGISTER_DATA_TEMP_MSB = 0x21; + +const float GRAVITY_EARTH = 9.80665f; + +void BMI160Component::internal_setup_(int stage) { + switch (stage) { + case 0: + ESP_LOGCONFIG(TAG, "Setting up BMI160..."); + uint8_t chipid; + if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) { + this->mark_failed(); + return; + } + + ESP_LOGV(TAG, " Bringing accelerometer out of sleep..."); + if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::ACCL_SET_PMU_MODE | (uint8_t) AcclPmuMode::NORMAL)) { + this->mark_failed(); + return; + } + ESP_LOGV(TAG, " Waiting for accelerometer to wake up..."); + // need to wait (max delay in datasheet) because we can't send commands while another is in progress + // min 5ms, 10ms + this->set_timeout(10, [this]() { this->internal_setup_(1); }); + break; + + case 1: + ESP_LOGV(TAG, " Bringing gyroscope out of sleep..."); + if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::GYRO_SET_PMU_MODE | (uint8_t) GyroPmuMode::NORMAL)) { + this->mark_failed(); + return; + } + ESP_LOGV(TAG, " Waiting for gyroscope to wake up..."); + // wait between 51 & 81ms, doing 100 to be safe + this->set_timeout(10, [this]() { this->internal_setup_(2); }); + break; + + case 2: + ESP_LOGV(TAG, " Setting up Gyro Config..."); + uint8_t gyro_config = (uint8_t) GyroBandwidth::OSR4 | (uint8_t) GyroOuputDataRate::HZ_25; + ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); + if (!this->write_byte(BMI160_REGISTER_GYRO_CONFIG, gyro_config)) { + this->mark_failed(); + return; + } + ESP_LOGV(TAG, " Setting up Gyro Range..."); + uint8_t gyro_range = (uint8_t) GyroRange::RANGE_2000_DPS; + ESP_LOGV(TAG, " Output gyro_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_range)); + if (!this->write_byte(BMI160_REGISTER_GYRO_RANGE, gyro_range)) { + this->mark_failed(); + return; + } + + ESP_LOGV(TAG, " Setting up Accel Config..."); + uint8_t accel_config = + (uint8_t) AcclFilterMode::PERF | (uint8_t) AcclBandwidth::RES_AVG16 | (uint8_t) AccelOutputDataRate::HZ_25; + ESP_LOGV(TAG, " Output accel_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_config)); + if (!this->write_byte(BMI160_REGISTER_ACCEL_CONFIG, accel_config)) { + this->mark_failed(); + return; + } + ESP_LOGV(TAG, " Setting up Accel Range..."); + uint8_t accel_range = (uint8_t) AccelRange::RANGE_16G; + ESP_LOGV(TAG, " Output accel_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_range)); + if (!this->write_byte(BMI160_REGISTER_ACCEL_RANGE, accel_range)) { + this->mark_failed(); + return; + } + + this->setup_complete_ = true; + } +} + +void BMI160Component::setup() { this->internal_setup_(0); } +void BMI160Component::dump_config() { + ESP_LOGCONFIG(TAG, "BMI160:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with BMI160 failed!"); + } + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Acceleration X", this->accel_x_sensor_); + LOG_SENSOR(" ", "Acceleration Y", this->accel_y_sensor_); + LOG_SENSOR(" ", "Acceleration Z", this->accel_z_sensor_); + LOG_SENSOR(" ", "Gyro X", this->gyro_x_sensor_); + LOG_SENSOR(" ", "Gyro Y", this->gyro_y_sensor_); + LOG_SENSOR(" ", "Gyro Z", this->gyro_z_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); +} + +i2c::ErrorCode BMI160Component::read_le_int16_(uint8_t reg, int16_t *value, uint8_t len) { + uint8_t raw_data[len * 2]; + // read using read_register because we have little-endian data, and read_bytes_16 will swap it + i2c::ErrorCode err = this->read_register(reg, raw_data, len * 2, true); + if (err != i2c::ERROR_OK) { + return err; + } + for (int i = 0; i < len; i++) { + value[i] = (int16_t) ((uint16_t) raw_data[i * 2] | ((uint16_t) raw_data[i * 2 + 1] << 8)); + } + return err; +} + +void BMI160Component::update() { + if (!this->setup_complete_) { + return; + } + + ESP_LOGV(TAG, " Updating BMI160..."); + int16_t data[6]; + if (this->read_le_int16_(BMI160_REGISTER_DATA_GYRO_X_LSB, data, 6) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + float gyro_x = (float) data[0] / (float) INT16_MAX * 2000.f; + float gyro_y = (float) data[1] / (float) INT16_MAX * 2000.f; + float gyro_z = (float) data[2] / (float) INT16_MAX * 2000.f; + float accel_x = (float) data[3] / (float) INT16_MAX * 16 * GRAVITY_EARTH; + float accel_y = (float) data[4] / (float) INT16_MAX * 16 * GRAVITY_EARTH; + float accel_z = (float) data[5] / (float) INT16_MAX * 16 * GRAVITY_EARTH; + + int16_t raw_temperature; + if (this->read_le_int16_(BMI160_REGISTER_DATA_TEMP_LSB, &raw_temperature, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + float temperature = (float) raw_temperature / (float) INT16_MAX * 64.5f + 23.f; + + ESP_LOGD(TAG, + "Got accel={x=%.3f m/s², y=%.3f m/s², z=%.3f m/s²}, " + "gyro={x=%.3f °/s, y=%.3f °/s, z=%.3f °/s}, temp=%.3f°C", + accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, temperature); + + if (this->accel_x_sensor_ != nullptr) + this->accel_x_sensor_->publish_state(accel_x); + if (this->accel_y_sensor_ != nullptr) + this->accel_y_sensor_->publish_state(accel_y); + if (this->accel_z_sensor_ != nullptr) + this->accel_z_sensor_->publish_state(accel_z); + + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(temperature); + + if (this->gyro_x_sensor_ != nullptr) + this->gyro_x_sensor_->publish_state(gyro_x); + if (this->gyro_y_sensor_ != nullptr) + this->gyro_y_sensor_->publish_state(gyro_y); + if (this->gyro_z_sensor_ != nullptr) + this->gyro_z_sensor_->publish_state(gyro_z); + + this->status_clear_warning(); +} +float BMI160Component::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace bmi160 +} // namespace esphome diff --git a/esphome/components/bmi160/bmi160.h b/esphome/components/bmi160/bmi160.h new file mode 100644 index 0000000000..47691a4de9 --- /dev/null +++ b/esphome/components/bmi160/bmi160.h @@ -0,0 +1,44 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace bmi160 { + +class BMI160Component : public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + + void update() override; + + float get_setup_priority() const override; + + void set_accel_x_sensor(sensor::Sensor *accel_x_sensor) { accel_x_sensor_ = accel_x_sensor; } + void set_accel_y_sensor(sensor::Sensor *accel_y_sensor) { accel_y_sensor_ = accel_y_sensor; } + void set_accel_z_sensor(sensor::Sensor *accel_z_sensor) { accel_z_sensor_ = accel_z_sensor; } + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } + void set_gyro_x_sensor(sensor::Sensor *gyro_x_sensor) { gyro_x_sensor_ = gyro_x_sensor; } + void set_gyro_y_sensor(sensor::Sensor *gyro_y_sensor) { gyro_y_sensor_ = gyro_y_sensor; } + void set_gyro_z_sensor(sensor::Sensor *gyro_z_sensor) { gyro_z_sensor_ = gyro_z_sensor; } + + protected: + sensor::Sensor *accel_x_sensor_{nullptr}; + sensor::Sensor *accel_y_sensor_{nullptr}; + sensor::Sensor *accel_z_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *gyro_x_sensor_{nullptr}; + sensor::Sensor *gyro_y_sensor_{nullptr}; + sensor::Sensor *gyro_z_sensor_{nullptr}; + + void internal_setup_(int stage); + bool setup_complete_{false}; + + /** reads `len` 16-bit little-endian integers from the given i2c register */ + i2c::ErrorCode read_le_int16_(uint8_t reg, int16_t *value, uint8_t len); +}; + +} // namespace bmi160 +} // namespace esphome diff --git a/esphome/components/bmi160/sensor.py b/esphome/components/bmi160/sensor.py new file mode 100644 index 0000000000..baf185f95a --- /dev/null +++ b/esphome/components/bmi160/sensor.py @@ -0,0 +1,102 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + CONF_TEMPERATURE, + CONF_ACCELERATION_X, + CONF_ACCELERATION_Y, + CONF_ACCELERATION_Z, + CONF_GYROSCOPE_X, + CONF_GYROSCOPE_Y, + CONF_GYROSCOPE_Z, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_METER_PER_SECOND_SQUARED, + ICON_ACCELERATION_X, + ICON_ACCELERATION_Y, + ICON_ACCELERATION_Z, + ICON_GYROSCOPE_X, + ICON_GYROSCOPE_Y, + ICON_GYROSCOPE_Z, + UNIT_DEGREE_PER_SECOND, + UNIT_CELSIUS, +) + +DEPENDENCIES = ["i2c"] + +bmi160_ns = cg.esphome_ns.namespace("bmi160") +BMI160Component = bmi160_ns.class_( + "BMI160Component", cg.PollingComponent, i2c.I2CDevice +) + +accel_schema = { + "unit_of_measurement": UNIT_METER_PER_SECOND_SQUARED, + "accuracy_decimals": 2, + "state_class": STATE_CLASS_MEASUREMENT, +} +gyro_schema = { + "unit_of_measurement": UNIT_DEGREE_PER_SECOND, + "accuracy_decimals": 2, + "state_class": STATE_CLASS_MEASUREMENT, +} + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(BMI160Component), + cv.Optional(CONF_ACCELERATION_X): sensor.sensor_schema( + icon=ICON_ACCELERATION_X, + **accel_schema, + ), + cv.Optional(CONF_ACCELERATION_Y): sensor.sensor_schema( + icon=ICON_ACCELERATION_Y, + **accel_schema, + ), + cv.Optional(CONF_ACCELERATION_Z): sensor.sensor_schema( + icon=ICON_ACCELERATION_Z, + **accel_schema, + ), + cv.Optional(CONF_GYROSCOPE_X): sensor.sensor_schema( + icon=ICON_GYROSCOPE_X, + **gyro_schema, + ), + cv.Optional(CONF_GYROSCOPE_Y): sensor.sensor_schema( + icon=ICON_GYROSCOPE_Y, + **gyro_schema, + ), + cv.Optional(CONF_GYROSCOPE_Z): sensor.sensor_schema( + icon=ICON_GYROSCOPE_Z, + **gyro_schema, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x68)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + for d in ["x", "y", "z"]: + accel_key = f"acceleration_{d}" + if accel_key in config: + sens = await sensor.new_sensor(config[accel_key]) + cg.add(getattr(var, f"set_accel_{d}_sensor")(sens)) + accel_key = f"gyroscope_{d}" + if accel_key in config: + sens = await sensor.new_sensor(config[accel_key]) + cg.add(getattr(var, f"set_gyro_{d}_sensor")(sens)) + + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index 0e4e880c19..bbc6e71885 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -298,6 +298,9 @@ CONF_GLYPHS = "glyphs" CONF_GPIO = "gpio" CONF_GREEN = "green" CONF_GROUP = "group" +CONF_GYROSCOPE_X = "gyroscope_x" +CONF_GYROSCOPE_Y = "gyroscope_y" +CONF_GYROSCOPE_Z = "gyroscope_z" CONF_HARDWARE_UART = "hardware_uart" CONF_HEAD = "head" CONF_HEARTBEAT = "heartbeat" @@ -867,6 +870,9 @@ ICON_FLOWER = "mdi:flower" ICON_GAS_CYLINDER = "mdi:gas-cylinder" ICON_GAUGE = "mdi:gauge" ICON_GRAIN = "mdi:grain" +ICON_GYROSCOPE_X = "mdi:axis-x-rotate-clockwise" +ICON_GYROSCOPE_Y = "mdi:axis-y-rotate-clockwise" +ICON_GYROSCOPE_Z = "mdi:axis-z-rotate-clockwise" ICON_HEATING_COIL = "mdi:heating-coil" ICON_KEY_PLUS = "mdi:key-plus" ICON_LIGHTBULB = "mdi:lightbulb" diff --git a/tests/test1.yaml b/tests/test1.yaml index 33782dbf53..fe983cf421 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -915,6 +915,23 @@ sensor: temperature: name: MPU6886 Temperature i2c_id: i2c_bus + - platform: bmi160 + address: 0x68 + acceleration_x: + name: BMI160 Accel X + acceleration_y: + name: BMI160 Accel Y + acceleration_z: + name: BMI160 Accel z + gyroscope_x: + name: BMI160 Gyro X + gyroscope_y: + name: BMI160 Gyro Y + gyroscope_z: + name: BMI160 Gyro z + temperature: + name: BMI160 Temperature + i2c_id: i2c_bus - platform: mmc5603 address: 0x30 field_strength_x: From 32b103eb1d67ea2275d61531ffc51b90f59870fa Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 10 Sep 2023 15:42:42 -0400 Subject: [PATCH 0462/2607] Use black-pre-commit-mirror to speed up pre-commit runs. (#5372) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cf86d354b7..0bbb2fee61 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - - repo: https://github.com/psf/black + - repo: https://github.com/psf/black-pre-commit-mirror rev: 23.7.0 hooks: - id: black From d2648657fb13e9bc576c1f8436ca7ab9a9d3748e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:20:06 +1000 Subject: [PATCH 0463/2607] Native SPI RGB LED component (#5288) * Add testing branch to workflow * Add workflow * Checkpoint * Align SPI data rates in c++ code with Python code. * Checkpoint * CI fixes * Update codeowners * Workflow cleanup * Rename to spi_rgb_led * Rename header file * Clang tidy * Disable spi after transfer. * Move enable() to where it belongs * Call spi_setup before enable * Clang tidy * Add test * Rename to spi_led_strip * Include 'defines.h' * Fix CODEOWNERS * Migrate data rate to new style setting. * Remove defines.h * Fix class name * Fix name in .py * And more more name tidy up. --------- Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/spi_led_strip/__init__.py | 2 + esphome/components/spi_led_strip/light.py | 27 ++++++ .../components/spi_led_strip/spi_led_strip.h | 91 +++++++++++++++++++ tests/test8.yaml | 6 ++ 5 files changed, 127 insertions(+) create mode 100644 esphome/components/spi_led_strip/__init__.py create mode 100644 esphome/components/spi_led_strip/light.py create mode 100644 esphome/components/spi_led_strip/spi_led_strip.h diff --git a/CODEOWNERS b/CODEOWNERS index 2658aebdc7..8e0911f2a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -272,6 +272,7 @@ esphome/components/sonoff_d1/* @anatoly-savchenkov esphome/components/speaker/* @jesserockz esphome/components/spi/* @esphome/core esphome/components/spi_device/* @clydebarrow +esphome/components/spi_led_strip/* @clydebarrow esphome/components/sprinkler/* @kbx81 esphome/components/sps30/* @martgras esphome/components/ssd1322_base/* @kbx81 diff --git a/esphome/components/spi_led_strip/__init__.py b/esphome/components/spi_led_strip/__init__.py new file mode 100644 index 0000000000..850a1f6e02 --- /dev/null +++ b/esphome/components/spi_led_strip/__init__.py @@ -0,0 +1,2 @@ +CODEOWNERS = ["@clydebarrow"] +DEPENDENCIES = ["spi"] diff --git a/esphome/components/spi_led_strip/light.py b/esphome/components/spi_led_strip/light.py new file mode 100644 index 0000000000..7420b0c929 --- /dev/null +++ b/esphome/components/spi_led_strip/light.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import light +from esphome.components import spi +from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_DATA_RATE + +spi_led_strip_ns = cg.esphome_ns.namespace("spi_led_strip") +SpiLedStrip = spi_led_strip_ns.class_( + "SpiLedStrip", light.AddressableLight, spi.SPIDevice +) + +CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpiLedStrip), + cv.Optional(CONF_NUM_LEDS, default=1): cv.positive_not_null_int, + cv.Optional(CONF_DATA_RATE, default="1MHz"): spi.SPI_DATA_RATE_SCHEMA, + } +).extend(spi.spi_device_schema(False)) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) + cg.add(var.set_data_rate(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]])) + cg.add(var.set_num_leds(config[CONF_NUM_LEDS])) + await light.register_light(var, config) + await spi.register_spi_device(var, config) + await cg.register_component(var, config) diff --git a/esphome/components/spi_led_strip/spi_led_strip.h b/esphome/components/spi_led_strip/spi_led_strip.h new file mode 100644 index 0000000000..0d8c1c1e1c --- /dev/null +++ b/esphome/components/spi_led_strip/spi_led_strip.h @@ -0,0 +1,91 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/log.h" +#include "esphome/components/light/addressable_light.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace spi_led_strip { + +static const char *const TAG = "spi_led_strip"; +class SpiLedStrip : public light::AddressableLight, + public spi::SPIDevice { + public: + void setup() { this->spi_setup(); } + + int32_t size() const override { return this->num_leds_; } + + light::LightTraits get_traits() override { + auto traits = light::LightTraits(); + traits.set_supported_color_modes({light::ColorMode::RGB}); + return traits; + } + void set_num_leds(uint16_t num_leds) { + this->num_leds_ = num_leds; + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->buffer_size_ = num_leds * 4 + 8; + this->buf_ = allocator.allocate(this->buffer_size_); + if (this->buf_ == nullptr) { + esph_log_e(TAG, "Failed to allocate buffer of size %u", this->buffer_size_); + this->mark_failed(); + return; + } + + this->effect_data_ = allocator.allocate(num_leds); + if (this->effect_data_ == nullptr) { + esph_log_e(TAG, "Failed to allocate effect data of size %u", num_leds); + this->mark_failed(); + return; + } + memset(this->buf_, 0xFF, this->buffer_size_); + memset(this->buf_, 0, 4); + } + + void dump_config() { + esph_log_config(TAG, "SPI LED Strip:"); + esph_log_config(TAG, " LEDs: %d", this->num_leds_); + if (this->data_rate_ >= spi::DATA_RATE_1MHZ) + esph_log_config(TAG, " Data rate: %uMHz", (unsigned) (this->data_rate_ / 1000000)); + else + esph_log_config(TAG, " Data rate: %ukHz", (unsigned) (this->data_rate_ / 1000)); + } + + void write_state(light::LightState *state) override { + if (this->is_failed()) + return; + if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE) { + char strbuf[49]; + size_t len = std::min(this->buffer_size_, (size_t) (sizeof(strbuf) - 1) / 3); + memset(strbuf, 0, sizeof(strbuf)); + for (size_t i = 0; i != len; i++) { + sprintf(strbuf + i * 3, "%02X ", this->buf_[i]); + } + esph_log_v(TAG, "write_state: buf = %s", strbuf); + } + this->enable(); + this->write_array(this->buf_, this->buffer_size_); + this->disable(); + } + + void clear_effect_data() override { + for (int i = 0; i < this->size(); i++) + this->effect_data_[i] = 0; + } + + protected: + light::ESPColorView get_view_internal(int32_t index) const override { + size_t pos = index * 4 + 5; + return {this->buf_ + pos + 2, this->buf_ + pos + 1, this->buf_ + pos + 0, nullptr, + this->effect_data_ + index, &this->correction_}; + } + + size_t buffer_size_{}; + uint8_t *effect_data_{nullptr}; + uint8_t *buf_{nullptr}; + uint16_t num_leds_; +}; + +} // namespace spi_led_strip +} // namespace esphome diff --git a/tests/test8.yaml b/tests/test8.yaml index 498da94483..01d12ea330 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -29,6 +29,12 @@ light: name: neopixel-enable internal: false restore_mode: ALWAYS_OFF + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz spi: id: spi_id_1 From b107948c476e0d587b41399fdc5a7bea90753c68 Mon Sep 17 00:00:00 2001 From: Lubos Horacek Date: Mon, 11 Sep 2023 21:13:24 +0200 Subject: [PATCH 0464/2607] Wireguard component (#4256) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Simone Rossetto Co-authored-by: Thomas Bernard --- .github/workflows/ci.yml | 2 +- .gitignore | 6 + CODEOWNERS | 1 + esphome/components/wireguard/__init__.py | 113 +++++++ esphome/components/wireguard/binary_sensor.py | 28 ++ esphome/components/wireguard/sensor.py | 30 ++ esphome/components/wireguard/wireguard.cpp | 296 ++++++++++++++++++ esphome/components/wireguard/wireguard.h | 122 ++++++++ platformio.ini | 2 + tests/README.md | 1 + tests/test10.yaml | 48 +++ 11 files changed, 648 insertions(+), 1 deletion(-) create mode 100644 esphome/components/wireguard/__init__.py create mode 100644 esphome/components/wireguard/binary_sensor.py create mode 100644 esphome/components/wireguard/sensor.py create mode 100644 esphome/components/wireguard/wireguard.cpp create mode 100644 esphome/components/wireguard/wireguard.h create mode 100644 tests/test10.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4214bc2c5d..79ebe8782e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,7 +232,7 @@ jobs: fail-fast: false max-parallel: 2 matrix: - file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8] + file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 10] steps: - name: Check out code from GitHub uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index d180b58259..0c9a878400 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,12 @@ __pycache__/ # Intellij Idea .idea +# Eclipse +.project +.cproject +.pydevproject +.settings/ + # Vim *.swp diff --git a/CODEOWNERS b/CODEOWNERS index 8e0911f2a9..22e46aa2f0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -333,6 +333,7 @@ esphome/components/web_server_idf/* @dentra esphome/components/whirlpool/* @glmnet esphome/components/whynter/* @aeonsablaze esphome/components/wiegand/* @ssieb +esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard esphome/components/wl_134/* @hobbypunk90 esphome/components/x9c/* @EtienneMD esphome/components/xiaomi_lywsd03mmc/* @ahpohl diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py new file mode 100644 index 0000000000..717fe50d2c --- /dev/null +++ b/esphome/components/wireguard/__init__.py @@ -0,0 +1,113 @@ +import re +import ipaddress +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_TIME_ID, + CONF_ADDRESS, + CONF_REBOOT_TIMEOUT, +) +from esphome.components import time + +CONF_NETMASK = "netmask" +CONF_PRIVATE_KEY = "private_key" +CONF_PEER_ENDPOINT = "peer_endpoint" +CONF_PEER_PUBLIC_KEY = "peer_public_key" +CONF_PEER_PORT = "peer_port" +CONF_PEER_PRESHARED_KEY = "peer_preshared_key" +CONF_PEER_ALLOWED_IPS = "peer_allowed_ips" +CONF_PEER_PERSISTENT_KEEPALIVE = "peer_persistent_keepalive" +CONF_REQUIRE_CONNECTION_TO_PROCEED = "require_connection_to_proceed" + +DEPENDENCIES = ["time", "esp32"] +CODEOWNERS = ["@lhoracek", "@droscy", "@thomas0bernard"] + +# The key validation regex has been described by Jason Donenfeld himself +# url: https://lists.zx2c4.com/pipermail/wireguard/2020-December/006222.html +_WG_KEY_REGEX = re.compile(r"^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw480]=$") + +wireguard_ns = cg.esphome_ns.namespace("wireguard") +Wireguard = wireguard_ns.class_("Wireguard", cg.Component, cg.PollingComponent) + + +def _wireguard_key(value): + if _WG_KEY_REGEX.match(cv.string(value)) is not None: + return value + raise cv.Invalid(f"Invalid WireGuard key: {value}") + + +def _cidr_network(value): + try: + ipaddress.ip_network(value, strict=False) + except ValueError as err: + raise cv.Invalid(f"Invalid network in CIDR notation: {err}") + return value + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(Wireguard), + cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), + cv.Required(CONF_ADDRESS): cv.ipv4, + cv.Optional(CONF_NETMASK, default="255.255.255.255"): cv.ipv4, + cv.Required(CONF_PRIVATE_KEY): _wireguard_key, + cv.Required(CONF_PEER_ENDPOINT): cv.string, + cv.Required(CONF_PEER_PUBLIC_KEY): _wireguard_key, + cv.Optional(CONF_PEER_PORT, default=51820): cv.port, + cv.Optional(CONF_PEER_PRESHARED_KEY): _wireguard_key, + cv.Optional(CONF_PEER_ALLOWED_IPS, default=["0.0.0.0/0"]): cv.ensure_list( + _cidr_network + ), + cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default=0): cv.Any( + cv.positive_time_period_seconds, + cv.uint16_t, + ), + cv.Optional( + CONF_REBOOT_TIMEOUT, default="15min" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_REQUIRE_CONNECTION_TO_PROCEED, default=False): cv.boolean, + } +).extend(cv.polling_component_schema("10s")) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + + cg.add(var.set_address(str(config[CONF_ADDRESS]))) + cg.add(var.set_netmask(str(config[CONF_NETMASK]))) + cg.add(var.set_private_key(config[CONF_PRIVATE_KEY])) + cg.add(var.set_peer_endpoint(config[CONF_PEER_ENDPOINT])) + cg.add(var.set_peer_public_key(config[CONF_PEER_PUBLIC_KEY])) + cg.add(var.set_peer_port(config[CONF_PEER_PORT])) + cg.add(var.set_keepalive(config[CONF_PEER_PERSISTENT_KEEPALIVE])) + cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) + + if CONF_PEER_PRESHARED_KEY in config: + cg.add(var.set_preshared_key(config[CONF_PEER_PRESHARED_KEY])) + + allowed_ips = list( + ipaddress.collapse_addresses( + [ + ipaddress.ip_network(ip, strict=False) + for ip in config[CONF_PEER_ALLOWED_IPS] + ] + ) + ) + + for ip in allowed_ips: + cg.add(var.add_allowed_ip(str(ip.network_address), str(ip.netmask))) + + cg.add(var.set_srctime(await cg.get_variable(config[CONF_TIME_ID]))) + + if config[CONF_REQUIRE_CONNECTION_TO_PROCEED]: + cg.add(var.disable_auto_proceed()) + + # This flag is added here because the esp_wireguard library statically + # set the size of its allowed_ips list at compile time using this value; + # the '+1' modifier is relative to the device's own address that will + # be automatically added to the provided list. + cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}") + cg.add_library("droscy/esp_wireguard", "0.3.2") + + await cg.register_component(var, config) diff --git a/esphome/components/wireguard/binary_sensor.py b/esphome/components/wireguard/binary_sensor.py new file mode 100644 index 0000000000..14ff2b0159 --- /dev/null +++ b/esphome/components/wireguard/binary_sensor.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import ( + CONF_STATUS, + DEVICE_CLASS_CONNECTIVITY, +) + +from . import Wireguard + +CONF_WIREGUARD_ID = "wireguard_id" + +DEPENDENCIES = ["wireguard"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_WIREGUARD_ID): cv.use_id(Wireguard), + cv.Optional(CONF_STATUS): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_CONNECTIVITY, + ), +} + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_WIREGUARD_ID]) + + if status_config := config.get(CONF_STATUS): + sens = await binary_sensor.new_binary_sensor(status_config) + cg.add(parent.set_status_sensor(sens)) diff --git a/esphome/components/wireguard/sensor.py b/esphome/components/wireguard/sensor.py new file mode 100644 index 0000000000..78cb619701 --- /dev/null +++ b/esphome/components/wireguard/sensor.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + DEVICE_CLASS_TIMESTAMP, + ENTITY_CATEGORY_DIAGNOSTIC, +) + +from . import Wireguard + +CONF_WIREGUARD_ID = "wireguard_id" +CONF_LATEST_HANDSHAKE = "latest_handshake" + +DEPENDENCIES = ["wireguard"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_WIREGUARD_ID): cv.use_id(Wireguard), + cv.Optional(CONF_LATEST_HANDSHAKE): sensor.sensor_schema( + device_class=DEVICE_CLASS_TIMESTAMP, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_WIREGUARD_ID]) + + if latest_handshake_config := config.get(CONF_LATEST_HANDSHAKE): + sens = await sensor.new_sensor(latest_handshake_config) + cg.add(parent.set_handshake_sensor(sens)) diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp new file mode 100644 index 0000000000..1b361cc1cc --- /dev/null +++ b/esphome/components/wireguard/wireguard.cpp @@ -0,0 +1,296 @@ +#include "wireguard.h" + +#ifdef USE_ESP32 + +#include +#include + +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/time.h" +#include "esphome/components/network/util.h" + +#include + +#include + +// includes for resume/suspend wdt +#if defined(USE_ESP_IDF) +#include +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif +#elif defined(USE_ARDUINO) +#include +#endif + +namespace esphome { +namespace wireguard { + +static const char *const TAG = "wireguard"; + +static const char *const LOGMSG_PEER_STATUS = "WireGuard remote peer is %s (latest handshake %s)"; +static const char *const LOGMSG_ONLINE = "online"; +static const char *const LOGMSG_OFFLINE = "offline"; + +void Wireguard::setup() { + ESP_LOGD(TAG, "initializing WireGuard..."); + + this->wg_config_.address = this->address_.c_str(); + this->wg_config_.private_key = this->private_key_.c_str(); + this->wg_config_.endpoint = this->peer_endpoint_.c_str(); + this->wg_config_.public_key = this->peer_public_key_.c_str(); + this->wg_config_.port = this->peer_port_; + this->wg_config_.netmask = this->netmask_.c_str(); + this->wg_config_.persistent_keepalive = this->keepalive_; + + if (this->preshared_key_.length() > 0) + this->wg_config_.preshared_key = this->preshared_key_.c_str(); + + this->wg_initialized_ = esp_wireguard_init(&(this->wg_config_), &(this->wg_ctx_)); + + if (this->wg_initialized_ == ESP_OK) { + ESP_LOGI(TAG, "WireGuard initialized"); + this->wg_peer_offline_time_ = millis(); + this->srctime_->add_on_time_sync_callback(std::bind(&Wireguard::start_connection_, this)); + this->defer(std::bind(&Wireguard::start_connection_, this)); // defer to avoid blocking setup + } else { + ESP_LOGE(TAG, "cannot initialize WireGuard, error code %d", this->wg_initialized_); + this->mark_failed(); + } +} + +void Wireguard::loop() { + if ((this->wg_initialized_ == ESP_OK) && (this->wg_connected_ == ESP_OK) && (!network::is_connected())) { + ESP_LOGV(TAG, "local network connection has been lost, stopping WireGuard..."); + this->stop_connection_(); + } +} + +void Wireguard::update() { + bool peer_up = this->is_peer_up(); + time_t lhs = this->get_latest_handshake(); + bool lhs_updated = (lhs > this->latest_saved_handshake_); + + ESP_LOGV(TAG, "handshake: latest=%.0f, saved=%.0f, updated=%d", (double) lhs, (double) this->latest_saved_handshake_, + (int) lhs_updated); + + if (lhs_updated) { + this->latest_saved_handshake_ = lhs; + } + + std::string latest_handshake = + (this->latest_saved_handshake_ > 0) + ? ESPTime::from_epoch_local(this->latest_saved_handshake_).strftime("%Y-%m-%d %H:%M:%S %Z") + : "timestamp not available"; + + if (peer_up) { + if (this->wg_peer_offline_time_ != 0) { + ESP_LOGI(TAG, LOGMSG_PEER_STATUS, LOGMSG_ONLINE, latest_handshake.c_str()); + this->wg_peer_offline_time_ = 0; + } else { + ESP_LOGD(TAG, LOGMSG_PEER_STATUS, LOGMSG_ONLINE, latest_handshake.c_str()); + } + } else { + if (this->wg_peer_offline_time_ == 0) { + ESP_LOGW(TAG, LOGMSG_PEER_STATUS, LOGMSG_OFFLINE, latest_handshake.c_str()); + this->wg_peer_offline_time_ = millis(); + } else { + ESP_LOGD(TAG, LOGMSG_PEER_STATUS, LOGMSG_OFFLINE, latest_handshake.c_str()); + this->start_connection_(); + } + + // check reboot timeout every time the peer is down + if (this->reboot_timeout_ > 0) { + if (millis() - this->wg_peer_offline_time_ > this->reboot_timeout_) { + ESP_LOGE(TAG, "WireGuard remote peer is unreachable, rebooting..."); + App.reboot(); + } + } + } + +#ifdef USE_BINARY_SENSOR + if (this->status_sensor_ != nullptr) { + this->status_sensor_->publish_state(peer_up); + } +#endif + +#ifdef USE_SENSOR + if (this->handshake_sensor_ != nullptr && lhs_updated) { + this->handshake_sensor_->publish_state((double) this->latest_saved_handshake_); + } +#endif +} + +void Wireguard::dump_config() { + ESP_LOGCONFIG(TAG, "WireGuard:"); + ESP_LOGCONFIG(TAG, " Address: %s", this->address_.c_str()); + ESP_LOGCONFIG(TAG, " Netmask: %s", this->netmask_.c_str()); + ESP_LOGCONFIG(TAG, " Private Key: " LOG_SECRET("%s"), mask_key(this->private_key_).c_str()); + ESP_LOGCONFIG(TAG, " Peer Endpoint: " LOG_SECRET("%s"), this->peer_endpoint_.c_str()); + ESP_LOGCONFIG(TAG, " Peer Port: " LOG_SECRET("%d"), this->peer_port_); + ESP_LOGCONFIG(TAG, " Peer Public Key: " LOG_SECRET("%s"), this->peer_public_key_.c_str()); + ESP_LOGCONFIG(TAG, " Peer Pre-shared Key: " LOG_SECRET("%s"), + (this->preshared_key_.length() > 0 ? mask_key(this->preshared_key_).c_str() : "NOT IN USE")); + ESP_LOGCONFIG(TAG, " Peer Allowed IPs:"); + for (auto &allowed_ip : this->allowed_ips_) { + ESP_LOGCONFIG(TAG, " - %s/%s", std::get<0>(allowed_ip).c_str(), std::get<1>(allowed_ip).c_str()); + } + ESP_LOGCONFIG(TAG, " Peer Persistent Keepalive: %d%s", this->keepalive_, + (this->keepalive_ > 0 ? "s" : " (DISABLED)")); + ESP_LOGCONFIG(TAG, " Reboot Timeout: %d%s", (this->reboot_timeout_ / 1000), + (this->reboot_timeout_ != 0 ? "s" : " (DISABLED)")); + // be careful: if proceed_allowed_ is true, require connection is false + ESP_LOGCONFIG(TAG, " Require Connection to Proceed: %s", (this->proceed_allowed_ ? "NO" : "YES")); + LOG_UPDATE_INTERVAL(this); +} + +void Wireguard::on_shutdown() { this->stop_connection_(); } + +bool Wireguard::can_proceed() { return (this->proceed_allowed_ || this->is_peer_up()); } + +bool Wireguard::is_peer_up() const { + return (this->wg_initialized_ == ESP_OK) && (this->wg_connected_ == ESP_OK) && + (esp_wireguardif_peer_is_up(&(this->wg_ctx_)) == ESP_OK); +} + +time_t Wireguard::get_latest_handshake() const { + time_t result; + if (esp_wireguard_latest_handshake(&(this->wg_ctx_), &result) != ESP_OK) { + result = 0; + } + return result; +} + +void Wireguard::set_address(const std::string &address) { this->address_ = address; } +void Wireguard::set_netmask(const std::string &netmask) { this->netmask_ = netmask; } +void Wireguard::set_private_key(const std::string &key) { this->private_key_ = key; } +void Wireguard::set_peer_endpoint(const std::string &endpoint) { this->peer_endpoint_ = endpoint; } +void Wireguard::set_peer_public_key(const std::string &key) { this->peer_public_key_ = key; } +void Wireguard::set_peer_port(const uint16_t port) { this->peer_port_ = port; } +void Wireguard::set_preshared_key(const std::string &key) { this->preshared_key_ = key; } + +void Wireguard::add_allowed_ip(const std::string &ip, const std::string &netmask) { + this->allowed_ips_.emplace_back(ip, netmask); +} + +void Wireguard::set_keepalive(const uint16_t seconds) { this->keepalive_ = seconds; } +void Wireguard::set_reboot_timeout(const uint32_t seconds) { this->reboot_timeout_ = seconds; } +void Wireguard::set_srctime(time::RealTimeClock *srctime) { this->srctime_ = srctime; } + +#ifdef USE_BINARY_SENSOR +void Wireguard::set_status_sensor(binary_sensor::BinarySensor *sensor) { this->status_sensor_ = sensor; } +#endif + +#ifdef USE_SENSOR +void Wireguard::set_handshake_sensor(sensor::Sensor *sensor) { this->handshake_sensor_ = sensor; } +#endif + +void Wireguard::disable_auto_proceed() { this->proceed_allowed_ = false; } + +void Wireguard::start_connection_() { + if (this->wg_initialized_ != ESP_OK) { + ESP_LOGE(TAG, "cannot start WireGuard, initialization in error with code %d", this->wg_initialized_); + return; + } + + if (!network::is_connected()) { + ESP_LOGD(TAG, "WireGuard is waiting for local network connection to be available"); + return; + } + + if (!this->srctime_->now().is_valid()) { + ESP_LOGD(TAG, "WireGuard is waiting for system time to be synchronized"); + return; + } + + if (this->wg_connected_ == ESP_OK) { + ESP_LOGV(TAG, "WireGuard connection already started"); + return; + } + + ESP_LOGD(TAG, "starting WireGuard connection..."); + + /* + * The function esp_wireguard_connect() contains a DNS resolution + * that could trigger the watchdog, so before it we suspend (or + * increase the time, it depends on the platform) the wdt and + * then we resume the normal timeout. + */ + suspend_wdt(); + ESP_LOGV(TAG, "executing esp_wireguard_connect"); + this->wg_connected_ = esp_wireguard_connect(&(this->wg_ctx_)); + resume_wdt(); + + if (this->wg_connected_ == ESP_OK) { + ESP_LOGI(TAG, "WireGuard connection started"); + } else { + ESP_LOGW(TAG, "cannot start WireGuard connection, error code %d", this->wg_connected_); + return; + } + + ESP_LOGD(TAG, "configuring WireGuard allowed IPs list..."); + bool allowed_ips_ok = true; + for (std::tuple ip : this->allowed_ips_) { + allowed_ips_ok &= + (esp_wireguard_add_allowed_ip(&(this->wg_ctx_), std::get<0>(ip).c_str(), std::get<1>(ip).c_str()) == ESP_OK); + } + + if (allowed_ips_ok) { + ESP_LOGD(TAG, "allowed IPs list configured correctly"); + } else { + ESP_LOGE(TAG, "cannot configure WireGuard allowed IPs list, aborting..."); + this->stop_connection_(); + this->mark_failed(); + } +} + +void Wireguard::stop_connection_() { + if (this->wg_initialized_ == ESP_OK && this->wg_connected_ == ESP_OK) { + ESP_LOGD(TAG, "stopping WireGuard connection..."); + esp_wireguard_disconnect(&(this->wg_ctx_)); + this->wg_connected_ = ESP_FAIL; + } +} + +void suspend_wdt() { +#if defined(USE_ESP_IDF) +#if ESP_IDF_VERSION_MAJOR >= 5 + ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15000 ms"); + esp_task_wdt_config_t wdtc; + wdtc.timeout_ms = 15000; + wdtc.idle_core_mask = 0; + wdtc.trigger_panic = false; + esp_task_wdt_reconfigure(&wdtc); +#else + ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15 seconds"); + esp_task_wdt_init(15, false); +#endif +#elif defined(USE_ARDUINO) + ESP_LOGV(TAG, "temporarily disabling the wdt"); + disableLoopWDT(); +#endif +} + +void resume_wdt() { +#if defined(USE_ESP_IDF) +#if ESP_IDF_VERSION_MAJOR >= 5 + wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; + esp_task_wdt_reconfigure(&wdtc); + ESP_LOGV(TAG, "wdt resumed with %d ms timeout", wdtc.timeout_ms); +#else + esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); + ESP_LOGV(TAG, "wdt resumed with %d seconds timeout", CONFIG_ESP_TASK_WDT_TIMEOUT_S); +#endif +#elif defined(USE_ARDUINO) + enableLoopWDT(); + ESP_LOGV(TAG, "wdt resumed"); +#endif +} + +std::string mask_key(const std::string &key) { return (key.substr(0, 5) + "[...]="); } + +} // namespace wireguard +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/wireguard/wireguard.h b/esphome/components/wireguard/wireguard.h new file mode 100644 index 0000000000..cfc5fa1a27 --- /dev/null +++ b/esphome/components/wireguard/wireguard.h @@ -0,0 +1,122 @@ +#pragma once + +#ifdef USE_ESP32 + +#include +#include +#include + +#include "esphome/core/component.h" +#include "esphome/components/time/real_time_clock.h" + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + +#include + +namespace esphome { +namespace wireguard { + +class Wireguard : public PollingComponent { + public: + void setup() override; + void loop() override; + void update() override; + void dump_config() override; + void on_shutdown() override; + bool can_proceed() override; + + float get_setup_priority() const override { return esphome::setup_priority::BEFORE_CONNECTION; } + + void set_address(const std::string &address); + void set_netmask(const std::string &netmask); + void set_private_key(const std::string &key); + void set_peer_endpoint(const std::string &endpoint); + void set_peer_public_key(const std::string &key); + void set_peer_port(uint16_t port); + void set_preshared_key(const std::string &key); + + void add_allowed_ip(const std::string &ip, const std::string &netmask); + + void set_keepalive(uint16_t seconds); + void set_reboot_timeout(uint32_t seconds); + void set_srctime(time::RealTimeClock *srctime); + +#ifdef USE_BINARY_SENSOR + void set_status_sensor(binary_sensor::BinarySensor *sensor); +#endif + +#ifdef USE_SENSOR + void set_handshake_sensor(sensor::Sensor *sensor); +#endif + + /// Block the setup step until peer is connected. + void disable_auto_proceed(); + + bool is_peer_up() const; + time_t get_latest_handshake() const; + + protected: + std::string address_; + std::string netmask_; + std::string private_key_; + std::string peer_endpoint_; + std::string peer_public_key_; + std::string preshared_key_; + + std::vector> allowed_ips_; + + uint16_t peer_port_; + uint16_t keepalive_; + uint32_t reboot_timeout_; + + time::RealTimeClock *srctime_; + +#ifdef USE_BINARY_SENSOR + binary_sensor::BinarySensor *status_sensor_ = nullptr; +#endif + +#ifdef USE_SENSOR + sensor::Sensor *handshake_sensor_ = nullptr; +#endif + + /// Set to false to block the setup step until peer is connected. + bool proceed_allowed_ = true; + + wireguard_config_t wg_config_ = ESP_WIREGUARD_CONFIG_DEFAULT(); + wireguard_ctx_t wg_ctx_ = ESP_WIREGUARD_CONTEXT_DEFAULT(); + + esp_err_t wg_initialized_ = ESP_FAIL; + esp_err_t wg_connected_ = ESP_FAIL; + + /// The last time the remote peer become offline. + uint32_t wg_peer_offline_time_ = 0; + + /** \brief The latest saved handshake. + * + * This is used to save (and log) the latest completed handshake even + * after a full refresh of the wireguard keys (for example after a + * stop/start connection cycle). + */ + time_t latest_saved_handshake_ = 0; + + void start_connection_(); + void stop_connection_(); +}; + +// These are used for possibly long DNS resolution to temporarily suspend the watchdog +void suspend_wdt(); +void resume_wdt(); + +/// Strip most part of the key only for secure printing +std::string mask_key(const std::string &key); + +} // namespace wireguard +} // namespace esphome + +#endif // USE_ESP32 diff --git a/platformio.ini b/platformio.ini index ab9584d9b8..aea164353d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -123,6 +123,7 @@ lib_deps = DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio crankyoldgit/IRremoteESP8266@2.7.12 ; heatpumpir + droscy/esp_wireguard@0.3.2 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_ESP32 @@ -141,6 +142,7 @@ framework = espidf lib_deps = ${common:idf.lib_deps} espressif/esp32-camera@1.0.0 ; esp32_camera + droscy/esp_wireguard@0.3.2 ; wireguard build_flags = ${common:idf.build_flags} -Wno-nonnull-compare diff --git a/tests/README.md b/tests/README.md index 6d83fc6886..5b312d00de 100644 --- a/tests/README.md +++ b/tests/README.md @@ -27,3 +27,4 @@ Current test_.yaml file contents. | test6.yaml | RP2040 | wifi | N/A | test7.yaml | ESP32-C3 | wifi | N/A | test8.yaml | ESP32-S3 | wifi | None +| test10.yaml | ESP32 | wifi | None diff --git a/tests/test10.yaml b/tests/test10.yaml new file mode 100644 index 0000000000..0470e37e6c --- /dev/null +++ b/tests/test10.yaml @@ -0,0 +1,48 @@ +--- +esphome: + name: test10 + build_path: build/test10 + +esp32: + board: esp32doit-devkit-v1 + framework: + type: arduino + +wifi: + ssid: "MySSID1" + password: "password1" + reboot_timeout: 3min + power_save_mode: high + +logger: + level: VERBOSE + +api: + reboot_timeout: 10min + +time: + - platform: sntp + +wireguard: + id: vpn + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' From 892d2ce34fb25332c2013ca3349f2558935734dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 11 Sep 2023 21:15:24 +0200 Subject: [PATCH 0465/2607] Bump LibreTiny version to 1.4.0 (#5375) --- esphome/components/libretiny/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index ac294d3f65..3c1c0ac3f0 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -168,9 +168,9 @@ def _notify_old_style(config): # NOTE: Keep this in mind when updating the recommended version: # * For all constants below, update platformio.ini (in this repo) ARDUINO_VERSIONS = { - "dev": (cv.Version(0, 0, 0), "https://github.com/kuba2k2/libretiny.git"), + "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"), "latest": (cv.Version(0, 0, 0), None), - "recommended": (cv.Version(1, 3, 0), None), + "recommended": (cv.Version(1, 4, 0), None), } From deb34c947314b27c9db4f49cd8771fa5c76eaf00 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Mon, 11 Sep 2023 16:02:07 -0400 Subject: [PATCH 0466/2607] time: Make std::string version of strftime() avoid runaway memory allocations (#5348) --- esphome/core/time.cpp | 5 +++++ esphome/core/time.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index bc5bfa173e..751b2a2703 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -49,6 +49,11 @@ std::string ESPTime::strftime(const std::string &format) { struct tm c_tm = this->to_c_tm(); size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); while (len == 0) { + if (timestr.size() >= 128) { + // strftime has failed for reasons unrelated to the size of the buffer + // so return a formatting error + return "ERROR"; + } timestr.resize(timestr.size() * 2); len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); } diff --git a/esphome/core/time.h b/esphome/core/time.h index e16e449f0b..14c36311e0 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -45,6 +45,10 @@ struct ESPTime { * * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some * microcontrollers. + * + * @warning This method can return "ERROR" when the underlying strftime() call fails, e.g. when the + * format string contains unsupported specifiers or when the format string doesn't produce any + * output. */ std::string strftime(const std::string &format); From d3196e0e34584bebc63b7a3a23d6403f4ceffdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20S=C3=A1rk=C3=B6zi?= Date: Mon, 11 Sep 2023 22:12:56 +0200 Subject: [PATCH 0467/2607] Fix disabled wifi crash on boot (#5370) --- esphome/components/wifi/wifi_component.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index ff621291f0..2cb36fe8ea 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -40,6 +40,9 @@ void WiFiComponent::setup() { if (this->enable_on_boot_) { this->start(); } else { +#ifdef USE_ESP32 + esp_netif_init(); +#endif this->state_ = WIFI_COMPONENT_STATE_DISABLED; } } From c930c86cfa80ca67be2f8d98ec9b1f010a7dd90a Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Mon, 11 Sep 2023 23:19:26 +0300 Subject: [PATCH 0468/2607] debug: add ESP32-C6 support (#5354) --- esphome/components/debug/debug_component.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 67b07237b7..fe66220ead 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -17,6 +17,8 @@ #include #elif defined(USE_ESP32_VARIANT_ESP32C3) #include +#elif defined(USE_ESP32_VARIANT_ESP32C6) +#include #elif defined(USE_ESP32_VARIANT_ESP32S2) #include #elif defined(USE_ESP32_VARIANT_ESP32S3) @@ -119,6 +121,8 @@ void DebugComponent::dump_config() { model = "ESP32"; #elif defined(USE_ESP32_VARIANT_ESP32C3) model = "ESP32-C3"; +#elif defined(USE_ESP32_VARIANT_ESP32C6) + model = "ESP32-C6"; #elif defined(USE_ESP32_VARIANT_ESP32S2) model = "ESP32-S2"; #elif defined(USE_ESP32_VARIANT_ESP32S3) @@ -202,9 +206,11 @@ void DebugComponent::dump_config() { case RTCWDT_SYS_RESET: reset_reason = "RTC Watch Dog Reset Digital Core"; break; +#if !defined(USE_ESP32_VARIANT_ESP32C6) case INTRUSION_RESET: reset_reason = "Intrusion Reset CPU"; break; +#endif #if defined(USE_ESP32_VARIANT_ESP32) case TGWDT_CPU_RESET: reset_reason = "Timer Group Reset CPU"; From 10eee47b6bd4f4032226aaf009b7339ec642d0fa Mon Sep 17 00:00:00 2001 From: Daniel Dunn Date: Mon, 11 Sep 2023 15:26:00 -0600 Subject: [PATCH 0469/2607] Make string globals persist-able using fixed size allocations (#5296) Co-authored-by: Daniel Dunn --- esphome/components/globals/__init__.py | 20 ++++++- .../components/globals/globals_component.h | 59 +++++++++++++++++++ esphome/cpp_generator.py | 7 ++- tests/test2.yaml | 7 +++ 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/esphome/components/globals/__init__.py b/esphome/components/globals/__init__.py index 97a7ba3d54..8defa4ac24 100644 --- a/esphome/components/globals/__init__.py +++ b/esphome/components/globals/__init__.py @@ -15,8 +15,14 @@ CODEOWNERS = ["@esphome/core"] globals_ns = cg.esphome_ns.namespace("globals") GlobalsComponent = globals_ns.class_("GlobalsComponent", cg.Component) RestoringGlobalsComponent = globals_ns.class_("RestoringGlobalsComponent", cg.Component) +RestoringGlobalStringComponent = globals_ns.class_( + "RestoringGlobalStringComponent", cg.Component +) GlobalVarSetAction = globals_ns.class_("GlobalVarSetAction", automation.Action) +CONF_MAX_RESTORE_DATA_LENGTH = "max_restore_data_length" + + MULTI_CONF = True CONFIG_SCHEMA = cv.Schema( { @@ -24,6 +30,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Required(CONF_TYPE): cv.string_strict, cv.Optional(CONF_INITIAL_VALUE): cv.string_strict, cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, + cv.Optional(CONF_MAX_RESTORE_DATA_LENGTH): cv.int_range(0, 254), } ).extend(cv.COMPONENT_SCHEMA) @@ -32,12 +39,19 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(-100.0) async def to_code(config): type_ = cg.RawExpression(config[CONF_TYPE]) - template_args = cg.TemplateArguments(type_) restore = config[CONF_RESTORE_VALUE] - type = RestoringGlobalsComponent if restore else GlobalsComponent - res_type = type.template(template_args) + # Special casing the strings to their own class with a different save/restore mechanism + if str(type_) == "std::string" and restore: + template_args = cg.TemplateArguments( + type_, config.get(CONF_MAX_RESTORE_DATA_LENGTH, 63) + 1 + ) + type = RestoringGlobalStringComponent + else: + template_args = cg.TemplateArguments(type_) + type = RestoringGlobalsComponent if restore else GlobalsComponent + res_type = type.template(template_args) initial_value = None if CONF_INITIAL_VALUE in config: initial_value = cg.RawExpression(config[CONF_INITIAL_VALUE]) diff --git a/esphome/components/globals/globals_component.h b/esphome/components/globals/globals_component.h index 101adeb311..78808436af 100644 --- a/esphome/components/globals/globals_component.h +++ b/esphome/components/globals/globals_component.h @@ -65,6 +65,64 @@ template class RestoringGlobalsComponent : public Component { ESPPreferenceObject rtc_; }; +// Use with string or subclasses of strings +template class RestoringGlobalStringComponent : public Component { + public: + using value_type = T; + explicit RestoringGlobalStringComponent() = default; + explicit RestoringGlobalStringComponent(T initial_value) { this->value_ = initial_value; } + explicit RestoringGlobalStringComponent( + std::array::type, std::extent::value> initial_value) { + memcpy(this->value_, initial_value.data(), sizeof(T)); + } + + T &value() { return this->value_; } + + void setup() override { + char temp[SZ]; + this->rtc_ = global_preferences->make_preference(1944399030U ^ this->name_hash_); + bool hasdata = this->rtc_.load(&temp); + if (hasdata) { + this->value_.assign(temp + 1, temp[0]); + } + this->prev_value_.assign(this->value_); + } + + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + void loop() override { store_value_(); } + + void on_shutdown() override { store_value_(); } + + void set_name_hash(uint32_t name_hash) { this->name_hash_ = name_hash; } + + protected: + void store_value_() { + int diff = this->value_.compare(this->prev_value_); + if (diff != 0) { + // Make it into a length prefixed thing + unsigned char temp[SZ]; + + // If string is bigger than the allocation, do not save it. + // We don't need to waste ram setting prev_value either. + int size = this->value_.size(); + // Less than, not less than or equal, SZ includes the length byte. + if (size < SZ) { + memcpy(temp + 1, this->value_.c_str(), size); + // SZ should be pre checked at the schema level, it can't go past the char range. + temp[0] = ((unsigned char) size); + this->rtc_.save(&temp); + this->prev_value_.assign(this->value_); + } + } + } + + T value_{}; + T prev_value_{}; + uint32_t name_hash_{}; + ESPPreferenceObject rtc_; +}; + template class GlobalVarSetAction : public Action { public: explicit GlobalVarSetAction(C *parent) : parent_(parent) {} @@ -81,6 +139,7 @@ template class GlobalVarSetAction : public Action T &id(GlobalsComponent *value) { return value->value(); } template T &id(RestoringGlobalsComponent *value) { return value->value(); } +template T &id(RestoringGlobalStringComponent *value) { return value->value(); } } // namespace globals } // namespace esphome diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 789bd58e5c..2841be1546 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -663,7 +663,11 @@ async def process_lambda( :param return_type: The return type of the lambda. :return: The generated lambda expression. """ - from esphome.components.globals import GlobalsComponent, RestoringGlobalsComponent + from esphome.components.globals import ( + GlobalsComponent, + RestoringGlobalsComponent, + RestoringGlobalStringComponent, + ) if value is None: return @@ -676,6 +680,7 @@ async def process_lambda( and ( full_id.type.inherits_from(GlobalsComponent) or full_id.type.inherits_from(RestoringGlobalsComponent) + or full_id.type.inherits_from(RestoringGlobalStringComponent) ) ): parts[i * 3 + 1] = var.value() diff --git a/tests/test2.yaml b/tests/test2.yaml index 4928b8b877..c04e6726b1 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -5,6 +5,13 @@ esphome: board: nodemcu-32s build_path: build/test2 +globals: + - id: my_global_string + type: std::string + restore_value: yes + max_restore_data_length: 70 + initial_value: '"DefaultValue"' + substitutions: devicename: test2 From fe81bcc00343ba8d99a437762087717d45a20946 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:26:48 +1200 Subject: [PATCH 0470/2607] Use /data directory for .esphome folder when running as HA add-on (#5374) --- .../etc/s6-overlay/s6-rc.d/esphome/run | 7 ++++++- esphome/components/font/__init__.py | 3 +-- esphome/components/image/__init__.py | 2 +- esphome/components/shelly_dimmer/light.py | 7 +------ esphome/core/__init__.py | 12 +++++++----- esphome/core/config.py | 4 ++-- esphome/dashboard/dashboard.py | 19 +++++++++---------- esphome/git.py | 2 +- esphome/storage_json.py | 14 +++++++------- esphome/wizard.py | 19 +++++++++++-------- tests/unit_tests/test_wizard.py | 7 +++++++ 11 files changed, 53 insertions(+), 43 deletions(-) diff --git a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run index 277f26ea49..775c2fa0d6 100755 --- a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run +++ b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run @@ -35,11 +35,16 @@ if bashio::config.has_value 'default_compile_process_limit'; then export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit') else if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then - export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1; + export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1 fi fi mkdir -p "${pio_cache_base}" +if bashio::fs.directory_exists '/config/esphome/.esphome'; then + bashio::log.info "Removing old .esphome directory..." + rm -rf /config/esphome/.esphome +fi + bashio::log.info "Starting ESPHome dashboard..." exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 52f877d986..e6244d8d44 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -98,10 +98,9 @@ def validate_truetype_file(value): def _compute_local_font_dir(name) -> Path: - base_dir = Path(CORE.config_dir) / ".esphome" / DOMAIN h = hashlib.new("sha256") h.update(name.encode()) - return base_dir / h.hexdigest()[:8] + return Path(CORE.data_dir) / DOMAIN / h.hexdigest()[:8] def _compute_gfonts_local_path(value) -> Path: diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 392efb18a2..aa402ee329 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -52,7 +52,7 @@ Image_ = image_ns.class_("Image") def _compute_local_icon_path(value) -> Path: - base_dir = Path(CORE.config_dir) / ".esphome" / DOMAIN / "mdi" + base_dir = Path(CORE.data_dir) / DOMAIN / "mdi" return base_dir / f"{value[CONF_ICON]}.svg" diff --git a/esphome/components/shelly_dimmer/light.py b/esphome/components/shelly_dimmer/light.py index c49193d135..467a3c3531 100644 --- a/esphome/components/shelly_dimmer/light.py +++ b/esphome/components/shelly_dimmer/light.py @@ -87,12 +87,7 @@ def get_firmware(value): url = value[CONF_URL] if CONF_SHA256 in value: # we have a hash, enable caching - path = ( - Path(CORE.config_dir) - / ".esphome" - / DOMAIN - / (value[CONF_SHA256] + "_fw_stm.bin") - ) + path = Path(CORE.data_dir) / DOMAIN / (value[CONF_SHA256] + "_fw_stm.bin") if not path.is_file(): firmware_data, dl_hash = dl(url) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index d9b1603894..cca758e3c1 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -554,6 +554,12 @@ class EsphomeCore: def config_dir(self): return os.path.dirname(self.config_path) + @property + def data_dir(self): + if is_ha_addon(): + return os.path.join("/data") + return self.relative_config_path(".esphome") + @property def config_filename(self): return os.path.basename(self.config_path) @@ -563,7 +569,7 @@ class EsphomeCore: return os.path.join(self.config_dir, path_) def relative_internal_path(self, *path: str) -> str: - return self.relative_config_path(".esphome", *path) + return os.path.join(self.data_dir, *path) def relative_build_path(self, *path): path_ = os.path.expanduser(os.path.join(*path)) @@ -573,13 +579,9 @@ class EsphomeCore: return self.relative_build_path("src", *path) def relative_pioenvs_path(self, *path): - if is_ha_addon(): - return os.path.join("/data", self.name, ".pioenvs", *path) return self.relative_build_path(".pioenvs", *path) def relative_piolibdeps_path(self, *path): - if is_ha_addon(): - return os.path.join("/data", self.name, ".piolibdeps", *path) return self.relative_build_path(".piolibdeps", *path) @property diff --git a/esphome/core/config.py b/esphome/core/config.py index a09252e4b4..1625644092 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -198,8 +198,8 @@ def preload_core_config(config, result): CORE.data[KEY_CORE] = {} if CONF_BUILD_PATH not in conf: - conf[CONF_BUILD_PATH] = f".esphome/build/{CORE.name}" - CORE.build_path = CORE.relative_config_path(conf[CONF_BUILD_PATH]) + conf[CONF_BUILD_PATH] = f"build/{CORE.name}" + CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH]) has_oldstyle = CONF_PLATFORM in conf newstyle_found = [key for key in TARGET_PLATFORMS if key in config] diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index cacd5e2db0..8049fb7f4c 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -32,6 +32,7 @@ import yaml from tornado.log import access_log from esphome import const, platformio_api, util, yaml_util +from esphome.core import CORE from esphome.helpers import get_bool_env, mkdir_p, run_system_command from esphome.storage_json import ( EsphomeStorageJSON, @@ -70,6 +71,7 @@ class DashboardSettings: self.password_hash = password_hash(password) self.config_dir = args.configuration self.absolute_config_dir = Path(self.config_dir).resolve() + CORE.config_path = os.path.join(self.config_dir, ".") @property def relative_url(self): @@ -534,7 +536,7 @@ class DownloadListRequestHandler(BaseHandler): @authenticated @bind_config def get(self, configuration=None): - storage_path = ext_storage_path(settings.config_dir, configuration) + storage_path = ext_storage_path(configuration) storage_json = StorageJSON.load(storage_path) if storage_json is None: self.send_error(404) @@ -577,7 +579,7 @@ class DownloadBinaryRequestHandler(BaseHandler): def get(self, configuration=None): compressed = self.get_argument("compressed", "0") == "1" - storage_path = ext_storage_path(settings.config_dir, configuration) + storage_path = ext_storage_path(configuration) storage_json = StorageJSON.load(storage_path) if storage_json is None: self.send_error(404) @@ -666,9 +668,7 @@ class DashboardEntry: @property def storage(self) -> Optional[StorageJSON]: if not self._loaded_storage: - self._storage = StorageJSON.load( - ext_storage_path(settings.config_dir, self.filename) - ) + self._storage = StorageJSON.load(ext_storage_path(self.filename)) self._loaded_storage = True return self._storage @@ -1044,9 +1044,9 @@ class DeleteRequestHandler(BaseHandler): @bind_config def post(self, configuration=None): config_file = settings.rel_path(configuration) - storage_path = ext_storage_path(settings.config_dir, configuration) + storage_path = ext_storage_path(configuration) - trash_path = trash_storage_path(settings.config_dir) + trash_path = trash_storage_path() mkdir_p(trash_path) shutil.move(config_file, os.path.join(trash_path, configuration)) @@ -1067,7 +1067,7 @@ class UndoDeleteRequestHandler(BaseHandler): @bind_config def post(self, configuration=None): config_file = settings.rel_path(configuration) - trash_path = trash_storage_path(settings.config_dir) + trash_path = trash_storage_path() shutil.move(os.path.join(trash_path, configuration), config_file) @@ -1325,10 +1325,9 @@ def make_app(debug=get_bool_env(ENV_DEV)): def start_web_server(args): settings.parse_args(args) - mkdir_p(settings.rel_path(".esphome")) if settings.using_auth: - path = esphome_storage_path(settings.config_dir) + path = esphome_storage_path() storage = EsphomeStorageJSON.load(path) if storage is None: storage = EsphomeStorageJSON.get_default() diff --git a/esphome/git.py b/esphome/git.py index dcc3e4d0c8..4f0911233e 100644 --- a/esphome/git.py +++ b/esphome/git.py @@ -35,7 +35,7 @@ def run_git_command(cmd, cwd=None) -> str: def _compute_destination_path(key: str, domain: str) -> Path: - base_dir = Path(CORE.config_dir) / ".esphome" / domain + base_dir = Path(CORE.data_dir) / domain h = hashlib.new("sha256") h.update(key.encode()) return base_dir / h.hexdigest()[:8] diff --git a/esphome/storage_json.py b/esphome/storage_json.py index acf525203d..a2619cb536 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -22,19 +22,19 @@ _LOGGER = logging.getLogger(__name__) def storage_path() -> str: - return CORE.relative_internal_path(f"{CORE.config_filename}.json") + return os.path.join(CORE.data_dir, "storage", f"{CORE.config_filename}.json") -def ext_storage_path(base_path: str, config_filename: str) -> str: - return os.path.join(base_path, ".esphome", f"{config_filename}.json") +def ext_storage_path(config_filename: str) -> str: + return os.path.join(CORE.data_dir, "storage", f"{config_filename}.json") -def esphome_storage_path(base_path: str) -> str: - return os.path.join(base_path, ".esphome", "esphome.json") +def esphome_storage_path() -> str: + return os.path.join(CORE.data_dir, "esphome.json") -def trash_storage_path(base_path: str) -> str: - return os.path.join(base_path, ".esphome", "trash") +def trash_storage_path() -> str: + return CORE.relative_config_path("trash") class StorageJSON: diff --git a/esphome/wizard.py b/esphome/wizard.py index 17a0882e1c..aa05e513a7 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -6,12 +6,12 @@ import unicodedata import voluptuous as vol import esphome.config_validation as cv +from esphome.const import ALLOWED_NAME_CHARS, ENV_QUICKWIZARD +from esphome.core import CORE from esphome.helpers import get_bool_env, write_file -from esphome.log import color, Fore - +from esphome.log import Fore, color from esphome.storage_json import StorageJSON, ext_storage_path from esphome.util import safe_print -from esphome.const import ALLOWED_NAME_CHARS, ENV_QUICKWIZARD CORE_BIG = r""" _____ ____ _____ ______ / ____/ __ \| __ \| ____| @@ -193,10 +193,10 @@ captive_portal: def wizard_write(path, **kwargs): - from esphome.components.esp8266 import boards as esp8266_boards - from esphome.components.esp32 import boards as esp32_boards - from esphome.components.rp2040 import boards as rp2040_boards from esphome.components.bk72xx import boards as bk72xx_boards + from esphome.components.esp32 import boards as esp32_boards + from esphome.components.esp8266 import boards as esp8266_boards + from esphome.components.rp2040 import boards as rp2040_boards from esphome.components.rtl87xx import boards as rtl87xx_boards name = kwargs["name"] @@ -225,7 +225,7 @@ def wizard_write(path, **kwargs): write_file(path, wizard_file(**kwargs)) storage = StorageJSON.from_wizard(name, name, f"{name}.local", hardware) - storage_path = ext_storage_path(os.path.dirname(path), os.path.basename(path)) + storage_path = ext_storage_path(os.path.basename(path)) storage.save(storage_path) return True @@ -265,9 +265,9 @@ def strip_accents(value): def wizard(path): + from esphome.components.bk72xx import boards as bk72xx_boards from esphome.components.esp32 import boards as esp32_boards from esphome.components.esp8266 import boards as esp8266_boards - from esphome.components.bk72xx import boards as bk72xx_boards from esphome.components.rtl87xx import boards as rtl87xx_boards if not path.endswith(".yaml") and not path.endswith(".yml"): @@ -280,6 +280,9 @@ def wizard(path): f"Uh oh, it seems like {color(Fore.CYAN, path)} already exists, please delete that file first or chose another configuration file." ) return 2 + + CORE.config_path = path + safe_print("Hi there!") sleep(1.5) safe_print("I'm the wizard of ESPHome :)") diff --git a/tests/unit_tests/test_wizard.py b/tests/unit_tests/test_wizard.py index d94624d1e4..8bbce08ae5 100644 --- a/tests/unit_tests/test_wizard.py +++ b/tests/unit_tests/test_wizard.py @@ -1,7 +1,9 @@ """Tests for the wizard.py file.""" +import os import esphome.wizard as wz import pytest +from esphome.core import CORE from esphome.components.esp8266.boards import ESP8266_BOARD_PINS from esphome.components.esp32.boards import ESP32_BOARD_PINS from esphome.components.bk72xx.boards import BK72XX_BOARD_PINS @@ -110,6 +112,7 @@ def test_wizard_write_sets_platform(default_config, tmp_path, monkeypatch): # Given del default_config["platform"] monkeypatch.setattr(wz, "write_file", MagicMock()) + monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path)) # When wz.wizard_write(tmp_path, **default_config) @@ -130,6 +133,7 @@ def test_wizard_write_defaults_platform_from_board_esp8266( default_config["board"] = [*ESP8266_BOARD_PINS][0] monkeypatch.setattr(wz, "write_file", MagicMock()) + monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path)) # When wz.wizard_write(tmp_path, **default_config) @@ -150,6 +154,7 @@ def test_wizard_write_defaults_platform_from_board_esp32( default_config["board"] = [*ESP32_BOARD_PINS][0] monkeypatch.setattr(wz, "write_file", MagicMock()) + monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path)) # When wz.wizard_write(tmp_path, **default_config) @@ -170,6 +175,7 @@ def test_wizard_write_defaults_platform_from_board_bk72xx( default_config["board"] = [*BK72XX_BOARD_PINS][0] monkeypatch.setattr(wz, "write_file", MagicMock()) + monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path)) # When wz.wizard_write(tmp_path, **default_config) @@ -190,6 +196,7 @@ def test_wizard_write_defaults_platform_from_board_rtl87xx( default_config["board"] = [*RTL87XX_BOARD_PINS][0] monkeypatch.setattr(wz, "write_file", MagicMock()) + monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path)) # When wz.wizard_write(tmp_path, **default_config) From e6da2313e69a1da4d1673ea28e5441fe189862fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:02:13 +1200 Subject: [PATCH 0471/2607] Bump zeroconf from 0.102.0 to 0.108.0 (#5376) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9bce4a309d..19c05bf8f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.102.0 +zeroconf==0.108.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 47b1b458284dd1d3e7bbf2a8bd196a5b2f4ac64a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 22:38:58 +0000 Subject: [PATCH 0472/2607] Bump black from 23.7.0 to 23.9.1 (#5377) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0bbb2fee61..6e7261ebc3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.7.0 + rev: 23.9.1 hooks: - id: black args: diff --git a/requirements_test.txt b/requirements_test.txt index f17ccd220d..a07815df54 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.17.5 flake8==6.1.0 # also change in .pre-commit-config.yaml when updating -black==23.7.0 # also change in .pre-commit-config.yaml when updating +black==23.9.1 # also change in .pre-commit-config.yaml when updating pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating pre-commit From fc354eec0e6377d4faf0dcb7c160da5cc4e76228 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:14:10 +1200 Subject: [PATCH 0473/2607] Attempt to fix rp2040 adc with vcc (#5378) --- esphome/components/adc/__init__.py | 9 ++--- esphome/components/adc/adc_sensor.cpp | 55 +++++++++++++-------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 0b6ee145f2..bad5cf74ef 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -5,10 +5,7 @@ from esphome.const import CONF_ANALOG, CONF_INPUT from esphome.core import CORE from esphome.components.esp32 import get_esp32_variant -from esphome.const import ( - PLATFORM_ESP8266, - PLATFORM_RP2040, -) +from esphome.const import PLATFORM_ESP8266 from esphome.components.esp32.const import ( VARIANT_ESP32, VARIANT_ESP32C2, @@ -147,7 +144,9 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = { def validate_adc_pin(value): if str(value).upper() == "VCC": - return cv.only_on([PLATFORM_ESP8266, PLATFORM_RP2040])("VCC") + if CORE.is_rp2040: + return pins.internal_gpio_input_pin_schema(29) + return cv.only_on([PLATFORM_ESP8266])("VCC") if str(value).upper() == "TEMPERATURE": return cv.only_on_rp2040("TEMPERATURE") diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index e69e6b9313..a9ac5a5cfe 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -1,6 +1,6 @@ #include "adc_sensor.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP8266 #ifdef USE_ADC_SENSOR_VCC @@ -246,45 +246,42 @@ float ADCSensor::sample() { adc_set_temp_sensor_enabled(true); delay(1); adc_select_input(4); + + int32_t raw = adc_read(); + adc_set_temp_sensor_enabled(false); + if (this->output_raw_) { + return raw; + } + return raw * 3.3f / 4096.0f; } else { - uint8_t pin; -#ifdef USE_ADC_SENSOR_VCC + uint8_t pin = this->pin_->get_pin(); #ifdef CYW43_USES_VSYS_PIN - // Measuring VSYS on Raspberry Pico W needs to be wrapped with - // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in - // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and - // VSYS ADC both share GPIO29 - cyw43_thread_enter(); + if (pin == PICO_VSYS_PIN) { + // Measuring VSYS on Raspberry Pico W needs to be wrapped with + // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in + // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and + // VSYS ADC both share GPIO29 + cyw43_thread_enter(); + } #endif // CYW43_USES_VSYS_PIN - pin = PICO_VSYS_PIN; -#else - pin = this->pin_->get_pin(); -#endif // USE_ADC_SENSOR_VCC adc_gpio_init(pin); adc_select_input(pin - 26); - } - int32_t raw = adc_read(); - if (this->is_temperature_) { - adc_set_temp_sensor_enabled(false); - } else { -#ifdef USE_ADC_SENSOR_VCC + int32_t raw = adc_read(); + #ifdef CYW43_USES_VSYS_PIN - cyw43_thread_exit(); + if (pin == PICO_VSYS_PIN) { + cyw43_thread_exit(); + } #endif // CYW43_USES_VSYS_PIN -#endif // USE_ADC_SENSOR_VCC - } - if (output_raw_) { - return raw; + if (output_raw_) { + return raw; + } + float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0; + return raw * 3.3f / 4096.0f * coeff; } - float coeff = 1.0; -#ifdef USE_ADC_SENSOR_VCC - // As per Raspberry Pico (W) datasheet (section 2.1) the VSYS/3 is measured - coeff = 3.0; -#endif // USE_ADC_SENSOR_VCC - return raw * 3.3f / 4096.0f * coeff; } #endif From dadbc1aefa267d1868aa189da6a3ee16bb318674 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 12 Sep 2023 22:05:02 +0200 Subject: [PATCH 0474/2607] Enable IPv6 for ESP8266 and Raspberry pi pico w (RP2040) (#4759) --- esphome/components/async_tcp/__init__.py | 2 +- esphome/components/mdns/mdns_esp8266.cpp | 3 +- esphome/components/mqtt/__init__.py | 4 +-- esphome/components/mqtt/mqtt_client.cpp | 10 ------- esphome/components/network/__init__.py | 29 ++++++++++--------- esphome/components/socket/socket.cpp | 2 +- .../wifi/wifi_component_esp8266.cpp | 17 +++++++++-- .../components/wifi/wifi_component_pico_w.cpp | 4 +++ platformio.ini | 4 +-- 9 files changed, 41 insertions(+), 34 deletions(-) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index 1677d4b9a8..fa74f7103f 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -19,4 +19,4 @@ async def to_code(config): cg.add_library("esphome/AsyncTCP-esphome", "2.0.1") elif CORE.is_esp8266: # https://github.com/esphome/ESPAsyncTCP - cg.add_library("esphome/ESPAsyncTCP-esphome", "1.2.3") + cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0") diff --git a/esphome/components/mdns/mdns_esp8266.cpp b/esphome/components/mdns/mdns_esp8266.cpp index 4ccfe42baa..5ff1b86341 100644 --- a/esphome/components/mdns/mdns_esp8266.cpp +++ b/esphome/components/mdns/mdns_esp8266.cpp @@ -13,8 +13,7 @@ namespace mdns { void MDNSComponent::setup() { this->compile_records_(); - network::IPAddress addr = network::get_ip_address(); - MDNS.begin(this->hostname_.c_str(), (uint32_t) addr); + MDNS.begin(this->hostname_.c_str()); for (const auto &service : this->services_) { // Strip the leading underscore from the proto and service_type. While it is diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 102c070eb6..9df2067832 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -273,8 +273,8 @@ async def to_code(config): await cg.register_component(var, config) # Add required libraries for ESP8266 if CORE.is_esp8266: - # https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json - cg.add_library("ottowinter/AsyncMqttClient-esphome", "0.8.6") + # https://github.com/heman/async-mqtt-client/blob/master/library.json + cg.add_library("heman/AsyncMqttClient-esphome", "1.0.0") cg.add_define("USE_MQTT") cg.add_global(mqtt_ns.using) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 1d804170f6..0c6da42328 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -168,15 +168,10 @@ void MQTTClientComponent::start_dnslookup_() { case ERR_OK: { // Got IP immediately this->dns_resolved_ = true; -#ifdef USE_ESP32 #if LWIP_IPV6 this->ip_ = addr.u_addr.ip4.addr; #else this->ip_ = addr.addr; -#endif -#endif -#ifdef USE_ESP8266 - this->ip_ = addr.addr; #endif this->start_connect_(); return; @@ -228,15 +223,10 @@ void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t * if (ipaddr == nullptr) { a_this->dns_resolve_error_ = true; } else { -#ifdef USE_ESP32 #if LWIP_IPV6 a_this->ip_ = ipaddr->u_addr.ip4.addr; #else a_this->ip_ = ipaddr->addr; -#endif -#endif // USE_ESP32 -#ifdef USE_ESP8266 - a_this->ip_ = ipaddr->addr; #endif a_this->dns_resolved_ = true; } diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 83778e0bf4..dd1353f86f 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -15,22 +15,23 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.SplitDefault(CONF_ENABLE_IPV6, esp32=False): cv.All( - cv.only_on_esp32, cv.boolean - ), + cv.Optional(CONF_ENABLE_IPV6, default=False): cv.boolean, } ) async def to_code(config): - if CONF_ENABLE_IPV6 in config: - cg.add_define("ENABLE_IPV6", config[CONF_ENABLE_IPV6]) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] - ) - else: - if config[CONF_ENABLE_IPV6]: - cg.add_build_flag("-DCONFIG_LWIP_IPV6") - cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") + cg.add_define("ENABLE_IPV6", config[CONF_ENABLE_IPV6]) + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) + else: + if config[CONF_ENABLE_IPV6]: + cg.add_build_flag("-DCONFIG_LWIP_IPV6") + cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") + if CORE.is_rp2040: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") + if CORE.is_esp8266: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 4c78397873..824e04150b 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -60,7 +60,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po memset(server, 0, sizeof(sockaddr_in6)); server->sin6_family = AF_INET6; server->sin6_port = htons(port); - server->sin6_addr = in6addr_any; + server->sin6_addr = IN6ADDR_ANY_INIT; return sizeof(sockaddr_in6); #else if (addrlen < sizeof(sockaddr_in)) { diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index a28aa8b858..1afa439567 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -19,6 +19,7 @@ extern "C" { #include "lwip/apps/sntp.h" #if LWIP_IPV6 #include "lwip/netif.h" // struct netif +#include #endif #if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0) #include "LwipDhcpServer.h" @@ -164,11 +165,11 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { ip_addr_t dns; if (uint32_t(manual_ip->dns1) != 0) { - dns.addr = static_cast(manual_ip->dns1); + ip_addr_set_ip4_u32_val(dns, static_cast(manual_ip->dns1)); dns_setserver(0, &dns); } if (uint32_t(manual_ip->dns2) != 0) { - dns.addr = static_cast(manual_ip->dns2); + ip_addr_set_ip4_u32_val(dns, static_cast(manual_ip->dns2)); dns_setserver(1, &dns); } @@ -325,6 +326,18 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { return false; } +#if ENABLE_IPV6 + for (bool configured = false; !configured;) { + for (auto addr : addrList) { + ESP_LOGV(TAG, "Address %s", addr.toString().c_str()); + if ((configured = !addr.isLocal() && addr.isV6())) { + break; + } + } + delay(500); // NOLINT + } +#endif + if (ap.get_channel().has_value()) { ret = wifi_set_channel(*ap.get_channel()); if (!ret) { diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 489ebc3699..149ca61cd5 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -175,7 +175,11 @@ network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask( network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { const ip_addr_t *dns_ip = dns_getserver(num); +#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_IPV6 + return {dns_ip->u_addr.ip4.addr}; +#else return {dns_ip->addr}; +#endif } void WiFiComponent::wifi_loop_() { diff --git a/platformio.ini b/platformio.ini index aea164353d..73cd7c65c8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -57,6 +57,7 @@ lib_deps = ${common.lib_deps} SPI ; spi (Arduino built-in) Wire ; i2c (Arduino built-int) + heman/AsyncMqttClient-esphome@1.0.0 ; mqtt esphome/ESPAsyncWebServer-esphome@2.1.0 ; web_server_base fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps @@ -88,8 +89,7 @@ lib_deps = ${common:arduino.lib_deps} ESP8266WiFi ; wifi (Arduino built-in) Update ; ota (Arduino built-in) - ottowinter/AsyncMqttClient-esphome@0.8.6 ; mqtt - esphome/ESPAsyncTCP-esphome@1.2.3 ; async_tcp + esphome/ESPAsyncTCP-esphome@2.0.0 ; async_tcp ESP8266HTTPClient ; http_request (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) From bff74af882d52e515798284b70ea4b5e3d9b16b4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:06:32 +1200 Subject: [PATCH 0475/2607] Workflow updates (#5384) --- .github/actions/restore-python/action.yml | 4 +-- .github/workflows/ci-docker.yml | 8 ++--- .github/workflows/ci.yml | 38 +++++++++-------------- .github/workflows/lock.yml | 2 +- .github/workflows/release.yml | 22 ++++++------- .github/workflows/stale.yml | 4 +-- .github/workflows/sync-device-classes.yml | 11 +++---- .github/workflows/yaml-lint.yml | 22 +++++++++++++ 8 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/yaml-lint.yml diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index c6e9ca4153..aa8dd6d894 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -17,12 +17,12 @@ runs: steps: - name: Set up Python ${{ inputs.python-version }} id: python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.7.0 with: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v3.3.1 + uses: actions/cache/restore@v3.3.2 with: path: venv # yamllint disable-line rule:line-length diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index dbd0d573da..b53eaf8e1a 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,15 +40,15 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.0.0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.7.0 with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3.0.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3.0.0 - name: Set TAG run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79ebe8782e..0786e1b9a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: branches: [dev, beta, release] pull_request: + paths: + - "**" + - "!.github/workflows/*.yml" + - ".github/workflows/ci.yml" merge_group: permissions: @@ -30,13 +34,13 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.7.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment @@ -55,15 +59,6 @@ jobs: pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt pip install -e . - yamllint: - name: yamllint - runs-on: ubuntu-latest - steps: - - name: Check out code from GitHub - uses: actions/checkout@v4 - - name: Run yamllint - uses: frenck/action-yamllint@v1.4.1 - black: name: Check black runs-on: ubuntu-latest @@ -71,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -92,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -113,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -134,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -155,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -176,7 +171,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -196,7 +191,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -227,7 +222,6 @@ jobs: - pylint - pytest - pyupgrade - - yamllint strategy: fail-fast: false max-parallel: 2 @@ -235,7 +229,7 @@ jobs: file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 10] steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -258,7 +252,6 @@ jobs: - pylint - pytest - pyupgrade - - yamllint strategy: fail-fast: false max-parallel: 2 @@ -291,7 +284,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -337,7 +330,6 @@ jobs: - pylint - pytest - pyupgrade - - yamllint - compile-tests - clang-tidy if: always() diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index e762512ff6..b455e3f4ea 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -18,7 +18,7 @@ jobs: lock: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v4 + - uses: dessant/lock-threads@v4.0.1 with: pr-inactive-days: "1" pr-lock-reason: "" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71a0cd2c78..99d1594f03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: outputs: tag: ${{ steps.tag.outputs.tag }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.0.0 - name: Get tag id: tag # yamllint disable rule:line-length @@ -43,9 +43,9 @@ jobs: if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.0.0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.7.0 with: python-version: "3.x" - name: Set up python environment @@ -88,24 +88,24 @@ jobs: target: "lint" baseimg: "docker" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.0.0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.7.0 with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3.0.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3.0.0 - name: Log in to docker hub - uses: docker/login-action@v2 + uses: docker/login-action@v3.0.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3.0.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -119,7 +119,7 @@ jobs: --suffix "${{ matrix.image.suffix }}" - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5.0.0 with: context: . file: ./docker/Dockerfile @@ -141,7 +141,7 @@ jobs: needs: [deploy-docker] steps: - name: Trigger Workflow - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }} script: | diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3a3e390eef..a2d3f2f77d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,7 +18,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v8.0.0 with: days-before-pr-stale: 90 days-before-pr-close: 7 @@ -38,7 +38,7 @@ jobs: close-issues: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v8.0.0 with: days-before-pr-stale: -1 days-before-pr-close: -1 diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 1759db962c..943e93a0b7 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -4,8 +4,7 @@ name: Synchronise Device Classes from Home Assistant on: workflow_dispatch: schedule: - - cron: '45 6 * * *' - + - cron: "45 6 * * *" jobs: sync: @@ -14,16 +13,16 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 - name: Checkout Home Assistant - uses: actions/checkout@v4 + uses: actions/checkout@v4.0.0 with: repository: home-assistant/core path: lib/home-assistant - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.7.0 with: python-version: 3.11 @@ -37,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v5.0.2 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml new file mode 100644 index 0000000000..77b3c1dcb5 --- /dev/null +++ b/.github/workflows/yaml-lint.yml @@ -0,0 +1,22 @@ +name: YAML lint + +on: + push: + branches: [dev, beta, release] + paths: + - "**.yaml" + - "**.yml" + pull_request: + paths: + - "**.yaml" + - "**.yml" + +jobs: + yamllint: + name: yamllint + runs-on: ubuntu-latest + steps: + - name: Check out code from GitHub + uses: actions/checkout@v4.0.0 + - name: Run yamllint + uses: frenck/action-yamllint@v1.4.1 From bf5352b44ee84f6880935fcc011be4df7edf4863 Mon Sep 17 00:00:00 2001 From: Tercio Filho Date: Tue, 12 Sep 2023 19:15:01 -0300 Subject: [PATCH 0476/2607] Modbus Controller added some features (#5318) --- .../components/modbus_controller/__init__.py | 5 +++- esphome/components/modbus_controller/const.py | 1 + .../modbus_controller/modbus_controller.cpp | 23 +++++++++++++++++++ .../modbus_controller/modbus_controller.h | 13 ++++++++--- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 46bb2c4233..8703771c3a 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -8,6 +8,7 @@ from .const import ( CONF_BITMASK, CONF_BYTE_OFFSET, CONF_COMMAND_THROTTLE, + CONF_OFFLINE_SKIP_UPDATES, CONF_CUSTOM_COMMAND, CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, @@ -104,6 +105,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional( CONF_COMMAND_THROTTLE, default="0ms" ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int, } ) .extend(cv.polling_component_schema("60s")) @@ -206,8 +208,9 @@ async def add_modbus_base_properties( async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID], config[CONF_COMMAND_THROTTLE]) + var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE])) + cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES])) await register_modbus_device(var, config) diff --git a/esphome/components/modbus_controller/const.py b/esphome/components/modbus_controller/const.py index baf72efb94..1a23640e17 100644 --- a/esphome/components/modbus_controller/const.py +++ b/esphome/components/modbus_controller/const.py @@ -1,6 +1,7 @@ CONF_BITMASK = "bitmask" CONF_BYTE_OFFSET = "byte_offset" CONF_COMMAND_THROTTLE = "command_throttle" +CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates" CONF_CUSTOM_COMMAND = "custom_command" CONF_FORCE_NEW_RANGE = "force_new_range" CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id" diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 79c13e3f68..7565dc5e1b 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -26,6 +26,17 @@ bool ModbusController::send_next_command_() { // remove from queue if command was sent too often if (command->send_countdown < 1) { + if (!this->module_offline_) { + ESP_LOGW(TAG, "Modbus device=%d set offline", this->address_); + + if (this->offline_skip_updates_ > 0) { + // Update skip_updates_counter to stop flooding channel with timeouts + for (auto &r : this->register_ranges_) { + r.skip_updates_counter = this->offline_skip_updates_; + } + } + } + this->module_offline_ = true; ESP_LOGD( TAG, "Modbus command to device=%d register=0x%02X countdown=%d no response received - removed from send queue", @@ -49,6 +60,18 @@ bool ModbusController::send_next_command_() { void ModbusController::on_modbus_data(const std::vector &data) { auto ¤t_command = this->command_queue_.front(); if (current_command != nullptr) { + if (this->module_offline_) { + ESP_LOGW(TAG, "Modbus device=%d back online", this->address_); + + if (this->offline_skip_updates_ > 0) { + // Restore skip_updates_counter to restore commands updates + for (auto &r : this->register_ranges_) { + r.skip_updates_counter = 0; + } + } + } + this->module_offline_ = false; + // Move the commandItem to the response queue current_command->payload = data; this->incoming_queue_.push(std::move(current_command)); diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index ccb0edf9c6..a389375523 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -409,7 +409,6 @@ class ModbusCommandItem { class ModbusController : public PollingComponent, public modbus::ModbusDevice { public: - ModbusController(uint16_t throttle = 0) : command_throttle_(throttle){}; void dump_config() override; void loop() override; void setup() override; @@ -431,6 +430,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { const std::vector &data); /// called by esphome generated code to set the command_throttle period void set_command_throttle(uint16_t command_throttle) { this->command_throttle_ = command_throttle; } + /// called by esphome generated code to set the offline_skip_updates + void set_offline_skip_updates(uint16_t offline_skip_updates) { this->offline_skip_updates_ = offline_skip_updates; } + /// get the number of queued modbus commands (should be mostly empty) + size_t get_command_queue_length() { return command_queue_.size(); } + /// get if the module is offline, didn't respond the last command + bool get_module_offline() { return module_offline_; } protected: /// parse sensormap_ and create range of sequential addresses @@ -443,8 +448,6 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { void process_modbus_data_(const ModbusCommandItem *response); /// send the next modbus command from the send queue bool send_next_command_(); - /// get the number of queued modbus commands (should be mostly empty) - size_t get_command_queue_length_() { return command_queue_.size(); } /// dump the parsed sensormap for diagnostics void dump_sensors_(); /// Collection of all sensors for this component @@ -459,6 +462,10 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { uint32_t last_command_timestamp_; /// min time in ms between sending modbus commands uint16_t command_throttle_; + /// if module didn't respond the last command + bool module_offline_; + /// how many updates to skip if module is offline + uint16_t offline_skip_updates_; }; /** Convert vector response payload to float. From b8fa737bc956577e7b2635af7f60b43633613a58 Mon Sep 17 00:00:00 2001 From: rufuswilson Date: Wed, 13 Sep 2023 00:20:00 +0200 Subject: [PATCH 0477/2607] Force heater off on setup (#5161) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sht3xd/sensor.py | 7 ++++++- esphome/components/sht3xd/sht3xd.cpp | 4 ++++ esphome/components/sht3xd/sht3xd.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index 8e1ef426ad..5c73a63f1a 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -12,6 +12,8 @@ from esphome.const import ( UNIT_PERCENT, ) +CONF_HEATER_ENABLED = "heater_enabled" + DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -36,7 +38,8 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, ), - } + cv.Optional(CONF_HEATER_ENABLED, default=True): cv.boolean, + }, ) .extend(cv.polling_component_schema("60s")) .extend(i2c.i2c_device_schema(0x44)) @@ -48,6 +51,8 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) + cg.add(var.set_heater_enabled(config[CONF_HEATER_ENABLED])) + if CONF_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) diff --git a/esphome/components/sht3xd/sht3xd.cpp b/esphome/components/sht3xd/sht3xd.cpp index 4e1c9742bc..f4bd2da271 100644 --- a/esphome/components/sht3xd/sht3xd.cpp +++ b/esphome/components/sht3xd/sht3xd.cpp @@ -22,6 +22,10 @@ void SHT3XDComponent::setup() { this->mark_failed(); return; } + if (!this->write_command(heater_enabled_ ? SHT3XD_COMMAND_HEATER_ENABLE : SHT3XD_COMMAND_HEATER_DISABLE)) { + this->mark_failed(); + return; + } uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); ESP_LOGV(TAG, " Serial Number: 0x%08X", serial_number); } diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h index 41ca3c5d6e..04023c8a46 100644 --- a/esphome/components/sht3xd/sht3xd.h +++ b/esphome/components/sht3xd/sht3xd.h @@ -17,10 +17,12 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir void dump_config() override; float get_setup_priority() const override; void update() override; + void set_heater_enabled(bool heater_enabled) { heater_enabled_ = heater_enabled; } protected: sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; + bool heater_enabled_{true}; }; } // namespace sht3xd From 736dbfac135e368f8c6ee0be2701597ec59ad3ef Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 12 Sep 2023 18:36:17 -0500 Subject: [PATCH 0478/2607] Add IDF 5 test yaml, add adc to IDF tests, fix adc for IDF 5 (#5379) --- .github/workflows/ci.yml | 2 +- esphome/components/adc/adc_sensor.h | 4 + tests/test11.5.yaml | 697 ++++++++++++++++++++++++++++ tests/test5.yaml | 6 + 4 files changed, 708 insertions(+), 1 deletion(-) create mode 100644 tests/test11.5.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0786e1b9a2..4e4e6c0ece 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -226,7 +226,7 @@ jobs: fail-fast: false max-parallel: 2 matrix: - file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 10] + file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 10, 11.5] steps: - name: Check out code from GitHub uses: actions/checkout@v4.0.0 diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 7d9c8959da..b1fdcd5d29 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -62,8 +62,12 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; +#if ESP_IDF_VERSION_MAJOR >= 5 + esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {}; +#else esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; #endif +#endif }; } // namespace adc diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml new file mode 100644 index 0000000000..544dc10930 --- /dev/null +++ b/tests/test11.5.yaml @@ -0,0 +1,697 @@ +--- +# copy of test5.yaml configured to build on IDF 5 +esphome: + name: test11-5 + build_path: build/test11.5 + project: + name: esphome.test11_5_project + version: "1.0.0" + +esp32: + board: nodemcu-32s + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 + advanced: + ignore_efuse_mac_crc: true + +wifi: + networks: + - ssid: "MySSID" + password: "password1" + manual_ip: + static_ip: 192.168.1.23 + gateway: 192.168.1.1 + subnet: 255.255.255.0 + +api: + +ota: + +logger: + +debug: + +psram: + +uart: + - id: uart_1 + tx_pin: 1 + rx_pin: 3 + baud_rate: 9600 + - id: uart_2 + tx_pin: 17 + rx_pin: 16 + baud_rate: 19200 + +i2c: + frequency: 100khz + +modbus: + uart_id: uart_1 + flow_control_pin: 5 + id: mod_bus1 + +modbus_controller: + - id: modbus_controller_test + address: 0x2 + modbus_id: mod_bus1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + idf_send_async: false + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + # yamllint disable rule:line-length + - lambda: |- + ESP_LOGD("Mqtt Test", "testing/sensor/testing_sensor/state=[%s]", x.c_str()); + # yamllint enable rule:line-length + +vbus: + - uart_id: uart_2 + +binary_sensor: + - platform: gpio + pin: GPIO0 + id: io0_button + icon: mdi:gesture-tap-button + + - platform: modbus_controller + modbus_controller_id: modbus_controller_test + id: modbus_binsensortest + register_type: read + address: 0x3200 + bitmask: 0x80 # (bit 8) + lambda: "return x;" + + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 + + - platform: ezo_pmp + pump_state: + name: "Pump State" + is_paused: + name: "Is Paused" + + - platform: matrix_keypad + keypad_id: keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + + - platform: vbus + model: deltasol_bs_plus + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +tlc5947: + data_pin: GPIO12 + clock_pin: GPIO14 + lat_pin: GPIO15 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gpio + pin: GPIO2 + id: built_in_led + + - platform: tlc5947 + id: output_red + channel: 0 + max_power: 0.8 + + - platform: mcp47a1 + id: output_mcp47a1 + + - platform: modbus_controller + modbus_controller_id: modbus_controller_test + id: modbus_output_test + lambda: |- + return x * 1.0 ; + address: 0x9001 + value_type: U_WORD + + - platform: tm1638 + id: Led4 + led: 4 + + - platform: tm1638 + id: Led5 + led: 5 + + - platform: tm1638 + id: Led6 + led: 6 + + - platform: tm1638 + id: Led7 + led: 7 + + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 + +demo: + +esp32_ble: + +esp32_ble_server: + manufacturer: ESPHome + model: Test11 + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +number: + - platform: template + name: My template number + id: template_number_id + optimistic: true + max_value: 100 + min_value: 0 + step: 5 + unit_of_measurement: "%" + mode: slider + device_class: humidity + on_value: + - logger.log: + format: Number changed to %f + args: [x] + set_action: + - logger.log: + format: Template Number set to %f + args: [x] + - number.set: + id: template_number_id + value: 50 + - number.to_min: template_number_id + - number.to_min: + id: template_number_id + - number.to_max: template_number_id + - number.to_max: + id: template_number_id + - number.increment: template_number_id + - number.increment: + id: template_number_id + cycle: false + - number.decrement: template_number_id + - number.decrement: + id: template_number_id + cycle: false + - number.operation: + id: template_number_id + operation: Increment + cycle: false + - number.operation: + id: template_number_id + operation: !lambda "return NUMBER_OP_INCREMENT;" + cycle: !lambda "return false;" + + - id: modbus_numbertest + platform: modbus_controller + modbus_controller_id: modbus_controller_test + name: ModbusNumber + address: 0x9002 + value_type: U_WORD + lambda: "return x * 1.0;" + write_lambda: |- + return x * 1.0 ; + multiply: 1.0 + +select: + - platform: template + name: My template select + id: template_select_id + optimistic: true + initial_option: two + restore_value: true + on_value: + - logger.log: + format: Select changed to %s (index %d)" + args: ["x.c_str()", "i"] + set_action: + - logger.log: + format: Template Select set to %s + args: ["x.c_str()"] + - select.set: + id: template_select_id + option: two + - select.first: template_select_id + - select.last: + id: template_select_id + - select.previous: template_select_id + - select.next: + id: template_select_id + cycle: false + - select.operation: + id: template_select_id + operation: Previous + cycle: false + - select.operation: + id: template_select_id + operation: !lambda "return SELECT_OP_PREVIOUS;" + cycle: !lambda "return true;" + - select.set_index: + id: template_select_id + index: 1 + - select.set_index: + id: template_select_id + index: !lambda "return 1 + 1;" + options: + - one + - two + - three + + - platform: modbus_controller + name: Modbus Select Register 1000 + address: 1000 + value_type: U_WORD + optionsmap: + "Zero": 0 + "One": 1 + "Two": 2 + "Three": 3 + +sensor: + - platform: adc + id: adc_sensor_p32 + name: ADC pin 32 + pin: 32 + attenuation: 11db + update_interval: 1s + - platform: internal_temperature + name: Internal Temperature + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true + + - id: modbus_sensortest + platform: modbus_controller + modbus_controller_id: modbus_controller_test + address: 0x331A + register_type: read + value_type: U_WORD + + - platform: t6615 + uart_id: uart_2 + co2: + name: CO2 Sensor + + - platform: bmp3xx + temperature: + name: BMP Temperature + oversampling: 16x + pressure: + name: BMP Pressure + address: 0x77 + iir_filter: 2X + + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature + + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + + - platform: vbus + model: deltasol c + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time + + - platform: debug + free: + name: "Heap Free" + block: + name: "Heap Max Block" + loop_time: + name: "Loop Time" + psram: + name: "PSRAM Free" + + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + sensors: + - id: vcustom + name: VBus Custom Sensor + lambda: return x[0] / 10.0; + + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature + +script: + - id: automation_test + then: + - repeat: + count: 5 + then: + - logger.log: looping! + + - id: zero_repeat_test + then: + - repeat: + count: !lambda "return 0;" + then: + - logger.log: shouldn't see mee! + +switch: + - platform: modbus_controller + modbus_controller_id: modbus_controller_test + id: modbus_switch_test + register_type: coil + address: 2 + bitmask: 1 + + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +display: + - platform: tm1638 + id: primarydisplay + stb_pin: 5 #TM1638 STB + clk_pin: 18 #TM1638 CLK + dio_pin: 23 #TM1638 DIO + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +time: + - platform: pcf85063 + - platform: pcf8563 + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? + +sn74hc165: + id: sn74hc165_hub + data_pin: GPIO12 + clock_pin: GPIO14 + load_pin: GPIO27 + clock_inhibit_pin: GPIO26 + sr_count: 4 + +matrix_keypad: + id: keypad + rows: + - pin: 21 + - pin: 19 + columns: + - pin: 17 + - pin: 16 + keys: "1234" + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + +light: + - platform: esp32_rmt_led_strip + id: led_strip + pin: 13 + num_leds: 60 + rmt_channel: 6 + rgb_order: GRB + chipset: ws2812 + - platform: esp32_rmt_led_strip + id: led_strip2 + pin: 15 + num_leds: 60 + rmt_channel: 2 + rgb_order: RGB + bit0_high: 100us + bit0_low: 100us + bit1_high: 100us + bit1_low: 100us diff --git a/tests/test5.yaml b/tests/test5.yaml index 417f3bfecd..274570aad6 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -392,6 +392,12 @@ select: "Three": 3 sensor: + - platform: adc + id: adc_sensor_p32 + name: ADC pin 32 + pin: 32 + attenuation: 11db + update_interval: 1s - platform: internal_temperature name: Internal Temperature - platform: selec_meter From 68a2c45edf01e426f26350693d91669696481ab1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:05:06 +1200 Subject: [PATCH 0479/2607] Bump version to 2023.9.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index bbc6e71885..cbb31e0ec6 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0-dev" +__version__ = "2023.9.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 11433c8c178df6604788f91aceeeb99755befe0c Mon Sep 17 00:00:00 2001 From: vr6racer <12117307+vr6racer@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:14:54 +0100 Subject: [PATCH 0480/2607] SX1509 component (#5385) --- esphome/components/sx1509/binary_sensor/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/sx1509/binary_sensor/__init__.py b/esphome/components/sx1509/binary_sensor/__init__.py index bbf0e5d0bc..fa620fa202 100644 --- a/esphome/components/sx1509/binary_sensor/__init__.py +++ b/esphome/components/sx1509/binary_sensor/__init__.py @@ -14,8 +14,8 @@ SX1509BinarySensor = sx1509_ns.class_("SX1509BinarySensor", binary_sensor.Binary CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(SX1509BinarySensor).extend( { cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component), - cv.Required(CONF_ROW): cv.int_range(min=0, max=4), - cv.Required(CONF_COL): cv.int_range(min=0, max=4), + cv.Required(CONF_ROW): cv.int_range(min=0, max=7), + cv.Required(CONF_COL): cv.int_range(min=0, max=7), } ) From 9d978075875b0fdb4fa72e07c657fa108f306296 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:05:06 +1200 Subject: [PATCH 0481/2607] Bump version to 2023.10.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index bbc6e71885..2865b369e8 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0-dev" +__version__ = "2023.10.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 280b090dfce2576f056ac0b04c011ee225235fad Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Wed, 13 Sep 2023 18:13:55 -0500 Subject: [PATCH 0482/2607] Add patch to apt install (#5389) --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index bf64897af7..a0bb007641 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,7 +29,8 @@ RUN \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ python3-cffi=1.14.5-1 \ - libcairo2=1.16.0-5; \ + libcairo2=1.16.0-5 \ + patch=2.7.6-7; \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ apt-get install -y --no-install-recommends \ build-essential=12.9 \ From 55b5c0fc32210fea202e930fe2d1e7ca374cc635 Mon Sep 17 00:00:00 2001 From: phoenixswiss <52887628+phoenixswiss@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:20:21 +0200 Subject: [PATCH 0483/2607] Fix Waveshare 7.5v2 epaper screens are always powered on (#5283) --- .../waveshare_epaper/waveshare_epaper.cpp | 66 ++++++++++++++++--- .../waveshare_epaper/waveshare_epaper.h | 4 ++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 73c2680add..f52808d295 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1561,6 +1561,23 @@ void WaveshareEPaper7P5In::dump_config() { LOG_PIN(" Busy Pin: ", this->busy_pin_); LOG_UPDATE_INTERVAL(this); } +bool WaveshareEPaper7P5InV2::wait_until_idle_() { + if (this->busy_pin_ == nullptr) { + return true; + } + + const uint32_t start = millis(); + while (this->busy_pin_->digital_read()) { + this->command(0x71); + if (millis() - start > this->idle_timeout_()) { + ESP_LOGE(TAG, "Timeout while displaying image!"); + return false; + } + App.feed_wdt(); + delay(10); + } + return true; +} void WaveshareEPaper7P5InV2::initialize() { // COMMAND POWER SETTING this->command(0x01); @@ -1568,10 +1585,21 @@ void WaveshareEPaper7P5InV2::initialize() { this->data(0x07); this->data(0x3f); this->data(0x3f); - this->command(0x04); + + // We don't want the display to be powered at this point delay(100); // NOLINT this->wait_until_idle_(); + + // COMMAND VCOM AND DATA INTERVAL SETTING + this->command(0x50); + this->data(0x10); + this->data(0x07); + + // COMMAND TCON SETTING + this->command(0x60); + this->data(0x22); + // COMMAND PANEL SETTING this->command(0x00); this->data(0x1F); @@ -1582,19 +1610,30 @@ void WaveshareEPaper7P5InV2::initialize() { this->data(0x20); this->data(0x01); this->data(0xE0); - // COMMAND ...? + + // COMMAND DUAL SPI MM_EN, DUSPI_EN this->command(0x15); this->data(0x00); - // COMMAND VCOM AND DATA INTERVAL SETTING - this->command(0x50); - this->data(0x10); - this->data(0x07); - // COMMAND TCON SETTING - this->command(0x60); - this->data(0x22); + + // COMMAND POWER DRIVER HAT DOWN + // This command will turn off booster, controller, source driver, gate driver, VCOM, and + // temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode. + // Source/Gate/Border/VCOM will be released to floating. + this->command(0x02); } void HOT WaveshareEPaper7P5InV2::display() { uint32_t buf_len = this->get_buffer_length_(); + + // COMMAND POWER ON + ESP_LOGI(TAG, "Power on the display and hat"); + + // This command will turn on booster, controller, regulators, and temperature sensor will be + // activated for one-time sensing before enabling booster. When all voltages are ready, the + // BUSY_N signal will return to high. + this->command(0x04); + delay(200); // NOLINT + this->wait_until_idle_(); + // COMMAND DATA START TRANSMISSION NEW DATA this->command(0x13); delay(2); @@ -1602,14 +1641,23 @@ void HOT WaveshareEPaper7P5InV2::display() { this->data(~(this->buffer_[i])); } + delay(100); // NOLINT + this->wait_until_idle_(); + // COMMAND DISPLAY REFRESH this->command(0x12); delay(100); // NOLINT this->wait_until_idle_(); + + ESP_LOGV(TAG, "Before command(0x02) (>> power off)"); + this->command(0x02); + this->wait_until_idle_(); + ESP_LOGV(TAG, "After command(0x02) (>> power off)"); } int WaveshareEPaper7P5InV2::get_width_internal() { return 800; } int WaveshareEPaper7P5InV2::get_height_internal() { return 480; } +uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; } void WaveshareEPaper7P5InV2::dump_config() { LOG_DISPLAY("", "Waveshare E-Paper", this); ESP_LOGCONFIG(TAG, " Model: 7.5inV2rev2"); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 315af9ea82..b3325d69eb 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -472,6 +472,8 @@ class WaveshareEPaper7P5InBC : public WaveshareEPaper { class WaveshareEPaper7P5InV2 : public WaveshareEPaper { public: + bool wait_until_idle_(); + void initialize() override; void display() override; @@ -491,6 +493,8 @@ class WaveshareEPaper7P5InV2 : public WaveshareEPaper { int get_width_internal() override; int get_height_internal() override; + + uint32_t idle_timeout_() override; }; class WaveshareEPaper7P5InV2alt : public WaveshareEPaper7P5InV2 { From b5f2d69ca529a04616262d96a066080a3b6ad847 Mon Sep 17 00:00:00 2001 From: rmmacias <46213351+rmmacias@users.noreply.github.com> Date: Sun, 17 Sep 2023 07:18:51 +0200 Subject: [PATCH 0484/2607] Update radon_eye_listener.cpp (#5401) New devices identifiers do not star by the hardcoded string. FR:RE222 is the 8-char length string of my devices bought in 2023. This proposal aims at solve the topic by making the detection track devices starting only by FR:R --- esphome/components/radon_eye_ble/radon_eye_listener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/radon_eye_ble/radon_eye_listener.cpp b/esphome/components/radon_eye_ble/radon_eye_listener.cpp index b10986c9cb..340322c188 100644 --- a/esphome/components/radon_eye_ble/radon_eye_listener.cpp +++ b/esphome/components/radon_eye_ble/radon_eye_listener.cpp @@ -10,7 +10,7 @@ static const char *const TAG = "radon_eye_ble"; bool RadonEyeListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { if (not device.get_name().empty()) { - if (device.get_name().rfind("FR:R20:SN", 0) == 0) { + if (device.get_name().rfind("FR:R", 0) == 0) { // This is an RD200, I think ESP_LOGD(TAG, "Found Radon Eye RD200 device Name: %s (MAC: %s)", device.get_name().c_str(), device.address_str().c_str()); From a61e3fadf66d38f5aa823be3a70b23dffa03dad5 Mon Sep 17 00:00:00 2001 From: Trevor North Date: Sun, 17 Sep 2023 06:20:31 +0100 Subject: [PATCH 0485/2607] Add shelly-dimmer-stm32 51.7 to known versions (#5400) This version removes support for no-neutral setups in favor of fixing flickering some users have experienced. --- esphome/components/shelly_dimmer/light.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/shelly_dimmer/light.py b/esphome/components/shelly_dimmer/light.py index 467a3c3531..5bdb54baf5 100644 --- a/esphome/components/shelly_dimmer/light.py +++ b/esphome/components/shelly_dimmer/light.py @@ -57,6 +57,10 @@ KNOWN_FIRMWARE = { "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.6/shelly-dimmer-stm32_v51.6.bin", "eda483e111c914723a33f5088f1397d5c0b19333db4a88dc965636b976c16c36", ), + "51.7": ( + "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.7/shelly-dimmer-stm32_v51.7.bin", + "7a20f1c967c469917368a79bc56498009045237080408cef7190743e08031889", + ), } From 164631fcec7f286c0ef6575e9c07c76c369e2b38 Mon Sep 17 00:00:00 2001 From: Fabian Date: Sun, 17 Sep 2023 07:24:31 +0200 Subject: [PATCH 0486/2607] Ci find YAML tests dynamically (#5399) * Find all YAML test files dynamically. * Merge error * GitHub set-ouput syntax upgrade. --------- Co-authored-by: Your Name --- .github/workflows/ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e4e6c0ece..792d972311 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -210,6 +210,17 @@ jobs: run: script/ci-suggest-changes if: always() + compile-tests-list: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Check out code from GitHub + uses: actions/checkout@v4.0.0 + - name: Find all YAML test files + id: set-matrix + run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + compile-tests: name: Run YAML test ${{ matrix.file }} runs-on: ubuntu-latest @@ -222,11 +233,12 @@ jobs: - pylint - pytest - pyupgrade + - compile-tests-list strategy: fail-fast: false max-parallel: 2 matrix: - file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 10, 11.5] + file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub uses: actions/checkout@v4.0.0 @@ -235,10 +247,10 @@ jobs: with: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - - name: Run esphome compile tests/test${{ matrix.file }}.yaml + - name: Run esphome compile ${{ matrix.file }} run: | . venv/bin/activate - esphome compile tests/test${{ matrix.file }}.yaml + esphome compile ${{ matrix.file }} clang-tidy: name: ${{ matrix.name }} From 11f6e555f9607767991a93d9c6259ef627a39bda Mon Sep 17 00:00:00 2001 From: Philipp Helo Rehs Date: Sun, 17 Sep 2023 07:30:52 +0200 Subject: [PATCH 0487/2607] Add E-Trailer Gaslevel support to Mopeka Std Check (#5397) * Add E-Trailer Gaslevel support to Mopeka Std Check Signed-off-by: Philipp Helo Rehs * fix format --------- Signed-off-by: Philipp Helo Rehs Co-authored-by: Philipp Helo Rehs --- esphome/components/mopeka_std_check/mopeka_std_check.cpp | 3 ++- esphome/components/mopeka_std_check/mopeka_std_check.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.cpp b/esphome/components/mopeka_std_check/mopeka_std_check.cpp index 67e749c68b..9dd1718cb2 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.cpp +++ b/esphome/components/mopeka_std_check/mopeka_std_check.cpp @@ -71,7 +71,8 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) const auto *mopeka_data = (const mopeka_std_package *) manu_data.data.data(); const u_int8_t hardware_id = mopeka_data->data_1 & 0xCF; - if (static_cast(hardware_id) != STANDARD && static_cast(hardware_id) != XL) { + if (static_cast(hardware_id) != STANDARD && static_cast(hardware_id) != XL && + static_cast(hardware_id) != ETRAILER) { ESP_LOGE(TAG, "[%s] Unsupported Sensor Type (0x%X)", device.address_str().c_str(), hardware_id); return false; } diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.h b/esphome/components/mopeka_std_check/mopeka_std_check.h index e4d81afbd7..ee588c8e5f 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.h +++ b/esphome/components/mopeka_std_check/mopeka_std_check.h @@ -14,6 +14,7 @@ namespace mopeka_std_check { enum SensorType { STANDARD = 0x02, XL = 0x03, + ETRAILER = 0x46, }; // 4 values in one struct so it aligns to 8 byte. One `mopeka_std_values` is 40 bit long. From e3eef1cc6dbbce019fc18168e61c71e5ba3d960e Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 14:20:54 -0700 Subject: [PATCH 0488/2607] fix disabled wifi power on 8266 (#5409) Co-authored-by: Samuel Sieb --- esphome/components/wifi/wifi_component_esp8266.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 1afa439567..6e7c491967 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -98,6 +98,7 @@ bool WiFiComponent::wifi_apply_power_save_() { power_save = NONE_SLEEP_T; break; } + wifi_fpm_auto_sleep_set_in_null_mode(1); return wifi_set_sleep_type(power_save); } From bf253c21fac829da986e0e914bff7f1d36eba996 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 14:25:16 -0700 Subject: [PATCH 0489/2607] fix handling of web server version (#5405) Co-authored-by: Samuel Sieb --- esphome/components/web_server/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index c6d9c31e93..966c978836 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -59,7 +59,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(WebServer), cv.Optional(CONF_PORT, default=80): cv.port, - cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2), + cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), cv.Optional(CONF_CSS_URL): cv.string, cv.Optional(CONF_CSS_INCLUDE): cv.file_, cv.Optional(CONF_JS_URL): cv.string, From 397f57ce74e87c447508e940c2f9a44d6ed7bfe6 Mon Sep 17 00:00:00 2001 From: Joris S <100357138+Jorre05@users.noreply.github.com> Date: Wed, 20 Sep 2023 23:28:03 +0200 Subject: [PATCH 0490/2607] Climate preset fix (#5407) --- esphome/components/thermostat/thermostat_climate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp index 51da663a0c..386e13dc37 100644 --- a/esphome/components/thermostat/thermostat_climate.cpp +++ b/esphome/components/thermostat/thermostat_climate.cpp @@ -986,6 +986,7 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) { // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; assert(trig != nullptr); + this->preset = preset; trig->trigger(); this->refresh(); @@ -1010,6 +1011,7 @@ void ThermostatClimate::change_custom_preset_(const std::string &custom_preset) // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; assert(trig != nullptr); + this->custom_preset = custom_preset; trig->trigger(); this->refresh(); From 61edf8c196613c2f38da96ca7ce311e3f24c6bb7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 20 Sep 2023 16:30:22 -0500 Subject: [PATCH 0491/2607] Remove Wi-Fi dependency from Midea component (#5394) --- esphome/components/midea/climate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/midea/climate.py b/esphome/components/midea/climate.py index 80b1461576..074ab8abb2 100644 --- a/esphome/components/midea/climate.py +++ b/esphome/components/midea/climate.py @@ -35,7 +35,7 @@ from esphome.components.climate import ( ) CODEOWNERS = ["@dudanov"] -DEPENDENCIES = ["climate", "uart", "wifi"] +DEPENDENCIES = ["climate", "uart"] AUTO_LOAD = ["sensor"] CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_POWER_USAGE = "power_usage" From 157a3e53ddde620f25522d0f218e692d86d7d291 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Wed, 20 Sep 2023 18:02:29 -0400 Subject: [PATCH 0492/2607] http_request: Cleanups and safety improvements (#5360) --- .../components/http_request/http_request.h | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 0958c07683..b885de18e6 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -80,8 +80,6 @@ template class HttpRequestSendAction : public Action { TEMPLATABLE_VALUE(std::string, url) TEMPLATABLE_VALUE(const char *, method) TEMPLATABLE_VALUE(std::string, body) - TEMPLATABLE_VALUE(const char *, useragent) - TEMPLATABLE_VALUE(uint16_t, timeout) void add_header(const char *key, TemplatableValue value) { this->headers_.insert({key, value}); } @@ -105,25 +103,18 @@ template class HttpRequestSendAction : public Action { auto f = std::bind(&HttpRequestSendAction::encode_json_func_, this, x..., std::placeholders::_1); this->parent_->set_body(json::build_json(f)); } - if (this->useragent_.has_value()) { - this->parent_->set_useragent(this->useragent_.value(x...)); - } - if (this->timeout_.has_value()) { - this->parent_->set_timeout(this->timeout_.value(x...)); - } - if (!this->headers_.empty()) { - std::list
headers; - for (const auto &item : this->headers_) { - auto val = item.second; - Header header; - header.name = item.first; - header.value = val.value(x...); - headers.push_back(header); - } - this->parent_->set_headers(headers); + std::list
headers; + for (const auto &item : this->headers_) { + auto val = item.second; + Header header; + header.name = item.first; + header.value = val.value(x...); + headers.push_back(header); } + this->parent_->set_headers(headers); this->parent_->send(this->response_triggers_); this->parent_->close(); + this->parent_->set_body(""); } protected: From 2c2821cd961b51cb303996fdb62e17f323eb8908 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Thu, 21 Sep 2023 08:04:03 +1000 Subject: [PATCH 0493/2607] Make the pulse meter timeout on startup when no pulses are received (#5388) --- .../pulse_meter/pulse_meter_sensor.cpp | 35 +++++++++++++------ .../pulse_meter/pulse_meter_sensor.h | 3 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 7eef18e5e0..be5fad6fe5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -11,6 +11,9 @@ void PulseMeterSensor::setup() { this->pin_->setup(); this->isr_pin_ = pin_->to_isr(); + // Set the last processed edge to now for the first timeout + this->last_processed_edge_us_ = micros(); + if (this->filter_mode_ == FILTER_EDGE) { this->pin_->attach_interrupt(PulseMeterSensor::edge_intr, this, gpio::INTERRUPT_RISING_EDGE); } else if (this->filter_mode_ == FILTER_PULSE) { @@ -38,12 +41,16 @@ void PulseMeterSensor::loop() { } // We need to detect at least two edges to have a valid pulse width - if (!this->initialized_) { - this->initialized_ = true; - } else { - uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; - float pulse_width_us = delta_us / float(this->get_->count_); - this->publish_state((60.0f * 1000000.0f) / pulse_width_us); + switch (this->meter_state_) { + case MeterState::INITIAL: + case MeterState::TIMED_OUT: { + this->meter_state_ = MeterState::RUNNING; + } break; + case MeterState::RUNNING: { + uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; + float pulse_width_us = delta_us / float(this->get_->count_); + this->publish_state((60.0f * 1000000.0f) / pulse_width_us); + } break; } this->last_processed_edge_us_ = this->get_->last_detected_edge_us_; @@ -53,10 +60,18 @@ void PulseMeterSensor::loop() { const uint32_t now = micros(); const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_; - if (this->initialized_ && time_since_valid_edge_us > this->timeout_us_) { - ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); - this->initialized_ = false; - this->publish_state(0.0f); + switch (this->meter_state_) { + // Running and initial states can timeout + case MeterState::INITIAL: + case MeterState::RUNNING: { + if (time_since_valid_edge_us > this->timeout_us_) { + this->meter_state_ = MeterState::TIMED_OUT; + ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); + this->publish_state(0.0f); + } + } break; + default: + break; } } } diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index ddd42c2ed5..f376ea48a5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -38,7 +38,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component { InternalFilterMode filter_mode_{FILTER_EDGE}; // Variables used in the loop - bool initialized_ = false; + enum class MeterState { INITIAL, RUNNING, TIMED_OUT }; + MeterState meter_state_ = MeterState::INITIAL; uint32_t total_pulses_ = 0; uint32_t last_processed_edge_us_ = 0; From 056a28906ba9de193da4aa78f6034984654bc4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 21 Sep 2023 00:09:23 +0200 Subject: [PATCH 0494/2607] Wizard: fix colored text in input prompts (#5313) --- esphome/util.py | 14 ++++++++++---- esphome/wizard.py | 18 ++++++++++-------- tests/unit_tests/test_wizard.py | 12 ++++++------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/esphome/util.py b/esphome/util.py index 0d60212f50..480618aca0 100644 --- a/esphome/util.py +++ b/esphome/util.py @@ -57,7 +57,7 @@ class SimpleRegistry(dict): return decorator -def safe_print(message=""): +def safe_print(message="", end="\n"): from esphome.core import CORE if CORE.dashboard: @@ -67,20 +67,26 @@ def safe_print(message=""): pass try: - print(message) + print(message, end=end) return except UnicodeEncodeError: pass try: - print(message.encode("utf-8", "backslashreplace")) + print(message.encode("utf-8", "backslashreplace"), end=end) except UnicodeEncodeError: try: - print(message.encode("ascii", "backslashreplace")) + print(message.encode("ascii", "backslashreplace"), end=end) except UnicodeEncodeError: print("Cannot print line because of invalid locale!") +def safe_input(prompt=""): + if prompt: + safe_print(prompt, end="") + return input() + + def shlex_quote(s): if not s: return "''" diff --git a/esphome/wizard.py b/esphome/wizard.py index aa05e513a7..1308338ad0 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -11,7 +11,7 @@ from esphome.core import CORE from esphome.helpers import get_bool_env, write_file from esphome.log import Fore, color from esphome.storage_json import StorageJSON, ext_storage_path -from esphome.util import safe_print +from esphome.util import safe_input, safe_print CORE_BIG = r""" _____ ____ _____ ______ / ____/ __ \| __ \| ____| @@ -252,7 +252,7 @@ def safe_print_step(step, big): def default_input(text, default): safe_print() safe_print(f"Press ENTER for default ({default})") - return input(text.format(default)) or default + return safe_input(text.format(default)) or default # From https://stackoverflow.com/a/518232/8924614 @@ -306,7 +306,7 @@ def wizard(path): ) safe_print() sleep(1) - name = input(color(Fore.BOLD_WHITE, "(name): ")) + name = safe_input(color(Fore.BOLD_WHITE, "(name): ")) while True: try: @@ -343,7 +343,9 @@ def wizard(path): while True: sleep(0.5) safe_print() - platform = input(color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ")) + platform = safe_input( + color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ") + ) try: platform = vol.All(vol.Upper, vol.Any(*wizard_platforms))(platform.upper()) break @@ -397,7 +399,7 @@ def wizard(path): boards.append(board_id) while True: - board = input(color(Fore.BOLD_WHITE, "(board): ")) + board = safe_input(color(Fore.BOLD_WHITE, "(board): ")) try: board = vol.All(vol.Lower, vol.Any(*boards))(board) break @@ -423,7 +425,7 @@ def wizard(path): sleep(1.5) safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'Abraham Linksys')}\".") while True: - ssid = input(color(Fore.BOLD_WHITE, "(ssid): ")) + ssid = safe_input(color(Fore.BOLD_WHITE, "(ssid): ")) try: ssid = cv.ssid(ssid) break @@ -449,7 +451,7 @@ def wizard(path): safe_print() safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'PASSWORD42')}\"") sleep(0.5) - psk = input(color(Fore.BOLD_WHITE, "(PSK): ")) + psk = safe_input(color(Fore.BOLD_WHITE, "(PSK): ")) safe_print( "Perfect! WiFi is now set up (you can create static IPs and so on later)." ) @@ -466,7 +468,7 @@ def wizard(path): safe_print() sleep(0.25) safe_print("Press ENTER for no password") - password = input(color(Fore.BOLD_WHITE, "(password): ")) + password = safe_input(color(Fore.BOLD_WHITE, "(password): ")) if not wizard_write( path=path, diff --git a/tests/unit_tests/test_wizard.py b/tests/unit_tests/test_wizard.py index 8bbce08ae5..46700a3ba8 100644 --- a/tests/unit_tests/test_wizard.py +++ b/tests/unit_tests/test_wizard.py @@ -319,7 +319,7 @@ def test_wizard_accepts_default_answers_esp8266(tmpdir, monkeypatch, wizard_answ config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -341,7 +341,7 @@ def test_wizard_accepts_default_answers_esp32(tmpdir, monkeypatch, wizard_answer config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -371,7 +371,7 @@ def test_wizard_offers_better_node_name(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -394,7 +394,7 @@ def test_wizard_requires_correct_platform(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -416,7 +416,7 @@ def test_wizard_requires_correct_board(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -438,7 +438,7 @@ def test_wizard_requires_valid_ssid(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) From 1100f67b66de7fa944c446335f6f1254ba78a78a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 15:26:36 -0700 Subject: [PATCH 0495/2607] support keypads with pulldowns (#5404) Co-authored-by: Samuel Sieb --- esphome/components/matrix_keypad/__init__.py | 4 ++++ .../components/matrix_keypad/matrix_keypad.cpp | 17 +++++++++++------ .../components/matrix_keypad/matrix_keypad.h | 2 ++ tests/test5.yaml | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/esphome/components/matrix_keypad/__init__.py b/esphome/components/matrix_keypad/__init__.py index 1c549007b9..5250a45732 100644 --- a/esphome/components/matrix_keypad/__init__.py +++ b/esphome/components/matrix_keypad/__init__.py @@ -21,6 +21,7 @@ CONF_COLUMNS = "columns" CONF_KEYS = "keys" CONF_DEBOUNCE_TIME = "debounce_time" CONF_HAS_DIODES = "has_diodes" +CONF_HAS_PULLDOWNS = "has_pulldowns" def check_keys(obj): @@ -45,6 +46,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_KEYS): cv.string, cv.Optional(CONF_DEBOUNCE_TIME, default=1): cv.int_range(min=1, max=100), cv.Optional(CONF_HAS_DIODES): cv.boolean, + cv.Optional(CONF_HAS_PULLDOWNS): cv.boolean, } ), check_keys, @@ -69,3 +71,5 @@ async def to_code(config): cg.add(var.set_debounce_time(config[CONF_DEBOUNCE_TIME])) if CONF_HAS_DIODES in config: cg.add(var.set_has_diodes(config[CONF_HAS_DIODES])) + if CONF_HAS_PULLDOWNS in config: + cg.add(var.set_has_pulldowns(config[CONF_HAS_PULLDOWNS])) diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index 4f8962a782..902e574846 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -11,11 +11,16 @@ void MatrixKeypad::setup() { if (!has_diodes_) { pin->pin_mode(gpio::FLAG_INPUT); } else { - pin->digital_write(true); + pin->digital_write(!has_pulldowns_); + } + } + for (auto *pin : this->columns_) { + if (has_pulldowns_) { + pin->pin_mode(gpio::FLAG_INPUT); + } else { + pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); } } - for (auto *pin : this->columns_) - pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); } void MatrixKeypad::loop() { @@ -28,9 +33,9 @@ void MatrixKeypad::loop() { for (auto *row : this->rows_) { if (!has_diodes_) row->pin_mode(gpio::FLAG_OUTPUT); - row->digital_write(false); + row->digital_write(has_pulldowns_); for (auto *col : this->columns_) { - if (!col->digital_read()) { + if (col->digital_read() == has_pulldowns_) { if (key != -1) { error = true; } else { @@ -39,7 +44,7 @@ void MatrixKeypad::loop() { } pos++; } - row->digital_write(true); + row->digital_write(!has_pulldowns_); if (!has_diodes_) row->pin_mode(gpio::FLAG_INPUT); } diff --git a/esphome/components/matrix_keypad/matrix_keypad.h b/esphome/components/matrix_keypad/matrix_keypad.h index 9f5942be9a..d506040b7c 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.h +++ b/esphome/components/matrix_keypad/matrix_keypad.h @@ -28,6 +28,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { void set_keys(std::string keys) { keys_ = std::move(keys); }; void set_debounce_time(int debounce_time) { debounce_time_ = debounce_time; }; void set_has_diodes(int has_diodes) { has_diodes_ = has_diodes; }; + void set_has_pulldowns(int has_pulldowns) { has_pulldowns_ = has_pulldowns; }; void register_listener(MatrixKeypadListener *listener); @@ -37,6 +38,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { std::string keys_; int debounce_time_ = 0; bool has_diodes_{false}; + bool has_pulldowns_{false}; int pressed_key_ = -1; std::vector listeners_{}; diff --git a/tests/test5.yaml b/tests/test5.yaml index 274570aad6..5727d30e61 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -667,6 +667,7 @@ matrix_keypad: - pin: 17 - pin: 16 keys: "1234" + has_pulldowns: true key_collector: - id: reader From b3ca71c6fb0d3f68228e522824c272d671292089 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Wed, 13 Sep 2023 18:13:55 -0500 Subject: [PATCH 0496/2607] Add patch to apt install (#5389) --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index bf64897af7..a0bb007641 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,7 +29,8 @@ RUN \ curl=7.74.0-1.3+deb11u7 \ openssh-client=1:8.4p1-5+deb11u1 \ python3-cffi=1.14.5-1 \ - libcairo2=1.16.0-5; \ + libcairo2=1.16.0-5 \ + patch=2.7.6-7; \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ apt-get install -y --no-install-recommends \ build-essential=12.9 \ From ec20778d83dd7bf10d8f32c49ff0dfd7102a0ade Mon Sep 17 00:00:00 2001 From: phoenixswiss <52887628+phoenixswiss@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:20:21 +0200 Subject: [PATCH 0497/2607] Fix Waveshare 7.5v2 epaper screens are always powered on (#5283) --- .../waveshare_epaper/waveshare_epaper.cpp | 66 ++++++++++++++++--- .../waveshare_epaper/waveshare_epaper.h | 4 ++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 73c2680add..f52808d295 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1561,6 +1561,23 @@ void WaveshareEPaper7P5In::dump_config() { LOG_PIN(" Busy Pin: ", this->busy_pin_); LOG_UPDATE_INTERVAL(this); } +bool WaveshareEPaper7P5InV2::wait_until_idle_() { + if (this->busy_pin_ == nullptr) { + return true; + } + + const uint32_t start = millis(); + while (this->busy_pin_->digital_read()) { + this->command(0x71); + if (millis() - start > this->idle_timeout_()) { + ESP_LOGE(TAG, "Timeout while displaying image!"); + return false; + } + App.feed_wdt(); + delay(10); + } + return true; +} void WaveshareEPaper7P5InV2::initialize() { // COMMAND POWER SETTING this->command(0x01); @@ -1568,10 +1585,21 @@ void WaveshareEPaper7P5InV2::initialize() { this->data(0x07); this->data(0x3f); this->data(0x3f); - this->command(0x04); + + // We don't want the display to be powered at this point delay(100); // NOLINT this->wait_until_idle_(); + + // COMMAND VCOM AND DATA INTERVAL SETTING + this->command(0x50); + this->data(0x10); + this->data(0x07); + + // COMMAND TCON SETTING + this->command(0x60); + this->data(0x22); + // COMMAND PANEL SETTING this->command(0x00); this->data(0x1F); @@ -1582,19 +1610,30 @@ void WaveshareEPaper7P5InV2::initialize() { this->data(0x20); this->data(0x01); this->data(0xE0); - // COMMAND ...? + + // COMMAND DUAL SPI MM_EN, DUSPI_EN this->command(0x15); this->data(0x00); - // COMMAND VCOM AND DATA INTERVAL SETTING - this->command(0x50); - this->data(0x10); - this->data(0x07); - // COMMAND TCON SETTING - this->command(0x60); - this->data(0x22); + + // COMMAND POWER DRIVER HAT DOWN + // This command will turn off booster, controller, source driver, gate driver, VCOM, and + // temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode. + // Source/Gate/Border/VCOM will be released to floating. + this->command(0x02); } void HOT WaveshareEPaper7P5InV2::display() { uint32_t buf_len = this->get_buffer_length_(); + + // COMMAND POWER ON + ESP_LOGI(TAG, "Power on the display and hat"); + + // This command will turn on booster, controller, regulators, and temperature sensor will be + // activated for one-time sensing before enabling booster. When all voltages are ready, the + // BUSY_N signal will return to high. + this->command(0x04); + delay(200); // NOLINT + this->wait_until_idle_(); + // COMMAND DATA START TRANSMISSION NEW DATA this->command(0x13); delay(2); @@ -1602,14 +1641,23 @@ void HOT WaveshareEPaper7P5InV2::display() { this->data(~(this->buffer_[i])); } + delay(100); // NOLINT + this->wait_until_idle_(); + // COMMAND DISPLAY REFRESH this->command(0x12); delay(100); // NOLINT this->wait_until_idle_(); + + ESP_LOGV(TAG, "Before command(0x02) (>> power off)"); + this->command(0x02); + this->wait_until_idle_(); + ESP_LOGV(TAG, "After command(0x02) (>> power off)"); } int WaveshareEPaper7P5InV2::get_width_internal() { return 800; } int WaveshareEPaper7P5InV2::get_height_internal() { return 480; } +uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; } void WaveshareEPaper7P5InV2::dump_config() { LOG_DISPLAY("", "Waveshare E-Paper", this); ESP_LOGCONFIG(TAG, " Model: 7.5inV2rev2"); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 315af9ea82..b3325d69eb 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -472,6 +472,8 @@ class WaveshareEPaper7P5InBC : public WaveshareEPaper { class WaveshareEPaper7P5InV2 : public WaveshareEPaper { public: + bool wait_until_idle_(); + void initialize() override; void display() override; @@ -491,6 +493,8 @@ class WaveshareEPaper7P5InV2 : public WaveshareEPaper { int get_width_internal() override; int get_height_internal() override; + + uint32_t idle_timeout_() override; }; class WaveshareEPaper7P5InV2alt : public WaveshareEPaper7P5InV2 { From d76f18b4f24fe8cd554e2e9ed2f24bcd601e63ae Mon Sep 17 00:00:00 2001 From: rmmacias <46213351+rmmacias@users.noreply.github.com> Date: Sun, 17 Sep 2023 07:18:51 +0200 Subject: [PATCH 0498/2607] Update radon_eye_listener.cpp (#5401) New devices identifiers do not star by the hardcoded string. FR:RE222 is the 8-char length string of my devices bought in 2023. This proposal aims at solve the topic by making the detection track devices starting only by FR:R --- esphome/components/radon_eye_ble/radon_eye_listener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/radon_eye_ble/radon_eye_listener.cpp b/esphome/components/radon_eye_ble/radon_eye_listener.cpp index b10986c9cb..340322c188 100644 --- a/esphome/components/radon_eye_ble/radon_eye_listener.cpp +++ b/esphome/components/radon_eye_ble/radon_eye_listener.cpp @@ -10,7 +10,7 @@ static const char *const TAG = "radon_eye_ble"; bool RadonEyeListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { if (not device.get_name().empty()) { - if (device.get_name().rfind("FR:R20:SN", 0) == 0) { + if (device.get_name().rfind("FR:R", 0) == 0) { // This is an RD200, I think ESP_LOGD(TAG, "Found Radon Eye RD200 device Name: %s (MAC: %s)", device.get_name().c_str(), device.address_str().c_str()); From 4622ef770d8a62232eddc8a1315699f91ef1952c Mon Sep 17 00:00:00 2001 From: Trevor North Date: Sun, 17 Sep 2023 06:20:31 +0100 Subject: [PATCH 0499/2607] Add shelly-dimmer-stm32 51.7 to known versions (#5400) This version removes support for no-neutral setups in favor of fixing flickering some users have experienced. --- esphome/components/shelly_dimmer/light.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/shelly_dimmer/light.py b/esphome/components/shelly_dimmer/light.py index 467a3c3531..5bdb54baf5 100644 --- a/esphome/components/shelly_dimmer/light.py +++ b/esphome/components/shelly_dimmer/light.py @@ -57,6 +57,10 @@ KNOWN_FIRMWARE = { "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.6/shelly-dimmer-stm32_v51.6.bin", "eda483e111c914723a33f5088f1397d5c0b19333db4a88dc965636b976c16c36", ), + "51.7": ( + "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.7/shelly-dimmer-stm32_v51.7.bin", + "7a20f1c967c469917368a79bc56498009045237080408cef7190743e08031889", + ), } From 2fa7f8c5112333a65c1a5c2de85cc28687f0d1c7 Mon Sep 17 00:00:00 2001 From: Philipp Helo Rehs Date: Sun, 17 Sep 2023 07:30:52 +0200 Subject: [PATCH 0500/2607] Add E-Trailer Gaslevel support to Mopeka Std Check (#5397) * Add E-Trailer Gaslevel support to Mopeka Std Check Signed-off-by: Philipp Helo Rehs * fix format --------- Signed-off-by: Philipp Helo Rehs Co-authored-by: Philipp Helo Rehs --- esphome/components/mopeka_std_check/mopeka_std_check.cpp | 3 ++- esphome/components/mopeka_std_check/mopeka_std_check.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.cpp b/esphome/components/mopeka_std_check/mopeka_std_check.cpp index 67e749c68b..9dd1718cb2 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.cpp +++ b/esphome/components/mopeka_std_check/mopeka_std_check.cpp @@ -71,7 +71,8 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) const auto *mopeka_data = (const mopeka_std_package *) manu_data.data.data(); const u_int8_t hardware_id = mopeka_data->data_1 & 0xCF; - if (static_cast(hardware_id) != STANDARD && static_cast(hardware_id) != XL) { + if (static_cast(hardware_id) != STANDARD && static_cast(hardware_id) != XL && + static_cast(hardware_id) != ETRAILER) { ESP_LOGE(TAG, "[%s] Unsupported Sensor Type (0x%X)", device.address_str().c_str(), hardware_id); return false; } diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.h b/esphome/components/mopeka_std_check/mopeka_std_check.h index e4d81afbd7..ee588c8e5f 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.h +++ b/esphome/components/mopeka_std_check/mopeka_std_check.h @@ -14,6 +14,7 @@ namespace mopeka_std_check { enum SensorType { STANDARD = 0x02, XL = 0x03, + ETRAILER = 0x46, }; // 4 values in one struct so it aligns to 8 byte. One `mopeka_std_values` is 40 bit long. From e8862620556008834356669be14f93a2b3395d62 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 14:20:54 -0700 Subject: [PATCH 0501/2607] fix disabled wifi power on 8266 (#5409) Co-authored-by: Samuel Sieb --- esphome/components/wifi/wifi_component_esp8266.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 1afa439567..6e7c491967 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -98,6 +98,7 @@ bool WiFiComponent::wifi_apply_power_save_() { power_save = NONE_SLEEP_T; break; } + wifi_fpm_auto_sleep_set_in_null_mode(1); return wifi_set_sleep_type(power_save); } From e55636ed521bc2feda4ce690c9b6eba50a8cf1cb Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 14:25:16 -0700 Subject: [PATCH 0502/2607] fix handling of web server version (#5405) Co-authored-by: Samuel Sieb --- esphome/components/web_server/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index c6d9c31e93..966c978836 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -59,7 +59,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(WebServer), cv.Optional(CONF_PORT, default=80): cv.port, - cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2), + cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), cv.Optional(CONF_CSS_URL): cv.string, cv.Optional(CONF_CSS_INCLUDE): cv.file_, cv.Optional(CONF_JS_URL): cv.string, From 8f1ce8c7f7a6a86b0e9d98e9324f9ab6ff0e41e2 Mon Sep 17 00:00:00 2001 From: Joris S <100357138+Jorre05@users.noreply.github.com> Date: Wed, 20 Sep 2023 23:28:03 +0200 Subject: [PATCH 0503/2607] Climate preset fix (#5407) --- esphome/components/thermostat/thermostat_climate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp index 51da663a0c..386e13dc37 100644 --- a/esphome/components/thermostat/thermostat_climate.cpp +++ b/esphome/components/thermostat/thermostat_climate.cpp @@ -986,6 +986,7 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) { // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; assert(trig != nullptr); + this->preset = preset; trig->trigger(); this->refresh(); @@ -1010,6 +1011,7 @@ void ThermostatClimate::change_custom_preset_(const std::string &custom_preset) // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; assert(trig != nullptr); + this->custom_preset = custom_preset; trig->trigger(); this->refresh(); From 41c829fa32ec2b13eab7647ed806575e0f5897a4 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 20 Sep 2023 16:30:22 -0500 Subject: [PATCH 0504/2607] Remove Wi-Fi dependency from Midea component (#5394) --- esphome/components/midea/climate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/midea/climate.py b/esphome/components/midea/climate.py index 80b1461576..074ab8abb2 100644 --- a/esphome/components/midea/climate.py +++ b/esphome/components/midea/climate.py @@ -35,7 +35,7 @@ from esphome.components.climate import ( ) CODEOWNERS = ["@dudanov"] -DEPENDENCIES = ["climate", "uart", "wifi"] +DEPENDENCIES = ["climate", "uart"] AUTO_LOAD = ["sensor"] CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_POWER_USAGE = "power_usage" From 7ebe6a5894da94d1dd9c4c2e711e2c0ce8a087d3 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Wed, 20 Sep 2023 18:02:29 -0400 Subject: [PATCH 0505/2607] http_request: Cleanups and safety improvements (#5360) --- .../components/http_request/http_request.h | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 0958c07683..b885de18e6 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -80,8 +80,6 @@ template class HttpRequestSendAction : public Action { TEMPLATABLE_VALUE(std::string, url) TEMPLATABLE_VALUE(const char *, method) TEMPLATABLE_VALUE(std::string, body) - TEMPLATABLE_VALUE(const char *, useragent) - TEMPLATABLE_VALUE(uint16_t, timeout) void add_header(const char *key, TemplatableValue value) { this->headers_.insert({key, value}); } @@ -105,25 +103,18 @@ template class HttpRequestSendAction : public Action { auto f = std::bind(&HttpRequestSendAction::encode_json_func_, this, x..., std::placeholders::_1); this->parent_->set_body(json::build_json(f)); } - if (this->useragent_.has_value()) { - this->parent_->set_useragent(this->useragent_.value(x...)); - } - if (this->timeout_.has_value()) { - this->parent_->set_timeout(this->timeout_.value(x...)); - } - if (!this->headers_.empty()) { - std::list
headers; - for (const auto &item : this->headers_) { - auto val = item.second; - Header header; - header.name = item.first; - header.value = val.value(x...); - headers.push_back(header); - } - this->parent_->set_headers(headers); + std::list
headers; + for (const auto &item : this->headers_) { + auto val = item.second; + Header header; + header.name = item.first; + header.value = val.value(x...); + headers.push_back(header); } + this->parent_->set_headers(headers); this->parent_->send(this->response_triggers_); this->parent_->close(); + this->parent_->set_body(""); } protected: From 807c47a076e202d681affe65414b49c40a0015d5 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Thu, 21 Sep 2023 08:04:03 +1000 Subject: [PATCH 0506/2607] Make the pulse meter timeout on startup when no pulses are received (#5388) --- .../pulse_meter/pulse_meter_sensor.cpp | 35 +++++++++++++------ .../pulse_meter/pulse_meter_sensor.h | 3 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 7eef18e5e0..be5fad6fe5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -11,6 +11,9 @@ void PulseMeterSensor::setup() { this->pin_->setup(); this->isr_pin_ = pin_->to_isr(); + // Set the last processed edge to now for the first timeout + this->last_processed_edge_us_ = micros(); + if (this->filter_mode_ == FILTER_EDGE) { this->pin_->attach_interrupt(PulseMeterSensor::edge_intr, this, gpio::INTERRUPT_RISING_EDGE); } else if (this->filter_mode_ == FILTER_PULSE) { @@ -38,12 +41,16 @@ void PulseMeterSensor::loop() { } // We need to detect at least two edges to have a valid pulse width - if (!this->initialized_) { - this->initialized_ = true; - } else { - uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; - float pulse_width_us = delta_us / float(this->get_->count_); - this->publish_state((60.0f * 1000000.0f) / pulse_width_us); + switch (this->meter_state_) { + case MeterState::INITIAL: + case MeterState::TIMED_OUT: { + this->meter_state_ = MeterState::RUNNING; + } break; + case MeterState::RUNNING: { + uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; + float pulse_width_us = delta_us / float(this->get_->count_); + this->publish_state((60.0f * 1000000.0f) / pulse_width_us); + } break; } this->last_processed_edge_us_ = this->get_->last_detected_edge_us_; @@ -53,10 +60,18 @@ void PulseMeterSensor::loop() { const uint32_t now = micros(); const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_; - if (this->initialized_ && time_since_valid_edge_us > this->timeout_us_) { - ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); - this->initialized_ = false; - this->publish_state(0.0f); + switch (this->meter_state_) { + // Running and initial states can timeout + case MeterState::INITIAL: + case MeterState::RUNNING: { + if (time_since_valid_edge_us > this->timeout_us_) { + this->meter_state_ = MeterState::TIMED_OUT; + ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); + this->publish_state(0.0f); + } + } break; + default: + break; } } } diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index ddd42c2ed5..f376ea48a5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -38,7 +38,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component { InternalFilterMode filter_mode_{FILTER_EDGE}; // Variables used in the loop - bool initialized_ = false; + enum class MeterState { INITIAL, RUNNING, TIMED_OUT }; + MeterState meter_state_ = MeterState::INITIAL; uint32_t total_pulses_ = 0; uint32_t last_processed_edge_us_ = 0; From d7e267eca53e47beec3496e9458ccce151d25ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 21 Sep 2023 00:09:23 +0200 Subject: [PATCH 0507/2607] Wizard: fix colored text in input prompts (#5313) --- esphome/util.py | 14 ++++++++++---- esphome/wizard.py | 18 ++++++++++-------- tests/unit_tests/test_wizard.py | 12 ++++++------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/esphome/util.py b/esphome/util.py index 0d60212f50..480618aca0 100644 --- a/esphome/util.py +++ b/esphome/util.py @@ -57,7 +57,7 @@ class SimpleRegistry(dict): return decorator -def safe_print(message=""): +def safe_print(message="", end="\n"): from esphome.core import CORE if CORE.dashboard: @@ -67,20 +67,26 @@ def safe_print(message=""): pass try: - print(message) + print(message, end=end) return except UnicodeEncodeError: pass try: - print(message.encode("utf-8", "backslashreplace")) + print(message.encode("utf-8", "backslashreplace"), end=end) except UnicodeEncodeError: try: - print(message.encode("ascii", "backslashreplace")) + print(message.encode("ascii", "backslashreplace"), end=end) except UnicodeEncodeError: print("Cannot print line because of invalid locale!") +def safe_input(prompt=""): + if prompt: + safe_print(prompt, end="") + return input() + + def shlex_quote(s): if not s: return "''" diff --git a/esphome/wizard.py b/esphome/wizard.py index aa05e513a7..1308338ad0 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -11,7 +11,7 @@ from esphome.core import CORE from esphome.helpers import get_bool_env, write_file from esphome.log import Fore, color from esphome.storage_json import StorageJSON, ext_storage_path -from esphome.util import safe_print +from esphome.util import safe_input, safe_print CORE_BIG = r""" _____ ____ _____ ______ / ____/ __ \| __ \| ____| @@ -252,7 +252,7 @@ def safe_print_step(step, big): def default_input(text, default): safe_print() safe_print(f"Press ENTER for default ({default})") - return input(text.format(default)) or default + return safe_input(text.format(default)) or default # From https://stackoverflow.com/a/518232/8924614 @@ -306,7 +306,7 @@ def wizard(path): ) safe_print() sleep(1) - name = input(color(Fore.BOLD_WHITE, "(name): ")) + name = safe_input(color(Fore.BOLD_WHITE, "(name): ")) while True: try: @@ -343,7 +343,9 @@ def wizard(path): while True: sleep(0.5) safe_print() - platform = input(color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ")) + platform = safe_input( + color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ") + ) try: platform = vol.All(vol.Upper, vol.Any(*wizard_platforms))(platform.upper()) break @@ -397,7 +399,7 @@ def wizard(path): boards.append(board_id) while True: - board = input(color(Fore.BOLD_WHITE, "(board): ")) + board = safe_input(color(Fore.BOLD_WHITE, "(board): ")) try: board = vol.All(vol.Lower, vol.Any(*boards))(board) break @@ -423,7 +425,7 @@ def wizard(path): sleep(1.5) safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'Abraham Linksys')}\".") while True: - ssid = input(color(Fore.BOLD_WHITE, "(ssid): ")) + ssid = safe_input(color(Fore.BOLD_WHITE, "(ssid): ")) try: ssid = cv.ssid(ssid) break @@ -449,7 +451,7 @@ def wizard(path): safe_print() safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'PASSWORD42')}\"") sleep(0.5) - psk = input(color(Fore.BOLD_WHITE, "(PSK): ")) + psk = safe_input(color(Fore.BOLD_WHITE, "(PSK): ")) safe_print( "Perfect! WiFi is now set up (you can create static IPs and so on later)." ) @@ -466,7 +468,7 @@ def wizard(path): safe_print() sleep(0.25) safe_print("Press ENTER for no password") - password = input(color(Fore.BOLD_WHITE, "(password): ")) + password = safe_input(color(Fore.BOLD_WHITE, "(password): ")) if not wizard_write( path=path, diff --git a/tests/unit_tests/test_wizard.py b/tests/unit_tests/test_wizard.py index 8bbce08ae5..46700a3ba8 100644 --- a/tests/unit_tests/test_wizard.py +++ b/tests/unit_tests/test_wizard.py @@ -319,7 +319,7 @@ def test_wizard_accepts_default_answers_esp8266(tmpdir, monkeypatch, wizard_answ config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -341,7 +341,7 @@ def test_wizard_accepts_default_answers_esp32(tmpdir, monkeypatch, wizard_answer config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -371,7 +371,7 @@ def test_wizard_offers_better_node_name(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -394,7 +394,7 @@ def test_wizard_requires_correct_platform(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -416,7 +416,7 @@ def test_wizard_requires_correct_board(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) @@ -438,7 +438,7 @@ def test_wizard_requires_valid_ssid(tmpdir, monkeypatch, wizard_answers): config_file = tmpdir.join("test.yaml") input_mock = MagicMock(side_effect=wizard_answers) monkeypatch.setattr("builtins.input", input_mock) - monkeypatch.setattr(wz, "safe_print", lambda t=None: 0) + monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0) monkeypatch.setattr(wz, "sleep", lambda _: 0) monkeypatch.setattr(wz, "wizard_write", MagicMock()) From 5b46088ae4089fa8f8c02f3a54a86d2f9da0bb24 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 20 Sep 2023 15:26:36 -0700 Subject: [PATCH 0508/2607] support keypads with pulldowns (#5404) Co-authored-by: Samuel Sieb --- esphome/components/matrix_keypad/__init__.py | 4 ++++ .../components/matrix_keypad/matrix_keypad.cpp | 17 +++++++++++------ .../components/matrix_keypad/matrix_keypad.h | 2 ++ tests/test5.yaml | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/esphome/components/matrix_keypad/__init__.py b/esphome/components/matrix_keypad/__init__.py index 1c549007b9..5250a45732 100644 --- a/esphome/components/matrix_keypad/__init__.py +++ b/esphome/components/matrix_keypad/__init__.py @@ -21,6 +21,7 @@ CONF_COLUMNS = "columns" CONF_KEYS = "keys" CONF_DEBOUNCE_TIME = "debounce_time" CONF_HAS_DIODES = "has_diodes" +CONF_HAS_PULLDOWNS = "has_pulldowns" def check_keys(obj): @@ -45,6 +46,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_KEYS): cv.string, cv.Optional(CONF_DEBOUNCE_TIME, default=1): cv.int_range(min=1, max=100), cv.Optional(CONF_HAS_DIODES): cv.boolean, + cv.Optional(CONF_HAS_PULLDOWNS): cv.boolean, } ), check_keys, @@ -69,3 +71,5 @@ async def to_code(config): cg.add(var.set_debounce_time(config[CONF_DEBOUNCE_TIME])) if CONF_HAS_DIODES in config: cg.add(var.set_has_diodes(config[CONF_HAS_DIODES])) + if CONF_HAS_PULLDOWNS in config: + cg.add(var.set_has_pulldowns(config[CONF_HAS_PULLDOWNS])) diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index 4f8962a782..902e574846 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -11,11 +11,16 @@ void MatrixKeypad::setup() { if (!has_diodes_) { pin->pin_mode(gpio::FLAG_INPUT); } else { - pin->digital_write(true); + pin->digital_write(!has_pulldowns_); + } + } + for (auto *pin : this->columns_) { + if (has_pulldowns_) { + pin->pin_mode(gpio::FLAG_INPUT); + } else { + pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); } } - for (auto *pin : this->columns_) - pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); } void MatrixKeypad::loop() { @@ -28,9 +33,9 @@ void MatrixKeypad::loop() { for (auto *row : this->rows_) { if (!has_diodes_) row->pin_mode(gpio::FLAG_OUTPUT); - row->digital_write(false); + row->digital_write(has_pulldowns_); for (auto *col : this->columns_) { - if (!col->digital_read()) { + if (col->digital_read() == has_pulldowns_) { if (key != -1) { error = true; } else { @@ -39,7 +44,7 @@ void MatrixKeypad::loop() { } pos++; } - row->digital_write(true); + row->digital_write(!has_pulldowns_); if (!has_diodes_) row->pin_mode(gpio::FLAG_INPUT); } diff --git a/esphome/components/matrix_keypad/matrix_keypad.h b/esphome/components/matrix_keypad/matrix_keypad.h index 9f5942be9a..d506040b7c 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.h +++ b/esphome/components/matrix_keypad/matrix_keypad.h @@ -28,6 +28,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { void set_keys(std::string keys) { keys_ = std::move(keys); }; void set_debounce_time(int debounce_time) { debounce_time_ = debounce_time; }; void set_has_diodes(int has_diodes) { has_diodes_ = has_diodes; }; + void set_has_pulldowns(int has_pulldowns) { has_pulldowns_ = has_pulldowns; }; void register_listener(MatrixKeypadListener *listener); @@ -37,6 +38,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { std::string keys_; int debounce_time_ = 0; bool has_diodes_{false}; + bool has_pulldowns_{false}; int pressed_key_ = -1; std::vector listeners_{}; diff --git a/tests/test5.yaml b/tests/test5.yaml index 274570aad6..5727d30e61 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -667,6 +667,7 @@ matrix_keypad: - pin: 17 - pin: 16 keys: "1234" + has_pulldowns: true key_collector: - id: reader From 90835ab917ec52e2e9de464477f9e24988392be0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 21 Sep 2023 10:35:38 +1200 Subject: [PATCH 0509/2607] Bump version to 2023.9.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cbb31e0ec6..8a10776c4a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0b1" +__version__ = "2023.9.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 518ecb4cc4489c8a76b899bfda7576b05d84c226 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:15:50 +1000 Subject: [PATCH 0510/2607] Fix SPI inverted clock on ESP8266 (#5416) --- esphome/components/spi/spi.h | 6 ++---- esphome/components/spi/spi_arduino.cpp | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 2761c2d604..56aa746fc9 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -351,6 +351,7 @@ class SPIClient { : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {} virtual void spi_setup() { + esph_log_d("spi_device", "mode %u, data_rate %ukHz", (unsigned) this->mode_, (unsigned) (this->data_rate_ / 1000)); this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_); } @@ -398,10 +399,7 @@ class SPIDevice : public SPIClient { void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; } - void set_bit_order(SPIBitOrder order) { - this->bit_order_ = order; - esph_log_d("spi.h", "bit order set to %d", order); - } + void set_bit_order(SPIBitOrder order) { this->bit_order_ = order; } void set_mode(SPIMode mode) { this->mode_ = mode; } diff --git a/esphome/components/spi/spi_arduino.cpp b/esphome/components/spi/spi_arduino.cpp index 40ed9e6062..2e6b2d6064 100644 --- a/esphome/components/spi/spi_arduino.cpp +++ b/esphome/components/spi/spi_arduino.cpp @@ -15,6 +15,11 @@ class SPIDelegateHw : public SPIDelegate { void begin_transaction() override { #ifdef USE_RP2040 SPISettings const settings(this->data_rate_, static_cast(this->bit_order_), this->mode_); +#elif defined(ESP8266) + // Arduino ESP8266 library has mangled values for SPI modes :-( + auto mode = (this->mode_ & 0x01) + ((this->mode_ & 0x02) << 3); + ESP_LOGV(TAG, "8266 mangled SPI mode 0x%X", mode); + SPISettings const settings(this->data_rate_, this->bit_order_, mode); #else SPISettings const settings(this->data_rate_, this->bit_order_, this->mode_); #endif From 3c7c4e1dbaf25c9fa35247328aa76c03fda53fac Mon Sep 17 00:00:00 2001 From: Andrew Garrett Date: Sun, 24 Sep 2023 19:34:37 +1000 Subject: [PATCH 0511/2607] Make ESPHome data dir configurable (#5417) --- esphome/core/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index cca758e3c1..4897b073fa 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -21,7 +21,7 @@ from esphome.coroutine import FakeEventLoop as _FakeEventLoop # pylint: disable=unused-import from esphome.coroutine import coroutine, coroutine_with_priority # noqa -from esphome.helpers import ensure_unique_string, is_ha_addon +from esphome.helpers import ensure_unique_string, get_str_env, is_ha_addon from esphome.util import OrderedDict if TYPE_CHECKING: @@ -558,6 +558,8 @@ class EsphomeCore: def data_dir(self): if is_ha_addon(): return os.path.join("/data") + if get_str_env("ESPHOME_DATA_DIR", None) is not None: + return get_str_env("ESPHOME_DATA_DIR", None) return self.relative_config_path(".esphome") @property From 0ca8dcd08e96b431f8034acc16a7f9c2ab64eb84 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Sun, 24 Sep 2023 12:44:55 +0300 Subject: [PATCH 0512/2607] [RP2040W] Fix WiFi bootloop upon LibreTiny support (#5414) --- esphome/components/rp2040/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index b31192f73f..5d8608c44d 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -152,6 +152,9 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): cg.add(rp2040_ns.setup_preferences()) + # Allow LDF to properly discover dependency including those in preprocessor + # conditionals + cg.add_platformio_option("lib_ldf_mode", "chain+") cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_build_flag("-DUSE_RP2040") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) From 727056a28c8c59351ac3be6a9ee2fa1e4343ef47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Sun, 24 Sep 2023 23:15:28 +0200 Subject: [PATCH 0513/2607] dallas: limit addresses to 64 bits (#5413) --- esphome/components/dallas/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py index 9288f0a3a6..c6ebda62c8 100644 --- a/esphome/components/dallas/sensor.py +++ b/esphome/components/dallas/sensor.py @@ -24,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ).extend( { cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent), - cv.Optional(CONF_ADDRESS): cv.hex_int, + cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, cv.Optional(CONF_INDEX): cv.positive_int, cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12), } From c34d5111fceb3f16f147c9aeb7bd7684a39dc454 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:23:40 +1300 Subject: [PATCH 0514/2607] Bump actions/checkout from 4.0.0 to 4.1.0 (#5420) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 22 +++++++++++----------- .github/workflows/release.yml | 6 +++--- .github/workflows/sync-device-classes.yml | 4 ++-- .github/workflows/yaml-lint.yml | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index b53eaf8e1a..7fe51163ba 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4.0.0 + - uses: actions/checkout@v4.1.0 - name: Set up Python uses: actions/setup-python@v4.7.0 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 792d972311..26fcbbf458 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -66,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -87,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -108,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -129,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -150,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -171,7 +171,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -191,7 +191,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -216,7 +216,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Find all YAML test files id: set-matrix run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT @@ -241,7 +241,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -296,7 +296,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 99d1594f03..6934d36686 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: outputs: tag: ${{ steps.tag.outputs.tag }} steps: - - uses: actions/checkout@v4.0.0 + - uses: actions/checkout@v4.1.0 - name: Get tag id: tag # yamllint disable rule:line-length @@ -43,7 +43,7 @@ jobs: if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.0.0 + - uses: actions/checkout@v4.1.0 - name: Set up Python uses: actions/setup-python@v4.7.0 with: @@ -88,7 +88,7 @@ jobs: target: "lint" baseimg: "docker" steps: - - uses: actions/checkout@v4.0.0 + - uses: actions/checkout@v4.1.0 - name: Set up Python uses: actions/setup-python@v4.7.0 with: diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 943e93a0b7..25d36bc6d0 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -13,10 +13,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Checkout Home Assistant - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 with: repository: home-assistant/core path: lib/home-assistant diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index 77b3c1dcb5..65628a22bb 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v4.0.0 + uses: actions/checkout@v4.1.0 - name: Run yamllint uses: frenck/action-yamllint@v1.4.1 From a031cc3b848b942119d63b6673027e39d2c26259 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:25:51 +1300 Subject: [PATCH 0515/2607] Bump zeroconf from 0.108.0 to 0.112.0 (#5392) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 19c05bf8f7..63199680cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.108.0 +zeroconf==0.112.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 17e1d4c2455997a0a15c875950be1942c6249d0d Mon Sep 17 00:00:00 2001 From: Kapil Yedidi Date: Sun, 24 Sep 2023 16:05:56 -0700 Subject: [PATCH 0516/2607] Fix typo in documentation (#5425) --- esphome/components/pmsa003i/pmsa003i.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/pmsa003i/pmsa003i.h b/esphome/components/pmsa003i/pmsa003i.h index 10176218ed..1fe4139951 100644 --- a/esphome/components/pmsa003i/pmsa003i.h +++ b/esphome/components/pmsa003i/pmsa003i.h @@ -17,12 +17,12 @@ struct PM25AQIData { 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 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 }; From b07a038bc8f17afe9aa6bdde6b8ec929b1120945 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:15:50 +1000 Subject: [PATCH 0517/2607] Fix SPI inverted clock on ESP8266 (#5416) --- esphome/components/spi/spi.h | 6 ++---- esphome/components/spi/spi_arduino.cpp | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 2761c2d604..56aa746fc9 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -351,6 +351,7 @@ class SPIClient { : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {} virtual void spi_setup() { + esph_log_d("spi_device", "mode %u, data_rate %ukHz", (unsigned) this->mode_, (unsigned) (this->data_rate_ / 1000)); this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_); } @@ -398,10 +399,7 @@ class SPIDevice : public SPIClient { void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; } - void set_bit_order(SPIBitOrder order) { - this->bit_order_ = order; - esph_log_d("spi.h", "bit order set to %d", order); - } + void set_bit_order(SPIBitOrder order) { this->bit_order_ = order; } void set_mode(SPIMode mode) { this->mode_ = mode; } diff --git a/esphome/components/spi/spi_arduino.cpp b/esphome/components/spi/spi_arduino.cpp index 40ed9e6062..2e6b2d6064 100644 --- a/esphome/components/spi/spi_arduino.cpp +++ b/esphome/components/spi/spi_arduino.cpp @@ -15,6 +15,11 @@ class SPIDelegateHw : public SPIDelegate { void begin_transaction() override { #ifdef USE_RP2040 SPISettings const settings(this->data_rate_, static_cast(this->bit_order_), this->mode_); +#elif defined(ESP8266) + // Arduino ESP8266 library has mangled values for SPI modes :-( + auto mode = (this->mode_ & 0x01) + ((this->mode_ & 0x02) << 3); + ESP_LOGV(TAG, "8266 mangled SPI mode 0x%X", mode); + SPISettings const settings(this->data_rate_, this->bit_order_, mode); #else SPISettings const settings(this->data_rate_, this->bit_order_, this->mode_); #endif From a42788812e5136e8235c76df2bb0526d1436a417 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Sun, 24 Sep 2023 12:44:55 +0300 Subject: [PATCH 0518/2607] [RP2040W] Fix WiFi bootloop upon LibreTiny support (#5414) --- esphome/components/rp2040/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index b31192f73f..5d8608c44d 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -152,6 +152,9 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): cg.add(rp2040_ns.setup_preferences()) + # Allow LDF to properly discover dependency including those in preprocessor + # conditionals + cg.add_platformio_option("lib_ldf_mode", "chain+") cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_build_flag("-DUSE_RP2040") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) From 33e2aa341e63a925123a27b758769a70ff012195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Sun, 24 Sep 2023 23:15:28 +0200 Subject: [PATCH 0519/2607] dallas: limit addresses to 64 bits (#5413) --- esphome/components/dallas/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py index 9288f0a3a6..c6ebda62c8 100644 --- a/esphome/components/dallas/sensor.py +++ b/esphome/components/dallas/sensor.py @@ -24,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ).extend( { cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent), - cv.Optional(CONF_ADDRESS): cv.hex_int, + cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, cv.Optional(CONF_INDEX): cv.positive_int, cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12), } From 0aeebdd2896cd5cf6d262fea41269c1dc21c3307 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:25:51 +1300 Subject: [PATCH 0520/2607] Bump zeroconf from 0.108.0 to 0.112.0 (#5392) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 19c05bf8f7..63199680cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.108.0 +zeroconf==0.112.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 5f5ee9c9204bda8b38d86eac065781a87b2ea27a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 25 Sep 2023 12:10:35 +1300 Subject: [PATCH 0521/2607] Bump version to 2023.9.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8a10776c4a..f5319adfa7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0b2" +__version__ = "2023.9.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 607d0b426402ff27324f05c881c617162c2a8a7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 09:28:25 +1300 Subject: [PATCH 0522/2607] Bump pylint from 2.17.5 to 2.17.6 (#5429) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index a07815df54..92cb8b1be2 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==2.17.5 +pylint==2.17.6 flake8==6.1.0 # also change in .pre-commit-config.yaml when updating black==23.9.1 # also change in .pre-commit-config.yaml when updating pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating From 2f7a378c7b87cd11b750b36475f6129599ffda8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 26 Sep 2023 23:23:21 +0200 Subject: [PATCH 0523/2607] LibreTiny: enable MQTT, bump to v1.4.1 (#5419) --- esphome/components/libretiny/__init__.py | 2 +- esphome/components/mqtt/__init__.py | 8 +- .../components/mqtt/mqtt_backend_libretiny.h | 74 +++++++++++++++++++ esphome/components/mqtt/mqtt_client.cpp | 5 +- esphome/components/mqtt/mqtt_client.h | 4 + 5 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 esphome/components/mqtt/mqtt_backend_libretiny.h diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 3c1c0ac3f0..b01d342a87 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -170,7 +170,7 @@ def _notify_old_style(config): ARDUINO_VERSIONS = { "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"), "latest": (cv.Version(0, 0, 0), None), - "recommended": (cv.Version(1, 4, 0), None), + "recommended": (cv.Version(1, 4, 1), None), } diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 9df2067832..10ae8ac40d 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -250,7 +250,7 @@ CONFIG_SCHEMA = cv.All( } ), validate_config, - cv.only_on(["esp32", "esp8266"]), + cv.only_on(["esp32", "esp8266", "bk72xx"]), ) @@ -271,10 +271,10 @@ def exp_mqtt_message(config): async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - # Add required libraries for ESP8266 - if CORE.is_esp8266: + # Add required libraries for ESP8266 and LibreTiny + if CORE.is_esp8266 or CORE.is_libretiny: # https://github.com/heman/async-mqtt-client/blob/master/library.json - cg.add_library("heman/AsyncMqttClient-esphome", "1.0.0") + cg.add_library("heman/AsyncMqttClient-esphome", "2.0.0") cg.add_define("USE_MQTT") cg.add_global(mqtt_ns.using) diff --git a/esphome/components/mqtt/mqtt_backend_libretiny.h b/esphome/components/mqtt/mqtt_backend_libretiny.h new file mode 100644 index 0000000000..5373a1926a --- /dev/null +++ b/esphome/components/mqtt/mqtt_backend_libretiny.h @@ -0,0 +1,74 @@ +#pragma once + +#ifdef USE_LIBRETINY + +#include "mqtt_backend.h" +#include + +namespace esphome { +namespace mqtt { + +class MQTTBackendLibreTiny final : public MQTTBackend { + public: + void set_keep_alive(uint16_t keep_alive) final { mqtt_client_.setKeepAlive(keep_alive); } + void set_client_id(const char *client_id) final { mqtt_client_.setClientId(client_id); } + void set_clean_session(bool clean_session) final { mqtt_client_.setCleanSession(clean_session); } + void set_credentials(const char *username, const char *password) final { + mqtt_client_.setCredentials(username, password); + } + void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final { + mqtt_client_.setWill(topic, qos, retain, payload); + } + void set_server(network::IPAddress ip, uint16_t port) final { + mqtt_client_.setServer(IPAddress(static_cast(ip)), port); + } + void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); } +#if ASYNC_TCP_SSL_ENABLED + void set_secure(bool secure) { mqtt_client.setSecure(secure); } + void add_server_fingerprint(const uint8_t *fingerprint) { mqtt_client.addServerFingerprint(fingerprint); } +#endif + + void set_on_connect(std::function &&callback) final { + this->mqtt_client_.onConnect(std::move(callback)); + } + void set_on_disconnect(std::function &&callback) final { + auto async_callback = [callback](AsyncMqttClientDisconnectReason reason) { + // int based enum so casting isn't a problem + callback(static_cast(reason)); + }; + this->mqtt_client_.onDisconnect(std::move(async_callback)); + } + void set_on_subscribe(std::function &&callback) final { + this->mqtt_client_.onSubscribe(std::move(callback)); + } + void set_on_unsubscribe(std::function &&callback) final { + this->mqtt_client_.onUnsubscribe(std::move(callback)); + } + void set_on_message(std::function &&callback) final { + auto async_callback = [callback](const char *topic, const char *payload, + AsyncMqttClientMessageProperties async_properties, size_t len, size_t index, + size_t total) { callback(topic, payload, len, index, total); }; + mqtt_client_.onMessage(std::move(async_callback)); + } + void set_on_publish(std::function &&callback) final { + this->mqtt_client_.onPublish(std::move(callback)); + } + + bool connected() const final { return mqtt_client_.connected(); } + void connect() final { mqtt_client_.connect(); } + void disconnect() final { mqtt_client_.disconnect(true); } + bool subscribe(const char *topic, uint8_t qos) final { return mqtt_client_.subscribe(topic, qos) != 0; } + bool unsubscribe(const char *topic) final { return mqtt_client_.unsubscribe(topic) != 0; } + bool publish(const char *topic, const char *payload, size_t length, uint8_t qos, bool retain) final { + return mqtt_client_.publish(topic, qos, retain, payload, length, false, 0) != 0; + } + using MQTTBackend::publish; + + protected: + AsyncMqttClient mqtt_client_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif // defined(USE_LIBRETINY) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 0c6da42328..fd5e13ecc7 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -106,6 +106,9 @@ void MQTTClientComponent::send_device_info_() { #ifdef USE_ESP32 root["platform"] = "ESP32"; #endif +#ifdef USE_LIBRETINY + root["platform"] = lt_cpu_get_model_name(); +#endif root["board"] = ESPHOME_BOARD; #if defined(USE_WIFI) @@ -156,7 +159,7 @@ void MQTTClientComponent::start_dnslookup_() { this->dns_resolve_error_ = false; this->dns_resolved_ = false; ip_addr_t addr; -#ifdef USE_ESP32 +#if defined(USE_ESP32) || defined(USE_LIBRETINY) err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr, MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV4); #endif diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 00eb3fdd40..bcb44ab4c2 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -13,6 +13,8 @@ #include "mqtt_backend_esp32.h" #elif defined(USE_ESP8266) #include "mqtt_backend_esp8266.h" +#elif defined(USE_LIBRETINY) +#include "mqtt_backend_libretiny.h" #endif #include "lwip/ip_addr.h" @@ -300,6 +302,8 @@ class MQTTClientComponent : public Component { MQTTBackendESP32 mqtt_backend_; #elif defined(USE_ESP8266) MQTTBackendESP8266 mqtt_backend_; +#elif defined(USE_LIBRETINY) + MQTTBackendLibreTiny mqtt_backend_; #endif MQTTClientState state_{MQTT_CLIENT_DISCONNECTED}; From 86db559f6e8edf1f0e69cb300dedd1954ab766bd Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Tue, 26 Sep 2023 20:25:00 -0300 Subject: [PATCH 0524/2607] Wireguard keepalive remove uint16 type (#5430) --- esphome/components/wireguard/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 717fe50d2c..acb5f690ec 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_REBOOT_TIMEOUT, ) from esphome.components import time +from esphome.core import TimePeriod CONF_NETMASK = "netmask" CONF_PRIVATE_KEY = "private_key" @@ -59,9 +60,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_PEER_ALLOWED_IPS, default=["0.0.0.0/0"]): cv.ensure_list( _cidr_network ), - cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default=0): cv.Any( + cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default="0s"): cv.All( cv.positive_time_period_seconds, - cv.uint16_t, + cv.Range(max=TimePeriod(seconds=65535)), ), cv.Optional( CONF_REBOOT_TIMEOUT, default="15min" From 5360e14a9ce3f6e0b3e169ef0c555323a68ed81b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 27 Sep 2023 09:25:14 +1000 Subject: [PATCH 0525/2607] Fix #4896 and #4903 (#5433) --- CODEOWNERS | 2 +- esphome/components/ili9xxx/display.py | 9 +++---- .../components/ili9xxx/ili9xxx_display.cpp | 12 ++++++++++ esphome/components/ili9xxx/ili9xxx_display.h | 6 +++++ esphome/components/ili9xxx/ili9xxx_init.h | 24 +++++++++++++++++++ tests/test1.yaml | 1 + 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 22e46aa2f0..3920a9100e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -131,7 +131,7 @@ esphome/components/i2s_audio/* @jesserockz esphome/components/i2s_audio/media_player/* @jesserockz esphome/components/i2s_audio/microphone/* @jesserockz esphome/components/i2s_audio/speaker/* @jesserockz -esphome/components/ili9xxx/* @nielsnl68 +esphome/components/ili9xxx/* @clydebarrow @nielsnl68 esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core esphome/components/ina260/* @mreditor97 diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 0435460b6a..89a6b2d1b9 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -25,7 +25,7 @@ def AUTO_LOAD(): return [] -CODEOWNERS = ["@nielsnl68"] +CODEOWNERS = ["@nielsnl68", "@clydebarrow"] ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx") ili9XXXSPI = ili9XXX_ns.class_( @@ -42,6 +42,7 @@ MODELS = { "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI), + "ILI9481-18": ili9XXX_ns.class_("ILI9XXXILI948118", ili9XXXSPI), "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ILI9488_A": ili9XXX_ns.class_("ILI9XXXILI9488A", ili9XXXSPI), @@ -140,8 +141,6 @@ async def to_code(config): rhs = [] for x in range(256): rhs.extend([HexInt(x), HexInt(x), HexInt(x)]) - prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) - cg.add(var.set_palette(prog_arr)) elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE": cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED)) from PIL import Image @@ -178,6 +177,4 @@ async def to_code(config): if rhs is not None: prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) - - spi_data_rate = str(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]]) - cg.add_define("ILI9XXXDisplay_DATA_RATE", cg.RawExpression(spi_data_rate)) + cg.add(var.set_data_rate(config[CONF_DATA_RATE])) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 750f629db2..abe01ea8c3 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -59,6 +59,7 @@ void ILI9XXXDisplay::dump_config() { if (this->is_18bitdisplay_) { ESP_LOGCONFIG(TAG, " 18-Bit Mode: YES"); } + ESP_LOGCONFIG(TAG, " Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_); @@ -387,6 +388,17 @@ void ILI9XXXILI9481::initialize() { } } +void ILI9XXXILI948118::initialize() { + this->init_lcd_(INITCMD_ILI9481_18); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 480; + } + this->is_18bitdisplay_ = true; +} + // 35_TFT display void ILI9XXXILI9486::initialize() { this->init_lcd_(INITCMD_ILI9486); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 15b08e6c76..4e8355b9a5 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -120,6 +120,12 @@ class ILI9XXXILI9481 : public ILI9XXXDisplay { void initialize() override; }; +//----------- ILI9481 in 18 bit mode -------------- +class ILI9XXXILI948118 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + //----------- ILI9XXX_35_TFT rotated display -------------- class ILI9XXXILI9486 : public ILI9XXXDisplay { protected: diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 1856fb06ab..031dc25f91 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -94,12 +94,36 @@ static const uint8_t PROGMEM INITCMD_ILI9481[] = { ILI9XXX_IFCTR , 1, 0x83, ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00, ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect + ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF, 0xE4 , 1, 0xA0, + ILI9XXX_MADCTL , 1, MADCTL_MV | MADCTL_BGR, // Memory Access Control ILI9XXX_CSCON , 1, 0x01, + ILI9XXX_PIXFMT, 1, 0x55, // 16 bit mode + ILI9XXX_INVON, 0, ILI9XXX_DISPON, 0x80, // Set display on 0x00 // end }; +static const uint8_t PROGMEM INITCMD_ILI9481_18[] = { + ILI9XXX_SLPOUT , 0x80, // Exit sleep mode + ILI9XXX_PWSET , 3, 0x07, 0x41, 0x1D, + ILI9XXX_VMCTR , 3, 0x00, 0x1C, 0x1F, + ILI9XXX_PWSETN , 2, 0x01, 0x11, + ILI9XXX_PWCTR1 , 5, 0x10, 0x3B, 0x00, 0x02, 0x11, + ILI9XXX_VMCTR1 , 1, 0x03, + ILI9XXX_IFCTR , 1, 0x83, + ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00, + ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect + ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF, + 0xE4 , 1, 0xA0, + ILI9XXX_MADCTL , 1, MADCTL_MX| MADCTL_BGR, // Memory Access Control + ILI9XXX_CSCON , 1, 0x01, + ILI9XXX_PIXFMT, 1, 0x66, // 18 bit mode + ILI9XXX_INVON, 0, + ILI9XXX_DISPON, 0x80, // Set display on + 0x00 // end +}; + static const uint8_t PROGMEM INITCMD_ILI9486[] = { ILI9XXX_SLPOUT, 0x80, ILI9XXX_PIXFMT, 1, 0x55, diff --git a/tests/test1.yaml b/tests/test1.yaml index fe983cf421..350057e3cc 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2972,6 +2972,7 @@ display: model: TFT 2.4 cs_pin: GPIO5 dc_pin: GPIO4 + color_palette: GRAYSCALE reset_pin: GPIO22 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); From b30bab8c1b310b5cb03bde7f86d8d8fc2e6ae3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 26 Sep 2023 23:23:21 +0200 Subject: [PATCH 0526/2607] LibreTiny: enable MQTT, bump to v1.4.1 (#5419) --- esphome/components/libretiny/__init__.py | 2 +- esphome/components/mqtt/__init__.py | 8 +- .../components/mqtt/mqtt_backend_libretiny.h | 74 +++++++++++++++++++ esphome/components/mqtt/mqtt_client.cpp | 5 +- esphome/components/mqtt/mqtt_client.h | 4 + 5 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 esphome/components/mqtt/mqtt_backend_libretiny.h diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 3c1c0ac3f0..b01d342a87 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -170,7 +170,7 @@ def _notify_old_style(config): ARDUINO_VERSIONS = { "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"), "latest": (cv.Version(0, 0, 0), None), - "recommended": (cv.Version(1, 4, 0), None), + "recommended": (cv.Version(1, 4, 1), None), } diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 9df2067832..10ae8ac40d 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -250,7 +250,7 @@ CONFIG_SCHEMA = cv.All( } ), validate_config, - cv.only_on(["esp32", "esp8266"]), + cv.only_on(["esp32", "esp8266", "bk72xx"]), ) @@ -271,10 +271,10 @@ def exp_mqtt_message(config): async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - # Add required libraries for ESP8266 - if CORE.is_esp8266: + # Add required libraries for ESP8266 and LibreTiny + if CORE.is_esp8266 or CORE.is_libretiny: # https://github.com/heman/async-mqtt-client/blob/master/library.json - cg.add_library("heman/AsyncMqttClient-esphome", "1.0.0") + cg.add_library("heman/AsyncMqttClient-esphome", "2.0.0") cg.add_define("USE_MQTT") cg.add_global(mqtt_ns.using) diff --git a/esphome/components/mqtt/mqtt_backend_libretiny.h b/esphome/components/mqtt/mqtt_backend_libretiny.h new file mode 100644 index 0000000000..5373a1926a --- /dev/null +++ b/esphome/components/mqtt/mqtt_backend_libretiny.h @@ -0,0 +1,74 @@ +#pragma once + +#ifdef USE_LIBRETINY + +#include "mqtt_backend.h" +#include + +namespace esphome { +namespace mqtt { + +class MQTTBackendLibreTiny final : public MQTTBackend { + public: + void set_keep_alive(uint16_t keep_alive) final { mqtt_client_.setKeepAlive(keep_alive); } + void set_client_id(const char *client_id) final { mqtt_client_.setClientId(client_id); } + void set_clean_session(bool clean_session) final { mqtt_client_.setCleanSession(clean_session); } + void set_credentials(const char *username, const char *password) final { + mqtt_client_.setCredentials(username, password); + } + void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final { + mqtt_client_.setWill(topic, qos, retain, payload); + } + void set_server(network::IPAddress ip, uint16_t port) final { + mqtt_client_.setServer(IPAddress(static_cast(ip)), port); + } + void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); } +#if ASYNC_TCP_SSL_ENABLED + void set_secure(bool secure) { mqtt_client.setSecure(secure); } + void add_server_fingerprint(const uint8_t *fingerprint) { mqtt_client.addServerFingerprint(fingerprint); } +#endif + + void set_on_connect(std::function &&callback) final { + this->mqtt_client_.onConnect(std::move(callback)); + } + void set_on_disconnect(std::function &&callback) final { + auto async_callback = [callback](AsyncMqttClientDisconnectReason reason) { + // int based enum so casting isn't a problem + callback(static_cast(reason)); + }; + this->mqtt_client_.onDisconnect(std::move(async_callback)); + } + void set_on_subscribe(std::function &&callback) final { + this->mqtt_client_.onSubscribe(std::move(callback)); + } + void set_on_unsubscribe(std::function &&callback) final { + this->mqtt_client_.onUnsubscribe(std::move(callback)); + } + void set_on_message(std::function &&callback) final { + auto async_callback = [callback](const char *topic, const char *payload, + AsyncMqttClientMessageProperties async_properties, size_t len, size_t index, + size_t total) { callback(topic, payload, len, index, total); }; + mqtt_client_.onMessage(std::move(async_callback)); + } + void set_on_publish(std::function &&callback) final { + this->mqtt_client_.onPublish(std::move(callback)); + } + + bool connected() const final { return mqtt_client_.connected(); } + void connect() final { mqtt_client_.connect(); } + void disconnect() final { mqtt_client_.disconnect(true); } + bool subscribe(const char *topic, uint8_t qos) final { return mqtt_client_.subscribe(topic, qos) != 0; } + bool unsubscribe(const char *topic) final { return mqtt_client_.unsubscribe(topic) != 0; } + bool publish(const char *topic, const char *payload, size_t length, uint8_t qos, bool retain) final { + return mqtt_client_.publish(topic, qos, retain, payload, length, false, 0) != 0; + } + using MQTTBackend::publish; + + protected: + AsyncMqttClient mqtt_client_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif // defined(USE_LIBRETINY) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 0c6da42328..fd5e13ecc7 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -106,6 +106,9 @@ void MQTTClientComponent::send_device_info_() { #ifdef USE_ESP32 root["platform"] = "ESP32"; #endif +#ifdef USE_LIBRETINY + root["platform"] = lt_cpu_get_model_name(); +#endif root["board"] = ESPHOME_BOARD; #if defined(USE_WIFI) @@ -156,7 +159,7 @@ void MQTTClientComponent::start_dnslookup_() { this->dns_resolve_error_ = false; this->dns_resolved_ = false; ip_addr_t addr; -#ifdef USE_ESP32 +#if defined(USE_ESP32) || defined(USE_LIBRETINY) err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr, MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV4); #endif diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 00eb3fdd40..bcb44ab4c2 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -13,6 +13,8 @@ #include "mqtt_backend_esp32.h" #elif defined(USE_ESP8266) #include "mqtt_backend_esp8266.h" +#elif defined(USE_LIBRETINY) +#include "mqtt_backend_libretiny.h" #endif #include "lwip/ip_addr.h" @@ -300,6 +302,8 @@ class MQTTClientComponent : public Component { MQTTBackendESP32 mqtt_backend_; #elif defined(USE_ESP8266) MQTTBackendESP8266 mqtt_backend_; +#elif defined(USE_LIBRETINY) + MQTTBackendLibreTiny mqtt_backend_; #endif MQTTClientState state_{MQTT_CLIENT_DISCONNECTED}; From 7dabbb65d081dbea8c266d7fbc9ac8bfb42dc461 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Tue, 26 Sep 2023 20:25:00 -0300 Subject: [PATCH 0527/2607] Wireguard keepalive remove uint16 type (#5430) --- esphome/components/wireguard/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 717fe50d2c..acb5f690ec 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_REBOOT_TIMEOUT, ) from esphome.components import time +from esphome.core import TimePeriod CONF_NETMASK = "netmask" CONF_PRIVATE_KEY = "private_key" @@ -59,9 +60,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_PEER_ALLOWED_IPS, default=["0.0.0.0/0"]): cv.ensure_list( _cidr_network ), - cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default=0): cv.Any( + cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default="0s"): cv.All( cv.positive_time_period_seconds, - cv.uint16_t, + cv.Range(max=TimePeriod(seconds=65535)), ), cv.Optional( CONF_REBOOT_TIMEOUT, default="15min" From 69adebfefa13e5f50512a114fed10b54b0ce20b6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 27 Sep 2023 09:25:14 +1000 Subject: [PATCH 0528/2607] Fix #4896 and #4903 (#5433) --- CODEOWNERS | 2 +- esphome/components/ili9xxx/display.py | 9 +++---- .../components/ili9xxx/ili9xxx_display.cpp | 12 ++++++++++ esphome/components/ili9xxx/ili9xxx_display.h | 6 +++++ esphome/components/ili9xxx/ili9xxx_init.h | 24 +++++++++++++++++++ tests/test1.yaml | 1 + 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 22e46aa2f0..3920a9100e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -131,7 +131,7 @@ esphome/components/i2s_audio/* @jesserockz esphome/components/i2s_audio/media_player/* @jesserockz esphome/components/i2s_audio/microphone/* @jesserockz esphome/components/i2s_audio/speaker/* @jesserockz -esphome/components/ili9xxx/* @nielsnl68 +esphome/components/ili9xxx/* @clydebarrow @nielsnl68 esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core esphome/components/ina260/* @mreditor97 diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 0435460b6a..89a6b2d1b9 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -25,7 +25,7 @@ def AUTO_LOAD(): return [] -CODEOWNERS = ["@nielsnl68"] +CODEOWNERS = ["@nielsnl68", "@clydebarrow"] ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx") ili9XXXSPI = ili9XXX_ns.class_( @@ -42,6 +42,7 @@ MODELS = { "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI), + "ILI9481-18": ili9XXX_ns.class_("ILI9XXXILI948118", ili9XXXSPI), "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), "ILI9488_A": ili9XXX_ns.class_("ILI9XXXILI9488A", ili9XXXSPI), @@ -140,8 +141,6 @@ async def to_code(config): rhs = [] for x in range(256): rhs.extend([HexInt(x), HexInt(x), HexInt(x)]) - prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) - cg.add(var.set_palette(prog_arr)) elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE": cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED)) from PIL import Image @@ -178,6 +177,4 @@ async def to_code(config): if rhs is not None: prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) - - spi_data_rate = str(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]]) - cg.add_define("ILI9XXXDisplay_DATA_RATE", cg.RawExpression(spi_data_rate)) + cg.add(var.set_data_rate(config[CONF_DATA_RATE])) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 750f629db2..abe01ea8c3 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -59,6 +59,7 @@ void ILI9XXXDisplay::dump_config() { if (this->is_18bitdisplay_) { ESP_LOGCONFIG(TAG, " 18-Bit Mode: YES"); } + ESP_LOGCONFIG(TAG, " Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_); @@ -387,6 +388,17 @@ void ILI9XXXILI9481::initialize() { } } +void ILI9XXXILI948118::initialize() { + this->init_lcd_(INITCMD_ILI9481_18); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 480; + } + this->is_18bitdisplay_ = true; +} + // 35_TFT display void ILI9XXXILI9486::initialize() { this->init_lcd_(INITCMD_ILI9486); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 15b08e6c76..4e8355b9a5 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -120,6 +120,12 @@ class ILI9XXXILI9481 : public ILI9XXXDisplay { void initialize() override; }; +//----------- ILI9481 in 18 bit mode -------------- +class ILI9XXXILI948118 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + //----------- ILI9XXX_35_TFT rotated display -------------- class ILI9XXXILI9486 : public ILI9XXXDisplay { protected: diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 1856fb06ab..031dc25f91 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -94,12 +94,36 @@ static const uint8_t PROGMEM INITCMD_ILI9481[] = { ILI9XXX_IFCTR , 1, 0x83, ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00, ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect + ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF, 0xE4 , 1, 0xA0, + ILI9XXX_MADCTL , 1, MADCTL_MV | MADCTL_BGR, // Memory Access Control ILI9XXX_CSCON , 1, 0x01, + ILI9XXX_PIXFMT, 1, 0x55, // 16 bit mode + ILI9XXX_INVON, 0, ILI9XXX_DISPON, 0x80, // Set display on 0x00 // end }; +static const uint8_t PROGMEM INITCMD_ILI9481_18[] = { + ILI9XXX_SLPOUT , 0x80, // Exit sleep mode + ILI9XXX_PWSET , 3, 0x07, 0x41, 0x1D, + ILI9XXX_VMCTR , 3, 0x00, 0x1C, 0x1F, + ILI9XXX_PWSETN , 2, 0x01, 0x11, + ILI9XXX_PWCTR1 , 5, 0x10, 0x3B, 0x00, 0x02, 0x11, + ILI9XXX_VMCTR1 , 1, 0x03, + ILI9XXX_IFCTR , 1, 0x83, + ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00, + ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect + ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF, + 0xE4 , 1, 0xA0, + ILI9XXX_MADCTL , 1, MADCTL_MX| MADCTL_BGR, // Memory Access Control + ILI9XXX_CSCON , 1, 0x01, + ILI9XXX_PIXFMT, 1, 0x66, // 18 bit mode + ILI9XXX_INVON, 0, + ILI9XXX_DISPON, 0x80, // Set display on + 0x00 // end +}; + static const uint8_t PROGMEM INITCMD_ILI9486[] = { ILI9XXX_SLPOUT, 0x80, ILI9XXX_PIXFMT, 1, 0x55, diff --git a/tests/test1.yaml b/tests/test1.yaml index fe983cf421..350057e3cc 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2972,6 +2972,7 @@ display: model: TFT 2.4 cs_pin: GPIO5 dc_pin: GPIO4 + color_palette: GRAYSCALE reset_pin: GPIO22 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); From e5bae8187f0886360a0807eaec6a83acf591a5db Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:28:12 +1300 Subject: [PATCH 0529/2607] Bump version to 2023.9.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f5319adfa7..c5cc7010a9 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0b3" +__version__ = "2023.9.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From cc1b7a7a569e89c509d7810b87b56690cc23ee36 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:21:35 +1300 Subject: [PATCH 0530/2607] Bump version to 2023.9.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c5cc7010a9..bf703d9595 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0b4" +__version__ = "2023.9.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 9d4f471855fcf3cab19368d0558f17a25629f0dc Mon Sep 17 00:00:00 2001 From: Marc J Date: Wed, 27 Sep 2023 00:45:21 -0700 Subject: [PATCH 0531/2607] Tuya Number Scaling by step value (#5108) --- esphome/components/tuya/number/tuya_number.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index 5c7cafbf7a..30ef8b8f72 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -10,7 +10,7 @@ void TuyaNumber::setup() { this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { if (datapoint.type == TuyaDatapointType::INTEGER) { ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); - this->publish_state(datapoint.value_int); + this->publish_state(datapoint.value_int * this->traits.get_step()); } else if (datapoint.type == TuyaDatapointType::ENUM) { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); @@ -22,7 +22,8 @@ void TuyaNumber::setup() { void TuyaNumber::control(float value) { ESP_LOGV(TAG, "Setting number %u: %f", this->number_id_, value); if (this->type_ == TuyaDatapointType::INTEGER) { - this->parent_->set_integer_datapoint_value(this->number_id_, value); + int integer_value = lround(value / this->traits.get_step()); + this->parent_->set_integer_datapoint_value(this->number_id_, integer_value); } else if (this->type_ == TuyaDatapointType::ENUM) { this->parent_->set_enum_datapoint_value(this->number_id_, value); } From 57b7dd0fa24d749420747729be854eb381a3238e Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 27 Sep 2023 10:38:43 +0200 Subject: [PATCH 0532/2607] Refactor ip address representation (#5252) --- .../captive_portal/captive_portal.cpp | 2 +- esphome/components/e131/e131_packet.cpp | 7 +- .../ethernet/ethernet_component.cpp | 41 +++---- esphome/components/mdns/mdns_rp2040.cpp | 3 +- .../components/mqtt/mqtt_backend_esp8266.h | 4 +- esphome/components/mqtt/mqtt_client.cpp | 12 +- esphome/components/network/ip_address.h | 110 ++++++++++++++---- .../components/wake_on_lan/wake_on_lan.cpp | 5 +- .../wifi/wifi_component_esp32_arduino.cpp | 55 ++++----- .../wifi/wifi_component_esp8266.cpp | 46 ++++---- .../wifi/wifi_component_esp_idf.cpp | 53 ++++----- .../wifi/wifi_component_libretiny.cpp | 7 +- .../components/wifi/wifi_component_pico_w.cpp | 22 ++-- tests/test1.yaml | 3 + tests/test10.yaml | 3 + tests/test11.5.yaml | 3 + tests/test2.yaml | 3 + tests/test3.1.yaml | 3 + tests/test3.yaml | 3 + tests/test4.yaml | 3 + tests/test5.yaml | 3 + tests/test6.yaml | 3 + tests/test7.yaml | 3 + tests/test8.yaml | 3 + 24 files changed, 225 insertions(+), 175 deletions(-) diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 74c6606fc0..cc78528e46 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -48,7 +48,7 @@ void CaptivePortal::start() { this->dns_server_ = make_unique(); this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError); network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip(); - this->dns_server_->start(53, "*", (uint32_t) ip); + this->dns_server_->start(53, "*", IPAddress(ip)); #endif this->base_->get_server()->onNotFound([this](AsyncWebServerRequest *req) { diff --git a/esphome/components/e131/e131_packet.cpp b/esphome/components/e131/e131_packet.cpp index ac8b72f6e7..e1ae41cbaf 100644 --- a/esphome/components/e131/e131_packet.cpp +++ b/esphome/components/e131/e131_packet.cpp @@ -67,8 +67,8 @@ bool E131Component::join_igmp_groups_() { if (!universe.second) continue; - ip4_addr_t multicast_addr = {static_cast( - network::IPAddress(239, 255, ((universe.first >> 8) & 0xff), ((universe.first >> 0) & 0xff)))}; + ip4_addr_t multicast_addr = + network::IPAddress(239, 255, ((universe.first >> 8) & 0xff), ((universe.first >> 0) & 0xff)); auto err = igmp_joingroup(IP4_ADDR_ANY4, &multicast_addr); @@ -101,8 +101,7 @@ void E131Component::leave_(int universe) { } if (listen_method_ == E131_MULTICAST) { - ip4_addr_t multicast_addr = { - static_cast(network::IPAddress(239, 255, ((universe >> 8) & 0xff), ((universe >> 0) & 0xff)))}; + ip4_addr_t multicast_addr = network::IPAddress(239, 255, ((universe >> 8) & 0xff), ((universe >> 0) & 0xff)); igmp_leavegroup(IP4_ADDR_ANY4, &multicast_addr); } diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 59d2e4c4d6..03fdc49338 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -236,7 +236,7 @@ bool EthernetComponent::can_proceed() { return this->is_connected(); } network::IPAddress EthernetComponent::get_ip_address() { esp_netif_ip_info_t ip; esp_netif_get_ip_info(this->eth_netif_, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) { @@ -293,9 +293,9 @@ void EthernetComponent::start_connect_() { esp_netif_ip_info_t info; if (this->manual_ip_.has_value()) { - info.ip.addr = static_cast(this->manual_ip_->static_ip); - info.gw.addr = static_cast(this->manual_ip_->gateway); - info.netmask.addr = static_cast(this->manual_ip_->subnet); + info.ip = this->manual_ip_->static_ip; + info.gw = this->manual_ip_->gateway; + info.netmask = this->manual_ip_->subnet; } else { info.ip.addr = 0; info.gw.addr = 0; @@ -318,24 +318,14 @@ void EthernetComponent::start_connect_() { ESPHL_ERROR_CHECK(err, "DHCPC set IP info error"); if (this->manual_ip_.has_value()) { - if (uint32_t(this->manual_ip_->dns1) != 0) { + if (this->manual_ip_->dns1.is_set()) { ip_addr_t d; -#if LWIP_IPV6 - d.type = IPADDR_TYPE_V4; - d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns1); -#else - d.addr = static_cast(this->manual_ip_->dns1); -#endif + d = this->manual_ip_->dns1; dns_setserver(0, &d); } - if (uint32_t(this->manual_ip_->dns2) != 0) { + if (this->manual_ip_->dns2.is_set()) { ip_addr_t d; -#if LWIP_IPV6 - d.type = IPADDR_TYPE_V4; - d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns2); -#else - d.addr = static_cast(this->manual_ip_->dns2); -#endif + d = this->manual_ip_->dns2; dns_setserver(1, &d); } } else { @@ -360,21 +350,16 @@ bool EthernetComponent::is_connected() { return this->state_ == EthernetComponen void EthernetComponent::dump_connect_params_() { esp_netif_ip_info_t ip; esp_netif_get_ip_info(this->eth_netif_, &ip); - ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(ip.ip.addr).str().c_str()); + ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(&ip.ip).str().c_str()); ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str()); - ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(ip.netmask.addr).str().c_str()); - ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(ip.gw.addr).str().c_str()); + ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(&ip.netmask).str().c_str()); + ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(&ip.gw).str().c_str()); const ip_addr_t *dns_ip1 = dns_getserver(0); const ip_addr_t *dns_ip2 = dns_getserver(1); -#if LWIP_IPV6 - ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str()); - ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str()); -#else - ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->addr).str().c_str()); - ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); -#endif + ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1).str().c_str()); + ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2).str().c_str()); #if ENABLE_IPV6 if (this->ipv6_count_ > 0) { diff --git a/esphome/components/mdns/mdns_rp2040.cpp b/esphome/components/mdns/mdns_rp2040.cpp index b30a3a4ee7..56afd6f5e1 100644 --- a/esphome/components/mdns/mdns_rp2040.cpp +++ b/esphome/components/mdns/mdns_rp2040.cpp @@ -13,8 +13,7 @@ namespace mdns { void MDNSComponent::setup() { this->compile_records_(); - network::IPAddress addr = network::get_ip_address(); - MDNS.begin(this->hostname_.c_str(), (uint32_t) addr); + MDNS.begin(this->hostname_.c_str()); for (const auto &service : this->services_) { // Strip the leading underscore from the proto and service_type. While it is diff --git a/esphome/components/mqtt/mqtt_backend_esp8266.h b/esphome/components/mqtt/mqtt_backend_esp8266.h index 2d91877e9d..981d27693f 100644 --- a/esphome/components/mqtt/mqtt_backend_esp8266.h +++ b/esphome/components/mqtt/mqtt_backend_esp8266.h @@ -19,9 +19,7 @@ class MQTTBackendESP8266 final : public MQTTBackend { void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final { mqtt_client_.setWill(topic, qos, retain, payload); } - void set_server(network::IPAddress ip, uint16_t port) final { - mqtt_client_.setServer(IPAddress(static_cast(ip)), port); - } + void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(IPAddress(ip), port); } void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); } #if ASYNC_TCP_SSL_ENABLED void set_secure(bool secure) { mqtt_client.setSecure(secure); } diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index fd5e13ecc7..6f63935e6e 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -171,11 +171,7 @@ void MQTTClientComponent::start_dnslookup_() { case ERR_OK: { // Got IP immediately this->dns_resolved_ = true; -#if LWIP_IPV6 - this->ip_ = addr.u_addr.ip4.addr; -#else - this->ip_ = addr.addr; -#endif + this->ip_ = network::IPAddress(&addr); this->start_connect_(); return; } @@ -226,11 +222,7 @@ void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t * if (ipaddr == nullptr) { a_this->dns_resolve_error_ = true; } else { -#if LWIP_IPV6 - a_this->ip_ = ipaddr->u_addr.ip4.addr; -#else - a_this->ip_ = ipaddr->addr; -#endif + a_this->ip_ = network::IPAddress(ipaddr); a_this->dns_resolved_ = true; } } diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index af198179ba..8b05237c05 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -3,42 +3,104 @@ #include #include #include +#include + +#if USE_ARDUINO +#include +#include +#endif /* USE_ADRDUINO */ + +#if USE_ESP32_FRAMEWORK_ARDUINO +#define arduino_ns Arduino_h +#elif USE_LIBRETINY +#define arduino_ns arduino +#elif USE_ARDUINO +#define arduino_ns +#endif + +#ifdef USE_ESP32 +#include +#include +#endif namespace esphome { namespace network { struct IPAddress { public: - IPAddress() : addr_({0, 0, 0, 0}) {} - IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) : addr_({first, second, third, fourth}) {} - IPAddress(uint32_t raw) { - addr_[0] = (uint8_t) (raw >> 0); - addr_[1] = (uint8_t) (raw >> 8); - addr_[2] = (uint8_t) (raw >> 16); - addr_[3] = (uint8_t) (raw >> 24); + IPAddress() { ip_addr_set_zero(&ip_addr_); } + IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) { + IP_ADDR4(&ip_addr_, first, second, third, fourth); } - operator uint32_t() const { - uint32_t res = 0; - res |= ((uint32_t) addr_[0]) << 0; - res |= ((uint32_t) addr_[1]) << 8; - res |= ((uint32_t) addr_[2]) << 16; - res |= ((uint32_t) addr_[3]) << 24; - return res; + IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); } + IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); } + IPAddress(ip4_addr_t *other_ip) { memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); } +#if USE_ARDUINO + IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); } +#endif +#if LWIP_IPV6 + IPAddress(ip6_addr_t *other_ip) { + memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip6_addr_t)); + ip_addr_.type = IPADDR_TYPE_V6; } - std::string str() const { - char buffer[24]; - snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", addr_[0], addr_[1], addr_[2], addr_[3]); - return buffer; +#endif /* LWIP_IPV6 */ + +#ifdef USE_ESP32 +#if LWIP_IPV6 + IPAddress(esp_ip6_addr_t *other_ip) { + memcpy((void *) &ip_addr_.u_addr.ip6, (void *) other_ip, sizeof(esp_ip6_addr_t)); + ip_addr_.type = IPADDR_TYPE_V6; } - bool operator==(const IPAddress &other) const { - return addr_[0] == other.addr_[0] && addr_[1] == other.addr_[1] && addr_[2] == other.addr_[2] && - addr_[3] == other.addr_[3]; +#endif /* LWIP_IPV6 */ + IPAddress(esp_ip4_addr_t *other_ip) { memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(esp_ip4_addr_t)); } + operator esp_ip_addr_t() const { + esp_ip_addr_t tmp; +#if LWIP_IPV6 + memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_)); +#else + memcpy((void *) &tmp.u_addr.ip4, (void *) &ip_addr_, sizeof(ip_addr_)); +#endif /* LWIP_IPV6 */ + return tmp; + } + operator esp_ip4_addr_t() const { + esp_ip4_addr_t tmp; +#if LWIP_IPV6 + memcpy((void *) &tmp, (void *) &ip_addr_.u_addr.ip4, sizeof(esp_ip4_addr_t)); +#else + memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_)); +#endif /* LWIP_IPV6 */ + return tmp; + } +#endif /* USE_ESP32 */ + + operator ip_addr_t() const { return ip_addr_; } +#if LWIP_IPV6 + operator ip4_addr_t() const { return *ip_2_ip4(&ip_addr_); } +#endif /* LWIP_IPV6 */ + +#if USE_ARDUINO + operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); } +#endif + + bool is_set() { return !ip_addr_isany(&ip_addr_); } + bool is_ip4() { return IP_IS_V4(&ip_addr_); } + bool is_ip6() { return IP_IS_V6(&ip_addr_); } + std::string str() const { return ipaddr_ntoa(&ip_addr_); } + bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); } + bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); } + IPAddress &operator+=(uint8_t increase) { + if (IP_IS_V4(&ip_addr_)) { +#if LWIP_IPV6 + (((u8_t *) (&ip_addr_.u_addr.ip4))[3]) += increase; +#else + (((u8_t *) (&ip_addr_.addr))[3]) += increase; +#endif /* LWIP_IPV6 */ + } + return *this; } - uint8_t operator[](int index) const { return addr_[index]; } - uint8_t &operator[](int index) { return addr_[index]; } protected: - std::array addr_; + ip_addr_t ip_addr_; }; } // namespace network diff --git a/esphome/components/wake_on_lan/wake_on_lan.cpp b/esphome/components/wake_on_lan/wake_on_lan.cpp index 893aa75895..a4dd0f3b6f 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.cpp +++ b/esphome/components/wake_on_lan/wake_on_lan.cpp @@ -30,11 +30,10 @@ void WakeOnLanButton::press_action() { ESP_LOGI(TAG, "Sending Wake-on-LAN Packet..."); bool begin_status = false; bool end_status = false; - uint32_t interface = esphome::network::get_ip_address(); - IPAddress interface_ip = IPAddress(interface); IPAddress broadcast = IPAddress(255, 255, 255, 255); #ifdef USE_ESP8266 - begin_status = this->udp_client_.beginPacketMulticast(broadcast, 9, interface_ip, 128); + begin_status = this->udp_client_.beginPacketMulticast(broadcast, 9, + IPAddress((ip_addr_t) esphome::network::get_ip_address()), 128); #endif #ifdef USE_ESP32 begin_status = this->udp_client_.beginPacket(broadcast, 9); diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 5b147b20c6..17b15757ef 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -113,9 +113,9 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { tcpip_adapter_ip_info_t info; memset(&info, 0, sizeof(info)); - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; esp_err_t dhcp_stop_ret = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); if (dhcp_stop_ret != ESP_OK && dhcp_stop_ret != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) { @@ -128,23 +128,16 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; +// TODO: is this needed? #if LWIP_IPV6 dns.type = IPADDR_TYPE_V4; #endif - if (uint32_t(manual_ip->dns1) != 0) { -#if LWIP_IPV6 - dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); -#else - dns.addr = static_cast(manual_ip->dns1); -#endif + if (manual_ip->dns1.is_set()) { + dns = manual_ip->dns1; dns_setserver(0, &dns); } - if (uint32_t(manual_ip->dns2) != 0) { -#if LWIP_IPV6 - dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); -#else - dns.addr = static_cast(manual_ip->dns2); -#endif + if (manual_ip->dns2.is_set()) { + dns = manual_ip->dns2; dns_setserver(1, &dns); } @@ -156,7 +149,7 @@ network::IPAddress WiFiComponent::wifi_sta_ip() { return {}; tcpip_adapter_ip_info_t ip; tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bool WiFiComponent::wifi_apply_hostname_() { @@ -614,13 +607,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { tcpip_adapter_ip_info_t info; memset(&info, 0, sizeof(info)); if (manual_ip.has_value()) { - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; } else { - info.ip.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.gw.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.netmask.addr = static_cast(network::IPAddress(255, 255, 255, 0)); + info.ip = network::IPAddress(192, 168, 4, 1); + info.gw = network::IPAddress(192, 168, 4, 1); + info.netmask = network::IPAddress(255, 255, 255, 0); } tcpip_adapter_dhcp_status_t dhcp_status; tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); @@ -638,12 +631,12 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { dhcps_lease_t lease; lease.enable = true; - network::IPAddress start_address = info.ip.addr; - start_address[3] += 99; - lease.start_ip.addr = static_cast(start_address); + network::IPAddress start_address = network::IPAddress(&info.ip); + start_address += 99; + lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address[3] += 100; - lease.end_ip.addr = static_cast(start_address); + start_address += 100; + lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = tcpip_adapter_dhcps_option(TCPIP_ADAPTER_OP_SET, TCPIP_ADAPTER_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); @@ -702,7 +695,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { network::IPAddress WiFiComponent::wifi_soft_ap_ip() { tcpip_adapter_ip_info_t ip; tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bool WiFiComponent::wifi_disconnect_() { return esp_wifi_disconnect(); } @@ -718,9 +711,9 @@ bssid_t WiFiComponent::wifi_bssid() { std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } -network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } -network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } -network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; } +network::IPAddress WiFiComponent::wifi_subnet_mask_() { return network::IPAddress(WiFi.subnetMask()); } +network::IPAddress WiFiComponent::wifi_gateway_ip_() { return network::IPAddress(WiFi.gatewayIP()); } +network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddress(WiFi.dnsIP(num)); } void WiFiComponent::wifi_loop_() {} } // namespace wifi diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 6e7c491967..a48c6c711d 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -147,9 +147,9 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { #endif struct ip_info info {}; - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; if (dhcp_status == DHCP_STARTED) { bool dhcp_stop_ret = wifi_station_dhcpc_stop(); @@ -165,12 +165,12 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; - if (uint32_t(manual_ip->dns1) != 0) { - ip_addr_set_ip4_u32_val(dns, static_cast(manual_ip->dns1)); + if (manual_ip->dns1.is_set()) { + dns = manual_ip->dns1; dns_setserver(0, &dns); } - if (uint32_t(manual_ip->dns2) != 0) { - ip_addr_set_ip4_u32_val(dns, static_cast(manual_ip->dns2)); + if (manual_ip->dns2.is_set()) { + dns = manual_ip->dns2; dns_setserver(1, &dns); } @@ -190,7 +190,7 @@ network::IPAddress WiFiComponent::wifi_sta_ip() { return {}; struct ip_info ip {}; wifi_get_ip_info(STATION_IF, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bool WiFiComponent::wifi_apply_hostname_() { const std::string &hostname = App.get_name(); @@ -695,13 +695,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { struct ip_info info {}; if (manual_ip.has_value()) { - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; } else { - info.ip.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.gw.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.netmask.addr = static_cast(network::IPAddress(255, 255, 255, 0)); + info.ip = network::IPAddress(192, 168, 4, 1); + info.gw = network::IPAddress(192, 168, 4, 1); + info.netmask = network::IPAddress(255, 255, 255, 0); } if (wifi_softap_dhcps_status() == DHCP_STARTED) { @@ -721,12 +721,12 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { struct dhcps_lease lease {}; lease.enable = true; - network::IPAddress start_address = info.ip.addr; - start_address[3] += 99; - lease.start_ip.addr = static_cast(start_address); + network::IPAddress start_address = network::IPAddress(&info.ip); + start_address += 99; + lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address[3] += 100; - lease.end_ip.addr = static_cast(start_address); + start_address += 100; + lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); if (!wifi_softap_set_dhcps_lease(&lease)) { ESP_LOGV(TAG, "Setting SoftAP DHCP lease failed!"); @@ -793,7 +793,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { network::IPAddress WiFiComponent::wifi_soft_ap_ip() { struct ip_info ip {}; wifi_get_ip_info(SOFTAP_IF, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bssid_t WiFiComponent::wifi_bssid() { bssid_t bssid{}; @@ -807,9 +807,9 @@ bssid_t WiFiComponent::wifi_bssid() { std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } -network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } -network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } -network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; } +network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; } +network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; } +network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {(const ip_addr_t *) WiFi.dnsIP(num)}; } void WiFiComponent::wifi_loop_() {} } // namespace wifi diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 0ff9e932b2..34ecaf887d 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -437,9 +437,9 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } esp_netif_ip_info_t info; // struct of ip4_addr_t with ip, netmask, gw - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; err = esp_netif_dhcpc_stop(s_sta_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); @@ -452,12 +452,12 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } esp_netif_dns_info_t dns; - if (uint32_t(manual_ip->dns1) != 0) { - dns.ip.u_addr.ip4.addr = static_cast(manual_ip->dns1); + if (manual_ip->dns1.is_set()) { + dns.ip = manual_ip->dns1; esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_MAIN, &dns); } - if (uint32_t(manual_ip->dns2) != 0) { - dns.ip.u_addr.ip4.addr = static_cast(manual_ip->dns2); + if (manual_ip->dns2.is_set()) { + dns.ip = manual_ip->dns2; esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_BACKUP, &dns); } @@ -471,9 +471,10 @@ network::IPAddress WiFiComponent::wifi_sta_ip() { esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); - return false; + // TODO: do something smarter + // return false; } - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bool WiFiComponent::wifi_apply_hostname_() { @@ -769,13 +770,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { esp_netif_ip_info_t info; if (manual_ip.has_value()) { - info.ip.addr = static_cast(manual_ip->static_ip); - info.gw.addr = static_cast(manual_ip->gateway); - info.netmask.addr = static_cast(manual_ip->subnet); + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; } else { - info.ip.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.gw.addr = static_cast(network::IPAddress(192, 168, 4, 1)); - info.netmask.addr = static_cast(network::IPAddress(255, 255, 255, 0)); + info.ip = network::IPAddress(192, 168, 4, 1); + info.gw = network::IPAddress(192, 168, 4, 1); + info.netmask = network::IPAddress(255, 255, 255, 0); } err = esp_netif_dhcpc_stop(s_sta_netif); @@ -792,12 +793,12 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { dhcps_lease_t lease; lease.enable = true; - network::IPAddress start_address = info.ip.addr; - start_address[3] += 99; - lease.start_ip.addr = static_cast(start_address); + network::IPAddress start_address = network::IPAddress(&info.ip); + start_address += 99; + lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address[3] += 100; - lease.end_ip.addr = static_cast(start_address); + start_address += 100; + lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = esp_netif_dhcps_option(s_sta_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); @@ -855,7 +856,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { network::IPAddress WiFiComponent::wifi_soft_ap_ip() { esp_netif_ip_info_t ip; esp_netif_get_ip_info(s_sta_netif, &ip); - return {ip.ip.addr}; + return network::IPAddress(&ip.ip); } bool WiFiComponent::wifi_disconnect_() { return esp_wifi_disconnect(); } @@ -907,7 +908,7 @@ network::IPAddress WiFiComponent::wifi_subnet_mask_() { ESP_LOGW(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); return {}; } - return {ip.netmask.addr}; + return network::IPAddress(&ip.netmask); } network::IPAddress WiFiComponent::wifi_gateway_ip_() { esp_netif_ip_info_t ip; @@ -916,15 +917,11 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { ESP_LOGW(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); return {}; } - return {ip.gw.addr}; + return network::IPAddress(&ip.gw); } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { const ip_addr_t *dns_ip = dns_getserver(num); -#if LWIP_IPV6 - return {dns_ip->u_addr.ip4.addr}; -#else - return {dns_ip->addr}; -#endif + return network::IPAddress(dns_ip); } } // namespace wifi diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index abad5aca9c..d7f4406540 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -76,9 +76,7 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { return true; } - WiFi.config(static_cast(manual_ip->static_ip), static_cast(manual_ip->gateway), - static_cast(manual_ip->subnet), static_cast(manual_ip->dns1), - static_cast(manual_ip->dns2)); + WiFi.config(manual_ip->static_ip, manual_ip->gateway, manual_ip->subnet, manual_ip->dns1, manual_ip->dns2); return true; } @@ -420,8 +418,7 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { return false; if (manual_ip.has_value()) { - return WiFi.softAPConfig(static_cast(manual_ip->static_ip), static_cast(manual_ip->gateway), - static_cast(manual_ip->subnet)); + return WiFi.softAPConfig(manual_ip->static_ip, manual_ip->gateway, manual_ip->subnet); } else { return WiFi.softAPConfig(IPAddress(192, 168, 4, 1), IPAddress(192, 168, 4, 1), IPAddress(255, 255, 255, 0)); } diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 149ca61cd5..d67b466d6c 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -70,11 +70,11 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { return true; } - IPAddress ip_address = IPAddress(manual_ip->static_ip); - IPAddress gateway = IPAddress(manual_ip->gateway); - IPAddress subnet = IPAddress(manual_ip->subnet); + IPAddress ip_address = manual_ip->static_ip; + IPAddress gateway = manual_ip->gateway; + IPAddress subnet = manual_ip->subnet; - IPAddress dns = IPAddress(manual_ip->dns1); + IPAddress dns = manual_ip->dns1; WiFi.config(ip_address, dns, gateway, subnet); return true; @@ -151,7 +151,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return true; } -network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {WiFi.localIP()}; } +network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.localIP()}; } bool WiFiComponent::wifi_disconnect_() { int err = cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA); @@ -170,16 +170,12 @@ std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } -network::IPAddress WiFiComponent::wifi_sta_ip() { return {WiFi.localIP()}; } -network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } -network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } +network::IPAddress WiFiComponent::wifi_sta_ip() { return {(const ip_addr_t *) WiFi.localIP()}; } +network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; } +network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { const ip_addr_t *dns_ip = dns_getserver(num); -#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_IPV6 - return {dns_ip->u_addr.ip4.addr}; -#else - return {dns_ip->addr}; -#endif + return network::IPAddress(dns_ip); } void WiFiComponent::wifi_loop_() { diff --git a/tests/test1.yaml b/tests/test1.yaml index 350057e3cc..96dda707b6 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -82,6 +82,9 @@ wifi: reboot_timeout: 120s power_save_mode: light +network: + enable_ipv6: true + mdns: disabled: false diff --git a/tests/test10.yaml b/tests/test10.yaml index 0470e37e6c..fc74d95d84 100644 --- a/tests/test10.yaml +++ b/tests/test10.yaml @@ -14,6 +14,9 @@ wifi: reboot_timeout: 3min power_save_mode: high +network: + enable_ipv6: true + logger: level: VERBOSE diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml index 544dc10930..06985611e7 100644 --- a/tests/test11.5.yaml +++ b/tests/test11.5.yaml @@ -25,6 +25,9 @@ wifi: gateway: 192.168.1.1 subnet: 255.255.255.0 +network: + enable_ipv6: true + api: ota: diff --git a/tests/test2.yaml b/tests/test2.yaml index c04e6726b1..5485711c2e 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -28,6 +28,9 @@ ethernet: subnet: 255.255.255.0 domain: .local +network: + enable_ipv6: true + mdns: disabled: true diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 16f31409d8..8884479f61 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -21,6 +21,9 @@ wifi: ssid: "MySSID" password: "password1" +network: + enable_ipv6: true + web_server: port: 80 version: 2 diff --git a/tests/test3.yaml b/tests/test3.yaml index 5d30e415fb..e7cf24a95a 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -215,6 +215,9 @@ wifi: ssid: "MySSID" password: "password1" +network: + enable_ipv6: true + uart: - id: uart_1 tx_pin: diff --git a/tests/test4.yaml b/tests/test4.yaml index 341e613785..1b809256e7 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -21,6 +21,9 @@ ethernet: subnet: 255.255.255.0 domain: .local +network: + enable_ipv6: true + api: i2c: diff --git a/tests/test5.yaml b/tests/test5.yaml index 5727d30e61..d87a7f50d4 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -22,6 +22,9 @@ wifi: gateway: 192.168.1.1 subnet: 255.255.255.0 +network: + enable_ipv6: true + api: ota: diff --git a/tests/test6.yaml b/tests/test6.yaml index 3d6a1ceb1f..7c72151860 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -16,6 +16,9 @@ wifi: - ssid: "MySSID" password: "password1" +network: + enable_ipv6: true + api: ota: diff --git a/tests/test7.yaml b/tests/test7.yaml index 2355dd6feb..b22fbfbcb4 100644 --- a/tests/test7.yaml +++ b/tests/test7.yaml @@ -3,6 +3,9 @@ wifi: ssid: 'ssid' +network: + enable_ipv6: true + esp32: board: lolin_c3_mini framework: diff --git a/tests/test8.yaml b/tests/test8.yaml index 01d12ea330..3ba8aa19ef 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -3,6 +3,9 @@ wifi: ssid: "ssid" +network: + enable_ipv6: true + esp32: board: esp32s3box variant: ESP32S3 From 4ac4492241deaecfdf1dd2597650a009659eb94d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:20:44 +1300 Subject: [PATCH 0533/2607] Fix .esphome path when not using envvar (#5440) --- esphome/core/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 4897b073fa..4c99aff011 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -558,7 +558,7 @@ class EsphomeCore: def data_dir(self): if is_ha_addon(): return os.path.join("/data") - if get_str_env("ESPHOME_DATA_DIR", None) is not None: + if "ESPHOME_DATA_DIR" in os.environ: return get_str_env("ESPHOME_DATA_DIR", None) return self.relative_config_path(".esphome") From 12365976c4dda765c22e0b51075196931da8e3ed Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:40:36 +1300 Subject: [PATCH 0534/2607] Migrate dashboard json files to /data folder instead of wiping out (#5441) --- docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run index 775c2fa0d6..edb98a8d9b 100755 --- a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run +++ b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run @@ -42,7 +42,12 @@ fi mkdir -p "${pio_cache_base}" if bashio::fs.directory_exists '/config/esphome/.esphome'; then - bashio::log.info "Removing old .esphome directory..." + bashio::log.info "Migrating old .esphome directory..." + if bashio::fs.file_exists '/config/esphome/.esphome/esphome.json'; then + mv /config/esphome/.esphome/esphome.json /data/esphome.json + fi + mkdir -p "/data/storage" + mv /config/esphome/.esphome/*.json /data/storage/ || true rm -rf /config/esphome/.esphome fi From dae8ab563c92288bc017be8567fe41f9f93ec159 Mon Sep 17 00:00:00 2001 From: Marc J Date: Wed, 27 Sep 2023 00:45:21 -0700 Subject: [PATCH 0535/2607] Tuya Number Scaling by step value (#5108) --- esphome/components/tuya/number/tuya_number.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index 5c7cafbf7a..30ef8b8f72 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -10,7 +10,7 @@ void TuyaNumber::setup() { this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { if (datapoint.type == TuyaDatapointType::INTEGER) { ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); - this->publish_state(datapoint.value_int); + this->publish_state(datapoint.value_int * this->traits.get_step()); } else if (datapoint.type == TuyaDatapointType::ENUM) { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); @@ -22,7 +22,8 @@ void TuyaNumber::setup() { void TuyaNumber::control(float value) { ESP_LOGV(TAG, "Setting number %u: %f", this->number_id_, value); if (this->type_ == TuyaDatapointType::INTEGER) { - this->parent_->set_integer_datapoint_value(this->number_id_, value); + int integer_value = lround(value / this->traits.get_step()); + this->parent_->set_integer_datapoint_value(this->number_id_, integer_value); } else if (this->type_ == TuyaDatapointType::ENUM) { this->parent_->set_enum_datapoint_value(this->number_id_, value); } From b5b654e0546f3fdfd835de3930b91f7e6760be69 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:40:36 +1300 Subject: [PATCH 0536/2607] Migrate dashboard json files to /data folder instead of wiping out (#5441) --- docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run index 775c2fa0d6..edb98a8d9b 100755 --- a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run +++ b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run @@ -42,7 +42,12 @@ fi mkdir -p "${pio_cache_base}" if bashio::fs.directory_exists '/config/esphome/.esphome'; then - bashio::log.info "Removing old .esphome directory..." + bashio::log.info "Migrating old .esphome directory..." + if bashio::fs.file_exists '/config/esphome/.esphome/esphome.json'; then + mv /config/esphome/.esphome/esphome.json /data/esphome.json + fi + mkdir -p "/data/storage" + mv /config/esphome/.esphome/*.json /data/storage/ || true rm -rf /config/esphome/.esphome fi From d262548d2e00bf7e9b3354430f1deca4ea79edf4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:52:35 +1300 Subject: [PATCH 0537/2607] Bump version to 2023.9.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index bf703d9595..65757da130 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.0" +__version__ = "2023.9.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 43355435756afee62d68368ee5985a4c420da875 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:58:51 +1300 Subject: [PATCH 0538/2607] Bump zeroconf from 0.112.0 to 0.115.0 (#5432) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 63199680cf..821e7c5786 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.112.0 +zeroconf==0.115.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 507dc5f4961751cdf651327ac76ca1c70561b4f2 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:36:31 +1000 Subject: [PATCH 0539/2607] SPI fixes for buggy components (#5446) --- CODEOWNERS | 2 +- esphome/components/max7219/max7219.cpp | 5 +---- esphome/components/spi/__init__.py | 2 +- esphome/components/spi/spi.h | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 3920a9100e..ce19f14c05 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -270,7 +270,7 @@ esphome/components/sn74hc165/* @jesserockz esphome/components/socket/* @esphome/core esphome/components/sonoff_d1/* @anatoly-savchenkov esphome/components/speaker/* @jesserockz -esphome/components/spi/* @esphome/core +esphome/components/spi/* @clydebarrow @esphome/core esphome/components/spi_device/* @clydebarrow esphome/components/spi_led_strip/* @clydebarrow esphome/components/sprinkler/* @kbx81 diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index 38b4a165cb..b08723f1d4 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -217,10 +217,7 @@ uint8_t MAX7219Component::printf(const char *format, ...) { return 0; } void MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; } -void MAX7219Component::set_intensity(uint8_t intensity) { - this->intensity_ = intensity; - this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_); -} +void MAX7219Component::set_intensity(uint8_t intensity) { this->intensity_ = intensity; } void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; } uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) { diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 79e7a5b034..a5aa610462 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -28,7 +28,7 @@ from esphome.const import ( ) from esphome.core import coroutine_with_priority, CORE -CODEOWNERS = ["@esphome/core"] +CODEOWNERS = ["@esphome/core", "@clydebarrow"] spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 56aa746fc9..107ffb7cb5 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -248,6 +248,7 @@ class SPIDelegateDummy : public SPIDelegate { SPIDelegateDummy() = default; uint8_t transfer(uint8_t data) override { return 0; } + void end_transaction() override{}; void begin_transaction() override; }; From 4d81153150a1bfd5f970bb930976d1e4c7a1077f Mon Sep 17 00:00:00 2001 From: Avri Chen-Roth Date: Fri, 29 Sep 2023 04:17:32 +0300 Subject: [PATCH 0540/2607] Fix an Issue with IR Remote Climate and Whirlpool protocol toggle (#5447) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/whirlpool/whirlpool.cpp | 7 +++++++ esphome/components/whirlpool/whirlpool.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/esphome/components/whirlpool/whirlpool.cpp b/esphome/components/whirlpool/whirlpool.cpp index 225423b4db..1ac32f30da 100644 --- a/esphome/components/whirlpool/whirlpool.cpp +++ b/esphome/components/whirlpool/whirlpool.cpp @@ -33,6 +33,7 @@ const uint8_t WHIRLPOOL_SWING_MASK = 128; const uint8_t WHIRLPOOL_POWER = 0x04; void WhirlpoolClimate::transmit_state() { + this->last_transmit_time_ = millis(); // setting the time of the last transmission. uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0}; remote_state[0] = 0x83; remote_state[1] = 0x06; @@ -149,6 +150,12 @@ void WhirlpoolClimate::transmit_state() { } bool WhirlpoolClimate::on_receive(remote_base::RemoteReceiveData data) { + // Check if the esp isn't currently transmitting. + if (millis() - this->last_transmit_time_ < 500) { + ESP_LOGV(TAG, "Blocked receive because of current trasmittion"); + return false; + } + // Validate header if (!data.expect_item(WHIRLPOOL_HEADER_MARK, WHIRLPOOL_HEADER_SPACE)) { ESP_LOGV(TAG, "Header fail"); diff --git a/esphome/components/whirlpool/whirlpool.h b/esphome/components/whirlpool/whirlpool.h index 7f31894df9..907a21225c 100644 --- a/esphome/components/whirlpool/whirlpool.h +++ b/esphome/components/whirlpool/whirlpool.h @@ -47,6 +47,8 @@ class WhirlpoolClimate : public climate_ir::ClimateIR { void transmit_state() override; /// Handle received IR Buffer bool on_receive(remote_base::RemoteReceiveData data) override; + /// Set the time of the last transmission. + int32_t last_transmit_time_{}; bool send_swing_cmd_{false}; Model model_; From 2c94c3d96f932056a1b8099906b3fabc57e6c79b Mon Sep 17 00:00:00 2001 From: leoshusar Date: Fri, 29 Sep 2023 05:40:56 +0200 Subject: [PATCH 0541/2607] [BP1658CJ] Missing clock line delays and ack bit (#5448) * fix: missing clock line delays and ack bit * chore: remove esphome namespace from delay methods * style: removed trailing whitespace --- esphome/components/bp1658cj/bp1658cj.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/esphome/components/bp1658cj/bp1658cj.cpp b/esphome/components/bp1658cj/bp1658cj.cpp index 5b9e4a5a2c..d3f3e71fed 100644 --- a/esphome/components/bp1658cj/bp1658cj.cpp +++ b/esphome/components/bp1658cj/bp1658cj.cpp @@ -12,6 +12,8 @@ static const uint8_t BP1658CJ_ADDR_START_3CH = 0x10; static const uint8_t BP1658CJ_ADDR_START_2CH = 0x20; static const uint8_t BP1658CJ_ADDR_START_5CH = 0x30; +static const uint8_t BP1658CJ_DELAY = 2; + void BP1658CJ::setup() { ESP_LOGCONFIG(TAG, "Setting up BP1658CJ Output Component..."); this->data_pin_->setup(); @@ -81,27 +83,41 @@ void BP1658CJ::set_channel_value_(uint8_t channel, uint16_t value) { } this->pwm_amounts_[channel] = value; } + void BP1658CJ::write_bit_(bool value) { - this->clock_pin_->digital_write(false); this->data_pin_->digital_write(value); this->clock_pin_->digital_write(true); + + delayMicroseconds(BP1658CJ_DELAY); + + this->clock_pin_->digital_write(false); } void BP1658CJ::write_byte_(uint8_t data) { for (uint8_t mask = 0x80; mask; mask >>= 1) { this->write_bit_(data & mask); + delayMicroseconds(BP1658CJ_DELAY); } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); + + // ack bit + this->data_pin_->pin_mode(gpio::FLAG_INPUT); this->clock_pin_->digital_write(true); + + delayMicroseconds(BP1658CJ_DELAY); + + this->clock_pin_->digital_write(false); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); } void BP1658CJ::write_buffer_(uint8_t *buffer, uint8_t size) { this->data_pin_->digital_write(false); + this->clock_pin_->digital_write(false); + for (uint32_t i = 0; i < size; i++) { this->write_byte_(buffer[i]); + delayMicroseconds(BP1658CJ_DELAY); } - this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); this->data_pin_->digital_write(true); } From d3913be7e531e07f90941eeba4f85c5272d79e90 Mon Sep 17 00:00:00 2001 From: De Cock Xavier Date: Sat, 30 Sep 2023 00:08:56 +0200 Subject: [PATCH 0542/2607] =?UTF-8?q?[ssd1351]=20fix:=20wait=20for=20the?= =?UTF-8?q?=20component=20to=20be=20at=20least=20in=20setup=20phase=20b?= =?UTF-8?q?=E2=80=A6=20(#5454)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/components/ssd1351_base/ssd1351_base.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/ssd1351_base/ssd1351_base.cpp b/esphome/components/ssd1351_base/ssd1351_base.cpp index 036a6a0e82..38ea05a0b8 100644 --- a/esphome/components/ssd1351_base/ssd1351_base.cpp +++ b/esphome/components/ssd1351_base/ssd1351_base.cpp @@ -112,6 +112,9 @@ void SSD1351::set_brightness(float brightness) { } else { this->brightness_ = brightness; } + if (!this->is_ready()) { + return; // Component is not yet setup skip the command + } // now write the new brightness level to the display this->command(SSD1351_CONTRASTMASTER); this->data(int(SSD1351_MAX_CONTRAST * (this->brightness_))); From b3dc2d43a52b181b700477db78a762a228ec2747 Mon Sep 17 00:00:00 2001 From: "John K. Luebs" Date: Fri, 29 Sep 2023 18:27:40 -0500 Subject: [PATCH 0543/2607] Do not enable SHT3x heater by default. Fixes #4886. (#5445) --- esphome/components/sht3xd/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index 5c73a63f1a..80e15a1ab9 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -38,7 +38,7 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Optional(CONF_HEATER_ENABLED, default=True): cv.boolean, + cv.Optional(CONF_HEATER_ENABLED, default=False): cv.boolean, }, ) .extend(cv.polling_component_schema("60s")) From 0b5a57ead403103050288dfe959201b8ead08965 Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Sat, 30 Sep 2023 01:34:56 +0200 Subject: [PATCH 0544/2607] Fix SPI support for second bus on 2023.9.1 (#5456) --- esphome/components/spi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index a5aa610462..fb30755511 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -187,7 +187,7 @@ def get_spi_interface(index): # Following code can't apply to C2, H2 or 8266 since they have only one SPI if get_target_variant() in (VARIANT_ESP32S3, VARIANT_ESP32S2): return "new SPIClass(FSPI)" - return "return new SPIClass(HSPI)" + return "new SPIClass(HSPI)" SPI_SCHEMA = cv.All( From 2513ede3ec2afc8a6d2f0561c1a5425dc0830589 Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Sat, 30 Sep 2023 03:48:51 +0200 Subject: [PATCH 0545/2607] Add testcases for multiple SPI buses on ESP32 Arduino (#5457) --- tests/test4.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test4.yaml b/tests/test4.yaml index 1b809256e7..bb4357e28d 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -32,10 +32,15 @@ i2c: scan: false spi: +- id: spi_id_1 clk_pin: GPIO21 mosi_pin: GPIO22 miso_pin: GPIO23 interface: hardware +- id: spi_id_2 + clk_pin: GPIO32 + mosi_pin: GPIO33 + interface: hardware uart: - id: uart115200 @@ -92,6 +97,7 @@ sx1509: address: 0x3E mcp3204: + spi_id: spi_id_1 cs_pin: GPIO23 dac7678: @@ -495,6 +501,7 @@ display: update_interval: 16ms - platform: waveshare_epaper + spi_id: spi_id_1 cs_pin: GPIO23 dc_pin: GPIO23 busy_pin: GPIO23 @@ -504,6 +511,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: waveshare_epaper + spi_id: spi_id_1 cs_pin: GPIO23 dc_pin: GPIO23 busy_pin: GPIO23 @@ -514,6 +522,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: waveshare_epaper + spi_id: spi_id_1 cs_pin: GPIO23 dc_pin: GPIO23 busy_pin: GPIO23 @@ -523,6 +532,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: waveshare_epaper + spi_id: spi_id_1 cs_pin: GPIO23 dc_pin: GPIO23 busy_pin: GPIO23 @@ -673,6 +683,7 @@ touchscreen: - platform: xpt2046 id: xpt_touchscreen + spi_id: spi_id_2 cs_pin: 17 interrupt_pin: 16 display: inkplate_display From 589b9e10b2c877909083c6551c9d510d02d23ca5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:45:24 +1300 Subject: [PATCH 0546/2607] Ensure esphome directory exists on addon startup (#5464) --- docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run index edb98a8d9b..f973dfcaf8 100755 --- a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run +++ b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run @@ -41,6 +41,8 @@ fi mkdir -p "${pio_cache_base}" +mkdir -p /config/esphome + if bashio::fs.directory_exists '/config/esphome/.esphome'; then bashio::log.info "Migrating old .esphome directory..." if bashio::fs.file_exists '/config/esphome/.esphome/esphome.json'; then From ec4777b8d03845d01e5ed87f72a19093f205d277 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:36:31 +1000 Subject: [PATCH 0547/2607] SPI fixes for buggy components (#5446) --- CODEOWNERS | 2 +- esphome/components/max7219/max7219.cpp | 5 +---- esphome/components/spi/__init__.py | 2 +- esphome/components/spi/spi.h | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 3920a9100e..ce19f14c05 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -270,7 +270,7 @@ esphome/components/sn74hc165/* @jesserockz esphome/components/socket/* @esphome/core esphome/components/sonoff_d1/* @anatoly-savchenkov esphome/components/speaker/* @jesserockz -esphome/components/spi/* @esphome/core +esphome/components/spi/* @clydebarrow @esphome/core esphome/components/spi_device/* @clydebarrow esphome/components/spi_led_strip/* @clydebarrow esphome/components/sprinkler/* @kbx81 diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index 38b4a165cb..b08723f1d4 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -217,10 +217,7 @@ uint8_t MAX7219Component::printf(const char *format, ...) { return 0; } void MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; } -void MAX7219Component::set_intensity(uint8_t intensity) { - this->intensity_ = intensity; - this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_); -} +void MAX7219Component::set_intensity(uint8_t intensity) { this->intensity_ = intensity; } void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; } uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) { diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 79e7a5b034..a5aa610462 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -28,7 +28,7 @@ from esphome.const import ( ) from esphome.core import coroutine_with_priority, CORE -CODEOWNERS = ["@esphome/core"] +CODEOWNERS = ["@esphome/core", "@clydebarrow"] spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 56aa746fc9..107ffb7cb5 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -248,6 +248,7 @@ class SPIDelegateDummy : public SPIDelegate { SPIDelegateDummy() = default; uint8_t transfer(uint8_t data) override { return 0; } + void end_transaction() override{}; void begin_transaction() override; }; From e9bda2810f5b9aaf867ced8c465d89401a0e1e00 Mon Sep 17 00:00:00 2001 From: Avri Chen-Roth Date: Fri, 29 Sep 2023 04:17:32 +0300 Subject: [PATCH 0548/2607] Fix an Issue with IR Remote Climate and Whirlpool protocol toggle (#5447) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/whirlpool/whirlpool.cpp | 7 +++++++ esphome/components/whirlpool/whirlpool.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/esphome/components/whirlpool/whirlpool.cpp b/esphome/components/whirlpool/whirlpool.cpp index 225423b4db..1ac32f30da 100644 --- a/esphome/components/whirlpool/whirlpool.cpp +++ b/esphome/components/whirlpool/whirlpool.cpp @@ -33,6 +33,7 @@ const uint8_t WHIRLPOOL_SWING_MASK = 128; const uint8_t WHIRLPOOL_POWER = 0x04; void WhirlpoolClimate::transmit_state() { + this->last_transmit_time_ = millis(); // setting the time of the last transmission. uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0}; remote_state[0] = 0x83; remote_state[1] = 0x06; @@ -149,6 +150,12 @@ void WhirlpoolClimate::transmit_state() { } bool WhirlpoolClimate::on_receive(remote_base::RemoteReceiveData data) { + // Check if the esp isn't currently transmitting. + if (millis() - this->last_transmit_time_ < 500) { + ESP_LOGV(TAG, "Blocked receive because of current trasmittion"); + return false; + } + // Validate header if (!data.expect_item(WHIRLPOOL_HEADER_MARK, WHIRLPOOL_HEADER_SPACE)) { ESP_LOGV(TAG, "Header fail"); diff --git a/esphome/components/whirlpool/whirlpool.h b/esphome/components/whirlpool/whirlpool.h index 7f31894df9..907a21225c 100644 --- a/esphome/components/whirlpool/whirlpool.h +++ b/esphome/components/whirlpool/whirlpool.h @@ -47,6 +47,8 @@ class WhirlpoolClimate : public climate_ir::ClimateIR { void transmit_state() override; /// Handle received IR Buffer bool on_receive(remote_base::RemoteReceiveData data) override; + /// Set the time of the last transmission. + int32_t last_transmit_time_{}; bool send_swing_cmd_{false}; Model model_; From efd31be21cd347950fe3ef4089e23109c1d81353 Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Sat, 30 Sep 2023 01:34:56 +0200 Subject: [PATCH 0549/2607] Fix SPI support for second bus on 2023.9.1 (#5456) --- esphome/components/spi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index a5aa610462..fb30755511 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -187,7 +187,7 @@ def get_spi_interface(index): # Following code can't apply to C2, H2 or 8266 since they have only one SPI if get_target_variant() in (VARIANT_ESP32S3, VARIANT_ESP32S2): return "new SPIClass(FSPI)" - return "return new SPIClass(HSPI)" + return "new SPIClass(HSPI)" SPI_SCHEMA = cv.All( From af005a6554265cb0f5f2f14fb3302880dfc89429 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:45:24 +1300 Subject: [PATCH 0550/2607] Ensure esphome directory exists on addon startup (#5464) --- docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run index edb98a8d9b..f973dfcaf8 100755 --- a/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run +++ b/docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/run @@ -41,6 +41,8 @@ fi mkdir -p "${pio_cache_base}" +mkdir -p /config/esphome + if bashio::fs.directory_exists '/config/esphome/.esphome'; then bashio::log.info "Migrating old .esphome directory..." if bashio::fs.file_exists '/config/esphome/.esphome/esphome.json'; then From 5e1472185cb478cdd8e60dbc1bb01d1902c921cb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:01:22 +1300 Subject: [PATCH 0551/2607] Bump version to 2023.9.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 65757da130..496880ac88 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.1" +__version__ = "2023.9.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From a33b8abce8ab0ec7b3bb81e62c58ab213c44193c Mon Sep 17 00:00:00 2001 From: De Cock Xavier Date: Mon, 2 Oct 2023 22:25:13 +0200 Subject: [PATCH 0552/2607] Feat/component poller suspend (#5423) --- esphome/automation.py | 38 ++++++++++++++++++++++++++++++++++ esphome/core/base_automation.h | 34 ++++++++++++++++++++++++++++++ esphome/core/component.cpp | 10 +++++++++ esphome/core/component.h | 6 ++++++ tests/test1.yaml | 16 ++++++++++++++ 5 files changed, 104 insertions(+) diff --git a/esphome/automation.py b/esphome/automation.py index 0c4bda09d1..d90a9cb99a 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_TYPE_ID, CONF_TIME, + CONF_UPDATE_INTERVAL, ) from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.util import Registry @@ -69,6 +70,8 @@ WhileAction = cg.esphome_ns.class_("WhileAction", Action) RepeatAction = cg.esphome_ns.class_("RepeatAction", Action) WaitUntilAction = cg.esphome_ns.class_("WaitUntilAction", Action, cg.Component) UpdateComponentAction = cg.esphome_ns.class_("UpdateComponentAction", Action) +SuspendComponentAction = cg.esphome_ns.class_("SuspendComponentAction", Action) +ResumeComponentAction = cg.esphome_ns.class_("ResumeComponentAction", Action) Automation = cg.esphome_ns.class_("Automation") LambdaCondition = cg.esphome_ns.class_("LambdaCondition", Condition) @@ -303,6 +306,41 @@ async def component_update_action_to_code(config, action_id, template_arg, args) return cg.new_Pvariable(action_id, template_arg, comp) +@register_action( + "component.suspend", + SuspendComponentAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(cg.PollingComponent), + } + ), +) +async def component_suspend_action_to_code(config, action_id, template_arg, args): + comp = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, comp) + + +@register_action( + "component.resume", + ResumeComponentAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(cg.PollingComponent), + cv.Optional(CONF_UPDATE_INTERVAL): cv.templatable( + cv.positive_time_period_milliseconds + ), + } + ), +) +async def component_resume_action_to_code(config, action_id, template_arg, args): + comp = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, comp) + if CONF_UPDATE_INTERVAL in config: + template_ = await cg.templatable(config[CONF_UPDATE_INTERVAL], args, int) + cg.add(var.set_update_interval(template_)) + return var + + async def build_action(full_config, template_arg, args): registry_entry, config = cg.extract_registry_entry_config( ACTION_REGISTRY, full_config diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index a17b6a6f85..af618af99a 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -330,4 +330,38 @@ template class UpdateComponentAction : public Action { PollingComponent *component_; }; +template class SuspendComponentAction : public Action { + public: + SuspendComponentAction(PollingComponent *component) : component_(component) {} + + void play(Ts... x) override { + if (!this->component_->is_ready()) + return; + this->component_->stop_poller(); + } + + protected: + PollingComponent *component_; +}; + +template class ResumeComponentAction : public Action { + public: + ResumeComponentAction(PollingComponent *component) : component_(component) {} + TEMPLATABLE_VALUE(uint32_t, update_interval) + + void play(Ts... x) override { + if (!this->component_->is_ready()) { + return; + } + optional update_interval = this->update_interval_.optional_value(x...); + if (update_interval.has_value()) { + this->component_->set_update_interval(update_interval.value()); + } + this->component_->start_poller(); + } + + protected: + PollingComponent *component_; +}; + } // namespace esphome diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index ae85d55498..e2f27f9828 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -188,10 +188,20 @@ void PollingComponent::call_setup() { // Let the polling component subclass setup their HW. this->setup(); + // init the poller + this->start_poller(); +} + +void PollingComponent::start_poller() { // Register interval. this->set_interval("update", this->get_update_interval(), [this]() { this->update(); }); } +void PollingComponent::stop_poller() { + // Clear the interval to suspend component + this->cancel_interval("update"); +} + uint32_t PollingComponent::get_update_interval() const { return this->update_interval_; } void PollingComponent::set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; } diff --git a/esphome/core/component.h b/esphome/core/component.h index 7382f1c617..51a6296811 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -308,6 +308,12 @@ class PollingComponent : public Component { /// Get the update interval in ms of this sensor virtual uint32_t get_update_interval() const; + // Start the poller, used for component.suspend + void start_poller(); + + // Stop the poller, used for component.suspend + void stop_poller(); + protected: uint32_t update_interval_; }; diff --git a/tests/test1.yaml b/tests/test1.yaml index 96dda707b6..b84aa21439 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3566,6 +3566,22 @@ button: name: Midea Power Inverse on_press: midea_ac.power_toggle: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: myteleinfo + - delay: 20s + - component.update: myteleinfo + - delay: 20s + - component.resume: myteleinfo + - delay: 20s + - component.resume: + id: myteleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: myteleinfo + update_interval: !lambda return 2500; - platform: ld2410 factory_reset: name: "factory reset" From e87c8d550bbc9cdf30a18b6ba1cf2f2792cc53e4 Mon Sep 17 00:00:00 2001 From: Maxime Gauduin Date: Mon, 2 Oct 2023 23:15:29 +0200 Subject: [PATCH 0553/2607] add pin config for denky_d4 (#5471) --- esphome/components/esp32/boards.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index 61cb8cdc3f..e6c23c4d96 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -235,6 +235,7 @@ ESP32_BOARD_PINS = { "SDA": 5, "SS": 15, }, + "denky_d4": {"RX": 8, "LED": 14}, "esp-wrover-kit": {}, "esp32-devkitlipo": {}, "esp32-evb": { From 205f41509b06fa243971690d54f39e46a02a9439 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 3 Oct 2023 08:24:20 +1100 Subject: [PATCH 0554/2607] Support RP2040 hardware SPI (#5466) --- esphome/components/spi/__init__.py | 64 +++++++++++++++++++++++++----- tests/test6.yaml | 8 ++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index fb30755511..07e8982f6e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -54,6 +54,21 @@ CONF_FORCE_SW = "force_sw" CONF_INTERFACE = "interface" CONF_INTERFACE_INDEX = "interface_index" +# RP2040 SPI pin assignments are complicated. Refer to https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf + +RP_SPI_PINSETS = [ + { + CONF_MISO_PIN: [0, 4, 16, 20, -1], + CONF_CLK_PIN: [2, 6, 18, 22], + CONF_MOSI_PIN: [3, 7, 19, 23, -1], + }, + { + CONF_MISO_PIN: [8, 12, 24, 28, -1], + CONF_CLK_PIN: [10, 14, 26], + CONF_MOSI_PIN: [11, 23, 27, -1], + }, +] + def get_target_platform(): return ( @@ -85,7 +100,7 @@ def get_hw_interface_list(): return [["spi", "spi2"]] return [["spi", "spi2"], ["spi3"]] if target_platform == "rp2040": - return [["spi"]] + return [["spi"], ["spi1"]] return [] @@ -99,8 +114,10 @@ def get_spi_index(name): # Check that pins are suitable for HW spi +# \param spi the config data for the spi instance +# \param index the selected hw interface number, -1 if not yet known # TODO verify that the pins are internal -def validate_hw_pins(spi): +def validate_hw_pins(spi, index=-1): clk_pin = spi[CONF_CLK_PIN] if clk_pin[CONF_INVERTED]: return False @@ -129,9 +146,30 @@ def validate_hw_pins(spi): if target_platform == "esp32": return clk_pin_no >= 0 + if target_platform == "rp2040": + pin_set = ( + list(filter(lambda s: clk_pin_no in s[CONF_CLK_PIN], RP_SPI_PINSETS))[0] + if index == -1 + else RP_SPI_PINSETS[index] + ) + if pin_set is None: + return False + if sdo_pin_no not in pin_set[CONF_MOSI_PIN]: + return False + if sdi_pin_no not in pin_set[CONF_MISO_PIN]: + return False + return True return False +def get_hw_spi(config, available): + """Get an available hardware spi interface suitable for this config""" + matching = list(filter(lambda idx: validate_hw_pins(config, idx), available)) + if len(matching) != 0: + return matching[0] + return None + + def validate_spi_config(config): available = list(range(len(get_hw_interface_list()))) for spi in config: @@ -147,9 +185,10 @@ def validate_spi_config(config): if not validate_hw_pins(spi): spi[CONF_INTERFACE] = "software" elif interface == "hardware": - if len(available) == 0: - raise cv.Invalid("No hardware interface available") - index = spi[CONF_INTERFACE_INDEX] = available[0] + index = get_hw_spi(spi, available) + if index is None: + raise cv.Invalid("No suitable hardware interface available") + spi[CONF_INTERFACE_INDEX] = index available.remove(index) else: # Must be a specific name @@ -164,11 +203,14 @@ def validate_spi_config(config): # Any specific names and any 'hardware' requests will have already been filled, # so just need to assign remaining hardware to 'any' requests. for spi in config: - if spi[CONF_INTERFACE] == "any" and len(available) != 0: - index = available[0] - spi[CONF_INTERFACE_INDEX] = index - available.remove(index) - if CONF_INTERFACE_INDEX in spi and not validate_hw_pins(spi): + if spi[CONF_INTERFACE] == "any": + index = get_hw_spi(spi, available) + if index is not None: + spi[CONF_INTERFACE_INDEX] = index + available.remove(index) + if CONF_INTERFACE_INDEX in spi and not validate_hw_pins( + spi, spi[CONF_INTERFACE_INDEX] + ): raise cv.Invalid("Invalid pin selections for hardware SPI interface") return config @@ -181,7 +223,7 @@ def get_spi_interface(index): # Arduino code follows platform = get_target_platform() if platform == "rp2040": - return "&spi1" + return ["&SPI", "&SPI1"][index] if index == 0: return "&SPI" # Following code can't apply to C2, H2 or 8266 since they have only one SPI diff --git a/tests/test6.yaml b/tests/test6.yaml index 7c72151860..b0ec04eb6a 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -42,6 +42,14 @@ switch: output: pin_4 id: pin_4_switch + +spi: # Pins are for SPI1 on the RP2040 Pico-W + miso_pin: 8 + clk_pin: 10 + mosi_pin: 11 + id: spi_0 + interface: hardware + #light: # - platform: rp2040_pio_led_strip # id: led_strip From 401a3862194b8b7711be607aec027b02fe4aa418 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:25:15 +1300 Subject: [PATCH 0555/2607] Bump actions/setup-python from 4.7.0 to 4.7.1 (#5467) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/sync-device-classes.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 7fe51163ba..897d01398e 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -42,7 +42,7 @@ jobs: steps: - uses: actions/checkout@v4.1.0 - name: Set up Python - uses: actions/setup-python@v4.7.0 + uses: actions/setup-python@v4.7.1 with: python-version: "3.9" - name: Set up Docker Buildx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26fcbbf458..435a2fdbec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v4.7.0 + uses: actions/setup-python@v4.7.1 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6934d36686..f7652bf478 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,7 @@ jobs: steps: - uses: actions/checkout@v4.1.0 - name: Set up Python - uses: actions/setup-python@v4.7.0 + uses: actions/setup-python@v4.7.1 with: python-version: "3.x" - name: Set up python environment @@ -90,7 +90,7 @@ jobs: steps: - uses: actions/checkout@v4.1.0 - name: Set up Python - uses: actions/setup-python@v4.7.0 + uses: actions/setup-python@v4.7.1 with: python-version: "3.9" diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 25d36bc6d0..082c63ae41 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -22,7 +22,7 @@ jobs: path: lib/home-assistant - name: Setup Python - uses: actions/setup-python@v4.7.0 + uses: actions/setup-python@v4.7.1 with: python-version: 3.11 From 49132565979f2e0bab96a135b3a68cf1484f88c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:51:29 +1300 Subject: [PATCH 0556/2607] Bump zeroconf from 0.115.0 to 0.115.1 (#5470) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 821e7c5786..97e42663d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.115.0 +zeroconf==0.115.1 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From e95ba57a6150ba83108435e3454adb04749d04fa Mon Sep 17 00:00:00 2001 From: dwildstr <65917913+dwildstr@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:06:54 -0400 Subject: [PATCH 0557/2607] Sleep mode fix for BP5758D driver (#5461) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bp5758d/bp5758d.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/bp5758d/bp5758d.cpp b/esphome/components/bp5758d/bp5758d.cpp index 111fd6b68e..71a81f7e6c 100644 --- a/esphome/components/bp5758d/bp5758d.cpp +++ b/esphome/components/bp5758d/bp5758d.cpp @@ -39,10 +39,14 @@ void BP5758D::loop() { uint8_t data[17]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; for (int i = 1; i < 16; i++) data[i] = 0; + + // First turn all channels off + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH; + this->write_buffer_(data, 17); + // Then sleep + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; this->write_buffer_(data, 17); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { From f38849828d8d7f069527b6cf1543af6a84c1d924 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Tue, 3 Oct 2023 03:23:18 +0300 Subject: [PATCH 0558/2607] Tuya Number: split "multiply" to a separate option (#5458) --- esphome/components/tuya/number/__init__.py | 7 +++++-- esphome/components/tuya/number/tuya_number.cpp | 4 ++-- esphome/components/tuya/number/tuya_number.h | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/tuya/number/__init__.py b/esphome/components/tuya/number/__init__.py index 42ac9fcfbe..4dae6d8d60 100644 --- a/esphome/components/tuya/number/__init__.py +++ b/esphome/components/tuya/number/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_NUMBER_DATAPOINT, CONF_MAX_VALUE, CONF_MIN_VALUE, + CONF_MULTIPLY, CONF_STEP, ) from .. import tuya_ns, CONF_TUYA_ID, Tuya @@ -31,6 +32,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_MAX_VALUE): cv.float_, cv.Required(CONF_MIN_VALUE): cv.float_, cv.Required(CONF_STEP): cv.positive_float, + cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_, } ) .extend(cv.COMPONENT_SCHEMA), @@ -49,7 +51,8 @@ async def to_code(config): step=config[CONF_STEP], ) - paren = await cg.get_variable(config[CONF_TUYA_ID]) - cg.add(var.set_tuya_parent(paren)) + cg.add(var.set_write_multiply(config[CONF_MULTIPLY])) + parent = await cg.get_variable(config[CONF_TUYA_ID]) + cg.add(var.set_tuya_parent(parent)) cg.add(var.set_number_id(config[CONF_NUMBER_DATAPOINT])) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index 30ef8b8f72..e883c72d3d 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -10,7 +10,7 @@ void TuyaNumber::setup() { this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { if (datapoint.type == TuyaDatapointType::INTEGER) { ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); - this->publish_state(datapoint.value_int * this->traits.get_step()); + this->publish_state(datapoint.value_int / multiply_by_); } else if (datapoint.type == TuyaDatapointType::ENUM) { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); @@ -22,7 +22,7 @@ void TuyaNumber::setup() { void TuyaNumber::control(float value) { ESP_LOGV(TAG, "Setting number %u: %f", this->number_id_, value); if (this->type_ == TuyaDatapointType::INTEGER) { - int integer_value = lround(value / this->traits.get_step()); + int integer_value = lround(value * multiply_by_); this->parent_->set_integer_datapoint_value(this->number_id_, integer_value); } else if (this->type_ == TuyaDatapointType::ENUM) { this->parent_->set_enum_datapoint_value(this->number_id_, value); diff --git a/esphome/components/tuya/number/tuya_number.h b/esphome/components/tuya/number/tuya_number.h index 7cca9fc646..f64dac8957 100644 --- a/esphome/components/tuya/number/tuya_number.h +++ b/esphome/components/tuya/number/tuya_number.h @@ -12,6 +12,7 @@ class TuyaNumber : public number::Number, public Component { void setup() override; void dump_config() override; void set_number_id(uint8_t number_id) { this->number_id_ = number_id; } + void set_write_multiply(float factor) { multiply_by_ = factor; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } @@ -20,6 +21,7 @@ class TuyaNumber : public number::Number, public Component { Tuya *parent_; uint8_t number_id_{0}; + float multiply_by_{1.0}; TuyaDatapointType type_{}; }; From f73fd975250364ae783593ef927393015fbe8577 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:58:51 +1300 Subject: [PATCH 0559/2607] Bump zeroconf from 0.112.0 to 0.115.0 (#5432) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 63199680cf..821e7c5786 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.112.0 +zeroconf==0.115.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 689c2f11a39f7b1c0411160714802c15ffaef74b Mon Sep 17 00:00:00 2001 From: Maxime Gauduin Date: Mon, 2 Oct 2023 23:15:29 +0200 Subject: [PATCH 0560/2607] add pin config for denky_d4 (#5471) --- esphome/components/esp32/boards.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index 61cb8cdc3f..e6c23c4d96 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -235,6 +235,7 @@ ESP32_BOARD_PINS = { "SDA": 5, "SS": 15, }, + "denky_d4": {"RX": 8, "LED": 14}, "esp-wrover-kit": {}, "esp32-devkitlipo": {}, "esp32-evb": { From f5dfbaff4b2938e2015434dc05e4213dfd43077d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 3 Oct 2023 08:24:20 +1100 Subject: [PATCH 0561/2607] Support RP2040 hardware SPI (#5466) --- esphome/components/spi/__init__.py | 64 +++++++++++++++++++++++++----- tests/test6.yaml | 8 ++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index fb30755511..07e8982f6e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -54,6 +54,21 @@ CONF_FORCE_SW = "force_sw" CONF_INTERFACE = "interface" CONF_INTERFACE_INDEX = "interface_index" +# RP2040 SPI pin assignments are complicated. Refer to https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf + +RP_SPI_PINSETS = [ + { + CONF_MISO_PIN: [0, 4, 16, 20, -1], + CONF_CLK_PIN: [2, 6, 18, 22], + CONF_MOSI_PIN: [3, 7, 19, 23, -1], + }, + { + CONF_MISO_PIN: [8, 12, 24, 28, -1], + CONF_CLK_PIN: [10, 14, 26], + CONF_MOSI_PIN: [11, 23, 27, -1], + }, +] + def get_target_platform(): return ( @@ -85,7 +100,7 @@ def get_hw_interface_list(): return [["spi", "spi2"]] return [["spi", "spi2"], ["spi3"]] if target_platform == "rp2040": - return [["spi"]] + return [["spi"], ["spi1"]] return [] @@ -99,8 +114,10 @@ def get_spi_index(name): # Check that pins are suitable for HW spi +# \param spi the config data for the spi instance +# \param index the selected hw interface number, -1 if not yet known # TODO verify that the pins are internal -def validate_hw_pins(spi): +def validate_hw_pins(spi, index=-1): clk_pin = spi[CONF_CLK_PIN] if clk_pin[CONF_INVERTED]: return False @@ -129,9 +146,30 @@ def validate_hw_pins(spi): if target_platform == "esp32": return clk_pin_no >= 0 + if target_platform == "rp2040": + pin_set = ( + list(filter(lambda s: clk_pin_no in s[CONF_CLK_PIN], RP_SPI_PINSETS))[0] + if index == -1 + else RP_SPI_PINSETS[index] + ) + if pin_set is None: + return False + if sdo_pin_no not in pin_set[CONF_MOSI_PIN]: + return False + if sdi_pin_no not in pin_set[CONF_MISO_PIN]: + return False + return True return False +def get_hw_spi(config, available): + """Get an available hardware spi interface suitable for this config""" + matching = list(filter(lambda idx: validate_hw_pins(config, idx), available)) + if len(matching) != 0: + return matching[0] + return None + + def validate_spi_config(config): available = list(range(len(get_hw_interface_list()))) for spi in config: @@ -147,9 +185,10 @@ def validate_spi_config(config): if not validate_hw_pins(spi): spi[CONF_INTERFACE] = "software" elif interface == "hardware": - if len(available) == 0: - raise cv.Invalid("No hardware interface available") - index = spi[CONF_INTERFACE_INDEX] = available[0] + index = get_hw_spi(spi, available) + if index is None: + raise cv.Invalid("No suitable hardware interface available") + spi[CONF_INTERFACE_INDEX] = index available.remove(index) else: # Must be a specific name @@ -164,11 +203,14 @@ def validate_spi_config(config): # Any specific names and any 'hardware' requests will have already been filled, # so just need to assign remaining hardware to 'any' requests. for spi in config: - if spi[CONF_INTERFACE] == "any" and len(available) != 0: - index = available[0] - spi[CONF_INTERFACE_INDEX] = index - available.remove(index) - if CONF_INTERFACE_INDEX in spi and not validate_hw_pins(spi): + if spi[CONF_INTERFACE] == "any": + index = get_hw_spi(spi, available) + if index is not None: + spi[CONF_INTERFACE_INDEX] = index + available.remove(index) + if CONF_INTERFACE_INDEX in spi and not validate_hw_pins( + spi, spi[CONF_INTERFACE_INDEX] + ): raise cv.Invalid("Invalid pin selections for hardware SPI interface") return config @@ -181,7 +223,7 @@ def get_spi_interface(index): # Arduino code follows platform = get_target_platform() if platform == "rp2040": - return "&spi1" + return ["&SPI", "&SPI1"][index] if index == 0: return "&SPI" # Following code can't apply to C2, H2 or 8266 since they have only one SPI diff --git a/tests/test6.yaml b/tests/test6.yaml index 3d6a1ceb1f..c6d9c6feba 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -39,6 +39,14 @@ switch: output: pin_4 id: pin_4_switch + +spi: # Pins are for SPI1 on the RP2040 Pico-W + miso_pin: 8 + clk_pin: 10 + mosi_pin: 11 + id: spi_0 + interface: hardware + #light: # - platform: rp2040_pio_led_strip # id: led_strip From 85c5928baa6bddc3668f20af3b32ac6052e77f9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:51:29 +1300 Subject: [PATCH 0562/2607] Bump zeroconf from 0.115.0 to 0.115.1 (#5470) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 821e7c5786..97e42663d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==15.0.0 -zeroconf==0.115.0 +zeroconf==0.115.1 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From f709350b04ebb52320492fb450fbeded051b6c8e Mon Sep 17 00:00:00 2001 From: dwildstr <65917913+dwildstr@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:06:54 -0400 Subject: [PATCH 0563/2607] Sleep mode fix for BP5758D driver (#5461) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bp5758d/bp5758d.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/bp5758d/bp5758d.cpp b/esphome/components/bp5758d/bp5758d.cpp index 111fd6b68e..71a81f7e6c 100644 --- a/esphome/components/bp5758d/bp5758d.cpp +++ b/esphome/components/bp5758d/bp5758d.cpp @@ -39,10 +39,14 @@ void BP5758D::loop() { uint8_t data[17]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; for (int i = 1; i < 16; i++) data[i] = 0; + + // First turn all channels off + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH; + this->write_buffer_(data, 17); + // Then sleep + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; this->write_buffer_(data, 17); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { From 7dfc4c74da6d20de03ee01254e81bf7c5a36509e Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Tue, 3 Oct 2023 03:23:18 +0300 Subject: [PATCH 0564/2607] Tuya Number: split "multiply" to a separate option (#5458) --- esphome/components/tuya/number/__init__.py | 7 +++++-- esphome/components/tuya/number/tuya_number.cpp | 4 ++-- esphome/components/tuya/number/tuya_number.h | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/tuya/number/__init__.py b/esphome/components/tuya/number/__init__.py index 42ac9fcfbe..4dae6d8d60 100644 --- a/esphome/components/tuya/number/__init__.py +++ b/esphome/components/tuya/number/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_NUMBER_DATAPOINT, CONF_MAX_VALUE, CONF_MIN_VALUE, + CONF_MULTIPLY, CONF_STEP, ) from .. import tuya_ns, CONF_TUYA_ID, Tuya @@ -31,6 +32,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_MAX_VALUE): cv.float_, cv.Required(CONF_MIN_VALUE): cv.float_, cv.Required(CONF_STEP): cv.positive_float, + cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_, } ) .extend(cv.COMPONENT_SCHEMA), @@ -49,7 +51,8 @@ async def to_code(config): step=config[CONF_STEP], ) - paren = await cg.get_variable(config[CONF_TUYA_ID]) - cg.add(var.set_tuya_parent(paren)) + cg.add(var.set_write_multiply(config[CONF_MULTIPLY])) + parent = await cg.get_variable(config[CONF_TUYA_ID]) + cg.add(var.set_tuya_parent(parent)) cg.add(var.set_number_id(config[CONF_NUMBER_DATAPOINT])) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index 30ef8b8f72..e883c72d3d 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -10,7 +10,7 @@ void TuyaNumber::setup() { this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { if (datapoint.type == TuyaDatapointType::INTEGER) { ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); - this->publish_state(datapoint.value_int * this->traits.get_step()); + this->publish_state(datapoint.value_int / multiply_by_); } else if (datapoint.type == TuyaDatapointType::ENUM) { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); @@ -22,7 +22,7 @@ void TuyaNumber::setup() { void TuyaNumber::control(float value) { ESP_LOGV(TAG, "Setting number %u: %f", this->number_id_, value); if (this->type_ == TuyaDatapointType::INTEGER) { - int integer_value = lround(value / this->traits.get_step()); + int integer_value = lround(value * multiply_by_); this->parent_->set_integer_datapoint_value(this->number_id_, integer_value); } else if (this->type_ == TuyaDatapointType::ENUM) { this->parent_->set_enum_datapoint_value(this->number_id_, value); diff --git a/esphome/components/tuya/number/tuya_number.h b/esphome/components/tuya/number/tuya_number.h index 7cca9fc646..f64dac8957 100644 --- a/esphome/components/tuya/number/tuya_number.h +++ b/esphome/components/tuya/number/tuya_number.h @@ -12,6 +12,7 @@ class TuyaNumber : public number::Number, public Component { void setup() override; void dump_config() override; void set_number_id(uint8_t number_id) { this->number_id_ = number_id; } + void set_write_multiply(float factor) { multiply_by_ = factor; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } @@ -20,6 +21,7 @@ class TuyaNumber : public number::Number, public Component { Tuya *parent_; uint8_t number_id_{0}; + float multiply_by_{1.0}; TuyaDatapointType type_{}; }; From 471533d0418290814216f84ab500ba2582ad99b2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 3 Oct 2023 13:35:19 +1300 Subject: [PATCH 0565/2607] Bump version to 2023.9.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 496880ac88..15558da081 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.9.2" +__version__ = "2023.9.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 88bb051f376eb600f6169b907e7490dda6acba13 Mon Sep 17 00:00:00 2001 From: kahrendt Date: Tue, 3 Oct 2023 05:58:11 -0400 Subject: [PATCH 0566/2607] Add xor automation condition (#5453) --- esphome/automation.py | 7 +++++++ esphome/core/base_automation.h | 16 +++++++++++++++ tests/test1.yaml | 36 ++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/esphome/automation.py b/esphome/automation.py index d90a9cb99a..8475858a9c 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -141,6 +141,7 @@ AUTOMATION_SCHEMA = cv.Schema( AndCondition = cg.esphome_ns.class_("AndCondition", Condition) OrCondition = cg.esphome_ns.class_("OrCondition", Condition) NotCondition = cg.esphome_ns.class_("NotCondition", Condition) +XorCondition = cg.esphome_ns.class_("XorCondition", Condition) @register_condition("and", AndCondition, validate_condition_list) @@ -161,6 +162,12 @@ async def not_condition_to_code(config, condition_id, template_arg, args): return cg.new_Pvariable(condition_id, template_arg, condition) +@register_condition("xor", XorCondition, validate_condition_list) +async def xor_condition_to_code(config, condition_id, template_arg, args): + conditions = await build_condition_list(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, conditions) + + @register_condition("lambda", LambdaCondition, cv.returning_lambda) async def lambda_condition_to_code(config, condition_id, template_arg, args): lambda_ = await cg.process_lambda(config, args, return_type=bool) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index af618af99a..9b3377f694 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -48,6 +48,22 @@ template class NotCondition : public Condition { Condition *condition_; }; +template class XorCondition : public Condition { + public: + explicit XorCondition(const std::vector *> &conditions) : conditions_(conditions) {} + bool check(Ts... x) override { + bool xor_state = false; + for (auto *condition : this->conditions_) { + xor_state = xor_state ^ condition->check(x...); + } + + return xor_state; + } + + protected: + std::vector *> conditions_; +}; + template class LambdaCondition : public Condition { public: explicit LambdaCondition(std::function &&f) : f_(std::move(f)) {} diff --git a/tests/test1.yaml b/tests/test1.yaml index b84aa21439..11ce86c5f3 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3104,11 +3104,39 @@ time: - platform: ds1307 id: ds1307_time update_interval: never - on_time: - seconds: 0 - then: ds1307.read_time i2c_id: i2c_bus - + on_time: + - seconds: 0 + then: ds1307.read_time + - at: "16:00:00" + then: + - if: + condition: + or: + - binary_sensor.is_on: close_sensor + - binary_sensor.is_on: open_sensor + then: + logger.log: "close_sensor or open_sensor is on" + - if: + condition: + and: + - binary_sensor.is_on: close_sensor + - binary_sensor.is_on: open_sensor + then: + logger.log: "close_sensor and open_sensor are both on" + - if: + condition: + xor: + - binary_sensor.is_on: close_sensor + - binary_sensor.is_on: open_sensor + then: + logger.log: "close_sensor or open_sensor is exclusively on" + - if: + condition: + not: + - binary_sensor.is_on: close_sensor + then: + logger.log: "close_sensor is not on" cover: - platform: template name: Template Cover From 050fa0d4c17ac240abf2ebafdc27fdab1d53135d Mon Sep 17 00:00:00 2001 From: kahrendt Date: Tue, 3 Oct 2023 06:01:57 -0400 Subject: [PATCH 0567/2607] Fix units for SPS30 number concentration sensors (#5452) --- esphome/components/sps30/sensor.py | 12 ++++++------ esphome/const.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/components/sps30/sensor.py b/esphome/components/sps30/sensor.py index ff8d5a3594..0f01bab514 100644 --- a/esphome/components/sps30/sensor.py +++ b/esphome/components/sps30/sensor.py @@ -20,7 +20,7 @@ from esphome.const import ( DEVICE_CLASS_PM25, STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, - UNIT_COUNTS_PER_CUBIC_METER, + UNIT_COUNTS_PER_CUBIC_CENTIMETER, UNIT_MICROMETER, ICON_CHEMICAL_WEAPON, ICON_COUNTER, @@ -73,31 +73,31 @@ CONFIG_SCHEMA = ( state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_0_5): sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS_PER_CUBIC_METER, + unit_of_measurement=UNIT_COUNTS_PER_CUBIC_CENTIMETER, icon=ICON_COUNTER, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_1_0): sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS_PER_CUBIC_METER, + unit_of_measurement=UNIT_COUNTS_PER_CUBIC_CENTIMETER, icon=ICON_COUNTER, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_2_5): sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS_PER_CUBIC_METER, + unit_of_measurement=UNIT_COUNTS_PER_CUBIC_CENTIMETER, icon=ICON_COUNTER, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_4_0): sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS_PER_CUBIC_METER, + unit_of_measurement=UNIT_COUNTS_PER_CUBIC_CENTIMETER, icon=ICON_COUNTER, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_10_0): sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS_PER_CUBIC_METER, + unit_of_measurement=UNIT_COUNTS_PER_CUBIC_CENTIMETER, icon=ICON_COUNTER, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, diff --git a/esphome/const.py b/esphome/const.py index 2865b369e8..e188ba478e 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -915,7 +915,7 @@ UNIT_BYTES = "B" UNIT_CELSIUS = "°C" UNIT_CENTIMETER = "cm" UNIT_COUNT_DECILITRE = "/dL" -UNIT_COUNTS_PER_CUBIC_METER = "#/m³" +UNIT_COUNTS_PER_CUBIC_CENTIMETER = "#/cm³" UNIT_CUBIC_METER = "m³" UNIT_CUBIC_METER_PER_HOUR = "m³/h" UNIT_DECIBEL = "dB" From 506c2ba6c7064692a11bf18b0a9ed935a6055ffc Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:10:26 +1100 Subject: [PATCH 0568/2607] ST7789v - Allow predefined backlight pin to be disabled. (#5476) * Allow predefined backlight pin to be disabled. * Add test * Update esphome/components/st7789v/display.py --- esphome/components/st7789v/display.py | 7 +++++-- tests/test1.yaml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index ad152bf356..a4c08974c6 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -138,7 +138,10 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_MODEL): cv.one_of(*MODELS.keys(), upper=True, space="_"), cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_DC_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_BACKLIGHT_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_BACKLIGHT_PIN): cv.Any( + cv.boolean, + pins.gpio_output_pin_schema, + ), cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), cv.Optional(CONF_EIGHTBITCOLOR, default=False): cv.boolean, cv.Optional(CONF_HEIGHT): cv.int_, @@ -174,7 +177,7 @@ async def to_code(config): reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) - if CONF_BACKLIGHT_PIN in config: + if CONF_BACKLIGHT_PIN in config and config[CONF_BACKLIGHT_PIN]: bl = await cg.gpio_pin_expression(config[CONF_BACKLIGHT_PIN]) cg.add(var.set_backlight_pin(bl)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 11ce86c5f3..ea69343dbf 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2948,7 +2948,7 @@ display: cs_pin: GPIO5 dc_pin: GPIO16 reset_pin: GPIO23 - backlight_pin: GPIO4 + backlight_pin: no lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: st7920 From 4e8cba49f1240c76388a9db49b1cb903e702a1af Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:15:44 +1100 Subject: [PATCH 0569/2607] MAX7219 - Update intensity (#5477) --- esphome/components/max7219/max7219.cpp | 12 +++++++++++- esphome/components/max7219/max7219.h | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index b08723f1d4..d3cf6f5c48 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -164,6 +164,10 @@ void MAX7219Component::send_to_all_(uint8_t a_register, uint8_t data) { this->disable(); } void MAX7219Component::update() { + if (this->intensity_changed_) { + this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_); + this->intensity_changed_ = false; + } for (uint8_t i = 0; i < this->num_chips_ * 8; i++) this->buffer_[i] = 0; if (this->writer_.has_value()) @@ -217,7 +221,13 @@ uint8_t MAX7219Component::printf(const char *format, ...) { return 0; } void MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; } -void MAX7219Component::set_intensity(uint8_t intensity) { this->intensity_ = intensity; } +void MAX7219Component::set_intensity(uint8_t intensity) { + intensity &= 0xF; + if (intensity != this->intensity_) { + this->intensity_changed_ = true; + this->intensity_ = intensity; + } +} void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; } uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) { diff --git a/esphome/components/max7219/max7219.h b/esphome/components/max7219/max7219.h index 1b724cef69..270edf3282 100644 --- a/esphome/components/max7219/max7219.h +++ b/esphome/components/max7219/max7219.h @@ -52,7 +52,8 @@ class MAX7219Component : public PollingComponent, void send_byte_(uint8_t a_register, uint8_t data); void send_to_all_(uint8_t a_register, uint8_t data); - uint8_t intensity_{15}; /// Intensity of the display from 0 to 15 (most) + uint8_t intensity_{15}; // Intensity of the display from 0 to 15 (most) + bool intensity_changed_{}; // True if we need to re-send the intensity uint8_t num_chips_{1}; uint8_t *buffer_; bool reverse_{false}; From b6d5cb4142c42de8c6b6a12af4caf4c87546b673 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 5 Oct 2023 07:18:33 +1100 Subject: [PATCH 0570/2607] St7789v and SPI data rate (#5472) --- esphome/components/ili9xxx/display.py | 5 +---- esphome/components/max6675/max6675.h | 2 +- esphome/components/spi/__init__.py | 27 ++++++++++++++++++++++- esphome/components/spi_device/__init__.py | 6 ++--- esphome/components/spi_led_strip/light.py | 6 ++--- esphome/components/st7789v/st7789v.cpp | 1 + tests/test2.yaml | 1 + 7 files changed, 34 insertions(+), 14 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 89a6b2d1b9..1a18978d94 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -13,7 +13,6 @@ from esphome.const import ( CONF_PAGES, CONF_RESET_PIN, CONF_DIMENSIONS, - CONF_DATA_RATE, ) DEPENDENCIES = ["spi"] @@ -100,11 +99,10 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( cv.file_ ), - cv.Optional(CONF_DATA_RATE, default="40MHz"): spi.SPI_DATA_RATE_SCHEMA, } ) .extend(cv.polling_component_schema("1s")) - .extend(spi.spi_device_schema(False)), + .extend(spi.spi_device_schema(False, "40MHz")), cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), _validate, ) @@ -177,4 +175,3 @@ async def to_code(config): if rhs is not None: prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) - cg.add(var.set_data_rate(config[CONF_DATA_RATE])) diff --git a/esphome/components/max6675/max6675.h b/esphome/components/max6675/max6675.h index 09bd9df3b8..ab0f06b041 100644 --- a/esphome/components/max6675/max6675.h +++ b/esphome/components/max6675/max6675.h @@ -10,7 +10,7 @@ namespace max6675 { class MAX6675Sensor : public sensor::Sensor, public PollingComponent, public spi::SPIDevice { + spi::DATA_RATE_1MHZ> { public: void setup() override; void dump_config() override; diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 07e8982f6e..dc9d560874 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -25,6 +25,7 @@ from esphome.const import ( KEY_CORE, KEY_TARGET_PLATFORM, KEY_VARIANT, + CONF_DATA_RATE, ) from esphome.core import coroutine_with_priority, CORE @@ -33,6 +34,7 @@ spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") SPIDataRate = spi_ns.enum("SPIDataRate") +SPIMode = spi_ns.enum("SPIMode") SPI_DATA_RATE_OPTIONS = { 80e6: SPIDataRate.DATA_RATE_80MHZ, @@ -50,6 +52,18 @@ SPI_DATA_RATE_OPTIONS = { } SPI_DATA_RATE_SCHEMA = cv.All(cv.frequency, cv.enum(SPI_DATA_RATE_OPTIONS)) +SPI_MODE_OPTIONS = { + "MODE0": SPIMode.MODE0, + "MODE1": SPIMode.MODE1, + "MODE2": SPIMode.MODE2, + "MODE3": SPIMode.MODE3, + 0: SPIMode.MODE0, + 1: SPIMode.MODE1, + 2: SPIMode.MODE2, + 3: SPIMode.MODE3, +} + +CONF_SPI_MODE = "spi_mode" CONF_FORCE_SW = "force_sw" CONF_INTERFACE = "interface" CONF_INTERFACE_INDEX = "interface_index" @@ -286,13 +300,20 @@ async def to_code(configs): cg.add_library("SPI", None) -def spi_device_schema(cs_pin_required=True): +def spi_device_schema( + cs_pin_required=True, default_data_rate=cv.UNDEFINED, default_mode=cv.UNDEFINED +): """Create a schema for an SPI device. :param cs_pin_required: If true, make the CS_PIN required in the config. + :param default_data_rate: Optional data_rate to use as default :return: The SPI device schema, `extend` this in your config schema. """ schema = { cv.GenerateID(CONF_SPI_ID): cv.use_id(SPIComponent), + cv.Optional(CONF_DATA_RATE, default=default_data_rate): SPI_DATA_RATE_SCHEMA, + cv.Optional(CONF_SPI_MODE, default=default_mode): cv.enum( + SPI_MODE_OPTIONS, upper=True + ), } if cs_pin_required: schema[cv.Required(CONF_CS_PIN)] = pins.gpio_output_pin_schema @@ -307,6 +328,10 @@ async def register_spi_device(var, config): if CONF_CS_PIN in config: pin = await cg.gpio_pin_expression(config[CONF_CS_PIN]) cg.add(var.set_cs_pin(pin)) + if CONF_DATA_RATE in config: + cg.add(var.set_data_rate(config[CONF_DATA_RATE])) + if CONF_SPI_MODE in config: + cg.add(var.set_mode(config[CONF_SPI_MODE])) def final_validate_device_schema(name: str, *, require_mosi: bool, require_miso: bool): diff --git a/esphome/components/spi_device/__init__.py b/esphome/components/spi_device/__init__.py index 428b5bfbda..65e7ee6fc6 100644 --- a/esphome/components/spi_device/__init__.py +++ b/esphome/components/spi_device/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import spi -from esphome.const import CONF_ID, CONF_DATA_RATE, CONF_MODE +from esphome.const import CONF_ID, CONF_MODE DEPENDENCIES = ["spi"] CODEOWNERS = ["@clydebarrow"] @@ -33,17 +33,15 @@ CONF_BIT_ORDER = "bit_order" CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_ID): cv.declare_id(spi_device), - cv.Optional(CONF_DATA_RATE, default="1MHz"): spi.SPI_DATA_RATE_SCHEMA, cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True), cv.Optional(CONF_MODE, default="0"): cv.enum(MODES, upper=True), } -).extend(spi.spi_device_schema(False)) +).extend(spi.spi_device_schema(False, "1MHz")) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - cg.add(var.set_data_rate(config[CONF_DATA_RATE])) cg.add(var.set_mode(config[CONF_MODE])) cg.add(var.set_bit_order(config[CONF_BIT_ORDER])) await spi.register_spi_device(var, config) diff --git a/esphome/components/spi_led_strip/light.py b/esphome/components/spi_led_strip/light.py index 7420b0c929..78642935de 100644 --- a/esphome/components/spi_led_strip/light.py +++ b/esphome/components/spi_led_strip/light.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import light from esphome.components import spi -from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_DATA_RATE +from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS spi_led_strip_ns = cg.esphome_ns.namespace("spi_led_strip") SpiLedStrip = spi_led_strip_ns.class_( @@ -13,14 +13,12 @@ CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( { cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpiLedStrip), cv.Optional(CONF_NUM_LEDS, default=1): cv.positive_not_null_int, - cv.Optional(CONF_DATA_RATE, default="1MHz"): spi.SPI_DATA_RATE_SCHEMA, } -).extend(spi.spi_device_schema(False)) +).extend(spi.spi_device_schema(False, "1MHz")) async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - cg.add(var.set_data_rate(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]])) cg.add(var.set_num_leds(config[CONF_NUM_LEDS])) await light.register_light(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index a181723546..74c7a4e9e3 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -133,6 +133,7 @@ void ST7789V::dump_config() { LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" B/L Pin: ", this->backlight_pin_); LOG_UPDATE_INTERVAL(this); + ESP_LOGCONFIG(TAG, " Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); #ifdef USE_POWER_SUPPLY ESP_LOGCONFIG(TAG, " Power Supply Configured: yes"); #endif diff --git a/tests/test2.yaml b/tests/test2.yaml index 5485711c2e..fe577c2188 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -724,6 +724,7 @@ interval: display: - platform: st7789v model: LILYGO_T-EMBED_170X320 + spi_mode: mode0 height: 320 width: 170 offset_height: 35 From 44e5b0c74540bdabfd55c0f68ed84e77277477d0 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Fri, 6 Oct 2023 00:28:51 -0500 Subject: [PATCH 0571/2607] Move CONF_IRQ_PIN into const.py (#5488) --- esphome/components/ade7953/sensor.py | 4 ++-- esphome/components/as3935/__init__.py | 12 ++++++------ esphome/components/xpt2046/touchscreen.py | 3 +-- esphome/const.py | 1 + 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/esphome/components/ade7953/sensor.py b/esphome/components/ade7953/sensor.py index 878f2f8e2d..8a43baf475 100644 --- a/esphome/components/ade7953/sensor.py +++ b/esphome/components/ade7953/sensor.py @@ -4,13 +4,14 @@ from esphome.components import sensor, i2c from esphome import pins from esphome.const import ( CONF_ID, + CONF_IRQ_PIN, CONF_VOLTAGE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT, - UNIT_VOLT, UNIT_AMPERE, + UNIT_VOLT, UNIT_WATT, ) @@ -19,7 +20,6 @@ DEPENDENCIES = ["i2c"] ade7953_ns = cg.esphome_ns.namespace("ade7953") ADE7953 = ade7953_ns.class_("ADE7953", cg.PollingComponent, i2c.I2CDevice) -CONF_IRQ_PIN = "irq_pin" CONF_CURRENT_A = "current_a" CONF_CURRENT_B = "current_b" CONF_ACTIVE_POWER_A = "active_power_a" diff --git a/esphome/components/as3935/__init__.py b/esphome/components/as3935/__init__.py index cf0580ca62..5cec1bfaba 100644 --- a/esphome/components/as3935/__init__.py +++ b/esphome/components/as3935/__init__.py @@ -2,14 +2,15 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins from esphome.const import ( + CONF_CAPACITANCE, + CONF_DIV_RATIO, CONF_INDOOR, - CONF_WATCHDOG_THRESHOLD, - CONF_NOISE_LEVEL, - CONF_SPIKE_REJECTION, + CONF_IRQ_PIN, CONF_LIGHTNING_THRESHOLD, CONF_MASK_DISTURBER, - CONF_DIV_RATIO, - CONF_CAPACITANCE, + CONF_NOISE_LEVEL, + CONF_SPIKE_REJECTION, + CONF_WATCHDOG_THRESHOLD, ) MULTI_CONF = True @@ -19,7 +20,6 @@ CONF_AS3935_ID = "as3935_id" as3935_ns = cg.esphome_ns.namespace("as3935") AS3935 = as3935_ns.class_("AS3935Component", cg.Component) -CONF_IRQ_PIN = "irq_pin" AS3935_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(AS3935), diff --git a/esphome/components/xpt2046/touchscreen.py b/esphome/components/xpt2046/touchscreen.py index e45b723179..150d1cf396 100644 --- a/esphome/components/xpt2046/touchscreen.py +++ b/esphome/components/xpt2046/touchscreen.py @@ -3,7 +3,7 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import spi, touchscreen -from esphome.const import CONF_ID, CONF_THRESHOLD, CONF_INTERRUPT_PIN +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_IRQ_PIN, CONF_THRESHOLD CODEOWNERS = ["@numo68", "@nielsnl68"] DEPENDENCIES = ["spi"] @@ -26,7 +26,6 @@ CONF_SWAP_X_Y = "swap_x_y" # obsolete Keys CONF_DIMENSION_X = "dimension_x" CONF_DIMENSION_Y = "dimension_y" -CONF_IRQ_PIN = "irq_pin" def validate_xpt2046(config): diff --git a/esphome/const.py b/esphome/const.py index e188ba478e..75ed874cfd 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -360,6 +360,7 @@ CONF_INVALID_COOLDOWN = "invalid_cooldown" CONF_INVERT = "invert" CONF_INVERTED = "inverted" CONF_IP_ADDRESS = "ip_address" +CONF_IRQ_PIN = "irq_pin" CONF_JS_INCLUDE = "js_include" CONF_JS_URL = "js_url" CONF_JVC = "jvc" From fa0dcac2c75d81f9b2a1b287c9792f1bc281bed4 Mon Sep 17 00:00:00 2001 From: Austin Date: Sun, 8 Oct 2023 14:34:12 -0400 Subject: [PATCH 0572/2607] Initial ESP32-H2 Support (#5498) --- esphome/components/deep_sleep/__init__.py | 2 + esphome/components/esp32/gpio_esp32_h2.py | 50 +++++++++++++++++-- .../components/esp32_rmt_led_strip/light.py | 1 + esphome/components/logger/__init__.py | 2 + esphome/components/logger/logger.cpp | 18 ++++--- esphome/components/logger/logger.h | 11 ++-- esphome/components/wifi/__init__.py | 12 ++++- 7 files changed, 80 insertions(+), 16 deletions(-) diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index 6e71f7bbf6..bb7084282c 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -24,6 +24,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S3, VARIANT_ESP32C2, VARIANT_ESP32C6, + VARIANT_ESP32H2, ) WAKEUP_PINS = { @@ -98,6 +99,7 @@ WAKEUP_PINS = { ], VARIANT_ESP32C2: [0, 1, 2, 3, 4, 5], VARIANT_ESP32C6: [0, 1, 2, 3, 4, 5, 6, 7], + VARIANT_ESP32H2: [7, 8, 9, 10, 11, 12, 13, 14], } diff --git a/esphome/components/esp32/gpio_esp32_h2.py b/esphome/components/esp32/gpio_esp32_h2.py index 5196ef0c09..d18ee8a2a6 100644 --- a/esphome/components/esp32/gpio_esp32_h2.py +++ b/esphome/components/esp32/gpio_esp32_h2.py @@ -1,11 +1,53 @@ +import logging + +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER + import esphome.config_validation as cv +_ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21} + +_ESP32H2_USB_JTAG_PINS = {26, 27} + +_ESP32H2_STRAPPING_PINS = {2, 3, 8, 9, 25} + +_LOGGER = logging.getLogger(__name__) + def esp32_h2_validate_gpio_pin(value): - # ESP32-H2 not yet supported - raise cv.Invalid("ESP32-H2 isn't supported yet") + if value < 0 or value > 27: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-27)") + if value in _ESP32H2_STRAPPING_PINS: + _LOGGER.warning( + "GPIO%d is a Strapping PIN and should be avoided.\n" + "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" + "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", + value, + ) + if value in _ESP32H2_SPI_FLASH_PINS: + _LOGGER.warning( + "GPIO%d is reserved for SPI Flash communication on some ESP32-H2 chip variants.\n" + "Utilizing SPI-reserved pins could cause unexpected failures.\n" + "See https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/peripherals/gpio.html", + value, + ) + if value in _ESP32H2_USB_JTAG_PINS: + _LOGGER.warning( + "GPIO%d is reserved for the USB-Serial-JTAG interface.\n" + "To use this pin as GPIO, USB-Serial-JTAG will be disabled.", + value, + ) + + return value def esp32_h2_validate_supports(value): - # ESP32-H2 not yet supported - raise cv.Invalid("ESP32-H2 isn't supported yet") + num = value[CONF_NUMBER] + mode = value[CONF_MODE] + is_input = mode[CONF_INPUT] + + if num < 0 or num > 27: + raise cv.Invalid(f"Invalid pin number: {value} (must be 0-27)") + if is_input: + # All ESP32 pins support input mode + pass + return value diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 5b65ecdabf..43629bec51 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -64,6 +64,7 @@ RMT_CHANNELS = { esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3], esp32.const.VARIANT_ESP32C3: [0, 1], esp32.const.VARIANT_ESP32C6: [0, 1], + esp32.const.VARIANT_ESP32H2: [0, 1], } diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 5225a227ec..e431997276 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -32,6 +32,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S3, VARIANT_ESP32C2, VARIANT_ESP32C6, + VARIANT_ESP32H2, ) from esphome.components.libretiny import get_libretiny_component, get_libretiny_family from esphome.components.libretiny.const import ( @@ -86,6 +87,7 @@ UART_SELECTION_ESP32 = { VARIANT_ESP32C3: [UART0, UART1, USB_SERIAL_JTAG], VARIANT_ESP32C2: [UART0, UART1], VARIANT_ESP32C6: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG], + VARIANT_ESP32H2: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG], } UART_SELECTION_ESP8266 = [UART0, UART0_SWAP, UART1] diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index df4662024f..d1f3149d84 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -121,7 +121,7 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { if ( #if defined(USE_ESP32_VARIANT_ESP32S2) uart_ == UART_SELECTION_USB_CDC -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) uart_ == UART_SELECTION_USB_SERIAL_JTAG #elif defined(USE_ESP32_VARIANT_ESP32S3) uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG @@ -218,21 +218,24 @@ void Logger::pre_setup() { uart_num_ = UART_NUM_1; break; #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2) case UART_SELECTION_UART2: uart_num_ = UART_NUM_2; break; -#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 +#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 && + // !USE_ESP32_VARIANT_ESP32H2 #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) case UART_SELECTION_USB_CDC: uart_num_ = -1; break; #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) case UART_SELECTION_USB_SERIAL_JTAG: uart_num_ = -1; break; -#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 +#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 || + // USE_ESP32_VARIANT_ESP32H2 } if (uart_num_ >= 0) { uart_config_t uart_config{}; @@ -331,9 +334,10 @@ const char *const LOG_LEVELS[] = {"NONE", "ERROR", "WARN", "INFO", "CONFIG", "DE const char *const UART_SELECTIONS[] = { "UART0", "UART1", #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2) "UART2", -#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 +#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARINT_ESP32C6 && !USE_ESP32_VARIANT_ESP32S2 && + // !USE_ESP32_VARIANT_ESP32S3 && !USE_ESP32_VARIANT_ESP32H2 #if defined(USE_ESP_IDF) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) "USB_CDC", diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index 4a7a43c7c2..de272934bf 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -41,16 +41,19 @@ enum UARTSelection { UART_SELECTION_UART1, #if defined(USE_ESP32) #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2) UART_SELECTION_UART2, -#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 +#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32C6 && !USE_ESP32_VARIANT_ESP32S2 && + // !USE_ESP32_VARIANT_ESP32S3 && !USE_ESP32_VARIANT_ESP32H2 #ifdef USE_ESP_IDF #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) UART_SELECTION_USB_CDC, #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) UART_SELECTION_USB_SERIAL_JTAG, -#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 +#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 || + // USE_ESP32_VARIANT_ESP32H2 #endif // USE_ESP_IDF #endif // USE_ESP32 #ifdef USE_ESP8266 diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 1baffcbfcc..86ce53b804 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -34,12 +34,14 @@ from esphome.const import ( CONF_EAP, ) from esphome.core import CORE, HexInt, coroutine_with_priority -from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const from esphome.components.network import IPAddress from . import wpa2_eap AUTO_LOAD = ["network"] +NO_WIFI_VARIANTS = [const.VARIANT_ESP32H2] + wifi_ns = cg.esphome_ns.namespace("wifi") EAPAuth = wifi_ns.struct("EAPAuth") ManualIP = wifi_ns.struct("ManualIP") @@ -148,6 +150,13 @@ WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend( ) +def validate_variant(_): + if CORE.is_esp32: + variant = get_esp32_variant() + if variant in NO_WIFI_VARIANTS: + raise cv.Invalid(f"{variant} does not support WiFi") + + def final_validate(config): has_sta = bool(config.get(CONF_NETWORKS, True)) has_ap = CONF_AP in config @@ -199,6 +208,7 @@ FINAL_VALIDATE_SCHEMA = cv.All( extra=cv.ALLOW_EXTRA, ), final_validate, + validate_variant, ) From ee4ccf2762a565ecc8f8d58646127626b7978601 Mon Sep 17 00:00:00 2001 From: Luke Ansell <33194087+lukeansell@users.noreply.github.com> Date: Sun, 8 Oct 2023 22:20:43 +0200 Subject: [PATCH 0573/2607] Increased debug message precision (#5496) --- esphome/components/ultrasonic/ultrasonic_sensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.cpp b/esphome/components/ultrasonic/ultrasonic_sensor.cpp index 9f47f9f6b9..dc828aed6b 100644 --- a/esphome/components/ultrasonic/ultrasonic_sensor.cpp +++ b/esphome/components/ultrasonic/ultrasonic_sensor.cpp @@ -37,7 +37,7 @@ void UltrasonicSensorComponent::update() { this->publish_state(NAN); } else { float result = UltrasonicSensorComponent::us_to_m(pulse_end - pulse_start); - ESP_LOGD(TAG, "'%s' - Got distance: %.2f m", this->name_.c_str(), result); + ESP_LOGD(TAG, "'%s' - Got distance: %.3f m", this->name_.c_str(), result); this->publish_state(result); } } From 7e7c83b3ca87a7eda8d76b20b994abb8170aa252 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Sun, 8 Oct 2023 22:49:55 +0200 Subject: [PATCH 0574/2607] Support for Haier IR protocol added (#5403) --- esphome/components/remote_base/__init__.py | 34 ++++++++ .../components/remote_base/haier_protocol.cpp | 84 +++++++++++++++++++ .../components/remote_base/haier_protocol.h | 40 +++++++++ tests/test1.yaml | 5 ++ 4 files changed, 163 insertions(+) create mode 100644 esphome/components/remote_base/haier_protocol.cpp create mode 100644 esphome/components/remote_base/haier_protocol.h diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index e2d96c9472..5a703066a1 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1558,3 +1558,37 @@ async def aeha_action(var, config, args): config[CONF_DATA], args, cg.std_vector.template(cg.uint8) ) cg.add(var.set_data(template_)) + + +# Haier +HaierData, HaierBinarySensor, HaierTrigger, HaierAction, HaierDumper = declare_protocol( + "Haier" +) +HaierAction = ns.class_("HaierAction", RemoteTransmitterActionBase) +HAIER_SCHEMA = cv.Schema( + { + cv.Required(CONF_CODE): cv.All([cv.hex_uint8_t], cv.Length(min=13, max=13)), + } +) + + +@register_binary_sensor("haier", HaierBinarySensor, HAIER_SCHEMA) +def haier_binary_sensor(var, config): + cg.add(var.set_code(config[CONF_CODE])) + + +@register_trigger("haier", HaierTrigger, HaierData) +def haier_trigger(var, config): + pass + + +@register_dumper("haier", HaierDumper) +def haier_dumper(var, config): + pass + + +@register_action("haier", HaierAction, HAIER_SCHEMA) +async def haier_action(var, config, args): + vec_ = cg.std_vector.template(cg.uint8) + template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_) + cg.add(var.set_code(template_)) diff --git a/esphome/components/remote_base/haier_protocol.cpp b/esphome/components/remote_base/haier_protocol.cpp new file mode 100644 index 0000000000..ec5cb5775c --- /dev/null +++ b/esphome/components/remote_base/haier_protocol.cpp @@ -0,0 +1,84 @@ +#include "haier_protocol.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace remote_base { + +static const char *const TAG = "remote.haier"; + +constexpr uint32_t HEADER_LOW_US = 3100; +constexpr uint32_t HEADER_HIGH_US = 4400; +constexpr uint32_t BIT_MARK_US = 540; +constexpr uint32_t BIT_ONE_SPACE_US = 1650; +constexpr uint32_t BIT_ZERO_SPACE_US = 580; +constexpr unsigned int HAIER_IR_PACKET_BIT_SIZE = 112; + +void HaierProtocol::encode_byte_(RemoteTransmitData *dst, uint8_t item) { + for (uint8_t mask = 1 << 7; mask != 0; mask >>= 1) { + if (item & mask) { + dst->space(BIT_ONE_SPACE_US); + } else { + dst->space(BIT_ZERO_SPACE_US); + } + dst->mark(BIT_MARK_US); + } +} + +void HaierProtocol::encode(RemoteTransmitData *dst, const HaierData &data) { + dst->set_carrier_frequency(38000); + dst->reserve(5 + ((data.data.size() + 1) * 2)); + dst->mark(HEADER_LOW_US); + dst->space(HEADER_LOW_US); + dst->mark(HEADER_LOW_US); + dst->space(HEADER_HIGH_US); + dst->mark(BIT_MARK_US); + uint8_t checksum = 0; + for (uint8_t item : data.data) { + this->encode_byte_(dst, item); + checksum += item; + } + this->encode_byte_(dst, checksum); +} + +optional HaierProtocol::decode(RemoteReceiveData src) { + if (!src.expect_item(HEADER_LOW_US, HEADER_LOW_US) || !src.expect_item(HEADER_LOW_US, HEADER_HIGH_US)) { + return {}; + } + if (!src.expect_mark(BIT_MARK_US)) { + return {}; + } + size_t size = src.size() - src.get_index() - 1; + if (size < HAIER_IR_PACKET_BIT_SIZE * 2) + return {}; + size = HAIER_IR_PACKET_BIT_SIZE * 2; + uint8_t checksum = 0; + HaierData out; + while (size > 0) { + uint8_t data = 0; + for (uint8_t mask = 0x80; mask != 0; mask >>= 1) { + if (src.expect_space(BIT_ONE_SPACE_US)) { + data |= mask; + } else if (!src.expect_space(BIT_ZERO_SPACE_US)) { + return {}; + } + if (!src.expect_mark(BIT_MARK_US)) { + return {}; + } + size -= 2; + } + if (size > 0) { + checksum += data; + out.data.push_back(data); + } else if (checksum != data) { + return {}; + } + } + return out; +} + +void HaierProtocol::dump(const HaierData &data) { + ESP_LOGI(TAG, "Received Haier: %s", format_hex_pretty(data.data).c_str()); +} + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/remote_base/haier_protocol.h b/esphome/components/remote_base/haier_protocol.h new file mode 100644 index 0000000000..6a1c4bea72 --- /dev/null +++ b/esphome/components/remote_base/haier_protocol.h @@ -0,0 +1,40 @@ +#pragma once + +#include "remote_base.h" +#include + +namespace esphome { +namespace remote_base { + +struct HaierData { + std::vector data; + + bool operator==(const HaierData &rhs) const { return data == rhs.data; } +}; + +class HaierProtocol : public RemoteProtocol { + public: + void encode(RemoteTransmitData *dst, const HaierData &data) override; + optional decode(RemoteReceiveData src) override; + void dump(const HaierData &data) override; + + protected: + void encode_byte_(RemoteTransmitData *dst, uint8_t item); +}; + +DECLARE_REMOTE_PROTOCOL(Haier) + +template class HaierAction : public RemoteTransmitterActionBase { + public: + TEMPLATABLE_VALUE(std::vector, data) + + void set_code(const std::vector &code) { data_ = code; } + void encode(RemoteTransmitData *dst, Ts... x) override { + HaierData data{}; + data.data = this->data_.value(x...); + HaierProtocol().encode(dst, data); + } +}; + +} // namespace remote_base +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index ea69343dbf..5110500e26 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2622,6 +2622,11 @@ switch: 0x00, 0xFF, ] + - platform: template + name: Haier + turn_on_action: + remote_transmitter.transmit_haier: + code: [0xA6, 0xDA, 0x00, 0x00, 0x40, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05] - platform: template name: Living Room Lights id: livingroom_lights From aba3cd557abe4fd48531a7dc0c90aa3dfcb75722 Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Sun, 8 Oct 2023 23:01:26 +0200 Subject: [PATCH 0575/2607] add USE_SPI define (#5500) --- esphome/components/spi/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index dc9d560874..00b23747d4 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -272,6 +272,7 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(1.0) async def to_code(configs): + cg.add_define("USE_SPI") cg.add_global(spi_ns.using) for spi in configs: var = cg.new_Pvariable(spi[CONF_ID]) From af62c2d9cf20c5d4fc68402e62ebf20884aa8519 Mon Sep 17 00:00:00 2001 From: Adam Goode Date: Sun, 8 Oct 2023 17:26:58 -0400 Subject: [PATCH 0576/2607] Implement sensor component for MMC5983 (#5361) --- CODEOWNERS | 1 + esphome/components/hmc5883l/sensor.py | 6 +- esphome/components/mmc5603/sensor.py | 6 +- esphome/components/mmc5983/__init__.py | 1 + esphome/components/mmc5983/mmc5983.cpp | 141 +++++++++++++++++++++++++ esphome/components/mmc5983/mmc5983.h | 28 +++++ esphome/components/mmc5983/sensor.py | 55 ++++++++++ esphome/components/qmc5883l/sensor.py | 6 +- esphome/const.py | 3 + tests/test1.yaml | 11 ++ 10 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 esphome/components/mmc5983/__init__.py create mode 100644 esphome/components/mmc5983/mmc5983.cpp create mode 100644 esphome/components/mmc5983/mmc5983.h create mode 100644 esphome/components/mmc5983/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index ce19f14c05..d7cf7269ab 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -186,6 +186,7 @@ esphome/components/mitsubishi/* @RubyBailey esphome/components/mlx90393/* @functionpointer esphome/components/mlx90614/* @jesserockz esphome/components/mmc5603/* @benhoff +esphome/components/mmc5983/* @agoode esphome/components/modbus_controller/* @martgras esphome/components/modbus_controller/binary_sensor/* @martgras esphome/components/modbus_controller/number/* @martgras diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py index 26e8e2b60c..7edd13965e 100644 --- a/esphome/components/hmc5883l/sensor.py +++ b/esphome/components/hmc5883l/sensor.py @@ -3,6 +3,9 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ADDRESS, + CONF_FIELD_STRENGTH_X, + CONF_FIELD_STRENGTH_Y, + CONF_FIELD_STRENGTH_Z, CONF_ID, CONF_OVERSAMPLING, CONF_RANGE, @@ -18,9 +21,6 @@ DEPENDENCIES = ["i2c"] hmc5883l_ns = cg.esphome_ns.namespace("hmc5883l") -CONF_FIELD_STRENGTH_X = "field_strength_x" -CONF_FIELD_STRENGTH_Y = "field_strength_y" -CONF_FIELD_STRENGTH_Z = "field_strength_z" CONF_HEADING = "heading" HMC5883LComponent = hmc5883l_ns.class_( diff --git a/esphome/components/mmc5603/sensor.py b/esphome/components/mmc5603/sensor.py index 348a0e7dcc..db4e5cbf26 100644 --- a/esphome/components/mmc5603/sensor.py +++ b/esphome/components/mmc5603/sensor.py @@ -3,6 +3,9 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ADDRESS, + CONF_FIELD_STRENGTH_X, + CONF_FIELD_STRENGTH_Y, + CONF_FIELD_STRENGTH_Z, CONF_ID, ICON_MAGNET, STATE_CLASS_MEASUREMENT, @@ -16,9 +19,6 @@ DEPENDENCIES = ["i2c"] mmc5603_ns = cg.esphome_ns.namespace("mmc5603") -CONF_FIELD_STRENGTH_X = "field_strength_x" -CONF_FIELD_STRENGTH_Y = "field_strength_y" -CONF_FIELD_STRENGTH_Z = "field_strength_z" CONF_HEADING = "heading" MMC5603Component = mmc5603_ns.class_( diff --git a/esphome/components/mmc5983/__init__.py b/esphome/components/mmc5983/__init__.py new file mode 100644 index 0000000000..c8db8c4300 --- /dev/null +++ b/esphome/components/mmc5983/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@agoode"] diff --git a/esphome/components/mmc5983/mmc5983.cpp b/esphome/components/mmc5983/mmc5983.cpp new file mode 100644 index 0000000000..5b045ae38b --- /dev/null +++ b/esphome/components/mmc5983/mmc5983.cpp @@ -0,0 +1,141 @@ +// See https://github.com/sparkfun/SparkFun_MMC5983MA_Magnetometer_Arduino_Library/tree/main +// for datasheets and an Arduino implementation. + +#include "mmc5983.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace mmc5983 { + +static const char *const TAG = "mmc5983"; + +namespace { +constexpr uint8_t IC0_ADDR = 0x09; +constexpr uint8_t IC1_ADDR = 0x0a; +constexpr uint8_t IC2_ADDR = 0x0b; +constexpr uint8_t IC3_ADDR = 0x0c; +constexpr uint8_t PRODUCT_ID_ADDR = 0x2f; + +float convert_data_to_millitesla(uint8_t data_17_10, uint8_t data_9_2, uint8_t data_1_0) { + int32_t counts = (data_17_10 << 10) | (data_9_2 << 2) | data_1_0; + counts -= 131072; // "Null Field Output" from datasheet. + + // Sensitivity is 16384 counts/gauss, which is 163840 counts/mT. + return counts / 163840.0f; +} +} // namespace + +void MMC5983Component::update() { + // Schedule a SET/RESET. This will recalibrate the sensor. + // We are supposed to be able to set this once, and have it automatically continue every reading, but + // this does not appear to work in continuous mode, even with En_prd_set turned on in Internal Control 2. + // Bit 5 = Auto_SR_en (automatic SET/RESET enable). + const uint8_t ic0_value = 0b10000; + i2c::ErrorCode err = this->write_register(IC0_ADDR, &ic0_value, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGW(TAG, "Writing Internal Control 0 failed with i2c error %d", err); + this->status_set_warning(); + } + + // Read out the data, 7 bytes starting from 0x00. + uint8_t data[7]; + err = this->read_register(0x00, data, sizeof(data)); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGW(TAG, "Reading data failed with i2c error %d", err); + this->status_set_warning(); + return; + } + + // Unpack the data and publish to sensors. + // Data is in this format: + // data[0]: Xout[17:10] + // data[1]: Xout[9:2] + // data[2]: Yout[17:10] + // data[3]: Yout[9:2] + // data[4]: Zout[17:10] + // data[5]: Zout[9:2] + // data[6]: { Xout[1], Xout[0], Yout[1], Yout[0], Zout[1], Zout[0], 0, 0 } + if (this->x_sensor_) { + this->x_sensor_->publish_state(convert_data_to_millitesla(data[0], data[1], (data[6] & 0b11000000) >> 6)); + } + if (this->y_sensor_) { + this->y_sensor_->publish_state(convert_data_to_millitesla(data[2], data[3], (data[6] & 0b00110000) >> 4)); + } + if (this->z_sensor_) { + this->z_sensor_->publish_state(convert_data_to_millitesla(data[4], data[5], (data[6] & 0b00001100) >> 2)); + } +} + +void MMC5983Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up MMC5983..."); + + // Verify product id. + const uint8_t mmc5983_product_id = 0x30; + uint8_t id; + i2c::ErrorCode err = this->read_register(PRODUCT_ID_ADDR, &id, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Reading product id failed with i2c error %d", err); + this->mark_failed(); + return; + } + if (id != mmc5983_product_id) { + ESP_LOGE(TAG, "Product id 0x%02x does not match expected value 0x%02x", id, mmc5983_product_id); + this->mark_failed(); + return; + } + + // Initialize Internal Control registers to 0. + // Internal Control 0. + const uint8_t zero = 0; + err = this->write_register(IC0_ADDR, &zero, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Initializing Internal Control 0 failed with i2c error %d", err); + this->mark_failed(); + return; + } + // Internal Control 1. + err = this->write_register(IC1_ADDR, &zero, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Initializing Internal Control 1 failed with i2c error %d", err); + this->mark_failed(); + return; + } + // Internal Control 2. + err = this->write_register(IC2_ADDR, &zero, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Initializing Internal Control 2 failed with i2c error %d", err); + this->mark_failed(); + return; + } + // Internal Control 3. + err = this->write_register(IC3_ADDR, &zero, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Initializing Internal Control 3 failed with i2c error %d", err); + this->mark_failed(); + return; + } + + // Enable continuous mode at 100 Hz, using Internal Control 2. + // Bit 3 = Cmm_en (continuous mode enable). + // Bit [2:0] = Cm_freq. 0b101 = 100 Hz, the fastest reading speed at Bandwidth=100 Hz. + const uint8_t ic2_value = 0b00001101; + err = this->write_register(IC2_ADDR, &ic2_value, 1); + if (err != i2c::ErrorCode::ERROR_OK) { + ESP_LOGE(TAG, "Writing Internal Control 2 failed with i2c error %d", err); + this->mark_failed(); + return; + } +} + +void MMC5983Component::dump_config() { + ESP_LOGD(TAG, "MMC5983:"); + LOG_I2C_DEVICE(this); + LOG_SENSOR(" ", "X", this->x_sensor_); + LOG_SENSOR(" ", "Y", this->y_sensor_); + LOG_SENSOR(" ", "Z", this->z_sensor_); +} + +float MMC5983Component::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace mmc5983 +} // namespace esphome diff --git a/esphome/components/mmc5983/mmc5983.h b/esphome/components/mmc5983/mmc5983.h new file mode 100644 index 0000000000..d425418904 --- /dev/null +++ b/esphome/components/mmc5983/mmc5983.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace mmc5983 { + +class MMC5983Component : public PollingComponent, public i2c::I2CDevice { + public: + void update() override; + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + + void set_x_sensor(sensor::Sensor *x_sensor) { x_sensor_ = x_sensor; } + void set_y_sensor(sensor::Sensor *y_sensor) { y_sensor_ = y_sensor; } + void set_z_sensor(sensor::Sensor *z_sensor) { z_sensor_ = z_sensor; } + + protected: + sensor::Sensor *x_sensor_{nullptr}; + sensor::Sensor *y_sensor_{nullptr}; + sensor::Sensor *z_sensor_{nullptr}; +}; + +} // namespace mmc5983 +} // namespace esphome diff --git a/esphome/components/mmc5983/sensor.py b/esphome/components/mmc5983/sensor.py new file mode 100644 index 0000000000..e3f4209cf9 --- /dev/null +++ b/esphome/components/mmc5983/sensor.py @@ -0,0 +1,55 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_FIELD_STRENGTH_X, + CONF_FIELD_STRENGTH_Y, + CONF_FIELD_STRENGTH_Z, + CONF_ID, + ICON_MAGNET, + STATE_CLASS_MEASUREMENT, + UNIT_MICROTESLA, +) + +DEPENDENCIES = ["i2c"] + +mmc5983_ns = cg.esphome_ns.namespace("mmc5983") +MMC5983Component = mmc5983_ns.class_( + "MMC5983Component", cg.PollingComponent, i2c.I2CDevice +) + +field_strength_schema = sensor.sensor_schema( + unit_of_measurement=UNIT_MICROTESLA, + icon=ICON_MAGNET, + accuracy_decimals=4, + state_class=STATE_CLASS_MEASUREMENT, +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MMC5983Component), + cv.Optional(CONF_FIELD_STRENGTH_X): field_strength_schema, + cv.Optional(CONF_FIELD_STRENGTH_Y): field_strength_schema, + cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema, + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x30)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if x_config := config.get(CONF_FIELD_STRENGTH_X): + sens = await sensor.new_sensor(x_config) + cg.add(var.set_x_sensor(sens)) + if y_config := config.get(CONF_FIELD_STRENGTH_Y): + sens = await sensor.new_sensor(y_config) + cg.add(var.set_y_sensor(sens)) + if z_config := config.get(CONF_FIELD_STRENGTH_Z): + sens = await sensor.new_sensor(z_config) + cg.add(var.set_z_sensor(sens)) diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py index cce4d93843..b819fecfe1 100644 --- a/esphome/components/qmc5883l/sensor.py +++ b/esphome/components/qmc5883l/sensor.py @@ -3,6 +3,9 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ADDRESS, + CONF_FIELD_STRENGTH_X, + CONF_FIELD_STRENGTH_Y, + CONF_FIELD_STRENGTH_Z, CONF_ID, CONF_OVERSAMPLING, CONF_RANGE, @@ -18,9 +21,6 @@ DEPENDENCIES = ["i2c"] qmc5883l_ns = cg.esphome_ns.namespace("qmc5883l") -CONF_FIELD_STRENGTH_X = "field_strength_x" -CONF_FIELD_STRENGTH_Y = "field_strength_y" -CONF_FIELD_STRENGTH_Z = "field_strength_z" CONF_HEADING = "heading" QMC5883LComponent = qmc5883l_ns.class_( diff --git a/esphome/const.py b/esphome/const.py index 75ed874cfd..01555c35ec 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -265,6 +265,9 @@ CONF_FAN_ONLY_MODE = "fan_only_mode" CONF_FAN_WITH_COOLING = "fan_with_cooling" CONF_FAN_WITH_HEATING = "fan_with_heating" CONF_FAST_CONNECT = "fast_connect" +CONF_FIELD_STRENGTH_X = "field_strength_x" +CONF_FIELD_STRENGTH_Y = "field_strength_y" +CONF_FIELD_STRENGTH_Z = "field_strength_z" CONF_FILE = "file" CONF_FILES = "files" CONF_FILTER = "filter" diff --git a/tests/test1.yaml b/tests/test1.yaml index 5110500e26..c504012481 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1482,6 +1482,17 @@ sensor: name: "Loop Time" psram: name: "PSRAM Free" + - platform: mmc5983 + i2c_id: i2c_bus + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z esp32_touch: setup_mode: false From e09c217fdeb533015d55b22bbb9b4065581f97e3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:13:12 +1300 Subject: [PATCH 0577/2607] Bump docker dependencies (#5501) --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index a0bb007641..99f15d64b2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,8 +26,8 @@ RUN \ python3-venv=3.9.2-3 \ iputils-ping=3:20210202-1 \ git=1:2.30.2-1+deb11u2 \ - curl=7.74.0-1.3+deb11u7 \ - openssh-client=1:8.4p1-5+deb11u1 \ + curl=7.74.0-1.3+deb11u9 \ + openssh-client=1:8.4p1-5+deb11u2 \ python3-cffi=1.14.5-1 \ libcairo2=1.16.0-5 \ patch=2.7.6-7; \ From 412a866de8ccdeb19cfe38d8056fc41ac16afd04 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Mon, 9 Oct 2023 03:47:52 +0300 Subject: [PATCH 0578/2607] Move to Pillow 10.x (#5489) Co-authored-by: Franck Nijhof Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/animation/__init__.py | 4 ++-- esphome/components/font/__init__.py | 13 ++++--------- esphome/components/ili9xxx/display.py | 5 +++-- esphome/components/image/__init__.py | 6 +++++- requirements_optional.txt | 2 +- tests/test2.yaml | 5 +++++ 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 52e14f0a43..9151d6e56d 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -151,7 +151,7 @@ async def to_code(config): pos = 0 for frameIndex in range(frames): image.seek(frameIndex) - frame = image.convert("LA", dither=Image.NONE) + frame = image.convert("LA", dither=Image.Dither.NONE) if CONF_RESIZE in config: frame = frame.resize([width, height]) pixels = list(frame.getdata()) @@ -259,7 +259,7 @@ async def to_code(config): if transparent: alpha = image.split()[-1] has_alpha = alpha.getextrema()[0] < 0xFF - frame = image.convert("1", dither=Image.NONE) + frame = image.convert("1", dither=Image.Dither.NONE) if CONF_RESIZE in config: frame = frame.resize([width, height]) if transparent: diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index e6244d8d44..2bd6beeaeb 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -67,18 +67,13 @@ def validate_pillow_installed(value): except ImportError as err: raise cv.Invalid( "Please install the pillow python package to use this feature. " - '(pip install pillow">4.0.0,<10.0.0")' + '(pip install "pillow==10.0.1")' ) from err - if version.parse(PIL.__version__) < version.parse("4.0.0"): + if version.parse(PIL.__version__) != version.parse("10.0.1"): raise cv.Invalid( - "Please update your pillow installation to at least 4.0.x. " - '(pip install pillow">4.0.0,<10.0.0")' - ) - if version.parse(PIL.__version__) >= version.parse("10.0.0"): - raise cv.Invalid( - "Please downgrade your pillow installation to below 10.0.0. " - '(pip install pillow">4.0.0,<10.0.0")' + "Please update your pillow installation to 10.0.1. " + '(pip install "pillow==10.0.1")' ) return value diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 1a18978d94..241f56e018 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import core, pins -from esphome.components import display, spi +from esphome.components import display, spi, font from esphome.core import CORE, HexInt from esphome.const import ( CONF_COLOR_PALETTE, @@ -84,6 +84,7 @@ def _validate(config): CONFIG_SCHEMA = cv.All( + font.validate_pillow_installed, display.FULL_DISPLAY_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(ili9XXXSPI), @@ -162,7 +163,7 @@ async def to_code(config): x = x + i.width # reduce the colors on combined image to 256. - converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256) + converted = ref_image.convert("P", palette=Image.Palette.ADAPTIVE, colors=256) # if you want to verify how the images look use # ref_image.save("ref_in.png") # converted.save("ref_out.png") diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index aa402ee329..1b7c654b0b 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -255,7 +255,11 @@ async def to_code(config): transparent = config[CONF_USE_TRANSPARENCY] - dither = Image.NONE if config[CONF_DITHER] == "NONE" else Image.FLOYDSTEINBERG + dither = ( + Image.Dither.NONE + if config[CONF_DITHER] == "NONE" + else Image.Dither.FLOYDSTEINBERG + ) if config[CONF_TYPE] == "GRAYSCALE": image = image.convert("LA", dither=dither) pixels = list(image.getdata()) diff --git a/requirements_optional.txt b/requirements_optional.txt index 8bbf0a6809..236f5e3f13 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,3 +1,3 @@ -pillow>4.0.0,<10.0.0 +pillow==10.0.1 cairosvg>=2.2.0 cryptography>=2.0.0,<4 diff --git a/tests/test2.yaml b/tests/test2.yaml index fe577c2188..fe1ad91f8d 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -760,6 +760,11 @@ image: file: mdi:alert-outline type: BINARY +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + graph: - id: my_graph sensor: ha_hello_world_temperature From c65d78f568fcb9bdd7bea001e05601df941714ec Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Mon, 9 Oct 2023 06:37:48 +0300 Subject: [PATCH 0579/2607] [Sprinkler] Initialize timers early to avoid crash (#5499) --- esphome/components/sprinkler/__init__.py | 16 +++++----------- esphome/components/sprinkler/sprinkler.cpp | 9 +++++++-- esphome/components/sprinkler/sprinkler.h | 4 ++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/esphome/components/sprinkler/__init__.py b/esphome/components/sprinkler/__init__.py index e1d855778a..02c80ad5a0 100644 --- a/esphome/components/sprinkler/__init__.py +++ b/esphome/components/sprinkler/__init__.py @@ -571,18 +571,12 @@ async def sprinkler_simple_action_to_code(config, action_id, template_arg, args) async def to_code(config): for sprinkler_controller in config: - var = cg.new_Pvariable(sprinkler_controller[CONF_ID]) - - if CONF_NAME in sprinkler_controller: - cg.add(var.set_name(sprinkler_controller[CONF_NAME])) + if len(sprinkler_controller[CONF_VALVES]) > 1: + name = sprinkler_controller[CONF_MAIN_SWITCH][CONF_NAME] else: - if len(sprinkler_controller[CONF_VALVES]) > 1: - name = sprinkler_controller[CONF_MAIN_SWITCH][CONF_NAME] - else: - name = sprinkler_controller[CONF_VALVES][0][CONF_VALVE_SWITCH][ - CONF_NAME - ] - cg.add(var.set_name(name)) + name = sprinkler_controller[CONF_VALVES][0][CONF_VALVE_SWITCH][CONF_NAME] + name = sprinkler_controller.get(CONF_NAME, name) + var = cg.new_Pvariable(sprinkler_controller[CONF_ID], name) await cg.register_component(var, sprinkler_controller) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 8afafcb5ce..6900c9461b 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -386,12 +386,17 @@ SprinklerValveOperator *SprinklerValveRunRequest::valve_operator() { return this SprinklerValveRunRequestOrigin SprinklerValveRunRequest::request_is_from() { return this->origin_; } -void Sprinkler::setup() { +Sprinkler::Sprinkler() {} +Sprinkler::Sprinkler(const std::string &name) { + // The `name` is needed to set timers up, hence non-default constructor + // replaces `set_name()` method previously existed + this->name_ = name; this->timer_.push_back({this->name_ + "sm", false, 0, 0, std::bind(&Sprinkler::sm_timer_callback_, this)}); this->timer_.push_back({this->name_ + "vs", false, 0, 0, std::bind(&Sprinkler::valve_selection_callback_, this)}); - this->all_valves_off_(true); } +void Sprinkler::setup() { this->all_valves_off_(true); } + void Sprinkler::loop() { for (auto &p : this->pump_) { p.loop(); diff --git a/esphome/components/sprinkler/sprinkler.h b/esphome/components/sprinkler/sprinkler.h index ae7554d3af..5311ae4c05 100644 --- a/esphome/components/sprinkler/sprinkler.h +++ b/esphome/components/sprinkler/sprinkler.h @@ -204,12 +204,12 @@ class SprinklerValveRunRequest { class Sprinkler : public Component { public: + Sprinkler(); + Sprinkler(const std::string &name); void setup() override; void loop() override; void dump_config() override; - void set_name(const std::string &name) { this->name_ = name; } - /// add a valve to the controller void add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControllerSwitch *enable_sw = nullptr); From be7e167c638d301b6c6f244fb463e94fc95f736a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:41:28 +1300 Subject: [PATCH 0580/2607] Deep sleep is only available on esp32 and esp8266 (#5507) --- esphome/components/deep_sleep/__init__.py | 61 +++++++++++++---------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index bb7084282c..fd7ef6fcce 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_SLEEP_DURATION, CONF_TIME_ID, CONF_WAKEUP_PIN, + PLATFORM_ESP32, + PLATFORM_ESP8266, ) from esphome.components.esp32 import get_esp32_variant @@ -165,34 +167,39 @@ WAKEUP_CAUSES_SCHEMA = cv.Schema( } ) -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(DeepSleepComponent), - cv.Optional(CONF_RUN_DURATION): cv.Any( - cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA), - cv.positive_time_period_milliseconds, - ), - cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, - cv.Optional(CONF_WAKEUP_PIN): cv.All( - cv.only_on_esp32, pins.internal_gpio_input_pin_schema, validate_pin_number - ), - cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All( - cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True - ), - cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( - cv.only_on_esp32, - cv.Schema( - { - cv.Required(CONF_PINS): cv.ensure_list( - pins.internal_gpio_input_pin_schema, validate_pin_number - ), - cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True), - } +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(DeepSleepComponent), + cv.Optional(CONF_RUN_DURATION): cv.Any( + cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA), + cv.positive_time_period_milliseconds, ), - ), - cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean), - } -).extend(cv.COMPONENT_SCHEMA) + cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, + cv.Optional(CONF_WAKEUP_PIN): cv.All( + cv.only_on_esp32, + pins.internal_gpio_input_pin_schema, + validate_pin_number, + ), + cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All( + cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True + ), + cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( + cv.only_on_esp32, + cv.Schema( + { + cv.Required(CONF_PINS): cv.ensure_list( + pins.internal_gpio_input_pin_schema, validate_pin_number + ), + cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True), + } + ), + ), + cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean), + } + ).extend(cv.COMPONENT_SCHEMA), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]), +) async def to_code(config): From 46be886ca69c59d074dcbfdbaa07f64b5b7311d6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:54:15 +1300 Subject: [PATCH 0581/2607] Use platform consts (#5508) --- esphome/components/async_tcp/__init__.py | 8 +++++++- esphome/components/captive_portal/__init__.py | 10 ++++++++-- esphome/components/esp32/__init__.py | 3 ++- esphome/components/esp8266/__init__.py | 3 ++- esphome/components/host/__init__.py | 3 ++- esphome/components/i2c/__init__.py | 5 ++++- .../components/internal_temperature/sensor.py | 4 +++- esphome/components/mqtt/__init__.py | 5 ++++- esphome/components/rp2040/__init__.py | 3 ++- esphome/components/spi/__init__.py | 19 +++++++++++-------- esphome/components/web_server/__init__.py | 6 +++++- esphome/config_validation.py | 9 ++++++--- esphome/core/__init__.py | 18 ++++++++++++------ esphome/dashboard/dashboard.py | 12 ++++++------ 14 files changed, 74 insertions(+), 34 deletions(-) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index fa74f7103f..0a69943a25 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -2,13 +2,19 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE, coroutine_with_priority +from esphome.const import ( + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, +) CODEOWNERS = ["@OttoWinter"] CONFIG_SCHEMA = cv.All( cv.Schema({}), cv.only_with_arduino, - cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), ) diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index 6af741c6b3..a90ea14c4e 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -2,7 +2,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import web_server_base from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID -from esphome.const import CONF_ID +from esphome.const import ( + CONF_ID, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, +) from esphome.core import coroutine_with_priority, CORE AUTO_LOAD = ["web_server_base"] @@ -21,7 +27,7 @@ CONFIG_SCHEMA = cv.All( ), } ).extend(cv.COMPONENT_SCHEMA), - cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), ) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 0b067dc78f..cda02f80c2 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -25,6 +25,7 @@ from esphome.const import ( KEY_NAME, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_ESP32, TYPE_GIT, TYPE_LOCAL, __version__, @@ -62,7 +63,7 @@ AUTO_LOAD = ["preferences"] def set_core_data(config): CORE.data[KEY_ESP32] = {} - CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "esp32" + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP32 conf = config[CONF_FRAMEWORK] if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "esp-idf" diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 412c2d903f..5336842b9d 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_ESP8266, ) from esphome.core import CORE, coroutine_with_priority import esphome.config_validation as cv @@ -38,7 +39,7 @@ AUTO_LOAD = ["preferences"] def set_core_data(config): CORE.data[KEY_ESP8266] = {} - CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "esp8266" + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP8266 CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( config[CONF_FRAMEWORK][CONF_VERSION] diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 46f763d255..14d2597866 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -3,6 +3,7 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_HOST, ) from esphome.core import CORE import esphome.config_validation as cv @@ -20,7 +21,7 @@ AUTO_LOAD = ["network"] def set_core_data(config): CORE.data[KEY_HOST] = {} - CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "host" + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_HOST CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "host" CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version(1, 0, 0) return config diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index e38cfd23fa..676190b0e5 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -12,6 +12,9 @@ from esphome.const import ( CONF_SDA, CONF_ADDRESS, CONF_I2C_ID, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, ) from esphome.core import coroutine_with_priority, CORE @@ -60,7 +63,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SCAN, default=True): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), - cv.only_on(["esp32", "esp8266", "rp2040"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), ) diff --git a/esphome/components/internal_temperature/sensor.py b/esphome/components/internal_temperature/sensor.py index 8d462bd801..2daf816538 100644 --- a/esphome/components/internal_temperature/sensor.py +++ b/esphome/components/internal_temperature/sensor.py @@ -12,6 +12,8 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, KEY_CORE, KEY_FRAMEWORK_VERSION, + PLATFORM_ESP32, + PLATFORM_RP2040, ) from esphome.core import CORE @@ -49,7 +51,7 @@ CONFIG_SCHEMA = cv.All( state_class=STATE_CLASS_MEASUREMENT, entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ).extend(cv.polling_component_schema("60s")), - cv.only_on(["esp32", "rp2040"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040]), validate_config, ) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 10ae8ac40d..2d1a3dc5fd 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -43,6 +43,9 @@ from esphome.const import ( CONF_USE_ABBREVIATIONS, CONF_USERNAME, CONF_WILL_MESSAGE, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_BK72XX, ) from esphome.core import coroutine_with_priority, CORE from esphome.components.esp32 import add_idf_sdkconfig_option @@ -250,7 +253,7 @@ CONFIG_SCHEMA = cv.All( } ), validate_config, - cv.only_on(["esp32", "esp8266", "bk72xx"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX]), ) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 5d8608c44d..62f199b040 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_RP2040, ) from esphome.core import CORE, coroutine_with_priority, EsphomeError from esphome.helpers import mkdir_p, write_file, copy_file_if_changed @@ -30,7 +31,7 @@ AUTO_LOAD = [] def set_core_data(config): CORE.data[KEY_RP2040] = {} - CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "rp2040" + CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_RP2040 CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( config[CONF_FRAMEWORK][CONF_VERSION] diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 00b23747d4..d116641373 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -26,6 +26,9 @@ from esphome.const import ( KEY_TARGET_PLATFORM, KEY_VARIANT, CONF_DATA_RATE, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, ) from esphome.core import coroutine_with_priority, CORE @@ -102,9 +105,9 @@ def get_target_variant(): # The returned value is a list of lists of names def get_hw_interface_list(): target_platform = get_target_platform() - if target_platform == "esp8266": + if target_platform == PLATFORM_ESP8266: return [["spi", "hspi"]] - if target_platform == "esp32": + if target_platform == PLATFORM_ESP32: if get_target_variant() in [ VARIANT_ESP32C2, VARIANT_ESP32C3, @@ -113,7 +116,7 @@ def get_hw_interface_list(): ]: return [["spi", "spi2"]] return [["spi", "spi2"], ["spi3"]] - if target_platform == "rp2040": + if target_platform == PLATFORM_RP2040: return [["spi"], ["spi1"]] return [] @@ -150,17 +153,17 @@ def validate_hw_pins(spi, index=-1): sdi_pin_no = sdi_pin[CONF_NUMBER] target_platform = get_target_platform() - if target_platform == "esp8266": + if target_platform == PLATFORM_ESP8266: if clk_pin_no == 6: return sdo_pin_no in (-1, 8) and sdi_pin_no in (-1, 7) if clk_pin_no == 14: return sdo_pin_no in (-1, 13) and sdi_pin_no in (-1, 12) return False - if target_platform == "esp32": + if target_platform == PLATFORM_ESP32: return clk_pin_no >= 0 - if target_platform == "rp2040": + if target_platform == PLATFORM_RP2040: pin_set = ( list(filter(lambda s: clk_pin_no in s[CONF_CLK_PIN], RP_SPI_PINSETS))[0] if index == -1 @@ -236,7 +239,7 @@ def get_spi_interface(index): return ["SPI2_HOST", "SPI3_HOST"][index] # Arduino code follows platform = get_target_platform() - if platform == "rp2040": + if platform == PLATFORM_RP2040: return ["&SPI", "&SPI1"][index] if index == 0: return "&SPI" @@ -261,7 +264,7 @@ SPI_SCHEMA = cv.All( } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), - cv.only_on(["esp32", "esp8266", "rp2040"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), ) CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 966c978836..b8698438e2 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -18,6 +18,10 @@ from esphome.const import ( CONF_LOG, CONF_VERSION, CONF_LOCAL, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, ) from esphome.core import CORE, coroutine_with_priority @@ -90,7 +94,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_LOCAL): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), - cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), default_url, validate_local, validate_ota, diff --git a/esphome/config_validation.py b/esphome/config_validation.py index b3f24d9d17..46f3f6a7bd 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -51,6 +51,9 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, TYPE_GIT, TYPE_LOCAL, VALID_SUBSTITUTIONS_CHARACTERS, @@ -583,9 +586,9 @@ def only_with_framework(frameworks): return validator_ -only_on_esp32 = only_on("esp32") -only_on_esp8266 = only_on("esp8266") -only_on_rp2040 = only_on("rp2040") +only_on_esp32 = only_on(PLATFORM_ESP32) +only_on_esp8266 = only_on(PLATFORM_ESP8266) +only_on_rp2040 = only_on(PLATFORM_RP2040) only_with_arduino = only_with_framework("arduino") only_with_esp_idf = only_with_framework("esp-idf") diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 4c99aff011..52c58cb54a 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -15,6 +15,12 @@ from esphome.const import ( KEY_CORE, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, + PLATFORM_RP2040, + PLATFORM_HOST, ) from esphome.coroutine import FakeAwaitable as _FakeAwaitable from esphome.coroutine import FakeEventLoop as _FakeEventLoop @@ -598,23 +604,23 @@ class EsphomeCore: @property def is_esp8266(self): - return self.target_platform == "esp8266" + return self.target_platform == PLATFORM_ESP8266 @property def is_esp32(self): - return self.target_platform == "esp32" + return self.target_platform == PLATFORM_ESP32 @property def is_rp2040(self): - return self.target_platform == "rp2040" + return self.target_platform == PLATFORM_RP2040 @property def is_bk72xx(self): - return self.target_platform == "bk72xx" + return self.target_platform == PLATFORM_BK72XX @property def is_rtl87xx(self): - return self.target_platform == "rtl87xx" + return self.target_platform == PLATFORM_RTL87XX @property def is_libretiny(self): @@ -622,7 +628,7 @@ class EsphomeCore: @property def is_host(self): - return self.target_platform == "host" + return self.target_platform == PLATFORM_HOST @property def target_framework(self): diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 8049fb7f4c..ce8976cb0f 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -838,17 +838,17 @@ class BoardsRequestHandler(BaseHandler): from esphome.components.rtl87xx.boards import BOARDS as RTL87XX_BOARDS platform_to_boards = { - "esp32": ESP32_BOARDS, - "esp8266": ESP8266_BOARDS, - "rp2040": RP2040_BOARDS, - "bk72xx": BK72XX_BOARDS, - "rtl87xx": RTL87XX_BOARDS, + const.PLATFORM_ESP32: ESP32_BOARDS, + const.PLATFORM_ESP8266: ESP8266_BOARDS, + const.PLATFORM_RP2040: RP2040_BOARDS, + const.PLATFORM_BK72XX: BK72XX_BOARDS, + const.PLATFORM_RTL87XX: RTL87XX_BOARDS, } # filter all ESP32 variants by requested platform if platform.startswith("esp32"): boards = { k: v - for k, v in platform_to_boards["esp32"].items() + for k, v in platform_to_boards[const.PLATFORM_ESP32].items() if v[const.KEY_VARIANT] == platform.upper() } else: From 6b96089f024c44716b594dfe03007c634414df84 Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Tue, 10 Oct 2023 03:16:12 +0300 Subject: [PATCH 0582/2607] Fixed precision for Nextion sensor with float values (#5497) --- esphome/components/nextion/sensor/nextion_sensor.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/esphome/components/nextion/sensor/nextion_sensor.cpp b/esphome/components/nextion/sensor/nextion_sensor.cpp index 32bfccf9f8..566dd30acf 100644 --- a/esphome/components/nextion/sensor/nextion_sensor.cpp +++ b/esphome/components/nextion/sensor/nextion_sensor.cpp @@ -76,9 +76,15 @@ void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) { } } + float published_state = state; if (this->wave_chan_id_ == UINT8_MAX) { if (publish) { - this->publish_state(state); + if (this->precision_ > 0) { + double to_multiply = pow(10, -this->precision_); + published_state = (float) (state * to_multiply); + } + + this->publish_state(published_state); } else { this->raw_state = state; this->state = state; @@ -87,7 +93,7 @@ void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) { } this->update_component_settings(); - ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %lf", this->variable_name_.c_str(), state); + ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %lf", this->variable_name_.c_str(), published_state); } void NextionSensor::wave_update_() { From 511af5845ecb54c36c8b575013cbbd7e145fa3af Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:52:42 +1300 Subject: [PATCH 0583/2607] Remote wake word support for voice assistant (#5229) --- esphome/components/api/api.proto | 19 +- esphome/components/api/api_connection.cpp | 13 +- esphome/components/api/api_connection.h | 2 +- esphome/components/api/api_pb2.cpp | 274 +++++++----- esphome/components/api/api_pb2.h | 26 +- esphome/components/api/api_server.cpp | 20 +- esphome/components/api/api_server.h | 11 +- .../microphone/i2s_audio_microphone.cpp | 9 +- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 4 +- .../components/voice_assistant/__init__.py | 86 +++- .../voice_assistant/voice_assistant.cpp | 391 +++++++++++++++--- .../voice_assistant/voice_assistant.h | 97 ++++- tests/test4.yaml | 3 + 13 files changed, 744 insertions(+), 211 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 86685aa5e6..ec4a0f7cc9 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1413,6 +1413,18 @@ message SubscribeVoiceAssistantRequest { bool subscribe = 1; } +enum VoiceAssistantRequestFlag { + VOICE_ASSISTANT_REQUEST_NONE = 0; + VOICE_ASSISTANT_REQUEST_USE_VAD = 1; + VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2; +} + +message VoiceAssistantAudioSettings { + uint32 noise_suppression_level = 1; + uint32 auto_gain = 2; + float volume_multiplier = 3; +} + message VoiceAssistantRequest { option (id) = 90; option (source) = SOURCE_SERVER; @@ -1420,7 +1432,8 @@ message VoiceAssistantRequest { bool start = 1; string conversation_id = 2; - bool use_vad = 3; + uint32 flags = 3; + VoiceAssistantAudioSettings audio_settings = 4; } message VoiceAssistantResponse { @@ -1442,6 +1455,10 @@ enum VoiceAssistantEvent { VOICE_ASSISTANT_INTENT_END = 6; VOICE_ASSISTANT_TTS_START = 7; VOICE_ASSISTANT_TTS_END = 8; + VOICE_ASSISTANT_WAKE_WORD_START = 9; + VOICE_ASSISTANT_WAKE_WORD_END = 10; + VOICE_ASSISTANT_STT_VAD_START = 11; + VOICE_ASSISTANT_STT_VAD_END = 12; } message VoiceAssistantEventData { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index ceec53bb65..3172b71fa2 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -907,21 +907,22 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ #endif #ifdef USE_VOICE_ASSISTANT -bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) { +bool APIConnection::request_voice_assistant(const VoiceAssistantRequest &msg) { if (!this->voice_assistant_subscription_) return false; - VoiceAssistantRequest msg; - msg.start = start; - msg.conversation_id = conversation_id; - msg.use_vad = use_vad; + return this->send_voice_assistant_request(msg); } void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { if (voice_assistant::global_voice_assistant != nullptr) { + if (msg.error) { + voice_assistant::global_voice_assistant->failed_to_start(); + return; + } struct sockaddr_storage storage; socklen_t len = sizeof(storage); this->helper_->getpeername((struct sockaddr *) &storage, &len); - voice_assistant::global_voice_assistant->start(&storage, msg.port); + voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port); } }; void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index acc4578661..2a62c2faff 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { this->voice_assistant_subscription_ = msg.subscribe; } - bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad); + bool request_voice_assistant(const VoiceAssistantRequest &msg); void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 6149a970ee..d0711aba7b 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3,8 +3,6 @@ #include "api_pb2.h" #include "esphome/core/log.h" -#include - namespace esphome { namespace api { @@ -410,6 +408,20 @@ const char *proto_enum_to_string(enums::Bluet } #endif #ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::VoiceAssistantRequestFlag value) { + switch (value) { + case enums::VOICE_ASSISTANT_REQUEST_NONE: + return "VOICE_ASSISTANT_REQUEST_NONE"; + case enums::VOICE_ASSISTANT_REQUEST_USE_VAD: + return "VOICE_ASSISTANT_REQUEST_USE_VAD"; + case enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD: + return "VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef HAS_PROTO_MESSAGE_DUMP template<> const char *proto_enum_to_string(enums::VoiceAssistantEvent value) { switch (value) { case enums::VOICE_ASSISTANT_ERROR: @@ -430,6 +442,14 @@ template<> const char *proto_enum_to_string(enums::V return "VOICE_ASSISTANT_TTS_START"; case enums::VOICE_ASSISTANT_TTS_END: return "VOICE_ASSISTANT_TTS_END"; + case enums::VOICE_ASSISTANT_WAKE_WORD_START: + return "VOICE_ASSISTANT_WAKE_WORD_START"; + case enums::VOICE_ASSISTANT_WAKE_WORD_END: + return "VOICE_ASSISTANT_WAKE_WORD_END"; + case enums::VOICE_ASSISTANT_STT_VAD_START: + return "VOICE_ASSISTANT_STT_VAD_START"; + case enums::VOICE_ASSISTANT_STT_VAD_END: + return "VOICE_ASSISTANT_STT_VAD_END"; default: return "UNKNOWN"; } @@ -524,12 +544,12 @@ void HelloRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" api_version_major: "); - sprintf(buffer, "%" PRIu32, this->api_version_major); + sprintf(buffer, "%u", this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%" PRIu32, this->api_version_minor); + sprintf(buffer, "%u", this->api_version_minor); out.append(buffer); out.append("\n"); out.append("}"); @@ -574,12 +594,12 @@ void HelloResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("HelloResponse {\n"); out.append(" api_version_major: "); - sprintf(buffer, "%" PRIu32, this->api_version_major); + sprintf(buffer, "%u", this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%" PRIu32, this->api_version_minor); + sprintf(buffer, "%u", this->api_version_minor); out.append(buffer); out.append("\n"); @@ -785,17 +805,17 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" webserver_port: "); - sprintf(buffer, "%" PRIu32, this->webserver_port); + sprintf(buffer, "%u", this->webserver_port); out.append(buffer); out.append("\n"); out.append(" legacy_bluetooth_proxy_version: "); - sprintf(buffer, "%" PRIu32, this->legacy_bluetooth_proxy_version); + sprintf(buffer, "%u", this->legacy_bluetooth_proxy_version); out.append(buffer); out.append("\n"); out.append(" bluetooth_proxy_feature_flags: "); - sprintf(buffer, "%" PRIu32, this->bluetooth_proxy_feature_flags); + sprintf(buffer, "%u", this->bluetooth_proxy_feature_flags); out.append(buffer); out.append("\n"); @@ -808,7 +828,7 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" voice_assistant_version: "); - sprintf(buffer, "%" PRIu32, this->voice_assistant_version); + sprintf(buffer, "%u", this->voice_assistant_version); out.append(buffer); out.append("\n"); out.append("}"); @@ -900,7 +920,7 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -968,7 +988,7 @@ void BinarySensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BinarySensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1071,7 +1091,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1161,7 +1181,7 @@ void CoverStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1244,7 +1264,7 @@ void CoverCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1364,7 +1384,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1389,7 +1409,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_speed_count: "); - sprintf(buffer, "%" PRId32, this->supported_speed_count); + sprintf(buffer, "%d", this->supported_speed_count); out.append(buffer); out.append("\n"); @@ -1456,7 +1476,7 @@ void FanStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1477,7 +1497,7 @@ void FanStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%" PRId32, this->speed_level); + sprintf(buffer, "%d", this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1557,7 +1577,7 @@ void FanCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1598,7 +1618,7 @@ void FanCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%" PRId32, this->speed_level); + sprintf(buffer, "%d", this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1712,7 +1732,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -1866,7 +1886,7 @@ void LightStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2089,7 +2109,7 @@ void LightCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2187,7 +2207,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" transition_length: "); - sprintf(buffer, "%" PRIu32, this->transition_length); + sprintf(buffer, "%u", this->transition_length); out.append(buffer); out.append("\n"); @@ -2196,7 +2216,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" flash_length: "); - sprintf(buffer, "%" PRIu32, this->flash_length); + sprintf(buffer, "%u", this->flash_length); out.append(buffer); out.append("\n"); @@ -2304,7 +2324,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2325,7 +2345,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" accuracy_decimals: "); - sprintf(buffer, "%" PRId32, this->accuracy_decimals); + sprintf(buffer, "%d", this->accuracy_decimals); out.append(buffer); out.append("\n"); @@ -2389,7 +2409,7 @@ void SensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2478,7 +2498,7 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2541,7 +2561,7 @@ void SwitchStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2580,7 +2600,7 @@ void SwitchCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2654,7 +2674,7 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -2720,7 +2740,7 @@ void TextSensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("TextSensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3027,7 +3047,7 @@ void GetTimeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("GetTimeResponse {\n"); out.append(" epoch_seconds: "); - sprintf(buffer, "%" PRIu32, this->epoch_seconds); + sprintf(buffer, "%u", this->epoch_seconds); out.append(buffer); out.append("\n"); out.append("}"); @@ -3111,7 +3131,7 @@ void ListEntitiesServicesResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3205,7 +3225,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" legacy_int: "); - sprintf(buffer, "%" PRId32, this->legacy_int); + sprintf(buffer, "%d", this->legacy_int); out.append(buffer); out.append("\n"); @@ -3219,7 +3239,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" int_: "); - sprintf(buffer, "%" PRId32, this->int_); + sprintf(buffer, "%d", this->int_); out.append(buffer); out.append("\n"); @@ -3231,7 +3251,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { for (const auto &it : this->int_array) { out.append(" int_array: "); - sprintf(buffer, "%" PRId32, it); + sprintf(buffer, "%d", it); out.append(buffer); out.append("\n"); } @@ -3282,7 +3302,7 @@ void ExecuteServiceRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ExecuteServiceRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3358,7 +3378,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3424,7 +3444,7 @@ void CameraImageResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CameraImageResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3616,7 +3636,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3804,7 +3824,7 @@ void ClimateStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -3992,7 +4012,7 @@ void ClimateCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4175,7 +4195,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4262,7 +4282,7 @@ void NumberStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4300,7 +4320,7 @@ void NumberCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4382,7 +4402,7 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4454,7 +4474,7 @@ void SelectStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4497,7 +4517,7 @@ void SelectCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4591,7 +4611,7 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4662,7 +4682,7 @@ void LockStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4717,7 +4737,7 @@ void LockCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4804,7 +4824,7 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4850,7 +4870,7 @@ void ButtonCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ButtonCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); out.append("}"); @@ -4925,7 +4945,7 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -4994,7 +5014,7 @@ void MediaPlayerStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -5073,7 +5093,7 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -5122,7 +5142,7 @@ void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const __attribute__((unused)) char buffer[64]; out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); out.append(" flags: "); - sprintf(buffer, "%" PRIu32, this->flags); + sprintf(buffer, "%u", this->flags); out.append(buffer); out.append("\n"); out.append("}"); @@ -5169,7 +5189,7 @@ void BluetoothServiceData::dump_to(std::string &out) const { for (const auto &it : this->legacy_data) { out.append(" legacy_data: "); - sprintf(buffer, "%" PRIu32, it); + sprintf(buffer, "%u", it); out.append(buffer); out.append("\n"); } @@ -5249,7 +5269,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%" PRId32, this->rssi); + sprintf(buffer, "%d", this->rssi); out.append(buffer); out.append("\n"); @@ -5272,7 +5292,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { } out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); + sprintf(buffer, "%u", this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5322,12 +5342,12 @@ void BluetoothLERawAdvertisement::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%" PRId32, this->rssi); + sprintf(buffer, "%d", this->rssi); out.append(buffer); out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); + sprintf(buffer, "%u", this->address_type); out.append(buffer); out.append("\n"); @@ -5410,7 +5430,7 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); + sprintf(buffer, "%u", this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5458,12 +5478,12 @@ void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" mtu: "); - sprintf(buffer, "%" PRIu32, this->mtu); + sprintf(buffer, "%u", this->mtu); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); + sprintf(buffer, "%d", this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -5523,7 +5543,7 @@ void BluetoothGATTDescriptor::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5579,12 +5599,12 @@ void BluetoothGATTCharacteristic::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append(" properties: "); - sprintf(buffer, "%" PRIu32, this->properties); + sprintf(buffer, "%u", this->properties); out.append(buffer); out.append("\n"); @@ -5641,7 +5661,7 @@ void BluetoothGATTService::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -5748,7 +5768,7 @@ void BluetoothGATTReadRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5793,7 +5813,7 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -5847,7 +5867,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -5889,7 +5909,7 @@ void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5934,7 +5954,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -5977,7 +5997,7 @@ void BluetoothGATTNotifyRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -6026,7 +6046,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); @@ -6065,12 +6085,12 @@ void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BluetoothConnectionsFreeResponse {\n"); out.append(" free: "); - sprintf(buffer, "%" PRIu32, this->free); + sprintf(buffer, "%u", this->free); out.append(buffer); out.append("\n"); out.append(" limit: "); - sprintf(buffer, "%" PRIu32, this->limit); + sprintf(buffer, "%u", this->limit); out.append(buffer); out.append("\n"); out.append("}"); @@ -6109,12 +6129,12 @@ void BluetoothGATTErrorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); + sprintf(buffer, "%d", this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6148,7 +6168,7 @@ void BluetoothGATTWriteResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6182,7 +6202,7 @@ void BluetoothGATTNotifyResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); + sprintf(buffer, "%u", this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6225,7 +6245,7 @@ void BluetoothDevicePairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); + sprintf(buffer, "%d", this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6268,7 +6288,7 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); + sprintf(buffer, "%d", this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6317,7 +6337,7 @@ void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); + sprintf(buffer, "%d", this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6344,6 +6364,56 @@ void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantAudioSettings::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->noise_suppression_level = value.as_uint32(); + return true; + } + case 2: { + this->auto_gain = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantAudioSettings::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 3: { + this->volume_multiplier = value.as_float(); + return true; + } + default: + return false; + } +} +void VoiceAssistantAudioSettings::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint32(1, this->noise_suppression_level); + buffer.encode_uint32(2, this->auto_gain); + buffer.encode_float(3, this->volume_multiplier); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantAudioSettings::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAudioSettings {\n"); + out.append(" noise_suppression_level: "); + sprintf(buffer, "%u", this->noise_suppression_level); + out.append(buffer); + out.append("\n"); + + out.append(" auto_gain: "); + sprintf(buffer, "%u", this->auto_gain); + out.append(buffer); + out.append("\n"); + + out.append(" volume_multiplier: "); + sprintf(buffer, "%g", this->volume_multiplier); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -6351,7 +6421,7 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) return true; } case 3: { - this->use_vad = value.as_bool(); + this->flags = value.as_uint32(); return true; } default: @@ -6364,6 +6434,10 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite this->conversation_id = value.as_string(); return true; } + case 4: { + this->audio_settings = value.as_message(); + return true; + } default: return false; } @@ -6371,7 +6445,8 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); buffer.encode_string(2, this->conversation_id); - buffer.encode_bool(3, this->use_vad); + buffer.encode_uint32(3, this->flags); + buffer.encode_message(4, this->audio_settings); } #ifdef HAS_PROTO_MESSAGE_DUMP void VoiceAssistantRequest::dump_to(std::string &out) const { @@ -6385,8 +6460,13 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append("'").append(this->conversation_id).append("'"); out.append("\n"); - out.append(" use_vad: "); - out.append(YESNO(this->use_vad)); + out.append(" flags: "); + sprintf(buffer, "%u", this->flags); + out.append(buffer); + out.append("\n"); + + out.append(" audio_settings: "); + this->audio_settings.dump_to(out); out.append("\n"); out.append("}"); } @@ -6414,7 +6494,7 @@ void VoiceAssistantResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantResponse {\n"); out.append(" port: "); - sprintf(buffer, "%" PRIu32, this->port); + sprintf(buffer, "%u", this->port); out.append(buffer); out.append("\n"); @@ -6577,7 +6657,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -6602,7 +6682,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_features: "); - sprintf(buffer, "%" PRIu32, this->supported_features); + sprintf(buffer, "%u", this->supported_features); out.append(buffer); out.append("\n"); @@ -6645,7 +6725,7 @@ void AlarmControlPanelStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); @@ -6695,7 +6775,7 @@ void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); + sprintf(buffer, "%u", this->key); out.append(buffer); out.append("\n"); diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 627165953d..a4826f09d2 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -165,6 +165,11 @@ enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, }; +enum VoiceAssistantRequestFlag : uint32_t { + VOICE_ASSISTANT_REQUEST_NONE = 0, + VOICE_ASSISTANT_REQUEST_USE_VAD = 1, + VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2, +}; enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_ERROR = 0, VOICE_ASSISTANT_RUN_START = 1, @@ -175,6 +180,10 @@ enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_INTENT_END = 6, VOICE_ASSISTANT_TTS_START = 7, VOICE_ASSISTANT_TTS_END = 8, + VOICE_ASSISTANT_WAKE_WORD_START = 9, + VOICE_ASSISTANT_WAKE_WORD_END = 10, + VOICE_ASSISTANT_STT_VAD_START = 11, + VOICE_ASSISTANT_STT_VAD_END = 12, }; enum AlarmControlPanelState : uint32_t { ALARM_STATE_DISARMED = 0, @@ -1651,11 +1660,26 @@ class SubscribeVoiceAssistantRequest : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantAudioSettings : public ProtoMessage { + public: + uint32_t noise_suppression_level{0}; + uint32_t auto_gain{0}; + float volume_multiplier{0.0f}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class VoiceAssistantRequest : public ProtoMessage { public: bool start{false}; std::string conversation_id{}; - bool use_vad{false}; + uint32_t flags{0}; + VoiceAssistantAudioSettings audio_settings{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index f70d45ecd0..54266ff0f0 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -1,13 +1,13 @@ #include "api_server.h" +#include #include "api_connection.h" +#include "esphome/components/network/util.h" #include "esphome/core/application.h" #include "esphome/core/defines.h" +#include "esphome/core/hal.h" #include "esphome/core/log.h" #include "esphome/core/util.h" #include "esphome/core/version.h" -#include "esphome/core/hal.h" -#include "esphome/components/network/util.h" -#include #ifdef USE_LOGGER #include "esphome/components/logger/logger.h" @@ -323,16 +323,24 @@ void APIServer::on_shutdown() { } #ifdef USE_VOICE_ASSISTANT -bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) { +bool APIServer::start_voice_assistant(const std::string &conversation_id, uint32_t flags, + const api::VoiceAssistantAudioSettings &audio_settings) { + VoiceAssistantRequest msg; + msg.start = true; + msg.conversation_id = conversation_id; + msg.flags = flags; + msg.audio_settings = audio_settings; for (auto &c : this->clients_) { - if (c->request_voice_assistant(true, conversation_id, use_vad)) + if (c->request_voice_assistant(msg)) return true; } return false; } void APIServer::stop_voice_assistant() { + VoiceAssistantRequest msg; + msg.start = false; for (auto &c : this->clients_) { - if (c->request_voice_assistant(false, "", false)) + if (c->request_voice_assistant(msg)) return; } } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 9b40a5ef02..a4454d4b84 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -1,16 +1,16 @@ #pragma once +#include "api_noise_context.h" +#include "api_pb2.h" +#include "api_pb2_service.h" +#include "esphome/components/socket/socket.h" #include "esphome/core/component.h" #include "esphome/core/controller.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" -#include "esphome/components/socket/socket.h" -#include "api_pb2.h" -#include "api_pb2_service.h" #include "list_entities.h" #include "subscribe_state.h" #include "user_services.h" -#include "api_noise_context.h" #include @@ -81,7 +81,8 @@ class APIServer : public Component, public Controller { #endif #ifdef USE_VOICE_ASSISTANT - bool start_voice_assistant(const std::string &conversation_id, bool use_vad); + bool start_voice_assistant(const std::string &conversation_id, uint32_t flags, + const api::VoiceAssistantAudioSettings &audio_settings); void stop_voice_assistant(); #endif diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index cf0628d638..44c73eb8fd 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -66,8 +66,9 @@ void I2SAudioMicrophone::start_() { i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); i2s_adc_enable(this->parent_->get_port()); - } else { + } else #endif + { if (this->pdm_) config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM); @@ -77,9 +78,7 @@ void I2SAudioMicrophone::start_() { pin_config.data_in_num = this->din_pin_; i2s_set_pin(this->parent_->get_port(), &pin_config); -#if SOC_I2S_SUPPORTS_ADC } -#endif this->state_ = microphone::STATE_RUNNING; this->high_freq_.start(); } @@ -110,6 +109,10 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { this->status_set_warning(); return 0; } + if (bytes_read == 0) { + this->status_set_warning(); + return 0; + } this->status_clear_warning(); if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { return bytes_read; diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 43bc005136..a0934e3844 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -158,10 +158,10 @@ void I2SAudioSpeaker::watch_() { this->status_clear_warning(); break; case TaskEventType::STOPPED: - this->parent_->unlock(); this->state_ = speaker::STATE_STOPPED; vTaskDelete(this->player_task_handle_); this->player_task_handle_ = nullptr; + this->parent_->unlock(); break; case TaskEventType::WARNING: ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); @@ -177,9 +177,9 @@ void I2SAudioSpeaker::loop() { this->start_(); break; case speaker::STATE_RUNNING: + case speaker::STATE_STOPPING: this->watch_(); break; - case speaker::STATE_STOPPING: case speaker::STATE_STOPPED: break; } diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index 55d995be88..14176ad7cf 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -19,11 +19,18 @@ CODEOWNERS = ["@jesserockz"] CONF_SILENCE_DETECTION = "silence_detection" CONF_ON_LISTENING = "on_listening" CONF_ON_START = "on_start" +CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected" CONF_ON_STT_END = "on_stt_end" CONF_ON_TTS_START = "on_tts_start" CONF_ON_TTS_END = "on_tts_end" CONF_ON_END = "on_end" CONF_ON_ERROR = "on_error" +CONF_USE_WAKE_WORD = "use_wake_word" +CONF_VAD_THRESHOLD = "vad_threshold" + +CONF_NOISE_SUPPRESSION_LEVEL = "noise_suppression_level" +CONF_AUTO_GAIN = "auto_gain" +CONF_VOLUME_MULTIPLIER = "volume_multiplier" voice_assistant_ns = cg.esphome_ns.namespace("voice_assistant") @@ -42,23 +49,40 @@ IsRunningCondition = voice_assistant_ns.class_( "IsRunningCondition", automation.Condition, cg.Parented.template(VoiceAssistant) ) - -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(VoiceAssistant), - cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), - cv.Exclusive(CONF_SPEAKER, "output"): cv.use_id(speaker.Speaker), - cv.Exclusive(CONF_MEDIA_PLAYER, "output"): cv.use_id(media_player.MediaPlayer), - cv.Optional(CONF_SILENCE_DETECTION, default=True): cv.boolean, - cv.Optional(CONF_ON_LISTENING): automation.validate_automation(single=True), - cv.Optional(CONF_ON_START): automation.validate_automation(single=True), - cv.Optional(CONF_ON_STT_END): automation.validate_automation(single=True), - cv.Optional(CONF_ON_TTS_START): automation.validate_automation(single=True), - cv.Optional(CONF_ON_TTS_END): automation.validate_automation(single=True), - cv.Optional(CONF_ON_END): automation.validate_automation(single=True), - cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True), - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(VoiceAssistant), + cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), + cv.Exclusive(CONF_SPEAKER, "output"): cv.use_id(speaker.Speaker), + cv.Exclusive(CONF_MEDIA_PLAYER, "output"): cv.use_id( + media_player.MediaPlayer + ), + cv.Optional(CONF_USE_WAKE_WORD, default=False): cv.boolean, + cv.Optional(CONF_VAD_THRESHOLD): cv.All( + cv.requires_component("esp_adf"), cv.only_with_esp_idf, cv.uint8_t + ), + cv.Optional(CONF_NOISE_SUPPRESSION_LEVEL, default=0): cv.int_range(0, 4), + cv.Optional(CONF_AUTO_GAIN, default="0dBFS"): cv.All( + cv.float_with_unit("decibel full scale", "(dBFS|dbfs|DBFS)"), + cv.int_range(0, 31), + ), + cv.Optional(CONF_VOLUME_MULTIPLIER, default=1.0): cv.float_range( + min=0.0, min_included=False + ), + cv.Optional(CONF_ON_LISTENING): automation.validate_automation(single=True), + cv.Optional(CONF_ON_START): automation.validate_automation(single=True), + cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_STT_END): automation.validate_automation(single=True), + cv.Optional(CONF_ON_TTS_START): automation.validate_automation(single=True), + cv.Optional(CONF_ON_TTS_END): automation.validate_automation(single=True), + cv.Optional(CONF_ON_END): automation.validate_automation(single=True), + cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True), + } + ).extend(cv.COMPONENT_SCHEMA), +) async def to_code(config): @@ -76,7 +100,14 @@ async def to_code(config): mp = await cg.get_variable(config[CONF_MEDIA_PLAYER]) cg.add(var.set_media_player(mp)) - cg.add(var.set_silence_detection(config[CONF_SILENCE_DETECTION])) + cg.add(var.set_use_wake_word(config[CONF_USE_WAKE_WORD])) + + if (vad_threshold := config.get(CONF_VAD_THRESHOLD)) is not None: + cg.add(var.set_vad_threshold(vad_threshold)) + + cg.add(var.set_noise_suppression_level(config[CONF_NOISE_SUPPRESSION_LEVEL])) + cg.add(var.set_auto_gain(config[CONF_AUTO_GAIN])) + cg.add(var.set_volume_multiplier(config[CONF_VOLUME_MULTIPLIER])) if CONF_ON_LISTENING in config: await automation.build_automation( @@ -88,6 +119,13 @@ async def to_code(config): var.get_start_trigger(), [], config[CONF_ON_START] ) + if CONF_ON_WAKE_WORD_DETECTED in config: + await automation.build_automation( + var.get_wake_word_detected_trigger(), + [], + config[CONF_ON_WAKE_WORD_DETECTED], + ) + if CONF_ON_STT_END in config: await automation.build_automation( var.get_stt_end_trigger(), [(cg.std_string, "x")], config[CONF_ON_STT_END] @@ -128,10 +166,20 @@ VOICE_ASSISTANT_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(VoiceAssis StartContinuousAction, VOICE_ASSISTANT_ACTION_SCHEMA, ) -@register_action("voice_assistant.start", StartAction, VOICE_ASSISTANT_ACTION_SCHEMA) +@register_action( + "voice_assistant.start", + StartAction, + VOICE_ASSISTANT_ACTION_SCHEMA.extend( + { + cv.Optional(CONF_SILENCE_DETECTION, default=True): cv.boolean, + } + ), +) async def voice_assistant_listen_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) + if CONF_SILENCE_DETECTION in config: + cg.add(var.set_silence_detection(config[CONF_SILENCE_DETECTION])) return var diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 217ddb6354..802ae508ff 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -11,6 +11,17 @@ namespace voice_assistant { static const char *const TAG = "voice_assistant"; +#ifdef SAMPLE_RATE_HZ +#undef SAMPLE_RATE_HZ +#endif + +static const size_t SAMPLE_RATE_HZ = 16000; +static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms +static const size_t BUFFER_SIZE = 1000 * SAMPLE_RATE_HZ / 1000; // 1s +static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t); +static const size_t RECEIVE_SIZE = 1024; +static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; + float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } void VoiceAssistant::setup() { @@ -47,7 +58,6 @@ void VoiceAssistant::setup() { this->mark_failed(); return; } - server.ss_family = AF_INET; err = socket_->bind((struct sockaddr *) &server, sizeof(server)); if (err != 0) { @@ -55,60 +65,262 @@ void VoiceAssistant::setup() { this->mark_failed(); return; } + + ExternalRAMAllocator speaker_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE); + if (this->speaker_buffer_ == nullptr) { + ESP_LOGW(TAG, "Could not allocate speaker buffer."); + this->mark_failed(); + return; + } } #endif - this->mic_->add_data_callback([this](const std::vector &data) { - if (!this->running_) { - return; + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE); + if (this->input_buffer_ == nullptr) { + ESP_LOGW(TAG, "Could not allocate input buffer."); + this->mark_failed(); + return; + } + +#ifdef USE_ESP_ADF + this->vad_instance_ = vad_create(VAD_MODE_4); + + this->ring_buffer_ = rb_create(BUFFER_SIZE, sizeof(int16_t)); + if (this->ring_buffer_ == nullptr) { + ESP_LOGW(TAG, "Could not allocate ring buffer."); + this->mark_failed(); + return; + } +#endif + + ExternalRAMAllocator send_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE); + if (send_buffer_ == nullptr) { + ESP_LOGW(TAG, "Could not allocate send buffer."); + this->mark_failed(); + return; + } +} + +int VoiceAssistant::read_microphone_() { + size_t bytes_read = 0; + if (this->mic_->is_running()) { // Read audio into input buffer + bytes_read = this->mic_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t)); + if (bytes_read == 0) { + memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + return 0; } - this->socket_->sendto(data.data(), data.size() * sizeof(int16_t), 0, (struct sockaddr *) &this->dest_addr_, - sizeof(this->dest_addr_)); - }); +#ifdef USE_ESP_ADF + // Write audio into ring buffer + int available = rb_bytes_available(this->ring_buffer_); + if (available < bytes_read) { + rb_read(this->ring_buffer_, nullptr, bytes_read - available, 0); + } + rb_write(this->ring_buffer_, (char *) this->input_buffer_, bytes_read, 0); +#endif + } else { + ESP_LOGD(TAG, "microphone not running"); + } + return bytes_read; } void VoiceAssistant::loop() { -#ifdef USE_SPEAKER - if (this->speaker_ != nullptr) { - uint8_t buf[1024]; - auto len = this->socket_->read(buf, sizeof(buf)); - if (len == -1) { - return; + if (this->state_ != State::IDLE && this->state_ != State::STOP_MICROPHONE && + this->state_ != State::STOPPING_MICROPHONE && !api::global_api_server->is_connected()) { + if (this->mic_->is_running() || this->state_ == State::STARTING_MICROPHONE) { + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + } else { + this->set_state_(State::IDLE, State::IDLE); } - this->speaker_->play(buf, len); - this->set_timeout("data-incoming", 200, [this]() { - if (this->continuous_) { - this->request_start(true); - } - }); + this->continuous_ = false; + this->signal_stop_(); return; } + switch (this->state_) { + case State::IDLE: { + if (this->continuous_ && this->desired_state_ == State::IDLE) { +#ifdef USE_ESP_ADF + if (this->use_wake_word_) { + rb_reset(this->ring_buffer_); + this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); + } else +#endif + { + this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + } + } else { + this->high_freq_.stop(); + } + break; + } + case State::START_MICROPHONE: { + ESP_LOGD(TAG, "Starting Microphone"); + memset(this->send_buffer_, 0, SEND_BUFFER_SIZE); + memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + this->mic_->start(); + this->high_freq_.start(); + this->set_state_(State::STARTING_MICROPHONE); + break; + } + case State::STARTING_MICROPHONE: { + if (this->mic_->is_running()) { + this->set_state_(this->desired_state_); + } + break; + } +#ifdef USE_ESP_ADF + case State::WAIT_FOR_VAD: { + this->read_microphone_(); + ESP_LOGD(TAG, "Waiting for speech..."); + this->set_state_(State::WAITING_FOR_VAD); + break; + } + case State::WAITING_FOR_VAD: { + size_t bytes_read = this->read_microphone_(); + if (bytes_read > 0) { + vad_state_t vad_state = + vad_process(this->vad_instance_, this->input_buffer_, SAMPLE_RATE_HZ, VAD_FRAME_LENGTH_MS); + if (vad_state == VAD_SPEECH) { + if (this->vad_counter_ < this->vad_threshold_) { + this->vad_counter_++; + } else { + ESP_LOGD(TAG, "VAD detected speech"); + this->set_state_(State::START_PIPELINE, State::STREAMING_MICROPHONE); + } + } else { + if (this->vad_counter_ > 0) { + this->vad_counter_--; + } + } + } + break; + } +#endif + case State::START_PIPELINE: { + this->read_microphone_(); + ESP_LOGD(TAG, "Requesting start..."); + uint32_t flags = 0; + if (this->use_wake_word_) + flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD; + if (this->silence_detection_) + flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_VAD; + api::VoiceAssistantAudioSettings audio_settings; + audio_settings.noise_suppression_level = this->noise_suppression_level_; + audio_settings.auto_gain = this->auto_gain_; + audio_settings.volume_multiplier = this->volume_multiplier_; + if (!api::global_api_server->start_voice_assistant(this->conversation_id_, flags, audio_settings)) { + ESP_LOGW(TAG, "Could not request start."); + this->error_trigger_->trigger("not-connected", "Could not request start."); + this->continuous_ = false; + this->set_state_(State::IDLE, State::IDLE); + break; + } + this->set_state_(State::STARTING_PIPELINE); + this->set_timeout("reset-conversation_id", 5 * 60 * 1000, [this]() { this->conversation_id_ = ""; }); + break; + } + case State::STARTING_PIPELINE: { + this->read_microphone_(); + break; // State changed when udp server port received + } + case State::STREAMING_MICROPHONE: { + size_t bytes_read = this->read_microphone_(); +#ifdef USE_ESP_ADF + if (rb_bytes_filled(this->ring_buffer_) >= SEND_BUFFER_SIZE) { + rb_read(this->ring_buffer_, (char *) this->send_buffer_, SEND_BUFFER_SIZE, 0); + this->socket_->sendto(this->send_buffer_, SEND_BUFFER_SIZE, 0, (struct sockaddr *) &this->dest_addr_, + sizeof(this->dest_addr_)); + } +#else + if (bytes_read > 0) { + this->socket_->sendto(this->input_buffer_, bytes_read, 0, (struct sockaddr *) &this->dest_addr_, + sizeof(this->dest_addr_)); + } +#endif + break; + } + case State::STOP_MICROPHONE: { + if (this->mic_->is_running()) { + this->mic_->stop(); + this->set_state_(State::STOPPING_MICROPHONE); + } else { + this->set_state_(this->desired_state_); + } + break; + } + case State::STOPPING_MICROPHONE: { + if (this->mic_->is_stopped()) { + this->set_state_(this->desired_state_); + } + break; + } + case State::AWAITING_RESPONSE: { + break; // State changed by events + } + case State::STREAMING_RESPONSE: { + bool playing = false; +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + if (this->speaker_buffer_index_ + RECEIVE_SIZE < SPEAKER_BUFFER_SIZE) { + auto len = this->socket_->read(this->speaker_buffer_ + this->speaker_buffer_index_, RECEIVE_SIZE); + if (len > 0) { + this->speaker_buffer_index_ += len; + this->speaker_buffer_size_ += len; + } + } else { + ESP_LOGW(TAG, "Speaker buffer full."); + } + if (this->speaker_buffer_size_ > 0) { + size_t written = this->speaker_->play(this->speaker_buffer_, this->speaker_buffer_size_); + memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); + this->speaker_buffer_size_ -= written; + this->speaker_buffer_index_ -= written; + } + playing = this->speaker_->is_running(); + } #endif #ifdef USE_MEDIA_PLAYER - if (this->media_player_ != nullptr) { - if (!this->playing_tts_ || - this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING) { - return; - } - this->set_timeout("playing-media", 1000, [this]() { - this->playing_tts_ = false; - if (this->continuous_) { - this->request_start(true); + if (this->media_player_ != nullptr) { + playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING); } - }); - return; - } #endif - // Set a 1 second timeout to start the voice assistant again. - this->set_timeout("continuous-no-sound", 1000, [this]() { - if (this->continuous_) { - this->request_start(true); + if (playing) { + this->set_timeout("playing", 100, [this]() { this->set_state_(State::IDLE, State::IDLE); }); + } + break; } - }); + default: + break; + } } -void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { - ESP_LOGD(TAG, "Starting..."); +void VoiceAssistant::set_state_(State state) { + State old_state = this->state_; + this->state_ = state; + ESP_LOGD(TAG, "State changed from %d to %d", static_cast(old_state), static_cast(state)); +} + +void VoiceAssistant::set_state_(State state, State desired_state) { + this->set_state_(state); + this->desired_state_ = desired_state; + ESP_LOGD(TAG, "Desired state set to %d", static_cast(desired_state)); +} + +void VoiceAssistant::failed_to_start() { + ESP_LOGE(TAG, "Failed to start server. See Home Assistant logs for more details."); + this->error_trigger_->trigger("failed-to-start", "Failed to start server. See Home Assistant logs for more details."); + this->set_state_(State::STOP_MICROPHONE, State::IDLE); +} + +void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t port) { + if (this->state_ != State::STARTING_PIPELINE) { + this->signal_stop_(); + return; + } + + ESP_LOGD(TAG, "Client started, streaming microphone"); memcpy(&this->dest_addr_, addr, sizeof(this->dest_addr_)); if (this->dest_addr_.ss_family == AF_INET) { @@ -123,38 +335,90 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) { ESP_LOGW(TAG, "Unknown address family: %d", this->dest_addr_.ss_family); return; } - this->running_ = true; - this->mic_->start(); - this->listening_trigger_->trigger(); + + if (this->mic_->is_running()) { + this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE); + } else { + this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE); + } } -void VoiceAssistant::request_start(bool continuous) { - ESP_LOGD(TAG, "Requesting start..."); - if (!api::global_api_server->start_voice_assistant(this->conversation_id_, this->silence_detection_)) { - ESP_LOGW(TAG, "Could not request start."); - this->error_trigger_->trigger("not-connected", "Could not request start."); +void VoiceAssistant::request_start(bool continuous, bool silence_detection) { + if (!api::global_api_server->is_connected()) { + ESP_LOGE(TAG, "No API client connected"); + this->set_state_(State::IDLE, State::IDLE); this->continuous_ = false; return; } - this->continuous_ = continuous; - this->set_timeout("reset-conversation_id", 5 * 60 * 1000, [this]() { this->conversation_id_ = ""; }); + if (this->state_ == State::IDLE) { + this->continuous_ = continuous; + this->silence_detection_ = silence_detection; +#ifdef USE_ESP_ADF + if (this->use_wake_word_) { + rb_reset(this->ring_buffer_); + this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); + } else +#endif + { + this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + } + } } -void VoiceAssistant::signal_stop() { +void VoiceAssistant::request_stop() { + this->continuous_ = false; + + switch (this->state_) { + case State::IDLE: + break; + case State::START_MICROPHONE: + case State::STARTING_MICROPHONE: + case State::WAIT_FOR_VAD: + case State::WAITING_FOR_VAD: + case State::START_PIPELINE: + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + break; + case State::STARTING_PIPELINE: + case State::STREAMING_MICROPHONE: + this->signal_stop_(); + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + break; + case State::STOP_MICROPHONE: + case State::STOPPING_MICROPHONE: + this->desired_state_ = State::IDLE; + break; + case State::AWAITING_RESPONSE: + case State::STREAMING_RESPONSE: + break; // Let the incoming audio stream finish then it will go to idle. + } +} + +void VoiceAssistant::signal_stop_() { ESP_LOGD(TAG, "Signaling stop..."); - this->mic_->stop(); - this->running_ = false; api::global_api_server->stop_voice_assistant(); memset(&this->dest_addr_, 0, sizeof(this->dest_addr_)); } void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { + ESP_LOGD(TAG, "Event Type: %d", msg.event_type); switch (msg.event_type) { case api::enums::VOICE_ASSISTANT_RUN_START: ESP_LOGD(TAG, "Assist Pipeline running"); this->start_trigger_->trigger(); break; + case api::enums::VOICE_ASSISTANT_WAKE_WORD_START: + break; + case api::enums::VOICE_ASSISTANT_WAKE_WORD_END: { + ESP_LOGD(TAG, "Wake word detected"); + this->wake_word_detected_trigger_->trigger(); + break; + } + case api::enums::VOICE_ASSISTANT_STT_START: + ESP_LOGD(TAG, "STT Started"); + this->listening_trigger_->trigger(); + break; case api::enums::VOICE_ASSISTANT_STT_END: { + this->set_state_(State::STOP_MICROPHONE, State::AWAITING_RESPONSE); std::string text; for (auto arg : msg.data) { if (arg.name == "text") { @@ -166,7 +430,6 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { return; } ESP_LOGD(TAG, "Speech recognised as: \"%s\"", text.c_str()); - this->signal_stop(); this->stt_end_trigger_->trigger(text); break; } @@ -191,6 +454,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } ESP_LOGD(TAG, "Response: \"%s\"", text.c_str()); this->tts_start_trigger_->trigger(text); +#ifdef USE_SPEAKER + this->speaker_->start(); +#endif break; } case api::enums::VOICE_ASSISTANT_TTS_END: { @@ -207,17 +473,22 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { ESP_LOGD(TAG, "Response URL: \"%s\"", url.c_str()); #ifdef USE_MEDIA_PLAYER if (this->media_player_ != nullptr) { - this->playing_tts_ = true; this->media_player_->make_call().set_media_url(url).perform(); } #endif + State new_state = this->local_output_ ? State::STREAMING_RESPONSE : State::IDLE; + this->set_state_(new_state, new_state); this->tts_end_trigger_->trigger(url); break; } - case api::enums::VOICE_ASSISTANT_RUN_END: + case api::enums::VOICE_ASSISTANT_RUN_END: { ESP_LOGD(TAG, "Assist Pipeline ended"); + if (this->state_ != State::STREAMING_RESPONSE && this->state_ != State::IDLE) { + this->set_state_(State::IDLE, State::IDLE); + } this->end_trigger_->trigger(); break; + } case api::enums::VOICE_ASSISTANT_ERROR: { std::string code = ""; std::string message = ""; @@ -228,12 +499,20 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { message = std::move(arg.value); } } + if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") { + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + return; + } ESP_LOGE(TAG, "Error: %s - %s", code.c_str(), message.c_str()); - this->continuous_ = false; - this->signal_stop(); + if (this->state_ != State::IDLE) { + this->signal_stop_(); + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + } this->error_trigger_->trigger(code, message); + break; } default: + ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type); break; } } diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 75c17965bc..ce22538a85 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -19,6 +19,11 @@ #endif #include "esphome/components/socket/socket.h" +#ifdef USE_ESP_ADF +#include +#include +#endif + namespace esphome { namespace voice_assistant { @@ -28,19 +33,41 @@ namespace voice_assistant { static const uint32_t INITIAL_VERSION = 1; static const uint32_t SPEAKER_SUPPORT = 2; +enum class State { + IDLE, + START_MICROPHONE, + STARTING_MICROPHONE, + WAIT_FOR_VAD, + WAITING_FOR_VAD, + START_PIPELINE, + STARTING_PIPELINE, + STREAMING_MICROPHONE, + STOP_MICROPHONE, + STOPPING_MICROPHONE, + AWAITING_RESPONSE, + STREAMING_RESPONSE, +}; + class VoiceAssistant : public Component { public: void setup() override; void loop() override; float get_setup_priority() const override; - void start(struct sockaddr_storage *addr, uint16_t port); + void start_streaming(struct sockaddr_storage *addr, uint16_t port); + void failed_to_start(); void set_microphone(microphone::Microphone *mic) { this->mic_ = mic; } #ifdef USE_SPEAKER - void set_speaker(speaker::Speaker *speaker) { this->speaker_ = speaker; } + void set_speaker(speaker::Speaker *speaker) { + this->speaker_ = speaker; + this->local_output_ = true; + } #endif #ifdef USE_MEDIA_PLAYER - void set_media_player(media_player::MediaPlayer *media_player) { this->media_player_ = media_player; } + void set_media_player(media_player::MediaPlayer *media_player) { + this->media_player_ = media_player; + this->local_output_ = true; + } #endif uint32_t get_version() const { @@ -52,19 +79,29 @@ class VoiceAssistant : public Component { return INITIAL_VERSION; } - void request_start(bool continuous = false); - void signal_stop(); + void request_start(bool continuous, bool silence_detection); + void request_stop(); void on_event(const api::VoiceAssistantEventResponse &msg); - bool is_running() const { return this->running_; } + bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } bool is_continuous() const { return this->continuous_; } - void set_silence_detection(bool silence_detection) { this->silence_detection_ = silence_detection; } + void set_use_wake_word(bool use_wake_word) { this->use_wake_word_ = use_wake_word; } +#ifdef USE_ESP_ADF + void set_vad_threshold(uint8_t vad_threshold) { this->vad_threshold_ = vad_threshold; } +#endif + + void set_noise_suppression_level(uint8_t noise_suppression_level) { + this->noise_suppression_level_ = noise_suppression_level; + } + void set_auto_gain(uint8_t auto_gain) { this->auto_gain_ = auto_gain; } + void set_volume_multiplier(float volume_multiplier) { this->volume_multiplier_ = volume_multiplier; } Trigger<> *get_listening_trigger() const { return this->listening_trigger_; } Trigger<> *get_start_trigger() const { return this->start_trigger_; } + Trigger<> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; } Trigger *get_stt_end_trigger() const { return this->stt_end_trigger_; } Trigger *get_tts_start_trigger() const { return this->tts_start_trigger_; } Trigger *get_tts_end_trigger() const { return this->tts_end_trigger_; } @@ -72,11 +109,17 @@ class VoiceAssistant : public Component { Trigger *get_error_trigger() const { return this->error_trigger_; } protected: + int read_microphone_(); + void set_state_(State state); + void set_state_(State state, State desired_state); + void signal_stop_(); + std::unique_ptr socket_ = nullptr; struct sockaddr_storage dest_addr_; Trigger<> *listening_trigger_ = new Trigger<>(); Trigger<> *start_trigger_ = new Trigger<>(); + Trigger<> *wake_word_detected_trigger_ = new Trigger<>(); Trigger *stt_end_trigger_ = new Trigger(); Trigger *tts_start_trigger_ = new Trigger(); Trigger *tts_end_trigger_ = new Trigger(); @@ -86,35 +129,61 @@ class VoiceAssistant : public Component { microphone::Microphone *mic_{nullptr}; #ifdef USE_SPEAKER speaker::Speaker *speaker_{nullptr}; + uint8_t *speaker_buffer_; + size_t speaker_buffer_index_{0}; + size_t speaker_buffer_size_{0}; #endif #ifdef USE_MEDIA_PLAYER media_player::MediaPlayer *media_player_{nullptr}; bool playing_tts_{false}; #endif + bool local_output_{false}; + std::string conversation_id_{""}; - bool running_{false}; + HighFrequencyLoopRequester high_freq_; + +#ifdef USE_ESP_ADF + vad_handle_t vad_instance_; + ringbuf_handle_t ring_buffer_; + uint8_t vad_threshold_{5}; + uint8_t vad_counter_{0}; +#endif + + bool use_wake_word_; + uint8_t noise_suppression_level_; + uint8_t auto_gain_; + float volume_multiplier_; + + uint8_t *send_buffer_; + int16_t *input_buffer_; + bool continuous_{false}; bool silence_detection_; + + State state_{State::IDLE}; + State desired_state_{State::IDLE}; }; template class StartAction : public Action, public Parented { public: - void play(Ts... x) override { this->parent_->request_start(); } + void play(Ts... x) override { this->parent_->request_start(false, this->silence_detection_); } + + void set_silence_detection(bool silence_detection) { this->silence_detection_ = silence_detection; } + + protected: + bool silence_detection_; }; template class StartContinuousAction : public Action, public Parented { public: - void play(Ts... x) override { this->parent_->request_start(true); } + void play(Ts... x) override { this->parent_->request_start(true, true); } }; template class StopAction : public Action, public Parented { public: - void play(Ts... x) override { - this->parent_->set_continuous(false); - this->parent_->signal_stop(); - } + void play(Ts... x) override { this->parent_->request_stop(); } }; template class IsRunningCondition : public Condition, public Parented { diff --git a/tests/test4.yaml b/tests/test4.yaml index bb4357e28d..3d0ed2f658 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -767,6 +767,9 @@ speaker: voice_assistant: microphone: mic_id_external + speaker: speaker_id + on_listening: + - logger.log: "Voice assistant microphone listening" on_start: - logger.log: "Voice assistant started" on_stt_end: From c77a9ad3630802376ab65d79d73d5663c79bf6a4 Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Tue, 10 Oct 2023 09:00:05 +0200 Subject: [PATCH 0584/2607] Don't allow entity category "CONFIG" for sensors (#5505) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sensor/__init__.py | 13 ++++++++++++- esphome/config_validation.py | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 8f7d581b2d..ee42011038 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -85,6 +85,7 @@ from esphome.const import ( DEVICE_CLASS_WATER, DEVICE_CLASS_WEIGHT, DEVICE_CLASS_WIND_SPEED, + ENTITY_CATEGORY_CONFIG, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass @@ -188,6 +189,15 @@ def validate_datapoint(value): return validate_datapoint({CONF_FROM: cv.float_(a), CONF_TO: cv.float_(b)}) +_SENSOR_ENTITY_CATEGORIES = { + k: v for k, v in cv.ENTITY_CATEGORIES.items() if k != ENTITY_CATEGORY_CONFIG +} + + +def sensor_entity_category(value): + return cv.enum(_SENSOR_ENTITY_CATEGORIES, lower=True)(value) + + # Base Sensor = sensor_ns.class_("Sensor", cg.EntityBase) SensorPtr = Sensor.operator("ptr") @@ -246,6 +256,7 @@ SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( cv.Optional(CONF_ACCURACY_DECIMALS): validate_accuracy_decimals, cv.Optional(CONF_DEVICE_CLASS): validate_device_class, cv.Optional(CONF_STATE_CLASS): validate_state_class, + cv.Optional(CONF_ENTITY_CATEGORY): sensor_entity_category, cv.Optional("last_reset_type"): cv.invalid( "last_reset_type has been removed since 2021.9.0. state_class: total_increasing should be used for total values." ), @@ -301,7 +312,7 @@ def sensor_schema( (CONF_ACCURACY_DECIMALS, accuracy_decimals, validate_accuracy_decimals), (CONF_DEVICE_CLASS, device_class, validate_device_class), (CONF_STATE_CLASS, state_class, validate_state_class), - (CONF_ENTITY_CATEGORY, entity_category, cv.entity_category), + (CONF_ENTITY_CATEGORY, entity_category, sensor_entity_category), ]: if default is not _UNDEF: schema[cv.Optional(key, default=default)] = validator diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 46f3f6a7bd..d699a2647b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1672,7 +1672,7 @@ def maybe_simple_value(*validators, **kwargs): return validate -_ENTITY_CATEGORIES = { +ENTITY_CATEGORIES = { ENTITY_CATEGORY_NONE: cg.EntityCategory.ENTITY_CATEGORY_NONE, ENTITY_CATEGORY_CONFIG: cg.EntityCategory.ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_DIAGNOSTIC: cg.EntityCategory.ENTITY_CATEGORY_DIAGNOSTIC, @@ -1680,7 +1680,7 @@ _ENTITY_CATEGORIES = { def entity_category(value): - return enum(_ENTITY_CATEGORIES, lower=True)(value) + return enum(ENTITY_CATEGORIES, lower=True)(value) MQTT_COMPONENT_AVAILABILITY_SCHEMA = Schema( From c9a8911029698c239cff21a0a67bd952c526da14 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 11 Oct 2023 00:51:53 +0200 Subject: [PATCH 0585/2607] Prepare protobuf for ESP-IDF >= 5 (#5510) --- esphome/components/api/api_pb2.cpp | 190 ++++++++++++++-------------- script/api_protobuf/api_protobuf.py | 12 +- 2 files changed, 103 insertions(+), 99 deletions(-) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index d0711aba7b..225b213a67 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3,6 +3,8 @@ #include "api_pb2.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace api { @@ -544,12 +546,12 @@ void HelloRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" api_version_major: "); - sprintf(buffer, "%u", this->api_version_major); + sprintf(buffer, "%" PRIu32, this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%u", this->api_version_minor); + sprintf(buffer, "%" PRIu32, this->api_version_minor); out.append(buffer); out.append("\n"); out.append("}"); @@ -594,12 +596,12 @@ void HelloResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("HelloResponse {\n"); out.append(" api_version_major: "); - sprintf(buffer, "%u", this->api_version_major); + sprintf(buffer, "%" PRIu32, this->api_version_major); out.append(buffer); out.append("\n"); out.append(" api_version_minor: "); - sprintf(buffer, "%u", this->api_version_minor); + sprintf(buffer, "%" PRIu32, this->api_version_minor); out.append(buffer); out.append("\n"); @@ -805,17 +807,17 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" webserver_port: "); - sprintf(buffer, "%u", this->webserver_port); + sprintf(buffer, "%" PRIu32, this->webserver_port); out.append(buffer); out.append("\n"); out.append(" legacy_bluetooth_proxy_version: "); - sprintf(buffer, "%u", this->legacy_bluetooth_proxy_version); + sprintf(buffer, "%" PRIu32, this->legacy_bluetooth_proxy_version); out.append(buffer); out.append("\n"); out.append(" bluetooth_proxy_feature_flags: "); - sprintf(buffer, "%u", this->bluetooth_proxy_feature_flags); + sprintf(buffer, "%" PRIu32, this->bluetooth_proxy_feature_flags); out.append(buffer); out.append("\n"); @@ -828,7 +830,7 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" voice_assistant_version: "); - sprintf(buffer, "%u", this->voice_assistant_version); + sprintf(buffer, "%" PRIu32, this->voice_assistant_version); out.append(buffer); out.append("\n"); out.append("}"); @@ -920,7 +922,7 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -988,7 +990,7 @@ void BinarySensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BinarySensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1091,7 +1093,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1181,7 +1183,7 @@ void CoverStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1264,7 +1266,7 @@ void CoverCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CoverCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1384,7 +1386,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1409,7 +1411,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_speed_count: "); - sprintf(buffer, "%d", this->supported_speed_count); + sprintf(buffer, "%" PRId32, this->supported_speed_count); out.append(buffer); out.append("\n"); @@ -1476,7 +1478,7 @@ void FanStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1497,7 +1499,7 @@ void FanStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%d", this->speed_level); + sprintf(buffer, "%" PRId32, this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1577,7 +1579,7 @@ void FanCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("FanCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1618,7 +1620,7 @@ void FanCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" speed_level: "); - sprintf(buffer, "%d", this->speed_level); + sprintf(buffer, "%" PRId32, this->speed_level); out.append(buffer); out.append("\n"); out.append("}"); @@ -1732,7 +1734,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -1886,7 +1888,7 @@ void LightStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2109,7 +2111,7 @@ void LightCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LightCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2207,7 +2209,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" transition_length: "); - sprintf(buffer, "%u", this->transition_length); + sprintf(buffer, "%" PRIu32, this->transition_length); out.append(buffer); out.append("\n"); @@ -2216,7 +2218,7 @@ void LightCommandRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" flash_length: "); - sprintf(buffer, "%u", this->flash_length); + sprintf(buffer, "%" PRIu32, this->flash_length); out.append(buffer); out.append("\n"); @@ -2324,7 +2326,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2345,7 +2347,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" accuracy_decimals: "); - sprintf(buffer, "%d", this->accuracy_decimals); + sprintf(buffer, "%" PRId32, this->accuracy_decimals); out.append(buffer); out.append("\n"); @@ -2409,7 +2411,7 @@ void SensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2498,7 +2500,7 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2561,7 +2563,7 @@ void SwitchStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2600,7 +2602,7 @@ void SwitchCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SwitchCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2674,7 +2676,7 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -2740,7 +2742,7 @@ void TextSensorStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("TextSensorStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3047,7 +3049,7 @@ void GetTimeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("GetTimeResponse {\n"); out.append(" epoch_seconds: "); - sprintf(buffer, "%u", this->epoch_seconds); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); out.append(buffer); out.append("\n"); out.append("}"); @@ -3131,7 +3133,7 @@ void ListEntitiesServicesResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3225,7 +3227,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" legacy_int: "); - sprintf(buffer, "%d", this->legacy_int); + sprintf(buffer, "%" PRId32, this->legacy_int); out.append(buffer); out.append("\n"); @@ -3239,7 +3241,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { out.append("\n"); out.append(" int_: "); - sprintf(buffer, "%d", this->int_); + sprintf(buffer, "%" PRId32, this->int_); out.append(buffer); out.append("\n"); @@ -3251,7 +3253,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { for (const auto &it : this->int_array) { out.append(" int_array: "); - sprintf(buffer, "%d", it); + sprintf(buffer, "%" PRId32, it); out.append(buffer); out.append("\n"); } @@ -3302,7 +3304,7 @@ void ExecuteServiceRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ExecuteServiceRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3378,7 +3380,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3444,7 +3446,7 @@ void CameraImageResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("CameraImageResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3636,7 +3638,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -3824,7 +3826,7 @@ void ClimateStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4012,7 +4014,7 @@ void ClimateCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ClimateCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4195,7 +4197,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4282,7 +4284,7 @@ void NumberStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4320,7 +4322,7 @@ void NumberCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NumberCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4402,7 +4404,7 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4474,7 +4476,7 @@ void SelectStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4517,7 +4519,7 @@ void SelectCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SelectCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4611,7 +4613,7 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4682,7 +4684,7 @@ void LockStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4737,7 +4739,7 @@ void LockCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("LockCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4824,7 +4826,7 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -4870,7 +4872,7 @@ void ButtonCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ButtonCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); out.append("}"); @@ -4945,7 +4947,7 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -5014,7 +5016,7 @@ void MediaPlayerStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -5093,7 +5095,7 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -5142,7 +5144,7 @@ void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const __attribute__((unused)) char buffer[64]; out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); out.append(" flags: "); - sprintf(buffer, "%u", this->flags); + sprintf(buffer, "%" PRIu32, this->flags); out.append(buffer); out.append("\n"); out.append("}"); @@ -5189,7 +5191,7 @@ void BluetoothServiceData::dump_to(std::string &out) const { for (const auto &it : this->legacy_data) { out.append(" legacy_data: "); - sprintf(buffer, "%u", it); + sprintf(buffer, "%" PRIu32, it); out.append(buffer); out.append("\n"); } @@ -5269,7 +5271,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%d", this->rssi); + sprintf(buffer, "%" PRId32, this->rssi); out.append(buffer); out.append("\n"); @@ -5292,7 +5294,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { } out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5342,12 +5344,12 @@ void BluetoothLERawAdvertisement::dump_to(std::string &out) const { out.append("\n"); out.append(" rssi: "); - sprintf(buffer, "%d", this->rssi); + sprintf(buffer, "%" PRId32, this->rssi); out.append(buffer); out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); @@ -5430,7 +5432,7 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" address_type: "); - sprintf(buffer, "%u", this->address_type); + sprintf(buffer, "%" PRIu32, this->address_type); out.append(buffer); out.append("\n"); out.append("}"); @@ -5478,12 +5480,12 @@ void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" mtu: "); - sprintf(buffer, "%u", this->mtu); + sprintf(buffer, "%" PRIu32, this->mtu); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -5543,7 +5545,7 @@ void BluetoothGATTDescriptor::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5599,12 +5601,12 @@ void BluetoothGATTCharacteristic::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append(" properties: "); - sprintf(buffer, "%u", this->properties); + sprintf(buffer, "%" PRIu32, this->properties); out.append(buffer); out.append("\n"); @@ -5661,7 +5663,7 @@ void BluetoothGATTService::dump_to(std::string &out) const { } out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5768,7 +5770,7 @@ void BluetoothGATTReadRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5813,7 +5815,7 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5867,7 +5869,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5909,7 +5911,7 @@ void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -5954,7 +5956,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -5997,7 +5999,7 @@ void BluetoothGATTNotifyRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -6046,7 +6048,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); @@ -6085,12 +6087,12 @@ void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("BluetoothConnectionsFreeResponse {\n"); out.append(" free: "); - sprintf(buffer, "%u", this->free); + sprintf(buffer, "%" PRIu32, this->free); out.append(buffer); out.append("\n"); out.append(" limit: "); - sprintf(buffer, "%u", this->limit); + sprintf(buffer, "%" PRIu32, this->limit); out.append(buffer); out.append("\n"); out.append("}"); @@ -6129,12 +6131,12 @@ void BluetoothGATTErrorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6168,7 +6170,7 @@ void BluetoothGATTWriteResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6202,7 +6204,7 @@ void BluetoothGATTNotifyResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" handle: "); - sprintf(buffer, "%u", this->handle); + sprintf(buffer, "%" PRIu32, this->handle); out.append(buffer); out.append("\n"); out.append("}"); @@ -6245,7 +6247,7 @@ void BluetoothDevicePairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6288,7 +6290,7 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6337,7 +6339,7 @@ void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" error: "); - sprintf(buffer, "%d", this->error); + sprintf(buffer, "%" PRId32, this->error); out.append(buffer); out.append("\n"); out.append("}"); @@ -6398,12 +6400,12 @@ void VoiceAssistantAudioSettings::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantAudioSettings {\n"); out.append(" noise_suppression_level: "); - sprintf(buffer, "%u", this->noise_suppression_level); + sprintf(buffer, "%" PRIu32, this->noise_suppression_level); out.append(buffer); out.append("\n"); out.append(" auto_gain: "); - sprintf(buffer, "%u", this->auto_gain); + sprintf(buffer, "%" PRIu32, this->auto_gain); out.append(buffer); out.append("\n"); @@ -6461,7 +6463,7 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" flags: "); - sprintf(buffer, "%u", this->flags); + sprintf(buffer, "%" PRIu32, this->flags); out.append(buffer); out.append("\n"); @@ -6494,7 +6496,7 @@ void VoiceAssistantResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantResponse {\n"); out.append(" port: "); - sprintf(buffer, "%u", this->port); + sprintf(buffer, "%" PRIu32, this->port); out.append(buffer); out.append("\n"); @@ -6657,7 +6659,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -6682,7 +6684,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" supported_features: "); - sprintf(buffer, "%u", this->supported_features); + sprintf(buffer, "%" PRIu32, this->supported_features); out.append(buffer); out.append("\n"); @@ -6725,7 +6727,7 @@ void AlarmControlPanelStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelStateResponse {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); @@ -6775,7 +6777,7 @@ void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("AlarmControlPanelCommandRequest {\n"); out.append(" key: "); - sprintf(buffer, "%u", this->key); + sprintf(buffer, "%" PRIu32, this->key); out.append(buffer); out.append("\n"); diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 5a0c92350d..3c19034e96 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -263,7 +263,7 @@ class Int32Type(TypeInfo): encode_func = "encode_int32" def dump(self, name): - o = f'sprintf(buffer, "%d", {name});\n' + o = f'sprintf(buffer, "%" PRId32, {name});\n' o += f"out.append(buffer);" return o @@ -289,7 +289,7 @@ class Fixed32Type(TypeInfo): encode_func = "encode_fixed32" def dump(self, name): - o = f'sprintf(buffer, "%u", {name});\n' + o = f'sprintf(buffer, "%" PRIu32, {name});\n' o += f"out.append(buffer);" return o @@ -371,7 +371,7 @@ class UInt32Type(TypeInfo): encode_func = "encode_uint32" def dump(self, name): - o = f'sprintf(buffer, "%u", {name});\n' + o = f'sprintf(buffer, "%" PRIu32, {name});\n' o += f"out.append(buffer);" return o @@ -405,7 +405,7 @@ class SFixed32Type(TypeInfo): encode_func = "encode_sfixed32" def dump(self, name): - o = f'sprintf(buffer, "%d", {name});\n' + o = f'sprintf(buffer, "%" PRId32, {name});\n' o += f"out.append(buffer);" return o @@ -431,7 +431,7 @@ class SInt32Type(TypeInfo): encode_func = "encode_sint32" def dump(self, name): - o = f'sprintf(buffer, "%d", {name});\n' + o = f'sprintf(buffer, "%" PRId32, {name});\n' o += f"out.append(buffer);" return o @@ -701,6 +701,8 @@ cpp += """\ #include "api_pb2.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace api { From 5d5cc960170ae0a4f68fbc3c37bf1ced820120a4 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Tue, 10 Oct 2023 19:52:40 -0300 Subject: [PATCH 0586/2607] fix build lang schema for spi and i2c (#5509) --- script/build_language_schema.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/script/build_language_schema.py b/script/build_language_schema.py index c6fcf5eb64..fb2010fe3e 100644 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -82,6 +82,10 @@ def load_components(): components[domain] = get_component(domain) +from esphome.const import CONF_TYPE, KEY_CORE +from esphome.core import CORE + +CORE.data[KEY_CORE] = {} load_components() # Import esphome after loading components (so schema is tracked) @@ -91,7 +95,6 @@ import esphome.config_validation as cv from esphome import automation from esphome import pins from esphome.components import remote_base -from esphome.const import CONF_TYPE from esphome.loader import get_platform, CORE_COMPONENTS_PATH from esphome.helpers import write_file_if_changed from esphome.util import Registry @@ -868,8 +871,11 @@ def convert(schema, config_var, path): else: raise Exception("Unknown extracted schema type") elif config_var.get("key") == "GeneratedID": - if path == "i2c/CONFIG_SCHEMA/extL/all/id": - config_var["id_type"] = {"class": "i2c::I2CBus", "parents": ["Component"]} + if path.startswith("i2c/CONFIG_SCHEMA/") and path.endswith("/id"): + config_var["id_type"] = { + "class": "i2c::I2CBus", + "parents": ["Component"], + } elif path == "uart/CONFIG_SCHEMA/val 1/extL/all/id": config_var["id_type"] = { "class": "uart::UARTComponent", From 9d95f5c1daece493abd61f37feb1a2d47ceef15c Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Wed, 11 Oct 2023 01:56:53 +0300 Subject: [PATCH 0587/2607] Added Nextion display error handling during setup (#5493) --- esphome/components/nextion/nextion.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index f8beaeab78..6133ad1d7e 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -61,6 +61,11 @@ bool Nextion::check_connect_() { std::string response; this->recv_ret_string_(response, 0, false); + if (!response.empty() && response[0] == 0x1A) { + // Swallow invalid variable name responses that may be caused by the above commands + ESP_LOGD(TAG, "0x1A error ignored during setup"); + return false; + } if (response.empty() || response.find("comok") == std::string::npos) { #ifdef NEXTION_PROTOCOL_LOG ESP_LOGN(TAG, "Bad connect request %s", response.c_str()); From 41f29c46d024138ae8b3a1dd19d94f1c4ed96816 Mon Sep 17 00:00:00 2001 From: justdaniel-gh <68163487+justdaniel-gh@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:42:38 -0500 Subject: [PATCH 0588/2607] Fix e131 and voice_assistant sockets (#5502) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/e131/e131.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/e131/e131.cpp b/esphome/components/e131/e131.cpp index 818006ced7..c3ff21c1a0 100644 --- a/esphome/components/e131/e131.cpp +++ b/esphome/components/e131/e131.cpp @@ -40,7 +40,6 @@ void E131Component::setup() { this->mark_failed(); return; } - server.ss_family = AF_INET; err = this->socket_->bind((struct sockaddr *) &server, sizeof(server)); if (err != 0) { From e35de626a46d595609556d83c1c18a9afe4d8183 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 12 Oct 2023 03:26:07 +0200 Subject: [PATCH 0589/2607] Allow manual set "Invert_display" (#5494) --- esphome/components/ili9xxx/display.py | 5 +++++ esphome/components/ili9xxx/ili9xxx_display.cpp | 15 +++++++++++---- esphome/components/ili9xxx/ili9xxx_display.h | 4 +++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 241f56e018..ec96d38cf8 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -54,6 +54,7 @@ COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") CONF_LED_PIN = "led_pin" CONF_COLOR_PALETTE_IMAGES = "color_palette_images" +CONF_INVERT_DISPLAY = "invert_display" def _validate(config): @@ -100,6 +101,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( cv.file_ ), + cv.Optional(CONF_INVERT_DISPLAY): cv.boolean, } ) .extend(cv.polling_component_schema("1s")) @@ -176,3 +178,6 @@ async def to_code(config): if rhs is not None: prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) + + if CONF_INVERT_DISPLAY in config: + cg.add(var.invert_display(config[CONF_INVERT_DISPLAY])) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index abe01ea8c3..fdbf3e3760 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -12,11 +12,13 @@ static const char *const TAG = "ili9xxx"; void ILI9XXXDisplay::setup() { this->setup_pins_(); this->initialize(); + this->command(this->pre_invertdisplay_ ? ILI9XXX_INVON : ILI9XXX_INVOFF); this->x_low_ = this->width_; this->y_low_ = this->height_; this->x_high_ = 0; this->y_high_ = 0; + if (this->buffer_color_mode_ == BITS_16) { this->init_internal_(this->get_buffer_length_() * 2); if (this->buffer_ != nullptr) { @@ -333,7 +335,12 @@ void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint this->command(ILI9XXX_RAMWR); // Write to RAM } -void ILI9XXXDisplay::invert_display_(bool invert) { this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); } +void ILI9XXXDisplay::invert_display(bool invert) { + this->pre_invertdisplay_ = invert; + if (is_ready()) { + this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); + } +} int ILI9XXXDisplay::get_width_internal() { return this->width_; } int ILI9XXXDisplay::get_height_internal() { return this->height_; } @@ -345,7 +352,7 @@ void ILI9XXXM5Stack::initialize() { this->width_ = 320; if (this->height_ == 0) this->height_ = 240; - this->invert_display_(true); + this->pre_invertdisplay_ = true; } // M5CORE display // Based on the configuration settings of M5stact's M5GFX code. @@ -355,7 +362,7 @@ void ILI9XXXM5CORE::initialize() { this->width_ = 320; if (this->height_ == 0) this->height_ = 240; - this->invert_display_(true); + this->pre_invertdisplay_ = true; } // 24_TFT display @@ -462,7 +469,7 @@ void ILI9XXXS3BoxLite::initialize() { if (this->height_ == 0) { this->height_ = 240; } - this->invert_display_(true); + this->pre_invertdisplay_ = true; } } // namespace ili9xxx diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 4e8355b9a5..e43585afeb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -33,6 +33,7 @@ class ILI9XXXDisplay : public PollingComponent, this->height_ = height; this->width_ = width; } + void invert_display(bool invert); void command(uint8_t value); void data(uint8_t value); void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes); @@ -55,7 +56,7 @@ class ILI9XXXDisplay : public PollingComponent, void display_(); void init_lcd_(const uint8_t *init_cmd); void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h); - void invert_display_(bool invert); + void reset_(); int16_t width_{0}; ///< Display width as modified by current rotation @@ -88,6 +89,7 @@ class ILI9XXXDisplay : public PollingComponent, bool prossing_update_ = false; bool need_update_ = false; bool is_18bitdisplay_ = false; + bool pre_invertdisplay_ = false; }; //----------- M5Stack display -------------- From 853d81c6ddb7d9d11e04156707a83451214c7356 Mon Sep 17 00:00:00 2001 From: Mark Veinot Date: Wed, 11 Oct 2023 22:27:36 -0300 Subject: [PATCH 0590/2607] As3935 calibration (#5366) --- esphome/components/as3935/__init__.py | 6 ++ esphome/components/as3935/as3935.cpp | 89 +++++++++++++++++++++++++++ esphome/components/as3935/as3935.h | 14 +++++ esphome/const.py | 1 + 4 files changed, 110 insertions(+) diff --git a/esphome/components/as3935/__init__.py b/esphome/components/as3935/__init__.py index 5cec1bfaba..2ec7c50859 100644 --- a/esphome/components/as3935/__init__.py +++ b/esphome/components/as3935/__init__.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_IRQ_PIN, CONF_LIGHTNING_THRESHOLD, CONF_MASK_DISTURBER, + CONF_CALIBRATION, + CONF_TUNE_ANTENNA, CONF_NOISE_LEVEL, CONF_SPIKE_REJECTION, CONF_WATCHDOG_THRESHOLD, @@ -34,6 +36,8 @@ AS3935_SCHEMA = cv.Schema( cv.Optional(CONF_MASK_DISTURBER, default=False): cv.boolean, cv.Optional(CONF_DIV_RATIO, default=0): cv.one_of(0, 16, 32, 64, 128, int=True), cv.Optional(CONF_CAPACITANCE, default=0): cv.int_range(min=0, max=15), + cv.Optional(CONF_TUNE_ANTENNA, default=False): cv.boolean, + cv.Optional(CONF_CALIBRATION, default=True): cv.boolean, } ) @@ -51,3 +55,5 @@ async def setup_as3935(var, config): cg.add(var.set_mask_disturber(config[CONF_MASK_DISTURBER])) cg.add(var.set_div_ratio(config[CONF_DIV_RATIO])) cg.add(var.set_capacitance(config[CONF_CAPACITANCE])) + cg.add(var.set_tune_antenna(config[CONF_TUNE_ANTENNA])) + cg.add(var.set_calibration(config[CONF_CALIBRATION])) diff --git a/esphome/components/as3935/as3935.cpp b/esphome/components/as3935/as3935.cpp index c5651caee3..29fc6ee685 100644 --- a/esphome/components/as3935/as3935.cpp +++ b/esphome/components/as3935/as3935.cpp @@ -21,6 +21,14 @@ void AS3935Component::setup() { this->write_mask_disturber(this->mask_disturber_); this->write_div_ratio(this->div_ratio_); this->write_capacitance(this->capacitance_); + + // Handle setting up tuning or auto-calibration + if (this->tune_antenna_) { + ESP_LOGCONFIG(TAG, " Antenna tuning: ENABLED - lightning detection will not function in this mode"); + this->tune_antenna(); + } else if (this->calibration_) { + this->calibrate_oscillator(); + } } void AS3935Component::dump_config() { @@ -227,6 +235,87 @@ uint32_t AS3935Component::get_lightning_energy_() { return pure_light; } +// REG0x03, bit [7:6], manufacturer default: 0 (16 division ratio). +// This function returns the current division ratio of the resonance frequency. +// The antenna resonance frequency should be within 3.5 percent of 500kHz, and +// so when modifying the resonance frequency with the internal capacitors +// (tuneCap()) it's important to keep in mind that the displayed frequency on +// the IRQ pin is divided by this number. +uint8_t AS3935Component::read_div_ratio() { + ESP_LOGV(TAG, "Calling read_div_ratio"); + uint8_t reg_val = this->read_register_(INT_MASK_ANT, DIV_MASK); + reg_val >>= 6; // Front of the line. + + if (reg_val == 0) { + return 16; + } else if (reg_val == 1) { + return 32; + } else if (reg_val == 2) { + return 64; + } else if (reg_val == 3) { + return 128; + } + ESP_LOGW(TAG, "Unknown response received for div_ratio"); + return 0; +} + +uint8_t AS3935Component::read_capacitance() { + ESP_LOGV(TAG, "Calling read_capacitance"); + uint8_t reg_val = this->read_register_(FREQ_DISP_IRQ, CAP_MASK) * 8; + return (reg_val); +} + +// REG0x08, bits [5,6,7], manufacturer default: 0. +// This will send the frequency of the oscillators to the IRQ pin. +// _osc 1, bit[5] = TRCO - System RCO at 32.768kHz +// _osc 2, bit[6] = SRCO - Timer RCO Oscillators 1.1MHz +// _osc 3, bit[7] = LCO - Frequency of the Antenna +void AS3935Component::display_oscillator(bool state, uint8_t osc) { + if ((osc < 1) || (osc > 3)) + return; + + this->write_register(FREQ_DISP_IRQ, OSC_MASK, state, 4 + osc); +} + +// REG0x3D, bits[7:0] +// This function calibrates both internal oscillators The oscillators are tuned +// based on the resonance frequency of the antenna and so it should be trimmed +// before the calibration is done. +bool AS3935Component::calibrate_oscillator() { + ESP_LOGI(TAG, "Starting oscillators calibration..."); + this->write_register(CALIB_RCO, WIPE_ALL, DIRECT_COMMAND, 0); // Send command to calibrate the oscillators + + this->display_oscillator(true, 2); + delay(2); // Give time for the internal oscillators to start up. + this->display_oscillator(false, 2); + + // Check it they were calibrated successfully. + uint8_t reg_val_srco = this->read_register_(CALIB_SRCO, CALIB_MASK_NOK); + uint8_t reg_val_trco = this->read_register_(CALIB_TRCO, CALIB_MASK_NOK); + + // reg_val_srco &= CALIB_MASK; + // reg_val_srco >>= 6; + // reg_val_trco &= CALIB_MASK; + // reg_val_trco >>= 6; + if (!reg_val_srco && !reg_val_trco) { // Zero upon success + ESP_LOGI(TAG, "Calibration was succesful"); + return true; + } else { + ESP_LOGW(TAG, "Calibration was NOT succesful"); + return false; + } +} + +void AS3935Component::tune_antenna() { + ESP_LOGI(TAG, "Starting antenna tuning..."); + uint8_t div_ratio = this->read_div_ratio(); + uint8_t tune_val = this->read_capacitance(); + ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio); + ESP_LOGI(TAG, "Internal Capacitor is set to: %d", tune_val); + ESP_LOGI(TAG, "Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio"); + this->display_oscillator(true, ANTFREQ); +} + uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) { uint8_t value = this->read_register(reg); value &= (~mask); diff --git a/esphome/components/as3935/as3935.h b/esphome/components/as3935/as3935.h index a8af703a59..dc590c268e 100644 --- a/esphome/components/as3935/as3935.h +++ b/esphome/components/as3935/as3935.h @@ -13,6 +13,9 @@ namespace esphome { namespace as3935 { +static const uint8_t DIRECT_COMMAND = 0x96; +static const uint8_t ANTFREQ = 3; + enum AS3935RegisterNames { AFE_GAIN = 0x00, THRESHOLD, @@ -30,6 +33,7 @@ enum AS3935RegisterNames { }; enum AS3935RegisterMasks { + WIPE_ALL = 0x0, GAIN_MASK = 0x3E, SPIKE_MASK = 0xF, IO_MASK = 0xC1, @@ -44,6 +48,7 @@ enum AS3935RegisterMasks { NOISE_FLOOR_MASK = 0x70, OSC_MASK = 0xE0, CALIB_MASK = 0x7F, + CALIB_MASK_NOK = 0xBF, DIV_MASK = 0x3F }; @@ -90,6 +95,13 @@ class AS3935Component : public Component { void write_div_ratio(uint8_t div_ratio); void set_capacitance(uint8_t capacitance) { capacitance_ = capacitance; } void write_capacitance(uint8_t capacitance); + uint8_t read_div_ratio(); + uint8_t read_capacitance(); + bool calibrate_oscillator(); + void display_oscillator(bool state, uint8_t osc); + void tune_antenna(); + void set_tune_antenna(bool tune_antenna) { tune_antenna_ = tune_antenna; } + void set_calibration(bool calibration) { calibration_ = calibration; } protected: uint8_t read_interrupt_register_(); @@ -112,6 +124,8 @@ class AS3935Component : public Component { bool mask_disturber_; uint8_t div_ratio_; uint8_t capacitance_; + bool tune_antenna_; + bool calibration_; }; } // namespace as3935 diff --git a/esphome/const.py b/esphome/const.py index 01555c35ec..fc67651193 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -783,6 +783,7 @@ CONF_TRACES = "traces" CONF_TRANSITION_LENGTH = "transition_length" CONF_TRIGGER_ID = "trigger_id" CONF_TRIGGER_PIN = "trigger_pin" +CONF_TUNE_ANTENNA = "tune_antenna" CONF_TURN_OFF_ACTION = "turn_off_action" CONF_TURN_ON_ACTION = "turn_on_action" CONF_TVOC = "tvoc" From 2fc4e8827131f3199a2e15c64201eed1312d0688 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Wed, 11 Oct 2023 20:51:29 -0500 Subject: [PATCH 0591/2607] Small fixes for voice assistant (#5513) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 26 +++++++++----- .../voice_assistant/voice_assistant.cpp | 36 ++++++++++++++----- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index a0934e3844..592a27b739 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -11,7 +11,7 @@ namespace esphome { namespace i2s_audio { -static const size_t BUFFER_COUNT = 10; +static const size_t BUFFER_COUNT = 20; static const char *const TAG = "i2s_audio.speaker"; @@ -19,7 +19,7 @@ void I2SAudioSpeaker::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker..."); this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent)); - this->event_queue_ = xQueueCreate(20, sizeof(TaskEvent)); + this->event_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(TaskEvent)); } void I2SAudioSpeaker::start() { this->state_ = speaker::STATE_STARTING; } @@ -47,7 +47,7 @@ void I2SAudioSpeaker::player_task(void *params) { .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, - .dma_buf_len = 1024, + .dma_buf_len = 128, .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = I2S_PIN_NO_CHANGE, @@ -60,7 +60,17 @@ void I2SAudioSpeaker::player_task(void *params) { } #endif - i2s_driver_install(this_speaker->parent_->get_port(), &config, 0, nullptr); + esp_err_t err = i2s_driver_install(this_speaker->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + event.type = TaskEventType::WARNING; + event.err = err; + xQueueSend(this_speaker->event_queue_, &event, 0); + event.type = TaskEventType::STOPPED; + xQueueSend(this_speaker->event_queue_, &event, 0); + while (true) { + delay(10); + } + } #if SOC_I2S_SUPPORTS_DAC if (this_speaker->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) { @@ -88,9 +98,7 @@ void I2SAudioSpeaker::player_task(void *params) { } if (data_event.stop) { // Stop signal from main thread - while (xQueueReceive(this_speaker->buffer_queue_, &data_event, 0) == pdTRUE) { - // Flush queue - } + xQueueReset(this_speaker->buffer_queue_); // Flush queue break; } size_t bytes_written; @@ -103,7 +111,7 @@ void I2SAudioSpeaker::player_task(void *params) { uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF); esp_err_t err = i2s_write(this_speaker->parent_->get_port(), &sample, sizeof(sample), &bytes_written, - (100 / portTICK_PERIOD_MS)); + (10 / portTICK_PERIOD_MS)); if (err != ESP_OK) { event = {.type = TaskEventType::WARNING, .err = err}; xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); @@ -122,7 +130,6 @@ void I2SAudioSpeaker::player_task(void *params) { event.type = TaskEventType::STOPPING; xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); - i2s_stop(this_speaker->parent_->get_port()); i2s_driver_uninstall(this_speaker->parent_->get_port()); event.type = TaskEventType::STOPPED; @@ -162,6 +169,7 @@ void I2SAudioSpeaker::watch_() { vTaskDelete(this->player_task_handle_); this->player_task_handle_ = nullptr; this->parent_->unlock(); + xQueueReset(this->buffer_queue_); break; case TaskEventType::WARNING: ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 802ae508ff..448df61d80 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -188,6 +188,9 @@ void VoiceAssistant::loop() { } else { ESP_LOGD(TAG, "VAD detected speech"); this->set_state_(State::START_PIPELINE, State::STREAMING_MICROPHONE); + + // Reset for next time + this->vad_counter_ = 0; } } else { if (this->vad_counter_ > 0) { @@ -270,13 +273,18 @@ void VoiceAssistant::loop() { this->speaker_buffer_size_ += len; } } else { - ESP_LOGW(TAG, "Speaker buffer full."); + ESP_LOGW(TAG, "Receive buffer full."); } if (this->speaker_buffer_size_ > 0) { size_t written = this->speaker_->play(this->speaker_buffer_, this->speaker_buffer_size_); - memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); - this->speaker_buffer_size_ -= written; - this->speaker_buffer_index_ -= written; + if (written > 0) { + memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); + this->speaker_buffer_size_ -= written; + this->speaker_buffer_index_ -= written; + this->set_timeout("speaker-timeout", 1000, [this]() { this->speaker_->stop(); }); + } else { + ESP_LOGW(TAG, "Speaker buffer full."); + } } playing = this->speaker_->is_running(); } @@ -287,7 +295,10 @@ void VoiceAssistant::loop() { } #endif if (playing) { - this->set_timeout("playing", 100, [this]() { this->set_state_(State::IDLE, State::IDLE); }); + this->set_timeout("playing", 100, [this]() { + this->cancel_timeout("speaker-timeout"); + this->set_state_(State::IDLE, State::IDLE); + }); } break; } @@ -483,8 +494,17 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } case api::enums::VOICE_ASSISTANT_RUN_END: { ESP_LOGD(TAG, "Assist Pipeline ended"); - if (this->state_ != State::STREAMING_RESPONSE && this->state_ != State::IDLE) { - this->set_state_(State::IDLE, State::IDLE); + if (this->state_ == State::STREAMING_MICROPHONE) { +#ifdef USE_ESP_ADF + if (this->use_wake_word_) { + rb_reset(this->ring_buffer_); + // No need to stop the microphone since we didn't use the speaker + this->set_state_(State::WAIT_FOR_VAD, State::WAITING_FOR_VAD); + } else +#endif + { + this->set_state_(State::IDLE, State::IDLE); + } } this->end_trigger_->trigger(); break; @@ -500,7 +520,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } } if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") { - this->set_state_(State::STOP_MICROPHONE, State::IDLE); + // Don't change state here since either the "tts-end" or "run-end" events will do it. return; } ESP_LOGE(TAG, "Error: %s - %s", code.c_str(), message.c_str()); From 689dcd1e2459f70f092222e3826367061b64d3e5 Mon Sep 17 00:00:00 2001 From: Daniel Baulig Date: Wed, 11 Oct 2023 18:55:01 -0700 Subject: [PATCH 0592/2607] Add detail param to allow listing of select options in WebServer REST API (#5503) --- esphome/components/web_server/web_server.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index e350e1b140..dec8fb8e21 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -805,7 +805,12 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM continue; if (request->method() == HTTP_GET) { - std::string data = this->select_json(obj, obj->state, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->select_json(obj, obj->state, detail); request->send(200, "application/json", data.c_str()); return; } From 11727391ad0b5d029eef2f54b4113b1b049a03ce Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:14:43 +1300 Subject: [PATCH 0593/2607] Bump version to 2023.11.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fc67651193..eb7a5dab09 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0-dev" +__version__ = "2023.11.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 54363f1246eeab37375b0c37748b18e8c7570d80 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:14:43 +1300 Subject: [PATCH 0594/2607] Bump version to 2023.10.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fc67651193..5a5b683c2d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0-dev" +__version__ = "2023.10.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From f4ce8b8b6c6ea414f9d05fa7dc0048e1582d4b40 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:52:57 +1300 Subject: [PATCH 0595/2607] Bump curl to 7.74.0-1.3+deb11u10 (#5517) --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 99f15d64b2..5ca36d1c13 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,7 +26,7 @@ RUN \ python3-venv=3.9.2-3 \ iputils-ping=3:20210202-1 \ git=1:2.30.2-1+deb11u2 \ - curl=7.74.0-1.3+deb11u9 \ + curl=7.74.0-1.3+deb11u10 \ openssh-client=1:8.4p1-5+deb11u2 \ python3-cffi=1.14.5-1 \ libcairo2=1.16.0-5 \ From 2910eb2ef70272719a0d2532e7e426d3d59aceb6 Mon Sep 17 00:00:00 2001 From: Nippey Date: Thu, 12 Oct 2023 19:56:30 +0200 Subject: [PATCH 0596/2607] Update htu21d.cpp, fix publishing of heater level (#5520) --- esphome/components/htu21d/htu21d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index 5030ac4d0f..a8133ae32e 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -76,7 +76,7 @@ void HTU21DComponent::update() { if (this->humidity_ != nullptr) this->humidity_->publish_state(humidity); if (this->heater_ != nullptr) - this->heater_->publish_state(humidity); + this->heater_->publish_state(heater_level); this->status_clear_warning(); } From 04b708c336ff93c907fcbbc3a7ab7a812293f8e7 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 12 Oct 2023 20:20:31 +0200 Subject: [PATCH 0597/2607] Splits FastLed test scripts out of test1.yaml (#5522) --- tests/test1.1.yaml | 205 +++++++++++++++++++++++++++++++++++++++++++++ tests/test1.yaml | 139 ------------------------------ 2 files changed, 205 insertions(+), 139 deletions(-) create mode 100644 tests/test1.1.yaml diff --git a/tests/test1.1.yaml b/tests/test1.1.yaml new file mode 100644 index 0000000000..3bad4e0492 --- /dev/null +++ b/tests/test1.1.yaml @@ -0,0 +1,205 @@ +--- +substitutions: + devicename: test1_1 + sensorname: my + textname: template + roomname: fastled_room + +esphome: + name: test1-1 + name_add_mac_suffix: true + platform: ESP32 + board: nodemcu-32s + platformio_options: + board_build.partitions: huge_app.csv + on_loop: + then: + - light.addressable_set: + id: addr1 + range_from: 0 + range_to: 100 + red: 100% + green: !lambda "return 255;" + blue: 0% + white: 100% + +wled: + +wifi: + networks: + - ssid: "MySSID" + password: "password1" + +uart: + - id: adalight_uart + tx_pin: GPIO25 + rx_pin: GPIO26 + baud_rate: 115200 + rx_buffer_size: 1024 + +adalight: + +network: + +e131: + +power_supply: + id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + pin: + number: 13 + inverted: true + +i2c: + sda: 21 + scl: 22 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +pca9685: + frequency: 500 + address: 0x0 + i2c_id: i2c_bus + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + +light: + - platform: rgb + name: Living Room Lights + id: ${roomname}_lights + red: pca_0 + green: pca_1 + blue: pca_2 + - platform: fastled_clockless + id: addr1 + chipset: WS2811 + pin: GPIO23 + num_leds: 60 + rgb_order: BRG + max_refresh_rate: 20ms + power_supply: atx_power_supply + color_correct: [75%, 100%, 50%] + name: FastLED WS2811 Light + effects: + - addressable_color_wipe: + - addressable_color_wipe: + name: Color Wipe Effect With Custom Values + colors: + - red: 100% + green: 100% + blue: 100% + num_leds: 1 + - red: 0% + green: 0% + blue: 0% + num_leds: 1 + add_led_interval: 100ms + reverse: false + - addressable_scan: + - addressable_scan: + name: Scan Effect With Custom Values + move_interval: 100ms + - addressable_twinkle: + - addressable_twinkle: + name: Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 4ms + - addressable_random_twinkle: + - addressable_random_twinkle: + name: Random Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 32ms + - addressable_fireworks: + - addressable_fireworks: + name: Fireworks Effect With Custom Values + update_interval: 32ms + spark_probability: 10% + use_random_color: false + fade_out_rate: 120 + - addressable_flicker: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + - addressable_lambda: + name: Test For Custom Lambda Effect + lambda: |- + if (initial_run) { + it[0] = current_color; + } + + - wled: + port: 11111 + + - adalight: + uart_id: adalight_uart + + - e131: + universe: 1 + + - automation: + name: Custom Effect + sequence: + - light.addressable_set: + id: addr1 + red: 100% + green: 100% + blue: 0% + - delay: 100ms + - light.addressable_set: + id: addr1 + red: 0% + green: 100% + blue: 0% + + - platform: fastled_spi + id: addr2 + chipset: WS2801 + data_pin: GPIO23 + clock_pin: GPIO22 + data_rate: 2MHz + num_leds: 60 + rgb_order: BRG + name: FastLED SPI Light + - platform: neopixelbus + id: addr3 + name: Neopixelbus Light + gamma_correct: 2.8 + color_correct: [0.0, 0.0, 0.0, 0.0] + default_transition_length: 10s + power_supply: atx_power_supply + effects: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + type: GRBW + variant: SK6812 + method: ESP32_I2S_0 + num_leds: 60 + pin: GPIO23 + - platform: partition + name: Partition Light + segments: + - id: addr1 + from: 0 + to: 0 + - id: addr2 + from: 1 + to: 10 + - id: addr2 + from: 20 + to: 25 + - single_light_id: ${roomname}_lights diff --git a/tests/test1.yaml b/tests/test1.yaml index c504012481..6d42e325d8 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -25,14 +25,6 @@ esphome: then: - lambda: >- ESP_LOGV("main", "ON LOOP!"); - - light.addressable_set: - id: addr1 - range_from: 0 - range_to: 100 - red: 100% - green: !lambda "return 255;" - blue: 0% - white: 100% - http_request.get: url: https://esphome.io headers: @@ -222,12 +214,6 @@ uart: - lambda: UARTDebug::log_string(direction, bytes); - lambda: UARTDebug::log_int(direction, bytes, ','); - lambda: UARTDebug::log_binary(direction, bytes, ';'); - - - id: adalight_uart - tx_pin: GPIO25 - rx_pin: GPIO26 - baud_rate: 115200 - rx_buffer_size: 1024 - id: ld2410_uart tx_pin: 18 rx_pin: 23 @@ -300,10 +286,6 @@ as3935_spi: cs_pin: GPIO12 irq_pin: GPIO13 -wled: - -adalight: - esp32_ble: io_capability: keyboard_only @@ -2073,8 +2055,6 @@ output: ud_pin: GPIO27 initial_value: 0.5 -e131: - light: - platform: binary name: Desk Lamp @@ -2163,125 +2143,6 @@ light: brightness: pca_6 cold_white_color_temperature: 153 mireds warm_white_color_temperature: 500 mireds - - platform: fastled_clockless - id: addr1 - chipset: WS2811 - pin: GPIO23 - num_leds: 60 - rgb_order: BRG - max_refresh_rate: 20ms - power_supply: atx_power_supply - color_correct: [75%, 100%, 50%] - name: FastLED WS2811 Light - effects: - - addressable_color_wipe: - - addressable_color_wipe: - name: Color Wipe Effect With Custom Values - colors: - - red: 100% - green: 100% - blue: 100% - num_leds: 1 - - red: 0% - green: 0% - blue: 0% - num_leds: 1 - add_led_interval: 100ms - reverse: false - - addressable_scan: - - addressable_scan: - name: Scan Effect With Custom Values - move_interval: 100ms - - addressable_twinkle: - - addressable_twinkle: - name: Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 4ms - - addressable_random_twinkle: - - addressable_random_twinkle: - name: Random Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 32ms - - addressable_fireworks: - - addressable_fireworks: - name: Fireworks Effect With Custom Values - update_interval: 32ms - spark_probability: 10% - use_random_color: false - fade_out_rate: 120 - - addressable_flicker: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - - addressable_lambda: - name: Test For Custom Lambda Effect - lambda: |- - if (initial_run) { - it[0] = current_color; - } - - - wled: - port: 11111 - - - adalight: - uart_id: adalight_uart - - - automation: - name: Custom Effect - sequence: - - light.addressable_set: - id: addr1 - red: 100% - green: 100% - blue: 0% - - delay: 100ms - - light.addressable_set: - id: addr1 - red: 0% - green: 100% - blue: 0% - - e131: - universe: 1 - - platform: fastled_spi - id: addr2 - chipset: WS2801 - data_pin: GPIO23 - clock_pin: GPIO22 - data_rate: 2MHz - num_leds: 60 - rgb_order: BRG - name: FastLED SPI Light - - platform: neopixelbus - id: addr3 - name: Neopixelbus Light - gamma_correct: 2.8 - color_correct: [0.0, 0.0, 0.0, 0.0] - default_transition_length: 10s - power_supply: atx_power_supply - effects: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - type: GRBW - variant: SK6812 - method: ESP32_I2S_0 - num_leds: 60 - pin: GPIO23 - - platform: partition - name: Partition Light - segments: - - id: addr1 - from: 0 - to: 0 - - id: addr2 - from: 1 - to: 10 - - id: addr2 - from: 20 - to: 25 - - single_light_id: ${roomname}_lights remote_transmitter: - pin: 32 From 7c890d8ebc2daf91268d1758548076880d0b7c64 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:09:07 -0500 Subject: [PATCH 0598/2607] BD5758D - Add delays and ACKs (#5524) --- esphome/components/bp5758d/bp5758d.cpp | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/esphome/components/bp5758d/bp5758d.cpp b/esphome/components/bp5758d/bp5758d.cpp index 71a81f7e6c..87c4165275 100644 --- a/esphome/components/bp5758d/bp5758d.cpp +++ b/esphome/components/bp5758d/bp5758d.cpp @@ -17,12 +17,16 @@ static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000; static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000; static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111; +static const uint8_t BP5758D_DELAY = 2; + void BP5758D::setup() { ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component..."); this->data_pin_->setup(); this->data_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); this->clock_pin_->setup(); this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); this->channel_current_.resize(5, 0); this->pwm_amounts_.resize(5, 0); } @@ -39,11 +43,11 @@ void BP5758D::loop() { uint8_t data[17]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - for (int i = 1; i < 16; i++) + for (int i = 1; i < 17; i++) data[i] = 0; // First turn all channels off - data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH; + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH; this->write_buffer_(data, 17); // Then sleep data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; @@ -123,28 +127,42 @@ void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) { void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; } void BP5758D::write_bit_(bool value) { - this->clock_pin_->digital_write(false); this->data_pin_->digital_write(value); + delayMicroseconds(BP5758D_DELAY); this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); } void BP5758D::write_byte_(uint8_t data) { for (uint8_t mask = 0x80; mask; mask >>= 1) { this->write_bit_(data & mask); } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); + + // ack bit + this->data_pin_->pin_mode(gpio::FLAG_INPUT); this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); } void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) { this->data_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + for (uint32_t i = 0; i < size; i++) { this->write_byte_(buffer[i]); } - this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); this->data_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); } } // namespace bp5758d From 33ebfd221ea5c0000a67da326eff16dcbe71581f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Oct 2023 12:46:46 +1300 Subject: [PATCH 0599/2607] Update Improv BLE component (#5518) --- .../esp32_ble_server/ble_service.cpp | 2 + .../components/esp32_ble_server/ble_service.h | 2 +- esphome/components/esp32_improv/__init__.py | 2 +- .../esp32_improv/esp32_improv_component.cpp | 79 +++++++++++-------- .../esp32_improv/esp32_improv_component.h | 29 +++++-- esphome/components/output/__init__.py | 1 + esphome/core/defines.h | 3 +- 7 files changed, 79 insertions(+), 39 deletions(-) diff --git a/esphome/components/esp32_ble_server/ble_service.cpp b/esphome/components/esp32_ble_server/ble_service.cpp index 4fcd2e3e79..e5aaebc137 100644 --- a/esphome/components/esp32_ble_server/ble_service.cpp +++ b/esphome/components/esp32_ble_server/ble_service.cpp @@ -90,6 +90,8 @@ void BLEService::stop() { ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); return; } + esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_); + esp32_ble::global_ble->get_advertising()->start(); this->running_state_ = STOPPING; } diff --git a/esphome/components/esp32_ble_server/ble_service.h b/esphome/components/esp32_ble_server/ble_service.h index 2766c931a7..93b4217517 100644 --- a/esphome/components/esp32_ble_server/ble_service.h +++ b/esphome/components/esp32_ble_server/ble_service.h @@ -7,11 +7,11 @@ #ifdef USE_ESP32 +#include #include #include #include #include -#include namespace esphome { namespace esp32_ble_server { diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index ae7f0b6427..fba2e55ae8 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -4,7 +4,7 @@ from esphome.components import binary_sensor, output, esp32_ble_server from esphome.const import CONF_ID -AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"] +AUTO_LOAD = ["esp32_ble_server"] CODEOWNERS = ["@jesserockz"] CONFLICTS_WITH = ["esp32_ble_beacon"] DEPENDENCIES = ["wifi", "esp32"] diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 85013c006b..5bdf7d19fe 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -18,6 +18,17 @@ ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; } void ESP32ImprovComponent::setup() { this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true); this->setup_characteristics(); + +#ifdef USE_BINARY_SENSOR + if (this->authorizer_ != nullptr) { + this->authorizer_->add_on_state_callback([this](bool state) { + if (state) { + this->authorized_start_ = millis(); + this->identify_start_ = 0; + } + }); + } +#endif } void ESP32ImprovComponent::setup_characteristics() { @@ -50,8 +61,10 @@ void ESP32ImprovComponent::setup_characteristics() { BLEDescriptor *capabilities_descriptor = new BLE2902(); this->capabilities_->add_descriptor(capabilities_descriptor); uint8_t capabilities = 0x00; +#ifdef USE_OUTPUT if (this->status_indicator_ != nullptr) capabilities |= improv::CAPABILITY_IDENTIFY; +#endif this->capabilities_->set_value(capabilities); this->setup_complete_ = true; } @@ -63,8 +76,7 @@ void ESP32ImprovComponent::loop() { switch (this->state_) { case improv::STATE_STOPPED: - if (this->status_indicator_ != nullptr) - this->status_indicator_->turn_off(); + this->set_status_indicator_state_(false); if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { if (this->service_->is_running()) { @@ -80,14 +92,17 @@ void ESP32ImprovComponent::loop() { } break; case improv::STATE_AWAITING_AUTHORIZATION: { - if (this->authorizer_ == nullptr || this->authorizer_->state) { +#ifdef USE_BINARY_SENSOR + if (this->authorizer_ == nullptr || + (this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) { this->set_state_(improv::STATE_AUTHORIZED); - this->authorized_start_ = now; - } else { - if (this->status_indicator_ != nullptr) { - if (!this->check_identify_()) - this->status_indicator_->turn_on(); - } + } else +#else + this->set_state_(improv::STATE_AUTHORIZED); +#endif + { + if (!this->check_identify_()) + this->set_status_indicator_state_(true); } break; } @@ -99,25 +114,13 @@ void ESP32ImprovComponent::loop() { return; } } - if (this->status_indicator_ != nullptr) { - if (!this->check_identify_()) { - if ((now % 1000) < 500) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } - } + if (!this->check_identify_()) { + this->set_status_indicator_state_((now % 1000) < 500); } break; } case improv::STATE_PROVISIONING: { - if (this->status_indicator_ != nullptr) { - if ((now % 200) < 100) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } - } + this->set_status_indicator_state_((now % 200) < 100); if (wifi::global_wifi_component->is_connected()) { wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), this->connecting_sta_.get_password()); @@ -142,13 +145,27 @@ void ESP32ImprovComponent::loop() { } case improv::STATE_PROVISIONED: { this->incoming_data_.clear(); - if (this->status_indicator_ != nullptr) - this->status_indicator_->turn_off(); + this->set_status_indicator_state_(false); break; } } } +void ESP32ImprovComponent::set_status_indicator_state_(bool state) { +#ifdef USE_OUTPUT + if (this->status_indicator_ == nullptr) + return; + if (this->status_indicator_state_ == state) + return; + this->status_indicator_state_ = state; + if (state) { + this->status_indicator_->turn_on(); + } else { + this->status_indicator_->turn_off(); + } +#endif +} + bool ESP32ImprovComponent::check_identify_() { uint32_t now = millis(); @@ -156,11 +173,7 @@ bool ESP32ImprovComponent::check_identify_() { if (identify) { uint32_t time = now % 1000; - if (time < 600 && time % 200 < 100) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } + this->set_status_indicator_state_(time < 600 && time % 200 < 100); } return identify; } @@ -213,8 +226,12 @@ float ESP32ImprovComponent::get_setup_priority() const { return setup_priority:: void ESP32ImprovComponent::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 Improv:"); +#ifdef USE_BINARY_SENSOR LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_); +#endif +#ifdef USE_OUTPUT ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr)); +#endif } void ESP32ImprovComponent::process_incoming_data_() { diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h index 1a142c94b6..ba9892d6a5 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.h +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -1,14 +1,22 @@ #pragma once -#include "esphome/components/binary_sensor/binary_sensor.h" -#include "esphome/components/esp32_ble_server/ble_characteristic.h" -#include "esphome/components/esp32_ble_server/ble_server.h" -#include "esphome/components/output/binary_output.h" -#include "esphome/components/wifi/wifi_component.h" #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" +#include "esphome/components/esp32_ble_server/ble_characteristic.h" +#include "esphome/components/esp32_ble_server/ble_server.h" +#include "esphome/components/wifi/wifi_component.h" + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +#ifdef USE_OUTPUT +#include "esphome/components/output/binary_output.h" +#endif + #include #ifdef USE_ESP32 @@ -34,8 +42,12 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void stop() override; bool is_active() const { return this->state_ != improv::STATE_STOPPED; } +#ifdef USE_BINARY_SENSOR void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } +#endif +#ifdef USE_OUTPUT void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; } +#endif void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } @@ -58,12 +70,19 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { BLECharacteristic *rpc_response_; BLECharacteristic *capabilities_; +#ifdef USE_BINARY_SENSOR binary_sensor::BinarySensor *authorizer_{nullptr}; +#endif +#ifdef USE_OUTPUT output::BinaryOutput *status_indicator_{nullptr}; +#endif improv::State state_{improv::STATE_STOPPED}; improv::Error error_state_{improv::ERROR_NONE}; + bool status_indicator_state_{false}; + void set_status_indicator_state_(bool state); + void set_state_(improv::State state); void set_error_(improv::Error error); void send_response_(std::vector &response); diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py index 4f1fb33fe7..726d1ac084 100644 --- a/esphome/components/output/__init__.py +++ b/esphome/components/output/__init__.py @@ -106,4 +106,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args): async def to_code(config): + cg.add_define("USE_OUTPUT") cg.add_global(output_ns.using) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1e0df74eec..71493119c0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -37,6 +37,7 @@ #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK +#define USE_OUTPUT #define USE_POWER_SUPPLY #define USE_QR_CODE #define USE_SELECT @@ -117,6 +118,6 @@ #endif // Disabled feature flags -//#define USE_BSEC // Requires a library with proprietary license. +// #define USE_BSEC // Requires a library with proprietary license. #define USE_DASHBOARD_IMPORT From f5c12b50cea418ca0b8315c294575089f529d120 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:51:19 -0500 Subject: [PATCH 0600/2607] SM10BIT_BASE - Add delays and ACKs, clear all channels before sleeping. (#5526) --- .../components/sm10bit_base/sm10bit_base.cpp | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/esphome/components/sm10bit_base/sm10bit_base.cpp b/esphome/components/sm10bit_base/sm10bit_base.cpp index 9c7abb48e2..d380f31c6f 100644 --- a/esphome/components/sm10bit_base/sm10bit_base.cpp +++ b/esphome/components/sm10bit_base/sm10bit_base.cpp @@ -11,6 +11,8 @@ static const uint8_t SM10BIT_ADDR_START_3CH = 0x8; static const uint8_t SM10BIT_ADDR_START_2CH = 0x10; static const uint8_t SM10BIT_ADDR_START_5CH = 0x18; +static const uint8_t SM10BIT_DELAY = 2; + // Power current values // HEX | Binary | RGB level | White level | Config value // 0x0 | 0000 | RGB 10mA | CW 5mA | 0 @@ -37,10 +39,13 @@ void Sm10BitBase::loop() { uint8_t data[12]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY; for (int i = 1; i < 12; i++) data[i] = 0; + // First turn all channels off + data[0] = this->model_id_ + SM10BIT_ADDR_START_5CH; + this->write_buffer_(data, 12); + // Then sleep + data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY; this->write_buffer_(data, 12); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { @@ -84,28 +89,42 @@ void Sm10BitBase::set_channel_value_(uint8_t channel, uint16_t value) { this->pwm_amounts_[channel] = value; } void Sm10BitBase::write_bit_(bool value) { - this->clock_pin_->digital_write(false); this->data_pin_->digital_write(value); + delayMicroseconds(SM10BIT_DELAY); this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); } void Sm10BitBase::write_byte_(uint8_t data) { for (uint8_t mask = 0x80; mask; mask >>= 1) { this->write_bit_(data & mask); } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); + + // ack bit + this->data_pin_->pin_mode(gpio::FLAG_INPUT); this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); } void Sm10BitBase::write_buffer_(uint8_t *buffer, uint8_t size) { this->data_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + for (uint32_t i = 0; i < size; i++) { this->write_byte_(buffer[i]); } - this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); this->data_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); } } // namespace sm10bit_base From da3e3903ddb36f5a5c3161bf6e23c8eadfdcfbbe Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:51:28 -0500 Subject: [PATCH 0601/2607] BP1658CJ - Clear all channels before sleeping. (#5525) --- esphome/components/bp1658cj/bp1658cj.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/bp1658cj/bp1658cj.cpp b/esphome/components/bp1658cj/bp1658cj.cpp index d3f3e71fed..05c3f790c2 100644 --- a/esphome/components/bp1658cj/bp1658cj.cpp +++ b/esphome/components/bp1658cj/bp1658cj.cpp @@ -37,10 +37,14 @@ void BP1658CJ::loop() { uint8_t data[12]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY; for (int i = 1; i < 12; i++) data[i] = 0; + + // First turn all channels off + data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH; + this->write_buffer_(data, 12); + // Then sleep + data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY; this->write_buffer_(data, 12); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { From d27e5e9c97ccb1035c3ef738f0fd22cb36227c7a Mon Sep 17 00:00:00 2001 From: Nippey Date: Thu, 12 Oct 2023 19:56:30 +0200 Subject: [PATCH 0602/2607] Update htu21d.cpp, fix publishing of heater level (#5520) --- esphome/components/htu21d/htu21d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index 5030ac4d0f..a8133ae32e 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -76,7 +76,7 @@ void HTU21DComponent::update() { if (this->humidity_ != nullptr) this->humidity_->publish_state(humidity); if (this->heater_ != nullptr) - this->heater_->publish_state(humidity); + this->heater_->publish_state(heater_level); this->status_clear_warning(); } From 6cce6d4c364104082b77a6ec12ede5243cbe11bb Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:09:07 -0500 Subject: [PATCH 0603/2607] BD5758D - Add delays and ACKs (#5524) --- esphome/components/bp5758d/bp5758d.cpp | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/esphome/components/bp5758d/bp5758d.cpp b/esphome/components/bp5758d/bp5758d.cpp index 71a81f7e6c..87c4165275 100644 --- a/esphome/components/bp5758d/bp5758d.cpp +++ b/esphome/components/bp5758d/bp5758d.cpp @@ -17,12 +17,16 @@ static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000; static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000; static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111; +static const uint8_t BP5758D_DELAY = 2; + void BP5758D::setup() { ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component..."); this->data_pin_->setup(); this->data_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); this->clock_pin_->setup(); this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); this->channel_current_.resize(5, 0); this->pwm_amounts_.resize(5, 0); } @@ -39,11 +43,11 @@ void BP5758D::loop() { uint8_t data[17]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - for (int i = 1; i < 16; i++) + for (int i = 1; i < 17; i++) data[i] = 0; // First turn all channels off - data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH; + data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH; this->write_buffer_(data, 17); // Then sleep data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; @@ -123,28 +127,42 @@ void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) { void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; } void BP5758D::write_bit_(bool value) { - this->clock_pin_->digital_write(false); this->data_pin_->digital_write(value); + delayMicroseconds(BP5758D_DELAY); this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); } void BP5758D::write_byte_(uint8_t data) { for (uint8_t mask = 0x80; mask; mask >>= 1) { this->write_bit_(data & mask); } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); + + // ack bit + this->data_pin_->pin_mode(gpio::FLAG_INPUT); this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); } void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) { this->data_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(BP5758D_DELAY); + for (uint32_t i = 0; i < size; i++) { this->write_byte_(buffer[i]); } - this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); this->data_pin_->digital_write(true); + delayMicroseconds(BP5758D_DELAY); } } // namespace bp5758d From 969f6dbe131824ce0c9e6c23fe9a8b207887f991 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Oct 2023 12:46:46 +1300 Subject: [PATCH 0604/2607] Update Improv BLE component (#5518) --- .../esp32_ble_server/ble_service.cpp | 2 + .../components/esp32_ble_server/ble_service.h | 2 +- esphome/components/esp32_improv/__init__.py | 2 +- .../esp32_improv/esp32_improv_component.cpp | 79 +++++++++++-------- .../esp32_improv/esp32_improv_component.h | 29 +++++-- esphome/components/output/__init__.py | 1 + esphome/core/defines.h | 3 +- 7 files changed, 79 insertions(+), 39 deletions(-) diff --git a/esphome/components/esp32_ble_server/ble_service.cpp b/esphome/components/esp32_ble_server/ble_service.cpp index 4fcd2e3e79..e5aaebc137 100644 --- a/esphome/components/esp32_ble_server/ble_service.cpp +++ b/esphome/components/esp32_ble_server/ble_service.cpp @@ -90,6 +90,8 @@ void BLEService::stop() { ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); return; } + esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_); + esp32_ble::global_ble->get_advertising()->start(); this->running_state_ = STOPPING; } diff --git a/esphome/components/esp32_ble_server/ble_service.h b/esphome/components/esp32_ble_server/ble_service.h index 2766c931a7..93b4217517 100644 --- a/esphome/components/esp32_ble_server/ble_service.h +++ b/esphome/components/esp32_ble_server/ble_service.h @@ -7,11 +7,11 @@ #ifdef USE_ESP32 +#include #include #include #include #include -#include namespace esphome { namespace esp32_ble_server { diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index ae7f0b6427..fba2e55ae8 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -4,7 +4,7 @@ from esphome.components import binary_sensor, output, esp32_ble_server from esphome.const import CONF_ID -AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"] +AUTO_LOAD = ["esp32_ble_server"] CODEOWNERS = ["@jesserockz"] CONFLICTS_WITH = ["esp32_ble_beacon"] DEPENDENCIES = ["wifi", "esp32"] diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 85013c006b..5bdf7d19fe 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -18,6 +18,17 @@ ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; } void ESP32ImprovComponent::setup() { this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true); this->setup_characteristics(); + +#ifdef USE_BINARY_SENSOR + if (this->authorizer_ != nullptr) { + this->authorizer_->add_on_state_callback([this](bool state) { + if (state) { + this->authorized_start_ = millis(); + this->identify_start_ = 0; + } + }); + } +#endif } void ESP32ImprovComponent::setup_characteristics() { @@ -50,8 +61,10 @@ void ESP32ImprovComponent::setup_characteristics() { BLEDescriptor *capabilities_descriptor = new BLE2902(); this->capabilities_->add_descriptor(capabilities_descriptor); uint8_t capabilities = 0x00; +#ifdef USE_OUTPUT if (this->status_indicator_ != nullptr) capabilities |= improv::CAPABILITY_IDENTIFY; +#endif this->capabilities_->set_value(capabilities); this->setup_complete_ = true; } @@ -63,8 +76,7 @@ void ESP32ImprovComponent::loop() { switch (this->state_) { case improv::STATE_STOPPED: - if (this->status_indicator_ != nullptr) - this->status_indicator_->turn_off(); + this->set_status_indicator_state_(false); if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { if (this->service_->is_running()) { @@ -80,14 +92,17 @@ void ESP32ImprovComponent::loop() { } break; case improv::STATE_AWAITING_AUTHORIZATION: { - if (this->authorizer_ == nullptr || this->authorizer_->state) { +#ifdef USE_BINARY_SENSOR + if (this->authorizer_ == nullptr || + (this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) { this->set_state_(improv::STATE_AUTHORIZED); - this->authorized_start_ = now; - } else { - if (this->status_indicator_ != nullptr) { - if (!this->check_identify_()) - this->status_indicator_->turn_on(); - } + } else +#else + this->set_state_(improv::STATE_AUTHORIZED); +#endif + { + if (!this->check_identify_()) + this->set_status_indicator_state_(true); } break; } @@ -99,25 +114,13 @@ void ESP32ImprovComponent::loop() { return; } } - if (this->status_indicator_ != nullptr) { - if (!this->check_identify_()) { - if ((now % 1000) < 500) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } - } + if (!this->check_identify_()) { + this->set_status_indicator_state_((now % 1000) < 500); } break; } case improv::STATE_PROVISIONING: { - if (this->status_indicator_ != nullptr) { - if ((now % 200) < 100) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } - } + this->set_status_indicator_state_((now % 200) < 100); if (wifi::global_wifi_component->is_connected()) { wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), this->connecting_sta_.get_password()); @@ -142,13 +145,27 @@ void ESP32ImprovComponent::loop() { } case improv::STATE_PROVISIONED: { this->incoming_data_.clear(); - if (this->status_indicator_ != nullptr) - this->status_indicator_->turn_off(); + this->set_status_indicator_state_(false); break; } } } +void ESP32ImprovComponent::set_status_indicator_state_(bool state) { +#ifdef USE_OUTPUT + if (this->status_indicator_ == nullptr) + return; + if (this->status_indicator_state_ == state) + return; + this->status_indicator_state_ = state; + if (state) { + this->status_indicator_->turn_on(); + } else { + this->status_indicator_->turn_off(); + } +#endif +} + bool ESP32ImprovComponent::check_identify_() { uint32_t now = millis(); @@ -156,11 +173,7 @@ bool ESP32ImprovComponent::check_identify_() { if (identify) { uint32_t time = now % 1000; - if (time < 600 && time % 200 < 100) { - this->status_indicator_->turn_on(); - } else { - this->status_indicator_->turn_off(); - } + this->set_status_indicator_state_(time < 600 && time % 200 < 100); } return identify; } @@ -213,8 +226,12 @@ float ESP32ImprovComponent::get_setup_priority() const { return setup_priority:: void ESP32ImprovComponent::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 Improv:"); +#ifdef USE_BINARY_SENSOR LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_); +#endif +#ifdef USE_OUTPUT ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr)); +#endif } void ESP32ImprovComponent::process_incoming_data_() { diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h index 1a142c94b6..ba9892d6a5 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.h +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -1,14 +1,22 @@ #pragma once -#include "esphome/components/binary_sensor/binary_sensor.h" -#include "esphome/components/esp32_ble_server/ble_characteristic.h" -#include "esphome/components/esp32_ble_server/ble_server.h" -#include "esphome/components/output/binary_output.h" -#include "esphome/components/wifi/wifi_component.h" #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" +#include "esphome/components/esp32_ble_server/ble_characteristic.h" +#include "esphome/components/esp32_ble_server/ble_server.h" +#include "esphome/components/wifi/wifi_component.h" + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +#ifdef USE_OUTPUT +#include "esphome/components/output/binary_output.h" +#endif + #include #ifdef USE_ESP32 @@ -34,8 +42,12 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void stop() override; bool is_active() const { return this->state_ != improv::STATE_STOPPED; } +#ifdef USE_BINARY_SENSOR void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } +#endif +#ifdef USE_OUTPUT void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; } +#endif void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } @@ -58,12 +70,19 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { BLECharacteristic *rpc_response_; BLECharacteristic *capabilities_; +#ifdef USE_BINARY_SENSOR binary_sensor::BinarySensor *authorizer_{nullptr}; +#endif +#ifdef USE_OUTPUT output::BinaryOutput *status_indicator_{nullptr}; +#endif improv::State state_{improv::STATE_STOPPED}; improv::Error error_state_{improv::ERROR_NONE}; + bool status_indicator_state_{false}; + void set_status_indicator_state_(bool state); + void set_state_(improv::State state); void set_error_(improv::Error error); void send_response_(std::vector &response); diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py index 4f1fb33fe7..726d1ac084 100644 --- a/esphome/components/output/__init__.py +++ b/esphome/components/output/__init__.py @@ -106,4 +106,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args): async def to_code(config): + cg.add_define("USE_OUTPUT") cg.add_global(output_ns.using) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1e0df74eec..71493119c0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -37,6 +37,7 @@ #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK +#define USE_OUTPUT #define USE_POWER_SUPPLY #define USE_QR_CODE #define USE_SELECT @@ -117,6 +118,6 @@ #endif // Disabled feature flags -//#define USE_BSEC // Requires a library with proprietary license. +// #define USE_BSEC // Requires a library with proprietary license. #define USE_DASHBOARD_IMPORT From 8c1ad1e9a6816d2d59cb768d8d9638359625a195 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:51:19 -0500 Subject: [PATCH 0605/2607] SM10BIT_BASE - Add delays and ACKs, clear all channels before sleeping. (#5526) --- .../components/sm10bit_base/sm10bit_base.cpp | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/esphome/components/sm10bit_base/sm10bit_base.cpp b/esphome/components/sm10bit_base/sm10bit_base.cpp index 9c7abb48e2..d380f31c6f 100644 --- a/esphome/components/sm10bit_base/sm10bit_base.cpp +++ b/esphome/components/sm10bit_base/sm10bit_base.cpp @@ -11,6 +11,8 @@ static const uint8_t SM10BIT_ADDR_START_3CH = 0x8; static const uint8_t SM10BIT_ADDR_START_2CH = 0x10; static const uint8_t SM10BIT_ADDR_START_5CH = 0x18; +static const uint8_t SM10BIT_DELAY = 2; + // Power current values // HEX | Binary | RGB level | White level | Config value // 0x0 | 0000 | RGB 10mA | CW 5mA | 0 @@ -37,10 +39,13 @@ void Sm10BitBase::loop() { uint8_t data[12]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY; for (int i = 1; i < 12; i++) data[i] = 0; + // First turn all channels off + data[0] = this->model_id_ + SM10BIT_ADDR_START_5CH; + this->write_buffer_(data, 12); + // Then sleep + data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY; this->write_buffer_(data, 12); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { @@ -84,28 +89,42 @@ void Sm10BitBase::set_channel_value_(uint8_t channel, uint16_t value) { this->pwm_amounts_[channel] = value; } void Sm10BitBase::write_bit_(bool value) { - this->clock_pin_->digital_write(false); this->data_pin_->digital_write(value); + delayMicroseconds(SM10BIT_DELAY); this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); } void Sm10BitBase::write_byte_(uint8_t data) { for (uint8_t mask = 0x80; mask; mask >>= 1) { this->write_bit_(data & mask); } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); + + // ack bit + this->data_pin_->pin_mode(gpio::FLAG_INPUT); this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); } void Sm10BitBase::write_buffer_(uint8_t *buffer, uint8_t size) { this->data_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + this->clock_pin_->digital_write(false); + delayMicroseconds(SM10BIT_DELAY); + for (uint32_t i = 0; i < size; i++) { this->write_byte_(buffer[i]); } - this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); this->data_pin_->digital_write(true); + delayMicroseconds(SM10BIT_DELAY); } } // namespace sm10bit_base From 5d7c3d16224ff4ce8b7afaa91907b95b9c29b7c2 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:51:28 -0500 Subject: [PATCH 0606/2607] BP1658CJ - Clear all channels before sleeping. (#5525) --- esphome/components/bp1658cj/bp1658cj.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/bp1658cj/bp1658cj.cpp b/esphome/components/bp1658cj/bp1658cj.cpp index d3f3e71fed..05c3f790c2 100644 --- a/esphome/components/bp1658cj/bp1658cj.cpp +++ b/esphome/components/bp1658cj/bp1658cj.cpp @@ -37,10 +37,14 @@ void BP1658CJ::loop() { uint8_t data[12]; if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { - // Off / Sleep - data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY; for (int i = 1; i < 12; i++) data[i] = 0; + + // First turn all channels off + data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH; + this->write_buffer_(data, 12); + // Then sleep + data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY; this->write_buffer_(data, 12); } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { From 90315b3c401f608ae3dbe6f3cf89d6ef000c7510 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:16:22 +1300 Subject: [PATCH 0607/2607] Bump version to 2023.10.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5a5b683c2d..cef733b2f9 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0b1" +__version__ = "2023.10.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7ddcdab35130ab54ba4735623df2aab95dcf3ce6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 14 Oct 2023 13:07:23 +1300 Subject: [PATCH 0608/2607] Add round sensor filter (#5532) --- esphome/components/sensor/__init__.py | 18 ++++++++++++++++++ esphome/components/sensor/filter.cpp | 9 +++++++++ esphome/components/sensor/filter.h | 9 +++++++++ 3 files changed, 36 insertions(+) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index ee42011038..bd7306ac28 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -242,6 +242,7 @@ CalibrateLinearFilter = sensor_ns.class_("CalibrateLinearFilter", Filter) CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter) SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter) ClampFilter = sensor_ns.class_("ClampFilter", Filter) +RoundFilter = sensor_ns.class_("RoundFilter", Filter) validate_unit_of_measurement = cv.string_strict validate_accuracy_decimals = cv.int_ @@ -702,6 +703,23 @@ async def clamp_filter_to_code(config, filter_id): ) +@FILTER_REGISTRY.register( + "round", + RoundFilter, + cv.maybe_simple_value( + { + cv.Required(CONF_ACCURACY_DECIMALS): cv.uint8_t, + }, + key=CONF_ACCURACY_DECIMALS, + ), +) +async def round_filter_to_code(config, filter_id): + return cg.new_Pvariable( + filter_id, + config[CONF_ACCURACY_DECIMALS], + ) + + async def build_filters(config): return await cg.build_registry_list(FILTER_REGISTRY, config) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 6323023d50..af67a60754 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -445,5 +445,14 @@ optional ClampFilter::new_value(float value) { return value; } +RoundFilter::RoundFilter(uint8_t precision) : precision_(precision) {} +optional RoundFilter::new_value(float value) { + if (std::isfinite(value)) { + float accuracy_mult = powf(10.0f, this->precision_); + return roundf(accuracy_mult * value) / accuracy_mult; + } + return value; +} + } // namespace sensor } // namespace esphome diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 46aeefac56..d4239837b6 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -419,5 +419,14 @@ class ClampFilter : public Filter { float max_{NAN}; }; +class RoundFilter : public Filter { + public: + explicit RoundFilter(uint8_t precision); + optional new_value(float value) override; + + protected: + uint8_t precision_; +}; + } // namespace sensor } // namespace esphome From 6143099f60d1c76e3faa0da3e75cb3fd25e5ebf1 Mon Sep 17 00:00:00 2001 From: ghsensdev <145111396+ghsensdev@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:49:57 +0200 Subject: [PATCH 0609/2607] Add Support for Sensirion SFA30 sensor (#5519) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/sfa30/__init__.py | 1 + esphome/components/sfa30/sensor.py | 78 ++++++++++++++++++++++ esphome/components/sfa30/sfa30.cpp | 99 ++++++++++++++++++++++++++++ esphome/components/sfa30/sfa30.h | 34 ++++++++++ tests/test1.yaml | 10 +++ 6 files changed, 223 insertions(+) create mode 100644 esphome/components/sfa30/__init__.py create mode 100644 esphome/components/sfa30/sensor.py create mode 100644 esphome/components/sfa30/sfa30.cpp create mode 100644 esphome/components/sfa30/sfa30.h diff --git a/CODEOWNERS b/CODEOWNERS index d7cf7269ab..326642e12c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -254,6 +254,7 @@ esphome/components/sen21231/* @shreyaskarnik esphome/components/sen5x/* @martgras esphome/components/sensirion_common/* @martgras esphome/components/sensor/* @esphome/core +esphome/components/sfa30/* @ghsensdev esphome/components/sgp40/* @SenexCrenshaw esphome/components/sgp4x/* @SenexCrenshaw @martgras esphome/components/shelly_dimmer/* @edge90 @rnauber diff --git a/esphome/components/sfa30/__init__.py b/esphome/components/sfa30/__init__.py new file mode 100644 index 0000000000..28b665906f --- /dev/null +++ b/esphome/components/sfa30/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@ghsensdev"] diff --git a/esphome/components/sfa30/sensor.py b/esphome/components/sfa30/sensor.py new file mode 100644 index 0000000000..428f6b874b --- /dev/null +++ b/esphome/components/sfa30/sensor.py @@ -0,0 +1,78 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor, sensirion_common + +from esphome.const import ( + CONF_ID, + CONF_FORMALDEHYDE, + CONF_HUMIDITY, + CONF_TEMPERATURE, + DEVICE_CLASS_GAS, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + ICON_RADIATOR, + ICON_WATER_PERCENT, + ICON_THERMOMETER, + STATE_CLASS_MEASUREMENT, + UNIT_PARTS_PER_BILLION, + UNIT_PERCENT, + UNIT_CELSIUS, +) + +CODEOWNERS = ["@ghsensdev"] +DEPENDENCIES = ["i2c"] +AUTO_LOAD = ["sensirion_common"] + +sfa30_ns = cg.esphome_ns.namespace("sfa30") + +SFA30Component = sfa30_ns.class_( + "SFA30Component", cg.PollingComponent, sensirion_common.SensirionI2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(SFA30Component), + cv.Optional(CONF_FORMALDEHYDE): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_BILLION, + icon=ICON_RADIATOR, + accuracy_decimals=1, + device_class=DEVICE_CLASS_GAS, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_WATER_PERCENT, + accuracy_decimals=2, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x5D)) +) + +SENSOR_MAP = { + CONF_FORMALDEHYDE: "set_formaldehyde_sensor", + CONF_HUMIDITY: "set_humidity_sensor", + CONF_TEMPERATURE: "set_temperature_sensor", +} + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + for key, funcName in SENSOR_MAP.items(): + if sensor_config := config.get(key): + sens = await sensor.new_sensor(sensor_config) + cg.add(getattr(var, funcName)(sens)) diff --git a/esphome/components/sfa30/sfa30.cpp b/esphome/components/sfa30/sfa30.cpp new file mode 100644 index 0000000000..20d5ddad5e --- /dev/null +++ b/esphome/components/sfa30/sfa30.cpp @@ -0,0 +1,99 @@ +#include "sfa30.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace sfa30 { + +static const char *const TAG = "sfa30"; + +static const uint16_t SFA30_CMD_GET_DEVICE_MARKING = 0xD060; +static const uint16_t SFA30_CMD_START_CONTINUOUS_MEASUREMENTS = 0x0006; +static const uint16_t SFA30_CMD_READ_MEASUREMENT = 0x0327; + +void SFA30Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up sfa30..."); + + // Serial Number identification + uint16_t raw_device_marking[16]; + if (!this->get_register(SFA30_CMD_GET_DEVICE_MARKING, raw_device_marking, 16, 5)) { + ESP_LOGE(TAG, "Failed to read device marking"); + this->error_code_ = DEVICE_MARKING_READ_FAILED; + this->mark_failed(); + return; + } + + for (size_t i = 0; i < 16; i++) { + this->device_marking_[i * 2] = static_cast(raw_device_marking[i] >> 8); + this->device_marking_[i * 2 + 1] = static_cast(raw_device_marking[i] & 0xFF); + } + ESP_LOGD(TAG, "Device Marking: '%s'", this->device_marking_); + + if (!this->write_command(SFA30_CMD_START_CONTINUOUS_MEASUREMENTS)) { + ESP_LOGE(TAG, "Error starting measurements."); + this->error_code_ = MEASUREMENT_INIT_FAILED; + this->mark_failed(); + return; + } + + ESP_LOGD(TAG, "Sensor initialized"); +} + +void SFA30Component::dump_config() { + ESP_LOGCONFIG(TAG, "sfa30:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + switch (this->error_code_) { + case DEVICE_MARKING_READ_FAILED: + ESP_LOGW(TAG, "Unable to read device marking!"); + break; + case MEASUREMENT_INIT_FAILED: + ESP_LOGW(TAG, "Measurement initialization failed!"); + break; + default: + ESP_LOGW(TAG, "Unknown setup error!"); + break; + } + } + LOG_UPDATE_INTERVAL(this); + ESP_LOGCONFIG(TAG, " Device Marking: '%s'", this->device_marking_); + LOG_SENSOR(" ", "Formaldehyde", this->formaldehyde_sensor_); + LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); +} + +void SFA30Component::update() { + if (!this->write_command(SFA30_CMD_READ_MEASUREMENT)) { + ESP_LOGW(TAG, "Error reading measurement!"); + this->status_set_warning(); + return; + } + + this->set_timeout(5, [this]() { + uint16_t raw_data[3]; + if (!this->read_data(raw_data, 3)) { + ESP_LOGW(TAG, "Error reading measurement data!"); + this->status_set_warning(); + return; + } + + if (this->formaldehyde_sensor_ != nullptr) { + const float formaldehyde = raw_data[0] / 5.0f; + this->formaldehyde_sensor_->publish_state(formaldehyde); + } + + if (this->humidity_sensor_ != nullptr) { + const float humidity = raw_data[1] / 100.0f; + this->humidity_sensor_->publish_state(humidity); + } + + if (this->temperature_sensor_ != nullptr) { + const float temperature = raw_data[2] / 200.0f; + this->temperature_sensor_->publish_state(temperature); + } + + this->status_clear_warning(); + }); +} + +} // namespace sfa30 +} // namespace esphome diff --git a/esphome/components/sfa30/sfa30.h b/esphome/components/sfa30/sfa30.h new file mode 100644 index 0000000000..fa2c59f624 --- /dev/null +++ b/esphome/components/sfa30/sfa30.h @@ -0,0 +1,34 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/sensirion_common/i2c_sensirion.h" + +namespace esphome { +namespace sfa30 { + +class SFA30Component : public PollingComponent, public sensirion_common::SensirionI2CDevice { + enum ErrorCode { DEVICE_MARKING_READ_FAILED, MEASUREMENT_INIT_FAILED, UNKNOWN }; + + public: + float get_setup_priority() const override { return setup_priority::DATA; } + void setup() override; + void dump_config() override; + void update() override; + + void set_formaldehyde_sensor(sensor::Sensor *formaldehyde) { this->formaldehyde_sensor_ = formaldehyde; } + void set_humidity_sensor(sensor::Sensor *humidity) { this->humidity_sensor_ = humidity; } + void set_temperature_sensor(sensor::Sensor *temperature) { this->temperature_sensor_ = temperature; } + + protected: + char device_marking_[32] = {0}; + + ErrorCode error_code_{UNKNOWN}; + + sensor::Sensor *formaldehyde_sensor_{nullptr}; + sensor::Sensor *humidity_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; +}; + +} // namespace sfa30 +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 6d42e325d8..b9b4beb5ad 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1083,6 +1083,16 @@ sensor: ambient_pressure_compensation: 961mBar temperature_offset: 4.2C i2c_id: i2c_bus + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + i2c_id: i2c_bus + address: 0x5D + update_interval: 30s - platform: sen0321 name: Workshop Ozone Sensor id: sen0321_ozone From 357ba1ab0f08ee0a0653a3cde8db246f5c10447f Mon Sep 17 00:00:00 2001 From: leoshusar Date: Mon, 16 Oct 2023 00:29:13 +0200 Subject: [PATCH 0610/2607] Change UART source clock to `UART_SCLK_DEFAULT` when IDF >=v5 (#5533) --- esphome/components/uart/uart_component_esp_idf.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index ae772fa8f8..9b519c4568 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -48,7 +48,11 @@ uart_config_t IDFUARTComponent::get_config_() { uart_config.parity = parity; uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + uart_config.source_clk = UART_SCLK_DEFAULT; +#else uart_config.source_clk = UART_SCLK_APB; +#endif uart_config.rx_flow_ctrl_thresh = 122; return uart_config; From 06eff72065c1510a4d4e7a5707adff70f243911f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:41:59 +1300 Subject: [PATCH 0611/2607] Prometheus fix for esp-idf and fix newlines (#5536) --- .../prometheus/prometheus_handler.cpp | 22 ++++++++----------- .../prometheus/prometheus_handler.h | 8 ++----- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index abb5111aaf..68bca95a21 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "prometheus_handler.h" #include "esphome/core/application.h" @@ -89,7 +87,7 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor stream->print(obj->get_unit_of_measurement().c_str()); stream->print(F("\"} ")); stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str()); - stream->print('\n'); + stream->print(F("\n")); } else { // Invalid state stream->print(F("esphome_sensor_failed{id=\"")); @@ -124,7 +122,7 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } else { // Invalid state stream->print(F("esphome_binary_sensor_failed{id=\"")); @@ -158,7 +156,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); // Speed if available if (obj->get_traits().supports_speed()) { stream->print(F("esphome_fan_speed{id=\"")); @@ -167,7 +165,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->speed); - stream->print('\n'); + stream->print(F("\n")); } // Oscillation if available if (obj->get_traits().supports_oscillation()) { @@ -177,7 +175,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->oscillating); - stream->print('\n'); + stream->print(F("\n")); } } #endif @@ -281,7 +279,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->position); - stream->print('\n'); + stream->print(F("\n")); if (obj->get_traits().get_supports_tilt()) { stream->print(F("esphome_cover_tilt{id=\"")); stream->print(relabel_id_(obj).c_str()); @@ -289,7 +287,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->tilt); - stream->print('\n'); + stream->print(F("\n")); } } else { // Invalid state @@ -322,7 +320,7 @@ void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } #endif @@ -346,11 +344,9 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } #endif } // namespace prometheus } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index 0ae2856ce4..a9505a3572 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -1,14 +1,12 @@ #pragma once -#ifdef USE_ARDUINO - #include #include -#include "esphome/core/entity_base.h" #include "esphome/components/web_server_base/web_server_base.h" -#include "esphome/core/controller.h" #include "esphome/core/component.h" +#include "esphome/core/controller.h" +#include "esphome/core/entity_base.h" namespace esphome { namespace prometheus { @@ -119,5 +117,3 @@ class PrometheusHandler : public AsyncWebHandler, public Component { } // namespace prometheus } // namespace esphome - -#endif // USE_ARDUINO From 26f12cd3bbed34df0a4829e999f378e37afc8902 Mon Sep 17 00:00:00 2001 From: raineth Date: Mon, 16 Oct 2023 02:42:18 -0400 Subject: [PATCH 0612/2607] Make IPAddress's operator!= compare values, not memory addresses. (#5537) Co-authored-by: Ben Winslow --- esphome/components/network/ip_address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 8b05237c05..7a4d394805 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -87,7 +87,7 @@ struct IPAddress { bool is_ip6() { return IP_IS_V6(&ip_addr_); } std::string str() const { return ipaddr_ntoa(&ip_addr_); } bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); } - bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); } + bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); } IPAddress &operator+=(uint8_t increase) { if (IP_IS_V4(&ip_addr_)) { #if LWIP_IPV6 From e42c51a222abb817d5dfba00cc7cd34d8b7c8fca Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 16 Oct 2023 20:47:35 +0100 Subject: [PATCH 0613/2607] Add change i2c address and allow multi conf for TB6612FNG (#5492) --- .../components/grove_tb6612fng/__init__.py | 25 +++++++++++++++++++ .../grove_tb6612fng/grove_tb6612fng.h | 11 ++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/esphome/components/grove_tb6612fng/__init__.py b/esphome/components/grove_tb6612fng/__init__.py index 75610ce9d3..7db0198a89 100644 --- a/esphome/components/grove_tb6612fng/__init__.py +++ b/esphome/components/grove_tb6612fng/__init__.py @@ -8,12 +8,15 @@ from esphome.const import ( CONF_CHANNEL, CONF_SPEED, CONF_DIRECTION, + CONF_ADDRESS, ) DEPENDENCIES = ["i2c"] CODEOWNERS = ["@max246"] +MULTI_CONF = True + grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng") GROVE_TB6612FNG = grove_tb6612fng_ns.class_( "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice @@ -33,6 +36,9 @@ GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_( GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorNoStandbyAction", automation.Action ) +GROVETB6612FNGMotorChangeAddressAction = grove_tb6612fng_ns.class_( + "GROVETB6612FNGMotorChangeAddressAction", automation.Action +) DIRECTION_TYPE = { "FORWARD": 1, @@ -150,3 +156,22 @@ async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, ar await cg.register_parented(var, config[CONF_ID]) return var + + +@automation.register_action( + "grove_tb6612fng.change_address", + GROVETB6612FNGMotorChangeAddressAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + cv.Required(CONF_ADDRESS): cv.i2c_address, + } + ), +) +async def grove_tb6612fng_change_address_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + template_channel = await cg.templatable(config[CONF_ADDRESS], args, int) + cg.add(var.set_address(template_channel)) + return var diff --git a/esphome/components/grove_tb6612fng/grove_tb6612fng.h b/esphome/components/grove_tb6612fng/grove_tb6612fng.h index ccdab6472a..2743ef4ed7 100644 --- a/esphome/components/grove_tb6612fng/grove_tb6612fng.h +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.h @@ -84,8 +84,7 @@ class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice { *************************************************************/ void set_i2c_addr(uint8_t addr); - /************************************************************* - Description + /***********************************change_address Drive a motor. Parameter chl: MOTOR_CHA or MOTOR_CHB @@ -204,5 +203,13 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action, public Parented void play(Ts... x) override { this->parent_->not_standby(); } }; +template +class GROVETB6612FNGMotorChangeAddressAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, address) + + void play(Ts... x) override { this->parent_->set_i2c_addr(this->address_.value(x...)); } +}; + } // namespace grove_tb6612fng } // namespace esphome From 4913b3cc356a996a548ea9ed8d61d11d172b5e8f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 17:18:05 +1300 Subject: [PATCH 0614/2607] Add stream start and end events (#5545) --- esphome/components/api/api.proto | 2 + esphome/components/api/api_pb2.cpp | 4 ++ esphome/components/api/api_pb2.h | 2 + .../i2s_audio/speaker/i2s_audio_speaker.cpp | 6 ++ .../voice_assistant/voice_assistant.cpp | 69 +++++++++++++++++-- .../voice_assistant/voice_assistant.h | 3 +- 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index ec4a0f7cc9..69765c7a94 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1459,6 +1459,8 @@ enum VoiceAssistantEvent { VOICE_ASSISTANT_WAKE_WORD_END = 10; VOICE_ASSISTANT_STT_VAD_START = 11; VOICE_ASSISTANT_STT_VAD_END = 12; + VOICE_ASSISTANT_TTS_STREAM_START = 98; + VOICE_ASSISTANT_TTS_STREAM_END = 99; } message VoiceAssistantEventData { diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 225b213a67..65df2312e1 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -452,6 +452,10 @@ template<> const char *proto_enum_to_string(enums::V return "VOICE_ASSISTANT_STT_VAD_START"; case enums::VOICE_ASSISTANT_STT_VAD_END: return "VOICE_ASSISTANT_STT_VAD_END"; + case enums::VOICE_ASSISTANT_TTS_STREAM_START: + return "VOICE_ASSISTANT_TTS_STREAM_START"; + case enums::VOICE_ASSISTANT_TTS_STREAM_END: + return "VOICE_ASSISTANT_TTS_STREAM_END"; default: return "UNKNOWN"; } diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index a4826f09d2..4c70facf3d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -184,6 +184,8 @@ enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_WAKE_WORD_END = 10, VOICE_ASSISTANT_STT_VAD_START = 11, VOICE_ASSISTANT_STT_VAD_END = 12, + VOICE_ASSISTANT_TTS_STREAM_START = 98, + VOICE_ASSISTANT_TTS_STREAM_END = 99, }; enum AlarmControlPanelState : uint32_t { ALARM_STATE_DISARMED = 0, diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 592a27b739..ed13e6b458 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -158,8 +158,13 @@ void I2SAudioSpeaker::watch_() { if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) { switch (event.type) { case TaskEventType::STARTING: + ESP_LOGD(TAG, "Starting I2S Audio Speaker"); + break; case TaskEventType::STARTED: + ESP_LOGD(TAG, "Started I2S Audio Speaker"); + break; case TaskEventType::STOPPING: + ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); break; case TaskEventType::PLAYING: this->status_clear_warning(); @@ -170,6 +175,7 @@ void I2SAudioSpeaker::watch_() { this->player_task_handle_ = nullptr; this->parent_->unlock(); xQueueReset(this->buffer_queue_); + ESP_LOGD(TAG, "Stopped I2S Audio Speaker"); break; case TaskEventType::WARNING: ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 448df61d80..12fbdc97b4 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -281,11 +281,14 @@ void VoiceAssistant::loop() { memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); this->speaker_buffer_size_ -= written; this->speaker_buffer_index_ -= written; - this->set_timeout("speaker-timeout", 1000, [this]() { this->speaker_->stop(); }); + this->set_timeout("speaker-timeout", 2000, [this]() { this->speaker_->stop(); }); } else { ESP_LOGW(TAG, "Speaker buffer full."); } } + if (this->wait_for_stream_end_) { + break; // We dont want to timeout here as the STREAM_END event will take care of that. + } playing = this->speaker_->is_running(); } #endif @@ -295,28 +298,77 @@ void VoiceAssistant::loop() { } #endif if (playing) { - this->set_timeout("playing", 100, [this]() { + this->set_timeout("playing", 2000, [this]() { this->cancel_timeout("speaker-timeout"); this->set_state_(State::IDLE, State::IDLE); }); } break; } + case State::RESPONSE_FINISHED: { +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + this->speaker_->stop(); + this->cancel_timeout("speaker-timeout"); + this->cancel_timeout("playing"); + this->speaker_buffer_size_ = 0; + this->speaker_buffer_index_ = 0; + memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + } +#endif + this->wait_for_stream_end_ = false; + this->set_state_(State::IDLE, State::IDLE); + break; + } default: break; } } +static const LogString *voice_assistant_state_to_string(State state) { + switch (state) { + case State::IDLE: + return LOG_STR("IDLE"); + case State::START_MICROPHONE: + return LOG_STR("START_MICROPHONE"); + case State::STARTING_MICROPHONE: + return LOG_STR("STARTING_MICROPHONE"); + case State::WAIT_FOR_VAD: + return LOG_STR("WAIT_FOR_VAD"); + case State::WAITING_FOR_VAD: + return LOG_STR("WAITING_FOR_VAD"); + case State::START_PIPELINE: + return LOG_STR("START_PIPELINE"); + case State::STARTING_PIPELINE: + return LOG_STR("STARTING_PIPELINE"); + case State::STREAMING_MICROPHONE: + return LOG_STR("STREAMING_MICROPHONE"); + case State::STOP_MICROPHONE: + return LOG_STR("STOP_MICROPHONE"); + case State::STOPPING_MICROPHONE: + return LOG_STR("STOPPING_MICROPHONE"); + case State::AWAITING_RESPONSE: + return LOG_STR("AWAITING_RESPONSE"); + case State::STREAMING_RESPONSE: + return LOG_STR("STREAMING_RESPONSE"); + case State::RESPONSE_FINISHED: + return LOG_STR("RESPONSE_FINISHED"); + default: + return LOG_STR("UNKNOWN"); + } +}; + void VoiceAssistant::set_state_(State state) { State old_state = this->state_; this->state_ = state; - ESP_LOGD(TAG, "State changed from %d to %d", static_cast(old_state), static_cast(state)); + ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(voice_assistant_state_to_string(old_state)), + LOG_STR_ARG(voice_assistant_state_to_string(state))); } void VoiceAssistant::set_state_(State state, State desired_state) { this->set_state_(state); this->desired_state_ = desired_state; - ESP_LOGD(TAG, "Desired state set to %d", static_cast(desired_state)); + ESP_LOGD(TAG, "Desired state set to %s", LOG_STR_ARG(voice_assistant_state_to_string(desired_state))); } void VoiceAssistant::failed_to_start() { @@ -400,6 +452,7 @@ void VoiceAssistant::request_stop() { break; case State::AWAITING_RESPONSE: case State::STREAMING_RESPONSE: + case State::RESPONSE_FINISHED: break; // Let the incoming audio stream finish then it will go to idle. } } @@ -531,6 +584,14 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->error_trigger_->trigger(code, message); break; } + case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { + this->wait_for_stream_end_ = true; + break; + } + case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { + this->set_state_(State::RESPONSE_FINISHED, State::IDLE); + break; + } default: ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type); break; diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index ce22538a85..cd448293db 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -46,6 +46,7 @@ enum class State { STOPPING_MICROPHONE, AWAITING_RESPONSE, STREAMING_RESPONSE, + RESPONSE_FINISHED, }; class VoiceAssistant : public Component { @@ -132,10 +133,10 @@ class VoiceAssistant : public Component { uint8_t *speaker_buffer_; size_t speaker_buffer_index_{0}; size_t speaker_buffer_size_{0}; + bool wait_for_stream_end_{false}; #endif #ifdef USE_MEDIA_PLAYER media_player::MediaPlayer *media_player_{nullptr}; - bool playing_tts_{false}; #endif bool local_output_{false}; From fb90e197132a1dc8c23fe7cbbef83fcb18fbfab8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:03:39 +1300 Subject: [PATCH 0615/2607] Fix esp32_improv authorizer with no binary sensors in config (#5546) --- esphome/components/esp32_improv/esp32_improv_component.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 5bdf7d19fe..8a901a79e5 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -107,6 +107,7 @@ void ESP32ImprovComponent::loop() { break; } case improv::STATE_AUTHORIZED: { +#ifdef USE_BINARY_SENSOR if (this->authorizer_ != nullptr) { if (now - this->authorized_start_ > this->authorized_duration_) { ESP_LOGD(TAG, "Authorization timeout"); @@ -114,6 +115,7 @@ void ESP32ImprovComponent::loop() { return; } } +#endif if (!this->check_identify_()) { this->set_status_indicator_state_((now % 1000) < 500); } @@ -290,8 +292,10 @@ void ESP32ImprovComponent::process_incoming_data_() { void ESP32ImprovComponent::on_wifi_connect_timeout_() { this->set_error_(improv::ERROR_UNABLE_TO_CONNECT); this->set_state_(improv::STATE_AUTHORIZED); +#ifdef USE_BINARY_SENSOR if (this->authorizer_ != nullptr) this->authorized_start_ = millis(); +#endif ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); wifi::global_wifi_component->clear_sta(); } From a960c8008ea3f15888b2388a08bf6308995ac278 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:11:37 +1300 Subject: [PATCH 0616/2607] More voice assistant fixes (#5547) --- .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 2 ++ esphome/components/voice_assistant/voice_assistant.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 44c73eb8fd..ec2fe258c9 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -37,6 +37,8 @@ void I2SAudioMicrophone::setup() { void I2SAudioMicrophone::start() { if (this->is_failed()) return; + if (this->state_ == microphone::STATE_RUNNING) + return; // Already running this->state_ = microphone::STATE_STARTING; } void I2SAudioMicrophone::start_() { diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 12fbdc97b4..27dc201073 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -287,6 +287,7 @@ void VoiceAssistant::loop() { } } if (this->wait_for_stream_end_) { + this->cancel_timeout("playing"); break; // We dont want to timeout here as the STREAM_END event will take care of that. } playing = this->speaker_->is_running(); From 261c271d60caa35a496cca256f667157c3ee2a4f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:41:59 +1300 Subject: [PATCH 0617/2607] Prometheus fix for esp-idf and fix newlines (#5536) --- .../prometheus/prometheus_handler.cpp | 22 ++++++++----------- .../prometheus/prometheus_handler.h | 8 ++----- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index abb5111aaf..68bca95a21 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "prometheus_handler.h" #include "esphome/core/application.h" @@ -89,7 +87,7 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor stream->print(obj->get_unit_of_measurement().c_str()); stream->print(F("\"} ")); stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str()); - stream->print('\n'); + stream->print(F("\n")); } else { // Invalid state stream->print(F("esphome_sensor_failed{id=\"")); @@ -124,7 +122,7 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } else { // Invalid state stream->print(F("esphome_binary_sensor_failed{id=\"")); @@ -158,7 +156,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); // Speed if available if (obj->get_traits().supports_speed()) { stream->print(F("esphome_fan_speed{id=\"")); @@ -167,7 +165,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->speed); - stream->print('\n'); + stream->print(F("\n")); } // Oscillation if available if (obj->get_traits().supports_oscillation()) { @@ -177,7 +175,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->oscillating); - stream->print('\n'); + stream->print(F("\n")); } } #endif @@ -281,7 +279,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->position); - stream->print('\n'); + stream->print(F("\n")); if (obj->get_traits().get_supports_tilt()) { stream->print(F("esphome_cover_tilt{id=\"")); stream->print(relabel_id_(obj).c_str()); @@ -289,7 +287,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->tilt); - stream->print('\n'); + stream->print(F("\n")); } } else { // Invalid state @@ -322,7 +320,7 @@ void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } #endif @@ -346,11 +344,9 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); stream->print(obj->state); - stream->print('\n'); + stream->print(F("\n")); } #endif } // namespace prometheus } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index 0ae2856ce4..a9505a3572 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -1,14 +1,12 @@ #pragma once -#ifdef USE_ARDUINO - #include #include -#include "esphome/core/entity_base.h" #include "esphome/components/web_server_base/web_server_base.h" -#include "esphome/core/controller.h" #include "esphome/core/component.h" +#include "esphome/core/controller.h" +#include "esphome/core/entity_base.h" namespace esphome { namespace prometheus { @@ -119,5 +117,3 @@ class PrometheusHandler : public AsyncWebHandler, public Component { } // namespace prometheus } // namespace esphome - -#endif // USE_ARDUINO From 52e8a2e9e4ec73620c3a31dc8925eb9cae19e3c5 Mon Sep 17 00:00:00 2001 From: raineth Date: Mon, 16 Oct 2023 02:42:18 -0400 Subject: [PATCH 0618/2607] Make IPAddress's operator!= compare values, not memory addresses. (#5537) Co-authored-by: Ben Winslow --- esphome/components/network/ip_address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 8b05237c05..7a4d394805 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -87,7 +87,7 @@ struct IPAddress { bool is_ip6() { return IP_IS_V6(&ip_addr_); } std::string str() const { return ipaddr_ntoa(&ip_addr_); } bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); } - bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); } + bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); } IPAddress &operator+=(uint8_t increase) { if (IP_IS_V4(&ip_addr_)) { #if LWIP_IPV6 From 97d624114d8722e84fd4ac62f841cccba5e7f725 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 16 Oct 2023 20:47:35 +0100 Subject: [PATCH 0619/2607] Add change i2c address and allow multi conf for TB6612FNG (#5492) --- .../components/grove_tb6612fng/__init__.py | 25 +++++++++++++++++++ .../grove_tb6612fng/grove_tb6612fng.h | 11 ++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/esphome/components/grove_tb6612fng/__init__.py b/esphome/components/grove_tb6612fng/__init__.py index 75610ce9d3..7db0198a89 100644 --- a/esphome/components/grove_tb6612fng/__init__.py +++ b/esphome/components/grove_tb6612fng/__init__.py @@ -8,12 +8,15 @@ from esphome.const import ( CONF_CHANNEL, CONF_SPEED, CONF_DIRECTION, + CONF_ADDRESS, ) DEPENDENCIES = ["i2c"] CODEOWNERS = ["@max246"] +MULTI_CONF = True + grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng") GROVE_TB6612FNG = grove_tb6612fng_ns.class_( "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice @@ -33,6 +36,9 @@ GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_( GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_( "GROVETB6612FNGMotorNoStandbyAction", automation.Action ) +GROVETB6612FNGMotorChangeAddressAction = grove_tb6612fng_ns.class_( + "GROVETB6612FNGMotorChangeAddressAction", automation.Action +) DIRECTION_TYPE = { "FORWARD": 1, @@ -150,3 +156,22 @@ async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, ar await cg.register_parented(var, config[CONF_ID]) return var + + +@automation.register_action( + "grove_tb6612fng.change_address", + GROVETB6612FNGMotorChangeAddressAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG), + cv.Required(CONF_ADDRESS): cv.i2c_address, + } + ), +) +async def grove_tb6612fng_change_address_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + template_channel = await cg.templatable(config[CONF_ADDRESS], args, int) + cg.add(var.set_address(template_channel)) + return var diff --git a/esphome/components/grove_tb6612fng/grove_tb6612fng.h b/esphome/components/grove_tb6612fng/grove_tb6612fng.h index ccdab6472a..2743ef4ed7 100644 --- a/esphome/components/grove_tb6612fng/grove_tb6612fng.h +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.h @@ -84,8 +84,7 @@ class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice { *************************************************************/ void set_i2c_addr(uint8_t addr); - /************************************************************* - Description + /***********************************change_address Drive a motor. Parameter chl: MOTOR_CHA or MOTOR_CHB @@ -204,5 +203,13 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action, public Parented void play(Ts... x) override { this->parent_->not_standby(); } }; +template +class GROVETB6612FNGMotorChangeAddressAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint8_t, address) + + void play(Ts... x) override { this->parent_->set_i2c_addr(this->address_.value(x...)); } +}; + } // namespace grove_tb6612fng } // namespace esphome From 61cf566560539ba0549843d8e645242833879ddd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 17:18:05 +1300 Subject: [PATCH 0620/2607] Add stream start and end events (#5545) --- esphome/components/api/api.proto | 2 + esphome/components/api/api_pb2.cpp | 4 ++ esphome/components/api/api_pb2.h | 2 + .../i2s_audio/speaker/i2s_audio_speaker.cpp | 6 ++ .../voice_assistant/voice_assistant.cpp | 69 +++++++++++++++++-- .../voice_assistant/voice_assistant.h | 3 +- 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index ec4a0f7cc9..69765c7a94 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1459,6 +1459,8 @@ enum VoiceAssistantEvent { VOICE_ASSISTANT_WAKE_WORD_END = 10; VOICE_ASSISTANT_STT_VAD_START = 11; VOICE_ASSISTANT_STT_VAD_END = 12; + VOICE_ASSISTANT_TTS_STREAM_START = 98; + VOICE_ASSISTANT_TTS_STREAM_END = 99; } message VoiceAssistantEventData { diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 225b213a67..65df2312e1 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -452,6 +452,10 @@ template<> const char *proto_enum_to_string(enums::V return "VOICE_ASSISTANT_STT_VAD_START"; case enums::VOICE_ASSISTANT_STT_VAD_END: return "VOICE_ASSISTANT_STT_VAD_END"; + case enums::VOICE_ASSISTANT_TTS_STREAM_START: + return "VOICE_ASSISTANT_TTS_STREAM_START"; + case enums::VOICE_ASSISTANT_TTS_STREAM_END: + return "VOICE_ASSISTANT_TTS_STREAM_END"; default: return "UNKNOWN"; } diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index a4826f09d2..4c70facf3d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -184,6 +184,8 @@ enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_WAKE_WORD_END = 10, VOICE_ASSISTANT_STT_VAD_START = 11, VOICE_ASSISTANT_STT_VAD_END = 12, + VOICE_ASSISTANT_TTS_STREAM_START = 98, + VOICE_ASSISTANT_TTS_STREAM_END = 99, }; enum AlarmControlPanelState : uint32_t { ALARM_STATE_DISARMED = 0, diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 592a27b739..ed13e6b458 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -158,8 +158,13 @@ void I2SAudioSpeaker::watch_() { if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) { switch (event.type) { case TaskEventType::STARTING: + ESP_LOGD(TAG, "Starting I2S Audio Speaker"); + break; case TaskEventType::STARTED: + ESP_LOGD(TAG, "Started I2S Audio Speaker"); + break; case TaskEventType::STOPPING: + ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); break; case TaskEventType::PLAYING: this->status_clear_warning(); @@ -170,6 +175,7 @@ void I2SAudioSpeaker::watch_() { this->player_task_handle_ = nullptr; this->parent_->unlock(); xQueueReset(this->buffer_queue_); + ESP_LOGD(TAG, "Stopped I2S Audio Speaker"); break; case TaskEventType::WARNING: ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 448df61d80..12fbdc97b4 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -281,11 +281,14 @@ void VoiceAssistant::loop() { memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); this->speaker_buffer_size_ -= written; this->speaker_buffer_index_ -= written; - this->set_timeout("speaker-timeout", 1000, [this]() { this->speaker_->stop(); }); + this->set_timeout("speaker-timeout", 2000, [this]() { this->speaker_->stop(); }); } else { ESP_LOGW(TAG, "Speaker buffer full."); } } + if (this->wait_for_stream_end_) { + break; // We dont want to timeout here as the STREAM_END event will take care of that. + } playing = this->speaker_->is_running(); } #endif @@ -295,28 +298,77 @@ void VoiceAssistant::loop() { } #endif if (playing) { - this->set_timeout("playing", 100, [this]() { + this->set_timeout("playing", 2000, [this]() { this->cancel_timeout("speaker-timeout"); this->set_state_(State::IDLE, State::IDLE); }); } break; } + case State::RESPONSE_FINISHED: { +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + this->speaker_->stop(); + this->cancel_timeout("speaker-timeout"); + this->cancel_timeout("playing"); + this->speaker_buffer_size_ = 0; + this->speaker_buffer_index_ = 0; + memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + } +#endif + this->wait_for_stream_end_ = false; + this->set_state_(State::IDLE, State::IDLE); + break; + } default: break; } } +static const LogString *voice_assistant_state_to_string(State state) { + switch (state) { + case State::IDLE: + return LOG_STR("IDLE"); + case State::START_MICROPHONE: + return LOG_STR("START_MICROPHONE"); + case State::STARTING_MICROPHONE: + return LOG_STR("STARTING_MICROPHONE"); + case State::WAIT_FOR_VAD: + return LOG_STR("WAIT_FOR_VAD"); + case State::WAITING_FOR_VAD: + return LOG_STR("WAITING_FOR_VAD"); + case State::START_PIPELINE: + return LOG_STR("START_PIPELINE"); + case State::STARTING_PIPELINE: + return LOG_STR("STARTING_PIPELINE"); + case State::STREAMING_MICROPHONE: + return LOG_STR("STREAMING_MICROPHONE"); + case State::STOP_MICROPHONE: + return LOG_STR("STOP_MICROPHONE"); + case State::STOPPING_MICROPHONE: + return LOG_STR("STOPPING_MICROPHONE"); + case State::AWAITING_RESPONSE: + return LOG_STR("AWAITING_RESPONSE"); + case State::STREAMING_RESPONSE: + return LOG_STR("STREAMING_RESPONSE"); + case State::RESPONSE_FINISHED: + return LOG_STR("RESPONSE_FINISHED"); + default: + return LOG_STR("UNKNOWN"); + } +}; + void VoiceAssistant::set_state_(State state) { State old_state = this->state_; this->state_ = state; - ESP_LOGD(TAG, "State changed from %d to %d", static_cast(old_state), static_cast(state)); + ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(voice_assistant_state_to_string(old_state)), + LOG_STR_ARG(voice_assistant_state_to_string(state))); } void VoiceAssistant::set_state_(State state, State desired_state) { this->set_state_(state); this->desired_state_ = desired_state; - ESP_LOGD(TAG, "Desired state set to %d", static_cast(desired_state)); + ESP_LOGD(TAG, "Desired state set to %s", LOG_STR_ARG(voice_assistant_state_to_string(desired_state))); } void VoiceAssistant::failed_to_start() { @@ -400,6 +452,7 @@ void VoiceAssistant::request_stop() { break; case State::AWAITING_RESPONSE: case State::STREAMING_RESPONSE: + case State::RESPONSE_FINISHED: break; // Let the incoming audio stream finish then it will go to idle. } } @@ -531,6 +584,14 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->error_trigger_->trigger(code, message); break; } + case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { + this->wait_for_stream_end_ = true; + break; + } + case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { + this->set_state_(State::RESPONSE_FINISHED, State::IDLE); + break; + } default: ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type); break; diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index ce22538a85..cd448293db 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -46,6 +46,7 @@ enum class State { STOPPING_MICROPHONE, AWAITING_RESPONSE, STREAMING_RESPONSE, + RESPONSE_FINISHED, }; class VoiceAssistant : public Component { @@ -132,10 +133,10 @@ class VoiceAssistant : public Component { uint8_t *speaker_buffer_; size_t speaker_buffer_index_{0}; size_t speaker_buffer_size_{0}; + bool wait_for_stream_end_{false}; #endif #ifdef USE_MEDIA_PLAYER media_player::MediaPlayer *media_player_{nullptr}; - bool playing_tts_{false}; #endif bool local_output_{false}; From fd7d3c4332537f58a2a52518c1bfefdca5513551 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:03:39 +1300 Subject: [PATCH 0621/2607] Fix esp32_improv authorizer with no binary sensors in config (#5546) --- esphome/components/esp32_improv/esp32_improv_component.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 5bdf7d19fe..8a901a79e5 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -107,6 +107,7 @@ void ESP32ImprovComponent::loop() { break; } case improv::STATE_AUTHORIZED: { +#ifdef USE_BINARY_SENSOR if (this->authorizer_ != nullptr) { if (now - this->authorized_start_ > this->authorized_duration_) { ESP_LOGD(TAG, "Authorization timeout"); @@ -114,6 +115,7 @@ void ESP32ImprovComponent::loop() { return; } } +#endif if (!this->check_identify_()) { this->set_status_indicator_state_((now % 1000) < 500); } @@ -290,8 +292,10 @@ void ESP32ImprovComponent::process_incoming_data_() { void ESP32ImprovComponent::on_wifi_connect_timeout_() { this->set_error_(improv::ERROR_UNABLE_TO_CONNECT); this->set_state_(improv::STATE_AUTHORIZED); +#ifdef USE_BINARY_SENSOR if (this->authorizer_ != nullptr) this->authorized_start_ = millis(); +#endif ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); wifi::global_wifi_component->clear_sta(); } From 1f02096edb29095c8ee5462c4a46a705bba163eb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:11:37 +1300 Subject: [PATCH 0622/2607] More voice assistant fixes (#5547) --- .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 2 ++ esphome/components/voice_assistant/voice_assistant.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 44c73eb8fd..ec2fe258c9 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -37,6 +37,8 @@ void I2SAudioMicrophone::setup() { void I2SAudioMicrophone::start() { if (this->is_failed()) return; + if (this->state_ == microphone::STATE_RUNNING) + return; // Already running this->state_ = microphone::STATE_STARTING; } void I2SAudioMicrophone::start_() { diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 12fbdc97b4..27dc201073 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -287,6 +287,7 @@ void VoiceAssistant::loop() { } } if (this->wait_for_stream_end_) { + this->cancel_timeout("playing"); break; // We dont want to timeout here as the STREAM_END event will take care of that. } playing = this->speaker_->is_running(); From 5e7ce610a030307ca4cbe9347c42c6dc6fbec7d9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:15:14 +1300 Subject: [PATCH 0623/2607] Bump version to 2023.10.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cef733b2f9..cf267a2424 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0b2" +__version__ = "2023.10.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b12dc98150d68e9a356c597cc16f1dfc4addf17e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:23:34 +1300 Subject: [PATCH 0624/2607] Fix default libretiny manufacturer reported to HA (#5549) --- esphome/components/libretiny/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index b01d342a87..e36c08d522 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -251,7 +251,7 @@ async def component_to_code(config): # setup board config cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_build_flag("-DUSE_LIBRETINY") - cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}") + cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID].upper()}") cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]]) From 6839de69c1730611ad8db6723996aea491a27581 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 17 Oct 2023 11:30:32 -0700 Subject: [PATCH 0625/2607] add uart button (#5540) Co-authored-by: Samuel Sieb --- CODEOWNERS | 1 + esphome/components/uart/button/__init__.py | 35 +++++++++++++++++++ .../components/uart/button/uart_button.cpp | 17 +++++++++ esphome/components/uart/button/uart_button.h | 24 +++++++++++++ tests/test1.yaml | 4 +++ 5 files changed, 81 insertions(+) create mode 100644 esphome/components/uart/button/__init__.py create mode 100644 esphome/components/uart/button/uart_button.cpp create mode 100644 esphome/components/uart/button/uart_button.h diff --git a/CODEOWNERS b/CODEOWNERS index 326642e12c..b66da4fc26 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -323,6 +323,7 @@ esphome/components/tuya/sensor/* @jesserockz esphome/components/tuya/switch/* @jesserockz esphome/components/tuya/text_sensor/* @dentra esphome/components/uart/* @esphome/core +esphome/components/uart/button/* @ssieb esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ise/* @pvizeli esphome/components/ultrasonic/* @OttoWinter diff --git a/esphome/components/uart/button/__init__.py b/esphome/components/uart/button/__init__.py new file mode 100644 index 0000000000..05909516a0 --- /dev/null +++ b/esphome/components/uart/button/__init__.py @@ -0,0 +1,35 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import button, uart +from esphome.const import CONF_DATA +from esphome.core import HexInt +from .. import uart_ns, validate_raw_data + +CODEOWNERS = ["@ssieb"] + +DEPENDENCIES = ["uart"] + +UARTButton = uart_ns.class_("UARTButton", button.Button, uart.UARTDevice, cg.Component) + + +CONFIG_SCHEMA = ( + button.button_schema(UARTButton) + .extend( + { + cv.Required(CONF_DATA): validate_raw_data, + } + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = await button.new_button(config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + data = config[CONF_DATA] + if isinstance(data, bytes): + data = [HexInt(x) for x in data] + cg.add(var.set_data(data)) diff --git a/esphome/components/uart/button/uart_button.cpp b/esphome/components/uart/button/uart_button.cpp new file mode 100644 index 0000000000..4db164c400 --- /dev/null +++ b/esphome/components/uart/button/uart_button.cpp @@ -0,0 +1,17 @@ +#include "uart_button.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace uart { + +static const char *const TAG = "uart.button"; + +void UARTButton::press_action() { + ESP_LOGD(TAG, "'%s': Sending data...", this->get_name().c_str()); + this->write_array(this->data_.data(), this->data_.size()); +} + +void UARTButton::dump_config() { LOG_BUTTON("", "UART Button", this); } + +} // namespace uart +} // namespace esphome diff --git a/esphome/components/uart/button/uart_button.h b/esphome/components/uart/button/uart_button.h new file mode 100644 index 0000000000..2d600b199a --- /dev/null +++ b/esphome/components/uart/button/uart_button.h @@ -0,0 +1,24 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/uart/uart.h" +#include "esphome/components/button/button.h" + +#include + +namespace esphome { +namespace uart { + +class UARTButton : public button::Button, public UARTDevice, public Component { + public: + void set_data(const std::vector &data) { this->data_ = data; } + + void dump_config() override; + + protected: + void press_action() override; + std::vector data_; +}; + +} // namespace uart +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index b9b4beb5ad..66471377f9 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3504,6 +3504,10 @@ button: name: "restart" query_params: name: query params + - platform: uart + uart_id: uart_0 + name: UART button + data: "Pressed\r\n" ld2410: id: my_ld2410 From b0ac729a8ed17f5d5626f7911a8ca816d826acdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Bl=C3=A4se?= Date: Tue, 17 Oct 2023 20:39:05 +0200 Subject: [PATCH 0626/2607] SML: fix incomplete sign extension for abbreviated transmissions (#5544) --- esphome/components/sml/sml_parser.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index 91b320a30e..3b23522b21 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -88,11 +88,6 @@ uint64_t bytes_to_uint(const bytes &buffer) { for (auto const value : buffer) { val = (val << 8) + value; } - // Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the - // 24 bit value is negative. - if (buffer.size() == 3 && buffer[0] & 0x80) { - val |= 0xFFFFFFFFFF000000; - } return val; } @@ -100,19 +95,15 @@ int64_t bytes_to_int(const bytes &buffer) { uint64_t tmp = bytes_to_uint(buffer); int64_t val; - switch (buffer.size()) { - case 1: // int8 - val = (int8_t) tmp; - break; - case 2: // int16 - val = (int16_t) tmp; - break; - case 4: // int32 - val = (int32_t) tmp; - break; - default: // int64 - val = (int64_t) tmp; + // sign extension for abbreviations of leading ones (e.g. 3 byte transmissions, see 6.2.2 of SML protocol definition) + // see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c + if (buffer.size() < 8) { + const int bits = buffer.size() * 8; + const uint64_t m = 1u << (bits - 1); + tmp = (tmp ^ m) - m; } + + val = (int64_t) tmp; return val; } From c19dbdb02dab3a328c6601971beb70b50fa874b5 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 17 Oct 2023 12:07:29 -0700 Subject: [PATCH 0627/2607] add on/off options for uart switch (#5539) Co-authored-by: Samuel Sieb --- esphome/components/uart/switch/__init__.py | 33 +++++++++++++++---- .../components/uart/switch/uart_switch.cpp | 26 +++++++++++---- esphome/components/uart/switch/uart_switch.h | 10 ++++-- tests/test1.yaml | 6 ++++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/esphome/components/uart/switch/__init__.py b/esphome/components/uart/switch/__init__.py index 60f5ddaf0d..8853a61ae3 100644 --- a/esphome/components/uart/switch/__init__.py +++ b/esphome/components/uart/switch/__init__.py @@ -9,14 +9,24 @@ DEPENDENCIES = ["uart"] UARTSwitch = uart_ns.class_("UARTSwitch", switch.Switch, uart.UARTDevice, cg.Component) +CONF_TURN_OFF = "turn_off" +CONF_TURN_ON = "turn_on" CONFIG_SCHEMA = ( switch.switch_schema(UARTSwitch, block_inverted=True) .extend( { - cv.Required(CONF_DATA): validate_raw_data, + cv.Required(CONF_DATA): cv.Any( + validate_raw_data, + cv.Schema( + { + cv.Optional(CONF_TURN_OFF): validate_raw_data, + cv.Optional(CONF_TURN_ON): validate_raw_data, + } + ), + ), cv.Optional(CONF_SEND_EVERY): cv.positive_time_period_milliseconds, - } + }, ) .extend(uart.UART_DEVICE_SCHEMA) .extend(cv.COMPONENT_SCHEMA) @@ -29,9 +39,20 @@ async def to_code(config): await uart.register_uart_device(var, config) data = config[CONF_DATA] - if isinstance(data, bytes): - data = [HexInt(x) for x in data] - cg.add(var.set_data(data)) - + if isinstance(data, dict): + if data_on := data.get(CONF_TURN_ON): + if isinstance(data_on, bytes): + data_on = [HexInt(x) for x in data_on] + cg.add(var.set_data_on(data_on)) + if data_off := data.get(CONF_TURN_OFF): + if isinstance(data_off, bytes): + data_off = [HexInt(x) for x in data_off] + cg.add(var.set_data_off(data_off)) + else: + data = config[CONF_DATA] + if isinstance(data, bytes): + data = [HexInt(x) for x in data] + cg.add(var.set_data_on(data)) + cg.add(var.set_single_state(True)) if CONF_SEND_EVERY in config: cg.add(var.set_send_every(config[CONF_SEND_EVERY])) diff --git a/esphome/components/uart/switch/uart_switch.cpp b/esphome/components/uart/switch/uart_switch.cpp index ffed08c731..b995aca98c 100644 --- a/esphome/components/uart/switch/uart_switch.cpp +++ b/esphome/components/uart/switch/uart_switch.cpp @@ -7,28 +7,41 @@ namespace uart { static const char *const TAG = "uart.switch"; void UARTSwitch::loop() { - if (this->state && this->send_every_) { + if (this->send_every_) { const uint32_t now = millis(); if (now - this->last_transmission_ > this->send_every_) { - this->write_command_(); + this->write_command_(this->state); this->last_transmission_ = now; } } } -void UARTSwitch::write_command_() { - ESP_LOGD(TAG, "'%s': Sending data...", this->get_name().c_str()); - this->write_array(this->data_.data(), this->data_.size()); +void UARTSwitch::write_command_(bool state) { + if (state && !this->data_on_.empty()) { + ESP_LOGD(TAG, "'%s': Sending on data...", this->get_name().c_str()); + this->write_array(this->data_on_.data(), this->data_on_.size()); + } + if (!state && !this->data_off_.empty()) { + ESP_LOGD(TAG, "'%s': Sending off data...", this->get_name().c_str()); + this->write_array(this->data_off_.data(), this->data_off_.size()); + } } void UARTSwitch::write_state(bool state) { + if (!this->single_state_) { + this->publish_state(state); + this->write_command_(state); + this->last_transmission_ = millis(); + return; + } + if (!state) { this->publish_state(false); return; } this->publish_state(true); - this->write_command_(); + this->write_command_(true); if (this->send_every_ == 0) { this->publish_state(false); @@ -36,6 +49,7 @@ void UARTSwitch::write_state(bool state) { this->last_transmission_ = millis(); } } + void UARTSwitch::dump_config() { LOG_SWITCH("", "UART Switch", this); if (this->send_every_) { diff --git a/esphome/components/uart/switch/uart_switch.h b/esphome/components/uart/switch/uart_switch.h index 4f24d76d0c..eb3d697a58 100644 --- a/esphome/components/uart/switch/uart_switch.h +++ b/esphome/components/uart/switch/uart_switch.h @@ -13,15 +13,19 @@ class UARTSwitch : public switch_::Switch, public UARTDevice, public Component { public: void loop() override; - void set_data(const std::vector &data) { data_ = data; } + void set_data_on(const std::vector &data) { this->data_on_ = data; } + void set_data_off(const std::vector &data) { this->data_off_ = data; } void set_send_every(uint32_t send_every) { this->send_every_ = send_every; } + void set_single_state(bool single) { this->single_state_ = single; } void dump_config() override; protected: - void write_command_(); + void write_command_(bool state); void write_state(bool state) override; - std::vector data_; + std::vector data_on_; + std::vector data_off_; + bool single_state_{false}; uint32_t send_every_; uint32_t last_transmission_; }; diff --git a/tests/test1.yaml b/tests/test1.yaml index 66471377f9..9bf9a32e17 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2588,6 +2588,12 @@ switch: name: UART Recurring Output data: [0xDE, 0xAD, 0xBE, 0xEF] send_every: 1s + - platform: uart + uart_id: uart_0 + name: "UART On/Off" + data: + turn_on: "TurnOn\r\n" + turn_off: "TurnOff\r\n" - platform: template assumed_state: true name: Stepper Switch From 14aa27f5e2df02dbe251f72ef0869e87405c15a0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:26:47 +1300 Subject: [PATCH 0628/2607] esp32_improv advertise capabilities and state in ble service data (#5553) --- .../components/esp32_ble/ble_advertising.cpp | 21 +++++++++++++------ .../components/esp32_ble/ble_advertising.h | 1 + .../esp32_improv/esp32_improv_component.cpp | 19 +++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 072bb38c07..59d2398829 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -2,9 +2,9 @@ #ifdef USE_ESP32 -#include "ble_uuid.h" -#include #include +#include +#include "ble_uuid.h" #include "esphome/core/log.h" namespace esphome { @@ -16,8 +16,8 @@ BLEAdvertising::BLEAdvertising() { this->advertising_data_.set_scan_rsp = false; this->advertising_data_.include_name = true; this->advertising_data_.include_txpower = true; - this->advertising_data_.min_interval = 0x20; - this->advertising_data_.max_interval = 0x40; + this->advertising_data_.min_interval = 0; + this->advertising_data_.max_interval = 0; this->advertising_data_.appearance = 0x00; this->advertising_data_.manufacturer_len = 0; this->advertising_data_.p_manufacturer_data = nullptr; @@ -42,6 +42,17 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) { this->advertising_uuids_.end()); } +void BLEAdvertising::set_service_data(const std::vector &data) { + delete[] this->advertising_data_.p_service_data; + this->advertising_data_.p_service_data = nullptr; + this->advertising_data_.service_data_len = data.size(); + if (!data.empty()) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + this->advertising_data_.p_service_data = new uint8_t[data.size()]; + memcpy(this->advertising_data_.p_service_data, data.data(), data.size()); + } +} + void BLEAdvertising::set_manufacturer_data(const std::vector &data) { delete[] this->advertising_data_.p_manufacturer_data; this->advertising_data_.p_manufacturer_data = nullptr; @@ -85,8 +96,6 @@ void BLEAdvertising::start() { this->scan_response_data_.set_scan_rsp = true; this->scan_response_data_.include_name = true; this->scan_response_data_.include_txpower = true; - this->scan_response_data_.min_interval = 0; - this->scan_response_data_.max_interval = 0; this->scan_response_data_.manufacturer_len = 0; this->scan_response_data_.appearance = 0; this->scan_response_data_.flag = 0; diff --git a/esphome/components/esp32_ble/ble_advertising.h b/esphome/components/esp32_ble/ble_advertising.h index 9e4e2b7701..16a7dd1d8e 100644 --- a/esphome/components/esp32_ble/ble_advertising.h +++ b/esphome/components/esp32_ble/ble_advertising.h @@ -21,6 +21,7 @@ class BLEAdvertising { void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; } void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } void set_manufacturer_data(const std::vector &data); + void set_service_data(const std::vector &data); void start(); void stop(); diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 8a901a79e5..19340c3dd8 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -189,6 +189,25 @@ void ESP32ImprovComponent::set_state_(improv::State state) { if (state != improv::STATE_STOPPED) this->status_->notify(); } + std::vector service_data(8, 0); + service_data[0] = 0x77; // PR + service_data[1] = 0x46; // IM + service_data[2] = static_cast(state); + + uint8_t capabilities = 0x00; +#ifdef USE_OUTPUT + if (this->status_indicator_ != nullptr) + capabilities |= improv::CAPABILITY_IDENTIFY; +#endif + + service_data[3] = capabilities; + service_data[4] = 0x00; // Reserved + service_data[5] = 0x00; // Reserved + service_data[6] = 0x00; // Reserved + service_data[7] = 0x00; // Reserved + + esp32_ble::global_ble->get_advertising()->set_service_data(service_data); + esp32_ble::global_ble->get_advertising()->start(); } void ESP32ImprovComponent::set_error_(improv::Error error) { From cc4c0e3e0bee6a88aa898e86bba48755b4c71d80 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:23:34 +1300 Subject: [PATCH 0629/2607] Fix default libretiny manufacturer reported to HA (#5549) --- esphome/components/libretiny/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index b01d342a87..e36c08d522 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -251,7 +251,7 @@ async def component_to_code(config): # setup board config cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_build_flag("-DUSE_LIBRETINY") - cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}") + cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID].upper()}") cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]]) From 51688d40780f2ef203e701b4d224c3abee283c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Bl=C3=A4se?= Date: Tue, 17 Oct 2023 20:39:05 +0200 Subject: [PATCH 0630/2607] SML: fix incomplete sign extension for abbreviated transmissions (#5544) --- esphome/components/sml/sml_parser.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index 91b320a30e..3b23522b21 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -88,11 +88,6 @@ uint64_t bytes_to_uint(const bytes &buffer) { for (auto const value : buffer) { val = (val << 8) + value; } - // Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the - // 24 bit value is negative. - if (buffer.size() == 3 && buffer[0] & 0x80) { - val |= 0xFFFFFFFFFF000000; - } return val; } @@ -100,19 +95,15 @@ int64_t bytes_to_int(const bytes &buffer) { uint64_t tmp = bytes_to_uint(buffer); int64_t val; - switch (buffer.size()) { - case 1: // int8 - val = (int8_t) tmp; - break; - case 2: // int16 - val = (int16_t) tmp; - break; - case 4: // int32 - val = (int32_t) tmp; - break; - default: // int64 - val = (int64_t) tmp; + // sign extension for abbreviations of leading ones (e.g. 3 byte transmissions, see 6.2.2 of SML protocol definition) + // see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c + if (buffer.size() < 8) { + const int bits = buffer.size() * 8; + const uint64_t m = 1u << (bits - 1); + tmp = (tmp ^ m) - m; } + + val = (int64_t) tmp; return val; } From 2189a40a39951f931b692a5f9aa8326ec41e3726 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:26:47 +1300 Subject: [PATCH 0631/2607] esp32_improv advertise capabilities and state in ble service data (#5553) --- .../components/esp32_ble/ble_advertising.cpp | 21 +++++++++++++------ .../components/esp32_ble/ble_advertising.h | 1 + .../esp32_improv/esp32_improv_component.cpp | 19 +++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 072bb38c07..59d2398829 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -2,9 +2,9 @@ #ifdef USE_ESP32 -#include "ble_uuid.h" -#include #include +#include +#include "ble_uuid.h" #include "esphome/core/log.h" namespace esphome { @@ -16,8 +16,8 @@ BLEAdvertising::BLEAdvertising() { this->advertising_data_.set_scan_rsp = false; this->advertising_data_.include_name = true; this->advertising_data_.include_txpower = true; - this->advertising_data_.min_interval = 0x20; - this->advertising_data_.max_interval = 0x40; + this->advertising_data_.min_interval = 0; + this->advertising_data_.max_interval = 0; this->advertising_data_.appearance = 0x00; this->advertising_data_.manufacturer_len = 0; this->advertising_data_.p_manufacturer_data = nullptr; @@ -42,6 +42,17 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) { this->advertising_uuids_.end()); } +void BLEAdvertising::set_service_data(const std::vector &data) { + delete[] this->advertising_data_.p_service_data; + this->advertising_data_.p_service_data = nullptr; + this->advertising_data_.service_data_len = data.size(); + if (!data.empty()) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + this->advertising_data_.p_service_data = new uint8_t[data.size()]; + memcpy(this->advertising_data_.p_service_data, data.data(), data.size()); + } +} + void BLEAdvertising::set_manufacturer_data(const std::vector &data) { delete[] this->advertising_data_.p_manufacturer_data; this->advertising_data_.p_manufacturer_data = nullptr; @@ -85,8 +96,6 @@ void BLEAdvertising::start() { this->scan_response_data_.set_scan_rsp = true; this->scan_response_data_.include_name = true; this->scan_response_data_.include_txpower = true; - this->scan_response_data_.min_interval = 0; - this->scan_response_data_.max_interval = 0; this->scan_response_data_.manufacturer_len = 0; this->scan_response_data_.appearance = 0; this->scan_response_data_.flag = 0; diff --git a/esphome/components/esp32_ble/ble_advertising.h b/esphome/components/esp32_ble/ble_advertising.h index 9e4e2b7701..16a7dd1d8e 100644 --- a/esphome/components/esp32_ble/ble_advertising.h +++ b/esphome/components/esp32_ble/ble_advertising.h @@ -21,6 +21,7 @@ class BLEAdvertising { void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; } void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } void set_manufacturer_data(const std::vector &data); + void set_service_data(const std::vector &data); void start(); void stop(); diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index 8a901a79e5..19340c3dd8 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -189,6 +189,25 @@ void ESP32ImprovComponent::set_state_(improv::State state) { if (state != improv::STATE_STOPPED) this->status_->notify(); } + std::vector service_data(8, 0); + service_data[0] = 0x77; // PR + service_data[1] = 0x46; // IM + service_data[2] = static_cast(state); + + uint8_t capabilities = 0x00; +#ifdef USE_OUTPUT + if (this->status_indicator_ != nullptr) + capabilities |= improv::CAPABILITY_IDENTIFY; +#endif + + service_data[3] = capabilities; + service_data[4] = 0x00; // Reserved + service_data[5] = 0x00; // Reserved + service_data[6] = 0x00; // Reserved + service_data[7] = 0x00; // Reserved + + esp32_ble::global_ble->get_advertising()->set_service_data(service_data); + esp32_ble::global_ble->get_advertising()->start(); } void ESP32ImprovComponent::set_error_(improv::Error error) { From 2aa787f5f0546fbb550ececaffe9d43f019b3053 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:28:03 +1300 Subject: [PATCH 0632/2607] Bump version to 2023.10.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cf267a2424..fead0a5f1f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0b3" +__version__ = "2023.10.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 582b8383d248cd1a8cfd17c3bba39b6341868c52 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:47:03 +1300 Subject: [PATCH 0633/2607] Bump version to 2023.10.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fead0a5f1f..30e7fd7b8e 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0b4" +__version__ = "2023.10.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 8ef743f25e3387ef69fb6f9cb000a492b6bbb2b2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 17 Oct 2023 20:33:19 -1000 Subject: [PATCH 0634/2607] Update docker base and packages + docker python 3.11 (#5473) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- docker/Dockerfile | 73 ++++++++++++++++++++++----------------- requirements_optional.txt | 4 +-- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 5ca36d1c13..f076173519 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,38 +6,47 @@ ARG BASEIMGTYPE=docker # https://github.com/hassio-addons/addon-debian-base/releases -FROM ghcr.io/hassio-addons/debian-base:6.2.3 AS base-hassio -# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye -FROM debian:bullseye-20230208-slim AS base-docker +FROM ghcr.io/hassio-addons/debian-base:7.2.0 AS base-hassio +# https://hub.docker.com/_/debian?tab=tags&page=1&name=bookworm +FROM debian:12.2-slim AS base-docker FROM base-${BASEIMGTYPE} AS base ARG TARGETARCH ARG TARGETVARIANT +# Note that --break-system-packages is used below because +# https://peps.python.org/pep-0668/ added a safety check that prevents +# installing packages with the same name as a system package. This is +# not a problem for us because we are not concerned about overwriting +# system packages because we are running in an isolated container. + RUN \ apt-get update \ # Use pinned versions so that we get updates with build caching && apt-get install -y --no-install-recommends \ - python3=3.9.2-3 \ - python3-pip=20.3.4-4+deb11u1 \ - python3-setuptools=52.0.0-4 \ - python3-cryptography=3.3.2-1 \ - python3-venv=3.9.2-3 \ - iputils-ping=3:20210202-1 \ - git=1:2.30.2-1+deb11u2 \ - curl=7.74.0-1.3+deb11u10 \ - openssh-client=1:8.4p1-5+deb11u2 \ - python3-cffi=1.14.5-1 \ - libcairo2=1.16.0-5 \ + python3-pip=23.0.1+dfsg-1 \ + python3-setuptools=66.1.1-1 \ + python3-venv=3.11.2-1+b1 \ + python3-wheel=0.38.4-2 \ + iputils-ping=3:20221126-1 \ + git=1:2.39.2-1.1 \ + curl=7.88.1-10+deb12u4 \ + openssh-client=1:9.2p1-2+deb12u1 \ + python3-cffi=1.15.1-5 \ + libcairo2=1.16.0-7 \ patch=2.7.6-7; \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ apt-get install -y --no-install-recommends \ build-essential=12.9 \ - python3-dev=3.9.2-3 \ - zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ - libjpeg-dev=1:2.0.6-4 \ - libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ + python3-dev=3.11.2-1+b1 \ + zlib1g-dev=1:1.2.13.dfsg-1 \ + libjpeg-dev=1:2.1.5-2 \ + libfreetype-dev=2.12.1+dfsg-5 \ + libssl-dev=3.0.11-1~deb12u1 \ + libffi-dev=3.4.4-1 \ + cargo=0.66.0+ds1-1 \ + pkg-config=1.8.1-1; \ fi; \ rm -rf \ /tmp/* \ @@ -50,6 +59,7 @@ ENV \ # Store globally installed pio libs in /piolibs PLATFORMIO_GLOBALLIB_DIR=/piolibs + # Support legacy binaries on Debian multiarch system. There is no "correct" way # to do this, other than using properly built toolchains... # See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian @@ -60,8 +70,7 @@ RUN \ RUN \ # Ubuntu python3-pip is missing wheel - pip3 install --no-cache-dir \ - wheel==0.37.1 \ + pip3 install --break-system-packages --no-cache-dir \ platformio==6.1.11 \ # Change some platformio settings && platformio settings set enable_telemetry No \ @@ -70,9 +79,11 @@ RUN \ # First install requirements to leverage caching when requirements don't change +# tmpfs is for https://github.com/rust-lang/cargo/issues/8719 + COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini / -RUN \ - pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ +RUN --mount=type=tmpfs,target=/root/.cargo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \ + pip3 install --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ && /platformio_install_deps.py /platformio.ini --libraries @@ -81,7 +92,7 @@ FROM base AS docker # Copy esphome and install COPY . /esphome -RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome +RUN pip3 install --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome # Settings for dashboard ENV USERNAME="" PASSWORD="" @@ -110,7 +121,7 @@ RUN \ apt-get update \ # Use pinned versions so that we get updates with build caching && apt-get install -y --no-install-recommends \ - nginx-light=1.18.0-6.1+deb11u3 \ + nginx-light=1.22.1-9 \ && rm -rf \ /tmp/* \ /var/{cache,log}/* \ @@ -123,7 +134,7 @@ COPY docker/ha-addon-rootfs/ / # Copy esphome and install COPY . /esphome -RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome +RUN pip3 install --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome # Labels LABEL \ @@ -146,20 +157,20 @@ RUN \ apt-get update \ # Use pinned versions so that we get updates with build caching && apt-get install -y --no-install-recommends \ - clang-format-13=1:13.0.1-6~deb11u1 \ - clang-tidy-11=1:11.0.1-2 \ + clang-format-13=1:13.0.1-11+b2 \ + clang-tidy-14=1:14.0.6-12 \ patch=2.7.6-7 \ - software-properties-common=0.96.20.2-2.1 \ - nano=5.4-2+deb11u2 \ + software-properties-common=0.99.30-4 \ + nano=7.2-1 \ build-essential=12.9 \ - python3-dev=3.9.2-3 \ + python3-dev=3.11.2-1+b1 \ && rm -rf \ /tmp/* \ /var/{cache,log}/* \ /var/lib/apt/lists/* COPY requirements_test.txt / -RUN pip3 install --no-cache-dir -r /requirements_test.txt +RUN pip3 install --break-system-packages --no-cache-dir -r /requirements_test.txt VOLUME ["/esphome"] WORKDIR /esphome diff --git a/requirements_optional.txt b/requirements_optional.txt index 236f5e3f13..40c27f8547 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,3 +1,3 @@ pillow==10.0.1 -cairosvg>=2.2.0 -cryptography>=2.0.0,<4 +cairosvg==2.7.1 +cryptography==41.0.4 From cdc4f7f59b53d185bf1a252dd57a24c648ba47ff Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 18 Oct 2023 01:33:36 -0500 Subject: [PATCH 0635/2607] IDF 5 fixes for various components from test1.yaml (#5451) --- esphome/components/binary_sensor/automation.cpp | 11 ++++++----- esphome/components/binary_sensor/automation.h | 1 + esphome/components/canbus/canbus.cpp | 16 +++++++++------- esphome/components/canbus/canbus.h | 1 + .../components/climate_ir_lg/climate_ir_lg.cpp | 4 ++-- esphome/components/climate_ir_lg/climate_ir_lg.h | 2 ++ esphome/components/coolix/coolix.cpp | 4 ++-- esphome/components/coolix/coolix.h | 2 ++ esphome/components/cs5460a/cs5460a.cpp | 4 ++-- esphome/components/cs5460a/cs5460a.h | 2 ++ .../deep_sleep/deep_sleep_component.cpp | 13 +++++++------ .../components/deep_sleep/deep_sleep_component.h | 2 ++ esphome/components/e131/e131.h | 1 + .../e131/e131_addressable_light_effect.cpp | 4 ++-- esphome/components/hlw8012/hlw8012.cpp | 2 +- esphome/components/hlw8012/hlw8012.h | 2 ++ esphome/components/hx711/hx711.cpp | 2 +- esphome/components/hx711/hx711.h | 2 ++ esphome/components/hyt271/hyt271.cpp | 2 +- esphome/components/ili9xxx/ili9xxx_display.cpp | 2 +- esphome/components/ili9xxx/ili9xxx_init.h | 2 ++ esphome/components/ina219/ina219.cpp | 2 +- esphome/components/ina219/ina219.h | 2 ++ esphome/components/max31855/max31855.cpp | 10 +++++----- esphome/components/max31855/max31855.h | 2 ++ esphome/components/max31856/max31856.cpp | 2 +- esphome/components/max31856/max31856.h | 2 ++ esphome/components/mitsubishi/mitsubishi.cpp | 4 ++-- esphome/components/mitsubishi/mitsubishi.h | 2 ++ esphome/components/ota/__init__.py | 2 +- esphome/components/ota/automation.h | 2 +- esphome/components/power_supply/power_supply.cpp | 2 +- esphome/components/power_supply/power_supply.h | 2 ++ .../pulse_counter/pulse_counter_sensor.cpp | 6 +++--- .../pulse_counter/pulse_counter_sensor.h | 2 ++ .../pulse_meter/pulse_meter_sensor.cpp | 12 +++++++----- .../components/pulse_meter/pulse_meter_sensor.h | 2 ++ .../pvvx_mithermometer/display/pvvx_display.cpp | 6 +++++- .../pvvx_mithermometer/display/pvvx_display.h | 2 ++ esphome/components/rdm6300/rdm6300.cpp | 2 +- esphome/components/rdm6300/rdm6300.h | 1 + esphome/components/remote_base/__init__.py | 13 ++++--------- .../components/remote_base/coolix_protocol.cpp | 6 +++--- esphome/components/remote_base/coolix_protocol.h | 2 ++ .../components/remote_base/drayton_protocol.cpp | 6 +++--- .../components/remote_base/drayton_protocol.h | 2 ++ esphome/components/remote_base/jvc_protocol.cpp | 2 +- esphome/components/remote_base/jvc_protocol.h | 2 ++ esphome/components/remote_base/lg_protocol.cpp | 2 +- esphome/components/remote_base/lg_protocol.h | 2 ++ .../remote_base/magiquest_protocol.cpp | 2 +- .../components/remote_base/magiquest_protocol.h | 2 ++ esphome/components/remote_base/nexa_protocol.cpp | 2 +- esphome/components/remote_base/nexa_protocol.h | 2 ++ .../remote_base/panasonic_protocol.cpp | 2 +- .../components/remote_base/panasonic_protocol.h | 2 ++ esphome/components/remote_base/raw_protocol.cpp | 8 ++++---- esphome/components/remote_base/raw_protocol.h | 1 + .../remote_base/samsung36_protocol.cpp | 2 +- .../components/remote_base/samsung36_protocol.h | 2 ++ esphome/components/remote_base/sony_protocol.cpp | 2 +- esphome/components/remote_base/sony_protocol.h | 2 ++ .../components/remote_receiver/remote_receiver.h | 2 ++ .../remote_receiver/remote_receiver_esp32.cpp | 2 +- esphome/components/sgp30/sgp30.cpp | 2 +- esphome/components/sgp30/sgp30.h | 2 ++ esphome/components/sht3xd/sht3xd.cpp | 2 +- esphome/components/sht3xd/sht3xd.h | 2 ++ esphome/components/sht4x/sht4x.cpp | 2 +- esphome/components/sht4x/sht4x.h | 2 ++ esphome/components/sts3x/sts3x.cpp | 2 +- esphome/components/sts3x/sts3x.h | 2 ++ .../template_alarm_control_panel.cpp | 12 ++++++------ .../template_alarm_control_panel.h | 1 + esphome/components/tsl2591/tsl2591.cpp | 4 ++-- esphome/components/tsl2591/tsl2591.h | 2 ++ esphome/components/uart/switch/uart_switch.cpp | 2 +- esphome/components/uart/switch/uart_switch.h | 1 + .../components/ultrasonic/ultrasonic_sensor.cpp | 6 +++--- .../components/ultrasonic/ultrasonic_sensor.h | 2 ++ esphome/components/whynter/whynter.cpp | 4 ++-- esphome/components/whynter/whynter.h | 2 ++ 82 files changed, 173 insertions(+), 97 deletions(-) diff --git a/esphome/components/binary_sensor/automation.cpp b/esphome/components/binary_sensor/automation.cpp index ce082aafb3..bfec882e07 100644 --- a/esphome/components/binary_sensor/automation.cpp +++ b/esphome/components/binary_sensor/automation.cpp @@ -22,7 +22,7 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) { // Start matching MultiClickTriggerEvent evt = this->timing_[0]; if (evt.state == state) { - ESP_LOGV(TAG, "START min=%u max=%u", evt.min_length, evt.max_length); + ESP_LOGV(TAG, "START min=%" PRIu32 " max=%" PRIu32, evt.min_length, evt.max_length); ESP_LOGV(TAG, "Multi Click: Starting multi click action!"); this->at_index_ = 1; if (this->timing_.size() == 1 && evt.max_length == 4294967294UL) { @@ -51,15 +51,15 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) { MultiClickTriggerEvent evt = this->timing_[*this->at_index_]; if (evt.max_length != 4294967294UL) { - ESP_LOGV(TAG, "A i=%u min=%u max=%u", *this->at_index_, evt.min_length, evt.max_length); // NOLINT + ESP_LOGV(TAG, "A i=%u min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT this->schedule_is_valid_(evt.min_length); this->schedule_is_not_valid_(evt.max_length); } else if (*this->at_index_ + 1 != this->timing_.size()) { - ESP_LOGV(TAG, "B i=%u min=%u", *this->at_index_, evt.min_length); // NOLINT + ESP_LOGV(TAG, "B i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT this->cancel_timeout("is_not_valid"); this->schedule_is_valid_(evt.min_length); } else { - ESP_LOGV(TAG, "C i=%u min=%u", *this->at_index_, evt.min_length); // NOLINT + ESP_LOGV(TAG, "C i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT this->is_valid_ = false; this->cancel_timeout("is_not_valid"); this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); }); @@ -68,7 +68,8 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) { *this->at_index_ = *this->at_index_ + 1; } void binary_sensor::MultiClickTrigger::schedule_cooldown_() { - ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %u ms...", this->invalid_cooldown_); + ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %" PRIu32 " ms...", + this->invalid_cooldown_); this->is_in_cooldown_ = true; this->set_timeout("cooldown", this->invalid_cooldown_, [this]() { ESP_LOGV(TAG, "Multi Click: Cooldown ended, matching is now enabled again."); diff --git a/esphome/components/binary_sensor/automation.h b/esphome/components/binary_sensor/automation.h index de527d1070..a5e9d208a1 100644 --- a/esphome/components/binary_sensor/automation.h +++ b/esphome/components/binary_sensor/automation.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/esphome/components/canbus/canbus.cpp b/esphome/components/canbus/canbus.cpp index 6316c77ff4..8cffebdaa0 100644 --- a/esphome/components/canbus/canbus.cpp +++ b/esphome/components/canbus/canbus.cpp @@ -16,9 +16,9 @@ void Canbus::setup() { void Canbus::dump_config() { if (this->use_extended_id_) { - ESP_LOGCONFIG(TAG, "config extended id=0x%08x", this->can_id_); + ESP_LOGCONFIG(TAG, "config extended id=0x%08" PRIx32, this->can_id_); } else { - ESP_LOGCONFIG(TAG, "config standard id=0x%03x", this->can_id_); + ESP_LOGCONFIG(TAG, "config standard id=0x%03" PRIx32, this->can_id_); } } @@ -28,9 +28,11 @@ void Canbus::send_data(uint32_t can_id, bool use_extended_id, bool remote_transm uint8_t size = static_cast(data.size()); if (use_extended_id) { - ESP_LOGD(TAG, "send extended id=0x%08x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); + ESP_LOGD(TAG, "send extended id=0x%08" PRIx32 " rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), + size); } else { - ESP_LOGD(TAG, "send standard id=0x%03x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); + ESP_LOGD(TAG, "send standard id=0x%03" PRIx32 " rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), + size); } if (size > CAN_MAX_DATA_LENGTH) size = CAN_MAX_DATA_LENGTH; @@ -63,10 +65,10 @@ void Canbus::loop() { while (this->read_message(&can_message) == canbus::ERROR_OK) { message_counter++; if (can_message.use_extended_id) { - ESP_LOGD(TAG, "received can message (#%d) extended can_id=0x%x size=%d", message_counter, can_message.can_id, - can_message.can_data_length_code); + ESP_LOGD(TAG, "received can message (#%d) extended can_id=0x%" PRIx32 " size=%d", message_counter, + can_message.can_id, can_message.can_data_length_code); } else { - ESP_LOGD(TAG, "received can message (#%d) std can_id=0x%x size=%d", message_counter, can_message.can_id, + ESP_LOGD(TAG, "received can message (#%d) std can_id=0x%" PRIx32 " size=%d", message_counter, can_message.can_id, can_message.can_data_length_code); } diff --git a/esphome/components/canbus/canbus.h b/esphome/components/canbus/canbus.h index c0ccff4866..1e5214fef4 100644 --- a/esphome/components/canbus/canbus.h +++ b/esphome/components/canbus/canbus.h @@ -4,6 +4,7 @@ #include "esphome/core/component.h" #include "esphome/core/optional.h" +#include #include namespace esphome { diff --git a/esphome/components/climate_ir_lg/climate_ir_lg.cpp b/esphome/components/climate_ir_lg/climate_ir_lg.cpp index a41aad1bd0..d2199c1cbe 100644 --- a/esphome/components/climate_ir_lg/climate_ir_lg.cpp +++ b/esphome/components/climate_ir_lg/climate_ir_lg.cpp @@ -121,7 +121,7 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { } } - ESP_LOGD(TAG, "Decoded 0x%02X", remote_state); + ESP_LOGD(TAG, "Decoded 0x%02" PRIX32, remote_state); if ((remote_state & 0xFF00000) != 0x8800000) return false; @@ -173,7 +173,7 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { } void LgIrClimate::transmit_(uint32_t value) { calc_checksum_(value); - ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02X", value); + ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02" PRIX32, value); auto transmit = this->transmitter_->transmit(); auto *data = transmit.get_data(); diff --git a/esphome/components/climate_ir_lg/climate_ir_lg.h b/esphome/components/climate_ir_lg/climate_ir_lg.h index 6b38b3247b..34f50744ef 100644 --- a/esphome/components/climate_ir_lg/climate_ir_lg.h +++ b/esphome/components/climate_ir_lg/climate_ir_lg.h @@ -2,6 +2,8 @@ #include "esphome/components/climate_ir/climate_ir.h" +#include + namespace esphome { namespace climate_ir_lg { diff --git a/esphome/components/coolix/coolix.cpp b/esphome/components/coolix/coolix.cpp index 6233014a96..f4309419a4 100644 --- a/esphome/components/coolix/coolix.cpp +++ b/esphome/components/coolix/coolix.cpp @@ -101,7 +101,7 @@ void CoolixClimate::transmit_state() { } } } - ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state); + ESP_LOGV(TAG, "Sending coolix code: 0x%06" PRIX32, remote_state); auto transmit = this->transmitter_->transmit(); auto *data = transmit.get_data(); @@ -115,7 +115,7 @@ bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteRecei return false; // Decoded remote state y 3 bytes long code. uint32_t remote_state = (*decoded).second; - ESP_LOGV(TAG, "Decoded 0x%06X", remote_state); + ESP_LOGV(TAG, "Decoded 0x%06" PRIX32, remote_state); if ((remote_state & 0xFF0000) != 0xB20000) return false; diff --git a/esphome/components/coolix/coolix.h b/esphome/components/coolix/coolix.h index 3419795875..f4b4ff8e0e 100644 --- a/esphome/components/coolix/coolix.h +++ b/esphome/components/coolix/coolix.h @@ -2,6 +2,8 @@ #include "esphome/components/climate_ir/climate_ir.h" +#include + namespace esphome { namespace coolix { diff --git a/esphome/components/cs5460a/cs5460a.cpp b/esphome/components/cs5460a/cs5460a.cpp index fb8e50b87a..0d347ae0c1 100644 --- a/esphome/components/cs5460a/cs5460a.cpp +++ b/esphome/components/cs5460a/cs5460a.cpp @@ -86,7 +86,7 @@ void CS5460AComponent::hw_init_() { } uint32_t status = this->read_register_(REG_STATUS); - ESP_LOGCONFIG(TAG, " Version: %x", (status >> 6) & 7); + ESP_LOGCONFIG(TAG, " Version: %" PRIx32, (status >> 6) & 7); this->write_register_(REG_CYCLE_COUNT, samples_); this->write_register_(REG_PULSE_RATE, lroundf(pulse_freq_ * 32.0f)); @@ -323,7 +323,7 @@ void CS5460AComponent::dump_config() { ESP_LOGCONFIG(TAG, " Init status: %s", state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other")); LOG_PIN(" CS Pin: ", cs_); - ESP_LOGCONFIG(TAG, " Samples / cycle: %u", samples_); + ESP_LOGCONFIG(TAG, " Samples / cycle: %" PRIu32, samples_); ESP_LOGCONFIG(TAG, " Phase offset: %i", phase_offset_); ESP_LOGCONFIG(TAG, " PGA Gain: %s", pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x"); ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_); diff --git a/esphome/components/cs5460a/cs5460a.h b/esphome/components/cs5460a/cs5460a.h index 699049757c..763ddc14fa 100644 --- a/esphome/components/cs5460a/cs5460a.h +++ b/esphome/components/cs5460a/cs5460a.h @@ -5,6 +5,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/spi/spi.h" +#include + namespace esphome { namespace cs5460a { diff --git a/esphome/components/deep_sleep/deep_sleep_component.cpp b/esphome/components/deep_sleep/deep_sleep_component.cpp index f6472a123c..328e972e6b 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.cpp +++ b/esphome/components/deep_sleep/deep_sleep_component.cpp @@ -39,7 +39,7 @@ void DeepSleepComponent::setup() { const optional run_duration = get_run_duration_(); if (run_duration.has_value()) { - ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %u ms", *run_duration); + ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %" PRIu32 " ms", *run_duration); this->set_timeout(*run_duration, [this]() { this->begin_sleep(); }); } else { ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured."); @@ -49,19 +49,20 @@ void DeepSleepComponent::dump_config() { ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); if (this->sleep_duration_.has_value()) { uint32_t duration = *this->sleep_duration_ / 1000; - ESP_LOGCONFIG(TAG, " Sleep Duration: %u ms", duration); + ESP_LOGCONFIG(TAG, " Sleep Duration: %" PRIu32 " ms", duration); } if (this->run_duration_.has_value()) { - ESP_LOGCONFIG(TAG, " Run Duration: %u ms", *this->run_duration_); + ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " ms", *this->run_duration_); } #ifdef USE_ESP32 if (wakeup_pin_ != nullptr) { LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_); } if (this->wakeup_cause_to_run_duration_.has_value()) { - ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->default_cause); - ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->touch_cause); - ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->gpio_cause); + ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms", + this->wakeup_cause_to_run_duration_->default_cause); + ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause); + ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause); } #endif } diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h index 2e54e53c56..e97d8300c4 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.h +++ b/esphome/components/deep_sleep/deep_sleep_component.h @@ -14,6 +14,8 @@ #include "esphome/core/time.h" #endif +#include + namespace esphome { namespace deep_sleep { diff --git a/esphome/components/e131/e131.h b/esphome/components/e131/e131.h index 364a05af75..91b67f62eb 100644 --- a/esphome/components/e131/e131.h +++ b/esphome/components/e131/e131.h @@ -3,6 +3,7 @@ #include "esphome/components/socket/socket.h" #include "esphome/core/component.h" +#include #include #include #include diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index 6b6a726ef3..be3144f590 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -57,8 +57,8 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1)); auto *input_data = packet.values + 1; - ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %d-%d.", get_name().c_str(), universe, output_offset, - output_end); + ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %" PRId32 "-%d.", get_name().c_str(), universe, + output_offset, output_end); switch (channels_) { case E131_MONO: diff --git a/esphome/components/hlw8012/hlw8012.cpp b/esphome/components/hlw8012/hlw8012.cpp index ecdaa07ab2..1a9f47faaf 100644 --- a/esphome/components/hlw8012/hlw8012.cpp +++ b/esphome/components/hlw8012/hlw8012.cpp @@ -38,7 +38,7 @@ void HLW8012Component::dump_config() { LOG_PIN(" SEL Pin: ", this->sel_pin_) LOG_PIN(" CF Pin: ", this->cf_pin_) LOG_PIN(" CF1 Pin: ", this->cf1_pin_) - ESP_LOGCONFIG(TAG, " Change measurement mode every %u", this->change_mode_every_); + ESP_LOGCONFIG(TAG, " Change measurement mode every %" PRIu32, this->change_mode_every_); ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f); ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_); LOG_UPDATE_INTERVAL(this) diff --git a/esphome/components/hlw8012/hlw8012.h b/esphome/components/hlw8012/hlw8012.h index adb49ffb66..312391f533 100644 --- a/esphome/components/hlw8012/hlw8012.h +++ b/esphome/components/hlw8012/hlw8012.h @@ -5,6 +5,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/pulse_counter/pulse_counter_sensor.h" +#include + namespace esphome { namespace hlw8012 { diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp index 62adc4ae86..dbbf4c91f4 100644 --- a/esphome/components/hx711/hx711.cpp +++ b/esphome/components/hx711/hx711.cpp @@ -28,7 +28,7 @@ void HX711Sensor::update() { uint32_t result; if (this->read_sensor_(&result)) { int32_t value = static_cast(result); - ESP_LOGD(TAG, "'%s': Got value %d", this->name_.c_str(), value); + ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), value); this->publish_state(value); } } diff --git a/esphome/components/hx711/hx711.h b/esphome/components/hx711/hx711.h index 9fef649b03..0cb6868ab5 100644 --- a/esphome/components/hx711/hx711.h +++ b/esphome/components/hx711/hx711.h @@ -4,6 +4,8 @@ #include "esphome/core/hal.h" #include "esphome/components/sensor/sensor.h" +#include + namespace esphome { namespace hx711 { diff --git a/esphome/components/hyt271/hyt271.cpp b/esphome/components/hyt271/hyt271.cpp index 94558fff04..3b81294cfc 100644 --- a/esphome/components/hyt271/hyt271.cpp +++ b/esphome/components/hyt271/hyt271.cpp @@ -17,7 +17,7 @@ void HYT271Component::dump_config() { LOG_SENSOR(" ", "Humidity", this->humidity_); } void HYT271Component::update() { - uint8_t raw_data[4]; + uint8_t raw_data[4] = {0, 0, 0, 0}; if (this->write(&raw_data[0], 0) != i2c::ERROR_OK) { this->status_set_warning(); diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index fdbf3e3760..902a9e6245 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -180,7 +180,7 @@ void ILI9XXXDisplay::display_() { ESP_LOGV(TAG, "Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, " - "heigth:%d, start_pos:%d)", + "heigth:%d, start_pos:%" PRId32 ")", this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos); this->start_data_(); diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 031dc25f91..e3be9389b7 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -1,6 +1,8 @@ #pragma once #include "esphome/core/helpers.h" +#include + namespace esphome { namespace ili9xxx { diff --git a/esphome/components/ina219/ina219.cpp b/esphome/components/ina219/ina219.cpp index 609f3d0f08..2fb3bea356 100644 --- a/esphome/components/ina219/ina219.cpp +++ b/esphome/components/ina219/ina219.cpp @@ -122,7 +122,7 @@ void INA219Component::setup() { this->calibration_lsb_ = lsb; auto calibration = uint32_t(0.04096f / (0.000001 * lsb * this->shunt_resistance_ohm_)); - ESP_LOGV(TAG, " Using LSB=%u calibration=%u", lsb, calibration); + ESP_LOGV(TAG, " Using LSB=%" PRIu32 " calibration=%" PRIu32, lsb, calibration); if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) { this->mark_failed(); return; diff --git a/esphome/components/ina219/ina219.h b/esphome/components/ina219/ina219.h index 31cd22375e..a6c0f2bc4c 100644 --- a/esphome/components/ina219/ina219.h +++ b/esphome/components/ina219/ina219.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" +#include + namespace esphome { namespace ina219 { diff --git a/esphome/components/max31855/max31855.cpp b/esphome/components/max31855/max31855.cpp index 2578c4742d..445e086ef6 100644 --- a/esphome/components/max31855/max31855.cpp +++ b/esphome/components/max31855/max31855.cpp @@ -47,7 +47,7 @@ void MAX31855Sensor::read_data_() { if (mem != 0xFFFFFFFF) { this->status_clear_error(); } else { - ESP_LOGE(TAG, "No data received from MAX31855 (0x%08X). Check wiring!", mem); + ESP_LOGE(TAG, "No data received from MAX31855 (0x%08" PRIX32 "). Check wiring!", mem); this->publish_state(NAN); if (this->temperature_reference_) { this->temperature_reference_->publish_state(NAN); @@ -69,25 +69,25 @@ void MAX31855Sensor::read_data_() { // Check thermocouple faults if (mem & 0x00000001) { - ESP_LOGW(TAG, "Thermocouple open circuit (not connected) fault from MAX31855 (0x%08X)", mem); + ESP_LOGW(TAG, "Thermocouple open circuit (not connected) fault from MAX31855 (0x%08" PRIX32 ")", mem); this->publish_state(NAN); this->status_set_warning(); return; } if (mem & 0x00000002) { - ESP_LOGW(TAG, "Thermocouple short circuit to ground fault from MAX31855 (0x%08X)", mem); + ESP_LOGW(TAG, "Thermocouple short circuit to ground fault from MAX31855 (0x%08" PRIX32 ")", mem); this->publish_state(NAN); this->status_set_warning(); return; } if (mem & 0x00000004) { - ESP_LOGW(TAG, "Thermocouple short circuit to VCC fault from MAX31855 (0x%08X)", mem); + ESP_LOGW(TAG, "Thermocouple short circuit to VCC fault from MAX31855 (0x%08" PRIX32 ")", mem); this->publish_state(NAN); this->status_set_warning(); return; } if (mem & 0x00010000) { - ESP_LOGW(TAG, "Got faulty reading from MAX31855 (0x%08X)", mem); + ESP_LOGW(TAG, "Got faulty reading from MAX31855 (0x%08" PRIX32 ")", mem); this->publish_state(NAN); this->status_set_warning(); return; diff --git a/esphome/components/max31855/max31855.h b/esphome/components/max31855/max31855.h index c0ed8a467d..822e256587 100644 --- a/esphome/components/max31855/max31855.h +++ b/esphome/components/max31855/max31855.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/spi/spi.h" +#include + namespace esphome { namespace max31855 { diff --git a/esphome/components/max31856/max31856.cpp b/esphome/components/max31856/max31856.cpp index 9300916fdc..8ae4be6657 100644 --- a/esphome/components/max31856/max31856.cpp +++ b/esphome/components/max31856/max31856.cpp @@ -188,7 +188,7 @@ uint32_t MAX31856Sensor::read_register24_(uint8_t reg) { ESP_LOGVV(TAG, "read_byte lsb=0x%02X", lsb); this->disable(); const uint32_t value((msb << 16) | (mid << 8) | lsb); - ESP_LOGV(TAG, "read_register_24_ reg=0x%02X: value=0x%06X", reg, value); + ESP_LOGV(TAG, "read_register_24_ reg=0x%02X: value=0x%06" PRIX32, reg, value); return value; } diff --git a/esphome/components/max31856/max31856.h b/esphome/components/max31856/max31856.h index 157aad433c..4deb6bc855 100644 --- a/esphome/components/max31856/max31856.h +++ b/esphome/components/max31856/max31856.h @@ -4,6 +4,8 @@ #include "esphome/components/spi/spi.h" #include "esphome/core/component.h" +#include + namespace esphome { namespace max31856 { diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index 99ca6d1cc5..87b78128e4 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -45,8 +45,8 @@ void MitsubishiClimate::transmit_state() { remote_state[7] = (uint8_t) roundf(clamp(this->target_temperature, MITSUBISHI_TEMP_MIN, MITSUBISHI_TEMP_MAX) - MITSUBISHI_TEMP_MIN); - ESP_LOGV(TAG, "Sending Mitsubishi target temp: %.1f state: %02X mode: %02X temp: %02X", this->target_temperature, - remote_state[5], remote_state[6], remote_state[7]); + ESP_LOGV(TAG, "Sending Mitsubishi target temp: %.1f state: %02" PRIX32 " mode: %02" PRIX32 " temp: %02" PRIX32, + this->target_temperature, remote_state[5], remote_state[6], remote_state[7]); // Checksum for (int i = 0; i < 17; i++) { diff --git a/esphome/components/mitsubishi/mitsubishi.h b/esphome/components/mitsubishi/mitsubishi.h index e6bd7b8ebe..9a88040d3f 100644 --- a/esphome/components/mitsubishi/mitsubishi.h +++ b/esphome/components/mitsubishi/mitsubishi.h @@ -2,6 +2,8 @@ #include "esphome/components/climate_ir/climate_ir.h" +#include + namespace esphome { namespace mitsubishi { diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index eb2a83272d..039596d897 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -128,7 +128,7 @@ async def to_code(config): use_state_callback = True for conf in config.get(CONF_ON_ERROR, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - await automation.build_automation(trigger, [(int, "x")], conf) + await automation.build_automation(trigger, [(cg.uint8, "x")], conf) use_state_callback = True if use_state_callback: cg.add_define("USE_OTA_STATE_CALLBACK") diff --git a/esphome/components/ota/automation.h b/esphome/components/ota/automation.h index 6c8aca3705..0c77a18ce1 100644 --- a/esphome/components/ota/automation.h +++ b/esphome/components/ota/automation.h @@ -54,7 +54,7 @@ class OTAEndTrigger : public Trigger<> { } }; -class OTAErrorTrigger : public Trigger { +class OTAErrorTrigger : public Trigger { public: explicit OTAErrorTrigger(OTAComponent *parent) { parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp index a492919202..c4d157615a 100644 --- a/esphome/components/power_supply/power_supply.cpp +++ b/esphome/components/power_supply/power_supply.cpp @@ -16,7 +16,7 @@ void PowerSupply::setup() { void PowerSupply::dump_config() { ESP_LOGCONFIG(TAG, "Power Supply:"); LOG_PIN(" Pin: ", this->pin_); - ESP_LOGCONFIG(TAG, " Time to enable: %u ms", this->enable_time_); + ESP_LOGCONFIG(TAG, " Time to enable: %" PRIu32 " ms", this->enable_time_); ESP_LOGCONFIG(TAG, " Keep on time: %.1f s", this->keep_on_time_ / 1000.0f); } diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h index 66e4a7565a..49d905ba3a 100644 --- a/esphome/components/power_supply/power_supply.h +++ b/esphome/components/power_supply/power_supply.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" +#include + namespace esphome { namespace power_supply { diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.cpp b/esphome/components/pulse_counter/pulse_counter_sensor.cpp index 1f50360fed..281a61a66a 100644 --- a/esphome/components/pulse_counter/pulse_counter_sensor.cpp +++ b/esphome/components/pulse_counter/pulse_counter_sensor.cpp @@ -104,7 +104,7 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) { if (this->filter_us != 0) { uint16_t filter_val = std::min(static_cast(this->filter_us * 80u), 1023u); - ESP_LOGCONFIG(TAG, " Filter Value: %uus (val=%u)", this->filter_us, filter_val); + ESP_LOGCONFIG(TAG, " Filter Value: %" PRIu32 "us (val=%u)", this->filter_us, filter_val); error = pcnt_set_filter_value(this->pcnt_unit, filter_val); if (error != ESP_OK) { ESP_LOGE(TAG, "Setting filter value failed: %s", esp_err_to_name(error)); @@ -161,7 +161,7 @@ void PulseCounterSensor::dump_config() { LOG_PIN(" Pin: ", this->pin_); ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]); ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]); - ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %u µs", this->storage_.filter_us); + ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %" PRIu32 " µs", this->storage_.filter_us); LOG_UPDATE_INTERVAL(this); } @@ -177,7 +177,7 @@ void PulseCounterSensor::update() { if (this->total_sensor_ != nullptr) { current_total_ += raw; - ESP_LOGD(TAG, "'%s': Total : %i pulses", this->get_name().c_str(), current_total_); + ESP_LOGD(TAG, "'%s': Total : %" PRIu32 " pulses", this->get_name().c_str(), current_total_); this->total_sensor_->publish_state(current_total_); } this->last_time_ = now; diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.h b/esphome/components/pulse_counter/pulse_counter_sensor.h index ef944f106f..ef9f73f95c 100644 --- a/esphome/components/pulse_counter/pulse_counter_sensor.h +++ b/esphome/components/pulse_counter/pulse_counter_sensor.h @@ -4,6 +4,8 @@ #include "esphome/core/hal.h" #include "esphome/components/sensor/sensor.h" +#include + #if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) #include #define HAS_PCNT diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index be5fad6fe5..6c4ebe002e 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -61,12 +61,13 @@ void PulseMeterSensor::loop() { const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_; switch (this->meter_state_) { - // Running and initial states can timeout + // Running and initial states can timeout case MeterState::INITIAL: case MeterState::RUNNING: { if (time_since_valid_edge_us > this->timeout_us_) { this->meter_state_ = MeterState::TIMED_OUT; - ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000); + ESP_LOGD(TAG, "No pulse detected for %" PRIu32 "s, assuming 0 pulses/min", + time_since_valid_edge_us / 1000000); this->publish_state(0.0f); } } break; @@ -82,11 +83,12 @@ void PulseMeterSensor::dump_config() { LOG_SENSOR("", "Pulse Meter", this); LOG_PIN(" Pin: ", this->pin_); if (this->filter_mode_ == FILTER_EDGE) { - ESP_LOGCONFIG(TAG, " Filtering rising edges less than %u µs apart", this->filter_us_); + ESP_LOGCONFIG(TAG, " Filtering rising edges less than %" PRIu32 " µs apart", this->filter_us_); } else { - ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %u µs", this->filter_us_); + ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %" PRIu32 " µs", this->filter_us_); } - ESP_LOGCONFIG(TAG, " Assuming 0 pulses/min after not receiving a pulse for %us", this->timeout_us_ / 1000000); + ESP_LOGCONFIG(TAG, " Assuming 0 pulses/min after not receiving a pulse for %" PRIu32 "s", + this->timeout_us_ / 1000000); } void IRAM_ATTR PulseMeterSensor::edge_intr(PulseMeterSensor *sensor) { diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index f376ea48a5..fc8d47538f 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -5,6 +5,8 @@ #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include + namespace esphome { namespace pulse_meter { diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp index 384537e5d7..fc200f7d71 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp @@ -14,7 +14,7 @@ void PVVXDisplay::dump_config() { ESP_LOGCONFIG(TAG, " Characteristic UUID : %s", this->char_uuid_.to_string().c_str()); ESP_LOGCONFIG(TAG, " Auto clear : %s", YESNO(this->auto_clear_enabled_)); ESP_LOGCONFIG(TAG, " Set time on connection: %s", YESNO(this->time_ != nullptr)); - ESP_LOGCONFIG(TAG, " Disconnect delay : %dms", this->disconnect_delay_ms_); + ESP_LOGCONFIG(TAG, " Disconnect delay : %" PRIu32 "ms", this->disconnect_delay_ms_); LOG_UPDATE_INTERVAL(this); } @@ -139,7 +139,11 @@ void PVVXDisplay::sync_time_() { } time.recalc_timestamp_utc(true); // calculate timestamp of local time uint8_t blk[5] = {}; +#if ESP_IDF_VERSION_MAJOR >= 5 + ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str().c_str(), time.timestamp); +#else ESP_LOGD(TAG, "[%s] Sync time with timestamp %lu.", this->parent_->address_str().c_str(), time.timestamp); +#endif blk[0] = 0x23; blk[1] = time.timestamp & 0xff; blk[2] = (time.timestamp >> 8) & 0xff; diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.h b/esphome/components/pvvx_mithermometer/display/pvvx_display.h index c7e7cc04fb..dfeb49c49d 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.h +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.h @@ -4,6 +4,8 @@ #include "esphome/core/defines.h" #include "esphome/components/ble_client/ble_client.h" +#include + #ifdef USE_ESP32 #include #ifdef USE_TIME diff --git a/esphome/components/rdm6300/rdm6300.cpp b/esphome/components/rdm6300/rdm6300.cpp index 434b9f5720..bfdd880079 100644 --- a/esphome/components/rdm6300/rdm6300.cpp +++ b/esphome/components/rdm6300/rdm6300.cpp @@ -57,7 +57,7 @@ void rdm6300::RDM6300Component::loop() { trig->process(result); if (report) { - ESP_LOGD(TAG, "Found new tag with ID %u", result); + ESP_LOGD(TAG, "Found new tag with ID %" PRIu32, result); } } } diff --git a/esphome/components/rdm6300/rdm6300.h b/esphome/components/rdm6300/rdm6300.h index 0aeabef2bc..1a1a0c0cd6 100644 --- a/esphome/components/rdm6300/rdm6300.h +++ b/esphome/components/rdm6300/rdm6300.h @@ -5,6 +5,7 @@ #include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/uart/uart.h" +#include #include namespace esphome { diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 5a703066a1..cf2ae89b6a 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -372,19 +372,14 @@ def coolix_binary_sensor(var, config): if isinstance(config, dict): cg.add( var.set_data( - cg.StructInitializer( - CoolixData, - ("first", config[CONF_FIRST]), - ("second", config[CONF_SECOND]), + cg.ArrayInitializer( + config[CONF_FIRST], + config[CONF_SECOND], ) ) ) else: - cg.add( - var.set_data( - cg.StructInitializer(CoolixData, ("first", 0), ("second", config)) - ) - ) + cg.add(var.set_data(cg.ArrayInitializer(0, config))) @register_action("coolix", CoolixAction, COOLIX_BASE_SCHEMA) diff --git a/esphome/components/remote_base/coolix_protocol.cpp b/esphome/components/remote_base/coolix_protocol.cpp index 295fccb762..21a9f598b7 100644 --- a/esphome/components/remote_base/coolix_protocol.cpp +++ b/esphome/components/remote_base/coolix_protocol.cpp @@ -101,11 +101,11 @@ optional CoolixProtocol::decode(RemoteReceiveData data) { void CoolixProtocol::dump(const CoolixData &data) { if (data.is_strict()) { - ESP_LOGI(TAG, "Received Coolix: 0x%06X", data.first); + ESP_LOGI(TAG, "Received Coolix: 0x%06" PRIX32, data.first); } else if (data.has_second()) { - ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06X, 0x%06X]", data.first, data.second); + ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06" PRIX32 ", 0x%06" PRIX32 "]", data.first, data.second); } else { - ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06X]", data.first); + ESP_LOGI(TAG, "Received unstrict Coolix: [0x%06" PRIX32 "]", data.first); } } diff --git a/esphome/components/remote_base/coolix_protocol.h b/esphome/components/remote_base/coolix_protocol.h index 50ac839200..b66415ff70 100644 --- a/esphome/components/remote_base/coolix_protocol.h +++ b/esphome/components/remote_base/coolix_protocol.h @@ -4,6 +4,8 @@ #include "esphome/core/helpers.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/drayton_protocol.cpp b/esphome/components/remote_base/drayton_protocol.cpp index 56a3dec1e0..12a553455f 100644 --- a/esphome/components/remote_base/drayton_protocol.cpp +++ b/esphome/components/remote_base/drayton_protocol.cpp @@ -114,7 +114,7 @@ void DraytonProtocol::encode(RemoteTransmitData *dst, const DraytonData &data) { out_data <<= NBITS_CHANNEL; out_data |= data.channel; - ESP_LOGV(TAG, "Send Drayton: out_data %08x", out_data); + ESP_LOGV(TAG, "Send Drayton: out_data %08" PRIx32, out_data); for (uint32_t mask = 1UL << (NBITS - 1); mask != 0; mask >>= 1) { if (out_data & mask) { @@ -169,7 +169,7 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { (src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) { out_data |= 1 << bit; } else { - ESP_LOGV(TAG, "Decode Drayton: Fail 1, - %d", src.get_index()); + ESP_LOGV(TAG, "Decode Drayton: Fail 1, - %" PRIu32, src.get_index()); return {}; } @@ -194,7 +194,7 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { } else if (src.expect_mark(BIT_TIME_US) || src.expect_mark(2 * BIT_TIME_US)) { out_data |= 1; } - ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08x", bit, out_data); + ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08" PRIx32, bit, out_data); out.channel = (uint8_t) (out_data & 0x1F); out_data >>= NBITS_CHANNEL; diff --git a/esphome/components/remote_base/drayton_protocol.h b/esphome/components/remote_base/drayton_protocol.h index f468e7b57e..75213b9186 100644 --- a/esphome/components/remote_base/drayton_protocol.h +++ b/esphome/components/remote_base/drayton_protocol.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/jvc_protocol.cpp b/esphome/components/remote_base/jvc_protocol.cpp index 3d34cc614e..ca423b61e6 100644 --- a/esphome/components/remote_base/jvc_protocol.cpp +++ b/esphome/components/remote_base/jvc_protocol.cpp @@ -46,7 +46,7 @@ optional JVCProtocol::decode(RemoteReceiveData src) { } return out; } -void JVCProtocol::dump(const JVCData &data) { ESP_LOGI(TAG, "Received JVC: data=0x%04X", data.data); } +void JVCProtocol::dump(const JVCData &data) { ESP_LOGI(TAG, "Received JVC: data=0x%04" PRIX32, data.data); } } // namespace remote_base } // namespace esphome diff --git a/esphome/components/remote_base/jvc_protocol.h b/esphome/components/remote_base/jvc_protocol.h index fc40a6a874..a17e593ad2 100644 --- a/esphome/components/remote_base/jvc_protocol.h +++ b/esphome/components/remote_base/jvc_protocol.h @@ -2,6 +2,8 @@ #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/lg_protocol.cpp b/esphome/components/remote_base/lg_protocol.cpp index d7d3a5ac7d..d25c59d2b1 100644 --- a/esphome/components/remote_base/lg_protocol.cpp +++ b/esphome/components/remote_base/lg_protocol.cpp @@ -51,7 +51,7 @@ optional LGProtocol::decode(RemoteReceiveData src) { return out; } void LGProtocol::dump(const LGData &data) { - ESP_LOGI(TAG, "Received LG: data=0x%08X, nbits=%d", data.data, data.nbits); + ESP_LOGI(TAG, "Received LG: data=0x%08" PRIX32 ", nbits=%d", data.data, data.nbits); } } // namespace remote_base diff --git a/esphome/components/remote_base/lg_protocol.h b/esphome/components/remote_base/lg_protocol.h index 6267560443..e0039d033d 100644 --- a/esphome/components/remote_base/lg_protocol.h +++ b/esphome/components/remote_base/lg_protocol.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/magiquest_protocol.cpp b/esphome/components/remote_base/magiquest_protocol.cpp index 76024b1eaf..1cec58a55f 100644 --- a/esphome/components/remote_base/magiquest_protocol.cpp +++ b/esphome/components/remote_base/magiquest_protocol.cpp @@ -76,7 +76,7 @@ optional MagiQuestProtocol::decode(RemoteReceiveData src) { return data; } void MagiQuestProtocol::dump(const MagiQuestData &data) { - ESP_LOGI(TAG, "Received MagiQuest: wand_id=0x%08X, magnitude=0x%04X", data.wand_id, data.magnitude); + ESP_LOGI(TAG, "Received MagiQuest: wand_id=0x%08" PRIX32 ", magnitude=0x%04X", data.wand_id, data.magnitude); } } // namespace remote_base diff --git a/esphome/components/remote_base/magiquest_protocol.h b/esphome/components/remote_base/magiquest_protocol.h index 909be346d0..a531a9aee1 100644 --- a/esphome/components/remote_base/magiquest_protocol.h +++ b/esphome/components/remote_base/magiquest_protocol.h @@ -2,6 +2,8 @@ #include "remote_base.h" +#include + /* Based on protocol analysis from * https://arduino-irremote.github.io/Arduino-IRremote/ir__MagiQuest_8cpp_source.html */ diff --git a/esphome/components/remote_base/nexa_protocol.cpp b/esphome/components/remote_base/nexa_protocol.cpp index f4e7d14187..862165714e 100644 --- a/esphome/components/remote_base/nexa_protocol.cpp +++ b/esphome/components/remote_base/nexa_protocol.cpp @@ -232,7 +232,7 @@ optional NexaProtocol::decode(RemoteReceiveData src) { } void NexaProtocol::dump(const NexaData &data) { - ESP_LOGI(TAG, "Received NEXA: device=0x%04X group=%d state=%d channel=%d level=%d", data.device, data.group, + ESP_LOGI(TAG, "Received NEXA: device=0x%04" PRIX32 " group=%d state=%d channel=%d level=%d", data.device, data.group, data.state, data.channel, data.level); } diff --git a/esphome/components/remote_base/nexa_protocol.h b/esphome/components/remote_base/nexa_protocol.h index f1ce380780..4d9443ce0e 100644 --- a/esphome/components/remote_base/nexa_protocol.h +++ b/esphome/components/remote_base/nexa_protocol.h @@ -2,6 +2,8 @@ #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/panasonic_protocol.cpp b/esphome/components/remote_base/panasonic_protocol.cpp index 460ca3b164..d6cf1a160d 100644 --- a/esphome/components/remote_base/panasonic_protocol.cpp +++ b/esphome/components/remote_base/panasonic_protocol.cpp @@ -67,7 +67,7 @@ optional PanasonicProtocol::decode(RemoteReceiveData src) { return out; } void PanasonicProtocol::dump(const PanasonicData &data) { - ESP_LOGI(TAG, "Received Panasonic: address=0x%04X, command=0x%08X", data.address, data.command); + ESP_LOGI(TAG, "Received Panasonic: address=0x%04X, command=0x%08" PRIX32, data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/panasonic_protocol.h b/esphome/components/remote_base/panasonic_protocol.h index eae97a8a14..c81366138a 100644 --- a/esphome/components/remote_base/panasonic_protocol.h +++ b/esphome/components/remote_base/panasonic_protocol.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp index 9304aa3e3d..bdeb935dc4 100644 --- a/esphome/components/remote_base/raw_protocol.cpp +++ b/esphome/components/remote_base/raw_protocol.cpp @@ -17,9 +17,9 @@ bool RawDumper::dump(RemoteReceiveData src) { int written; if (i + 1 < src.size() - 1) { - written = snprintf(buffer + buffer_offset, remaining_length, "%d, ", value); + written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32 ", ", value); } else { - written = snprintf(buffer + buffer_offset, remaining_length, "%d", value); + written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32, value); } if (written < 0 || written >= int(remaining_length)) { @@ -29,9 +29,9 @@ bool RawDumper::dump(RemoteReceiveData src) { buffer_offset = 0; written = sprintf(buffer, " "); if (i + 1 < src.size()) { - written += sprintf(buffer + written, "%d, ", value); + written += sprintf(buffer + written, "%" PRId32 ", ", value); } else { - written += sprintf(buffer + written, "%d", value); + written += sprintf(buffer + written, "%" PRId32, value); } } diff --git a/esphome/components/remote_base/raw_protocol.h b/esphome/components/remote_base/raw_protocol.h index 494903daa8..9b671e611f 100644 --- a/esphome/components/remote_base/raw_protocol.h +++ b/esphome/components/remote_base/raw_protocol.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include #include namespace esphome { diff --git a/esphome/components/remote_base/samsung36_protocol.cpp b/esphome/components/remote_base/samsung36_protocol.cpp index 2396986670..bd3eee5849 100644 --- a/esphome/components/remote_base/samsung36_protocol.cpp +++ b/esphome/components/remote_base/samsung36_protocol.cpp @@ -96,7 +96,7 @@ optional Samsung36Protocol::decode(RemoteReceiveData src) { return out; } void Samsung36Protocol::dump(const Samsung36Data &data) { - ESP_LOGI(TAG, "Received Samsung36: address=0x%04X, command=0x%08X", data.address, data.command); + ESP_LOGI(TAG, "Received Samsung36: address=0x%04X, command=0x%08" PRIX32, data.address, data.command); } } // namespace remote_base diff --git a/esphome/components/remote_base/samsung36_protocol.h b/esphome/components/remote_base/samsung36_protocol.h index 4ba6226edd..aa7fd21609 100644 --- a/esphome/components/remote_base/samsung36_protocol.h +++ b/esphome/components/remote_base/samsung36_protocol.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_base/sony_protocol.cpp b/esphome/components/remote_base/sony_protocol.cpp index bcd8e4c8cf..69f2b49c42 100644 --- a/esphome/components/remote_base/sony_protocol.cpp +++ b/esphome/components/remote_base/sony_protocol.cpp @@ -62,7 +62,7 @@ optional SonyProtocol::decode(RemoteReceiveData src) { return out; } void SonyProtocol::dump(const SonyData &data) { - ESP_LOGI(TAG, "Received Sony: data=0x%08X, nbits=%d", data.data, data.nbits); + ESP_LOGI(TAG, "Received Sony: data=0x%08" PRIX32 ", nbits=%d", data.data, data.nbits); } } // namespace remote_base diff --git a/esphome/components/remote_base/sony_protocol.h b/esphome/components/remote_base/sony_protocol.h index aecc8ab91c..d9e4f37d53 100644 --- a/esphome/components/remote_base/sony_protocol.h +++ b/esphome/components/remote_base/sony_protocol.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "remote_base.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index 82c66e3cd0..c1343a8603 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -3,6 +3,8 @@ #include "esphome/core/component.h" #include "esphome/components/remote_base/remote_base.h" +#include + namespace esphome { namespace remote_receiver { diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index 5a7fb3c985..1ebb5a5955 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -62,7 +62,7 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); - ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); + ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_); if (this->is_failed()) { ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); } diff --git a/esphome/components/sgp30/sgp30.cpp b/esphome/components/sgp30/sgp30.cpp index 25a3c1ab8f..0910a32a35 100644 --- a/esphome/components/sgp30/sgp30.cpp +++ b/esphome/components/sgp30/sgp30.cpp @@ -255,7 +255,7 @@ void SGP30Component::dump_config() { } else { ESP_LOGCONFIG(TAG, " Baseline: No baseline configured"); } - ESP_LOGCONFIG(TAG, " Warm up time: %us", this->required_warm_up_time_); + ESP_LOGCONFIG(TAG, " Warm up time: %" PRIu32 "s", this->required_warm_up_time_); } LOG_UPDATE_INTERVAL(this); LOG_SENSOR(" ", "eCO2 sensor", this->eco2_sensor_); diff --git a/esphome/components/sgp30/sgp30.h b/esphome/components/sgp30/sgp30.h index d61eee00db..9e882e6b05 100644 --- a/esphome/components/sgp30/sgp30.h +++ b/esphome/components/sgp30/sgp30.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/sensirion_common/i2c_sensirion.h" #include "esphome/core/preferences.h" + +#include #include namespace esphome { diff --git a/esphome/components/sht3xd/sht3xd.cpp b/esphome/components/sht3xd/sht3xd.cpp index f4bd2da271..25332165c0 100644 --- a/esphome/components/sht3xd/sht3xd.cpp +++ b/esphome/components/sht3xd/sht3xd.cpp @@ -27,7 +27,7 @@ void SHT3XDComponent::setup() { return; } uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); - ESP_LOGV(TAG, " Serial Number: 0x%08X", serial_number); + ESP_LOGV(TAG, " Serial Number: 0x%08" PRIX32, serial_number); } void SHT3XDComponent::dump_config() { ESP_LOGCONFIG(TAG, "SHT3xD:"); diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h index 04023c8a46..4133bf7b93 100644 --- a/esphome/components/sht3xd/sht3xd.h +++ b/esphome/components/sht3xd/sht3xd.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/sensirion_common/i2c_sensirion.h" +#include + namespace esphome { namespace sht3xd { diff --git a/esphome/components/sht4x/sht4x.cpp b/esphome/components/sht4x/sht4x.cpp index 0f9123434d..dea542ea9e 100644 --- a/esphome/components/sht4x/sht4x.cpp +++ b/esphome/components/sht4x/sht4x.cpp @@ -20,7 +20,7 @@ void SHT4XComponent::setup() { if (this->duty_cycle_ > 0.0) { uint32_t heater_interval = (uint32_t) (this->heater_time_ / this->duty_cycle_); - ESP_LOGD(TAG, "Heater interval: %i", heater_interval); + ESP_LOGD(TAG, "Heater interval: %" PRIu32, heater_interval); if (this->heater_power_ == SHT4X_HEATERPOWER_HIGH) { if (this->heater_time_ == SHT4X_HEATERTIME_LONG) { diff --git a/esphome/components/sht4x/sht4x.h b/esphome/components/sht4x/sht4x.h index 01553d5c15..46037bb0e8 100644 --- a/esphome/components/sht4x/sht4x.h +++ b/esphome/components/sht4x/sht4x.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/sensirion_common/i2c_sensirion.h" +#include + namespace esphome { namespace sht4x { diff --git a/esphome/components/sts3x/sts3x.cpp b/esphome/components/sts3x/sts3x.cpp index 5af808b6e7..a533bc1d87 100644 --- a/esphome/components/sts3x/sts3x.cpp +++ b/esphome/components/sts3x/sts3x.cpp @@ -30,7 +30,7 @@ void STS3XComponent::setup() { return; } uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16); - ESP_LOGV(TAG, " Serial Number: 0x%08X", serial_number); + ESP_LOGV(TAG, " Serial Number: 0x%08" PRIX32, serial_number); } void STS3XComponent::dump_config() { ESP_LOGCONFIG(TAG, "STS3x:"); diff --git a/esphome/components/sts3x/sts3x.h b/esphome/components/sts3x/sts3x.h index 261033efad..8f806a3471 100644 --- a/esphome/components/sts3x/sts3x.h +++ b/esphome/components/sts3x/sts3x.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/sensirion_common/i2c_sensirion.h" +#include + namespace esphome { namespace sts3x { diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp index da56976b56..b39b587811 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp @@ -26,14 +26,14 @@ void TemplateAlarmControlPanel::dump_config() { ESP_LOGCONFIG(TAG, " Number of Codes: %u", this->codes_.size()); if (!this->codes_.empty()) ESP_LOGCONFIG(TAG, " Requires Code To Arm: %s", YESNO(this->requires_code_to_arm_)); - ESP_LOGCONFIG(TAG, " Arming Away Time: %us", (this->arming_away_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Arming Away Time: %" PRIu32 "s", (this->arming_away_time_ / 1000)); if (this->arming_home_time_ != 0) - ESP_LOGCONFIG(TAG, " Arming Home Time: %us", (this->arming_home_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Arming Home Time: %" PRIu32 "s", (this->arming_home_time_ / 1000)); if (this->arming_night_time_ != 0) - ESP_LOGCONFIG(TAG, " Arming Night Time: %us", (this->arming_night_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Pending Time: %us", (this->pending_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Trigger Time: %us", (this->trigger_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Supported Features: %u", this->get_supported_features()); + ESP_LOGCONFIG(TAG, " Arming Night Time: %" PRIu32 "s", (this->arming_night_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Pending Time: %" PRIu32 "s", (this->pending_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Trigger Time: %" PRIu32 "s", (this->trigger_time_ / 1000)); + ESP_LOGCONFIG(TAG, " Supported Features: %" PRIu32, this->get_supported_features()); #ifdef USE_BINARY_SENSOR for (auto sensor_pair : this->sensor_map_) { ESP_LOGCONFIG(TAG, " Binary Sesnsor:"); diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h index ebd8696692..9582ed157c 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "esphome/core/automation.h" diff --git a/esphome/components/tsl2591/tsl2591.cpp b/esphome/components/tsl2591/tsl2591.cpp index 5086a38408..977048364c 100644 --- a/esphome/components/tsl2591/tsl2591.cpp +++ b/esphome/components/tsl2591/tsl2591.cpp @@ -142,8 +142,8 @@ void TSL2591Component::process_update_() { uint16_t full = this->get_illuminance(TSL2591_SENSOR_CHANNEL_FULL_SPECTRUM, combined); float lux = this->get_calculated_lux(full, infrared); uint16_t actual_gain = this->get_actual_gain(); - ESP_LOGD(TAG, "Got illuminance: combined 0x%X, full %d, IR %d, vis %d. Calc lux: %f. Actual gain: %d.", combined, - full, infrared, visible, lux, actual_gain); + ESP_LOGD(TAG, "Got illuminance: combined 0x%" PRIX32 ", full %d, IR %d, vis %d. Calc lux: %f. Actual gain: %d.", + combined, full, infrared, visible, lux, actual_gain); if (this->full_spectrum_sensor_ != nullptr) { this->full_spectrum_sensor_->publish_state(full); } diff --git a/esphome/components/tsl2591/tsl2591.h b/esphome/components/tsl2591/tsl2591.h index d7c5230276..fa302b14b0 100644 --- a/esphome/components/tsl2591/tsl2591.h +++ b/esphome/components/tsl2591/tsl2591.h @@ -4,6 +4,8 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" +#include + namespace esphome { namespace tsl2591 { diff --git a/esphome/components/uart/switch/uart_switch.cpp b/esphome/components/uart/switch/uart_switch.cpp index b995aca98c..1edb54641b 100644 --- a/esphome/components/uart/switch/uart_switch.cpp +++ b/esphome/components/uart/switch/uart_switch.cpp @@ -53,7 +53,7 @@ void UARTSwitch::write_state(bool state) { void UARTSwitch::dump_config() { LOG_SWITCH("", "UART Switch", this); if (this->send_every_) { - ESP_LOGCONFIG(TAG, " Send Every: %u", this->send_every_); + ESP_LOGCONFIG(TAG, " Send Every: %" PRIu32, this->send_every_); } } diff --git a/esphome/components/uart/switch/uart_switch.h b/esphome/components/uart/switch/uart_switch.h index eb3d697a58..4ef5b6da4b 100644 --- a/esphome/components/uart/switch/uart_switch.h +++ b/esphome/components/uart/switch/uart_switch.h @@ -4,6 +4,7 @@ #include "esphome/components/uart/uart.h" #include "esphome/components/switch/switch.h" +#include #include namespace esphome { diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.cpp b/esphome/components/ultrasonic/ultrasonic_sensor.cpp index dc828aed6b..604e78d6f8 100644 --- a/esphome/components/ultrasonic/ultrasonic_sensor.cpp +++ b/esphome/components/ultrasonic/ultrasonic_sensor.cpp @@ -30,7 +30,7 @@ void UltrasonicSensorComponent::update() { ; const uint32_t pulse_end = micros(); - ESP_LOGV(TAG, "Echo took %uµs", pulse_end - pulse_start); + ESP_LOGV(TAG, "Echo took %" PRIu32 "µs", pulse_end - pulse_start); if (pulse_end - start >= timeout_us_) { ESP_LOGD(TAG, "'%s' - Distance measurement timed out!", this->name_.c_str()); @@ -45,8 +45,8 @@ void UltrasonicSensorComponent::dump_config() { LOG_SENSOR("", "Ultrasonic Sensor", this); LOG_PIN(" Echo Pin: ", this->echo_pin_); LOG_PIN(" Trigger Pin: ", this->trigger_pin_); - ESP_LOGCONFIG(TAG, " Pulse time: %u µs", this->pulse_time_us_); - ESP_LOGCONFIG(TAG, " Timeout: %u µs", this->timeout_us_); + ESP_LOGCONFIG(TAG, " Pulse time: %" PRIu32 " µs", this->pulse_time_us_); + ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " µs", this->timeout_us_); LOG_UPDATE_INTERVAL(this); } float UltrasonicSensorComponent::us_to_m(uint32_t us) { diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.h b/esphome/components/ultrasonic/ultrasonic_sensor.h index e0d71b99ef..1a255d6122 100644 --- a/esphome/components/ultrasonic/ultrasonic_sensor.h +++ b/esphome/components/ultrasonic/ultrasonic_sensor.h @@ -4,6 +4,8 @@ #include "esphome/core/gpio.h" #include "esphome/components/sensor/sensor.h" +#include + namespace esphome { namespace ultrasonic { diff --git a/esphome/components/whynter/whynter.cpp b/esphome/components/whynter/whynter.cpp index 190bf70acc..9f57fdb843 100644 --- a/esphome/components/whynter/whynter.cpp +++ b/esphome/components/whynter/whynter.cpp @@ -118,7 +118,7 @@ bool Whynter::on_receive(remote_base::RemoteReceiveData data) { } } - ESP_LOGD(TAG, "Decoded 0x%02X", remote_state); + ESP_LOGD(TAG, "Decoded 0x%02" PRIX32, remote_state); if ((remote_state & COMMAND_MASK) != COMMAND_CODE) return false; if ((remote_state & POWER_MASK) != POWER_MASK) { @@ -156,7 +156,7 @@ bool Whynter::on_receive(remote_base::RemoteReceiveData data) { } void Whynter::transmit_(uint32_t value) { - ESP_LOGD(TAG, "Sending whynter code: 0x%02X", value); + ESP_LOGD(TAG, "Sending Whynter code: 0x%02" PRIX32, value); auto transmit = this->transmitter_->transmit(); auto *data = transmit.get_data(); diff --git a/esphome/components/whynter/whynter.h b/esphome/components/whynter/whynter.h index 939583ebfb..8273c21e4b 100644 --- a/esphome/components/whynter/whynter.h +++ b/esphome/components/whynter/whynter.h @@ -2,6 +2,8 @@ #include "esphome/components/climate_ir/climate_ir.h" +#include + namespace esphome { namespace whynter { From 19736f6e537269fff2ec42b0348b43b277dc8fb2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:12:35 +1300 Subject: [PATCH 0636/2607] Fix voice_assistant without a speaker (#5558) --- esphome/components/voice_assistant/voice_assistant.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 27dc201073..df7853156d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -316,8 +316,8 @@ void VoiceAssistant::loop() { this->speaker_buffer_index_ = 0; memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); } -#endif this->wait_for_stream_end_ = false; +#endif this->set_state_(State::IDLE, State::IDLE); break; } @@ -586,7 +586,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { +#ifdef USE_SPEAKER this->wait_for_stream_end_ = true; +#endif break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { From b735fc475e65799a5d95fb7a4bf4f51b82efdfc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 08:28:52 -1000 Subject: [PATCH 0637/2607] Bump aioesphomeapi from 15.0.0 to 18.0.6 (#5557) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 97e42663d7..44a9dc4916 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.11 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 -aioesphomeapi==15.0.0 +aioesphomeapi==18.0.6 zeroconf==0.115.1 # esp-idf requires this, but doesn't bundle it by default From 10c89771e35776c3f90fbcac95fdcabb2e479812 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:21:19 -1000 Subject: [PATCH 0638/2607] Bump zeroconf from 0.115.1 to 0.119.0 (#5560) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 44a9dc4916..23d133a6ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 aioesphomeapi==18.0.6 -zeroconf==0.115.1 +zeroconf==0.119.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From a8667b680ec76907f2b5da8f06b557e44ea097ca Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:42:52 +1300 Subject: [PATCH 0639/2607] esp32_improv add timeout (#5556) --- esphome/components/esp32_improv/__init__.py | 5 +++++ .../esp32_improv/esp32_improv_component.h | 5 +++++ esphome/components/wifi/wifi_component.cpp | 14 +++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index fba2e55ae8..49d95d89e5 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -36,6 +36,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional( CONF_AUTHORIZED_DURATION, default="1min" ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_WIFI_TIMEOUT, default="1min" + ): cv.positive_time_period_milliseconds, } ).extend(cv.COMPONENT_SCHEMA) @@ -53,6 +56,8 @@ async def to_code(config): cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) + cg.add(var.set_wifi_timeout(config[CONF_WIFI_TIMEOUT])) + if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None: activator = await cg.get_variable(config[CONF_AUTHORIZER]) cg.add(var.set_authorizer(activator)) diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h index ba9892d6a5..00c6cf885a 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.h +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -51,6 +51,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } + void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; } + uint32_t get_wifi_timeout() const { return this->wifi_timeout_; } + protected: bool should_start_{false}; bool setup_complete_{false}; @@ -60,6 +63,8 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { uint32_t authorized_start_{0}; uint32_t authorized_duration_; + uint32_t wifi_timeout_{}; + std::vector incoming_data_; wifi::WiFiAP connecting_sta_; diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 2cb36fe8ea..b08f20de21 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -8,16 +8,16 @@ #include #endif -#include #include -#include "lwip/err.h" +#include #include "lwip/dns.h" +#include "lwip/err.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" #include "esphome/core/util.h" -#include "esphome/core/application.h" #ifdef USE_CAPTIVE_PORTAL #include "esphome/components/captive_portal/captive_portal.h" @@ -96,7 +96,7 @@ void WiFiComponent::start() { #endif } #ifdef USE_IMPROV - if (esp32_improv::global_improv_component != nullptr) { + if (!this->has_sta() && esp32_improv::global_improv_component != nullptr) { if (this->wifi_mode_(true, {})) esp32_improv::global_improv_component->start(); } @@ -163,8 +163,8 @@ void WiFiComponent::loop() { } #ifdef USE_IMPROV - if (esp32_improv::global_improv_component != nullptr) { - if (!this->is_connected()) { + if (esp32_improv::global_improv_component != nullptr && !esp32_improv::global_improv_component->is_active()) { + if (now - this->last_connected_ > esp32_improv::global_improv_component->get_wifi_timeout()) { if (this->wifi_mode_(true, {})) esp32_improv::global_improv_component->start(); } From b7402ee6ffb99b1b0433ea2e00e665f9dde82dd3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:25:43 +1300 Subject: [PATCH 0640/2607] Create IPv4 sockets if ipv6 is not enabled (#5565) --- esphome/components/socket/socket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 824e04150b..d0fce9198f 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -10,7 +10,7 @@ namespace socket { Socket::~Socket() {} std::unique_ptr socket_ip(int type, int protocol) { -#if LWIP_IPV6 +#if ENABLE_IPV6 return socket(AF_INET6, type, protocol); #else return socket(AF_INET, type, protocol); @@ -18,7 +18,7 @@ std::unique_ptr socket_ip(int type, int protocol) { } socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) { -#if LWIP_IPV6 +#if ENABLE_IPV6 if (addrlen < sizeof(sockaddr_in6)) { errno = EINVAL; return 0; @@ -51,7 +51,7 @@ socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::stri } socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) { -#if LWIP_IPV6 +#if ENABLE_IPV6 if (addrlen < sizeof(sockaddr_in6)) { errno = EINVAL; return 0; From 799c3cf439b4f2a72c0c37c42955d6e38eb334ff Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Wed, 18 Oct 2023 19:00:15 -0500 Subject: [PATCH 0641/2607] Incorrect ESP32 Strapping PIN Defined (#5563) Co-authored-by: descipher <120155735+GelidusResearch@users.noreply.github.com> --- esphome/components/esp32/gpio_esp32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32/gpio_esp32.py b/esphome/components/esp32/gpio_esp32.py index 66ba2ffa62..91f006444c 100644 --- a/esphome/components/esp32/gpio_esp32.py +++ b/esphome/components/esp32/gpio_esp32.py @@ -18,7 +18,7 @@ _ESP_SDIO_PINS = { 11: "Flash Command", } -_ESP32_STRAPPING_PINS = {0, 2, 4, 12, 15} +_ESP32_STRAPPING_PINS = {0, 2, 5, 12, 15} _LOGGER = logging.getLogger(__name__) From a794836ebe9c50feb2213b71d30d13e55a778ca2 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 19 Oct 2023 09:04:53 +0900 Subject: [PATCH 0642/2607] Add config to allow suppression of warnings about use of strapping pins (#5287) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32/gpio.py | 2 ++ esphome/components/esp32/gpio_esp32.py | 9 ++------- esphome/components/esp32/gpio_esp32_c2.py | 10 +++------- esphome/components/esp32/gpio_esp32_c3.py | 10 +++------- esphome/components/esp32/gpio_esp32_c6.py | 10 +++------- esphome/components/esp32/gpio_esp32_s2.py | 9 ++------- esphome/components/esp32/gpio_esp32_s3.py | 11 +++-------- esphome/const.py | 1 + esphome/pins.py | 17 ++++++++++++++++- tests/test8.yaml | 4 +++- 10 files changed, 38 insertions(+), 45 deletions(-) diff --git a/esphome/components/esp32/gpio.py b/esphome/components/esp32/gpio.py index 6950cd58a0..a53649e3e4 100644 --- a/esphome/components/esp32/gpio.py +++ b/esphome/components/esp32/gpio.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_OUTPUT, CONF_PULLDOWN, CONF_PULLUP, + CONF_IGNORE_STRAPPING_WARNING, ) from esphome import pins from esphome.core import CORE @@ -176,6 +177,7 @@ ESP32_PIN_SCHEMA = cv.All( } ), cv.Optional(CONF_INVERTED, default=False): cv.boolean, + cv.Optional(CONF_IGNORE_STRAPPING_WARNING, default=False): cv.boolean, cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All( cv.float_with_unit("current", "mA", optional_unit=True), cv.enum(DRIVE_STRENGTHS), diff --git a/esphome/components/esp32/gpio_esp32.py b/esphome/components/esp32/gpio_esp32.py index 91f006444c..d10b266c7a 100644 --- a/esphome/components/esp32/gpio_esp32.py +++ b/esphome/components/esp32/gpio_esp32.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_PULLUP, ) import esphome.config_validation as cv +from esphome.pins import check_strapping_pin _ESP_SDIO_PINS = { @@ -35,13 +36,6 @@ def esp32_validate_gpio_pin(value): "flash interface in QUAD IO flash mode.", value, ) - if value in _ESP32_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) if value in (24, 28, 29, 30, 31): # These pins are not exposed in GPIO mux (reason unknown) # but they're missing from IO_MUX list in datasheet @@ -74,4 +68,5 @@ def esp32_validate_supports(value): f"GPIO{num} (34-39) does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN] ) + check_strapping_pin(value, _ESP32_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/components/esp32/gpio_esp32_c2.py b/esphome/components/esp32/gpio_esp32_c2.py index c444f804a3..0bee7d82bf 100644 --- a/esphome/components/esp32/gpio_esp32_c2.py +++ b/esphome/components/esp32/gpio_esp32_c2.py @@ -1,6 +1,7 @@ import logging from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER +from esphome.pins import check_strapping_pin import esphome.config_validation as cv @@ -12,13 +13,6 @@ _LOGGER = logging.getLogger(__name__) def esp32_c2_validate_gpio_pin(value): if value < 0 or value > 20: raise cv.Invalid(f"Invalid pin number: {value} (must be 0-20)") - if value in _ESP32C2_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) return value @@ -34,4 +28,6 @@ def esp32_c2_validate_supports(value): if is_input: # All ESP32 pins support input mode pass + + check_strapping_pin(value, _ESP32C2_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/components/esp32/gpio_esp32_c3.py b/esphome/components/esp32/gpio_esp32_c3.py index fc1cef29e5..6c70c09f9e 100644 --- a/esphome/components/esp32/gpio_esp32_c3.py +++ b/esphome/components/esp32/gpio_esp32_c3.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_NUMBER, ) import esphome.config_validation as cv +from esphome.pins import check_strapping_pin _ESP32C3_SPI_PSRAM_PINS = { 12: "SPIHD", @@ -28,13 +29,6 @@ def esp32_c3_validate_gpio_pin(value): raise cv.Invalid( f"This pin cannot be used on ESP32-C3s and is already used by the SPI/PSRAM interface (function: {_ESP32C3_SPI_PSRAM_PINS[value]})" ) - if value in _ESP32C3_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) return value @@ -50,4 +44,6 @@ def esp32_c3_validate_supports(value): if is_input: # All ESP32 pins support input mode pass + + check_strapping_pin(value, _ESP32C3_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/components/esp32/gpio_esp32_c6.py b/esphome/components/esp32/gpio_esp32_c6.py index b26b6bc6b4..a1f777c625 100644 --- a/esphome/components/esp32/gpio_esp32_c6.py +++ b/esphome/components/esp32/gpio_esp32_c6.py @@ -3,6 +3,7 @@ import logging from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER import esphome.config_validation as cv +from esphome.pins import check_strapping_pin _ESP32C6_SPI_PSRAM_PINS = { 24: "SPICS0", @@ -26,13 +27,6 @@ def esp32_c6_validate_gpio_pin(value): raise cv.Invalid( f"This pin cannot be used on ESP32-C6s and is already used by the SPI/PSRAM interface (function: {_ESP32C6_SPI_PSRAM_PINS[value]})" ) - if value in _ESP32C6_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) return value @@ -47,4 +41,6 @@ def esp32_c6_validate_supports(value): if is_input: # All ESP32 pins support input mode pass + + check_strapping_pin(value, _ESP32C6_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/components/esp32/gpio_esp32_s2.py b/esphome/components/esp32/gpio_esp32_s2.py index db244b6259..82449532ec 100644 --- a/esphome/components/esp32/gpio_esp32_s2.py +++ b/esphome/components/esp32/gpio_esp32_s2.py @@ -10,6 +10,7 @@ from esphome.const import ( ) import esphome.config_validation as cv +from esphome.pins import check_strapping_pin _ESP32S2_SPI_PSRAM_PINS = { 26: "SPICS1", @@ -34,13 +35,6 @@ def esp32_s2_validate_gpio_pin(value): raise cv.Invalid( f"This pin cannot be used on ESP32-S2s and is already used by the SPI/PSRAM interface (function: {_ESP32S2_SPI_PSRAM_PINS[value]})" ) - if value in _ESP32S2_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) if value in (22, 23, 24, 25): # These pins are not exposed in GPIO mux (reason unknown) @@ -77,4 +71,5 @@ def esp32_s2_validate_supports(value): f"GPIO{num} does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN] ) + check_strapping_pin(value, _ESP32S2_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/components/esp32/gpio_esp32_s3.py b/esphome/components/esp32/gpio_esp32_s3.py index f729a757c2..8dcbf8c7bb 100644 --- a/esphome/components/esp32/gpio_esp32_s3.py +++ b/esphome/components/esp32/gpio_esp32_s3.py @@ -7,6 +7,7 @@ from esphome.const import ( ) import esphome.config_validation as cv +from esphome.pins import check_strapping_pin _ESP_32S3_SPI_PSRAM_PINS = { 26: "SPICS1", @@ -45,14 +46,6 @@ def esp32_s3_validate_gpio_pin(value): value, ) - if value in _ESP_32S3_STRAPPING_PINS: - _LOGGER.warning( - "GPIO%d is a Strapping PIN and should be avoided.\n" - "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" - "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", - value, - ) - if value in (22, 23, 24, 25): # These pins are not exposed in GPIO mux (reason unknown) # but they're missing from IO_MUX list in datasheet @@ -71,4 +64,6 @@ def esp32_s3_validate_supports(value): if is_input: # All ESP32 pins support input mode pass + + check_strapping_pin(value, _ESP_32S3_STRAPPING_PINS, _LOGGER) return value diff --git a/esphome/const.py b/esphome/const.py index eb7a5dab09..be561c2880 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -335,6 +335,7 @@ CONF_IDLE_LEVEL = "idle_level" CONF_IDLE_TIME = "idle_time" CONF_IF = "if" CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc" +CONF_IGNORE_STRAPPING_WARNING = "ignore_strapping_warning" CONF_IIR_FILTER = "iir_filter" CONF_ILLUMINANCE = "illuminance" CONF_IMPEDANCE = "impedance" diff --git a/esphome/pins.py b/esphome/pins.py index 2ac4cd4b54..cec715b922 100644 --- a/esphome/pins.py +++ b/esphome/pins.py @@ -9,11 +9,11 @@ from esphome.const import ( CONF_OUTPUT, CONF_PULLDOWN, CONF_PULLUP, + CONF_IGNORE_STRAPPING_WARNING, ) from esphome.util import SimpleRegistry from esphome.core import CORE - PIN_SCHEMA_REGISTRY = SimpleRegistry() @@ -146,3 +146,18 @@ internal_gpio_input_pullup_pin_number = _internal_number_creator( CONF_PULLUP: True, } ) + + +def check_strapping_pin(conf, strapping_pin_list, logger): + import esphome.config_validation as cv + + num = conf[CONF_NUMBER] + if num in strapping_pin_list and not conf.get(CONF_IGNORE_STRAPPING_WARNING): + logger.warning( + f"GPIO{num} is a strapping PIN and should only be used for I/O with care.\n" + "Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n" + "See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins", + ) + # mitigate undisciplined use of strapping: + if num not in strapping_pin_list and conf.get(CONF_IGNORE_STRAPPING_WARNING): + raise cv.Invalid(f"GPIO{num} is not a strapping pin") diff --git a/tests/test8.yaml b/tests/test8.yaml index 3ba8aa19ef..cbac2cb833 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -65,7 +65,9 @@ i2c: touchscreen: - platform: tt21100 - interrupt_pin: GPIO3 + interrupt_pin: + number: GPIO3 + ignore_strapping_warning: true reset_pin: GPIO48 binary_sensor: From a7d817656e0546b99d629065479b80b25027ee06 Mon Sep 17 00:00:00 2001 From: jj-uk <10943625+jj-uk@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:06:28 +0100 Subject: [PATCH 0643/2607] Hydreon updates (#5424) --- .../components/hydreon_rgxx/hydreon_rgxx.cpp | 36 +++++++++++++++++-- .../components/hydreon_rgxx/hydreon_rgxx.h | 3 ++ esphome/components/hydreon_rgxx/sensor.py | 16 +++++++-- tests/test3.yaml | 6 ++++ 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp index da4345e136..58e00ba7a5 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp @@ -25,6 +25,10 @@ void HydreonRGxxComponent::dump_config() { LOG_SENSOR(" ", #s, this->sensors_[i - 1]); \ } HYDREON_RGXX_PROTOCOL_LIST(HYDREON_RGXX_LOG_SENSOR, ); + + if (this->model_ == RG9) { + ESP_LOGCONFIG(TAG, "disable_led: %s", TRUEFALSE(this->disable_led_)); + } } void HydreonRGxxComponent::setup() { @@ -187,7 +191,20 @@ void HydreonRGxxComponent::process_line_() { this->cancel_interval("reboot"); this->no_response_count_ = 0; ESP_LOGI(TAG, "Boot detected: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); - this->write_str("P\nH\nM\n"); // set sensor to polling mode, high res mode, metric mode + + if (this->model_ == RG15) { + this->write_str("P\nH\nM\n"); // set sensor to (P)polling mode, (H)high res mode, (M)metric mode + } + + if (this->model_ == RG9) { + this->write_str("P\n"); // set sensor to (P)polling mode + + if (this->disable_led_) { + this->write_str("D 1\n"); // set sensor (D 1)rain detection LED disabled + } else { + this->write_str("D 0\n"); // set sensor (D 0)rain detection LED enabled + } + } return; } if (this->buffer_starts_with_("SW")) { @@ -227,7 +244,22 @@ void HydreonRGxxComponent::process_line_() { if (n == std::string::npos) { continue; } - float data = strtof(this->buffer_.substr(n + strlen(PROTOCOL_NAMES[i])).c_str(), nullptr); + + if (n == this->buffer_.find('t', n)) { + // The device temperature ('t') response contains both °C and °F values: + // "t 72F 22C". + // ESPHome uses only °C, only parse °C value (move past 'F'). + n = this->buffer_.find('F', n); + if (n == std::string::npos) { + continue; + } + n += 1; // move past 'F' + } else { + n += strlen(PROTOCOL_NAMES[i]); // move past protocol name + } + + // parse value, starting at str position n + float data = strtof(this->buffer_.substr(n).c_str(), nullptr); this->sensors_[i]->publish_state(data); ESP_LOGD(TAG, "Received %s: %f", PROTOCOL_NAMES[i], this->sensors_[i]->get_raw_state()); this->sensors_received_ |= (1 << i); diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.h b/esphome/components/hydreon_rgxx/hydreon_rgxx.h index 34b9bd8d5e..1edda59800 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.h +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.h @@ -49,6 +49,8 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice { float get_setup_priority() const override; + void set_disable_led(bool disable_led) { this->disable_led_ = disable_led; } + protected: void process_line_(); void schedule_reboot_(); @@ -72,6 +74,7 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice { bool lens_bad_ = false; bool em_sat_ = false; bool request_temperature_ = false; + bool disable_led_ = false; // bit field showing which sensors we have received data for int sensors_received_ = -1; diff --git a/esphome/components/hydreon_rgxx/sensor.py b/esphome/components/hydreon_rgxx/sensor.py index c2dbbd6737..0fc380f959 100644 --- a/esphome/components/hydreon_rgxx/sensor.py +++ b/esphome/components/hydreon_rgxx/sensor.py @@ -25,12 +25,17 @@ CONF_EVENT_ACC = "event_acc" CONF_TOTAL_ACC = "total_acc" CONF_R_INT = "r_int" +CONF_DISABLE_LED = "disable_led" + RG_MODELS = { "RG_9": RGModel.RG9, "RG_15": RGModel.RG15, - # https://rainsensors.com/wp-content/uploads/sites/3/2020/07/rg-15_instructions_sw_1.000.pdf - # https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2020.08.25-rg-9_instructions.pdf - # https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf + # RG-15 + # 1.000 - https://rainsensors.com/wp-content/uploads/sites/3/2020/07/rg-15_instructions_sw_1.000.pdf + # RG-9 + # 1.000 - https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2020.08.25-rg-9_instructions.pdf + # 1.100 - https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf + # 1.200 - https://rainsensors.com/wp-content/uploads/sites/3/2022/03/2022.02.17-rev-1.200-rg-9_instructions.pdf } SUPPORTED_SENSORS = { CONF_ACC: ["RG_15"], @@ -39,6 +44,7 @@ SUPPORTED_SENSORS = { CONF_R_INT: ["RG_15"], CONF_MOISTURE: ["RG_9"], CONF_TEMPERATURE: ["RG_9"], + CONF_DISABLE_LED: ["RG_9"], } PROTOCOL_NAMES = { CONF_MOISTURE: "R", @@ -105,6 +111,7 @@ CONFIG_SCHEMA = cv.All( icon=ICON_THERMOMETER, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_DISABLE_LED): cv.boolean, } ) .extend(cv.polling_component_schema("60s")) @@ -132,3 +139,6 @@ async def to_code(config): cg.add(var.set_sensor(sens, i)) cg.add(var.set_request_temperature(CONF_TEMPERATURE in config)) + + if CONF_DISABLE_LED in config: + cg.add(var.set_disable_led(config[CONF_DISABLE_LED])) diff --git a/tests/test3.yaml b/tests/test3.yaml index e7cf24a95a..41ded7ee39 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -347,6 +347,10 @@ sensor: moisture: name: hydreon_rain id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx model: RG_15 uart_id: uart_6 @@ -358,6 +362,7 @@ sensor: name: hydreon_total_acc r_int: name: hydreon_r_int + - platform: adc pin: VCC id: my_sensor @@ -725,6 +730,7 @@ binary_sensor: name: rg9_emsat lens_bad: name: rg9_lens_bad + - platform: template id: pzemac_reset_energy on_press: From 9a087c07678f22286edced4b4f9a4d283b53e725 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:08:15 +1300 Subject: [PATCH 0644/2607] Bump actions/checkout from 4.1.0 to 4.1.1 (#5551) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 22 +++++++++++----------- .github/workflows/release.yml | 6 +++--- .github/workflows/sync-device-classes.yml | 4 ++-- .github/workflows/yaml-lint.yml | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 897d01398e..51f47d39aa 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Set up Python uses: actions/setup-python@v4.7.1 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 435a2fdbec..70da22e57a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -66,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -87,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -108,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -129,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -150,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -171,7 +171,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -191,7 +191,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -216,7 +216,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Find all YAML test files id: set-matrix run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT @@ -241,7 +241,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -296,7 +296,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7652bf478..14dbeee7b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: outputs: tag: ${{ steps.tag.outputs.tag }} steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Get tag id: tag # yamllint disable rule:line-length @@ -43,7 +43,7 @@ jobs: if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Set up Python uses: actions/setup-python@v4.7.1 with: @@ -88,7 +88,7 @@ jobs: target: "lint" baseimg: "docker" steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Set up Python uses: actions/setup-python@v4.7.1 with: diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 082c63ae41..88edb63546 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -13,10 +13,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Checkout Home Assistant - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 with: repository: home-assistant/core path: lib/home-assistant diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index 65628a22bb..a77bd2c078 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Run yamllint uses: frenck/action-yamllint@v1.4.1 From 53572dcb8a22e78666103f9d3ec9a1031bee7895 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:08:44 +1300 Subject: [PATCH 0645/2607] Bump pyupgrade from 3.10.1 to 3.13.0 (#5428) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- esphome/components/remote_base/__init__.py | 4 ++-- requirements_test.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e7261ebc3..eba6834cb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - --branch=release - --branch=beta - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.13.0 hooks: - id: pyupgrade args: [--py39-plus] diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index cf2ae89b6a..fb9d5e56a6 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -964,7 +964,7 @@ RC_SWITCH_PROTOCOL_SCHEMA = cv.Any( def validate_rc_switch_code(value): - if not isinstance(value, (str, str)): + if not isinstance(value, str): raise cv.Invalid("All RCSwitch codes must be in quotes ('')") for c in value: if c not in ("0", "1"): @@ -981,7 +981,7 @@ def validate_rc_switch_code(value): def validate_rc_switch_raw_code(value): - if not isinstance(value, (str, str)): + if not isinstance(value, str): raise cv.Invalid("All RCSwitch raw codes must be in quotes ('')") for c in value: if c not in ("0", "1", "x"): diff --git a/requirements_test.txt b/requirements_test.txt index 92cb8b1be2..5178c5c11f 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ pylint==2.17.6 flake8==6.1.0 # also change in .pre-commit-config.yaml when updating black==23.9.1 # also change in .pre-commit-config.yaml when updating -pyupgrade==3.10.1 # also change in .pre-commit-config.yaml when updating +pyupgrade==3.13.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests From 960d6a143134dacab67a57cf74d5a0ae037281d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:09:04 +1300 Subject: [PATCH 0646/2607] Bump tzlocal from 5.0.1 to 5.1 (#5480) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 23d133a6ed..4be7279f33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ PyYAML==6.0.1 paho-mqtt==1.6.1 colorama==0.4.6 tornado==6.3.3 -tzlocal==5.0.1 # from time +tzlocal==5.1 # from time tzdata>=2021.1 # from time pyserial==3.5 platformio==6.1.11 # When updating platformio, also update Dockerfile From 02449f24c9718aa959dbd5401a815685215acd59 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:12:35 +1300 Subject: [PATCH 0647/2607] Fix voice_assistant without a speaker (#5558) --- esphome/components/voice_assistant/voice_assistant.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 27dc201073..df7853156d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -316,8 +316,8 @@ void VoiceAssistant::loop() { this->speaker_buffer_index_ = 0; memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); } -#endif this->wait_for_stream_end_ = false; +#endif this->set_state_(State::IDLE, State::IDLE); break; } @@ -586,7 +586,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { +#ifdef USE_SPEAKER this->wait_for_stream_end_ = true; +#endif break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { From 9579423b24545c2921e83897a96ca2370dff44d7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:42:52 +1300 Subject: [PATCH 0648/2607] esp32_improv add timeout (#5556) --- esphome/components/esp32_improv/__init__.py | 5 +++++ .../esp32_improv/esp32_improv_component.h | 5 +++++ esphome/components/wifi/wifi_component.cpp | 14 +++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index fba2e55ae8..49d95d89e5 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -36,6 +36,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional( CONF_AUTHORIZED_DURATION, default="1min" ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_WIFI_TIMEOUT, default="1min" + ): cv.positive_time_period_milliseconds, } ).extend(cv.COMPONENT_SCHEMA) @@ -53,6 +56,8 @@ async def to_code(config): cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) + cg.add(var.set_wifi_timeout(config[CONF_WIFI_TIMEOUT])) + if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None: activator = await cg.get_variable(config[CONF_AUTHORIZER]) cg.add(var.set_authorizer(activator)) diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h index ba9892d6a5..00c6cf885a 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.h +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -51,6 +51,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } + void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; } + uint32_t get_wifi_timeout() const { return this->wifi_timeout_; } + protected: bool should_start_{false}; bool setup_complete_{false}; @@ -60,6 +63,8 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { uint32_t authorized_start_{0}; uint32_t authorized_duration_; + uint32_t wifi_timeout_{}; + std::vector incoming_data_; wifi::WiFiAP connecting_sta_; diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 2cb36fe8ea..b08f20de21 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -8,16 +8,16 @@ #include #endif -#include #include -#include "lwip/err.h" +#include #include "lwip/dns.h" +#include "lwip/err.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" #include "esphome/core/util.h" -#include "esphome/core/application.h" #ifdef USE_CAPTIVE_PORTAL #include "esphome/components/captive_portal/captive_portal.h" @@ -96,7 +96,7 @@ void WiFiComponent::start() { #endif } #ifdef USE_IMPROV - if (esp32_improv::global_improv_component != nullptr) { + if (!this->has_sta() && esp32_improv::global_improv_component != nullptr) { if (this->wifi_mode_(true, {})) esp32_improv::global_improv_component->start(); } @@ -163,8 +163,8 @@ void WiFiComponent::loop() { } #ifdef USE_IMPROV - if (esp32_improv::global_improv_component != nullptr) { - if (!this->is_connected()) { + if (esp32_improv::global_improv_component != nullptr && !esp32_improv::global_improv_component->is_active()) { + if (now - this->last_connected_ > esp32_improv::global_improv_component->get_wifi_timeout()) { if (this->wifi_mode_(true, {})) esp32_improv::global_improv_component->start(); } From fa4ba43eb95b22223863916b2b2f19713d00a35b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:25:43 +1300 Subject: [PATCH 0649/2607] Create IPv4 sockets if ipv6 is not enabled (#5565) --- esphome/components/socket/socket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 824e04150b..d0fce9198f 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -10,7 +10,7 @@ namespace socket { Socket::~Socket() {} std::unique_ptr socket_ip(int type, int protocol) { -#if LWIP_IPV6 +#if ENABLE_IPV6 return socket(AF_INET6, type, protocol); #else return socket(AF_INET, type, protocol); @@ -18,7 +18,7 @@ std::unique_ptr socket_ip(int type, int protocol) { } socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) { -#if LWIP_IPV6 +#if ENABLE_IPV6 if (addrlen < sizeof(sockaddr_in6)) { errno = EINVAL; return 0; @@ -51,7 +51,7 @@ socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::stri } socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) { -#if LWIP_IPV6 +#if ENABLE_IPV6 if (addrlen < sizeof(sockaddr_in6)) { errno = EINVAL; return 0; From f077a5962d6f452bf0ba54cc93904e03784fbc0c Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Wed, 18 Oct 2023 19:00:15 -0500 Subject: [PATCH 0650/2607] Incorrect ESP32 Strapping PIN Defined (#5563) Co-authored-by: descipher <120155735+GelidusResearch@users.noreply.github.com> --- esphome/components/esp32/gpio_esp32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32/gpio_esp32.py b/esphome/components/esp32/gpio_esp32.py index 66ba2ffa62..91f006444c 100644 --- a/esphome/components/esp32/gpio_esp32.py +++ b/esphome/components/esp32/gpio_esp32.py @@ -18,7 +18,7 @@ _ESP_SDIO_PINS = { 11: "Flash Command", } -_ESP32_STRAPPING_PINS = {0, 2, 4, 12, 15} +_ESP32_STRAPPING_PINS = {0, 2, 5, 12, 15} _LOGGER = logging.getLogger(__name__) From db02c4ea21f034d902872f90b58e8e4eb3ab1f57 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:30:13 +1300 Subject: [PATCH 0651/2607] Bump version to 2023.10.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 30e7fd7b8e..bb77fa578d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.10.0" +__version__ = "2023.10.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From e99b8aaf96a965c02530694a4b7c1f25d7547b6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 00:50:09 +0000 Subject: [PATCH 0652/2607] Bump black from 23.9.1 to 23.10.0 (#5561) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eba6834cb6..578e8982da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.9.1 + rev: 23.10.0 hooks: - id: black args: diff --git a/requirements_test.txt b/requirements_test.txt index 5178c5c11f..ee3b5e89c8 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.17.6 flake8==6.1.0 # also change in .pre-commit-config.yaml when updating -black==23.9.1 # also change in .pre-commit-config.yaml when updating +black==23.10.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.13.0 # also change in .pre-commit-config.yaml when updating pre-commit From b9d72231b0f444889c53c4a44afcf5e4fa0c5a8d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:36:01 +1300 Subject: [PATCH 0653/2607] Fix XOR condition (#5567) --- esphome/core/base_automation.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index 9b3377f694..50087f3efd 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -52,12 +52,12 @@ template class XorCondition : public Condition { public: explicit XorCondition(const std::vector *> &conditions) : conditions_(conditions) {} bool check(Ts... x) override { - bool xor_state = false; + size_t result = 0; for (auto *condition : this->conditions_) { - xor_state = xor_state ^ condition->check(x...); + result += condition->check(x...); } - return xor_state; + return result == 1; } protected: From b632ae49d4804a0527cd5162870de6ad2b43b450 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 19 Oct 2023 01:53:09 -0500 Subject: [PATCH 0654/2607] Improv Serial support via USB CDC and JTAG (#5559) --- esphome/components/improv_serial/__init__.py | 13 ++- .../improv_serial/improv_serial_component.cpp | 102 +++++++++++++---- .../improv_serial/improv_serial_component.h | 11 +- esphome/components/logger/logger.cpp | 107 +++++++++++++----- esphome/components/logger/logger.h | 10 ++ 5 files changed, 189 insertions(+), 54 deletions(-) diff --git a/esphome/components/improv_serial/__init__.py b/esphome/components/improv_serial/__init__.py index 311256804b..2b377d77b8 100644 --- a/esphome/components/improv_serial/__init__.py +++ b/esphome/components/improv_serial/__init__.py @@ -1,10 +1,14 @@ -from esphome.components.logger import USB_CDC, USB_SERIAL_JTAG +from esphome.components import improv_base +from esphome.components.esp32 import get_esp32_variant +from esphome.components.esp32.const import ( + VARIANT_ESP32S3, +) +from esphome.components.logger import USB_CDC from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE import esphome.final_validate as fv -from esphome.components import improv_base AUTO_LOAD = ["improv_base"] CODEOWNERS = ["@esphome/core"] @@ -30,7 +34,10 @@ def validate_logger(config): if logger_conf[CONF_BAUD_RATE] == 0: raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0") if CORE.using_esp_idf: - if logger_conf[CONF_HARDWARE_UART] in [USB_SERIAL_JTAG, USB_CDC]: + if ( + logger_conf[CONF_HARDWARE_UART] == USB_CDC + and get_esp32_variant() == VARIANT_ESP32S3 + ): raise cv.Invalid( "improv_serial does not support the selected logger hardware_uart" ) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 1dd1c9cf6f..600069b781 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -31,26 +31,57 @@ void ImprovSerialComponent::setup() { void ImprovSerialComponent::dump_config() { ESP_LOGCONFIG(TAG, "Improv Serial:"); } -int ImprovSerialComponent::available_() { +optional ImprovSerialComponent::read_byte_() { + optional byte; + uint8_t data = 0; #ifdef USE_ARDUINO - return this->hw_serial_->available(); + if (this->hw_serial_->available()) { + this->hw_serial_->readBytes(&data, 1); + byte = data; + } #endif #ifdef USE_ESP_IDF - size_t available; - uart_get_buffered_data_len(this->uart_num_, &available); - return available; + switch (logger::global_logger->get_uart()) { + case logger::UART_SELECTION_UART0: + case logger::UART_SELECTION_UART1: +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) + case logger::UART_SELECTION_UART2: +#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 + if (this->uart_num_ >= 0) { + size_t available; + uart_get_buffered_data_len(this->uart_num_, &available); + if (available) { + uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS); + byte = data; + } + } + break; +#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) + case logger::UART_SELECTION_USB_CDC: +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + if (esp_usb_console_available_for_read()) { +#else + if (esp_usb_console_read_available()) { #endif -} - -uint8_t ImprovSerialComponent::read_byte_() { - uint8_t data; -#ifdef USE_ARDUINO - this->hw_serial_->readBytes(&data, 1); + esp_usb_console_read_buf((char *) &data, 1); + byte = data; + } + break; +#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) + case logger::UART_SELECTION_USB_SERIAL_JTAG: { + if (usb_serial_jtag_read_bytes((char *) &data, 1, 20 / portTICK_PERIOD_MS)) { + byte = data; + } + break; + } +#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 + default: + break; + } #endif -#ifdef USE_ESP_IDF - uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS); -#endif - return data; + return byte; } void ImprovSerialComponent::write_data_(std::vector &data) { @@ -59,24 +90,49 @@ void ImprovSerialComponent::write_data_(std::vector &data) { this->hw_serial_->write(data.data(), data.size()); #endif #ifdef USE_ESP_IDF - uart_write_bytes(this->uart_num_, data.data(), data.size()); + switch (logger::global_logger->get_uart()) { + case logger::UART_SELECTION_UART0: + case logger::UART_SELECTION_UART1: +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ + !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) + case logger::UART_SELECTION_UART2: +#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 + uart_write_bytes(this->uart_num_, data.data(), data.size()); + break; +#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) + case logger::UART_SELECTION_USB_CDC: { + const char *msg = (char *) data.data(); + esp_usb_console_write_buf(msg, data.size()); + break; + } +#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) + case logger::UART_SELECTION_USB_SERIAL_JTAG: + usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); + break; +#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 + default: + break; + } #endif } void ImprovSerialComponent::loop() { - const uint32_t now = millis(); - if (now - this->last_read_byte_ > 50) { + if (this->last_read_byte_ && (millis() - this->last_read_byte_ > IMPROV_SERIAL_TIMEOUT)) { + this->last_read_byte_ = 0; this->rx_buffer_.clear(); - this->last_read_byte_ = now; + ESP_LOGV(TAG, "Improv Serial timeout"); } - while (this->available_()) { - uint8_t byte = this->read_byte_(); - if (this->parse_improv_serial_byte_(byte)) { - this->last_read_byte_ = now; + auto byte = this->read_byte_(); + while (byte.has_value()) { + if (this->parse_improv_serial_byte_(byte.value())) { + this->last_read_byte_ = millis(); } else { + this->last_read_byte_ = 0; this->rx_buffer_.clear(); } + byte = this->read_byte_(); } if (this->state_ == improv::STATE_PROVISIONING) { diff --git a/esphome/components/improv_serial/improv_serial_component.h b/esphome/components/improv_serial/improv_serial_component.h index 731f9f9984..8583d0762b 100644 --- a/esphome/components/improv_serial/improv_serial_component.h +++ b/esphome/components/improv_serial/improv_serial_component.h @@ -14,6 +14,13 @@ #endif #ifdef USE_ESP_IDF #include +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) +#include +#endif +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#include +#endif #endif namespace esphome { @@ -26,6 +33,7 @@ enum ImprovSerialType : uint8_t { TYPE_RPC_RESPONSE = 0x04 }; +static const uint16_t IMPROV_SERIAL_TIMEOUT = 100; static const uint8_t IMPROV_SERIAL_VERSION = 1; class ImprovSerialComponent : public Component, public improv_base::ImprovBase { @@ -48,8 +56,7 @@ class ImprovSerialComponent : public Component, public improv_base::ImprovBase { std::vector build_rpc_settings_response_(improv::Command command); std::vector build_version_info_(); - int available_(); - uint8_t read_byte_(); + optional read_byte_(); void write_data_(std::vector &data); #ifdef USE_ARDUINO diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index d1f3149d84..2d2524b5f4 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -3,8 +3,21 @@ #ifdef USE_ESP_IDF #include + +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) +#include +#include +#include +#endif + #include "freertos/FreeRTOS.h" #include "esp_idf_version.h" + +#include +#include +#include + #endif // USE_ESP_IDF #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_ESP_IDF) @@ -93,6 +106,58 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr } #endif +#ifdef USE_ESP_IDF +void Logger::init_uart_() { + uart_config_t uart_config{}; + uart_config.baud_rate = (int) baud_rate_; + uart_config.data_bits = UART_DATA_8_BITS; + uart_config.parity = UART_PARITY_DISABLE; + uart_config.stop_bits = UART_STOP_BITS_1; + uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + uart_config.source_clk = UART_SCLK_DEFAULT; +#endif + uart_param_config(this->uart_num_, &uart_config); + const int uart_buffer_size = tx_buffer_size_; + // Install UART driver using an event queue here + uart_driver_install(this->uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0); +} + +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +void Logger::init_usb_cdc_() {} +#endif + +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) +void Logger::init_usb_serial_jtag_() { + setvbuf(stdin, NULL, _IONBF, 0); // Disable buffering on stdin + + // Minicom, screen, idf_monitor send CR when ENTER key is pressed + esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + // Move the caret to the beginning of the next line on '\n' + esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + // Enable non-blocking mode on stdin and stdout + fcntl(fileno(stdout), F_SETFL, 0); + fcntl(fileno(stdin), F_SETFL, 0); + + usb_serial_jtag_driver_config_t usb_serial_jtag_config{}; + usb_serial_jtag_config.rx_buffer_size = 512; + usb_serial_jtag_config.tx_buffer_size = 512; + + esp_err_t ret = ESP_OK; + // Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes + ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config); + if (ret != ESP_OK) { + return; + } + + // Tell vfs to use usb-serial-jtag driver + esp_vfs_usb_serial_jtag_use_driver(); +} +#endif +#endif + int HOT Logger::level_for(const char *tag) { // Uses std::vector<> for low memory footprint, though the vector // could be sorted to minimize lookup times. This feature isn't used that @@ -120,19 +185,19 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { #ifdef USE_ESP_IDF if ( #if defined(USE_ESP32_VARIANT_ESP32S2) - uart_ == UART_SELECTION_USB_CDC + this->uart_ == UART_SELECTION_USB_CDC #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) - uart_ == UART_SELECTION_USB_SERIAL_JTAG + this->uart_ == UART_SELECTION_USB_SERIAL_JTAG #elif defined(USE_ESP32_VARIANT_ESP32S3) - uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG + this->uart_ == UART_SELECTION_USB_CDC || this->uart_ == UART_SELECTION_USB_SERIAL_JTAG #else /* DISABLES CODE */ (false) // NOLINT #endif ) { puts(msg); } else { - uart_write_bytes(uart_num_, msg, strlen(msg)); - uart_write_bytes(uart_num_, "\n", 1); + uart_write_bytes(this->uart_num_, msg, strlen(msg)); + uart_write_bytes(this->uart_num_, "\n", 1); } #endif } @@ -209,48 +274,38 @@ void Logger::pre_setup() { } #endif // USE_ARDUINO #ifdef USE_ESP_IDF - uart_num_ = UART_NUM_0; - switch (uart_) { + this->uart_num_ = UART_NUM_0; + switch (this->uart_) { case UART_SELECTION_UART0: - uart_num_ = UART_NUM_0; + this->uart_num_ = UART_NUM_0; break; case UART_SELECTION_UART1: - uart_num_ = UART_NUM_1; + this->uart_num_ = UART_NUM_1; break; #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2) case UART_SELECTION_UART2: - uart_num_ = UART_NUM_2; + this->uart_num_ = UART_NUM_2; break; #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 && // !USE_ESP32_VARIANT_ESP32H2 #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) case UART_SELECTION_USB_CDC: - uart_num_ = -1; + this->uart_num_ = -1; + this->init_usb_cdc_(); break; #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ defined(USE_ESP32_VARIANT_ESP32H2) case UART_SELECTION_USB_SERIAL_JTAG: - uart_num_ = -1; + this->uart_num_ = -1; + this->init_usb_serial_jtag_(); break; #endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 || // USE_ESP32_VARIANT_ESP32H2 } - if (uart_num_ >= 0) { - uart_config_t uart_config{}; - uart_config.baud_rate = (int) baud_rate_; - uart_config.data_bits = UART_DATA_8_BITS; - uart_config.parity = UART_PARITY_DISABLE; - uart_config.stop_bits = UART_STOP_BITS_1; - uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - uart_config.source_clk = UART_SCLK_DEFAULT; -#endif - uart_param_config(uart_num_, &uart_config); - const int uart_buffer_size = tx_buffer_size_; - // Install UART driver using an event queue here - uart_driver_install(uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0); + if (this->uart_num_ >= 0) { + this->init_uart_(); } #endif // USE_ESP_IDF } diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index de272934bf..3816b1dd14 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -107,6 +107,16 @@ class Logger : public Component { #endif protected: +#ifdef USE_ESP_IDF + void init_uart_(); +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + void init_usb_cdc_(); +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32H2) + void init_usb_serial_jtag_(); +#endif +#endif void write_header_(int level, const char *tag, int line); void write_footer_(); void log_message_(int level, const char *tag, int offset = 0); From 9f033bce3b0c2c985c4328295c5e1d111168d157 Mon Sep 17 00:00:00 2001 From: "Jordan W. Cobb" Date: Thu, 19 Oct 2023 03:02:27 -0400 Subject: [PATCH 0655/2607] Fan no off cycle action (#5564) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/fan/__init__.py | 17 +++++++++++++++-- esphome/components/fan/automation.h | 12 ++++++++++-- esphome/const.py | 1 + tests/test1.yaml | 13 ++++++++++++- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 9a05bff3a0..23df3c2214 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_SPEED_LEVEL_STATE_TOPIC, CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC, + CONF_OFF_SPEED_CYCLE, CONF_ON_SPEED_SET, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, @@ -217,10 +218,22 @@ async def fan_turn_on_to_code(config, action_id, template_arg, args): return var -@automation.register_action("fan.cycle_speed", CycleSpeedAction, FAN_ACTION_SCHEMA) +@automation.register_action( + "fan.cycle_speed", + CycleSpeedAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(Fan), + cv.Optional(CONF_OFF_SPEED_CYCLE, default=True): cv.boolean, + } + ), +) async def fan_cycle_speed_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable(config[CONF_OFF_SPEED_CYCLE], args, bool) + cg.add(var.set_no_off_cycle(template_)) + return var @automation.register_condition( diff --git a/esphome/components/fan/automation.h b/esphome/components/fan/automation.h index 23fb70a95b..511acf5682 100644 --- a/esphome/components/fan/automation.h +++ b/esphome/components/fan/automation.h @@ -54,18 +54,26 @@ template class CycleSpeedAction : public Action { public: explicit CycleSpeedAction(Fan *state) : state_(state) {} + TEMPLATABLE_VALUE(bool, no_off_cycle) + void play(Ts... x) override { // check to see if fan supports speeds and is on if (this->state_->get_traits().supported_speed_count()) { if (this->state_->state) { int speed = this->state_->speed + 1; int supported_speed_count = this->state_->get_traits().supported_speed_count(); - if (speed > supported_speed_count) { - // was running at max speed, so turn off + bool off_speed_cycle = no_off_cycle_.value(x...); + if (speed > supported_speed_count && off_speed_cycle) { + // was running at max speed, off speed cycle enabled, so turn off speed = 1; auto call = this->state_->turn_off(); call.set_speed(speed); call.perform(); + } else if (speed > supported_speed_count && !off_speed_cycle) { + // was running at max speed, off speed cycle disabled, so set to lowest speed + auto call = this->state_->turn_on(); + call.set_speed(1); + call.perform(); } else { auto call = this->state_->turn_on(); call.set_speed(speed); diff --git a/esphome/const.py b/esphome/const.py index be561c2880..a06c75ae44 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -475,6 +475,7 @@ CONF_NUM_SCANS = "num_scans" CONF_NUMBER = "number" CONF_NUMBER_DATAPOINT = "number_datapoint" CONF_OFF_MODE = "off_mode" +CONF_OFF_SPEED_CYCLE = "off_speed_cycle" CONF_OFFSET = "offset" CONF_ON = "on" CONF_ON_BLE_ADVERTISE = "on_ble_advertise" diff --git a/tests/test1.yaml b/tests/test1.yaml index 9bf9a32e17..acd119d8a5 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1693,7 +1693,18 @@ binary_sensor: number: 7 mode: INPUT inverted: false - + - platform: gpio + name: Speed Fan Cycle binary sensor" + pin: + number: 18 + mode: + input: true + pulldown: true + on_press: + - fan.cycle_speed: + id: fan_speed + off_speed_cycle: False + - logger.log: "Cycle speed clicked" - platform: remote_receiver name: Raw Remote Receiver Test raw: From d82471942f91a85fe5e4812edfd954f47af74c2b Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Fri, 20 Oct 2023 08:28:05 +1100 Subject: [PATCH 0656/2607] Publish the `pulse_meter` total when setting the total (#5475) --- CODEOWNERS | 2 +- esphome/components/pulse_meter/pulse_meter_sensor.cpp | 7 +++++++ esphome/components/pulse_meter/pulse_meter_sensor.h | 3 ++- esphome/components/pulse_meter/sensor.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index b66da4fc26..0c371d6ee6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -225,7 +225,7 @@ esphome/components/pn532_spi/* @OttoWinter @jesserockz esphome/components/power_supply/* @esphome/core esphome/components/preferences/* @esphome/core esphome/components/psram/* @esphome/core -esphome/components/pulse_meter/* @cstaahl @stevebaxter +esphome/components/pulse_meter/* @TrentHouliston @cstaahl @stevebaxter esphome/components/pvvx_mithermometer/* @pasiz esphome/components/qmp6988/* @andrewpc esphome/components/qr_code/* @wjtje diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 6c4ebe002e..14f8e508b5 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -7,6 +7,13 @@ namespace pulse_meter { static const char *const TAG = "pulse_meter"; +void PulseMeterSensor::set_total_pulses(uint32_t pulses) { + this->total_pulses_ = pulses; + if (this->total_sensor_ != nullptr) { + this->total_sensor_->publish_state(this->total_pulses_); + } +} + void PulseMeterSensor::setup() { this->pin_->setup(); this->isr_pin_ = pin_->to_isr(); diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index fc8d47538f..1cd02e3ca2 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -22,7 +22,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component { void set_timeout_us(uint32_t timeout) { this->timeout_us_ = timeout; } void set_total_sensor(sensor::Sensor *sensor) { this->total_sensor_ = sensor; } void set_filter_mode(InternalFilterMode mode) { this->filter_mode_ = mode; } - void set_total_pulses(uint32_t pulses) { this->total_pulses_ = pulses; } + + void set_total_pulses(uint32_t pulses); void setup() override; void loop() override; diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py index 26bc6b189b..59ffa58c21 100644 --- a/esphome/components/pulse_meter/sensor.py +++ b/esphome/components/pulse_meter/sensor.py @@ -19,7 +19,7 @@ from esphome.const import ( ) from esphome.core import CORE -CODEOWNERS = ["@stevebaxter", "@cstaahl"] +CODEOWNERS = ["@stevebaxter", "@cstaahl", "@TrentHouliston"] pulse_meter_ns = cg.esphome_ns.namespace("pulse_meter") From 76417103c7559cba9cfc7d965133fe0488548193 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:48:56 -1000 Subject: [PATCH 0657/2607] Bump aioesphomeapi from 18.0.6 to 18.0.7 (#5573) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4be7279f33..bfab8e0faf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.11 # When updating platformio, also update Dockerfile esptool==4.6.2 click==8.1.7 esphome-dashboard==20230904.0 -aioesphomeapi==18.0.6 +aioesphomeapi==18.0.7 zeroconf==0.119.0 # esp-idf requires this, but doesn't bundle it by default From 05a95f8ee9f390deab5fca5e4c136fb820b25c6a Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Sat, 21 Oct 2023 06:04:07 +0200 Subject: [PATCH 0658/2607] Remove explicit cast for IPAddress (#5574) * Remove explicit cast for IPAddress * Make linter happy --- esphome/components/mqtt/mqtt_backend_libretiny.h | 4 +--- tests/test9.yaml | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/components/mqtt/mqtt_backend_libretiny.h b/esphome/components/mqtt/mqtt_backend_libretiny.h index 5373a1926a..ac4d4298fc 100644 --- a/esphome/components/mqtt/mqtt_backend_libretiny.h +++ b/esphome/components/mqtt/mqtt_backend_libretiny.h @@ -19,9 +19,7 @@ class MQTTBackendLibreTiny final : public MQTTBackend { void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final { mqtt_client_.setWill(topic, qos, retain, payload); } - void set_server(network::IPAddress ip, uint16_t port) final { - mqtt_client_.setServer(IPAddress(static_cast(ip)), port); - } + void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(IPAddress(ip), port); } void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); } #if ASYNC_TCP_SSL_ENABLED void set_secure(bool secure) { mqtt_client.setSecure(secure); } diff --git a/tests/test9.yaml b/tests/test9.yaml index ccf5f4b5b0..d660b4f24a 100644 --- a/tests/test9.yaml +++ b/tests/test9.yaml @@ -26,3 +26,9 @@ sensor: name: ADC pin: GPIO23 update_interval: 1s + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant From 3d7d0d4f73bc17a86ad25e1cdb725d4d4c1bde55 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:38:22 +0200 Subject: [PATCH 0659/2607] Remove unnecessary checks in Nextion component (#5578) --- esphome/components/nextion/nextion_commands.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index 0409e5ea6c..806e03850f 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -10,15 +10,11 @@ static const char *const TAG = "nextion"; void Nextion::soft_reset() { this->send_command_("rest"); } void Nextion::set_wake_up_page(uint8_t page_id) { - if (page_id > 255) { - ESP_LOGD(TAG, "Wake up page of bounds, range 0-255"); - return; - } this->add_no_result_to_queue_with_set_internal_("wake_up_page", "wup", page_id, true); } void Nextion::set_touch_sleep_timeout(uint16_t timeout) { - if (timeout < 3 || timeout > 65535) { + if (timeout < 3) { ESP_LOGD(TAG, "Sleep timeout out of bounds, range 3-65535"); return; } From e3fbf54a1aafad77ab3125855f21607ed35be74d Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 23 Oct 2023 08:41:16 +0200 Subject: [PATCH 0660/2607] Set addr type when copy from ip4_addr_t (#5583) --- esphome/components/network/ip_address.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 7a4d394805..03ba6e85d5 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -34,7 +34,12 @@ struct IPAddress { } IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); } IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); } - IPAddress(ip4_addr_t *other_ip) { memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); } + IPAddress(ip4_addr_t *other_ip) { + memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); +#if USE_ESP32 + ip_addr_.type = IPADDR_TYPE_V4; +#endif + } #if USE_ARDUINO IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); } #endif From 84c00a58675a63f7ef587119494d49fb81dbe671 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 23 Oct 2023 11:26:23 -0700 Subject: [PATCH 0661/2607] fix canbus send config (#5585) Co-authored-by: Samuel Sieb --- esphome/components/canbus/__init__.py | 25 +++++++++++-------------- tests/test1.1.yaml | 16 ++++++++++++++++ tests/test1.yaml | 4 ++++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/esphome/components/canbus/__init__.py b/esphome/components/canbus/__init__.py index f49398858c..76e77021ad 100644 --- a/esphome/components/canbus/__init__.py +++ b/esphome/components/canbus/__init__.py @@ -17,11 +17,12 @@ CONF_ON_FRAME = "on_frame" def validate_id(config): - can_id = config[CONF_CAN_ID] - id_ext = config[CONF_USE_EXTENDED_ID] - if not id_ext: - if can_id > 0x7FF: - raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") + if CONF_CAN_ID in config: + can_id = config[CONF_CAN_ID] + id_ext = config[CONF_USE_EXTENDED_ID] + if not id_ext: + if can_id > 0x7FF: + raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") return config @@ -151,22 +152,18 @@ async def canbus_action_to_code(config, action_id, template_arg, args): if can_id := config.get(CONF_CAN_ID): can_id = await cg.templatable(can_id, args, cg.uint32) cg.add(var.set_can_id(can_id)) - use_extended_id = await cg.templatable( - config[CONF_USE_EXTENDED_ID], args, cg.uint32 - ) - cg.add(var.set_use_extended_id(use_extended_id)) + cg.add(var.set_use_extended_id(config[CONF_USE_EXTENDED_ID])) - remote_transmission_request = await cg.templatable( - config[CONF_REMOTE_TRANSMISSION_REQUEST], args, bool + cg.add( + var.set_remote_transmission_request(config[CONF_REMOTE_TRANSMISSION_REQUEST]) ) - cg.add(var.set_remote_transmission_request(remote_transmission_request)) data = config[CONF_DATA] - if isinstance(data, bytes): - data = [int(x) for x in data] if cg.is_template(data): templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) cg.add(var.set_data_template(templ)) else: + if isinstance(data, bytes): + data = [int(x) for x in data] cg.add(var.set_data_static(data)) return var diff --git a/tests/test1.1.yaml b/tests/test1.1.yaml index 3bad4e0492..f4ad89897b 100644 --- a/tests/test1.1.yaml +++ b/tests/test1.1.yaml @@ -203,3 +203,19 @@ light: from: 20 to: 25 - single_light_id: ${roomname}_lights + +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: GPIO04 + tx_pin: GPIO05 + can_id: 4 + bit_rate: 50kbps + +button: + - platform: template + name: Canbus Actions + on_press: + - canbus.send: "abc" + - canbus.send: [0, 1, 2] + - canbus.send: !lambda return {0, 1, 2}; diff --git a/tests/test1.yaml b/tests/test1.yaml index acd119d8a5..f40dc35934 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3214,6 +3214,10 @@ text_sensor: canbus_id: mcp2515_can can_id: 23 data: [0x10, 0x20, 0x30] + - canbus.send: + canbus_id: mcp2515_can + can_id: 23 + data: !lambda return {0x10, 0x20, 0x30}; - canbus.send: canbus_id: esp32_internal_can can_id: 23 From b898f75631d9d2ec4cc2fa7a46c5ebc6a9601b69 Mon Sep 17 00:00:00 2001 From: dentra Date: Mon, 23 Oct 2023 21:29:32 +0300 Subject: [PATCH 0662/2607] Allow set climate preset to NONE (#5588) --- esphome/components/climate/climate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 1680601279..ea24cab954 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -213,6 +213,8 @@ ClimateCall &ClimateCall::set_preset(const std::string &preset) { this->set_preset(CLIMATE_PRESET_SLEEP); } else if (str_equals_case_insensitive(preset, "ACTIVITY")) { this->set_preset(CLIMATE_PRESET_ACTIVITY); + } else if (str_equals_case_insensitive(preset, "NONE")) { + this->set_preset(CLIMATE_PRESET_NONE); } else { if (this->parent_->get_traits().supports_custom_preset(preset)) { this->custom_preset_ = preset; From eead33b6f2df61d77258aaac4a168b9a652081ee Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Mon, 23 Oct 2023 16:02:29 -0300 Subject: [PATCH 0663/2607] update storage version from mdns (#5584) --- esphome/zeroconf.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/esphome/zeroconf.py b/esphome/zeroconf.py index 924d7253df..14dd740a96 100644 --- a/esphome/zeroconf.py +++ b/esphome/zeroconf.py @@ -17,6 +17,8 @@ from zeroconf import ( current_time_millis, ) +from esphome.storage_json import StorageJSON, ext_storage_path + _CLASS_IN = 1 _FLAGS_QR_QUERY = 0x0000 # query _TYPE_A = 1 @@ -131,6 +133,7 @@ TXT_RECORD_PROJECT_NAME = b"project_name" TXT_RECORD_PROJECT_VERSION = b"project_version" TXT_RECORD_NETWORK = b"network" TXT_RECORD_FRIENDLY_NAME = b"friendly_name" +TXT_RECORD_VERSION = b"version" @dataclass @@ -186,6 +189,10 @@ class DashboardImportDiscovery: ] if any(key not in info.properties for key in required_keys): # Not a dashboard import device + version = info.properties.get(TXT_RECORD_VERSION) + if version is not None: + version = version.decode() + self.update_device_mdns(node_name, version) return import_url = info.properties[TXT_RECORD_PACKAGE_IMPORT_URL].decode() @@ -208,6 +215,22 @@ class DashboardImportDiscovery: def cancel(self) -> None: self.service_browser.cancel() + def update_device_mdns(self, node_name: str, version: str): + storage_path = ext_storage_path(node_name + ".yaml") + storage_json = StorageJSON.load(storage_path) + + if storage_json is not None: + storage_version = storage_json.esphome_version + if version != storage_version: + storage_json.esphome_version = version + storage_json.save(storage_path) + _LOGGER.info( + "Updated %s with mdns version %s (was %s)", + node_name, + version, + storage_version, + ) + class EsphomeZeroconf(Zeroconf): def resolve_host(self, host: str, timeout=3.0): From 7e27e98bff376a237b8911e87d0d44d5cd6648be Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:02:57 +0200 Subject: [PATCH 0664/2607] set Nextion protocol reparse mode (#5484) --- esphome/components/nextion/nextion.h | 7 +++++++ .../components/nextion/nextion_commands.cpp | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 28663138d7..7518d7f4cb 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -623,6 +623,13 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @param True or false. Sleep=true to enter sleep mode or sleep=false to exit sleep mode. */ void sleep(bool sleep); + /** + * Sets Nextion Protocol Reparse mode between active or passive + * @param True or false. + * active_mode=true to enter active protocol reparse mode + * active_mode=false to enter passive protocol reparse mode. + */ + void set_protocol_reparse_mode(bool active_mode); // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index 806e03850f..c4caf29287 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -32,6 +32,25 @@ void Nextion::sleep(bool sleep) { } // End sleep safe commands +// Protocol reparse mode +void Nextion::set_protocol_reparse_mode(bool active_mode) { + const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF}; + if (active_mode) { // Sets active protocol reparse mode + this->write_str( + "recmod=1"); // send_command_ cannot be used as Nextion might not be setup if incorrect reparse mode + this->write_array(to_send, sizeof(to_send)); + } else { // Sets passive protocol reparse mode + this->write_str("DRAKJHSUYDGBNCJHGJKSHBDN"); // To exit active reparse mode this sequence must be sent + this->write_array(to_send, sizeof(to_send)); + this->write_str("recmod=0"); // Sending recmode=0 twice is recommended + this->write_array(to_send, sizeof(to_send)); + this->write_str("recmod=0"); + this->write_array(to_send, sizeof(to_send)); + } + this->write_str("connect"); + this->write_array(to_send, sizeof(to_send)); +} + // Set Colors void Nextion::set_component_background_color(const char *component, uint32_t color) { this->add_no_result_to_queue_with_printf_("set_component_background_color", "%s.bco=%d", component, color); From e7d51f9c16a08d1d814e4f5fe52c9ba93dc53521 Mon Sep 17 00:00:00 2001 From: Simone Rossetto Date: Mon, 23 Oct 2023 21:05:57 +0200 Subject: [PATCH 0665/2607] Add address text sensor to WireGuard (#5576) --- esphome/components/wireguard/text_sensor.py | 28 +++++++++++++++++++++ esphome/components/wireguard/wireguard.cpp | 10 ++++++++ esphome/components/wireguard/wireguard.h | 12 +++++++++ tests/test10.yaml | 5 ++++ 4 files changed, 55 insertions(+) create mode 100644 esphome/components/wireguard/text_sensor.py diff --git a/esphome/components/wireguard/text_sensor.py b/esphome/components/wireguard/text_sensor.py new file mode 100644 index 0000000000..3b05f6173e --- /dev/null +++ b/esphome/components/wireguard/text_sensor.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import ( + CONF_ADDRESS, + ENTITY_CATEGORY_DIAGNOSTIC, +) + +from . import Wireguard + +CONF_WIREGUARD_ID = "wireguard_id" + +DEPENDENCIES = ["wireguard"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_WIREGUARD_ID): cv.use_id(Wireguard), + cv.Optional(CONF_ADDRESS): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_WIREGUARD_ID]) + + if address_config := config.get(CONF_ADDRESS): + sens = await text_sensor.new_text_sensor(address_config) + cg.add(parent.set_address_sensor(sens)) diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp index 1b361cc1cc..3cd4409dda 100644 --- a/esphome/components/wireguard/wireguard.cpp +++ b/esphome/components/wireguard/wireguard.cpp @@ -54,6 +54,12 @@ void Wireguard::setup() { this->wg_peer_offline_time_ = millis(); this->srctime_->add_on_time_sync_callback(std::bind(&Wireguard::start_connection_, this)); this->defer(std::bind(&Wireguard::start_connection_, this)); // defer to avoid blocking setup + +#ifdef USE_TEXT_SENSOR + if (this->address_sensor_ != nullptr) { + this->address_sensor_->publish_state(this->address_); + } +#endif } else { ESP_LOGE(TAG, "cannot initialize WireGuard, error code %d", this->wg_initialized_); this->mark_failed(); @@ -186,6 +192,10 @@ void Wireguard::set_status_sensor(binary_sensor::BinarySensor *sensor) { this->s void Wireguard::set_handshake_sensor(sensor::Sensor *sensor) { this->handshake_sensor_ = sensor; } #endif +#ifdef USE_TEXT_SENSOR +void Wireguard::set_address_sensor(text_sensor::TextSensor *sensor) { this->address_sensor_ = sensor; } +#endif + void Wireguard::disable_auto_proceed() { this->proceed_allowed_ = false; } void Wireguard::start_connection_() { diff --git a/esphome/components/wireguard/wireguard.h b/esphome/components/wireguard/wireguard.h index cfc5fa1a27..c47d9e6603 100644 --- a/esphome/components/wireguard/wireguard.h +++ b/esphome/components/wireguard/wireguard.h @@ -17,6 +17,10 @@ #include "esphome/components/sensor/sensor.h" #endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif + #include namespace esphome { @@ -55,6 +59,10 @@ class Wireguard : public PollingComponent { void set_handshake_sensor(sensor::Sensor *sensor); #endif +#ifdef USE_TEXT_SENSOR + void set_address_sensor(text_sensor::TextSensor *sensor); +#endif + /// Block the setup step until peer is connected. void disable_auto_proceed(); @@ -85,6 +93,10 @@ class Wireguard : public PollingComponent { sensor::Sensor *handshake_sensor_ = nullptr; #endif +#ifdef USE_TEXT_SENSOR + text_sensor::TextSensor *address_sensor_ = nullptr; +#endif + /// Set to false to block the setup step until peer is connected. bool proceed_allowed_ = true; diff --git a/tests/test10.yaml b/tests/test10.yaml index fc74d95d84..dda7601048 100644 --- a/tests/test10.yaml +++ b/tests/test10.yaml @@ -49,3 +49,8 @@ sensor: - platform: wireguard latest_handshake: name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' From 5347c9aafeb7c15f2f0a0dd664345563e5cdd902 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 23 Oct 2023 21:06:23 +0200 Subject: [PATCH 0666/2607] Add LibreTiny hardwares to PR Template (#5575) --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3221b8ac5c..3bf9c4e1f6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -19,6 +19,8 @@ - [ ] ESP32 IDF - [ ] ESP8266 - [ ] RP2040 +- [ ] BK72xx +- [ ] RTL87xx ## Example entry for `config.yaml`: horizontal default position + break; + } + + ESP_LOGD(TAG, "default_horizontal_direction_: %02X", this->default_horizontal_direction_); + + // Fan Speed & Vertical Vane + // Map of Climate fan mode to this device expected value + // For 3Level: Low = 1, Medium = 2, High = 3 + // For 4Level: Low = 1, Middle = 2, Medium = 3, High = 4 + // For 5Level: Low = 1, Middle = 2, Medium = 3, High = 4 + // For 4Level + Quiet: Low = 1, Middle = 2, Medium = 3, High = 4, Quiet = 5 + + switch (this->fan_mode.value()) { + case climate::CLIMATE_FAN_LOW: + remote_state[9] = 1; + break; + case climate::CLIMATE_FAN_MEDIUM: + if (this->fan_mode_ == MITSUBISHI_FAN_3L) { + remote_state[9] = 2; + } else { + remote_state[9] = 3; + } + break; + case climate::CLIMATE_FAN_HIGH: + if (this->fan_mode_ == MITSUBISHI_FAN_3L) { + remote_state[9] = 3; + } else { + remote_state[9] = 4; + } + break; + case climate::CLIMATE_FAN_MIDDLE: + remote_state[9] = 2; + break; + case climate::CLIMATE_FAN_QUIET: + remote_state[9] = 5; + break; + default: + remote_state[9] = MITSUBISHI_FAN_AUTO; + break; + } + + ESP_LOGD(TAG, "fan: %02x state: %02x", this->fan_mode.value(), remote_state[9]); + + // Vertical Vane + switch (this->swing_mode) { + case climate::CLIMATE_SWING_VERTICAL: + case climate::CLIMATE_SWING_BOTH: + remote_state[9] = remote_state[9] | MITSUBISHI_VERTICAL_VANE_SWING | MITSUBISHI_OTHERWISE; // Vane Swing + break; + case climate::CLIMATE_SWING_OFF: + default: + remote_state[9] = remote_state[9] | this->default_vertical_direction_ | + MITSUBISHI_OTHERWISE; // Off--> vertical default position + break; + } + + ESP_LOGD(TAG, "default_vertical_direction_: %02X", this->default_vertical_direction_); + + // Special modes + switch (this->preset.value()) { + case climate::CLIMATE_PRESET_ECO: + remote_state[6] = MITSUBISHI_MODE_COOL | MITSUBISHI_OTHERWISE; + remote_state[8] = (remote_state[8] & ~7) | MITSUBISHI_MODE_A_COOL; + remote_state[14] = MITSUBISHI_ECONOCOOL; + break; + case climate::CLIMATE_PRESET_SLEEP: + remote_state[9] = MITSUBISHI_FAN_AUTO; + remote_state[14] = MITSUBISHI_NIGHTMODE; + break; + case climate::CLIMATE_PRESET_BOOST: + remote_state[6] |= MITSUBISHI_OTHERWISE; + remote_state[15] = MITSUBISHI_POWERFUL; + break; + case climate::CLIMATE_PRESET_NONE: + default: + break; + } // Checksum for (int i = 0; i < 17; i++) { remote_state[17] += remote_state[i]; } + ESP_LOGD(TAG, "sending: %02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X", + remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5], + remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11], + remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17]); + auto transmit = this->transmitter_->transmit(); auto *data = transmit.get_data(); @@ -81,5 +272,119 @@ void MitsubishiClimate::transmit_state() { transmit.perform(); } +bool MitsubishiClimate::parse_state_frame_(const uint8_t frame[]) { return false; } + +bool MitsubishiClimate::on_receive(remote_base::RemoteReceiveData data) { + uint8_t state_frame[18] = {}; + + if (!data.expect_item(MITSUBISHI_HEADER_MARK, MITSUBISHI_HEADER_SPACE)) { + ESP_LOGV(TAG, "Header fail"); + return false; + } + + for (uint8_t pos = 0; pos < 18; pos++) { + uint8_t byte = 0; + for (int8_t bit = 0; bit < 8; bit++) { + if (data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ONE_SPACE)) { + byte |= 1 << bit; + } else if (!data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ZERO_SPACE)) { + ESP_LOGV(TAG, "Byte %d bit %d fail", pos, bit); + return false; + } + } + state_frame[pos] = byte; + + // Check Header && Footer + if ((pos == 0 && byte != MITSUBISHI_BYTE00) || (pos == 1 && byte != MITSUBISHI_BYTE01) || + (pos == 2 && byte != MITSUBISHI_BYTE02) || (pos == 3 && byte != MITSUBISHI_BYTE03) || + (pos == 4 && byte != MITSUBISHI_BYTE04) || (pos == 13 && byte != MITSUBISHI_BYTE13) || + (pos == 16 && byte != MITSUBISHI_BYTE16)) { + ESP_LOGV(TAG, "Bytes 0,1,2,3,4,13 or 16 fail - invalid value"); + return false; + } + } + + // On/Off and Mode + if (state_frame[5] == MITSUBISHI_OFF) { + this->mode = climate::CLIMATE_MODE_OFF; + } else { + switch (state_frame[6]) { + case MITSUBISHI_MODE_HEAT: + this->mode = climate::CLIMATE_MODE_HEAT; + break; + case MITSUBISHI_MODE_DRY: + this->mode = climate::CLIMATE_MODE_DRY; + break; + case MITSUBISHI_MODE_COOL: + this->mode = climate::CLIMATE_MODE_COOL; + break; + case MITSUBISHI_MODE_FAN_ONLY: + this->mode = climate::CLIMATE_MODE_FAN_ONLY; + break; + case MITSUBISHI_MODE_AUTO: + this->mode = climate::CLIMATE_MODE_HEAT_COOL; + break; + } + } + + // Temp + this->target_temperature = state_frame[7] + MITSUBISHI_TEMP_MIN; + + // Fan + uint8_t fan = state_frame[9] & 0x07; //(Bit 0,1,2 = Speed) + // Map of Climate fan mode to this device expected value + // For 3Level: Low = 1, Medium = 2, High = 3 + // For 4Level: Low = 1, Middle = 2, Medium = 3, High = 4 + // For 5Level: Low = 1, Middle = 2, Medium = 3, High = 4 + // For 4Level + Quiet: Low = 1, Middle = 2, Medium = 3, High = 4, Quiet = 5 + climate::ClimateFanMode modes_mapping[8] = { + climate::CLIMATE_FAN_AUTO, + climate::CLIMATE_FAN_LOW, + this->fan_mode_ == MITSUBISHI_FAN_3L ? climate::CLIMATE_FAN_MEDIUM : climate::CLIMATE_FAN_MIDDLE, + this->fan_mode_ == MITSUBISHI_FAN_3L ? climate::CLIMATE_FAN_HIGH : climate::CLIMATE_FAN_MEDIUM, + climate::CLIMATE_FAN_HIGH, + climate::CLIMATE_FAN_QUIET, + climate::CLIMATE_FAN_AUTO, + climate::CLIMATE_FAN_AUTO}; + this->fan_mode = modes_mapping[fan]; + + // Wide Vane + uint8_t wide_vane = state_frame[8] & 0xF0; // Bits 4,5,6,7 + switch (wide_vane) { + case MITSUBISHI_WIDE_VANE_SWING: + this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; + break; + default: + this->swing_mode = climate::CLIMATE_SWING_OFF; + break; + } + + // Vertical Vane + uint8_t vertical_vane = state_frame[9] & 0x38; // Bits 3,4,5 + switch (vertical_vane) { + case MITSUBISHI_VERTICAL_VANE_SWING: + if (this->swing_mode == climate::CLIMATE_SWING_HORIZONTAL) { + this->swing_mode = climate::CLIMATE_SWING_BOTH; + } else { + this->swing_mode = climate::CLIMATE_SWING_VERTICAL; + } + break; + } + + switch (state_frame[14]) { + case MITSUBISHI_ECONOCOOL: + this->preset = climate::CLIMATE_PRESET_ECO; + break; + case MITSUBISHI_NIGHTMODE: + this->preset = climate::CLIMATE_PRESET_SLEEP; + break; + } + + ESP_LOGV(TAG, "Receiving: %s", format_hex_pretty(state_frame, 18).c_str()); + + this->publish_state(); + return true; +} + } // namespace mitsubishi } // namespace esphome diff --git a/esphome/components/mitsubishi/mitsubishi.h b/esphome/components/mitsubishi/mitsubishi.h index 9a88040d3f..cfe12428da 100644 --- a/esphome/components/mitsubishi/mitsubishi.h +++ b/esphome/components/mitsubishi/mitsubishi.h @@ -11,13 +11,72 @@ namespace mitsubishi { const uint8_t MITSUBISHI_TEMP_MIN = 16; // Celsius const uint8_t MITSUBISHI_TEMP_MAX = 31; // Celsius +// Fan mode +enum SetFanMode { + MITSUBISHI_FAN_3L = 0, // 3 levels + auto + MITSUBISHI_FAN_4L, // 4 levels + auto + MITSUBISHI_FAN_Q4L, // Quiet + 4 levels + auto + // MITSUBISHI_FAN_5L, // 5 levels + auto +}; + +// Enum to represent horizontal directios +enum HorizontalDirection { + HORIZONTAL_DIRECTION_LEFT = 0x10, + HORIZONTAL_DIRECTION_MIDDLE_LEFT = 0x20, + HORIZONTAL_DIRECTION_MIDDLE = 0x30, + HORIZONTAL_DIRECTION_MIDDLE_RIGHT = 0x40, + HORIZONTAL_DIRECTION_RIGHT = 0x50, + HORIZONTAL_DIRECTION_SPLIT = 0x80, +}; + +// Enum to represent vertical directions +enum VerticalDirection { + VERTICAL_DIRECTION_AUTO = 0x00, + VERTICAL_DIRECTION_UP = 0x08, + VERTICAL_DIRECTION_MIDDLE_UP = 0x10, + VERTICAL_DIRECTION_MIDDLE = 0x18, + VERTICAL_DIRECTION_MIDDLE_DOWN = 0x20, + VERTICAL_DIRECTION_DOWN = 0x28, +}; + class MitsubishiClimate : public climate_ir::ClimateIR { public: - MitsubishiClimate() : climate_ir::ClimateIR(MITSUBISHI_TEMP_MIN, MITSUBISHI_TEMP_MAX) {} + MitsubishiClimate() + : climate_ir::ClimateIR(MITSUBISHI_TEMP_MIN, MITSUBISHI_TEMP_MAX, 1.0f, true, true, + {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MIDDLE, + climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH, climate::CLIMATE_FAN_QUIET}, + {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL}, + {climate::CLIMATE_PRESET_NONE, climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_BOOST, + climate::CLIMATE_PRESET_SLEEP}) {} + + void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; } + void set_supports_dry(bool supports_dry) { this->supports_dry_ = supports_dry; } + void set_supports_fan_only(bool supports_fan_only) { this->supports_fan_only_ = supports_fan_only; } + void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; } + + void set_fan_mode(SetFanMode fan_mode) { this->fan_mode_ = fan_mode; } + + void set_horizontal_default(HorizontalDirection horizontal_direction) { + this->default_horizontal_direction_ = horizontal_direction; + } + void set_vertical_default(VerticalDirection vertical_direction) { + this->default_vertical_direction_ = vertical_direction; + } protected: - /// Transmit via IR the state of this climate controller. + // Transmit via IR the state of this climate controller. void transmit_state() override; + // Handle received IR Buffer + bool on_receive(remote_base::RemoteReceiveData data) override; + bool parse_state_frame_(const uint8_t frame[]); + + SetFanMode fan_mode_; + + HorizontalDirection default_horizontal_direction_; + VerticalDirection default_vertical_direction_; + + climate::ClimateTraits traits() override; }; } // namespace mitsubishi diff --git a/tests/test1.yaml b/tests/test1.yaml index 505e839f5b..c8ae9691c2 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2652,6 +2652,10 @@ climate: name: Yashima Climate - platform: mitsubishi name: Mitsubishi + supports_dry: "true" + supports_fan_only: "true" + horizontal_default: "left" + vertical_default: "down" - platform: whirlpool name: Whirlpool Climate - platform: climate_ir_lg From 1dd14254b3eddcf84903d36508cbd1649223a027 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 12 Mar 2024 09:55:23 +1100 Subject: [PATCH 1354/2607] Drivers for RGB 16 bit parallel displays (#5872) Co-authored-by: clydebarrow <366188+clydebarrow@users.noreply.github.com> --- CODEOWNERS | 2 + esphome/components/rpi_dpi_rgb/__init__.py | 1 + esphome/components/rpi_dpi_rgb/display.py | 197 ++++++++++ .../components/rpi_dpi_rgb/rpi_dpi_rgb.cpp | 116 ++++++ esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h | 92 +++++ esphome/components/st7701s/__init__.py | 1 + esphome/components/st7701s/display.py | 253 ++++++++++++ esphome/components/st7701s/init_sequences.py | 363 ++++++++++++++++++ esphome/components/st7701s/st7701s.cpp | 180 +++++++++ esphome/components/st7701s/st7701s.h | 115 ++++++ .../rpi_dpi_rgb/test.esp32-s3-idf.yaml | 40 ++ .../components/st7701s/test.esp32-s3-idf.yaml | 60 +++ 12 files changed, 1420 insertions(+) create mode 100644 esphome/components/rpi_dpi_rgb/__init__.py create mode 100644 esphome/components/rpi_dpi_rgb/display.py create mode 100644 esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp create mode 100644 esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h create mode 100644 esphome/components/st7701s/__init__.py create mode 100644 esphome/components/st7701s/display.py create mode 100644 esphome/components/st7701s/init_sequences.py create mode 100644 esphome/components/st7701s/st7701s.cpp create mode 100644 esphome/components/st7701s/st7701s.h create mode 100644 tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml create mode 100644 tests/components/st7701s/test.esp32-s3-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 3b2d1eeeed..320c2d5e7e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -282,6 +282,7 @@ esphome/components/rgbct/* @jesserockz esphome/components/rp2040/* @jesserockz esphome/components/rp2040_pio_led_strip/* @Papa-DMan esphome/components/rp2040_pwm/* @jesserockz +esphome/components/rpi_dpi_rgb/* @clydebarrow esphome/components/rtl87xx/* @kuba2k2 esphome/components/rtttl/* @glmnet esphome/components/safe_mode/* @jsuanet @paulmonigatti @@ -333,6 +334,7 @@ esphome/components/ssd1351_spi/* @kbx81 esphome/components/st7567_base/* @latonita esphome/components/st7567_i2c/* @latonita esphome/components/st7567_spi/* @latonita +esphome/components/st7701s/* @clydebarrow esphome/components/st7735/* @SenexCrenshaw esphome/components/st7789v/* @kbx81 esphome/components/st7920/* @marsjan155 diff --git a/esphome/components/rpi_dpi_rgb/__init__.py b/esphome/components/rpi_dpi_rgb/__init__.py new file mode 100644 index 0000000000..c58ce8a01e --- /dev/null +++ b/esphome/components/rpi_dpi_rgb/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@clydebarrow"] diff --git a/esphome/components/rpi_dpi_rgb/display.py b/esphome/components/rpi_dpi_rgb/display.py new file mode 100644 index 0000000000..0cde16e0fb --- /dev/null +++ b/esphome/components/rpi_dpi_rgb/display.py @@ -0,0 +1,197 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import display +from esphome.const import ( + CONF_RESET_PIN, + CONF_DATA_PINS, + CONF_ID, + CONF_IGNORE_STRAPPING_WARNING, + CONF_DIMENSIONS, + CONF_WIDTH, + CONF_HEIGHT, + CONF_LAMBDA, + CONF_COLOR_ORDER, + CONF_RED, + CONF_GREEN, + CONF_BLUE, + CONF_NUMBER, + CONF_OFFSET_HEIGHT, + CONF_OFFSET_WIDTH, + CONF_INVERT_COLORS, +) +from esphome.components.esp32 import ( + only_on_variant, + const, +) + +DEPENDENCIES = ["esp32"] + +CONF_DE_PIN = "de_pin" +CONF_PCLK_PIN = "pclk_pin" +CONF_HSYNC_PIN = "hsync_pin" +CONF_VSYNC_PIN = "vsync_pin" + +CONF_HSYNC_FRONT_PORCH = "hsync_front_porch" +CONF_HSYNC_PULSE_WIDTH = "hsync_pulse_width" +CONF_HSYNC_BACK_PORCH = "hsync_back_porch" +CONF_VSYNC_FRONT_PORCH = "vsync_front_porch" +CONF_VSYNC_PULSE_WIDTH = "vsync_pulse_width" +CONF_VSYNC_BACK_PORCH = "vsync_back_porch" +CONF_PCLK_FREQUENCY = "pclk_frequency" +CONF_PCLK_INVERTED = "pclk_inverted" + +rpi_dpi_rgb_ns = cg.esphome_ns.namespace("rpi_dpi_rgb") +RPI_DPI_RGB = rpi_dpi_rgb_ns.class_("RpiDpiRgb", display.Display, cg.Component) +ColorOrder = display.display_ns.enum("ColorMode") + +COLOR_ORDERS = { + "RGB": ColorOrder.COLOR_ORDER_RGB, + "BGR": ColorOrder.COLOR_ORDER_BGR, +} +DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + + +def data_pin_validate(value): + """ + It is safe to use strapping pins as RGB output data bits, as they are outputs only, + and not initialised until after boot. + """ + if not isinstance(value, dict): + try: + return DATA_PIN_SCHEMA( + {CONF_NUMBER: value, CONF_IGNORE_STRAPPING_WARNING: True} + ) + except cv.Invalid: + pass + return DATA_PIN_SCHEMA(value) + + +def data_pin_set(length): + return cv.All( + [data_pin_validate], + cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"), + ) + + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(RPI_DPI_RGB), + cv.Required(CONF_DIMENSIONS): cv.Any( + cv.dimensions, + cv.Schema( + { + cv.Required(CONF_WIDTH): cv.int_, + cv.Required(CONF_HEIGHT): cv.int_, + cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, + cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, + } + ), + ), + cv.Optional(CONF_PCLK_FREQUENCY, default="16MHz"): cv.All( + cv.frequency, cv.Range(min=4e6, max=30e6) + ), + cv.Optional(CONF_PCLK_INVERTED, default=True): cv.boolean, + cv.Required(CONF_DATA_PINS): cv.Any( + data_pin_set(16), + cv.Schema( + { + cv.Required(CONF_RED): data_pin_set(5), + cv.Required(CONF_GREEN): data_pin_set(6), + cv.Required(CONF_BLUE): data_pin_set(5), + } + ), + ), + cv.Optional(CONF_COLOR_ORDER): cv.one_of( + *COLOR_ORDERS.keys(), upper=True + ), + cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, + cv.Required(CONF_DE_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_PCLK_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_HSYNC_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_VSYNC_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_HSYNC_PULSE_WIDTH, default=10): cv.int_, + cv.Optional(CONF_HSYNC_BACK_PORCH, default=10): cv.int_, + cv.Optional(CONF_HSYNC_FRONT_PORCH, default=20): cv.int_, + cv.Optional(CONF_VSYNC_PULSE_WIDTH, default=10): cv.int_, + cv.Optional(CONF_VSYNC_BACK_PORCH, default=10): cv.int_, + cv.Optional(CONF_VSYNC_FRONT_PORCH, default=10): cv.int_, + } + ) + ), + only_on_variant(supported=[const.VARIANT_ESP32S3]), + cv.only_with_esp_idf, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await display.register_display(var, config) + + cg.add(var.set_color_mode(COLOR_ORDERS[config[CONF_COLOR_ORDER]])) + cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) + cg.add(var.set_hsync_pulse_width(config[CONF_HSYNC_PULSE_WIDTH])) + cg.add(var.set_hsync_back_porch(config[CONF_HSYNC_BACK_PORCH])) + cg.add(var.set_hsync_front_porch(config[CONF_HSYNC_FRONT_PORCH])) + cg.add(var.set_vsync_pulse_width(config[CONF_VSYNC_PULSE_WIDTH])) + cg.add(var.set_vsync_back_porch(config[CONF_VSYNC_BACK_PORCH])) + cg.add(var.set_vsync_front_porch(config[CONF_VSYNC_FRONT_PORCH])) + cg.add(var.set_pclk_inverted(config[CONF_PCLK_INVERTED])) + cg.add(var.set_pclk_frequency(config[CONF_PCLK_FREQUENCY])) + index = 0 + dpins = [] + if CONF_RED in config[CONF_DATA_PINS]: + red_pins = config[CONF_DATA_PINS][CONF_RED] + green_pins = config[CONF_DATA_PINS][CONF_GREEN] + blue_pins = config[CONF_DATA_PINS][CONF_BLUE] + if config[CONF_COLOR_ORDER] == "BGR": + dpins.extend(red_pins) + dpins.extend(green_pins) + dpins.extend(blue_pins) + else: + dpins.extend(blue_pins) + dpins.extend(green_pins) + dpins.extend(red_pins) + # swap bytes to match big-endian format + dpins = dpins[8:16] + dpins[0:8] + else: + dpins = config[CONF_DATA_PINS] + for pin in dpins: + data_pin = await cg.gpio_pin_expression(pin) + cg.add(var.add_data_pin(data_pin, index)) + index += 1 + + if reset_pin := config.get(CONF_RESET_PIN): + reset = await cg.gpio_pin_expression(reset_pin) + cg.add(var.set_reset_pin(reset)) + + if CONF_DIMENSIONS in config: + dimensions = config[CONF_DIMENSIONS] + if isinstance(dimensions, dict): + cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) + cg.add( + var.set_offsets( + dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] + ) + ) + else: + (width, height) = dimensions + cg.add(var.set_dimensions(width, height)) + + if lamb := config.get(CONF_LAMBDA): + lambda_ = await cg.process_lambda( + lamb, [(display.DisplayRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) + + pin = await cg.gpio_pin_expression(config[CONF_DE_PIN]) + cg.add(var.set_de_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_PCLK_PIN]) + cg.add(var.set_pclk_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_HSYNC_PIN]) + cg.add(var.set_hsync_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_VSYNC_PIN]) + cg.add(var.set_vsync_pin(pin)) diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp new file mode 100644 index 0000000000..2ffdb3272a --- /dev/null +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp @@ -0,0 +1,116 @@ +#ifdef USE_ESP32_VARIANT_ESP32S3 +#include "rpi_dpi_rgb.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace rpi_dpi_rgb { + +void RpiDpiRgb::setup() { + esph_log_config(TAG, "Setting up RPI_DPI_RGB"); + esp_lcd_rgb_panel_config_t config{}; + config.flags.fb_in_psram = 1; + config.timings.h_res = this->width_; + config.timings.v_res = this->height_; + config.timings.hsync_pulse_width = this->hsync_pulse_width_; + config.timings.hsync_back_porch = this->hsync_back_porch_; + config.timings.hsync_front_porch = this->hsync_front_porch_; + config.timings.vsync_pulse_width = this->vsync_pulse_width_; + config.timings.vsync_back_porch = this->vsync_back_porch_; + config.timings.vsync_front_porch = this->vsync_front_porch_; + config.timings.flags.pclk_active_neg = this->pclk_inverted_; + config.timings.pclk_hz = this->pclk_frequency_; + config.clk_src = LCD_CLK_SRC_PLL160M; + config.sram_trans_align = 64; + config.psram_trans_align = 64; + size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); + for (size_t i = 0; i != data_pin_count; i++) { + config.data_gpio_nums[i] = this->data_pins_[i]->get_pin(); + } + config.data_width = data_pin_count; + config.disp_gpio_num = -1; + config.hsync_gpio_num = this->hsync_pin_->get_pin(); + config.vsync_gpio_num = this->vsync_pin_->get_pin(); + config.de_gpio_num = this->de_pin_->get_pin(); + config.pclk_gpio_num = this->pclk_pin_->get_pin(); + esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_); + if (err != ESP_OK) { + esph_log_e(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err)); + } + ESP_ERROR_CHECK(esp_lcd_panel_reset(this->handle_)); + ESP_ERROR_CHECK(esp_lcd_panel_init(this->handle_)); + esph_log_config(TAG, "RPI_DPI_RGB setup complete"); +} + +void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { + if (w <= 0 || h <= 0) + return; + // if color mapping is required, pass the buck. + // note that endianness is not considered here - it is assumed to match! + if (bitness != display::COLOR_BITNESS_565) { + return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, + x_pad); + } + x_start += this->offset_x_; + y_start += this->offset_y_; + esp_err_t err; + // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. + if (x_offset == 0 && x_pad == 0 && y_offset == 0) { + // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother + err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y_start, x_start + w, y_start + h, ptr); + } else { + // draw line by line + auto stride = x_offset + w + x_pad; + for (int y = 0; y != h; y++) { + err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y + y_start, x_start + w, y + y_start + 1, + ptr + ((y + y_offset) * stride + x_offset) * 2); + if (err != ESP_OK) + break; + } + } + if (err != ESP_OK) + esph_log_e(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err)); +} + +void RpiDpiRgb::draw_pixel_at(int x, int y, Color color) { + if (!this->get_clipping().inside(x, y)) + return; // NOLINT + + switch (this->rotation_) { + case display::DISPLAY_ROTATION_0_DEGREES: + break; + case display::DISPLAY_ROTATION_90_DEGREES: + std::swap(x, y); + x = this->width_ - x - 1; + break; + case display::DISPLAY_ROTATION_180_DEGREES: + x = this->width_ - x - 1; + y = this->height_ - y - 1; + break; + case display::DISPLAY_ROTATION_270_DEGREES: + std::swap(x, y); + y = this->height_ - y - 1; + break; + } + auto pixel = convert_big_endian(display::ColorUtil::color_to_565(color)); + + this->draw_pixels_at(x, y, 1, 1, (const uint8_t *) &pixel, display::COLOR_ORDER_RGB, display::COLOR_BITNESS_565, true, + 0, 0, 0); + App.feed_wdt(); +} + +void RpiDpiRgb::dump_config() { + ESP_LOGCONFIG("", "RPI_DPI_RGB LCD"); + ESP_LOGCONFIG(TAG, " Height: %u", this->height_); + ESP_LOGCONFIG(TAG, " Width: %u", this->width_); + LOG_PIN(" DE Pin: ", this->de_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); + for (size_t i = 0; i != data_pin_count; i++) + ESP_LOGCONFIG(TAG, " Data pin %d: %s", i, (this->data_pins_[i])->dump_summary().c_str()); +} + +} // namespace rpi_dpi_rgb +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32S3 diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h new file mode 100644 index 0000000000..0319b46391 --- /dev/null +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h @@ -0,0 +1,92 @@ +// +// Created by Clyde Stubbs on 29/10/2023. +// +#pragma once + +// only applicable on ESP32-S3 +#ifdef USE_ESP32_VARIANT_ESP32S3 +#include "esphome/core/component.h" +#include "esphome/core/gpio.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/components/display/display.h" +#include "esp_lcd_panel_ops.h" + +#include "esp_lcd_panel_rgb.h" + +namespace esphome { +namespace rpi_dpi_rgb { + +constexpr static const char *const TAG = "rpi_dpi_rgb"; + +class RpiDpiRgb : public display::Display { + public: + void update() override { this->do_update_(); } + void setup() override; + void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; + void draw_pixel_at(int x, int y, Color color) override; + + display::ColorOrder get_color_mode() { return this->color_mode_; } + void set_color_mode(display::ColorOrder color_mode) { this->color_mode_ = color_mode; } + void set_invert_colors(bool invert_colors) { this->invert_colors_ = invert_colors; } + + void add_data_pin(InternalGPIOPin *data_pin, size_t index) { this->data_pins_[index] = data_pin; }; + void set_de_pin(InternalGPIOPin *de_pin) { this->de_pin_ = de_pin; } + void set_pclk_pin(InternalGPIOPin *pclk_pin) { this->pclk_pin_ = pclk_pin; } + void set_vsync_pin(InternalGPIOPin *vsync_pin) { this->vsync_pin_ = vsync_pin; } + void set_hsync_pin(InternalGPIOPin *hsync_pin) { this->hsync_pin_ = hsync_pin; } + void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } + void set_width(uint16_t width) { this->width_ = width; } + void set_dimensions(uint16_t width, uint16_t height) { + this->width_ = width; + this->height_ = height; + } + int get_width() override { return this->width_; } + int get_height() override { return this->height_; } + void set_hsync_back_porch(uint16_t hsync_back_porch) { this->hsync_back_porch_ = hsync_back_porch; } + void set_hsync_front_porch(uint16_t hsync_front_porch) { this->hsync_front_porch_ = hsync_front_porch; } + void set_hsync_pulse_width(uint16_t hsync_pulse_width) { this->hsync_pulse_width_ = hsync_pulse_width; } + void set_vsync_pulse_width(uint16_t vsync_pulse_width) { this->vsync_pulse_width_ = vsync_pulse_width; } + void set_vsync_back_porch(uint16_t vsync_back_porch) { this->vsync_back_porch_ = vsync_back_porch; } + void set_vsync_front_porch(uint16_t vsync_front_porch) { this->vsync_front_porch_ = vsync_front_porch; } + void set_pclk_frequency(uint32_t pclk_frequency) { this->pclk_frequency_ = pclk_frequency; } + void set_pclk_inverted(bool inverted) { this->pclk_inverted_ = inverted; } + void set_offsets(int16_t offset_x, int16_t offset_y) { + this->offset_x_ = offset_x; + this->offset_y_ = offset_y; + } + display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } + void dump_config() override; + + protected: + int get_width_internal() override { return this->width_; } + int get_height_internal() override { return this->height_; } + InternalGPIOPin *de_pin_{nullptr}; + InternalGPIOPin *pclk_pin_{nullptr}; + InternalGPIOPin *hsync_pin_{nullptr}; + InternalGPIOPin *vsync_pin_{nullptr}; + GPIOPin *reset_pin_{nullptr}; + InternalGPIOPin *data_pins_[16] = {}; + uint16_t hsync_front_porch_ = 8; + uint16_t hsync_pulse_width_ = 4; + uint16_t hsync_back_porch_ = 8; + uint16_t vsync_front_porch_ = 8; + uint16_t vsync_pulse_width_ = 4; + uint16_t vsync_back_porch_ = 8; + uint32_t pclk_frequency_ = 16 * 1000 * 1000; + bool pclk_inverted_{true}; + + bool invert_colors_{}; + display::ColorOrder color_mode_{display::COLOR_ORDER_BGR}; + size_t width_{}; + size_t height_{}; + int16_t offset_x_{0}; + int16_t offset_y_{0}; + + esp_lcd_panel_handle_t handle_{}; +}; + +} // namespace rpi_dpi_rgb +} // namespace esphome +#endif // USE_ESP32_VARIANT_ESP32S3 diff --git a/esphome/components/st7701s/__init__.py b/esphome/components/st7701s/__init__.py new file mode 100644 index 0000000000..c58ce8a01e --- /dev/null +++ b/esphome/components/st7701s/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@clydebarrow"] diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py new file mode 100644 index 0000000000..e33eeb89ae --- /dev/null +++ b/esphome/components/st7701s/display.py @@ -0,0 +1,253 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import ( + spi, + display, +) +from esphome.const import ( + CONF_DC_PIN, + CONF_RESET_PIN, + CONF_DATA_PINS, + CONF_ID, + CONF_DIMENSIONS, + CONF_WIDTH, + CONF_HEIGHT, + CONF_LAMBDA, + CONF_MIRROR_X, + CONF_MIRROR_Y, + CONF_COLOR_ORDER, + CONF_TRANSFORM, + CONF_OFFSET_HEIGHT, + CONF_OFFSET_WIDTH, + CONF_INVERT_COLORS, + CONF_RED, + CONF_GREEN, + CONF_BLUE, + CONF_NUMBER, + CONF_IGNORE_STRAPPING_WARNING, +) + +from esphome.components.esp32 import ( + only_on_variant, + const, +) +from esphome.components.rpi_dpi_rgb.display import ( + CONF_PCLK_FREQUENCY, + CONF_PCLK_INVERTED, +) +from .init_sequences import ( + ST7701S_INITS, + cmd, +) + +CONF_INIT_SEQUENCE = "init_sequence" +CONF_DE_PIN = "de_pin" +CONF_PCLK_PIN = "pclk_pin" +CONF_HSYNC_PIN = "hsync_pin" +CONF_VSYNC_PIN = "vsync_pin" + +CONF_HSYNC_PULSE_WIDTH = "hsync_pulse_width" +CONF_HSYNC_BACK_PORCH = "hsync_back_porch" +CONF_HSYNC_FRONT_PORCH = "hsync_front_porch" +CONF_VSYNC_PULSE_WIDTH = "vsync_pulse_width" +CONF_VSYNC_BACK_PORCH = "vsync_back_porch" +CONF_VSYNC_FRONT_PORCH = "vsync_front_porch" + +DEPENDENCIES = ["spi", "esp32"] + +st7701s_ns = cg.esphome_ns.namespace("st7701s") +ST7701S = st7701s_ns.class_("ST7701S", display.Display, cg.Component, spi.SPIDevice) +ColorOrder = display.display_ns.enum("ColorMode") + +COLOR_ORDERS = { + "RGB": ColorOrder.COLOR_ORDER_RGB, + "BGR": ColorOrder.COLOR_ORDER_BGR, +} +DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + + +def data_pin_validate(value): + """ + It is safe to use strapping pins as RGB output data bits, as they are outputs only, + and not initialised until after boot. + """ + if not isinstance(value, dict): + try: + return DATA_PIN_SCHEMA( + {CONF_NUMBER: value, CONF_IGNORE_STRAPPING_WARNING: True} + ) + except cv.Invalid: + pass + return DATA_PIN_SCHEMA(value) + + +def data_pin_set(length): + return cv.All( + [data_pin_validate], + cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"), + ) + + +def map_sequence(value): + """ + An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py, + or can be a literal array of data bytes. + The format is a repeated sequence of [CMD, LEN, ] where is LEN bytes. + """ + if not isinstance(value, list): + value = cv.int_(value) + value = cv.one_of(*ST7701S_INITS)(value) + return ST7701S_INITS[value] + # value = cv.ensure_list(cv.uint8_t)(value) + data_length = len(value) + if data_length == 0: + raise cv.Invalid("Empty sequence") + value = cmd(*value) + return value + + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ST7701S), + cv.Required(CONF_DIMENSIONS): cv.Any( + cv.dimensions, + cv.Schema( + { + cv.Required(CONF_WIDTH): cv.int_, + cv.Required(CONF_HEIGHT): cv.int_, + cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, + cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, + } + ), + ), + cv.Optional(CONF_TRANSFORM): cv.Schema( + { + cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, + cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, + } + ), + cv.Required(CONF_DATA_PINS): cv.Any( + data_pin_set(16), + cv.Schema( + { + cv.Required(CONF_RED): data_pin_set(5), + cv.Required(CONF_GREEN): data_pin_set(6), + cv.Required(CONF_BLUE): data_pin_set(5), + } + ), + ), + cv.Optional(CONF_INIT_SEQUENCE, default=1): cv.ensure_list( + map_sequence + ), + cv.Optional(CONF_COLOR_ORDER): cv.one_of( + *COLOR_ORDERS.keys(), upper=True + ), + cv.Optional(CONF_PCLK_FREQUENCY, default="16MHz"): cv.All( + cv.frequency, cv.Range(min=4e6, max=30e6) + ), + cv.Optional(CONF_PCLK_INVERTED, default=True): cv.boolean, + cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, + cv.Required(CONF_DE_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_PCLK_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_HSYNC_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_VSYNC_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_DC_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_HSYNC_PULSE_WIDTH, default=10): cv.int_, + cv.Optional(CONF_HSYNC_BACK_PORCH, default=10): cv.int_, + cv.Optional(CONF_HSYNC_FRONT_PORCH, default=20): cv.int_, + cv.Optional(CONF_VSYNC_PULSE_WIDTH, default=10): cv.int_, + cv.Optional(CONF_VSYNC_BACK_PORCH, default=10): cv.int_, + cv.Optional(CONF_VSYNC_FRONT_PORCH, default=10): cv.int_, + } + ).extend(spi.spi_device_schema(cs_pin_required=False, default_data_rate=1e6)) + ), + only_on_variant(supported=[const.VARIANT_ESP32S3]), + cv.only_with_esp_idf, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await display.register_display(var, config) + await spi.register_spi_device(var, config) + + sequence = [] + for seq in config[CONF_INIT_SEQUENCE]: + sequence.extend(seq) + cg.add(var.set_init_sequence(sequence)) + cg.add(var.set_color_mode(COLOR_ORDERS[config[CONF_COLOR_ORDER]])) + cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) + cg.add(var.set_hsync_pulse_width(config[CONF_HSYNC_PULSE_WIDTH])) + cg.add(var.set_hsync_back_porch(config[CONF_HSYNC_BACK_PORCH])) + cg.add(var.set_hsync_front_porch(config[CONF_HSYNC_FRONT_PORCH])) + cg.add(var.set_vsync_pulse_width(config[CONF_VSYNC_PULSE_WIDTH])) + cg.add(var.set_vsync_back_porch(config[CONF_VSYNC_BACK_PORCH])) + cg.add(var.set_vsync_front_porch(config[CONF_VSYNC_FRONT_PORCH])) + cg.add(var.set_pclk_inverted(config[CONF_PCLK_INVERTED])) + cg.add(var.set_pclk_frequency(config[CONF_PCLK_FREQUENCY])) + index = 0 + dpins = [] + if CONF_RED in config[CONF_DATA_PINS]: + red_pins = config[CONF_DATA_PINS][CONF_RED] + green_pins = config[CONF_DATA_PINS][CONF_GREEN] + blue_pins = config[CONF_DATA_PINS][CONF_BLUE] + if config[CONF_COLOR_ORDER] == "BGR": + dpins.extend(red_pins) + dpins.extend(green_pins) + dpins.extend(blue_pins) + else: + dpins.extend(blue_pins) + dpins.extend(green_pins) + dpins.extend(red_pins) + # swap bytes to match big-endian format + dpins = dpins[8:16] + dpins[0:8] + else: + dpins = config[CONF_DATA_PINS] + for pin in dpins: + data_pin = await cg.gpio_pin_expression(pin) + cg.add(var.add_data_pin(data_pin, index)) + index += 1 + + if dc_pin := config.get(CONF_DC_PIN): + dc = await cg.gpio_pin_expression(dc_pin) + cg.add(var.set_dc_pin(dc)) + + if reset_pin := config.get(CONF_RESET_PIN): + reset = await cg.gpio_pin_expression(reset_pin) + cg.add(var.set_reset_pin(reset)) + + if transform := config.get(CONF_TRANSFORM): + cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) + cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) + + if CONF_DIMENSIONS in config: + dimensions = config[CONF_DIMENSIONS] + if isinstance(dimensions, dict): + cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) + cg.add( + var.set_offsets( + dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] + ) + ) + else: + (width, height) = dimensions + cg.add(var.set_dimensions(width, height)) + + if lamb := config.get(CONF_LAMBDA): + lambda_ = await cg.process_lambda( + lamb, [(display.DisplayRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) + + pin = await cg.gpio_pin_expression(config[CONF_DE_PIN]) + cg.add(var.set_de_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_PCLK_PIN]) + cg.add(var.set_pclk_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_HSYNC_PIN]) + cg.add(var.set_hsync_pin(pin)) + pin = await cg.gpio_pin_expression(config[CONF_VSYNC_PIN]) + cg.add(var.set_vsync_pin(pin)) diff --git a/esphome/components/st7701s/init_sequences.py b/esphome/components/st7701s/init_sequences.py new file mode 100644 index 0000000000..4786731c78 --- /dev/null +++ b/esphome/components/st7701s/init_sequences.py @@ -0,0 +1,363 @@ +# These are initialisation sequences for ST7701S displays. The contents are somewhat arcane. + + +def cmd(c, *args): + """ + Create a command sequence + :param c: The command (8 bit) + :param args: zero or more arguments (8 bit values) + :return: a list with the command, the argument count and the arguments + """ + return [c, len(args)] + list(args) + + +ST7701S_1_INIT = ( + cmd(0x01) + + cmd(0xFF, 0x77, 0x01, 0x00, 0x00, 0x10) + + cmd(0xC0, 0x3B, 0x00) + + cmd(0xC1, 0x0D, 0x02) + + cmd(0xC2, 0x31, 0x05) + + cmd(0xCD, 0x08) + + cmd( + 0xB0, + 0x00, + 0x11, + 0x18, + 0x0E, + 0x11, + 0x06, + 0x07, + 0x08, + 0x07, + 0x22, + 0x04, + 0x12, + 0x0F, + 0xAA, + 0x31, + 0x18, + ) + + cmd( + 0xB1, + 0x00, + 0x11, + 0x19, + 0x0E, + 0x12, + 0x07, + 0x08, + 0x08, + 0x08, + 0x22, + 0x04, + 0x11, + 0x11, + 0xA9, + 0x32, + 0x18, + ) + + cmd(0xFF, 0x77, 0x01, 0x00, 0x00, 0x11) + + cmd(0xB0, 0x60) + + cmd(0xB1, 0x32) + + cmd(0xB2, 0x07) + + cmd(0xB3, 0x80) + + cmd(0xB5, 0x49) + + cmd(0xB7, 0x85) + + cmd(0xB8, 0x21) + + cmd(0xC1, 0x78) + + cmd(0xC2, 0x78) + + cmd(0xE0, 0x00, 0x1B, 0x02) + + cmd(0xE1, 0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44) + + cmd(0xE2, 0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00) + + cmd(0xE3, 0x00, 0x00, 0x11, 0x11) + + cmd(0xE4, 0x44, 0x44) + + cmd( + 0xE5, + 0x0A, + 0xE9, + 0xD8, + 0xA0, + 0x0C, + 0xEB, + 0xD8, + 0xA0, + 0x0E, + 0xED, + 0xD8, + 0xA0, + 0x10, + 0xEF, + 0xD8, + 0xA0, + ) + + cmd(0xE6, 0x00, 0x00, 0x11, 0x11) + + cmd(0xE7, 0x44, 0x44) + + cmd( + 0xE8, + 0x09, + 0xE8, + 0xD8, + 0xA0, + 0x0B, + 0xEA, + 0xD8, + 0xA0, + 0x0D, + 0xEC, + 0xD8, + 0xA0, + 0x0F, + 0xEE, + 0xD8, + 0xA0, + ) + + cmd(0xEB, 0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40) + + cmd(0xEC, 0x3C, 0x00) + + cmd( + 0xED, + 0xAB, + 0x89, + 0x76, + 0x54, + 0x02, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x20, + 0x45, + 0x67, + 0x98, + 0xBA, + ) + + cmd(0xFF, 0x77, 0x01, 0x00, 0x00, 0x13) + + cmd(0xE5, 0xE4) + + cmd(0x3A, 0x60) +) + +# This is untested +ST7701S_7_INIT = ( + cmd( + 0xFF, + 0x77, + 0x01, + 0x00, + 0x00, + 0x10, + ) + + cmd(0xC0, 0x3B, 0x00) + + cmd(0xC1, 0x0B, 0x02) + + cmd(0xC2, 0x07, 0x02) + + cmd(0xCC, 0x10) + + cmd(0xCD, 0x08) + + cmd( + 0xB0, + 0x00, + 0x11, + 0x16, + 0x0E, + 0x11, + 0x06, + 0x05, + 0x09, + 0x08, + 0x21, + 0x06, + 0x13, + 0x10, + 0x29, + 0x31, + 0x18, + ) + + cmd( + 0xB1, + 0x00, + 0x11, + 0x16, + 0x0E, + 0x11, + 0x07, + 0x05, + 0x09, + 0x09, + 0x21, + 0x05, + 0x13, + 0x11, + 0x2A, + 0x31, + 0x18, + ) + + cmd( + 0xFF, + 0x77, + 0x01, + 0x00, + 0x00, + 0x11, + ) + + cmd(0xB0, 0x6D) + + cmd(0xB1, 0x37) + + cmd(0xB2, 0x81) + + cmd(0xB3, 0x80) + + cmd(0xB5, 0x43) + + cmd(0xB7, 0x85) + + cmd(0xB8, 0x20) + + cmd(0xC1, 0x78) + + cmd(0xC2, 0x78) + + cmd(0xD0, 0x88) + + cmd( + 0xE0, + 3, + 0x00, + 0x00, + 0x02, + ) + + cmd( + 0xE1, + 0x03, + 0xA0, + 0x00, + 0x00, + 0x04, + 0xA0, + 0x00, + 0x00, + 0x00, + 0x20, + 0x20, + ) + + cmd( + 0xE2, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ) + + cmd( + 0xE3, + 0x00, + 0x00, + 0x11, + 0x00, + ) + + cmd(0xE4, 0x22, 0x00) + + cmd( + 0xE5, + 0x05, + 0xEC, + 0xA0, + 0xA0, + 0x07, + 0xEE, + 0xA0, + 0xA0, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ) + + cmd( + 0xE6, + 0x00, + 0x00, + 0x11, + 0x00, + ) + + cmd(0xE7, 0x22, 0x00) + + cmd( + 0xE8, + 0x06, + 0xED, + 0xA0, + 0xA0, + 0x08, + 0xEF, + 0xA0, + 0xA0, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ) + + cmd( + 0xEB, + 0x00, + 0x00, + 0x40, + 0x40, + 0x00, + 0x00, + 0x00, + ) + + cmd( + 0xED, + 0xFF, + 0xFF, + 0xFF, + 0xBA, + 0x0A, + 0xBF, + 0x45, + 0xFF, + 0xFF, + 0x54, + 0xFB, + 0xA0, + 0xAB, + 0xFF, + 0xFF, + 0xFF, + ) + + cmd( + 0xEF, + 0x10, + 0x0D, + 0x04, + 0x08, + 0x3F, + 0x1F, + ) + + cmd( + 0xFF, + 0x77, + 0x01, + 0x00, + 0x00, + 0x13, + ) + + cmd(0xEF, 0x08) + + cmd( + 0xFF, + 0x77, + 0x01, + 0x00, + 0x00, + 0x00, + ) + + cmd(0x3A, 0x66) +) + +ST7701S_INITS = { + 1: ST7701S_1_INIT, + # 7: ST7701S_7_INIT, +} diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp new file mode 100644 index 0000000000..43d8653709 --- /dev/null +++ b/esphome/components/st7701s/st7701s.cpp @@ -0,0 +1,180 @@ +#ifdef USE_ESP32_VARIANT_ESP32S3 +#include "st7701s.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace st7701s { + +void ST7701S::setup() { + esph_log_config(TAG, "Setting up ST7701S"); + this->spi_setup(); + esp_lcd_rgb_panel_config_t config{}; + config.flags.fb_in_psram = 1; + config.timings.h_res = this->width_; + config.timings.v_res = this->height_; + config.timings.hsync_pulse_width = this->hsync_pulse_width_; + config.timings.hsync_back_porch = this->hsync_back_porch_; + config.timings.hsync_front_porch = this->hsync_front_porch_; + config.timings.vsync_pulse_width = this->vsync_pulse_width_; + config.timings.vsync_back_porch = this->vsync_back_porch_; + config.timings.vsync_front_porch = this->vsync_front_porch_; + config.timings.flags.pclk_active_neg = this->pclk_inverted_; + config.timings.pclk_hz = this->pclk_frequency_; + config.clk_src = LCD_CLK_SRC_PLL160M; + config.sram_trans_align = 64; + config.psram_trans_align = 64; + size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); + for (size_t i = 0; i != data_pin_count; i++) { + config.data_gpio_nums[i] = this->data_pins_[i]->get_pin(); + } + config.data_width = data_pin_count; + config.disp_gpio_num = -1; + config.hsync_gpio_num = this->hsync_pin_->get_pin(); + config.vsync_gpio_num = this->vsync_pin_->get_pin(); + config.de_gpio_num = this->de_pin_->get_pin(); + config.pclk_gpio_num = this->pclk_pin_->get_pin(); + esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_); + if (err != ESP_OK) { + esph_log_e(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err)); + } + ESP_ERROR_CHECK(esp_lcd_panel_reset(this->handle_)); + ESP_ERROR_CHECK(esp_lcd_panel_init(this->handle_)); + this->write_init_sequence_(); + esph_log_config(TAG, "ST7701S setup complete"); +} + +void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { + if (w <= 0 || h <= 0) + return; + // if color mapping is required, pass the buck. + // note that endianness is not considered here - it is assumed to match! + if (bitness != display::COLOR_BITNESS_565) { + return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, + x_pad); + } + x_start += this->offset_x_; + y_start += this->offset_y_; + esp_err_t err; + // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. + if (x_offset == 0 && x_pad == 0 && y_offset == 0) { + // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother + err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y_start, x_start + w, y_start + h, ptr); + } else { + // draw line by line + auto stride = x_offset + w + x_pad; + for (int y = 0; y != h; y++) { + err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y + y_start, x_start + w, y + y_start + 1, + ptr + ((y + y_offset) * stride + x_offset) * 2); + if (err != ESP_OK) + break; + } + } + if (err != ESP_OK) + esph_log_e(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err)); +} + +void ST7701S::draw_pixel_at(int x, int y, Color color) { + if (!this->get_clipping().inside(x, y)) + return; // NOLINT + + switch (this->rotation_) { + case display::DISPLAY_ROTATION_0_DEGREES: + break; + case display::DISPLAY_ROTATION_90_DEGREES: + std::swap(x, y); + x = this->width_ - x - 1; + break; + case display::DISPLAY_ROTATION_180_DEGREES: + x = this->width_ - x - 1; + y = this->height_ - y - 1; + break; + case display::DISPLAY_ROTATION_270_DEGREES: + std::swap(x, y); + y = this->height_ - y - 1; + break; + } + auto pixel = convert_big_endian(display::ColorUtil::color_to_565(color)); + + this->draw_pixels_at(x, y, 1, 1, (const uint8_t *) &pixel, display::COLOR_ORDER_RGB, display::COLOR_BITNESS_565, true, + 0, 0, 0); + App.feed_wdt(); +} + +void ST7701S::write_command_(uint8_t value) { + this->enable(); + if (this->dc_pin_ == nullptr) { + this->write(value, 9); + } else { + this->dc_pin_->digital_write(false); + this->write_byte(value); + this->dc_pin_->digital_write(true); + } + this->disable(); +} + +void ST7701S::write_data_(uint8_t value) { + this->enable(); + if (this->dc_pin_ == nullptr) { + this->write(value | 0x100, 9); + } else { + this->dc_pin_->digital_write(true); + this->write_byte(value); + } + this->disable(); +} + +/** + * this relies upon the init sequence being well-formed, which is guaranteed by the Python init code. + */ + +void ST7701S::write_sequence_(uint8_t cmd, size_t len, const uint8_t *bytes) { + this->write_command_(cmd); + while (len-- != 0) + this->write_data_(*bytes++); +} + +void ST7701S::write_init_sequence_() { + for (size_t i = 0; i != this->init_sequence_.size();) { + uint8_t cmd = this->init_sequence_[i++]; + size_t len = this->init_sequence_[i++]; + this->write_sequence_(cmd, len, &this->init_sequence_[i]); + i += len; + esph_log_v(TAG, "Command %X, %d bytes", cmd, len); + if (cmd == SW_RESET_CMD) + delay(6); + } + // st7701 does not appear to support axis swapping + this->write_sequence_(CMD2_BKSEL, sizeof(CMD2_BK0), CMD2_BK0); + this->write_command_(SDIR_CMD); // this is in the BK0 command set + this->write_data_(this->mirror_x_ ? 0x04 : 0x00); + uint8_t val = this->color_mode_ == display::COLOR_ORDER_BGR ? 0x08 : 0x00; + if (this->mirror_y_) + val |= 0x10; + this->write_command_(MADCTL_CMD); + this->write_data_(val); + esph_log_d(TAG, "write MADCTL %X", val); + this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); + this->set_timeout(120, [this] { + this->write_command_(SLEEP_OUT); + this->write_command_(DISPLAY_ON); + }); +} + +void ST7701S::dump_config() { + ESP_LOGCONFIG("", "ST7701S RGB LCD"); + ESP_LOGCONFIG(TAG, " Height: %u", this->height_); + ESP_LOGCONFIG(TAG, " Width: %u", this->width_); + LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" DE Pin: ", this->de_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); + for (size_t i = 0; i != data_pin_count; i++) + ESP_LOGCONFIG(TAG, " Data pin %d: %s", i, (this->data_pins_[i])->dump_summary().c_str()); + ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); +} + +} // namespace st7701s +} // namespace esphome +#endif // USE_ESP32_VARIANT_ESP32S3 diff --git a/esphome/components/st7701s/st7701s.h b/esphome/components/st7701s/st7701s.h new file mode 100644 index 0000000000..2328bca965 --- /dev/null +++ b/esphome/components/st7701s/st7701s.h @@ -0,0 +1,115 @@ +// +// Created by Clyde Stubbs on 29/10/2023. +// +#pragma once + +// only applicable on ESP32-S3 +#ifdef USE_ESP32_VARIANT_ESP32S3 +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/display/display.h" +#include "esp_lcd_panel_ops.h" + +#include "esp_lcd_panel_rgb.h" + +namespace esphome { +namespace st7701s { + +constexpr static const char *const TAG = "display.st7701s"; +const uint8_t SW_RESET_CMD = 0x01; +const uint8_t SLEEP_OUT = 0x11; +const uint8_t SDIR_CMD = 0xC7; +const uint8_t MADCTL_CMD = 0x36; +const uint8_t INVERT_OFF = 0x20; +const uint8_t INVERT_ON = 0x21; +const uint8_t DISPLAY_ON = 0x29; +const uint8_t CMD2_BKSEL = 0xFF; +const uint8_t CMD2_BK0[5] = {0x77, 0x01, 0x00, 0x00, 0x10}; + +class ST7701S : public display::Display, + public spi::SPIDevice { + public: + void update() override { this->do_update_(); } + void setup() override; + void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; + + display::ColorOrder get_color_mode() { return this->color_mode_; } + void set_color_mode(display::ColorOrder color_mode) { this->color_mode_ = color_mode; } + void set_invert_colors(bool invert_colors) { this->invert_colors_ = invert_colors; } + + void add_data_pin(InternalGPIOPin *data_pin, size_t index) { this->data_pins_[index] = data_pin; }; + void set_de_pin(InternalGPIOPin *de_pin) { this->de_pin_ = de_pin; } + void set_pclk_pin(InternalGPIOPin *pclk_pin) { this->pclk_pin_ = pclk_pin; } + void set_vsync_pin(InternalGPIOPin *vsync_pin) { this->vsync_pin_ = vsync_pin; } + void set_hsync_pin(InternalGPIOPin *hsync_pin) { this->hsync_pin_ = hsync_pin; } + void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } + void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } + void set_width(uint16_t width) { this->width_ = width; } + void set_pclk_frequency(uint32_t pclk_frequency) { this->pclk_frequency_ = pclk_frequency; } + void set_pclk_inverted(bool inverted) { this->pclk_inverted_ = inverted; } + void set_dimensions(uint16_t width, uint16_t height) { + this->width_ = width; + this->height_ = height; + } + int get_width() override { return this->width_; } + int get_height() override { return this->height_; } + void set_hsync_back_porch(uint16_t hsync_back_porch) { this->hsync_back_porch_ = hsync_back_porch; } + void set_hsync_front_porch(uint16_t hsync_front_porch) { this->hsync_front_porch_ = hsync_front_porch; } + void set_hsync_pulse_width(uint16_t hsync_pulse_width) { this->hsync_pulse_width_ = hsync_pulse_width; } + void set_vsync_pulse_width(uint16_t vsync_pulse_width) { this->vsync_pulse_width_ = vsync_pulse_width; } + void set_vsync_back_porch(uint16_t vsync_back_porch) { this->vsync_back_porch_ = vsync_back_porch; } + void set_vsync_front_porch(uint16_t vsync_front_porch) { this->vsync_front_porch_ = vsync_front_porch; } + void set_init_sequence(const std::vector &init_sequence) { this->init_sequence_ = init_sequence; } + void set_mirror_x(bool mirror_x) { this->mirror_x_ = mirror_x; } + void set_mirror_y(bool mirror_y) { this->mirror_y_ = mirror_y; } + void set_offsets(int16_t offset_x, int16_t offset_y) { + this->offset_x_ = offset_x; + this->offset_y_ = offset_y; + } + display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } + int get_width_internal() override { return this->width_; } + int get_height_internal() override { return this->height_; } + void dump_config() override; + void draw_pixel_at(int x, int y, Color color) override; + + // this will be horribly slow. + protected: + void write_command_(uint8_t value); + void write_data_(uint8_t value); + void write_sequence_(uint8_t cmd, size_t len, const uint8_t *bytes); + void write_init_sequence_(); + + InternalGPIOPin *de_pin_{nullptr}; + InternalGPIOPin *pclk_pin_{nullptr}; + InternalGPIOPin *hsync_pin_{nullptr}; + InternalGPIOPin *vsync_pin_{nullptr}; + GPIOPin *reset_pin_{nullptr}; + GPIOPin *dc_pin_{nullptr}; + InternalGPIOPin *data_pins_[16] = {}; + uint16_t hsync_pulse_width_ = 10; + uint16_t hsync_back_porch_ = 10; + uint16_t hsync_front_porch_ = 20; + uint16_t vsync_pulse_width_ = 10; + uint16_t vsync_back_porch_ = 10; + uint16_t vsync_front_porch_ = 10; + std::vector init_sequence_; + uint32_t pclk_frequency_ = 16 * 1000 * 1000; + bool pclk_inverted_{true}; + + bool invert_colors_{}; + display::ColorOrder color_mode_{display::COLOR_ORDER_BGR}; + size_t width_{}; + size_t height_{}; + int16_t offset_x_{0}; + int16_t offset_y_{0}; + bool mirror_x_{}; + bool mirror_y_{}; + + esp_lcd_panel_handle_t handle_{}; +}; + +} // namespace st7701s +} // namespace esphome +#endif diff --git a/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml b/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..9ce2d9b9fd --- /dev/null +++ b/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml @@ -0,0 +1,40 @@ +psram: + mode: octal + speed: 80MHz +display: + - platform: rpi_dpi_rgb + update_interval: never + auto_clear_enabled: false + id: rpi_display + color_order: RGB + rotation: 90 + dimensions: + width: 800 + height: 480 + de_pin: + number: 40 + hsync_pin: 39 + vsync_pin: 41 + pclk_pin: 42 + data_pins: + red: + - number: 45 # r1 + ignore_strapping_warning: true + - 48 # r2 + - 47 # r3 + - 21 # r4 + - number: 14 # r5 + ignore_strapping_warning: false + green: + - 5 # g0 + - 6 # g1 + - 7 # g2 + - 15 # g3 + - 16 # g4 + - 4 # g5 + blue: + - 8 # b1 + - 3 # b2 + - 46 # b3 + - 9 # b4 + - 1 # b5 diff --git a/tests/components/st7701s/test.esp32-s3-idf.yaml b/tests/components/st7701s/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..497df8c8ce --- /dev/null +++ b/tests/components/st7701s/test.esp32-s3-idf.yaml @@ -0,0 +1,60 @@ +psram: + mode: octal + speed: 80MHz +spi: + - id: lcd_spi + clk_pin: 41 + mosi_pin: 48 + +i2c: + sda: 39 + scl: 40 + scan: false + id: bus_a + +pca9554: + - id: p_c_a + pin_count: 16 + address: 0x20 + +display: + - platform: st7701s + spi_mode: MODE3 + color_order: RGB + dimensions: + width: 480 + height: 480 + invert_colors: true + transform: + mirror_x: true + mirror_y: true + cs_pin: + pca9554: p_c_a + number: 4 + reset_pin: + pca9554: p_c_a + number: 5 + de_pin: 18 + hsync_pin: 16 + vsync_pin: 17 + pclk_pin: 21 + init_sequence: 1 + data_pins: + - number: 0 + ignore_strapping_warning: true + - 1 + - 2 + - 3 + - number: 4 + ignore_strapping_warning: false + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 From 51ab15c40e6f81ac78fc884946ff3ecd999a14d0 Mon Sep 17 00:00:00 2001 From: mrtoy-me <118446898+mrtoy-me@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:31:58 +1000 Subject: [PATCH 1355/2607] hydreon_rgxx - add resolution option (#6077) Co-authored-by: functionpointer --- esphome/components/hydreon_rgxx/__init__.py | 1 + .../components/hydreon_rgxx/hydreon_rgxx.cpp | 11 ++++++++++- esphome/components/hydreon_rgxx/hydreon_rgxx.h | 9 +++++++++ esphome/components/hydreon_rgxx/sensor.py | 18 +++++++++++++++--- tests/test3.yaml | 1 + 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/esphome/components/hydreon_rgxx/__init__.py b/esphome/components/hydreon_rgxx/__init__.py index 5fe050edf2..b488bfc1b4 100644 --- a/esphome/components/hydreon_rgxx/__init__.py +++ b/esphome/components/hydreon_rgxx/__init__.py @@ -6,6 +6,7 @@ DEPENDENCIES = ["uart"] hydreon_rgxx_ns = cg.esphome_ns.namespace("hydreon_rgxx") RGModel = hydreon_rgxx_ns.enum("RGModel") +RG15Resolution = hydreon_rgxx_ns.enum("RG15Resolution") HydreonRGxxComponent = hydreon_rgxx_ns.class_( "HydreonRGxxComponent", cg.PollingComponent, uart.UARTDevice ) diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp index c026d7cce6..95702fe9e8 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp @@ -22,6 +22,11 @@ void HydreonRGxxComponent::dump_config() { ESP_LOGCONFIG(TAG, " Disable Led: %s", TRUEFALSE(this->disable_led_)); } else { ESP_LOGCONFIG(TAG, " Model: RG15"); + if (this->resolution_ == FORCE_HIGH) { + ESP_LOGCONFIG(TAG, " Resolution: high"); + } else { + ESP_LOGCONFIG(TAG, " Resolution: low"); + } } LOG_UPDATE_INTERVAL(this); @@ -195,7 +200,11 @@ void HydreonRGxxComponent::process_line_() { ESP_LOGI(TAG, "Boot detected: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); if (this->model_ == RG15) { - this->write_str("P\nH\nM\n"); // set sensor to (P)polling mode, (H)high res mode, (M)metric mode + if (this->resolution_ == FORCE_HIGH) { + this->write_str("P\nH\nM\n"); // set sensor to (P)polling mode, (H)high res mode, (M)metric mode + } else { + this->write_str("P\nL\nM\n"); // set sensor to (P)polling mode, (L)low res mode, (M)metric mode + } } if (this->model_ == RG9) { diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.h b/esphome/components/hydreon_rgxx/hydreon_rgxx.h index 1edda59800..76b0985a24 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.h +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.h @@ -16,6 +16,11 @@ enum RGModel { RG15 = 2, }; +enum RG15Resolution { + FORCE_LOW = 1, + FORCE_HIGH = 2, +}; + #ifdef HYDREON_RGXX_NUM_SENSORS static const uint8_t NUM_SENSORS = HYDREON_RGXX_NUM_SENSORS; #else @@ -37,6 +42,7 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice { void set_em_sat_sensor(binary_sensor::BinarySensor *sensor) { this->em_sat_sensor_ = sensor; } #endif void set_model(RGModel model) { model_ = model; } + void set_resolution(RG15Resolution resolution) { resolution_ = resolution; } void set_request_temperature(bool b) { request_temperature_ = b; } /// Schedule data readings. @@ -68,7 +74,10 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice { int16_t boot_count_ = 0; int16_t no_response_count_ = 0; std::string buffer_; + RGModel model_ = RG9; + RG15Resolution resolution_ = FORCE_HIGH; + int sw_version_ = 0; bool too_cold_ = false; bool lens_bad_ = false; diff --git a/esphome/components/hydreon_rgxx/sensor.py b/esphome/components/hydreon_rgxx/sensor.py index f9cb316c24..72b74bf624 100644 --- a/esphome/components/hydreon_rgxx/sensor.py +++ b/esphome/components/hydreon_rgxx/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, CONF_MODEL, CONF_MOISTURE, + CONF_RESOLUTION, CONF_TEMPERATURE, DEVICE_CLASS_PRECIPITATION_INTENSITY, DEVICE_CLASS_PRECIPITATION, @@ -14,7 +15,7 @@ from esphome.const import ( ICON_THERMOMETER, ) -from . import RGModel, HydreonRGxxComponent +from . import RGModel, RG15Resolution, HydreonRGxxComponent UNIT_INTENSITY = "intensity" UNIT_MILLIMETERS = "mm" @@ -37,11 +38,18 @@ RG_MODELS = { # 1.100 - https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf # 1.200 - https://rainsensors.com/wp-content/uploads/sites/3/2022/03/2022.02.17-rev-1.200-rg-9_instructions.pdf } -SUPPORTED_SENSORS = { + +RG15_RESOLUTION = { + "low": RG15Resolution.FORCE_LOW, + "high": RG15Resolution.FORCE_HIGH, +} + +SUPPORTED_OPTIONS = { CONF_ACC: ["RG_15"], CONF_EVENT_ACC: ["RG_15"], CONF_TOTAL_ACC: ["RG_15"], CONF_R_INT: ["RG_15"], + CONF_RESOLUTION: ["RG_15"], CONF_MOISTURE: ["RG_9"], CONF_TEMPERATURE: ["RG_9"], CONF_DISABLE_LED: ["RG_9"], @@ -57,7 +65,7 @@ PROTOCOL_NAMES = { def _validate(config): - for conf, models in SUPPORTED_SENSORS.items(): + for conf, models in SUPPORTED_OPTIONS.items(): if conf in config: if config[CONF_MODEL] not in models: raise cv.Invalid( @@ -75,6 +83,7 @@ CONFIG_SCHEMA = cv.All( upper=True, space="_", ), + cv.Optional(CONF_RESOLUTION): cv.enum(RG15_RESOLUTION, upper=False), cv.Optional(CONF_ACC): sensor.sensor_schema( unit_of_measurement=UNIT_MILLIMETERS, accuracy_decimals=2, @@ -139,6 +148,9 @@ async def to_code(config): cg.add(var.set_sensor(sens, i)) cg.add(var.set_model(config[CONF_MODEL])) + if CONF_RESOLUTION in config: + cg.add(var.set_resolution(config[CONF_RESOLUTION])) + cg.add(var.set_request_temperature(CONF_TEMPERATURE in config)) if CONF_DISABLE_LED in config: diff --git a/tests/test3.yaml b/tests/test3.yaml index 29ed40c52a..61d814385b 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -409,6 +409,7 @@ sensor: name: hydreon_total_acc r_int: name: hydreon_r_int + resolution: low - platform: adc pin: VCC From 782d662c2029e21fbb6ddb3a434cbe20dc310208 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:50:24 +1100 Subject: [PATCH 1356/2607] SPI schema now uses typed_schema with `type` key (#6353) --- esphome/components/spi/__init__.py | 22 +++++++++++++------- tests/components/spi/test.esp32-s3-idf.yaml | 23 +++++++++++++++++++++ tests/test8.1.yaml | 12 ++--------- 3 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 tests/components/spi/test.esp32-s3-idf.yaml diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index d45362435e..c2335bd92a 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -32,7 +32,10 @@ from esphome.const import ( CONF_ALLOW_OTHER_USES, CONF_DATA_PINS, ) -from esphome.core import coroutine_with_priority, CORE +from esphome.core import ( + coroutine_with_priority, + CORE, +) CODEOWNERS = ["@esphome/core", "@clydebarrow"] spi_ns = cg.esphome_ns.namespace("spi") @@ -73,6 +76,8 @@ CONF_SPI_MODE = "spi_mode" CONF_FORCE_SW = "force_sw" CONF_INTERFACE = "interface" CONF_INTERFACE_INDEX = "interface_index" +TYPE_SINGLE = "single" +TYPE_QUAD = "quad" # RP2040 SPI pin assignments are complicated; # refer to GPIO function select table in https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf @@ -297,18 +302,19 @@ SPI_QUAD_SCHEMA = cv.All( ), } ), + cv.only_on([PLATFORM_ESP32]), cv.only_with_esp_idf, ) CONFIG_SCHEMA = cv.All( - # Order is important. SPI_SCHEMA is the default. cv.ensure_list( - cv.Any( - SPI_SCHEMA, - SPI_QUAD_SCHEMA, - msg="Standard SPI requires mosi_pin and/or miso_pin; quad SPI requires data_pins only." - + " A clock pin is always required", - ), + cv.typed_schema( + { + TYPE_SINGLE: SPI_SCHEMA, + TYPE_QUAD: SPI_QUAD_SCHEMA, + }, + default_type=TYPE_SINGLE, + ) ), validate_spi_config, ) diff --git a/tests/components/spi/test.esp32-s3-idf.yaml b/tests/components/spi/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..3aae21cbeb --- /dev/null +++ b/tests/components/spi/test.esp32-s3-idf.yaml @@ -0,0 +1,23 @@ +spi: + - id: spi_id_1 + type: single + clk_pin: + number: GPIO7 + allow_other_uses: false + mosi_pin: GPIO6 + interface: hardware + - id: quad_spi + type: quad + clk_pin: 47 + interface: spi3 + data_pins: + - number: 40 + allow_other_uses: false + - 41 + - 42 + - 43 + - id: spi_id_3 + clk_pin: 8 + mosi_pin: 9 + interface: any + diff --git a/tests/test8.1.yaml b/tests/test8.1.yaml index fdfa8bc786..ab3d0d44aa 100644 --- a/tests/test8.1.yaml +++ b/tests/test8.1.yaml @@ -23,20 +23,12 @@ psram: spi: - id: spi_id_1 + type: single clk_pin: number: GPIO7 allow_other_uses: false mosi_pin: GPIO6 - interface: any - - id: quad_spi - clk_pin: 47 - data_pins: - - number: 40 - allow_other_uses: false - - 41 - - 42 - - 43 - + interface: hardware spi_device: id: spidev data_rate: 2MHz From 5b28bd3d97733c44a7f79f9f6d2f143b0264fe34 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Tue, 12 Mar 2024 03:51:01 +0100 Subject: [PATCH 1357/2607] VEML7700 and VEML6030 light sensors (#6067) * VEML7700 and VEML6030 light sensors * VEML7700 and VEML6030 light sensors - CODEOWNERS * VEML7700 and VEML6030 light sensors - tidy up * VEML7700 and VEML6030 light sensors - tidy up * VEML7700 tidy up * VEML7700 tidy up 4 * VEML7700 tidying up more * VEML7700 after review. non-blocking approach * VEML7700 CONSTANT_CASE * VEML7700 merge fix * VEML7700 pragma pack changed to attribute * VEML7700 pragma pack -> attribute * Minor publish split * minor * LOGD->LOGV * new school tests added * Discard changes to tests/test1.yaml --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/veml7700/__init__.py | 1 + esphome/components/veml7700/sensor.py | 190 ++++++++ esphome/components/veml7700/veml7700.cpp | 437 ++++++++++++++++++ esphome/components/veml7700/veml7700.h | 202 ++++++++ tests/components/veml7700/common.yaml | 10 + .../veml7700/test.esp32-c3-idf.yaml | 6 + tests/components/veml7700/test.esp32-c3.yaml | 6 + tests/components/veml7700/test.esp32-idf.yaml | 6 + tests/components/veml7700/test.esp32.yaml | 6 + tests/components/veml7700/test.esp8266.yaml | 6 + tests/components/veml7700/test.rp2040.yaml | 6 + 12 files changed, 877 insertions(+) create mode 100644 esphome/components/veml7700/__init__.py create mode 100644 esphome/components/veml7700/sensor.py create mode 100644 esphome/components/veml7700/veml7700.cpp create mode 100644 esphome/components/veml7700/veml7700.h create mode 100644 tests/components/veml7700/common.yaml create mode 100644 tests/components/veml7700/test.esp32-c3-idf.yaml create mode 100644 tests/components/veml7700/test.esp32-c3.yaml create mode 100644 tests/components/veml7700/test.esp32-idf.yaml create mode 100644 tests/components/veml7700/test.esp32.yaml create mode 100644 tests/components/veml7700/test.esp8266.yaml create mode 100644 tests/components/veml7700/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 320c2d5e7e..e31dd16077 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -380,6 +380,7 @@ esphome/components/ultrasonic/* @OttoWinter esphome/components/uponor_smatrix/* @kroimon esphome/components/vbus/* @ssieb esphome/components/veml3235/* @kbx81 +esphome/components/veml7700/* @latonita esphome/components/version/* @esphome/core esphome/components/voice_assistant/* @jesserockz esphome/components/wake_on_lan/* @willwill2will54 diff --git a/esphome/components/veml7700/__init__.py b/esphome/components/veml7700/__init__.py new file mode 100644 index 0000000000..dd06cfffea --- /dev/null +++ b/esphome/components/veml7700/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@latonita"] diff --git a/esphome/components/veml7700/sensor.py b/esphome/components/veml7700/sensor.py new file mode 100644 index 0000000000..7ce05b47e4 --- /dev/null +++ b/esphome/components/veml7700/sensor.py @@ -0,0 +1,190 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ACTUAL_GAIN, + CONF_AUTO_MODE, + CONF_FULL_SPECTRUM, + CONF_GAIN, + CONF_GLASS_ATTENUATION_FACTOR, + CONF_ID, + CONF_INFRARED, + CONF_INTEGRATION_TIME, + CONF_NAME, + UNIT_LUX, + UNIT_MILLISECOND, + ICON_BRIGHTNESS_5, + ICON_BRIGHTNESS_6, + ICON_TIMER, + DEVICE_CLASS_ILLUMINANCE, + STATE_CLASS_MEASUREMENT, +) + +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +UNIT_COUNTS = "#" +ICON_MULTIPLICATION = "mdi:multiplication" +ICON_BRIGHTNESS_7 = "mdi:brightness-7" + +CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" +CONF_AMBIENT_LIGHT = "ambient_light" +CONF_AMBIENT_LIGHT_COUNTS = "ambient_light_counts" +CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" +CONF_LUX_COMPENSATION = "lux_compensation" + +veml7700_ns = cg.esphome_ns.namespace("veml7700") + +VEML7700Component = veml7700_ns.class_( + "VEML7700Component", cg.PollingComponent, i2c.I2CDevice +) + +Gain = veml7700_ns.enum("Gain") +GAINS = { + "1/8X": Gain.X_1_8, + "1/4X": Gain.X_1_4, + "1X": Gain.X_1, + "2X": Gain.X_2, +} + +IntegrationTime = veml7700_ns.enum("IntegrationTime") +INTEGRATION_TIMES = { + 25: IntegrationTime.INTEGRATION_TIME_25MS, + 50: IntegrationTime.INTEGRATION_TIME_50MS, + 100: IntegrationTime.INTEGRATION_TIME_100MS, + 200: IntegrationTime.INTEGRATION_TIME_200MS, + 400: IntegrationTime.INTEGRATION_TIME_400MS, + 800: IntegrationTime.INTEGRATION_TIME_800MS, +} + + +def validate_integration_time(value): + value = cv.positive_time_period_milliseconds(value).total_milliseconds + return cv.enum(INTEGRATION_TIMES, int=True)(value) + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(VEML7700Component), + cv.Optional(CONF_AUTO_MODE, default=True): cv.boolean, + cv.Optional(CONF_GAIN, default="1/8X"): cv.enum(GAINS, upper=True), + cv.Optional( + CONF_INTEGRATION_TIME, default="100ms" + ): validate_integration_time, + cv.Optional(CONF_LUX_COMPENSATION, default=True): cv.boolean, + cv.Optional(CONF_GLASS_ATTENUATION_FACTOR, default=1.0): cv.float_range( + min=1.0 + ), + cv.Optional(CONF_AMBIENT_LIGHT): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_BRIGHTNESS_6, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_AMBIENT_LIGHT_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_6, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_FULL_SPECTRUM): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_BRIGHTNESS_7, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_FULL_SPECTRUM_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_7, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_INFRARED): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_BRIGHTNESS_5, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_GAIN): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_MULTIPLICATION, + accuracy_decimals=3, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_INTEGRATION_TIME): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_MILLISECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x10)), +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if als_config := config.get(CONF_AMBIENT_LIGHT): + sens = await sensor.new_sensor(als_config) + cg.add(var.set_ambient_light_sensor(sens)) + + if als_cnt_config := config.get(CONF_AMBIENT_LIGHT_COUNTS): + sens = await sensor.new_sensor(als_cnt_config) + cg.add(var.set_ambient_light_counts_sensor(sens)) + + if full_spect_config := config.get(CONF_FULL_SPECTRUM): + sens = await sensor.new_sensor(full_spect_config) + cg.add(var.set_white_sensor(sens)) + + if full_spect_cnt_config := config.get(CONF_FULL_SPECTRUM_COUNTS): + sens = await sensor.new_sensor(full_spect_cnt_config) + cg.add(var.set_white_counts_sensor(sens)) + + if infrared_config := config.get(CONF_INFRARED): + sens = await sensor.new_sensor(infrared_config) + cg.add(var.set_infrared_sensor(sens)) + + if act_gain_config := config.get(CONF_ACTUAL_GAIN): + sens = await sensor.new_sensor(act_gain_config) + cg.add(var.set_actual_gain_sensor(sens)) + + if act_itime_config := config.get(CONF_ACTUAL_INTEGRATION_TIME): + sens = await sensor.new_sensor(act_itime_config) + cg.add(var.set_actual_integration_time_sensor(sens)) + + cg.add(var.set_enable_automatic_mode(config[CONF_AUTO_MODE])) + cg.add(var.set_enable_lux_compensation(config[CONF_LUX_COMPENSATION])) + cg.add(var.set_gain(config[CONF_GAIN])) + cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME])) + cg.add(var.set_glass_attenuation_factor(config[CONF_GLASS_ATTENUATION_FACTOR])) diff --git a/esphome/components/veml7700/veml7700.cpp b/esphome/components/veml7700/veml7700.cpp new file mode 100644 index 0000000000..68550811a1 --- /dev/null +++ b/esphome/components/veml7700/veml7700.cpp @@ -0,0 +1,437 @@ +#include "veml7700.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace veml7700 { + +static const char *const TAG = "veml7700"; +static const size_t VEML_REG_SIZE = 2; + +static float reduce_to_zero(float a, float b) { return (a > b) ? (a - b) : 0; } + +template T get_next(const T (&array)[size], const T val) { + size_t i = 0; + size_t idx = -1; + while (idx == -1 && i < size) { + if (array[i] == val) { + idx = i; + break; + } + i++; + } + if (idx == -1 || i + 1 >= size) + return val; + return array[i + 1]; +} + +template T get_prev(const T (&array)[size], const T val) { + size_t i = size - 1; + size_t idx = -1; + while (idx == -1 && i > 0) { + if (array[i] == val) { + idx = i; + break; + } + i--; + } + if (idx == -1 || i == 0) + return val; + return array[i - 1]; +} + +static uint16_t get_itime_ms(IntegrationTime time) { + uint16_t ms = 0; + switch (time) { + case INTEGRATION_TIME_100MS: + ms = 100; + break; + case INTEGRATION_TIME_200MS: + ms = 200; + break; + case INTEGRATION_TIME_400MS: + ms = 400; + break; + case INTEGRATION_TIME_800MS: + ms = 800; + break; + case INTEGRATION_TIME_50MS: + ms = 50; + break; + case INTEGRATION_TIME_25MS: + ms = 25; + break; + default: + ms = 100; + } + return ms; +} + +static float get_gain_coeff(Gain gain) { + static const float GAIN_FLOAT[GAINS_COUNT] = {1.0f, 2.0f, 0.125f, 0.25f}; + return GAIN_FLOAT[gain & 0b11]; +} + +static const char *get_gain_str(Gain gain) { + static const char *gain_str[GAINS_COUNT] = {"1x", "2x", "1/8x", "1/4x"}; + return gain_str[gain & 0b11]; +} + +void VEML7700Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up VEML7700/6030..."); + + auto err = this->configure_(); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Sensor configuration failed"); + this->mark_failed(); + } else { + this->state_ = State::INITIAL_SETUP_COMPLETED; + } +} + +void VEML7700Component::dump_config() { + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Automatic gain/time: %s", YESNO(this->automatic_mode_enabled_)); + if (!this->automatic_mode_enabled_) { + ESP_LOGCONFIG(TAG, " Gain: %s", get_gain_str(this->gain_)); + ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); + } + ESP_LOGCONFIG(TAG, " Lux compensation: %s", YESNO(this->lux_compensation_enabled_)); + ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + LOG_UPDATE_INTERVAL(this); + + LOG_SENSOR(" ", "ALS channel lux", this->ambient_light_sensor_); + LOG_SENSOR(" ", "ALS channel counts", this->ambient_light_counts_sensor_); + LOG_SENSOR(" ", "WHITE channel lux", this->white_sensor_); + LOG_SENSOR(" ", "WHITE channel counts", this->white_counts_sensor_); + LOG_SENSOR(" ", "FAKE_IR channel lux", this->fake_infrared_sensor_); + LOG_SENSOR(" ", "Actual gain", this->actual_gain_sensor_); + LOG_SENSOR(" ", "Actual integration time", this->actual_integration_time_sensor_); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with I2C VEML7700/6030 failed!"); + } +} + +void VEML7700Component::update() { + if (this->is_ready() && this->state_ == State::IDLE) { + ESP_LOGV(TAG, "Update: Initiating new data collection"); + + this->state_ = this->automatic_mode_enabled_ ? State::COLLECTING_DATA_AUTO : State::COLLECTING_DATA; + + this->readings_.als_counts = 0; + this->readings_.white_counts = 0; + this->readings_.actual_time = this->integration_time_; + this->readings_.actual_gain = this->gain_; + this->readings_.als_lux = 0; + this->readings_.white_lux = 0; + this->readings_.fake_infrared_lux = 0; + } else { + ESP_LOGV(TAG, "Update: Component not ready yet"); + } +} + +void VEML7700Component::loop() { + ErrorCode err = i2c::ERROR_OK; + + if (this->state_ == State::INITIAL_SETUP_COMPLETED) { + // Datasheet: 2.5 ms before the first measurement is needed, allowing for the correct start of the signal processor + // and oscillator. + // Reality: wait for couple integration times to have first samples captured + this->set_timeout(2 * this->integration_time_, [this]() { this->state_ = State::IDLE; }); + } + + if (this->is_ready()) { + switch (this->state_) { + case State::IDLE: + // doing nothing, having best time + break; + + case State::COLLECTING_DATA: + err = this->read_sensor_output_(this->readings_); + this->state_ = (err == i2c::ERROR_OK) ? State::DATA_COLLECTED : State::IDLE; + break; + + case State::COLLECTING_DATA_AUTO: // Automatic mode - we start here to reconfigure device first + case State::DATA_COLLECTED: + if (!this->are_adjustments_required_(this->readings_)) { + this->state_ = State::READY_TO_PUBLISH_PART_1; + } else { + // if sensitivity adjustment needed - + // shutdown device to change config and wait one integration time period + this->state_ = State::ADJUSTMENT_IN_PROGRESS; + err = this->reconfigure_time_and_gain_(this->readings_.actual_time, this->readings_.actual_gain, true); + if (err == i2c::ERROR_OK) { + this->set_timeout(1 * get_itime_ms(this->readings_.actual_time), + [this]() { this->state_ = State::READY_TO_APPLY_ADJUSTMENTS; }); + } else { + this->state_ = State::IDLE; + } + } + break; + + case State::ADJUSTMENT_IN_PROGRESS: + // nothing to be done, just waiting for the timeout + break; + + case State::READY_TO_APPLY_ADJUSTMENTS: + // second stage of sensitivity adjustment - turn device back on + // and wait 2-3 integration time periods to get good data samples + this->state_ = State::ADJUSTMENT_IN_PROGRESS; + err = this->reconfigure_time_and_gain_(this->readings_.actual_time, this->readings_.actual_gain, false); + if (err == i2c::ERROR_OK) { + this->set_timeout(3 * get_itime_ms(this->readings_.actual_time), + [this]() { this->state_ = State::COLLECTING_DATA; }); + } else { + this->state_ = State::IDLE; + } + break; + + case State::READY_TO_PUBLISH_PART_1: + this->status_clear_warning(); + + this->apply_lux_calculation_(this->readings_); + this->apply_lux_compensation_(this->readings_); + this->apply_glass_attenuation_(this->readings_); + + this->publish_data_part_1_(this->readings_); + this->state_ = State::READY_TO_PUBLISH_PART_2; + break; + + case State::READY_TO_PUBLISH_PART_2: + this->publish_data_part_2_(this->readings_); + this->state_ = State::READY_TO_PUBLISH_PART_3; + break; + + case State::READY_TO_PUBLISH_PART_3: + this->publish_data_part_3_(this->readings_); + this->state_ = State::IDLE; + break; + + default: + break; + } + if (err != i2c::ERROR_OK) + this->status_set_warning(); + } +} + +ErrorCode VEML7700Component::configure_() { + ESP_LOGV(TAG, "Configure"); + + ConfigurationRegister als_conf{0}; + als_conf.ALS_INT_EN = false; + als_conf.ALS_PERS = Persistence::PERSISTENCE_1; + als_conf.ALS_IT = this->integration_time_; + als_conf.ALS_GAIN = this->gain_; + + als_conf.ALS_SD = true; + ESP_LOGV(TAG, "Shutdown before config. ALS_CONF_0 to 0x%04X", als_conf.raw); + auto err = this->write_register((uint8_t) CommandRegisters::ALS_CONF_0, als_conf.raw_bytes, VEML_REG_SIZE); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Failed to shutdown, I2C error %d", err); + return err; + } + delay(3); + + als_conf.ALS_SD = false; + ESP_LOGV(TAG, "Turning on. Setting ALS_CONF_0 to 0x%04X", als_conf.raw); + err = this->write_register((uint8_t) CommandRegisters::ALS_CONF_0, als_conf.raw_bytes, VEML_REG_SIZE); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Failed to turn on, I2C error %d", err); + return err; + } + + PSMRegister psm{0}; + psm.PSM = PSM::PSM_MODE_1; + psm.PSM_EN = false; + ESP_LOGV(TAG, "Setting PSM to 0x%04X", psm.raw); + err = this->write_register((uint8_t) CommandRegisters::PWR_SAVING, psm.raw_bytes, VEML_REG_SIZE); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Failed to set PSM, I2C error %d", err); + return err; + } + + return err; +} + +ErrorCode VEML7700Component::reconfigure_time_and_gain_(IntegrationTime time, Gain gain, bool shutdown) { + ESP_LOGV(TAG, "Reconfigure time and gain (%d ms, %s) %s", get_itime_ms(time), get_gain_str(gain), + shutdown ? "Shutting down" : "Turning back on"); + + ConfigurationRegister als_conf{0}; + als_conf.raw = 0; + + // We have to before changing parameters + als_conf.ALS_SD = shutdown; + als_conf.ALS_INT_EN = false; + als_conf.ALS_PERS = Persistence::PERSISTENCE_1; + als_conf.ALS_IT = time; + als_conf.ALS_GAIN = gain; + auto err = this->write_register((uint8_t) CommandRegisters::ALS_CONF_0, als_conf.raw_bytes, VEML_REG_SIZE); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "%s failed", shutdown ? "Shutdown" : "Turn on"); + } + + return err; +} + +ErrorCode VEML7700Component::read_sensor_output_(Readings &data) { + auto als_err = + this->read_register((uint8_t) CommandRegisters::ALS, (uint8_t *) &data.als_counts, VEML_REG_SIZE, false); + if (als_err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Error reading ALS register, err = %d", als_err); + } + auto white_err = + this->read_register((uint8_t) CommandRegisters::WHITE, (uint8_t *) &data.white_counts, VEML_REG_SIZE, false); + if (white_err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Error reading WHITE register, err = %d", white_err); + } + + ConfigurationRegister conf{0}; + auto err = + this->read_register((uint8_t) CommandRegisters::ALS_CONF_0, (uint8_t *) conf.raw_bytes, VEML_REG_SIZE, false); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "Error reading ALS_CONF_0 register, err = %d", white_err); + } + data.actual_time = conf.ALS_IT; + data.actual_gain = conf.ALS_GAIN; + + ESP_LOGV(TAG, "Data from sensors: ALS = %d, WHITE = %d, Gain = %s, Time = %d ms", data.als_counts, data.white_counts, + get_gain_str(data.actual_gain), get_itime_ms(data.actual_time)); + return std::max(als_err, white_err); +} + +bool VEML7700Component::are_adjustments_required_(Readings &data) { + // skip first sample in auto mode - + // we need to reconfigure device after last measurement + if (this->state_ == State::COLLECTING_DATA_AUTO) + return true; + + if (!this->automatic_mode_enabled_) + return false; + + // Recommended thresholds as per datasheet + static constexpr uint16_t LOW_INTENSITY_THRESHOLD = 100; + static constexpr uint16_t HIGH_INTENSITY_THRESHOLD = 10000; + + static const IntegrationTime TIMES[INTEGRATION_TIMES_COUNT] = {INTEGRATION_TIME_25MS, INTEGRATION_TIME_50MS, + INTEGRATION_TIME_100MS, INTEGRATION_TIME_200MS, + INTEGRATION_TIME_400MS, INTEGRATION_TIME_800MS}; + static const Gain GAINS[GAINS_COUNT] = {X_1_8, X_1_4, X_1, X_2}; + + if (data.als_counts <= LOW_INTENSITY_THRESHOLD) { + Gain next_gain = get_next(GAINS, data.actual_gain); + if (next_gain != data.actual_gain) { + data.actual_gain = next_gain; + return true; + } + IntegrationTime next_time = get_next(TIMES, data.actual_time); + if (next_time != data.actual_time) { + data.actual_time = next_time; + return true; + } + } else if (data.als_counts >= HIGH_INTENSITY_THRESHOLD) { + Gain prev_gain = get_prev(GAINS, data.actual_gain); + if (prev_gain != data.actual_gain) { + data.actual_gain = prev_gain; + return true; + } + IntegrationTime prev_time = get_prev(TIMES, data.actual_time); + if (prev_time != data.actual_time) { + data.actual_time = prev_time; + return true; + } + } + + // Counts are either good (between thresholds) + // or there is no room to change sensitivity anymore + return false; +} + +void VEML7700Component::apply_lux_calculation_(Readings &data) { + static const float MAX_GAIN = 2.0f; + static const float MAX_ITIME_MS = 800.0f; + static const float MAX_LX_RESOLUTION = 0.0036f; + float lux_resolution = (MAX_ITIME_MS / (float) get_itime_ms(data.actual_time)) * + (MAX_GAIN / get_gain_coeff(data.actual_gain)) * MAX_LX_RESOLUTION; + ESP_LOGV(TAG, "Lux resolution for (%d, %s) = %.4f ", get_itime_ms(data.actual_time), get_gain_str(data.actual_gain), + lux_resolution); + + data.als_lux = lux_resolution * (float) data.als_counts; + data.white_lux = lux_resolution * (float) data.white_counts; + data.fake_infrared_lux = reduce_to_zero(data.white_lux, data.als_lux); + + ESP_LOGV(TAG, "%s mode - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx", + this->automatic_mode_enabled_ ? "Automatic" : "Manual", data.als_lux, data.white_lux, + data.fake_infrared_lux); +} + +void VEML7700Component::apply_lux_compensation_(Readings &data) { + if (!this->lux_compensation_enabled_) + return; + auto &local_data = data; + // Always apply correction for G1/4 and G1/8 + // Other Gains G1 and G2 are not supposed to be used for lux > 1000, + // corrections may help, but not a lot. + // + // "Illumination values higher than 1000 lx show non-linearity. + // This non-linearity is the same for all sensors, so a compensation formula can be applied + // if this light level is exceeded" + auto compensate = [&local_data](float &lux) { + auto calculate_high_lux_compensation = [](float lux_veml) -> float { + return (((6.0135e-13 * lux_veml - 9.3924e-9) * lux_veml + 8.1488e-5) * lux_veml + 1.0023) * lux_veml; + }; + + if (lux > 1000.0f || local_data.actual_gain == Gain::X_1_8 || local_data.actual_gain == Gain::X_1_4) { + lux = calculate_high_lux_compensation(lux); + } + }; + + compensate(data.als_lux); + compensate(data.white_lux); + data.fake_infrared_lux = reduce_to_zero(data.white_lux, data.als_lux); + + ESP_LOGV(TAG, "Lux compensation - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx", data.als_lux, data.white_lux, + data.fake_infrared_lux); +} + +void VEML7700Component::apply_glass_attenuation_(Readings &data) { + data.als_lux *= this->glass_attenuation_factor_; + data.white_lux *= this->glass_attenuation_factor_; + data.fake_infrared_lux = reduce_to_zero(data.white_lux, data.als_lux); + ESP_LOGV(TAG, "Glass attenuation - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx", data.als_lux, data.white_lux, + data.fake_infrared_lux); +} + +void VEML7700Component::publish_data_part_1_(Readings &data) { + if (this->ambient_light_sensor_ != nullptr) { + this->ambient_light_sensor_->publish_state(data.als_lux); + } + if (this->white_sensor_ != nullptr) { + this->white_sensor_->publish_state(data.white_lux); + } +} + +void VEML7700Component::publish_data_part_2_(Readings &data) { + if (this->fake_infrared_sensor_ != nullptr) { + this->fake_infrared_sensor_->publish_state(data.fake_infrared_lux); + } + if (this->ambient_light_counts_sensor_ != nullptr) { + this->ambient_light_counts_sensor_->publish_state(data.als_counts); + } + if (this->white_counts_sensor_ != nullptr) { + this->white_counts_sensor_->publish_state(data.white_counts); + } +} + +void VEML7700Component::publish_data_part_3_(Readings &data) { + if (this->actual_gain_sensor_ != nullptr) { + this->actual_gain_sensor_->publish_state(get_gain_coeff(data.actual_gain)); + } + if (this->actual_integration_time_sensor_ != nullptr) { + this->actual_integration_time_sensor_->publish_state(get_itime_ms(data.actual_time)); + } +} +} // namespace veml7700 +} // namespace esphome diff --git a/esphome/components/veml7700/veml7700.h b/esphome/components/veml7700/veml7700.h new file mode 100644 index 0000000000..fe5e1158e3 --- /dev/null +++ b/esphome/components/veml7700/veml7700.h @@ -0,0 +1,202 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/optional.h" + +namespace esphome { +namespace veml7700 { + +using esphome::i2c::ErrorCode; + +// +// Datasheet: https://www.vishay.com/docs/84286/veml7700.pdf +// + +enum class CommandRegisters : uint8_t { + ALS_CONF_0 = 0x00, // W: ALS gain, integration time, interrupt, and shutdown + ALS_WH = 0x01, // W: ALS high threshold window setting + ALS_WL = 0x02, // W: ALS low threshold window setting + PWR_SAVING = 0x03, // W: Set (15 : 3) 0000 0000 0000 0b + ALS = 0x04, // R: MSB, LSB data of whole ALS 16 bits + WHITE = 0x05, // R: MSB, LSB data of whole WHITE 16 bits + ALS_INT = 0x06 // R: ALS INT trigger event +}; + +enum Gain : uint8_t { + X_1 = 0, + X_2 = 1, + X_1_8 = 2, + X_1_4 = 3, +}; +const uint8_t GAINS_COUNT = 4; + +enum IntegrationTime : uint8_t { + INTEGRATION_TIME_25MS = 0b1100, + INTEGRATION_TIME_50MS = 0b1000, + INTEGRATION_TIME_100MS = 0b0000, + INTEGRATION_TIME_200MS = 0b0001, + INTEGRATION_TIME_400MS = 0b0010, + INTEGRATION_TIME_800MS = 0b0011, +}; +const uint8_t INTEGRATION_TIMES_COUNT = 6; + +enum Persistence : uint8_t { + PERSISTENCE_1 = 0, + PERSISTENCE_2 = 1, + PERSISTENCE_4 = 2, + PERSISTENCE_8 = 3, +}; + +enum PSM : uint8_t { + PSM_MODE_1 = 0, + PSM_MODE_2 = 1, + PSM_MODE_3 = 2, + PSM_MODE_4 = 3, +}; + +// The following section with bit-fields brings GCC compilation 'notes' about padding bytes due to bug in older GCC back +// in 2009 "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4" Even more to +// this - this message can't be disabled with "#pragma GCC diagnostic ignored" due to another bug which was only fixed +// in GCC 13 in 2022 :) No actions required, it is just a note. The code is correct. + +// +// VEML7700_CR_ALS_CONF_0 Register (0x00) +// +union ConfigurationRegister { + uint16_t raw; + uint8_t raw_bytes[2]; + struct { + bool ALS_SD : 1; // ALS shut down setting: 0 = ALS power on, 1 = ALS shut + // down + bool ALS_INT_EN : 1; // ALS interrupt enable setting: 0 = ALS INT disable, 1 + // = ALS INT enable + bool reserved_2 : 1; // 0 + bool reserved_3 : 1; // 0 + Persistence ALS_PERS : 2; // 00 - 1, 01- 2, 10 - 4, 11 - 8 + IntegrationTime ALS_IT : 4; // ALS integration time setting + bool reserved_10 : 1; // 0 + Gain ALS_GAIN : 2; // Gain selection + bool reserved_13 : 1; // 0 + bool reserved_14 : 1; // 0 + bool reserved_15 : 1; // 0 + } __attribute__((packed)); +}; + +// +// Power Saving Mode: PSM Register (0x03) +// +union PSMRegister { + uint16_t raw; + uint8_t raw_bytes[2]; + struct { + bool PSM_EN : 1; + uint8_t PSM : 2; + uint16_t reserved : 13; + } __attribute__((packed)); +}; + +class VEML7700Component : public PollingComponent, public i2c::I2CDevice { + public: + // + // EspHome framework functions + // + float get_setup_priority() const override { return setup_priority::DATA; } + void setup() override; + void dump_config() override; + void update() override; + void loop() override; + + // + // Configuration setters + // + void set_gain(Gain gain) { this->gain_ = gain; } + void set_integration_time(IntegrationTime time) { this->integration_time_ = time; } + void set_enable_automatic_mode(bool enable) { this->automatic_mode_enabled_ = enable; } + void set_enable_lux_compensation(bool enable) { this->lux_compensation_enabled_ = enable; } + void set_glass_attenuation_factor(float factor) { this->glass_attenuation_factor_ = factor; } + + void set_ambient_light_sensor(sensor::Sensor *sensor) { this->ambient_light_sensor_ = sensor; } + void set_ambient_light_counts_sensor(sensor::Sensor *sensor) { this->ambient_light_counts_sensor_ = sensor; } + void set_white_sensor(sensor::Sensor *sensor) { this->white_sensor_ = sensor; } + void set_white_counts_sensor(sensor::Sensor *sensor) { this->white_counts_sensor_ = sensor; } + void set_infrared_sensor(sensor::Sensor *sensor) { this->fake_infrared_sensor_ = sensor; } + void set_actual_gain_sensor(sensor::Sensor *sensor) { this->actual_gain_sensor_ = sensor; } + void set_actual_integration_time_sensor(sensor::Sensor *sensor) { this->actual_integration_time_sensor_ = sensor; } + + protected: + // + // Internal state machine, used to split all the actions into + // small steps in loop() to make sure we are not blocking execution + // + enum class State : uint8_t { + NOT_INITIALIZED, + INITIAL_SETUP_COMPLETED, + IDLE, + COLLECTING_DATA, + COLLECTING_DATA_AUTO, + DATA_COLLECTED, + ADJUSTMENT_NEEDED, + ADJUSTMENT_IN_PROGRESS, + READY_TO_APPLY_ADJUSTMENTS, + READY_TO_PUBLISH_PART_1, + READY_TO_PUBLISH_PART_2, + READY_TO_PUBLISH_PART_3 + } state_{State::NOT_INITIALIZED}; + + // + // Current measurements data + // + struct Readings { + uint16_t als_counts{0}; + uint16_t white_counts{0}; + IntegrationTime actual_time{INTEGRATION_TIME_100MS}; + Gain actual_gain{X_1_8}; + float als_lux{0}; + float white_lux{0}; + float fake_infrared_lux{0}; + ErrorCode err{i2c::ERROR_OK}; + } readings_; + + // + // Device interaction + // + ErrorCode configure_(); + ErrorCode reconfigure_time_and_gain_(IntegrationTime time, Gain gain, bool shutdown); + ErrorCode read_sensor_output_(Readings &data); + + // + // Working with the data + // + bool are_adjustments_required_(Readings &data); + void apply_lux_calculation_(Readings &data); + void apply_lux_compensation_(Readings &data); + void apply_glass_attenuation_(Readings &data); + void publish_data_part_1_(Readings &data); + void publish_data_part_2_(Readings &data); + void publish_data_part_3_(Readings &data); + + // + // Component configuration + // + bool automatic_mode_enabled_{true}; + bool lux_compensation_enabled_{true}; + float glass_attenuation_factor_{1.0}; + IntegrationTime integration_time_{INTEGRATION_TIME_100MS}; + Gain gain_{X_1}; + + // + // Sensors for publishing data + // + sensor::Sensor *ambient_light_sensor_{nullptr}; // Human eye range 500-600 nm, lx + sensor::Sensor *ambient_light_counts_sensor_{nullptr}; // Raw counts + sensor::Sensor *white_sensor_{nullptr}; // Wide range 450-950 nm, lx + sensor::Sensor *white_counts_sensor_{nullptr}; // Raw counts + sensor::Sensor *fake_infrared_sensor_{nullptr}; // Artificial. = WHITE lx - ALS lx. + sensor::Sensor *actual_gain_sensor_{nullptr}; // Actual gain multiplier for the measurement + sensor::Sensor *actual_integration_time_sensor_{nullptr}; // Actual integration time for the measurement +}; + +} // namespace veml7700 +} // namespace esphome diff --git a/tests/components/veml7700/common.yaml b/tests/components/veml7700/common.yaml new file mode 100644 index 0000000000..6620c8d7e1 --- /dev/null +++ b/tests/components/veml7700/common.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: veml7700 + address: 0x10 + i2c_id: i2c_veml7700 + ambient_light: Ambient light + ambient_light_counts: Ambient light counts + full_spectrum: Full spectrum + full_spectrum_counts: Full spectrum counts + actual_integration_time: Actual integration time + actual_gain: Actual gain diff --git a/tests/components/veml7700/test.esp32-c3-idf.yaml b/tests/components/veml7700/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ce0fa0125b --- /dev/null +++ b/tests/components/veml7700/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/veml7700/test.esp32-c3.yaml b/tests/components/veml7700/test.esp32-c3.yaml new file mode 100644 index 0000000000..ce0fa0125b --- /dev/null +++ b/tests/components/veml7700/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/veml7700/test.esp32-idf.yaml b/tests/components/veml7700/test.esp32-idf.yaml new file mode 100644 index 0000000000..4b812a1392 --- /dev/null +++ b/tests/components/veml7700/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/veml7700/test.esp32.yaml b/tests/components/veml7700/test.esp32.yaml new file mode 100644 index 0000000000..4b812a1392 --- /dev/null +++ b/tests/components/veml7700/test.esp32.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/veml7700/test.esp8266.yaml b/tests/components/veml7700/test.esp8266.yaml new file mode 100644 index 0000000000..ce0fa0125b --- /dev/null +++ b/tests/components/veml7700/test.esp8266.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/veml7700/test.rp2040.yaml b/tests/components/veml7700/test.rp2040.yaml new file mode 100644 index 0000000000..ce0fa0125b --- /dev/null +++ b/tests/components/veml7700/test.rp2040.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_veml7700 + scl: 5 + sda: 4 + +<<: !include common.yaml From 4bbde8357a65c0b2060f459b3b1f6e7bc228e4e2 Mon Sep 17 00:00:00 2001 From: Citric Lee <37475446+limengdu@users.noreply.github.com> Date: Tue, 12 Mar 2024 11:33:40 +0800 Subject: [PATCH 1358/2607] Add Seeed Studio mmWave Kit MR24HPC1 (#5761) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Peter Pan --- CODEOWNERS | 1 + esphome/components/seeed_mr24hpc1/__init__.py | 51 + .../seeed_mr24hpc1/binary_sensor.py | 23 + .../seeed_mr24hpc1/button/__init__.py | 42 + .../button/custom_mode_end_button.cpp | 9 + .../button/custom_mode_end_button.h | 18 + .../seeed_mr24hpc1/button/restart_button.cpp | 9 + .../seeed_mr24hpc1/button/restart_button.h | 18 + .../seeed_mr24hpc1/number/__init__.py | 132 +++ .../number/custom_mode_number.cpp | 12 + .../number/custom_mode_number.h | 18 + .../number/custom_unman_time_number.cpp | 9 + .../number/custom_unman_time_number.h | 18 + .../number/existence_threshold_number.cpp | 9 + .../number/existence_threshold_number.h | 18 + .../number/motion_threshold_number.cpp | 9 + .../number/motion_threshold_number.h | 18 + .../number/motion_trigger_time_number.cpp | 9 + .../number/motion_trigger_time_number.h | 18 + .../number/motiontorest_time_number.cpp | 9 + .../number/motiontorest_time_number.h | 18 + .../number/sensitivity_number.cpp | 9 + .../number/sensitivity_number.h | 18 + .../seeed_mr24hpc1/seeed_mr24hpc1.cpp | 890 ++++++++++++++++++ .../seeed_mr24hpc1/seeed_mr24hpc1.h | 217 +++++ .../seeed_mr24hpc1/seeed_mr24hpc1_constants.h | 173 ++++ .../seeed_mr24hpc1/select/__init__.py | 103 ++ .../select/existence_boundary_select.cpp | 15 + .../select/existence_boundary_select.h | 18 + .../select/motion_boundary_select.cpp | 15 + .../select/motion_boundary_select.h | 18 + .../select/scene_mode_select.cpp | 15 + .../seeed_mr24hpc1/select/scene_mode_select.h | 18 + .../select/unman_time_select.cpp | 15 + .../seeed_mr24hpc1/select/unman_time_select.h | 18 + esphome/components/seeed_mr24hpc1/sensor.py | 82 ++ .../seeed_mr24hpc1/switch/__init__.py | 32 + .../switch/underlyFuc_switch.cpp | 12 + .../seeed_mr24hpc1/switch/underlyFuc_switch.h | 18 + .../components/seeed_mr24hpc1/text_sensor.py | 74 ++ tests/components/seeed_mr24hpc1/common.yaml | 92 ++ .../seeed_mr24hpc1/test.esp32-c3-idf.yaml | 5 + .../seeed_mr24hpc1/test.esp32-c3.yaml | 5 + 43 files changed, 2330 insertions(+) create mode 100644 esphome/components/seeed_mr24hpc1/__init__.py create mode 100644 esphome/components/seeed_mr24hpc1/binary_sensor.py create mode 100644 esphome/components/seeed_mr24hpc1/button/__init__.py create mode 100644 esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.cpp create mode 100644 esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.h create mode 100644 esphome/components/seeed_mr24hpc1/button/restart_button.cpp create mode 100644 esphome/components/seeed_mr24hpc1/button/restart_button.h create mode 100644 esphome/components/seeed_mr24hpc1/number/__init__.py create mode 100644 esphome/components/seeed_mr24hpc1/number/custom_mode_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/custom_mode_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/existence_threshold_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/existence_threshold_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/motion_threshold_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/motion_threshold_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.h create mode 100644 esphome/components/seeed_mr24hpc1/number/sensitivity_number.cpp create mode 100644 esphome/components/seeed_mr24hpc1/number/sensitivity_number.h create mode 100644 esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp create mode 100644 esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h create mode 100644 esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h create mode 100644 esphome/components/seeed_mr24hpc1/select/__init__.py create mode 100644 esphome/components/seeed_mr24hpc1/select/existence_boundary_select.cpp create mode 100644 esphome/components/seeed_mr24hpc1/select/existence_boundary_select.h create mode 100644 esphome/components/seeed_mr24hpc1/select/motion_boundary_select.cpp create mode 100644 esphome/components/seeed_mr24hpc1/select/motion_boundary_select.h create mode 100644 esphome/components/seeed_mr24hpc1/select/scene_mode_select.cpp create mode 100644 esphome/components/seeed_mr24hpc1/select/scene_mode_select.h create mode 100644 esphome/components/seeed_mr24hpc1/select/unman_time_select.cpp create mode 100644 esphome/components/seeed_mr24hpc1/select/unman_time_select.h create mode 100644 esphome/components/seeed_mr24hpc1/sensor.py create mode 100644 esphome/components/seeed_mr24hpc1/switch/__init__.py create mode 100644 esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.cpp create mode 100644 esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h create mode 100644 esphome/components/seeed_mr24hpc1/text_sensor.py create mode 100644 tests/components/seeed_mr24hpc1/common.yaml create mode 100644 tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml create mode 100644 tests/components/seeed_mr24hpc1/test.esp32-c3.yaml diff --git a/CODEOWNERS b/CODEOWNERS index e31dd16077..64005b1a81 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -290,6 +290,7 @@ esphome/components/scd4x/* @martgras @sjtrny esphome/components/script/* @esphome/core esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdp3x/* @Azimath +esphome/components/seeed_mr24hpc1/* @limengdu esphome/components/selec_meter/* @sourabhjaiswal esphome/components/select/* @esphome/core esphome/components/sen0321/* @notjj diff --git a/esphome/components/seeed_mr24hpc1/__init__.py b/esphome/components/seeed_mr24hpc1/__init__.py new file mode 100644 index 0000000000..52b971e7e4 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/__init__.py @@ -0,0 +1,51 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import CONF_ID + +DEPENDENCIES = ["uart"] +# is the code owner of the relevant code base +CODEOWNERS = ["@limengdu"] +# The current component or platform can be configured or defined multiple times in the same configuration file. +MULTI_CONF = True + +# This line of code creates a new namespace called mr24hpc1_ns. +# This namespace will be used as a prefix for all classes, functions and variables associated with the mr24hpc1_ns component, ensuring that they do not conflict with the names of other components. +mr24hpc1_ns = cg.esphome_ns.namespace("seeed_mr24hpc1") +# This MR24HPC1Component class will be a periodically polled UART device +MR24HPC1Component = mr24hpc1_ns.class_( + "MR24HPC1Component", cg.Component, uart.UARTDevice +) + +CONF_MR24HPC1_ID = "mr24hpc1_id" + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MR24HPC1Component), + } + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + +# A verification mode was created to verify the configuration parameters of a UART device named "seeed_mr24hpc1". +# This authentication mode requires that the device must have transmit and receive functionality, a parity mode of "NONE", and a stop bit of one. +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "seeed_mr24hpc1", + require_tx=True, + require_rx=True, + parity="NONE", + stop_bits=1, +) + + +# The async def keyword is used to define a concurrent function. +# Concurrent functions are special functions designed to work with Python's asyncio library to support asynchronous I/O operations. +async def to_code(config): + # This line of code creates a new Pvariable (a Python object representing a C++ variable) with the variable's ID taken from the configuration. + var = cg.new_Pvariable(config[CONF_ID]) + # This line of code registers the newly created Pvariable as a component so that ESPHome can manage it at runtime. + await cg.register_component(var, config) + # This line of code registers the newly created Pvariable as a device. + await uart.register_uart_device(var, config) diff --git a/esphome/components/seeed_mr24hpc1/binary_sensor.py b/esphome/components/seeed_mr24hpc1/binary_sensor.py new file mode 100644 index 0000000000..e3e54d03f9 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/binary_sensor.py @@ -0,0 +1,23 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_OCCUPANCY, +) +from . import CONF_MR24HPC1_ID, MR24HPC1Component + +CONF_HAS_TARGET = "has_target" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_OCCUPANCY, icon="mdi:motion-sensor" + ), +} + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if has_target_config := config.get(CONF_HAS_TARGET): + sens = await binary_sensor.new_binary_sensor(has_target_config) + cg.add(mr24hpc1_component.set_has_target_binary_sensor(sens)) diff --git a/esphome/components/seeed_mr24hpc1/button/__init__.py b/esphome/components/seeed_mr24hpc1/button/__init__.py new file mode 100644 index 0000000000..0a0e7a1865 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/button/__init__.py @@ -0,0 +1,42 @@ +import esphome.codegen as cg +from esphome.components import button +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_RESTART, + ENTITY_CATEGORY_CONFIG, + ICON_RESTART_ALERT, +) +from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns + +RestartButton = mr24hpc1_ns.class_("RestartButton", button.Button) +CustomSetEndButton = mr24hpc1_ns.class_("CustomSetEndButton", button.Button) + +CONF_RESTART = "restart" +CONF_CUSTOM_SET_END = "custom_set_end" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_RESTART): button.button_schema( + RestartButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RESTART_ALERT, + ), + cv.Optional(CONF_CUSTOM_SET_END): button.button_schema( + CustomSetEndButton, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:cog", + ), +} + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if restart_config := config.get(CONF_RESTART): + b = await button.new_button(restart_config) + await cg.register_parented(b, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_restart_button(b)) + if custom_set_end_config := config.get(CONF_CUSTOM_SET_END): + b = await button.new_button(custom_set_end_config) + await cg.register_parented(b, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_custom_set_end_button(b)) diff --git a/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.cpp b/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.cpp new file mode 100644 index 0000000000..0ae8889247 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.cpp @@ -0,0 +1,9 @@ +#include "custom_mode_end_button.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void CustomSetEndButton::press_action() { this->parent_->set_custom_end_mode(); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.h b/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.h new file mode 100644 index 0000000000..a1701d8581 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/button/custom_mode_end_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class CustomSetEndButton : public button::Button, public Parented { + public: + CustomSetEndButton() = default; + + protected: + void press_action() override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/button/restart_button.cpp b/esphome/components/seeed_mr24hpc1/button/restart_button.cpp new file mode 100644 index 0000000000..6c4a070d1c --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/button/restart_button.cpp @@ -0,0 +1,9 @@ +#include "restart_button.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void RestartButton::press_action() { this->parent_->set_restart(); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/button/restart_button.h b/esphome/components/seeed_mr24hpc1/button/restart_button.h new file mode 100644 index 0000000000..8a2ec2087c --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/button/restart_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class RestartButton : public button::Button, public Parented { + public: + RestartButton() = default; + + protected: + void press_action() override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/__init__.py b/esphome/components/seeed_mr24hpc1/number/__init__.py new file mode 100644 index 0000000000..d9dfcb19a5 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/__init__.py @@ -0,0 +1,132 @@ +import esphome.codegen as cg +from esphome.components import number +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_CONFIG, +) +from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns + +SensitivityNumber = mr24hpc1_ns.class_("SensitivityNumber", number.Number) +CustomModeNumber = mr24hpc1_ns.class_("CustomModeNumber", number.Number) +ExistenceThresholdNumber = mr24hpc1_ns.class_("ExistenceThresholdNumber", number.Number) +MotionThresholdNumber = mr24hpc1_ns.class_("MotionThresholdNumber", number.Number) +MotionTriggerTimeNumber = mr24hpc1_ns.class_("MotionTriggerTimeNumber", number.Number) +MotionToRestTimeNumber = mr24hpc1_ns.class_("MotionToRestTimeNumber", number.Number) +CustomUnmanTimeNumber = mr24hpc1_ns.class_("CustomUnmanTimeNumber", number.Number) + +CONF_SENSITIVITY = "sensitivity" +CONF_CUSTOM_MODE = "custom_mode" +CONF_EXISTENCE_THRESHOLD = "existence_threshold" +CONF_MOTION_THRESHOLD = "motion_threshold" +CONF_MOTION_TRIGGER = "motion_trigger" +CONF_MOTION_TO_REST = "motion_to_rest" +CONF_CUSTOM_UNMAN_TIME = "custom_unman_time" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_SENSITIVITY): number.number_schema( + SensitivityNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:archive-check-outline", + ), + cv.Optional(CONF_CUSTOM_MODE): number.number_schema( + CustomModeNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:cog", + ), + cv.Optional(CONF_EXISTENCE_THRESHOLD): number.number_schema( + ExistenceThresholdNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_MOTION_THRESHOLD): number.number_schema( + MotionThresholdNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_MOTION_TRIGGER): number.number_schema( + MotionTriggerTimeNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:camera-timer", + unit_of_measurement="ms", + ), + cv.Optional(CONF_MOTION_TO_REST): number.number_schema( + MotionToRestTimeNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:camera-timer", + unit_of_measurement="ms", + ), + cv.Optional(CONF_CUSTOM_UNMAN_TIME): number.number_schema( + CustomUnmanTimeNumber, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:camera-timer", + unit_of_measurement="s", + ), + } +) + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if sensitivity_config := config.get(CONF_SENSITIVITY): + n = await number.new_number( + sensitivity_config, + min_value=0, + max_value=3, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_sensitivity_number(n)) + if custom_mode_config := config.get(CONF_CUSTOM_MODE): + n = await number.new_number( + custom_mode_config, + min_value=0, + max_value=4, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_custom_mode_number(n)) + if existence_threshold_config := config.get(CONF_EXISTENCE_THRESHOLD): + n = await number.new_number( + existence_threshold_config, + min_value=0, + max_value=250, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_existence_threshold_number(n)) + if motion_threshold_config := config.get(CONF_MOTION_THRESHOLD): + n = await number.new_number( + motion_threshold_config, + min_value=0, + max_value=250, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_motion_threshold_number(n)) + if motion_trigger_config := config.get(CONF_MOTION_TRIGGER): + n = await number.new_number( + motion_trigger_config, + min_value=0, + max_value=150, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_motion_trigger_number(n)) + if motion_to_rest_config := config.get(CONF_MOTION_TO_REST): + n = await number.new_number( + motion_to_rest_config, + min_value=0, + max_value=3000, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_motion_to_rest_number(n)) + if custom_unman_time_config := config.get(CONF_CUSTOM_UNMAN_TIME): + n = await number.new_number( + custom_unman_time_config, + min_value=0, + max_value=3600, + step=1, + ) + await cg.register_parented(n, mr24hpc1_component) + cg.add(mr24hpc1_component.set_custom_unman_time_number(n)) diff --git a/esphome/components/seeed_mr24hpc1/number/custom_mode_number.cpp b/esphome/components/seeed_mr24hpc1/number/custom_mode_number.cpp new file mode 100644 index 0000000000..0aebd8fb9f --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/custom_mode_number.cpp @@ -0,0 +1,12 @@ +#include "custom_mode_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void CustomModeNumber::control(float value) { + this->publish_state(value); + this->parent_->set_custom_mode(value); +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/custom_mode_number.h b/esphome/components/seeed_mr24hpc1/number/custom_mode_number.h new file mode 100644 index 0000000000..40ff3f201a --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/custom_mode_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class CustomModeNumber : public number::Number, public Parented { + public: + CustomModeNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.cpp b/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.cpp new file mode 100644 index 0000000000..12a8ff69fa --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.cpp @@ -0,0 +1,9 @@ +#include "custom_unman_time_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void CustomUnmanTimeNumber::control(float value) { this->parent_->set_custom_unman_time(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.h b/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.h new file mode 100644 index 0000000000..6b871c4c13 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/custom_unman_time_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class CustomUnmanTimeNumber : public number::Number, public Parented { + public: + CustomUnmanTimeNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.cpp b/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.cpp new file mode 100644 index 0000000000..58ef56509e --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.cpp @@ -0,0 +1,9 @@ +#include "existence_threshold_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void ExistenceThresholdNumber::control(float value) { this->parent_->set_existence_threshold(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.h b/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.h new file mode 100644 index 0000000000..656bad17de --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/existence_threshold_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class ExistenceThresholdNumber : public number::Number, public Parented { + public: + ExistenceThresholdNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.cpp b/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.cpp new file mode 100644 index 0000000000..d252b4f01d --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.cpp @@ -0,0 +1,9 @@ +#include "motion_threshold_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void MotionThresholdNumber::control(float value) { this->parent_->set_motion_threshold(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.h b/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.h new file mode 100644 index 0000000000..e8ae37b96f --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motion_threshold_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class MotionThresholdNumber : public number::Number, public Parented { + public: + MotionThresholdNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.cpp b/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.cpp new file mode 100644 index 0000000000..fc7659dc54 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.cpp @@ -0,0 +1,9 @@ +#include "motion_trigger_time_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void MotionTriggerTimeNumber::control(float value) { this->parent_->set_motion_trigger_time(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.h b/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.h new file mode 100644 index 0000000000..996356e237 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motion_trigger_time_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class MotionTriggerTimeNumber : public number::Number, public Parented { + public: + MotionTriggerTimeNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.cpp b/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.cpp new file mode 100644 index 0000000000..f598e6686c --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.cpp @@ -0,0 +1,9 @@ +#include "motiontorest_time_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void MotionToRestTimeNumber::control(float value) { this->parent_->set_motion_to_rest_time(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.h b/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.h new file mode 100644 index 0000000000..559d23fdeb --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/motiontorest_time_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class MotionToRestTimeNumber : public number::Number, public Parented { + public: + MotionToRestTimeNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/sensitivity_number.cpp b/esphome/components/seeed_mr24hpc1/number/sensitivity_number.cpp new file mode 100644 index 0000000000..d903dfd818 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/sensitivity_number.cpp @@ -0,0 +1,9 @@ +#include "sensitivity_number.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void SensitivityNumber::control(float value) { this->parent_->set_sensitivity(value); } + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/number/sensitivity_number.h b/esphome/components/seeed_mr24hpc1/number/sensitivity_number.h new file mode 100644 index 0000000000..fee33521d0 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/number/sensitivity_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class SensitivityNumber : public number::Number, public Parented { + public: + SensitivityNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp new file mode 100644 index 0000000000..1cf9bd300a --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp @@ -0,0 +1,890 @@ +#include "seeed_mr24hpc1.h" + +#include "esphome/core/log.h" + +#include + +namespace esphome { +namespace seeed_mr24hpc1 { + +static const char *const TAG = "seeed_mr24hpc1"; + +// Prints the component's configuration data. dump_config() prints all of the component's configuration +// items in an easy-to-read format, including the configuration key-value pairs. +void MR24HPC1Component::dump_config() { + ESP_LOGCONFIG(TAG, "MR24HPC1:"); +#ifdef USE_TEXT_SENSOR + LOG_TEXT_SENSOR(" ", "Heartbeat Text Sensor", this->heartbeat_state_text_sensor_); + LOG_TEXT_SENSOR(" ", "Product Model Text Sensor", this->product_model_text_sensor_); + LOG_TEXT_SENSOR(" ", "Product ID Text Sensor", this->product_id_text_sensor_); + LOG_TEXT_SENSOR(" ", "Hardware Model Text Sensor", this->hardware_model_text_sensor_); + LOG_TEXT_SENSOR(" ", "Firware Verison Text Sensor", this->firware_version_text_sensor_); + LOG_TEXT_SENSOR(" ", "Keep Away Text Sensor", this->keep_away_text_sensor_); + LOG_TEXT_SENSOR(" ", "Motion Status Text Sensor", this->motion_status_text_sensor_); + LOG_TEXT_SENSOR(" ", "Custom Mode End Text Sensor", this->custom_mode_end_text_sensor_); +#endif +#ifdef USE_BINARY_SENSOR + LOG_BINARY_SENSOR(" ", "Has Target Binary Sensor", this->has_target_binary_sensor_); +#endif +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Custom Presence Of Detection Sensor", this->custom_presence_of_detection_sensor_); + LOG_SENSOR(" ", "Movement Signs Sensor", this->movement_signs_sensor_); + LOG_SENSOR(" ", "Custom Motion Distance Sensor", this->custom_motion_distance_sensor_); + LOG_SENSOR(" ", "Custom Spatial Static Sensor", this->custom_spatial_static_value_sensor_); + LOG_SENSOR(" ", "Custom Spatial Motion Sensor", this->custom_spatial_motion_value_sensor_); + LOG_SENSOR(" ", "Custom Motion Speed Sensor", this->custom_motion_speed_sensor_); + LOG_SENSOR(" ", "Custom Mode Num Sensor", this->custom_mode_num_sensor_); +#endif +#ifdef USE_SWITCH + LOG_SWITCH(" ", "Underly Open Function Switch", this->underlying_open_function_switch_); +#endif +#ifdef USE_BUTTON + LOG_BUTTON(" ", "Restart Button", this->restart_button_); + LOG_BUTTON(" ", "Custom Set End Button", this->custom_set_end_button_); +#endif +#ifdef USE_SELECT + LOG_SELECT(" ", "Scene Mode Select", this->scene_mode_select_); + LOG_SELECT(" ", "Unman Time Select", this->unman_time_select_); + LOG_SELECT(" ", "Existence Boundary Select", this->existence_boundary_select_); + LOG_SELECT(" ", "Motion Boundary Select", this->motion_boundary_select_); +#endif +#ifdef USE_NUMBER + LOG_NUMBER(" ", "Sensitivity Number", this->sensitivity_number_); + LOG_NUMBER(" ", "Custom Mode Number", this->custom_mode_number_); + LOG_NUMBER(" ", "Existence Threshold Number", this->existence_threshold_number_); + LOG_NUMBER(" ", "Motion Threshold Number", this->motion_threshold_number_); + LOG_NUMBER(" ", "Motion Trigger Time Number", this->motion_trigger_number_); + LOG_NUMBER(" ", "Motion To Rest Time Number", this->motion_to_rest_number_); + LOG_NUMBER(" ", "Custom Unman Time Number", this->custom_unman_time_number_); +#endif +} + +// Initialisation functions +void MR24HPC1Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up MR24HPC1..."); + this->check_uart_settings(115200); + + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); // Zero out the custom mode + } + if (this->custom_mode_num_sensor_ != nullptr) { + this->custom_mode_num_sensor_->publish_state(0); + } + if (this->custom_mode_end_text_sensor_ != nullptr) { + this->custom_mode_end_text_sensor_->publish_state("Not in custom mode"); + } + this->set_custom_end_mode(); + this->poll_time_base_func_check_ = true; + this->check_dev_inf_sign_ = true; + this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE; + this->sg_data_len_ = 0; + this->sg_frame_len_ = 0; + this->sg_recv_data_state_ = FRAME_IDLE; + this->s_output_info_switch_flag_ = OUTPUT_SWITCH_INIT; + + memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE); + memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE); + memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE); + memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE); + memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE); + memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE); + + this->set_interval(8000, [this]() { this->update_(); }); + ESP_LOGCONFIG(TAG, "Set up MR24HPC1 complete"); +} + +// Timed polling of radar data +void MR24HPC1Component::update_() { + this->get_radar_output_information_switch(); // Query the key status every so often + this->poll_time_base_func_check_ = true; // Query the base functionality information at regular intervals +} + +// main loop +void MR24HPC1Component::loop() { + uint8_t byte; + + // Is there data on the serial port + while (this->available()) { + this->read_byte(&byte); + this->r24_split_data_frame_(byte); // split data frame + } + + if ((this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) && + (this->sg_start_query_data_ > CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED) && (!this->check_dev_inf_sign_)) { + this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_SCENE_MODE; + } else if ((this->s_output_info_switch_flag_ == OUTPUT_SWITCH_ON) && + (this->sg_start_query_data_ < CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY) && (!this->check_dev_inf_sign_)) { + this->sg_start_query_data_ = CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY; + } else if (this->check_dev_inf_sign_ && (this->sg_start_query_data_ > STANDARD_FUNCTION_QUERY_HARDWARE_MODE)) { + // First time power up information polling + this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE; + } + + // Polling Functions + if (this->poll_time_base_func_check_) { + switch (this->sg_start_query_data_) { + case STANDARD_FUNCTION_QUERY_PRODUCT_MODE: + this->get_product_mode(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_PRODUCT_ID: + this->get_product_id(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_FIRMWARE_VERSION: + this->get_product_mode(); + this->get_product_id(); + this->get_firmware_version(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_HARDWARE_MODE: // Above is the equipment information + this->get_product_mode(); + this->get_product_id(); + this->get_hardware_model(); + this->sg_start_query_data_++; + this->check_dev_inf_sign_ = false; + break; + case STANDARD_FUNCTION_QUERY_SCENE_MODE: + this->get_scene_mode(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_SENSITIVITY: + this->get_sensitivity(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_UNMANNED_TIME: + this->get_unmanned_time(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_HUMAN_STATUS: + this->get_human_status(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_HUMAN_MOTION_INF: + this->get_human_motion_info(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_BODY_MOVE_PARAMETER: + this->get_body_motion_params(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS: // The above is the basic functional information + this->get_keep_away(); + this->sg_start_query_data_++; + break; + case STANDARD_QUERY_CUSTOM_MODE: + this->get_custom_mode(); + this->sg_start_query_data_++; + break; + case STANDARD_FUNCTION_QUERY_HEARTBEAT_STATE: + this->get_heartbeat_packet(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY: + this->get_existence_boundary(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_MOTION_BOUNDARY: + this->get_motion_boundary(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_EXISTENCE_THRESHOLD: + this->get_existence_threshold(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_MOTION_THRESHOLD: + this->get_motion_threshold(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_MOTION_TRIGGER_TIME: + this->get_motion_trigger_time(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_MOTION_TO_REST_TIME: + this->get_motion_to_rest_time(); + this->sg_start_query_data_++; + break; + case CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED: + this->get_custom_unman_time(); + this->sg_start_query_data_++; + if (this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) { + this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam + } + break; + case UNDERLY_FUNCTION_QUERY_HUMAN_STATUS: + this->get_human_status(); + this->sg_start_query_data_++; + break; + case UNDERLY_FUNCTION_QUERY_SPATIAL_STATIC_VALUE: + this->get_spatial_static_value(); + this->sg_start_query_data_++; + break; + case UNDERLY_FUNCTION_QUERY_SPATIAL_MOTION_VALUE: + this->get_spatial_motion_value(); + this->sg_start_query_data_++; + break; + case UNDERLY_FUNCTION_QUERY_DISTANCE_OF_STATIC_OBJECT: + this->get_distance_of_static_object(); + this->sg_start_query_data_++; + break; + case UNDERLY_FUNCTION_QUERY_DISTANCE_OF_MOVING_OBJECT: + this->get_distance_of_moving_object(); + this->sg_start_query_data_++; + break; + case UNDERLY_FUNCTION_QUERY_TARGET_MOVEMENT_SPEED: + this->get_target_movement_speed(); + this->sg_start_query_data_++; + this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam + break; + default: + break; + } + } +} + +// Calculate CRC check digit +static uint8_t get_frame_crc_sum(const uint8_t *data, int len) { + unsigned int crc_sum = 0; + for (int i = 0; i < len - 3; i++) { + crc_sum += data[i]; + } + return crc_sum & 0xff; +} + +// Check that the check digit is correct +static int get_frame_check_status(uint8_t *data, int len) { + uint8_t crc_sum = get_frame_crc_sum(data, len); + uint8_t verified = data[len - 3]; + return (verified == crc_sum) ? 1 : 0; +} + +// split data frame +void MR24HPC1Component::r24_split_data_frame_(uint8_t value) { + switch (this->sg_recv_data_state_) { + case FRAME_IDLE: // starting value + if (FRAME_HEADER1_VALUE == value) { + this->sg_recv_data_state_ = FRAME_HEADER2; + } + break; + case FRAME_HEADER2: + if (FRAME_HEADER2_VALUE == value) { + this->sg_frame_buf_[0] = FRAME_HEADER1_VALUE; + this->sg_frame_buf_[1] = FRAME_HEADER2_VALUE; + this->sg_recv_data_state_ = FRAME_CTL_WORD; + } else { + this->sg_recv_data_state_ = FRAME_IDLE; + ESP_LOGD(TAG, "FRAME_IDLE ERROR value:%x", value); + } + break; + case FRAME_CTL_WORD: + this->sg_frame_buf_[2] = value; + this->sg_recv_data_state_ = FRAME_CMD_WORD; + break; + case FRAME_CMD_WORD: + this->sg_frame_buf_[3] = value; + this->sg_recv_data_state_ = FRAME_DATA_LEN_H; + break; + case FRAME_DATA_LEN_H: + if (value <= 4) { + this->sg_data_len_ = value * 256; + this->sg_frame_buf_[4] = value; + this->sg_recv_data_state_ = FRAME_DATA_LEN_L; + } else { + this->sg_data_len_ = 0; + this->sg_recv_data_state_ = FRAME_IDLE; + ESP_LOGD(TAG, "FRAME_DATA_LEN_H ERROR value:%x", value); + } + break; + case FRAME_DATA_LEN_L: + this->sg_data_len_ += value; + if (this->sg_data_len_ > 32) { + ESP_LOGD(TAG, "len=%d, FRAME_DATA_LEN_L ERROR value:%x", this->sg_data_len_, value); + this->sg_data_len_ = 0; + this->sg_recv_data_state_ = FRAME_IDLE; + } else { + this->sg_frame_buf_[5] = value; + this->sg_frame_len_ = 6; + this->sg_recv_data_state_ = FRAME_DATA_BYTES; + } + break; + case FRAME_DATA_BYTES: + this->sg_data_len_ -= 1; + this->sg_frame_buf_[this->sg_frame_len_++] = value; + if (this->sg_data_len_ <= 0) { + this->sg_recv_data_state_ = FRAME_DATA_CRC; + } + break; + case FRAME_DATA_CRC: + this->sg_frame_buf_[this->sg_frame_len_++] = value; + this->sg_recv_data_state_ = FRAME_TAIL1; + break; + case FRAME_TAIL1: + if (FRAME_TAIL1_VALUE == value) { + this->sg_recv_data_state_ = FRAME_TAIL2; + } else { + this->sg_recv_data_state_ = FRAME_IDLE; + this->sg_frame_len_ = 0; + this->sg_data_len_ = 0; + ESP_LOGD(TAG, "FRAME_TAIL1 ERROR value:%x", value); + } + break; + case FRAME_TAIL2: + if (FRAME_TAIL2_VALUE == value) { + this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL1_VALUE; + this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL2_VALUE; + memcpy(this->sg_frame_prase_buf_, this->sg_frame_buf_, this->sg_frame_len_); + if (get_frame_check_status(this->sg_frame_prase_buf_, this->sg_frame_len_)) { + this->r24_parse_data_frame_(this->sg_frame_prase_buf_, this->sg_frame_len_); + } else { + ESP_LOGD(TAG, "frame check failer!"); + } + } else { + ESP_LOGD(TAG, "FRAME_TAIL2 ERROR value:%x", value); + } + memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE); + memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE); + this->sg_frame_len_ = 0; + this->sg_data_len_ = 0; + this->sg_recv_data_state_ = FRAME_IDLE; + break; + default: + this->sg_recv_data_state_ = FRAME_IDLE; + } +} + +// Parses data frames related to product information +void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) { + uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]); + if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) { + if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { + memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE); + memcpy(this->c_product_mode_, &data[FRAME_DATA_INDEX], product_len); + this->product_model_text_sensor_->publish_state(this->c_product_mode_); + } else { + ESP_LOGD(TAG, "Reply: get product_mode error!"); + } + } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_ID) { + if ((this->product_id_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { + memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE); + memcpy(this->c_product_id_, &data[FRAME_DATA_INDEX], product_len); + this->product_id_text_sensor_->publish_state(this->c_product_id_); + } else { + ESP_LOGD(TAG, "Reply: get productId error!"); + } + } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_HARDWARE_MODEL) { + if ((this->hardware_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { + memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE); + memcpy(this->c_hardware_model_, &data[FRAME_DATA_INDEX], product_len); + this->hardware_model_text_sensor_->publish_state(this->c_hardware_model_); + ESP_LOGD(TAG, "Reply: get hardware_model :%s", this->c_hardware_model_); + } else { + ESP_LOGD(TAG, "Reply: get hardwareModel error!"); + } + } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_FIRMWARE_VERSION) { + if ((this->firware_version_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { + memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE); + memcpy(this->c_firmware_version_, &data[FRAME_DATA_INDEX], product_len); + this->firware_version_text_sensor_->publish_state(this->c_firmware_version_); + } else { + ESP_LOGD(TAG, "Reply: get firmwareVersion error!"); + } + } +} + +// Parsing the underlying open parameters +void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) { + if (data[FRAME_COMMAND_WORD_INDEX] == 0x00) { + if (this->underlying_open_function_switch_ != nullptr) { + this->underlying_open_function_switch_->publish_state( + data[FRAME_DATA_INDEX]); // Underlying Open Parameter Switch Status Updates + } + if (data[FRAME_DATA_INDEX]) { + this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON; + } else { + this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF; + } + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) { + if (this->custom_spatial_static_value_sensor_ != nullptr) { + this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } + if (this->custom_presence_of_detection_sensor_ != nullptr) { + this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f); + } + if (this->custom_spatial_motion_value_sensor_ != nullptr) { + this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]); + } + if (this->custom_motion_distance_sensor_ != nullptr) { + this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f); + } + if (this->custom_motion_speed_sensor_ != nullptr) { + this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f); + } + } else if ((data[FRAME_COMMAND_WORD_INDEX] == 0x06) || (data[FRAME_COMMAND_WORD_INDEX] == 0x86)) { + // none:0x00 close_to:0x01 far_away:0x02 + if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) { + this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]); + } + } else if ((this->movement_signs_sensor_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x07) || (data[FRAME_COMMAND_WORD_INDEX] == 0x87))) { + this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->existence_threshold_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) { + this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->motion_threshold_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x09) || (data[FRAME_COMMAND_WORD_INDEX] == 0x89))) { + this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->existence_boundary_select_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0a) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8a))) { + if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) { + this->existence_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]); + } + } else if ((this->motion_boundary_select_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0b) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8b))) { + if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) { + this->motion_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]); + } + } else if ((this->motion_trigger_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0c) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8c))) { + uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], + data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); + this->motion_trigger_number_->publish_state(motion_trigger_time); + } else if ((this->motion_to_rest_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0d) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8d))) { + uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], + data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); + this->motion_to_rest_number_->publish_state(move_to_rest_time); + } else if ((this->custom_unman_time_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0e) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8e))) { + uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], + data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); + float custom_unmanned_time = enter_unmanned_time / 1000.0; + this->custom_unman_time_number_->publish_state(custom_unmanned_time); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x80) { + if (data[FRAME_DATA_INDEX]) { + this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON; + } else { + this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF; + } + if (this->underlying_open_function_switch_ != nullptr) { + this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]); + } + } else if ((this->custom_spatial_static_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x81)) { + this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->custom_spatial_motion_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x82)) { + this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->custom_presence_of_detection_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x83)) { + this->custom_presence_of_detection_sensor_->publish_state( + S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]); + } else if ((this->custom_motion_distance_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x84)) { + this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f); + } else if ((this->custom_motion_speed_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x85)) { + this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f); + } +} + +void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) { + switch (data[FRAME_CONTROL_WORD_INDEX]) { + case 0x01: { + if ((this->heartbeat_state_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x01)) { + this->heartbeat_state_text_sensor_->publish_state("Equipment Normal"); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) { + ESP_LOGD(TAG, "Reply: query restart packet"); + } else if (this->heartbeat_state_text_sensor_ != nullptr) { + this->heartbeat_state_text_sensor_->publish_state("Equipment Abnormal"); + } + } break; + case 0x02: { + this->r24_frame_parse_product_information_(data); + } break; + case 0x05: { + this->r24_frame_parse_work_status_(data); + } break; + case 0x08: { + this->r24_frame_parse_open_underlying_information_(data); + } break; + case 0x80: { + this->r24_frame_parse_human_information_(data); + } break; + default: + ESP_LOGD(TAG, "control word:0x%02X not found", data[FRAME_CONTROL_WORD_INDEX]); + break; + } +} + +void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) { + if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) { + ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x07) { + if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) { + this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]); + } else { + ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]); + } + } else if ((this->sensitivity_number_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) { + // 1-3 + this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x09) { + // 1-4 + if (this->custom_mode_num_sensor_ != nullptr) { + this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); + } + if (this->custom_mode_end_text_sensor_ != nullptr) { + this->custom_mode_end_text_sensor_->publish_state("Setup in progress..."); + } + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x81) { + ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x87) { + if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) { + this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]); + } else { + ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]); + } + } else if ((this->custom_mode_end_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x0A)) { + this->custom_mode_end_text_sensor_->publish_state("Set Success!"); + } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x89) { + if (data[FRAME_DATA_INDEX] == 0) { + if (this->custom_mode_end_text_sensor_ != nullptr) { + this->custom_mode_end_text_sensor_->publish_state("Not in custom mode"); + } + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); + } + if (this->custom_mode_num_sensor_ != nullptr) { + this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } + } else { + if (this->custom_mode_num_sensor_ != nullptr) { + this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } + } + } else { + ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]); + } +} + +void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) { + if ((this->has_target_binary_sensor_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x01) || (data[FRAME_COMMAND_WORD_INDEX] == 0x81))) { + this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]); + } else if ((this->motion_status_text_sensor_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x02) || (data[FRAME_COMMAND_WORD_INDEX] == 0x82))) { + if (data[FRAME_DATA_INDEX] < 3) { + this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]); + } + } else if ((this->movement_signs_sensor_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x03) || (data[FRAME_COMMAND_WORD_INDEX] == 0x83))) { + this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]); + } else if ((this->unman_time_select_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0A) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8A))) { + // none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08 + if (data[FRAME_DATA_INDEX] < 9) { + this->unman_time_select_->publish_state(S_UNMANNED_TIME_STR[data[FRAME_DATA_INDEX]]); + } + } else if ((this->keep_away_text_sensor_ != nullptr) && + ((data[FRAME_COMMAND_WORD_INDEX] == 0x0B) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8B))) { + // none:0x00 close_to:0x01 far_away:0x02 + if (data[FRAME_DATA_INDEX] < 3) { + this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]); + } + } else { + ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]); + } +} + +// Sending data frames +void MR24HPC1Component::send_query_(const uint8_t *query, size_t string_length) { + this->write_array(query, string_length); +} + +// Send Heartbeat Packet Command +void MR24HPC1Component::get_heartbeat_packet() { this->send_query_(GET_HEARTBEAT, sizeof(GET_HEARTBEAT)); } + +// Issuance of the underlying open parameter query command +void MR24HPC1Component::get_radar_output_information_switch() { + this->send_query_(GET_RADAR_OUTPUT_INFORMATION_SWITCH, sizeof(GET_RADAR_OUTPUT_INFORMATION_SWITCH)); +} + +// Issuance of product model orders +void MR24HPC1Component::get_product_mode() { this->send_query_(GET_PRODUCT_MODE, sizeof(GET_PRODUCT_MODE)); } + +// Issuing the Get Product ID command +void MR24HPC1Component::get_product_id() { this->send_query_(GET_PRODUCT_ID, sizeof(GET_PRODUCT_ID)); } + +// Issuing hardware model commands +void MR24HPC1Component::get_hardware_model() { this->send_query_(GET_HARDWARE_MODEL, sizeof(GET_HARDWARE_MODEL)); } + +// Issuing software version commands +void MR24HPC1Component::get_firmware_version() { + this->send_query_(GET_FIRMWARE_VERSION, sizeof(GET_FIRMWARE_VERSION)); +} + +void MR24HPC1Component::get_human_status() { this->send_query_(GET_HUMAN_STATUS, sizeof(GET_HUMAN_STATUS)); } + +void MR24HPC1Component::get_human_motion_info() { + this->send_query_(GET_HUMAN_MOTION_INFORMATION, sizeof(GET_HUMAN_MOTION_INFORMATION)); +} + +void MR24HPC1Component::get_body_motion_params() { + this->send_query_(GET_BODY_MOTION_PARAMETERS, sizeof(GET_BODY_MOTION_PARAMETERS)); +} + +void MR24HPC1Component::get_keep_away() { this->send_query_(GET_KEEP_AWAY, sizeof(GET_KEEP_AWAY)); } + +void MR24HPC1Component::get_scene_mode() { this->send_query_(GET_SCENE_MODE, sizeof(GET_SCENE_MODE)); } + +void MR24HPC1Component::get_sensitivity() { this->send_query_(GET_SENSITIVITY, sizeof(GET_SENSITIVITY)); } + +void MR24HPC1Component::get_unmanned_time() { this->send_query_(GET_UNMANNED_TIME, sizeof(GET_UNMANNED_TIME)); } + +void MR24HPC1Component::get_custom_mode() { this->send_query_(GET_CUSTOM_MODE, sizeof(GET_CUSTOM_MODE)); } + +void MR24HPC1Component::get_existence_boundary() { + this->send_query_(GET_EXISTENCE_BOUNDARY, sizeof(GET_EXISTENCE_BOUNDARY)); +} + +void MR24HPC1Component::get_motion_boundary() { this->send_query_(GET_MOTION_BOUNDARY, sizeof(GET_MOTION_BOUNDARY)); } + +void MR24HPC1Component::get_spatial_static_value() { + this->send_query_(GET_SPATIAL_STATIC_VALUE, sizeof(GET_SPATIAL_STATIC_VALUE)); +} + +void MR24HPC1Component::get_spatial_motion_value() { + this->send_query_(GET_SPATIAL_MOTION_VALUE, sizeof(GET_SPATIAL_MOTION_VALUE)); +} + +void MR24HPC1Component::get_distance_of_static_object() { + this->send_query_(GET_DISTANCE_OF_STATIC_OBJECT, sizeof(GET_DISTANCE_OF_STATIC_OBJECT)); +} + +void MR24HPC1Component::get_distance_of_moving_object() { + this->send_query_(GET_DISTANCE_OF_MOVING_OBJECT, sizeof(GET_DISTANCE_OF_MOVING_OBJECT)); +} + +void MR24HPC1Component::get_target_movement_speed() { + this->send_query_(GET_TARGET_MOVEMENT_SPEED, sizeof(GET_TARGET_MOVEMENT_SPEED)); +} + +void MR24HPC1Component::get_existence_threshold() { + this->send_query_(GET_EXISTENCE_THRESHOLD, sizeof(GET_EXISTENCE_THRESHOLD)); +} + +void MR24HPC1Component::get_motion_threshold() { + this->send_query_(GET_MOTION_THRESHOLD, sizeof(GET_MOTION_THRESHOLD)); +} + +void MR24HPC1Component::get_motion_trigger_time() { + this->send_query_(GET_MOTION_TRIGGER_TIME, sizeof(GET_MOTION_TRIGGER_TIME)); +} + +void MR24HPC1Component::get_motion_to_rest_time() { + this->send_query_(GET_MOTION_TO_REST_TIME, sizeof(GET_MOTION_TO_REST_TIME)); +} + +void MR24HPC1Component::get_custom_unman_time() { + this->send_query_(GET_CUSTOM_UNMAN_TIME, sizeof(GET_CUSTOM_UNMAN_TIME)); +} + +// Logic of setting: After setting, query whether the setting is successful or not! + +void MR24HPC1Component::set_underlying_open_function(bool enable) { + if (enable) { + this->send_query_(UNDERLYING_SWITCH_ON, sizeof(UNDERLYING_SWITCH_ON)); + } else { + this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF)); + } + if (this->keep_away_text_sensor_ != nullptr) { + this->keep_away_text_sensor_->publish_state(""); + } + if (this->motion_status_text_sensor_ != nullptr) { + this->motion_status_text_sensor_->publish_state(""); + } + if (this->custom_spatial_static_value_sensor_ != nullptr) { + this->custom_spatial_static_value_sensor_->publish_state(NAN); + } + if (this->custom_spatial_motion_value_sensor_ != nullptr) { + this->custom_spatial_motion_value_sensor_->publish_state(NAN); + } + if (this->custom_motion_distance_sensor_ != nullptr) { + this->custom_motion_distance_sensor_->publish_state(NAN); + } + if (this->custom_presence_of_detection_sensor_ != nullptr) { + this->custom_presence_of_detection_sensor_->publish_state(NAN); + } + if (this->custom_motion_speed_sensor_ != nullptr) { + this->custom_motion_speed_sensor_->publish_state(NAN); + } +} + +void MR24HPC1Component::set_scene_mode(uint8_t value) { + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); + } + if (this->custom_mode_num_sensor_ != nullptr) { + this->custom_mode_num_sensor_->publish_state(0); + } + this->get_scene_mode(); + this->get_sensitivity(); + this->get_custom_mode(); + this->get_existence_boundary(); + this->get_motion_boundary(); + this->get_existence_threshold(); + this->get_motion_threshold(); + this->get_motion_trigger_time(); + this->get_motion_to_rest_time(); + this->get_custom_unman_time(); +} + +void MR24HPC1Component::set_sensitivity(uint8_t value) { + if (value == 0x00) + return; + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_scene_mode(); + this->get_sensitivity(); +} + +void MR24HPC1Component::set_restart() { + this->send_query_(SET_RESTART, sizeof(SET_RESTART)); + this->check_dev_inf_sign_ = true; +} + +void MR24HPC1Component::set_unman_time(uint8_t value) { + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x80, 0x0a, 0x00, 0x01, value, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_unmanned_time(); +} + +void MR24HPC1Component::set_custom_mode(uint8_t mode) { + if (mode == 0) { + this->set_custom_end_mode(); // Equivalent to end setting + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); + } + return; + } + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x09, 0x00, 0x01, mode, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_existence_boundary(); + this->get_motion_boundary(); + this->get_existence_threshold(); + this->get_motion_threshold(); + this->get_motion_trigger_time(); + this->get_motion_to_rest_time(); + this->get_custom_unman_time(); + this->get_custom_mode(); + this->get_scene_mode(); + this->get_sensitivity(); +} + +void MR24HPC1Component::set_custom_end_mode() { + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43}; + this->send_query_(send_data, send_data_len); + if (this->custom_mode_number_ != nullptr) { + this->custom_mode_number_->publish_state(0); // Clear setpoints + } + this->get_existence_boundary(); + this->get_motion_boundary(); + this->get_existence_threshold(); + this->get_motion_threshold(); + this->get_motion_trigger_time(); + this->get_motion_to_rest_time(); + this->get_custom_unman_time(); + this->get_custom_mode(); + this->get_scene_mode(); + this->get_sensitivity(); +} + +void MR24HPC1Component::set_existence_boundary(uint8_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_existence_boundary(); +} + +void MR24HPC1Component::set_motion_boundary(uint8_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_motion_boundary(); +} + +void MR24HPC1Component::set_existence_threshold(uint8_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_existence_threshold(); +} + +void MR24HPC1Component::set_motion_threshold(uint8_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t send_data_len = 10; + uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43}; + send_data[7] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_motion_threshold(); +} + +void MR24HPC1Component::set_motion_trigger_time(uint8_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t send_data_len = 13; + uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43}; + send_data[10] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_motion_trigger_time(); +} + +void MR24HPC1Component::set_motion_to_rest_time(uint16_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint8_t h8_num = (value >> 8) & 0xff; + uint8_t l8_num = value & 0xff; + uint8_t send_data_len = 13; + uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0D, 0x00, 0x04, 0x00, 0x00, h8_num, l8_num, 0x00, 0x54, 0x43}; + send_data[10] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_motion_to_rest_time(); +} + +void MR24HPC1Component::set_custom_unman_time(uint16_t value) { + if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) + return; // You'll have to check that you're in custom mode to set it up + uint32_t value_ms = value * 1000; + uint8_t h24_num = (value_ms >> 24) & 0xff; + uint8_t h16_num = (value_ms >> 16) & 0xff; + uint8_t h8_num = (value_ms >> 8) & 0xff; + uint8_t l8_num = value_ms & 0xff; + uint8_t send_data_len = 13; + uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0E, 0x00, 0x04, h24_num, h16_num, h8_num, l8_num, 0x00, 0x54, 0x43}; + send_data[10] = get_frame_crc_sum(send_data, send_data_len); + this->send_query_(send_data, send_data_len); + this->get_custom_unman_time(); +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h new file mode 100644 index 0000000000..8fc61ad37c --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h @@ -0,0 +1,217 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_NUMBER +#include "esphome/components/number/number.h" +#endif +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif +#ifdef USE_BUTTON +#include "esphome/components/button/button.h" +#endif +#ifdef USE_SELECT +#include "esphome/components/select/select.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif +#include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" + +#include "seeed_mr24hpc1_constants.h" + +#include + +namespace esphome { +namespace seeed_mr24hpc1 { + +enum FrameState { + FRAME_IDLE, + FRAME_HEADER2, + FRAME_CTL_WORD, + FRAME_CMD_WORD, + FRAME_DATA_LEN_H, + FRAME_DATA_LEN_L, + FRAME_DATA_BYTES, + FRAME_DATA_CRC, + FRAME_TAIL1, + FRAME_TAIL2, +}; + +enum PollingState { + STANDARD_FUNCTION_QUERY_PRODUCT_MODE = 0, + STANDARD_FUNCTION_QUERY_PRODUCT_ID, + STANDARD_FUNCTION_QUERY_FIRMWARE_VERSION, + STANDARD_FUNCTION_QUERY_HARDWARE_MODE, // Above is the equipment information + STANDARD_FUNCTION_QUERY_SCENE_MODE, + STANDARD_FUNCTION_QUERY_SENSITIVITY, + STANDARD_FUNCTION_QUERY_UNMANNED_TIME, + STANDARD_FUNCTION_QUERY_HUMAN_STATUS, + STANDARD_FUNCTION_QUERY_HUMAN_MOTION_INF, + STANDARD_FUNCTION_QUERY_BODY_MOVE_PARAMETER, + STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS, + STANDARD_QUERY_CUSTOM_MODE, + STANDARD_FUNCTION_QUERY_HEARTBEAT_STATE, // Above is the basic function + + CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY, + CUSTOM_FUNCTION_QUERY_MOTION_BOUNDARY, + CUSTOM_FUNCTION_QUERY_EXISTENCE_THRESHOLD, + CUSTOM_FUNCTION_QUERY_MOTION_THRESHOLD, + CUSTOM_FUNCTION_QUERY_MOTION_TRIGGER_TIME, + CUSTOM_FUNCTION_QUERY_MOTION_TO_REST_TIME, + CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED, + + UNDERLY_FUNCTION_QUERY_HUMAN_STATUS, + UNDERLY_FUNCTION_QUERY_SPATIAL_STATIC_VALUE, + UNDERLY_FUNCTION_QUERY_SPATIAL_MOTION_VALUE, + UNDERLY_FUNCTION_QUERY_DISTANCE_OF_STATIC_OBJECT, + UNDERLY_FUNCTION_QUERY_DISTANCE_OF_MOVING_OBJECT, + UNDERLY_FUNCTION_QUERY_TARGET_MOVEMENT_SPEED, +}; + +enum OutputSwitch { + OUTPUT_SWITCH_INIT, + OUTPUT_SWITCH_ON, + OUTPUT_SWTICH_OFF, +}; + +static const char *const S_SCENE_STR[5] = {"None", "Living Room", "Bedroom", "Washroom", "Area Detection"}; +static const bool S_SOMEONE_EXISTS_STR[2] = {false, true}; +static const char *const S_MOTION_STATUS_STR[3] = {"None", "Motionless", "Active"}; +static const char *const S_KEEP_AWAY_STR[3] = {"None", "Close", "Away"}; +static const char *const S_UNMANNED_TIME_STR[9] = {"None", "10s", "30s", "1min", "2min", + "5min", "10min", "30min", "60min"}; +static const char *const S_BOUNDARY_STR[10] = {"0.5m", "1.0m", "1.5m", "2.0m", "2.5m", + "3.0m", "3.5m", "4.0m", "4.5m", "5.0m"}; // uint: m +static const float S_PRESENCE_OF_DETECTION_RANGE_STR[7] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f}; // uint: m + +class MR24HPC1Component : public Component, + public uart::UARTDevice { // The class name must be the name defined by text_sensor.py +#ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(heartbeat_state) + SUB_TEXT_SENSOR(product_model) + SUB_TEXT_SENSOR(product_id) + SUB_TEXT_SENSOR(hardware_model) + SUB_TEXT_SENSOR(firware_version) + SUB_TEXT_SENSOR(keep_away) + SUB_TEXT_SENSOR(motion_status) + SUB_TEXT_SENSOR(custom_mode_end) +#endif +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(has_target) +#endif +#ifdef USE_SENSOR + SUB_SENSOR(custom_presence_of_detection) + SUB_SENSOR(movement_signs) + SUB_SENSOR(custom_motion_distance) + SUB_SENSOR(custom_spatial_static_value) + SUB_SENSOR(custom_spatial_motion_value) + SUB_SENSOR(custom_motion_speed) + SUB_SENSOR(custom_mode_num) +#endif +#ifdef USE_SWITCH + SUB_SWITCH(underlying_open_function) +#endif +#ifdef USE_BUTTON + SUB_BUTTON(restart) + SUB_BUTTON(custom_set_end) +#endif +#ifdef USE_SELECT + SUB_SELECT(scene_mode) + SUB_SELECT(unman_time) + SUB_SELECT(existence_boundary) + SUB_SELECT(motion_boundary) +#endif +#ifdef USE_NUMBER + SUB_NUMBER(sensitivity) + SUB_NUMBER(custom_mode) + SUB_NUMBER(existence_threshold) + SUB_NUMBER(motion_threshold) + SUB_NUMBER(motion_trigger) + SUB_NUMBER(motion_to_rest) + SUB_NUMBER(custom_unman_time) +#endif + + protected: + char c_product_mode_[PRODUCT_BUF_MAX_SIZE + 1]; + char c_product_id_[PRODUCT_BUF_MAX_SIZE + 1]; + char c_hardware_model_[PRODUCT_BUF_MAX_SIZE + 1]; + char c_firmware_version_[PRODUCT_BUF_MAX_SIZE + 1]; + uint8_t s_output_info_switch_flag_; + uint8_t sg_recv_data_state_; + uint8_t sg_frame_len_; + uint8_t sg_data_len_; + uint8_t sg_frame_buf_[FRAME_BUF_MAX_SIZE]; + uint8_t sg_frame_prase_buf_[FRAME_BUF_MAX_SIZE]; + int sg_start_query_data_; + bool check_dev_inf_sign_; + bool poll_time_base_func_check_; + + void update_(); + void r24_split_data_frame_(uint8_t value); + void r24_parse_data_frame_(uint8_t *data, uint8_t len); + void r24_frame_parse_open_underlying_information_(uint8_t *data); + void r24_frame_parse_work_status_(uint8_t *data); + void r24_frame_parse_product_information_(uint8_t *data); + void r24_frame_parse_human_information_(uint8_t *data); + void send_query_(const uint8_t *query, size_t string_length); + + public: + float get_setup_priority() const override { return esphome::setup_priority::LATE; } + void setup() override; + void dump_config() override; + void loop() override; + + void get_heartbeat_packet(); + void get_radar_output_information_switch(); + void get_product_mode(); + void get_product_id(); + void get_hardware_model(); + void get_firmware_version(); + void get_human_status(); + void get_human_motion_info(); + void get_body_motion_params(); + void get_keep_away(); + void get_scene_mode(); + void get_sensitivity(); + void get_unmanned_time(); + void get_custom_mode(); + void get_existence_boundary(); + void get_motion_boundary(); + void get_spatial_static_value(); + void get_spatial_motion_value(); + void get_distance_of_static_object(); + void get_distance_of_moving_object(); + void get_target_movement_speed(); + void get_existence_threshold(); + void get_motion_threshold(); + void get_motion_trigger_time(); + void get_motion_to_rest_time(); + void get_custom_unman_time(); + + void set_scene_mode(uint8_t value); + void set_underlying_open_function(bool enable); + void set_sensitivity(uint8_t value); + void set_restart(); + void set_unman_time(uint8_t value); + void set_custom_mode(uint8_t mode); + void set_custom_end_mode(); + void set_existence_boundary(uint8_t value); + void set_motion_boundary(uint8_t value); + void set_existence_threshold(uint8_t value); + void set_motion_threshold(uint8_t value); + void set_motion_trigger_time(uint8_t value); + void set_motion_to_rest_time(uint16_t value); + void set_custom_unman_time(uint16_t value); +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h new file mode 100644 index 0000000000..dafc6c0368 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h @@ -0,0 +1,173 @@ +#pragma once + +#include + +namespace esphome { +namespace seeed_mr24hpc1 { + +static const uint8_t FRAME_BUF_MAX_SIZE = 128; +static const uint8_t PRODUCT_BUF_MAX_SIZE = 32; + +static const uint8_t FRAME_CONTROL_WORD_INDEX = 2; +static const uint8_t FRAME_COMMAND_WORD_INDEX = 3; +static const uint8_t FRAME_DATA_INDEX = 6; + +static const uint8_t FRAME_HEADER1_VALUE = 0x53; +static const uint8_t FRAME_HEADER2_VALUE = 0x59; +static const uint8_t FRAME_TAIL1_VALUE = 0x54; +static const uint8_t FRAME_TAIL2_VALUE = 0x43; + +static const uint8_t CONTROL_MAIN = 0x01; +static const uint8_t CONTROL_PRODUCT_INFORMATION = 0x02; +static const uint8_t CONTROL_WORK = 0x05; +static const uint8_t CONTROL_UNDERLYING_FUNCTION = 0x08; +static const uint8_t CONTROL_HUMAN_INFORMATION = 0x80; + +static const uint8_t COMMAND_HEARTBEAT = 0x01; +static const uint8_t COMMAND_RESTART = 0x02; + +static const uint8_t COMMAND_PRODUCT_MODE = 0xA1; +static const uint8_t COMMAND_PRODUCT_ID = 0xA2; +static const uint8_t COMMAND_HARDWARE_MODEL = 0xA3; +static const uint8_t COMMAND_FIRMWARE_VERSION = 0xA4; + +static const uint8_t GET_HEARTBEAT[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_MAIN, COMMAND_HEARTBEAT, 0x00, 0x01, 0x0F, 0xBE, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t SET_RESTART[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_MAIN, COMMAND_RESTART, 0x00, 0x01, 0x0F, 0xBF, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; + +static const uint8_t GET_PRODUCT_MODE[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_PRODUCT_INFORMATION, COMMAND_PRODUCT_MODE, 0x00, 0x01, 0x0F, 0x5F, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_PRODUCT_ID[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_PRODUCT_INFORMATION, COMMAND_PRODUCT_ID, 0x00, 0x01, 0x0F, 0x60, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_HARDWARE_MODEL[] = { + FRAME_HEADER1_VALUE, + FRAME_HEADER2_VALUE, + CONTROL_PRODUCT_INFORMATION, + COMMAND_HARDWARE_MODEL, + 0x00, + 0x01, + 0x0F, + 0x61, + FRAME_TAIL1_VALUE, + FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_FIRMWARE_VERSION[] = { + FRAME_HEADER1_VALUE, + FRAME_HEADER2_VALUE, + CONTROL_PRODUCT_INFORMATION, + COMMAND_FIRMWARE_VERSION, + 0x00, + 0x01, + 0x0F, + 0x62, + FRAME_TAIL1_VALUE, + FRAME_TAIL2_VALUE, +}; + +static const uint8_t GET_SCENE_MODE[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x87, 0x00, 0x01, 0x0F, 0x48, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_SENSITIVITY[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x88, 0x00, 0x01, 0x0F, 0x49, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_CUSTOM_MODE[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x89, 0x00, 0x01, 0x0F, 0x4A, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; + +static const uint8_t UNDERLYING_SWITCH_ON[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x00, 0x00, 0x01, 0x01, 0xB6, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t UNDERLYING_SWITCH_OFF[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x00, 0x00, 0x01, 0x00, 0xB5, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; + +static const uint8_t GET_RADAR_OUTPUT_INFORMATION_SWITCH[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x80, 0x00, 0x01, 0x0F, 0x44, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_SPATIAL_STATIC_VALUE[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x81, 0x00, 0x01, 0x0F, 0x45, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_SPATIAL_MOTION_VALUE[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x82, 0x00, 0x01, 0x0F, 0x46, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_DISTANCE_OF_STATIC_OBJECT[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x83, 0x00, 0x01, 0x0F, 0x47, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_DISTANCE_OF_MOVING_OBJECT[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x84, 0x00, 0x01, 0x0F, 0x48, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_TARGET_MOVEMENT_SPEED[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x85, 0x00, 0x01, 0x0F, 0x49, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_EXISTENCE_THRESHOLD[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x88, 0x00, 0x01, 0x0F, 0x4C, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_MOTION_THRESHOLD[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x89, 0x00, 0x01, 0x0F, 0x4D, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_EXISTENCE_BOUNDARY[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8A, 0x00, 0x01, 0x0F, 0x4E, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_MOTION_BOUNDARY[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8B, 0x00, 0x01, 0x0F, 0x4F, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_MOTION_TRIGGER_TIME[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8C, 0x00, 0x01, 0x0F, 0x50, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_MOTION_TO_REST_TIME[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8D, 0x00, 0x01, 0x0F, 0x51, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_CUSTOM_UNMAN_TIME[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8E, 0x00, 0x01, 0x0F, 0x52, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; + +static const uint8_t GET_HUMAN_STATUS[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x81, 0x00, 0x01, 0x0F, 0xBD, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_HUMAN_MOTION_INFORMATION[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x82, 0x00, 0x01, 0x0F, 0xBE, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_BODY_MOTION_PARAMETERS[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x83, 0x00, 0x01, 0x0F, 0xBF, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_UNMANNED_TIME[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x8A, 0x00, 0x01, 0x0F, 0xC6, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; +static const uint8_t GET_KEEP_AWAY[] = { + FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x8B, 0x00, 0x01, 0x0F, 0xC7, + FRAME_TAIL1_VALUE, FRAME_TAIL2_VALUE, +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/__init__.py b/esphome/components/seeed_mr24hpc1/select/__init__.py new file mode 100644 index 0000000000..7da83627b9 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/__init__.py @@ -0,0 +1,103 @@ +import esphome.codegen as cg +from esphome.components import select +import esphome.config_validation as cv +from esphome.const import ( + ENTITY_CATEGORY_CONFIG, +) +from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns + +SceneModeSelect = mr24hpc1_ns.class_("SceneModeSelect", select.Select) +UnmanTimeSelect = mr24hpc1_ns.class_("UnmanTimeSelect", select.Select) +ExistenceBoundarySelect = mr24hpc1_ns.class_("ExistenceBoundarySelect", select.Select) +MotionBoundarySelect = mr24hpc1_ns.class_("MotionBoundarySelect", select.Select) + +CONF_SCENE_MODE = "scene_mode" +CONF_UNMAN_TIME = "unman_time" +CONF_EXISTENCE_BOUNDARY = "existence_boundary" +CONF_MOTION_BOUNDARY = "motion_boundary" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_SCENE_MODE): select.select_schema( + SceneModeSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:hoop-house", + ), + cv.Optional(CONF_UNMAN_TIME): select.select_schema( + UnmanTimeSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:timeline-clock", + ), + cv.Optional(CONF_EXISTENCE_BOUNDARY): select.select_schema( + ExistenceBoundarySelect, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_MOTION_BOUNDARY): select.select_schema( + MotionBoundarySelect, + entity_category=ENTITY_CATEGORY_CONFIG, + ), +} + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if scenemode_config := config.get(CONF_SCENE_MODE): + s = await select.new_select( + scenemode_config, + options=["None", "Living Room", "Bedroom", "Washroom", "Area Detection"], + ) + await cg.register_parented(s, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_scene_mode_select(s)) + if unmantime_config := config.get(CONF_UNMAN_TIME): + s = await select.new_select( + unmantime_config, + options=[ + "None", + "10s", + "30s", + "1min", + "2min", + "5min", + "10min", + "30min", + "60min", + ], + ) + await cg.register_parented(s, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_unman_time_select(s)) + if existence_boundary_config := config.get(CONF_EXISTENCE_BOUNDARY): + s = await select.new_select( + existence_boundary_config, + options=[ + "0.5m", + "1.0m", + "1.5m", + "2.0m", + "2.5m", + "3.0m", + "3.5m", + "4.0m", + "4.5m", + "5.0m", + ], + ) + await cg.register_parented(s, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_existence_boundary_select(s)) + if motion_boundary_config := config.get(CONF_MOTION_BOUNDARY): + s = await select.new_select( + motion_boundary_config, + options=[ + "0.5m", + "1.0m", + "1.5m", + "2.0m", + "2.5m", + "3.0m", + "3.5m", + "4.0m", + "4.5m", + "5.0m", + ], + ) + await cg.register_parented(s, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_motion_boundary_select(s)) diff --git a/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.cpp b/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.cpp new file mode 100644 index 0000000000..03c2ec4745 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.cpp @@ -0,0 +1,15 @@ +#include "existence_boundary_select.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void ExistenceBoundarySelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_existence_boundary(index.value()); + } +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.h b/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.h new file mode 100644 index 0000000000..ad770a7296 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/existence_boundary_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class ExistenceBoundarySelect : public select::Select, public Parented { + public: + ExistenceBoundarySelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.cpp b/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.cpp new file mode 100644 index 0000000000..619a4f0935 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.cpp @@ -0,0 +1,15 @@ +#include "motion_boundary_select.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void MotionBoundarySelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_motion_boundary(index.value()); + } +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.h b/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.h new file mode 100644 index 0000000000..9058e3130b --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/motion_boundary_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class MotionBoundarySelect : public select::Select, public Parented { + public: + MotionBoundarySelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/scene_mode_select.cpp b/esphome/components/seeed_mr24hpc1/select/scene_mode_select.cpp new file mode 100644 index 0000000000..153ae603cf --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/scene_mode_select.cpp @@ -0,0 +1,15 @@ +#include "scene_mode_select.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void SceneModeSelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_scene_mode(index.value()); + } +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/scene_mode_select.h b/esphome/components/seeed_mr24hpc1/select/scene_mode_select.h new file mode 100644 index 0000000000..95508d49b0 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/scene_mode_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class SceneModeSelect : public select::Select, public Parented { + public: + SceneModeSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/unman_time_select.cpp b/esphome/components/seeed_mr24hpc1/select/unman_time_select.cpp new file mode 100644 index 0000000000..a9d96c8f67 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/unman_time_select.cpp @@ -0,0 +1,15 @@ +#include "unman_time_select.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void UnmanTimeSelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_unman_time(index.value()); + } +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/select/unman_time_select.h b/esphome/components/seeed_mr24hpc1/select/unman_time_select.h new file mode 100644 index 0000000000..7131988cda --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/select/unman_time_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class UnmanTimeSelect : public select::Select, public Parented { + public: + UnmanTimeSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/sensor.py b/esphome/components/seeed_mr24hpc1/sensor.py new file mode 100644 index 0000000000..d5eb09e265 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/sensor.py @@ -0,0 +1,82 @@ +import esphome.codegen as cg +from esphome.components import sensor +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_SPEED, + UNIT_METER, +) +from . import CONF_MR24HPC1_ID, MR24HPC1Component + +CONF_CUSTOM_PRESENCE_OF_DETECTION = "custom_presence_of_detection" +CONF_MOVEMENT_SIGNS = "movement_signs" +CONF_CUSTOM_MOTION_DISTANCE = "custom_motion_distance" +CONF_CUSTOM_SPATIAL_STATIC_VALUE = "custom_spatial_static_value" +CONF_CUSTOM_SPATIAL_MOTION_VALUE = "custom_spatial_motion_value" +CONF_CUSTOM_MOTION_SPEED = "custom_motion_speed" +CONF_CUSTOM_MODE_NUM = "custom_mode_num" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_CUSTOM_PRESENCE_OF_DETECTION): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + unit_of_measurement=UNIT_METER, + accuracy_decimals=2, # Specify the number of decimal places + icon="mdi:signal-distance-variant", + ), + cv.Optional(CONF_MOVEMENT_SIGNS): sensor.sensor_schema( + icon="mdi:human-greeting-variant", + ), + cv.Optional(CONF_CUSTOM_MOTION_DISTANCE): sensor.sensor_schema( + unit_of_measurement=UNIT_METER, + accuracy_decimals=2, + icon="mdi:signal-distance-variant", + ), + cv.Optional(CONF_CUSTOM_SPATIAL_STATIC_VALUE): sensor.sensor_schema( + device_class=DEVICE_CLASS_ENERGY, + icon="mdi:counter", + ), + cv.Optional(CONF_CUSTOM_SPATIAL_MOTION_VALUE): sensor.sensor_schema( + device_class=DEVICE_CLASS_ENERGY, + icon="mdi:counter", + ), + cv.Optional(CONF_CUSTOM_MOTION_SPEED): sensor.sensor_schema( + unit_of_measurement="m/s", + device_class=DEVICE_CLASS_SPEED, + accuracy_decimals=2, + icon="mdi:run-fast", + ), + cv.Optional(CONF_CUSTOM_MODE_NUM): sensor.sensor_schema( + icon="mdi:counter", + ), + } +) + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if custompresenceofdetection_config := config.get( + CONF_CUSTOM_PRESENCE_OF_DETECTION + ): + sens = await sensor.new_sensor(custompresenceofdetection_config) + cg.add(mr24hpc1_component.set_custom_presence_of_detection_sensor(sens)) + if movementsigns_config := config.get(CONF_MOVEMENT_SIGNS): + sens = await sensor.new_sensor(movementsigns_config) + cg.add(mr24hpc1_component.set_movement_signs_sensor(sens)) + if custommotiondistance_config := config.get(CONF_CUSTOM_MOTION_DISTANCE): + sens = await sensor.new_sensor(custommotiondistance_config) + cg.add(mr24hpc1_component.set_custom_motion_distance_sensor(sens)) + if customspatialstaticvalue_config := config.get(CONF_CUSTOM_SPATIAL_STATIC_VALUE): + sens = await sensor.new_sensor(customspatialstaticvalue_config) + cg.add(mr24hpc1_component.set_custom_spatial_static_value_sensor(sens)) + if customspatialmotionvalue_config := config.get(CONF_CUSTOM_SPATIAL_MOTION_VALUE): + sens = await sensor.new_sensor(customspatialmotionvalue_config) + cg.add(mr24hpc1_component.set_custom_spatial_motion_value_sensor(sens)) + if custommotionspeed_config := config.get(CONF_CUSTOM_MOTION_SPEED): + sens = await sensor.new_sensor(custommotionspeed_config) + cg.add(mr24hpc1_component.set_custom_motion_speed_sensor(sens)) + if custommodenum_config := config.get(CONF_CUSTOM_MODE_NUM): + sens = await sensor.new_sensor(custommodenum_config) + cg.add(mr24hpc1_component.set_custom_mode_num_sensor(sens)) diff --git a/esphome/components/seeed_mr24hpc1/switch/__init__.py b/esphome/components/seeed_mr24hpc1/switch/__init__.py new file mode 100644 index 0000000000..bbf5391a57 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/switch/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_SWITCH, + ENTITY_CATEGORY_CONFIG, +) +from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns + +UnderlyingOpenFuncSwitch = mr24hpc1_ns.class_( + "UnderlyOpenFunctionSwitch", switch.Switch +) + +CONF_UNDERLYING_OPEN_FUNCTION = "underlying_open_function" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_UNDERLYING_OPEN_FUNCTION): switch.switch_schema( + UnderlyingOpenFuncSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon="mdi:electric-switch", + ), +} + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if underlying_open_function_config := config.get(CONF_UNDERLYING_OPEN_FUNCTION): + s = await switch.new_switch(underlying_open_function_config) + await cg.register_parented(s, config[CONF_MR24HPC1_ID]) + cg.add(mr24hpc1_component.set_underlying_open_function_switch(s)) diff --git a/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.cpp b/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.cpp new file mode 100644 index 0000000000..0fcc49bc4c --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.cpp @@ -0,0 +1,12 @@ +#include "underlyFuc_switch.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +void UnderlyOpenFunctionSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_underlying_open_function(state); +} + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h b/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h new file mode 100644 index 0000000000..1baabb25ce --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../seeed_mr24hpc1.h" + +namespace esphome { +namespace seeed_mr24hpc1 { + +class UnderlyOpenFunctionSwitch : public switch_::Switch, public Parented { + public: + UnderlyOpenFunctionSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace seeed_mr24hpc1 +} // namespace esphome diff --git a/esphome/components/seeed_mr24hpc1/text_sensor.py b/esphome/components/seeed_mr24hpc1/text_sensor.py new file mode 100644 index 0000000000..aa50f577d4 --- /dev/null +++ b/esphome/components/seeed_mr24hpc1/text_sensor.py @@ -0,0 +1,74 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC +from . import CONF_MR24HPC1_ID, MR24HPC1Component + +CONF_HEART_BEAT = "heart_beat" +CONF_PRODUCT_MODEL = "product_model" +CONF_PRODUCT_ID = "product_id" +CONF_HARDWARE_MODEL = "hardware_model" +CONF_HARDWARE_VERSION = "hardware_version" + +CONF_KEEP_AWAY = "keep_away" +CONF_MOTION_STATUS = "motion_status" + +CONF_CUSTOM_MODE_END = "custom_mode_end" + + +# The entity category for read only diagnostic values, for example RSSI, uptime or MAC Address +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), + cv.Optional(CONF_HEART_BEAT): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:connection" + ), + cv.Optional(CONF_PRODUCT_MODEL): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" + ), + cv.Optional(CONF_PRODUCT_ID): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" + ), + cv.Optional(CONF_HARDWARE_MODEL): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" + ), + cv.Optional(CONF_HARDWARE_VERSION): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" + ), + cv.Optional(CONF_KEEP_AWAY): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:walk" + ), + cv.Optional(CONF_MOTION_STATUS): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:human-greeting" + ), + cv.Optional(CONF_CUSTOM_MODE_END): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:account-check" + ), +} + + +async def to_code(config): + mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) + if heartbeat_config := config.get(CONF_HEART_BEAT): + sens = await text_sensor.new_text_sensor(heartbeat_config) + cg.add(mr24hpc1_component.set_heartbeat_state_text_sensor(sens)) + if productmodel_config := config.get(CONF_PRODUCT_MODEL): + sens = await text_sensor.new_text_sensor(productmodel_config) + cg.add(mr24hpc1_component.set_product_model_text_sensor(sens)) + if productid_config := config.get(CONF_PRODUCT_ID): + sens = await text_sensor.new_text_sensor(productid_config) + cg.add(mr24hpc1_component.set_product_id_text_sensor(sens)) + if hardwaremodel_config := config.get(CONF_HARDWARE_MODEL): + sens = await text_sensor.new_text_sensor(hardwaremodel_config) + cg.add(mr24hpc1_component.set_hardware_model_text_sensor(sens)) + if firwareversion_config := config.get(CONF_HARDWARE_VERSION): + sens = await text_sensor.new_text_sensor(firwareversion_config) + cg.add(mr24hpc1_component.set_firware_version_text_sensor(sens)) + if keepaway_config := config.get(CONF_KEEP_AWAY): + sens = await text_sensor.new_text_sensor(keepaway_config) + cg.add(mr24hpc1_component.set_keep_away_text_sensor(sens)) + if motionstatus_config := config.get(CONF_MOTION_STATUS): + sens = await text_sensor.new_text_sensor(motionstatus_config) + cg.add(mr24hpc1_component.set_motion_status_text_sensor(sens)) + if custommodeend_config := config.get(CONF_CUSTOM_MODE_END): + sens = await text_sensor.new_text_sensor(custommodeend_config) + cg.add(mr24hpc1_component.set_custom_mode_end_text_sensor(sens)) diff --git a/tests/components/seeed_mr24hpc1/common.yaml b/tests/components/seeed_mr24hpc1/common.yaml new file mode 100644 index 0000000000..38692b3e5e --- /dev/null +++ b/tests/components/seeed_mr24hpc1/common.yaml @@ -0,0 +1,92 @@ +uart: + - id: seeed_mr24hpc1_uart + tx_pin: ${uart_tx_pin} + rx_pin: ${uart_rx_pin} + baud_rate: 115200 + parity: NONE + stop_bits: 1 + +seeed_mr24hpc1: + id: my_seeed_mr24hpc1 + uart_id: seeed_mr24hpc1_uart + +sensor: + - platform: seeed_mr24hpc1 + custom_presence_of_detection: + name: "Static Distance" + movement_signs: + name: "Body Movement Parameter" + custom_motion_distance: + name: "Motion Distance" + custom_spatial_static_value: + name: "Existence Energy" + custom_spatial_motion_value: + name: "Motion Energy" + custom_motion_speed: + name: "Motion Speed" + custom_mode_num: + name: "Current Custom Mode" + +binary_sensor: + - platform: seeed_mr24hpc1 + has_target: + name: "Presence Information" + +switch: + - platform: seeed_mr24hpc1 + underlying_open_function: + name: Underlying Open Function Info Output Switch + +text_sensor: + - platform: seeed_mr24hpc1 + heart_beat: + name: "Heartbeat" + product_model: + name: "Product Model" + product_id: + name: "Product ID" + hardware_model: + name: "Hardware Model" + hardware_version: + name: "Hardware Version" + keep_away: + name: "Active Reporting Of Proximity" + motion_status: + name: "Motion Information" + custom_mode_end: + name: "Custom Mode Status" + +number: + - platform: seeed_mr24hpc1 + sensitivity: + name: "Sensitivity" + custom_mode: + name: "Custom Mode" + existence_threshold: + name: "Existence Energy Threshold" + motion_threshold: + name: "Motion Energy Threshold" + motion_trigger: + name: "Motion Trigger Time" + motion_to_rest: + name: "Motion To Rest Time" + custom_unman_time: + name: "Time For Entering No Person State (Underlying Open Function)" + +select: + - platform: seeed_mr24hpc1 + scene_mode: + name: "Scene" + unman_time: + name: "Time For Entering No Person State (Standard Function)" + existence_boundary: + name: "Existence Boundary" + motion_boundary: + name: "Motion Boundary" + +button: + - platform: seeed_mr24hpc1 + restart: + name: "Module Restart" + custom_set_end: + name: "End Of Custom Mode Settings" diff --git a/tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml b/tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/seeed_mr24hpc1/test.esp32-c3.yaml b/tests/components/seeed_mr24hpc1/test.esp32-c3.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr24hpc1/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml From b0a192d6a5ae8d79b70dfa1ccc7edf2bd2706b2c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:26:31 +1100 Subject: [PATCH 1359/2607] Add getter for font glyph data (#6355) --- esphome/components/font/font.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/font/font.h b/esphome/components/font/font.h index 91bcd399ba..57002cf510 100644 --- a/esphome/components/font/font.h +++ b/esphome/components/font/font.h @@ -30,6 +30,8 @@ class Glyph { void scan_area(int *x1, int *y1, int *width, int *height) const; + const GlyphData *get_glyph_data() const { return this->glyph_data_; } + protected: friend Font; From f5b02056b95a4d3af6b854e714d0657ce65f93cd Mon Sep 17 00:00:00 2001 From: Manuel Kasper Date: Tue, 12 Mar 2024 11:35:29 +0100 Subject: [PATCH 1360/2607] Require reset_pin for certain waveshare_epaper models in YAML validation (#6357) --- esphome/components/waveshare_epaper/display.py | 11 +++++++++++ .../waveshare_epaper/test.esp32.yaml | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 744ae8848f..dc43cbf5a7 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -131,6 +131,8 @@ MODELS = { "1.54in-m5coreink-m09": ("c", GDEW0154M09), } +RESET_PIN_REQUIRED_MODELS = ("2.13inv2", "2.13in-ttgo-b74") + def validate_full_update_every_only_types_ac(value): if CONF_FULL_UPDATE_EVERY not in value: @@ -147,6 +149,14 @@ def validate_full_update_every_only_types_ac(value): return value +def validate_reset_pin_required(config): + if config[CONF_MODEL] in RESET_PIN_REQUIRED_MODELS and CONF_RESET_PIN not in config: + raise cv.Invalid( + f"'{CONF_RESET_PIN}' is required for model {config[CONF_MODEL]}" + ) + return config + + CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( { @@ -165,6 +175,7 @@ CONFIG_SCHEMA = cv.All( .extend(cv.polling_component_schema("1s")) .extend(spi.spi_device_schema()), validate_full_update_every_only_types_ac, + validate_reset_pin_required, cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) diff --git a/tests/components/waveshare_epaper/test.esp32.yaml b/tests/components/waveshare_epaper/test.esp32.yaml index 616698f902..cc6c665e7d 100644 --- a/tests/components/waveshare_epaper/test.esp32.yaml +++ b/tests/components/waveshare_epaper/test.esp32.yaml @@ -28,6 +28,24 @@ display: full_update_every: 30 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + model: 2.13in-ttgo-b74 + spi_id: spi_id_1 + cs_pin: + allow_other_uses: true + number: GPIO25 + dc_pin: + allow_other_uses: true + number: GPIO26 + busy_pin: + allow_other_uses: true + number: GPIO27 + reset_pin: + allow_other_uses: true + number: GPIO32 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: waveshare_epaper model: 2.90in spi_id: spi_id_1 From f264151537729625b86a62d2b34a85781abc8443 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 13 Mar 2024 05:20:16 +1100 Subject: [PATCH 1361/2607] touchscreen driver fixes (#6356) --- .../ft5x06/touchscreen/ft5x06_touchscreen.h | 2 +- esphome/components/touchscreen/touchscreen.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h index 0a1e51227d..7ddd2e44d7 100644 --- a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h +++ b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h @@ -71,7 +71,7 @@ class FT5x06Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice this->x_raw_max_ = this->display_->get_native_width(); } if (this->y_raw_max_ == this->y_raw_min_) { - this->x_raw_max_ = this->display_->get_native_height(); + this->y_raw_max_ = this->display_->get_native_height(); } } esph_log_config(TAG, "FT5x06 Touchscreen setup complete"); diff --git a/esphome/components/touchscreen/touchscreen.cpp b/esphome/components/touchscreen/touchscreen.cpp index 83783a634f..b9498de152 100644 --- a/esphome/components/touchscreen/touchscreen.cpp +++ b/esphome/components/touchscreen/touchscreen.cpp @@ -39,7 +39,6 @@ void Touchscreen::loop() { ESP_LOGVV(TAG, "<< Do Touch loop >>"); this->first_touch_ = this->touches_.empty(); this->need_update_ = false; - this->was_touched_ = this->is_touched_; this->is_touched_ = false; this->skip_update_ = false; for (auto &tp : this->touches_) { @@ -62,7 +61,11 @@ void Touchscreen::loop() { if (this->touch_timeout_ > 0) { // Simulate a touch after touch_timeout_> ms. This will reset any existing timeout operation. // This is to detect touch release. - this->set_timeout(TAG, this->touch_timeout_, [this]() { this->store_.touched = true; }); + if (this->is_touched_) { + this->set_timeout(TAG, this->touch_timeout_, [this]() { this->store_.touched = true; }); + } else { + this->cancel_timeout(TAG); + } } } } @@ -111,6 +114,7 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r void Touchscreen::send_touches_() { TouchPoints_t touches; + ESP_LOGV(TAG, "Touch status: is_touched=%d, was_touched=%d", this->is_touched_, this->was_touched_); for (auto tp : this->touches_) { ESP_LOGV(TAG, "Touch status: %d/%d: raw:(%4d,%4d,%4d) calc:(%3d,%4d)", tp.second.id, tp.second.state, tp.second.x_raw, tp.second.y_raw, tp.second.z_raw, tp.second.x, tp.second.y); @@ -124,14 +128,10 @@ void Touchscreen::send_touches_() { } if (!this->is_touched_) { if (this->was_touched_) { - if (this->touch_timeout_ > 0) { - this->cancel_timeout(TAG); - } this->release_trigger_.trigger(); for (auto *listener : this->touch_listeners_) listener->release(); this->touches_.clear(); - this->was_touched_ = false; } } else { if (this->first_touch_) { @@ -142,6 +142,7 @@ void Touchscreen::send_touches_() { } } } + this->was_touched_ = this->is_touched_; } int16_t Touchscreen::normalize_(int16_t val, int16_t min_val, int16_t max_val, bool inverted) { From d3a028f7fa4174ab6d2e5fbb10e4374454480124 Mon Sep 17 00:00:00 2001 From: M-A Date: Tue, 12 Mar 2024 16:22:28 -0400 Subject: [PATCH 1362/2607] Make USE_HOST compilable on msys2 (#6359) --- esphome/core/helpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index cec8a82d04..0f7afc6a4e 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -12,9 +12,11 @@ #include #ifdef USE_HOST +#ifndef _WIN32 #include #include #include +#endif #include #endif #if defined(USE_ESP8266) From 2df9c30446f471e8754beeb89b2e45ca57e1c786 Mon Sep 17 00:00:00 2001 From: Landon Rohatensky Date: Tue, 12 Mar 2024 16:07:40 -0700 Subject: [PATCH 1363/2607] download font from url on build (#5254) Co-authored-by: guillempages Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/font/__init__.py | 145 +++++++++++++++++++------- esphome/external_files.py | 4 +- tests/components/font/test.esp32.yaml | 11 ++ tests/test2.yaml | 5 - 4 files changed, 122 insertions(+), 43 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 6473ef53dc..76eb05e6ad 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -1,13 +1,15 @@ +import hashlib +import logging + import functools from pathlib import Path -import hashlib import os import re from packaging import version - import requests from esphome import core +from esphome import external_files import esphome.config_validation as cv import esphome.codegen as cg from esphome.helpers import ( @@ -15,21 +17,26 @@ from esphome.helpers import ( cpp_string_escape, ) from esphome.const import ( + __version__, CONF_FAMILY, CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_RAW_DATA_ID, CONF_TYPE, + CONF_REFRESH, CONF_SIZE, CONF_PATH, CONF_WEIGHT, + CONF_URL, ) from esphome.core import ( CORE, HexInt, ) +_LOGGER = logging.getLogger(__name__) + DOMAIN = "font" DEPENDENCIES = ["display"] MULTI_CONF = True @@ -125,20 +132,10 @@ def validate_truetype_file(value): return cv.file_(value) -def _compute_local_font_dir(name) -> Path: - h = hashlib.new("sha256") - h.update(name.encode()) - return Path(CORE.data_dir) / DOMAIN / h.hexdigest()[:8] - - -def _compute_gfonts_local_path(value) -> Path: - name = f"{value[CONF_FAMILY]}@{value[CONF_WEIGHT]}@{value[CONF_ITALIC]}@v1" - return _compute_local_font_dir(name) / "font.ttf" - - TYPE_LOCAL = "local" TYPE_LOCAL_BITMAP = "local_bitmap" TYPE_GFONTS = "gfonts" +TYPE_WEB = "web" LOCAL_SCHEMA = cv.Schema( { cv.Required(CONF_PATH): validate_truetype_file, @@ -169,21 +166,64 @@ def validate_weight_name(value): return FONT_WEIGHTS[cv.one_of(*FONT_WEIGHTS, lower=True, space="-")(value)] -def download_gfonts(value): +def _compute_local_font_path(value: dict) -> Path: + url = value[CONF_URL] + h = hashlib.new("sha256") + h.update(url.encode()) + key = h.hexdigest()[:8] + base_dir = external_files.compute_local_file_dir(DOMAIN) + _LOGGER.debug("_compute_local_font_path: base_dir=%s", base_dir / key) + return base_dir / key + + +def get_font_path(value, type) -> Path: + if type == TYPE_GFONTS: + name = f"{value[CONF_FAMILY]}@{value[CONF_WEIGHT]}@{value[CONF_ITALIC]}@v1" + return external_files.compute_local_file_dir(DOMAIN) / f"{name}.ttf" + if type == TYPE_WEB: + return _compute_local_font_path(value) / "font.ttf" + return None + + +def download_content(url: str, path: Path) -> None: + if not external_files.has_remote_file_changed(url, path): + _LOGGER.debug("Remote file has not changed %s", url) + return + + _LOGGER.debug( + "Remote file has changed, downloading from %s to %s", + url, + path, + ) + + try: + req = requests.get( + url, + timeout=external_files.NETWORK_TIMEOUT, + headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, + ) + req.raise_for_status() + except requests.exceptions.RequestException as e: + raise cv.Invalid(f"Could not download from {url}: {e}") + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(req.content) + + +def download_gfont(value): name = ( f"{value[CONF_FAMILY]}:ital,wght@{int(value[CONF_ITALIC])},{value[CONF_WEIGHT]}" ) url = f"https://fonts.googleapis.com/css2?family={name}" + path = get_font_path(value, TYPE_GFONTS) + _LOGGER.debug("download_gfont: path=%s", path) - path = _compute_gfonts_local_path(value) - if path.is_file(): - return value try: - req = requests.get(url, timeout=30) + req = requests.get(url, timeout=external_files.NETWORK_TIMEOUT) req.raise_for_status() except requests.exceptions.RequestException as e: raise cv.Invalid( - f"Could not download font for {name}, please check the fonts exists " + f"Could not download font at {url}, please check the fonts exists " f"at google fonts ({e})" ) match = re.search(r"src:\s+url\((.+)\)\s+format\('truetype'\);", req.text) @@ -194,26 +234,48 @@ def download_gfonts(value): ) ttf_url = match.group(1) - try: - req = requests.get(ttf_url, timeout=30) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise cv.Invalid(f"Could not download ttf file for {name} ({ttf_url}): {e}") + _LOGGER.debug("download_gfont: ttf_url=%s", ttf_url) - path.parent.mkdir(exist_ok=True, parents=True) - path.write_bytes(req.content) + download_content(ttf_url, path) return value -GFONTS_SCHEMA = cv.All( +def download_web_font(value): + url = value[CONF_URL] + path = get_font_path(value, TYPE_WEB) + + download_content(url, path) + _LOGGER.debug("download_web_font: path=%s", path) + return value + + +EXTERNAL_FONT_SCHEMA = cv.Schema( { - cv.Required(CONF_FAMILY): cv.string_strict, cv.Optional(CONF_WEIGHT, default="regular"): cv.Any( cv.int_, validate_weight_name ), cv.Optional(CONF_ITALIC, default=False): cv.boolean, - }, - download_gfonts, + cv.Optional(CONF_REFRESH, default="1d"): cv.All(cv.string, cv.source_refresh), + } +) + + +GFONTS_SCHEMA = cv.All( + EXTERNAL_FONT_SCHEMA.extend( + { + cv.Required(CONF_FAMILY): cv.string_strict, + } + ), + download_gfont, +) + +WEB_FONT_SCHEMA = cv.All( + EXTERNAL_FONT_SCHEMA.extend( + { + cv.Required(CONF_URL): cv.string_strict, + } + ), + download_web_font, ) @@ -233,6 +295,14 @@ def validate_file_shorthand(value): data[CONF_WEIGHT] = weight[1:] return FILE_SCHEMA(data) + if value.startswith("http://") or value.startswith("https://"): + return FILE_SCHEMA( + { + CONF_TYPE: TYPE_WEB, + CONF_URL: value, + } + ) + if value.endswith(".pcf") or value.endswith(".bdf"): return FILE_SCHEMA( { @@ -254,6 +324,7 @@ TYPED_FILE_SCHEMA = cv.typed_schema( TYPE_LOCAL: LOCAL_SCHEMA, TYPE_GFONTS: GFONTS_SCHEMA, TYPE_LOCAL_BITMAP: LOCAL_BITMAP_SCHEMA, + TYPE_WEB: WEB_FONT_SCHEMA, } ) @@ -264,7 +335,7 @@ def _file_schema(value): return TYPED_FILE_SCHEMA(value) -FILE_SCHEMA = cv.Schema(_file_schema) +FILE_SCHEMA = cv.All(_file_schema) DEFAULT_GLYPHS = ( ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' @@ -288,7 +359,7 @@ FONT_SCHEMA = cv.Schema( ), cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), cv.GenerateID(CONF_RAW_GLYPH_ID): cv.declare_id(GlyphData), - } + }, ) CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, merge_glyphs) @@ -343,8 +414,8 @@ class EFont: elif ftype == TYPE_LOCAL: path = CORE.relative_config_path(file[CONF_PATH]) font = load_ttf_font(path, size) - elif ftype == TYPE_GFONTS: - path = _compute_gfonts_local_path(file) + elif ftype in (TYPE_GFONTS, TYPE_WEB): + path = get_font_path(file, ftype) font = load_ttf_font(path, size) else: raise cv.Invalid(f"Could not load font: unknown type: {ftype}") @@ -361,9 +432,9 @@ def convert_bitmap_to_pillow_font(filepath): BdfFontFile, ) - local_bitmap_font_file = _compute_local_font_dir(filepath) / os.path.basename( - filepath - ) + local_bitmap_font_file = external_files.compute_local_file_dir( + DOMAIN, + ) / os.path.basename(filepath) copy_file_if_changed(filepath, local_bitmap_font_file) diff --git a/esphome/external_files.py b/esphome/external_files.py index 5b476286f3..a1422d02b1 100644 --- a/esphome/external_files.py +++ b/esphome/external_files.py @@ -33,7 +33,9 @@ def has_remote_file_changed(url, local_file_path): IF_MODIFIED_SINCE: local_modification_time_str, CACHE_CONTROL: CACHE_CONTROL_MAX_AGE + "3600", } - response = requests.head(url, headers=headers, timeout=NETWORK_TIMEOUT) + response = requests.head( + url, headers=headers, timeout=NETWORK_TIMEOUT, allow_redirects=True + ) _LOGGER.debug( "has_remote_file_changed: File %s, Local modified %s, response code %d", diff --git a/tests/components/font/test.esp32.yaml b/tests/components/font/test.esp32.yaml index 9d699a1752..d142463893 100644 --- a/tests/components/font/test.esp32.yaml +++ b/tests/components/font/test.esp32.yaml @@ -6,6 +6,17 @@ font: extras: - file: "gfonts://Roboto" glyphs: ["\u00C4", "\u00C5", "\U000000C7"] + - file: "gfonts://Roboto" + id: roboto_web + size: 20 + - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft + size: 20 + - file: + type: web + url: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft2 + size: 24 spi: clk_pin: 14 diff --git a/tests/test2.yaml b/tests/test2.yaml index 217a4c8feb..a1e310be9c 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -812,11 +812,6 @@ image: file: mdi:alert-outline type: BINARY -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 - graph: - id: my_graph sensor: ha_hello_world_temperature From c7305e15a7a5181cce3db77ba9842afcceb7cfa5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:14:57 +1100 Subject: [PATCH 1364/2607] Add driver for quad SPI AMOLED displays (#6354) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/qspi_amoled/__init__.py | 1 + esphome/components/qspi_amoled/display.py | 131 ++++++++++++++ .../components/qspi_amoled/qspi_amoled.cpp | 165 ++++++++++++++++++ esphome/components/qspi_amoled/qspi_amoled.h | 165 ++++++++++++++++++ .../qspi_amoled/test.esp32-s3-idf.yaml | 36 ++++ 6 files changed, 499 insertions(+) create mode 100644 esphome/components/qspi_amoled/__init__.py create mode 100644 esphome/components/qspi_amoled/display.py create mode 100644 esphome/components/qspi_amoled/qspi_amoled.cpp create mode 100644 esphome/components/qspi_amoled/qspi_amoled.h create mode 100644 tests/components/qspi_amoled/test.esp32-s3-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 64005b1a81..483672bf54 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -269,6 +269,7 @@ esphome/components/pvvx_mithermometer/* @pasiz esphome/components/pylontech/* @functionpointer esphome/components/qmp6988/* @andrewpc esphome/components/qr_code/* @wjtje +esphome/components/qspi_amoled/* @clydebarrow esphome/components/qwiic_pir/* @kahrendt esphome/components/radon_eye_ble/* @jeffeb3 esphome/components/radon_eye_rd200/* @jeffeb3 diff --git a/esphome/components/qspi_amoled/__init__.py b/esphome/components/qspi_amoled/__init__.py new file mode 100644 index 0000000000..c58ce8a01e --- /dev/null +++ b/esphome/components/qspi_amoled/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@clydebarrow"] diff --git a/esphome/components/qspi_amoled/display.py b/esphome/components/qspi_amoled/display.py new file mode 100644 index 0000000000..84bf9553cb --- /dev/null +++ b/esphome/components/qspi_amoled/display.py @@ -0,0 +1,131 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import ( + spi, + display, +) +from esphome.const import ( + CONF_RESET_PIN, + CONF_ID, + CONF_DIMENSIONS, + CONF_WIDTH, + CONF_HEIGHT, + CONF_LAMBDA, + CONF_BRIGHTNESS, + CONF_ENABLE_PIN, + CONF_MODEL, + CONF_OFFSET_HEIGHT, + CONF_OFFSET_WIDTH, + CONF_INVERT_COLORS, + CONF_MIRROR_X, + CONF_MIRROR_Y, + CONF_SWAP_XY, + CONF_COLOR_ORDER, + CONF_TRANSFORM, +) + +DEPENDENCIES = ["spi"] + +qspi_amoled_ns = cg.esphome_ns.namespace("qspi_amoled") +QSPI_AMOLED = qspi_amoled_ns.class_( + "QspiAmoLed", display.Display, display.DisplayBuffer, cg.Component, spi.SPIDevice +) +ColorOrder = display.display_ns.enum("ColorMode") +Model = qspi_amoled_ns.enum("Model") + +MODELS = {"RM690B0": Model.RM690B0, "RM67162": Model.RM67162} + +COLOR_ORDERS = { + "RGB": ColorOrder.COLOR_ORDER_RGB, + "BGR": ColorOrder.COLOR_ORDER_BGR, +} +DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(QSPI_AMOLED), + cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True), + cv.Required(CONF_DIMENSIONS): cv.Any( + cv.dimensions, + cv.Schema( + { + cv.Required(CONF_WIDTH): cv.int_, + cv.Required(CONF_HEIGHT): cv.int_, + cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, + cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, + } + ), + ), + cv.Optional(CONF_TRANSFORM): cv.Schema( + { + cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, + cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, + cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, + } + ), + cv.Optional(CONF_COLOR_ORDER, default="RGB"): cv.enum( + COLOR_ORDERS, upper=True + ), + cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_BRIGHTNESS, default=0xD0): cv.int_range( + 0, 0xFF, min_included=True, max_included=True + ), + } + ).extend( + spi.spi_device_schema( + cs_pin_required=False, + default_mode="MODE0", + default_data_rate=10e6, + quad=True, + ) + ) + ), + cv.only_with_esp_idf, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await display.register_display(var, config) + await spi.register_spi_device(var, config) + + cg.add(var.set_color_mode(config[CONF_COLOR_ORDER])) + cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) + cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) + cg.add(var.set_model(config[CONF_MODEL])) + if enable_pin := config.get(CONF_ENABLE_PIN): + enable = await cg.gpio_pin_expression(enable_pin) + cg.add(var.set_enable_pin(enable)) + + if reset_pin := config.get(CONF_RESET_PIN): + reset = await cg.gpio_pin_expression(reset_pin) + cg.add(var.set_reset_pin(reset)) + + if transform := config.get(CONF_TRANSFORM): + cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) + cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) + cg.add(var.set_swap_xy(transform[CONF_SWAP_XY])) + + if CONF_DIMENSIONS in config: + dimensions = config[CONF_DIMENSIONS] + if isinstance(dimensions, dict): + cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) + cg.add( + var.set_offsets( + dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] + ) + ) + else: + (width, height) = dimensions + cg.add(var.set_dimensions(width, height)) + + if lamb := config.get(CONF_LAMBDA): + lambda_ = await cg.process_lambda( + lamb, [(display.DisplayRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/qspi_amoled/qspi_amoled.cpp b/esphome/components/qspi_amoled/qspi_amoled.cpp new file mode 100644 index 0000000000..697989e861 --- /dev/null +++ b/esphome/components/qspi_amoled/qspi_amoled.cpp @@ -0,0 +1,165 @@ +#ifdef USE_ESP_IDF +#include "qspi_amoled.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace qspi_amoled { + +void QspiAmoLed::setup() { + esph_log_config(TAG, "Setting up QSPI_AMOLED"); + this->spi_setup(); + if (this->enable_pin_ != nullptr) { + this->enable_pin_->setup(); + this->enable_pin_->digital_write(true); + } + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(true); + delay(5); + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + } + this->set_timeout(120, [this] { this->write_command_(SLEEP_OUT); }); + this->set_timeout(240, [this] { this->write_init_sequence_(); }); +} + +void QspiAmoLed::update() { + this->do_update_(); + int w = this->x_high_ - this->x_low_ + 1; + int h = this->y_high_ - this->y_low_ + 1; + this->draw_pixels_at(this->x_low_, this->y_low_, w, h, this->buffer_, this->color_mode_, display::COLOR_BITNESS_565, + true, this->x_low_, this->y_low_, this->get_width_internal() - w - this->x_low_); + // invalidate watermarks + this->x_low_ = this->width_; + this->y_low_ = this->height_; + this->x_high_ = 0; + this->y_high_ = 0; +} + +void QspiAmoLed::draw_absolute_pixel_internal(int x, int y, Color color) { + if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) { + return; + } + if (this->buffer_ == nullptr) + this->init_internal_(this->width_ * this->height_ * 2); + if (this->is_failed()) + return; + uint32_t pos = (y * this->width_) + x; + uint16_t new_color; + bool updated = false; + pos = pos * 2; + new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); + if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) { + this->buffer_[pos] = (uint8_t) (new_color >> 8); + updated = true; + } + pos = pos + 1; + new_color = new_color & 0xFF; + + if (this->buffer_[pos] != new_color) { + this->buffer_[pos] = new_color; + updated = true; + } + if (updated) { + // low and high watermark may speed up drawing from buffer + if (x < this->x_low_) + this->x_low_ = x; + if (y < this->y_low_) + this->y_low_ = y; + if (x > this->x_high_) + this->x_high_ = x; + if (y > this->y_high_) + this->y_high_ = y; + } +} + +void QspiAmoLed::reset_params_(bool ready) { + if (!ready && !this->is_ready()) + return; + this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); + // custom x/y transform and color order + uint8_t mad = this->color_mode_ == display::COLOR_ORDER_BGR ? MADCTL_BGR : MADCTL_RGB; + if (this->swap_xy_) + mad |= MADCTL_MV; + if (this->mirror_x_) + mad |= MADCTL_MX; + if (this->mirror_y_) + mad |= MADCTL_MY; + this->write_command_(MADCTL_CMD, &mad, 1); + this->write_command_(BRIGHTNESS, &this->brightness_, 1); +} + +void QspiAmoLed::write_init_sequence_() { + if (this->model_ == RM690B0) { + this->write_command_(PAGESEL, 0x20); + this->write_command_(MIPI, 0x0A); + this->write_command_(WRAM, 0x80); + this->write_command_(SWIRE1, 0x51); + this->write_command_(SWIRE2, 0x2E); + this->write_command_(PAGESEL, 0x00); + this->write_command_(0xC2, 0x00); + delay(10); + this->write_command_(TEON, 0x00); + } + this->write_command_(PIXFMT, 0x55); + this->write_command_(BRIGHTNESS, 0); + this->write_command_(DISPLAY_ON); + this->reset_params_(true); + this->setup_complete_ = true; + esph_log_config(TAG, "QSPI_AMOLED setup complete"); +} + +void QspiAmoLed::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { + uint8_t buf[4]; + x1 += this->offset_x_; + x2 += this->offset_x_; + y1 += this->offset_y_; + y2 += this->offset_y_; + put16_be(buf, x1); + put16_be(buf + 2, x2); + this->write_command_(CASET, buf, sizeof buf); + put16_be(buf, y1); + put16_be(buf + 2, y2); + this->write_command_(RASET, buf, sizeof buf); +} + +void QspiAmoLed::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { + if (!this->setup_complete_ || this->is_failed()) + return; + if (w <= 0 || h <= 0) + return; + if (bitness != display::COLOR_BITNESS_565 || order != this->color_mode_ || + big_endian != (this->bit_order_ == spi::BIT_ORDER_MSB_FIRST)) { + return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, + x_pad); + } + this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1); + this->enable(); + // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. + if (x_offset == 0 && x_pad == 0 && y_offset == 0) { + // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother + this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, ptr, w * h * 2, 4); + } else { + this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, nullptr, 0, 4); + auto stride = x_offset + w + x_pad; + for (int y = 0; y != h; y++) { + this->write_cmd_addr_data(0, 0, 0, 0, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4); + } + } + this->disable(); +} + +void QspiAmoLed::dump_config() { + ESP_LOGCONFIG("", "QSPI AMOLED"); + ESP_LOGCONFIG(TAG, " Height: %u", this->height_); + ESP_LOGCONFIG(TAG, " Width: %u", this->width_); + LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); +} + +} // namespace qspi_amoled +} // namespace esphome +#endif diff --git a/esphome/components/qspi_amoled/qspi_amoled.h b/esphome/components/qspi_amoled/qspi_amoled.h new file mode 100644 index 0000000000..28d243f548 --- /dev/null +++ b/esphome/components/qspi_amoled/qspi_amoled.h @@ -0,0 +1,165 @@ +// +// Created by Clyde Stubbs on 29/10/2023. +// +#pragma once + +#ifdef USE_ESP_IDF +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/display/display.h" +#include "esphome/components/display/display_buffer.h" +#include "esphome/components/display/display_color_utils.h" +#include "esp_lcd_panel_ops.h" + +#include "esp_lcd_panel_rgb.h" + +namespace esphome { +namespace qspi_amoled { + +constexpr static const char *const TAG = "display.qspi_amoled"; +static const uint8_t SW_RESET_CMD = 0x01; +static const uint8_t SLEEP_OUT = 0x11; +static const uint8_t INVERT_OFF = 0x20; +static const uint8_t INVERT_ON = 0x21; +static const uint8_t ALL_ON = 0x23; +static const uint8_t WRAM = 0x24; +static const uint8_t MIPI = 0x26; +static const uint8_t DISPLAY_ON = 0x29; +static const uint8_t RASET = 0x2B; +static const uint8_t CASET = 0x2A; +static const uint8_t WDATA = 0x2C; +static const uint8_t TEON = 0x35; +static const uint8_t MADCTL_CMD = 0x36; +static const uint8_t PIXFMT = 0x3A; +static const uint8_t BRIGHTNESS = 0x51; +static const uint8_t SWIRE1 = 0x5A; +static const uint8_t SWIRE2 = 0x5B; +static const uint8_t PAGESEL = 0xFE; + +static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top +static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left +static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode +static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order +static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order + +// store a 16 bit value in a buffer, big endian. +static inline void put16_be(uint8_t *buf, uint16_t value) { + buf[0] = value >> 8; + buf[1] = value; +} + +enum Model { + RM690B0, + RM67162, +}; + +class QspiAmoLed : public display::DisplayBuffer, + public spi::SPIDevice { + public: + void set_model(Model model) { this->model_ = model; } + void update() override; + void setup() override; + display::ColorOrder get_color_mode() { return this->color_mode_; } + void set_color_mode(display::ColorOrder color_mode) { this->color_mode_ = color_mode; } + + void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } + void set_enable_pin(GPIOPin *enable_pin) { this->enable_pin_ = enable_pin; } + void set_width(uint16_t width) { this->width_ = width; } + void set_dimensions(uint16_t width, uint16_t height) { + this->width_ = width; + this->height_ = height; + } + int get_width() override { return this->width_; } + int get_height() override { return this->height_; } + void set_invert_colors(bool invert_colors) { + this->invert_colors_ = invert_colors; + this->reset_params_(); + } + void set_mirror_x(bool mirror_x) { + this->mirror_x_ = mirror_x; + this->reset_params_(); + } + void set_mirror_y(bool mirror_y) { + this->mirror_y_ = mirror_y; + this->reset_params_(); + } + void set_swap_xy(bool swap_xy) { + this->swap_xy_ = swap_xy; + this->reset_params_(); + } + void set_brightness(uint8_t brightness) { + this->brightness_ = brightness; + this->reset_params_(); + } + void set_offsets(int16_t offset_x, int16_t offset_y) { + this->offset_x_ = offset_x; + this->offset_y_ = offset_y; + } + display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } + void dump_config() override; + + int get_width_internal() override { return this->width_; } + int get_height_internal() override { return this->height_; } + bool can_proceed() override { return this->setup_complete_; } + + protected: + void draw_absolute_pixel_internal(int x, int y, Color color) override; + void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; + /** + * the RM67162 in quad SPI mode seems to work like this (not in the datasheet, this is deduced from the + * sample code.) + * + * Immediately after enabling /CS send 4 bytes in single-dataline SPI mode: + * 0: either 0x2 or 0x32. The first indicates that any subsequent data bytes after the initial 4 will be + * sent in 1-dataline SPI. The second indicates quad mode. + * 1: 0x00 + * 2: The command (register address) byte. + * 3: 0x00 + * + * This is followed by zero or more data bytes in either 1-wire or 4-wire mode, depending on the first byte. + * At the conclusion of the write, de-assert /CS. + * + * @param cmd + * @param bytes + * @param len + */ + void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) { + this->enable(); + this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len); + this->disable(); + } + + void write_command_(uint8_t cmd, uint8_t data) { this->write_command_(cmd, &data, 1); } + void write_command_(uint8_t cmd) { this->write_command_(cmd, &cmd, 0); } + void reset_params_(bool ready = false); + void write_init_sequence_(); + void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + + GPIOPin *reset_pin_{nullptr}; + GPIOPin *enable_pin_{nullptr}; + uint16_t x_low_{0}; + uint16_t y_low_{0}; + uint16_t x_high_{0}; + uint16_t y_high_{0}; + bool setup_complete_{}; + + bool invert_colors_{}; + display::ColorOrder color_mode_{display::COLOR_ORDER_BGR}; + size_t width_{}; + size_t height_{}; + int16_t offset_x_{0}; + int16_t offset_y_{0}; + bool swap_xy_{}; + bool mirror_x_{}; + bool mirror_y_{}; + uint8_t brightness_{0xD0}; + Model model_{RM690B0}; + + esp_lcd_panel_handle_t handle_{}; +}; + +} // namespace qspi_amoled +} // namespace esphome +#endif diff --git a/tests/components/qspi_amoled/test.esp32-s3-idf.yaml b/tests/components/qspi_amoled/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..01d1a63bcb --- /dev/null +++ b/tests/components/qspi_amoled/test.esp32-s3-idf.yaml @@ -0,0 +1,36 @@ +spi: + id: quad_spi + clk_pin: 15 + type: quad + data_pins: [14, 10, 16, 12] + +display: + - platform: qspi_amoled + model: RM690B0 + data_rate: 80MHz + spi_mode: mode0 + dimensions: + width: 450 + height: 600 + offset_width: 16 + color_order: rgb + invert_colors: false + brightness: 255 + cs_pin: 11 + reset_pin: 13 + enable_pin: 9 + + - platform: qspi_amoled + model: RM67162 + id: main_lcd + dimensions: + height: 240 + width: 536 + transform: + mirror_x: true + swap_xy: true + color_order: rgb + brightness: 255 + cs_pin: 6 + reset_pin: 17 + enable_pin: 38 From 77214a677b85266e319f81f30573bc3546f032d7 Mon Sep 17 00:00:00 2001 From: Sorin Iordachescu Date: Tue, 12 Mar 2024 23:17:06 +0000 Subject: [PATCH 1365/2607] ADE7953: Add the ability to use accumulating energy registers, more precise power reporting (#6311) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/ade7953_base/__init__.py | 5 +++ .../components/ade7953_base/ade7953_base.cpp | 43 +++++++++++++------ .../components/ade7953_base/ade7953_base.h | 4 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/esphome/components/ade7953_base/__init__.py b/esphome/components/ade7953_base/__init__.py index d4c18f8ffd..28014ef142 100644 --- a/esphome/components/ade7953_base/__init__.py +++ b/esphome/components/ade7953_base/__init__.py @@ -41,6 +41,7 @@ CONF_CURRENT_GAIN_A = "current_gain_a" CONF_CURRENT_GAIN_B = "current_gain_b" CONF_ACTIVE_POWER_GAIN_A = "active_power_gain_a" CONF_ACTIVE_POWER_GAIN_B = "active_power_gain_b" +CONF_USE_ACCUMULATED_ENERGY_REGISTERS = "use_accumulated_energy_registers" PGA_GAINS = { "1x": 0b000, "2x": 0b001, @@ -155,6 +156,7 @@ ADE7953_CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_ACTIVE_POWER_GAIN_B, default=0x400000): cv.hex_int_range( min=0x100000, max=0x800000 ), + cv.Optional(CONF_USE_ACCUMULATED_ENERGY_REGISTERS, default=False): cv.boolean, } ).extend(cv.polling_component_schema("60s")) @@ -174,6 +176,9 @@ async def register_ade7953(var, config): cg.add(var.set_bigain(config.get(CONF_CURRENT_GAIN_B))) cg.add(var.set_awgain(config.get(CONF_ACTIVE_POWER_GAIN_A))) cg.add(var.set_bwgain(config.get(CONF_ACTIVE_POWER_GAIN_B))) + cg.add( + var.set_use_acc_energy_regs(config.get(CONF_USE_ACCUMULATED_ENERGY_REGISTERS)) + ) for key in [ CONF_VOLTAGE, diff --git a/esphome/components/ade7953_base/ade7953_base.cpp b/esphome/components/ade7953_base/ade7953_base.cpp index af6fe0a5df..862f5567a8 100644 --- a/esphome/components/ade7953_base/ade7953_base.cpp +++ b/esphome/components/ade7953_base/ade7953_base.cpp @@ -6,6 +6,9 @@ namespace ade7953_base { static const char *const TAG = "ade7953"; +static const float ADE_POWER_FACTOR = 154.0f; +static const float ADE_WATTSEC_POWER_FACTOR = ADE_POWER_FACTOR * ADE_POWER_FACTOR / 3600; + void ADE7953::setup() { if (this->irq_pin_ != nullptr) { this->irq_pin_->setup(); @@ -34,6 +37,7 @@ void ADE7953::setup() { this->ade_read_32(BIGAIN_32, &bigain_); this->ade_read_32(AWGAIN_32, &awgain_); this->ade_read_32(BWGAIN_32, &bwgain_); + this->last_update_ = millis(); this->is_setup_ = true; }); } @@ -52,6 +56,7 @@ void ADE7953::dump_config() { LOG_SENSOR(" ", "Active Power B Sensor", this->active_power_b_sensor_); LOG_SENSOR(" ", "Rective Power A Sensor", this->reactive_power_a_sensor_); LOG_SENSOR(" ", "Reactive Power B Sensor", this->reactive_power_b_sensor_); + ESP_LOGCONFIG(TAG, " USE_ACC_ENERGY_REGS: %d", this->use_acc_energy_regs_); ESP_LOGCONFIG(TAG, " PGA_V_8: 0x%X", pga_v_); ESP_LOGCONFIG(TAG, " PGA_IA_8: 0x%X", pga_ia_); ESP_LOGCONFIG(TAG, " PGA_IB_8: 0x%X", pga_ib_); @@ -85,6 +90,7 @@ void ADE7953::update() { uint32_t val; uint16_t val_16; + uint16_t reg; // Power factor err = this->ade_read_16(0x010A, &val_16); @@ -92,23 +98,36 @@ void ADE7953::update() { err = this->ade_read_16(0x010B, &val_16); ADE_PUBLISH(power_factor_b, (int16_t) val_16, (0x7FFF / 100.0f)); + float pf = ADE_POWER_FACTOR; + if (this->use_acc_energy_regs_) { + const uint32_t now = millis(); + const auto diff = now - this->last_update_; + this->last_update_ = now; + // prevent DIV/0 + pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000; + ESP_LOGVV(TAG, "ADE7953::update() diff=%d pf=%f", diff, pf); + } + // Apparent power - err = this->ade_read_32(0x0310, &val); - ADE_PUBLISH(apparent_power_a, (int32_t) val, 154.0f); - err = this->ade_read_32(0x0311, &val); - ADE_PUBLISH(apparent_power_b, (int32_t) val, 154.0f); + reg = this->use_acc_energy_regs_ ? 0x0322 : 0x0310; + err = this->ade_read_32(reg, &val); + ADE_PUBLISH(apparent_power_a, (int32_t) val, pf); + err = this->ade_read_32(reg + 1, &val); + ADE_PUBLISH(apparent_power_b, (int32_t) val, pf); // Active power - err = this->ade_read_32(0x0312, &val); - ADE_PUBLISH(active_power_a, (int32_t) val, 154.0f); - err = this->ade_read_32(0x0313, &val); - ADE_PUBLISH(active_power_b, (int32_t) val, 154.0f); + reg = this->use_acc_energy_regs_ ? 0x031E : 0x0312; + err = this->ade_read_32(reg, &val); + ADE_PUBLISH(active_power_a, (int32_t) val, pf); + err = this->ade_read_32(reg + 1, &val); + ADE_PUBLISH(active_power_b, (int32_t) val, pf); // Reactive power - err = this->ade_read_32(0x0314, &val); - ADE_PUBLISH(reactive_power_a, (int32_t) val, 154.0f); - err = this->ade_read_32(0x0315, &val); - ADE_PUBLISH(reactive_power_b, (int32_t) val, 154.0f); + reg = this->use_acc_energy_regs_ ? 0x0320 : 0x0314; + err = this->ade_read_32(reg, &val); + ADE_PUBLISH(reactive_power_a, (int32_t) val, pf); + err = this->ade_read_32(reg + 1, &val); + ADE_PUBLISH(reactive_power_b, (int32_t) val, pf); // Current err = this->ade_read_32(0x031A, &val); diff --git a/esphome/components/ade7953_base/ade7953_base.h b/esphome/components/ade7953_base/ade7953_base.h index f57a8aa1df..d711a5c6be 100644 --- a/esphome/components/ade7953_base/ade7953_base.h +++ b/esphome/components/ade7953_base/ade7953_base.h @@ -52,6 +52,8 @@ class ADE7953 : public PollingComponent, public sensor::Sensor { void set_awgain(uint32_t awgain) { awgain_ = awgain; } void set_bwgain(uint32_t bwgain) { bwgain_ = bwgain; } + void set_use_acc_energy_regs(bool use_acc_energy_regs) { use_acc_energy_regs_ = use_acc_energy_regs; } + void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; } @@ -103,6 +105,8 @@ class ADE7953 : public PollingComponent, public sensor::Sensor { uint32_t bigain_; uint32_t awgain_; uint32_t bwgain_; + bool use_acc_energy_regs_{false}; + uint32_t last_update_; virtual bool ade_write_8(uint16_t reg, uint8_t value) = 0; From 3abf2f1d1489608f9304ea7ccbd49f28fa8e208d Mon Sep 17 00:00:00 2001 From: Mark Spicer Date: Tue, 12 Mar 2024 21:04:59 -0400 Subject: [PATCH 1366/2607] feat: Add HTU31D Support (#5805) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/htu31d/__init__.py | 1 + esphome/components/htu31d/htu31d.cpp | 269 ++++++++++++++++++++ esphome/components/htu31d/htu31d.h | 33 +++ esphome/components/htu31d/sensor.py | 56 ++++ tests/components/htu31d/common.yaml | 9 + tests/components/htu31d/test.esp32-idf.yaml | 1 + tests/components/htu31d/test.esp32.yaml | 1 + tests/components/htu31d/test.esp8266.yaml | 1 + 9 files changed, 372 insertions(+) create mode 100644 esphome/components/htu31d/__init__.py create mode 100644 esphome/components/htu31d/htu31d.cpp create mode 100644 esphome/components/htu31d/htu31d.h create mode 100644 esphome/components/htu31d/sensor.py create mode 100644 tests/components/htu31d/common.yaml create mode 100644 tests/components/htu31d/test.esp32-idf.yaml create mode 100644 tests/components/htu31d/test.esp32.yaml create mode 100644 tests/components/htu31d/test.esp8266.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 483672bf54..c8d2a579d1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -152,6 +152,7 @@ esphome/components/honeywellabp2_i2c/* @jpfaff esphome/components/host/* @esphome/core esphome/components/hrxl_maxsonar_wr/* @netmikey esphome/components/hte501/* @Stock-M +esphome/components/htu31d/* @betterengineering esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hyt271/* @Philippe12 esphome/components/i2c/* @esphome/core diff --git a/esphome/components/htu31d/__init__.py b/esphome/components/htu31d/__init__.py new file mode 100644 index 0000000000..039693cb30 --- /dev/null +++ b/esphome/components/htu31d/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@betterengineering"] diff --git a/esphome/components/htu31d/htu31d.cpp b/esphome/components/htu31d/htu31d.cpp new file mode 100644 index 0000000000..928250a5b2 --- /dev/null +++ b/esphome/components/htu31d/htu31d.cpp @@ -0,0 +1,269 @@ +/* + * This file contains source code derived from Adafruit_HTU31D which is under + * the BSD license: + * Written by Limor Fried/Ladyada for Adafruit Industries. + * BSD license, all text above must be included in any redistribution. + * + * Modifications made by Mark Spicer. + */ + +#include "htu31d.h" +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace htu31d { + +/** Logging prefix */ +static const char *const TAG = "htu31d"; + +/** Default I2C address for the HTU31D. */ +static const uint8_t HTU31D_DEFAULT_I2CADDR = 0x40; + +/** Read temperature and humidity. */ +static const uint8_t HTU31D_READTEMPHUM = 0x00; + +/** Start a conversion! */ +static const uint8_t HTU31D_CONVERSION = 0x40; + +/** Read serial number command. */ +static const uint8_t HTU31D_READSERIAL = 0x0A; + +/** Enable heater */ +static const uint8_t HTU31D_HEATERON = 0x04; + +/** Disable heater */ +static const uint8_t HTU31D_HEATEROFF = 0x02; + +/** Reset command. */ +static const uint8_t HTU31D_RESET = 0x1E; + +/** Diagnostics command. */ +static const uint8_t HTU31D_DIAGNOSTICS = 0x08; + +/** + * Computes a CRC result for the provided input. + * + * @returns the computed CRC result for the provided input + */ +uint8_t compute_crc(uint32_t value) { + uint32_t polynom = 0x98800000; // x^8 + x^5 + x^4 + 1 + uint32_t msb = 0x80000000; + uint32_t mask = 0xFF800000; + uint32_t threshold = 0x00000080; + uint32_t result = value; + + while (msb != threshold) { + // Check if msb of current value is 1 and apply XOR mask + if (result & msb) + result = ((result ^ polynom) & mask) | (result & ~mask); + + // Shift by one + msb >>= 1; + mask >>= 1; + polynom >>= 1; + } + + return result; +} + +/** + * Resets the sensor and ensures that the devices serial number can be read over + * I2C. + */ +void HTU31DComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up esphome/components/htu31d HTU31D..."); + + if (!this->reset_()) { + this->mark_failed(); + return; + } + + if (this->read_serial_num_() == 0) { + this->mark_failed(); + return; + } +} + +/** + * Called once every update interval (user configured, defaults to 60s) and sets + * the current temperature and humidity. + */ +void HTU31DComponent::update() { + ESP_LOGD(TAG, "Checking temperature and humidty values"); + + // Trigger a conversion. From the spec sheet: The conversion command triggers + // a single temperature and humidity conversion. + if (this->write_register(HTU31D_CONVERSION, nullptr, 0) != i2c::ERROR_OK) { + this->status_set_warning(); + ESP_LOGE(TAG, "Received errror writing conversion register"); + return; + } + + // Wait conversion time. + this->set_timeout(20, [this]() { + uint8_t thdata[6]; + if (this->read_register(HTU31D_READTEMPHUM, thdata, 6) != i2c::ERROR_OK) { + this->status_set_warning(); + ESP_LOGE(TAG, "Error reading temperature/humidty register"); + return; + } + + // Calculate temperature value. + uint16_t raw_temp = encode_uint16(thdata[0], thdata[1]); + + uint8_t crc = compute_crc((uint32_t) raw_temp << 8); + if (crc != thdata[2]) { + this->status_set_warning(); + ESP_LOGE(TAG, "Error validating temperature CRC"); + return; + } + + float temperature = raw_temp; + temperature /= 65535.0f; + temperature *= 165; + temperature -= 40; + + if (this->temperature_ != nullptr) { + this->temperature_->publish_state(temperature); + } + + // Calculate humidty value. + uint16_t raw_hum = encode_uint16(thdata[3], thdata[4]); + + crc = compute_crc((uint32_t) raw_hum << 8); + if (crc != thdata[5]) { + this->status_set_warning(); + ESP_LOGE(TAG, "Error validating humidty CRC"); + return; + } + + float humidity = raw_hum; + humidity /= 65535.0f; + humidity *= 100; + + if (this->humidity_ != nullptr) { + this->humidity_->publish_state(humidity); + } + + ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity); + this->status_clear_warning(); + }); +} + +/** + * Logs the current compoenent config. + */ +void HTU31DComponent::dump_config() { + ESP_LOGCONFIG(TAG, "HTU31D:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with HTU31D failed!"); + } + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Temperature", this->temperature_); + LOG_SENSOR(" ", "Humidity", this->humidity_); +} + +/** + * Sends a 'reset' request to the HTU31D, followed by a 15ms delay. + * + * @returns True if was able to write the command successfully + */ +bool HTU31DComponent::reset_() { + if (this->write_register(HTU31D_RESET, nullptr, 0) != i2c::ERROR_OK) { + return false; + } + + delay(15); + return true; +} + +/** + * Reads the serial number from the device and checks the CRC. + * + * @returns the 24bit serial number from the device + */ +uint32_t HTU31DComponent::read_serial_num_() { + uint8_t reply[4]; + uint32_t serial = 0; + uint8_t padding = 0; + + // Verify we can read the device serial. + if (this->read_register(HTU31D_READSERIAL, reply, 4) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Error reading device serial"); + return 0; + } + + serial = encode_uint32(reply[0], reply[1], reply[2], padding); + + uint8_t crc = compute_crc(serial); + if (crc != reply[3]) { + ESP_LOGE(TAG, "Error validating serial CRC"); + return 0; + } + + ESP_LOGD(TAG, "Found serial: 0x%X", serial); + + return serial; +} + +/** + * Checks the diagnostics register to determine if the heater is currently + * enabled. + * + * @returns True if the heater is currently enabled, False otherwise + */ +bool HTU31DComponent::is_heater_enabled() { + uint8_t reply[1]; + uint8_t heater_enabled_position = 0; + uint8_t mask = 1 << heater_enabled_position; + uint8_t diagnostics = 0; + + if (this->read_register(HTU31D_DIAGNOSTICS, reply, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Error reading device serial"); + return false; + } + + diagnostics = reply[0]; + return (diagnostics & mask) != 0; +} + +/** + * Sets the heater state on or off. + * + * @param desired True for on, and False for off. + */ +void HTU31DComponent::set_heater_state(bool desired) { + bool current = this->is_heater_enabled(); + + // If the current state matches the desired state, there is nothing to do. + if (current == desired) { + return; + } + + // Update heater state. + esphome::i2c::ErrorCode err; + if (desired) { + err = this->write_register(HTU31D_HEATERON, nullptr, 0); + } else { + err = this->write_register(HTU31D_HEATEROFF, nullptr, 0); + } + + // Record any error. + if (err != i2c::ERROR_OK) { + this->status_set_warning(); + ESP_LOGE(TAG, "Received error updating heater state"); + return; + } +} + +/** + * Sets the startup priority for this component. + * + * @returns The startup priority + */ +float HTU31DComponent::get_setup_priority() const { return setup_priority::DATA; } +} // namespace htu31d +} // namespace esphome diff --git a/esphome/components/htu31d/htu31d.h b/esphome/components/htu31d/htu31d.h new file mode 100644 index 0000000000..9462133ced --- /dev/null +++ b/esphome/components/htu31d/htu31d.h @@ -0,0 +1,33 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace htu31d { + +class HTU31DComponent : public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; /// Setup (reset) the sensor and check connection. + void update() override; /// Update the sensor values (temperature+humidity). + void dump_config() override; /// Dumps the configuration values. + + void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; } + void set_humidity(sensor::Sensor *humidity) { this->humidity_ = humidity; } + + void set_heater_state(bool desired); + bool is_heater_enabled(); + + float get_setup_priority() const override; + + protected: + bool reset_(); + uint32_t read_serial_num_(); + + sensor::Sensor *temperature_{nullptr}; + sensor::Sensor *humidity_{nullptr}; +}; +} // namespace htu31d +} // namespace esphome diff --git a/esphome/components/htu31d/sensor.py b/esphome/components/htu31d/sensor.py new file mode 100644 index 0000000000..fe53aa376e --- /dev/null +++ b/esphome/components/htu31d/sensor.py @@ -0,0 +1,56 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_HUMIDITY, + CONF_ID, + CONF_TEMPERATURE, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PERCENT, +) + +DEPENDENCIES = ["i2c"] + +htu31d_ns = cg.esphome_ns.namespace("htu31d") +HTU31DComponent = htu31d_ns.class_( + "HTU31DComponent", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(HTU31DComponent), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=1, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x40)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature(sens)) + + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) + cg.add(var.set_humidity(sens)) diff --git a/tests/components/htu31d/common.yaml b/tests/components/htu31d/common.yaml new file mode 100644 index 0000000000..c8ef2fede9 --- /dev/null +++ b/tests/components/htu31d/common.yaml @@ -0,0 +1,9 @@ +i2c: + +sensor: + - platform: htu31d + temperature: + name: Living Room Temperature 7 + humidity: + name: Living Room Humidity 7 + update_interval: 15s diff --git a/tests/components/htu31d/test.esp32-idf.yaml b/tests/components/htu31d/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/htu31d/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/htu31d/test.esp32.yaml b/tests/components/htu31d/test.esp32.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/htu31d/test.esp32.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/htu31d/test.esp8266.yaml b/tests/components/htu31d/test.esp8266.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/htu31d/test.esp8266.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From b34b10888bf89777dbc887e6b17601737ab35859 Mon Sep 17 00:00:00 2001 From: Ettore Beltrame <42470585+E440QF@users.noreply.github.com> Date: Wed, 13 Mar 2024 02:16:02 +0100 Subject: [PATCH 1367/2607] Emmeti infrared climate support (#5197) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/emmeti/__init__.py | 0 esphome/components/emmeti/climate.py | 21 ++ esphome/components/emmeti/emmeti.cpp | 316 ++++++++++++++++++++ esphome/components/emmeti/emmeti.h | 109 +++++++ tests/components/emmeti/common.yaml | 14 + tests/components/emmeti/test.esp32-idf.yaml | 5 + tests/components/emmeti/test.esp32.yaml | 5 + tests/components/emmeti/test.esp8266.yaml | 5 + 9 files changed, 476 insertions(+) create mode 100644 esphome/components/emmeti/__init__.py create mode 100644 esphome/components/emmeti/climate.py create mode 100644 esphome/components/emmeti/emmeti.cpp create mode 100644 esphome/components/emmeti/emmeti.h create mode 100644 tests/components/emmeti/common.yaml create mode 100644 tests/components/emmeti/test.esp32-idf.yaml create mode 100644 tests/components/emmeti/test.esp32.yaml create mode 100644 tests/components/emmeti/test.esp8266.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c8d2a579d1..0a94c254d2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -103,6 +103,7 @@ esphome/components/duty_time/* @dudanov esphome/components/ee895/* @Stock-M esphome/components/ektf2232/touchscreen/* @jesserockz esphome/components/emc2101/* @ellull +esphome/components/emmeti/* @E440QF esphome/components/ens160/* @vincentscode esphome/components/ens210/* @itn3rd77 esphome/components/esp32/* @esphome/core diff --git a/esphome/components/emmeti/__init__.py b/esphome/components/emmeti/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/emmeti/climate.py b/esphome/components/emmeti/climate.py new file mode 100644 index 0000000000..36585061e6 --- /dev/null +++ b/esphome/components/emmeti/climate.py @@ -0,0 +1,21 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import climate_ir +from esphome.const import CONF_ID + +CODEOWNERS = ["@E440QF"] +AUTO_LOAD = ["climate_ir"] + +emmeti_ns = cg.esphome_ns.namespace("emmeti") +EmmetiClimate = emmeti_ns.class_("EmmetiClimate", climate_ir.ClimateIR) + +CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(EmmetiClimate), + } +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/emmeti/emmeti.cpp b/esphome/components/emmeti/emmeti.cpp new file mode 100644 index 0000000000..3cb184f868 --- /dev/null +++ b/esphome/components/emmeti/emmeti.cpp @@ -0,0 +1,316 @@ +#include "emmeti.h" +#include "esphome/components/remote_base/remote_base.h" + +namespace esphome { +namespace emmeti { + +static const char *const TAG = "emmeti.climate"; + +// setters +uint8_t EmmetiClimate::set_temp_() { + return (uint8_t) roundf(clamp(this->target_temperature, EMMETI_TEMP_MIN, EMMETI_TEMP_MAX) - EMMETI_TEMP_MIN); +} + +uint8_t EmmetiClimate::set_mode_() { + switch (this->mode) { + case climate::CLIMATE_MODE_COOL: + return EMMETI_MODE_COOL; + case climate::CLIMATE_MODE_DRY: + return EMMETI_MODE_DRY; + case climate::CLIMATE_MODE_HEAT: + return EMMETI_MODE_HEAT; + case climate::CLIMATE_MODE_FAN_ONLY: + return EMMETI_MODE_FAN; + case climate::CLIMATE_MODE_HEAT_COOL: + default: + return EMMETI_MODE_HEAT_COOL; + } +} + +uint8_t EmmetiClimate::set_fan_speed_() { + switch (this->fan_mode.value()) { + case climate::CLIMATE_FAN_LOW: + return EMMETI_FAN_1; + case climate::CLIMATE_FAN_MEDIUM: + return EMMETI_FAN_2; + case climate::CLIMATE_FAN_HIGH: + return EMMETI_FAN_3; + case climate::CLIMATE_FAN_AUTO: + default: + return EMMETI_FAN_AUTO; + } +} + +uint8_t EmmetiClimate::set_blades_() { + if (this->swing_mode == climate::CLIMATE_SWING_VERTICAL) { + switch (this->blades_) { + case EMMETI_BLADES_1: + case EMMETI_BLADES_2: + case EMMETI_BLADES_HIGH: + this->blades_ = EMMETI_BLADES_HIGH; + break; + case EMMETI_BLADES_3: + case EMMETI_BLADES_MID: + this->blades_ = EMMETI_BLADES_MID; + break; + case EMMETI_BLADES_4: + case EMMETI_BLADES_5: + case EMMETI_BLADES_LOW: + this->blades_ = EMMETI_BLADES_LOW; + break; + default: + this->blades_ = EMMETI_BLADES_FULL; + break; + } + } else { + switch (this->blades_) { + case EMMETI_BLADES_1: + case EMMETI_BLADES_2: + case EMMETI_BLADES_HIGH: + this->blades_ = EMMETI_BLADES_1; + break; + case EMMETI_BLADES_3: + case EMMETI_BLADES_MID: + this->blades_ = EMMETI_BLADES_3; + break; + case EMMETI_BLADES_4: + case EMMETI_BLADES_5: + case EMMETI_BLADES_LOW: + this->blades_ = EMMETI_BLADES_5; + break; + default: + this->blades_ = EMMETI_BLADES_STOP; + break; + } + } + return this->blades_; +} + +uint8_t EmmetiClimate::gen_checksum_() { return (this->set_temp_() + this->set_mode_() + 2) % 16; } + +// getters +float EmmetiClimate::get_temp_(uint8_t temp) { return (float) (temp + EMMETI_TEMP_MIN); } + +climate::ClimateMode EmmetiClimate::get_mode_(uint8_t mode) { + switch (mode) { + case EMMETI_MODE_COOL: + return climate::CLIMATE_MODE_COOL; + case EMMETI_MODE_DRY: + return climate::CLIMATE_MODE_DRY; + case EMMETI_MODE_HEAT: + return climate::CLIMATE_MODE_HEAT; + case EMMETI_MODE_HEAT_COOL: + return climate::CLIMATE_MODE_HEAT_COOL; + case EMMETI_MODE_FAN: + return climate::CLIMATE_MODE_FAN_ONLY; + default: + return climate::CLIMATE_MODE_HEAT_COOL; + } +} + +climate::ClimateFanMode EmmetiClimate::get_fan_speed_(uint8_t fan_speed) { + switch (fan_speed) { + case EMMETI_FAN_1: + return climate::CLIMATE_FAN_LOW; + case EMMETI_FAN_2: + return climate::CLIMATE_FAN_MEDIUM; + case EMMETI_FAN_3: + return climate::CLIMATE_FAN_HIGH; + case EMMETI_FAN_AUTO: + default: + return climate::CLIMATE_FAN_AUTO; + } +} + +climate::ClimateSwingMode EmmetiClimate::get_swing_(uint8_t bitmap) { + return (bitmap >> 1) & 0x01 ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; +} + +template T EmmetiClimate::reverse_(T val, size_t len) { + T result = 0; + for (size_t i = 0; i < len; i++) { + result |= ((val & 1 << i) != 0) << (len - 1 - i); + } + return result; +} + +template void EmmetiClimate::add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data) { + for (size_t i = len; i > 0; i--) { + data->mark(EMMETI_BIT_MARK); + data->space((val & (1 << (i - 1))) ? EMMETI_ONE_SPACE : EMMETI_ZERO_SPACE); + } +} + +template void EmmetiClimate::add_(T val, esphome::remote_base::RemoteTransmitData *data) { + data->mark(EMMETI_BIT_MARK); + data->space((val & 1) ? EMMETI_ONE_SPACE : EMMETI_ZERO_SPACE); +} + +template +void EmmetiClimate::reverse_add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data) { + this->add_(this->reverse_(val, len), len, data); +} + +bool EmmetiClimate::check_checksum_(uint8_t checksum) { + uint8_t expected = this->gen_checksum_(); + ESP_LOGV(TAG, "Expected checksum: %X", expected); + ESP_LOGV(TAG, "Checksum received: %X", checksum); + + return checksum == expected; +} + +void EmmetiClimate::transmit_state() { + auto transmit = this->transmitter_->transmit(); + auto *data = transmit.get_data(); + data->set_carrier_frequency(EMMETI_IR_FREQUENCY); + + data->mark(EMMETI_HEADER_MARK); + data->space(EMMETI_HEADER_SPACE); + + if (this->mode != climate::CLIMATE_MODE_OFF) { + this->reverse_add_(this->set_mode_(), 3, data); + this->add_(1, data); + this->reverse_add_(this->set_fan_speed_(), 2, data); + this->add_(this->swing_mode != climate::CLIMATE_SWING_OFF, data); + this->add_(0, data); // sleep mode + this->reverse_add_(this->set_temp_(), 4, data); + this->add_(0, 8, data); // zeros + this->add_(0, data); // turbo mode + this->add_(1, data); // light + this->add_(1, data); // tree icon thingy + this->add_(0, data); // blow mode + this->add_(0x52, 11, data); // idk + + data->mark(EMMETI_BIT_MARK); + data->space(EMMETI_MESSAGE_SPACE); + + this->reverse_add_(this->set_blades_(), 4, data); + this->add_(0, 4, data); // zeros + this->reverse_add_(2, 2, data); // thermometer + this->add_(0, 18, data); // zeros + this->reverse_add_(this->gen_checksum_(), 4, data); + } else { + this->add_(9, 12, data); + this->add_(0, 8, data); + this->add_(0x2052, 15, data); + data->mark(EMMETI_BIT_MARK); + data->space(EMMETI_MESSAGE_SPACE); + this->add_(0, 8, data); + this->add_(1, 2, data); + this->add_(0, 18, data); + this->add_(0x0C, 4, data); + } + data->mark(EMMETI_BIT_MARK); + data->space(0); + + transmit.perform(); +} + +bool EmmetiClimate::parse_state_frame_(EmmetiState curr_state) { + this->mode = this->get_mode_(curr_state.mode); + this->fan_mode = this->get_fan_speed_(curr_state.fan_speed); + this->target_temperature = this->get_temp_(curr_state.temp); + this->swing_mode = this->get_swing_(curr_state.bitmap); + // this->blades_ = curr_state.fan_pos; + if (!(curr_state.bitmap & 0x01)) { + this->mode = climate::CLIMATE_MODE_OFF; + } + + this->publish_state(); + return true; +} + +bool EmmetiClimate::on_receive(remote_base::RemoteReceiveData data) { + if (!data.expect_item(EMMETI_HEADER_MARK, EMMETI_HEADER_SPACE)) { + return false; + } + ESP_LOGD(TAG, "Received emmeti frame"); + + EmmetiState curr_state; + + for (size_t pos = 0; pos < 3; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.mode |= 1 << pos; + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + ESP_LOGD(TAG, "Mode: %d", curr_state.mode); + + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.bitmap |= 1 << 0; + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + + ESP_LOGD(TAG, "On: %d", curr_state.bitmap & 0x01); + + for (size_t pos = 0; pos < 2; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.fan_speed |= 1 << pos; + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + ESP_LOGD(TAG, "Fan speed: %d", curr_state.fan_speed); + + for (size_t pos = 0; pos < 2; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.bitmap |= 1 << (pos + 1); + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + ESP_LOGD(TAG, "Swing: %d", (curr_state.bitmap >> 1) & 0x01); + ESP_LOGD(TAG, "Sleep: %d", (curr_state.bitmap >> 2) & 0x01); + + for (size_t pos = 0; pos < 4; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.temp |= 1 << pos; + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + ESP_LOGD(TAG, "Temp: %d", curr_state.temp); + + for (size_t pos = 0; pos < 8; pos++) { + if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + for (size_t pos = 0; pos < 4; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + curr_state.bitmap |= 1 << (pos + 3); + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + ESP_LOGD(TAG, "Turbo: %d", (curr_state.bitmap >> 3) & 0x01); + ESP_LOGD(TAG, "Light: %d", (curr_state.bitmap >> 4) & 0x01); + ESP_LOGD(TAG, "Tree: %d", (curr_state.bitmap >> 5) & 0x01); + ESP_LOGD(TAG, "Blow: %d", (curr_state.bitmap >> 6) & 0x01); + + uint16_t control_data = 0; + for (size_t pos = 0; pos < 11; pos++) { + if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { + control_data |= 1 << pos; + } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { + return false; + } + } + + if (control_data != 0x250) { + return false; + } + + return this->parse_state_frame_(curr_state); +} + +} // namespace emmeti +} // namespace esphome diff --git a/esphome/components/emmeti/emmeti.h b/esphome/components/emmeti/emmeti.h new file mode 100644 index 0000000000..9bfb7a7a98 --- /dev/null +++ b/esphome/components/emmeti/emmeti.h @@ -0,0 +1,109 @@ +#pragma once + +#include "esphome/components/climate_ir/climate_ir.h" + +namespace esphome { +namespace emmeti { + +const uint8_t EMMETI_TEMP_MIN = 16; // Celsius +const uint8_t EMMETI_TEMP_MAX = 30; // Celsius + +// Modes + +enum EmmetiMode : uint8_t { + EMMETI_MODE_HEAT_COOL = 0x00, + EMMETI_MODE_COOL = 0x01, + EMMETI_MODE_DRY = 0x02, + EMMETI_MODE_FAN = 0x03, + EMMETI_MODE_HEAT = 0x04, +}; + +// Fan Speed + +enum EmmetiFanMode : uint8_t { + EMMETI_FAN_AUTO = 0x00, + EMMETI_FAN_1 = 0x01, + EMMETI_FAN_2 = 0x02, + EMMETI_FAN_3 = 0x03, +}; + +// Fan Position + +enum EmmetiBlades : uint8_t { + EMMETI_BLADES_STOP = 0x00, + EMMETI_BLADES_FULL = 0x01, + EMMETI_BLADES_1 = 0x02, + EMMETI_BLADES_2 = 0x03, + EMMETI_BLADES_3 = 0x04, + EMMETI_BLADES_4 = 0x05, + EMMETI_BLADES_5 = 0x06, + EMMETI_BLADES_LOW = 0x07, + EMMETI_BLADES_MID = 0x09, + EMMETI_BLADES_HIGH = 0x11, +}; + +// IR Transmission +const uint32_t EMMETI_IR_FREQUENCY = 38000; +const uint32_t EMMETI_HEADER_MARK = 9076; +const uint32_t EMMETI_HEADER_SPACE = 4408; +const uint32_t EMMETI_BIT_MARK = 660; +const uint32_t EMMETI_ONE_SPACE = 1630; +const uint32_t EMMETI_ZERO_SPACE = 530; +const uint32_t EMMETI_MESSAGE_SPACE = 20000; + +struct EmmetiState { + uint8_t mode = 0; + uint8_t bitmap = 0; + uint8_t fan_speed = 0; + uint8_t temp = 0; + uint8_t fan_pos = 0; + uint8_t th = 0; + uint8_t checksum = 0; +}; + +class EmmetiClimate : public climate_ir::ClimateIR { + public: + EmmetiClimate() + : climate_ir::ClimateIR(EMMETI_TEMP_MIN, EMMETI_TEMP_MAX, 1.0f, true, true, + {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, + climate::CLIMATE_FAN_HIGH}, + {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {} + + protected: + // Transmit via IR the state of this climate controller + void transmit_state() override; + // Handle received IR Buffer + bool on_receive(remote_base::RemoteReceiveData data) override; + bool parse_state_frame_(EmmetiState curr_state); + + // setters + uint8_t set_mode_(); + uint8_t set_temp_(); + uint8_t set_fan_speed_(); + uint8_t gen_checksum_(); + uint8_t set_blades_(); + + // getters + climate::ClimateMode get_mode_(uint8_t mode); + climate::ClimateFanMode get_fan_speed_(uint8_t fan); + void get_blades_(uint8_t fanpos); + // get swing + climate::ClimateSwingMode get_swing_(uint8_t bitmap); + float get_temp_(uint8_t temp); + + // check if the received frame is valid + bool check_checksum_(uint8_t checksum); + + template T reverse_(T val, size_t len); + + template void add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *ata); + + template void add_(T val, esphome::remote_base::RemoteTransmitData *data); + + template void reverse_add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data); + + uint8_t blades_ = EMMETI_BLADES_STOP; +}; + +} // namespace emmeti +} // namespace esphome diff --git a/tests/components/emmeti/common.yaml b/tests/components/emmeti/common.yaml new file mode 100644 index 0000000000..ac4201e19b --- /dev/null +++ b/tests/components/emmeti/common.yaml @@ -0,0 +1,14 @@ +remote_transmitter: + id: tx + pin: ${remote_transmitter_pin} + carrier_duty_percent: 100% + +remote_receiver: + id: rcvr + pin: ${remote_receiver_pin} + +climate: + - platform: emmeti + name: Emmeti + receiver_id: rcvr + transmitter_id: tx diff --git a/tests/components/emmeti/test.esp32-idf.yaml b/tests/components/emmeti/test.esp32-idf.yaml new file mode 100644 index 0000000000..2689ff279e --- /dev/null +++ b/tests/components/emmeti/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + remote_transmitter_pin: GPIO33 + remote_receiver_pin: GPIO32 + +<<: !include common.yaml diff --git a/tests/components/emmeti/test.esp32.yaml b/tests/components/emmeti/test.esp32.yaml new file mode 100644 index 0000000000..2689ff279e --- /dev/null +++ b/tests/components/emmeti/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + remote_transmitter_pin: GPIO33 + remote_receiver_pin: GPIO32 + +<<: !include common.yaml diff --git a/tests/components/emmeti/test.esp8266.yaml b/tests/components/emmeti/test.esp8266.yaml new file mode 100644 index 0000000000..2fb00aea61 --- /dev/null +++ b/tests/components/emmeti/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + remote_transmitter_pin: GPIO4 + remote_receiver_pin: GPIO5 + +<<: !include common.yaml From 64a47f840eecc10e463ac678e51788ecba827546 Mon Sep 17 00:00:00 2001 From: Chris Feenstra <73584137+cfeenstra1024@users.noreply.github.com> Date: Wed, 13 Mar 2024 04:01:22 +0100 Subject: [PATCH 1368/2607] Added Kamstrup Multical 40x component (#4200) Co-authored-by: Chris Feenstra Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: cfeenstra1024 --- CODEOWNERS | 1 + esphome/components/dfplayer/__init__.py | 3 +- esphome/components/ezo_pmp/__init__.py | 9 +- esphome/components/kamstrup_kmp/__init__.py | 0 .../components/kamstrup_kmp/kamstrup_kmp.cpp | 301 ++++++++++++++++++ .../components/kamstrup_kmp/kamstrup_kmp.h | 131 ++++++++ esphome/components/kamstrup_kmp/sensor.py | 132 ++++++++ esphome/components/media_player/__init__.py | 3 +- esphome/const.py | 1 + tests/components/kamstrup_kmp/common.yaml | 25 ++ .../kamstrup_kmp/test.esp32-idf.yaml | 5 + tests/components/kamstrup_kmp/test.esp32.yaml | 5 + .../components/kamstrup_kmp/test.esp8266.yaml | 5 + 13 files changed, 615 insertions(+), 6 deletions(-) create mode 100644 esphome/components/kamstrup_kmp/__init__.py create mode 100644 esphome/components/kamstrup_kmp/kamstrup_kmp.cpp create mode 100644 esphome/components/kamstrup_kmp/kamstrup_kmp.h create mode 100644 esphome/components/kamstrup_kmp/sensor.py create mode 100644 tests/components/kamstrup_kmp/common.yaml create mode 100644 tests/components/kamstrup_kmp/test.esp32-idf.yaml create mode 100644 tests/components/kamstrup_kmp/test.esp32.yaml create mode 100644 tests/components/kamstrup_kmp/test.esp8266.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 0a94c254d2..4c24096faa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -173,6 +173,7 @@ esphome/components/integration/* @OttoWinter esphome/components/internal_temperature/* @Mat931 esphome/components/interval/* @esphome/core esphome/components/json/* @OttoWinter +esphome/components/kamstrup_kmp/* @cfeenstra1024 esphome/components/key_collector/* @ssieb esphome/components/key_provider/* @ssieb esphome/components/kuntze/* @ssieb diff --git a/esphome/components/dfplayer/__init__.py b/esphome/components/dfplayer/__init__.py index 5ea04b4804..c37c9999aa 100644 --- a/esphome/components/dfplayer/__init__.py +++ b/esphome/components/dfplayer/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_FILE, CONF_DEVICE +from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_FILE, CONF_DEVICE, CONF_VOLUME from esphome.components import uart DEPENDENCIES = ["uart"] @@ -19,7 +19,6 @@ DFPlayerIsPlayingCondition = dfplayer_ns.class_( MULTI_CONF = True CONF_FOLDER = "folder" CONF_LOOP = "loop" -CONF_VOLUME = "volume" CONF_EQ_PRESET = "eq_preset" CONF_ON_FINISHED_PLAYBACK = "on_finished_playback" diff --git a/esphome/components/ezo_pmp/__init__.py b/esphome/components/ezo_pmp/__init__.py index e65fcf74ca..87cda41f89 100644 --- a/esphome/components/ezo_pmp/__init__.py +++ b/esphome/components/ezo_pmp/__init__.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c -from esphome.const import CONF_ADDRESS, CONF_COMMAND, CONF_ID, CONF_DURATION +from esphome.const import ( + CONF_ADDRESS, + CONF_COMMAND, + CONF_ID, + CONF_DURATION, + CONF_VOLUME, +) from esphome import automation from esphome.automation import maybe_simple_id @@ -9,7 +15,6 @@ CODEOWNERS = ["@carlos-sarmiento"] DEPENDENCIES = ["i2c"] MULTI_CONF = True -CONF_VOLUME = "volume" CONF_VOLUME_PER_MINUTE = "volume_per_minute" ezo_pmp_ns = cg.esphome_ns.namespace("ezo_pmp") diff --git a/esphome/components/kamstrup_kmp/__init__.py b/esphome/components/kamstrup_kmp/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp b/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp new file mode 100644 index 0000000000..b870d1b56d --- /dev/null +++ b/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp @@ -0,0 +1,301 @@ +#include "kamstrup_kmp.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace kamstrup_kmp { + +static const char *const TAG = "kamstrup_kmp"; + +void KamstrupKMPComponent::dump_config() { + ESP_LOGCONFIG(TAG, "kamstrup_kmp:"); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with Kamstrup meter failed!"); + } + LOG_UPDATE_INTERVAL(this); + + LOG_SENSOR(" ", "Heat Energy", this->heat_energy_sensor_); + LOG_SENSOR(" ", "Power", this->power_sensor_); + LOG_SENSOR(" ", "Temperature 1", this->temp1_sensor_); + LOG_SENSOR(" ", "Temperature 2", this->temp2_sensor_); + LOG_SENSOR(" ", "Temperature Difference", this->temp_diff_sensor_); + LOG_SENSOR(" ", "Flow", this->flow_sensor_); + LOG_SENSOR(" ", "Volume", this->volume_sensor_); + + for (int i = 0; i < this->custom_sensors_.size(); i++) { + LOG_SENSOR(" ", "Custom Sensor", this->custom_sensors_[i]); + ESP_LOGCONFIG(TAG, " Command: 0x%04X", this->custom_commands_[i]); + } + + this->check_uart_settings(1200, 2, uart::UART_CONFIG_PARITY_NONE, 8); +} + +float KamstrupKMPComponent::get_setup_priority() const { return setup_priority::DATA; } + +void KamstrupKMPComponent::update() { + if (this->heat_energy_sensor_ != nullptr) { + this->command_queue_.push(CMD_HEAT_ENERGY); + } + + if (this->power_sensor_ != nullptr) { + this->command_queue_.push(CMD_POWER); + } + + if (this->temp1_sensor_ != nullptr) { + this->command_queue_.push(CMD_TEMP1); + } + + if (this->temp2_sensor_ != nullptr) { + this->command_queue_.push(CMD_TEMP2); + } + + if (this->temp_diff_sensor_ != nullptr) { + this->command_queue_.push(CMD_TEMP_DIFF); + } + + if (this->flow_sensor_ != nullptr) { + this->command_queue_.push(CMD_FLOW); + } + + if (this->volume_sensor_ != nullptr) { + this->command_queue_.push(CMD_VOLUME); + } + + for (uint16_t custom_command : this->custom_commands_) { + this->command_queue_.push(custom_command); + } +} + +void KamstrupKMPComponent::loop() { + if (!this->command_queue_.empty()) { + uint16_t command = this->command_queue_.front(); + this->send_command_(command); + this->command_queue_.pop(); + } +} + +void KamstrupKMPComponent::send_command_(uint16_t command) { + uint32_t msg_len = 5; + uint8_t msg[msg_len]; + + msg[0] = 0x3F; + msg[1] = 0x10; + msg[2] = 0x01; + msg[3] = command >> 8; + msg[4] = command & 0xFF; + + this->clear_uart_rx_buffer_(); + this->send_message_(msg, msg_len); + this->read_command_(command); +} + +void KamstrupKMPComponent::send_message_(const uint8_t *msg, int msg_len) { + int buffer_len = msg_len + 2; + uint8_t buffer[buffer_len]; + + // Prepare the basic message and appand CRC + for (int i = 0; i < msg_len; i++) { + buffer[i] = msg[i]; + } + + buffer[buffer_len - 2] = 0; + buffer[buffer_len - 1] = 0; + + uint16_t crc = crc16_ccitt(buffer, buffer_len); + buffer[buffer_len - 2] = crc >> 8; + buffer[buffer_len - 1] = crc & 0xFF; + + // Prepare actual TX message + uint8_t tx_msg[20]; + int tx_msg_len = 1; + tx_msg[0] = 0x80; // prefix + + for (int i = 0; i < buffer_len; i++) { + if (buffer[i] == 0x06 || buffer[i] == 0x0d || buffer[i] == 0x1b || buffer[i] == 0x40 || buffer[i] == 0x80) { + tx_msg[tx_msg_len++] = 0x1b; + tx_msg[tx_msg_len++] = buffer[i] ^ 0xff; + } else { + tx_msg[tx_msg_len++] = buffer[i]; + } + } + + tx_msg[tx_msg_len++] = 0x0D; // EOM + + this->write_array(tx_msg, tx_msg_len); +} + +void KamstrupKMPComponent::clear_uart_rx_buffer_() { + uint8_t tmp; + while (this->available()) { + this->read_byte(&tmp); + } +} + +void KamstrupKMPComponent::read_command_(uint16_t command) { + uint8_t buffer[20] = {0}; + int buffer_len = 0; + int data; + int timeout = 250; // ms + + // Read the data from the UART + while (timeout > 0) { + if (this->available()) { + data = this->read(); + if (data > -1) { + if (data == 0x40) { // start of message + buffer_len = 0; + } + buffer[buffer_len++] = (uint8_t) data; + if (data == 0x0D) { + break; + } + } else { + ESP_LOGE(TAG, "Error while reading from UART"); + } + } else { + delay(1); + timeout--; + } + } + + if (timeout == 0 || buffer_len == 0) { + ESP_LOGE(TAG, "Request timed out"); + return; + } + + // Validate message (prefix and suffix) + if (buffer[0] != 0x40) { + ESP_LOGE(TAG, "Received invalid message (prefix mismatch received 0x%02X, expected 0x40)", buffer[0]); + return; + } + + if (buffer[buffer_len - 1] != 0x0D) { + ESP_LOGE(TAG, "Received invalid message (EOM mismatch received 0x%02X, expected 0x0D)", buffer[buffer_len - 1]); + return; + } + + // Decode + uint8_t msg[20] = {0}; + int msg_len = 0; + for (int i = 1; i < buffer_len - 1; i++) { + if (buffer[i] == 0x1B) { + msg[msg_len++] = buffer[i + 1] ^ 0xFF; + i++; + } else { + msg[msg_len++] = buffer[i]; + } + } + + // Validate CRC + if (crc16_ccitt(msg, msg_len)) { + ESP_LOGE(TAG, "Received invalid message (CRC mismatch)"); + return; + } + + // All seems good. Now parse the message + this->parse_command_message_(command, msg, msg_len); +} + +void KamstrupKMPComponent::parse_command_message_(uint16_t command, const uint8_t *msg, int msg_len) { + // Validate the message + if (msg_len < 8) { + ESP_LOGE(TAG, "Received invalid message (message too small)"); + return; + } + + if (msg[0] != 0x3F || msg[1] != 0x10) { + ESP_LOGE(TAG, "Received invalid message (invalid header received 0x%02X%02X, expected 0x3F10)", msg[0], msg[1]); + return; + } + + uint16_t recv_command = msg[2] << 8 | msg[3]; + if (recv_command != command) { + ESP_LOGE(TAG, "Received invalid message (invalid unexpected command received 0x%04X, expected 0x%04X)", + recv_command, command); + return; + } + + uint8_t unit_idx = msg[4]; + uint8_t mantissa_range = msg[5]; + + if (mantissa_range > 4) { + ESP_LOGE(TAG, "Received invalid message (mantissa size too large %d, expected 4)", mantissa_range); + return; + } + + // Calculate exponent + float exponent = msg[6] & 0x3F; + if (msg[6] & 0x40) { + exponent = -exponent; + } + exponent = powf(10, exponent); + if (msg[6] & 0x80) { + exponent = -exponent; + } + + // Calculate mantissa + uint32_t mantissa = 0; + for (int i = 0; i < mantissa_range; i++) { + mantissa <<= 8; + mantissa |= msg[i + 7]; + } + + // Calculate the actual value + float value = mantissa * exponent; + + // Set sensor value + this->set_sensor_value_(command, value, unit_idx); +} + +void KamstrupKMPComponent::set_sensor_value_(uint16_t command, float value, uint8_t unit_idx) { + const char *unit = UNITS[unit_idx]; + + // Standard sensors + if (command == CMD_HEAT_ENERGY && this->heat_energy_sensor_ != nullptr) { + this->heat_energy_sensor_->publish_state(value); + } else if (command == CMD_POWER && this->power_sensor_ != nullptr) { + this->power_sensor_->publish_state(value); + } else if (command == CMD_TEMP1 && this->temp1_sensor_ != nullptr) { + this->temp1_sensor_->publish_state(value); + } else if (command == CMD_TEMP2 && this->temp2_sensor_ != nullptr) { + this->temp2_sensor_->publish_state(value); + } else if (command == CMD_TEMP_DIFF && this->temp_diff_sensor_ != nullptr) { + this->temp_diff_sensor_->publish_state(value); + } else if (command == CMD_FLOW && this->flow_sensor_ != nullptr) { + this->flow_sensor_->publish_state(value); + } else if (command == CMD_VOLUME && this->volume_sensor_ != nullptr) { + this->volume_sensor_->publish_state(value); + } + + // Custom sensors + for (int i = 0; i < this->custom_commands_.size(); i++) { + if (command == this->custom_commands_[i]) { + this->custom_sensors_[i]->publish_state(value); + } + } + + ESP_LOGD(TAG, "Received value for command 0x%04X: %.3f [%s]", command, value, unit); +} + +uint16_t crc16_ccitt(const uint8_t *buffer, int len) { + uint32_t poly = 0x1021; + uint32_t reg = 0x00; + for (int i = 0; i < len; i++) { + int mask = 0x80; + while (mask > 0) { + reg <<= 1; + if (buffer[i] & mask) { + reg |= 1; + } + mask >>= 1; + if (reg & 0x10000) { + reg &= 0xffff; + reg ^= poly; + } + } + } + return (uint16_t) reg; +} + +} // namespace kamstrup_kmp +} // namespace esphome diff --git a/esphome/components/kamstrup_kmp/kamstrup_kmp.h b/esphome/components/kamstrup_kmp/kamstrup_kmp.h new file mode 100644 index 0000000000..c9cc9c5a39 --- /dev/null +++ b/esphome/components/kamstrup_kmp/kamstrup_kmp.h @@ -0,0 +1,131 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace kamstrup_kmp { + +/* + =========================================================================== + === KAMSTRUP KMP === + =========================================================================== + + Kamstrup Meter Protocol (KMP) is a protocol used with Kamstrup district + heating meters, e.g. Kamstrup MULTICAL 403. + These devices register consumed heat from a district heating system. + It does this by measuring the incoming and outgoing water temperature + and by measuring the water flow. The temperature difference (delta T) + together with the water flow results in consumed energy, typically + in giga joule (GJ). + + The Kamstrup Multical has an optical interface just above the display. + This interface is essentially an RS-232 interface using a proprietary + protocol (Kamstrup Meter Protocol [KMP]). + + The integration uses this optical interface to periodically read the + configured values (sensors) from the meter. Supported sensors are: + - Heat Energy [GJ] + - Current Power Consumption [kW] + - Temperature 1 [°C] + - Temperature 2 [°C] + - Temperature Difference [°K] + - Water Flow [l/h] + - Volume [m3] + + Apart from these supported 'fixed' sensors, the user can configure up to + five custom sensors. The KMP command (16 bit unsigned int) has to be + provided in that case. + + Note: + The optical interface is enabled as soon as a button on the meter is pushed. + The interface stays active for a few minutes. To keep the interface 'alive' + magnets must be placed around the optical sensor. + + Units: + Units are set using the regular Sensor config in the user yaml. However, + KMP does also send the correct unit with every value. When DEBUG logging + is enabled, the received value with the received unit are logged. + + Acknowledgement: + This interface was inspired by: + - https://atomstar.tweakblogs.net/blog/19110/reading-out-kamstrup-multical-402-403-with-home-built-optical-head + - https://wiki.hal9k.dk/projects/kamstrup +*/ + +// KMP Commands +static const uint16_t CMD_HEAT_ENERGY = 0x003C; +static const uint16_t CMD_POWER = 0x0050; +static const uint16_t CMD_TEMP1 = 0x0056; +static const uint16_t CMD_TEMP2 = 0x0057; +static const uint16_t CMD_TEMP_DIFF = 0x0059; +static const uint16_t CMD_FLOW = 0x004A; +static const uint16_t CMD_VOLUME = 0x0044; + +// KMP units +static const char *const UNITS[] = { + "", "Wh", "kWh", "MWh", "GWh", "J", "kJ", "MJ", "GJ", "Cal", + "kCal", "Mcal", "Gcal", "varh", "kvarh", "Mvarh", "Gvarh", "VAh", "kVAh", "MVAh", + "GVAh", "kW", "kW", "MW", "GW", "kvar", "kvar", "Mvar", "Gvar", "VA", + "kVA", "MVA", "GVA", "V", "A", "kV", "kA", "C", "K", "l", + "m3", "l/h", "m3/h", "m3xC", "ton", "ton/h", "h", "hh:mm:ss", "yy:mm:dd", "yyyy:mm:dd", + "mm:dd", "", "bar", "RTC", "ASCII", "m3 x 10", "ton x 10", "GJ x 10", "minutes", "Bitfield", + "s", "ms", "days", "RTC-Q", "Datetime"}; + +class KamstrupKMPComponent : public PollingComponent, public uart::UARTDevice { + public: + void set_heat_energy_sensor(sensor::Sensor *sensor) { this->heat_energy_sensor_ = sensor; } + void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; } + void set_temp1_sensor(sensor::Sensor *sensor) { this->temp1_sensor_ = sensor; } + void set_temp2_sensor(sensor::Sensor *sensor) { this->temp2_sensor_ = sensor; } + void set_temp_diff_sensor(sensor::Sensor *sensor) { this->temp_diff_sensor_ = sensor; } + void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; } + void set_volume_sensor(sensor::Sensor *sensor) { this->volume_sensor_ = sensor; } + void dump_config() override; + float get_setup_priority() const override; + void update() override; + void loop() override; + void add_custom_sensor(sensor::Sensor *sensor, uint16_t command) { + this->custom_sensors_.push_back(sensor); + this->custom_commands_.push_back(command); + } + + protected: + // Sensors + sensor::Sensor *heat_energy_sensor_{nullptr}; + sensor::Sensor *power_sensor_{nullptr}; + sensor::Sensor *temp1_sensor_{nullptr}; + sensor::Sensor *temp2_sensor_{nullptr}; + sensor::Sensor *temp_diff_sensor_{nullptr}; + sensor::Sensor *flow_sensor_{nullptr}; + sensor::Sensor *volume_sensor_{nullptr}; + + // Custom sensors and commands + std::vector custom_sensors_; + std::vector custom_commands_; + + // Command queue + std::queue command_queue_; + + // Methods + + // Sends a command to the meter and receives its response + void send_command_(uint16_t command); + // Sends a message to the meter. A prefix/suffix and CRC are added + void send_message_(const uint8_t *msg, int msg_len); + // Clears and data that might be in the UART Rx buffer + void clear_uart_rx_buffer_(); + // Reads and validates the response to a send command + void read_command_(uint16_t command); + // Parses a received message + void parse_command_message_(uint16_t command, const uint8_t *msg, int msg_len); + // Sets the received value to the correct sensor + void set_sensor_value_(uint16_t command, float value, uint8_t unit_idx); +}; + +// "true" CCITT CRC-16 +uint16_t crc16_ccitt(const uint8_t *buffer, int len); + +} // namespace kamstrup_kmp +} // namespace esphome diff --git a/esphome/components/kamstrup_kmp/sensor.py b/esphome/components/kamstrup_kmp/sensor.py new file mode 100644 index 0000000000..c9024e4a2b --- /dev/null +++ b/esphome/components/kamstrup_kmp/sensor.py @@ -0,0 +1,132 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, uart +from esphome.const import ( + CONF_COMMAND, + CONF_CUSTOM, + CONF_FLOW, + CONF_ID, + CONF_POWER, + CONF_VOLUME, + DEVICE_CLASS_EMPTY, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLUME, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + UNIT_CELSIUS, + UNIT_CUBIC_METER, + UNIT_EMPTY, + UNIT_KELVIN, + UNIT_KILOWATT, +) + +CODEOWNERS = ["@cfeenstra1024"] +DEPENDENCIES = ["uart"] + +kamstrup_kmp_ns = cg.esphome_ns.namespace("kamstrup_kmp") +KamstrupKMPComponent = kamstrup_kmp_ns.class_( + "KamstrupKMPComponent", cg.PollingComponent, uart.UARTDevice +) + +CONF_HEAT_ENERGY = "heat_energy" +CONF_TEMP1 = "temp1" +CONF_TEMP2 = "temp2" +CONF_TEMP_DIFF = "temp_diff" + +UNIT_GIGA_JOULE = "GJ" +UNIT_LITRE_PER_HOUR = "l/h" + +# Note: The sensor units are set automatically based un the received data from the meter +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(KamstrupKMPComponent), + cv.Optional(CONF_HEAT_ENERGY): sensor.sensor_schema( + accuracy_decimals=3, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_TOTAL_INCREASING, + unit_of_measurement=UNIT_GIGA_JOULE, + ), + cv.Optional(CONF_POWER): sensor.sensor_schema( + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_KILOWATT, + ), + cv.Optional(CONF_TEMP1): sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_CELSIUS, + ), + cv.Optional(CONF_TEMP2): sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_CELSIUS, + ), + cv.Optional(CONF_TEMP_DIFF): sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_KELVIN, + ), + cv.Optional(CONF_FLOW): sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLUME, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_LITRE_PER_HOUR, + ), + cv.Optional(CONF_VOLUME): sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLUME, + state_class=STATE_CLASS_TOTAL_INCREASING, + unit_of_measurement=UNIT_CUBIC_METER, + ), + cv.Optional(CONF_CUSTOM): cv.ensure_list( + sensor.sensor_schema( + accuracy_decimals=1, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_EMPTY, + ).extend({cv.Required(CONF_COMMAND): cv.hex_uint16_t}) + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(uart.UART_DEVICE_SCHEMA) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "kamstrup_kmp", baud_rate=1200, require_rx=True, require_tx=True +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + # Standard sensors + for key in [ + CONF_HEAT_ENERGY, + CONF_POWER, + CONF_TEMP1, + CONF_TEMP2, + CONF_TEMP_DIFF, + CONF_FLOW, + CONF_VOLUME, + ]: + if key not in config: + continue + conf = config[key] + sens = await sensor.new_sensor(conf) + cg.add(getattr(var, f"set_{key}_sensor")(sens)) + + # Custom sensors + if CONF_CUSTOM in config: + for conf in config[CONF_CUSTOM]: + sens = await sensor.new_sensor(conf) + cg.add(var.add_custom_sensor(sens, conf[CONF_COMMAND])) diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 80f5fc558a..86e038d76d 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -3,7 +3,7 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID +from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID, CONF_VOLUME from esphome.core import CORE from esphome.coroutine import coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -43,7 +43,6 @@ VolumeSetAction = media_player_ns.class_( ) -CONF_VOLUME = "volume" CONF_ON_IDLE = "on_idle" CONF_ON_PLAY = "on_play" CONF_ON_PAUSE = "on_pause" diff --git a/esphome/const.py b/esphome/const.py index 4e53970cdf..918cf94ed3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -856,6 +856,7 @@ CONF_VISUAL = "visual" CONF_VOLTAGE = "voltage" CONF_VOLTAGE_ATTENUATION = "voltage_attenuation" CONF_VOLTAGE_DIVIDER = "voltage_divider" +CONF_VOLUME = "volume" CONF_WAIT_TIME = "wait_time" CONF_WAIT_UNTIL = "wait_until" CONF_WAKEUP_PIN = "wakeup_pin" diff --git a/tests/components/kamstrup_kmp/common.yaml b/tests/components/kamstrup_kmp/common.yaml new file mode 100644 index 0000000000..b348d03c72 --- /dev/null +++ b/tests/components/kamstrup_kmp/common.yaml @@ -0,0 +1,25 @@ +uart: + tx_pin: ${uart_tx_pin} + rx_pin: ${uart_rx_pin} + baud_rate: 1200 + stop_bits: 2 + +sensor: + - platform: kamstrup_kmp + heat_energy: + name: Heat Energy + power: + name: Power + temp1: + name: Temperature 1 + temp2: + name: Temperature 2 + temp_diff: + name: Temperature Difference + flow: + name: Flow + volume: + name: Volume + custom: + - name: Custom 1 + command: 0x1234 diff --git a/tests/components/kamstrup_kmp/test.esp32-idf.yaml b/tests/components/kamstrup_kmp/test.esp32-idf.yaml new file mode 100644 index 0000000000..adc2c4d24a --- /dev/null +++ b/tests/components/kamstrup_kmp/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO1 + uart_rx_pin: GPIO3 + +<<: !include common.yaml diff --git a/tests/components/kamstrup_kmp/test.esp32.yaml b/tests/components/kamstrup_kmp/test.esp32.yaml new file mode 100644 index 0000000000..adc2c4d24a --- /dev/null +++ b/tests/components/kamstrup_kmp/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO1 + uart_rx_pin: GPIO3 + +<<: !include common.yaml diff --git a/tests/components/kamstrup_kmp/test.esp8266.yaml b/tests/components/kamstrup_kmp/test.esp8266.yaml new file mode 100644 index 0000000000..adc2c4d24a --- /dev/null +++ b/tests/components/kamstrup_kmp/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO1 + uart_rx_pin: GPIO3 + +<<: !include common.yaml From de436785254006cd84b490cefe2c55023ba75fc0 Mon Sep 17 00:00:00 2001 From: kev300 Date: Wed, 13 Mar 2024 04:25:38 +0100 Subject: [PATCH 1369/2607] =?UTF-8?q?add=20possibility=20to=20provide=20di?= =?UTF-8?q?fferent=20conversion=20times=20for=20Bus=20Voltage=E2=80=A6=20(?= =?UTF-8?q?#6327)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kevin Hübner --- esphome/components/ina226/ina226.cpp | 7 ++++--- esphome/components/ina226/ina226.h | 6 ++++-- esphome/components/ina226/sensor.py | 21 +++++++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/esphome/components/ina226/ina226.cpp b/esphome/components/ina226/ina226.cpp index 94016ad302..7a57c118af 100644 --- a/esphome/components/ina226/ina226.cpp +++ b/esphome/components/ina226/ina226.cpp @@ -55,10 +55,10 @@ void INA226Component::setup() { config.avg_samples = this->adc_avg_samples_; // Bus Voltage Conversion Time VBUSCT Bit Settings [8:6] (100 -> 1.1ms, 111 -> 8.244 ms) - config.bus_voltage_conversion_time = this->adc_time_; + config.bus_voltage_conversion_time = this->adc_time_voltage_; // Shunt Voltage Conversion Time VSHCT Bit Settings [5:3] (100 -> 1.1ms, 111 -> 8.244 ms) - config.shunt_voltage_conversion_time = this->adc_time_; + config.shunt_voltage_conversion_time = this->adc_time_current_; // Mode Settings [2:0] Combinations (111 -> Shunt and Bus, Continuous) config.mode = 0b111; @@ -93,7 +93,8 @@ void INA226Component::dump_config() { } LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " ADC Conversion Time: %d", INA226_ADC_TIMES[this->adc_time_ & 0b111]); + ESP_LOGCONFIG(TAG, " ADC Conversion Time Bus Voltage: %d", INA226_ADC_TIMES[this->adc_time_voltage_ & 0b111]); + ESP_LOGCONFIG(TAG, " ADC Conversion Time Shunt Voltage: %d", INA226_ADC_TIMES[this->adc_time_current_ & 0b111]); ESP_LOGCONFIG(TAG, " ADC Averaging Samples: %d", INA226_ADC_AVG_SAMPLES[this->adc_avg_samples_ & 0b111]); LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_); diff --git a/esphome/components/ina226/ina226.h b/esphome/components/ina226/ina226.h index 2af9c8c195..61214fea0e 100644 --- a/esphome/components/ina226/ina226.h +++ b/esphome/components/ina226/ina226.h @@ -50,7 +50,8 @@ class INA226Component : public PollingComponent, public i2c::I2CDevice { void set_shunt_resistance_ohm(float shunt_resistance_ohm) { shunt_resistance_ohm_ = shunt_resistance_ohm; } void set_max_current_a(float max_current_a) { max_current_a_ = max_current_a; } - void set_adc_time(AdcTime time) { adc_time_ = time; } + void set_adc_time_voltage(AdcTime time) { adc_time_voltage_ = time; } + void set_adc_time_current(AdcTime time) { adc_time_current_ = time; } void set_adc_avg_samples(AdcAvgSamples samples) { adc_avg_samples_ = samples; } void set_bus_voltage_sensor(sensor::Sensor *bus_voltage_sensor) { bus_voltage_sensor_ = bus_voltage_sensor; } @@ -61,7 +62,8 @@ class INA226Component : public PollingComponent, public i2c::I2CDevice { protected: float shunt_resistance_ohm_; float max_current_a_; - AdcTime adc_time_{AdcTime::ADC_TIME_1100US}; + AdcTime adc_time_voltage_{AdcTime::ADC_TIME_1100US}; + AdcTime adc_time_current_{AdcTime::ADC_TIME_1100US}; AdcAvgSamples adc_avg_samples_{AdcAvgSamples::ADC_AVG_SAMPLES_4}; uint32_t calibration_lsb_; sensor::Sensor *bus_voltage_sensor_{nullptr}; diff --git a/esphome/components/ina226/sensor.py b/esphome/components/ina226/sensor.py index 32fca504a9..0accc58c00 100644 --- a/esphome/components/ina226/sensor.py +++ b/esphome/components/ina226/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, + CONF_VOLTAGE, ) DEPENDENCIES = ["i2c"] @@ -92,7 +93,15 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_MAX_CURRENT, default=3.2): cv.All( cv.current, cv.Range(min=0.0) ), - cv.Optional(CONF_ADC_TIME, default="1100 us"): validate_adc_time, + cv.Optional(CONF_ADC_TIME, default="1100 us"): cv.Any( + validate_adc_time, + cv.Schema( + { + cv.Required(CONF_VOLTAGE): validate_adc_time, + cv.Required(CONF_CURRENT): validate_adc_time, + } + ), + ), cv.Optional(CONF_ADC_AVERAGING, default=4): cv.enum( ADC_AVG_SAMPLES, int=True ), @@ -110,7 +119,15 @@ async def to_code(config): cg.add(var.set_shunt_resistance_ohm(config[CONF_SHUNT_RESISTANCE])) cg.add(var.set_max_current_a(config[CONF_MAX_CURRENT])) - cg.add(var.set_adc_time(config[CONF_ADC_TIME])) + + adc_time_config = config[CONF_ADC_TIME] + if isinstance(adc_time_config, dict): + cg.add(var.set_adc_time_voltage(adc_time_config[CONF_VOLTAGE])) + cg.add(var.set_adc_time_current(adc_time_config[CONF_CURRENT])) + else: + cg.add(var.set_adc_time_voltage(adc_time_config)) + cg.add(var.set_adc_time_current(adc_time_config)) + cg.add(var.set_adc_avg_samples(config[CONF_ADC_AVERAGING])) if CONF_BUS_VOLTAGE in config: From 0ebb6efee691a4330050073ce74d60a8d63d65a4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:33:42 +1300 Subject: [PATCH 1370/2607] Bump version to 2024.3.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 918cf94ed3..c5e86444ab 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0-dev" +__version__ = "2024.3.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From bbf7e2be28ba0c01fd82f5ce02cf01b3e15f2a2c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:33:43 +1300 Subject: [PATCH 1371/2607] Bump version to 2024.4.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 918cf94ed3..8e3fd59ff0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0-dev" +__version__ = "2024.4.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From dbf50381f1ddbf9ab6a92ca78301f2edced55d03 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:42:54 +1100 Subject: [PATCH 1372/2607] SPI: Revert clk_pin to standard output pin schema (#6368) --- esphome/components/spi/__init__.py | 17 ++--------------- tests/components/spi/test.esp32-s3-idf.yaml | 3 ++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index c2335bd92a..2847c5bfa1 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -29,7 +29,6 @@ from esphome.const import ( PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, - CONF_ALLOW_OTHER_USES, CONF_DATA_PINS, ) from esphome.core import ( @@ -199,8 +198,6 @@ def get_hw_spi(config, available): def validate_spi_config(config): available = list(range(len(get_hw_interface_list()))) for spi in config: - # map pin number to schema - spi[CONF_CLK_PIN] = pins.gpio_output_pin_schema(spi[CONF_CLK_PIN]) interface = spi[CONF_INTERFACE] if interface == "software": pass @@ -257,21 +254,11 @@ def get_spi_interface(index): return "new SPIClass(HSPI)" -# Do not use a pin schema for the number, as that will trigger a pin reuse error due to duplication of the -# clock pin in the standard and quad schemas. -clk_pin_validator = cv.maybe_simple_value( - { - cv.Required(CONF_NUMBER): cv.Any(cv.int_, cv.string), - cv.Optional(CONF_ALLOW_OTHER_USES): cv.boolean, - }, - key=CONF_NUMBER, -) - SPI_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(SPIComponent), - cv.Required(CONF_CLK_PIN): clk_pin_validator, + cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_FORCE_SW): cv.invalid( @@ -291,7 +278,7 @@ SPI_QUAD_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(QuadSPIComponent), - cv.Required(CONF_CLK_PIN): clk_pin_validator, + cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_DATA_PINS): cv.All( cv.ensure_list(pins.internal_gpio_output_pin_number), cv.Length(min=4, max=4), diff --git a/tests/components/spi/test.esp32-s3-idf.yaml b/tests/components/spi/test.esp32-s3-idf.yaml index 3aae21cbeb..8db934023a 100644 --- a/tests/components/spi/test.esp32-s3-idf.yaml +++ b/tests/components/spi/test.esp32-s3-idf.yaml @@ -2,7 +2,8 @@ spi: - id: spi_id_1 type: single clk_pin: - number: GPIO7 + number: GPIO0 + ignore_strapping_warning: true allow_other_uses: false mosi_pin: GPIO6 interface: hardware From df5dfb8087ebb78d85e8789ab88e543f3e683b39 Mon Sep 17 00:00:00 2001 From: Attila Farago Date: Thu, 14 Mar 2024 03:56:17 +0100 Subject: [PATCH 1373/2607] Allow button press action in web_server to be executed via GET method (#5938) --- esphome/components/web_server/web_server.cpp | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index ba787239da..69d601ed49 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -486,7 +486,7 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->switch_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -517,7 +517,7 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM for (button::Button *obj : App.get_buttons()) { if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_POST && match.method == "press") { + if (match.method == "press") { this->schedule_([obj]() { obj->press(); }); request->send(200); return; @@ -572,7 +572,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->fan_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -630,7 +630,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->light_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -736,7 +736,7 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->cover_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); continue; @@ -805,7 +805,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->number_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -910,7 +910,7 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->text_json(obj, obj->state, DETAIL_STATE); request->send(200, "text/json", data.c_str()); return; @@ -961,7 +961,7 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { auto detail = DETAIL_STATE; auto *param = request->getParam("detail"); if (param && param->value() == "all") { @@ -1016,7 +1016,7 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->climate_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -1162,7 +1162,7 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->lock_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "lock") { @@ -1201,7 +1201,7 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -1251,7 +1251,7 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { #endif #ifdef USE_BUTTON - if (request->method() == HTTP_POST && match.domain == "button") + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "button") return true; #endif From 72d1fa67fa212558696398d685f3af84fe2dc7fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:26:10 +1300 Subject: [PATCH 1374/2607] Bump docker/login-action from 3.0.0 to 3.1.0 (#6367) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 61f5ba4b23..0771aa0f20 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -91,12 +91,12 @@ jobs: uses: docker/setup-qemu-action@v3.0.0 - name: Log in to docker hub - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -167,13 +167,13 @@ jobs: - name: Log in to docker hub if: matrix.registry == 'dockerhub' - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry if: matrix.registry == 'ghcr' - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: registry: ghcr.io username: ${{ github.actor }} From fa4adb61f4a29347cd585b97c591b4a490f8034f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:28:05 +1300 Subject: [PATCH 1375/2607] Bump peter-evans/create-pull-request from 6.0.1 to 6.0.2 (#6361) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index ef3c04b595..36fce2bbcf 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -37,7 +37,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.1 + uses: peter-evans/create-pull-request@v6.0.2 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From d3842a7ab49c32813185d00e4b6d8399c2b1dad7 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 13 Mar 2024 22:08:57 -0700 Subject: [PATCH 1376/2607] fix servo restore (#6370) --- esphome/components/servo/servo.cpp | 35 +++++++++++++++++++++++++----- esphome/components/servo/servo.h | 22 +++++-------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/esphome/components/servo/servo.cpp b/esphome/components/servo/servo.cpp index 666c017dea..18e8c8087e 100644 --- a/esphome/components/servo/servo.cpp +++ b/esphome/components/servo/servo.cpp @@ -19,13 +19,28 @@ void Servo::dump_config() { ESP_LOGCONFIG(TAG, " run duration: %" PRIu32 " ms", this->transition_length_); } +void Servo::setup() { + float v; + if (this->restore_) { + this->rtc_ = global_preferences->make_preference(global_servo_id); + global_servo_id++; + if (this->rtc_.load(&v)) { + this->target_value_ = v; + this->internal_write(v); + this->state_ = STATE_ATTACHED; + this->start_millis_ = millis(); + return; + } + } + this->detach(); +} + void Servo::loop() { // check if auto_detach_time_ is set and servo reached target if (this->auto_detach_time_ && this->state_ == STATE_TARGET_REACHED) { if (millis() - this->start_millis_ > this->auto_detach_time_) { this->detach(); this->start_millis_ = 0; - this->state_ = STATE_DETACHED; ESP_LOGD(TAG, "Servo detached on auto_detach_time"); } } @@ -54,8 +69,11 @@ void Servo::loop() { void Servo::write(float value) { value = clamp(value, -1.0f, 1.0f); - if (this->target_value_ == value) + if ((this->state_ == STATE_DETACHED) && (this->target_value_ == value)) { this->internal_write(value); + } else { + this->save_level_(value); + } this->target_value_ = value; this->source_value_ = this->current_value_; this->state_ = STATE_ATTACHED; @@ -72,11 +90,18 @@ void Servo::internal_write(float value) { level = lerp(value, this->idle_level_, this->max_level_); } this->output_->set_level(level); - if (this->target_value_ == this->current_value_) { - this->save_level_(level); - } this->current_value_ = value; } +void Servo::detach() { + this->state_ = STATE_DETACHED; + this->output_->set_level(0.0f); +} + +void Servo::save_level_(float v) { + if (this->restore_) + this->rtc_.save(&v); +} + } // namespace servo } // namespace esphome diff --git a/esphome/components/servo/servo.h b/esphome/components/servo/servo.h index e2e3823158..13a7472ae5 100644 --- a/esphome/components/servo/servo.h +++ b/esphome/components/servo/servo.h @@ -17,22 +17,8 @@ class Servo : public Component { void loop() override; void write(float value); void internal_write(float value); - void detach() { - this->output_->set_level(0.0f); - this->save_level_(0.0f); - } - void setup() override { - float v; - if (this->restore_) { - this->rtc_ = global_preferences->make_preference(global_servo_id); - global_servo_id++; - if (this->rtc_.load(&v)) { - this->output_->set_level(v); - return; - } - } - this->detach(); - } + void detach(); + void setup() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } void set_min_level(float min_level) { min_level_ = min_level; } @@ -42,8 +28,10 @@ class Servo : public Component { void set_auto_detach_time(uint32_t auto_detach_time) { auto_detach_time_ = auto_detach_time; } void set_transition_length(uint32_t transition_length) { transition_length_ = transition_length; } + bool has_reached_target() { return this->current_value_ == this->target_value_; } + protected: - void save_level_(float v) { this->rtc_.save(&v); } + void save_level_(float v); output::FloatOutput *output_; float min_level_ = 0.0300f; From 4e850c3f325d8083a586020a5aa64cc1fe08f006 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 14 Mar 2024 21:26:29 +0100 Subject: [PATCH 1377/2607] Don't try to get IPv6 addresses when disabled (#6366) --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index d7241fb66c..35e6c57e62 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -157,7 +157,7 @@ network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { } else { addresses[0] = network::IPAddress(&ip.ip); } -#if LWIP_IPV6 +#if USE_NETWORK_IPV6 ip6_addr_t ipv6; err = tcpip_adapter_get_ip6_global(TCPIP_ADAPTER_IF_STA, &ipv6); if (err != ESP_OK) { @@ -171,7 +171,7 @@ network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { } else { addresses[2] = network::IPAddress(&ipv6); } -#endif /* LWIP_IPV6 */ +#endif /* USE_NETWORK_IPV6 */ return addresses; } From b7af94c76fde3f92a403755117bd8faeae9acf43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 12:39:32 +1300 Subject: [PATCH 1378/2607] Bump docker/build-push-action from 5.2.0 to 5.3.0 in /.github/actions/build-image (#6373) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index f93cf61abb..838bc362a1 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -36,7 +36,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v5.2.0 + uses: docker/build-push-action@v5.3.0 with: context: . file: ./docker/Dockerfile @@ -67,7 +67,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v5.2.0 + uses: docker/build-push-action@v5.3.0 with: context: . file: ./docker/Dockerfile From e42ab710291e50b9a1cdd81355cea086a8cd38e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 12:42:38 +1300 Subject: [PATCH 1379/2607] Bump docker/setup-buildx-action from 3.1.0 to 3.2.0 (#6372) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 1637f69954..8a7b35fe33 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.1.0 + uses: docker/setup-buildx-action@v3.2.0 - name: Set up QEMU uses: docker/setup-qemu-action@v3.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0771aa0f20..6b567b5b6f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.1.0 + uses: docker/setup-buildx-action@v3.2.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.0.0 @@ -163,7 +163,7 @@ jobs: name: digests-${{ matrix.image.target }}-${{ matrix.registry }} path: /tmp/digests - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.1.0 + uses: docker/setup-buildx-action@v3.2.0 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From e33e09a6859a7bc1bd11d163e8139b1019140e9f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:42:54 +1100 Subject: [PATCH 1380/2607] SPI: Revert clk_pin to standard output pin schema (#6368) --- esphome/components/spi/__init__.py | 17 ++--------------- tests/components/spi/test.esp32-s3-idf.yaml | 3 ++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index c2335bd92a..2847c5bfa1 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -29,7 +29,6 @@ from esphome.const import ( PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, - CONF_ALLOW_OTHER_USES, CONF_DATA_PINS, ) from esphome.core import ( @@ -199,8 +198,6 @@ def get_hw_spi(config, available): def validate_spi_config(config): available = list(range(len(get_hw_interface_list()))) for spi in config: - # map pin number to schema - spi[CONF_CLK_PIN] = pins.gpio_output_pin_schema(spi[CONF_CLK_PIN]) interface = spi[CONF_INTERFACE] if interface == "software": pass @@ -257,21 +254,11 @@ def get_spi_interface(index): return "new SPIClass(HSPI)" -# Do not use a pin schema for the number, as that will trigger a pin reuse error due to duplication of the -# clock pin in the standard and quad schemas. -clk_pin_validator = cv.maybe_simple_value( - { - cv.Required(CONF_NUMBER): cv.Any(cv.int_, cv.string), - cv.Optional(CONF_ALLOW_OTHER_USES): cv.boolean, - }, - key=CONF_NUMBER, -) - SPI_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(SPIComponent), - cv.Required(CONF_CLK_PIN): clk_pin_validator, + cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_FORCE_SW): cv.invalid( @@ -291,7 +278,7 @@ SPI_QUAD_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(QuadSPIComponent), - cv.Required(CONF_CLK_PIN): clk_pin_validator, + cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_DATA_PINS): cv.All( cv.ensure_list(pins.internal_gpio_output_pin_number), cv.Length(min=4, max=4), diff --git a/tests/components/spi/test.esp32-s3-idf.yaml b/tests/components/spi/test.esp32-s3-idf.yaml index 3aae21cbeb..8db934023a 100644 --- a/tests/components/spi/test.esp32-s3-idf.yaml +++ b/tests/components/spi/test.esp32-s3-idf.yaml @@ -2,7 +2,8 @@ spi: - id: spi_id_1 type: single clk_pin: - number: GPIO7 + number: GPIO0 + ignore_strapping_warning: true allow_other_uses: false mosi_pin: GPIO6 interface: hardware From 76c4bfbed368850a63048c1ddfce4e631d3cef2e Mon Sep 17 00:00:00 2001 From: Attila Farago Date: Thu, 14 Mar 2024 03:56:17 +0100 Subject: [PATCH 1381/2607] Allow button press action in web_server to be executed via GET method (#5938) --- esphome/components/web_server/web_server.cpp | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index ba787239da..69d601ed49 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -486,7 +486,7 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->switch_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -517,7 +517,7 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM for (button::Button *obj : App.get_buttons()) { if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_POST && match.method == "press") { + if (match.method == "press") { this->schedule_([obj]() { obj->press(); }); request->send(200); return; @@ -572,7 +572,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->fan_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -630,7 +630,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->light_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { @@ -736,7 +736,7 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->cover_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); continue; @@ -805,7 +805,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->number_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -910,7 +910,7 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->text_json(obj, obj->state, DETAIL_STATE); request->send(200, "text/json", data.c_str()); return; @@ -961,7 +961,7 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { auto detail = DETAIL_STATE; auto *param = request->getParam("detail"); if (param && param->value() == "all") { @@ -1016,7 +1016,7 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->climate_json(obj, DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -1162,7 +1162,7 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->lock_json(obj, obj->state, DETAIL_STATE); request->send(200, "application/json", data.c_str()); } else if (match.method == "lock") { @@ -1201,7 +1201,7 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { + if (request->method() == HTTP_GET && match.method.empty()) { std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE); request->send(200, "application/json", data.c_str()); return; @@ -1251,7 +1251,7 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { #endif #ifdef USE_BUTTON - if (request->method() == HTTP_POST && match.domain == "button") + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "button") return true; #endif From 92fbc61c46d4229e00bb5fbc42b0f22b55126330 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 13 Mar 2024 22:08:57 -0700 Subject: [PATCH 1382/2607] fix servo restore (#6370) --- esphome/components/servo/servo.cpp | 35 +++++++++++++++++++++++++----- esphome/components/servo/servo.h | 22 +++++-------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/esphome/components/servo/servo.cpp b/esphome/components/servo/servo.cpp index 666c017dea..18e8c8087e 100644 --- a/esphome/components/servo/servo.cpp +++ b/esphome/components/servo/servo.cpp @@ -19,13 +19,28 @@ void Servo::dump_config() { ESP_LOGCONFIG(TAG, " run duration: %" PRIu32 " ms", this->transition_length_); } +void Servo::setup() { + float v; + if (this->restore_) { + this->rtc_ = global_preferences->make_preference(global_servo_id); + global_servo_id++; + if (this->rtc_.load(&v)) { + this->target_value_ = v; + this->internal_write(v); + this->state_ = STATE_ATTACHED; + this->start_millis_ = millis(); + return; + } + } + this->detach(); +} + void Servo::loop() { // check if auto_detach_time_ is set and servo reached target if (this->auto_detach_time_ && this->state_ == STATE_TARGET_REACHED) { if (millis() - this->start_millis_ > this->auto_detach_time_) { this->detach(); this->start_millis_ = 0; - this->state_ = STATE_DETACHED; ESP_LOGD(TAG, "Servo detached on auto_detach_time"); } } @@ -54,8 +69,11 @@ void Servo::loop() { void Servo::write(float value) { value = clamp(value, -1.0f, 1.0f); - if (this->target_value_ == value) + if ((this->state_ == STATE_DETACHED) && (this->target_value_ == value)) { this->internal_write(value); + } else { + this->save_level_(value); + } this->target_value_ = value; this->source_value_ = this->current_value_; this->state_ = STATE_ATTACHED; @@ -72,11 +90,18 @@ void Servo::internal_write(float value) { level = lerp(value, this->idle_level_, this->max_level_); } this->output_->set_level(level); - if (this->target_value_ == this->current_value_) { - this->save_level_(level); - } this->current_value_ = value; } +void Servo::detach() { + this->state_ = STATE_DETACHED; + this->output_->set_level(0.0f); +} + +void Servo::save_level_(float v) { + if (this->restore_) + this->rtc_.save(&v); +} + } // namespace servo } // namespace esphome diff --git a/esphome/components/servo/servo.h b/esphome/components/servo/servo.h index e2e3823158..13a7472ae5 100644 --- a/esphome/components/servo/servo.h +++ b/esphome/components/servo/servo.h @@ -17,22 +17,8 @@ class Servo : public Component { void loop() override; void write(float value); void internal_write(float value); - void detach() { - this->output_->set_level(0.0f); - this->save_level_(0.0f); - } - void setup() override { - float v; - if (this->restore_) { - this->rtc_ = global_preferences->make_preference(global_servo_id); - global_servo_id++; - if (this->rtc_.load(&v)) { - this->output_->set_level(v); - return; - } - } - this->detach(); - } + void detach(); + void setup() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } void set_min_level(float min_level) { min_level_ = min_level; } @@ -42,8 +28,10 @@ class Servo : public Component { void set_auto_detach_time(uint32_t auto_detach_time) { auto_detach_time_ = auto_detach_time; } void set_transition_length(uint32_t transition_length) { transition_length_ = transition_length; } + bool has_reached_target() { return this->current_value_ == this->target_value_; } + protected: - void save_level_(float v) { this->rtc_.save(&v); } + void save_level_(float v); output::FloatOutput *output_; float min_level_ = 0.0300f; From ca85a41a724db49582e82b31d4e4a813dd272250 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 14 Mar 2024 21:26:29 +0100 Subject: [PATCH 1383/2607] Don't try to get IPv6 addresses when disabled (#6366) --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index d7241fb66c..35e6c57e62 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -157,7 +157,7 @@ network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { } else { addresses[0] = network::IPAddress(&ip.ip); } -#if LWIP_IPV6 +#if USE_NETWORK_IPV6 ip6_addr_t ipv6; err = tcpip_adapter_get_ip6_global(TCPIP_ADAPTER_IF_STA, &ipv6); if (err != ESP_OK) { @@ -171,7 +171,7 @@ network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { } else { addresses[2] = network::IPAddress(&ipv6); } -#endif /* LWIP_IPV6 */ +#endif /* USE_NETWORK_IPV6 */ return addresses; } From 83cc7b9d48815d7da0c606ef26450344e575386f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:23:12 +1300 Subject: [PATCH 1384/2607] Bump version to 2024.3.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c5e86444ab..4259c82ad7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0b1" +__version__ = "2024.3.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6e8760eba0dd1b183a38cc3105a6e9b563885e99 Mon Sep 17 00:00:00 2001 From: Federico Ferretti Date: Sat, 16 Mar 2024 02:17:01 +0100 Subject: [PATCH 1385/2607] Fix deep_sleep for ESP32-C6 (#6377) --- esphome/components/deep_sleep/deep_sleep_component.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/deep_sleep/deep_sleep_component.cpp b/esphome/components/deep_sleep/deep_sleep_component.cpp index 328e972e6b..97fdf11366 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.cpp +++ b/esphome/components/deep_sleep/deep_sleep_component.cpp @@ -81,7 +81,7 @@ void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) { #endif #if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C3) +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; } @@ -121,7 +121,7 @@ void DeepSleepComponent::begin_sleep(bool manual) { App.run_safe_shutdown_hooks(); #if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C3) +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) if (this->sleep_duration_.has_value()) esp_sleep_enable_timer_wakeup(*this->sleep_duration_); if (this->wakeup_pin_ != nullptr) { @@ -140,7 +140,7 @@ void DeepSleepComponent::begin_sleep(bool manual) { esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); } #endif -#ifdef USE_ESP32_VARIANT_ESP32C3 +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) if (this->sleep_duration_.has_value()) esp_sleep_enable_timer_wakeup(*this->sleep_duration_); if (this->wakeup_pin_ != nullptr) { From 5d96b5c52befc30e8649a929c3d6f0fd29229e72 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Sat, 16 Mar 2024 01:21:44 +0000 Subject: [PATCH 1386/2607] Use AQI device class (#6376) --- esphome/components/sen5x/sensor.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/sen5x/sensor.py b/esphome/components/sen5x/sensor.py index 4bc4a138a3..67bd627f7f 100644 --- a/esphome/components/sen5x/sensor.py +++ b/esphome/components/sen5x/sensor.py @@ -14,13 +14,12 @@ from esphome.const import ( CONF_PM_4_0, CONF_STORE_BASELINE, CONF_TEMPERATURE, + DEVICE_CLASS_AQI, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, ICON_CHEMICAL_WEAPON, ICON_RADIATOR, ICON_THERMOMETER, @@ -132,13 +131,13 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_VOC): sensor.sensor_schema( icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_AQI, state_class=STATE_CLASS_MEASUREMENT, ).extend(GAS_SENSOR), cv.Optional(CONF_NOX): sensor.sensor_schema( icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_NITROUS_OXIDE, + device_class=DEVICE_CLASS_AQI, state_class=STATE_CLASS_MEASUREMENT, ).extend(GAS_SENSOR), cv.Optional(CONF_STORE_BASELINE, default=True): cv.boolean, From 1148d41a66f37dcb3b37bb10feb9ba8d52348824 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 16 Mar 2024 14:22:34 +1300 Subject: [PATCH 1387/2607] Fix list-components when PR is not targeting dev (#6375) --- .github/workflows/ci.yml | 15 ++++++++++----- script/helpers.py | 4 ++-- script/list-components.py | 11 ++++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3de879176..47709739dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,6 +398,7 @@ jobs: runs-on: ubuntu-latest needs: - common + if: github.event_name == 'pull_request' outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -406,10 +407,14 @@ jobs: with: # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. fetch-depth: 500 - - name: Fetch dev branch + - name: Get target branch + id: target-branch run: | - git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/dev*:refs/remotes/origin/dev* +refs/tags/dev*:refs/tags/dev* - git merge-base refs/remotes/origin/dev HEAD + echo "branch=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT + - name: Fetch ${{ steps.target-branch.outputs.branch }} branch + run: | + git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/${{ steps.target-branch.outputs.branch }}:refs/remotes/origin/${{ steps.target-branch.outputs.branch }} + git merge-base refs/remotes/origin/${{ steps.target-branch.outputs.branch }} HEAD - name: Restore Python uses: ./.github/actions/restore-python with: @@ -419,7 +424,7 @@ jobs: id: set-matrix run: | . venv/bin/activate - echo "matrix=$(script/list-components.py --changed | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + echo "matrix=$(script/list-components.py --changed --branch ${{ steps.target-branch.outputs.branch }} | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT test-build-components: name: Component test ${{ matrix.file }} @@ -427,7 +432,7 @@ jobs: needs: - common - list-components - if: ${{ needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }} + if: ${{ github.event_name == 'pull_request' && needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }} strategy: fail-fast: false max-parallel: 2 diff --git a/script/helpers.py b/script/helpers.py index a971fdf475..52b0658fb6 100644 --- a/script/helpers.py +++ b/script/helpers.py @@ -70,11 +70,11 @@ def splitlines_no_ends(string): return [s.strip() for s in string.splitlines()] -def changed_files(): +def changed_files(branch="dev"): check_remotes = ["upstream", "origin"] check_remotes.extend(splitlines_no_ends(get_output("git", "remote"))) for remote in check_remotes: - command = ["git", "merge-base", f"refs/remotes/{remote}/dev", "HEAD"] + command = ["git", "merge-base", f"refs/remotes/{remote}/{branch}", "HEAD"] try: merge_base = splitlines_no_ends(get_output(*command))[0] break diff --git a/script/list-components.py b/script/list-components.py index 3e55c0e5f7..8e2d47c6b3 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -120,13 +120,22 @@ def main(): parser.add_argument( "-c", "--changed", action="store_true", help="Only run on changed files" ) + parser.add_argument( + "-b", "--branch", help="Branch to compare changed files against" + ) args = parser.parse_args() + if args.branch and not args.changed: + parser.error("--branch requires --changed") + files = git_ls_files() files = filter(filter_component_files, files) if args.changed: - changed = changed_files() + if args.branch: + changed = changed_files(args.branch) + else: + changed = changed_files() files = [f for f in files if f in changed] components = extract_component_names_array_from_files_array(files) From 4f59b14ab09f1581cb15b475f6d4f47d3a5fa93b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sat, 16 Mar 2024 00:18:51 -0500 Subject: [PATCH 1388/2607] Fix keeloq for IDF 5+ (#6382) --- esphome/components/remote_base/keeloq_protocol.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_base/keeloq_protocol.cpp b/esphome/components/remote_base/keeloq_protocol.cpp index 77a2f9be6c..09d9ea4f53 100644 --- a/esphome/components/remote_base/keeloq_protocol.cpp +++ b/esphome/components/remote_base/keeloq_protocol.cpp @@ -1,6 +1,8 @@ #include "keeloq_protocol.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace remote_base { @@ -34,7 +36,8 @@ transmitter and nutton command is decoded. void KeeloqProtocol::encode(RemoteTransmitData *dst, const KeeloqData &data) { uint32_t out_data = 0x0; - ESP_LOGD(TAG, "Send Keeloq: address=%07x command=%03x encrypted=%08x", data.address, data.command, data.encrypted); + ESP_LOGD(TAG, "Send Keeloq: address=%07" PRIx32 " command=%03x encrypted=%08" PRIx32, data.address, data.command, + data.encrypted); ESP_LOGV(TAG, "Send Keeloq: data bits (%d + %d)", NBITS_ENCRYPTED_DATA, NBITS_FIXED_DATA); // Preamble = '01' x 12 @@ -181,7 +184,7 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { } void KeeloqProtocol::dump(const KeeloqData &data) { - ESP_LOGD(TAG, "Received Keeloq: address=0x%08X, command=0x%02x", data.address, data.command); + ESP_LOGD(TAG, "Received Keeloq: address=0x%08" PRIx32 ", command=0x%02x", data.address, data.command); } } // namespace remote_base From e753ac3a97aa0d51695a880137f7d4078d57f088 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Sat, 16 Mar 2024 06:19:25 +0100 Subject: [PATCH 1389/2607] Fix Nextion set_component_picture call (#6378) This fixes the call to the Nextion display to change the pic id from a component. It was previously changing the attribute `val`, which is related to something else. In addition, I've changed the parameter for picture_id to be uint_8, as Nextion requires an integer from 0 to 255 on this attribute. --- esphome/components/nextion/nextion.h | 6 +++--- esphome/components/nextion/nextion_commands.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index eef2c61638..f9f01de72c 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -82,16 +82,16 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe /** * Set the picture of an image component. * @param component The component name. - * @param value The picture name. + * @param value The picture id. * * Example: * ```cpp - * it.set_component_picture("pic", "4"); + * it.set_component_picture("pic", 4); * ``` * * This will change the image of the component `pic` to the image with ID `4`. */ - void set_component_picture(const char *component, const char *picture); + void set_component_picture(const char *component, uint8_t picture_id); /** * Set the background color of a component. * @param component The component name. diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index c4849d6050..e378111376 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -197,8 +197,8 @@ void Nextion::disable_component_touch(const char *component) { this->add_no_result_to_queue_with_printf_("disable_component_touch", "tsw %s,0", component); } -void Nextion::set_component_picture(const char *component, const char *picture) { - this->add_no_result_to_queue_with_printf_("set_component_picture", "%s.val=%s", component, picture); +void Nextion::set_component_picture(const char *component, uint8_t picture_id) { + this->add_no_result_to_queue_with_printf_("set_component_picture", "%s.pic=%d", component, picture_id); } void Nextion::set_component_text(const char *component, const char *text) { From 23f8498ff972b0c67d0cd4f708e728c11d5a0630 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 17 Mar 2024 12:10:47 -0700 Subject: [PATCH 1390/2607] allow negative ppm for sensair (#6385) --- esphome/components/senseair/senseair.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/senseair/senseair.cpp b/esphome/components/senseair/senseair.cpp index e0504eb2b9..e58ee157f7 100644 --- a/esphome/components/senseair/senseair.cpp +++ b/esphome/components/senseair/senseair.cpp @@ -54,9 +54,9 @@ void SenseAirComponent::update() { this->status_clear_warning(); const uint8_t length = response[2]; const uint16_t status = (uint16_t(response[3]) << 8) | response[4]; - const uint16_t ppm = (uint16_t(response[length + 1]) << 8) | response[length + 2]; + const int16_t ppm = int16_t((response[length + 1] << 8) | response[length + 2]); - ESP_LOGD(TAG, "SenseAir Received CO₂=%uppm Status=0x%02X", ppm, status); + ESP_LOGD(TAG, "SenseAir Received CO₂=%dppm Status=0x%02X", ppm, status); if (this->co2_sensor_ != nullptr) this->co2_sensor_->publish_state(ppm); } From 9f121e6016921591d26d08dbe5340d6e5e3766be Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Sun, 17 Mar 2024 15:13:55 -0400 Subject: [PATCH 1391/2607] microWakeWord - add new ops and small improvements (#6360) --- .../micro_wake_word/micro_wake_word.cpp | 66 ++++++++----------- .../micro_wake_word/micro_wake_word.h | 3 +- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/esphome/components/micro_wake_word/micro_wake_word.cpp b/esphome/components/micro_wake_word/micro_wake_word.cpp index 7321e5b05b..f637f8b2bb 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.cpp +++ b/esphome/components/micro_wake_word/micro_wake_word.cpp @@ -93,11 +93,18 @@ int MicroWakeWord::read_microphone_() { return 0; } - size_t bytes_written = this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); - if (bytes_written != bytes_read) { - ESP_LOGW(TAG, "Failed to write some data to ring buffer (written=%d, expected=%d)", bytes_written, bytes_read); + size_t bytes_free = this->ring_buffer_->free(); + + if (bytes_free < bytes_read) { + ESP_LOGW(TAG, + "Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). " + "Resetting the ring buffer. Wake word detection accuracy will be reduced.", + bytes_free, bytes_read); + + this->ring_buffer_->reset(); } - return bytes_written; + + return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); } void MicroWakeWord::loop() { @@ -206,12 +213,6 @@ bool MicroWakeWord::initialize_models() { return false; } - this->preprocessor_stride_buffer_ = audio_samples_allocator.allocate(HISTORY_SAMPLES_TO_KEEP); - if (this->preprocessor_stride_buffer_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the audio preprocessor's stride buffer."); - return false; - } - this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE); if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) { ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported"); @@ -225,7 +226,7 @@ bool MicroWakeWord::initialize_models() { } static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver; - static tflite::MicroMutableOpResolver<14> streaming_op_resolver; + static tflite::MicroMutableOpResolver<17> streaming_op_resolver; if (!this->register_preprocessor_ops_(preprocessor_op_resolver)) return false; @@ -329,7 +330,6 @@ bool MicroWakeWord::detect_wake_word_() { } // Perform inference - uint32_t streaming_size = micros(); float streaming_prob = this->perform_streaming_inference_(); // Add the most recent probability to the sliding window @@ -357,6 +357,9 @@ bool MicroWakeWord::detect_wake_word_() { for (auto &prob : this->recent_streaming_probabilities_) { prob = 0; } + + ESP_LOGD(TAG, "Wake word sliding average probability is %.3f and most recent probability is %.3f", + sliding_window_average, streaming_prob); return true; } @@ -371,23 +374,6 @@ void MicroWakeWord::set_sliding_window_average_size(size_t size) { bool MicroWakeWord::slice_available_() { size_t available = this->ring_buffer_->available(); - size_t free = this->ring_buffer_->free(); - - if (free < NEW_SAMPLES_TO_GET * sizeof(int16_t)) { - // If the ring buffer is within one audio slice of being full, then wake word detection will have issues. - // If this is constantly occuring, then some possibilities why are - // 1) there are too many other slow components configured - // 2) the ESP32 isn't fast enough; e.g., an ESP32 is much slower than an ESP32-S3 at inferences. - // 3) the model is too large - // 4) the model uses operations that are not optimized - ESP_LOGW(TAG, - "Audio buffer is nearly full. Wake word detection may be less accurate and have slower reponse times. " -#if !defined(USE_ESP32_VARIANT_ESP32S3) - "microWakeWord is designed for the ESP32-S3. The current platform is too slow for this model." -#endif - ); - } - return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t)); } @@ -396,13 +382,12 @@ bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { return false; } - // Copy 320 bytes (160 samples over 10 ms) into preprocessor_audio_buffer_ from history in - // preprocessor_stride_buffer_ - memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_stride_buffer_), + // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer to the start of the audio buffer + memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); - // Copy 640 bytes (320 samples over 20 ms) from the ring buffer - // The first 320 bytes (160 samples over 10 ms) will be from history + // Copy 640 bytes (320 samples over 20 ms) from the ring buffer into the audio buffer offset 320 bytes (160 samples + // over 10 ms) size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP), NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200)); @@ -415,11 +400,6 @@ bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { return false; } - // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer into history stride buffer for the next - // iteration - memcpy((void *) (this->preprocessor_stride_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), - HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); - *audio_samples = this->preprocessor_audio_buffer_; return true; } @@ -480,7 +460,7 @@ bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18 return true; } -bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver) { +bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver) { if (op_resolver.AddCallOnce() != kTfLiteOk) return false; if (op_resolver.AddVarHandle() != kTfLiteOk) @@ -509,6 +489,12 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> & return false; if (op_resolver.AddQuantize() != kTfLiteOk) return false; + if (op_resolver.AddDepthwiseConv2D() != kTfLiteOk) + return false; + if (op_resolver.AddAveragePool2D() != kTfLiteOk) + return false; + if (op_resolver.AddMaxPool2D() != kTfLiteOk) + return false; return true; } diff --git a/esphome/components/micro_wake_word/micro_wake_word.h b/esphome/components/micro_wake_word/micro_wake_word.h index 27d05c3e09..1d7c18d686 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.h +++ b/esphome/components/micro_wake_word/micro_wake_word.h @@ -128,7 +128,6 @@ class MicroWakeWord : public Component { // Stores audio fed into feature generator preprocessor int16_t *preprocessor_audio_buffer_; - int16_t *preprocessor_stride_buffer_; bool detected_{false}; @@ -181,7 +180,7 @@ class MicroWakeWord : public Component { bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver); /// @brief Returns true if successfully registered the streaming model's TensorFlow operations - bool register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver); + bool register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver); }; template class StartAction : public Action, public Parented { From c24946e09ff964d76ae44011638ef2c35280f525 Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:00:07 +0100 Subject: [PATCH 1392/2607] Fix compilation for uponor_smatrix without time component (#6389) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 2 ++ esphome/components/uponor_smatrix/uponor_smatrix.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index 10cd787c7f..df81691fb1 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -61,9 +61,11 @@ void UponorSmatrixComponent::loop() { // Send packets during bus silence if ((now - this->last_rx_ > 300) && (now - this->last_poll_start_ < 9500) && (now - this->last_tx_ > 200)) { +#ifdef USE_TIME // Only build time packet when bus is silent and queue is empty to make sure we can send it right away if (this->send_time_requested_ && this->tx_queue_.empty() && this->do_send_time_()) this->send_time_requested_ = false; +#endif // Send the next packet in the queue if (!this->tx_queue_.empty()) { auto packet = std::move(this->tx_queue_.front()); diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.h b/esphome/components/uponor_smatrix/uponor_smatrix.h index b6675199b5..b7667b5b87 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.h +++ b/esphome/components/uponor_smatrix/uponor_smatrix.h @@ -4,6 +4,8 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" +#include "esphome/core/defines.h" + #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" #include "esphome/core/time.h" From 0b9a022ef6c430671ec6d906968634c4af8343fb Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:01:25 +0100 Subject: [PATCH 1393/2607] Shows component operation time in `ms` (#6388) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/component.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index b0406e6502..d737ec0ae3 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -5,6 +5,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" #include +#include namespace esphome { @@ -211,8 +212,8 @@ WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() { uint32_t now = millis(); if (now - started_ > 50) { const char *src = component_ == nullptr ? "" : component_->get_component_source(); - ESP_LOGW(TAG, "Component %s took a long time for an operation (%.2f s).", src, (now - started_) / 1e3f); - ESP_LOGW(TAG, "Components should block for at most 20-30ms."); + ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms).", src, (now - started_)); + ESP_LOGW(TAG, "Components should block for at most 30 ms."); ; } } From 72c6563a3b4fafffa08f82765e3b8853bc88ccc9 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Sun, 17 Mar 2024 22:06:02 +0100 Subject: [PATCH 1394/2607] IPv6 can't be enabled for libretiny (#6387) --- esphome/components/network/__init__.py | 38 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 4e87ff1c12..36144ff0a4 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -6,6 +6,9 @@ from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.const import ( CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, ) CODEOWNERS = ["@esphome/core"] @@ -16,25 +19,30 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.Optional(CONF_ENABLE_IPV6, default=False): cv.boolean, + cv.SplitDefault(CONF_ENABLE_IPV6): cv.All( + cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } ) async def to_code(config): - cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) - cg.add_define("USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT]) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + if CONF_ENABLE_IPV6 in config: + cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) + cg.add_define( + "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] ) - else: - if config[CONF_ENABLE_IPV6]: - cg.add_build_flag("-DCONFIG_LWIP_IPV6") - cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") - if CORE.is_rp2040: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") - if CORE.is_esp8266: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) + else: + if config[CONF_ENABLE_IPV6]: + cg.add_build_flag("-DCONFIG_LWIP_IPV6") + cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") + if CORE.is_rp2040: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") + if CORE.is_esp8266: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") From 8fd10d6859ca3013c72820a64f3853a2fed89622 Mon Sep 17 00:00:00 2001 From: Daniel Eisterhold Date: Sun, 17 Mar 2024 18:51:46 -0500 Subject: [PATCH 1395/2607] Add line_at_angle method to Display component (#6381) --- esphome/components/display/display.cpp | 15 ++++++++++ esphome/components/display/display.h | 7 +++++ tests/components/display/test.esp32.yaml | 35 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 tests/components/display/test.esp32.yaml diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 8ae1ee46aa..010e6eca0b 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -36,6 +36,21 @@ void HOT Display::line(int x1, int y1, int x2, int y2, Color color) { } } +void Display::line_at_angle(int x, int y, int angle, int length, Color color) { + this->line_at_angle(x, y, angle, 0, length, color); +} + +void Display::line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color) { + // Calculate start and end points + int x1 = (start_radius * cos(angle * M_PI / 180)) + x; + int y1 = (start_radius * sin(angle * M_PI / 180)) + y; + int x2 = (stop_radius * cos(angle * M_PI / 180)) + x; + int y2 = (stop_radius * sin(angle * M_PI / 180)) + y; + + // Draw line + this->line(x1, y1, x2, y2, color); +} + void Display::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { size_t line_stride = x_offset + w + x_pad; // length of each source line in pixels diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 21954ebb71..a30ba976b4 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -258,6 +258,13 @@ class Display : public PollingComponent { /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON); + /// Draw a straight line at the given angle based on the origin [x, y] for a specified length with the given color. + void line_at_angle(int x, int y, int angle, int length, Color color = COLOR_ON); + + /// Draw a straight line at the given angle based on the origin [x, y] from a specified start and stop radius with the + /// given color. + void line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color = COLOR_ON); + /// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color. void horizontal_line(int x, int y, int width, Color color = COLOR_ON); diff --git a/tests/components/display/test.esp32.yaml b/tests/components/display/test.esp32.yaml new file mode 100644 index 0000000000..a22aa76780 --- /dev/null +++ b/tests/components/display/test.esp32.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + lambda: |- + // Draw an analog clock in the center of the screen + int centerX = it.get_width() / 2; + int centerY = it.get_height() / 2; + int radius = min(it.get_width(), it.get_height()) / 4; + + // Draw border + it.circle(centerX, centerY, radius); + + // Draw hour ticks + for(int h = 0; h < 12; h++) { + int hourAngle = (h * 30) - 90; + + it.line_at_angle(centerX, centerY, hourAngle, radius - 10, radius); + } + + // Draw minute ticks + for(int m = 0; m < 60; m++) { + int minuteAngle = (m * 6) - 90; + + it.line_at_angle(centerX, centerY, minuteAngle, radius - 5, radius); + } From 687553a285fc13d4b17a75a84050e5c0e6ba2cb1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:00:59 +1300 Subject: [PATCH 1396/2607] Replace name and friendly name in full adopted configs (#4456) --- .../components/dashboard_import/__init__.py | 130 +++++++++--------- esphome/dashboard/web_server.py | 3 +- requirements.txt | 1 + 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/esphome/components/dashboard_import/__init__.py b/esphome/components/dashboard_import/__init__.py index e0994be6a0..b1b22b816b 100644 --- a/esphome/components/dashboard_import/__init__.py +++ b/esphome/components/dashboard_import/__init__.py @@ -2,8 +2,10 @@ import base64 import secrets from pathlib import Path from typing import Optional +import re import requests +from ruamel.yaml import YAML import esphome.codegen as cg import esphome.config_validation as cv @@ -11,7 +13,6 @@ import esphome.final_validate as fv from esphome import git from esphome.components.packages import validate_source_shorthand from esphome.const import CONF_REF, CONF_WIFI, CONF_ESPHOME, CONF_PROJECT -from esphome.wizard import wizard_file from esphome.yaml_util import dump dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import") @@ -94,75 +95,74 @@ def import_config( if p.exists(): raise FileExistsError - if project_name == "esphome.web": - if "esp32c3" in import_url: - board = "esp32-c3-devkitm-1" - platform = "ESP32" - elif "esp32s2" in import_url: - board = "esp32-s2-saola-1" - platform = "ESP32" - elif "esp32s3" in import_url: - board = "esp32-s3-devkitc-1" - platform = "ESP32" - elif "esp32" in import_url: - board = "esp32dev" - platform = "ESP32" - elif "esp8266" in import_url: - board = "esp01_1m" - platform = "ESP8266" - elif "pico-w" in import_url: - board = "pico-w" - platform = "RP2040" + git_file = git.GitFile.from_shorthand(import_url) - kwargs = { - "name": name, - "friendly_name": friendly_name, - "platform": platform, - "board": board, - "ssid": "!secret wifi_ssid", - "psk": "!secret wifi_password", + if git_file.query and "full_config" in git_file.query: + url = git_file.raw_url + try: + req = requests.get(url, timeout=30) + req.raise_for_status() + except requests.exceptions.RequestException as e: + raise ValueError(f"Error while fetching {url}: {e}") from e + + contents = req.text + yaml = YAML() + loaded_yaml = yaml.load(contents) + if ( + "name_add_mac_suffix" in loaded_yaml["esphome"] + and loaded_yaml["esphome"]["name_add_mac_suffix"] + ): + loaded_yaml["esphome"]["name_add_mac_suffix"] = False + name_val = loaded_yaml["esphome"]["name"] + sub_pattern = re.compile(r"\$\{?([a-zA-Z-_]+)\}?") + if match := sub_pattern.match(name_val): + name_sub = match.group(1) + if name_sub in loaded_yaml["substitutions"]: + loaded_yaml["substitutions"][name_sub] = name + else: + raise ValueError( + f"Name substitution {name_sub} not found in substitutions" + ) + else: + loaded_yaml["esphome"]["name"] = name + if friendly_name is not None: + friendly_name_val = loaded_yaml["esphome"]["friendly_name"] + if match := sub_pattern.match(friendly_name_val): + friendly_name_sub = match.group(1) + if friendly_name_sub in loaded_yaml["substitutions"]: + loaded_yaml["substitutions"][friendly_name_sub] = friendly_name + else: + raise ValueError( + f"Friendly name substitution {friendly_name_sub} not found in substitutions" + ) + else: + loaded_yaml["esphome"]["friendly_name"] = friendly_name + + with p.open("w", encoding="utf8") as f: + yaml.dump(loaded_yaml, f) + else: + with p.open("w", encoding="utf8") as f: + f.write(contents) + + else: + substitutions = {"name": name} + esphome_core = {"name": "${name}", "name_add_mac_suffix": False} + if friendly_name: + substitutions["friendly_name"] = friendly_name + esphome_core["friendly_name"] = "${friendly_name}" + config = { + "substitutions": substitutions, + "packages": {project_name: import_url}, + "esphome": esphome_core, } if encryption: noise_psk = secrets.token_bytes(32) key = base64.b64encode(noise_psk).decode() - kwargs["api_encryption_key"] = key + config["api"] = {"encryption": {"key": key}} - p.write_text( - wizard_file(**kwargs), - encoding="utf8", - ) - else: - git_file = git.GitFile.from_shorthand(import_url) + output = dump(config) - if git_file.query and "full_config" in git_file.query: - url = git_file.raw_url - try: - req = requests.get(url, timeout=30) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise ValueError(f"Error while fetching {url}: {e}") from e + if network == CONF_WIFI: + output += WIFI_CONFIG - p.write_text(req.text, encoding="utf8") - - else: - substitutions = {"name": name} - esphome_core = {"name": "${name}", "name_add_mac_suffix": False} - if friendly_name: - substitutions["friendly_name"] = friendly_name - esphome_core["friendly_name"] = "${friendly_name}" - config = { - "substitutions": substitutions, - "packages": {project_name: import_url}, - "esphome": esphome_core, - } - if encryption: - noise_psk = secrets.token_bytes(32) - key = base64.b64encode(noise_psk).decode() - config["api"] = {"encryption": {"key": key}} - - output = dump(config) - - if network == CONF_WIFI: - output += WIFI_CONFIG - - p.write_text(output, encoding="utf8") + p.write_text(output, encoding="utf8") diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index de3fe6e8ae..3de1d69115 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -516,7 +516,8 @@ class ImportRequestHandler(BaseHandler): self.set_status(500) self.write("File already exists") return - except ValueError: + except ValueError as e: + _LOGGER.error(e) self.set_status(422) self.write("Invalid package url") return diff --git a/requirements.txt b/requirements.txt index 32955bf6e7..9b5e06fc59 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ esphome-dashboard==20231107.0 aioesphomeapi==23.1.1 zeroconf==0.131.0 python-magic==0.4.27 +ruamel.yaml==0.18.6 # dashboard_import # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From a5553827f1262742abb9921f68d849c321e57d43 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Sat, 16 Mar 2024 01:21:44 +0000 Subject: [PATCH 1397/2607] Use AQI device class (#6376) --- esphome/components/sen5x/sensor.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/sen5x/sensor.py b/esphome/components/sen5x/sensor.py index 4bc4a138a3..67bd627f7f 100644 --- a/esphome/components/sen5x/sensor.py +++ b/esphome/components/sen5x/sensor.py @@ -14,13 +14,12 @@ from esphome.const import ( CONF_PM_4_0, CONF_STORE_BASELINE, CONF_TEMPERATURE, + DEVICE_CLASS_AQI, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, ICON_CHEMICAL_WEAPON, ICON_RADIATOR, ICON_THERMOMETER, @@ -132,13 +131,13 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_VOC): sensor.sensor_schema( icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + device_class=DEVICE_CLASS_AQI, state_class=STATE_CLASS_MEASUREMENT, ).extend(GAS_SENSOR), cv.Optional(CONF_NOX): sensor.sensor_schema( icon=ICON_RADIATOR, accuracy_decimals=0, - device_class=DEVICE_CLASS_NITROUS_OXIDE, + device_class=DEVICE_CLASS_AQI, state_class=STATE_CLASS_MEASUREMENT, ).extend(GAS_SENSOR), cv.Optional(CONF_STORE_BASELINE, default=True): cv.boolean, From 4de58559c6bad70a61efb3a32e1b04f6e98f1474 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 16 Mar 2024 14:22:34 +1300 Subject: [PATCH 1398/2607] Fix list-components when PR is not targeting dev (#6375) --- .github/workflows/ci.yml | 15 ++++++++++----- script/helpers.py | 4 ++-- script/list-components.py | 11 ++++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3de879176..47709739dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,6 +398,7 @@ jobs: runs-on: ubuntu-latest needs: - common + if: github.event_name == 'pull_request' outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -406,10 +407,14 @@ jobs: with: # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. fetch-depth: 500 - - name: Fetch dev branch + - name: Get target branch + id: target-branch run: | - git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/dev*:refs/remotes/origin/dev* +refs/tags/dev*:refs/tags/dev* - git merge-base refs/remotes/origin/dev HEAD + echo "branch=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT + - name: Fetch ${{ steps.target-branch.outputs.branch }} branch + run: | + git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/${{ steps.target-branch.outputs.branch }}:refs/remotes/origin/${{ steps.target-branch.outputs.branch }} + git merge-base refs/remotes/origin/${{ steps.target-branch.outputs.branch }} HEAD - name: Restore Python uses: ./.github/actions/restore-python with: @@ -419,7 +424,7 @@ jobs: id: set-matrix run: | . venv/bin/activate - echo "matrix=$(script/list-components.py --changed | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + echo "matrix=$(script/list-components.py --changed --branch ${{ steps.target-branch.outputs.branch }} | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT test-build-components: name: Component test ${{ matrix.file }} @@ -427,7 +432,7 @@ jobs: needs: - common - list-components - if: ${{ needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }} + if: ${{ github.event_name == 'pull_request' && needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }} strategy: fail-fast: false max-parallel: 2 diff --git a/script/helpers.py b/script/helpers.py index a971fdf475..52b0658fb6 100644 --- a/script/helpers.py +++ b/script/helpers.py @@ -70,11 +70,11 @@ def splitlines_no_ends(string): return [s.strip() for s in string.splitlines()] -def changed_files(): +def changed_files(branch="dev"): check_remotes = ["upstream", "origin"] check_remotes.extend(splitlines_no_ends(get_output("git", "remote"))) for remote in check_remotes: - command = ["git", "merge-base", f"refs/remotes/{remote}/dev", "HEAD"] + command = ["git", "merge-base", f"refs/remotes/{remote}/{branch}", "HEAD"] try: merge_base = splitlines_no_ends(get_output(*command))[0] break diff --git a/script/list-components.py b/script/list-components.py index 3e55c0e5f7..8e2d47c6b3 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -120,13 +120,22 @@ def main(): parser.add_argument( "-c", "--changed", action="store_true", help="Only run on changed files" ) + parser.add_argument( + "-b", "--branch", help="Branch to compare changed files against" + ) args = parser.parse_args() + if args.branch and not args.changed: + parser.error("--branch requires --changed") + files = git_ls_files() files = filter(filter_component_files, files) if args.changed: - changed = changed_files() + if args.branch: + changed = changed_files(args.branch) + else: + changed = changed_files() files = [f for f in files if f in changed] components = extract_component_names_array_from_files_array(files) From d121fa5d05604df28ab470a4fb79946eb3d8858b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 17 Mar 2024 12:10:47 -0700 Subject: [PATCH 1399/2607] allow negative ppm for sensair (#6385) --- esphome/components/senseair/senseair.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/senseair/senseair.cpp b/esphome/components/senseair/senseair.cpp index e0504eb2b9..e58ee157f7 100644 --- a/esphome/components/senseair/senseair.cpp +++ b/esphome/components/senseair/senseair.cpp @@ -54,9 +54,9 @@ void SenseAirComponent::update() { this->status_clear_warning(); const uint8_t length = response[2]; const uint16_t status = (uint16_t(response[3]) << 8) | response[4]; - const uint16_t ppm = (uint16_t(response[length + 1]) << 8) | response[length + 2]; + const int16_t ppm = int16_t((response[length + 1] << 8) | response[length + 2]); - ESP_LOGD(TAG, "SenseAir Received CO₂=%uppm Status=0x%02X", ppm, status); + ESP_LOGD(TAG, "SenseAir Received CO₂=%dppm Status=0x%02X", ppm, status); if (this->co2_sensor_ != nullptr) this->co2_sensor_->publish_state(ppm); } From 9e378189c3157a548a6dc8ef335a6dfacf546fc6 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Sun, 17 Mar 2024 15:13:55 -0400 Subject: [PATCH 1400/2607] microWakeWord - add new ops and small improvements (#6360) --- .../micro_wake_word/micro_wake_word.cpp | 66 ++++++++----------- .../micro_wake_word/micro_wake_word.h | 3 +- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/esphome/components/micro_wake_word/micro_wake_word.cpp b/esphome/components/micro_wake_word/micro_wake_word.cpp index 7321e5b05b..f637f8b2bb 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.cpp +++ b/esphome/components/micro_wake_word/micro_wake_word.cpp @@ -93,11 +93,18 @@ int MicroWakeWord::read_microphone_() { return 0; } - size_t bytes_written = this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); - if (bytes_written != bytes_read) { - ESP_LOGW(TAG, "Failed to write some data to ring buffer (written=%d, expected=%d)", bytes_written, bytes_read); + size_t bytes_free = this->ring_buffer_->free(); + + if (bytes_free < bytes_read) { + ESP_LOGW(TAG, + "Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). " + "Resetting the ring buffer. Wake word detection accuracy will be reduced.", + bytes_free, bytes_read); + + this->ring_buffer_->reset(); } - return bytes_written; + + return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); } void MicroWakeWord::loop() { @@ -206,12 +213,6 @@ bool MicroWakeWord::initialize_models() { return false; } - this->preprocessor_stride_buffer_ = audio_samples_allocator.allocate(HISTORY_SAMPLES_TO_KEEP); - if (this->preprocessor_stride_buffer_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the audio preprocessor's stride buffer."); - return false; - } - this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE); if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) { ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported"); @@ -225,7 +226,7 @@ bool MicroWakeWord::initialize_models() { } static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver; - static tflite::MicroMutableOpResolver<14> streaming_op_resolver; + static tflite::MicroMutableOpResolver<17> streaming_op_resolver; if (!this->register_preprocessor_ops_(preprocessor_op_resolver)) return false; @@ -329,7 +330,6 @@ bool MicroWakeWord::detect_wake_word_() { } // Perform inference - uint32_t streaming_size = micros(); float streaming_prob = this->perform_streaming_inference_(); // Add the most recent probability to the sliding window @@ -357,6 +357,9 @@ bool MicroWakeWord::detect_wake_word_() { for (auto &prob : this->recent_streaming_probabilities_) { prob = 0; } + + ESP_LOGD(TAG, "Wake word sliding average probability is %.3f and most recent probability is %.3f", + sliding_window_average, streaming_prob); return true; } @@ -371,23 +374,6 @@ void MicroWakeWord::set_sliding_window_average_size(size_t size) { bool MicroWakeWord::slice_available_() { size_t available = this->ring_buffer_->available(); - size_t free = this->ring_buffer_->free(); - - if (free < NEW_SAMPLES_TO_GET * sizeof(int16_t)) { - // If the ring buffer is within one audio slice of being full, then wake word detection will have issues. - // If this is constantly occuring, then some possibilities why are - // 1) there are too many other slow components configured - // 2) the ESP32 isn't fast enough; e.g., an ESP32 is much slower than an ESP32-S3 at inferences. - // 3) the model is too large - // 4) the model uses operations that are not optimized - ESP_LOGW(TAG, - "Audio buffer is nearly full. Wake word detection may be less accurate and have slower reponse times. " -#if !defined(USE_ESP32_VARIANT_ESP32S3) - "microWakeWord is designed for the ESP32-S3. The current platform is too slow for this model." -#endif - ); - } - return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t)); } @@ -396,13 +382,12 @@ bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { return false; } - // Copy 320 bytes (160 samples over 10 ms) into preprocessor_audio_buffer_ from history in - // preprocessor_stride_buffer_ - memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_stride_buffer_), + // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer to the start of the audio buffer + memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); - // Copy 640 bytes (320 samples over 20 ms) from the ring buffer - // The first 320 bytes (160 samples over 10 ms) will be from history + // Copy 640 bytes (320 samples over 20 ms) from the ring buffer into the audio buffer offset 320 bytes (160 samples + // over 10 ms) size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP), NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200)); @@ -415,11 +400,6 @@ bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { return false; } - // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer into history stride buffer for the next - // iteration - memcpy((void *) (this->preprocessor_stride_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), - HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); - *audio_samples = this->preprocessor_audio_buffer_; return true; } @@ -480,7 +460,7 @@ bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18 return true; } -bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver) { +bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver) { if (op_resolver.AddCallOnce() != kTfLiteOk) return false; if (op_resolver.AddVarHandle() != kTfLiteOk) @@ -509,6 +489,12 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> & return false; if (op_resolver.AddQuantize() != kTfLiteOk) return false; + if (op_resolver.AddDepthwiseConv2D() != kTfLiteOk) + return false; + if (op_resolver.AddAveragePool2D() != kTfLiteOk) + return false; + if (op_resolver.AddMaxPool2D() != kTfLiteOk) + return false; return true; } diff --git a/esphome/components/micro_wake_word/micro_wake_word.h b/esphome/components/micro_wake_word/micro_wake_word.h index 27d05c3e09..1d7c18d686 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.h +++ b/esphome/components/micro_wake_word/micro_wake_word.h @@ -128,7 +128,6 @@ class MicroWakeWord : public Component { // Stores audio fed into feature generator preprocessor int16_t *preprocessor_audio_buffer_; - int16_t *preprocessor_stride_buffer_; bool detected_{false}; @@ -181,7 +180,7 @@ class MicroWakeWord : public Component { bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver); /// @brief Returns true if successfully registered the streaming model's TensorFlow operations - bool register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver); + bool register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver); }; template class StartAction : public Action, public Parented { From 3908a9ce9da17572d2176d85874ebd52406ad567 Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:00:07 +0100 Subject: [PATCH 1401/2607] Fix compilation for uponor_smatrix without time component (#6389) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 2 ++ esphome/components/uponor_smatrix/uponor_smatrix.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index 10cd787c7f..df81691fb1 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -61,9 +61,11 @@ void UponorSmatrixComponent::loop() { // Send packets during bus silence if ((now - this->last_rx_ > 300) && (now - this->last_poll_start_ < 9500) && (now - this->last_tx_ > 200)) { +#ifdef USE_TIME // Only build time packet when bus is silent and queue is empty to make sure we can send it right away if (this->send_time_requested_ && this->tx_queue_.empty() && this->do_send_time_()) this->send_time_requested_ = false; +#endif // Send the next packet in the queue if (!this->tx_queue_.empty()) { auto packet = std::move(this->tx_queue_.front()); diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.h b/esphome/components/uponor_smatrix/uponor_smatrix.h index b6675199b5..b7667b5b87 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.h +++ b/esphome/components/uponor_smatrix/uponor_smatrix.h @@ -4,6 +4,8 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" +#include "esphome/core/defines.h" + #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" #include "esphome/core/time.h" From 22f427165fa8fc0e9407c66db682d3b005f54d43 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:01:25 +0100 Subject: [PATCH 1402/2607] Shows component operation time in `ms` (#6388) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/component.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index b0406e6502..d737ec0ae3 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -5,6 +5,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" #include +#include namespace esphome { @@ -211,8 +212,8 @@ WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() { uint32_t now = millis(); if (now - started_ > 50) { const char *src = component_ == nullptr ? "" : component_->get_component_source(); - ESP_LOGW(TAG, "Component %s took a long time for an operation (%.2f s).", src, (now - started_) / 1e3f); - ESP_LOGW(TAG, "Components should block for at most 20-30ms."); + ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms).", src, (now - started_)); + ESP_LOGW(TAG, "Components should block for at most 30 ms."); ; } } From 4429e5ae5612d3e0b5acf459ea213f4762ab106d Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Sun, 17 Mar 2024 22:06:02 +0100 Subject: [PATCH 1403/2607] IPv6 can't be enabled for libretiny (#6387) --- esphome/components/network/__init__.py | 38 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 4e87ff1c12..36144ff0a4 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -6,6 +6,9 @@ from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.const import ( CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, ) CODEOWNERS = ["@esphome/core"] @@ -16,25 +19,30 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.Optional(CONF_ENABLE_IPV6, default=False): cv.boolean, + cv.SplitDefault(CONF_ENABLE_IPV6): cv.All( + cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } ) async def to_code(config): - cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) - cg.add_define("USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT]) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + if CONF_ENABLE_IPV6 in config: + cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) + cg.add_define( + "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] ) - else: - if config[CONF_ENABLE_IPV6]: - cg.add_build_flag("-DCONFIG_LWIP_IPV6") - cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") - if CORE.is_rp2040: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") - if CORE.is_esp8266: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) + else: + if config[CONF_ENABLE_IPV6]: + cg.add_build_flag("-DCONFIG_LWIP_IPV6") + cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") + if CORE.is_rp2040: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") + if CORE.is_esp8266: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") From 690a7d46cebec6d02df9d75277b492a9360b5c08 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:00:59 +1300 Subject: [PATCH 1404/2607] Replace name and friendly name in full adopted configs (#4456) --- .../components/dashboard_import/__init__.py | 130 +++++++++--------- esphome/dashboard/web_server.py | 3 +- requirements.txt | 1 + 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/esphome/components/dashboard_import/__init__.py b/esphome/components/dashboard_import/__init__.py index e0994be6a0..b1b22b816b 100644 --- a/esphome/components/dashboard_import/__init__.py +++ b/esphome/components/dashboard_import/__init__.py @@ -2,8 +2,10 @@ import base64 import secrets from pathlib import Path from typing import Optional +import re import requests +from ruamel.yaml import YAML import esphome.codegen as cg import esphome.config_validation as cv @@ -11,7 +13,6 @@ import esphome.final_validate as fv from esphome import git from esphome.components.packages import validate_source_shorthand from esphome.const import CONF_REF, CONF_WIFI, CONF_ESPHOME, CONF_PROJECT -from esphome.wizard import wizard_file from esphome.yaml_util import dump dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import") @@ -94,75 +95,74 @@ def import_config( if p.exists(): raise FileExistsError - if project_name == "esphome.web": - if "esp32c3" in import_url: - board = "esp32-c3-devkitm-1" - platform = "ESP32" - elif "esp32s2" in import_url: - board = "esp32-s2-saola-1" - platform = "ESP32" - elif "esp32s3" in import_url: - board = "esp32-s3-devkitc-1" - platform = "ESP32" - elif "esp32" in import_url: - board = "esp32dev" - platform = "ESP32" - elif "esp8266" in import_url: - board = "esp01_1m" - platform = "ESP8266" - elif "pico-w" in import_url: - board = "pico-w" - platform = "RP2040" + git_file = git.GitFile.from_shorthand(import_url) - kwargs = { - "name": name, - "friendly_name": friendly_name, - "platform": platform, - "board": board, - "ssid": "!secret wifi_ssid", - "psk": "!secret wifi_password", + if git_file.query and "full_config" in git_file.query: + url = git_file.raw_url + try: + req = requests.get(url, timeout=30) + req.raise_for_status() + except requests.exceptions.RequestException as e: + raise ValueError(f"Error while fetching {url}: {e}") from e + + contents = req.text + yaml = YAML() + loaded_yaml = yaml.load(contents) + if ( + "name_add_mac_suffix" in loaded_yaml["esphome"] + and loaded_yaml["esphome"]["name_add_mac_suffix"] + ): + loaded_yaml["esphome"]["name_add_mac_suffix"] = False + name_val = loaded_yaml["esphome"]["name"] + sub_pattern = re.compile(r"\$\{?([a-zA-Z-_]+)\}?") + if match := sub_pattern.match(name_val): + name_sub = match.group(1) + if name_sub in loaded_yaml["substitutions"]: + loaded_yaml["substitutions"][name_sub] = name + else: + raise ValueError( + f"Name substitution {name_sub} not found in substitutions" + ) + else: + loaded_yaml["esphome"]["name"] = name + if friendly_name is not None: + friendly_name_val = loaded_yaml["esphome"]["friendly_name"] + if match := sub_pattern.match(friendly_name_val): + friendly_name_sub = match.group(1) + if friendly_name_sub in loaded_yaml["substitutions"]: + loaded_yaml["substitutions"][friendly_name_sub] = friendly_name + else: + raise ValueError( + f"Friendly name substitution {friendly_name_sub} not found in substitutions" + ) + else: + loaded_yaml["esphome"]["friendly_name"] = friendly_name + + with p.open("w", encoding="utf8") as f: + yaml.dump(loaded_yaml, f) + else: + with p.open("w", encoding="utf8") as f: + f.write(contents) + + else: + substitutions = {"name": name} + esphome_core = {"name": "${name}", "name_add_mac_suffix": False} + if friendly_name: + substitutions["friendly_name"] = friendly_name + esphome_core["friendly_name"] = "${friendly_name}" + config = { + "substitutions": substitutions, + "packages": {project_name: import_url}, + "esphome": esphome_core, } if encryption: noise_psk = secrets.token_bytes(32) key = base64.b64encode(noise_psk).decode() - kwargs["api_encryption_key"] = key + config["api"] = {"encryption": {"key": key}} - p.write_text( - wizard_file(**kwargs), - encoding="utf8", - ) - else: - git_file = git.GitFile.from_shorthand(import_url) + output = dump(config) - if git_file.query and "full_config" in git_file.query: - url = git_file.raw_url - try: - req = requests.get(url, timeout=30) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise ValueError(f"Error while fetching {url}: {e}") from e + if network == CONF_WIFI: + output += WIFI_CONFIG - p.write_text(req.text, encoding="utf8") - - else: - substitutions = {"name": name} - esphome_core = {"name": "${name}", "name_add_mac_suffix": False} - if friendly_name: - substitutions["friendly_name"] = friendly_name - esphome_core["friendly_name"] = "${friendly_name}" - config = { - "substitutions": substitutions, - "packages": {project_name: import_url}, - "esphome": esphome_core, - } - if encryption: - noise_psk = secrets.token_bytes(32) - key = base64.b64encode(noise_psk).decode() - config["api"] = {"encryption": {"key": key}} - - output = dump(config) - - if network == CONF_WIFI: - output += WIFI_CONFIG - - p.write_text(output, encoding="utf8") + p.write_text(output, encoding="utf8") diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index de3fe6e8ae..3de1d69115 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -516,7 +516,8 @@ class ImportRequestHandler(BaseHandler): self.set_status(500) self.write("File already exists") return - except ValueError: + except ValueError as e: + _LOGGER.error(e) self.set_status(422) self.write("Invalid package url") return diff --git a/requirements.txt b/requirements.txt index 32955bf6e7..9b5e06fc59 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ esphome-dashboard==20231107.0 aioesphomeapi==23.1.1 zeroconf==0.131.0 python-magic==0.4.27 +ruamel.yaml==0.18.6 # dashboard_import # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 8a8bfe01c7e16295de9a8256b811b1c6f1a500ee Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:54:39 +1300 Subject: [PATCH 1405/2607] Bump version to 2024.3.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4259c82ad7..60ea6f0423 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0b2" +__version__ = "2024.3.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From f3f7bdc4e11a006b6305a48740b85a68b9d31be5 Mon Sep 17 00:00:00 2001 From: swoboda1337 <154711427+swoboda1337@users.noreply.github.com> Date: Mon, 18 Mar 2024 02:35:06 -0400 Subject: [PATCH 1406/2607] Fix bug in `remote_base` conditional (#6281) Co-authored-by: Jonathan Swoboda --- esphome/components/remote_base/remote_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index 095f95053f..f3e86aaab6 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -16,7 +16,7 @@ RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_b } void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { - if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) >= RMT_CHANNEL_MAX) { + if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) { this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_); ESP_LOGW(TAG, "Not enough RMT memory blocks available, reduced to %i blocks.", this->mem_block_num_); } From 1e5dc159724a330b4f28616a310e026d76c80281 Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Mon, 18 Mar 2024 19:04:53 +0100 Subject: [PATCH 1407/2607] Fix sending packets to uponor_smatrix devices (#6392) --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index df81691fb1..a7014dc96c 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -173,7 +173,9 @@ bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixDa return false; // Assemble packet for send queue. All fields are big-endian except for the little-endian checksum. - std::vector packet(6 + 3 * data_len); + std::vector packet; + packet.reserve(6 + 3 * data_len); + packet.push_back(this->address_ >> 8); packet.push_back(this->address_ >> 0); packet.push_back(device_address >> 8); From 55677bb68e285aa2b076c1ff0e54d5fd83ff7814 Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Mon, 18 Mar 2024 19:06:17 +0100 Subject: [PATCH 1408/2607] Fix wrong initialization of vectors in ade7953_i2c (#6393) --- .../components/ade7953_i2c/ade7953_i2c.cpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/esphome/components/ade7953_i2c/ade7953_i2c.cpp b/esphome/components/ade7953_i2c/ade7953_i2c.cpp index 572337428a..ae381824db 100644 --- a/esphome/components/ade7953_i2c/ade7953_i2c.cpp +++ b/esphome/components/ade7953_i2c/ade7953_i2c.cpp @@ -13,29 +13,29 @@ void AdE7953I2c::dump_config() { ade7953_base::ADE7953::dump_config(); } bool AdE7953I2c::ade_write_8(uint16_t reg, uint8_t value) { - std::vector data(3); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[3]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value; + return this->write(data, 3) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_16(uint16_t reg, uint16_t value) { - std::vector data(4); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value >> 8); - data.push_back(value >> 0); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[4]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value >> 8; + data[3] = value >> 0; + return this->write(data, 4) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_32(uint16_t reg, uint32_t value) { - std::vector data(6); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value >> 24); - data.push_back(value >> 16); - data.push_back(value >> 8); - data.push_back(value >> 0); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[6]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value >> 24; + data[3] = value >> 16; + data[4] = value >> 8; + data[5] = value >> 0; + return this->write(data, 6) != i2c::ERROR_OK; } bool AdE7953I2c::ade_read_8(uint16_t reg, uint8_t *value) { uint8_t reg_data[2]; From e7fe2a2816f6bc45ae46f8d17efc1cb20222bd74 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 19 Mar 2024 07:15:52 +1300 Subject: [PATCH 1409/2607] Check generated proto files are as expected if any are modified in PRs (#6254) --- .github/workflows/ci-api-proto.yml | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 .github/workflows/ci-api-proto.yml diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml new file mode 100644 index 0000000000..038ef3a587 --- /dev/null +++ b/.github/workflows/ci-api-proto.yml @@ -0,0 +1,81 @@ +name: API Proto CI + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - "esphome/components/api/api.proto" + - "esphome/components/api/api_pb2.cpp" + - "esphome/components/api/api_pb2.h" + - "esphome/components/api/api_pb2_service.cpp" + - "esphome/components/api/api_pb2_service.h" + - "script/api_protobuf/api_protobuf.py" + - ".github/workflows/ci-api-proto.yml" + +permissions: + contents: read + pull-requests: write + +jobs: + check: + name: Check generated files + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + - name: Set up Python + uses: actions/setup-python@v5.0.0 + with: + python-version: "3.11" + + - name: Install apt dependencies + run: | + sudo apt update + sudo apt-cache show protobuf-compiler + sudo apt install -y protobuf-compiler + protoc --version + - name: Install python dependencies + run: pip install aioesphomeapi -c requirements.txt -r requirements_dev.txt + - name: Generate files + run: script/api_protobuf/api_protobuf.py + - name: Check for changes + run: | + if ! git diff --quiet; then + echo "## Job Failed" | tee -a $GITHUB_STEP_SUMMARY + echo "You have altered the generated proto files but they do not match what is expected." | tee -a $GITHUB_STEP_SUMMARY + echo "Please run 'script/api_protobuf/api_protobuf.py' and commit the changes." | tee -a $GITHUB_STEP_SUMMARY + exit 1 + fi + - if: failure() + name: Review PR + uses: actions/github-script@v7.0.1 + with: + script: | + await github.rest.pulls.createReview({ + pull_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + event: 'REQUEST_CHANGES', + body: 'You have altered the generated proto files but they do not match what is expected.\nPlease run "script/api_protobuf/api_protobuf.py" and commit the changes.' + }) + - if: success() + name: Dismiss review + uses: actions/github-script@v7.0.1 + with: + script: | + let reviews = await github.rest.pulls.listReviews({ + pull_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + for (let review of reviews.data) { + if (review.user.login === 'github-actions[bot]' && review.state === 'CHANGES_REQUESTED') { + await github.rest.pulls.dismissReview({ + pull_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + review_id: review.id, + message: 'Files now match the expected proto files.' + }); + } + } From d692b5404cc40af1bf6394bcc26574847e1727bc Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Mon, 18 Mar 2024 13:26:39 -0500 Subject: [PATCH 1410/2607] ld2420: Firmware v1.5.4+ bug workaround (#6168) --- esphome/components/ld2420/ld2420.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index bda1764cfc..bf1412ee9f 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -211,10 +211,11 @@ void LD2420Component::factory_reset_action() { void LD2420Component::restart_module_action() { ESP_LOGCONFIG(TAG, "Restarting LD2420 module..."); this->send_module_restart(); - delay_microseconds_safe(45000); - this->set_config_mode(true); - this->set_system_mode(system_mode_); - this->set_config_mode(false); + this->set_timeout(250, [this]() { + this->set_config_mode(true); + this->set_system_mode(system_mode_); + this->set_config_mode(false); + }); ESP_LOGCONFIG(TAG, "LD2420 Restarted."); } @@ -527,18 +528,16 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) { this->write_byte(cmd_buffer[index]); } - delay_microseconds_safe(500); // give the module a moment to process it error = 0; if (frame.command == CMD_RESTART) { - delay_microseconds_safe(25000); // Wait for the restart - return 0; // restart does not reply exit now + return 0; // restart does not reply exit now } while (!this->cmd_reply_.ack) { while (available()) { this->readline_(read(), ack_buffer, sizeof(ack_buffer)); } - delay_microseconds_safe(250); + delay_microseconds_safe(1450); if (loop_count <= 0) { error = LD2420_ERROR_TIMEOUT; retry--; From f5695733bc615fa3e6c1ab3c4c5b3d95ce25461c Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Mon, 18 Mar 2024 20:28:15 +0200 Subject: [PATCH 1411/2607] ld2420: fix energy mode documentation (#6225) --- esphome/components/ld2420/ld2420.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index bf1412ee9f..58c9a289a3 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -40,9 +40,9 @@ There are three documented parameters for modes: 00 04 = Energy output mode This mode outputs detailed signal energy values for each gate and the target distance. The data format consist of the following. - Header HH, Length LL, Persence PP, Distance DD, Range Gate GG, 16 Gate Energies EE, Footer FF - HH HH HH HH LL LL PP DD DD GG GG EE EE .. 16x .. FF FF FF FF - F4 F3 F2 F1 00 23 00 00 00 00 01 00 00 .. .. .. .. F8 F7 F6 F5 + Header HH, Length LL, Persence PP, Distance DD, 16 Gate Energies EE, Footer FF + HH HH HH HH LL LL PP DD DD EE EE .. 16x .. FF FF FF FF + F4 F3 F2 F1 23 00 00 00 00 00 00 .. .. .. .. F8 F7 F6 F5 00 00 = debug output mode This mode outputs detailed values consisting of 20 Dopplers, 16 Ranges for a total 20 * 16 * 4 bytes The data format consist of the following. From cb731926be637a6b6c1344df877f49fe2c35bc30 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 18 Mar 2024 16:00:06 -0500 Subject: [PATCH 1412/2607] Add actions for component tests A, B and C (#6256) --- tests/components/api/test.esp32-c3-idf.yaml | 13 +++++++++++++ tests/components/api/test.esp32-c3.yaml | 13 +++++++++++++ tests/components/api/test.esp32-idf.yaml | 13 +++++++++++++ tests/components/api/test.esp32.yaml | 13 +++++++++++++ tests/components/api/test.esp8266.yaml | 13 +++++++++++++ tests/components/api/test.rp2040.yaml | 13 +++++++++++++ 6 files changed, 78 insertions(+) diff --git a/tests/components/api/test.esp32-c3-idf.yaml b/tests/components/api/test.esp32-c3-idf.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.esp32-c3-idf.yaml +++ b/tests/components/api/test.esp32-c3-idf.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 diff --git a/tests/components/api/test.esp32-c3.yaml b/tests/components/api/test.esp32-c3.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.esp32-c3.yaml +++ b/tests/components/api/test.esp32-c3.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 diff --git a/tests/components/api/test.esp32-idf.yaml b/tests/components/api/test.esp32-idf.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.esp32-idf.yaml +++ b/tests/components/api/test.esp32-idf.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 diff --git a/tests/components/api/test.esp32.yaml b/tests/components/api/test.esp32.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.esp32.yaml +++ b/tests/components/api/test.esp32.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 diff --git a/tests/components/api/test.esp8266.yaml b/tests/components/api/test.esp8266.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.esp8266.yaml +++ b/tests/components/api/test.esp8266.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 diff --git a/tests/components/api/test.rp2040.yaml b/tests/components/api/test.rp2040.yaml index 8e7ca0fb06..3c56811b95 100644 --- a/tests/components/api/test.rp2040.yaml +++ b/tests/components/api/test.rp2040.yaml @@ -1,3 +1,16 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + wifi: ssid: MySSID password: password1 From d5a8bea8e94a6ea4114ecf3e9cf79946b10f198e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 18 Mar 2024 16:42:03 -0500 Subject: [PATCH 1413/2607] Add some components to the new testing framework (V) (#6231) --- tests/components/vbus/test.esp32-c3-idf.yaml | 42 ++++++++++++++ tests/components/vbus/test.esp32-c3.yaml | 42 ++++++++++++++ tests/components/vbus/test.esp32-idf.yaml | 42 ++++++++++++++ tests/components/vbus/test.esp32.yaml | 42 ++++++++++++++ tests/components/vbus/test.esp8266.yaml | 42 ++++++++++++++ tests/components/vbus/test.rp2040.yaml | 42 ++++++++++++++ .../veml3235/test.esp32-c3-idf.yaml | 15 +++++ tests/components/veml3235/test.esp32-c3.yaml | 15 +++++ tests/components/veml3235/test.esp32-idf.yaml | 15 +++++ tests/components/veml3235/test.esp32.yaml | 15 +++++ tests/components/veml3235/test.esp8266.yaml | 15 +++++ tests/components/veml3235/test.rp2040.yaml | 15 +++++ .../components/version/test.esp32-c3-idf.yaml | 3 + tests/components/version/test.esp32-c3.yaml | 3 + tests/components/version/test.esp32-idf.yaml | 3 + tests/components/version/test.esp32.yaml | 3 + tests/components/version/test.esp8266.yaml | 3 + tests/components/version/test.rp2040.yaml | 3 + .../components/vl53l0x/test.esp32-c3-idf.yaml | 12 ++++ tests/components/vl53l0x/test.esp32-c3.yaml | 12 ++++ tests/components/vl53l0x/test.esp32-idf.yaml | 12 ++++ tests/components/vl53l0x/test.esp32.yaml | 12 ++++ tests/components/vl53l0x/test.esp8266.yaml | 12 ++++ tests/components/vl53l0x/test.rp2040.yaml | 12 ++++ .../voice_assistant/test.esp32-c3-idf.yaml | 57 +++++++++++++++++++ .../voice_assistant/test.esp32-c3.yaml | 57 +++++++++++++++++++ .../voice_assistant/test.esp32-idf.yaml | 57 +++++++++++++++++++ .../voice_assistant/test.esp32.yaml | 57 +++++++++++++++++++ 28 files changed, 660 insertions(+) create mode 100644 tests/components/vbus/test.esp32-c3-idf.yaml create mode 100644 tests/components/vbus/test.esp32-c3.yaml create mode 100644 tests/components/vbus/test.esp32-idf.yaml create mode 100644 tests/components/vbus/test.esp32.yaml create mode 100644 tests/components/vbus/test.esp8266.yaml create mode 100644 tests/components/vbus/test.rp2040.yaml create mode 100644 tests/components/veml3235/test.esp32-c3-idf.yaml create mode 100644 tests/components/veml3235/test.esp32-c3.yaml create mode 100644 tests/components/veml3235/test.esp32-idf.yaml create mode 100644 tests/components/veml3235/test.esp32.yaml create mode 100644 tests/components/veml3235/test.esp8266.yaml create mode 100644 tests/components/veml3235/test.rp2040.yaml create mode 100644 tests/components/version/test.esp32-c3-idf.yaml create mode 100644 tests/components/version/test.esp32-c3.yaml create mode 100644 tests/components/version/test.esp32-idf.yaml create mode 100644 tests/components/version/test.esp32.yaml create mode 100644 tests/components/version/test.esp8266.yaml create mode 100644 tests/components/version/test.rp2040.yaml create mode 100644 tests/components/vl53l0x/test.esp32-c3-idf.yaml create mode 100644 tests/components/vl53l0x/test.esp32-c3.yaml create mode 100644 tests/components/vl53l0x/test.esp32-idf.yaml create mode 100644 tests/components/vl53l0x/test.esp32.yaml create mode 100644 tests/components/vl53l0x/test.esp8266.yaml create mode 100644 tests/components/vl53l0x/test.rp2040.yaml create mode 100644 tests/components/voice_assistant/test.esp32-c3-idf.yaml create mode 100644 tests/components/voice_assistant/test.esp32-c3.yaml create mode 100644 tests/components/voice_assistant/test.esp32-idf.yaml create mode 100644 tests/components/voice_assistant/test.esp32.yaml diff --git a/tests/components/vbus/test.esp32-c3-idf.yaml b/tests/components/vbus/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..67ee542031 --- /dev/null +++ b/tests/components/vbus/test.esp32-c3-idf.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/vbus/test.esp32-c3.yaml b/tests/components/vbus/test.esp32-c3.yaml new file mode 100644 index 0000000000..67ee542031 --- /dev/null +++ b/tests/components/vbus/test.esp32-c3.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/vbus/test.esp32-idf.yaml b/tests/components/vbus/test.esp32-idf.yaml new file mode 100644 index 0000000000..a0e5ca42cc --- /dev/null +++ b/tests/components/vbus/test.esp32-idf.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/vbus/test.esp32.yaml b/tests/components/vbus/test.esp32.yaml new file mode 100644 index 0000000000..a0e5ca42cc --- /dev/null +++ b/tests/components/vbus/test.esp32.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/vbus/test.esp8266.yaml b/tests/components/vbus/test.esp8266.yaml new file mode 100644 index 0000000000..67ee542031 --- /dev/null +++ b/tests/components/vbus/test.esp8266.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/vbus/test.rp2040.yaml b/tests/components/vbus/test.rp2040.yaml new file mode 100644 index 0000000000..67ee542031 --- /dev/null +++ b/tests/components/vbus/test.rp2040.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_vbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +vbus: + +binary_sensor: + - platform: vbus + model: deltasol_bs_plus + relay1: + name: Relay 1 On + relay2: + name: Relay 2 On + sensor1_error: + name: Sensor 1 Error + - platform: vbus + model: custom + command: 0x100 + source: 0x1234 + dest: 0x10 + binary_sensors: + - id: vcustom_b + name: VBus Custom Binary Sensor + lambda: return x[0] & 1; + +sensor: + - platform: vbus + model: deltasol c + temperature_1: + name: Temperature 1 + temperature_2: + name: Temperature 2 + temperature_3: + name: Temperature 3 + operating_hours_1: + name: Operating Hours 1 + heat_quantity: + name: Heat Quantity + time: + name: System Time diff --git a/tests/components/veml3235/test.esp32-c3-idf.yaml b/tests/components/veml3235/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1f79c5f50c --- /dev/null +++ b/tests/components/veml3235/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 5 + sda: 4 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/veml3235/test.esp32-c3.yaml b/tests/components/veml3235/test.esp32-c3.yaml new file mode 100644 index 0000000000..1f79c5f50c --- /dev/null +++ b/tests/components/veml3235/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 5 + sda: 4 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/veml3235/test.esp32-idf.yaml b/tests/components/veml3235/test.esp32-idf.yaml new file mode 100644 index 0000000000..3442fa4317 --- /dev/null +++ b/tests/components/veml3235/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 16 + sda: 17 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/veml3235/test.esp32.yaml b/tests/components/veml3235/test.esp32.yaml new file mode 100644 index 0000000000..3442fa4317 --- /dev/null +++ b/tests/components/veml3235/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 16 + sda: 17 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/veml3235/test.esp8266.yaml b/tests/components/veml3235/test.esp8266.yaml new file mode 100644 index 0000000000..1f79c5f50c --- /dev/null +++ b/tests/components/veml3235/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 5 + sda: 4 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/veml3235/test.rp2040.yaml b/tests/components/veml3235/test.rp2040.yaml new file mode 100644 index 0000000000..1f79c5f50c --- /dev/null +++ b/tests/components/veml3235/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_veml3235 + scl: 5 + sda: 4 + +sensor: + - platform: veml3235 + id: veml3235_sensor + name: VEML3235 Light Sensor + auto_gain: true + auto_gain_threshold_high: 90% + auto_gain_threshold_low: 15% + digital_gain: 1X + gain: 1X + integration_time: 50ms diff --git a/tests/components/version/test.esp32-c3-idf.yaml b/tests/components/version/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.esp32-c3.yaml b/tests/components/version/test.esp32-c3.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.esp32-idf.yaml b/tests/components/version/test.esp32-idf.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.esp32.yaml b/tests/components/version/test.esp32.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.esp32.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.esp8266.yaml b/tests/components/version/test.esp8266.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.esp8266.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.rp2040.yaml b/tests/components/version/test.rp2040.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/test.rp2040.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/vl53l0x/test.esp32-c3-idf.yaml b/tests/components/vl53l0x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..832f7dcfbc --- /dev/null +++ b/tests/components/vl53l0x/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 5 + sda: 4 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/vl53l0x/test.esp32-c3.yaml b/tests/components/vl53l0x/test.esp32-c3.yaml new file mode 100644 index 0000000000..832f7dcfbc --- /dev/null +++ b/tests/components/vl53l0x/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 5 + sda: 4 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/vl53l0x/test.esp32-idf.yaml b/tests/components/vl53l0x/test.esp32-idf.yaml new file mode 100644 index 0000000000..8f35de0e72 --- /dev/null +++ b/tests/components/vl53l0x/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 16 + sda: 17 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/vl53l0x/test.esp32.yaml b/tests/components/vl53l0x/test.esp32.yaml new file mode 100644 index 0000000000..8f35de0e72 --- /dev/null +++ b/tests/components/vl53l0x/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 16 + sda: 17 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/vl53l0x/test.esp8266.yaml b/tests/components/vl53l0x/test.esp8266.yaml new file mode 100644 index 0000000000..832f7dcfbc --- /dev/null +++ b/tests/components/vl53l0x/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 5 + sda: 4 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/vl53l0x/test.rp2040.yaml b/tests/components/vl53l0x/test.rp2040.yaml new file mode 100644 index 0000000000..832f7dcfbc --- /dev/null +++ b/tests/components/vl53l0x/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_vl53l0x + scl: 5 + sda: 4 + +sensor: + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + enable_pin: 3 + timeout: 200us + update_interval: 60s diff --git a/tests/components/voice_assistant/test.esp32-c3-idf.yaml b/tests/components/voice_assistant/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..248ae4d0dc --- /dev/null +++ b/tests/components/voice_assistant/test.esp32-c3-idf.yaml @@ -0,0 +1,57 @@ +esphome: + on_boot: + then: + - voice_assistant.start + - voice_assistant.start_continuous + - voice_assistant.stop + +wifi: + ssid: MySSID + password: password1 + +api: + +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 5 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 3 + adc_type: external + pdm: false + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 2 + mode: mono + +voice_assistant: + microphone: mic_id_external + speaker: speaker_id + on_listening: + - logger.log: "Voice assistant microphone listening" + on_start: + - logger.log: "Voice assistant started" + on_stt_end: + - logger.log: + format: "Voice assistant STT ended with result %s" + args: [x.c_str()] + on_tts_start: + - logger.log: + format: "Voice assistant TTS started with text %s" + args: [x.c_str()] + on_tts_end: + - logger.log: + format: "Voice assistant TTS ended with url %s" + args: [x.c_str()] + on_end: + - logger.log: "Voice assistant ended" + on_error: + - logger.log: + format: "Voice assistant error - code %s, message: %s" + args: [code.c_str(), message.c_str()] diff --git a/tests/components/voice_assistant/test.esp32-c3.yaml b/tests/components/voice_assistant/test.esp32-c3.yaml new file mode 100644 index 0000000000..248ae4d0dc --- /dev/null +++ b/tests/components/voice_assistant/test.esp32-c3.yaml @@ -0,0 +1,57 @@ +esphome: + on_boot: + then: + - voice_assistant.start + - voice_assistant.start_continuous + - voice_assistant.stop + +wifi: + ssid: MySSID + password: password1 + +api: + +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 5 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 3 + adc_type: external + pdm: false + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 2 + mode: mono + +voice_assistant: + microphone: mic_id_external + speaker: speaker_id + on_listening: + - logger.log: "Voice assistant microphone listening" + on_start: + - logger.log: "Voice assistant started" + on_stt_end: + - logger.log: + format: "Voice assistant STT ended with result %s" + args: [x.c_str()] + on_tts_start: + - logger.log: + format: "Voice assistant TTS started with text %s" + args: [x.c_str()] + on_tts_end: + - logger.log: + format: "Voice assistant TTS ended with url %s" + args: [x.c_str()] + on_end: + - logger.log: "Voice assistant ended" + on_error: + - logger.log: + format: "Voice assistant error - code %s, message: %s" + args: [code.c_str(), message.c_str()] diff --git a/tests/components/voice_assistant/test.esp32-idf.yaml b/tests/components/voice_assistant/test.esp32-idf.yaml new file mode 100644 index 0000000000..2e0209311d --- /dev/null +++ b/tests/components/voice_assistant/test.esp32-idf.yaml @@ -0,0 +1,57 @@ +esphome: + on_boot: + then: + - voice_assistant.start + - voice_assistant.start_continuous + - voice_assistant.stop + +wifi: + ssid: MySSID + password: password1 + +api: + +i2s_audio: + i2s_lrclk_pin: 16 + i2s_bclk_pin: 17 + i2s_mclk_pin: 15 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 13 + adc_type: external + pdm: false + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 12 + mode: mono + +voice_assistant: + microphone: mic_id_external + speaker: speaker_id + on_listening: + - logger.log: "Voice assistant microphone listening" + on_start: + - logger.log: "Voice assistant started" + on_stt_end: + - logger.log: + format: "Voice assistant STT ended with result %s" + args: [x.c_str()] + on_tts_start: + - logger.log: + format: "Voice assistant TTS started with text %s" + args: [x.c_str()] + on_tts_end: + - logger.log: + format: "Voice assistant TTS ended with url %s" + args: [x.c_str()] + on_end: + - logger.log: "Voice assistant ended" + on_error: + - logger.log: + format: "Voice assistant error - code %s, message: %s" + args: [code.c_str(), message.c_str()] diff --git a/tests/components/voice_assistant/test.esp32.yaml b/tests/components/voice_assistant/test.esp32.yaml new file mode 100644 index 0000000000..2e0209311d --- /dev/null +++ b/tests/components/voice_assistant/test.esp32.yaml @@ -0,0 +1,57 @@ +esphome: + on_boot: + then: + - voice_assistant.start + - voice_assistant.start_continuous + - voice_assistant.stop + +wifi: + ssid: MySSID + password: password1 + +api: + +i2s_audio: + i2s_lrclk_pin: 16 + i2s_bclk_pin: 17 + i2s_mclk_pin: 15 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 13 + adc_type: external + pdm: false + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 12 + mode: mono + +voice_assistant: + microphone: mic_id_external + speaker: speaker_id + on_listening: + - logger.log: "Voice assistant microphone listening" + on_start: + - logger.log: "Voice assistant started" + on_stt_end: + - logger.log: + format: "Voice assistant STT ended with result %s" + args: [x.c_str()] + on_tts_start: + - logger.log: + format: "Voice assistant TTS started with text %s" + args: [x.c_str()] + on_tts_end: + - logger.log: + format: "Voice assistant TTS ended with url %s" + args: [x.c_str()] + on_end: + - logger.log: "Voice assistant ended" + on_error: + - logger.log: + format: "Voice assistant error - code %s, message: %s" + args: [code.c_str(), message.c_str()] From 95443a43540306ef68cf8ec3fe09cf8d83c92e8c Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 18 Mar 2024 18:49:00 -0500 Subject: [PATCH 1414/2607] Add some components to the new testing framework (X,Y,Z) (#6233) --- tests/components/x9c/test.esp32-c3-idf.yaml | 7 ++++ tests/components/x9c/test.esp32-c3.yaml | 7 ++++ tests/components/x9c/test.esp32-idf.yaml | 7 ++++ tests/components/x9c/test.esp32.yaml | 7 ++++ tests/components/x9c/test.esp8266.yaml | 7 ++++ tests/components/x9c/test.rp2040.yaml | 7 ++++ .../xgzp68xx/test.esp32-c3-idf.yaml | 12 +++++++ tests/components/xgzp68xx/test.esp32-c3.yaml | 12 +++++++ tests/components/xgzp68xx/test.esp32-idf.yaml | 12 +++++++ tests/components/xgzp68xx/test.esp32.yaml | 12 +++++++ tests/components/xgzp68xx/test.esp8266.yaml | 12 +++++++ tests/components/xgzp68xx/test.rp2040.yaml | 12 +++++++ .../xiaomi_ble/test.esp32-c3-idf.yaml | 3 ++ .../components/xiaomi_ble/test.esp32-c3.yaml | 3 ++ .../components/xiaomi_ble/test.esp32-idf.yaml | 3 ++ tests/components/xiaomi_ble/test.esp32.yaml | 3 ++ .../xiaomi_cgd1/test.esp32-c3-idf.yaml | 12 +++++++ .../components/xiaomi_cgd1/test.esp32-c3.yaml | 12 +++++++ .../xiaomi_cgd1/test.esp32-idf.yaml | 12 +++++++ tests/components/xiaomi_cgd1/test.esp32.yaml | 12 +++++++ .../xiaomi_cgdk2/test.esp32-c3-idf.yaml | 12 +++++++ .../xiaomi_cgdk2/test.esp32-c3.yaml | 12 +++++++ .../xiaomi_cgdk2/test.esp32-idf.yaml | 12 +++++++ tests/components/xiaomi_cgdk2/test.esp32.yaml | 12 +++++++ .../xiaomi_cgg1/test.esp32-c3-idf.yaml | 12 +++++++ .../components/xiaomi_cgg1/test.esp32-c3.yaml | 12 +++++++ .../xiaomi_cgg1/test.esp32-idf.yaml | 12 +++++++ tests/components/xiaomi_cgg1/test.esp32.yaml | 12 +++++++ .../xiaomi_cgpr1/test.esp32-c3-idf.yaml | 13 ++++++++ .../xiaomi_cgpr1/test.esp32-c3.yaml | 13 ++++++++ .../xiaomi_cgpr1/test.esp32-idf.yaml | 13 ++++++++ tests/components/xiaomi_cgpr1/test.esp32.yaml | 13 ++++++++ .../xiaomi_gcls002/test.esp32-c3-idf.yaml | 13 ++++++++ .../xiaomi_gcls002/test.esp32-c3.yaml | 13 ++++++++ .../xiaomi_gcls002/test.esp32-idf.yaml | 13 ++++++++ .../components/xiaomi_gcls002/test.esp32.yaml | 13 ++++++++ .../xiaomi_hhccjcy01/test.esp32-c3-idf.yaml | 15 +++++++++ .../xiaomi_hhccjcy01/test.esp32-c3.yaml | 15 +++++++++ .../xiaomi_hhccjcy01/test.esp32-idf.yaml | 15 +++++++++ .../xiaomi_hhccjcy01/test.esp32.yaml | 15 +++++++++ .../xiaomi_hhccpot002/test.esp32-c3-idf.yaml | 9 +++++ .../xiaomi_hhccpot002/test.esp32-c3.yaml | 9 +++++ .../xiaomi_hhccpot002/test.esp32-idf.yaml | 9 +++++ .../xiaomi_hhccpot002/test.esp32.yaml | 9 +++++ .../xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml | 13 ++++++++ .../xiaomi_jqjcy01ym/test.esp32-c3.yaml | 13 ++++++++ .../xiaomi_jqjcy01ym/test.esp32-idf.yaml | 13 ++++++++ .../xiaomi_jqjcy01ym/test.esp32.yaml | 13 ++++++++ .../xiaomi_lywsd02/test.esp32-c3-idf.yaml | 11 +++++++ .../xiaomi_lywsd02/test.esp32-c3.yaml | 11 +++++++ .../xiaomi_lywsd02/test.esp32-idf.yaml | 11 +++++++ .../components/xiaomi_lywsd02/test.esp32.yaml | 11 +++++++ .../xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml | 12 +++++++ .../xiaomi_lywsd03mmc/test.esp32-c3.yaml | 12 +++++++ .../xiaomi_lywsd03mmc/test.esp32-idf.yaml | 12 +++++++ .../xiaomi_lywsd03mmc/test.esp32.yaml | 12 +++++++ .../xiaomi_lywsdcgq/test.esp32-c3-idf.yaml | 11 +++++++ .../xiaomi_lywsdcgq/test.esp32-c3.yaml | 11 +++++++ .../xiaomi_lywsdcgq/test.esp32-idf.yaml | 11 +++++++ .../xiaomi_lywsdcgq/test.esp32.yaml | 11 +++++++ .../xiaomi_mhoc303/test.esp32-c3-idf.yaml | 11 +++++++ .../xiaomi_mhoc303/test.esp32-c3.yaml | 11 +++++++ .../xiaomi_mhoc303/test.esp32-idf.yaml | 11 +++++++ .../components/xiaomi_mhoc303/test.esp32.yaml | 11 +++++++ .../xiaomi_mhoc401/test.esp32-c3-idf.yaml | 12 +++++++ .../xiaomi_mhoc401/test.esp32-c3.yaml | 12 +++++++ .../xiaomi_mhoc401/test.esp32-idf.yaml | 12 +++++++ .../components/xiaomi_mhoc401/test.esp32.yaml | 12 +++++++ .../test.esp32-c3-idf.yaml | 9 +++++ .../xiaomi_miscale copy/test.esp32-c3.yaml | 9 +++++ .../xiaomi_miscale copy/test.esp32-idf.yaml | 9 +++++ .../xiaomi_miscale copy/test.esp32.yaml | 9 +++++ .../xiaomi_miscale/test.esp32-c3-idf.yaml | 9 +++++ .../xiaomi_miscale/test.esp32-c3.yaml | 9 +++++ .../xiaomi_miscale/test.esp32-idf.yaml | 9 +++++ .../components/xiaomi_miscale/test.esp32.yaml | 9 +++++ .../xiaomi_mjyd02yla/test.esp32-c3-idf.yaml | 13 ++++++++ .../xiaomi_mjyd02yla/test.esp32-c3.yaml | 13 ++++++++ .../xiaomi_mjyd02yla/test.esp32-idf.yaml | 13 ++++++++ .../xiaomi_mjyd02yla/test.esp32.yaml | 13 ++++++++ .../xiaomi_mue4094rt/test.esp32-c3-idf.yaml | 7 ++++ .../xiaomi_mue4094rt/test.esp32-c3.yaml | 7 ++++ .../xiaomi_mue4094rt/test.esp32-idf.yaml | 7 ++++ .../xiaomi_mue4094rt/test.esp32.yaml | 7 ++++ .../xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml | 22 +++++++++++++ .../xiaomi_rtcgq02lm/test.esp32-c3.yaml | 22 +++++++++++++ .../xiaomi_rtcgq02lm/test.esp32-idf.yaml | 22 +++++++++++++ .../xiaomi_rtcgq02lm/test.esp32.yaml | 22 +++++++++++++ .../xiaomi_wx08zm/test.esp32-c3-idf.yaml | 10 ++++++ .../xiaomi_wx08zm/test.esp32-c3.yaml | 10 ++++++ .../xiaomi_wx08zm/test.esp32-idf.yaml | 10 ++++++ .../components/xiaomi_wx08zm/test.esp32.yaml | 10 ++++++ .../components/xl9535/test.esp32-c3-idf.yaml | 26 +++++++++++++++ tests/components/xl9535/test.esp32-c3.yaml | 26 +++++++++++++++ tests/components/xl9535/test.esp32-idf.yaml | 26 +++++++++++++++ tests/components/xl9535/test.esp32.yaml | 26 +++++++++++++++ tests/components/xl9535/test.esp8266.yaml | 26 +++++++++++++++ tests/components/xl9535/test.rp2040.yaml | 26 +++++++++++++++ .../components/xpt2046/test.esp32-c3-idf.yaml | 33 +++++++++++++++++++ tests/components/xpt2046/test.esp32-c3.yaml | 33 +++++++++++++++++++ tests/components/xpt2046/test.esp32-idf.yaml | 33 +++++++++++++++++++ tests/components/xpt2046/test.esp32.yaml | 33 +++++++++++++++++++ tests/components/xpt2046/test.esp8266.yaml | 33 +++++++++++++++++++ tests/components/xpt2046/test.rp2040.yaml | 33 +++++++++++++++++++ .../components/yashima/test.esp32-c3-idf.yaml | 7 ++++ tests/components/yashima/test.esp32-c3.yaml | 7 ++++ tests/components/yashima/test.esp32-idf.yaml | 7 ++++ tests/components/yashima/test.esp32.yaml | 7 ++++ tests/components/yashima/test.esp8266.yaml | 7 ++++ .../components/zhlt01/test.esp32-c3-idf.yaml | 7 ++++ tests/components/zhlt01/test.esp32-c3.yaml | 7 ++++ tests/components/zhlt01/test.esp32-idf.yaml | 7 ++++ tests/components/zhlt01/test.esp32.yaml | 7 ++++ tests/components/zhlt01/test.esp8266.yaml | 7 ++++ .../zio_ultrasonic/test.esp32-c3-idf.yaml | 9 +++++ .../zio_ultrasonic/test.esp32-c3.yaml | 9 +++++ .../zio_ultrasonic/test.esp32-idf.yaml | 9 +++++ .../components/zio_ultrasonic/test.esp32.yaml | 9 +++++ .../zio_ultrasonic/test.esp8266.yaml | 9 +++++ .../zio_ultrasonic/test.rp2040.yaml | 9 +++++ .../components/zyaura/test.esp32-c3-idf.yaml | 10 ++++++ tests/components/zyaura/test.esp32-c3.yaml | 10 ++++++ tests/components/zyaura/test.esp32-idf.yaml | 10 ++++++ tests/components/zyaura/test.esp32.yaml | 10 ++++++ tests/components/zyaura/test.esp8266.yaml | 10 ++++++ tests/components/zyaura/test.rp2040.yaml | 10 ++++++ 126 files changed, 1568 insertions(+) create mode 100644 tests/components/x9c/test.esp32-c3-idf.yaml create mode 100644 tests/components/x9c/test.esp32-c3.yaml create mode 100644 tests/components/x9c/test.esp32-idf.yaml create mode 100644 tests/components/x9c/test.esp32.yaml create mode 100644 tests/components/x9c/test.esp8266.yaml create mode 100644 tests/components/x9c/test.rp2040.yaml create mode 100644 tests/components/xgzp68xx/test.esp32-c3-idf.yaml create mode 100644 tests/components/xgzp68xx/test.esp32-c3.yaml create mode 100644 tests/components/xgzp68xx/test.esp32-idf.yaml create mode 100644 tests/components/xgzp68xx/test.esp32.yaml create mode 100644 tests/components/xgzp68xx/test.esp8266.yaml create mode 100644 tests/components/xgzp68xx/test.rp2040.yaml create mode 100644 tests/components/xiaomi_ble/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_ble/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_ble/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_ble/test.esp32.yaml create mode 100644 tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_cgd1/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_cgd1/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_cgd1/test.esp32.yaml create mode 100644 tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_cgdk2/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_cgdk2/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_cgdk2/test.esp32.yaml create mode 100644 tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_cgg1/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_cgg1/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_cgg1/test.esp32.yaml create mode 100644 tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_cgpr1/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_cgpr1/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_cgpr1/test.esp32.yaml create mode 100644 tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_gcls002/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_gcls002/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_gcls002/test.esp32.yaml create mode 100644 tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_hhccjcy01/test.esp32.yaml create mode 100644 tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_hhccpot002/test.esp32.yaml create mode 100644 tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_jqjcy01ym/test.esp32.yaml create mode 100644 tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_lywsd02/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_lywsd02/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_lywsd02/test.esp32.yaml create mode 100644 tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_lywsd03mmc/test.esp32.yaml create mode 100644 tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_lywsdcgq/test.esp32.yaml create mode 100644 tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_mhoc303/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_mhoc303/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_mhoc303/test.esp32.yaml create mode 100644 tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_mhoc401/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_mhoc401/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_mhoc401/test.esp32.yaml create mode 100644 tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_miscale copy/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_miscale copy/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_miscale copy/test.esp32.yaml create mode 100644 tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_miscale/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_miscale/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_miscale/test.esp32.yaml create mode 100644 tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_mjyd02yla/test.esp32.yaml create mode 100644 tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_mue4094rt/test.esp32.yaml create mode 100644 tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_rtcgq02lm/test.esp32.yaml create mode 100644 tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_wx08zm/test.esp32-c3.yaml create mode 100644 tests/components/xiaomi_wx08zm/test.esp32-idf.yaml create mode 100644 tests/components/xiaomi_wx08zm/test.esp32.yaml create mode 100644 tests/components/xl9535/test.esp32-c3-idf.yaml create mode 100644 tests/components/xl9535/test.esp32-c3.yaml create mode 100644 tests/components/xl9535/test.esp32-idf.yaml create mode 100644 tests/components/xl9535/test.esp32.yaml create mode 100644 tests/components/xl9535/test.esp8266.yaml create mode 100644 tests/components/xl9535/test.rp2040.yaml create mode 100644 tests/components/xpt2046/test.esp32-c3-idf.yaml create mode 100644 tests/components/xpt2046/test.esp32-c3.yaml create mode 100644 tests/components/xpt2046/test.esp32-idf.yaml create mode 100644 tests/components/xpt2046/test.esp32.yaml create mode 100644 tests/components/xpt2046/test.esp8266.yaml create mode 100644 tests/components/xpt2046/test.rp2040.yaml create mode 100644 tests/components/yashima/test.esp32-c3-idf.yaml create mode 100644 tests/components/yashima/test.esp32-c3.yaml create mode 100644 tests/components/yashima/test.esp32-idf.yaml create mode 100644 tests/components/yashima/test.esp32.yaml create mode 100644 tests/components/yashima/test.esp8266.yaml create mode 100644 tests/components/zhlt01/test.esp32-c3-idf.yaml create mode 100644 tests/components/zhlt01/test.esp32-c3.yaml create mode 100644 tests/components/zhlt01/test.esp32-idf.yaml create mode 100644 tests/components/zhlt01/test.esp32.yaml create mode 100644 tests/components/zhlt01/test.esp8266.yaml create mode 100644 tests/components/zio_ultrasonic/test.esp32-c3-idf.yaml create mode 100644 tests/components/zio_ultrasonic/test.esp32-c3.yaml create mode 100644 tests/components/zio_ultrasonic/test.esp32-idf.yaml create mode 100644 tests/components/zio_ultrasonic/test.esp32.yaml create mode 100644 tests/components/zio_ultrasonic/test.esp8266.yaml create mode 100644 tests/components/zio_ultrasonic/test.rp2040.yaml create mode 100644 tests/components/zyaura/test.esp32-c3-idf.yaml create mode 100644 tests/components/zyaura/test.esp32-c3.yaml create mode 100644 tests/components/zyaura/test.esp32-idf.yaml create mode 100644 tests/components/zyaura/test.esp32.yaml create mode 100644 tests/components/zyaura/test.esp8266.yaml create mode 100644 tests/components/zyaura/test.rp2040.yaml diff --git a/tests/components/x9c/test.esp32-c3-idf.yaml b/tests/components/x9c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a0480aa68f --- /dev/null +++ b/tests/components/x9c/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 3 + inc_pin: 4 + ud_pin: 5 + initial_value: 0.5 diff --git a/tests/components/x9c/test.esp32-c3.yaml b/tests/components/x9c/test.esp32-c3.yaml new file mode 100644 index 0000000000..a0480aa68f --- /dev/null +++ b/tests/components/x9c/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 3 + inc_pin: 4 + ud_pin: 5 + initial_value: 0.5 diff --git a/tests/components/x9c/test.esp32-idf.yaml b/tests/components/x9c/test.esp32-idf.yaml new file mode 100644 index 0000000000..28b18f7a92 --- /dev/null +++ b/tests/components/x9c/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 13 + inc_pin: 14 + ud_pin: 15 + initial_value: 0.5 diff --git a/tests/components/x9c/test.esp32.yaml b/tests/components/x9c/test.esp32.yaml new file mode 100644 index 0000000000..28b18f7a92 --- /dev/null +++ b/tests/components/x9c/test.esp32.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 13 + inc_pin: 14 + ud_pin: 15 + initial_value: 0.5 diff --git a/tests/components/x9c/test.esp8266.yaml b/tests/components/x9c/test.esp8266.yaml new file mode 100644 index 0000000000..28b18f7a92 --- /dev/null +++ b/tests/components/x9c/test.esp8266.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 13 + inc_pin: 14 + ud_pin: 15 + initial_value: 0.5 diff --git a/tests/components/x9c/test.rp2040.yaml b/tests/components/x9c/test.rp2040.yaml new file mode 100644 index 0000000000..a0480aa68f --- /dev/null +++ b/tests/components/x9c/test.rp2040.yaml @@ -0,0 +1,7 @@ +output: + - platform: x9c + id: test_x9c + cs_pin: 3 + inc_pin: 4 + ud_pin: 5 + initial_value: 0.5 diff --git a/tests/components/xgzp68xx/test.esp32-c3-idf.yaml b/tests/components/xgzp68xx/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25df8cc225 --- /dev/null +++ b/tests/components/xgzp68xx/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 5 + sda: 4 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xgzp68xx/test.esp32-c3.yaml b/tests/components/xgzp68xx/test.esp32-c3.yaml new file mode 100644 index 0000000000..25df8cc225 --- /dev/null +++ b/tests/components/xgzp68xx/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 5 + sda: 4 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xgzp68xx/test.esp32-idf.yaml b/tests/components/xgzp68xx/test.esp32-idf.yaml new file mode 100644 index 0000000000..fb55421123 --- /dev/null +++ b/tests/components/xgzp68xx/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 16 + sda: 17 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xgzp68xx/test.esp32.yaml b/tests/components/xgzp68xx/test.esp32.yaml new file mode 100644 index 0000000000..fb55421123 --- /dev/null +++ b/tests/components/xgzp68xx/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 16 + sda: 17 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xgzp68xx/test.esp8266.yaml b/tests/components/xgzp68xx/test.esp8266.yaml new file mode 100644 index 0000000000..25df8cc225 --- /dev/null +++ b/tests/components/xgzp68xx/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 5 + sda: 4 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xgzp68xx/test.rp2040.yaml b/tests/components/xgzp68xx/test.rp2040.yaml new file mode 100644 index 0000000000..25df8cc225 --- /dev/null +++ b/tests/components/xgzp68xx/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_xgzp68xx + scl: 5 + sda: 4 + +sensor: + - platform: xgzp68xx + k_value: 4096 + temperature: + name: Pressure Temperature + pressure: + name: Differential pressure diff --git a/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml b/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9d10393177 --- /dev/null +++ b/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +xiaomi_ble: diff --git a/tests/components/xiaomi_ble/test.esp32-c3.yaml b/tests/components/xiaomi_ble/test.esp32-c3.yaml new file mode 100644 index 0000000000..9d10393177 --- /dev/null +++ b/tests/components/xiaomi_ble/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +xiaomi_ble: diff --git a/tests/components/xiaomi_ble/test.esp32-idf.yaml b/tests/components/xiaomi_ble/test.esp32-idf.yaml new file mode 100644 index 0000000000..9d10393177 --- /dev/null +++ b/tests/components/xiaomi_ble/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +xiaomi_ble: diff --git a/tests/components/xiaomi_ble/test.esp32.yaml b/tests/components/xiaomi_ble/test.esp32.yaml new file mode 100644 index 0000000000..9d10393177 --- /dev/null +++ b/tests/components/xiaomi_ble/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +xiaomi_ble: diff --git a/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..94ed09e8f2 --- /dev/null +++ b/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgd1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgd1/test.esp32-c3.yaml b/tests/components/xiaomi_cgd1/test.esp32-c3.yaml new file mode 100644 index 0000000000..94ed09e8f2 --- /dev/null +++ b/tests/components/xiaomi_cgd1/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgd1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgd1/test.esp32-idf.yaml b/tests/components/xiaomi_cgd1/test.esp32-idf.yaml new file mode 100644 index 0000000000..94ed09e8f2 --- /dev/null +++ b/tests/components/xiaomi_cgd1/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgd1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgd1/test.esp32.yaml b/tests/components/xiaomi_cgd1/test.esp32.yaml new file mode 100644 index 0000000000..94ed09e8f2 --- /dev/null +++ b/tests/components/xiaomi_cgd1/test.esp32.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgd1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dddca56222 --- /dev/null +++ b/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgdk2 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml b/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml new file mode 100644 index 0000000000..dddca56222 --- /dev/null +++ b/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgdk2 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml b/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml new file mode 100644 index 0000000000..dddca56222 --- /dev/null +++ b/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgdk2 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgdk2/test.esp32.yaml b/tests/components/xiaomi_cgdk2/test.esp32.yaml new file mode 100644 index 0000000000..dddca56222 --- /dev/null +++ b/tests/components/xiaomi_cgdk2/test.esp32.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgdk2 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..170aebfbde --- /dev/null +++ b/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgg1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgg1/test.esp32-c3.yaml b/tests/components/xiaomi_cgg1/test.esp32-c3.yaml new file mode 100644 index 0000000000..170aebfbde --- /dev/null +++ b/tests/components/xiaomi_cgg1/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgg1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgg1/test.esp32-idf.yaml b/tests/components/xiaomi_cgg1/test.esp32-idf.yaml new file mode 100644 index 0000000000..170aebfbde --- /dev/null +++ b/tests/components/xiaomi_cgg1/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgg1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgg1/test.esp32.yaml b/tests/components/xiaomi_cgg1/test.esp32.yaml new file mode 100644 index 0000000000..170aebfbde --- /dev/null +++ b/tests/components/xiaomi_cgg1/test.esp32.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgg1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..48082a886c --- /dev/null +++ b/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_cgpr1 + name: CGPR1 Motion + mac_address: "12:34:56:12:34:56" + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + battery_level: + name: CGPR1 battery Level + idle_time: + name: CGPR1 Idle Time + illuminance: + name: CGPR1 Illuminance diff --git a/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml b/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml new file mode 100644 index 0000000000..48082a886c --- /dev/null +++ b/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_cgpr1 + name: CGPR1 Motion + mac_address: "12:34:56:12:34:56" + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + battery_level: + name: CGPR1 battery Level + idle_time: + name: CGPR1 Idle Time + illuminance: + name: CGPR1 Illuminance diff --git a/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml b/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml new file mode 100644 index 0000000000..48082a886c --- /dev/null +++ b/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_cgpr1 + name: CGPR1 Motion + mac_address: "12:34:56:12:34:56" + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + battery_level: + name: CGPR1 battery Level + idle_time: + name: CGPR1 Idle Time + illuminance: + name: CGPR1 Illuminance diff --git a/tests/components/xiaomi_cgpr1/test.esp32.yaml b/tests/components/xiaomi_cgpr1/test.esp32.yaml new file mode 100644 index 0000000000..48082a886c --- /dev/null +++ b/tests/components/xiaomi_cgpr1/test.esp32.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_cgpr1 + name: CGPR1 Motion + mac_address: "12:34:56:12:34:56" + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + battery_level: + name: CGPR1 battery Level + idle_time: + name: CGPR1 Idle Time + illuminance: + name: CGPR1 Illuminance diff --git a/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml b/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..32990708cc --- /dev/null +++ b/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_gcls002 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: GCLS02 Temperature + moisture: + name: GCLS02 Moisture + conductivity: + name: GCLS02 Soil Conductivity + illuminance: + name: GCLS02 Illuminance diff --git a/tests/components/xiaomi_gcls002/test.esp32-c3.yaml b/tests/components/xiaomi_gcls002/test.esp32-c3.yaml new file mode 100644 index 0000000000..32990708cc --- /dev/null +++ b/tests/components/xiaomi_gcls002/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_gcls002 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: GCLS02 Temperature + moisture: + name: GCLS02 Moisture + conductivity: + name: GCLS02 Soil Conductivity + illuminance: + name: GCLS02 Illuminance diff --git a/tests/components/xiaomi_gcls002/test.esp32-idf.yaml b/tests/components/xiaomi_gcls002/test.esp32-idf.yaml new file mode 100644 index 0000000000..32990708cc --- /dev/null +++ b/tests/components/xiaomi_gcls002/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_gcls002 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: GCLS02 Temperature + moisture: + name: GCLS02 Moisture + conductivity: + name: GCLS02 Soil Conductivity + illuminance: + name: GCLS02 Illuminance diff --git a/tests/components/xiaomi_gcls002/test.esp32.yaml b/tests/components/xiaomi_gcls002/test.esp32.yaml new file mode 100644 index 0000000000..32990708cc --- /dev/null +++ b/tests/components/xiaomi_gcls002/test.esp32.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_gcls002 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: GCLS02 Temperature + moisture: + name: GCLS02 Moisture + conductivity: + name: GCLS02 Soil Conductivity + illuminance: + name: GCLS02 Illuminance diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0def909488 --- /dev/null +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccjcy01 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: Xiaomi HHCCJCY01 Temperature + moisture: + name: Xiaomi HHCCJCY01 Moisture + illuminance: + name: Xiaomi HHCCJCY01 Illuminance + conductivity: + name: Xiaomi HHCCJCY01 Soil Conductivity + battery_level: + name: Xiaomi HHCCJCY01 Battery Level diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml new file mode 100644 index 0000000000..0def909488 --- /dev/null +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccjcy01 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: Xiaomi HHCCJCY01 Temperature + moisture: + name: Xiaomi HHCCJCY01 Moisture + illuminance: + name: Xiaomi HHCCJCY01 Illuminance + conductivity: + name: Xiaomi HHCCJCY01 Soil Conductivity + battery_level: + name: Xiaomi HHCCJCY01 Battery Level diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml new file mode 100644 index 0000000000..0def909488 --- /dev/null +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccjcy01 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: Xiaomi HHCCJCY01 Temperature + moisture: + name: Xiaomi HHCCJCY01 Moisture + illuminance: + name: Xiaomi HHCCJCY01 Illuminance + conductivity: + name: Xiaomi HHCCJCY01 Soil Conductivity + battery_level: + name: Xiaomi HHCCJCY01 Battery Level diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32.yaml new file mode 100644 index 0000000000..0def909488 --- /dev/null +++ b/tests/components/xiaomi_hhccjcy01/test.esp32.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccjcy01 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: Xiaomi HHCCJCY01 Temperature + moisture: + name: Xiaomi HHCCJCY01 Moisture + illuminance: + name: Xiaomi HHCCJCY01 Illuminance + conductivity: + name: Xiaomi HHCCJCY01 Soil Conductivity + battery_level: + name: Xiaomi HHCCJCY01 Battery Level diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2e5fa14620 --- /dev/null +++ b/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccpot002 + mac_address: 94:2B:FF:5C:91:61 + moisture: + name: HHCCPOT002 Moisture + conductivity: + name: HHCCPOT002 Soil Conductivity diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml new file mode 100644 index 0000000000..2e5fa14620 --- /dev/null +++ b/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccpot002 + mac_address: 94:2B:FF:5C:91:61 + moisture: + name: HHCCPOT002 Moisture + conductivity: + name: HHCCPOT002 Soil Conductivity diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml new file mode 100644 index 0000000000..2e5fa14620 --- /dev/null +++ b/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccpot002 + mac_address: 94:2B:FF:5C:91:61 + moisture: + name: HHCCPOT002 Moisture + conductivity: + name: HHCCPOT002 Soil Conductivity diff --git a/tests/components/xiaomi_hhccpot002/test.esp32.yaml b/tests/components/xiaomi_hhccpot002/test.esp32.yaml new file mode 100644 index 0000000000..2e5fa14620 --- /dev/null +++ b/tests/components/xiaomi_hhccpot002/test.esp32.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccpot002 + mac_address: 94:2B:FF:5C:91:61 + moisture: + name: HHCCPOT002 Moisture + conductivity: + name: HHCCPOT002 Soil Conductivity diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..54c4b33dcd --- /dev/null +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_jqjcy01ym + mac_address: 7A:80:8E:19:36:BA + temperature: + name: JQJCY01YM Temperature + humidity: + name: JQJCY01YM Humidity + formaldehyde: + name: JQJCY01YM Formaldehyde + battery_level: + name: JQJCY01YM Battery Level diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml new file mode 100644 index 0000000000..54c4b33dcd --- /dev/null +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_jqjcy01ym + mac_address: 7A:80:8E:19:36:BA + temperature: + name: JQJCY01YM Temperature + humidity: + name: JQJCY01YM Humidity + formaldehyde: + name: JQJCY01YM Formaldehyde + battery_level: + name: JQJCY01YM Battery Level diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml new file mode 100644 index 0000000000..54c4b33dcd --- /dev/null +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_jqjcy01ym + mac_address: 7A:80:8E:19:36:BA + temperature: + name: JQJCY01YM Temperature + humidity: + name: JQJCY01YM Humidity + formaldehyde: + name: JQJCY01YM Formaldehyde + battery_level: + name: JQJCY01YM Battery Level diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml new file mode 100644 index 0000000000..54c4b33dcd --- /dev/null +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_jqjcy01ym + mac_address: 7A:80:8E:19:36:BA + temperature: + name: JQJCY01YM Temperature + humidity: + name: JQJCY01YM Humidity + formaldehyde: + name: JQJCY01YM Formaldehyde + battery_level: + name: JQJCY01YM Battery Level diff --git a/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3e40ab8d70 --- /dev/null +++ b/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02 + mac_address: 3F:5B:7D:82:58:4E + temperature: + name: Xiaomi LYWSD02 Temperature + humidity: + name: Xiaomi LYWSD02 Humidity + battery_level: + name: Xiaomi LYWSD02 Battery Level diff --git a/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml new file mode 100644 index 0000000000..3e40ab8d70 --- /dev/null +++ b/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02 + mac_address: 3F:5B:7D:82:58:4E + temperature: + name: Xiaomi LYWSD02 Temperature + humidity: + name: Xiaomi LYWSD02 Humidity + battery_level: + name: Xiaomi LYWSD02 Battery Level diff --git a/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml b/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml new file mode 100644 index 0000000000..3e40ab8d70 --- /dev/null +++ b/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02 + mac_address: 3F:5B:7D:82:58:4E + temperature: + name: Xiaomi LYWSD02 Temperature + humidity: + name: Xiaomi LYWSD02 Humidity + battery_level: + name: Xiaomi LYWSD02 Battery Level diff --git a/tests/components/xiaomi_lywsd02/test.esp32.yaml b/tests/components/xiaomi_lywsd02/test.esp32.yaml new file mode 100644 index 0000000000..3e40ab8d70 --- /dev/null +++ b/tests/components/xiaomi_lywsd02/test.esp32.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02 + mac_address: 3F:5B:7D:82:58:4E + temperature: + name: Xiaomi LYWSD02 Temperature + humidity: + name: Xiaomi LYWSD02 Humidity + battery_level: + name: Xiaomi LYWSD02 Battery Level diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d10a859c56 --- /dev/null +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd03mmc + mac_address: A4:C1:38:4E:16:78 + bindkey: e9efaa6873f9f9c87a5e75a5f814801c + temperature: + name: Xiaomi LYWSD03MMC Temperature + humidity: + name: Xiaomi LYWSD03MMC Humidity + battery_level: + name: Xiaomi LYWSD03MMC Battery Level diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml new file mode 100644 index 0000000000..d10a859c56 --- /dev/null +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd03mmc + mac_address: A4:C1:38:4E:16:78 + bindkey: e9efaa6873f9f9c87a5e75a5f814801c + temperature: + name: Xiaomi LYWSD03MMC Temperature + humidity: + name: Xiaomi LYWSD03MMC Humidity + battery_level: + name: Xiaomi LYWSD03MMC Battery Level diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml new file mode 100644 index 0000000000..d10a859c56 --- /dev/null +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd03mmc + mac_address: A4:C1:38:4E:16:78 + bindkey: e9efaa6873f9f9c87a5e75a5f814801c + temperature: + name: Xiaomi LYWSD03MMC Temperature + humidity: + name: Xiaomi LYWSD03MMC Humidity + battery_level: + name: Xiaomi LYWSD03MMC Battery Level diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml new file mode 100644 index 0000000000..d10a859c56 --- /dev/null +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd03mmc + mac_address: A4:C1:38:4E:16:78 + bindkey: e9efaa6873f9f9c87a5e75a5f814801c + temperature: + name: Xiaomi LYWSD03MMC Temperature + humidity: + name: Xiaomi LYWSD03MMC Humidity + battery_level: + name: Xiaomi LYWSD03MMC Battery Level diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d8422b4c0c --- /dev/null +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsdcgq + mac_address: 7A:80:8E:19:36:BA + temperature: + name: Xiaomi LYWSDCGQ Temperature + humidity: + name: Xiaomi LYWSDCGQ Humidity + battery_level: + name: Xiaomi LYWSDCGQ Battery Level diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml new file mode 100644 index 0000000000..d8422b4c0c --- /dev/null +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsdcgq + mac_address: 7A:80:8E:19:36:BA + temperature: + name: Xiaomi LYWSDCGQ Temperature + humidity: + name: Xiaomi LYWSDCGQ Humidity + battery_level: + name: Xiaomi LYWSDCGQ Battery Level diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml new file mode 100644 index 0000000000..d8422b4c0c --- /dev/null +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsdcgq + mac_address: 7A:80:8E:19:36:BA + temperature: + name: Xiaomi LYWSDCGQ Temperature + humidity: + name: Xiaomi LYWSDCGQ Humidity + battery_level: + name: Xiaomi LYWSDCGQ Battery Level diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32.yaml new file mode 100644 index 0000000000..d8422b4c0c --- /dev/null +++ b/tests/components/xiaomi_lywsdcgq/test.esp32.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsdcgq + mac_address: 7A:80:8E:19:36:BA + temperature: + name: Xiaomi LYWSDCGQ Temperature + humidity: + name: Xiaomi LYWSDCGQ Humidity + battery_level: + name: Xiaomi LYWSDCGQ Battery Level diff --git a/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e4353d3c6a --- /dev/null +++ b/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc303 + mac_address: E7:50:59:32:A0:1C + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml new file mode 100644 index 0000000000..e4353d3c6a --- /dev/null +++ b/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc303 + mac_address: E7:50:59:32:A0:1C + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml b/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml new file mode 100644 index 0000000000..e4353d3c6a --- /dev/null +++ b/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc303 + mac_address: E7:50:59:32:A0:1C + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc303/test.esp32.yaml b/tests/components/xiaomi_mhoc303/test.esp32.yaml new file mode 100644 index 0000000000..e4353d3c6a --- /dev/null +++ b/tests/components/xiaomi_mhoc303/test.esp32.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc303 + mac_address: E7:50:59:32:A0:1C + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ae378f5604 --- /dev/null +++ b/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc401 + mac_address: E7:50:59:32:A0:1C + bindkey: "eef418daf699a0c188f3bfd17e4565d9" + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml new file mode 100644 index 0000000000..ae378f5604 --- /dev/null +++ b/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc401 + mac_address: E7:50:59:32:A0:1C + bindkey: "eef418daf699a0c188f3bfd17e4565d9" + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml b/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml new file mode 100644 index 0000000000..ae378f5604 --- /dev/null +++ b/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc401 + mac_address: E7:50:59:32:A0:1C + bindkey: "eef418daf699a0c188f3bfd17e4565d9" + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc401/test.esp32.yaml b/tests/components/xiaomi_mhoc401/test.esp32.yaml new file mode 100644 index 0000000000..ae378f5604 --- /dev/null +++ b/tests/components/xiaomi_mhoc401/test.esp32.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc401 + mac_address: E7:50:59:32:A0:1C + bindkey: "eef418daf699a0c188f3bfd17e4565d9" + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml b/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml b/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml b/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale copy/test.esp32.yaml b/tests/components/xiaomi_miscale copy/test.esp32.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale copy/test.esp32.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml b/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale/test.esp32-c3.yaml b/tests/components/xiaomi_miscale/test.esp32-c3.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale/test.esp32-idf.yaml b/tests/components/xiaomi_miscale/test.esp32-idf.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale/test.esp32.yaml b/tests/components/xiaomi_miscale/test.esp32.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale/test.esp32.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dffcef84c4 --- /dev/null +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mjyd02yla + name: MJYD02YL-A Motion + mac_address: 50:EC:50:CD:32:02 + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + idle_time: + name: MJYD02YL-A Idle Time + light: + name: MJYD02YL-A Light Status + battery_level: + name: MJYD02YL-A Battery Level diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml new file mode 100644 index 0000000000..dffcef84c4 --- /dev/null +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mjyd02yla + name: MJYD02YL-A Motion + mac_address: 50:EC:50:CD:32:02 + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + idle_time: + name: MJYD02YL-A Idle Time + light: + name: MJYD02YL-A Light Status + battery_level: + name: MJYD02YL-A Battery Level diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml new file mode 100644 index 0000000000..dffcef84c4 --- /dev/null +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mjyd02yla + name: MJYD02YL-A Motion + mac_address: 50:EC:50:CD:32:02 + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + idle_time: + name: MJYD02YL-A Idle Time + light: + name: MJYD02YL-A Light Status + battery_level: + name: MJYD02YL-A Battery Level diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32.yaml new file mode 100644 index 0000000000..dffcef84c4 --- /dev/null +++ b/tests/components/xiaomi_mjyd02yla/test.esp32.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mjyd02yla + name: MJYD02YL-A Motion + mac_address: 50:EC:50:CD:32:02 + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + idle_time: + name: MJYD02YL-A Idle Time + light: + name: MJYD02YL-A Light Status + battery_level: + name: MJYD02YL-A Battery Level diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4f0e5ccbae --- /dev/null +++ b/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mue4094rt + name: MUE4094RT Motion + mac_address: 7A:80:8E:19:36:BA + timeout: 5s diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml new file mode 100644 index 0000000000..4f0e5ccbae --- /dev/null +++ b/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mue4094rt + name: MUE4094RT Motion + mac_address: 7A:80:8E:19:36:BA + timeout: 5s diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml new file mode 100644 index 0000000000..4f0e5ccbae --- /dev/null +++ b/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mue4094rt + name: MUE4094RT Motion + mac_address: 7A:80:8E:19:36:BA + timeout: 5s diff --git a/tests/components/xiaomi_mue4094rt/test.esp32.yaml b/tests/components/xiaomi_mue4094rt/test.esp32.yaml new file mode 100644 index 0000000000..4f0e5ccbae --- /dev/null +++ b/tests/components/xiaomi_mue4094rt/test.esp32.yaml @@ -0,0 +1,7 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mue4094rt + name: MUE4094RT Motion + mac_address: 7A:80:8E:19:36:BA + timeout: 5s diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a2e0c66ba5 --- /dev/null +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +xiaomi_rtcgq02lm: + - id: motion_rtcgq02lm + mac_address: 01:02:03:04:05:06 + bindkey: "48403ebe2d385db8d0c187f81e62cb64" + +binary_sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + motion: + name: Mi Motion Sensor 2 + light: + name: Mi Motion Sensor 2 Light + button: + name: Mi Motion Sensor 2 Button + +sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + battery_level: + name: Mi Motion Sensor 2 Battery level diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml new file mode 100644 index 0000000000..a2e0c66ba5 --- /dev/null +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +xiaomi_rtcgq02lm: + - id: motion_rtcgq02lm + mac_address: 01:02:03:04:05:06 + bindkey: "48403ebe2d385db8d0c187f81e62cb64" + +binary_sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + motion: + name: Mi Motion Sensor 2 + light: + name: Mi Motion Sensor 2 Light + button: + name: Mi Motion Sensor 2 Button + +sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + battery_level: + name: Mi Motion Sensor 2 Battery level diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml new file mode 100644 index 0000000000..a2e0c66ba5 --- /dev/null +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +xiaomi_rtcgq02lm: + - id: motion_rtcgq02lm + mac_address: 01:02:03:04:05:06 + bindkey: "48403ebe2d385db8d0c187f81e62cb64" + +binary_sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + motion: + name: Mi Motion Sensor 2 + light: + name: Mi Motion Sensor 2 Light + button: + name: Mi Motion Sensor 2 Button + +sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + battery_level: + name: Mi Motion Sensor 2 Battery level diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml new file mode 100644 index 0000000000..a2e0c66ba5 --- /dev/null +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +xiaomi_rtcgq02lm: + - id: motion_rtcgq02lm + mac_address: 01:02:03:04:05:06 + bindkey: "48403ebe2d385db8d0c187f81e62cb64" + +binary_sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + motion: + name: Mi Motion Sensor 2 + light: + name: Mi Motion Sensor 2 Light + button: + name: Mi Motion Sensor 2 Button + +sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + battery_level: + name: Mi Motion Sensor 2 Battery level diff --git a/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml b/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3e83ad3e95 --- /dev/null +++ b/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_wx08zm + name: WX08ZM Activation State + mac_address: 74:a3:4a:b5:07:34 + tablet: + name: WX08ZM Tablet Resource + battery_level: + name: WX08ZM Battery Level diff --git a/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml b/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml new file mode 100644 index 0000000000..3e83ad3e95 --- /dev/null +++ b/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_wx08zm + name: WX08ZM Activation State + mac_address: 74:a3:4a:b5:07:34 + tablet: + name: WX08ZM Tablet Resource + battery_level: + name: WX08ZM Battery Level diff --git a/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml b/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml new file mode 100644 index 0000000000..3e83ad3e95 --- /dev/null +++ b/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_wx08zm + name: WX08ZM Activation State + mac_address: 74:a3:4a:b5:07:34 + tablet: + name: WX08ZM Tablet Resource + battery_level: + name: WX08ZM Battery Level diff --git a/tests/components/xiaomi_wx08zm/test.esp32.yaml b/tests/components/xiaomi_wx08zm/test.esp32.yaml new file mode 100644 index 0000000000..3e83ad3e95 --- /dev/null +++ b/tests/components/xiaomi_wx08zm/test.esp32.yaml @@ -0,0 +1,10 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_wx08zm + name: WX08ZM Activation State + mac_address: 74:a3:4a:b5:07:34 + tablet: + name: WX08ZM Tablet Resource + battery_level: + name: WX08ZM Battery Level diff --git a/tests/components/xl9535/test.esp32-c3-idf.yaml b/tests/components/xl9535/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..178adf870e --- /dev/null +++ b/tests/components/xl9535/test.esp32-c3-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 5 + sda: 4 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xl9535/test.esp32-c3.yaml b/tests/components/xl9535/test.esp32-c3.yaml new file mode 100644 index 0000000000..178adf870e --- /dev/null +++ b/tests/components/xl9535/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 5 + sda: 4 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xl9535/test.esp32-idf.yaml b/tests/components/xl9535/test.esp32-idf.yaml new file mode 100644 index 0000000000..a65aae890e --- /dev/null +++ b/tests/components/xl9535/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 16 + sda: 17 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xl9535/test.esp32.yaml b/tests/components/xl9535/test.esp32.yaml new file mode 100644 index 0000000000..a65aae890e --- /dev/null +++ b/tests/components/xl9535/test.esp32.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 16 + sda: 17 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xl9535/test.esp8266.yaml b/tests/components/xl9535/test.esp8266.yaml new file mode 100644 index 0000000000..178adf870e --- /dev/null +++ b/tests/components/xl9535/test.esp8266.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 5 + sda: 4 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xl9535/test.rp2040.yaml b/tests/components/xl9535/test.rp2040.yaml new file mode 100644 index 0000000000..178adf870e --- /dev/null +++ b/tests/components/xl9535/test.rp2040.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_xl9535 + scl: 5 + sda: 4 + +xl9535: + - id: xl9535_hub + address: 0x20 + +binary_sensor: + - platform: gpio + name: XL9535 Pin 0 + pin: + xl9535: xl9535_hub + number: 0 + mode: + input: true + inverted: false + - platform: gpio + name: XL9535 Pin 17 + pin: + xl9535: xl9535_hub + number: 17 + mode: + input: true + inverted: false diff --git a/tests/components/xpt2046/test.esp32-c3-idf.yaml b/tests/components/xpt2046/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..38a1da74ae --- /dev/null +++ b/tests/components/xpt2046/test.esp32-c3-idf.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 4 + interrupt_pin: 3 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/xpt2046/test.esp32-c3.yaml b/tests/components/xpt2046/test.esp32-c3.yaml new file mode 100644 index 0000000000..38a1da74ae --- /dev/null +++ b/tests/components/xpt2046/test.esp32-c3.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 4 + interrupt_pin: 3 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/xpt2046/test.esp32-idf.yaml b/tests/components/xpt2046/test.esp32-idf.yaml new file mode 100644 index 0000000000..7f8617d176 --- /dev/null +++ b/tests/components/xpt2046/test.esp32-idf.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 13 + dc_pin: 14 + reset_pin: 21 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 18 + interrupt_pin: 19 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/xpt2046/test.esp32.yaml b/tests/components/xpt2046/test.esp32.yaml new file mode 100644 index 0000000000..7f8617d176 --- /dev/null +++ b/tests/components/xpt2046/test.esp32.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 13 + dc_pin: 14 + reset_pin: 21 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 18 + interrupt_pin: 19 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/xpt2046/test.esp8266.yaml b/tests/components/xpt2046/test.esp8266.yaml new file mode 100644 index 0000000000..a998d2df14 --- /dev/null +++ b/tests/components/xpt2046/test.esp8266.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 15 + dc_pin: 4 + reset_pin: 5 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 0 + interrupt_pin: 16 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/xpt2046/test.rp2040.yaml b/tests/components/xpt2046/test.rp2040.yaml new file mode 100644 index 0000000000..3e5d602247 --- /dev/null +++ b/tests/components/xpt2046/test.rp2040.yaml @@ -0,0 +1,33 @@ +spi: + - id: spi_xpt2046 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ili9xxx + id: xpt_display + dimensions: 320x240 + model: TFT 2.4 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: xpt2046 + id: xpt_touchscreen + cs_pin: 5 + interrupt_pin: 6 + display: xpt_display + update_interval: 50ms + threshold: 400 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/yashima/test.esp32-c3-idf.yaml b/tests/components/yashima/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4b6d6daee4 --- /dev/null +++ b/tests/components/yashima/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: yashima + name: Yashima Climate diff --git a/tests/components/yashima/test.esp32-c3.yaml b/tests/components/yashima/test.esp32-c3.yaml new file mode 100644 index 0000000000..4b6d6daee4 --- /dev/null +++ b/tests/components/yashima/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: yashima + name: Yashima Climate diff --git a/tests/components/yashima/test.esp32-idf.yaml b/tests/components/yashima/test.esp32-idf.yaml new file mode 100644 index 0000000000..4b6d6daee4 --- /dev/null +++ b/tests/components/yashima/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: yashima + name: Yashima Climate diff --git a/tests/components/yashima/test.esp32.yaml b/tests/components/yashima/test.esp32.yaml new file mode 100644 index 0000000000..4b6d6daee4 --- /dev/null +++ b/tests/components/yashima/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: yashima + name: Yashima Climate diff --git a/tests/components/yashima/test.esp8266.yaml b/tests/components/yashima/test.esp8266.yaml new file mode 100644 index 0000000000..296a7ede25 --- /dev/null +++ b/tests/components/yashima/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: yashima + name: Yashima Climate diff --git a/tests/components/zhlt01/test.esp32-c3-idf.yaml b/tests/components/zhlt01/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d1dc3b4926 --- /dev/null +++ b/tests/components/zhlt01/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: zhlt01 + name: ZH/LT-01 Climate diff --git a/tests/components/zhlt01/test.esp32-c3.yaml b/tests/components/zhlt01/test.esp32-c3.yaml new file mode 100644 index 0000000000..d1dc3b4926 --- /dev/null +++ b/tests/components/zhlt01/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: zhlt01 + name: ZH/LT-01 Climate diff --git a/tests/components/zhlt01/test.esp32-idf.yaml b/tests/components/zhlt01/test.esp32-idf.yaml new file mode 100644 index 0000000000..d1dc3b4926 --- /dev/null +++ b/tests/components/zhlt01/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: zhlt01 + name: ZH/LT-01 Climate diff --git a/tests/components/zhlt01/test.esp32.yaml b/tests/components/zhlt01/test.esp32.yaml new file mode 100644 index 0000000000..d1dc3b4926 --- /dev/null +++ b/tests/components/zhlt01/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: zhlt01 + name: ZH/LT-01 Climate diff --git a/tests/components/zhlt01/test.esp8266.yaml b/tests/components/zhlt01/test.esp8266.yaml new file mode 100644 index 0000000000..40a00bc458 --- /dev/null +++ b/tests/components/zhlt01/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: zhlt01 + name: ZH/LT-01 Climate diff --git a/tests/components/zio_ultrasonic/test.esp32-c3-idf.yaml b/tests/components/zio_ultrasonic/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..36e1697a38 --- /dev/null +++ b/tests/components/zio_ultrasonic/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 5 + sda: 4 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zio_ultrasonic/test.esp32-c3.yaml b/tests/components/zio_ultrasonic/test.esp32-c3.yaml new file mode 100644 index 0000000000..36e1697a38 --- /dev/null +++ b/tests/components/zio_ultrasonic/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 5 + sda: 4 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zio_ultrasonic/test.esp32-idf.yaml b/tests/components/zio_ultrasonic/test.esp32-idf.yaml new file mode 100644 index 0000000000..ad4050307e --- /dev/null +++ b/tests/components/zio_ultrasonic/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 16 + sda: 17 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zio_ultrasonic/test.esp32.yaml b/tests/components/zio_ultrasonic/test.esp32.yaml new file mode 100644 index 0000000000..ad4050307e --- /dev/null +++ b/tests/components/zio_ultrasonic/test.esp32.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 16 + sda: 17 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zio_ultrasonic/test.esp8266.yaml b/tests/components/zio_ultrasonic/test.esp8266.yaml new file mode 100644 index 0000000000..36e1697a38 --- /dev/null +++ b/tests/components/zio_ultrasonic/test.esp8266.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 5 + sda: 4 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zio_ultrasonic/test.rp2040.yaml b/tests/components/zio_ultrasonic/test.rp2040.yaml new file mode 100644 index 0000000000..36e1697a38 --- /dev/null +++ b/tests/components/zio_ultrasonic/test.rp2040.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_zio_ultrasonic + scl: 5 + sda: 4 + +sensor: + - platform: zio_ultrasonic + name: "Distance" + update_interval: 60s diff --git a/tests/components/zyaura/test.esp32-c3-idf.yaml b/tests/components/zyaura/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..90205c468c --- /dev/null +++ b/tests/components/zyaura/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 5 + data_pin: 4 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity diff --git a/tests/components/zyaura/test.esp32-c3.yaml b/tests/components/zyaura/test.esp32-c3.yaml new file mode 100644 index 0000000000..90205c468c --- /dev/null +++ b/tests/components/zyaura/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 5 + data_pin: 4 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity diff --git a/tests/components/zyaura/test.esp32-idf.yaml b/tests/components/zyaura/test.esp32-idf.yaml new file mode 100644 index 0000000000..29116a978b --- /dev/null +++ b/tests/components/zyaura/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 16 + data_pin: 17 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity diff --git a/tests/components/zyaura/test.esp32.yaml b/tests/components/zyaura/test.esp32.yaml new file mode 100644 index 0000000000..29116a978b --- /dev/null +++ b/tests/components/zyaura/test.esp32.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 16 + data_pin: 17 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity diff --git a/tests/components/zyaura/test.esp8266.yaml b/tests/components/zyaura/test.esp8266.yaml new file mode 100644 index 0000000000..90205c468c --- /dev/null +++ b/tests/components/zyaura/test.esp8266.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 5 + data_pin: 4 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity diff --git a/tests/components/zyaura/test.rp2040.yaml b/tests/components/zyaura/test.rp2040.yaml new file mode 100644 index 0000000000..90205c468c --- /dev/null +++ b/tests/components/zyaura/test.rp2040.yaml @@ -0,0 +1,10 @@ +sensor: + - platform: zyaura + clock_pin: 5 + data_pin: 4 + co2: + name: ZyAura CO2 + temperature: + name: ZyAura Temperature + humidity: + name: ZyAura Humidity From 61f11386a94424f892e70fbc7bf86afc60f38c9f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 18 Mar 2024 18:52:40 -0500 Subject: [PATCH 1415/2607] Add some components to the new testing framework (E) (#6176) --- tests/components/e131/test.esp32-c3-idf.yaml | 18 ++++++ tests/components/e131/test.esp32-c3.yaml | 18 ++++++ tests/components/e131/test.esp32-idf.yaml | 18 ++++++ tests/components/e131/test.esp32.yaml | 18 ++++++ tests/components/e131/test.esp8266.yaml | 17 ++++++ tests/components/e131/test.rp2040.yaml | 17 ++++++ tests/components/ee895/test.esp32-c3-idf.yaml | 14 +++++ tests/components/ee895/test.esp32-c3.yaml | 14 +++++ tests/components/ee895/test.esp32-idf.yaml | 14 +++++ tests/components/ee895/test.esp32.yaml | 14 +++++ tests/components/ee895/test.esp8266.yaml | 14 +++++ tests/components/ee895/test.rp2040.yaml | 14 +++++ .../ektf2232/test.esp32-c3-idf.yaml | 24 ++++++++ tests/components/ektf2232/test.esp32-c3.yaml | 24 ++++++++ tests/components/ektf2232/test.esp32-idf.yaml | 24 ++++++++ tests/components/ektf2232/test.esp32.yaml | 24 ++++++++ tests/components/ektf2232/test.esp8266.yaml | 24 ++++++++ tests/components/ektf2232/test.rp2040.yaml | 24 ++++++++ .../components/emc2101/test.esp32-c3-idf.yaml | 25 ++++++++ tests/components/emc2101/test.esp32-c3.yaml | 25 ++++++++ tests/components/emc2101/test.esp32-idf.yaml | 25 ++++++++ tests/components/emc2101/test.esp32.yaml | 25 ++++++++ tests/components/emc2101/test.esp8266.yaml | 25 ++++++++ tests/components/emc2101/test.rp2040.yaml | 25 ++++++++ .../components/endstop/test.esp32-c3-idf.yaml | 33 ++++++++++ tests/components/endstop/test.esp32-c3.yaml | 33 ++++++++++ tests/components/endstop/test.esp32-idf.yaml | 33 ++++++++++ tests/components/endstop/test.esp32.yaml | 33 ++++++++++ tests/components/endstop/test.esp8266.yaml | 33 ++++++++++ tests/components/endstop/test.rp2040.yaml | 33 ++++++++++ .../components/ens160/test.esp32-c3-idf.yaml | 13 ++++ tests/components/ens160/test.esp32-c3.yaml | 13 ++++ tests/components/ens160/test.esp32-idf.yaml | 13 ++++ tests/components/ens160/test.esp32.yaml | 13 ++++ tests/components/ens160/test.esp8266.yaml | 13 ++++ tests/components/ens160/test.rp2040.yaml | 13 ++++ .../components/ens210/test.esp32-c3-idf.yaml | 12 ++++ tests/components/ens210/test.esp32-c3.yaml | 12 ++++ tests/components/ens210/test.esp32-idf.yaml | 12 ++++ tests/components/ens210/test.esp32.yaml | 12 ++++ tests/components/ens210/test.esp8266.yaml | 12 ++++ tests/components/ens210/test.rp2040.yaml | 12 ++++ .../esp32_ble/test.esp32-c3-idf.yaml | 2 + tests/components/esp32_ble/test.esp32-c3.yaml | 2 + .../components/esp32_ble/test.esp32-idf.yaml | 2 + tests/components/esp32_ble/test.esp32.yaml | 2 + .../esp32_ble_beacon/test.esp32-c3-idf.yaml | 3 + .../esp32_ble_beacon/test.esp32-c3.yaml | 3 + .../esp32_ble_beacon/test.esp32-idf.yaml | 3 + .../esp32_ble_beacon/test.esp32.yaml | 3 + .../esp32_ble_client/test.esp32-c3-idf.yaml | 5 ++ .../esp32_ble_client/test.esp32-c3.yaml | 5 ++ .../esp32_ble_client/test.esp32-idf.yaml | 5 ++ .../esp32_ble_client/test.esp32.yaml | 5 ++ .../esp32_ble_server/test.esp32-c3-idf.yaml | 3 + .../esp32_ble_server/test.esp32-c3.yaml | 3 + .../esp32_ble_server/test.esp32-idf.yaml | 3 + .../esp32_ble_server/test.esp32.yaml | 3 + .../esp32_ble_tracker/test.esp32-c3-idf.yaml | 41 +++++++++++++ .../esp32_ble_tracker/test.esp32-c3.yaml | 41 +++++++++++++ .../esp32_ble_tracker/test.esp32-idf.yaml | 41 +++++++++++++ .../esp32_ble_tracker/test.esp32.yaml | 41 +++++++++++++ .../esp32_camera/test.esp32-idf.yaml | 28 +++++++++ tests/components/esp32_camera/test.esp32.yaml | 28 +++++++++ .../test.esp32-idf.yaml | 34 +++++++++++ .../esp32_camera_web_server/test.esp32.yaml | 34 +++++++++++ .../esp32_can/test.esp32-c3-idf.yaml | 45 ++++++++++++++ tests/components/esp32_can/test.esp32-c3.yaml | 45 ++++++++++++++ .../components/esp32_can/test.esp32-idf.yaml | 45 ++++++++++++++ tests/components/esp32_can/test.esp32.yaml | 45 ++++++++++++++ .../components/esp32_dac/test.esp32-idf.yaml | 4 ++ tests/components/esp32_dac/test.esp32.yaml | 4 ++ .../components/esp32_hall/test.esp32-idf.yaml | 3 + tests/components/esp32_hall/test.esp32.yaml | 3 + .../esp32_improv/test.esp32-c3-idf.yaml | 18 ++++++ .../esp32_improv/test.esp32-c3.yaml | 18 ++++++ .../esp32_improv/test.esp32-idf.yaml | 18 ++++++ tests/components/esp32_improv/test.esp32.yaml | 18 ++++++ .../test.esp32-c3-idf.yaml | 18 ++++++ .../esp32_rmt_led_strip/test.esp32-c3.yaml | 18 ++++++ .../esp32_rmt_led_strip/test.esp32-idf.yaml | 18 ++++++ .../esp32_rmt_led_strip/test.esp32.yaml | 18 ++++++ .../esp32_touch/test.esp32-idf.yaml | 16 +++++ tests/components/esp32_touch/test.esp32.yaml | 16 +++++ .../components/esp8266_pwm/test.esp8266.yaml | 8 +++ tests/components/ethernet/test.esp32-idf.yaml | 12 ++++ tests/components/ethernet/test.esp32.yaml | 12 ++++ .../ethernet_info/test.esp32-idf.yaml | 17 ++++++ .../components/ethernet_info/test.esp32.yaml | 17 ++++++ .../test.esp32-c3-idf.yaml | 9 +++ .../exposure_notifications/test.esp32-c3.yaml | 9 +++ .../test.esp32-idf.yaml | 9 +++ .../exposure_notifications/test.esp32.yaml | 9 +++ .../test.esp32-c3-idf.yaml | 6 ++ .../external_components/test.esp32-c3.yaml | 6 ++ .../external_components/test.esp32-idf.yaml | 6 ++ .../external_components/test.esp32.yaml | 6 ++ .../external_components/test.esp8266.yaml | 6 ++ .../external_components/test.rp2040.yaml | 6 ++ tests/components/ezo/test.esp32-c3-idf.yaml | 10 +++ tests/components/ezo/test.esp32-c3.yaml | 10 +++ tests/components/ezo/test.esp32-idf.yaml | 10 +++ tests/components/ezo/test.esp32.yaml | 10 +++ tests/components/ezo/test.esp8266.yaml | 10 +++ tests/components/ezo/test.rp2040.yaml | 10 +++ .../components/ezo_pmp/test.esp32-c3-idf.yaml | 61 +++++++++++++++++++ tests/components/ezo_pmp/test.esp32-c3.yaml | 61 +++++++++++++++++++ tests/components/ezo_pmp/test.esp32-idf.yaml | 61 +++++++++++++++++++ tests/components/ezo_pmp/test.esp32.yaml | 61 +++++++++++++++++++ tests/components/ezo_pmp/test.esp8266.yaml | 61 +++++++++++++++++++ tests/components/ezo_pmp/test.rp2040.yaml | 61 +++++++++++++++++++ 111 files changed, 2106 insertions(+) create mode 100644 tests/components/e131/test.esp32-c3-idf.yaml create mode 100644 tests/components/e131/test.esp32-c3.yaml create mode 100644 tests/components/e131/test.esp32-idf.yaml create mode 100644 tests/components/e131/test.esp32.yaml create mode 100644 tests/components/e131/test.esp8266.yaml create mode 100644 tests/components/e131/test.rp2040.yaml create mode 100644 tests/components/ee895/test.esp32-c3-idf.yaml create mode 100644 tests/components/ee895/test.esp32-c3.yaml create mode 100644 tests/components/ee895/test.esp32-idf.yaml create mode 100644 tests/components/ee895/test.esp32.yaml create mode 100644 tests/components/ee895/test.esp8266.yaml create mode 100644 tests/components/ee895/test.rp2040.yaml create mode 100644 tests/components/ektf2232/test.esp32-c3-idf.yaml create mode 100644 tests/components/ektf2232/test.esp32-c3.yaml create mode 100644 tests/components/ektf2232/test.esp32-idf.yaml create mode 100644 tests/components/ektf2232/test.esp32.yaml create mode 100644 tests/components/ektf2232/test.esp8266.yaml create mode 100644 tests/components/ektf2232/test.rp2040.yaml create mode 100644 tests/components/emc2101/test.esp32-c3-idf.yaml create mode 100644 tests/components/emc2101/test.esp32-c3.yaml create mode 100644 tests/components/emc2101/test.esp32-idf.yaml create mode 100644 tests/components/emc2101/test.esp32.yaml create mode 100644 tests/components/emc2101/test.esp8266.yaml create mode 100644 tests/components/emc2101/test.rp2040.yaml create mode 100644 tests/components/endstop/test.esp32-c3-idf.yaml create mode 100644 tests/components/endstop/test.esp32-c3.yaml create mode 100644 tests/components/endstop/test.esp32-idf.yaml create mode 100644 tests/components/endstop/test.esp32.yaml create mode 100644 tests/components/endstop/test.esp8266.yaml create mode 100644 tests/components/endstop/test.rp2040.yaml create mode 100644 tests/components/ens160/test.esp32-c3-idf.yaml create mode 100644 tests/components/ens160/test.esp32-c3.yaml create mode 100644 tests/components/ens160/test.esp32-idf.yaml create mode 100644 tests/components/ens160/test.esp32.yaml create mode 100644 tests/components/ens160/test.esp8266.yaml create mode 100644 tests/components/ens160/test.rp2040.yaml create mode 100644 tests/components/ens210/test.esp32-c3-idf.yaml create mode 100644 tests/components/ens210/test.esp32-c3.yaml create mode 100644 tests/components/ens210/test.esp32-idf.yaml create mode 100644 tests/components/ens210/test.esp32.yaml create mode 100644 tests/components/ens210/test.esp8266.yaml create mode 100644 tests/components/ens210/test.rp2040.yaml create mode 100644 tests/components/esp32_ble/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_ble/test.esp32-c3.yaml create mode 100644 tests/components/esp32_ble/test.esp32-idf.yaml create mode 100644 tests/components/esp32_ble/test.esp32.yaml create mode 100644 tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_ble_beacon/test.esp32-c3.yaml create mode 100644 tests/components/esp32_ble_beacon/test.esp32-idf.yaml create mode 100644 tests/components/esp32_ble_beacon/test.esp32.yaml create mode 100644 tests/components/esp32_ble_client/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_ble_client/test.esp32-c3.yaml create mode 100644 tests/components/esp32_ble_client/test.esp32-idf.yaml create mode 100644 tests/components/esp32_ble_client/test.esp32.yaml create mode 100644 tests/components/esp32_ble_server/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_ble_server/test.esp32-c3.yaml create mode 100644 tests/components/esp32_ble_server/test.esp32-idf.yaml create mode 100644 tests/components/esp32_ble_server/test.esp32.yaml create mode 100644 tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_ble_tracker/test.esp32-c3.yaml create mode 100644 tests/components/esp32_ble_tracker/test.esp32-idf.yaml create mode 100644 tests/components/esp32_ble_tracker/test.esp32.yaml create mode 100644 tests/components/esp32_camera/test.esp32-idf.yaml create mode 100644 tests/components/esp32_camera/test.esp32.yaml create mode 100644 tests/components/esp32_camera_web_server/test.esp32-idf.yaml create mode 100644 tests/components/esp32_camera_web_server/test.esp32.yaml create mode 100644 tests/components/esp32_can/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_can/test.esp32-c3.yaml create mode 100644 tests/components/esp32_can/test.esp32-idf.yaml create mode 100644 tests/components/esp32_can/test.esp32.yaml create mode 100644 tests/components/esp32_dac/test.esp32-idf.yaml create mode 100644 tests/components/esp32_dac/test.esp32.yaml create mode 100644 tests/components/esp32_hall/test.esp32-idf.yaml create mode 100644 tests/components/esp32_hall/test.esp32.yaml create mode 100644 tests/components/esp32_improv/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_improv/test.esp32-c3.yaml create mode 100644 tests/components/esp32_improv/test.esp32-idf.yaml create mode 100644 tests/components/esp32_improv/test.esp32.yaml create mode 100644 tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml create mode 100644 tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml create mode 100644 tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml create mode 100644 tests/components/esp32_rmt_led_strip/test.esp32.yaml create mode 100644 tests/components/esp32_touch/test.esp32-idf.yaml create mode 100644 tests/components/esp32_touch/test.esp32.yaml create mode 100644 tests/components/esp8266_pwm/test.esp8266.yaml create mode 100644 tests/components/ethernet/test.esp32-idf.yaml create mode 100644 tests/components/ethernet/test.esp32.yaml create mode 100644 tests/components/ethernet_info/test.esp32-idf.yaml create mode 100644 tests/components/ethernet_info/test.esp32.yaml create mode 100644 tests/components/exposure_notifications/test.esp32-c3-idf.yaml create mode 100644 tests/components/exposure_notifications/test.esp32-c3.yaml create mode 100644 tests/components/exposure_notifications/test.esp32-idf.yaml create mode 100644 tests/components/exposure_notifications/test.esp32.yaml create mode 100644 tests/components/external_components/test.esp32-c3-idf.yaml create mode 100644 tests/components/external_components/test.esp32-c3.yaml create mode 100644 tests/components/external_components/test.esp32-idf.yaml create mode 100644 tests/components/external_components/test.esp32.yaml create mode 100644 tests/components/external_components/test.esp8266.yaml create mode 100644 tests/components/external_components/test.rp2040.yaml create mode 100644 tests/components/ezo/test.esp32-c3-idf.yaml create mode 100644 tests/components/ezo/test.esp32-c3.yaml create mode 100644 tests/components/ezo/test.esp32-idf.yaml create mode 100644 tests/components/ezo/test.esp32.yaml create mode 100644 tests/components/ezo/test.esp8266.yaml create mode 100644 tests/components/ezo/test.rp2040.yaml create mode 100644 tests/components/ezo_pmp/test.esp32-c3-idf.yaml create mode 100644 tests/components/ezo_pmp/test.esp32-c3.yaml create mode 100644 tests/components/ezo_pmp/test.esp32-idf.yaml create mode 100644 tests/components/ezo_pmp/test.esp32.yaml create mode 100644 tests/components/ezo_pmp/test.esp8266.yaml create mode 100644 tests/components/ezo_pmp/test.rp2040.yaml diff --git a/tests/components/e131/test.esp32-c3-idf.yaml b/tests/components/e131/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25304cd3b4 --- /dev/null +++ b/tests/components/e131/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - e131: + universe: 1 diff --git a/tests/components/e131/test.esp32-c3.yaml b/tests/components/e131/test.esp32-c3.yaml new file mode 100644 index 0000000000..25304cd3b4 --- /dev/null +++ b/tests/components/e131/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - e131: + universe: 1 diff --git a/tests/components/e131/test.esp32-idf.yaml b/tests/components/e131/test.esp32-idf.yaml new file mode 100644 index 0000000000..25304cd3b4 --- /dev/null +++ b/tests/components/e131/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - e131: + universe: 1 diff --git a/tests/components/e131/test.esp32.yaml b/tests/components/e131/test.esp32.yaml new file mode 100644 index 0000000000..25304cd3b4 --- /dev/null +++ b/tests/components/e131/test.esp32.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - e131: + universe: 1 diff --git a/tests/components/e131/test.esp8266.yaml b/tests/components/e131/test.esp8266.yaml new file mode 100644 index 0000000000..54245014a5 --- /dev/null +++ b/tests/components/e131/test.esp8266.yaml @@ -0,0 +1,17 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: neopixelbus + name: Neopixelbus Light + pin: 1 + type: GRBW + variant: SK6812 + method: ESP8266_UART0 + num_leds: 256 + effects: + - e131: + universe: 1 diff --git a/tests/components/e131/test.rp2040.yaml b/tests/components/e131/test.rp2040.yaml new file mode 100644 index 0000000000..0ae31f5403 --- /dev/null +++ b/tests/components/e131/test.rp2040.yaml @@ -0,0 +1,17 @@ +wifi: + ssid: MySSID + password: password1 + +e131: + +light: + - platform: rp2040_pio_led_strip + id: led_strip + pin: 2 + pio: 0 + num_leds: 256 + rgb_order: GRB + chipset: WS2812 + effects: + - e131: + universe: 1 diff --git a/tests/components/ee895/test.esp32-c3-idf.yaml b/tests/components/ee895/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4a36117fab --- /dev/null +++ b/tests/components/ee895/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 5 + sda: 4 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ee895/test.esp32-c3.yaml b/tests/components/ee895/test.esp32-c3.yaml new file mode 100644 index 0000000000..4a36117fab --- /dev/null +++ b/tests/components/ee895/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 5 + sda: 4 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ee895/test.esp32-idf.yaml b/tests/components/ee895/test.esp32-idf.yaml new file mode 100644 index 0000000000..241bdb9574 --- /dev/null +++ b/tests/components/ee895/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 16 + sda: 17 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ee895/test.esp32.yaml b/tests/components/ee895/test.esp32.yaml new file mode 100644 index 0000000000..241bdb9574 --- /dev/null +++ b/tests/components/ee895/test.esp32.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 16 + sda: 17 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ee895/test.esp8266.yaml b/tests/components/ee895/test.esp8266.yaml new file mode 100644 index 0000000000..4a36117fab --- /dev/null +++ b/tests/components/ee895/test.esp8266.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 5 + sda: 4 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ee895/test.rp2040.yaml b/tests/components/ee895/test.rp2040.yaml new file mode 100644 index 0000000000..4a36117fab --- /dev/null +++ b/tests/components/ee895/test.rp2040.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_ee895 + scl: 5 + sda: 4 + +sensor: + - platform: ee895 + address: 0x5F + co2: + name: EE895 CO2 + temperature: + name: EE895 Temperature + pressure: + name: EE895 Pressure diff --git a/tests/components/ektf2232/test.esp32-c3-idf.yaml b/tests/components/ektf2232/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..371f2795a2 --- /dev/null +++ b/tests/components/ektf2232/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 6 + rts_pin: 7 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ektf2232/test.esp32-c3.yaml b/tests/components/ektf2232/test.esp32-c3.yaml new file mode 100644 index 0000000000..371f2795a2 --- /dev/null +++ b/tests/components/ektf2232/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 6 + rts_pin: 7 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ektf2232/test.esp32-idf.yaml b/tests/components/ektf2232/test.esp32-idf.yaml new file mode 100644 index 0000000000..9c6eef8bb3 --- /dev/null +++ b/tests/components/ektf2232/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 14 + rts_pin: 15 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ektf2232/test.esp32.yaml b/tests/components/ektf2232/test.esp32.yaml new file mode 100644 index 0000000000..9c6eef8bb3 --- /dev/null +++ b/tests/components/ektf2232/test.esp32.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 14 + rts_pin: 15 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ektf2232/test.esp8266.yaml b/tests/components/ektf2232/test.esp8266.yaml new file mode 100644 index 0000000000..03f18f7184 --- /dev/null +++ b/tests/components/ektf2232/test.esp8266.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 12 + rts_pin: 13 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ektf2232/test.rp2040.yaml b/tests/components/ektf2232/test.rp2040.yaml new file mode 100644 index 0000000000..371f2795a2 --- /dev/null +++ b/tests/components/ektf2232/test.rp2040.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ektf2232 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ektf2232 + interrupt_pin: 6 + rts_pin: 7 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/emc2101/test.esp32-c3-idf.yaml b/tests/components/emc2101/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d95bc1b001 --- /dev/null +++ b/tests/components/emc2101/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 5 + sda: 4 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/emc2101/test.esp32-c3.yaml b/tests/components/emc2101/test.esp32-c3.yaml new file mode 100644 index 0000000000..d95bc1b001 --- /dev/null +++ b/tests/components/emc2101/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 5 + sda: 4 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/emc2101/test.esp32-idf.yaml b/tests/components/emc2101/test.esp32-idf.yaml new file mode 100644 index 0000000000..34a7d22b71 --- /dev/null +++ b/tests/components/emc2101/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 16 + sda: 17 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/emc2101/test.esp32.yaml b/tests/components/emc2101/test.esp32.yaml new file mode 100644 index 0000000000..34a7d22b71 --- /dev/null +++ b/tests/components/emc2101/test.esp32.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 16 + sda: 17 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/emc2101/test.esp8266.yaml b/tests/components/emc2101/test.esp8266.yaml new file mode 100644 index 0000000000..d95bc1b001 --- /dev/null +++ b/tests/components/emc2101/test.esp8266.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 5 + sda: 4 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/emc2101/test.rp2040.yaml b/tests/components/emc2101/test.rp2040.yaml new file mode 100644 index 0000000000..d95bc1b001 --- /dev/null +++ b/tests/components/emc2101/test.rp2040.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_emc2101 + scl: 5 + sda: 4 + +emc2101: + pwm: + resolution: 8 + +output: + - platform: emc2101 + id: fan_duty_cycle + +sensor: + - platform: emc2101 + internal_temperature: + id: internal_temperature_sensor + name: Internal Temperature Sensor + speed: + id: speed_sensor + name: Speed Sensor + duty_cycle: + id: duty_cycle_sensor + name: Duty Cycle Sensor + update_interval: 5s diff --git a/tests/components/endstop/test.esp32-c3-idf.yaml b/tests/components/endstop/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.esp32-c3-idf.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.esp32-c3.yaml b/tests/components/endstop/test.esp32-c3.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.esp32-c3.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.esp32-idf.yaml b/tests/components/endstop/test.esp32-idf.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.esp32-idf.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.esp32.yaml b/tests/components/endstop/test.esp32.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.esp32.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.esp8266.yaml b/tests/components/endstop/test.esp8266.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.esp8266.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.rp2040.yaml b/tests/components/endstop/test.rp2040.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/test.rp2040.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/ens160/test.esp32-c3-idf.yaml b/tests/components/ens160/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..29f48e812f --- /dev/null +++ b/tests/components/ens160/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 5 + sda: 4 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32-c3.yaml b/tests/components/ens160/test.esp32-c3.yaml new file mode 100644 index 0000000000..29f48e812f --- /dev/null +++ b/tests/components/ens160/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 5 + sda: 4 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32-idf.yaml b/tests/components/ens160/test.esp32-idf.yaml new file mode 100644 index 0000000000..23f7674aef --- /dev/null +++ b/tests/components/ens160/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 16 + sda: 17 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32.yaml b/tests/components/ens160/test.esp32.yaml new file mode 100644 index 0000000000..23f7674aef --- /dev/null +++ b/tests/components/ens160/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 16 + sda: 17 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp8266.yaml b/tests/components/ens160/test.esp8266.yaml new file mode 100644 index 0000000000..29f48e812f --- /dev/null +++ b/tests/components/ens160/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 5 + sda: 4 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.rp2040.yaml b/tests/components/ens160/test.rp2040.yaml new file mode 100644 index 0000000000..29f48e812f --- /dev/null +++ b/tests/components/ens160/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ens160 + scl: 5 + sda: 4 + +sensor: + - platform: ens160 + eco2: + name: ENS160 eCO2 + tvoc: + name: ENS160 Total Volatile Organic Compounds + aqi: + name: ENS160 Air Quality Index diff --git a/tests/components/ens210/test.esp32-c3-idf.yaml b/tests/components/ens210/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..bacb71f9f8 --- /dev/null +++ b/tests/components/ens210/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 5 + sda: 4 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/ens210/test.esp32-c3.yaml b/tests/components/ens210/test.esp32-c3.yaml new file mode 100644 index 0000000000..bacb71f9f8 --- /dev/null +++ b/tests/components/ens210/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 5 + sda: 4 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/ens210/test.esp32-idf.yaml b/tests/components/ens210/test.esp32-idf.yaml new file mode 100644 index 0000000000..8b2d29cc25 --- /dev/null +++ b/tests/components/ens210/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 16 + sda: 17 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/ens210/test.esp32.yaml b/tests/components/ens210/test.esp32.yaml new file mode 100644 index 0000000000..8b2d29cc25 --- /dev/null +++ b/tests/components/ens210/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 16 + sda: 17 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/ens210/test.esp8266.yaml b/tests/components/ens210/test.esp8266.yaml new file mode 100644 index 0000000000..bacb71f9f8 --- /dev/null +++ b/tests/components/ens210/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 5 + sda: 4 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/ens210/test.rp2040.yaml b/tests/components/ens210/test.rp2040.yaml new file mode 100644 index 0000000000..bacb71f9f8 --- /dev/null +++ b/tests/components/ens210/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_ens210 + scl: 5 + sda: 4 + +sensor: + - platform: ens210 + temperature: + name: ENS210 Temperature + humidity: + name: ENS210 Humidity + update_interval: 15s diff --git a/tests/components/esp32_ble/test.esp32-c3-idf.yaml b/tests/components/esp32_ble/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..76b35fc8f8 --- /dev/null +++ b/tests/components/esp32_ble/test.esp32-c3-idf.yaml @@ -0,0 +1,2 @@ +esp32_ble: + io_capability: keyboard_only diff --git a/tests/components/esp32_ble/test.esp32-c3.yaml b/tests/components/esp32_ble/test.esp32-c3.yaml new file mode 100644 index 0000000000..76b35fc8f8 --- /dev/null +++ b/tests/components/esp32_ble/test.esp32-c3.yaml @@ -0,0 +1,2 @@ +esp32_ble: + io_capability: keyboard_only diff --git a/tests/components/esp32_ble/test.esp32-idf.yaml b/tests/components/esp32_ble/test.esp32-idf.yaml new file mode 100644 index 0000000000..76b35fc8f8 --- /dev/null +++ b/tests/components/esp32_ble/test.esp32-idf.yaml @@ -0,0 +1,2 @@ +esp32_ble: + io_capability: keyboard_only diff --git a/tests/components/esp32_ble/test.esp32.yaml b/tests/components/esp32_ble/test.esp32.yaml new file mode 100644 index 0000000000..76b35fc8f8 --- /dev/null +++ b/tests/components/esp32_ble/test.esp32.yaml @@ -0,0 +1,2 @@ +esp32_ble: + io_capability: keyboard_only diff --git a/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..aafb0341d7 --- /dev/null +++ b/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_beacon: + type: iBeacon + uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' diff --git a/tests/components/esp32_ble_beacon/test.esp32-c3.yaml b/tests/components/esp32_ble_beacon/test.esp32-c3.yaml new file mode 100644 index 0000000000..aafb0341d7 --- /dev/null +++ b/tests/components/esp32_ble_beacon/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_beacon: + type: iBeacon + uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' diff --git a/tests/components/esp32_ble_beacon/test.esp32-idf.yaml b/tests/components/esp32_ble_beacon/test.esp32-idf.yaml new file mode 100644 index 0000000000..aafb0341d7 --- /dev/null +++ b/tests/components/esp32_ble_beacon/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_beacon: + type: iBeacon + uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' diff --git a/tests/components/esp32_ble_beacon/test.esp32.yaml b/tests/components/esp32_ble_beacon/test.esp32.yaml new file mode 100644 index 0000000000..aafb0341d7 --- /dev/null +++ b/tests/components/esp32_ble_beacon/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_beacon: + type: iBeacon + uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' diff --git a/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..33b7205bf2 --- /dev/null +++ b/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: blec diff --git a/tests/components/esp32_ble_client/test.esp32-c3.yaml b/tests/components/esp32_ble_client/test.esp32-c3.yaml new file mode 100644 index 0000000000..33b7205bf2 --- /dev/null +++ b/tests/components/esp32_ble_client/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: blec diff --git a/tests/components/esp32_ble_client/test.esp32-idf.yaml b/tests/components/esp32_ble_client/test.esp32-idf.yaml new file mode 100644 index 0000000000..33b7205bf2 --- /dev/null +++ b/tests/components/esp32_ble_client/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: blec diff --git a/tests/components/esp32_ble_client/test.esp32.yaml b/tests/components/esp32_ble_client/test.esp32.yaml new file mode 100644 index 0000000000..33b7205bf2 --- /dev/null +++ b/tests/components/esp32_ble_client/test.esp32.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: blec diff --git a/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..29a5407f84 --- /dev/null +++ b/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] diff --git a/tests/components/esp32_ble_server/test.esp32-c3.yaml b/tests/components/esp32_ble_server/test.esp32-c3.yaml new file mode 100644 index 0000000000..29a5407f84 --- /dev/null +++ b/tests/components/esp32_ble_server/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] diff --git a/tests/components/esp32_ble_server/test.esp32-idf.yaml b/tests/components/esp32_ble_server/test.esp32-idf.yaml new file mode 100644 index 0000000000..29a5407f84 --- /dev/null +++ b/tests/components/esp32_ble_server/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] diff --git a/tests/components/esp32_ble_server/test.esp32.yaml b/tests/components/esp32_ble_server/test.esp32.yaml new file mode 100644 index 0000000000..29a5407f84 --- /dev/null +++ b/tests/components/esp32_ble_server/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] diff --git a/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ef23635c9e --- /dev/null +++ b/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml @@ -0,0 +1,41 @@ +esphome: + on_boot: + then: + - esp32_ble_tracker.start_scan + - esp32_ble_tracker.stop_scan + +esp32_ble_tracker: + on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length + - mac_address: AC:37:43:77:5F:4C + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + - then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + on_ble_service_data_advertise: + - service_uuid: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of service data is %i", x.size()); + on_ble_manufacturer_data_advertise: + - manufacturer_id: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); + on_scan_end: + - then: + - lambda: |- + ESP_LOGD("ble_auto", "The scan has ended!"); diff --git a/tests/components/esp32_ble_tracker/test.esp32-c3.yaml b/tests/components/esp32_ble_tracker/test.esp32-c3.yaml new file mode 100644 index 0000000000..ef23635c9e --- /dev/null +++ b/tests/components/esp32_ble_tracker/test.esp32-c3.yaml @@ -0,0 +1,41 @@ +esphome: + on_boot: + then: + - esp32_ble_tracker.start_scan + - esp32_ble_tracker.stop_scan + +esp32_ble_tracker: + on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length + - mac_address: AC:37:43:77:5F:4C + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + - then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + on_ble_service_data_advertise: + - service_uuid: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of service data is %i", x.size()); + on_ble_manufacturer_data_advertise: + - manufacturer_id: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); + on_scan_end: + - then: + - lambda: |- + ESP_LOGD("ble_auto", "The scan has ended!"); diff --git a/tests/components/esp32_ble_tracker/test.esp32-idf.yaml b/tests/components/esp32_ble_tracker/test.esp32-idf.yaml new file mode 100644 index 0000000000..ef23635c9e --- /dev/null +++ b/tests/components/esp32_ble_tracker/test.esp32-idf.yaml @@ -0,0 +1,41 @@ +esphome: + on_boot: + then: + - esp32_ble_tracker.start_scan + - esp32_ble_tracker.stop_scan + +esp32_ble_tracker: + on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length + - mac_address: AC:37:43:77:5F:4C + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + - then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + on_ble_service_data_advertise: + - service_uuid: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of service data is %i", x.size()); + on_ble_manufacturer_data_advertise: + - manufacturer_id: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); + on_scan_end: + - then: + - lambda: |- + ESP_LOGD("ble_auto", "The scan has ended!"); diff --git a/tests/components/esp32_ble_tracker/test.esp32.yaml b/tests/components/esp32_ble_tracker/test.esp32.yaml new file mode 100644 index 0000000000..ef23635c9e --- /dev/null +++ b/tests/components/esp32_ble_tracker/test.esp32.yaml @@ -0,0 +1,41 @@ +esphome: + on_boot: + then: + - esp32_ble_tracker.start_scan + - esp32_ble_tracker.stop_scan + +esp32_ble_tracker: + on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length + - mac_address: AC:37:43:77:5F:4C + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + - then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + on_ble_service_data_advertise: + - service_uuid: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of service data is %i", x.size()); + on_ble_manufacturer_data_advertise: + - manufacturer_id: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); + on_scan_end: + - then: + - lambda: |- + ESP_LOGD("ble_auto", "The scan has ended!"); diff --git a/tests/components/esp32_camera/test.esp32-idf.yaml b/tests/components/esp32_camera/test.esp32-idf.yaml new file mode 100644 index 0000000000..366f601657 --- /dev/null +++ b/tests/components/esp32_camera/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); diff --git a/tests/components/esp32_camera/test.esp32.yaml b/tests/components/esp32_camera/test.esp32.yaml new file mode 100644 index 0000000000..366f601657 --- /dev/null +++ b/tests/components/esp32_camera/test.esp32.yaml @@ -0,0 +1,28 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); diff --git a/tests/components/esp32_camera_web_server/test.esp32-idf.yaml b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml new file mode 100644 index 0000000000..14b7bd5c34 --- /dev/null +++ b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml @@ -0,0 +1,34 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + +esp32_camera_web_server: + - port: 8080 + mode: stream + - port: 8081 + mode: snapshot diff --git a/tests/components/esp32_camera_web_server/test.esp32.yaml b/tests/components/esp32_camera_web_server/test.esp32.yaml new file mode 100644 index 0000000000..14b7bd5c34 --- /dev/null +++ b/tests/components/esp32_camera_web_server/test.esp32.yaml @@ -0,0 +1,34 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + +esp32_camera_web_server: + - port: 8080 + mode: stream + - port: 8081 + mode: snapshot diff --git a/tests/components/esp32_can/test.esp32-c3-idf.yaml b/tests/components/esp32_can/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b4fd34cf51 --- /dev/null +++ b/tests/components/esp32_can/test.esp32-c3-idf.yaml @@ -0,0 +1,45 @@ +esphome: + on_boot: + then: + - canbus.send: + # Extended ID explicit + use_extended_id: true + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + - canbus.send: + # Standard ID by default + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: 4 + tx_pin: 5 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("canid 500", "%s", b.c_str() ); + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/esp32_can/test.esp32-c3.yaml b/tests/components/esp32_can/test.esp32-c3.yaml new file mode 100644 index 0000000000..b4fd34cf51 --- /dev/null +++ b/tests/components/esp32_can/test.esp32-c3.yaml @@ -0,0 +1,45 @@ +esphome: + on_boot: + then: + - canbus.send: + # Extended ID explicit + use_extended_id: true + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + - canbus.send: + # Standard ID by default + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: 4 + tx_pin: 5 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("canid 500", "%s", b.c_str() ); + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/esp32_can/test.esp32-idf.yaml b/tests/components/esp32_can/test.esp32-idf.yaml new file mode 100644 index 0000000000..159a695853 --- /dev/null +++ b/tests/components/esp32_can/test.esp32-idf.yaml @@ -0,0 +1,45 @@ +esphome: + on_boot: + then: + - canbus.send: + # Extended ID explicit + use_extended_id: true + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + - canbus.send: + # Standard ID by default + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: 13 + tx_pin: 14 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("canid 500", "%s", b.c_str() ); + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/esp32_can/test.esp32.yaml b/tests/components/esp32_can/test.esp32.yaml new file mode 100644 index 0000000000..159a695853 --- /dev/null +++ b/tests/components/esp32_can/test.esp32.yaml @@ -0,0 +1,45 @@ +esphome: + on_boot: + then: + - canbus.send: + # Extended ID explicit + use_extended_id: true + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + - canbus.send: + # Standard ID by default + can_id: 0x100 + data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] + +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: 13 + tx_pin: 14 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("canid 500", "%s", b.c_str() ); + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/esp32_dac/test.esp32-idf.yaml b/tests/components/esp32_dac/test.esp32-idf.yaml new file mode 100644 index 0000000000..225627f5af --- /dev/null +++ b/tests/components/esp32_dac/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +output: + - platform: esp32_dac + id: dac_output + pin: 25 diff --git a/tests/components/esp32_dac/test.esp32.yaml b/tests/components/esp32_dac/test.esp32.yaml new file mode 100644 index 0000000000..225627f5af --- /dev/null +++ b/tests/components/esp32_dac/test.esp32.yaml @@ -0,0 +1,4 @@ +output: + - platform: esp32_dac + id: dac_output + pin: 25 diff --git a/tests/components/esp32_hall/test.esp32-idf.yaml b/tests/components/esp32_hall/test.esp32-idf.yaml new file mode 100644 index 0000000000..f8429f5aa0 --- /dev/null +++ b/tests/components/esp32_hall/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: esp32_hall + name: ESP32 Hall Sensor diff --git a/tests/components/esp32_hall/test.esp32.yaml b/tests/components/esp32_hall/test.esp32.yaml new file mode 100644 index 0000000000..f8429f5aa0 --- /dev/null +++ b/tests/components/esp32_hall/test.esp32.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: esp32_hall + name: ESP32 Hall Sensor diff --git a/tests/components/esp32_improv/test.esp32-c3-idf.yaml b/tests/components/esp32_improv/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7eb3f9c0be --- /dev/null +++ b/tests/components/esp32_improv/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +binary_sensor: + - platform: gpio + pin: 0 + id: io0_button + +output: + - platform: gpio + pin: 2 + id: built_in_led + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led diff --git a/tests/components/esp32_improv/test.esp32-c3.yaml b/tests/components/esp32_improv/test.esp32-c3.yaml new file mode 100644 index 0000000000..7eb3f9c0be --- /dev/null +++ b/tests/components/esp32_improv/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +binary_sensor: + - platform: gpio + pin: 0 + id: io0_button + +output: + - platform: gpio + pin: 2 + id: built_in_led + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led diff --git a/tests/components/esp32_improv/test.esp32-idf.yaml b/tests/components/esp32_improv/test.esp32-idf.yaml new file mode 100644 index 0000000000..7eb3f9c0be --- /dev/null +++ b/tests/components/esp32_improv/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +binary_sensor: + - platform: gpio + pin: 0 + id: io0_button + +output: + - platform: gpio + pin: 2 + id: built_in_led + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led diff --git a/tests/components/esp32_improv/test.esp32.yaml b/tests/components/esp32_improv/test.esp32.yaml new file mode 100644 index 0000000000..7eb3f9c0be --- /dev/null +++ b/tests/components/esp32_improv/test.esp32.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +binary_sensor: + - platform: gpio + pin: 0 + id: io0_button + +output: + - platform: gpio + pin: 2 + id: built_in_led + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b226d1de06 --- /dev/null +++ b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +light: + - platform: esp32_rmt_led_strip + id: led_strip + pin: 4 + num_leds: 60 + rmt_channel: 0 + rgb_order: GRB + chipset: ws2812 + - platform: esp32_rmt_led_strip + id: led_strip2 + pin: 5 + num_leds: 60 + rmt_channel: 1 + rgb_order: RGB + bit0_high: 100us + bit0_low: 100us + bit1_high: 100us + bit1_low: 100us diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml new file mode 100644 index 0000000000..b226d1de06 --- /dev/null +++ b/tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +light: + - platform: esp32_rmt_led_strip + id: led_strip + pin: 4 + num_leds: 60 + rmt_channel: 0 + rgb_order: GRB + chipset: ws2812 + - platform: esp32_rmt_led_strip + id: led_strip2 + pin: 5 + num_leds: 60 + rmt_channel: 1 + rgb_order: RGB + bit0_high: 100us + bit0_low: 100us + bit1_high: 100us + bit1_low: 100us diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml new file mode 100644 index 0000000000..d51a66451f --- /dev/null +++ b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +light: + - platform: esp32_rmt_led_strip + id: led_strip + pin: 13 + num_leds: 60 + rmt_channel: 6 + rgb_order: GRB + chipset: ws2812 + - platform: esp32_rmt_led_strip + id: led_strip2 + pin: 14 + num_leds: 60 + rmt_channel: 2 + rgb_order: RGB + bit0_high: 100us + bit0_low: 100us + bit1_high: 100us + bit1_low: 100us diff --git a/tests/components/esp32_rmt_led_strip/test.esp32.yaml b/tests/components/esp32_rmt_led_strip/test.esp32.yaml new file mode 100644 index 0000000000..d51a66451f --- /dev/null +++ b/tests/components/esp32_rmt_led_strip/test.esp32.yaml @@ -0,0 +1,18 @@ +light: + - platform: esp32_rmt_led_strip + id: led_strip + pin: 13 + num_leds: 60 + rmt_channel: 6 + rgb_order: GRB + chipset: ws2812 + - platform: esp32_rmt_led_strip + id: led_strip2 + pin: 14 + num_leds: 60 + rmt_channel: 2 + rgb_order: RGB + bit0_high: 100us + bit0_low: 100us + bit1_high: 100us + bit1_low: 100us diff --git a/tests/components/esp32_touch/test.esp32-idf.yaml b/tests/components/esp32_touch/test.esp32-idf.yaml new file mode 100644 index 0000000000..691cce8d86 --- /dev/null +++ b/tests/components/esp32_touch/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +esp32_touch: + setup_mode: false + iir_filter: 10ms + sleep_duration: 27ms + measurement_duration: 8ms + low_voltage_reference: 0.5V + high_voltage_reference: 2.7V + voltage_attenuation: 1.5V + +binary_sensor: + - platform: esp32_touch + name: ESP32 Touch Pad + pin: 27 + threshold: 1000 + on_press: + - logger.log: "I'm touched!" diff --git a/tests/components/esp32_touch/test.esp32.yaml b/tests/components/esp32_touch/test.esp32.yaml new file mode 100644 index 0000000000..691cce8d86 --- /dev/null +++ b/tests/components/esp32_touch/test.esp32.yaml @@ -0,0 +1,16 @@ +esp32_touch: + setup_mode: false + iir_filter: 10ms + sleep_duration: 27ms + measurement_duration: 8ms + low_voltage_reference: 0.5V + high_voltage_reference: 2.7V + voltage_attenuation: 1.5V + +binary_sensor: + - platform: esp32_touch + name: ESP32 Touch Pad + pin: 27 + threshold: 1000 + on_press: + - logger.log: "I'm touched!" diff --git a/tests/components/esp8266_pwm/test.esp8266.yaml b/tests/components/esp8266_pwm/test.esp8266.yaml new file mode 100644 index 0000000000..52b290f91b --- /dev/null +++ b/tests/components/esp8266_pwm/test.esp8266.yaml @@ -0,0 +1,8 @@ +output: + - platform: esp8266_pwm + id: out + pin: 4 + frequency: 50Hz + - platform: esp8266_pwm + id: out2 + pin: 5 diff --git a/tests/components/ethernet/test.esp32-idf.yaml b/tests/components/ethernet/test.esp32-idf.yaml new file mode 100644 index 0000000000..b9ed9cb036 --- /dev/null +++ b/tests/components/ethernet/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/test.esp32.yaml b/tests/components/ethernet/test.esp32.yaml new file mode 100644 index 0000000000..b9ed9cb036 --- /dev/null +++ b/tests/components/ethernet/test.esp32.yaml @@ -0,0 +1,12 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet_info/test.esp32-idf.yaml b/tests/components/ethernet_info/test.esp32-idf.yaml new file mode 100644 index 0000000000..c5da2bb666 --- /dev/null +++ b/tests/components/ethernet_info/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local + +text_sensor: + - platform: ethernet_info + ip_address: + name: IP Address diff --git a/tests/components/ethernet_info/test.esp32.yaml b/tests/components/ethernet_info/test.esp32.yaml new file mode 100644 index 0000000000..c5da2bb666 --- /dev/null +++ b/tests/components/ethernet_info/test.esp32.yaml @@ -0,0 +1,17 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local + +text_sensor: + - platform: ethernet_info + ip_address: + name: IP Address diff --git a/tests/components/exposure_notifications/test.esp32-c3-idf.yaml b/tests/components/exposure_notifications/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..faba5bb2d1 --- /dev/null +++ b/tests/components/exposure_notifications/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +exposure_notifications: + on_exposure_notification: + then: + - lambda: | + ESP_LOGD("main", "Got notification:"); + ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); + ESP_LOGD("main", " RSSI: %d", x.rssi); diff --git a/tests/components/exposure_notifications/test.esp32-c3.yaml b/tests/components/exposure_notifications/test.esp32-c3.yaml new file mode 100644 index 0000000000..faba5bb2d1 --- /dev/null +++ b/tests/components/exposure_notifications/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +exposure_notifications: + on_exposure_notification: + then: + - lambda: | + ESP_LOGD("main", "Got notification:"); + ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); + ESP_LOGD("main", " RSSI: %d", x.rssi); diff --git a/tests/components/exposure_notifications/test.esp32-idf.yaml b/tests/components/exposure_notifications/test.esp32-idf.yaml new file mode 100644 index 0000000000..faba5bb2d1 --- /dev/null +++ b/tests/components/exposure_notifications/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +exposure_notifications: + on_exposure_notification: + then: + - lambda: | + ESP_LOGD("main", "Got notification:"); + ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); + ESP_LOGD("main", " RSSI: %d", x.rssi); diff --git a/tests/components/exposure_notifications/test.esp32.yaml b/tests/components/exposure_notifications/test.esp32.yaml new file mode 100644 index 0000000000..faba5bb2d1 --- /dev/null +++ b/tests/components/exposure_notifications/test.esp32.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +exposure_notifications: + on_exposure_notification: + then: + - lambda: | + ESP_LOGD("main", "Got notification:"); + ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); + ESP_LOGD("main", " RSSI: %d", x.rssi); diff --git a/tests/components/external_components/test.esp32-c3-idf.yaml b/tests/components/external_components/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.esp32-c3.yaml b/tests/components/external_components/test.esp32-c3.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.esp32-idf.yaml b/tests/components/external_components/test.esp32-idf.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.esp32.yaml b/tests/components/external_components/test.esp32.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.esp32.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.esp8266.yaml b/tests/components/external_components/test.esp8266.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.esp8266.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.rp2040.yaml b/tests/components/external_components/test.rp2040.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/test.rp2040.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/ezo/test.esp32-c3-idf.yaml b/tests/components/ezo/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..93ceb9efd3 --- /dev/null +++ b/tests/components/ezo/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 5 + sda: 4 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo/test.esp32-c3.yaml b/tests/components/ezo/test.esp32-c3.yaml new file mode 100644 index 0000000000..93ceb9efd3 --- /dev/null +++ b/tests/components/ezo/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 5 + sda: 4 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo/test.esp32-idf.yaml b/tests/components/ezo/test.esp32-idf.yaml new file mode 100644 index 0000000000..61a8d2b25f --- /dev/null +++ b/tests/components/ezo/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 16 + sda: 17 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo/test.esp32.yaml b/tests/components/ezo/test.esp32.yaml new file mode 100644 index 0000000000..61a8d2b25f --- /dev/null +++ b/tests/components/ezo/test.esp32.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 16 + sda: 17 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo/test.esp8266.yaml b/tests/components/ezo/test.esp8266.yaml new file mode 100644 index 0000000000..93ceb9efd3 --- /dev/null +++ b/tests/components/ezo/test.esp8266.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 5 + sda: 4 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo/test.rp2040.yaml b/tests/components/ezo/test.rp2040.yaml new file mode 100644 index 0000000000..93ceb9efd3 --- /dev/null +++ b/tests/components/ezo/test.rp2040.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_ezo + scl: 5 + sda: 4 + +sensor: + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH diff --git a/tests/components/ezo_pmp/test.esp32-c3-idf.yaml b/tests/components/ezo_pmp/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fa047de3de --- /dev/null +++ b/tests/components/ezo_pmp/test.esp32-c3-idf.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 5 + sda: 4 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? diff --git a/tests/components/ezo_pmp/test.esp32-c3.yaml b/tests/components/ezo_pmp/test.esp32-c3.yaml new file mode 100644 index 0000000000..fa047de3de --- /dev/null +++ b/tests/components/ezo_pmp/test.esp32-c3.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 5 + sda: 4 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? diff --git a/tests/components/ezo_pmp/test.esp32-idf.yaml b/tests/components/ezo_pmp/test.esp32-idf.yaml new file mode 100644 index 0000000000..9fc929b365 --- /dev/null +++ b/tests/components/ezo_pmp/test.esp32-idf.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 16 + sda: 17 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? diff --git a/tests/components/ezo_pmp/test.esp32.yaml b/tests/components/ezo_pmp/test.esp32.yaml new file mode 100644 index 0000000000..9fc929b365 --- /dev/null +++ b/tests/components/ezo_pmp/test.esp32.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 16 + sda: 17 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? diff --git a/tests/components/ezo_pmp/test.esp8266.yaml b/tests/components/ezo_pmp/test.esp8266.yaml new file mode 100644 index 0000000000..fa047de3de --- /dev/null +++ b/tests/components/ezo_pmp/test.esp8266.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 5 + sda: 4 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? diff --git a/tests/components/ezo_pmp/test.rp2040.yaml b/tests/components/ezo_pmp/test.rp2040.yaml new file mode 100644 index 0000000000..fa047de3de --- /dev/null +++ b/tests/components/ezo_pmp/test.rp2040.yaml @@ -0,0 +1,61 @@ +i2c: + - id: i2c_ezo_pmp + scl: 5 + sda: 4 + +ezo_pmp: + id: hcl_pump + update_interval: 1s + +binary_sensor: + - platform: ezo_pmp + pump_state: + name: Pump State + is_paused: + name: Is Paused + +sensor: + - platform: ezo_pmp + current_volume_dosed: + name: Current Volume Dosed + total_volume_dosed: + name: Total Volume Dosed + absolute_total_volume_dosed: + name: Absolute Total Volume Dosed + pump_voltage: + name: Pump Voltage + last_volume_requested: + name: Last Volume Requested + max_flow_rate: + name: Max Flow Rate + +text_sensor: + - platform: ezo_pmp + dosing_mode: + name: Dosing Mode + calibration_status: + name: Calibration Status + on_value: + - ezo_pmp.dose_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.dose_volume_over_time: + id: hcl_pump + volume: 10 + duration: 2 + - ezo_pmp.dose_with_constant_flow_rate: + id: hcl_pump + volume_per_minute: 10 + duration: 2 + - ezo_pmp.set_calibration_volume: + id: hcl_pump + volume: 10 + - ezo_pmp.find: hcl_pump + - ezo_pmp.dose_continuously: hcl_pump + - ezo_pmp.clear_total_volume_dosed: hcl_pump + - ezo_pmp.clear_calibration: hcl_pump + - ezo_pmp.pause_dosing: hcl_pump + - ezo_pmp.stop_dosing: hcl_pump + - ezo_pmp.arbitrary_command: + id: hcl_pump + command: D,? From 9b7438a56d0ebace3979c9d55e79093e3dd94469 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:39:01 +1300 Subject: [PATCH 1416/2607] Require xsrf/csrf when using a password (#6396) --- esphome/dashboard/web_server.py | 6 ++++++ requirements.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 3de1d69115..9ee2312781 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -688,6 +688,11 @@ class MainRequestHandler(BaseHandler): @authenticated def get(self) -> None: begin = bool(self.get_argument("begin", False)) + if settings.using_password: + # Simply accessing the xsrf_token sets the cookie for us + self.xsrf_token # pylint: disable=pointless-statement + else: + self.clear_cookie("_xsrf") self.render( "index.template.html", @@ -1102,6 +1107,7 @@ def make_app(debug=get_bool_env(ENV_DEV)) -> tornado.web.Application: "log_function": log_function, "websocket_ping_interval": 30.0, "template_path": get_base_frontend_path(), + "xsrf_cookies": settings.using_password, } rel = settings.relative_url return tornado.web.Application( diff --git a/requirements.txt b/requirements.txt index 9b5e06fc59..4b7e501e97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20231107.0 +esphome-dashboard==20240319.0 aioesphomeapi==23.1.1 zeroconf==0.131.0 python-magic==0.4.27 From b3aa950c60714a4e49028946656588611761def7 Mon Sep 17 00:00:00 2001 From: swoboda1337 <154711427+swoboda1337@users.noreply.github.com> Date: Mon, 18 Mar 2024 02:35:06 -0400 Subject: [PATCH 1417/2607] Fix bug in `remote_base` conditional (#6281) Co-authored-by: Jonathan Swoboda --- esphome/components/remote_base/remote_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index 095f95053f..f3e86aaab6 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -16,7 +16,7 @@ RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_b } void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { - if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) >= RMT_CHANNEL_MAX) { + if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) { this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_); ESP_LOGW(TAG, "Not enough RMT memory blocks available, reduced to %i blocks.", this->mem_block_num_); } From 9442f7a2713d6ed324fbdf4ef6da70a3ca563fb6 Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Mon, 18 Mar 2024 19:04:53 +0100 Subject: [PATCH 1418/2607] Fix sending packets to uponor_smatrix devices (#6392) --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index df81691fb1..a7014dc96c 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -173,7 +173,9 @@ bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixDa return false; // Assemble packet for send queue. All fields are big-endian except for the little-endian checksum. - std::vector packet(6 + 3 * data_len); + std::vector packet; + packet.reserve(6 + 3 * data_len); + packet.push_back(this->address_ >> 8); packet.push_back(this->address_ >> 0); packet.push_back(device_address >> 8); From db1b187e80029ab9aad61fe347d24fe3fcd24dfe Mon Sep 17 00:00:00 2001 From: Stefan Rado <628587+kroimon@users.noreply.github.com> Date: Mon, 18 Mar 2024 19:06:17 +0100 Subject: [PATCH 1419/2607] Fix wrong initialization of vectors in ade7953_i2c (#6393) --- .../components/ade7953_i2c/ade7953_i2c.cpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/esphome/components/ade7953_i2c/ade7953_i2c.cpp b/esphome/components/ade7953_i2c/ade7953_i2c.cpp index 572337428a..ae381824db 100644 --- a/esphome/components/ade7953_i2c/ade7953_i2c.cpp +++ b/esphome/components/ade7953_i2c/ade7953_i2c.cpp @@ -13,29 +13,29 @@ void AdE7953I2c::dump_config() { ade7953_base::ADE7953::dump_config(); } bool AdE7953I2c::ade_write_8(uint16_t reg, uint8_t value) { - std::vector data(3); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[3]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value; + return this->write(data, 3) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_16(uint16_t reg, uint16_t value) { - std::vector data(4); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value >> 8); - data.push_back(value >> 0); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[4]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value >> 8; + data[3] = value >> 0; + return this->write(data, 4) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_32(uint16_t reg, uint32_t value) { - std::vector data(6); - data.push_back(reg >> 8); - data.push_back(reg >> 0); - data.push_back(value >> 24); - data.push_back(value >> 16); - data.push_back(value >> 8); - data.push_back(value >> 0); - return this->write(data.data(), data.size()) != i2c::ERROR_OK; + uint8_t data[6]; + data[0] = reg >> 8; + data[1] = reg >> 0; + data[2] = value >> 24; + data[3] = value >> 16; + data[4] = value >> 8; + data[5] = value >> 0; + return this->write(data, 6) != i2c::ERROR_OK; } bool AdE7953I2c::ade_read_8(uint16_t reg, uint8_t *value) { uint8_t reg_data[2]; From a3bd8ad02526a831bc0ab52e76ddfcec78f39440 Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Mon, 18 Mar 2024 13:26:39 -0500 Subject: [PATCH 1420/2607] ld2420: Firmware v1.5.4+ bug workaround (#6168) --- esphome/components/ld2420/ld2420.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index bda1764cfc..bf1412ee9f 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -211,10 +211,11 @@ void LD2420Component::factory_reset_action() { void LD2420Component::restart_module_action() { ESP_LOGCONFIG(TAG, "Restarting LD2420 module..."); this->send_module_restart(); - delay_microseconds_safe(45000); - this->set_config_mode(true); - this->set_system_mode(system_mode_); - this->set_config_mode(false); + this->set_timeout(250, [this]() { + this->set_config_mode(true); + this->set_system_mode(system_mode_); + this->set_config_mode(false); + }); ESP_LOGCONFIG(TAG, "LD2420 Restarted."); } @@ -527,18 +528,16 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) { this->write_byte(cmd_buffer[index]); } - delay_microseconds_safe(500); // give the module a moment to process it error = 0; if (frame.command == CMD_RESTART) { - delay_microseconds_safe(25000); // Wait for the restart - return 0; // restart does not reply exit now + return 0; // restart does not reply exit now } while (!this->cmd_reply_.ack) { while (available()) { this->readline_(read(), ack_buffer, sizeof(ack_buffer)); } - delay_microseconds_safe(250); + delay_microseconds_safe(1450); if (loop_count <= 0) { error = LD2420_ERROR_TIMEOUT; retry--; From c56c40cb824e34ed2b89ba1cb8a3a5eb31459c74 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:39:01 +1300 Subject: [PATCH 1421/2607] Require xsrf/csrf when using a password (#6396) --- esphome/dashboard/web_server.py | 6 ++++++ requirements.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 3de1d69115..9ee2312781 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -688,6 +688,11 @@ class MainRequestHandler(BaseHandler): @authenticated def get(self) -> None: begin = bool(self.get_argument("begin", False)) + if settings.using_password: + # Simply accessing the xsrf_token sets the cookie for us + self.xsrf_token # pylint: disable=pointless-statement + else: + self.clear_cookie("_xsrf") self.render( "index.template.html", @@ -1102,6 +1107,7 @@ def make_app(debug=get_bool_env(ENV_DEV)) -> tornado.web.Application: "log_function": log_function, "websocket_ping_interval": 30.0, "template_path": get_base_frontend_path(), + "xsrf_cookies": settings.using_password, } rel = settings.relative_url return tornado.web.Application( diff --git a/requirements.txt b/requirements.txt index 9b5e06fc59..4b7e501e97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20231107.0 +esphome-dashboard==20240319.0 aioesphomeapi==23.1.1 zeroconf==0.131.0 python-magic==0.4.27 From 855b1fd7062e1fabfe60c57bad08749aa7c1f390 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:22:28 +1300 Subject: [PATCH 1422/2607] Bump version to 2024.3.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 60ea6f0423..2b5724c9f3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0b3" +__version__ = "2024.3.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 19022ace12595295fadcc3fbb36c69a8d5c846f4 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 19 Mar 2024 03:56:36 +0100 Subject: [PATCH 1423/2607] Make SPI compile with IDF >= 5.0 (#6383) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/spi_device/spi_device.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/spi_device/spi_device.cpp b/esphome/components/spi_device/spi_device.cpp index 4e0b72ae60..1f579cb802 100644 --- a/esphome/components/spi_device/spi_device.cpp +++ b/esphome/components/spi_device/spi_device.cpp @@ -1,6 +1,7 @@ #include "spi_device.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include namespace esphome { namespace spi_device { @@ -18,9 +19,9 @@ void SPIDeviceComponent::dump_config() { LOG_PIN(" CS pin: ", this->cs_); ESP_LOGCONFIG(TAG, " Mode: %d", this->mode_); if (this->data_rate_ < 1000000) { - ESP_LOGCONFIG(TAG, " Data rate: %dkHz", this->data_rate_ / 1000); + ESP_LOGCONFIG(TAG, " Data rate: %" PRId32 "kHz", this->data_rate_ / 1000); } else { - ESP_LOGCONFIG(TAG, " Data rate: %dMHz", this->data_rate_ / 1000000); + ESP_LOGCONFIG(TAG, " Data rate: %" PRId32 "MHz", this->data_rate_ / 1000000); } } From af3fb615ead27b90c8c98fdbaf33e80e6eaf87f4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 19 Mar 2024 00:18:03 -0500 Subject: [PATCH 1424/2607] Fix esp32-camera test yaml (#6398) * Fix esp32-camera test yaml * Fix esp32-camera test yaml, take 2 --- .../components/esp32_camera/test.esp32-idf.yaml | 16 ++++++++-------- tests/components/esp32_camera/test.esp32.yaml | 16 ++++++++-------- .../esp32_camera_web_server/test.esp32-idf.yaml | 16 ++++++++-------- .../esp32_camera_web_server/test.esp32.yaml | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/components/esp32_camera/test.esp32-idf.yaml b/tests/components/esp32_camera/test.esp32-idf.yaml index 366f601657..2f5f792f1c 100644 --- a/tests/components/esp32_camera/test.esp32-idf.yaml +++ b/tests/components/esp32_camera/test.esp32-idf.yaml @@ -3,12 +3,12 @@ esp32_camera: data_pins: - number: 17 - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 vsync_pin: 22 href_pin: 26 pixel_clock_pin: 21 @@ -24,5 +24,5 @@ esp32_camera: jpeg_quality: 10 on_image: then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); diff --git a/tests/components/esp32_camera/test.esp32.yaml b/tests/components/esp32_camera/test.esp32.yaml index 366f601657..2f5f792f1c 100644 --- a/tests/components/esp32_camera/test.esp32.yaml +++ b/tests/components/esp32_camera/test.esp32.yaml @@ -3,12 +3,12 @@ esp32_camera: data_pins: - number: 17 - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 vsync_pin: 22 href_pin: 26 pixel_clock_pin: 21 @@ -24,5 +24,5 @@ esp32_camera: jpeg_quality: 10 on_image: then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); diff --git a/tests/components/esp32_camera_web_server/test.esp32-idf.yaml b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml index 14b7bd5c34..5edefdf0a8 100644 --- a/tests/components/esp32_camera_web_server/test.esp32-idf.yaml +++ b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml @@ -3,12 +3,12 @@ esp32_camera: data_pins: - number: 17 - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 vsync_pin: 22 href_pin: 26 pixel_clock_pin: 21 @@ -24,8 +24,8 @@ esp32_camera: jpeg_quality: 10 on_image: then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); esp32_camera_web_server: - port: 8080 diff --git a/tests/components/esp32_camera_web_server/test.esp32.yaml b/tests/components/esp32_camera_web_server/test.esp32.yaml index 14b7bd5c34..5edefdf0a8 100644 --- a/tests/components/esp32_camera_web_server/test.esp32.yaml +++ b/tests/components/esp32_camera_web_server/test.esp32.yaml @@ -3,12 +3,12 @@ esp32_camera: data_pins: - number: 17 - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 vsync_pin: 22 href_pin: 26 pixel_clock_pin: 21 @@ -24,8 +24,8 @@ esp32_camera: jpeg_quality: 10 on_image: then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); esp32_camera_web_server: - port: 8080 From f0936dd22dd2c6ce62f75f3afe42964d578340c6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:53:01 +1100 Subject: [PATCH 1425/2607] AHT10: Use state machine to avoid blocking delay (#6401) --- esphome/components/aht10/aht10.cpp | 107 +++++++++++++++-------------- esphome/components/aht10/aht10.h | 5 ++ 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index 57102e6d27..d5af06c2a2 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -36,6 +36,7 @@ static const uint8_t AHT10_INIT_ATTEMPTS = 10; static const uint8_t AHT10_STATUS_BUSY = 0x80; void AHT10Component::setup() { + this->read_delay_ = this->humidity_sensor_ != nullptr ? AHT10_HUMIDITY_DELAY : AHT10_DEFAULT_DELAY; if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Reset AHT10 failed!"); } @@ -83,74 +84,78 @@ void AHT10Component::setup() { ESP_LOGV(TAG, "AHT10 initialization"); } -void AHT10Component::update() { - if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); - return; - } - uint8_t data[6]; - uint8_t delay_ms = AHT10_DEFAULT_DELAY; - if (this->humidity_sensor_ != nullptr) - delay_ms = AHT10_HUMIDITY_DELAY; - bool success = false; - for (int i = 0; i < AHT10_ATTEMPTS; ++i) { - ESP_LOGVV(TAG, "Attempt %d at %6" PRIu32, i, millis()); - delay(delay_ms); - if (this->read(data, 6) != i2c::ERROR_OK) { - ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); - continue; - } - - if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy - ESP_LOGD(TAG, "AHT10 is busy, waiting..."); - } else if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { - // Unrealistic humidity (0x0) - if (this->humidity_sensor_ == nullptr) { - ESP_LOGVV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); - break; - } else { - ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); - if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); - return; - } - } - } else { - // data is valid, we can break the loop - ESP_LOGVV(TAG, "Answer at %6" PRIu32, millis()); - success = true; - break; - } - } - if (!success || (data[0] & 0x80) == 0x80) { +void AHT10Component::restart_read_() { + if (this->read_count_ == AHT10_ATTEMPTS) { + this->read_count_ = 0; ESP_LOGE(TAG, "Measurements reading timed-out!"); - this->status_set_warning(); + this->status_set_error(); + return; + } + this->read_count_++; + this->set_timeout(this->read_delay_, [this]() { this->read_data_(); }); +} + +void AHT10Component::read_data_() { + uint8_t data[6]; + ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); + if (this->read(data, 6) != i2c::ERROR_OK) { + ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); + this->restart_read_(); return; } + if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy + ESP_LOGD(TAG, "AHT10 is busy, waiting..."); + this->restart_read_(); + return; + } + if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { + // Unrealistic humidity (0x0) + if (this->humidity_sensor_ == nullptr) { + ESP_LOGV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); + } else { + ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); + if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Communication with AHT10 failed!"); + this->status_set_warning(); + } + this->restart_read_(); + return; + } + } + ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; - float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; - float humidity; - if (raw_humidity == 0) { // unrealistic value - humidity = NAN; - } else { - humidity = (float) raw_humidity * 100.0f / 1048576.0f; - } - if (this->temperature_sensor_ != nullptr) { + float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; this->temperature_sensor_->publish_state(temperature); } if (this->humidity_sensor_ != nullptr) { + float humidity; + if (raw_humidity == 0) { // unrealistic value + humidity = NAN; + } else { + humidity = (float) raw_humidity * 100.0f / 1048576.0f; + } if (std::isnan(humidity)) { ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum"); } this->humidity_sensor_->publish_state(humidity); } this->status_clear_warning(); + this->read_count_ = 0; +} +void AHT10Component::update() { + if (this->read_count_ != 0) + return; + this->start_time_ = millis(); + if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Communication with AHT10 failed!"); + this->status_set_warning(); + return; + } + this->restart_read_(); } float AHT10Component::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/aht10/aht10.h b/esphome/components/aht10/aht10.h index 3840609d56..76f051878e 100644 --- a/esphome/components/aht10/aht10.h +++ b/esphome/components/aht10/aht10.h @@ -26,6 +26,11 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; AHT10Variant variant_{}; + unsigned read_count_{}; + unsigned read_delay_{}; + void read_data_(); + void restart_read_(); + uint32_t start_time_{}; }; } // namespace aht10 From 774cbde1b6c6d121a8b2a92a2aa53f79a77f320f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:56:43 +1100 Subject: [PATCH 1426/2607] Show component warnings and errors in the log; (#6400) --- esphome/core/component.cpp | 29 +++++++++++++++++++++++------ esphome/core/component.h | 8 ++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index d737ec0ae3..b9a7697015 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -141,18 +141,35 @@ bool Component::is_ready() { (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP; } bool Component::can_proceed() { return true; } -bool Component::status_has_warning() { return this->component_state_ & STATUS_LED_WARNING; } -bool Component::status_has_error() { return this->component_state_ & STATUS_LED_ERROR; } -void Component::status_set_warning() { +bool Component::status_has_warning() const { return this->component_state_ & STATUS_LED_WARNING; } +bool Component::status_has_error() const { return this->component_state_ & STATUS_LED_ERROR; } +void Component::status_set_warning(const char *message) { + // Don't spam the log. This risks missing different warning messages though. + if ((this->component_state_ & STATUS_LED_WARNING) != 0) + return; this->component_state_ |= STATUS_LED_WARNING; App.app_state_ |= STATUS_LED_WARNING; + ESP_LOGW(this->get_component_source(), "Warning set: %s", message); } -void Component::status_set_error() { +void Component::status_set_error(const char *message) { + if ((this->component_state_ & STATUS_LED_ERROR) != 0) + return; this->component_state_ |= STATUS_LED_ERROR; App.app_state_ |= STATUS_LED_ERROR; + ESP_LOGE(this->get_component_source(), "Error set: %s", message); +} +void Component::status_clear_warning() { + if ((this->component_state_ & STATUS_LED_WARNING) == 0) + return; + this->component_state_ &= ~STATUS_LED_WARNING; + ESP_LOGW(this->get_component_source(), "Warning cleared"); +} +void Component::status_clear_error() { + if ((this->component_state_ & STATUS_LED_ERROR) == 0) + return; + this->component_state_ &= ~STATUS_LED_ERROR; + ESP_LOGE(this->get_component_source(), "Error cleared"); } -void Component::status_clear_warning() { this->component_state_ &= ~STATUS_LED_WARNING; } -void Component::status_clear_error() { this->component_state_ &= ~STATUS_LED_ERROR; } void Component::status_momentary_warning(const std::string &name, uint32_t length) { this->status_set_warning(); this->set_timeout(name, length, [this]() { this->status_clear_warning(); }); diff --git a/esphome/core/component.h b/esphome/core/component.h index deefedf3d8..4f244e5fcb 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -124,13 +124,13 @@ class Component { virtual bool can_proceed(); - bool status_has_warning(); + bool status_has_warning() const; - bool status_has_error(); + bool status_has_error() const; - void status_set_warning(); + void status_set_warning(const char *message = "unspecified"); - void status_set_error(); + void status_set_error(const char *message = "unspecified"); void status_clear_warning(); From 7e8e658999d169757c0a00b56d97cbde09113a60 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Wed, 20 Mar 2024 04:37:18 +0100 Subject: [PATCH 1427/2607] web_server support for v3 (#6203) --- esphome/components/web_server/__init__.py | 9 +++++++-- esphome/components/web_server/web_server.cpp | 2 +- esphome/components/web_server/web_server.h | 2 +- tests/test10.yaml | 3 +++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 2708b5d06e..bbd5bc662e 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -44,6 +44,11 @@ def default_url(config): config[CONF_CSS_URL] = "" if not (CONF_JS_URL in config): config[CONF_JS_URL] = "https://oi.esphome.io/v2/www.js" + if config[CONF_VERSION] == 3: + if not (CONF_CSS_URL in config): + config[CONF_CSS_URL] = "" + if not (CONF_JS_URL in config): + config[CONF_JS_URL] = "https://oi.esphome.io/v3/www.js" return config @@ -64,7 +69,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(WebServer), cv.Optional(CONF_PORT, default=80): cv.port, - cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), + cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, 3, int=True), cv.Optional(CONF_CSS_URL): cv.string, cv.Optional(CONF_CSS_INCLUDE): cv.file_, cv.Optional(CONF_JS_URL): cv.string, @@ -152,7 +157,7 @@ async def to_code(config): cg.add_define("USE_WEBSERVER") cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) cg.add_define("USE_WEBSERVER_VERSION", version) - if version == 2: + if version >= 2: # Don't compress the index HTML as the data sizes are almost the same. add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) else: diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 69d601ed49..f065dc6684 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -358,7 +358,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("")); request->send(stream); } -#elif USE_WEBSERVER_VERSION == 2 +#elif USE_WEBSERVER_VERSION >= 2 void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 06c59ecaca..57cbbe1339 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -13,7 +13,7 @@ #include #endif -#if USE_WEBSERVER_VERSION == 2 +#if USE_WEBSERVER_VERSION >= 2 extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; #endif diff --git a/tests/test10.yaml b/tests/test10.yaml index 7e3a685b36..854173cfe9 100644 --- a/tests/test10.yaml +++ b/tests/test10.yaml @@ -23,6 +23,9 @@ logger: api: reboot_timeout: 10min +web_server: + version: 3 + time: - platform: sntp From 507568db647d24a58e765a256a43ca04dcc5aeb3 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:53:01 +1100 Subject: [PATCH 1428/2607] AHT10: Use state machine to avoid blocking delay (#6401) --- esphome/components/aht10/aht10.cpp | 107 +++++++++++++++-------------- esphome/components/aht10/aht10.h | 5 ++ 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index 57102e6d27..d5af06c2a2 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -36,6 +36,7 @@ static const uint8_t AHT10_INIT_ATTEMPTS = 10; static const uint8_t AHT10_STATUS_BUSY = 0x80; void AHT10Component::setup() { + this->read_delay_ = this->humidity_sensor_ != nullptr ? AHT10_HUMIDITY_DELAY : AHT10_DEFAULT_DELAY; if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Reset AHT10 failed!"); } @@ -83,74 +84,78 @@ void AHT10Component::setup() { ESP_LOGV(TAG, "AHT10 initialization"); } -void AHT10Component::update() { - if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); - return; - } - uint8_t data[6]; - uint8_t delay_ms = AHT10_DEFAULT_DELAY; - if (this->humidity_sensor_ != nullptr) - delay_ms = AHT10_HUMIDITY_DELAY; - bool success = false; - for (int i = 0; i < AHT10_ATTEMPTS; ++i) { - ESP_LOGVV(TAG, "Attempt %d at %6" PRIu32, i, millis()); - delay(delay_ms); - if (this->read(data, 6) != i2c::ERROR_OK) { - ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); - continue; - } - - if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy - ESP_LOGD(TAG, "AHT10 is busy, waiting..."); - } else if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { - // Unrealistic humidity (0x0) - if (this->humidity_sensor_ == nullptr) { - ESP_LOGVV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); - break; - } else { - ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); - if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); - return; - } - } - } else { - // data is valid, we can break the loop - ESP_LOGVV(TAG, "Answer at %6" PRIu32, millis()); - success = true; - break; - } - } - if (!success || (data[0] & 0x80) == 0x80) { +void AHT10Component::restart_read_() { + if (this->read_count_ == AHT10_ATTEMPTS) { + this->read_count_ = 0; ESP_LOGE(TAG, "Measurements reading timed-out!"); - this->status_set_warning(); + this->status_set_error(); + return; + } + this->read_count_++; + this->set_timeout(this->read_delay_, [this]() { this->read_data_(); }); +} + +void AHT10Component::read_data_() { + uint8_t data[6]; + ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); + if (this->read(data, 6) != i2c::ERROR_OK) { + ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); + this->restart_read_(); return; } + if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy + ESP_LOGD(TAG, "AHT10 is busy, waiting..."); + this->restart_read_(); + return; + } + if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { + // Unrealistic humidity (0x0) + if (this->humidity_sensor_ == nullptr) { + ESP_LOGV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); + } else { + ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); + if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Communication with AHT10 failed!"); + this->status_set_warning(); + } + this->restart_read_(); + return; + } + } + ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; - float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; - float humidity; - if (raw_humidity == 0) { // unrealistic value - humidity = NAN; - } else { - humidity = (float) raw_humidity * 100.0f / 1048576.0f; - } - if (this->temperature_sensor_ != nullptr) { + float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; this->temperature_sensor_->publish_state(temperature); } if (this->humidity_sensor_ != nullptr) { + float humidity; + if (raw_humidity == 0) { // unrealistic value + humidity = NAN; + } else { + humidity = (float) raw_humidity * 100.0f / 1048576.0f; + } if (std::isnan(humidity)) { ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum"); } this->humidity_sensor_->publish_state(humidity); } this->status_clear_warning(); + this->read_count_ = 0; +} +void AHT10Component::update() { + if (this->read_count_ != 0) + return; + this->start_time_ = millis(); + if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Communication with AHT10 failed!"); + this->status_set_warning(); + return; + } + this->restart_read_(); } float AHT10Component::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/aht10/aht10.h b/esphome/components/aht10/aht10.h index 3840609d56..76f051878e 100644 --- a/esphome/components/aht10/aht10.h +++ b/esphome/components/aht10/aht10.h @@ -26,6 +26,11 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; AHT10Variant variant_{}; + unsigned read_count_{}; + unsigned read_delay_{}; + void read_data_(); + void restart_read_(); + uint32_t start_time_{}; }; } // namespace aht10 From e27e3429276b9b5eea17721262b62bafe52a7ce5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:56:43 +1100 Subject: [PATCH 1429/2607] Show component warnings and errors in the log; (#6400) --- esphome/core/component.cpp | 29 +++++++++++++++++++++++------ esphome/core/component.h | 8 ++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index d737ec0ae3..b9a7697015 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -141,18 +141,35 @@ bool Component::is_ready() { (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP; } bool Component::can_proceed() { return true; } -bool Component::status_has_warning() { return this->component_state_ & STATUS_LED_WARNING; } -bool Component::status_has_error() { return this->component_state_ & STATUS_LED_ERROR; } -void Component::status_set_warning() { +bool Component::status_has_warning() const { return this->component_state_ & STATUS_LED_WARNING; } +bool Component::status_has_error() const { return this->component_state_ & STATUS_LED_ERROR; } +void Component::status_set_warning(const char *message) { + // Don't spam the log. This risks missing different warning messages though. + if ((this->component_state_ & STATUS_LED_WARNING) != 0) + return; this->component_state_ |= STATUS_LED_WARNING; App.app_state_ |= STATUS_LED_WARNING; + ESP_LOGW(this->get_component_source(), "Warning set: %s", message); } -void Component::status_set_error() { +void Component::status_set_error(const char *message) { + if ((this->component_state_ & STATUS_LED_ERROR) != 0) + return; this->component_state_ |= STATUS_LED_ERROR; App.app_state_ |= STATUS_LED_ERROR; + ESP_LOGE(this->get_component_source(), "Error set: %s", message); +} +void Component::status_clear_warning() { + if ((this->component_state_ & STATUS_LED_WARNING) == 0) + return; + this->component_state_ &= ~STATUS_LED_WARNING; + ESP_LOGW(this->get_component_source(), "Warning cleared"); +} +void Component::status_clear_error() { + if ((this->component_state_ & STATUS_LED_ERROR) == 0) + return; + this->component_state_ &= ~STATUS_LED_ERROR; + ESP_LOGE(this->get_component_source(), "Error cleared"); } -void Component::status_clear_warning() { this->component_state_ &= ~STATUS_LED_WARNING; } -void Component::status_clear_error() { this->component_state_ &= ~STATUS_LED_ERROR; } void Component::status_momentary_warning(const std::string &name, uint32_t length) { this->status_set_warning(); this->set_timeout(name, length, [this]() { this->status_clear_warning(); }); diff --git a/esphome/core/component.h b/esphome/core/component.h index deefedf3d8..4f244e5fcb 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -124,13 +124,13 @@ class Component { virtual bool can_proceed(); - bool status_has_warning(); + bool status_has_warning() const; - bool status_has_error(); + bool status_has_error() const; - void status_set_warning(); + void status_set_warning(const char *message = "unspecified"); - void status_set_error(); + void status_set_error(const char *message = "unspecified"); void status_clear_warning(); From ccca5458623077a77e63f3e5be20229e1cd26b3a Mon Sep 17 00:00:00 2001 From: RFDarter Date: Wed, 20 Mar 2024 04:37:18 +0100 Subject: [PATCH 1430/2607] web_server support for v3 (#6203) --- esphome/components/web_server/__init__.py | 9 +++++++-- esphome/components/web_server/web_server.cpp | 2 +- esphome/components/web_server/web_server.h | 2 +- tests/test10.yaml | 3 +++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 2708b5d06e..bbd5bc662e 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -44,6 +44,11 @@ def default_url(config): config[CONF_CSS_URL] = "" if not (CONF_JS_URL in config): config[CONF_JS_URL] = "https://oi.esphome.io/v2/www.js" + if config[CONF_VERSION] == 3: + if not (CONF_CSS_URL in config): + config[CONF_CSS_URL] = "" + if not (CONF_JS_URL in config): + config[CONF_JS_URL] = "https://oi.esphome.io/v3/www.js" return config @@ -64,7 +69,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(WebServer), cv.Optional(CONF_PORT, default=80): cv.port, - cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), + cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, 3, int=True), cv.Optional(CONF_CSS_URL): cv.string, cv.Optional(CONF_CSS_INCLUDE): cv.file_, cv.Optional(CONF_JS_URL): cv.string, @@ -152,7 +157,7 @@ async def to_code(config): cg.add_define("USE_WEBSERVER") cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) cg.add_define("USE_WEBSERVER_VERSION", version) - if version == 2: + if version >= 2: # Don't compress the index HTML as the data sizes are almost the same. add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) else: diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 69d601ed49..f065dc6684 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -358,7 +358,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("")); request->send(stream); } -#elif USE_WEBSERVER_VERSION == 2 +#elif USE_WEBSERVER_VERSION >= 2 void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 06c59ecaca..57cbbe1339 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -13,7 +13,7 @@ #include #endif -#if USE_WEBSERVER_VERSION == 2 +#if USE_WEBSERVER_VERSION >= 2 extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; #endif diff --git a/tests/test10.yaml b/tests/test10.yaml index 7e3a685b36..854173cfe9 100644 --- a/tests/test10.yaml +++ b/tests/test10.yaml @@ -23,6 +23,9 @@ logger: api: reboot_timeout: 10min +web_server: + version: 3 + time: - platform: sntp From 6f7273d9cb00d1c6a4618c2b819d00b01601ffd1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:38:15 +1300 Subject: [PATCH 1431/2607] Bump version to 2024.3.0b5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 2b5724c9f3..e573a64e1d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0b4" +__version__ = "2024.3.0b5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 9541df9d88ed99677335c4dc9affef30373dce8e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:15:19 +1300 Subject: [PATCH 1432/2607] Bump version to 2024.3.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e573a64e1d..e386448462 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0b5" +__version__ = "2024.3.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From afbaf56c0bdc90d6b6894b334dc7247ae9a17d95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:14:15 +1300 Subject: [PATCH 1433/2607] Bump pytest-asyncio from 0.23.5.post1 to 0.23.6 (#6402) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 29e5420d78..8fb59683b4 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -8,6 +8,6 @@ pre-commit pytest==8.1.1 pytest-cov==4.1.0 pytest-mock==3.12.0 -pytest-asyncio==0.23.5.post1 +pytest-asyncio==0.23.6 asyncmock==0.4.2 hypothesis==6.92.1 From bdb6881cd5a700b65d8aef312ac45f1cc20bfdcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:14:52 +1300 Subject: [PATCH 1434/2607] Bump actions/cache from 4.0.1 to 4.0.2 in /.github/actions/restore-python (#6403) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 756e279635..aa4f7ba887 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v4.0.1 + uses: actions/cache/restore@v4.0.2 with: path: venv # yamllint disable-line rule:line-length From b12ccd460b4a9b530475e3dc9e01c866d4b7b711 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:15:03 +1300 Subject: [PATCH 1435/2607] Bump actions/cache from 4.0.1 to 4.0.2 (#6404) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47709739dc..871f2e72c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v4.0.1 + uses: actions/cache@v4.0.2 with: path: venv # yamllint disable-line rule:line-length @@ -367,7 +367,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - name: Cache platformio - uses: actions/cache@v4.0.1 + uses: actions/cache@v4.0.2 with: path: ~/.platformio # yamllint disable-line rule:line-length From 7d9fc3ceaab4db660a8aeddb55499d640b549cbe Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Wed, 20 Mar 2024 09:16:10 +0100 Subject: [PATCH 1436/2607] Bump ESP8266 Arduino versions (#5359) --- esphome/components/esp8266/__init__.py | 12 ++++++++---- esphome/components/mqtt/mqtt_client.cpp | 4 ---- esphome/components/wifi/wifi_component_esp8266.cpp | 10 +++++++++- esphome/core/defines.h | 2 +- platformio.ini | 4 ++-- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 5336842b9d..00729921a3 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -83,20 +83,22 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/esp8266/Arduino/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-arduinoespressif8266 -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 0, 2) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 1, 2) # The platformio/espressif8266 version to use for arduino 2 framework versions # - https://github.com/platformio/platform-espressif8266/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif8266 ARDUINO_2_PLATFORM_VERSION = cv.Version(2, 6, 3) # for arduino 3 framework versions ARDUINO_3_PLATFORM_VERSION = cv.Version(3, 2, 0) +# for arduino 4 framework versions +ARDUINO_4_PLATFORM_VERSION = cv.Version(4, 2, 1) def _arduino_check_versions(value): value = value.copy() lookups = { - "dev": (cv.Version(3, 0, 2), "https://github.com/esp8266/Arduino.git"), - "latest": (cv.Version(3, 0, 2), None), + "dev": (cv.Version(3, 1, 2), "https://github.com/esp8266/Arduino.git"), + "latest": (cv.Version(3, 1, 2), None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), } @@ -116,7 +118,9 @@ def _arduino_check_versions(value): platform_version = value.get(CONF_PLATFORM_VERSION) if platform_version is None: - if version >= cv.Version(3, 0, 0): + if version >= cv.Version(3, 1, 0): + platform_version = _parse_platform_version(str(ARDUINO_4_PLATFORM_VERSION)) + elif version >= cv.Version(3, 0, 0): platform_version = _parse_platform_version(str(ARDUINO_3_PLATFORM_VERSION)) elif version >= cv.Version(2, 5, 0): platform_version = _parse_platform_version(str(ARDUINO_2_PLATFORM_VERSION)) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 0f5f49abc1..abcbb414d9 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -187,11 +187,7 @@ void MQTTClientComponent::start_dnslookup_() { default: case ERR_ARG: { // error -#if defined(USE_ESP8266) - ESP_LOGW(TAG, "Error resolving MQTT broker IP address: %ld", err); -#else ESP_LOGW(TAG, "Error resolving MQTT broker IP address: %d", err); -#endif break; } } diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index f274e37a9f..838250972b 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -21,10 +21,14 @@ extern "C" { #include #if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0) #include "LwipDhcpServer.h" +#if USE_ARDUINO_VERSION_CODE < VERSION_CODE(3, 1, 0) +#include +#include "ESP8266WiFiAP.h" #define wifi_softap_set_dhcps_lease(lease) dhcpSoftAP.set_dhcps_lease(lease) #define wifi_softap_set_dhcps_lease_time(time) dhcpSoftAP.set_dhcps_lease_time(time) #define wifi_softap_set_dhcps_offer_option(offer, mode) dhcpSoftAP.set_dhcps_offer_option(offer, mode) #endif +#endif } #include "esphome/core/helpers.h" @@ -721,7 +725,7 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { return false; } -#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0) +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0) && USE_ARDUINO_VERSION_CODE < VERSION_CODE(3, 1, 0) dhcpSoftAP.begin(&info); #endif @@ -745,12 +749,16 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { return false; } +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 1, 0) + ESP8266WiFiClass::softAPDhcpServer().setRouter(true); // send ROUTER option with netif's gateway IP +#else uint8_t mode = 1; // bit0, 1 enables router information from ESP8266 SoftAP DHCP server. if (!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) { ESP_LOGV(TAG, "wifi_softap_set_dhcps_offer_option failed!"); return false; } +#endif if (!wifi_softap_dhcps_start()) { ESP_LOGV(TAG, "Starting SoftAP DHCPS failed!"); diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 86f89e7bf6..501dccc6fa 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -98,7 +98,7 @@ // ESP8266-specific feature flags #ifdef USE_ESP8266 #define USE_ADC_SENSOR_VCC -#define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 0, 2) +#define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 1, 2) #define USE_ESP8266_PREFERENCES_FLASH #define USE_HTTP_REQUEST_ESP8266_HTTPS #define USE_SOCKET_IMPL_LWIP_TCP diff --git a/platformio.ini b/platformio.ini index 8ba8b8a2cf..b326c9722e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,9 +80,9 @@ build_flags = ; This are common settings for the ESP8266 using Arduino. [common:esp8266-arduino] extends = common:arduino -platform = platformio/espressif8266@3.2.0 +platform = platformio/espressif8266@4.2.1 platform_packages = - platformio/framework-arduinoespressif8266@~3.30002.0 + platformio/framework-arduinoespressif8266@~3.30102.0 framework = arduino lib_deps = From b95a7f6438461e1b46f8eb95871345d2be246cf6 Mon Sep 17 00:00:00 2001 From: cvwillegen Date: Wed, 20 Mar 2024 09:16:52 +0100 Subject: [PATCH 1437/2607] Allow accept/reject delta to be specified. (#5060) --- esphome/components/remote_base/__init__.py | 3 +++ esphome/components/remote_base/pronto_protocol.cpp | 5 +++-- esphome/components/remote_base/pronto_protocol.h | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 1d8c6e0967..08652bbfc9 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -32,6 +32,7 @@ from esphome.const import ( CONF_MAGNITUDE, CONF_WAND_ID, CONF_LEVEL, + CONF_DELTA, ) from esphome.core import coroutine from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -792,6 +793,7 @@ async def pioneer_action(var, config, args): PRONTO_SCHEMA = cv.Schema( { cv.Required(CONF_DATA): cv.string, + cv.Optional(CONF_DELTA, default=-1): cv.int_, } ) @@ -803,6 +805,7 @@ def pronto_binary_sensor(var, config): cg.StructInitializer( ProntoData, ("data", config[CONF_DATA]), + ("delta", config[CONF_DELTA]), ) ) ) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index ccae64449a..625af76235 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -49,13 +49,13 @@ bool ProntoData::operator==(const ProntoData &rhs) const { for (std::vector::size_type i = 0; i < data1.size() - 1; ++i) { int diff = data2[i] - data1[i]; diff *= diff; - if (diff > 9) + if (rhs.delta == -1 && diff > 9) return false; total_diff += diff; } - return total_diff <= data1.size() * 3; + return total_diff <= (rhs.delta == -1 ? data1.size() * 3 : rhs.delta); } // DO NOT EXPORT from this file @@ -222,6 +222,7 @@ optional ProntoProtocol::decode(RemoteReceiveData src) { prontodata += compensate_and_dump_sequence_(data, timebase); out.data = prontodata; + out.delta = -1; return out; } diff --git a/esphome/components/remote_base/pronto_protocol.h b/esphome/components/remote_base/pronto_protocol.h index 8b2163af12..e600834d1a 100644 --- a/esphome/components/remote_base/pronto_protocol.h +++ b/esphome/components/remote_base/pronto_protocol.h @@ -12,6 +12,7 @@ std::vector encode_pronto(const std::string &str); struct ProntoData { std::string data; + int delta; bool operator==(const ProntoData &rhs) const; }; @@ -40,10 +41,12 @@ DECLARE_REMOTE_PROTOCOL(Pronto) template class ProntoAction : public RemoteTransmitterActionBase { public: TEMPLATABLE_VALUE(std::string, data) + TEMPLATABLE_VALUE(int, delta) void encode(RemoteTransmitData *dst, Ts... x) override { ProntoData data{}; data.data = this->data_.value(x...); + data.delta = this->delta_.value(x...); ProntoProtocol().encode(dst, data); } }; From b0db7319f90452f66bfaecd6e16a0bc3d8e730d3 Mon Sep 17 00:00:00 2001 From: Gagootron Date: Wed, 20 Mar 2024 09:17:32 +0100 Subject: [PATCH 1438/2607] Allow setting htop for ledc (#6340) --- esphome/components/ledc/ledc_output.cpp | 14 ++++++++++++-- esphome/components/ledc/ledc_output.h | 2 ++ esphome/components/ledc/output.py | 6 ++++++ tests/components/cwww/test.esp32-c3-idf.yaml | 3 +++ tests/components/cwww/test.esp32-idf.yaml | 3 +++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index dfb84c1e76..0533143d37 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -96,6 +96,12 @@ esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_n } #endif +#ifdef USE_ESP_IDF +constexpr int ledc_angle_to_htop(float angle, uint8_t bit_depth) { + return static_cast(angle * ((1U << bit_depth) - 1) / 360.); +} +#endif // USE_ESP_IDF + void LEDCOutput::write_state(float state) { if (!initialized_) { ESP_LOGW(TAG, "LEDC output hasn't been initialized yet!"); @@ -117,7 +123,8 @@ void LEDCOutput::write_state(float state) { #ifdef USE_ESP_IDF auto speed_mode = get_speed_mode(channel_); auto chan_num = static_cast(channel_ % 8); - ledc_set_duty(speed_mode, chan_num, duty); + int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); + ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); ledc_update_duty(speed_mode, chan_num); #endif } @@ -143,8 +150,10 @@ void LEDCOutput::setup() { this->status_set_error(); return; } + int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); ESP_LOGV(TAG, "Configured frequency %f with a bit depth of %u bits", this->frequency_, this->bit_depth_); + ESP_LOGV(TAG, "Angle of %.1f° results in hpoint %u", this->phase_angle_, hpoint); ledc_channel_config_t chan_conf{}; chan_conf.gpio_num = pin_->get_pin(); @@ -153,7 +162,7 @@ void LEDCOutput::setup() { chan_conf.intr_type = LEDC_INTR_DISABLE; chan_conf.timer_sel = timer_num; chan_conf.duty = inverted_ == pin_->is_inverted() ? 0 : (1U << bit_depth_); - chan_conf.hpoint = 0; + chan_conf.hpoint = hpoint; ledc_channel_config(&chan_conf); initialized_ = true; this->status_clear_error(); @@ -165,6 +174,7 @@ void LEDCOutput::dump_config() { LOG_PIN(" Pin ", this->pin_); ESP_LOGCONFIG(TAG, " LEDC Channel: %u", this->channel_); ESP_LOGCONFIG(TAG, " PWM Frequency: %.1f Hz", this->frequency_); + ESP_LOGCONFIG(TAG, " Phase angle: %.1f°", this->phase_angle_); ESP_LOGCONFIG(TAG, " Bit depth: %u", this->bit_depth_); ESP_LOGV(TAG, " Max frequency for bit depth: %f", ledc_max_frequency_for_bit_depth(this->bit_depth_)); ESP_LOGV(TAG, " Min frequency for bit depth: %f", diff --git a/esphome/components/ledc/ledc_output.h b/esphome/components/ledc/ledc_output.h index a78bf440a9..f04543bc5b 100644 --- a/esphome/components/ledc/ledc_output.h +++ b/esphome/components/ledc/ledc_output.h @@ -19,6 +19,7 @@ class LEDCOutput : public output::FloatOutput, public Component { void set_channel(uint8_t channel) { this->channel_ = channel; } void set_frequency(float frequency) { this->frequency_ = frequency; } + void set_phase_angle(float angle) { this->phase_angle_ = angle; } /// Dynamically change frequency at runtime void update_frequency(float frequency) override; @@ -35,6 +36,7 @@ class LEDCOutput : public output::FloatOutput, public Component { InternalGPIOPin *pin_; uint8_t channel_{}; uint8_t bit_depth_{}; + float phase_angle_{0.0f}; float frequency_{}; float duty_{0.0f}; bool initialized_ = false; diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py index f6dc89cd9b..32c68f8d24 100644 --- a/esphome/components/ledc/output.py +++ b/esphome/components/ledc/output.py @@ -3,6 +3,7 @@ from esphome.components import output import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( + CONF_PHASE_ANGLE, CONF_CHANNEL, CONF_FREQUENCY, CONF_ID, @@ -46,6 +47,9 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_FREQUENCY, default="1kHz"): cv.frequency, cv.Optional(CONF_CHANNEL): cv.int_range(min=0, max=15), + cv.Optional(CONF_PHASE_ANGLE): cv.All( + cv.only_with_esp_idf, cv.angle, cv.float_range(min=0.0, max=360.0) + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -58,6 +62,8 @@ async def to_code(config): if CONF_CHANNEL in config: cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_frequency(config[CONF_FREQUENCY])) + if CONF_PHASE_ANGLE in config: + cg.add(var.set_phase_angle(config[CONF_PHASE_ANGLE])) @automation.register_action( diff --git a/tests/components/cwww/test.esp32-c3-idf.yaml b/tests/components/cwww/test.esp32-c3-idf.yaml index c829ca2a2b..2760a167ee 100644 --- a/tests/components/cwww/test.esp32-c3-idf.yaml +++ b/tests/components/cwww/test.esp32-c3-idf.yaml @@ -2,9 +2,12 @@ output: - platform: ledc id: light_output_1 pin: 1 + channel: 0 - platform: ledc id: light_output_2 pin: 2 + channel: 1 + phase_angle: 180° light: - platform: cwww diff --git a/tests/components/cwww/test.esp32-idf.yaml b/tests/components/cwww/test.esp32-idf.yaml index f108d96ad3..27fa160e56 100644 --- a/tests/components/cwww/test.esp32-idf.yaml +++ b/tests/components/cwww/test.esp32-idf.yaml @@ -2,9 +2,12 @@ output: - platform: ledc id: light_output_1 pin: 12 + channel: 0 - platform: ledc id: light_output_2 pin: 13 + channel: 1 + phase_angle: 180° light: - platform: cwww From 98466cb7f5edf1dd4540efc76ff1a5f6f7b21ff8 Mon Sep 17 00:00:00 2001 From: Jasper Albering Date: Wed, 20 Mar 2024 09:17:59 +0100 Subject: [PATCH 1439/2607] sm2135: add separate_modes option to support different chip variants (#6152) --- esphome/components/sm2135/__init__.py | 3 +++ esphome/components/sm2135/sm2135.cpp | 31 +++++++++++++++++---------- esphome/components/sm2135/sm2135.h | 3 +++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/esphome/components/sm2135/__init__.py b/esphome/components/sm2135/__init__.py index ce78d5337f..52128f1f24 100644 --- a/esphome/components/sm2135/__init__.py +++ b/esphome/components/sm2135/__init__.py @@ -15,6 +15,7 @@ SM2135 = sm2135_ns.class_("SM2135", cg.Component) CONF_RGB_CURRENT = "rgb_current" CONF_CW_CURRENT = "cw_current" +CONF_SEPARATE_MODES = "separate_modes" SM2135Current = sm2135_ns.enum("SM2135Current") @@ -51,6 +52,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_RGB_CURRENT, "20mA"): cv.enum(DRIVE_STRENGTHS_RGB), cv.Optional(CONF_CW_CURRENT, "10mA"): cv.enum(DRIVE_STRENGTHS_CW), + cv.Optional(CONF_SEPARATE_MODES, default=True): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA) @@ -66,3 +68,4 @@ async def to_code(config): cg.add(var.set_rgb_current(config[CONF_RGB_CURRENT])) cg.add(var.set_cw_current(config[CONF_CW_CURRENT])) + cg.add(var.set_separate_modes(config[CONF_SEPARATE_MODES])) diff --git a/esphome/components/sm2135/sm2135.cpp b/esphome/components/sm2135/sm2135.cpp index f9cd4235ed..9a576859ac 100644 --- a/esphome/components/sm2135/sm2135.cpp +++ b/esphome/components/sm2135/sm2135.cpp @@ -97,23 +97,32 @@ void SM2135::loop() { this->write_byte_(SM2135_ADDR_MC); this->write_byte_(current_mask_); - if (this->update_channel_ == 3 || this->update_channel_ == 4) { - // No color so must be Cold/Warm + if (this->separate_modes_) { + if (this->update_channel_ == 3 || this->update_channel_ == 4) { + // No color so must be Cold/Warm - this->write_byte_(SM2135_CW); - this->sm2135_stop_(); - delay(1); - this->sm2135_start_(); - this->write_byte_(SM2135_ADDR_C); - this->write_byte_(this->pwm_amounts_[4]); // Warm - this->write_byte_(this->pwm_amounts_[3]); // Cold + this->write_byte_(SM2135_CW); + this->sm2135_stop_(); + delay(1); + this->sm2135_start_(); + this->write_byte_(SM2135_ADDR_C); + this->write_byte_(this->pwm_amounts_[4]); // Warm + this->write_byte_(this->pwm_amounts_[3]); // Cold + } else { + // Color + + this->write_byte_(SM2135_RGB); + this->write_byte_(this->pwm_amounts_[1]); // Green + this->write_byte_(this->pwm_amounts_[0]); // Red + this->write_byte_(this->pwm_amounts_[2]); // Blue + } } else { - // Color - this->write_byte_(SM2135_RGB); this->write_byte_(this->pwm_amounts_[1]); // Green this->write_byte_(this->pwm_amounts_[0]); // Red this->write_byte_(this->pwm_amounts_[2]); // Blue + this->write_byte_(this->pwm_amounts_[4]); // Warm + this->write_byte_(this->pwm_amounts_[3]); // Cold } this->sm2135_stop_(); diff --git a/esphome/components/sm2135/sm2135.h b/esphome/components/sm2135/sm2135.h index a557fc3287..6f207d093a 100644 --- a/esphome/components/sm2135/sm2135.h +++ b/esphome/components/sm2135/sm2135.h @@ -39,6 +39,8 @@ class SM2135 : public Component { this->current_mask_ = (this->rgb_current_ << 4) | this->cw_current_; } + void set_separate_modes(bool separate_modes) { this->separate_modes_ = separate_modes; } + void setup() override; void dump_config() override; @@ -78,6 +80,7 @@ class SM2135 : public Component { uint8_t current_mask_; SM2135Current rgb_current_; SM2135Current cw_current_; + bool separate_modes_; uint8_t update_channel_; std::vector pwm_amounts_; bool update_{true}; From 0cb1cc9e1c1ee2ada27b81b7f6fad54f6b2fea63 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 20 Mar 2024 19:20:42 +1100 Subject: [PATCH 1440/2607] AHT10: fix temperature-only operation; add warning/error messages (#6405) --- esphome/components/aht10/aht10.cpp | 23 ++++++++++------------- esphome/components/aht10/aht10.h | 1 - 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index d5af06c2a2..d812d8ef2d 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -15,7 +15,6 @@ #include "aht10.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" -#include namespace esphome { namespace aht10 { @@ -27,7 +26,7 @@ static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00}; static const uint8_t AHT10_SOFTRESET_CMD[] = {0xBA}; static const uint8_t AHT10_DEFAULT_DELAY = 5; // ms, for initialization and temperature measurement -static const uint8_t AHT10_HUMIDITY_DELAY = 30; // ms +static const uint8_t AHT10_READ_DELAY = 80; // ms, time to wait for conversion result static const uint8_t AHT10_SOFTRESET_DELAY = 30; // ms static const uint8_t AHT10_ATTEMPTS = 3; // safety margin, normally 3 attempts are enough: 3*30=90ms @@ -36,7 +35,6 @@ static const uint8_t AHT10_INIT_ATTEMPTS = 10; static const uint8_t AHT10_STATUS_BUSY = 0x80; void AHT10Component::setup() { - this->read_delay_ = this->humidity_sensor_ != nullptr ? AHT10_HUMIDITY_DELAY : AHT10_DEFAULT_DELAY; if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Reset AHT10 failed!"); } @@ -87,19 +85,19 @@ void AHT10Component::setup() { void AHT10Component::restart_read_() { if (this->read_count_ == AHT10_ATTEMPTS) { this->read_count_ = 0; - ESP_LOGE(TAG, "Measurements reading timed-out!"); - this->status_set_error(); + this->status_set_error("Measurements reading timed-out!"); return; } this->read_count_++; - this->set_timeout(this->read_delay_, [this]() { this->read_data_(); }); + this->set_timeout(AHT10_READ_DELAY, [this]() { this->read_data_(); }); } void AHT10Component::read_data_() { uint8_t data[6]; - ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); + if (this->read_count_ > 1) + ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); if (this->read(data, 6) != i2c::ERROR_OK) { - ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); + this->status_set_warning("AHT10 read failed, retrying soon"); this->restart_read_(); return; } @@ -116,14 +114,14 @@ void AHT10Component::read_data_() { } else { ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); + this->status_set_warning("Communication with AHT10 failed!"); } this->restart_read_(); return; } } - ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); + if (this->read_count_ > 1) + ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; @@ -151,8 +149,7 @@ void AHT10Component::update() { return; this->start_time_ = millis(); if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Communication with AHT10 failed!"); - this->status_set_warning(); + this->status_set_warning("Communication with AHT10 failed!"); return; } this->restart_read_(); diff --git a/esphome/components/aht10/aht10.h b/esphome/components/aht10/aht10.h index 76f051878e..a3320c77e0 100644 --- a/esphome/components/aht10/aht10.h +++ b/esphome/components/aht10/aht10.h @@ -27,7 +27,6 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *humidity_sensor_{nullptr}; AHT10Variant variant_{}; unsigned read_count_{}; - unsigned read_delay_{}; void read_data_(); void restart_read_(); uint32_t start_time_{}; From b637fb3adc8dc0d0620f706dc3f20b5cbb53fcbe Mon Sep 17 00:00:00 2001 From: DAVe3283 Date: Wed, 20 Mar 2024 17:57:27 -0600 Subject: [PATCH 1441/2607] Fix logger compile error on ESP32-C6 (#6323) --- esphome/components/logger/logger_esp32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index 7c4d6781c9..740e086f92 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -129,7 +129,7 @@ void Logger::pre_setup() { this->uart_num_ = UART_NUM_2; break; #endif -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#ifdef USE_LOGGER_USB_CDC case UART_SELECTION_USB_CDC: this->uart_num_ = -1; break; From 13059805d074173878132501c58727be286a3d54 Mon Sep 17 00:00:00 2001 From: Moriah Morgan Date: Wed, 20 Mar 2024 19:40:14 -0500 Subject: [PATCH 1442/2607] Add support for new modes in Tuya Climate (#5159) * Add support support for new modes Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control. Also added/fixed support for entity states syncing with current operation mode. * Add support for more climate modes in climate.tuya Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control. Also added/fixed support for entity states syncing with current operation mode. This commit fixes the namespace, because I uploaded the test files to start with. * Code Formatting Changes per Clang format. * More clang formatting fixes. * Breaking Change: Group YAML entries by type Add grouping to Preset, Swing Mode, Fan Speed and Active State. This is a breaking change. * Formatting Changes for validation Formatting changes to be compliant with black and flake8. Also changed constants to match expected format. * More constant value fixes * Final black formatting check? * Changes to init.py according to reviewer requests Make changes to _init_.py according to https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620976, https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278621039, https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620904, and https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620549 Also put Sleep preset in its own config block to be consistent with other presets and fix logic for validate_cooling_values function to better align with existing documentation. * Commit reviewed change Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * update deprecated config option wording * add "this->" to member variables that were missed adding "this->" to some member variables in the swing_mode function. * Update _init_.py to use Python 3.8 Walrus operator Adding Walrus Operator in the to_code function for _init_.py similar to https://github.com/esphome/esphome/pull/5181 * Fix Temperature_Multiplier config entry for code generation --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski --- esphome/components/tuya/climate/__init__.py | 246 ++++++++++++------ .../components/tuya/climate/tuya_climate.cpp | 241 ++++++++++++++++- .../components/tuya/climate/tuya_climate.h | 42 +++ 3 files changed, 449 insertions(+), 80 deletions(-) diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index 199c2eabeb..b3d401e5a4 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -7,15 +7,22 @@ from esphome.const import ( CONF_SWITCH_DATAPOINT, CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, + CONF_PRESET, + CONF_SWING_MODE, + CONF_FAN_MODE, + CONF_TEMPERATURE, ) from .. import tuya_ns, CONF_TUYA_ID, Tuya DEPENDENCIES = ["tuya"] CODEOWNERS = ["@jesserockz"] -CONF_ACTIVE_STATE_DATAPOINT = "active_state_datapoint" -CONF_ACTIVE_STATE_HEATING_VALUE = "active_state_heating_value" -CONF_ACTIVE_STATE_COOLING_VALUE = "active_state_cooling_value" +CONF_ACTIVE_STATE = "active_state" +CONF_DATAPOINT = "datapoint" +CONF_HEATING_VALUE = "heating_value" +CONF_COOLING_VALUE = "cooling_value" +CONF_DRYING_VALUE = "drying_value" +CONF_FANONLY_VALUE = "fanonly_value" CONF_HEATING_STATE_PIN = "heating_state_pin" CONF_COOLING_STATE_PIN = "cooling_state_pin" CONF_TARGET_TEMPERATURE_DATAPOINT = "target_temperature_datapoint" @@ -23,9 +30,17 @@ CONF_CURRENT_TEMPERATURE_DATAPOINT = "current_temperature_datapoint" CONF_TEMPERATURE_MULTIPLIER = "temperature_multiplier" CONF_CURRENT_TEMPERATURE_MULTIPLIER = "current_temperature_multiplier" CONF_TARGET_TEMPERATURE_MULTIPLIER = "target_temperature_multiplier" -CONF_ECO_DATAPOINT = "eco_datapoint" -CONF_ECO_TEMPERATURE = "eco_temperature" +CONF_ECO = "eco" +CONF_SLEEP = "sleep" +CONF_SLEEP_DATAPOINT = "sleep_datapoint" CONF_REPORTS_FAHRENHEIT = "reports_fahrenheit" +CONF_VERTICAL_DATAPOINT = "vertical_datapoint" +CONF_HORIZONTAL_DATAPOINT = "horizontal_datapoint" +CONF_LOW_VALUE = "low_value" +CONF_MEDIUM_VALUE = "medium_value" +CONF_MIDDLE_VALUE = "middle_value" +CONF_HIGH_VALUE = "high_value" +CONF_AUTO_VALUE = "auto_value" TuyaClimate = tuya_ns.class_("TuyaClimate", climate.Climate, cg.Component) @@ -67,30 +82,73 @@ def validate_temperature_multipliers(value): return value -def validate_active_state_values(value): - if CONF_ACTIVE_STATE_DATAPOINT not in value: - if CONF_ACTIVE_STATE_COOLING_VALUE in value: - raise cv.Invalid( - f"{CONF_ACTIVE_STATE_DATAPOINT} required if using " - f"{CONF_ACTIVE_STATE_COOLING_VALUE}" - ) - else: - if value[CONF_SUPPORTS_COOL] and CONF_ACTIVE_STATE_COOLING_VALUE not in value: - raise cv.Invalid( - f"{CONF_ACTIVE_STATE_COOLING_VALUE} required if using " - f"{CONF_ACTIVE_STATE_DATAPOINT} and device supports cooling" - ) +def validate_cooling_values(value): + if CONF_SUPPORTS_COOL in value: + cooling_supported = value[CONF_SUPPORTS_COOL] + if not cooling_supported and CONF_ACTIVE_STATE in value: + active_state_config = value[CONF_ACTIVE_STATE] + if ( + CONF_COOLING_VALUE in active_state_config + or CONF_COOLING_STATE_PIN in value + ): + raise cv.Invalid( + f"Device does not support cooling, but {CONF_COOLING_VALUE} or {CONF_COOLING_STATE_PIN} specified." + f" Please add '{CONF_SUPPORTS_COOL}: true' to your configuration." + ) + elif cooling_supported and CONF_ACTIVE_STATE in value: + active_state_config = value[CONF_ACTIVE_STATE] + if ( + CONF_COOLING_VALUE not in active_state_config + and CONF_COOLING_STATE_PIN not in value + ): + raise cv.Invalid( + f"Either {CONF_ACTIVE_STATE} {CONF_COOLING_VALUE} or {CONF_COOLING_STATE_PIN} is required if" + f" {CONF_SUPPORTS_COOL}: true' is in your configuration." + ) return value -def validate_eco_values(value): - if CONF_ECO_TEMPERATURE in value and CONF_ECO_DATAPOINT not in value: - raise cv.Invalid( - f"{CONF_ECO_DATAPOINT} required if using {CONF_ECO_TEMPERATURE}" - ) - return value +ACTIVE_STATES = cv.Schema( + { + cv.Required(CONF_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_HEATING_VALUE, default=1): cv.uint8_t, + cv.Optional(CONF_COOLING_VALUE): cv.uint8_t, + cv.Optional(CONF_DRYING_VALUE): cv.uint8_t, + cv.Optional(CONF_FANONLY_VALUE): cv.uint8_t, + }, +) +PRESETS = cv.Schema( + { + cv.Optional(CONF_ECO): { + cv.Required(CONF_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_TEMPERATURE): cv.temperature, + }, + cv.Optional(CONF_SLEEP): { + cv.Required(CONF_DATAPOINT): cv.uint8_t, + }, + }, +) + +FAN_MODES = cv.Schema( + { + cv.Required(CONF_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_AUTO_VALUE): cv.uint8_t, + cv.Optional(CONF_LOW_VALUE): cv.uint8_t, + cv.Optional(CONF_MEDIUM_VALUE): cv.uint8_t, + cv.Optional(CONF_MIDDLE_VALUE): cv.uint8_t, + cv.Optional(CONF_HIGH_VALUE): cv.uint8_t, + } +) + +SWING_MODES = cv.Schema( + { + cv.Optional(CONF_VERTICAL_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_HORIZONTAL_DATAPOINT): cv.uint8_t, + }, +) + CONFIG_SCHEMA = cv.All( climate.CLIMATE_SCHEMA.extend( { @@ -99,9 +157,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, cv.Optional(CONF_SUPPORTS_COOL, default=False): cv.boolean, cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t, - cv.Optional(CONF_ACTIVE_STATE_DATAPOINT): cv.uint8_t, - cv.Optional(CONF_ACTIVE_STATE_HEATING_VALUE, default=1): cv.uint8_t, - cv.Optional(CONF_ACTIVE_STATE_COOLING_VALUE): cv.uint8_t, + cv.Optional(CONF_ACTIVE_STATE): ACTIVE_STATES, cv.Optional(CONF_HEATING_STATE_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_COOLING_STATE_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_TARGET_TEMPERATURE_DATAPOINT): cv.uint8_t, @@ -109,17 +165,32 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_TEMPERATURE_MULTIPLIER): cv.positive_float, cv.Optional(CONF_CURRENT_TEMPERATURE_MULTIPLIER): cv.positive_float, cv.Optional(CONF_TARGET_TEMPERATURE_MULTIPLIER): cv.positive_float, - cv.Optional(CONF_ECO_DATAPOINT): cv.uint8_t, - cv.Optional(CONF_ECO_TEMPERATURE): cv.temperature, cv.Optional(CONF_REPORTS_FAHRENHEIT, default=False): cv.boolean, + cv.Optional(CONF_PRESET): PRESETS, + cv.Optional(CONF_FAN_MODE): FAN_MODES, + cv.Optional(CONF_SWING_MODE): SWING_MODES, + cv.Optional("active_state_datapoint"): cv.invalid( + "'active_state_datapoint' has been moved inside of the 'active_state' config block as 'datapoint'" + ), + cv.Optional("active_state_heating_value"): cv.invalid( + "'active_state_heating_value' has been moved inside of the 'active_state' config block as 'heating_value'" + ), + cv.Optional("active_state_cooling_value"): cv.invalid( + "'active_state_cooling_value' has been moved inside of the 'active_state' config block as 'cooling_value'" + ), + cv.Optional("eco_datapoint"): cv.invalid( + "'eco_datapoint' has been moved inside of the 'eco' config block under 'preset' as 'datapoint'" + ), + cv.Optional("eco_temperature"): cv.invalid( + "'eco_temperature' has been moved inside of the 'eco' config block under 'preset' as 'temperature'" + ), } ).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT), validate_temperature_multipliers, - validate_active_state_values, - cv.has_at_most_one_key(CONF_ACTIVE_STATE_DATAPOINT, CONF_HEATING_STATE_PIN), - cv.has_at_most_one_key(CONF_ACTIVE_STATE_DATAPOINT, CONF_COOLING_STATE_PIN), - validate_eco_values, + validate_cooling_values, + cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_HEATING_STATE_PIN), + cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_COOLING_STATE_PIN), ) @@ -133,61 +204,78 @@ async def to_code(config): cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) - if CONF_SWITCH_DATAPOINT in config: - cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT])) - if CONF_ACTIVE_STATE_DATAPOINT in config: - cg.add(var.set_active_state_id(config[CONF_ACTIVE_STATE_DATAPOINT])) - if CONF_ACTIVE_STATE_HEATING_VALUE in config: - cg.add( - var.set_active_state_heating_value( - config[CONF_ACTIVE_STATE_HEATING_VALUE] - ) - ) - if CONF_ACTIVE_STATE_COOLING_VALUE in config: - cg.add( - var.set_active_state_cooling_value( - config[CONF_ACTIVE_STATE_COOLING_VALUE] - ) - ) + if switch_datapoint := config.get(CONF_SWITCH_DATAPOINT): + cg.add(var.set_switch_id(switch_datapoint)) + + if active_state_config := config.get(CONF_ACTIVE_STATE): + cg.add(var.set_active_state_id(CONF_DATAPOINT)) + if (heating_value := active_state_config.get(CONF_HEATING_VALUE)) is not None: + cg.add(var.set_active_state_heating_value(heating_value)) + if (cooling_value := active_state_config.get(CONF_COOLING_VALUE)) is not None: + cg.add(var.set_active_state_cooling_value(cooling_value)) + if (drying_value := active_state_config.get(CONF_DRYING_VALUE)) is not None: + cg.add(var.set_active_state_drying_value(drying_value)) + if (fanonly_value := active_state_config.get(CONF_FANONLY_VALUE)) is not None: + cg.add(var.set_active_state_fanonly_value(fanonly_value)) else: - if CONF_HEATING_STATE_PIN in config: + if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): heating_state_pin = await cg.gpio_pin_expression( - config[CONF_HEATING_STATE_PIN] + config(heating_state_pin_config) ) cg.add(var.set_heating_state_pin(heating_state_pin)) - if CONF_COOLING_STATE_PIN in config: + if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): cooling_state_pin = await cg.gpio_pin_expression( - config[CONF_COOLING_STATE_PIN] + config(cooling_state_pin_config) ) cg.add(var.set_cooling_state_pin(cooling_state_pin)) - if CONF_TARGET_TEMPERATURE_DATAPOINT in config: - cg.add(var.set_target_temperature_id(config[CONF_TARGET_TEMPERATURE_DATAPOINT])) - if CONF_CURRENT_TEMPERATURE_DATAPOINT in config: - cg.add( - var.set_current_temperature_id(config[CONF_CURRENT_TEMPERATURE_DATAPOINT]) - ) - if CONF_TEMPERATURE_MULTIPLIER in config: - cg.add( - var.set_target_temperature_multiplier(config[CONF_TEMPERATURE_MULTIPLIER]) - ) - cg.add( - var.set_current_temperature_multiplier(config[CONF_TEMPERATURE_MULTIPLIER]) - ) + + if target_temperature_datapoint := config.get(CONF_TARGET_TEMPERATURE_DATAPOINT): + cg.add(var.set_target_temperature_id(target_temperature_datapoint)) + if current_temperature_datapoint := config.get(CONF_CURRENT_TEMPERATURE_DATAPOINT): + cg.add(var.set_current_temperature_id(current_temperature_datapoint)) + + if temperature_multiplier := config.get(CONF_TEMPERATURE_MULTIPLIER): + cg.add(var.set_target_temperature_multiplier(temperature_multiplier)) + cg.add(var.set_current_temperature_multiplier(temperature_multiplier)) else: - cg.add( - var.set_current_temperature_multiplier( - config[CONF_CURRENT_TEMPERATURE_MULTIPLIER] + if current_temperature_multiplier := config.get( + CONF_CURRENT_TEMPERATURE_MULTIPLIER + ): + cg.add( + var.set_current_temperature_multiplier(current_temperature_multiplier) ) - ) - cg.add( - var.set_target_temperature_multiplier( - config[CONF_TARGET_TEMPERATURE_MULTIPLIER] - ) - ) - if CONF_ECO_DATAPOINT in config: - cg.add(var.set_eco_id(config[CONF_ECO_DATAPOINT])) - if CONF_ECO_TEMPERATURE in config: - cg.add(var.set_eco_temperature(config[CONF_ECO_TEMPERATURE])) + if target_temperature_multiplier := config.get( + CONF_TARGET_TEMPERATURE_MULTIPLIER + ): + cg.add(var.set_target_temperature_multiplier(target_temperature_multiplier)) if config[CONF_REPORTS_FAHRENHEIT]: cg.add(var.set_reports_fahrenheit()) + + if preset_config := config.get(CONF_PRESET, {}): + if eco_config := preset_config.get(CONF_ECO, {}): + cg.add(var.set_eco_id(CONF_DATAPOINT)) + if eco_temperature := eco_config.get(CONF_TEMPERATURE): + cg.add(var.set_eco_temperature(eco_temperature)) + if CONF_SLEEP in preset_config: + cg.add(var.set_sleep_id(CONF_DATAPOINT)) + + if swing_mode_config := config.get(CONF_SWING_MODE): + if swing_vertical_datapoint := swing_mode_config.get(CONF_VERTICAL_DATAPOINT): + cg.add(var.set_swing_vertical_id(swing_vertical_datapoint)) + if swing_horizontal_datapoint := swing_mode_config.get( + CONF_HORIZONTAL_DATAPOINT + ): + cg.add(var.set_swing_horizontal_id(swing_horizontal_datapoint)) + if fan_mode_config := config.get(CONF_FAN_MODE): + cg.add(var.set_fan_speed_id(CONF_DATAPOINT)) + if (fan_auto_value := fan_mode_config.get(CONF_AUTO_VALUE)) is not None: + cg.add(var.set_fan_speed_auto_value(fan_auto_value)) + if (fan_low_value := fan_mode_config.get(CONF_LOW_VALUE)) is not None: + cg.add(var.set_fan_speed_low_value(fan_low_value)) + if (fan_medium_value := fan_mode_config.get(CONF_MEDIUM_VALUE)) is not None: + cg.add(var.set_fan_speed_medium_value(fan_medium_value)) + if (fan_middle_value := fan_mode_config.get(CONF_MIDDLE_VALUE)) is not None: + cg.add(var.set_fan_speed_middle_value(fan_middle_value)) + if (fan_high_value := fan_mode_config.get(CONF_HIGH_VALUE)) is not None: + cg.add(var.set_fan_speed_high_value(fan_high_value)) diff --git a/esphome/components/tuya/climate/tuya_climate.cpp b/esphome/components/tuya/climate/tuya_climate.cpp index 687764e30f..274e19a69e 100644 --- a/esphome/components/tuya/climate/tuya_climate.cpp +++ b/esphome/components/tuya/climate/tuya_climate.cpp @@ -75,6 +75,41 @@ void TuyaClimate::setup() { this->publish_state(); }); } + if (this->sleep_id_.has_value()) { + this->parent_->register_listener(*this->sleep_id_, [this](const TuyaDatapoint &datapoint) { + this->sleep_ = datapoint.value_bool; + ESP_LOGV(TAG, "MCU reported sleep is: %s", ONOFF(this->sleep_)); + this->compute_preset_(); + this->compute_target_temperature_(); + this->publish_state(); + }); + } + if (this->swing_vertical_id_.has_value()) { + this->parent_->register_listener(*this->swing_vertical_id_, [this](const TuyaDatapoint &datapoint) { + this->swing_vertical_ = datapoint.value_bool; + ESP_LOGV(TAG, "MCU reported vertical swing is: %s", ONOFF(datapoint.value_bool)); + this->compute_swingmode_(); + this->publish_state(); + }); + } + + if (this->swing_horizontal_id_.has_value()) { + this->parent_->register_listener(*this->swing_horizontal_id_, [this](const TuyaDatapoint &datapoint) { + this->swing_horizontal_ = datapoint.value_bool; + ESP_LOGV(TAG, "MCU reported horizontal swing is: %s", ONOFF(datapoint.value_bool)); + this->compute_swingmode_(); + this->publish_state(); + }); + } + + if (this->fan_speed_id_.has_value()) { + this->parent_->register_listener(*this->fan_speed_id_, [this](const TuyaDatapoint &datapoint) { + ESP_LOGV(TAG, "MCU reported Fan Speed Mode is: %u", datapoint.value_enum); + this->fan_state_ = datapoint.value_enum; + this->compute_fanmode_(); + this->publish_state(); + }); + } } void TuyaClimate::loop() { @@ -110,8 +145,22 @@ void TuyaClimate::control(const climate::ClimateCall &call) { const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF; ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state)); this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state); + const climate::ClimateMode new_mode = *call.get_mode(); + + if (new_mode == climate::CLIMATE_MODE_HEAT && this->supports_heat_) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_heating_value_); + } else if (new_mode == climate::CLIMATE_MODE_COOL && this->supports_cool_) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_cooling_value_); + } else if (new_mode == climate::CLIMATE_MODE_DRY && this->active_state_drying_value_.has_value()) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_drying_value_); + } else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY && this->active_state_fanonly_value_.has_value()) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_fanonly_value_); + } } + control_swing_mode_(call); + control_fan_mode_(call); + if (call.get_target_temperature().has_value()) { float target_temperature = *call.get_target_temperature(); if (this->reports_fahrenheit_) @@ -129,6 +178,106 @@ void TuyaClimate::control(const climate::ClimateCall &call) { ESP_LOGV(TAG, "Setting eco: %s", ONOFF(eco)); this->parent_->set_boolean_datapoint_value(*this->eco_id_, eco); } + if (this->sleep_id_.has_value()) { + const bool sleep = preset == climate::CLIMATE_PRESET_SLEEP; + ESP_LOGV(TAG, "Setting sleep: %s", ONOFF(sleep)); + this->parent_->set_boolean_datapoint_value(*this->sleep_id_, sleep); + } + } +} + +void TuyaClimate::control_swing_mode_(const climate::ClimateCall &call) { + bool vertical_swing_changed = false; + bool horizontal_swing_changed = false; + + if (call.get_swing_mode().has_value()) { + const auto swing_mode = *call.get_swing_mode(); + + switch (swing_mode) { + case climate::CLIMATE_SWING_OFF: + if (swing_vertical_ || swing_horizontal_) { + this->swing_vertical_ = false; + this->swing_horizontal_ = false; + vertical_swing_changed = true; + horizontal_swing_changed = true; + } + break; + + case climate::CLIMATE_SWING_BOTH: + if (!swing_vertical_ || !swing_horizontal_) { + this->swing_vertical_ = true; + this->swing_horizontal_ = true; + vertical_swing_changed = true; + horizontal_swing_changed = true; + } + break; + + case climate::CLIMATE_SWING_VERTICAL: + if (!swing_vertical_ || swing_horizontal_) { + this->swing_vertical_ = true; + this->swing_horizontal_ = false; + vertical_swing_changed = true; + horizontal_swing_changed = true; + } + break; + + case climate::CLIMATE_SWING_HORIZONTAL: + if (swing_vertical_ || !swing_horizontal_) { + this->swing_vertical_ = false; + this->swing_horizontal_ = true; + vertical_swing_changed = true; + horizontal_swing_changed = true; + } + break; + + default: + break; + } + } + + if (vertical_swing_changed && this->swing_vertical_id_.has_value()) { + ESP_LOGV(TAG, "Setting vertical swing: %s", ONOFF(swing_vertical_)); + this->parent_->set_boolean_datapoint_value(*this->swing_vertical_id_, swing_vertical_); + } + + if (horizontal_swing_changed && this->swing_horizontal_id_.has_value()) { + ESP_LOGV(TAG, "Setting horizontal swing: %s", ONOFF(swing_horizontal_)); + this->parent_->set_boolean_datapoint_value(*this->swing_horizontal_id_, swing_horizontal_); + } + + // Publish the state after updating the swing mode + this->publish_state(); +} + +void TuyaClimate::control_fan_mode_(const climate::ClimateCall &call) { + if (call.get_fan_mode().has_value()) { + climate::ClimateFanMode fan_mode = *call.get_fan_mode(); + + uint8_t tuya_fan_speed; + switch (fan_mode) { + case climate::CLIMATE_FAN_LOW: + tuya_fan_speed = *fan_speed_low_value_; + break; + case climate::CLIMATE_FAN_MEDIUM: + tuya_fan_speed = *fan_speed_medium_value_; + break; + case climate::CLIMATE_FAN_MIDDLE: + tuya_fan_speed = *fan_speed_middle_value_; + break; + case climate::CLIMATE_FAN_HIGH: + tuya_fan_speed = *fan_speed_high_value_; + break; + case climate::CLIMATE_FAN_AUTO: + tuya_fan_speed = *fan_speed_auto_value_; + break; + default: + tuya_fan_speed = 0; + break; + } + + if (this->fan_speed_id_.has_value()) { + this->parent_->set_enum_datapoint_value(*this->fan_speed_id_, tuya_fan_speed); + } } } @@ -140,10 +289,46 @@ climate::ClimateTraits TuyaClimate::traits() { traits.add_supported_mode(climate::CLIMATE_MODE_HEAT); if (supports_cool_) traits.add_supported_mode(climate::CLIMATE_MODE_COOL); + if (this->active_state_drying_value_.has_value()) + traits.add_supported_mode(climate::CLIMATE_MODE_DRY); + if (this->active_state_fanonly_value_.has_value()) + traits.add_supported_mode(climate::CLIMATE_MODE_FAN_ONLY); if (this->eco_id_.has_value()) { - traits.add_supported_preset(climate::CLIMATE_PRESET_NONE); traits.add_supported_preset(climate::CLIMATE_PRESET_ECO); } + if (this->sleep_id_.has_value()) { + traits.add_supported_preset(climate::CLIMATE_PRESET_SLEEP); + } + if (this->sleep_id_.has_value() || this->eco_id_.has_value()) { + traits.add_supported_preset(climate::CLIMATE_PRESET_NONE); + } + if (this->swing_vertical_id_.has_value() && this->swing_horizontal_id_.has_value()) { + std::set supported_swing_modes = { + climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL}; + traits.set_supported_swing_modes(std::move(supported_swing_modes)); + } else if (this->swing_vertical_id_.has_value()) { + std::set supported_swing_modes = {climate::CLIMATE_SWING_OFF, + climate::CLIMATE_SWING_VERTICAL}; + traits.set_supported_swing_modes(std::move(supported_swing_modes)); + } else if (this->swing_horizontal_id_.has_value()) { + std::set supported_swing_modes = {climate::CLIMATE_SWING_OFF, + climate::CLIMATE_SWING_HORIZONTAL}; + traits.set_supported_swing_modes(std::move(supported_swing_modes)); + } + + if (fan_speed_id_) { + if (fan_speed_low_value_) + traits.add_supported_fan_mode(climate::CLIMATE_FAN_LOW); + if (fan_speed_medium_value_) + traits.add_supported_fan_mode(climate::CLIMATE_FAN_MEDIUM); + if (fan_speed_middle_value_) + traits.add_supported_fan_mode(climate::CLIMATE_FAN_MIDDLE); + if (fan_speed_high_value_) + traits.add_supported_fan_mode(climate::CLIMATE_FAN_HIGH); + if (fan_speed_auto_value_) + traits.add_supported_fan_mode(climate::CLIMATE_FAN_AUTO); + } return traits; } @@ -166,16 +351,56 @@ void TuyaClimate::dump_config() { if (this->eco_id_.has_value()) { ESP_LOGCONFIG(TAG, " Eco has datapoint ID %u", *this->eco_id_); } + if (this->sleep_id_.has_value()) { + ESP_LOGCONFIG(TAG, " Sleep has datapoint ID %u", *this->sleep_id_); + } + if (this->swing_vertical_id_.has_value()) { + ESP_LOGCONFIG(TAG, " Swing Vertical has datapoint ID %u", *this->swing_vertical_id_); + } + if (this->swing_horizontal_id_.has_value()) { + ESP_LOGCONFIG(TAG, " Swing Horizontal has datapoint ID %u", *this->swing_horizontal_id_); + } } void TuyaClimate::compute_preset_() { if (this->eco_) { this->preset = climate::CLIMATE_PRESET_ECO; + } else if (this->sleep_) { + this->preset = climate::CLIMATE_PRESET_SLEEP; } else { this->preset = climate::CLIMATE_PRESET_NONE; } } +void TuyaClimate::compute_swingmode_() { + if (this->swing_vertical_ && this->swing_horizontal_) { + this->swing_mode = climate::CLIMATE_SWING_BOTH; + } else if (this->swing_vertical_) { + this->swing_mode = climate::CLIMATE_SWING_VERTICAL; + } else if (this->swing_horizontal_) { + this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; + } else { + this->swing_mode = climate::CLIMATE_SWING_OFF; + } +} + +void TuyaClimate::compute_fanmode_() { + if (this->fan_speed_id_.has_value()) { + // Use state from MCU datapoint + if (this->fan_speed_auto_value_.has_value() && this->fan_state_ == this->fan_speed_auto_value_) { + this->fan_mode = climate::CLIMATE_FAN_AUTO; + } else if (this->fan_speed_high_value_.has_value() && this->fan_state_ == this->fan_speed_high_value_) { + this->fan_mode = climate::CLIMATE_FAN_HIGH; + } else if (this->fan_speed_medium_value_.has_value() && this->fan_state_ == this->fan_speed_medium_value_) { + this->fan_mode = climate::CLIMATE_FAN_MEDIUM; + } else if (this->fan_speed_middle_value_.has_value() && this->fan_state_ == this->fan_speed_middle_value_) { + this->fan_mode = climate::CLIMATE_FAN_MIDDLE; + } else if (this->fan_speed_low_value_.has_value() && this->fan_state_ == this->fan_speed_low_value_) { + this->fan_mode = climate::CLIMATE_FAN_LOW; + } + } +} + void TuyaClimate::compute_target_temperature_() { if (this->eco_ && this->eco_temperature_.has_value()) { this->target_temperature = *this->eco_temperature_; @@ -202,16 +427,28 @@ void TuyaClimate::compute_state_() { if (this->supports_heat_ && this->active_state_heating_value_.has_value() && this->active_state_ == this->active_state_heating_value_) { target_action = climate::CLIMATE_ACTION_HEATING; + this->mode = climate::CLIMATE_MODE_HEAT; } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() && this->active_state_ == this->active_state_cooling_value_) { target_action = climate::CLIMATE_ACTION_COOLING; + this->mode = climate::CLIMATE_MODE_COOL; + } else if (this->active_state_drying_value_.has_value() && + this->active_state_ == this->active_state_drying_value_) { + target_action = climate::CLIMATE_ACTION_DRYING; + this->mode = climate::CLIMATE_MODE_DRY; + } else if (this->active_state_fanonly_value_.has_value() && + this->active_state_ == this->active_state_fanonly_value_) { + target_action = climate::CLIMATE_ACTION_FAN; + this->mode = climate::CLIMATE_MODE_FAN_ONLY; } } else if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) { // Use state from input pins if (this->heating_state_) { target_action = climate::CLIMATE_ACTION_HEATING; + this->mode = climate::CLIMATE_MODE_HEAT; } else if (this->cooling_state_) { target_action = climate::CLIMATE_ACTION_COOLING; + this->mode = climate::CLIMATE_MODE_COOL; } } else { // Fallback to active state calc based on temp and hysteresis @@ -219,8 +456,10 @@ void TuyaClimate::compute_state_() { if (std::abs(temp_diff) > this->hysteresis_) { if (this->supports_heat_ && temp_diff > 0) { target_action = climate::CLIMATE_ACTION_HEATING; + this->mode = climate::CLIMATE_MODE_HEAT; } else if (this->supports_cool_ && temp_diff < 0) { target_action = climate::CLIMATE_ACTION_COOLING; + this->mode = climate::CLIMATE_MODE_COOL; } } } diff --git a/esphome/components/tuya/climate/tuya_climate.h b/esphome/components/tuya/climate/tuya_climate.h index 7c18625c4e..d6258c21e1 100644 --- a/esphome/components/tuya/climate/tuya_climate.h +++ b/esphome/components/tuya/climate/tuya_climate.h @@ -18,8 +18,22 @@ class TuyaClimate : public climate::Climate, public Component { void set_active_state_id(uint8_t state_id) { this->active_state_id_ = state_id; } void set_active_state_heating_value(uint8_t value) { this->active_state_heating_value_ = value; } void set_active_state_cooling_value(uint8_t value) { this->active_state_cooling_value_ = value; } + void set_active_state_drying_value(uint8_t value) { this->active_state_drying_value_ = value; } + void set_active_state_fanonly_value(uint8_t value) { this->active_state_fanonly_value_ = value; } void set_heating_state_pin(GPIOPin *pin) { this->heating_state_pin_ = pin; } void set_cooling_state_pin(GPIOPin *pin) { this->cooling_state_pin_ = pin; } + void set_swing_vertical_id(uint8_t swing_vertical_id) { this->swing_vertical_id_ = swing_vertical_id; } + void set_swing_horizontal_id(uint8_t swing_horizontal_id) { this->swing_horizontal_id_ = swing_horizontal_id; } + void set_fan_speed_id(uint8_t fan_speed_id) { this->fan_speed_id_ = fan_speed_id; } + void set_fan_speed_low_value(uint8_t fan_speed_low_value) { this->fan_speed_low_value_ = fan_speed_low_value; } + void set_fan_speed_medium_value(uint8_t fan_speed_medium_value) { + this->fan_speed_medium_value_ = fan_speed_medium_value; + } + void set_fan_speed_middle_value(uint8_t fan_speed_middle_value) { + this->fan_speed_middle_value_ = fan_speed_middle_value; + } + void set_fan_speed_high_value(uint8_t fan_speed_high_value) { this->fan_speed_high_value_ = fan_speed_high_value; } + void set_fan_speed_auto_value(uint8_t fan_speed_auto_value) { this->fan_speed_auto_value_ = fan_speed_auto_value; } void set_target_temperature_id(uint8_t target_temperature_id) { this->target_temperature_id_ = target_temperature_id; } @@ -34,6 +48,7 @@ class TuyaClimate : public climate::Climate, public Component { } void set_eco_id(uint8_t eco_id) { this->eco_id_ = eco_id; } void set_eco_temperature(float eco_temperature) { this->eco_temperature_ = eco_temperature; } + void set_sleep_id(uint8_t sleep_id) { this->sleep_id_ = sleep_id; } void set_reports_fahrenheit() { this->reports_fahrenheit_ = true; } @@ -43,6 +58,12 @@ class TuyaClimate : public climate::Climate, public Component { /// Override control to change settings of the climate device. void control(const climate::ClimateCall &call) override; + /// Override control to change settings of swing mode. + void control_swing_mode_(const climate::ClimateCall &call); + + /// Override control to change settings of fan mode. + void control_fan_mode_(const climate::ClimateCall &call); + /// Return the traits of this controller. climate::ClimateTraits traits() override; @@ -55,6 +76,12 @@ class TuyaClimate : public climate::Climate, public Component { /// Re-compute the state of this climate controller. void compute_state_(); + /// Re-Compute the swing mode of this climate controller. + void compute_swingmode_(); + + /// Re-Compute the fan mode of this climate controller. + void compute_fanmode_(); + /// Switch the climate device to the given climate mode. void switch_to_action_(climate::ClimateAction action); @@ -65,6 +92,8 @@ class TuyaClimate : public climate::Climate, public Component { optional active_state_id_{}; optional active_state_heating_value_{}; optional active_state_cooling_value_{}; + optional active_state_drying_value_{}; + optional active_state_fanonly_value_{}; GPIOPin *heating_state_pin_{nullptr}; GPIOPin *cooling_state_pin_{nullptr}; optional target_temperature_id_{}; @@ -73,12 +102,25 @@ class TuyaClimate : public climate::Climate, public Component { float target_temperature_multiplier_{1.0f}; float hysteresis_{1.0f}; optional eco_id_{}; + optional sleep_id_{}; optional eco_temperature_{}; uint8_t active_state_; + uint8_t fan_state_; + optional swing_vertical_id_{}; + optional swing_horizontal_id_{}; + optional fan_speed_id_{}; + optional fan_speed_low_value_{}; + optional fan_speed_medium_value_{}; + optional fan_speed_middle_value_{}; + optional fan_speed_high_value_{}; + optional fan_speed_auto_value_{}; + bool swing_vertical_{false}; + bool swing_horizontal_{false}; bool heating_state_{false}; bool cooling_state_{false}; float manual_temperature_; bool eco_; + bool sleep_; bool reports_fahrenheit_{false}; }; From 1d6f245ced851d5875eac1e691fbda2cf2a692be Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Thu, 21 Mar 2024 03:23:30 +0000 Subject: [PATCH 1443/2607] Add sun_gtil2 component (for SUN-1000G2 / SUN-2000G2 grid tie inverters) (#4958) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/sun_gtil2/__init__.py | 26 ++++ esphome/components/sun_gtil2/sensor.py | 87 +++++++++++ esphome/components/sun_gtil2/sun_gtil2.cpp | 135 ++++++++++++++++++ esphome/components/sun_gtil2/sun_gtil2.h | 58 ++++++++ esphome/components/sun_gtil2/text_sensor.py | 31 ++++ .../sun_gtil2/test.esp32-c3-idf.yaml | 44 ++++++ tests/components/sun_gtil2/test.esp32-c3.yaml | 44 ++++++ .../components/sun_gtil2/test.esp32-idf.yaml | 44 ++++++ tests/components/sun_gtil2/test.esp32.yaml | 44 ++++++ tests/components/sun_gtil2/test.esp8266.yaml | 44 ++++++ tests/components/sun_gtil2/test.rp2040.yaml | 44 ++++++ 12 files changed, 602 insertions(+) create mode 100644 esphome/components/sun_gtil2/__init__.py create mode 100644 esphome/components/sun_gtil2/sensor.py create mode 100644 esphome/components/sun_gtil2/sun_gtil2.cpp create mode 100644 esphome/components/sun_gtil2/sun_gtil2.h create mode 100644 esphome/components/sun_gtil2/text_sensor.py create mode 100644 tests/components/sun_gtil2/test.esp32-c3-idf.yaml create mode 100644 tests/components/sun_gtil2/test.esp32-c3.yaml create mode 100644 tests/components/sun_gtil2/test.esp32-idf.yaml create mode 100644 tests/components/sun_gtil2/test.esp32.yaml create mode 100644 tests/components/sun_gtil2/test.esp8266.yaml create mode 100644 tests/components/sun_gtil2/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 4c24096faa..2c1b8f04ae 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -345,6 +345,7 @@ esphome/components/st7789v/* @kbx81 esphome/components/st7920/* @marsjan155 esphome/components/substitutions/* @esphome/core esphome/components/sun/* @OttoWinter +esphome/components/sun_gtil2/* @Mat931 esphome/components/switch/* @esphome/core esphome/components/t6615/* @tylermenezes esphome/components/tca9548a/* @andreashergert1984 diff --git a/esphome/components/sun_gtil2/__init__.py b/esphome/components/sun_gtil2/__init__.py new file mode 100644 index 0000000000..f4d46fade7 --- /dev/null +++ b/esphome/components/sun_gtil2/__init__.py @@ -0,0 +1,26 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import CONF_ID + +CODEOWNERS = ["@Mat931"] +MULTI_CONF = True +DEPENDENCIES = ["uart"] + +CONF_SUN_GTIL2_ID = "sun_gtil2_id" + +sun_gtil2_ns = cg.esphome_ns.namespace("sun_gtil2") + +SunGTIL2Component = sun_gtil2_ns.class_("SunGTIL2", cg.Component, uart.UARTDevice) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(SunGTIL2Component), + } +).extend(uart.UART_DEVICE_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/esphome/components/sun_gtil2/sensor.py b/esphome/components/sun_gtil2/sensor.py new file mode 100644 index 0000000000..6d1be9c740 --- /dev/null +++ b/esphome/components/sun_gtil2/sensor.py @@ -0,0 +1,87 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + DEVICE_CLASS_VOLTAGE, + DEVICE_CLASS_POWER, + DEVICE_CLASS_TEMPERATURE, + ICON_FLASH, + UNIT_VOLT, + ICON_THERMOMETER, + UNIT_WATT, + UNIT_CELSIUS, + CONF_TEMPERATURE, +) +from . import SunGTIL2Component, CONF_SUN_GTIL2_ID + +CONF_AC_VOLTAGE = "ac_voltage" +CONF_DC_VOLTAGE = "dc_voltage" +CONF_AC_POWER = "ac_power" +CONF_DC_POWER = "dc_power" +CONF_LIMITER_POWER = "limiter_power" + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_SUN_GTIL2_ID): cv.use_id(SunGTIL2Component), + cv.Optional(CONF_AC_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + icon=ICON_FLASH, + accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLTAGE, + ), + cv.Optional(CONF_DC_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + icon=ICON_FLASH, + accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLTAGE, + ), + cv.Optional(CONF_AC_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + icon=ICON_FLASH, + accuracy_decimals=1, + device_class=DEVICE_CLASS_POWER, + ), + cv.Optional(CONF_DC_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + icon=ICON_FLASH, + accuracy_decimals=1, + device_class=DEVICE_CLASS_POWER, + ), + cv.Optional(CONF_LIMITER_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + icon=ICON_FLASH, + accuracy_decimals=1, + device_class=DEVICE_CLASS_POWER, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_SUN_GTIL2_ID]) + if ac_voltage_config := config.get(CONF_AC_VOLTAGE): + sens = await sensor.new_sensor(ac_voltage_config) + cg.add(hub.set_ac_voltage(sens)) + if dc_voltage_config := config.get(CONF_DC_VOLTAGE): + sens = await sensor.new_sensor(dc_voltage_config) + cg.add(hub.set_dc_voltage(sens)) + if ac_power_config := config.get(CONF_AC_POWER): + sens = await sensor.new_sensor(ac_power_config) + cg.add(hub.set_ac_power(sens)) + if dc_power_config := config.get(CONF_DC_POWER): + sens = await sensor.new_sensor(dc_power_config) + cg.add(hub.set_dc_power(sens)) + if limiter_power_config := config.get(CONF_LIMITER_POWER): + sens = await sensor.new_sensor(limiter_power_config) + cg.add(hub.set_limiter_power(sens)) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(hub.set_temperature(sens)) diff --git a/esphome/components/sun_gtil2/sun_gtil2.cpp b/esphome/components/sun_gtil2/sun_gtil2.cpp new file mode 100644 index 0000000000..1653f937dd --- /dev/null +++ b/esphome/components/sun_gtil2/sun_gtil2.cpp @@ -0,0 +1,135 @@ +#include "sun_gtil2.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace sun_gtil2 { + +static const char *const TAG = "sun_gtil2"; + +static const double NTC_A = 0.0011591051055979914; +static const double NTC_B = 0.00022878183547845582; +static const double NTC_C = 1.0396291358342124e-07; +static const float PULLUP_RESISTANCE = 10000.0f; +static const uint16_t ADC_MAX = 1023; // ADC of the inverter controller, not the ESP + +struct SunGTIL2Message { + uint16_t sync; + uint8_t ac_waveform[277]; + uint8_t frequency; + uint16_t ac_voltage; + uint16_t ac_power; + uint16_t dc_voltage; + uint8_t state; + uint8_t unknown1; + uint8_t unknown2; + uint8_t unknown3; + uint8_t limiter_mode; + uint8_t unknown4; + uint16_t temperature; + uint32_t limiter_power; + uint16_t dc_power; + char serial_number[10]; + uint8_t unknown5; + uint8_t end[39]; +} __attribute__((packed)); + +static const uint16_t MESSAGE_SIZE = sizeof(SunGTIL2Message); + +static_assert(MESSAGE_SIZE == 350, "Expected the message size to be 350 bytes"); + +void SunGTIL2::setup() { this->rx_message_.reserve(MESSAGE_SIZE); } + +void SunGTIL2::loop() { + while (this->available()) { + uint8_t c; + this->read_byte(&c); + this->handle_char_(c); + } +} + +std::string SunGTIL2::state_to_string_(uint8_t state) { + switch (state) { + case 0x02: + return "Starting voltage too low"; + case 0x07: + return "Working"; + default: + return str_sprintf("Unknown (0x%02x)", state); + } +} + +float SunGTIL2::calculate_temperature_(uint16_t adc_value) { + if (adc_value >= ADC_MAX || adc_value == 0) { + return NAN; + } + + float ntc_resistance = PULLUP_RESISTANCE / ((static_cast(ADC_MAX) / adc_value) - 1.0f); + double lr = log(double(ntc_resistance)); + double v = NTC_A + NTC_B * lr + NTC_C * lr * lr * lr; + return float(1.0 / v - 273.15); +} + +void SunGTIL2::handle_char_(uint8_t c) { + if (this->rx_message_.size() > 1 || c == 0x07) { + this->rx_message_.push_back(c); + } else if (!this->rx_message_.empty()) { + this->rx_message_.clear(); + } + if (this->rx_message_.size() < MESSAGE_SIZE) { + return; + } + + SunGTIL2Message msg; + memcpy(&msg, this->rx_message_.data(), MESSAGE_SIZE); + this->rx_message_.clear(); + + if (!((msg.end[0] == 0) && (msg.end[38] == 0x08))) + return; + + ESP_LOGVV(TAG, "Frequency raw value: %02x", msg.frequency); + ESP_LOGVV(TAG, "Unknown values: %02x %02x %02x %02x %02x", msg.unknown1, msg.unknown2, msg.unknown3, msg.unknown4, + msg.unknown5); + +#ifdef USE_SENSOR + if (this->ac_voltage_ != nullptr) + this->ac_voltage_->publish_state(__builtin_bswap16(msg.ac_voltage) / 10.0f); + if (this->dc_voltage_ != nullptr) + this->dc_voltage_->publish_state(__builtin_bswap16(msg.dc_voltage) / 8.0f); + if (this->ac_power_ != nullptr) + this->ac_power_->publish_state(__builtin_bswap16(msg.ac_power) / 10.0f); + if (this->dc_power_ != nullptr) + this->dc_power_->publish_state(__builtin_bswap16(msg.dc_power) / 10.0f); + if (this->limiter_power_ != nullptr) + this->limiter_power_->publish_state(static_cast(__builtin_bswap32(msg.limiter_power)) / 10.0f); + if (this->temperature_ != nullptr) + this->temperature_->publish_state(calculate_temperature_(__builtin_bswap16(msg.temperature))); +#endif +#ifdef USE_TEXT_SENSOR + if (this->state_ != nullptr) { + this->state_->publish_state(this->state_to_string_(msg.state)); + } + if (this->serial_number_ != nullptr) { + std::string serial_number; + serial_number.assign(msg.serial_number, 10); + this->serial_number_->publish_state(serial_number); + } +#endif +} + +void SunGTIL2::dump_config() { +#ifdef USE_SENSOR + LOG_SENSOR("", "AC Voltage", this->ac_voltage_); + LOG_SENSOR("", "DC Voltage", this->dc_voltage_); + LOG_SENSOR("", "AC Power", this->ac_power_); + LOG_SENSOR("", "DC Power", this->dc_power_); + LOG_SENSOR("", "Limiter Power", this->limiter_power_); + LOG_SENSOR("", "Temperature", this->temperature_); +#endif +#ifdef USE_TEXT_SENSOR + LOG_TEXT_SENSOR("", "State", this->state_); + LOG_TEXT_SENSOR("", "Serial Number", this->serial_number_); +#endif +} + +} // namespace sun_gtil2 +} // namespace esphome diff --git a/esphome/components/sun_gtil2/sun_gtil2.h b/esphome/components/sun_gtil2/sun_gtil2.h new file mode 100644 index 0000000000..0c29ae695d --- /dev/null +++ b/esphome/components/sun_gtil2/sun_gtil2.h @@ -0,0 +1,58 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" + +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif +#include "esphome/components/uart/uart.h" + +namespace esphome { +namespace sun_gtil2 { + +class SunGTIL2 : public Component, public uart::UARTDevice { + public: + float get_setup_priority() const override { return setup_priority::LATE; } + void setup() override; + void loop() override; + void dump_config() override; + +#ifdef USE_SENSOR + void set_ac_voltage(sensor::Sensor *sensor) { ac_voltage_ = sensor; } + void set_dc_voltage(sensor::Sensor *sensor) { dc_voltage_ = sensor; } + void set_ac_power(sensor::Sensor *sensor) { ac_power_ = sensor; } + void set_dc_power(sensor::Sensor *sensor) { dc_power_ = sensor; } + void set_limiter_power(sensor::Sensor *sensor) { limiter_power_ = sensor; } + void set_temperature(sensor::Sensor *sensor) { temperature_ = sensor; } +#endif +#ifdef USE_TEXT_SENSOR + void set_state(text_sensor::TextSensor *text_sensor) { state_ = text_sensor; } + void set_serial_number(text_sensor::TextSensor *text_sensor) { serial_number_ = text_sensor; } +#endif + + protected: + std::string state_to_string_(uint8_t state); +#ifdef USE_SENSOR + sensor::Sensor *ac_voltage_{nullptr}; + sensor::Sensor *dc_voltage_{nullptr}; + sensor::Sensor *ac_power_{nullptr}; + sensor::Sensor *dc_power_{nullptr}; + sensor::Sensor *limiter_power_{nullptr}; + sensor::Sensor *temperature_{nullptr}; +#endif +#ifdef USE_TEXT_SENSOR + text_sensor::TextSensor *state_{nullptr}; + text_sensor::TextSensor *serial_number_{nullptr}; +#endif + + float calculate_temperature_(uint16_t adc_value); + void handle_char_(uint8_t c); + std::vector rx_message_; +}; + +} // namespace sun_gtil2 +} // namespace esphome diff --git a/esphome/components/sun_gtil2/text_sensor.py b/esphome/components/sun_gtil2/text_sensor.py new file mode 100644 index 0000000000..d9d3e3ca66 --- /dev/null +++ b/esphome/components/sun_gtil2/text_sensor.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import CONF_STATE +from . import SunGTIL2Component, CONF_SUN_GTIL2_ID + +CONF_SERIAL_NUMBER = "serial_number" + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_SUN_GTIL2_ID): cv.use_id(SunGTIL2Component), + cv.Optional(CONF_STATE): text_sensor.text_sensor_schema( + text_sensor.TextSensor + ), + cv.Optional(CONF_SERIAL_NUMBER): text_sensor.text_sensor_schema( + text_sensor.TextSensor + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_SUN_GTIL2_ID]) + if state_config := config.get(CONF_STATE): + sens = await text_sensor.new_text_sensor(state_config) + cg.add(hub.set_state(sens)) + if serial_number_config := config.get(CONF_SERIAL_NUMBER): + sens = await text_sensor.new_text_sensor(serial_number_config) + cg.add(hub.set_serial_number(sens)) diff --git a/tests/components/sun_gtil2/test.esp32-c3-idf.yaml b/tests/components/sun_gtil2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..6ec834db98 --- /dev/null +++ b/tests/components/sun_gtil2/test.esp32-c3-idf.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 5 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true diff --git a/tests/components/sun_gtil2/test.esp32-c3.yaml b/tests/components/sun_gtil2/test.esp32-c3.yaml new file mode 100644 index 0000000000..6ec834db98 --- /dev/null +++ b/tests/components/sun_gtil2/test.esp32-c3.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 5 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true diff --git a/tests/components/sun_gtil2/test.esp32-idf.yaml b/tests/components/sun_gtil2/test.esp32-idf.yaml new file mode 100644 index 0000000000..ed1e68e574 --- /dev/null +++ b/tests/components/sun_gtil2/test.esp32-idf.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 16 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true diff --git a/tests/components/sun_gtil2/test.esp32.yaml b/tests/components/sun_gtil2/test.esp32.yaml new file mode 100644 index 0000000000..ed1e68e574 --- /dev/null +++ b/tests/components/sun_gtil2/test.esp32.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 16 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true diff --git a/tests/components/sun_gtil2/test.esp8266.yaml b/tests/components/sun_gtil2/test.esp8266.yaml new file mode 100644 index 0000000000..6ec834db98 --- /dev/null +++ b/tests/components/sun_gtil2/test.esp8266.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 5 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true diff --git a/tests/components/sun_gtil2/test.rp2040.yaml b/tests/components/sun_gtil2/test.rp2040.yaml new file mode 100644 index 0000000000..6ec834db98 --- /dev/null +++ b/tests/components/sun_gtil2/test.rp2040.yaml @@ -0,0 +1,44 @@ +uart: + - id: control_to_display + rx_pin: + number: 5 + baud_rate: 9600 + +sun_gtil2: + uart_id: control_to_display + +sensor: + - platform: sun_gtil2 + temperature: + id: gtil_temperature + name: "Heatsink Temperature" + filters: + - throttle_average: 30s + dc_voltage: + id: gtil_dc_voltage + name: "DC Voltage" + filters: + - throttle_average: 30s + ac_voltage: + id: gtil_ac_voltage + name: "AC Voltage" + filters: + - throttle_average: 30s + ac_power: + id: gtil_ac_power + name: "AC Power" + dc_power: + id: gtil_dc_power + name: "DC Power" + limiter_power: + id: gtil_limiter_power + internal: true + +text_sensor: + - platform: sun_gtil2 + state: + id: gtil_state + name: "State" + serial_number: + id: gtil_serial_number + internal: true From d0ced3471e8acce2c72e11458005d870ee5eb88c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:25:11 +1100 Subject: [PATCH 1444/2607] SPI: Make some validation failures give more useful messages. (#6413) --- esphome/components/spi/__init__.py | 9 +++++++++ tests/components/xpt2046/test.esp32-c3-idf.yaml | 9 +++++---- tests/components/xpt2046/test.esp32-c3.yaml | 9 +++++---- tests/components/xpt2046/test.esp32-idf.yaml | 9 +++++---- tests/components/xpt2046/test.esp32.yaml | 9 +++++---- tests/components/xpt2046/test.esp8266.yaml | 9 +++++---- tests/components/xpt2046/test.rp2040.yaml | 9 +++++---- 7 files changed, 39 insertions(+), 24 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 2847c5bfa1..fdf19bb56e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -268,6 +268,9 @@ SPI_SCHEMA = cv.All( *sum(get_hw_interface_list(), ["software", "hardware", "any"]), lower=True, ), + cv.Optional(CONF_DATA_PINS): cv.invalid( + "'data_pins' should be used with 'type: quad' only" + ), } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), @@ -287,6 +290,12 @@ SPI_QUAD_SCHEMA = cv.All( *sum(get_hw_interface_list(), ["hardware"]), lower=True, ), + cv.Optional(CONF_MISO_PIN): cv.invalid( + "'miso_pin' should not be used with quad SPI" + ), + cv.Optional(CONF_MOSI_PIN): cv.invalid( + "'mosi_pin' should not be used with quad SPI" + ), } ), cv.only_on([PLATFORM_ESP32]), diff --git a/tests/components/xpt2046/test.esp32-c3-idf.yaml b/tests/components/xpt2046/test.esp32-c3-idf.yaml index 38a1da74ae..f3a2cf9aae 100644 --- a/tests/components/xpt2046/test.esp32-c3-idf.yaml +++ b/tests/components/xpt2046/test.esp32-c3-idf.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) diff --git a/tests/components/xpt2046/test.esp32-c3.yaml b/tests/components/xpt2046/test.esp32-c3.yaml index 38a1da74ae..f3a2cf9aae 100644 --- a/tests/components/xpt2046/test.esp32-c3.yaml +++ b/tests/components/xpt2046/test.esp32-c3.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) diff --git a/tests/components/xpt2046/test.esp32-idf.yaml b/tests/components/xpt2046/test.esp32-idf.yaml index 7f8617d176..bb166866f4 100644 --- a/tests/components/xpt2046/test.esp32-idf.yaml +++ b/tests/components/xpt2046/test.esp32-idf.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) diff --git a/tests/components/xpt2046/test.esp32.yaml b/tests/components/xpt2046/test.esp32.yaml index 7f8617d176..bb166866f4 100644 --- a/tests/components/xpt2046/test.esp32.yaml +++ b/tests/components/xpt2046/test.esp32.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) diff --git a/tests/components/xpt2046/test.esp8266.yaml b/tests/components/xpt2046/test.esp8266.yaml index a998d2df14..a917290e8e 100644 --- a/tests/components/xpt2046/test.esp8266.yaml +++ b/tests/components/xpt2046/test.esp8266.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) diff --git a/tests/components/xpt2046/test.rp2040.yaml b/tests/components/xpt2046/test.rp2040.yaml index 3e5d602247..a7a49309ac 100644 --- a/tests/components/xpt2046/test.rp2040.yaml +++ b/tests/components/xpt2046/test.rp2040.yaml @@ -23,10 +23,11 @@ touchscreen: display: xpt_display update_interval: 50ms threshold: 400 - calibration_x_min: 3860 - calibration_x_max: 280 - calibration_y_min: 340 - calibration_y_max: 3860 + calibration: + x_min: 3860 + x_max: 280 + y_min: 340 + y_max: 3860 on_touch: - logger.log: format: Touch at (%d, %d) From a3b0ddf6864bfdd2142d2c5f532d1de3136fdce4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:31:20 +1300 Subject: [PATCH 1445/2607] Bump aioesphomeapi from 23.1.1 to 23.2.0 (#6412) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4b7e501e97..702127eca8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240319.0 -aioesphomeapi==23.1.1 +aioesphomeapi==23.2.0 zeroconf==0.131.0 python-magic==0.4.27 ruamel.yaml==0.18.6 # dashboard_import From 380146258994f699e505906ec846f697eec756ad Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 22 Mar 2024 19:32:37 +1100 Subject: [PATCH 1446/2607] Add check for use of GPIOXX in config (#6419) --- esphome/pins.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/pins.py b/esphome/pins.py index 87f7084d4f..d02ad357a0 100644 --- a/esphome/pins.py +++ b/esphome/pins.py @@ -311,10 +311,18 @@ def gpio_base_schema( map(lambda m: (cv.Optional(m, default=mode_default), cv.boolean), modes) ) + def _number_validator(value): + if isinstance(value, str) and value.upper().startswith("GPIOX"): + raise cv.Invalid( + f"Found placeholder '{value}' when expecting a GPIO pin number.\n" + "You must replace this with an actual pin number." + ) + return number_validator(value) + schema = cv.Schema( { cv.GenerateID(): cv.declare_id(pin_type), - cv.Required(CONF_NUMBER): number_validator, + cv.Required(CONF_NUMBER): _number_validator, cv.Optional(CONF_ALLOW_OTHER_USES): cv.boolean, cv.Optional(CONF_MODE, default={}): cv.All(mode_dict, mode_validator), } From bd8f9db037d36fac6e71724df41cb751a41b53b2 Mon Sep 17 00:00:00 2001 From: Simone Rossetto Date: Sun, 24 Mar 2024 23:21:04 +0100 Subject: [PATCH 1447/2607] WireGuard for esp8266 (#6365) --- esphome/components/wireguard/__init__.py | 4 +- esphome/components/wireguard/wireguard.cpp | 72 +++---------------- esphome/components/wireguard/wireguard.h | 4 -- platformio.ini | 5 +- .../wireguard/test.esp32-idf.yaml} | 22 ------ tests/components/wireguard/test.esp32.yaml | 62 ++++++++++++++++ tests/components/wireguard/test.esp8266.yaml | 62 ++++++++++++++++ 7 files changed, 139 insertions(+), 92 deletions(-) rename tests/{test10.yaml => components/wireguard/test.esp32-idf.yaml} (84%) create mode 100644 tests/components/wireguard/test.esp32.yaml create mode 100644 tests/components/wireguard/test.esp8266.yaml diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index b59a6011cd..2d68cd001e 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -22,7 +22,7 @@ CONF_PEER_ALLOWED_IPS = "peer_allowed_ips" CONF_PEER_PERSISTENT_KEEPALIVE = "peer_persistent_keepalive" CONF_REQUIRE_CONNECTION_TO_PROCEED = "require_connection_to_proceed" -DEPENDENCIES = ["time", "esp32"] +DEPENDENCIES = ["time"] CODEOWNERS = ["@lhoracek", "@droscy", "@thomas0bernard"] # The key validation regex has been described by Jason Donenfeld himself @@ -120,7 +120,7 @@ async def to_code(config): # the '+1' modifier is relative to the device's own address that will # be automatically added to the provided list. cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}") - cg.add_library("droscy/esp_wireguard", "0.3.2") + cg.add_library("droscy/esp_wireguard", "0.4.0") await cg.register_component(var, config) diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp index cca30d4310..17ebc701e3 100644 --- a/esphome/components/wireguard/wireguard.cpp +++ b/esphome/components/wireguard/wireguard.cpp @@ -1,7 +1,5 @@ #include "wireguard.h" -#ifdef USE_ESP32 - #include #include #include @@ -11,26 +9,20 @@ #include "esphome/core/time.h" #include "esphome/components/network/util.h" -#include - #include - -// includes for resume/suspend wdt -#if defined(USE_ESP_IDF) -#include -#if ESP_IDF_VERSION_MAJOR >= 5 -#include -#endif -#elif defined(USE_ARDUINO) -#include -#endif +#include namespace esphome { namespace wireguard { static const char *const TAG = "wireguard"; -static const char *const LOGMSG_PEER_STATUS = "WireGuard remote peer is %s (latest handshake %s)"; +/* + * Cannot use `static const char*` for LOGMSG_PEER_STATUS on esp8266 platform + * because log messages in `Wireguard::update()` method fail. + */ +#define LOGMSG_PEER_STATUS "WireGuard remote peer is %s (latest handshake %s)" + static const char *const LOGMSG_ONLINE = "online"; static const char *const LOGMSG_OFFLINE = "offline"; @@ -257,20 +249,13 @@ void Wireguard::start_connection_() { } ESP_LOGD(TAG, "starting WireGuard connection..."); - - /* - * The function esp_wireguard_connect() contains a DNS resolution - * that could trigger the watchdog, so before it we suspend (or - * increase the time, it depends on the platform) the wdt and - * then we resume the normal timeout. - */ - suspend_wdt(); - ESP_LOGV(TAG, "executing esp_wireguard_connect"); this->wg_connected_ = esp_wireguard_connect(&(this->wg_ctx_)); - resume_wdt(); if (this->wg_connected_ == ESP_OK) { ESP_LOGI(TAG, "WireGuard connection started"); + } else if (this->wg_connected_ == ESP_ERR_RETRY) { + ESP_LOGD(TAG, "WireGuard is waiting for endpoint IP address to be available"); + return; } else { ESP_LOGW(TAG, "cannot start WireGuard connection, error code %d", this->wg_connected_); return; @@ -300,44 +285,7 @@ void Wireguard::stop_connection_() { } } -void suspend_wdt() { -#if defined(USE_ESP_IDF) -#if ESP_IDF_VERSION_MAJOR >= 5 - ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15000 ms"); - esp_task_wdt_config_t wdtc; - wdtc.timeout_ms = 15000; - wdtc.idle_core_mask = 0; - wdtc.trigger_panic = false; - esp_task_wdt_reconfigure(&wdtc); -#else - ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15 seconds"); - esp_task_wdt_init(15, false); -#endif -#elif defined(USE_ARDUINO) - ESP_LOGV(TAG, "temporarily disabling the wdt"); - disableLoopWDT(); -#endif -} - -void resume_wdt() { -#if defined(USE_ESP_IDF) -#if ESP_IDF_VERSION_MAJOR >= 5 - wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; - esp_task_wdt_reconfigure(&wdtc); - ESP_LOGV(TAG, "wdt resumed with %" PRIu32 " ms timeout", wdtc.timeout_ms); -#else - esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); - ESP_LOGV(TAG, "wdt resumed with %d seconds timeout", CONFIG_ESP_TASK_WDT_TIMEOUT_S); -#endif -#elif defined(USE_ARDUINO) - enableLoopWDT(); - ESP_LOGV(TAG, "wdt resumed"); -#endif -} - std::string mask_key(const std::string &key) { return (key.substr(0, 5) + "[...]="); } } // namespace wireguard } // namespace esphome - -#endif // USE_ESP32 diff --git a/esphome/components/wireguard/wireguard.h b/esphome/components/wireguard/wireguard.h index 7753a8dfc2..a0e9e27a1b 100644 --- a/esphome/components/wireguard/wireguard.h +++ b/esphome/components/wireguard/wireguard.h @@ -1,7 +1,5 @@ #pragma once -#ifdef USE_ESP32 - #include #include #include @@ -172,5 +170,3 @@ template class WireguardDisableAction : public Action, pu } // namespace wireguard } // namespace esphome - -#endif // USE_ESP32 diff --git a/platformio.ini b/platformio.ini index b326c9722e..db5fb3a544 100644 --- a/platformio.ini +++ b/platformio.ini @@ -94,6 +94,7 @@ lib_deps = ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir + droscy/esp_wireguard@0.4.0 ; wireguard build_flags = ${common:arduino.build_flags} -Wno-nonnull-compare @@ -123,7 +124,7 @@ lib_deps = DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir - droscy/esp_wireguard@0.3.2 ; wireguard + droscy/esp_wireguard@0.4.0 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_ESP32 @@ -142,7 +143,7 @@ framework = espidf lib_deps = ${common:idf.lib_deps} espressif/esp32-camera@1.0.0 ; esp32_camera - droscy/esp_wireguard@0.3.2 ; wireguard + droscy/esp_wireguard@0.4.0 ; wireguard build_flags = ${common:idf.build_flags} -Wno-nonnull-compare diff --git a/tests/test10.yaml b/tests/components/wireguard/test.esp32-idf.yaml similarity index 84% rename from tests/test10.yaml rename to tests/components/wireguard/test.esp32-idf.yaml index 854173cfe9..9ea7f00bdb 100644 --- a/tests/test10.yaml +++ b/tests/components/wireguard/test.esp32-idf.yaml @@ -1,36 +1,14 @@ ---- -esphome: - name: test10 - build_path: build/test10 - -esp32: - board: esp32doit-devkit-v1 - framework: - type: arduino - wifi: ssid: "MySSID1" password: "password1" - reboot_timeout: 3min - power_save_mode: high network: enable_ipv6: true -logger: - level: VERBOSE - -api: - reboot_timeout: 10min - -web_server: - version: 3 - time: - platform: sntp wireguard: - id: vpn address: 172.16.34.100 netmask: 255.255.255.0 # NEVER use the following keys for your vpn, they are now public! diff --git a/tests/components/wireguard/test.esp32.yaml b/tests/components/wireguard/test.esp32.yaml new file mode 100644 index 0000000000..9ea7f00bdb --- /dev/null +++ b/tests/components/wireguard/test.esp32.yaml @@ -0,0 +1,62 @@ +wifi: + ssid: "MySSID1" + password: "password1" + +network: + enable_ipv6: true + +time: + - platform: sntp + +wireguard: + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wireguard/test.esp8266.yaml b/tests/components/wireguard/test.esp8266.yaml new file mode 100644 index 0000000000..9ea7f00bdb --- /dev/null +++ b/tests/components/wireguard/test.esp8266.yaml @@ -0,0 +1,62 @@ +wifi: + ssid: "MySSID1" + password: "password1" + +network: + enable_ipv6: true + +time: + - platform: sntp + +wireguard: + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' From 2997964b72f45dc923bed8d166c08df4768fddc7 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Sun, 24 Mar 2024 23:41:53 +0100 Subject: [PATCH 1448/2607] setup.cfg: drop duplicate, underintended trove classifier (#6421) --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 755cef47c0..b3cfbba6a1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,7 +13,6 @@ classifier = Programming Language :: C++ Programming Language :: Python :: 3 Topic :: Home Automation -Topic :: Home Automation [flake8] max-line-length = 120 From e87727aed33c5637d2c2dc64bd76845ea77f6b3b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 25 Mar 2024 09:44:05 +1100 Subject: [PATCH 1449/2607] AHT10: Fix bug (#6409) --- esphome/components/aht10/aht10.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index d812d8ef2d..332218b9e9 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -40,19 +40,18 @@ void AHT10Component::setup() { } delay(AHT10_SOFTRESET_DELAY); - const uint8_t *init_cmd; + i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT; switch (this->variant_) { case AHT10Variant::AHT20: - init_cmd = AHT20_INITIALIZE_CMD; ESP_LOGCONFIG(TAG, "Setting up AHT20"); + error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD)); break; case AHT10Variant::AHT10: - default: - init_cmd = AHT10_INITIALIZE_CMD; ESP_LOGCONFIG(TAG, "Setting up AHT10"); + error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD)); + break; } - - if (this->write(init_cmd, sizeof(init_cmd)) != i2c::ERROR_OK) { + if (error_code != i2c::ERROR_OK) { ESP_LOGE(TAG, "Communication with AHT10 failed!"); this->mark_failed(); return; From 121bd84854fbf8ea33daabdbb320e6508c9ad0d4 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 26 Mar 2024 09:03:51 +1100 Subject: [PATCH 1450/2607] Store preferences in disk file on host platform (#6428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: H. Árkosi Róbert Co-authored-by: clydeps --- esphome/components/host/preferences.cpp | 75 +++++++++++++++++++++---- esphome/components/host/preferences.h | 53 +++++++++++++++++ 2 files changed, 116 insertions(+), 12 deletions(-) diff --git a/esphome/components/host/preferences.cpp b/esphome/components/host/preferences.cpp index bf45893e40..7b939cdebb 100644 --- a/esphome/components/host/preferences.cpp +++ b/esphome/components/host/preferences.cpp @@ -1,36 +1,87 @@ #ifdef USE_HOST +#include +#include #include "preferences.h" -#include -#include "esphome/core/preferences.h" -#include "esphome/core/helpers.h" -#include "esphome/core/log.h" -#include "esphome/core/defines.h" +#include "esphome/core/application.h" namespace esphome { namespace host { +namespace fs = std::filesystem; static const char *const TAG = "host.preferences"; -class HostPreferences : public ESPPreferences { - public: - ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { return {}; } +void HostPreferences::setup_() { + if (this->setup_complete_) + return; + this->filename_.append(getenv("HOME")); + this->filename_.append("/.esphome"); + this->filename_.append("/prefs"); + fs::create_directories(this->filename_); + this->filename_.append("/"); + this->filename_.append(App.get_name()); + this->filename_.append(".prefs"); + FILE *fp = fopen(this->filename_.c_str(), "rb"); + if (fp != nullptr) { + while (!feof((fp))) { + uint32_t key; + uint8_t len; + if (fread(&key, sizeof(key), 1, fp) != 1) + break; + if (fread(&len, sizeof(len), 1, fp) != 1) + break; + uint8_t data[len]; + if (fread(data, sizeof(uint8_t), len, fp) != len) + break; + std::vector vec(data, data + len); + this->data[key] = vec; + } + fclose(fp); + } + this->setup_complete_ = true; +} - ESPPreferenceObject make_preference(size_t length, uint32_t type) override { return {}; } +bool HostPreferences::sync() { + this->setup_(); + FILE *fp = fopen(this->filename_.c_str(), "wb"); + std::map>::iterator it; - bool sync() override { return true; } - bool reset() override { return true; } + for (it = this->data.begin(); it != this->data.end(); ++it) { + fwrite(&it->first, sizeof(uint32_t), 1, fp); + uint8_t len = it->second.size(); + fwrite(&len, sizeof(len), 1, fp); + fwrite(it->second.data(), sizeof(uint8_t), it->second.size(), fp); + } + fclose(fp); + return true; +} + +bool HostPreferences::reset() { + host_preferences->data.clear(); + return true; +} + +ESPPreferenceObject HostPreferences::make_preference(size_t length, uint32_t type, bool in_flash) { + auto backend = new HostPreferenceBackend(type); + return ESPPreferenceObject(backend); }; void setup_preferences() { auto *pref = new HostPreferences(); // NOLINT(cppcoreguidelines-owning-memory) + host_preferences = pref; global_preferences = pref; } +bool HostPreferenceBackend::save(const uint8_t *data, size_t len) { + return host_preferences->save(this->key_, data, len); +} + +bool HostPreferenceBackend::load(uint8_t *data, size_t len) { return host_preferences->load(this->key_, data, len); } + +HostPreferences *host_preferences; } // namespace host ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - } // namespace esphome #endif // USE_HOST diff --git a/esphome/components/host/preferences.h b/esphome/components/host/preferences.h index 7462360ec3..6707366517 100644 --- a/esphome/components/host/preferences.h +++ b/esphome/components/host/preferences.h @@ -2,10 +2,63 @@ #ifdef USE_HOST +#include "esphome/core/preferences.h" +#include + namespace esphome { namespace host { +class HostPreferenceBackend : public ESPPreferenceBackend { + public: + explicit HostPreferenceBackend(uint32_t key) { this->key_ = key; } + + bool save(const uint8_t *data, size_t len) override; + bool load(uint8_t *data, size_t len) override; + + protected: + uint32_t key_{}; +}; + +class HostPreferences : public ESPPreferences { + public: + bool sync() override; + bool reset() override; + + ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override; + ESPPreferenceObject make_preference(size_t length, uint32_t type) override { + return make_preference(length, type, false); + } + + bool save(uint32_t key, const uint8_t *data, size_t len) { + if (len > 255) + return false; + this->setup_(); + std::vector vec(data, data + len); + this->data[key] = vec; + return true; + } + + bool load(uint32_t key, uint8_t *data, size_t len) { + if (len > 255) + return false; + this->setup_(); + if (this->data.count(key) == 0) + return false; + auto vec = this->data[key]; + if (vec.size() != len) + return false; + memcpy(data, vec.data(), len); + return true; + } + + protected: + void setup_(); + bool setup_complete_{}; + std::string filename_{}; + std::map> data{}; +}; void setup_preferences(); +extern HostPreferences *host_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace host } // namespace esphome From f5ac1bd90598701cf579c22aaeb9b740e396cb67 Mon Sep 17 00:00:00 2001 From: ebw44 Date: Tue, 26 Mar 2024 11:20:15 +1300 Subject: [PATCH 1451/2607] microWakeWord: Fix model path joining (#6426) --- esphome/components/micro_wake_word/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 209a1412ca..9073d103f1 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -287,7 +287,7 @@ def _load_model_data(manifest_path: Path): except cv.Invalid as e: raise EsphomeError(f"Invalid manifest file: {e}") from e - model_path = urljoin(str(manifest_path), manifest[CONF_MODEL]) + model_path = manifest_path.parent / manifest[CONF_MODEL] with open(model_path, "rb") as f: model = f.read() From 7cb8f99884d6af18efd1b08e47634c488815f1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 25 Mar 2024 23:34:47 +0100 Subject: [PATCH 1452/2607] Don't compile strptime unless its required (#6424) --- esphome/core/time.cpp | 6 ++++++ esphome/core/time.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index 2e46a611e6..ae4fabac52 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -1,4 +1,6 @@ +#ifdef USE_DATETIME #include +#endif #include "helpers.h" #include "time.h" // NOLINT @@ -64,6 +66,8 @@ std::string ESPTime::strftime(const std::string &format) { return timestr; } +#ifdef USE_DATETIME + bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { // clang-format off std::regex dt_regex(R"(^ @@ -102,6 +106,8 @@ bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { return true; } +#endif + void ESPTime::increment_second() { this->timestamp++; if (!increment_time_value(this->second, 0, 60)) diff --git a/esphome/core/time.h b/esphome/core/time.h index 4300cf26b7..738a0261c7 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -67,6 +67,8 @@ struct ESPTime { this->day_of_year < 367 && this->month > 0 && this->month < 13; } +#ifdef USE_DATETIME + /** Convert a string to ESPTime struct as specified by the format argument. * @param time_to_parse null-terminated c string formatet like this: 2020-08-25 05:30:00. * @param esp_time an instance of a ESPTime struct @@ -74,6 +76,8 @@ struct ESPTime { */ static bool strptime(const std::string &time_to_parse, ESPTime &esp_time); +#endif + /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); From 2345e7606a1ef2d1ec89e36d487666e9be8b2496 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 25 Mar 2024 21:24:58 -1000 Subject: [PATCH 1453/2607] Fix editor live validation (#6431) --- esphome/config.py | 24 ++++++++++++----------- esphome/config_helpers.py | 24 ----------------------- esphome/vscode.py | 41 +++++++++++++++++++++++++++++++++------ esphome/yaml_util.py | 25 ++++++++++++++---------- 4 files changed, 63 insertions(+), 51 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index f5a1ebb8d7..c5764dd4f2 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -1,10 +1,11 @@ +from __future__ import annotations import abc import functools import heapq import logging import re -from typing import Optional, Union +from typing import Union, Any from contextlib import contextmanager import contextvars @@ -76,7 +77,7 @@ def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool: @functools.total_ordering class _ValidationStepTask: - def __init__(self, priority: float, id_number: int, step: "ConfigValidationStep"): + def __init__(self, priority: float, id_number: int, step: ConfigValidationStep): self.priority = priority self.id_number = id_number self.step = step @@ -130,7 +131,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): ) self.errors.append(error) - def add_validation_step(self, step: "ConfigValidationStep"): + def add_validation_step(self, step: ConfigValidationStep): id_num = self._validation_tasks_id self._validation_tasks_id += 1 heapq.heappush( @@ -172,7 +173,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): conf = conf[key] conf[path[-1]] = value - def get_error_for_path(self, path: ConfigPath) -> Optional[vol.Invalid]: + def get_error_for_path(self, path: ConfigPath) -> vol.Invalid | None: for err in self.errors: if self.get_deepest_path(err.path) == path: self.errors.remove(err) @@ -181,7 +182,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): def get_deepest_document_range_for_path( self, path: ConfigPath, get_key: bool = False - ) -> Optional[ESPHomeDataBase]: + ) -> ESPHomeDataBase | None: data = self doc_range = None for index, path_item in enumerate(path): @@ -733,7 +734,9 @@ class PinUseValidationCheck(ConfigValidationStep): pins.PIN_SCHEMA_REGISTRY.final_validate(result) -def validate_config(config, command_line_substitutions) -> Config: +def validate_config( + config: dict[str, Any], command_line_substitutions: dict[str, Any] +) -> Config: result = Config() loader.clear_component_meta_finders() @@ -897,24 +900,23 @@ class InvalidYAMLError(EsphomeError): self.base_exc = base_exc -def _load_config(command_line_substitutions): +def _load_config(command_line_substitutions: dict[str, Any]) -> Config: + """Load the configuration file.""" try: config = yaml_util.load_yaml(CORE.config_path) except EsphomeError as e: raise InvalidYAMLError(e) from e try: - result = validate_config(config, command_line_substitutions) + return validate_config(config, command_line_substitutions) except EsphomeError: raise except Exception: _LOGGER.error("Unexpected exception while reading configuration:") raise - return result - -def load_config(command_line_substitutions): +def load_config(command_line_substitutions: dict[str, Any]) -> Config: try: return _load_config(command_line_substitutions) except vol.Invalid as err: diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index ac52c6ede2..7b47e097c8 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -1,9 +1,4 @@ -import json -import os - from esphome.const import CONF_ID -from esphome.core import CORE -from esphome.helpers import read_file class Extend: @@ -38,25 +33,6 @@ class Remove: return isinstance(b, Remove) and self.value == b.value -def read_config_file(path: str) -> str: - if CORE.vscode and ( - not CORE.ace or os.path.abspath(path) == os.path.abspath(CORE.config_path) - ): - print( - json.dumps( - { - "type": "read_file", - "path": path, - } - ) - ) - data = json.loads(input()) - assert data["type"] == "file_response" - return data["content"] - - return read_file(path) - - def merge_config(full_old, full_new): def merge(old, new): if isinstance(new, dict): diff --git a/esphome/vscode.py b/esphome/vscode.py index cb2f51976f..8198d2659a 100644 --- a/esphome/vscode.py +++ b/esphome/vscode.py @@ -1,20 +1,22 @@ +from __future__ import annotations import json import os +from io import StringIO +from typing import Any -from typing import Optional - -from esphome.config import load_config, _format_vol_invalid, Config +from esphome.yaml_util import parse_yaml +from esphome.config import validate_config, _format_vol_invalid, Config from esphome.core import CORE, DocumentRange import esphome.config_validation as cv -def _get_invalid_range(res: Config, invalid: cv.Invalid) -> Optional[DocumentRange]: +def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None: return res.get_deepest_document_range_for_path( invalid.path, invalid.error_message == "extra keys not allowed" ) -def _dump_range(range: Optional[DocumentRange]) -> Optional[dict]: +def _dump_range(range: DocumentRange | None) -> dict | None: if range is None: return None return { @@ -56,6 +58,25 @@ class VSCodeResult: ) +def _read_file_content_from_json_on_stdin() -> str: + """Read the content of a json encoded file from stdin.""" + data = json.loads(input()) + assert data["type"] == "file_response" + return data["content"] + + +def _print_file_read_event(path: str) -> None: + """Print a file read event.""" + print( + json.dumps( + { + "type": "read_file", + "path": path, + } + ) + ) + + def read_config(args): while True: CORE.reset() @@ -68,9 +89,17 @@ def read_config(args): CORE.config_path = os.path.join(args.configuration, f) else: CORE.config_path = data["file"] + + file_name = CORE.config_path + _print_file_read_event(file_name) + raw_yaml = _read_file_content_from_json_on_stdin() + command_line_substitutions: dict[str, Any] = ( + dict(args.substitution) if args.substitution else {} + ) vs = VSCodeResult() try: - res = load_config(dict(args.substitution) if args.substitution else {}) + config = parse_yaml(file_name, StringIO(raw_yaml)) + res = validate_config(config, command_line_substitutions) except Exception as err: # pylint: disable=broad-except vs.add_yaml_error(str(err)) else: diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index 60705082b6..c7aa78201f 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -417,20 +417,25 @@ def load_yaml(fname: str, clear_secrets: bool = True) -> Any: return _load_yaml_internal(fname) +def parse_yaml(file_name: str, file_handle: TextIOWrapper) -> Any: + """Parse a YAML file.""" + try: + return _load_yaml_internal_with_type(ESPHomeLoader, file_name, file_handle) + except EsphomeError: + # Loading failed, so we now load with the Python loader which has more + # readable exceptions + # Rewind the stream so we can try again + file_handle.seek(0, 0) + return _load_yaml_internal_with_type( + ESPHomePurePythonLoader, file_name, file_handle + ) + + def _load_yaml_internal(fname: str) -> Any: """Load a YAML file.""" try: with open(fname, encoding="utf-8") as f_handle: - try: - return _load_yaml_internal_with_type(ESPHomeLoader, fname, f_handle) - except EsphomeError: - # Loading failed, so we now load with the Python loader which has more - # readable exceptions - # Rewind the stream so we can try again - f_handle.seek(0, 0) - return _load_yaml_internal_with_type( - ESPHomePurePythonLoader, fname, f_handle - ) + return parse_yaml(fname, f_handle) except (UnicodeDecodeError, OSError) as err: raise EsphomeError(f"Error reading file {fname}: {err}") from err From 952ccf554be11d4505db833c62186cfd8ae3eb1b Mon Sep 17 00:00:00 2001 From: X-Ryl669 Date: Tue, 26 Mar 2024 23:51:56 +0100 Subject: [PATCH 1454/2607] Add support for AT581x component (#6297) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/at581x/__init__.py | 224 ++++++++++++++++++ esphome/components/at581x/at581x.cpp | 195 +++++++++++++++ esphome/components/at581x/at581x.h | 62 +++++ esphome/components/at581x/automation.h | 71 ++++++ esphome/components/at581x/switch/__init__.py | 31 +++ .../components/at581x/switch/rf_switch.cpp | 12 + esphome/components/at581x/switch/rf_switch.h | 15 ++ .../components/at581x/test.esp32-c3-idf.yaml | 38 +++ tests/components/at581x/test.esp32-c3.yaml | 38 +++ tests/components/at581x/test.esp32-idf.yaml | 38 +++ tests/components/at581x/test.esp32.yaml | 38 +++ tests/components/at581x/test.esp8266.yaml | 38 +++ tests/components/at581x/test.rp2040.yaml | 38 +++ 14 files changed, 839 insertions(+) create mode 100644 esphome/components/at581x/__init__.py create mode 100644 esphome/components/at581x/at581x.cpp create mode 100644 esphome/components/at581x/at581x.h create mode 100644 esphome/components/at581x/automation.h create mode 100644 esphome/components/at581x/switch/__init__.py create mode 100644 esphome/components/at581x/switch/rf_switch.cpp create mode 100644 esphome/components/at581x/switch/rf_switch.h create mode 100644 tests/components/at581x/test.esp32-c3-idf.yaml create mode 100644 tests/components/at581x/test.esp32-c3.yaml create mode 100644 tests/components/at581x/test.esp32-idf.yaml create mode 100644 tests/components/at581x/test.esp32.yaml create mode 100644 tests/components/at581x/test.esp8266.yaml create mode 100644 tests/components/at581x/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 2c1b8f04ae..b924f55d0b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -42,6 +42,7 @@ esphome/components/as5600/* @ammmze esphome/components/as5600/sensor/* @ammmze esphome/components/as7341/* @mrgnr esphome/components/async_tcp/* @OttoWinter +esphome/components/at581x/* @X-Ryl669 esphome/components/atc_mithermometer/* @ahpohl esphome/components/atm90e26/* @danieltwagner esphome/components/b_parasite/* @rbaron diff --git a/esphome/components/at581x/__init__.py b/esphome/components/at581x/__init__.py new file mode 100644 index 0000000000..2860d21f6c --- /dev/null +++ b/esphome/components/at581x/__init__.py @@ -0,0 +1,224 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation, core +from esphome.components import i2c +from esphome.automation import maybe_simple_id +from esphome.const import ( + CONF_ID, + CONF_FREQUENCY, +) + + +CODEOWNERS = ["@X-Ryl669"] +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + + +at581x_ns = cg.esphome_ns.namespace("at581x") +AT581XComponent = at581x_ns.class_("AT581XComponent", cg.Component, i2c.I2CDevice) + + +CONF_AT581X_ID = "at581x_id" + + +CONF_SENSING_DISTANCE = "sensing_distance" +CONF_SENSITIVITY = "sensitivity" +CONF_POWERON_SELFCHECK_TIME = "poweron_selfcheck_time" +CONF_PROTECT_TIME = "protect_time" +CONF_TRIGGER_BASE = "trigger_base" +CONF_TRIGGER_KEEP = "trigger_keep" +CONF_STAGE_GAIN = "stage_gain" +CONF_POWER_CONSUMPTION = "power_consumption" +CONF_HW_FRONTEND_RESET = "hw_frontend_reset" + +RADAR_ALLOWED_FREQ = [ + 5696e6, + 5715e6, + 5730e6, + 5748e6, + 5765e6, + 5784e6, + 5800e6, + 5819e6, + 5836e6, + 5851e6, + 5869e6, + 5888e6, +] +RADAR_ALLOWED_CUR_CONSUMPTION = [ + 48e-6, + 56e-6, + 63e-6, + 70e-6, + 77e-6, + 91e-6, + 105e-6, + 115e-6, + 40e-6, + 44e-6, + 47e-6, + 51e-6, + 54e-6, + 61e-6, + 68e-6, + 78e-6, +] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(AT581XComponent), + } +) + +CONFIG_SCHEMA = cv.All( + CONFIG_SCHEMA.extend(i2c.i2c_device_schema(0x28)).extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +# Actions +AT581XResetAction = at581x_ns.class_("AT581XResetAction", automation.Action) +AT581XSettingsAction = at581x_ns.class_("AT581XSettingsAction", automation.Action) + + +@automation.register_action( + "at581x.reset", + AT581XResetAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(AT581XComponent), + } + ), +) +async def at581x_reset_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + return var + + +RADAR_SETTINGS_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(AT581XComponent), + cv.Optional(CONF_HW_FRONTEND_RESET): cv.templatable(cv.boolean), + cv.Optional(CONF_FREQUENCY, default="5800MHz"): cv.templatable( + cv.All(cv.frequency, cv.one_of(*RADAR_ALLOWED_FREQ)) + ), + cv.Optional(CONF_SENSING_DISTANCE, default=823): cv.templatable( + cv.int_range(min=0, max=1023) + ), + cv.Optional(CONF_POWERON_SELFCHECK_TIME, default="2000ms"): cv.templatable( + cv.All( + cv.positive_time_period_milliseconds, + cv.Range(max=core.TimePeriod(milliseconds=65535)), + ) + ), + cv.Optional(CONF_POWER_CONSUMPTION, default="70uA"): cv.templatable( + cv.All(cv.current, cv.one_of(*RADAR_ALLOWED_CUR_CONSUMPTION)) + ), + cv.Optional(CONF_PROTECT_TIME, default="1000ms"): cv.templatable( + cv.All( + cv.positive_time_period_milliseconds, + cv.Range( + min=core.TimePeriod(milliseconds=1), + max=core.TimePeriod(milliseconds=65535), + ), + ) + ), + cv.Optional(CONF_TRIGGER_BASE, default="500ms"): cv.templatable( + cv.All( + cv.positive_time_period_milliseconds, + cv.Range( + min=core.TimePeriod(milliseconds=1), + max=core.TimePeriod(milliseconds=65535), + ), + ) + ), + cv.Optional(CONF_TRIGGER_KEEP, default="1500ms"): cv.templatable( + cv.All( + cv.positive_time_period_milliseconds, + cv.Range( + min=core.TimePeriod(milliseconds=1), + max=core.TimePeriod(milliseconds=65535), + ), + ) + ), + cv.Optional(CONF_STAGE_GAIN, default=3): cv.templatable( + cv.int_range(min=0, max=12) + ), + } +).add_extra( + cv.has_at_least_one_key( + CONF_HW_FRONTEND_RESET, + CONF_FREQUENCY, + CONF_SENSING_DISTANCE, + ) +) + + +@automation.register_action( + "at581x.settings", + AT581XSettingsAction, + RADAR_SETTINGS_SCHEMA, +) +async def at581x_settings_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + # Radar configuration + if frontend_reset := config.get(CONF_HW_FRONTEND_RESET): + template_ = await cg.templatable(frontend_reset, args, int) + cg.add(var.set_hw_frontend_reset(template_)) + + if freq := config.get(CONF_FREQUENCY): + template_ = await cg.templatable(freq, args, float) + template_ = int(template_ / 1000000) + cg.add(var.set_frequency(template_)) + + if sens_dist := config.get(CONF_SENSING_DISTANCE): + template_ = await cg.templatable(sens_dist, args, int) + cg.add(var.set_sensing_distance(template_)) + + if selfcheck := config.get(CONF_POWERON_SELFCHECK_TIME): + template_ = await cg.templatable(selfcheck, args, float) + if isinstance(template_, cv.TimePeriod): + template_ = template_.total_milliseconds + template_ = int(template_) + cg.add(var.set_poweron_selfcheck_time(template_)) + + if protect := config.get(CONF_PROTECT_TIME): + template_ = await cg.templatable(protect, args, float) + if isinstance(template_, cv.TimePeriod): + template_ = template_.total_milliseconds + template_ = int(template_) + cg.add(var.set_protect_time(template_)) + + if trig_base := config.get(CONF_TRIGGER_BASE): + template_ = await cg.templatable(trig_base, args, float) + if isinstance(template_, cv.TimePeriod): + template_ = template_.total_milliseconds + template_ = int(template_) + cg.add(var.set_trigger_base(template_)) + + if trig_keep := config.get(CONF_TRIGGER_KEEP): + template_ = await cg.templatable(trig_keep, args, float) + if isinstance(template_, cv.TimePeriod): + template_ = template_.total_milliseconds + template_ = int(template_) + cg.add(var.set_trigger_keep(template_)) + + if stage_gain := config.get(CONF_STAGE_GAIN): + template_ = await cg.templatable(stage_gain, args, int) + cg.add(var.set_stage_gain(template_)) + + if power := config.get(CONF_POWER_CONSUMPTION): + template_ = await cg.templatable(power, args, float) + template_ = int(template_ * 1000000) + cg.add(var.set_power_consumption(template_)) + + return var diff --git a/esphome/components/at581x/at581x.cpp b/esphome/components/at581x/at581x.cpp new file mode 100644 index 0000000000..eef457f985 --- /dev/null +++ b/esphome/components/at581x/at581x.cpp @@ -0,0 +1,195 @@ +#include "at581x.h" +#include "esphome/core/log.h" + +/* Select gain for AT581X (3dB per step for level1, 6dB per step for level 2), high value = small gain. (p12) */ +const uint8_t GAIN_ADDR_TABLE[] = {0x5c, 0x63}; +const uint8_t GAIN5C_TABLE[] = {0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8}; +const uint8_t GAIN63_TABLE[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; +const uint8_t GAIN61_VALUE = 0xCA; // 0xC0 | 0x02 (freq present) | 0x08 (gain present) + +/*!< Power consumption configuration table (p12). */ +const uint8_t POWER_TABLE[] = {48, 56, 63, 70, 77, 91, 105, 115, 40, 44, 47, 51, 54, 61, 68, 78}; +const uint8_t POWER67_TABLE[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; +const uint8_t POWER68_TABLE[] = {0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 24, 24, 24, 24, 24, 24, 24, 24}; // See Page 12, shift by 3 bits + +/*!< Frequency Configuration table (p14/15 of datasheet). */ +const uint8_t FREQ_ADDR = 0x61; +const uint16_t FREQ_TABLE[] = {5696, 5715, 5730, 5748, 5765, 5784, 5800, 5819, 5836, 5851, 5869, 5888}; +const uint8_t FREQ5F_TABLE[] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x40, 0x41, 0x42, 0x43}; +const uint8_t FREQ60_TABLE[] = {0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e}; + +/*!< Value for RF and analog modules switch (p10). */ +const uint8_t RF_OFF_TABLE[] = {0x46, 0xaa, 0x50}; +const uint8_t RF_ON_TABLE[] = {0x45, 0x55, 0xA0}; +const uint8_t RF_REG_ADDR[] = {0x5d, 0x62, 0x51}; + +/*!< Registers of Lighting delay time. Unit: ms, min 2s (p8) */ +const uint8_t HIGH_LEVEL_DELAY_CONTROL_ADDR = 0x41; /*!< Time_flag_out_ctrl 0x01 */ +const uint8_t HIGH_LEVEL_DELAY_VALUE_ADDR = 0x42; /*!< Time_flag_out_1 Bit<7:0> */ + +const uint8_t RESET_ADDR = 0x00; + +/*!< Sensing distance address */ +const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_LO = 0x10; +const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_HI = 0x11; + +/*!< Bit field value for power registers */ +const uint8_t POWER_THRESHOLD_ADDR_HI = 0x68; +const uint8_t POWER_THRESHOLD_ADDR_LO = 0x67; +const uint8_t PWR_WORK_TIME_EN = 8; // Reg 0x67 +const uint8_t PWR_BURST_TIME_EN = 32; // Reg 0x68 +const uint8_t PWR_THRESH_EN = 64; // Reg 0x68 +const uint8_t PWR_THRESH_VAL_EN = 128; // Reg 0x67 + +/*!< Times */ +const uint8_t TRIGGER_BASE_TIME_ADDR = 0x3D; // 4 bytes, so up to 0x40 +const uint8_t PROTECT_TIME_ADDR = 0x4E; // 2 bytes, up to 0x4F +const uint8_t TRIGGER_KEEP_TIME_ADDR = 0x42; // 4 bytes, so up to 0x45 +const uint8_t TIME41_VALUE = 1; +const uint8_t SELF_CHECK_TIME_ADDR = 0x38; // 2 bytes, up to 0x39 + +namespace esphome { +namespace at581x { + +static const char *const TAG = "at581x"; + +bool AT581XComponent::i2c_write_reg(uint8_t addr, uint8_t data) { + return this->write_register(addr, &data, 1) == esphome::i2c::NO_ERROR; +} +bool AT581XComponent::i2c_write_reg(uint8_t addr, uint32_t data) { + return this->i2c_write_reg(addr + 0, uint8_t(data & 0xFF)) && + this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF)) && + this->i2c_write_reg(addr + 2, uint8_t((data >> 16) & 0xFF)) && + this->i2c_write_reg(addr + 3, uint8_t((data >> 24) & 0xFF)); +} +bool AT581XComponent::i2c_write_reg(uint8_t addr, uint16_t data) { + return this->i2c_write_reg(addr, uint8_t(data & 0xFF)) && this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF)); +} + +bool AT581XComponent::i2c_read_reg(uint8_t addr, uint8_t &data) { + return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR; +} + +void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up AT581X..."); } +void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); } +#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) +bool AT581XComponent::i2c_write_config() { + ESP_LOGCONFIG(TAG, "Writing new config for AT581X..."); + ESP_LOGCONFIG(TAG, "Frequency: %dMHz", this->freq_); + ESP_LOGCONFIG(TAG, "Sensing distance: %d", this->delta_); + ESP_LOGCONFIG(TAG, "Power: %dµA", this->power_); + ESP_LOGCONFIG(TAG, "Gain: %d", this->gain_); + ESP_LOGCONFIG(TAG, "Trigger base time: %dms", this->trigger_base_time_ms_); + ESP_LOGCONFIG(TAG, "Trigger keep time: %dms", this->trigger_keep_time_ms_); + ESP_LOGCONFIG(TAG, "Protect time: %dms", this->protect_time_ms_); + ESP_LOGCONFIG(TAG, "Self check time: %dms", this->self_check_time_ms_); + + // Set frequency point + if (!this->i2c_write_reg(FREQ_ADDR, GAIN61_VALUE)) { + ESP_LOGE(TAG, "Failed to write AT581X Freq mode"); + return false; + } + // Find the current frequency from the table to know what value to write + for (size_t i = 0; i < ARRAY_SIZE(FREQ_TABLE) + 1; i++) { + if (i == ARRAY_SIZE(FREQ_TABLE)) { + ESP_LOGE(TAG, "Set frequency not found"); + return false; + } + if (FREQ_TABLE[i] == this->freq_) { + if (!this->i2c_write_reg(0x5F, FREQ5F_TABLE[i]) || !this->i2c_write_reg(0x60, FREQ60_TABLE[i])) { + ESP_LOGE(TAG, "Failed to write AT581X Freq value"); + return false; + } + break; + } + } + + // Set distance + if (!this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_LO, (uint8_t) (this->delta_ & 0xFF)) || + !this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_HI, (uint8_t) (this->delta_ >> 8))) { + ESP_LOGE(TAG, "Failed to write AT581X sensing distance low"); + return false; + } + + // Set power setting + uint8_t pwr67 = PWR_THRESH_VAL_EN | PWR_WORK_TIME_EN, pwr68 = PWR_BURST_TIME_EN | PWR_THRESH_EN; + for (size_t i = 0; i < ARRAY_SIZE(POWER_TABLE) + 1; i++) { + if (i == ARRAY_SIZE(POWER_TABLE)) { + ESP_LOGE(TAG, "Set power not found"); + return false; + } + if (POWER_TABLE[i] == this->power_) { + pwr67 |= POWER67_TABLE[i]; + pwr68 |= POWER68_TABLE[i]; // See Page 12 + break; + } + } + + if (!this->i2c_write_reg(POWER_THRESHOLD_ADDR_LO, pwr67) || !this->i2c_write_reg(POWER_THRESHOLD_ADDR_HI, pwr68)) { + ESP_LOGE(TAG, "Failed to write AT581X power registers"); + return false; + } + + // Set gain + if (!this->i2c_write_reg(GAIN_ADDR_TABLE[0], GAIN5C_TABLE[this->gain_]) || + !this->i2c_write_reg(GAIN_ADDR_TABLE[1], GAIN63_TABLE[this->gain_ >> 1])) { + ESP_LOGE(TAG, "Failed to write AT581X gain registers"); + return false; + } + + // Set times + if (!this->i2c_write_reg(TRIGGER_BASE_TIME_ADDR, (uint32_t) this->trigger_base_time_ms_)) { + ESP_LOGE(TAG, "Failed to write AT581X trigger base time registers"); + return false; + } + if (!this->i2c_write_reg(TRIGGER_KEEP_TIME_ADDR, (uint32_t) this->trigger_keep_time_ms_)) { + ESP_LOGE(TAG, "Failed to write AT581X trigger keep time registers"); + return false; + } + + if (!this->i2c_write_reg(PROTECT_TIME_ADDR, (uint16_t) this->protect_time_ms_)) { + ESP_LOGE(TAG, "Failed to write AT581X protect time registers"); + return false; + } + if (!this->i2c_write_reg(SELF_CHECK_TIME_ADDR, (uint16_t) this->self_check_time_ms_)) { + ESP_LOGE(TAG, "Failed to write AT581X self check time registers"); + return false; + } + + if (!this->i2c_write_reg(0x41, TIME41_VALUE)) { + ESP_LOGE(TAG, "Failed to enable AT581X time registers"); + return false; + } + + // Don't know why it's required in other code, it's not in datasheet + if (!this->i2c_write_reg(0x55, (uint8_t) 0x04)) { + ESP_LOGE(TAG, "Failed to enable AT581X"); + return false; + } + + // Ok, config is written, let's reset the chip so it's using the new config + return this->reset_hardware_frontend(); +} + +// float AT581XComponent::get_setup_priority() const { return 0; } +bool AT581XComponent::reset_hardware_frontend() { + if (!this->i2c_write_reg(RESET_ADDR, (uint8_t) 0) || !this->i2c_write_reg(RESET_ADDR, (uint8_t) 1)) { + ESP_LOGE(TAG, "Failed to reset AT581X hardware frontend"); + return false; + } + return true; +} + +void AT581XComponent::set_rf_mode(bool enable) { + const uint8_t *p = enable ? &RF_ON_TABLE[0] : &RF_OFF_TABLE[0]; + for (size_t i = 0; i < ARRAY_SIZE(RF_REG_ADDR); i++) { + if (!this->i2c_write_reg(RF_REG_ADDR[i], p[i])) { + ESP_LOGE(TAG, "Failed to write AT581X RF mode"); + return; + } + } +} + +} // namespace at581x +} // namespace esphome diff --git a/esphome/components/at581x/at581x.h b/esphome/components/at581x/at581x.h new file mode 100644 index 0000000000..6c637d08c5 --- /dev/null +++ b/esphome/components/at581x/at581x.h @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/defines.h" +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace at581x { + +class AT581XComponent : public Component, public i2c::I2CDevice { +#ifdef USE_SWITCH + protected: + switch_::Switch *rf_power_switch_{nullptr}; + + public: + void set_rf_power_switch(switch_::Switch *s) { + this->rf_power_switch_ = s; + s->turn_on(); + } +#endif + + void setup() override; + void dump_config() override; + // float get_setup_priority() const override; + + void set_sensing_distance(int distance) { this->delta_ = 1023 - distance; } + + void set_rf_mode(bool enabled); + void set_frequency(int frequency) { this->freq_ = frequency; } + void set_poweron_selfcheck_time(int value) { this->self_check_time_ms_ = value; } + void set_protect_time(int value) { this->protect_time_ms_ = value; } + void set_trigger_base(int value) { this->trigger_base_time_ms_ = value; } + void set_trigger_keep(int value) { this->trigger_keep_time_ms_ = value; } + void set_stage_gain(int value) { this->gain_ = value; } + void set_power_consumption(int value) { this->power_ = value; } + + bool i2c_write_config(); + bool reset_hardware_frontend(); + bool i2c_write_reg(uint8_t addr, uint8_t data); + bool i2c_write_reg(uint8_t addr, uint32_t data); + bool i2c_write_reg(uint8_t addr, uint16_t data); + bool i2c_read_reg(uint8_t addr, uint8_t &data); + + protected: + int freq_; + int self_check_time_ms_; /*!< Power-on self-test time, range: 0 ~ 65536 ms */ + int protect_time_ms_; /*!< Protection time, recommended 1000 ms */ + int trigger_base_time_ms_; /*!< Default: 500 ms */ + int trigger_keep_time_ms_; /*!< Total trig time = TRIGGER_BASE_TIME + DEF_TRIGGER_KEEP_TIME, minimum: 1 */ + int delta_; /*!< Delta value: 0 ~ 1023, the larger the value, the shorter the distance */ + int gain_; /*!< Default: 9dB */ + int power_; /*!< In µA */ +}; + +} // namespace at581x +} // namespace esphome diff --git a/esphome/components/at581x/automation.h b/esphome/components/at581x/automation.h new file mode 100644 index 0000000000..4863a87565 --- /dev/null +++ b/esphome/components/at581x/automation.h @@ -0,0 +1,71 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" + +#include "at581x.h" + +namespace esphome { +namespace at581x { + +template class AT581XResetAction : public Action, public Parented { + public: + void play(Ts... x) { this->parent_->reset_hardware_frontend(); } +}; + +template class AT581XSettingsAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(int8_t, hw_frontend_reset) + TEMPLATABLE_VALUE(int, frequency) + TEMPLATABLE_VALUE(int, sensing_distance) + TEMPLATABLE_VALUE(int, poweron_selfcheck_time) + TEMPLATABLE_VALUE(int, power_consumption) + TEMPLATABLE_VALUE(int, protect_time) + TEMPLATABLE_VALUE(int, trigger_base) + TEMPLATABLE_VALUE(int, trigger_keep) + TEMPLATABLE_VALUE(int, stage_gain) + + void play(Ts... x) { + if (this->frequency_.has_value()) { + int v = this->frequency_.value(x...); + this->parent_->set_frequency(v); + } + if (this->sensing_distance_.has_value()) { + int v = this->sensing_distance_.value(x...); + this->parent_->set_sensing_distance(v); + } + if (this->poweron_selfcheck_time_.has_value()) { + int v = this->poweron_selfcheck_time_.value(x...); + this->parent_->set_poweron_selfcheck_time(v); + } + if (this->power_consumption_.has_value()) { + int v = this->power_consumption_.value(x...); + this->parent_->set_power_consumption(v); + } + if (this->protect_time_.has_value()) { + int v = this->protect_time_.value(x...); + this->parent_->set_protect_time(v); + } + if (this->trigger_base_.has_value()) { + int v = this->trigger_base_.value(x...); + this->parent_->set_trigger_base(v); + } + if (this->trigger_keep_.has_value()) { + int v = this->trigger_keep_.value(x...); + this->parent_->set_trigger_keep(v); + } + if (this->stage_gain_.has_value()) { + int v = this->stage_gain_.value(x...); + this->parent_->set_stage_gain(v); + } + + // This actually perform all the modification on the system + this->parent_->i2c_write_config(); + + if (this->hw_frontend_reset_.has_value() && this->hw_frontend_reset_.value(x...) == true) { + this->parent_->reset_hardware_frontend(); + } + } +}; +} // namespace at581x +} // namespace esphome diff --git a/esphome/components/at581x/switch/__init__.py b/esphome/components/at581x/switch/__init__.py new file mode 100644 index 0000000000..c441b381a3 --- /dev/null +++ b/esphome/components/at581x/switch/__init__.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_SWITCH, + ICON_WIFI, +) +from .. import CONF_AT581X_ID, AT581XComponent, at581x_ns + +DEPENDENCIES = ["at581x"] + +RFSwitch = at581x_ns.class_("RFSwitch", switch.Switch) + +CONFIG_SCHEMA = switch.switch_schema( + RFSwitch, + device_class=DEVICE_CLASS_SWITCH, + icon=ICON_WIFI, +).extend( + cv.Schema( + { + cv.GenerateID(CONF_AT581X_ID): cv.use_id(AT581XComponent), + } + ) +) + + +async def to_code(config): + at581x_component = await cg.get_variable(config[CONF_AT581X_ID]) + s = await switch.new_switch(config) + await cg.register_parented(s, config[CONF_AT581X_ID]) + cg.add(at581x_component.set_rf_power_switch(s)) diff --git a/esphome/components/at581x/switch/rf_switch.cpp b/esphome/components/at581x/switch/rf_switch.cpp new file mode 100644 index 0000000000..f1d03dc8a5 --- /dev/null +++ b/esphome/components/at581x/switch/rf_switch.cpp @@ -0,0 +1,12 @@ +#include "rf_switch.h" + +namespace esphome { +namespace at581x { + +void RFSwitch::write_state(bool state) { + this->publish_state(state); + this->parent_->set_rf_mode(state); +} + +} // namespace at581x +} // namespace esphome diff --git a/esphome/components/at581x/switch/rf_switch.h b/esphome/components/at581x/switch/rf_switch.h new file mode 100644 index 0000000000..920ddbb66a --- /dev/null +++ b/esphome/components/at581x/switch/rf_switch.h @@ -0,0 +1,15 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../at581x.h" + +namespace esphome { +namespace at581x { + +class RFSwitch : public switch_::Switch, public Parented { + protected: + void write_state(bool state) override; +}; + +} // namespace at581x +} // namespace esphome diff --git a/tests/components/at581x/test.esp32-c3-idf.yaml b/tests/components/at581x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b49a283eca --- /dev/null +++ b/tests/components/at581x/test.esp32-c3-idf.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 8 + scl: 9 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO21 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" diff --git a/tests/components/at581x/test.esp32-c3.yaml b/tests/components/at581x/test.esp32-c3.yaml new file mode 100644 index 0000000000..b49a283eca --- /dev/null +++ b/tests/components/at581x/test.esp32-c3.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 8 + scl: 9 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO21 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" diff --git a/tests/components/at581x/test.esp32-idf.yaml b/tests/components/at581x/test.esp32-idf.yaml new file mode 100644 index 0000000000..ff84e61e1e --- /dev/null +++ b/tests/components/at581x/test.esp32-idf.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 14 + scl: 15 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO21 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" diff --git a/tests/components/at581x/test.esp32.yaml b/tests/components/at581x/test.esp32.yaml new file mode 100644 index 0000000000..ff84e61e1e --- /dev/null +++ b/tests/components/at581x/test.esp32.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 14 + scl: 15 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO21 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" diff --git a/tests/components/at581x/test.esp8266.yaml b/tests/components/at581x/test.esp8266.yaml new file mode 100644 index 0000000000..a7b0069045 --- /dev/null +++ b/tests/components/at581x/test.esp8266.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 14 + scl: 15 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO4 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" diff --git a/tests/components/at581x/test.rp2040.yaml b/tests/components/at581x/test.rp2040.yaml new file mode 100644 index 0000000000..b49a283eca --- /dev/null +++ b/tests/components/at581x/test.rp2040.yaml @@ -0,0 +1,38 @@ +esphome: + on_boot: + then: + - at581x.settings: + id: "Waveradar" + hw_frontend_reset: false + frequency: 5800MHz + sensing_distance: 200 + poweron_selfcheck_time: 2s + protect_time: 1s + trigger_base: 500ms + trigger_keep: 10s + stage_gain: 3 + power_consumption: 70uA + - at581x.reset: + id: "Waveradar" + +at581x: + id: "Waveradar" + i2c_id: i2c_bus + +i2c: + sda: 8 + scl: 9 + scan: true + frequency: 100kHz + setup_priority: -100 + id: i2c_bus + +binary_sensor: + - platform: gpio + pin: GPIO21 + name: "Radar motion" + +switch: + - platform: at581x + at581x_id: "Waveradar" + name: "Enable Radar" From 37345e11ebd0a8f80754af8f08aff04d858d8354 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 25 Mar 2024 09:44:05 +1100 Subject: [PATCH 1455/2607] AHT10: Fix bug (#6409) --- esphome/components/aht10/aht10.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index d5af06c2a2..d2fad91cb5 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -42,19 +42,18 @@ void AHT10Component::setup() { } delay(AHT10_SOFTRESET_DELAY); - const uint8_t *init_cmd; + i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT; switch (this->variant_) { case AHT10Variant::AHT20: - init_cmd = AHT20_INITIALIZE_CMD; ESP_LOGCONFIG(TAG, "Setting up AHT20"); + error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD)); break; case AHT10Variant::AHT10: - default: - init_cmd = AHT10_INITIALIZE_CMD; ESP_LOGCONFIG(TAG, "Setting up AHT10"); + error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD)); + break; } - - if (this->write(init_cmd, sizeof(init_cmd)) != i2c::ERROR_OK) { + if (error_code != i2c::ERROR_OK) { ESP_LOGE(TAG, "Communication with AHT10 failed!"); this->mark_failed(); return; From 7abb82c1ca379575f379bfd99a2a6ddde9b3bd60 Mon Sep 17 00:00:00 2001 From: ebw44 Date: Tue, 26 Mar 2024 11:20:15 +1300 Subject: [PATCH 1456/2607] microWakeWord: Fix model path joining (#6426) --- esphome/components/micro_wake_word/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 209a1412ca..9073d103f1 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -287,7 +287,7 @@ def _load_model_data(manifest_path: Path): except cv.Invalid as e: raise EsphomeError(f"Invalid manifest file: {e}") from e - model_path = urljoin(str(manifest_path), manifest[CONF_MODEL]) + model_path = manifest_path.parent / manifest[CONF_MODEL] with open(model_path, "rb") as f: model = f.read() From d304e529408c816ef6c22ddcd9cc2305dc89d449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 25 Mar 2024 23:34:47 +0100 Subject: [PATCH 1457/2607] Don't compile strptime unless its required (#6424) --- esphome/core/time.cpp | 6 ++++++ esphome/core/time.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index 2e46a611e6..ae4fabac52 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -1,4 +1,6 @@ +#ifdef USE_DATETIME #include +#endif #include "helpers.h" #include "time.h" // NOLINT @@ -64,6 +66,8 @@ std::string ESPTime::strftime(const std::string &format) { return timestr; } +#ifdef USE_DATETIME + bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { // clang-format off std::regex dt_regex(R"(^ @@ -102,6 +106,8 @@ bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { return true; } +#endif + void ESPTime::increment_second() { this->timestamp++; if (!increment_time_value(this->second, 0, 60)) diff --git a/esphome/core/time.h b/esphome/core/time.h index 4300cf26b7..738a0261c7 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -67,6 +67,8 @@ struct ESPTime { this->day_of_year < 367 && this->month > 0 && this->month < 13; } +#ifdef USE_DATETIME + /** Convert a string to ESPTime struct as specified by the format argument. * @param time_to_parse null-terminated c string formatet like this: 2020-08-25 05:30:00. * @param esp_time an instance of a ESPTime struct @@ -74,6 +76,8 @@ struct ESPTime { */ static bool strptime(const std::string &time_to_parse, ESPTime &esp_time); +#endif + /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); From f00d8760807b9def3e837ccfa32d49faf73f9943 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 25 Mar 2024 21:24:58 -1000 Subject: [PATCH 1458/2607] Fix editor live validation (#6431) --- esphome/config.py | 24 ++++++++++++----------- esphome/config_helpers.py | 24 ----------------------- esphome/vscode.py | 41 +++++++++++++++++++++++++++++++++------ esphome/yaml_util.py | 25 ++++++++++++++---------- 4 files changed, 63 insertions(+), 51 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index f5a1ebb8d7..c5764dd4f2 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -1,10 +1,11 @@ +from __future__ import annotations import abc import functools import heapq import logging import re -from typing import Optional, Union +from typing import Union, Any from contextlib import contextmanager import contextvars @@ -76,7 +77,7 @@ def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool: @functools.total_ordering class _ValidationStepTask: - def __init__(self, priority: float, id_number: int, step: "ConfigValidationStep"): + def __init__(self, priority: float, id_number: int, step: ConfigValidationStep): self.priority = priority self.id_number = id_number self.step = step @@ -130,7 +131,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): ) self.errors.append(error) - def add_validation_step(self, step: "ConfigValidationStep"): + def add_validation_step(self, step: ConfigValidationStep): id_num = self._validation_tasks_id self._validation_tasks_id += 1 heapq.heappush( @@ -172,7 +173,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): conf = conf[key] conf[path[-1]] = value - def get_error_for_path(self, path: ConfigPath) -> Optional[vol.Invalid]: + def get_error_for_path(self, path: ConfigPath) -> vol.Invalid | None: for err in self.errors: if self.get_deepest_path(err.path) == path: self.errors.remove(err) @@ -181,7 +182,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): def get_deepest_document_range_for_path( self, path: ConfigPath, get_key: bool = False - ) -> Optional[ESPHomeDataBase]: + ) -> ESPHomeDataBase | None: data = self doc_range = None for index, path_item in enumerate(path): @@ -733,7 +734,9 @@ class PinUseValidationCheck(ConfigValidationStep): pins.PIN_SCHEMA_REGISTRY.final_validate(result) -def validate_config(config, command_line_substitutions) -> Config: +def validate_config( + config: dict[str, Any], command_line_substitutions: dict[str, Any] +) -> Config: result = Config() loader.clear_component_meta_finders() @@ -897,24 +900,23 @@ class InvalidYAMLError(EsphomeError): self.base_exc = base_exc -def _load_config(command_line_substitutions): +def _load_config(command_line_substitutions: dict[str, Any]) -> Config: + """Load the configuration file.""" try: config = yaml_util.load_yaml(CORE.config_path) except EsphomeError as e: raise InvalidYAMLError(e) from e try: - result = validate_config(config, command_line_substitutions) + return validate_config(config, command_line_substitutions) except EsphomeError: raise except Exception: _LOGGER.error("Unexpected exception while reading configuration:") raise - return result - -def load_config(command_line_substitutions): +def load_config(command_line_substitutions: dict[str, Any]) -> Config: try: return _load_config(command_line_substitutions) except vol.Invalid as err: diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index ac52c6ede2..7b47e097c8 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -1,9 +1,4 @@ -import json -import os - from esphome.const import CONF_ID -from esphome.core import CORE -from esphome.helpers import read_file class Extend: @@ -38,25 +33,6 @@ class Remove: return isinstance(b, Remove) and self.value == b.value -def read_config_file(path: str) -> str: - if CORE.vscode and ( - not CORE.ace or os.path.abspath(path) == os.path.abspath(CORE.config_path) - ): - print( - json.dumps( - { - "type": "read_file", - "path": path, - } - ) - ) - data = json.loads(input()) - assert data["type"] == "file_response" - return data["content"] - - return read_file(path) - - def merge_config(full_old, full_new): def merge(old, new): if isinstance(new, dict): diff --git a/esphome/vscode.py b/esphome/vscode.py index cb2f51976f..8198d2659a 100644 --- a/esphome/vscode.py +++ b/esphome/vscode.py @@ -1,20 +1,22 @@ +from __future__ import annotations import json import os +from io import StringIO +from typing import Any -from typing import Optional - -from esphome.config import load_config, _format_vol_invalid, Config +from esphome.yaml_util import parse_yaml +from esphome.config import validate_config, _format_vol_invalid, Config from esphome.core import CORE, DocumentRange import esphome.config_validation as cv -def _get_invalid_range(res: Config, invalid: cv.Invalid) -> Optional[DocumentRange]: +def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None: return res.get_deepest_document_range_for_path( invalid.path, invalid.error_message == "extra keys not allowed" ) -def _dump_range(range: Optional[DocumentRange]) -> Optional[dict]: +def _dump_range(range: DocumentRange | None) -> dict | None: if range is None: return None return { @@ -56,6 +58,25 @@ class VSCodeResult: ) +def _read_file_content_from_json_on_stdin() -> str: + """Read the content of a json encoded file from stdin.""" + data = json.loads(input()) + assert data["type"] == "file_response" + return data["content"] + + +def _print_file_read_event(path: str) -> None: + """Print a file read event.""" + print( + json.dumps( + { + "type": "read_file", + "path": path, + } + ) + ) + + def read_config(args): while True: CORE.reset() @@ -68,9 +89,17 @@ def read_config(args): CORE.config_path = os.path.join(args.configuration, f) else: CORE.config_path = data["file"] + + file_name = CORE.config_path + _print_file_read_event(file_name) + raw_yaml = _read_file_content_from_json_on_stdin() + command_line_substitutions: dict[str, Any] = ( + dict(args.substitution) if args.substitution else {} + ) vs = VSCodeResult() try: - res = load_config(dict(args.substitution) if args.substitution else {}) + config = parse_yaml(file_name, StringIO(raw_yaml)) + res = validate_config(config, command_line_substitutions) except Exception as err: # pylint: disable=broad-except vs.add_yaml_error(str(err)) else: diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index 60705082b6..c7aa78201f 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -417,20 +417,25 @@ def load_yaml(fname: str, clear_secrets: bool = True) -> Any: return _load_yaml_internal(fname) +def parse_yaml(file_name: str, file_handle: TextIOWrapper) -> Any: + """Parse a YAML file.""" + try: + return _load_yaml_internal_with_type(ESPHomeLoader, file_name, file_handle) + except EsphomeError: + # Loading failed, so we now load with the Python loader which has more + # readable exceptions + # Rewind the stream so we can try again + file_handle.seek(0, 0) + return _load_yaml_internal_with_type( + ESPHomePurePythonLoader, file_name, file_handle + ) + + def _load_yaml_internal(fname: str) -> Any: """Load a YAML file.""" try: with open(fname, encoding="utf-8") as f_handle: - try: - return _load_yaml_internal_with_type(ESPHomeLoader, fname, f_handle) - except EsphomeError: - # Loading failed, so we now load with the Python loader which has more - # readable exceptions - # Rewind the stream so we can try again - f_handle.seek(0, 0) - return _load_yaml_internal_with_type( - ESPHomePurePythonLoader, fname, f_handle - ) + return parse_yaml(fname, f_handle) except (UnicodeDecodeError, OSError) as err: raise EsphomeError(f"Error reading file {fname}: {err}") from err From 4d30c81b0b181b38f2d0079445c2499c63216c57 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:17:31 +1300 Subject: [PATCH 1459/2607] Bump version to 2024.3.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e386448462..b09d0a8eb0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.0" +__version__ = "2024.3.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 0948a3c30690f71f6a16c3e28f29edccb68872ba Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:06:57 -0500 Subject: [PATCH 1460/2607] Add some components to the new testing framework (F) (#6177) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../factory_reset/test.esp32-c3-idf.yaml | 3 + .../factory_reset/test.esp32-c3.yaml | 3 + .../factory_reset/test.esp32-idf.yaml | 3 + .../components/factory_reset/test.esp32.yaml | 3 + .../factory_reset/test.esp8266.yaml | 3 + .../components/factory_reset/test.rp2040.yaml | 3 + .../fastled_clockless/test.esp32.yaml | 71 +++++++++++++++++++ tests/components/fastled_spi/test.esp32.yaml | 71 +++++++++++++++++++ .../feedback/test.esp32-c3-idf.yaml | 39 ++++++++++ tests/components/feedback/test.esp32-c3.yaml | 39 ++++++++++ tests/components/feedback/test.esp32-idf.yaml | 39 ++++++++++ tests/components/feedback/test.esp32.yaml | 39 ++++++++++ tests/components/feedback/test.esp8266.yaml | 39 ++++++++++ tests/components/feedback/test.rp2040.yaml | 39 ++++++++++ .../fingerprint_grow/test.esp32-c3-idf.yaml | 56 +++++++++++++++ .../fingerprint_grow/test.esp32-c3.yaml | 56 +++++++++++++++ .../fingerprint_grow/test.esp32-idf.yaml | 56 +++++++++++++++ .../fingerprint_grow/test.esp32.yaml | 56 +++++++++++++++ .../fingerprint_grow/test.esp8266.yaml | 56 +++++++++++++++ .../fingerprint_grow/test.rp2040.yaml | 56 +++++++++++++++ tests/components/font/test.esp32-c3-idf.yaml | 19 +++++ tests/components/font/test.esp32-c3.yaml | 19 +++++ tests/components/font/test.esp32-idf.yaml | 19 +++++ tests/components/font/test.esp8266.yaml | 19 +++++ tests/components/font/test.rp2040.yaml | 19 +++++ .../components/fs3000/test.esp32-c3-idf.yaml | 10 +++ tests/components/fs3000/test.esp32-c3.yaml | 10 +++ tests/components/fs3000/test.esp32-idf.yaml | 10 +++ tests/components/fs3000/test.esp32.yaml | 10 +++ tests/components/fs3000/test.esp8266.yaml | 10 +++ tests/components/fs3000/test.rp2040.yaml | 10 +++ .../components/ft5x06/test.esp32-c3-idf.yaml | 21 ++++++ tests/components/ft5x06/test.esp32-c3.yaml | 21 ++++++ tests/components/ft5x06/test.esp32-idf.yaml | 21 ++++++ tests/components/ft5x06/test.esp32.yaml | 21 ++++++ tests/components/ft5x06/test.esp8266.yaml | 21 ++++++ tests/components/ft5x06/test.rp2040.yaml | 21 ++++++ .../components/ft63x6/test.esp32-c3-idf.yaml | 21 ++++++ tests/components/ft63x6/test.esp32-c3.yaml | 21 ++++++ tests/components/ft63x6/test.esp32-idf.yaml | 21 ++++++ tests/components/ft63x6/test.esp8266.yaml | 21 ++++++ tests/components/ft63x6/test.rp2040.yaml | 21 ++++++ .../fujitsu_general/test.esp32-c3-idf.yaml | 7 ++ .../fujitsu_general/test.esp32-c3.yaml | 7 ++ .../fujitsu_general/test.esp32-idf.yaml | 7 ++ .../fujitsu_general/test.esp32.yaml | 7 ++ .../fujitsu_general/test.esp8266.yaml | 7 ++ 47 files changed, 1151 insertions(+) create mode 100644 tests/components/factory_reset/test.esp32-c3-idf.yaml create mode 100644 tests/components/factory_reset/test.esp32-c3.yaml create mode 100644 tests/components/factory_reset/test.esp32-idf.yaml create mode 100644 tests/components/factory_reset/test.esp32.yaml create mode 100644 tests/components/factory_reset/test.esp8266.yaml create mode 100644 tests/components/factory_reset/test.rp2040.yaml create mode 100644 tests/components/fastled_clockless/test.esp32.yaml create mode 100644 tests/components/fastled_spi/test.esp32.yaml create mode 100644 tests/components/feedback/test.esp32-c3-idf.yaml create mode 100644 tests/components/feedback/test.esp32-c3.yaml create mode 100644 tests/components/feedback/test.esp32-idf.yaml create mode 100644 tests/components/feedback/test.esp32.yaml create mode 100644 tests/components/feedback/test.esp8266.yaml create mode 100644 tests/components/feedback/test.rp2040.yaml create mode 100644 tests/components/fingerprint_grow/test.esp32-c3-idf.yaml create mode 100644 tests/components/fingerprint_grow/test.esp32-c3.yaml create mode 100644 tests/components/fingerprint_grow/test.esp32-idf.yaml create mode 100644 tests/components/fingerprint_grow/test.esp32.yaml create mode 100644 tests/components/fingerprint_grow/test.esp8266.yaml create mode 100644 tests/components/fingerprint_grow/test.rp2040.yaml create mode 100644 tests/components/font/test.esp32-c3-idf.yaml create mode 100644 tests/components/font/test.esp32-c3.yaml create mode 100644 tests/components/font/test.esp32-idf.yaml create mode 100644 tests/components/font/test.esp8266.yaml create mode 100644 tests/components/font/test.rp2040.yaml create mode 100644 tests/components/fs3000/test.esp32-c3-idf.yaml create mode 100644 tests/components/fs3000/test.esp32-c3.yaml create mode 100644 tests/components/fs3000/test.esp32-idf.yaml create mode 100644 tests/components/fs3000/test.esp32.yaml create mode 100644 tests/components/fs3000/test.esp8266.yaml create mode 100644 tests/components/fs3000/test.rp2040.yaml create mode 100644 tests/components/ft5x06/test.esp32-c3-idf.yaml create mode 100644 tests/components/ft5x06/test.esp32-c3.yaml create mode 100644 tests/components/ft5x06/test.esp32-idf.yaml create mode 100644 tests/components/ft5x06/test.esp32.yaml create mode 100644 tests/components/ft5x06/test.esp8266.yaml create mode 100644 tests/components/ft5x06/test.rp2040.yaml create mode 100644 tests/components/ft63x6/test.esp32-c3-idf.yaml create mode 100644 tests/components/ft63x6/test.esp32-c3.yaml create mode 100644 tests/components/ft63x6/test.esp32-idf.yaml create mode 100644 tests/components/ft63x6/test.esp8266.yaml create mode 100644 tests/components/ft63x6/test.rp2040.yaml create mode 100644 tests/components/fujitsu_general/test.esp32-c3-idf.yaml create mode 100644 tests/components/fujitsu_general/test.esp32-c3.yaml create mode 100644 tests/components/fujitsu_general/test.esp32-idf.yaml create mode 100644 tests/components/fujitsu_general/test.esp32.yaml create mode 100644 tests/components/fujitsu_general/test.esp8266.yaml diff --git a/tests/components/factory_reset/test.esp32-c3-idf.yaml b/tests/components/factory_reset/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.esp32-c3.yaml b/tests/components/factory_reset/test.esp32-c3.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.esp32-idf.yaml b/tests/components/factory_reset/test.esp32-idf.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.esp32.yaml b/tests/components/factory_reset/test.esp32.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.esp32.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.esp8266.yaml b/tests/components/factory_reset/test.esp8266.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.esp8266.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.rp2040.yaml b/tests/components/factory_reset/test.rp2040.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/test.rp2040.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/fastled_clockless/test.esp32.yaml b/tests/components/fastled_clockless/test.esp32.yaml new file mode 100644 index 0000000000..8b1447a17a --- /dev/null +++ b/tests/components/fastled_clockless/test.esp32.yaml @@ -0,0 +1,71 @@ +light: + - platform: fastled_clockless + id: addr1 + chipset: WS2811 + pin: 13 + num_leds: 100 + rgb_order: BRG + max_refresh_rate: 20ms + color_correct: [75%, 100%, 50%] + name: FastLED WS2811 Light + effects: + - addressable_color_wipe: + - addressable_color_wipe: + name: Color Wipe Effect With Custom Values + colors: + - red: 100% + green: 100% + blue: 100% + num_leds: 1 + - red: 0% + green: 0% + blue: 0% + num_leds: 1 + add_led_interval: 100ms + reverse: false + - addressable_scan: + - addressable_scan: + name: Scan Effect With Custom Values + move_interval: 100ms + - addressable_twinkle: + - addressable_twinkle: + name: Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 4ms + - addressable_random_twinkle: + - addressable_random_twinkle: + name: Random Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 32ms + - addressable_fireworks: + - addressable_fireworks: + name: Fireworks Effect With Custom Values + update_interval: 32ms + spark_probability: 10% + use_random_color: false + fade_out_rate: 120 + - addressable_flicker: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + - addressable_lambda: + name: Test For Custom Lambda Effect + lambda: |- + if (initial_run) { + it[0] = current_color; + } + - automation: + name: Custom Effect + sequence: + - light.addressable_set: + id: addr1 + red: 100% + green: 100% + blue: 0% + - delay: 100ms + - light.addressable_set: + id: addr1 + red: 0% + green: 100% + blue: 0% diff --git a/tests/components/fastled_spi/test.esp32.yaml b/tests/components/fastled_spi/test.esp32.yaml new file mode 100644 index 0000000000..f6f7c5553b --- /dev/null +++ b/tests/components/fastled_spi/test.esp32.yaml @@ -0,0 +1,71 @@ +light: + - platform: fastled_spi + id: addr1 + chipset: WS2801 + clock_pin: 22 + data_pin: 23 + data_rate: 2MHz + num_leds: 60 + rgb_order: BRG + name: FastLED SPI Light + effects: + - addressable_color_wipe: + - addressable_color_wipe: + name: Color Wipe Effect With Custom Values + colors: + - red: 100% + green: 100% + blue: 100% + num_leds: 1 + - red: 0% + green: 0% + blue: 0% + num_leds: 1 + add_led_interval: 100ms + reverse: false + - addressable_scan: + - addressable_scan: + name: Scan Effect With Custom Values + move_interval: 100ms + - addressable_twinkle: + - addressable_twinkle: + name: Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 4ms + - addressable_random_twinkle: + - addressable_random_twinkle: + name: Random Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 32ms + - addressable_fireworks: + - addressable_fireworks: + name: Fireworks Effect With Custom Values + update_interval: 32ms + spark_probability: 10% + use_random_color: false + fade_out_rate: 120 + - addressable_flicker: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + - addressable_lambda: + name: Test For Custom Lambda Effect + lambda: |- + if (initial_run) { + it[0] = current_color; + } + - automation: + name: Custom Effect + sequence: + - light.addressable_set: + id: addr1 + red: 100% + green: 100% + blue: 0% + - delay: 100ms + - light.addressable_set: + id: addr1 + red: 0% + green: 100% + blue: 0% diff --git a/tests/components/feedback/test.esp32-c3-idf.yaml b/tests/components/feedback/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.esp32-c3-idf.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.esp32-c3.yaml b/tests/components/feedback/test.esp32-c3.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.esp32-c3.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.esp32-idf.yaml b/tests/components/feedback/test.esp32-idf.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.esp32-idf.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.esp32.yaml b/tests/components/feedback/test.esp32.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.esp32.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.esp8266.yaml b/tests/components/feedback/test.esp8266.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.esp8266.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.rp2040.yaml b/tests/components/feedback/test.rp2040.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/test.rp2040.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/fingerprint_grow/test.esp32-c3-idf.yaml b/tests/components/fingerprint_grow/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e7ac08eb28 --- /dev/null +++ b/tests/components/fingerprint_grow/test.esp32-c3-idf.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 4 + rx_pin: 5 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 6 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/fingerprint_grow/test.esp32-c3.yaml b/tests/components/fingerprint_grow/test.esp32-c3.yaml new file mode 100644 index 0000000000..e7ac08eb28 --- /dev/null +++ b/tests/components/fingerprint_grow/test.esp32-c3.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 4 + rx_pin: 5 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 6 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/fingerprint_grow/test.esp32-idf.yaml b/tests/components/fingerprint_grow/test.esp32-idf.yaml new file mode 100644 index 0000000000..0950145a05 --- /dev/null +++ b/tests/components/fingerprint_grow/test.esp32-idf.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 17 + rx_pin: 16 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 18 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/fingerprint_grow/test.esp32.yaml b/tests/components/fingerprint_grow/test.esp32.yaml new file mode 100644 index 0000000000..0950145a05 --- /dev/null +++ b/tests/components/fingerprint_grow/test.esp32.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 17 + rx_pin: 16 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 18 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/fingerprint_grow/test.esp8266.yaml b/tests/components/fingerprint_grow/test.esp8266.yaml new file mode 100644 index 0000000000..1d00d977b9 --- /dev/null +++ b/tests/components/fingerprint_grow/test.esp8266.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 4 + rx_pin: 5 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 16 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/fingerprint_grow/test.rp2040.yaml b/tests/components/fingerprint_grow/test.rp2040.yaml new file mode 100644 index 0000000000..e7ac08eb28 --- /dev/null +++ b/tests/components/fingerprint_grow/test.rp2040.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - fingerprint_grow.enroll: + finger_id: 2 + num_scans: 2 + - fingerprint_grow.cancel_enroll: + - fingerprint_grow.delete: + finger_id: 2 + - fingerprint_grow.delete_all: + +uart: + - id: uart_fingerprint_grow + tx_pin: 4 + rx_pin: 5 + baud_rate: 57600 + +fingerprint_grow: + sensing_pin: 6 + password: 0x12FE37DC + new_password: 0xA65B9840 + on_finger_scan_start: + - logger.log: test_fingerprint_grow_finger_scan_start + on_finger_scan_invalid: + - logger.log: test_fingerprint_grow_finger_scan_invalid + on_finger_scan_matched: + - logger.log: test_fingerprint_grow_finger_scan_matched + on_finger_scan_unmatched: + - logger.log: test_fingerprint_grow_finger_scan_unmatched + on_finger_scan_misplaced: + - logger.log: test_fingerprint_grow_finger_scan_misplaced + on_enrollment_scan: + - logger.log: test_fingerprint_grow_enrollment_scan + on_enrollment_done: + - logger.log: test_fingerprint_grow_node_enrollment_done + on_enrollment_failed: + - logger.log: test_fingerprint_grow_enrollment_failed + +binary_sensor: + - platform: fingerprint_grow + name: Fingerprint Enrolling + +sensor: + - platform: fingerprint_grow + fingerprint_count: + name: Fingerprint Count + status: + name: Fingerprint Status + capacity: + name: Fingerprint Capacity + security_level: + name: Fingerprint Security Level + last_finger_id: + name: Fingerprint Last Finger ID + last_confidence: + name: Fingerprint Last Confidence diff --git a/tests/components/font/test.esp32-c3-idf.yaml b/tests/components/font/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b63b4d025a --- /dev/null +++ b/tests/components/font/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_font + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 diff --git a/tests/components/font/test.esp32-c3.yaml b/tests/components/font/test.esp32-c3.yaml new file mode 100644 index 0000000000..b63b4d025a --- /dev/null +++ b/tests/components/font/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_font + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 diff --git a/tests/components/font/test.esp32-idf.yaml b/tests/components/font/test.esp32-idf.yaml new file mode 100644 index 0000000000..dcf8fb49d5 --- /dev/null +++ b/tests/components/font/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_font + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 diff --git a/tests/components/font/test.esp8266.yaml b/tests/components/font/test.esp8266.yaml new file mode 100644 index 0000000000..b63b4d025a --- /dev/null +++ b/tests/components/font/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_font + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 diff --git a/tests/components/font/test.rp2040.yaml b/tests/components/font/test.rp2040.yaml new file mode 100644 index 0000000000..b63b4d025a --- /dev/null +++ b/tests/components/font/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_font + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 diff --git a/tests/components/fs3000/test.esp32-c3-idf.yaml b/tests/components/fs3000/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..69de83b463 --- /dev/null +++ b/tests/components/fs3000/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 5 + sda: 4 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/fs3000/test.esp32-c3.yaml b/tests/components/fs3000/test.esp32-c3.yaml new file mode 100644 index 0000000000..69de83b463 --- /dev/null +++ b/tests/components/fs3000/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 5 + sda: 4 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/fs3000/test.esp32-idf.yaml b/tests/components/fs3000/test.esp32-idf.yaml new file mode 100644 index 0000000000..53b49cc9a2 --- /dev/null +++ b/tests/components/fs3000/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 16 + sda: 17 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/fs3000/test.esp32.yaml b/tests/components/fs3000/test.esp32.yaml new file mode 100644 index 0000000000..53b49cc9a2 --- /dev/null +++ b/tests/components/fs3000/test.esp32.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 16 + sda: 17 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/fs3000/test.esp8266.yaml b/tests/components/fs3000/test.esp8266.yaml new file mode 100644 index 0000000000..69de83b463 --- /dev/null +++ b/tests/components/fs3000/test.esp8266.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 5 + sda: 4 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/fs3000/test.rp2040.yaml b/tests/components/fs3000/test.rp2040.yaml new file mode 100644 index 0000000000..69de83b463 --- /dev/null +++ b/tests/components/fs3000/test.rp2040.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_fs3000 + scl: 5 + sda: 4 + +sensor: + - platform: fs3000 + name: Air Velocity + model: 1005 + update_interval: 60s diff --git a/tests/components/ft5x06/test.esp32-c3-idf.yaml b/tests/components/ft5x06/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4fa9532f53 --- /dev/null +++ b/tests/components/ft5x06/test.esp32-c3-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft5x06/test.esp32-c3.yaml b/tests/components/ft5x06/test.esp32-c3.yaml new file mode 100644 index 0000000000..4fa9532f53 --- /dev/null +++ b/tests/components/ft5x06/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft5x06/test.esp32-idf.yaml b/tests/components/ft5x06/test.esp32-idf.yaml new file mode 100644 index 0000000000..648929896d --- /dev/null +++ b/tests/components/ft5x06/test.esp32-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 18 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft5x06/test.esp32.yaml b/tests/components/ft5x06/test.esp32.yaml new file mode 100644 index 0000000000..648929896d --- /dev/null +++ b/tests/components/ft5x06/test.esp32.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 18 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft5x06/test.esp8266.yaml b/tests/components/ft5x06/test.esp8266.yaml new file mode 100644 index 0000000000..4fa9532f53 --- /dev/null +++ b/tests/components/ft5x06/test.esp8266.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft5x06/test.rp2040.yaml b/tests/components/ft5x06/test.rp2040.yaml new file mode 100644 index 0000000000..4fa9532f53 --- /dev/null +++ b/tests/components/ft5x06/test.rp2040.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft5x06 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft5x06 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft63x6/test.esp32-c3-idf.yaml b/tests/components/ft63x6/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..19ca4cfc19 --- /dev/null +++ b/tests/components/ft63x6/test.esp32-c3-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft63x6 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft63x6 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft63x6/test.esp32-c3.yaml b/tests/components/ft63x6/test.esp32-c3.yaml new file mode 100644 index 0000000000..19ca4cfc19 --- /dev/null +++ b/tests/components/ft63x6/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft63x6 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft63x6 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft63x6/test.esp32-idf.yaml b/tests/components/ft63x6/test.esp32-idf.yaml new file mode 100644 index 0000000000..5ceb107e31 --- /dev/null +++ b/tests/components/ft63x6/test.esp32-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft63x6 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 18 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft63x6 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft63x6/test.esp8266.yaml b/tests/components/ft63x6/test.esp8266.yaml new file mode 100644 index 0000000000..19ca4cfc19 --- /dev/null +++ b/tests/components/ft63x6/test.esp8266.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft63x6 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft63x6 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/ft63x6/test.rp2040.yaml b/tests/components/ft63x6/test.rp2040.yaml new file mode 100644 index 0000000000..19ca4cfc19 --- /dev/null +++ b/tests/components/ft63x6/test.rp2040.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_ft63x6 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: ft63x6 + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/fujitsu_general/test.esp32-c3-idf.yaml b/tests/components/fujitsu_general/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b4146f2a18 --- /dev/null +++ b/tests/components/fujitsu_general/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: fujitsu_general + name: Fujitsu General Climate diff --git a/tests/components/fujitsu_general/test.esp32-c3.yaml b/tests/components/fujitsu_general/test.esp32-c3.yaml new file mode 100644 index 0000000000..b4146f2a18 --- /dev/null +++ b/tests/components/fujitsu_general/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: fujitsu_general + name: Fujitsu General Climate diff --git a/tests/components/fujitsu_general/test.esp32-idf.yaml b/tests/components/fujitsu_general/test.esp32-idf.yaml new file mode 100644 index 0000000000..b4146f2a18 --- /dev/null +++ b/tests/components/fujitsu_general/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: fujitsu_general + name: Fujitsu General Climate diff --git a/tests/components/fujitsu_general/test.esp32.yaml b/tests/components/fujitsu_general/test.esp32.yaml new file mode 100644 index 0000000000..b4146f2a18 --- /dev/null +++ b/tests/components/fujitsu_general/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: fujitsu_general + name: Fujitsu General Climate diff --git a/tests/components/fujitsu_general/test.esp8266.yaml b/tests/components/fujitsu_general/test.esp8266.yaml new file mode 100644 index 0000000000..2a05bdde6b --- /dev/null +++ b/tests/components/fujitsu_general/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: fujitsu_general + name: Fujitsu General Climate From 58de8a4ee6cea6df248a904bde7e4a6dcf041a70 Mon Sep 17 00:00:00 2001 From: Ben Kristinsson Date: Wed, 27 Mar 2024 02:13:41 +0100 Subject: [PATCH 1461/2607] Add get_contrast() and get_brightness() to SSD1306 class to get protected variables (#6435) --- esphome/components/ssd1306_base/ssd1306_base.cpp | 2 ++ esphome/components/ssd1306_base/ssd1306_base.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esphome/components/ssd1306_base/ssd1306_base.cpp b/esphome/components/ssd1306_base/ssd1306_base.cpp index 749c3511c1..90b805a79f 100644 --- a/esphome/components/ssd1306_base/ssd1306_base.cpp +++ b/esphome/components/ssd1306_base/ssd1306_base.cpp @@ -236,6 +236,7 @@ void SSD1306::set_invert(bool invert) { // Inverse display mode (0xA6, 0xA7) this->command(SSD1306_COMMAND_NORMAL_DISPLAY | this->invert_); } +float SSD1306::get_contrast() { return this->contrast_; }; void SSD1306::set_contrast(float contrast) { // validation this->contrast_ = clamp(contrast, 0.0F, 1.0F); @@ -243,6 +244,7 @@ void SSD1306::set_contrast(float contrast) { this->command(SSD1306_COMMAND_SET_CONTRAST); this->command(int(SSD1306_MAX_CONTRAST * (this->contrast_))); } +float SSD1306::get_brightness() { return this->brightness_; }; void SSD1306::set_brightness(float brightness) { // validation if (!this->is_ssd1305_()) diff --git a/esphome/components/ssd1306_base/ssd1306_base.h b/esphome/components/ssd1306_base/ssd1306_base.h index 2e09755863..14ec309ae0 100644 --- a/esphome/components/ssd1306_base/ssd1306_base.h +++ b/esphome/components/ssd1306_base/ssd1306_base.h @@ -36,7 +36,9 @@ class SSD1306 : public display::DisplayBuffer { void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_external_vcc(bool external_vcc) { this->external_vcc_ = external_vcc; } void init_contrast(float contrast) { this->contrast_ = contrast; } + float get_contrast(); void set_contrast(float contrast); + float get_brightness(); void init_brightness(float brightness) { this->brightness_ = brightness; } void set_brightness(float brightness); void init_flip_x(bool flip_x) { this->flip_x_ = flip_x; } From 94e9476838368cb3b896fc58fe8bcb70ff6177cf Mon Sep 17 00:00:00 2001 From: Mafus1 Date: Wed, 27 Mar 2024 02:14:23 +0100 Subject: [PATCH 1462/2607] Add new Component: Ultrasonic Distance Sensor JSN-SR04T (#6023) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/jsn_sr04t/__init__.py | 1 + esphome/components/jsn_sr04t/jsn_sr04t.cpp | 58 +++++++++++++++++++ esphome/components/jsn_sr04t/jsn_sr04t.h | 28 +++++++++ esphome/components/jsn_sr04t/sensor.py | 44 ++++++++++++++ .../jsn_sr04t/test.esp32-c3-idf.yaml | 14 +++++ tests/components/jsn_sr04t/test.esp32-c3.yaml | 14 +++++ .../components/jsn_sr04t/test.esp32-idf.yaml | 14 +++++ tests/components/jsn_sr04t/test.esp32.yaml | 14 +++++ tests/components/jsn_sr04t/test.esp8266.yaml | 14 +++++ tests/components/jsn_sr04t/test.rp2040.yaml | 14 +++++ 11 files changed, 216 insertions(+) create mode 100644 esphome/components/jsn_sr04t/__init__.py create mode 100644 esphome/components/jsn_sr04t/jsn_sr04t.cpp create mode 100644 esphome/components/jsn_sr04t/jsn_sr04t.h create mode 100644 esphome/components/jsn_sr04t/sensor.py create mode 100644 tests/components/jsn_sr04t/test.esp32-c3-idf.yaml create mode 100644 tests/components/jsn_sr04t/test.esp32-c3.yaml create mode 100644 tests/components/jsn_sr04t/test.esp32-idf.yaml create mode 100644 tests/components/jsn_sr04t/test.esp32.yaml create mode 100644 tests/components/jsn_sr04t/test.esp8266.yaml create mode 100644 tests/components/jsn_sr04t/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index b924f55d0b..d6ec3843a5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -173,6 +173,7 @@ esphome/components/inkplate6/* @jesserockz esphome/components/integration/* @OttoWinter esphome/components/internal_temperature/* @Mat931 esphome/components/interval/* @esphome/core +esphome/components/jsn_sr04t/* @Mafus1 esphome/components/json/* @OttoWinter esphome/components/kamstrup_kmp/* @cfeenstra1024 esphome/components/key_collector/* @ssieb diff --git a/esphome/components/jsn_sr04t/__init__.py b/esphome/components/jsn_sr04t/__init__.py new file mode 100644 index 0000000000..ef6335f316 --- /dev/null +++ b/esphome/components/jsn_sr04t/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@Mafus1"] diff --git a/esphome/components/jsn_sr04t/jsn_sr04t.cpp b/esphome/components/jsn_sr04t/jsn_sr04t.cpp new file mode 100644 index 0000000000..70e21a137d --- /dev/null +++ b/esphome/components/jsn_sr04t/jsn_sr04t.cpp @@ -0,0 +1,58 @@ +#include "jsn_sr04t.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#include + +// Very basic support for JSN_SR04T V3.0 distance sensor in mode 2 + +namespace esphome { +namespace jsn_sr04t { + +static const char *const TAG = "jsn_sr04t.sensor"; + +void Jsnsr04tComponent::update() { + this->write_byte(0x55); + ESP_LOGV(TAG, "Request read out from sensor"); +} + +void Jsnsr04tComponent::loop() { + while (this->available() > 0) { + uint8_t data; + this->read_byte(&data); + + ESP_LOGV(TAG, "Read byte from sensor: %x", data); + + if (this->buffer_.empty() && data != 0xFF) + continue; + + this->buffer_.push_back(data); + if (this->buffer_.size() == 4) + this->check_buffer_(); + } +} + +void Jsnsr04tComponent::check_buffer_() { + uint8_t checksum = this->buffer_[0] + this->buffer_[1] + this->buffer_[2]; + if (this->buffer_[3] == checksum) { + uint16_t distance = encode_uint16(this->buffer_[1], this->buffer_[2]); + if (distance > 250) { + float meters = distance / 1000.0f; + ESP_LOGV(TAG, "Distance from sensor: %" PRIu32 "mm, %.3fm", distance, meters); + this->publish_state(meters); + } else { + ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str()); + } + } else { + ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]); + } + this->buffer_.clear(); +} + +void Jsnsr04tComponent::dump_config() { + LOG_SENSOR("", "JST_SR04T Sensor", this); + LOG_UPDATE_INTERVAL(this); +} + +} // namespace jsn_sr04t +} // namespace esphome diff --git a/esphome/components/jsn_sr04t/jsn_sr04t.h b/esphome/components/jsn_sr04t/jsn_sr04t.h new file mode 100644 index 0000000000..bd43252be8 --- /dev/null +++ b/esphome/components/jsn_sr04t/jsn_sr04t.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" + +namespace esphome { +namespace jsn_sr04t { + +class Jsnsr04tComponent : public sensor::Sensor, public PollingComponent, public uart::UARTDevice { + public: + // Nothing really public. + + // ========== INTERNAL METHODS ========== + void update() override; + void loop() override; + void dump_config() override; + + protected: + void check_buffer_(); + + std::vector buffer_; +}; + +} // namespace jsn_sr04t +} // namespace esphome diff --git a/esphome/components/jsn_sr04t/sensor.py b/esphome/components/jsn_sr04t/sensor.py new file mode 100644 index 0000000000..4b062e81e9 --- /dev/null +++ b/esphome/components/jsn_sr04t/sensor.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, uart +from esphome.const import ( + STATE_CLASS_MEASUREMENT, + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, +) + +CODEOWNERS = ["@Mafus1"] +DEPENDENCIES = ["uart"] + +jsn_sr04t_ns = cg.esphome_ns.namespace("jsn_sr04t") +Jsnsr04tComponent = jsn_sr04t_ns.class_( + "Jsnsr04tComponent", sensor.Sensor, cg.PollingComponent, uart.UARTDevice +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + Jsnsr04tComponent, + unit_of_measurement=UNIT_METER, + icon=ICON_ARROW_EXPAND_VERTICAL, + accuracy_decimals=3, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("60s")) + .extend(uart.UART_DEVICE_SCHEMA) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "jsn_sr04t", + baud_rate=9600, + require_tx=True, + require_rx=True, + data_bits=8, + parity=None, + stop_bits=1, +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/tests/components/jsn_sr04t/test.esp32-c3-idf.yaml b/tests/components/jsn_sr04t/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5a37418a7d --- /dev/null +++ b/tests/components/jsn_sr04t/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 4 + rx_pin: + number: 5 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s diff --git a/tests/components/jsn_sr04t/test.esp32-c3.yaml b/tests/components/jsn_sr04t/test.esp32-c3.yaml new file mode 100644 index 0000000000..5a37418a7d --- /dev/null +++ b/tests/components/jsn_sr04t/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 4 + rx_pin: + number: 5 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s diff --git a/tests/components/jsn_sr04t/test.esp32-idf.yaml b/tests/components/jsn_sr04t/test.esp32-idf.yaml new file mode 100644 index 0000000000..32b4221b3f --- /dev/null +++ b/tests/components/jsn_sr04t/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 17 + rx_pin: + number: 16 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s diff --git a/tests/components/jsn_sr04t/test.esp32.yaml b/tests/components/jsn_sr04t/test.esp32.yaml new file mode 100644 index 0000000000..32b4221b3f --- /dev/null +++ b/tests/components/jsn_sr04t/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 17 + rx_pin: + number: 16 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s diff --git a/tests/components/jsn_sr04t/test.esp8266.yaml b/tests/components/jsn_sr04t/test.esp8266.yaml new file mode 100644 index 0000000000..5a37418a7d --- /dev/null +++ b/tests/components/jsn_sr04t/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 4 + rx_pin: + number: 5 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s diff --git a/tests/components/jsn_sr04t/test.rp2040.yaml b/tests/components/jsn_sr04t/test.rp2040.yaml new file mode 100644 index 0000000000..5a37418a7d --- /dev/null +++ b/tests/components/jsn_sr04t/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_jsn_sr04t + tx_pin: + number: 4 + rx_pin: + number: 5 + baud_rate: 9600 + +sensor: + - platform: jsn_sr04t + id: jsn_sr04t_sensor + name: "jsn_sr04t Distance" + uart_id: uart_jsn_sr04t + update_interval: 1s From eee71466142dafb573c8578923b75d0712a99792 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:22:01 -0500 Subject: [PATCH 1463/2607] Add some components to the new testing framework (G) (#6178) --- tests/components/gcja5/test.esp32-c3-idf.yaml | 25 ++++ tests/components/gcja5/test.esp32-c3.yaml | 25 ++++ tests/components/gcja5/test.esp32-idf.yaml | 25 ++++ tests/components/gcja5/test.esp32.yaml | 25 ++++ tests/components/gcja5/test.esp8266.yaml | 25 ++++ tests/components/gcja5/test.rp2040.yaml | 25 ++++ .../components/globals/test.esp32-c3-idf.yaml | 28 ++++ tests/components/globals/test.esp32-c3.yaml | 28 ++++ tests/components/globals/test.esp32-idf.yaml | 28 ++++ tests/components/globals/test.esp32.yaml | 28 ++++ tests/components/globals/test.esp8266.yaml | 28 ++++ tests/components/globals/test.rp2040.yaml | 28 ++++ .../components/gp8403/test.esp32-c3-idf.yaml | 20 +++ tests/components/gp8403/test.esp32-c3.yaml | 20 +++ tests/components/gp8403/test.esp32-idf.yaml | 20 +++ tests/components/gp8403/test.esp32.yaml | 20 +++ tests/components/gp8403/test.esp8266.yaml | 20 +++ tests/components/gp8403/test.rp2040.yaml | 20 +++ tests/components/gpio/test.esp32-c3-idf.yaml | 14 ++ tests/components/gpio/test.esp32-c3.yaml | 14 ++ tests/components/gpio/test.esp32-idf.yaml | 14 ++ tests/components/gpio/test.esp32.yaml | 14 ++ tests/components/gpio/test.esp8266.yaml | 14 ++ tests/components/gpio/test.rp2040.yaml | 14 ++ tests/components/gps/test.esp32-c3.yaml | 14 ++ tests/components/gps/test.esp32.yaml | 14 ++ tests/components/gps/test.esp8266.yaml | 14 ++ tests/components/gps/test.rp2040.yaml | 14 ++ tests/components/graph/test.esp32-c3-idf.yaml | 25 ++++ tests/components/graph/test.esp32-c3.yaml | 25 ++++ tests/components/graph/test.esp32-idf.yaml | 25 ++++ tests/components/graph/test.esp32.yaml | 25 ++++ tests/components/graph/test.esp8266.yaml | 25 ++++ tests/components/graph/test.rp2040.yaml | 25 ++++ .../test.esp32-c3-idf.yaml | 120 ++++++++++++++++++ .../graphical_display_menu/test.esp32-c3.yaml | 120 ++++++++++++++++++ .../test.esp32-idf.yaml | 120 ++++++++++++++++++ .../graphical_display_menu/test.esp32.yaml | 120 ++++++++++++++++++ .../graphical_display_menu/test.esp8266.yaml | 120 ++++++++++++++++++ .../graphical_display_menu/test.rp2040.yaml | 120 ++++++++++++++++++ tests/components/gree/test.esp32-c3-idf.yaml | 8 ++ tests/components/gree/test.esp32-c3.yaml | 8 ++ tests/components/gree/test.esp32-idf.yaml | 8 ++ tests/components/gree/test.esp32.yaml | 8 ++ tests/components/gree/test.esp8266.yaml | 8 ++ .../grove_tb6612fng/test.esp32-c3-idf.yaml | 23 ++++ .../grove_tb6612fng/test.esp32-c3.yaml | 23 ++++ .../grove_tb6612fng/test.esp32-idf.yaml | 23 ++++ .../grove_tb6612fng/test.esp32.yaml | 23 ++++ .../grove_tb6612fng/test.esp8266.yaml | 23 ++++ .../grove_tb6612fng/test.rp2040.yaml | 23 ++++ .../growatt_solar/test.esp32-c3-idf.yaml | 62 +++++++++ .../growatt_solar/test.esp32-c3.yaml | 62 +++++++++ .../growatt_solar/test.esp32-idf.yaml | 62 +++++++++ .../components/growatt_solar/test.esp32.yaml | 62 +++++++++ .../growatt_solar/test.esp8266.yaml | 62 +++++++++ .../components/growatt_solar/test.rp2040.yaml | 62 +++++++++ tests/components/gt911/test.esp32-c3-idf.yaml | 24 ++++ tests/components/gt911/test.esp32-c3.yaml | 24 ++++ tests/components/gt911/test.esp32-idf.yaml | 24 ++++ tests/components/gt911/test.esp32.yaml | 24 ++++ tests/components/gt911/test.esp8266.yaml | 24 ++++ tests/components/gt911/test.rp2040.yaml | 24 ++++ 63 files changed, 2142 insertions(+) create mode 100644 tests/components/gcja5/test.esp32-c3-idf.yaml create mode 100644 tests/components/gcja5/test.esp32-c3.yaml create mode 100644 tests/components/gcja5/test.esp32-idf.yaml create mode 100644 tests/components/gcja5/test.esp32.yaml create mode 100644 tests/components/gcja5/test.esp8266.yaml create mode 100644 tests/components/gcja5/test.rp2040.yaml create mode 100644 tests/components/globals/test.esp32-c3-idf.yaml create mode 100644 tests/components/globals/test.esp32-c3.yaml create mode 100644 tests/components/globals/test.esp32-idf.yaml create mode 100644 tests/components/globals/test.esp32.yaml create mode 100644 tests/components/globals/test.esp8266.yaml create mode 100644 tests/components/globals/test.rp2040.yaml create mode 100644 tests/components/gp8403/test.esp32-c3-idf.yaml create mode 100644 tests/components/gp8403/test.esp32-c3.yaml create mode 100644 tests/components/gp8403/test.esp32-idf.yaml create mode 100644 tests/components/gp8403/test.esp32.yaml create mode 100644 tests/components/gp8403/test.esp8266.yaml create mode 100644 tests/components/gp8403/test.rp2040.yaml create mode 100644 tests/components/gpio/test.esp32-c3-idf.yaml create mode 100644 tests/components/gpio/test.esp32-c3.yaml create mode 100644 tests/components/gpio/test.esp32-idf.yaml create mode 100644 tests/components/gpio/test.esp32.yaml create mode 100644 tests/components/gpio/test.esp8266.yaml create mode 100644 tests/components/gpio/test.rp2040.yaml create mode 100644 tests/components/gps/test.esp32-c3.yaml create mode 100644 tests/components/gps/test.esp32.yaml create mode 100644 tests/components/gps/test.esp8266.yaml create mode 100644 tests/components/gps/test.rp2040.yaml create mode 100644 tests/components/graph/test.esp32-c3-idf.yaml create mode 100644 tests/components/graph/test.esp32-c3.yaml create mode 100644 tests/components/graph/test.esp32-idf.yaml create mode 100644 tests/components/graph/test.esp32.yaml create mode 100644 tests/components/graph/test.esp8266.yaml create mode 100644 tests/components/graph/test.rp2040.yaml create mode 100644 tests/components/graphical_display_menu/test.esp32-c3-idf.yaml create mode 100644 tests/components/graphical_display_menu/test.esp32-c3.yaml create mode 100644 tests/components/graphical_display_menu/test.esp32-idf.yaml create mode 100644 tests/components/graphical_display_menu/test.esp32.yaml create mode 100644 tests/components/graphical_display_menu/test.esp8266.yaml create mode 100644 tests/components/graphical_display_menu/test.rp2040.yaml create mode 100644 tests/components/gree/test.esp32-c3-idf.yaml create mode 100644 tests/components/gree/test.esp32-c3.yaml create mode 100644 tests/components/gree/test.esp32-idf.yaml create mode 100644 tests/components/gree/test.esp32.yaml create mode 100644 tests/components/gree/test.esp8266.yaml create mode 100644 tests/components/grove_tb6612fng/test.esp32-c3-idf.yaml create mode 100644 tests/components/grove_tb6612fng/test.esp32-c3.yaml create mode 100644 tests/components/grove_tb6612fng/test.esp32-idf.yaml create mode 100644 tests/components/grove_tb6612fng/test.esp32.yaml create mode 100644 tests/components/grove_tb6612fng/test.esp8266.yaml create mode 100644 tests/components/grove_tb6612fng/test.rp2040.yaml create mode 100644 tests/components/growatt_solar/test.esp32-c3-idf.yaml create mode 100644 tests/components/growatt_solar/test.esp32-c3.yaml create mode 100644 tests/components/growatt_solar/test.esp32-idf.yaml create mode 100644 tests/components/growatt_solar/test.esp32.yaml create mode 100644 tests/components/growatt_solar/test.esp8266.yaml create mode 100644 tests/components/growatt_solar/test.rp2040.yaml create mode 100644 tests/components/gt911/test.esp32-c3-idf.yaml create mode 100644 tests/components/gt911/test.esp32-c3.yaml create mode 100644 tests/components/gt911/test.esp32-idf.yaml create mode 100644 tests/components/gt911/test.esp32.yaml create mode 100644 tests/components/gt911/test.esp8266.yaml create mode 100644 tests/components/gt911/test.rp2040.yaml diff --git a/tests/components/gcja5/test.esp32-c3-idf.yaml b/tests/components/gcja5/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ec8765be52 --- /dev/null +++ b/tests/components/gcja5/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/gcja5/test.esp32-c3.yaml b/tests/components/gcja5/test.esp32-c3.yaml new file mode 100644 index 0000000000..ec8765be52 --- /dev/null +++ b/tests/components/gcja5/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/gcja5/test.esp32-idf.yaml b/tests/components/gcja5/test.esp32-idf.yaml new file mode 100644 index 0000000000..bc0f89eb9e --- /dev/null +++ b/tests/components/gcja5/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/gcja5/test.esp32.yaml b/tests/components/gcja5/test.esp32.yaml new file mode 100644 index 0000000000..bc0f89eb9e --- /dev/null +++ b/tests/components/gcja5/test.esp32.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/gcja5/test.esp8266.yaml b/tests/components/gcja5/test.esp8266.yaml new file mode 100644 index 0000000000..ec8765be52 --- /dev/null +++ b/tests/components/gcja5/test.esp8266.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/gcja5/test.rp2040.yaml b/tests/components/gcja5/test.rp2040.yaml new file mode 100644 index 0000000000..ec8765be52 --- /dev/null +++ b/tests/components/gcja5/test.rp2040.yaml @@ -0,0 +1,25 @@ +uart: + - id: uart_gcja5 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +sensor: + - platform: gcja5 + pm_1_0: + name: "Particulate Matter <1.0µm Concentration" + pm_2_5: + name: "Particulate Matter <2.5µm Concentration" + pm_10_0: + name: "Particulate Matter <10.0µm Concentration" + pmc_0_5: + name: "PMC 0.5" + pmc_1_0: + name: "PMC 1.0" + pmc_2_5: + name: "PMC 2.5" + pmc_5_0: + name: "PMC 5.0" + pmc_10_0: + name: "PMC 10.0" diff --git a/tests/components/globals/test.esp32-c3-idf.yaml b/tests/components/globals/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.esp32-c3.yaml b/tests/components/globals/test.esp32-c3.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.esp32-idf.yaml b/tests/components/globals/test.esp32-idf.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.esp32.yaml b/tests/components/globals/test.esp32.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.esp32.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.esp8266.yaml b/tests/components/globals/test.esp8266.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.esp8266.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.rp2040.yaml b/tests/components/globals/test.rp2040.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/test.rp2040.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/gp8403/test.esp32-c3-idf.yaml b/tests/components/gp8403/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fbc40b948b --- /dev/null +++ b/tests/components/gp8403/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 5 + sda: 4 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gp8403/test.esp32-c3.yaml b/tests/components/gp8403/test.esp32-c3.yaml new file mode 100644 index 0000000000..fbc40b948b --- /dev/null +++ b/tests/components/gp8403/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 5 + sda: 4 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gp8403/test.esp32-idf.yaml b/tests/components/gp8403/test.esp32-idf.yaml new file mode 100644 index 0000000000..8470a303e1 --- /dev/null +++ b/tests/components/gp8403/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 16 + sda: 17 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gp8403/test.esp32.yaml b/tests/components/gp8403/test.esp32.yaml new file mode 100644 index 0000000000..8470a303e1 --- /dev/null +++ b/tests/components/gp8403/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 16 + sda: 17 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gp8403/test.esp8266.yaml b/tests/components/gp8403/test.esp8266.yaml new file mode 100644 index 0000000000..fbc40b948b --- /dev/null +++ b/tests/components/gp8403/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 5 + sda: 4 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gp8403/test.rp2040.yaml b/tests/components/gp8403/test.rp2040.yaml new file mode 100644 index 0000000000..fbc40b948b --- /dev/null +++ b/tests/components/gp8403/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_gp8403 + scl: 5 + sda: 4 + +gp8403: + - id: gp8403_5v + voltage: 5V + - id: gp8403_10v + voltage: 10V + +output: + - platform: gp8403 + id: gp8403_output_0 + gp8403_id: gp8403_5v + channel: 0 + - platform: gp8403 + gp8403_id: gp8403_10v + id: gp8403_output_1 + channel: 1 diff --git a/tests/components/gpio/test.esp32-c3-idf.yaml b/tests/components/gpio/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3ca285117d --- /dev/null +++ b/tests/components/gpio/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 2 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 3 + id: gpio_output + +switch: + - platform: gpio + pin: 4 + id: gpio_switch diff --git a/tests/components/gpio/test.esp32-c3.yaml b/tests/components/gpio/test.esp32-c3.yaml new file mode 100644 index 0000000000..3ca285117d --- /dev/null +++ b/tests/components/gpio/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 2 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 3 + id: gpio_output + +switch: + - platform: gpio + pin: 4 + id: gpio_switch diff --git a/tests/components/gpio/test.esp32-idf.yaml b/tests/components/gpio/test.esp32-idf.yaml new file mode 100644 index 0000000000..30dfa94b68 --- /dev/null +++ b/tests/components/gpio/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 12 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 13 + id: gpio_output + +switch: + - platform: gpio + pin: 14 + id: gpio_switch diff --git a/tests/components/gpio/test.esp32.yaml b/tests/components/gpio/test.esp32.yaml new file mode 100644 index 0000000000..30dfa94b68 --- /dev/null +++ b/tests/components/gpio/test.esp32.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 12 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 13 + id: gpio_output + +switch: + - platform: gpio + pin: 14 + id: gpio_switch diff --git a/tests/components/gpio/test.esp8266.yaml b/tests/components/gpio/test.esp8266.yaml new file mode 100644 index 0000000000..30dfa94b68 --- /dev/null +++ b/tests/components/gpio/test.esp8266.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 12 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 13 + id: gpio_output + +switch: + - platform: gpio + pin: 14 + id: gpio_switch diff --git a/tests/components/gpio/test.rp2040.yaml b/tests/components/gpio/test.rp2040.yaml new file mode 100644 index 0000000000..3ca285117d --- /dev/null +++ b/tests/components/gpio/test.rp2040.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: gpio + pin: 2 + id: gpio_binary_sensor + +output: + - platform: gpio + pin: 3 + id: gpio_output + +switch: + - platform: gpio + pin: 4 + id: gpio_switch diff --git a/tests/components/gps/test.esp32-c3.yaml b/tests/components/gps/test.esp32-c3.yaml new file mode 100644 index 0000000000..031f45b873 --- /dev/null +++ b/tests/components/gps/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_gps + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +gps: + +time: + - platform: gps + on_time_sync: + then: + logger.log: "It's time!" diff --git a/tests/components/gps/test.esp32.yaml b/tests/components/gps/test.esp32.yaml new file mode 100644 index 0000000000..c4e4cf9f6f --- /dev/null +++ b/tests/components/gps/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_gps + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + parity: EVEN + +gps: + +time: + - platform: gps + on_time_sync: + then: + logger.log: "It's time!" diff --git a/tests/components/gps/test.esp8266.yaml b/tests/components/gps/test.esp8266.yaml new file mode 100644 index 0000000000..031f45b873 --- /dev/null +++ b/tests/components/gps/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_gps + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +gps: + +time: + - platform: gps + on_time_sync: + then: + logger.log: "It's time!" diff --git a/tests/components/gps/test.rp2040.yaml b/tests/components/gps/test.rp2040.yaml new file mode 100644 index 0000000000..031f45b873 --- /dev/null +++ b/tests/components/gps/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_gps + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + parity: EVEN + +gps: + +time: + - platform: gps + on_time_sync: + then: + logger.log: "It's time!" diff --git a/tests/components/graph/test.esp32-c3-idf.yaml b/tests/components/graph/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..8ce40e84ac --- /dev/null +++ b/tests/components/graph/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 5 + sda: 4 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graph/test.esp32-c3.yaml b/tests/components/graph/test.esp32-c3.yaml new file mode 100644 index 0000000000..8ce40e84ac --- /dev/null +++ b/tests/components/graph/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 5 + sda: 4 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graph/test.esp32-idf.yaml b/tests/components/graph/test.esp32-idf.yaml new file mode 100644 index 0000000000..8c0c0d4c9e --- /dev/null +++ b/tests/components/graph/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 16 + sda: 17 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graph/test.esp32.yaml b/tests/components/graph/test.esp32.yaml new file mode 100644 index 0000000000..8c0c0d4c9e --- /dev/null +++ b/tests/components/graph/test.esp32.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 16 + sda: 17 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graph/test.esp8266.yaml b/tests/components/graph/test.esp8266.yaml new file mode 100644 index 0000000000..33318355d5 --- /dev/null +++ b/tests/components/graph/test.esp8266.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 5 + sda: 4 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graph/test.rp2040.yaml b/tests/components/graph/test.rp2040.yaml new file mode 100644 index 0000000000..8ce40e84ac --- /dev/null +++ b/tests/components/graph/test.rp2040.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_graph + scl: 5 + sda: 4 + +sensor: + - platform: template + id: some_sensor + +graph: + - id: some_graph + sensor: some_sensor + duration: 1h + width: 100 + height: 100 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/graphical_display_menu/test.esp32-c3-idf.yaml b/tests/components/graphical_display_menu/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..23acd4e4d9 --- /dev/null +++ b/tests/components/graphical_display_menu/test.esp32-c3-idf.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/graphical_display_menu/test.esp32-c3.yaml b/tests/components/graphical_display_menu/test.esp32-c3.yaml new file mode 100644 index 0000000000..23acd4e4d9 --- /dev/null +++ b/tests/components/graphical_display_menu/test.esp32-c3.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/graphical_display_menu/test.esp32-idf.yaml b/tests/components/graphical_display_menu/test.esp32-idf.yaml new file mode 100644 index 0000000000..a0897536d7 --- /dev/null +++ b/tests/components/graphical_display_menu/test.esp32-idf.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/graphical_display_menu/test.esp32.yaml b/tests/components/graphical_display_menu/test.esp32.yaml new file mode 100644 index 0000000000..a0897536d7 --- /dev/null +++ b/tests/components/graphical_display_menu/test.esp32.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/graphical_display_menu/test.esp8266.yaml b/tests/components/graphical_display_menu/test.esp8266.yaml new file mode 100644 index 0000000000..28c1a7298d --- /dev/null +++ b/tests/components/graphical_display_menu/test.esp8266.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/graphical_display_menu/test.rp2040.yaml b/tests/components/graphical_display_menu/test.rp2040.yaml new file mode 100644 index 0000000000..23acd4e4d9 --- /dev/null +++ b/tests/components/graphical_display_menu/test.rp2040.yaml @@ -0,0 +1,120 @@ +i2c: + - id: i2c_graphical_display_menu + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + id: test_switch + optimistic: true + +graphical_display_menu: + id: test_graphical_display_menu + display: ssd1306_display + font: roboto + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' + items: + - type: back + text: "Back" + - type: label + - type: menu + text: "Submenu 1" + items: + - type: back + text: "Back" + - type: menu + text: "Submenu 21" + items: + - type: back + text: "Back" + - type: command + text: "Show Main" + on_value: + then: + - display_menu.show_main: test_graphical_display_menu + - type: select + text: "Enum Item" + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: "Number" + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: "Hide" + on_value: + then: + - display_menu.hide: test_graphical_display_menu + - type: switch + text: "Switch" + switch: test_switch + on_text: "Bright" + off_text: "Dark" + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/gree/test.esp32-c3-idf.yaml b/tests/components/gree/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..91491d7e16 --- /dev/null +++ b/tests/components/gree/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: gree + name: GREE + model: generic diff --git a/tests/components/gree/test.esp32-c3.yaml b/tests/components/gree/test.esp32-c3.yaml new file mode 100644 index 0000000000..91491d7e16 --- /dev/null +++ b/tests/components/gree/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: gree + name: GREE + model: generic diff --git a/tests/components/gree/test.esp32-idf.yaml b/tests/components/gree/test.esp32-idf.yaml new file mode 100644 index 0000000000..91491d7e16 --- /dev/null +++ b/tests/components/gree/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: gree + name: GREE + model: generic diff --git a/tests/components/gree/test.esp32.yaml b/tests/components/gree/test.esp32.yaml new file mode 100644 index 0000000000..91491d7e16 --- /dev/null +++ b/tests/components/gree/test.esp32.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: gree + name: GREE + model: generic diff --git a/tests/components/gree/test.esp8266.yaml b/tests/components/gree/test.esp8266.yaml new file mode 100644 index 0000000000..d0542973ce --- /dev/null +++ b/tests/components/gree/test.esp8266.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: gree + name: GREE + model: generic diff --git a/tests/components/grove_tb6612fng/test.esp32-c3-idf.yaml b/tests/components/grove_tb6612fng/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ef6dff6539 --- /dev/null +++ b/tests/components/grove_tb6612fng/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 5 + sda: 4 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/grove_tb6612fng/test.esp32-c3.yaml b/tests/components/grove_tb6612fng/test.esp32-c3.yaml new file mode 100644 index 0000000000..ef6dff6539 --- /dev/null +++ b/tests/components/grove_tb6612fng/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 5 + sda: 4 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/grove_tb6612fng/test.esp32-idf.yaml b/tests/components/grove_tb6612fng/test.esp32-idf.yaml new file mode 100644 index 0000000000..3271fb754f --- /dev/null +++ b/tests/components/grove_tb6612fng/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 16 + sda: 17 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/grove_tb6612fng/test.esp32.yaml b/tests/components/grove_tb6612fng/test.esp32.yaml new file mode 100644 index 0000000000..3271fb754f --- /dev/null +++ b/tests/components/grove_tb6612fng/test.esp32.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 16 + sda: 17 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/grove_tb6612fng/test.esp8266.yaml b/tests/components/grove_tb6612fng/test.esp8266.yaml new file mode 100644 index 0000000000..ef6dff6539 --- /dev/null +++ b/tests/components/grove_tb6612fng/test.esp8266.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 5 + sda: 4 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/grove_tb6612fng/test.rp2040.yaml b/tests/components/grove_tb6612fng/test.rp2040.yaml new file mode 100644 index 0000000000..ef6dff6539 --- /dev/null +++ b/tests/components/grove_tb6612fng/test.rp2040.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - grove_tb6612fng.run: + channel: 1 + speed: 255 + direction: BACKWARD + id: test_motor + - grove_tb6612fng.stop: + channel: 1 + id: test_motor + - grove_tb6612fng.break: + channel: 1 + id: test_motor + +i2c: + - id: i2c_grove_tb6612fng + scl: 5 + sda: 4 + +grove_tb6612fng: + id: test_motor + address: 0x14 diff --git a/tests/components/growatt_solar/test.esp32-c3-idf.yaml b/tests/components/growatt_solar/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3b5e2e4ce4 --- /dev/null +++ b/tests/components/growatt_solar/test.esp32-c3-idf.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/growatt_solar/test.esp32-c3.yaml b/tests/components/growatt_solar/test.esp32-c3.yaml new file mode 100644 index 0000000000..3b5e2e4ce4 --- /dev/null +++ b/tests/components/growatt_solar/test.esp32-c3.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/growatt_solar/test.esp32-idf.yaml b/tests/components/growatt_solar/test.esp32-idf.yaml new file mode 100644 index 0000000000..a0670fdbd6 --- /dev/null +++ b/tests/components/growatt_solar/test.esp32-idf.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/growatt_solar/test.esp32.yaml b/tests/components/growatt_solar/test.esp32.yaml new file mode 100644 index 0000000000..a0670fdbd6 --- /dev/null +++ b/tests/components/growatt_solar/test.esp32.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/growatt_solar/test.esp8266.yaml b/tests/components/growatt_solar/test.esp8266.yaml new file mode 100644 index 0000000000..fed27ffda1 --- /dev/null +++ b/tests/components/growatt_solar/test.esp8266.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/growatt_solar/test.rp2040.yaml b/tests/components/growatt_solar/test.rp2040.yaml new file mode 100644 index 0000000000..3b5e2e4ce4 --- /dev/null +++ b/tests/components/growatt_solar/test.rp2040.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_growatt_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: growatt_solar + update_interval: 10s + protocol_version: RTU + inverter_status: + name: Growatt Status Code + phase_a: + voltage: + name: Growatt Voltage Phase A + current: + name: Growatt Current Phase A + active_power: + name: Growatt Power Phase A + phase_b: + voltage: + name: Growatt Voltage Phase B + current: + name: Growatt Current Phase B + active_power: + name: Growatt Power Phase B + phase_c: + voltage: + name: Growatt Voltage Phase C + current: + name: Growatt Current Phase C + active_power: + name: Growatt Power Phase C + pv1: + voltage: + name: Growatt PV1 Voltage + current: + name: Growatt PV1 Current + active_power: + name: Growatt PV1 Active Power + pv2: + voltage: + name: Growatt PV2 Voltage + current: + name: Growatt PV2 Current + active_power: + name: Growatt PV2 Active Power + active_power: + name: Growatt Grid Active Power + pv_active_power: + name: Growatt PV Active Power + frequency: + name: Growatt Frequency + energy_production_day: + name: Growatt Today's Generation + total_energy_production: + name: Growatt Total Energy Production + inverter_module_temp: + name: Growatt Inverter Module Temp diff --git a/tests/components/gt911/test.esp32-c3-idf.yaml b/tests/components/gt911/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..43f7ac5902 --- /dev/null +++ b/tests/components/gt911/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 6 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.esp32-c3.yaml b/tests/components/gt911/test.esp32-c3.yaml new file mode 100644 index 0000000000..43f7ac5902 --- /dev/null +++ b/tests/components/gt911/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 6 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.esp32-idf.yaml b/tests/components/gt911/test.esp32-idf.yaml new file mode 100644 index 0000000000..a47f7bf260 --- /dev/null +++ b/tests/components/gt911/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 14 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.esp32.yaml b/tests/components/gt911/test.esp32.yaml new file mode 100644 index 0000000000..a47f7bf260 --- /dev/null +++ b/tests/components/gt911/test.esp32.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 14 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.esp8266.yaml b/tests/components/gt911/test.esp8266.yaml new file mode 100644 index 0000000000..8b76eff29e --- /dev/null +++ b/tests/components/gt911/test.esp8266.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 12 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.rp2040.yaml b/tests/components/gt911/test.rp2040.yaml new file mode 100644 index 0000000000..43f7ac5902 --- /dev/null +++ b/tests/components/gt911/test.rp2040.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_gt911 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 6 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 From ca6020e11a801b65f334c268a3638ae73b629f66 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:22:54 -0500 Subject: [PATCH 1464/2607] Add some components to the new testing framework (K) (#6186) --- .../key_collector/test.esp32-c3-idf.yaml | 28 +++++++++++++++++++ .../key_collector/test.esp32-c3.yaml | 28 +++++++++++++++++++ .../key_collector/test.esp32-idf.yaml | 28 +++++++++++++++++++ .../components/key_collector/test.esp32.yaml | 28 +++++++++++++++++++ .../key_collector/test.esp8266.yaml | 28 +++++++++++++++++++ .../components/key_collector/test.rp2040.yaml | 28 +++++++++++++++++++ .../kmeteriso/test.esp32-c3-idf.yaml | 12 ++++++++ tests/components/kmeteriso/test.esp32-c3.yaml | 12 ++++++++ .../components/kmeteriso/test.esp32-idf.yaml | 12 ++++++++ tests/components/kmeteriso/test.esp32.yaml | 12 ++++++++ tests/components/kmeteriso/test.esp8266.yaml | 12 ++++++++ tests/components/kmeteriso/test.rp2040.yaml | 12 ++++++++ .../components/kuntze/test.esp32-c3-idf.yaml | 15 ++++++++++ tests/components/kuntze/test.esp32-c3.yaml | 15 ++++++++++ tests/components/kuntze/test.esp32-idf.yaml | 15 ++++++++++ tests/components/kuntze/test.esp32.yaml | 15 ++++++++++ tests/components/kuntze/test.esp8266.yaml | 15 ++++++++++ tests/components/kuntze/test.rp2040.yaml | 15 ++++++++++ 18 files changed, 330 insertions(+) create mode 100644 tests/components/key_collector/test.esp32-c3-idf.yaml create mode 100644 tests/components/key_collector/test.esp32-c3.yaml create mode 100644 tests/components/key_collector/test.esp32-idf.yaml create mode 100644 tests/components/key_collector/test.esp32.yaml create mode 100644 tests/components/key_collector/test.esp8266.yaml create mode 100644 tests/components/key_collector/test.rp2040.yaml create mode 100644 tests/components/kmeteriso/test.esp32-c3-idf.yaml create mode 100644 tests/components/kmeteriso/test.esp32-c3.yaml create mode 100644 tests/components/kmeteriso/test.esp32-idf.yaml create mode 100644 tests/components/kmeteriso/test.esp32.yaml create mode 100644 tests/components/kmeteriso/test.esp8266.yaml create mode 100644 tests/components/kmeteriso/test.rp2040.yaml create mode 100644 tests/components/kuntze/test.esp32-c3-idf.yaml create mode 100644 tests/components/kuntze/test.esp32-c3.yaml create mode 100644 tests/components/kuntze/test.esp32-idf.yaml create mode 100644 tests/components/kuntze/test.esp32.yaml create mode 100644 tests/components/kuntze/test.esp8266.yaml create mode 100644 tests/components/kuntze/test.rp2040.yaml diff --git a/tests/components/key_collector/test.esp32-c3-idf.yaml b/tests/components/key_collector/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a186d4fa23 --- /dev/null +++ b/tests/components/key_collector/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/key_collector/test.esp32-c3.yaml b/tests/components/key_collector/test.esp32-c3.yaml new file mode 100644 index 0000000000..a186d4fa23 --- /dev/null +++ b/tests/components/key_collector/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/key_collector/test.esp32-idf.yaml b/tests/components/key_collector/test.esp32-idf.yaml new file mode 100644 index 0000000000..d357b33279 --- /dev/null +++ b/tests/components/key_collector/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/key_collector/test.esp32.yaml b/tests/components/key_collector/test.esp32.yaml new file mode 100644 index 0000000000..d357b33279 --- /dev/null +++ b/tests/components/key_collector/test.esp32.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/key_collector/test.esp8266.yaml b/tests/components/key_collector/test.esp8266.yaml new file mode 100644 index 0000000000..d357b33279 --- /dev/null +++ b/tests/components/key_collector/test.esp8266.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/key_collector/test.rp2040.yaml b/tests/components/key_collector/test.rp2040.yaml new file mode 100644 index 0000000000..a186d4fa23 --- /dev/null +++ b/tests/components/key_collector/test.rp2040.yaml @@ -0,0 +1,28 @@ +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true + +key_collector: + - id: reader + source_id: keypad + min_length: 4 + max_length: 4 + on_progress: + - logger.log: + format: "input progress: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + on_result: + - logger.log: + format: "input result: '%s', started by '%c', ended by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + on_timeout: + - logger.log: + format: "input timeout: '%s', started by '%c'" + args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] diff --git a/tests/components/kmeteriso/test.esp32-c3-idf.yaml b/tests/components/kmeteriso/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7780cfea32 --- /dev/null +++ b/tests/components/kmeteriso/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 5 + sda: 4 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kmeteriso/test.esp32-c3.yaml b/tests/components/kmeteriso/test.esp32-c3.yaml new file mode 100644 index 0000000000..7780cfea32 --- /dev/null +++ b/tests/components/kmeteriso/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 5 + sda: 4 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kmeteriso/test.esp32-idf.yaml b/tests/components/kmeteriso/test.esp32-idf.yaml new file mode 100644 index 0000000000..2c375dda31 --- /dev/null +++ b/tests/components/kmeteriso/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 16 + sda: 17 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kmeteriso/test.esp32.yaml b/tests/components/kmeteriso/test.esp32.yaml new file mode 100644 index 0000000000..2c375dda31 --- /dev/null +++ b/tests/components/kmeteriso/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 16 + sda: 17 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kmeteriso/test.esp8266.yaml b/tests/components/kmeteriso/test.esp8266.yaml new file mode 100644 index 0000000000..7780cfea32 --- /dev/null +++ b/tests/components/kmeteriso/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 5 + sda: 4 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kmeteriso/test.rp2040.yaml b/tests/components/kmeteriso/test.rp2040.yaml new file mode 100644 index 0000000000..7780cfea32 --- /dev/null +++ b/tests/components/kmeteriso/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_kmeteriso + scl: 5 + sda: 4 + +sensor: + - platform: kmeteriso + temperature: + name: Outside Temperature + internal_temperature: + name: Internal Temperature + update_interval: 15s diff --git a/tests/components/kuntze/test.esp32-c3-idf.yaml b/tests/components/kuntze/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..08278c3c82 --- /dev/null +++ b/tests/components/kuntze/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature diff --git a/tests/components/kuntze/test.esp32-c3.yaml b/tests/components/kuntze/test.esp32-c3.yaml new file mode 100644 index 0000000000..08278c3c82 --- /dev/null +++ b/tests/components/kuntze/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature diff --git a/tests/components/kuntze/test.esp32-idf.yaml b/tests/components/kuntze/test.esp32-idf.yaml new file mode 100644 index 0000000000..6b6c638971 --- /dev/null +++ b/tests/components/kuntze/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature diff --git a/tests/components/kuntze/test.esp32.yaml b/tests/components/kuntze/test.esp32.yaml new file mode 100644 index 0000000000..6b6c638971 --- /dev/null +++ b/tests/components/kuntze/test.esp32.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature diff --git a/tests/components/kuntze/test.esp8266.yaml b/tests/components/kuntze/test.esp8266.yaml new file mode 100644 index 0000000000..eba6cddc2d --- /dev/null +++ b/tests/components/kuntze/test.esp8266.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 13 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature diff --git a/tests/components/kuntze/test.rp2040.yaml b/tests/components/kuntze/test.rp2040.yaml new file mode 100644 index 0000000000..08278c3c82 --- /dev/null +++ b/tests/components/kuntze/test.rp2040.yaml @@ -0,0 +1,15 @@ +uart: + - id: uart_kuntze + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: kuntze + ph: + name: Kuntze pH + temperature: + name: Kuntze temperature From 9779989f674a19e1475a31728accd5e10438d434 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:24:32 -0500 Subject: [PATCH 1465/2607] Add some components to the new testing framework (N) (#6210) --- .../components/neopixelbus/test.esp32-c3.yaml | 19 ++++++ tests/components/neopixelbus/test.esp32.yaml | 17 ++++++ .../components/neopixelbus/test.esp8266.yaml | 17 ++++++ .../components/network/test.esp32-c3-idf.yaml | 6 ++ tests/components/network/test.esp32-c3.yaml | 6 ++ tests/components/network/test.esp32-idf.yaml | 6 ++ tests/components/network/test.esp32.yaml | 6 ++ tests/components/network/test.esp8266.yaml | 6 ++ tests/components/network/test.rp2040.yaml | 6 ++ .../components/nextion/test.esp32-c3-idf.yaml | 60 +++++++++++++++++++ tests/components/nextion/test.esp32-c3.yaml | 60 +++++++++++++++++++ tests/components/nextion/test.esp32-idf.yaml | 60 +++++++++++++++++++ tests/components/nextion/test.esp32.yaml | 60 +++++++++++++++++++ tests/components/nextion/test.esp8266.yaml | 60 +++++++++++++++++++ tests/components/nextion/test.rp2040.yaml | 55 +++++++++++++++++ .../components/noblex/test.esp32-c3-idf.yaml | 20 +++++++ tests/components/noblex/test.esp32-c3.yaml | 20 +++++++ tests/components/noblex/test.esp32-idf.yaml | 20 +++++++ tests/components/noblex/test.esp32.yaml | 20 +++++++ tests/components/noblex/test.esp8266.yaml | 20 +++++++ tests/components/ntc/test.esp32-c3.yaml | 26 ++++++++ tests/components/ntc/test.esp32-idf.yaml | 26 ++++++++ tests/components/ntc/test.esp32-s2.yaml | 26 ++++++++ tests/components/ntc/test.esp32-s3.yaml | 26 ++++++++ tests/components/ntc/test.esp32.yaml | 26 ++++++++ tests/components/ntc/test.esp8266.yaml | 25 ++++++++ tests/components/ntc/test.rp2040.yaml | 25 ++++++++ 27 files changed, 724 insertions(+) create mode 100644 tests/components/neopixelbus/test.esp32-c3.yaml create mode 100644 tests/components/neopixelbus/test.esp32.yaml create mode 100644 tests/components/neopixelbus/test.esp8266.yaml create mode 100644 tests/components/network/test.esp32-c3-idf.yaml create mode 100644 tests/components/network/test.esp32-c3.yaml create mode 100644 tests/components/network/test.esp32-idf.yaml create mode 100644 tests/components/network/test.esp32.yaml create mode 100644 tests/components/network/test.esp8266.yaml create mode 100644 tests/components/network/test.rp2040.yaml create mode 100644 tests/components/nextion/test.esp32-c3-idf.yaml create mode 100644 tests/components/nextion/test.esp32-c3.yaml create mode 100644 tests/components/nextion/test.esp32-idf.yaml create mode 100644 tests/components/nextion/test.esp32.yaml create mode 100644 tests/components/nextion/test.esp8266.yaml create mode 100644 tests/components/nextion/test.rp2040.yaml create mode 100644 tests/components/noblex/test.esp32-c3-idf.yaml create mode 100644 tests/components/noblex/test.esp32-c3.yaml create mode 100644 tests/components/noblex/test.esp32-idf.yaml create mode 100644 tests/components/noblex/test.esp32.yaml create mode 100644 tests/components/noblex/test.esp8266.yaml create mode 100644 tests/components/ntc/test.esp32-c3.yaml create mode 100644 tests/components/ntc/test.esp32-idf.yaml create mode 100644 tests/components/ntc/test.esp32-s2.yaml create mode 100644 tests/components/ntc/test.esp32-s3.yaml create mode 100644 tests/components/ntc/test.esp32.yaml create mode 100644 tests/components/ntc/test.esp8266.yaml create mode 100644 tests/components/ntc/test.rp2040.yaml diff --git a/tests/components/neopixelbus/test.esp32-c3.yaml b/tests/components/neopixelbus/test.esp32-c3.yaml new file mode 100644 index 0000000000..f2b53ab1e9 --- /dev/null +++ b/tests/components/neopixelbus/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +light: + - platform: neopixelbus + id: addr3 + name: Neopixelbus Light + gamma_correct: 2.8 + color_correct: [0.0, 0.0, 0.0, 0.0] + default_transition_length: 10s + effects: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + type: GRBW + variant: SK6812 + method: + type: esp32_rmt + channel: 0 + num_leds: 5 + pin: 4 diff --git a/tests/components/neopixelbus/test.esp32.yaml b/tests/components/neopixelbus/test.esp32.yaml new file mode 100644 index 0000000000..fd468586e0 --- /dev/null +++ b/tests/components/neopixelbus/test.esp32.yaml @@ -0,0 +1,17 @@ +light: + - platform: neopixelbus + id: addr3 + name: Neopixelbus Light + gamma_correct: 2.8 + color_correct: [0.0, 0.0, 0.0, 0.0] + default_transition_length: 10s + effects: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + type: GRBW + variant: SK6812 + method: ESP32_I2S_0 + num_leds: 5 + pin: 4 diff --git a/tests/components/neopixelbus/test.esp8266.yaml b/tests/components/neopixelbus/test.esp8266.yaml new file mode 100644 index 0000000000..2c1f16a38c --- /dev/null +++ b/tests/components/neopixelbus/test.esp8266.yaml @@ -0,0 +1,17 @@ +light: + - platform: neopixelbus + id: addr3 + name: Neopixelbus Light + gamma_correct: 2.8 + color_correct: [0.0, 0.0, 0.0, 0.0] + default_transition_length: 10s + effects: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + type: GRBW + variant: SK6812 + method: esp8266_uart + num_leds: 5 + pin: 2 diff --git a/tests/components/network/test.esp32-c3-idf.yaml b/tests/components/network/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.esp32-c3.yaml b/tests/components/network/test.esp32-c3.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.esp32-idf.yaml b/tests/components/network/test.esp32-idf.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.esp32.yaml b/tests/components/network/test.esp32.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.esp32.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.esp8266.yaml b/tests/components/network/test.esp8266.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.esp8266.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.rp2040.yaml b/tests/components/network/test.rp2040.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/test.rp2040.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/nextion/test.esp32-c3-idf.yaml b/tests/components/nextion/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5881d6e165 --- /dev/null +++ b/tests/components/nextion/test.esp32-c3-idf.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + tft_url: http://esphome.io/default35.tft + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/nextion/test.esp32-c3.yaml b/tests/components/nextion/test.esp32-c3.yaml new file mode 100644 index 0000000000..5881d6e165 --- /dev/null +++ b/tests/components/nextion/test.esp32-c3.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + tft_url: http://esphome.io/default35.tft + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/nextion/test.esp32-idf.yaml b/tests/components/nextion/test.esp32-idf.yaml new file mode 100644 index 0000000000..27568ebc2a --- /dev/null +++ b/tests/components/nextion/test.esp32-idf.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + tft_url: http://esphome.io/default35.tft + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/nextion/test.esp32.yaml b/tests/components/nextion/test.esp32.yaml new file mode 100644 index 0000000000..27568ebc2a --- /dev/null +++ b/tests/components/nextion/test.esp32.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + tft_url: http://esphome.io/default35.tft + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/nextion/test.esp8266.yaml b/tests/components/nextion/test.esp8266.yaml new file mode 100644 index 0000000000..5881d6e165 --- /dev/null +++ b/tests/components/nextion/test.esp8266.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + tft_url: http://esphome.io/default35.tft + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/nextion/test.rp2040.yaml b/tests/components/nextion/test.rp2040.yaml new file mode 100644 index 0000000000..a1c5848ce6 --- /dev/null +++ b/tests/components/nextion/test.rp2040.yaml @@ -0,0 +1,55 @@ +uart: + - id: uart_nextion + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' diff --git a/tests/components/noblex/test.esp32-c3-idf.yaml b/tests/components/noblex/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/noblex/test.esp32-c3.yaml b/tests/components/noblex/test.esp32-c3.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/noblex/test.esp32-idf.yaml b/tests/components/noblex/test.esp32-idf.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/noblex/test.esp32.yaml b/tests/components/noblex/test.esp32.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/test.esp32.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/noblex/test.esp8266.yaml b/tests/components/noblex/test.esp8266.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/test.esp8266.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/ntc/test.esp32-c3.yaml b/tests/components/ntc/test.esp32-c3.yaml new file mode 100644 index 0000000000..c0edb83d9d --- /dev/null +++ b/tests/components/ntc/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +sensor: + - platform: adc + id: my_sensor + pin: 4 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.esp32-idf.yaml b/tests/components/ntc/test.esp32-idf.yaml new file mode 100644 index 0000000000..3e0e901b6e --- /dev/null +++ b/tests/components/ntc/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +sensor: + - platform: adc + id: my_sensor + pin: 32 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.esp32-s2.yaml b/tests/components/ntc/test.esp32-s2.yaml new file mode 100644 index 0000000000..c0edb83d9d --- /dev/null +++ b/tests/components/ntc/test.esp32-s2.yaml @@ -0,0 +1,26 @@ +sensor: + - platform: adc + id: my_sensor + pin: 4 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.esp32-s3.yaml b/tests/components/ntc/test.esp32-s3.yaml new file mode 100644 index 0000000000..c0edb83d9d --- /dev/null +++ b/tests/components/ntc/test.esp32-s3.yaml @@ -0,0 +1,26 @@ +sensor: + - platform: adc + id: my_sensor + pin: 4 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.esp32.yaml b/tests/components/ntc/test.esp32.yaml new file mode 100644 index 0000000000..3e0e901b6e --- /dev/null +++ b/tests/components/ntc/test.esp32.yaml @@ -0,0 +1,26 @@ +sensor: + - platform: adc + id: my_sensor + pin: 32 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.esp8266.yaml b/tests/components/ntc/test.esp8266.yaml new file mode 100644 index 0000000000..370d16d3f7 --- /dev/null +++ b/tests/components/ntc/test.esp8266.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: adc + id: my_sensor + pin: A0 + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C diff --git a/tests/components/ntc/test.rp2040.yaml b/tests/components/ntc/test.rp2040.yaml new file mode 100644 index 0000000000..9c7ba7b539 --- /dev/null +++ b/tests/components/ntc/test.rp2040.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: adc + id: my_sensor + pin: 26 + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C From c36d7c0c3c758849ad3af52144aaccd6de6491ba Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:25:02 -0500 Subject: [PATCH 1466/2607] Add some components to the new testing framework (Q) (#6218) --- .../qmc5883l/test.esp32-c3-idf.yaml | 19 +++++++++++++++++++ tests/components/qmc5883l/test.esp32-c3.yaml | 19 +++++++++++++++++++ tests/components/qmc5883l/test.esp32-idf.yaml | 19 +++++++++++++++++++ tests/components/qmc5883l/test.esp32.yaml | 19 +++++++++++++++++++ tests/components/qmc5883l/test.esp8266.yaml | 19 +++++++++++++++++++ tests/components/qmc5883l/test.rp2040.yaml | 19 +++++++++++++++++++ .../components/qmp6988/test.esp32-c3-idf.yaml | 16 ++++++++++++++++ tests/components/qmp6988/test.esp32-c3.yaml | 16 ++++++++++++++++ tests/components/qmp6988/test.esp32-idf.yaml | 16 ++++++++++++++++ tests/components/qmp6988/test.esp32.yaml | 16 ++++++++++++++++ tests/components/qmp6988/test.esp8266.yaml | 16 ++++++++++++++++ tests/components/qmp6988/test.rp2040.yaml | 16 ++++++++++++++++ .../components/qr_code/test.esp32-c3-idf.yaml | 17 +++++++++++++++++ tests/components/qr_code/test.esp32-c3.yaml | 17 +++++++++++++++++ tests/components/qr_code/test.esp32-idf.yaml | 17 +++++++++++++++++ tests/components/qr_code/test.esp32.yaml | 17 +++++++++++++++++ tests/components/qr_code/test.esp8266.yaml | 17 +++++++++++++++++ tests/components/qr_code/test.rp2040.yaml | 17 +++++++++++++++++ .../qwiic_pir/test.esp32-c3-idf.yaml | 8 ++++++++ tests/components/qwiic_pir/test.esp32-c3.yaml | 8 ++++++++ .../components/qwiic_pir/test.esp32-idf.yaml | 8 ++++++++ tests/components/qwiic_pir/test.esp32.yaml | 8 ++++++++ tests/components/qwiic_pir/test.esp8266.yaml | 8 ++++++++ tests/components/qwiic_pir/test.rp2040.yaml | 8 ++++++++ 24 files changed, 360 insertions(+) create mode 100644 tests/components/qmc5883l/test.esp32-c3-idf.yaml create mode 100644 tests/components/qmc5883l/test.esp32-c3.yaml create mode 100644 tests/components/qmc5883l/test.esp32-idf.yaml create mode 100644 tests/components/qmc5883l/test.esp32.yaml create mode 100644 tests/components/qmc5883l/test.esp8266.yaml create mode 100644 tests/components/qmc5883l/test.rp2040.yaml create mode 100644 tests/components/qmp6988/test.esp32-c3-idf.yaml create mode 100644 tests/components/qmp6988/test.esp32-c3.yaml create mode 100644 tests/components/qmp6988/test.esp32-idf.yaml create mode 100644 tests/components/qmp6988/test.esp32.yaml create mode 100644 tests/components/qmp6988/test.esp8266.yaml create mode 100644 tests/components/qmp6988/test.rp2040.yaml create mode 100644 tests/components/qr_code/test.esp32-c3-idf.yaml create mode 100644 tests/components/qr_code/test.esp32-c3.yaml create mode 100644 tests/components/qr_code/test.esp32-idf.yaml create mode 100644 tests/components/qr_code/test.esp32.yaml create mode 100644 tests/components/qr_code/test.esp8266.yaml create mode 100644 tests/components/qr_code/test.rp2040.yaml create mode 100644 tests/components/qwiic_pir/test.esp32-c3-idf.yaml create mode 100644 tests/components/qwiic_pir/test.esp32-c3.yaml create mode 100644 tests/components/qwiic_pir/test.esp32-idf.yaml create mode 100644 tests/components/qwiic_pir/test.esp32.yaml create mode 100644 tests/components/qwiic_pir/test.esp8266.yaml create mode 100644 tests/components/qwiic_pir/test.rp2040.yaml diff --git a/tests/components/qmc5883l/test.esp32-c3-idf.yaml b/tests/components/qmc5883l/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c638f7e5be --- /dev/null +++ b/tests/components/qmc5883l/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32-c3.yaml b/tests/components/qmc5883l/test.esp32-c3.yaml new file mode 100644 index 0000000000..c638f7e5be --- /dev/null +++ b/tests/components/qmc5883l/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32-idf.yaml b/tests/components/qmc5883l/test.esp32-idf.yaml new file mode 100644 index 0000000000..1aafa86cfa --- /dev/null +++ b/tests/components/qmc5883l/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 16 + sda: 17 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32.yaml b/tests/components/qmc5883l/test.esp32.yaml new file mode 100644 index 0000000000..1aafa86cfa --- /dev/null +++ b/tests/components/qmc5883l/test.esp32.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 16 + sda: 17 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp8266.yaml b/tests/components/qmc5883l/test.esp8266.yaml new file mode 100644 index 0000000000..c638f7e5be --- /dev/null +++ b/tests/components/qmc5883l/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmc5883l/test.rp2040.yaml b/tests/components/qmc5883l/test.rp2040.yaml new file mode 100644 index 0000000000..c638f7e5be --- /dev/null +++ b/tests/components/qmc5883l/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_qmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: qmc5883l + address: 0x0D + field_strength_x: + name: QMC5883L Field Strength X + field_strength_y: + name: QMC5883L Field Strength Y + field_strength_z: + name: QMC5883L Field Strength Z + heading: + name: QMC5883L Heading + range: 800uT + oversampling: 256x + update_interval: 15s diff --git a/tests/components/qmp6988/test.esp32-c3-idf.yaml b/tests/components/qmp6988/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..bcd87ae6b8 --- /dev/null +++ b/tests/components/qmp6988/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 5 + sda: 4 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qmp6988/test.esp32-c3.yaml b/tests/components/qmp6988/test.esp32-c3.yaml new file mode 100644 index 0000000000..bcd87ae6b8 --- /dev/null +++ b/tests/components/qmp6988/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 5 + sda: 4 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qmp6988/test.esp32-idf.yaml b/tests/components/qmp6988/test.esp32-idf.yaml new file mode 100644 index 0000000000..f3fbf75bbe --- /dev/null +++ b/tests/components/qmp6988/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 16 + sda: 17 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qmp6988/test.esp32.yaml b/tests/components/qmp6988/test.esp32.yaml new file mode 100644 index 0000000000..f3fbf75bbe --- /dev/null +++ b/tests/components/qmp6988/test.esp32.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 16 + sda: 17 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qmp6988/test.esp8266.yaml b/tests/components/qmp6988/test.esp8266.yaml new file mode 100644 index 0000000000..bcd87ae6b8 --- /dev/null +++ b/tests/components/qmp6988/test.esp8266.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 5 + sda: 4 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qmp6988/test.rp2040.yaml b/tests/components/qmp6988/test.rp2040.yaml new file mode 100644 index 0000000000..bcd87ae6b8 --- /dev/null +++ b/tests/components/qmp6988/test.rp2040.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_qmp6988 + scl: 5 + sda: 4 + +sensor: + - platform: qmp6988 + temperature: + name: QMP6988 Temperature + oversampling: 32x + pressure: + name: QMP6988 Pressure + oversampling: 2x + address: 0x70 + update_interval: 30s + iir_filter: 16x diff --git a/tests/components/qr_code/test.esp32-c3-idf.yaml b/tests/components/qr_code/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3e875c026c --- /dev/null +++ b/tests/components/qr_code/test.esp32-c3-idf.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qr_code/test.esp32-c3.yaml b/tests/components/qr_code/test.esp32-c3.yaml new file mode 100644 index 0000000000..3e875c026c --- /dev/null +++ b/tests/components/qr_code/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qr_code/test.esp32-idf.yaml b/tests/components/qr_code/test.esp32-idf.yaml new file mode 100644 index 0000000000..b354a3f512 --- /dev/null +++ b/tests/components/qr_code/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qr_code/test.esp32.yaml b/tests/components/qr_code/test.esp32.yaml new file mode 100644 index 0000000000..b354a3f512 --- /dev/null +++ b/tests/components/qr_code/test.esp32.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qr_code/test.esp8266.yaml b/tests/components/qr_code/test.esp8266.yaml new file mode 100644 index 0000000000..dd0d75c472 --- /dev/null +++ b/tests/components/qr_code/test.esp8266.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 5 + dc_pin: 15 + reset_pin: 16 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qr_code/test.rp2040.yaml b/tests/components/qr_code/test.rp2040.yaml new file mode 100644 index 0000000000..b0e046d275 --- /dev/null +++ b/tests/components/qr_code/test.rp2040.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_main_lcd + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 20 + dc_pin: 21 + reset_pin: 22 + +qr_code: + - id: homepage_qr + value: https://esphome.io/index.html diff --git a/tests/components/qwiic_pir/test.esp32-c3-idf.yaml b/tests/components/qwiic_pir/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ad52ac91c5 --- /dev/null +++ b/tests/components/qwiic_pir/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 5 + sda: 4 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor diff --git a/tests/components/qwiic_pir/test.esp32-c3.yaml b/tests/components/qwiic_pir/test.esp32-c3.yaml new file mode 100644 index 0000000000..ad52ac91c5 --- /dev/null +++ b/tests/components/qwiic_pir/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 5 + sda: 4 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor diff --git a/tests/components/qwiic_pir/test.esp32-idf.yaml b/tests/components/qwiic_pir/test.esp32-idf.yaml new file mode 100644 index 0000000000..da2e275cf3 --- /dev/null +++ b/tests/components/qwiic_pir/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 16 + sda: 17 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor diff --git a/tests/components/qwiic_pir/test.esp32.yaml b/tests/components/qwiic_pir/test.esp32.yaml new file mode 100644 index 0000000000..da2e275cf3 --- /dev/null +++ b/tests/components/qwiic_pir/test.esp32.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 16 + sda: 17 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor diff --git a/tests/components/qwiic_pir/test.esp8266.yaml b/tests/components/qwiic_pir/test.esp8266.yaml new file mode 100644 index 0000000000..ad52ac91c5 --- /dev/null +++ b/tests/components/qwiic_pir/test.esp8266.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 5 + sda: 4 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor diff --git a/tests/components/qwiic_pir/test.rp2040.yaml b/tests/components/qwiic_pir/test.rp2040.yaml new file mode 100644 index 0000000000..ad52ac91c5 --- /dev/null +++ b/tests/components/qwiic_pir/test.rp2040.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_qwiic_pir + scl: 5 + sda: 4 + +binary_sensor: + - platform: qwiic_pir + name: Qwiic PIR Motion Sensor From dc071bed24bd5ee29f386c2eddd70c972a61fdf5 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Mar 2024 20:26:50 -0500 Subject: [PATCH 1467/2607] Add some components to the new testing framework (U) (#6230) --- tests/components/uart/test.esp32-c3-idf.yaml | 15 ++++++++++ tests/components/uart/test.esp32-c3.yaml | 15 ++++++++++ tests/components/uart/test.esp32-idf.yaml | 15 ++++++++++ tests/components/uart/test.esp32.yaml | 15 ++++++++++ tests/components/uart/test.esp8266.yaml | 15 ++++++++++ tests/components/uart/test.rp2040.yaml | 15 ++++++++++ .../ufire_ec/test.esp32-c3-idf.yaml | 25 ++++++++++++++++ tests/components/ufire_ec/test.esp32-c3.yaml | 25 ++++++++++++++++ tests/components/ufire_ec/test.esp32-idf.yaml | 25 ++++++++++++++++ tests/components/ufire_ec/test.esp32.yaml | 25 ++++++++++++++++ tests/components/ufire_ec/test.esp8266.yaml | 25 ++++++++++++++++ tests/components/ufire_ec/test.rp2040.yaml | 25 ++++++++++++++++ .../ufire_ise/test.esp32-c3-idf.yaml | 25 ++++++++++++++++ tests/components/ufire_ise/test.esp32-c3.yaml | 25 ++++++++++++++++ .../components/ufire_ise/test.esp32-idf.yaml | 25 ++++++++++++++++ tests/components/ufire_ise/test.esp32.yaml | 25 ++++++++++++++++ tests/components/ufire_ise/test.esp8266.yaml | 25 ++++++++++++++++ tests/components/ufire_ise/test.rp2040.yaml | 25 ++++++++++++++++ .../components/uln2003/test.esp32-c3-idf.yaml | 29 +++++++++++++++++++ tests/components/uln2003/test.esp32-c3.yaml | 29 +++++++++++++++++++ tests/components/uln2003/test.esp32-idf.yaml | 29 +++++++++++++++++++ tests/components/uln2003/test.esp32.yaml | 29 +++++++++++++++++++ tests/components/uln2003/test.esp8266.yaml | 29 +++++++++++++++++++ tests/components/uln2003/test.rp2040.yaml | 29 +++++++++++++++++++ .../ultrasonic/test.esp32-c3-idf.yaml | 7 +++++ .../components/ultrasonic/test.esp32-c3.yaml | 7 +++++ .../components/ultrasonic/test.esp32-idf.yaml | 7 +++++ tests/components/ultrasonic/test.esp32.yaml | 7 +++++ tests/components/ultrasonic/test.esp8266.yaml | 7 +++++ tests/components/ultrasonic/test.rp2040.yaml | 7 +++++ .../components/uptime/test.esp32-c3-idf.yaml | 3 ++ tests/components/uptime/test.esp32-c3.yaml | 3 ++ tests/components/uptime/test.esp32-idf.yaml | 3 ++ tests/components/uptime/test.esp32.yaml | 3 ++ tests/components/uptime/test.esp8266.yaml | 3 ++ tests/components/uptime/test.rp2040.yaml | 3 ++ 36 files changed, 624 insertions(+) create mode 100644 tests/components/uart/test.esp32-c3-idf.yaml create mode 100644 tests/components/uart/test.esp32-c3.yaml create mode 100644 tests/components/uart/test.esp32-idf.yaml create mode 100644 tests/components/uart/test.esp32.yaml create mode 100644 tests/components/uart/test.esp8266.yaml create mode 100644 tests/components/uart/test.rp2040.yaml create mode 100644 tests/components/ufire_ec/test.esp32-c3-idf.yaml create mode 100644 tests/components/ufire_ec/test.esp32-c3.yaml create mode 100644 tests/components/ufire_ec/test.esp32-idf.yaml create mode 100644 tests/components/ufire_ec/test.esp32.yaml create mode 100644 tests/components/ufire_ec/test.esp8266.yaml create mode 100644 tests/components/ufire_ec/test.rp2040.yaml create mode 100644 tests/components/ufire_ise/test.esp32-c3-idf.yaml create mode 100644 tests/components/ufire_ise/test.esp32-c3.yaml create mode 100644 tests/components/ufire_ise/test.esp32-idf.yaml create mode 100644 tests/components/ufire_ise/test.esp32.yaml create mode 100644 tests/components/ufire_ise/test.esp8266.yaml create mode 100644 tests/components/ufire_ise/test.rp2040.yaml create mode 100644 tests/components/uln2003/test.esp32-c3-idf.yaml create mode 100644 tests/components/uln2003/test.esp32-c3.yaml create mode 100644 tests/components/uln2003/test.esp32-idf.yaml create mode 100644 tests/components/uln2003/test.esp32.yaml create mode 100644 tests/components/uln2003/test.esp8266.yaml create mode 100644 tests/components/uln2003/test.rp2040.yaml create mode 100644 tests/components/ultrasonic/test.esp32-c3-idf.yaml create mode 100644 tests/components/ultrasonic/test.esp32-c3.yaml create mode 100644 tests/components/ultrasonic/test.esp32-idf.yaml create mode 100644 tests/components/ultrasonic/test.esp32.yaml create mode 100644 tests/components/ultrasonic/test.esp8266.yaml create mode 100644 tests/components/ultrasonic/test.rp2040.yaml create mode 100644 tests/components/uptime/test.esp32-c3-idf.yaml create mode 100644 tests/components/uptime/test.esp32-c3.yaml create mode 100644 tests/components/uptime/test.esp32-idf.yaml create mode 100644 tests/components/uptime/test.esp32.yaml create mode 100644 tests/components/uptime/test.esp8266.yaml create mode 100644 tests/components/uptime/test.rp2040.yaml diff --git a/tests/components/uart/test.esp32-c3-idf.yaml b/tests/components/uart/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..09178f1663 --- /dev/null +++ b/tests/components/uart/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test.esp32-c3.yaml b/tests/components/uart/test.esp32-c3.yaml new file mode 100644 index 0000000000..09178f1663 --- /dev/null +++ b/tests/components/uart/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test.esp32-idf.yaml b/tests/components/uart/test.esp32-idf.yaml new file mode 100644 index 0000000000..bef5b460ab --- /dev/null +++ b/tests/components/uart/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test.esp32.yaml b/tests/components/uart/test.esp32.yaml new file mode 100644 index 0000000000..bef5b460ab --- /dev/null +++ b/tests/components/uart/test.esp32.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test.esp8266.yaml b/tests/components/uart/test.esp8266.yaml new file mode 100644 index 0000000000..09178f1663 --- /dev/null +++ b/tests/components/uart/test.esp8266.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test.rp2040.yaml b/tests/components/uart/test.rp2040.yaml new file mode 100644 index 0000000000..09178f1663 --- /dev/null +++ b/tests/components/uart/test.rp2040.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/ufire_ec/test.esp32-c3-idf.yaml b/tests/components/ufire_ec/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..aa72c992b8 --- /dev/null +++ b/tests/components/ufire_ec/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ec/test.esp32-c3.yaml b/tests/components/ufire_ec/test.esp32-c3.yaml new file mode 100644 index 0000000000..aa72c992b8 --- /dev/null +++ b/tests/components/ufire_ec/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ec/test.esp32-idf.yaml b/tests/components/ufire_ec/test.esp32-idf.yaml new file mode 100644 index 0000000000..5e6a0daa9e --- /dev/null +++ b/tests/components/ufire_ec/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 16 + sda: 17 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ec/test.esp32.yaml b/tests/components/ufire_ec/test.esp32.yaml new file mode 100644 index 0000000000..5e6a0daa9e --- /dev/null +++ b/tests/components/ufire_ec/test.esp32.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 16 + sda: 17 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ec/test.esp8266.yaml b/tests/components/ufire_ec/test.esp8266.yaml new file mode 100644 index 0000000000..aa72c992b8 --- /dev/null +++ b/tests/components/ufire_ec/test.esp8266.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ec/test.rp2040.yaml b/tests/components/ufire_ec/test.rp2040.yaml new file mode 100644 index 0000000000..aa72c992b8 --- /dev/null +++ b/tests/components/ufire_ec/test.rp2040.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ec.calibrate_probe: + id: ufire_ec_board + solution: 0.146 + temperature: !lambda "return id(test_sensor).state;" + - ufire_ec.reset: + +i2c: + - id: i2c_ufire_ec + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ec + id: ufire_ec_board + ec: + name: Ufire EC + temperature_sensor: test_sensor + temperature_compensation: 20.0 + temperature_coefficient: 0.019 diff --git a/tests/components/ufire_ise/test.esp32-c3-idf.yaml b/tests/components/ufire_ise/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..36aec73113 --- /dev/null +++ b/tests/components/ufire_ise/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/ufire_ise/test.esp32-c3.yaml b/tests/components/ufire_ise/test.esp32-c3.yaml new file mode 100644 index 0000000000..36aec73113 --- /dev/null +++ b/tests/components/ufire_ise/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/ufire_ise/test.esp32-idf.yaml b/tests/components/ufire_ise/test.esp32-idf.yaml new file mode 100644 index 0000000000..9ed0ac433a --- /dev/null +++ b/tests/components/ufire_ise/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 16 + sda: 17 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/ufire_ise/test.esp32.yaml b/tests/components/ufire_ise/test.esp32.yaml new file mode 100644 index 0000000000..9ed0ac433a --- /dev/null +++ b/tests/components/ufire_ise/test.esp32.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 16 + sda: 17 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/ufire_ise/test.esp8266.yaml b/tests/components/ufire_ise/test.esp8266.yaml new file mode 100644 index 0000000000..36aec73113 --- /dev/null +++ b/tests/components/ufire_ise/test.esp8266.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/ufire_ise/test.rp2040.yaml b/tests/components/ufire_ise/test.rp2040.yaml new file mode 100644 index 0000000000..36aec73113 --- /dev/null +++ b/tests/components/ufire_ise/test.rp2040.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - ufire_ise.calibrate_probe_high: + id: ufire_ise_sensor + solution: 7.0 + - ufire_ise.calibrate_probe_low: + id: ufire_ise_sensor + solution: 4.0 + - ufire_ise.reset: + +i2c: + - id: i2c_ufire_ise + scl: 5 + sda: 4 + +sensor: + - platform: template + id: test_sensor + lambda: "return 21;" + - platform: ufire_ise + id: ufire_ise_sensor + temperature_sensor: test_sensor + ph: + name: Ufire pH diff --git a/tests/components/uln2003/test.esp32-c3-idf.yaml b/tests/components/uln2003/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2d19d4dba3 --- /dev/null +++ b/tests/components/uln2003/test.esp32-c3-idf.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 0 + pin_b: 1 + pin_c: 2 + pin_d: 3 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/uln2003/test.esp32-c3.yaml b/tests/components/uln2003/test.esp32-c3.yaml new file mode 100644 index 0000000000..2d19d4dba3 --- /dev/null +++ b/tests/components/uln2003/test.esp32-c3.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 0 + pin_b: 1 + pin_c: 2 + pin_d: 3 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/uln2003/test.esp32-idf.yaml b/tests/components/uln2003/test.esp32-idf.yaml new file mode 100644 index 0000000000..61a6e94396 --- /dev/null +++ b/tests/components/uln2003/test.esp32-idf.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 12 + pin_b: 13 + pin_c: 14 + pin_d: 15 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/uln2003/test.esp32.yaml b/tests/components/uln2003/test.esp32.yaml new file mode 100644 index 0000000000..61a6e94396 --- /dev/null +++ b/tests/components/uln2003/test.esp32.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 12 + pin_b: 13 + pin_c: 14 + pin_d: 15 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/uln2003/test.esp8266.yaml b/tests/components/uln2003/test.esp8266.yaml new file mode 100644 index 0000000000..61a6e94396 --- /dev/null +++ b/tests/components/uln2003/test.esp8266.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 12 + pin_b: 13 + pin_c: 14 + pin_d: 15 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/uln2003/test.rp2040.yaml b/tests/components/uln2003/test.rp2040.yaml new file mode 100644 index 0000000000..2d19d4dba3 --- /dev/null +++ b/tests/components/uln2003/test.rp2040.yaml @@ -0,0 +1,29 @@ +esphome: + on_boot: + then: + - stepper.report_position: + id: uln2003_stepper + position: 250 + - stepper.set_target: + id: uln2003_stepper + target: 250 + - stepper.set_acceleration: + id: uln2003_stepper + acceleration: 250 steps/s^2 + - stepper.set_deceleration: + id: uln2003_stepper + deceleration: 250 steps/s^2 + - stepper.set_speed: + id: uln2003_stepper + speed: 250 steps/s + +stepper: + - platform: uln2003 + id: uln2003_stepper + pin_a: 0 + pin_b: 1 + pin_c: 2 + pin_d: 3 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 diff --git a/tests/components/ultrasonic/test.esp32-c3-idf.yaml b/tests/components/ultrasonic/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.esp32-c3.yaml b/tests/components/ultrasonic/test.esp32-c3.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.esp32-idf.yaml b/tests/components/ultrasonic/test.esp32-idf.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.esp32.yaml b/tests/components/ultrasonic/test.esp32.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.esp32.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.esp8266.yaml b/tests/components/ultrasonic/test.esp8266.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.esp8266.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.rp2040.yaml b/tests/components/ultrasonic/test.rp2040.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/test.rp2040.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/uptime/test.esp32-c3-idf.yaml b/tests/components/uptime/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.esp32-c3.yaml b/tests/components/uptime/test.esp32-c3.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.esp32-idf.yaml b/tests/components/uptime/test.esp32-idf.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.esp32.yaml b/tests/components/uptime/test.esp32.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.esp32.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.esp8266.yaml b/tests/components/uptime/test.esp8266.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.esp8266.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.rp2040.yaml b/tests/components/uptime/test.rp2040.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/test.rp2040.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor From 54a68bf069fc11d582f7c50b143b6f428f385e3f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Mar 2024 02:15:50 -0500 Subject: [PATCH 1468/2607] Fix spacing in new test yaml (#6441) --- .../growatt_solar/test.esp32-c3-idf.yaml | 30 +++++++++---------- .../growatt_solar/test.esp32-c3.yaml | 30 +++++++++---------- .../growatt_solar/test.esp32-idf.yaml | 30 +++++++++---------- .../components/growatt_solar/test.esp32.yaml | 30 +++++++++---------- .../growatt_solar/test.esp8266.yaml | 30 +++++++++---------- .../components/growatt_solar/test.rp2040.yaml | 30 +++++++++---------- .../key_collector/test.esp32-c3-idf.yaml | 6 ++-- .../key_collector/test.esp32-c3.yaml | 6 ++-- .../key_collector/test.esp32-idf.yaml | 6 ++-- .../components/key_collector/test.esp32.yaml | 6 ++-- .../key_collector/test.esp8266.yaml | 6 ++-- .../components/key_collector/test.rp2040.yaml | 6 ++-- 12 files changed, 108 insertions(+), 108 deletions(-) diff --git a/tests/components/growatt_solar/test.esp32-c3-idf.yaml b/tests/components/growatt_solar/test.esp32-c3-idf.yaml index 3b5e2e4ce4..7e73897856 100644 --- a/tests/components/growatt_solar/test.esp32-c3-idf.yaml +++ b/tests/components/growatt_solar/test.esp32-c3-idf.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/growatt_solar/test.esp32-c3.yaml b/tests/components/growatt_solar/test.esp32-c3.yaml index 3b5e2e4ce4..7e73897856 100644 --- a/tests/components/growatt_solar/test.esp32-c3.yaml +++ b/tests/components/growatt_solar/test.esp32-c3.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/growatt_solar/test.esp32-idf.yaml b/tests/components/growatt_solar/test.esp32-idf.yaml index a0670fdbd6..654f2ccedf 100644 --- a/tests/components/growatt_solar/test.esp32-idf.yaml +++ b/tests/components/growatt_solar/test.esp32-idf.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/growatt_solar/test.esp32.yaml b/tests/components/growatt_solar/test.esp32.yaml index a0670fdbd6..654f2ccedf 100644 --- a/tests/components/growatt_solar/test.esp32.yaml +++ b/tests/components/growatt_solar/test.esp32.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/growatt_solar/test.esp8266.yaml b/tests/components/growatt_solar/test.esp8266.yaml index fed27ffda1..a1cf8267ae 100644 --- a/tests/components/growatt_solar/test.esp8266.yaml +++ b/tests/components/growatt_solar/test.esp8266.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/growatt_solar/test.rp2040.yaml b/tests/components/growatt_solar/test.rp2040.yaml index 3b5e2e4ce4..7e73897856 100644 --- a/tests/components/growatt_solar/test.rp2040.yaml +++ b/tests/components/growatt_solar/test.rp2040.yaml @@ -15,39 +15,39 @@ sensor: name: Growatt Status Code phase_a: voltage: - name: Growatt Voltage Phase A + name: Growatt Voltage Phase A current: - name: Growatt Current Phase A + name: Growatt Current Phase A active_power: - name: Growatt Power Phase A + name: Growatt Power Phase A phase_b: voltage: - name: Growatt Voltage Phase B + name: Growatt Voltage Phase B current: - name: Growatt Current Phase B + name: Growatt Current Phase B active_power: - name: Growatt Power Phase B + name: Growatt Power Phase B phase_c: voltage: - name: Growatt Voltage Phase C + name: Growatt Voltage Phase C current: - name: Growatt Current Phase C + name: Growatt Current Phase C active_power: - name: Growatt Power Phase C + name: Growatt Power Phase C pv1: voltage: - name: Growatt PV1 Voltage + name: Growatt PV1 Voltage current: - name: Growatt PV1 Current + name: Growatt PV1 Current active_power: - name: Growatt PV1 Active Power + name: Growatt PV1 Active Power pv2: voltage: - name: Growatt PV2 Voltage + name: Growatt PV2 Voltage current: - name: Growatt PV2 Current + name: Growatt PV2 Current active_power: - name: Growatt PV2 Active Power + name: Growatt PV2 Active Power active_power: name: Growatt Grid Active Power pv_active_power: diff --git a/tests/components/key_collector/test.esp32-c3-idf.yaml b/tests/components/key_collector/test.esp32-c3-idf.yaml index a186d4fa23..1f133c5cd8 100644 --- a/tests/components/key_collector/test.esp32-c3-idf.yaml +++ b/tests/components/key_collector/test.esp32-c3-idf.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] diff --git a/tests/components/key_collector/test.esp32-c3.yaml b/tests/components/key_collector/test.esp32-c3.yaml index a186d4fa23..1f133c5cd8 100644 --- a/tests/components/key_collector/test.esp32-c3.yaml +++ b/tests/components/key_collector/test.esp32-c3.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] diff --git a/tests/components/key_collector/test.esp32-idf.yaml b/tests/components/key_collector/test.esp32-idf.yaml index d357b33279..7cbe9c0fc1 100644 --- a/tests/components/key_collector/test.esp32-idf.yaml +++ b/tests/components/key_collector/test.esp32-idf.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] diff --git a/tests/components/key_collector/test.esp32.yaml b/tests/components/key_collector/test.esp32.yaml index d357b33279..7cbe9c0fc1 100644 --- a/tests/components/key_collector/test.esp32.yaml +++ b/tests/components/key_collector/test.esp32.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] diff --git a/tests/components/key_collector/test.esp8266.yaml b/tests/components/key_collector/test.esp8266.yaml index d357b33279..7cbe9c0fc1 100644 --- a/tests/components/key_collector/test.esp8266.yaml +++ b/tests/components/key_collector/test.esp8266.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] diff --git a/tests/components/key_collector/test.rp2040.yaml b/tests/components/key_collector/test.rp2040.yaml index a186d4fa23..1f133c5cd8 100644 --- a/tests/components/key_collector/test.rp2040.yaml +++ b/tests/components/key_collector/test.rp2040.yaml @@ -17,12 +17,12 @@ key_collector: on_progress: - logger.log: format: "input progress: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] on_result: - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)"] on_timeout: - logger.log: format: "input timeout: '%s', started by '%c'" - args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + args: ['x.c_str()', "(start == 0 ? '~' : start)"] From 0630cdded376eeefd3a628cfa19d70b1f2e764c7 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Mar 2024 02:15:59 -0500 Subject: [PATCH 1469/2607] Add some components to the new testing framework (W) (#6232) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/wake_on_lan/test.esp32-c3.yaml | 9 ++ tests/components/wake_on_lan/test.esp32.yaml | 9 ++ .../components/wake_on_lan/test.esp8266.yaml | 9 ++ tests/components/wake_on_lan/test.rp2040.yaml | 9 ++ .../waveshare_epaper/test.esp32-c3-idf.yaml | 107 ++++++++++++++++++ .../waveshare_epaper/test.esp32-c3.yaml | 107 ++++++++++++++++++ .../waveshare_epaper/test.esp32-idf.yaml | 107 ++++++++++++++++++ .../waveshare_epaper/test.esp8266.yaml | 107 ++++++++++++++++++ .../waveshare_epaper/test.rp2040.yaml | 107 ++++++++++++++++++ .../web_server/test.esp32-c3-idf.yaml | 7 ++ .../components/web_server/test.esp32-c3.yaml | 7 ++ .../components/web_server/test.esp32-idf.yaml | 7 ++ tests/components/web_server/test.esp32.yaml | 7 ++ tests/components/web_server/test.esp8266.yaml | 7 ++ .../whirlpool/test.esp32-c3-idf.yaml | 7 ++ tests/components/whirlpool/test.esp32-c3.yaml | 7 ++ .../components/whirlpool/test.esp32-idf.yaml | 7 ++ tests/components/whirlpool/test.esp32.yaml | 7 ++ tests/components/whirlpool/test.esp8266.yaml | 7 ++ .../components/whynter/test.esp32-c3-idf.yaml | 7 ++ tests/components/whynter/test.esp32-c3.yaml | 7 ++ tests/components/whynter/test.esp32-idf.yaml | 7 ++ tests/components/whynter/test.esp32.yaml | 7 ++ tests/components/whynter/test.esp8266.yaml | 7 ++ .../components/wiegand/test.esp32-c3-idf.yaml | 10 ++ tests/components/wiegand/test.esp32-c3.yaml | 10 ++ tests/components/wiegand/test.esp32-idf.yaml | 10 ++ tests/components/wiegand/test.esp32.yaml | 10 ++ tests/components/wiegand/test.esp8266.yaml | 10 ++ tests/components/wiegand/test.rp2040.yaml | 10 ++ tests/components/wifi/test.esp32-c3-idf.yaml | 9 ++ tests/components/wifi/test.esp32-c3.yaml | 9 ++ tests/components/wifi/test.esp32-idf.yaml | 9 ++ tests/components/wifi/test.esp32.yaml | 9 ++ tests/components/wifi/test.esp8266.yaml | 9 ++ tests/components/wifi/test.rp2040.yaml | 9 ++ .../wifi_info/test.esp32-c3-idf.yaml | 18 +++ tests/components/wifi_info/test.esp32-c3.yaml | 18 +++ .../components/wifi_info/test.esp32-idf.yaml | 18 +++ tests/components/wifi_info/test.esp32.yaml | 18 +++ tests/components/wifi_info/test.esp8266.yaml | 18 +++ tests/components/wifi_info/test.rp2040.yaml | 18 +++ .../wifi_signal/test.esp32-c3-idf.yaml | 8 ++ .../components/wifi_signal/test.esp32-c3.yaml | 8 ++ .../wifi_signal/test.esp32-idf.yaml | 8 ++ tests/components/wifi_signal/test.esp32.yaml | 8 ++ .../components/wifi_signal/test.esp8266.yaml | 8 ++ tests/components/wifi_signal/test.rp2040.yaml | 8 ++ .../wireguard/test.esp32-c3-idf.yaml | 60 ++++++++++ tests/components/wireguard/test.esp32-c3.yaml | 60 ++++++++++ .../components/wl_134/test.esp32-c3-idf.yaml | 10 ++ tests/components/wl_134/test.esp32-c3.yaml | 10 ++ tests/components/wl_134/test.esp32-idf.yaml | 10 ++ tests/components/wl_134/test.esp32.yaml | 10 ++ tests/components/wl_134/test.esp8266.yaml | 10 ++ tests/components/wl_134/test.rp2040.yaml | 10 ++ tests/components/wled/test.esp32-c3.yaml | 17 +++ tests/components/wled/test.esp32.yaml | 17 +++ tests/components/wled/test.esp8266.yaml | 17 +++ 59 files changed, 1177 insertions(+) create mode 100644 tests/components/wake_on_lan/test.esp32-c3.yaml create mode 100644 tests/components/wake_on_lan/test.esp32.yaml create mode 100644 tests/components/wake_on_lan/test.esp8266.yaml create mode 100644 tests/components/wake_on_lan/test.rp2040.yaml create mode 100644 tests/components/waveshare_epaper/test.esp32-c3-idf.yaml create mode 100644 tests/components/waveshare_epaper/test.esp32-c3.yaml create mode 100644 tests/components/waveshare_epaper/test.esp32-idf.yaml create mode 100644 tests/components/waveshare_epaper/test.esp8266.yaml create mode 100644 tests/components/waveshare_epaper/test.rp2040.yaml create mode 100644 tests/components/web_server/test.esp32-c3-idf.yaml create mode 100644 tests/components/web_server/test.esp32-c3.yaml create mode 100644 tests/components/web_server/test.esp32-idf.yaml create mode 100644 tests/components/web_server/test.esp32.yaml create mode 100644 tests/components/web_server/test.esp8266.yaml create mode 100644 tests/components/whirlpool/test.esp32-c3-idf.yaml create mode 100644 tests/components/whirlpool/test.esp32-c3.yaml create mode 100644 tests/components/whirlpool/test.esp32-idf.yaml create mode 100644 tests/components/whirlpool/test.esp32.yaml create mode 100644 tests/components/whirlpool/test.esp8266.yaml create mode 100644 tests/components/whynter/test.esp32-c3-idf.yaml create mode 100644 tests/components/whynter/test.esp32-c3.yaml create mode 100644 tests/components/whynter/test.esp32-idf.yaml create mode 100644 tests/components/whynter/test.esp32.yaml create mode 100644 tests/components/whynter/test.esp8266.yaml create mode 100644 tests/components/wiegand/test.esp32-c3-idf.yaml create mode 100644 tests/components/wiegand/test.esp32-c3.yaml create mode 100644 tests/components/wiegand/test.esp32-idf.yaml create mode 100644 tests/components/wiegand/test.esp32.yaml create mode 100644 tests/components/wiegand/test.esp8266.yaml create mode 100644 tests/components/wiegand/test.rp2040.yaml create mode 100644 tests/components/wifi/test.esp32-c3-idf.yaml create mode 100644 tests/components/wifi/test.esp32-c3.yaml create mode 100644 tests/components/wifi/test.esp32-idf.yaml create mode 100644 tests/components/wifi/test.esp32.yaml create mode 100644 tests/components/wifi/test.esp8266.yaml create mode 100644 tests/components/wifi/test.rp2040.yaml create mode 100644 tests/components/wifi_info/test.esp32-c3-idf.yaml create mode 100644 tests/components/wifi_info/test.esp32-c3.yaml create mode 100644 tests/components/wifi_info/test.esp32-idf.yaml create mode 100644 tests/components/wifi_info/test.esp32.yaml create mode 100644 tests/components/wifi_info/test.esp8266.yaml create mode 100644 tests/components/wifi_info/test.rp2040.yaml create mode 100644 tests/components/wifi_signal/test.esp32-c3-idf.yaml create mode 100644 tests/components/wifi_signal/test.esp32-c3.yaml create mode 100644 tests/components/wifi_signal/test.esp32-idf.yaml create mode 100644 tests/components/wifi_signal/test.esp32.yaml create mode 100644 tests/components/wifi_signal/test.esp8266.yaml create mode 100644 tests/components/wifi_signal/test.rp2040.yaml create mode 100644 tests/components/wireguard/test.esp32-c3-idf.yaml create mode 100644 tests/components/wireguard/test.esp32-c3.yaml create mode 100644 tests/components/wl_134/test.esp32-c3-idf.yaml create mode 100644 tests/components/wl_134/test.esp32-c3.yaml create mode 100644 tests/components/wl_134/test.esp32-idf.yaml create mode 100644 tests/components/wl_134/test.esp32.yaml create mode 100644 tests/components/wl_134/test.esp8266.yaml create mode 100644 tests/components/wl_134/test.rp2040.yaml create mode 100644 tests/components/wled/test.esp32-c3.yaml create mode 100644 tests/components/wled/test.esp32.yaml create mode 100644 tests/components/wled/test.esp8266.yaml diff --git a/tests/components/wake_on_lan/test.esp32-c3.yaml b/tests/components/wake_on_lan/test.esp32-c3.yaml new file mode 100644 index 0000000000..6a5351b624 --- /dev/null +++ b/tests/components/wake_on_lan/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: MySSID + password: password1 + +button: + - platform: wake_on_lan + id: wol_1 + name: wol_test_1 + target_mac_address: 12:34:56:78:90:ab diff --git a/tests/components/wake_on_lan/test.esp32.yaml b/tests/components/wake_on_lan/test.esp32.yaml new file mode 100644 index 0000000000..6a5351b624 --- /dev/null +++ b/tests/components/wake_on_lan/test.esp32.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: MySSID + password: password1 + +button: + - platform: wake_on_lan + id: wol_1 + name: wol_test_1 + target_mac_address: 12:34:56:78:90:ab diff --git a/tests/components/wake_on_lan/test.esp8266.yaml b/tests/components/wake_on_lan/test.esp8266.yaml new file mode 100644 index 0000000000..6a5351b624 --- /dev/null +++ b/tests/components/wake_on_lan/test.esp8266.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: MySSID + password: password1 + +button: + - platform: wake_on_lan + id: wol_1 + name: wol_test_1 + target_mac_address: 12:34:56:78:90:ab diff --git a/tests/components/wake_on_lan/test.rp2040.yaml b/tests/components/wake_on_lan/test.rp2040.yaml new file mode 100644 index 0000000000..6a5351b624 --- /dev/null +++ b/tests/components/wake_on_lan/test.rp2040.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: MySSID + password: password1 + +button: + - platform: wake_on_lan + id: wol_1 + name: wol_test_1 + target_mac_address: 12:34:56:78:90:ab diff --git a/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml b/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1c4547b7b4 --- /dev/null +++ b/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml @@ -0,0 +1,107 @@ +spi: + - id: spi_waveshare_epaper + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.13in-ttgo-b1 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90in + full_update_every: 30 + reset_duration: 200ms + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90inv2 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-b + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-bv2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp32-c3.yaml b/tests/components/waveshare_epaper/test.esp32-c3.yaml new file mode 100644 index 0000000000..1c4547b7b4 --- /dev/null +++ b/tests/components/waveshare_epaper/test.esp32-c3.yaml @@ -0,0 +1,107 @@ +spi: + - id: spi_waveshare_epaper + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.13in-ttgo-b1 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90in + full_update_every: 30 + reset_duration: 200ms + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90inv2 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-b + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-bv2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp32-idf.yaml b/tests/components/waveshare_epaper/test.esp32-idf.yaml new file mode 100644 index 0000000000..b6082fcfbf --- /dev/null +++ b/tests/components/waveshare_epaper/test.esp32-idf.yaml @@ -0,0 +1,107 @@ +spi: + - id: spi_bme280 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.13in-ttgo-b1 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90in + full_update_every: 30 + reset_duration: 200ms + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90inv2 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-b + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-bv2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp8266.yaml b/tests/components/waveshare_epaper/test.esp8266.yaml new file mode 100644 index 0000000000..1f076a67be --- /dev/null +++ b/tests/components/waveshare_epaper/test.esp8266.yaml @@ -0,0 +1,107 @@ +spi: + - id: spi_bme280 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.13in-ttgo-b1 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90in + full_update_every: 30 + reset_duration: 200ms + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.90inv2 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-b + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 2.70in-bv2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.rp2040.yaml b/tests/components/waveshare_epaper/test.rp2040.yaml new file mode 100644 index 0000000000..6050062d7e --- /dev/null +++ b/tests/components/waveshare_epaper/test.rp2040.yaml @@ -0,0 +1,107 @@ +spi: + - id: spi_bme280 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 2.13in-ttgo-b1 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 2.90in + full_update_every: 30 + reset_duration: 200ms + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 2.90inv2 + full_update_every: 30 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 2.70in-b + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 2.70in-bv2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 1.54in-m5coreink-m09 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/web_server/test.esp32-c3-idf.yaml b/tests/components/web_server/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp32-c3.yaml b/tests/components/web_server/test.esp32-c3.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp32-idf.yaml b/tests/components/web_server/test.esp32-idf.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp32.yaml b/tests/components/web_server/test.esp32.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/test.esp32.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp8266.yaml b/tests/components/web_server/test.esp8266.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/test.esp8266.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/whirlpool/test.esp32-c3-idf.yaml b/tests/components/whirlpool/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4d0afc39a4 --- /dev/null +++ b/tests/components/whirlpool/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whirlpool + name: Whirlpool Climate diff --git a/tests/components/whirlpool/test.esp32-c3.yaml b/tests/components/whirlpool/test.esp32-c3.yaml new file mode 100644 index 0000000000..4d0afc39a4 --- /dev/null +++ b/tests/components/whirlpool/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whirlpool + name: Whirlpool Climate diff --git a/tests/components/whirlpool/test.esp32-idf.yaml b/tests/components/whirlpool/test.esp32-idf.yaml new file mode 100644 index 0000000000..4d0afc39a4 --- /dev/null +++ b/tests/components/whirlpool/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whirlpool + name: Whirlpool Climate diff --git a/tests/components/whirlpool/test.esp32.yaml b/tests/components/whirlpool/test.esp32.yaml new file mode 100644 index 0000000000..4d0afc39a4 --- /dev/null +++ b/tests/components/whirlpool/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whirlpool + name: Whirlpool Climate diff --git a/tests/components/whirlpool/test.esp8266.yaml b/tests/components/whirlpool/test.esp8266.yaml new file mode 100644 index 0000000000..efd530c160 --- /dev/null +++ b/tests/components/whirlpool/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: whirlpool + name: Whirlpool Climate diff --git a/tests/components/whynter/test.esp32-c3-idf.yaml b/tests/components/whynter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dc8fb9584d --- /dev/null +++ b/tests/components/whynter/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whynter + name: Whynter Climate diff --git a/tests/components/whynter/test.esp32-c3.yaml b/tests/components/whynter/test.esp32-c3.yaml new file mode 100644 index 0000000000..dc8fb9584d --- /dev/null +++ b/tests/components/whynter/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whynter + name: Whynter Climate diff --git a/tests/components/whynter/test.esp32-idf.yaml b/tests/components/whynter/test.esp32-idf.yaml new file mode 100644 index 0000000000..dc8fb9584d --- /dev/null +++ b/tests/components/whynter/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whynter + name: Whynter Climate diff --git a/tests/components/whynter/test.esp32.yaml b/tests/components/whynter/test.esp32.yaml new file mode 100644 index 0000000000..dc8fb9584d --- /dev/null +++ b/tests/components/whynter/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: whynter + name: Whynter Climate diff --git a/tests/components/whynter/test.esp8266.yaml b/tests/components/whynter/test.esp8266.yaml new file mode 100644 index 0000000000..a656a7427d --- /dev/null +++ b/tests/components/whynter/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: whynter + name: Whynter Climate diff --git a/tests/components/wiegand/test.esp32-c3-idf.yaml b/tests/components/wiegand/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.esp32-c3.yaml b/tests/components/wiegand/test.esp32-c3.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.esp32-idf.yaml b/tests/components/wiegand/test.esp32-idf.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.esp32.yaml b/tests/components/wiegand/test.esp32.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.esp32.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.esp8266.yaml b/tests/components/wiegand/test.esp8266.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.esp8266.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.rp2040.yaml b/tests/components/wiegand/test.rp2040.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/test.rp2040.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wifi/test.esp32-c3-idf.yaml b/tests/components/wifi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.esp32-c3.yaml b/tests/components/wifi/test.esp32-c3.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.esp32-idf.yaml b/tests/components/wifi/test.esp32-idf.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.esp32.yaml b/tests/components/wifi/test.esp32.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.esp32.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.esp8266.yaml b/tests/components/wifi/test.esp8266.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.esp8266.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.rp2040.yaml b/tests/components/wifi/test.rp2040.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/test.rp2040.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi_info/test.esp32-c3-idf.yaml b/tests/components/wifi_info/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.esp32-c3.yaml b/tests/components/wifi_info/test.esp32-c3.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.esp32-idf.yaml b/tests/components/wifi_info/test.esp32-idf.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.esp32.yaml b/tests/components/wifi_info/test.esp32.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.esp32.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.esp8266.yaml b/tests/components/wifi_info/test.esp8266.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.esp8266.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.rp2040.yaml b/tests/components/wifi_info/test.rp2040.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/test.rp2040.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_signal/test.esp32-c3-idf.yaml b/tests/components/wifi_signal/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.esp32-c3.yaml b/tests/components/wifi_signal/test.esp32-c3.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.esp32-idf.yaml b/tests/components/wifi_signal/test.esp32-idf.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.esp32.yaml b/tests/components/wifi_signal/test.esp32.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.esp32.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.esp8266.yaml b/tests/components/wifi_signal/test.esp8266.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.esp8266.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.rp2040.yaml b/tests/components/wifi_signal/test.rp2040.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/test.rp2040.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wireguard/test.esp32-c3-idf.yaml b/tests/components/wireguard/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..37d1727842 --- /dev/null +++ b/tests/components/wireguard/test.esp32-c3-idf.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + +wireguard: + id: vpn + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wireguard/test.esp32-c3.yaml b/tests/components/wireguard/test.esp32-c3.yaml new file mode 100644 index 0000000000..37d1727842 --- /dev/null +++ b/tests/components/wireguard/test.esp32-c3.yaml @@ -0,0 +1,60 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + +wireguard: + id: vpn + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wl_134/test.esp32-c3-idf.yaml b/tests/components/wl_134/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7cda1ba060 --- /dev/null +++ b/tests/components/wl_134/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wl_134/test.esp32-c3.yaml b/tests/components/wl_134/test.esp32-c3.yaml new file mode 100644 index 0000000000..7cda1ba060 --- /dev/null +++ b/tests/components/wl_134/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wl_134/test.esp32-idf.yaml b/tests/components/wl_134/test.esp32-idf.yaml new file mode 100644 index 0000000000..d517889d28 --- /dev/null +++ b/tests/components/wl_134/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wl_134/test.esp32.yaml b/tests/components/wl_134/test.esp32.yaml new file mode 100644 index 0000000000..d517889d28 --- /dev/null +++ b/tests/components/wl_134/test.esp32.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wl_134/test.esp8266.yaml b/tests/components/wl_134/test.esp8266.yaml new file mode 100644 index 0000000000..7cda1ba060 --- /dev/null +++ b/tests/components/wl_134/test.esp8266.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wl_134/test.rp2040.yaml b/tests/components/wl_134/test.rp2040.yaml new file mode 100644 index 0000000000..7cda1ba060 --- /dev/null +++ b/tests/components/wl_134/test.rp2040.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_wl_134 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +text_sensor: + - platform: wl_134 + name: Transponder Code + reset: true diff --git a/tests/components/wled/test.esp32-c3.yaml b/tests/components/wled/test.esp32-c3.yaml new file mode 100644 index 0000000000..a24f28e154 --- /dev/null +++ b/tests/components/wled/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +wifi: + ssid: MySSID + password: password1 + +wled: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - wled: diff --git a/tests/components/wled/test.esp32.yaml b/tests/components/wled/test.esp32.yaml new file mode 100644 index 0000000000..a24f28e154 --- /dev/null +++ b/tests/components/wled/test.esp32.yaml @@ -0,0 +1,17 @@ +wifi: + ssid: MySSID + password: password1 + +wled: + +light: + - platform: esp32_rmt_led_strip + id: led_matrix_32x8 + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + effects: + - wled: diff --git a/tests/components/wled/test.esp8266.yaml b/tests/components/wled/test.esp8266.yaml new file mode 100644 index 0000000000..e291af927c --- /dev/null +++ b/tests/components/wled/test.esp8266.yaml @@ -0,0 +1,17 @@ +wifi: + ssid: MySSID + password: password1 + +wled: + +light: + - platform: neopixelbus + id: addr + name: Neopixelbus Light + method: esp8266_uart + num_leds: 5 + pin: 2 + type: GRBW + variant: SK6812 + effects: + - wled: From 92b3d94cc70c52ce18fd92204259c16507036540 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Mar 2024 02:30:13 -0500 Subject: [PATCH 1470/2607] Add some components to the new testing framework (L) (#6195) --- .../lcd_gpio/test.esp32-c3-idf.yaml | 13 ++ tests/components/lcd_gpio/test.esp32-c3.yaml | 13 ++ tests/components/lcd_gpio/test.esp32-idf.yaml | 13 ++ tests/components/lcd_gpio/test.esp32.yaml | 13 ++ tests/components/lcd_gpio/test.esp8266.yaml | 13 ++ tests/components/lcd_gpio/test.rp2040.yaml | 13 ++ .../lcd_menu/test.esp32-c3-idf.yaml | 118 ++++++++++++ tests/components/lcd_menu/test.esp32-c3.yaml | 118 ++++++++++++ tests/components/lcd_menu/test.esp32-idf.yaml | 118 ++++++++++++ tests/components/lcd_menu/test.esp32.yaml | 118 ++++++++++++ tests/components/lcd_menu/test.esp8266.yaml | 118 ++++++++++++ tests/components/lcd_menu/test.rp2040.yaml | 118 ++++++++++++ .../lcd_pcf8574/test.esp32-c3-idf.yaml | 22 +++ .../components/lcd_pcf8574/test.esp32-c3.yaml | 22 +++ .../lcd_pcf8574/test.esp32-idf.yaml | 22 +++ tests/components/lcd_pcf8574/test.esp32.yaml | 22 +++ .../components/lcd_pcf8574/test.esp8266.yaml | 22 +++ tests/components/lcd_pcf8574/test.rp2040.yaml | 22 +++ .../components/ld2410/test.esp32-c3-idf.yaml | 169 ++++++++++++++++++ tests/components/ld2410/test.esp32-c3.yaml | 169 ++++++++++++++++++ tests/components/ld2410/test.esp32-idf.yaml | 169 ++++++++++++++++++ tests/components/ld2410/test.esp32.yaml | 169 ++++++++++++++++++ tests/components/ld2410/test.esp8266.yaml | 169 ++++++++++++++++++ tests/components/ld2410/test.rp2040.yaml | 169 ++++++++++++++++++ .../components/ld2420/test.esp32-c3-idf.yaml | 132 ++++++++++++++ tests/components/ld2420/test.esp32-c3.yaml | 132 ++++++++++++++ tests/components/ld2420/test.esp32-idf.yaml | 132 ++++++++++++++ tests/components/ld2420/test.esp32.yaml | 132 ++++++++++++++ tests/components/ld2420/test.esp8266.yaml | 132 ++++++++++++++ tests/components/ld2420/test.rp2040.yaml | 132 ++++++++++++++ tests/components/ledc/test.esp32-c3-idf.yaml | 11 ++ tests/components/ledc/test.esp32-c3.yaml | 11 ++ tests/components/ledc/test.esp32-idf.yaml | 11 ++ tests/components/ledc/test.esp32.yaml | 11 ++ tests/components/light/test.esp32-c3-idf.yaml | 132 ++++++++++++++ tests/components/light/test.esp32-c3.yaml | 132 ++++++++++++++ tests/components/light/test.esp32-idf.yaml | 132 ++++++++++++++ tests/components/light/test.esp32.yaml | 132 ++++++++++++++ tests/components/light/test.esp8266.yaml | 132 ++++++++++++++ tests/components/light/test.rp2040.yaml | 132 ++++++++++++++ .../components/lightwaverf/test.esp8266.yaml | 13 ++ .../lilygo_t5_47/test.esp32-c3-idf.yaml | 24 +++ .../lilygo_t5_47/test.esp32-c3.yaml | 24 +++ .../lilygo_t5_47/test.esp32-idf.yaml | 24 +++ tests/components/lilygo_t5_47/test.esp32.yaml | 24 +++ .../components/lilygo_t5_47/test.esp8266.yaml | 24 +++ .../components/lilygo_t5_47/test.rp2040.yaml | 24 +++ tests/components/lock/test.esp32-c3-idf.yaml | 36 ++++ tests/components/lock/test.esp32-c3.yaml | 36 ++++ tests/components/lock/test.esp32-idf.yaml | 36 ++++ tests/components/lock/test.esp32.yaml | 36 ++++ tests/components/lock/test.esp8266.yaml | 36 ++++ tests/components/lock/test.rp2040.yaml | 36 ++++ .../components/logger/test.esp32-c3-idf.yaml | 7 + tests/components/logger/test.esp32-c3.yaml | 7 + tests/components/logger/test.esp32-idf.yaml | 7 + tests/components/logger/test.esp32.yaml | 7 + tests/components/logger/test.esp8266.yaml | 7 + tests/components/logger/test.rp2040.yaml | 7 + .../components/ltr390/test.esp32-c3-idf.yaml | 20 +++ tests/components/ltr390/test.esp32-c3.yaml | 20 +++ tests/components/ltr390/test.esp32-idf.yaml | 20 +++ tests/components/ltr390/test.esp32.yaml | 20 +++ tests/components/ltr390/test.esp8266.yaml | 20 +++ tests/components/ltr390/test.rp2040.yaml | 20 +++ 65 files changed, 4095 insertions(+) create mode 100644 tests/components/lcd_gpio/test.esp32-c3-idf.yaml create mode 100644 tests/components/lcd_gpio/test.esp32-c3.yaml create mode 100644 tests/components/lcd_gpio/test.esp32-idf.yaml create mode 100644 tests/components/lcd_gpio/test.esp32.yaml create mode 100644 tests/components/lcd_gpio/test.esp8266.yaml create mode 100644 tests/components/lcd_gpio/test.rp2040.yaml create mode 100644 tests/components/lcd_menu/test.esp32-c3-idf.yaml create mode 100644 tests/components/lcd_menu/test.esp32-c3.yaml create mode 100644 tests/components/lcd_menu/test.esp32-idf.yaml create mode 100644 tests/components/lcd_menu/test.esp32.yaml create mode 100644 tests/components/lcd_menu/test.esp8266.yaml create mode 100644 tests/components/lcd_menu/test.rp2040.yaml create mode 100644 tests/components/lcd_pcf8574/test.esp32-c3-idf.yaml create mode 100644 tests/components/lcd_pcf8574/test.esp32-c3.yaml create mode 100644 tests/components/lcd_pcf8574/test.esp32-idf.yaml create mode 100644 tests/components/lcd_pcf8574/test.esp32.yaml create mode 100644 tests/components/lcd_pcf8574/test.esp8266.yaml create mode 100644 tests/components/lcd_pcf8574/test.rp2040.yaml create mode 100644 tests/components/ld2410/test.esp32-c3-idf.yaml create mode 100644 tests/components/ld2410/test.esp32-c3.yaml create mode 100644 tests/components/ld2410/test.esp32-idf.yaml create mode 100644 tests/components/ld2410/test.esp32.yaml create mode 100644 tests/components/ld2410/test.esp8266.yaml create mode 100644 tests/components/ld2410/test.rp2040.yaml create mode 100644 tests/components/ld2420/test.esp32-c3-idf.yaml create mode 100644 tests/components/ld2420/test.esp32-c3.yaml create mode 100644 tests/components/ld2420/test.esp32-idf.yaml create mode 100644 tests/components/ld2420/test.esp32.yaml create mode 100644 tests/components/ld2420/test.esp8266.yaml create mode 100644 tests/components/ld2420/test.rp2040.yaml create mode 100644 tests/components/ledc/test.esp32-c3-idf.yaml create mode 100644 tests/components/ledc/test.esp32-c3.yaml create mode 100644 tests/components/ledc/test.esp32-idf.yaml create mode 100644 tests/components/ledc/test.esp32.yaml create mode 100644 tests/components/light/test.esp32-c3-idf.yaml create mode 100644 tests/components/light/test.esp32-c3.yaml create mode 100644 tests/components/light/test.esp32-idf.yaml create mode 100644 tests/components/light/test.esp32.yaml create mode 100644 tests/components/light/test.esp8266.yaml create mode 100644 tests/components/light/test.rp2040.yaml create mode 100644 tests/components/lightwaverf/test.esp8266.yaml create mode 100644 tests/components/lilygo_t5_47/test.esp32-c3-idf.yaml create mode 100644 tests/components/lilygo_t5_47/test.esp32-c3.yaml create mode 100644 tests/components/lilygo_t5_47/test.esp32-idf.yaml create mode 100644 tests/components/lilygo_t5_47/test.esp32.yaml create mode 100644 tests/components/lilygo_t5_47/test.esp8266.yaml create mode 100644 tests/components/lilygo_t5_47/test.rp2040.yaml create mode 100644 tests/components/lock/test.esp32-c3-idf.yaml create mode 100644 tests/components/lock/test.esp32-c3.yaml create mode 100644 tests/components/lock/test.esp32-idf.yaml create mode 100644 tests/components/lock/test.esp32.yaml create mode 100644 tests/components/lock/test.esp8266.yaml create mode 100644 tests/components/lock/test.rp2040.yaml create mode 100644 tests/components/logger/test.esp32-c3-idf.yaml create mode 100644 tests/components/logger/test.esp32-c3.yaml create mode 100644 tests/components/logger/test.esp32-idf.yaml create mode 100644 tests/components/logger/test.esp32.yaml create mode 100644 tests/components/logger/test.esp8266.yaml create mode 100644 tests/components/logger/test.rp2040.yaml create mode 100644 tests/components/ltr390/test.esp32-c3-idf.yaml create mode 100644 tests/components/ltr390/test.esp32-c3.yaml create mode 100644 tests/components/ltr390/test.esp32-idf.yaml create mode 100644 tests/components/ltr390/test.esp32.yaml create mode 100644 tests/components/ltr390/test.esp8266.yaml create mode 100644 tests/components/ltr390/test.rp2040.yaml diff --git a/tests/components/lcd_gpio/test.esp32-c3-idf.yaml b/tests/components/lcd_gpio/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b89715a755 --- /dev/null +++ b/tests/components/lcd_gpio/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_gpio/test.esp32-c3.yaml b/tests/components/lcd_gpio/test.esp32-c3.yaml new file mode 100644 index 0000000000..b89715a755 --- /dev/null +++ b/tests/components/lcd_gpio/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_gpio/test.esp32-idf.yaml b/tests/components/lcd_gpio/test.esp32-idf.yaml new file mode 100644 index 0000000000..d2b33aeb3a --- /dev/null +++ b/tests/components/lcd_gpio/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_gpio/test.esp32.yaml b/tests/components/lcd_gpio/test.esp32.yaml new file mode 100644 index 0000000000..d2b33aeb3a --- /dev/null +++ b/tests/components/lcd_gpio/test.esp32.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_gpio/test.esp8266.yaml b/tests/components/lcd_gpio/test.esp8266.yaml new file mode 100644 index 0000000000..d2b33aeb3a --- /dev/null +++ b/tests/components/lcd_gpio/test.esp8266.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_gpio/test.rp2040.yaml b/tests/components/lcd_gpio/test.rp2040.yaml new file mode 100644 index 0000000000..b89715a755 --- /dev/null +++ b/tests/components/lcd_gpio/test.rp2040.yaml @@ -0,0 +1,13 @@ +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_menu/test.esp32-c3-idf.yaml b/tests/components/lcd_menu/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..39d2278d3d --- /dev/null +++ b/tests/components/lcd_menu/test.esp32-c3-idf.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_menu/test.esp32-c3.yaml b/tests/components/lcd_menu/test.esp32-c3.yaml new file mode 100644 index 0000000000..39d2278d3d --- /dev/null +++ b/tests/components/lcd_menu/test.esp32-c3.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_menu/test.esp32-idf.yaml b/tests/components/lcd_menu/test.esp32-idf.yaml new file mode 100644 index 0000000000..833ea2169a --- /dev/null +++ b/tests/components/lcd_menu/test.esp32-idf.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_menu/test.esp32.yaml b/tests/components/lcd_menu/test.esp32.yaml new file mode 100644 index 0000000000..833ea2169a --- /dev/null +++ b/tests/components/lcd_menu/test.esp32.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_menu/test.esp8266.yaml b/tests/components/lcd_menu/test.esp8266.yaml new file mode 100644 index 0000000000..833ea2169a --- /dev/null +++ b/tests/components/lcd_menu/test.esp8266.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 12 + - number: 13 + - number: 14 + - number: 15 + enable_pin: 16 + rs_pin: 5 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_menu/test.rp2040.yaml b/tests/components/lcd_menu/test.rp2040.yaml new file mode 100644 index 0000000000..39d2278d3d --- /dev/null +++ b/tests/components/lcd_menu/test.rp2040.yaml @@ -0,0 +1,118 @@ +number: + - platform: template + id: test_number + min_value: 0 + step: 1 + max_value: 10 + optimistic: true + +select: + - platform: template + id: test_select + options: + - one + - two + optimistic: true + +switch: + - platform: template + name: Template Switch + id: my_switch + optimistic: true + +display: + - platform: lcd_gpio + id: my_lcd_gpio + dimensions: 18x4 + data_pins: + - number: 1 + - number: 2 + - number: 3 + - number: 4 + enable_pin: 5 + rs_pin: 6 + lambda: |- + it.print("Hello World!"); + +lcd_menu: + id: test_lcd_menu + display_id: my_lcd_gpio + mark_back: 0x5e + mark_selected: 0x3e + mark_editing: 0x2a + mark_submenu: 0x7e + active: false + mode: rotary + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "root enter");' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "root leave");' + items: + - type: back + text: Back + - type: label + - type: menu + text: Submenu 1 + items: + - type: back + text: Back + - type: menu + text: Submenu 21 + items: + - type: back + text: Back + - type: command + text: Show Main + on_value: + then: + - display_menu.show_main: test_lcd_menu + - type: select + text: Enum Item + immediate_edit: true + select: test_select + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: number + text: Number + number: test_number + on_enter: + then: + lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_leave: + then: + lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' + - type: command + text: Hide + on_value: + then: + - display_menu.hide: test_lcd_menu + - type: switch + text: Switch + switch: my_switch + on_text: Bright + off_text: Dark + immediate_edit: false + on_value: + then: + lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' + - type: custom + text: !lambda 'return "Custom";' + value_lambda: 'return "Val";' + on_next: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' + on_prev: + then: + lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' diff --git a/tests/components/lcd_pcf8574/test.esp32-c3-idf.yaml b/tests/components/lcd_pcf8574/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..41eba26950 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 5 + sda: 4 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_pcf8574/test.esp32-c3.yaml b/tests/components/lcd_pcf8574/test.esp32-c3.yaml new file mode 100644 index 0000000000..41eba26950 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 5 + sda: 4 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_pcf8574/test.esp32-idf.yaml b/tests/components/lcd_pcf8574/test.esp32-idf.yaml new file mode 100644 index 0000000000..9d7d475f30 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 16 + sda: 17 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_pcf8574/test.esp32.yaml b/tests/components/lcd_pcf8574/test.esp32.yaml new file mode 100644 index 0000000000..9d7d475f30 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.esp32.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 16 + sda: 17 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_pcf8574/test.esp8266.yaml b/tests/components/lcd_pcf8574/test.esp8266.yaml new file mode 100644 index 0000000000..41eba26950 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.esp8266.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 5 + sda: 4 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/lcd_pcf8574/test.rp2040.yaml b/tests/components/lcd_pcf8574/test.rp2040.yaml new file mode 100644 index 0000000000..41eba26950 --- /dev/null +++ b/tests/components/lcd_pcf8574/test.rp2040.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_lcd_pcf8574 + scl: 5 + sda: 4 + +display: + - platform: lcd_pcf8574 + dimensions: 18x4 + address: 0x3F + user_characters: + - position: 0 + data: + - 0b00000 + - 0b01010 + - 0b00000 + - 0b00100 + - 0b00100 + - 0b10001 + - 0b01110 + - 0b00000 + lambda: |- + it.print("Hello World!"); diff --git a/tests/components/ld2410/test.esp32-c3-idf.yaml b/tests/components/ld2410/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..afcaa81b3e --- /dev/null +++ b/tests/components/ld2410/test.esp32-c3-idf.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2410/test.esp32-c3.yaml b/tests/components/ld2410/test.esp32-c3.yaml new file mode 100644 index 0000000000..afcaa81b3e --- /dev/null +++ b/tests/components/ld2410/test.esp32-c3.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2410/test.esp32-idf.yaml b/tests/components/ld2410/test.esp32-idf.yaml new file mode 100644 index 0000000000..48ed179d93 --- /dev/null +++ b/tests/components/ld2410/test.esp32-idf.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2410/test.esp32.yaml b/tests/components/ld2410/test.esp32.yaml new file mode 100644 index 0000000000..48ed179d93 --- /dev/null +++ b/tests/components/ld2410/test.esp32.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2410/test.esp8266.yaml b/tests/components/ld2410/test.esp8266.yaml new file mode 100644 index 0000000000..afcaa81b3e --- /dev/null +++ b/tests/components/ld2410/test.esp8266.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2410/test.rp2040.yaml b/tests/components/ld2410/test.rp2040.yaml new file mode 100644 index 0000000000..afcaa81b3e --- /dev/null +++ b/tests/components/ld2410/test.rp2040.yaml @@ -0,0 +1,169 @@ +uart: + - id: uart_ld2410 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2410: + id: my_ld2410 + +binary_sensor: + - platform: ld2410 + has_target: + name: presence + has_moving_target: + name: movement + has_still_target: + name: still + out_pin_presence_status: + name: out pin presence status + +button: + - platform: ld2410 + factory_reset: + name: factory reset + restart: + name: restart + query_params: + name: query params + +number: + - platform: ld2410 + light_threshold: + name: light threshold + timeout: + name: timeout + max_move_distance_gate: + name: max move distance gate + max_still_distance_gate: + name: max still distance gate + g0: + move_threshold: + name: g0 move threshold + still_threshold: + name: g0 still threshold + g1: + move_threshold: + name: g1 move threshold + still_threshold: + name: g1 still threshold + g2: + move_threshold: + name: g2 move threshold + still_threshold: + name: g2 still threshold + g3: + move_threshold: + name: g3 move threshold + still_threshold: + name: g3 still threshold + g4: + move_threshold: + name: g4 move threshold + still_threshold: + name: g4 still threshold + g5: + move_threshold: + name: g5 move threshold + still_threshold: + name: g5 still threshold + g6: + move_threshold: + name: g6 move threshold + still_threshold: + name: g6 still threshold + g7: + move_threshold: + name: g7 move threshold + still_threshold: + name: g7 still threshold + g8: + move_threshold: + name: g8 move threshold + still_threshold: + name: g8 still threshold + +select: + - platform: ld2410 + distance_resolution: + name: distance resolution + baud_rate: + name: baud rate + light_function: + name: light function + out_pin_level: + name: out ping level + +sensor: + - platform: ld2410 + light: + name: light + moving_distance: + name: Moving distance + still_distance: + name: Still Distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Distance Detection + g0: + move_energy: + name: g0 move energy + still_energy: + name: g0 still energy + g1: + move_energy: + name: g1 move energy + still_energy: + name: g1 still energy + g2: + move_energy: + name: g2 move energy + still_energy: + name: g2 still energy + g3: + move_energy: + name: g3 move energy + still_energy: + name: g3 still energy + g4: + move_energy: + name: g4 move energy + still_energy: + name: g4 still energy + g5: + move_energy: + name: g5 move energy + still_energy: + name: g5 still energy + g6: + move_energy: + name: g6 move energy + still_energy: + name: g6 still energy + g7: + move_energy: + name: g7 move energy + still_energy: + name: g7 still energy + g8: + move_energy: + name: g8 move energy + still_energy: + name: g8 still energy + +switch: + - platform: ld2410 + engineering_mode: + name: control ld2410 engineering mode + bluetooth: + name: control ld2410 bluetooth + +text_sensor: + - platform: ld2410 + version: + name: presenece sensor version + mac_address: + name: presenece sensor mac address diff --git a/tests/components/ld2420/test.esp32-c3-idf.yaml b/tests/components/ld2420/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5e0b9db1c2 --- /dev/null +++ b/tests/components/ld2420/test.esp32-c3-idf.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ld2420/test.esp32-c3.yaml b/tests/components/ld2420/test.esp32-c3.yaml new file mode 100644 index 0000000000..5e0b9db1c2 --- /dev/null +++ b/tests/components/ld2420/test.esp32-c3.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ld2420/test.esp32-idf.yaml b/tests/components/ld2420/test.esp32-idf.yaml new file mode 100644 index 0000000000..8c883664ec --- /dev/null +++ b/tests/components/ld2420/test.esp32-idf.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ld2420/test.esp32.yaml b/tests/components/ld2420/test.esp32.yaml new file mode 100644 index 0000000000..8c883664ec --- /dev/null +++ b/tests/components/ld2420/test.esp32.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ld2420/test.esp8266.yaml b/tests/components/ld2420/test.esp8266.yaml new file mode 100644 index 0000000000..5e0b9db1c2 --- /dev/null +++ b/tests/components/ld2420/test.esp8266.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ld2420/test.rp2040.yaml b/tests/components/ld2420/test.rp2040.yaml new file mode 100644 index 0000000000..5e0b9db1c2 --- /dev/null +++ b/tests/components/ld2420/test.rp2040.yaml @@ -0,0 +1,132 @@ +uart: + - id: uart_ld2420 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +ld2420: + id: my_ld2420 + +binary_sensor: + - platform: ld2420 + has_target: + name: Presence + +button: + - platform: ld2420 + apply_config: + name: Apply Config + factory_reset: + name: Factory Reset + restart_module: + name: Restart Module + revert_config: + name: Undo Edits + +number: + - platform: ld2420 + presence_timeout: + name: Detection Presence Timeout + min_gate_distance: + name: Detection Gate Minimum + max_gate_distance: + name: Detection Gate Maximum + gate_move_sensitivity: + name: Move Calibration Sensitivity Factor + gate_still_sensitivity: + name: Still Calibration Sensitivity Factor + gate_0: + move_threshold: + name: Gate 0 Move Threshold + still_threshold: + name: Gate 0 Still Threshold + gate_1: + move_threshold: + name: Gate 1 Move Threshold + still_threshold: + name: Gate 1 Still Threshold + gate_2: + move_threshold: + name: Gate 2 Move Threshold + still_threshold: + name: Gate 2 Still Threshold + gate_3: + move_threshold: + name: Gate 3 Move Threshold + still_threshold: + name: Gate 3 Still Threshold + gate_4: + move_threshold: + name: Gate 4 Move Threshold + still_threshold: + name: Gate 4 Still Threshold + gate_5: + move_threshold: + name: Gate 5 Move Threshold + still_threshold: + name: Gate 5 Still Threshold + gate_6: + move_threshold: + name: Gate 6 Move Threshold + still_threshold: + name: Gate 6 Still Threshold + gate_7: + move_threshold: + name: Gate 7 Move Threshold + still_threshold: + name: Gate 7 Still Threshold + gate_8: + move_threshold: + name: Gate 8 Move Threshold + still_threshold: + name: Gate 8 Still Threshold + gate_9: + move_threshold: + name: Gate 9 Move Threshold + still_threshold: + name: Gate 9 Still Threshold + gate_10: + move_threshold: + name: Gate 10 Move Threshold + still_threshold: + name: Gate 10 Still Threshold + gate_11: + move_threshold: + name: Gate 11 Move Threshold + still_threshold: + name: Gate 11 Still Threshold + gate_12: + move_threshold: + name: Gate 12 Move Threshold + still_threshold: + name: Gate 12 Still Threshold + gate_13: + move_threshold: + name: Gate 13 Move Threshold + still_threshold: + name: Gate 13 Still Threshold + gate_14: + move_threshold: + name: Gate 14 Move Threshold + still_threshold: + name: Gate 14 Still Threshold + gate_15: + move_threshold: + name: Gate 15 Move Threshold + still_threshold: + name: Gate 15 Still Threshold + +select: + - platform: ld2420 + operating_mode: + name: Operating Mode + +sensor: + - platform: ld2420 + moving_distance: + name: "Moving distance (cm)" + +text_sensor: + - platform: ld2420 + fw_version: + name: LD2420 Firmware diff --git a/tests/components/ledc/test.esp32-c3-idf.yaml b/tests/components/ledc/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..70352b4519 --- /dev/null +++ b/tests/components/ledc/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +esphome: + on_boot: + then: + - output.ledc.set_frequency: + id: test_ledc + frequency: 100Hz + +output: + - platform: ledc + id: test_ledc + pin: 4 diff --git a/tests/components/ledc/test.esp32-c3.yaml b/tests/components/ledc/test.esp32-c3.yaml new file mode 100644 index 0000000000..70352b4519 --- /dev/null +++ b/tests/components/ledc/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +esphome: + on_boot: + then: + - output.ledc.set_frequency: + id: test_ledc + frequency: 100Hz + +output: + - platform: ledc + id: test_ledc + pin: 4 diff --git a/tests/components/ledc/test.esp32-idf.yaml b/tests/components/ledc/test.esp32-idf.yaml new file mode 100644 index 0000000000..70352b4519 --- /dev/null +++ b/tests/components/ledc/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +esphome: + on_boot: + then: + - output.ledc.set_frequency: + id: test_ledc + frequency: 100Hz + +output: + - platform: ledc + id: test_ledc + pin: 4 diff --git a/tests/components/ledc/test.esp32.yaml b/tests/components/ledc/test.esp32.yaml new file mode 100644 index 0000000000..70352b4519 --- /dev/null +++ b/tests/components/ledc/test.esp32.yaml @@ -0,0 +1,11 @@ +esphome: + on_boot: + then: + - output.ledc.set_frequency: + id: test_ledc + frequency: 100Hz + +output: + - platform: ledc + id: test_ledc + pin: 4 diff --git a/tests/components/light/test.esp32-c3-idf.yaml b/tests/components/light/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..8e1709838a --- /dev/null +++ b/tests/components/light/test.esp32-c3-idf.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 0 + - platform: ledc + id: test_ledc_1 + pin: 1 + - platform: ledc + id: test_ledc_2 + pin: 2 + - platform: ledc + id: test_ledc_3 + pin: 3 + - platform: ledc + id: test_ledc_4 + pin: 4 + - platform: ledc + id: test_ledc_5 + pin: 5 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/light/test.esp32-c3.yaml b/tests/components/light/test.esp32-c3.yaml new file mode 100644 index 0000000000..8e1709838a --- /dev/null +++ b/tests/components/light/test.esp32-c3.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 0 + - platform: ledc + id: test_ledc_1 + pin: 1 + - platform: ledc + id: test_ledc_2 + pin: 2 + - platform: ledc + id: test_ledc_3 + pin: 3 + - platform: ledc + id: test_ledc_4 + pin: 4 + - platform: ledc + id: test_ledc_5 + pin: 5 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/light/test.esp32-idf.yaml b/tests/components/light/test.esp32-idf.yaml new file mode 100644 index 0000000000..7e5718d8d4 --- /dev/null +++ b/tests/components/light/test.esp32-idf.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 12 + - platform: ledc + id: test_ledc_1 + pin: 13 + - platform: ledc + id: test_ledc_2 + pin: 14 + - platform: ledc + id: test_ledc_3 + pin: 15 + - platform: ledc + id: test_ledc_4 + pin: 16 + - platform: ledc + id: test_ledc_5 + pin: 17 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/light/test.esp32.yaml b/tests/components/light/test.esp32.yaml new file mode 100644 index 0000000000..7e5718d8d4 --- /dev/null +++ b/tests/components/light/test.esp32.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 12 + - platform: ledc + id: test_ledc_1 + pin: 13 + - platform: ledc + id: test_ledc_2 + pin: 14 + - platform: ledc + id: test_ledc_3 + pin: 15 + - platform: ledc + id: test_ledc_4 + pin: 16 + - platform: ledc + id: test_ledc_5 + pin: 17 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/light/test.esp8266.yaml b/tests/components/light/test.esp8266.yaml new file mode 100644 index 0000000000..4611fb374a --- /dev/null +++ b/tests/components/light/test.esp8266.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 4 + - platform: esp8266_pwm + id: test_ledc_1 + pin: 12 + - platform: esp8266_pwm + id: test_ledc_2 + pin: 13 + - platform: esp8266_pwm + id: test_ledc_3 + pin: 14 + - platform: esp8266_pwm + id: test_ledc_4 + pin: 15 + - platform: esp8266_pwm + id: test_ledc_5 + pin: 16 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/light/test.rp2040.yaml b/tests/components/light/test.rp2040.yaml new file mode 100644 index 0000000000..0215a17e71 --- /dev/null +++ b/tests/components/light/test.rp2040.yaml @@ -0,0 +1,132 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + +output: + - platform: gpio + id: test_binary + pin: 0 + - platform: rp2040_pwm + id: test_ledc_1 + pin: 1 + - platform: rp2040_pwm + id: test_ledc_2 + pin: 2 + - platform: rp2040_pwm + id: test_ledc_3 + pin: 3 + - platform: rp2040_pwm + id: test_ledc_4 + pin: 4 + - platform: rp2040_pwm + id: test_ledc_5 + pin: 5 + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds diff --git a/tests/components/lightwaverf/test.esp8266.yaml b/tests/components/lightwaverf/test.esp8266.yaml new file mode 100644 index 0000000000..8f983a3cca --- /dev/null +++ b/tests/components/lightwaverf/test.esp8266.yaml @@ -0,0 +1,13 @@ +lightwaverf: + read_pin: 5 + write_pin: 4 + +button: + - platform: template + name: "Turn off sofa" + id: light_off_ceiling_sofa + on_press: + lightwaverf.send_raw: + code: [0x04, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x0d, 0x09, 0x08, 0x08] + name: "Sofa" + repeat: 1 diff --git a/tests/components/lilygo_t5_47/test.esp32-c3-idf.yaml b/tests/components/lilygo_t5_47/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..41e81103ac --- /dev/null +++ b/tests/components/lilygo_t5_47/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 6 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lilygo_t5_47/test.esp32-c3.yaml b/tests/components/lilygo_t5_47/test.esp32-c3.yaml new file mode 100644 index 0000000000..41e81103ac --- /dev/null +++ b/tests/components/lilygo_t5_47/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 6 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lilygo_t5_47/test.esp32-idf.yaml b/tests/components/lilygo_t5_47/test.esp32-idf.yaml new file mode 100644 index 0000000000..35eb3df022 --- /dev/null +++ b/tests/components/lilygo_t5_47/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 14 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lilygo_t5_47/test.esp32.yaml b/tests/components/lilygo_t5_47/test.esp32.yaml new file mode 100644 index 0000000000..35eb3df022 --- /dev/null +++ b/tests/components/lilygo_t5_47/test.esp32.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 14 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lilygo_t5_47/test.esp8266.yaml b/tests/components/lilygo_t5_47/test.esp8266.yaml new file mode 100644 index 0000000000..766c492b12 --- /dev/null +++ b/tests/components/lilygo_t5_47/test.esp8266.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 12 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lilygo_t5_47/test.rp2040.yaml b/tests/components/lilygo_t5_47/test.rp2040.yaml new file mode 100644 index 0000000000..41e81103ac --- /dev/null +++ b/tests/components/lilygo_t5_47/test.rp2040.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_lilygo_t5_47 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: lilygo_t5_47 + id: lilygo_touchscreen + interrupt_pin: 6 + display: ssd1306_display + on_touch: + - logger.log: + format: Touch at (%d, %d) + args: [touch.x, touch.y] diff --git a/tests/components/lock/test.esp32-c3-idf.yaml b/tests/components/lock/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.esp32-c3-idf.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.esp32-c3.yaml b/tests/components/lock/test.esp32-c3.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.esp32-c3.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.esp32-idf.yaml b/tests/components/lock/test.esp32-idf.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.esp32-idf.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.esp32.yaml b/tests/components/lock/test.esp32.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.esp32.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.esp8266.yaml b/tests/components/lock/test.esp8266.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.esp8266.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.rp2040.yaml b/tests/components/lock/test.rp2040.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/test.rp2040.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/logger/test.esp32-c3-idf.yaml b/tests/components/logger/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.esp32-c3.yaml b/tests/components/logger/test.esp32-c3.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.esp32-idf.yaml b/tests/components/logger/test.esp32-idf.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.esp32.yaml b/tests/components/logger/test.esp32.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.esp32.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.esp8266.yaml b/tests/components/logger/test.esp8266.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.esp8266.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.rp2040.yaml b/tests/components/logger/test.rp2040.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/test.rp2040.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/ltr390/test.esp32-c3-idf.yaml b/tests/components/ltr390/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fee0f37ce1 --- /dev/null +++ b/tests/components/ltr390/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 5 + sda: 4 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp32-c3.yaml b/tests/components/ltr390/test.esp32-c3.yaml new file mode 100644 index 0000000000..fee0f37ce1 --- /dev/null +++ b/tests/components/ltr390/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 5 + sda: 4 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp32-idf.yaml b/tests/components/ltr390/test.esp32-idf.yaml new file mode 100644 index 0000000000..9786c7dac3 --- /dev/null +++ b/tests/components/ltr390/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 16 + sda: 17 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp32.yaml b/tests/components/ltr390/test.esp32.yaml new file mode 100644 index 0000000000..9786c7dac3 --- /dev/null +++ b/tests/components/ltr390/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 16 + sda: 17 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp8266.yaml b/tests/components/ltr390/test.esp8266.yaml new file mode 100644 index 0000000000..fee0f37ce1 --- /dev/null +++ b/tests/components/ltr390/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 5 + sda: 4 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.rp2040.yaml b/tests/components/ltr390/test.rp2040.yaml new file mode 100644 index 0000000000..fee0f37ce1 --- /dev/null +++ b/tests/components/ltr390/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ltr390 + scl: 5 + sda: 4 + +sensor: + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: X3 + resolution: 18 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s From 6b7f9b15ea52ba15a48f37e22e70c6a49dbdc8d7 Mon Sep 17 00:00:00 2001 From: MagicBear Date: Thu, 28 Mar 2024 02:56:19 +0800 Subject: [PATCH 1471/2607] feat: Add Daikin ARC (tested on Daikin ARC472A62) (#6429) --- CODEOWNERS | 1 + esphome/components/daikin_arc/__init__.py | 1 + esphome/components/daikin_arc/climate.py | 18 + esphome/components/daikin_arc/daikin_arc.cpp | 487 ++++++++++++++++++ esphome/components/daikin_arc/daikin_arc.h | 76 +++ tests/components/daikin_arc/test.esp32.yaml | 19 + tests/components/daikin_arc/test.esp8266.yaml | 19 + 7 files changed, 621 insertions(+) create mode 100644 esphome/components/daikin_arc/__init__.py create mode 100644 esphome/components/daikin_arc/climate.py create mode 100644 esphome/components/daikin_arc/daikin_arc.cpp create mode 100644 esphome/components/daikin_arc/daikin_arc.h create mode 100644 tests/components/daikin_arc/test.esp32.yaml create mode 100644 tests/components/daikin_arc/test.esp8266.yaml diff --git a/CODEOWNERS b/CODEOWNERS index d6ec3843a5..7c1f7ff70b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -87,6 +87,7 @@ esphome/components/cst816/* @clydebarrow esphome/components/ct_clamp/* @jesserockz esphome/components/current_based/* @djwmarcx esphome/components/dac7678/* @NickB1 +esphome/components/daikin_arc/* @MagicBear esphome/components/daikin_brc/* @hagak esphome/components/daly_bms/* @s1lvi0 esphome/components/dashboard_import/* @esphome/core diff --git a/esphome/components/daikin_arc/__init__.py b/esphome/components/daikin_arc/__init__.py new file mode 100644 index 0000000000..f9164fb02b --- /dev/null +++ b/esphome/components/daikin_arc/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@MagicBear"] diff --git a/esphome/components/daikin_arc/climate.py b/esphome/components/daikin_arc/climate.py new file mode 100644 index 0000000000..51f253e9cb --- /dev/null +++ b/esphome/components/daikin_arc/climate.py @@ -0,0 +1,18 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import climate_ir +from esphome.const import CONF_ID + +AUTO_LOAD = ["climate_ir"] + +daikin_arc_ns = cg.esphome_ns.namespace("daikin_arc") +DaikinArcClimate = daikin_arc_ns.class_("DaikinArcClimate", climate_ir.ClimateIR) + +CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( + {cv.GenerateID(): cv.declare_id(DaikinArcClimate)} +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/daikin_arc/daikin_arc.cpp b/esphome/components/daikin_arc/daikin_arc.cpp new file mode 100644 index 0000000000..f806463d00 --- /dev/null +++ b/esphome/components/daikin_arc/daikin_arc.cpp @@ -0,0 +1,487 @@ +#include "daikin_arc.h" + +#include + +#include "esphome/components/remote_base/remote_base.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace daikin_arc { + +static const char *const TAG = "daikin.climate"; + +void DaikinArcClimate::setup() { + climate_ir::ClimateIR::setup(); + + // Never send nan to HA + if (std::isnan(this->target_humidity)) + this->target_humidity = 0; + if (std::isnan(this->current_temperature)) + this->current_temperature = 0; + if (std::isnan(this->current_humidity)) + this->current_humidity = 0; +} + +void DaikinArcClimate::transmit_query_() { + uint8_t remote_header[8] = {0x11, 0xDA, 0x27, 0x00, 0x84, 0x87, 0x20, 0x00}; + + // Calculate checksum + for (int i = 0; i < sizeof(remote_header) - 1; i++) { + remote_header[sizeof(remote_header) - 1] += remote_header[i]; + } + + auto transmit = this->transmitter_->transmit(); + auto *data = transmit.get_data(); + data->set_carrier_frequency(DAIKIN_IR_FREQUENCY); + + data->mark(DAIKIN_ARC_PRE_MARK); + data->space(DAIKIN_ARC_PRE_SPACE); + + data->mark(DAIKIN_HEADER_MARK); + data->space(DAIKIN_HEADER_SPACE); + + for (uint8_t i : remote_header) { + for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask + data->mark(DAIKIN_BIT_MARK); + bool bit = i & mask; + data->space(bit ? DAIKIN_ONE_SPACE : DAIKIN_ZERO_SPACE); + } + } + data->mark(DAIKIN_BIT_MARK); + data->space(0); + + transmit.perform(); +} + +void DaikinArcClimate::transmit_state() { + // 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7, 0x11, 0xDA, 0x27, 0x00, + // 0x42, 0x49, 0x05, 0xA2, + uint8_t remote_header[20] = {0x11, 0xDA, 0x27, 0x00, 0x02, 0xd0, 0x02, 0x03, 0x80, 0x03, 0x82, 0x30, 0x41, 0x1f, 0x82, + 0xf4, + /* とつど */ + /* 0x13 */ + 0x00, 0x24, 0x00, 0x00}; + + // 05 0 [1:3]MODE 1 [OFF TMR] [ON TMR] Power + // 06-07 TEMP + // 08 [0:3] SPEED [4:7] Swing + // 09 00 + // 10 00 + // 11, 12: timer + // 13 [0:6] 0000000 [7] POWERMODE + // 14 0a + // 15 c4 + // 16 [0:3] 8 00 [6:7] SENSOR WIND = 11 / NORMAL = 00 + // 17 24 + + uint8_t remote_state[19] = { + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0a, 0xC4, + /* MODE TEMP HUMD FANH FANL + パワフル音声応答 */ + /* ON + 0x01入 0x0a */ + /* OF + 0x00切 0x02 */ + 0x80, 0x24, 0x00 + /* センサー風 */ + /* ON 0x83 */ + /* OF 0x80 */ + }; + + remote_state[5] = this->operation_mode_() | 0x08; + remote_state[6] = this->temperature_(); + remote_state[7] = this->humidity_(); + static uint8_t last_humidity = 0x66; + if (remote_state[7] != last_humidity && this->mode != climate::CLIMATE_MODE_OFF) { + ESP_LOGD(TAG, "Set Humditiy: %d, %d\n", (int) this->target_humidity, (int) remote_state[7]); + remote_header[9] |= 0x10; + last_humidity = remote_state[7]; + } + uint16_t fan_speed = this->fan_speed_(); + remote_state[8] = fan_speed >> 8; + remote_state[9] = fan_speed & 0xff; + + // Calculate checksum + for (int i = 0; i < sizeof(remote_header) - 1; i++) { + remote_header[sizeof(remote_header) - 1] += remote_header[i]; + } + + // Calculate checksum + for (int i = 0; i < DAIKIN_STATE_FRAME_SIZE - 1; i++) { + remote_state[DAIKIN_STATE_FRAME_SIZE - 1] += remote_state[i]; + } + + auto transmit = this->transmitter_->transmit(); + auto *data = transmit.get_data(); + data->set_carrier_frequency(DAIKIN_IR_FREQUENCY); + + data->mark(DAIKIN_ARC_PRE_MARK); + data->space(DAIKIN_ARC_PRE_SPACE); + + data->mark(DAIKIN_HEADER_MARK); + data->space(DAIKIN_HEADER_SPACE); + + for (uint8_t i : remote_header) { + for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask + data->mark(DAIKIN_BIT_MARK); + bool bit = i & mask; + data->space(bit ? DAIKIN_ONE_SPACE : DAIKIN_ZERO_SPACE); + } + } + data->mark(DAIKIN_BIT_MARK); + data->space(DAIKIN_MESSAGE_SPACE); + + data->mark(DAIKIN_HEADER_MARK); + data->space(DAIKIN_HEADER_SPACE); + + for (uint8_t i : remote_state) { + for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask + data->mark(DAIKIN_BIT_MARK); + bool bit = i & mask; + data->space(bit ? DAIKIN_ONE_SPACE : DAIKIN_ZERO_SPACE); + } + } + data->mark(DAIKIN_BIT_MARK); + data->space(0); + + transmit.perform(); +} + +uint8_t DaikinArcClimate::operation_mode_() { + uint8_t operating_mode = DAIKIN_MODE_ON; + switch (this->mode) { + case climate::CLIMATE_MODE_COOL: + operating_mode |= DAIKIN_MODE_COOL; + break; + case climate::CLIMATE_MODE_DRY: + operating_mode |= DAIKIN_MODE_DRY; + break; + case climate::CLIMATE_MODE_HEAT: + operating_mode |= DAIKIN_MODE_HEAT; + break; + case climate::CLIMATE_MODE_HEAT_COOL: + operating_mode |= DAIKIN_MODE_AUTO; + break; + case climate::CLIMATE_MODE_FAN_ONLY: + operating_mode |= DAIKIN_MODE_FAN; + break; + case climate::CLIMATE_MODE_OFF: + default: + operating_mode = DAIKIN_MODE_OFF; + break; + } + + return operating_mode; +} + +uint16_t DaikinArcClimate::fan_speed_() { + uint16_t fan_speed; + switch (this->fan_mode.value()) { + case climate::CLIMATE_FAN_LOW: + fan_speed = DAIKIN_FAN_1 << 8; + break; + case climate::CLIMATE_FAN_MEDIUM: + fan_speed = DAIKIN_FAN_3 << 8; + break; + case climate::CLIMATE_FAN_HIGH: + fan_speed = DAIKIN_FAN_5 << 8; + break; + case climate::CLIMATE_FAN_AUTO: + default: + fan_speed = DAIKIN_FAN_AUTO << 8; + } + + // If swing is enabled switch first 4 bits to 1111 + switch (this->swing_mode) { + case climate::CLIMATE_SWING_VERTICAL: + fan_speed |= 0x0F00; + break; + case climate::CLIMATE_SWING_HORIZONTAL: + fan_speed |= 0x000F; + break; + case climate::CLIMATE_SWING_BOTH: + fan_speed |= 0x0F0F; + break; + default: + break; + } + return fan_speed; +} + +uint8_t DaikinArcClimate::temperature_() { + // Force special temperatures depending on the mode + switch (this->mode) { + case climate::CLIMATE_MODE_FAN_ONLY: + return 0x32; + case climate::CLIMATE_MODE_HEAT_COOL: + case climate::CLIMATE_MODE_DRY: + return 0xc0; + default: + float new_temp = clamp(this->target_temperature, DAIKIN_TEMP_MIN, DAIKIN_TEMP_MAX); + uint8_t temperature = (uint8_t) floor(new_temp); + return temperature << 1 | (new_temp - temperature > 0 ? 0x01 : 0); + } +} + +uint8_t DaikinArcClimate::humidity_() { + if (this->target_humidity == 39) { + return 0; + } else if (this->target_humidity <= 40 || this->target_humidity == 44) { + return 40; + } else if (this->target_humidity <= 45 || this->target_humidity == 49) // 41 - 45 + { + return 45; + } else if (this->target_humidity <= 50 || this->target_humidity == 52) // 45 - 50 + { + return 50; + } else { + return 0xff; + } +} + +climate::ClimateTraits DaikinArcClimate::traits() { + climate::ClimateTraits traits = climate_ir::ClimateIR::traits(); + traits.set_supports_current_temperature(true); + traits.set_supports_current_humidity(false); + traits.set_supports_target_humidity(true); + traits.set_visual_min_humidity(38); + traits.set_visual_max_humidity(52); + return traits; +} + +bool DaikinArcClimate::parse_state_frame_(const uint8_t frame[]) { + uint8_t checksum = 0; + for (int i = 0; i < (DAIKIN_STATE_FRAME_SIZE - 1); i++) { + checksum += frame[i]; + } + if (frame[DAIKIN_STATE_FRAME_SIZE - 1] != checksum) { + ESP_LOGI(TAG, "checksum error"); + return false; + } + + char buf[DAIKIN_STATE_FRAME_SIZE * 3 + 1] = {0}; + for (size_t i = 0; i < DAIKIN_STATE_FRAME_SIZE; i++) { + sprintf(buf, "%s%02x ", buf, frame[i]); + } + ESP_LOGD(TAG, "FRAME %s", buf); + + uint8_t mode = frame[5]; + if (mode & DAIKIN_MODE_ON) { + switch (mode & 0xF0) { + case DAIKIN_MODE_COOL: + this->mode = climate::CLIMATE_MODE_COOL; + break; + case DAIKIN_MODE_DRY: + this->mode = climate::CLIMATE_MODE_DRY; + break; + case DAIKIN_MODE_HEAT: + this->mode = climate::CLIMATE_MODE_HEAT; + break; + case DAIKIN_MODE_AUTO: + this->mode = climate::CLIMATE_MODE_HEAT_COOL; + break; + case DAIKIN_MODE_FAN: + this->mode = climate::CLIMATE_MODE_FAN_ONLY; + break; + } + } else { + this->mode = climate::CLIMATE_MODE_OFF; + } + uint8_t temperature = frame[6]; + if (!(temperature & 0xC0)) { + this->target_temperature = temperature >> 1; + this->target_temperature += (temperature & 0x1) ? 0.5 : 0; + } + this->target_humidity = frame[7]; // 0, 40, 45, 50, 0xff + uint8_t fan_mode = frame[8]; + uint8_t swing_mode = frame[9]; + if (fan_mode & 0xF && swing_mode & 0xF) { + this->swing_mode = climate::CLIMATE_SWING_BOTH; + } else if (fan_mode & 0xF) { + this->swing_mode = climate::CLIMATE_SWING_VERTICAL; + } else if (swing_mode & 0xF) { + this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; + } else { + this->swing_mode = climate::CLIMATE_SWING_OFF; + } + switch (fan_mode & 0xF0) { + case DAIKIN_FAN_1: + case DAIKIN_FAN_2: + case DAIKIN_FAN_SILENT: + this->fan_mode = climate::CLIMATE_FAN_LOW; + break; + case DAIKIN_FAN_3: + this->fan_mode = climate::CLIMATE_FAN_MEDIUM; + break; + case DAIKIN_FAN_4: + case DAIKIN_FAN_5: + this->fan_mode = climate::CLIMATE_FAN_HIGH; + break; + case DAIKIN_FAN_AUTO: + this->fan_mode = climate::CLIMATE_FAN_AUTO; + break; + } + /* + 05 0 [1:3]MODE 1 [OFF TMR] [ON TMR] Power + 06-07 TEMP + 08 [0:3] SPEED [4:7] Swing + 09 00 + 10 00 + 11, 12: timer + 13 [0:6] 0000000 [7] POWERMODE + 14 0a + 15 c4 + 16 [0:3] 8 00 [6:7] SENSOR WIND = 11 / NORMAL = 00 + 17 24 + 05 06 07 08 09 10 11 12 13 14 15 16 17 18 + None FRAME 11 da 27 00 00 49 2e 00 b0 00 00 06 60 00 0a c4 80 24 11 + 1H FRAME 11 da 27 00 00 4d 2e 00 b0 00 00 c6 30 00 2a c4 80 24 c5 + 1H30 FRAME 11 da 27 00 00 4d 2e 00 b0 00 00 a6 32 00 2a c4 80 24 a7 + 2H FRAME 11 da 27 00 00 4d 2e 00 b0 00 00 86 34 00 2a c4 80 24 89 + + */ + this->publish_state(); + return true; +} + +bool DaikinArcClimate::on_receive(remote_base::RemoteReceiveData data) { + uint8_t state_frame[DAIKIN_STATE_FRAME_SIZE] = {}; + + bool valid_daikin_frame = false; + if (data.expect_item(DAIKIN_HEADER_MARK, DAIKIN_HEADER_SPACE)) { + valid_daikin_frame = true; + int bytes_count = data.size() / 2 / 8; + std::unique_ptr buf(new char[bytes_count * 3 + 1]); + buf[0] = '\0'; + for (size_t i = 0; i < bytes_count; i++) { + uint8_t byte = 0; + for (int8_t bit = 0; bit < 8; bit++) { + if (data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE)) { + byte |= 1 << bit; + } else if (!data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE)) { + valid_daikin_frame = false; + break; + } + } + sprintf(buf.get(), "%s%02x ", buf.get(), byte); + } + ESP_LOGD(TAG, "WHOLE FRAME %s size: %d", buf.get(), data.size()); + } + if (!valid_daikin_frame) { + char sbuf[16 * 10 + 1]; + sbuf[0] = '\0'; + for (size_t j = 0; j < data.size(); j++) { + if ((j - 2) % 16 == 0) { + if (j > 0) { + ESP_LOGD(TAG, "DATA %04x: %s", (j - 16 > 0xffff ? 0 : j - 16), sbuf); + } + sbuf[0] = '\0'; + } + char type_ch = ' '; + // debug_tolerance = 25% + + if (DAIKIN_DBG_LOWER(DAIKIN_ARC_PRE_MARK) <= data[j] && data[j] <= DAIKIN_DBG_UPPER(DAIKIN_ARC_PRE_MARK)) + type_ch = 'P'; + if (DAIKIN_DBG_LOWER(DAIKIN_ARC_PRE_SPACE) <= -data[j] && -data[j] <= DAIKIN_DBG_UPPER(DAIKIN_ARC_PRE_SPACE)) + type_ch = 'a'; + if (DAIKIN_DBG_LOWER(DAIKIN_HEADER_MARK) <= data[j] && data[j] <= DAIKIN_DBG_UPPER(DAIKIN_HEADER_MARK)) + type_ch = 'H'; + if (DAIKIN_DBG_LOWER(DAIKIN_HEADER_SPACE) <= -data[j] && -data[j] <= DAIKIN_DBG_UPPER(DAIKIN_HEADER_SPACE)) + type_ch = 'h'; + if (DAIKIN_DBG_LOWER(DAIKIN_BIT_MARK) <= data[j] && data[j] <= DAIKIN_DBG_UPPER(DAIKIN_BIT_MARK)) + type_ch = 'B'; + if (DAIKIN_DBG_LOWER(DAIKIN_ONE_SPACE) <= -data[j] && -data[j] <= DAIKIN_DBG_UPPER(DAIKIN_ONE_SPACE)) + type_ch = '1'; + if (DAIKIN_DBG_LOWER(DAIKIN_ZERO_SPACE) <= -data[j] && -data[j] <= DAIKIN_DBG_UPPER(DAIKIN_ZERO_SPACE)) + type_ch = '0'; + + if (abs(data[j]) > 100000) { + sprintf(sbuf, "%s%-5d[%c] ", sbuf, data[j] > 0 ? 99999 : -99999, type_ch); + } else { + sprintf(sbuf, "%s%-5d[%c] ", sbuf, (int) (round(data[j] / 10.) * 10), type_ch); + } + if (j == data.size() - 1) { + ESP_LOGD(TAG, "DATA %04x: %s", (j - 8 > 0xffff ? 0 : j - 8), sbuf); + } + } + } + + data.reset(); + + if (!data.expect_item(DAIKIN_HEADER_MARK, DAIKIN_HEADER_SPACE)) { + ESP_LOGI(TAG, "non daikin_arc expect item"); + return false; + } + + for (uint8_t pos = 0; pos < DAIKIN_STATE_FRAME_SIZE; pos++) { + uint8_t byte = 0; + for (int8_t bit = 0; bit < 8; bit++) { + if (data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE)) { + byte |= 1 << bit; + } else if (!data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE)) { + ESP_LOGI(TAG, "non daikin_arc expect item pos: %d", pos); + return false; + } + } + state_frame[pos] = byte; + if (pos == 0) { + // frame header + if (byte != 0x11) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } else if (pos == 1) { + // frame header + if (byte != 0xDA) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } else if (pos == 2) { + // frame header + if (byte != 0x27) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } else if (pos == 3) { // NOLINT(bugprone-branch-clone) + // frame header + if (byte != 0x00) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } else if (pos == 4) { + // frame type + if (byte != 0x00) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } else if (pos == 5) { + if (data.size() == 385) { + /* + 11 da 27 00 00 1a 0c 04 2c 21 61 07 00 07 0c 00 18 00 0e 3c 00 6c 1b 61 + Inside Temp + Outside Temp + Humdidity + + */ + this->current_temperature = state_frame[5]; // Inside temperature + // this->current_temperature = state_frame[6]; // Outside temperature + this->publish_state(); + return true; + } else if ((byte & 0x40) != 0x40) { + ESP_LOGI(TAG, "non daikin_arc expect pos: %d header: %02x", pos, byte); + return false; + } + } + } + return this->parse_state_frame_(state_frame); +} + +void DaikinArcClimate::control(const climate::ClimateCall &call) { + if (call.get_target_humidity().has_value()) { + this->target_humidity = *call.get_target_humidity(); + } + climate_ir::ClimateIR::control(call); +} + +} // namespace daikin_arc +} // namespace esphome diff --git a/esphome/components/daikin_arc/daikin_arc.h b/esphome/components/daikin_arc/daikin_arc.h new file mode 100644 index 0000000000..6cfffd4725 --- /dev/null +++ b/esphome/components/daikin_arc/daikin_arc.h @@ -0,0 +1,76 @@ +#pragma once + +#include "esphome/components/climate_ir/climate_ir.h" + +namespace esphome { +namespace daikin_arc { + +// Values for Daikin ARC43XXX IR Controllers +// Temperature +const uint8_t DAIKIN_TEMP_MIN = 10; // Celsius +const uint8_t DAIKIN_TEMP_MAX = 30; // Celsius + +// Modes +const uint8_t DAIKIN_MODE_AUTO = 0x00; +const uint8_t DAIKIN_MODE_COOL = 0x30; +const uint8_t DAIKIN_MODE_HEAT = 0x40; +const uint8_t DAIKIN_MODE_DRY = 0x20; +const uint8_t DAIKIN_MODE_FAN = 0x60; +const uint8_t DAIKIN_MODE_OFF = 0x00; +const uint8_t DAIKIN_MODE_ON = 0x01; + +// Fan Speed +const uint8_t DAIKIN_FAN_AUTO = 0xA0; +const uint8_t DAIKIN_FAN_SILENT = 0xB0; +const uint8_t DAIKIN_FAN_1 = 0x30; +const uint8_t DAIKIN_FAN_2 = 0x40; +const uint8_t DAIKIN_FAN_3 = 0x50; +const uint8_t DAIKIN_FAN_4 = 0x60; +const uint8_t DAIKIN_FAN_5 = 0x70; + +// IR Transmission +const uint32_t DAIKIN_IR_FREQUENCY = 38000; +const uint32_t DAIKIN_ARC_PRE_MARK = 9950; +const uint32_t DAIKIN_ARC_PRE_SPACE = 25100; +const uint32_t DAIKIN_HEADER_MARK = 3450; +const uint32_t DAIKIN_HEADER_SPACE = 1760; +const uint32_t DAIKIN_BIT_MARK = 400; +const uint32_t DAIKIN_ONE_SPACE = 1300; +const uint32_t DAIKIN_ZERO_SPACE = 480; +const uint32_t DAIKIN_MESSAGE_SPACE = 35000; + +const uint8_t DAIKIN_DBG_TOLERANCE = 25; +#define DAIKIN_DBG_LOWER(x) ((100 - DAIKIN_DBG_TOLERANCE) * (x) / 100U) +#define DAIKIN_DBG_UPPER(x) ((100 + DAIKIN_DBG_TOLERANCE) * (x) / 100U) + +// State Frame size +const uint8_t DAIKIN_STATE_FRAME_SIZE = 19; + +class DaikinArcClimate : public climate_ir::ClimateIR { + public: + DaikinArcClimate() + : climate_ir::ClimateIR(DAIKIN_TEMP_MIN, DAIKIN_TEMP_MAX, 0.5f, true, true, + {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, + climate::CLIMATE_FAN_HIGH}, + {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {} + + void setup() override; + + protected: + void control(const climate::ClimateCall &call) override; + // Transmit via IR the state of this climate controller. + void transmit_query_(); + void transmit_state() override; + climate::ClimateTraits traits() override; + uint8_t operation_mode_(); + uint16_t fan_speed_(); + uint8_t temperature_(); + uint8_t humidity_(); + // Handle received IR Buffer + bool on_receive(remote_base::RemoteReceiveData data) override; + bool parse_state_frame_(const uint8_t frame[]); +}; + +} // namespace daikin_arc +} // namespace esphome diff --git a/tests/components/daikin_arc/test.esp32.yaml b/tests/components/daikin_arc/test.esp32.yaml new file mode 100644 index 0000000000..a8556e8576 --- /dev/null +++ b/tests/components/daikin_arc/test.esp32.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + id: tsvr + +remote_receiver: + id: rcvr + pin: + number: 27 + inverted: true + mode: + input: true + pullup: true + tolerance: 40% + +climate: + - platform: daikin_arc + name: "AC" + receiver_id: rcvr diff --git a/tests/components/daikin_arc/test.esp8266.yaml b/tests/components/daikin_arc/test.esp8266.yaml new file mode 100644 index 0000000000..abf1b34a6e --- /dev/null +++ b/tests/components/daikin_arc/test.esp8266.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + id: tsvr + +remote_receiver: + id: rcvr + pin: + number: 2 + inverted: true + mode: + input: true + pullup: true + tolerance: 40% + +climate: + - platform: daikin_arc + name: "AC" + receiver_id: rcvr From 0ff543ffe5c38509ab1f8cd7ddcaffb4617b1a99 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Mar 2024 10:20:51 +1300 Subject: [PATCH 1472/2607] Disable truthy yamllint rule (#6442) --- .github/workflows/ci-api-proto.yml | 1 - .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 1 - .github/workflows/lock.yml | 1 - .github/workflows/needs-docs.yml | 1 - .github/workflows/release.yml | 1 - .github/workflows/stale.yml | 1 - .github/workflows/sync-device-classes.yml | 1 - .github/workflows/yaml-lint.yml | 1 - .yamllint | 1 + tests/components/lightwaverf/test.esp8266.yaml | 2 +- 11 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 038ef3a587..0b2465d1aa 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -1,6 +1,5 @@ name: API Proto CI -# yamllint disable-line rule:truthy on: pull_request: paths: diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 8a7b35fe33..f02efadf4d 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -2,7 +2,7 @@ name: CI for docker images # Only run when docker paths change -# yamllint disable-line rule:truthy + on: push: branches: [dev, beta, release] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 871f2e72c8..b0ac840972 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ --- name: CI -# yamllint disable-line rule:truthy on: push: branches: [dev, beta, release] diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index e3d75f6d58..ee10f49f61 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -1,7 +1,6 @@ --- name: Lock -# yamllint disable-line rule:truthy on: schedule: - cron: "30 0 * * *" diff --git a/.github/workflows/needs-docs.yml b/.github/workflows/needs-docs.yml index 6a66e5769c..628b5cc5e3 100644 --- a/.github/workflows/needs-docs.yml +++ b/.github/workflows/needs-docs.yml @@ -1,6 +1,5 @@ name: Needs Docs -# yamllint disable-line rule:truthy on: pull_request: types: [labeled, unlabeled] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b567b5b6f..16469c904b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,6 @@ --- name: Publish Release -# yamllint disable-line rule:truthy on: workflow_dispatch: release: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5f510ffe75..95f275e5a4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,7 +1,6 @@ --- name: Stale -# yamllint disable-line rule:truthy on: schedule: - cron: "30 0 * * *" diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 36fce2bbcf..3f8af4249a 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -1,7 +1,6 @@ --- name: Synchronise Device Classes from Home Assistant -# yamllint disable-line rule:truthy on: workflow_dispatch: schedule: diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index 3694436866..a3c1937e56 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -1,7 +1,6 @@ --- name: YAML lint -# yamllint disable-line rule:truthy on: push: branches: [dev, beta, release] diff --git a/.yamllint b/.yamllint index 9cd1482869..22e9237f61 100644 --- a/.yamllint +++ b/.yamllint @@ -16,3 +16,4 @@ rules: indent-sequences: true check-multi-line-strings: false line-length: disable + truthy: disable diff --git a/tests/components/lightwaverf/test.esp8266.yaml b/tests/components/lightwaverf/test.esp8266.yaml index 8f983a3cca..7ed8000271 100644 --- a/tests/components/lightwaverf/test.esp8266.yaml +++ b/tests/components/lightwaverf/test.esp8266.yaml @@ -8,6 +8,6 @@ button: id: light_off_ceiling_sofa on_press: lightwaverf.send_raw: - code: [0x04, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x0d, 0x09, 0x08, 0x08] + code: [0x04, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x0d, 0x09, 0x08, 0x08] name: "Sofa" repeat: 1 From 9194f7eb27f503e0f712d3e6407e48a16fc4ef99 Mon Sep 17 00:00:00 2001 From: Daniel Eisterhold Date: Wed, 27 Mar 2024 18:56:26 -0500 Subject: [PATCH 1473/2607] Add get_size method to QR Code header (#6430) --- esphome/components/qr_code/qr_code.cpp | 12 ++++++++++++ esphome/components/qr_code/qr_code.h | 2 ++ tests/components/qr_code/test.esp32-c3-idf.yaml | 7 +++++++ tests/components/qr_code/test.esp32-c3.yaml | 7 +++++++ tests/components/qr_code/test.esp32-idf.yaml | 7 +++++++ tests/components/qr_code/test.esp32.yaml | 7 +++++++ tests/components/qr_code/test.esp8266.yaml | 7 +++++++ tests/components/qr_code/test.rp2040.yaml | 7 +++++++ 8 files changed, 56 insertions(+) diff --git a/esphome/components/qr_code/qr_code.cpp b/esphome/components/qr_code/qr_code.cpp index aecf7628dc..b60e60a4b0 100644 --- a/esphome/components/qr_code/qr_code.cpp +++ b/esphome/components/qr_code/qr_code.cpp @@ -51,5 +51,17 @@ void QrCode::draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, } } } + +uint8_t QrCode::get_size() { + if (this->needs_update_) { + this->generate_qr_code(); + this->needs_update_ = false; + } + + uint8_t size = qrcodegen_getSize(this->qr_); + + return size; +} + } // namespace qr_code } // namespace esphome diff --git a/esphome/components/qr_code/qr_code.h b/esphome/components/qr_code/qr_code.h index d88e0aa09a..ab4c587b6d 100644 --- a/esphome/components/qr_code/qr_code.h +++ b/esphome/components/qr_code/qr_code.h @@ -24,6 +24,8 @@ class QrCode : public Component { void generate_qr_code(); + uint8_t get_size(); + protected: std::string value_; qrcodegen_Ecc ecc_; diff --git a/tests/components/qr_code/test.esp32-c3-idf.yaml b/tests/components/qr_code/test.esp32-c3-idf.yaml index 3e875c026c..63973b1aa2 100644 --- a/tests/components/qr_code/test.esp32-c3-idf.yaml +++ b/tests/components/qr_code/test.esp32-c3-idf.yaml @@ -11,6 +11,13 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr diff --git a/tests/components/qr_code/test.esp32-c3.yaml b/tests/components/qr_code/test.esp32-c3.yaml index 3e875c026c..63973b1aa2 100644 --- a/tests/components/qr_code/test.esp32-c3.yaml +++ b/tests/components/qr_code/test.esp32-c3.yaml @@ -11,6 +11,13 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr diff --git a/tests/components/qr_code/test.esp32-idf.yaml b/tests/components/qr_code/test.esp32-idf.yaml index b354a3f512..3e70d3258f 100644 --- a/tests/components/qr_code/test.esp32-idf.yaml +++ b/tests/components/qr_code/test.esp32-idf.yaml @@ -11,6 +11,13 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr diff --git a/tests/components/qr_code/test.esp32.yaml b/tests/components/qr_code/test.esp32.yaml index b354a3f512..3e70d3258f 100644 --- a/tests/components/qr_code/test.esp32.yaml +++ b/tests/components/qr_code/test.esp32.yaml @@ -11,6 +11,13 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr diff --git a/tests/components/qr_code/test.esp8266.yaml b/tests/components/qr_code/test.esp8266.yaml index dd0d75c472..3c304d7575 100644 --- a/tests/components/qr_code/test.esp8266.yaml +++ b/tests/components/qr_code/test.esp8266.yaml @@ -11,6 +11,13 @@ display: cs_pin: 5 dc_pin: 15 reset_pin: 16 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr diff --git a/tests/components/qr_code/test.rp2040.yaml b/tests/components/qr_code/test.rp2040.yaml index b0e046d275..94cb772ba3 100644 --- a/tests/components/qr_code/test.rp2040.yaml +++ b/tests/components/qr_code/test.rp2040.yaml @@ -11,6 +11,13 @@ display: cs_pin: 20 dc_pin: 21 reset_pin: 22 + lambda: |- + // Draw a QR code in the center of the screen + auto scale = 2; + auto size = id(homepage_qr).get_size() * scale; + auto x = (it.get_width() / 2) - (size / 2); + auto y = (it.get_height() / 2) - (size / 2); + it.qr_code(x, y, id(homepage_qr), Color(255,255,255), scale); qr_code: - id: homepage_qr From 731dcc40bcbadb197f0f2a091c4d3790f28e5980 Mon Sep 17 00:00:00 2001 From: mrtoy-me <118446898+mrtoy-me@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:19:27 +1000 Subject: [PATCH 1474/2607] Minor change to support sht85 sensor (#6415) --- CODEOWNERS | 1 + esphome/components/sht3xd/sensor.py | 6 ++++-- esphome/components/sht3xd/sht3xd.cpp | 21 ++++++++++++++++----- esphome/components/sht3xd/sht3xd.h | 1 + 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 7c1f7ff70b..fafbaae6c6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -309,6 +309,7 @@ esphome/components/sfa30/* @ghsensdev esphome/components/sgp40/* @SenexCrenshaw esphome/components/sgp4x/* @SenexCrenshaw @martgras esphome/components/shelly_dimmer/* @edge90 @rnauber +esphome/components/sht3xd/* @mrtoy-me esphome/components/sht4x/* @sjtrny esphome/components/shutdown/* @esphome/core @jsuanet esphome/components/sigma_delta_output/* @Cat-Ion diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index 80e15a1ab9..1286489b29 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_HEATER_ENABLED = "heater_enabled" +CODEOWNERS = ["@mrtoy-me"] + DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -26,13 +28,13 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(SHT3XDComponent), - cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, accuracy_decimals=1, device_class=DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Required(CONF_HUMIDITY): sensor.sensor_schema( + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, accuracy_decimals=1, device_class=DEVICE_CLASS_HUMIDITY, diff --git a/esphome/components/sht3xd/sht3xd.cpp b/esphome/components/sht3xd/sht3xd.cpp index 25332165c0..888e954c6b 100644 --- a/esphome/components/sht3xd/sht3xd.cpp +++ b/esphome/components/sht3xd/sht3xd.cpp @@ -6,7 +6,11 @@ namespace sht3xd { static const char *const TAG = "sht3xd"; -static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER = 0x3780; +// use read serial number register with clock stretching disabled as per other SHT3XD_COMMAND registers +// which provides support for SHT85 sensor +// SHT85 does not support clock stretching and uses same registers as SHT3xd with clock stretching disabled +static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER = 0x3682; + static const uint16_t SHT3XD_COMMAND_READ_STATUS = 0xF32D; static const uint16_t SHT3XD_COMMAND_CLEAR_STATUS = 0x3041; static const uint16_t SHT3XD_COMMAND_HEATER_ENABLE = 0x306D; @@ -22,25 +26,32 @@ void SHT3XDComponent::setup() { this->mark_failed(); return; } + this->serial_number_ = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); + if (!this->write_command(heater_enabled_ ? SHT3XD_COMMAND_HEATER_ENABLE : SHT3XD_COMMAND_HEATER_DISABLE)) { this->mark_failed(); return; } - uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); - ESP_LOGV(TAG, " Serial Number: 0x%08" PRIX32, serial_number); } + void SHT3XDComponent::dump_config() { ESP_LOGCONFIG(TAG, "SHT3xD:"); - LOG_I2C_DEVICE(this); if (this->is_failed()) { - ESP_LOGE(TAG, "Communication with SHT3xD failed!"); + ESP_LOGE(TAG, " Communication with SHT3xD failed!"); + return; } + ESP_LOGD(TAG, " Serial Number: 0x%08" PRIX32, this->serial_number_); + ESP_LOGD(TAG, " Heater Enabled: %s", this->heater_enabled_ ? "true" : "false"); + + LOG_I2C_DEVICE(this); LOG_UPDATE_INTERVAL(this); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); } + float SHT3XDComponent::get_setup_priority() const { return setup_priority::DATA; } + void SHT3XDComponent::update() { if (this->status_has_warning()) { ESP_LOGD(TAG, "Retrying to reconnect the sensor."); diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h index 4133bf7b93..d1a3360e69 100644 --- a/esphome/components/sht3xd/sht3xd.h +++ b/esphome/components/sht3xd/sht3xd.h @@ -25,6 +25,7 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; bool heater_enabled_{true}; + uint32_t serial_number_{0}; }; } // namespace sht3xd From dc0a7b1e205f5fa4e25fd1cadd507c27173636e1 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 28 Mar 2024 12:51:01 -0700 Subject: [PATCH 1475/2607] Add missing ethernet types (#6444) --- esphome/components/ethernet/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index de6040339a..ade94cb9f5 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -155,6 +155,8 @@ CONFIG_SCHEMA = cv.All( "DP83848": RMII_SCHEMA, "IP101": RMII_SCHEMA, "JL1101": RMII_SCHEMA, + "KSZ8081": RMII_SCHEMA, + "KSZ8081RNA": RMII_SCHEMA, "W5500": SPI_SCHEMA, }, upper=True, From f4e8a8972635bd99c72b47a69cde7c6a19cf61bb Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 1 Apr 2024 01:40:11 +0200 Subject: [PATCH 1476/2607] IPv6 string representation follows RFC5952 (#6449) --- esphome/components/network/ip_address.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index b02c358a77..30a426e458 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -4,6 +4,7 @@ #include #include #include "esphome/core/macros.h" +#include "esphome/core/helpers.h" #if defined(USE_ESP_IDF) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0) #include @@ -116,7 +117,7 @@ struct IPAddress { bool is_set() { return !ip_addr_isany(&ip_addr_); } bool is_ip4() { return IP_IS_V4(&ip_addr_); } bool is_ip6() { return IP_IS_V6(&ip_addr_); } - std::string str() const { return ipaddr_ntoa(&ip_addr_); } + std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); } bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); } bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); } IPAddress &operator+=(uint8_t increase) { From 1207eda4ca19bce2db574f84d9f30f3068183856 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:41:43 +1300 Subject: [PATCH 1477/2607] Bump actions/setup-python from 5.0.0 to 5.1.0 (#6437) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/sync-device-classes.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 0b2465d1aa..40766ad728 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -23,7 +23,7 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - name: Set up Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: "3.11" diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index f02efadf4d..d8fd4efa0e 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -42,7 +42,7 @@ jobs: steps: - uses: actions/checkout@v4.1.1 - name: Set up Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: "3.9" - name: Set up Docker Buildx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0ac840972..7df57acb08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 16469c904b..cb7defc2b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v4.1.1 - name: Set up Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: "3.x" - name: Set up python environment @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@v4.1.1 - name: Set up Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: "3.9" diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 3f8af4249a..c12f1f31b5 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -22,7 +22,7 @@ jobs: path: lib/home-assistant - name: Setup Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: 3.11 From 3a49e91ce03201c13133dee1a2bf0f474805682d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:42:02 +1300 Subject: [PATCH 1478/2607] Bump actions/setup-python from 5.0.0 to 5.1.0 in /.github/actions/restore-python (#6438) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index aa4f7ba887..4ad9e2eaed 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -17,7 +17,7 @@ runs: steps: - name: Set up Python ${{ inputs.python-version }} id: python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment From 1be5d14fd946b708bb1016bc26158bdc2e20d1f2 Mon Sep 17 00:00:00 2001 From: NewoPL <27411874+NewoPL@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:43:49 +0200 Subject: [PATCH 1479/2607] fix: changing the content source when playing is paused blocks the player (#6454) --- .../i2s_audio/media_player/i2s_audio_media_player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 9e2e3f136a..6e07983920 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -12,12 +12,12 @@ static const char *const TAG = "audio"; void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { if (call.get_media_url().has_value()) { this->current_url_ = call.get_media_url(); - - if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && this->audio_ != nullptr) { + if (this->i2s_state_ != I2S_STATE_STOPPED && this->audio_ != nullptr) { if (this->audio_->isRunning()) { this->audio_->stopSong(); } this->audio_->connecttohost(this->current_url_.value().c_str()); + this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; } else { this->start(); } From 63db07a156756b30aa2fdc9b35e14f9d4c0ed16f Mon Sep 17 00:00:00 2001 From: tronikos Date: Mon, 1 Apr 2024 13:21:53 -0700 Subject: [PATCH 1480/2607] Optimize QMC5883L: Read registers only for enabled sensors (#6458) --- esphome/components/qmc5883l/qmc5883l.cpp | 45 +++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index f03b6af191..4052b395f9 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -76,15 +76,8 @@ void QMC5883LComponent::dump_config() { float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } void QMC5883LComponent::update() { uint8_t status = false; - this->read_byte(QMC5883L_REGISTER_STATUS, &status); - - uint16_t raw_x, raw_y, raw_z; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x) || - !this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y) || - !this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { - this->status_set_warning(); - return; - } + if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG) + this->read_byte(QMC5883L_REGISTER_STATUS, &status); float mg_per_bit; switch (this->range_) { @@ -99,11 +92,37 @@ void QMC5883LComponent::update() { } // in µT - const float x = int16_t(raw_x) * mg_per_bit * 0.1f; - const float y = int16_t(raw_y) * mg_per_bit * 0.1f; - const float z = int16_t(raw_z) * mg_per_bit * 0.1f; + float x = NAN, y = NAN, z = NAN; + if (this->x_sensor_ != nullptr || this->heading_sensor_ != nullptr) { + uint16_t raw_x; + if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x)) { + this->status_set_warning(); + return; + } + x = int16_t(raw_x) * mg_per_bit * 0.1f; + } + if (this->y_sensor_ != nullptr || this->heading_sensor_ != nullptr) { + uint16_t raw_y; + if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y)) { + this->status_set_warning(); + return; + } + y = int16_t(raw_y) * mg_per_bit * 0.1f; + } + if (this->z_sensor_ != nullptr) { + uint16_t raw_z; + if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { + this->status_set_warning(); + return; + } + z = int16_t(raw_z) * mg_per_bit * 0.1f; + } + + float heading = NAN; + if (this->heading_sensor_ != nullptr) { + heading = atan2f(0.0f - x, y) * 180.0f / M_PI; + } - float heading = atan2f(0.0f - x, y) * 180.0f / M_PI; ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f° status=%u", x, y, z, heading, status); if (this->x_sensor_ != nullptr) From 6deb253fa68879d8b03b05be97644d05cf572fd3 Mon Sep 17 00:00:00 2001 From: Leland Sindt Date: Mon, 1 Apr 2024 21:32:40 -0500 Subject: [PATCH 1481/2607] minor refactor to allow commit hash as ref value. (#6446) --- esphome/git.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/esphome/git.py b/esphome/git.py index 4f0911233e..e41777f425 100644 --- a/esphome/git.py +++ b/esphome/git.py @@ -59,17 +59,14 @@ def clone_or_update( ) repo_dir = _compute_destination_path(key, domain) - fetch_pr_branch = ref is not None and ref.startswith("pull/") if not repo_dir.is_dir(): _LOGGER.info("Cloning %s", key) _LOGGER.debug("Location: %s", repo_dir) cmd = ["git", "clone", "--depth=1"] - if ref is not None and not fetch_pr_branch: - cmd += ["--branch", ref] cmd += ["--", url, str(repo_dir)] run_git_command(cmd) - if fetch_pr_branch: + if ref is not None: # We need to fetch the PR branch first, otherwise git will complain # about missing objects _LOGGER.info("Fetching %s", ref) From e32b8296702539e2d5cfafa4dbefae280a1abc06 Mon Sep 17 00:00:00 2001 From: mrtoy-me <118446898+mrtoy-me@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:35:59 +1000 Subject: [PATCH 1482/2607] TMP117 fix polling period config (#6452) --- esphome/components/tmp117/sensor.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/tmp117/sensor.py b/esphome/components/tmp117/sensor.py index fb97258bc1..82d099cf12 100644 --- a/esphome/components/tmp117/sensor.py +++ b/esphome/components/tmp117/sensor.py @@ -30,37 +30,37 @@ CONFIG_SCHEMA = cv.All( def determine_config_register(polling_period): - if polling_period >= 16.0: + if polling_period >= 16000: # 64 averaged conversions, max conversion time # 0000 00 111 11 00000 # 0000 0011 1110 0000 return 0x03E0 - if polling_period >= 8.0: + if polling_period >= 8000: # 64 averaged conversions, high conversion time # 0000 00 110 11 00000 # 0000 0011 0110 0000 return 0x0360 - if polling_period >= 4.0: + if polling_period >= 4000: # 64 averaged conversions, mid conversion time # 0000 00 101 11 00000 # 0000 0010 1110 0000 return 0x02E0 - if polling_period >= 1.0: + if polling_period >= 1000: # 64 averaged conversions, min conversion time # 0000 00 000 11 00000 # 0000 0000 0110 0000 return 0x0060 - if polling_period >= 0.5: + if polling_period >= 500: # 32 averaged conversions, min conversion time # 0000 00 000 10 00000 # 0000 0000 0100 0000 return 0x0040 - if polling_period >= 0.25: + if polling_period >= 250: # 8 averaged conversions, mid conversion time # 0000 00 010 01 00000 # 0000 0001 0010 0000 return 0x0120 - if polling_period >= 0.125: + if polling_period >= 125: # 8 averaged conversions, min conversion time # 0000 00 000 01 00000 # 0000 0000 0010 0000 @@ -76,5 +76,5 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - update_period = config[CONF_UPDATE_INTERVAL].total_seconds + update_period = config[CONF_UPDATE_INTERVAL].total_milliseconds cg.add(var.set_config(determine_config_register(update_period))) From ec32501d405a462bb8120d94ae504265d7832f15 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 2 Apr 2024 05:00:47 +0200 Subject: [PATCH 1483/2607] Bump Arduino Pico Framework to 3.7.2 and Platform to 1.12.0 (#6386) --- esphome/components/rp2040/__init__.py | 4 ++-- platformio.ini | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index d027f48244..b262a068fb 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -74,12 +74,12 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/earlephilhower/arduino-pico/releases # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 6, 0) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 7, 2) # The platformio/raspberrypi version to use for arduino frameworks # - https://github.com/platformio/platform-raspberrypi/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 10, 0) +ARDUINO_PLATFORM_VERSION = cv.Version(1, 12, 0) def _arduino_check_versions(value): diff --git a/platformio.ini b/platformio.ini index db5fb3a544..5fedd14086 100644 --- a/platformio.ini +++ b/platformio.ini @@ -154,13 +154,12 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script ; These are common settings for the RP2040 using Arduino. [common:rp2040-arduino] extends = common:arduino -board_build.core = earlephilhower board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.6.0/rp2040-3.6.0.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.7.2/rp2040-3.7.2.zip framework = arduino lib_deps = From 4fcb26d69dd4b245023df25d63946e5a974a391c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Apr 2024 07:33:18 +1300 Subject: [PATCH 1484/2607] Display menu: Allow "left" key to exit current menu if not editing (#6460) --- esphome/components/display_menu_base/display_menu_base.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/display_menu_base/display_menu_base.cpp b/esphome/components/display_menu_base/display_menu_base.cpp index 0bfee338ca..5502623607 100644 --- a/esphome/components/display_menu_base/display_menu_base.cpp +++ b/esphome/components/display_menu_base/display_menu_base.cpp @@ -60,6 +60,8 @@ void DisplayMenuComponent::left() { if (this->editing_) { this->finish_editing_(); changed = true; + } else { + changed = this->leave_menu_(); } break; case MENU_MODE_JOYSTICK: From 02632f0cad8a6026225765e9da48ffb5ff353a26 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:16:38 +1300 Subject: [PATCH 1485/2607] Fix NOLINT on inclusive-language check (#6464) --- esphome/components/pmsx003/pmsx003.h | 9 +++++---- script/ci-custom.py | 26 +++++++++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/esphome/components/pmsx003/pmsx003.h b/esphome/components/pmsx003/pmsx003.h index eb33f66909..cb5c16aecf 100644 --- a/esphome/components/pmsx003/pmsx003.h +++ b/esphome/components/pmsx003/pmsx003.h @@ -1,16 +1,17 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" +#include "esphome/core/component.h" namespace esphome { namespace pmsx003 { // known command bytes -#define PMS_CMD_AUTO_MANUAL 0xE1 // data=0: perform measurement manually, data=1: perform measurement automatically -#define PMS_CMD_TRIG_MANUAL 0xE2 // trigger a manual measurement -#define PMS_CMD_ON_STANDBY 0xE4 // data=0: go to standby mode, data=1: go to normal mode +static const uint8_t PMS_CMD_AUTO_MANUAL = + 0xE1; // data=0: perform measurement manually, data=1: perform measurement automatically +static const uint8_t PMS_CMD_TRIG_MANUAL = 0xE2; // trigger a manual measurement +static const uint8_t PMS_CMD_ON_STANDBY = 0xE4; // data=0: go to standby mode, data=1: go to normal mode static const uint16_t PMS_STABILISING_MS = 30000; // time taken for the sensor to become stable after power on diff --git a/script/ci-custom.py b/script/ci-custom.py index 422fdf52f0..1ad44dc930 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -57,6 +57,7 @@ file_types = ( "", ) cpp_include = ("*.h", "*.c", "*.cpp", "*.tcc") +py_include = ("*.py",) ignore_types = (".ico", ".png", ".woff", ".woff2", "") LINT_FILE_CHECKS = [] @@ -265,7 +266,8 @@ def lint_end_newline(fname, content): return None -CPP_RE_EOL = r"\s*?(?://.*?)?$" +CPP_RE_EOL = r".*?(?://.*?)?$" +PY_RE_EOL = r".*?(?:#.*?)?$" def highlight(s): @@ -273,7 +275,7 @@ def highlight(s): @lint_re_check( - r"^#define\s+([a-zA-Z0-9_]+)\s+([0-9bx]+)" + CPP_RE_EOL, + r"^#define\s+([a-zA-Z0-9_]+)\s+(0b[10]+|0x[0-9a-fA-F]+|\d+)\s*?(?:\/\/.*?)?$", include=cpp_include, exclude=[ "esphome/core/log.h", @@ -574,11 +576,6 @@ def lint_pragma_once(fname, content): return None -@lint_re_check( - r"(whitelist|blacklist|slave)", - exclude=["script/ci-custom.py"], - flags=re.IGNORECASE | re.MULTILINE, -) def lint_inclusive_language(fname, match): # From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=49decddd39e5f6132ccd7d9fdc3d7c470b0061bb return ( @@ -596,6 +593,21 @@ def lint_inclusive_language(fname, match): ) +lint_re_check( + r"(whitelist|blacklist|slave)" + PY_RE_EOL, + include=py_include, + exclude=["script/ci-custom.py"], + flags=re.IGNORECASE | re.MULTILINE, +)(lint_inclusive_language) + + +lint_re_check( + r"(whitelist|blacklist|slave)" + CPP_RE_EOL, + include=cpp_include, + flags=re.IGNORECASE | re.MULTILINE, +)(lint_inclusive_language) + + @lint_re_check(r"[\t\r\f\v ]+$") def lint_trailing_whitespace(fname, match): return "Trailing whitespace detected" From be8d188a558cc0cf239b11133789f9f42c69c57b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:16:59 +1300 Subject: [PATCH 1486/2607] Add yamllint to dev requirements (#6466) --- requirements_dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements_dev.txt b/requirements_dev.txt index 6b6319d0a0..6bfa015c6f 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,3 +1,4 @@ # Useful stuff when working in a development environment clang-format==13.0.1 clang-tidy==14.0.6 +yamllint==1.35.1 From 96f4c70b6b256fb43420f9f5431f3d5bc6df7c67 Mon Sep 17 00:00:00 2001 From: tronikos Date: Tue, 2 Apr 2024 19:57:05 -0700 Subject: [PATCH 1487/2607] Add temperature for QMC5883L (#6456) --- esphome/components/qmc5883l/qmc5883l.cpp | 16 +++++++++++++++- esphome/components/qmc5883l/qmc5883l.h | 2 ++ esphome/components/qmc5883l/sensor.py | 13 +++++++++++++ tests/components/qmc5883l/test.esp32-c3-idf.yaml | 2 ++ tests/components/qmc5883l/test.esp32-c3.yaml | 2 ++ tests/components/qmc5883l/test.esp32-idf.yaml | 2 ++ tests/components/qmc5883l/test.esp32.yaml | 2 ++ tests/components/qmc5883l/test.esp8266.yaml | 2 ++ tests/components/qmc5883l/test.rp2040.yaml | 2 ++ 9 files changed, 42 insertions(+), 1 deletion(-) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 4052b395f9..4946ad1b77 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -72,6 +72,7 @@ void QMC5883LComponent::dump_config() { LOG_SENSOR(" ", "Y Axis", this->y_sensor_); LOG_SENSOR(" ", "Z Axis", this->z_sensor_); LOG_SENSOR(" ", "Heading", this->heading_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); } float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } void QMC5883LComponent::update() { @@ -123,7 +124,18 @@ void QMC5883LComponent::update() { heading = atan2f(0.0f - x, y) * 180.0f / M_PI; } - ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f° status=%u", x, y, z, heading, status); + float temp = NAN; + if (this->temperature_sensor_ != nullptr) { + uint16_t raw_temp; + if (!this->read_byte_16_(QMC5883L_REGISTER_TEMPERATURE_LSB, &raw_temp)) { + this->status_set_warning(); + return; + } + temp = int16_t(raw_temp) * 0.01f; + } + + ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f° temperature=%0.01f°C status=%u", x, y, z, heading, + temp, status); if (this->x_sensor_ != nullptr) this->x_sensor_->publish_state(x); @@ -133,6 +145,8 @@ void QMC5883LComponent::update() { this->z_sensor_->publish_state(z); if (this->heading_sensor_ != nullptr) this->heading_sensor_->publish_state(heading); + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(temp); } bool QMC5883LComponent::read_byte_16_(uint8_t a_register, uint16_t *data) { diff --git a/esphome/components/qmc5883l/qmc5883l.h b/esphome/components/qmc5883l/qmc5883l.h index 15ef435ce5..b0c0af40d2 100644 --- a/esphome/components/qmc5883l/qmc5883l.h +++ b/esphome/components/qmc5883l/qmc5883l.h @@ -40,6 +40,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice { void set_y_sensor(sensor::Sensor *y_sensor) { y_sensor_ = y_sensor; } void set_z_sensor(sensor::Sensor *z_sensor) { z_sensor_ = z_sensor; } void set_heading_sensor(sensor::Sensor *heading_sensor) { heading_sensor_ = heading_sensor; } + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } protected: QMC5883LDatarate datarate_{QMC5883L_DATARATE_10_HZ}; @@ -49,6 +50,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *y_sensor_{nullptr}; sensor::Sensor *z_sensor_{nullptr}; sensor::Sensor *heading_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py index b819fecfe1..24e1019507 100644 --- a/esphome/components/qmc5883l/sensor.py +++ b/esphome/components/qmc5883l/sensor.py @@ -6,12 +6,15 @@ from esphome.const import ( CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Z, + CONF_TEMPERATURE, CONF_ID, CONF_OVERSAMPLING, CONF_RANGE, + DEVICE_CLASS_TEMPERATURE, ICON_MAGNET, STATE_CLASS_MEASUREMENT, UNIT_MICROTESLA, + UNIT_CELSIUS, UNIT_DEGREES, ICON_SCREEN_ROTATION, CONF_UPDATE_INTERVAL, @@ -79,6 +82,12 @@ heading_schema = sensor.sensor_schema( icon=ICON_SCREEN_ROTATION, accuracy_decimals=1, ) +temperature_schema = sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, +) CONFIG_SCHEMA = ( cv.Schema( @@ -95,6 +104,7 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_FIELD_STRENGTH_Y): field_strength_schema, cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema, cv.Optional(CONF_HEADING): heading_schema, + cv.Optional(CONF_TEMPERATURE): temperature_schema, } ) .extend(cv.polling_component_schema("60s")) @@ -131,3 +141,6 @@ async def to_code(config): if CONF_HEADING in config: sens = await sensor.new_sensor(config[CONF_HEADING]) cg.add(var.set_heading_sensor(sens)) + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature_sensor(sens)) diff --git a/tests/components/qmc5883l/test.esp32-c3-idf.yaml b/tests/components/qmc5883l/test.esp32-c3-idf.yaml index c638f7e5be..841bbd5d1e 100644 --- a/tests/components/qmc5883l/test.esp32-c3-idf.yaml +++ b/tests/components/qmc5883l/test.esp32-c3-idf.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32-c3.yaml b/tests/components/qmc5883l/test.esp32-c3.yaml index c638f7e5be..841bbd5d1e 100644 --- a/tests/components/qmc5883l/test.esp32-c3.yaml +++ b/tests/components/qmc5883l/test.esp32-c3.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32-idf.yaml b/tests/components/qmc5883l/test.esp32-idf.yaml index 1aafa86cfa..9acd391497 100644 --- a/tests/components/qmc5883l/test.esp32-idf.yaml +++ b/tests/components/qmc5883l/test.esp32-idf.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp32.yaml b/tests/components/qmc5883l/test.esp32.yaml index 1aafa86cfa..9acd391497 100644 --- a/tests/components/qmc5883l/test.esp32.yaml +++ b/tests/components/qmc5883l/test.esp32.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s diff --git a/tests/components/qmc5883l/test.esp8266.yaml b/tests/components/qmc5883l/test.esp8266.yaml index c638f7e5be..841bbd5d1e 100644 --- a/tests/components/qmc5883l/test.esp8266.yaml +++ b/tests/components/qmc5883l/test.esp8266.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s diff --git a/tests/components/qmc5883l/test.rp2040.yaml b/tests/components/qmc5883l/test.rp2040.yaml index c638f7e5be..841bbd5d1e 100644 --- a/tests/components/qmc5883l/test.rp2040.yaml +++ b/tests/components/qmc5883l/test.rp2040.yaml @@ -14,6 +14,8 @@ sensor: name: QMC5883L Field Strength Z heading: name: QMC5883L Heading + temperature: + name: QMC5883L Temperature range: 800uT oversampling: 256x update_interval: 15s From 5cc3d60feef8e674342f5d6c97f76f1b6a7305e2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 4 Apr 2024 11:13:59 +1300 Subject: [PATCH 1488/2607] web_server: Return early if no clients connected (#6467) --- .../components/web_server/list_entities.cpp | 30 +++++++++++++++++ esphome/components/web_server/web_server.cpp | 32 ++++++++++++++++++- .../web_server_idf/web_server_idf.h | 6 ++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 197af1eb14..2252f55008 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -12,6 +12,8 @@ ListEntitiesIterator::ListEntitiesIterator(WebServer *web_server) : web_server_( #ifdef USE_BINARY_SENSOR bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send( this->web_server_->binary_sensor_json(binary_sensor, binary_sensor->state, DETAIL_ALL).c_str(), "state"); return true; @@ -19,30 +21,40 @@ bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_ #endif #ifdef USE_COVER bool ListEntitiesIterator::on_cover(cover::Cover *cover) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->cover_json(cover, DETAIL_ALL).c_str(), "state"); return true; } #endif #ifdef USE_FAN bool ListEntitiesIterator::on_fan(fan::Fan *fan) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->fan_json(fan, DETAIL_ALL).c_str(), "state"); return true; } #endif #ifdef USE_LIGHT bool ListEntitiesIterator::on_light(light::LightState *light) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->light_json(light, DETAIL_ALL).c_str(), "state"); return true; } #endif #ifdef USE_SENSOR bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->sensor_json(sensor, sensor->state, DETAIL_ALL).c_str(), "state"); return true; } #endif #ifdef USE_SWITCH bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->switch_json(a_switch, a_switch->state, DETAIL_ALL).c_str(), "state"); return true; @@ -50,12 +62,16 @@ bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { #endif #ifdef USE_BUTTON bool ListEntitiesIterator::on_button(button::Button *button) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->button_json(button, DETAIL_ALL).c_str(), "state"); return true; } #endif #ifdef USE_TEXT_SENSOR bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send( this->web_server_->text_sensor_json(text_sensor, text_sensor->state, DETAIL_ALL).c_str(), "state"); return true; @@ -63,6 +79,8 @@ bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) #endif #ifdef USE_LOCK bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->lock_json(a_lock, a_lock->state, DETAIL_ALL).c_str(), "state"); return true; } @@ -70,6 +88,8 @@ bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { #ifdef USE_CLIMATE bool ListEntitiesIterator::on_climate(climate::Climate *climate) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->climate_json(climate, DETAIL_ALL).c_str(), "state"); return true; } @@ -77,6 +97,8 @@ bool ListEntitiesIterator::on_climate(climate::Climate *climate) { #ifdef USE_NUMBER bool ListEntitiesIterator::on_number(number::Number *number) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->number_json(number, number->state, DETAIL_ALL).c_str(), "state"); return true; } @@ -84,6 +106,8 @@ bool ListEntitiesIterator::on_number(number::Number *number) { #ifdef USE_DATETIME_DATE bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->date_json(date, DETAIL_ALL).c_str(), "state"); return true; } @@ -91,6 +115,8 @@ bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { #ifdef USE_TEXT bool ListEntitiesIterator::on_text(text::Text *text) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->text_json(text, text->state, DETAIL_ALL).c_str(), "state"); return true; } @@ -98,6 +124,8 @@ bool ListEntitiesIterator::on_text(text::Text *text) { #ifdef USE_SELECT bool ListEntitiesIterator::on_select(select::Select *select) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send(this->web_server_->select_json(select, select->state, DETAIL_ALL).c_str(), "state"); return true; } @@ -105,6 +133,8 @@ bool ListEntitiesIterator::on_select(select::Select *select) { #ifdef USE_ALARM_CONTROL_PANEL bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + if (this->web_server_->events_.count() == 0) + return true; this->web_server_->events_.send( this->web_server_->alarm_control_panel_json(a_alarm_control_panel, a_alarm_control_panel->get_state(), DETAIL_ALL) .c_str(), diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index f065dc6684..4e6797ae1f 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -416,6 +416,8 @@ void WebServer::handle_js_request(AsyncWebServerRequest *request) { #ifdef USE_SENSOR void WebServer::on_sensor_update(sensor::Sensor *obj, float state) { + if (this->events_.count() == 0) + return; this->events_.send(this->sensor_json(obj, state, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -449,6 +451,8 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail #ifdef USE_TEXT_SENSOR void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) { + if (this->events_.count() == 0) + return; this->events_.send(this->text_sensor_json(obj, state, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -471,6 +475,8 @@ std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std: #ifdef USE_SWITCH void WebServer::on_switch_update(switch_::Switch *obj, bool state) { + if (this->events_.count() == 0) + return; this->events_.send(this->switch_json(obj, state, DETAIL_STATE).c_str(), "state"); } std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail start_config) { @@ -532,6 +538,8 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM #ifdef USE_BINARY_SENSOR void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) { + if (this->events_.count() == 0) + return; this->events_.send(this->binary_sensor_json(obj, state, DETAIL_STATE).c_str(), "state"); } std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool value, JsonDetail start_config) { @@ -553,7 +561,11 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con #endif #ifdef USE_FAN -void WebServer::on_fan_update(fan::Fan *obj) { this->events_.send(this->fan_json(obj, DETAIL_STATE).c_str(), "state"); } +void WebServer::on_fan_update(fan::Fan *obj) { + if (this->events_.count() == 0) + return; + this->events_.send(this->fan_json(obj, DETAIL_STATE).c_str(), "state"); +} std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) { return json::build_json([obj, start_config](JsonObject root) { set_json_icon_state_value(root, obj, "fan-" + obj->get_object_id(), obj->state ? "ON" : "OFF", obj->state, @@ -623,6 +635,8 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc #ifdef USE_LIGHT void WebServer::on_light_update(light::LightState *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->light_json(obj, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -729,6 +743,8 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi #ifdef USE_COVER void WebServer::on_cover_update(cover::Cover *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->cover_json(obj, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -798,6 +814,8 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) { #ifdef USE_NUMBER void WebServer::on_number_update(number::Number *obj, float state) { + if (this->events_.count() == 0) + return; this->events_.send(this->number_json(obj, state, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -856,6 +874,8 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail #ifdef USE_DATETIME_DATE void WebServer::on_date_update(datetime::DateEntity *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->date_json(obj, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -903,6 +923,8 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con #ifdef USE_TEXT void WebServer::on_text_update(text::Text *obj, const std::string &state) { + if (this->events_.count() == 0) + return; this->events_.send(this->text_json(obj, state, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -954,6 +976,8 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json #ifdef USE_SELECT void WebServer::on_select_update(select::Select *obj, const std::string &state, size_t index) { + if (this->events_.count() == 0) + return; this->events_.send(this->select_json(obj, state, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -1008,6 +1032,8 @@ std::string WebServer::select_json(select::Select *obj, const std::string &value #ifdef USE_CLIMATE void WebServer::on_climate_update(climate::Climate *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->climate_json(obj, DETAIL_STATE).c_str(), "state"); } @@ -1149,6 +1175,8 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf #ifdef USE_LOCK void WebServer::on_lock_update(lock::Lock *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->lock_json(obj, obj->state, DETAIL_STATE).c_str(), "state"); } std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDetail start_config) { @@ -1185,6 +1213,8 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat #ifdef USE_ALARM_CONTROL_PANEL void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE).c_str(), "state"); } std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmControlPanel *obj, diff --git a/esphome/components/web_server_idf/web_server_idf.h b/esphome/components/web_server_idf/web_server_idf.h index 750f890fc7..2ead5e3f03 100644 --- a/esphome/components/web_server_idf/web_server_idf.h +++ b/esphome/components/web_server_idf/web_server_idf.h @@ -3,11 +3,11 @@ #include -#include #include -#include #include #include +#include +#include namespace esphome { namespace web_server_idf { @@ -251,6 +251,8 @@ class AsyncEventSource : public AsyncWebHandler { void send(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0); + size_t count() const { return this->sessions_.size(); } + protected: std::string url_; std::set sessions_; From f09bfa731181e7dce43165d9d2a2b886053c5afd Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Thu, 4 Apr 2024 02:55:24 +0300 Subject: [PATCH 1489/2607] ESP32 Arduino WiFi: misc bug fixes (#6470) --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 35e6c57e62..44d77b4eed 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -582,14 +582,14 @@ void WiFiComponent::wifi_pre_setup_() { } WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { auto status = WiFiClass::status(); - if (status == WL_CONNECTED) { - return WiFiSTAConnectStatus::CONNECTED; - } else if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { + if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; } else if (status == WL_NO_SSID_AVAIL) { return WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND; } else if (s_sta_connecting) { return WiFiSTAConnectStatus::CONNECTING; + } else if (status == WL_CONNECTED) { + return WiFiSTAConnectStatus::CONNECTED; } return WiFiSTAConnectStatus::IDLE; } @@ -707,7 +707,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.ap.password = 0; } else { conf.ap.authmode = WIFI_AUTH_WPA2_PSK; - strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.ssid)); + strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password)); } conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP; From 0148ebcaa604f929aba06b6722697bb1b6e4c83c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:41:41 +1300 Subject: [PATCH 1490/2607] Replace std::regex with sscanf calls (#6468) * Replace std::regex with sscanf calls * Fix CI * Use regular formatting placeholders * Fix --- esphome/core/time.cpp | 77 +++++++++++++++++++++---------------------- esphome/core/time.h | 4 --- 2 files changed, 37 insertions(+), 44 deletions(-) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index ae4fabac52..0004fc7e8e 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -1,9 +1,7 @@ -#ifdef USE_DATETIME -#include -#endif - -#include "helpers.h" #include "time.h" // NOLINT +#include "helpers.h" + +#include namespace esphome { @@ -66,48 +64,47 @@ std::string ESPTime::strftime(const std::string &format) { return timestr; } -#ifdef USE_DATETIME - bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { - // clang-format off - std::regex dt_regex(R"(^ - ( - (\d{4})-(\d{1,2})-(\d{1,2}) - (?:\s(?=.+)) - )? - ( - (\d{1,2}):(\d{2}) - (?::(\d{2}))? - )? - $)"); - // clang-format on + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + int num; - std::smatch match; - if (std::regex_match(time_to_parse, match, dt_regex) == 0) + if (sscanf(time_to_parse.c_str(), "%04hu-%02hhu-%02hhu %02hhu:%02hhu:%02hhu %n", &year, &month, &day, // NOLINT + &hour, // NOLINT + &minute, // NOLINT + &second, &num) == 6 && // NOLINT + num == time_to_parse.size()) { + esp_time.year = year; + esp_time.month = month; + esp_time.day_of_month = day; + esp_time.hour = hour; + esp_time.minute = minute; + esp_time.second = second; + } else if (sscanf(time_to_parse.c_str(), "%02hhu:%02hhu:%02hhu %n", &hour, &minute, &second, &num) == 3 && // NOLINT + num == time_to_parse.size()) { + esp_time.hour = hour; + esp_time.minute = minute; + esp_time.second = second; + } else if (sscanf(time_to_parse.c_str(), "%02hhu:%02hhu %n", &hour, &minute, &num) == 2 && // NOLINT + num == time_to_parse.size()) { + esp_time.hour = hour; + esp_time.minute = minute; + esp_time.second = 0; + } else if (sscanf(time_to_parse.c_str(), "%04hu-%02hhu-%02hhu %n", &year, &month, &day, &num) == 3 && // NOLINT + num == time_to_parse.size()) { + esp_time.year = year; + esp_time.month = month; + esp_time.day_of_month = day; + } else { return false; - - if (match[1].matched) { // Has date parts - - esp_time.year = parse_number(match[2].str()).value_or(0); - esp_time.month = parse_number(match[3].str()).value_or(0); - esp_time.day_of_month = parse_number(match[4].str()).value_or(0); } - if (match[5].matched) { // Has time parts - - esp_time.hour = parse_number(match[6].str()).value_or(0); - esp_time.minute = parse_number(match[7].str()).value_or(0); - if (match[8].matched) { - esp_time.second = parse_number(match[8].str()).value_or(0); - } else { - esp_time.second = 0; - } - } - return true; } -#endif - void ESPTime::increment_second() { this->timestamp++; if (!increment_time_value(this->second, 0, 60)) diff --git a/esphome/core/time.h b/esphome/core/time.h index 738a0261c7..4300cf26b7 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -67,8 +67,6 @@ struct ESPTime { this->day_of_year < 367 && this->month > 0 && this->month < 13; } -#ifdef USE_DATETIME - /** Convert a string to ESPTime struct as specified by the format argument. * @param time_to_parse null-terminated c string formatet like this: 2020-08-25 05:30:00. * @param esp_time an instance of a ESPTime struct @@ -76,8 +74,6 @@ struct ESPTime { */ static bool strptime(const std::string &time_to_parse, ESPTime &esp_time); -#endif - /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); From 4c9bcc71cbcf285daa7a73e30b7eadf834503e64 Mon Sep 17 00:00:00 2001 From: DAVe3283 Date: Wed, 20 Mar 2024 17:57:27 -0600 Subject: [PATCH 1491/2607] Fix logger compile error on ESP32-C6 (#6323) --- esphome/components/logger/logger_esp32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index 7c4d6781c9..740e086f92 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -129,7 +129,7 @@ void Logger::pre_setup() { this->uart_num_ = UART_NUM_2; break; #endif -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#ifdef USE_LOGGER_USB_CDC case UART_SELECTION_USB_CDC: this->uart_num_ = -1; break; From 87c4ad025698b2e240c397d54332a3a62e92cd81 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 28 Mar 2024 12:51:01 -0700 Subject: [PATCH 1492/2607] Add missing ethernet types (#6444) --- esphome/components/ethernet/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index de6040339a..ade94cb9f5 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -155,6 +155,8 @@ CONFIG_SCHEMA = cv.All( "DP83848": RMII_SCHEMA, "IP101": RMII_SCHEMA, "JL1101": RMII_SCHEMA, + "KSZ8081": RMII_SCHEMA, + "KSZ8081RNA": RMII_SCHEMA, "W5500": SPI_SCHEMA, }, upper=True, From d2b386146509837264079d93d9d5d3fb598f1137 Mon Sep 17 00:00:00 2001 From: NewoPL <27411874+NewoPL@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:43:49 +0200 Subject: [PATCH 1493/2607] fix: changing the content source when playing is paused blocks the player (#6454) --- .../i2s_audio/media_player/i2s_audio_media_player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 9e2e3f136a..6e07983920 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -12,12 +12,12 @@ static const char *const TAG = "audio"; void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { if (call.get_media_url().has_value()) { this->current_url_ = call.get_media_url(); - - if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && this->audio_ != nullptr) { + if (this->i2s_state_ != I2S_STATE_STOPPED && this->audio_ != nullptr) { if (this->audio_->isRunning()) { this->audio_->stopSong(); } this->audio_->connecttohost(this->current_url_.value().c_str()); + this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; } else { this->start(); } From c029ef51181412dd8e35ef8e5280d5cd2a38abdc Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 4 Apr 2024 18:12:28 +1300 Subject: [PATCH 1494/2607] Bump version to 2024.3.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index b09d0a8eb0..5368f0bc9a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.3.1" +__version__ = "2024.3.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 2c67d83976305e21ae2bcd93f0412db0a6e13814 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:21:56 +1100 Subject: [PATCH 1495/2607] Include "Failed" status in config log. (#6482) --- esphome/core/component.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index b9a7697015..803bc11e02 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -76,7 +76,12 @@ bool Component::cancel_timeout(const std::string &name) { // NOLINT void Component::call_loop() { this->loop(); } void Component::call_setup() { this->setup(); } -void Component::call_dump_config() { this->dump_config(); } +void Component::call_dump_config() { + this->dump_config(); + if (this->is_failed()) { + ESP_LOGE(this->get_component_source(), " Component is marked FAILED"); + } +} uint32_t Component::get_component_state() const { return this->component_state_; } void Component::call() { From 38233444e7e30a031defb3198f6be12c08fed328 Mon Sep 17 00:00:00 2001 From: Remy van Elst Date: Sun, 7 Apr 2024 04:48:42 +0200 Subject: [PATCH 1496/2607] Fix Microphone IsCapturingCondition (#6490) --- esphome/components/microphone/automation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/microphone/automation.h b/esphome/components/microphone/automation.h index 5313f07f72..29c0ec5df2 100644 --- a/esphome/components/microphone/automation.h +++ b/esphome/components/microphone/automation.h @@ -23,7 +23,7 @@ class DataTrigger : public Trigger &> { } }; -template class IsCapturingActon : public Condition, public Parented { +template class IsCapturingCondition : public Condition, public Parented { public: bool check(Ts... x) override { return this->parent_->is_running(); } }; From 97ff87b71893f4d1e01b61722bf4e556014699b6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:13:12 +1000 Subject: [PATCH 1497/2607] Remove misleading tag/line in messages (#6495) --- esphome/core/component.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 803bc11e02..594e8ff7df 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -79,7 +79,7 @@ void Component::call_setup() { this->setup(); } void Component::call_dump_config() { this->dump_config(); if (this->is_failed()) { - ESP_LOGE(this->get_component_source(), " Component is marked FAILED"); + ESP_LOGE(TAG, " Component %s is marked FAILED", this->get_component_source()); } } @@ -154,26 +154,26 @@ void Component::status_set_warning(const char *message) { return; this->component_state_ |= STATUS_LED_WARNING; App.app_state_ |= STATUS_LED_WARNING; - ESP_LOGW(this->get_component_source(), "Warning set: %s", message); + ESP_LOGW(TAG, "Component %s set Warning flag: %s", this->get_component_source(), message); } void Component::status_set_error(const char *message) { if ((this->component_state_ & STATUS_LED_ERROR) != 0) return; this->component_state_ |= STATUS_LED_ERROR; App.app_state_ |= STATUS_LED_ERROR; - ESP_LOGE(this->get_component_source(), "Error set: %s", message); + ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message); } void Component::status_clear_warning() { if ((this->component_state_ & STATUS_LED_WARNING) == 0) return; this->component_state_ &= ~STATUS_LED_WARNING; - ESP_LOGW(this->get_component_source(), "Warning cleared"); + ESP_LOGW(TAG, "Component %s cleared Warning flag", this->get_component_source()); } void Component::status_clear_error() { if ((this->component_state_ & STATUS_LED_ERROR) == 0) return; this->component_state_ &= ~STATUS_LED_ERROR; - ESP_LOGE(this->get_component_source(), "Error cleared"); + ESP_LOGE(TAG, "Component %s cleared Error flag", this->get_component_source()); } void Component::status_momentary_warning(const std::string &name, uint32_t length) { this->status_set_warning(); From 6f71363d9b9b2b35f13ff6bdde5870e9135e4977 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:19:22 +1200 Subject: [PATCH 1498/2607] Send/Receive Voice Assistant audio via API (#6471) Co-authored-by: Michael Hansen --- esphome/components/api/api.proto | 19 ++- esphome/components/api/api_connection.cpp | 27 ++++- esphome/components/api/api_connection.h | 1 + esphome/components/api/api_pb2.cpp | 83 ++++++++++++- esphome/components/api/api_pb2.h | 21 +++- esphome/components/api/api_pb2_service.cpp | 19 +++ esphome/components/api/api_pb2_service.h | 4 + .../voice_assistant/voice_assistant.cpp | 109 +++++++++++++----- .../voice_assistant/voice_assistant.h | 40 ++++++- 9 files changed, 275 insertions(+), 48 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 7efc7aef64..6b685b8974 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -217,7 +217,8 @@ message DeviceInfoResponse { string friendly_name = 13; - uint32 voice_assistant_version = 14; + uint32 legacy_voice_assistant_version = 14; + uint32 voice_assistant_feature_flags = 17; string suggested_area = 16; } @@ -1422,12 +1423,18 @@ message BluetoothDeviceClearCacheResponse { } // ==================== PUSH TO TALK ==================== +enum VoiceAssistantSubscribeFlag { + VOICE_ASSISTANT_SUBSCRIBE_NONE = 0; + VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1; +} + message SubscribeVoiceAssistantRequest { option (id) = 89; option (source) = SOURCE_CLIENT; option (ifdef) = "USE_VOICE_ASSISTANT"; bool subscribe = 1; + uint32 flags = 2; } enum VoiceAssistantRequestFlag { @@ -1495,6 +1502,16 @@ message VoiceAssistantEventResponse { repeated VoiceAssistantEventData data = 2; } +message VoiceAssistantAudio { + option (id) = 106; + option (source) = SOURCE_BOTH; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + bytes data = 1; + bool end = 2; +} + + // ==================== ALARM CONTROL PANEL ==================== enum AlarmControlPanelState { ALARM_STATE_DISARMED = 0; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bd4790df95..e9607f7f77 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1040,10 +1040,15 @@ void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &ms voice_assistant::global_voice_assistant->failed_to_start(); return; } - struct sockaddr_storage storage; - socklen_t len = sizeof(storage); - this->helper_->getpeername((struct sockaddr *) &storage, &len); - voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port); + if (msg.port == 0) { + // Use API Audio + voice_assistant::global_voice_assistant->start_streaming(); + } else { + struct sockaddr_storage storage; + socklen_t len = sizeof(storage); + this->helper_->getpeername((struct sockaddr *) &storage, &len); + voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port); + } } }; void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) { @@ -1055,6 +1060,15 @@ void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventR voice_assistant::global_voice_assistant->on_event(msg); } } +void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return; + } + + voice_assistant::global_voice_assistant->on_audio(msg); + } +}; #endif @@ -1142,7 +1156,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { HelloResponse resp; resp.api_version_major = 1; - resp.api_version_minor = 9; + resp.api_version_minor = 10; resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; resp.name = App.get_name(); @@ -1203,7 +1217,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags(); #endif #ifdef USE_VOICE_ASSISTANT - resp.voice_assistant_version = voice_assistant::global_voice_assistant->get_version(); + resp.legacy_voice_assistant_version = voice_assistant::global_voice_assistant->get_legacy_version(); + resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags(); #endif return resp; } diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 6fe6e0d509..c19c209969 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -134,6 +134,7 @@ class APIConnection : public APIServerConnection { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override; void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; + void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 32654f3148..f6325d0854 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -410,6 +410,19 @@ const char *proto_enum_to_string(enums::Bluet } #endif #ifdef HAS_PROTO_MESSAGE_DUMP +template<> +const char *proto_enum_to_string(enums::VoiceAssistantSubscribeFlag value) { + switch (value) { + case enums::VOICE_ASSISTANT_SUBSCRIBE_NONE: + return "VOICE_ASSISTANT_SUBSCRIBE_NONE"; + case enums::VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO: + return "VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef HAS_PROTO_MESSAGE_DUMP template<> const char *proto_enum_to_string(enums::VoiceAssistantRequestFlag value) { switch (value) { case enums::VOICE_ASSISTANT_REQUEST_NONE: @@ -716,7 +729,11 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { return true; } case 14: { - this->voice_assistant_version = value.as_uint32(); + this->legacy_voice_assistant_version = value.as_uint32(); + return true; + } + case 17: { + this->voice_assistant_feature_flags = value.as_uint32(); return true; } default: @@ -784,7 +801,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags); buffer.encode_string(12, this->manufacturer); buffer.encode_string(13, this->friendly_name); - buffer.encode_uint32(14, this->voice_assistant_version); + buffer.encode_uint32(14, this->legacy_voice_assistant_version); + buffer.encode_uint32(17, this->voice_assistant_feature_flags); buffer.encode_string(16, this->suggested_area); } #ifdef HAS_PROTO_MESSAGE_DUMP @@ -850,8 +868,13 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append("'").append(this->friendly_name).append("'"); out.append("\n"); - out.append(" voice_assistant_version: "); - sprintf(buffer, "%" PRIu32, this->voice_assistant_version); + out.append(" legacy_voice_assistant_version: "); + sprintf(buffer, "%" PRIu32, this->legacy_voice_assistant_version); + out.append(buffer); + out.append("\n"); + + out.append(" voice_assistant_feature_flags: "); + sprintf(buffer, "%" PRIu32, this->voice_assistant_feature_flags); out.append(buffer); out.append("\n"); @@ -6514,11 +6537,18 @@ bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarIn this->subscribe = value.as_bool(); return true; } + case 2: { + this->flags = value.as_uint32(); + return true; + } default: return false; } } -void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->subscribe); } +void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_bool(1, this->subscribe); + buffer.encode_uint32(2, this->flags); +} #ifdef HAS_PROTO_MESSAGE_DUMP void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; @@ -6526,6 +6556,11 @@ void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { out.append(" subscribe: "); out.append(YESNO(this->subscribe)); out.append("\n"); + + out.append(" flags: "); + sprintf(buffer, "%" PRIu32, this->flags); + out.append(buffer); + out.append("\n"); out.append("}"); } #endif @@ -6752,6 +6787,44 @@ void VoiceAssistantEventResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantAudio::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->end = value.as_bool(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->data = value.as_string(); + return true; + } + default: + return false; + } +} +void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->data); + buffer.encode_bool(2, this->end); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantAudio::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAudio {\n"); + out.append(" data: "); + out.append("'").append(this->data).append("'"); + out.append("\n"); + + out.append(" end: "); + out.append(YESNO(this->end)); + out.append("\n"); + out.append("}"); +} +#endif bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index f9847a6a19..e361e6b8e1 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -165,6 +165,10 @@ enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, }; +enum VoiceAssistantSubscribeFlag : uint32_t { + VOICE_ASSISTANT_SUBSCRIBE_NONE = 0, + VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1, +}; enum VoiceAssistantRequestFlag : uint32_t { VOICE_ASSISTANT_REQUEST_NONE = 0, VOICE_ASSISTANT_REQUEST_USE_VAD = 1, @@ -327,7 +331,8 @@ class DeviceInfoResponse : public ProtoMessage { uint32_t bluetooth_proxy_feature_flags{0}; std::string manufacturer{}; std::string friendly_name{}; - uint32_t voice_assistant_version{0}; + uint32_t legacy_voice_assistant_version{0}; + uint32_t voice_assistant_feature_flags{0}; std::string suggested_area{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1674,6 +1679,7 @@ class BluetoothDeviceClearCacheResponse : public ProtoMessage { class SubscribeVoiceAssistantRequest : public ProtoMessage { public: bool subscribe{false}; + uint32_t flags{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; @@ -1749,6 +1755,19 @@ class VoiceAssistantEventResponse : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantAudio : public ProtoMessage { + public: + std::string data{}; + bool end{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 4e61893bae..2067f530ce 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -476,6 +476,14 @@ bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantR #endif #ifdef USE_VOICE_ASSISTANT #endif +#ifdef USE_VOICE_ASSISTANT +bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAudio &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_voice_assistant_audio: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 106); +} +#endif #ifdef USE_ALARM_CONTROL_PANEL bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( const ListEntitiesAlarmControlPanelResponse &msg) { @@ -971,6 +979,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str()); #endif this->on_date_command_request(msg); +#endif + break; + } + case 106: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantAudio msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_audio(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index a3c53a7534..effcfc30f4 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -240,6 +240,10 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){}; #endif +#ifdef USE_VOICE_ASSISTANT + bool send_voice_assistant_audio(const VoiceAssistantAudio &msg); + virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){}; +#endif #ifdef USE_ALARM_CONTROL_PANEL bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); #endif diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 49b8fdc959..34a26eec01 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -24,28 +24,24 @@ static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } -void VoiceAssistant::setup() { - ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); - - global_voice_assistant = this; - +bool VoiceAssistant::start_udp_socket_() { this->socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (socket_ == nullptr) { - ESP_LOGW(TAG, "Could not create socket"); + if (this->socket_ == nullptr) { + ESP_LOGE(TAG, "Could not create socket"); this->mark_failed(); - return; + return false; } int enable = 1; - int err = socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + int err = this->socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); if (err != 0) { ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err); // we can still continue } - err = socket_->setblocking(false); + err = this->socket_->setblocking(false); if (err != 0) { - ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err); + ESP_LOGE(TAG, "Socket unable to set nonblocking mode: errno %d", err); this->mark_failed(); - return; + return false; } #ifdef USE_SPEAKER @@ -54,18 +50,30 @@ void VoiceAssistant::setup() { socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), 6055); if (sl == 0) { - ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); + ESP_LOGE(TAG, "Socket unable to set sockaddr: errno %d", errno); this->mark_failed(); - return; + return false; } - err = socket_->bind((struct sockaddr *) &server, sizeof(server)); + err = this->socket_->bind((struct sockaddr *) &server, sizeof(server)); if (err != 0) { - ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno); + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); this->mark_failed(); - return; + return false; } + } +#endif + this->udp_socket_running_ = true; + return true; +} +void VoiceAssistant::setup() { + ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); + + global_voice_assistant = this; + +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { ExternalRAMAllocator speaker_allocator(ExternalRAMAllocator::ALLOW_FAILURE); this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE); if (this->speaker_buffer_ == nullptr) { @@ -238,8 +246,20 @@ void VoiceAssistant::loop() { size_t available = this->ring_buffer_->available(); while (available >= SEND_BUFFER_SIZE) { size_t read_bytes = this->ring_buffer_->read((void *) this->send_buffer_, SEND_BUFFER_SIZE, 0); - this->socket_->sendto(this->send_buffer_, read_bytes, 0, (struct sockaddr *) &this->dest_addr_, - sizeof(this->dest_addr_)); + if (this->audio_mode_ == AUDIO_MODE_API) { + api::VoiceAssistantAudio msg; + msg.data.assign((char *) this->send_buffer_, read_bytes); + this->api_client_->send_voice_assistant_audio(msg); + } else { + if (!this->udp_socket_running_) { + if (!this->start_udp_socket_()) { + this->set_state_(State::STOP_MICROPHONE, State::IDLE); + break; + } + } + this->socket_->sendto(this->send_buffer_, read_bytes, 0, (struct sockaddr *) &this->dest_addr_, + sizeof(this->dest_addr_)); + } available = this->ring_buffer_->available(); } @@ -268,22 +288,25 @@ void VoiceAssistant::loop() { #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { ssize_t received_len = 0; - if (this->speaker_buffer_index_ + RECEIVE_SIZE < SPEAKER_BUFFER_SIZE) { - received_len = this->socket_->read(this->speaker_buffer_ + this->speaker_buffer_index_, RECEIVE_SIZE); - if (received_len > 0) { - this->speaker_buffer_index_ += received_len; - this->speaker_buffer_size_ += received_len; - this->speaker_bytes_received_ += received_len; + if (this->audio_mode_ == AUDIO_MODE_UDP) { + if (this->speaker_buffer_index_ + RECEIVE_SIZE < SPEAKER_BUFFER_SIZE) { + received_len = this->socket_->read(this->speaker_buffer_ + this->speaker_buffer_index_, RECEIVE_SIZE); + if (received_len > 0) { + this->speaker_buffer_index_ += received_len; + this->speaker_buffer_size_ += received_len; + this->speaker_bytes_received_ += received_len; + } + } else { + ESP_LOGD(TAG, "Receive buffer full"); } - } else { - ESP_LOGD(TAG, "Receive buffer full"); } // Build a small buffer of audio before sending to the speaker - if (this->speaker_bytes_received_ > RECEIVE_SIZE * 4) + bool end_of_stream = this->stream_ended_ && (this->audio_mode_ == AUDIO_MODE_API || received_len < 0); + if (this->speaker_bytes_received_ > RECEIVE_SIZE * 4 || end_of_stream) this->write_speaker_(); if (this->wait_for_stream_end_) { this->cancel_timeout("playing"); - if (this->stream_ended_ && received_len < 0) { + if (end_of_stream) { ESP_LOGD(TAG, "End of audio stream received"); this->cancel_timeout("speaker-timeout"); this->set_state_(State::RESPONSE_FINISHED, State::RESPONSE_FINISHED); @@ -428,6 +451,22 @@ void VoiceAssistant::failed_to_start() { this->set_state_(State::STOP_MICROPHONE, State::IDLE); } +void VoiceAssistant::start_streaming() { + if (this->state_ != State::STARTING_PIPELINE) { + this->signal_stop_(); + return; + } + + ESP_LOGD(TAG, "Client started, streaming microphone"); + this->audio_mode_ = AUDIO_MODE_API; + + if (this->mic_->is_running()) { + this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE); + } else { + this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE); + } +} + void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t port) { if (this->state_ != State::STARTING_PIPELINE) { this->signal_stop_(); @@ -435,6 +474,7 @@ void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t por } ESP_LOGD(TAG, "Client started, streaming microphone"); + this->audio_mode_ = AUDIO_MODE_UDP; memcpy(&this->dest_addr_, addr, sizeof(this->dest_addr_)); if (this->dest_addr_.ss_family == AF_INET) { @@ -688,6 +728,17 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } } +void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { + if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { + memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); + this->speaker_buffer_index_ += msg.data.length(); + this->speaker_buffer_size_ += msg.data.length(); + this->speaker_bytes_received_ += msg.data.length(); + } else { + ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); + } +} + VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace voice_assistant diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 14352bf3ae..d6b1502381 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -29,9 +29,14 @@ namespace voice_assistant { // Version 1: Initial version // Version 2: Adds raw speaker support -// Version 3: Unused/skip -static const uint32_t INITIAL_VERSION = 1; -static const uint32_t SPEAKER_SUPPORT = 2; +static const uint32_t LEGACY_INITIAL_VERSION = 1; +static const uint32_t LEGACY_SPEAKER_SUPPORT = 2; + +enum VoiceAssistantFeature : uint32_t { + FEATURE_VOICE_ASSISTANT = 1 << 0, + FEATURE_SPEAKER = 1 << 1, + FEATURE_API_AUDIO = 1 << 2, +}; enum class State { IDLE, @@ -49,11 +54,17 @@ enum class State { RESPONSE_FINISHED, }; +enum AudioMode : uint8_t { + AUDIO_MODE_UDP, + AUDIO_MODE_API, +}; + class VoiceAssistant : public Component { public: void setup() override; void loop() override; float get_setup_priority() const override; + void start_streaming(); void start_streaming(struct sockaddr_storage *addr, uint16_t port); void failed_to_start(); @@ -71,19 +82,32 @@ class VoiceAssistant : public Component { } #endif - uint32_t get_version() const { + uint32_t get_legacy_version() const { #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { - return SPEAKER_SUPPORT; + return LEGACY_SPEAKER_SUPPORT; } #endif - return INITIAL_VERSION; + return LEGACY_INITIAL_VERSION; + } + + uint32_t get_feature_flags() const { + uint32_t flags = 0; + flags |= VoiceAssistantFeature::FEATURE_VOICE_ASSISTANT; +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + flags |= VoiceAssistantFeature::FEATURE_SPEAKER; + flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; + } +#endif + return flags; } void request_start(bool continuous, bool silence_detection); void request_stop(); void on_event(const api::VoiceAssistantEventResponse &msg); + void on_audio(const api::VoiceAssistantAudio &msg); bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } @@ -201,6 +225,10 @@ class VoiceAssistant : public Component { State state_{State::IDLE}; State desired_state_{State::IDLE}; + + AudioMode audio_mode_{AUDIO_MODE_UDP}; + bool udp_socket_running_{false}; + bool start_udp_socket_(); }; template class StartAction : public Action, public Parented { From d6352b3be416a90e454f2c5b4fa168c4ef4fe1a2 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Mon, 8 Apr 2024 09:36:23 +0200 Subject: [PATCH 1499/2607] Datetime date initial value fix (#6483) --- esphome/components/template/datetime/__init__.py | 11 ++++++++++- esphome/components/web_server/web_server.cpp | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/esphome/components/template/datetime/__init__.py b/esphome/components/template/datetime/__init__.py index 034be9b3b8..16f341301e 100644 --- a/esphome/components/template/datetime/__init__.py +++ b/esphome/components/template/datetime/__init__.py @@ -8,6 +8,9 @@ from esphome.const import ( CONF_OPTIMISTIC, CONF_RESTORE_VALUE, CONF_SET_ACTION, + CONF_DAY, + CONF_MONTH, + CONF_YEAR, ) from esphome.core import coroutine_with_priority @@ -82,7 +85,13 @@ async def to_code(config): cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE])) if initial_value := config.get(CONF_INITIAL_VALUE): - cg.add(var.set_initial_value(initial_value)) + date_struct = cg.StructInitializer( + cg.ESPTime, + ("day_of_month", initial_value[CONF_DAY]), + ("month", initial_value[CONF_MONTH]), + ("year", initial_value[CONF_YEAR]), + ) + cg.add(var.set_initial_value(date_struct)) if CONF_SET_ACTION in config: await automation.build_automation( diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 4e6797ae1f..6c3e4e5eec 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -914,7 +914,7 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_config) { return json::build_json([obj, start_config](JsonObject root) { set_json_id(root, obj, "date-" + obj->get_object_id(), start_config); - std::string value = str_sprintf("%d-%d-%d", obj->year, obj->month, obj->day); + std::string value = str_sprintf("%d-%02d-%02d", obj->year, obj->month, obj->day); root["value"] = value; root["state"] = value; }); From e6b1187689b81d38fc4f755a88922cdd820319e1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:56:08 +1000 Subject: [PATCH 1500/2607] If the loop() took more than the required time, don't delay further (#6496) --- esphome/core/application.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index d82a7a5d37..a4550bcd9e 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -81,13 +81,11 @@ void Application::loop() { const uint32_t now = millis(); - if (HighFrequencyLoopRequester::is_high_frequency()) { + auto elapsed = now - this->last_loop_; + if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) { yield(); } else { - uint32_t delay_time = this->loop_interval_; - if (now - this->last_loop_ < this->loop_interval_) - delay_time = this->loop_interval_ - (now - this->last_loop_); - + uint32_t delay_time = this->loop_interval_ - elapsed; uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time); // next_schedule is max 0.5*delay_time // otherwise interval=0 schedules result in constant looping with almost no sleep From 46c63f48c25e278dcf485bc7c4cf315e4d9a9a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 8 Apr 2024 21:19:50 +0200 Subject: [PATCH 1501/2607] Bump LibreTiny version to 1.5.1 (#6500) --- esphome/components/libretiny/__init__.py | 2 +- esphome/components/rtl87xx/boards.py | 132 +++++++++++++---------- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 7dca370eff..34aff0ae16 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -170,7 +170,7 @@ def _notify_old_style(config): ARDUINO_VERSIONS = { "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"), "latest": (cv.Version(0, 0, 0), None), - "recommended": (cv.Version(1, 4, 1), None), + "recommended": (cv.Version(1, 5, 1), None), } diff --git a/esphome/components/rtl87xx/boards.py b/esphome/components/rtl87xx/boards.py index 6c29467f6e..e737767a56 100644 --- a/esphome/components/rtl87xx/boards.py +++ b/esphome/components/rtl87xx/boards.py @@ -36,6 +36,10 @@ RTL87XX_BOARDS = { "name": "T103_V1.0", "family": FAMILY_RTL8710B, }, + "t112-v1.1": { + "name": "T112_V1.1", + "family": FAMILY_RTL8710B, + }, "wr1": { "name": "WR1 Wi-Fi Module", "family": FAMILY_RTL8710B, @@ -125,7 +129,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -136,9 +139,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 22, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -180,11 +181,9 @@ RTL87XX_BOARD_PINS = { "SERIAL2_RTS": 20, "SERIAL2_RX": 15, "SERIAL2_TX": 16, - "CS0": 15, "CTS1": 4, "CTS2": 19, "MISO0": 20, - "MOSI0": 19, "PA00": 0, "PA0": 0, "PA01": 1, @@ -203,23 +202,15 @@ RTL87XX_BOARD_PINS = { "PA18": 18, "PA19": 19, "PA20": 20, - "PWM0": 0, "PWM1": 1, - "PWM2": 14, - "PWM3": 3, - "PWM4": 16, "PWM5": 17, "PWM6": 18, - "PWM7": 13, "RTS2": 20, "RX0": 13, - "RX1": 0, "RX2": 15, - "SCK0": 3, "SCL0": 19, "SDA0": 3, "TX0": 14, - "TX1": 1, "TX2": 16, "D0": 17, "D1": 18, @@ -294,7 +285,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -305,9 +295,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -390,7 +378,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -401,9 +388,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -485,7 +470,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -496,9 +480,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -560,7 +542,6 @@ RTL87XX_BOARD_PINS = { "CTS0": 10, "CTS1": 4, "CTS2": 19, - "MISO0": 20, "MOSI0": 19, "PA00": 0, "PA0": 0, @@ -591,23 +572,13 @@ RTL87XX_BOARD_PINS = { "PA20": 20, "PA23": 23, "PWM0": 20, - "PWM1": 12, - "PWM2": 14, - "PWM3": 15, - "PWM4": 16, "PWM5": 17, "PWM6": 18, "PWM7": 23, "RTS0": 9, "RTS2": 20, - "RX0": 13, - "RX1": 2, "RX2": 15, "SCK0": 16, - "SCL0": 19, - "SDA0": 20, - "TX0": 14, - "TX1": 3, "TX2": 16, "D0": 0, "D1": 1, @@ -652,7 +623,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 14, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -720,7 +690,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -731,9 +700,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -751,6 +718,75 @@ RTL87XX_BOARD_PINS = { "A0": 19, "A1": 41, }, + "t112-v1.1": { + "SPI0_CS": 19, + "SPI0_MISO": 22, + "SPI0_MOSI": 23, + "SPI0_SCK": 18, + "SPI1_CS": 19, + "SPI1_MISO": 22, + "SPI1_MOSI": 23, + "SPI1_SCK": 18, + "WIRE0_SCL_0": 29, + "WIRE0_SCL_1": 22, + "WIRE0_SDA_0": 19, + "WIRE0_SDA_1": 30, + "WIRE1_SCL": 18, + "WIRE1_SDA": 23, + "SERIAL0_CTS": 19, + "SERIAL0_RTS": 22, + "SERIAL0_RX": 18, + "SERIAL0_TX": 23, + "SERIAL2_RX": 29, + "SERIAL2_TX": 30, + "ADC1": 19, + "CS0": 19, + "CS1": 19, + "CTS0": 19, + "MISO0": 22, + "MISO1": 22, + "MOSI0": 23, + "MOSI1": 23, + "PA00": 0, + "PA0": 0, + "PA05": 5, + "PA5": 5, + "PA12": 12, + "PA14": 14, + "PA15": 15, + "PA18": 18, + "PA19": 19, + "PA22": 22, + "PA23": 23, + "PA29": 29, + "PA30": 30, + "PWM1": 15, + "PWM2": 0, + "PWM3": 12, + "PWM4": 30, + "PWM5": 22, + "RTS0": 22, + "RX0": 18, + "RX2": 29, + "SCK0": 18, + "SCK1": 18, + "SCL1": 18, + "SDA1": 23, + "TX0": 23, + "TX2": 30, + "D0": 29, + "D1": 19, + "D2": 15, + "D3": 14, + "D4": 0, + "D5": 5, + "D6": 18, + "D7": 12, + "D8": 23, + "D9": 22, + "D10": 30, + "A0": 19, + }, "wr1": { "SPI0_CS": 19, "SPI0_MISO": 22, @@ -793,7 +829,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 14, "PWM1": 15, "PWM2": 0, "PWM4": 29, @@ -803,9 +838,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 22, "SCL1": 18, - "SDA0": 19, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -863,7 +896,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 14, "PWM1": 15, "PWM3": 12, "PWM4": 29, @@ -873,9 +905,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 22, "SCL1": 18, - "SDA0": 19, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -915,7 +945,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 14, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -969,7 +998,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 14, "PWM1": 15, "PWM3": 12, "PWM4": 29, @@ -979,7 +1007,6 @@ RTL87XX_BOARD_PINS = { "SCK1": 18, "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -1083,7 +1110,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -1094,9 +1120,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -1157,7 +1181,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -1168,9 +1191,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 22, "SCL1": 18, - "SDA0": 19, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -1231,7 +1252,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -1242,9 +1262,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 29, "SCL1": 18, - "SDA0": 30, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -1305,7 +1323,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, @@ -1316,9 +1333,7 @@ RTL87XX_BOARD_PINS = { "RX2": 29, "SCK0": 18, "SCK1": 18, - "SCL0": 22, "SCL1": 18, - "SDA0": 19, "SDA1": 23, "TX0": 23, "TX2": 30, @@ -1359,7 +1374,6 @@ RTL87XX_BOARD_PINS = { "PA23": 23, "PA29": 29, "PA30": 30, - "PWM0": 23, "PWM1": 15, "PWM2": 0, "PWM3": 12, From 270fb5e7ac24cfea3841e8e1f173a308c5437d2e Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:21:51 +0000 Subject: [PATCH 1502/2607] Internal temperature: Support Beken platform (#6491) --- .../internal_temperature/internal_temperature.cpp | 15 +++++++++++++++ esphome/components/internal_temperature/sensor.py | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index a387708263..255d95f6f8 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -14,6 +14,11 @@ uint8_t temprature_sens_read(); #ifdef USE_RP2040 #include "Arduino.h" #endif // USE_RP2040 +#ifdef USE_BK72XX +extern "C" { +uint32_t temp_single_get_current_temperature(uint32_t *temp_value); +} +#endif // USE_BK72XX namespace esphome { namespace internal_temperature { @@ -46,6 +51,16 @@ void InternalTemperatureSensor::update() { temperature = analogReadTemp(); success = (temperature != 0.0f); #endif // USE_RP2040 +#ifdef USE_BK72XX + uint32_t raw, result; + result = temp_single_get_current_temperature(&raw); + success = (result == 0); +#ifdef USE_LIBRETINY_VARIANT_BK7231T + temperature = raw * 0.04f; +#else + temperature = raw * 0.128f; +#endif // USE_LIBRETINY_VARIANT_BK7231T +#endif // USE_BK72XX if (success && std::isfinite(temperature)) { this->publish_state(temperature); } else { diff --git a/esphome/components/internal_temperature/sensor.py b/esphome/components/internal_temperature/sensor.py index 2daf816538..809d7a40b9 100644 --- a/esphome/components/internal_temperature/sensor.py +++ b/esphome/components/internal_temperature/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, PLATFORM_ESP32, PLATFORM_RP2040, + PLATFORM_BK72XX, ) from esphome.core import CORE @@ -51,7 +52,7 @@ CONFIG_SCHEMA = cv.All( state_class=STATE_CLASS_MEASUREMENT, entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ).extend(cv.polling_component_schema("60s")), - cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040]), + cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040, PLATFORM_BK72XX]), validate_config, ) From 708d5034cb5eb92654056c546bdb1e5c0b25ecb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:48:04 +1200 Subject: [PATCH 1503/2607] Bump docker/setup-buildx-action from 3.2.0 to 3.3.0 (#6502) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index d8fd4efa0e..6063d1e052 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 + uses: docker/setup-buildx-action@v3.3.0 - name: Set up QEMU uses: docker/setup-qemu-action@v3.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb7defc2b0..7c0ec0270b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,7 +84,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 + uses: docker/setup-buildx-action@v3.3.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.0.0 @@ -162,7 +162,7 @@ jobs: name: digests-${{ matrix.image.target }}-${{ matrix.registry }} path: /tmp/digests - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 + uses: docker/setup-buildx-action@v3.3.0 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From efc9fd060d3f46d7a843fd0dfc523910075ccca9 Mon Sep 17 00:00:00 2001 From: fariouche Date: Tue, 9 Apr 2024 00:17:51 +0200 Subject: [PATCH 1504/2607] add support for Tuya pink version of miflora (#5402) --- CODEOWNERS | 1 + .../components/xiaomi_hhccjcy10/__init__.py | 1 + esphome/components/xiaomi_hhccjcy10/sensor.py | 96 +++++++++++++++++++ .../xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp | 68 +++++++++++++ .../xiaomi_hhccjcy10/xiaomi_hhccjcy10.h | 38 ++++++++ tests/test2.yaml | 12 +++ 6 files changed, 216 insertions(+) create mode 100644 esphome/components/xiaomi_hhccjcy10/__init__.py create mode 100644 esphome/components/xiaomi_hhccjcy10/sensor.py create mode 100644 esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp create mode 100644 esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h diff --git a/CODEOWNERS b/CODEOWNERS index fafbaae6c6..d2a86cd3d9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -404,6 +404,7 @@ esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard esphome/components/wl_134/* @hobbypunk90 esphome/components/x9c/* @EtienneMD esphome/components/xgzp68xx/* @gcormier +esphome/components/xiaomi_hhccjcy10/* @fariouche esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_mhoc303/* @drug123 esphome/components/xiaomi_mhoc401/* @vevsvevs diff --git a/esphome/components/xiaomi_hhccjcy10/__init__.py b/esphome/components/xiaomi_hhccjcy10/__init__.py new file mode 100644 index 0000000000..d47cef13c6 --- /dev/null +++ b/esphome/components/xiaomi_hhccjcy10/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@fariouche"] diff --git a/esphome/components/xiaomi_hhccjcy10/sensor.py b/esphome/components/xiaomi_hhccjcy10/sensor.py new file mode 100644 index 0000000000..4f77fa8103 --- /dev/null +++ b/esphome/components/xiaomi_hhccjcy10/sensor.py @@ -0,0 +1,96 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, esp32_ble_tracker +from esphome.const import ( + CONF_MAC_ADDRESS, + CONF_TEMPERATURE, + DEVICE_CLASS_ILLUMINANCE, + DEVICE_CLASS_TEMPERATURE, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_WATER_PERCENT, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PERCENT, + CONF_ID, + CONF_MOISTURE, + CONF_ILLUMINANCE, + UNIT_LUX, + CONF_CONDUCTIVITY, + UNIT_MICROSIEMENS_PER_CENTIMETER, + ICON_FLOWER, + DEVICE_CLASS_BATTERY, + CONF_BATTERY_LEVEL, +) + +DEPENDENCIES = ["esp32_ble_tracker"] + +xiaomi_hhccjcy10_ns = cg.esphome_ns.namespace("xiaomi_hhccjcy10") +XiaomiHHCCJCY10 = xiaomi_hhccjcy10_ns.class_( + "XiaomiHHCCJCY10", esp32_ble_tracker.ESPBTDeviceListener, cg.Component +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XiaomiHHCCJCY10), + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MOISTURE): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_WATER_PERCENT, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CONDUCTIVITY): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROSIEMENS_PER_CENTIMETER, + icon=ICON_FLOWER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_BATTERY, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ) + .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature(sens)) + if moisture_config := config.get(CONF_MOISTURE): + sens = await sensor.new_sensor(moisture_config) + cg.add(var.set_moisture(sens)) + if illuminance_config := config.get(CONF_ILLUMINANCE): + sens = await sensor.new_sensor(illuminance_config) + cg.add(var.set_illuminance(sens)) + if conductivity_config := config.get(CONF_CONDUCTIVITY): + sens = await sensor.new_sensor(conductivity_config) + cg.add(var.set_conductivity(sens)) + if battery_level_config := config.get(CONF_BATTERY_LEVEL): + sens = await sensor.new_sensor(battery_level_config) + cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp new file mode 100644 index 0000000000..45d4cceb52 --- /dev/null +++ b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp @@ -0,0 +1,68 @@ +#include "xiaomi_hhccjcy10.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_hhccjcy10 { + +static const char *const TAG = "xiaomi_hhccjcy10"; + +void XiaomiHHCCJCY10::dump_config() { + ESP_LOGCONFIG(TAG, "Xiaomi HHCCJCY10"); + LOG_SENSOR(" ", "Temperature", this->temperature_); + LOG_SENSOR(" ", "Moisture", this->moisture_); + LOG_SENSOR(" ", "Conductivity", this->conductivity_); + LOG_SENSOR(" ", "Illuminance", this->illuminance_); + LOG_SENSOR(" ", "Battery Level", this->battery_level_); +} + +bool XiaomiHHCCJCY10::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { + if (device.address_uint64() != this->address_) { + ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); + return false; + } + ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); + + bool success = false; + for (auto &service_data : device.get_service_datas()) { + if (!service_data.uuid.contains(0x50, 0xFD)) { + ESP_LOGVV(TAG, "no tuya service data UUID."); + continue; + } + if (service_data.data.size() != 9) { // tuya alternate between two service data + continue; + } + const uint8_t *data = service_data.data.data(); + + if (this->temperature_ != nullptr) { + const int16_t temperature = encode_uint16(data[1], data[2]); + this->temperature_->publish_state((float) temperature / 10.0f); + } + + if (this->moisture_ != nullptr) + this->moisture_->publish_state(data[0]); + + if (this->conductivity_ != nullptr) { + const uint16_t conductivity = encode_uint16(data[7], data[8]); + this->conductivity_->publish_state((float) conductivity); + } + + if (this->illuminance_ != nullptr) { + const uint32_t illuminance = encode_uint24(data[3], data[4], data[5]); + this->illuminance_->publish_state((float) illuminance); + } + + if (this->battery_level_ != nullptr) + this->battery_level_->publish_state(data[6]); + success = true; + } + + return success; +} + +} // namespace xiaomi_hhccjcy10 +} // namespace esphome + +#endif diff --git a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h new file mode 100644 index 0000000000..bc1e580ce4 --- /dev/null +++ b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h @@ -0,0 +1,38 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_hhccjcy10 { + +class XiaomiHHCCJCY10 : public Component, public esp32_ble_tracker::ESPBTDeviceListener { + public: + void set_address(uint64_t address) { this->address_ = address; } + + bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; + + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; } + void set_moisture(sensor::Sensor *moisture) { this->moisture_ = moisture; } + void set_conductivity(sensor::Sensor *conductivity) { this->conductivity_ = conductivity; } + void set_illuminance(sensor::Sensor *illuminance) { this->illuminance_ = illuminance; } + void set_battery_level(sensor::Sensor *battery_level) { this->battery_level_ = battery_level; } + + protected: + uint64_t address_; + sensor::Sensor *temperature_{nullptr}; + sensor::Sensor *moisture_{nullptr}; + sensor::Sensor *conductivity_{nullptr}; + sensor::Sensor *illuminance_{nullptr}; + sensor::Sensor *battery_level_{nullptr}; +}; + +} // namespace xiaomi_hhccjcy10 +} // namespace esphome + +#endif diff --git a/tests/test2.yaml b/tests/test2.yaml index a1e310be9c..2fdef72c08 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -203,6 +203,18 @@ sensor: name: Xiaomi HHCCJCY01 Soil Conductivity battery_level: name: Xiaomi HHCCJCY01 Battery Level + - platform: xiaomi_hhccjcy10 + mac_address: DD:25:6D:E4:FF:8F + temperature: + name: "Xiaomi HHCCJCY10 Temperature" + moisture: + name: "Xiaomi HHCCJCY10 Moisture" + illuminance: + name: "Xiaomi HHCCJCY10 Illuminance" + conductivity: + name: "Xiaomi HHCCJCY10 Soil Conductivity" + battery_level: + name: "Xiaomi HHCCJCY10 Battery Level" - platform: xiaomi_lywsdcgq mac_address: 7A:80:8E:19:36:BA temperature: From 16d154e2e5ec31957f233173dfcf55b37eead1c8 Mon Sep 17 00:00:00 2001 From: cvwillegen Date: Tue, 9 Apr 2024 03:07:04 +0200 Subject: [PATCH 1505/2607] Add MAC address to WiFi config reply (#6489) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/captive_portal/captive_index.h | 190 +++++++++--------- .../captive_portal/captive_portal.cpp | 2 +- 2 files changed, 97 insertions(+), 95 deletions(-) diff --git a/esphome/components/captive_portal/captive_index.h b/esphome/components/captive_portal/captive_index.h index 56071f3d2a..d262a89b09 100644 --- a/esphome/components/captive_portal/captive_index.h +++ b/esphome/components/captive_portal/captive_index.h @@ -6,100 +6,102 @@ namespace esphome { namespace captive_portal { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x5b, 0x8f, 0xdb, 0x36, 0x16, 0x7e, 0xef, - 0xaf, 0xe0, 0x2a, 0x49, 0x2d, 0x37, 0x23, 0xea, 0x66, 0xf9, 0x2a, 0xa9, 0x48, 0xb2, 0x29, 0x5a, 0x20, 0x69, 0x03, - 0xcc, 0xb4, 0xfb, 0x10, 0x04, 0x18, 0x5a, 0xa2, 0x2c, 0x66, 0x24, 0x4a, 0x15, 0xe9, 0x5b, 0x0c, 0xef, 0x6f, 0xdf, - 0x43, 0x52, 0xf6, 0x38, 0xb3, 0x99, 0x05, 0x52, 0xec, 0x62, 0xd1, 0x4e, 0x26, 0x1c, 0x92, 0x3a, 0xd7, 0x4f, 0x3c, - 0x17, 0x2a, 0xfe, 0x5b, 0xde, 0x64, 0x72, 0xdf, 0x52, 0x54, 0xca, 0xba, 0x4a, 0x63, 0x35, 0xa2, 0x8a, 0xf0, 0x55, - 0x42, 0x39, 0xac, 0x28, 0xc9, 0xd3, 0xb8, 0xa6, 0x92, 0xa0, 0xac, 0x24, 0x9d, 0xa0, 0x32, 0xf9, 0xf5, 0xe6, 0x07, - 0x67, 0x8a, 0xdc, 0x34, 0xae, 0x18, 0xbf, 0x43, 0x1d, 0xad, 0x12, 0x96, 0x35, 0x1c, 0x95, 0x1d, 0x2d, 0x92, 0x9c, - 0x48, 0x32, 0x67, 0x35, 0x59, 0x51, 0x45, 0xa0, 0xd9, 0x38, 0xa9, 0x69, 0xb2, 0x61, 0x74, 0xdb, 0x36, 0x9d, 0x44, - 0x40, 0x29, 0x29, 0x97, 0x89, 0xb5, 0x65, 0xb9, 0x2c, 0x93, 0x9c, 0x6e, 0x58, 0x46, 0x1d, 0xbd, 0xb8, 0x62, 0x9c, - 0x49, 0x46, 0x2a, 0x47, 0x64, 0xa4, 0xa2, 0x89, 0x7f, 0xb5, 0x16, 0xb4, 0xd3, 0x0b, 0xb2, 0x84, 0x35, 0x6f, 0x2c, - 0x10, 0x29, 0xb2, 0x8e, 0xb5, 0x12, 0x29, 0x7b, 0x93, 0xba, 0xc9, 0xd7, 0x15, 0x4d, 0x5d, 0x97, 0x08, 0xb0, 0x4b, - 0xb8, 0x8c, 0xe7, 0x74, 0x87, 0xa7, 0xb3, 0x68, 0x32, 0x9e, 0xe6, 0x13, 0xfc, 0x51, 0x7c, 0x03, 0x9e, 0xad, 0x6b, - 0x50, 0x87, 0xab, 0x26, 0x23, 0x92, 0x35, 0x1c, 0x0b, 0x4a, 0xba, 0xac, 0x4c, 0x92, 0xc4, 0xfa, 0x5e, 0x90, 0x0d, - 0xb5, 0xbe, 0xfd, 0xd6, 0x3e, 0x13, 0xad, 0xa8, 0x7c, 0x5d, 0x51, 0x35, 0x15, 0x2f, 0xf7, 0x37, 0x64, 0xf5, 0x33, - 0x58, 0x6e, 0x5b, 0x44, 0xb0, 0x9c, 0x5a, 0xc3, 0xf7, 0xde, 0x07, 0x2c, 0xe4, 0xbe, 0xa2, 0x38, 0x67, 0xa2, 0xad, - 0xc8, 0x3e, 0xb1, 0x96, 0x20, 0xf5, 0xce, 0x1a, 0x2e, 0x8a, 0x35, 0xcf, 0x94, 0x70, 0x24, 0x6c, 0x3a, 0x3c, 0x54, - 0x14, 0xcc, 0x4b, 0xde, 0x12, 0x59, 0xe2, 0x9a, 0xec, 0x6c, 0x33, 0x61, 0xdc, 0x0e, 0xbe, 0xb3, 0xe9, 0x73, 0xdf, - 0xf3, 0x86, 0x57, 0x7a, 0xf0, 0x86, 0x2e, 0xfc, 0x5d, 0x74, 0x54, 0xae, 0x3b, 0x8e, 0x88, 0x7d, 0x1b, 0xb7, 0x40, - 0x89, 0xf2, 0xc4, 0xaa, 0xfd, 0x00, 0x7b, 0xde, 0x14, 0xf9, 0x33, 0x1c, 0x44, 0x8e, 0xef, 0xe3, 0xd0, 0xf1, 0xa3, - 0x6c, 0xe2, 0x44, 0xc8, 0x1f, 0xc1, 0x10, 0x04, 0x38, 0x42, 0xde, 0x27, 0x0b, 0x15, 0xac, 0xaa, 0x12, 0x8b, 0x37, - 0x9c, 0x5a, 0x48, 0xc8, 0xae, 0xb9, 0xa3, 0x89, 0x95, 0xad, 0xbb, 0x0e, 0xec, 0x7f, 0xd5, 0x54, 0x4d, 0x07, 0x70, - 0x7d, 0x83, 0x3e, 0xfb, 0xf9, 0x6a, 0x15, 0xb2, 0x23, 0x5c, 0x14, 0x4d, 0x57, 0x27, 0x96, 0x7e, 0x29, 0xf6, 0xd3, - 0x83, 0x3c, 0x22, 0x35, 0x0c, 0x2f, 0x1e, 0x3a, 0x4d, 0xc7, 0x56, 0x8c, 0x27, 0x96, 0x1f, 0x20, 0x7f, 0x0a, 0x6a, - 0x6f, 0x87, 0xc7, 0x33, 0x26, 0x44, 0x61, 0xd2, 0x7b, 0xd9, 0xd8, 0xef, 0x6f, 0x63, 0xb1, 0x59, 0xa1, 0x5d, 0x5d, - 0x71, 0x91, 0x58, 0xa5, 0x94, 0xed, 0xdc, 0x75, 0xb7, 0xdb, 0x2d, 0xde, 0x86, 0xb8, 0xe9, 0x56, 0x6e, 0xe0, 0x79, - 0x9e, 0x0b, 0x14, 0x16, 0x32, 0xe7, 0xc3, 0x0a, 0x46, 0x16, 0x2a, 0x29, 0x5b, 0x95, 0x52, 0xcf, 0xd3, 0xa7, 0x07, - 0x7a, 0x8c, 0x15, 0x45, 0x7a, 0xfb, 0xe1, 0x42, 0x4b, 0x77, 0xa1, 0x85, 0x7e, 0x7f, 0x81, 0xe6, 0xe0, 0xad, 0x32, - 0x6a, 0x42, 0x02, 0x14, 0x20, 0x4f, 0xff, 0x0b, 0x1c, 0x35, 0xef, 0x57, 0xce, 0x83, 0x15, 0xba, 0x58, 0xc1, 0x5f, - 0xc0, 0x2f, 0xa8, 0xc7, 0xce, 0xec, 0xcc, 0xee, 0xab, 0xc7, 0x1b, 0xdf, 0xbb, 0xdf, 0x50, 0x3c, 0x3f, 0x8e, 0x2f, - 0xd7, 0x4e, 0xf0, 0x9b, 0x22, 0x50, 0xd8, 0x9f, 0x99, 0x9c, 0xa0, 0xf4, 0x7f, 0x1b, 0x93, 0x08, 0x45, 0xfd, 0x4e, - 0xe4, 0xa8, 0xf9, 0x79, 0xa5, 0x34, 0xa1, 0x68, 0x03, 0x54, 0xb5, 0x33, 0x76, 0x22, 0x12, 0xa2, 0xb0, 0x37, 0x09, - 0x66, 0xb0, 0x3d, 0x06, 0xe6, 0x8b, 0x3d, 0x27, 0xfc, 0x34, 0x50, 0x30, 0xcf, 0x2d, 0xeb, 0x1e, 0x83, 0xe6, 0x12, - 0x03, 0xfc, 0xb1, 0x81, 0x33, 0x67, 0x59, 0x80, 0x11, 0x95, 0x59, 0x69, 0x5b, 0x2e, 0x44, 0x5e, 0xc1, 0x56, 0x10, - 0x15, 0x0d, 0xb7, 0x86, 0x58, 0x96, 0x94, 0xdb, 0x27, 0x56, 0xc5, 0x48, 0xf5, 0x13, 0xfb, 0xe1, 0x13, 0x39, 0x3c, - 0x9c, 0xe3, 0x43, 0x32, 0x09, 0x71, 0x28, 0xb1, 0x8a, 0xe8, 0xab, 0xf3, 0xee, 0xb2, 0xc9, 0xf7, 0x8f, 0x84, 0x4e, - 0xe9, 0x9b, 0xb8, 0x61, 0x9c, 0xd3, 0xee, 0x86, 0xee, 0xe0, 0x1d, 0xfe, 0x83, 0xfd, 0xc0, 0xd0, 0xcf, 0x54, 0x6e, - 0x9b, 0xee, 0x4e, 0xcc, 0x91, 0xf5, 0xdc, 0x88, 0x5b, 0xa8, 0xa8, 0x61, 0x20, 0x9b, 0xb4, 0x02, 0x8b, 0x0a, 0x72, - 0x82, 0xed, 0x0f, 0x21, 0x7e, 0xda, 0x7b, 0x4b, 0xf8, 0xc9, 0xb9, 0xdb, 0x38, 0x67, 0x1b, 0x94, 0x55, 0x10, 0xf5, - 0x70, 0xfc, 0x8d, 0x28, 0x0b, 0xf5, 0x47, 0xbd, 0xe1, 0x19, 0x70, 0xdf, 0x25, 0xd6, 0x17, 0xa2, 0xfa, 0xe5, 0xfe, - 0xa7, 0xdc, 0x1e, 0x08, 0x88, 0xe7, 0xc1, 0x10, 0x6f, 0x48, 0xb5, 0xa6, 0x28, 0x41, 0xb2, 0x64, 0xe2, 0xde, 0xc0, - 0xc5, 0xa3, 0x6c, 0xad, 0xb8, 0x03, 0xae, 0x02, 0x1e, 0x0b, 0x7b, 0x68, 0x9d, 0x22, 0x2b, 0x26, 0x26, 0xef, 0x59, - 0x4f, 0xac, 0x07, 0x16, 0x39, 0x15, 0x2d, 0xa4, 0x75, 0x1f, 0x81, 0x4f, 0x0f, 0xc2, 0xe6, 0xb8, 0x03, 0xed, 0xc3, - 0xe3, 0x79, 0x33, 0x16, 0x2d, 0xe1, 0x0f, 0x19, 0x95, 0x81, 0xea, 0xa0, 0x43, 0xb2, 0x82, 0x99, 0x3a, 0xed, 0x40, - 0x74, 0x56, 0xe8, 0x92, 0xd3, 0xf4, 0xe9, 0xa1, 0x03, 0x89, 0x2a, 0x07, 0x9d, 0x25, 0xc6, 0x2e, 0x40, 0x93, 0xde, - 0x1e, 0x87, 0xf7, 0x7e, 0xfc, 0xbe, 0xa6, 0xdd, 0xfe, 0x9a, 0x56, 0x34, 0x93, 0x4d, 0x67, 0x5b, 0x4f, 0x40, 0x0b, - 0xbc, 0x7e, 0xed, 0xf0, 0x8f, 0x37, 0x6f, 0xdf, 0x24, 0x8d, 0xcd, 0x86, 0x57, 0x8f, 0x51, 0xab, 0x0c, 0xff, 0x1e, - 0x32, 0xfc, 0x3f, 0x93, 0x81, 0xca, 0xf1, 0x83, 0x0f, 0xc0, 0xaa, 0xfd, 0xbd, 0xbd, 0x4f, 0xf4, 0x2a, 0x18, 0x9f, - 0x43, 0x40, 0x5f, 0x29, 0x0f, 0x9d, 0x71, 0x34, 0x3c, 0x82, 0x7e, 0xb0, 0x00, 0xec, 0xd6, 0xb9, 0x1a, 0x72, 0xb6, - 0x4a, 0x9b, 0xe9, 0x77, 0x87, 0x65, 0xb3, 0x73, 0x04, 0xfb, 0xc4, 0xf8, 0x6a, 0xce, 0x78, 0x49, 0x3b, 0x26, 0x8f, - 0x60, 0x2e, 0xa4, 0xfd, 0x76, 0x2d, 0x0f, 0x2d, 0xc9, 0x73, 0xf5, 0x24, 0x6a, 0x77, 0x8b, 0x02, 0x8a, 0x84, 0xa2, - 0xa4, 0x73, 0x9f, 0xd6, 0x47, 0xf3, 0x5c, 0xe7, 0x83, 0xf9, 0x2c, 0x7a, 0x76, 0x54, 0x07, 0xee, 0x20, 0xe1, 0x65, - 0x39, 0xa4, 0x62, 0x2b, 0x3e, 0xcf, 0xc0, 0x70, 0xda, 0x19, 0xa6, 0x82, 0xd4, 0xac, 0xda, 0xcf, 0x05, 0x64, 0x26, - 0x07, 0xaa, 0x07, 0x2b, 0x8e, 0xcb, 0xb5, 0x94, 0x0d, 0x07, 0xdd, 0x5d, 0x4e, 0xbb, 0xb9, 0xb7, 0x30, 0x13, 0xa7, - 0x23, 0x39, 0x5b, 0x8b, 0x39, 0x0e, 0x3b, 0x5a, 0x2f, 0x96, 0x24, 0xbb, 0x5b, 0x75, 0xcd, 0x9a, 0xe7, 0x4e, 0xa6, - 0x32, 0xe7, 0xfc, 0x89, 0x5f, 0x90, 0x90, 0x66, 0x8b, 0x7e, 0x55, 0x14, 0xc5, 0x02, 0xa0, 0xa0, 0x8e, 0xc9, 0x44, - 0xf3, 0x00, 0x8f, 0x14, 0xdb, 0x85, 0x99, 0x38, 0x50, 0x1b, 0xc6, 0x46, 0x48, 0xeb, 0xcf, 0x16, 0x27, 0x77, 0xbc, - 0x05, 0xa4, 0x64, 0x01, 0x42, 0x5a, 0x88, 0x47, 0x30, 0xf3, 0x58, 0x13, 0xc6, 0x2f, 0xad, 0x57, 0xc7, 0x64, 0xd1, - 0x97, 0x14, 0x80, 0x45, 0xab, 0xd1, 0x85, 0x65, 0x01, 0x45, 0xc3, 0x14, 0xc6, 0x79, 0x30, 0xf6, 0xda, 0xdd, 0x11, - 0xf7, 0x07, 0xe4, 0x70, 0xa2, 0x2e, 0x2a, 0xba, 0x5b, 0x7c, 0x5c, 0x0b, 0xc9, 0x8a, 0xbd, 0xd3, 0x17, 0xd6, 0x39, - 0x1c, 0x16, 0x28, 0xa8, 0x4b, 0x20, 0xa5, 0x94, 0x2f, 0xb4, 0x0e, 0x87, 0x49, 0x5a, 0x8b, 0x1e, 0xa7, 0xb3, 0x18, - 0x7d, 0x40, 0x3f, 0x97, 0xf5, 0x9f, 0xa8, 0xd5, 0x59, 0x3c, 0xd4, 0xa4, 0x83, 0x44, 0xef, 0x2c, 0x1b, 0xc0, 0xb4, - 0x9e, 0x3b, 0x13, 0x78, 0x57, 0xfd, 0x96, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xba, 0x5e, 0x9e, 0xf0, 0xf6, 0xdb, 0x1d, - 0x12, 0x4d, 0xc5, 0xf2, 0x9e, 0x4e, 0x93, 0x20, 0xef, 0x0c, 0x8f, 0x0f, 0xaf, 0x1b, 0xa9, 0xbd, 0x13, 0xd4, 0xa3, - 0x62, 0x4a, 0x7c, 0xef, 0x0b, 0x6f, 0x24, 0x2f, 0x8a, 0x60, 0x59, 0x9c, 0x91, 0x52, 0x65, 0xef, 0xc8, 0xfa, 0x53, - 0x11, 0x8c, 0x40, 0xc0, 0xe9, 0xdd, 0xc0, 0xfc, 0xc8, 0x74, 0x58, 0x1c, 0x2e, 0xa4, 0xe8, 0xa3, 0x3a, 0x5f, 0x77, - 0x95, 0x6d, 0x7d, 0xe1, 0xe8, 0x3e, 0x0b, 0x5f, 0xdd, 0x97, 0xa5, 0xc1, 0xe3, 0x65, 0x69, 0x80, 0x54, 0x23, 0xf3, - 0xb2, 0xd9, 0x25, 0x03, 0x5d, 0x20, 0x46, 0xf0, 0x3b, 0x78, 0x16, 0xbe, 0x06, 0xfe, 0xff, 0x4a, 0xbd, 0xf9, 0xc3, - 0xc5, 0xe6, 0x2b, 0x2a, 0xcd, 0x57, 0x56, 0x19, 0xe3, 0x9d, 0x72, 0x1e, 0x66, 0x50, 0x4e, 0x18, 0x16, 0x6c, 0xe5, - 0xff, 0x2f, 0xa0, 0xfd, 0x77, 0x1c, 0xc3, 0x17, 0xfe, 0x14, 0xcf, 0x90, 0x1e, 0x0c, 0x44, 0x38, 0x9c, 0xa2, 0xc9, - 0xab, 0x11, 0x1e, 0xf9, 0x48, 0xb5, 0x30, 0x63, 0x34, 0x81, 0x7e, 0x0f, 0xf9, 0x63, 0x1c, 0x4e, 0x60, 0x03, 0x05, - 0x3e, 0x8e, 0xde, 0x04, 0x21, 0x1e, 0x47, 0x40, 0x15, 0x78, 0x38, 0x0c, 0x90, 0xa1, 0x1d, 0xe3, 0x00, 0xc4, 0x29, - 0x92, 0xb0, 0x06, 0xa0, 0xb3, 0x10, 0x7b, 0x13, 0x10, 0x37, 0xc6, 0xde, 0x0c, 0x4f, 0xc7, 0x68, 0x8a, 0x27, 0x00, - 0x1d, 0x1e, 0x45, 0x95, 0x13, 0x61, 0x1f, 0xb6, 0xc3, 0x31, 0x99, 0xe2, 0x51, 0x88, 0xf4, 0x60, 0xe0, 0x98, 0x80, - 0x08, 0x07, 0x7b, 0xfe, 0x9b, 0x10, 0x07, 0x13, 0xd0, 0x3b, 0x1a, 0xbd, 0x00, 0xb1, 0xb3, 0x11, 0x32, 0xa3, 0x81, - 0x17, 0x14, 0x44, 0x8f, 0x81, 0x16, 0xfc, 0x75, 0x41, 0x03, 0x48, 0x7c, 0x14, 0xe2, 0x19, 0xc4, 0xae, 0xaf, 0xf8, - 0xcd, 0x68, 0x70, 0xf3, 0x7d, 0xe4, 0xfd, 0x61, 0xcc, 0xc2, 0xbf, 0x2e, 0x66, 0xbe, 0x42, 0x00, 0xa6, 0xa0, 0x1b, - 0xe4, 0x20, 0x3d, 0x18, 0xdd, 0xc0, 0x3c, 0x7d, 0x35, 0x43, 0x53, 0xe0, 0x1a, 0x4f, 0xd1, 0x0c, 0x45, 0x0a, 0x5d, - 0x60, 0x1f, 0x19, 0x26, 0x07, 0x98, 0xbe, 0x12, 0xc6, 0xd1, 0x9f, 0x18, 0xc6, 0xc7, 0x7c, 0xfa, 0x13, 0xbb, 0xf4, - 0xff, 0x48, 0x41, 0xd0, 0x8e, 0xe9, 0x36, 0x2c, 0x76, 0xcd, 0x95, 0x5e, 0x75, 0x51, 0x70, 0x43, 0x87, 0x6e, 0x04, - 0x2e, 0xf9, 0x3e, 0x62, 0x79, 0x52, 0xfa, 0xe9, 0x67, 0xdd, 0x39, 0x50, 0xfa, 0x69, 0xac, 0xcb, 0x79, 0x7a, 0x53, - 0x52, 0xf4, 0xfa, 0xfa, 0x1d, 0xdc, 0xca, 0xaa, 0x0a, 0xf1, 0x66, 0x0b, 0x97, 0xbf, 0x3d, 0x92, 0x8d, 0xba, 0xce, - 0x73, 0xe8, 0x15, 0xd5, 0x14, 0xee, 0x0d, 0xa8, 0x6f, 0x16, 0x30, 0xc6, 0xf1, 0xb2, 0x4b, 0xdf, 0x55, 0x94, 0x08, - 0x8a, 0x56, 0x6c, 0x43, 0x11, 0x93, 0xd0, 0x07, 0xd4, 0x14, 0x49, 0xa6, 0x86, 0x33, 0xa3, 0xa6, 0x83, 0x9e, 0x56, - 0x2b, 0x31, 0xdd, 0x30, 0x58, 0x02, 0x62, 0xd2, 0xbe, 0xed, 0x8d, 0xcb, 0xd0, 0x58, 0x75, 0x4d, 0xa5, 0x84, 0x8e, - 0x41, 0x59, 0x15, 0xa6, 0xb1, 0xba, 0x76, 0x22, 0xa2, 0x2f, 0x06, 0x89, 0xbb, 0x65, 0x05, 0x53, 0x97, 0xf9, 0x34, - 0xd6, 0xad, 0xa2, 0x92, 0xa0, 0xba, 0x15, 0xf3, 0xe5, 0x41, 0xcf, 0x2a, 0xca, 0x57, 0x70, 0x9b, 0x84, 0x77, 0x01, - 0xcd, 0x43, 0x46, 0xcb, 0xa6, 0x82, 0xe6, 0x24, 0xb9, 0xbe, 0xfe, 0xe9, 0xef, 0xea, 0x33, 0x85, 0x32, 0xe1, 0xcc, - 0x09, 0x7d, 0xbe, 0x61, 0x54, 0x93, 0x9e, 0x6f, 0x3c, 0x32, 0x1f, 0x1c, 0x5a, 0xe8, 0xd3, 0xc1, 0xbf, 0xfc, 0x33, - 0x29, 0xef, 0x4e, 0x9b, 0xbd, 0x24, 0xfd, 0x5f, 0x37, 0x9d, 0x86, 0x49, 0xac, 0x97, 0x35, 0x93, 0xe9, 0x35, 0x18, - 0x18, 0xbb, 0xe6, 0x01, 0x38, 0xa7, 0x1c, 0x30, 0xb4, 0x65, 0xcf, 0x03, 0x60, 0xff, 0x72, 0xf3, 0x02, 0xfd, 0xda, - 0xc2, 0x09, 0xa6, 0x06, 0x7b, 0xed, 0x65, 0x4d, 0x65, 0xd9, 0xe4, 0xc9, 0xbb, 0x5f, 0xae, 0x6f, 0xce, 0x1e, 0xaf, - 0x35, 0x11, 0xa2, 0x3c, 0x33, 0x1f, 0x42, 0xd6, 0x95, 0x64, 0x2d, 0xe9, 0xa4, 0x16, 0xeb, 0xa8, 0x10, 0x38, 0x79, - 0xa4, 0x9f, 0x17, 0xac, 0xa2, 0xc6, 0xa9, 0x9e, 0xd1, 0x4d, 0xd1, 0x97, 0x6c, 0x3c, 0xe9, 0x7e, 0x60, 0xa5, 0x6b, - 0x4e, 0x89, 0x6b, 0x8e, 0x8c, 0xab, 0x3f, 0x13, 0xfd, 0x0b, 0x65, 0x37, 0xa3, 0x8e, 0x36, 0x12, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x69, 0x6f, 0xdc, 0x36, 0x1a, 0xfe, 0xde, + 0x5f, 0xc1, 0x2a, 0x49, 0x47, 0xd3, 0x58, 0xd4, 0x35, 0x9a, 0x53, 0x9a, 0xc2, 0xf1, 0xa6, 0x68, 0x81, 0xa4, 0x0d, + 0x60, 0xb7, 0xfd, 0x10, 0x04, 0x30, 0x47, 0xa2, 0x46, 0x8c, 0x25, 0x4a, 0x2b, 0x72, 0xae, 0x0c, 0x66, 0x7f, 0xfb, + 0xbe, 0x24, 0x35, 0xe3, 0xb1, 0x37, 0x5e, 0x6c, 0x8a, 0x2d, 0x8a, 0xd6, 0x71, 0x68, 0x1e, 0xef, 0xf9, 0x88, 0xef, + 0x21, 0xc5, 0x5f, 0x67, 0x75, 0x2a, 0x77, 0x0d, 0x45, 0x85, 0xac, 0xca, 0x79, 0xac, 0x46, 0x54, 0x12, 0xbe, 0x4c, + 0x28, 0x87, 0x15, 0x25, 0xd9, 0x3c, 0xae, 0xa8, 0x24, 0x28, 0x2d, 0x48, 0x2b, 0xa8, 0x4c, 0x7e, 0xb9, 0xf9, 0xde, + 0x19, 0x23, 0x77, 0x1e, 0x97, 0x8c, 0xdf, 0xa1, 0x96, 0x96, 0x09, 0x4b, 0x6b, 0x8e, 0x8a, 0x96, 0xe6, 0x49, 0x46, + 0x24, 0x99, 0xb2, 0x8a, 0x2c, 0xa9, 0x22, 0xd0, 0x6c, 0x9c, 0x54, 0x34, 0x59, 0x33, 0xba, 0x69, 0xea, 0x56, 0x22, + 0xa0, 0x94, 0x94, 0xcb, 0xc4, 0xda, 0xb0, 0x4c, 0x16, 0x49, 0x46, 0xd7, 0x2c, 0xa5, 0x8e, 0x5e, 0x5c, 0x30, 0xce, + 0x24, 0x23, 0xa5, 0x23, 0x52, 0x52, 0xd2, 0xc4, 0xbf, 0x58, 0x09, 0xda, 0xea, 0x05, 0x59, 0xc0, 0x9a, 0xd7, 0x16, + 0x88, 0x14, 0x69, 0xcb, 0x1a, 0x89, 0x94, 0xbd, 0x49, 0x55, 0x67, 0xab, 0x92, 0xce, 0x5d, 0x97, 0x08, 0xb0, 0x4b, + 0xb8, 0x8c, 0x67, 0x74, 0x8b, 0x87, 0x61, 0x98, 0x06, 0x64, 0x94, 0xe3, 0x8f, 0xe2, 0x2b, 0xf0, 0x6c, 0x55, 0x81, + 0x3a, 0x5c, 0xd6, 0x29, 0x91, 0xac, 0xe6, 0x58, 0x50, 0xd2, 0xa6, 0x45, 0x92, 0x24, 0xd6, 0x77, 0x82, 0xac, 0xa9, + 0xf5, 0xcd, 0x37, 0xf6, 0x89, 0x68, 0x49, 0xe5, 0xeb, 0x92, 0xaa, 0xa9, 0x78, 0xb5, 0xbb, 0x21, 0xcb, 0x9f, 0xc0, + 0x72, 0xdb, 0x22, 0x82, 0x65, 0xd4, 0xea, 0xbf, 0xf7, 0x3e, 0x60, 0x21, 0x77, 0x25, 0xc5, 0x19, 0x13, 0x4d, 0x49, + 0x76, 0x89, 0xb5, 0x00, 0xa9, 0x77, 0x56, 0x7f, 0x96, 0xaf, 0x78, 0xaa, 0x84, 0x23, 0x61, 0xd3, 0xfe, 0xbe, 0xa4, + 0x60, 0x5e, 0xf2, 0x96, 0xc8, 0x02, 0x57, 0x64, 0x6b, 0x9b, 0x09, 0xe3, 0x76, 0xf0, 0xad, 0x4d, 0x5f, 0xfa, 0x9e, + 0xd7, 0xbf, 0xd0, 0x83, 0xd7, 0x77, 0xe1, 0xef, 0xac, 0xa5, 0x72, 0xd5, 0x72, 0x44, 0xec, 0xdb, 0xb8, 0x01, 0x4a, + 0x94, 0x25, 0x56, 0xe5, 0x07, 0xd8, 0xf3, 0xc6, 0xc8, 0x9f, 0xe0, 0x20, 0x72, 0x7c, 0x1f, 0x87, 0x8e, 0x1f, 0xa5, + 0x23, 0x27, 0x42, 0xfe, 0x00, 0x86, 0x20, 0xc0, 0x11, 0xf2, 0x3e, 0x59, 0x28, 0x67, 0x65, 0x99, 0x58, 0xbc, 0xe6, + 0xd4, 0x42, 0x42, 0xb6, 0xf5, 0x1d, 0x4d, 0xac, 0x74, 0xd5, 0xb6, 0x60, 0xff, 0x55, 0x5d, 0xd6, 0x2d, 0xc0, 0xf5, + 0x15, 0x7a, 0xf0, 0xf3, 0xc5, 0x2a, 0x64, 0x4b, 0xb8, 0xc8, 0xeb, 0xb6, 0x4a, 0x2c, 0xfd, 0x50, 0xec, 0xe7, 0x7b, + 0x79, 0x40, 0x6a, 0xe8, 0x9f, 0x1d, 0x3a, 0x75, 0xcb, 0x96, 0x8c, 0x27, 0x96, 0x1f, 0x20, 0x7f, 0x0c, 0x6a, 0x6f, + 0xfb, 0x87, 0x13, 0x26, 0x44, 0x61, 0xd2, 0x79, 0x59, 0xdb, 0xef, 0x6f, 0x63, 0xb1, 0x5e, 0xa2, 0x6d, 0x55, 0x72, + 0x91, 0x58, 0x85, 0x94, 0xcd, 0xd4, 0x75, 0x37, 0x9b, 0x0d, 0xde, 0x84, 0xb8, 0x6e, 0x97, 0x6e, 0xe0, 0x79, 0x9e, + 0x0b, 0x14, 0x16, 0x32, 0xf7, 0xc3, 0x0a, 0x06, 0x16, 0x2a, 0x28, 0x5b, 0x16, 0x52, 0xcf, 0xe7, 0xcf, 0xf7, 0xf4, + 0x10, 0x2b, 0x8a, 0xf9, 0xed, 0x87, 0x33, 0x2d, 0xec, 0x4c, 0x0b, 0xfd, 0xee, 0x0c, 0xcd, 0xde, 0x5b, 0x65, 0xd4, + 0x88, 0x04, 0x28, 0x40, 0x9e, 0xfe, 0x17, 0x38, 0x6a, 0xde, 0xad, 0x9c, 0x47, 0x2b, 0x74, 0xb6, 0x82, 0xbf, 0x80, + 0x5f, 0x50, 0x0d, 0x9d, 0xc9, 0x89, 0xdd, 0x57, 0xc7, 0x6b, 0xdf, 0xbb, 0xdf, 0x50, 0x3c, 0x3f, 0x0c, 0xcf, 0xd7, + 0x4e, 0xf0, 0xab, 0x22, 0x50, 0xd8, 0x9f, 0x98, 0x9c, 0xa0, 0xf0, 0x7f, 0x1d, 0x92, 0x08, 0x45, 0xdd, 0x4e, 0xe4, + 0xa8, 0xf9, 0x69, 0xa5, 0x34, 0xa1, 0x68, 0x0d, 0x54, 0x95, 0x33, 0x74, 0x22, 0x12, 0xa2, 0xb0, 0x33, 0x09, 0x66, + 0xb0, 0x3d, 0x04, 0xe6, 0xb3, 0x3d, 0x27, 0xfc, 0xd4, 0x53, 0x30, 0x4f, 0x2d, 0xeb, 0x1e, 0x83, 0xfa, 0x1c, 0x03, + 0xfc, 0xb1, 0x86, 0x3b, 0x67, 0x59, 0x80, 0x11, 0x95, 0x69, 0x61, 0x5b, 0x2e, 0x44, 0x5e, 0xce, 0x96, 0x10, 0x15, + 0x35, 0xb7, 0xfa, 0x58, 0x16, 0x94, 0xdb, 0x47, 0x56, 0xc5, 0x48, 0xf5, 0x89, 0xfd, 0xf8, 0x44, 0xf6, 0xf7, 0xa7, + 0xf8, 0x90, 0x4c, 0x42, 0x1c, 0x4a, 0xac, 0x22, 0xfa, 0xe2, 0xb4, 0xbb, 0xa8, 0xb3, 0xdd, 0x13, 0xa1, 0x53, 0xf8, + 0x26, 0x6e, 0x18, 0xe7, 0xb4, 0xbd, 0xa1, 0x5b, 0x78, 0x86, 0x6f, 0x2f, 0xaf, 0xd0, 0x65, 0x96, 0xb5, 0x54, 0x88, + 0x29, 0xb2, 0x5e, 0x4a, 0x88, 0x91, 0xf4, 0x7f, 0x97, 0xe5, 0x3f, 0x90, 0xf5, 0x1b, 0xfb, 0x9e, 0xa1, 0x9f, 0xa8, + 0xdc, 0xd4, 0xed, 0x5d, 0x27, 0x4d, 0x99, 0x36, 0x53, 0x11, 0xd8, 0x82, 0x9d, 0xa4, 0x11, 0x58, 0x94, 0x90, 0x5f, + 0x6c, 0xbf, 0x0f, 0x7a, 0x9a, 0x7b, 0xaf, 0xf8, 0x11, 0xa8, 0xdb, 0x38, 0x63, 0x6b, 0x94, 0x96, 0x90, 0x41, 0x20, + 0x94, 0x8c, 0x28, 0x0b, 0x75, 0x61, 0x53, 0xf3, 0x14, 0xb8, 0xef, 0x12, 0xeb, 0x33, 0x19, 0xe2, 0xd5, 0xee, 0xc7, + 0xcc, 0xee, 0x09, 0xc8, 0x0d, 0xbd, 0x3e, 0x5e, 0x93, 0x72, 0x45, 0x51, 0x82, 0x64, 0xc1, 0xc4, 0xbd, 0x81, 0xb3, + 0x27, 0xd9, 0x1a, 0x71, 0x07, 0x5c, 0x39, 0x1c, 0x0b, 0xbb, 0x6f, 0x1d, 0xa3, 0x34, 0x26, 0x26, 0x87, 0x5a, 0xcf, + 0xac, 0x47, 0x16, 0x39, 0x25, 0xcd, 0xa5, 0x75, 0x1f, 0xcd, 0xcf, 0xf7, 0xc2, 0xe6, 0xb8, 0x05, 0xed, 0xfd, 0xc3, + 0x69, 0x33, 0x16, 0x0d, 0xe1, 0x8f, 0x19, 0x95, 0x81, 0x2a, 0x68, 0x20, 0xf1, 0xc1, 0x4c, 0x45, 0x0e, 0x10, 0x9d, + 0x14, 0xba, 0xe4, 0x38, 0x7d, 0xbe, 0x67, 0x20, 0x51, 0xe5, 0xb3, 0x93, 0xc4, 0xd8, 0x05, 0x68, 0xe6, 0xb7, 0x87, + 0xfe, 0xbd, 0x1f, 0xff, 0x5c, 0xd1, 0x76, 0x77, 0x4d, 0x4b, 0x9a, 0xca, 0xba, 0xb5, 0xad, 0x67, 0xa0, 0x05, 0xae, + 0x92, 0x76, 0xf8, 0x87, 0x9b, 0xb7, 0x6f, 0x92, 0xda, 0x6e, 0xfb, 0x17, 0x4f, 0x51, 0xab, 0x6a, 0xf1, 0x1e, 0xaa, + 0xc5, 0xbf, 0x92, 0x9e, 0xaa, 0x17, 0xbd, 0x0f, 0xc0, 0xaa, 0xfd, 0xbd, 0xbd, 0x2f, 0x1a, 0x2a, 0xb0, 0x5f, 0x42, + 0x72, 0xb8, 0x50, 0x1e, 0x3a, 0xc3, 0xa8, 0x7f, 0x00, 0xfd, 0x60, 0x01, 0xd8, 0xad, 0xf3, 0x3e, 0xe4, 0x7f, 0x95, + 0x82, 0xe7, 0xdf, 0xee, 0x17, 0xf5, 0xd6, 0x11, 0xec, 0x13, 0xe3, 0xcb, 0x29, 0xe3, 0x05, 0x6d, 0x99, 0x3c, 0x80, + 0xb9, 0x50, 0x42, 0x9a, 0x95, 0xdc, 0x37, 0x24, 0xcb, 0xd4, 0x49, 0xd4, 0x6c, 0x67, 0x39, 0x14, 0x1c, 0x45, 0x49, + 0xa7, 0x3e, 0xad, 0x0e, 0xe6, 0x5c, 0xe7, 0x96, 0xe9, 0x24, 0x7a, 0x71, 0x50, 0x17, 0x6e, 0x2f, 0xe1, 0x61, 0x39, + 0xa4, 0x64, 0x4b, 0x3e, 0x4d, 0xc1, 0x70, 0xda, 0x1a, 0xa6, 0x9c, 0x54, 0xac, 0xdc, 0x4d, 0x05, 0x64, 0x39, 0x07, + 0x2a, 0x11, 0xcb, 0x0f, 0x8b, 0x95, 0x94, 0x35, 0x07, 0xdd, 0x6d, 0x46, 0xdb, 0xa9, 0x37, 0x33, 0x13, 0xa7, 0x25, + 0x19, 0x5b, 0x89, 0x29, 0x0e, 0x5b, 0x5a, 0xcd, 0x16, 0x24, 0xbd, 0x5b, 0xb6, 0xf5, 0x8a, 0x67, 0x4e, 0xaa, 0xb2, + 0xf0, 0xf4, 0x99, 0x9f, 0x93, 0x90, 0xa6, 0xb3, 0x6e, 0x95, 0xe7, 0xf9, 0x0c, 0xa0, 0xa0, 0x8e, 0xc9, 0x6a, 0xd3, + 0x00, 0x0f, 0x14, 0xdb, 0x99, 0x99, 0x38, 0x50, 0x1b, 0xc6, 0x46, 0x28, 0x11, 0x2f, 0x66, 0x47, 0x77, 0xbc, 0x19, + 0xa4, 0x77, 0x01, 0x42, 0x1a, 0x88, 0x6d, 0x30, 0xf3, 0x50, 0x11, 0xc6, 0xcf, 0xad, 0x57, 0xd7, 0x64, 0xd6, 0x95, + 0x27, 0x80, 0x45, 0xab, 0xd1, 0x45, 0x6a, 0x06, 0x05, 0xc8, 0x14, 0xd9, 0x69, 0x30, 0xf4, 0x9a, 0xed, 0x01, 0x77, + 0x17, 0x64, 0x7f, 0xa4, 0xce, 0x4b, 0xba, 0x9d, 0x7d, 0x5c, 0x09, 0xc9, 0xf2, 0x9d, 0xd3, 0x15, 0xe9, 0x29, 0x5c, + 0x16, 0x28, 0xce, 0x0b, 0x20, 0xa5, 0x94, 0xcf, 0xb4, 0x0e, 0x87, 0x49, 0x5a, 0x89, 0x0e, 0xa7, 0x93, 0x18, 0x7d, + 0x41, 0x1f, 0xca, 0xfa, 0x6f, 0xd4, 0xea, 0x2e, 0xee, 0x2b, 0xd2, 0x42, 0xd1, 0x70, 0x16, 0x35, 0x60, 0x5a, 0x4d, + 0x9d, 0x11, 0x3c, 0xab, 0x6e, 0x4b, 0x09, 0x03, 0xcf, 0xc1, 0x4c, 0x5d, 0x7b, 0x8f, 0x78, 0xfb, 0xcd, 0x16, 0x89, + 0xba, 0x64, 0x59, 0x47, 0xa7, 0x49, 0x90, 0x77, 0x82, 0xc7, 0x87, 0xc7, 0x8d, 0xd4, 0xde, 0x11, 0xea, 0x41, 0x3e, + 0x26, 0xbe, 0xf7, 0x99, 0x27, 0x92, 0xe5, 0x79, 0xb0, 0xc8, 0x4f, 0x48, 0xa9, 0x12, 0x7a, 0x60, 0xdd, 0xad, 0x08, + 0x06, 0x20, 0xe0, 0xf8, 0x6c, 0x60, 0x7e, 0x60, 0x3a, 0x2c, 0xf6, 0x67, 0x52, 0xf4, 0x55, 0x9d, 0xae, 0xda, 0xd2, + 0xb6, 0x3e, 0x73, 0x75, 0x5f, 0x84, 0x57, 0xf7, 0x25, 0xae, 0xf7, 0x74, 0x89, 0xeb, 0x21, 0xd5, 0x14, 0xbd, 0xaa, + 0xb7, 0x49, 0x4f, 0x17, 0x9b, 0x01, 0xfc, 0xf6, 0x5e, 0x84, 0xaf, 0x81, 0xff, 0xff, 0x52, 0xbb, 0x7e, 0x77, 0xe1, + 0xfa, 0x82, 0xaa, 0xf5, 0x85, 0x15, 0xcb, 0x78, 0xa7, 0x9c, 0x87, 0x19, 0x94, 0x26, 0x86, 0x05, 0x5b, 0xfa, 0x7f, + 0x04, 0xb4, 0xff, 0x89, 0x63, 0x78, 0xe9, 0x8f, 0xf1, 0x04, 0xe9, 0xc1, 0x40, 0x84, 0xc3, 0x31, 0x1a, 0x5d, 0x0d, + 0xf0, 0xc0, 0x47, 0xaa, 0x1d, 0x1a, 0xa2, 0x11, 0x1e, 0x03, 0xc1, 0x10, 0x87, 0x23, 0xd8, 0x40, 0x81, 0x8f, 0xa3, + 0x37, 0x41, 0x88, 0x87, 0x11, 0x50, 0x05, 0x1e, 0x0e, 0x03, 0x64, 0x68, 0x87, 0x38, 0x00, 0x71, 0x8a, 0x24, 0xac, + 0x00, 0xe8, 0x34, 0xc4, 0xde, 0x08, 0xc4, 0x0d, 0xb1, 0x37, 0xc1, 0xe3, 0x21, 0x1a, 0xe3, 0x11, 0x40, 0x87, 0x07, + 0x51, 0xe9, 0x44, 0xd8, 0x87, 0xed, 0x70, 0x48, 0xc6, 0x78, 0x10, 0x22, 0x3d, 0x18, 0x38, 0x46, 0x20, 0xc2, 0xc1, + 0x9e, 0xff, 0x26, 0xc4, 0xc1, 0x08, 0xf4, 0x0e, 0x06, 0x97, 0x20, 0x76, 0x32, 0x40, 0x66, 0x34, 0xf0, 0x82, 0x82, + 0xe8, 0x29, 0xd0, 0x82, 0xbf, 0x2f, 0x68, 0x00, 0x89, 0x8f, 0x42, 0x3c, 0x81, 0xd8, 0xf5, 0x15, 0xbf, 0x19, 0x0d, + 0x6e, 0xbe, 0x8f, 0xbc, 0xdf, 0x8d, 0x59, 0xf8, 0xf7, 0xc5, 0xcc, 0x57, 0x08, 0xc0, 0x14, 0x74, 0x83, 0x1c, 0xa4, + 0x07, 0xa3, 0x1b, 0x98, 0xc7, 0x57, 0x13, 0x34, 0x06, 0xae, 0xe1, 0x18, 0x4d, 0x50, 0xa4, 0xd0, 0x05, 0xf6, 0x81, + 0x61, 0x72, 0x80, 0xe9, 0x0b, 0x61, 0x1c, 0xfc, 0x85, 0x61, 0x7c, 0xca, 0xa7, 0xbf, 0xb0, 0x4b, 0x7f, 0x46, 0x0a, + 0x82, 0x76, 0x4c, 0xb7, 0x61, 0xb1, 0x6b, 0x3e, 0x0f, 0xa8, 0x2e, 0x0a, 0xde, 0xf6, 0xa1, 0x1b, 0x99, 0xc7, 0x85, + 0x8f, 0x58, 0x96, 0x40, 0x57, 0x3f, 0x3f, 0x6b, 0xf5, 0x81, 0xd0, 0x3f, 0x1e, 0xc1, 0xec, 0x41, 0xe3, 0x6e, 0xce, + 0x74, 0xa5, 0x9f, 0xdf, 0x14, 0x14, 0xbd, 0xbe, 0x7e, 0x07, 0x2f, 0x7f, 0x65, 0x89, 0x78, 0xbd, 0x81, 0x77, 0xcc, + 0x1d, 0x92, 0xb5, 0xfa, 0x6a, 0xc0, 0xa1, 0x8d, 0x54, 0x53, 0x78, 0x3d, 0x41, 0x5d, 0x1f, 0x81, 0x31, 0x8e, 0x17, + 0xed, 0xfc, 0x5d, 0x49, 0x89, 0xa0, 0x68, 0xc9, 0xd6, 0x14, 0x31, 0x09, 0x2d, 0x42, 0x45, 0x91, 0x64, 0x6a, 0x38, + 0x31, 0x6a, 0x3a, 0x68, 0x77, 0xb5, 0x12, 0xd3, 0x28, 0x83, 0x25, 0x20, 0x66, 0xde, 0x75, 0xc4, 0x71, 0x11, 0x1a, + 0xab, 0xae, 0xa9, 0x94, 0xd0, 0x4c, 0x28, 0xab, 0xc2, 0x79, 0xac, 0xde, 0x6e, 0x11, 0xd1, 0xef, 0x0c, 0x89, 0xbb, + 0x61, 0x39, 0x53, 0xdf, 0x0c, 0xe6, 0xb1, 0xee, 0x22, 0x95, 0x04, 0xd5, 0xc8, 0x98, 0x0f, 0x1c, 0x7a, 0x56, 0x52, + 0xbe, 0x84, 0x97, 0x56, 0x78, 0x4c, 0xd0, 0x57, 0xa4, 0xb4, 0xa8, 0x4b, 0xe8, 0x5b, 0x92, 0xeb, 0xeb, 0x1f, 0xff, + 0xa1, 0xbe, 0x86, 0x28, 0x13, 0x4e, 0x9c, 0xf0, 0x0a, 0x60, 0x18, 0xd5, 0xa4, 0xe3, 0x1b, 0x0e, 0xcc, 0x77, 0x8d, + 0x06, 0x5a, 0x78, 0xf0, 0x2f, 0x7b, 0x20, 0xe5, 0xdd, 0x71, 0xb3, 0x93, 0xa4, 0xff, 0xeb, 0x7e, 0xd4, 0x30, 0x89, + 0xd5, 0xa2, 0x62, 0x72, 0x7e, 0x0d, 0x06, 0xc6, 0xae, 0x39, 0x00, 0xe7, 0x94, 0x03, 0x86, 0xb6, 0xe8, 0x78, 0x00, + 0xec, 0x9f, 0x6f, 0x2e, 0xd1, 0x2f, 0x0d, 0x5c, 0x6e, 0x6a, 0xb0, 0xd7, 0x5e, 0x56, 0x54, 0x16, 0x75, 0x96, 0xbc, + 0xfb, 0xf9, 0xfa, 0xe6, 0xe4, 0xf1, 0x4a, 0x13, 0x21, 0xca, 0x53, 0xf3, 0xbd, 0x65, 0x55, 0x4a, 0xd6, 0x90, 0x56, + 0x6a, 0xb1, 0x8e, 0x8a, 0x8e, 0xa3, 0x47, 0xfa, 0x3c, 0x67, 0x25, 0x35, 0x4e, 0x75, 0x8c, 0xee, 0x1c, 0x7d, 0xce, + 0xc6, 0xa3, 0xee, 0x47, 0x56, 0xba, 0xe6, 0x02, 0xb9, 0xe6, 0x36, 0xb9, 0xfa, 0x6b, 0xd4, 0xbf, 0x01, 0x14, 0xee, + 0xbc, 0x64, 0x9d, 0x12, 0x00, 0x00}; } // namespace captive_portal } // namespace esphome diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 78eee4b226..630e00f0b7 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -12,7 +12,7 @@ static const char *const TAG = "captive_portal"; void CaptivePortal::handle_config(AsyncWebServerRequest *request) { AsyncResponseStream *stream = request->beginResponseStream("application/json"); stream->addHeader("cache-control", "public, max-age=0, must-revalidate"); - stream->printf(R"({"name":"%s","aps":[{})", App.get_name().c_str()); + stream->printf(R"({"mac":"%s","name":"%s","aps":[{})", get_mac_address_pretty().c_str(), App.get_name().c_str()); for (auto &scan : wifi::global_wifi_component->get_scan_result()) { if (scan.get_is_hidden()) From 5441213b270d933f8f35830ee425010612adc935 Mon Sep 17 00:00:00 2001 From: tracestep <16390082+tracestep@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:11:46 -0300 Subject: [PATCH 1506/2607] Adds i2c timeout config (#4614) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/i2c/__init__.py | 45 ++++++++++++++++++++-- esphome/components/i2c/i2c_bus_arduino.cpp | 21 ++++++++++ esphome/components/i2c/i2c_bus_arduino.h | 2 + esphome/components/i2c/i2c_bus_esp_idf.cpp | 29 +++++++++++--- esphome/components/i2c/i2c_bus_esp_idf.h | 2 + 5 files changed, 90 insertions(+), 9 deletions(-) diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index 0a1f049b93..f52a0edb9f 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -4,6 +4,7 @@ import esphome.final_validate as fv from esphome import pins from esphome.const import ( CONF_FREQUENCY, + CONF_TIMEOUT, CONF_ID, CONF_INPUT, CONF_OUTPUT, @@ -59,6 +60,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_FREQUENCY, default="50kHz"): cv.All( cv.frequency, cv.Range(min=0, min_included=False) ), + cv.Optional(CONF_TIMEOUT): cv.positive_time_period, cv.Optional(CONF_SCAN, default=True): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), @@ -81,6 +83,8 @@ async def to_code(config): cg.add(var.set_frequency(int(config[CONF_FREQUENCY]))) cg.add(var.set_scan(config[CONF_SCAN])) + if CONF_TIMEOUT in config: + cg.add(var.set_timeout(int(config[CONF_TIMEOUT].total_microseconds))) if CORE.using_arduino: cg.add_library("Wire", None) @@ -119,23 +123,56 @@ async def register_i2c_device(var, config): def final_validate_device_schema( - name: str, *, min_frequency: cv.frequency = None, max_frequency: cv.frequency = None + name: str, + *, + min_frequency: cv.frequency = None, + max_frequency: cv.frequency = None, + min_timeout: cv.time_period = None, + max_timeout: cv.time_period = None, ): hub_schema = {} - if min_frequency is not None: + if (min_frequency is not None) and (max_frequency is not None): + hub_schema[cv.Required(CONF_FREQUENCY)] = cv.Range( + min=cv.frequency(min_frequency), + min_included=True, + max=cv.frequency(max_frequency), + max_included=True, + msg=f"Component {name} requires a frequency between {min_frequency} and {max_frequency} for the I2C bus", + ) + elif min_frequency is not None: hub_schema[cv.Required(CONF_FREQUENCY)] = cv.Range( min=cv.frequency(min_frequency), min_included=True, msg=f"Component {name} requires a minimum frequency of {min_frequency} for the I2C bus", ) - - if max_frequency is not None: + elif max_frequency is not None: hub_schema[cv.Required(CONF_FREQUENCY)] = cv.Range( max=cv.frequency(max_frequency), max_included=True, msg=f"Component {name} cannot be used with a frequency of over {max_frequency} for the I2C bus", ) + if (min_timeout is not None) and (max_timeout is not None): + hub_schema[cv.Required(CONF_TIMEOUT)] = cv.Range( + min=cv.time_period(min_timeout), + min_included=True, + max=cv.time_period(max_timeout), + max_included=True, + msg=f"Component {name} requires a timeout between {min_timeout} and {max_timeout} for the I2C bus", + ) + elif min_timeout is not None: + hub_schema[cv.Required(CONF_TIMEOUT)] = cv.Range( + min=cv.time_period(min_timeout), + min_included=True, + msg=f"Component {name} requires a minimum timeout of {min_timeout} for the I2C bus", + ) + elif max_timeout is not None: + hub_schema[cv.Required(CONF_TIMEOUT)] = cv.Range( + max=cv.time_period(max_timeout), + max_included=True, + msg=f"Component {name} cannot be used with a timeout of over {max_timeout} for the I2C bus", + ) + return cv.Schema( {cv.Required(CONF_I2C_ID): fv.id_declaration_match_schema(hub_schema)}, extra=cv.ALLOW_EXTRA, diff --git a/esphome/components/i2c/i2c_bus_arduino.cpp b/esphome/components/i2c/i2c_bus_arduino.cpp index 0966bd4d97..cd1b2aacc7 100644 --- a/esphome/components/i2c/i2c_bus_arduino.cpp +++ b/esphome/components/i2c/i2c_bus_arduino.cpp @@ -52,6 +52,18 @@ void ArduinoI2CBus::set_pins_and_clock_() { #else wire_->begin(static_cast(sda_pin_), static_cast(scl_pin_)); #endif + if (timeout_ > 0) { // if timeout specified in yaml +#if defined(USE_ESP32) + // https://github.com/espressif/arduino-esp32/blob/master/libraries/Wire/src/Wire.cpp + wire_->setTimeOut(timeout_ / 1000); // unit: ms +#elif defined(USE_ESP8266) + // https://github.com/esp8266/Arduino/blob/master/libraries/Wire/Wire.h + wire_->setClockStretchLimit(timeout_); // unit: us +#elif defined(USE_RP2040) + // https://github.com/earlephilhower/ArduinoCore-API/blob/e37df85425e0ac020bfad226d927f9b00d2e0fb7/api/Stream.h + wire_->setTimeout(timeout_ / 1000); // unit: ms +#endif + } wire_->setClock(frequency_); } @@ -60,6 +72,15 @@ void ArduinoI2CBus::dump_config() { ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); ESP_LOGCONFIG(TAG, " Frequency: %u Hz", this->frequency_); + if (timeout_ > 0) { +#if defined(USE_ESP32) + ESP_LOGCONFIG(TAG, " Timeout: %u ms", this->timeout_ / 1000); +#elif defined(USE_ESP8266) + ESP_LOGCONFIG(TAG, " Timeout: %u us", this->timeout_); +#elif defined(USE_RP2040) + ESP_LOGCONFIG(TAG, " Timeout: %u ms", this->timeout_ / 1000); +#endif + } switch (this->recovery_result_) { case RECOVERY_COMPLETED: ESP_LOGCONFIG(TAG, " Recovery: bus successfully recovered"); diff --git a/esphome/components/i2c/i2c_bus_arduino.h b/esphome/components/i2c/i2c_bus_arduino.h index 6304c2b039..6a670a2a05 100644 --- a/esphome/components/i2c/i2c_bus_arduino.h +++ b/esphome/components/i2c/i2c_bus_arduino.h @@ -27,6 +27,7 @@ class ArduinoI2CBus : public I2CBus, public Component { void set_sda_pin(uint8_t sda_pin) { sda_pin_ = sda_pin; } void set_scl_pin(uint8_t scl_pin) { scl_pin_ = scl_pin; } void set_frequency(uint32_t frequency) { frequency_ = frequency; } + void set_timeout(uint32_t timeout) { timeout_ = timeout; } private: void recover_(); @@ -38,6 +39,7 @@ class ArduinoI2CBus : public I2CBus, public Component { uint8_t sda_pin_; uint8_t scl_pin_; uint32_t frequency_; + uint32_t timeout_ = 0; bool initialized_ = false; }; diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index 5d35c1968b..cbb748cca1 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -1,12 +1,12 @@ #ifdef USE_ESP_IDF #include "i2c_bus_esp_idf.h" -#include "esphome/core/hal.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" -#include "esphome/core/application.h" -#include #include +#include +#include "esphome/core/application.h" +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace i2c { @@ -45,6 +45,20 @@ void IDFI2CBus::setup() { this->mark_failed(); return; } + if (timeout_ > 0) { // if timeout specified in yaml: + if (timeout_ > 13000) { + ESP_LOGW(TAG, "i2c timeout of %" PRIu32 "us greater than max of 13ms on esp-idf, setting to max", timeout_); + timeout_ = 13000; + } + err = i2c_set_timeout(port_, timeout_ * 80); // unit: APB 80MHz clock cycle + if (err != ESP_OK) { + ESP_LOGW(TAG, "i2c_set_timeout failed: %s", esp_err_to_name(err)); + this->mark_failed(); + return; + } else { + ESP_LOGV(TAG, "i2c_timeout set to %d ticks (%d us)", timeout_ * 80, timeout_); + } + } err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, ESP_INTR_FLAG_IRAM); if (err != ESP_OK) { ESP_LOGW(TAG, "i2c_driver_install failed: %s", esp_err_to_name(err)); @@ -62,6 +76,9 @@ void IDFI2CBus::dump_config() { ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); ESP_LOGCONFIG(TAG, " Frequency: %" PRIu32 " Hz", this->frequency_); + if (timeout_ > 0) { + ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 "us", this->timeout_); + } switch (this->recovery_result_) { case RECOVERY_COMPLETED: ESP_LOGCONFIG(TAG, " Recovery: bus successfully recovered"); @@ -127,6 +144,8 @@ ErrorCode IDFI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) { return ERROR_UNKNOWN; } err = i2c_master_cmd_begin(port_, cmd, 20 / portTICK_PERIOD_MS); + // i2c_master_cmd_begin() will block for a whole second if no ack: + // https://github.com/espressif/esp-idf/issues/4999 i2c_cmd_link_delete(cmd); if (err == ESP_FAIL) { // transfer not acked diff --git a/esphome/components/i2c/i2c_bus_esp_idf.h b/esphome/components/i2c/i2c_bus_esp_idf.h index c80ea8c99d..afb4c2d22b 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.h +++ b/esphome/components/i2c/i2c_bus_esp_idf.h @@ -29,6 +29,7 @@ class IDFI2CBus : public I2CBus, public Component { void set_scl_pin(uint8_t scl_pin) { scl_pin_ = scl_pin; } void set_scl_pullup_enabled(bool scl_pullup_enabled) { scl_pullup_enabled_ = scl_pullup_enabled; } void set_frequency(uint32_t frequency) { frequency_ = frequency; } + void set_timeout(uint32_t timeout) { timeout_ = timeout; } private: void recover_(); @@ -41,6 +42,7 @@ class IDFI2CBus : public I2CBus, public Component { uint8_t scl_pin_; bool scl_pullup_enabled_; uint32_t frequency_; + uint32_t timeout_ = 0; bool initialized_ = false; }; From 3b6e8fa66649ab5e842c2e1c02e810f3af48ca5e Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Tue, 9 Apr 2024 01:43:53 +0000 Subject: [PATCH 1507/2607] Add ABB-Welcome / Busch-Welcome Door Intercom Protocol (#4689) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/remote_base/__init__.py | 102 +++++++ .../remote_base/abbwelcome_protocol.cpp | 123 +++++++++ .../remote_base/abbwelcome_protocol.h | 251 ++++++++++++++++++ 3 files changed, 476 insertions(+) create mode 100644 esphome/components/remote_base/abbwelcome_protocol.cpp create mode 100644 esphome/components/remote_base/abbwelcome_protocol.h diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 08652bbfc9..c771f406d8 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1718,3 +1718,105 @@ async def haier_action(var, config, args): vec_ = cg.std_vector.template(cg.uint8) template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_) cg.add(var.set_code(template_)) + + +# ABBWelcome +( + ABBWelcomeData, + ABBWelcomeBinarySensor, + ABBWelcomeTrigger, + ABBWelcomeAction, + ABBWelcomeDumper, +) = declare_protocol("ABBWelcome") + +CONF_SOURCE_ADDRESS = "source_address" +CONF_DESTINATION_ADDRESS = "destination_address" +CONF_THREE_BYTE_ADDRESS = "three_byte_address" +CONF_MESSAGE_TYPE = "message_type" +CONF_MESSAGE_ID = "message_id" +CONF_RETRANSMISSION = "retransmission" + +ABB_WELCOME_SCHEMA = cv.Schema( + { + cv.Required(CONF_SOURCE_ADDRESS): cv.hex_uint32_t, + cv.Required(CONF_DESTINATION_ADDRESS): cv.hex_uint32_t, + cv.Optional(CONF_RETRANSMISSION, default=False): cv.boolean, + cv.Optional(CONF_THREE_BYTE_ADDRESS, default=False): cv.boolean, + cv.Required(CONF_MESSAGE_TYPE): cv.Any(cv.hex_uint8_t, cv.uint8_t), + cv.Optional(CONF_MESSAGE_ID): cv.Any(cv.hex_uint8_t, cv.uint8_t), + cv.Optional(CONF_DATA): cv.All( + [cv.Any(cv.hex_uint8_t, cv.uint8_t)], + cv.Length(min=0, max=7), + ), + } +) + + +@register_binary_sensor("abbwelcome", ABBWelcomeBinarySensor, ABB_WELCOME_SCHEMA) +def abbwelcome_binary_sensor(var, config): + cg.add(var.set_three_byte_address(config[CONF_THREE_BYTE_ADDRESS])) + cg.add(var.set_source_address(config[CONF_SOURCE_ADDRESS])) + cg.add(var.set_destination_address(config[CONF_DESTINATION_ADDRESS])) + cg.add(var.set_retransmission(config[CONF_RETRANSMISSION])) + cg.add(var.set_message_type(config[CONF_MESSAGE_TYPE])) + cg.add(var.set_auto_message_id(CONF_MESSAGE_ID not in config)) + if CONF_MESSAGE_ID in config: + cg.add(var.set_message_id(config[CONF_MESSAGE_ID])) + if CONF_DATA in config: + cg.add(var.set_data(config[CONF_DATA])) + cg.add(var.finalize()) + + +@register_trigger("abbwelcome", ABBWelcomeTrigger, ABBWelcomeData) +def abbwelcome_trigger(var, config): + pass + + +@register_dumper("abbwelcome", ABBWelcomeDumper) +def abbwelcome_dumper(var, config): + pass + + +@register_action("abbwelcome", ABBWelcomeAction, ABB_WELCOME_SCHEMA) +async def abbwelcome_action(var, config, args): + cg.add( + var.set_three_byte_address( + await cg.templatable(config[CONF_THREE_BYTE_ADDRESS], args, cg.bool_) + ) + ) + cg.add( + var.set_source_address( + await cg.templatable(config[CONF_SOURCE_ADDRESS], args, cg.uint16) + ) + ) + cg.add( + var.set_destination_address( + await cg.templatable(config[CONF_DESTINATION_ADDRESS], args, cg.uint16) + ) + ) + cg.add( + var.set_retransmission( + await cg.templatable(config[CONF_RETRANSMISSION], args, cg.bool_) + ) + ) + cg.add( + var.set_message_type( + await cg.templatable(config[CONF_MESSAGE_TYPE], args, cg.uint8) + ) + ) + cg.add(var.set_auto_message_id(CONF_MESSAGE_ID not in config)) + if CONF_MESSAGE_ID in config: + cg.add( + var.set_message_id( + await cg.templatable(config[CONF_MESSAGE_ID], args, cg.uint8) + ) + ) + if CONF_DATA in config: + data_ = config[CONF_DATA] + if cg.is_template(data_): + template_ = await cg.templatable( + data_, args, cg.std_vector.template(cg.uint8) + ) + cg.add(var.set_data_template(template_)) + else: + cg.add(var.set_data_static(data_)) diff --git a/esphome/components/remote_base/abbwelcome_protocol.cpp b/esphome/components/remote_base/abbwelcome_protocol.cpp new file mode 100644 index 0000000000..88f928901b --- /dev/null +++ b/esphome/components/remote_base/abbwelcome_protocol.cpp @@ -0,0 +1,123 @@ +#include "abbwelcome_protocol.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace remote_base { + +static const char *const TAG = "remote.abbwelcome"; + +static const uint32_t BIT_ONE_SPACE_US = 102; +static const uint32_t BIT_ZERO_MARK_US = 32; // 18-44 +static const uint32_t BIT_ZERO_SPACE_US = BIT_ONE_SPACE_US - BIT_ZERO_MARK_US; +static const uint16_t BYTE_SPACE_US = 210; + +uint8_t ABBWelcomeData::calc_cs_() const { + uint8_t checksum = 0; + for (uint8_t i = 0; i < this->size() - 1; i++) { + uint16_t temp = checksum ^ (this->data_[i]); + temp = temp ^ (uint16_t) (((uint32_t) temp << 0x11) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x12) >> 0x10) ^ + (uint16_t) (((uint32_t) temp << 0x13) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x14) >> 0x10) ^ + (uint16_t) (((uint32_t) temp << 0x15) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x16) >> 0x10) ^ + (uint16_t) (((uint32_t) temp << 0x17) >> 0x10); + checksum = (temp & 0xfe) ^ ((temp >> 8) & 1); + } + return ~checksum; +} + +void ABBWelcomeProtocol::encode_byte_(RemoteTransmitData *dst, uint8_t data) const { + // space = bus high, mark = activate bus pulldown + dst->mark(BIT_ZERO_MARK_US); + uint32_t next_space = BIT_ZERO_SPACE_US; + for (uint8_t mask = 1 << 7; mask; mask >>= 1) { + if (data & mask) { + next_space += BIT_ONE_SPACE_US; + } else { + dst->space(next_space); + dst->mark(BIT_ZERO_MARK_US); + next_space = BIT_ZERO_SPACE_US; + } + } + next_space += BYTE_SPACE_US; + dst->space(next_space); +} + +void ABBWelcomeProtocol::encode(RemoteTransmitData *dst, const ABBWelcomeData &src) { + dst->set_carrier_frequency(0); + uint32_t reserve_count = 0; + for (size_t i = 0; i < src.size(); i++) { + reserve_count += 2 * (9 - (src[i] & 1) - ((src[i] >> 1) & 1) - ((src[i] >> 2) & 1) - ((src[i] >> 3) & 1) - + ((src[i] >> 4) & 1) - ((src[i] >> 5) & 1) - ((src[i] >> 6) & 1) - ((src[i] >> 7) & 1)); + } + dst->reserve(reserve_count); + for (size_t i = 0; i < src.size(); i++) + this->encode_byte_(dst, src[i]); + ESP_LOGD(TAG, "Transmitting: %s", src.to_string().c_str()); +} + +bool ABBWelcomeProtocol::decode_byte_(RemoteReceiveData &src, bool &done, uint8_t &data) { + if (!src.expect_mark(BIT_ZERO_MARK_US)) + return false; + uint32_t next_space = BIT_ZERO_SPACE_US; + for (uint8_t mask = 1 << 7; mask; mask >>= 1) { + // if (!src.peek_space_at_least(next_space, 0)) + // return false; + if (src.expect_space(next_space)) { + if (!src.expect_mark(BIT_ZERO_MARK_US)) + return false; + next_space = BIT_ZERO_SPACE_US; + } else { + data |= mask; + next_space += BIT_ONE_SPACE_US; + } + } + next_space += BYTE_SPACE_US; + // if (!src.peek_space_at_least(next_space, 0)) + // return false; + done = !(src.expect_space(next_space)); + return true; +} + +optional ABBWelcomeProtocol::decode(RemoteReceiveData src) { + if (src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US) && + src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) && + src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) && + src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) && + src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US + BYTE_SPACE_US) && + src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + 8 * BIT_ONE_SPACE_US + BYTE_SPACE_US)) { + ESP_LOGVV(TAG, "Received Header: 0x55FF"); + ABBWelcomeData out; + out[0] = 0x55; + out[1] = 0xff; + bool done = false; + uint8_t length = 10; + uint8_t received_bytes = 2; + for (; (received_bytes < length) && !done; received_bytes++) { + uint8_t data = 0; + if (!this->decode_byte_(src, done, data)) { + ESP_LOGW(TAG, "Received incomplete packet: %s", out.to_string(received_bytes).c_str()); + return {}; + } + if (received_bytes == 2) { + length += std::min(static_cast(data & DATA_LENGTH_MASK), MAX_DATA_LENGTH); + if (data & 0x40) { + length += 2; + } + } + ESP_LOGVV(TAG, "Received Byte: 0x%02X", data); + out[received_bytes] = data; + } + if (out.is_valid()) { + ESP_LOGI(TAG, "Received: %s", out.to_string().c_str()); + return out; + } + ESP_LOGW(TAG, "Received malformed packet: %s", out.to_string(received_bytes).c_str()); + } + return {}; +} + +void ABBWelcomeProtocol::dump(const ABBWelcomeData &data) { + ESP_LOGD(TAG, "Received ABBWelcome: %s", data.to_string().c_str()); +} + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/remote_base/abbwelcome_protocol.h b/esphome/components/remote_base/abbwelcome_protocol.h new file mode 100644 index 0000000000..0493993926 --- /dev/null +++ b/esphome/components/remote_base/abbwelcome_protocol.h @@ -0,0 +1,251 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "remote_base.h" +#include +#include +#include + +namespace esphome { +namespace remote_base { + +static const uint8_t MAX_DATA_LENGTH = 15; +static const uint8_t DATA_LENGTH_MASK = 0x3f; + +/* +Message Format: + 2 bytes: Sync (0x55FF) + 1 bit: Retransmission flag (High means retransmission) + 1 bit: Address length flag (Low means 2 bytes, High means 3 bytes) + 2 bits: Unknown + 4 bits: Data length (in bytes) + 1 bit: Reply flag (High means this is a reply to a previous message with the same message type) + 7 bits: Message type + 2-3 bytes: Destination address + 2-3 bytes: Source address + 1 byte: Message ID (randomized, does not change for retransmissions) + 0-? bytes: Data + 1 byte: Checksum +*/ + +class ABBWelcomeData { + public: + // Make default + ABBWelcomeData() { + std::fill(std::begin(this->data_), std::end(this->data_), 0); + this->data_[0] = 0x55; + this->data_[1] = 0xff; + } + // Make from initializer_list + ABBWelcomeData(std::initializer_list data) { + std::fill(std::begin(this->data_), std::end(this->data_), 0); + std::copy_n(data.begin(), std::min(data.size(), this->data_.size()), this->data_.begin()); + } + // Make from vector + ABBWelcomeData(const std::vector &data) { + std::fill(std::begin(this->data_), std::end(this->data_), 0); + std::copy_n(data.begin(), std::min(data.size(), this->data_.size()), this->data_.begin()); + } + // Default copy constructor + ABBWelcomeData(const ABBWelcomeData &) = default; + + bool auto_message_id{false}; + + uint8_t *data() { return this->data_.data(); } + const uint8_t *data() const { return this->data_.data(); } + uint8_t size() const { + return std::min(static_cast(6 + (2 * this->get_address_length()) + (this->data_[2] & DATA_LENGTH_MASK)), + static_cast(this->data_.size())); + } + bool is_valid() const { + return this->data_[0] == 0x55 && this->data_[1] == 0xff && + ((this->data_[2] & DATA_LENGTH_MASK) <= MAX_DATA_LENGTH) && + (this->data_[this->size() - 1] == this->calc_cs_()); + } + void set_retransmission(bool retransmission) { + if (retransmission) { + this->data_[2] |= 0x80; + } else { + this->data_[2] &= 0x7f; + } + } + bool get_retransmission() const { return this->data_[2] & 0x80; } + // set_three_byte_address must be called before set_source_address, set_destination_address, set_message_id and + // set_data! + void set_three_byte_address(bool three_byte_address) { + if (three_byte_address) { + this->data_[2] |= 0x40; + } else { + this->data_[2] &= 0xbf; + } + } + uint8_t get_three_byte_address() const { return (this->data_[2] & 0x40); } + uint8_t get_address_length() const { return this->get_three_byte_address() ? 3 : 2; } + void set_message_type(uint8_t message_type) { this->data_[3] = message_type; } + uint8_t get_message_type() const { return this->data_[3]; } + void set_destination_address(uint32_t address) { + if (this->get_address_length() == 2) { + this->data_[4] = (address >> 8) & 0xff; + this->data_[5] = address & 0xff; + } else { + this->data_[4] = (address >> 16) & 0xff; + this->data_[5] = (address >> 8) & 0xff; + this->data_[6] = address & 0xff; + } + } + uint32_t get_destination_address() const { + if (this->get_address_length() == 2) { + return (this->data_[4] << 8) + this->data_[5]; + } + return (this->data_[4] << 16) + (this->data_[5] << 8) + this->data_[6]; + } + void set_source_address(uint32_t address) { + if (this->get_address_length() == 2) { + this->data_[6] = (address >> 8) & 0xff; + this->data_[7] = address & 0xff; + } else { + this->data_[7] = (address >> 16) & 0xff; + this->data_[8] = (address >> 8) & 0xff; + this->data_[9] = address & 0xff; + } + } + uint32_t get_source_address() const { + if (this->get_address_length() == 2) { + return (this->data_[6] << 8) + this->data_[7]; + } + return (this->data_[7] << 16) + (this->data_[8] << 8) + this->data_[9]; + } + void set_message_id(uint8_t message_id) { this->data_[4 + 2 * this->get_address_length()] = message_id; } + uint8_t get_message_id() const { return this->data_[4 + 2 * this->get_address_length()]; } + void set_data(std::vector data) { + uint8_t size = std::min(MAX_DATA_LENGTH, static_cast(data.size())); + this->data_[2] &= (0xff ^ DATA_LENGTH_MASK); + this->data_[2] |= (size & DATA_LENGTH_MASK); + if (size) + std::copy_n(data.begin(), size, this->data_.begin() + 5 + 2 * this->get_address_length()); + } + std::vector get_data() const { + std::vector data(this->data_.begin() + 5 + 2 * this->get_address_length(), + this->data_.begin() + 5 + 2 * this->get_address_length() + this->get_data_size()); + return data; + } + uint8_t get_data_size() const { + return std::min(MAX_DATA_LENGTH, static_cast(this->data_[2] & DATA_LENGTH_MASK)); + } + void finalize() { + if (this->auto_message_id && !this->get_retransmission() && !(this->data_[3] & 0x80)) { + this->set_message_id(static_cast(random_uint32())); + } + this->data_[0] = 0x55; + this->data_[1] = 0xff; + this->data_[this->size() - 1] = this->calc_cs_(); + } + std::string to_string(uint8_t max_print_bytes = 255) const { + std::string info; + if (this->is_valid()) { + info = str_sprintf(this->get_three_byte_address() ? "[%06X %s %06X] Type: %02X" : "[%04X %s %04X] Type: %02X", + this->get_source_address(), this->get_retransmission() ? "»" : ">", + this->get_destination_address(), this->get_message_type()); + if (this->get_data_size()) + info += str_sprintf(", Data: %s", format_hex_pretty(this->get_data()).c_str()); + } else { + info = "[Invalid]"; + } + uint8_t print_bytes = std::min(this->size(), max_print_bytes); + if (print_bytes) + info = str_sprintf("%s %s", format_hex_pretty(this->data_.data(), print_bytes).c_str(), info.c_str()); + return info; + } + bool operator==(const ABBWelcomeData &rhs) const { + if (std::equal(this->data_.begin(), this->data_.begin() + this->size(), rhs.data_.begin())) + return true; + return (this->auto_message_id || rhs.auto_message_id) && this->is_valid() && rhs.is_valid() && + (this->get_message_type() == rhs.get_message_type()) && + (this->get_source_address() == rhs.get_source_address()) && + (this->get_destination_address() == rhs.get_destination_address()) && (this->get_data() == rhs.get_data()); + } + uint8_t &operator[](size_t idx) { return this->data_[idx]; } + const uint8_t &operator[](size_t idx) const { return this->data_[idx]; } + + protected: + std::array data_; + // Calculate checksum + uint8_t calc_cs_() const; +}; + +class ABBWelcomeProtocol : public RemoteProtocol { + public: + void encode(RemoteTransmitData *dst, const ABBWelcomeData &src) override; + optional decode(RemoteReceiveData src) override; + void dump(const ABBWelcomeData &data) override; + + protected: + void encode_byte_(RemoteTransmitData *dst, uint8_t data) const; + bool decode_byte_(RemoteReceiveData &src, bool &done, uint8_t &data); +}; + +class ABBWelcomeBinarySensor : public RemoteReceiverBinarySensorBase { + public: + bool matches(RemoteReceiveData src) override { + auto data = ABBWelcomeProtocol().decode(src); + return data.has_value() && data.value() == this->data_; + } + void set_source_address(const uint32_t source_address) { this->data_.set_source_address(source_address); } + void set_destination_address(const uint32_t destination_address) { + this->data_.set_destination_address(destination_address); + } + void set_retransmission(const bool retransmission) { this->data_.set_retransmission(retransmission); } + void set_three_byte_address(const bool three_byte_address) { this->data_.set_three_byte_address(three_byte_address); } + void set_message_type(const uint8_t message_type) { this->data_.set_message_type(message_type); } + void set_message_id(const uint8_t message_id) { this->data_.set_message_id(message_id); } + void set_auto_message_id(const bool auto_message_id) { this->data_.auto_message_id = auto_message_id; } + void set_data(const std::vector &data) { this->data_.set_data(data); } + void finalize() { this->data_.finalize(); } + + protected: + ABBWelcomeData data_; +}; + +using ABBWelcomeTrigger = RemoteReceiverTrigger; +using ABBWelcomeDumper = RemoteReceiverDumper; + +template class ABBWelcomeAction : public RemoteTransmitterActionBase { + TEMPLATABLE_VALUE(uint32_t, source_address) + TEMPLATABLE_VALUE(uint32_t, destination_address) + TEMPLATABLE_VALUE(bool, retransmission) + TEMPLATABLE_VALUE(bool, three_byte_address) + TEMPLATABLE_VALUE(uint8_t, message_type) + TEMPLATABLE_VALUE(uint8_t, message_id) + TEMPLATABLE_VALUE(bool, auto_message_id) + void set_data_static(std::vector data) { data_static_ = std::move(data); } + void set_data_template(std::function(Ts...)> func) { + this->data_func_ = func; + has_data_func_ = true; + } + void encode(RemoteTransmitData *dst, Ts... x) override { + ABBWelcomeData data; + data.set_three_byte_address(this->three_byte_address_.value(x...)); + data.set_source_address(this->source_address_.value(x...)); + data.set_destination_address(this->destination_address_.value(x...)); + data.set_retransmission(this->retransmission_.value(x...)); + data.set_message_type(this->message_type_.value(x...)); + data.set_message_id(this->message_id_.value(x...)); + data.auto_message_id = this->auto_message_id_.value(x...); + if (has_data_func_) { + data.set_data(this->data_func_(x...)); + } else { + data.set_data(this->data_static_); + } + data.finalize(); + ABBWelcomeProtocol().encode(dst, data); + } + + protected: + std::function(Ts...)> data_func_{}; + std::vector data_static_{}; + bool has_data_func_{false}; +}; + +} // namespace remote_base +} // namespace esphome From 76c53379877c0c8f40200ec0b1253ba0e5d39151 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:46:35 +1200 Subject: [PATCH 1508/2607] Add support for time entities (#6399) * Add time entities * Add tests * Add myself to datetime codeowners * Fix publishing times with 0 values * Log performing TimeCall * Implement `on_time` trigger * Rename var * Fix initial value for time * Add arg name for clarity * Remove useless checks --- CODEOWNERS | 2 +- esphome/components/api/api.proto | 42 ++++ esphome/components/api/api_connection.cpp | 37 +++ esphome/components/api/api_connection.h | 5 + esphome/components/api/api_pb2.cpp | 219 ++++++++++++++++++ esphome/components/api/api_pb2.h | 50 ++++ esphome/components/api/api_pb2_service.cpp | 42 ++++ esphome/components/api/api_pb2_service.h | 15 ++ esphome/components/api/api_server.cpp | 9 + esphome/components/api/api_server.h | 3 + esphome/components/api/list_entities.cpp | 4 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.cpp | 3 + esphome/components/api/subscribe_state.h | 3 + esphome/components/datetime/__init__.py | 83 ++++++- esphome/components/datetime/time_entity.cpp | 156 +++++++++++++ esphome/components/datetime/time_entity.h | 137 +++++++++++ esphome/components/mqtt/__init__.py | 3 +- esphome/components/mqtt/mqtt_date.h | 4 +- esphome/components/mqtt/mqtt_time.cpp | 68 ++++++ esphome/components/mqtt/mqtt_time.h | 45 ++++ .../components/template/datetime/__init__.py | 38 ++- .../template/datetime/template_time.cpp | 111 +++++++++ .../template/datetime/template_time.h | 46 ++++ .../components/web_server/list_entities.cpp | 7 + esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 58 +++++ esphome/components/web_server/web_server.h | 11 +- esphome/core/application.h | 19 ++ esphome/core/component_iterator.cpp | 15 ++ esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + script/ci-custom.py | 1 + .../datetime/{date.all.yaml => test.all.yaml} | 0 tests/components/template/test.all.yaml | 13 ++ 37 files changed, 1251 insertions(+), 23 deletions(-) create mode 100644 esphome/components/datetime/time_entity.cpp create mode 100644 esphome/components/datetime/time_entity.h create mode 100644 esphome/components/mqtt/mqtt_time.cpp create mode 100644 esphome/components/mqtt/mqtt_time.h create mode 100644 esphome/components/template/datetime/template_time.cpp create mode 100644 esphome/components/template/datetime/template_time.h rename tests/components/datetime/{date.all.yaml => test.all.yaml} (100%) diff --git a/CODEOWNERS b/CODEOWNERS index d2a86cd3d9..4a3205acf0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -91,7 +91,7 @@ esphome/components/daikin_arc/* @MagicBear esphome/components/daikin_brc/* @hagak esphome/components/daly_bms/* @s1lvi0 esphome/components/dashboard_import/* @esphome/core -esphome/components/datetime/* @rfdarter +esphome/components/datetime/* @jesserockz @rfdarter esphome/components/debug/* @OttoWinter esphome/components/delonghi/* @grob6000 esphome/components/dfplayer/* @glmnet diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 6b685b8974..8d5459e717 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -45,6 +45,7 @@ service APIConnection { rpc lock_command (LockCommandRequest) returns (void) {} rpc media_player_command (MediaPlayerCommandRequest) returns (void) {} rpc date_command (DateCommandRequest) returns (void) {} + rpc time_command (TimeCommandRequest) returns (void) {} rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {} @@ -1658,3 +1659,44 @@ message DateCommandRequest { uint32 month = 3; uint32 day = 4; } + +// ==================== DATETIME TIME ==================== +message ListEntitiesTimeResponse { + option (id) = 103; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_DATETIME_TIME"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; +} +message TimeStateResponse { + option (id) = 104; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_DATETIME_TIME"; + option (no_delay) = true; + + fixed32 key = 1; + // If the time does not have a valid state yet. + // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller + bool missing_state = 2; + uint32 hour = 3; + uint32 minute = 4; + uint32 second = 5; +} +message TimeCommandRequest { + option (id) = 105; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_DATETIME_TIME"; + option (no_delay) = true; + + fixed32 key = 1; + uint32 hour = 2; + uint32 minute = 3; + uint32 second = 4; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index e9607f7f77..e51fa8c154 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -735,6 +735,43 @@ void APIConnection::date_command(const DateCommandRequest &msg) { } #endif +#ifdef USE_DATETIME_TIME +bool APIConnection::send_time_state(datetime::TimeEntity *time) { + if (!this->state_subscription_) + return false; + + TimeStateResponse resp{}; + resp.key = time->get_object_id_hash(); + resp.missing_state = !time->has_state(); + resp.hour = time->hour; + resp.minute = time->minute; + resp.second = time->second; + return this->send_time_state_response(resp); +} +bool APIConnection::send_time_info(datetime::TimeEntity *time) { + ListEntitiesTimeResponse msg; + msg.key = time->get_object_id_hash(); + msg.object_id = time->get_object_id(); + if (time->has_own_name()) + msg.name = time->get_name(); + msg.unique_id = get_default_unique_id("time", time); + msg.icon = time->get_icon(); + msg.disabled_by_default = time->is_disabled_by_default(); + msg.entity_category = static_cast(time->get_entity_category()); + + return this->send_list_entities_time_response(msg); +} +void APIConnection::time_command(const TimeCommandRequest &msg) { + datetime::TimeEntity *time = App.get_time_by_key(msg.key); + if (time == nullptr) + return; + + auto call = time->make_call(); + call.set_time(msg.hour, msg.minute, msg.second); + call.perform(); +} +#endif + #ifdef USE_TEXT bool APIConnection::send_text_state(text::Text *text, std::string state) { if (!this->state_subscription_) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index c19c209969..5c0a78015d 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -77,6 +77,11 @@ class APIConnection : public APIServerConnection { bool send_date_info(datetime::DateEntity *date); void date_command(const DateCommandRequest &msg) override; #endif +#ifdef USE_DATETIME_TIME + bool send_time_state(datetime::TimeEntity *time); + bool send_time_info(datetime::TimeEntity *time); + void time_command(const TimeCommandRequest &msg) override; +#endif #ifdef USE_TEXT bool send_text_state(text::Text *text, std::string state); bool send_text_info(text::Text *text); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index f6325d0854..884396bda3 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7476,6 +7476,225 @@ void DateCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ListEntitiesTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + default: + return false; + } +} +bool ListEntitiesTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesTimeResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesTimeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesTimeResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + out.append("}"); +} +#endif +bool TimeStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->missing_state = value.as_bool(); + return true; + } + case 3: { + this->hour = value.as_uint32(); + return true; + } + case 4: { + this->minute = value.as_uint32(); + return true; + } + case 5: { + this->second = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool TimeStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void TimeStateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_bool(2, this->missing_state); + buffer.encode_uint32(3, this->hour); + buffer.encode_uint32(4, this->minute); + buffer.encode_uint32(5, this->second); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void TimeStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TimeStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" hour: "); + sprintf(buffer, "%" PRIu32, this->hour); + out.append(buffer); + out.append("\n"); + + out.append(" minute: "); + sprintf(buffer, "%" PRIu32, this->minute); + out.append(buffer); + out.append("\n"); + + out.append(" second: "); + sprintf(buffer, "%" PRIu32, this->second); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +bool TimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->hour = value.as_uint32(); + return true; + } + case 3: { + this->minute = value.as_uint32(); + return true; + } + case 4: { + this->second = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool TimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void TimeCommandRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_uint32(2, this->hour); + buffer.encode_uint32(3, this->minute); + buffer.encode_uint32(4, this->second); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void TimeCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TimeCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" hour: "); + sprintf(buffer, "%" PRIu32, this->hour); + out.append(buffer); + out.append("\n"); + + out.append(" minute: "); + sprintf(buffer, "%" PRIu32, this->minute); + out.append(buffer); + out.append("\n"); + + out.append(" second: "); + sprintf(buffer, "%" PRIu32, this->second); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index e361e6b8e1..2ae6fd2bb6 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1919,6 +1919,56 @@ class DateCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class ListEntitiesTimeResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class TimeStateResponse : public ProtoMessage { + public: + uint32_t key{0}; + bool missing_state{false}; + uint32_t hour{0}; + uint32_t minute{0}; + uint32_t second{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class TimeCommandRequest : public ProtoMessage { + public: + uint32_t key{0}; + uint32_t hour{0}; + uint32_t minute{0}; + uint32_t second{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 2067f530ce..7a97df1ce0 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -539,6 +539,24 @@ bool APIServerConnectionBase::send_date_state_response(const DateStateResponse & #endif #ifdef USE_DATETIME_DATE #endif +#ifdef USE_DATETIME_TIME +bool APIServerConnectionBase::send_list_entities_time_response(const ListEntitiesTimeResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_time_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 103); +} +#endif +#ifdef USE_DATETIME_TIME +bool APIServerConnectionBase::send_time_state_response(const TimeStateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_time_state_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 104); +} +#endif +#ifdef USE_DATETIME_TIME +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -979,6 +997,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str()); #endif this->on_date_command_request(msg); +#endif + break; + } + case 105: { +#ifdef USE_DATETIME_TIME + TimeCommandRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str()); +#endif + this->on_time_command_request(msg); #endif break; } @@ -1279,6 +1308,19 @@ void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) this->date_command(msg); } #endif +#ifdef USE_DATETIME_TIME +void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->time_command(msg); +} +#endif #ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &msg) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index effcfc30f4..095ce51b0f 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -270,6 +270,15 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_DATETIME_DATE virtual void on_date_command_request(const DateCommandRequest &value){}; +#endif +#ifdef USE_DATETIME_TIME + bool send_list_entities_time_response(const ListEntitiesTimeResponse &msg); +#endif +#ifdef USE_DATETIME_TIME + bool send_time_state_response(const TimeStateResponse &msg); +#endif +#ifdef USE_DATETIME_TIME + virtual void on_time_command_request(const TimeCommandRequest &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -328,6 +337,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_DATE virtual void date_command(const DateCommandRequest &msg) = 0; #endif +#ifdef USE_DATETIME_TIME + virtual void time_command(const TimeCommandRequest &msg) = 0; +#endif #ifdef USE_BLUETOOTH_PROXY virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; #endif @@ -417,6 +429,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_DATE void on_date_command_request(const DateCommandRequest &msg) override; #endif +#ifdef USE_DATETIME_TIME + void on_time_command_request(const TimeCommandRequest &msg) override; +#endif #ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index b17555bb49..4c809126e6 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -264,6 +264,15 @@ void APIServer::on_date_update(datetime::DateEntity *obj) { } #endif +#ifdef USE_DATETIME_TIME +void APIServer::on_time_update(datetime::TimeEntity *obj) { + if (obj->is_internal()) + return; + for (auto &c : this->clients_) + c->send_time_state(obj); +} +#endif + #ifdef USE_TEXT void APIServer::on_text_update(text::Text *obj, const std::string &state) { if (obj->is_internal()) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index c12355cc8b..8a9c26af73 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -69,6 +69,9 @@ class APIServer : public Component, public Controller { #ifdef USE_DATETIME_DATE void on_date_update(datetime::DateEntity *obj) override; #endif +#ifdef USE_DATETIME_TIME + void on_time_update(datetime::TimeEntity *obj) override; +#endif #ifdef USE_TEXT void on_text_update(text::Text *obj, const std::string &state) override; #endif diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index cd1841de5e..18685ee4d1 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -64,6 +64,10 @@ bool ListEntitiesIterator::on_number(number::Number *number) { return this->clie bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_info(date); } #endif +#ifdef USE_DATETIME_TIME +bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_info(time); } +#endif + #ifdef USE_TEXT bool ListEntitiesIterator::on_text(text::Text *text) { return this->client_->send_text_info(text); } #endif diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index b49867048d..95a09fc25b 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -49,6 +49,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_DATETIME_DATE bool on_date(datetime::DateEntity *date) override; #endif +#ifdef USE_DATETIME_TIME + bool on_time(datetime::TimeEntity *time) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 4e7216ddef..5eb40cfa7e 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -45,6 +45,9 @@ bool InitialStateIterator::on_number(number::Number *number) { #ifdef USE_DATETIME_DATE bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_state(date); } #endif +#ifdef USE_DATETIME_TIME +bool InitialStateIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_state(time); } +#endif #ifdef USE_TEXT bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text, text->state); } #endif diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 4a96659b76..447f1707d2 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -46,6 +46,9 @@ class InitialStateIterator : public ComponentIterator { #ifdef USE_DATETIME_DATE bool on_date(datetime::DateEntity *date) override; #endif +#ifdef USE_DATETIME_TIME + bool on_time(datetime::TimeEntity *time) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 3ae99cfff6..b255a27303 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -3,38 +3,50 @@ import esphome.codegen as cg # import cpp_generator as cpp import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, time from esphome.const import ( CONF_ID, + CONF_ON_TIME, CONF_ON_VALUE, + CONF_TIME_ID, CONF_TRIGGER_ID, CONF_TYPE, CONF_MQTT_ID, CONF_DATE, + CONF_TIME, CONF_YEAR, CONF_MONTH, CONF_DAY, + CONF_SECOND, + CONF_HOUR, + CONF_MINUTE, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity -CODEOWNERS = ["@rfdarter"] +CODEOWNERS = ["@rfdarter", "@jesserockz"] IS_PLATFORM_COMPONENT = True datetime_ns = cg.esphome_ns.namespace("datetime") DateTimeBase = datetime_ns.class_("DateTimeBase", cg.EntityBase) DateEntity = datetime_ns.class_("DateEntity", DateTimeBase) +TimeEntity = datetime_ns.class_("TimeEntity", DateTimeBase) # Actions DateSetAction = datetime_ns.class_("DateSetAction", automation.Action) +TimeSetAction = datetime_ns.class_("TimeSetAction", automation.Action) DateTimeStateTrigger = datetime_ns.class_( "DateTimeStateTrigger", automation.Trigger.template(cg.ESPTime) ) +OnTimeTrigger = datetime_ns.class_( + "OnTimeTrigger", automation.Trigger, cg.Component, cg.Parented.template(TimeEntity) +) + DATETIME_MODES = [ "DATE", "TIME", @@ -44,7 +56,6 @@ DATETIME_MODES = [ _DATETIME_SCHEMA = cv.Schema( { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTDatetimeComponent), cv.Optional(CONF_ON_VALUE): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), @@ -57,6 +68,7 @@ _DATETIME_SCHEMA = cv.Schema( def date_schema(class_: MockObjClass) -> cv.Schema: schema = { cv.GenerateID(): cv.declare_id(class_), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTDateComponent), cv.Optional(CONF_TYPE, default="DATE"): cv.one_of("DATE", upper=True), } return _DATETIME_SCHEMA.extend(schema) @@ -65,7 +77,20 @@ def date_schema(class_: MockObjClass) -> cv.Schema: def time_schema(class_: MockObjClass) -> cv.Schema: schema = { cv.GenerateID(): cv.declare_id(class_), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTimeComponent), cv.Optional(CONF_TYPE, default="TIME"): cv.one_of("TIME", upper=True), + cv.Inclusive( + CONF_ON_TIME, + group_of_inclusion=CONF_ON_TIME, + msg="`on_time` and `time_id` must both be specified", + ): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnTimeTrigger), + } + ), + cv.Inclusive(CONF_TIME_ID, group_of_inclusion=CONF_ON_TIME): cv.use_id( + time.RealTimeClock + ), } return _DATETIME_SCHEMA.extend(schema) @@ -88,6 +113,17 @@ async def setup_datetime_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) + rtc_id = config.get(CONF_TIME_ID) + rtc = None + if rtc_id is not None: + rtc = await cg.get_variable(rtc_id) + for conf in config.get(CONF_ON_TIME, []): + assert rtc is not None + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], rtc) + await automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await cg.register_parented(trigger, var) + async def register_datetime(var, config): if not CORE.has_id(config[CONF_ID]): @@ -109,18 +145,12 @@ async def to_code(config): cg.add_global(datetime_ns.using) -OPERATION_BASE_SCHEMA = cv.Schema( - { - cv.Required(CONF_ID): cv.use_id(DateEntity), - } -) - - @automation.register_action( "datetime.date.set", DateSetAction, - OPERATION_BASE_SCHEMA.extend( + cv.Schema( { + cv.Required(CONF_ID): cv.use_id(DateEntity), cv.Required(CONF_DATE): cv.Any( cv.returning_lambda, cv.date_time(allowed_time=False) ), @@ -144,3 +174,34 @@ async def datetime_date_set_to_code(config, action_id, template_arg, args): ) cg.add(action_var.set_date(date_struct)) return action_var + + +@automation.register_action( + "datetime.time.set", + TimeSetAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(TimeEntity), + cv.Required(CONF_TIME): cv.Any( + cv.returning_lambda, cv.date_time(allowed_date=False) + ), + } + ), +) +async def datetime_time_set_to_code(config, action_id, template_arg, args): + action_var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(action_var, config[CONF_ID]) + + time_config = config[CONF_TIME] + if cg.is_template(time_config): + template_ = await cg.templatable(config[CONF_TIME], [], cg.ESPTime) + cg.add(action_var.set_time(template_)) + else: + time_struct = cg.StructInitializer( + cg.ESPTime, + ("second", time_config[CONF_SECOND]), + ("minute", time_config[CONF_MINUTE]), + ("hour", time_config[CONF_HOUR]), + ) + cg.add(action_var.set_time(time_struct)) + return action_var diff --git a/esphome/components/datetime/time_entity.cpp b/esphome/components/datetime/time_entity.cpp new file mode 100644 index 0000000000..98558152d7 --- /dev/null +++ b/esphome/components/datetime/time_entity.cpp @@ -0,0 +1,156 @@ +#include "time_entity.h" + +#ifdef USE_DATETIME_TIME + +#include "esphome/core/log.h" + +namespace esphome { +namespace datetime { + +static const char *const TAG = "datetime.time_entity"; + +void TimeEntity::publish_state() { + if (this->hour_ > 23) { + this->has_state_ = false; + ESP_LOGE(TAG, "Hour must be between 0 and 23"); + return; + } + if (this->minute_ > 59) { + this->has_state_ = false; + ESP_LOGE(TAG, "Minute must be between 0 and 59"); + return; + } + if (this->second_ > 59) { + this->has_state_ = false; + ESP_LOGE(TAG, "Second must be between 0 and 59"); + return; + } + this->has_state_ = true; + ESP_LOGD(TAG, "'%s': Sending time %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_, + this->second_); + this->state_callback_.call(); +} + +TimeCall TimeEntity::make_call() { return TimeCall(this); } + +void TimeCall::validate_() { + if (this->hour_.has_value() && this->hour_ > 23) { + ESP_LOGE(TAG, "Hour must be between 0 and 23"); + this->hour_.reset(); + } + if (this->minute_.has_value() && this->minute_ > 59) { + ESP_LOGE(TAG, "Minute must be between 0 and 59"); + this->minute_.reset(); + } + if (this->second_.has_value() && this->second_ > 59) { + ESP_LOGE(TAG, "Second must be between 0 and 59"); + this->second_.reset(); + } +} + +void TimeCall::perform() { + this->validate_(); + ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str()); + if (this->hour_.has_value()) { + ESP_LOGD(TAG, " Hour: %d", *this->hour_); + } + if (this->minute_.has_value()) { + ESP_LOGD(TAG, " Minute: %d", *this->minute_); + } + if (this->second_.has_value()) { + ESP_LOGD(TAG, " Second: %d", *this->second_); + } + this->parent_->control(*this); +} + +TimeCall &TimeCall::set_time(uint8_t hour, uint8_t minute, uint8_t second) { + this->hour_ = hour; + this->minute_ = minute; + this->second_ = second; + return *this; +}; + +TimeCall &TimeCall::set_time(ESPTime time) { return this->set_time(time.hour, time.minute, time.second); }; + +TimeCall &TimeCall::set_time(const std::string &time) { + ESPTime val{}; + if (!ESPTime::strptime(time, val)) { + ESP_LOGE(TAG, "Could not convert the time string to an ESPTime object"); + return *this; + } + return this->set_time(val); +} + +TimeCall TimeEntityRestoreState::to_call(TimeEntity *time) { + TimeCall call = time->make_call(); + call.set_time(this->hour, this->minute, this->second); + return call; +} + +void TimeEntityRestoreState::apply(TimeEntity *time) { + time->hour_ = this->hour; + time->minute_ = this->minute; + time->second_ = this->second; + time->publish_state(); +} + +#ifdef USE_TIME + +static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider + // there has been a drastic time synchronization + +void OnTimeTrigger::loop() { + if (!this->parent_->has_state()) { + return; + } + ESPTime time = this->rtc_->now(); + if (!time.is_valid()) { + return; + } + if (this->last_check_.has_value()) { + if (*this->last_check_ > time && this->last_check_->timestamp - time.timestamp > MAX_TIMESTAMP_DRIFT) { + // We went back in time (a lot), probably caused by time synchronization + ESP_LOGW(TAG, "Time has jumped back!"); + } else if (*this->last_check_ >= time) { + // already handled this one + return; + } else if (time > *this->last_check_ && time.timestamp - this->last_check_->timestamp > MAX_TIMESTAMP_DRIFT) { + // We went ahead in time (a lot), probably caused by time synchronization + ESP_LOGW(TAG, "Time has jumped ahead!"); + this->last_check_ = time; + return; + } + + while (true) { + this->last_check_->increment_second(); + if (*this->last_check_ >= time) + break; + + if (this->matches_(*this->last_check_)) { + this->trigger(); + break; + } + } + } + + this->last_check_ = time; + if (!time.fields_in_range()) { + ESP_LOGW(TAG, "Time is out of range!"); + ESP_LOGD(TAG, "Second=%02u Minute=%02u Hour=%02u", time.second, time.minute, time.hour); + } + + if (this->matches_(time)) + this->trigger(); +} + +bool OnTimeTrigger::matches_(const ESPTime &time) const { + return time.is_valid() && time.hour == this->parent_->hour && time.minute == this->parent_->minute && + time.second == this->parent_->second; +} + +#endif + +} // namespace datetime +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/datetime/time_entity.h b/esphome/components/datetime/time_entity.h new file mode 100644 index 0000000000..956c09e2b4 --- /dev/null +++ b/esphome/components/datetime/time_entity.h @@ -0,0 +1,137 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_DATETIME_TIME + +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" +#include "esphome/core/time.h" + +#include "datetime_base.h" + +#ifdef USE_TIME +#include "esphome/components/time/real_time_clock.h" +#endif + +namespace esphome { +namespace datetime { + +#define LOG_DATETIME_TIME(prefix, type, obj) \ + if ((obj) != nullptr) { \ + ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ + if (!(obj)->get_icon().empty()) { \ + ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ + } \ + } + +class TimeCall; +class TimeEntity; + +struct TimeEntityRestoreState { + uint8_t hour; + uint8_t minute; + uint8_t second; + + TimeCall to_call(TimeEntity *time); + void apply(TimeEntity *time); +} __attribute__((packed)); + +class TimeEntity : public DateTimeBase { + protected: + uint8_t hour_; + uint8_t minute_; + uint8_t second_; + + public: + void publish_state(); + TimeCall make_call(); + + ESPTime state_as_esptime() const override { + ESPTime obj; + obj.hour = this->hour_; + obj.minute = this->minute_; + obj.second = this->second_; + return obj; + } + + const uint8_t &hour = hour_; + const uint8_t &minute = minute_; + const uint8_t &second = second_; + + protected: + friend class TimeCall; + friend struct TimeEntityRestoreState; + + virtual void control(const TimeCall &call) = 0; +}; + +class TimeCall { + public: + explicit TimeCall(TimeEntity *parent) : parent_(parent) {} + void perform(); + TimeCall &set_time(uint8_t hour, uint8_t minute, uint8_t second); + TimeCall &set_time(ESPTime time); + TimeCall &set_time(const std::string &time); + + TimeCall &set_hour(uint8_t hour) { + this->hour_ = hour; + return *this; + } + TimeCall &set_minute(uint8_t minute) { + this->minute_ = minute; + return *this; + } + TimeCall &set_second(uint8_t second) { + this->second_ = second; + return *this; + } + + optional get_hour() const { return this->hour_; } + optional get_minute() const { return this->minute_; } + optional get_second() const { return this->second_; } + + protected: + void validate_(); + + TimeEntity *parent_; + + optional hour_; + optional minute_; + optional second_; +}; + +template class TimeSetAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(ESPTime, time) + + void play(Ts... x) override { + auto call = this->parent_->make_call(); + + if (this->time_.has_value()) { + call.set_time(this->time_.value(x...)); + } + call.perform(); + } +}; + +#ifdef USE_TIME + +class OnTimeTrigger : public Trigger<>, public Component, public Parented { + public: + explicit OnTimeTrigger(time::RealTimeClock *rtc) : rtc_(rtc) {} + void loop() override; + + protected: + bool matches_(const ESPTime &time) const; + + time::RealTimeClock *rtc_; + optional last_check_; +}; + +#endif + +} // namespace datetime +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index e442eb9146..b2c03c1546 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -113,7 +113,8 @@ MQTTSensorComponent = mqtt_ns.class_("MQTTSensorComponent", MQTTComponent) MQTTSwitchComponent = mqtt_ns.class_("MQTTSwitchComponent", MQTTComponent) MQTTTextSensor = mqtt_ns.class_("MQTTTextSensor", MQTTComponent) MQTTNumberComponent = mqtt_ns.class_("MQTTNumberComponent", MQTTComponent) -MQTTDatetimeComponent = mqtt_ns.class_("MQTTDatetimeComponent", MQTTComponent) +MQTTDateComponent = mqtt_ns.class_("MQTTDateComponent", MQTTComponent) +MQTTTimeComponent = mqtt_ns.class_("MQTTTimeComponent", MQTTComponent) MQTTTextComponent = mqtt_ns.class_("MQTTTextComponent", MQTTComponent) MQTTSelectComponent = mqtt_ns.class_("MQTTSelectComponent", MQTTComponent) MQTTButtonComponent = mqtt_ns.class_("MQTTButtonComponent", MQTTComponent) diff --git a/esphome/components/mqtt/mqtt_date.h b/esphome/components/mqtt/mqtt_date.h index 2776893d32..5147afe7e7 100644 --- a/esphome/components/mqtt/mqtt_date.h +++ b/esphome/components/mqtt/mqtt_date.h @@ -13,9 +13,9 @@ namespace mqtt { class MQTTDateComponent : public mqtt::MQTTComponent { public: - /** Construct this MQTTDatetimeComponent instance with the provided friendly_name and datetime + /** Construct this MQTTDateComponent instance with the provided friendly_name and date * - * @param datetime The datetime component. + * @param date The date component. */ explicit MQTTDateComponent(datetime::DateEntity *date); diff --git a/esphome/components/mqtt/mqtt_time.cpp b/esphome/components/mqtt/mqtt_time.cpp new file mode 100644 index 0000000000..332ef53cbc --- /dev/null +++ b/esphome/components/mqtt/mqtt_time.cpp @@ -0,0 +1,68 @@ +#include "mqtt_time.h" + +#include +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_DATETIME_TIME + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.datetime.time"; + +using namespace esphome::datetime; + +MQTTTimeComponent::MQTTTimeComponent(TimeEntity *time) : time_(time) {} + +void MQTTTimeComponent::setup() { + this->subscribe_json(this->get_command_topic_(), [this](const std::string &topic, JsonObject root) { + auto call = this->time_->make_call(); + if (root.containsKey("hour")) { + call.set_hour(root["hour"]); + } + if (root.containsKey("minute")) { + call.set_minute(root["minute"]); + } + if (root.containsKey("second")) { + call.set_second(root["second"]); + } + call.perform(); + }); + this->time_->add_on_state_callback( + [this]() { this->publish_state(this->time_->hour, this->time_->minute, this->time_->second); }); +} + +void MQTTTimeComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Time '%s':", this->time_->get_name().c_str()); + LOG_MQTT_COMPONENT(true, true) +} + +std::string MQTTTimeComponent::component_type() const { return "time"; } +const EntityBase *MQTTTimeComponent::get_entity() const { return this->time_; } + +void MQTTTimeComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + // Nothing extra to add here +} +bool MQTTTimeComponent::send_initial_state() { + if (this->time_->has_state()) { + return this->publish_state(this->time_->hour, this->time_->minute, this->time_->second); + } else { + return true; + } +} +bool MQTTTimeComponent::publish_state(uint8_t hour, uint8_t minute, uint8_t second) { + return this->publish_json(this->get_state_topic_(), [hour, minute, second](JsonObject root) { + root["hour"] = hour; + root["minute"] = minute; + root["second"] = second; + }); +} + +} // namespace mqtt +} // namespace esphome + +#endif // USE_DATETIME_TIME +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_time.h b/esphome/components/mqtt/mqtt_time.h new file mode 100644 index 0000000000..b9dd822a73 --- /dev/null +++ b/esphome/components/mqtt/mqtt_time.h @@ -0,0 +1,45 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_MQTT +#ifdef USE_DATETIME_TIME + +#include "esphome/components/datetime/time_entity.h" +#include "mqtt_component.h" + +namespace esphome { +namespace mqtt { + +class MQTTTimeComponent : public mqtt::MQTTComponent { + public: + /** Construct this MQTTTimeComponent instance with the provided friendly_name and time + * + * @param time The time entity. + */ + explicit MQTTTimeComponent(datetime::TimeEntity *time); + + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + /// Override setup. + void setup() override; + void dump_config() override; + + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + bool send_initial_state() override; + + bool publish_state(uint8_t hour, uint8_t minute, uint8_t second); + + protected: + std::string component_type() const override; + const EntityBase *get_entity() const override; + + datetime::TimeEntity *time_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif // USE_DATETIME_DATE +#endif // USE_MQTT diff --git a/esphome/components/template/datetime/__init__.py b/esphome/components/template/datetime/__init__.py index 16f341301e..53d9d1b9d3 100644 --- a/esphome/components/template/datetime/__init__.py +++ b/esphome/components/template/datetime/__init__.py @@ -9,7 +9,11 @@ from esphome.const import ( CONF_RESTORE_VALUE, CONF_SET_ACTION, CONF_DAY, + CONF_HOUR, + CONF_MINUTE, CONF_MONTH, + CONF_SECOND, + CONF_TYPE, CONF_YEAR, ) @@ -23,6 +27,10 @@ TemplateDate = template_ns.class_( "TemplateDate", datetime.DateEntity, cg.PollingComponent ) +TemplateTime = template_ns.class_( + "TemplateTime", datetime.TimeEntity, cg.PollingComponent +) + def validate(config): config = config.copy() @@ -63,6 +71,13 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_VALUE): cv.date_time(allowed_time=False), } ), + "TIME": datetime.time_schema(TemplateTime) + .extend(_BASE_SCHEMA) + .extend( + { + cv.Optional(CONF_INITIAL_VALUE): cv.date_time(allowed_date=False), + } + ), }, upper=True, ), @@ -85,13 +100,22 @@ async def to_code(config): cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE])) if initial_value := config.get(CONF_INITIAL_VALUE): - date_struct = cg.StructInitializer( - cg.ESPTime, - ("day_of_month", initial_value[CONF_DAY]), - ("month", initial_value[CONF_MONTH]), - ("year", initial_value[CONF_YEAR]), - ) - cg.add(var.set_initial_value(date_struct)) + if config[CONF_TYPE] == "DATE": + date_struct = cg.StructInitializer( + cg.ESPTime, + ("day_of_month", initial_value[CONF_DAY]), + ("month", initial_value[CONF_MONTH]), + ("year", initial_value[CONF_YEAR]), + ) + cg.add(var.set_initial_value(date_struct)) + elif config[CONF_TYPE] == "TIME": + time_struct = cg.StructInitializer( + cg.ESPTime, + ("second", initial_value[CONF_SECOND]), + ("minute", initial_value[CONF_MINUTE]), + ("hour", initial_value[CONF_HOUR]), + ) + cg.add(var.set_initial_value(time_struct)) if CONF_SET_ACTION in config: await automation.build_automation( diff --git a/esphome/components/template/datetime/template_time.cpp b/esphome/components/template/datetime/template_time.cpp new file mode 100644 index 0000000000..0e4d734d16 --- /dev/null +++ b/esphome/components/template/datetime/template_time.cpp @@ -0,0 +1,111 @@ +#include "template_time.h" + +#ifdef USE_DATETIME_TIME + +#include "esphome/core/log.h" + +namespace esphome { +namespace template_ { + +static const char *const TAG = "template.time"; + +void TemplateTime::setup() { + if (this->f_.has_value()) + return; + + ESPTime state{}; + + if (!this->restore_value_) { + state = this->initial_value_; + } else { + datetime::TimeEntityRestoreState temp; + this->pref_ = + global_preferences->make_preference(194434060U ^ this->get_object_id_hash()); + if (this->pref_.load(&temp)) { + temp.apply(this); + return; + } else { + // set to inital value if loading from pref failed + state = this->initial_value_; + } + } + + this->hour_ = state.hour; + this->minute_ = state.minute; + this->second_ = state.second; + this->publish_state(); +} + +void TemplateTime::update() { + if (!this->f_.has_value()) + return; + + auto val = (*this->f_)(); + if (!val.has_value()) + return; + + this->hour_ = val->hour; + this->minute_ = val->minute; + this->second_ = val->second; + this->publish_state(); +} + +void TemplateTime::control(const datetime::TimeCall &call) { + bool has_hour = call.get_hour().has_value(); + bool has_minute = call.get_minute().has_value(); + bool has_second = call.get_second().has_value(); + + ESPTime value = {}; + if (has_hour) + value.hour = *call.get_hour(); + + if (has_minute) + value.minute = *call.get_minute(); + + if (has_second) + value.second = *call.get_second(); + + this->set_trigger_->trigger(value); + + if (this->optimistic_) { + if (has_hour) + this->hour_ = *call.get_hour(); + if (has_minute) + this->minute_ = *call.get_minute(); + if (has_second) + this->second_ = *call.get_second(); + this->publish_state(); + } + + if (this->restore_value_) { + datetime::TimeEntityRestoreState temp = {}; + if (has_hour) { + temp.hour = *call.get_hour(); + } else { + temp.hour = this->hour_; + } + if (has_minute) { + temp.minute = *call.get_minute(); + } else { + temp.minute = this->minute_; + } + if (has_second) { + temp.second = *call.get_second(); + } else { + temp.second = this->second_; + } + + this->pref_.save(&temp); + } +} + +void TemplateTime::dump_config() { + LOG_DATETIME_TIME("", "Template Time", this); + ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); + LOG_UPDATE_INTERVAL(this); +} + +} // namespace template_ +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/template/datetime/template_time.h b/esphome/components/template/datetime/template_time.h new file mode 100644 index 0000000000..4a7c0098ec --- /dev/null +++ b/esphome/components/template/datetime/template_time.h @@ -0,0 +1,46 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_DATETIME_TIME + +#include "esphome/components/datetime/time_entity.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" +#include "esphome/core/time.h" + +namespace esphome { +namespace template_ { + +class TemplateTime : public datetime::TimeEntity, public PollingComponent { + public: + void set_template(std::function()> &&f) { this->f_ = f; } + + void setup() override; + void update() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + Trigger *get_set_trigger() const { return this->set_trigger_; } + void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } + + void set_initial_value(ESPTime initial_value) { this->initial_value_ = initial_value; } + void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } + + protected: + void control(const datetime::TimeCall &call) override; + + bool optimistic_{false}; + ESPTime initial_value_{}; + bool restore_value_{false}; + Trigger *set_trigger_ = new Trigger(); + optional()>> f_; + + ESPPreferenceObject pref_; +}; + +} // namespace template_ +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 2252f55008..dd9fd4afe4 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -113,6 +113,13 @@ bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { } #endif +#ifdef USE_DATETIME_TIME +bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { + this->web_server_->events_.send(this->web_server_->time_json(time, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + #ifdef USE_TEXT bool ListEntitiesIterator::on_text(text::Text *text) { if (this->web_server_->events_.count() == 0) diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index cd7c9099d6..fc48186b32 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -44,6 +44,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_DATETIME_DATE bool on_date(datetime::DateEntity *date) override; #endif +#ifdef USE_DATETIME_TIME + bool on_time(datetime::TimeEntity *time) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 6c3e4e5eec..b48a39cbcb 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -921,6 +921,52 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con } #endif // USE_DATETIME_DATE +#ifdef USE_DATETIME_TIME +void WebServer::on_time_update(datetime::TimeEntity *obj) { + this->events_.send(this->time_json(obj, DETAIL_STATE).c_str(), "state"); +} +void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (auto *obj : App.get_times()) { + if (obj->get_object_id() != match.id) + continue; + if (request->method() == HTTP_GET && match.method.empty()) { + std::string data = this->time_json(obj, DETAIL_STATE); + request->send(200, "application/json", data.c_str()); + return; + } + if (match.method != "set") { + request->send(404); + return; + } + + auto call = obj->make_call(); + + if (!request->hasParam("value")) { + request->send(409); + return; + } + + if (request->hasParam("value")) { + std::string value = request->getParam("value")->value().c_str(); + call.set_time(value); + } + + this->schedule_([call]() mutable { call.perform(); }); + request->send(200); + return; + } + request->send(404); +} +std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_config) { + return json::build_json([obj, start_config](JsonObject root) { + set_json_id(root, obj, "time-" + obj->get_object_id(), start_config); + std::string value = str_sprintf("%02d:%02d:%02d", obj->hour, obj->minute, obj->second); + root["value"] = value; + root["state"] = value; + }); +} +#endif // USE_DATETIME_TIME + #ifdef USE_TEXT void WebServer::on_text_update(text::Text *obj, const std::string &state) { if (this->events_.count() == 0) @@ -1320,6 +1366,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_DATETIME_TIME + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "time") + return true; +#endif + #ifdef USE_TEXT if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "text") return true; @@ -1445,6 +1496,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { } #endif +#ifdef USE_DATETIME_TIME + if (match.domain == "time") { + this->handle_time_request(request, match); + return; + } +#endif + #ifdef USE_TEXT if (match.domain == "text") { this->handle_text_request(request, match); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 57cbbe1339..1935f8d076 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -8,9 +8,9 @@ #include #ifdef USE_ESP32 -#include #include #include +#include #endif #if USE_WEBSERVER_VERSION >= 2 @@ -230,6 +230,15 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string date_json(datetime::DateEntity *obj, JsonDetail start_config); #endif +#ifdef USE_DATETIME_TIME + void on_time_update(datetime::TimeEntity *obj) override; + /// Handle a time request under '/time/'. + void handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match); + + /// Dump the time state with its value as a JSON string. + std::string time_json(datetime::TimeEntity *obj, JsonDetail start_config); +#endif + #ifdef USE_TEXT void on_text_update(text::Text *obj, const std::string &state) override; /// Handle a text input request under '/text/'. diff --git a/esphome/core/application.h b/esphome/core/application.h index 26125dd935..73330d27e3 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -42,6 +42,9 @@ #ifdef USE_DATETIME_DATE #include "esphome/components/datetime/date_entity.h" #endif +#ifdef USE_DATETIME_TIME +#include "esphome/components/datetime/time_entity.h" +#endif #ifdef USE_TEXT #include "esphome/components/text/text.h" #endif @@ -128,6 +131,10 @@ class Application { void register_date(datetime::DateEntity *date) { this->dates_.push_back(date); } #endif +#ifdef USE_DATETIME_TIME + void register_time(datetime::TimeEntity *time) { this->times_.push_back(time); } +#endif + #ifdef USE_TEXT void register_text(text::Text *text) { this->texts_.push_back(text); } #endif @@ -305,6 +312,15 @@ class Application { return nullptr; } #endif +#ifdef USE_DATETIME_TIME + const std::vector &get_times() { return this->times_; } + datetime::TimeEntity *get_time_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->times_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif #ifdef USE_TEXT const std::vector &get_texts() { return this->texts_; } text::Text *get_text_by_key(uint32_t key, bool include_internal = false) { @@ -401,6 +417,9 @@ class Application { #ifdef USE_DATETIME_DATE std::vector dates_{}; #endif +#ifdef USE_DATETIME_TIME + std::vector times_{}; +#endif #ifdef USE_SELECT std::vector selects_{}; #endif diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index 1e06221af6..228cf64d54 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -217,6 +217,21 @@ void ComponentIterator::advance() { } break; #endif +#ifdef USE_DATETIME_TIME + case IteratorState::DATETIME_TIME: + if (this->at_ >= App.get_times().size()) { + advance_platform = true; + } else { + auto *time = App.get_times()[this->at_]; + if (time->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_time(time); + } + } + break; +#endif #ifdef USE_TEXT case IteratorState::TEXT: if (this->at_ >= App.get_texts().size()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index 02c6dddacb..d7f19f2850 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -60,6 +60,9 @@ class ComponentIterator { #ifdef USE_DATETIME_DATE virtual bool on_date(datetime::DateEntity *date) = 0; #endif +#ifdef USE_DATETIME_TIME + virtual bool on_time(datetime::TimeEntity *time) = 0; +#endif #ifdef USE_TEXT virtual bool on_text(text::Text *text) = 0; #endif @@ -120,6 +123,9 @@ class ComponentIterator { #ifdef USE_DATETIME_DATE DATETIME_DATE, #endif +#ifdef USE_DATETIME_TIME + DATETIME_TIME, +#endif #ifdef USE_TEXT TEXT, #endif diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index 43b8fea50c..db5818d455 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -65,6 +65,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_state_callback([this, obj]() { this->on_date_update(obj); }); } #endif +#ifdef USE_DATETIME_TIME + for (auto *obj : App.get_times()) { + if (include_internal || !obj->is_internal()) + obj->add_on_state_callback([this, obj]() { this->on_time_update(obj); }); + } +#endif #ifdef USE_TEXT for (auto *obj : App.get_texts()) { if (include_internal || !obj->is_internal()) diff --git a/esphome/core/controller.h b/esphome/core/controller.h index c31cd22d07..9b1cfd93c6 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -34,6 +34,9 @@ #ifdef USE_DATETIME_DATE #include "esphome/components/datetime/date_entity.h" #endif +#ifdef USE_DATETIME_TIME +#include "esphome/components/datetime/time_entity.h" +#endif #ifdef USE_TEXT #include "esphome/components/text/text.h" #endif @@ -85,6 +88,9 @@ class Controller { #ifdef USE_DATETIME_DATE virtual void on_date_update(datetime::DateEntity *obj){}; #endif +#ifdef USE_DATETIME_TIME + virtual void on_time_update(datetime::TimeEntity *obj){}; +#endif #ifdef USE_TEXT virtual void on_text_update(text::Text *obj, const std::string &state){}; #endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 501dccc6fa..22153de5de 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -36,6 +36,7 @@ #define USE_NUMBER #define USE_DATETIME #define USE_DATETIME_DATE +#define USE_DATETIME_TIME #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK diff --git a/script/ci-custom.py b/script/ci-custom.py index 1ad44dc930..3be7be76a2 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -622,6 +622,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/climate/climate.h", "esphome/components/cover/cover.h", "esphome/components/datetime/date_entity.h", + "esphome/components/datetime/time_entity.h", "esphome/components/display/display.h", "esphome/components/fan/fan.h", "esphome/components/i2c/i2c.h", diff --git a/tests/components/datetime/date.all.yaml b/tests/components/datetime/test.all.yaml similarity index 100% rename from tests/components/datetime/date.all.yaml rename to tests/components/datetime/test.all.yaml diff --git a/tests/components/template/test.all.yaml b/tests/components/template/test.all.yaml index e50ffd7f67..29dc83b649 100644 --- a/tests/components/template/test.all.yaml +++ b/tests/components/template/test.all.yaml @@ -153,3 +153,16 @@ datetime: - x.year - x.month - x.day_of_month + - platform: template + name: Time + id: test_time + type: time + set_action: + - logger.log: "set_value" + on_value: + - logger.log: + format: "Time: %02d:%02d:%02d" + args: + - x.hour + - x.minute + - x.second From 55c49281a224966b4e40b38c0e2e56f39cf93e3b Mon Sep 17 00:00:00 2001 From: MRemy2 <95053616+MRemy2@users.noreply.github.com> Date: Tue, 9 Apr 2024 04:49:37 +0300 Subject: [PATCH 1509/2607] Fix Match by IRK (#6499) Co-authored-by: Remus --- esphome/components/ble_presence/ble_presence_device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/esphome/components/ble_presence/ble_presence_device.h b/esphome/components/ble_presence/ble_presence_device.h index 0d86f6a40d..e74c2f4f45 100644 --- a/esphome/components/ble_presence/ble_presence_device.h +++ b/esphome/components/ble_presence/ble_presence_device.h @@ -73,8 +73,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff, break; case MATCH_BY_IRK: if (resolve_irk_(device.address_uint64(), this->irk_)) { - this->publish_state(true); - this->found_ = true; + this->set_found_(true); return true; } break; From c66b2c52c1fb22fcc872edf8bf0caa5f3a369344 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:53:57 +1200 Subject: [PATCH 1510/2607] Add rmt_channel to remote_transmitter and remote_receiver (#6497) * Add rmt_channel to remote_transmitter and remote_receiver * Add codeowner * Add tests --- CODEOWNERS | 1 + esphome/components/esp32_rmt/__init__.py | 55 ++++++ .../components/esp32_rmt_led_strip/light.py | 26 +-- .../components/remote_base/remote_base.cpp | 3 + esphome/components/remote_base/remote_base.h | 5 +- .../components/remote_receiver/__init__.py | 11 +- .../remote_receiver/remote_receiver.h | 5 +- .../components/remote_transmitter/__init__.py | 10 +- .../remote_transmitter/remote_transmitter.h | 11 +- esphome/const.py | 1 + .../remote_receiver/esp32-common.yaml | 18 ++ .../remote_receiver/test.esp32-c3-idf.yaml | 6 + .../remote_receiver/test.esp32-c3.yaml | 6 + .../remote_receiver/test.esp32-idf.yaml | 6 + .../remote_receiver/test.esp32-s3-idf.yaml | 6 + .../remote_receiver/test.esp32.yaml | 6 + .../remote_receiver/test.esp8266.yaml | 17 ++ .../remote_transmitter/common-buttons.yaml | 178 ++++++++++++++++++ .../remote_transmitter/esp32-common.yaml | 8 + .../remote_transmitter/test.esp32-c3-idf.yaml | 6 + .../remote_transmitter/test.esp32-c3.yaml | 6 + .../remote_transmitter/test.esp32-idf.yaml | 6 + .../remote_transmitter/test.esp32-s3-idf.yaml | 6 + .../remote_transmitter/test.esp32.yaml | 6 + .../remote_transmitter/test.esp8266.yaml | 7 + 25 files changed, 383 insertions(+), 33 deletions(-) create mode 100644 esphome/components/esp32_rmt/__init__.py create mode 100644 tests/components/remote_receiver/esp32-common.yaml create mode 100644 tests/components/remote_receiver/test.esp32-c3-idf.yaml create mode 100644 tests/components/remote_receiver/test.esp32-c3.yaml create mode 100644 tests/components/remote_receiver/test.esp32-idf.yaml create mode 100644 tests/components/remote_receiver/test.esp32-s3-idf.yaml create mode 100644 tests/components/remote_receiver/test.esp32.yaml create mode 100644 tests/components/remote_receiver/test.esp8266.yaml create mode 100644 tests/components/remote_transmitter/common-buttons.yaml create mode 100644 tests/components/remote_transmitter/esp32-common.yaml create mode 100644 tests/components/remote_transmitter/test.esp32-c3-idf.yaml create mode 100644 tests/components/remote_transmitter/test.esp32-c3.yaml create mode 100644 tests/components/remote_transmitter/test.esp32-idf.yaml create mode 100644 tests/components/remote_transmitter/test.esp32-s3-idf.yaml create mode 100644 tests/components/remote_transmitter/test.esp32.yaml create mode 100644 tests/components/remote_transmitter/test.esp8266.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 4a3205acf0..126513943f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -115,6 +115,7 @@ esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz esphome/components/esp32_camera_web_server/* @ayufan esphome/components/esp32_can/* @Sympatron esphome/components/esp32_improv/* @jesserockz +esphome/components/esp32_rmt/* @jesserockz esphome/components/esp32_rmt_led_strip/* @jesserockz esphome/components/esp8266/* @esphome/core esphome/components/ethernet_info/* @gtjadsonsantos diff --git a/esphome/components/esp32_rmt/__init__.py b/esphome/components/esp32_rmt/__init__.py new file mode 100644 index 0000000000..bda240680b --- /dev/null +++ b/esphome/components/esp32_rmt/__init__.py @@ -0,0 +1,55 @@ +import esphome.config_validation as cv +import esphome.codegen as cg + +from esphome.components import esp32 + +CODEOWNERS = ["@jesserockz"] + +RMT_TX_CHANNELS = { + esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7], + esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], + esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3], + esp32.const.VARIANT_ESP32C3: [0, 1], + esp32.const.VARIANT_ESP32C6: [0, 1], + esp32.const.VARIANT_ESP32H2: [0, 1], +} + +RMT_RX_CHANNELS = { + esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7], + esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], + esp32.const.VARIANT_ESP32S3: [4, 5, 6, 7], + esp32.const.VARIANT_ESP32C3: [2, 3], + esp32.const.VARIANT_ESP32C6: [2, 3], + esp32.const.VARIANT_ESP32H2: [2, 3], +} + +rmt_channel_t = cg.global_ns.enum("rmt_channel_t") +RMT_CHANNEL_ENUMS = { + 0: rmt_channel_t.RMT_CHANNEL_0, + 1: rmt_channel_t.RMT_CHANNEL_1, + 2: rmt_channel_t.RMT_CHANNEL_2, + 3: rmt_channel_t.RMT_CHANNEL_3, + 4: rmt_channel_t.RMT_CHANNEL_4, + 5: rmt_channel_t.RMT_CHANNEL_5, + 6: rmt_channel_t.RMT_CHANNEL_6, + 7: rmt_channel_t.RMT_CHANNEL_7, +} + + +def validate_rmt_channel(*, tx: bool): + + rmt_channels = RMT_TX_CHANNELS if tx else RMT_RX_CHANNELS + + def _validator(value): + cv.only_on_esp32(value) + value = cv.int_(value) + variant = esp32.get_esp32_variant() + if variant not in rmt_channels: + raise cv.Invalid(f"ESP32 variant {variant} does not support RMT.") + if value not in rmt_channels[variant]: + raise cv.Invalid( + f"RMT channel {value} does not support {'transmitting' if tx else 'receiving'} for ESP32 variant {variant}." + ) + return cv.enum(RMT_CHANNEL_ENUMS)(value) + + return _validator diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index d38c7abeb8..3442940e3f 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -3,7 +3,7 @@ from dataclasses import dataclass import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import esp32, light +from esphome.components import esp32_rmt, light from esphome.const import ( CONF_CHIPSET, CONF_MAX_REFRESH_RATE, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_OUTPUT_ID, CONF_PIN, CONF_RGB_ORDER, + CONF_RMT_CHANNEL, ) CODEOWNERS = ["@jesserockz"] @@ -57,27 +58,6 @@ CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_LOW = "bit0_low" CONF_BIT1_HIGH = "bit1_high" CONF_BIT1_LOW = "bit1_low" -CONF_RMT_CHANNEL = "rmt_channel" - -RMT_CHANNELS = { - esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7], - esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], - esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3], - esp32.const.VARIANT_ESP32C3: [0, 1], - esp32.const.VARIANT_ESP32C6: [0, 1], - esp32.const.VARIANT_ESP32H2: [0, 1], -} - - -def _validate_rmt_channel(value): - variant = esp32.get_esp32_variant() - if variant not in RMT_CHANNELS: - raise cv.Invalid(f"ESP32 variant {variant} does not support RMT.") - if value not in RMT_CHANNELS[variant]: - raise cv.Invalid( - f"RMT channel {value} is not supported for ESP32 variant {variant}." - ) - return value CONFIG_SCHEMA = cv.All( @@ -87,7 +67,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number, cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True), - cv.Required(CONF_RMT_CHANNEL): _validate_rmt_channel, + cv.Required(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True), cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index f3e86aaab6..0e9cef8cca 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -15,6 +15,9 @@ RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_b next_rmt_channel = rmt_channel_t(int(next_rmt_channel) + mem_block_num); } +RemoteRMTChannel::RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num) + : channel_(channel), mem_block_num_(mem_block_num) {} + void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) { this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_); diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index ebbb528a23..b2a4b543ea 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -3,10 +3,10 @@ #pragma once +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" -#include "esphome/core/automation.h" -#include "esphome/components/binary_sensor/binary_sensor.h" #ifdef USE_ESP32 #include @@ -86,6 +86,7 @@ class RemoteComponentBase { class RemoteRMTChannel { public: explicit RemoteRMTChannel(uint8_t mem_block_num = 1); + explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1); void config_rmt(rmt_config_t &rmt); void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; } diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 5737957adb..6a68c8b254 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import remote_base +from esphome.components import remote_base, esp32_rmt from esphome.const import ( CONF_BUFFER_SIZE, CONF_DUMP, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_PIN, CONF_TOLERANCE, CONF_MEMORY_BLOCKS, + CONF_RMT_CHANNEL, ) from esphome.core import CORE, TimePeriod @@ -45,6 +46,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers( CONF_IDLE, default="10ms" ): cv.positive_time_period_microseconds, cv.Optional(CONF_MEMORY_BLOCKS, default=3): cv.Range(min=1, max=8), + cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=False), } ).extend(cv.COMPONENT_SCHEMA) ) @@ -53,7 +55,12 @@ CONFIG_SCHEMA = remote_base.validate_triggers( async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_PIN]) if CORE.is_esp32: - var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS]) + if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None: + var = cg.new_Pvariable( + config[CONF_ID], pin, rmt_channel, config[CONF_MEMORY_BLOCKS] + ) + else: + var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS]) else: var = cg.new_Pvariable(config[CONF_ID], pin) diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index c1343a8603..f29145a59e 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/remote_base/remote_base.h" +#include "esphome/core/component.h" #include @@ -38,6 +38,9 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, #ifdef USE_ESP32 RemoteReceiverComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} + + RemoteReceiverComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) + : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} #else RemoteReceiverComponent(InternalGPIOPin *pin) : RemoteReceiverBase(pin) {} #endif diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index e09e4c7f55..d203ff3417 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -1,8 +1,8 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import remote_base -from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN +from esphome.components import remote_base, esp32_rmt +from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN, CONF_RMT_CHANNEL AUTO_LOAD = ["remote_base"] remote_transmitter_ns = cg.esphome_ns.namespace("remote_transmitter") @@ -18,13 +18,17 @@ CONFIG_SCHEMA = cv.Schema( cv.Required(CONF_CARRIER_DUTY_PERCENT): cv.All( cv.percentage_int, cv.Range(min=1, max=100) ), + cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True), } ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_PIN]) - var = cg.new_Pvariable(config[CONF_ID], pin) + if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None: + var = cg.new_Pvariable(config[CONF_ID], pin, rmt_channel) + else: + var = cg.new_Pvariable(config[CONF_ID], pin) await cg.register_component(var, config) cg.add(var.set_carrier_duty_percent(config[CONF_CARRIER_DUTY_PERCENT])) diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index 686a6ec09b..e736172cda 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/remote_base/remote_base.h" +#include "esphome/core/component.h" #include @@ -16,8 +16,15 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, #endif { public: - explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {} +#ifdef USE_ESP32 + RemoteTransmitterComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) + : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} + RemoteTransmitterComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) + : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} +#else + explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {} +#endif void setup() override; void dump_config() override; diff --git a/esphome/const.py b/esphome/const.py index 8e3fd59ff0..7304653363 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -676,6 +676,7 @@ CONF_REVERSED = "reversed" CONF_RGB_ORDER = "rgb_order" CONF_RGBW = "rgbw" CONF_RISING_EDGE = "rising_edge" +CONF_RMT_CHANNEL = "rmt_channel" CONF_ROTATION = "rotation" CONF_RS_PIN = "rs_pin" CONF_RTD_NOMINAL_RESISTANCE = "rtd_nominal_resistance" diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml new file mode 100644 index 0000000000..d1d47661c5 --- /dev/null +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -0,0 +1,18 @@ +remote_receiver: + id: rcvr + pin: ${pin} + rmt_channel: ${rmt_channel} + dump: all + on_coolix: + then: + delay: !lambda "return x.first + x.second;" + on_rc_switch: + then: + delay: !lambda "return uint32_t(x.code) + x.protocol;" + +binary_sensor: + - platform: remote_receiver + name: Panasonic Remote Input + panasonic: + address: 0x4004 + command: 0x100BCBD diff --git a/tests/components/remote_receiver/test.esp32-c3-idf.yaml b/tests/components/remote_receiver/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_receiver/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_receiver/test.esp32-c3.yaml b/tests/components/remote_receiver/test.esp32-c3.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_receiver/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_receiver/test.esp32-idf.yaml b/tests/components/remote_receiver/test.esp32-idf.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_receiver/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_receiver/test.esp32-s3-idf.yaml b/tests/components/remote_receiver/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..265ecda771 --- /dev/null +++ b/tests/components/remote_receiver/test.esp32-s3-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO38 + rmt_channel: "5" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_receiver/test.esp32.yaml b/tests/components/remote_receiver/test.esp32.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_receiver/test.esp32.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_receiver/test.esp8266.yaml b/tests/components/remote_receiver/test.esp8266.yaml new file mode 100644 index 0000000000..a7c283da1e --- /dev/null +++ b/tests/components/remote_receiver/test.esp8266.yaml @@ -0,0 +1,17 @@ +remote_receiver: + id: rcvr + pin: GPIO5 + dump: all + on_coolix: + then: + delay: !lambda "return x.first + x.second;" + on_rc_switch: + then: + delay: !lambda "return uint32_t(x.code) + x.protocol;" + +binary_sensor: + - platform: remote_receiver + name: Panasonic Remote Input + panasonic: + address: 0x4004 + command: 0x100BCBD diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml new file mode 100644 index 0000000000..5f655acb7c --- /dev/null +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -0,0 +1,178 @@ +button: + - platform: template + name: JVC Off + id: living_room_lights_on + on_press: + remote_transmitter.transmit_jvc: + data: 0x10EF + - platform: template + name: MagiQuest + on_press: + remote_transmitter.transmit_magiquest: + wand_id: 0x01234567 + - platform: template + name: NEC + id: living_room_lights_off + on_press: + remote_transmitter.transmit_nec: + address: 0x4242 + command: 0x8484 + - platform: template + name: LG + on_press: + remote_transmitter.transmit_lg: + data: 4294967295 + nbits: 28 + - platform: template + name: Samsung + on_press: + remote_transmitter.transmit_samsung: + data: 0xABCDEF + - platform: template + name: Samsung36 + on_press: + remote_transmitter.transmit_samsung36: + address: 0x0400 + command: 0x000E00FF + - platform: template + name: ToshibaAC + on_press: + - remote_transmitter.transmit_toshiba_ac: + rc_code_1: 0xB24DBF4050AF + rc_code_2: 0xD5660001003C + - platform: template + name: Sony + on_press: + remote_transmitter.transmit_sony: + data: 0xABCDEF + nbits: 12 + - platform: template + name: Panasonic + on_press: + remote_transmitter.transmit_panasonic: + address: 0x4004 + command: 0x1000BCD + - platform: template + name: Pioneer + on_press: + - remote_transmitter.transmit_pioneer: + rc_code_1: 0xA556 + rc_code_2: 0xA506 + repeat: + times: 2 + - platform: template + name: RC Switch Raw + on_press: + remote_transmitter.transmit_rc_switch_raw: + code: "00101001100111110101xxxx" + protocol: 1 + - platform: template + name: RC Switch Type A + on_press: + remote_transmitter.transmit_rc_switch_type_a: + group: "11001" + device: "01000" + state: true + protocol: + pulse_length: 175 + sync: [1, 31] + zero: [1, 3] + one: [3, 1] + inverted: false + - platform: template + name: RC Switch Type B + on_press: + remote_transmitter.transmit_rc_switch_type_b: + address: 4 + channel: 2 + state: true + - platform: template + name: RC Switch Type C + on_press: + remote_transmitter.transmit_rc_switch_type_c: + family: "a" + group: 1 + device: 2 + state: true + - platform: template + name: RC Switch Type D + on_press: + remote_transmitter.transmit_rc_switch_type_d: + group: "a" + device: 2 + state: true + - platform: template + name: RC5 + on_press: + remote_transmitter.transmit_rc5: + address: 0x00 + command: 0x0B + - platform: template + name: RC5 + on_press: + remote_transmitter.transmit_raw: + code: [1000, -1000] + - platform: template + name: AEHA + id: eaha_hitachi_climate_power_on + on_press: + remote_transmitter.transmit_aeha: + address: 0x8008 + data: + [ + 0x00, + 0x02, + 0xFD, + 0xFF, + 0x00, + 0x33, + 0xCC, + 0x49, + 0xB6, + 0xC8, + 0x37, + 0x16, + 0xE9, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0xCA, + 0x35, + 0x8F, + 0x70, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0xFF, + ] + - platform: template + name: Haier + on_press: + remote_transmitter.transmit_haier: + code: + [ + 0xA6, + 0xDA, + 0x00, + 0x00, + 0x40, + 0x40, + 0x00, + 0x80, + 0x00, + 0x00, + 0x00, + 0x00, + 0x05, + ] diff --git a/tests/components/remote_transmitter/esp32-common.yaml b/tests/components/remote_transmitter/esp32-common.yaml new file mode 100644 index 0000000000..3f3cd3f8c7 --- /dev/null +++ b/tests/components/remote_transmitter/esp32-common.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + id: rcvr + pin: ${pin} + rmt_channel: ${rmt_channel} + carrier_duty_percent: 50% + +packages: + buttons: !include common-buttons.yaml diff --git a/tests/components/remote_transmitter/test.esp32-c3-idf.yaml b/tests/components/remote_transmitter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3e2dc88e5a --- /dev/null +++ b/tests/components/remote_transmitter/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "1" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_transmitter/test.esp32-c3.yaml b/tests/components/remote_transmitter/test.esp32-c3.yaml new file mode 100644 index 0000000000..3e2dc88e5a --- /dev/null +++ b/tests/components/remote_transmitter/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "1" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_transmitter/test.esp32-idf.yaml b/tests/components/remote_transmitter/test.esp32-idf.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_transmitter/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_transmitter/test.esp32-s3-idf.yaml b/tests/components/remote_transmitter/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..31851dc54c --- /dev/null +++ b/tests/components/remote_transmitter/test.esp32-s3-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO38 + rmt_channel: "3" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_transmitter/test.esp32.yaml b/tests/components/remote_transmitter/test.esp32.yaml new file mode 100644 index 0000000000..16d276958a --- /dev/null +++ b/tests/components/remote_transmitter/test.esp32.yaml @@ -0,0 +1,6 @@ +substitutions: + pin: GPIO2 + rmt_channel: "2" + +packages: + common: !include esp32-common.yaml diff --git a/tests/components/remote_transmitter/test.esp8266.yaml b/tests/components/remote_transmitter/test.esp8266.yaml new file mode 100644 index 0000000000..de494485f4 --- /dev/null +++ b/tests/components/remote_transmitter/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + id: trns + pin: GPIO5 + carrier_duty_percent: 50% + +packages: + buttons: !include common-buttons.yaml From 12aa2722349fd494b5d0e8063d57c77bb46186d1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 9 Apr 2024 15:51:54 +1200 Subject: [PATCH 1511/2607] Rework tlc5947 to remove AUTO_LOAD (#6503) --- esphome/components/tlc5947/__init__.py | 1 - .../tlc5947/{output.py => output/__init__.py} | 13 ++++---- .../tlc5947/output/tlc5947_output.cpp | 12 ++++++++ .../tlc5947/output/tlc5947_output.h | 22 ++++++++++++++ esphome/components/tlc5947/tlc5947.cpp | 9 ++++++ esphome/components/tlc5947/tlc5947.h | 30 ++----------------- tests/components/tlc5947/common.yaml | 13 ++++++++ .../components/tlc5947/test.esp32-c3-idf.yaml | 7 +++++ tests/components/tlc5947/test.esp32-c3.yaml | 7 +++++ tests/components/tlc5947/test.esp32-idf.yaml | 7 +++++ tests/components/tlc5947/test.esp32.yaml | 7 +++++ tests/components/tlc5947/test.esp8266.yaml | 7 +++++ tests/components/tlc5947/test.rp2040.yaml | 7 +++++ 13 files changed, 107 insertions(+), 35 deletions(-) rename esphome/components/tlc5947/{output.py => output/__init__.py} (69%) create mode 100644 esphome/components/tlc5947/output/tlc5947_output.cpp create mode 100644 esphome/components/tlc5947/output/tlc5947_output.h create mode 100644 tests/components/tlc5947/common.yaml create mode 100644 tests/components/tlc5947/test.esp32-c3-idf.yaml create mode 100644 tests/components/tlc5947/test.esp32-c3.yaml create mode 100644 tests/components/tlc5947/test.esp32-idf.yaml create mode 100644 tests/components/tlc5947/test.esp32.yaml create mode 100644 tests/components/tlc5947/test.esp8266.yaml create mode 100644 tests/components/tlc5947/test.rp2040.yaml diff --git a/esphome/components/tlc5947/__init__.py b/esphome/components/tlc5947/__init__.py index 84380bdace..8a4bd5e0ce 100644 --- a/esphome/components/tlc5947/__init__.py +++ b/esphome/components/tlc5947/__init__.py @@ -14,7 +14,6 @@ from esphome.const import ( CONF_LAT_PIN = "lat_pin" CONF_OE_PIN = "oe_pin" -AUTO_LOAD = ["output"] CODEOWNERS = ["@rnauber"] tlc5947_ns = cg.esphome_ns.namespace("tlc5947") diff --git a/esphome/components/tlc5947/output.py b/esphome/components/tlc5947/output/__init__.py similarity index 69% rename from esphome/components/tlc5947/output.py rename to esphome/components/tlc5947/output/__init__.py index ece47fa63d..1b5dff1854 100644 --- a/esphome/components/tlc5947/output.py +++ b/esphome/components/tlc5947/output/__init__.py @@ -2,18 +2,19 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import output from esphome.const import CONF_CHANNEL, CONF_ID -from . import TLC5947 +from .. import TLC5947, tlc5947_ns DEPENDENCIES = ["tlc5947"] -CODEOWNERS = ["@rnauber"] -Channel = TLC5947.class_("Channel", output.FloatOutput) +TLC5947Channel = tlc5947_ns.class_( + "TLC5947Channel", output.FloatOutput, cg.Parented.template(TLC5947) +) CONF_TLC5947_ID = "tlc5947_id" CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( { cv.GenerateID(CONF_TLC5947_ID): cv.use_id(TLC5947), - cv.Required(CONF_ID): cv.declare_id(Channel), + cv.Required(CONF_ID): cv.declare_id(TLC5947Channel), cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=65535), } ).extend(cv.COMPONENT_SCHEMA) @@ -22,7 +23,5 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) - - parent = await cg.get_variable(config[CONF_TLC5947_ID]) - cg.add(var.set_parent(parent)) + await cg.register_parented(var, config[CONF_TLC5947_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/tlc5947/output/tlc5947_output.cpp b/esphome/components/tlc5947/output/tlc5947_output.cpp new file mode 100644 index 0000000000..9630fb8c1e --- /dev/null +++ b/esphome/components/tlc5947/output/tlc5947_output.cpp @@ -0,0 +1,12 @@ +#include "tlc5947_output.h" + +namespace esphome { +namespace tlc5947 { + +void TLC5947Channel::write_state(float state) { + auto amount = static_cast(state * 0xfff); + this->parent_->set_channel_value(this->channel_, amount); +} + +} // namespace tlc5947 +} // namespace esphome diff --git a/esphome/components/tlc5947/output/tlc5947_output.h b/esphome/components/tlc5947/output/tlc5947_output.h new file mode 100644 index 0000000000..5b2c51020c --- /dev/null +++ b/esphome/components/tlc5947/output/tlc5947_output.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/helpers.h" + +#include "esphome/components/output/float_output.h" + +#include "../tlc5947.h" + +namespace esphome { +namespace tlc5947 { + +class TLC5947Channel : public output::FloatOutput, public Parented { + public: + void set_channel(uint8_t channel) { this->channel_ = channel; } + + protected: + void write_state(float state) override; + uint8_t channel_; +}; + +} // namespace tlc5947 +} // namespace esphome diff --git a/esphome/components/tlc5947/tlc5947.cpp b/esphome/components/tlc5947/tlc5947.cpp index 8f3f60f087..5a5c0c17c0 100644 --- a/esphome/components/tlc5947/tlc5947.cpp +++ b/esphome/components/tlc5947/tlc5947.cpp @@ -60,5 +60,14 @@ void TLC5947::loop() { this->update_ = false; } +void TLC5947::set_channel_value(uint16_t channel, uint16_t value) { + if (channel >= this->num_chips_ * N_CHANNELS_PER_CHIP) + return; + if (this->pwm_amounts_[channel] != value) { + this->update_ = true; + } + this->pwm_amounts_[channel] = value; +} + } // namespace tlc5947 } // namespace esphome diff --git a/esphome/components/tlc5947/tlc5947.h b/esphome/components/tlc5947/tlc5947.h index 0eb7f10604..95d76408c9 100644 --- a/esphome/components/tlc5947/tlc5947.h +++ b/esphome/components/tlc5947/tlc5947.h @@ -2,18 +2,16 @@ // TLC5947 24-Channel, 12-Bit PWM LED Driver // https://www.ti.com/lit/ds/symlink/tlc5947.pdf +#include +#include "esphome/components/output/float_output.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" -#include "esphome/components/output/float_output.h" -#include namespace esphome { namespace tlc5947 { class TLC5947 : public Component { public: - class Channel; - const uint8_t N_CHANNELS_PER_CHIP = 24; void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; } @@ -31,31 +29,9 @@ class TLC5947 : public Component { /// Send new values if they were updated. void loop() override; - class Channel : public output::FloatOutput { - public: - void set_parent(TLC5947 *parent) { parent_ = parent; } - void set_channel(uint8_t channel) { channel_ = channel; } - - protected: - void write_state(float state) override { - auto amount = static_cast(state * 0xfff); - this->parent_->set_channel_value_(this->channel_, amount); - } - - TLC5947 *parent_; - uint8_t channel_; - }; + void set_channel_value(uint16_t channel, uint16_t value); protected: - void set_channel_value_(uint16_t channel, uint16_t value) { - if (channel >= this->num_chips_ * N_CHANNELS_PER_CHIP) - return; - if (this->pwm_amounts_[channel] != value) { - this->update_ = true; - } - this->pwm_amounts_[channel] = value; - } - GPIOPin *data_pin_; GPIOPin *clock_pin_; GPIOPin *lat_pin_; diff --git a/tests/components/tlc5947/common.yaml b/tests/components/tlc5947/common.yaml new file mode 100644 index 0000000000..89588f3c76 --- /dev/null +++ b/tests/components/tlc5947/common.yaml @@ -0,0 +1,13 @@ +tlc5947: + clock_pin: ${clock_pin} + data_pin: ${data_pin} + lat_pin: ${lat_pin} + +output: + - platform: tlc5947 + id: output_1 + channel: 0 + max_power: 0.8 + - platform: tlc5947 + id: output_2 + channel: 1 diff --git a/tests/components/tlc5947/test.esp32-c3-idf.yaml b/tests/components/tlc5947/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4694c43642 --- /dev/null +++ b/tests/components/tlc5947/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + lat_pin: GPIO3 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5947/test.esp32-c3.yaml b/tests/components/tlc5947/test.esp32-c3.yaml new file mode 100644 index 0000000000..4694c43642 --- /dev/null +++ b/tests/components/tlc5947/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + lat_pin: GPIO3 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5947/test.esp32-idf.yaml b/tests/components/tlc5947/test.esp32-idf.yaml new file mode 100644 index 0000000000..52411bc1e9 --- /dev/null +++ b/tests/components/tlc5947/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO15 + data_pin: GPIO14 + lat_pin: GPIO13 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5947/test.esp32.yaml b/tests/components/tlc5947/test.esp32.yaml new file mode 100644 index 0000000000..52411bc1e9 --- /dev/null +++ b/tests/components/tlc5947/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO15 + data_pin: GPIO14 + lat_pin: GPIO13 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5947/test.esp8266.yaml b/tests/components/tlc5947/test.esp8266.yaml new file mode 100644 index 0000000000..44da5a07b3 --- /dev/null +++ b/tests/components/tlc5947/test.esp8266.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + lat_pin: GPIO13 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5947/test.rp2040.yaml b/tests/components/tlc5947/test.rp2040.yaml new file mode 100644 index 0000000000..4694c43642 --- /dev/null +++ b/tests/components/tlc5947/test.rp2040.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + lat_pin: GPIO3 + +packages: + common: !include common.yaml From 0ba4e8c0bac001a2c59a2e209cc2904ae1d8b7e8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:55:20 +1200 Subject: [PATCH 1512/2607] UART: ignore require_tx/rx if not a native uart implementation (#6504) --- esphome/components/uart/__init__.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index 9005422ce6..82bc6caaa4 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -46,6 +46,14 @@ LibreTinyUARTComponent = uart_ns.class_( "LibreTinyUARTComponent", UARTComponent, cg.Component ) +NATIVE_UART_CLASSES = ( + str(IDFUARTComponent), + str(ESP32ArduinoUARTComponent), + str(ESP8266UartComponent), + str(RP2040UartComponent), + str(LibreTinyUARTComponent), +) + UARTDevice = uart_ns.class_("UARTDevice") UARTWriteAction = uart_ns.class_("UARTWriteAction", automation.Action) UARTDebugger = uart_ns.class_("UARTDebugger", cg.Component, automation.Action) @@ -299,17 +307,18 @@ def final_validate_device_schema( def validate_hub(hub_config): hub_schema = {} uart_id = hub_config[CONF_ID] + uart_id_type_str = str(uart_id.type) devices = fv.full_config.get().data.setdefault(KEY_UART_DEVICES, {}) device = devices.setdefault(uart_id, {}) - if require_tx: + if require_tx and uart_id_type_str in NATIVE_UART_CLASSES: hub_schema[ cv.Required( CONF_TX_PIN, msg=f"Component {name} requires this uart bus to declare a tx_pin", ) ] = validate_pin(CONF_TX_PIN, device) - if require_rx: + if require_rx and uart_id_type_str in NATIVE_UART_CLASSES: hub_schema[ cv.Required( CONF_RX_PIN, From 857b8ef363e93b5755533f400406d490526ca6dc Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:14:56 +0000 Subject: [PATCH 1513/2607] esp32_rmt_led_strip bugfixes (#6506) --- esphome/components/esp32_rmt_led_strip/led_strip.h | 2 +- esphome/components/esp32_rmt_led_strip/light.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index 51eed8e01c..e9b19c9399 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -64,7 +64,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { protected: light::ESPColorView get_view_internal(int32_t index) const override; - size_t get_buffer_size_() const { return this->num_leds_ * (3 + this->is_rgbw_); } + size_t get_buffer_size_() const { return this->num_leds_ * (this->is_rgbw_ || this->is_wrgb_ ? 4 : 3); } uint8_t *buf_{nullptr}; uint8_t *effect_data_{nullptr}; diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 3442940e3f..1c15a468d9 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -48,7 +48,7 @@ CHIPSETS = { "WS2812": LEDStripTimings(400, 1000, 1000, 400), "SK6812": LEDStripTimings(300, 900, 600, 600), "APA106": LEDStripTimings(350, 1360, 1360, 350), - "SM16703": LEDStripTimings(300, 900, 1360, 350), + "SM16703": LEDStripTimings(300, 900, 900, 300), } From 3adfed3675b3515f74ca9f8147c28092d69bda3d Mon Sep 17 00:00:00 2001 From: IJssel Date: Tue, 9 Apr 2024 22:03:18 +0200 Subject: [PATCH 1514/2607] Implemented support for the TLC5971 as an output component (#6494) --- CODEOWNERS | 1 + esphome/components/tlc5971/__init__.py | 40 +++++++ esphome/components/tlc5971/output/__init__.py | 27 +++++ .../tlc5971/output/tlc5971_output.cpp | 12 +++ .../tlc5971/output/tlc5971_output.h | 22 ++++ esphome/components/tlc5971/tlc5971.cpp | 101 ++++++++++++++++++ esphome/components/tlc5971/tlc5971.h | 43 ++++++++ tests/components/tlc5971/common.yaml | 12 +++ .../components/tlc5971/test.esp32-c3-idf.yaml | 6 ++ tests/components/tlc5971/test.esp32-c3.yaml | 6 ++ tests/components/tlc5971/test.esp32-idf.yaml | 6 ++ tests/components/tlc5971/test.esp32-s2.yaml | 6 ++ tests/components/tlc5971/test.esp32.yaml | 7 ++ tests/components/tlc5971/test.esp8266.yaml | 7 ++ tests/components/tlc5971/test.rp2040.yaml | 7 ++ 15 files changed, 303 insertions(+) create mode 100644 esphome/components/tlc5971/__init__.py create mode 100644 esphome/components/tlc5971/output/__init__.py create mode 100644 esphome/components/tlc5971/output/tlc5971_output.cpp create mode 100644 esphome/components/tlc5971/output/tlc5971_output.h create mode 100644 esphome/components/tlc5971/tlc5971.cpp create mode 100644 esphome/components/tlc5971/tlc5971.h create mode 100644 tests/components/tlc5971/common.yaml create mode 100644 tests/components/tlc5971/test.esp32-c3-idf.yaml create mode 100644 tests/components/tlc5971/test.esp32-c3.yaml create mode 100644 tests/components/tlc5971/test.esp32-idf.yaml create mode 100644 tests/components/tlc5971/test.esp32-s2.yaml create mode 100644 tests/components/tlc5971/test.esp32.yaml create mode 100644 tests/components/tlc5971/test.esp8266.yaml create mode 100644 tests/components/tlc5971/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 126513943f..9f770d4efc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -364,6 +364,7 @@ esphome/components/text/* @mauritskorse esphome/components/thermostat/* @kbx81 esphome/components/time/* @OttoWinter esphome/components/tlc5947/* @rnauber +esphome/components/tlc5971/* @IJIJI esphome/components/tm1621/* @Philippe12 esphome/components/tm1637/* @glmnet esphome/components/tm1638/* @skykingjwc diff --git a/esphome/components/tlc5971/__init__.py b/esphome/components/tlc5971/__init__.py new file mode 100644 index 0000000000..0ff2a5d176 --- /dev/null +++ b/esphome/components/tlc5971/__init__.py @@ -0,0 +1,40 @@ +# this component is for the "TLC5971 12-Channel, 12-Bit PWM LED Driver" [https://www.ti.com/lit/ds/symlink/tlc5971.pdf], +# which is used e.g. on [https://www.adafruit.com/product/1455]. The code is based on the TLC5947 component by @rnauber. + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.const import ( + CONF_CLOCK_PIN, + CONF_DATA_PIN, + CONF_ID, + CONF_NUM_CHIPS, +) + + +CODEOWNERS = ["@IJIJI"] + +tlc5971_ns = cg.esphome_ns.namespace("tlc5971") +TLC5971 = tlc5971_ns.class_("TLC5971", cg.Component) + +MULTI_CONF = True +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(TLC5971), + cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=85), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + data = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) + cg.add(var.set_data_pin(data)) + clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + cg.add(var.set_clock_pin(clock)) + + cg.add(var.set_num_chips(config[CONF_NUM_CHIPS])) diff --git a/esphome/components/tlc5971/output/__init__.py b/esphome/components/tlc5971/output/__init__.py new file mode 100644 index 0000000000..9fe7b18294 --- /dev/null +++ b/esphome/components/tlc5971/output/__init__.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import output +from esphome.const import CONF_CHANNEL, CONF_ID +from .. import TLC5971, tlc5971_ns + +DEPENDENCIES = ["tlc5971"] + +TLC5971Channel = tlc5971_ns.class_( + "TLC5971Channel", output.FloatOutput, cg.Parented.template(TLC5971) +) + +CONF_TLC5971_ID = "tlc5971_id" +CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( + { + cv.GenerateID(CONF_TLC5971_ID): cv.use_id(TLC5971), + cv.Required(CONF_ID): cv.declare_id(TLC5971Channel), + cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=65535), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await output.register_output(var, config) + await cg.register_parented(var, config[CONF_TLC5971_ID]) + cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/tlc5971/output/tlc5971_output.cpp b/esphome/components/tlc5971/output/tlc5971_output.cpp new file mode 100644 index 0000000000..b437889072 --- /dev/null +++ b/esphome/components/tlc5971/output/tlc5971_output.cpp @@ -0,0 +1,12 @@ +#include "tlc5971_output.h" + +namespace esphome { +namespace tlc5971 { + +void TLC5971Channel::write_state(float state) { + auto amount = static_cast(state * 0xffff); + this->parent_->set_channel_value(this->channel_, amount); +} + +} // namespace tlc5971 +} // namespace esphome diff --git a/esphome/components/tlc5971/output/tlc5971_output.h b/esphome/components/tlc5971/output/tlc5971_output.h new file mode 100644 index 0000000000..944ee19b2d --- /dev/null +++ b/esphome/components/tlc5971/output/tlc5971_output.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/helpers.h" + +#include "esphome/components/output/float_output.h" + +#include "../tlc5971.h" + +namespace esphome { +namespace tlc5971 { + +class TLC5971Channel : public output::FloatOutput, public Parented { + public: + void set_channel(uint8_t channel) { this->channel_ = channel; } + + protected: + void write_state(float state) override; + uint8_t channel_; +}; + +} // namespace tlc5971 +} // namespace esphome diff --git a/esphome/components/tlc5971/tlc5971.cpp b/esphome/components/tlc5971/tlc5971.cpp new file mode 100644 index 0000000000..ebcc3af361 --- /dev/null +++ b/esphome/components/tlc5971/tlc5971.cpp @@ -0,0 +1,101 @@ +#include "tlc5971.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace tlc5971 { + +static const char *const TAG = "tlc5971"; + +void TLC5971::setup() { + this->data_pin_->setup(); + this->data_pin_->digital_write(true); + this->clock_pin_->setup(); + this->clock_pin_->digital_write(true); + + this->pwm_amounts_.resize(this->num_chips_ * N_CHANNELS_PER_CHIP, 0); + + ESP_LOGCONFIG(TAG, "Done setting up TLC5971 output component."); +} +void TLC5971::dump_config() { + ESP_LOGCONFIG(TAG, "TLC5971:"); + LOG_PIN(" Data Pin: ", this->data_pin_); + LOG_PIN(" Clock Pin: ", this->clock_pin_); + ESP_LOGCONFIG(TAG, " Number of chips: %u", this->num_chips_); +} + +void TLC5971::loop() { + if (!this->update_) + return; + + uint32_t command; + + // Magic word for write + command = 0x25; + + command <<= 5; + // OUTTMG = 1, EXTGCK = 0, TMGRST = 1, DSPRPT = 1, BLANK = 0 -> 0x16 + command |= 0x16; + + command <<= 7; + command |= 0x7F; // default 100% brigthness + + command <<= 7; + command |= 0x7F; // default 100% brigthness + + command <<= 7; + command |= 0x7F; // default 100% brigthness + + for (uint8_t n = 0; n < num_chips_; n++) { + this->transfer_(command >> 24); + this->transfer_(command >> 16); + this->transfer_(command >> 8); + this->transfer_(command); + + // 12 channels per TLC59711 + for (int8_t c = 11; c >= 0; c--) { + // 16 bits per channel, send MSB first + this->transfer_(pwm_amounts_.at(n * 12 + c) >> 8); + this->transfer_(pwm_amounts_.at(n * 12 + c)); + } + } + + this->update_ = false; +} + +void TLC5971::transfer_(uint8_t send) { + uint8_t startbit = 0x80; + + bool towrite, lastmosi = !(send & startbit); + uint8_t bitdelay_us = (1000000 / 1000000) / 2; + + for (uint8_t b = startbit; b != 0; b = b >> 1) { + if (bitdelay_us) { + delayMicroseconds(bitdelay_us); + } + + towrite = send & b; + if ((lastmosi != towrite)) { + this->data_pin_->digital_write(towrite); + lastmosi = towrite; + } + + this->clock_pin_->digital_write(true); + + if (bitdelay_us) { + delayMicroseconds(bitdelay_us); + } + + this->clock_pin_->digital_write(false); + } +} +void TLC5971::set_channel_value(uint16_t channel, uint16_t value) { + if (channel >= this->num_chips_ * N_CHANNELS_PER_CHIP) + return; + if (this->pwm_amounts_[channel] != value) { + this->update_ = true; + } + this->pwm_amounts_[channel] = value; +} + +} // namespace tlc5971 +} // namespace esphome diff --git a/esphome/components/tlc5971/tlc5971.h b/esphome/components/tlc5971/tlc5971.h new file mode 100644 index 0000000000..6b0daf10d1 --- /dev/null +++ b/esphome/components/tlc5971/tlc5971.h @@ -0,0 +1,43 @@ +#pragma once +// TLC5971 12-Channel, 16-Bit PWM LED Driver +// https://www.ti.com/lit/ds/symlink/tlc5971.pdf + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/output/float_output.h" +#include + +namespace esphome { +namespace tlc5971 { + +class TLC5971 : public Component { + public: + const uint8_t N_CHANNELS_PER_CHIP = 12; + + void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; } + void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; } + void set_num_chips(uint8_t num_chips) { num_chips_ = num_chips; } + + void setup() override; + + void dump_config() override; + + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + /// Send new values if they were updated. + void loop() override; + + void set_channel_value(uint16_t channel, uint16_t value); + + protected: + void transfer_(uint8_t send); + + GPIOPin *data_pin_; + GPIOPin *clock_pin_; + uint8_t num_chips_; + + std::vector pwm_amounts_; + bool update_{true}; +}; +} // namespace tlc5971 +} // namespace esphome diff --git a/tests/components/tlc5971/common.yaml b/tests/components/tlc5971/common.yaml new file mode 100644 index 0000000000..fe7fe25f0e --- /dev/null +++ b/tests/components/tlc5971/common.yaml @@ -0,0 +1,12 @@ +tlc5971: + clock_pin: ${clock_pin} + data_pin: ${data_pin} + +output: + - platform: tlc5971 + id: output_1 + channel: 0 + max_power: 0.8 + - platform: tlc5971 + id: output_2 + channel: 1 diff --git a/tests/components/tlc5971/test.esp32-c3-idf.yaml b/tests/components/tlc5971/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d898a21d46 --- /dev/null +++ b/tests/components/tlc5971/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.esp32-c3.yaml b/tests/components/tlc5971/test.esp32-c3.yaml new file mode 100644 index 0000000000..d898a21d46 --- /dev/null +++ b/tests/components/tlc5971/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.esp32-idf.yaml b/tests/components/tlc5971/test.esp32-idf.yaml new file mode 100644 index 0000000000..e8943a572a --- /dev/null +++ b/tests/components/tlc5971/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + clock_pin: GPIO15 + data_pin: GPIO14 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.esp32-s2.yaml b/tests/components/tlc5971/test.esp32-s2.yaml new file mode 100644 index 0000000000..7bba0b0117 --- /dev/null +++ b/tests/components/tlc5971/test.esp32-s2.yaml @@ -0,0 +1,6 @@ +substitutions: + clock_pin: GPIO36 + data_pin: GPIO35 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.esp32.yaml b/tests/components/tlc5971/test.esp32.yaml new file mode 100644 index 0000000000..52411bc1e9 --- /dev/null +++ b/tests/components/tlc5971/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO15 + data_pin: GPIO14 + lat_pin: GPIO13 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.esp8266.yaml b/tests/components/tlc5971/test.esp8266.yaml new file mode 100644 index 0000000000..52411bc1e9 --- /dev/null +++ b/tests/components/tlc5971/test.esp8266.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO15 + data_pin: GPIO14 + lat_pin: GPIO13 + +packages: + common: !include common.yaml diff --git a/tests/components/tlc5971/test.rp2040.yaml b/tests/components/tlc5971/test.rp2040.yaml new file mode 100644 index 0000000000..4694c43642 --- /dev/null +++ b/tests/components/tlc5971/test.rp2040.yaml @@ -0,0 +1,7 @@ +substitutions: + clock_pin: GPIO5 + data_pin: GPIO4 + lat_pin: GPIO3 + +packages: + common: !include common.yaml From 522b43bb41d8ef37bc6492ee895980d921db239d Mon Sep 17 00:00:00 2001 From: bukureckid Date: Tue, 9 Apr 2024 23:04:35 +0200 Subject: [PATCH 1515/2607] Add Dooya protocol to remote_base (#6488) --- esphome/components/remote_base/__init__.py | 54 ++++++++ .../components/remote_base/dooya_protocol.cpp | 120 ++++++++++++++++++ .../components/remote_base/dooya_protocol.h | 49 +++++++ .../xiaomi_rtcgq02lm/binary_sensor.py | 3 +- esphome/const.py | 3 + 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 esphome/components/remote_base/dooya_protocol.cpp create mode 100644 esphome/components/remote_base/dooya_protocol.h diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index c771f406d8..6deab63c60 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -33,6 +33,9 @@ from esphome.const import ( CONF_WAND_ID, CONF_LEVEL, CONF_DELTA, + CONF_ID, + CONF_BUTTON, + CONF_CHECK, ) from esphome.core import coroutine from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -512,6 +515,57 @@ async def dish_action(var, config, args): cg.add(var.set_command(template_)) +# Dooya +DooyaData, DooyaBinarySensor, DooyaTrigger, DooyaAction, DooyaDumper = declare_protocol( + "Dooya" +) +DOOYA_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.hex_int_range(0, 16777215), + cv.Required(CONF_CHANNEL): cv.hex_int_range(0, 255), + cv.Required(CONF_BUTTON): cv.hex_int_range(0, 15), + cv.Required(CONF_CHECK): cv.hex_int_range(0, 15), + } +) + + +@register_binary_sensor("dooya", DooyaBinarySensor, DOOYA_SCHEMA) +def dooya_binary_sensor(var, config): + cg.add( + var.set_data( + cg.StructInitializer( + DooyaData, + ("id", config[CONF_ID]), + ("channel", config[CONF_CHANNEL]), + ("button", config[CONF_BUTTON]), + ("check", config[CONF_CHECK]), + ) + ) + ) + + +@register_trigger("dooya", DooyaTrigger, DooyaData) +def dooya_trigger(var, config): + pass + + +@register_dumper("dooya", DooyaDumper) +def dooya_dumper(var, config): + pass + + +@register_action("dooya", DooyaAction, DOOYA_SCHEMA) +async def dooya_action(var, config, args): + template_ = await cg.templatable(config[CONF_ID], args, cg.uint32) + cg.add(var.set_id(template_)) + template_ = await cg.templatable(config[CONF_CHANNEL], args, cg.uint8) + cg.add(var.set_channel(template_)) + template_ = await cg.templatable(config[CONF_BUTTON], args, cg.uint8) + cg.add(var.set_button(template_)) + template_ = await cg.templatable(config[CONF_CHECK], args, cg.uint8) + cg.add(var.set_check(template_)) + + # JVC JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol("JVC") JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t}) diff --git a/esphome/components/remote_base/dooya_protocol.cpp b/esphome/components/remote_base/dooya_protocol.cpp new file mode 100644 index 0000000000..d979bca8c5 --- /dev/null +++ b/esphome/components/remote_base/dooya_protocol.cpp @@ -0,0 +1,120 @@ +#include "dooya_protocol.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace remote_base { + +static const char *const TAG = "remote.dooya"; + +static const uint32_t HEADER_HIGH_US = 5000; +static const uint32_t HEADER_LOW_US = 1500; +static const uint32_t BIT_ZERO_HIGH_US = 750; +static const uint32_t BIT_ZERO_LOW_US = 350; +static const uint32_t BIT_ONE_HIGH_US = 350; +static const uint32_t BIT_ONE_LOW_US = 750; + +void DooyaProtocol::encode(RemoteTransmitData *dst, const DooyaData &data) { + dst->set_carrier_frequency(0); + dst->reserve(2 + 40 * 2u); + + dst->item(HEADER_HIGH_US, HEADER_LOW_US); + + for (uint32_t mask = 1UL << (23); mask != 0; mask >>= 1) { + if (data.id & mask) { + dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US); + } else { + dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US); + } + } + + for (uint32_t mask = 1UL << (7); mask != 0; mask >>= 1) { + if (data.channel & mask) { + dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US); + } else { + dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US); + } + } + + for (uint32_t mask = 1UL << (3); mask != 0; mask >>= 1) { + if (data.button & mask) { + dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US); + } else { + dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US); + } + } + + for (uint32_t mask = 1UL << (3); mask != 0; mask >>= 1) { + if (data.check & mask) { + dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US); + } else { + dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US); + } + } +} +optional DooyaProtocol::decode(RemoteReceiveData src) { + DooyaData out{ + .id = 0, + .channel = 0, + .button = 0, + .check = 0, + }; + if (!src.expect_item(HEADER_HIGH_US, HEADER_LOW_US)) + return {}; + + for (uint8_t i = 0; i < 24; i++) { + if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) { + out.id = (out.id << 1) | 1; + } else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) { + out.id = (out.id << 1) | 0; + } else { + return {}; + } + } + + for (uint8_t i = 0; i < 8; i++) { + if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) { + out.channel = (out.channel << 1) | 1; + } else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) { + out.channel = (out.channel << 1) | 0; + } else { + return {}; + } + } + + for (uint8_t i = 0; i < 4; i++) { + if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) { + out.button = (out.button << 1) | 1; + } else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) { + out.button = (out.button << 1) | 0; + } else { + return {}; + } + } + + for (uint8_t i = 0; i < 3; i++) { + if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) { + out.check = (out.check << 1) | 1; + } else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) { + out.check = (out.check << 1) | 0; + } else { + return {}; + } + } + // Last bit is not received properly but can be decoded + if (src.expect_mark(BIT_ONE_HIGH_US)) { + out.check = (out.check << 1) | 1; + } else if (src.expect_mark(BIT_ZERO_HIGH_US)) { + out.check = (out.check << 1) | 0; + } else { + return {}; + } + + return out; +} +void DooyaProtocol::dump(const DooyaData &data) { + ESP_LOGI(TAG, "Received Dooya: id=0x%08" PRIX32 ", channel=%d, button=%d, check=%d", data.id, data.channel, + data.button, data.check); +} + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/remote_base/dooya_protocol.h b/esphome/components/remote_base/dooya_protocol.h new file mode 100644 index 0000000000..9d17ad5d5e --- /dev/null +++ b/esphome/components/remote_base/dooya_protocol.h @@ -0,0 +1,49 @@ +#pragma once + +#include "esphome/core/component.h" +#include "remote_base.h" + +#include + +namespace esphome { +namespace remote_base { + +struct DooyaData { + uint32_t id; + uint8_t channel; + uint8_t button; + uint8_t check; + + bool operator==(const DooyaData &rhs) const { + return id == rhs.id && channel == rhs.channel && button == rhs.button && check == rhs.check; + } +}; + +class DooyaProtocol : public RemoteProtocol { + public: + void encode(RemoteTransmitData *dst, const DooyaData &data) override; + optional decode(RemoteReceiveData src) override; + void dump(const DooyaData &data) override; +}; + +DECLARE_REMOTE_PROTOCOL(Dooya) + +template class DooyaAction : public RemoteTransmitterActionBase { + public: + TEMPLATABLE_VALUE(uint32_t, id) + TEMPLATABLE_VALUE(uint8_t, channel) + TEMPLATABLE_VALUE(uint8_t, button) + TEMPLATABLE_VALUE(uint8_t, check) + + void encode(RemoteTransmitData *dst, Ts... x) override { + DooyaData data{}; + data.id = this->id_.value(x...); + data.channel = this->channel_.value(x...); + data.button = this->button_.value(x...); + data.check = this->check_.value(x...); + DooyaProtocol().encode(dst, data); + } +}; + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/xiaomi_rtcgq02lm/binary_sensor.py b/esphome/components/xiaomi_rtcgq02lm/binary_sensor.py index 8eee10685e..ef8a472d66 100644 --- a/esphome/components/xiaomi_rtcgq02lm/binary_sensor.py +++ b/esphome/components/xiaomi_rtcgq02lm/binary_sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_LIGHT, DEVICE_CLASS_MOTION, CONF_ID, + CONF_BUTTON, ) from esphome.core import TimePeriod @@ -15,8 +16,6 @@ from . import XiaomiRTCGQ02LM DEPENDENCIES = ["xiaomi_rtcgq02lm"] -CONF_BUTTON = "button" - CONFIG_SCHEMA = cv.Schema( { diff --git a/esphome/const.py b/esphome/const.py index 7304653363..992d148bdc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -96,6 +96,7 @@ CONF_BUFFER_SIZE = "buffer_size" CONF_BUILD_PATH = "build_path" CONF_BUS_VOLTAGE = "bus_voltage" CONF_BUSY_PIN = "busy_pin" +CONF_BUTTON = "button" CONF_BYTES = "bytes" CONF_CALCULATED_LUX = "calculated_lux" CONF_CALIBRATE_LINEAR = "calibrate_linear" @@ -110,6 +111,7 @@ CONF_CHANGE_MODE_EVERY = "change_mode_every" CONF_CHANNEL = "channel" CONF_CHANNELS = "channels" CONF_CHARACTERISTIC_UUID = "characteristic_uuid" +CONF_CHECK = "check" CONF_CHIPSET = "chipset" CONF_CLEAR_IMPEDANCE = "clear_impedance" CONF_CLIENT_CERTIFICATE = "client_certificate" @@ -220,6 +222,7 @@ CONF_DNS_ADDRESS = "dns_address" CONF_DNS1 = "dns1" CONF_DNS2 = "dns2" CONF_DOMAIN = "domain" +CONF_DOOYA = "dooya" CONF_DRY_ACTION = "dry_action" CONF_DRY_MODE = "dry_mode" CONF_DUMMY_RECEIVER = "dummy_receiver" From e5e8bc85152ae93d3531a329ab85d08752338162 Mon Sep 17 00:00:00 2001 From: leejoow Date: Wed, 10 Apr 2024 01:22:18 +0200 Subject: [PATCH 1516/2607] Only give error for connected sensors at startup (#6474) Co-authored-by: Leo Schelvis --- esphome/components/dallas/dallas_component.cpp | 18 +++++++++++++++--- esphome/components/dallas/dallas_component.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/esphome/components/dallas/dallas_component.cpp b/esphome/components/dallas/dallas_component.cpp index b1983fef72..a51bc369a1 100644 --- a/esphome/components/dallas/dallas_component.cpp +++ b/esphome/components/dallas/dallas_component.cpp @@ -60,7 +60,7 @@ void DallasComponent::setup() { for (auto *sensor : this->sensors_) { if (sensor->get_index().has_value()) { if (*sensor->get_index() >= this->found_sensors_.size()) { - this->status_set_error(); + this->status_set_error("Sensor configured by index but not found"); continue; } sensor->set_address(this->found_sensors_[*sensor->get_index()]); @@ -109,8 +109,12 @@ void DallasComponent::update() { result = this->one_wire_->reset(); } if (!result) { - ESP_LOGE(TAG, "Requesting conversion failed"); - this->status_set_warning(); + if (!this->found_sensors_.empty()) { + // Only log error if at the start sensors were found (and thus are disconnected during uptime) + ESP_LOGE(TAG, "Requesting conversion failed"); + this->status_set_warning(); + } + for (auto *sensor : this->sensors_) { sensor->publish_state(NAN); } @@ -124,6 +128,12 @@ void DallasComponent::update() { } for (auto *sensor : this->sensors_) { + if (sensor->get_address() == 0) { + ESP_LOGV(TAG, "'%s' - Indexed sensor not found at startup, skipping update", sensor->get_name().c_str()); + sensor->publish_state(NAN); + continue; + } + this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { bool res = sensor->read_scratch_pad(); @@ -152,6 +162,8 @@ void DallasTemperatureSensor::set_resolution(uint8_t resolution) { this->resolut optional DallasTemperatureSensor::get_index() const { return this->index_; } void DallasTemperatureSensor::set_index(uint8_t index) { this->index_ = index; } uint8_t *DallasTemperatureSensor::get_address8() { return reinterpret_cast(&this->address_); } +uint64_t DallasTemperatureSensor::get_address() { return this->address_; } + const std::string &DallasTemperatureSensor::get_address_name() { if (this->address_name_.empty()) { this->address_name_ = std::string("0x") + format_hex(this->address_); diff --git a/esphome/components/dallas/dallas_component.h b/esphome/components/dallas/dallas_component.h index b21bc02e54..10bde7338b 100644 --- a/esphome/components/dallas/dallas_component.h +++ b/esphome/components/dallas/dallas_component.h @@ -37,6 +37,7 @@ class DallasTemperatureSensor : public sensor::Sensor { void set_parent(DallasComponent *parent) { parent_ = parent; } /// Helper to get a pointer to the address as uint8_t. uint8_t *get_address8(); + uint64_t get_address(); /// Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29". const std::string &get_address_name(); From b4b4e81c1c443add8811c7e9dd36875ff93d71fc Mon Sep 17 00:00:00 2001 From: RFDarter Date: Wed, 10 Apr 2024 01:33:26 +0200 Subject: [PATCH 1517/2607] Webserver float to string fix (#6507) --- esphome/components/web_server/web_server.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index b48a39cbcb..2e6206b691 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -851,9 +851,12 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail return json::build_json([obj, value, start_config](JsonObject root) { set_json_id(root, obj, "number-" + obj->get_object_id(), start_config); if (start_config == DETAIL_ALL) { - root["min_value"] = obj->traits.get_min_value(); - root["max_value"] = obj->traits.get_max_value(); - root["step"] = obj->traits.get_step(); + root["min_value"] = + value_accuracy_to_string(obj->traits.get_min_value(), step_to_accuracy_decimals(obj->traits.get_step())); + root["max_value"] = + value_accuracy_to_string(obj->traits.get_max_value(), step_to_accuracy_decimals(obj->traits.get_step())); + root["step"] = + value_accuracy_to_string(obj->traits.get_step(), step_to_accuracy_decimals(obj->traits.get_step())); root["mode"] = (int) obj->traits.get_mode(); if (!obj->traits.get_unit_of_measurement().empty()) root["uom"] = obj->traits.get_unit_of_measurement(); @@ -862,7 +865,7 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail root["value"] = "\"NaN\""; root["state"] = "NA"; } else { - root["value"] = value; + root["value"] = value_accuracy_to_string(value, step_to_accuracy_decimals(obj->traits.get_step())); std::string state = value_accuracy_to_string(value, step_to_accuracy_decimals(obj->traits.get_step())); if (!obj->traits.get_unit_of_measurement().empty()) state += " " + obj->traits.get_unit_of_measurement(); From 9af083af037fab54d9973691aaf59e1069bfe040 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:49:45 +1200 Subject: [PATCH 1518/2607] Bump version to 2024.4.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 992d148bdc..5f8082c395 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0-dev" +__version__ = "2024.4.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From a102e982b380da03fe1bd566efa6d647def82c91 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:49:45 +1200 Subject: [PATCH 1519/2607] Bump version to 2024.5.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 992d148bdc..8410d36708 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0-dev" +__version__ = "2024.5.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 1e0f6e139a67313f80715196c366236aae467106 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:25:35 +1200 Subject: [PATCH 1520/2607] Add dooya remote transmitter test (#6508) --- tests/components/remote_transmitter/common-buttons.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml index 5f655acb7c..27683b387f 100644 --- a/tests/components/remote_transmitter/common-buttons.yaml +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -176,3 +176,11 @@ button: 0x00, 0x05, ] + - platform: template + name: Dooya + on_press: + remote_transmitter.transmit_dooya: + id: 0x123456 + channel: 1 + button: 1 + check: 1 From e59b81612fb5d6b6d7611269b6834afbbeeabbb4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 10 Apr 2024 03:57:22 -0500 Subject: [PATCH 1521/2607] Add some components to the new testing framework (H) (#6179) * Add some components to the new testing framework (H) * Remove C3 * Fix indentation --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../havells_solar/test.esp32-c3-idf.yaml | 79 +++++++++++++++++++ .../havells_solar/test.esp32-c3.yaml | 79 +++++++++++++++++++ .../havells_solar/test.esp32-idf.yaml | 79 +++++++++++++++++++ .../components/havells_solar/test.esp32.yaml | 79 +++++++++++++++++++ .../havells_solar/test.esp8266.yaml | 79 +++++++++++++++++++ .../components/havells_solar/test.rp2040.yaml | 79 +++++++++++++++++++ .../components/hbridge/test.esp32-c3-idf.yaml | 33 ++++++++ tests/components/hbridge/test.esp32-c3.yaml | 33 ++++++++ tests/components/hbridge/test.esp32-idf.yaml | 33 ++++++++ tests/components/hbridge/test.esp32.yaml | 33 ++++++++ tests/components/hbridge/test.esp8266.yaml | 33 ++++++++ tests/components/hbridge/test.rp2040.yaml | 33 ++++++++ .../components/hdc1080/test.esp32-c3-idf.yaml | 12 +++ tests/components/hdc1080/test.esp32-c3.yaml | 12 +++ tests/components/hdc1080/test.esp32-idf.yaml | 12 +++ tests/components/hdc1080/test.esp32.yaml | 12 +++ tests/components/hdc1080/test.esp8266.yaml | 12 +++ tests/components/hdc1080/test.rp2040.yaml | 12 +++ tests/components/he60r/test.esp32-c3-idf.yaml | 13 +++ tests/components/he60r/test.esp32-c3.yaml | 13 +++ tests/components/he60r/test.esp32-idf.yaml | 13 +++ tests/components/he60r/test.esp32.yaml | 13 +++ tests/components/he60r/test.esp8266.yaml | 13 +++ tests/components/he60r/test.rp2040.yaml | 13 +++ tests/components/heatpumpir/test.esp32.yaml | 19 +++++ tests/components/heatpumpir/test.esp8266.yaml | 19 +++++ .../hitachi_ac344/test.esp32-c3-idf.yaml | 7 ++ .../hitachi_ac344/test.esp32-c3.yaml | 7 ++ .../hitachi_ac344/test.esp32-idf.yaml | 7 ++ .../components/hitachi_ac344/test.esp32.yaml | 7 ++ .../hitachi_ac344/test.esp8266.yaml | 7 ++ .../hitachi_ac424/test.esp32-c3-idf.yaml | 7 ++ .../hitachi_ac424/test.esp32-c3.yaml | 7 ++ .../hitachi_ac424/test.esp32-idf.yaml | 7 ++ .../components/hitachi_ac424/test.esp32.yaml | 7 ++ .../hitachi_ac424/test.esp8266.yaml | 7 ++ .../components/hlw8012/test.esp32-c3-idf.yaml | 21 +++++ tests/components/hlw8012/test.esp32-c3.yaml | 21 +++++ tests/components/hlw8012/test.esp32-idf.yaml | 21 +++++ tests/components/hlw8012/test.esp32.yaml | 21 +++++ tests/components/hlw8012/test.esp8266.yaml | 21 +++++ tests/components/hlw8012/test.rp2040.yaml | 21 +++++ .../components/hm3301/test.esp32-c3-idf.yaml | 16 ++++ tests/components/hm3301/test.esp32-c3.yaml | 16 ++++ tests/components/hm3301/test.esp32-idf.yaml | 16 ++++ tests/components/hm3301/test.esp32.yaml | 16 ++++ tests/components/hm3301/test.esp8266.yaml | 16 ++++ tests/components/hm3301/test.rp2040.yaml | 16 ++++ .../hmc5883l/test.esp32-c3-idf.yaml | 19 +++++ tests/components/hmc5883l/test.esp32-c3.yaml | 19 +++++ tests/components/hmc5883l/test.esp32-idf.yaml | 19 +++++ tests/components/hmc5883l/test.esp32.yaml | 19 +++++ tests/components/hmc5883l/test.esp8266.yaml | 19 +++++ tests/components/hmc5883l/test.rp2040.yaml | 19 +++++ .../homeassistant/test.esp32-c3-idf.yaml | 39 +++++++++ .../homeassistant/test.esp32-c3.yaml | 39 +++++++++ .../homeassistant/test.esp32-idf.yaml | 39 +++++++++ .../components/homeassistant/test.esp32.yaml | 39 +++++++++ .../homeassistant/test.esp8266.yaml | 39 +++++++++ .../components/homeassistant/test.rp2040.yaml | 39 +++++++++ .../honeywell_hih_i2c/test.esp32-c3-idf.yaml | 12 +++ .../honeywell_hih_i2c/test.esp32-c3.yaml | 12 +++ .../honeywell_hih_i2c/test.esp32-idf.yaml | 12 +++ .../honeywell_hih_i2c/test.esp32.yaml | 12 +++ .../honeywell_hih_i2c/test.esp8266.yaml | 12 +++ .../honeywell_hih_i2c/test.rp2040.yaml | 12 +++ .../honeywellabp/test.esp32-c3-idf.yaml | 15 ++++ .../honeywellabp/test.esp32-c3.yaml | 15 ++++ .../honeywellabp/test.esp32-idf.yaml | 15 ++++ tests/components/honeywellabp/test.esp32.yaml | 15 ++++ .../components/honeywellabp/test.esp8266.yaml | 15 ++++ .../components/honeywellabp/test.rp2040.yaml | 15 ++++ .../honeywellabp2_i2c/test.esp32-c3-idf.yaml | 15 ++++ .../honeywellabp2_i2c/test.esp32-c3.yaml | 15 ++++ .../honeywellabp2_i2c/test.esp32-idf.yaml | 15 ++++ .../honeywellabp2_i2c/test.esp32.yaml | 15 ++++ .../honeywellabp2_i2c/test.esp8266.yaml | 15 ++++ .../honeywellabp2_i2c/test.rp2040.yaml | 15 ++++ .../hrxl_maxsonar_wr/test.esp32-c3-idf.yaml | 10 +++ .../hrxl_maxsonar_wr/test.esp32-c3.yaml | 10 +++ .../hrxl_maxsonar_wr/test.esp32-idf.yaml | 10 +++ .../hrxl_maxsonar_wr/test.esp32.yaml | 10 +++ .../hrxl_maxsonar_wr/test.esp8266.yaml | 10 +++ .../hrxl_maxsonar_wr/test.rp2040.yaml | 10 +++ .../components/hte501/test.esp32-c3-idf.yaml | 12 +++ tests/components/hte501/test.esp32-c3.yaml | 12 +++ tests/components/hte501/test.esp32-idf.yaml | 12 +++ tests/components/hte501/test.esp32.yaml | 12 +++ tests/components/hte501/test.esp8266.yaml | 12 +++ tests/components/hte501/test.rp2040.yaml | 12 +++ .../http_request/test.esp32-c3.yaml | 7 ++ tests/components/http_request/test.esp32.yaml | 7 ++ .../components/http_request/test.esp8266.yaml | 7 ++ .../components/htu21d/test.esp32-c3-idf.yaml | 14 ++++ tests/components/htu21d/test.esp32-c3.yaml | 14 ++++ tests/components/htu21d/test.esp32-idf.yaml | 14 ++++ tests/components/htu21d/test.esp32.yaml | 14 ++++ tests/components/htu21d/test.esp8266.yaml | 14 ++++ tests/components/htu21d/test.rp2040.yaml | 14 ++++ tests/components/hx711/test.esp32-c3-idf.yaml | 7 ++ tests/components/hx711/test.esp32-c3.yaml | 7 ++ tests/components/hx711/test.esp32-idf.yaml | 7 ++ tests/components/hx711/test.esp32.yaml | 7 ++ tests/components/hx711/test.esp8266.yaml | 7 ++ tests/components/hx711/test.rp2040.yaml | 7 ++ .../hydreon_rgxx/test.esp32-c3-idf.yaml | 37 +++++++++ .../hydreon_rgxx/test.esp32-c3.yaml | 37 +++++++++ .../hydreon_rgxx/test.esp32-idf.yaml | 37 +++++++++ tests/components/hydreon_rgxx/test.esp32.yaml | 37 +++++++++ .../components/hydreon_rgxx/test.esp8266.yaml | 37 +++++++++ .../components/hydreon_rgxx/test.rp2040.yaml | 37 +++++++++ .../components/hyt271/test.esp32-c3-idf.yaml | 11 +++ tests/components/hyt271/test.esp32-c3.yaml | 11 +++ tests/components/hyt271/test.esp32-idf.yaml | 11 +++ tests/components/hyt271/test.esp32.yaml | 11 +++ tests/components/hyt271/test.esp8266.yaml | 11 +++ tests/components/hyt271/test.rp2040.yaml | 11 +++ 117 files changed, 2319 insertions(+) create mode 100644 tests/components/havells_solar/test.esp32-c3-idf.yaml create mode 100644 tests/components/havells_solar/test.esp32-c3.yaml create mode 100644 tests/components/havells_solar/test.esp32-idf.yaml create mode 100644 tests/components/havells_solar/test.esp32.yaml create mode 100644 tests/components/havells_solar/test.esp8266.yaml create mode 100644 tests/components/havells_solar/test.rp2040.yaml create mode 100644 tests/components/hbridge/test.esp32-c3-idf.yaml create mode 100644 tests/components/hbridge/test.esp32-c3.yaml create mode 100644 tests/components/hbridge/test.esp32-idf.yaml create mode 100644 tests/components/hbridge/test.esp32.yaml create mode 100644 tests/components/hbridge/test.esp8266.yaml create mode 100644 tests/components/hbridge/test.rp2040.yaml create mode 100644 tests/components/hdc1080/test.esp32-c3-idf.yaml create mode 100644 tests/components/hdc1080/test.esp32-c3.yaml create mode 100644 tests/components/hdc1080/test.esp32-idf.yaml create mode 100644 tests/components/hdc1080/test.esp32.yaml create mode 100644 tests/components/hdc1080/test.esp8266.yaml create mode 100644 tests/components/hdc1080/test.rp2040.yaml create mode 100644 tests/components/he60r/test.esp32-c3-idf.yaml create mode 100644 tests/components/he60r/test.esp32-c3.yaml create mode 100644 tests/components/he60r/test.esp32-idf.yaml create mode 100644 tests/components/he60r/test.esp32.yaml create mode 100644 tests/components/he60r/test.esp8266.yaml create mode 100644 tests/components/he60r/test.rp2040.yaml create mode 100644 tests/components/heatpumpir/test.esp32.yaml create mode 100644 tests/components/heatpumpir/test.esp8266.yaml create mode 100644 tests/components/hitachi_ac344/test.esp32-c3-idf.yaml create mode 100644 tests/components/hitachi_ac344/test.esp32-c3.yaml create mode 100644 tests/components/hitachi_ac344/test.esp32-idf.yaml create mode 100644 tests/components/hitachi_ac344/test.esp32.yaml create mode 100644 tests/components/hitachi_ac344/test.esp8266.yaml create mode 100644 tests/components/hitachi_ac424/test.esp32-c3-idf.yaml create mode 100644 tests/components/hitachi_ac424/test.esp32-c3.yaml create mode 100644 tests/components/hitachi_ac424/test.esp32-idf.yaml create mode 100644 tests/components/hitachi_ac424/test.esp32.yaml create mode 100644 tests/components/hitachi_ac424/test.esp8266.yaml create mode 100644 tests/components/hlw8012/test.esp32-c3-idf.yaml create mode 100644 tests/components/hlw8012/test.esp32-c3.yaml create mode 100644 tests/components/hlw8012/test.esp32-idf.yaml create mode 100644 tests/components/hlw8012/test.esp32.yaml create mode 100644 tests/components/hlw8012/test.esp8266.yaml create mode 100644 tests/components/hlw8012/test.rp2040.yaml create mode 100644 tests/components/hm3301/test.esp32-c3-idf.yaml create mode 100644 tests/components/hm3301/test.esp32-c3.yaml create mode 100644 tests/components/hm3301/test.esp32-idf.yaml create mode 100644 tests/components/hm3301/test.esp32.yaml create mode 100644 tests/components/hm3301/test.esp8266.yaml create mode 100644 tests/components/hm3301/test.rp2040.yaml create mode 100644 tests/components/hmc5883l/test.esp32-c3-idf.yaml create mode 100644 tests/components/hmc5883l/test.esp32-c3.yaml create mode 100644 tests/components/hmc5883l/test.esp32-idf.yaml create mode 100644 tests/components/hmc5883l/test.esp32.yaml create mode 100644 tests/components/hmc5883l/test.esp8266.yaml create mode 100644 tests/components/hmc5883l/test.rp2040.yaml create mode 100644 tests/components/homeassistant/test.esp32-c3-idf.yaml create mode 100644 tests/components/homeassistant/test.esp32-c3.yaml create mode 100644 tests/components/homeassistant/test.esp32-idf.yaml create mode 100644 tests/components/homeassistant/test.esp32.yaml create mode 100644 tests/components/homeassistant/test.esp8266.yaml create mode 100644 tests/components/homeassistant/test.rp2040.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.esp32-c3.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.esp32-idf.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.esp32.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.esp8266.yaml create mode 100644 tests/components/honeywell_hih_i2c/test.rp2040.yaml create mode 100644 tests/components/honeywellabp/test.esp32-c3-idf.yaml create mode 100644 tests/components/honeywellabp/test.esp32-c3.yaml create mode 100644 tests/components/honeywellabp/test.esp32-idf.yaml create mode 100644 tests/components/honeywellabp/test.esp32.yaml create mode 100644 tests/components/honeywellabp/test.esp8266.yaml create mode 100644 tests/components/honeywellabp/test.rp2040.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.esp32-c3.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.esp32-idf.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.esp32.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.esp8266.yaml create mode 100644 tests/components/honeywellabp2_i2c/test.rp2040.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.esp32-c3-idf.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.esp32-idf.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.esp32.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.esp8266.yaml create mode 100644 tests/components/hrxl_maxsonar_wr/test.rp2040.yaml create mode 100644 tests/components/hte501/test.esp32-c3-idf.yaml create mode 100644 tests/components/hte501/test.esp32-c3.yaml create mode 100644 tests/components/hte501/test.esp32-idf.yaml create mode 100644 tests/components/hte501/test.esp32.yaml create mode 100644 tests/components/hte501/test.esp8266.yaml create mode 100644 tests/components/hte501/test.rp2040.yaml create mode 100644 tests/components/http_request/test.esp32-c3.yaml create mode 100644 tests/components/http_request/test.esp32.yaml create mode 100644 tests/components/http_request/test.esp8266.yaml create mode 100644 tests/components/htu21d/test.esp32-c3-idf.yaml create mode 100644 tests/components/htu21d/test.esp32-c3.yaml create mode 100644 tests/components/htu21d/test.esp32-idf.yaml create mode 100644 tests/components/htu21d/test.esp32.yaml create mode 100644 tests/components/htu21d/test.esp8266.yaml create mode 100644 tests/components/htu21d/test.rp2040.yaml create mode 100644 tests/components/hx711/test.esp32-c3-idf.yaml create mode 100644 tests/components/hx711/test.esp32-c3.yaml create mode 100644 tests/components/hx711/test.esp32-idf.yaml create mode 100644 tests/components/hx711/test.esp32.yaml create mode 100644 tests/components/hx711/test.esp8266.yaml create mode 100644 tests/components/hx711/test.rp2040.yaml create mode 100644 tests/components/hydreon_rgxx/test.esp32-c3-idf.yaml create mode 100644 tests/components/hydreon_rgxx/test.esp32-c3.yaml create mode 100644 tests/components/hydreon_rgxx/test.esp32-idf.yaml create mode 100644 tests/components/hydreon_rgxx/test.esp32.yaml create mode 100644 tests/components/hydreon_rgxx/test.esp8266.yaml create mode 100644 tests/components/hydreon_rgxx/test.rp2040.yaml create mode 100644 tests/components/hyt271/test.esp32-c3-idf.yaml create mode 100644 tests/components/hyt271/test.esp32-c3.yaml create mode 100644 tests/components/hyt271/test.esp32-idf.yaml create mode 100644 tests/components/hyt271/test.esp32.yaml create mode 100644 tests/components/hyt271/test.esp8266.yaml create mode 100644 tests/components/hyt271/test.rp2040.yaml diff --git a/tests/components/havells_solar/test.esp32-c3-idf.yaml b/tests/components/havells_solar/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5cb911cf71 --- /dev/null +++ b/tests/components/havells_solar/test.esp32-c3-idf.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/havells_solar/test.esp32-c3.yaml b/tests/components/havells_solar/test.esp32-c3.yaml new file mode 100644 index 0000000000..5cb911cf71 --- /dev/null +++ b/tests/components/havells_solar/test.esp32-c3.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/havells_solar/test.esp32-idf.yaml b/tests/components/havells_solar/test.esp32-idf.yaml new file mode 100644 index 0000000000..2cda8e37be --- /dev/null +++ b/tests/components/havells_solar/test.esp32-idf.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/havells_solar/test.esp32.yaml b/tests/components/havells_solar/test.esp32.yaml new file mode 100644 index 0000000000..2cda8e37be --- /dev/null +++ b/tests/components/havells_solar/test.esp32.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/havells_solar/test.esp8266.yaml b/tests/components/havells_solar/test.esp8266.yaml new file mode 100644 index 0000000000..5cb911cf71 --- /dev/null +++ b/tests/components/havells_solar/test.esp8266.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/havells_solar/test.rp2040.yaml b/tests/components/havells_solar/test.rp2040.yaml new file mode 100644 index 0000000000..5cb911cf71 --- /dev/null +++ b/tests/components/havells_solar/test.rp2040.yaml @@ -0,0 +1,79 @@ +uart: + - id: uart_havells_solar + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + flow_control_pin: 3 + +sensor: + - platform: havells_solar + update_interval: 60s + phase_a: + voltage: + name: Phase A Voltage + current: + name: Phase A Current + phase_b: + voltage: + name: Voltage Phase B + current: + name: Current Phase B + phase_c: + voltage: + name: Voltage Phase C + current: + name: Current Phase C + pv1: + voltage: + name: PV1 Voltage + current: + name: PV1 Current + active_power: + name: PV1 Active Power + voltage_sampled_by_secondary_cpu: + name: PV1 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV1 Insulation Of +VE To Ground + pv2: + voltage: + name: PV2 Voltage + current: + name: PV2 Current + active_power: + name: PV2 Active Power + voltage_sampled_by_secondary_cpu: + name: PV2 Voltage Sampled By Secondary CPU + insulation_of_p_to_ground: + name: PV2 Insulation Of +VE To Ground + active_power: + name: Active Power + reactive_power: + name: Reactive Power + frequency: + name: Frequency + energy_production_day: + name: Today's Generation + total_energy_production: + name: Total Energy Production + total_generation_time: + name: Total Generation Time + today_generation_time: + name: Today Generation Time + inverter_module_temp: + name: Inverter Module Temp + inverter_inner_temp: + name: Inverter Inner Temp + inverter_bus_voltage: + name: Inverter BUS Voltage + insulation_of_pv_n_to_ground: + name: Insulation Of PV- To Ground + gfci_value: + name: GFCI Value + dci_of_r: + name: DCI Of R + dci_of_s: + name: DCI Of S + dci_of_t: + name: DCI Of T diff --git a/tests/components/hbridge/test.esp32-c3-idf.yaml b/tests/components/hbridge/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..70cfd6ab6f --- /dev/null +++ b/tests/components/hbridge/test.esp32-c3-idf.yaml @@ -0,0 +1,33 @@ +output: + - platform: ledc + pin: 4 + id: gpio_output1 + - platform: ledc + pin: 5 + id: gpio_output2 + - platform: ledc + pin: 6 + id: gpio_output3 + - platform: ledc + pin: 7 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hbridge/test.esp32-c3.yaml b/tests/components/hbridge/test.esp32-c3.yaml new file mode 100644 index 0000000000..70cfd6ab6f --- /dev/null +++ b/tests/components/hbridge/test.esp32-c3.yaml @@ -0,0 +1,33 @@ +output: + - platform: ledc + pin: 4 + id: gpio_output1 + - platform: ledc + pin: 5 + id: gpio_output2 + - platform: ledc + pin: 6 + id: gpio_output3 + - platform: ledc + pin: 7 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hbridge/test.esp32-idf.yaml b/tests/components/hbridge/test.esp32-idf.yaml new file mode 100644 index 0000000000..6a80aaaf3b --- /dev/null +++ b/tests/components/hbridge/test.esp32-idf.yaml @@ -0,0 +1,33 @@ +output: + - platform: ledc + pin: 14 + id: gpio_output1 + - platform: ledc + pin: 15 + id: gpio_output2 + - platform: ledc + pin: 12 + id: gpio_output3 + - platform: ledc + pin: 13 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hbridge/test.esp32.yaml b/tests/components/hbridge/test.esp32.yaml new file mode 100644 index 0000000000..6a80aaaf3b --- /dev/null +++ b/tests/components/hbridge/test.esp32.yaml @@ -0,0 +1,33 @@ +output: + - platform: ledc + pin: 14 + id: gpio_output1 + - platform: ledc + pin: 15 + id: gpio_output2 + - platform: ledc + pin: 12 + id: gpio_output3 + - platform: ledc + pin: 13 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hbridge/test.esp8266.yaml b/tests/components/hbridge/test.esp8266.yaml new file mode 100644 index 0000000000..4f8915879d --- /dev/null +++ b/tests/components/hbridge/test.esp8266.yaml @@ -0,0 +1,33 @@ +output: + - platform: esp8266_pwm + pin: 4 + id: gpio_output1 + - platform: esp8266_pwm + pin: 5 + id: gpio_output2 + - platform: esp8266_pwm + pin: 12 + id: gpio_output3 + - platform: esp8266_pwm + pin: 13 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hbridge/test.rp2040.yaml b/tests/components/hbridge/test.rp2040.yaml new file mode 100644 index 0000000000..e21b55091d --- /dev/null +++ b/tests/components/hbridge/test.rp2040.yaml @@ -0,0 +1,33 @@ +output: + - platform: rp2040_pwm + pin: 4 + id: gpio_output1 + - platform: rp2040_pwm + pin: 5 + id: gpio_output2 + - platform: rp2040_pwm + pin: 6 + id: gpio_output3 + - platform: rp2040_pwm + pin: 7 + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! diff --git a/tests/components/hdc1080/test.esp32-c3-idf.yaml b/tests/components/hdc1080/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7bf7af6fa7 --- /dev/null +++ b/tests/components/hdc1080/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 5 + sda: 4 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/hdc1080/test.esp32-c3.yaml b/tests/components/hdc1080/test.esp32-c3.yaml new file mode 100644 index 0000000000..7bf7af6fa7 --- /dev/null +++ b/tests/components/hdc1080/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 5 + sda: 4 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/hdc1080/test.esp32-idf.yaml b/tests/components/hdc1080/test.esp32-idf.yaml new file mode 100644 index 0000000000..8e313dfa40 --- /dev/null +++ b/tests/components/hdc1080/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 16 + sda: 17 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/hdc1080/test.esp32.yaml b/tests/components/hdc1080/test.esp32.yaml new file mode 100644 index 0000000000..8e313dfa40 --- /dev/null +++ b/tests/components/hdc1080/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 16 + sda: 17 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/hdc1080/test.esp8266.yaml b/tests/components/hdc1080/test.esp8266.yaml new file mode 100644 index 0000000000..7bf7af6fa7 --- /dev/null +++ b/tests/components/hdc1080/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 5 + sda: 4 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/hdc1080/test.rp2040.yaml b/tests/components/hdc1080/test.rp2040.yaml new file mode 100644 index 0000000000..7bf7af6fa7 --- /dev/null +++ b/tests/components/hdc1080/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hdc1080 + scl: 5 + sda: 4 + +sensor: + - platform: hdc1080 + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/he60r/test.esp32-c3-idf.yaml b/tests/components/he60r/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..bcbb544442 --- /dev/null +++ b/tests/components/he60r/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/he60r/test.esp32-c3.yaml b/tests/components/he60r/test.esp32-c3.yaml new file mode 100644 index 0000000000..bcbb544442 --- /dev/null +++ b/tests/components/he60r/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/he60r/test.esp32-idf.yaml b/tests/components/he60r/test.esp32-idf.yaml new file mode 100644 index 0000000000..840387ae36 --- /dev/null +++ b/tests/components/he60r/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 17 + rx_pin: 16 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/he60r/test.esp32.yaml b/tests/components/he60r/test.esp32.yaml new file mode 100644 index 0000000000..840387ae36 --- /dev/null +++ b/tests/components/he60r/test.esp32.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 17 + rx_pin: 16 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/he60r/test.esp8266.yaml b/tests/components/he60r/test.esp8266.yaml new file mode 100644 index 0000000000..bcbb544442 --- /dev/null +++ b/tests/components/he60r/test.esp8266.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/he60r/test.rp2040.yaml b/tests/components/he60r/test.rp2040.yaml new file mode 100644 index 0000000000..bcbb544442 --- /dev/null +++ b/tests/components/he60r/test.rp2040.yaml @@ -0,0 +1,13 @@ +uart: + - id: uart_he60r + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +cover: + - platform: he60r + id: garage_door + name: Garage Door + open_duration: 14s + close_duration: 14s diff --git a/tests/components/heatpumpir/test.esp32.yaml b/tests/components/heatpumpir/test.esp32.yaml new file mode 100644 index 0000000000..db3f81f6a0 --- /dev/null +++ b/tests/components/heatpumpir/test.esp32.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: heatpumpir + protocol: mitsubishi_heavy_zm + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 + - platform: heatpumpir + protocol: greeyt + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 diff --git a/tests/components/heatpumpir/test.esp8266.yaml b/tests/components/heatpumpir/test.esp8266.yaml new file mode 100644 index 0000000000..26a01cb198 --- /dev/null +++ b/tests/components/heatpumpir/test.esp8266.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: heatpumpir + protocol: mitsubishi_heavy_zm + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 + - platform: heatpumpir + protocol: greeyt + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 diff --git a/tests/components/hitachi_ac344/test.esp32-c3-idf.yaml b/tests/components/hitachi_ac344/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..684d5899de --- /dev/null +++ b/tests/components/hitachi_ac344/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac344 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac344/test.esp32-c3.yaml b/tests/components/hitachi_ac344/test.esp32-c3.yaml new file mode 100644 index 0000000000..684d5899de --- /dev/null +++ b/tests/components/hitachi_ac344/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac344 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac344/test.esp32-idf.yaml b/tests/components/hitachi_ac344/test.esp32-idf.yaml new file mode 100644 index 0000000000..684d5899de --- /dev/null +++ b/tests/components/hitachi_ac344/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac344 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac344/test.esp32.yaml b/tests/components/hitachi_ac344/test.esp32.yaml new file mode 100644 index 0000000000..684d5899de --- /dev/null +++ b/tests/components/hitachi_ac344/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac344 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac344/test.esp8266.yaml b/tests/components/hitachi_ac344/test.esp8266.yaml new file mode 100644 index 0000000000..e6203e3084 --- /dev/null +++ b/tests/components/hitachi_ac344/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac344 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac424/test.esp32-c3-idf.yaml b/tests/components/hitachi_ac424/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a09821b9c6 --- /dev/null +++ b/tests/components/hitachi_ac424/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac424 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac424/test.esp32-c3.yaml b/tests/components/hitachi_ac424/test.esp32-c3.yaml new file mode 100644 index 0000000000..a09821b9c6 --- /dev/null +++ b/tests/components/hitachi_ac424/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac424 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac424/test.esp32-idf.yaml b/tests/components/hitachi_ac424/test.esp32-idf.yaml new file mode 100644 index 0000000000..a09821b9c6 --- /dev/null +++ b/tests/components/hitachi_ac424/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac424 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac424/test.esp32.yaml b/tests/components/hitachi_ac424/test.esp32.yaml new file mode 100644 index 0000000000..a09821b9c6 --- /dev/null +++ b/tests/components/hitachi_ac424/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac424 + name: Hitachi Climate diff --git a/tests/components/hitachi_ac424/test.esp8266.yaml b/tests/components/hitachi_ac424/test.esp8266.yaml new file mode 100644 index 0000000000..78b9e7c98c --- /dev/null +++ b/tests/components/hitachi_ac424/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: hitachi_ac424 + name: Hitachi Climate diff --git a/tests/components/hlw8012/test.esp32-c3-idf.yaml b/tests/components/hlw8012/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..da6053a1b9 --- /dev/null +++ b/tests/components/hlw8012/test.esp32-c3-idf.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 2 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hlw8012/test.esp32-c3.yaml b/tests/components/hlw8012/test.esp32-c3.yaml new file mode 100644 index 0000000000..da6053a1b9 --- /dev/null +++ b/tests/components/hlw8012/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 2 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hlw8012/test.esp32-idf.yaml b/tests/components/hlw8012/test.esp32-idf.yaml new file mode 100644 index 0000000000..5b2d865722 --- /dev/null +++ b/tests/components/hlw8012/test.esp32-idf.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 12 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hlw8012/test.esp32.yaml b/tests/components/hlw8012/test.esp32.yaml new file mode 100644 index 0000000000..5b2d865722 --- /dev/null +++ b/tests/components/hlw8012/test.esp32.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 12 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hlw8012/test.esp8266.yaml b/tests/components/hlw8012/test.esp8266.yaml new file mode 100644 index 0000000000..5b2d865722 --- /dev/null +++ b/tests/components/hlw8012/test.esp8266.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 12 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hlw8012/test.rp2040.yaml b/tests/components/hlw8012/test.rp2040.yaml new file mode 100644 index 0000000000..da6053a1b9 --- /dev/null +++ b/tests/components/hlw8012/test.rp2040.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: hlw8012 + model: hlw8012 + sel_pin: 2 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE diff --git a/tests/components/hm3301/test.esp32-c3-idf.yaml b/tests/components/hm3301/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..eb6c4a14e6 --- /dev/null +++ b/tests/components/hm3301/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 5 + sda: 4 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hm3301/test.esp32-c3.yaml b/tests/components/hm3301/test.esp32-c3.yaml new file mode 100644 index 0000000000..eb6c4a14e6 --- /dev/null +++ b/tests/components/hm3301/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 5 + sda: 4 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hm3301/test.esp32-idf.yaml b/tests/components/hm3301/test.esp32-idf.yaml new file mode 100644 index 0000000000..413e88a265 --- /dev/null +++ b/tests/components/hm3301/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 16 + sda: 17 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hm3301/test.esp32.yaml b/tests/components/hm3301/test.esp32.yaml new file mode 100644 index 0000000000..413e88a265 --- /dev/null +++ b/tests/components/hm3301/test.esp32.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 16 + sda: 17 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hm3301/test.esp8266.yaml b/tests/components/hm3301/test.esp8266.yaml new file mode 100644 index 0000000000..eb6c4a14e6 --- /dev/null +++ b/tests/components/hm3301/test.esp8266.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 5 + sda: 4 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hm3301/test.rp2040.yaml b/tests/components/hm3301/test.rp2040.yaml new file mode 100644 index 0000000000..eb6c4a14e6 --- /dev/null +++ b/tests/components/hm3301/test.rp2040.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_hm3301 + scl: 5 + sda: 4 + +sensor: + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: CAQI diff --git a/tests/components/hmc5883l/test.esp32-c3-idf.yaml b/tests/components/hmc5883l/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e65b2e5c5b --- /dev/null +++ b/tests/components/hmc5883l/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/hmc5883l/test.esp32-c3.yaml b/tests/components/hmc5883l/test.esp32-c3.yaml new file mode 100644 index 0000000000..e65b2e5c5b --- /dev/null +++ b/tests/components/hmc5883l/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/hmc5883l/test.esp32-idf.yaml b/tests/components/hmc5883l/test.esp32-idf.yaml new file mode 100644 index 0000000000..db632fc411 --- /dev/null +++ b/tests/components/hmc5883l/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 16 + sda: 17 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/hmc5883l/test.esp32.yaml b/tests/components/hmc5883l/test.esp32.yaml new file mode 100644 index 0000000000..db632fc411 --- /dev/null +++ b/tests/components/hmc5883l/test.esp32.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 16 + sda: 17 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/hmc5883l/test.esp8266.yaml b/tests/components/hmc5883l/test.esp8266.yaml new file mode 100644 index 0000000000..e65b2e5c5b --- /dev/null +++ b/tests/components/hmc5883l/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/hmc5883l/test.rp2040.yaml b/tests/components/hmc5883l/test.rp2040.yaml new file mode 100644 index 0000000000..e65b2e5c5b --- /dev/null +++ b/tests/components/hmc5883l/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_hmc5883l + scl: 5 + sda: 4 + +sensor: + - platform: hmc5883l + address: 0x68 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + heading: + name: HMC5883L Heading + range: 130uT + oversampling: 8x + update_interval: 15s diff --git a/tests/components/homeassistant/test.esp32-c3-idf.yaml b/tests/components/homeassistant/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.esp32-c3-idf.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.esp32-c3.yaml b/tests/components/homeassistant/test.esp32-c3.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.esp32-c3.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.esp32-idf.yaml b/tests/components/homeassistant/test.esp32-idf.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.esp32-idf.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.esp32.yaml b/tests/components/homeassistant/test.esp32.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.esp32.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.esp8266.yaml b/tests/components/homeassistant/test.esp8266.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.esp8266.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.rp2040.yaml b/tests/components/homeassistant/test.rp2040.yaml new file mode 100644 index 0000000000..d2608f077c --- /dev/null +++ b/tests/components/homeassistant/test.rp2040.yaml @@ -0,0 +1,39 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/honeywell_hih_i2c/test.esp32-c3-idf.yaml b/tests/components/honeywell_hih_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5dae3d5d52 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 5 + sda: 4 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywell_hih_i2c/test.esp32-c3.yaml b/tests/components/honeywell_hih_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..5dae3d5d52 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 5 + sda: 4 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywell_hih_i2c/test.esp32-idf.yaml b/tests/components/honeywell_hih_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..0119aec3f3 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 16 + sda: 17 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywell_hih_i2c/test.esp32.yaml b/tests/components/honeywell_hih_i2c/test.esp32.yaml new file mode 100644 index 0000000000..0119aec3f3 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 16 + sda: 17 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywell_hih_i2c/test.esp8266.yaml b/tests/components/honeywell_hih_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..5dae3d5d52 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 5 + sda: 4 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywell_hih_i2c/test.rp2040.yaml b/tests/components/honeywell_hih_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..5dae3d5d52 --- /dev/null +++ b/tests/components/honeywell_hih_i2c/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_honeywell_hih + scl: 5 + sda: 4 + +sensor: + - platform: honeywell_hih_i2c + temperature: + name: Temperature + humidity: + name: Humidity + update_interval: 15s diff --git a/tests/components/honeywellabp/test.esp32-c3-idf.yaml b/tests/components/honeywellabp/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a53e3296dd --- /dev/null +++ b/tests/components/honeywellabp/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_honeywellabp + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: honeywellabp + cs_pin: 8 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp/test.esp32-c3.yaml b/tests/components/honeywellabp/test.esp32-c3.yaml new file mode 100644 index 0000000000..a53e3296dd --- /dev/null +++ b/tests/components/honeywellabp/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_honeywellabp + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: honeywellabp + cs_pin: 8 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp/test.esp32-idf.yaml b/tests/components/honeywellabp/test.esp32-idf.yaml new file mode 100644 index 0000000000..6bf9fa0f4d --- /dev/null +++ b/tests/components/honeywellabp/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_bme280 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: honeywellabp + cs_pin: 12 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp/test.esp32.yaml b/tests/components/honeywellabp/test.esp32.yaml new file mode 100644 index 0000000000..6bf9fa0f4d --- /dev/null +++ b/tests/components/honeywellabp/test.esp32.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_bme280 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: honeywellabp + cs_pin: 12 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp/test.esp8266.yaml b/tests/components/honeywellabp/test.esp8266.yaml new file mode 100644 index 0000000000..31988c035e --- /dev/null +++ b/tests/components/honeywellabp/test.esp8266.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_bme280 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sensor: + - platform: honeywellabp + cs_pin: 15 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp/test.rp2040.yaml b/tests/components/honeywellabp/test.rp2040.yaml new file mode 100644 index 0000000000..2e0c471fa0 --- /dev/null +++ b/tests/components/honeywellabp/test.rp2040.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_bme280 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +sensor: + - platform: honeywellabp + cs_pin: 6 + pressure: + name: Honeywell pressure + min_pressure: 0 + max_pressure: 15 + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.esp32-c3-idf.yaml b/tests/components/honeywellabp2_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b47411c238 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 5 + sda: 4 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.esp32-c3.yaml b/tests/components/honeywellabp2_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..b47411c238 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 5 + sda: 4 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.esp32-idf.yaml b/tests/components/honeywellabp2_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..0f0d61ca06 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 16 + sda: 17 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.esp32.yaml b/tests/components/honeywellabp2_i2c/test.esp32.yaml new file mode 100644 index 0000000000..0f0d61ca06 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 16 + sda: 17 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.esp8266.yaml b/tests/components/honeywellabp2_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..b47411c238 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 5 + sda: 4 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/honeywellabp2_i2c/test.rp2040.yaml b/tests/components/honeywellabp2_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..b47411c238 --- /dev/null +++ b/tests/components/honeywellabp2_i2c/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_honeywellabp2 + scl: 5 + sda: 4 + +sensor: + - platform: honeywellabp2_i2c + address: 0x28 + pressure: + name: Honeywell2 pressure + min_pressure: 0 + max_pressure: 16000 + transfer_function: A + temperature: + name: Honeywell temperature diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32-c3-idf.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..729cb96120 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml new file mode 100644 index 0000000000..729cb96120 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32-idf.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32-idf.yaml new file mode 100644 index 0000000000..da283cc072 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32.yaml new file mode 100644 index 0000000000..da283cc072 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.esp32.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hrxl_maxsonar_wr/test.esp8266.yaml b/tests/components/hrxl_maxsonar_wr/test.esp8266.yaml new file mode 100644 index 0000000000..729cb96120 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.esp8266.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hrxl_maxsonar_wr/test.rp2040.yaml b/tests/components/hrxl_maxsonar_wr/test.rp2040.yaml new file mode 100644 index 0000000000..729cb96120 --- /dev/null +++ b/tests/components/hrxl_maxsonar_wr/test.rp2040.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_hrxl_maxsonar_wr + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: hrxl_maxsonar_wr + id: hrxl_maxsonar_wr_sensor + name: Rainwater Tank Level diff --git a/tests/components/hte501/test.esp32-c3-idf.yaml b/tests/components/hte501/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e14b589dbd --- /dev/null +++ b/tests/components/hte501/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 5 + sda: 4 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hte501/test.esp32-c3.yaml b/tests/components/hte501/test.esp32-c3.yaml new file mode 100644 index 0000000000..e14b589dbd --- /dev/null +++ b/tests/components/hte501/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 5 + sda: 4 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hte501/test.esp32-idf.yaml b/tests/components/hte501/test.esp32-idf.yaml new file mode 100644 index 0000000000..83e4d26603 --- /dev/null +++ b/tests/components/hte501/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 16 + sda: 17 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hte501/test.esp32.yaml b/tests/components/hte501/test.esp32.yaml new file mode 100644 index 0000000000..83e4d26603 --- /dev/null +++ b/tests/components/hte501/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 16 + sda: 17 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hte501/test.esp8266.yaml b/tests/components/hte501/test.esp8266.yaml new file mode 100644 index 0000000000..e14b589dbd --- /dev/null +++ b/tests/components/hte501/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 5 + sda: 4 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hte501/test.rp2040.yaml b/tests/components/hte501/test.rp2040.yaml new file mode 100644 index 0000000000..e14b589dbd --- /dev/null +++ b/tests/components/hte501/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_hte501 + scl: 5 + sda: 4 + +sensor: + - platform: hte501 + address: 0x40 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/http_request/test.esp32-c3.yaml b/tests/components/http_request/test.esp32-c3.yaml new file mode 100644 index 0000000000..19fc6af2c4 --- /dev/null +++ b/tests/components/http_request/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +http_request: + useragent: esphome/tagreader + timeout: 10s diff --git a/tests/components/http_request/test.esp32.yaml b/tests/components/http_request/test.esp32.yaml new file mode 100644 index 0000000000..19fc6af2c4 --- /dev/null +++ b/tests/components/http_request/test.esp32.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +http_request: + useragent: esphome/tagreader + timeout: 10s diff --git a/tests/components/http_request/test.esp8266.yaml b/tests/components/http_request/test.esp8266.yaml new file mode 100644 index 0000000000..19fc6af2c4 --- /dev/null +++ b/tests/components/http_request/test.esp8266.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +http_request: + useragent: esphome/tagreader + timeout: 10s diff --git a/tests/components/htu21d/test.esp32-c3-idf.yaml b/tests/components/htu21d/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d9fbb09550 --- /dev/null +++ b/tests/components/htu21d/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 5 + sda: 4 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/htu21d/test.esp32-c3.yaml b/tests/components/htu21d/test.esp32-c3.yaml new file mode 100644 index 0000000000..d9fbb09550 --- /dev/null +++ b/tests/components/htu21d/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 5 + sda: 4 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/htu21d/test.esp32-idf.yaml b/tests/components/htu21d/test.esp32-idf.yaml new file mode 100644 index 0000000000..48f03eb368 --- /dev/null +++ b/tests/components/htu21d/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 16 + sda: 17 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/htu21d/test.esp32.yaml b/tests/components/htu21d/test.esp32.yaml new file mode 100644 index 0000000000..48f03eb368 --- /dev/null +++ b/tests/components/htu21d/test.esp32.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 16 + sda: 17 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/htu21d/test.esp8266.yaml b/tests/components/htu21d/test.esp8266.yaml new file mode 100644 index 0000000000..d9fbb09550 --- /dev/null +++ b/tests/components/htu21d/test.esp8266.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 5 + sda: 4 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/htu21d/test.rp2040.yaml b/tests/components/htu21d/test.rp2040.yaml new file mode 100644 index 0000000000..d9fbb09550 --- /dev/null +++ b/tests/components/htu21d/test.rp2040.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_htu21d + scl: 5 + sda: 4 + +sensor: + - platform: htu21d + temperature: + name: Temperature + humidity: + name: Humidity + heater: + name: Heater + update_interval: 15s diff --git a/tests/components/hx711/test.esp32-c3-idf.yaml b/tests/components/hx711/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9850417440 --- /dev/null +++ b/tests/components/hx711/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 4 + clk_pin: 5 + gain: 128 + update_interval: 15s diff --git a/tests/components/hx711/test.esp32-c3.yaml b/tests/components/hx711/test.esp32-c3.yaml new file mode 100644 index 0000000000..9850417440 --- /dev/null +++ b/tests/components/hx711/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 4 + clk_pin: 5 + gain: 128 + update_interval: 15s diff --git a/tests/components/hx711/test.esp32-idf.yaml b/tests/components/hx711/test.esp32-idf.yaml new file mode 100644 index 0000000000..554b184422 --- /dev/null +++ b/tests/components/hx711/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 14 + clk_pin: 15 + gain: 128 + update_interval: 15s diff --git a/tests/components/hx711/test.esp32.yaml b/tests/components/hx711/test.esp32.yaml new file mode 100644 index 0000000000..554b184422 --- /dev/null +++ b/tests/components/hx711/test.esp32.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 14 + clk_pin: 15 + gain: 128 + update_interval: 15s diff --git a/tests/components/hx711/test.esp8266.yaml b/tests/components/hx711/test.esp8266.yaml new file mode 100644 index 0000000000..9850417440 --- /dev/null +++ b/tests/components/hx711/test.esp8266.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 4 + clk_pin: 5 + gain: 128 + update_interval: 15s diff --git a/tests/components/hx711/test.rp2040.yaml b/tests/components/hx711/test.rp2040.yaml new file mode 100644 index 0000000000..9850417440 --- /dev/null +++ b/tests/components/hx711/test.rp2040.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: hx711 + name: HX711 Value + dout_pin: 4 + clk_pin: 5 + gain: 128 + update_interval: 15s diff --git a/tests/components/hydreon_rgxx/test.esp32-c3-idf.yaml b/tests/components/hydreon_rgxx/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f62f4942db --- /dev/null +++ b/tests/components/hydreon_rgxx/test.esp32-c3-idf.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hydreon_rgxx/test.esp32-c3.yaml b/tests/components/hydreon_rgxx/test.esp32-c3.yaml new file mode 100644 index 0000000000..f62f4942db --- /dev/null +++ b/tests/components/hydreon_rgxx/test.esp32-c3.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hydreon_rgxx/test.esp32-idf.yaml b/tests/components/hydreon_rgxx/test.esp32-idf.yaml new file mode 100644 index 0000000000..b6f9486d86 --- /dev/null +++ b/tests/components/hydreon_rgxx/test.esp32-idf.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hydreon_rgxx/test.esp32.yaml b/tests/components/hydreon_rgxx/test.esp32.yaml new file mode 100644 index 0000000000..b6f9486d86 --- /dev/null +++ b/tests/components/hydreon_rgxx/test.esp32.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hydreon_rgxx/test.esp8266.yaml b/tests/components/hydreon_rgxx/test.esp8266.yaml new file mode 100644 index 0000000000..f62f4942db --- /dev/null +++ b/tests/components/hydreon_rgxx/test.esp8266.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hydreon_rgxx/test.rp2040.yaml b/tests/components/hydreon_rgxx/test.rp2040.yaml new file mode 100644 index 0000000000..f62f4942db --- /dev/null +++ b/tests/components/hydreon_rgxx/test.rp2040.yaml @@ -0,0 +1,37 @@ +uart: + - id: uart_hydreon_rgxx + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +binary_sensor: + - platform: hydreon_rgxx + hydreon_rgxx_id: hydreon_rg9 + too_cold: + name: rg9_toocold + em_sat: + name: rg9_emsat + lens_bad: + name: rg9_lens_bad + +sensor: + - platform: hydreon_rgxx + id: hydreon_rg9 + model: RG 9 + moisture: + name: hydreon_rain + id: hydreon_rain + temperature: + name: hydreon_temperature + disable_led: true + - platform: hydreon_rgxx + id: hydreon_rg15 + model: RG_15 + acc: + name: hydreon_acc + event_acc: + name: hydreon_event_acc + total_acc: + name: hydreon_total_acc + r_int: + name: hydreon_r_int diff --git a/tests/components/hyt271/test.esp32-c3-idf.yaml b/tests/components/hyt271/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c44f0a1f5d --- /dev/null +++ b/tests/components/hyt271/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 5 + sda: 4 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hyt271/test.esp32-c3.yaml b/tests/components/hyt271/test.esp32-c3.yaml new file mode 100644 index 0000000000..c44f0a1f5d --- /dev/null +++ b/tests/components/hyt271/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 5 + sda: 4 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hyt271/test.esp32-idf.yaml b/tests/components/hyt271/test.esp32-idf.yaml new file mode 100644 index 0000000000..297611a89b --- /dev/null +++ b/tests/components/hyt271/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 16 + sda: 17 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hyt271/test.esp32.yaml b/tests/components/hyt271/test.esp32.yaml new file mode 100644 index 0000000000..297611a89b --- /dev/null +++ b/tests/components/hyt271/test.esp32.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 16 + sda: 17 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hyt271/test.esp8266.yaml b/tests/components/hyt271/test.esp8266.yaml new file mode 100644 index 0000000000..c44f0a1f5d --- /dev/null +++ b/tests/components/hyt271/test.esp8266.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 5 + sda: 4 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity diff --git a/tests/components/hyt271/test.rp2040.yaml b/tests/components/hyt271/test.rp2040.yaml new file mode 100644 index 0000000000..c44f0a1f5d --- /dev/null +++ b/tests/components/hyt271/test.rp2040.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_hyt271 + scl: 5 + sda: 4 + +sensor: + - platform: hyt271 + temperature: + name: Temperature + humidity: + name: Humidity From 6d480c5f058323933bc1f24de891928f86b36e95 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:09:25 +1200 Subject: [PATCH 1522/2607] ads1115: remove auto-load and split sensor into platform folder (#5981) --- esphome/components/ads1115/__init__.py | 3 +- esphome/components/ads1115/ads1115.cpp | 31 +++++----------- esphome/components/ads1115/ads1115.h | 31 ++-------------- .../ads1115/{sensor.py => sensor/__init__.py} | 21 +++-------- .../ads1115/sensor/ads1115_sensor.cpp | 30 ++++++++++++++++ .../ads1115/sensor/ads1115_sensor.h | 35 +++++++++++++++++++ 6 files changed, 82 insertions(+), 69 deletions(-) rename esphome/components/ads1115/{sensor.py => sensor/__init__.py} (82%) create mode 100644 esphome/components/ads1115/sensor/ads1115_sensor.cpp create mode 100644 esphome/components/ads1115/sensor/ads1115_sensor.h diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index e8861a2f67..a463d8390d 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -4,13 +4,14 @@ from esphome.components import i2c from esphome.const import CONF_ID DEPENDENCIES = ["i2c"] -AUTO_LOAD = ["sensor", "voltage_sampler"] MULTI_CONF = True ads1115_ns = cg.esphome_ns.namespace("ads1115") ADS1115Component = ads1115_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice) CONF_CONTINUOUS_MODE = "continuous_mode" +CONF_ADS1115_ID = "ads1115_id" + CONFIG_SCHEMA = ( cv.Schema( { diff --git a/esphome/components/ads1115/ads1115.cpp b/esphome/components/ads1115/ads1115.cpp index c3f3c00c63..218edc4c81 100644 --- a/esphome/components/ads1115/ads1115.cpp +++ b/esphome/components/ads1115/ads1115.cpp @@ -1,6 +1,6 @@ #include "ads1115.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace ads1115 { @@ -75,25 +75,19 @@ void ADS1115Component::dump_config() { if (this->is_failed()) { ESP_LOGE(TAG, "Communication with ADS1115 failed!"); } - - for (auto *sensor : this->sensors_) { - LOG_SENSOR(" ", "Sensor", sensor); - ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer()); - ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain()); - ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution()); - } } -float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { +float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, + ADS1115Resolution resolution) { uint16_t config = this->prev_config_; // Multiplexer // 0bxBBBxxxxxxxxxxxx config &= 0b1000111111111111; - config |= (sensor->get_multiplexer() & 0b111) << 12; + config |= (multiplexer & 0b111) << 12; // Gain // 0bxxxxBBBxxxxxxxxx config &= 0b1111000111111111; - config |= (sensor->get_gain() & 0b111) << 9; + config |= (gain & 0b111) << 9; if (!this->continuous_mode_) { // Start conversion @@ -132,7 +126,7 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { return NAN; } - if (sensor->get_resolution() == ADS1015_12_BITS) { + if (resolution == ADS1015_12_BITS) { bool negative = (raw_conversion >> 15) == 1; // shift raw_conversion as it's only 12-bits, left justified @@ -151,8 +145,8 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { auto signed_conversion = static_cast(raw_conversion); float millivolts; - float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f; - switch (sensor->get_gain()) { + float divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f; + switch (gain) { case ADS1115_GAIN_6P144: millivolts = (signed_conversion * 6144) / divider; break; @@ -179,14 +173,5 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { return millivolts / 1e3f; } -float ADS1115Sensor::sample() { return this->parent_->request_measurement(this); } -void ADS1115Sensor::update() { - float v = this->parent_->request_measurement(this); - if (!std::isnan(v)) { - ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); - this->publish_state(v); - } -} - } // namespace ads1115 } // namespace esphome diff --git a/esphome/components/ads1115/ads1115.h b/esphome/components/ads1115/ads1115.h index 0b8bfb339b..509333d2c8 100644 --- a/esphome/components/ads1115/ads1115.h +++ b/esphome/components/ads1115/ads1115.h @@ -1,9 +1,7 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" -#include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/core/component.h" #include @@ -35,12 +33,8 @@ enum ADS1115Resolution { ADS1015_12_BITS = 12, }; -class ADS1115Sensor; - class ADS1115Component : public Component, public i2c::I2CDevice { public: - void register_sensor(ADS1115Sensor *obj) { this->sensors_.push_back(obj); } - /// Set up the internal sensor array. void setup() override; void dump_config() override; /// HARDWARE_LATE setup priority @@ -48,33 +42,12 @@ class ADS1115Component : public Component, public i2c::I2CDevice { void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } /// Helper method to request a measurement from a sensor. - float request_measurement(ADS1115Sensor *sensor); + float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution); protected: - std::vector sensors_; uint16_t prev_config_{0}; bool continuous_mode_; }; -/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. -class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { - public: - ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {} - void update() override; - void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; } - void set_gain(ADS1115Gain gain) { gain_ = gain; } - void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; } - float sample() override; - uint8_t get_multiplexer() const { return multiplexer_; } - uint8_t get_gain() const { return gain_; } - uint8_t get_resolution() const { return resolution_; } - - protected: - ADS1115Component *parent_; - ADS1115Multiplexer multiplexer_; - ADS1115Gain gain_; - ADS1115Resolution resolution_; -}; - } // namespace ads1115 } // namespace esphome diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor/__init__.py similarity index 82% rename from esphome/components/ads1115/sensor.py rename to esphome/components/ads1115/sensor/__init__.py index f0d894e2af..baec31d35c 100644 --- a/esphome/components/ads1115/sensor.py +++ b/esphome/components/ads1115/sensor/__init__.py @@ -10,8 +10,9 @@ from esphome.const import ( UNIT_VOLT, CONF_ID, ) -from . import ads1115_ns, ADS1115Component +from .. import ads1115_ns, ADS1115Component, CONF_ADS1115_ID +AUTO_LOAD = ["voltage_sampler"] DEPENDENCIES = ["ads1115"] ADS1115Multiplexer = ads1115_ns.enum("ADS1115Multiplexer") @@ -43,20 +44,10 @@ RESOLUTION = { } -def validate_gain(value): - if isinstance(value, float): - value = f"{value:0.03f}" - elif not isinstance(value, str): - raise cv.Invalid(f'invalid gain "{value}"') - - return cv.enum(GAIN)(value) - - ADS1115Sensor = ads1115_ns.class_( "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler ) -CONF_ADS1115_ID = "ads1115_id" CONFIG_SCHEMA = ( sensor.sensor_schema( ADS1115Sensor, @@ -69,7 +60,7 @@ CONFIG_SCHEMA = ( { cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component), cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"), - cv.Required(CONF_GAIN): validate_gain, + cv.Required(CONF_GAIN): cv.enum(GAIN, string=True), cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum( RESOLUTION, upper=True, space="_" ), @@ -80,13 +71,11 @@ CONFIG_SCHEMA = ( async def to_code(config): - paren = await cg.get_variable(config[CONF_ADS1115_ID]) - var = cg.new_Pvariable(config[CONF_ID], paren) + var = cg.new_Pvariable(config[CONF_ID]) await sensor.register_sensor(var, config) await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_ADS1115_ID]) cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) cg.add(var.set_gain(config[CONF_GAIN])) cg.add(var.set_resolution(config[CONF_RESOLUTION])) - - cg.add(paren.register_sensor(var)) diff --git a/esphome/components/ads1115/sensor/ads1115_sensor.cpp b/esphome/components/ads1115/sensor/ads1115_sensor.cpp new file mode 100644 index 0000000000..335fca4845 --- /dev/null +++ b/esphome/components/ads1115/sensor/ads1115_sensor.cpp @@ -0,0 +1,30 @@ +#include "ads1115_sensor.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace ads1115 { + +static const char *const TAG = "ads1115.sensor"; + +float ADS1115Sensor::sample() { + return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_); +} + +void ADS1115Sensor::update() { + float v = this->sample(); + if (!std::isnan(v)) { + ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); + this->publish_state(v); + } +} + +void ADS1115Sensor::dump_config() { + LOG_SENSOR(" ", "ADS1115 Sensor", this); + ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); + ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); + ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_); +} + +} // namespace ads1115 +} // namespace esphome diff --git a/esphome/components/ads1115/sensor/ads1115_sensor.h b/esphome/components/ads1115/sensor/ads1115_sensor.h new file mode 100644 index 0000000000..191afc3de6 --- /dev/null +++ b/esphome/components/ads1115/sensor/ads1115_sensor.h @@ -0,0 +1,35 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" + +#include "../ads1115.h" + +namespace esphome { +namespace ads1115 { + +/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. +class ADS1115Sensor : public sensor::Sensor, + public PollingComponent, + public voltage_sampler::VoltageSampler, + public Parented { + public: + void update() override; + void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } + void set_gain(ADS1115Gain gain) { this->gain_ = gain; } + void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; } + float sample() override; + + void dump_config() override; + + protected: + ADS1115Multiplexer multiplexer_; + ADS1115Gain gain_; + ADS1115Resolution resolution_; +}; + +} // namespace ads1115 +} // namespace esphome From e6bfa275fca4056cd2417023850c3c94b622c291 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 07:57:41 +1200 Subject: [PATCH 1523/2607] Bump esphome-dashboard to 20240412.0 (#6517) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 702127eca8..4abc4d98d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240319.0 +esphome-dashboard==20240412.0 aioesphomeapi==23.2.0 zeroconf==0.131.0 python-magic==0.4.27 From 68b4d8865c14ecde4f8d9bdc1febae981962b0a6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:25:35 +1200 Subject: [PATCH 1524/2607] Add dooya remote transmitter test (#6508) --- tests/components/remote_transmitter/common-buttons.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml index 5f655acb7c..27683b387f 100644 --- a/tests/components/remote_transmitter/common-buttons.yaml +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -176,3 +176,11 @@ button: 0x00, 0x05, ] + - platform: template + name: Dooya + on_press: + remote_transmitter.transmit_dooya: + id: 0x123456 + channel: 1 + button: 1 + check: 1 From 1d4c074ee6aa301dea5fb7f9f161e83abd83f313 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:09:25 +1200 Subject: [PATCH 1525/2607] ads1115: remove auto-load and split sensor into platform folder (#5981) --- esphome/components/ads1115/__init__.py | 3 +- esphome/components/ads1115/ads1115.cpp | 31 +++++----------- esphome/components/ads1115/ads1115.h | 31 ++-------------- .../ads1115/{sensor.py => sensor/__init__.py} | 21 +++-------- .../ads1115/sensor/ads1115_sensor.cpp | 30 ++++++++++++++++ .../ads1115/sensor/ads1115_sensor.h | 35 +++++++++++++++++++ 6 files changed, 82 insertions(+), 69 deletions(-) rename esphome/components/ads1115/{sensor.py => sensor/__init__.py} (82%) create mode 100644 esphome/components/ads1115/sensor/ads1115_sensor.cpp create mode 100644 esphome/components/ads1115/sensor/ads1115_sensor.h diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index e8861a2f67..a463d8390d 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -4,13 +4,14 @@ from esphome.components import i2c from esphome.const import CONF_ID DEPENDENCIES = ["i2c"] -AUTO_LOAD = ["sensor", "voltage_sampler"] MULTI_CONF = True ads1115_ns = cg.esphome_ns.namespace("ads1115") ADS1115Component = ads1115_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice) CONF_CONTINUOUS_MODE = "continuous_mode" +CONF_ADS1115_ID = "ads1115_id" + CONFIG_SCHEMA = ( cv.Schema( { diff --git a/esphome/components/ads1115/ads1115.cpp b/esphome/components/ads1115/ads1115.cpp index c3f3c00c63..218edc4c81 100644 --- a/esphome/components/ads1115/ads1115.cpp +++ b/esphome/components/ads1115/ads1115.cpp @@ -1,6 +1,6 @@ #include "ads1115.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace ads1115 { @@ -75,25 +75,19 @@ void ADS1115Component::dump_config() { if (this->is_failed()) { ESP_LOGE(TAG, "Communication with ADS1115 failed!"); } - - for (auto *sensor : this->sensors_) { - LOG_SENSOR(" ", "Sensor", sensor); - ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer()); - ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain()); - ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution()); - } } -float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { +float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, + ADS1115Resolution resolution) { uint16_t config = this->prev_config_; // Multiplexer // 0bxBBBxxxxxxxxxxxx config &= 0b1000111111111111; - config |= (sensor->get_multiplexer() & 0b111) << 12; + config |= (multiplexer & 0b111) << 12; // Gain // 0bxxxxBBBxxxxxxxxx config &= 0b1111000111111111; - config |= (sensor->get_gain() & 0b111) << 9; + config |= (gain & 0b111) << 9; if (!this->continuous_mode_) { // Start conversion @@ -132,7 +126,7 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { return NAN; } - if (sensor->get_resolution() == ADS1015_12_BITS) { + if (resolution == ADS1015_12_BITS) { bool negative = (raw_conversion >> 15) == 1; // shift raw_conversion as it's only 12-bits, left justified @@ -151,8 +145,8 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { auto signed_conversion = static_cast(raw_conversion); float millivolts; - float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f; - switch (sensor->get_gain()) { + float divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f; + switch (gain) { case ADS1115_GAIN_6P144: millivolts = (signed_conversion * 6144) / divider; break; @@ -179,14 +173,5 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { return millivolts / 1e3f; } -float ADS1115Sensor::sample() { return this->parent_->request_measurement(this); } -void ADS1115Sensor::update() { - float v = this->parent_->request_measurement(this); - if (!std::isnan(v)) { - ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); - this->publish_state(v); - } -} - } // namespace ads1115 } // namespace esphome diff --git a/esphome/components/ads1115/ads1115.h b/esphome/components/ads1115/ads1115.h index 0b8bfb339b..509333d2c8 100644 --- a/esphome/components/ads1115/ads1115.h +++ b/esphome/components/ads1115/ads1115.h @@ -1,9 +1,7 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" -#include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/core/component.h" #include @@ -35,12 +33,8 @@ enum ADS1115Resolution { ADS1015_12_BITS = 12, }; -class ADS1115Sensor; - class ADS1115Component : public Component, public i2c::I2CDevice { public: - void register_sensor(ADS1115Sensor *obj) { this->sensors_.push_back(obj); } - /// Set up the internal sensor array. void setup() override; void dump_config() override; /// HARDWARE_LATE setup priority @@ -48,33 +42,12 @@ class ADS1115Component : public Component, public i2c::I2CDevice { void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } /// Helper method to request a measurement from a sensor. - float request_measurement(ADS1115Sensor *sensor); + float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution); protected: - std::vector sensors_; uint16_t prev_config_{0}; bool continuous_mode_; }; -/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. -class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { - public: - ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {} - void update() override; - void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; } - void set_gain(ADS1115Gain gain) { gain_ = gain; } - void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; } - float sample() override; - uint8_t get_multiplexer() const { return multiplexer_; } - uint8_t get_gain() const { return gain_; } - uint8_t get_resolution() const { return resolution_; } - - protected: - ADS1115Component *parent_; - ADS1115Multiplexer multiplexer_; - ADS1115Gain gain_; - ADS1115Resolution resolution_; -}; - } // namespace ads1115 } // namespace esphome diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor/__init__.py similarity index 82% rename from esphome/components/ads1115/sensor.py rename to esphome/components/ads1115/sensor/__init__.py index f0d894e2af..baec31d35c 100644 --- a/esphome/components/ads1115/sensor.py +++ b/esphome/components/ads1115/sensor/__init__.py @@ -10,8 +10,9 @@ from esphome.const import ( UNIT_VOLT, CONF_ID, ) -from . import ads1115_ns, ADS1115Component +from .. import ads1115_ns, ADS1115Component, CONF_ADS1115_ID +AUTO_LOAD = ["voltage_sampler"] DEPENDENCIES = ["ads1115"] ADS1115Multiplexer = ads1115_ns.enum("ADS1115Multiplexer") @@ -43,20 +44,10 @@ RESOLUTION = { } -def validate_gain(value): - if isinstance(value, float): - value = f"{value:0.03f}" - elif not isinstance(value, str): - raise cv.Invalid(f'invalid gain "{value}"') - - return cv.enum(GAIN)(value) - - ADS1115Sensor = ads1115_ns.class_( "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler ) -CONF_ADS1115_ID = "ads1115_id" CONFIG_SCHEMA = ( sensor.sensor_schema( ADS1115Sensor, @@ -69,7 +60,7 @@ CONFIG_SCHEMA = ( { cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component), cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"), - cv.Required(CONF_GAIN): validate_gain, + cv.Required(CONF_GAIN): cv.enum(GAIN, string=True), cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum( RESOLUTION, upper=True, space="_" ), @@ -80,13 +71,11 @@ CONFIG_SCHEMA = ( async def to_code(config): - paren = await cg.get_variable(config[CONF_ADS1115_ID]) - var = cg.new_Pvariable(config[CONF_ID], paren) + var = cg.new_Pvariable(config[CONF_ID]) await sensor.register_sensor(var, config) await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_ADS1115_ID]) cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) cg.add(var.set_gain(config[CONF_GAIN])) cg.add(var.set_resolution(config[CONF_RESOLUTION])) - - cg.add(paren.register_sensor(var)) diff --git a/esphome/components/ads1115/sensor/ads1115_sensor.cpp b/esphome/components/ads1115/sensor/ads1115_sensor.cpp new file mode 100644 index 0000000000..335fca4845 --- /dev/null +++ b/esphome/components/ads1115/sensor/ads1115_sensor.cpp @@ -0,0 +1,30 @@ +#include "ads1115_sensor.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace ads1115 { + +static const char *const TAG = "ads1115.sensor"; + +float ADS1115Sensor::sample() { + return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_); +} + +void ADS1115Sensor::update() { + float v = this->sample(); + if (!std::isnan(v)) { + ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); + this->publish_state(v); + } +} + +void ADS1115Sensor::dump_config() { + LOG_SENSOR(" ", "ADS1115 Sensor", this); + ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); + ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); + ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_); +} + +} // namespace ads1115 +} // namespace esphome diff --git a/esphome/components/ads1115/sensor/ads1115_sensor.h b/esphome/components/ads1115/sensor/ads1115_sensor.h new file mode 100644 index 0000000000..191afc3de6 --- /dev/null +++ b/esphome/components/ads1115/sensor/ads1115_sensor.h @@ -0,0 +1,35 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" + +#include "../ads1115.h" + +namespace esphome { +namespace ads1115 { + +/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. +class ADS1115Sensor : public sensor::Sensor, + public PollingComponent, + public voltage_sampler::VoltageSampler, + public Parented { + public: + void update() override; + void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } + void set_gain(ADS1115Gain gain) { this->gain_ = gain; } + void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; } + float sample() override; + + void dump_config() override; + + protected: + ADS1115Multiplexer multiplexer_; + ADS1115Gain gain_; + ADS1115Resolution resolution_; +}; + +} // namespace ads1115 +} // namespace esphome From 4ebbd4ebd8c1e4960f4ee081a8c46fa6d3a8d7ee Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 07:57:41 +1200 Subject: [PATCH 1526/2607] Bump esphome-dashboard to 20240412.0 (#6517) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 702127eca8..4abc4d98d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240319.0 +esphome-dashboard==20240412.0 aioesphomeapi==23.2.0 zeroconf==0.131.0 python-magic==0.4.27 From 8ada8f5e11f3ce4045a3752d0ff8fbf11d748a2a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:02:52 +1200 Subject: [PATCH 1527/2607] Bump version to 2024.4.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5f8082c395..08a1a42ea3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0b1" +__version__ = "2024.4.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 55433463d75c65405296972b4fd389b9f0e39cdd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:19:49 +1200 Subject: [PATCH 1528/2607] Fix missing ifdefs in voice assistant (#6520) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 34a26eec01..e68e00948e 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -729,6 +729,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { +#ifdef USE_SPEAKER // We should never get to this function if there is no speaker anyway if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); this->speaker_buffer_index_ += msg.data.length(); @@ -737,6 +738,7 @@ void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { } else { ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); } +#endif } VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) From 39947a163440e3bbdee2d4082c11599de46ffbd0 Mon Sep 17 00:00:00 2001 From: MRemy2 <95053616+MRemy2@users.noreply.github.com> Date: Fri, 12 Apr 2024 02:28:59 +0300 Subject: [PATCH 1529/2607] Added Htu21d model option (#6511) Co-authored-by: Remus Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/htu21d/htu21d.cpp | 21 ++++++++++++++++--- esphome/components/htu21d/htu21d.h | 4 ++++ esphome/components/htu21d/sensor.py | 11 +++++++++- .../components/htu21d/test.esp32-c3-idf.yaml | 1 + tests/components/htu21d/test.esp32-c3.yaml | 1 + tests/components/htu21d/test.esp32-idf.yaml | 1 + tests/components/htu21d/test.esp32.yaml | 1 + tests/components/htu21d/test.esp8266.yaml | 1 + tests/components/htu21d/test.rp2040.yaml | 1 + 9 files changed, 38 insertions(+), 4 deletions(-) diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index d0dbb15a43..411d1e1d6a 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -76,12 +76,27 @@ void HTU21DComponent::update() { float humidity = (float(raw_humidity & 0xFFFC)) * 125.0f / 65536.0f - 6.0f; - int8_t heater_level = this->get_heater_level(); - - ESP_LOGD(TAG, "Got Humidity=%.1f%% Heater Level=%d", humidity, heater_level); + ESP_LOGD(TAG, "Got Humidity=%.1f%%", humidity); if (this->humidity_ != nullptr) this->humidity_->publish_state(humidity); + + int8_t heater_level; + + // HTU21D does have a heater module but does not have heater level + // Setting heater level to 1 in case the heater is ON + if (this->sensor_model_ == HTU21D_SENSOR_MODEL_HTU21D) { + if (this->is_heater_enabled()) { + heater_level = 1; + } else { + heater_level = 0; + } + } else { + heater_level = this->get_heater_level(); + } + + ESP_LOGD(TAG, "Heater Level=%d", heater_level); + if (this->heater_ != nullptr) this->heater_->publish_state(heater_level); this->status_clear_warning(); diff --git a/esphome/components/htu21d/htu21d.h b/esphome/components/htu21d/htu21d.h index a77a8e3ada..8533875d43 100644 --- a/esphome/components/htu21d/htu21d.h +++ b/esphome/components/htu21d/htu21d.h @@ -8,6 +8,8 @@ namespace esphome { namespace htu21d { +enum HTU21DSensorModels { HTU21D_SENSOR_MODEL_HTU21D = 0, HTU21D_SENSOR_MODEL_SI7021, HTU21D_SENSOR_MODEL_SHT21 }; + class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { public: void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } @@ -17,6 +19,7 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { /// Setup (reset) the sensor and check connection. void setup() override; void dump_config() override; + void set_sensor_model(HTU21DSensorModels sensor_model) { sensor_model_ = sensor_model; } /// Update the sensor values (temperature+humidity). void update() override; @@ -31,6 +34,7 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *temperature_{nullptr}; sensor::Sensor *humidity_{nullptr}; sensor::Sensor *heater_{nullptr}; + HTU21DSensorModels sensor_model_{HTU21D_SENSOR_MODEL_HTU21D}; }; template class SetHeaterLevelAction : public Action, public Parented { diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 1f878230f8..bf0b9a23fb 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -5,6 +5,7 @@ from esphome import automation from esphome.const import ( CONF_HUMIDITY, CONF_ID, + CONF_MODEL, CONF_TEMPERATURE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, @@ -23,10 +24,15 @@ htu21d_ns = cg.esphome_ns.namespace("htu21d") HTU21DComponent = htu21d_ns.class_( "HTU21DComponent", cg.PollingComponent, i2c.I2CDevice ) - SetHeaterLevelAction = htu21d_ns.class_("SetHeaterLevelAction", automation.Action) SetHeaterAction = htu21d_ns.class_("SetHeaterAction", automation.Action) +HTU21DSensorModels = htu21d_ns.enum("HTU21DSensorModels") +MODELS = { + "HTU21D": HTU21DSensorModels.HTU21D_SENSOR_MODEL_HTU21D, + "SI7021": HTU21DSensorModels.HTU21D_SENSOR_MODEL_SI7021, + "SHT21": HTU21DSensorModels.HTU21D_SENSOR_MODEL_SHT21, +} CONFIG_SCHEMA = ( cv.Schema( @@ -49,6 +55,7 @@ CONFIG_SCHEMA = ( accuracy_decimals=1, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_MODEL, default="HTU21D"): cv.enum(MODELS, upper=True), } ) .extend(cv.polling_component_schema("60s")) @@ -73,6 +80,8 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_HEATER]) cg.add(var.set_heater(sens)) + cg.add(var.set_sensor_model(config[CONF_MODEL])) + @automation.register_action( "htu21d.set_heater_level", diff --git a/tests/components/htu21d/test.esp32-c3-idf.yaml b/tests/components/htu21d/test.esp32-c3-idf.yaml index d9fbb09550..8131d13661 100644 --- a/tests/components/htu21d/test.esp32-c3-idf.yaml +++ b/tests/components/htu21d/test.esp32-c3-idf.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: diff --git a/tests/components/htu21d/test.esp32-c3.yaml b/tests/components/htu21d/test.esp32-c3.yaml index d9fbb09550..8131d13661 100644 --- a/tests/components/htu21d/test.esp32-c3.yaml +++ b/tests/components/htu21d/test.esp32-c3.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: diff --git a/tests/components/htu21d/test.esp32-idf.yaml b/tests/components/htu21d/test.esp32-idf.yaml index 48f03eb368..6655a1cc1a 100644 --- a/tests/components/htu21d/test.esp32-idf.yaml +++ b/tests/components/htu21d/test.esp32-idf.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: diff --git a/tests/components/htu21d/test.esp32.yaml b/tests/components/htu21d/test.esp32.yaml index 48f03eb368..6655a1cc1a 100644 --- a/tests/components/htu21d/test.esp32.yaml +++ b/tests/components/htu21d/test.esp32.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: diff --git a/tests/components/htu21d/test.esp8266.yaml b/tests/components/htu21d/test.esp8266.yaml index d9fbb09550..8131d13661 100644 --- a/tests/components/htu21d/test.esp8266.yaml +++ b/tests/components/htu21d/test.esp8266.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: diff --git a/tests/components/htu21d/test.rp2040.yaml b/tests/components/htu21d/test.rp2040.yaml index d9fbb09550..8131d13661 100644 --- a/tests/components/htu21d/test.rp2040.yaml +++ b/tests/components/htu21d/test.rp2040.yaml @@ -5,6 +5,7 @@ i2c: sensor: - platform: htu21d + model: htu21d temperature: name: Temperature humidity: From 810cf3b0a4d705a35d0cd2285ff304485e7905df Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:56:18 +1200 Subject: [PATCH 1530/2607] Add bk72xx base test file (#6522) --- .../build_components_base.bk72xx.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/test_build_components/build_components_base.bk72xx.yaml diff --git a/tests/test_build_components/build_components_base.bk72xx.yaml b/tests/test_build_components/build_components_base.bk72xx.yaml new file mode 100644 index 0000000000..7fdaebc768 --- /dev/null +++ b/tests/test_build_components/build_components_base.bk72xx.yaml @@ -0,0 +1,18 @@ +esphome: + name: componenttestespbk72xx + friendly_name: $component_name + +bk72xx: + board: cb3s + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_name: $component_name + test_name: $test_name + target_platform: $target_platform + component_test_file: $component_test_file From 7eb524f920143ce7be075c84ac13c4856544ac91 Mon Sep 17 00:00:00 2001 From: Peter Zich Date: Thu, 11 Apr 2024 20:46:59 -0700 Subject: [PATCH 1531/2607] Add "log" alias for "logs" command (#6519) --- esphome/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/__main__.py b/esphome/__main__.py index 95d444ca9b..dcd2dddb4b 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -785,6 +785,7 @@ def parse_args(argv): parser_logs = subparsers.add_parser( "logs", help="Validate the configuration and show all logs.", + aliases=["log"], parents=[mqtt_options], ) parser_logs.add_argument( From 76daefe21c5f7a405d3f7df232bb7df0a2f4fe09 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Fri, 12 Apr 2024 06:03:08 +0200 Subject: [PATCH 1532/2607] Add ethernet DNS text sensor and simplify DNS display format (#6450) --- .../ethernet/ethernet_component.cpp | 5 +++++ .../components/ethernet/ethernet_component.h | 1 + .../ethernet_info_text_sensor.cpp | 1 + .../ethernet_info/ethernet_info_text_sensor.h | 21 +++++++++++++++++++ .../components/ethernet_info/text_sensor.py | 17 ++++++++++++--- .../wifi_info/wifi_info_text_sensor.h | 7 +------ .../ethernet_info/test.esp32-idf.yaml | 2 ++ .../components/ethernet_info/test.esp32.yaml | 2 ++ 8 files changed, 47 insertions(+), 9 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 3c61fbe0a6..243135de89 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -340,6 +340,11 @@ network::IPAddresses EthernetComponent::get_ip_addresses() { return addresses; } +network::IPAddress EthernetComponent::get_dns_address(uint8_t num) { + const ip_addr_t *dns_ip = dns_getserver(num); + return dns_ip; +} + void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) { const char *event_name; diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 621ac87c10..daeb5a2029 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -70,6 +70,7 @@ class EthernetComponent : public Component { void set_manual_ip(const ManualIP &manual_ip); network::IPAddresses get_ip_addresses(); + network::IPAddress get_dns_address(uint8_t num); std::string get_use_address() const; void set_use_address(const std::string &use_address); bool powerdown(); diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp index f841875396..c8b2b5885b 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp @@ -9,6 +9,7 @@ namespace ethernet_info { static const char *const TAG = "ethernet_info"; void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); } +void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); } } // namespace ethernet_info } // namespace esphome diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.h b/esphome/components/ethernet_info/ethernet_info_text_sensor.h index b5764d2519..82a7dcf56e 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.h +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.h @@ -38,6 +38,27 @@ class IPAddressEthernetInfo : public PollingComponent, public text_sensor::TextS std::array ip_sensors_; }; +class DNSAddressEthernetInfo : public PollingComponent, public text_sensor::TextSensor { + public: + void update() override { + auto dns_one = ethernet::global_eth_component->get_dns_address(0); + auto dns_two = ethernet::global_eth_component->get_dns_address(1); + + std::string dns_results = dns_one.str() + " " + dns_two.str(); + + if (dns_results != this->last_results_) { + this->last_results_ = dns_results; + this->publish_state(dns_results); + } + } + float get_setup_priority() const override { return setup_priority::ETHERNET; } + std::string unique_id() override { return get_mac_address() + "-ethernetinfo-dns"; } + void dump_config() override; + + protected: + std::string last_results_; +}; + } // namespace ethernet_info } // namespace esphome diff --git a/esphome/components/ethernet_info/text_sensor.py b/esphome/components/ethernet_info/text_sensor.py index b802c427e8..292673c182 100644 --- a/esphome/components/ethernet_info/text_sensor.py +++ b/esphome/components/ethernet_info/text_sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import text_sensor from esphome.const import ( CONF_IP_ADDRESS, + CONF_DNS_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC, ) @@ -10,14 +11,18 @@ DEPENDENCIES = ["ethernet"] ethernet_info_ns = cg.esphome_ns.namespace("ethernet_info") -IPAddressEsthernetInfo = ethernet_info_ns.class_( +IPAddressEthernetInfo = ethernet_info_ns.class_( "IPAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent ) +DNSAddressEthernetInfo = ethernet_info_ns.class_( + "DNSAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent +) + CONFIG_SCHEMA = cv.Schema( { cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema( - IPAddressEsthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + IPAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC ) .extend(cv.polling_component_schema("1s")) .extend( @@ -27,7 +32,10 @@ CONFIG_SCHEMA = cv.Schema( ) for x in range(5) } - ) + ), + cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema( + DNSAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), } ) @@ -40,3 +48,6 @@ async def to_code(config): if sensor_conf := conf.get(f"address_{x}"): sens = await text_sensor.new_text_sensor(sensor_conf) cg.add(ip_info.add_ip_sensors(x, sens)) + if conf := config.get(CONF_DNS_ADDRESS): + dns_info = await text_sensor.new_text_sensor(config[CONF_DNS_ADDRESS]) + await cg.register_component(dns_info, config[CONF_DNS_ADDRESS]) diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.h b/esphome/components/wifi_info/wifi_info_text_sensor.h index 6f189da3a3..0f31a57cc5 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.h +++ b/esphome/components/wifi_info/wifi_info_text_sensor.h @@ -39,15 +39,10 @@ class IPAddressWiFiInfo : public PollingComponent, public text_sensor::TextSenso class DNSAddressWifiInfo : public PollingComponent, public text_sensor::TextSensor { public: void update() override { - std::string dns_results; - auto dns_one = wifi::global_wifi_component->get_dns_address(0); auto dns_two = wifi::global_wifi_component->get_dns_address(1); - dns_results += "DNS1: "; - dns_results += dns_one.str(); - dns_results += " DNS2: "; - dns_results += dns_two.str(); + std::string dns_results = dns_one.str() + " " + dns_two.str(); if (dns_results != this->last_results_) { this->last_results_ = dns_results; diff --git a/tests/components/ethernet_info/test.esp32-idf.yaml b/tests/components/ethernet_info/test.esp32-idf.yaml index c5da2bb666..dade4d7ca5 100644 --- a/tests/components/ethernet_info/test.esp32-idf.yaml +++ b/tests/components/ethernet_info/test.esp32-idf.yaml @@ -15,3 +15,5 @@ text_sensor: - platform: ethernet_info ip_address: name: IP Address + dns_address: + name: DNS Address diff --git a/tests/components/ethernet_info/test.esp32.yaml b/tests/components/ethernet_info/test.esp32.yaml index c5da2bb666..dade4d7ca5 100644 --- a/tests/components/ethernet_info/test.esp32.yaml +++ b/tests/components/ethernet_info/test.esp32.yaml @@ -15,3 +15,5 @@ text_sensor: - platform: ethernet_info ip_address: name: IP Address + dns_address: + name: DNS Address From 1ab4fc8faf8de4c1d505522e16256c1e810a6b17 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Fri, 12 Apr 2024 04:35:12 -0500 Subject: [PATCH 1533/2607] Add all missing `remote_receiver` `on_...` tests (#6524) --- .../remote_receiver/esp32-common.yaml | 138 +++++++++++++++++- .../remote_receiver/test.esp8266.yaml | 138 +++++++++++++++++- 2 files changed, 272 insertions(+), 4 deletions(-) diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index d1d47661c5..0e71143fc3 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -3,12 +3,146 @@ remote_receiver: pin: ${pin} rmt_channel: ${rmt_channel} dump: all + on_abbwelcome: + then: + - logger.log: + format: "on_abbwelcome: %u" + args: ["x.data()[0]"] + on_aeha: + then: + - logger.log: + format: "on_aeha: %u %u" + args: ["x.address", "x.data.front()"] + on_byronsx: + then: + - logger.log: + format: "on_byronsx: %u %u" + args: ["x.address", "x.command"] + on_canalsat: + then: + - logger.log: + format: "on_canalsat: %u %u" + args: ["x.address", "x.command"] + # on_canalsatld: + # then: + # - logger.log: + # format: "on_canalsatld: %u %u" + # args: ["x.address", "x.command"] on_coolix: then: - delay: !lambda "return x.first + x.second;" + - logger.log: + format: "on_coolix: %u %u" + args: ["x.first", "x.second"] + on_dish: + then: + - logger.log: + format: "on_dish: %u %u" + args: ["x.address", "x.command"] + on_dooya: + then: + - logger.log: + format: "on_dooya: %u %u %u" + args: ["x.channel", "x.button", "x.check"] + on_drayton: + then: + - logger.log: + format: "on_drayton: %u %u %u" + args: ["x.address", "x.channel", "x.command"] + on_jvc: + then: + - logger.log: + format: "on_jvc: %u" + args: ["x.data"] + on_keeloq: + then: + - logger.log: + format: "on_keeloq: %u %u %u" + args: ["x.encrypted", "x.address", "x.command"] + on_haier: + then: + - logger.log: + format: "on_haier: %u" + args: ["x.data.front()"] + on_lg: + then: + - logger.log: + format: "on_lg: %u %u" + args: ["x.data", "x.nbits"] + on_magiquest: + then: + - logger.log: + format: "on_magiquest: %u %u" + args: ["x.magnitude", "x.wand_id"] + on_midea: + then: + - logger.log: + format: "on_midea: %u %u" + args: ["x.size()", "x.data()[0]"] + on_nec: + then: + - logger.log: + format: "on_nec: %u %u" + args: ["x.address", "x.command"] + on_nexa: + then: + - logger.log: + format: "on_nexa: %u %u %u %u %u" + args: ["x.device", "x.group", "x.state", "x.channel", "x.level"] + on_panasonic: + then: + - logger.log: + format: "on_panasonic: %u %u" + args: ["x.address", "x.command"] + on_pioneer: + then: + - logger.log: + format: "on_pioneer: %u %u" + args: ["x.rc_code_1", "x.rc_code_2"] + on_pronto: + then: + - logger.log: + format: "on_pronto: %s" + args: ["x.data.c_str()"] + on_raw: + then: + - logger.log: + format: "on_raw: %u" + args: ["x.front()"] + on_rc5: + then: + - logger.log: + format: "on_rc5: %u %u" + args: ["x.address", "x.command"] + on_rc6: + then: + - logger.log: + format: "on_rc6: %u %u" + args: ["x.address", "x.command"] on_rc_switch: then: - delay: !lambda "return uint32_t(x.code) + x.protocol;" + - logger.log: + format: "on_rc_switch: %llu %u" + args: ["x.code", "x.protocol"] + on_samsung: + then: + - logger.log: + format: "on_samsung: %llu %u" + args: ["x.data", "x.nbits"] + on_samsung36: + then: + - logger.log: + format: "on_samsung36: %u %u" + args: ["x.address", "x.command"] + on_sony: + then: + - logger.log: + format: "on_sony: %u %u" + args: ["x.data", "x.nbits"] + on_toshiba_ac: + then: + - logger.log: + format: "on_toshiba_ac: %llu %llu" + args: ["x.rc_code_1", "x.rc_code_2"] binary_sensor: - platform: remote_receiver diff --git a/tests/components/remote_receiver/test.esp8266.yaml b/tests/components/remote_receiver/test.esp8266.yaml index a7c283da1e..e96f031e90 100644 --- a/tests/components/remote_receiver/test.esp8266.yaml +++ b/tests/components/remote_receiver/test.esp8266.yaml @@ -2,12 +2,146 @@ remote_receiver: id: rcvr pin: GPIO5 dump: all + on_abbwelcome: + then: + - logger.log: + format: "on_abbwelcome: %u" + args: ["x.data()[0]"] + on_aeha: + then: + - logger.log: + format: "on_aeha: %u %u" + args: ["x.address", "x.data.front()"] + on_byronsx: + then: + - logger.log: + format: "on_byronsx: %u %u" + args: ["x.address", "x.command"] + on_canalsat: + then: + - logger.log: + format: "on_canalsat: %u %u" + args: ["x.address", "x.command"] + # on_canalsatld: + # then: + # - logger.log: + # format: "on_canalsatld: %u %u" + # args: ["x.address", "x.command"] on_coolix: then: - delay: !lambda "return x.first + x.second;" + - logger.log: + format: "on_coolix: %u %u" + args: ["x.first", "x.second"] + on_dish: + then: + - logger.log: + format: "on_dish: %u %u" + args: ["x.address", "x.command"] + on_dooya: + then: + - logger.log: + format: "on_dooya: %u %u %u" + args: ["x.channel", "x.button", "x.check"] + on_drayton: + then: + - logger.log: + format: "on_drayton: %u %u %u" + args: ["x.address", "x.channel", "x.command"] + on_jvc: + then: + - logger.log: + format: "on_jvc: %u" + args: ["x.data"] + on_keeloq: + then: + - logger.log: + format: "on_keeloq: %u %u %u" + args: ["x.encrypted", "x.address", "x.command"] + on_haier: + then: + - logger.log: + format: "on_haier: %u" + args: ["x.data.front()"] + on_lg: + then: + - logger.log: + format: "on_lg: %u %u" + args: ["x.data", "x.nbits"] + on_magiquest: + then: + - logger.log: + format: "on_magiquest: %u %u" + args: ["x.magnitude", "x.wand_id"] + on_midea: + then: + - logger.log: + format: "on_midea: %u %u" + args: ["x.size()", "x.data()[0]"] + on_nec: + then: + - logger.log: + format: "on_nec: %u %u" + args: ["x.address", "x.command"] + on_nexa: + then: + - logger.log: + format: "on_nexa: %u %u %u %u %u" + args: ["x.device", "x.group", "x.state", "x.channel", "x.level"] + on_panasonic: + then: + - logger.log: + format: "on_panasonic: %u %u" + args: ["x.address", "x.command"] + on_pioneer: + then: + - logger.log: + format: "on_pioneer: %u %u" + args: ["x.rc_code_1", "x.rc_code_2"] + on_pronto: + then: + - logger.log: + format: "on_pronto: %s" + args: ["x.data.c_str()"] + on_raw: + then: + - logger.log: + format: "on_raw: %u" + args: ["x.front()"] + on_rc5: + then: + - logger.log: + format: "on_rc5: %u %u" + args: ["x.address", "x.command"] + on_rc6: + then: + - logger.log: + format: "on_rc6: %u %u" + args: ["x.address", "x.command"] on_rc_switch: then: - delay: !lambda "return uint32_t(x.code) + x.protocol;" + - logger.log: + format: "on_rc_switch: %llu %u" + args: ["x.code", "x.protocol"] + on_samsung: + then: + - logger.log: + format: "on_samsung: %llu %u" + args: ["x.data", "x.nbits"] + on_samsung36: + then: + - logger.log: + format: "on_samsung36: %u %u" + args: ["x.address", "x.command"] + on_sony: + then: + - logger.log: + format: "on_sony: %u %u" + args: ["x.data", "x.nbits"] + on_toshiba_ac: + then: + - logger.log: + format: "on_toshiba_ac: %llu %llu" + args: ["x.rc_code_1", "x.rc_code_2"] binary_sensor: - platform: remote_receiver From 6370e68670f35b82cd02a29f814a75561d1c856b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 14 Apr 2024 16:38:31 -0500 Subject: [PATCH 1534/2607] Add actions to http_request tests (#6529) --- tests/components/http_request/common.yaml | 37 +++++++++++++++++++ .../http_request/test.esp32-c3.yaml | 9 +---- tests/components/http_request/test.esp32.yaml | 9 +---- .../components/http_request/test.esp8266.yaml | 9 +---- 4 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 tests/components/http_request/common.yaml diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml new file mode 100644 index 0000000000..848fe3f509 --- /dev/null +++ b/tests/components/http_request/common.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - http_request.get: + url: https://esphome.io + headers: + Content-Type: application/json + verify_ssl: false + on_response: + then: + - logger.log: + format: 'Response status: %d, Duration: %u ms' + args: + - status_code + - duration_ms + - http_request.post: + url: https://esphome.io + headers: + Content-Type: application/json + json: + key: value + verify_ssl: false + - http_request.send: + method: PUT + url: https://esphome.io + headers: + Content-Type: application/json + body: "Some data" + verify_ssl: false + +wifi: + ssid: MySSID + password: password1 + +http_request: + useragent: esphome/tagreader + timeout: 10s diff --git a/tests/components/http_request/test.esp32-c3.yaml b/tests/components/http_request/test.esp32-c3.yaml index 19fc6af2c4..25cb37a0b4 100644 --- a/tests/components/http_request/test.esp32-c3.yaml +++ b/tests/components/http_request/test.esp32-c3.yaml @@ -1,7 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -http_request: - useragent: esphome/tagreader - timeout: 10s +packages: + common: !include common.yaml diff --git a/tests/components/http_request/test.esp32.yaml b/tests/components/http_request/test.esp32.yaml index 19fc6af2c4..25cb37a0b4 100644 --- a/tests/components/http_request/test.esp32.yaml +++ b/tests/components/http_request/test.esp32.yaml @@ -1,7 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -http_request: - useragent: esphome/tagreader - timeout: 10s +packages: + common: !include common.yaml diff --git a/tests/components/http_request/test.esp8266.yaml b/tests/components/http_request/test.esp8266.yaml index 19fc6af2c4..25cb37a0b4 100644 --- a/tests/components/http_request/test.esp8266.yaml +++ b/tests/components/http_request/test.esp8266.yaml @@ -1,7 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -http_request: - useragent: esphome/tagreader - timeout: 10s +packages: + common: !include common.yaml From dc200948fa2c779e0c2b2bb4eded62ba347254dc Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:02:19 +1200 Subject: [PATCH 1535/2607] Fix project version longer than 30 characters breaking compilation (#6535) --- esphome/core/base_automation.h | 2 +- esphome/core/config.py | 1 + esphome/core/defines.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index b0ae0aff84..1bf0efb9a4 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -134,7 +134,7 @@ class ProjectUpdateTrigger : public Trigger, public Component { uint32_t hash = fnv1_hash(ESPHOME_PROJECT_NAME); ESPPreferenceObject pref = global_preferences->make_preference(hash, true); char previous_version[30]; - char current_version[30] = ESPHOME_PROJECT_VERSION; + char current_version[30] = ESPHOME_PROJECT_VERSION_30; if (pref.load(&previous_version)) { int cmp = strcmp(previous_version, current_version); if (cmp < 0) { diff --git a/esphome/core/config.py b/esphome/core/config.py index 792f9da6dd..2d87796987 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -394,6 +394,7 @@ async def to_code(config): if project_conf := config.get(CONF_PROJECT): cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME]) cg.add_define("ESPHOME_PROJECT_VERSION", project_conf[CONF_VERSION]) + cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:30]) for conf in project_conf.get(CONF_ON_UPDATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await cg.register_component(trigger, conf) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 22153de5de..f13ae968f0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -11,6 +11,7 @@ #define ESPHOME_BOARD "dummy_board" #define ESPHOME_PROJECT_NAME "dummy project" #define ESPHOME_PROJECT_VERSION "v2" +#define ESPHOME_PROJECT_VERSION_30 "v2" #define ESPHOME_VARIANT "ESP32" // Feature flags From b43ad5da6d91b082290a9fca877c9d182af3185f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 14 Apr 2024 19:25:10 -0500 Subject: [PATCH 1536/2607] Update homeassistant component tests with actions (#6528) --- tests/components/homeassistant/common.yaml | 67 +++++++++++++++++++ .../components/homeassistant/test.bk72xx.yaml | 2 + .../homeassistant/test.esp32-c3-idf.yaml | 41 +----------- .../homeassistant/test.esp32-c3.yaml | 41 +----------- .../homeassistant/test.esp32-idf.yaml | 41 +----------- .../components/homeassistant/test.esp32.yaml | 41 +----------- .../homeassistant/test.esp8266.yaml | 41 +----------- .../components/homeassistant/test.rp2040.yaml | 41 +----------- 8 files changed, 81 insertions(+), 234 deletions(-) create mode 100644 tests/components/homeassistant/common.yaml create mode 100644 tests/components/homeassistant/test.bk72xx.yaml diff --git a/tests/components/homeassistant/common.yaml b/tests/components/homeassistant/common.yaml new file mode 100644 index 0000000000..ae016a3bea --- /dev/null +++ b/tests/components/homeassistant/common.yaml @@ -0,0 +1,67 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.event: + event: esphome.html5 + data: + message: New Humidity + data_template: + message: The humidity is {{ my_variable }}%. + variables: + my_variable: "return id(ha_hello_world_temperature).state;" + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + title: New Humidity + data_template: + message: The humidity is {{ my_variable }}%. + variables: + my_variable: "return id(ha_hello_world_temperature).state;" + +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: homeassistant + entity_id: binary_sensor.hello_world + id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute + +sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature + +text_sensor: + - platform: homeassistant + entity_id: sensor.hello_world + id: ha_hello_world_text + - platform: homeassistant + entity_id: sensor.hello_world1 + id: ha_hello_world_text2 + attribute: some_attribute + +time: + - platform: homeassistant + on_time: + - at: "16:00:00" + then: + - logger.log: It's 16:00 diff --git a/tests/components/homeassistant/test.bk72xx.yaml b/tests/components/homeassistant/test.bk72xx.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/homeassistant/test.bk72xx.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.esp32-c3-idf.yaml b/tests/components/homeassistant/test.esp32-c3-idf.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.esp32-c3-idf.yaml +++ b/tests/components/homeassistant/test.esp32-c3-idf.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.esp32-c3.yaml b/tests/components/homeassistant/test.esp32-c3.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.esp32-c3.yaml +++ b/tests/components/homeassistant/test.esp32-c3.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.esp32-idf.yaml b/tests/components/homeassistant/test.esp32-idf.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.esp32-idf.yaml +++ b/tests/components/homeassistant/test.esp32-idf.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.esp32.yaml b/tests/components/homeassistant/test.esp32.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.esp32.yaml +++ b/tests/components/homeassistant/test.esp32.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.esp8266.yaml b/tests/components/homeassistant/test.esp8266.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.esp8266.yaml +++ b/tests/components/homeassistant/test.esp8266.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml diff --git a/tests/components/homeassistant/test.rp2040.yaml b/tests/components/homeassistant/test.rp2040.yaml index d2608f077c..25cb37a0b4 100644 --- a/tests/components/homeassistant/test.rp2040.yaml +++ b/tests/components/homeassistant/test.rp2040.yaml @@ -1,39 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - -text_sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world_text - - platform: homeassistant - entity_id: sensor.hello_world1 - id: ha_hello_world_text2 - attribute: some_attribute - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 +packages: + common: !include common.yaml From 86f9af13aa1642b58bf2759f2df984e38bc5f11a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:08:35 +1000 Subject: [PATCH 1537/2607] Fix no-release bug on ft6x36 (#6527) --- esphome/components/ft63x6/ft63x6.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/esphome/components/ft63x6/ft63x6.cpp b/esphome/components/ft63x6/ft63x6.cpp index fe64f76fac..e5f7613901 100644 --- a/esphome/components/ft63x6/ft63x6.cpp +++ b/esphome/components/ft63x6/ft63x6.cpp @@ -32,7 +32,7 @@ void FT63X6Touchscreen::setup() { if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); this->interrupt_pin_->setup(); - this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); + this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_ANY_EDGE); } if (this->reset_pin_ != nullptr) { @@ -78,13 +78,12 @@ void FT63X6Touchscreen::update_touches() { uint16_t touch_id, x, y; uint8_t touches = this->read_touch_number_(); + ESP_LOGV(TAG, "Touches found: %d", touches); if ((touches == 0x00) || (touches == 0xff)) { // ESP_LOGD(TAG, "No touches detected"); return; } - ESP_LOGV(TAG, "Touches found: %d", touches); - for (auto point = 0; point < touches; point++) { if (((this->read_touch_event_(point)) & 0x01) == 0) { // checking event flag bit 6 if it is null touch_id = this->read_touch_id_(point); // id1 = 0 or 1 From ff0d33ffe32595402f5cbd4bd4b50853ec673a69 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:19:49 +1200 Subject: [PATCH 1538/2607] Fix missing ifdefs in voice assistant (#6520) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 34a26eec01..e68e00948e 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -729,6 +729,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { +#ifdef USE_SPEAKER // We should never get to this function if there is no speaker anyway if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); this->speaker_buffer_index_ += msg.data.length(); @@ -737,6 +738,7 @@ void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { } else { ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); } +#endif } VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) From ed02747ebc1d5808d13d7010d20116a758fd1447 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:02:19 +1200 Subject: [PATCH 1539/2607] Fix project version longer than 30 characters breaking compilation (#6535) --- esphome/core/base_automation.h | 2 +- esphome/core/config.py | 1 + esphome/core/defines.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index b0ae0aff84..1bf0efb9a4 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -134,7 +134,7 @@ class ProjectUpdateTrigger : public Trigger, public Component { uint32_t hash = fnv1_hash(ESPHOME_PROJECT_NAME); ESPPreferenceObject pref = global_preferences->make_preference(hash, true); char previous_version[30]; - char current_version[30] = ESPHOME_PROJECT_VERSION; + char current_version[30] = ESPHOME_PROJECT_VERSION_30; if (pref.load(&previous_version)) { int cmp = strcmp(previous_version, current_version); if (cmp < 0) { diff --git a/esphome/core/config.py b/esphome/core/config.py index 792f9da6dd..2d87796987 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -394,6 +394,7 @@ async def to_code(config): if project_conf := config.get(CONF_PROJECT): cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME]) cg.add_define("ESPHOME_PROJECT_VERSION", project_conf[CONF_VERSION]) + cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:30]) for conf in project_conf.get(CONF_ON_UPDATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await cg.register_component(trigger, conf) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 22153de5de..f13ae968f0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -11,6 +11,7 @@ #define ESPHOME_BOARD "dummy_board" #define ESPHOME_PROJECT_NAME "dummy project" #define ESPHOME_PROJECT_VERSION "v2" +#define ESPHOME_PROJECT_VERSION_30 "v2" #define ESPHOME_VARIANT "ESP32" // Feature flags From 09fbddea21356d506f68b638c425818fd84df415 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:08:35 +1000 Subject: [PATCH 1540/2607] Fix no-release bug on ft6x36 (#6527) --- esphome/components/ft63x6/ft63x6.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/esphome/components/ft63x6/ft63x6.cpp b/esphome/components/ft63x6/ft63x6.cpp index fe64f76fac..e5f7613901 100644 --- a/esphome/components/ft63x6/ft63x6.cpp +++ b/esphome/components/ft63x6/ft63x6.cpp @@ -32,7 +32,7 @@ void FT63X6Touchscreen::setup() { if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); this->interrupt_pin_->setup(); - this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); + this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_ANY_EDGE); } if (this->reset_pin_ != nullptr) { @@ -78,13 +78,12 @@ void FT63X6Touchscreen::update_touches() { uint16_t touch_id, x, y; uint8_t touches = this->read_touch_number_(); + ESP_LOGV(TAG, "Touches found: %d", touches); if ((touches == 0x00) || (touches == 0xff)) { // ESP_LOGD(TAG, "No touches detected"); return; } - ESP_LOGV(TAG, "Touches found: %d", touches); - for (auto point = 0; point < touches; point++) { if (((this->read_touch_event_(point)) & 0x01) == 0) { // checking event flag bit 6 if it is null touch_id = this->read_touch_id_(point); // id1 = 0 or 1 From b6f1cfd69fbff80979f500d2fdd1fc3beb83dba9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 15 Apr 2024 13:27:01 +1200 Subject: [PATCH 1541/2607] Bump version to 2024.4.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 08a1a42ea3..66da96bc82 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0b2" +__version__ = "2024.4.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6876c65edada3710687260c91302ccfa432d4f08 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Mon, 15 Apr 2024 07:13:31 +0200 Subject: [PATCH 1542/2607] Define `USE_PSRAM` (#6526) --- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h | 5 +++-- esphome/components/psram/__init__.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 0d986804ce..76dee875c5 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -2,6 +2,7 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include @@ -248,11 +249,11 @@ class ESP32BLETracker : public Component, SemaphoreHandle_t scan_result_lock_; SemaphoreHandle_t scan_end_lock_; size_t scan_result_index_{0}; -#if CONFIG_SPIRAM +#ifdef USE_PSRAM const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 32; #else const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 16; -#endif // CONFIG_SPIRAM +#endif // USE_PSRAM esp_ble_gap_cb_param_t::ble_scan_result_evt_param *scan_result_buffer_; esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS}; esp_bt_status_t scan_set_param_failed_{ESP_BT_STATUS_SUCCESS}; diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index f7a2ef7b92..796957c315 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -54,5 +54,7 @@ async def to_code(config): if CONF_SPEED in config: add_idf_sdkconfig_option(f"{SPIRAM_SPEEDS[config[CONF_SPEED]]}", True) + cg.add_define("USE_PSRAM") + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) From b3f02e54cdb07e9536413c0933895fc1392f6386 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 08:58:10 +1200 Subject: [PATCH 1543/2607] Bump black from 24.2.0 to 24.4.0 (#6539) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 8fb59683b4..f94b2a5c51 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==3.0.3 flake8==7.0.0 # also change in .pre-commit-config.yaml when updating -black==24.2.0 # also change in .pre-commit-config.yaml when updating +black==24.4.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.15.1 # also change in .pre-commit-config.yaml when updating pre-commit From cca5f818e53fea55df60668455dde3fd3580d0f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 09:39:27 +1200 Subject: [PATCH 1544/2607] Bump peter-evans/create-pull-request from 6.0.2 to 6.0.3 (#6525) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index c12f1f31b5..6d3449b84a 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.2 + uses: peter-evans/create-pull-request@v6.0.3 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From 27b286b57f832ed7f3b301f6616e912c0bdd5268 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Apr 2024 09:42:15 +1200 Subject: [PATCH 1545/2607] Bump python version in sync-device-classes workflow to 3.12 for HA (#6541) --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 6d3449b84a..62b9c7df9b 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -24,7 +24,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5.1.0 with: - python-version: 3.11 + python-version: 3.12 - name: Install Home Assistant run: | From 01419822f73e8784ed7047950c437b5416efb861 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:59:44 +1200 Subject: [PATCH 1546/2607] Bump pylint from 3.0.3 to 3.1.0 (#6287) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/font/__init__.py | 3 +-- esphome/components/time/__init__.py | 2 +- esphome/loader.py | 13 ++++++++++--- requirements_test.txt | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 76eb05e6ad..b3a5beb199 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -400,8 +400,7 @@ class BitmapFontWrapper: for glyph in glyphs: mask = self.getmask(glyph, mode="1") _, height = mask.size - if height > max_height: - max_height = height + max_height = max(max_height, height) return (max_height, 0) diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index 2bb3a0cd63..c888705ba2 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -49,7 +49,7 @@ def _load_tzdata(iana_key: str) -> Optional[bytes]: package = "tzdata.zoneinfo." + package_loc.replace("/", ".") try: - return resources.read_binary(package, resource) + return (resources.files(package) / resource).read_bytes() except (FileNotFoundError, ModuleNotFoundError): return None diff --git a/esphome/loader.py b/esphome/loader.py index 40a38d0a14..e0457eb425 100644 --- a/esphome/loader.py +++ b/esphome/loader.py @@ -23,7 +23,9 @@ class FileResource: resource: str def path(self) -> ContextManager[Path]: - return importlib.resources.path(self.package, self.resource) + return importlib.resources.as_file( + importlib.resources.files(self.package) / self.resource + ) class ComponentManifest: @@ -101,10 +103,15 @@ class ComponentManifest: loaded .py file (does not look through subdirectories) """ ret = [] - for resource in importlib.resources.contents(self.package): + + for resource in ( + r.name + for r in importlib.resources.files(self.package).iterdir() + if r.is_file() + ): if Path(resource).suffix not in SOURCE_FILE_EXTENSIONS: continue - if not importlib.resources.is_resource(self.package, resource): + if not importlib.resources.files(self.package).joinpath(resource).is_file(): # Not a resource = this is a directory (yeah this is confusing) continue ret.append(FileResource(self.package, resource)) diff --git a/requirements_test.txt b/requirements_test.txt index f94b2a5c51..16e9ec7422 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==3.0.3 +pylint==3.1.0 flake8==7.0.0 # also change in .pre-commit-config.yaml when updating black==24.4.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.15.1 # also change in .pre-commit-config.yaml when updating From 80488a2b721727f4bc9615263feb7515ae87728a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 19:34:56 +0000 Subject: [PATCH 1547/2607] Bump aioesphomeapi from 23.2.0 to 24.0.0 (#6544) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4abc4d98d2..7424267d08 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240412.0 -aioesphomeapi==23.2.0 +aioesphomeapi==24.0.0 zeroconf==0.131.0 python-magic==0.4.27 ruamel.yaml==0.18.6 # dashboard_import From 7d99676fe88858ef29e7bd21c81eb5b1bebb8349 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 19:50:22 +0000 Subject: [PATCH 1548/2607] Bump pyupgrade from 3.15.1 to 3.15.2 (#6543) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7865c52abd..69aafd4d15 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - --branch=release - --branch=beta - repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 + rev: v3.15.2 hooks: - id: pyupgrade args: [--py39-plus] diff --git a/requirements_test.txt b/requirements_test.txt index 16e9ec7422..767018d07a 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ pylint==3.1.0 flake8==7.0.0 # also change in .pre-commit-config.yaml when updating black==24.4.0 # also change in .pre-commit-config.yaml when updating -pyupgrade==3.15.1 # also change in .pre-commit-config.yaml when updating +pyupgrade==3.15.2 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests From 6a1ea0674469a5c487ee3b83da40e96f6dac792f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:04:10 +1200 Subject: [PATCH 1549/2607] Add enum option to typed_schema (#6546) * Add enum option to typed_schema * Assert keys all match --- esphome/config_validation.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 358608cd35..bc58979f33 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1590,6 +1590,10 @@ def typed_schema(schemas, **kwargs): """Create a schema that has a key to distinguish between schemas""" key = kwargs.pop("key", CONF_TYPE) default_schema_option = kwargs.pop("default_type", None) + enum_mapping = kwargs.pop("enum", None) + if enum_mapping is not None: + assert isinstance(enum_mapping, dict) + assert set(enum_mapping.keys()) == set(schemas.keys()) key_validator = one_of(*schemas, **kwargs) def validator(value): @@ -1600,6 +1604,9 @@ def typed_schema(schemas, **kwargs): if schema_option is None: raise Invalid(f"{key} not specified!") key_v = key_validator(schema_option) + if enum_mapping is not None: + key_v = add_class_to_obj(key_v, core.EnumValue) + key_v.enum_value = enum_mapping[key_v] value = Schema(schemas[key_v])(value) value[key] = key_v return value From f2a12589f3619601ade5f698a9c2f75f1d980ba3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 13:08:27 +1200 Subject: [PATCH 1550/2607] Bump version to 2024.4.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 66da96bc82..76320e6c71 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0b3" +__version__ = "2024.4.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 0af26fdfd41671b571755ea906c744f7d1a3fc2c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:43:29 +1200 Subject: [PATCH 1551/2607] Move esphome-fork startup script to main repo. (#6523) Co-authored-by: Blair McBride --- .../etc/cont-init.d/30-esphome-fork.sh | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 docker/ha-addon-rootfs/etc/cont-init.d/30-esphome-fork.sh diff --git a/docker/ha-addon-rootfs/etc/cont-init.d/30-esphome-fork.sh b/docker/ha-addon-rootfs/etc/cont-init.d/30-esphome-fork.sh new file mode 100755 index 0000000000..03dbb34c8f --- /dev/null +++ b/docker/ha-addon-rootfs/etc/cont-init.d/30-esphome-fork.sh @@ -0,0 +1,47 @@ +#!/usr/bin/with-contenv bashio +# ============================================================================== +# This file installs the user ESPHome fork if specified. +# The fork must be up to date with the latest ESPHome dev branch +# and have no conflicts. +# This config option only exists in the ESPHome Dev add-on. +# ============================================================================== + +declare esphome_fork + +if bashio::config.has_value 'esphome_fork'; then + esphome_fork=$(bashio::config 'esphome_fork') + # format: [username][/repository]:ref + if [[ "$esphome_fork" =~ ^(([^/]+)(/([^:]+))?:)?([^:/]+)$ ]]; then + username="${BASH_REMATCH[2]:-esphome}" + repository="${BASH_REMATCH[4]:-esphome}" + ref="${BASH_REMATCH[5]}" + else + bashio::exit.nok "Invalid esphome_fork format: $esphome_fork" + fi + full_url="https://github.com/${username}/${repository}/archive/${ref}.tar.gz" + bashio::log.info "Checking forked ESPHome" + dev_version=$(python3 -c "from esphome.const import __version__; print(__version__)") + bashio::log.info "Downloading ESPHome from fork '${esphome_fork}' (${full_url})..." + curl -L -o /tmp/esphome.tar.gz "${full_url}" -qq || + bashio::exit.nok "Failed downloading ESPHome fork." + bashio::log.info "Installing ESPHome from fork '${esphome_fork}' (${full_url})..." + rm -rf /esphome || bashio::exit.nok "Failed to remove ESPHome." + mkdir /esphome + tar -zxf /tmp/esphome.tar.gz -C /esphome --strip-components=1 || + bashio::exit.nok "Failed installing ESPHome from fork." + pip install -U -e /esphome || bashio::exit.nok "Failed installing ESPHome from fork." + rm -f /tmp/esphome.tar.gz + fork_version=$(python3 -c "from esphome.const import __version__; print(__version__)") + + if [[ "$fork_version" != "$dev_version" ]]; then + bashio::log.error "############################" + bashio::log.error "Uninstalled fork as version does not match" + bashio::log.error "Update (or ask the author to update) the branch" + bashio::log.error "This is important as the dev addon and the dev ESPHome" + bashio::log.error "branch can have changes that are not compatible with old forks" + bashio::log.error "and get reported as bugs which we cannot solve easily." + bashio::log.error "############################" + bashio::exit.nok + fi + bashio::log.info "Installed ESPHome from fork '${esphome_fork}' (${full_url})..." +fi From ca5d38f413f3b7d723ed376a2f7a0da968c95669 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:32:19 +1200 Subject: [PATCH 1552/2607] Call workflow for addon with dev version (#6549) --- .github/workflows/release.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c0ec0270b..2e1177d13f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,14 +17,16 @@ jobs: runs-on: ubuntu-latest outputs: tag: ${{ steps.tag.outputs.tag }} + branch_build: ${{ steps.tag.outputs.branch_build }} steps: - uses: actions/checkout@v4.1.1 - name: Get tag id: tag # yamllint disable rule:line-length run: | - if [[ "$GITHUB_EVENT_NAME" = "release" ]]; then - TAG="${GITHUB_REF#refs/tags/}" + if [[ "${{ github.event_name }}" = "release" ]]; then + TAG="${{ github.event.release.tag_name}}" + BRANCH_BUILD="false" else TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p") today="$(date --utc '+%Y%m%d')" @@ -32,9 +34,13 @@ jobs: BRANCH=${GITHUB_REF#refs/heads/} if [[ "$BRANCH" != "dev" ]]; then TAG="${TAG}-${BRANCH}" + BRANCH_BUILD="true" + else + BRANCH_BUILD="false" fi fi echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "branch_build=${BRANCH_BUILD}" >> $GITHUB_OUTPUT # yamllint enable rule:line-length deploy-pypi: @@ -197,22 +203,28 @@ jobs: $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *) deploy-ha-addon-repo: - if: github.repository == 'esphome/esphome' && github.event_name == 'release' + if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false' runs-on: ubuntu-latest - needs: [deploy-manifest] + needs: + - init + - deploy-manifest steps: - name: Trigger Workflow uses: actions/github-script@v7.0.1 with: github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }} script: | + let description = "ESPHome"; + if (context.eventName == "release") { + description = ${{ toJSON(github.event.release.body) }}; + } github.rest.actions.createWorkflowDispatch({ owner: "esphome", repo: "home-assistant-addon", workflow_id: "bump-version.yml", ref: "main", inputs: { - version: "${{ github.event.release.tag_name }}", - content: ${{ toJSON(github.event.release.body) }} + version: "${{ needs.init.outputs.tag }}", + content: description } }) From 83feae4eb2b043f63e710acdc2959143cb746fc8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:55:13 +1200 Subject: [PATCH 1553/2607] Use trusted publishing token for pypi (#6545) --- .github/workflows/release.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e1177d13f..72b06ab4fe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,6 +47,9 @@ jobs: name: Build and publish to PyPi if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - uses: actions/checkout@v4.1.1 - name: Set up Python @@ -56,16 +59,11 @@ jobs: - name: Set up python environment env: ESPHOME_NO_VENV: 1 - run: | - script/setup - pip install twine + run: script/setup - name: Build run: python setup.py sdist bdist_wheel - - name: Upload - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - run: twine upload dist/* + - name: Publish + uses: pypa/gh-action-pypi-publish@v1.8.14 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From 6104e7591eb02d1e530241998600c89c0a8a2869 Mon Sep 17 00:00:00 2001 From: luar123 <49960470+luar123@users.noreply.github.com> Date: Wed, 17 Apr 2024 06:57:26 +0200 Subject: [PATCH 1554/2607] Fix uart to work with new enum definition in esp-idf-v5.2.1 (#6487) --- esphome/components/logger/logger_esp32.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index 740e086f92..b0f1051d34 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -120,30 +120,28 @@ void Logger::pre_setup() { switch (this->uart_) { case UART_SELECTION_UART0: this->uart_num_ = UART_NUM_0; + init_uart(this->uart_num_, baud_rate_, tx_buffer_size_); break; case UART_SELECTION_UART1: this->uart_num_ = UART_NUM_1; + init_uart(this->uart_num_, baud_rate_, tx_buffer_size_); break; #ifdef USE_ESP32_VARIANT_ESP32 case UART_SELECTION_UART2: this->uart_num_ = UART_NUM_2; + init_uart(this->uart_num_, baud_rate_, tx_buffer_size_); break; #endif #ifdef USE_LOGGER_USB_CDC case UART_SELECTION_USB_CDC: - this->uart_num_ = -1; break; #endif #ifdef USE_LOGGER_USB_SERIAL_JTAG case UART_SELECTION_USB_SERIAL_JTAG: - this->uart_num_ = -1; init_usb_serial_jtag_(); break; #endif } - if (this->uart_num_ >= 0) { - init_uart(this->uart_num_, baud_rate_, tx_buffer_size_); - } #endif // USE_ESP_IDF } From 717cea548f99b0953853378bdaec889d2c0812b4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:42:40 +1200 Subject: [PATCH 1555/2607] Housecleaning: Use walrus operator in datetime (#6552) --- esphome/components/datetime/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index b255a27303..a22c60aae9 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -106,8 +106,8 @@ def datetime_schema(class_: MockObjClass) -> cv.Schema: async def setup_datetime_core_(var, config): await setup_entity(var, config) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) for conf in config.get(CONF_ON_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) From 2fc2d5839fabdd47fdf2154d4d216a9a8adc5b2b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:22:52 +1200 Subject: [PATCH 1556/2607] Housecleaning: Use walrus operator in text (#6560) --- esphome/components/text/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index 21c23ce73b..c0140ff082 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -73,8 +73,8 @@ async def setup_text_core_( trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.std_string, "x")], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) From 3f015562d7109d3c245fcf38ab9bc150390dbce8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:26:36 +1200 Subject: [PATCH 1557/2607] Housecleaning: Use walrus operator in light (#6556) --- esphome/components/light/__init__.py | 34 +++++++++++++--------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index ba3a26ebe5..fdc4676758 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -137,18 +137,16 @@ async def setup_light_core_(light_var, output_var, config): cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE])) - if CONF_DEFAULT_TRANSITION_LENGTH in config: - cg.add( - light_var.set_default_transition_length( - config[CONF_DEFAULT_TRANSITION_LENGTH] - ) - ) - if CONF_FLASH_TRANSITION_LENGTH in config: - cg.add( - light_var.set_flash_transition_length(config[CONF_FLASH_TRANSITION_LENGTH]) - ) - if CONF_GAMMA_CORRECT in config: - cg.add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT])) + if ( + default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH) + ) is not None: + cg.add(light_var.set_default_transition_length(default_transition_length)) + if ( + flash_transition_length := config.get(CONF_FLASH_TRANSITION_LENGTH) + ) is not None: + cg.add(light_var.set_flash_transition_length(flash_transition_length)) + if (gamma_correct := config.get(CONF_GAMMA_CORRECT)) is not None: + cg.add(light_var.set_gamma_correct(gamma_correct)) effects = await cg.build_registry_list( EFFECTS_REGISTRY, config.get(CONF_EFFECTS, []) ) @@ -164,15 +162,15 @@ async def setup_light_core_(light_var, output_var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_var) await auto.build_automation(trigger, [], conf) - if CONF_COLOR_CORRECT in config: - cg.add(output_var.set_correction(*config[CONF_COLOR_CORRECT])) + if (color_correct := config.get(CONF_COLOR_CORRECT)) is not None: + cg.add(output_var.set_correction(*color_correct)) - if CONF_POWER_SUPPLY in config: - var_ = await cg.get_variable(config[CONF_POWER_SUPPLY]) + if (power_supply_id := config.get(CONF_POWER_SUPPLY)) is not None: + var_ = await cg.get_variable(power_supply_id) cg.add(output_var.set_power_supply(var_)) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], light_var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, light_var) await mqtt.register_mqtt_component(mqtt_, config) From 8eff3435e74194a02aa5b16c2508e996c1c90416 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:26:49 +1200 Subject: [PATCH 1558/2607] Housecleaning: Use walrus operator in select (#6557) --- esphome/components/select/__init__.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index 760f7600b7..7ad14f2440 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -95,8 +95,8 @@ async def setup_select_core_(var, config, *, options: list[str]): trigger, [(cg.std_string, "x"), (cg.size_t, "i")], conf ) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) @@ -223,14 +223,14 @@ async def select_set_index_to_code(config, action_id, template_arg, args): async def select_operation_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_OPERATION in config: - op_ = await cg.templatable(config[CONF_OPERATION], args, SelectOperation) + if (operation := config.get(CONF_OPERATION)) is not None: + op_ = await cg.templatable(operation, args, SelectOperation) cg.add(var.set_operation(op_)) - if CONF_CYCLE in config: - cycle_ = await cg.templatable(config[CONF_CYCLE], args, bool) - cg.add(var.set_cycle(cycle_)) - if CONF_MODE in config: - cg.add(var.set_operation(SELECT_OPERATION_OPTIONS[config[CONF_MODE]])) - if CONF_CYCLE in config: - cg.add(var.set_cycle(config[CONF_CYCLE])) + if (cycle := config.get(CONF_CYCLE)) is not None: + template_ = await cg.templatable(cycle, args, bool) + cg.add(var.set_cycle(template_)) + if (mode := config.get(CONF_MODE)) is not None: + cg.add(var.set_operation(SELECT_OPERATION_OPTIONS[mode])) + if (cycle := config.get(CONF_CYCLE)) is not None: + cg.add(var.set_cycle(cycle)) return var From 21e3faad3876fdbc194b344da4bace6ff01d82d7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:27:04 +1200 Subject: [PATCH 1559/2607] Housecleaning: Use walrus operator in number (#6561) --- esphome/components/number/__init__.py | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index ecc2ab2ee7..6d7ec97c90 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -239,13 +239,14 @@ async def setup_number_core_( cg.add(trigger.set_max(template_)) await automation.build_automation(trigger, [(float, "x")], conf) - if CONF_UNIT_OF_MEASUREMENT in config: - cg.add(var.traits.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (unit_of_measurement := config.get(CONF_UNIT_OF_MEASUREMENT)) is not None: + cg.add(var.traits.set_unit_of_measurement(unit_of_measurement)) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.traits.set_device_class(device_class)) + + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.traits.set_device_class(config[CONF_DEVICE_CLASS])) async def register_number( @@ -284,10 +285,10 @@ async def number_in_range_to_code(config, condition_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(condition_id, template_arg, paren) - if CONF_ABOVE in config: - cg.add(var.set_min(config[CONF_ABOVE])) - if CONF_BELOW in config: - cg.add(var.set_max(config[CONF_BELOW])) + if (above := config.get(CONF_ABOVE)) is not None: + cg.add(var.set_min(above)) + if (below := config.get(CONF_BELOW)) is not None: + cg.add(var.set_max(below)) return var @@ -391,14 +392,14 @@ async def number_set_to_code(config, action_id, template_arg, args): async def number_to_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_OPERATION in config: - to_ = await cg.templatable(config[CONF_OPERATION], args, NumberOperation) + if (operation := config.get(CONF_OPERATION)) is not None: + to_ = await cg.templatable(operation, args, NumberOperation) cg.add(var.set_operation(to_)) - if CONF_CYCLE in config: - cycle_ = await cg.templatable(config[CONF_CYCLE], args, bool) - cg.add(var.set_cycle(cycle_)) - if CONF_MODE in config: - cg.add(var.set_operation(NUMBER_OPERATION_OPTIONS[config[CONF_MODE]])) - if CONF_CYCLE in config: - cg.add(var.set_cycle(config[CONF_CYCLE])) + if (cycle := config.get(CONF_CYCLE)) is not None: + template_ = await cg.templatable(cycle, args, bool) + cg.add(var.set_cycle(template_)) + if (mode := config.get(CONF_MODE)) is not None: + cg.add(var.set_operation(NUMBER_OPERATION_OPTIONS[mode])) + if (cycle := config.get(CONF_CYCLE)) is not None: + cg.add(var.set_cycle(cycle)) return var From fa1adf752816555e28fc4a055161430730d26c8a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:28:01 +1200 Subject: [PATCH 1560/2607] Housecleaning: Use walrus operator in cover (#6562) --- esphome/components/cover/__init__.py | 48 +++++++++++++--------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 90e5ee1f03..8e0371017d 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -122,8 +122,8 @@ COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex async def setup_cover_core_(var, config): await setup_entity(var, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.set_device_class(device_class)) for conf in config.get(CONF_ON_OPEN, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) @@ -132,24 +132,20 @@ async def setup_cover_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_POSITION_STATE_TOPIC in config: - cg.add( - mqtt_.set_custom_position_state_topic(config[CONF_POSITION_STATE_TOPIC]) - ) - if CONF_POSITION_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_position_command_topic( - config[CONF_POSITION_COMMAND_TOPIC] - ) - ) - if CONF_TILT_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_tilt_state_topic(config[CONF_TILT_STATE_TOPIC])) - if CONF_TILT_COMMAND_TOPIC in config: - cg.add(mqtt_.set_custom_tilt_command_topic(config[CONF_TILT_COMMAND_TOPIC])) + if (position_state_topic := config.get(CONF_POSITION_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_position_state_topic(position_state_topic)) + if ( + position_command_topic := config.get(CONF_POSITION_COMMAND_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_position_command_topic(position_command_topic)) + if (tilt_state_topic := config.get(CONF_TILT_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_tilt_state_topic(tilt_state_topic)) + if (tilt_command_topic := config.get(CONF_TILT_COMMAND_TOPIC)) is not None: + cg.add(mqtt_.set_custom_tilt_command_topic(tilt_command_topic)) async def register_cover(var, config): @@ -205,17 +201,17 @@ COVER_CONTROL_ACTION_SCHEMA = cv.Schema( async def cover_control_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_STOP in config: - template_ = await cg.templatable(config[CONF_STOP], args, bool) + if (stop := config.get(CONF_STOP)) is not None: + template_ = await cg.templatable(stop, args, bool) cg.add(var.set_stop(template_)) - if CONF_STATE in config: - template_ = await cg.templatable(config[CONF_STATE], args, float) + if (state := config.get(CONF_STATE)) is not None: + template_ = await cg.templatable(state, args, float) cg.add(var.set_position(template_)) - if CONF_POSITION in config: - template_ = await cg.templatable(config[CONF_POSITION], args, float) + if (position := config.get(CONF_POSITION)) is not None: + template_ = await cg.templatable(position, args, float) cg.add(var.set_position(template_)) - if CONF_TILT in config: - template_ = await cg.templatable(config[CONF_TILT], args, float) + if (tilt := config.get(CONF_TILT)) is not None: + template_ = await cg.templatable(tilt, args, float) cg.add(var.set_tilt(template_)) return var From 77ade12ee9e3a62b708fad712d90e9364a9cedfa Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:58:20 +1200 Subject: [PATCH 1561/2607] Housecleaning: Use walrus operator in climate (#6551) --- esphome/components/climate/__init__.py | 218 +++++++++++++------------ 1 file changed, 118 insertions(+), 100 deletions(-) diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index c9c3900a0c..7b0a27feae 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -244,122 +244,150 @@ async def setup_climate_core_(var, config): await setup_entity(var, config) visual = config[CONF_VISUAL] - if CONF_MIN_TEMPERATURE in visual: - cg.add(var.set_visual_min_temperature_override(visual[CONF_MIN_TEMPERATURE])) - if CONF_MAX_TEMPERATURE in visual: - cg.add(var.set_visual_max_temperature_override(visual[CONF_MAX_TEMPERATURE])) - if CONF_TEMPERATURE_STEP in visual: + if (min_temp := visual.get(CONF_MIN_TEMPERATURE)) is not None: + cg.add(var.set_visual_min_temperature_override(min_temp)) + if (max_temp := visual.get(CONF_MAX_TEMPERATURE)) is not None: + cg.add(var.set_visual_max_temperature_override(max_temp)) + if (temp_step := visual.get(CONF_TEMPERATURE_STEP)) is not None: cg.add( var.set_visual_temperature_step_override( - visual[CONF_TEMPERATURE_STEP][CONF_TARGET_TEMPERATURE], - visual[CONF_TEMPERATURE_STEP][CONF_CURRENT_TEMPERATURE], + temp_step[CONF_TARGET_TEMPERATURE], + temp_step[CONF_CURRENT_TEMPERATURE], ) ) - if CONF_MIN_HUMIDITY in visual: - cg.add(var.set_visual_min_humidity_override(visual[CONF_MIN_HUMIDITY])) - if CONF_MAX_HUMIDITY in visual: - cg.add(var.set_visual_max_humidity_override(visual[CONF_MAX_HUMIDITY])) + if (min_humidity := visual.get(CONF_MIN_HUMIDITY)) is not None: + cg.add(var.set_visual_min_humidity_override(min_humidity)) + if (max_humidity := visual.get(CONF_MAX_HUMIDITY)) is not None: + cg.add(var.set_visual_max_humidity_override(max_humidity)) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_ACTION_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_action_state_topic(config[CONF_ACTION_STATE_TOPIC])) - if CONF_AWAY_COMMAND_TOPIC in config: - cg.add(mqtt_.set_custom_away_command_topic(config[CONF_AWAY_COMMAND_TOPIC])) - if CONF_AWAY_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_away_state_topic(config[CONF_AWAY_STATE_TOPIC])) - if CONF_CURRENT_TEMPERATURE_STATE_TOPIC in config: + if (action_state_topic := config.get(CONF_ACTION_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_action_state_topic(action_state_topic)) + if (away_command_topic := config.get(CONF_AWAY_COMMAND_TOPIC)) is not None: + cg.add(mqtt_.set_custom_away_command_topic(away_command_topic)) + if (away_state_topic := config.get(CONF_AWAY_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_away_state_topic(away_state_topic)) + if ( + current_temperature_state_topic := config.get( + CONF_CURRENT_TEMPERATURE_STATE_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_current_temperature_state_topic( - config[CONF_CURRENT_TEMPERATURE_STATE_TOPIC] + current_temperature_state_topic ) ) - if CONF_CURRENT_HUMIDITY_STATE_TOPIC in config: + if ( + current_humidity_state_topic := config.get( + CONF_CURRENT_HUMIDITY_STATE_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_current_humidity_state_topic( - config[CONF_CURRENT_HUMIDITY_STATE_TOPIC] + current_humidity_state_topic ) ) - if CONF_FAN_MODE_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_fan_mode_command_topic( - config[CONF_FAN_MODE_COMMAND_TOPIC] - ) + if ( + fan_mode_command_topic := config.get(CONF_FAN_MODE_COMMAND_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_fan_mode_command_topic(fan_mode_command_topic)) + if (fan_mode_state_topic := config.get(CONF_FAN_MODE_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_fan_mode_state_topic(fan_mode_state_topic)) + if (mode_command_topic := config.get(CONF_MODE_COMMAND_TOPIC)) is not None: + cg.add(mqtt_.set_custom_mode_command_topic(mode_command_topic)) + if (mode_state_topic := config.get(CONF_MODE_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_mode_state_topic(mode_state_topic)) + if (preset_command_topic := config.get(CONF_PRESET_COMMAND_TOPIC)) is not None: + cg.add(mqtt_.set_custom_preset_command_topic(preset_command_topic)) + if (preset_state_topic := config.get(CONF_PRESET_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_preset_state_topic(preset_state_topic)) + if ( + swing_mode_command_topic := config.get(CONF_SWING_MODE_COMMAND_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_swing_mode_command_topic(swing_mode_command_topic)) + if ( + swing_mode_state_topic := config.get(CONF_SWING_MODE_STATE_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_swing_mode_state_topic(swing_mode_state_topic)) + if ( + target_temperature_command_topic := config.get( + CONF_TARGET_TEMPERATURE_COMMAND_TOPIC ) - if CONF_FAN_MODE_STATE_TOPIC in config: - cg.add( - mqtt_.set_custom_fan_mode_state_topic(config[CONF_FAN_MODE_STATE_TOPIC]) - ) - if CONF_MODE_COMMAND_TOPIC in config: - cg.add(mqtt_.set_custom_mode_command_topic(config[CONF_MODE_COMMAND_TOPIC])) - if CONF_MODE_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_mode_state_topic(config[CONF_MODE_STATE_TOPIC])) - if CONF_PRESET_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_preset_command_topic(config[CONF_PRESET_COMMAND_TOPIC]) - ) - if CONF_PRESET_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_preset_state_topic(config[CONF_PRESET_STATE_TOPIC])) - if CONF_SWING_MODE_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_swing_mode_command_topic( - config[CONF_SWING_MODE_COMMAND_TOPIC] - ) - ) - if CONF_SWING_MODE_STATE_TOPIC in config: - cg.add( - mqtt_.set_custom_swing_mode_state_topic( - config[CONF_SWING_MODE_STATE_TOPIC] - ) - ) - if CONF_TARGET_TEMPERATURE_COMMAND_TOPIC in config: + ) is not None: cg.add( mqtt_.set_custom_target_temperature_command_topic( - config[CONF_TARGET_TEMPERATURE_COMMAND_TOPIC] + target_temperature_command_topic ) ) - if CONF_TARGET_TEMPERATURE_STATE_TOPIC in config: + if ( + target_temperature_state_topic := config.get( + CONF_TARGET_TEMPERATURE_STATE_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_temperature_state_topic( - config[CONF_TARGET_TEMPERATURE_STATE_TOPIC] + target_temperature_state_topic ) ) - if CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC in config: + if ( + target_temperature_high_command_topic := config.get( + CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_temperature_high_command_topic( - config[CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC] + target_temperature_high_command_topic ) ) - if CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC in config: + if ( + target_temperature_high_state_topic := config.get( + CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_temperature_high_state_topic( - config[CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC] + target_temperature_high_state_topic ) ) - if CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC in config: + if ( + target_temperature_low_command_topic := config.get( + CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_temperature_low_command_topic( - config[CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC] + target_temperature_low_command_topic ) ) - if CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC in config: + if ( + target_temperature_low_state_topic := config.get( + CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_temperature_state_topic( - config[CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC] + target_temperature_low_state_topic ) ) - if CONF_TARGET_HUMIDITY_COMMAND_TOPIC in config: + if ( + target_humidity_command_topic := config.get( + CONF_TARGET_HUMIDITY_COMMAND_TOPIC + ) + ) is not None: cg.add( mqtt_.set_custom_target_humidity_command_topic( - config[CONF_TARGET_HUMIDITY_COMMAND_TOPIC] + target_humidity_command_topic ) ) - if CONF_TARGET_HUMIDITY_STATE_TOPIC in config: + if ( + target_humidity_state_topic := config.get(CONF_TARGET_HUMIDITY_STATE_TOPIC) + ) is not None: cg.add( mqtt_.set_custom_target_humidity_state_topic( - config[CONF_TARGET_HUMIDITY_STATE_TOPIC] + target_humidity_state_topic ) ) @@ -411,45 +439,35 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema( async def climate_control_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_MODE in config: - template_ = await cg.templatable(config[CONF_MODE], args, ClimateMode) + if (mode := config.get(CONF_MODE)) is not None: + template_ = await cg.templatable(mode, args, ClimateMode) cg.add(var.set_mode(template_)) - if CONF_TARGET_TEMPERATURE in config: - template_ = await cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float) + if (target_temp := config.get(CONF_TARGET_TEMPERATURE)) is not None: + template_ = await cg.templatable(target_temp, args, float) cg.add(var.set_target_temperature(template_)) - if CONF_TARGET_TEMPERATURE_LOW in config: - template_ = await cg.templatable( - config[CONF_TARGET_TEMPERATURE_LOW], args, float - ) + if (target_temp_low := config.get(CONF_TARGET_TEMPERATURE_LOW)) is not None: + template_ = await cg.templatable(target_temp_low, args, float) cg.add(var.set_target_temperature_low(template_)) - if CONF_TARGET_TEMPERATURE_HIGH in config: - template_ = await cg.templatable( - config[CONF_TARGET_TEMPERATURE_HIGH], args, float - ) + if (target_temp_high := config.get(CONF_TARGET_TEMPERATURE_HIGH)) is not None: + template_ = await cg.templatable(target_temp_high, args, float) cg.add(var.set_target_temperature_high(template_)) - if CONF_TARGET_HUMIDITY in config: - template_ = await cg.templatable(config[CONF_TARGET_HUMIDITY], args, float) + if (target_humidity := config.get(CONF_TARGET_HUMIDITY)) is not None: + template_ = await cg.templatable(target_humidity, args, float) cg.add(var.set_target_humidity(template_)) - if CONF_FAN_MODE in config: - template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode) + if (fan_mode := config.get(CONF_FAN_MODE)) is not None: + template_ = await cg.templatable(fan_mode, args, ClimateFanMode) cg.add(var.set_fan_mode(template_)) - if CONF_CUSTOM_FAN_MODE in config: - template_ = await cg.templatable( - config[CONF_CUSTOM_FAN_MODE], args, cg.std_string - ) + if (custom_fan_mode := config.get(CONF_CUSTOM_FAN_MODE)) is not None: + template_ = await cg.templatable(custom_fan_mode, args, cg.std_string) cg.add(var.set_custom_fan_mode(template_)) - if CONF_PRESET in config: - template_ = await cg.templatable(config[CONF_PRESET], args, ClimatePreset) + if (preset := config.get(CONF_PRESET)) is not None: + template_ = await cg.templatable(preset, args, ClimatePreset) cg.add(var.set_preset(template_)) - if CONF_CUSTOM_PRESET in config: - template_ = await cg.templatable( - config[CONF_CUSTOM_PRESET], args, cg.std_string - ) + if (custom_preset := config.get(CONF_CUSTOM_PRESET)) is not None: + template_ = await cg.templatable(custom_preset, args, cg.std_string) cg.add(var.set_custom_preset(template_)) - if CONF_SWING_MODE in config: - template_ = await cg.templatable( - config[CONF_SWING_MODE], args, ClimateSwingMode - ) + if (swing_mode := config.get(CONF_SWING_MODE)) is not None: + template_ = await cg.templatable(swing_mode, args, ClimateSwingMode) cg.add(var.set_swing_mode(template_)) return var From 214c237c8dc978970fcff7cf958043c3abe36ef2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:03:57 +1200 Subject: [PATCH 1562/2607] Housecleaning: Use walrus operator in fan (#6555) Co-authored-by: Keith Burzinski --- esphome/components/fan/__init__.py | 62 ++++++++++++++---------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 05e276d987..14cf6cc9c9 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -180,40 +180,34 @@ async def setup_fan_core_(var, config): cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_OSCILLATION_STATE_TOPIC in config: + if ( + oscillation_state_topic := config.get(CONF_OSCILLATION_STATE_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_oscillation_state_topic(oscillation_state_topic)) + if ( + oscillation_command_topic := config.get(CONF_OSCILLATION_COMMAND_TOPIC) + ) is not None: cg.add( - mqtt_.set_custom_oscillation_state_topic( - config[CONF_OSCILLATION_STATE_TOPIC] - ) + mqtt_.set_custom_oscillation_command_topic(oscillation_command_topic) ) - if CONF_OSCILLATION_COMMAND_TOPIC in config: + if ( + speed_level_state_topic := config.get(CONF_SPEED_LEVEL_STATE_TOPIC) + ) is not None: + cg.add(mqtt_.set_custom_speed_level_state_topic(speed_level_state_topic)) + if ( + speed_level_command_topic := config.get(CONF_SPEED_LEVEL_COMMAND_TOPIC) + ) is not None: cg.add( - mqtt_.set_custom_oscillation_command_topic( - config[CONF_OSCILLATION_COMMAND_TOPIC] - ) - ) - if CONF_SPEED_LEVEL_STATE_TOPIC in config: - cg.add( - mqtt_.set_custom_speed_level_state_topic( - config[CONF_SPEED_LEVEL_STATE_TOPIC] - ) - ) - if CONF_SPEED_LEVEL_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_speed_level_command_topic( - config[CONF_SPEED_LEVEL_COMMAND_TOPIC] - ) - ) - if CONF_SPEED_STATE_TOPIC in config: - cg.add(mqtt_.set_custom_speed_state_topic(config[CONF_SPEED_STATE_TOPIC])) - if CONF_SPEED_COMMAND_TOPIC in config: - cg.add( - mqtt_.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC]) + mqtt_.set_custom_speed_level_command_topic(speed_level_command_topic) ) + if (speed_state_topic := config.get(CONF_SPEED_STATE_TOPIC)) is not None: + cg.add(mqtt_.set_custom_speed_state_topic(speed_state_topic)) + if (speed_command_topic := config.get(CONF_SPEED_COMMAND_TOPIC)) is not None: + cg.add(mqtt_.set_custom_speed_command_topic(speed_command_topic)) for conf in config.get(CONF_ON_STATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) @@ -288,14 +282,14 @@ async def fan_turn_off_to_code(config, action_id, template_arg, args): async def fan_turn_on_to_code(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - if CONF_OSCILLATING in config: - template_ = await cg.templatable(config[CONF_OSCILLATING], args, bool) + if (oscillating := config.get(CONF_OSCILLATING)) is not None: + template_ = await cg.templatable(oscillating, args, bool) cg.add(var.set_oscillating(template_)) - if CONF_SPEED in config: - template_ = await cg.templatable(config[CONF_SPEED], args, int) + if (speed := config.get(CONF_SPEED)) is not None: + template_ = await cg.templatable(speed, args, int) cg.add(var.set_speed(template_)) - if CONF_DIRECTION in config: - template_ = await cg.templatable(config[CONF_DIRECTION], args, FanDirection) + if (direction := config.get(CONF_DIRECTION)) is not None: + template_ = await cg.templatable(direction, args, FanDirection) cg.add(var.set_direction(template_)) return var From 7733781e091199d3638e1fa78a181eefff4b2b19 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:51:33 +1200 Subject: [PATCH 1563/2607] Housecleaning: Use walrus operator in text_sensor (#6559) --- esphome/components/text_sensor/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index cf7d23aec7..6c28b57b3d 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -186,8 +186,8 @@ async def build_filters(config): async def setup_text_sensor_core_(var, config): await setup_entity(var, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.set_device_class(device_class)) if config.get(CONF_FILTERS): # must exist and not be empty filters = await build_filters(config[CONF_FILTERS]) @@ -201,8 +201,8 @@ async def setup_text_sensor_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.std_string, "x")], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) From 987ffcbaba01be4642c36b68fc14e02bae553103 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 17 Apr 2024 16:09:42 -0500 Subject: [PATCH 1564/2607] Bump zeroconf to 0.132.2 (#6548) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7424267d08..68041675f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ esptool==4.7.0 click==8.1.7 esphome-dashboard==20240412.0 aioesphomeapi==24.0.0 -zeroconf==0.131.0 +zeroconf==0.132.2 python-magic==0.4.27 ruamel.yaml==0.18.6 # dashboard_import From 51ed6d62d928ec66496bb972ec3c1be36c6f8bb3 Mon Sep 17 00:00:00 2001 From: zry98 Date: Wed, 17 Apr 2024 23:31:20 +0200 Subject: [PATCH 1565/2607] [Tuya Climate] Fix compilation error caused by codegen (#6568) --- esphome/components/tuya/climate/__init__.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index b3d401e5a4..56eb377ed7 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -208,7 +208,7 @@ async def to_code(config): cg.add(var.set_switch_id(switch_datapoint)) if active_state_config := config.get(CONF_ACTIVE_STATE): - cg.add(var.set_active_state_id(CONF_DATAPOINT)) + cg.add(var.set_active_state_id(active_state_config.get(CONF_DATAPOINT))) if (heating_value := active_state_config.get(CONF_HEATING_VALUE)) is not None: cg.add(var.set_active_state_heating_value(heating_value)) if (cooling_value := active_state_config.get(CONF_COOLING_VALUE)) is not None: @@ -219,14 +219,10 @@ async def to_code(config): cg.add(var.set_active_state_fanonly_value(fanonly_value)) else: if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): - heating_state_pin = await cg.gpio_pin_expression( - config(heating_state_pin_config) - ) + heating_state_pin = await cg.gpio_pin_expression(heating_state_pin_config) cg.add(var.set_heating_state_pin(heating_state_pin)) if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): - cooling_state_pin = await cg.gpio_pin_expression( - config(cooling_state_pin_config) - ) + cooling_state_pin = await cg.gpio_pin_expression(cooling_state_pin_config) cg.add(var.set_cooling_state_pin(cooling_state_pin)) if target_temperature_datapoint := config.get(CONF_TARGET_TEMPERATURE_DATAPOINT): @@ -254,11 +250,11 @@ async def to_code(config): if preset_config := config.get(CONF_PRESET, {}): if eco_config := preset_config.get(CONF_ECO, {}): - cg.add(var.set_eco_id(CONF_DATAPOINT)) + cg.add(var.set_eco_id(eco_config.get(CONF_DATAPOINT))) if eco_temperature := eco_config.get(CONF_TEMPERATURE): cg.add(var.set_eco_temperature(eco_temperature)) - if CONF_SLEEP in preset_config: - cg.add(var.set_sleep_id(CONF_DATAPOINT)) + if sleep_config := preset_config.get(CONF_SLEEP, {}): + cg.add(var.set_sleep_id(sleep_config.get(CONF_DATAPOINT))) if swing_mode_config := config.get(CONF_SWING_MODE): if swing_vertical_datapoint := swing_mode_config.get(CONF_VERTICAL_DATAPOINT): @@ -268,7 +264,7 @@ async def to_code(config): ): cg.add(var.set_swing_horizontal_id(swing_horizontal_datapoint)) if fan_mode_config := config.get(CONF_FAN_MODE): - cg.add(var.set_fan_speed_id(CONF_DATAPOINT)) + cg.add(var.set_fan_speed_id(fan_mode_config.get(CONF_DATAPOINT))) if (fan_auto_value := fan_mode_config.get(CONF_AUTO_VALUE)) is not None: cg.add(var.set_fan_speed_auto_value(fan_auto_value)) if (fan_low_value := fan_mode_config.get(CONF_LOW_VALUE)) is not None: From c8cdb30459146c9e1e854098328d7cdf817df448 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 18 Apr 2024 09:43:00 +1200 Subject: [PATCH 1566/2607] Housecleaning: Use walrus operator in switch (#6558) --- esphome/components/switch/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index 21cbe3dfe4..e997ec7ca5 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -138,8 +138,8 @@ SWITCH_SCHEMA = switch_schema() # for compatibility async def setup_switch_core_(var, config): await setup_entity(var, config) - if CONF_INVERTED in config: - cg.add(var.set_inverted(config[CONF_INVERTED])) + if (inverted := config.get(CONF_INVERTED)) is not None: + cg.add(var.set_inverted(inverted)) for conf in config.get(CONF_ON_TURN_ON, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) @@ -147,12 +147,12 @@ async def setup_switch_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.set_device_class(device_class)) cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) From 72c1c3f0910ff12448857574f2386ff72de3682b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 18 Apr 2024 09:43:11 +1200 Subject: [PATCH 1567/2607] Housecleaning: Use walrus operator in lock (#6554) Co-authored-by: Keith Burzinski --- esphome/components/lock/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/lock/__init__.py b/esphome/components/lock/__init__.py index f659c48a6e..457ffa278a 100644 --- a/esphome/components/lock/__init__.py +++ b/esphome/components/lock/__init__.py @@ -57,8 +57,8 @@ async def setup_lock_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if mqtt_id := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) From 4559e963b340e2dae8a0edd3bc9893b0d4e140d0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 18 Apr 2024 09:43:18 +1200 Subject: [PATCH 1568/2607] Housecleaning: Use walrus operator in sensor (#6553) Co-authored-by: Keith Burzinski --- esphome/components/sensor/__init__.py | 42 +++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 46295fe958..ece232e1a6 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -732,14 +732,14 @@ async def build_filters(config): async def setup_sensor_core_(var, config): await setup_entity(var, config) - if CONF_DEVICE_CLASS in config: - cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) - if CONF_STATE_CLASS in config: - cg.add(var.set_state_class(config[CONF_STATE_CLASS])) - if CONF_UNIT_OF_MEASUREMENT in config: - cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) - if CONF_ACCURACY_DECIMALS in config: - cg.add(var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.set_device_class(device_class)) + if (state_class := config.get(CONF_STATE_CLASS)) is not None: + cg.add(var.set_state_class(state_class)) + if (unit_of_measurement := config.get(CONF_UNIT_OF_MEASUREMENT)) is not None: + cg.add(var.set_unit_of_measurement(unit_of_measurement)) + if (accuracy_decimals := config.get(CONF_ACCURACY_DECIMALS)) is not None: + cg.add(var.set_accuracy_decimals(accuracy_decimals)) cg.add(var.set_force_update(config[CONF_FORCE_UPDATE])) if config.get(CONF_FILTERS): # must exist and not be empty filters = await build_filters(config[CONF_FILTERS]) @@ -754,23 +754,23 @@ async def setup_sensor_core_(var, config): for conf in config.get(CONF_ON_VALUE_RANGE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await cg.register_component(trigger, conf) - if CONF_ABOVE in conf: - template_ = await cg.templatable(conf[CONF_ABOVE], [(float, "x")], float) + if (above := conf.get(CONF_ABOVE)) is not None: + template_ = await cg.templatable(above, [(float, "x")], float) cg.add(trigger.set_min(template_)) - if CONF_BELOW in conf: - template_ = await cg.templatable(conf[CONF_BELOW], [(float, "x")], float) + if (below := conf.get(CONF_BELOW)) is not None: + template_ = await cg.templatable(below, [(float, "x")], float) cg.add(trigger.set_max(template_)) await automation.build_automation(trigger, [(float, "x")], conf) - if CONF_MQTT_ID in config: - mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: + mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if CONF_EXPIRE_AFTER in config: - if config[CONF_EXPIRE_AFTER] is None: + if (expire_after := config.get(CONF_EXPIRE_AFTER, _UNDEF)) is not _UNDEF: + if expire_after is None: cg.add(mqtt_.disable_expire_after()) else: - cg.add(mqtt_.set_expire_after(config[CONF_EXPIRE_AFTER])) + cg.add(mqtt_.set_expire_after(expire_after)) async def register_sensor(var, config): @@ -803,10 +803,10 @@ async def sensor_in_range_to_code(config, condition_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(condition_id, template_arg, paren) - if CONF_ABOVE in config: - cg.add(var.set_min(config[CONF_ABOVE])) - if CONF_BELOW in config: - cg.add(var.set_max(config[CONF_BELOW])) + if (above := config.get(CONF_ABOVE)) is not None: + cg.add(var.set_min(above)) + if (below := config.get(CONF_BELOW)) is not None: + cg.add(var.set_max(below)) return var From 09def255dd70c8f406e046b87fe1cd77953fd9ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:02:37 +1200 Subject: [PATCH 1569/2607] Bump pytest-mock from 3.12.0 to 3.14.0 (#6572) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 767018d07a..78820765f4 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -7,7 +7,7 @@ pre-commit # Unit tests pytest==8.1.1 pytest-cov==4.1.0 -pytest-mock==3.12.0 +pytest-mock==3.14.0 pytest-asyncio==0.23.6 asyncmock==0.4.2 hypothesis==6.92.1 From 6075067e843788eb7fae90333ae8ff7f59b25a8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:02:54 +1200 Subject: [PATCH 1570/2607] Bump peter-evans/create-pull-request from 6.0.3 to 6.0.4 (#6569) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 62b9c7df9b..c9614618d5 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.3 + uses: peter-evans/create-pull-request@v6.0.4 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From 8c323e2e4c9941f3e300ba4aa98887a3a09bfda7 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 18 Apr 2024 01:07:05 +0200 Subject: [PATCH 1571/2607] Nextion - Review set_protocol_reparse_mode() (#6567) --- esphome/components/nextion/nextion.h | 22 ++++++++++---- .../components/nextion/nextion_commands.cpp | 29 ++++++++++--------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index f9f01de72c..d84f1df3de 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -878,12 +878,24 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ void sleep(bool sleep); /** - * Sets Nextion Protocol Reparse mode between active or passive - * @param True or false. - * active_mode=true to enter active protocol reparse mode - * active_mode=false to enter passive protocol reparse mode. + * @brief Sets the Nextion display's protocol reparse mode. + * + * This function toggles the Nextion display's protocol reparse mode between active and passive. + * In active mode, the display actively parses incoming data. + * In passive mode, it does not parse data unless specifically instructed to do so. + * This is useful for managing how the Nextion display interprets incoming commands, + * especially during initialization or in scenarios where precise control over command processing is needed. + * + * @param active_mode A boolean value indicating the desired reparse mode. + * - true to set the display to active protocol reparse mode, where it actively parses incoming commands. + * - false to set the display to passive protocol reparse mode, where command parsing is done only on explicit + * instruction. + * + * @return bool Returns true if all commands were sent successfully to the Nextion display, indicating that the mode + * was set as expected. Returns false if any of the commands failed to send, indicating that the desired reparse mode + * may not be correctly set. */ - void set_protocol_reparse_mode(bool active_mode); + bool set_protocol_reparse_mode(bool active_mode); // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index e378111376..a2325861a3 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -36,22 +36,23 @@ void Nextion::sleep(bool sleep) { // End sleep safe commands // Protocol reparse mode -void Nextion::set_protocol_reparse_mode(bool active_mode) { - const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF}; +bool Nextion::set_protocol_reparse_mode(bool active_mode) { + ESP_LOGV(TAG, "Set Nextion protocol reparse mode: %s", YESNO(active_mode)); + this->ignore_is_setup_ = true; // if not in reparse mode setup will fail, so it should be ignored + bool all_commands_sent = true; if (active_mode) { // Sets active protocol reparse mode - this->write_str( - "recmod=1"); // send_command_ cannot be used as Nextion might not be setup if incorrect reparse mode - this->write_array(to_send, sizeof(to_send)); - } else { // Sets passive protocol reparse mode - this->write_str("DRAKJHSUYDGBNCJHGJKSHBDN"); // To exit active reparse mode this sequence must be sent - this->write_array(to_send, sizeof(to_send)); - this->write_str("recmod=0"); // Sending recmode=0 twice is recommended - this->write_array(to_send, sizeof(to_send)); - this->write_str("recmod=0"); - this->write_array(to_send, sizeof(to_send)); + all_commands_sent &= this->send_command_("recmod=1"); + } else { // Sets passive protocol reparse mode + all_commands_sent &= + this->send_command_("DRAKJHSUYDGBNCJHGJKSHBDN"); // To exit active reparse mode this sequence must be sent + all_commands_sent &= this->send_command_("recmod=0"); // Sending recmode=0 twice is recommended + all_commands_sent &= this->send_command_("recmod=0"); } - this->write_str("connect"); - this->write_array(to_send, sizeof(to_send)); + if (!this->nextion_reports_is_setup_) { // No need to connect if is already setup + all_commands_sent &= this->send_command_("connect"); + } + this->ignore_is_setup_ = false; + return all_commands_sent; } void Nextion::set_exit_reparse_on_start(bool exit_reparse) { this->exit_reparse_on_start_ = exit_reparse; } From abc09a15c38b4c77a1316ccad32b97a4638b03d8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 17 Apr 2024 18:47:34 -0500 Subject: [PATCH 1572/2607] Allow component final_validate (#6475) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/config.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index c5764dd4f2..1f6867eb59 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -333,10 +333,11 @@ class LoadValidationStep(ConfigValidationStep): if load not in result: result.add_validation_step(AutoLoadValidationStep(load)) + result.add_validation_step( + MetadataValidationStep([self.domain], self.domain, self.conf, component) + ) + if not component.is_platform_component: - result.add_validation_step( - MetadataValidationStep([self.domain], self.domain, self.conf, component) - ) return # This is a platform component, proceed to reading platform entries @@ -520,8 +521,6 @@ class SchemaValidationStep(ConfigValidationStep): self.comp = comp def run(self, result: Config) -> None: - if self.comp.config_schema is None: - return token = path_context.set(self.path) with result.catch_error(self.path): if self.comp.is_platform: @@ -536,7 +535,7 @@ class SchemaValidationStep(ConfigValidationStep): validated["platform"] = platform_val validated.move_to_end("platform", last=False) result.set_by_path(self.path, validated) - else: + elif self.comp.config_schema is not None: schema = cv.Schema(self.comp.config_schema) validated = schema(self.conf) result.set_by_path(self.path, validated) From 5a093acbf509f958fb79af5d4d705f6e49befbd4 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:03:59 -0500 Subject: [PATCH 1573/2607] SM2135 - Use standard channel ordering. (#6573) --- esphome/components/sm2135/sm2135.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/esphome/components/sm2135/sm2135.cpp b/esphome/components/sm2135/sm2135.cpp index 9a576859ac..ee5948bb3a 100644 --- a/esphome/components/sm2135/sm2135.cpp +++ b/esphome/components/sm2135/sm2135.cpp @@ -106,23 +106,23 @@ void SM2135::loop() { delay(1); this->sm2135_start_(); this->write_byte_(SM2135_ADDR_C); - this->write_byte_(this->pwm_amounts_[4]); // Warm - this->write_byte_(this->pwm_amounts_[3]); // Cold + this->write_byte_(this->pwm_amounts_[3]); + this->write_byte_(this->pwm_amounts_[4]); } else { // Color this->write_byte_(SM2135_RGB); - this->write_byte_(this->pwm_amounts_[1]); // Green - this->write_byte_(this->pwm_amounts_[0]); // Red - this->write_byte_(this->pwm_amounts_[2]); // Blue + this->write_byte_(this->pwm_amounts_[0]); + this->write_byte_(this->pwm_amounts_[1]); + this->write_byte_(this->pwm_amounts_[2]); } } else { this->write_byte_(SM2135_RGB); - this->write_byte_(this->pwm_amounts_[1]); // Green - this->write_byte_(this->pwm_amounts_[0]); // Red - this->write_byte_(this->pwm_amounts_[2]); // Blue - this->write_byte_(this->pwm_amounts_[4]); // Warm - this->write_byte_(this->pwm_amounts_[3]); // Cold + this->write_byte_(this->pwm_amounts_[0]); + this->write_byte_(this->pwm_amounts_[1]); + this->write_byte_(this->pwm_amounts_[2]); + this->write_byte_(this->pwm_amounts_[3]); + this->write_byte_(this->pwm_amounts_[4]); } this->sm2135_stop_(); From 39deb8910868d72ab043e579f861eef0e8227508 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 18 Apr 2024 02:05:37 +0200 Subject: [PATCH 1574/2607] Nextion - Do not refresh sensors while updating (#6566) --- .../binary_sensor/nextion_binarysensor.cpp | 4 ++-- esphome/components/nextion/nextion.cpp | 2 ++ esphome/components/nextion/nextion.h | 20 +++++++++++++++++++ esphome/components/nextion/nextion_base.h | 2 ++ .../nextion/sensor/nextion_sensor.cpp | 4 ++-- .../nextion/switch/nextion_switch.cpp | 4 ++-- .../text_sensor/nextion_textsensor.cpp | 4 ++-- 7 files changed, 32 insertions(+), 8 deletions(-) diff --git a/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp b/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp index bf6e74cb38..499cd901c0 100644 --- a/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +++ b/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp @@ -27,7 +27,7 @@ void NextionBinarySensor::process_touch(uint8_t page_id, uint8_t component_id, b } void NextionBinarySensor::update() { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (this->variable_name_.empty()) // This is a touch component @@ -37,7 +37,7 @@ void NextionBinarySensor::update() { } void NextionBinarySensor::set_state(bool state, bool publish, bool send_to_nextion) { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (this->component_id_ == 0) // This is a legacy touch component diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 29dcfa6cef..ac8a96fa7f 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -1137,5 +1137,7 @@ void Nextion::set_writer(const nextion_writer_t &writer) { this->writer_ = write ESPDEPRECATED("set_wait_for_ack(bool) is deprecated and has no effect", "v1.20") void Nextion::set_wait_for_ack(bool wait_for_ack) { ESP_LOGE(TAG, "This command is deprecated"); } +bool Nextion::is_updating() { return this->is_updating_; } + } // namespace nextion } // namespace esphome diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index d84f1df3de..0769b3f93f 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -1031,6 +1031,26 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ size_t queue_size() { return this->nextion_queue_.size(); } + /** + * @brief Check if the TFT update process is currently running. + * + * This method provides a way to determine if the Nextion display is in the + * process of updating its TFT firmware. When a TFT update is in progress, + * certain operations or commands may be restricted or could interfere with the + * update process. By checking the state of the update process, the system can + * make informed decisions about performing actions that involve communication + * with the Nextion display. + * + * @return true if the TFT update process is active, indicating that the Nextion + * display is currently updating its firmware. This implies that caution + * should be taken with commands sent to the display to avoid interrupting + * the update process. + * @return false if the TFT update process is not active, indicating that the Nextion + * display is not currently updating its firmware and is in a normal operational + * state, ready to receive and process commands as usual. + */ + bool is_updating() override; + protected: std::deque nextion_queue_; std::deque waveform_queue_; diff --git a/esphome/components/nextion/nextion_base.h b/esphome/components/nextion/nextion_base.h index b5729a1df1..f16eabc003 100644 --- a/esphome/components/nextion/nextion_base.h +++ b/esphome/components/nextion/nextion_base.h @@ -48,6 +48,8 @@ class NextionBase { virtual void show_component(const char *component) = 0; virtual void hide_component(const char *component) = 0; + virtual bool is_updating() { return false; } + bool is_sleeping() { return this->is_sleeping_; } bool is_setup() { return this->is_setup_; } bool is_detected() { return this->is_detected_; } diff --git a/esphome/components/nextion/sensor/nextion_sensor.cpp b/esphome/components/nextion/sensor/nextion_sensor.cpp index 566dd30acf..6cc641fcf3 100644 --- a/esphome/components/nextion/sensor/nextion_sensor.cpp +++ b/esphome/components/nextion/sensor/nextion_sensor.cpp @@ -30,7 +30,7 @@ void NextionSensor::add_to_wave_buffer(float state) { } void NextionSensor::update() { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (this->wave_chan_id_ == UINT8_MAX) { @@ -45,7 +45,7 @@ void NextionSensor::update() { } void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (std::isnan(state)) diff --git a/esphome/components/nextion/switch/nextion_switch.cpp b/esphome/components/nextion/switch/nextion_switch.cpp index 1f32ad3425..63c1882b48 100644 --- a/esphome/components/nextion/switch/nextion_switch.cpp +++ b/esphome/components/nextion/switch/nextion_switch.cpp @@ -18,13 +18,13 @@ void NextionSwitch::process_bool(const std::string &variable_name, bool on) { } void NextionSwitch::update() { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; this->nextion_->add_to_get_queue(this); } void NextionSwitch::set_state(bool state, bool publish, bool send_to_nextion) { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (send_to_nextion) { diff --git a/esphome/components/nextion/text_sensor/nextion_textsensor.cpp b/esphome/components/nextion/text_sensor/nextion_textsensor.cpp index 08f032df74..a3fc9390f5 100644 --- a/esphome/components/nextion/text_sensor/nextion_textsensor.cpp +++ b/esphome/components/nextion/text_sensor/nextion_textsensor.cpp @@ -16,13 +16,13 @@ void NextionTextSensor::process_text(const std::string &variable_name, const std } void NextionTextSensor::update() { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; this->nextion_->add_to_get_queue(this); } void NextionTextSensor::set_state(const std::string &state, bool publish, bool send_to_nextion) { - if (!this->nextion_->is_setup()) + if (!this->nextion_->is_setup() || this->nextion_->is_updating()) return; if (send_to_nextion) { From 197f9d6d0322210984de4c50681a7afb72cd0105 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 18 Apr 2024 02:10:10 +0200 Subject: [PATCH 1575/2607] Nextion - Review types (#6565) --- esphome/components/nextion/display.py | 4 +- esphome/components/nextion/nextion.cpp | 12 +- esphome/components/nextion/nextion.h | 137 ++++++++++++------ esphome/components/nextion/nextion_base.h | 4 +- .../components/nextion/nextion_commands.cpp | 137 ++++++++++-------- 5 files changed, 183 insertions(+), 111 deletions(-) diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index 27f2030f0d..6487c12f36 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -68,8 +68,8 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_TOUCH_SLEEP_TIMEOUT): cv.int_range(min=3, max=65535), - cv.Optional(CONF_WAKE_UP_PAGE): cv.positive_int, - cv.Optional(CONF_START_UP_PAGE): cv.positive_int, + cv.Optional(CONF_WAKE_UP_PAGE): cv.uint8_t, + cv.Optional(CONF_START_UP_PAGE): cv.uint8_t, cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean, cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean, } diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index ac8a96fa7f..8de5ca9143 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -138,11 +138,11 @@ void Nextion::dump_config() { } if (this->wake_up_page_ != -1) { - ESP_LOGCONFIG(TAG, " Wake Up Page: %d", this->wake_up_page_); + ESP_LOGCONFIG(TAG, " Wake Up Page: %" PRId16, this->wake_up_page_); } if (this->start_up_page_ != -1) { - ESP_LOGCONFIG(TAG, " Start Up Page: %d", this->start_up_page_); + ESP_LOGCONFIG(TAG, " Start Up Page: %" PRId16, this->start_up_page_); } } @@ -1024,23 +1024,23 @@ bool Nextion::add_no_result_to_queue_with_printf_(const std::string &variable_na * @param is_sleep_safe The command is safe to send when the Nextion is sleeping */ -void Nextion::add_no_result_to_queue_with_set(NextionComponentBase *component, int state_value) { +void Nextion::add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) { this->add_no_result_to_queue_with_set(component->get_variable_name(), component->get_variable_name_to_send(), state_value); } void Nextion::add_no_result_to_queue_with_set(const std::string &variable_name, - const std::string &variable_name_to_send, int state_value) { + const std::string &variable_name_to_send, int32_t state_value) { this->add_no_result_to_queue_with_set_internal_(variable_name, variable_name_to_send, state_value); } void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &variable_name, - const std::string &variable_name_to_send, int state_value, + const std::string &variable_name_to_send, int32_t state_value, bool is_sleep_safe) { if ((!this->is_setup() && !this->ignore_is_setup_) || (!is_sleep_safe && this->is_sleeping())) return; - this->add_no_result_to_queue_with_ignore_sleep_printf_(variable_name, "%s=%d", variable_name_to_send.c_str(), + this->add_no_result_to_queue_with_ignore_sleep_printf_(variable_name, "%s=%" PRId32, variable_name_to_send.c_str(), state_value); } diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 0769b3f93f..bc75df3ce6 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -50,6 +50,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will set the `txt` property of the component `textview` to `Hello World`. */ void set_component_text(const char *component, const char *text); + /** * Set the text of a component to a formatted string * @param component The component name. @@ -66,6 +67,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * For example when `uptime_sensor` = 506, then, `The uptime is: 506` will be displayed. */ void set_component_text_printf(const char *component, const char *format, ...) __attribute__((format(printf, 3, 4))); + /** * Set the integer value of a component * @param component The component name. @@ -78,7 +80,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * This will change the property `value` of the component `gauge` to 50. */ - void set_component_value(const char *component, int value); + void set_component_value(const char *component, int32_t value); + /** * Set the picture of an image component. * @param component The component name. @@ -92,6 +95,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the image of the component `pic` to the image with ID `4`. */ void set_component_picture(const char *component, uint8_t picture_id); + /** * Set the background color of a component. * @param component The component name. @@ -107,6 +111,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_background_color(const char *component, uint16_t color); + /** * Set the background color of a component. * @param component The component name. @@ -121,6 +126,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_background_color(const char *component, const char *color); + /** * Set the background color of a component. * @param component The component name. @@ -135,6 +141,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the background color of the component `button` to blue. */ void set_component_background_color(const char *component, Color color) override; + /** * Set the pressed background color of a component. * @param component The component name. @@ -151,6 +158,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_pressed_background_color(const char *component, uint16_t color); + /** * Set the pressed background color of a component. * @param component The component name. @@ -166,6 +174,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_pressed_background_color(const char *component, const char *color); + /** * Set the pressed background color of a component. * @param component The component name. @@ -181,6 +190,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * is shown when the component is pressed. */ void set_component_pressed_background_color(const char *component, Color color) override; + /** * Set the foreground color of a component. * @param component The component name. @@ -196,6 +206,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_foreground_color(const char *component, uint16_t color); + /** * Set the foreground color of a component. * @param component The component name. @@ -210,6 +221,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_foreground_color(const char *component, const char *color); + /** * Set the foreground color of a component. * @param component The component name. @@ -223,6 +235,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the foreground color of the component `button` to black. */ void set_component_foreground_color(const char *component, Color color) override; + /** * Set the pressed foreground color of a component. * @param component The component name. @@ -239,6 +252,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_pressed_foreground_color(const char *component, uint16_t color); + /** * Set the pressed foreground color of a component. * @param component The component name. @@ -254,6 +268,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_pressed_foreground_color(const char *component, const char *color); + /** * Set the pressed foreground color of a component. * @param component The component name. @@ -283,6 +298,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the picture id of the component `textview`. */ void set_component_pic(const char *component, uint8_t pic_id); + /** * Set the background picture id of component. * @param component The component name. @@ -312,6 +328,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_font_color(const char *component, uint16_t color); + /** * Set the font color of a component. * @param component The component name. @@ -326,6 +343,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_font_color(const char *component, const char *color); + /** * Set the font color of a component. * @param component The component name. @@ -339,6 +357,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the font color of the component `textview` to black. */ void set_component_font_color(const char *component, Color color) override; + /** * Set the pressed font color of a component. * @param component The component name. @@ -354,6 +373,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Nextion HMI colors. */ void set_component_pressed_font_color(const char *component, uint16_t color); + /** * Set the pressed font color of a component. * @param component The component name. @@ -368,6 +388,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ void set_component_pressed_font_color(const char *component, const char *color); + /** * Set the pressed font color of a component. * @param component The component name. @@ -381,6 +402,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * This will change the pressed font color of the component `button` to black. */ void set_component_pressed_font_color(const char *component, Color color) override; + /** * Set the coordinates of a component on screen. * @param component The component name. @@ -394,7 +416,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * This will move the position of the component `pic` to the x coordinate `55` and y coordinate `100`. */ - void set_component_coordinates(const char *component, int x, int y); + void set_component_coordinates(const char *component, uint16_t x, uint16_t y); + /** * Set the font id for a component. * @param component The component name. @@ -408,6 +431,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Changes the font of the component named `textveiw`. Font IDs are set in the Nextion Editor. */ void set_component_font(const char *component, uint8_t font_id) override; + /** * Send the current time to the nextion display. * @param time The time instance to send (get this with id(my_time).now() ). @@ -426,6 +450,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Switches to the page named `main`. Pages are named in the Nextion Editor. */ void goto_page(const char *page); + /** * Show the page with a given id. * @param page The id of the page. @@ -438,6 +463,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Switches to the page named `main`. Pages are named in the Nextion Editor. */ void goto_page(uint8_t page); + /** * Hide a component. * @param component The component name. @@ -450,6 +476,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Hides the component named `button`. */ void hide_component(const char *component) override; + /** * Show a component. * @param component The component name. @@ -462,6 +489,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Shows the component named `button`. */ void show_component(const char *component) override; + /** * Enable touch for a component. * @param component The component name. @@ -474,6 +502,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Enables touch for component named `button`. */ void enable_component_touch(const char *component); + /** * Disable touch for a component. * @param component The component name. @@ -486,14 +515,17 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Disables touch for component named `button`. */ void disable_component_touch(const char *component); + /** * Add waveform data to a waveform component * @param component_id The integer component id. * @param channel_number The channel number to write to. * @param value The value to write. */ - void add_waveform_data(int component_id, uint8_t channel_number, uint8_t value); - void open_waveform_channel(int component_id, uint8_t channel_number, uint8_t value); + void add_waveform_data(uint8_t component_id, uint8_t channel_number, uint8_t value); + + void open_waveform_channel(uint8_t component_id, uint8_t channel_number, uint8_t value); + /** * Display a picture at coordinates. * @param picture_id The picture id. @@ -507,7 +539,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * Displays the picture who has the id `2` at the x coordinates `15` and y coordinates `25`. */ - void display_picture(int picture_id, int x_start, int y_start); + void display_picture(uint16_t picture_id, uint16_t x_start, uint16_t y_start); + /** * Fill a rectangle with a color. * @param x1 The starting x coordinate. @@ -526,7 +559,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to * Nextion HMI colors. */ - void fill_area(int x1, int y1, int width, int height, uint16_t color); + void fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t color); + /** * Fill a rectangle with a color. * @param x1 The starting x coordinate. @@ -544,7 +578,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * the red color. * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ - void fill_area(int x1, int y1, int width, int height, const char *color); + void fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, const char *color); + /** * Fill a rectangle with a color. * @param x1 The starting x coordinate. @@ -562,7 +597,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Fills an area that starts at x coordinate `50` and y coordinate `50` with a height of `100` and width of `100` with * blue color. */ - void fill_area(int x1, int y1, int width, int height, Color color); + void fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, Color color); + /** * Draw a line on the screen. * @param x1 The starting x coordinate. @@ -581,7 +617,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to * Nextion HMI colors. */ - void line(int x1, int y1, int x2, int y2, uint16_t color); + void line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); + /** * Draw a line on the screen. * @param x1 The starting x coordinate. @@ -599,7 +636,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * `75` with the blue color. * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ - void line(int x1, int y1, int x2, int y2, const char *color); + void line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const char *color); + /** * Draw a line on the screen. * @param x1 The starting x coordinate. @@ -617,7 +655,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Makes a line that starts at x coordinate `50` and y coordinate `50` and ends at x coordinate `75` and y coordinate * `75` with blue color. */ - void line(int x1, int y1, int x2, int y2, Color color); + void line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, Color color); + /** * Draw a rectangle outline. * @param x1 The starting x coordinate. @@ -636,7 +675,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to * Nextion HMI colors. */ - void rectangle(int x1, int y1, int width, int height, uint16_t color); + void rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t color); + /** * Draw a rectangle outline. * @param x1 The starting x coordinate. @@ -654,7 +694,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * length of `50` with the blue color. * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ - void rectangle(int x1, int y1, int width, int height, const char *color); + void rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, const char *color); + /** * Draw a rectangle outline. * @param x1 The starting x coordinate. @@ -672,7 +713,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Makes a outline of a rectangle that starts at x coordinate `25` and y coordinate `35` and has a width of `40` and a * length of `50` with blue color. */ - void rectangle(int x1, int y1, int width, int height, Color color); + void rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, Color color); + /** * Draw a circle outline * @param center_x The center x coordinate. @@ -682,7 +724,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to * Nextion HMI colors. */ - void circle(int center_x, int center_y, int radius, uint16_t color); + void circle(uint16_t center_x, uint16_t center_y, uint16_t radius, uint16_t color); + /** * Draw a circle outline * @param center_x The center x coordinate. @@ -691,7 +734,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @param color The color to draw with (as a string). * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ - void circle(int center_x, int center_y, int radius, const char *color); + void circle(uint16_t center_x, uint16_t center_y, uint16_t radius, const char *color); + /** * Draw a circle outline * @param center_x The center x coordinate. @@ -699,7 +743,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @param radius The circle radius. * @param color The color to draw with (as Color). */ - void circle(int center_x, int center_y, int radius, Color color); + void circle(uint16_t center_x, uint16_t center_y, uint16_t radius, Color color); + /** * Draw a filled circled. * @param center_x The center x coordinate. @@ -716,7 +761,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to * Nextion HMI colors. */ - void filled_circle(int center_x, int center_y, int radius, uint16_t color); + void filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, uint16_t color); + /** * Draw a filled circled. * @param center_x The center x coordinate. @@ -732,7 +778,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Makes a filled circle at the x coordinate `25` and y coordinate `25` with a radius of `10` with the blue color. * Use [Nextion Instruction Set](https://nextion.tech/instruction-set/#s5) for a list of Nextion HMI colors constants. */ - void filled_circle(int center_x, int center_y, int radius, const char *color); + void filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, const char *color); + /** * Draw a filled circled. * @param center_x The center x coordinate. @@ -748,7 +795,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * Makes a filled circle at the x coordinate `25` and y coordinate `25` with a radius of `10` with blue color. */ - void filled_circle(int center_x, int center_y, int radius, Color color); + void filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, Color color); /** * Draws a QR code in the screen @@ -768,8 +815,9 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * Draws a QR code with a Wi-Fi network credentials starting at the given coordinates (25,25). */ - void qrcode(int x1, int y1, const char *content, int size = 200, uint16_t background_color = 65535, - uint16_t foreground_color = 0, int logo_pic = -1, uint8_t border_width = 8); + void qrcode(uint16_t x1, uint16_t y1, const char *content, uint16_t size = 200, uint16_t background_color = 65535, + uint16_t foreground_color = 0, uint8_t logo_pic = -1, uint8_t border_width = 8); + /** * Draws a QR code in the screen * @param x1 The top left x coordinate to start the QR code. @@ -791,8 +839,9 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Draws a QR code with a Wi-Fi network credentials starting at the given coordinates (25,25) with size of 150px in * red on a blue background. */ - void qrcode(int x1, int y1, const char *content, int size, Color background_color = Color(255, 255, 255), - Color foreground_color = Color(0, 0, 0), int logo_pic = -1, uint8_t border_width = 8); + void qrcode(uint16_t x1, uint16_t y1, const char *content, uint16_t size, + Color background_color = Color(255, 255, 255), Color foreground_color = Color(0, 0, 0), + uint8_t logo_pic = -1, uint8_t border_width = 8); /** Set the brightness of the backlight. * @@ -806,6 +855,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Changes the brightness of the display to 30%. */ void set_backlight_brightness(float brightness); + /** * Set the touch sleep timeout of the display. * @param timeout Timeout in seconds. @@ -819,6 +869,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * `thup`. */ void set_touch_sleep_timeout(uint16_t timeout); + /** * Sets which page Nextion loads when exiting sleep mode. Note this can be set even when Nextion is in sleep mode. * @param page_id The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to @@ -832,6 +883,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * The display will wake up to page 2. */ void set_wake_up_page(uint8_t page_id = 255); + /** * Sets which page Nextion loads when connecting to ESPHome. * @param page_id The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to @@ -859,6 +911,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * The display will wake up by touch. */ void set_auto_wake_on_touch(bool auto_wake); + /** * Sets if Nextion should exit the active reparse mode before the "connect" command is sent * @param exit_reparse True or false. When exit_reparse is true, the exit reparse command @@ -872,11 +925,13 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * The display will be requested to leave active reparse mode before setup. */ void set_exit_reparse_on_start(bool exit_reparse); + /** * Sets Nextion mode between sleep and awake * @param True or false. Sleep=true to enter sleep mode or sleep=false to exit sleep mode. */ void sleep(bool sleep); + /** * @brief Sets the Nextion display's protocol reparse mode. * @@ -928,7 +983,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Set the tft file URL. https seems problematic with arduino.. */ void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } - #endif /** @@ -992,9 +1046,9 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void set_nextion_sensor_state(NextionQueueType queue_type, const std::string &name, float state); void set_nextion_text_state(const std::string &name, const std::string &state); - void add_no_result_to_queue_with_set(NextionComponentBase *component, int state_value) override; + void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) override; void add_no_result_to_queue_with_set(const std::string &variable_name, const std::string &variable_name_to_send, - int state_value) override; + int32_t state_value) override; void add_no_result_to_queue_with_set(NextionComponentBase *component, const std::string &state_value) override; void add_no_result_to_queue_with_set(const std::string &variable_name, const std::string &variable_name_to_send, @@ -1070,8 +1124,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void process_serial_(); bool is_updating_ = false; uint32_t touch_sleep_timeout_ = 0; - int wake_up_page_ = -1; - int start_up_page_ = -1; + int16_t wake_up_page_ = -1; + int16_t start_up_page_ = -1; bool auto_wake_on_touch_ = true; bool exit_reparse_on_start_ = false; @@ -1089,7 +1143,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe __attribute__((format(printf, 3, 4))); void add_no_result_to_queue_with_set_internal_(const std::string &variable_name, - const std::string &variable_name_to_send, int state_value, + const std::string &variable_name_to_send, int32_t state_value, bool is_sleep_safe = false); void add_no_result_to_queue_with_set_internal_(const std::string &variable_name, @@ -1099,13 +1153,21 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void check_pending_waveform_(); #ifdef USE_NEXTION_TFT_UPLOAD + uint32_t content_length_ = 0; + int tft_size_ = 0; + uint32_t original_baud_rate_ = 0; + bool upload_first_chunk_sent_ = false; + + std::string tft_url_; + uint8_t *transfer_buffer_{nullptr}; + size_t transfer_buffer_size_; + #ifdef USE_ESP8266 WiFiClient *wifi_client_{nullptr}; BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr}; WiFiClient *get_wifi_client_(); #endif - int content_length_ = 0; - int tft_size_ = 0; + #ifdef ARDUINO /** * will request chunk_size chunks from the web server @@ -1178,13 +1240,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void remove_front_no_sensors_(); -#ifdef USE_NEXTION_TFT_UPLOAD - std::string tft_url_; - uint8_t *transfer_buffer_{nullptr}; - size_t transfer_buffer_size_; - bool upload_first_chunk_sent_ = false; -#endif - #ifdef NEXTION_PROTOCOL_LOG void print_queue_members_(); #endif @@ -1192,8 +1247,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe std::string command_data_; bool is_connected_ = false; - uint32_t startup_override_ms_ = 8000; - uint32_t max_q_age_ms_ = 8000; + const uint16_t startup_override_ms_ = 8000; + const uint16_t max_q_age_ms_ = 8000; uint32_t started_ms_ = 0; bool sent_setup_commands_ = false; }; diff --git a/esphome/components/nextion/nextion_base.h b/esphome/components/nextion/nextion_base.h index f16eabc003..b88dd399f8 100644 --- a/esphome/components/nextion/nextion_base.h +++ b/esphome/components/nextion/nextion_base.h @@ -24,9 +24,9 @@ class NextionBase; class NextionBase { public: - virtual void add_no_result_to_queue_with_set(NextionComponentBase *component, int state_value) = 0; + virtual void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) = 0; virtual void add_no_result_to_queue_with_set(const std::string &variable_name, - const std::string &variable_name_to_send, int state_value) = 0; + const std::string &variable_name_to_send, int32_t state_value) = 0; virtual void add_no_result_to_queue_with_set(NextionComponentBase *component, const std::string &state_value) = 0; virtual void add_no_result_to_queue_with_set(const std::string &variable_name, diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index a2325861a3..fdd6c74d99 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -144,11 +144,11 @@ void Nextion::set_component_pressed_font_color(const char *component, Color colo // Set picture void Nextion::set_component_pic(const char *component, uint8_t pic_id) { - this->add_no_result_to_queue_with_printf_("set_component_pic", "%s.pic=%d", component, pic_id); + this->add_no_result_to_queue_with_printf_("set_component_pic", "%s.pic=%" PRIu8, component, pic_id); } void Nextion::set_component_picc(const char *component, uint8_t pic_id) { - this->add_no_result_to_queue_with_printf_("set_component_pic", "%s.picc=%d", component, pic_id); + this->add_no_result_to_queue_with_printf_("set_component_pic", "%s.picc=%" PRIu8, component, pic_id); } void Nextion::set_component_text_printf(const char *component, const char *format, ...) { @@ -179,7 +179,7 @@ void Nextion::set_auto_wake_on_touch(bool auto_wake) { // General Component void Nextion::set_component_font(const char *component, uint8_t font_id) { - this->add_no_result_to_queue_with_printf_("set_component_font", "%s.font=%d", component, font_id); + this->add_no_result_to_queue_with_printf_("set_component_font", "%s.font=%" PRIu8, component, font_id); } void Nextion::hide_component(const char *component) { @@ -199,113 +199,130 @@ void Nextion::disable_component_touch(const char *component) { } void Nextion::set_component_picture(const char *component, uint8_t picture_id) { - this->add_no_result_to_queue_with_printf_("set_component_picture", "%s.pic=%d", component, picture_id); + this->add_no_result_to_queue_with_printf_("set_component_picture", "%s.pic=%" PRIu8, component, picture_id); } void Nextion::set_component_text(const char *component, const char *text) { this->add_no_result_to_queue_with_printf_("set_component_text", "%s.txt=\"%s\"", component, text); } -void Nextion::set_component_value(const char *component, int value) { - this->add_no_result_to_queue_with_printf_("set_component_value", "%s.val=%d", component, value); +void Nextion::set_component_value(const char *component, int32_t value) { + this->add_no_result_to_queue_with_printf_("set_component_value", "%s.val=%" PRId32, component, value); } -void Nextion::add_waveform_data(int component_id, uint8_t channel_number, uint8_t value) { - this->add_no_result_to_queue_with_printf_("add_waveform_data", "add %d,%u,%u", component_id, channel_number, value); +void Nextion::add_waveform_data(uint8_t component_id, uint8_t channel_number, uint8_t value) { + this->add_no_result_to_queue_with_printf_("add_waveform_data", "add %" PRIu8 ",%" PRIu8 ",%" PRIu8, component_id, + channel_number, value); } -void Nextion::open_waveform_channel(int component_id, uint8_t channel_number, uint8_t value) { - this->add_no_result_to_queue_with_printf_("open_waveform_channel", "addt %d,%u,%u", component_id, channel_number, - value); +void Nextion::open_waveform_channel(uint8_t component_id, uint8_t channel_number, uint8_t value) { + this->add_no_result_to_queue_with_printf_("open_waveform_channel", "addt %" PRIu8 ",%" PRIu8 ",%" PRIu8, component_id, + channel_number, value); } -void Nextion::set_component_coordinates(const char *component, int x, int y) { - this->add_no_result_to_queue_with_printf_("set_component_coordinates command 1", "%s.xcen=%d", component, x); - this->add_no_result_to_queue_with_printf_("set_component_coordinates command 2", "%s.ycen=%d", component, y); +void Nextion::set_component_coordinates(const char *component, uint16_t x, uint16_t y) { + this->add_no_result_to_queue_with_printf_("set_component_coordinates command 1", "%s.xcen=%" PRIu16, component, x); + this->add_no_result_to_queue_with_printf_("set_component_coordinates command 2", "%s.ycen=%" PRIu16, component, y); } // Drawing -void Nextion::display_picture(int picture_id, int x_start, int y_start) { - this->add_no_result_to_queue_with_printf_("display_picture", "pic %d, %d, %d", x_start, y_start, picture_id); +void Nextion::display_picture(uint16_t picture_id, uint16_t x_start, uint16_t y_start) { + this->add_no_result_to_queue_with_printf_("display_picture", "pic %" PRIu16 ", %" PRIu16 ", %" PRIu16, x_start, + y_start, picture_id); } -void Nextion::fill_area(int x1, int y1, int width, int height, uint16_t color) { - this->add_no_result_to_queue_with_printf_("fill_area", "fill %d,%d,%d,%d,%" PRIu16, x1, y1, width, height, color); +void Nextion::fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t color) { + this->add_no_result_to_queue_with_printf_( + "fill_area", "fill %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, y1, width, height, color); } -void Nextion::fill_area(int x1, int y1, int width, int height, const char *color) { - this->add_no_result_to_queue_with_printf_("fill_area", "fill %d,%d,%d,%d,%s", x1, y1, width, height, color); +void Nextion::fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, const char *color) { + this->add_no_result_to_queue_with_printf_("fill_area", "fill %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%s", x1, + y1, width, height, color); } -void Nextion::fill_area(int x1, int y1, int width, int height, Color color) { - this->add_no_result_to_queue_with_printf_("fill_area", "fill %d,%d,%d,%d,%d", x1, y1, width, height, - display::ColorUtil::color_to_565(color)); +void Nextion::fill_area(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, Color color) { + this->add_no_result_to_queue_with_printf_("fill_area", + "fill %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, y1, + width, height, display::ColorUtil::color_to_565(color)); } -void Nextion::line(int x1, int y1, int x2, int y2, uint16_t color) { - this->add_no_result_to_queue_with_printf_("line", "line %d,%d,%d,%d,%" PRIu16, x1, y1, x2, y2, color); +void Nextion::line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { + this->add_no_result_to_queue_with_printf_("line", "line %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, + y1, x2, y2, color); } -void Nextion::line(int x1, int y1, int x2, int y2, const char *color) { - this->add_no_result_to_queue_with_printf_("line", "line %d,%d,%d,%d,%s", x1, y1, x2, y2, color); +void Nextion::line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const char *color) { + this->add_no_result_to_queue_with_printf_("line", "line %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%s", x1, y1, + x2, y2, color); } -void Nextion::line(int x1, int y1, int x2, int y2, Color color) { - this->add_no_result_to_queue_with_printf_("line", "line %d,%d,%d,%d,%d", x1, y1, x2, y2, - display::ColorUtil::color_to_565(color)); +void Nextion::line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, Color color) { + this->add_no_result_to_queue_with_printf_("line", "line %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, + y1, x2, y2, display::ColorUtil::color_to_565(color)); } -void Nextion::rectangle(int x1, int y1, int width, int height, uint16_t color) { - this->add_no_result_to_queue_with_printf_("draw", "draw %d,%d,%d,%d,%" PRIu16, x1, y1, x1 + width, y1 + height, +void Nextion::rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t color) { + this->add_no_result_to_queue_with_printf_("draw", "draw %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, + y1, static_cast(x1 + width), static_cast(y1 + height), color); } -void Nextion::rectangle(int x1, int y1, int width, int height, const char *color) { - this->add_no_result_to_queue_with_printf_("draw", "draw %d,%d,%d,%d,%s", x1, y1, x1 + width, y1 + height, color); +void Nextion::rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, const char *color) { + this->add_no_result_to_queue_with_printf_("draw", "draw %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%s", x1, y1, + static_cast(x1 + width), static_cast(y1 + height), + color); } -void Nextion::rectangle(int x1, int y1, int width, int height, Color color) { - this->add_no_result_to_queue_with_printf_("draw", "draw %d,%d,%d,%d,%d", x1, y1, x1 + width, y1 + height, +void Nextion::rectangle(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, Color color) { + this->add_no_result_to_queue_with_printf_("draw", "draw %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, x1, + y1, static_cast(x1 + width), static_cast(y1 + height), display::ColorUtil::color_to_565(color)); } -void Nextion::circle(int center_x, int center_y, int radius, uint16_t color) { - this->add_no_result_to_queue_with_printf_("cir", "cir %d,%d,%d,%" PRIu16, center_x, center_y, radius, color); +void Nextion::circle(uint16_t center_x, uint16_t center_y, uint16_t radius, uint16_t color) { + this->add_no_result_to_queue_with_printf_("cir", "cir %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, center_x, + center_y, radius, color); } -void Nextion::circle(int center_x, int center_y, int radius, const char *color) { - this->add_no_result_to_queue_with_printf_("cir", "cir %d,%d,%d,%s", center_x, center_y, radius, color); +void Nextion::circle(uint16_t center_x, uint16_t center_y, uint16_t radius, const char *color) { + this->add_no_result_to_queue_with_printf_("cir", "cir %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%s", center_x, center_y, + radius, color); } -void Nextion::circle(int center_x, int center_y, int radius, Color color) { - this->add_no_result_to_queue_with_printf_("cir", "cir %d,%d,%d,%d", center_x, center_y, radius, - display::ColorUtil::color_to_565(color)); +void Nextion::circle(uint16_t center_x, uint16_t center_y, uint16_t radius, Color color) { + this->add_no_result_to_queue_with_printf_("cir", "cir %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, center_x, + center_y, radius, display::ColorUtil::color_to_565(color)); } -void Nextion::filled_circle(int center_x, int center_y, int radius, uint16_t color) { - this->add_no_result_to_queue_with_printf_("cirs", "cirs %d,%d,%d,%" PRIu16, center_x, center_y, radius, color); +void Nextion::filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, uint16_t color) { + this->add_no_result_to_queue_with_printf_("cirs", "cirs %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, center_x, + center_y, radius, color); } -void Nextion::filled_circle(int center_x, int center_y, int radius, const char *color) { - this->add_no_result_to_queue_with_printf_("cirs", "cirs %d,%d,%d,%s", center_x, center_y, radius, color); +void Nextion::filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, const char *color) { + this->add_no_result_to_queue_with_printf_("cirs", "cirs %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%s", center_x, center_y, + radius, color); } -void Nextion::filled_circle(int center_x, int center_y, int radius, Color color) { - this->add_no_result_to_queue_with_printf_("cirs", "cirs %d,%d,%d,%d", center_x, center_y, radius, - display::ColorUtil::color_to_565(color)); +void Nextion::filled_circle(uint16_t center_x, uint16_t center_y, uint16_t radius, Color color) { + this->add_no_result_to_queue_with_printf_("cirs", "cirs %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16, center_x, + center_y, radius, display::ColorUtil::color_to_565(color)); } -void Nextion::qrcode(int x1, int y1, const char *content, int size, uint16_t background_color, - uint16_t foreground_color, int logo_pic, uint8_t border_width) { - this->add_no_result_to_queue_with_printf_("qrcode", "qrcode %d,%d,%d,%d,%d,%d,%d,\"%s\"", x1, y1, size, - background_color, foreground_color, logo_pic, border_width, content); -} - -void Nextion::qrcode(int x1, int y1, const char *content, int size, Color background_color, Color foreground_color, - int logo_pic, uint8_t border_width) { +void Nextion::qrcode(uint16_t x1, uint16_t y1, const char *content, uint16_t size, uint16_t background_color, + uint16_t foreground_color, uint8_t logo_pic, uint8_t border_width) { this->add_no_result_to_queue_with_printf_( - "qrcode", "qrcode %d,%d,%d,%d,%d,%d,%d,\"%s\"", x1, y1, size, display::ColorUtil::color_to_565(background_color), - display::ColorUtil::color_to_565(foreground_color), logo_pic, border_width, content); + "qrcode", "qrcode %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu8 ",%" PRIu8 ",\"%s\"", x1, + y1, size, background_color, foreground_color, logo_pic, border_width, content); +} + +void Nextion::qrcode(uint16_t x1, uint16_t y1, const char *content, uint16_t size, Color background_color, + Color foreground_color, uint8_t logo_pic, uint8_t border_width) { + this->add_no_result_to_queue_with_printf_( + "qrcode", "qrcode %" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu8 ",%" PRIu8 ",\"%s\"", x1, + y1, size, display::ColorUtil::color_to_565(background_color), display::ColorUtil::color_to_565(foreground_color), + logo_pic, border_width, content); } void Nextion::set_nextion_rtc_time(ESPTime time) { From 2fed6955de41aad58f353d3feed5e5fcb1e70ddc Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:11:00 +1000 Subject: [PATCH 1576/2607] On failure, dump the output of preceding jobs in CI status (#6564) --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7df57acb08..d3ac7981d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -472,6 +472,7 @@ jobs: - compile-tests - clang-tidy - test-build-components + - list-components if: always() steps: - name: Success @@ -479,4 +480,8 @@ jobs: run: exit 0 - name: Failure if: ${{ contains(needs.*.result, 'failure') }} - run: exit 1 + env: + JSON_DOC: ${{ toJSON(needs) }} + run: | + echo $JSON_DOC | jq + exit 1 From 2e7ac26adacd5a7c1aa02ff47de785f4b9e79fee Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 18 Apr 2024 04:16:49 +0200 Subject: [PATCH 1577/2607] Nextion `send_command` method (#6540) This is a simplified version of `send_command_printf` without the `printf` support. Manually send a raw command to the display. param command The pcommand, like "page 0" return Whether the send was successful. --- esphome/components/nextion/nextion.cpp | 11 +++++++++++ esphome/components/nextion/nextion.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 8de5ca9143..ddbd3328ef 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -194,6 +194,17 @@ void Nextion::update_all_components() { } } +bool Nextion::send_command(const char *command) { + if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping()) + return false; + + if (this->send_command_(command)) { + this->add_no_result_to_queue_("send_command"); + return true; + } + return false; +} + bool Nextion::send_command_printf(const char *format, ...) { if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping()) return false; diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index bc75df3ce6..a8f0ea8ba9 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -970,6 +970,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe // This function has been deprecated void set_wait_for_ack(bool wait_for_ack); + /** + * Manually send a raw command to the display. + * @param command The pcommand, like "page 0" + * @return Whether the send was successful. + */ + bool send_command(const char *command); /** * Manually send a raw formatted command to the display. * @param format The printf-style command format, like "vis %s,0" From 8c31aea94fca4d83e7357593c0567e0b381135d0 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:03:15 +1000 Subject: [PATCH 1578/2607] Fix some printf formats for size_t. (#6542) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/select/select.cpp | 2 +- esphome/components/select/select_call.cpp | 2 +- esphome/components/sensor/filter.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/select/select.cpp b/esphome/components/select/select.cpp index f4583b4e2e..806882ad94 100644 --- a/esphome/components/select/select.cpp +++ b/esphome/components/select/select.cpp @@ -12,7 +12,7 @@ void Select::publish_state(const std::string &state) { if (index.has_value()) { this->has_state_ = true; this->state = state; - ESP_LOGD(TAG, "'%s': Sending state %s (index %d)", name, state.c_str(), index.value()); + ESP_LOGD(TAG, "'%s': Sending state %s (index %zu)", name, state.c_str(), index.value()); this->state_callback_.call(state, index.value()); } else { ESP_LOGE(TAG, "'%s': invalid state for publish_state(): %s", name, state.c_str()); diff --git a/esphome/components/select/select_call.cpp b/esphome/components/select/select_call.cpp index 6ee41b1029..85f755645c 100644 --- a/esphome/components/select/select_call.cpp +++ b/esphome/components/select/select_call.cpp @@ -71,7 +71,7 @@ void SelectCall::perform() { return; } if (this->index_.value() >= options.size()) { - ESP_LOGW(TAG, "'%s' - Index value %d out of bounds", name, this->index_.value()); + ESP_LOGW(TAG, "'%s' - Index value %zu out of bounds", name, this->index_.value()); return; } target_value = options[this->index_.value()]; diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 6d7acad7e0..3f67af59be 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -79,7 +79,7 @@ SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_ optional SkipInitialFilter::new_value(float value) { if (num_to_ignore_ > 0) { num_to_ignore_--; - ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %u left", this, value, num_to_ignore_); + ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left", this, value, num_to_ignore_); return {}; } From 655dbc48b5f7e53a4ceee83f4aa159e276d8b864 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Thu, 18 Apr 2024 14:52:22 -0700 Subject: [PATCH 1579/2607] remove delay from tmp102 (#6577) Co-authored-by: Samuel Sieb --- esphome/components/tmp102/tmp102.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/esphome/components/tmp102/tmp102.cpp b/esphome/components/tmp102/tmp102.cpp index be60a2d8d4..f35fbf5d4b 100644 --- a/esphome/components/tmp102/tmp102.cpp +++ b/esphome/components/tmp102/tmp102.cpp @@ -28,23 +28,24 @@ void TMP102Component::dump_config() { } void TMP102Component::update() { - int16_t raw_temperature; if (this->write(&TMP102_REGISTER_TEMPERATURE, 1) != i2c::ERROR_OK) { this->status_set_warning(); return; } - delay(50); // NOLINT - if (this->read(reinterpret_cast(&raw_temperature), 2) != i2c::ERROR_OK) { - this->status_set_warning(); - return; - } - raw_temperature = i2c::i2ctohs(raw_temperature); - raw_temperature = raw_temperature >> 4; - float temperature = raw_temperature * TMP102_CONVERSION_FACTOR; - ESP_LOGD(TAG, "Got Temperature=%.1f°C", temperature); + this->set_timeout("read_temp", 50, [this]() { + int16_t raw_temperature; + if (this->read(reinterpret_cast(&raw_temperature), 2) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + raw_temperature = i2c::i2ctohs(raw_temperature); + raw_temperature = raw_temperature >> 4; + float temperature = raw_temperature * TMP102_CONVERSION_FACTOR; + ESP_LOGD(TAG, "Got Temperature=%.1f°C", temperature); - this->publish_state(temperature); - this->status_clear_warning(); + this->publish_state(temperature); + this->status_clear_warning(); + }); } float TMP102Component::get_setup_priority() const { return setup_priority::DATA; } From 45ae78de03cbed77809f51ee89f461d68fd66907 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 22 Apr 2024 10:29:56 +1200 Subject: [PATCH 1580/2607] =?UTF-8?q?Create=20``component=5Fdir``=20substi?= =?UTF-8?q?tution=20for=20local=20files=20to=20be=20included=20in=E2=80=A6?= =?UTF-8?q?=20(#6575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/ci-custom.py | 2 +- tests/components/font/Monocraft.ttf | Bin 0 -> 202764 bytes tests/components/font/common.yaml | 38 ++++++++++++++++ tests/components/font/test.esp32-c3-idf.yaml | 24 +++------- tests/components/font/test.esp32-c3.yaml | 24 +++------- tests/components/font/test.esp32-idf.yaml | 24 +++------- tests/components/font/test.esp32.yaml | 43 +++--------------- tests/components/font/test.esp8266.yaml | 24 +++------- tests/components/font/test.rp2040.yaml | 24 +++------- .../build_components_base.bk72xx.yaml | 1 + .../build_components_base.esp32-ard.yaml | 1 + .../build_components_base.esp32-c3-ard.yaml | 1 + .../build_components_base.esp32-c3-idf.yaml | 1 + .../build_components_base.esp32-idf.yaml | 1 + .../build_components_base.esp32-s2-ard.yaml | 1 + .../build_components_base.esp32-s2-idf.yaml | 1 + .../build_components_base.esp32-s3-ard.yaml | 1 + .../build_components_base.esp32-s3-idf.yaml | 1 + .../build_components_base.esp8266.yaml | 1 + .../build_components_base.host.yaml | 1 + .../build_components_base.rp2040.yaml | 1 + 21 files changed, 87 insertions(+), 128 deletions(-) create mode 100644 tests/components/font/Monocraft.ttf create mode 100644 tests/components/font/common.yaml diff --git a/script/ci-custom.py b/script/ci-custom.py index 3be7be76a2..c3cfc7a331 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -58,7 +58,7 @@ file_types = ( ) cpp_include = ("*.h", "*.c", "*.cpp", "*.tcc") py_include = ("*.py",) -ignore_types = (".ico", ".png", ".woff", ".woff2", "") +ignore_types = (".ico", ".png", ".woff", ".woff2", "", ".ttf", ".otf") LINT_FILE_CHECKS = [] LINT_CONTENT_CHECKS = [] diff --git a/tests/components/font/Monocraft.ttf b/tests/components/font/Monocraft.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4066b0a9889c2505d31b953487ac1d48fafaf9e9 GIT binary patch literal 202764 zcmeF44VYC|b@%s~xs#xvfxslFWHNjP4JMd?AqFFfsHhl;qN1V_LliA4Dk>@}T58Zn zMWuCAtVGeEMT;p`RIF6dqNR0eX~l{OCPbsfc3w*>8erbvf33aG+2`Inkl;t3=Y4yJ zbwAHupZ~S?+WVY)2}KBDBzKJv9{>1-PxzpZ)b7KHm~T?>SF>`o)(_yY~M~3ZYoX=S!}C z*>x+P`{+4;9l}G7hA@1@^{-vo8zyyZ4dDW$g~p4od-aOJ!O+S0)w~||;^nV@(c88@ z>yJaYYFy|jCM~<+x}|S;?bL4gjo|Y~F5`_CjCuYics-Zbla{?~<*Gm2{_MMX4Lx|| z@>g7cUDwKMH^6@wugARXx>YOA_)f=UK3~T1y)VD+Wj8$S$$xiq=(u`L2px-7yyDd> z&t3nLCxwo=eIeZXqaa^&hA{VAFCX)Qvu6KS7~Yu0JK^A`U-|C%_}&l(M?NPsw()vc z=&%v6$Czz{Bg1vi;ca~$-`60!ov~K$oUyhz67FYjbZ}qTQFFpY_D-XtzgQo-(Ce=| zj_}S0{ITPVFta$9cS9GN>2@ew^VNC74&D>Ors;aU;6;yH8rFo~!Q-8~2G@n_&~0Ez zC@#}y9g8~W@z5K3i<<&*K`5T+=r7|D5vA zejm@1@6+S&L+0;OhI}jA+C8?@Bga{KKGb8o@xP1rlKkH`Z~5fj@VvLjos3tWpUruc zVsoGJshah&|tj!wrH|I;zZ=f7tCn?KX*=414_ z`M7q+b*%iXI>qA($B!p*84?#Qo|10UIIs-N?G=}|{Geui?ac0;O-W;|TXBCr+hZoa}D~ox>Gm7hq8;VyJZzRr^fA#|7!fID|9`x zYhBknyWZ3F*InQ2`dQbJGxv=A#>l@N`S&9SyMNUE>vP7Ov+11e=Nvuntn((E_qy}m z+tb-Iyk}z11wD`Gd0fx4d#>yGgPu3_+}QKpo)7kXwC5{5|JgHm{^!pB;`#r0{`b%S z(fL2^ozi<*@1uLK?tNPCvwC0I`{v$v_kObXv%Oy(fA07R<1ZOMcl?vbUpxL;<6kiT z9pg8Q-#vcc`2U*Fm@s0(=m|X&E}C%JgoP7cIN`<#TPA#E!Z#;&Onk`1?@auUiN`13 zJoyWg|7P-cChwp8<0)rM88&6il-?JI|${$Vnz?4r+*)!!kQ|`W?}SeDXyPzUZQhW?gjE zMNgi7_9G_W^3Yozamy9AJolE@-}2U5K6T5sd%Es9|DFr)nR(9@_sqTLn!(|N$2pIx z^L(4aXN$9osYL3M;;LePv8Y&DEGt$PZ!O+ke5kmENPVIBGLiawB6Uac?;T@1CUsoY zaY@IcIhBsLQkyJN{bi&+cFtd&7tR}Nk?QEVe@{=(l%DB5SN1IIS<>^; zp4B~TdfwUdfu0Zd?CkkP&(T_>M)gkby_`tRBT_4RSN5*y-PHT3-fb~bR}rZNHsQ+?zCJNb9808rI`Kb=)UA_uPX4Av zD#S=lpK|$>B~xB9WzCfJQ*NHJJB!p9i`4aHq^^C~*DX>%n|8yrmpwdOG?qxsEF(4L zmg%=#e#>)+)S6qi-0~OqgnP~-Qjf4mJ;@_Ac<12P2LER8tAk$|{PN(J26qg8e()~` zKR5UngP-B-@n-1#gEtMX8@zGwZG&$ad>wHOgHIWJ^5EkJA3Hc_@XEnQ56&LEV(?Le zvj#64ylAj@aO7a)#F7(>PCWI*H7A~M;*lrLJ~8qH=a-KkIR4$^-#-4$<6k`fh2x(; z{+Gu;bNo%m-+25D$6tG#bHc|jKR)B0>wfXhU%cZNYk%>!pWpoRcl>$7)lxogv1>+gE^T{qoz<6UpR>!o)+k~7h7Ikf7~ zb%&mF=;?>%^J?^=vkyIx$BsLHcIVx9{^ZVoxpUv0|8(c-J70C@^&#B(lslhz=e#?g zaA(h*WAFIs9k<`{)jK{P!W~=h;A}pRuZOOI&ey9De#ANdgTK6ep})HQ!rOap@4CHl z+pli>_uFm{;kK{bw)3{F{@HEIZ(DfV6}Qd2?GYjT@Wc;)`NJRm@Z~@F*$>wI;6eZT ztABmR_fLHPm*0QU{-1}i|5+h??^@`p@6Gz>SM6KkqeFQ9x#?L5_kT6?qWeFeGxZyJ zSG916Tfy}Jg^tN?MPKpB?B%_DTDH;pa0ilOyZKdRvB2;GVu{#d^s z;@wZ%h^+-zaui>Kc0>O_wcpR<0sHJw@$bdaCSJ$6n!8Y3R9sxpsqyR)#UuUthhkQ7 zIrG&s?cHZl4WC^+r+99$xOkr4;mGF~FW`O&GujL7_4UQlj#V9?5zcSuc%wb8?s!w@ znR?batkbOJ*$+E!;~p$_9_;*4=N&wfH=Tz%@8bT)oj>WkTgUVKr=36R{I||yoyR** zbPnnrs%X)8SmQ!_KCSWa#zl>b8{|^sGQZY@XO}k~)wqJk*^NgxuH^ACjX900bUe?m zZd}`VTI1;r%Z$b|8d%nNR%21)PwmqWG`_^^FE@5Jh*0Ajjc+#omd8Ez*|!?sZu}ju z_BQ^3`|mXVh5PR{h#-&OZ~V|6Z);#t<6z@Q+~3i-vvF60K7i*xY24lTY2&{ezqD6J z8^3D&y214)d~&RDym6vomeHf@t$;@tQXXe?&9wI( z*>#y7d1qGFn|SA4 zUGJtxcyHJHy58Tlq3ch&{*HOUyQnx_pX}Na z&Jfy&zWwtf;(fv8HhxQwwU4tG4CdBJSi8a*bW6jyzUTg7co-2L5FQxL3M0d)aCR6S z#)R&0PB=G=4G#(r4iBNnIxqBu^FwbKA0~u}T$?jFObHi+so|mFVd26sjRng^;o>ko zJR)2YE)6rn%<#x?S(p_r50460gxTTI;mYusFeh9Ut`3h4bHn4pEr10c0 zKRhK|6P_9tglogo!qdaT@Qm=x@T{;XJe#G=bHn2Byzu<+g0Li9hyH&Q-X7M4cZT1!e4}K;nuJ{{AKuj_(J%r@a6EOurqw6 z@tE++ur%BdUII>E7dC}gggrCYUS)oIad>Ux3yrUkTW5mG<>8IR zFT*Y2i(yT;KD^wH(A~?z>c-XKh2gDXZTQpT%wm{w!?Jfc_&OX3>r{5E^wH6bK;dRObw6IkXd^4m5b(SOf98aSZIu zfmTAhm}eRg_3VsA&?bmnJ#!?)>oYe(`&gBXffhjU7`7GSz58*@{bobUpbgM|=qR(- z3}^+k1>(Koz0hK4GX(G9M?x4e9YVhmynX=kA21K%^#eHO0lfFX0F8s@K&zqc&_D=h zO@)?1eb7Eu-oqet7`YPSn2`rU7&Qjsy-~b3Y8!MogtNy%i=dkzjyoG(qtR>hDqp#e z=9n>)AmokVy)le4+8;tU?{_1!dj~7ekr2Gk*#PnS+y=z!b2mY|LKw^Vv5TSg5OzEW z{j?+SpcN3uJP3XdI>L2<WHdOyv2*ZO{<_Hw#(~?FnJ>NQg0$ z;V~H=Q>HnhxS6NpuOyF41?xE9QUw2AzU~PS`O_9 zVH!S~hTLh}*#Y7C!;$-Nct3n6bS#967 zLu;Y^?4Y2>CF`LBAzV5Y;{8hxhA?9qgxnchpd;+E%z^qKct3I+v>4*ENAlTa^P$bq zF?M1WLR%r;zkD{d4noeOCP6Eq-M&+E1!Jy2))jk0n2pb7&x3e9o7ayX1Hu2%+e5f= z7{q5+u7P$!heLQwFSG>O3>{#{XB@Nw+Qzk}0h$e=>s1FsxOytYXICTlv16fC5cDOk1|1IJN$`5o z3TOwrO?>v`#SpsBNB8+0H=pC4!tk5H>F!3$21U z{(0jdct4NhpO4MYUkq)8j)d@nMbI|rSO`ntyM*JGaNKnqcOAU0+XBJkg?#qH6%fb1 z@Ms9v&wZs7F|jJ<)eHw=XEqF!hT)CckTi+TOxWe_^Q_)rMT zCP93@jN_Lb4&f!!p_R~f2w5+k2O;aF==IVgA^gECh|m9ER|v}+&|GK@#OE&y&}?WG z#A{7@FP{OehIT;c^9uOC0{O4l3?XmDBxnJ&0on&4^OeYW3Sc zt42Z#piK~;zn<5xp9igj_J;5V3Ga&e{f#(|Ddn?Dh zbt<$J+8)B&MndTDHa>sbz7YPf7g_;v>>o0I?E+{ugv_-EX@>axkCs3j|3`a5cssA( zz6e6*+jl^Wxe=K+a?FhzpaUVS59A>_Ra`S0q7c<#=Rdt?_UNn?)})Y0ofZCL%iOwKZHLS3(bO7KwF_B zA^hnaXf?#=AK>#3%!SrKeExw$A@mJ{c(0H5`Zh!G{oo{sF(2fZ4>ImU9P=Ugdr04M3G!|L} z!D|z*Z-)2H@Vw&2Sx%b?vMdjpy4qX4@9%a0s891HtQa$h(!#Zk++Ggz)jL z2SfPFUT7Y)3c`-RJQl+CsSxjNUjy|A+IR>(K7SL$F`qvY!e32-RzRDeLm_-&B(w

aqJ zL-?Bj!S`<%^EbO7Z2Q_cXaU4AU)v5L>+2&S-upVbf4x71-BY0@&_;-H-$2$kCPDKd zbo>V6zHu;wZ=%yTXG6=Nwa^xb@qddhf7=VqftEv?AoSTY0)qD*WbIi8?SYPl@U7_( z$9;?O-#Qe+w}(ND{q_n7oxZ&b;{Csa@88XUc>nLVLcF&Zo_iNUt02bjJsiT{Ple_| zYoI+L`~%1Q1N{DBJ+vD_=68_!oyE`wXnzR(y%2o*8PmTF8VKPZ@zpWLe4*}hPH>WFF?HBcN4TLgn#DsKhJ>}|IY_P_?M~B3W#I>1^(Zg z0rA=Q;I*I6_OFB(_x%R61lj=c*}qPQ)Ub4zl|<7g`1F zV25xR1i#z%gm630Z(j^;XHOAd99#%(fUxOD;PoARe#cs9H@lW2p+yij z-O1;N8qholIfvkP=x+8#r$Ni0t?Zlf`HyEqE1|t1{A3J-zCY=M82^)_A>55Ucdvs6 zLij0Tf6C`S-3%QI;b&8!rO9Mu@L^7WBz+HbTEWpj)7J|y#D3k5RT4( zmO>nV6j{H5$FF8X=<=)e&`t;*zee9*Bj?wfpaUV?6QF4j$K3<3d*FR+9K`EmJJ`|Y z^W(Fjwa`xJSO_QPK^q|C45G*2B4~3cIJ96dq+nm82**NE%!AfL2SU*?23id9S;yf} zu%0hE*Fd{M(crVj5{P3P{h{cZ4)MI}P$~cDzp+}+(hI}Tnudu#Uyl^v;^Y) zNk>C5c_9S<$@@Yvr5Cyhf*0RAEG}To1=~U~6<$+ULK~s|p?D}f9=ZbB8;XZbgEoZX zLi~2&G6+7?=0RIR@$fOw+E84?XBVx3j)dak+0b@qAQaOXJDoApH$#U*@rYT_P0*fD zT*8=3=0K~V{!m;x7DAs(`=CRim;vt@yq>W$6f-$?=28fmGj~JBLh;B2&_?J$C@z}> z&4<=P9Dmu}p_s+^S<9hK(7sSyJ`&=X%Q@z9m(6j#FUO7yw%a3~&w9gkTBG43(PLNN!vbKo-vxmWc<$h~SM zv=Q0^4TR!qcwIdU;<&4ihT^efpxMw;2%R3wadR8cbZ9x$2f^=gjCLa|^j#ODjvLwiDTEyr97 zziXF6yCC>K4PQKMF|-9@%+r@ZTcJatShxVX+vyq8L-C9?P=6?%36E#4gV5nwi=a)R zSTqvi_(gr8c=l9?W1o#4&lv`x=W{sjIU7Uq+y*os+5jC0#o|fOa)@J}2ao5W%kwzy zc?U!B{IL)`pAXOH^Z5$`G#gqAZG#SnVhQ7yEP>Ex$u8(vD6Zp}>sCTrq5YwF;Rt9R zv;x`=q4)K3Azoh(@9X!3f+?j~IvrXHZGjGj;s$u%uoyzt4ZMEQNN6qu?-#-QMeuns zvR=F#g71qDgksq+s25rWZG`$m@e(&ec56NU0;ShFX#A|FNYZaa%_IZFbICHSO#r^4u)dIScvyltcG?&@OVpo2 zV(oNjHMA!be>4VK0&RtkhT`pWq4m&#P~12bS_$pqtLP)3MbKtwAQbPI4XuOrh2ovP z&~j);DE_zsEr2#ccZcGp8PFPNZz$e17Fr5zgN}vb-SeOg(7{l!7BAkj3fdit^&_Fh z&=%-ODBe29Q$3pSJvCs@?0kj-i2W^ISK?k6t zq4>}k2>u^J-iMI?p|#K^XeYEEIueQx^Vx^tyK!+SKEm-IIUI^VI~0nKBI9QGf9$4E zY;J_&6B|Qu%fe86YFa4%d{QVrGdmQ2u`(2&+Z&4Qb3^f02SV}14WZb%JQQDD8j7#2 z4h8F~;#(s^v3G4K`p1RhpZ0~~ds{>CgUt|j9GC{(1RV>-57&g^wlUDoP~5&U6bI*o z;zx|RgYkDlhk8SC7jk~QIut+I9g3gw`e%$i%x6E}7>fVk_<?q`(Bx(H}a)nc&xuzV*yAies~HE%g4SqsEWA;L=eOCl$TN_V4fLKR$g@$GQN|0eCL!oM$}4)`sxMa98%T){CDb=*OY>sU0vO~>d!eaF9(bBST} z%uBmFp-X38I&-3tkD1tgX}1W@wVPy~=z|mQilH8?H+G&6;XDRh#A`f%lCHl?yT|i) zscU?quQ+IIi)ANzoA`73E7R{x&U&ID7C_F|cpFdgm074$YA7S|#=t85*SGS=jqyo3o9qgo(g9D~y)Xyr3XmP9DrA*cU%7@ zKf3G`2UGB=a88yK_vZMpaQuRJex!z;u^ zS!$W;(UClYVL6FBm!o)=H3&&AH-@i8l-^K^Kqs#V z46d{K1U9=2ljs66jThClW6_CTc^DEOO$|&`LaX^O@`$>CEzPwaTTlrn4P>N20(AE( z*BLq8WtTPx*VGneggo#0VL@eRWY7z*vfQxGRAI{VO5>Y;&%l6k*DTf1m0tIgKhlxl*i#%uns|<~yr!zid)Th5 zmi9_RIgJs#I?<=BX0k|`dN=(z|#Moqj6Y0($lHgz7 z+&Nx)hZyS`nvShwPxN)pGl*+&6+_iaWX60@d`iC=s9mhEQuoONEEh5~8$K)(dId6W z2&&|GT{QIO(qw6LS6tcq(qXx4a*scxO~2paHhjcW+$uilS*ls-wH}#K zoAk1ISo%1Y#n0yAI7-O!+wm>+7+aiFDgCeP&fw&b5IACp#ldsXdm=eUYZ=7|PZA|+ z-hjFub6$!t^kilY`CJC@8F^393f=o{-F%&%QD@rsUi ziAd$(R4|Z8=|FLB=NMeoKIeb3zO5c-o?Bu#$Um1d8X-LecaX1~P zEhw0!BpuV}m87Gs&5;!QK_UnK6Ph{BMjhLMini93eo2<*x0yn|=JITQgU5C`Fy73W z_PjV~@lWIF1C(p7Wyd(FC~2M&$qybgi*V%$MwQ$xO}%nkL5Tiiob?&8?}{B)s`4CJ z9e1j^ER`(>1mj|C!SA_X$*ji<@tI3X(2s?ns`J&@F0a~#40%y_%n*!J>k7>+)p`lL z5-!~D-S{4Fl(;a*)a*-nX1I^@m!nXSw?@ign0%VW*nFdUh!klGo`_UD5Eap`%oD(C zy}sfq96?qU4Moh!CMxrL)azvP7s%CUzb|tGAAoZ4H?5K!(<*hIq*Z>r<}4!B2CZh9 z-mll$ ztz{hAdoL<&1(@3WBk=fsp7{*co%3u;BNlK@^N#sP-k7QUcYnYq1v_JDF=Qu-IH1dA zGu^A|t9*1mUpaim1U1-Ov^A*jSNd8N-|mma_1T6b@-EseyU7jN z9hc=AteYd(r$D_%r4&o^JGk_^p$v07lNUV((oXYsoM*(tgruiyyG$M*Wq@I zjv^*!Dk_uB_KBk`laPsD%N50d2HI??PL|OGO7kT-;;Rd-`I*z;HC&Yun-vSRzO-8% z5!q<9SlaSUQ%@`SNKbvkpFPOYe6PiH$RfaKJda+@@A*nyX2b~F({^_;&M3?NBp%aRvn%+4N-7obRfFbjjJRh@4@A#kjMJN+a^r_Dmk}ae+-Mj>)H{$_iE#iIG z4-a?`KsLH|vd}-nU-GNGibT^)vb#N+IFYrx?MDgp3^AX2J+W9!u10w*e0NvdpbYST zHcoRfOBH05XsF9m#`{LTq@uj2ym>vc@ze{KS|4w*#A6W&8q?(u?=ggP>sM7f6j^a4eqQ%HiF|!0A+TW_j+OV- z*DHfyFA0&SYAAc+ri0t5n3zlKPO3(qsP1zd8K!OnsWB7fK}}Ru+&qWQQbli$w&fAx zN^Qw-d!jIVNUE4!$c=Mqr?O0_8f~_y_9vSxLl~RtiBHPT zTLMxXIuD|D)w0s@taKhT`V8BL;@g&UD{nHK1X|RXW&8IrGV*D&ww5h& z>&YGJHAnGLzY?S3$hE8h&3YtGM9Hd(dBHtF+^hJc_w!n&xuRQqwbHl#2kZ!=Xv``^ zXGvBKSi)JW;3%-w4|)xbw7G_h?mTm=p3dfc%Q71w3mt^YQdoNZ)ozs4z$zYRdcATC zGK1Mlg&xN7r&{Iv%L#pMu)5zC9*(=y zm^guhoRedqiBXLWcB%LuwET1~@VHdxglz6n|6o2wDP?)-7)y0_Yg@* zHgm1vrBb$uo#6%ntPO}d>s#fuXSSYO?8!_X^}diGolbf4p3M7WbTmAA?S!|yO5dXW zI=Uh)axCOt`YiTzUfLSVF;mNLIDi)8km04mN_hrh$l7PPyYD>O?!O`WCCvRKBLD#r~v>S>h*D`7Q24s3tS#u?AwEGcME){^Hyj z=VG@~rxk@A^;wJ|#^?IZudmsNFj}bcXx>c=dMm>7QgTbS@6E(GckZIkV#Z9hLF-%V zu|S<>URJn@Hg{1Ks}QNdGM||}$u|{0_sDO7-*A2_qCWSv=onE@?XfHO(o*{P^i0i6 z&$IaLiI$q%s;~3L1?{=3`N;W4tPvkwFX5i`dA3Ds8`hR>on_LQ9?o<&+!^w~9dT;a z*HAx!!_o-iK9~ z@|sA;q6~4Is_#e`)ylZUX~Jl%b1+SQtoTKY{^tBzG1|g2VYH2s3P+}9>ebp{sD*39 zP#dOome}s+MU?OC7L@s}SwTI9&f^F#3UBE;bEo{)G&cF|K8+o&&Yn2{Bq@&SJkxkT zpQBSPNw~QripL-6oQ`tJwHG!s4#j3^pE0P;L>VSyo%Ov)uaw3?`6FaozvlJMcMS~Y zsUuSI$D4<-oa4aKSwgzoWqvW+%GFibu?gF0X)0dIKnt5@f}G!d>eZ@HiG82yULEJw zt$4i9(Q438ecvf~okp+b96gq8^*ileEpcw)U9Z3QrB`cfzU89#YQi3SU7*%>8@q%* z?VDLouZbOK@Q+wl^|ZAQ6Y9KX)%!3neK62P0Zn+w^R?cEF-jOss_X2OEsX1Uvhguz z@B8@Hye)ZnGI*LsB@~cMjiy?b=WfZxlB>p~&O&wDdLGrTW<1A!vg}k)DQ0cl2C|dO zsd=&UHL-u9=Zfc7yW90#3I#=A;Mg455XT4u&6vtHP?@kqCn)4%dlk|=WP38!jgD`# z8zYs=lve*Zx^m*K!rEfcb4a|w*}*E_TI2kk#EwE zcTS??F8I=2K`zGH=KD@s*GhA1w^Qt;E^4P-u{?1+ zWc^CUr&}|FaHUmP6DKX8;AO~_YTRl*w5$E2t!W=r*XE$7??p)&aY#{43wc&9sJMtb z&Ol{6t!K&C95a>AO;=vF@JzPC%>*hnYI+W@_8Zfj+{#z6uA=Svm94af()YA^yVh3O z+v}}8o0x^nY3=;b;@Khnsy_Wb@RDxotWM_79OFaiCx^D^s5ghyQ~5*payqFY_Ii|R}rS|>TkpUz70%(Q^Vz<|~e z$G32utfAi_S*wY5Mvz*T@3&eN%Xc{OlwrD*?dKU&9cTn!=~}I^TWen%{Ys8mxz1yU^DOyF9hC>>D|N!Pz3IAMnXA&+YR<5+Xw$Tw5{D)| zYObp4FEg0c-%JD5Ock-@90DcfW4uz2r23uKiCS}lwVD>G?$#8sx@(^DLeyN(nsD6Y z7kRMm8@-Wo<{*{(zmJZH0g^*3b111NtUKF_pKJ? zL+IPgx2|u=_ulKPoUj^T=O3H(lt=42D)#O4Qyt6rH0foL=`}2sKCJt%$`4kD=Ynqj znzYf{QxT~Ya$M*7q`so;e{Dy}>a^A97QKvJlV(I=hnfoYv(2$3U#Rt9#OMFGZtW%$ z1HpKst9<+Hc{k+Cd=Mzj9 z$5b9gxLPFRH*m0}thY_MliO71Q!BB4p|kj;^^2WJCkH)OtX5d(L|jxk^ju-_n@@lS zNvWwDCkE_e(viJ~+3?l%64qy7JV|%TfwbJ*L^Zw3BKUk*vC}zqEcZHr%C1sWzr>Qus-!R42+kYR5?@ zt9f+7qYikFUrh3R7q!Z%(V9C{S(|k!^C@ZL7^tga7Q2nHN4=los}9ZeD7m;Q=2%}^ z2pQaR|Fo>z?uCz%mjsuS`KhIrH~T7<#Inh&?K($)=lf7r!@LW{TGiERP6IoA3SL>+ zy|R|J+L|KnXPt_VqNjPzrb{svsFFTy_Mk?q&e!xZNaAdtH_}xLE!tI>YT4I1HP2MH zn>0=5lXWeG?Oiq1Y6p`Z)78y@fpUJK+>)wNVuH0`US;Fjua<Nj{K)wqB@q}G?kf{jh=YV=83*kgvj^g1)EG# zjN0x==DfS9AFX_2Eh4ANo5JHbvbk_#eH{_AsYPeh^^07}b@{nvj~xDTd&pWzIuJi|%dt59Qw+A2!EWU2y&53M46` z?><*LDm}Qwv|9gk#%nss1+RLl-0BrN##su;WgY!&QQGuG@w3WQ$sb}}O1;!s2lyn< zOCQBD>EeYxyDq7ko7%5UTRCc{BGo48SwB&hbS&3rT4Ppv<#V}ovSt|$TG^Db(;6+U zPfPhWvXY%kO)}fAPjlI+T;(3AX;9Vx!%uTRoathmaBl93T%}|SwZvj&SO+OYnYk|R z3&mI^%y{i1R`cXm-Lz%W8Y{a7C+)#xJc~-dn8hkgxrR-_s`n6C2VLtSl9rmy1go@A z9uiVby+hIzt4qF>rim*Z=1DXy<6^a$RVBHMCpE+SZ@hSy&3Z%cz&+t#UgVZ^CD?kE zed)i#|M2P>3g;_-CVnZS;+!6*=HyRpzcXXm^pVXWO?r;jTyGk~l}D`$T+d3|N>R1k zezS`+(6e0g6RF((Jilr?tmaX5C24xLEjVif`e2>nWW9GhTc{X;&NiBw<;{xv${z6FgQ1Ie?e>wt3F4cvqY)r>vnfw#tXpO-X{^ zGM?rG%K&s5TGw`(4y~u^nDu%&&zg>{8aA~gnLmf?N?ofX79(5V5A9QHpW1lUO0LY0 z$jf}tZqBTHQPW!tT6NdE&HC4V8-f`QbdjCRXmL)o-rc^7M4bR5RvCnq*kgkcFf&R= z3%GvIW?EFBteu))eI1a#i&pVq6`|SH7qL-o+lba^va1?r`w-}WbXMBpkc~}Wcu)Nv zUoXqY>)an*f!P4YrFYrc0&7*bDBDxpjL2lCvD91SrcUTo*YCUTlFfBNS}imGtEXny zMd^gjY?PaDyUxJYbaB5$c1ArJ<$0NkJDO^D3Z-3Ht_UJ#fTfa0wxl?jzStZ2$@X-O zw{?`V-EO{d2=)>$YMSE3Y|nm1vKtG)CpFbvWHo`xCE2<=$nort`F@dVy`;IkB*YXq z5t+W);UuCqQ=qBMMS5hcQ+|!RuQ$mNe-atH{i?(C!~6ySzi&W{wI_p@%wcku{BAY7 z@>Pnh)jl+@dD~G@Iy?U4V$Ii7k?3njrSl<^lAkRzSaC*Ar?lW@#Rr{DkMUOD6f4hZ z+o4m#jtM0Pw>Za)=^!l>XGSw#zEp1MVk-@Z5sPE3#P~j6x^@ZqoTv3!6}*_|)%7l_ zCYEw)g=M8XF}J-%#>DJY9Vyq#Cd#ne%XqE0@x9HLhIQ6Lj7l?)GCLvEf|U{*2GYZ9 zL39fbMpe0q?xpujthy7pr(^eiAnJkdsV!QQsjgY3nE#RxF>Ik{Jhr3yO$i)e``w<`H47}F{?!MjIV&H2ryjPF4gVp3 zcb2|JHJfQilDITZhnX9Oh?Ln&PNoEw}1r^d_Y&_E{Zb+ZCt}{))q1V7!JX3S6IA#~# z##}FJM8cWXEYEVAabl-o*i*`8*s{LdR*yp_BSuT6Piz6WQjtA-Tc zc@vB3l8X!`hB~FQn`Pi%{*aK#P@UEHC+fG#Go@e>Qxf8O*nDpBY{EO* z$L=Q0_9gPOIY05gXOHq-GScK9`CAUO@;A*Re`aK_`KG#f#Kya?N(wLFin(7?nZ>-ux7&NwW}aLnV{aKF=N5U<2=t6(Z^TONq)JDQz!cZU3nexI|g;$~(ufL#< zs5^p(-ODrd;HiphsC*Ealn560k{|OQzG%;{4Y#C``5@lq_;2Zn;(0&Sp{D+=R->yc z=Biw3f1c0lKiOIFlR^AT^^yseK91F*%(sGH`L6xCm`EMlQT?`W>~Eu=m9^f}5;M&} zc$jq#o{m+|qzi!V55J;Bt&fx{ap&Jjrd#0Ge2AO>d6l+m1J|@tON^|m69$Nx zt=AHtii`2+LntgP<$T_d8r;e{rSl)G4(Ku3{%(whN`C+(pWch_)zFcY{gb27P^dUK zA0pA_Yc(m>nLai@2+gWfy1t^kW-j%tObp(G)caNSPSK{5^N4*?W@ODTHs_5WVwc%} z7r?#gu8}H!V^;-x;+zt7Q6EQ5i2beNWSyJ&SLpO6$R?)bD6bc*;x&EoS}VsOm;rTC zyu9hhfq9YYL+8AN4ewy64(3N6>3F4yC|L|xJCNE6;R{q~4+}2{UC8x&JK+0+v!-EGs(u$@{#wZa(>+f#stvMv6p+Ns`Yb_OAFAI~^i!X@72 zqyJ`u*_E!PH@muHcLzWDRQ`2t-iTP@mQ2!D4x?^yPf)WF+Nn0+n~r|-B4f1kO6KTS z{-Rv`sl5!JbMXf<8KXQwrbSZ|1~)4qsa)55k?k+VdXHQi>s6i*I4Ax83`uUewvnDl z^~{V2isO8)VWzRr>(2H(nG>*1$n~+hCl37Cj;2s=yF#f_^h$e~9d9^8+X>=ldj*as z^MLr6^)bUegM6s5z!2M;h#3Kk%8z8Y;BR@Fm zG{ih$w)<0b_j;nS<+&RE&xjTdWepMwB{?-Ap#fl+4%8*_v3Y~2;xpCPghF;X`)zgM z^3jGVG5wM|uiTH~fggya?UTxSyf2^FoXEXZ7`Yx3OaoI59dyfmfgX|%!YX8m*Qj`r zhs7RHsjG_j`A}2C1jjphC+bjQ5?}hrh)MVmRqd)VTmz(f zRKVCI9n>S>3-6ukxQ2(Sl>VBrt%?u7yn;vHs#j0>Duh+}CWN>*lT%C)g^RGH+=ycp zQAGvMdQ_x=dBVS8;&F+XsAReqEVq^Qg7PMaw50?O2u{l~LwB zGT6t&k;t_c+Dd%lfzB}}%IcKmL^VD-OmE~pP}a99kKAt8K(<$2&I=PPjGdTCk9uB^ z%{A{4!F~or2MPzZA2zRI7jw&MJUFg%aTKH|z>udF(Uv$^&BcfOp@$wN)8gJ|xe#3e zgVxx49im@n~tv*Ev)?Ea%Ez$K_jP ztn1L{$zT9P5zj`qUws(tl}Fy0*HyILMP6Psbq>Znz7jy9{K?@QZFZpwN? zqGm=kaQ~^-^t{(Oq!tcxn&R$72N33CtK9cmgU87|cz7RV1>9EDinLM*C z)6M?aQ_1jy#7XDCXJRd0M*FIFP2SCGtNGVvHu1N4+WZ^4R3H#<@~>^%Sb$PqRXx0A zRW;spt$L2c#rh?CL5#Kb(C^lA7Rcs#$@CdZ=a}RRubYcfKcT$AD%s{JM2b}oN1(w@ z4mq~N-J0P@-x^Tv3JY#2(rl)1)zq5B0#eEKdBgBijxjEAzKuis%b~oHbY`seKnXw6 z+3^>3w#p_BW$F4!vlBeZ4TBeKE1-C$F5=GSaqwYkJlSDQ@`O-g%Ut*|B8SzWcfw7J=| zcC0f5(5Xw-nQ_NonxibsOMFll(;Th%#x6;Cw*1YrMh>@|7c4!EvtGno^odPk^u5M_(UXty>+P(hW--Qpj(xNRV}=m!t8O5Z#?vy^s>hlORHN{odCX#l ze )jc(0-5Vb+MlV%``i^5}vS3RfIdychhJIFG!&aUq0GYER0QC>3?=LV}cXaaA# z3jWfs&ic&YlY#F;uES7n8p@LIycSn|TN`=uie@9j1+3+H4KKy<)Z%4(EIxPJwGUQ-RGG_q z$C19SMq?FouZ{5XTKUd|$4*UNM_ve0GtX zs3m^lueQ=A$T|gw9IK{jKho^=>v@Ta=e|YC;-!fB#)rI#m9Z3?w&EkaRX8vCDB2OP zaImNwpDI%{*vq={5}$bf1OGojol+ssyG=x(>6I!xx8y}0jiLTane+_32IBvp!Btv{ zCN9vA3AxVpfB$gx5}z@5=`#kVG0cPc7`HS2e?j*DV6Ykx$I)@5qlw-;^45QE1Li6o zQq(__p|KAu>${>=VbW89*4fv%P3Hkr-@%X0qIf1KFWcm!xX37O<-V=tf+tlV^*vnr ziimVhFzRLe!8?|zR%y;cw`wf`4v3;Qv>fyKHHx;T)9ge1k&u=vbjPMiO%KayS>S)d ztI(@IN4knpiZ4bOOk&@WeCU0m=F{AN7*?J@tuXbQ)IvgMYe=(CeU8@=X=iEgl~Vz( zasm5nzL$0>vt*s(?6#Ou@F?S?UuLNBAQpJXVt`L$OlsFYD+Vf_iih`P$u}BX^&2i( zvdfz*t(ss6$#qX-sg^>T^f$e0V{2c=2k8+%^kuW!dp2b}p#eyiD9_G4Dp zh3;~GFrekLQ?4tS=y~LwydZsix?TQR#lm{8JX<_pg9l z716r?(My>iq!1oXX(^lA`pmCAMP$qKmW1}jE?!wy_JXcx8+F)f4VJ;jd@UWKr;?u-Xwy;6 zMdqK_6X5Ui|5sGR%qJGFZq3eyC{!^frcajT{-4&Ok9eWa`QB&8`Br{SvFAB>;6CY< zJSx`Jb2%#6hkxN`=oXiVrmWWh4W3I;J7a^2B|qt0@k2kw3)IU>VP95?Qa#VQJ>%s# zihe3>bL)%;^0Co)m~Et-2~XKqYEoHP@kF2Y*Qt;jnj!M_PsCb8iO;IOW-wGJ;rn8< zrp(H}zo8nhIa_%PPQXWuLE4IPfBy!*Yg6T#VOnuEOj^|3$5m~&m{>+AIM!HH_+cKp z*Z<#_@MiIBsWUZmFqnkGBF*hC8rx4MhD zsJ+c-n>197N%NR?2+cz$u}wO-EuUK=U zZC2YEC4@W56V4Smzf~%FOl!HwJYnZ{O6<1cN|~N`Wsm0X?6oG$%J*Q@_8v;jWK~@^ z)q979=~d3Rwx8tlp{l3#Nq#SXqK)TrjFvs1hFhuT$zp1{WIeD&E@FW3>Q7bw;?dHC z=Xw>VABN&5dV8*OKK=g(D)v$Fd%pOjkp56XKW*CZXt5URbuNIPM%^VPbcL|Au@*Ao zQT@KoDWE?{!85Aq>PS>w$S|Erq&bli z59Fp9+iOMXacS-QJ<8(T|IR}*y=9`+8Z^*jtTzI;V$cT(fB~RV2|Mvc0 zC;8gsDYtT6(J+3^r_AAaeq0ezE%R(NKhe9HSGcpThSqty*@=+@JQc*qnTS*N)tWgN zTIkXe%B?z<9CX$x8;_rnZdwRq?r+6AecL^`*iL|gF5{{RH^&JxeuWcq7Mr{eaqRFs zUh7)wl)jOmYbmYJ%UrlSc5~jg4Pjz3l$#bLJheIt&K?-!!ddBB})6cS!+~ltuD@#?+s?km3hukxW_ETe+ zYl*yd`N-j~8*b)7k9y}W$_?!rDO=WU+Xu0nscKv5G0hg@SHml4FuW^kz?k6+Y&bre z*CyT;Sc@6^s1vyaN{WF|s*Y+O z8uO?a*XEkv$^JlIKdox0M$u;pW$415N!$9VnxP}zBh@)yT`FTuLDT+2JU&VAP^|Le z>;g2U5*PH*+>FoT`EDfW51snu84F|7s?@BCr^ia3rWP=c%(K~q`h!K>fd@a=9rGVq z_WSp;B-Jw;DVw}-q9*f)4{q-5=+N?dUY(N`I?5rHepO#ZZpM1YT%f8WJsnfA+PRaw zKg)9{uPK)430ZlbtKzZw4%!X(^w_mJZat}TJ=I<1vCS8t&H^X^dYQ0gUCJ5OS2}lx zuWa6oRv2PpN zYS_L{IgjEHOSZIkp*(Qg;yjvp*8I{(JdGtkHAb9>Z5fm36SJx6Cw#XCMn#4>FOx0ulzb%&n6GN{X-r%= zrRzbWkA|2_1qM6kk;ha%(A-`5Kr*xaSD#xvO%slCIqJvi=S8w}ov|hm|1`fSTJ7di z7vq_b>(?@uDu0ynv5pGQ*pT*MgaOML*&v>=%m8cLC6DEM<32X#*vaQr@iJg#acY@Y zt-AF(#$v8njjww4mU)%JRi=*F9mj!zd|q|0$hq|)kgnH1F^T=s8hk~10A0+PwMk0BMc{mEQPQsfA7ou z>A3W;<^E1J#44MzJIZZ z3^x;8;WzaO=3(n`x~uw9_8G(~-H1{8ef9Wzn)0T1kkplFXe^VZv-X4h_fCG(|K}21 zsHRyQ$vEWcdKY!OJX8OGc1i?Er3F}~)jPU4a9#p*O&gy$u^0pbO?Z#T| z@$s7Dkm#f1Z0a%9s2FOBktVt5V|4aBGUvj?xs&@SBqQs zt`c&h80je0YJBO2@Td6^zWS?mGKNC)iQOfRyr{P|;%PBbUt>JoQ;N@Mj}`H%R)wg< zKLxFVcnn@jzx=6j%TI9q*pJRQ?ar`#iE_B#cxTj>#b0R8-mY#-|k{JGG_vlutoh)&jX3O7_(G+_no-+bs( zIFPO1k(T_jPDbC<#}V_Uak_-q(O%U@<%)Dv?Bq-H=BchNiS{zK>*QmluUrN-?X_qf z$k>|KT{e2u1s@rUKG!*QiqwLt;&@D`!;il z@L^+GRBid;kH`;v>6$lcMB>+8OK;nnb*%lGUfrjrVL}8m44sv7!Ma%Yr)qe94w$Jv zI}4oSp!&@t!yLSn3Fbjr4EKs7Pm?bzKYIN5AkQnG&n+e~9%xw2$O;Rk%uM#>h^|u9 zbeM9J+N%A$nI%@Ts4CUcXa&Onq!8BQXqI^#$*LiA5k91QrI5of{(1_$qhdqHw5^WL zw^B60*xpYH*Y%xP;Y7cZce2bk*p_!mV^4T1L@^sl`nukk3_ALgW_-!so+SNamRHF> zqz&$K!)44#Re3PQ998B~^1bi*BtzUuCRd@cxpGK5tYXe=lA~-LT23;?B$Rhmj?Kbr zmSgsNh45A^K$8Bb`uJH|`As@g06)rmB?DN2Wf{(~ptH;*?surW`*VzBPY&Qj&Fbed)ss zvP!*A(${OdGOa1!yrMQ`b*%JW{pztjUEWQ4J4#dT*?dl2(<{-_Up2G@(@R>U@>8pLWq5mJUQ}K7*jlcGsG6yI9Rkza>c8*i3 zHM>r9G3B*!QQcHAuUmd%cJspc@8wLt;aJ<=Hs)m)i^)@UR&?kIIv?qaqNY`ow`rmkZ70Q zRb#C0HNQw#`BVO(VrCL8+SUQFXe1uFf4H9AyrUl6z9r?dB&c?tTrsP8(e~wHD{Hdq zKBVR_^P-V-O4oe4Kk+{vr=cU0bvM{v7!B!gVQ)p|!aRi&eJLzgXTy zFQuwvy%80-hBvuQi~ue7@gd{ovK48fB)phxJ61awwS8>aNS>se$JhL6M@^%Bq-4eY zJESE)^KR~^9OsO*!#KpRSjuXf}JIAG&NUz}|;>wYMo%~sB zI1VopS7CrFB2rz=WhX>|0p*3^xvW=m6@q2ByN)+hwW5z>eN|U4Z$&h@%?2h5t_`ip z#z&TiadsAKiHJ_B<3Y!gU*2J6=b<$>QMGFIv&4?@=~;$P@uiP;If|PZTorsWTbW~RUPh{0U>?I})lhSnX(9%A$ty!XUieG32_4cJ zuk^C&Nx7`c4Bo@x0nj!6MZ1pSu0;Z zX0)tCinzo>;1RzQj{oz|rMlrlGW6Yn{BvTc@phgh8(-5QGBAH99$*U@hOMNBG%>5} zoQrn3k;Ob%2npn)CTCOu?#X|?N2aQV&lGvtL=H+{-B69Rr$qAH&O^o;8^=k$&zw{# zRk)Z48Y*#qjw;rfYX4u??Fc2M_L3-^7&0VQ40KC5!q|9zOV`J!5?7J7-1KVW<82D@ zrc9wTgV8(kpq@t_)G6W2oQrHjJaO2pU-)wM@`@KJrjP%I`)rg)v1(5mWY*@$20nuzDCE_<7u%sS;%CROLX@N3vnzp z$bU~sb}Bx0pP@qDw40t7D(n>;t5{Y2mG3F%ou2!;PdcE2WtLRIoXQ3;OD!-x5+cD? zbd^bUKyspFj&f4Jp#~noxnB=t$^gF{JMbh9k*8zUtuoHW+YPZrS?YvMLYXV@upY{) zj8I5Ky#~boue)5^mEE6WTcO$AZp9?}+-*I@@ALTuMs4~)GPcUv%ts2aBJg3afu1Ku@*Dr*MSj!icX8KzA~RVlYupw*nB0%gnD z6yK7saYaWv56afPm$KOERk>n$?RBi|r)|DY=#i9s$`i^|dZnA@7k+=<`IlitI%N~oOB;$X5;aO)lVL+@`GH5Havtr;w|Bs_u(tL>VJ{75>zevh_rtxNJ9 zUWvDTx6}GwpZhdQ9Oq`)45c8n>_#2Y zQ3oYgS(-ejqdv-It?y@2k>wLr7>lg!4kZ&*SK{_k!Vvzj{9#1n6{EBc#-$)?~#0 zR}MYw|E(*~do(1++gvS$TwetaF8b{Q`Nw84&Pka(i&L*3$GyqY-VeU?e$9?H@2EdW zMMh4Qj;?e1O@TOG^;&Td_Nn)(H4zGqigNAZ{+IV%mi!|rcGaJ8=gwsy4D~Af;d}KP zl7K%nYsf9y1&QaX;oW5xqXAlg2lpMwQAq*jOtJi~6HL`l;9nhsf;!Cok^EN5vTIIY zkVIwr;9GTFh}Pmz)@tUca(74dQ@NUISHuPL ziO+ws-EzU>ZL^>!nC6D)U<6tdgdbwhM~u`vNpU5z>5*dOdWawSkGcTUZ0(b}nLkSZ z$8H4Q#p4hy$?fWv!nS5oD!UH%8)KDsa+dg{+)Hs%U!sgq_C-%|H6O#{{FX3> zvX+CDo{9z|qMqPZ8-><(Netxn<@3GOGqMODn}_SyN+HzC8C_J(H^fJ>@{D&YmBFzt z(JE-P-;`@n?gQf07mU_?ryM>r#>y*}7+A$HC)MOyetEU<)I4Y*>CNLteOG=OKCubA z)UlDseXfcZV4{v|@^SPCnk_v8gbgXrF{VX{koX(amTRsJvb2{Bb0t=)2~Ee1Mw5c$ zERf1go!wR>IZg#B@l*CH62?!*`FE~XDZ@DiiI=(8ZGXWW>^6X5J_ieY-W{VVUgdYG z%%iZYY-TRBy_pgNAjf*g_`l8*eVMPD0ikK1h_TigbX#>LmbThSIb#3oi;uO6AZJ@` zv))88vfOYEs^#NH>GuddNCJDm^;vo+8yDv#(^JROsN1nLh9r5co!I5;2~`e5navbL zHswazXf5+tiq?7%+PEXy;4~B7{39IU)+!Lr7g)O#*ZnrO{z7c8CQ~Aah9!vf5 z^9YKMd(7r#1;+RSLv8t(>k^jA|H}hAgkG`_PqbQwmowAU&DU*9|33<-@aji>sO+0k*nfwxg6(M`mWT6;}sjvti!Mh&!)fkU(#C^m?cTJ^2lW&&ZV1Rn23|S zEWcB#vKR>$;$o=7p19`lg(H(vTsWpNX1ig@Rw-nJa)N_=y#erSqLjnxax9m`U-O0P zp0dddH0K(Kw5w{VpXG?p_Z+Qi=_6zsh|PN6mR&{NN*Zxd(pC-Q`5Gbhc<)fiQLt6f5he}l*;f`O$8QH@AAO#yVjrho4X$XOGyE7}9LPVWTso)No>aRO$TBc%X~^yv!@i=5b>~ zTy@K84SksV9vw6rf>*ouF`C*12h8Cys~=t~H9}cx@`N?-=JCG{x6HC0QmtR?T+>uf*-pnxfY2;1* zqnlSzc-QkcX~m@h7sw7{R{#JewV{pO<<_6gnedMpKH!nF5Gw(ON%=MKqhlkb0INvA#kUbV*7{v5( z!|bK-5`BXF$|oM3I?|+paY(+X#l`kGFKmvvd|;K%V=lWa?)JXwQ<;OMeg2NQJALTB z&#>*eY4Im+;wn$UIj&Xvzz~D1Vev`DoW&dU9M5}a>Kb#>OvS*t;5GdkRoP*x@ivYb z4}4DivCw8SBB!Y5@vFzK0+fRscUHJ&UajL2yJV5w+w+L$zKV@(bXVDf&9Sw3VvGD^ zXq07%j|VaZ)Gy!Ql?q|zXL4B4OIVh7A~rSe!3*w&uQGa;y~f=9@5<>@SZ992R-doT zSL!>&r?M}y@y;<}H2vQ*8iQ=}wcppqyDn~^6)E1x+lUPF?(ZsIik?NV^pi7_{(X8{ zRV#N@#_NK5{xoR_UqwOhCOgG1-5lYSx1_OdiGS?5gsn86Rk75uJ`Hg0!SuAdG!~3< zKCxbl%Q(7LF>jJKdMvAOm5(ugO*J^5*~|QM4)PImT%SXsDgJ(rv(@)#lpu6YgK1^TNK-?2 zrH^`CkC%_m>XQXbh*CE$Xj!>R@gmj{OR@nT5tW9hsEK`opKKkOz?rP7LYLmLtB;Uc z+FHp_ujJ$%PUU^%);bNCnWoM(c_4`>A7h_i_HoAF@_T0L9yGRWJ$xl;Id0b>G|fYb zLYX(Q8IOLqSo#bi-^D)FaTRTnZ7Gg=tmidI;MUHP$WP~YnA5D*Req8_k@QI^!)AdB zq4J1TiPAOY6D!*KPDILym{aJ^`k>n*qI<9Y>6u~^vFl2Eq>ZiTm_fUa>9UXW?yt!U z+IdOE!}CG{a-3N0aE%O&_|tg!J+D$dBhMMzrepGONMRs!^BH6{JB3#e7!fb-U$3S7KCJvjb*+Pm{`YU z5KI!IrubUlns}HOZQe_JA5|jDPXCXtYxT);Lv|%ZcubWc`4yN6(c)q@mA+55n9o61 z$p;VF`rTVaW8l@-EYY358?uVs<%9A64q<;{G|^{X={^&RJ!T4-V@UhVx(6OPNIk&gOui*g=GCY7Xby#L8j!N;D z`AMsYxyUp2>Sga@{g3U)ISyi7GdKVW7`ZO7Hrbv|HOAL}I!wE!?D}~@sA`$!5Or{L zxAsW9gu7~-%VTt0597wXe`7u~yy7=uMx#Z_hRTmvidMXlmX}`Bk%gS$H#r>A~%6x2-K+QkqXIsNDLYx~+Z6dxPy z*l6}qKDstGmyegDz4uza^%>NC5S~WIvGTX)dbBR>@8(9O=V_sUn=*fTESmYo^I2)A z9_<3SDh_E})vYU2(%fwWW2esZ4Cl7qk{$YUy!d0;^&1~!&~#TuITe4afwAs*?si+8 zjql0%c|9x{RaoY_KKU|bplJy|s{`tiYdI0Yn)IZ=Sln$6;haA{noP76Z?h50#Mx(^ zG$=i~j|{J#Po)l6Qc86n6bEbg((%5om*v7ld3=-=_qL<26ubKI(kzR4gbK-C+q3l8 z&1~|HOGL8Xm;7W=_NbhW9icy|%^CEc@(_QFcF*Ilq`Ad|E$ffA5B**-! z9CkS+Pv)J>TZ~8`ORhtlLw6m&ZF|lKG_anmhXQkukuYn8t?Pn$0CdFoZv+FH<)-^_OKQl87u z+T7w%j*(as@2EM^YhzQrMvnQ-tk&85>~MK2w>6hj*_d=o1LZRH^FCHavBjQUV`TrS zRI?7Y!WGZjXo3hgFzV~M4o4?OL^O~t^ z`(Z9f+b8d`nqg=pWjv{eRYQEKJ}7wR!)p85rjILM^gN|g8A1yyD>I?AG0npp`4ivE z$;O-zC4URGZ_As=7cJN${-j@#tYAp|&74BW$bIGYBz#js^mgL#J}y#^Khms=r|g~A zlkKv07@#)jTa)zvNDr+AiQcDYY!BSt;^2H2m7H^#d@R<_EexzPEt}*a{r8J zXY5{iQq36M0L{*qjCH8dS__ecS9rDbf(FqDa&v2!I$u!xkp9I= z3jMQpF%kL7#VNtCxdtRflp-f?>^1%Ck9<2?tgbaS;#*}&v~28FBQp;&(L~tknlz|Q zQueleA89FKuw%6VnS%)(!jQvKyJ1VT*FTPPIlFR|d-R4p>tvmK8*M-yY{fmGVT=1YUPJ=j zUpYTIPi)H~P@b7=%!q5t40UB@G)dW?8AfB0u;$B%v++H?qWbZLAcFZe?{GgcZV><^+oFWSu6&RN!WtOZgsq6hqP zn-anwa4CNaB?I`6QY;y=!l>1m;%wm)9UdF$M z16iSBjF&ttXyo!R9sTm-lj<5YgL9ita2x-?hi|OQQD=e}kEm5a94dE-9mwsG&nOnq zMCKAbvNQn=GkzJ~v-V;yh#@jAC_SW6w#dDeF)hU?M1OTg!-F`C|D;E*JC*fAW|4?H zloPI5-NP&ZYm+7S6Krw$lg2c}Oj%DfR1k;ZPrq{Z#_J}mEY$|+eVh#lsbbwCua2Bf z=W^r@f8do|vM=+8qkWVna5_G!cfe;GRu5t~W{j6v66aRLqqb#)D&z=?ODoafY}fZP zy<~RCaSrq-okYuzk!Vax%mPJ$7UXZ}mn}7uf)}Gx%0-rHbdAxj$(pzUzoH$8G(fvZ zLB==op){b(SXL$)6X&=uV#lu=ag4D^Y!O?vxfZA*76(_f!+zia@^s!T zIufc#nMa-(N!ZByUWQ||YGOL%y&Q9c77OAfhgY{`kq={Ek;KR!1J>S)iHM7~@O_DU~xGIgMfv<%e=J{lNAmw%P0BI7aB1 z0Tcg;&t(@Q9TBFZv5=R7cky^hUR|A>&N&`g9z@=PYH4w{C6Pp=%oZK~Cmh3xX=WK8 z+LrneAE5nHQ}`8*voBZ>nlS!KYEBtSuI-NOnmUy>Bu{;1 zmc2yiU958{R8e6yAj;z=<=u^l{RtsHqrKc{Va4i8v7j|p3e_(XsJt%*eoRZFF%7%W~SK);}RX)5x}JCX^?L=-uB z7@b6*h?FgYUMWu1V#X8SJ0-8lEbs(xv9gr72DuumF#53Vd7}>HYHT9P^f5yMzKEkm9QN?t5A#8LAQas;PHkku2P0f@{La%EfE2s9-~IAU~e zG1_6%qh7_fxsS!B?(`$4BQiY@7uiOEX4nOFDUl?j z*EY|nRol`e-O>uhz{dEjLPR7FCgswJh!ds6<~`bo1fpjdS&H^=G$baYg*d#1%1LaY4O<9X_DBipW{s zi7dWs?QM}*86tyeZymtKX=7xhiv-x1Kz-$H0PTSYneh4~*)sf)9uuuqY4>cEq=m+X zl>+Mre3m4#0rl-pn$#sNMOnbh(?cCueV5SEK}k6sX6!NXsY57N&M~vWZ%nG60NNCJgSVR4;F%4~GRAaEXOyuq6p!b4^j04*&tWcY+lxO z3_plL_X1yyn>}!$Nj0J0Ir@#ysGmgOp)+H&W?)EFqCqe|cqGRiTrlpAn`*C+1>~6J zDwKnuSx6f)?L-D6c21X_G5w&@rm<$fX)BJm#uF$zd1f}a6|K_-IEu-bYvh& znBtpN&1%GMIweOm3+aNlA*m|4XIJtbs>4I`P}$BgP)id>8cfnb9zZ?`FT+4A@)H+RTAfmKt9P$`2&x z#+Hs}b9am|%yP4(VrvVzQ6@jG&92}op@5nY34n9Tp*yyc1nWkYJQCRDpVSZLbna=~ zIb6sB$OT;yS7b;2nfEyGj)#exXDY~i(Tv6P5a^9|g8@_>n(f_r8Cj!*#ZjYLSH8ic zt~rYI?b;v+Q5JC&LZNeJ=kkg(Q)$l?LaRM8!B1g*5u=rvLvmJ1-a!NBrRc`Ag+-BI zWgaF3%H5g~tjA=S;)}FUiD$&3RWXYZUo>Q(e*h^-qy<|zpJU@Ua|(jVV)5Q!;2}vyHIQq%Q4d(J1e-zJWkD#Jxi(PiefVLX(!=FQWXcWdkjs3M`lE6+< zsV|9flx-G2^7<9OB9kikg~N~- zr0pfaSGu%uw$S4G2WRNh^(*m*HZ4{T8?{l_P{ALifm;eLJ_=dwz`7(X8`u2n8VgY1 zWr8Sv2P{&cTD9^*eo6PWyP3_&crO{)BChelR}5#c7;MShpV8Vh#1HS)HnCd6hq3OC zaZko8zW2qB&1S7bnAEuE8F}jKRhJ-TM1OpPUSBbc~51-{TykyL?v=|!Ll0Gl> zC05EB6xXxJ2WKwu`K-@u4wb3M#tZ4o(2VgRvlO6Y?Nz3>XU(Kc|LP;zcn^BJbuGMG z1z1W7j%%(r(sPjH+EUKYjQ@>rhb!alhg5(qi?+G4Xq&!DN6KJGay|;{>d-LtD%TFk zkSW&_mz6W5qF;HoD9(bSJ+Gv*?P&=VJO1wyT|x3{K~hKR(Rlfh^Gn>2Yl`-zKI_t8 ziI3-8?Lz;+*ZYsU@da9{vp(Y$^a;z+ST8v(Af zE>c3p=@;Ai&lO9aiJqCgRQ0?R`X(O!5{z^sOMIq;}wXVcIj!#;f)aXA_um4~( zD?vpTsyJ!n6+1$mS$m;M_!L+q+S|mYNr#Et4qa*T_Mju6r8D0J#m4}`FOk7C&v}Lx zrn3uY{nQ1o2m;NB)y9tcNTJF@wL(4Hk88^#)QO`9Qbap5Pu7YQiS$vVNhQI$mSu-q zMw4x$eb{!S!nL(D@t&juxSl+B9s0#$2k1*U(h(!yCwr2Q)%(hv-md`DXve=r=2z!A z9D5|%6Srt-a)c7$KeaqK4gT{+968}_d+hjSWK`qKnP^8H?!xwIKpNlGJ}W%O%6~X> z)kjXzkx5T+c3tm25~g$UdM+)6S6ZlzNUqt3z1+E4>nmug9t_9Fwz!9UQC7Te_`#Hu z%EMY5dG{TIXQCI%OevLmk^=~Le2srZn0{ub~lJH-bd3^eZU((|(L zi@r`h2%}_HS(Ys@ZqMhhmbfe)F&DfEIn)e8DCO_+4!M?muBQjzG1seh$nP?RgMz&6 zW84u+Kn*Mk62LDq7IVKMflRu=J1)7}E_6y9llU&92IY|b36feS{iypopkj<-7mRa- zdm$zJ$+ABvjVgoQC@`Dt@wzC`WMYlV6m}yrl|TS(>-8{sZ16@KhR=XD<~Nibfnl+- zCF55oJ+Mz%&&C-_v>`p5Iul<-Py3|)Tsz3sT!TfMf=s1PZ7T-IFMimxqb=-FV=k{m z(Flmj@LGJMnY5HV#>foWv-X9a*jLud^+_Jp@NK{Bo1ZS4RrUtM#ujO9HDDSFzmS}a zFOnr^{o7SJQ3g9Pb&;pRcaWuIxh0GrWw3jLW3F*qgga+#_Ngb1L4ox@>Ky&y8aZRH zW}GFHY9YilIg-|eJWWPz=Q;VRlmT-*WOI<4i zXqwg0M(M_C1Fzia@CEHH=L<$Y@CC?}w#jdwFBm%WzTot6ELzD-s?!(1r1J$+zeGOP zC)6M*9P?L@P>xrnxtA}P>_7!;>#Dvh45!Yt+&|;}^1E_zdDYbSzv@b2`$| z!pV{Tnd^xBrlw*MzmjX-aP}ehe016X{+aLqwjdClmdhah+l3^9w3zwHBF)Gn$U{9x ztf`L{(Va!m6O!}n2){96c~eatSs z-DOsm64uI{-;n1(&6KMRC9e`xcoO;HGg)Og5H_$Nv6^QRAsKvOQBBvW^!h5SA)iW} zTkiFjTIy4av16=Q3?$2o3$wUHQBXv*MSMixi;c}frlN0Pck3LsEFn#s8zGa!;>Y5W zR`??%*+*?>$dIq0{3szsS`!WE#tN{5BC!KUqpqQmGWmnlL{pTZiknkWf*H!>M}6Az zsBtKh9C*xV5q`O!$%#<%0gxCGzB1^7ed78OwISy*lFyPpwHPEA08#s32Qm#X@M<59 zPklc~rU6T>`b>^nON^xvzh-cvGw1yW+BNjS(yV@&bK~E#oCndit>s!MpyvI^&jgD zx3oXxlF3>@O zYC}|6WL53LW^jX6tx32Vj+MK#5xG+~R<9~|6T{S&(V@!Q^sJJS z?+lB+YU~cOrksU0YkP{PoypE7q8I|V;tRbm(5kJ1wv;wWaYuzg31ZgDPUg-FgFKcESi*1nV?OPRq1s*pq4 z)a4DlC6d1g_{A7-4%7n;%%!DhUV|-(p`=yh2fkU#a`>%vC3ayt5INAMaSS}=YZ!l) zdoL+p%*?p{$H+)*)je!leLaNcriEi{_mM>S-9^c!3_T;zrei z{CMrR@CeJJpY!@u@dWU}v>z=vK1!D&rd-@X-X{{ERZ^1}rAaZ#$$z-$P>5H!V!_6K zX@~Y`&41jYT(fT@HLHFHOV+t(f2}`Jj;9*BfMbx79KEx@tm8r99V0`oedcVB>x|i`-1GbAx19*1VzqqhD|QE2|ZGnai@8m_IKg5{bf8FzY`j~{W`UgjAG}OFmjyl9~LtW zzghoI#wEQQLHjy4QYiKf&zPofNZyQa;_qesX3Q1jP0{1e_`8htoXb$N@~>N)LZt5Ohb;XV@7y^cla~P*J>VbA&kWuc zO@ECaxwe`)8`^|AJA;=7`D~!8t;$T=GEe60$kx|1#`Rs&mZO}mT`0}20k$jywr#Wx z{6b%}5Th@pdztD@`8HCsKl-aar`Pe|d?)<+aLyb8>ISVzdw`M4&YPH-BiZ6&h$aOR zhe(`_^97oa+g-d2xsS@DPjE<+AnT}PRx#wl9f2_v5i|R!T{_(WFT?7ydPRPui;7t@ zZdiJ(Oio?Z zux&-JkYTA_AzS9OSqK-(Gf5FO{w*2_pFl*#*ygc@mvFoF-$Ka&I+ z+H@VotWih?jqH)uCo>>ORpg>ZA)62oGgxZZ`YF~AK?`zFlS5dKgYD}YhgK#585!t4 zm%qw<5Z0v`KJ5(hps(`V(7+B!2dKa%2NqHwR#w0|9CXMkFJ;Q-D)LH9niSJ+wvh1; ztC-m}qUO5i3;QDUiI@rFE5 zsz4_8pLxjBzSB=J8ZCWR8$$;ldYQcsjMs03wd zd+J3JcSt2lj7NYdK5*?~X<^Punzbi?`~{`75Xw#C1gVjawj^DWe~4YdujLvJ8*Ywn&|kKV>R%2XSObX*6muyZB*b zf#n+cm}{8=@W(%nywD^5!?qX()fGsKw~f?C8|Hso*i1twTd|E?^B{WAe#9qCFQzwb znSFymhJQ3?+dX14xweog+VQ*%fA!`X{kEZ&O|3pOFXQMf(qfO$AvH;Rhlos8D#F5- zX~!{3@==cZ`L-qoNqae`A{ctE+6tVs^J8hSV-9fWb);NI97Y5Bug$Kw#dbW_*;eDA ziGi>byMClGPfFj3?Gs#HKOsWpQ3Rc1&Q)>_}XIE}V@6w>vf)J6uLg z>PERCtlc7>*%oMa0bCa|c`X~F3r03l3hJn5Mq{(i%i&EBz%d&8+H$;rmM}K5Ep0+u zGxBz{B|jP?a5fNmBmU7}Wl0&X$V;t-=d2FT3c-GOt)YMkcxN48;2)@#I4EcZ9QeHU zmFrLYqyl04A`k6Tu7TqCVLTmHtWijK6Kj!1d^mv>G7mV}D2};LMXmvceu|Nhk`Wa7 zqWh}L>oFta4jdm%b`&&N-9XNMnEP;KH+N5nmbRds21#5!54p?pyZ8HAAn8Nq6>c6# z`H9bT+N}7Y=#;jr{|xocXz5&;*-B~gh^t9^bp10|ujf8zqBCbt*asF;XfL@DbS(V}_3E*C_mqZ|iRuGnD+b0onOEm%P$Y8FCz|b~Lojf46$K&0c(7=5 zw3;GSjCIA2Vi>wK{27^2HW6n|+4YK!E_tt`q{~FpV4?&ufQmo3b7>OCXs>SAm5TDULtFl$@(zQs6(EF43il>N^BnQd|G6A zF{E@X{zxc>U`d@sn(Bi*5AD|@V+20NS6PqNoatNrgVDz5T}jkN^b55q#uxem`Y70x z)FWRV@c?~f^&okX7G&jMwT;MKOd?00@X>8&mJw$^mY1xq`V@MjglU_iR?`r?m^rND zCGSh-RR*vZbMga0bze7J_Wr+3}N4A~F&(R2(iM&ap#4(GJWr6P;;7wR?ioOyvJw1uzWml?WVtuDu< zM2<-rYcS_xeZ(yZ@se9&Ku3~iMjEj+d13?;K$Vny3%l47j_nTiGn*7T&3b~fD&Y>j zGS)59+`;4uyd#zNPjr53+CbX?&s=+ft$`0YQ)V&{iSmpKlFI=RddR5|-ldAfPe!4x zqsZ82aL-a)`iuPasqBjNU)?m0{w-gXb$ReWjt6x&Uq)WzkksbUSx+Wh)6iPZ7wn8(tXlIl_E#i?F{TT7H6MRTsXCJu!hO!mw7er{3deB}l z=T!T2GQMZ4wMHWpK1j#e3eJ#Gs`LYuBdEl-V3KBMIXsRdK(RndCia~DWSTZCh=H1Q z0Bf6~!)3%4iO4UuVLy_8oAo0DAc0@wG9@B;!$KLyJnJ|*Th=UDZ^z-NY8(`RVq2Pz zKC?C_%kw?i$Ffaw65**jwN+u^2M~-0$GD$sh!7Qd*GAbcimB@b?Z^;0Qwvm(Z zQM6~+H$6xKIc*tnho>4O01=6IM&|XLYp;=rkyLY7@dX)fivVcv;uvjhuH>|^ct)29 z6zG=3vCQ&85wSAorSTUjk~rW0nFCB>PzE@Y_KnBtmUiyUX~3I@pMo2PJgy)FBILZ+q{Mi;_SnBP?um z$+k;IMY%YMK%F^SL@#JtltrqdE=ee@gt4f!Gk-A4apfaf_8VK|pkj=4gf z&0+LhD&`loP@#{ts8|{7c|E+VD`OA!fN@>CgJY=H=QW&MKZj%C2ZJR}w^9bOo-6Gl zuIC1b8G($v$hD;7YZnkbb3C)2~Er*)E(jwY}~4 zucgbb32ML0qjUZDX`W6Uf*twfS=1x+x9r*oSjyaGZtMk*W&~CL)fNO3Jc5~lSY#&$ zsZ-#YbAPZi#vJ7wmI4hKYvCCw;K4cs)y&HXNqdpVM!OLkF>`6mZzRtEk0M)@a-ZRy z`anNiH^|nXB&P6-6Jt#}M6K*Z|IoS0()5AxoHIM~k82U=OEJa5fUWf68>hr_7Grx* zek3*;8$Dd#xg}Jiy;=K!WMt$3{pbVRif^c7C%RNG?qcj;<<4Z5<>q`>fqs#ZNSvrD z6Z{%WmEP6!aXw%hL5%#d0YI{YQ9+L9%P1o=9?2RMSNP4Sr#2??(ltf2vtj`Qc2i7{ zC#KZr#h=cTv6XZ>S`DS79RH*Q*s@113g>%Brv12n>=E;ui!q>D{R6nb!avh5Vs~DV zkO?e?2IBIV>|C}`gLdTDV1PPqNqzRJ79hXeB#`x2;rlY7L%1t&Y48LW+hWi1tN0>g z$bx+p={2l&{8%y!L2j1^^09ZZ#$F#SYC|3T89?pMaHz+MIYIu}6X1hbs#o`(07EiG z#7+G*w27>o&LoNm1}zW&)KkR81x96}LCDHm;v+^yG@>2)(%ySZEzi1awJF| zBM4U`i6v*JWvU_%T=L`%995ZVRPo1OwnG01Y?`RR`ehgHs-q`;2*uGh%yZzW0VER9 zlE@Ejk=r6AZmXpiflC24}1G{H>`=Ua3d+3X2k*N=$`NC|A9N2^;yg2zDHs zb2>##L3`erN-9Yb8uJGo^W25isnCb{8|^>qRV*U+o<%wntwEuTZqTRU4LTuj__MsB zDmwh_LZd^DEuc+gARJNeq6N{PQpFW=UQU5SCZ=Sx31yH7__0!f08}2B8X1wxP^fl8 z+R&%2n~*xOn7r;JGHx-tqmZnaI($Sdh6wxz?L!h$lUH`p@TAjDdFnil)Mo!UkIUS` zUWO)?YkZQnD(fhk1=Ewc3_`UTl|wMrC&1egB2W4Q{0`Y{RvQFH+bBr%XXlAV9ug~z zmZ1m!%X}6BF#KR$LkV*>g8s}so$7zo^A;sc(+Krd+5>zB;~4%)bRcEAMSfP($)GmQ zY0L-gQ7lLfa<&4!!B(<=;BOguR5fWsuqadtr8rdZH;flDM-pohEzpk z*N|^g=kUNg^a7uhY=kz5ApxS@1HJIu`mghc%w~+W$Y>5j$zmGiB$zIq8Hs`r4ZI9X zjt11H|G-CGi$c6cZAcf+Es~WO#(1K%Gb^L#F#j|5n;F%fYz@N1AKDc>*|f-MO#`Jk zo2bj!E&JfLTQ+)7(wVIDlD5_*vry6r_N>mqA8ZrrDCS?m%b_aDT0B<$O~RM;1+=BT zh?UVtsi!QyAk>O(7qUHdPGj@SR%|wtueDWcsTw+Ira7AJJX!jLjk0&`pE8ht>=J#- zTs1EZIZA>=%~qDGXOV)99@LqVEs;(I!DT8-N2X)#xu|0{rG_Q{k$7sy2+#^CEo1ax z3=`>YL3I(=7SLS8r$5@U*V(G|La(jntkw9O3R6ZCHPw#z#PK$>BTBQ=l5F5mZ7{%D zhlMR6FB2Q)`4f}x&xKBip}Jrck$j&E={v*}yd==tiN;4Ag&E_NW@bbxHyuGC>4of4KiU@e@X7O|^ZG$wXek)7C7h#? z9eYG$sy8uQ!85c7o;0ugs4GLusOJH987=tj<4va`Hw0j9av(Wf~`75sYFuqB1s(7`zy7 z@F6WSh&o@Eb8L*sT-fAUH%TgS4vzkdScLT(=FgzX%myT1c6mJW|3yj%ETT_r0&-9u z@V$(g826}k(U-Y7f!jFXw1pj!jI%Q{=OZfZO|@@hgyMlEG*hF`q?F~-kgduHbZC?T zhOv1Q;gk$eA=1JZEeb!G9jlz#KeWPV0sjXEIHCs$&C(R)Z`vbI8&O+yI+isGu60m5 zlFzB6C>7Bia80CRxT8?A44YKxl6 zG)fZ&H5zSkl$n?rx1i%}+_K{xeU^-%M6YAkIxvMfzAbAkbHP~v zZA&D=Hg$g?bPi6$c)^LfgQj`FF!9^q2yGZSE=F67g0LNW+9J%!ObkTlAd>@*FbAG! zc#H|cle9zsQh^oeq|~S2n|cNxXHIhXsI1mdfY)}CkIDOfkTdYSE8B7OWZW?8cc2L4 ziXn}2>Mi-$1Nvx#@CkSoERlTSn=5wgm@dg5Ws(h*uZGAK5rsL%ae=IQWdan&^702? z0dP?_Qk9?@dx&z;}<D#kmZ0@Ge$>z(#xsK^xU0F1(pIHx$<_vbY1|A?=Wqd?>Lk*wTG|>z3$j zQ?kU`gz|-}td{(0C;yC)Y3o?uuI|m}kGvL3|EhcU&ai)!Ah7XY^P6M|^dfnR_%nQ( zbn8Fnqf9!XQ@&eUV z+tnF+_qwBzhv6^tD^vei3WYw&}4JuC`cTy<^eJuWWVu zMXXb9n;vWN5{vcaou|zI(r&k3#5(<^>9J1TYq7pKVi}m^C zXKel4O1EFcI;S!{)>&ID)@K@L-+K2Zw_n6MZ^!gl=Qb?Xr?;H9ddD4Zzle3g?bBnO zzuaPdYWoFCKDpEF7qOO&O^$daMWTv{)Zoa`E=<%iVqv z>%nuT$9m8m7V9IcFWK_phTAV0skeyiIrVqLdwdaP?#TdcRGq3QPpnLjwR(%idQIaAx4wFl+b?3dJV&!f%^;cS@gK7&$)k`nF-6~NL5sg# zc}`EPnLB^J{IKo6$dus4a(PZqtXX&bq;bTSpRO)q*gZp+%X4~S&EE8*Epr-sGNZL9 z`fIRUp3@WS=#@X%K6m*Kw-zz%p22c?PEV}9`QP0;Z^rj_+t$TjgXQv^o><53{?3y5 zJ9p17V%R-{gjGyY-|^UoS#rdj`wpIX$r! zuKvo_MJvC0N7lTsVX$1D(-Uj)k}vH(W&W3U79g@6gXQv^o>-^u{lfgyc7Jh3*1WJ` zuw0(g6Kl!#&#gRT>*tpjAhI2UPn583p=EtfX#x;1NF*f3Zw z&*_PE*~$-WU$K1K)&fMfW3XJF(-Z6R`S06%#f#CqhdZ@=}LP46fmxE+J#@|>Pn*RFoc z*6UWj^$yoQzh$sop3@U+)si>uzJC6jcjgh?w!w0FPEV}I?0v)h8+N~OhHIbSGFUFp z>528Y?XO*V;55yn53UZhcL|wa;%EESKk$uWh;YoK1Ugsos)D z;dZvRRlc6%*2!k>%$ooF&cjw^J7y!pa(PZUUAgs}pX@pU3)sa^hUM~{a;)6?&7L{4 zby+h9mtna)ryMJ{e)Gc>M{mo)$YzG+@|<$4-1^P;#`(sqj^Do?X+E}(@HZrPvMTfh0-wlh|gV!1r094ohebN8OJ z=agc(Jf|Ehw|?{Kh3D=n#d3L0IaY4{=2NTAzq1s}5Jf|Ehw|?{1rPuB##d3L0IaY4{=FK;)y1f+35X;twjXvWuoKJWIlZy^Zu?%BVRd4; zJf}C-{F}aW`*iYhc}{Pv1xvrVV>&FC=k&%psq*#8bXYFW>5a8;$5)q5hvo8|-dKxo z|ME@KVYxh~H`ZxmU$|{LESKl>#yVrg=eA9U5X;Swrwk>!*Y2}Z>-C2d;i#UST4`$jdkTs@40##*`bT|1`3 za(PZ~tZORos7#0D@|@mS*Y0@h(&?~Vp3@s^)$MP-X*w*I=k&(9VeAdJO^4<3oZeVB zu6XUX>9Aa$(;Mpvb6<H&)P?G3MS6F=OnPx8Y(nF3{kbsGxE93Riacil1%EmmN9B zl^r?f$MQ@A+iuP-S2kzYk8mBH!<>7kE1P@g4_4*N=H24T=H2q$Tk>Vct#W0@t@`$z z`LYvm5hAaQ3vk8K2@AimD_?ff9#?kKp0CZxmo3`n$`)<=%8Gp1DYv<@Q*QgxSibD^ zn_SuHH|@MVUv}nFS9a#o&+f>Vol|jT=Tz>l{M<~TR(3tjt6Un!klTKAdWBHc2d8rUDY_nZEne3bIC-~1H$lDS>` zK=?Xf{-))#C$9(0Z;@}Ahd%4x@O`iO-zPatD~o$AkD^>;PW|G8A(w+DpM93oKFR8! z$*U+gSwDE?!IaxUm*0NLai3**(B)Z_tE{EG?NG?|kjZzy<-A|AK4kJP%3ao-?mCom zKjiX1AU*82E)Kaqih7YXyu0rUz1(N|Ibb~!shgFZFhx>+fFa@ql%C zpX;-zS6RFM>HVSC`%S<1TF>`N*Y}&gi+bmIh9J5>^?twW|Df2xy|#t>-5!c|!E;8z z+}{Vg_`R`@gJvfO#a4cA?4@WoJU>K}}~7VVbTLj?nWNOt=NXTOKkjt`kF|H0XF(XM%IUeNwSwCg`u`#$7$en@To z57yp`cF*fbgJ=CA+x;KB{of~kaL9e(58fY&e!**^gBSlX_{ATMf81w&a-aChAC12h z{f5{72e15N@|!<8|G7{7=sxqMKRSOZ`W5em3EuX{=vRNV{&k=G*?sD3f3*Hq^gG@+ z7Top6?00|k{&&Cl;eGClfAs!X^h@4@8QlG+;Fo_g{&~Oo>HXrXe=`1B^jqHV9DL(X z$#4JU{P%wK;`8YF7E-?82``W3Yo7EE8~O|n^NuOJw@2F++ZQl0m<-8a@kic=wCS+z zpkr|!s~fKqGY^|X&aeetpGmvvh%LZBs}tYfho_&8t_r>7`g8ou;X4yA^z~QXr@!Cs zt~+`!^q=Q>?sCxZ;4&I|(@{!`mz*w&I%slonKuJ8UD1oC>FMf4TN!yC3cF~`%WnQo z(0R>tbnY9i)6m<4WG~eox}AI%+yT08*cZC@o%ZSJ@6AF97hXQ{Iyh+)czM#k^0I&Y z>=RGZvQ^4i32#nMi&lcSf&Jla|M}Zj9`}XK9-Nl)n%Cti^TF@>{pI(-c-{}b_mTCU z-1p$$>HDG`E{bWS(Ni9In>b@DWb(8FmC3!6%YMsdzr-`Ggr<>^ zvzxPTg^ZqcZ)9}u<#Zsj+Fx<)gT$tlS>CqJTMfBA|K7^&;K=R(<#zxg+$SmSgB+dx zU9bdleDT4Me#sWd|Mdr3{)a{f2SE?_QWg89js4Jv^M^|t z(8t>jg+30QP7aPmpS;hkSPmV%_fYBR(CX=+>FS`UYri$NpE`4Xb;S(m z?5;zpvqP`9gQ>fNrM?5u;C|~c?|WD7gdRU}sP%Z?=<*=z^B}79fV6r5dUgJ}@($?r z?)yTo_nmGJzJ3p`iVslB2c+k`4_~thy8hCArR)1v--kr!2VLz4toZ}fz4P!aiKQxM4T! z&*^Vlw2B(@?eP<>=s%W;?0O3mRrS#qk$ZuC5GL#w&IF zYgZOlR#s~GZR2~iayIrGl?nVC!;woW=i%Q_rHTDUWwNrSaxSiOXjMjVG>>sLS`OgY zwJ00K-vH2Sm9=P9xq5KCUT-g4S!=gzqh~K{OiYZmFFEhLq2@$ma?QB|t&#Jz#?_+( z=Uv+xZ4Hdq)}omQDOdU!P(B2DhSAG-rSh2i(ByCp8&^sH6Y@Kb8g+1U0cc)|-%Ie< zjjG4bM~!nT55(UE*t&q%dR^5Tow%wsK2%?L!MRHpUa~Oj9oy$GJ?DYvT(I;4RO?2p zWHl?58$rQ1W5zMR{5gb;TU71rk3idL$a!jSKGOu!MWq#$j%JG#2l@lr_;$7M&Ln@0Z z52!2-4i9DpM+8R(vx7OoQNhu{+~Am?FPIk`8_W-m3yu#K1SbS11}6n42MdEm!2^QD z!70J1mCJ(Dg3~LP2TOu8f-{4&g0q8jf^&oOf~CRv!3DvE!9~Hc;DN!#!Sdii!6m_i zgNFo{1`iD`3swXV3oZ|?2p%3>8C(@SB3Kz*9Xv9)CU{hEZE#)i=wMZFeejszhTyT4 zF9webZVVnDtPY+KJTZ7u@Z`!@f~N#e4f=zdf?BX97zhS~dayPa3K~H(SQo4hhJ%q{ zG-w55!Og*V&<-Yo$zVgUG1wGL1)GDX1%DPiJ^1tB8Nn^VUj)w#o)tVh_{-oq!E=LK zgXaZ*6+Az9LGahX-voaf+!nkrcv0};;3dJ|1%Ds>L$D?I$KaoWmj*8j{yF%U;9rB= zgO>-d2woYyD)_hH)xm3mJA&5+uM1uuydijF@TTC+!JWZdg0}{53*H{QBY0=bU&!Ck?Jf)58D2|gNZ4?Y%rJorTLpTQ@CPX+%K><#`e_*L-h;GW<&!Eb}#g_SS}!!Qct zFbUJJ8qNr3hKGfRhqJ;X!Xv}k;hgZO@aS-Ecud$A&I^wX=ZD9I$A=5T6T%b2lfsk3 zh2f&`0pa5ClwD9zBNq9zhW_VV3c6d&BZg^g}G(11NAiOZVC|njkFuXWi9zH0% zBz$oAknqy*q2XoWitu6K<>3|K!^11XtHMWwE5ob9M~2sgj|#61uL~a?t_rUY9~0gX zJ~n(@cw_kZaCP{E@QLA*!Y7AM37;DFhc|__a7{Q64utSHiD`yTY%9Uk|?#elz@5`0emJ;qLIe;rGJt zhd&5^82)egqi|37wyqBu&T zG^$23qM6ZQ(c#go=!odZXm&IwIx0Fknj0Mx^+ofdW25=eanbS7g6M?k#OS2xk1mKVj4q0nMGuTFj+RFciY|#B z96cnuGgbWtHPNG@YoqI;M@Oro>!Zg+H$;z( z9v9shJw93;Jt2Bx^rYy?(Nm(QM*Y!EQ7u{%4Mc-cJz5(LMUAK#t&7%2!_i1I8nvRa z=;mlVYDW{%WV9jL7;TECqRr9MqCbnC9{qXrjOdo=FQR8g&x)QM{blr==(*9Y(et9e zik=_6Ao}a*Z=%1AZi`+Ry(oHd^pfcBqQ8&+A=(oCWAsnaOQV-X{~Y~G^smwF(aWP( zM6Zlq75!WE>gYAm9nou}*F~?7-VnVpdQ5t`cAYv`fl{S==;$R zq8~>88~rHS6a6^)N%Yg`XVK52Uqru*_D25~{VMu(bWik~=(o}D;z}IEVI0MAoWyBd zjc3F&^<5}?$@saWDcuss&d~`fFJ|^yq=f%gy^W)><XN%6_?!gx{q zfOv6yN_=X3T6}uEBt9cPGd?RmJ3c2qH$E?38lN9u5MLNy6fcV(7+)MOj~^6Y5yQIsFN^;<{+IY)pz|2_Udye< z2PY3nE=?YqT$Zdz9+q65T#-CHxiYybc|@`@xjK1da!vB6$qmV4 zlgA}DCXY{6Cr?P8m^>+Ya`KeqsY!owQ&LOTBm>D{Qcu<(-j=*Qc}McjOWvRSd-8!~Tk;>t2a~&!4<#Q?K9YPi*`9nX`FQe)I@;}K}lCLJalCLFSPri|SGx=8X?c_Vj?&Q14 z_mb}?KS+L<{BQE3WKZ(ryWm=_%={>1pZd>5}w}^vv|E^z8JU^xX8kbZL5idO><&dQrM8ePDWVx;%YQ zdP(}=^dae`=|j`Y(iQ2$(#z8;(ub#4rdOqpNLQv;r;kjpNgtJ7n_ibbI$f1spFSqN zA$@H6xb(*K@#*UH3F#BlC#6qLpOQW`?N4t?Yw4PFARSEW>DqKCZKTa~UAjIUPDj$w zw3UvfH>cxiJDo@;(+%mybW=K&Zcd+;{#p9;^v~00q_?Dhkv=nhR{HGpFVp9w&rNSl zpO^ks`uy|->0hURlm2abTl&KEMd^#vm!yA}{(brn>6Y{#(|<}|n!YUk=k#CFe@$;s zU!J}qeP#Np^xx7~r>{xxNMD=2E`5FahV+f;o6(x0Y3OMjmJBK>8$H~qi#SLv_Qd(z*ezfFHvtyF_*SdFT2 zHL0f6YIR0+X7#Y@;ni8yBdSMMXIJM`kE$MBom)Mo+E<-dJ+?Z(dR+DR>VoPC)f1~H zRZp%itS+iPpt`tvO7+z0Y1PxKOR8s7&#azRJ-d2N_1x-t)uq+*s~1!+tX@=IR()Xg z;_CA1gQ}NQA6$J%_0sA?tCv+*R3BEoyn03T;ngdvS5+TTU0J=l`pD`v)kjsYtzK7s zbahqr`s!n6eO&d%>f@`ct52vtvHGOyldDguKDF9ky{THOu9;KcG%#EnsZC&F z)jv`jUw`DyldTE2d-&+&$eQ|if4ey}diY>#81qHho;6kwZh`T!)xt(82omKh{uJIil@EsiV9jyBfuJs)p@*QmW4mN!U*ZB^v_Z=Me z9USo;9Q7S+`3{cx4&LlLIPN>x_8s)EZ0OpXsviHX%` zZK#h=GzSpH*3`yL%*z!UQ=4cG57v(yZJo1byk1-1-yW+C)Q@Y9vTc2^zcU!m%tGv8 zW39>2L5Z1102RS?U`qC8Ow~ta zhmAA`##@3kYpgkp?TyOuNON!ybPcv93W%-I`hpR7_T;daxiigpv=7`Z*f2Rfgb{Bo zVu%P7&=}=vP}cZ-UstReC` ztrx~Xb9`WOWbJT$Q%@i<&{KN>W%kswyKx#$ZB1)K{a8O(eX;lWfO0%gA8aDo@RM4f zRw|}O52=_MPAYz$O|^_?KS9lD2{JW$5M*jhN06zO5j5W`#rj0UPwA*qDq8l}XidwD zsnLTMQ^WDnv#TB^XMi$p=Z;JcPc+Ad8K#)AGSWQ2D*@B8J;A8x?|yPxPECy-oSGVr zQ@F#(hR}+oa_^2r=Bq!}gZG5c1eX_PH6xDKU_9&NLPbqKjSnL5J zsx*%6BO(((kB(gA=<`uym05rHIi2*)v(=hWfe_%A>V5EjTYSbsGLIr=IGF6bn zZm9cM$d~t|qBVq!YJCqXw1S@sf39M~MwS}+!ctcye~35Lkc?{DY|T$UsQBUq_}!rlaF@Xv^f^9I8!BVwJ18 z&P=n6)ZKBvtk>;}th*|in3naf%eCtbR$1DcG;4TA3rZ?0QFsBev|kr9+bA)7W>u z+%E-FqjXrxm-`Xg)6kGF_lFZx!_5(WiBwl5zlGXr<>ACzqeHH?PML+~%l%TBFk!6> zAz$uCFxh_TAe1lndx@!0?j?l^J*g=55(6RSe(jnXZes4!ZdWD0$C+x=d0ct54n1!) zTI!inbyf27X(mv;t+=a_f8g$%jQMr5c^c2lm;3uMHL?W3_*5Z$b=K)gOKBW2C{k{s zU!j-b7FK-QW?<{k(i-Kn(Q2(f(Hn>-xU$}EZd%}(x_6XyK)1$l(xY{f7qzx_94m#R z{evb2>}bmA>v)^zUHq$U?SaO|nxUwpsq|X+GrP8n*`l1Z80Tq>MvJAjku`&6{;a8j z@uNa5Gro$*^>oH?eaP={X6!QON+cHbPyx=yl&Sz_C9BQthLOKHf$s#{ZuAegT4R1e zZE%7r0p47)j9uT{=(nBt())b*32GXKG%%sPs&M^wBNn%|xuI^_7G$3lo?8IUPU{Q} zwpI^Tz^XfTgh@U+zaR6PHqie7PUN=&2MTU+zaRgGebtzT9i| zljEa|4*oo)X6E}kI2#HImg23^5lHOBxGc-am;1T2ldCd>e7Tt9nJZf*2M`0iSMG@D=cM(eKSm)%rrs8L)ZP?_?$U#5AR@M%0>ex_F*-cia#+=8Rn z^+;Sz;U6hX?!o-Q*FIP5&yq~M>X{{V*6|~msM8avvyR{5OomvV+ZQVM*tTm95Sy>q zh@Tgs_=>INpx95K5r__y{wiicyL?TfP{E&t87`0yo#nM6Lnlsa;ADY}tL3M3^JA~i zX7lBKj!dSi9Qo72NnT@9l0)f;vB8gR28?oP6)N~KOq?ypC{*xERDJJemwok5)SAP- znL}qCKTT$Zp`4~d1wV!{_Hv9ug&w1I&3DeMHaym-`3wS!rySy?+~*{@iHmQ}Q*)+n<$>WAr(PXxe3Ko-+TnV;-CwY5pVUkSL8~}EQuFu_>vBjC97BTqPyu^wltA7KlSs8%?9B5@PtqN zrr6CUNUSfF7)F-ZLqa1yD=^XJ&NYB~`D& z5&U_PW6Kv#j8V5n>O=M-_JTo-HJUvngzGNla`-|MBOwz)t%Q7uWw9oO;PvC8sC!gd z+iW+8Vg``{Rhiowx@_HE(zNRxX6mYV*736G^Z5B5A$UUoE=U~|UHgQ=3%w^?bg8!+ zKL5gD6$j&V56yTT!z3m}bMggbNf>-rZB34~o6xAw+;eLqJ?Prdqikc3vZ-Ern)1w;*T1}j(!u7Xu!QTcuFqw*( z&E&C+0<4iuKs^HuU>n1VIU;o6#}T~z5Mjx|2UtfO=B(VjB0UCK=Z)~<5_zE>v= zU;MUn>hV^aLnV`i9y(p$3*Vb%CLWYIBJk>vR1S+n0WiggyH!XBeg}Hg_uwGXBXM?+U}XzENm{XHD8ZwtaDdX&(UMG(N_ON zeYoDN9j^zhW=xlo`W@#jT2r4WX*5&=fquL}45PIZym)nWcYkM_(b;@|vob1hf7L|I zkJiLZTz>l2*T%+5if|*?VC`5h4I`8Od*! zBD9Ixq@My4bNxMGeD)U%loddwe%d4lFkpqDQw+`spin?_^ED7-^A(7xncfRX#?XA7 z(9Gtkii=JBeT#|taA;sYn#8<(1!7!%o}Nc0eMd*VM>knv7ic#|<%1b(`j~}5o#dfp zt=t8ZH>yH6Qs9Gwt@*TIEX~&fcIG<_EAt(Ojrk-h7G~VPNazIp;?x1$>@$qB37xlB zHqA1Ftd<^MTC267tY~muy|ip-UHz1@c9Xcu2X`Fdgj};6U~qGNX&JzpDJ-gvbL;>{ z4y}}lsb*tK0zAm&>F+TuMrPq`YXfRQ#>d zMq}k%*T+j+)!U^-6Xmj+ENxU@TUykpmHPTbyWBvKbCC$zWMQ zvkVKKR)V#;UcyMz>8n7N@v#!P^=16mhf7-2N6HFDODJoVG#D%65qEC-l~Qk)6ik#! zWwN9}eQilWqvi~+AV+voNeTR@qy%2%Jgk7$Zor3JTr8Aj9^@RpP)`3TX_|RYi7Lt@ zK2;{CsoG+{Dhe4&i7cC~61gBdDJem2@&JE_xm+R_0SbcQ@OrMlby-?cLitp)q@a{= zBqSv)Ass1EB$JVnMo2|U zct%#SgTnRpe6@viyc8h2>Xjm5DN9a9WJH!AcGYvn)IlRwjcW4nm&t`08wKKA1?O6& z79R^4SVq5s zqBu2X3aCObkw}1=Q|}rEay^`o1N!#I3sOm1{uR(JM#FG?1_3nCRfw#QTif z65HskR*Gk@e6g&S;B{7W(V>Grd#>#yzmeGD^RnWS_8s~^C#zpjs)g&QUCM2zVoSK~ ztX8U5b3I~Dy%y?}Qf6vRr`OJEXJvBfkfW_=9t6YtWSqShWaz2s9J2!zxoxSa3!vQ< zODSdk+5uWZsi$UXGO->@jQxZ41-0>!x-4LIa8jFEQ(CsBK3ZBf)Eqg!40Etn+N?g% zC~da6R$5dqZ&jZtZ8gyFuIG)%gPh>pK9qxQqV^$(3OkMlJc~Gau+8X9#P51P! zg&9C0+?unn2x_kHLWS}Y1iO+p2zB%Q-3``Cnjp-TG}&A$DX5pVs85u%m}r&sj^I{O zg3#uKS`Z8aTS+5?wGs*j%J@e}D{0bbl@zSYMTr7s3}z)nGnADOjX+k?(Nwdf34&Nj z2|`#2*oHD4Abgd8A$XOr!_ZaI&v+Rc!d6K?2wElmFl3c9Lcl7aU?4XV74*YkRnied zRY^w(R3#m?${0eB>T-Mgv;a6_9%s#(S zN5t9KKQ=i!FoEl_^dYl1*VdlkDZug~9vj=9y!j+g;ppUOf1|c`a($zAv?9!W zs(1(|(&rYBAo$dWJB|(3fH0?6uTk%S+EClj(QI>VsyW(G3)f+E9GU1kGSwP9w%D1T zZeCyOBp*jQ`oy{Oy1(^EeWasj9P#!833k-PkzD#~p2DLcarvTsbS2bya##G7i4%pP6e>K|<4-97zvu7({yRL2`~cnZ677BRY@ ztY}TGylkjP*w9o8Tx*w-IntxuXl=Zd^Hw=` zcyRRzWm4IUlP9ILjMwU=Wq5~EY1u>%Iwwa9}8k7hksXtc^9 zr^>}y!$6!-X@|(sxt)g)Pr8mFj&vPE{OE$KcUMEa=xT~M(RB>*p$pE_6!D;|DdIra zG5CMiG5CE~7p?AU@bhCjg+l-C!h>IT9fLo29fKct^@{al@UyOp^sg>N_*Iv58r_10A9YpR=&9x*1^&|2 zbZxWi(9~#Or%LL>xCYsIy>S{d3HCV!E@E?G35Ha|g=GwmvM+T?lw57&k!p_3up;^HNJxJWvdhCyf13~{VT^B_EIbN?V5 zv460rp%&u)FjzsfgekO&IQ80i@j$aRUi5;2jbewz2#Qx)3>2f(0B+41C{}7Cvn!4n zdGSq+7yU9Px~YzEg!{d~0Nz8<-#LQZT(qc7##hX{hjMdr)0cTvd_BMVWNZSDK1M{y zH8D!4jStr*@er%2ku@!=u89pzs22lV;V7Q&F~m{I94(TzzBmN58^!%r$M}M`ON_4P z(A~y+YB0nU{i;~n>{(iG^lDohC|YO{nZshQJIHFi3VXI3?A5Z~jWRxVeXfhs>jA3QN(shY!dt zw!H7q+#hIpH3BeCN62o&^WB);S;voL`s|6+S;voLp1#%-sk4r`3A%$jbL(dL16m3d z{M4A+i+fVjS*JIWy|l(BYl~#-_#fNzqUXt#t zxy=4jwL_>s($dwN=6XC40oTJ1v!dOqy6tCEj$Yp0fS-xF<(#Ct#X z))4M0`5rtXxp1eGnVabgLvNvC@qt(75o@K@8#uLuXHN3jSSB0j7|w7qimwRrJ)lBv zB=)4y(A^*tgZSA2@+?qa#`TisJriqo`GM<-p?7JIOG_jMlXR4-I#Ez@CvZ*!A!9&Cvh z%u{jhC|uQLYgN?7hhLvApK?Ls1Nc8Q-+x}PTS7K#ICuyC68mR;|^-vf89P3D>eNi zxSv{IY1qfz3Gj+Z;3Q55=xS{;HjWDoW*IQunZR2P(MWcV%pRE`yM5VizJ)uQZ+eCm zh`e3bzPr%(O2#uy&5qX``l^DSwK#u0I#8D@&5ku>biRi2aJ&byK0e;UNu!||HNNDr z*&aDAyU47w`f>RKSuMU?cn;Q%T5|m?*RQck;dsrz*l`wBWcpcubS9)W-d8!$LWo?* zhxpp^HXhyvFf9JrXM+q+_3?T*JY|H>cgekW5|0EL9G}dzF(?1p$<6ig*24S&&r^t+ zg%)dDljFq$c%n(+MU;4+b>Y>PZ9H#!v~WbO2PlB>g`9nPIQ}m${}CO@0@G$+d-8 za&1K@xqT5yt}z8N*L9VNBiBTP0ijuPa-uli9qkmv0$0=}hNJ6~c;jf{MXQI2>B(hH zM-1ScM;)dtdq=IM2jSERPaw#VnZwQTnr<;-$kt(_HG6QzM)RJs*`v5Ns@zuB!^Y)RvfP}B$5tCE*EA;v z5YnW^acz0i?Rb4aUQ0XFpS`tqHaHp7NF_Drm=za0fUaF&4j>+b4MeH6*%dZJJ<6sm zP;CTJox$Au-d8cyiN>tUoNB@>P2_~7xKZ5Y6$r0s=U+gv-*@HUc?_6c2h z@`_n4^diFNCK_FA@e$_`C5qZzy^$^P#m0&L-n6ir76CPdT}?%Z2Dd#AE~D?&#arfa z0tTl}`_XL|nT$k6T(jxL8*z3NVIL#X#v>-ja(i>ck#h%T54JXr=Jxfi&Fb#b{?yJE z{di+7A4gT_WpS>S86%~&W=)!O&vR|^RgSR)<_{iQf;Z2RTc|FfOR3HuKhsrLavTY` zmeO`CMb)*CEl$fJij80Z#C5$B$KY)B1V>0bf=jXh?##l80|bNmCcMkJeT?o5w(9ME zzUNtv9>p!5Vo;QRT(md9RH+G{tKo|E`Up<$9G|r@Wv*!UC^UzlHHjx^@q$pi-Pyhu z`e@w*rCF4pIWW1V-ap=IO&rca1?R}PJ$non%;St1nuGp{*5N$yj?_%Hak2$ZiyP+B z~8WaI8hY zh;$SEO+L6^dYov@a%xN!S*+xqi?x#2a#@`R?hBB5oz3?6Fy>|Z0Nvfn->l+^Ooh`^@ zpjFl)Tjl(R1Bc-eSL-$>Mf?jU<Bo%D{Z+o6PPEpyifEa&zF~xPjc==Ojy1k%gwVHCFV9+I2bOwa zS5PMIrRk}WuAmT~3Yx=jS7&&3Vxm&sS6=K}_}p&qHI|j~HYqJv0}G$%^%X1F{q7yj zpBdU$VR-lC?1(cvi6?Jt`$<=D;sOB{1G1N^oq+-F@=o6odBX$MXXRT5(9<)MD{7Xt zED?B(08cA@m7VawTk`Q1NQW^NS9;I{K*&k&niwk&;R(hKvnGaimKDb6_)NJstPzy0 zDB*?~SsGRXx|C=7!kkHjfpSz))UbqI9qaWgHj3dNao2U*MuAs7L1huM)>%PQgjsM7 zcqXq+33`*$(^HE^%XnX>AKZ4-Q*L0pO9q^k+3~9D=Z^-!JGdkxC{O|@I^AO}@r|}m z%npZbDs!3m3ZYDVhLVY2P(72yHD@t~lo$D7l^l%Ay~AaBDj^_e8Kcse z&t5V)TR}WNibq-x=zDw`G5Kum*}(N#!5pCs)JJg6U$*SF{<)->OXlX1`MG3aE?Eq& zKa_f1a8=4A$z4{{Gu_@52KOs_5$0FY=z>XXU|Z_VV(yv7D>Q=#jy|tX0Ik@1R_~s^ z;F|ZY;OSY^3irVB;6lUKZg78im$7`^oV^R*(+NP&U-y?!U)X3kG149M@^)|SY7*` z?ZAI^)?NPv2yc$I=@%e|bPEc>vR2?O-mJZ%zVB0+lN}0e2vr1_fScPYsz|U+H9~?p zg@|Ip`%ab2u$wy~GwkV(kYN8$L@|+>VaHcQW(Y7NBpB!-B-mOT;lOm137#6}w*4wC zAa{aCl!N`?5fTJ|5fTi+5x&ia&dVqs$bI4w&dJ^45hA%~Ji-U;9FH)P`^O_hau<0- ze%L-7A;FIF2nm2RvY^NY#~$+tBe~N&q9p86jc9S4>eb(M7!o2(_C}gSI*r}vef8Iq zho;Y$`Ku&#tdXb3#w*L~bKLW$%l)sD)F-~Xf(b5vnPP4=!8`ulh3HAnZTrGS@>n?@ zQsq$7JB+90$?4JQ+J0_K=jp!^CBI0a`?N!dUz=?Uwg6T4>%J>j-QR3S(r7bbMVH^u z9vx)k;GQ=!gqCYC2nI`Y^ZdkcK3zo+T-(N`+-!BB-WF3Ev+^5zBTXT{*}K^%^dHCy zmV~E=C&tn7!RoDU0a>fqtQB`Rb#>n7J8Fj}M@QAZuk*(v_!H`4a$SFPJSaYB<(eQ^ z-mcb;O9s~vj#dU8IX*MK8&Q*YXc((H{4&gp-~Ok$Xy2Ufpu z>a)7GmWwaPk>KE-Ltt4MnZL$C&hW(uymgDyK3*S(V60CY7^6Xv19mzk=V=bd1YGviNW1#l5i za!M-W&lZF^KBNSkW%4UL8SF5g%1qDryi9dkzL{D+yfp|qWx$4`=6Fn71$bzCXGIY)K8|1!-4QO~J4R5ed<8xNW?AI}cj+xUj^Ezfh$1LiY13G3&$JEtG z=xQW%H4?fS30;kZu0}#vBcZF2(A7xjY9w?u%4K`zV#V6E*2of#tXv~2-^eO7vWktY zfksxTku})c=xSEO>(}svhL_Xu@)}-2!z*fd0~%gQ!_(A5XzC#}^$?nR2u(eNrXE65 z522}t(9}a{>LE1s$Yr~Hyz+kwg~};ZUZDyKRaB?}g(@l3V0XB@{;W#&tE5oLoJ!_Z zvY?Vhl^jsXl1i#x3Dqm1dL>k^gzA-0y%MTdLiI|hUJ2DJp?Za`!W#?9)r|kUU!jCT z0BtC52XvCbTO132&GG*^x)!9 zS=lhrA0|YY$c2e~m?(saVwe~R6QwW__CSO^5Md8Q*aH#vK!iOIVGl&u0}=K>ggp>p z4{}+{`lpouk-e;|iYfT5y53x$7_gbstSkevX$F@tP_gE|2 zwW0&oiuP>i-PT#{SkQiJdF%SL&sx^1HeHWvwxw30y;g54nzYC2G3(K+wbZ0VRm*Lz zLltXDGYy()D&1{$MagLwutVD}G;J-?NodOIY~<6V)iIw-6Tk~4Z`uj$2ytkKM2^}I zja#gq9s}Zd61on!f)tGcSGuiD)_$PMnZ%~V{=~hB)5&adNAeTNQ>nhxWvPRyBdMqC zRrVJ9fPI(!2y3rHsRr)v`rBie!y(WEO`pR@QeM|aq`b7Fv`n1#O zWSqQnsdJSx;T&*oc5ZVHIY*rPoClqg&MD_fS`1Wk7x2UBwLrB6D=`AJT^>;kD^8bS+-S2b zVr|=Sx)@_kTjh}5rUj>qFgmqS2Bq54=kyAUW-aGW$u_h(y&Pj-i+NL`WnE62Fiy6V zFIg>Wa(Wp?)E4q&&$pz<=|YUW#{Ag-TF~M&i1FEw7yGYKhf~Rz%Nc_PrvZ%eO?+Yh zX)5Pb#P}F#&;H#+%Bg@DA;OmZD^kWOkN81r$DWIjaLOUF(AcnlYWbW5B8~=q_74r0 zQ$OO6dAjWH4LnX+#3qU!J3WuX>7|HPLOSek3eD*PL@#wYdp1OIdI@5gK*s)BPjlLc zxW?nNXMz-`7bC&}kNw5_%h_iU>2T{J>!5W!VJ9{xK9D$$2fIzl>yvjUpH6K^U7fl$ z^+4*3owbMUkJ=~f(`-H4$_}tY>>+lBHqaKDL7a1p9#1FJ8`7K8Bk3E{x2KP#A5K5( zEOs_Ho1810F~m5xICmhzIf3}*3FjH-Oo!9a)3K&wL&wIBe8+`!{sQA2m;G5j4=&_~ zUbLWy$7O$l{Q^9o^A-^Exa?_I$1a^-7(425*&ksWvt&9qX58blKfp3psdP@P$j4>B zhh2;kX+wspS2T=r||wwN=W-C`W%vL~R~Qm(YNrAWwSzk*&1IntUIVj-734lQGD zwAvUAx$KwFG2}$XXBPGtM#ZMN(8{I}k;@*1yh#ou=dXin%Kx?4};sFO}!1#k;{Gt-aJj}nHL|q?5E%; zTC`M&kX-f?&>;|1S(WSrgK#@NK!H(MTWI6KkeD8kt{S{fZVJKh5B zbM|#3rgL_m0kJvzT2n;k?5j;Mm$R=#;wopyBG8kwFKbbfv!fb3C!uZH!Wz=mB1UL9=#oSW6+|v0dJb>&|85wO*H5&z?(=py%~5DA*CyT zH(D9J33#KC&{p701E1aqyqU+P%YiovkKO>h32|r(@TN}F>wz}`MVA3@yfnQIID-^j z3S7CwN+1WhrsjGP2?wXPFJPl}fwC`P1@!O_`vT^61xSYcmyo|6+w$m5^6%q^cYiqe H`;q?xJ@PKt literal 0 HcmV?d00001 diff --git a/tests/components/font/common.yaml b/tests/components/font/common.yaml new file mode 100644 index 0000000000..a81457a05d --- /dev/null +++ b/tests/components/font/common.yaml @@ -0,0 +1,38 @@ +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + glyphs: "0123456789." + extras: + - file: "gfonts://Roboto" + glyphs: ["\u00C4", "\u00C5", "\U000000C7"] + - file: "gfonts://Roboto" + id: roboto_web + size: 20 + - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft + size: 20 + - file: + type: web + url: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft2 + size: 24 + - file: $component_dir/Monocraft.ttf + id: monocraft3 + size: 28 + +i2c: + scl: ${i2c_scl} + sda: ${i2c_sda} + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: ${display_reset_pin} + lambda: |- + it.print(0, 0, id(roboto), "Hello, World!"); + it.print(0, 20, id(roboto_web), "Hello, World!"); + it.print(0, 40, id(monocraft), "Hello, World!"); + it.print(0, 60, id(monocraft2), "Hello, World!"); + it.print(0, 80, id(monocraft3), "Hello, World!"); diff --git a/tests/components/font/test.esp32-c3-idf.yaml b/tests/components/font/test.esp32-c3-idf.yaml index b63b4d025a..ad14a2e9a6 100644 --- a/tests/components/font/test.esp32-c3-idf.yaml +++ b/tests/components/font/test.esp32-c3-idf.yaml @@ -1,19 +1,7 @@ -i2c: - - id: i2c_font - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + display_reset_pin: GPIO3 -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 +packages: + common: !include common.yaml diff --git a/tests/components/font/test.esp32-c3.yaml b/tests/components/font/test.esp32-c3.yaml index b63b4d025a..ad14a2e9a6 100644 --- a/tests/components/font/test.esp32-c3.yaml +++ b/tests/components/font/test.esp32-c3.yaml @@ -1,19 +1,7 @@ -i2c: - - id: i2c_font - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + display_reset_pin: GPIO3 -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 +packages: + common: !include common.yaml diff --git a/tests/components/font/test.esp32-idf.yaml b/tests/components/font/test.esp32-idf.yaml index dcf8fb49d5..d98600a51b 100644 --- a/tests/components/font/test.esp32-idf.yaml +++ b/tests/components/font/test.esp32-idf.yaml @@ -1,19 +1,7 @@ -i2c: - - id: i2c_font - scl: 16 - sda: 17 +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + display_reset_pin: GPIO13 -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 13 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 +packages: + common: !include common.yaml diff --git a/tests/components/font/test.esp32.yaml b/tests/components/font/test.esp32.yaml index d142463893..d98600a51b 100644 --- a/tests/components/font/test.esp32.yaml +++ b/tests/components/font/test.esp32.yaml @@ -1,38 +1,7 @@ -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 - glyphs: "0123456789." - extras: - - file: "gfonts://Roboto" - glyphs: ["\u00C4", "\u00C5", "\U000000C7"] - - file: "gfonts://Roboto" - id: roboto_web - size: 20 - - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" - id: monocraft - size: 20 - - file: - type: web - url: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" - id: monocraft2 - size: 24 - -spi: - clk_pin: 14 - mosi_pin: 13 - -display: - - id: my_display - platform: ili9xxx - dimensions: 480x320 - model: ST7796 - cs_pin: 15 - dc_pin: 21 - reset_pin: 22 - transform: - swap_xy: true - mirror_x: true - mirror_y: true - auto_clear_enabled: false +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + display_reset_pin: GPIO13 +packages: + common: !include common.yaml diff --git a/tests/components/font/test.esp8266.yaml b/tests/components/font/test.esp8266.yaml index b63b4d025a..ad14a2e9a6 100644 --- a/tests/components/font/test.esp8266.yaml +++ b/tests/components/font/test.esp8266.yaml @@ -1,19 +1,7 @@ -i2c: - - id: i2c_font - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + display_reset_pin: GPIO3 -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 +packages: + common: !include common.yaml diff --git a/tests/components/font/test.rp2040.yaml b/tests/components/font/test.rp2040.yaml index b63b4d025a..ad14a2e9a6 100644 --- a/tests/components/font/test.rp2040.yaml +++ b/tests/components/font/test.rp2040.yaml @@ -1,19 +1,7 @@ -i2c: - - id: i2c_font - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + display_reset_pin: GPIO3 -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 +packages: + common: !include common.yaml diff --git a/tests/test_build_components/build_components_base.bk72xx.yaml b/tests/test_build_components/build_components_base.bk72xx.yaml index 7fdaebc768..d74cc651eb 100644 --- a/tests/test_build_components/build_components_base.bk72xx.yaml +++ b/tests/test_build_components/build_components_base.bk72xx.yaml @@ -16,3 +16,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-ard.yaml b/tests/test_build_components/build_components_base.esp32-ard.yaml index f460c57298..e345adcafc 100644 --- a/tests/test_build_components/build_components_base.esp32-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-ard.yaml @@ -18,3 +18,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-c3-ard.yaml b/tests/test_build_components/build_components_base.esp32-c3-ard.yaml index 8a52e0c916..136ee62d4b 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-ard.yaml @@ -18,3 +18,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf.yaml index 6b4b61fe58..4e809dd7ce 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-idf.yaml @@ -18,3 +18,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-idf.yaml b/tests/test_build_components/build_components_base.esp32-idf.yaml index ab1bda2a19..3c4532a958 100644 --- a/tests/test_build_components/build_components_base.esp32-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-idf.yaml @@ -18,3 +18,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s2-ard.yaml b/tests/test_build_components/build_components_base.esp32-s2-ard.yaml index ffb912d3d9..db62cdff6a 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-ard.yaml @@ -19,3 +19,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml index 4d1378b2b2..19fb657d8b 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml @@ -19,3 +19,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s3-ard.yaml b/tests/test_build_components/build_components_base.esp32-s3-ard.yaml index c850c9665f..39e12de08c 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-ard.yaml @@ -19,3 +19,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml index a43a2a6736..95c73f917e 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml @@ -19,3 +19,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp8266.yaml b/tests/test_build_components/build_components_base.esp8266.yaml index d7bdc03659..0019298ef0 100644 --- a/tests/test_build_components/build_components_base.esp8266.yaml +++ b/tests/test_build_components/build_components_base.esp8266.yaml @@ -16,3 +16,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.host.yaml b/tests/test_build_components/build_components_base.host.yaml index 00b252da2d..ec7570d99a 100644 --- a/tests/test_build_components/build_components_base.host.yaml +++ b/tests/test_build_components/build_components_base.host.yaml @@ -16,3 +16,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.rp2040.yaml b/tests/test_build_components/build_components_base.rp2040.yaml index a02942ea35..cb1cb6359b 100644 --- a/tests/test_build_components/build_components_base.rp2040.yaml +++ b/tests/test_build_components/build_components_base.rp2040.yaml @@ -19,3 +19,4 @@ packages: test_name: $test_name target_platform: $target_platform component_test_file: $component_test_file + component_dir: "../../components/$component_name" From 16e0b78c643867e94fde5fe912f08c77f5ab6921 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:05:50 +0200 Subject: [PATCH 1581/2607] Define `USE_ESP32_BLE` (#6585) --- esphome/components/esp32_ble/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 57a7341505..088a3b6d1e 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -65,6 +65,8 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) + cg.add_define("USE_ESP32_BLE") + @automation.register_condition("ble.enabled", BLEEnabledCondition, cv.Schema({})) async def ble_enabled_to_code(config, condition_id, template_arg, args): From 927caf062bab2e08e483666b3d67b94c4a6fb764 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Mon, 22 Apr 2024 22:48:06 +0200 Subject: [PATCH 1582/2607] wifi: fix reconnect issue due to enablement of fast connect (#6598) --- esphome/components/wifi/wifi_component.cpp | 8 ++++++-- esphome/components/wifi/wifi_component.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 8f46bf29a0..075e683bb5 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -128,7 +128,7 @@ void WiFiComponent::loop() { case WIFI_COMPONENT_STATE_COOLDOWN: { this->status_set_warning(); if (millis() - this->action_started_ > 5000) { - if (this->fast_connect_) { + if (this->fast_connect_ || this->retry_hidden_) { this->start_connecting(this->sta_[0], false); } else { this->start_scanning(); @@ -591,6 +591,9 @@ void WiFiComponent::check_connecting_finished() { return; } + // We won't retry hidden networks unless a reconnect fails more than three times again + this->retry_hidden_ = false; + ESP_LOGI(TAG, "WiFi Connected!"); this->print_connect_params_(); @@ -668,10 +671,11 @@ void WiFiComponent::retry_connect() { this->wifi_mode_(false, {}); delay(100); // NOLINT this->num_retried_ = 0; + this->retry_hidden_ = false; } else { // Try hidden networks after 3 failed retries ESP_LOGD(TAG, "Retrying with hidden networks..."); - this->fast_connect_ = true; + this->retry_hidden_ = true; this->num_retried_++; } } else { diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d9cb6a9ae2..133fa2970c 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -371,6 +371,7 @@ class WiFiComponent : public Component { std::vector sta_priorities_; WiFiAP selected_ap_; bool fast_connect_{false}; + bool retry_hidden_{false}; bool has_ap_{false}; WiFiAP ap_; From 50e3ce4c809489a5cd2b0166d7120d1c990d0c0d Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:59:06 +0000 Subject: [PATCH 1583/2607] Calibrate Beken internal temperature (#6599) --- .../internal_temperature/internal_temperature.cpp | 8 +++++--- tests/components/internal_temperature/test.bk72xx.yaml | 3 +++ .../internal_temperature/test.esp32-c3-idf.yaml | 3 +++ tests/components/internal_temperature/test.esp32-c3.yaml | 3 +++ tests/components/internal_temperature/test.esp32-idf.yaml | 3 +++ tests/components/internal_temperature/test.esp32.yaml | 3 +++ tests/components/internal_temperature/test.rp2040.yaml | 3 +++ 7 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/components/internal_temperature/test.bk72xx.yaml create mode 100644 tests/components/internal_temperature/test.esp32-c3-idf.yaml create mode 100644 tests/components/internal_temperature/test.esp32-c3.yaml create mode 100644 tests/components/internal_temperature/test.esp32-idf.yaml create mode 100644 tests/components/internal_temperature/test.esp32.yaml create mode 100644 tests/components/internal_temperature/test.rp2040.yaml diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index 255d95f6f8..47f516f568 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -55,11 +55,13 @@ void InternalTemperatureSensor::update() { uint32_t raw, result; result = temp_single_get_current_temperature(&raw); success = (result == 0); -#ifdef USE_LIBRETINY_VARIANT_BK7231T +#if defined(USE_LIBRETINY_VARIANT_BK7231N) + temperature = raw * -0.38f + 156.0f; +#elif defined(USE_LIBRETINY_VARIANT_BK7231T) temperature = raw * 0.04f; -#else +#else // USE_LIBRETINY_VARIANT temperature = raw * 0.128f; -#endif // USE_LIBRETINY_VARIANT_BK7231T +#endif // USE_LIBRETINY_VARIANT #endif // USE_BK72XX if (success && std::isfinite(temperature)) { this->publish_state(temperature); diff --git a/tests/components/internal_temperature/test.bk72xx.yaml b/tests/components/internal_temperature/test.bk72xx.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.bk72xx.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-c3-idf.yaml b/tests/components/internal_temperature/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-c3.yaml b/tests/components/internal_temperature/test.esp32-c3.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-idf.yaml b/tests/components/internal_temperature/test.esp32-idf.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32.yaml b/tests/components/internal_temperature/test.esp32.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.rp2040.yaml b/tests/components/internal_temperature/test.rp2040.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.rp2040.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" From a9a9be32d3a6869aab78d37bb77b6d385c95837b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:14:56 +1200 Subject: [PATCH 1584/2607] Bump aioesphomeapi from 24.0.0 to 24.3.0 (#6602) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 68041675f6..df94b8b77c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240412.0 -aioesphomeapi==24.0.0 +aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 ruamel.yaml==0.18.6 # dashboard_import From 7c893aa3309bcd7756432c6ba5b96a8c57d9e4ff Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Mon, 22 Apr 2024 15:48:29 -0600 Subject: [PATCH 1585/2607] fix streaming logs from MQTT for ESP32 devices using TLS (#6605) --- esphome/mqtt.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/mqtt.py b/esphome/mqtt.py index 166301005d..667a20bcf8 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -10,6 +10,7 @@ import paho.mqtt.client as mqtt from esphome.const import ( CONF_BROKER, + CONF_CERTIFICATE_AUTHORITY, CONF_DISCOVERY_PREFIX, CONF_ESPHOME, CONF_LOG_TOPIC, @@ -99,7 +100,9 @@ def prepare( elif username: client.username_pw_set(username, password) - if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS): + if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS) or config[CONF_MQTT].get( + CONF_CERTIFICATE_AUTHORITY + ): if sys.version_info >= (2, 7, 13): tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member else: From c7bfd9b46b63a52ad4ccd45e35e36cd4b073dbd9 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:04:56 +1000 Subject: [PATCH 1586/2607] Disallow variant/family override for known boards (#6512) --- esphome/components/esp32/__init__.py | 25 +++++++++++++------ esphome/components/libretiny/__init__.py | 31 +++++++++++++++--------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 50d6d229f9..8ae6262f2f 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -316,17 +316,26 @@ def _parse_platform_version(value): def _detect_variant(value): - if CONF_VARIANT not in value: - board = value[CONF_BOARD] - if board not in BOARDS: + board = value[CONF_BOARD] + if board in BOARDS: + variant = BOARDS[board][KEY_VARIANT] + if CONF_VARIANT in value and variant != value[CONF_VARIANT]: raise cv.Invalid( - "This board is unknown, please set the variant manually", + f"Option '{CONF_VARIANT}' does not match selected board.", + path=[CONF_VARIANT], + ) + value = value.copy() + value[CONF_VARIANT] = variant + else: + if CONF_VARIANT not in value: + raise cv.Invalid( + "This board is unknown, if you are sure you want to compile with this board selection, " + f"override with option '{CONF_VARIANT}'", path=[CONF_BOARD], ) - - value = value.copy() - value[CONF_VARIANT] = BOARDS[board][KEY_VARIANT] - + _LOGGER.warning( + "This board is unknown. Make sure the chosen chip component is correct.", + ) return value diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 34aff0ae16..a8034f8fab 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -1,6 +1,10 @@ import json import logging -from os.path import dirname, isfile, join +from os.path import ( + dirname, + isfile, + join, +) import esphome.codegen as cg import esphome.config_validation as cv @@ -55,15 +59,25 @@ def _detect_variant(value): component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] board = value[CONF_BOARD] # read board-default family if not specified - if CONF_FAMILY not in value: - if board not in component.boards: + if board not in component.boards: + if CONF_FAMILY not in value: raise cv.Invalid( - "This board is unknown, please set the family manually. " - "Also, make sure the chosen chip component is correct.", + "This board is unknown, if you are sure you want to compile with this board selection, " + f"override with option '{CONF_FAMILY}'", path=[CONF_BOARD], ) + _LOGGER.warning( + "This board is unknown. Make sure the chosen chip component is correct.", + ) + else: + family = component.boards[board][KEY_FAMILY] + if CONF_FAMILY in value and family != value[CONF_FAMILY]: + raise cv.Invalid( + f"Option '{CONF_FAMILY}' does not match selected board.", + path=[CONF_FAMILY], + ) value = value.copy() - value[CONF_FAMILY] = component.boards[board][KEY_FAMILY] + value[CONF_FAMILY] = family # read component name matching this family value[CONF_COMPONENT_ID] = FAMILY_COMPONENT[value[CONF_FAMILY]] # make sure the chosen component matches the family @@ -72,11 +86,6 @@ def _detect_variant(value): f"The chosen family doesn't belong to '{component.name}' component. The correct component is '{value[CONF_COMPONENT_ID]}'", path=[CONF_FAMILY], ) - # warn anyway if the board wasn't found - if board not in component.boards: - _LOGGER.warning( - "This board is unknown. Make sure the chosen chip component is correct.", - ) return value From 7510468a9bd9956b097d5bd4f00ef8e751c97b17 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:10:07 +1000 Subject: [PATCH 1587/2607] Add yamllint and clang-format to pre-commit hooks (#6578) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 69aafd4d15..15e59b7eb7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,3 +31,12 @@ repos: hooks: - id: pyupgrade args: [--py39-plus] + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.35.1 + hooks: + - id: yamllint + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v13.0.1 + hooks: + - id: clang-format + From aee2a49cad466232b087dc0a690e0cd50f10a802 Mon Sep 17 00:00:00 2001 From: polyfloyd Date: Tue, 23 Apr 2024 00:17:00 +0200 Subject: [PATCH 1588/2607] esp32_ble: Consider ESP_BT_STATUS_DONE a successful state (#6493) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index a5bbd85b47..a5209c764a 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -364,7 +364,11 @@ void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_ga } void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m) { - this->scan_set_param_failed_ = param.status; + if (param.status == ESP_BT_STATUS_DONE) { + this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS; + } else { + this->scan_set_param_failed_ = param.status; + } } void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m) { From 0874440a317bc8541b79f829a253209608be9568 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:48:30 -0400 Subject: [PATCH 1589/2607] Fix or filter (#6574) Co-authored-by: Jonathan Swoboda --- esphome/components/sensor/filter.cpp | 6 +++++- esphome/components/sensor/filter.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 3f67af59be..eaa909429b 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -359,11 +359,15 @@ OrFilter::OrFilter(std::vector filters) : filters_(std::move(filters)) OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {} optional OrFilter::PhiNode::new_value(float value) { - this->or_parent_->output(value); + if (!this->or_parent_->has_value_) { + this->or_parent_->output(value); + this->or_parent_->has_value_ = true; + } return {}; } optional OrFilter::new_value(float value) { + this->has_value_ = false; for (Filter *filter : this->filters_) filter->input(value); diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 1a08699d7b..c13cb3420a 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -388,6 +388,7 @@ class OrFilter : public Filter { }; std::vector filters_; + bool has_value_{false}; PhiNode phi_; }; From 496b7f45db59958eb5e3c75ebc19f24fc752b698 Mon Sep 17 00:00:00 2001 From: zry98 Date: Wed, 17 Apr 2024 23:31:20 +0200 Subject: [PATCH 1590/2607] [Tuya Climate] Fix compilation error caused by codegen (#6568) --- esphome/components/tuya/climate/__init__.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index b3d401e5a4..56eb377ed7 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -208,7 +208,7 @@ async def to_code(config): cg.add(var.set_switch_id(switch_datapoint)) if active_state_config := config.get(CONF_ACTIVE_STATE): - cg.add(var.set_active_state_id(CONF_DATAPOINT)) + cg.add(var.set_active_state_id(active_state_config.get(CONF_DATAPOINT))) if (heating_value := active_state_config.get(CONF_HEATING_VALUE)) is not None: cg.add(var.set_active_state_heating_value(heating_value)) if (cooling_value := active_state_config.get(CONF_COOLING_VALUE)) is not None: @@ -219,14 +219,10 @@ async def to_code(config): cg.add(var.set_active_state_fanonly_value(fanonly_value)) else: if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): - heating_state_pin = await cg.gpio_pin_expression( - config(heating_state_pin_config) - ) + heating_state_pin = await cg.gpio_pin_expression(heating_state_pin_config) cg.add(var.set_heating_state_pin(heating_state_pin)) if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): - cooling_state_pin = await cg.gpio_pin_expression( - config(cooling_state_pin_config) - ) + cooling_state_pin = await cg.gpio_pin_expression(cooling_state_pin_config) cg.add(var.set_cooling_state_pin(cooling_state_pin)) if target_temperature_datapoint := config.get(CONF_TARGET_TEMPERATURE_DATAPOINT): @@ -254,11 +250,11 @@ async def to_code(config): if preset_config := config.get(CONF_PRESET, {}): if eco_config := preset_config.get(CONF_ECO, {}): - cg.add(var.set_eco_id(CONF_DATAPOINT)) + cg.add(var.set_eco_id(eco_config.get(CONF_DATAPOINT))) if eco_temperature := eco_config.get(CONF_TEMPERATURE): cg.add(var.set_eco_temperature(eco_temperature)) - if CONF_SLEEP in preset_config: - cg.add(var.set_sleep_id(CONF_DATAPOINT)) + if sleep_config := preset_config.get(CONF_SLEEP, {}): + cg.add(var.set_sleep_id(sleep_config.get(CONF_DATAPOINT))) if swing_mode_config := config.get(CONF_SWING_MODE): if swing_vertical_datapoint := swing_mode_config.get(CONF_VERTICAL_DATAPOINT): @@ -268,7 +264,7 @@ async def to_code(config): ): cg.add(var.set_swing_horizontal_id(swing_horizontal_datapoint)) if fan_mode_config := config.get(CONF_FAN_MODE): - cg.add(var.set_fan_speed_id(CONF_DATAPOINT)) + cg.add(var.set_fan_speed_id(fan_mode_config.get(CONF_DATAPOINT))) if (fan_auto_value := fan_mode_config.get(CONF_AUTO_VALUE)) is not None: cg.add(var.set_fan_speed_auto_value(fan_auto_value)) if (fan_low_value := fan_mode_config.get(CONF_LOW_VALUE)) is not None: From 1a152169e0fb6ea0d1cd0873b9f140c201ae4def Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Mon, 22 Apr 2024 22:48:06 +0200 Subject: [PATCH 1591/2607] wifi: fix reconnect issue due to enablement of fast connect (#6598) --- esphome/components/wifi/wifi_component.cpp | 8 ++++++-- esphome/components/wifi/wifi_component.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 8f46bf29a0..075e683bb5 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -128,7 +128,7 @@ void WiFiComponent::loop() { case WIFI_COMPONENT_STATE_COOLDOWN: { this->status_set_warning(); if (millis() - this->action_started_ > 5000) { - if (this->fast_connect_) { + if (this->fast_connect_ || this->retry_hidden_) { this->start_connecting(this->sta_[0], false); } else { this->start_scanning(); @@ -591,6 +591,9 @@ void WiFiComponent::check_connecting_finished() { return; } + // We won't retry hidden networks unless a reconnect fails more than three times again + this->retry_hidden_ = false; + ESP_LOGI(TAG, "WiFi Connected!"); this->print_connect_params_(); @@ -668,10 +671,11 @@ void WiFiComponent::retry_connect() { this->wifi_mode_(false, {}); delay(100); // NOLINT this->num_retried_ = 0; + this->retry_hidden_ = false; } else { // Try hidden networks after 3 failed retries ESP_LOGD(TAG, "Retrying with hidden networks..."); - this->fast_connect_ = true; + this->retry_hidden_ = true; this->num_retried_++; } } else { diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d9cb6a9ae2..133fa2970c 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -371,6 +371,7 @@ class WiFiComponent : public Component { std::vector sta_priorities_; WiFiAP selected_ap_; bool fast_connect_{false}; + bool retry_hidden_{false}; bool has_ap_{false}; WiFiAP ap_; From a29e634af103baa07dbcdaf02cd898e638d79d3a Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:59:06 +0000 Subject: [PATCH 1592/2607] Calibrate Beken internal temperature (#6599) --- .../internal_temperature/internal_temperature.cpp | 8 +++++--- tests/components/internal_temperature/test.bk72xx.yaml | 3 +++ .../internal_temperature/test.esp32-c3-idf.yaml | 3 +++ tests/components/internal_temperature/test.esp32-c3.yaml | 3 +++ tests/components/internal_temperature/test.esp32-idf.yaml | 3 +++ tests/components/internal_temperature/test.esp32.yaml | 3 +++ tests/components/internal_temperature/test.rp2040.yaml | 3 +++ 7 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/components/internal_temperature/test.bk72xx.yaml create mode 100644 tests/components/internal_temperature/test.esp32-c3-idf.yaml create mode 100644 tests/components/internal_temperature/test.esp32-c3.yaml create mode 100644 tests/components/internal_temperature/test.esp32-idf.yaml create mode 100644 tests/components/internal_temperature/test.esp32.yaml create mode 100644 tests/components/internal_temperature/test.rp2040.yaml diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index 255d95f6f8..47f516f568 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -55,11 +55,13 @@ void InternalTemperatureSensor::update() { uint32_t raw, result; result = temp_single_get_current_temperature(&raw); success = (result == 0); -#ifdef USE_LIBRETINY_VARIANT_BK7231T +#if defined(USE_LIBRETINY_VARIANT_BK7231N) + temperature = raw * -0.38f + 156.0f; +#elif defined(USE_LIBRETINY_VARIANT_BK7231T) temperature = raw * 0.04f; -#else +#else // USE_LIBRETINY_VARIANT temperature = raw * 0.128f; -#endif // USE_LIBRETINY_VARIANT_BK7231T +#endif // USE_LIBRETINY_VARIANT #endif // USE_BK72XX if (success && std::isfinite(temperature)) { this->publish_state(temperature); diff --git a/tests/components/internal_temperature/test.bk72xx.yaml b/tests/components/internal_temperature/test.bk72xx.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.bk72xx.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-c3-idf.yaml b/tests/components/internal_temperature/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-c3.yaml b/tests/components/internal_temperature/test.esp32-c3.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32-idf.yaml b/tests/components/internal_temperature/test.esp32-idf.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.esp32.yaml b/tests/components/internal_temperature/test.esp32.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" diff --git a/tests/components/internal_temperature/test.rp2040.yaml b/tests/components/internal_temperature/test.rp2040.yaml new file mode 100644 index 0000000000..28df4a6d9f --- /dev/null +++ b/tests/components/internal_temperature/test.rp2040.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: "Internal Temperature" From dd8be524b433ddd80c68c7556b5ba156b58cf81b Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Mon, 22 Apr 2024 15:48:29 -0600 Subject: [PATCH 1593/2607] fix streaming logs from MQTT for ESP32 devices using TLS (#6605) --- esphome/mqtt.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/mqtt.py b/esphome/mqtt.py index 166301005d..667a20bcf8 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -10,6 +10,7 @@ import paho.mqtt.client as mqtt from esphome.const import ( CONF_BROKER, + CONF_CERTIFICATE_AUTHORITY, CONF_DISCOVERY_PREFIX, CONF_ESPHOME, CONF_LOG_TOPIC, @@ -99,7 +100,9 @@ def prepare( elif username: client.username_pw_set(username, password) - if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS): + if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS) or config[CONF_MQTT].get( + CONF_CERTIFICATE_AUTHORITY + ): if sys.version_info >= (2, 7, 13): tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member else: From 03d547d2c0a0b1e89487a5fec8a4696d6afd8685 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:04:56 +1000 Subject: [PATCH 1594/2607] Disallow variant/family override for known boards (#6512) --- esphome/components/esp32/__init__.py | 25 +++++++++++++------ esphome/components/libretiny/__init__.py | 31 +++++++++++++++--------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 50d6d229f9..8ae6262f2f 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -316,17 +316,26 @@ def _parse_platform_version(value): def _detect_variant(value): - if CONF_VARIANT not in value: - board = value[CONF_BOARD] - if board not in BOARDS: + board = value[CONF_BOARD] + if board in BOARDS: + variant = BOARDS[board][KEY_VARIANT] + if CONF_VARIANT in value and variant != value[CONF_VARIANT]: raise cv.Invalid( - "This board is unknown, please set the variant manually", + f"Option '{CONF_VARIANT}' does not match selected board.", + path=[CONF_VARIANT], + ) + value = value.copy() + value[CONF_VARIANT] = variant + else: + if CONF_VARIANT not in value: + raise cv.Invalid( + "This board is unknown, if you are sure you want to compile with this board selection, " + f"override with option '{CONF_VARIANT}'", path=[CONF_BOARD], ) - - value = value.copy() - value[CONF_VARIANT] = BOARDS[board][KEY_VARIANT] - + _LOGGER.warning( + "This board is unknown. Make sure the chosen chip component is correct.", + ) return value diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 34aff0ae16..a8034f8fab 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -1,6 +1,10 @@ import json import logging -from os.path import dirname, isfile, join +from os.path import ( + dirname, + isfile, + join, +) import esphome.codegen as cg import esphome.config_validation as cv @@ -55,15 +59,25 @@ def _detect_variant(value): component: LibreTinyComponent = CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] board = value[CONF_BOARD] # read board-default family if not specified - if CONF_FAMILY not in value: - if board not in component.boards: + if board not in component.boards: + if CONF_FAMILY not in value: raise cv.Invalid( - "This board is unknown, please set the family manually. " - "Also, make sure the chosen chip component is correct.", + "This board is unknown, if you are sure you want to compile with this board selection, " + f"override with option '{CONF_FAMILY}'", path=[CONF_BOARD], ) + _LOGGER.warning( + "This board is unknown. Make sure the chosen chip component is correct.", + ) + else: + family = component.boards[board][KEY_FAMILY] + if CONF_FAMILY in value and family != value[CONF_FAMILY]: + raise cv.Invalid( + f"Option '{CONF_FAMILY}' does not match selected board.", + path=[CONF_FAMILY], + ) value = value.copy() - value[CONF_FAMILY] = component.boards[board][KEY_FAMILY] + value[CONF_FAMILY] = family # read component name matching this family value[CONF_COMPONENT_ID] = FAMILY_COMPONENT[value[CONF_FAMILY]] # make sure the chosen component matches the family @@ -72,11 +86,6 @@ def _detect_variant(value): f"The chosen family doesn't belong to '{component.name}' component. The correct component is '{value[CONF_COMPONENT_ID]}'", path=[CONF_FAMILY], ) - # warn anyway if the board wasn't found - if board not in component.boards: - _LOGGER.warning( - "This board is unknown. Make sure the chosen chip component is correct.", - ) return value From 44d13f2405abba7d7f21334e1364b2ca90967a07 Mon Sep 17 00:00:00 2001 From: polyfloyd Date: Tue, 23 Apr 2024 00:17:00 +0200 Subject: [PATCH 1595/2607] esp32_ble: Consider ESP_BT_STATUS_DONE a successful state (#6493) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index a5bbd85b47..a5209c764a 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -364,7 +364,11 @@ void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_ga } void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m) { - this->scan_set_param_failed_ = param.status; + if (param.status == ESP_BT_STATUS_DONE) { + this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS; + } else { + this->scan_set_param_failed_ = param.status; + } } void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m) { From 3e6487609714d207a69d2a984ab40f9b9c0539a5 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:48:30 -0400 Subject: [PATCH 1596/2607] Fix or filter (#6574) Co-authored-by: Jonathan Swoboda --- esphome/components/sensor/filter.cpp | 6 +++++- esphome/components/sensor/filter.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 6d7acad7e0..18cc10ed8b 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -359,11 +359,15 @@ OrFilter::OrFilter(std::vector filters) : filters_(std::move(filters)) OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {} optional OrFilter::PhiNode::new_value(float value) { - this->or_parent_->output(value); + if (!this->or_parent_->has_value_) { + this->or_parent_->output(value); + this->or_parent_->has_value_ = true; + } return {}; } optional OrFilter::new_value(float value) { + this->has_value_ = false; for (Filter *filter : this->filters_) filter->input(value); diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 1a08699d7b..c13cb3420a 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -388,6 +388,7 @@ class OrFilter : public Filter { }; std::vector filters_; + bool has_value_{false}; PhiNode phi_; }; From 7ae36b023cec67a6e183df1ee7d183c12dd1d2a2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:50:41 +1200 Subject: [PATCH 1597/2607] Bump version to 2024.4.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 76320e6c71..69949dc086 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.0" +__version__ = "2024.4.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From a7fb2ce3e114c96b4148b27516581b3455f09f40 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:01:20 +1200 Subject: [PATCH 1598/2607] Use clang-format version from requirements_dev file (#6606) --- .github/workflows/ci.yml | 3 +-- requirements_dev.txt | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3ac7981d3..15f0904df4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,6 @@ permissions: env: DEFAULT_PYTHON: "3.9" PYUPGRADE_TARGET: "--py39-plus" - CLANG_FORMAT_VERSION: "13.0.1" concurrency: # yamllint disable-line rule:line-length @@ -239,7 +238,7 @@ jobs: - name: Install clang-format run: | . venv/bin/activate - pip install clang-format==${{ env.CLANG_FORMAT_VERSION }} + pip install clang-format -c requirements_dev.txt - name: Run clang-format run: | . venv/bin/activate diff --git a/requirements_dev.txt b/requirements_dev.txt index 6bfa015c6f..eb749a861d 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ # Useful stuff when working in a development environment -clang-format==13.0.1 -clang-tidy==14.0.6 -yamllint==1.35.1 +clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating +clang-tidy==14.0.6 # When updating clang-tidy, also update Dockerfile +yamllint==1.35.1 # also change in .pre-commit-config.yaml when updating From b737fe70a6c3fc811845d0e43097a4d4a5abf88c Mon Sep 17 00:00:00 2001 From: mrtoy-me <118446898+mrtoy-me@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:16:55 +1000 Subject: [PATCH 1599/2607] Fix SHT3xd fails sometimes in 2024.4.0 (#6592) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sht3xd/sht3xd.cpp | 34 +++++++++++++++++++++++----- esphome/components/sht3xd/sht3xd.h | 7 ++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/esphome/components/sht3xd/sht3xd.cpp b/esphome/components/sht3xd/sht3xd.cpp index 888e954c6b..ffaf5db322 100644 --- a/esphome/components/sht3xd/sht3xd.cpp +++ b/esphome/components/sht3xd/sht3xd.cpp @@ -6,9 +6,14 @@ namespace sht3xd { static const char *const TAG = "sht3xd"; -// use read serial number register with clock stretching disabled as per other SHT3XD_COMMAND registers -// which provides support for SHT85 sensor -// SHT85 does not support clock stretching and uses same registers as SHT3xd with clock stretching disabled +// https://sensirion.com/media/documents/E5762713/63D103C2/Sensirion_electronic_identification_code_SHT3x.pdf +// indicates two possible read serial number registers either with clock stretching enabled or disabled. +// Other SHT3XD_COMMAND registers use the clock stretching disabled register. +// To ensure compatibility, reading serial number using the register with clock stretching register enabled +// (used originally in this component) is tried first and if that fails the alternate register address +// with clock stretching disabled is read. + +static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER_CLOCK_STRETCHING = 0x3780; static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER = 0x3682; static const uint16_t SHT3XD_COMMAND_READ_STATUS = 0xF32D; @@ -22,13 +27,19 @@ static const uint16_t SHT3XD_COMMAND_FETCH_DATA = 0xE000; void SHT3XDComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SHT3xD..."); uint16_t raw_serial_number[2]; - if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER, raw_serial_number, 2)) { - this->mark_failed(); - return; + if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER_CLOCK_STRETCHING, raw_serial_number, 2)) { + this->error_code_ = READ_SERIAL_STRETCHED_FAILED; + if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER, raw_serial_number, 2)) { + this->error_code_ = READ_SERIAL_FAILED; + this->mark_failed(); + return; + } } + this->serial_number_ = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); if (!this->write_command(heater_enabled_ ? SHT3XD_COMMAND_HEATER_ENABLE : SHT3XD_COMMAND_HEATER_DISABLE)) { + this->error_code_ = WRITE_HEATER_MODE_FAILED; this->mark_failed(); return; } @@ -36,10 +47,21 @@ void SHT3XDComponent::setup() { void SHT3XDComponent::dump_config() { ESP_LOGCONFIG(TAG, "SHT3xD:"); + switch (this->error_code_) { + case READ_SERIAL_FAILED: + ESP_LOGD(TAG, " Error reading serial number"); + break; + case WRITE_HEATER_MODE_FAILED: + ESP_LOGD(TAG, " Error writing heater mode"); + break; + default: + break; + } if (this->is_failed()) { ESP_LOGE(TAG, " Communication with SHT3xD failed!"); return; } + ESP_LOGD(TAG, " Setup successful"); ESP_LOGD(TAG, " Serial Number: 0x%08" PRIX32, this->serial_number_); ESP_LOGD(TAG, " Heater Enabled: %s", this->heater_enabled_ ? "true" : "false"); diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h index d1a3360e69..74f155121b 100644 --- a/esphome/components/sht3xd/sht3xd.h +++ b/esphome/components/sht3xd/sht3xd.h @@ -22,6 +22,13 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir void set_heater_enabled(bool heater_enabled) { heater_enabled_ = heater_enabled; } protected: + enum ErrorCode { + NONE = 0, + READ_SERIAL_STRETCHED_FAILED, + READ_SERIAL_FAILED, + WRITE_HEATER_MODE_FAILED, + } error_code_{NONE}; + sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; bool heater_enabled_{true}; From 057f473a4a19f05de5780337cfd84de6b2ec9061 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 22:38:51 -0500 Subject: [PATCH 1600/2607] Add some components to the new testing framework (P) (#6213) --- .../partition/test.esp32-c3-idf.yaml | 22 ++ tests/components/partition/test.esp32-c3.yaml | 22 ++ .../components/partition/test.esp32-idf.yaml | 22 ++ tests/components/partition/test.esp32.yaml | 22 ++ .../pca6416a/test.esp32-c3-idf.yaml | 17 ++ tests/components/pca6416a/test.esp32-c3.yaml | 17 ++ tests/components/pca6416a/test.esp32-idf.yaml | 17 ++ tests/components/pca6416a/test.esp32.yaml | 17 ++ tests/components/pca6416a/test.esp8266.yaml | 17 ++ tests/components/pca6416a/test.rp2040.yaml | 17 ++ .../components/pca9554/test.esp32-c3-idf.yaml | 26 ++ tests/components/pca9554/test.esp32-c3.yaml | 26 ++ tests/components/pca9554/test.esp32-idf.yaml | 26 ++ tests/components/pca9554/test.esp32.yaml | 26 ++ tests/components/pca9554/test.esp8266.yaml | 26 ++ tests/components/pca9554/test.rp2040.yaml | 26 ++ .../components/pca9685/test.esp32-c3-idf.yaml | 34 +++ tests/components/pca9685/test.esp32-c3.yaml | 34 +++ tests/components/pca9685/test.esp32-idf.yaml | 34 +++ tests/components/pca9685/test.esp32.yaml | 34 +++ tests/components/pca9685/test.esp8266.yaml | 34 +++ tests/components/pca9685/test.rp2040.yaml | 26 ++ .../components/pcd8544/test.esp32-c3-idf.yaml | 14 + tests/components/pcd8544/test.esp32-c3.yaml | 14 + tests/components/pcd8544/test.esp32-idf.yaml | 14 + tests/components/pcd8544/test.esp32.yaml | 14 + tests/components/pcd8544/test.esp8266.yaml | 14 + tests/components/pcd8544/test.rp2040.yaml | 14 + .../pcf85063/test.esp32-c3-idf.yaml | 12 + tests/components/pcf85063/test.esp32-c3.yaml | 12 + tests/components/pcf85063/test.esp32-idf.yaml | 12 + tests/components/pcf85063/test.esp32.yaml | 12 + tests/components/pcf85063/test.esp8266.yaml | 12 + tests/components/pcf85063/test.rp2040.yaml | 12 + .../components/pcf8563/test.esp32-c3-idf.yaml | 12 + tests/components/pcf8563/test.esp32-c3.yaml | 12 + tests/components/pcf8563/test.esp32-idf.yaml | 12 + tests/components/pcf8563/test.esp32.yaml | 12 + tests/components/pcf8563/test.esp8266.yaml | 12 + tests/components/pcf8563/test.rp2040.yaml | 12 + .../components/pcf8574/test.esp32-c3-idf.yaml | 28 ++ tests/components/pcf8574/test.esp32-c3.yaml | 28 ++ tests/components/pcf8574/test.esp32-idf.yaml | 28 ++ tests/components/pcf8574/test.esp32.yaml | 28 ++ tests/components/pcf8574/test.esp8266.yaml | 28 ++ tests/components/pcf8574/test.rp2040.yaml | 28 ++ tests/components/pid/test.esp32-c3-idf.yaml | 56 ++++ tests/components/pid/test.esp32-c3.yaml | 56 ++++ tests/components/pid/test.esp32-idf.yaml | 56 ++++ tests/components/pid/test.esp32.yaml | 56 ++++ tests/components/pid/test.esp8266.yaml | 56 ++++ tests/components/pid/test.rp2040.yaml | 56 ++++ .../pipsolar/test.esp32-c3-idf.yaml | 247 ++++++++++++++++++ tests/components/pipsolar/test.esp32-c3.yaml | 247 ++++++++++++++++++ tests/components/pipsolar/test.esp32-idf.yaml | 247 ++++++++++++++++++ tests/components/pipsolar/test.esp32.yaml | 247 ++++++++++++++++++ tests/components/pipsolar/test.esp8266.yaml | 247 ++++++++++++++++++ tests/components/pipsolar/test.rp2040.yaml | 247 ++++++++++++++++++ .../components/pm1006/test.esp32-c3-idf.yaml | 10 + tests/components/pm1006/test.esp32-c3.yaml | 10 + tests/components/pm1006/test.esp32-idf.yaml | 10 + tests/components/pm1006/test.esp32.yaml | 10 + tests/components/pm1006/test.esp8266.yaml | 10 + tests/components/pm1006/test.rp2040.yaml | 10 + .../pmsa003i/test.esp32-c3-idf.yaml | 27 ++ tests/components/pmsa003i/test.esp32-c3.yaml | 27 ++ tests/components/pmsa003i/test.esp32-idf.yaml | 27 ++ tests/components/pmsa003i/test.esp32.yaml | 27 ++ tests/components/pmsa003i/test.esp8266.yaml | 27 ++ tests/components/pmsa003i/test.rp2040.yaml | 27 ++ .../components/pmsx003/test.esp32-c3-idf.yaml | 34 +++ tests/components/pmsx003/test.esp32-c3.yaml | 34 +++ tests/components/pmsx003/test.esp32-idf.yaml | 34 +++ tests/components/pmsx003/test.esp32.yaml | 34 +++ tests/components/pmsx003/test.esp8266.yaml | 34 +++ tests/components/pmsx003/test.rp2040.yaml | 34 +++ .../components/pmwcs3/test.esp32-c3-idf.yaml | 15 ++ tests/components/pmwcs3/test.esp32-c3.yaml | 15 ++ tests/components/pmwcs3/test.esp32-idf.yaml | 15 ++ tests/components/pmwcs3/test.esp32.yaml | 15 ++ tests/components/pmwcs3/test.esp8266.yaml | 15 ++ tests/components/pmwcs3/test.rp2040.yaml | 15 ++ .../pn532_i2c/test.esp32-c3-idf.yaml | 13 + tests/components/pn532_i2c/test.esp32-c3.yaml | 13 + .../components/pn532_i2c/test.esp32-idf.yaml | 13 + tests/components/pn532_i2c/test.esp32.yaml | 13 + tests/components/pn532_i2c/test.esp8266.yaml | 13 + tests/components/pn532_i2c/test.rp2040.yaml | 13 + .../pn532_spi/test.esp32-c3-idf.yaml | 15 ++ tests/components/pn532_spi/test.esp32-c3.yaml | 15 ++ .../components/pn532_spi/test.esp32-idf.yaml | 15 ++ tests/components/pn532_spi/test.esp32.yaml | 15 ++ tests/components/pn532_spi/test.esp8266.yaml | 15 ++ tests/components/pn532_spi/test.rp2040.yaml | 15 ++ .../pn7150_i2c/test.esp32-c3-idf.yaml | 35 +++ .../components/pn7150_i2c/test.esp32-c3.yaml | 35 +++ .../components/pn7150_i2c/test.esp32-idf.yaml | 35 +++ tests/components/pn7150_i2c/test.esp32.yaml | 35 +++ tests/components/pn7150_i2c/test.esp8266.yaml | 35 +++ tests/components/pn7150_i2c/test.rp2040.yaml | 35 +++ .../pn7160_i2c/test.esp32-c3-idf.yaml | 35 +++ .../components/pn7160_i2c/test.esp32-c3.yaml | 35 +++ .../components/pn7160_i2c/test.esp32-idf.yaml | 35 +++ tests/components/pn7160_i2c/test.esp32.yaml | 35 +++ tests/components/pn7160_i2c/test.esp8266.yaml | 35 +++ tests/components/pn7160_i2c/test.rp2040.yaml | 35 +++ .../pn7160_spi/test.esp32-c3-idf.yaml | 37 +++ .../components/pn7160_spi/test.esp32-c3.yaml | 37 +++ .../components/pn7160_spi/test.esp32-idf.yaml | 37 +++ tests/components/pn7160_spi/test.esp32.yaml | 37 +++ tests/components/pn7160_spi/test.esp8266.yaml | 37 +++ tests/components/pn7160_spi/test.rp2040.yaml | 37 +++ .../power_supply/test.esp32-c3-idf.yaml | 6 + .../power_supply/test.esp32-c3.yaml | 6 + .../power_supply/test.esp32-idf.yaml | 6 + tests/components/power_supply/test.esp32.yaml | 6 + .../components/power_supply/test.esp8266.yaml | 6 + .../components/power_supply/test.rp2040.yaml | 6 + .../prometheus/test.esp32-c3-idf.yaml | 21 ++ .../components/prometheus/test.esp32-c3.yaml | 21 ++ .../components/prometheus/test.esp32-idf.yaml | 21 ++ tests/components/prometheus/test.esp32.yaml | 21 ++ tests/components/prometheus/test.esp8266.yaml | 21 ++ tests/components/psram/test.esp32-c3-idf.yaml | 3 + tests/components/psram/test.esp32-c3.yaml | 3 + tests/components/psram/test.esp32-idf.yaml | 3 + tests/components/psram/test.esp32.yaml | 3 + .../pulse_counter/test.esp32-c3-idf.yaml | 9 + .../pulse_counter/test.esp32-c3.yaml | 9 + .../pulse_counter/test.esp32-idf.yaml | 9 + .../components/pulse_counter/test.esp32.yaml | 9 + .../pulse_counter/test.esp8266.yaml | 9 + .../components/pulse_counter/test.rp2040.yaml | 9 + .../pulse_meter/test.esp32-c3-idf.yaml | 13 + .../components/pulse_meter/test.esp32-c3.yaml | 13 + .../pulse_meter/test.esp32-idf.yaml | 13 + tests/components/pulse_meter/test.esp32.yaml | 13 + .../components/pulse_meter/test.esp8266.yaml | 13 + tests/components/pulse_meter/test.rp2040.yaml | 13 + .../pulse_width/test.esp32-c3-idf.yaml | 4 + .../components/pulse_width/test.esp32-c3.yaml | 4 + .../pulse_width/test.esp32-idf.yaml | 4 + tests/components/pulse_width/test.esp32.yaml | 4 + .../components/pulse_width/test.esp8266.yaml | 4 + tests/components/pulse_width/test.rp2040.yaml | 4 + .../pvvx_mithermometer/test.esp32-c3-idf.yaml | 44 ++++ .../pvvx_mithermometer/test.esp32-c3.yaml | 44 ++++ .../pvvx_mithermometer/test.esp32-idf.yaml | 44 ++++ .../pvvx_mithermometer/test.esp32.yaml | 44 ++++ .../pylontech/test.esp32-c3-idf.yaml | 48 ++++ tests/components/pylontech/test.esp32-c3.yaml | 48 ++++ .../components/pylontech/test.esp32-idf.yaml | 48 ++++ tests/components/pylontech/test.esp32.yaml | 48 ++++ tests/components/pylontech/test.esp8266.yaml | 48 ++++ tests/components/pylontech/test.rp2040.yaml | 48 ++++ .../pzem004t/test.esp32-c3-idf.yaml | 14 + tests/components/pzem004t/test.esp32-c3.yaml | 14 + tests/components/pzem004t/test.esp32-idf.yaml | 14 + tests/components/pzem004t/test.esp32.yaml | 14 + tests/components/pzem004t/test.esp8266.yaml | 14 + tests/components/pzem004t/test.rp2040.yaml | 14 + .../components/pzemac/test.esp32-c3-idf.yaml | 28 ++ tests/components/pzemac/test.esp32-c3.yaml | 28 ++ tests/components/pzemac/test.esp32-idf.yaml | 28 ++ tests/components/pzemac/test.esp32.yaml | 28 ++ tests/components/pzemac/test.esp8266.yaml | 28 ++ tests/components/pzemac/test.rp2040.yaml | 28 ++ .../components/pzemdc/test.esp32-c3-idf.yaml | 23 ++ tests/components/pzemdc/test.esp32-c3.yaml | 23 ++ tests/components/pzemdc/test.esp32-idf.yaml | 23 ++ tests/components/pzemdc/test.esp32.yaml | 23 ++ tests/components/pzemdc/test.esp8266.yaml | 23 ++ tests/components/pzemdc/test.rp2040.yaml | 23 ++ 173 files changed, 5245 insertions(+) create mode 100644 tests/components/partition/test.esp32-c3-idf.yaml create mode 100644 tests/components/partition/test.esp32-c3.yaml create mode 100644 tests/components/partition/test.esp32-idf.yaml create mode 100644 tests/components/partition/test.esp32.yaml create mode 100644 tests/components/pca6416a/test.esp32-c3-idf.yaml create mode 100644 tests/components/pca6416a/test.esp32-c3.yaml create mode 100644 tests/components/pca6416a/test.esp32-idf.yaml create mode 100644 tests/components/pca6416a/test.esp32.yaml create mode 100644 tests/components/pca6416a/test.esp8266.yaml create mode 100644 tests/components/pca6416a/test.rp2040.yaml create mode 100644 tests/components/pca9554/test.esp32-c3-idf.yaml create mode 100644 tests/components/pca9554/test.esp32-c3.yaml create mode 100644 tests/components/pca9554/test.esp32-idf.yaml create mode 100644 tests/components/pca9554/test.esp32.yaml create mode 100644 tests/components/pca9554/test.esp8266.yaml create mode 100644 tests/components/pca9554/test.rp2040.yaml create mode 100644 tests/components/pca9685/test.esp32-c3-idf.yaml create mode 100644 tests/components/pca9685/test.esp32-c3.yaml create mode 100644 tests/components/pca9685/test.esp32-idf.yaml create mode 100644 tests/components/pca9685/test.esp32.yaml create mode 100644 tests/components/pca9685/test.esp8266.yaml create mode 100644 tests/components/pca9685/test.rp2040.yaml create mode 100644 tests/components/pcd8544/test.esp32-c3-idf.yaml create mode 100644 tests/components/pcd8544/test.esp32-c3.yaml create mode 100644 tests/components/pcd8544/test.esp32-idf.yaml create mode 100644 tests/components/pcd8544/test.esp32.yaml create mode 100644 tests/components/pcd8544/test.esp8266.yaml create mode 100644 tests/components/pcd8544/test.rp2040.yaml create mode 100644 tests/components/pcf85063/test.esp32-c3-idf.yaml create mode 100644 tests/components/pcf85063/test.esp32-c3.yaml create mode 100644 tests/components/pcf85063/test.esp32-idf.yaml create mode 100644 tests/components/pcf85063/test.esp32.yaml create mode 100644 tests/components/pcf85063/test.esp8266.yaml create mode 100644 tests/components/pcf85063/test.rp2040.yaml create mode 100644 tests/components/pcf8563/test.esp32-c3-idf.yaml create mode 100644 tests/components/pcf8563/test.esp32-c3.yaml create mode 100644 tests/components/pcf8563/test.esp32-idf.yaml create mode 100644 tests/components/pcf8563/test.esp32.yaml create mode 100644 tests/components/pcf8563/test.esp8266.yaml create mode 100644 tests/components/pcf8563/test.rp2040.yaml create mode 100644 tests/components/pcf8574/test.esp32-c3-idf.yaml create mode 100644 tests/components/pcf8574/test.esp32-c3.yaml create mode 100644 tests/components/pcf8574/test.esp32-idf.yaml create mode 100644 tests/components/pcf8574/test.esp32.yaml create mode 100644 tests/components/pcf8574/test.esp8266.yaml create mode 100644 tests/components/pcf8574/test.rp2040.yaml create mode 100644 tests/components/pid/test.esp32-c3-idf.yaml create mode 100644 tests/components/pid/test.esp32-c3.yaml create mode 100644 tests/components/pid/test.esp32-idf.yaml create mode 100644 tests/components/pid/test.esp32.yaml create mode 100644 tests/components/pid/test.esp8266.yaml create mode 100644 tests/components/pid/test.rp2040.yaml create mode 100644 tests/components/pipsolar/test.esp32-c3-idf.yaml create mode 100644 tests/components/pipsolar/test.esp32-c3.yaml create mode 100644 tests/components/pipsolar/test.esp32-idf.yaml create mode 100644 tests/components/pipsolar/test.esp32.yaml create mode 100644 tests/components/pipsolar/test.esp8266.yaml create mode 100644 tests/components/pipsolar/test.rp2040.yaml create mode 100644 tests/components/pm1006/test.esp32-c3-idf.yaml create mode 100644 tests/components/pm1006/test.esp32-c3.yaml create mode 100644 tests/components/pm1006/test.esp32-idf.yaml create mode 100644 tests/components/pm1006/test.esp32.yaml create mode 100644 tests/components/pm1006/test.esp8266.yaml create mode 100644 tests/components/pm1006/test.rp2040.yaml create mode 100644 tests/components/pmsa003i/test.esp32-c3-idf.yaml create mode 100644 tests/components/pmsa003i/test.esp32-c3.yaml create mode 100644 tests/components/pmsa003i/test.esp32-idf.yaml create mode 100644 tests/components/pmsa003i/test.esp32.yaml create mode 100644 tests/components/pmsa003i/test.esp8266.yaml create mode 100644 tests/components/pmsa003i/test.rp2040.yaml create mode 100644 tests/components/pmsx003/test.esp32-c3-idf.yaml create mode 100644 tests/components/pmsx003/test.esp32-c3.yaml create mode 100644 tests/components/pmsx003/test.esp32-idf.yaml create mode 100644 tests/components/pmsx003/test.esp32.yaml create mode 100644 tests/components/pmsx003/test.esp8266.yaml create mode 100644 tests/components/pmsx003/test.rp2040.yaml create mode 100644 tests/components/pmwcs3/test.esp32-c3-idf.yaml create mode 100644 tests/components/pmwcs3/test.esp32-c3.yaml create mode 100644 tests/components/pmwcs3/test.esp32-idf.yaml create mode 100644 tests/components/pmwcs3/test.esp32.yaml create mode 100644 tests/components/pmwcs3/test.esp8266.yaml create mode 100644 tests/components/pmwcs3/test.rp2040.yaml create mode 100644 tests/components/pn532_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/pn532_i2c/test.esp32-c3.yaml create mode 100644 tests/components/pn532_i2c/test.esp32-idf.yaml create mode 100644 tests/components/pn532_i2c/test.esp32.yaml create mode 100644 tests/components/pn532_i2c/test.esp8266.yaml create mode 100644 tests/components/pn532_i2c/test.rp2040.yaml create mode 100644 tests/components/pn532_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/pn532_spi/test.esp32-c3.yaml create mode 100644 tests/components/pn532_spi/test.esp32-idf.yaml create mode 100644 tests/components/pn532_spi/test.esp32.yaml create mode 100644 tests/components/pn532_spi/test.esp8266.yaml create mode 100644 tests/components/pn532_spi/test.rp2040.yaml create mode 100644 tests/components/pn7150_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/pn7150_i2c/test.esp32-c3.yaml create mode 100644 tests/components/pn7150_i2c/test.esp32-idf.yaml create mode 100644 tests/components/pn7150_i2c/test.esp32.yaml create mode 100644 tests/components/pn7150_i2c/test.esp8266.yaml create mode 100644 tests/components/pn7150_i2c/test.rp2040.yaml create mode 100644 tests/components/pn7160_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/pn7160_i2c/test.esp32-c3.yaml create mode 100644 tests/components/pn7160_i2c/test.esp32-idf.yaml create mode 100644 tests/components/pn7160_i2c/test.esp32.yaml create mode 100644 tests/components/pn7160_i2c/test.esp8266.yaml create mode 100644 tests/components/pn7160_i2c/test.rp2040.yaml create mode 100644 tests/components/pn7160_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/pn7160_spi/test.esp32-c3.yaml create mode 100644 tests/components/pn7160_spi/test.esp32-idf.yaml create mode 100644 tests/components/pn7160_spi/test.esp32.yaml create mode 100644 tests/components/pn7160_spi/test.esp8266.yaml create mode 100644 tests/components/pn7160_spi/test.rp2040.yaml create mode 100644 tests/components/power_supply/test.esp32-c3-idf.yaml create mode 100644 tests/components/power_supply/test.esp32-c3.yaml create mode 100644 tests/components/power_supply/test.esp32-idf.yaml create mode 100644 tests/components/power_supply/test.esp32.yaml create mode 100644 tests/components/power_supply/test.esp8266.yaml create mode 100644 tests/components/power_supply/test.rp2040.yaml create mode 100644 tests/components/prometheus/test.esp32-c3-idf.yaml create mode 100644 tests/components/prometheus/test.esp32-c3.yaml create mode 100644 tests/components/prometheus/test.esp32-idf.yaml create mode 100644 tests/components/prometheus/test.esp32.yaml create mode 100644 tests/components/prometheus/test.esp8266.yaml create mode 100644 tests/components/psram/test.esp32-c3-idf.yaml create mode 100644 tests/components/psram/test.esp32-c3.yaml create mode 100644 tests/components/psram/test.esp32-idf.yaml create mode 100644 tests/components/psram/test.esp32.yaml create mode 100644 tests/components/pulse_counter/test.esp32-c3-idf.yaml create mode 100644 tests/components/pulse_counter/test.esp32-c3.yaml create mode 100644 tests/components/pulse_counter/test.esp32-idf.yaml create mode 100644 tests/components/pulse_counter/test.esp32.yaml create mode 100644 tests/components/pulse_counter/test.esp8266.yaml create mode 100644 tests/components/pulse_counter/test.rp2040.yaml create mode 100644 tests/components/pulse_meter/test.esp32-c3-idf.yaml create mode 100644 tests/components/pulse_meter/test.esp32-c3.yaml create mode 100644 tests/components/pulse_meter/test.esp32-idf.yaml create mode 100644 tests/components/pulse_meter/test.esp32.yaml create mode 100644 tests/components/pulse_meter/test.esp8266.yaml create mode 100644 tests/components/pulse_meter/test.rp2040.yaml create mode 100644 tests/components/pulse_width/test.esp32-c3-idf.yaml create mode 100644 tests/components/pulse_width/test.esp32-c3.yaml create mode 100644 tests/components/pulse_width/test.esp32-idf.yaml create mode 100644 tests/components/pulse_width/test.esp32.yaml create mode 100644 tests/components/pulse_width/test.esp8266.yaml create mode 100644 tests/components/pulse_width/test.rp2040.yaml create mode 100644 tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml create mode 100644 tests/components/pvvx_mithermometer/test.esp32-c3.yaml create mode 100644 tests/components/pvvx_mithermometer/test.esp32-idf.yaml create mode 100644 tests/components/pvvx_mithermometer/test.esp32.yaml create mode 100644 tests/components/pylontech/test.esp32-c3-idf.yaml create mode 100644 tests/components/pylontech/test.esp32-c3.yaml create mode 100644 tests/components/pylontech/test.esp32-idf.yaml create mode 100644 tests/components/pylontech/test.esp32.yaml create mode 100644 tests/components/pylontech/test.esp8266.yaml create mode 100644 tests/components/pylontech/test.rp2040.yaml create mode 100644 tests/components/pzem004t/test.esp32-c3-idf.yaml create mode 100644 tests/components/pzem004t/test.esp32-c3.yaml create mode 100644 tests/components/pzem004t/test.esp32-idf.yaml create mode 100644 tests/components/pzem004t/test.esp32.yaml create mode 100644 tests/components/pzem004t/test.esp8266.yaml create mode 100644 tests/components/pzem004t/test.rp2040.yaml create mode 100644 tests/components/pzemac/test.esp32-c3-idf.yaml create mode 100644 tests/components/pzemac/test.esp32-c3.yaml create mode 100644 tests/components/pzemac/test.esp32-idf.yaml create mode 100644 tests/components/pzemac/test.esp32.yaml create mode 100644 tests/components/pzemac/test.esp8266.yaml create mode 100644 tests/components/pzemac/test.rp2040.yaml create mode 100644 tests/components/pzemdc/test.esp32-c3-idf.yaml create mode 100644 tests/components/pzemdc/test.esp32-c3.yaml create mode 100644 tests/components/pzemdc/test.esp32-idf.yaml create mode 100644 tests/components/pzemdc/test.esp32.yaml create mode 100644 tests/components/pzemdc/test.esp8266.yaml create mode 100644 tests/components/pzemdc/test.rp2040.yaml diff --git a/tests/components/partition/test.esp32-c3-idf.yaml b/tests/components/partition/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..77cfc5ad44 --- /dev/null +++ b/tests/components/partition/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +light: + - platform: esp32_rmt_led_strip + id: part_leds + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + - platform: partition + name: Partition Light + segments: + - id: part_leds + from: 0 + to: 0 + - id: part_leds + from: 1 + to: 10 + - id: part_leds + from: 20 + to: 25 + - single_light_id: part_leds diff --git a/tests/components/partition/test.esp32-c3.yaml b/tests/components/partition/test.esp32-c3.yaml new file mode 100644 index 0000000000..77cfc5ad44 --- /dev/null +++ b/tests/components/partition/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +light: + - platform: esp32_rmt_led_strip + id: part_leds + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + - platform: partition + name: Partition Light + segments: + - id: part_leds + from: 0 + to: 0 + - id: part_leds + from: 1 + to: 10 + - id: part_leds + from: 20 + to: 25 + - single_light_id: part_leds diff --git a/tests/components/partition/test.esp32-idf.yaml b/tests/components/partition/test.esp32-idf.yaml new file mode 100644 index 0000000000..77cfc5ad44 --- /dev/null +++ b/tests/components/partition/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +light: + - platform: esp32_rmt_led_strip + id: part_leds + default_transition_length: 500ms + chipset: ws2812 + rgb_order: GRB + num_leds: 256 + pin: 2 + rmt_channel: 0 + - platform: partition + name: Partition Light + segments: + - id: part_leds + from: 0 + to: 0 + - id: part_leds + from: 1 + to: 10 + - id: part_leds + from: 20 + to: 25 + - single_light_id: part_leds diff --git a/tests/components/partition/test.esp32.yaml b/tests/components/partition/test.esp32.yaml new file mode 100644 index 0000000000..c8eae67d40 --- /dev/null +++ b/tests/components/partition/test.esp32.yaml @@ -0,0 +1,22 @@ +light: + - platform: fastled_clockless + id: part_leds + chipset: WS2812B + pin: 2 + num_leds: 256 + rgb_order: GRB + default_transition_length: 0s + color_correct: [50%, 50%, 50%] + - platform: partition + name: Partition Light + segments: + - id: part_leds + from: 0 + to: 0 + - id: part_leds + from: 1 + to: 10 + - id: part_leds + from: 20 + to: 25 + - single_light_id: part_leds diff --git a/tests/components/pca6416a/test.esp32-c3-idf.yaml b/tests/components/pca6416a/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fe940c44cc --- /dev/null +++ b/tests/components/pca6416a/test.esp32-c3-idf.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 5 + sda: 4 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca6416a/test.esp32-c3.yaml b/tests/components/pca6416a/test.esp32-c3.yaml new file mode 100644 index 0000000000..fe940c44cc --- /dev/null +++ b/tests/components/pca6416a/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 5 + sda: 4 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca6416a/test.esp32-idf.yaml b/tests/components/pca6416a/test.esp32-idf.yaml new file mode 100644 index 0000000000..669e9416e4 --- /dev/null +++ b/tests/components/pca6416a/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 16 + sda: 17 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca6416a/test.esp32.yaml b/tests/components/pca6416a/test.esp32.yaml new file mode 100644 index 0000000000..669e9416e4 --- /dev/null +++ b/tests/components/pca6416a/test.esp32.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 16 + sda: 17 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca6416a/test.esp8266.yaml b/tests/components/pca6416a/test.esp8266.yaml new file mode 100644 index 0000000000..fe940c44cc --- /dev/null +++ b/tests/components/pca6416a/test.esp8266.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 5 + sda: 4 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca6416a/test.rp2040.yaml b/tests/components/pca6416a/test.rp2040.yaml new file mode 100644 index 0000000000..fe940c44cc --- /dev/null +++ b/tests/components/pca6416a/test.rp2040.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_pca6416a + scl: 5 + sda: 4 + +pca6416a: + - id: pca6416a_hub + address: 0x21 + +binary_sensor: + - platform: gpio + name: PCA6416A Binary Sensor + pin: + pca6416a: pca6416a_hub + number: 15 + mode: INPUT + inverted: true diff --git a/tests/components/pca9554/test.esp32-c3-idf.yaml b/tests/components/pca9554/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0ff453e64f --- /dev/null +++ b/tests/components/pca9554/test.esp32-c3-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 5 + sda: 4 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9554/test.esp32-c3.yaml b/tests/components/pca9554/test.esp32-c3.yaml new file mode 100644 index 0000000000..0ff453e64f --- /dev/null +++ b/tests/components/pca9554/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 5 + sda: 4 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9554/test.esp32-idf.yaml b/tests/components/pca9554/test.esp32-idf.yaml new file mode 100644 index 0000000000..8fe9686303 --- /dev/null +++ b/tests/components/pca9554/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 16 + sda: 17 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9554/test.esp32.yaml b/tests/components/pca9554/test.esp32.yaml new file mode 100644 index 0000000000..8fe9686303 --- /dev/null +++ b/tests/components/pca9554/test.esp32.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 16 + sda: 17 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9554/test.esp8266.yaml b/tests/components/pca9554/test.esp8266.yaml new file mode 100644 index 0000000000..0ff453e64f --- /dev/null +++ b/tests/components/pca9554/test.esp8266.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 5 + sda: 4 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9554/test.rp2040.yaml b/tests/components/pca9554/test.rp2040.yaml new file mode 100644 index 0000000000..0ff453e64f --- /dev/null +++ b/tests/components/pca9554/test.rp2040.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 5 + sda: 4 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pca9685/test.esp32-c3-idf.yaml b/tests/components/pca9685/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e532f323be --- /dev/null +++ b/tests/components/pca9685/test.esp32-c3-idf.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_pca9685 + scl: 5 + sda: 4 + +pca9685: + frequency: 500 + address: 0x0 + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + - platform: pca9685 + id: pca_3 + channel: 3 + - platform: pca9685 + id: pca_4 + channel: 4 + - platform: pca9685 + id: pca_5 + channel: 5 + - platform: pca9685 + id: pca_6 + channel: 6 + - platform: pca9685 + id: pca_7 + channel: 7 diff --git a/tests/components/pca9685/test.esp32-c3.yaml b/tests/components/pca9685/test.esp32-c3.yaml new file mode 100644 index 0000000000..e532f323be --- /dev/null +++ b/tests/components/pca9685/test.esp32-c3.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_pca9685 + scl: 5 + sda: 4 + +pca9685: + frequency: 500 + address: 0x0 + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + - platform: pca9685 + id: pca_3 + channel: 3 + - platform: pca9685 + id: pca_4 + channel: 4 + - platform: pca9685 + id: pca_5 + channel: 5 + - platform: pca9685 + id: pca_6 + channel: 6 + - platform: pca9685 + id: pca_7 + channel: 7 diff --git a/tests/components/pca9685/test.esp32-idf.yaml b/tests/components/pca9685/test.esp32-idf.yaml new file mode 100644 index 0000000000..d02a16bcd1 --- /dev/null +++ b/tests/components/pca9685/test.esp32-idf.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_pca9685 + scl: 16 + sda: 17 + +pca9685: + frequency: 500 + address: 0x0 + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + - platform: pca9685 + id: pca_3 + channel: 3 + - platform: pca9685 + id: pca_4 + channel: 4 + - platform: pca9685 + id: pca_5 + channel: 5 + - platform: pca9685 + id: pca_6 + channel: 6 + - platform: pca9685 + id: pca_7 + channel: 7 diff --git a/tests/components/pca9685/test.esp32.yaml b/tests/components/pca9685/test.esp32.yaml new file mode 100644 index 0000000000..d02a16bcd1 --- /dev/null +++ b/tests/components/pca9685/test.esp32.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_pca9685 + scl: 16 + sda: 17 + +pca9685: + frequency: 500 + address: 0x0 + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + - platform: pca9685 + id: pca_3 + channel: 3 + - platform: pca9685 + id: pca_4 + channel: 4 + - platform: pca9685 + id: pca_5 + channel: 5 + - platform: pca9685 + id: pca_6 + channel: 6 + - platform: pca9685 + id: pca_7 + channel: 7 diff --git a/tests/components/pca9685/test.esp8266.yaml b/tests/components/pca9685/test.esp8266.yaml new file mode 100644 index 0000000000..e532f323be --- /dev/null +++ b/tests/components/pca9685/test.esp8266.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_pca9685 + scl: 5 + sda: 4 + +pca9685: + frequency: 500 + address: 0x0 + +output: + - platform: pca9685 + id: pca_0 + channel: 0 + - platform: pca9685 + id: pca_1 + channel: 1 + - platform: pca9685 + id: pca_2 + channel: 2 + - platform: pca9685 + id: pca_3 + channel: 3 + - platform: pca9685 + id: pca_4 + channel: 4 + - platform: pca9685 + id: pca_5 + channel: 5 + - platform: pca9685 + id: pca_6 + channel: 6 + - platform: pca9685 + id: pca_7 + channel: 7 diff --git a/tests/components/pca9685/test.rp2040.yaml b/tests/components/pca9685/test.rp2040.yaml new file mode 100644 index 0000000000..0ff453e64f --- /dev/null +++ b/tests/components/pca9685/test.rp2040.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_pca9554 + scl: 5 + sda: 4 + +pca9554: + - id: pca9554_hub + pin_count: 8 + address: 0x3F + +binary_sensor: + - platform: gpio + id: pca9554_input + name: PCA9554 Binary Sensor + pin: + pca9554: pca9554_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: pca9554_output + pin: + pca9554: pca9554_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcd8544/test.esp32-c3-idf.yaml b/tests/components/pcd8544/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..57771d2d73 --- /dev/null +++ b/tests/components/pcd8544/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: pcd8544 + cs_pin: 2 + dc_pin: 3 + reset_pin: 1 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcd8544/test.esp32-c3.yaml b/tests/components/pcd8544/test.esp32-c3.yaml new file mode 100644 index 0000000000..57771d2d73 --- /dev/null +++ b/tests/components/pcd8544/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: pcd8544 + cs_pin: 2 + dc_pin: 3 + reset_pin: 1 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcd8544/test.esp32-idf.yaml b/tests/components/pcd8544/test.esp32-idf.yaml new file mode 100644 index 0000000000..20c05c407f --- /dev/null +++ b/tests/components/pcd8544/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: pcd8544 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcd8544/test.esp32.yaml b/tests/components/pcd8544/test.esp32.yaml new file mode 100644 index 0000000000..20c05c407f --- /dev/null +++ b/tests/components/pcd8544/test.esp32.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: pcd8544 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcd8544/test.esp8266.yaml b/tests/components/pcd8544/test.esp8266.yaml new file mode 100644 index 0000000000..6e6022c6d2 --- /dev/null +++ b/tests/components/pcd8544/test.esp8266.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: pcd8544 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcd8544/test.rp2040.yaml b/tests/components/pcd8544/test.rp2040.yaml new file mode 100644 index 0000000000..7181f99fb1 --- /dev/null +++ b/tests/components/pcd8544/test.rp2040.yaml @@ -0,0 +1,14 @@ +spi: + - id: spi_pcd8544 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: pcd8544 + cs_pin: 6 + dc_pin: 5 + reset_pin: 7 + contrast: 60 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/pcf85063/test.esp32-c3-idf.yaml b/tests/components/pcf85063/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9e1a3da81e --- /dev/null +++ b/tests/components/pcf85063/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 5 + sda: 4 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf85063/test.esp32-c3.yaml b/tests/components/pcf85063/test.esp32-c3.yaml new file mode 100644 index 0000000000..9e1a3da81e --- /dev/null +++ b/tests/components/pcf85063/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 5 + sda: 4 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf85063/test.esp32-idf.yaml b/tests/components/pcf85063/test.esp32-idf.yaml new file mode 100644 index 0000000000..9cce415103 --- /dev/null +++ b/tests/components/pcf85063/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 16 + sda: 17 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf85063/test.esp32.yaml b/tests/components/pcf85063/test.esp32.yaml new file mode 100644 index 0000000000..9cce415103 --- /dev/null +++ b/tests/components/pcf85063/test.esp32.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 16 + sda: 17 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf85063/test.esp8266.yaml b/tests/components/pcf85063/test.esp8266.yaml new file mode 100644 index 0000000000..9e1a3da81e --- /dev/null +++ b/tests/components/pcf85063/test.esp8266.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 5 + sda: 4 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf85063/test.rp2040.yaml b/tests/components/pcf85063/test.rp2040.yaml new file mode 100644 index 0000000000..9e1a3da81e --- /dev/null +++ b/tests/components/pcf85063/test.rp2040.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf85063.read_time + - pcf85063.write_time + +i2c: + - id: i2c_pcf85063 + scl: 5 + sda: 4 + +time: + - platform: pcf85063 diff --git a/tests/components/pcf8563/test.esp32-c3-idf.yaml b/tests/components/pcf8563/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f91a465e0f --- /dev/null +++ b/tests/components/pcf8563/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8563/test.esp32-c3.yaml b/tests/components/pcf8563/test.esp32-c3.yaml new file mode 100644 index 0000000000..f91a465e0f --- /dev/null +++ b/tests/components/pcf8563/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8563/test.esp32-idf.yaml b/tests/components/pcf8563/test.esp32-idf.yaml new file mode 100644 index 0000000000..e95b487b19 --- /dev/null +++ b/tests/components/pcf8563/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 16 + sda: 17 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8563/test.esp32.yaml b/tests/components/pcf8563/test.esp32.yaml new file mode 100644 index 0000000000..e95b487b19 --- /dev/null +++ b/tests/components/pcf8563/test.esp32.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 16 + sda: 17 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8563/test.esp8266.yaml b/tests/components/pcf8563/test.esp8266.yaml new file mode 100644 index 0000000000..f91a465e0f --- /dev/null +++ b/tests/components/pcf8563/test.esp8266.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8563/test.rp2040.yaml b/tests/components/pcf8563/test.rp2040.yaml new file mode 100644 index 0000000000..f91a465e0f --- /dev/null +++ b/tests/components/pcf8563/test.rp2040.yaml @@ -0,0 +1,12 @@ +esphome: + on_boot: + - pcf8563.read_time + - pcf8563.write_time + +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +time: + - platform: pcf8563 diff --git a/tests/components/pcf8574/test.esp32-c3-idf.yaml b/tests/components/pcf8574/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..551e425892 --- /dev/null +++ b/tests/components/pcf8574/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcf8574/test.esp32-c3.yaml b/tests/components/pcf8574/test.esp32-c3.yaml new file mode 100644 index 0000000000..551e425892 --- /dev/null +++ b/tests/components/pcf8574/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcf8574/test.esp32-idf.yaml b/tests/components/pcf8574/test.esp32-idf.yaml new file mode 100644 index 0000000000..aeed55f4fe --- /dev/null +++ b/tests/components/pcf8574/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 16 + sda: 17 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcf8574/test.esp32.yaml b/tests/components/pcf8574/test.esp32.yaml new file mode 100644 index 0000000000..aeed55f4fe --- /dev/null +++ b/tests/components/pcf8574/test.esp32.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 16 + sda: 17 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcf8574/test.esp8266.yaml b/tests/components/pcf8574/test.esp8266.yaml new file mode 100644 index 0000000000..551e425892 --- /dev/null +++ b/tests/components/pcf8574/test.esp8266.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pcf8574/test.rp2040.yaml b/tests/components/pcf8574/test.rp2040.yaml new file mode 100644 index 0000000000..551e425892 --- /dev/null +++ b/tests/components/pcf8574/test.rp2040.yaml @@ -0,0 +1,28 @@ +i2c: + - id: i2c_pcf8563 + scl: 5 + sda: 4 + +pcf8574: + - id: pcf8574_hub + address: 0x21 + pcf8575: false + +binary_sensor: + - platform: gpio + id: pcf8574_binary_sensor + name: PCF Binary Sensor + pin: + pcf8574: pcf8574_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: pcf8574_output + pin: + pcf8574: pcf8574_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/pid/test.esp32-c3-idf.yaml b/tests/components/pid/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.esp32-c3-idf.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.esp32-c3.yaml b/tests/components/pid/test.esp32-c3.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.esp32-c3.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.esp32-idf.yaml b/tests/components/pid/test.esp32-idf.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.esp32-idf.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.esp32.yaml b/tests/components/pid/test.esp32.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.esp32.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.esp8266.yaml b/tests/components/pid/test.esp8266.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.esp8266.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.rp2040.yaml b/tests/components/pid/test.rp2040.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/test.rp2040.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pipsolar/test.esp32-c3-idf.yaml b/tests/components/pipsolar/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..12e9266343 --- /dev/null +++ b/tests/components/pipsolar/test.esp32-c3-idf.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pipsolar/test.esp32-c3.yaml b/tests/components/pipsolar/test.esp32-c3.yaml new file mode 100644 index 0000000000..12e9266343 --- /dev/null +++ b/tests/components/pipsolar/test.esp32-c3.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pipsolar/test.esp32-idf.yaml b/tests/components/pipsolar/test.esp32-idf.yaml new file mode 100644 index 0000000000..fcd4575739 --- /dev/null +++ b/tests/components/pipsolar/test.esp32-idf.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pipsolar/test.esp32.yaml b/tests/components/pipsolar/test.esp32.yaml new file mode 100644 index 0000000000..fcd4575739 --- /dev/null +++ b/tests/components/pipsolar/test.esp32.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pipsolar/test.esp8266.yaml b/tests/components/pipsolar/test.esp8266.yaml new file mode 100644 index 0000000000..12e9266343 --- /dev/null +++ b/tests/components/pipsolar/test.esp8266.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pipsolar/test.rp2040.yaml b/tests/components/pipsolar/test.rp2040.yaml new file mode 100644 index 0000000000..12e9266343 --- /dev/null +++ b/tests/components/pipsolar/test.rp2040.yaml @@ -0,0 +1,247 @@ +esphome: + on_boot: + then: + - output.pipsolar.set_level: + id: inverter0_battery_recharge_voltage_out + value: 48.0 + +uart: + - id: uart_pipsolar + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pipsolar: + id: inverter0 + +binary_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + add_sbu_priority_version: + id: inverter0_add_sbu_priority_version + name: inverter0_add_sbu_priority_version + configuration_status: + id: inverter0_configuration_status + name: inverter0_configuration_status + scc_firmware_version: + id: inverter0_scc_firmware_version + name: inverter0_scc_firmware_version + load_status: + id: inverter0_load_status + name: inverter0_load_status + battery_voltage_to_steady_while_charging: + id: inverter0_battery_voltage_to_steady_while_charging + name: inverter0_battery_voltage_to_steady_while_charging + charging_status: + id: inverter0_charging_status + name: inverter0_charging_status + scc_charging_status: + id: inverter0_scc_charging_status + name: inverter0_scc_charging_status + ac_charging_status: + id: inverter0_ac_charging_status + name: inverter0_ac_charging_status + charging_to_floating_mode: + id: inverter0_charging_to_floating_mode + name: inverter0_charging_to_floating_mode + switch_on: + id: inverter0_switch_on + name: inverter0_switch_on + dustproof_installed: + id: inverter0_dustproof_installed + name: inverter0_dustproof_installed + silence_buzzer_open_buzzer: + id: inverter0_silence_buzzer_open_buzzer + name: inverter0_silence_buzzer_open_buzzer + overload_bypass_function: + id: inverter0_overload_bypass_function + name: inverter0_overload_bypass_function + lcd_escape_to_default: + id: inverter0_lcd_escape_to_default + name: inverter0_lcd_escape_to_default + overload_restart_function: + id: inverter0_overload_restart_function + name: inverter0_overload_restart_function + over_temperature_restart_function: + id: inverter0_over_temperature_restart_function + name: inverter0_over_temperature_restart_function + backlight_on: + id: inverter0_backlight_on + name: inverter0_backlight_on + +output: + - platform: pipsolar + pipsolar_id: inverter0 + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage_out + +sensor: + - platform: pipsolar + pipsolar_id: inverter0 + grid_rating_voltage: + id: inverter0_grid_rating_voltage + name: inverter0_grid_rating_voltage + grid_rating_current: + id: inverter0_grid_rating_current + name: inverter0_grid_rating_current + ac_output_rating_voltage: + id: inverter0_ac_output_rating_voltage + name: inverter0_ac_output_rating_voltage + ac_output_rating_frequency: + id: inverter0_ac_output_rating_frequency + name: inverter0_ac_output_rating_frequency + ac_output_rating_current: + id: inverter0_ac_output_rating_current + name: inverter0_ac_output_rating_current + ac_output_rating_apparent_power: + id: inverter0_ac_output_rating_apparent_power + name: inverter0_ac_output_rating_apparent_power + ac_output_rating_active_power: + id: inverter0_ac_output_rating_active_power + name: inverter0_ac_output_rating_active_power + battery_rating_voltage: + id: inverter0_battery_rating_voltage + name: inverter0_battery_rating_voltage + battery_recharge_voltage: + id: inverter0_battery_recharge_voltage + name: inverter0_battery_recharge_voltage + battery_under_voltage: + id: inverter0_battery_under_voltage + name: inverter0_battery_under_voltage + battery_bulk_voltage: + id: inverter0_battery_bulk_voltage + name: inverter0_battery_bulk_voltage + battery_float_voltage: + id: inverter0_battery_float_voltage + name: inverter0_battery_float_voltage + battery_type: + id: inverter0_battery_type + name: inverter0_battery_type + current_max_ac_charging_current: + id: inverter0_current_max_ac_charging_current + name: inverter0_current_max_ac_charging_current + current_max_charging_current: + id: inverter0_current_max_charging_current + name: inverter0_current_max_charging_current + input_voltage_range: + id: inverter0_input_voltage_range + name: inverter0_input_voltage_range + output_source_priority: + id: inverter0_output_source_priority + name: inverter0_output_source_priority + charger_source_priority: + id: inverter0_charger_source_priority + name: inverter0_charger_source_priority + parallel_max_num: + id: inverter0_parallel_max_num + name: inverter0_parallel_max_num + machine_type: + id: inverter0_machine_type + name: inverter0_machine_type + topology: + id: inverter0_topology + name: inverter0_topology + output_mode: + id: inverter0_output_mode + name: inverter0_output_mode + battery_redischarge_voltage: + id: inverter0_battery_redischarge_voltage + name: inverter0_battery_redischarge_voltage + pv_ok_condition_for_parallel: + id: inverter0_pv_ok_condition_for_parallel + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + id: inverter0_pv_power_balance + name: inverter0_pv_power_balance + grid_voltage: + id: inverter0_grid_voltage + name: inverter0_grid_voltage + grid_frequency: + id: inverter0_grid_frequency + name: inverter0_grid_frequency + ac_output_voltage: + id: inverter0_ac_output_voltage + name: inverter0_ac_output_voltage + ac_output_frequency: + id: inverter0_ac_output_frequency + name: inverter0_ac_output_frequency + ac_output_apparent_power: + id: inverter0_ac_output_apparent_power + name: inverter0_ac_output_apparent_power + ac_output_active_power: + id: inverter0_ac_output_active_power + name: inverter0_ac_output_active_power + output_load_percent: + id: inverter0_output_load_percent + name: inverter0_output_load_percent + bus_voltage: + id: inverter0_bus_voltage + name: inverter0_bus_voltage + battery_voltage: + id: inverter0_battery_voltage + name: inverter0_battery_voltage + battery_charging_current: + id: inverter0_battery_charging_current + name: inverter0_battery_charging_current + battery_capacity_percent: + id: inverter0_battery_capacity_percent + name: inverter0_battery_capacity_percent + inverter_heat_sink_temperature: + id: inverter0_inverter_heat_sink_temperature + name: inverter0_inverter_heat_sink_temperature + pv_input_current_for_battery: + id: inverter0_pv_input_current_for_battery + name: inverter0_pv_input_current_for_battery + pv_input_voltage: + id: inverter0_pv_input_voltage + name: inverter0_pv_input_voltage + battery_voltage_scc: + id: inverter0_battery_voltage_scc + name: inverter0_battery_voltage_scc + battery_discharge_current: + id: inverter0_battery_discharge_current + name: inverter0_battery_discharge_current + battery_voltage_offset_for_fans_on: + id: inverter0_battery_voltage_offset_for_fans_on + name: inverter0_battery_voltage_offset_for_fans_on + eeprom_version: + id: inverter0_eeprom_version + name: inverter0_eeprom_version + pv_charging_power: + id: inverter0_pv_charging_power + name: inverter0_pv_charging_power + +switch: + - platform: pipsolar + pipsolar_id: inverter0 + output_source_priority_utility: + name: inverter0_output_source_priority_utility + output_source_priority_solar: + name: inverter0_output_source_priority_solar + output_source_priority_battery: + name: inverter0_output_source_priority_battery + input_voltage_range: + name: inverter0_input_voltage_range + pv_ok_condition_for_parallel: + name: inverter0_pv_ok_condition_for_parallel + pv_power_balance: + name: inverter0_pv_power_balance + +text_sensor: + - platform: pipsolar + pipsolar_id: inverter0 + device_mode: + id: inverter0_device_mode + name: inverter0_device_mode + last_qpigs: + id: inverter0_last_qpigs + name: inverter0_last_qpigs + last_qpiri: + id: inverter0_last_qpiri + name: inverter0_last_qpiri + last_qmod: + id: inverter0_last_qmod + name: inverter0_last_qmod + last_qflag: + id: inverter0_last_qflag + name: inverter0_last_qflag diff --git a/tests/components/pm1006/test.esp32-c3-idf.yaml b/tests/components/pm1006/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..15ee077f3e --- /dev/null +++ b/tests/components/pm1006/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pm1006/test.esp32-c3.yaml b/tests/components/pm1006/test.esp32-c3.yaml new file mode 100644 index 0000000000..15ee077f3e --- /dev/null +++ b/tests/components/pm1006/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pm1006/test.esp32-idf.yaml b/tests/components/pm1006/test.esp32-idf.yaml new file mode 100644 index 0000000000..635af37b25 --- /dev/null +++ b/tests/components/pm1006/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pm1006/test.esp32.yaml b/tests/components/pm1006/test.esp32.yaml new file mode 100644 index 0000000000..635af37b25 --- /dev/null +++ b/tests/components/pm1006/test.esp32.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pm1006/test.esp8266.yaml b/tests/components/pm1006/test.esp8266.yaml new file mode 100644 index 0000000000..15ee077f3e --- /dev/null +++ b/tests/components/pm1006/test.esp8266.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pm1006/test.rp2040.yaml b/tests/components/pm1006/test.rp2040.yaml new file mode 100644 index 0000000000..15ee077f3e --- /dev/null +++ b/tests/components/pm1006/test.rp2040.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_pm1006 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pm1006 + pm_2_5: + name: Particulate Matter 2.5µm Concentration diff --git a/tests/components/pmsa003i/test.esp32-c3-idf.yaml b/tests/components/pmsa003i/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..70e28303a2 --- /dev/null +++ b/tests/components/pmsa003i/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 5 + sda: 4 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsa003i/test.esp32-c3.yaml b/tests/components/pmsa003i/test.esp32-c3.yaml new file mode 100644 index 0000000000..70e28303a2 --- /dev/null +++ b/tests/components/pmsa003i/test.esp32-c3.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 5 + sda: 4 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsa003i/test.esp32-idf.yaml b/tests/components/pmsa003i/test.esp32-idf.yaml new file mode 100644 index 0000000000..d8d96400f6 --- /dev/null +++ b/tests/components/pmsa003i/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 16 + sda: 17 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsa003i/test.esp32.yaml b/tests/components/pmsa003i/test.esp32.yaml new file mode 100644 index 0000000000..d8d96400f6 --- /dev/null +++ b/tests/components/pmsa003i/test.esp32.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 16 + sda: 17 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsa003i/test.esp8266.yaml b/tests/components/pmsa003i/test.esp8266.yaml new file mode 100644 index 0000000000..70e28303a2 --- /dev/null +++ b/tests/components/pmsa003i/test.esp8266.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 5 + sda: 4 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsa003i/test.rp2040.yaml b/tests/components/pmsa003i/test.rp2040.yaml new file mode 100644 index 0000000000..70e28303a2 --- /dev/null +++ b/tests/components/pmsa003i/test.rp2040.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_pmsa003i + scl: 5 + sda: 4 + +sensor: + - platform: pmsa003i + pm_1_0: + name: PMSA003i PM1.0 + pm_2_5: + name: PMSA003i PM2.5 + pm_10_0: + name: PMSA003i PM10.0 + pmc_0_3: + name: PMSA003i PMC <0.3µm + pmc_0_5: + name: PMSA003i PMC <0.5µm + pmc_1_0: + name: PMSA003i PMC <1µm + pmc_2_5: + name: PMSA003i PMC <2.5µm + pmc_5_0: + name: PMSA003i PMC <5µm + pmc_10_0: + name: PMSA003i PMC <10µm + address: 0x12 + standard_units: true diff --git a/tests/components/pmsx003/test.esp32-c3-idf.yaml b/tests/components/pmsx003/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..58adc9390a --- /dev/null +++ b/tests/components/pmsx003/test.esp32-c3-idf.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmsx003/test.esp32-c3.yaml b/tests/components/pmsx003/test.esp32-c3.yaml new file mode 100644 index 0000000000..58adc9390a --- /dev/null +++ b/tests/components/pmsx003/test.esp32-c3.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmsx003/test.esp32-idf.yaml b/tests/components/pmsx003/test.esp32-idf.yaml new file mode 100644 index 0000000000..5e7ebbbb2e --- /dev/null +++ b/tests/components/pmsx003/test.esp32-idf.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmsx003/test.esp32.yaml b/tests/components/pmsx003/test.esp32.yaml new file mode 100644 index 0000000000..5e7ebbbb2e --- /dev/null +++ b/tests/components/pmsx003/test.esp32.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmsx003/test.esp8266.yaml b/tests/components/pmsx003/test.esp8266.yaml new file mode 100644 index 0000000000..58adc9390a --- /dev/null +++ b/tests/components/pmsx003/test.esp8266.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmsx003/test.rp2040.yaml b/tests/components/pmsx003/test.rp2040.yaml new file mode 100644 index 0000000000..58adc9390a --- /dev/null +++ b/tests/components/pmsx003/test.rp2040.yaml @@ -0,0 +1,34 @@ +uart: + - id: uart_pmsx003 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: pmsx003 + type: PMSX003 + pm_1_0: + name: PM 1.0 Concentration + pm_2_5: + name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um + pm_5_0um: + name: Particulate Count >5.0um + pm_10_0um: + name: Particulate Count >10.0um + update_interval: 30s diff --git a/tests/components/pmwcs3/test.esp32-c3-idf.yaml b/tests/components/pmwcs3/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7e7e72692d --- /dev/null +++ b/tests/components/pmwcs3/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 5 + sda: 4 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pmwcs3/test.esp32-c3.yaml b/tests/components/pmwcs3/test.esp32-c3.yaml new file mode 100644 index 0000000000..7e7e72692d --- /dev/null +++ b/tests/components/pmwcs3/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 5 + sda: 4 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pmwcs3/test.esp32-idf.yaml b/tests/components/pmwcs3/test.esp32-idf.yaml new file mode 100644 index 0000000000..787eaca650 --- /dev/null +++ b/tests/components/pmwcs3/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 16 + sda: 17 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pmwcs3/test.esp32.yaml b/tests/components/pmwcs3/test.esp32.yaml new file mode 100644 index 0000000000..787eaca650 --- /dev/null +++ b/tests/components/pmwcs3/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 16 + sda: 17 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pmwcs3/test.esp8266.yaml b/tests/components/pmwcs3/test.esp8266.yaml new file mode 100644 index 0000000000..7e7e72692d --- /dev/null +++ b/tests/components/pmwcs3/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 5 + sda: 4 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pmwcs3/test.rp2040.yaml b/tests/components/pmwcs3/test.rp2040.yaml new file mode 100644 index 0000000000..7e7e72692d --- /dev/null +++ b/tests/components/pmwcs3/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_pmwcs3 + scl: 5 + sda: 4 + +sensor: + - platform: pmwcs3 + e25: + name: pmwcs3_e25 + ec: + name: pmwcs3_ec + temperature: + name: pmwcs3_temperature + vwc: + name: pmwcs3_vwc diff --git a/tests/components/pn532_i2c/test.esp32-c3-idf.yaml b/tests/components/pn532_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..62816d2ace --- /dev/null +++ b/tests/components/pn532_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 5 + sda: 4 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_i2c/test.esp32-c3.yaml b/tests/components/pn532_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..62816d2ace --- /dev/null +++ b/tests/components/pn532_i2c/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 5 + sda: 4 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_i2c/test.esp32-idf.yaml b/tests/components/pn532_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..a50533b1d0 --- /dev/null +++ b/tests/components/pn532_i2c/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 16 + sda: 17 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_i2c/test.esp32.yaml b/tests/components/pn532_i2c/test.esp32.yaml new file mode 100644 index 0000000000..a50533b1d0 --- /dev/null +++ b/tests/components/pn532_i2c/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 16 + sda: 17 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_i2c/test.esp8266.yaml b/tests/components/pn532_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..62816d2ace --- /dev/null +++ b/tests/components/pn532_i2c/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 5 + sda: 4 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_i2c/test.rp2040.yaml b/tests/components/pn532_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..62816d2ace --- /dev/null +++ b/tests/components/pn532_i2c/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_pn532 + scl: 5 + sda: 4 + +pn532_i2c: + id: pn532_nfcc + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.esp32-c3-idf.yaml b/tests/components/pn532_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d21d50aa5c --- /dev/null +++ b/tests/components/pn532_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +pn532_spi: + id: pn532_nfcc + cs_pin: 4 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.esp32-c3.yaml b/tests/components/pn532_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..d21d50aa5c --- /dev/null +++ b/tests/components/pn532_spi/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +pn532_spi: + id: pn532_nfcc + cs_pin: 4 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.esp32-idf.yaml b/tests/components/pn532_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..18a382a007 --- /dev/null +++ b/tests/components/pn532_spi/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +pn532_spi: + id: pn532_nfcc + cs_pin: 12 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.esp32.yaml b/tests/components/pn532_spi/test.esp32.yaml new file mode 100644 index 0000000000..18a382a007 --- /dev/null +++ b/tests/components/pn532_spi/test.esp32.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +pn532_spi: + id: pn532_nfcc + cs_pin: 12 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.esp8266.yaml b/tests/components/pn532_spi/test.esp8266.yaml new file mode 100644 index 0000000000..1dba38e63e --- /dev/null +++ b/tests/components/pn532_spi/test.esp8266.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +pn532_spi: + id: pn532_nfcc + cs_pin: 15 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn532_spi/test.rp2040.yaml b/tests/components/pn532_spi/test.rp2040.yaml new file mode 100644 index 0000000000..ab02b2cc47 --- /dev/null +++ b/tests/components/pn532_spi/test.rp2040.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_pn532 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +pn532_spi: + id: pn532_nfcc + cs_pin: 6 + +binary_sensor: + - platform: pn532 + pn532_id: pn532_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/pn7150_i2c/test.esp32-c3-idf.yaml b/tests/components/pn7150_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..aee1886cd4 --- /dev/null +++ b/tests/components/pn7150_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7150_i2c/test.esp32-c3.yaml b/tests/components/pn7150_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..aee1886cd4 --- /dev/null +++ b/tests/components/pn7150_i2c/test.esp32-c3.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7150_i2c/test.esp32-idf.yaml b/tests/components/pn7150_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..23d1061608 --- /dev/null +++ b/tests/components/pn7150_i2c/test.esp32-idf.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 16 + sda: 17 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7150_i2c/test.esp32.yaml b/tests/components/pn7150_i2c/test.esp32.yaml new file mode 100644 index 0000000000..23d1061608 --- /dev/null +++ b/tests/components/pn7150_i2c/test.esp32.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 16 + sda: 17 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7150_i2c/test.esp8266.yaml b/tests/components/pn7150_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..6017d548ca --- /dev/null +++ b/tests/components/pn7150_i2c/test.esp8266.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7150_i2c/test.rp2040.yaml b/tests/components/pn7150_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..aee1886cd4 --- /dev/null +++ b/tests/components/pn7150_i2c/test.rp2040.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7150 + - tag.set_format_mode: nfcc_pn7150 + - tag.set_read_mode: nfcc_pn7150 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7150 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7150 + - tag.emulation_on: nfcc_pn7150 + - tag.polling_off: nfcc_pn7150 + - tag.polling_on: nfcc_pn7150 + +i2c: + - id: i2c_pn7150 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7150 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.esp32-c3-idf.yaml b/tests/components/pn7160_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d1d7947352 --- /dev/null +++ b/tests/components/pn7160_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 5 + sda: 4 + +pn7160_i2c: + id: nfcc_pn7160 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.esp32-c3.yaml b/tests/components/pn7160_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..d1d7947352 --- /dev/null +++ b/tests/components/pn7160_i2c/test.esp32-c3.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 5 + sda: 4 + +pn7160_i2c: + id: nfcc_pn7160 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.esp32-idf.yaml b/tests/components/pn7160_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..d1a3cf5c77 --- /dev/null +++ b/tests/components/pn7160_i2c/test.esp32-idf.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 16 + sda: 17 + +pn7150_i2c: + id: nfcc_pn7160 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.esp32.yaml b/tests/components/pn7160_i2c/test.esp32.yaml new file mode 100644 index 0000000000..d1a3cf5c77 --- /dev/null +++ b/tests/components/pn7160_i2c/test.esp32.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 16 + sda: 17 + +pn7150_i2c: + id: nfcc_pn7160 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.esp8266.yaml b/tests/components/pn7160_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..57bd965fc9 --- /dev/null +++ b/tests/components/pn7160_i2c/test.esp8266.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7160 + irq_pin: 12 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_i2c/test.rp2040.yaml b/tests/components/pn7160_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..5224b465ed --- /dev/null +++ b/tests/components/pn7160_i2c/test.rp2040.yaml @@ -0,0 +1,35 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +i2c: + - id: i2c_pn7160 + scl: 5 + sda: 4 + +pn7150_i2c: + id: nfcc_pn7160 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.esp32-c3-idf.yaml b/tests/components/pn7160_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fd19a53b2b --- /dev/null +++ b/tests/components/pn7160_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 4 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.esp32-c3.yaml b/tests/components/pn7160_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..fd19a53b2b --- /dev/null +++ b/tests/components/pn7160_spi/test.esp32-c3.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 4 + irq_pin: 2 + ven_pin: 3 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.esp32-idf.yaml b/tests/components/pn7160_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..0319648f13 --- /dev/null +++ b/tests/components/pn7160_spi/test.esp32-idf.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 12 + irq_pin: 14 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.esp32.yaml b/tests/components/pn7160_spi/test.esp32.yaml new file mode 100644 index 0000000000..0319648f13 --- /dev/null +++ b/tests/components/pn7160_spi/test.esp32.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 12 + irq_pin: 14 + ven_pin: 13 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.esp8266.yaml b/tests/components/pn7160_spi/test.esp8266.yaml new file mode 100644 index 0000000000..fa356d5610 --- /dev/null +++ b/tests/components/pn7160_spi/test.esp8266.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 15 + irq_pin: 4 + ven_pin: 5 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/pn7160_spi/test.rp2040.yaml b/tests/components/pn7160_spi/test.rp2040.yaml new file mode 100644 index 0000000000..b36650032f --- /dev/null +++ b/tests/components/pn7160_spi/test.rp2040.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - tag.set_clean_mode: nfcc_pn7160 + - tag.set_format_mode: nfcc_pn7160 + - tag.set_read_mode: nfcc_pn7160 + - tag.set_write_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.set_write_mode: nfcc_pn7160 + - tag.set_emulation_message: + message: https://www.home-assistant.io/tag/pulse + include_android_app_record: false + - tag.emulation_off: nfcc_pn7160 + - tag.emulation_on: nfcc_pn7160 + - tag.polling_off: nfcc_pn7160 + - tag.polling_on: nfcc_pn7160 + +spi: + - id: spi_pn7160 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +pn7160_spi: + id: nfcc_pn7160 + cs_pin: 6 + irq_pin: 7 + ven_pin: 5 + emulation_message: https://www.home-assistant.io/tag/pulse_ce + tag_ttl: 1000ms + on_tag: + - logger.log: "Tag" + on_tag_removed: + - logger.log: "Tag removed" + on_emulated_tag_scan: + - logger.log: "Tag emulated" diff --git a/tests/components/power_supply/test.esp32-c3-idf.yaml b/tests/components/power_supply/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.esp32-c3.yaml b/tests/components/power_supply/test.esp32-c3.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.esp32-idf.yaml b/tests/components/power_supply/test.esp32-idf.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.esp32.yaml b/tests/components/power_supply/test.esp32.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.esp32.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.esp8266.yaml b/tests/components/power_supply/test.esp8266.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.esp8266.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.rp2040.yaml b/tests/components/power_supply/test.rp2040.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/test.rp2040.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/prometheus/test.esp32-c3-idf.yaml b/tests/components/prometheus/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/test.esp32-c3-idf.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/prometheus/test.esp32-c3.yaml b/tests/components/prometheus/test.esp32-c3.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/prometheus/test.esp32-idf.yaml b/tests/components/prometheus/test.esp32-idf.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/test.esp32-idf.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/prometheus/test.esp32.yaml b/tests/components/prometheus/test.esp32.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/test.esp32.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/prometheus/test.esp8266.yaml b/tests/components/prometheus/test.esp8266.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/test.esp8266.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/psram/test.esp32-c3-idf.yaml b/tests/components/psram/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..cfd39f77fe --- /dev/null +++ b/tests/components/psram/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +psram: + mode: octal + speed: 80MHz diff --git a/tests/components/psram/test.esp32-c3.yaml b/tests/components/psram/test.esp32-c3.yaml new file mode 100644 index 0000000000..cfd39f77fe --- /dev/null +++ b/tests/components/psram/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +psram: + mode: octal + speed: 80MHz diff --git a/tests/components/psram/test.esp32-idf.yaml b/tests/components/psram/test.esp32-idf.yaml new file mode 100644 index 0000000000..cfd39f77fe --- /dev/null +++ b/tests/components/psram/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +psram: + mode: octal + speed: 80MHz diff --git a/tests/components/psram/test.esp32.yaml b/tests/components/psram/test.esp32.yaml new file mode 100644 index 0000000000..cfd39f77fe --- /dev/null +++ b/tests/components/psram/test.esp32.yaml @@ -0,0 +1,3 @@ +psram: + mode: octal + speed: 80MHz diff --git a/tests/components/pulse_counter/test.esp32-c3-idf.yaml b/tests/components/pulse_counter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.esp32-c3.yaml b/tests/components/pulse_counter/test.esp32-c3.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.esp32-idf.yaml b/tests/components/pulse_counter/test.esp32-idf.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.esp32.yaml b/tests/components/pulse_counter/test.esp32.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.esp32.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.esp8266.yaml b/tests/components/pulse_counter/test.esp8266.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.esp8266.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.rp2040.yaml b/tests/components/pulse_counter/test.rp2040.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/test.rp2040.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_meter/test.esp32-c3-idf.yaml b/tests/components/pulse_meter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.esp32-c3.yaml b/tests/components/pulse_meter/test.esp32-c3.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.esp32-idf.yaml b/tests/components/pulse_meter/test.esp32-idf.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.esp32.yaml b/tests/components/pulse_meter/test.esp32.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.esp32.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.esp8266.yaml b/tests/components/pulse_meter/test.esp8266.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.esp8266.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.rp2040.yaml b/tests/components/pulse_meter/test.rp2040.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/test.rp2040.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_width/test.esp32-c3-idf.yaml b/tests/components/pulse_width/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.esp32-c3.yaml b/tests/components/pulse_width/test.esp32-c3.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.esp32-c3.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.esp32-idf.yaml b/tests/components/pulse_width/test.esp32-idf.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.esp32.yaml b/tests/components/pulse_width/test.esp32.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.esp32.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.esp8266.yaml b/tests/components/pulse_width/test.esp8266.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.esp8266.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.rp2040.yaml b/tests/components/pulse_width/test.rp2040.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/test.rp2040.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml b/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..972f23122c --- /dev/null +++ b/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml @@ -0,0 +1,44 @@ +wifi: + ssid: MySSID + password: password1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: pvvx_ble_display + +display: + - platform: pvvx_mithermometer + ble_client_id: pvvx_ble_display + time_id: sntp_time + disconnect_delay: 3s + update_interval: 10min + validity_period: 20min + lambda: |- + it.print_bignum(188.8); + it.print_unit(pvvx_mithermometer::UNIT_DEG_E); + it.print_smallnum(88); + it.print_percent(true); + it.print_happy(true); + it.print_sad(true); + it.print_bracket(true); + it.print_battery(true); + +sensor: + - platform: pvvx_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: PVVX Temperature + humidity: + name: PVVX Humidity + battery_level: + name: PVVX Battery-Level + battery_voltage: + name: PVVX Battery-Voltage + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org diff --git a/tests/components/pvvx_mithermometer/test.esp32-c3.yaml b/tests/components/pvvx_mithermometer/test.esp32-c3.yaml new file mode 100644 index 0000000000..972f23122c --- /dev/null +++ b/tests/components/pvvx_mithermometer/test.esp32-c3.yaml @@ -0,0 +1,44 @@ +wifi: + ssid: MySSID + password: password1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: pvvx_ble_display + +display: + - platform: pvvx_mithermometer + ble_client_id: pvvx_ble_display + time_id: sntp_time + disconnect_delay: 3s + update_interval: 10min + validity_period: 20min + lambda: |- + it.print_bignum(188.8); + it.print_unit(pvvx_mithermometer::UNIT_DEG_E); + it.print_smallnum(88); + it.print_percent(true); + it.print_happy(true); + it.print_sad(true); + it.print_bracket(true); + it.print_battery(true); + +sensor: + - platform: pvvx_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: PVVX Temperature + humidity: + name: PVVX Humidity + battery_level: + name: PVVX Battery-Level + battery_voltage: + name: PVVX Battery-Voltage + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org diff --git a/tests/components/pvvx_mithermometer/test.esp32-idf.yaml b/tests/components/pvvx_mithermometer/test.esp32-idf.yaml new file mode 100644 index 0000000000..972f23122c --- /dev/null +++ b/tests/components/pvvx_mithermometer/test.esp32-idf.yaml @@ -0,0 +1,44 @@ +wifi: + ssid: MySSID + password: password1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: pvvx_ble_display + +display: + - platform: pvvx_mithermometer + ble_client_id: pvvx_ble_display + time_id: sntp_time + disconnect_delay: 3s + update_interval: 10min + validity_period: 20min + lambda: |- + it.print_bignum(188.8); + it.print_unit(pvvx_mithermometer::UNIT_DEG_E); + it.print_smallnum(88); + it.print_percent(true); + it.print_happy(true); + it.print_sad(true); + it.print_bracket(true); + it.print_battery(true); + +sensor: + - platform: pvvx_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: PVVX Temperature + humidity: + name: PVVX Humidity + battery_level: + name: PVVX Battery-Level + battery_voltage: + name: PVVX Battery-Voltage + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org diff --git a/tests/components/pvvx_mithermometer/test.esp32.yaml b/tests/components/pvvx_mithermometer/test.esp32.yaml new file mode 100644 index 0000000000..972f23122c --- /dev/null +++ b/tests/components/pvvx_mithermometer/test.esp32.yaml @@ -0,0 +1,44 @@ +wifi: + ssid: MySSID + password: password1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: pvvx_ble_display + +display: + - platform: pvvx_mithermometer + ble_client_id: pvvx_ble_display + time_id: sntp_time + disconnect_delay: 3s + update_interval: 10min + validity_period: 20min + lambda: |- + it.print_bignum(188.8); + it.print_unit(pvvx_mithermometer::UNIT_DEG_E); + it.print_smallnum(88); + it.print_percent(true); + it.print_happy(true); + it.print_sad(true); + it.print_bracket(true); + it.print_battery(true); + +sensor: + - platform: pvvx_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: PVVX Temperature + humidity: + name: PVVX Humidity + battery_level: + name: PVVX Battery-Level + battery_voltage: + name: PVVX Battery-Voltage + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org diff --git a/tests/components/pylontech/test.esp32-c3-idf.yaml b/tests/components/pylontech/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f7ec493422 --- /dev/null +++ b/tests/components/pylontech/test.esp32-c3-idf.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pylontech/test.esp32-c3.yaml b/tests/components/pylontech/test.esp32-c3.yaml new file mode 100644 index 0000000000..f7ec493422 --- /dev/null +++ b/tests/components/pylontech/test.esp32-c3.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pylontech/test.esp32-idf.yaml b/tests/components/pylontech/test.esp32-idf.yaml new file mode 100644 index 0000000000..a4c168fb47 --- /dev/null +++ b/tests/components/pylontech/test.esp32-idf.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pylontech/test.esp32.yaml b/tests/components/pylontech/test.esp32.yaml new file mode 100644 index 0000000000..a4c168fb47 --- /dev/null +++ b/tests/components/pylontech/test.esp32.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pylontech/test.esp8266.yaml b/tests/components/pylontech/test.esp8266.yaml new file mode 100644 index 0000000000..f7ec493422 --- /dev/null +++ b/tests/components/pylontech/test.esp8266.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pylontech/test.rp2040.yaml b/tests/components/pylontech/test.rp2040.yaml new file mode 100644 index 0000000000..f7ec493422 --- /dev/null +++ b/tests/components/pylontech/test.rp2040.yaml @@ -0,0 +1,48 @@ +uart: + - id: uart_pylontech0 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +pylontech: + - id: pylontech0 + - id: pylontech1 + +sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + voltage: + id: pyl01_voltage + current: + id: pyl01_current + coulomb: + id: pyl01_soc + mos_temperature: + id: pyl01_mos_temperature + - platform: pylontech + pylontech_id: pylontech1 + battery: 1 + voltage: + id: pyl13_voltage + temperature_low: + id: pyl13_temperature_low + temperature_high: + id: pyl13_temperature_high + voltage_low: + id: pyl13_voltage_low + voltage_high: + id: pyl13_voltage_high + +text_sensor: + - platform: pylontech + pylontech_id: pylontech0 + battery: 1 + base_state: + id: pyl0_base_state + voltage_state: + id: pyl0_voltage_state + current_state: + id: pyl0_current_state + temperature_state: + id: pyl0_temperature_state diff --git a/tests/components/pzem004t/test.esp32-c3-idf.yaml b/tests/components/pzem004t/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b9c93f8761 --- /dev/null +++ b/tests/components/pzem004t/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzem004t/test.esp32-c3.yaml b/tests/components/pzem004t/test.esp32-c3.yaml new file mode 100644 index 0000000000..b9c93f8761 --- /dev/null +++ b/tests/components/pzem004t/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzem004t/test.esp32-idf.yaml b/tests/components/pzem004t/test.esp32-idf.yaml new file mode 100644 index 0000000000..23f2bd0eca --- /dev/null +++ b/tests/components/pzem004t/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzem004t/test.esp32.yaml b/tests/components/pzem004t/test.esp32.yaml new file mode 100644 index 0000000000..23f2bd0eca --- /dev/null +++ b/tests/components/pzem004t/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzem004t/test.esp8266.yaml b/tests/components/pzem004t/test.esp8266.yaml new file mode 100644 index 0000000000..b9c93f8761 --- /dev/null +++ b/tests/components/pzem004t/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzem004t/test.rp2040.yaml b/tests/components/pzem004t/test.rp2040.yaml new file mode 100644 index 0000000000..b9c93f8761 --- /dev/null +++ b/tests/components/pzem004t/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_pzem004t + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: pzem004t + voltage: + name: PZEM004T Voltage + current: + name: PZEM004T Current + power: + name: PZEM004T Power diff --git a/tests/components/pzemac/test.esp32-c3-idf.yaml b/tests/components/pzemac/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..6d9abbebe9 --- /dev/null +++ b/tests/components/pzemac/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemac/test.esp32-c3.yaml b/tests/components/pzemac/test.esp32-c3.yaml new file mode 100644 index 0000000000..6d9abbebe9 --- /dev/null +++ b/tests/components/pzemac/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemac/test.esp32-idf.yaml b/tests/components/pzemac/test.esp32-idf.yaml new file mode 100644 index 0000000000..ce431a6100 --- /dev/null +++ b/tests/components/pzemac/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemac/test.esp32.yaml b/tests/components/pzemac/test.esp32.yaml new file mode 100644 index 0000000000..ce431a6100 --- /dev/null +++ b/tests/components/pzemac/test.esp32.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemac/test.esp8266.yaml b/tests/components/pzemac/test.esp8266.yaml new file mode 100644 index 0000000000..6d9abbebe9 --- /dev/null +++ b/tests/components/pzemac/test.esp8266.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemac/test.rp2040.yaml b/tests/components/pzemac/test.rp2040.yaml new file mode 100644 index 0000000000..6d9abbebe9 --- /dev/null +++ b/tests/components/pzemac/test.rp2040.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - pzemac.reset_energy: pzemac1 + +uart: + - id: uart_pzemac + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + +sensor: + - platform: pzemac + id: pzemac1 + voltage: + name: PZEMAC Voltage + current: + name: PZEMAC Current + power: + name: PZEMAC Power + energy: + name: PZEMAC Energy + frequency: + name: PZEMAC Frequency + power_factor: + name: PZEMAC Power Factor diff --git a/tests/components/pzemdc/test.esp32-c3-idf.yaml b/tests/components/pzemdc/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..02114b781d --- /dev/null +++ b/tests/components/pzemdc/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy diff --git a/tests/components/pzemdc/test.esp32-c3.yaml b/tests/components/pzemdc/test.esp32-c3.yaml new file mode 100644 index 0000000000..02114b781d --- /dev/null +++ b/tests/components/pzemdc/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy diff --git a/tests/components/pzemdc/test.esp32-idf.yaml b/tests/components/pzemdc/test.esp32-idf.yaml new file mode 100644 index 0000000000..9cc61137de --- /dev/null +++ b/tests/components/pzemdc/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy diff --git a/tests/components/pzemdc/test.esp32.yaml b/tests/components/pzemdc/test.esp32.yaml new file mode 100644 index 0000000000..9cc61137de --- /dev/null +++ b/tests/components/pzemdc/test.esp32.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy diff --git a/tests/components/pzemdc/test.esp8266.yaml b/tests/components/pzemdc/test.esp8266.yaml new file mode 100644 index 0000000000..02114b781d --- /dev/null +++ b/tests/components/pzemdc/test.esp8266.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy diff --git a/tests/components/pzemdc/test.rp2040.yaml b/tests/components/pzemdc/test.rp2040.yaml new file mode 100644 index 0000000000..02114b781d --- /dev/null +++ b/tests/components/pzemdc/test.rp2040.yaml @@ -0,0 +1,23 @@ +esphome: + on_boot: + then: + - pzemdc.reset_energy: pzemdc1 + +uart: + - id: uart_pzemdc + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + stop_bits: 2 + +sensor: + - platform: pzemdc + id: pzemdc1 + voltage: + name: PZEMDC Voltage + current: + name: PZEMDC Current + power: + name: PZEMDC Power + energy: + name: PZEMDC Energy From 2b215fecc953496d62db17407ec04f85d27abe23 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 22:45:12 -0500 Subject: [PATCH 1601/2607] Add some components to the new testing framework (M part 1) (#6207) --- .../matrix_keypad/test.esp32-c3-idf.yaml | 19 ++++++++ .../matrix_keypad/test.esp32-c3.yaml | 19 ++++++++ .../matrix_keypad/test.esp32-idf.yaml | 19 ++++++++ .../components/matrix_keypad/test.esp32.yaml | 19 ++++++++ .../matrix_keypad/test.esp8266.yaml | 19 ++++++++ .../components/matrix_keypad/test.rp2040.yaml | 19 ++++++++ .../max31855/test.esp32-c3-idf.yaml | 13 ++++++ tests/components/max31855/test.esp32-c3.yaml | 13 ++++++ tests/components/max31855/test.esp32-idf.yaml | 13 ++++++ tests/components/max31855/test.esp32.yaml | 13 ++++++ tests/components/max31855/test.esp8266.yaml | 13 ++++++ tests/components/max31855/test.rp2040.yaml | 13 ++++++ .../max31856/test.esp32-c3-idf.yaml | 12 +++++ tests/components/max31856/test.esp32-c3.yaml | 12 +++++ tests/components/max31856/test.esp32-idf.yaml | 12 +++++ tests/components/max31856/test.esp32.yaml | 12 +++++ tests/components/max31856/test.esp8266.yaml | 12 +++++ tests/components/max31856/test.rp2040.yaml | 12 +++++ .../max31865/test.esp32-c3-idf.yaml | 13 ++++++ tests/components/max31865/test.esp32-c3.yaml | 13 ++++++ tests/components/max31865/test.esp32-idf.yaml | 13 ++++++ tests/components/max31865/test.esp32.yaml | 13 ++++++ tests/components/max31865/test.esp8266.yaml | 13 ++++++ tests/components/max31865/test.rp2040.yaml | 13 ++++++ .../max44009/test.esp32-c3-idf.yaml | 12 +++++ tests/components/max44009/test.esp32-c3.yaml | 12 +++++ tests/components/max44009/test.esp32-idf.yaml | 12 +++++ tests/components/max44009/test.esp32.yaml | 12 +++++ tests/components/max44009/test.esp8266.yaml | 12 +++++ tests/components/max44009/test.rp2040.yaml | 12 +++++ .../components/max6675/test.esp32-c3-idf.yaml | 11 +++++ tests/components/max6675/test.esp32-c3.yaml | 11 +++++ tests/components/max6675/test.esp32-idf.yaml | 11 +++++ tests/components/max6675/test.esp32.yaml | 11 +++++ tests/components/max6675/test.esp8266.yaml | 11 +++++ tests/components/max6675/test.rp2040.yaml | 11 +++++ .../components/max6956/test.esp32-c3-idf.yaml | 19 ++++++++ tests/components/max6956/test.esp32-c3.yaml | 19 ++++++++ tests/components/max6956/test.esp32-idf.yaml | 19 ++++++++ tests/components/max6956/test.esp32.yaml | 19 ++++++++ tests/components/max6956/test.esp8266.yaml | 19 ++++++++ tests/components/max6956/test.rp2040.yaml | 19 ++++++++ .../components/max7219/test.esp32-c3-idf.yaml | 12 +++++ tests/components/max7219/test.esp32-c3.yaml | 12 +++++ tests/components/max7219/test.esp32-idf.yaml | 12 +++++ tests/components/max7219/test.esp32.yaml | 12 +++++ tests/components/max7219/test.esp8266.yaml | 12 +++++ tests/components/max7219/test.rp2040.yaml | 12 +++++ .../max7219digit/test.esp32-c3-idf.yaml | 16 +++++++ .../max7219digit/test.esp32-c3.yaml | 16 +++++++ .../max7219digit/test.esp32-idf.yaml | 16 +++++++ tests/components/max7219digit/test.esp32.yaml | 16 +++++++ .../components/max7219digit/test.esp8266.yaml | 16 +++++++ .../components/max7219digit/test.rp2040.yaml | 16 +++++++ .../components/max9611/test.esp32-c3-idf.yaml | 18 ++++++++ tests/components/max9611/test.esp32-c3.yaml | 18 ++++++++ tests/components/max9611/test.esp32-idf.yaml | 18 ++++++++ tests/components/max9611/test.esp32.yaml | 18 ++++++++ tests/components/max9611/test.esp8266.yaml | 18 ++++++++ tests/components/max9611/test.rp2040.yaml | 18 ++++++++ .../mcp23008/test.esp32-c3-idf.yaml | 23 ++++++++++ tests/components/mcp23008/test.esp32-c3.yaml | 23 ++++++++++ tests/components/mcp23008/test.esp32-idf.yaml | 23 ++++++++++ tests/components/mcp23008/test.esp32.yaml | 23 ++++++++++ tests/components/mcp23008/test.esp8266.yaml | 23 ++++++++++ tests/components/mcp23008/test.rp2040.yaml | 23 ++++++++++ .../mcp23016/test.esp32-c3-idf.yaml | 23 ++++++++++ tests/components/mcp23016/test.esp32-c3.yaml | 23 ++++++++++ tests/components/mcp23016/test.esp32-idf.yaml | 23 ++++++++++ tests/components/mcp23016/test.esp32.yaml | 23 ++++++++++ tests/components/mcp23016/test.esp8266.yaml | 23 ++++++++++ tests/components/mcp23016/test.rp2040.yaml | 23 ++++++++++ .../mcp23017/test.esp32-c3-idf.yaml | 23 ++++++++++ tests/components/mcp23017/test.esp32-c3.yaml | 23 ++++++++++ tests/components/mcp23017/test.esp32-idf.yaml | 23 ++++++++++ tests/components/mcp23017/test.esp32.yaml | 23 ++++++++++ tests/components/mcp23017/test.esp8266.yaml | 23 ++++++++++ tests/components/mcp23017/test.rp2040.yaml | 23 ++++++++++ .../mcp23s08/test.esp32-c3-idf.yaml | 10 +++++ tests/components/mcp23s08/test.esp32-c3.yaml | 10 +++++ tests/components/mcp23s08/test.esp32-idf.yaml | 10 +++++ tests/components/mcp23s08/test.esp32.yaml | 10 +++++ tests/components/mcp23s08/test.esp8266.yaml | 10 +++++ tests/components/mcp23s08/test.rp2040.yaml | 10 +++++ .../mcp23s17/test.esp32-c3-idf.yaml | 10 +++++ tests/components/mcp23s17/test.esp32-c3.yaml | 10 +++++ tests/components/mcp23s17/test.esp32-idf.yaml | 10 +++++ tests/components/mcp23s17/test.esp32.yaml | 10 +++++ tests/components/mcp23s17/test.esp8266.yaml | 10 +++++ tests/components/mcp23s17/test.rp2040.yaml | 10 +++++ .../components/mcp2515/test.esp32-c3-idf.yaml | 44 +++++++++++++++++++ tests/components/mcp2515/test.esp32-c3.yaml | 44 +++++++++++++++++++ tests/components/mcp2515/test.esp32-idf.yaml | 44 +++++++++++++++++++ tests/components/mcp2515/test.esp32.yaml | 44 +++++++++++++++++++ tests/components/mcp2515/test.esp8266.yaml | 44 +++++++++++++++++++ tests/components/mcp2515/test.rp2040.yaml | 44 +++++++++++++++++++ .../components/mcp3008/test.esp32-c3-idf.yaml | 17 +++++++ tests/components/mcp3008/test.esp32-c3.yaml | 17 +++++++ tests/components/mcp3008/test.esp32-idf.yaml | 17 +++++++ tests/components/mcp3008/test.esp32.yaml | 17 +++++++ tests/components/mcp3008/test.esp8266.yaml | 17 +++++++ tests/components/mcp3008/test.rp2040.yaml | 17 +++++++ .../components/mcp3204/test.esp32-c3-idf.yaml | 16 +++++++ tests/components/mcp3204/test.esp32-c3.yaml | 16 +++++++ tests/components/mcp3204/test.esp32-idf.yaml | 16 +++++++ tests/components/mcp3204/test.esp32.yaml | 16 +++++++ tests/components/mcp3204/test.esp8266.yaml | 16 +++++++ tests/components/mcp3204/test.rp2040.yaml | 16 +++++++ .../components/mcp4725/test.esp32-c3-idf.yaml | 8 ++++ tests/components/mcp4725/test.esp32-c3.yaml | 8 ++++ tests/components/mcp4725/test.esp32-idf.yaml | 8 ++++ tests/components/mcp4725/test.esp32.yaml | 8 ++++ tests/components/mcp4725/test.esp8266.yaml | 8 ++++ tests/components/mcp4725/test.rp2040.yaml | 8 ++++ .../components/mcp4728/test.esp32-c3-idf.yaml | 31 +++++++++++++ tests/components/mcp4728/test.esp32-c3.yaml | 31 +++++++++++++ tests/components/mcp4728/test.esp32-idf.yaml | 31 +++++++++++++ tests/components/mcp4728/test.esp32.yaml | 31 +++++++++++++ tests/components/mcp4728/test.esp8266.yaml | 31 +++++++++++++ tests/components/mcp4728/test.rp2040.yaml | 31 +++++++++++++ .../components/mcp47a1/test.esp32-c3-idf.yaml | 8 ++++ tests/components/mcp47a1/test.esp32-c3.yaml | 8 ++++ tests/components/mcp47a1/test.esp32-idf.yaml | 8 ++++ tests/components/mcp47a1/test.esp32.yaml | 8 ++++ tests/components/mcp47a1/test.esp8266.yaml | 8 ++++ tests/components/mcp47a1/test.rp2040.yaml | 8 ++++ .../components/mcp9600/test.esp32-c3-idf.yaml | 12 +++++ tests/components/mcp9600/test.esp32-c3.yaml | 12 +++++ tests/components/mcp9600/test.esp32-idf.yaml | 12 +++++ tests/components/mcp9600/test.esp32.yaml | 12 +++++ tests/components/mcp9600/test.esp8266.yaml | 12 +++++ tests/components/mcp9600/test.rp2040.yaml | 12 +++++ .../components/mcp9808/test.esp32-c3-idf.yaml | 8 ++++ tests/components/mcp9808/test.esp32-c3.yaml | 8 ++++ tests/components/mcp9808/test.esp32-idf.yaml | 8 ++++ tests/components/mcp9808/test.esp32.yaml | 8 ++++ tests/components/mcp9808/test.esp8266.yaml | 8 ++++ tests/components/mcp9808/test.rp2040.yaml | 8 ++++ tests/components/mdns/test.esp32-c3-idf.yaml | 6 +++ tests/components/mdns/test.esp32-c3.yaml | 6 +++ tests/components/mdns/test.esp32-idf.yaml | 6 +++ tests/components/mdns/test.esp32.yaml | 6 +++ tests/components/mdns/test.esp8266.yaml | 6 +++ tests/components/mdns/test.rp2040.yaml | 6 +++ tests/components/media_player/test.esp32.yaml | 32 ++++++++++++++ tests/components/mhz19/test.esp32-c3-idf.yaml | 14 ++++++ tests/components/mhz19/test.esp32-c3.yaml | 14 ++++++ tests/components/mhz19/test.esp32-idf.yaml | 14 ++++++ tests/components/mhz19/test.esp32.yaml | 14 ++++++ tests/components/mhz19/test.esp8266.yaml | 14 ++++++ tests/components/mhz19/test.rp2040.yaml | 14 ++++++ 151 files changed, 2420 insertions(+) create mode 100644 tests/components/matrix_keypad/test.esp32-c3-idf.yaml create mode 100644 tests/components/matrix_keypad/test.esp32-c3.yaml create mode 100644 tests/components/matrix_keypad/test.esp32-idf.yaml create mode 100644 tests/components/matrix_keypad/test.esp32.yaml create mode 100644 tests/components/matrix_keypad/test.esp8266.yaml create mode 100644 tests/components/matrix_keypad/test.rp2040.yaml create mode 100644 tests/components/max31855/test.esp32-c3-idf.yaml create mode 100644 tests/components/max31855/test.esp32-c3.yaml create mode 100644 tests/components/max31855/test.esp32-idf.yaml create mode 100644 tests/components/max31855/test.esp32.yaml create mode 100644 tests/components/max31855/test.esp8266.yaml create mode 100644 tests/components/max31855/test.rp2040.yaml create mode 100644 tests/components/max31856/test.esp32-c3-idf.yaml create mode 100644 tests/components/max31856/test.esp32-c3.yaml create mode 100644 tests/components/max31856/test.esp32-idf.yaml create mode 100644 tests/components/max31856/test.esp32.yaml create mode 100644 tests/components/max31856/test.esp8266.yaml create mode 100644 tests/components/max31856/test.rp2040.yaml create mode 100644 tests/components/max31865/test.esp32-c3-idf.yaml create mode 100644 tests/components/max31865/test.esp32-c3.yaml create mode 100644 tests/components/max31865/test.esp32-idf.yaml create mode 100644 tests/components/max31865/test.esp32.yaml create mode 100644 tests/components/max31865/test.esp8266.yaml create mode 100644 tests/components/max31865/test.rp2040.yaml create mode 100644 tests/components/max44009/test.esp32-c3-idf.yaml create mode 100644 tests/components/max44009/test.esp32-c3.yaml create mode 100644 tests/components/max44009/test.esp32-idf.yaml create mode 100644 tests/components/max44009/test.esp32.yaml create mode 100644 tests/components/max44009/test.esp8266.yaml create mode 100644 tests/components/max44009/test.rp2040.yaml create mode 100644 tests/components/max6675/test.esp32-c3-idf.yaml create mode 100644 tests/components/max6675/test.esp32-c3.yaml create mode 100644 tests/components/max6675/test.esp32-idf.yaml create mode 100644 tests/components/max6675/test.esp32.yaml create mode 100644 tests/components/max6675/test.esp8266.yaml create mode 100644 tests/components/max6675/test.rp2040.yaml create mode 100644 tests/components/max6956/test.esp32-c3-idf.yaml create mode 100644 tests/components/max6956/test.esp32-c3.yaml create mode 100644 tests/components/max6956/test.esp32-idf.yaml create mode 100644 tests/components/max6956/test.esp32.yaml create mode 100644 tests/components/max6956/test.esp8266.yaml create mode 100644 tests/components/max6956/test.rp2040.yaml create mode 100644 tests/components/max7219/test.esp32-c3-idf.yaml create mode 100644 tests/components/max7219/test.esp32-c3.yaml create mode 100644 tests/components/max7219/test.esp32-idf.yaml create mode 100644 tests/components/max7219/test.esp32.yaml create mode 100644 tests/components/max7219/test.esp8266.yaml create mode 100644 tests/components/max7219/test.rp2040.yaml create mode 100644 tests/components/max7219digit/test.esp32-c3-idf.yaml create mode 100644 tests/components/max7219digit/test.esp32-c3.yaml create mode 100644 tests/components/max7219digit/test.esp32-idf.yaml create mode 100644 tests/components/max7219digit/test.esp32.yaml create mode 100644 tests/components/max7219digit/test.esp8266.yaml create mode 100644 tests/components/max7219digit/test.rp2040.yaml create mode 100644 tests/components/max9611/test.esp32-c3-idf.yaml create mode 100644 tests/components/max9611/test.esp32-c3.yaml create mode 100644 tests/components/max9611/test.esp32-idf.yaml create mode 100644 tests/components/max9611/test.esp32.yaml create mode 100644 tests/components/max9611/test.esp8266.yaml create mode 100644 tests/components/max9611/test.rp2040.yaml create mode 100644 tests/components/mcp23008/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp23008/test.esp32-c3.yaml create mode 100644 tests/components/mcp23008/test.esp32-idf.yaml create mode 100644 tests/components/mcp23008/test.esp32.yaml create mode 100644 tests/components/mcp23008/test.esp8266.yaml create mode 100644 tests/components/mcp23008/test.rp2040.yaml create mode 100644 tests/components/mcp23016/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp23016/test.esp32-c3.yaml create mode 100644 tests/components/mcp23016/test.esp32-idf.yaml create mode 100644 tests/components/mcp23016/test.esp32.yaml create mode 100644 tests/components/mcp23016/test.esp8266.yaml create mode 100644 tests/components/mcp23016/test.rp2040.yaml create mode 100644 tests/components/mcp23017/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp23017/test.esp32-c3.yaml create mode 100644 tests/components/mcp23017/test.esp32-idf.yaml create mode 100644 tests/components/mcp23017/test.esp32.yaml create mode 100644 tests/components/mcp23017/test.esp8266.yaml create mode 100644 tests/components/mcp23017/test.rp2040.yaml create mode 100644 tests/components/mcp23s08/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp23s08/test.esp32-c3.yaml create mode 100644 tests/components/mcp23s08/test.esp32-idf.yaml create mode 100644 tests/components/mcp23s08/test.esp32.yaml create mode 100644 tests/components/mcp23s08/test.esp8266.yaml create mode 100644 tests/components/mcp23s08/test.rp2040.yaml create mode 100644 tests/components/mcp23s17/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp23s17/test.esp32-c3.yaml create mode 100644 tests/components/mcp23s17/test.esp32-idf.yaml create mode 100644 tests/components/mcp23s17/test.esp32.yaml create mode 100644 tests/components/mcp23s17/test.esp8266.yaml create mode 100644 tests/components/mcp23s17/test.rp2040.yaml create mode 100644 tests/components/mcp2515/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp2515/test.esp32-c3.yaml create mode 100644 tests/components/mcp2515/test.esp32-idf.yaml create mode 100644 tests/components/mcp2515/test.esp32.yaml create mode 100644 tests/components/mcp2515/test.esp8266.yaml create mode 100644 tests/components/mcp2515/test.rp2040.yaml create mode 100644 tests/components/mcp3008/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp3008/test.esp32-c3.yaml create mode 100644 tests/components/mcp3008/test.esp32-idf.yaml create mode 100644 tests/components/mcp3008/test.esp32.yaml create mode 100644 tests/components/mcp3008/test.esp8266.yaml create mode 100644 tests/components/mcp3008/test.rp2040.yaml create mode 100644 tests/components/mcp3204/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp3204/test.esp32-c3.yaml create mode 100644 tests/components/mcp3204/test.esp32-idf.yaml create mode 100644 tests/components/mcp3204/test.esp32.yaml create mode 100644 tests/components/mcp3204/test.esp8266.yaml create mode 100644 tests/components/mcp3204/test.rp2040.yaml create mode 100644 tests/components/mcp4725/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp4725/test.esp32-c3.yaml create mode 100644 tests/components/mcp4725/test.esp32-idf.yaml create mode 100644 tests/components/mcp4725/test.esp32.yaml create mode 100644 tests/components/mcp4725/test.esp8266.yaml create mode 100644 tests/components/mcp4725/test.rp2040.yaml create mode 100644 tests/components/mcp4728/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp4728/test.esp32-c3.yaml create mode 100644 tests/components/mcp4728/test.esp32-idf.yaml create mode 100644 tests/components/mcp4728/test.esp32.yaml create mode 100644 tests/components/mcp4728/test.esp8266.yaml create mode 100644 tests/components/mcp4728/test.rp2040.yaml create mode 100644 tests/components/mcp47a1/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp47a1/test.esp32-c3.yaml create mode 100644 tests/components/mcp47a1/test.esp32-idf.yaml create mode 100644 tests/components/mcp47a1/test.esp32.yaml create mode 100644 tests/components/mcp47a1/test.esp8266.yaml create mode 100644 tests/components/mcp47a1/test.rp2040.yaml create mode 100644 tests/components/mcp9600/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp9600/test.esp32-c3.yaml create mode 100644 tests/components/mcp9600/test.esp32-idf.yaml create mode 100644 tests/components/mcp9600/test.esp32.yaml create mode 100644 tests/components/mcp9600/test.esp8266.yaml create mode 100644 tests/components/mcp9600/test.rp2040.yaml create mode 100644 tests/components/mcp9808/test.esp32-c3-idf.yaml create mode 100644 tests/components/mcp9808/test.esp32-c3.yaml create mode 100644 tests/components/mcp9808/test.esp32-idf.yaml create mode 100644 tests/components/mcp9808/test.esp32.yaml create mode 100644 tests/components/mcp9808/test.esp8266.yaml create mode 100644 tests/components/mcp9808/test.rp2040.yaml create mode 100644 tests/components/mdns/test.esp32-c3-idf.yaml create mode 100644 tests/components/mdns/test.esp32-c3.yaml create mode 100644 tests/components/mdns/test.esp32-idf.yaml create mode 100644 tests/components/mdns/test.esp32.yaml create mode 100644 tests/components/mdns/test.esp8266.yaml create mode 100644 tests/components/mdns/test.rp2040.yaml create mode 100644 tests/components/media_player/test.esp32.yaml create mode 100644 tests/components/mhz19/test.esp32-c3-idf.yaml create mode 100644 tests/components/mhz19/test.esp32-c3.yaml create mode 100644 tests/components/mhz19/test.esp32-idf.yaml create mode 100644 tests/components/mhz19/test.esp32.yaml create mode 100644 tests/components/mhz19/test.esp8266.yaml create mode 100644 tests/components/mhz19/test.rp2040.yaml diff --git a/tests/components/matrix_keypad/test.esp32-c3-idf.yaml b/tests/components/matrix_keypad/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d15e6af21a --- /dev/null +++ b/tests/components/matrix_keypad/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/matrix_keypad/test.esp32-c3.yaml b/tests/components/matrix_keypad/test.esp32-c3.yaml new file mode 100644 index 0000000000..d15e6af21a --- /dev/null +++ b/tests/components/matrix_keypad/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/matrix_keypad/test.esp32-idf.yaml b/tests/components/matrix_keypad/test.esp32-idf.yaml new file mode 100644 index 0000000000..c8e9b54534 --- /dev/null +++ b/tests/components/matrix_keypad/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/matrix_keypad/test.esp32.yaml b/tests/components/matrix_keypad/test.esp32.yaml new file mode 100644 index 0000000000..c8e9b54534 --- /dev/null +++ b/tests/components/matrix_keypad/test.esp32.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/matrix_keypad/test.esp8266.yaml b/tests/components/matrix_keypad/test.esp8266.yaml new file mode 100644 index 0000000000..c8e9b54534 --- /dev/null +++ b/tests/components/matrix_keypad/test.esp8266.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 12 + - pin: 13 + columns: + - pin: 14 + - pin: 15 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/matrix_keypad/test.rp2040.yaml b/tests/components/matrix_keypad/test.rp2040.yaml new file mode 100644 index 0000000000..d15e6af21a --- /dev/null +++ b/tests/components/matrix_keypad/test.rp2040.yaml @@ -0,0 +1,19 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 + +matrix_keypad: + id: keypad + rows: + - pin: 1 + - pin: 2 + columns: + - pin: 3 + - pin: 4 + keys: "1234" + has_pulldowns: true diff --git a/tests/components/max31855/test.esp32-c3-idf.yaml b/tests/components/max31855/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e7c8f3f824 --- /dev/null +++ b/tests/components/max31855/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 8 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31855/test.esp32-c3.yaml b/tests/components/max31855/test.esp32-c3.yaml new file mode 100644 index 0000000000..e7c8f3f824 --- /dev/null +++ b/tests/components/max31855/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 8 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31855/test.esp32-idf.yaml b/tests/components/max31855/test.esp32-idf.yaml new file mode 100644 index 0000000000..25fee986d2 --- /dev/null +++ b/tests/components/max31855/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 12 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31855/test.esp32.yaml b/tests/components/max31855/test.esp32.yaml new file mode 100644 index 0000000000..25fee986d2 --- /dev/null +++ b/tests/components/max31855/test.esp32.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 12 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31855/test.esp8266.yaml b/tests/components/max31855/test.esp8266.yaml new file mode 100644 index 0000000000..7e02d41fce --- /dev/null +++ b/tests/components/max31855/test.esp8266.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 15 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31855/test.rp2040.yaml b/tests/components/max31855/test.rp2040.yaml new file mode 100644 index 0000000000..379d4d33d6 --- /dev/null +++ b/tests/components/max31855/test.rp2040.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31855 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +sensor: + - platform: max31855 + name: MAX31855 Temperature + cs_pin: 6 + update_interval: 15s + reference_temperature: + name: MAX31855 Internal Temperature diff --git a/tests/components/max31856/test.esp32-c3-idf.yaml b/tests/components/max31856/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2794866c59 --- /dev/null +++ b/tests/components/max31856/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 8 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31856/test.esp32-c3.yaml b/tests/components/max31856/test.esp32-c3.yaml new file mode 100644 index 0000000000..2794866c59 --- /dev/null +++ b/tests/components/max31856/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 8 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31856/test.esp32-idf.yaml b/tests/components/max31856/test.esp32-idf.yaml new file mode 100644 index 0000000000..5561903207 --- /dev/null +++ b/tests/components/max31856/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 12 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31856/test.esp32.yaml b/tests/components/max31856/test.esp32.yaml new file mode 100644 index 0000000000..5561903207 --- /dev/null +++ b/tests/components/max31856/test.esp32.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 12 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31856/test.esp8266.yaml b/tests/components/max31856/test.esp8266.yaml new file mode 100644 index 0000000000..dfd9572ca9 --- /dev/null +++ b/tests/components/max31856/test.esp8266.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 15 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31856/test.rp2040.yaml b/tests/components/max31856/test.rp2040.yaml new file mode 100644 index 0000000000..0abc8a081b --- /dev/null +++ b/tests/components/max31856/test.rp2040.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max31856 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +sensor: + - platform: max31856 + name: MAX31856 Temperature + cs_pin: 6 + update_interval: 15s + mains_filter: 50Hz diff --git a/tests/components/max31865/test.esp32-c3-idf.yaml b/tests/components/max31865/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..45de22331e --- /dev/null +++ b/tests/components/max31865/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 8 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max31865/test.esp32-c3.yaml b/tests/components/max31865/test.esp32-c3.yaml new file mode 100644 index 0000000000..45de22331e --- /dev/null +++ b/tests/components/max31865/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 8 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max31865/test.esp32-idf.yaml b/tests/components/max31865/test.esp32-idf.yaml new file mode 100644 index 0000000000..8326a578ee --- /dev/null +++ b/tests/components/max31865/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 12 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max31865/test.esp32.yaml b/tests/components/max31865/test.esp32.yaml new file mode 100644 index 0000000000..8326a578ee --- /dev/null +++ b/tests/components/max31865/test.esp32.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 12 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max31865/test.esp8266.yaml b/tests/components/max31865/test.esp8266.yaml new file mode 100644 index 0000000000..4828019acc --- /dev/null +++ b/tests/components/max31865/test.esp8266.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 15 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max31865/test.rp2040.yaml b/tests/components/max31865/test.rp2040.yaml new file mode 100644 index 0000000000..5af64b41ad --- /dev/null +++ b/tests/components/max31865/test.rp2040.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_max31865 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +sensor: + - platform: max31865 + name: MAX31865 Temperature + cs_pin: 6 + update_interval: 15s + reference_resistance: 430 Ω + rtd_nominal_resistance: 100 Ω diff --git a/tests/components/max44009/test.esp32-c3-idf.yaml b/tests/components/max44009/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..593d4bd48c --- /dev/null +++ b/tests/components/max44009/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 5 + sda: 4 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max44009/test.esp32-c3.yaml b/tests/components/max44009/test.esp32-c3.yaml new file mode 100644 index 0000000000..593d4bd48c --- /dev/null +++ b/tests/components/max44009/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 5 + sda: 4 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max44009/test.esp32-idf.yaml b/tests/components/max44009/test.esp32-idf.yaml new file mode 100644 index 0000000000..56eecebc4a --- /dev/null +++ b/tests/components/max44009/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 16 + sda: 17 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max44009/test.esp32.yaml b/tests/components/max44009/test.esp32.yaml new file mode 100644 index 0000000000..56eecebc4a --- /dev/null +++ b/tests/components/max44009/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 16 + sda: 17 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max44009/test.esp8266.yaml b/tests/components/max44009/test.esp8266.yaml new file mode 100644 index 0000000000..593d4bd48c --- /dev/null +++ b/tests/components/max44009/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 5 + sda: 4 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max44009/test.rp2040.yaml b/tests/components/max44009/test.rp2040.yaml new file mode 100644 index 0000000000..593d4bd48c --- /dev/null +++ b/tests/components/max44009/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_max44009 + scl: 5 + sda: 4 + +sensor: + - platform: max44009 + name: MAX44009 Brightness + internal: true + mode: low_power + address: 0x4A + update_interval: 30s diff --git a/tests/components/max6675/test.esp32-c3-idf.yaml b/tests/components/max6675/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2f05102ca1 --- /dev/null +++ b/tests/components/max6675/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 8 + update_interval: 15s diff --git a/tests/components/max6675/test.esp32-c3.yaml b/tests/components/max6675/test.esp32-c3.yaml new file mode 100644 index 0000000000..2f05102ca1 --- /dev/null +++ b/tests/components/max6675/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 8 + update_interval: 15s diff --git a/tests/components/max6675/test.esp32-idf.yaml b/tests/components/max6675/test.esp32-idf.yaml new file mode 100644 index 0000000000..9771bf9d5f --- /dev/null +++ b/tests/components/max6675/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 12 + update_interval: 15s diff --git a/tests/components/max6675/test.esp32.yaml b/tests/components/max6675/test.esp32.yaml new file mode 100644 index 0000000000..9771bf9d5f --- /dev/null +++ b/tests/components/max6675/test.esp32.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 12 + update_interval: 15s diff --git a/tests/components/max6675/test.esp8266.yaml b/tests/components/max6675/test.esp8266.yaml new file mode 100644 index 0000000000..f67e9e04a8 --- /dev/null +++ b/tests/components/max6675/test.esp8266.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 15 + update_interval: 15s diff --git a/tests/components/max6675/test.rp2040.yaml b/tests/components/max6675/test.rp2040.yaml new file mode 100644 index 0000000000..89c0932f94 --- /dev/null +++ b/tests/components/max6675/test.rp2040.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_max6675 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +sensor: + - platform: max6675 + name: Temperature + cs_pin: 6 + update_interval: 15s diff --git a/tests/components/max6956/test.esp32-c3-idf.yaml b/tests/components/max6956/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..690941784c --- /dev/null +++ b/tests/components/max6956/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 5 + sda: 4 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max6956/test.esp32-c3.yaml b/tests/components/max6956/test.esp32-c3.yaml new file mode 100644 index 0000000000..690941784c --- /dev/null +++ b/tests/components/max6956/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 5 + sda: 4 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max6956/test.esp32-idf.yaml b/tests/components/max6956/test.esp32-idf.yaml new file mode 100644 index 0000000000..abd1404634 --- /dev/null +++ b/tests/components/max6956/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 16 + sda: 17 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max6956/test.esp32.yaml b/tests/components/max6956/test.esp32.yaml new file mode 100644 index 0000000000..abd1404634 --- /dev/null +++ b/tests/components/max6956/test.esp32.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 16 + sda: 17 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max6956/test.esp8266.yaml b/tests/components/max6956/test.esp8266.yaml new file mode 100644 index 0000000000..690941784c --- /dev/null +++ b/tests/components/max6956/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 5 + sda: 4 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max6956/test.rp2040.yaml b/tests/components/max6956/test.rp2040.yaml new file mode 100644 index 0000000000..690941784c --- /dev/null +++ b/tests/components/max6956/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_max6956 + scl: 5 + sda: 4 + +max6956: + - id: max6956_1 + address: 0x40 + +binary_sensor: + - platform: gpio + name: Max Input Pin 4 + pin: + max6956: max6956_1 + number: 4 + mode: + input: true + pullup: true + inverted: false diff --git a/tests/components/max7219/test.esp32-c3-idf.yaml b/tests/components/max7219/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fa1ac15f33 --- /dev/null +++ b/tests/components/max7219/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max7219 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: max7219 + cs_pin: 8 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219/test.esp32-c3.yaml b/tests/components/max7219/test.esp32-c3.yaml new file mode 100644 index 0000000000..fa1ac15f33 --- /dev/null +++ b/tests/components/max7219/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max7219 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: max7219 + cs_pin: 8 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219/test.esp32-idf.yaml b/tests/components/max7219/test.esp32-idf.yaml new file mode 100644 index 0000000000..2985345a48 --- /dev/null +++ b/tests/components/max7219/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max6675 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: max7219 + cs_pin: 12 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219/test.esp32.yaml b/tests/components/max7219/test.esp32.yaml new file mode 100644 index 0000000000..2985345a48 --- /dev/null +++ b/tests/components/max7219/test.esp32.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max6675 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: max7219 + cs_pin: 12 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219/test.esp8266.yaml b/tests/components/max7219/test.esp8266.yaml new file mode 100644 index 0000000000..a8c280daff --- /dev/null +++ b/tests/components/max7219/test.esp8266.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max6675 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: max7219 + cs_pin: 15 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219/test.rp2040.yaml b/tests/components/max7219/test.rp2040.yaml new file mode 100644 index 0000000000..37b2220649 --- /dev/null +++ b/tests/components/max7219/test.rp2040.yaml @@ -0,0 +1,12 @@ +spi: + - id: spi_max6675 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: max7219 + cs_pin: 6 + num_chips: 1 + lambda: |- + it.print("01234567"); diff --git a/tests/components/max7219digit/test.esp32-c3-idf.yaml b/tests/components/max7219digit/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0c04784380 --- /dev/null +++ b/tests/components/max7219digit/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: max7219digit + cs_pin: 8 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max7219digit/test.esp32-c3.yaml b/tests/components/max7219digit/test.esp32-c3.yaml new file mode 100644 index 0000000000..0c04784380 --- /dev/null +++ b/tests/components/max7219digit/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: max7219digit + cs_pin: 8 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max7219digit/test.esp32-idf.yaml b/tests/components/max7219digit/test.esp32-idf.yaml new file mode 100644 index 0000000000..7f3aed964a --- /dev/null +++ b/tests/components/max7219digit/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: max7219digit + cs_pin: 12 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max7219digit/test.esp32.yaml b/tests/components/max7219digit/test.esp32.yaml new file mode 100644 index 0000000000..7f3aed964a --- /dev/null +++ b/tests/components/max7219digit/test.esp32.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: max7219digit + cs_pin: 12 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max7219digit/test.esp8266.yaml b/tests/components/max7219digit/test.esp8266.yaml new file mode 100644 index 0000000000..52587e8b0e --- /dev/null +++ b/tests/components/max7219digit/test.esp8266.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: max7219digit + cs_pin: 15 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max7219digit/test.rp2040.yaml b/tests/components/max7219digit/test.rp2040.yaml new file mode 100644 index 0000000000..f986483ec2 --- /dev/null +++ b/tests/components/max7219digit/test.rp2040.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_max7219digit + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: max7219digit + cs_pin: 6 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); diff --git a/tests/components/max9611/test.esp32-c3-idf.yaml b/tests/components/max9611/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..00f8330280 --- /dev/null +++ b/tests/components/max9611/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 5 + sda: 4 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/max9611/test.esp32-c3.yaml b/tests/components/max9611/test.esp32-c3.yaml new file mode 100644 index 0000000000..00f8330280 --- /dev/null +++ b/tests/components/max9611/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 5 + sda: 4 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/max9611/test.esp32-idf.yaml b/tests/components/max9611/test.esp32-idf.yaml new file mode 100644 index 0000000000..5c480cc815 --- /dev/null +++ b/tests/components/max9611/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 16 + sda: 17 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/max9611/test.esp32.yaml b/tests/components/max9611/test.esp32.yaml new file mode 100644 index 0000000000..5c480cc815 --- /dev/null +++ b/tests/components/max9611/test.esp32.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 16 + sda: 17 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/max9611/test.esp8266.yaml b/tests/components/max9611/test.esp8266.yaml new file mode 100644 index 0000000000..00f8330280 --- /dev/null +++ b/tests/components/max9611/test.esp8266.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 5 + sda: 4 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/max9611/test.rp2040.yaml b/tests/components/max9611/test.rp2040.yaml new file mode 100644 index 0000000000..00f8330280 --- /dev/null +++ b/tests/components/max9611/test.rp2040.yaml @@ -0,0 +1,18 @@ +i2c: + - id: i2c_max9611 + scl: 5 + sda: 4 + +sensor: + - platform: max9611 + shunt_resistance: 0.2 ohm + gain: 1X + voltage: + name: Max9611 Voltage + current: + name: Max9611 Current + power: + name: Max9611 Watts + temperature: + name: Max9611 Temp + update_interval: 1s diff --git a/tests/components/mcp23008/test.esp32-c3-idf.yaml b/tests/components/mcp23008/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..eabd5a7311 --- /dev/null +++ b/tests/components/mcp23008/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 5 + sda: 4 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23008/test.esp32-c3.yaml b/tests/components/mcp23008/test.esp32-c3.yaml new file mode 100644 index 0000000000..eabd5a7311 --- /dev/null +++ b/tests/components/mcp23008/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 5 + sda: 4 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23008/test.esp32-idf.yaml b/tests/components/mcp23008/test.esp32-idf.yaml new file mode 100644 index 0000000000..cbf03f371c --- /dev/null +++ b/tests/components/mcp23008/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 16 + sda: 17 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23008/test.esp32.yaml b/tests/components/mcp23008/test.esp32.yaml new file mode 100644 index 0000000000..cbf03f371c --- /dev/null +++ b/tests/components/mcp23008/test.esp32.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 16 + sda: 17 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23008/test.esp8266.yaml b/tests/components/mcp23008/test.esp8266.yaml new file mode 100644 index 0000000000..eabd5a7311 --- /dev/null +++ b/tests/components/mcp23008/test.esp8266.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 5 + sda: 4 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23008/test.rp2040.yaml b/tests/components/mcp23008/test.rp2040.yaml new file mode 100644 index 0000000000..eabd5a7311 --- /dev/null +++ b/tests/components/mcp23008/test.rp2040.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23008 + scl: 5 + sda: 4 + +mcp23008: + id: mcp23008_hub + +binary_sensor: + - platform: gpio + id: mcp23008_binary_sensor + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23008_switch + pin: + mcp23xxx: mcp23008_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.esp32-c3-idf.yaml b/tests/components/mcp23016/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2211931e3d --- /dev/null +++ b/tests/components/mcp23016/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 5 + sda: 4 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.esp32-c3.yaml b/tests/components/mcp23016/test.esp32-c3.yaml new file mode 100644 index 0000000000..2211931e3d --- /dev/null +++ b/tests/components/mcp23016/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 5 + sda: 4 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.esp32-idf.yaml b/tests/components/mcp23016/test.esp32-idf.yaml new file mode 100644 index 0000000000..48574a9b01 --- /dev/null +++ b/tests/components/mcp23016/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 16 + sda: 17 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.esp32.yaml b/tests/components/mcp23016/test.esp32.yaml new file mode 100644 index 0000000000..48574a9b01 --- /dev/null +++ b/tests/components/mcp23016/test.esp32.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 16 + sda: 17 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.esp8266.yaml b/tests/components/mcp23016/test.esp8266.yaml new file mode 100644 index 0000000000..2211931e3d --- /dev/null +++ b/tests/components/mcp23016/test.esp8266.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 5 + sda: 4 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23016/test.rp2040.yaml b/tests/components/mcp23016/test.rp2040.yaml new file mode 100644 index 0000000000..2211931e3d --- /dev/null +++ b/tests/components/mcp23016/test.rp2040.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23016 + scl: 5 + sda: 4 + +mcp23016: + id: mcp23016_hub + +binary_sensor: + - platform: gpio + id: mcp23016_binary_sensor + pin: + mcp23016: mcp23016_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23016_switch + pin: + mcp23016: mcp23016_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.esp32-c3-idf.yaml b/tests/components/mcp23017/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..863b2b8f0b --- /dev/null +++ b/tests/components/mcp23017/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 5 + sda: 4 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.esp32-c3.yaml b/tests/components/mcp23017/test.esp32-c3.yaml new file mode 100644 index 0000000000..863b2b8f0b --- /dev/null +++ b/tests/components/mcp23017/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 5 + sda: 4 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.esp32-idf.yaml b/tests/components/mcp23017/test.esp32-idf.yaml new file mode 100644 index 0000000000..9b7c45eb8a --- /dev/null +++ b/tests/components/mcp23017/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 16 + sda: 17 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.esp32.yaml b/tests/components/mcp23017/test.esp32.yaml new file mode 100644 index 0000000000..9b7c45eb8a --- /dev/null +++ b/tests/components/mcp23017/test.esp32.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 16 + sda: 17 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.esp8266.yaml b/tests/components/mcp23017/test.esp8266.yaml new file mode 100644 index 0000000000..863b2b8f0b --- /dev/null +++ b/tests/components/mcp23017/test.esp8266.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 5 + sda: 4 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23017/test.rp2040.yaml b/tests/components/mcp23017/test.rp2040.yaml new file mode 100644 index 0000000000..863b2b8f0b --- /dev/null +++ b/tests/components/mcp23017/test.rp2040.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_mcp23017 + scl: 5 + sda: 4 + +mcp23017: + id: mcp23017_hub + +binary_sensor: + - platform: gpio + id: mcp23017_binary_sensor + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: INPUT + +switch: + - platform: gpio + id: mcp23017_switch + pin: + mcp23xxx: mcp23017_hub + number: 1 + mode: OUTPUT diff --git a/tests/components/mcp23s08/test.esp32-c3-idf.yaml b/tests/components/mcp23s08/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f1af8a71a9 --- /dev/null +++ b/tests/components/mcp23s08/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 8 + deviceaddress: 0 diff --git a/tests/components/mcp23s08/test.esp32-c3.yaml b/tests/components/mcp23s08/test.esp32-c3.yaml new file mode 100644 index 0000000000..f1af8a71a9 --- /dev/null +++ b/tests/components/mcp23s08/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 8 + deviceaddress: 0 diff --git a/tests/components/mcp23s08/test.esp32-idf.yaml b/tests/components/mcp23s08/test.esp32-idf.yaml new file mode 100644 index 0000000000..0b26035c3e --- /dev/null +++ b/tests/components/mcp23s08/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 12 + deviceaddress: 0 diff --git a/tests/components/mcp23s08/test.esp32.yaml b/tests/components/mcp23s08/test.esp32.yaml new file mode 100644 index 0000000000..0b26035c3e --- /dev/null +++ b/tests/components/mcp23s08/test.esp32.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 12 + deviceaddress: 0 diff --git a/tests/components/mcp23s08/test.esp8266.yaml b/tests/components/mcp23s08/test.esp8266.yaml new file mode 100644 index 0000000000..eff856aca9 --- /dev/null +++ b/tests/components/mcp23s08/test.esp8266.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 15 + deviceaddress: 0 diff --git a/tests/components/mcp23s08/test.rp2040.yaml b/tests/components/mcp23s08/test.rp2040.yaml new file mode 100644 index 0000000000..1b23d2d3b5 --- /dev/null +++ b/tests/components/mcp23s08/test.rp2040.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s08 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +mcp23s08: + - id: mcp23s08_hub + cs_pin: 6 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.esp32-c3-idf.yaml b/tests/components/mcp23s17/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d83f66d3b1 --- /dev/null +++ b/tests/components/mcp23s17/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 8 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.esp32-c3.yaml b/tests/components/mcp23s17/test.esp32-c3.yaml new file mode 100644 index 0000000000..d83f66d3b1 --- /dev/null +++ b/tests/components/mcp23s17/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 8 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.esp32-idf.yaml b/tests/components/mcp23s17/test.esp32-idf.yaml new file mode 100644 index 0000000000..9a42c12e85 --- /dev/null +++ b/tests/components/mcp23s17/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 12 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.esp32.yaml b/tests/components/mcp23s17/test.esp32.yaml new file mode 100644 index 0000000000..9a42c12e85 --- /dev/null +++ b/tests/components/mcp23s17/test.esp32.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 12 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.esp8266.yaml b/tests/components/mcp23s17/test.esp8266.yaml new file mode 100644 index 0000000000..36dac63f6f --- /dev/null +++ b/tests/components/mcp23s17/test.esp8266.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 15 + deviceaddress: 0 diff --git a/tests/components/mcp23s17/test.rp2040.yaml b/tests/components/mcp23s17/test.rp2040.yaml new file mode 100644 index 0000000000..2730f6a9d6 --- /dev/null +++ b/tests/components/mcp23s17/test.rp2040.yaml @@ -0,0 +1,10 @@ +spi: + - id: spi_mcp23s17 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +mcp23s17: + - id: mcp23s17_hub + cs_pin: 6 + deviceaddress: 0 diff --git a/tests/components/mcp2515/test.esp32-c3-idf.yaml b/tests/components/mcp2515/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3ceeea268f --- /dev/null +++ b/tests/components/mcp2515/test.esp32-c3-idf.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 8 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp2515/test.esp32-c3.yaml b/tests/components/mcp2515/test.esp32-c3.yaml new file mode 100644 index 0000000000..3ceeea268f --- /dev/null +++ b/tests/components/mcp2515/test.esp32-c3.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 8 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp2515/test.esp32-idf.yaml b/tests/components/mcp2515/test.esp32-idf.yaml new file mode 100644 index 0000000000..07fae36cc3 --- /dev/null +++ b/tests/components/mcp2515/test.esp32-idf.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 12 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp2515/test.esp32.yaml b/tests/components/mcp2515/test.esp32.yaml new file mode 100644 index 0000000000..07fae36cc3 --- /dev/null +++ b/tests/components/mcp2515/test.esp32.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 12 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp2515/test.esp8266.yaml b/tests/components/mcp2515/test.esp8266.yaml new file mode 100644 index 0000000000..1096a0e809 --- /dev/null +++ b/tests/components/mcp2515/test.esp8266.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 15 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp2515/test.rp2040.yaml b/tests/components/mcp2515/test.rp2040.yaml new file mode 100644 index 0000000000..678c817d3d --- /dev/null +++ b/tests/components/mcp2515/test.rp2040.yaml @@ -0,0 +1,44 @@ +spi: + - id: spi_mcp2515 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +canbus: + - platform: mcp2515 + id: mcp2515_can + cs_pin: 6 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("can_id 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: "x[0] == 0x11" + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + // to be continued... + } diff --git a/tests/components/mcp3008/test.esp32-c3-idf.yaml b/tests/components/mcp3008/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9e66372e4f --- /dev/null +++ b/tests/components/mcp3008/test.esp32-c3-idf.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp3008: + - id: mcp3008_hub + cs_pin: 8 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3008/test.esp32-c3.yaml b/tests/components/mcp3008/test.esp32-c3.yaml new file mode 100644 index 0000000000..9e66372e4f --- /dev/null +++ b/tests/components/mcp3008/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp3008: + - id: mcp3008_hub + cs_pin: 8 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3008/test.esp32-idf.yaml b/tests/components/mcp3008/test.esp32-idf.yaml new file mode 100644 index 0000000000..a66fbeb7a1 --- /dev/null +++ b/tests/components/mcp3008/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp3008: + - id: mcp3008_hub + cs_pin: 12 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3008/test.esp32.yaml b/tests/components/mcp3008/test.esp32.yaml new file mode 100644 index 0000000000..a66fbeb7a1 --- /dev/null +++ b/tests/components/mcp3008/test.esp32.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp3008: + - id: mcp3008_hub + cs_pin: 12 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3008/test.esp8266.yaml b/tests/components/mcp3008/test.esp8266.yaml new file mode 100644 index 0000000000..eaccca0765 --- /dev/null +++ b/tests/components/mcp3008/test.esp8266.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +mcp3008: + - id: mcp3008_hub + cs_pin: 15 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3008/test.rp2040.yaml b/tests/components/mcp3008/test.rp2040.yaml new file mode 100644 index 0000000000..8ab9630553 --- /dev/null +++ b/tests/components/mcp3008/test.rp2040.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_mcp3008 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +mcp3008: + - id: mcp3008_hub + cs_pin: 6 + +sensor: + - platform: mcp3008 + id: mcp3008_sensor + mcp3008_id: mcp3008_hub + number: 0 + reference_voltage: 3.19 + update_interval: 5s diff --git a/tests/components/mcp3204/test.esp32-c3-idf.yaml b/tests/components/mcp3204/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5bf5ba81e1 --- /dev/null +++ b/tests/components/mcp3204/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp3204: + - id: mcp3204_hub + cs_pin: 8 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp3204/test.esp32-c3.yaml b/tests/components/mcp3204/test.esp32-c3.yaml new file mode 100644 index 0000000000..5bf5ba81e1 --- /dev/null +++ b/tests/components/mcp3204/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +mcp3204: + - id: mcp3204_hub + cs_pin: 8 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp3204/test.esp32-idf.yaml b/tests/components/mcp3204/test.esp32-idf.yaml new file mode 100644 index 0000000000..c340797c8e --- /dev/null +++ b/tests/components/mcp3204/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp3204: + - id: mcp3204_hub + cs_pin: 12 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp3204/test.esp32.yaml b/tests/components/mcp3204/test.esp32.yaml new file mode 100644 index 0000000000..c340797c8e --- /dev/null +++ b/tests/components/mcp3204/test.esp32.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +mcp3204: + - id: mcp3204_hub + cs_pin: 12 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp3204/test.esp8266.yaml b/tests/components/mcp3204/test.esp8266.yaml new file mode 100644 index 0000000000..d208e3e06c --- /dev/null +++ b/tests/components/mcp3204/test.esp8266.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +mcp3204: + - id: mcp3204_hub + cs_pin: 15 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp3204/test.rp2040.yaml b/tests/components/mcp3204/test.rp2040.yaml new file mode 100644 index 0000000000..63f30e3621 --- /dev/null +++ b/tests/components/mcp3204/test.rp2040.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_mcp3204 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +mcp3204: + - id: mcp3204_hub + cs_pin: 6 + +sensor: + - platform: mcp3204 + id: mcp3204_sensor + mcp3204_id: mcp3204_hub + number: 0 + update_interval: 5s diff --git a/tests/components/mcp4725/test.esp32-c3-idf.yaml b/tests/components/mcp4725/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5fc799203d --- /dev/null +++ b/tests/components/mcp4725/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 5 + sda: 4 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4725/test.esp32-c3.yaml b/tests/components/mcp4725/test.esp32-c3.yaml new file mode 100644 index 0000000000..5fc799203d --- /dev/null +++ b/tests/components/mcp4725/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 5 + sda: 4 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4725/test.esp32-idf.yaml b/tests/components/mcp4725/test.esp32-idf.yaml new file mode 100644 index 0000000000..a523ad95e1 --- /dev/null +++ b/tests/components/mcp4725/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 16 + sda: 17 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4725/test.esp32.yaml b/tests/components/mcp4725/test.esp32.yaml new file mode 100644 index 0000000000..a523ad95e1 --- /dev/null +++ b/tests/components/mcp4725/test.esp32.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 16 + sda: 17 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4725/test.esp8266.yaml b/tests/components/mcp4725/test.esp8266.yaml new file mode 100644 index 0000000000..5fc799203d --- /dev/null +++ b/tests/components/mcp4725/test.esp8266.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 5 + sda: 4 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4725/test.rp2040.yaml b/tests/components/mcp4725/test.rp2040.yaml new file mode 100644 index 0000000000..5fc799203d --- /dev/null +++ b/tests/components/mcp4725/test.rp2040.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp4725 + scl: 5 + sda: 4 + +output: + - platform: mcp4725 + id: mcp4725_dac_output diff --git a/tests/components/mcp4728/test.esp32-c3-idf.yaml b/tests/components/mcp4728/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2f24dd0b8c --- /dev/null +++ b/tests/components/mcp4728/test.esp32-c3-idf.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 5 + sda: 4 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp4728/test.esp32-c3.yaml b/tests/components/mcp4728/test.esp32-c3.yaml new file mode 100644 index 0000000000..2f24dd0b8c --- /dev/null +++ b/tests/components/mcp4728/test.esp32-c3.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 5 + sda: 4 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp4728/test.esp32-idf.yaml b/tests/components/mcp4728/test.esp32-idf.yaml new file mode 100644 index 0000000000..b29a6ee53c --- /dev/null +++ b/tests/components/mcp4728/test.esp32-idf.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 16 + sda: 17 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp4728/test.esp32.yaml b/tests/components/mcp4728/test.esp32.yaml new file mode 100644 index 0000000000..b29a6ee53c --- /dev/null +++ b/tests/components/mcp4728/test.esp32.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 16 + sda: 17 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp4728/test.esp8266.yaml b/tests/components/mcp4728/test.esp8266.yaml new file mode 100644 index 0000000000..2f24dd0b8c --- /dev/null +++ b/tests/components/mcp4728/test.esp8266.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 5 + sda: 4 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp4728/test.rp2040.yaml b/tests/components/mcp4728/test.rp2040.yaml new file mode 100644 index 0000000000..2f24dd0b8c --- /dev/null +++ b/tests/components/mcp4728/test.rp2040.yaml @@ -0,0 +1,31 @@ +i2c: + - id: i2c_mcp4728 + scl: 5 + sda: 4 + +mcp4728: + - id: mcp4728_dac + +output: + - platform: mcp4728 + id: mcp4728_dac_output_a + channel: A + vref: vdd + power_down: normal + - platform: mcp4728 + id: mcp4728_dac_output_b + channel: B + vref: internal + gain: X1 + power_down: gnd_1k + - platform: mcp4728 + id: mcp4728_dac_output_c + channel: C + vref: vdd + power_down: gnd_100k + - platform: mcp4728 + id: mcp4728_dac_output_d + channel: D + vref: internal + gain: X2 + power_down: gnd_500k diff --git a/tests/components/mcp47a1/test.esp32-c3-idf.yaml b/tests/components/mcp47a1/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..68273e00eb --- /dev/null +++ b/tests/components/mcp47a1/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 5 + sda: 4 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp47a1/test.esp32-c3.yaml b/tests/components/mcp47a1/test.esp32-c3.yaml new file mode 100644 index 0000000000..68273e00eb --- /dev/null +++ b/tests/components/mcp47a1/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 5 + sda: 4 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp47a1/test.esp32-idf.yaml b/tests/components/mcp47a1/test.esp32-idf.yaml new file mode 100644 index 0000000000..9e2133de66 --- /dev/null +++ b/tests/components/mcp47a1/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 16 + sda: 17 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp47a1/test.esp32.yaml b/tests/components/mcp47a1/test.esp32.yaml new file mode 100644 index 0000000000..9e2133de66 --- /dev/null +++ b/tests/components/mcp47a1/test.esp32.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 16 + sda: 17 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp47a1/test.esp8266.yaml b/tests/components/mcp47a1/test.esp8266.yaml new file mode 100644 index 0000000000..68273e00eb --- /dev/null +++ b/tests/components/mcp47a1/test.esp8266.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 5 + sda: 4 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp47a1/test.rp2040.yaml b/tests/components/mcp47a1/test.rp2040.yaml new file mode 100644 index 0000000000..68273e00eb --- /dev/null +++ b/tests/components/mcp47a1/test.rp2040.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp47a1 + scl: 5 + sda: 4 + +output: + - platform: mcp47a1 + id: output_mcp47a1 diff --git a/tests/components/mcp9600/test.esp32-c3-idf.yaml b/tests/components/mcp9600/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b07f4589ce --- /dev/null +++ b/tests/components/mcp9600/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9600/test.esp32-c3.yaml b/tests/components/mcp9600/test.esp32-c3.yaml new file mode 100644 index 0000000000..b07f4589ce --- /dev/null +++ b/tests/components/mcp9600/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9600/test.esp32-idf.yaml b/tests/components/mcp9600/test.esp32-idf.yaml new file mode 100644 index 0000000000..0c94f099ae --- /dev/null +++ b/tests/components/mcp9600/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 16 + sda: 17 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9600/test.esp32.yaml b/tests/components/mcp9600/test.esp32.yaml new file mode 100644 index 0000000000..0c94f099ae --- /dev/null +++ b/tests/components/mcp9600/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 16 + sda: 17 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9600/test.esp8266.yaml b/tests/components/mcp9600/test.esp8266.yaml new file mode 100644 index 0000000000..b07f4589ce --- /dev/null +++ b/tests/components/mcp9600/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9600/test.rp2040.yaml b/tests/components/mcp9600/test.rp2040.yaml new file mode 100644 index 0000000000..b07f4589ce --- /dev/null +++ b/tests/components/mcp9600/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mcp9600 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9600 + thermocouple_type: K + hot_junction: + name: Thermocouple Temperature + cold_junction: + name: Ambient Temperature diff --git a/tests/components/mcp9808/test.esp32-c3-idf.yaml b/tests/components/mcp9808/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..86b4d7f181 --- /dev/null +++ b/tests/components/mcp9808/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mcp9808/test.esp32-c3.yaml b/tests/components/mcp9808/test.esp32-c3.yaml new file mode 100644 index 0000000000..86b4d7f181 --- /dev/null +++ b/tests/components/mcp9808/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mcp9808/test.esp32-idf.yaml b/tests/components/mcp9808/test.esp32-idf.yaml new file mode 100644 index 0000000000..1e5affdac0 --- /dev/null +++ b/tests/components/mcp9808/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 16 + sda: 17 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mcp9808/test.esp32.yaml b/tests/components/mcp9808/test.esp32.yaml new file mode 100644 index 0000000000..1e5affdac0 --- /dev/null +++ b/tests/components/mcp9808/test.esp32.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 16 + sda: 17 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mcp9808/test.esp8266.yaml b/tests/components/mcp9808/test.esp8266.yaml new file mode 100644 index 0000000000..86b4d7f181 --- /dev/null +++ b/tests/components/mcp9808/test.esp8266.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mcp9808/test.rp2040.yaml b/tests/components/mcp9808/test.rp2040.yaml new file mode 100644 index 0000000000..86b4d7f181 --- /dev/null +++ b/tests/components/mcp9808/test.rp2040.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_mcp9808 + scl: 5 + sda: 4 + +sensor: + - platform: mcp9808 + name: MCP9808 Temperature diff --git a/tests/components/mdns/test.esp32-c3-idf.yaml b/tests/components/mdns/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.esp32-c3.yaml b/tests/components/mdns/test.esp32-c3.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.esp32-idf.yaml b/tests/components/mdns/test.esp32-idf.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.esp32.yaml b/tests/components/mdns/test.esp32.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.esp32.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.esp8266.yaml b/tests/components/mdns/test.esp8266.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.esp8266.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.rp2040.yaml b/tests/components/mdns/test.rp2040.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/test.rp2040.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/media_player/test.esp32.yaml b/tests/components/media_player/test.esp32.yaml new file mode 100644 index 0000000000..24b85cd474 --- /dev/null +++ b/tests/components/media_player/test.esp32.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +i2s_audio: + i2s_lrclk_pin: 13 + i2s_bclk_pin: 14 + i2s_mclk_pin: 15 + +media_player: + - platform: i2s_audio + name: None + dac_type: external + i2s_dout_pin: 18 + mute_pin: 19 + on_state: + - media_player.play: + - media_player.play_media: http://localhost/media.mp3 + - media_player.play_media: !lambda 'return "http://localhost/media.mp3";' + on_idle: + - media_player.pause: + on_play: + - media_player.stop: + on_pause: + - media_player.toggle: + - wait_until: + media_player.is_idle: + - wait_until: + media_player.is_playing: + - media_player.volume_up: + - media_player.volume_down: + - media_player.volume_set: 50% diff --git a/tests/components/mhz19/test.esp32-c3-idf.yaml b/tests/components/mhz19/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1edfa49c23 --- /dev/null +++ b/tests/components/mhz19/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s diff --git a/tests/components/mhz19/test.esp32-c3.yaml b/tests/components/mhz19/test.esp32-c3.yaml new file mode 100644 index 0000000000..1edfa49c23 --- /dev/null +++ b/tests/components/mhz19/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s diff --git a/tests/components/mhz19/test.esp32-idf.yaml b/tests/components/mhz19/test.esp32-idf.yaml new file mode 100644 index 0000000000..0e30713b54 --- /dev/null +++ b/tests/components/mhz19/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s diff --git a/tests/components/mhz19/test.esp32.yaml b/tests/components/mhz19/test.esp32.yaml new file mode 100644 index 0000000000..0e30713b54 --- /dev/null +++ b/tests/components/mhz19/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s diff --git a/tests/components/mhz19/test.esp8266.yaml b/tests/components/mhz19/test.esp8266.yaml new file mode 100644 index 0000000000..1edfa49c23 --- /dev/null +++ b/tests/components/mhz19/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s diff --git a/tests/components/mhz19/test.rp2040.yaml b/tests/components/mhz19/test.rp2040.yaml new file mode 100644 index 0000000000..1edfa49c23 --- /dev/null +++ b/tests/components/mhz19/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_mhz19 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: mhz19 + co2: + name: MH-Z19 CO2 Value + temperature: + name: MH-Z19 Temperature + automatic_baseline_calibration: false + update_interval: 15s From c0dc9c20fc7b383659d962cf4ef6de283ca45ba1 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 22:45:25 -0500 Subject: [PATCH 1602/2607] Add some components to the new testing framework (M part 2) (#6208) --- .../micronova/test.esp32-c3-idf.yaml | 49 +++++++++++++++ tests/components/micronova/test.esp32-c3.yaml | 49 +++++++++++++++ .../components/micronova/test.esp32-idf.yaml | 49 +++++++++++++++ tests/components/micronova/test.esp32.yaml | 49 +++++++++++++++ tests/components/micronova/test.esp8266.yaml | 49 +++++++++++++++ tests/components/micronova/test.rp2040.yaml | 49 +++++++++++++++ .../microphone/test.esp32-c3-idf.yaml | 11 ++++ .../components/microphone/test.esp32-c3.yaml | 11 ++++ .../components/microphone/test.esp32-idf.yaml | 15 +++++ tests/components/microphone/test.esp32.yaml | 15 +++++ .../mics_4514/test.esp32-c3-idf.yaml | 20 +++++++ tests/components/mics_4514/test.esp32-c3.yaml | 20 +++++++ .../components/mics_4514/test.esp32-idf.yaml | 20 +++++++ tests/components/mics_4514/test.esp32.yaml | 20 +++++++ tests/components/mics_4514/test.esp8266.yaml | 20 +++++++ tests/components/mics_4514/test.rp2040.yaml | 20 +++++++ tests/components/midea/test.esp32-c3.yaml | 59 +++++++++++++++++++ tests/components/midea/test.esp32.yaml | 59 +++++++++++++++++++ tests/components/midea/test.esp8266.yaml | 59 +++++++++++++++++++ .../midea_ir/test.esp32-c3-idf.yaml | 8 +++ tests/components/midea_ir/test.esp32-c3.yaml | 8 +++ tests/components/midea_ir/test.esp32-idf.yaml | 8 +++ tests/components/midea_ir/test.esp32.yaml | 8 +++ tests/components/midea_ir/test.esp8266.yaml | 8 +++ .../mitsubishi/test.esp32-c3-idf.yaml | 7 +++ .../components/mitsubishi/test.esp32-c3.yaml | 7 +++ .../components/mitsubishi/test.esp32-idf.yaml | 7 +++ tests/components/mitsubishi/test.esp32.yaml | 7 +++ tests/components/mitsubishi/test.esp8266.yaml | 7 +++ .../mlx90393/test.esp32-c3-idf.yaml | 20 +++++++ tests/components/mlx90393/test.esp32-c3.yaml | 20 +++++++ tests/components/mlx90393/test.esp32-idf.yaml | 20 +++++++ tests/components/mlx90393/test.esp32.yaml | 20 +++++++ tests/components/mlx90393/test.esp8266.yaml | 20 +++++++ tests/components/mlx90393/test.rp2040.yaml | 20 +++++++ .../mlx90614/test.esp32-c3-idf.yaml | 12 ++++ tests/components/mlx90614/test.esp32-c3.yaml | 12 ++++ tests/components/mlx90614/test.esp32-idf.yaml | 12 ++++ tests/components/mlx90614/test.esp32.yaml | 12 ++++ tests/components/mlx90614/test.esp8266.yaml | 12 ++++ tests/components/mlx90614/test.rp2040.yaml | 12 ++++ .../components/mmc5603/test.esp32-c3-idf.yaml | 14 +++++ tests/components/mmc5603/test.esp32-c3.yaml | 14 +++++ tests/components/mmc5603/test.esp32-idf.yaml | 14 +++++ tests/components/mmc5603/test.esp32.yaml | 14 +++++ tests/components/mmc5603/test.esp8266.yaml | 14 +++++ tests/components/mmc5603/test.rp2040.yaml | 14 +++++ .../components/mmc5983/test.esp32-c3-idf.yaml | 16 +++++ tests/components/mmc5983/test.esp32-c3.yaml | 16 +++++ tests/components/mmc5983/test.esp32-idf.yaml | 16 +++++ tests/components/mmc5983/test.esp32.yaml | 16 +++++ tests/components/mmc5983/test.esp8266.yaml | 16 +++++ tests/components/mmc5983/test.rp2040.yaml | 16 +++++ .../components/modbus/test.esp32-c3-idf.yaml | 9 +++ tests/components/modbus/test.esp32-c3.yaml | 9 +++ tests/components/modbus/test.esp32-idf.yaml | 9 +++ tests/components/modbus/test.esp32.yaml | 9 +++ tests/components/modbus/test.esp8266.yaml | 9 +++ tests/components/modbus/test.rp2040.yaml | 9 +++ .../modbus_controller/test.esp32-c3-idf.yaml | 14 +++++ .../modbus_controller/test.esp32-c3.yaml | 14 +++++ .../modbus_controller/test.esp32-idf.yaml | 14 +++++ .../modbus_controller/test.esp32.yaml | 14 +++++ .../modbus_controller/test.esp8266.yaml | 14 +++++ .../modbus_controller/test.rp2040.yaml | 14 +++++ .../monochromatic/test.esp32-c3-idf.yaml | 40 +++++++++++++ .../monochromatic/test.esp32-c3.yaml | 40 +++++++++++++ .../monochromatic/test.esp32-idf.yaml | 40 +++++++++++++ .../components/monochromatic/test.esp32.yaml | 40 +++++++++++++ .../monochromatic/test.esp8266.yaml | 40 +++++++++++++ .../components/monochromatic/test.rp2040.yaml | 40 +++++++++++++ .../mopeka_ble/test.esp32-c3-idf.yaml | 3 + .../components/mopeka_ble/test.esp32-c3.yaml | 3 + .../components/mopeka_ble/test.esp32-idf.yaml | 3 + tests/components/mopeka_ble/test.esp32.yaml | 3 + .../mopeka_pro_check/test.esp32-c3-idf.yaml | 16 +++++ .../mopeka_pro_check/test.esp32-c3.yaml | 16 +++++ .../mopeka_pro_check/test.esp32-idf.yaml | 16 +++++ .../mopeka_pro_check/test.esp32.yaml | 16 +++++ .../mopeka_std_check/test.esp32-c3-idf.yaml | 16 +++++ .../mopeka_std_check/test.esp32-c3.yaml | 16 +++++ .../mopeka_std_check/test.esp32-idf.yaml | 16 +++++ .../mpl3115a2/test.esp32-c3-idf.yaml | 12 ++++ tests/components/mpl3115a2/test.esp32-c3.yaml | 12 ++++ .../components/mpl3115a2/test.esp32-idf.yaml | 12 ++++ tests/components/mpl3115a2/test.esp32.yaml | 12 ++++ tests/components/mpl3115a2/test.esp8266.yaml | 12 ++++ tests/components/mpl3115a2/test.rp2040.yaml | 12 ++++ .../components/mpr121/test.esp32-c3-idf.yaml | 26 ++++++++ tests/components/mpr121/test.esp32-c3.yaml | 26 ++++++++ tests/components/mpr121/test.esp32-idf.yaml | 26 ++++++++ tests/components/mpr121/test.esp32.yaml | 26 ++++++++ tests/components/mpr121/test.esp8266.yaml | 26 ++++++++ tests/components/mpr121/test.rp2040.yaml | 26 ++++++++ .../components/mpu6050/test.esp32-c3-idf.yaml | 22 +++++++ tests/components/mpu6050/test.esp32-c3.yaml | 22 +++++++ tests/components/mpu6050/test.esp32-idf.yaml | 22 +++++++ tests/components/mpu6050/test.esp32.yaml | 22 +++++++ tests/components/mpu6050/test.esp8266.yaml | 22 +++++++ tests/components/mpu6050/test.rp2040.yaml | 22 +++++++ .../components/mpu6886/test.esp32-c3-idf.yaml | 22 +++++++ tests/components/mpu6886/test.esp32-c3.yaml | 22 +++++++ tests/components/mpu6886/test.esp32-idf.yaml | 22 +++++++ tests/components/mpu6886/test.esp32.yaml | 22 +++++++ tests/components/mpu6886/test.esp8266.yaml | 22 +++++++ tests/components/mpu6886/test.rp2040.yaml | 22 +++++++ tests/components/mqtt/test.esp32-c3-idf.yaml | 16 +++++ tests/components/mqtt/test.esp32-c3.yaml | 15 +++++ tests/components/mqtt/test.esp32-idf.yaml | 16 +++++ tests/components/mqtt/test.esp32.yaml | 15 +++++ tests/components/mqtt/test.esp8266.yaml | 15 +++++ .../mqtt_subscribe/test.esp32-c3-idf.yaml | 37 ++++++++++++ .../mqtt_subscribe/test.esp32-c3.yaml | 36 +++++++++++ .../mqtt_subscribe/test.esp32-idf.yaml | 37 ++++++++++++ .../components/mqtt_subscribe/test.esp32.yaml | 36 +++++++++++ .../mqtt_subscribe/test.esp8266.yaml | 36 +++++++++++ .../components/ms5611/test.esp32-c3-idf.yaml | 13 ++++ tests/components/ms5611/test.esp32-c3.yaml | 13 ++++ tests/components/ms5611/test.esp32-idf.yaml | 13 ++++ tests/components/ms5611/test.esp32.yaml | 13 ++++ tests/components/ms5611/test.esp8266.yaml | 13 ++++ tests/components/ms5611/test.rp2040.yaml | 13 ++++ .../components/my9231/test.esp32-c3-idf.yaml | 26 ++++++++ tests/components/my9231/test.esp32-c3.yaml | 26 ++++++++ tests/components/my9231/test.esp32-idf.yaml | 26 ++++++++ tests/components/my9231/test.esp32.yaml | 26 ++++++++ tests/components/my9231/test.esp8266.yaml | 26 ++++++++ tests/components/my9231/test.rp2040.yaml | 26 ++++++++ 128 files changed, 2577 insertions(+) create mode 100644 tests/components/micronova/test.esp32-c3-idf.yaml create mode 100644 tests/components/micronova/test.esp32-c3.yaml create mode 100644 tests/components/micronova/test.esp32-idf.yaml create mode 100644 tests/components/micronova/test.esp32.yaml create mode 100644 tests/components/micronova/test.esp8266.yaml create mode 100644 tests/components/micronova/test.rp2040.yaml create mode 100644 tests/components/microphone/test.esp32-c3-idf.yaml create mode 100644 tests/components/microphone/test.esp32-c3.yaml create mode 100644 tests/components/microphone/test.esp32-idf.yaml create mode 100644 tests/components/microphone/test.esp32.yaml create mode 100644 tests/components/mics_4514/test.esp32-c3-idf.yaml create mode 100644 tests/components/mics_4514/test.esp32-c3.yaml create mode 100644 tests/components/mics_4514/test.esp32-idf.yaml create mode 100644 tests/components/mics_4514/test.esp32.yaml create mode 100644 tests/components/mics_4514/test.esp8266.yaml create mode 100644 tests/components/mics_4514/test.rp2040.yaml create mode 100644 tests/components/midea/test.esp32-c3.yaml create mode 100644 tests/components/midea/test.esp32.yaml create mode 100644 tests/components/midea/test.esp8266.yaml create mode 100644 tests/components/midea_ir/test.esp32-c3-idf.yaml create mode 100644 tests/components/midea_ir/test.esp32-c3.yaml create mode 100644 tests/components/midea_ir/test.esp32-idf.yaml create mode 100644 tests/components/midea_ir/test.esp32.yaml create mode 100644 tests/components/midea_ir/test.esp8266.yaml create mode 100644 tests/components/mitsubishi/test.esp32-c3-idf.yaml create mode 100644 tests/components/mitsubishi/test.esp32-c3.yaml create mode 100644 tests/components/mitsubishi/test.esp32-idf.yaml create mode 100644 tests/components/mitsubishi/test.esp32.yaml create mode 100644 tests/components/mitsubishi/test.esp8266.yaml create mode 100644 tests/components/mlx90393/test.esp32-c3-idf.yaml create mode 100644 tests/components/mlx90393/test.esp32-c3.yaml create mode 100644 tests/components/mlx90393/test.esp32-idf.yaml create mode 100644 tests/components/mlx90393/test.esp32.yaml create mode 100644 tests/components/mlx90393/test.esp8266.yaml create mode 100644 tests/components/mlx90393/test.rp2040.yaml create mode 100644 tests/components/mlx90614/test.esp32-c3-idf.yaml create mode 100644 tests/components/mlx90614/test.esp32-c3.yaml create mode 100644 tests/components/mlx90614/test.esp32-idf.yaml create mode 100644 tests/components/mlx90614/test.esp32.yaml create mode 100644 tests/components/mlx90614/test.esp8266.yaml create mode 100644 tests/components/mlx90614/test.rp2040.yaml create mode 100644 tests/components/mmc5603/test.esp32-c3-idf.yaml create mode 100644 tests/components/mmc5603/test.esp32-c3.yaml create mode 100644 tests/components/mmc5603/test.esp32-idf.yaml create mode 100644 tests/components/mmc5603/test.esp32.yaml create mode 100644 tests/components/mmc5603/test.esp8266.yaml create mode 100644 tests/components/mmc5603/test.rp2040.yaml create mode 100644 tests/components/mmc5983/test.esp32-c3-idf.yaml create mode 100644 tests/components/mmc5983/test.esp32-c3.yaml create mode 100644 tests/components/mmc5983/test.esp32-idf.yaml create mode 100644 tests/components/mmc5983/test.esp32.yaml create mode 100644 tests/components/mmc5983/test.esp8266.yaml create mode 100644 tests/components/mmc5983/test.rp2040.yaml create mode 100644 tests/components/modbus/test.esp32-c3-idf.yaml create mode 100644 tests/components/modbus/test.esp32-c3.yaml create mode 100644 tests/components/modbus/test.esp32-idf.yaml create mode 100644 tests/components/modbus/test.esp32.yaml create mode 100644 tests/components/modbus/test.esp8266.yaml create mode 100644 tests/components/modbus/test.rp2040.yaml create mode 100644 tests/components/modbus_controller/test.esp32-c3-idf.yaml create mode 100644 tests/components/modbus_controller/test.esp32-c3.yaml create mode 100644 tests/components/modbus_controller/test.esp32-idf.yaml create mode 100644 tests/components/modbus_controller/test.esp32.yaml create mode 100644 tests/components/modbus_controller/test.esp8266.yaml create mode 100644 tests/components/modbus_controller/test.rp2040.yaml create mode 100644 tests/components/monochromatic/test.esp32-c3-idf.yaml create mode 100644 tests/components/monochromatic/test.esp32-c3.yaml create mode 100644 tests/components/monochromatic/test.esp32-idf.yaml create mode 100644 tests/components/monochromatic/test.esp32.yaml create mode 100644 tests/components/monochromatic/test.esp8266.yaml create mode 100644 tests/components/monochromatic/test.rp2040.yaml create mode 100644 tests/components/mopeka_ble/test.esp32-c3-idf.yaml create mode 100644 tests/components/mopeka_ble/test.esp32-c3.yaml create mode 100644 tests/components/mopeka_ble/test.esp32-idf.yaml create mode 100644 tests/components/mopeka_ble/test.esp32.yaml create mode 100644 tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml create mode 100644 tests/components/mopeka_pro_check/test.esp32-c3.yaml create mode 100644 tests/components/mopeka_pro_check/test.esp32-idf.yaml create mode 100644 tests/components/mopeka_pro_check/test.esp32.yaml create mode 100644 tests/components/mopeka_std_check/test.esp32-c3-idf.yaml create mode 100644 tests/components/mopeka_std_check/test.esp32-c3.yaml create mode 100644 tests/components/mopeka_std_check/test.esp32-idf.yaml create mode 100644 tests/components/mpl3115a2/test.esp32-c3-idf.yaml create mode 100644 tests/components/mpl3115a2/test.esp32-c3.yaml create mode 100644 tests/components/mpl3115a2/test.esp32-idf.yaml create mode 100644 tests/components/mpl3115a2/test.esp32.yaml create mode 100644 tests/components/mpl3115a2/test.esp8266.yaml create mode 100644 tests/components/mpl3115a2/test.rp2040.yaml create mode 100644 tests/components/mpr121/test.esp32-c3-idf.yaml create mode 100644 tests/components/mpr121/test.esp32-c3.yaml create mode 100644 tests/components/mpr121/test.esp32-idf.yaml create mode 100644 tests/components/mpr121/test.esp32.yaml create mode 100644 tests/components/mpr121/test.esp8266.yaml create mode 100644 tests/components/mpr121/test.rp2040.yaml create mode 100644 tests/components/mpu6050/test.esp32-c3-idf.yaml create mode 100644 tests/components/mpu6050/test.esp32-c3.yaml create mode 100644 tests/components/mpu6050/test.esp32-idf.yaml create mode 100644 tests/components/mpu6050/test.esp32.yaml create mode 100644 tests/components/mpu6050/test.esp8266.yaml create mode 100644 tests/components/mpu6050/test.rp2040.yaml create mode 100644 tests/components/mpu6886/test.esp32-c3-idf.yaml create mode 100644 tests/components/mpu6886/test.esp32-c3.yaml create mode 100644 tests/components/mpu6886/test.esp32-idf.yaml create mode 100644 tests/components/mpu6886/test.esp32.yaml create mode 100644 tests/components/mpu6886/test.esp8266.yaml create mode 100644 tests/components/mpu6886/test.rp2040.yaml create mode 100644 tests/components/mqtt/test.esp32-c3-idf.yaml create mode 100644 tests/components/mqtt/test.esp32-c3.yaml create mode 100644 tests/components/mqtt/test.esp32-idf.yaml create mode 100644 tests/components/mqtt/test.esp32.yaml create mode 100644 tests/components/mqtt/test.esp8266.yaml create mode 100644 tests/components/mqtt_subscribe/test.esp32-c3-idf.yaml create mode 100644 tests/components/mqtt_subscribe/test.esp32-c3.yaml create mode 100644 tests/components/mqtt_subscribe/test.esp32-idf.yaml create mode 100644 tests/components/mqtt_subscribe/test.esp32.yaml create mode 100644 tests/components/mqtt_subscribe/test.esp8266.yaml create mode 100644 tests/components/ms5611/test.esp32-c3-idf.yaml create mode 100644 tests/components/ms5611/test.esp32-c3.yaml create mode 100644 tests/components/ms5611/test.esp32-idf.yaml create mode 100644 tests/components/ms5611/test.esp32.yaml create mode 100644 tests/components/ms5611/test.esp8266.yaml create mode 100644 tests/components/ms5611/test.rp2040.yaml create mode 100644 tests/components/my9231/test.esp32-c3-idf.yaml create mode 100644 tests/components/my9231/test.esp32-c3.yaml create mode 100644 tests/components/my9231/test.esp32-idf.yaml create mode 100644 tests/components/my9231/test.esp32.yaml create mode 100644 tests/components/my9231/test.esp8266.yaml create mode 100644 tests/components/my9231/test.rp2040.yaml diff --git a/tests/components/micronova/test.esp32-c3-idf.yaml b/tests/components/micronova/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ec9699909e --- /dev/null +++ b/tests/components/micronova/test.esp32-c3-idf.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +micronova: + enable_rx_pin: 6 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/micronova/test.esp32-c3.yaml b/tests/components/micronova/test.esp32-c3.yaml new file mode 100644 index 0000000000..ec9699909e --- /dev/null +++ b/tests/components/micronova/test.esp32-c3.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +micronova: + enable_rx_pin: 6 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/micronova/test.esp32-idf.yaml b/tests/components/micronova/test.esp32-idf.yaml new file mode 100644 index 0000000000..9156f7d6a9 --- /dev/null +++ b/tests/components/micronova/test.esp32-idf.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +micronova: + enable_rx_pin: 18 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/micronova/test.esp32.yaml b/tests/components/micronova/test.esp32.yaml new file mode 100644 index 0000000000..9156f7d6a9 --- /dev/null +++ b/tests/components/micronova/test.esp32.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +micronova: + enable_rx_pin: 18 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/micronova/test.esp8266.yaml b/tests/components/micronova/test.esp8266.yaml new file mode 100644 index 0000000000..d10ab7ad7a --- /dev/null +++ b/tests/components/micronova/test.esp8266.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +micronova: + enable_rx_pin: 16 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/micronova/test.rp2040.yaml b/tests/components/micronova/test.rp2040.yaml new file mode 100644 index 0000000000..ec9699909e --- /dev/null +++ b/tests/components/micronova/test.rp2040.yaml @@ -0,0 +1,49 @@ +uart: + - id: uart_micronova + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +micronova: + enable_rx_pin: 6 + +button: + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F + +number: + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level + +sensor: + - platform: micronova + room_temperature: + name: Room Temperature + fumes_temperature: + name: Fumes Temperature + water_temperature: + name: Water temperature + water_pressure: + name: Water pressure + stove_power: + name: Stove Power + fan_speed: + fan_rpm_offset: 240 + name: Fan RPM + memory_address_sensor: + memory_location: 0x20 + memory_address: 0x7d + name: Adres sensor + +switch: + - platform: micronova + stove: + name: Stove on/off diff --git a/tests/components/microphone/test.esp32-c3-idf.yaml b/tests/components/microphone/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..706a38f910 --- /dev/null +++ b/tests/components/microphone/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 8 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 3 + adc_type: external + pdm: false diff --git a/tests/components/microphone/test.esp32-c3.yaml b/tests/components/microphone/test.esp32-c3.yaml new file mode 100644 index 0000000000..706a38f910 --- /dev/null +++ b/tests/components/microphone/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 8 + +microphone: + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 3 + adc_type: external + pdm: false diff --git a/tests/components/microphone/test.esp32-idf.yaml b/tests/components/microphone/test.esp32-idf.yaml new file mode 100644 index 0000000000..166eedb54d --- /dev/null +++ b/tests/components/microphone/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2s_audio: + i2s_lrclk_pin: 13 + i2s_bclk_pin: 14 + i2s_mclk_pin: 15 + +microphone: + - platform: i2s_audio + id: mic_id_adc + adc_pin: 32 + adc_type: internal + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 33 + adc_type: external + pdm: false diff --git a/tests/components/microphone/test.esp32.yaml b/tests/components/microphone/test.esp32.yaml new file mode 100644 index 0000000000..166eedb54d --- /dev/null +++ b/tests/components/microphone/test.esp32.yaml @@ -0,0 +1,15 @@ +i2s_audio: + i2s_lrclk_pin: 13 + i2s_bclk_pin: 14 + i2s_mclk_pin: 15 + +microphone: + - platform: i2s_audio + id: mic_id_adc + adc_pin: 32 + adc_type: internal + - platform: i2s_audio + id: mic_id_external + i2s_din_pin: 33 + adc_type: external + pdm: false diff --git a/tests/components/mics_4514/test.esp32-c3-idf.yaml b/tests/components/mics_4514/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..72369bec01 --- /dev/null +++ b/tests/components/mics_4514/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 5 + sda: 4 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/mics_4514/test.esp32-c3.yaml b/tests/components/mics_4514/test.esp32-c3.yaml new file mode 100644 index 0000000000..72369bec01 --- /dev/null +++ b/tests/components/mics_4514/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 5 + sda: 4 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/mics_4514/test.esp32-idf.yaml b/tests/components/mics_4514/test.esp32-idf.yaml new file mode 100644 index 0000000000..234839c91c --- /dev/null +++ b/tests/components/mics_4514/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 16 + sda: 17 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/mics_4514/test.esp32.yaml b/tests/components/mics_4514/test.esp32.yaml new file mode 100644 index 0000000000..234839c91c --- /dev/null +++ b/tests/components/mics_4514/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 16 + sda: 17 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/mics_4514/test.esp8266.yaml b/tests/components/mics_4514/test.esp8266.yaml new file mode 100644 index 0000000000..72369bec01 --- /dev/null +++ b/tests/components/mics_4514/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 5 + sda: 4 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/mics_4514/test.rp2040.yaml b/tests/components/mics_4514/test.rp2040.yaml new file mode 100644 index 0000000000..72369bec01 --- /dev/null +++ b/tests/components/mics_4514/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mics_4514 + scl: 5 + sda: 4 + +sensor: + - platform: mics_4514 + update_interval: 60s + nitrogen_dioxide: + name: MICS-4514 NO2 + carbon_monoxide: + name: MICS-4514 CO + methane: + name: MICS-4514 CH4 + hydrogen: + name: MICS-4514 H2 + ethanol: + name: MICS-4514 C2H5OH + ammonia: + name: MICS-4514 NH3 diff --git a/tests/components/midea/test.esp32-c3.yaml b/tests/components/midea/test.esp32-c3.yaml new file mode 100644 index 0000000000..bcb8635eaf --- /dev/null +++ b/tests/components/midea/test.esp32-c3.yaml @@ -0,0 +1,59 @@ +wifi: + ssid: MySSID + password: password1 + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +uart: + - id: uart_midea + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +climate: + - platform: midea + id: midea_unit + name: Midea Climate + on_control: + - logger.log: Control message received! + - lambda: |- + x.set_mode(CLIMATE_MODE_FAN_ONLY); + on_state: + - logger.log: State changed! + transmitter_id: + period: 1s + num_attempts: 5 + timeout: 2s + beeper: false + autoconf: true + visual: + min_temperature: 17 °C + max_temperature: 30 °C + temperature_step: 0.5 °C + supported_modes: + - FAN_ONLY + - HEAT_COOL + - COOL + - HEAT + - DRY + custom_fan_modes: + - SILENT + - TURBO + supported_presets: + - ECO + - BOOST + - SLEEP + custom_presets: + - FREEZE_PROTECTION + supported_swing_modes: + - VERTICAL + - HORIZONTAL + - BOTH + outdoor_temperature: + name: Temp + power_usage: + name: Power + humidity_setpoint: + name: Humidity diff --git a/tests/components/midea/test.esp32.yaml b/tests/components/midea/test.esp32.yaml new file mode 100644 index 0000000000..5c638b9613 --- /dev/null +++ b/tests/components/midea/test.esp32.yaml @@ -0,0 +1,59 @@ +wifi: + ssid: MySSID + password: password1 + +remote_transmitter: + pin: 18 + carrier_duty_percent: 50% + +uart: + - id: uart_midea + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +climate: + - platform: midea + id: midea_unit + name: Midea Climate + on_control: + - logger.log: Control message received! + - lambda: |- + x.set_mode(CLIMATE_MODE_FAN_ONLY); + on_state: + - logger.log: State changed! + transmitter_id: + period: 1s + num_attempts: 5 + timeout: 2s + beeper: false + autoconf: true + visual: + min_temperature: 17 °C + max_temperature: 30 °C + temperature_step: 0.5 °C + supported_modes: + - FAN_ONLY + - HEAT_COOL + - COOL + - HEAT + - DRY + custom_fan_modes: + - SILENT + - TURBO + supported_presets: + - ECO + - BOOST + - SLEEP + custom_presets: + - FREEZE_PROTECTION + supported_swing_modes: + - VERTICAL + - HORIZONTAL + - BOTH + outdoor_temperature: + name: Temp + power_usage: + name: Power + humidity_setpoint: + name: Humidity diff --git a/tests/components/midea/test.esp8266.yaml b/tests/components/midea/test.esp8266.yaml new file mode 100644 index 0000000000..b0ed7eb472 --- /dev/null +++ b/tests/components/midea/test.esp8266.yaml @@ -0,0 +1,59 @@ +wifi: + ssid: MySSID + password: password1 + +remote_transmitter: + pin: 12 + carrier_duty_percent: 50% + +uart: + - id: uart_midea + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +climate: + - platform: midea + id: midea_unit + name: Midea Climate + on_control: + - logger.log: Control message received! + - lambda: |- + x.set_mode(CLIMATE_MODE_FAN_ONLY); + on_state: + - logger.log: State changed! + transmitter_id: + period: 1s + num_attempts: 5 + timeout: 2s + beeper: false + autoconf: true + visual: + min_temperature: 17 °C + max_temperature: 30 °C + temperature_step: 0.5 °C + supported_modes: + - FAN_ONLY + - HEAT_COOL + - COOL + - HEAT + - DRY + custom_fan_modes: + - SILENT + - TURBO + supported_presets: + - ECO + - BOOST + - SLEEP + custom_presets: + - FREEZE_PROTECTION + supported_swing_modes: + - VERTICAL + - HORIZONTAL + - BOTH + outdoor_temperature: + name: Temp + power_usage: + name: Power + humidity_setpoint: + name: Humidity diff --git a/tests/components/midea_ir/test.esp32-c3-idf.yaml b/tests/components/midea_ir/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/midea_ir/test.esp32-c3.yaml b/tests/components/midea_ir/test.esp32-c3.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/midea_ir/test.esp32-idf.yaml b/tests/components/midea_ir/test.esp32-idf.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/midea_ir/test.esp32.yaml b/tests/components/midea_ir/test.esp32.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/test.esp32.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/midea_ir/test.esp8266.yaml b/tests/components/midea_ir/test.esp8266.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/test.esp8266.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/mitsubishi/test.esp32-c3-idf.yaml b/tests/components/mitsubishi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mitsubishi/test.esp32-c3.yaml b/tests/components/mitsubishi/test.esp32-c3.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mitsubishi/test.esp32-idf.yaml b/tests/components/mitsubishi/test.esp32-idf.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mitsubishi/test.esp32.yaml b/tests/components/mitsubishi/test.esp32.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mitsubishi/test.esp8266.yaml b/tests/components/mitsubishi/test.esp8266.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mlx90393/test.esp32-c3-idf.yaml b/tests/components/mlx90393/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..549eea8032 --- /dev/null +++ b/tests/components/mlx90393/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90393/test.esp32-c3.yaml b/tests/components/mlx90393/test.esp32-c3.yaml new file mode 100644 index 0000000000..549eea8032 --- /dev/null +++ b/tests/components/mlx90393/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90393/test.esp32-idf.yaml b/tests/components/mlx90393/test.esp32-idf.yaml new file mode 100644 index 0000000000..089fd136f4 --- /dev/null +++ b/tests/components/mlx90393/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 16 + sda: 17 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90393/test.esp32.yaml b/tests/components/mlx90393/test.esp32.yaml new file mode 100644 index 0000000000..089fd136f4 --- /dev/null +++ b/tests/components/mlx90393/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 16 + sda: 17 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90393/test.esp8266.yaml b/tests/components/mlx90393/test.esp8266.yaml new file mode 100644 index 0000000000..549eea8032 --- /dev/null +++ b/tests/components/mlx90393/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90393/test.rp2040.yaml b/tests/components/mlx90393/test.rp2040.yaml new file mode 100644 index 0000000000..549eea8032 --- /dev/null +++ b/tests/components/mlx90393/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_mlx90393 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 diff --git a/tests/components/mlx90614/test.esp32-c3-idf.yaml b/tests/components/mlx90614/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a863e0ee2e --- /dev/null +++ b/tests/components/mlx90614/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mlx90614/test.esp32-c3.yaml b/tests/components/mlx90614/test.esp32-c3.yaml new file mode 100644 index 0000000000..a863e0ee2e --- /dev/null +++ b/tests/components/mlx90614/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mlx90614/test.esp32-idf.yaml b/tests/components/mlx90614/test.esp32-idf.yaml new file mode 100644 index 0000000000..8c1ee68f42 --- /dev/null +++ b/tests/components/mlx90614/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 16 + sda: 17 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mlx90614/test.esp32.yaml b/tests/components/mlx90614/test.esp32.yaml new file mode 100644 index 0000000000..8c1ee68f42 --- /dev/null +++ b/tests/components/mlx90614/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 16 + sda: 17 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mlx90614/test.esp8266.yaml b/tests/components/mlx90614/test.esp8266.yaml new file mode 100644 index 0000000000..a863e0ee2e --- /dev/null +++ b/tests/components/mlx90614/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mlx90614/test.rp2040.yaml b/tests/components/mlx90614/test.rp2040.yaml new file mode 100644 index 0000000000..a863e0ee2e --- /dev/null +++ b/tests/components/mlx90614/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mlx90614 + scl: 5 + sda: 4 + +sensor: + - platform: mlx90614 + ambient: + name: Ambient + object: + name: Object + emissivity: 1.0 diff --git a/tests/components/mmc5603/test.esp32-c3-idf.yaml b/tests/components/mmc5603/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..834591bb39 --- /dev/null +++ b/tests/components/mmc5603/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5603/test.esp32-c3.yaml b/tests/components/mmc5603/test.esp32-c3.yaml new file mode 100644 index 0000000000..834591bb39 --- /dev/null +++ b/tests/components/mmc5603/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5603/test.esp32-idf.yaml b/tests/components/mmc5603/test.esp32-idf.yaml new file mode 100644 index 0000000000..fbb83cd9f8 --- /dev/null +++ b/tests/components/mmc5603/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 16 + sda: 17 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5603/test.esp32.yaml b/tests/components/mmc5603/test.esp32.yaml new file mode 100644 index 0000000000..fbb83cd9f8 --- /dev/null +++ b/tests/components/mmc5603/test.esp32.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 16 + sda: 17 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5603/test.esp8266.yaml b/tests/components/mmc5603/test.esp8266.yaml new file mode 100644 index 0000000000..834591bb39 --- /dev/null +++ b/tests/components/mmc5603/test.esp8266.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5603/test.rp2040.yaml b/tests/components/mmc5603/test.rp2040.yaml new file mode 100644 index 0000000000..834591bb39 --- /dev/null +++ b/tests/components/mmc5603/test.rp2040.yaml @@ -0,0 +1,14 @@ +i2c: + - id: i2c_mmc5603 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z diff --git a/tests/components/mmc5983/test.esp32-c3-idf.yaml b/tests/components/mmc5983/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..68d821e9a5 --- /dev/null +++ b/tests/components/mmc5983/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/mmc5983/test.esp32-c3.yaml b/tests/components/mmc5983/test.esp32-c3.yaml new file mode 100644 index 0000000000..68d821e9a5 --- /dev/null +++ b/tests/components/mmc5983/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/mmc5983/test.esp32-idf.yaml b/tests/components/mmc5983/test.esp32-idf.yaml new file mode 100644 index 0000000000..6104be9b83 --- /dev/null +++ b/tests/components/mmc5983/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 16 + sda: 17 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/mmc5983/test.esp32.yaml b/tests/components/mmc5983/test.esp32.yaml new file mode 100644 index 0000000000..6104be9b83 --- /dev/null +++ b/tests/components/mmc5983/test.esp32.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 16 + sda: 17 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/mmc5983/test.esp8266.yaml b/tests/components/mmc5983/test.esp8266.yaml new file mode 100644 index 0000000000..68d821e9a5 --- /dev/null +++ b/tests/components/mmc5983/test.esp8266.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/mmc5983/test.rp2040.yaml b/tests/components/mmc5983/test.rp2040.yaml new file mode 100644 index 0000000000..68d821e9a5 --- /dev/null +++ b/tests/components/mmc5983/test.rp2040.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_mmc5983 + scl: 5 + sda: 4 + +sensor: + - platform: mmc5983 + field_strength_x: + name: "Magnet X" + id: magnet_x + field_strength_y: + name: "Magnet Y" + id: magnet_y + field_strength_z: + name: "Magnet Z" + id: magnet_z diff --git a/tests/components/modbus/test.esp32-c3-idf.yaml b/tests/components/modbus/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d22b507be0 --- /dev/null +++ b/tests/components/modbus/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 diff --git a/tests/components/modbus/test.esp32-c3.yaml b/tests/components/modbus/test.esp32-c3.yaml new file mode 100644 index 0000000000..d22b507be0 --- /dev/null +++ b/tests/components/modbus/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 diff --git a/tests/components/modbus/test.esp32-idf.yaml b/tests/components/modbus/test.esp32-idf.yaml new file mode 100644 index 0000000000..20cf238b1b --- /dev/null +++ b/tests/components/modbus/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 15 diff --git a/tests/components/modbus/test.esp32.yaml b/tests/components/modbus/test.esp32.yaml new file mode 100644 index 0000000000..20cf238b1b --- /dev/null +++ b/tests/components/modbus/test.esp32.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 15 diff --git a/tests/components/modbus/test.esp8266.yaml b/tests/components/modbus/test.esp8266.yaml new file mode 100644 index 0000000000..560c044766 --- /dev/null +++ b/tests/components/modbus/test.esp8266.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 12 diff --git a/tests/components/modbus/test.rp2040.yaml b/tests/components/modbus/test.rp2040.yaml new file mode 100644 index 0000000000..d22b507be0 --- /dev/null +++ b/tests/components/modbus/test.rp2040.yaml @@ -0,0 +1,9 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 diff --git a/tests/components/modbus_controller/test.esp32-c3-idf.yaml b/tests/components/modbus_controller/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..476e65ecb0 --- /dev/null +++ b/tests/components/modbus_controller/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/modbus_controller/test.esp32-c3.yaml b/tests/components/modbus_controller/test.esp32-c3.yaml new file mode 100644 index 0000000000..476e65ecb0 --- /dev/null +++ b/tests/components/modbus_controller/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/modbus_controller/test.esp32-idf.yaml b/tests/components/modbus_controller/test.esp32-idf.yaml new file mode 100644 index 0000000000..c5fe3fd057 --- /dev/null +++ b/tests/components/modbus_controller/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 15 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/modbus_controller/test.esp32.yaml b/tests/components/modbus_controller/test.esp32.yaml new file mode 100644 index 0000000000..c5fe3fd057 --- /dev/null +++ b/tests/components/modbus_controller/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 15 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/modbus_controller/test.esp8266.yaml b/tests/components/modbus_controller/test.esp8266.yaml new file mode 100644 index 0000000000..67cac65d1b --- /dev/null +++ b/tests/components/modbus_controller/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 12 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/modbus_controller/test.rp2040.yaml b/tests/components/modbus_controller/test.rp2040.yaml new file mode 100644 index 0000000000..476e65ecb0 --- /dev/null +++ b/tests/components/modbus_controller/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_modbus + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +modbus: + id: mod_bus1 + flow_control_pin: 6 + +modbus_controller: + - id: modbus_controller1 + address: 0x2 + modbus_id: mod_bus1 diff --git a/tests/components/monochromatic/test.esp32-c3-idf.yaml b/tests/components/monochromatic/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9524efcb2d --- /dev/null +++ b/tests/components/monochromatic/test.esp32-c3-idf.yaml @@ -0,0 +1,40 @@ +output: + - platform: ledc + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/monochromatic/test.esp32-c3.yaml b/tests/components/monochromatic/test.esp32-c3.yaml new file mode 100644 index 0000000000..9524efcb2d --- /dev/null +++ b/tests/components/monochromatic/test.esp32-c3.yaml @@ -0,0 +1,40 @@ +output: + - platform: ledc + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/monochromatic/test.esp32-idf.yaml b/tests/components/monochromatic/test.esp32-idf.yaml new file mode 100644 index 0000000000..9524efcb2d --- /dev/null +++ b/tests/components/monochromatic/test.esp32-idf.yaml @@ -0,0 +1,40 @@ +output: + - platform: ledc + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/monochromatic/test.esp32.yaml b/tests/components/monochromatic/test.esp32.yaml new file mode 100644 index 0000000000..9524efcb2d --- /dev/null +++ b/tests/components/monochromatic/test.esp32.yaml @@ -0,0 +1,40 @@ +output: + - platform: ledc + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/monochromatic/test.esp8266.yaml b/tests/components/monochromatic/test.esp8266.yaml new file mode 100644 index 0000000000..94d849581d --- /dev/null +++ b/tests/components/monochromatic/test.esp8266.yaml @@ -0,0 +1,40 @@ +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/monochromatic/test.rp2040.yaml b/tests/components/monochromatic/test.rp2040.yaml new file mode 100644 index 0000000000..093577e256 --- /dev/null +++ b/tests/components/monochromatic/test.rp2040.yaml @@ -0,0 +1,40 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 4 + +light: + - platform: monochromatic + name: Monochromatic Light + id: monochromatic_light + output: light_output_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% diff --git a/tests/components/mopeka_ble/test.esp32-c3-idf.yaml b/tests/components/mopeka_ble/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a115404f1c --- /dev/null +++ b/tests/components/mopeka_ble/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +mopeka_ble: diff --git a/tests/components/mopeka_ble/test.esp32-c3.yaml b/tests/components/mopeka_ble/test.esp32-c3.yaml new file mode 100644 index 0000000000..a115404f1c --- /dev/null +++ b/tests/components/mopeka_ble/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +mopeka_ble: diff --git a/tests/components/mopeka_ble/test.esp32-idf.yaml b/tests/components/mopeka_ble/test.esp32-idf.yaml new file mode 100644 index 0000000000..a115404f1c --- /dev/null +++ b/tests/components/mopeka_ble/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +mopeka_ble: diff --git a/tests/components/mopeka_ble/test.esp32.yaml b/tests/components/mopeka_ble/test.esp32.yaml new file mode 100644 index 0000000000..a115404f1c --- /dev/null +++ b/tests/components/mopeka_ble/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +mopeka_ble: diff --git a/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml b/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..147cbcb9de --- /dev/null +++ b/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level diff --git a/tests/components/mopeka_pro_check/test.esp32-c3.yaml b/tests/components/mopeka_pro_check/test.esp32-c3.yaml new file mode 100644 index 0000000000..147cbcb9de --- /dev/null +++ b/tests/components/mopeka_pro_check/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level diff --git a/tests/components/mopeka_pro_check/test.esp32-idf.yaml b/tests/components/mopeka_pro_check/test.esp32-idf.yaml new file mode 100644 index 0000000000..147cbcb9de --- /dev/null +++ b/tests/components/mopeka_pro_check/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level diff --git a/tests/components/mopeka_pro_check/test.esp32.yaml b/tests/components/mopeka_pro_check/test.esp32.yaml new file mode 100644 index 0000000000..147cbcb9de --- /dev/null +++ b/tests/components/mopeka_pro_check/test.esp32.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level diff --git a/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..830adf952f --- /dev/null +++ b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + # Example using 11kg 100% propane tank. + - platform: mopeka_std_check + mac_address: D3:75:F2:DC:16:91 + tank_type: Europe_11kg + temperature: + name: "Propane test temp" + level: + name: "Propane test level" + distance: + name: "Propane test distance" + battery_level: + name: "Propane test battery level" + diff --git a/tests/components/mopeka_std_check/test.esp32-c3.yaml b/tests/components/mopeka_std_check/test.esp32-c3.yaml new file mode 100644 index 0000000000..830adf952f --- /dev/null +++ b/tests/components/mopeka_std_check/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + # Example using 11kg 100% propane tank. + - platform: mopeka_std_check + mac_address: D3:75:F2:DC:16:91 + tank_type: Europe_11kg + temperature: + name: "Propane test temp" + level: + name: "Propane test level" + distance: + name: "Propane test distance" + battery_level: + name: "Propane test battery level" + diff --git a/tests/components/mopeka_std_check/test.esp32-idf.yaml b/tests/components/mopeka_std_check/test.esp32-idf.yaml new file mode 100644 index 0000000000..830adf952f --- /dev/null +++ b/tests/components/mopeka_std_check/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + # Example using 11kg 100% propane tank. + - platform: mopeka_std_check + mac_address: D3:75:F2:DC:16:91 + tank_type: Europe_11kg + temperature: + name: "Propane test temp" + level: + name: "Propane test level" + distance: + name: "Propane test distance" + battery_level: + name: "Propane test battery level" + diff --git a/tests/components/mpl3115a2/test.esp32-c3-idf.yaml b/tests/components/mpl3115a2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9cbe08d920 --- /dev/null +++ b/tests/components/mpl3115a2/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 5 + sda: 4 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpl3115a2/test.esp32-c3.yaml b/tests/components/mpl3115a2/test.esp32-c3.yaml new file mode 100644 index 0000000000..9cbe08d920 --- /dev/null +++ b/tests/components/mpl3115a2/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 5 + sda: 4 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpl3115a2/test.esp32-idf.yaml b/tests/components/mpl3115a2/test.esp32-idf.yaml new file mode 100644 index 0000000000..5e9d6d190d --- /dev/null +++ b/tests/components/mpl3115a2/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 16 + sda: 17 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpl3115a2/test.esp32.yaml b/tests/components/mpl3115a2/test.esp32.yaml new file mode 100644 index 0000000000..5e9d6d190d --- /dev/null +++ b/tests/components/mpl3115a2/test.esp32.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 16 + sda: 17 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpl3115a2/test.esp8266.yaml b/tests/components/mpl3115a2/test.esp8266.yaml new file mode 100644 index 0000000000..9cbe08d920 --- /dev/null +++ b/tests/components/mpl3115a2/test.esp8266.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 5 + sda: 4 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpl3115a2/test.rp2040.yaml b/tests/components/mpl3115a2/test.rp2040.yaml new file mode 100644 index 0000000000..9cbe08d920 --- /dev/null +++ b/tests/components/mpl3115a2/test.rp2040.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_mpl3115a2 + scl: 5 + sda: 4 + +sensor: + - platform: mpl3115a2 + temperature: + name: MPL3115A2 Temperature + pressure: + name: MPL3115A2 Pressure + update_interval: 10s diff --git a/tests/components/mpr121/test.esp32-c3-idf.yaml b/tests/components/mpr121/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..517e092560 --- /dev/null +++ b/tests/components/mpr121/test.esp32-c3-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 5 + sda: 4 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpr121/test.esp32-c3.yaml b/tests/components/mpr121/test.esp32-c3.yaml new file mode 100644 index 0000000000..517e092560 --- /dev/null +++ b/tests/components/mpr121/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 5 + sda: 4 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpr121/test.esp32-idf.yaml b/tests/components/mpr121/test.esp32-idf.yaml new file mode 100644 index 0000000000..96996fd8ee --- /dev/null +++ b/tests/components/mpr121/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 16 + sda: 17 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpr121/test.esp32.yaml b/tests/components/mpr121/test.esp32.yaml new file mode 100644 index 0000000000..96996fd8ee --- /dev/null +++ b/tests/components/mpr121/test.esp32.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 16 + sda: 17 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpr121/test.esp8266.yaml b/tests/components/mpr121/test.esp8266.yaml new file mode 100644 index 0000000000..517e092560 --- /dev/null +++ b/tests/components/mpr121/test.esp8266.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 5 + sda: 4 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpr121/test.rp2040.yaml b/tests/components/mpr121/test.rp2040.yaml new file mode 100644 index 0000000000..517e092560 --- /dev/null +++ b/tests/components/mpr121/test.rp2040.yaml @@ -0,0 +1,26 @@ +i2c: + - id: i2c_mpr121 + scl: 5 + sda: 4 + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 3 diff --git a/tests/components/mpu6050/test.esp32-c3-idf.yaml b/tests/components/mpu6050/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..39c8506d2b --- /dev/null +++ b/tests/components/mpu6050/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6050/test.esp32-c3.yaml b/tests/components/mpu6050/test.esp32-c3.yaml new file mode 100644 index 0000000000..39c8506d2b --- /dev/null +++ b/tests/components/mpu6050/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6050/test.esp32-idf.yaml b/tests/components/mpu6050/test.esp32-idf.yaml new file mode 100644 index 0000000000..45bca55dea --- /dev/null +++ b/tests/components/mpu6050/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 16 + sda: 17 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6050/test.esp32.yaml b/tests/components/mpu6050/test.esp32.yaml new file mode 100644 index 0000000000..45bca55dea --- /dev/null +++ b/tests/components/mpu6050/test.esp32.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 16 + sda: 17 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6050/test.esp8266.yaml b/tests/components/mpu6050/test.esp8266.yaml new file mode 100644 index 0000000000..39c8506d2b --- /dev/null +++ b/tests/components/mpu6050/test.esp8266.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6050/test.rp2040.yaml b/tests/components/mpu6050/test.rp2040.yaml new file mode 100644 index 0000000000..39c8506d2b --- /dev/null +++ b/tests/components/mpu6050/test.rp2040.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6050 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6050 + address: 0x68 + accel_x: + name: MPU6050 Accel X + accel_y: + name: MPU6050 Accel Y + accel_z: + name: MPU6050 Accel z + gyro_x: + name: MPU6050 Gyro X + gyro_y: + name: MPU6050 Gyro Y + gyro_z: + name: MPU6050 Gyro z + temperature: + name: MPU6050 Temperature diff --git a/tests/components/mpu6886/test.esp32-c3-idf.yaml b/tests/components/mpu6886/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fad51a80b4 --- /dev/null +++ b/tests/components/mpu6886/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mpu6886/test.esp32-c3.yaml b/tests/components/mpu6886/test.esp32-c3.yaml new file mode 100644 index 0000000000..fad51a80b4 --- /dev/null +++ b/tests/components/mpu6886/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mpu6886/test.esp32-idf.yaml b/tests/components/mpu6886/test.esp32-idf.yaml new file mode 100644 index 0000000000..84e4d56739 --- /dev/null +++ b/tests/components/mpu6886/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 16 + sda: 17 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mpu6886/test.esp32.yaml b/tests/components/mpu6886/test.esp32.yaml new file mode 100644 index 0000000000..84e4d56739 --- /dev/null +++ b/tests/components/mpu6886/test.esp32.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 16 + sda: 17 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mpu6886/test.esp8266.yaml b/tests/components/mpu6886/test.esp8266.yaml new file mode 100644 index 0000000000..fad51a80b4 --- /dev/null +++ b/tests/components/mpu6886/test.esp8266.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mpu6886/test.rp2040.yaml b/tests/components/mpu6886/test.rp2040.yaml new file mode 100644 index 0000000000..fad51a80b4 --- /dev/null +++ b/tests/components/mpu6886/test.rp2040.yaml @@ -0,0 +1,22 @@ +i2c: + - id: i2c_mpu6886 + scl: 5 + sda: 4 + +sensor: + - platform: mpu6886 + address: 0x68 + accel_x: + name: MPU6886 Accel X + accel_y: + name: MPU6886 Accel Y + accel_z: + name: MPU6886 Accel z + gyro_x: + name: MPU6886 Gyro X + gyro_y: + name: MPU6886 Gyro Y + gyro_z: + name: MPU6886 Gyro z + temperature: + name: MPU6886 Temperature diff --git a/tests/components/mqtt/test.esp32-c3-idf.yaml b/tests/components/mqtt/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7702ed5610 --- /dev/null +++ b/tests/components/mqtt/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + idf_send_async: false + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test diff --git a/tests/components/mqtt/test.esp32-c3.yaml b/tests/components/mqtt/test.esp32-c3.yaml new file mode 100644 index 0000000000..692d504d6d --- /dev/null +++ b/tests/components/mqtt/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test diff --git a/tests/components/mqtt/test.esp32-idf.yaml b/tests/components/mqtt/test.esp32-idf.yaml new file mode 100644 index 0000000000..7702ed5610 --- /dev/null +++ b/tests/components/mqtt/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + idf_send_async: false + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test diff --git a/tests/components/mqtt/test.esp32.yaml b/tests/components/mqtt/test.esp32.yaml new file mode 100644 index 0000000000..692d504d6d --- /dev/null +++ b/tests/components/mqtt/test.esp32.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test diff --git a/tests/components/mqtt/test.esp8266.yaml b/tests/components/mqtt/test.esp8266.yaml new file mode 100644 index 0000000000..692d504d6d --- /dev/null +++ b/tests/components/mqtt/test.esp8266.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test diff --git a/tests/components/mqtt_subscribe/test.esp32-c3-idf.yaml b/tests/components/mqtt_subscribe/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..070672f15c --- /dev/null +++ b/tests/components/mqtt_subscribe/test.esp32-c3-idf.yaml @@ -0,0 +1,37 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + idf_send_async: false + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test + +sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(the_sensor).state; + root["greeting"] = "Hello World"; + +text_sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: "the/topic" + qos: 2 + on_value: + - logger.log: "Text sensor got value" diff --git a/tests/components/mqtt_subscribe/test.esp32-c3.yaml b/tests/components/mqtt_subscribe/test.esp32-c3.yaml new file mode 100644 index 0000000000..13ed311b17 --- /dev/null +++ b/tests/components/mqtt_subscribe/test.esp32-c3.yaml @@ -0,0 +1,36 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test + +sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(the_sensor).state; + root["greeting"] = "Hello World"; + +text_sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: "the/topic" + qos: 2 + on_value: + - logger.log: "Text sensor got value" diff --git a/tests/components/mqtt_subscribe/test.esp32-idf.yaml b/tests/components/mqtt_subscribe/test.esp32-idf.yaml new file mode 100644 index 0000000000..070672f15c --- /dev/null +++ b/tests/components/mqtt_subscribe/test.esp32-idf.yaml @@ -0,0 +1,37 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + idf_send_async: false + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test + +sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(the_sensor).state; + root["greeting"] = "Hello World"; + +text_sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: "the/topic" + qos: 2 + on_value: + - logger.log: "Text sensor got value" diff --git a/tests/components/mqtt_subscribe/test.esp32.yaml b/tests/components/mqtt_subscribe/test.esp32.yaml new file mode 100644 index 0000000000..13ed311b17 --- /dev/null +++ b/tests/components/mqtt_subscribe/test.esp32.yaml @@ -0,0 +1,36 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test + +sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(the_sensor).state; + root["greeting"] = "Hello World"; + +text_sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: "the/topic" + qos: 2 + on_value: + - logger.log: "Text sensor got value" diff --git a/tests/components/mqtt_subscribe/test.esp8266.yaml b/tests/components/mqtt_subscribe/test.esp8266.yaml new file mode 100644 index 0000000000..13ed311b17 --- /dev/null +++ b/tests/components/mqtt_subscribe/test.esp8266.yaml @@ -0,0 +1,36 @@ +wifi: + ssid: MySSID + password: password1 + +mqtt: + broker: test.mosquitto.org + port: 1883 + discovery: true + discovery_prefix: homeassistant + log_topic: + on_message: + topic: testing/sensor/testing_sensor/state + qos: 0 + then: + - logger.log: Mqtt Test + +sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(the_sensor).state; + root["greeting"] = "Hello World"; + +text_sensor: + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: "the/topic" + qos: 2 + on_value: + - logger.log: "Text sensor got value" diff --git a/tests/components/ms5611/test.esp32-c3-idf.yaml b/tests/components/ms5611/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..8f18501eef --- /dev/null +++ b/tests/components/ms5611/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 5 + sda: 4 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/ms5611/test.esp32-c3.yaml b/tests/components/ms5611/test.esp32-c3.yaml new file mode 100644 index 0000000000..8f18501eef --- /dev/null +++ b/tests/components/ms5611/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 5 + sda: 4 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/ms5611/test.esp32-idf.yaml b/tests/components/ms5611/test.esp32-idf.yaml new file mode 100644 index 0000000000..b090eeaa93 --- /dev/null +++ b/tests/components/ms5611/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 16 + sda: 17 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/ms5611/test.esp32.yaml b/tests/components/ms5611/test.esp32.yaml new file mode 100644 index 0000000000..b090eeaa93 --- /dev/null +++ b/tests/components/ms5611/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 16 + sda: 17 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/ms5611/test.esp8266.yaml b/tests/components/ms5611/test.esp8266.yaml new file mode 100644 index 0000000000..8f18501eef --- /dev/null +++ b/tests/components/ms5611/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 5 + sda: 4 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/ms5611/test.rp2040.yaml b/tests/components/ms5611/test.rp2040.yaml new file mode 100644 index 0000000000..8f18501eef --- /dev/null +++ b/tests/components/ms5611/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_ms5611 + scl: 5 + sda: 4 + +sensor: + - platform: ms5611 + temperature: + name: Outside Temperature + pressure: + name: Outside Pressure + address: 0x77 + update_interval: 15s diff --git a/tests/components/my9231/test.esp32-c3-idf.yaml b/tests/components/my9231/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.esp32-c3-idf.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.esp32-c3.yaml b/tests/components/my9231/test.esp32-c3.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.esp32-idf.yaml b/tests/components/my9231/test.esp32-idf.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.esp32.yaml b/tests/components/my9231/test.esp32.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.esp32.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.esp8266.yaml b/tests/components/my9231/test.esp8266.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.esp8266.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.rp2040.yaml b/tests/components/my9231/test.rp2040.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/test.rp2040.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 From 6806cb28f616287a4db61eb18ea1f6206e35a50f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 22:45:59 -0500 Subject: [PATCH 1603/2607] Add some components to the new testing framework (O) (#6211) --- tests/components/ota/test.esp32-c3-idf.yaml | 30 +++++++++++++++++++ tests/components/ota/test.esp32-c3.yaml | 30 +++++++++++++++++++ tests/components/ota/test.esp32-idf.yaml | 30 +++++++++++++++++++ tests/components/ota/test.esp32.yaml | 30 +++++++++++++++++++ tests/components/ota/test.esp8266.yaml | 30 +++++++++++++++++++ tests/components/ota/test.rp2040.yaml | 30 +++++++++++++++++++ .../components/output/test.esp32-c3-idf.yaml | 13 ++++++++ tests/components/output/test.esp32-c3.yaml | 13 ++++++++ tests/components/output/test.esp32-idf.yaml | 13 ++++++++ tests/components/output/test.esp32.yaml | 13 ++++++++ tests/components/output/test.esp8266.yaml | 13 ++++++++ tests/components/output/test.rp2040.yaml | 13 ++++++++ 12 files changed, 258 insertions(+) create mode 100644 tests/components/ota/test.esp32-c3-idf.yaml create mode 100644 tests/components/ota/test.esp32-c3.yaml create mode 100644 tests/components/ota/test.esp32-idf.yaml create mode 100644 tests/components/ota/test.esp32.yaml create mode 100644 tests/components/ota/test.esp8266.yaml create mode 100644 tests/components/ota/test.rp2040.yaml create mode 100644 tests/components/output/test.esp32-c3-idf.yaml create mode 100644 tests/components/output/test.esp32-c3.yaml create mode 100644 tests/components/output/test.esp32-idf.yaml create mode 100644 tests/components/output/test.esp32.yaml create mode 100644 tests/components/output/test.esp8266.yaml create mode 100644 tests/components/output/test.rp2040.yaml diff --git a/tests/components/ota/test.esp32-c3-idf.yaml b/tests/components/ota/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.esp32-c3-idf.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.esp32-c3.yaml b/tests/components/ota/test.esp32-c3.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.esp32-c3.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.esp32-idf.yaml b/tests/components/ota/test.esp32-idf.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.esp32-idf.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.esp32.yaml b/tests/components/ota/test.esp32.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.esp32.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.esp8266.yaml b/tests/components/ota/test.esp8266.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.esp8266.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.rp2040.yaml b/tests/components/ota/test.rp2040.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/test.rp2040.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/output/test.esp32-c3-idf.yaml b/tests/components/output/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c56d85c296 --- /dev/null +++ b/tests/components/output/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: ledc + id: light_output_1 + pin: 1 diff --git a/tests/components/output/test.esp32-c3.yaml b/tests/components/output/test.esp32-c3.yaml new file mode 100644 index 0000000000..c56d85c296 --- /dev/null +++ b/tests/components/output/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: ledc + id: light_output_1 + pin: 1 diff --git a/tests/components/output/test.esp32-idf.yaml b/tests/components/output/test.esp32-idf.yaml new file mode 100644 index 0000000000..480f9dfe1f --- /dev/null +++ b/tests/components/output/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: ledc + id: light_output_1 + pin: 12 diff --git a/tests/components/output/test.esp32.yaml b/tests/components/output/test.esp32.yaml new file mode 100644 index 0000000000..480f9dfe1f --- /dev/null +++ b/tests/components/output/test.esp32.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: ledc + id: light_output_1 + pin: 12 diff --git a/tests/components/output/test.esp8266.yaml b/tests/components/output/test.esp8266.yaml new file mode 100644 index 0000000000..d9cb353636 --- /dev/null +++ b/tests/components/output/test.esp8266.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 12 diff --git a/tests/components/output/test.rp2040.yaml b/tests/components/output/test.rp2040.yaml new file mode 100644 index 0000000000..399259fdd9 --- /dev/null +++ b/tests/components/output/test.rp2040.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - output.turn_off: light_output_1 + - output.turn_on: light_output_1 + - output.set_level: + id: light_output_1 + level: 50% + +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 12 From fa8d09aca9dc26befd101df0720d4563dd8c1577 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:20:37 +1200 Subject: [PATCH 1604/2607] [mopeka_std_check] Fix test file indentation (#6610) --- tests/components/mopeka_std_check/test.esp32-c3-idf.yaml | 9 ++++----- tests/components/mopeka_std_check/test.esp32-c3.yaml | 9 ++++----- tests/components/mopeka_std_check/test.esp32-idf.yaml | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml index 830adf952f..383e2e2a19 100644 --- a/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml +++ b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml @@ -6,11 +6,10 @@ sensor: mac_address: D3:75:F2:DC:16:91 tank_type: Europe_11kg temperature: - name: "Propane test temp" + name: "Propane test temp" level: - name: "Propane test level" + name: "Propane test level" distance: - name: "Propane test distance" + name: "Propane test distance" battery_level: - name: "Propane test battery level" - + name: "Propane test battery level" diff --git a/tests/components/mopeka_std_check/test.esp32-c3.yaml b/tests/components/mopeka_std_check/test.esp32-c3.yaml index 830adf952f..383e2e2a19 100644 --- a/tests/components/mopeka_std_check/test.esp32-c3.yaml +++ b/tests/components/mopeka_std_check/test.esp32-c3.yaml @@ -6,11 +6,10 @@ sensor: mac_address: D3:75:F2:DC:16:91 tank_type: Europe_11kg temperature: - name: "Propane test temp" + name: "Propane test temp" level: - name: "Propane test level" + name: "Propane test level" distance: - name: "Propane test distance" + name: "Propane test distance" battery_level: - name: "Propane test battery level" - + name: "Propane test battery level" diff --git a/tests/components/mopeka_std_check/test.esp32-idf.yaml b/tests/components/mopeka_std_check/test.esp32-idf.yaml index 830adf952f..383e2e2a19 100644 --- a/tests/components/mopeka_std_check/test.esp32-idf.yaml +++ b/tests/components/mopeka_std_check/test.esp32-idf.yaml @@ -6,11 +6,10 @@ sensor: mac_address: D3:75:F2:DC:16:91 tank_type: Europe_11kg temperature: - name: "Propane test temp" + name: "Propane test temp" level: - name: "Propane test level" + name: "Propane test level" distance: - name: "Propane test distance" + name: "Propane test distance" battery_level: - name: "Propane test battery level" - + name: "Propane test battery level" From eb89d99999941a6de6872d3bea01d2ef3c684924 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 23:47:03 -0500 Subject: [PATCH 1605/2607] Add valve component (#6447) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/api/api.proto | 51 ++++ esphome/components/api/api_connection.cpp | 42 +++ esphome/components/api/api_connection.h | 5 + esphome/components/api/api_pb2.cpp | 247 ++++++++++++++++++ esphome/components/api/api_pb2.h | 57 ++++ esphome/components/api/api_pb2_service.cpp | 42 +++ esphome/components/api/api_pb2_service.h | 15 ++ esphome/components/api/api_server.cpp | 9 + esphome/components/api/api_server.h | 3 + esphome/components/api/list_entities.cpp | 3 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.cpp | 3 + esphome/components/api/subscribe_state.h | 3 + esphome/components/mqtt/__init__.py | 1 + esphome/components/mqtt/mqtt_valve.cpp | 90 +++++++ esphome/components/mqtt/mqtt_valve.h | 41 +++ esphome/components/template/valve/__init__.py | 118 +++++++++ .../template/valve/template_valve.cpp | 131 ++++++++++ .../template/valve/template_valve.h | 60 +++++ esphome/components/valve/__init__.py | 186 +++++++++++++ esphome/components/valve/automation.h | 129 +++++++++ esphome/components/valve/valve.cpp | 179 +++++++++++++ esphome/components/valve/valve.h | 152 +++++++++++ esphome/components/valve/valve_traits.h | 27 ++ .../components/web_server/list_entities.cpp | 9 + esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 74 ++++++ esphome/components/web_server/web_server.h | 10 + esphome/core/application.h | 19 ++ esphome/core/component_iterator.cpp | 15 ++ esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + script/ci-custom.py | 1 + tests/components/template/test.all.yaml | 17 ++ 37 files changed, 1765 insertions(+) create mode 100644 esphome/components/mqtt/mqtt_valve.cpp create mode 100644 esphome/components/mqtt/mqtt_valve.h create mode 100644 esphome/components/template/valve/__init__.py create mode 100644 esphome/components/template/valve/template_valve.cpp create mode 100644 esphome/components/template/valve/template_valve.h create mode 100644 esphome/components/valve/__init__.py create mode 100644 esphome/components/valve/automation.h create mode 100644 esphome/components/valve/valve.cpp create mode 100644 esphome/components/valve/valve.h create mode 100644 esphome/components/valve/valve_traits.h diff --git a/CODEOWNERS b/CODEOWNERS index 9f770d4efc..28ce8e7b6a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -390,6 +390,7 @@ esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ise/* @pvizeli esphome/components/ultrasonic/* @OttoWinter esphome/components/uponor_smatrix/* @kroimon +esphome/components/valve/* @esphome/core esphome/components/vbus/* @ssieb esphome/components/veml3235/* @kbx81 esphome/components/veml7700/* @latonita diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 8d5459e717..12b7ef0958 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -43,6 +43,7 @@ service APIConnection { rpc select_command (SelectCommandRequest) returns (void) {} rpc button_command (ButtonCommandRequest) returns (void) {} rpc lock_command (LockCommandRequest) returns (void) {} + rpc valve_command (ValveCommandRequest) returns (void) {} rpc media_player_command (MediaPlayerCommandRequest) returns (void) {} rpc date_command (DateCommandRequest) returns (void) {} rpc time_command (TimeCommandRequest) returns (void) {} @@ -1700,3 +1701,53 @@ message TimeCommandRequest { uint32 minute = 3; uint32 second = 4; } + + +// ==================== VALVE ==================== +message ListEntitiesValveResponse { + option (id) = 109; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VALVE"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; + string device_class = 8; + + bool assumed_state = 9; + bool supports_position = 10; + bool supports_stop = 11; +} + +enum ValveOperation { + VALVE_OPERATION_IDLE = 0; + VALVE_OPERATION_IS_OPENING = 1; + VALVE_OPERATION_IS_CLOSING = 2; +} +message ValveStateResponse { + option (id) = 110; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VALVE"; + option (no_delay) = true; + + fixed32 key = 1; + float position = 2; + ValveOperation current_operation = 3; +} + +message ValveCommandRequest { + option (id) = 111; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VALVE"; + option (no_delay) = true; + + fixed32 key = 1; + bool has_position = 2; + float position = 3; + bool stop = 4; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index e51fa8c154..47136fff98 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -915,6 +915,48 @@ void APIConnection::lock_command(const LockCommandRequest &msg) { } #endif +#ifdef USE_VALVE +bool APIConnection::send_valve_state(valve::Valve *valve) { + if (!this->state_subscription_) + return false; + + ValveStateResponse resp{}; + resp.key = valve->get_object_id_hash(); + resp.position = valve->position; + resp.current_operation = static_cast(valve->current_operation); + return this->send_valve_state_response(resp); +} +bool APIConnection::send_valve_info(valve::Valve *valve) { + auto traits = valve->get_traits(); + ListEntitiesValveResponse msg; + msg.key = valve->get_object_id_hash(); + msg.object_id = valve->get_object_id(); + if (valve->has_own_name()) + msg.name = valve->get_name(); + msg.unique_id = get_default_unique_id("valve", valve); + msg.icon = valve->get_icon(); + msg.disabled_by_default = valve->is_disabled_by_default(); + msg.entity_category = static_cast(valve->get_entity_category()); + msg.device_class = valve->get_device_class(); + msg.assumed_state = traits.get_is_assumed_state(); + msg.supports_position = traits.get_supports_position(); + msg.supports_stop = traits.get_supports_stop(); + return this->send_list_entities_valve_response(msg); +} +void APIConnection::valve_command(const ValveCommandRequest &msg) { + valve::Valve *valve = App.get_valve_by_key(msg.key); + if (valve == nullptr) + return; + + auto call = valve->make_call(); + if (msg.has_position) + call.set_position(msg.position); + if (msg.stop) + call.set_command_stop(); + call.perform(); +} +#endif + #ifdef USE_MEDIA_PLAYER bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) { if (!this->state_subscription_) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 5c0a78015d..af2dd9e681 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -101,6 +101,11 @@ class APIConnection : public APIServerConnection { bool send_lock_info(lock::Lock *a_lock); void lock_command(const LockCommandRequest &msg) override; #endif +#ifdef USE_VALVE + bool send_valve_state(valve::Valve *valve); + bool send_valve_info(valve::Valve *valve); + void valve_command(const ValveCommandRequest &msg) override; +#endif #ifdef USE_MEDIA_PLAYER bool send_media_player_state(media_player::MediaPlayer *media_player); bool send_media_player_info(media_player::MediaPlayer *media_player); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 884396bda3..508947ba24 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -537,6 +537,20 @@ template<> const char *proto_enum_to_string(enums::TextMode val } } #endif +#ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::ValveOperation value) { + switch (value) { + case enums::VALVE_OPERATION_IDLE: + return "VALVE_OPERATION_IDLE"; + case enums::VALVE_OPERATION_IS_OPENING: + return "VALVE_OPERATION_IS_OPENING"; + case enums::VALVE_OPERATION_IS_CLOSING: + return "VALVE_OPERATION_IS_CLOSING"; + default: + return "UNKNOWN"; + } +} +#endif bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -7695,6 +7709,239 @@ void TimeCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesValveResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + case 9: { + this->assumed_state = value.as_bool(); + return true; + } + case 10: { + this->supports_position = value.as_bool(); + return true; + } + case 11: { + this->supports_stop = value.as_bool(); + return true; + } + default: + return false; + } +} +bool ListEntitiesValveResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + case 8: { + this->device_class = value.as_string(); + return true; + } + default: + return false; + } +} +bool ListEntitiesValveResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesValveResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); + buffer.encode_string(8, this->device_class); + buffer.encode_bool(9, this->assumed_state); + buffer.encode_bool(10, this->supports_position); + buffer.encode_bool(11, this->supports_stop); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesValveResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesValveResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" assumed_state: "); + out.append(YESNO(this->assumed_state)); + out.append("\n"); + + out.append(" supports_position: "); + out.append(YESNO(this->supports_position)); + out.append("\n"); + + out.append(" supports_stop: "); + out.append(YESNO(this->supports_stop)); + out.append("\n"); + out.append("}"); +} +#endif +bool ValveStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 3: { + this->current_operation = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ValveStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + case 2: { + this->position = value.as_float(); + return true; + } + default: + return false; + } +} +void ValveStateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_float(2, this->position); + buffer.encode_enum(3, this->current_operation); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ValveStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ValveStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" current_operation: "); + out.append(proto_enum_to_string(this->current_operation)); + out.append("\n"); + out.append("}"); +} +#endif +bool ValveCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->has_position = value.as_bool(); + return true; + } + case 4: { + this->stop = value.as_bool(); + return true; + } + default: + return false; + } +} +bool ValveCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + case 3: { + this->position = value.as_float(); + return true; + } + default: + return false; + } +} +void ValveCommandRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_bool(2, this->has_position); + buffer.encode_float(3, this->position); + buffer.encode_bool(4, this->stop); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ValveCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ValveCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_position: "); + out.append(YESNO(this->has_position)); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" stop: "); + out.append(YESNO(this->stop)); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 2ae6fd2bb6..950ffcdc88 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -216,6 +216,11 @@ enum TextMode : uint32_t { TEXT_MODE_TEXT = 0, TEXT_MODE_PASSWORD = 1, }; +enum ValveOperation : uint32_t { + VALVE_OPERATION_IDLE = 0, + VALVE_OPERATION_IS_OPENING = 1, + VALVE_OPERATION_IS_CLOSING = 2, +}; } // namespace enums @@ -1969,6 +1974,58 @@ class TimeCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class ListEntitiesValveResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + std::string device_class{}; + bool assumed_state{false}; + bool supports_position{false}; + bool supports_stop{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class ValveStateResponse : public ProtoMessage { + public: + uint32_t key{0}; + float position{0.0f}; + enums::ValveOperation current_operation{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class ValveCommandRequest : public ProtoMessage { + public: + uint32_t key{0}; + bool has_position{false}; + float position{0.0f}; + bool stop{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 7a97df1ce0..4b8b8cf5ae 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -557,6 +557,24 @@ bool APIServerConnectionBase::send_time_state_response(const TimeStateResponse & #endif #ifdef USE_DATETIME_TIME #endif +#ifdef USE_VALVE +bool APIServerConnectionBase::send_list_entities_valve_response(const ListEntitiesValveResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_valve_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 109); +} +#endif +#ifdef USE_VALVE +bool APIServerConnectionBase::send_valve_state_response(const ValveStateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_valve_state_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 110); +} +#endif +#ifdef USE_VALVE +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -1019,6 +1037,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str()); #endif this->on_voice_assistant_audio(msg); +#endif + break; + } + case 111: { +#ifdef USE_VALVE + ValveCommandRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str()); +#endif + this->on_valve_command_request(msg); #endif break; } @@ -1282,6 +1311,19 @@ void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) this->lock_command(msg); } #endif +#ifdef USE_VALVE +void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->valve_command(msg); +} +#endif #ifdef USE_MEDIA_PLAYER void APIServerConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) { if (!this->is_connection_setup()) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 095ce51b0f..9f1d711257 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -279,6 +279,15 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_DATETIME_TIME virtual void on_time_command_request(const TimeCommandRequest &value){}; +#endif +#ifdef USE_VALVE + bool send_list_entities_valve_response(const ListEntitiesValveResponse &msg); +#endif +#ifdef USE_VALVE + bool send_valve_state_response(const ValveStateResponse &msg); +#endif +#ifdef USE_VALVE + virtual void on_valve_command_request(const ValveCommandRequest &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -331,6 +340,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_LOCK virtual void lock_command(const LockCommandRequest &msg) = 0; #endif +#ifdef USE_VALVE + virtual void valve_command(const ValveCommandRequest &msg) = 0; +#endif #ifdef USE_MEDIA_PLAYER virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0; #endif @@ -423,6 +435,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_LOCK void on_lock_command_request(const LockCommandRequest &msg) override; #endif +#ifdef USE_VALVE + void on_valve_command_request(const ValveCommandRequest &msg) override; +#endif #ifdef USE_MEDIA_PLAYER void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 4c809126e6..457eeb1229 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -300,6 +300,15 @@ void APIServer::on_lock_update(lock::Lock *obj) { } #endif +#ifdef USE_VALVE +void APIServer::on_valve_update(valve::Valve *obj) { + if (obj->is_internal()) + return; + for (auto &c : this->clients_) + c->send_valve_state(obj); +} +#endif + #ifdef USE_MEDIA_PLAYER void APIServer::on_media_player_update(media_player::MediaPlayer *obj) { if (obj->is_internal()) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 8a9c26af73..d64643b961 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -81,6 +81,9 @@ class APIServer : public Component, public Controller { #ifdef USE_LOCK void on_lock_update(lock::Lock *obj) override; #endif +#ifdef USE_VALVE + void on_valve_update(valve::Valve *obj) override; +#endif #ifdef USE_MEDIA_PLAYER void on_media_player_update(media_player::MediaPlayer *obj) override; #endif diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index 18685ee4d1..d6ff8e5557 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -38,6 +38,9 @@ bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) #ifdef USE_LOCK bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_info(a_lock); } #endif +#ifdef USE_VALVE +bool ListEntitiesIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_info(valve); } +#endif bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {} diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index 95a09fc25b..5d0c243f4a 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -61,6 +61,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_LOCK bool on_lock(lock::Lock *a_lock) override; #endif +#ifdef USE_VALVE + bool on_valve(valve::Valve *valve) override; +#endif #ifdef USE_MEDIA_PLAYER bool on_media_player(media_player::MediaPlayer *media_player) override; #endif diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 5eb40cfa7e..7aa8e8ffac 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -59,6 +59,9 @@ bool InitialStateIterator::on_select(select::Select *select) { #ifdef USE_LOCK bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); } #endif +#ifdef USE_VALVE +bool InitialStateIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_state(valve); } +#endif #ifdef USE_MEDIA_PLAYER bool InitialStateIterator::on_media_player(media_player::MediaPlayer *media_player) { return this->client_->send_media_player_state(media_player); diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 447f1707d2..8d50e0d89a 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -58,6 +58,9 @@ class InitialStateIterator : public ComponentIterator { #ifdef USE_LOCK bool on_lock(lock::Lock *a_lock) override; #endif +#ifdef USE_VALVE + bool on_valve(valve::Valve *valve) override; +#endif #ifdef USE_MEDIA_PLAYER bool on_media_player(media_player::MediaPlayer *media_player) override; #endif diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index b2c03c1546..72ee81dbbc 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -119,6 +119,7 @@ MQTTTextComponent = mqtt_ns.class_("MQTTTextComponent", MQTTComponent) MQTTSelectComponent = mqtt_ns.class_("MQTTSelectComponent", MQTTComponent) MQTTButtonComponent = mqtt_ns.class_("MQTTButtonComponent", MQTTComponent) MQTTLockComponent = mqtt_ns.class_("MQTTLockComponent", MQTTComponent) +MQTTValveComponent = mqtt_ns.class_("MQTTValveComponent", MQTTComponent) MQTTDiscoveryUniqueIdGenerator = mqtt_ns.enum("MQTTDiscoveryUniqueIdGenerator") MQTT_DISCOVERY_UNIQUE_ID_GENERATOR_OPTIONS = { diff --git a/esphome/components/mqtt/mqtt_valve.cpp b/esphome/components/mqtt/mqtt_valve.cpp new file mode 100644 index 0000000000..07eeca08d6 --- /dev/null +++ b/esphome/components/mqtt/mqtt_valve.cpp @@ -0,0 +1,90 @@ +#include "mqtt_valve.h" +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_VALVE + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.valve"; + +using namespace esphome::valve; + +MQTTValveComponent::MQTTValveComponent(Valve *valve) : valve_(valve) {} +void MQTTValveComponent::setup() { + auto traits = this->valve_->get_traits(); + this->valve_->add_on_state_callback([this]() { this->publish_state(); }); + this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &payload) { + auto call = this->valve_->make_call(); + call.set_command(payload.c_str()); + call.perform(); + }); + if (traits.get_supports_position()) { + this->subscribe(this->get_position_command_topic(), [this](const std::string &topic, const std::string &payload) { + auto value = parse_number(payload); + if (!value.has_value()) { + ESP_LOGW(TAG, "Invalid position value: '%s'", payload.c_str()); + return; + } + auto call = this->valve_->make_call(); + call.set_position(*value / 100.0f); + call.perform(); + }); + } +} + +void MQTTValveComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT valve '%s':", this->valve_->get_name().c_str()); + auto traits = this->valve_->get_traits(); + bool has_command_topic = traits.get_supports_position(); + LOG_MQTT_COMPONENT(true, has_command_topic) + if (traits.get_supports_position()) { + ESP_LOGCONFIG(TAG, " Position State Topic: '%s'", this->get_position_state_topic().c_str()); + ESP_LOGCONFIG(TAG, " Position Command Topic: '%s'", this->get_position_command_topic().c_str()); + } +} +void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + if (!this->valve_->get_device_class().empty()) + root[MQTT_DEVICE_CLASS] = this->valve_->get_device_class(); + + auto traits = this->valve_->get_traits(); + if (traits.get_is_assumed_state()) { + root[MQTT_OPTIMISTIC] = true; + } + if (traits.get_supports_position()) { + root[MQTT_POSITION_TOPIC] = this->get_position_state_topic(); + root[MQTT_SET_POSITION_TOPIC] = this->get_position_command_topic(); + } +} + +std::string MQTTValveComponent::component_type() const { return "valve"; } +const EntityBase *MQTTValveComponent::get_entity() const { return this->valve_; } + +bool MQTTValveComponent::send_initial_state() { return this->publish_state(); } +bool MQTTValveComponent::publish_state() { + auto traits = this->valve_->get_traits(); + bool success = true; + if (traits.get_supports_position()) { + std::string pos = value_accuracy_to_string(roundf(this->valve_->position * 100), 0); + if (!this->publish(this->get_position_state_topic(), pos)) + success = false; + } + const char *state_s = this->valve_->current_operation == VALVE_OPERATION_OPENING ? "opening" + : this->valve_->current_operation == VALVE_OPERATION_CLOSING ? "closing" + : this->valve_->position == VALVE_CLOSED ? "closed" + : this->valve_->position == VALVE_OPEN ? "open" + : traits.get_supports_position() ? "open" + : "unknown"; + if (!this->publish(this->get_state_topic_(), state_s)) + success = false; + return success; +} + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_valve.h b/esphome/components/mqtt/mqtt_valve.h new file mode 100644 index 0000000000..63a0462193 --- /dev/null +++ b/esphome/components/mqtt/mqtt_valve.h @@ -0,0 +1,41 @@ +#pragma once + +#include "esphome/core/defines.h" +#include "mqtt_component.h" + +#ifdef USE_MQTT +#ifdef USE_VALVE + +#include "esphome/components/valve/valve.h" + +namespace esphome { +namespace mqtt { + +class MQTTValveComponent : public mqtt::MQTTComponent { + public: + explicit MQTTValveComponent(valve::Valve *valve); + + void setup() override; + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + MQTT_COMPONENT_CUSTOM_TOPIC(position, command) + MQTT_COMPONENT_CUSTOM_TOPIC(position, state) + + bool send_initial_state() override; + + bool publish_state(); + + void dump_config() override; + + protected: + std::string component_type() const override; + const EntityBase *get_entity() const override; + + valve::Valve *valve_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/esphome/components/template/valve/__init__.py b/esphome/components/template/valve/__init__.py new file mode 100644 index 0000000000..89d776dfdd --- /dev/null +++ b/esphome/components/template/valve/__init__.py @@ -0,0 +1,118 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import valve +from esphome.const import ( + CONF_ASSUMED_STATE, + CONF_CLOSE_ACTION, + CONF_CURRENT_OPERATION, + CONF_ID, + CONF_LAMBDA, + CONF_OPEN_ACTION, + CONF_OPTIMISTIC, + CONF_POSITION, + CONF_POSITION_ACTION, + CONF_RESTORE_MODE, + CONF_STATE, + CONF_STOP_ACTION, +) +from .. import template_ns + +TemplateValve = template_ns.class_("TemplateValve", valve.Valve, cg.Component) + +TemplateValveRestoreMode = template_ns.enum("TemplateValveRestoreMode") +RESTORE_MODES = { + "NO_RESTORE": TemplateValveRestoreMode.VALVE_NO_RESTORE, + "RESTORE": TemplateValveRestoreMode.VALVE_RESTORE, + "RESTORE_AND_CALL": TemplateValveRestoreMode.VALVE_RESTORE_AND_CALL, +} + +CONF_HAS_POSITION = "has_position" +CONF_TOGGLE_ACTION = "toggle_action" + +CONFIG_SCHEMA = valve.VALVE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(TemplateValve), + cv.Optional(CONF_LAMBDA): cv.returning_lambda, + cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, + cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean, + cv.Optional(CONF_HAS_POSITION, default=False): cv.boolean, + cv.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True), + cv.Optional(CONF_CLOSE_ACTION): automation.validate_automation(single=True), + cv.Optional(CONF_STOP_ACTION): automation.validate_automation(single=True), + cv.Optional(CONF_TOGGLE_ACTION): automation.validate_automation(single=True), + cv.Optional(CONF_POSITION_ACTION): automation.validate_automation(single=True), + cv.Optional(CONF_RESTORE_MODE, default="NO_RESTORE"): cv.enum( + RESTORE_MODES, upper=True + ), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = await valve.new_valve(config) + await cg.register_component(var, config) + if lambda_config := config.get(CONF_LAMBDA): + template_ = await cg.process_lambda( + lambda_config, [], return_type=cg.optional.template(float) + ) + cg.add(var.set_state_lambda(template_)) + if open_action_config := config.get(CONF_OPEN_ACTION): + await automation.build_automation( + var.get_open_trigger(), [], open_action_config + ) + if close_action_config := config.get(CONF_CLOSE_ACTION): + await automation.build_automation( + var.get_close_trigger(), [], close_action_config + ) + if stop_action_config := config.get(CONF_STOP_ACTION): + await automation.build_automation( + var.get_stop_trigger(), [], stop_action_config + ) + cg.add(var.set_has_stop(True)) + if toggle_action_config := config.get(CONF_TOGGLE_ACTION): + await automation.build_automation( + var.get_toggle_trigger(), [], toggle_action_config + ) + cg.add(var.set_has_toggle(True)) + if position_action_config := config.get(CONF_POSITION_ACTION): + await automation.build_automation( + var.get_position_trigger(), [(float, "pos")], position_action_config + ) + cg.add(var.set_has_position(True)) + else: + cg.add(var.set_has_position(config[CONF_HAS_POSITION])) + cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) + cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE])) + cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) + + +@automation.register_action( + "valve.template.publish", + valve.ValvePublishAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(valve.Valve), + cv.Exclusive(CONF_STATE, "pos"): cv.templatable(valve.validate_valve_state), + cv.Exclusive(CONF_POSITION, "pos"): cv.templatable(cv.percentage), + cv.Optional(CONF_CURRENT_OPERATION): cv.templatable( + valve.validate_valve_operation + ), + } + ), +) +async def valve_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if state_config := config.get(CONF_STATE): + template_ = await cg.templatable(state_config, args, float) + cg.add(var.set_position(template_)) + if (position_config := config.get(CONF_POSITION)) is not None: + template_ = await cg.templatable(position_config, args, float) + cg.add(var.set_position(template_)) + if current_operation_config := config.get(CONF_CURRENT_OPERATION): + template_ = await cg.templatable( + current_operation_config, args, valve.ValveOperation + ) + cg.add(var.set_current_operation(template_)) + return var diff --git a/esphome/components/template/valve/template_valve.cpp b/esphome/components/template/valve/template_valve.cpp new file mode 100644 index 0000000000..f943e19da9 --- /dev/null +++ b/esphome/components/template/valve/template_valve.cpp @@ -0,0 +1,131 @@ +#include "template_valve.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace template_ { + +using namespace esphome::valve; + +static const char *const TAG = "template.valve"; + +TemplateValve::TemplateValve() + : open_trigger_(new Trigger<>()), + close_trigger_(new Trigger<>), + stop_trigger_(new Trigger<>()), + toggle_trigger_(new Trigger<>()), + position_trigger_(new Trigger()) {} + +void TemplateValve::setup() { + ESP_LOGCONFIG(TAG, "Setting up template valve '%s'...", this->name_.c_str()); + switch (this->restore_mode_) { + case VALVE_NO_RESTORE: + break; + case VALVE_RESTORE: { + auto restore = this->restore_state_(); + if (restore.has_value()) + restore->apply(this); + break; + } + case VALVE_RESTORE_AND_CALL: { + auto restore = this->restore_state_(); + if (restore.has_value()) { + restore->to_call(this).perform(); + } + break; + } + } +} + +void TemplateValve::loop() { + bool changed = false; + + if (this->state_f_.has_value()) { + auto s = (*this->state_f_)(); + if (s.has_value()) { + auto pos = clamp(*s, 0.0f, 1.0f); + if (pos != this->position) { + this->position = pos; + changed = true; + } + } + } + + if (changed) + this->publish_state(); +} + +void TemplateValve::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } +void TemplateValve::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; } +void TemplateValve::set_state_lambda(std::function()> &&f) { this->state_f_ = f; } +float TemplateValve::get_setup_priority() const { return setup_priority::HARDWARE; } + +Trigger<> *TemplateValve::get_open_trigger() const { return this->open_trigger_; } +Trigger<> *TemplateValve::get_close_trigger() const { return this->close_trigger_; } +Trigger<> *TemplateValve::get_stop_trigger() const { return this->stop_trigger_; } +Trigger<> *TemplateValve::get_toggle_trigger() const { return this->toggle_trigger_; } + +void TemplateValve::dump_config() { + LOG_VALVE("", "Template Valve", this); + ESP_LOGCONFIG(TAG, " Has position: %s", YESNO(this->has_position_)); + ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); +} + +void TemplateValve::control(const ValveCall &call) { + if (call.get_stop()) { + this->stop_prev_trigger_(); + this->stop_trigger_->trigger(); + this->prev_command_trigger_ = this->stop_trigger_; + this->publish_state(); + } + if (call.get_toggle().has_value()) { + this->stop_prev_trigger_(); + this->toggle_trigger_->trigger(); + this->prev_command_trigger_ = this->toggle_trigger_; + this->publish_state(); + } + if (call.get_position().has_value()) { + auto pos = *call.get_position(); + this->stop_prev_trigger_(); + + if (pos == VALVE_OPEN) { + this->open_trigger_->trigger(); + this->prev_command_trigger_ = this->open_trigger_; + } else if (pos == VALVE_CLOSED) { + this->close_trigger_->trigger(); + this->prev_command_trigger_ = this->close_trigger_; + } else { + this->position_trigger_->trigger(pos); + } + + if (this->optimistic_) { + this->position = pos; + } + } + + this->publish_state(); +} + +ValveTraits TemplateValve::get_traits() { + auto traits = ValveTraits(); + traits.set_is_assumed_state(this->assumed_state_); + traits.set_supports_stop(this->has_stop_); + traits.set_supports_toggle(this->has_toggle_); + traits.set_supports_position(this->has_position_); + return traits; +} + +Trigger *TemplateValve::get_position_trigger() const { return this->position_trigger_; } + +void TemplateValve::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; } +void TemplateValve::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; } +void TemplateValve::set_has_position(bool has_position) { this->has_position_ = has_position; } + +void TemplateValve::stop_prev_trigger_() { + if (this->prev_command_trigger_ != nullptr) { + this->prev_command_trigger_->stop_action(); + this->prev_command_trigger_ = nullptr; + } +} + +} // namespace template_ +} // namespace esphome diff --git a/esphome/components/template/valve/template_valve.h b/esphome/components/template/valve/template_valve.h new file mode 100644 index 0000000000..5e3fb6aff3 --- /dev/null +++ b/esphome/components/template/valve/template_valve.h @@ -0,0 +1,60 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/valve/valve.h" + +namespace esphome { +namespace template_ { + +enum TemplateValveRestoreMode { + VALVE_NO_RESTORE, + VALVE_RESTORE, + VALVE_RESTORE_AND_CALL, +}; + +class TemplateValve : public valve::Valve, public Component { + public: + TemplateValve(); + + void set_state_lambda(std::function()> &&f); + Trigger<> *get_open_trigger() const; + Trigger<> *get_close_trigger() const; + Trigger<> *get_stop_trigger() const; + Trigger<> *get_toggle_trigger() const; + Trigger *get_position_trigger() const; + void set_optimistic(bool optimistic); + void set_assumed_state(bool assumed_state); + void set_has_stop(bool has_stop); + void set_has_position(bool has_position); + void set_has_toggle(bool has_toggle); + void set_restore_mode(TemplateValveRestoreMode restore_mode) { restore_mode_ = restore_mode; } + + void setup() override; + void loop() override; + void dump_config() override; + + float get_setup_priority() const override; + + protected: + void control(const valve::ValveCall &call) override; + valve::ValveTraits get_traits() override; + void stop_prev_trigger_(); + + TemplateValveRestoreMode restore_mode_{VALVE_NO_RESTORE}; + optional()>> state_f_; + bool assumed_state_{false}; + bool optimistic_{false}; + Trigger<> *open_trigger_; + Trigger<> *close_trigger_; + bool has_stop_{false}; + bool has_toggle_{false}; + Trigger<> *stop_trigger_; + Trigger<> *toggle_trigger_; + Trigger<> *prev_command_trigger_{nullptr}; + Trigger *position_trigger_; + bool has_position_{false}; +}; + +} // namespace template_ +} // namespace esphome diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py new file mode 100644 index 0000000000..22d617cc36 --- /dev/null +++ b/esphome/components/valve/__init__.py @@ -0,0 +1,186 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.automation import maybe_simple_id, Condition +from esphome.components import mqtt +from esphome.const import ( + CONF_DEVICE_CLASS, + CONF_ID, + CONF_MQTT_ID, + CONF_ON_OPEN, + CONF_POSITION, + CONF_POSITION_COMMAND_TOPIC, + CONF_POSITION_STATE_TOPIC, + CONF_STATE, + CONF_STOP, + CONF_TRIGGER_ID, +) +from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_helpers import setup_entity + +IS_PLATFORM_COMPONENT = True + +CODEOWNERS = ["@esphome/core"] + +valve_ns = cg.esphome_ns.namespace("valve") + +Valve = valve_ns.class_("Valve", cg.EntityBase) + +VALVE_OPEN = valve_ns.VALVE_OPEN +VALVE_CLOSED = valve_ns.VALVE_CLOSED + +VALVE_STATES = { + "OPEN": VALVE_OPEN, + "CLOSED": VALVE_CLOSED, +} +validate_valve_state = cv.enum(VALVE_STATES, upper=True) + +ValveOperation = valve_ns.enum("ValveOperation") +VALVE_OPERATIONS = { + "IDLE": ValveOperation.VALVE_OPERATION_IDLE, + "OPENING": ValveOperation.VALVE_OPERATION_OPENING, + "CLOSING": ValveOperation.VALVE_OPERATION_CLOSING, +} +validate_valve_operation = cv.enum(VALVE_OPERATIONS, upper=True) + +# Actions +OpenAction = valve_ns.class_("OpenAction", automation.Action) +CloseAction = valve_ns.class_("CloseAction", automation.Action) +StopAction = valve_ns.class_("StopAction", automation.Action) +ToggleAction = valve_ns.class_("ToggleAction", automation.Action) +ControlAction = valve_ns.class_("ControlAction", automation.Action) +ValvePublishAction = valve_ns.class_("ValvePublishAction", automation.Action) +ValveIsOpenCondition = valve_ns.class_("ValveIsOpenCondition", Condition) +ValveIsClosedCondition = valve_ns.class_("ValveIsClosedCondition", Condition) + +# Triggers +ValveOpenTrigger = valve_ns.class_("ValveOpenTrigger", automation.Trigger.template()) +ValveClosedTrigger = valve_ns.class_( + "ValveClosedTrigger", automation.Trigger.template() +) + +CONF_ON_CLOSED = "on_closed" + +VALVE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(Valve), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTValveComponent), + cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_ON_OPEN): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveOpenTrigger), + } + ), + cv.Optional(CONF_ON_CLOSED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveClosedTrigger), + } + ), + } +) + + +async def setup_valve_core_(var, config): + await setup_entity(var, config) + + if device_class_config := config.get(CONF_DEVICE_CLASS): + cg.add(var.set_device_class(device_class_config)) + + for conf in config.get(CONF_ON_OPEN, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_CLOSED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + + if mqtt_id_config := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id_config, var) + await mqtt.register_mqtt_component(mqtt_, config) + + if position_state_topic_config := config.get(CONF_POSITION_STATE_TOPIC): + cg.add(mqtt_.set_custom_position_state_topic(position_state_topic_config)) + if position_command_topic_config := config.get(CONF_POSITION_COMMAND_TOPIC): + cg.add( + mqtt_.set_custom_position_command_topic(position_command_topic_config) + ) + + +async def register_valve(var, config): + if not CORE.has_id(config[CONF_ID]): + var = cg.Pvariable(config[CONF_ID], var) + cg.add(cg.App.register_valve(var)) + await setup_valve_core_(var, config) + + +async def new_valve(config, *args): + var = cg.new_Pvariable(config[CONF_ID], *args) + await register_valve(var, config) + return var + + +VALVE_ACTION_SCHEMA = maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(Valve), + } +) + + +@automation.register_action("valve.open", OpenAction, VALVE_ACTION_SCHEMA) +async def valve_open_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@automation.register_action("valve.close", CloseAction, VALVE_ACTION_SCHEMA) +async def valve_close_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@automation.register_action("valve.stop", StopAction, VALVE_ACTION_SCHEMA) +async def valve_stop_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@automation.register_action("valve.toggle", ToggleAction, VALVE_ACTION_SCHEMA) +def valve_toggle_to_code(config, action_id, template_arg, args): + paren = yield cg.get_variable(config[CONF_ID]) + yield cg.new_Pvariable(action_id, template_arg, paren) + + +VALVE_CONTROL_ACTION_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(Valve), + cv.Optional(CONF_STOP): cv.templatable(cv.boolean), + cv.Exclusive(CONF_STATE, "pos"): cv.templatable(validate_valve_state), + cv.Exclusive(CONF_POSITION, "pos"): cv.templatable(cv.percentage), + } +) + + +@automation.register_action("valve.control", ControlAction, VALVE_CONTROL_ACTION_SCHEMA) +async def valve_control_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if stop_config := config.get(CONF_STOP): + template_ = await cg.templatable(stop_config, args, bool) + cg.add(var.set_stop(template_)) + if state_config := config.get(CONF_STATE): + template_ = await cg.templatable(state_config, args, float) + cg.add(var.set_position(template_)) + if (position_config := config.get(CONF_POSITION)) is not None: + template_ = await cg.templatable(position_config, args, float) + cg.add(var.set_position(template_)) + return var + + +@coroutine_with_priority(100.0) +async def to_code(config): + cg.add_define("USE_VALVE") + cg.add_global(valve_ns.using) diff --git a/esphome/components/valve/automation.h b/esphome/components/valve/automation.h new file mode 100644 index 0000000000..24c94a5570 --- /dev/null +++ b/esphome/components/valve/automation.h @@ -0,0 +1,129 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "valve.h" + +namespace esphome { +namespace valve { + +template class OpenAction : public Action { + public: + explicit OpenAction(Valve *valve) : valve_(valve) {} + + void play(Ts... x) override { this->valve_->make_call().set_command_open().perform(); } + + protected: + Valve *valve_; +}; + +template class CloseAction : public Action { + public: + explicit CloseAction(Valve *valve) : valve_(valve) {} + + void play(Ts... x) override { this->valve_->make_call().set_command_close().perform(); } + + protected: + Valve *valve_; +}; + +template class StopAction : public Action { + public: + explicit StopAction(Valve *valve) : valve_(valve) {} + + void play(Ts... x) override { this->valve_->make_call().set_command_stop().perform(); } + + protected: + Valve *valve_; +}; + +template class ToggleAction : public Action { + public: + explicit ToggleAction(Valve *valve) : valve_(valve) {} + + void play(Ts... x) override { this->valve_->make_call().set_command_toggle().perform(); } + + protected: + Valve *valve_; +}; + +template class ControlAction : public Action { + public: + explicit ControlAction(Valve *valve) : valve_(valve) {} + + TEMPLATABLE_VALUE(bool, stop) + TEMPLATABLE_VALUE(float, position) + + void play(Ts... x) override { + auto call = this->valve_->make_call(); + if (this->stop_.has_value()) + call.set_stop(this->stop_.value(x...)); + if (this->position_.has_value()) + call.set_position(this->position_.value(x...)); + call.perform(); + } + + protected: + Valve *valve_; +}; + +template class ValvePublishAction : public Action { + public: + ValvePublishAction(Valve *valve) : valve_(valve) {} + TEMPLATABLE_VALUE(float, position) + TEMPLATABLE_VALUE(ValveOperation, current_operation) + + void play(Ts... x) override { + if (this->position_.has_value()) + this->valve_->position = this->position_.value(x...); + if (this->current_operation_.has_value()) + this->valve_->current_operation = this->current_operation_.value(x...); + this->valve_->publish_state(); + } + + protected: + Valve *valve_; +}; + +template class ValveIsOpenCondition : public Condition { + public: + ValveIsOpenCondition(Valve *valve) : valve_(valve) {} + bool check(Ts... x) override { return this->valve_->is_fully_open(); } + + protected: + Valve *valve_; +}; + +template class ValveIsClosedCondition : public Condition { + public: + ValveIsClosedCondition(Valve *valve) : valve_(valve) {} + bool check(Ts... x) override { return this->valve_->is_fully_closed(); } + + protected: + Valve *valve_; +}; + +class ValveOpenTrigger : public Trigger<> { + public: + ValveOpenTrigger(Valve *a_valve) { + a_valve->add_on_state_callback([this, a_valve]() { + if (a_valve->is_fully_open()) { + this->trigger(); + } + }); + } +}; + +class ValveClosedTrigger : public Trigger<> { + public: + ValveClosedTrigger(Valve *a_valve) { + a_valve->add_on_state_callback([this, a_valve]() { + if (a_valve->is_fully_closed()) { + this->trigger(); + } + }); + } +}; + +} // namespace valve +} // namespace esphome diff --git a/esphome/components/valve/valve.cpp b/esphome/components/valve/valve.cpp new file mode 100644 index 0000000000..d1ec17945a --- /dev/null +++ b/esphome/components/valve/valve.cpp @@ -0,0 +1,179 @@ +#include "valve.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace valve { + +static const char *const TAG = "valve"; + +const float VALVE_OPEN = 1.0f; +const float VALVE_CLOSED = 0.0f; + +const char *valve_command_to_str(float pos) { + if (pos == VALVE_OPEN) { + return "OPEN"; + } else if (pos == VALVE_CLOSED) { + return "CLOSE"; + } else { + return "UNKNOWN"; + } +} +const char *valve_operation_to_str(ValveOperation op) { + switch (op) { + case VALVE_OPERATION_IDLE: + return "IDLE"; + case VALVE_OPERATION_OPENING: + return "OPENING"; + case VALVE_OPERATION_CLOSING: + return "CLOSING"; + default: + return "UNKNOWN"; + } +} + +Valve::Valve() : position{VALVE_OPEN} {} + +ValveCall::ValveCall(Valve *parent) : parent_(parent) {} +ValveCall &ValveCall::set_command(const char *command) { + if (strcasecmp(command, "OPEN") == 0) { + this->set_command_open(); + } else if (strcasecmp(command, "CLOSE") == 0) { + this->set_command_close(); + } else if (strcasecmp(command, "STOP") == 0) { + this->set_command_stop(); + } else if (strcasecmp(command, "TOGGLE") == 0) { + this->set_command_toggle(); + } else { + ESP_LOGW(TAG, "'%s' - Unrecognized command %s", this->parent_->get_name().c_str(), command); + } + return *this; +} +ValveCall &ValveCall::set_command_open() { + this->position_ = VALVE_OPEN; + return *this; +} +ValveCall &ValveCall::set_command_close() { + this->position_ = VALVE_CLOSED; + return *this; +} +ValveCall &ValveCall::set_command_stop() { + this->stop_ = true; + return *this; +} +ValveCall &ValveCall::set_command_toggle() { + this->toggle_ = true; + return *this; +} +ValveCall &ValveCall::set_position(float position) { + this->position_ = position; + return *this; +} +void ValveCall::perform() { + ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str()); + auto traits = this->parent_->get_traits(); + this->validate_(); + if (this->stop_) { + ESP_LOGD(TAG, " Command: STOP"); + } + if (this->position_.has_value()) { + if (traits.get_supports_position()) { + ESP_LOGD(TAG, " Position: %.0f%%", *this->position_ * 100.0f); + } else { + ESP_LOGD(TAG, " Command: %s", valve_command_to_str(*this->position_)); + } + } + if (this->toggle_.has_value()) { + ESP_LOGD(TAG, " Command: TOGGLE"); + } + this->parent_->control(*this); +} +const optional &ValveCall::get_position() const { return this->position_; } +const optional &ValveCall::get_toggle() const { return this->toggle_; } +void ValveCall::validate_() { + auto traits = this->parent_->get_traits(); + if (this->position_.has_value()) { + auto pos = *this->position_; + if (!traits.get_supports_position() && pos != VALVE_OPEN && pos != VALVE_CLOSED) { + ESP_LOGW(TAG, "'%s' - This valve device does not support setting position!", this->parent_->get_name().c_str()); + this->position_.reset(); + } else if (pos < 0.0f || pos > 1.0f) { + ESP_LOGW(TAG, "'%s' - Position %.2f is out of range [0.0 - 1.0]", this->parent_->get_name().c_str(), pos); + this->position_ = clamp(pos, 0.0f, 1.0f); + } + } + if (this->toggle_.has_value()) { + if (!traits.get_supports_toggle()) { + ESP_LOGW(TAG, "'%s' - This valve device does not support toggle!", this->parent_->get_name().c_str()); + this->toggle_.reset(); + } + } + if (this->stop_) { + if (this->position_.has_value()) { + ESP_LOGW(TAG, "Cannot set position when stopping a valve!"); + this->position_.reset(); + } + if (this->toggle_.has_value()) { + ESP_LOGW(TAG, "Cannot set toggle when stopping a valve!"); + this->toggle_.reset(); + } + } +} +ValveCall &ValveCall::set_stop(bool stop) { + this->stop_ = stop; + return *this; +} +bool ValveCall::get_stop() const { return this->stop_; } + +ValveCall Valve::make_call() { return {this}; } + +void Valve::add_on_state_callback(std::function &&f) { this->state_callback_.add(std::move(f)); } +void Valve::publish_state(bool save) { + this->position = clamp(this->position, 0.0f, 1.0f); + + ESP_LOGD(TAG, "'%s' - Publishing:", this->name_.c_str()); + auto traits = this->get_traits(); + if (traits.get_supports_position()) { + ESP_LOGD(TAG, " Position: %.0f%%", this->position * 100.0f); + } else { + if (this->position == VALVE_OPEN) { + ESP_LOGD(TAG, " State: OPEN"); + } else if (this->position == VALVE_CLOSED) { + ESP_LOGD(TAG, " State: CLOSED"); + } else { + ESP_LOGD(TAG, " State: UNKNOWN"); + } + } + ESP_LOGD(TAG, " Current Operation: %s", valve_operation_to_str(this->current_operation)); + + this->state_callback_.call(); + + if (save) { + ValveRestoreState restore{}; + memset(&restore, 0, sizeof(restore)); + restore.position = this->position; + this->rtc_.save(&restore); + } +} +optional Valve::restore_state_() { + this->rtc_ = global_preferences->make_preference(this->get_object_id_hash()); + ValveRestoreState recovered{}; + if (!this->rtc_.load(&recovered)) + return {}; + return recovered; +} + +bool Valve::is_fully_open() const { return this->position == VALVE_OPEN; } +bool Valve::is_fully_closed() const { return this->position == VALVE_CLOSED; } + +ValveCall ValveRestoreState::to_call(Valve *valve) { + auto call = valve->make_call(); + call.set_position(this->position); + return call; +} +void ValveRestoreState::apply(Valve *valve) { + valve->position = this->position; + valve->publish_state(); +} + +} // namespace valve +} // namespace esphome diff --git a/esphome/components/valve/valve.h b/esphome/components/valve/valve.h new file mode 100644 index 0000000000..0e14a8d8f0 --- /dev/null +++ b/esphome/components/valve/valve.h @@ -0,0 +1,152 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/entity_base.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" +#include "valve_traits.h" + +namespace esphome { +namespace valve { + +const extern float VALVE_OPEN; +const extern float VALVE_CLOSED; + +#define LOG_VALVE(prefix, type, obj) \ + if ((obj) != nullptr) { \ + ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ + auto traits_ = (obj)->get_traits(); \ + if (traits_.get_is_assumed_state()) { \ + ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \ + } \ + if (!(obj)->get_device_class().empty()) { \ + ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ + } \ + } + +class Valve; + +class ValveCall { + public: + ValveCall(Valve *parent); + + /// Set the command as a string, "STOP", "OPEN", "CLOSE", "TOGGLE". + ValveCall &set_command(const char *command); + /// Set the command to open the valve. + ValveCall &set_command_open(); + /// Set the command to close the valve. + ValveCall &set_command_close(); + /// Set the command to stop the valve. + ValveCall &set_command_stop(); + /// Set the command to toggle the valve. + ValveCall &set_command_toggle(); + /// Set the call to a certain target position. + ValveCall &set_position(float position); + /// Set whether this valve call should stop the valve. + ValveCall &set_stop(bool stop); + + /// Perform the valve call. + void perform(); + + const optional &get_position() const; + bool get_stop() const; + const optional &get_toggle() const; + + protected: + void validate_(); + + Valve *parent_; + bool stop_{false}; + optional position_{}; + optional toggle_{}; +}; + +/// Struct used to store the restored state of a valve +struct ValveRestoreState { + float position; + + /// Convert this struct to a valve call that can be performed. + ValveCall to_call(Valve *valve); + /// Apply these settings to the valve + void apply(Valve *valve); +} __attribute__((packed)); + +/// Enum encoding the current operation of a valve. +enum ValveOperation : uint8_t { + /// The valve is currently idle (not moving) + VALVE_OPERATION_IDLE = 0, + /// The valve is currently opening. + VALVE_OPERATION_OPENING, + /// The valve is currently closing. + VALVE_OPERATION_CLOSING, +}; + +const char *valve_operation_to_str(ValveOperation op); + +/** Base class for all valve devices. + * + * Valves currently have three properties: + * - position - The current position of the valve from 0.0 (fully closed) to 1.0 (fully open). + * For valves with only binary OPEN/CLOSED position this will always be either 0.0 or 1.0 + * - current_operation - The operation the valve is currently performing, this can + * be one of IDLE, OPENING and CLOSING. + * + * For users: All valve operations must be performed over the .make_call() interface. + * To command a valve, use .make_call() to create a call object, set all properties + * you wish to set, and activate the command with .perform(). + * For reading out the current values of the valve, use the public .position, etc. + * properties (these are read-only for users) + * + * For integrations: Integrations must implement two methods: control() and get_traits(). + * Control will be called with the arguments supplied by the user and should be used + * to control all values of the valve. Also implement get_traits() to return what operations + * the valve supports. + */ +class Valve : public EntityBase, public EntityBase_DeviceClass { + public: + explicit Valve(); + + /// The current operation of the valve (idle, opening, closing). + ValveOperation current_operation{VALVE_OPERATION_IDLE}; + /** The position of the valve from 0.0 (fully closed) to 1.0 (fully open). + * + * For binary valves this is always equals to 0.0 or 1.0 (see also VALVE_OPEN and + * VALVE_CLOSED constants). + */ + float position; + + /// Construct a new valve call used to control the valve. + ValveCall make_call(); + + void add_on_state_callback(std::function &&f); + + /** Publish the current state of the valve. + * + * First set the .position, etc. values and then call this method + * to publish the state of the valve. + * + * @param save Whether to save the updated values in RTC area. + */ + void publish_state(bool save = true); + + virtual ValveTraits get_traits() = 0; + + /// Helper method to check if the valve is fully open. Equivalent to comparing .position against 1.0 + bool is_fully_open() const; + /// Helper method to check if the valve is fully closed. Equivalent to comparing .position against 0.0 + bool is_fully_closed() const; + + protected: + friend ValveCall; + + virtual void control(const ValveCall &call) = 0; + + optional restore_state_(); + + CallbackManager state_callback_{}; + + ESPPreferenceObject rtc_; +}; + +} // namespace valve +} // namespace esphome diff --git a/esphome/components/valve/valve_traits.h b/esphome/components/valve/valve_traits.h new file mode 100644 index 0000000000..7e9aab2f26 --- /dev/null +++ b/esphome/components/valve/valve_traits.h @@ -0,0 +1,27 @@ +#pragma once + +namespace esphome { +namespace valve { + +class ValveTraits { + public: + ValveTraits() = default; + + bool get_is_assumed_state() const { return this->is_assumed_state_; } + void set_is_assumed_state(bool is_assumed_state) { this->is_assumed_state_ = is_assumed_state; } + bool get_supports_position() const { return this->supports_position_; } + void set_supports_position(bool supports_position) { this->supports_position_ = supports_position; } + bool get_supports_toggle() const { return this->supports_toggle_; } + void set_supports_toggle(bool supports_toggle) { this->supports_toggle_ = supports_toggle; } + bool get_supports_stop() const { return this->supports_stop_; } + void set_supports_stop(bool supports_stop) { this->supports_stop_ = supports_stop; } + + protected: + bool is_assumed_state_{false}; + bool supports_position_{false}; + bool supports_toggle_{false}; + bool supports_stop_{false}; +}; + +} // namespace valve +} // namespace esphome diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index dd9fd4afe4..13e396dc82 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -86,6 +86,15 @@ bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { } #endif +#ifdef USE_VALVE +bool ListEntitiesIterator::on_valve(valve::Valve *valve) { + if (this->web_server_->events_.count() == 0) + return true; + this->web_server_->events_.send(this->web_server_->valve_json(valve, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + #ifdef USE_CLIMATE bool ListEntitiesIterator::on_climate(climate::Climate *climate) { if (this->web_server_->events_.count() == 0) diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index fc48186b32..d0b8dda233 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -56,6 +56,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_LOCK bool on_lock(lock::Lock *a_lock) override; #endif +#ifdef USE_VALVE + bool on_valve(valve::Valve *valve) override; +#endif #ifdef USE_ALARM_CONTROL_PANEL bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; #endif diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 2e6206b691..412f8816ee 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1260,6 +1260,68 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat } #endif +#ifdef USE_VALVE +void WebServer::on_valve_update(valve::Valve *obj) { + if (this->events_.count() == 0) + return; + this->events_.send(this->valve_json(obj, DETAIL_STATE).c_str(), "state"); +} +void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (valve::Valve *obj : App.get_valves()) { + if (obj->get_object_id() != match.id) + continue; + + if (request->method() == HTTP_GET && match.method.empty()) { + std::string data = this->valve_json(obj, DETAIL_STATE); + request->send(200, "application/json", data.c_str()); + continue; + } + + auto call = obj->make_call(); + if (match.method == "open") { + call.set_command_open(); + } else if (match.method == "close") { + call.set_command_close(); + } else if (match.method == "stop") { + call.set_command_stop(); + } else if (match.method == "toggle") { + call.set_command_toggle(); + } else if (match.method != "set") { + request->send(404); + return; + } + + auto traits = obj->get_traits(); + if (request->hasParam("position") && !traits.get_supports_position()) { + request->send(409); + return; + } + + if (request->hasParam("position")) { + auto position = parse_number(request->getParam("position")->value().c_str()); + if (position.has_value()) { + call.set_position(*position); + } + } + + this->schedule_([call]() mutable { call.perform(); }); + request->send(200); + return; + } + request->send(404); +} +std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) { + return json::build_json([obj, start_config](JsonObject root) { + set_json_icon_state_value(root, obj, "valve-" + obj->get_object_id(), obj->is_fully_closed() ? "CLOSED" : "OPEN", + obj->position, start_config); + root["current_operation"] = valve::valve_operation_to_str(obj->current_operation); + + if (obj->get_traits().get_supports_position()) + root["position"] = obj->position; + }); +} +#endif + #ifdef USE_ALARM_CONTROL_PANEL void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) { if (this->events_.count() == 0) @@ -1394,6 +1456,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_VALVE + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "valve") + return true; +#endif + #ifdef USE_ALARM_CONTROL_PANEL if (request->method() == HTTP_GET && match.domain == "alarm_control_panel") return true; @@ -1535,6 +1602,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { } #endif +#ifdef USE_VALVE + if (match.domain == "valve") { + this->handle_valve_request(request, match); + return; + } +#endif + #ifdef USE_ALARM_CONTROL_PANEL if (match.domain == "alarm_control_panel") { this->handle_alarm_control_panel_request(request, match); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 1935f8d076..9f807efc43 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -276,6 +276,16 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string lock_json(lock::Lock *obj, lock::LockState value, JsonDetail start_config); #endif +#ifdef USE_VALVE + void on_valve_update(valve::Valve *obj) override; + + /// Handle a valve request under '/valve//'. + void handle_valve_request(AsyncWebServerRequest *request, const UrlMatch &match); + + /// Dump the valve state as a JSON string. + std::string valve_json(valve::Valve *obj, JsonDetail start_config); +#endif + #ifdef USE_ALARM_CONTROL_PANEL void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override; diff --git a/esphome/core/application.h b/esphome/core/application.h index 73330d27e3..ee931282a6 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -54,6 +54,9 @@ #ifdef USE_LOCK #include "esphome/components/lock/lock.h" #endif +#ifdef USE_VALVE +#include "esphome/components/valve/valve.h" +#endif #ifdef USE_MEDIA_PLAYER #include "esphome/components/media_player/media_player.h" #endif @@ -147,6 +150,10 @@ class Application { void register_lock(lock::Lock *a_lock) { this->locks_.push_back(a_lock); } #endif +#ifdef USE_VALVE + void register_valve(valve::Valve *valve) { this->valves_.push_back(valve); } +#endif + #ifdef USE_MEDIA_PLAYER void register_media_player(media_player::MediaPlayer *media_player) { this->media_players_.push_back(media_player); } #endif @@ -348,6 +355,15 @@ class Application { return nullptr; } #endif +#ifdef USE_VALVE + const std::vector &get_valves() { return this->valves_; } + valve::Valve *get_valve_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->valves_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif #ifdef USE_MEDIA_PLAYER const std::vector &get_media_players() { return this->media_players_; } media_player::MediaPlayer *get_media_player_by_key(uint32_t key, bool include_internal = false) { @@ -429,6 +445,9 @@ class Application { #ifdef USE_LOCK std::vector locks_{}; #endif +#ifdef USE_VALVE + std::vector valves_{}; +#endif #ifdef USE_MEDIA_PLAYER std::vector media_players_{}; #endif diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index 228cf64d54..b00154c685 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -277,6 +277,21 @@ void ComponentIterator::advance() { } break; #endif +#ifdef USE_VALVE + case IteratorState::VALVE: + if (this->at_ >= App.get_valves().size()) { + advance_platform = true; + } else { + auto *valve = App.get_valves()[this->at_]; + if (valve->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_valve(valve); + } + } + break; +#endif #ifdef USE_MEDIA_PLAYER case IteratorState::MEDIA_PLAYER: if (this->at_ >= App.get_media_players().size()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index d7f19f2850..3fbbc0bc19 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -72,6 +72,9 @@ class ComponentIterator { #ifdef USE_LOCK virtual bool on_lock(lock::Lock *a_lock) = 0; #endif +#ifdef USE_VALVE + virtual bool on_valve(valve::Valve *valve) = 0; +#endif #ifdef USE_MEDIA_PLAYER virtual bool on_media_player(media_player::MediaPlayer *media_player); #endif @@ -135,6 +138,9 @@ class ComponentIterator { #ifdef USE_LOCK LOCK, #endif +#ifdef USE_VALVE + VALVE, +#endif #ifdef USE_MEDIA_PLAYER MEDIA_PLAYER, #endif diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index db5818d455..eab818bdb4 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -91,6 +91,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_state_callback([this, obj]() { this->on_lock_update(obj); }); } #endif +#ifdef USE_VALVE + for (auto *obj : App.get_valves()) { + if (include_internal || !obj->is_internal()) + obj->add_on_state_callback([this, obj]() { this->on_valve_update(obj); }); + } +#endif #ifdef USE_MEDIA_PLAYER for (auto *obj : App.get_media_players()) { if (include_internal || !obj->is_internal()) diff --git a/esphome/core/controller.h b/esphome/core/controller.h index 9b1cfd93c6..94a4acb7c7 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -46,6 +46,9 @@ #ifdef USE_LOCK #include "esphome/components/lock/lock.h" #endif +#ifdef USE_VALVE +#include "esphome/components/valve/valve.h" +#endif #ifdef USE_MEDIA_PLAYER #include "esphome/components/media_player/media_player.h" #endif @@ -100,6 +103,9 @@ class Controller { #ifdef USE_LOCK virtual void on_lock_update(lock::Lock *obj){}; #endif +#ifdef USE_VALVE + virtual void on_valve_update(valve::Valve *obj){}; +#endif #ifdef USE_MEDIA_PLAYER virtual void on_media_player_update(media_player::MediaPlayer *obj){}; #endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index f13ae968f0..2064ca1356 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -54,6 +54,7 @@ #define USE_TIME #define USE_TOUCHSCREEN #define USE_UART_DEBUGGER +#define USE_VALVE #define USE_WIFI #define USE_WIFI_AP #define USE_GRAPHICAL_DISPLAY_MENU diff --git a/script/ci-custom.py b/script/ci-custom.py index c3cfc7a331..c591bfe5c3 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -638,6 +638,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/stepper/stepper.h", "esphome/components/switch/switch.h", "esphome/components/text_sensor/text_sensor.h", + "esphome/components/valve/valve.h", "esphome/core/component.h", "esphome/core/gpio.h", "esphome/core/log.h", diff --git a/tests/components/template/test.all.yaml b/tests/components/template/test.all.yaml index 29dc83b649..64faec36c2 100644 --- a/tests/components/template/test.all.yaml +++ b/tests/components/template/test.all.yaml @@ -125,6 +125,23 @@ lock: open_action: - logger.log: open_action +valve: + - platform: template + name: "Template Valve" + lambda: |- + if (id(some_binary_sensor).state) { + return VALVE_OPEN; + } else { + return VALVE_CLOSED; + } + open_action: + - logger.log: open_action + close_action: + - logger.log: close_action + stop_action: + - logger.log: stop_action + optimistic: true + text: - platform: template name: "Template text" From 7e5b100b7778ba451d2ebda597ca7c4dc37ac3c1 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 22 Apr 2024 23:53:13 -0500 Subject: [PATCH 1606/2607] Add some components to the new testing framework (R) (#6219) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../radon_eye_ble/test.esp32-c3-idf.yaml | 3 ++ .../radon_eye_ble/test.esp32-c3.yaml | 3 ++ .../radon_eye_ble/test.esp32-idf.yaml | 3 ++ .../components/radon_eye_ble/test.esp32.yaml | 3 ++ .../radon_eye_rd200/test.esp32-c3-idf.yaml | 14 ++++++++ .../radon_eye_rd200/test.esp32-c3.yaml | 14 ++++++++ .../radon_eye_rd200/test.esp32-idf.yaml | 14 ++++++++ .../radon_eye_rd200/test.esp32.yaml | 14 ++++++++ .../rc522_i2c/test.esp32-c3-idf.yaml | 17 +++++++++ tests/components/rc522_i2c/test.esp32-c3.yaml | 17 +++++++++ .../components/rc522_i2c/test.esp32-idf.yaml | 17 +++++++++ tests/components/rc522_i2c/test.esp32.yaml | 17 +++++++++ tests/components/rc522_i2c/test.esp8266.yaml | 17 +++++++++ tests/components/rc522_i2c/test.rp2040.yaml | 17 +++++++++ .../rc522_spi/test.esp32-c3-idf.yaml | 15 ++++++++ tests/components/rc522_spi/test.esp32-c3.yaml | 15 ++++++++ .../components/rc522_spi/test.esp32-idf.yaml | 15 ++++++++ tests/components/rc522_spi/test.esp32.yaml | 15 ++++++++ tests/components/rc522_spi/test.esp8266.yaml | 15 ++++++++ tests/components/rc522_spi/test.rp2040.yaml | 15 ++++++++ .../components/rdm6300/test.esp32-c3-idf.yaml | 12 +++++++ tests/components/rdm6300/test.esp32-c3.yaml | 12 +++++++ tests/components/rdm6300/test.esp32-idf.yaml | 12 +++++++ tests/components/rdm6300/test.esp32.yaml | 12 +++++++ tests/components/rdm6300/test.esp8266.yaml | 12 +++++++ tests/components/rdm6300/test.rp2040.yaml | 12 +++++++ .../components/resistance/test.esp32-c3.yaml | 12 +++++++ .../components/resistance/test.esp32-idf.yaml | 12 +++++++ .../components/resistance/test.esp32-s2.yaml | 12 +++++++ .../components/resistance/test.esp32-s3.yaml | 12 +++++++ tests/components/resistance/test.esp32.yaml | 12 +++++++ tests/components/resistance/test.esp8266.yaml | 11 ++++++ tests/components/resistance/test.rp2040.yaml | 12 +++++++ .../components/restart/test.esp32-c3-idf.yaml | 7 ++++ tests/components/restart/test.esp32-c3.yaml | 7 ++++ tests/components/restart/test.esp32-idf.yaml | 7 ++++ tests/components/restart/test.esp32.yaml | 7 ++++ tests/components/restart/test.esp8266.yaml | 7 ++++ tests/components/restart/test.rp2040.yaml | 7 ++++ .../rf_bridge/test.esp32-c3-idf.yaml | 35 +++++++++++++++++++ tests/components/rf_bridge/test.esp32-c3.yaml | 35 +++++++++++++++++++ .../components/rf_bridge/test.esp32-idf.yaml | 35 +++++++++++++++++++ tests/components/rf_bridge/test.esp32.yaml | 35 +++++++++++++++++++ tests/components/rf_bridge/test.esp8266.yaml | 35 +++++++++++++++++++ tests/components/rf_bridge/test.rp2040.yaml | 35 +++++++++++++++++++ tests/components/rgb/test.esp32-c3-idf.yaml | 18 ++++++++++ tests/components/rgb/test.esp32-c3.yaml | 18 ++++++++++ tests/components/rgb/test.esp32-idf.yaml | 18 ++++++++++ tests/components/rgb/test.esp32.yaml | 18 ++++++++++ tests/components/rgb/test.esp8266.yaml | 18 ++++++++++ tests/components/rgb/test.rp2040.yaml | 18 ++++++++++ tests/components/rgbct/test.esp32-c3-idf.yaml | 28 +++++++++++++++ tests/components/rgbct/test.esp32-c3.yaml | 28 +++++++++++++++ tests/components/rgbct/test.esp32-idf.yaml | 28 +++++++++++++++ tests/components/rgbct/test.esp32.yaml | 28 +++++++++++++++ tests/components/rgbct/test.esp8266.yaml | 28 +++++++++++++++ tests/components/rgbct/test.rp2040.yaml | 28 +++++++++++++++ tests/components/rgbw/test.esp32-c3-idf.yaml | 22 ++++++++++++ tests/components/rgbw/test.esp32-c3.yaml | 22 ++++++++++++ tests/components/rgbw/test.esp32-idf.yaml | 22 ++++++++++++ tests/components/rgbw/test.esp32.yaml | 22 ++++++++++++ tests/components/rgbw/test.esp8266.yaml | 22 ++++++++++++ tests/components/rgbw/test.rp2040.yaml | 22 ++++++++++++ tests/components/rgbww/test.esp32-c3-idf.yaml | 28 +++++++++++++++ tests/components/rgbww/test.esp32-c3.yaml | 28 +++++++++++++++ tests/components/rgbww/test.esp32-idf.yaml | 28 +++++++++++++++ tests/components/rgbww/test.esp32.yaml | 28 +++++++++++++++ tests/components/rgbww/test.esp8266.yaml | 28 +++++++++++++++ tests/components/rgbww/test.rp2040.yaml | 28 +++++++++++++++ .../rotary_encoder/test.esp32-c3-idf.yaml | 25 +++++++++++++ .../rotary_encoder/test.esp32-c3.yaml | 25 +++++++++++++ .../rotary_encoder/test.esp32-idf.yaml | 25 +++++++++++++ .../components/rotary_encoder/test.esp32.yaml | 25 +++++++++++++ .../rotary_encoder/test.esp8266.yaml | 25 +++++++++++++ .../rotary_encoder/test.rp2040.yaml | 25 +++++++++++++ .../rp2040_pio_led_strip/test.rp2040.yaml | 18 ++++++++++ tests/components/rp2040_pwm/test.rp2040.yaml | 7 ++++ tests/components/rtttl/test.esp32-c3-idf.yaml | 16 +++++++++ tests/components/rtttl/test.esp32-c3.yaml | 16 +++++++++ tests/components/rtttl/test.esp32-idf.yaml | 16 +++++++++ tests/components/rtttl/test.esp32.yaml | 16 +++++++++ tests/components/rtttl/test.esp8266.yaml | 15 ++++++++ tests/components/rtttl/test.rp2040.yaml | 15 ++++++++ .../ruuvi_ble/test.esp32-c3-idf.yaml | 3 ++ tests/components/ruuvi_ble/test.esp32-c3.yaml | 3 ++ .../components/ruuvi_ble/test.esp32-idf.yaml | 3 ++ tests/components/ruuvi_ble/test.esp32.yaml | 3 ++ .../ruuvitag/test.esp32-c3-idf.yaml | 27 ++++++++++++++ tests/components/ruuvitag/test.esp32-c3.yaml | 27 ++++++++++++++ tests/components/ruuvitag/test.esp32-idf.yaml | 27 ++++++++++++++ tests/components/ruuvitag/test.esp32.yaml | 27 ++++++++++++++ 91 files changed, 1632 insertions(+) create mode 100644 tests/components/radon_eye_ble/test.esp32-c3-idf.yaml create mode 100644 tests/components/radon_eye_ble/test.esp32-c3.yaml create mode 100644 tests/components/radon_eye_ble/test.esp32-idf.yaml create mode 100644 tests/components/radon_eye_ble/test.esp32.yaml create mode 100644 tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml create mode 100644 tests/components/radon_eye_rd200/test.esp32-c3.yaml create mode 100644 tests/components/radon_eye_rd200/test.esp32-idf.yaml create mode 100644 tests/components/radon_eye_rd200/test.esp32.yaml create mode 100644 tests/components/rc522_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/rc522_i2c/test.esp32-c3.yaml create mode 100644 tests/components/rc522_i2c/test.esp32-idf.yaml create mode 100644 tests/components/rc522_i2c/test.esp32.yaml create mode 100644 tests/components/rc522_i2c/test.esp8266.yaml create mode 100644 tests/components/rc522_i2c/test.rp2040.yaml create mode 100644 tests/components/rc522_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/rc522_spi/test.esp32-c3.yaml create mode 100644 tests/components/rc522_spi/test.esp32-idf.yaml create mode 100644 tests/components/rc522_spi/test.esp32.yaml create mode 100644 tests/components/rc522_spi/test.esp8266.yaml create mode 100644 tests/components/rc522_spi/test.rp2040.yaml create mode 100644 tests/components/rdm6300/test.esp32-c3-idf.yaml create mode 100644 tests/components/rdm6300/test.esp32-c3.yaml create mode 100644 tests/components/rdm6300/test.esp32-idf.yaml create mode 100644 tests/components/rdm6300/test.esp32.yaml create mode 100644 tests/components/rdm6300/test.esp8266.yaml create mode 100644 tests/components/rdm6300/test.rp2040.yaml create mode 100644 tests/components/resistance/test.esp32-c3.yaml create mode 100644 tests/components/resistance/test.esp32-idf.yaml create mode 100644 tests/components/resistance/test.esp32-s2.yaml create mode 100644 tests/components/resistance/test.esp32-s3.yaml create mode 100644 tests/components/resistance/test.esp32.yaml create mode 100644 tests/components/resistance/test.esp8266.yaml create mode 100644 tests/components/resistance/test.rp2040.yaml create mode 100644 tests/components/restart/test.esp32-c3-idf.yaml create mode 100644 tests/components/restart/test.esp32-c3.yaml create mode 100644 tests/components/restart/test.esp32-idf.yaml create mode 100644 tests/components/restart/test.esp32.yaml create mode 100644 tests/components/restart/test.esp8266.yaml create mode 100644 tests/components/restart/test.rp2040.yaml create mode 100644 tests/components/rf_bridge/test.esp32-c3-idf.yaml create mode 100644 tests/components/rf_bridge/test.esp32-c3.yaml create mode 100644 tests/components/rf_bridge/test.esp32-idf.yaml create mode 100644 tests/components/rf_bridge/test.esp32.yaml create mode 100644 tests/components/rf_bridge/test.esp8266.yaml create mode 100644 tests/components/rf_bridge/test.rp2040.yaml create mode 100644 tests/components/rgb/test.esp32-c3-idf.yaml create mode 100644 tests/components/rgb/test.esp32-c3.yaml create mode 100644 tests/components/rgb/test.esp32-idf.yaml create mode 100644 tests/components/rgb/test.esp32.yaml create mode 100644 tests/components/rgb/test.esp8266.yaml create mode 100644 tests/components/rgb/test.rp2040.yaml create mode 100644 tests/components/rgbct/test.esp32-c3-idf.yaml create mode 100644 tests/components/rgbct/test.esp32-c3.yaml create mode 100644 tests/components/rgbct/test.esp32-idf.yaml create mode 100644 tests/components/rgbct/test.esp32.yaml create mode 100644 tests/components/rgbct/test.esp8266.yaml create mode 100644 tests/components/rgbct/test.rp2040.yaml create mode 100644 tests/components/rgbw/test.esp32-c3-idf.yaml create mode 100644 tests/components/rgbw/test.esp32-c3.yaml create mode 100644 tests/components/rgbw/test.esp32-idf.yaml create mode 100644 tests/components/rgbw/test.esp32.yaml create mode 100644 tests/components/rgbw/test.esp8266.yaml create mode 100644 tests/components/rgbw/test.rp2040.yaml create mode 100644 tests/components/rgbww/test.esp32-c3-idf.yaml create mode 100644 tests/components/rgbww/test.esp32-c3.yaml create mode 100644 tests/components/rgbww/test.esp32-idf.yaml create mode 100644 tests/components/rgbww/test.esp32.yaml create mode 100644 tests/components/rgbww/test.esp8266.yaml create mode 100644 tests/components/rgbww/test.rp2040.yaml create mode 100644 tests/components/rotary_encoder/test.esp32-c3-idf.yaml create mode 100644 tests/components/rotary_encoder/test.esp32-c3.yaml create mode 100644 tests/components/rotary_encoder/test.esp32-idf.yaml create mode 100644 tests/components/rotary_encoder/test.esp32.yaml create mode 100644 tests/components/rotary_encoder/test.esp8266.yaml create mode 100644 tests/components/rotary_encoder/test.rp2040.yaml create mode 100644 tests/components/rp2040_pio_led_strip/test.rp2040.yaml create mode 100644 tests/components/rp2040_pwm/test.rp2040.yaml create mode 100644 tests/components/rtttl/test.esp32-c3-idf.yaml create mode 100644 tests/components/rtttl/test.esp32-c3.yaml create mode 100644 tests/components/rtttl/test.esp32-idf.yaml create mode 100644 tests/components/rtttl/test.esp32.yaml create mode 100644 tests/components/rtttl/test.esp8266.yaml create mode 100644 tests/components/rtttl/test.rp2040.yaml create mode 100644 tests/components/ruuvi_ble/test.esp32-c3-idf.yaml create mode 100644 tests/components/ruuvi_ble/test.esp32-c3.yaml create mode 100644 tests/components/ruuvi_ble/test.esp32-idf.yaml create mode 100644 tests/components/ruuvi_ble/test.esp32.yaml create mode 100644 tests/components/ruuvitag/test.esp32-c3-idf.yaml create mode 100644 tests/components/ruuvitag/test.esp32-c3.yaml create mode 100644 tests/components/ruuvitag/test.esp32-idf.yaml create mode 100644 tests/components/ruuvitag/test.esp32.yaml diff --git a/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml b/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..85638d5c0e --- /dev/null +++ b/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +radon_eye_ble: diff --git a/tests/components/radon_eye_ble/test.esp32-c3.yaml b/tests/components/radon_eye_ble/test.esp32-c3.yaml new file mode 100644 index 0000000000..85638d5c0e --- /dev/null +++ b/tests/components/radon_eye_ble/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +radon_eye_ble: diff --git a/tests/components/radon_eye_ble/test.esp32-idf.yaml b/tests/components/radon_eye_ble/test.esp32-idf.yaml new file mode 100644 index 0000000000..85638d5c0e --- /dev/null +++ b/tests/components/radon_eye_ble/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +radon_eye_ble: diff --git a/tests/components/radon_eye_ble/test.esp32.yaml b/tests/components/radon_eye_ble/test.esp32.yaml new file mode 100644 index 0000000000..85638d5c0e --- /dev/null +++ b/tests/components/radon_eye_ble/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +radon_eye_ble: diff --git a/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml b/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d06979be6f --- /dev/null +++ b/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: radon_eye_blec + +sensor: + - platform: radon_eye_rd200 + ble_client_id: radon_eye_blec + radon: + name: RD200 Radon + radon_long_term: + name: RD200 Radon Long Term + update_interval: 10min diff --git a/tests/components/radon_eye_rd200/test.esp32-c3.yaml b/tests/components/radon_eye_rd200/test.esp32-c3.yaml new file mode 100644 index 0000000000..d06979be6f --- /dev/null +++ b/tests/components/radon_eye_rd200/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: radon_eye_blec + +sensor: + - platform: radon_eye_rd200 + ble_client_id: radon_eye_blec + radon: + name: RD200 Radon + radon_long_term: + name: RD200 Radon Long Term + update_interval: 10min diff --git a/tests/components/radon_eye_rd200/test.esp32-idf.yaml b/tests/components/radon_eye_rd200/test.esp32-idf.yaml new file mode 100644 index 0000000000..d06979be6f --- /dev/null +++ b/tests/components/radon_eye_rd200/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: radon_eye_blec + +sensor: + - platform: radon_eye_rd200 + ble_client_id: radon_eye_blec + radon: + name: RD200 Radon + radon_long_term: + name: RD200 Radon Long Term + update_interval: 10min diff --git a/tests/components/radon_eye_rd200/test.esp32.yaml b/tests/components/radon_eye_rd200/test.esp32.yaml new file mode 100644 index 0000000000..d06979be6f --- /dev/null +++ b/tests/components/radon_eye_rd200/test.esp32.yaml @@ -0,0 +1,14 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: radon_eye_blec + +sensor: + - platform: radon_eye_rd200 + ble_client_id: radon_eye_blec + radon: + name: RD200 Radon + radon_long_term: + name: RD200 Radon Long Term + update_interval: 10min diff --git a/tests/components/rc522_i2c/test.esp32-c3-idf.yaml b/tests/components/rc522_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..8c8819e257 --- /dev/null +++ b/tests/components/rc522_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 5 + sda: 4 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_i2c/test.esp32-c3.yaml b/tests/components/rc522_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..8c8819e257 --- /dev/null +++ b/tests/components/rc522_i2c/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 5 + sda: 4 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_i2c/test.esp32-idf.yaml b/tests/components/rc522_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..69b7d892a4 --- /dev/null +++ b/tests/components/rc522_i2c/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 16 + sda: 17 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_i2c/test.esp32.yaml b/tests/components/rc522_i2c/test.esp32.yaml new file mode 100644 index 0000000000..69b7d892a4 --- /dev/null +++ b/tests/components/rc522_i2c/test.esp32.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 16 + sda: 17 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_i2c/test.esp8266.yaml b/tests/components/rc522_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..8c8819e257 --- /dev/null +++ b/tests/components/rc522_i2c/test.esp8266.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 5 + sda: 4 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_i2c/test.rp2040.yaml b/tests/components/rc522_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..8c8819e257 --- /dev/null +++ b/tests/components/rc522_i2c/test.rp2040.yaml @@ -0,0 +1,17 @@ +i2c: + - id: i2c_rc522 + scl: 5 + sda: 4 + +rc522_i2c: + - id: rc522_nfcc + update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: RC522 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.esp32-c3-idf.yaml b/tests/components/rc522_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..8bcab84700 --- /dev/null +++ b/tests/components/rc522_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +rc522_spi: + id: rc522_nfcc + cs_pin: 4 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.esp32-c3.yaml b/tests/components/rc522_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..8bcab84700 --- /dev/null +++ b/tests/components/rc522_spi/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +rc522_spi: + id: rc522_nfcc + cs_pin: 4 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.esp32-idf.yaml b/tests/components/rc522_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..5c0b698a08 --- /dev/null +++ b/tests/components/rc522_spi/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +rc522_spi: + id: rc522_nfcc + cs_pin: 12 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.esp32.yaml b/tests/components/rc522_spi/test.esp32.yaml new file mode 100644 index 0000000000..5c0b698a08 --- /dev/null +++ b/tests/components/rc522_spi/test.esp32.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +rc522_spi: + id: rc522_nfcc + cs_pin: 12 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.esp8266.yaml b/tests/components/rc522_spi/test.esp8266.yaml new file mode 100644 index 0000000000..3c33311266 --- /dev/null +++ b/tests/components/rc522_spi/test.esp8266.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +rc522_spi: + id: rc522_nfcc + cs_pin: 15 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rc522_spi/test.rp2040.yaml b/tests/components/rc522_spi/test.rp2040.yaml new file mode 100644 index 0000000000..ed2827dbb9 --- /dev/null +++ b/tests/components/rc522_spi/test.rp2040.yaml @@ -0,0 +1,15 @@ +spi: + - id: spi_rc522 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +rc522_spi: + id: rc522_nfcc + cs_pin: 6 + +binary_sensor: + - platform: rc522 + rc522_id: rc522_nfcc + name: PN532 NFC Tag + uid: 74-10-37-94 diff --git a/tests/components/rdm6300/test.esp32-c3-idf.yaml b/tests/components/rdm6300/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b92fce06e2 --- /dev/null +++ b/tests/components/rdm6300/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/rdm6300/test.esp32-c3.yaml b/tests/components/rdm6300/test.esp32-c3.yaml new file mode 100644 index 0000000000..b92fce06e2 --- /dev/null +++ b/tests/components/rdm6300/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/rdm6300/test.esp32-idf.yaml b/tests/components/rdm6300/test.esp32-idf.yaml new file mode 100644 index 0000000000..4159248124 --- /dev/null +++ b/tests/components/rdm6300/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/rdm6300/test.esp32.yaml b/tests/components/rdm6300/test.esp32.yaml new file mode 100644 index 0000000000..4159248124 --- /dev/null +++ b/tests/components/rdm6300/test.esp32.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/rdm6300/test.esp8266.yaml b/tests/components/rdm6300/test.esp8266.yaml new file mode 100644 index 0000000000..b92fce06e2 --- /dev/null +++ b/tests/components/rdm6300/test.esp8266.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/rdm6300/test.rp2040.yaml b/tests/components/rdm6300/test.rp2040.yaml new file mode 100644 index 0000000000..b92fce06e2 --- /dev/null +++ b/tests/components/rdm6300/test.rp2040.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_rdm6300 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rdm6300: + +binary_sensor: + - platform: rdm6300 + uid: 7616525 + name: RDM6300 NFC Tag diff --git a/tests/components/resistance/test.esp32-c3.yaml b/tests/components/resistance/test.esp32-c3.yaml new file mode 100644 index 0000000000..84e23d5115 --- /dev/null +++ b/tests/components/resistance/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + pin: 4 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.esp32-idf.yaml b/tests/components/resistance/test.esp32-idf.yaml new file mode 100644 index 0000000000..b1ffc64972 --- /dev/null +++ b/tests/components/resistance/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + pin: 32 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.esp32-s2.yaml b/tests/components/resistance/test.esp32-s2.yaml new file mode 100644 index 0000000000..4ebd6b5c49 --- /dev/null +++ b/tests/components/resistance/test.esp32-s2.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + pin: 1 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.esp32-s3.yaml b/tests/components/resistance/test.esp32-s3.yaml new file mode 100644 index 0000000000..4ebd6b5c49 --- /dev/null +++ b/tests/components/resistance/test.esp32-s3.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + pin: 1 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.esp32.yaml b/tests/components/resistance/test.esp32.yaml new file mode 100644 index 0000000000..b1ffc64972 --- /dev/null +++ b/tests/components/resistance/test.esp32.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + pin: 32 + attenuation: 11db + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.esp8266.yaml b/tests/components/resistance/test.esp8266.yaml new file mode 100644 index 0000000000..f723f7c7c7 --- /dev/null +++ b/tests/components/resistance/test.esp8266.yaml @@ -0,0 +1,11 @@ +sensor: + - platform: adc + id: my_sensor + pin: VCC + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/resistance/test.rp2040.yaml b/tests/components/resistance/test.rp2040.yaml new file mode 100644 index 0000000000..5cc643926a --- /dev/null +++ b/tests/components/resistance/test.rp2040.yaml @@ -0,0 +1,12 @@ +sensor: + - platform: adc + id: my_sensor + name: VSYS + pin: VCC + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist diff --git a/tests/components/restart/test.esp32-c3-idf.yaml b/tests/components/restart/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.esp32-c3.yaml b/tests/components/restart/test.esp32-c3.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.esp32-idf.yaml b/tests/components/restart/test.esp32-idf.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.esp32.yaml b/tests/components/restart/test.esp32.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.esp32.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.esp8266.yaml b/tests/components/restart/test.esp8266.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.esp8266.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.rp2040.yaml b/tests/components/restart/test.rp2040.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/test.rp2040.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/rf_bridge/test.esp32-c3-idf.yaml b/tests/components/rf_bridge/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..95a7aa861a --- /dev/null +++ b/tests/components/rf_bridge/test.esp32-c3-idf.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rf_bridge/test.esp32-c3.yaml b/tests/components/rf_bridge/test.esp32-c3.yaml new file mode 100644 index 0000000000..95a7aa861a --- /dev/null +++ b/tests/components/rf_bridge/test.esp32-c3.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rf_bridge/test.esp32-idf.yaml b/tests/components/rf_bridge/test.esp32-idf.yaml new file mode 100644 index 0000000000..9ade7f0ac0 --- /dev/null +++ b/tests/components/rf_bridge/test.esp32-idf.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rf_bridge/test.esp32.yaml b/tests/components/rf_bridge/test.esp32.yaml new file mode 100644 index 0000000000..9ade7f0ac0 --- /dev/null +++ b/tests/components/rf_bridge/test.esp32.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rf_bridge/test.esp8266.yaml b/tests/components/rf_bridge/test.esp8266.yaml new file mode 100644 index 0000000000..95a7aa861a --- /dev/null +++ b/tests/components/rf_bridge/test.esp8266.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rf_bridge/test.rp2040.yaml b/tests/components/rf_bridge/test.rp2040.yaml new file mode 100644 index 0000000000..95a7aa861a --- /dev/null +++ b/tests/components/rf_bridge/test.rp2040.yaml @@ -0,0 +1,35 @@ +uart: + - id: uart_rf_bridge + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +rf_bridge: + on_code_received: + - lambda: |- + uint32_t test; + test = data.sync; + test = data.low; + test = data.high; + test = data.code; + - rf_bridge.send_code: + sync: 0x1234 + low: 0x1234 + high: 0x1234 + code: 0x123456 + - rf_bridge.learn + on_advanced_code_received: + - lambda: |- + uint32_t test; + std::string test_code; + test = data.length; + test = data.protocol; + test_code = data.code; + - rf_bridge.start_advanced_sniffing: + - rf_bridge.stop_advanced_sniffing: + - rf_bridge.send_advanced_code: + length: 0x04 + protocol: 0x01 + code: "ABC123" + - rf_bridge.send_raw: + raw: "AAA5070008001000ABC12355" diff --git a/tests/components/rgb/test.esp32-c3-idf.yaml b/tests/components/rgb/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..30ff1527b4 --- /dev/null +++ b/tests/components/rgb/test.esp32-c3-idf.yaml @@ -0,0 +1,18 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgb/test.esp32-c3.yaml b/tests/components/rgb/test.esp32-c3.yaml new file mode 100644 index 0000000000..30ff1527b4 --- /dev/null +++ b/tests/components/rgb/test.esp32-c3.yaml @@ -0,0 +1,18 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgb/test.esp32-idf.yaml b/tests/components/rgb/test.esp32-idf.yaml new file mode 100644 index 0000000000..2173e718be --- /dev/null +++ b/tests/components/rgb/test.esp32-idf.yaml @@ -0,0 +1,18 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgb/test.esp32.yaml b/tests/components/rgb/test.esp32.yaml new file mode 100644 index 0000000000..2173e718be --- /dev/null +++ b/tests/components/rgb/test.esp32.yaml @@ -0,0 +1,18 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgb/test.esp8266.yaml b/tests/components/rgb/test.esp8266.yaml new file mode 100644 index 0000000000..60c5a7e04f --- /dev/null +++ b/tests/components/rgb/test.esp8266.yaml @@ -0,0 +1,18 @@ +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 12 + - platform: esp8266_pwm + id: light_output_2 + pin: 13 + - platform: esp8266_pwm + id: light_output_3 + pin: 14 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgb/test.rp2040.yaml b/tests/components/rgb/test.rp2040.yaml new file mode 100644 index 0000000000..fd6519707b --- /dev/null +++ b/tests/components/rgb/test.rp2040.yaml @@ -0,0 +1,18 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 12 + - platform: rp2040_pwm + id: light_output_2 + pin: 13 + - platform: rp2040_pwm + id: light_output_3 + pin: 14 + +light: + - platform: rgb + name: RGB Light + id: rgb_light + red: light_output_1 + green: light_output_2 + blue: light_output_3 diff --git a/tests/components/rgbct/test.esp32-c3-idf.yaml b/tests/components/rgbct/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..426c4b8937 --- /dev/null +++ b/tests/components/rgbct/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + - platform: ledc + id: light_output_5 + pin: 5 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbct/test.esp32-c3.yaml b/tests/components/rgbct/test.esp32-c3.yaml new file mode 100644 index 0000000000..426c4b8937 --- /dev/null +++ b/tests/components/rgbct/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + - platform: ledc + id: light_output_5 + pin: 5 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbct/test.esp32-idf.yaml b/tests/components/rgbct/test.esp32-idf.yaml new file mode 100644 index 0000000000..d9758c9ec7 --- /dev/null +++ b/tests/components/rgbct/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + - platform: ledc + id: light_output_5 + pin: 16 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbct/test.esp32.yaml b/tests/components/rgbct/test.esp32.yaml new file mode 100644 index 0000000000..d9758c9ec7 --- /dev/null +++ b/tests/components/rgbct/test.esp32.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + - platform: ledc + id: light_output_5 + pin: 16 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbct/test.esp8266.yaml b/tests/components/rgbct/test.esp8266.yaml new file mode 100644 index 0000000000..b7008c9ae3 --- /dev/null +++ b/tests/components/rgbct/test.esp8266.yaml @@ -0,0 +1,28 @@ +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 12 + - platform: esp8266_pwm + id: light_output_2 + pin: 13 + - platform: esp8266_pwm + id: light_output_3 + pin: 14 + - platform: esp8266_pwm + id: light_output_4 + pin: 15 + - platform: esp8266_pwm + id: light_output_5 + pin: 16 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbct/test.rp2040.yaml b/tests/components/rgbct/test.rp2040.yaml new file mode 100644 index 0000000000..e7e959b2a4 --- /dev/null +++ b/tests/components/rgbct/test.rp2040.yaml @@ -0,0 +1,28 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 12 + - platform: rp2040_pwm + id: light_output_2 + pin: 13 + - platform: rp2040_pwm + id: light_output_3 + pin: 14 + - platform: rp2040_pwm + id: light_output_4 + pin: 15 + - platform: rp2040_pwm + id: light_output_5 + pin: 16 + +light: + - platform: rgbct + name: RGBCT Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + color_temperature: light_output_4 + white_brightness: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbw/test.esp32-c3-idf.yaml b/tests/components/rgbw/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c5d4fceb9d --- /dev/null +++ b/tests/components/rgbw/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbw/test.esp32-c3.yaml b/tests/components/rgbw/test.esp32-c3.yaml new file mode 100644 index 0000000000..c5d4fceb9d --- /dev/null +++ b/tests/components/rgbw/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbw/test.esp32-idf.yaml b/tests/components/rgbw/test.esp32-idf.yaml new file mode 100644 index 0000000000..6e9e92a03c --- /dev/null +++ b/tests/components/rgbw/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbw/test.esp32.yaml b/tests/components/rgbw/test.esp32.yaml new file mode 100644 index 0000000000..6e9e92a03c --- /dev/null +++ b/tests/components/rgbw/test.esp32.yaml @@ -0,0 +1,22 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbw/test.esp8266.yaml b/tests/components/rgbw/test.esp8266.yaml new file mode 100644 index 0000000000..54098613e4 --- /dev/null +++ b/tests/components/rgbw/test.esp8266.yaml @@ -0,0 +1,22 @@ +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 12 + - platform: esp8266_pwm + id: light_output_2 + pin: 13 + - platform: esp8266_pwm + id: light_output_3 + pin: 14 + - platform: esp8266_pwm + id: light_output_4 + pin: 15 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbw/test.rp2040.yaml b/tests/components/rgbw/test.rp2040.yaml new file mode 100644 index 0000000000..6a4437b898 --- /dev/null +++ b/tests/components/rgbw/test.rp2040.yaml @@ -0,0 +1,22 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 12 + - platform: rp2040_pwm + id: light_output_2 + pin: 13 + - platform: rp2040_pwm + id: light_output_3 + pin: 14 + - platform: rp2040_pwm + id: light_output_4 + pin: 15 + +light: + - platform: rgbw + name: RGBW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + white: light_output_4 + color_interlock: true diff --git a/tests/components/rgbww/test.esp32-c3-idf.yaml b/tests/components/rgbww/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..49e9c7f331 --- /dev/null +++ b/tests/components/rgbww/test.esp32-c3-idf.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + - platform: ledc + id: light_output_5 + pin: 5 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbww/test.esp32-c3.yaml b/tests/components/rgbww/test.esp32-c3.yaml new file mode 100644 index 0000000000..49e9c7f331 --- /dev/null +++ b/tests/components/rgbww/test.esp32-c3.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 1 + - platform: ledc + id: light_output_2 + pin: 2 + - platform: ledc + id: light_output_3 + pin: 3 + - platform: ledc + id: light_output_4 + pin: 4 + - platform: ledc + id: light_output_5 + pin: 5 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbww/test.esp32-idf.yaml b/tests/components/rgbww/test.esp32-idf.yaml new file mode 100644 index 0000000000..c24b6b7746 --- /dev/null +++ b/tests/components/rgbww/test.esp32-idf.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + - platform: ledc + id: light_output_5 + pin: 16 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbww/test.esp32.yaml b/tests/components/rgbww/test.esp32.yaml new file mode 100644 index 0000000000..c24b6b7746 --- /dev/null +++ b/tests/components/rgbww/test.esp32.yaml @@ -0,0 +1,28 @@ +output: + - platform: ledc + id: light_output_1 + pin: 12 + - platform: ledc + id: light_output_2 + pin: 13 + - platform: ledc + id: light_output_3 + pin: 14 + - platform: ledc + id: light_output_4 + pin: 15 + - platform: ledc + id: light_output_5 + pin: 16 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbww/test.esp8266.yaml b/tests/components/rgbww/test.esp8266.yaml new file mode 100644 index 0000000000..4ea26e6526 --- /dev/null +++ b/tests/components/rgbww/test.esp8266.yaml @@ -0,0 +1,28 @@ +output: + - platform: esp8266_pwm + id: light_output_1 + pin: 12 + - platform: esp8266_pwm + id: light_output_2 + pin: 13 + - platform: esp8266_pwm + id: light_output_3 + pin: 14 + - platform: esp8266_pwm + id: light_output_4 + pin: 15 + - platform: esp8266_pwm + id: light_output_5 + pin: 16 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rgbww/test.rp2040.yaml b/tests/components/rgbww/test.rp2040.yaml new file mode 100644 index 0000000000..0986f06e78 --- /dev/null +++ b/tests/components/rgbww/test.rp2040.yaml @@ -0,0 +1,28 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 12 + - platform: rp2040_pwm + id: light_output_2 + pin: 13 + - platform: rp2040_pwm + id: light_output_3 + pin: 14 + - platform: rp2040_pwm + id: light_output_4 + pin: 15 + - platform: rp2040_pwm + id: light_output_5 + pin: 16 + +light: + - platform: rgbww + name: RGBWW Light + red: light_output_1 + green: light_output_2 + blue: light_output_3 + cold_white: light_output_4 + warm_white: light_output_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true diff --git a/tests/components/rotary_encoder/test.esp32-c3-idf.yaml b/tests/components/rotary_encoder/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..59f8b56abf --- /dev/null +++ b/tests/components/rotary_encoder/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 3 + pin_b: 4 + pin_reset: 5 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rotary_encoder/test.esp32-c3.yaml b/tests/components/rotary_encoder/test.esp32-c3.yaml new file mode 100644 index 0000000000..59f8b56abf --- /dev/null +++ b/tests/components/rotary_encoder/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 3 + pin_b: 4 + pin_reset: 5 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rotary_encoder/test.esp32-idf.yaml b/tests/components/rotary_encoder/test.esp32-idf.yaml new file mode 100644 index 0000000000..da3843f82d --- /dev/null +++ b/tests/components/rotary_encoder/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 13 + pin_b: 14 + pin_reset: 15 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rotary_encoder/test.esp32.yaml b/tests/components/rotary_encoder/test.esp32.yaml new file mode 100644 index 0000000000..da3843f82d --- /dev/null +++ b/tests/components/rotary_encoder/test.esp32.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 13 + pin_b: 14 + pin_reset: 15 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rotary_encoder/test.esp8266.yaml b/tests/components/rotary_encoder/test.esp8266.yaml new file mode 100644 index 0000000000..da3843f82d --- /dev/null +++ b/tests/components/rotary_encoder/test.esp8266.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 13 + pin_b: 14 + pin_reset: 15 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rotary_encoder/test.rp2040.yaml b/tests/components/rotary_encoder/test.rp2040.yaml new file mode 100644 index 0000000000..da3843f82d --- /dev/null +++ b/tests/components/rotary_encoder/test.rp2040.yaml @@ -0,0 +1,25 @@ +sensor: + - platform: rotary_encoder + name: Rotary Encoder + id: rotary_encoder1 + pin_a: 13 + pin_b: 14 + pin_reset: 15 + filters: + - or: + - debounce: 0.1s + - delta: 10 + resolution: 4 + min_value: -10 + max_value: 30 + on_value: + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: 10 + - sensor.rotary_encoder.set_value: + id: rotary_encoder1 + value: !lambda "return -1;" + on_clockwise: + - logger.log: Clockwise + on_anticlockwise: + - logger.log: Anticlockwise diff --git a/tests/components/rp2040_pio_led_strip/test.rp2040.yaml b/tests/components/rp2040_pio_led_strip/test.rp2040.yaml new file mode 100644 index 0000000000..b9b1436cdb --- /dev/null +++ b/tests/components/rp2040_pio_led_strip/test.rp2040.yaml @@ -0,0 +1,18 @@ +light: + - platform: rp2040_pio_led_strip + id: led_strip + pin: 4 + num_leds: 60 + pio: 0 + rgb_order: GRB + chipset: WS2812 + - platform: rp2040_pio_led_strip + id: led_strip_custom_timings + pin: 5 + num_leds: 60 + pio: 1 + rgb_order: GRB + bit0_high: .1us + bit0_low: 1.2us + bit1_high: .69us + bit1_low: .4us diff --git a/tests/components/rp2040_pwm/test.rp2040.yaml b/tests/components/rp2040_pwm/test.rp2040.yaml new file mode 100644 index 0000000000..45c039106f --- /dev/null +++ b/tests/components/rp2040_pwm/test.rp2040.yaml @@ -0,0 +1,7 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 2 + - platform: rp2040_pwm + id: light_output_2 + pin: 3 diff --git a/tests/components/rtttl/test.esp32-c3-idf.yaml b/tests/components/rtttl/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c525f417de --- /dev/null +++ b/tests/components/rtttl/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: ledc + id: rtttl_output + pin: 1 + frequency: 1500Hz + channel: 14 + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/rtttl/test.esp32-c3.yaml b/tests/components/rtttl/test.esp32-c3.yaml new file mode 100644 index 0000000000..c525f417de --- /dev/null +++ b/tests/components/rtttl/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: ledc + id: rtttl_output + pin: 1 + frequency: 1500Hz + channel: 14 + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/rtttl/test.esp32-idf.yaml b/tests/components/rtttl/test.esp32-idf.yaml new file mode 100644 index 0000000000..367a670741 --- /dev/null +++ b/tests/components/rtttl/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: ledc + id: rtttl_output + pin: 13 + frequency: 1500Hz + channel: 14 + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/rtttl/test.esp32.yaml b/tests/components/rtttl/test.esp32.yaml new file mode 100644 index 0000000000..367a670741 --- /dev/null +++ b/tests/components/rtttl/test.esp32.yaml @@ -0,0 +1,16 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: ledc + id: rtttl_output + pin: 13 + frequency: 1500Hz + channel: 14 + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/rtttl/test.esp8266.yaml b/tests/components/rtttl/test.esp8266.yaml new file mode 100644 index 0000000000..c3b87c0f72 --- /dev/null +++ b/tests/components/rtttl/test.esp8266.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: esp8266_pwm + id: rtttl_output + pin: 13 + frequency: 1500Hz + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/rtttl/test.rp2040.yaml b/tests/components/rtttl/test.rp2040.yaml new file mode 100644 index 0000000000..ea240aa34d --- /dev/null +++ b/tests/components/rtttl/test.rp2040.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e' + - rtttl.stop + +output: + - platform: rp2040_pwm + id: rtttl_output + pin: 3 + frequency: 1500Hz + max_power: 0.5 + +rtttl: + output: rtttl_output diff --git a/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml b/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1f155fd8e1 --- /dev/null +++ b/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +ruuvi_ble: diff --git a/tests/components/ruuvi_ble/test.esp32-c3.yaml b/tests/components/ruuvi_ble/test.esp32-c3.yaml new file mode 100644 index 0000000000..1f155fd8e1 --- /dev/null +++ b/tests/components/ruuvi_ble/test.esp32-c3.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +ruuvi_ble: diff --git a/tests/components/ruuvi_ble/test.esp32-idf.yaml b/tests/components/ruuvi_ble/test.esp32-idf.yaml new file mode 100644 index 0000000000..1f155fd8e1 --- /dev/null +++ b/tests/components/ruuvi_ble/test.esp32-idf.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +ruuvi_ble: diff --git a/tests/components/ruuvi_ble/test.esp32.yaml b/tests/components/ruuvi_ble/test.esp32.yaml new file mode 100644 index 0000000000..1f155fd8e1 --- /dev/null +++ b/tests/components/ruuvi_ble/test.esp32.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +ruuvi_ble: diff --git a/tests/components/ruuvitag/test.esp32-c3-idf.yaml b/tests/components/ruuvitag/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7990617710 --- /dev/null +++ b/tests/components/ruuvitag/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +esp32_ble_tracker: + +sensor: + - platform: ruuvitag + mac_address: FF:56:D3:2F:7D:E8 + humidity: + name: RuuviTag Humidity + temperature: + name: RuuviTag Temperature + pressure: + name: RuuviTag Pressure + acceleration: + name: RuuviTag Acceleration + acceleration_x: + name: RuuviTag Acceleration X + acceleration_y: + name: RuuviTag Acceleration Y + acceleration_z: + name: RuuviTag Acceleration Z + battery_voltage: + name: RuuviTag Battery Voltage + tx_power: + name: RuuviTag TX Power + movement_counter: + name: RuuviTag Movement Counter + measurement_sequence_number: + name: RuuviTag Measurement Sequence Number diff --git a/tests/components/ruuvitag/test.esp32-c3.yaml b/tests/components/ruuvitag/test.esp32-c3.yaml new file mode 100644 index 0000000000..7990617710 --- /dev/null +++ b/tests/components/ruuvitag/test.esp32-c3.yaml @@ -0,0 +1,27 @@ +esp32_ble_tracker: + +sensor: + - platform: ruuvitag + mac_address: FF:56:D3:2F:7D:E8 + humidity: + name: RuuviTag Humidity + temperature: + name: RuuviTag Temperature + pressure: + name: RuuviTag Pressure + acceleration: + name: RuuviTag Acceleration + acceleration_x: + name: RuuviTag Acceleration X + acceleration_y: + name: RuuviTag Acceleration Y + acceleration_z: + name: RuuviTag Acceleration Z + battery_voltage: + name: RuuviTag Battery Voltage + tx_power: + name: RuuviTag TX Power + movement_counter: + name: RuuviTag Movement Counter + measurement_sequence_number: + name: RuuviTag Measurement Sequence Number diff --git a/tests/components/ruuvitag/test.esp32-idf.yaml b/tests/components/ruuvitag/test.esp32-idf.yaml new file mode 100644 index 0000000000..7990617710 --- /dev/null +++ b/tests/components/ruuvitag/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +esp32_ble_tracker: + +sensor: + - platform: ruuvitag + mac_address: FF:56:D3:2F:7D:E8 + humidity: + name: RuuviTag Humidity + temperature: + name: RuuviTag Temperature + pressure: + name: RuuviTag Pressure + acceleration: + name: RuuviTag Acceleration + acceleration_x: + name: RuuviTag Acceleration X + acceleration_y: + name: RuuviTag Acceleration Y + acceleration_z: + name: RuuviTag Acceleration Z + battery_voltage: + name: RuuviTag Battery Voltage + tx_power: + name: RuuviTag TX Power + movement_counter: + name: RuuviTag Movement Counter + measurement_sequence_number: + name: RuuviTag Measurement Sequence Number diff --git a/tests/components/ruuvitag/test.esp32.yaml b/tests/components/ruuvitag/test.esp32.yaml new file mode 100644 index 0000000000..7990617710 --- /dev/null +++ b/tests/components/ruuvitag/test.esp32.yaml @@ -0,0 +1,27 @@ +esp32_ble_tracker: + +sensor: + - platform: ruuvitag + mac_address: FF:56:D3:2F:7D:E8 + humidity: + name: RuuviTag Humidity + temperature: + name: RuuviTag Temperature + pressure: + name: RuuviTag Pressure + acceleration: + name: RuuviTag Acceleration + acceleration_x: + name: RuuviTag Acceleration X + acceleration_y: + name: RuuviTag Acceleration Y + acceleration_z: + name: RuuviTag Acceleration Z + battery_voltage: + name: RuuviTag Battery Voltage + tx_power: + name: RuuviTag TX Power + movement_counter: + name: RuuviTag Movement Counter + measurement_sequence_number: + name: RuuviTag Measurement Sequence Number From 8cb809d84de843a5866760ccb05ba7d5a266347f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Apr 2024 17:22:14 +1200 Subject: [PATCH 1607/2607] [sn74hc595] Enforce type field to distinguish gpio vs spi mode (#6609) --- esphome/components/sn74hc595/__init__.py | 69 +++++++++---------- .../sn74hc595/test.esp32-c3-idf.yaml | 27 ++++++++ tests/components/sn74hc595/test.esp32-c3.yaml | 27 ++++++++ .../components/sn74hc595/test.esp32-idf.yaml | 27 ++++++++ tests/components/sn74hc595/test.esp32.yaml | 27 ++++++++ tests/components/sn74hc595/test.esp8266.yaml | 27 ++++++++ tests/components/sn74hc595/test.rp2040.yaml | 27 ++++++++ tests/test1.yaml | 1 + 8 files changed, 197 insertions(+), 35 deletions(-) create mode 100644 tests/components/sn74hc595/test.esp32-c3-idf.yaml create mode 100644 tests/components/sn74hc595/test.esp32-c3.yaml create mode 100644 tests/components/sn74hc595/test.esp32-idf.yaml create mode 100644 tests/components/sn74hc595/test.esp32.yaml create mode 100644 tests/components/sn74hc595/test.esp8266.yaml create mode 100644 tests/components/sn74hc595/test.rp2040.yaml diff --git a/esphome/components/sn74hc595/__init__.py b/esphome/components/sn74hc595/__init__.py index 11a6747656..e0cd5e70ad 100644 --- a/esphome/components/sn74hc595/__init__.py +++ b/esphome/components/sn74hc595/__init__.py @@ -4,14 +4,13 @@ from esphome import pins from esphome.components import spi from esphome.const import ( CONF_ID, - CONF_SPI_ID, CONF_NUMBER, CONF_INVERTED, CONF_DATA_PIN, CONF_CLOCK_PIN, CONF_OUTPUT, + CONF_TYPE, ) -from esphome.core import EsphomeError MULTI_CONF = True @@ -34,53 +33,53 @@ CONF_LATCH_PIN = "latch_pin" CONF_OE_PIN = "oe_pin" CONF_SR_COUNT = "sr_count" -CONFIG_SCHEMA = cv.Any( - cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(SN74HC595GPIOComponent), - cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, - cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, - cv.Required(CONF_LATCH_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_OE_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_SR_COUNT, default=1): cv.int_range(min=1, max=256), - } - ).extend(cv.COMPONENT_SCHEMA), - cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(SN74HC595SPIComponent), - cv.Required(CONF_LATCH_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_OE_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_SR_COUNT, default=1): cv.int_range(min=1, max=256), - } - ) - .extend(cv.COMPONENT_SCHEMA) - .extend(spi.spi_device_schema(cs_pin_required=False)) - .extend( - { - cv.Required(CONF_SPI_ID): cv.use_id(spi.SPIComponent), - } - ), - msg='Either "data_pin" and "clock_pin" must be set or "spi_id" must be set.', +TYPE_GPIO = "gpio" +TYPE_SPI = "spi" + +_COMMON_SCHEMA = cv.Schema( + { + cv.Required(CONF_LATCH_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_OE_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_SR_COUNT, default=1): cv.int_range(min=1, max=256), + } +) + +CONFIG_SCHEMA = cv.typed_schema( + { + TYPE_GPIO: _COMMON_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.declare_id(SN74HC595GPIOComponent), + cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, + } + ).extend(cv.COMPONENT_SCHEMA), + TYPE_SPI: _COMMON_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.declare_id(SN74HC595SPIComponent), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(spi.spi_device_schema(cs_pin_required=False)), + }, + default_type=TYPE_GPIO, ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - if CONF_DATA_PIN in config: + if config[CONF_TYPE] == TYPE_GPIO: data_pin = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_data_pin(data_pin)) clock_pin = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_clock_pin(clock_pin)) - elif CONF_SPI_ID in config: - await spi.register_spi_device(var, config) else: - raise EsphomeError("Not supported") + await spi.register_spi_device(var, config) latch_pin = await cg.gpio_pin_expression(config[CONF_LATCH_PIN]) cg.add(var.set_latch_pin(latch_pin)) - if CONF_OE_PIN in config: - oe_pin = await cg.gpio_pin_expression(config[CONF_OE_PIN]) + if oe_pin := config.get(CONF_OE_PIN): + oe_pin = await cg.gpio_pin_expression(oe_pin) cg.add(var.set_oe_pin(oe_pin)) cg.add(var.set_sr_count(config[CONF_SR_COUNT])) diff --git a/tests/components/sn74hc595/test.esp32-c3-idf.yaml b/tests/components/sn74hc595/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9b093899d3 --- /dev/null +++ b/tests/components/sn74hc595/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 0 + data_pin: 1 + latch_pin: 2 + oe_pin: 3 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 8 + oe_pin: 9 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/components/sn74hc595/test.esp32-c3.yaml b/tests/components/sn74hc595/test.esp32-c3.yaml new file mode 100644 index 0000000000..9b093899d3 --- /dev/null +++ b/tests/components/sn74hc595/test.esp32-c3.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 0 + data_pin: 1 + latch_pin: 2 + oe_pin: 3 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 8 + oe_pin: 9 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/components/sn74hc595/test.esp32-idf.yaml b/tests/components/sn74hc595/test.esp32-idf.yaml new file mode 100644 index 0000000000..f695395797 --- /dev/null +++ b/tests/components/sn74hc595/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 12 + data_pin: 13 + latch_pin: 14 + oe_pin: 18 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 21 + oe_pin: 22 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/components/sn74hc595/test.esp32.yaml b/tests/components/sn74hc595/test.esp32.yaml new file mode 100644 index 0000000000..f695395797 --- /dev/null +++ b/tests/components/sn74hc595/test.esp32.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 12 + data_pin: 13 + latch_pin: 14 + oe_pin: 18 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 21 + oe_pin: 22 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/components/sn74hc595/test.esp8266.yaml b/tests/components/sn74hc595/test.esp8266.yaml new file mode 100644 index 0000000000..64bf5d1925 --- /dev/null +++ b/tests/components/sn74hc595/test.esp8266.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 0 + data_pin: 2 + latch_pin: 4 + oe_pin: 5 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 15 + oe_pin: 16 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/components/sn74hc595/test.rp2040.yaml b/tests/components/sn74hc595/test.rp2040.yaml new file mode 100644 index 0000000000..de8e192659 --- /dev/null +++ b/tests/components/sn74hc595/test.rp2040.yaml @@ -0,0 +1,27 @@ +spi: + - id: spi_sn74hc595 + clk_pin: 6 + mosi_pin: 5 + miso_pin: 4 + +sn74hc595: + - id: sn74hc595_hub + clock_pin: 0 + data_pin: 1 + latch_pin: 2 + oe_pin: 3 + sr_count: 2 + - id: sn74hc595_hub_2 + latch_pin: 8 + oe_pin: 9 + spi_id: spi_sn74hc595 + type: spi + sr_count: 2 + +switch: + - platform: gpio + name: SN74HC595 Pin 0 + pin: + sn74hc595: sn74hc595_hub_2 + number: 0 + inverted: false diff --git a/tests/test1.yaml b/tests/test1.yaml index c8ae9691c2..09994afa42 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3996,6 +3996,7 @@ sn74hc595: number: GPIO32 sr_count: 2 spi_id: spi_bus + type: spi rtttl: output: gpio_19 From 06d3829b45911952a01c47b8a3961623ff1dab0b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 22 Apr 2024 23:43:11 -0700 Subject: [PATCH 1608/2607] allow defaults with no include vars (#6613) --- esphome/yaml_util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index c7aa78201f..06bfd8b217 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -321,8 +321,9 @@ class ESPHomeLoaderMixin: file, vars = node.value, None result = _load_yaml_internal(self._rel_path(file)) - if vars: - result = substitute_vars(result, vars) + if not vars: + vars = {} + result = substitute_vars(result, vars) return result @_add_data_ref From b1839702f914621a90cc4c30644c449d32e006f1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:19:10 +1200 Subject: [PATCH 1609/2607] [tests] Run yaml tests in groups if over 100 to run (#6612) --- .github/workflows/ci.yml | 81 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15f0904df4..fd7a45ff50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,7 +398,8 @@ jobs: - common if: github.event_name == 'pull_request' outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} + components: ${{ steps.list-components.outputs.components }} + count: ${{ steps.list-components.outputs.count }} steps: - name: Check out code from GitHub uses: actions/checkout@v4.1.1 @@ -419,10 +420,18 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - name: Find changed components - id: set-matrix + id: list-components run: | . venv/bin/activate - echo "matrix=$(script/list-components.py --changed --branch ${{ steps.target-branch.outputs.branch }} | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + components=$(script/list-components.py --changed --branch ${{ steps.target-branch.outputs.branch }}) + output_components=$(echo "$components" | jq -R -s -c 'split("\n")[:-1] | map(select(length > 0))') + count=$(echo "$output_components" | jq length) + + echo "components=$output_components" >> $GITHUB_OUTPUT + echo "count=$count" >> $GITHUB_OUTPUT + + echo "$count Components:" + echo "$output_components" | jq test-build-components: name: Component test ${{ matrix.file }} @@ -430,12 +439,12 @@ jobs: needs: - common - list-components - if: ${{ github.event_name == 'pull_request' && needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }} + if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) > 0 && fromJSON(needs.list-components.outputs.count) < 100 strategy: fail-fast: false max-parallel: 2 matrix: - file: ${{ fromJson(needs.list-components.outputs.matrix) }} + file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install libsodium run: sudo apt-get install libsodium-dev @@ -456,6 +465,64 @@ jobs: . venv/bin/activate ./script/test_build_components -e compile -c ${{ matrix.file }} + test-build-components-splitter: + name: Split components for testing into 20 groups maximum + runs-on: ubuntu-latest + needs: + - common + - list-components + if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) >= 100 + outputs: + matrix: ${{ steps.split.outputs.components }} + steps: + - name: Check out code from GitHub + uses: actions/checkout@v4.1.1 + - name: Split components into 20 groups + id: split + run: | + components=$(echo '${{ needs.list-components.outputs.components }}' | jq -c '.[]' | shuf | jq -s -c '[_nwise(20) | join(" ")]') + echo "components=$components" >> $GITHUB_OUTPUT + + test-build-components-split: + name: Test split components + runs-on: ubuntu-latest + needs: + - common + - list-components + - test-build-components-splitter + if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) >= 100 + strategy: + fail-fast: false + max-parallel: 4 + matrix: + components: ${{ fromJson(needs.test-build-components-splitter.outputs.matrix) }} + steps: + - name: List components + run: echo ${{ matrix.components }} + + - name: Install libsodium + run: sudo apt-get install libsodium-dev + + - name: Check out code from GitHub + uses: actions/checkout@v4.1.1 + - name: Restore Python + uses: ./.github/actions/restore-python + with: + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} + - name: Validate config + run: | + . venv/bin/activate + for component in ${{ matrix.components }}; do + ./script/test_build_components -e config -c $component + done + - name: Compile config + run: | + . venv/bin/activate + for component in ${{ matrix.components }}; do + ./script/test_build_components -e compile -c $component + done + ci-status: name: CI Status runs-on: ubuntu-latest @@ -470,8 +537,10 @@ jobs: - pyupgrade - compile-tests - clang-tidy - - test-build-components - list-components + - test-build-components + - test-build-components-splitter + - test-build-components-split if: always() steps: - name: Success From 18149bc2762b284c17a0a0030691fa7566a9d1c4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 23 Apr 2024 04:36:30 -0500 Subject: [PATCH 1610/2607] Add some components to the new testing framework (I) (#6185) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- tests/components/i2c/test.esp32-c3-idf.yaml | 4 ++ tests/components/i2c/test.esp32-c3.yaml | 4 ++ tests/components/i2c/test.esp32-idf.yaml | 4 ++ tests/components/i2c/test.esp32.yaml | 4 ++ tests/components/i2c/test.esp8266.yaml | 4 ++ tests/components/i2c/test.rp2040.yaml | 4 ++ .../i2s_audio/test.esp32-c3-idf.yaml | 4 ++ tests/components/i2s_audio/test.esp32-c3.yaml | 4 ++ .../components/i2s_audio/test.esp32-idf.yaml | 4 ++ tests/components/i2s_audio/test.esp32.yaml | 4 ++ .../components/iaqcore/test.esp32-c3-idf.yaml | 11 ++++ tests/components/iaqcore/test.esp32-c3.yaml | 11 ++++ tests/components/iaqcore/test.esp32-idf.yaml | 11 ++++ tests/components/iaqcore/test.esp32.yaml | 11 ++++ tests/components/iaqcore/test.esp8266.yaml | 11 ++++ tests/components/iaqcore/test.rp2040.yaml | 11 ++++ .../components/ili9xxx/test.esp32-c3-idf.yaml | 35 +++++++++++ tests/components/ili9xxx/test.esp32-c3.yaml | 35 +++++++++++ tests/components/ili9xxx/test.esp32-idf.yaml | 35 +++++++++++ tests/components/ili9xxx/test.esp32.yaml | 37 ++++++++--- tests/components/ili9xxx/test.esp8266.yaml | 35 +++++++++++ tests/components/ili9xxx/test.rp2040.yaml | 35 +++++++++++ tests/components/image/test.esp32-c3-idf.yaml | 52 ++++++++++++++++ tests/components/image/test.esp32-c3.yaml | 52 ++++++++++++++++ tests/components/image/test.esp32-idf.yaml | 52 ++++++++++++++++ tests/components/image/test.esp32.yaml | 52 ++++++++++++++++ tests/components/image/test.esp8266.yaml | 52 ++++++++++++++++ tests/components/image/test.rp2040.yaml | 52 ++++++++++++++++ .../improv_serial/test.esp32-c3-idf.yaml | 5 ++ .../improv_serial/test.esp32-c3.yaml | 5 ++ .../improv_serial/test.esp32-idf.yaml | 5 ++ .../components/improv_serial/test.esp32.yaml | 5 ++ .../improv_serial/test.esp8266.yaml | 5 ++ .../components/improv_serial/test.rp2040.yaml | 5 ++ .../components/ina219/test.esp32-c3-idf.yaml | 20 ++++++ tests/components/ina219/test.esp32-c3.yaml | 20 ++++++ tests/components/ina219/test.esp32-idf.yaml | 20 ++++++ tests/components/ina219/test.esp32.yaml | 20 ++++++ tests/components/ina219/test.esp8266.yaml | 20 ++++++ tests/components/ina219/test.rp2040.yaml | 20 ++++++ .../components/ina226/test.esp32-c3-idf.yaml | 19 ++++++ tests/components/ina226/test.esp32-c3.yaml | 19 ++++++ tests/components/ina226/test.esp32-idf.yaml | 19 ++++++ tests/components/ina226/test.esp32.yaml | 19 ++++++ tests/components/ina226/test.esp8266.yaml | 19 ++++++ tests/components/ina226/test.rp2040.yaml | 19 ++++++ .../components/ina260/test.esp32-c3-idf.yaml | 15 +++++ tests/components/ina260/test.esp32-c3.yaml | 15 +++++ tests/components/ina260/test.esp32-idf.yaml | 15 +++++ tests/components/ina260/test.esp32.yaml | 15 +++++ tests/components/ina260/test.esp8266.yaml | 15 +++++ tests/components/ina260/test.rp2040.yaml | 15 +++++ .../components/ina3221/test.esp32-c3-idf.yaml | 19 ++++++ tests/components/ina3221/test.esp32-c3.yaml | 19 ++++++ tests/components/ina3221/test.esp32-idf.yaml | 19 ++++++ tests/components/ina3221/test.esp32.yaml | 19 ++++++ tests/components/ina3221/test.esp8266.yaml | 19 ++++++ tests/components/ina3221/test.rp2040.yaml | 19 ++++++ .../test.esp32-c3-idf.yaml | 11 ++++ .../inkbird_ibsth1_mini/test.esp32-c3.yaml | 11 ++++ .../inkbird_ibsth1_mini/test.esp32-idf.yaml | 11 ++++ .../inkbird_ibsth1_mini/test.esp32.yaml | 11 ++++ tests/components/inkplate6/test.esp32.yaml | 62 +++++++++++++++++++ .../components/integration/test.esp32-c3.yaml | 9 +++ .../integration/test.esp32-idf.yaml | 9 +++ .../components/integration/test.esp32-s2.yaml | 9 +++ .../components/integration/test.esp32-s3.yaml | 9 +++ tests/components/integration/test.esp32.yaml | 9 +++ .../components/integration/test.esp8266.yaml | 8 +++ tests/components/integration/test.rp2040.yaml | 8 +++ .../internal_temperature/test.esp32-c3.yaml | 2 +- .../internal_temperature/test.esp32-idf.yaml | 2 +- .../internal_temperature/test.esp32-s2.yaml | 3 + .../internal_temperature/test.esp32-s3.yaml | 7 +++ .../internal_temperature/test.esp32.yaml | 2 +- .../internal_temperature/test.rp2040.yaml | 2 +- .../interval/test.esp32-c3-idf.yaml | 4 ++ tests/components/interval/test.esp32-c3.yaml | 4 ++ tests/components/interval/test.esp32-idf.yaml | 4 ++ tests/components/interval/test.esp32.yaml | 4 ++ tests/components/interval/test.esp8266.yaml | 4 ++ tests/components/interval/test.rp2040.yaml | 4 ++ 82 files changed, 1296 insertions(+), 11 deletions(-) create mode 100644 tests/components/i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/i2c/test.esp32-c3.yaml create mode 100644 tests/components/i2c/test.esp32-idf.yaml create mode 100644 tests/components/i2c/test.esp32.yaml create mode 100644 tests/components/i2c/test.esp8266.yaml create mode 100644 tests/components/i2c/test.rp2040.yaml create mode 100644 tests/components/i2s_audio/test.esp32-c3-idf.yaml create mode 100644 tests/components/i2s_audio/test.esp32-c3.yaml create mode 100644 tests/components/i2s_audio/test.esp32-idf.yaml create mode 100644 tests/components/i2s_audio/test.esp32.yaml create mode 100644 tests/components/iaqcore/test.esp32-c3-idf.yaml create mode 100644 tests/components/iaqcore/test.esp32-c3.yaml create mode 100644 tests/components/iaqcore/test.esp32-idf.yaml create mode 100644 tests/components/iaqcore/test.esp32.yaml create mode 100644 tests/components/iaqcore/test.esp8266.yaml create mode 100644 tests/components/iaqcore/test.rp2040.yaml create mode 100644 tests/components/ili9xxx/test.esp32-c3-idf.yaml create mode 100644 tests/components/ili9xxx/test.esp32-c3.yaml create mode 100644 tests/components/ili9xxx/test.esp32-idf.yaml create mode 100644 tests/components/ili9xxx/test.esp8266.yaml create mode 100644 tests/components/ili9xxx/test.rp2040.yaml create mode 100644 tests/components/image/test.esp32-c3-idf.yaml create mode 100644 tests/components/image/test.esp32-c3.yaml create mode 100644 tests/components/image/test.esp32-idf.yaml create mode 100644 tests/components/image/test.esp32.yaml create mode 100644 tests/components/image/test.esp8266.yaml create mode 100644 tests/components/image/test.rp2040.yaml create mode 100644 tests/components/improv_serial/test.esp32-c3-idf.yaml create mode 100644 tests/components/improv_serial/test.esp32-c3.yaml create mode 100644 tests/components/improv_serial/test.esp32-idf.yaml create mode 100644 tests/components/improv_serial/test.esp32.yaml create mode 100644 tests/components/improv_serial/test.esp8266.yaml create mode 100644 tests/components/improv_serial/test.rp2040.yaml create mode 100644 tests/components/ina219/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina219/test.esp32-c3.yaml create mode 100644 tests/components/ina219/test.esp32-idf.yaml create mode 100644 tests/components/ina219/test.esp32.yaml create mode 100644 tests/components/ina219/test.esp8266.yaml create mode 100644 tests/components/ina219/test.rp2040.yaml create mode 100644 tests/components/ina226/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina226/test.esp32-c3.yaml create mode 100644 tests/components/ina226/test.esp32-idf.yaml create mode 100644 tests/components/ina226/test.esp32.yaml create mode 100644 tests/components/ina226/test.esp8266.yaml create mode 100644 tests/components/ina226/test.rp2040.yaml create mode 100644 tests/components/ina260/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina260/test.esp32-c3.yaml create mode 100644 tests/components/ina260/test.esp32-idf.yaml create mode 100644 tests/components/ina260/test.esp32.yaml create mode 100644 tests/components/ina260/test.esp8266.yaml create mode 100644 tests/components/ina260/test.rp2040.yaml create mode 100644 tests/components/ina3221/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina3221/test.esp32-c3.yaml create mode 100644 tests/components/ina3221/test.esp32-idf.yaml create mode 100644 tests/components/ina3221/test.esp32.yaml create mode 100644 tests/components/ina3221/test.esp8266.yaml create mode 100644 tests/components/ina3221/test.rp2040.yaml create mode 100644 tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml create mode 100644 tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml create mode 100644 tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml create mode 100644 tests/components/inkbird_ibsth1_mini/test.esp32.yaml create mode 100644 tests/components/inkplate6/test.esp32.yaml create mode 100644 tests/components/integration/test.esp32-c3.yaml create mode 100644 tests/components/integration/test.esp32-idf.yaml create mode 100644 tests/components/integration/test.esp32-s2.yaml create mode 100644 tests/components/integration/test.esp32-s3.yaml create mode 100644 tests/components/integration/test.esp32.yaml create mode 100644 tests/components/integration/test.esp8266.yaml create mode 100644 tests/components/integration/test.rp2040.yaml create mode 100644 tests/components/internal_temperature/test.esp32-s2.yaml create mode 100644 tests/components/internal_temperature/test.esp32-s3.yaml create mode 100644 tests/components/interval/test.esp32-c3-idf.yaml create mode 100644 tests/components/interval/test.esp32-c3.yaml create mode 100644 tests/components/interval/test.esp32-idf.yaml create mode 100644 tests/components/interval/test.esp32.yaml create mode 100644 tests/components/interval/test.esp8266.yaml create mode 100644 tests/components/interval/test.rp2040.yaml diff --git a/tests/components/i2c/test.esp32-c3-idf.yaml b/tests/components/i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a881438faa --- /dev/null +++ b/tests/components/i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 diff --git a/tests/components/i2c/test.esp32-c3.yaml b/tests/components/i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..a881438faa --- /dev/null +++ b/tests/components/i2c/test.esp32-c3.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 diff --git a/tests/components/i2c/test.esp32-idf.yaml b/tests/components/i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..19114a9e5d --- /dev/null +++ b/tests/components/i2c/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 16 + sda: 17 diff --git a/tests/components/i2c/test.esp32.yaml b/tests/components/i2c/test.esp32.yaml new file mode 100644 index 0000000000..19114a9e5d --- /dev/null +++ b/tests/components/i2c/test.esp32.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 16 + sda: 17 diff --git a/tests/components/i2c/test.esp8266.yaml b/tests/components/i2c/test.esp8266.yaml new file mode 100644 index 0000000000..a881438faa --- /dev/null +++ b/tests/components/i2c/test.esp8266.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 diff --git a/tests/components/i2c/test.rp2040.yaml b/tests/components/i2c/test.rp2040.yaml new file mode 100644 index 0000000000..a881438faa --- /dev/null +++ b/tests/components/i2c/test.rp2040.yaml @@ -0,0 +1,4 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 diff --git a/tests/components/i2s_audio/test.esp32-c3-idf.yaml b/tests/components/i2s_audio/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..08cd56b1a7 --- /dev/null +++ b/tests/components/i2s_audio/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +i2s_audio: + i2s_bclk_pin: 7 + i2s_lrclk_pin: 6 + i2s_mclk_pin: 5 diff --git a/tests/components/i2s_audio/test.esp32-c3.yaml b/tests/components/i2s_audio/test.esp32-c3.yaml new file mode 100644 index 0000000000..08cd56b1a7 --- /dev/null +++ b/tests/components/i2s_audio/test.esp32-c3.yaml @@ -0,0 +1,4 @@ +i2s_audio: + i2s_bclk_pin: 7 + i2s_lrclk_pin: 6 + i2s_mclk_pin: 5 diff --git a/tests/components/i2s_audio/test.esp32-idf.yaml b/tests/components/i2s_audio/test.esp32-idf.yaml new file mode 100644 index 0000000000..938dd5c25f --- /dev/null +++ b/tests/components/i2s_audio/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +i2s_audio: + i2s_bclk_pin: 27 + i2s_lrclk_pin: 26 + i2s_mclk_pin: 25 diff --git a/tests/components/i2s_audio/test.esp32.yaml b/tests/components/i2s_audio/test.esp32.yaml new file mode 100644 index 0000000000..938dd5c25f --- /dev/null +++ b/tests/components/i2s_audio/test.esp32.yaml @@ -0,0 +1,4 @@ +i2s_audio: + i2s_bclk_pin: 27 + i2s_lrclk_pin: 26 + i2s_mclk_pin: 25 diff --git a/tests/components/iaqcore/test.esp32-c3-idf.yaml b/tests/components/iaqcore/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a1809dffd7 --- /dev/null +++ b/tests/components/iaqcore/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 5 + sda: 4 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/iaqcore/test.esp32-c3.yaml b/tests/components/iaqcore/test.esp32-c3.yaml new file mode 100644 index 0000000000..a1809dffd7 --- /dev/null +++ b/tests/components/iaqcore/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 5 + sda: 4 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/iaqcore/test.esp32-idf.yaml b/tests/components/iaqcore/test.esp32-idf.yaml new file mode 100644 index 0000000000..26b01dadf9 --- /dev/null +++ b/tests/components/iaqcore/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 16 + sda: 17 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/iaqcore/test.esp32.yaml b/tests/components/iaqcore/test.esp32.yaml new file mode 100644 index 0000000000..26b01dadf9 --- /dev/null +++ b/tests/components/iaqcore/test.esp32.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 16 + sda: 17 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/iaqcore/test.esp8266.yaml b/tests/components/iaqcore/test.esp8266.yaml new file mode 100644 index 0000000000..a1809dffd7 --- /dev/null +++ b/tests/components/iaqcore/test.esp8266.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 5 + sda: 4 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/iaqcore/test.rp2040.yaml b/tests/components/iaqcore/test.rp2040.yaml new file mode 100644 index 0000000000..a1809dffd7 --- /dev/null +++ b/tests/components/iaqcore/test.rp2040.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_iaqcore + scl: 5 + sda: 4 + +sensor: + - platform: iaqcore + co2: + name: iAQ Core CO2 Sensor + tvoc: + name: iAQ Core TVOC Sensor diff --git a/tests/components/ili9xxx/test.esp32-c3-idf.yaml b/tests/components/ili9xxx/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9526ae1f6b --- /dev/null +++ b/tests/components/ili9xxx/test.esp32-c3-idf.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/ili9xxx/test.esp32-c3.yaml b/tests/components/ili9xxx/test.esp32-c3.yaml new file mode 100644 index 0000000000..9526ae1f6b --- /dev/null +++ b/tests/components/ili9xxx/test.esp32-c3.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/ili9xxx/test.esp32-idf.yaml b/tests/components/ili9xxx/test.esp32-idf.yaml new file mode 100644 index 0000000000..0d7bda8ac6 --- /dev/null +++ b/tests/components/ili9xxx/test.esp32-idf.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 25 + dc_pin: 26 + reset_pin: 27 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/ili9xxx/test.esp32.yaml b/tests/components/ili9xxx/test.esp32.yaml index 1095d565d2..ecee21686e 100644 --- a/tests/components/ili9xxx/test.esp32.yaml +++ b/tests/components/ili9xxx/test.esp32.yaml @@ -1,11 +1,34 @@ spi: - mosi_pin: GPIO23 - clk_pin: GPIO18 + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 display: - platform: ili9xxx - model: gc9a01a - id: gca901_display - cs_pin: GPIO5 - dc_pin: GPIO22 - reset_pin: GPIO21 + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 25 + dc_pin: 26 + reset_pin: 27 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/ili9xxx/test.esp8266.yaml b/tests/components/ili9xxx/test.esp8266.yaml new file mode 100644 index 0000000000..0791c25aca --- /dev/null +++ b/tests/components/ili9xxx/test.esp8266.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ili9xxx + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 5 + dc_pin: 15 + reset_pin: 16 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 2 + dc_pin: 4 + reset_pin: 0 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/ili9xxx/test.rp2040.yaml b/tests/components/ili9xxx/test.rp2040.yaml new file mode 100644 index 0000000000..54083ebce8 --- /dev/null +++ b/tests/components/ili9xxx/test.rp2040.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ili9xxx + invert_colors: true + dimensions: 320x240 + transform: + swap_xy: true + mirror_x: true + mirror_y: false + model: TFT 2.4 + color_palette: GRAYSCALE + cs_pin: 5 + dc_pin: 15 + reset_pin: 16 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: ili9xxx + dimensions: + width: 320 + height: 240 + offset_width: 20 + offset_height: 10 + model: TFT 2.4 + cs_pin: 20 + dc_pin: 21 + reset_pin: 22 + auto_clear_enabled: false + rotation: 90 + lambda: |- + it.fill(Color::WHITE); diff --git a/tests/components/image/test.esp32-c3-idf.yaml b/tests/components/image/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c083a97c94 --- /dev/null +++ b/tests/components/image/test.esp32-c3-idf.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.esp32-c3.yaml b/tests/components/image/test.esp32-c3.yaml new file mode 100644 index 0000000000..c083a97c94 --- /dev/null +++ b/tests/components/image/test.esp32-c3.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.esp32-idf.yaml b/tests/components/image/test.esp32-idf.yaml new file mode 100644 index 0000000000..ff9adde6b1 --- /dev/null +++ b/tests/components/image/test.esp32-idf.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.esp32.yaml b/tests/components/image/test.esp32.yaml new file mode 100644 index 0000000000..ff9adde6b1 --- /dev/null +++ b/tests/components/image/test.esp32.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.esp8266.yaml b/tests/components/image/test.esp8266.yaml new file mode 100644 index 0000000000..3632b95485 --- /dev/null +++ b/tests/components/image/test.esp8266.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 5 + dc_pin: 15 + reset_pin: 16 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.rp2040.yaml b/tests/components/image/test.rp2040.yaml new file mode 100644 index 0000000000..b79c8a9195 --- /dev/null +++ b/tests/components/image/test.rp2040.yaml @@ -0,0 +1,52 @@ +spi: + - id: spi_main_lcd + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 20 + dc_pin: 21 + reset_pin: 22 + +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/improv_serial/test.esp32-c3-idf.yaml b/tests/components/improv_serial/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.esp32-c3.yaml b/tests/components/improv_serial/test.esp32-c3.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.esp32-idf.yaml b/tests/components/improv_serial/test.esp32-idf.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.esp32.yaml b/tests/components/improv_serial/test.esp32.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.esp32.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.esp8266.yaml b/tests/components/improv_serial/test.esp8266.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.esp8266.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.rp2040.yaml b/tests/components/improv_serial/test.rp2040.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/test.rp2040.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/ina219/test.esp32-c3-idf.yaml b/tests/components/ina219/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..586add9d16 --- /dev/null +++ b/tests/components/ina219/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 5 + sda: 4 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina219/test.esp32-c3.yaml b/tests/components/ina219/test.esp32-c3.yaml new file mode 100644 index 0000000000..586add9d16 --- /dev/null +++ b/tests/components/ina219/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 5 + sda: 4 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina219/test.esp32-idf.yaml b/tests/components/ina219/test.esp32-idf.yaml new file mode 100644 index 0000000000..affbec67c4 --- /dev/null +++ b/tests/components/ina219/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 16 + sda: 17 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina219/test.esp32.yaml b/tests/components/ina219/test.esp32.yaml new file mode 100644 index 0000000000..affbec67c4 --- /dev/null +++ b/tests/components/ina219/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 16 + sda: 17 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina219/test.esp8266.yaml b/tests/components/ina219/test.esp8266.yaml new file mode 100644 index 0000000000..586add9d16 --- /dev/null +++ b/tests/components/ina219/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 5 + sda: 4 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina219/test.rp2040.yaml b/tests/components/ina219/test.rp2040.yaml new file mode 100644 index 0000000000..586add9d16 --- /dev/null +++ b/tests/components/ina219/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina219 + scl: 5 + sda: 4 + +sensor: + - platform: ina219 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA219 Current + power: + name: INA219 Power + bus_voltage: + name: INA219 Bus Voltage + shunt_voltage: + name: INA219 Shunt Voltage + max_voltage: 32.0V + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.esp32-c3-idf.yaml b/tests/components/ina226/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..6581763294 --- /dev/null +++ b/tests/components/ina226/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 5 + sda: 4 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.esp32-c3.yaml b/tests/components/ina226/test.esp32-c3.yaml new file mode 100644 index 0000000000..6581763294 --- /dev/null +++ b/tests/components/ina226/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 5 + sda: 4 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.esp32-idf.yaml b/tests/components/ina226/test.esp32-idf.yaml new file mode 100644 index 0000000000..feab5e146c --- /dev/null +++ b/tests/components/ina226/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 16 + sda: 17 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.esp32.yaml b/tests/components/ina226/test.esp32.yaml new file mode 100644 index 0000000000..feab5e146c --- /dev/null +++ b/tests/components/ina226/test.esp32.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 16 + sda: 17 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.esp8266.yaml b/tests/components/ina226/test.esp8266.yaml new file mode 100644 index 0000000000..6581763294 --- /dev/null +++ b/tests/components/ina226/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 5 + sda: 4 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina226/test.rp2040.yaml b/tests/components/ina226/test.rp2040.yaml new file mode 100644 index 0000000000..6581763294 --- /dev/null +++ b/tests/components/ina226/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina226 + scl: 5 + sda: 4 + +sensor: + - platform: ina226 + address: 0x40 + shunt_resistance: 0.1 ohm + current: + name: INA226 Current + power: + name: INA226 Power + bus_voltage: + name: INA226 Bus Voltage + shunt_voltage: + name: INA226 Shunt Voltage + max_current: 3.2A + update_interval: 15s diff --git a/tests/components/ina260/test.esp32-c3-idf.yaml b/tests/components/ina260/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a1da63351d --- /dev/null +++ b/tests/components/ina260/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 5 + sda: 4 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina260/test.esp32-c3.yaml b/tests/components/ina260/test.esp32-c3.yaml new file mode 100644 index 0000000000..a1da63351d --- /dev/null +++ b/tests/components/ina260/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 5 + sda: 4 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina260/test.esp32-idf.yaml b/tests/components/ina260/test.esp32-idf.yaml new file mode 100644 index 0000000000..be6cf73bff --- /dev/null +++ b/tests/components/ina260/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 16 + sda: 17 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina260/test.esp32.yaml b/tests/components/ina260/test.esp32.yaml new file mode 100644 index 0000000000..be6cf73bff --- /dev/null +++ b/tests/components/ina260/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 16 + sda: 17 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina260/test.esp8266.yaml b/tests/components/ina260/test.esp8266.yaml new file mode 100644 index 0000000000..a1da63351d --- /dev/null +++ b/tests/components/ina260/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 5 + sda: 4 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina260/test.rp2040.yaml b/tests/components/ina260/test.rp2040.yaml new file mode 100644 index 0000000000..a1da63351d --- /dev/null +++ b/tests/components/ina260/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ina260 + scl: 5 + sda: 4 + +sensor: + - platform: ina260 + address: 0x40 + current: + name: INA260 Current + power: + name: INA260 Power + bus_voltage: + name: INA260 Voltage + update_interval: 60s diff --git a/tests/components/ina3221/test.esp32-c3-idf.yaml b/tests/components/ina3221/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..55990871a0 --- /dev/null +++ b/tests/components/ina3221/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 5 + sda: 4 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/ina3221/test.esp32-c3.yaml b/tests/components/ina3221/test.esp32-c3.yaml new file mode 100644 index 0000000000..55990871a0 --- /dev/null +++ b/tests/components/ina3221/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 5 + sda: 4 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/ina3221/test.esp32-idf.yaml b/tests/components/ina3221/test.esp32-idf.yaml new file mode 100644 index 0000000000..ad9cf79e38 --- /dev/null +++ b/tests/components/ina3221/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 16 + sda: 17 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/ina3221/test.esp32.yaml b/tests/components/ina3221/test.esp32.yaml new file mode 100644 index 0000000000..ad9cf79e38 --- /dev/null +++ b/tests/components/ina3221/test.esp32.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 16 + sda: 17 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/ina3221/test.esp8266.yaml b/tests/components/ina3221/test.esp8266.yaml new file mode 100644 index 0000000000..55990871a0 --- /dev/null +++ b/tests/components/ina3221/test.esp8266.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 5 + sda: 4 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/ina3221/test.rp2040.yaml b/tests/components/ina3221/test.rp2040.yaml new file mode 100644 index 0000000000..55990871a0 --- /dev/null +++ b/tests/components/ina3221/test.rp2040.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_ina3221 + scl: 5 + sda: 4 + +sensor: + - platform: ina3221 + address: 0x40 + channel_1: + shunt_resistance: 0.1 ohm + current: + name: INA3221 Channel 1 Current + power: + name: INA3221 Channel 1 Power + bus_voltage: + name: INA3221 Channel 1 Bus Voltage + shunt_voltage: + name: INA3221 Channel 1 Shunt Voltage + update_interval: 15s diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ba46b7dbf6 --- /dev/null +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: inkbird_ibsth1_mini + mac_address: 38:81:D7:0A:9C:11 + temperature: + name: Inkbird IBS-TH1 Temperature + humidity: + name: Inkbird IBS-TH1 Humidity + battery_level: + name: Inkbird IBS-TH1 Battery Level diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml new file mode 100644 index 0000000000..ba46b7dbf6 --- /dev/null +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: inkbird_ibsth1_mini + mac_address: 38:81:D7:0A:9C:11 + temperature: + name: Inkbird IBS-TH1 Temperature + humidity: + name: Inkbird IBS-TH1 Humidity + battery_level: + name: Inkbird IBS-TH1 Battery Level diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml new file mode 100644 index 0000000000..ba46b7dbf6 --- /dev/null +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: inkbird_ibsth1_mini + mac_address: 38:81:D7:0A:9C:11 + temperature: + name: Inkbird IBS-TH1 Temperature + humidity: + name: Inkbird IBS-TH1 Humidity + battery_level: + name: Inkbird IBS-TH1 Battery Level diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32.yaml new file mode 100644 index 0000000000..ba46b7dbf6 --- /dev/null +++ b/tests/components/inkbird_ibsth1_mini/test.esp32.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: inkbird_ibsth1_mini + mac_address: 38:81:D7:0A:9C:11 + temperature: + name: Inkbird IBS-TH1 Temperature + humidity: + name: Inkbird IBS-TH1 Humidity + battery_level: + name: Inkbird IBS-TH1 Battery Level diff --git a/tests/components/inkplate6/test.esp32.yaml b/tests/components/inkplate6/test.esp32.yaml new file mode 100644 index 0000000000..31b14e6c73 --- /dev/null +++ b/tests/components/inkplate6/test.esp32.yaml @@ -0,0 +1,62 @@ +i2c: + - id: i2c_inkplate6 + scl: 16 + sda: 17 + +display: + - platform: inkplate6 + id: inkplate_display + greyscale: false + partial_updating: false + update_interval: 60s + display_data_0_pin: + number: 1 + allow_other_uses: true + display_data_1_pin: + number: 1 + allow_other_uses: true + display_data_2_pin: + number: 1 + allow_other_uses: true + display_data_3_pin: + number: 1 + allow_other_uses: true + display_data_5_pin: + number: 1 + allow_other_uses: true + display_data_4_pin: + number: 1 + allow_other_uses: true + display_data_6_pin: + number: 1 + allow_other_uses: true + display_data_7_pin: + number: 1 + allow_other_uses: true + ckv_pin: + number: 1 + allow_other_uses: true + sph_pin: + number: 1 + allow_other_uses: true + gmod_pin: + number: 1 + allow_other_uses: true + gpio0_enable_pin: + number: 1 + allow_other_uses: true + oe_pin: + number: 1 + allow_other_uses: true + spv_pin: + number: 1 + allow_other_uses: true + powerup_pin: + number: 1 + allow_other_uses: true + wakeup_pin: + number: 1 + allow_other_uses: true + vcom_pin: + number: 1 + allow_other_uses: true diff --git a/tests/components/integration/test.esp32-c3.yaml b/tests/components/integration/test.esp32-c3.yaml new file mode 100644 index 0000000000..b68cb9f87d --- /dev/null +++ b/tests/components/integration/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: adc + id: my_sensor + pin: 4 + attenuation: 11db + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.esp32-idf.yaml b/tests/components/integration/test.esp32-idf.yaml new file mode 100644 index 0000000000..0095fdb1ff --- /dev/null +++ b/tests/components/integration/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: adc + id: my_sensor + pin: A0 + attenuation: 2.5db + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.esp32-s2.yaml b/tests/components/integration/test.esp32-s2.yaml new file mode 100644 index 0000000000..1415952571 --- /dev/null +++ b/tests/components/integration/test.esp32-s2.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: adc + id: my_sensor + pin: 1 + attenuation: 11db + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.esp32-s3.yaml b/tests/components/integration/test.esp32-s3.yaml new file mode 100644 index 0000000000..1415952571 --- /dev/null +++ b/tests/components/integration/test.esp32-s3.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: adc + id: my_sensor + pin: 1 + attenuation: 11db + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.esp32.yaml b/tests/components/integration/test.esp32.yaml new file mode 100644 index 0000000000..0095fdb1ff --- /dev/null +++ b/tests/components/integration/test.esp32.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: adc + id: my_sensor + pin: A0 + attenuation: 2.5db + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.esp8266.yaml b/tests/components/integration/test.esp8266.yaml new file mode 100644 index 0000000000..51d3e19077 --- /dev/null +++ b/tests/components/integration/test.esp8266.yaml @@ -0,0 +1,8 @@ +sensor: + - platform: adc + id: my_sensor + pin: VCC + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/integration/test.rp2040.yaml b/tests/components/integration/test.rp2040.yaml new file mode 100644 index 0000000000..51d3e19077 --- /dev/null +++ b/tests/components/integration/test.rp2040.yaml @@ -0,0 +1,8 @@ +sensor: + - platform: adc + id: my_sensor + pin: VCC + - platform: integration + sensor: my_sensor + name: Integration Sensor + time_unit: s diff --git a/tests/components/internal_temperature/test.esp32-c3.yaml b/tests/components/internal_temperature/test.esp32-c3.yaml index 28df4a6d9f..19f740339d 100644 --- a/tests/components/internal_temperature/test.esp32-c3.yaml +++ b/tests/components/internal_temperature/test.esp32-c3.yaml @@ -1,3 +1,3 @@ sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature diff --git a/tests/components/internal_temperature/test.esp32-idf.yaml b/tests/components/internal_temperature/test.esp32-idf.yaml index 28df4a6d9f..19f740339d 100644 --- a/tests/components/internal_temperature/test.esp32-idf.yaml +++ b/tests/components/internal_temperature/test.esp32-idf.yaml @@ -1,3 +1,3 @@ sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature diff --git a/tests/components/internal_temperature/test.esp32-s2.yaml b/tests/components/internal_temperature/test.esp32-s2.yaml new file mode 100644 index 0000000000..19f740339d --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-s2.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: internal_temperature + name: Internal Temperature diff --git a/tests/components/internal_temperature/test.esp32-s3.yaml b/tests/components/internal_temperature/test.esp32-s3.yaml new file mode 100644 index 0000000000..9eb1ec0b0f --- /dev/null +++ b/tests/components/internal_temperature/test.esp32-s3.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: internal_temperature + name: Internal Temperature + +esp32: + framework: + version: 2.0.9 diff --git a/tests/components/internal_temperature/test.esp32.yaml b/tests/components/internal_temperature/test.esp32.yaml index 28df4a6d9f..19f740339d 100644 --- a/tests/components/internal_temperature/test.esp32.yaml +++ b/tests/components/internal_temperature/test.esp32.yaml @@ -1,3 +1,3 @@ sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature diff --git a/tests/components/internal_temperature/test.rp2040.yaml b/tests/components/internal_temperature/test.rp2040.yaml index 28df4a6d9f..19f740339d 100644 --- a/tests/components/internal_temperature/test.rp2040.yaml +++ b/tests/components/internal_temperature/test.rp2040.yaml @@ -1,3 +1,3 @@ sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature diff --git a/tests/components/interval/test.esp32-c3-idf.yaml b/tests/components/interval/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.esp32-c3.yaml b/tests/components/interval/test.esp32-c3.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.esp32-c3.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.esp32-idf.yaml b/tests/components/interval/test.esp32-idf.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.esp32.yaml b/tests/components/interval/test.esp32.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.esp32.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.esp8266.yaml b/tests/components/interval/test.esp8266.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.esp8266.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.rp2040.yaml b/tests/components/interval/test.rp2040.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/test.rp2040.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick From ed381b45eb99c0774edf619b4239b7a35a1984e9 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 23 Apr 2024 04:49:03 -0500 Subject: [PATCH 1611/2607] Add some components to the new testing framework (T) (#6229) --- tests/components/t6615/test.esp32-c3-idf.yaml | 10 ++ tests/components/t6615/test.esp32-c3.yaml | 10 ++ tests/components/t6615/test.esp32-idf.yaml | 10 ++ tests/components/t6615/test.esp32.yaml | 10 ++ tests/components/t6615/test.esp8266.yaml | 10 ++ tests/components/t6615/test.rp2040.yaml | 10 ++ .../tca9548a/test.esp32-c3-idf.yaml | 15 +++ tests/components/tca9548a/test.esp32-c3.yaml | 15 +++ tests/components/tca9548a/test.esp32-idf.yaml | 15 +++ tests/components/tca9548a/test.esp32.yaml | 15 +++ tests/components/tca9548a/test.esp8266.yaml | 15 +++ tests/components/tca9548a/test.rp2040.yaml | 15 +++ .../components/tcl112/test.esp32-c3-idf.yaml | 15 +++ tests/components/tcl112/test.esp32-c3.yaml | 15 +++ tests/components/tcl112/test.esp32-idf.yaml | 15 +++ tests/components/tcl112/test.esp32.yaml | 15 +++ tests/components/tcl112/test.esp8266.yaml | 15 +++ .../tcs34725/test.esp32-c3-idf.yaml | 21 ++++ tests/components/tcs34725/test.esp32-c3.yaml | 21 ++++ tests/components/tcs34725/test.esp32-idf.yaml | 21 ++++ tests/components/tcs34725/test.esp32.yaml | 21 ++++ tests/components/tcs34725/test.esp8266.yaml | 21 ++++ tests/components/tcs34725/test.rp2040.yaml | 21 ++++ .../components/tee501/test.esp32-c3-idf.yaml | 9 ++ tests/components/tee501/test.esp32-c3.yaml | 9 ++ tests/components/tee501/test.esp32-idf.yaml | 9 ++ tests/components/tee501/test.esp32.yaml | 9 ++ tests/components/tee501/test.esp8266.yaml | 9 ++ tests/components/tee501/test.rp2040.yaml | 9 ++ .../teleinfo/test.esp32-c3-idf.yaml | 42 +++++++ tests/components/teleinfo/test.esp32-c3.yaml | 42 +++++++ tests/components/teleinfo/test.esp32-idf.yaml | 42 +++++++ tests/components/teleinfo/test.esp32.yaml | 42 +++++++ tests/components/teleinfo/test.esp8266.yaml | 42 +++++++ tests/components/teleinfo/test.rp2040.yaml | 42 +++++++ .../thermostat/test.esp32-c3-idf.yaml | 93 ++++++++++++++ .../components/thermostat/test.esp32-c3.yaml | 93 ++++++++++++++ .../components/thermostat/test.esp32-idf.yaml | 93 ++++++++++++++ tests/components/thermostat/test.esp32.yaml | 93 ++++++++++++++ tests/components/thermostat/test.esp8266.yaml | 93 ++++++++++++++ tests/components/thermostat/test.rp2040.yaml | 93 ++++++++++++++ tests/components/time/test.esp32-c3-idf.yaml | 10 ++ tests/components/time/test.esp32-c3.yaml | 10 ++ tests/components/time/test.esp32-idf.yaml | 10 ++ tests/components/time/test.esp32.yaml | 10 ++ tests/components/time/test.esp8266.yaml | 10 ++ tests/components/time/test.rp2040.yaml | 10 ++ .../time_based/test.esp32-c3-idf.yaml | 12 ++ .../components/time_based/test.esp32-c3.yaml | 12 ++ .../components/time_based/test.esp32-idf.yaml | 12 ++ tests/components/time_based/test.esp32.yaml | 12 ++ tests/components/time_based/test.esp8266.yaml | 12 ++ tests/components/time_based/test.rp2040.yaml | 12 ++ .../tlc59208f/test.esp32-c3-idf.yaml | 50 ++++++++ tests/components/tlc59208f/test.esp32-c3.yaml | 50 ++++++++ .../components/tlc59208f/test.esp32-idf.yaml | 50 ++++++++ tests/components/tlc59208f/test.esp32.yaml | 50 ++++++++ tests/components/tlc59208f/test.esp8266.yaml | 50 ++++++++ tests/components/tlc59208f/test.rp2040.yaml | 50 ++++++++ .../components/tm1621/test.esp32-c3-idf.yaml | 12 ++ tests/components/tm1621/test.esp32-c3.yaml | 12 ++ tests/components/tm1621/test.esp32-idf.yaml | 12 ++ tests/components/tm1621/test.esp32.yaml | 12 ++ tests/components/tm1621/test.esp8266.yaml | 12 ++ tests/components/tm1621/test.rp2040.yaml | 12 ++ .../components/tm1637/test.esp32-c3-idf.yaml | 7 ++ tests/components/tm1637/test.esp32-c3.yaml | 7 ++ tests/components/tm1637/test.esp32-idf.yaml | 7 ++ tests/components/tm1637/test.esp32.yaml | 7 ++ tests/components/tm1637/test.esp8266.yaml | 7 ++ tests/components/tm1637/test.rp2040.yaml | 7 ++ .../components/tm1638/test.esp32-c3-idf.yaml | 118 ++++++++++++++++++ tests/components/tm1638/test.esp32-c3.yaml | 118 ++++++++++++++++++ tests/components/tm1638/test.esp32-idf.yaml | 118 ++++++++++++++++++ tests/components/tm1638/test.esp32.yaml | 118 ++++++++++++++++++ tests/components/tm1638/test.esp8266.yaml | 118 ++++++++++++++++++ tests/components/tm1638/test.rp2040.yaml | 118 ++++++++++++++++++ tests/components/tm1651/test.esp32-c3.yaml | 21 ++++ tests/components/tm1651/test.esp32.yaml | 21 ++++ tests/components/tm1651/test.esp8266.yaml | 21 ++++ tests/components/tm1651/test.rp2040.yaml | 21 ++++ .../components/tmp102/test.esp32-c3-idf.yaml | 8 ++ tests/components/tmp102/test.esp32-c3.yaml | 8 ++ tests/components/tmp102/test.esp32-idf.yaml | 8 ++ tests/components/tmp102/test.esp32.yaml | 8 ++ tests/components/tmp102/test.esp8266.yaml | 8 ++ tests/components/tmp102/test.rp2040.yaml | 8 ++ .../components/tmp1075/test.esp32-c3-idf.yaml | 16 +++ tests/components/tmp1075/test.esp32-c3.yaml | 16 +++ tests/components/tmp1075/test.esp32-idf.yaml | 16 +++ tests/components/tmp1075/test.esp32.yaml | 16 +++ tests/components/tmp1075/test.esp8266.yaml | 16 +++ tests/components/tmp1075/test.rp2040.yaml | 16 +++ .../components/tmp117/test.esp32-c3-idf.yaml | 9 ++ tests/components/tmp117/test.esp32-c3.yaml | 9 ++ tests/components/tmp117/test.esp32-idf.yaml | 9 ++ tests/components/tmp117/test.esp32.yaml | 9 ++ tests/components/tmp117/test.esp8266.yaml | 9 ++ tests/components/tmp117/test.rp2040.yaml | 9 ++ .../tof10120/test.esp32-c3-idf.yaml | 9 ++ tests/components/tof10120/test.esp32-c3.yaml | 9 ++ tests/components/tof10120/test.esp32-idf.yaml | 9 ++ tests/components/tof10120/test.esp32.yaml | 9 ++ tests/components/tof10120/test.esp8266.yaml | 9 ++ tests/components/tof10120/test.rp2040.yaml | 9 ++ .../components/toshiba/test.esp32-c3-idf.yaml | 7 ++ tests/components/toshiba/test.esp32-c3.yaml | 7 ++ tests/components/toshiba/test.esp32-idf.yaml | 7 ++ tests/components/toshiba/test.esp32.yaml | 7 ++ tests/components/toshiba/test.esp8266.yaml | 7 ++ .../total_daily_energy/test.esp32-c3-idf.yaml | 32 +++++ .../total_daily_energy/test.esp32-c3.yaml | 32 +++++ .../total_daily_energy/test.esp32-idf.yaml | 32 +++++ .../total_daily_energy/test.esp32.yaml | 32 +++++ .../total_daily_energy/test.esp8266.yaml | 32 +++++ .../total_daily_energy/test.rp2040.yaml | 32 +++++ .../components/tsl2561/test.esp32-c3-idf.yaml | 13 ++ tests/components/tsl2561/test.esp32-c3.yaml | 13 ++ tests/components/tsl2561/test.esp32-idf.yaml | 13 ++ tests/components/tsl2561/test.esp32.yaml | 13 ++ tests/components/tsl2561/test.esp8266.yaml | 13 ++ tests/components/tsl2561/test.rp2040.yaml | 13 ++ .../components/tsl2591/test.esp32-c3-idf.yaml | 25 ++++ tests/components/tsl2591/test.esp32-c3.yaml | 25 ++++ tests/components/tsl2591/test.esp32-idf.yaml | 25 ++++ tests/components/tsl2591/test.esp32.yaml | 25 ++++ tests/components/tsl2591/test.esp8266.yaml | 25 ++++ tests/components/tsl2591/test.rp2040.yaml | 25 ++++ .../components/tt21100/test.esp32-c3-idf.yaml | 25 ++++ tests/components/tt21100/test.esp32-c3.yaml | 25 ++++ tests/components/tt21100/test.esp32-idf.yaml | 25 ++++ tests/components/tt21100/test.esp32.yaml | 25 ++++ tests/components/tt21100/test.esp8266.yaml | 25 ++++ tests/components/tt21100/test.rp2040.yaml | 25 ++++ .../ttp229_bsf/test.esp32-c3-idf.yaml | 8 ++ .../components/ttp229_bsf/test.esp32-c3.yaml | 8 ++ .../components/ttp229_bsf/test.esp32-idf.yaml | 8 ++ tests/components/ttp229_bsf/test.esp32.yaml | 8 ++ tests/components/ttp229_bsf/test.esp8266.yaml | 8 ++ tests/components/ttp229_bsf/test.rp2040.yaml | 8 ++ .../ttp229_lsf/test.esp32-c3-idf.yaml | 11 ++ .../components/ttp229_lsf/test.esp32-c3.yaml | 11 ++ .../components/ttp229_lsf/test.esp32-idf.yaml | 11 ++ tests/components/ttp229_lsf/test.esp32.yaml | 11 ++ tests/components/ttp229_lsf/test.esp8266.yaml | 11 ++ tests/components/ttp229_lsf/test.rp2040.yaml | 11 ++ tests/components/tuya/test.esp32-c3-idf.yaml | 78 ++++++++++++ tests/components/tuya/test.esp32-c3.yaml | 78 ++++++++++++ tests/components/tuya/test.esp32-idf.yaml | 78 ++++++++++++ tests/components/tuya/test.esp32.yaml | 78 ++++++++++++ tests/components/tuya/test.esp8266.yaml | 78 ++++++++++++ tests/components/tuya/test.rp2040.yaml | 78 ++++++++++++ tests/components/tx20/test.esp32-c3-idf.yaml | 7 ++ tests/components/tx20/test.esp32-c3.yaml | 7 ++ tests/components/tx20/test.esp32-idf.yaml | 7 ++ tests/components/tx20/test.esp32.yaml | 7 ++ tests/components/tx20/test.esp8266.yaml | 7 ++ tests/components/tx20/test.rp2040.yaml | 7 ++ 158 files changed, 4034 insertions(+) create mode 100644 tests/components/t6615/test.esp32-c3-idf.yaml create mode 100644 tests/components/t6615/test.esp32-c3.yaml create mode 100644 tests/components/t6615/test.esp32-idf.yaml create mode 100644 tests/components/t6615/test.esp32.yaml create mode 100644 tests/components/t6615/test.esp8266.yaml create mode 100644 tests/components/t6615/test.rp2040.yaml create mode 100644 tests/components/tca9548a/test.esp32-c3-idf.yaml create mode 100644 tests/components/tca9548a/test.esp32-c3.yaml create mode 100644 tests/components/tca9548a/test.esp32-idf.yaml create mode 100644 tests/components/tca9548a/test.esp32.yaml create mode 100644 tests/components/tca9548a/test.esp8266.yaml create mode 100644 tests/components/tca9548a/test.rp2040.yaml create mode 100644 tests/components/tcl112/test.esp32-c3-idf.yaml create mode 100644 tests/components/tcl112/test.esp32-c3.yaml create mode 100644 tests/components/tcl112/test.esp32-idf.yaml create mode 100644 tests/components/tcl112/test.esp32.yaml create mode 100644 tests/components/tcl112/test.esp8266.yaml create mode 100644 tests/components/tcs34725/test.esp32-c3-idf.yaml create mode 100644 tests/components/tcs34725/test.esp32-c3.yaml create mode 100644 tests/components/tcs34725/test.esp32-idf.yaml create mode 100644 tests/components/tcs34725/test.esp32.yaml create mode 100644 tests/components/tcs34725/test.esp8266.yaml create mode 100644 tests/components/tcs34725/test.rp2040.yaml create mode 100644 tests/components/tee501/test.esp32-c3-idf.yaml create mode 100644 tests/components/tee501/test.esp32-c3.yaml create mode 100644 tests/components/tee501/test.esp32-idf.yaml create mode 100644 tests/components/tee501/test.esp32.yaml create mode 100644 tests/components/tee501/test.esp8266.yaml create mode 100644 tests/components/tee501/test.rp2040.yaml create mode 100644 tests/components/teleinfo/test.esp32-c3-idf.yaml create mode 100644 tests/components/teleinfo/test.esp32-c3.yaml create mode 100644 tests/components/teleinfo/test.esp32-idf.yaml create mode 100644 tests/components/teleinfo/test.esp32.yaml create mode 100644 tests/components/teleinfo/test.esp8266.yaml create mode 100644 tests/components/teleinfo/test.rp2040.yaml create mode 100644 tests/components/thermostat/test.esp32-c3-idf.yaml create mode 100644 tests/components/thermostat/test.esp32-c3.yaml create mode 100644 tests/components/thermostat/test.esp32-idf.yaml create mode 100644 tests/components/thermostat/test.esp32.yaml create mode 100644 tests/components/thermostat/test.esp8266.yaml create mode 100644 tests/components/thermostat/test.rp2040.yaml create mode 100644 tests/components/time/test.esp32-c3-idf.yaml create mode 100644 tests/components/time/test.esp32-c3.yaml create mode 100644 tests/components/time/test.esp32-idf.yaml create mode 100644 tests/components/time/test.esp32.yaml create mode 100644 tests/components/time/test.esp8266.yaml create mode 100644 tests/components/time/test.rp2040.yaml create mode 100644 tests/components/time_based/test.esp32-c3-idf.yaml create mode 100644 tests/components/time_based/test.esp32-c3.yaml create mode 100644 tests/components/time_based/test.esp32-idf.yaml create mode 100644 tests/components/time_based/test.esp32.yaml create mode 100644 tests/components/time_based/test.esp8266.yaml create mode 100644 tests/components/time_based/test.rp2040.yaml create mode 100644 tests/components/tlc59208f/test.esp32-c3-idf.yaml create mode 100644 tests/components/tlc59208f/test.esp32-c3.yaml create mode 100644 tests/components/tlc59208f/test.esp32-idf.yaml create mode 100644 tests/components/tlc59208f/test.esp32.yaml create mode 100644 tests/components/tlc59208f/test.esp8266.yaml create mode 100644 tests/components/tlc59208f/test.rp2040.yaml create mode 100644 tests/components/tm1621/test.esp32-c3-idf.yaml create mode 100644 tests/components/tm1621/test.esp32-c3.yaml create mode 100644 tests/components/tm1621/test.esp32-idf.yaml create mode 100644 tests/components/tm1621/test.esp32.yaml create mode 100644 tests/components/tm1621/test.esp8266.yaml create mode 100644 tests/components/tm1621/test.rp2040.yaml create mode 100644 tests/components/tm1637/test.esp32-c3-idf.yaml create mode 100644 tests/components/tm1637/test.esp32-c3.yaml create mode 100644 tests/components/tm1637/test.esp32-idf.yaml create mode 100644 tests/components/tm1637/test.esp32.yaml create mode 100644 tests/components/tm1637/test.esp8266.yaml create mode 100644 tests/components/tm1637/test.rp2040.yaml create mode 100644 tests/components/tm1638/test.esp32-c3-idf.yaml create mode 100644 tests/components/tm1638/test.esp32-c3.yaml create mode 100644 tests/components/tm1638/test.esp32-idf.yaml create mode 100644 tests/components/tm1638/test.esp32.yaml create mode 100644 tests/components/tm1638/test.esp8266.yaml create mode 100644 tests/components/tm1638/test.rp2040.yaml create mode 100644 tests/components/tm1651/test.esp32-c3.yaml create mode 100644 tests/components/tm1651/test.esp32.yaml create mode 100644 tests/components/tm1651/test.esp8266.yaml create mode 100644 tests/components/tm1651/test.rp2040.yaml create mode 100644 tests/components/tmp102/test.esp32-c3-idf.yaml create mode 100644 tests/components/tmp102/test.esp32-c3.yaml create mode 100644 tests/components/tmp102/test.esp32-idf.yaml create mode 100644 tests/components/tmp102/test.esp32.yaml create mode 100644 tests/components/tmp102/test.esp8266.yaml create mode 100644 tests/components/tmp102/test.rp2040.yaml create mode 100644 tests/components/tmp1075/test.esp32-c3-idf.yaml create mode 100644 tests/components/tmp1075/test.esp32-c3.yaml create mode 100644 tests/components/tmp1075/test.esp32-idf.yaml create mode 100644 tests/components/tmp1075/test.esp32.yaml create mode 100644 tests/components/tmp1075/test.esp8266.yaml create mode 100644 tests/components/tmp1075/test.rp2040.yaml create mode 100644 tests/components/tmp117/test.esp32-c3-idf.yaml create mode 100644 tests/components/tmp117/test.esp32-c3.yaml create mode 100644 tests/components/tmp117/test.esp32-idf.yaml create mode 100644 tests/components/tmp117/test.esp32.yaml create mode 100644 tests/components/tmp117/test.esp8266.yaml create mode 100644 tests/components/tmp117/test.rp2040.yaml create mode 100644 tests/components/tof10120/test.esp32-c3-idf.yaml create mode 100644 tests/components/tof10120/test.esp32-c3.yaml create mode 100644 tests/components/tof10120/test.esp32-idf.yaml create mode 100644 tests/components/tof10120/test.esp32.yaml create mode 100644 tests/components/tof10120/test.esp8266.yaml create mode 100644 tests/components/tof10120/test.rp2040.yaml create mode 100644 tests/components/toshiba/test.esp32-c3-idf.yaml create mode 100644 tests/components/toshiba/test.esp32-c3.yaml create mode 100644 tests/components/toshiba/test.esp32-idf.yaml create mode 100644 tests/components/toshiba/test.esp32.yaml create mode 100644 tests/components/toshiba/test.esp8266.yaml create mode 100644 tests/components/total_daily_energy/test.esp32-c3-idf.yaml create mode 100644 tests/components/total_daily_energy/test.esp32-c3.yaml create mode 100644 tests/components/total_daily_energy/test.esp32-idf.yaml create mode 100644 tests/components/total_daily_energy/test.esp32.yaml create mode 100644 tests/components/total_daily_energy/test.esp8266.yaml create mode 100644 tests/components/total_daily_energy/test.rp2040.yaml create mode 100644 tests/components/tsl2561/test.esp32-c3-idf.yaml create mode 100644 tests/components/tsl2561/test.esp32-c3.yaml create mode 100644 tests/components/tsl2561/test.esp32-idf.yaml create mode 100644 tests/components/tsl2561/test.esp32.yaml create mode 100644 tests/components/tsl2561/test.esp8266.yaml create mode 100644 tests/components/tsl2561/test.rp2040.yaml create mode 100644 tests/components/tsl2591/test.esp32-c3-idf.yaml create mode 100644 tests/components/tsl2591/test.esp32-c3.yaml create mode 100644 tests/components/tsl2591/test.esp32-idf.yaml create mode 100644 tests/components/tsl2591/test.esp32.yaml create mode 100644 tests/components/tsl2591/test.esp8266.yaml create mode 100644 tests/components/tsl2591/test.rp2040.yaml create mode 100644 tests/components/tt21100/test.esp32-c3-idf.yaml create mode 100644 tests/components/tt21100/test.esp32-c3.yaml create mode 100644 tests/components/tt21100/test.esp32-idf.yaml create mode 100644 tests/components/tt21100/test.esp32.yaml create mode 100644 tests/components/tt21100/test.esp8266.yaml create mode 100644 tests/components/tt21100/test.rp2040.yaml create mode 100644 tests/components/ttp229_bsf/test.esp32-c3-idf.yaml create mode 100644 tests/components/ttp229_bsf/test.esp32-c3.yaml create mode 100644 tests/components/ttp229_bsf/test.esp32-idf.yaml create mode 100644 tests/components/ttp229_bsf/test.esp32.yaml create mode 100644 tests/components/ttp229_bsf/test.esp8266.yaml create mode 100644 tests/components/ttp229_bsf/test.rp2040.yaml create mode 100644 tests/components/ttp229_lsf/test.esp32-c3-idf.yaml create mode 100644 tests/components/ttp229_lsf/test.esp32-c3.yaml create mode 100644 tests/components/ttp229_lsf/test.esp32-idf.yaml create mode 100644 tests/components/ttp229_lsf/test.esp32.yaml create mode 100644 tests/components/ttp229_lsf/test.esp8266.yaml create mode 100644 tests/components/ttp229_lsf/test.rp2040.yaml create mode 100644 tests/components/tuya/test.esp32-c3-idf.yaml create mode 100644 tests/components/tuya/test.esp32-c3.yaml create mode 100644 tests/components/tuya/test.esp32-idf.yaml create mode 100644 tests/components/tuya/test.esp32.yaml create mode 100644 tests/components/tuya/test.esp8266.yaml create mode 100644 tests/components/tuya/test.rp2040.yaml create mode 100644 tests/components/tx20/test.esp32-c3-idf.yaml create mode 100644 tests/components/tx20/test.esp32-c3.yaml create mode 100644 tests/components/tx20/test.esp32-idf.yaml create mode 100644 tests/components/tx20/test.esp32.yaml create mode 100644 tests/components/tx20/test.esp8266.yaml create mode 100644 tests/components/tx20/test.rp2040.yaml diff --git a/tests/components/t6615/test.esp32-c3-idf.yaml b/tests/components/t6615/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e8690c770f --- /dev/null +++ b/tests/components/t6615/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 4 + rx_pin: 5 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/t6615/test.esp32-c3.yaml b/tests/components/t6615/test.esp32-c3.yaml new file mode 100644 index 0000000000..e8690c770f --- /dev/null +++ b/tests/components/t6615/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 4 + rx_pin: 5 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/t6615/test.esp32-idf.yaml b/tests/components/t6615/test.esp32-idf.yaml new file mode 100644 index 0000000000..2cfaa0ae5b --- /dev/null +++ b/tests/components/t6615/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 17 + rx_pin: 16 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/t6615/test.esp32.yaml b/tests/components/t6615/test.esp32.yaml new file mode 100644 index 0000000000..2cfaa0ae5b --- /dev/null +++ b/tests/components/t6615/test.esp32.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 17 + rx_pin: 16 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/t6615/test.esp8266.yaml b/tests/components/t6615/test.esp8266.yaml new file mode 100644 index 0000000000..e8690c770f --- /dev/null +++ b/tests/components/t6615/test.esp8266.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 4 + rx_pin: 5 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/t6615/test.rp2040.yaml b/tests/components/t6615/test.rp2040.yaml new file mode 100644 index 0000000000..e8690c770f --- /dev/null +++ b/tests/components/t6615/test.rp2040.yaml @@ -0,0 +1,10 @@ +uart: + - id: uart_t6615 + tx_pin: 4 + rx_pin: 5 + baud_rate: 19200 + +sensor: + - platform: t6615 + co2: + name: CO2 Sensor diff --git a/tests/components/tca9548a/test.esp32-c3-idf.yaml b/tests/components/tca9548a/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2294530d14 --- /dev/null +++ b/tests/components/tca9548a/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 5 + sda: 4 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tca9548a/test.esp32-c3.yaml b/tests/components/tca9548a/test.esp32-c3.yaml new file mode 100644 index 0000000000..2294530d14 --- /dev/null +++ b/tests/components/tca9548a/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 5 + sda: 4 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tca9548a/test.esp32-idf.yaml b/tests/components/tca9548a/test.esp32-idf.yaml new file mode 100644 index 0000000000..7edb83c821 --- /dev/null +++ b/tests/components/tca9548a/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 16 + sda: 17 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tca9548a/test.esp32.yaml b/tests/components/tca9548a/test.esp32.yaml new file mode 100644 index 0000000000..7edb83c821 --- /dev/null +++ b/tests/components/tca9548a/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 16 + sda: 17 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tca9548a/test.esp8266.yaml b/tests/components/tca9548a/test.esp8266.yaml new file mode 100644 index 0000000000..2294530d14 --- /dev/null +++ b/tests/components/tca9548a/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 5 + sda: 4 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tca9548a/test.rp2040.yaml b/tests/components/tca9548a/test.rp2040.yaml new file mode 100644 index 0000000000..2294530d14 --- /dev/null +++ b/tests/components/tca9548a/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_tca9548a + scl: 5 + sda: 4 + +tca9548a: + - id: multiplex0 + address: 0x70 + channels: + - bus_id: multiplex0_chan0 + channel: 0 + i2c_id: i2c_tca9548a + - id: multiplex1 + address: 0x71 + i2c_id: multiplex0_chan0 diff --git a/tests/components/tcl112/test.esp32-c3-idf.yaml b/tests/components/tcl112/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..03c0e84fe5 --- /dev/null +++ b/tests/components/tcl112/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: tcl112_sensor + lambda: "return 21;" + +climate: + - platform: tcl112 + name: TCL112 Climate with Sensor + supports_heat: true + supports_cool: true + sensor: tcl112_sensor diff --git a/tests/components/tcl112/test.esp32-c3.yaml b/tests/components/tcl112/test.esp32-c3.yaml new file mode 100644 index 0000000000..03c0e84fe5 --- /dev/null +++ b/tests/components/tcl112/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: tcl112_sensor + lambda: "return 21;" + +climate: + - platform: tcl112 + name: TCL112 Climate with Sensor + supports_heat: true + supports_cool: true + sensor: tcl112_sensor diff --git a/tests/components/tcl112/test.esp32-idf.yaml b/tests/components/tcl112/test.esp32-idf.yaml new file mode 100644 index 0000000000..03c0e84fe5 --- /dev/null +++ b/tests/components/tcl112/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: tcl112_sensor + lambda: "return 21;" + +climate: + - platform: tcl112 + name: TCL112 Climate with Sensor + supports_heat: true + supports_cool: true + sensor: tcl112_sensor diff --git a/tests/components/tcl112/test.esp32.yaml b/tests/components/tcl112/test.esp32.yaml new file mode 100644 index 0000000000..03c0e84fe5 --- /dev/null +++ b/tests/components/tcl112/test.esp32.yaml @@ -0,0 +1,15 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: tcl112_sensor + lambda: "return 21;" + +climate: + - platform: tcl112 + name: TCL112 Climate with Sensor + supports_heat: true + supports_cool: true + sensor: tcl112_sensor diff --git a/tests/components/tcl112/test.esp8266.yaml b/tests/components/tcl112/test.esp8266.yaml new file mode 100644 index 0000000000..0a85536928 --- /dev/null +++ b/tests/components/tcl112/test.esp8266.yaml @@ -0,0 +1,15 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: tcl112_sensor + lambda: "return 21;" + +climate: + - platform: tcl112 + name: TCL112 Climate with Sensor + supports_heat: true + supports_cool: true + sensor: tcl112_sensor diff --git a/tests/components/tcs34725/test.esp32-c3-idf.yaml b/tests/components/tcs34725/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9b459c9104 --- /dev/null +++ b/tests/components/tcs34725/test.esp32-c3-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 5 + sda: 4 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tcs34725/test.esp32-c3.yaml b/tests/components/tcs34725/test.esp32-c3.yaml new file mode 100644 index 0000000000..9b459c9104 --- /dev/null +++ b/tests/components/tcs34725/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 5 + sda: 4 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tcs34725/test.esp32-idf.yaml b/tests/components/tcs34725/test.esp32-idf.yaml new file mode 100644 index 0000000000..86ef82962e --- /dev/null +++ b/tests/components/tcs34725/test.esp32-idf.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 16 + sda: 17 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tcs34725/test.esp32.yaml b/tests/components/tcs34725/test.esp32.yaml new file mode 100644 index 0000000000..86ef82962e --- /dev/null +++ b/tests/components/tcs34725/test.esp32.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 16 + sda: 17 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tcs34725/test.esp8266.yaml b/tests/components/tcs34725/test.esp8266.yaml new file mode 100644 index 0000000000..9b459c9104 --- /dev/null +++ b/tests/components/tcs34725/test.esp8266.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 5 + sda: 4 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tcs34725/test.rp2040.yaml b/tests/components/tcs34725/test.rp2040.yaml new file mode 100644 index 0000000000..9b459c9104 --- /dev/null +++ b/tests/components/tcs34725/test.rp2040.yaml @@ -0,0 +1,21 @@ +i2c: + - id: i2c_tcs34725 + scl: 5 + sda: 4 + +sensor: + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x diff --git a/tests/components/tee501/test.esp32-c3-idf.yaml b/tests/components/tee501/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..11991a6153 --- /dev/null +++ b/tests/components/tee501/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 5 + sda: 4 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/tee501/test.esp32-c3.yaml b/tests/components/tee501/test.esp32-c3.yaml new file mode 100644 index 0000000000..11991a6153 --- /dev/null +++ b/tests/components/tee501/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 5 + sda: 4 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/tee501/test.esp32-idf.yaml b/tests/components/tee501/test.esp32-idf.yaml new file mode 100644 index 0000000000..acf6fed4bf --- /dev/null +++ b/tests/components/tee501/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 16 + sda: 17 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/tee501/test.esp32.yaml b/tests/components/tee501/test.esp32.yaml new file mode 100644 index 0000000000..acf6fed4bf --- /dev/null +++ b/tests/components/tee501/test.esp32.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 16 + sda: 17 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/tee501/test.esp8266.yaml b/tests/components/tee501/test.esp8266.yaml new file mode 100644 index 0000000000..11991a6153 --- /dev/null +++ b/tests/components/tee501/test.esp8266.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 5 + sda: 4 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/tee501/test.rp2040.yaml b/tests/components/tee501/test.rp2040.yaml new file mode 100644 index 0000000000..11991a6153 --- /dev/null +++ b/tests/components/tee501/test.rp2040.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tee501 + scl: 5 + sda: 4 + +sensor: + - platform: tee501 + name: TEE501 Temperature + address: 0x48 diff --git a/tests/components/teleinfo/test.esp32-c3-idf.yaml b/tests/components/teleinfo/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..55641e1e01 --- /dev/null +++ b/tests/components/teleinfo/test.esp32-c3-idf.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/teleinfo/test.esp32-c3.yaml b/tests/components/teleinfo/test.esp32-c3.yaml new file mode 100644 index 0000000000..55641e1e01 --- /dev/null +++ b/tests/components/teleinfo/test.esp32-c3.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/teleinfo/test.esp32-idf.yaml b/tests/components/teleinfo/test.esp32-idf.yaml new file mode 100644 index 0000000000..a5bd176143 --- /dev/null +++ b/tests/components/teleinfo/test.esp32-idf.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 17 + rx_pin: 16 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/teleinfo/test.esp32.yaml b/tests/components/teleinfo/test.esp32.yaml new file mode 100644 index 0000000000..a5bd176143 --- /dev/null +++ b/tests/components/teleinfo/test.esp32.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 17 + rx_pin: 16 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/teleinfo/test.esp8266.yaml b/tests/components/teleinfo/test.esp8266.yaml new file mode 100644 index 0000000000..55641e1e01 --- /dev/null +++ b/tests/components/teleinfo/test.esp8266.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/teleinfo/test.rp2040.yaml b/tests/components/teleinfo/test.rp2040.yaml new file mode 100644 index 0000000000..55641e1e01 --- /dev/null +++ b/tests/components/teleinfo/test.rp2040.yaml @@ -0,0 +1,42 @@ +uart: + - id: uart_teleinfo + tx_pin: 4 + rx_pin: 5 + baud_rate: 1200 + parity: EVEN + +button: + - platform: template + name: Poller component suspend test + on_press: + - component.suspend: test_teleinfo + - delay: 20s + - component.update: test_teleinfo + - delay: 20s + - component.resume: test_teleinfo + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: 2s + - delay: 20s + - component.resume: + id: test_teleinfo + update_interval: !lambda return 2500; + +teleinfo: + id: test_teleinfo + historical_mode: true + update_interval: 60s + +sensor: + - platform: teleinfo + name: hchc + tag_name: HCHC + teleinfo_id: test_teleinfo + unit_of_measurement: Wh + +text_sensor: + - platform: teleinfo + name: optarif + tag_name: OPTARIF + teleinfo_id: test_teleinfo diff --git a/tests/components/thermostat/test.esp32-c3-idf.yaml b/tests/components/thermostat/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.esp32-c3-idf.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.esp32-c3.yaml b/tests/components/thermostat/test.esp32-c3.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.esp32-c3.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.esp32-idf.yaml b/tests/components/thermostat/test.esp32-idf.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.esp32-idf.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.esp32.yaml b/tests/components/thermostat/test.esp32.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.esp32.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.esp8266.yaml b/tests/components/thermostat/test.esp8266.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.esp8266.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.rp2040.yaml b/tests/components/thermostat/test.rp2040.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/test.rp2040.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/time/test.esp32-c3-idf.yaml b/tests/components/time/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.esp32-c3.yaml b/tests/components/time/test.esp32-c3.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.esp32-idf.yaml b/tests/components/time/test.esp32-idf.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.esp32.yaml b/tests/components/time/test.esp32.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.esp32.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.esp8266.yaml b/tests/components/time/test.esp8266.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.esp8266.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.rp2040.yaml b/tests/components/time/test.rp2040.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/test.rp2040.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time_based/test.esp32-c3-idf.yaml b/tests/components/time_based/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.esp32-c3.yaml b/tests/components/time_based/test.esp32-c3.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.esp32-idf.yaml b/tests/components/time_based/test.esp32-idf.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.esp32.yaml b/tests/components/time_based/test.esp32.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.esp32.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.esp8266.yaml b/tests/components/time_based/test.esp8266.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.esp8266.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.rp2040.yaml b/tests/components/time_based/test.rp2040.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/test.rp2040.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/tlc59208f/test.esp32-c3-idf.yaml b/tests/components/tlc59208f/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..923ea4b4a4 --- /dev/null +++ b/tests/components/tlc59208f/test.esp32-c3-idf.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 5 + sda: 4 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tlc59208f/test.esp32-c3.yaml b/tests/components/tlc59208f/test.esp32-c3.yaml new file mode 100644 index 0000000000..923ea4b4a4 --- /dev/null +++ b/tests/components/tlc59208f/test.esp32-c3.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 5 + sda: 4 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tlc59208f/test.esp32-idf.yaml b/tests/components/tlc59208f/test.esp32-idf.yaml new file mode 100644 index 0000000000..2639de3b3d --- /dev/null +++ b/tests/components/tlc59208f/test.esp32-idf.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 16 + sda: 17 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tlc59208f/test.esp32.yaml b/tests/components/tlc59208f/test.esp32.yaml new file mode 100644 index 0000000000..2639de3b3d --- /dev/null +++ b/tests/components/tlc59208f/test.esp32.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 16 + sda: 17 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tlc59208f/test.esp8266.yaml b/tests/components/tlc59208f/test.esp8266.yaml new file mode 100644 index 0000000000..923ea4b4a4 --- /dev/null +++ b/tests/components/tlc59208f/test.esp8266.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 5 + sda: 4 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tlc59208f/test.rp2040.yaml b/tests/components/tlc59208f/test.rp2040.yaml new file mode 100644 index 0000000000..923ea4b4a4 --- /dev/null +++ b/tests/components/tlc59208f/test.rp2040.yaml @@ -0,0 +1,50 @@ +i2c: + - id: i2c_tlc59208f + scl: 5 + sda: 4 + +tlc59208f: + - address: 0x20 + id: tlc59208f_1 + - address: 0x22 + id: tlc59208f_2 + - address: 0x24 + id: tlc59208f_3 + +output: + - platform: tlc59208f + id: tlc_0 + channel: 0 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_1 + channel: 1 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_2 + channel: 2 + tlc59208f_id: tlc59208f_1 + - platform: tlc59208f + id: tlc_3 + channel: 0 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_4 + channel: 1 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_5 + channel: 2 + tlc59208f_id: tlc59208f_2 + - platform: tlc59208f + id: tlc_6 + channel: 0 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_7 + channel: 1 + tlc59208f_id: tlc59208f_3 + - platform: tlc59208f + id: tlc_8 + channel: 2 + tlc59208f_id: tlc59208f_3 diff --git a/tests/components/tm1621/test.esp32-c3-idf.yaml b/tests/components/tm1621/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..cddd64f31f --- /dev/null +++ b/tests/components/tm1621/test.esp32-c3-idf.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 7 + data_pin: 4 + read_pin: 5 + write_pin: 6 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1621/test.esp32-c3.yaml b/tests/components/tm1621/test.esp32-c3.yaml new file mode 100644 index 0000000000..cddd64f31f --- /dev/null +++ b/tests/components/tm1621/test.esp32-c3.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 7 + data_pin: 4 + read_pin: 5 + write_pin: 6 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1621/test.esp32-idf.yaml b/tests/components/tm1621/test.esp32-idf.yaml new file mode 100644 index 0000000000..8eab46f000 --- /dev/null +++ b/tests/components/tm1621/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 15 + data_pin: 14 + read_pin: 12 + write_pin: 13 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1621/test.esp32.yaml b/tests/components/tm1621/test.esp32.yaml new file mode 100644 index 0000000000..8eab46f000 --- /dev/null +++ b/tests/components/tm1621/test.esp32.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 15 + data_pin: 14 + read_pin: 12 + write_pin: 13 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1621/test.esp8266.yaml b/tests/components/tm1621/test.esp8266.yaml new file mode 100644 index 0000000000..8eab46f000 --- /dev/null +++ b/tests/components/tm1621/test.esp8266.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 15 + data_pin: 14 + read_pin: 12 + write_pin: 13 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1621/test.rp2040.yaml b/tests/components/tm1621/test.rp2040.yaml new file mode 100644 index 0000000000..cddd64f31f --- /dev/null +++ b/tests/components/tm1621/test.rp2040.yaml @@ -0,0 +1,12 @@ +display: + - platform: tm1621 + id: tm1621_display + cs_pin: 7 + data_pin: 4 + read_pin: 5 + write_pin: 6 + lambda: |- + it.printf(0, "%.1f", 20.0); + it.display_celsius(true); + it.printf(1, "%.1f", 20.0); + it.display_humidity(true); diff --git a/tests/components/tm1637/test.esp32-c3-idf.yaml b/tests/components/tm1637/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fa4c95b443 --- /dev/null +++ b/tests/components/tm1637/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 5 + dio_pin: 4 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1637/test.esp32-c3.yaml b/tests/components/tm1637/test.esp32-c3.yaml new file mode 100644 index 0000000000..fa4c95b443 --- /dev/null +++ b/tests/components/tm1637/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 5 + dio_pin: 4 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1637/test.esp32-idf.yaml b/tests/components/tm1637/test.esp32-idf.yaml new file mode 100644 index 0000000000..bf5f331cca --- /dev/null +++ b/tests/components/tm1637/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 15 + dio_pin: 14 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1637/test.esp32.yaml b/tests/components/tm1637/test.esp32.yaml new file mode 100644 index 0000000000..bf5f331cca --- /dev/null +++ b/tests/components/tm1637/test.esp32.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 15 + dio_pin: 14 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1637/test.esp8266.yaml b/tests/components/tm1637/test.esp8266.yaml new file mode 100644 index 0000000000..fa4c95b443 --- /dev/null +++ b/tests/components/tm1637/test.esp8266.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 5 + dio_pin: 4 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1637/test.rp2040.yaml b/tests/components/tm1637/test.rp2040.yaml new file mode 100644 index 0000000000..fa4c95b443 --- /dev/null +++ b/tests/components/tm1637/test.rp2040.yaml @@ -0,0 +1,7 @@ +display: + - platform: tm1637 + clk_pin: 5 + dio_pin: 4 + intensity: 3 + lambda: |- + it.print("1234"); diff --git a/tests/components/tm1638/test.esp32-c3-idf.yaml b/tests/components/tm1638/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.esp32-c3-idf.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.esp32-c3.yaml b/tests/components/tm1638/test.esp32-c3.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.esp32-c3.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.esp32-idf.yaml b/tests/components/tm1638/test.esp32-idf.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.esp32-idf.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.esp32.yaml b/tests/components/tm1638/test.esp32.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.esp32.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.esp8266.yaml b/tests/components/tm1638/test.esp8266.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.esp8266.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.rp2040.yaml b/tests/components/tm1638/test.rp2040.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/test.rp2040.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1651/test.esp32-c3.yaml b/tests/components/tm1651/test.esp32-c3.yaml new file mode 100644 index 0000000000..667648f4d6 --- /dev/null +++ b/tests/components/tm1651/test.esp32-c3.yaml @@ -0,0 +1,21 @@ +tm1651: + id: tm1651_battery + clk_pin: 5 + dio_pin: 4 + +esphome: + on_boot: + then: + - tm1651.set_level_percent: + id: tm1651_battery + level_percent: 50 + - tm1651.set_level: + id: tm1651_battery + level: 5 + - tm1651.set_brightness: + id: tm1651_battery + brightness: 2 + - tm1651.turn_on: + id: tm1651_battery + - tm1651.turn_off: + id: tm1651_battery diff --git a/tests/components/tm1651/test.esp32.yaml b/tests/components/tm1651/test.esp32.yaml new file mode 100644 index 0000000000..667648f4d6 --- /dev/null +++ b/tests/components/tm1651/test.esp32.yaml @@ -0,0 +1,21 @@ +tm1651: + id: tm1651_battery + clk_pin: 5 + dio_pin: 4 + +esphome: + on_boot: + then: + - tm1651.set_level_percent: + id: tm1651_battery + level_percent: 50 + - tm1651.set_level: + id: tm1651_battery + level: 5 + - tm1651.set_brightness: + id: tm1651_battery + brightness: 2 + - tm1651.turn_on: + id: tm1651_battery + - tm1651.turn_off: + id: tm1651_battery diff --git a/tests/components/tm1651/test.esp8266.yaml b/tests/components/tm1651/test.esp8266.yaml new file mode 100644 index 0000000000..667648f4d6 --- /dev/null +++ b/tests/components/tm1651/test.esp8266.yaml @@ -0,0 +1,21 @@ +tm1651: + id: tm1651_battery + clk_pin: 5 + dio_pin: 4 + +esphome: + on_boot: + then: + - tm1651.set_level_percent: + id: tm1651_battery + level_percent: 50 + - tm1651.set_level: + id: tm1651_battery + level: 5 + - tm1651.set_brightness: + id: tm1651_battery + brightness: 2 + - tm1651.turn_on: + id: tm1651_battery + - tm1651.turn_off: + id: tm1651_battery diff --git a/tests/components/tm1651/test.rp2040.yaml b/tests/components/tm1651/test.rp2040.yaml new file mode 100644 index 0000000000..667648f4d6 --- /dev/null +++ b/tests/components/tm1651/test.rp2040.yaml @@ -0,0 +1,21 @@ +tm1651: + id: tm1651_battery + clk_pin: 5 + dio_pin: 4 + +esphome: + on_boot: + then: + - tm1651.set_level_percent: + id: tm1651_battery + level_percent: 50 + - tm1651.set_level: + id: tm1651_battery + level: 5 + - tm1651.set_brightness: + id: tm1651_battery + brightness: 2 + - tm1651.turn_on: + id: tm1651_battery + - tm1651.turn_off: + id: tm1651_battery diff --git a/tests/components/tmp102/test.esp32-c3-idf.yaml b/tests/components/tmp102/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c1d35fca3f --- /dev/null +++ b/tests/components/tmp102/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 5 + sda: 4 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp102/test.esp32-c3.yaml b/tests/components/tmp102/test.esp32-c3.yaml new file mode 100644 index 0000000000..c1d35fca3f --- /dev/null +++ b/tests/components/tmp102/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 5 + sda: 4 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp102/test.esp32-idf.yaml b/tests/components/tmp102/test.esp32-idf.yaml new file mode 100644 index 0000000000..840bf7edb3 --- /dev/null +++ b/tests/components/tmp102/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 16 + sda: 17 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp102/test.esp32.yaml b/tests/components/tmp102/test.esp32.yaml new file mode 100644 index 0000000000..840bf7edb3 --- /dev/null +++ b/tests/components/tmp102/test.esp32.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 16 + sda: 17 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp102/test.esp8266.yaml b/tests/components/tmp102/test.esp8266.yaml new file mode 100644 index 0000000000..c1d35fca3f --- /dev/null +++ b/tests/components/tmp102/test.esp8266.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 5 + sda: 4 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp102/test.rp2040.yaml b/tests/components/tmp102/test.rp2040.yaml new file mode 100644 index 0000000000..c1d35fca3f --- /dev/null +++ b/tests/components/tmp102/test.rp2040.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tmp102 + scl: 5 + sda: 4 + +sensor: + - platform: tmp102 + name: TMP102 Temperature diff --git a/tests/components/tmp1075/test.esp32-c3-idf.yaml b/tests/components/tmp1075/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..99433aa655 --- /dev/null +++ b/tests/components/tmp1075/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 5 + sda: 4 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp1075/test.esp32-c3.yaml b/tests/components/tmp1075/test.esp32-c3.yaml new file mode 100644 index 0000000000..99433aa655 --- /dev/null +++ b/tests/components/tmp1075/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 5 + sda: 4 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp1075/test.esp32-idf.yaml b/tests/components/tmp1075/test.esp32-idf.yaml new file mode 100644 index 0000000000..6c50d0da77 --- /dev/null +++ b/tests/components/tmp1075/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 16 + sda: 17 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp1075/test.esp32.yaml b/tests/components/tmp1075/test.esp32.yaml new file mode 100644 index 0000000000..6c50d0da77 --- /dev/null +++ b/tests/components/tmp1075/test.esp32.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 16 + sda: 17 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp1075/test.esp8266.yaml b/tests/components/tmp1075/test.esp8266.yaml new file mode 100644 index 0000000000..99433aa655 --- /dev/null +++ b/tests/components/tmp1075/test.esp8266.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 5 + sda: 4 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp1075/test.rp2040.yaml b/tests/components/tmp1075/test.rp2040.yaml new file mode 100644 index 0000000000..99433aa655 --- /dev/null +++ b/tests/components/tmp1075/test.rp2040.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_tmp1075 + scl: 5 + sda: 4 + +sensor: + - platform: tmp1075 + name: Temperature TMP1075 + conversion_rate: 27.5ms + alert: + limit_low: 50 + limit_high: 75 + fault_count: 1 + polarity: active_high + function: comparator + update_interval: 10s diff --git a/tests/components/tmp117/test.esp32-c3-idf.yaml b/tests/components/tmp117/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..61fc2cc03d --- /dev/null +++ b/tests/components/tmp117/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 5 + sda: 4 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tmp117/test.esp32-c3.yaml b/tests/components/tmp117/test.esp32-c3.yaml new file mode 100644 index 0000000000..61fc2cc03d --- /dev/null +++ b/tests/components/tmp117/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 5 + sda: 4 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tmp117/test.esp32-idf.yaml b/tests/components/tmp117/test.esp32-idf.yaml new file mode 100644 index 0000000000..03e0dd4e8e --- /dev/null +++ b/tests/components/tmp117/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 16 + sda: 17 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tmp117/test.esp32.yaml b/tests/components/tmp117/test.esp32.yaml new file mode 100644 index 0000000000..03e0dd4e8e --- /dev/null +++ b/tests/components/tmp117/test.esp32.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 16 + sda: 17 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tmp117/test.esp8266.yaml b/tests/components/tmp117/test.esp8266.yaml new file mode 100644 index 0000000000..61fc2cc03d --- /dev/null +++ b/tests/components/tmp117/test.esp8266.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 5 + sda: 4 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tmp117/test.rp2040.yaml b/tests/components/tmp117/test.rp2040.yaml new file mode 100644 index 0000000000..61fc2cc03d --- /dev/null +++ b/tests/components/tmp117/test.rp2040.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tmp117 + scl: 5 + sda: 4 + +sensor: + - platform: tmp117 + name: TMP117 Temperature + update_interval: 5s diff --git a/tests/components/tof10120/test.esp32-c3-idf.yaml b/tests/components/tof10120/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..01cde0df6a --- /dev/null +++ b/tests/components/tof10120/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 5 + sda: 4 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/tof10120/test.esp32-c3.yaml b/tests/components/tof10120/test.esp32-c3.yaml new file mode 100644 index 0000000000..01cde0df6a --- /dev/null +++ b/tests/components/tof10120/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 5 + sda: 4 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/tof10120/test.esp32-idf.yaml b/tests/components/tof10120/test.esp32-idf.yaml new file mode 100644 index 0000000000..74541ecde8 --- /dev/null +++ b/tests/components/tof10120/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 16 + sda: 17 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/tof10120/test.esp32.yaml b/tests/components/tof10120/test.esp32.yaml new file mode 100644 index 0000000000..74541ecde8 --- /dev/null +++ b/tests/components/tof10120/test.esp32.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 16 + sda: 17 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/tof10120/test.esp8266.yaml b/tests/components/tof10120/test.esp8266.yaml new file mode 100644 index 0000000000..01cde0df6a --- /dev/null +++ b/tests/components/tof10120/test.esp8266.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 5 + sda: 4 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/tof10120/test.rp2040.yaml b/tests/components/tof10120/test.rp2040.yaml new file mode 100644 index 0000000000..01cde0df6a --- /dev/null +++ b/tests/components/tof10120/test.rp2040.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_tof10120 + scl: 5 + sda: 4 + +sensor: + - platform: tof10120 + name: Distance sensor + update_interval: 5s diff --git a/tests/components/toshiba/test.esp32-c3-idf.yaml b/tests/components/toshiba/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c134c7f5bd --- /dev/null +++ b/tests/components/toshiba/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: toshiba + name: Toshiba Climate diff --git a/tests/components/toshiba/test.esp32-c3.yaml b/tests/components/toshiba/test.esp32-c3.yaml new file mode 100644 index 0000000000..c134c7f5bd --- /dev/null +++ b/tests/components/toshiba/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: toshiba + name: Toshiba Climate diff --git a/tests/components/toshiba/test.esp32-idf.yaml b/tests/components/toshiba/test.esp32-idf.yaml new file mode 100644 index 0000000000..c134c7f5bd --- /dev/null +++ b/tests/components/toshiba/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: toshiba + name: Toshiba Climate diff --git a/tests/components/toshiba/test.esp32.yaml b/tests/components/toshiba/test.esp32.yaml new file mode 100644 index 0000000000..c134c7f5bd --- /dev/null +++ b/tests/components/toshiba/test.esp32.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +climate: + - platform: toshiba + name: Toshiba Climate diff --git a/tests/components/toshiba/test.esp8266.yaml b/tests/components/toshiba/test.esp8266.yaml new file mode 100644 index 0000000000..8730a5d4ab --- /dev/null +++ b/tests/components/toshiba/test.esp8266.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 5 + carrier_duty_percent: 50% + +climate: + - platform: toshiba + name: Toshiba Climate diff --git a/tests/components/total_daily_energy/test.esp32-c3-idf.yaml b/tests/components/total_daily_energy/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..71afa45ed5 --- /dev/null +++ b/tests/components/total_daily_energy/test.esp32-c3-idf.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 5 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/total_daily_energy/test.esp32-c3.yaml b/tests/components/total_daily_energy/test.esp32-c3.yaml new file mode 100644 index 0000000000..71afa45ed5 --- /dev/null +++ b/tests/components/total_daily_energy/test.esp32-c3.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 5 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/total_daily_energy/test.esp32-idf.yaml b/tests/components/total_daily_energy/test.esp32-idf.yaml new file mode 100644 index 0000000000..34d452aae5 --- /dev/null +++ b/tests/components/total_daily_energy/test.esp32-idf.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 15 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/total_daily_energy/test.esp32.yaml b/tests/components/total_daily_energy/test.esp32.yaml new file mode 100644 index 0000000000..34d452aae5 --- /dev/null +++ b/tests/components/total_daily_energy/test.esp32.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 15 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/total_daily_energy/test.esp8266.yaml b/tests/components/total_daily_energy/test.esp8266.yaml new file mode 100644 index 0000000000..34d452aae5 --- /dev/null +++ b/tests/components/total_daily_energy/test.esp8266.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 15 + cf_pin: 14 + cf1_pin: 13 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/total_daily_energy/test.rp2040.yaml b/tests/components/total_daily_energy/test.rp2040.yaml new file mode 100644 index 0000000000..71afa45ed5 --- /dev/null +++ b/tests/components/total_daily_energy/test.rp2040.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + +sensor: + - platform: hlw8012 + sel_pin: 5 + cf_pin: 4 + cf1_pin: 3 + current: + name: HLW8012 Current + voltage: + name: HLW8012 Voltage + power: + name: HLW8012 Power + id: hlw8012_power + energy: + name: HLW8012 Energy + id: hlw8012_energy + update_interval: 15s + current_resistor: 0.001 ohm + voltage_divider: 2351 + change_mode_every: "never" + initial_mode: VOLTAGE + model: hlw8012 + - platform: total_daily_energy + name: HLW8012 Total Daily Energy + power_id: hlw8012_power diff --git a/tests/components/tsl2561/test.esp32-c3-idf.yaml b/tests/components/tsl2561/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1ea768c5d9 --- /dev/null +++ b/tests/components/tsl2561/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2561/test.esp32-c3.yaml b/tests/components/tsl2561/test.esp32-c3.yaml new file mode 100644 index 0000000000..1ea768c5d9 --- /dev/null +++ b/tests/components/tsl2561/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2561/test.esp32-idf.yaml b/tests/components/tsl2561/test.esp32-idf.yaml new file mode 100644 index 0000000000..8d43c62414 --- /dev/null +++ b/tests/components/tsl2561/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 16 + sda: 17 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2561/test.esp32.yaml b/tests/components/tsl2561/test.esp32.yaml new file mode 100644 index 0000000000..8d43c62414 --- /dev/null +++ b/tests/components/tsl2561/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 16 + sda: 17 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2561/test.esp8266.yaml b/tests/components/tsl2561/test.esp8266.yaml new file mode 100644 index 0000000000..1ea768c5d9 --- /dev/null +++ b/tests/components/tsl2561/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2561/test.rp2040.yaml b/tests/components/tsl2561/test.rp2040.yaml new file mode 100644 index 0000000000..1ea768c5d9 --- /dev/null +++ b/tests/components/tsl2561/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_tsl2561 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2561 + name: TSL2561 Ambient Light + address: 0x39 + is_cs_package: true + integration_time: 402ms + gain: 16x + update_interval: 15s diff --git a/tests/components/tsl2591/test.esp32-c3-idf.yaml b/tests/components/tsl2591/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..de57ef548a --- /dev/null +++ b/tests/components/tsl2591/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tsl2591/test.esp32-c3.yaml b/tests/components/tsl2591/test.esp32-c3.yaml new file mode 100644 index 0000000000..de57ef548a --- /dev/null +++ b/tests/components/tsl2591/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tsl2591/test.esp32-idf.yaml b/tests/components/tsl2591/test.esp32-idf.yaml new file mode 100644 index 0000000000..14f9311ae6 --- /dev/null +++ b/tests/components/tsl2591/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 16 + sda: 17 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tsl2591/test.esp32.yaml b/tests/components/tsl2591/test.esp32.yaml new file mode 100644 index 0000000000..14f9311ae6 --- /dev/null +++ b/tests/components/tsl2591/test.esp32.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 16 + sda: 17 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tsl2591/test.esp8266.yaml b/tests/components/tsl2591/test.esp8266.yaml new file mode 100644 index 0000000000..de57ef548a --- /dev/null +++ b/tests/components/tsl2591/test.esp8266.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tsl2591/test.rp2040.yaml b/tests/components/tsl2591/test.rp2040.yaml new file mode 100644 index 0000000000..de57ef548a --- /dev/null +++ b/tests/components/tsl2591/test.rp2040.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tsl2591 + scl: 5 + sda: 4 + +sensor: + - platform: tsl2591 + id: test_tsl2591 + address: 0x29 + integration_time: 600ms + gain: high + visible: + name: tsl2591 visible + id: tsl2591_vis + unit_of_measurement: pH + infrared: + name: tsl2591 infrared + id: tsl2591_ir + full_spectrum: + name: tsl2591 full_spectrum + id: tsl2591_fs + calculated_lux: + name: tsl2591 calculated_lux + id: tsl2591_cl + update_interval: 15s diff --git a/tests/components/tt21100/test.esp32-c3-idf.yaml b/tests/components/tt21100/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..17b8c8065a --- /dev/null +++ b/tests/components/tt21100/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 6 + reset_pin: 7 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/tt21100/test.esp32-c3.yaml b/tests/components/tt21100/test.esp32-c3.yaml new file mode 100644 index 0000000000..17b8c8065a --- /dev/null +++ b/tests/components/tt21100/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 6 + reset_pin: 7 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/tt21100/test.esp32-idf.yaml b/tests/components/tt21100/test.esp32-idf.yaml new file mode 100644 index 0000000000..2419b0ad6a --- /dev/null +++ b/tests/components/tt21100/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 14 + reset_pin: 15 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/tt21100/test.esp32.yaml b/tests/components/tt21100/test.esp32.yaml new file mode 100644 index 0000000000..2419b0ad6a --- /dev/null +++ b/tests/components/tt21100/test.esp32.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 14 + reset_pin: 15 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/tt21100/test.esp8266.yaml b/tests/components/tt21100/test.esp8266.yaml new file mode 100644 index 0000000000..1393019417 --- /dev/null +++ b/tests/components/tt21100/test.esp8266.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 14 + reset_pin: 15 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/tt21100/test.rp2040.yaml b/tests/components/tt21100/test.rp2040.yaml new file mode 100644 index 0000000000..17b8c8065a --- /dev/null +++ b/tests/components/tt21100/test.rp2040.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_tt21100 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 3 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: tt21100 + display: ssd1306_display + interrupt_pin: 6 + reset_pin: 7 + +binary_sensor: + - platform: tt21100 + name: Home Button + index: 1 diff --git a/tests/components/ttp229_bsf/test.esp32-c3-idf.yaml b/tests/components/ttp229_bsf/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2006061c6e --- /dev/null +++ b/tests/components/ttp229_bsf/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 5 + sdo_pin: 4 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_bsf/test.esp32-c3.yaml b/tests/components/ttp229_bsf/test.esp32-c3.yaml new file mode 100644 index 0000000000..2006061c6e --- /dev/null +++ b/tests/components/ttp229_bsf/test.esp32-c3.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 5 + sdo_pin: 4 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_bsf/test.esp32-idf.yaml b/tests/components/ttp229_bsf/test.esp32-idf.yaml new file mode 100644 index 0000000000..edee6d164e --- /dev/null +++ b/tests/components/ttp229_bsf/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 16 + sdo_pin: 17 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_bsf/test.esp32.yaml b/tests/components/ttp229_bsf/test.esp32.yaml new file mode 100644 index 0000000000..edee6d164e --- /dev/null +++ b/tests/components/ttp229_bsf/test.esp32.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 16 + sdo_pin: 17 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_bsf/test.esp8266.yaml b/tests/components/ttp229_bsf/test.esp8266.yaml new file mode 100644 index 0000000000..2006061c6e --- /dev/null +++ b/tests/components/ttp229_bsf/test.esp8266.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 5 + sdo_pin: 4 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_bsf/test.rp2040.yaml b/tests/components/ttp229_bsf/test.rp2040.yaml new file mode 100644 index 0000000000..2006061c6e --- /dev/null +++ b/tests/components/ttp229_bsf/test.rp2040.yaml @@ -0,0 +1,8 @@ +ttp229_bsf: + scl_pin: 5 + sdo_pin: 4 + +binary_sensor: + - platform: ttp229_bsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.esp32-c3-idf.yaml b/tests/components/ttp229_lsf/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3927aff40e --- /dev/null +++ b/tests/components/ttp229_lsf/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 5 + sda: 4 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.esp32-c3.yaml b/tests/components/ttp229_lsf/test.esp32-c3.yaml new file mode 100644 index 0000000000..3927aff40e --- /dev/null +++ b/tests/components/ttp229_lsf/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 5 + sda: 4 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.esp32-idf.yaml b/tests/components/ttp229_lsf/test.esp32-idf.yaml new file mode 100644 index 0000000000..81fb965883 --- /dev/null +++ b/tests/components/ttp229_lsf/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 16 + sda: 17 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.esp32.yaml b/tests/components/ttp229_lsf/test.esp32.yaml new file mode 100644 index 0000000000..81fb965883 --- /dev/null +++ b/tests/components/ttp229_lsf/test.esp32.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 16 + sda: 17 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.esp8266.yaml b/tests/components/ttp229_lsf/test.esp8266.yaml new file mode 100644 index 0000000000..3927aff40e --- /dev/null +++ b/tests/components/ttp229_lsf/test.esp8266.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 5 + sda: 4 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/ttp229_lsf/test.rp2040.yaml b/tests/components/ttp229_lsf/test.rp2040.yaml new file mode 100644 index 0000000000..3927aff40e --- /dev/null +++ b/tests/components/ttp229_lsf/test.rp2040.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_ttp229_lsf + scl: 5 + sda: 4 + +ttp229_lsf: + +binary_sensor: + - platform: ttp229_lsf + name: TTP229 Channel 0 + channel: 0 diff --git a/tests/components/tuya/test.esp32-c3-idf.yaml b/tests/components/tuya/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4892e807b1 --- /dev/null +++ b/tests/components/tuya/test.esp32-c3-idf.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +tuya: + status_pin: + number: 6 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tuya/test.esp32-c3.yaml b/tests/components/tuya/test.esp32-c3.yaml new file mode 100644 index 0000000000..4892e807b1 --- /dev/null +++ b/tests/components/tuya/test.esp32-c3.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +tuya: + status_pin: + number: 6 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tuya/test.esp32-idf.yaml b/tests/components/tuya/test.esp32-idf.yaml new file mode 100644 index 0000000000..9105522dcd --- /dev/null +++ b/tests/components/tuya/test.esp32-idf.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +tuya: + status_pin: + number: 15 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tuya/test.esp32.yaml b/tests/components/tuya/test.esp32.yaml new file mode 100644 index 0000000000..9105522dcd --- /dev/null +++ b/tests/components/tuya/test.esp32.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +tuya: + status_pin: + number: 15 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tuya/test.esp8266.yaml b/tests/components/tuya/test.esp8266.yaml new file mode 100644 index 0000000000..56177fb982 --- /dev/null +++ b/tests/components/tuya/test.esp8266.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +tuya: + status_pin: + number: 16 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tuya/test.rp2040.yaml b/tests/components/tuya/test.rp2040.yaml new file mode 100644 index 0000000000..4892e807b1 --- /dev/null +++ b/tests/components/tuya/test.rp2040.yaml @@ -0,0 +1,78 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_tuya + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +tuya: + status_pin: + number: 6 + inverted: true + on_datapoint_update: + - sensor_datapoint: 6 + datapoint_type: raw + then: + - logger.log: Datapoint 6 updated + +binary_sensor: + - platform: tuya + id: tuya_binary_sensor + sensor_datapoint: 1 + +climate: + - platform: tuya + id: tuya_climate + switch_datapoint: 1 + target_temperature_datapoint: 3 + current_temperature_multiplier: 0.5 + target_temperature_multiplier: 0.5 + reports_fahrenheit: true + +cover: + - platform: tuya + id: tuya_cover + position_datapoint: 2 + +light: + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 + +number: + - platform: tuya + id: tuya_number + number_datapoint: 102 + min_value: 0 + max_value: 17 + step: 1 + +select: + - platform: tuya + id: tuya_select + enum_datapoint: 42 + options: + 0: Internal + 1: Floor + 2: Both + +sensor: + - platform: tuya + id: tuya_sensor + sensor_datapoint: 1 + +switch: + - platform: tuya + id: tuya_switch + switch_datapoint: 1 diff --git a/tests/components/tx20/test.esp32-c3-idf.yaml b/tests/components/tx20/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.esp32-c3.yaml b/tests/components/tx20/test.esp32-c3.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.esp32-idf.yaml b/tests/components/tx20/test.esp32-idf.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.esp32.yaml b/tests/components/tx20/test.esp32.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.esp32.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.esp8266.yaml b/tests/components/tx20/test.esp8266.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.esp8266.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.rp2040.yaml b/tests/components/tx20/test.rp2040.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/test.rp2040.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 From 7e8ed5c391fa773ecf8f450196f05215bb5cf3d4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 23 Apr 2024 04:49:15 -0500 Subject: [PATCH 1612/2607] Add some components to the new testing framework (S part 1) (#6224) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../safe_mode/test.esp32-c3-idf.yaml | 13 +++++ tests/components/safe_mode/test.esp32-c3.yaml | 13 +++++ .../components/safe_mode/test.esp32-idf.yaml | 13 +++++ tests/components/safe_mode/test.esp32.yaml | 13 +++++ tests/components/safe_mode/test.esp8266.yaml | 13 +++++ tests/components/safe_mode/test.rp2040.yaml | 13 +++++ tests/components/scd30/test.esp32-c3-idf.yaml | 20 ++++++++ tests/components/scd30/test.esp32-c3.yaml | 20 ++++++++ tests/components/scd30/test.esp32-idf.yaml | 20 ++++++++ tests/components/scd30/test.esp32.yaml | 20 ++++++++ tests/components/scd30/test.esp8266.yaml | 20 ++++++++ tests/components/scd30/test.rp2040.yaml | 20 ++++++++ tests/components/scd4x/test.esp32-c3-idf.yaml | 20 ++++++++ tests/components/scd4x/test.esp32-c3.yaml | 20 ++++++++ tests/components/scd4x/test.esp32-idf.yaml | 20 ++++++++ tests/components/scd4x/test.esp32.yaml | 20 ++++++++ tests/components/scd4x/test.esp8266.yaml | 20 ++++++++ tests/components/scd4x/test.rp2040.yaml | 20 ++++++++ .../components/script/test.esp32-c3-idf.yaml | 26 ++++++++++ tests/components/script/test.esp32-c3.yaml | 26 ++++++++++ tests/components/script/test.esp32-idf.yaml | 26 ++++++++++ tests/components/script/test.esp32.yaml | 26 ++++++++++ tests/components/script/test.esp8266.yaml | 26 ++++++++++ tests/components/script/test.rp2040.yaml | 26 ++++++++++ .../sdm_meter/test.esp32-c3-idf.yaml | 23 +++++++++ tests/components/sdm_meter/test.esp32-c3.yaml | 23 +++++++++ .../components/sdm_meter/test.esp32-idf.yaml | 23 +++++++++ tests/components/sdm_meter/test.esp32.yaml | 23 +++++++++ tests/components/sdm_meter/test.esp8266.yaml | 23 +++++++++ tests/components/sdm_meter/test.rp2040.yaml | 23 +++++++++ tests/components/sdp3x/test.esp32-c3-idf.yaml | 11 +++++ tests/components/sdp3x/test.esp32-c3.yaml | 11 +++++ tests/components/sdp3x/test.esp32-idf.yaml | 11 +++++ tests/components/sdp3x/test.esp32.yaml | 11 +++++ tests/components/sdp3x/test.esp8266.yaml | 11 +++++ tests/components/sdp3x/test.rp2040.yaml | 11 +++++ .../components/sds011/test.esp32-c3-idf.yaml | 14 ++++++ tests/components/sds011/test.esp32-c3.yaml | 14 ++++++ tests/components/sds011/test.esp32-idf.yaml | 14 ++++++ tests/components/sds011/test.esp32.yaml | 14 ++++++ tests/components/sds011/test.esp8266.yaml | 14 ++++++ tests/components/sds011/test.rp2040.yaml | 14 ++++++ .../selec_meter/test.esp32-c3-idf.yaml | 45 +++++++++++++++++ .../components/selec_meter/test.esp32-c3.yaml | 45 +++++++++++++++++ .../selec_meter/test.esp32-idf.yaml | 45 +++++++++++++++++ tests/components/selec_meter/test.esp32.yaml | 45 +++++++++++++++++ .../components/selec_meter/test.esp8266.yaml | 45 +++++++++++++++++ tests/components/selec_meter/test.rp2040.yaml | 45 +++++++++++++++++ .../components/sen0321/test.esp32-c3-idf.yaml | 10 ++++ tests/components/sen0321/test.esp32-c3.yaml | 10 ++++ tests/components/sen0321/test.esp32-idf.yaml | 10 ++++ tests/components/sen0321/test.esp32.yaml | 10 ++++ tests/components/sen0321/test.esp8266.yaml | 10 ++++ tests/components/sen0321/test.rp2040.yaml | 10 ++++ .../sen21231/test.esp32-c3-idf.yaml | 9 ++++ tests/components/sen21231/test.esp32-c3.yaml | 9 ++++ tests/components/sen21231/test.esp32-idf.yaml | 9 ++++ tests/components/sen21231/test.esp32.yaml | 9 ++++ tests/components/sen21231/test.esp8266.yaml | 9 ++++ tests/components/sen21231/test.rp2040.yaml | 9 ++++ tests/components/sen5x/test.esp32-c3-idf.yaml | 49 +++++++++++++++++++ tests/components/sen5x/test.esp32-c3.yaml | 49 +++++++++++++++++++ tests/components/sen5x/test.esp32-idf.yaml | 49 +++++++++++++++++++ tests/components/sen5x/test.esp32.yaml | 49 +++++++++++++++++++ tests/components/sen5x/test.esp8266.yaml | 49 +++++++++++++++++++ tests/components/sen5x/test.rp2040.yaml | 49 +++++++++++++++++++ .../senseair/test.esp32-c3-idf.yaml | 19 +++++++ tests/components/senseair/test.esp32-c3.yaml | 19 +++++++ tests/components/senseair/test.esp32-idf.yaml | 19 +++++++ tests/components/senseair/test.esp32.yaml | 19 +++++++ tests/components/senseair/test.esp8266.yaml | 19 +++++++ tests/components/senseair/test.rp2040.yaml | 19 +++++++ tests/components/servo/test.esp32-c3-idf.yaml | 19 +++++++ tests/components/servo/test.esp32-c3.yaml | 19 +++++++ tests/components/servo/test.esp32-idf.yaml | 19 +++++++ tests/components/servo/test.esp32.yaml | 19 +++++++ tests/components/servo/test.esp8266.yaml | 19 +++++++ tests/components/servo/test.rp2040.yaml | 19 +++++++ tests/components/sfa30/test.esp32-c3-idf.yaml | 15 ++++++ tests/components/sfa30/test.esp32-c3.yaml | 15 ++++++ tests/components/sfa30/test.esp32-idf.yaml | 15 ++++++ tests/components/sfa30/test.esp32.yaml | 15 ++++++ tests/components/sfa30/test.esp8266.yaml | 15 ++++++ tests/components/sfa30/test.rp2040.yaml | 15 ++++++ tests/components/sgp30/test.esp32-c3-idf.yaml | 15 ++++++ tests/components/sgp30/test.esp32-c3.yaml | 15 ++++++ tests/components/sgp30/test.esp32-idf.yaml | 15 ++++++ tests/components/sgp30/test.esp32.yaml | 15 ++++++ tests/components/sgp30/test.esp8266.yaml | 15 ++++++ tests/components/sgp30/test.rp2040.yaml | 15 ++++++ tests/components/sgp4x/test.esp32-c3-idf.yaml | 27 ++++++++++ tests/components/sgp4x/test.esp32-c3.yaml | 27 ++++++++++ tests/components/sgp4x/test.esp32-idf.yaml | 27 ++++++++++ tests/components/sgp4x/test.esp32.yaml | 27 ++++++++++ tests/components/sgp4x/test.esp8266.yaml | 27 ++++++++++ tests/components/sgp4x/test.rp2040.yaml | 27 ++++++++++ .../shelly_dimmer/test.esp8266.yaml | 19 +++++++ .../components/sht3xd/test.esp32-c3-idf.yaml | 13 +++++ tests/components/sht3xd/test.esp32-c3.yaml | 13 +++++ tests/components/sht3xd/test.esp32-idf.yaml | 13 +++++ tests/components/sht3xd/test.esp32.yaml | 13 +++++ tests/components/sht3xd/test.esp8266.yaml | 13 +++++ tests/components/sht3xd/test.rp2040.yaml | 13 +++++ tests/components/sht4x/test.esp32-c3-idf.yaml | 13 +++++ tests/components/sht4x/test.esp32-c3.yaml | 13 +++++ tests/components/sht4x/test.esp32-idf.yaml | 13 +++++ tests/components/sht4x/test.esp32.yaml | 13 +++++ tests/components/sht4x/test.esp8266.yaml | 13 +++++ tests/components/sht4x/test.rp2040.yaml | 13 +++++ tests/components/shtcx/test.esp32-c3-idf.yaml | 13 +++++ tests/components/shtcx/test.esp32-c3.yaml | 13 +++++ tests/components/shtcx/test.esp32-idf.yaml | 13 +++++ tests/components/shtcx/test.esp32.yaml | 13 +++++ tests/components/shtcx/test.esp8266.yaml | 13 +++++ tests/components/shtcx/test.rp2040.yaml | 13 +++++ .../shutdown/test.esp32-c3-idf.yaml | 7 +++ tests/components/shutdown/test.esp32-c3.yaml | 7 +++ tests/components/shutdown/test.esp32-idf.yaml | 7 +++ tests/components/shutdown/test.esp32.yaml | 7 +++ tests/components/shutdown/test.esp8266.yaml | 7 +++ tests/components/shutdown/test.rp2040.yaml | 7 +++ .../sigma_delta_output/test.esp32-c3-idf.yaml | 16 ++++++ .../sigma_delta_output/test.esp32-c3.yaml | 16 ++++++ .../sigma_delta_output/test.esp32-idf.yaml | 16 ++++++ .../sigma_delta_output/test.esp32.yaml | 16 ++++++ .../sigma_delta_output/test.esp8266.yaml | 16 ++++++ .../sigma_delta_output/test.rp2040.yaml | 16 ++++++ .../components/sim800l/test.esp32-c3-idf.yaml | 37 ++++++++++++++ tests/components/sim800l/test.esp32-c3.yaml | 37 ++++++++++++++ tests/components/sim800l/test.esp32-idf.yaml | 37 ++++++++++++++ tests/components/sim800l/test.esp32.yaml | 37 ++++++++++++++ tests/components/sim800l/test.esp8266.yaml | 37 ++++++++++++++ tests/components/sim800l/test.rp2040.yaml | 37 ++++++++++++++ .../slow_pwm/test.esp32-c3-idf.yaml | 6 +++ tests/components/slow_pwm/test.esp32-c3.yaml | 6 +++ tests/components/slow_pwm/test.esp32-idf.yaml | 6 +++ tests/components/slow_pwm/test.esp32.yaml | 6 +++ tests/components/slow_pwm/test.esp8266.yaml | 6 +++ tests/components/slow_pwm/test.rp2040.yaml | 6 +++ .../components/sm16716/test.esp32-c3-idf.yaml | 16 ++++++ tests/components/sm16716/test.esp32-c3.yaml | 16 ++++++ tests/components/sm16716/test.esp32-idf.yaml | 16 ++++++ tests/components/sm16716/test.esp32.yaml | 16 ++++++ tests/components/sm16716/test.esp8266.yaml | 16 ++++++ tests/components/sm16716/test.rp2040.yaml | 16 ++++++ .../components/sm2135/test.esp32-c3-idf.yaml | 22 +++++++++ tests/components/sm2135/test.esp32-c3.yaml | 22 +++++++++ tests/components/sm2135/test.esp32-idf.yaml | 22 +++++++++ tests/components/sm2135/test.esp32.yaml | 22 +++++++++ tests/components/sm2135/test.esp8266.yaml | 22 +++++++++ tests/components/sm2135/test.rp2040.yaml | 22 +++++++++ .../components/sm2235/test.esp32-c3-idf.yaml | 22 +++++++++ tests/components/sm2235/test.esp32-c3.yaml | 22 +++++++++ tests/components/sm2235/test.esp32-idf.yaml | 22 +++++++++ tests/components/sm2235/test.esp32.yaml | 22 +++++++++ tests/components/sm2235/test.esp8266.yaml | 22 +++++++++ tests/components/sm2235/test.rp2040.yaml | 22 +++++++++ .../components/sm2335/test.esp32-c3-idf.yaml | 22 +++++++++ tests/components/sm2335/test.esp32-c3.yaml | 22 +++++++++ tests/components/sm2335/test.esp32-idf.yaml | 22 +++++++++ tests/components/sm2335/test.esp32.yaml | 22 +++++++++ tests/components/sm2335/test.esp8266.yaml | 22 +++++++++ tests/components/sm2335/test.rp2040.yaml | 22 +++++++++ .../components/sm300d2/test.esp32-c3-idf.yaml | 23 +++++++++ tests/components/sm300d2/test.esp32-c3.yaml | 23 +++++++++ tests/components/sm300d2/test.esp32-idf.yaml | 23 +++++++++ tests/components/sm300d2/test.esp32.yaml | 23 +++++++++ tests/components/sm300d2/test.esp8266.yaml | 23 +++++++++ tests/components/sm300d2/test.rp2040.yaml | 23 +++++++++ tests/components/sml/test.esp32-c3-idf.yaml | 31 ++++++++++++ tests/components/sml/test.esp32-c3.yaml | 31 ++++++++++++ tests/components/sml/test.esp32-idf.yaml | 31 ++++++++++++ tests/components/sml/test.esp32.yaml | 31 ++++++++++++ tests/components/sml/test.esp8266.yaml | 31 ++++++++++++ tests/components/sml/test.rp2040.yaml | 31 ++++++++++++ .../components/smt100/test.esp32-c3-idf.yaml | 19 +++++++ tests/components/smt100/test.esp32-c3.yaml | 19 +++++++ tests/components/smt100/test.esp32-idf.yaml | 19 +++++++ tests/components/smt100/test.esp32.yaml | 19 +++++++ tests/components/smt100/test.esp8266.yaml | 19 +++++++ tests/components/smt100/test.rp2040.yaml | 19 +++++++ 181 files changed, 3589 insertions(+) create mode 100644 tests/components/safe_mode/test.esp32-c3-idf.yaml create mode 100644 tests/components/safe_mode/test.esp32-c3.yaml create mode 100644 tests/components/safe_mode/test.esp32-idf.yaml create mode 100644 tests/components/safe_mode/test.esp32.yaml create mode 100644 tests/components/safe_mode/test.esp8266.yaml create mode 100644 tests/components/safe_mode/test.rp2040.yaml create mode 100644 tests/components/scd30/test.esp32-c3-idf.yaml create mode 100644 tests/components/scd30/test.esp32-c3.yaml create mode 100644 tests/components/scd30/test.esp32-idf.yaml create mode 100644 tests/components/scd30/test.esp32.yaml create mode 100644 tests/components/scd30/test.esp8266.yaml create mode 100644 tests/components/scd30/test.rp2040.yaml create mode 100644 tests/components/scd4x/test.esp32-c3-idf.yaml create mode 100644 tests/components/scd4x/test.esp32-c3.yaml create mode 100644 tests/components/scd4x/test.esp32-idf.yaml create mode 100644 tests/components/scd4x/test.esp32.yaml create mode 100644 tests/components/scd4x/test.esp8266.yaml create mode 100644 tests/components/scd4x/test.rp2040.yaml create mode 100644 tests/components/script/test.esp32-c3-idf.yaml create mode 100644 tests/components/script/test.esp32-c3.yaml create mode 100644 tests/components/script/test.esp32-idf.yaml create mode 100644 tests/components/script/test.esp32.yaml create mode 100644 tests/components/script/test.esp8266.yaml create mode 100644 tests/components/script/test.rp2040.yaml create mode 100644 tests/components/sdm_meter/test.esp32-c3-idf.yaml create mode 100644 tests/components/sdm_meter/test.esp32-c3.yaml create mode 100644 tests/components/sdm_meter/test.esp32-idf.yaml create mode 100644 tests/components/sdm_meter/test.esp32.yaml create mode 100644 tests/components/sdm_meter/test.esp8266.yaml create mode 100644 tests/components/sdm_meter/test.rp2040.yaml create mode 100644 tests/components/sdp3x/test.esp32-c3-idf.yaml create mode 100644 tests/components/sdp3x/test.esp32-c3.yaml create mode 100644 tests/components/sdp3x/test.esp32-idf.yaml create mode 100644 tests/components/sdp3x/test.esp32.yaml create mode 100644 tests/components/sdp3x/test.esp8266.yaml create mode 100644 tests/components/sdp3x/test.rp2040.yaml create mode 100644 tests/components/sds011/test.esp32-c3-idf.yaml create mode 100644 tests/components/sds011/test.esp32-c3.yaml create mode 100644 tests/components/sds011/test.esp32-idf.yaml create mode 100644 tests/components/sds011/test.esp32.yaml create mode 100644 tests/components/sds011/test.esp8266.yaml create mode 100644 tests/components/sds011/test.rp2040.yaml create mode 100644 tests/components/selec_meter/test.esp32-c3-idf.yaml create mode 100644 tests/components/selec_meter/test.esp32-c3.yaml create mode 100644 tests/components/selec_meter/test.esp32-idf.yaml create mode 100644 tests/components/selec_meter/test.esp32.yaml create mode 100644 tests/components/selec_meter/test.esp8266.yaml create mode 100644 tests/components/selec_meter/test.rp2040.yaml create mode 100644 tests/components/sen0321/test.esp32-c3-idf.yaml create mode 100644 tests/components/sen0321/test.esp32-c3.yaml create mode 100644 tests/components/sen0321/test.esp32-idf.yaml create mode 100644 tests/components/sen0321/test.esp32.yaml create mode 100644 tests/components/sen0321/test.esp8266.yaml create mode 100644 tests/components/sen0321/test.rp2040.yaml create mode 100644 tests/components/sen21231/test.esp32-c3-idf.yaml create mode 100644 tests/components/sen21231/test.esp32-c3.yaml create mode 100644 tests/components/sen21231/test.esp32-idf.yaml create mode 100644 tests/components/sen21231/test.esp32.yaml create mode 100644 tests/components/sen21231/test.esp8266.yaml create mode 100644 tests/components/sen21231/test.rp2040.yaml create mode 100644 tests/components/sen5x/test.esp32-c3-idf.yaml create mode 100644 tests/components/sen5x/test.esp32-c3.yaml create mode 100644 tests/components/sen5x/test.esp32-idf.yaml create mode 100644 tests/components/sen5x/test.esp32.yaml create mode 100644 tests/components/sen5x/test.esp8266.yaml create mode 100644 tests/components/sen5x/test.rp2040.yaml create mode 100644 tests/components/senseair/test.esp32-c3-idf.yaml create mode 100644 tests/components/senseair/test.esp32-c3.yaml create mode 100644 tests/components/senseair/test.esp32-idf.yaml create mode 100644 tests/components/senseair/test.esp32.yaml create mode 100644 tests/components/senseair/test.esp8266.yaml create mode 100644 tests/components/senseair/test.rp2040.yaml create mode 100644 tests/components/servo/test.esp32-c3-idf.yaml create mode 100644 tests/components/servo/test.esp32-c3.yaml create mode 100644 tests/components/servo/test.esp32-idf.yaml create mode 100644 tests/components/servo/test.esp32.yaml create mode 100644 tests/components/servo/test.esp8266.yaml create mode 100644 tests/components/servo/test.rp2040.yaml create mode 100644 tests/components/sfa30/test.esp32-c3-idf.yaml create mode 100644 tests/components/sfa30/test.esp32-c3.yaml create mode 100644 tests/components/sfa30/test.esp32-idf.yaml create mode 100644 tests/components/sfa30/test.esp32.yaml create mode 100644 tests/components/sfa30/test.esp8266.yaml create mode 100644 tests/components/sfa30/test.rp2040.yaml create mode 100644 tests/components/sgp30/test.esp32-c3-idf.yaml create mode 100644 tests/components/sgp30/test.esp32-c3.yaml create mode 100644 tests/components/sgp30/test.esp32-idf.yaml create mode 100644 tests/components/sgp30/test.esp32.yaml create mode 100644 tests/components/sgp30/test.esp8266.yaml create mode 100644 tests/components/sgp30/test.rp2040.yaml create mode 100644 tests/components/sgp4x/test.esp32-c3-idf.yaml create mode 100644 tests/components/sgp4x/test.esp32-c3.yaml create mode 100644 tests/components/sgp4x/test.esp32-idf.yaml create mode 100644 tests/components/sgp4x/test.esp32.yaml create mode 100644 tests/components/sgp4x/test.esp8266.yaml create mode 100644 tests/components/sgp4x/test.rp2040.yaml create mode 100644 tests/components/shelly_dimmer/test.esp8266.yaml create mode 100644 tests/components/sht3xd/test.esp32-c3-idf.yaml create mode 100644 tests/components/sht3xd/test.esp32-c3.yaml create mode 100644 tests/components/sht3xd/test.esp32-idf.yaml create mode 100644 tests/components/sht3xd/test.esp32.yaml create mode 100644 tests/components/sht3xd/test.esp8266.yaml create mode 100644 tests/components/sht3xd/test.rp2040.yaml create mode 100644 tests/components/sht4x/test.esp32-c3-idf.yaml create mode 100644 tests/components/sht4x/test.esp32-c3.yaml create mode 100644 tests/components/sht4x/test.esp32-idf.yaml create mode 100644 tests/components/sht4x/test.esp32.yaml create mode 100644 tests/components/sht4x/test.esp8266.yaml create mode 100644 tests/components/sht4x/test.rp2040.yaml create mode 100644 tests/components/shtcx/test.esp32-c3-idf.yaml create mode 100644 tests/components/shtcx/test.esp32-c3.yaml create mode 100644 tests/components/shtcx/test.esp32-idf.yaml create mode 100644 tests/components/shtcx/test.esp32.yaml create mode 100644 tests/components/shtcx/test.esp8266.yaml create mode 100644 tests/components/shtcx/test.rp2040.yaml create mode 100644 tests/components/shutdown/test.esp32-c3-idf.yaml create mode 100644 tests/components/shutdown/test.esp32-c3.yaml create mode 100644 tests/components/shutdown/test.esp32-idf.yaml create mode 100644 tests/components/shutdown/test.esp32.yaml create mode 100644 tests/components/shutdown/test.esp8266.yaml create mode 100644 tests/components/shutdown/test.rp2040.yaml create mode 100644 tests/components/sigma_delta_output/test.esp32-c3-idf.yaml create mode 100644 tests/components/sigma_delta_output/test.esp32-c3.yaml create mode 100644 tests/components/sigma_delta_output/test.esp32-idf.yaml create mode 100644 tests/components/sigma_delta_output/test.esp32.yaml create mode 100644 tests/components/sigma_delta_output/test.esp8266.yaml create mode 100644 tests/components/sigma_delta_output/test.rp2040.yaml create mode 100644 tests/components/sim800l/test.esp32-c3-idf.yaml create mode 100644 tests/components/sim800l/test.esp32-c3.yaml create mode 100644 tests/components/sim800l/test.esp32-idf.yaml create mode 100644 tests/components/sim800l/test.esp32.yaml create mode 100644 tests/components/sim800l/test.esp8266.yaml create mode 100644 tests/components/sim800l/test.rp2040.yaml create mode 100644 tests/components/slow_pwm/test.esp32-c3-idf.yaml create mode 100644 tests/components/slow_pwm/test.esp32-c3.yaml create mode 100644 tests/components/slow_pwm/test.esp32-idf.yaml create mode 100644 tests/components/slow_pwm/test.esp32.yaml create mode 100644 tests/components/slow_pwm/test.esp8266.yaml create mode 100644 tests/components/slow_pwm/test.rp2040.yaml create mode 100644 tests/components/sm16716/test.esp32-c3-idf.yaml create mode 100644 tests/components/sm16716/test.esp32-c3.yaml create mode 100644 tests/components/sm16716/test.esp32-idf.yaml create mode 100644 tests/components/sm16716/test.esp32.yaml create mode 100644 tests/components/sm16716/test.esp8266.yaml create mode 100644 tests/components/sm16716/test.rp2040.yaml create mode 100644 tests/components/sm2135/test.esp32-c3-idf.yaml create mode 100644 tests/components/sm2135/test.esp32-c3.yaml create mode 100644 tests/components/sm2135/test.esp32-idf.yaml create mode 100644 tests/components/sm2135/test.esp32.yaml create mode 100644 tests/components/sm2135/test.esp8266.yaml create mode 100644 tests/components/sm2135/test.rp2040.yaml create mode 100644 tests/components/sm2235/test.esp32-c3-idf.yaml create mode 100644 tests/components/sm2235/test.esp32-c3.yaml create mode 100644 tests/components/sm2235/test.esp32-idf.yaml create mode 100644 tests/components/sm2235/test.esp32.yaml create mode 100644 tests/components/sm2235/test.esp8266.yaml create mode 100644 tests/components/sm2235/test.rp2040.yaml create mode 100644 tests/components/sm2335/test.esp32-c3-idf.yaml create mode 100644 tests/components/sm2335/test.esp32-c3.yaml create mode 100644 tests/components/sm2335/test.esp32-idf.yaml create mode 100644 tests/components/sm2335/test.esp32.yaml create mode 100644 tests/components/sm2335/test.esp8266.yaml create mode 100644 tests/components/sm2335/test.rp2040.yaml create mode 100644 tests/components/sm300d2/test.esp32-c3-idf.yaml create mode 100644 tests/components/sm300d2/test.esp32-c3.yaml create mode 100644 tests/components/sm300d2/test.esp32-idf.yaml create mode 100644 tests/components/sm300d2/test.esp32.yaml create mode 100644 tests/components/sm300d2/test.esp8266.yaml create mode 100644 tests/components/sm300d2/test.rp2040.yaml create mode 100644 tests/components/sml/test.esp32-c3-idf.yaml create mode 100644 tests/components/sml/test.esp32-c3.yaml create mode 100644 tests/components/sml/test.esp32-idf.yaml create mode 100644 tests/components/sml/test.esp32.yaml create mode 100644 tests/components/sml/test.esp8266.yaml create mode 100644 tests/components/sml/test.rp2040.yaml create mode 100644 tests/components/smt100/test.esp32-c3-idf.yaml create mode 100644 tests/components/smt100/test.esp32-c3.yaml create mode 100644 tests/components/smt100/test.esp32-idf.yaml create mode 100644 tests/components/smt100/test.esp32.yaml create mode 100644 tests/components/smt100/test.esp8266.yaml create mode 100644 tests/components/smt100/test.rp2040.yaml diff --git a/tests/components/safe_mode/test.esp32-c3-idf.yaml b/tests/components/safe_mode/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.esp32-c3.yaml b/tests/components/safe_mode/test.esp32-c3.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.esp32-idf.yaml b/tests/components/safe_mode/test.esp32-idf.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.esp32.yaml b/tests/components/safe_mode/test.esp32.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.esp32.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.esp8266.yaml b/tests/components/safe_mode/test.esp8266.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.esp8266.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.rp2040.yaml b/tests/components/safe_mode/test.rp2040.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/test.rp2040.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/scd30/test.esp32-c3-idf.yaml b/tests/components/scd30/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..80f02a1b87 --- /dev/null +++ b/tests/components/scd30/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 5 + sda: 4 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd30/test.esp32-c3.yaml b/tests/components/scd30/test.esp32-c3.yaml new file mode 100644 index 0000000000..80f02a1b87 --- /dev/null +++ b/tests/components/scd30/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 5 + sda: 4 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd30/test.esp32-idf.yaml b/tests/components/scd30/test.esp32-idf.yaml new file mode 100644 index 0000000000..b48f8054c8 --- /dev/null +++ b/tests/components/scd30/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 16 + sda: 17 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd30/test.esp32.yaml b/tests/components/scd30/test.esp32.yaml new file mode 100644 index 0000000000..b48f8054c8 --- /dev/null +++ b/tests/components/scd30/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 16 + sda: 17 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd30/test.esp8266.yaml b/tests/components/scd30/test.esp8266.yaml new file mode 100644 index 0000000000..80f02a1b87 --- /dev/null +++ b/tests/components/scd30/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 5 + sda: 4 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd30/test.rp2040.yaml b/tests/components/scd30/test.rp2040.yaml new file mode 100644 index 0000000000..80f02a1b87 --- /dev/null +++ b/tests/components/scd30/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd30 + scl: 5 + sda: 4 + +sensor: + - platform: scd30 + co2: + name: SCD30 CO2 + temperature: + id: scd30_temperature + name: SCD30 Temperature + humidity: + name: SCD30 Humidity + address: 0x61 + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.esp32-c3-idf.yaml b/tests/components/scd4x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..353293be65 --- /dev/null +++ b/tests/components/scd4x/test.esp32-c3-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 5 + sda: 4 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.esp32-c3.yaml b/tests/components/scd4x/test.esp32-c3.yaml new file mode 100644 index 0000000000..353293be65 --- /dev/null +++ b/tests/components/scd4x/test.esp32-c3.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 5 + sda: 4 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.esp32-idf.yaml b/tests/components/scd4x/test.esp32-idf.yaml new file mode 100644 index 0000000000..02cec921d2 --- /dev/null +++ b/tests/components/scd4x/test.esp32-idf.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 16 + sda: 17 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.esp32.yaml b/tests/components/scd4x/test.esp32.yaml new file mode 100644 index 0000000000..02cec921d2 --- /dev/null +++ b/tests/components/scd4x/test.esp32.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 16 + sda: 17 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.esp8266.yaml b/tests/components/scd4x/test.esp8266.yaml new file mode 100644 index 0000000000..353293be65 --- /dev/null +++ b/tests/components/scd4x/test.esp8266.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 5 + sda: 4 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/scd4x/test.rp2040.yaml b/tests/components/scd4x/test.rp2040.yaml new file mode 100644 index 0000000000..353293be65 --- /dev/null +++ b/tests/components/scd4x/test.rp2040.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_scd4x + scl: 5 + sda: 4 + +sensor: + - platform: scd4x + id: scd40 + co2: + name: SCD4X CO2 + temperature: + id: scd4x_temperature + name: SCD4X Temperature + humidity: + name: SCD4X Humidity + automatic_self_calibration: true + altitude_compensation: 10m + ambient_pressure_compensation: 961mBar + temperature_offset: 4.2C + update_interval: 15s diff --git a/tests/components/script/test.esp32-c3-idf.yaml b/tests/components/script/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3872c690ff --- /dev/null +++ b/tests/components/script/test.esp32-c3-idf.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' diff --git a/tests/components/script/test.esp32-c3.yaml b/tests/components/script/test.esp32-c3.yaml new file mode 100644 index 0000000000..3872c690ff --- /dev/null +++ b/tests/components/script/test.esp32-c3.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' diff --git a/tests/components/script/test.esp32-idf.yaml b/tests/components/script/test.esp32-idf.yaml new file mode 100644 index 0000000000..3872c690ff --- /dev/null +++ b/tests/components/script/test.esp32-idf.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' diff --git a/tests/components/script/test.esp32.yaml b/tests/components/script/test.esp32.yaml new file mode 100644 index 0000000000..3872c690ff --- /dev/null +++ b/tests/components/script/test.esp32.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' diff --git a/tests/components/script/test.esp8266.yaml b/tests/components/script/test.esp8266.yaml new file mode 100644 index 0000000000..ce0e40e7ee --- /dev/null +++ b/tests/components/script/test.esp8266.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD(prefix.c_str(), "Hello World! %i %i", param2, param3);' diff --git a/tests/components/script/test.rp2040.yaml b/tests/components/script/test.rp2040.yaml new file mode 100644 index 0000000000..3872c690ff --- /dev/null +++ b/tests/components/script/test.rp2040.yaml @@ -0,0 +1,26 @@ +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: int + param3: bool + then: + - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' diff --git a/tests/components/sdm_meter/test.esp32-c3-idf.yaml b/tests/components/sdm_meter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0c2144f983 --- /dev/null +++ b/tests/components/sdm_meter/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdm_meter/test.esp32-c3.yaml b/tests/components/sdm_meter/test.esp32-c3.yaml new file mode 100644 index 0000000000..0c2144f983 --- /dev/null +++ b/tests/components/sdm_meter/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdm_meter/test.esp32-idf.yaml b/tests/components/sdm_meter/test.esp32-idf.yaml new file mode 100644 index 0000000000..eb3958db19 --- /dev/null +++ b/tests/components/sdm_meter/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdm_meter/test.esp32.yaml b/tests/components/sdm_meter/test.esp32.yaml new file mode 100644 index 0000000000..eb3958db19 --- /dev/null +++ b/tests/components/sdm_meter/test.esp32.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdm_meter/test.esp8266.yaml b/tests/components/sdm_meter/test.esp8266.yaml new file mode 100644 index 0000000000..0c2144f983 --- /dev/null +++ b/tests/components/sdm_meter/test.esp8266.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdm_meter/test.rp2040.yaml b/tests/components/sdm_meter/test.rp2040.yaml new file mode 100644 index 0000000000..0c2144f983 --- /dev/null +++ b/tests/components/sdm_meter/test.rp2040.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sdm_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sdm_meter + phase_a: + current: + name: Phase A Current + voltage: + name: Phase A Voltage + active_power: + name: Phase A Power + power_factor: + name: Phase A Power Factor + apparent_power: + name: Phase A Apparent Power + reactive_power: + name: Phase A Reactive Power + phase_angle: + name: Phase A Phase Angle diff --git a/tests/components/sdp3x/test.esp32-c3-idf.yaml b/tests/components/sdp3x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..42b90f1b81 --- /dev/null +++ b/tests/components/sdp3x/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 5 + sda: 4 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sdp3x/test.esp32-c3.yaml b/tests/components/sdp3x/test.esp32-c3.yaml new file mode 100644 index 0000000000..42b90f1b81 --- /dev/null +++ b/tests/components/sdp3x/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 5 + sda: 4 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sdp3x/test.esp32-idf.yaml b/tests/components/sdp3x/test.esp32-idf.yaml new file mode 100644 index 0000000000..00666082eb --- /dev/null +++ b/tests/components/sdp3x/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 16 + sda: 17 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sdp3x/test.esp32.yaml b/tests/components/sdp3x/test.esp32.yaml new file mode 100644 index 0000000000..00666082eb --- /dev/null +++ b/tests/components/sdp3x/test.esp32.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 16 + sda: 17 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sdp3x/test.esp8266.yaml b/tests/components/sdp3x/test.esp8266.yaml new file mode 100644 index 0000000000..42b90f1b81 --- /dev/null +++ b/tests/components/sdp3x/test.esp8266.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 5 + sda: 4 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sdp3x/test.rp2040.yaml b/tests/components/sdp3x/test.rp2040.yaml new file mode 100644 index 0000000000..42b90f1b81 --- /dev/null +++ b/tests/components/sdp3x/test.rp2040.yaml @@ -0,0 +1,11 @@ +i2c: + - id: i2c_sdp3x + scl: 5 + sda: 4 + +sensor: + - platform: sdp3x + id: filter_pressure + name: HVAC Filter Pressure drop + accuracy_decimals: 3 + update_interval: 5s diff --git a/tests/components/sds011/test.esp32-c3-idf.yaml b/tests/components/sds011/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e680a62dfe --- /dev/null +++ b/tests/components/sds011/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/sds011/test.esp32-c3.yaml b/tests/components/sds011/test.esp32-c3.yaml new file mode 100644 index 0000000000..e680a62dfe --- /dev/null +++ b/tests/components/sds011/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/sds011/test.esp32-idf.yaml b/tests/components/sds011/test.esp32-idf.yaml new file mode 100644 index 0000000000..275390f14c --- /dev/null +++ b/tests/components/sds011/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/sds011/test.esp32.yaml b/tests/components/sds011/test.esp32.yaml new file mode 100644 index 0000000000..275390f14c --- /dev/null +++ b/tests/components/sds011/test.esp32.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 17 + rx_pin: 16 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/sds011/test.esp8266.yaml b/tests/components/sds011/test.esp8266.yaml new file mode 100644 index 0000000000..e680a62dfe --- /dev/null +++ b/tests/components/sds011/test.esp8266.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/sds011/test.rp2040.yaml b/tests/components/sds011/test.rp2040.yaml new file mode 100644 index 0000000000..e680a62dfe --- /dev/null +++ b/tests/components/sds011/test.rp2040.yaml @@ -0,0 +1,14 @@ +uart: + - id: uart_sdm_sds011 + tx_pin: 4 + rx_pin: 5 + baud_rate: 115200 + +sensor: + - platform: sds011 + pm_2_5: + name: SDS011 PM2.5 + pm_10_0: + name: SDS011 PM10.0 + rx_only: false + update_interval: 5min diff --git a/tests/components/selec_meter/test.esp32-c3-idf.yaml b/tests/components/selec_meter/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5f6e69f96f --- /dev/null +++ b/tests/components/selec_meter/test.esp32-c3-idf.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/selec_meter/test.esp32-c3.yaml b/tests/components/selec_meter/test.esp32-c3.yaml new file mode 100644 index 0000000000..5f6e69f96f --- /dev/null +++ b/tests/components/selec_meter/test.esp32-c3.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/selec_meter/test.esp32-idf.yaml b/tests/components/selec_meter/test.esp32-idf.yaml new file mode 100644 index 0000000000..648adc1757 --- /dev/null +++ b/tests/components/selec_meter/test.esp32-idf.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/selec_meter/test.esp32.yaml b/tests/components/selec_meter/test.esp32.yaml new file mode 100644 index 0000000000..648adc1757 --- /dev/null +++ b/tests/components/selec_meter/test.esp32.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/selec_meter/test.esp8266.yaml b/tests/components/selec_meter/test.esp8266.yaml new file mode 100644 index 0000000000..5f6e69f96f --- /dev/null +++ b/tests/components/selec_meter/test.esp8266.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/selec_meter/test.rp2040.yaml b/tests/components/selec_meter/test.rp2040.yaml new file mode 100644 index 0000000000..5f6e69f96f --- /dev/null +++ b/tests/components/selec_meter/test.rp2040.yaml @@ -0,0 +1,45 @@ +uart: + - id: uart_selec_meter + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: selec_meter + total_active_energy: + name: SelecEM2M Total Active Energy + import_active_energy: + name: SelecEM2M Import Active Energy + export_active_energy: + name: SelecEM2M Export Active Energy + total_reactive_energy: + name: SelecEM2M Total Reactive Energy + import_reactive_energy: + name: SelecEM2M Import Reactive Energy + export_reactive_energy: + name: SelecEM2M Export Reactive Energy + apparent_energy: + name: SelecEM2M Apparent Energy + active_power: + name: SelecEM2M Active Power + reactive_power: + name: SelecEM2M Reactive Power + apparent_power: + name: SelecEM2M Apparent Power + voltage: + name: SelecEM2M Voltage + current: + name: SelecEM2M Current + power_factor: + name: SelecEM2M Power Factor + frequency: + name: SelecEM2M Frequency + maximum_demand_active_power: + name: SelecEM2M Maximum Demand Active Power + disabled_by_default: true + maximum_demand_reactive_power: + name: SelecEM2M Maximum Demand Reactive Power + disabled_by_default: true + maximum_demand_apparent_power: + name: SelecEM2M Maximum Demand Apparent Power + disabled_by_default: true diff --git a/tests/components/sen0321/test.esp32-c3-idf.yaml b/tests/components/sen0321/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7fa461a7fa --- /dev/null +++ b/tests/components/sen0321/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 5 + sda: 4 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen0321/test.esp32-c3.yaml b/tests/components/sen0321/test.esp32-c3.yaml new file mode 100644 index 0000000000..7fa461a7fa --- /dev/null +++ b/tests/components/sen0321/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 5 + sda: 4 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen0321/test.esp32-idf.yaml b/tests/components/sen0321/test.esp32-idf.yaml new file mode 100644 index 0000000000..44f76bf5e6 --- /dev/null +++ b/tests/components/sen0321/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 16 + sda: 17 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen0321/test.esp32.yaml b/tests/components/sen0321/test.esp32.yaml new file mode 100644 index 0000000000..44f76bf5e6 --- /dev/null +++ b/tests/components/sen0321/test.esp32.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 16 + sda: 17 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen0321/test.esp8266.yaml b/tests/components/sen0321/test.esp8266.yaml new file mode 100644 index 0000000000..7fa461a7fa --- /dev/null +++ b/tests/components/sen0321/test.esp8266.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 5 + sda: 4 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen0321/test.rp2040.yaml b/tests/components/sen0321/test.rp2040.yaml new file mode 100644 index 0000000000..7fa461a7fa --- /dev/null +++ b/tests/components/sen0321/test.rp2040.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sen0321 + scl: 5 + sda: 4 + +sensor: + - platform: sen0321 + name: Workshop Ozone Sensor + id: sen0321_ozone + update_interval: 10s diff --git a/tests/components/sen21231/test.esp32-c3-idf.yaml b/tests/components/sen21231/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..efd7843f56 --- /dev/null +++ b/tests/components/sen21231/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 5 + sda: 4 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen21231/test.esp32-c3.yaml b/tests/components/sen21231/test.esp32-c3.yaml new file mode 100644 index 0000000000..efd7843f56 --- /dev/null +++ b/tests/components/sen21231/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 5 + sda: 4 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen21231/test.esp32-idf.yaml b/tests/components/sen21231/test.esp32-idf.yaml new file mode 100644 index 0000000000..3173683f17 --- /dev/null +++ b/tests/components/sen21231/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 16 + sda: 17 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen21231/test.esp32.yaml b/tests/components/sen21231/test.esp32.yaml new file mode 100644 index 0000000000..3173683f17 --- /dev/null +++ b/tests/components/sen21231/test.esp32.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 16 + sda: 17 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen21231/test.esp8266.yaml b/tests/components/sen21231/test.esp8266.yaml new file mode 100644 index 0000000000..efd7843f56 --- /dev/null +++ b/tests/components/sen21231/test.esp8266.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 5 + sda: 4 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen21231/test.rp2040.yaml b/tests/components/sen21231/test.rp2040.yaml new file mode 100644 index 0000000000..efd7843f56 --- /dev/null +++ b/tests/components/sen21231/test.rp2040.yaml @@ -0,0 +1,9 @@ +i2c: + - id: i2c_sen21231 + scl: 5 + sda: 4 + +sensor: + - platform: sen21231 + id: sen21231_sensor1 + name: Person Sensor diff --git a/tests/components/sen5x/test.esp32-c3-idf.yaml b/tests/components/sen5x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3352a59b17 --- /dev/null +++ b/tests/components/sen5x/test.esp32-c3-idf.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 5 + sda: 4 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/sen5x/test.esp32-c3.yaml b/tests/components/sen5x/test.esp32-c3.yaml new file mode 100644 index 0000000000..3352a59b17 --- /dev/null +++ b/tests/components/sen5x/test.esp32-c3.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 5 + sda: 4 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/sen5x/test.esp32-idf.yaml b/tests/components/sen5x/test.esp32-idf.yaml new file mode 100644 index 0000000000..b8f89c435f --- /dev/null +++ b/tests/components/sen5x/test.esp32-idf.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 16 + sda: 17 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/sen5x/test.esp32.yaml b/tests/components/sen5x/test.esp32.yaml new file mode 100644 index 0000000000..b8f89c435f --- /dev/null +++ b/tests/components/sen5x/test.esp32.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 16 + sda: 17 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/sen5x/test.esp8266.yaml b/tests/components/sen5x/test.esp8266.yaml new file mode 100644 index 0000000000..3352a59b17 --- /dev/null +++ b/tests/components/sen5x/test.esp8266.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 5 + sda: 4 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/sen5x/test.rp2040.yaml b/tests/components/sen5x/test.rp2040.yaml new file mode 100644 index 0000000000..3352a59b17 --- /dev/null +++ b/tests/components/sen5x/test.rp2040.yaml @@ -0,0 +1,49 @@ +i2c: + - id: i2c_sen5x + scl: 5 + sda: 4 + +sensor: + - platform: sen5x + id: sen54 + temperature: + name: Temperature + accuracy_decimals: 1 + humidity: + name: Humidity + accuracy_decimals: 0 + pm_1_0: + name: PM <1µm Weight concentration + id: pm_1_0 + accuracy_decimals: 1 + pm_2_5: + name: PM <2.5µm Weight concentration + id: pm_2_5 + accuracy_decimals: 1 + pm_4_0: + name: PM <4µm Weight concentration + id: pm_4_0 + accuracy_decimals: 1 + pm_10_0: + name: PM <10µm Weight concentration + id: pm_10_0 + accuracy_decimals: 1 + nox: + name: NOx + voc: + name: VOC + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + temperature_compensation: + offset: 0 + normalized_offset_slope: 0 + time_constant: 0 + auto_cleaning_interval: 604800s + acceleration_mode: low + store_baseline: true + address: 0x69 diff --git a/tests/components/senseair/test.esp32-c3-idf.yaml b/tests/components/senseair/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..41a441f496 --- /dev/null +++ b/tests/components/senseair/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/senseair/test.esp32-c3.yaml b/tests/components/senseair/test.esp32-c3.yaml new file mode 100644 index 0000000000..41a441f496 --- /dev/null +++ b/tests/components/senseair/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/senseair/test.esp32-idf.yaml b/tests/components/senseair/test.esp32-idf.yaml new file mode 100644 index 0000000000..daa4645f59 --- /dev/null +++ b/tests/components/senseair/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/senseair/test.esp32.yaml b/tests/components/senseair/test.esp32.yaml new file mode 100644 index 0000000000..daa4645f59 --- /dev/null +++ b/tests/components/senseair/test.esp32.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/senseair/test.esp8266.yaml b/tests/components/senseair/test.esp8266.yaml new file mode 100644 index 0000000000..41a441f496 --- /dev/null +++ b/tests/components/senseair/test.esp8266.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/senseair/test.rp2040.yaml b/tests/components/senseair/test.rp2040.yaml new file mode 100644 index 0000000000..41a441f496 --- /dev/null +++ b/tests/components/senseair/test.rp2040.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_senseair + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: senseair + id: senseair0 + co2: + name: SenseAir CO2 Value + on_value: + then: + - senseair.background_calibration: senseair0 + - senseair.background_calibration_result: senseair0 + - senseair.abc_get_period: senseair0 + - senseair.abc_enable: senseair0 + - senseair.abc_disable: senseair0 + update_interval: 15s diff --git a/tests/components/servo/test.esp32-c3-idf.yaml b/tests/components/servo/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..29ebea3359 --- /dev/null +++ b/tests/components/servo/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: ledc + id: servo_output_1 + pin: 1 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/servo/test.esp32-c3.yaml b/tests/components/servo/test.esp32-c3.yaml new file mode 100644 index 0000000000..29ebea3359 --- /dev/null +++ b/tests/components/servo/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: ledc + id: servo_output_1 + pin: 1 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/servo/test.esp32-idf.yaml b/tests/components/servo/test.esp32-idf.yaml new file mode 100644 index 0000000000..e769f055b4 --- /dev/null +++ b/tests/components/servo/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: ledc + id: servo_output_1 + pin: 12 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/servo/test.esp32.yaml b/tests/components/servo/test.esp32.yaml new file mode 100644 index 0000000000..e769f055b4 --- /dev/null +++ b/tests/components/servo/test.esp32.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: ledc + id: servo_output_1 + pin: 12 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/servo/test.esp8266.yaml b/tests/components/servo/test.esp8266.yaml new file mode 100644 index 0000000000..48b4421641 --- /dev/null +++ b/tests/components/servo/test.esp8266.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: esp8266_pwm + id: servo_output_1 + pin: 12 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/servo/test.rp2040.yaml b/tests/components/servo/test.rp2040.yaml new file mode 100644 index 0000000000..75efa9407e --- /dev/null +++ b/tests/components/servo/test.rp2040.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - servo.write: + id: test_servo + level: -100.0% + - servo.detach: test_servo + +output: + - platform: rp2040_pwm + id: servo_output_1 + pin: 12 + +servo: + id: test_servo + output: servo_output_1 + restore: true + min_level: 4% + max_level: 8% diff --git a/tests/components/sfa30/test.esp32-c3-idf.yaml b/tests/components/sfa30/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..119059e4e2 --- /dev/null +++ b/tests/components/sfa30/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 5 + sda: 4 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sfa30/test.esp32-c3.yaml b/tests/components/sfa30/test.esp32-c3.yaml new file mode 100644 index 0000000000..119059e4e2 --- /dev/null +++ b/tests/components/sfa30/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 5 + sda: 4 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sfa30/test.esp32-idf.yaml b/tests/components/sfa30/test.esp32-idf.yaml new file mode 100644 index 0000000000..dc7e4988e5 --- /dev/null +++ b/tests/components/sfa30/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 16 + sda: 17 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sfa30/test.esp32.yaml b/tests/components/sfa30/test.esp32.yaml new file mode 100644 index 0000000000..dc7e4988e5 --- /dev/null +++ b/tests/components/sfa30/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 16 + sda: 17 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sfa30/test.esp8266.yaml b/tests/components/sfa30/test.esp8266.yaml new file mode 100644 index 0000000000..119059e4e2 --- /dev/null +++ b/tests/components/sfa30/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 5 + sda: 4 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sfa30/test.rp2040.yaml b/tests/components/sfa30/test.rp2040.yaml new file mode 100644 index 0000000000..119059e4e2 --- /dev/null +++ b/tests/components/sfa30/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sfa30 + scl: 5 + sda: 4 + +sensor: + - platform: sfa30 + formaldehyde: + name: "SFA30 formaldehyde" + temperature: + name: "SFA30 temperature" + humidity: + name: "SFA30 humidity" + address: 0x5D + update_interval: 30s diff --git a/tests/components/sgp30/test.esp32-c3-idf.yaml b/tests/components/sgp30/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..45de67e94b --- /dev/null +++ b/tests/components/sgp30/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 5 + sda: 4 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp30/test.esp32-c3.yaml b/tests/components/sgp30/test.esp32-c3.yaml new file mode 100644 index 0000000000..45de67e94b --- /dev/null +++ b/tests/components/sgp30/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 5 + sda: 4 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp30/test.esp32-idf.yaml b/tests/components/sgp30/test.esp32-idf.yaml new file mode 100644 index 0000000000..6ea23c25cd --- /dev/null +++ b/tests/components/sgp30/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 16 + sda: 17 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp30/test.esp32.yaml b/tests/components/sgp30/test.esp32.yaml new file mode 100644 index 0000000000..6ea23c25cd --- /dev/null +++ b/tests/components/sgp30/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 16 + sda: 17 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp30/test.esp8266.yaml b/tests/components/sgp30/test.esp8266.yaml new file mode 100644 index 0000000000..45de67e94b --- /dev/null +++ b/tests/components/sgp30/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 5 + sda: 4 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp30/test.rp2040.yaml b/tests/components/sgp30/test.rp2040.yaml new file mode 100644 index 0000000000..45de67e94b --- /dev/null +++ b/tests/components/sgp30/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sgp30 + scl: 5 + sda: 4 + +sensor: + - platform: sgp30 + eco2: + name: Workshop eCO2 + accuracy_decimals: 1 + tvoc: + name: Workshop TVOC + accuracy_decimals: 1 + address: 0x58 + update_interval: 5s diff --git a/tests/components/sgp4x/test.esp32-c3-idf.yaml b/tests/components/sgp4x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b2876478bd --- /dev/null +++ b/tests/components/sgp4x/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 5 + sda: 4 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/sgp4x/test.esp32-c3.yaml b/tests/components/sgp4x/test.esp32-c3.yaml new file mode 100644 index 0000000000..b2876478bd --- /dev/null +++ b/tests/components/sgp4x/test.esp32-c3.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 5 + sda: 4 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/sgp4x/test.esp32-idf.yaml b/tests/components/sgp4x/test.esp32-idf.yaml new file mode 100644 index 0000000000..c7380b5a10 --- /dev/null +++ b/tests/components/sgp4x/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 16 + sda: 17 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/sgp4x/test.esp32.yaml b/tests/components/sgp4x/test.esp32.yaml new file mode 100644 index 0000000000..c7380b5a10 --- /dev/null +++ b/tests/components/sgp4x/test.esp32.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 16 + sda: 17 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/sgp4x/test.esp8266.yaml b/tests/components/sgp4x/test.esp8266.yaml new file mode 100644 index 0000000000..b2876478bd --- /dev/null +++ b/tests/components/sgp4x/test.esp8266.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 5 + sda: 4 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/sgp4x/test.rp2040.yaml b/tests/components/sgp4x/test.rp2040.yaml new file mode 100644 index 0000000000..b2876478bd --- /dev/null +++ b/tests/components/sgp4x/test.rp2040.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_sgp4x + scl: 5 + sda: 4 + +sensor: + - platform: sgp4x + voc: + name: VOC Index + id: sgp40_voc_index + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + nox: + name: NOx + algorithm_tuning: + index_offset: 100 + learning_time_offset_hours: 12 + learning_time_gain_hours: 12 + gating_max_duration_minutes: 180 + std_initial: 50 + gain_factor: 230 + update_interval: 5s diff --git a/tests/components/shelly_dimmer/test.esp8266.yaml b/tests/components/shelly_dimmer/test.esp8266.yaml new file mode 100644 index 0000000000..3acd0260d5 --- /dev/null +++ b/tests/components/shelly_dimmer/test.esp8266.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_shelly_dimmer + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +light: + - platform: shelly_dimmer + name: Shelly Dimmer Light + power: + name: Shelly Dimmer Power + voltage: + name: Shelly Dimmer Voltage + current: + name: Shelly Dimmer Current + max_brightness: 500 + firmware: "51.6" + nrst_pin: 13 + boot0_pin: 14 diff --git a/tests/components/sht3xd/test.esp32-c3-idf.yaml b/tests/components/sht3xd/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0409ff65c6 --- /dev/null +++ b/tests/components/sht3xd/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 5 + sda: 4 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht3xd/test.esp32-c3.yaml b/tests/components/sht3xd/test.esp32-c3.yaml new file mode 100644 index 0000000000..0409ff65c6 --- /dev/null +++ b/tests/components/sht3xd/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 5 + sda: 4 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht3xd/test.esp32-idf.yaml b/tests/components/sht3xd/test.esp32-idf.yaml new file mode 100644 index 0000000000..2b6ee50760 --- /dev/null +++ b/tests/components/sht3xd/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 16 + sda: 17 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht3xd/test.esp32.yaml b/tests/components/sht3xd/test.esp32.yaml new file mode 100644 index 0000000000..2b6ee50760 --- /dev/null +++ b/tests/components/sht3xd/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 16 + sda: 17 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht3xd/test.esp8266.yaml b/tests/components/sht3xd/test.esp8266.yaml new file mode 100644 index 0000000000..0409ff65c6 --- /dev/null +++ b/tests/components/sht3xd/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 5 + sda: 4 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht3xd/test.rp2040.yaml b/tests/components/sht3xd/test.rp2040.yaml new file mode 100644 index 0000000000..0409ff65c6 --- /dev/null +++ b/tests/components/sht3xd/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht3xd + scl: 5 + sda: 4 + +sensor: + - platform: sht3xd + temperature: + name: SHT3XD Temperature + humidity: + name: SHT3XD Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.esp32-c3-idf.yaml b/tests/components/sht4x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0bcdd864f6 --- /dev/null +++ b/tests/components/sht4x/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 5 + sda: 4 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.esp32-c3.yaml b/tests/components/sht4x/test.esp32-c3.yaml new file mode 100644 index 0000000000..0bcdd864f6 --- /dev/null +++ b/tests/components/sht4x/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 5 + sda: 4 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.esp32-idf.yaml b/tests/components/sht4x/test.esp32-idf.yaml new file mode 100644 index 0000000000..13ec524d7d --- /dev/null +++ b/tests/components/sht4x/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 16 + sda: 17 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.esp32.yaml b/tests/components/sht4x/test.esp32.yaml new file mode 100644 index 0000000000..13ec524d7d --- /dev/null +++ b/tests/components/sht4x/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 16 + sda: 17 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.esp8266.yaml b/tests/components/sht4x/test.esp8266.yaml new file mode 100644 index 0000000000..0bcdd864f6 --- /dev/null +++ b/tests/components/sht4x/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 5 + sda: 4 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/sht4x/test.rp2040.yaml b/tests/components/sht4x/test.rp2040.yaml new file mode 100644 index 0000000000..0bcdd864f6 --- /dev/null +++ b/tests/components/sht4x/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_sht4x + scl: 5 + sda: 4 + +sensor: + - platform: sht4x + temperature: + name: SHT4X Temperature + humidity: + name: SHT4X Humidity + address: 0x44 + update_interval: 15s diff --git a/tests/components/shtcx/test.esp32-c3-idf.yaml b/tests/components/shtcx/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c1c7a2a63f --- /dev/null +++ b/tests/components/shtcx/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 5 + sda: 4 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shtcx/test.esp32-c3.yaml b/tests/components/shtcx/test.esp32-c3.yaml new file mode 100644 index 0000000000..c1c7a2a63f --- /dev/null +++ b/tests/components/shtcx/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 5 + sda: 4 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shtcx/test.esp32-idf.yaml b/tests/components/shtcx/test.esp32-idf.yaml new file mode 100644 index 0000000000..619bac9548 --- /dev/null +++ b/tests/components/shtcx/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 16 + sda: 17 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shtcx/test.esp32.yaml b/tests/components/shtcx/test.esp32.yaml new file mode 100644 index 0000000000..619bac9548 --- /dev/null +++ b/tests/components/shtcx/test.esp32.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 16 + sda: 17 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shtcx/test.esp8266.yaml b/tests/components/shtcx/test.esp8266.yaml new file mode 100644 index 0000000000..c1c7a2a63f --- /dev/null +++ b/tests/components/shtcx/test.esp8266.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 5 + sda: 4 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shtcx/test.rp2040.yaml b/tests/components/shtcx/test.rp2040.yaml new file mode 100644 index 0000000000..c1c7a2a63f --- /dev/null +++ b/tests/components/shtcx/test.rp2040.yaml @@ -0,0 +1,13 @@ +i2c: + - id: i2c_shtcx + scl: 5 + sda: 4 + +sensor: + - platform: shtcx + temperature: + name: SHTCX Temperature + humidity: + name: SHTCX Humidity + address: 0x70 + update_interval: 15s diff --git a/tests/components/shutdown/test.esp32-c3-idf.yaml b/tests/components/shutdown/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.esp32-c3.yaml b/tests/components/shutdown/test.esp32-c3.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.esp32-idf.yaml b/tests/components/shutdown/test.esp32-idf.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.esp32.yaml b/tests/components/shutdown/test.esp32.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.esp32.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.esp8266.yaml b/tests/components/shutdown/test.esp8266.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.esp8266.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.rp2040.yaml b/tests/components/shutdown/test.rp2040.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/test.rp2040.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml b/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.esp32-c3.yaml b/tests/components/sigma_delta_output/test.esp32-c3.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.esp32-idf.yaml b/tests/components/sigma_delta_output/test.esp32-idf.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.esp32.yaml b/tests/components/sigma_delta_output/test.esp32.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.esp32.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.esp8266.yaml b/tests/components/sigma_delta_output/test.esp8266.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.esp8266.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.rp2040.yaml b/tests/components/sigma_delta_output/test.rp2040.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/test.rp2040.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sim800l/test.esp32-c3-idf.yaml b/tests/components/sim800l/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..7ff359d1e7 --- /dev/null +++ b/tests/components/sim800l/test.esp32-c3-idf.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/sim800l/test.esp32-c3.yaml b/tests/components/sim800l/test.esp32-c3.yaml new file mode 100644 index 0000000000..7ff359d1e7 --- /dev/null +++ b/tests/components/sim800l/test.esp32-c3.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/sim800l/test.esp32-idf.yaml b/tests/components/sim800l/test.esp32-idf.yaml new file mode 100644 index 0000000000..c116548c6f --- /dev/null +++ b/tests/components/sim800l/test.esp32-idf.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/sim800l/test.esp32.yaml b/tests/components/sim800l/test.esp32.yaml new file mode 100644 index 0000000000..c116548c6f --- /dev/null +++ b/tests/components/sim800l/test.esp32.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/sim800l/test.esp8266.yaml b/tests/components/sim800l/test.esp8266.yaml new file mode 100644 index 0000000000..7ff359d1e7 --- /dev/null +++ b/tests/components/sim800l/test.esp8266.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/sim800l/test.rp2040.yaml b/tests/components/sim800l/test.rp2040.yaml new file mode 100644 index 0000000000..7ff359d1e7 --- /dev/null +++ b/tests/components/sim800l/test.rp2040.yaml @@ -0,0 +1,37 @@ +esphome: + on_boot: + then: + - sim800l.send_sms: + recipient: '+15551234567' + message: Hello there + - sim800l.dial: + recipient: '+15551234567' + - sim800l.connect + - sim800l.disconnect + - sim800l.send_ussd: + ussd: test_ussd + +uart: + - id: uart_sim800l + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sim800l: + on_sms_received: + - lambda: |- + std::string str; + str = sender; + str = message; + - sim800l.send_sms: + message: hello you + recipient: "+1234" + - sim800l.dial: + recipient: "+1234" + on_incoming_call: + - logger.log: + format: "Incoming call from '%s'" + args: ["caller_id.c_str()"] + - sim800l.disconnect + on_ussd_received: + - logger.log: "ussd_received" diff --git a/tests/components/slow_pwm/test.esp32-c3-idf.yaml b/tests/components/slow_pwm/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.esp32-c3.yaml b/tests/components/slow_pwm/test.esp32-c3.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.esp32-idf.yaml b/tests/components/slow_pwm/test.esp32-idf.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.esp32.yaml b/tests/components/slow_pwm/test.esp32.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.esp32.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.esp8266.yaml b/tests/components/slow_pwm/test.esp8266.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.esp8266.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.rp2040.yaml b/tests/components/slow_pwm/test.rp2040.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/test.rp2040.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/sm16716/test.esp32-c3-idf.yaml b/tests/components/sm16716/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.esp32-c3-idf.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.esp32-c3.yaml b/tests/components/sm16716/test.esp32-c3.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.esp32-c3.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.esp32-idf.yaml b/tests/components/sm16716/test.esp32-idf.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.esp32.yaml b/tests/components/sm16716/test.esp32.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.esp32.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.esp8266.yaml b/tests/components/sm16716/test.esp8266.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.esp8266.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.rp2040.yaml b/tests/components/sm16716/test.rp2040.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/test.rp2040.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm2135/test.esp32-c3-idf.yaml b/tests/components/sm2135/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.esp32-c3.yaml b/tests/components/sm2135/test.esp32-c3.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.esp32-idf.yaml b/tests/components/sm2135/test.esp32-idf.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.esp32.yaml b/tests/components/sm2135/test.esp32.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.esp32.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.esp8266.yaml b/tests/components/sm2135/test.esp8266.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.esp8266.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.rp2040.yaml b/tests/components/sm2135/test.rp2040.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/test.rp2040.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2235/test.esp32-c3-idf.yaml b/tests/components/sm2235/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.esp32-c3.yaml b/tests/components/sm2235/test.esp32-c3.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.esp32-idf.yaml b/tests/components/sm2235/test.esp32-idf.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.esp32.yaml b/tests/components/sm2235/test.esp32.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.esp32.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.esp8266.yaml b/tests/components/sm2235/test.esp8266.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.esp8266.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.rp2040.yaml b/tests/components/sm2235/test.rp2040.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/test.rp2040.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp32-c3-idf.yaml b/tests/components/sm2335/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.esp32-c3-idf.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp32-c3.yaml b/tests/components/sm2335/test.esp32-c3.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.esp32-c3.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp32-idf.yaml b/tests/components/sm2335/test.esp32-idf.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.esp32-idf.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp32.yaml b/tests/components/sm2335/test.esp32.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.esp32.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp8266.yaml b/tests/components/sm2335/test.esp8266.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.esp8266.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.rp2040.yaml b/tests/components/sm2335/test.rp2040.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/test.rp2040.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm300d2/test.esp32-c3-idf.yaml b/tests/components/sm300d2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..bcd0a728b2 --- /dev/null +++ b/tests/components/sm300d2/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sm300d2/test.esp32-c3.yaml b/tests/components/sm300d2/test.esp32-c3.yaml new file mode 100644 index 0000000000..bcd0a728b2 --- /dev/null +++ b/tests/components/sm300d2/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sm300d2/test.esp32-idf.yaml b/tests/components/sm300d2/test.esp32-idf.yaml new file mode 100644 index 0000000000..92dba4fb3b --- /dev/null +++ b/tests/components/sm300d2/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sm300d2/test.esp32.yaml b/tests/components/sm300d2/test.esp32.yaml new file mode 100644 index 0000000000..92dba4fb3b --- /dev/null +++ b/tests/components/sm300d2/test.esp32.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sm300d2/test.esp8266.yaml b/tests/components/sm300d2/test.esp8266.yaml new file mode 100644 index 0000000000..bcd0a728b2 --- /dev/null +++ b/tests/components/sm300d2/test.esp8266.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sm300d2/test.rp2040.yaml b/tests/components/sm300d2/test.rp2040.yaml new file mode 100644 index 0000000000..bcd0a728b2 --- /dev/null +++ b/tests/components/sm300d2/test.rp2040.yaml @@ -0,0 +1,23 @@ +uart: + - id: uart_sm300d2 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: sm300d2 + co2: + name: SM300D2 CO2 Value + formaldehyde: + name: SM300D2 Formaldehyde Value + tvoc: + name: SM300D2 TVOC Value + pm_2_5: + name: SM300D2 PM2.5 Value + pm_10_0: + name: SM300D2 PM10 Value + temperature: + name: SM300D2 Temperature Value + humidity: + name: SM300D2 Humidity Value + update_interval: 60s diff --git a/tests/components/sml/test.esp32-c3-idf.yaml b/tests/components/sml/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..903f968c26 --- /dev/null +++ b/tests/components/sml/test.esp32-c3-idf.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/sml/test.esp32-c3.yaml b/tests/components/sml/test.esp32-c3.yaml new file mode 100644 index 0000000000..903f968c26 --- /dev/null +++ b/tests/components/sml/test.esp32-c3.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/sml/test.esp32-idf.yaml b/tests/components/sml/test.esp32-idf.yaml new file mode 100644 index 0000000000..7217199380 --- /dev/null +++ b/tests/components/sml/test.esp32-idf.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/sml/test.esp32.yaml b/tests/components/sml/test.esp32.yaml new file mode 100644 index 0000000000..7217199380 --- /dev/null +++ b/tests/components/sml/test.esp32.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/sml/test.esp8266.yaml b/tests/components/sml/test.esp8266.yaml new file mode 100644 index 0000000000..903f968c26 --- /dev/null +++ b/tests/components/sml/test.esp8266.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/sml/test.rp2040.yaml b/tests/components/sml/test.rp2040.yaml new file mode 100644 index 0000000000..903f968c26 --- /dev/null +++ b/tests/components/sml/test.rp2040.yaml @@ -0,0 +1,31 @@ +uart: + - id: uart_sml + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sml: + id: mysml + on_data: + - logger.log: "SML on_data" + +sensor: + - platform: sml + name: Total energy + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "1-0:1.8.0" + unit_of_measurement: kWh + accuracy_decimals: 1 + device_class: energy + state_class: total_increasing + filters: + - multiply: 0.0001 + +text_sensor: + - platform: sml + name: Manufacturer + sml_id: mysml + server_id: 0123456789abcdef + obis_code: "129-129:199.130.3" + format: text diff --git a/tests/components/smt100/test.esp32-c3-idf.yaml b/tests/components/smt100/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4277f2567b --- /dev/null +++ b/tests/components/smt100/test.esp32-c3-idf.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s diff --git a/tests/components/smt100/test.esp32-c3.yaml b/tests/components/smt100/test.esp32-c3.yaml new file mode 100644 index 0000000000..4277f2567b --- /dev/null +++ b/tests/components/smt100/test.esp32-c3.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s diff --git a/tests/components/smt100/test.esp32-idf.yaml b/tests/components/smt100/test.esp32-idf.yaml new file mode 100644 index 0000000000..7c19f4bc45 --- /dev/null +++ b/tests/components/smt100/test.esp32-idf.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s diff --git a/tests/components/smt100/test.esp32.yaml b/tests/components/smt100/test.esp32.yaml new file mode 100644 index 0000000000..7c19f4bc45 --- /dev/null +++ b/tests/components/smt100/test.esp32.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s diff --git a/tests/components/smt100/test.esp8266.yaml b/tests/components/smt100/test.esp8266.yaml new file mode 100644 index 0000000000..4277f2567b --- /dev/null +++ b/tests/components/smt100/test.esp8266.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s diff --git a/tests/components/smt100/test.rp2040.yaml b/tests/components/smt100/test.rp2040.yaml new file mode 100644 index 0000000000..4277f2567b --- /dev/null +++ b/tests/components/smt100/test.rp2040.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_smt100 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +sensor: + - platform: smt100 + counts: + name: Counts + dielectric_constant: + name: Dielectric Constant + temperature: + name: Temperature + moisture: + name: Moisture + voltage: + name: Voltage + update_interval: 60s From 06829b53fe134cb74a06afd00d618c85cc189052 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 23 Apr 2024 14:40:20 -0500 Subject: [PATCH 1613/2607] Add some components to the new testing framework (S part 2) (#6227) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../sn74hc165/test.esp32-c3-idf.yaml | 14 ++++ tests/components/sn74hc165/test.esp32-c3.yaml | 14 ++++ .../components/sn74hc165/test.esp32-idf.yaml | 14 ++++ tests/components/sn74hc165/test.esp32.yaml | 14 ++++ tests/components/sn74hc165/test.esp8266.yaml | 14 ++++ tests/components/sn74hc165/test.rp2040.yaml | 14 ++++ tests/components/sntp/test.esp32-c3-idf.yaml | 15 ++++ tests/components/sntp/test.esp32-c3.yaml | 15 ++++ tests/components/sntp/test.esp32-idf.yaml | 15 ++++ tests/components/sntp/test.esp32.yaml | 15 ++++ tests/components/sntp/test.esp8266.yaml | 15 ++++ tests/components/sntp/test.rp2040.yaml | 15 ++++ .../components/sonoff_d1/test.esp32-idf.yaml | 12 +++ tests/components/sonoff_d1/test.esp32.yaml | 12 +++ tests/components/sonoff_d1/test.esp8266.yaml | 12 +++ .../components/speaker/test.esp32-c3-idf.yaml | 17 ++++ tests/components/speaker/test.esp32-c3.yaml | 17 ++++ tests/components/speaker/test.esp32-idf.yaml | 17 ++++ tests/components/speaker/test.esp32.yaml | 17 ++++ tests/components/speed/test.esp32-c3-idf.yaml | 9 ++ tests/components/speed/test.esp32-c3.yaml | 9 ++ tests/components/speed/test.esp32-idf.yaml | 9 ++ tests/components/speed/test.esp32.yaml | 9 ++ tests/components/speed/test.esp8266.yaml | 9 ++ tests/components/speed/test.rp2040.yaml | 9 ++ tests/components/spi/test.esp32-c3-idf.yaml | 5 ++ tests/components/spi/test.esp32-c3.yaml | 5 ++ tests/components/spi/test.esp32-idf.yaml | 5 ++ tests/components/spi/test.esp32.yaml | 5 ++ tests/components/spi/test.esp8266.yaml | 5 ++ tests/components/spi/test.rp2040.yaml | 5 ++ .../spi_device/test.esp32-c3-idf.yaml | 11 +++ .../components/spi_device/test.esp32-c3.yaml | 11 +++ .../components/spi_device/test.esp32-idf.yaml | 11 +++ tests/components/spi_device/test.esp32.yaml | 11 +++ tests/components/spi_device/test.esp8266.yaml | 11 +++ tests/components/spi_device/test.rp2040.yaml | 11 +++ .../spi_led_strip/test.esp32-c3-idf.yaml | 13 +++ .../spi_led_strip/test.esp32-c3.yaml | 13 +++ .../spi_led_strip/test.esp32-idf.yaml | 13 +++ .../components/spi_led_strip/test.esp32.yaml | 13 +++ .../spi_led_strip/test.esp8266.yaml | 13 +++ .../components/spi_led_strip/test.rp2040.yaml | 13 +++ .../sprinkler/test.esp32-c3-idf.yaml | 83 +++++++++++++++++++ tests/components/sprinkler/test.esp32-c3.yaml | 83 +++++++++++++++++++ .../components/sprinkler/test.esp32-idf.yaml | 83 +++++++++++++++++++ tests/components/sprinkler/test.esp32.yaml | 83 +++++++++++++++++++ tests/components/sprinkler/test.esp8266.yaml | 83 +++++++++++++++++++ tests/components/sprinkler/test.rp2040.yaml | 83 +++++++++++++++++++ tests/components/sps30/test.esp32-c3-idf.yaml | 36 ++++++++ tests/components/sps30/test.esp32-c3.yaml | 36 ++++++++ tests/components/sps30/test.esp32-idf.yaml | 36 ++++++++ tests/components/sps30/test.esp32.yaml | 36 ++++++++ tests/components/sps30/test.esp8266.yaml | 36 ++++++++ tests/components/sps30/test.rp2040.yaml | 36 ++++++++ .../ssd1306_i2c/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1306_i2c/test.esp32-c3.yaml | 25 ++++++ .../ssd1306_i2c/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1306_i2c/test.esp32.yaml | 25 ++++++ .../components/ssd1306_i2c/test.esp8266.yaml | 25 ++++++ tests/components/ssd1306_i2c/test.rp2040.yaml | 25 ++++++ .../ssd1306_spi/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1306_spi/test.esp32-c3.yaml | 25 ++++++ .../ssd1306_spi/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1306_spi/test.esp32.yaml | 25 ++++++ .../components/ssd1306_spi/test.esp8266.yaml | 25 ++++++ tests/components/ssd1306_spi/test.rp2040.yaml | 25 ++++++ .../ssd1322_spi/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1322_spi/test.esp32-c3.yaml | 25 ++++++ .../ssd1322_spi/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1322_spi/test.esp32.yaml | 25 ++++++ .../components/ssd1322_spi/test.esp8266.yaml | 25 ++++++ tests/components/ssd1322_spi/test.rp2040.yaml | 25 ++++++ .../ssd1325_spi/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1325_spi/test.esp32-c3.yaml | 25 ++++++ .../ssd1325_spi/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1325_spi/test.esp32.yaml | 25 ++++++ .../components/ssd1325_spi/test.esp8266.yaml | 25 ++++++ tests/components/ssd1325_spi/test.rp2040.yaml | 25 ++++++ .../ssd1327_i2c/test.esp32-c3-idf.yaml | 24 ++++++ .../components/ssd1327_i2c/test.esp32-c3.yaml | 24 ++++++ .../ssd1327_i2c/test.esp32-idf.yaml | 24 ++++++ tests/components/ssd1327_i2c/test.esp32.yaml | 24 ++++++ .../components/ssd1327_i2c/test.esp8266.yaml | 24 ++++++ tests/components/ssd1327_i2c/test.rp2040.yaml | 24 ++++++ .../ssd1327_spi/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1327_spi/test.esp32-c3.yaml | 25 ++++++ .../ssd1327_spi/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1327_spi/test.esp32.yaml | 25 ++++++ .../components/ssd1327_spi/test.esp8266.yaml | 25 ++++++ tests/components/ssd1327_spi/test.rp2040.yaml | 25 ++++++ .../ssd1331_spi/test.esp32-c3-idf.yaml | 24 ++++++ .../components/ssd1331_spi/test.esp32-c3.yaml | 24 ++++++ .../ssd1331_spi/test.esp32-idf.yaml | 24 ++++++ tests/components/ssd1331_spi/test.esp32.yaml | 24 ++++++ .../components/ssd1331_spi/test.esp8266.yaml | 24 ++++++ tests/components/ssd1331_spi/test.rp2040.yaml | 24 ++++++ .../ssd1351_spi/test.esp32-c3-idf.yaml | 25 ++++++ .../components/ssd1351_spi/test.esp32-c3.yaml | 25 ++++++ .../ssd1351_spi/test.esp32-idf.yaml | 25 ++++++ tests/components/ssd1351_spi/test.esp32.yaml | 25 ++++++ .../components/ssd1351_spi/test.esp8266.yaml | 25 ++++++ tests/components/ssd1351_spi/test.rp2040.yaml | 25 ++++++ .../st7567_i2c/test.esp32-c3-idf.yaml | 23 +++++ .../components/st7567_i2c/test.esp32-c3.yaml | 23 +++++ .../components/st7567_i2c/test.esp32-idf.yaml | 23 +++++ tests/components/st7567_i2c/test.esp32.yaml | 23 +++++ tests/components/st7567_i2c/test.esp8266.yaml | 23 +++++ tests/components/st7567_i2c/test.rp2040.yaml | 23 +++++ .../st7567_spi/test.esp32-c3-idf.yaml | 24 ++++++ .../components/st7567_spi/test.esp32-c3.yaml | 24 ++++++ .../components/st7567_spi/test.esp32-idf.yaml | 24 ++++++ tests/components/st7567_spi/test.esp32.yaml | 24 ++++++ tests/components/st7567_spi/test.esp8266.yaml | 24 ++++++ tests/components/st7567_spi/test.rp2040.yaml | 24 ++++++ .../components/st7735/test.esp32-c3-idf.yaml | 29 +++++++ tests/components/st7735/test.esp32-c3.yaml | 29 +++++++ tests/components/st7735/test.esp32-idf.yaml | 29 +++++++ tests/components/st7735/test.esp32.yaml | 29 +++++++ tests/components/st7735/test.esp8266.yaml | 29 +++++++ tests/components/st7735/test.rp2040.yaml | 29 +++++++ .../components/st7789v/test.esp32-c3-idf.yaml | 25 ++++++ tests/components/st7789v/test.esp32-c3.yaml | 25 ++++++ tests/components/st7789v/test.esp32-idf.yaml | 25 ++++++ tests/components/st7789v/test.esp32.yaml | 25 ++++++ tests/components/st7789v/test.esp8266.yaml | 25 ++++++ tests/components/st7789v/test.rp2040.yaml | 25 ++++++ .../components/st7920/test.esp32-c3-idf.yaml | 24 ++++++ tests/components/st7920/test.esp32-c3.yaml | 24 ++++++ tests/components/st7920/test.esp32-idf.yaml | 24 ++++++ tests/components/st7920/test.esp32.yaml | 24 ++++++ tests/components/st7920/test.esp8266.yaml | 24 ++++++ tests/components/st7920/test.rp2040.yaml | 24 ++++++ .../components/status/test.esp32-c3-idf.yaml | 10 +++ tests/components/status/test.esp32-c3.yaml | 10 +++ tests/components/status/test.esp32-idf.yaml | 10 +++ tests/components/status/test.esp32.yaml | 10 +++ tests/components/status/test.esp8266.yaml | 10 +++ tests/components/status/test.rp2040.yaml | 10 +++ .../status_led/test.esp32-c3-idf.yaml | 10 +++ .../components/status_led/test.esp32-c3.yaml | 10 +++ .../components/status_led/test.esp32-idf.yaml | 10 +++ tests/components/status_led/test.esp32.yaml | 10 +++ tests/components/status_led/test.esp8266.yaml | 10 +++ tests/components/status_led/test.rp2040.yaml | 10 +++ .../components/stepper/test.esp32-c3-idf.yaml | 27 ++++++ tests/components/stepper/test.esp32-c3.yaml | 27 ++++++ tests/components/stepper/test.esp32-idf.yaml | 27 ++++++ tests/components/stepper/test.esp32.yaml | 27 ++++++ tests/components/stepper/test.esp8266.yaml | 27 ++++++ tests/components/stepper/test.rp2040.yaml | 27 ++++++ tests/components/sts3x/test.esp32-c3-idf.yaml | 10 +++ tests/components/sts3x/test.esp32-c3.yaml | 10 +++ tests/components/sts3x/test.esp32-idf.yaml | 10 +++ tests/components/sts3x/test.esp32.yaml | 10 +++ tests/components/sts3x/test.esp8266.yaml | 10 +++ tests/components/sts3x/test.rp2040.yaml | 10 +++ tests/components/sun/test.esp32-c3-idf.yaml | 38 +++++++++ tests/components/sun/test.esp32-c3.yaml | 38 +++++++++ tests/components/sun/test.esp32-idf.yaml | 38 +++++++++ tests/components/sun/test.esp32.yaml | 38 +++++++++ tests/components/sun/test.esp8266.yaml | 38 +++++++++ tests/components/sun/test.rp2040.yaml | 38 +++++++++ .../components/sx1509/test.esp32-c3-idf.yaml | 15 ++++ tests/components/sx1509/test.esp32-c3.yaml | 15 ++++ tests/components/sx1509/test.esp32-idf.yaml | 15 ++++ tests/components/sx1509/test.esp32.yaml | 15 ++++ tests/components/sx1509/test.esp8266.yaml | 15 ++++ tests/components/sx1509/test.rp2040.yaml | 15 ++++ 169 files changed, 3818 insertions(+) create mode 100644 tests/components/sn74hc165/test.esp32-c3-idf.yaml create mode 100644 tests/components/sn74hc165/test.esp32-c3.yaml create mode 100644 tests/components/sn74hc165/test.esp32-idf.yaml create mode 100644 tests/components/sn74hc165/test.esp32.yaml create mode 100644 tests/components/sn74hc165/test.esp8266.yaml create mode 100644 tests/components/sn74hc165/test.rp2040.yaml create mode 100644 tests/components/sntp/test.esp32-c3-idf.yaml create mode 100644 tests/components/sntp/test.esp32-c3.yaml create mode 100644 tests/components/sntp/test.esp32-idf.yaml create mode 100644 tests/components/sntp/test.esp32.yaml create mode 100644 tests/components/sntp/test.esp8266.yaml create mode 100644 tests/components/sntp/test.rp2040.yaml create mode 100644 tests/components/sonoff_d1/test.esp32-idf.yaml create mode 100644 tests/components/sonoff_d1/test.esp32.yaml create mode 100644 tests/components/sonoff_d1/test.esp8266.yaml create mode 100644 tests/components/speaker/test.esp32-c3-idf.yaml create mode 100644 tests/components/speaker/test.esp32-c3.yaml create mode 100644 tests/components/speaker/test.esp32-idf.yaml create mode 100644 tests/components/speaker/test.esp32.yaml create mode 100644 tests/components/speed/test.esp32-c3-idf.yaml create mode 100644 tests/components/speed/test.esp32-c3.yaml create mode 100644 tests/components/speed/test.esp32-idf.yaml create mode 100644 tests/components/speed/test.esp32.yaml create mode 100644 tests/components/speed/test.esp8266.yaml create mode 100644 tests/components/speed/test.rp2040.yaml create mode 100644 tests/components/spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/spi/test.esp32-c3.yaml create mode 100644 tests/components/spi/test.esp32-idf.yaml create mode 100644 tests/components/spi/test.esp32.yaml create mode 100644 tests/components/spi/test.esp8266.yaml create mode 100644 tests/components/spi/test.rp2040.yaml create mode 100644 tests/components/spi_device/test.esp32-c3-idf.yaml create mode 100644 tests/components/spi_device/test.esp32-c3.yaml create mode 100644 tests/components/spi_device/test.esp32-idf.yaml create mode 100644 tests/components/spi_device/test.esp32.yaml create mode 100644 tests/components/spi_device/test.esp8266.yaml create mode 100644 tests/components/spi_device/test.rp2040.yaml create mode 100644 tests/components/spi_led_strip/test.esp32-c3-idf.yaml create mode 100644 tests/components/spi_led_strip/test.esp32-c3.yaml create mode 100644 tests/components/spi_led_strip/test.esp32-idf.yaml create mode 100644 tests/components/spi_led_strip/test.esp32.yaml create mode 100644 tests/components/spi_led_strip/test.esp8266.yaml create mode 100644 tests/components/spi_led_strip/test.rp2040.yaml create mode 100644 tests/components/sprinkler/test.esp32-c3-idf.yaml create mode 100644 tests/components/sprinkler/test.esp32-c3.yaml create mode 100644 tests/components/sprinkler/test.esp32-idf.yaml create mode 100644 tests/components/sprinkler/test.esp32.yaml create mode 100644 tests/components/sprinkler/test.esp8266.yaml create mode 100644 tests/components/sprinkler/test.rp2040.yaml create mode 100644 tests/components/sps30/test.esp32-c3-idf.yaml create mode 100644 tests/components/sps30/test.esp32-c3.yaml create mode 100644 tests/components/sps30/test.esp32-idf.yaml create mode 100644 tests/components/sps30/test.esp32.yaml create mode 100644 tests/components/sps30/test.esp8266.yaml create mode 100644 tests/components/sps30/test.rp2040.yaml create mode 100644 tests/components/ssd1306_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1306_i2c/test.esp32-c3.yaml create mode 100644 tests/components/ssd1306_i2c/test.esp32-idf.yaml create mode 100644 tests/components/ssd1306_i2c/test.esp32.yaml create mode 100644 tests/components/ssd1306_i2c/test.esp8266.yaml create mode 100644 tests/components/ssd1306_i2c/test.rp2040.yaml create mode 100644 tests/components/ssd1306_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1306_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1306_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1306_spi/test.esp32.yaml create mode 100644 tests/components/ssd1306_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1306_spi/test.rp2040.yaml create mode 100644 tests/components/ssd1322_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1322_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1322_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1322_spi/test.esp32.yaml create mode 100644 tests/components/ssd1322_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1322_spi/test.rp2040.yaml create mode 100644 tests/components/ssd1325_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1325_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1325_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1325_spi/test.esp32.yaml create mode 100644 tests/components/ssd1325_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1325_spi/test.rp2040.yaml create mode 100644 tests/components/ssd1327_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1327_i2c/test.esp32-c3.yaml create mode 100644 tests/components/ssd1327_i2c/test.esp32-idf.yaml create mode 100644 tests/components/ssd1327_i2c/test.esp32.yaml create mode 100644 tests/components/ssd1327_i2c/test.esp8266.yaml create mode 100644 tests/components/ssd1327_i2c/test.rp2040.yaml create mode 100644 tests/components/ssd1327_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1327_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1327_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1327_spi/test.esp32.yaml create mode 100644 tests/components/ssd1327_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1327_spi/test.rp2040.yaml create mode 100644 tests/components/ssd1331_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1331_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1331_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1331_spi/test.esp32.yaml create mode 100644 tests/components/ssd1331_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1331_spi/test.rp2040.yaml create mode 100644 tests/components/ssd1351_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ssd1351_spi/test.esp32-c3.yaml create mode 100644 tests/components/ssd1351_spi/test.esp32-idf.yaml create mode 100644 tests/components/ssd1351_spi/test.esp32.yaml create mode 100644 tests/components/ssd1351_spi/test.esp8266.yaml create mode 100644 tests/components/ssd1351_spi/test.rp2040.yaml create mode 100644 tests/components/st7567_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/st7567_i2c/test.esp32-c3.yaml create mode 100644 tests/components/st7567_i2c/test.esp32-idf.yaml create mode 100644 tests/components/st7567_i2c/test.esp32.yaml create mode 100644 tests/components/st7567_i2c/test.esp8266.yaml create mode 100644 tests/components/st7567_i2c/test.rp2040.yaml create mode 100644 tests/components/st7567_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/st7567_spi/test.esp32-c3.yaml create mode 100644 tests/components/st7567_spi/test.esp32-idf.yaml create mode 100644 tests/components/st7567_spi/test.esp32.yaml create mode 100644 tests/components/st7567_spi/test.esp8266.yaml create mode 100644 tests/components/st7567_spi/test.rp2040.yaml create mode 100644 tests/components/st7735/test.esp32-c3-idf.yaml create mode 100644 tests/components/st7735/test.esp32-c3.yaml create mode 100644 tests/components/st7735/test.esp32-idf.yaml create mode 100644 tests/components/st7735/test.esp32.yaml create mode 100644 tests/components/st7735/test.esp8266.yaml create mode 100644 tests/components/st7735/test.rp2040.yaml create mode 100644 tests/components/st7789v/test.esp32-c3-idf.yaml create mode 100644 tests/components/st7789v/test.esp32-c3.yaml create mode 100644 tests/components/st7789v/test.esp32-idf.yaml create mode 100644 tests/components/st7789v/test.esp32.yaml create mode 100644 tests/components/st7789v/test.esp8266.yaml create mode 100644 tests/components/st7789v/test.rp2040.yaml create mode 100644 tests/components/st7920/test.esp32-c3-idf.yaml create mode 100644 tests/components/st7920/test.esp32-c3.yaml create mode 100644 tests/components/st7920/test.esp32-idf.yaml create mode 100644 tests/components/st7920/test.esp32.yaml create mode 100644 tests/components/st7920/test.esp8266.yaml create mode 100644 tests/components/st7920/test.rp2040.yaml create mode 100644 tests/components/status/test.esp32-c3-idf.yaml create mode 100644 tests/components/status/test.esp32-c3.yaml create mode 100644 tests/components/status/test.esp32-idf.yaml create mode 100644 tests/components/status/test.esp32.yaml create mode 100644 tests/components/status/test.esp8266.yaml create mode 100644 tests/components/status/test.rp2040.yaml create mode 100644 tests/components/status_led/test.esp32-c3-idf.yaml create mode 100644 tests/components/status_led/test.esp32-c3.yaml create mode 100644 tests/components/status_led/test.esp32-idf.yaml create mode 100644 tests/components/status_led/test.esp32.yaml create mode 100644 tests/components/status_led/test.esp8266.yaml create mode 100644 tests/components/status_led/test.rp2040.yaml create mode 100644 tests/components/stepper/test.esp32-c3-idf.yaml create mode 100644 tests/components/stepper/test.esp32-c3.yaml create mode 100644 tests/components/stepper/test.esp32-idf.yaml create mode 100644 tests/components/stepper/test.esp32.yaml create mode 100644 tests/components/stepper/test.esp8266.yaml create mode 100644 tests/components/stepper/test.rp2040.yaml create mode 100644 tests/components/sts3x/test.esp32-c3-idf.yaml create mode 100644 tests/components/sts3x/test.esp32-c3.yaml create mode 100644 tests/components/sts3x/test.esp32-idf.yaml create mode 100644 tests/components/sts3x/test.esp32.yaml create mode 100644 tests/components/sts3x/test.esp8266.yaml create mode 100644 tests/components/sts3x/test.rp2040.yaml create mode 100644 tests/components/sun/test.esp32-c3-idf.yaml create mode 100644 tests/components/sun/test.esp32-c3.yaml create mode 100644 tests/components/sun/test.esp32-idf.yaml create mode 100644 tests/components/sun/test.esp32.yaml create mode 100644 tests/components/sun/test.esp8266.yaml create mode 100644 tests/components/sun/test.rp2040.yaml create mode 100644 tests/components/sx1509/test.esp32-c3-idf.yaml create mode 100644 tests/components/sx1509/test.esp32-c3.yaml create mode 100644 tests/components/sx1509/test.esp32-idf.yaml create mode 100644 tests/components/sx1509/test.esp32.yaml create mode 100644 tests/components/sx1509/test.esp8266.yaml create mode 100644 tests/components/sx1509/test.rp2040.yaml diff --git a/tests/components/sn74hc165/test.esp32-c3-idf.yaml b/tests/components/sn74hc165/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f687b23c9d --- /dev/null +++ b/tests/components/sn74hc165/test.esp32-c3-idf.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 3 + data_pin: 4 + load_pin: 5 + clock_inhibit_pin: 6 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sn74hc165/test.esp32-c3.yaml b/tests/components/sn74hc165/test.esp32-c3.yaml new file mode 100644 index 0000000000..f687b23c9d --- /dev/null +++ b/tests/components/sn74hc165/test.esp32-c3.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 3 + data_pin: 4 + load_pin: 5 + clock_inhibit_pin: 6 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sn74hc165/test.esp32-idf.yaml b/tests/components/sn74hc165/test.esp32-idf.yaml new file mode 100644 index 0000000000..55b06aec9b --- /dev/null +++ b/tests/components/sn74hc165/test.esp32-idf.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 13 + data_pin: 14 + load_pin: 15 + clock_inhibit_pin: 16 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sn74hc165/test.esp32.yaml b/tests/components/sn74hc165/test.esp32.yaml new file mode 100644 index 0000000000..55b06aec9b --- /dev/null +++ b/tests/components/sn74hc165/test.esp32.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 13 + data_pin: 14 + load_pin: 15 + clock_inhibit_pin: 16 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sn74hc165/test.esp8266.yaml b/tests/components/sn74hc165/test.esp8266.yaml new file mode 100644 index 0000000000..55b06aec9b --- /dev/null +++ b/tests/components/sn74hc165/test.esp8266.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 13 + data_pin: 14 + load_pin: 15 + clock_inhibit_pin: 16 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sn74hc165/test.rp2040.yaml b/tests/components/sn74hc165/test.rp2040.yaml new file mode 100644 index 0000000000..f687b23c9d --- /dev/null +++ b/tests/components/sn74hc165/test.rp2040.yaml @@ -0,0 +1,14 @@ +sn74hc165: + id: sn74hc165_hub + clock_pin: 3 + data_pin: 4 + load_pin: 5 + clock_inhibit_pin: 6 + sr_count: 2 + +binary_sensor: + - platform: gpio + id: sn74hc165_pin_0 + pin: + sn74hc165: sn74hc165_hub + number: 0 diff --git a/tests/components/sntp/test.esp32-c3-idf.yaml b/tests/components/sntp/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.esp32-c3.yaml b/tests/components/sntp/test.esp32-c3.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.esp32-idf.yaml b/tests/components/sntp/test.esp32-idf.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.esp32.yaml b/tests/components/sntp/test.esp32.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.esp32.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.esp8266.yaml b/tests/components/sntp/test.esp8266.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.esp8266.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.rp2040.yaml b/tests/components/sntp/test.rp2040.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/test.rp2040.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sonoff_d1/test.esp32-idf.yaml b/tests/components/sonoff_d1/test.esp32-idf.yaml new file mode 100644 index 0000000000..dc35e3b6ac --- /dev/null +++ b/tests/components/sonoff_d1/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_sonoff_d1 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +light: + - platform: sonoff_d1 + id: d1_light + name: Sonoff D1 Dimmer + restore_mode: RESTORE_DEFAULT_OFF + use_rm433_remote: false diff --git a/tests/components/sonoff_d1/test.esp32.yaml b/tests/components/sonoff_d1/test.esp32.yaml new file mode 100644 index 0000000000..dc35e3b6ac --- /dev/null +++ b/tests/components/sonoff_d1/test.esp32.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_sonoff_d1 + tx_pin: 17 + rx_pin: 16 + baud_rate: 9600 + +light: + - platform: sonoff_d1 + id: d1_light + name: Sonoff D1 Dimmer + restore_mode: RESTORE_DEFAULT_OFF + use_rm433_remote: false diff --git a/tests/components/sonoff_d1/test.esp8266.yaml b/tests/components/sonoff_d1/test.esp8266.yaml new file mode 100644 index 0000000000..c4a62f4cb3 --- /dev/null +++ b/tests/components/sonoff_d1/test.esp8266.yaml @@ -0,0 +1,12 @@ +uart: + - id: uart_sonoff_d1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +light: + - platform: sonoff_d1 + id: d1_light + name: Sonoff D1 Dimmer + restore_mode: RESTORE_DEFAULT_OFF + use_rm433_remote: false diff --git a/tests/components/speaker/test.esp32-c3-idf.yaml b/tests/components/speaker/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c7809baace --- /dev/null +++ b/tests/components/speaker/test.esp32-c3-idf.yaml @@ -0,0 +1,17 @@ +esphome: + on_boot: + then: + - speaker.play: [0, 1, 2, 3] + - speaker.stop + +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 5 + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 3 + mode: mono diff --git a/tests/components/speaker/test.esp32-c3.yaml b/tests/components/speaker/test.esp32-c3.yaml new file mode 100644 index 0000000000..c7809baace --- /dev/null +++ b/tests/components/speaker/test.esp32-c3.yaml @@ -0,0 +1,17 @@ +esphome: + on_boot: + then: + - speaker.play: [0, 1, 2, 3] + - speaker.stop + +i2s_audio: + i2s_lrclk_pin: 6 + i2s_bclk_pin: 7 + i2s_mclk_pin: 5 + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 3 + mode: mono diff --git a/tests/components/speaker/test.esp32-idf.yaml b/tests/components/speaker/test.esp32-idf.yaml new file mode 100644 index 0000000000..416e203d7b --- /dev/null +++ b/tests/components/speaker/test.esp32-idf.yaml @@ -0,0 +1,17 @@ +esphome: + on_boot: + then: + - speaker.play: [0, 1, 2, 3] + - speaker.stop + +i2s_audio: + i2s_lrclk_pin: 16 + i2s_bclk_pin: 17 + i2s_mclk_pin: 15 + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 13 + mode: mono diff --git a/tests/components/speaker/test.esp32.yaml b/tests/components/speaker/test.esp32.yaml new file mode 100644 index 0000000000..416e203d7b --- /dev/null +++ b/tests/components/speaker/test.esp32.yaml @@ -0,0 +1,17 @@ +esphome: + on_boot: + then: + - speaker.play: [0, 1, 2, 3] + - speaker.stop + +i2s_audio: + i2s_lrclk_pin: 16 + i2s_bclk_pin: 17 + i2s_mclk_pin: 15 + +speaker: + - platform: i2s_audio + id: speaker_id + dac_type: external + i2s_dout_pin: 13 + mode: mono diff --git a/tests/components/speed/test.esp32-c3-idf.yaml b/tests/components/speed/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fa1920676e --- /dev/null +++ b/tests/components/speed/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +output: + - platform: ledc + id: fan_output_1 + pin: 2 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/speed/test.esp32-c3.yaml b/tests/components/speed/test.esp32-c3.yaml new file mode 100644 index 0000000000..fa1920676e --- /dev/null +++ b/tests/components/speed/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +output: + - platform: ledc + id: fan_output_1 + pin: 2 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/speed/test.esp32-idf.yaml b/tests/components/speed/test.esp32-idf.yaml new file mode 100644 index 0000000000..29a55e9edd --- /dev/null +++ b/tests/components/speed/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +output: + - platform: ledc + id: fan_output_1 + pin: 12 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/speed/test.esp32.yaml b/tests/components/speed/test.esp32.yaml new file mode 100644 index 0000000000..29a55e9edd --- /dev/null +++ b/tests/components/speed/test.esp32.yaml @@ -0,0 +1,9 @@ +output: + - platform: ledc + id: fan_output_1 + pin: 12 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/speed/test.esp8266.yaml b/tests/components/speed/test.esp8266.yaml new file mode 100644 index 0000000000..6ed9949cf5 --- /dev/null +++ b/tests/components/speed/test.esp8266.yaml @@ -0,0 +1,9 @@ +output: + - platform: esp8266_pwm + id: fan_output_1 + pin: 12 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/speed/test.rp2040.yaml b/tests/components/speed/test.rp2040.yaml new file mode 100644 index 0000000000..02b572db75 --- /dev/null +++ b/tests/components/speed/test.rp2040.yaml @@ -0,0 +1,9 @@ +output: + - platform: rp2040_pwm + id: fan_output_1 + pin: 12 + +fan: + - platform: speed + id: fan_speed + output: fan_output_1 diff --git a/tests/components/spi/test.esp32-c3-idf.yaml b/tests/components/spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f49470ad07 --- /dev/null +++ b/tests/components/spi/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 diff --git a/tests/components/spi/test.esp32-c3.yaml b/tests/components/spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..f49470ad07 --- /dev/null +++ b/tests/components/spi/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 diff --git a/tests/components/spi/test.esp32-idf.yaml b/tests/components/spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..1cdcf461dd --- /dev/null +++ b/tests/components/spi/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 diff --git a/tests/components/spi/test.esp32.yaml b/tests/components/spi/test.esp32.yaml new file mode 100644 index 0000000000..1cdcf461dd --- /dev/null +++ b/tests/components/spi/test.esp32.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 diff --git a/tests/components/spi/test.esp8266.yaml b/tests/components/spi/test.esp8266.yaml new file mode 100644 index 0000000000..83f110921f --- /dev/null +++ b/tests/components/spi/test.esp8266.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 diff --git a/tests/components/spi/test.rp2040.yaml b/tests/components/spi/test.rp2040.yaml new file mode 100644 index 0000000000..1e39d247fe --- /dev/null +++ b/tests/components/spi/test.rp2040.yaml @@ -0,0 +1,5 @@ +spi: + - id: spi_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 diff --git a/tests/components/spi_device/test.esp32-c3-idf.yaml b/tests/components/spi_device/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..49e2733676 --- /dev/null +++ b/tests/components/spi_device/test.esp32-c3-idf.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32-c3.yaml b/tests/components/spi_device/test.esp32-c3.yaml new file mode 100644 index 0000000000..49e2733676 --- /dev/null +++ b/tests/components/spi_device/test.esp32-c3.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32-idf.yaml b/tests/components/spi_device/test.esp32-idf.yaml new file mode 100644 index 0000000000..cad8ca49f8 --- /dev/null +++ b/tests/components/spi_device/test.esp32-idf.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32.yaml b/tests/components/spi_device/test.esp32.yaml new file mode 100644 index 0000000000..cad8ca49f8 --- /dev/null +++ b/tests/components/spi_device/test.esp32.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp8266.yaml b/tests/components/spi_device/test.esp8266.yaml new file mode 100644 index 0000000000..1b191bdb6a --- /dev/null +++ b/tests/components/spi_device/test.esp8266.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_device/test.rp2040.yaml b/tests/components/spi_device/test.rp2040.yaml new file mode 100644 index 0000000000..c70493c70d --- /dev/null +++ b/tests/components/spi_device/test.rp2040.yaml @@ -0,0 +1,11 @@ +spi: + - id: spi_device1 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +spi_device: + id: spi_device_test + data_rate: 2MHz + mode: 3 + bit_order: lsb_first diff --git a/tests/components/spi_led_strip/test.esp32-c3-idf.yaml b/tests/components/spi_led_strip/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..983ad2863f --- /dev/null +++ b/tests/components/spi_led_strip/test.esp32-c3-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/spi_led_strip/test.esp32-c3.yaml b/tests/components/spi_led_strip/test.esp32-c3.yaml new file mode 100644 index 0000000000..983ad2863f --- /dev/null +++ b/tests/components/spi_led_strip/test.esp32-c3.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/spi_led_strip/test.esp32-idf.yaml b/tests/components/spi_led_strip/test.esp32-idf.yaml new file mode 100644 index 0000000000..f4a760bf4c --- /dev/null +++ b/tests/components/spi_led_strip/test.esp32-idf.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/spi_led_strip/test.esp32.yaml b/tests/components/spi_led_strip/test.esp32.yaml new file mode 100644 index 0000000000..f4a760bf4c --- /dev/null +++ b/tests/components/spi_led_strip/test.esp32.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/spi_led_strip/test.esp8266.yaml b/tests/components/spi_led_strip/test.esp8266.yaml new file mode 100644 index 0000000000..8e76303b6a --- /dev/null +++ b/tests/components/spi_led_strip/test.esp8266.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/spi_led_strip/test.rp2040.yaml b/tests/components/spi_led_strip/test.rp2040.yaml new file mode 100644 index 0000000000..9d12f1592b --- /dev/null +++ b/tests/components/spi_led_strip/test.rp2040.yaml @@ -0,0 +1,13 @@ +spi: + - id: spi_spi_led_strip + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +light: + - platform: spi_led_strip + num_leds: 4 + color_correct: [80%, 60%, 100%] + id: rgb_led + name: "RGB LED" + data_rate: 8MHz diff --git a/tests/components/sprinkler/test.esp32-c3-idf.yaml b/tests/components/sprinkler/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.esp32-c3-idf.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.esp32-c3.yaml b/tests/components/sprinkler/test.esp32-c3.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.esp32-c3.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.esp32-idf.yaml b/tests/components/sprinkler/test.esp32-idf.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.esp32-idf.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.esp32.yaml b/tests/components/sprinkler/test.esp32.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.esp32.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.esp8266.yaml b/tests/components/sprinkler/test.esp8266.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.esp8266.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.rp2040.yaml b/tests/components/sprinkler/test.rp2040.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/test.rp2040.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sps30/test.esp32-c3-idf.yaml b/tests/components/sps30/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e071a00936 --- /dev/null +++ b/tests/components/sps30/test.esp32-c3-idf.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 5 + sda: 4 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/sps30/test.esp32-c3.yaml b/tests/components/sps30/test.esp32-c3.yaml new file mode 100644 index 0000000000..e071a00936 --- /dev/null +++ b/tests/components/sps30/test.esp32-c3.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 5 + sda: 4 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/sps30/test.esp32-idf.yaml b/tests/components/sps30/test.esp32-idf.yaml new file mode 100644 index 0000000000..f9d1ee4e55 --- /dev/null +++ b/tests/components/sps30/test.esp32-idf.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 16 + sda: 17 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/sps30/test.esp32.yaml b/tests/components/sps30/test.esp32.yaml new file mode 100644 index 0000000000..f9d1ee4e55 --- /dev/null +++ b/tests/components/sps30/test.esp32.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 16 + sda: 17 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/sps30/test.esp8266.yaml b/tests/components/sps30/test.esp8266.yaml new file mode 100644 index 0000000000..e071a00936 --- /dev/null +++ b/tests/components/sps30/test.esp8266.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 5 + sda: 4 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/sps30/test.rp2040.yaml b/tests/components/sps30/test.rp2040.yaml new file mode 100644 index 0000000000..e071a00936 --- /dev/null +++ b/tests/components/sps30/test.rp2040.yaml @@ -0,0 +1,36 @@ +i2c: + - id: i2c_sps30 + scl: 5 + sda: 4 + +sensor: + - platform: sps30 + pm_1_0: + name: Workshop PM <1µm Weight concentration + id: workshop_PM_1_0 + pm_2_5: + name: Workshop PM <2.5µm Weight concentration + id: workshop_PM_2_5 + pm_4_0: + name: Workshop PM <4µm Weight concentration + id: workshop_PM_4_0 + pm_10_0: + name: Workshop PM <10µm Weight concentration + id: workshop_PM_10_0 + pmc_0_5: + name: Workshop PM <0.5µm Number concentration + id: workshop_PMC_0_5 + pmc_1_0: + name: Workshop PM <1µm Number concentration + id: workshop_PMC_1_0 + pmc_2_5: + name: Workshop PM <2.5µm Number concentration + id: workshop_PMC_2_5 + pmc_4_0: + name: Workshop PM <4µm Number concentration + id: workshop_PMC_4_0 + pmc_10_0: + name: Workshop PM <10µm Number concentration + id: workshop_PMC_10_0 + address: 0x69 + update_interval: 10s diff --git a/tests/components/ssd1306_i2c/test.esp32-c3-idf.yaml b/tests/components/ssd1306_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..f4a301db51 --- /dev/null +++ b/tests/components/ssd1306_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_i2c/test.esp32-c3.yaml b/tests/components/ssd1306_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..f4a301db51 --- /dev/null +++ b/tests/components/ssd1306_i2c/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_i2c/test.esp32-idf.yaml b/tests/components/ssd1306_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..dddc67309c --- /dev/null +++ b/tests/components/ssd1306_i2c/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_i2c/test.esp32.yaml b/tests/components/ssd1306_i2c/test.esp32.yaml new file mode 100644 index 0000000000..dddc67309c --- /dev/null +++ b/tests/components/ssd1306_i2c/test.esp32.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 16 + sda: 17 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_i2c/test.esp8266.yaml b/tests/components/ssd1306_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..f4a301db51 --- /dev/null +++ b/tests/components/ssd1306_i2c/test.esp8266.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_i2c/test.rp2040.yaml b/tests/components/ssd1306_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..f4a301db51 --- /dev/null +++ b/tests/components/ssd1306_i2c/test.rp2040.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_ssd1306_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + model: SSD1306_128X64 + reset_pin: 3 + address: 0x3C + id: display1 + contrast: 60% + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1306_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..01b2d0e4a8 --- /dev/null +++ b/tests/components/ssd1306_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.esp32-c3.yaml b/tests/components/ssd1306_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..01b2d0e4a8 --- /dev/null +++ b/tests/components/ssd1306_spi/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.esp32-idf.yaml b/tests/components/ssd1306_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..b0e5e0f1a2 --- /dev/null +++ b/tests/components/ssd1306_spi/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.esp32.yaml b/tests/components/ssd1306_spi/test.esp32.yaml new file mode 100644 index 0000000000..b0e5e0f1a2 --- /dev/null +++ b/tests/components/ssd1306_spi/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.esp8266.yaml b/tests/components/ssd1306_spi/test.esp8266.yaml new file mode 100644 index 0000000000..135e364bb2 --- /dev/null +++ b/tests/components/ssd1306_spi/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1306_spi/test.rp2040.yaml b/tests/components/ssd1306_spi/test.rp2040.yaml new file mode 100644 index 0000000000..94c4b85158 --- /dev/null +++ b/tests/components/ssd1306_spi/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1306_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1306_spi + model: SSD1306 128x64 + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1322_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4fa9f86594 --- /dev/null +++ b/tests/components/ssd1322_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.esp32-c3.yaml b/tests/components/ssd1322_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..4fa9f86594 --- /dev/null +++ b/tests/components/ssd1322_spi/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.esp32-idf.yaml b/tests/components/ssd1322_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..aa6d0fbf01 --- /dev/null +++ b/tests/components/ssd1322_spi/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.esp32.yaml b/tests/components/ssd1322_spi/test.esp32.yaml new file mode 100644 index 0000000000..aa6d0fbf01 --- /dev/null +++ b/tests/components/ssd1322_spi/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.esp8266.yaml b/tests/components/ssd1322_spi/test.esp8266.yaml new file mode 100644 index 0000000000..a5aa565c09 --- /dev/null +++ b/tests/components/ssd1322_spi/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1322_spi/test.rp2040.yaml b/tests/components/ssd1322_spi/test.rp2040.yaml new file mode 100644 index 0000000000..59544e7878 --- /dev/null +++ b/tests/components/ssd1322_spi/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1322_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1322_spi + model: SSD1322 256x64 + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1325_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..0fa8cb6488 --- /dev/null +++ b/tests/components/ssd1325_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.esp32-c3.yaml b/tests/components/ssd1325_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..0fa8cb6488 --- /dev/null +++ b/tests/components/ssd1325_spi/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.esp32-idf.yaml b/tests/components/ssd1325_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..84d94eff28 --- /dev/null +++ b/tests/components/ssd1325_spi/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.esp32.yaml b/tests/components/ssd1325_spi/test.esp32.yaml new file mode 100644 index 0000000000..84d94eff28 --- /dev/null +++ b/tests/components/ssd1325_spi/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.esp8266.yaml b/tests/components/ssd1325_spi/test.esp8266.yaml new file mode 100644 index 0000000000..9d7e483585 --- /dev/null +++ b/tests/components/ssd1325_spi/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1325_spi/test.rp2040.yaml b/tests/components/ssd1325_spi/test.rp2040.yaml new file mode 100644 index 0000000000..869663c19d --- /dev/null +++ b/tests/components/ssd1325_spi/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1325_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1325_spi + model: SSD1325 128x64 + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.esp32-c3-idf.yaml b/tests/components/ssd1327_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..cd28795ff1 --- /dev/null +++ b/tests/components/ssd1327_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.esp32-c3.yaml b/tests/components/ssd1327_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..cd28795ff1 --- /dev/null +++ b/tests/components/ssd1327_i2c/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.esp32-idf.yaml b/tests/components/ssd1327_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..e72a9c7b7a --- /dev/null +++ b/tests/components/ssd1327_i2c/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 16 + sda: 17 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.esp32.yaml b/tests/components/ssd1327_i2c/test.esp32.yaml new file mode 100644 index 0000000000..e72a9c7b7a --- /dev/null +++ b/tests/components/ssd1327_i2c/test.esp32.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 16 + sda: 17 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.esp8266.yaml b/tests/components/ssd1327_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..cd28795ff1 --- /dev/null +++ b/tests/components/ssd1327_i2c/test.esp8266.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_i2c/test.rp2040.yaml b/tests/components/ssd1327_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..cd28795ff1 --- /dev/null +++ b/tests/components/ssd1327_i2c/test.rp2040.yaml @@ -0,0 +1,24 @@ +i2c: + - id: i2c_ssd1327_i2c + scl: 5 + sda: 4 + +display: + - platform: ssd1327_i2c + model: SSD1327_128x128 + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1327_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ec5795d716 --- /dev/null +++ b/tests/components/ssd1327_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.esp32-c3.yaml b/tests/components/ssd1327_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..ec5795d716 --- /dev/null +++ b/tests/components/ssd1327_spi/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.esp32-idf.yaml b/tests/components/ssd1327_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..e103ded187 --- /dev/null +++ b/tests/components/ssd1327_spi/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.esp32.yaml b/tests/components/ssd1327_spi/test.esp32.yaml new file mode 100644 index 0000000000..e103ded187 --- /dev/null +++ b/tests/components/ssd1327_spi/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.esp8266.yaml b/tests/components/ssd1327_spi/test.esp8266.yaml new file mode 100644 index 0000000000..30455d24ee --- /dev/null +++ b/tests/components/ssd1327_spi/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1327_spi/test.rp2040.yaml b/tests/components/ssd1327_spi/test.rp2040.yaml new file mode 100644 index 0000000000..f819ab2c41 --- /dev/null +++ b/tests/components/ssd1327_spi/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1327_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1327_spi + model: SSD1327 128x128 + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1331_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9a35918faf --- /dev/null +++ b/tests/components/ssd1331_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1331_spi + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.esp32-c3.yaml b/tests/components/ssd1331_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..9a35918faf --- /dev/null +++ b/tests/components/ssd1331_spi/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1331_spi + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.esp32-idf.yaml b/tests/components/ssd1331_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..e9eb8ea9ad --- /dev/null +++ b/tests/components/ssd1331_spi/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1331_spi + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.esp32.yaml b/tests/components/ssd1331_spi/test.esp32.yaml new file mode 100644 index 0000000000..e9eb8ea9ad --- /dev/null +++ b/tests/components/ssd1331_spi/test.esp32.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1331_spi + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.esp8266.yaml b/tests/components/ssd1331_spi/test.esp8266.yaml new file mode 100644 index 0000000000..3b319ef38e --- /dev/null +++ b/tests/components/ssd1331_spi/test.esp8266.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1331_spi + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1331_spi/test.rp2040.yaml b/tests/components/ssd1331_spi/test.rp2040.yaml new file mode 100644 index 0000000000..947685b07a --- /dev/null +++ b/tests/components/ssd1331_spi/test.rp2040.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_ssd1331_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1331_spi + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.esp32-c3-idf.yaml b/tests/components/ssd1351_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2a7266f502 --- /dev/null +++ b/tests/components/ssd1351_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.esp32-c3.yaml b/tests/components/ssd1351_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..2a7266f502 --- /dev/null +++ b/tests/components/ssd1351_spi/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.esp32-idf.yaml b/tests/components/ssd1351_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..8342cb972b --- /dev/null +++ b/tests/components/ssd1351_spi/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.esp32.yaml b/tests/components/ssd1351_spi/test.esp32.yaml new file mode 100644 index 0000000000..8342cb972b --- /dev/null +++ b/tests/components/ssd1351_spi/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.esp8266.yaml b/tests/components/ssd1351_spi/test.esp8266.yaml new file mode 100644 index 0000000000..7ed9a31dde --- /dev/null +++ b/tests/components/ssd1351_spi/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/ssd1351_spi/test.rp2040.yaml b/tests/components/ssd1351_spi/test.rp2040.yaml new file mode 100644 index 0000000000..72936d046b --- /dev/null +++ b/tests/components/ssd1351_spi/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_ssd1351_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: ssd1351_spi + model: "SSD1351 128x128" + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.esp32-c3-idf.yaml b/tests/components/st7567_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d779040500 --- /dev/null +++ b/tests/components/st7567_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 5 + sda: 4 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.esp32-c3.yaml b/tests/components/st7567_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..d779040500 --- /dev/null +++ b/tests/components/st7567_i2c/test.esp32-c3.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 5 + sda: 4 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.esp32-idf.yaml b/tests/components/st7567_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..b7aee61b68 --- /dev/null +++ b/tests/components/st7567_i2c/test.esp32-idf.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 16 + sda: 17 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.esp32.yaml b/tests/components/st7567_i2c/test.esp32.yaml new file mode 100644 index 0000000000..b7aee61b68 --- /dev/null +++ b/tests/components/st7567_i2c/test.esp32.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 16 + sda: 17 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.esp8266.yaml b/tests/components/st7567_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..d779040500 --- /dev/null +++ b/tests/components/st7567_i2c/test.esp8266.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 5 + sda: 4 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_i2c/test.rp2040.yaml b/tests/components/st7567_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..d779040500 --- /dev/null +++ b/tests/components/st7567_i2c/test.rp2040.yaml @@ -0,0 +1,23 @@ +i2c: + - id: i2c_st7567_i2c + scl: 5 + sda: 4 + +display: + - platform: st7567_i2c + reset_pin: 3 + address: 0x3C + id: display1 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, 10, 10); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.esp32-c3-idf.yaml b/tests/components/st7567_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..b799ce7302 --- /dev/null +++ b/tests/components/st7567_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7567_spi + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.esp32-c3.yaml b/tests/components/st7567_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..b799ce7302 --- /dev/null +++ b/tests/components/st7567_spi/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7567_spi + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.esp32-idf.yaml b/tests/components/st7567_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..bb4530248f --- /dev/null +++ b/tests/components/st7567_spi/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7567_spi + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.esp32.yaml b/tests/components/st7567_spi/test.esp32.yaml new file mode 100644 index 0000000000..bb4530248f --- /dev/null +++ b/tests/components/st7567_spi/test.esp32.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7567_spi + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.esp8266.yaml b/tests/components/st7567_spi/test.esp8266.yaml new file mode 100644 index 0000000000..bbc47e67f6 --- /dev/null +++ b/tests/components/st7567_spi/test.esp8266.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: st7567_spi + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7567_spi/test.rp2040.yaml b/tests/components/st7567_spi/test.rp2040.yaml new file mode 100644 index 0000000000..1b491101a8 --- /dev/null +++ b/tests/components/st7567_spi/test.rp2040.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7567_spi + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: st7567_spi + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.esp32-c3-idf.yaml b/tests/components/st7735/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fc6c2421c4 --- /dev/null +++ b/tests/components/st7735/test.esp32-c3-idf.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.esp32-c3.yaml b/tests/components/st7735/test.esp32-c3.yaml new file mode 100644 index 0000000000..fc6c2421c4 --- /dev/null +++ b/tests/components/st7735/test.esp32-c3.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 2 + dc_pin: 3 + reset_pin: 4 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.esp32-idf.yaml b/tests/components/st7735/test.esp32-idf.yaml new file mode 100644 index 0000000000..fd3f6cade6 --- /dev/null +++ b/tests/components/st7735/test.esp32-idf.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.esp32.yaml b/tests/components/st7735/test.esp32.yaml new file mode 100644 index 0000000000..fd3f6cade6 --- /dev/null +++ b/tests/components/st7735/test.esp32.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.esp8266.yaml b/tests/components/st7735/test.esp8266.yaml new file mode 100644 index 0000000000..ea8fa93c36 --- /dev/null +++ b/tests/components/st7735/test.esp8266.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7735/test.rp2040.yaml b/tests/components/st7735/test.rp2040.yaml new file mode 100644 index 0000000000..828f9a3ae1 --- /dev/null +++ b/tests/components/st7735/test.rp2040.yaml @@ -0,0 +1,29 @@ +spi: + - id: spi_st7735 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: st7735 + model: "INITR_18BLACKTAB" + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + device_width: 128 + device_height: 160 + col_start: 0 + row_start: 0 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.esp32-c3-idf.yaml b/tests/components/st7789v/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..1cb8d22fcb --- /dev/null +++ b/tests/components/st7789v/test.esp32-c3-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 2 + dc_pin: 3 + reset_pin: 8 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.esp32-c3.yaml b/tests/components/st7789v/test.esp32-c3.yaml new file mode 100644 index 0000000000..1cb8d22fcb --- /dev/null +++ b/tests/components/st7789v/test.esp32-c3.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 2 + dc_pin: 3 + reset_pin: 8 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.esp32-idf.yaml b/tests/components/st7789v/test.esp32-idf.yaml new file mode 100644 index 0000000000..54a9db6da1 --- /dev/null +++ b/tests/components/st7789v/test.esp32-idf.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.esp32.yaml b/tests/components/st7789v/test.esp32.yaml new file mode 100644 index 0000000000..54a9db6da1 --- /dev/null +++ b/tests/components/st7789v/test.esp32.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 12 + dc_pin: 13 + reset_pin: 14 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.esp8266.yaml b/tests/components/st7789v/test.esp8266.yaml new file mode 100644 index 0000000000..deeceb8c9a --- /dev/null +++ b/tests/components/st7789v/test.esp8266.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 15 + dc_pin: 16 + reset_pin: 5 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7789v/test.rp2040.yaml b/tests/components/st7789v/test.rp2040.yaml new file mode 100644 index 0000000000..778aa2aa55 --- /dev/null +++ b/tests/components/st7789v/test.rp2040.yaml @@ -0,0 +1,25 @@ +spi: + - id: spi_st7789v + clk_pin: 2 + mosi_pin: 3 + miso_pin: 8 + +display: + - platform: st7789v + model: TTGO TDisplay 135x240 + cs_pin: 5 + dc_pin: 6 + reset_pin: 7 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.esp32-c3-idf.yaml b/tests/components/st7920/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..84ae88461f --- /dev/null +++ b/tests/components/st7920/test.esp32-c3-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7920 + cs_pin: 2 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.esp32-c3.yaml b/tests/components/st7920/test.esp32-c3.yaml new file mode 100644 index 0000000000..84ae88461f --- /dev/null +++ b/tests/components/st7920/test.esp32-c3.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 6 + mosi_pin: 7 + miso_pin: 5 + +display: + - platform: st7920 + cs_pin: 2 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.esp32-idf.yaml b/tests/components/st7920/test.esp32-idf.yaml new file mode 100644 index 0000000000..cdcbc85642 --- /dev/null +++ b/tests/components/st7920/test.esp32-idf.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7920 + cs_pin: 12 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.esp32.yaml b/tests/components/st7920/test.esp32.yaml new file mode 100644 index 0000000000..cdcbc85642 --- /dev/null +++ b/tests/components/st7920/test.esp32.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: st7920 + cs_pin: 12 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.esp8266.yaml b/tests/components/st7920/test.esp8266.yaml new file mode 100644 index 0000000000..0450bf1c5e --- /dev/null +++ b/tests/components/st7920/test.esp8266.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: st7920 + cs_pin: 15 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/st7920/test.rp2040.yaml b/tests/components/st7920/test.rp2040.yaml new file mode 100644 index 0000000000..f442820e7b --- /dev/null +++ b/tests/components/st7920/test.rp2040.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_st7920 + clk_pin: 2 + mosi_pin: 3 + miso_pin: 4 + +display: + - platform: st7920 + cs_pin: 5 + height: 128 + width: 64 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + - id: page2 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); diff --git a/tests/components/status/test.esp32-c3-idf.yaml b/tests/components/status/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.esp32-c3.yaml b/tests/components/status/test.esp32-c3.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.esp32-idf.yaml b/tests/components/status/test.esp32-idf.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.esp32.yaml b/tests/components/status/test.esp32.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.esp32.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.esp8266.yaml b/tests/components/status/test.esp8266.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.esp8266.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.rp2040.yaml b/tests/components/status/test.rp2040.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/test.rp2040.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status_led/test.esp32-c3-idf.yaml b/tests/components/status_led/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.esp32-c3.yaml b/tests/components/status_led/test.esp32-c3.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.esp32-idf.yaml b/tests/components/status_led/test.esp32-idf.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.esp32.yaml b/tests/components/status_led/test.esp32.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.esp32.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.esp8266.yaml b/tests/components/status_led/test.esp8266.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.esp8266.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.rp2040.yaml b/tests/components/status_led/test.rp2040.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/test.rp2040.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/stepper/test.esp32-c3-idf.yaml b/tests/components/stepper/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.esp32-c3.yaml b/tests/components/stepper/test.esp32-c3.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.esp32-c3.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.esp32-idf.yaml b/tests/components/stepper/test.esp32-idf.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.esp32.yaml b/tests/components/stepper/test.esp32.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.esp32.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.esp8266.yaml b/tests/components/stepper/test.esp8266.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.esp8266.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.rp2040.yaml b/tests/components/stepper/test.rp2040.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/test.rp2040.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/sts3x/test.esp32-c3-idf.yaml b/tests/components/sts3x/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..87980ce3a7 --- /dev/null +++ b/tests/components/sts3x/test.esp32-c3-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 5 + sda: 4 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sts3x/test.esp32-c3.yaml b/tests/components/sts3x/test.esp32-c3.yaml new file mode 100644 index 0000000000..87980ce3a7 --- /dev/null +++ b/tests/components/sts3x/test.esp32-c3.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 5 + sda: 4 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sts3x/test.esp32-idf.yaml b/tests/components/sts3x/test.esp32-idf.yaml new file mode 100644 index 0000000000..a74d61e748 --- /dev/null +++ b/tests/components/sts3x/test.esp32-idf.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 16 + sda: 17 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sts3x/test.esp32.yaml b/tests/components/sts3x/test.esp32.yaml new file mode 100644 index 0000000000..a74d61e748 --- /dev/null +++ b/tests/components/sts3x/test.esp32.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 16 + sda: 17 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sts3x/test.esp8266.yaml b/tests/components/sts3x/test.esp8266.yaml new file mode 100644 index 0000000000..87980ce3a7 --- /dev/null +++ b/tests/components/sts3x/test.esp8266.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 5 + sda: 4 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sts3x/test.rp2040.yaml b/tests/components/sts3x/test.rp2040.yaml new file mode 100644 index 0000000000..87980ce3a7 --- /dev/null +++ b/tests/components/sts3x/test.rp2040.yaml @@ -0,0 +1,10 @@ +i2c: + - id: i2c_sts3x + scl: 5 + sda: 4 + +sensor: + - platform: sts3x + id: sts3x_sensor + name: STS3X Temperature + address: 0x4A diff --git a/tests/components/sun/test.esp32-c3-idf.yaml b/tests/components/sun/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.esp32-c3-idf.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.esp32-c3.yaml b/tests/components/sun/test.esp32-c3.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.esp32-c3.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.esp32-idf.yaml b/tests/components/sun/test.esp32-idf.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.esp32-idf.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.esp32.yaml b/tests/components/sun/test.esp32.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.esp32.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.esp8266.yaml b/tests/components/sun/test.esp8266.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.esp8266.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.rp2040.yaml b/tests/components/sun/test.rp2040.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/test.rp2040.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sx1509/test.esp32-c3-idf.yaml b/tests/components/sx1509/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ced849b3df --- /dev/null +++ b/tests/components/sx1509/test.esp32-c3-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 5 + sda: 4 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 diff --git a/tests/components/sx1509/test.esp32-c3.yaml b/tests/components/sx1509/test.esp32-c3.yaml new file mode 100644 index 0000000000..ced849b3df --- /dev/null +++ b/tests/components/sx1509/test.esp32-c3.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 5 + sda: 4 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 diff --git a/tests/components/sx1509/test.esp32-idf.yaml b/tests/components/sx1509/test.esp32-idf.yaml new file mode 100644 index 0000000000..1698f2abc4 --- /dev/null +++ b/tests/components/sx1509/test.esp32-idf.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 16 + sda: 17 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 diff --git a/tests/components/sx1509/test.esp32.yaml b/tests/components/sx1509/test.esp32.yaml new file mode 100644 index 0000000000..1698f2abc4 --- /dev/null +++ b/tests/components/sx1509/test.esp32.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 16 + sda: 17 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 diff --git a/tests/components/sx1509/test.esp8266.yaml b/tests/components/sx1509/test.esp8266.yaml new file mode 100644 index 0000000000..ced849b3df --- /dev/null +++ b/tests/components/sx1509/test.esp8266.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 5 + sda: 4 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 diff --git a/tests/components/sx1509/test.rp2040.yaml b/tests/components/sx1509/test.rp2040.yaml new file mode 100644 index 0000000000..ced849b3df --- /dev/null +++ b/tests/components/sx1509/test.rp2040.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_sx1509 + scl: 5 + sda: 4 + +sx1509: + - id: sx1509_hub + address: 0x3E + +binary_sensor: + - platform: gpio + name: GPIO SX1509 Test + pin: + sx1509: sx1509_hub + number: 3 From 8027921ba3c226fd489dd8f12ccbe8f3f6f2aa80 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 24 Apr 2024 05:55:27 +1000 Subject: [PATCH 1614/2607] `graphical_display_menu` requires a Display, not DisplayBuffer (#6614) --- esphome/components/graphical_display_menu/__init__.py | 2 +- .../graphical_display_menu/graphical_display_menu.cpp | 3 ++- esphome/core/color.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index dc49358efd..3849449523 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -38,7 +38,7 @@ CONFIG_SCHEMA = DISPLAY_MENU_BASE_SCHEMA.extend( cv.Schema( { cv.GenerateID(): cv.declare_id(GraphicalDisplayMenu), - cv.Optional(CONF_DISPLAY): cv.use_id(display.DisplayBuffer), + cv.Optional(CONF_DISPLAY): cv.use_id(display.Display), cv.Required(CONF_FONT): cv.use_id(font.Font), cv.Optional(CONF_MENU_ITEM_VALUE): cv.templatable(cv.string), cv.Optional(CONF_FOREGROUND_COLOR): cv.use_id(color.ColorStruct), diff --git a/esphome/components/graphical_display_menu/graphical_display_menu.cpp b/esphome/components/graphical_display_menu/graphical_display_menu.cpp index 2e4c14fb7b..fcbad41388 100644 --- a/esphome/components/graphical_display_menu/graphical_display_menu.cpp +++ b/esphome/components/graphical_display_menu/graphical_display_menu.cpp @@ -229,7 +229,8 @@ inline void GraphicalDisplayMenu::draw_item(display::Display *display, const dis label.append(this->menu_item_value_.value(&args)); } - display->print(bounds->x, bounds->y, this->font_, foreground_color, display::TextAlign::TOP_LEFT, label.c_str()); + display->print(bounds->x, bounds->y, this->font_, foreground_color, display::TextAlign::TOP_LEFT, label.c_str(), + ~foreground_color); } void GraphicalDisplayMenu::draw_item(const display_menu_base::MenuItem *item, const uint8_t row, const bool selected) { diff --git a/esphome/core/color.h b/esphome/core/color.h index 45b2d4c871..fb72973017 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -62,6 +62,7 @@ struct Color { return Color(esp_scale8(this->red, scale), esp_scale8(this->green, scale), esp_scale8(this->blue, scale), esp_scale8(this->white, scale)); } + inline Color operator~() const ALWAYS_INLINE { return Color(255 - this->red, 255 - this->green, 255 - this->blue); } inline Color &operator*=(uint8_t scale) ALWAYS_INLINE { this->red = esp_scale8(this->red, scale); this->green = esp_scale8(this->green, scale); From b8f0182fc5b93c45eeafb048695ac655bcf3297e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 24 Apr 2024 06:49:14 +1000 Subject: [PATCH 1615/2607] Add null GPIO pin (#6611) --- .../cst226/touchscreen/cst226_touchscreen.cpp | 18 +++++++----------- .../cst226/touchscreen/cst226_touchscreen.h | 2 +- esphome/core/gpio.h | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp index d4e43d30f5..69728dc666 100644 --- a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +++ b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp @@ -5,17 +5,13 @@ namespace cst226 { void CST226Touchscreen::setup() { esph_log_config(TAG, "Setting up CST226 Touchscreen..."); - if (this->reset_pin_ != nullptr) { - this->reset_pin_->setup(); - this->reset_pin_->digital_write(true); - delay(5); - this->reset_pin_->digital_write(false); - delay(5); - this->reset_pin_->digital_write(true); - this->set_timeout(30, [this] { this->continue_setup_(); }); - } else { - this->continue_setup_(); - } + this->reset_pin_->setup(); + this->reset_pin_->digital_write(true); + delay(5); + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + this->set_timeout(30, [this] { this->continue_setup_(); }); } void CST226Touchscreen::update_touches() { diff --git a/esphome/components/cst226/touchscreen/cst226_touchscreen.h b/esphome/components/cst226/touchscreen/cst226_touchscreen.h index 9f518e5068..1b15b952c4 100644 --- a/esphome/components/cst226/touchscreen/cst226_touchscreen.h +++ b/esphome/components/cst226/touchscreen/cst226_touchscreen.h @@ -35,7 +35,7 @@ class CST226Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice void continue_setup_(); InternalGPIOPin *interrupt_pin_{}; - GPIOPin *reset_pin_{}; + GPIOPin *reset_pin_{NULL_PIN}; uint8_t chip_id_{}; bool setup_complete_{}; }; diff --git a/esphome/core/gpio.h b/esphome/core/gpio.h index 1b6f2ba1e6..b3f6b00196 100644 --- a/esphome/core/gpio.h +++ b/esphome/core/gpio.h @@ -62,6 +62,24 @@ class GPIOPin { virtual bool is_internal() { return false; } }; +/** + * A pin to replace those that don't exist. + */ +class NullPin : public GPIOPin { + public: + void setup() override {} + + void pin_mode(gpio::Flags _) override {} + + bool digital_read() override { return false; } + + void digital_write(bool _) override {} + + std::string dump_summary() const override { return {"Not used"}; } +}; + +static GPIOPin *const NULL_PIN = new NullPin(); + /// Copy of GPIOPin that is safe to use from ISRs (with no virtual functions) class ISRInternalGPIOPin { public: From f9ce35c89443b7245b889ed728f45f964d89a439 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 24 Apr 2024 09:59:19 +1200 Subject: [PATCH 1616/2607] Allow UART to be AUTO LOADed (#6617) --- esphome/components/uart/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index 82bc6caaa4..088227afe5 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -59,6 +59,7 @@ UARTWriteAction = uart_ns.class_("UARTWriteAction", automation.Action) UARTDebugger = uart_ns.class_("UARTDebugger", cg.Component, automation.Action) UARTDummyReceiver = uart_ns.class_("UARTDummyReceiver", cg.Component) MULTI_CONF = True +MULTI_CONF_NO_DEFAULT = True def validate_raw_data(value): From f8cdb087fc0eec5199312da94379c6407cdc3339 Mon Sep 17 00:00:00 2001 From: Jean Louis-Guerin Date: Wed, 24 Apr 2024 03:21:44 +0200 Subject: [PATCH 1617/2607] Add the WeiKai SPI/I2C UART/IO Expander components to esphome (#5218) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 11 + esphome/components/weikai/__init__.py | 108 +++ esphome/components/weikai/weikai.cpp | 615 ++++++++++++++++++ esphome/components/weikai/weikai.h | 443 +++++++++++++ esphome/components/weikai/wk_reg_def.h | 304 +++++++++ esphome/components/weikai_i2c/__init__.py | 1 + esphome/components/weikai_i2c/weikai_i2c.cpp | 177 +++++ esphome/components/weikai_i2c/weikai_i2c.h | 61 ++ esphome/components/weikai_spi/__init__.py | 1 + esphome/components/weikai_spi/weikai_spi.cpp | 189 ++++++ esphome/components/weikai_spi/weikai_spi.h | 54 ++ esphome/components/wk2132_i2c/__init__.py | 30 + esphome/components/wk2132_i2c/wk2132_i2c.cpp | 4 + esphome/components/wk2132_spi/__init__.py | 31 + esphome/components/wk2168_i2c/__init__.py | 64 ++ esphome/components/wk2168_spi/__init__.py | 62 ++ esphome/components/wk2204_i2c/__init__.py | 30 + esphome/components/wk2204_spi/__init__.py | 30 + esphome/components/wk2212_i2c/__init__.py | 64 ++ esphome/components/wk2212_spi/__init__.py | 62 ++ tests/components/wk2132_i2c/common.yaml | 20 + .../components/wk2132_i2c/test.esp32-idf.yaml | 5 + .../wk2132_i2c/test.esp32-s3-idf.yaml | 5 + .../components/wk2132_i2c/test.esp32-s3.yaml | 5 + tests/components/wk2132_i2c/test.esp32.yaml | 5 + tests/components/wk2132_spi/common.yaml | 21 + .../components/wk2132_spi/test.esp32-idf.yaml | 7 + .../wk2132_spi/test.esp32-s3-idf.yaml | 7 + .../components/wk2132_spi/test.esp32-s3.yaml | 7 + tests/components/wk2132_spi/test.esp32.yaml | 7 + tests/components/wk2168_i2c/common.yaml | 63 ++ .../components/wk2168_i2c/test.esp32-idf.yaml | 5 + .../wk2168_i2c/test.esp32-s3-idf.yaml | 5 + .../components/wk2168_i2c/test.esp32-s3.yaml | 5 + tests/components/wk2168_i2c/test.esp32.yaml | 5 + tests/components/wk2168_spi/common.yaml | 63 ++ .../components/wk2168_spi/test.esp32-idf.yaml | 7 + .../wk2168_spi/test.esp32-s3-idf.yaml | 7 + .../components/wk2168_spi/test.esp32-s3.yaml | 7 + tests/components/wk2168_spi/test.esp32.yaml | 7 + tests/components/wk2204_i2c/common.yaml | 28 + .../components/wk2204_i2c/test.esp32-idf.yaml | 5 + .../wk2204_i2c/test.esp32-s3-idf.yaml | 5 + .../components/wk2204_i2c/test.esp32-s3.yaml | 5 + tests/components/wk2204_i2c/test.esp32.yaml | 5 + tests/components/wk2204_spi/common.yaml | 29 + .../components/wk2204_spi/test.esp32-idf.yaml | 7 + .../wk2204_spi/test.esp32-s3-idf.yaml | 7 + .../components/wk2204_spi/test.esp32-s3.yaml | 7 + tests/components/wk2204_spi/test.esp32.yaml | 7 + tests/components/wk2212_i2c/common.yaml | 59 ++ .../components/wk2212_i2c/test.esp32-idf.yaml | 5 + .../wk2212_i2c/test.esp32-s3-idf.yaml | 5 + .../components/wk2212_i2c/test.esp32-s3.yaml | 5 + tests/components/wk2212_i2c/test.esp32.yaml | 5 + tests/components/wk2212_spi/common.yaml | 58 ++ .../components/wk2212_spi/test.esp32-idf.yaml | 7 + .../wk2212_spi/test.esp32-s3-idf.yaml | 7 + .../components/wk2212_spi/test.esp32-s3.yaml | 7 + tests/components/wk2212_spi/test.esp32.yaml | 7 + 60 files changed, 2874 insertions(+) create mode 100644 esphome/components/weikai/__init__.py create mode 100644 esphome/components/weikai/weikai.cpp create mode 100644 esphome/components/weikai/weikai.h create mode 100644 esphome/components/weikai/wk_reg_def.h create mode 100644 esphome/components/weikai_i2c/__init__.py create mode 100644 esphome/components/weikai_i2c/weikai_i2c.cpp create mode 100644 esphome/components/weikai_i2c/weikai_i2c.h create mode 100644 esphome/components/weikai_spi/__init__.py create mode 100644 esphome/components/weikai_spi/weikai_spi.cpp create mode 100644 esphome/components/weikai_spi/weikai_spi.h create mode 100644 esphome/components/wk2132_i2c/__init__.py create mode 100644 esphome/components/wk2132_i2c/wk2132_i2c.cpp create mode 100644 esphome/components/wk2132_spi/__init__.py create mode 100644 esphome/components/wk2168_i2c/__init__.py create mode 100644 esphome/components/wk2168_spi/__init__.py create mode 100644 esphome/components/wk2204_i2c/__init__.py create mode 100644 esphome/components/wk2204_spi/__init__.py create mode 100644 esphome/components/wk2212_i2c/__init__.py create mode 100644 esphome/components/wk2212_spi/__init__.py create mode 100644 tests/components/wk2132_i2c/common.yaml create mode 100644 tests/components/wk2132_i2c/test.esp32-idf.yaml create mode 100644 tests/components/wk2132_i2c/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2132_i2c/test.esp32-s3.yaml create mode 100644 tests/components/wk2132_i2c/test.esp32.yaml create mode 100644 tests/components/wk2132_spi/common.yaml create mode 100644 tests/components/wk2132_spi/test.esp32-idf.yaml create mode 100644 tests/components/wk2132_spi/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2132_spi/test.esp32-s3.yaml create mode 100644 tests/components/wk2132_spi/test.esp32.yaml create mode 100644 tests/components/wk2168_i2c/common.yaml create mode 100644 tests/components/wk2168_i2c/test.esp32-idf.yaml create mode 100644 tests/components/wk2168_i2c/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2168_i2c/test.esp32-s3.yaml create mode 100644 tests/components/wk2168_i2c/test.esp32.yaml create mode 100644 tests/components/wk2168_spi/common.yaml create mode 100644 tests/components/wk2168_spi/test.esp32-idf.yaml create mode 100644 tests/components/wk2168_spi/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2168_spi/test.esp32-s3.yaml create mode 100644 tests/components/wk2168_spi/test.esp32.yaml create mode 100644 tests/components/wk2204_i2c/common.yaml create mode 100644 tests/components/wk2204_i2c/test.esp32-idf.yaml create mode 100644 tests/components/wk2204_i2c/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2204_i2c/test.esp32-s3.yaml create mode 100644 tests/components/wk2204_i2c/test.esp32.yaml create mode 100644 tests/components/wk2204_spi/common.yaml create mode 100644 tests/components/wk2204_spi/test.esp32-idf.yaml create mode 100644 tests/components/wk2204_spi/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2204_spi/test.esp32-s3.yaml create mode 100644 tests/components/wk2204_spi/test.esp32.yaml create mode 100644 tests/components/wk2212_i2c/common.yaml create mode 100644 tests/components/wk2212_i2c/test.esp32-idf.yaml create mode 100644 tests/components/wk2212_i2c/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2212_i2c/test.esp32-s3.yaml create mode 100644 tests/components/wk2212_i2c/test.esp32.yaml create mode 100644 tests/components/wk2212_spi/common.yaml create mode 100644 tests/components/wk2212_spi/test.esp32-idf.yaml create mode 100644 tests/components/wk2212_spi/test.esp32-s3-idf.yaml create mode 100644 tests/components/wk2212_spi/test.esp32-s3.yaml create mode 100644 tests/components/wk2212_spi/test.esp32.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 28ce8e7b6a..8da1618636 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -400,10 +400,21 @@ esphome/components/wake_on_lan/* @willwill2will54 esphome/components/waveshare_epaper/* @clydebarrow esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_idf/* @dentra +esphome/components/weikai/* @DrCoolZic +esphome/components/weikai_i2c/* @DrCoolZic +esphome/components/weikai_spi/* @DrCoolZic esphome/components/whirlpool/* @glmnet esphome/components/whynter/* @aeonsablaze esphome/components/wiegand/* @ssieb esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard +esphome/components/wk2132_i2c/* @DrCoolZic +esphome/components/wk2132_spi/* @DrCoolZic +esphome/components/wk2168_i2c/* @DrCoolZic +esphome/components/wk2168_spi/* @DrCoolZic +esphome/components/wk2204_i2c/* @DrCoolZic +esphome/components/wk2204_spi/* @DrCoolZic +esphome/components/wk2212_i2c/* @DrCoolZic +esphome/components/wk2212_spi/* @DrCoolZic esphome/components/wl_134/* @hobbypunk90 esphome/components/x9c/* @EtienneMD esphome/components/xgzp68xx/* @gcormier diff --git a/esphome/components/weikai/__init__.py b/esphome/components/weikai/__init__.py new file mode 100644 index 0000000000..4248c48e35 --- /dev/null +++ b/esphome/components/weikai/__init__.py @@ -0,0 +1,108 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import ( + CONF_BAUD_RATE, + CONF_CHANNEL, + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, +) + +CODEOWNERS = ["@DrCoolZic"] +AUTO_LOAD = ["uart"] + +MULTI_CONF = True +CONF_STOP_BITS = "stop_bits" +CONF_PARITY = "parity" +CONF_CRYSTAL = "crystal" +CONF_UART = "uart" +CONF_TEST_MODE = "test_mode" + +weikai_ns = cg.esphome_ns.namespace("weikai") +WeikaiComponent = weikai_ns.class_("WeikaiComponent", cg.Component) +WeikaiChannel = weikai_ns.class_("WeikaiChannel", uart.UARTComponent) + + +def check_channel_max(value, max): + channel_uniq = [] + channel_dup = [] + for x in value[CONF_UART]: + if x[CONF_CHANNEL] > max - 1: + raise cv.Invalid(f"Invalid channel number: {x[CONF_CHANNEL]}") + if x[CONF_CHANNEL] not in channel_uniq: + channel_uniq.append(x[CONF_CHANNEL]) + else: + channel_dup.append(x[CONF_CHANNEL]) + if len(channel_dup) > 0: + raise cv.Invalid(f"Duplicate channel list: {channel_dup}") + return value + + +def check_channel_max_4(value): + return check_channel_max(value, 4) + + +def check_channel_max_2(value): + return check_channel_max(value, 2) + + +WKBASE_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(WeikaiComponent), + cv.Optional(CONF_CRYSTAL, default=14745600): cv.int_, + cv.Optional(CONF_TEST_MODE, default=0): cv.int_, + cv.Required(CONF_UART): cv.ensure_list( + { + cv.Required(CONF_ID): cv.declare_id(WeikaiChannel), + cv.Optional(CONF_CHANNEL, default=0): cv.int_range(min=0, max=3), + cv.Required(CONF_BAUD_RATE): cv.int_range(min=1), + cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True), + cv.Optional(CONF_PARITY, default="NONE"): cv.enum( + uart.UART_PARITY_OPTIONS, upper=True + ), + } + ), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def register_weikai(var, config): + """Register an weikai device with the given config.""" + cg.add(var.set_crystal(config[CONF_CRYSTAL])) + cg.add(var.set_test_mode(config[CONF_TEST_MODE])) + await cg.register_component(var, config) + for uart_elem in config[CONF_UART]: + chan = cg.new_Pvariable(uart_elem[CONF_ID]) + cg.add(chan.set_channel_name(str(uart_elem[CONF_ID]))) + cg.add(chan.set_parent(var)) + cg.add(chan.set_channel(uart_elem[CONF_CHANNEL])) + cg.add(chan.set_baud_rate(uart_elem[CONF_BAUD_RATE])) + cg.add(chan.set_stop_bits(uart_elem[CONF_STOP_BITS])) + cg.add(chan.set_parity(uart_elem[CONF_PARITY])) + + +def validate_pin_mode(value): + """Checks input/output mode inconsistency""" + if not (value[CONF_MODE][CONF_INPUT] or value[CONF_MODE][CONF_OUTPUT]): + raise cv.Invalid("Mode must be either input or output") + if value[CONF_MODE][CONF_INPUT] and value[CONF_MODE][CONF_OUTPUT]: + raise cv.Invalid("Mode must be either input or output") + return value + + +WEIKAI_PIN_SCHEMA = cv.Schema( + { + cv.Required(CONF_NUMBER): cv.int_range(min=0, max=7), + cv.Optional(CONF_MODE, default={}): cv.All( + { + cv.Optional(CONF_INPUT, default=False): cv.boolean, + cv.Optional(CONF_OUTPUT, default=False): cv.boolean, + }, + ), + cv.Optional(CONF_INVERTED, default=False): cv.boolean, + } +) diff --git a/esphome/components/weikai/weikai.cpp b/esphome/components/weikai/weikai.cpp new file mode 100644 index 0000000000..a04bc0a574 --- /dev/null +++ b/esphome/components/weikai/weikai.cpp @@ -0,0 +1,615 @@ +/// @file weikai.cpp +/// @brief WeiKai component family - classes implementation +/// @date Last Modified: 2024/04/06 15:13:11 +/// @details The classes declared in this file can be used by the Weikai family + +#include "weikai.h" + +namespace esphome { +namespace weikai { + +/*! @mainpage Weikai source code documentation + This documentation provides information about the implementation of the family of WeiKai Components in ESPHome. + Here is the class diagram related to Weikai family of components: + @image html weikai_class.png + + @section WKRingBuffer_ The WKRingBuffer template class +The WKRingBuffer template class has it names implies implement a simple ring buffer helper class. This straightforward +container implements FIFO functionality, enabling bytes to be pushed into one side and popped from the other in the +order of entry. Implementation is classic and therefore not described in any details. + + @section WeikaiRegister_ The WeikaiRegister class + The WeikaiRegister helper class creates objects that act as proxies to the device registers. + @details This is an abstract virtual class (interface) that provides all the necessary access to registers while hiding + the actual implementation. The access to the registers can be made through an I²C bus in for example for wk2168_i2c + component or through a SPI bus for example in the case of the wk2168_spi component. Derived classes will actually + performs the specific bus operations. + + @section WeikaiRegisterI2C_ WeikaiRegisterI2C + The weikai_i2c::WeikaiRegisterI2C class implements the virtual methods of the WeikaiRegister class for an I2C bus. + + @section WeikaiRegisterSPI_ WeikaiRegisterSPI + The weikai_spi::WeikaiRegisterSPI class implements the virtual methods of the WeikaiRegister class for an SPI bus. + + @section WeikaiComponent_ The WeikaiComponent class +The WeikaiComponent class stores the information global to a WeiKai family component and provides methods to set/access +this information. It also serves as a container for WeikaiChannel instances. This is done by maintaining an array of +references these WeikaiChannel instances. This class derives from the esphome::Component classes. This class override +esphome::Component::loop() method to facilitate the seamless transfer of accumulated bytes from the receive +FIFO into the ring buffer. This process ensures quick access to the stored bytes, enhancing the overall efficiency of +the component. + + @section WeikaiComponentI2C_ WeikaiComponentI2C + The weikai_i2c::WeikaiComponentI2C class implements the virtual methods of the WeikaiComponent class for an I2C bus. + + @section WeikaiComponentSPI_ WeikaiComponentSPI + The weikai_spi::WeikaiComponentSPI class implements the virtual methods of the WeikaiComponent class for an SPI bus. + + @section WeikaiGPIOPin_ WeikaiGPIOPin class + The WeikaiGPIOPin class is an helper class to expose the GPIO pins of WK family components as if they were internal + GPIO pins. It also provides the setup() and dump_summary() methods. + + @section WeikaiChannel_ The WeikaiChannel class + The WeikaiChannel class is used to implement all the virtual methods of the ESPHome uart::UARTComponent class. An + individual instance of this class is created for each UART channel. It has a link back to the WeikaiComponent object it + belongs to. This class derives from the uart::UARTComponent class. It collaborates through an aggregation with + WeikaiComponent. This implies that WeikaiComponent acts as a container, housing several WeikaiChannel instances. + Furthermore, the WeikaiChannel class derives from the ESPHome uart::UARTComponent class, it also has an association + relationship with the WKRingBuffer and WeikaiRegister helper classes. Consequently, when a WeikaiChannel instance is + destroyed, the associated WKRingBuffer instance is also destroyed. + +*/ + +static const char *const TAG = "weikai"; + +/// @brief convert an int to binary representation as C++ std::string +/// @param val integer to convert +/// @return a std::string +inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); } +/// Convert std::string to C string +#define I2S2CS(val) (i2s(val).c_str()) + +/// @brief measure the time elapsed between two calls +/// @param last_time time of the previous call +/// @return the elapsed time in milliseconds +uint32_t elapsed_ms(uint32_t &last_time) { + uint32_t e = millis() - last_time; + last_time = millis(); + return e; +}; + +/// @brief Converts the parity enum value to a C string +/// @param parity enum +/// @return the string +const char *p2s(uart::UARTParityOptions parity) { + using namespace uart; + switch (parity) { + case UART_CONFIG_PARITY_NONE: + return "NONE"; + case UART_CONFIG_PARITY_EVEN: + return "EVEN"; + case UART_CONFIG_PARITY_ODD: + return "ODD"; + default: + return "UNKNOWN"; + } +} + +/// @brief Display a buffer in hexadecimal format (32 hex values / line) for debug +void print_buffer(const uint8_t *data, size_t length) { + char hex_buffer[100]; + hex_buffer[(3 * 32) + 1] = 0; + for (size_t i = 0; i < length; i++) { + snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); + if (i % 32 == 31) { + ESP_LOGVV(TAG, " %s", hex_buffer); + } + } + if (length % 32) { + // null terminate if incomplete line + hex_buffer[3 * (length % 32) + 2] = 0; + ESP_LOGVV(TAG, " %s", hex_buffer); + } +} + +static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER", + "SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"}; +static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", + "TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"}; + +// method to print a register value as text: used in the log messages ... +const char *reg_to_str(int reg, bool page1) { + if (reg == WKREG_GPDAT) { + return "GPDAT"; + } else if (reg == WKREG_GPDIR) { + return "GPDIR"; + } else { + return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; + } +} + +enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiRegister methods +/////////////////////////////////////////////////////////////////////////////// +WeikaiRegister &WeikaiRegister::operator=(uint8_t value) { + write_reg(value); + return *this; +} + +WeikaiRegister &WeikaiRegister::operator&=(uint8_t value) { + value &= read_reg(); + write_reg(value); + return *this; +} + +WeikaiRegister &WeikaiRegister::operator|=(uint8_t value) { + value |= read_reg(); + write_reg(value); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiComponent methods +/////////////////////////////////////////////////////////////////////////////// +void WeikaiComponent::loop() { + if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP) + return; + + // If there are some bytes in the receive FIFO we transfers them to the ring buffers + size_t transferred = 0; + for (auto *child : this->children_) { + // we look if some characters has been received in the fifo + transferred += child->xfer_fifo_to_buffer_(); + } + if (transferred > 0) { + ESP_LOGV(TAG, "we transferred %d bytes from fifo to buffer...", transferred); + } + +#ifdef TEST_COMPONENT + static uint32_t loop_time = 0; + static uint32_t loop_count = 0; + uint32_t time = 0; + + if (test_mode_ == 1) { // test component in loopback + ESP_LOGI(TAG, "Component loop %" PRIu32 " for %s : %" PRIu32 " ms since last call ...", loop_count++, + this->get_name(), millis() - loop_time); + loop_time = millis(); + char message[64]; + elapsed_ms(time); // set time to now + for (int i = 0; i < this->children_.size(); i++) { + if (i != ((loop_count - 1) % this->children_.size())) // we do only one per loop + continue; + snprintf(message, sizeof(message), "%s:%s", this->get_name(), children_[i]->get_channel_name()); + children_[i]->uart_send_test_(message); + uint32_t const start_time = millis(); + while (children_[i]->tx_fifo_is_not_empty_()) { // wait until buffer empty + if (millis() - start_time > 1500) { + ESP_LOGE(TAG, "timeout while flushing - %d bytes left in buffer...", children_[i]->tx_in_fifo_()); + break; + } + yield(); // reschedule our thread to avoid blocking + } + bool status = children_[i]->uart_receive_test_(message); + ESP_LOGI(TAG, "Test %s => send/received %u bytes %s - execution time %" PRIu32 " ms...", message, + RING_BUFFER_SIZE, status ? "correctly" : "with error", elapsed_ms(time)); + } + } + + if (this->test_mode_ == 2) { // test component in echo mode + for (auto *child : this->children_) { + uint8_t data = 0; + if (child->available()) { + child->read_byte(&data); + ESP_LOGI(TAG, "echo mode: read -> send %02X", data); + child->write_byte(data); + } + } + } + if (test_mode_ == 3) { + test_gpio_input_(); + } + + if (test_mode_ == 4) { + test_gpio_output_(); + } +#endif +} + +#if defined(TEST_COMPONENT) +void WeikaiComponent::test_gpio_input_() { + static bool init_input{false}; + static uint8_t state{0}; + uint8_t value; + if (!init_input) { + init_input = true; + // set all pins in input mode + this->reg(WKREG_GPDIR, 0) = 0x00; + ESP_LOGI(TAG, "initializing all pins to input mode"); + state = this->reg(WKREG_GPDAT, 0); + ESP_LOGI(TAG, "initial input data state = %02X (%s)", state, I2S2CS(state)); + } + value = this->reg(WKREG_GPDAT, 0); + if (value != state) { + ESP_LOGI(TAG, "Input data changed from %02X to %02X (%s)", state, value, I2S2CS(value)); + state = value; + } +} + +void WeikaiComponent::test_gpio_output_() { + static bool init_output{false}; + static uint8_t state{0}; + if (!init_output) { + init_output = true; + // set all pins in output mode + this->reg(WKREG_GPDIR, 0) = 0xFF; + ESP_LOGI(TAG, "initializing all pins to output mode"); + this->reg(WKREG_GPDAT, 0) = state; + ESP_LOGI(TAG, "setting all outputs to 0"); + } + state = ~state; + this->reg(WKREG_GPDAT, 0) = state; + ESP_LOGI(TAG, "Flipping all outputs to %02X (%s)", state, I2S2CS(state)); + delay(100); // NOLINT +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiGPIOPin methods +/////////////////////////////////////////////////////////////////////////////// +bool WeikaiComponent::read_pin_val_(uint8_t pin) { + this->input_state_ = this->reg(WKREG_GPDAT, 0); + ESP_LOGVV(TAG, "reading input pin %u = %u in_state %s", pin, this->input_state_ & (1 << pin), I2S2CS(input_state_)); + return this->input_state_ & (1 << pin); +} + +void WeikaiComponent::write_pin_val_(uint8_t pin, bool value) { + if (value) { + this->output_state_ |= (1 << pin); + } else { + this->output_state_ &= ~(1 << pin); + } + ESP_LOGVV(TAG, "writing output pin %d with %d out_state %s", pin, uint8_t(value), I2S2CS(this->output_state_)); + this->reg(WKREG_GPDAT, 0) = this->output_state_; +} + +void WeikaiComponent::set_pin_direction_(uint8_t pin, gpio::Flags flags) { + if (flags == gpio::FLAG_INPUT) { + this->pin_config_ &= ~(1 << pin); // clear bit (input mode) + } else { + if (flags == gpio::FLAG_OUTPUT) { + this->pin_config_ |= 1 << pin; // set bit (output mode) + } else { + ESP_LOGE(TAG, "pin %d direction invalid", pin); + } + } + ESP_LOGVV(TAG, "setting pin %d direction to %d pin_config=%s", pin, flags, I2S2CS(this->pin_config_)); + this->reg(WKREG_GPDIR, 0) = this->pin_config_; // TODO check ~ +} + +void WeikaiGPIOPin::setup() { + ESP_LOGCONFIG(TAG, "Setting GPIO pin %d mode to %s", this->pin_, + flags_ == gpio::FLAG_INPUT ? "Input" + : this->flags_ == gpio::FLAG_OUTPUT ? "Output" + : "NOT SPECIFIED"); + // ESP_LOGCONFIG(TAG, "Setting GPIO pins mode to '%s' %02X", I2S2CS(this->flags_), this->flags_); + this->pin_mode(this->flags_); +} + +std::string WeikaiGPIOPin::dump_summary() const { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%u via WeiKai %s", this->pin_, this->parent_->get_name()); + return buffer; +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiChannel methods +/////////////////////////////////////////////////////////////////////////////// +void WeikaiChannel::setup_channel() { + ESP_LOGCONFIG(TAG, " Setting up UART %s:%s ...", this->parent_->get_name(), this->get_channel_name()); + // we enable transmit and receive on this channel + if (this->check_channel_down()) { + ESP_LOGCONFIG(TAG, " Error channel %s not working...", this->get_channel_name()); + } + this->reset_fifo_(); + this->receive_buffer_.clear(); + this->set_line_param_(); + this->set_baudrate_(); +} + +void WeikaiChannel::dump_channel() { + ESP_LOGCONFIG(TAG, " UART %s ...", this->get_channel_name()); + ESP_LOGCONFIG(TAG, " Baud rate: %" PRIu32 " Bd", this->baud_rate_); + ESP_LOGCONFIG(TAG, " Data bits: %u", this->data_bits_); + ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, " Parity: %s", p2s(this->parity_)); +} + +void WeikaiChannel::reset_fifo_() { + // enable transmission and reception + this->reg(WKREG_SCR) = SCR_RXEN | SCR_TXEN; + // we reset and enable transmit and receive FIFO + this->reg(WKREG_FCR) = FCR_TFEN | FCR_RFEN | FCR_TFRST | FCR_RFRST; +} + +void WeikaiChannel::set_line_param_() { + this->data_bits_ = 8; // always equal to 8 for WeiKai (cant be changed) + uint8_t lcr = 0; + if (this->stop_bits_ == 2) + lcr |= LCR_STPL; + switch (this->parity_) { // parity selection settings + case uart::UART_CONFIG_PARITY_ODD: + lcr |= (LCR_PAEN | LCR_PAR_ODD); + break; + case uart::UART_CONFIG_PARITY_EVEN: + lcr |= (LCR_PAEN | LCR_PAR_EVEN); + break; + default: + break; // no parity 000x + } + this->reg(WKREG_LCR) = lcr; // write LCR + ESP_LOGV(TAG, " line config: %d data_bits, %d stop_bits, parity %s register [%s]", this->data_bits_, + this->stop_bits_, p2s(this->parity_), I2S2CS(lcr)); +} + +void WeikaiChannel::set_baudrate_() { + if (this->baud_rate_ > this->parent_->crystal_ / 16) { + baud_rate_ = this->parent_->crystal_ / 16; + ESP_LOGE(TAG, " Requested baudrate too high for crystal=%" PRIu32 " Hz. Has been reduced to %" PRIu32 " Bd", + this->parent_->crystal_, this->baud_rate_); + }; + uint16_t const val_int = this->parent_->crystal_ / (this->baud_rate_ * 16) - 1; + uint16_t val_dec = (this->parent_->crystal_ % (this->baud_rate_ * 16)) / (this->baud_rate_ * 16); + uint8_t const baud_high = (uint8_t) (val_int >> 8); + uint8_t const baud_low = (uint8_t) (val_int & 0xFF); + while (val_dec > 0x0A) + val_dec /= 0x0A; + uint8_t const baud_dec = (uint8_t) (val_dec); + + this->parent_->page1_ = true; // switch to page 1 + this->reg(WKREG_SPAGE) = 1; + this->reg(WKREG_BRH) = baud_high; + this->reg(WKREG_BRL) = baud_low; + this->reg(WKREG_BRD) = baud_dec; + this->parent_->page1_ = false; // switch back to page 0 + this->reg(WKREG_SPAGE) = 0; + + ESP_LOGV(TAG, " Crystal=%d baudrate=%d => registers [%d %d %d]", this->parent_->crystal_, this->baud_rate_, + baud_high, baud_low, baud_dec); +} + +inline bool WeikaiChannel::tx_fifo_is_not_empty_() { return this->reg(WKREG_FSR) & FSR_TFDAT; } + +size_t WeikaiChannel::tx_in_fifo_() { + size_t tfcnt = this->reg(WKREG_TFCNT); + if (tfcnt == 0) { + uint8_t const fsr = this->reg(WKREG_FSR); + if (fsr & FSR_TFFULL) { + ESP_LOGVV(TAG, "tx FIFO full FSR=%s", I2S2CS(fsr)); + tfcnt = FIFO_SIZE; + } + } + ESP_LOGVV(TAG, "tx FIFO contains %d bytes", tfcnt); + return tfcnt; +} + +size_t WeikaiChannel::rx_in_fifo_() { + size_t available = this->reg(WKREG_RFCNT); + uint8_t const fsr = this->reg(WKREG_FSR); + if (fsr & (FSR_RFOE | FSR_RFLB | FSR_RFFE | FSR_RFPE)) { + if (fsr & FSR_RFOE) + ESP_LOGE(TAG, "Receive data overflow FSR=%s", I2S2CS(fsr)); + if (fsr & FSR_RFLB) + ESP_LOGE(TAG, "Receive line break FSR=%s", I2S2CS(fsr)); + if (fsr & FSR_RFFE) + ESP_LOGE(TAG, "Receive frame error FSR=%s", I2S2CS(fsr)); + if (fsr & FSR_RFPE) + ESP_LOGE(TAG, "Receive parity error FSR=%s", I2S2CS(fsr)); + } + if ((available == 0) && (fsr & FSR_RFDAT)) { + // here we should be very careful because we can have something like this: + // - at time t0 we read RFCNT=0 because nothing yet received + // - at time t0+delta we might read FIFO not empty because one byte has just been received + // - so to be sure we need to do another read of RFCNT and if it is still zero -> buffer full + available = this->reg(WKREG_RFCNT); + if (available == 0) { // still zero ? + ESP_LOGV(TAG, "rx FIFO is full FSR=%s", I2S2CS(fsr)); + available = FIFO_SIZE; + } + } + ESP_LOGVV(TAG, "rx FIFO contain %d bytes - FSR status=%s", available, I2S2CS(fsr)); + return available; +} + +bool WeikaiChannel::check_channel_down() { + // to check if we channel is up we write to the LCR W/R register + // note that this will put a break on the tx line for few ms + WeikaiRegister &lcr = this->reg(WKREG_LCR); + lcr = 0x3F; + uint8_t val = lcr; + if (val != 0x3F) { + ESP_LOGE(TAG, "R/W of register failed expected 0x3F received 0x%02X", val); + return true; + } + lcr = 0; + val = lcr; + if (val != 0x00) { + ESP_LOGE(TAG, "R/W of register failed expected 0x00 received 0x%02X", val); + return true; + } + return false; +} + +bool WeikaiChannel::peek_byte(uint8_t *buffer) { + auto available = this->receive_buffer_.count(); + if (!available) + xfer_fifo_to_buffer_(); + return this->receive_buffer_.peek(*buffer); +} + +int WeikaiChannel::available() { + size_t available = this->receive_buffer_.count(); + if (!available) + available = xfer_fifo_to_buffer_(); + return available; +} + +bool WeikaiChannel::read_array(uint8_t *buffer, size_t length) { + bool status = true; + auto available = this->receive_buffer_.count(); + if (length > available) { + ESP_LOGW(TAG, "read_array: buffer underflow requested %d bytes only %d bytes available...", length, available); + length = available; + status = false; + } + // retrieve the bytes from ring buffer + for (size_t i = 0; i < length; i++) { + this->receive_buffer_.pop(buffer[i]); + } + ESP_LOGVV(TAG, "read_array(ch=%d buffer[0]=%02X, length=%d): status %s", this->channel_, *buffer, length, + status ? "OK" : "ERROR"); + return status; +} + +void WeikaiChannel::write_array(const uint8_t *buffer, size_t length) { + if (length > XFER_MAX_SIZE) { + ESP_LOGE(TAG, "Write_array: invalid call - requested %d bytes but max size %d ...", length, XFER_MAX_SIZE); + length = XFER_MAX_SIZE; + } + this->reg(0).write_fifo(const_cast(buffer), length); +} + +void WeikaiChannel::flush() { + uint32_t const start_time = millis(); + while (this->tx_fifo_is_not_empty_()) { // wait until buffer empty + if (millis() - start_time > 200) { + ESP_LOGW(TAG, "WARNING flush timeout - still %d bytes not sent after 200 ms...", this->tx_in_fifo_()); + return; + } + yield(); // reschedule our thread to avoid blocking + } +} + +size_t WeikaiChannel::xfer_fifo_to_buffer_() { + size_t to_transfer; + size_t free; + while ((to_transfer = this->rx_in_fifo_()) && (free = this->receive_buffer_.free())) { + // while bytes in fifo and some room in the buffer we transfer + if (to_transfer > XFER_MAX_SIZE) + to_transfer = XFER_MAX_SIZE; // we can only do so much + if (to_transfer > free) + to_transfer = free; // we'll do the rest next time + if (to_transfer) { + uint8_t data[to_transfer]; + this->reg(0).read_fifo(data, to_transfer); + for (size_t i = 0; i < to_transfer; i++) + this->receive_buffer_.push(data[i]); + } + } // while work to do + return to_transfer; +} + +/// +// TEST COMPONENT +// +#ifdef TEST_COMPONENT +/// @addtogroup test_ Test component information +/// @{ + +/// @brief An increment "Functor" (i.e. a class object that acts like a method with state!) +/// +/// Functors are objects that can be treated as though they are a function or function pointer. +class Increment { + public: + /// @brief constructor: initialize current value to 0 + Increment() : i_(0) {} + /// @brief overload of the parenthesis operator. + /// Returns the current value and auto increment it + /// @return the current value. + uint8_t operator()() { return i_++; } + + private: + uint8_t i_; +}; + +/// @brief Hex converter to print/display a buffer in hexadecimal format (32 hex values / line). +/// @param buffer contains the values to display +void print_buffer(std::vector buffer) { + char hex_buffer[100]; + hex_buffer[(3 * 32) + 1] = 0; + for (size_t i = 0; i < buffer.size(); i++) { + snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", buffer[i]); + if (i % 32 == 31) + ESP_LOGI(TAG, " %s", hex_buffer); + } + if (buffer.size() % 32) { + // null terminate if incomplete line + hex_buffer[3 * (buffer.size() % 32) + 1] = 0; + ESP_LOGI(TAG, " %s", hex_buffer); + } +} + +/// @brief test the write_array method +void WeikaiChannel::uart_send_test_(char *message) { + auto start_exec = micros(); + std::vector output_buffer(XFER_MAX_SIZE); + generate(output_buffer.begin(), output_buffer.end(), Increment()); // fill with incrementing number + size_t to_send = RING_BUFFER_SIZE; + while (to_send) { + this->write_array(&output_buffer[0], XFER_MAX_SIZE); // we send the buffer + this->flush(); + to_send -= XFER_MAX_SIZE; + } + ESP_LOGV(TAG, "%s => sent %d bytes - exec time %d µs ...", message, RING_BUFFER_SIZE, micros() - start_exec); +} + +/// @brief test read_array method +bool WeikaiChannel::uart_receive_test_(char *message) { + auto start_exec = micros(); + bool status = true; + size_t received = 0; + std::vector buffer(RING_BUFFER_SIZE); + + // we wait until we have received all the bytes + uint32_t const start_time = millis(); + status = true; + while (received < RING_BUFFER_SIZE) { + while (XFER_MAX_SIZE > this->available()) { + this->xfer_fifo_to_buffer_(); + if (millis() - start_time > 1500) { + ESP_LOGE(TAG, "uart_receive_test_() timeout: only %d bytes received...", this->available()); + break; + } + yield(); // reschedule our thread to avoid blocking + } + status = this->read_array(&buffer[received], XFER_MAX_SIZE) && status; + received += XFER_MAX_SIZE; + } + + uint8_t peek_value = 0; + this->peek_byte(&peek_value); + if (peek_value != 0) { + ESP_LOGE(TAG, "Peek first byte value error..."); + status = false; + } + + for (size_t i = 0; i < RING_BUFFER_SIZE; i++) { + if (buffer[i] != i % XFER_MAX_SIZE) { + ESP_LOGE(TAG, "Read buffer contains error...b=%x i=%x", buffer[i], i % XFER_MAX_SIZE); + print_buffer(buffer); + status = false; + break; + } + } + + ESP_LOGV(TAG, "%s => received %d bytes status %s - exec time %d µs ...", message, received, status ? "OK" : "ERROR", + micros() - start_exec); + return status; +} + +/// @} +#endif + +} // namespace weikai +} // namespace esphome diff --git a/esphome/components/weikai/weikai.h b/esphome/components/weikai/weikai.h new file mode 100644 index 0000000000..042c729162 --- /dev/null +++ b/esphome/components/weikai/weikai.h @@ -0,0 +1,443 @@ +/// @file weikai.h +/// @author DrCoolZic +/// @brief WeiKai component family - classes declaration +/// @date Last Modified: 2024/04/06 14:44:17 +/// @details The classes declared in this file can be used by the Weikai family +/// of UART and GPIO expander components. As of today it provides support for +/// wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi, +/// wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c + +#pragma once +#include +#include +#include +#include "esphome/core/component.h" +#include "esphome/components/uart/uart.h" +#include "wk_reg_def.h" + +/// When the TEST_COMPONENT flag is defined we include some auto-test methods. Used to test the software during +/// development but can also be used in situ to test if the component is working correctly. For release we do +/// not set it by default but you can set it by using the following lines in you configuration file: +/// @code +/// esphome: +/// platformio_options: +/// build_flags: +/// - -DTEST_COMPONENT +/// @endcode +// #define TEST_COMPONENT + +namespace esphome { +namespace weikai { + +/// @brief XFER_MAX_SIZE defines the maximum number of bytes allowed during one transfer. +#if defined(I2C_BUFFER_LENGTH) +constexpr size_t XFER_MAX_SIZE = I2C_BUFFER_LENGTH; +#else +constexpr size_t XFER_MAX_SIZE = 128; +#endif + +/// @brief size of the internal WeiKai FIFO +constexpr size_t FIFO_SIZE = 256; + +/// @brief size of the ring buffer set to size of the FIFO +constexpr size_t RING_BUFFER_SIZE = FIFO_SIZE; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief This is an helper class that provides a simple ring buffers that works as a FIFO +/// @details This ring buffer is used to buffer the bytes received in the FIFO of the Weika device. The best way to read +/// characters from the device FIFO, is to first check how many bytes were received and then read them all at once. +/// Unfortunately in all the code I have reviewed the characters are read one by one in a while loop by checking if +/// bytes are available then reading the byte until no more byte available. This is pretty inefficient for two reasons: +/// - Fist you need to perform a test for each byte to read +/// - and second you call the read byte method for each character. +/// . +/// Assuming you need to read 100 bytes that results into 200 calls. This is to compare to 2 calls (one to find the +/// number of bytes available plus one to read all the bytes) in the best case! If the registers you read are located on +/// the micro-controller this is acceptable because the registers can be accessed fast. But when the registers are +/// located on a remote device accessing them requires several cycles on a slow bus. As it it not possible to fix this +/// problem by asking users to rewrite their code, I have implemented this ring buffer that store the bytes received +/// locally. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template class WKRingBuffer { + public: + /// @brief pushes an item at the tail of the fifo + /// @param item item to push + /// @return true if item has been pushed, false il item could not pushed (buffer full) + bool push(const T item) { + if (is_full()) + return false; + this->rb_[this->head_] = item; + this->head_ = (this->head_ + 1) % SIZE; + this->count_++; + return true; + } + + /// @brief return and remove the item at head of the fifo + /// @param item item read + /// @return true if an item has been retrieved, false il no item available (buffer empty) + bool pop(T &item) { + if (is_empty()) + return false; + item = this->rb_[this->tail_]; + this->tail_ = (this->tail_ + 1) % SIZE; + this->count_--; + return true; + } + + /// @brief return the value of the item at fifo's head without removing it + /// @param item pointer to item to return + /// @return true if item has been retrieved, false il no item available (buffer empty) + bool peek(T &item) { + if (is_empty()) + return false; + item = this->rb_[this->tail_]; + return true; + } + + /// @brief test is the Ring Buffer is empty ? + /// @return true if empty + inline bool is_empty() { return (this->count_ == 0); } + + /// @brief test is the ring buffer is full ? + /// @return true if full + inline bool is_full() { return (this->count_ == SIZE); } + + /// @brief return the number of item in the ring buffer + /// @return the number of items + inline size_t count() { return this->count_; } + + /// @brief returns the number of free positions in the buffer + /// @return how many items can be added + inline size_t free() { return SIZE - this->count_; } + + /// @brief clear the buffer content + inline void clear() { this->head_ = this->tail_ = this->count_ = 0; } + + protected: + std::array rb_{0}; ///< the ring buffer + int tail_{0}; ///< position of the next element to read + int head_{0}; ///< position of the next element to write + size_t count_{0}; ///< count number of element in the buffer +}; + +class WeikaiComponent; +// class WeikaiComponentSPI; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief WeikaiRegister objects acts as proxies to access remote register independently of the bus type. +/// @details This is an abstract interface class that provides many operations to access to registers while hiding +/// the actual implementation. This allow to accesses the registers in the Weikai component abstract class independently +/// of the actual bus (I2C, SPI). The derived classes will actually implements the specific bus operations dependant of +/// the bus used. +/// @n typical usage of WeikaiRegister: +/// @code +/// WeikaiRegister reg_X {&WeikaiComponent, ADDR_REGISTER_X, CHANNEL_NUM} // declaration +/// reg_X |= 0x01; // set bit 0 of the weikai register +/// reg_X &= ~0x01; // reset bit 0 of the weikai register +/// reg_X = 10; // Set the value of weikai register +/// uint val = reg_X; // get the value of weikai register +/// @endcode +class WeikaiRegister { + public: + /// @brief WeikaiRegister constructor. + /// @param comp our parent WeikaiComponent + /// @param reg address of the register + /// @param channel the channel of this register + WeikaiRegister(WeikaiComponent *const comp, uint8_t reg, uint8_t channel) + : comp_(comp), register_(reg), channel_(channel) {} + virtual ~WeikaiRegister() {} + + /// @brief overloads the = operator. This is used to set a value into the weikai register + /// @param value to be set + /// @return this object + WeikaiRegister &operator=(uint8_t value); + + /// @brief overloads the compound &= operator. This is often used to reset bits in the weikai register + /// @param value performs an & operation with value and store the result + /// @return this object + WeikaiRegister &operator&=(uint8_t value); + + /// @brief overloads the compound |= operator. This is often used to set bits in the weikai register + /// @param value performs an | operation with value and store the result + /// @return this object + WeikaiRegister &operator|=(uint8_t value); + + /// @brief cast operator that returns the content of the weikai register + operator uint8_t() const { return read_reg(); } + + /// @brief reads the register + /// @return the value read from the register + virtual uint8_t read_reg() const = 0; + + /// @brief writes the register + /// @param value to write in the register + virtual void write_reg(uint8_t value) = 0; + + /// @brief read an array of bytes from the receiver fifo + /// @param data pointer to data buffer + /// @param length number of bytes to read + virtual void read_fifo(uint8_t *data, size_t length) const = 0; + + /// @brief write an array of bytes to the transmitter fifo + /// @param data pointer to data buffer + /// @param length number of bytes to write + virtual void write_fifo(uint8_t *data, size_t length) = 0; + + WeikaiComponent *const comp_; ///< pointer to our parent (aggregation) + uint8_t register_; ///< address of the register + uint8_t channel_; ///< channel for this register +}; + +class WeikaiChannel; // forward declaration +//////////////////////////////////////////////////////////////////////////////////// +/// @brief The WeikaiComponent class stores the information global to the WeiKai component +/// and provides methods to set/access this information. It is also the container of +/// the WeikaiChannel children objects. This class is derived from esphome::Component +/// class. +//////////////////////////////////////////////////////////////////////////////////// +class WeikaiComponent : public Component { + public: + /// @brief virtual destructor + virtual ~WeikaiComponent() {} + + /// @brief store crystal frequency + /// @param crystal frequency + void set_crystal(uint32_t crystal) { this->crystal_ = crystal; } + + /// @brief store if the component is in test mode + /// @param test_mode 0=normal mode any other values mean component in test mode + void set_test_mode(int test_mode) { this->test_mode_ = test_mode; } + + /// @brief store the name for the component + /// @param name the name as defined by the python code generator + void set_name(std::string name) { this->name_ = std::move(name); } + + /// @brief Get the name of the component + /// @return the name + const char *get_name() { return this->name_.c_str(); } + + /// @brief override the Component loop() + void loop() override; + + bool page1() { return page1_; } + + /// @brief Factory method to create a Register object + /// @param reg address of the register + /// @param channel channel associated with this register + /// @return a reference to WeikaiRegister + virtual WeikaiRegister ®(uint8_t reg, uint8_t channel) = 0; + + protected: + friend class WeikaiChannel; + + /// @brief Get the priority of the component + /// @return the priority + /// @details The priority is set below setup_priority::BUS because we use + /// the spi/i2c busses (which has a priority of BUS) to communicate and the WeiKai + /// therefore it is seen by our client almost as if it was a bus. + float get_setup_priority() const override { return setup_priority::BUS - 0.1F; } + + friend class WeikaiGPIOPin; + /// Helper method to read the value of a pin. + bool read_pin_val_(uint8_t pin); + + /// Helper method to write the value of a pin. + void write_pin_val_(uint8_t pin, bool value); + + /// Helper method to set the pin mode of a pin. + void set_pin_direction_(uint8_t pin, gpio::Flags flags); + +#ifdef TEST_COMPONENT + /// @defgroup test_ Test component information + /// @brief Contains information about the auto-tests of the component + /// @{ + void test_gpio_input_(); + void test_gpio_output_(); + /// @} +#endif + + uint8_t pin_config_{0x00}; ///< pin config mask: 1 means OUTPUT, 0 means INPUT + uint8_t output_state_{0x00}; ///< output state: 1 means HIGH, 0 means LOW + uint8_t input_state_{0x00}; ///< input pin states: 1 means HIGH, 0 means LOW + uint32_t crystal_; ///< crystal value; + int test_mode_; ///< test mode value (0 -> no tests) + bool page1_{false}; ///< set to true when in "page1 mode" + std::vector children_{}; ///< the list of WeikaiChannel UART children + std::string name_; ///< name of entity +}; + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Helper class to expose a WeiKai family IO pin as an internal GPIO pin. +/////////////////////////////////////////////////////////////////////////////// +class WeikaiGPIOPin : public GPIOPin { + public: + void set_parent(WeikaiComponent *parent) { this->parent_ = parent; } + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } + + void setup() override; + std::string dump_summary() const override; + void pin_mode(gpio::Flags flags) override { this->parent_->set_pin_direction_(this->pin_, flags); } + bool digital_read() override { return this->parent_->read_pin_val_(this->pin_) != this->inverted_; } + void digital_write(bool value) override { this->parent_->write_pin_val_(this->pin_, value != this->inverted_); } + + protected: + WeikaiComponent *parent_{nullptr}; + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief The WeikaiChannel class is used to implement all the virtual methods of the ESPHome +/// uart::UARTComponent virtual class. This class is common to the different members of the Weikai +/// components family and therefore avoid code duplication. +/////////////////////////////////////////////////////////////////////////////////////////////////// +class WeikaiChannel : public uart::UARTComponent { + public: + /// @brief We belongs to this WeikaiComponent + /// @param parent pointer to the component we belongs to + void set_parent(WeikaiComponent *parent) { + this->parent_ = parent; + this->parent_->children_.push_back(this); // add ourself to the list (vector) + } + + /// @brief Sets the channel number + /// @param channel number + void set_channel(uint8_t channel) { this->channel_ = channel; } + + /// @brief The name as generated by the Python code generator + /// @param name of the channel + void set_channel_name(std::string name) { this->name_ = std::move(name); } + + /// @brief Get the channel name + /// @return the name + const char *get_channel_name() { return this->name_.c_str(); } + + /// @brief Setup the channel + void virtual setup_channel(); + + /// @brief dump channel information + void virtual dump_channel(); + + /// @brief Factory method to create a WeikaiRegister proxy object + /// @param reg address of the register + /// @return a reference to WeikaiRegister + WeikaiRegister ®(uint8_t reg) { return this->parent_->reg(reg, channel_); } + + // + // we implements/overrides the virtual class from UARTComponent + // + + /// @brief Writes a specified number of bytes to a serial port + /// @param buffer pointer to the buffer + /// @param length number of bytes to write + /// @details This method sends 'length' characters from the buffer to the serial line. Unfortunately (unlike the + /// Arduino equivalent) this method does not return any flag and therefore it is not possible to know if any/all bytes + /// have been transmitted correctly. Another problem is that it is not possible to know ahead of time how many bytes + /// we can safely send as there is no tx_available() method provided! To avoid overrun when using the write method you + /// can use the flush() method to wait until the transmit fifo is empty. + /// @n Typical usage could be: + /// @code + /// // ... + /// uint8_t buffer[128]; + /// // ... + /// write_array(&buffer, length); + /// flush(); + /// // ... + /// @endcode + void write_array(const uint8_t *buffer, size_t length) override; + + /// @brief Reads a specified number of bytes from a serial port + /// @param buffer buffer to store the bytes + /// @param length number of bytes to read + /// @return true if succeed, false otherwise + /// @details Typical usage: + /// @code + /// // ... + /// auto length = available(); + /// uint8_t buffer[128]; + /// if (length > 0) { + /// auto status = read_array(&buffer, length) + /// // test status ... + /// } + /// @endcode + bool read_array(uint8_t *buffer, size_t length) override; + + /// @brief Reads the first byte in FIFO without removing it + /// @param buffer pointer to the byte + /// @return true if succeed reading one byte, false if no character available + /// @details This method returns the next byte from receiving buffer without removing it from the internal fifo. It + /// returns true if a character is available and has been read, false otherwise.\n + bool peek_byte(uint8_t *buffer) override; + + /// @brief Returns the number of bytes in the receive buffer + /// @return the number of bytes available in the receiver fifo + int available() override; + + /// @brief Flush the output fifo. + /// @details If we refer to Serial.flush() in Arduino it says: ** Waits for the transmission of outgoing serial data + /// to complete. (Prior to Arduino 1.0, this the method was removing any buffered incoming serial data.). ** Therefore + /// we wait until all bytes are gone with a timeout of 100 ms + void flush() override; + + protected: + friend class WeikaiComponent; + + /// @brief this cannot happen with external uart therefore we do nothing + void check_logger_conflict() override {} + + /// @brief reset the weikai internal FIFO + void reset_fifo_(); + + /// @brief set the line parameters + void set_line_param_(); + + /// @brief set the baud rate + void set_baudrate_(); + + /// @brief Returns the number of bytes in the receive fifo + /// @return the number of bytes in the fifo + size_t rx_in_fifo_(); + + /// @brief Returns the number of bytes in the transmit fifo + /// @return the number of bytes in the fifo + size_t tx_in_fifo_(); + + /// @brief test if transmit buffer is not empty in the status register (optimization) + /// @return true if not emptygroup test_ + bool tx_fifo_is_not_empty_(); + + /// @brief transfer bytes from the weikai internal FIFO to the buffer (if any) + /// @return number of bytes transferred + size_t xfer_fifo_to_buffer_(); + + /// @brief check if channel is alive + /// @return true if OK + bool virtual check_channel_down(); + +#ifdef TEST_COMPONENT + /// @ingroup test_ + /// @{ + + /// @brief Test the write_array() method + /// @param message to display + void uart_send_test_(char *message); + + /// @brief Test the read_array() method + /// @param message to display + /// @return true if success + bool uart_receive_test_(char *message); + /// @} +#endif + + /// @brief the buffer where we store temporarily the bytes received + WKRingBuffer receive_buffer_; + WeikaiComponent *parent_; ///< our WK2168component parent + uint8_t channel_; ///< our Channel number + uint8_t data_; ///< a one byte buffer for register read storage + std::string name_; ///< name of the entity +}; + +} // namespace weikai +} // namespace esphome diff --git a/esphome/components/weikai/wk_reg_def.h b/esphome/components/weikai/wk_reg_def.h new file mode 100644 index 0000000000..f3c90b196a --- /dev/null +++ b/esphome/components/weikai/wk_reg_def.h @@ -0,0 +1,304 @@ +/// @file wk_reg_def.h +/// @author DrCoolZic +/// @brief WeiKai component family - registers' definition +/// @date Last Modified: 2024/02/18 15:49:18 +#pragma once + +namespace esphome { +namespace weikai { + +//////////////////////////////////////////////////////////////////////////////////////// +/// Definition of the WeiKai registers +//////////////////////////////////////////////////////////////////////////////////////// + +/// @defgroup wk2168_gr_ WeiKai Global Registers +/// This section groups all **Global Registers**: these registers are global to the +/// the WeiKai chip (i.e. independent of the UART channel used) +/// @note only registers and parameters used have been fully documented +/// @{ + +/// @brief Global Control Register - 00 0000 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | M0 | M1 | RSV | C4EN | C3EN | C2EN | C1EN | name +/// ------------------------------------------------------------------------- +/// | R | R | R | R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_GENA = 0x00; +/// @brief Channel 4 enable clock (0: disable, 1: enable) +constexpr uint8_t GENA_C4EN = 1 << 3; +/// @brief Channel 3 enable clock (0: disable, 1: enable) +constexpr uint8_t GENA_C3EN = 1 << 2; +/// @brief Channel 2 enable clock (0: disable, 1: enable) +constexpr uint8_t GENA_C2EN = 1 << 1; +/// @brief Channel 1 enable clock (0: disable, 1: enable) +constexpr uint8_t GENA_C1EN = 1 << 0; + +/// @brief Global Reset Register - 00 0001 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | C4SLEEP| C3SLEEP| C2SLEEP| C1SLEEP| C4RST | C3RST | C2RST | C1RST | name +/// ------------------------------------------------------------------------- +/// | R | R | R | R | W1/R0 | W1/R0 | W1/R0 | W1/R0 | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_GRST = 0x01; +/// @brief Channel 4 soft reset (0: not reset, 1: reset) +constexpr uint8_t GRST_C4RST = 1 << 3; +/// @brief Channel 3 soft reset (0: not reset, 1: reset) +constexpr uint8_t GRST_C3RST = 1 << 2; +/// @brief Channel 2 soft reset (0: not reset, 1: reset) +constexpr uint8_t GRST_C2RST = 1 << 1; +/// @brief Channel 1 soft reset (0: not reset, 1: reset) +constexpr uint8_t GRST_C1RST = 1 << 0; + +/// @brief Global Master channel control register (not used) - 000010 +constexpr uint8_t WKREG_GMUT = 0x02; + +/// Global interrupt register (not used) - 01 0000 +constexpr uint8_t WKREG_GIER = 0x10; + +/// Global interrupt flag register (not used) 01 0001 +constexpr uint8_t WKREG_GIFR = 0x11; + +/// @brief Global GPIO direction register - 10 0001 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 | name +/// ------------------------------------------------------------------------- +/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_GPDIR = 0x21; + +/// @brief Global GPIO data register - 11 0001 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | PV7 | PV6 | PV5 | PV4 | PV3 | PV2 | PV1 | PV0 | name +/// ------------------------------------------------------------------------- +/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_GPDAT = 0x31; + +/// @} +/// @defgroup WeiKai_cr_ WeiKai Channel Registers +/// @brief Definition of the register linked to a particular channel +/// @details This topic groups all the **Channel Registers**: these registers are specific +/// to the a specific channel i.e. each channel has its own set of registers +/// @note only registers and parameters used have been documented +/// @{ + +/// @defgroup cr_p0 Channel registers when SPAGE=0 +/// @brief Definition of the register linked to a particular channel when SPAGE=0 +/// @details The channel registers are further splitted into two groups. +/// This first group is defined when the Global register WKREG_SPAGE is 0 +/// @{ + +/// @brief Global Page register c0/c1 0011 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | RSV | PAGE | name +/// ------------------------------------------------------------------------- +/// | R | R | R | R | R | R | R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_SPAGE = 0x03; + +/// @brief Serial Control Register - c0/c1 0100 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | RSV | SLPEN | TXEN | RXEN | name +/// ------------------------------------------------------------------------- +/// | R | R | R | R | R | R/W | R/W | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_SCR = 0x04; +/// @brief transmission control (0: enable, 1: disable) +constexpr uint8_t SCR_TXEN = 1 << 1; +/// @brief receiving control (0: enable, 1: disable) +constexpr uint8_t SCR_RXEN = 1 << 0; + +/// @brief Line Configuration Register - c0/c1 0101 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | RSV | BREAK | IREN | PAEN | PARITY | STPL | name +/// ------------------------------------------------------------------------- +/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_LCR = 0x05; +/// @brief Parity enable (0: no check, 1: check) +constexpr uint8_t LCR_PAEN = 1 << 3; +/// @brief Parity force 0 +constexpr uint8_t LCR_PAR_F0 = 0 << 1; +/// @brief Parity odd +constexpr uint8_t LCR_PAR_ODD = 1 << 1; +/// @brief Parity even +constexpr uint8_t LCR_PAR_EVEN = 2 << 1; +/// @brief Parity force 1 +constexpr uint8_t LCR_PAR_F1 = 3 << 1; +/// @brief Stop length (0: 1 bit, 1: 2 bits) +constexpr uint8_t LCR_STPL = 1 << 0; + +/// @brief FIFO Control Register - c0/c1 0110 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | TFTRIG | RFTRIG | TFEN | RFEN | TFRST | RFRST | name +/// ------------------------------------------------------------------------- +/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_FCR = 0x06; +/// @brief Transmitter FIFO enable +constexpr uint8_t FCR_TFEN = 1 << 3; +/// @brief Receiver FIFO enable +constexpr uint8_t FCR_RFEN = 1 << 2; +/// @brief Transmitter FIFO reset +constexpr uint8_t FCR_TFRST = 1 << 1; +/// @brief Receiver FIFO reset +constexpr uint8_t FCR_RFRST = 1 << 0; + +/// @brief Serial Interrupt Enable Register (not used) - c0/c1 0111 +constexpr uint8_t WKREG_SIER = 0x07; + +/// @brief Serial Interrupt Flag Register (not used) - c0/c1 1000 +constexpr uint8_t WKREG_SIFR = 0x08; + +/// @brief Transmitter FIFO Count - c0/c1 1001 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | +/// ------------------------------------------------------------------------- +/// | NUMBER OF DATA IN TRANSMITTER FIFO | +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_TFCNT = 0x09; + +/// @brief Receiver FIFO count - c0/c1 1010 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | +/// ------------------------------------------------------------------------- +/// | NUMBER OF DATA IN RECEIVER FIFO | +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_RFCNT = 0x0A; + +/// @brief FIFO Status Register - c0/c1 1011 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit +/// ------------------------------------------------------------------------- +/// | RFOE | RFLB | RFFE | RFPE | RFDAT | TFDAT | TFFULL | TBUSY | name +/// ------------------------------------------------------------------------- +/// | R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type +/// ------------------------------------------------------------------------- +/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset +/// ------------------------------------------------------------------------- +/// @endcode +/// @warning The received buffer can hold 256 bytes. However, as the RFCNT reg +/// is 8 bits, if we have 256 byte in the register this is reported as 0 ! Therefore +/// RFCNT=0 can indicate that there are 0 **or** 256 bytes in the buffer. If we +/// have RFDAT = 1 and RFCNT = 0 it should be interpreted as 256 bytes in the FIFO. +/// @note Note that in case of overflow the RFOE goes to one **but** as soon as you read +/// the FSR this bit is cleared. Therefore Overflow can be read only once. +/// @n The same problem applies to the transmit buffer but here we have to check the +/// TFFULL flag. So if TFFULL is set and TFCNT is 0 this should be interpreted as 256 +constexpr uint8_t WKREG_FSR = 0x0B; +/// @brief Receiver FIFO Overflow Error (0: no OE, 1: OE) +constexpr uint8_t FSR_RFOE = 1 << 7; +/// @brief Receiver FIFO Line Break (0: no LB, 1: LB) +constexpr uint8_t FSR_RFLB = 1 << 6; +/// @brief Receiver FIFO Frame Error (0: no FE, 1: FE) +constexpr uint8_t FSR_RFFE = 1 << 5; +/// @brief Receiver Parity Error (0: no PE, 1: PE) +constexpr uint8_t FSR_RFPE = 1 << 4; +/// @brief Receiver FIFO count (0: empty, 1: not empty) +constexpr uint8_t FSR_RFDAT = 1 << 3; +/// @brief Transmitter FIFO count (0: empty, 1: not empty) +constexpr uint8_t FSR_TFDAT = 1 << 2; +/// @brief Transmitter FIFO full (0: not full, 1: full) +constexpr uint8_t FSR_TFFULL = 1 << 1; +/// @brief Transmitter busy (0 nothing to transmit, 1: transmitter busy sending) +constexpr uint8_t FSR_TBUSY = 1 << 0; + +/// @brief Line Status Register (not used - using FIFO) +constexpr uint8_t WKREG_LSR = 0x0C; + +/// @brief FIFO Data Register (not used - does not seems to work) +constexpr uint8_t WKREG_FDAT = 0x0D; + +/// @} +/// @defgroup cr_p1 Channel registers for SPAGE=1 +/// @brief Definition of the register linked to a particular channel when SPAGE=1 +/// @details The channel registers are further splitted into two groups. +/// This second group is defined when the Global register WKREG_SPAGE is 1 +/// @{ + +/// @brief Baud rate configuration register: high byte - c0/c1 0100 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | +/// ------------------------------------------------------------------------- +/// | High byte of the baud rate | +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_BRH = 0x04; + +/// @brief Baud rate configuration register: low byte - c0/c1 0101 +/// @details @code +/// ------------------------------------------------------------------------- +/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | +/// ------------------------------------------------------------------------- +/// | Low byte of the baud rate | +/// ------------------------------------------------------------------------- +/// @endcode +constexpr uint8_t WKREG_BRL = 0x05; + +/// @brief Baud rate configuration register decimal part - c0/c1 0110 +constexpr uint8_t WKREG_BRD = 0x06; + +/// @brief Receive FIFO Interrupt trigger configuration (not used) - c0/c1 0111 +constexpr uint8_t WKREG_RFI = 0x07; + +/// @brief Transmit FIFO interrupt trigger configuration (not used) - c0/c1 1000 +constexpr uint8_t WKREG_TFI = 0x08; + +/// @} +/// @} +} // namespace weikai +} // namespace esphome diff --git a/esphome/components/weikai_i2c/__init__.py b/esphome/components/weikai_i2c/__init__.py new file mode 100644 index 0000000000..2c6a421a0a --- /dev/null +++ b/esphome/components/weikai_i2c/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@DrCoolZic"] diff --git a/esphome/components/weikai_i2c/weikai_i2c.cpp b/esphome/components/weikai_i2c/weikai_i2c.cpp new file mode 100644 index 0000000000..9d0c9446ec --- /dev/null +++ b/esphome/components/weikai_i2c/weikai_i2c.cpp @@ -0,0 +1,177 @@ +/// @file weikai_i2c.cpp +/// @brief WeiKai component family - classes implementation +/// @date Last Modified: 2024/04/06 14:43:31 +/// @details The classes declared in this file can be used by the Weikai family + +#include "weikai_i2c.h" + +namespace esphome { +namespace weikai_i2c { +static const char *const TAG = "weikai_i2c"; + +/// @brief Display a buffer in hexadecimal format (32 hex values / line). +void print_buffer(const uint8_t *data, size_t length) { + char hex_buffer[100]; + hex_buffer[(3 * 32) + 1] = 0; + for (size_t i = 0; i < length; i++) { + snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); + if (i % 32 == 31) { + ESP_LOGVV(TAG, " %s", hex_buffer); + } + } + if (length % 32) { + // null terminate if incomplete line + hex_buffer[3 * (length % 32) + 2] = 0; + ESP_LOGVV(TAG, " %s", hex_buffer); + } +} + +static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER", + "SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"}; +static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", + "TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"}; +using namespace weikai; +// method to print a register value as text: used in the log messages ... +const char *reg_to_str(int reg, bool page1) { + if (reg == WKREG_GPDAT) { + return "GPDAT"; + } else if (reg == WKREG_GPDIR) { + return "GPDIR"; + } else { + return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; + } +} +enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO + +/// @brief Computes the I²C bus's address used to access the component +/// @param base_address the base address of the component - set by the A1 A0 pins +/// @param channel (0-3) the UART channel +/// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo +/// @return the i2c address to use +inline uint8_t i2c_address(uint8_t base_address, uint8_t channel, RegType fifo) { + // the address of the device is: + // +----+----+----+----+----+----+----+----+ + // | 0 | A1 | A0 | 1 | 0 | C1 | C0 | F | + // +----+----+----+----+----+----+----+----+ + // where: + // - A1,A0 is the address read from A1,A0 switch + // - C1,C0 is the channel number (in practice only 00 or 01) + // - F is: 0 when accessing register, one when accessing FIFO + uint8_t const addr = base_address | channel << 1 | fifo << 0; + return addr; +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiRegisterI2C methods +/////////////////////////////////////////////////////////////////////////////// +uint8_t WeikaiRegisterI2C::read_reg() const { + uint8_t value = 0x00; + WeikaiComponentI2C *comp_i2c = static_cast(this->comp_); + uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG); + comp_i2c->set_i2c_address(address); + auto error = comp_i2c->read_register(this->register_, &value, 1); + if (error == i2c::NO_ERROR) { + this->comp_->status_clear_warning(); + ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address, + reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); + } else { // error + this->comp_->status_set_warning(); + ESP_LOGE(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address, + reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); + } + return value; +} + +void WeikaiRegisterI2C::read_fifo(uint8_t *data, size_t length) const { + WeikaiComponentI2C *comp_i2c = static_cast(this->comp_); + uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO); + comp_i2c->set_i2c_address(address); + auto error = comp_i2c->read(data, length); + if (error == i2c::NO_ERROR) { + this->comp_->status_clear_warning(); +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE + ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_, + (int) error, length); + print_buffer(data, length); +#endif + } else { // error + this->comp_->status_set_warning(); + ESP_LOGE(TAG, "WeikaiRegisterI2C::read_fifo() @%02X reg=N/A ch=%d I2C_code:%d len=%d buf=%02X...", address, + this->channel_, (int) error, length, data[0]); + } +} + +void WeikaiRegisterI2C::write_reg(uint8_t value) { + WeikaiComponentI2C *comp_i2c = static_cast(this->comp_); + uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG); // update the i2c bus + comp_i2c->set_i2c_address(address); + auto error = comp_i2c->write_register(this->register_, &value, 1); + if (error == i2c::NO_ERROR) { + this->comp_->status_clear_warning(); + ESP_LOGVV(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%02X", address, + reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); + } else { // error + this->comp_->status_set_warning(); + ESP_LOGE(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%d", address, + reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); + } +} + +void WeikaiRegisterI2C::write_fifo(uint8_t *data, size_t length) { + WeikaiComponentI2C *comp_i2c = static_cast(this->comp_); + uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO); // set fifo flag + comp_i2c->set_i2c_address(address); + auto error = comp_i2c->write(data, length); + if (error == i2c::NO_ERROR) { + this->comp_->status_clear_warning(); +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE + ESP_LOGVV(TAG, "WK2168Reg::write_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_, + (int) error, length); + print_buffer(data, length); +#endif + } else { // error + this->comp_->status_set_warning(); + ESP_LOGE(TAG, "WK2168Reg::write_fifo() @%02X reg=N/A, ch=%d I2C_code:%d len=%d, buf=%02X...", address, + this->channel_, (int) error, length, data[0]); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiComponentI2C methods +/////////////////////////////////////////////////////////////////////////////// +void WeikaiComponentI2C::setup() { + // before any manipulation we store the address to base_address_ for future use + this->base_address_ = this->address_; + ESP_LOGCONFIG(TAG, "Setting up wk2168_i2c: %s with %d UARTs at @%02X ...", this->get_name(), this->children_.size(), + this->base_address_); + + // enable all channels + this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN; + // reset all channels + this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST; + // initialize the spage register to page 0 + this->reg(WKREG_SPAGE, 0) = 0; + this->page1_ = false; + + // we setup our children channels + for (auto *child : this->children_) { + child->setup_channel(); + } +} + +void WeikaiComponentI2C::dump_config() { + ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); + ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32, this->crystal_); + if (test_mode_) + ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_); + ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE); + this->address_ = this->base_address_; // we restore the base_address before display (less confusing) + LOG_I2C_DEVICE(this); + + for (auto *child : this->children_) { + child->dump_channel(); + } +} + +} // namespace weikai_i2c +} // namespace esphome diff --git a/esphome/components/weikai_i2c/weikai_i2c.h b/esphome/components/weikai_i2c/weikai_i2c.h new file mode 100644 index 0000000000..0da9ed9cde --- /dev/null +++ b/esphome/components/weikai_i2c/weikai_i2c.h @@ -0,0 +1,61 @@ +/// @file weikai_i2c.h +/// @author DrCoolZic +/// @brief WeiKai component family - classes declaration +/// @date Last Modified: 2024/03/01 13:31:57 +/// @details The classes declared in this file can be used by the Weikai family +/// wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c + +#pragma once +#include +#include +#include "esphome/core/component.h" +#include "esphome/components/uart/uart.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/weikai/weikai.h" + +namespace esphome { +namespace weikai_i2c { + +class WeikaiComponentI2C; + +// using namespace weikai; +//////////////////////////////////////////////////////////////////////////////////// +/// @brief WeikaiRegisterI2C objects acts as proxies to access remote register through an I2C Bus +//////////////////////////////////////////////////////////////////////////////////// +class WeikaiRegisterI2C : public weikai::WeikaiRegister { + public: + uint8_t read_reg() const override; + void write_reg(uint8_t value) override; + void read_fifo(uint8_t *data, size_t length) const override; + void write_fifo(uint8_t *data, size_t length) override; + + protected: + friend WeikaiComponentI2C; + WeikaiRegisterI2C(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel) + : weikai::WeikaiRegister(comp, reg, channel) {} +}; + +//////////////////////////////////////////////////////////////////////////////////// +/// @brief The WeikaiComponentI2C class stores the information to the WeiKai component +/// connected through an I2C bus. +//////////////////////////////////////////////////////////////////////////////////// +class WeikaiComponentI2C : public weikai::WeikaiComponent, public i2c::I2CDevice { + public: + weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override { + reg_i2c_.register_ = reg; + reg_i2c_.channel_ = channel; + return reg_i2c_; + } + + // + // override Component methods + // + void setup() override; + void dump_config() override; + + uint8_t base_address_; ///< base address of I2C device + WeikaiRegisterI2C reg_i2c_{this, 0, 0}; ///< init to this component +}; + +} // namespace weikai_i2c +} // namespace esphome diff --git a/esphome/components/weikai_spi/__init__.py b/esphome/components/weikai_spi/__init__.py new file mode 100644 index 0000000000..2c6a421a0a --- /dev/null +++ b/esphome/components/weikai_spi/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@DrCoolZic"] diff --git a/esphome/components/weikai_spi/weikai_spi.cpp b/esphome/components/weikai_spi/weikai_spi.cpp new file mode 100644 index 0000000000..22c63bbd2d --- /dev/null +++ b/esphome/components/weikai_spi/weikai_spi.cpp @@ -0,0 +1,189 @@ +/// @file weikai_spi.cpp +/// @brief WeiKai component family - classes implementation +/// @date Last Modified: 2024/04/06 14:46:09 +/// @details The classes declared in this file can be used by the Weikai family + +#include "weikai_spi.h" + +namespace esphome { +namespace weikai_spi { +using namespace weikai; +static const char *const TAG = "weikai_spi"; + +/// @brief convert an int to binary representation as C++ std::string +/// @param val integer to convert +/// @return a std::string +inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); } +/// Convert std::string to C string +#define I2S2CS(val) (i2s(val).c_str()) + +/// @brief measure the time elapsed between two calls +/// @param last_time time of the previous call +/// @return the elapsed time in microseconds +uint32_t elapsed_ms(uint32_t &last_time) { + uint32_t e = millis() - last_time; + last_time = millis(); + return e; +}; + +/// @brief Converts the parity enum value to a C string +/// @param parity enum +/// @return the string +const char *p2s(uart::UARTParityOptions parity) { + using namespace uart; + switch (parity) { + case UART_CONFIG_PARITY_NONE: + return "NONE"; + case UART_CONFIG_PARITY_EVEN: + return "EVEN"; + case UART_CONFIG_PARITY_ODD: + return "ODD"; + default: + return "UNKNOWN"; + } +} + +/// @brief Display a buffer in hexadecimal format (32 hex values / line). +void print_buffer(const uint8_t *data, size_t length) { + char hex_buffer[100]; + hex_buffer[(3 * 32) + 1] = 0; + for (size_t i = 0; i < length; i++) { + snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); + if (i % 32 == 31) { + ESP_LOGVV(TAG, " %s", hex_buffer); + } + } + if (length % 32) { + // null terminate if incomplete line + hex_buffer[3 * (length % 32) + 2] = 0; + ESP_LOGVV(TAG, " %s", hex_buffer); + } +} + +static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER", + "SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"}; +static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", + "TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"}; + +// method to print a register value as text: used in the log messages ... +const char *reg_to_str(int reg, bool page1) { + if (reg == WKREG_GPDAT) { + return "GPDAT"; + } else if (reg == WKREG_GPDIR) { + return "GPDIR"; + } else { + return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; + } +} + +enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO +enum CmdType { WRITE_CMD = 0, READ_CMD = 1 }; ///< Read or Write transfer + +/// @brief Computes the SPI command byte +/// @param transfer_type read or write command +/// @param reg (0-15) the address of the register +/// @param channel (0-3) the UART channel +/// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo +/// @return the spi command byte +/// @details +/// +------+------+------+------+------+------+------+------+ +/// | FIFO | R/W | C1-C0 | A3-A0 | +/// +------+------+-------------+---------------------------+ +/// FIFO: 0 = register, 1 = FIFO +/// R/W: 0 = write, 1 = read +/// C1-C0: Channel (0-1) +/// A3-A0: Address (0-F) +inline static uint8_t cmd_byte(RegType fifo, CmdType transfer_type, uint8_t channel, uint8_t reg) { + return (fifo << 7 | transfer_type << 6 | channel << 4 | reg << 0); +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiRegisterSPI methods +/////////////////////////////////////////////////////////////////////////////// +uint8_t WeikaiRegisterSPI::read_reg() const { + auto *spi_comp = static_cast(this->comp_); + uint8_t cmd = cmd_byte(REG, READ_CMD, this->channel_, this->register_); + spi_comp->enable(); + spi_comp->write_byte(cmd); + uint8_t val = spi_comp->read_byte(); + spi_comp->disable(); + ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(cmd), cmd, + reg_to_str(this->register_, this->comp_->page1()), this->channel_, val); + return val; +} + +void WeikaiRegisterSPI::read_fifo(uint8_t *data, size_t length) const { + auto *spi_comp = static_cast(this->comp_); + uint8_t cmd = cmd_byte(FIFO, READ_CMD, this->channel_, this->register_); + spi_comp->enable(); + spi_comp->write_byte(cmd); + spi_comp->read_array(data, length); + spi_comp->disable(); +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE + ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_, + length); + print_buffer(data, length); +#endif +} + +void WeikaiRegisterSPI::write_reg(uint8_t value) { + auto *spi_comp = static_cast(this->comp_); + uint8_t buf[2]{cmd_byte(REG, WRITE_CMD, this->channel_, this->register_), value}; + spi_comp->enable(); + spi_comp->write_array(buf, 2); + spi_comp->disable(); + ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(buf[0]), buf[0], + reg_to_str(this->register_, this->comp_->page1()), this->channel_, buf[1]); +} + +void WeikaiRegisterSPI::write_fifo(uint8_t *data, size_t length) { + auto *spi_comp = static_cast(this->comp_); + uint8_t cmd = cmd_byte(FIFO, WRITE_CMD, this->channel_, this->register_); + spi_comp->enable(); + spi_comp->write_byte(cmd); + spi_comp->write_array(data, length); + spi_comp->disable(); + +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE + ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_, + length); + print_buffer(data, length); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// The WeikaiComponentSPI methods +/////////////////////////////////////////////////////////////////////////////// +void WeikaiComponentSPI::setup() { + using namespace weikai; + ESP_LOGCONFIG(TAG, "Setting up wk2168_spi: %s with %d UARTs...", this->get_name(), this->children_.size()); + this->spi_setup(); + // enable all channels + this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN; + // reset all channels + this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST; + // initialize the spage register to page 0 + this->reg(WKREG_SPAGE, 0) = 0; + this->page1_ = false; + + // we setup our children channels + for (auto *child : this->children_) { + child->setup_channel(); + } +} + +void WeikaiComponentSPI::dump_config() { + ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); + ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32 "", this->crystal_); + if (test_mode_) + ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_); + ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE); + LOG_PIN(" CS Pin: ", this->cs_); + + for (auto *child : this->children_) { + child->dump_channel(); + } +} + +} // namespace weikai_spi +} // namespace esphome diff --git a/esphome/components/weikai_spi/weikai_spi.h b/esphome/components/weikai_spi/weikai_spi.h new file mode 100644 index 0000000000..dd0dc8d495 --- /dev/null +++ b/esphome/components/weikai_spi/weikai_spi.h @@ -0,0 +1,54 @@ +/// @file weikai.h +/// @author DrCoolZic +/// @brief WeiKai component family - classes declaration +/// @date Last Modified: 2024/02/29 17:20:32 +/// @details The classes declared in this file can be used by the Weikai family +/// wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi, + +#pragma once +#include +#include +#include "esphome/core/component.h" +#include "esphome/components/uart/uart.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/weikai/weikai.h" + +namespace esphome { +namespace weikai_spi { +//////////////////////////////////////////////////////////////////////////////////// +/// @brief WeikaiRegisterSPI objects acts as proxies to access remote register through an SPI Bus +//////////////////////////////////////////////////////////////////////////////////// +class WeikaiRegisterSPI : public weikai::WeikaiRegister { + public: + WeikaiRegisterSPI(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel) + : weikai::WeikaiRegister(comp, reg, channel) {} + + uint8_t read_reg() const override; + void write_reg(uint8_t value) override; + void read_fifo(uint8_t *data, size_t length) const override; + void write_fifo(uint8_t *data, size_t length) override; +}; + +//////////////////////////////////////////////////////////////////////////////////// +/// @brief The WeikaiComponentSPI class stores the information to the WeiKai component +/// connected through an SPI bus. +//////////////////////////////////////////////////////////////////////////////////// +class WeikaiComponentSPI : public weikai::WeikaiComponent, + public spi::SPIDevice { + public: + weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override { + reg_spi_.register_ = reg; + reg_spi_.channel_ = channel; + return reg_spi_; + } + + void setup() override; + void dump_config() override; + + protected: + WeikaiRegisterSPI reg_spi_{this, 0, 0}; ///< init to this component +}; + +} // namespace weikai_spi +} // namespace esphome diff --git a/esphome/components/wk2132_i2c/__init__.py b/esphome/components/wk2132_i2c/__init__.py new file mode 100644 index 0000000000..912ab04236 --- /dev/null +++ b/esphome/components/wk2132_i2c/__init__.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, weikai +from esphome.const import CONF_ID + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["i2c"] +AUTO_LOAD = ["weikai", "weikai_i2c"] +MULTI_CONF = True + +weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") +WeikaiComponentI2C = weikai_i2c_ns.class_( + "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), + } + ).extend(i2c.i2c_device_schema(0x2C)), + weikai.check_channel_max_2, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/wk2132_i2c/wk2132_i2c.cpp b/esphome/components/wk2132_i2c/wk2132_i2c.cpp new file mode 100644 index 0000000000..aaefae6f97 --- /dev/null +++ b/esphome/components/wk2132_i2c/wk2132_i2c.cpp @@ -0,0 +1,4 @@ +/* compiling with esp-idf framework requires a .cpp file for some reason ? */ +namespace esphome { +namespace wk2132_i2c {} +} // namespace esphome diff --git a/esphome/components/wk2132_spi/__init__.py b/esphome/components/wk2132_spi/__init__.py new file mode 100644 index 0000000000..02c5fd9604 --- /dev/null +++ b/esphome/components/wk2132_spi/__init__.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi, weikai + +from esphome.const import CONF_ID + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["spi"] +AUTO_LOAD = ["weikai", "weikai_spi"] +MULTI_CONF = True + +weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") +WeikaiComponentSPI = weikai_spi_ns.class_( + "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentSPI), + } + ).extend(spi.spi_device_schema()), + weikai.check_channel_max_2, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/wk2168_i2c/__init__.py b/esphome/components/wk2168_i2c/__init__.py new file mode 100644 index 0000000000..93a8161e8e --- /dev/null +++ b/esphome/components/wk2168_i2c/__init__.py @@ -0,0 +1,64 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import i2c, weikai +from esphome.const import ( + CONF_ID, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, +) + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["i2c"] +AUTO_LOAD = ["weikai", "weikai_i2c"] +MULTI_CONF = True +CONF_WK2168_I2C = "wk2168_i2c" + +weikai_ns = cg.esphome_ns.namespace("weikai") +weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") +WeikaiComponentI2C = weikai_i2c_ns.class_( + "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice +) +WeikaiGPIOPin = weikai_ns.class_( + "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C) +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), + } + ).extend(i2c.i2c_device_schema(0x2C)), + weikai.check_channel_max_4, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await i2c.register_i2c_device(var, config) + + +WK2168_PIN_SCHEMA = cv.All( + weikai.WEIKAI_PIN_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), + cv.Required(CONF_WK2168_I2C): cv.use_id(WeikaiComponentI2C), + } + ), + weikai.validate_pin_mode, +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_I2C, WK2168_PIN_SCHEMA) +async def sc16is75x_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_WK2168_I2C]) + cg.add(var.set_parent(parent)) + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/wk2168_spi/__init__.py b/esphome/components/wk2168_spi/__init__.py new file mode 100644 index 0000000000..8861a6738c --- /dev/null +++ b/esphome/components/wk2168_spi/__init__.py @@ -0,0 +1,62 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import spi, weikai +from esphome.const import ( + CONF_ID, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, +) + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["spi"] +AUTO_LOAD = ["weikai", "weikai_spi"] +MULTI_CONF = True +CONF_WK2168_SPI = "wk2168_spi" + +weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") +weikai_ns = cg.esphome_ns.namespace("weikai") +WeikaiComponentSPI = weikai_spi_ns.class_( + "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice +) +WeikaiGPIOPin = weikai_ns.class_( + "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI) +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + {cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)} + ).extend(spi.spi_device_schema()), + weikai.check_channel_max_4, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await spi.register_spi_device(var, config) + + +WK2168_PIN_SCHEMA = cv.All( + weikai.WEIKAI_PIN_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), + cv.Required(CONF_WK2168_SPI): cv.use_id(WeikaiComponentSPI), + }, + ), + weikai.validate_pin_mode, +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_SPI, WK2168_PIN_SCHEMA) +async def sc16is75x_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_WK2168_SPI]) + cg.add(var.set_parent(parent)) + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/wk2204_i2c/__init__.py b/esphome/components/wk2204_i2c/__init__.py new file mode 100644 index 0000000000..98eca56c4d --- /dev/null +++ b/esphome/components/wk2204_i2c/__init__.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, weikai +from esphome.const import CONF_ID + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["i2c"] +AUTO_LOAD = ["weikai", "weikai_i2c"] +MULTI_CONF = True + +weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") +WeikaiComponentI2C = weikai_i2c_ns.class_( + "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), + } + ).extend(i2c.i2c_device_schema(0x2C)), + weikai.check_channel_max_4, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/wk2204_spi/__init__.py b/esphome/components/wk2204_spi/__init__.py new file mode 100644 index 0000000000..447805375d --- /dev/null +++ b/esphome/components/wk2204_spi/__init__.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi, weikai +from esphome.const import CONF_ID + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["spi"] +AUTO_LOAD = ["weikai", "weikai_spi"] +MULTI_CONF = True + +weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") +WeikaiComponentSPI = weikai_spi_ns.class_( + "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentSPI), + } + ).extend(spi.spi_device_schema()), + weikai.check_channel_max_4, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/wk2212_i2c/__init__.py b/esphome/components/wk2212_i2c/__init__.py new file mode 100644 index 0000000000..fd4d717b31 --- /dev/null +++ b/esphome/components/wk2212_i2c/__init__.py @@ -0,0 +1,64 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import i2c, weikai +from esphome.const import ( + CONF_ID, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, +) + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["i2c"] +AUTO_LOAD = ["weikai", "weikai_i2c"] +MULTI_CONF = True +CONF_WK2212_I2C = "wk2212_i2c" + +weikai_ns = cg.esphome_ns.namespace("weikai") +weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") +WeikaiComponentI2C = weikai_i2c_ns.class_( + "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice +) +WeikaiGPIOPin = weikai_ns.class_( + "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C) +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), + } + ).extend(i2c.i2c_device_schema(0x2C)), + weikai.check_channel_max_2, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await i2c.register_i2c_device(var, config) + + +WK2212_PIN_SCHEMA = cv.All( + weikai.WEIKAI_PIN_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), + cv.Required(CONF_WK2212_I2C): cv.use_id(WeikaiComponentI2C), + } + ), + weikai.validate_pin_mode, +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_I2C, WK2212_PIN_SCHEMA) +async def sc16is75x_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_WK2212_I2C]) + cg.add(var.set_parent(parent)) + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/wk2212_spi/__init__.py b/esphome/components/wk2212_spi/__init__.py new file mode 100644 index 0000000000..bfeca87c22 --- /dev/null +++ b/esphome/components/wk2212_spi/__init__.py @@ -0,0 +1,62 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import spi, weikai +from esphome.const import ( + CONF_ID, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, +) + +CODEOWNERS = ["@DrCoolZic"] +DEPENDENCIES = ["spi"] +AUTO_LOAD = ["weikai", "weikai_spi"] +MULTI_CONF = True +CONF_WK2212_SPI = "wk2212_spi" + +weikai_ns = cg.esphome_ns.namespace("weikai") +weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") +WeikaiComponentSPI = weikai_spi_ns.class_( + "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice +) +WeikaiGPIOPin = weikai_ns.class_( + "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI) +) + +CONFIG_SCHEMA = cv.All( + weikai.WKBASE_SCHEMA.extend( + {cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)} + ).extend(spi.spi_device_schema()), + weikai.check_channel_max_2, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_name(str(config[CONF_ID]))) + await weikai.register_weikai(var, config) + await spi.register_spi_device(var, config) + + +WK2212_PIN_SCHEMA = cv.All( + weikai.WEIKAI_PIN_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), + cv.Required(CONF_WK2212_SPI): cv.use_id(WeikaiComponentSPI), + }, + ), + weikai.validate_pin_mode, +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_SPI, WK2212_PIN_SCHEMA) +async def sc16is75x_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_WK2212_SPI]) + cg.add(var.set_parent(parent)) + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/tests/components/wk2132_i2c/common.yaml b/tests/components/wk2132_i2c/common.yaml new file mode 100644 index 0000000000..f9c8ab756d --- /dev/null +++ b/tests/components/wk2132_i2c/common.yaml @@ -0,0 +1,20 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + scan: true + frequency: 600kHz + +wk2132_i2c: + - id: wk2132_i2c_id + address: 0x70 + i2c_id: i2c_bus + uart: + - id: wk2132_id_0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2132_id_1 + channel: 1 + baud_rate: 19200 diff --git a/tests/components/wk2132_i2c/test.esp32-idf.yaml b/tests/components/wk2132_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2132_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2132_i2c/test.esp32-s3-idf.yaml b/tests/components/wk2132_i2c/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2132_i2c/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2132_i2c/test.esp32-s3.yaml b/tests/components/wk2132_i2c/test.esp32-s3.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2132_i2c/test.esp32-s3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2132_i2c/test.esp32.yaml b/tests/components/wk2132_i2c/test.esp32.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2132_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2132_spi/common.yaml b/tests/components/wk2132_spi/common.yaml new file mode 100644 index 0000000000..b21e89120c --- /dev/null +++ b/tests/components/wk2132_spi/common.yaml @@ -0,0 +1,21 @@ +spi: + id: spi_bus + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +wk2132_spi: + - id: wk2132_spi_id + cs_pin: ${cs_pin} + spi_id: spi_bus + crystal: 11059200 + data_rate: 1MHz + uart: + - id: wk2132_spi_id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2132_spi_id1 + channel: 1 + baud_rate: 921600 diff --git a/tests/components/wk2132_spi/test.esp32-idf.yaml b/tests/components/wk2132_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2132_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2132_spi/test.esp32-s3-idf.yaml b/tests/components/wk2132_spi/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2132_spi/test.esp32-s3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2132_spi/test.esp32-s3.yaml b/tests/components/wk2132_spi/test.esp32-s3.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2132_spi/test.esp32-s3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2132_spi/test.esp32.yaml b/tests/components/wk2132_spi/test.esp32.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2132_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2168_i2c/common.yaml b/tests/components/wk2168_i2c/common.yaml new file mode 100644 index 0000000000..fe4689d6db --- /dev/null +++ b/tests/components/wk2168_i2c/common.yaml @@ -0,0 +1,63 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + scan: true + frequency: 600kHz + +# component declaration +wk2168_i2c: + - id: bridge_i2c + i2c_id: i2c_bus + address: 0x70 + uart: + - id: id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: id1 + channel: 1 + baud_rate: 115200 + - id: id2 + channel: 2 + baud_rate: 115200 + - id: id3 + channel: 3 + baud_rate: 115200 + +# individual binary_sensor inputs +binary_sensor: + - platform: gpio + name: "pin_0" + pin: + wk2168_i2c: bridge_i2c + number: 0 + mode: + input: true + - platform: gpio + name: "pin_1" + pin: + wk2168_i2c: bridge_i2c + number: 1 + mode: + input: true + inverted: true + +# Individual binary outputs +switch: + - platform: gpio + name: "pin_2" + pin: + wk2168_i2c: bridge_i2c + number: 2 + mode: + output: true + - platform: gpio + name: "pin_3" + pin: + wk2168_i2c: bridge_i2c + number: 3 + mode: + output: true + inverted: true diff --git a/tests/components/wk2168_i2c/test.esp32-idf.yaml b/tests/components/wk2168_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2168_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2168_i2c/test.esp32-s3-idf.yaml b/tests/components/wk2168_i2c/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2168_i2c/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2168_i2c/test.esp32-s3.yaml b/tests/components/wk2168_i2c/test.esp32-s3.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2168_i2c/test.esp32-s3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2168_i2c/test.esp32.yaml b/tests/components/wk2168_i2c/test.esp32.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2168_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2168_spi/common.yaml b/tests/components/wk2168_spi/common.yaml new file mode 100644 index 0000000000..7626e18df6 --- /dev/null +++ b/tests/components/wk2168_spi/common.yaml @@ -0,0 +1,63 @@ +spi: + id: spi_bus + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +wk2168_spi: + - id: bridge_spi + cs_pin: ${cs_pin} + spi_id: spi_bus + crystal: 11059200 + data_rate: 1MHz + uart: + - id: id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: id1 + channel: 1 + baud_rate: 115200 + - id: id2 + channel: 2 + baud_rate: 115200 + - id: id3 + channel: 3 + baud_rate: 115200 + +# individual binary_sensor inputs +binary_sensor: + - platform: gpio + name: "pin_0" + pin: + wk2168_spi: bridge_spi + number: 0 + mode: + input: true + - platform: gpio + name: "pin_1" + pin: + wk2168_spi: bridge_spi + number: 1 + mode: + input: true + inverted: true + +# Individual binary outputs +switch: + - platform: gpio + name: "pin_2" + pin: + wk2168_spi: bridge_spi + number: 2 + mode: + output: true + - platform: gpio + name: "pin_3" + pin: + wk2168_spi: bridge_spi + number: 3 + mode: + output: true + inverted: true diff --git a/tests/components/wk2168_spi/test.esp32-idf.yaml b/tests/components/wk2168_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2168_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2168_spi/test.esp32-s3-idf.yaml b/tests/components/wk2168_spi/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2168_spi/test.esp32-s3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2168_spi/test.esp32-s3.yaml b/tests/components/wk2168_spi/test.esp32-s3.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2168_spi/test.esp32-s3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2168_spi/test.esp32.yaml b/tests/components/wk2168_spi/test.esp32.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2168_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2204_i2c/common.yaml b/tests/components/wk2204_i2c/common.yaml new file mode 100644 index 0000000000..80f636c690 --- /dev/null +++ b/tests/components/wk2204_i2c/common.yaml @@ -0,0 +1,28 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + scan: true + frequency: 600kHz + +wk2204_i2c: + - id: wk2204_i2c_id + i2c_id: i2c_bus + address: 0x70 + uart: + - id: wk2204_id_0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2204_id_1 + channel: 1 + baud_rate: 19200 + - id: wk2204_id_2 + channel: 2 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2204_id_3 + channel: 3 + baud_rate: 19200 diff --git a/tests/components/wk2204_i2c/test.esp32-idf.yaml b/tests/components/wk2204_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2204_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2204_i2c/test.esp32-s3-idf.yaml b/tests/components/wk2204_i2c/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2204_i2c/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2204_i2c/test.esp32-s3.yaml b/tests/components/wk2204_i2c/test.esp32-s3.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2204_i2c/test.esp32-s3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2204_i2c/test.esp32.yaml b/tests/components/wk2204_i2c/test.esp32.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2204_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2204_spi/common.yaml b/tests/components/wk2204_spi/common.yaml new file mode 100644 index 0000000000..3bae9c9a6d --- /dev/null +++ b/tests/components/wk2204_spi/common.yaml @@ -0,0 +1,29 @@ +spi: + id: spi_bus + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +wk2204_spi: + - id: wk2204_spi_id + cs_pin: ${cs_pin} + spi_id: spi_bus + crystal: 11059200 + data_rate: 1MHz + uart: + - id: wk2204_spi_id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2204_spi_id1 + channel: 1 + baud_rate: 921600 + - id: wk2204_spi_id2 + channel: 2 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: wk2204_spi_id3 + channel: 3 + baud_rate: 921600 diff --git a/tests/components/wk2204_spi/test.esp32-idf.yaml b/tests/components/wk2204_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2204_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2204_spi/test.esp32-s3-idf.yaml b/tests/components/wk2204_spi/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2204_spi/test.esp32-s3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2204_spi/test.esp32-s3.yaml b/tests/components/wk2204_spi/test.esp32-s3.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2204_spi/test.esp32-s3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2204_spi/test.esp32.yaml b/tests/components/wk2204_spi/test.esp32.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2204_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2212_i2c/common.yaml b/tests/components/wk2212_i2c/common.yaml new file mode 100644 index 0000000000..2e891c5520 --- /dev/null +++ b/tests/components/wk2212_i2c/common.yaml @@ -0,0 +1,59 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + scan: true + frequency: 600kHz + +# component declaration +wk2212_i2c: + - id: bridge_i2c + i2c_id: i2c_bus + address: 0x70 + uart: + - id: uart_i2c_id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: uart_i2c_id1 + channel: 1 + baud_rate: 115200 + stop_bits: 1 + parity: none + +# individual binary_sensor inputs +binary_sensor: + - platform: gpio + name: "pin_0" + pin: + wk2212_i2c: bridge_i2c + number: 0 + mode: + input: true + - platform: gpio + name: "pin_1" + pin: + wk2212_i2c: bridge_i2c + number: 1 + mode: + input: true + inverted: true + +# Individual binary outputs +switch: + - platform: gpio + name: "pin_2" + pin: + wk2212_i2c: bridge_i2c + number: 2 + mode: + output: true + - platform: gpio + name: "pin_3" + pin: + wk2212_i2c: bridge_i2c + number: 3 + mode: + output: true + inverted: true diff --git a/tests/components/wk2212_i2c/test.esp32-idf.yaml b/tests/components/wk2212_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2212_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2212_i2c/test.esp32-s3-idf.yaml b/tests/components/wk2212_i2c/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2212_i2c/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2212_i2c/test.esp32-s3.yaml b/tests/components/wk2212_i2c/test.esp32-s3.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/wk2212_i2c/test.esp32-s3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/wk2212_i2c/test.esp32.yaml b/tests/components/wk2212_i2c/test.esp32.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/wk2212_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/wk2212_spi/common.yaml b/tests/components/wk2212_spi/common.yaml new file mode 100644 index 0000000000..ad9f11d9e8 --- /dev/null +++ b/tests/components/wk2212_spi/common.yaml @@ -0,0 +1,58 @@ +spi: + id: spi_bus + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +wk2212_spi: + - id: bridge_spi + cs_pin: ${cs_pin} + spi_id: spi_bus + crystal: 11059200 + data_rate: 1MHz + uart: + - id: id0 + channel: 0 + baud_rate: 115200 + stop_bits: 1 + parity: none + - id: id1 + channel: 1 + baud_rate: 115200 + +# individual binary_sensor inputs +binary_sensor: + - platform: gpio + name: "pin_0" + pin: + wk2212_spi: bridge_spi + number: 0 + mode: + input: true + - platform: gpio + name: "pin_1" + pin: + wk2212_spi: bridge_spi + number: 1 + mode: + input: true + inverted: true + +# Individual binary outputs +switch: + - platform: gpio + name: "pin_2" + pin: + wk2212_spi: bridge_spi + number: 2 + mode: + output: true + - platform: gpio + name: "pin_3" + pin: + wk2212_spi: bridge_spi + number: 3 + mode: + output: true + inverted: true + diff --git a/tests/components/wk2212_spi/test.esp32-idf.yaml b/tests/components/wk2212_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2212_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/wk2212_spi/test.esp32-s3-idf.yaml b/tests/components/wk2212_spi/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2212_spi/test.esp32-s3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2212_spi/test.esp32-s3.yaml b/tests/components/wk2212_spi/test.esp32-s3.yaml new file mode 100644 index 0000000000..b0aadf620a --- /dev/null +++ b/tests/components/wk2212_spi/test.esp32-s3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO40 + miso_pin: GPIO41 + mosi_pin: GPIO6 + cs_pin: GPIO19 + +<<: !include common.yaml diff --git a/tests/components/wk2212_spi/test.esp32.yaml b/tests/components/wk2212_spi/test.esp32.yaml new file mode 100644 index 0000000000..76e7138ab0 --- /dev/null +++ b/tests/components/wk2212_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO18 + miso_pin: GPIO19 + mosi_pin: GPIO23 + cs_pin: GPIO5 + +<<: !include common.yaml From 217988fd9937b44257794bd10ab304c72039903f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:49:08 +1200 Subject: [PATCH 1618/2607] Sort mqtt_const alphabetically (#6619) --- esphome/components/mqtt/mqtt_const.h | 257 +++++++++++++-------------- 1 file changed, 128 insertions(+), 129 deletions(-) diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index 3d9e0b4c00..2209f96e7a 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -9,8 +9,8 @@ namespace mqtt { #ifdef USE_MQTT_ABBREVIATIONS -constexpr const char *const MQTT_ACTION_TOPIC = "act_t"; constexpr const char *const MQTT_ACTION_TEMPLATE = "act_tpl"; +constexpr const char *const MQTT_ACTION_TOPIC = "act_t"; constexpr const char *const MQTT_AUTOMATION_TYPE = "atype"; constexpr const char *const MQTT_AUX_COMMAND_TOPIC = "aux_cmd_t"; constexpr const char *const MQTT_AUX_STATE_TEMPLATE = "aux_stat_tpl"; @@ -21,60 +21,68 @@ constexpr const char *const MQTT_AVAILABILITY_TOPIC = "avty_t"; constexpr const char *const MQTT_AWAY_MODE_COMMAND_TOPIC = "away_mode_cmd_t"; constexpr const char *const MQTT_AWAY_MODE_STATE_TEMPLATE = "away_mode_stat_tpl"; constexpr const char *const MQTT_AWAY_MODE_STATE_TOPIC = "away_mode_stat_t"; +constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "bat_lev_tpl"; +constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "bat_lev_t"; constexpr const char *const MQTT_BLUE_TEMPLATE = "b_tpl"; constexpr const char *const MQTT_BRIGHTNESS_COMMAND_TOPIC = "bri_cmd_t"; constexpr const char *const MQTT_BRIGHTNESS_SCALE = "bri_scl"; constexpr const char *const MQTT_BRIGHTNESS_STATE_TOPIC = "bri_stat_t"; constexpr const char *const MQTT_BRIGHTNESS_TEMPLATE = "bri_tpl"; constexpr const char *const MQTT_BRIGHTNESS_VALUE_TEMPLATE = "bri_val_tpl"; -constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "clr_temp_cmd_tpl"; -constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "bat_lev_t"; -constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "bat_lev_tpl"; -constexpr const char *const MQTT_CONFIGURATION_URL = "cu"; -constexpr const char *const MQTT_CHARGING_TOPIC = "chrg_t"; constexpr const char *const MQTT_CHARGING_TEMPLATE = "chrg_tpl"; +constexpr const char *const MQTT_CHARGING_TOPIC = "chrg_t"; +constexpr const char *const MQTT_CLEANING_TEMPLATE = "cln_tpl"; +constexpr const char *const MQTT_CLEANING_TOPIC = "cln_t"; +constexpr const char *const MQTT_CODE_ARM_REQUIRED = "cod_arm_req"; +constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "cod_dis_req"; constexpr const char *const MQTT_COLOR_MODE = "clrm"; constexpr const char *const MQTT_COLOR_MODE_STATE_TOPIC = "clrm_stat_t"; constexpr const char *const MQTT_COLOR_MODE_VALUE_TEMPLATE = "clrm_val_tpl"; +constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "clr_temp_cmd_tpl"; constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TOPIC = "clr_temp_cmd_t"; constexpr const char *const MQTT_COLOR_TEMP_STATE_TOPIC = "clr_temp_stat_t"; constexpr const char *const MQTT_COLOR_TEMP_TEMPLATE = "clr_temp_tpl"; constexpr const char *const MQTT_COLOR_TEMP_VALUE_TEMPLATE = "clr_temp_val_tpl"; -constexpr const char *const MQTT_CLEANING_TOPIC = "cln_t"; -constexpr const char *const MQTT_CLEANING_TEMPLATE = "cln_tpl"; constexpr const char *const MQTT_COMMAND_OFF_TEMPLATE = "cmd_off_tpl"; constexpr const char *const MQTT_COMMAND_ON_TEMPLATE = "cmd_on_tpl"; -constexpr const char *const MQTT_COMMAND_TOPIC = "cmd_t"; constexpr const char *const MQTT_COMMAND_RETAIN = "ret"; constexpr const char *const MQTT_COMMAND_TEMPLATE = "cmd_tpl"; -constexpr const char *const MQTT_CODE_ARM_REQUIRED = "cod_arm_req"; -constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "cod_dis_req"; -constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "curr_temp_t"; -constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "curr_temp_tpl"; -constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "curr_hum_t"; +constexpr const char *const MQTT_COMMAND_TOPIC = "cmd_t"; +constexpr const char *const MQTT_CONFIGURATION_URL = "cu"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "curr_hum_tpl"; +constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "curr_hum_t"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "curr_temp_tpl"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "curr_temp_t"; constexpr const char *const MQTT_DEVICE = "dev"; constexpr const char *const MQTT_DEVICE_CLASS = "dev_cla"; -constexpr const char *const MQTT_DOCKED_TOPIC = "dock_t"; +constexpr const char *const MQTT_DEVICE_CONNECTIONS = "cns"; +constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "ids"; +constexpr const char *const MQTT_DEVICE_MANUFACTURER = "mf"; +constexpr const char *const MQTT_DEVICE_MODEL = "mdl"; +constexpr const char *const MQTT_DEVICE_NAME = "name"; +constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "sa"; +constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw"; constexpr const char *const MQTT_DOCKED_TEMPLATE = "dock_tpl"; -constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "en"; -constexpr const char *const MQTT_ERROR_TOPIC = "err_t"; -constexpr const char *const MQTT_ERROR_TEMPLATE = "err_tpl"; -constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fanspd_t"; -constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fanspd_tpl"; -constexpr const char *const MQTT_FAN_SPEED_LIST = "fanspd_lst"; -constexpr const char *const MQTT_FLASH_TIME_LONG = "flsh_tlng"; -constexpr const char *const MQTT_FLASH_TIME_SHORT = "flsh_tsht"; +constexpr const char *const MQTT_DOCKED_TOPIC = "dock_t"; constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "fx_cmd_t"; constexpr const char *const MQTT_EFFECT_LIST = "fx_list"; constexpr const char *const MQTT_EFFECT_STATE_TOPIC = "fx_stat_t"; constexpr const char *const MQTT_EFFECT_TEMPLATE = "fx_tpl"; constexpr const char *const MQTT_EFFECT_VALUE_TEMPLATE = "fx_val_tpl"; +constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "en"; +constexpr const char *const MQTT_ENTITY_CATEGORY = "ent_cat"; +constexpr const char *const MQTT_ERROR_TEMPLATE = "err_tpl"; +constexpr const char *const MQTT_ERROR_TOPIC = "err_t"; constexpr const char *const MQTT_EXPIRE_AFTER = "exp_aft"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_cmd_tpl"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_cmd_t"; constexpr const char *const MQTT_FAN_MODE_STATE_TEMPLATE = "fan_mode_stat_tpl"; constexpr const char *const MQTT_FAN_MODE_STATE_TOPIC = "fan_mode_stat_t"; +constexpr const char *const MQTT_FAN_SPEED_LIST = "fanspd_lst"; +constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fanspd_tpl"; +constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fanspd_t"; +constexpr const char *const MQTT_FLASH_TIME_LONG = "flsh_tlng"; +constexpr const char *const MQTT_FLASH_TIME_SHORT = "flsh_tsht"; constexpr const char *const MQTT_FORCE_UPDATE = "frc_upd"; constexpr const char *const MQTT_GREEN_TEMPLATE = "g_tpl"; constexpr const char *const MQTT_HOLD_COMMAND_TEMPLATE = "hold_cmd_tpl"; @@ -86,56 +94,49 @@ constexpr const char *const MQTT_HS_STATE_TOPIC = "hs_stat_t"; constexpr const char *const MQTT_HS_VALUE_TEMPLATE = "hs_val_tpl"; constexpr const char *const MQTT_ICON = "ic"; constexpr const char *const MQTT_INITIAL = "init"; -constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "hum_cmd_t"; -constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "hum_cmd_tpl"; -constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "hum_stat_t"; -constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "hum_state_tpl"; constexpr const char *const MQTT_JSON_ATTRIBUTES = "json_attr"; -constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attr_t"; constexpr const char *const MQTT_JSON_ATTRIBUTES_TEMPLATE = "json_attr_tpl"; +constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attr_t"; constexpr const char *const MQTT_LAST_RESET_TOPIC = "lrst_t"; constexpr const char *const MQTT_LAST_RESET_VALUE_TEMPLATE = "lrst_val_tpl"; constexpr const char *const MQTT_MAX = "max"; -constexpr const char *const MQTT_MIN = "min"; constexpr const char *const MQTT_MAX_HUMIDITY = "max_hum"; -constexpr const char *const MQTT_MIN_HUMIDITY = "min_hum"; constexpr const char *const MQTT_MAX_MIREDS = "max_mirs"; -constexpr const char *const MQTT_MIN_MIREDS = "min_mirs"; constexpr const char *const MQTT_MAX_TEMP = "max_temp"; +constexpr const char *const MQTT_MIN = "min"; +constexpr const char *const MQTT_MIN_HUMIDITY = "min_hum"; +constexpr const char *const MQTT_MIN_MIREDS = "min_mirs"; constexpr const char *const MQTT_MIN_TEMP = "min_temp"; +constexpr const char *const MQTT_MODE = "mode"; constexpr const char *const MQTT_MODE_COMMAND_TEMPLATE = "mode_cmd_tpl"; constexpr const char *const MQTT_MODE_COMMAND_TOPIC = "mode_cmd_t"; -constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_stat_t"; constexpr const char *const MQTT_MODE_STATE_TEMPLATE = "mode_stat_tpl"; +constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_stat_t"; constexpr const char *const MQTT_MODES = "modes"; constexpr const char *const MQTT_NAME = "name"; constexpr const char *const MQTT_OBJECT_ID = "obj_id"; constexpr const char *const MQTT_OFF_DELAY = "off_dly"; constexpr const char *const MQTT_ON_COMMAND_TYPE = "on_cmd_type"; -constexpr const char *const MQTT_OPTIONS = "ops"; constexpr const char *const MQTT_OPTIMISTIC = "opt"; -constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "osc_cmd_t"; +constexpr const char *const MQTT_OPTIONS = "ops"; constexpr const char *const MQTT_OSCILLATION_COMMAND_TEMPLATE = "osc_cmd_tpl"; +constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "osc_cmd_t"; constexpr const char *const MQTT_OSCILLATION_STATE_TOPIC = "osc_stat_t"; constexpr const char *const MQTT_OSCILLATION_VALUE_TEMPLATE = "osc_val_tpl"; -constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "pct_cmd_t"; -constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "pct_cmd_tpl"; -constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "pct_stat_t"; -constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "pct_val_tpl"; constexpr const char *const MQTT_PAYLOAD = "pl"; constexpr const char *const MQTT_PAYLOAD_ARM_AWAY = "pl_arm_away"; +constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "pl_arm_custom_b"; constexpr const char *const MQTT_PAYLOAD_ARM_HOME = "pl_arm_home"; constexpr const char *const MQTT_PAYLOAD_ARM_NIGHT = "pl_arm_nite"; constexpr const char *const MQTT_PAYLOAD_ARM_VACATION = "pl_arm_vacation"; -constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "pl_arm_custom_b"; constexpr const char *const MQTT_PAYLOAD_AVAILABLE = "pl_avail"; constexpr const char *const MQTT_PAYLOAD_CLEAN_SPOT = "pl_cln_sp"; constexpr const char *const MQTT_PAYLOAD_CLOSE = "pl_cls"; constexpr const char *const MQTT_PAYLOAD_DISARM = "pl_disarm"; constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "pl_hi_spd"; constexpr const char *const MQTT_PAYLOAD_HOME = "pl_home"; -constexpr const char *const MQTT_PAYLOAD_LOCK = "pl_lock"; constexpr const char *const MQTT_PAYLOAD_LOCATE = "pl_loc"; +constexpr const char *const MQTT_PAYLOAD_LOCK = "pl_lock"; constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "pl_lo_spd"; constexpr const char *const MQTT_PAYLOAD_MEDIUM_SPEED = "pl_med_spd"; constexpr const char *const MQTT_PAYLOAD_NOT_AVAILABLE = "pl_not_avail"; @@ -152,20 +153,26 @@ constexpr const char *const MQTT_PAYLOAD_RESET_HUMIDITY = "pl_rst_hum"; constexpr const char *const MQTT_PAYLOAD_RESET_MODE = "pl_rst_mode"; constexpr const char *const MQTT_PAYLOAD_RESET_PERCENTAGE = "pl_rst_pct"; constexpr const char *const MQTT_PAYLOAD_RESET_PRESET_MODE = "pl_rst_pr_mode"; -constexpr const char *const MQTT_PAYLOAD_STOP = "pl_stop"; +constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "pl_ret"; constexpr const char *const MQTT_PAYLOAD_START = "pl_strt"; constexpr const char *const MQTT_PAYLOAD_START_PAUSE = "pl_stpa"; -constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "pl_ret"; +constexpr const char *const MQTT_PAYLOAD_STOP = "pl_stop"; constexpr const char *const MQTT_PAYLOAD_TURN_OFF = "pl_toff"; constexpr const char *const MQTT_PAYLOAD_TURN_ON = "pl_ton"; constexpr const char *const MQTT_PAYLOAD_UNLOCK = "pl_unlk"; +constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "pct_cmd_tpl"; +constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "pct_cmd_t"; +constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "pct_stat_t"; +constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "pct_val_tpl"; constexpr const char *const MQTT_POSITION_CLOSED = "pos_clsd"; constexpr const char *const MQTT_POSITION_OPEN = "pos_open"; +constexpr const char *const MQTT_POSITION_TEMPLATE = "pos_tpl"; +constexpr const char *const MQTT_POSITION_TOPIC = "pos_t"; constexpr const char *const MQTT_POWER_COMMAND_TOPIC = "pow_cmd_t"; -constexpr const char *const MQTT_POWER_STATE_TOPIC = "pow_stat_t"; constexpr const char *const MQTT_POWER_STATE_TEMPLATE = "pow_stat_tpl"; -constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "pr_mode_cmd_t"; +constexpr const char *const MQTT_POWER_STATE_TOPIC = "pow_stat_t"; constexpr const char *const MQTT_PRESET_MODE_COMMAND_TEMPLATE = "pr_mode_cmd_tpl"; +constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "pr_mode_cmd_t"; constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "pr_mode_stat_t"; constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "pr_mode_val_tpl"; constexpr const char *const MQTT_PRESET_MODES = "pr_modes"; @@ -188,36 +195,38 @@ constexpr const char *const MQTT_SEND_IF_OFF = "send_if_off"; constexpr const char *const MQTT_SET_FAN_SPEED_TOPIC = "set_fan_spd_t"; constexpr const char *const MQTT_SET_POSITION_TEMPLATE = "set_pos_tpl"; constexpr const char *const MQTT_SET_POSITION_TOPIC = "set_pos_t"; -constexpr const char *const MQTT_POSITION_TOPIC = "pos_t"; -constexpr const char *const MQTT_POSITION_TEMPLATE = "pos_tpl"; +constexpr const char *const MQTT_SOURCE_TYPE = "src_type"; constexpr const char *const MQTT_SPEED_COMMAND_TOPIC = "spd_cmd_t"; -constexpr const char *const MQTT_SPEED_STATE_TOPIC = "spd_stat_t"; -constexpr const char *const MQTT_SPEED_RANGE_MIN = "spd_rng_min"; constexpr const char *const MQTT_SPEED_RANGE_MAX = "spd_rng_max"; +constexpr const char *const MQTT_SPEED_RANGE_MIN = "spd_rng_min"; +constexpr const char *const MQTT_SPEED_STATE_TOPIC = "spd_stat_t"; constexpr const char *const MQTT_SPEED_VALUE_TEMPLATE = "spd_val_tpl"; constexpr const char *const MQTT_SPEEDS = "spds"; -constexpr const char *const MQTT_SOURCE_TYPE = "src_type"; constexpr const char *const MQTT_STATE_CLASS = "stat_cla"; constexpr const char *const MQTT_STATE_CLOSED = "stat_clsd"; constexpr const char *const MQTT_STATE_CLOSING = "stat_closing"; +constexpr const char *const MQTT_STATE_LOCKED = "stat_locked"; constexpr const char *const MQTT_STATE_OFF = "stat_off"; constexpr const char *const MQTT_STATE_ON = "stat_on"; constexpr const char *const MQTT_STATE_OPEN = "stat_open"; constexpr const char *const MQTT_STATE_OPENING = "stat_opening"; constexpr const char *const MQTT_STATE_STOPPED = "stat_stopped"; -constexpr const char *const MQTT_STATE_LOCKED = "stat_locked"; -constexpr const char *const MQTT_STATE_UNLOCKED = "stat_unlocked"; -constexpr const char *const MQTT_STATE_TOPIC = "stat_t"; constexpr const char *const MQTT_STATE_TEMPLATE = "stat_tpl"; +constexpr const char *const MQTT_STATE_TOPIC = "stat_t"; +constexpr const char *const MQTT_STATE_UNLOCKED = "stat_unlocked"; constexpr const char *const MQTT_STATE_VALUE_TEMPLATE = "stat_val_tpl"; constexpr const char *const MQTT_STEP = "step"; constexpr const char *const MQTT_SUBTYPE = "stype"; -constexpr const char *const MQTT_SUPPORTED_FEATURES = "sup_feat"; constexpr const char *const MQTT_SUPPORTED_COLOR_MODES = "sup_clrm"; +constexpr const char *const MQTT_SUPPORTED_FEATURES = "sup_feat"; constexpr const char *const MQTT_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_cmd_tpl"; constexpr const char *const MQTT_SWING_MODE_COMMAND_TOPIC = "swing_mode_cmd_t"; constexpr const char *const MQTT_SWING_MODE_STATE_TEMPLATE = "swing_mode_stat_tpl"; constexpr const char *const MQTT_SWING_MODE_STATE_TOPIC = "swing_mode_stat_t"; +constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "hum_cmd_tpl"; +constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "hum_cmd_t"; +constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "hum_state_tpl"; +constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "hum_stat_t"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temp_cmd_tpl"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temp_cmd_t"; constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temp_hi_cmd_tpl"; @@ -232,15 +241,15 @@ constexpr const char *const MQTT_TEMPERATURE_STATE_TEMPLATE = "temp_stat_tpl"; constexpr const char *const MQTT_TEMPERATURE_STATE_TOPIC = "temp_stat_t"; constexpr const char *const MQTT_TEMPERATURE_UNIT = "temp_unit"; constexpr const char *const MQTT_TILT_CLOSED_VALUE = "tilt_clsd_val"; -constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_cmd_t"; constexpr const char *const MQTT_TILT_COMMAND_TEMPLATE = "tilt_cmd_tpl"; +constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_cmd_t"; constexpr const char *const MQTT_TILT_INVERT_STATE = "tilt_inv_stat"; constexpr const char *const MQTT_TILT_MAX = "tilt_max"; constexpr const char *const MQTT_TILT_MIN = "tilt_min"; constexpr const char *const MQTT_TILT_OPENED_VALUE = "tilt_opnd_val"; constexpr const char *const MQTT_TILT_OPTIMISTIC = "tilt_opt"; -constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_t"; constexpr const char *const MQTT_TILT_STATUS_TEMPLATE = "tilt_status_tpl"; +constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_t"; constexpr const char *const MQTT_TOPIC = "t"; constexpr const char *const MQTT_UNIQUE_ID = "uniq_id"; constexpr const char *const MQTT_UNIT_OF_MEASUREMENT = "unit_of_meas"; @@ -255,18 +264,10 @@ constexpr const char *const MQTT_XY_COMMAND_TOPIC = "xy_cmd_t"; constexpr const char *const MQTT_XY_STATE_TOPIC = "xy_stat_t"; constexpr const char *const MQTT_XY_VALUE_TEMPLATE = "xy_val_tpl"; -constexpr const char *const MQTT_DEVICE_CONNECTIONS = "cns"; -constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "ids"; -constexpr const char *const MQTT_DEVICE_NAME = "name"; -constexpr const char *const MQTT_DEVICE_MANUFACTURER = "mf"; -constexpr const char *const MQTT_DEVICE_MODEL = "mdl"; -constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw"; -constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "sa"; - #else -constexpr const char *const MQTT_ACTION_TOPIC = "action_topic"; constexpr const char *const MQTT_ACTION_TEMPLATE = "action_template"; +constexpr const char *const MQTT_ACTION_TOPIC = "action_topic"; constexpr const char *const MQTT_AUTOMATION_TYPE = "automation_type"; constexpr const char *const MQTT_AUX_COMMAND_TOPIC = "aux_command_topic"; constexpr const char *const MQTT_AUX_STATE_TEMPLATE = "aux_state_template"; @@ -277,60 +278,68 @@ constexpr const char *const MQTT_AVAILABILITY_TOPIC = "availability_topic"; constexpr const char *const MQTT_AWAY_MODE_COMMAND_TOPIC = "away_mode_command_topic"; constexpr const char *const MQTT_AWAY_MODE_STATE_TEMPLATE = "away_mode_state_template"; constexpr const char *const MQTT_AWAY_MODE_STATE_TOPIC = "away_mode_state_topic"; +constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "battery_level_template"; +constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "battery_level_topic"; constexpr const char *const MQTT_BLUE_TEMPLATE = "blue_template"; constexpr const char *const MQTT_BRIGHTNESS_COMMAND_TOPIC = "brightness_command_topic"; constexpr const char *const MQTT_BRIGHTNESS_SCALE = "brightness_scale"; constexpr const char *const MQTT_BRIGHTNESS_STATE_TOPIC = "brightness_state_topic"; constexpr const char *const MQTT_BRIGHTNESS_TEMPLATE = "brightness_template"; constexpr const char *const MQTT_BRIGHTNESS_VALUE_TEMPLATE = "brightness_value_template"; -constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "color_temp_command_template"; -constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "battery_level_topic"; -constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "battery_level_template"; -constexpr const char *const MQTT_CONFIGURATION_URL = "configuration_url"; -constexpr const char *const MQTT_CHARGING_TOPIC = "charging_topic"; constexpr const char *const MQTT_CHARGING_TEMPLATE = "charging_template"; +constexpr const char *const MQTT_CHARGING_TOPIC = "charging_topic"; +constexpr const char *const MQTT_CLEANING_TEMPLATE = "cleaning_template"; +constexpr const char *const MQTT_CLEANING_TOPIC = "cleaning_topic"; +constexpr const char *const MQTT_CODE_ARM_REQUIRED = "code_arm_required"; +constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "code_disarm_required"; constexpr const char *const MQTT_COLOR_MODE = "color_mode"; constexpr const char *const MQTT_COLOR_MODE_STATE_TOPIC = "color_mode_state_topic"; constexpr const char *const MQTT_COLOR_MODE_VALUE_TEMPLATE = "color_mode_value_template"; +constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "color_temp_command_template"; constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TOPIC = "color_temp_command_topic"; constexpr const char *const MQTT_COLOR_TEMP_STATE_TOPIC = "color_temp_state_topic"; constexpr const char *const MQTT_COLOR_TEMP_TEMPLATE = "color_temp_template"; constexpr const char *const MQTT_COLOR_TEMP_VALUE_TEMPLATE = "color_temp_value_template"; -constexpr const char *const MQTT_CLEANING_TOPIC = "cleaning_topic"; -constexpr const char *const MQTT_CLEANING_TEMPLATE = "cleaning_template"; constexpr const char *const MQTT_COMMAND_OFF_TEMPLATE = "command_off_template"; constexpr const char *const MQTT_COMMAND_ON_TEMPLATE = "command_on_template"; -constexpr const char *const MQTT_COMMAND_TOPIC = "command_topic"; constexpr const char *const MQTT_COMMAND_RETAIN = "retain"; constexpr const char *const MQTT_COMMAND_TEMPLATE = "command_template"; -constexpr const char *const MQTT_CODE_ARM_REQUIRED = "code_arm_required"; -constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "code_disarm_required"; -constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "current_temperature_topic"; -constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "current_temperature_template"; -constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"; +constexpr const char *const MQTT_COMMAND_TOPIC = "command_topic"; +constexpr const char *const MQTT_CONFIGURATION_URL = "configuration_url"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template"; +constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "current_temperature_template"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "current_temperature_topic"; constexpr const char *const MQTT_DEVICE = "device"; constexpr const char *const MQTT_DEVICE_CLASS = "device_class"; -constexpr const char *const MQTT_DOCKED_TOPIC = "docked_topic"; +constexpr const char *const MQTT_DEVICE_CONNECTIONS = "connections"; +constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "identifiers"; +constexpr const char *const MQTT_DEVICE_MANUFACTURER = "manufacturer"; +constexpr const char *const MQTT_DEVICE_MODEL = "model"; +constexpr const char *const MQTT_DEVICE_NAME = "name"; +constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "suggested_area"; +constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw_version"; constexpr const char *const MQTT_DOCKED_TEMPLATE = "docked_template"; -constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "enabled_by_default"; -constexpr const char *const MQTT_ERROR_TOPIC = "error_topic"; -constexpr const char *const MQTT_ERROR_TEMPLATE = "error_template"; -constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fan_speed_topic"; -constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fan_speed_template"; -constexpr const char *const MQTT_FAN_SPEED_LIST = "fan_speed_list"; -constexpr const char *const MQTT_FLASH_TIME_LONG = "flash_time_long"; -constexpr const char *const MQTT_FLASH_TIME_SHORT = "flash_time_short"; +constexpr const char *const MQTT_DOCKED_TOPIC = "docked_topic"; constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "effect_command_topic"; constexpr const char *const MQTT_EFFECT_LIST = "effect_list"; constexpr const char *const MQTT_EFFECT_STATE_TOPIC = "effect_state_topic"; constexpr const char *const MQTT_EFFECT_TEMPLATE = "effect_template"; constexpr const char *const MQTT_EFFECT_VALUE_TEMPLATE = "effect_value_template"; +constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "enabled_by_default"; +constexpr const char *const MQTT_ENTITY_CATEGORY = "entity_category"; +constexpr const char *const MQTT_ERROR_TEMPLATE = "error_template"; +constexpr const char *const MQTT_ERROR_TOPIC = "error_topic"; constexpr const char *const MQTT_EXPIRE_AFTER = "expire_after"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic"; constexpr const char *const MQTT_FAN_MODE_STATE_TEMPLATE = "fan_mode_state_template"; constexpr const char *const MQTT_FAN_MODE_STATE_TOPIC = "fan_mode_state_topic"; +constexpr const char *const MQTT_FAN_SPEED_LIST = "fan_speed_list"; +constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fan_speed_template"; +constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fan_speed_topic"; +constexpr const char *const MQTT_FLASH_TIME_LONG = "flash_time_long"; +constexpr const char *const MQTT_FLASH_TIME_SHORT = "flash_time_short"; constexpr const char *const MQTT_FORCE_UPDATE = "force_update"; constexpr const char *const MQTT_GREEN_TEMPLATE = "green_template"; constexpr const char *const MQTT_HOLD_COMMAND_TEMPLATE = "hold_command_template"; @@ -342,56 +351,49 @@ constexpr const char *const MQTT_HS_STATE_TOPIC = "hs_state_topic"; constexpr const char *const MQTT_HS_VALUE_TEMPLATE = "hs_value_template"; constexpr const char *const MQTT_ICON = "icon"; constexpr const char *const MQTT_INITIAL = "initial"; -constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic"; -constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "target_humidity_command_template"; -constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic"; -constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template"; constexpr const char *const MQTT_JSON_ATTRIBUTES = "json_attributes"; -constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attributes_topic"; constexpr const char *const MQTT_JSON_ATTRIBUTES_TEMPLATE = "json_attributes_template"; +constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attributes_topic"; constexpr const char *const MQTT_LAST_RESET_TOPIC = "last_reset_topic"; constexpr const char *const MQTT_LAST_RESET_VALUE_TEMPLATE = "last_reset_value_template"; constexpr const char *const MQTT_MAX = "max"; -constexpr const char *const MQTT_MIN = "min"; constexpr const char *const MQTT_MAX_HUMIDITY = "max_humidity"; -constexpr const char *const MQTT_MIN_HUMIDITY = "min_humidity"; constexpr const char *const MQTT_MAX_MIREDS = "max_mireds"; -constexpr const char *const MQTT_MIN_MIREDS = "min_mireds"; constexpr const char *const MQTT_MAX_TEMP = "max_temp"; +constexpr const char *const MQTT_MIN = "min"; +constexpr const char *const MQTT_MIN_HUMIDITY = "min_humidity"; +constexpr const char *const MQTT_MIN_MIREDS = "min_mireds"; constexpr const char *const MQTT_MIN_TEMP = "min_temp"; +constexpr const char *const MQTT_MODE = "mode"; constexpr const char *const MQTT_MODE_COMMAND_TEMPLATE = "mode_command_template"; constexpr const char *const MQTT_MODE_COMMAND_TOPIC = "mode_command_topic"; -constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_state_topic"; constexpr const char *const MQTT_MODE_STATE_TEMPLATE = "mode_state_template"; +constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_state_topic"; constexpr const char *const MQTT_MODES = "modes"; constexpr const char *const MQTT_NAME = "name"; constexpr const char *const MQTT_OBJECT_ID = "object_id"; constexpr const char *const MQTT_OFF_DELAY = "off_delay"; constexpr const char *const MQTT_ON_COMMAND_TYPE = "on_command_type"; -constexpr const char *const MQTT_OPTIONS = "options"; constexpr const char *const MQTT_OPTIMISTIC = "optimistic"; -constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "oscillation_command_topic"; +constexpr const char *const MQTT_OPTIONS = "options"; constexpr const char *const MQTT_OSCILLATION_COMMAND_TEMPLATE = "oscillation_command_template"; +constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "oscillation_command_topic"; constexpr const char *const MQTT_OSCILLATION_STATE_TOPIC = "oscillation_state_topic"; constexpr const char *const MQTT_OSCILLATION_VALUE_TEMPLATE = "oscillation_value_template"; -constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic"; -constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "percentage_command_template"; -constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"; -constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "percentage_value_template"; constexpr const char *const MQTT_PAYLOAD = "payload"; constexpr const char *const MQTT_PAYLOAD_ARM_AWAY = "payload_arm_away"; +constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass"; constexpr const char *const MQTT_PAYLOAD_ARM_HOME = "payload_arm_home"; constexpr const char *const MQTT_PAYLOAD_ARM_NIGHT = "payload_arm_night"; constexpr const char *const MQTT_PAYLOAD_ARM_VACATION = "payload_arm_vacation"; -constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass"; constexpr const char *const MQTT_PAYLOAD_AVAILABLE = "payload_available"; constexpr const char *const MQTT_PAYLOAD_CLEAN_SPOT = "payload_clean_spot"; constexpr const char *const MQTT_PAYLOAD_CLOSE = "payload_close"; constexpr const char *const MQTT_PAYLOAD_DISARM = "payload_disarm"; constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "payload_high_speed"; constexpr const char *const MQTT_PAYLOAD_HOME = "payload_home"; -constexpr const char *const MQTT_PAYLOAD_LOCK = "payload_lock"; constexpr const char *const MQTT_PAYLOAD_LOCATE = "payload_locate"; +constexpr const char *const MQTT_PAYLOAD_LOCK = "payload_lock"; constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "payload_low_speed"; constexpr const char *const MQTT_PAYLOAD_MEDIUM_SPEED = "payload_medium_speed"; constexpr const char *const MQTT_PAYLOAD_NOT_AVAILABLE = "payload_not_available"; @@ -408,20 +410,26 @@ constexpr const char *const MQTT_PAYLOAD_RESET_HUMIDITY = "payload_reset_humidit constexpr const char *const MQTT_PAYLOAD_RESET_MODE = "payload_reset_mode"; constexpr const char *const MQTT_PAYLOAD_RESET_PERCENTAGE = "payload_reset_percentage"; constexpr const char *const MQTT_PAYLOAD_RESET_PRESET_MODE = "payload_reset_preset_mode"; -constexpr const char *const MQTT_PAYLOAD_STOP = "payload_stop"; +constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "payload_return_to_base"; constexpr const char *const MQTT_PAYLOAD_START = "payload_start"; constexpr const char *const MQTT_PAYLOAD_START_PAUSE = "payload_start_pause"; -constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "payload_return_to_base"; +constexpr const char *const MQTT_PAYLOAD_STOP = "payload_stop"; constexpr const char *const MQTT_PAYLOAD_TURN_OFF = "payload_turn_off"; constexpr const char *const MQTT_PAYLOAD_TURN_ON = "payload_turn_on"; constexpr const char *const MQTT_PAYLOAD_UNLOCK = "payload_unlock"; +constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "percentage_command_template"; +constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic"; +constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"; +constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "percentage_value_template"; constexpr const char *const MQTT_POSITION_CLOSED = "position_closed"; constexpr const char *const MQTT_POSITION_OPEN = "position_open"; +constexpr const char *const MQTT_POSITION_TEMPLATE = "position_template"; +constexpr const char *const MQTT_POSITION_TOPIC = "position_topic"; constexpr const char *const MQTT_POWER_COMMAND_TOPIC = "power_command_topic"; -constexpr const char *const MQTT_POWER_STATE_TOPIC = "power_state_topic"; constexpr const char *const MQTT_POWER_STATE_TEMPLATE = "power_state_template"; -constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "preset_mode_command_topic"; +constexpr const char *const MQTT_POWER_STATE_TOPIC = "power_state_topic"; constexpr const char *const MQTT_PRESET_MODE_COMMAND_TEMPLATE = "preset_mode_command_template"; +constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "preset_mode_command_topic"; constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "preset_mode_state_topic"; constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "preset_mode_value_template"; constexpr const char *const MQTT_PRESET_MODES = "preset_modes"; @@ -444,36 +452,38 @@ constexpr const char *const MQTT_SEND_IF_OFF = "send_if_off"; constexpr const char *const MQTT_SET_FAN_SPEED_TOPIC = "set_fan_speed_topic"; constexpr const char *const MQTT_SET_POSITION_TEMPLATE = "set_position_template"; constexpr const char *const MQTT_SET_POSITION_TOPIC = "set_position_topic"; -constexpr const char *const MQTT_POSITION_TOPIC = "position_topic"; -constexpr const char *const MQTT_POSITION_TEMPLATE = "position_template"; +constexpr const char *const MQTT_SOURCE_TYPE = "source_type"; constexpr const char *const MQTT_SPEED_COMMAND_TOPIC = "speed_command_topic"; -constexpr const char *const MQTT_SPEED_STATE_TOPIC = "speed_state_topic"; -constexpr const char *const MQTT_SPEED_RANGE_MIN = "speed_range_min"; constexpr const char *const MQTT_SPEED_RANGE_MAX = "speed_range_max"; +constexpr const char *const MQTT_SPEED_RANGE_MIN = "speed_range_min"; +constexpr const char *const MQTT_SPEED_STATE_TOPIC = "speed_state_topic"; constexpr const char *const MQTT_SPEED_VALUE_TEMPLATE = "speed_value_template"; constexpr const char *const MQTT_SPEEDS = "speeds"; -constexpr const char *const MQTT_SOURCE_TYPE = "source_type"; constexpr const char *const MQTT_STATE_CLASS = "state_class"; constexpr const char *const MQTT_STATE_CLOSED = "state_closed"; constexpr const char *const MQTT_STATE_CLOSING = "state_closing"; +constexpr const char *const MQTT_STATE_LOCKED = "state_locked"; constexpr const char *const MQTT_STATE_OFF = "state_off"; constexpr const char *const MQTT_STATE_ON = "state_on"; constexpr const char *const MQTT_STATE_OPEN = "state_open"; constexpr const char *const MQTT_STATE_OPENING = "state_opening"; constexpr const char *const MQTT_STATE_STOPPED = "state_stopped"; -constexpr const char *const MQTT_STATE_LOCKED = "state_locked"; -constexpr const char *const MQTT_STATE_UNLOCKED = "state_unlocked"; -constexpr const char *const MQTT_STATE_TOPIC = "state_topic"; constexpr const char *const MQTT_STATE_TEMPLATE = "state_template"; +constexpr const char *const MQTT_STATE_TOPIC = "state_topic"; +constexpr const char *const MQTT_STATE_UNLOCKED = "state_unlocked"; constexpr const char *const MQTT_STATE_VALUE_TEMPLATE = "state_value_template"; constexpr const char *const MQTT_STEP = "step"; constexpr const char *const MQTT_SUBTYPE = "subtype"; -constexpr const char *const MQTT_SUPPORTED_FEATURES = "supported_features"; constexpr const char *const MQTT_SUPPORTED_COLOR_MODES = "supported_color_modes"; +constexpr const char *const MQTT_SUPPORTED_FEATURES = "supported_features"; constexpr const char *const MQTT_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_command_template"; constexpr const char *const MQTT_SWING_MODE_COMMAND_TOPIC = "swing_mode_command_topic"; constexpr const char *const MQTT_SWING_MODE_STATE_TEMPLATE = "swing_mode_state_template"; constexpr const char *const MQTT_SWING_MODE_STATE_TOPIC = "swing_mode_state_topic"; +constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "target_humidity_command_template"; +constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic"; +constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template"; +constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temperature_command_template"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temperature_command_topic"; constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temperature_high_command_template"; @@ -488,15 +498,15 @@ constexpr const char *const MQTT_TEMPERATURE_STATE_TEMPLATE = "temperature_state constexpr const char *const MQTT_TEMPERATURE_STATE_TOPIC = "temperature_state_topic"; constexpr const char *const MQTT_TEMPERATURE_UNIT = "temperature_unit"; constexpr const char *const MQTT_TILT_CLOSED_VALUE = "tilt_closed_value"; -constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_command_topic"; constexpr const char *const MQTT_TILT_COMMAND_TEMPLATE = "tilt_command_template"; +constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_command_topic"; constexpr const char *const MQTT_TILT_INVERT_STATE = "tilt_invert_state"; constexpr const char *const MQTT_TILT_MAX = "tilt_max"; constexpr const char *const MQTT_TILT_MIN = "tilt_min"; constexpr const char *const MQTT_TILT_OPENED_VALUE = "tilt_opened_value"; constexpr const char *const MQTT_TILT_OPTIMISTIC = "tilt_optimistic"; -constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_topic"; constexpr const char *const MQTT_TILT_STATUS_TEMPLATE = "tilt_status_template"; +constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_topic"; constexpr const char *const MQTT_TOPIC = "topic"; constexpr const char *const MQTT_UNIQUE_ID = "unique_id"; constexpr const char *const MQTT_UNIT_OF_MEASUREMENT = "unit_of_measurement"; @@ -511,19 +521,8 @@ constexpr const char *const MQTT_XY_COMMAND_TOPIC = "xy_command_topic"; constexpr const char *const MQTT_XY_STATE_TOPIC = "xy_state_topic"; constexpr const char *const MQTT_XY_VALUE_TEMPLATE = "xy_value_template"; -constexpr const char *const MQTT_DEVICE_CONNECTIONS = "connections"; -constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "identifiers"; -constexpr const char *const MQTT_DEVICE_NAME = "name"; -constexpr const char *const MQTT_DEVICE_MANUFACTURER = "manufacturer"; -constexpr const char *const MQTT_DEVICE_MODEL = "model"; -constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw_version"; -constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "suggested_area"; #endif -// Additional MQTT fields where no abbreviation is defined in HA source -constexpr const char *const MQTT_ENTITY_CATEGORY = "entity_category"; -constexpr const char *const MQTT_MODE = "mode"; - } // namespace mqtt } // namespace esphome From b03d0f37a43e177174316f786586623629efe749 Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Tue, 23 Apr 2024 21:01:28 -0500 Subject: [PATCH 1619/2607] Limit Rx wait loop time to 3 seconds. (#6594) Co-authored-by: descipher --- esphome/components/ld2420/ld2420.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index 58c9a289a3..e57fdbc84e 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -493,19 +493,16 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) { } int LD2420Component::send_cmd_from_array(CmdFrameT frame) { + uint32_t start_millis = millis(); uint8_t error = 0; uint8_t ack_buffer[64]; uint8_t cmd_buffer[64]; - uint16_t loop_count; this->cmd_reply_.ack = false; if (frame.command != CMD_RESTART) this->set_cmd_active_(true); // Restart does not reply, thus no ack state required. uint8_t retry = 3; while (retry) { - // TODO setup a dynamic method e.g. millis time count etc. to tune for non ESP32 240Mhz devices - // this is ok for now since the module firmware is changing like the weather atm frame.length = 0; - loop_count = 1250; uint16_t frame_data_bytes = frame.data_length + 2; // Always add two bytes for the cmd size memcpy(&cmd_buffer[frame.length], &frame.header, sizeof(frame.header)); @@ -538,12 +535,13 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) { this->readline_(read(), ack_buffer, sizeof(ack_buffer)); } delay_microseconds_safe(1450); - if (loop_count <= 0) { + // Wait on an Rx from the LD2420 for up to 3 1 second loops, otherwise it could trigger a WDT. + if ((millis() - start_millis) > 1000) { + start_millis = millis(); error = LD2420_ERROR_TIMEOUT; retry--; break; } - loop_count--; } if (this->cmd_reply_.ack) retry = 0; From c531a528f0fd56d0778921aad96a01df80062222 Mon Sep 17 00:00:00 2001 From: David Friedland Date: Tue, 23 Apr 2024 19:35:26 -0700 Subject: [PATCH 1620/2607] Event entity support (#6451) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 + esphome/components/api/api.proto | 26 +++ esphome/components/api/api_connection.cpp | 24 +++ esphome/components/api/api_connection.h | 5 + esphome/components/api/api_pb2.cpp | 151 ++++++++++++++++++ esphome/components/api/api_pb2.h | 34 ++++ esphome/components/api/api_pb2_service.cpp | 16 ++ esphome/components/api/api_pb2_service.h | 6 + esphome/components/api/api_server.cpp | 7 + esphome/components/api/api_server.h | 3 + esphome/components/api/list_entities.cpp | 3 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.h | 3 + esphome/components/event/__init__.py | 134 ++++++++++++++++ esphome/components/event/automation.h | 25 +++ esphome/components/event/event.cpp | 24 +++ esphome/components/event/event.h | 37 +++++ esphome/components/mqtt/__init__.py | 1 + esphome/components/mqtt/mqtt_const.h | 4 + esphome/components/mqtt/mqtt_event.cpp | 54 +++++++ esphome/components/mqtt/mqtt_event.h | 39 +++++ esphome/components/template/event/__init__.py | 24 +++ .../template/event/template_event.h | 12 ++ .../components/web_server/list_entities.cpp | 9 ++ esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 22 +++ esphome/components/web_server/web_server.h | 7 + esphome/const.py | 5 + esphome/core/application.h | 20 +++ esphome/core/component_iterator.cpp | 15 ++ esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + script/ci-custom.py | 1 + tests/components/event/test.esp32-c3-idf.yaml | 9 ++ tests/components/event/test.esp32-c3.yaml | 9 ++ tests/components/event/test.esp32-idf.yaml | 9 ++ tests/components/event/test.esp32.yaml | 9 ++ tests/components/event/test.esp8266.yaml | 9 ++ tests/components/event/test.rp2040.yaml | 9 ++ 41 files changed, 792 insertions(+) create mode 100644 esphome/components/event/__init__.py create mode 100644 esphome/components/event/automation.h create mode 100644 esphome/components/event/event.cpp create mode 100644 esphome/components/event/event.h create mode 100644 esphome/components/mqtt/mqtt_event.cpp create mode 100644 esphome/components/mqtt/mqtt_event.h create mode 100644 esphome/components/template/event/__init__.py create mode 100644 esphome/components/template/event/template_event.h create mode 100644 tests/components/event/test.esp32-c3-idf.yaml create mode 100644 tests/components/event/test.esp32-c3.yaml create mode 100644 tests/components/event/test.esp32-idf.yaml create mode 100644 tests/components/event/test.esp32.yaml create mode 100644 tests/components/event/test.esp8266.yaml create mode 100644 tests/components/event/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 8da1618636..a60a5c3099 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -119,6 +119,7 @@ esphome/components/esp32_rmt/* @jesserockz esphome/components/esp32_rmt_led_strip/* @jesserockz esphome/components/esp8266/* @esphome/core esphome/components/ethernet_info/* @gtjadsonsantos +esphome/components/event/* @nohat esphome/components/exposure_notifications/* @OttoWinter esphome/components/ezo/* @ssieb esphome/components/ezo_pmp/* @carlos-sarmiento @@ -359,6 +360,7 @@ esphome/components/tee501/* @Stock-M esphome/components/teleinfo/* @0hax esphome/components/template/alarm_control_panel/* @grahambrown11 @hwstar esphome/components/template/datetime/* @rfdarter +esphome/components/template/event/* @nohat esphome/components/template/fan/* @ssieb esphome/components/text/* @mauritskorse esphome/components/thermostat/* @kbx81 diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 12b7ef0958..17826ea7ed 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1702,6 +1702,32 @@ message TimeCommandRequest { uint32 second = 4; } +// ==================== EVENT ==================== +message ListEntitiesEventResponse { + option (id) = 107; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_EVENT"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; + string device_class = 8; + + repeated string event_types = 9; +} +message EventResponse { + option (id) = 108; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_EVENT"; + + fixed32 key = 1; + string event_type = 2; +} // ==================== VALVE ==================== message ListEntitiesValveResponse { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 47136fff98..ec09604d95 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1209,6 +1209,30 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe } #endif +#ifdef USE_EVENT +bool APIConnection::send_event(event::Event *event, std::string event_type) { + EventResponse resp{}; + resp.key = event->get_object_id_hash(); + resp.event_type = std::move(event_type); + return this->send_event_response(resp); +} +bool APIConnection::send_event_info(event::Event *event) { + ListEntitiesEventResponse msg; + msg.key = event->get_object_id_hash(); + msg.object_id = event->get_object_id(); + if (event->has_own_name()) + msg.name = event->get_name(); + msg.unique_id = get_default_unique_id("event", event); + msg.icon = event->get_icon(); + msg.disabled_by_default = event->is_disabled_by_default(); + msg.entity_category = static_cast(event->get_entity_category()); + msg.device_class = event->get_device_class(); + for (const auto &event_type : event->get_event_types()) + msg.event_types.push_back(event_type); + return this->send_list_entities_event_response(msg); +} +#endif + bool APIConnection::send_log_message(int level, const char *tag, const char *line) { if (this->log_subscription_ < level) return false; diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index af2dd9e681..2c1d733d3e 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -153,6 +153,11 @@ class APIConnection : public APIServerConnection { void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override; #endif +#ifdef USE_EVENT + bool send_event(event::Event *event, std::string event_type); + bool send_event_info(event::Event *event); +#endif + void on_disconnect_response(const DisconnectResponse &value) override; void on_ping_response(const PingResponse &value) override { // we initiated ping diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 508947ba24..3f01d88c58 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7709,6 +7709,157 @@ void TimeCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ListEntitiesEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + case 8: { + this->device_class = value.as_string(); + return true; + } + case 9: { + this->event_types.push_back(value.as_string()); + return true; + } + default: + return false; + } +} +bool ListEntitiesEventResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesEventResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); + buffer.encode_string(8, this->device_class); + for (auto &it : this->event_types) { + buffer.encode_string(9, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesEventResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + for (const auto &it : this->event_types) { + out.append(" event_types: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +#endif +bool EventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->event_type = value.as_string(); + return true; + } + default: + return false; + } +} +bool EventResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void EventResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_string(2, this->event_type); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void EventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("EventResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" event_type: "); + out.append("'").append(this->event_type).append("'"); + out.append("\n"); + out.append("}"); +} +#endif bool ListEntitiesValveResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 950ffcdc88..9a6aab254d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1974,6 +1974,40 @@ class TimeCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class ListEntitiesEventResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + std::string device_class{}; + std::vector event_types{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class EventResponse : public ProtoMessage { + public: + uint32_t key{0}; + std::string event_type{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; +}; class ListEntitiesValveResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 4b8b8cf5ae..ced81fa643 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -557,6 +557,22 @@ bool APIServerConnectionBase::send_time_state_response(const TimeStateResponse & #endif #ifdef USE_DATETIME_TIME #endif +#ifdef USE_EVENT +bool APIServerConnectionBase::send_list_entities_event_response(const ListEntitiesEventResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_event_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 107); +} +#endif +#ifdef USE_EVENT +bool APIServerConnectionBase::send_event_response(const EventResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_event_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 108); +} +#endif #ifdef USE_VALVE bool APIServerConnectionBase::send_list_entities_valve_response(const ListEntitiesValveResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 9f1d711257..c8b2bc5789 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -280,6 +280,12 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_DATETIME_TIME virtual void on_time_command_request(const TimeCommandRequest &value){}; #endif +#ifdef USE_EVENT + bool send_list_entities_event_response(const ListEntitiesEventResponse &msg); +#endif +#ifdef USE_EVENT + bool send_event_response(const EventResponse &msg); +#endif #ifdef USE_VALVE bool send_list_entities_valve_response(const ListEntitiesValveResponse &msg); #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 457eeb1229..6d4e4db1e8 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -318,6 +318,13 @@ void APIServer::on_media_player_update(media_player::MediaPlayer *obj) { } #endif +#ifdef USE_EVENT +void APIServer::on_event(event::Event *obj, const std::string &event_type) { + for (auto &c : this->clients_) + c->send_event(obj, event_type); +} +#endif + float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } void APIServer::set_port(uint16_t port) { this->port_ = port; } APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index d64643b961..e9e03cde0d 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -96,6 +96,9 @@ class APIServer : public Component, public Controller { #ifdef USE_ALARM_CONTROL_PANEL void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override; #endif +#ifdef USE_EVENT + void on_event(event::Event *obj, const std::string &event_type) override; +#endif bool is_connected() const; diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index d6ff8e5557..82bfd45333 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -89,6 +89,9 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont return this->client_->send_alarm_control_panel_info(a_alarm_control_panel); } #endif +#ifdef USE_EVENT +bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); } +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index 5d0c243f4a..19cd99ea01 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -69,6 +69,9 @@ class ListEntitiesIterator : public ComponentIterator { #endif #ifdef USE_ALARM_CONTROL_PANEL bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; +#endif +#ifdef USE_EVENT + bool on_event(event::Event *event) override; #endif bool on_end() override; diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 8d50e0d89a..17d444c441 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -66,6 +66,9 @@ class InitialStateIterator : public ComponentIterator { #endif #ifdef USE_ALARM_CONTROL_PANEL bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; +#endif +#ifdef USE_EVENT + bool on_event(event::Event *event) override { return true; }; #endif protected: APIConnection *client_; diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py new file mode 100644 index 0000000000..789f121cf3 --- /dev/null +++ b/esphome/components/event/__init__.py @@ -0,0 +1,134 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import mqtt +from esphome.const import ( + CONF_DEVICE_CLASS, + CONF_ENTITY_CATEGORY, + CONF_ICON, + CONF_ID, + CONF_ON_EVENT, + CONF_TRIGGER_ID, + CONF_MQTT_ID, + CONF_EVENT_TYPE, + DEVICE_CLASS_BUTTON, + DEVICE_CLASS_DOORBELL, + DEVICE_CLASS_EMPTY, + DEVICE_CLASS_MOTION, +) +from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_helpers import setup_entity +from esphome.cpp_generator import MockObjClass + +CODEOWNERS = ["@nohat"] +IS_PLATFORM_COMPONENT = True + +DEVICE_CLASSES = [ + DEVICE_CLASS_BUTTON, + DEVICE_CLASS_EMPTY, + DEVICE_CLASS_DOORBELL, + DEVICE_CLASS_MOTION, +] + +event_ns = cg.esphome_ns.namespace("event") +Event = event_ns.class_("Event", cg.EntityBase) +EventPtr = Event.operator("ptr") + +TriggerEventAction = event_ns.class_("TriggerEventAction", automation.Action) + +EventTrigger = event_ns.class_("EventTrigger", automation.Trigger.template()) + +validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") + +EVENT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent), + cv.GenerateID(): cv.declare_id(Event), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_ON_EVENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger), + } + ), + } +) + +_UNDEF = object() + + +def event_schema( + class_: MockObjClass = _UNDEF, + *, + icon: str = _UNDEF, + entity_category: str = _UNDEF, + device_class: str = _UNDEF, +) -> cv.Schema: + schema = {} + + if class_ is not _UNDEF: + schema[cv.GenerateID()] = cv.declare_id(class_) + + for key, default, validator in [ + (CONF_ICON, icon, cv.icon), + (CONF_ENTITY_CATEGORY, entity_category, cv.entity_category), + (CONF_DEVICE_CLASS, device_class, validate_device_class), + ]: + if default is not _UNDEF: + schema[cv.Optional(key, default=default)] = validator + + return EVENT_SCHEMA.extend(schema) + + +async def setup_event_core_(var, config, *, event_types: list[str]): + await setup_entity(var, config) + + for conf in config.get(CONF_ON_EVENT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation( + trigger, [(cg.std_string, "event_type")], conf + ) + + cg.add(var.set_event_types(event_types)) + + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: + cg.add(var.set_device_class(device_class)) + + if mqtt_id := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id, var) + await mqtt.register_mqtt_component(mqtt_, config) + + +async def register_event(var, config, *, event_types: list[str]): + if not CORE.has_id(config[CONF_ID]): + var = cg.Pvariable(config[CONF_ID], var) + cg.add(cg.App.register_event(var)) + await setup_event_core_(var, config, event_types=event_types) + + +async def new_event(config, *, event_types: list[str]): + var = cg.new_Pvariable(config[CONF_ID]) + await register_event(var, config, event_types=event_types) + return var + + +TRIGGER_EVENT_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(Event), + cv.Required(CONF_EVENT_TYPE): cv.templatable(cv.string_strict), + } +) + + +@automation.register_action("event.trigger", TriggerEventAction, TRIGGER_EVENT_SCHEMA) +async def event_fire_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + templ = await cg.templatable(config[CONF_EVENT_TYPE], args, cg.std_string) + cg.add(var.set_event_type(templ)) + return var + + +@coroutine_with_priority(100.0) +async def to_code(config): + cg.add_define("USE_EVENT") + cg.add_global(event_ns.using) diff --git a/esphome/components/event/automation.h b/esphome/components/event/automation.h new file mode 100644 index 0000000000..9ebcb654a0 --- /dev/null +++ b/esphome/components/event/automation.h @@ -0,0 +1,25 @@ +#pragma once + +#include "esphome/components/event/event.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace event { + +template class TriggerEventAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(std::string, event_type) + + void play(Ts... x) override { this->parent_->trigger(this->event_type_.value(x...)); } +}; + +class EventTrigger : public Trigger { + public: + EventTrigger(Event *event) { + event->add_on_event_callback([this](const std::string &event_type) { this->trigger(event_type); }); + } +}; + +} // namespace event +} // namespace esphome diff --git a/esphome/components/event/event.cpp b/esphome/components/event/event.cpp new file mode 100644 index 0000000000..061afcb026 --- /dev/null +++ b/esphome/components/event/event.cpp @@ -0,0 +1,24 @@ +#include "event.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace event { + +static const char *const TAG = "event"; + +void Event::trigger(const std::string &event_type) { + if (types_.find(event_type) == types_.end()) { + ESP_LOGE(TAG, "'%s': invalid event type for trigger(): %s", this->get_name().c_str(), event_type.c_str()); + return; + } + ESP_LOGD(TAG, "'%s' Triggered event '%s'", this->get_name().c_str(), event_type.c_str()); + this->event_callback_.call(event_type); +} + +void Event::add_on_event_callback(std::function &&callback) { + this->event_callback_.add(std::move(callback)); +} + +} // namespace event +} // namespace esphome diff --git a/esphome/components/event/event.h b/esphome/components/event/event.h new file mode 100644 index 0000000000..067a867360 --- /dev/null +++ b/esphome/components/event/event.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include "esphome/core/component.h" +#include "esphome/core/entity_base.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace event { + +#define LOG_EVENT(prefix, type, obj) \ + if ((obj) != nullptr) { \ + ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ + if (!(obj)->get_icon().empty()) { \ + ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ + } \ + if (!(obj)->get_device_class().empty()) { \ + ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ + } \ + } + +class Event : public EntityBase, public EntityBase_DeviceClass { + public: + void trigger(const std::string &event_type); + void set_event_types(const std::set &event_types) { this->types_ = event_types; } + std::set get_event_types() const { return this->types_; } + void add_on_event_callback(std::function &&callback); + + protected: + CallbackManager event_callback_; + std::set types_; +}; + +} // namespace event +} // namespace esphome diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 72ee81dbbc..7a42140ef6 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -119,6 +119,7 @@ MQTTTextComponent = mqtt_ns.class_("MQTTTextComponent", MQTTComponent) MQTTSelectComponent = mqtt_ns.class_("MQTTSelectComponent", MQTTComponent) MQTTButtonComponent = mqtt_ns.class_("MQTTButtonComponent", MQTTComponent) MQTTLockComponent = mqtt_ns.class_("MQTTLockComponent", MQTTComponent) +MQTTEventComponent = mqtt_ns.class_("MQTTEventComponent", MQTTComponent) MQTTValveComponent = mqtt_ns.class_("MQTTValveComponent", MQTTComponent) MQTTDiscoveryUniqueIdGenerator = mqtt_ns.enum("MQTTDiscoveryUniqueIdGenerator") diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index 2209f96e7a..66872680bb 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -73,6 +73,8 @@ constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "en"; constexpr const char *const MQTT_ENTITY_CATEGORY = "ent_cat"; constexpr const char *const MQTT_ERROR_TEMPLATE = "err_tpl"; constexpr const char *const MQTT_ERROR_TOPIC = "err_t"; +constexpr const char *const MQTT_EVENT_TYPE = "event_type"; +constexpr const char *const MQTT_EVENT_TYPES = "evt_typ"; constexpr const char *const MQTT_EXPIRE_AFTER = "exp_aft"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_cmd_tpl"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_cmd_t"; @@ -330,6 +332,8 @@ constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "enabled_by_default"; constexpr const char *const MQTT_ENTITY_CATEGORY = "entity_category"; constexpr const char *const MQTT_ERROR_TEMPLATE = "error_template"; constexpr const char *const MQTT_ERROR_TOPIC = "error_topic"; +constexpr const char *const MQTT_EVENT_TYPE = "event_type"; +constexpr const char *const MQTT_EVENT_TYPES = "event_types"; constexpr const char *const MQTT_EXPIRE_AFTER = "expire_after"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template"; constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic"; diff --git a/esphome/components/mqtt/mqtt_event.cpp b/esphome/components/mqtt/mqtt_event.cpp new file mode 100644 index 0000000000..cf0b90e3d6 --- /dev/null +++ b/esphome/components/mqtt/mqtt_event.cpp @@ -0,0 +1,54 @@ +#include "mqtt_event.h" +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_EVENT + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.event"; + +using namespace esphome::event; + +MQTTEventComponent::MQTTEventComponent(event::Event *event) : event_(event) {} + +void MQTTEventComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + JsonArray event_types = root.createNestedArray(MQTT_EVENT_TYPES); + for (const auto &event_type : this->event_->get_event_types()) + event_types.add(event_type); + + if (!this->event_->get_device_class().empty()) + root[MQTT_DEVICE_CLASS] = this->event_->get_device_class(); + + config.command_topic = false; +} + +void MQTTEventComponent::setup() { + this->event_->add_on_event_callback([this](const std::string &event_type) { this->publish_event_(event_type); }); +} + +void MQTTEventComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Event '%s': ", this->event_->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Event Types: "); + for (const auto &event_type : this->event_->get_event_types()) { + ESP_LOGCONFIG(TAG, "- %s", event_type.c_str()); + } + LOG_MQTT_COMPONENT(true, true); +} + +bool MQTTEventComponent::publish_event_(const std::string &event_type) { + return this->publish_json(this->get_state_topic_(), + [event_type](JsonObject root) { root[MQTT_EVENT_TYPE] = event_type; }); +} + +std::string MQTTEventComponent::component_type() const { return "event"; } +const EntityBase *MQTTEventComponent::get_entity() const { return this->event_; } + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_event.h b/esphome/components/mqtt/mqtt_event.h new file mode 100644 index 0000000000..4335820e53 --- /dev/null +++ b/esphome/components/mqtt/mqtt_event.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_MQTT +#ifdef USE_EVENT + +#include "esphome/components/event/event.h" +#include "mqtt_component.h" + +namespace esphome { +namespace mqtt { + +class MQTTEventComponent : public mqtt::MQTTComponent { + public: + explicit MQTTEventComponent(event::Event *event); + + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + void setup() override; + + void dump_config() override; + + /// Events do not send a state so just return true. + bool send_initial_state() override { return true; } + + protected: + bool publish_event_(const std::string &event_type); + std::string component_type() const override; + const EntityBase *get_entity() const override; + + event::Event *event_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/esphome/components/template/event/__init__.py b/esphome/components/template/event/__init__.py new file mode 100644 index 0000000000..2a948cfdfd --- /dev/null +++ b/esphome/components/template/event/__init__.py @@ -0,0 +1,24 @@ +import esphome.config_validation as cv + +from esphome.components import event + +import esphome.codegen as cg + +from esphome.const import CONF_EVENT_TYPES + +from .. import template_ns + +CODEOWNERS = ["@nohat"] + +TemplateEvent = template_ns.class_("TemplateEvent", event.Event, cg.Component) + +CONFIG_SCHEMA = event.event_schema(TemplateEvent).extend( + { + cv.Required(CONF_EVENT_TYPES): cv.ensure_list(cv.string_strict), + } +) + + +async def to_code(config): + var = await event.new_event(config, event_types=config[CONF_EVENT_TYPES]) + await cg.register_component(var, config) diff --git a/esphome/components/template/event/template_event.h b/esphome/components/template/event/template_event.h new file mode 100644 index 0000000000..251ae9299b --- /dev/null +++ b/esphome/components/template/event/template_event.h @@ -0,0 +1,12 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/event/event.h" + +namespace esphome { +namespace template_ { + +class TemplateEvent : public Component, public event::Event {}; + +} // namespace template_ +} // namespace esphome diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 13e396dc82..8d08783c8c 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -159,5 +159,14 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont } #endif +#ifdef USE_EVENT +bool ListEntitiesIterator::on_event(event::Event *event) { + // Null event type, since we are just iterating over entities + const std::string null_event_type = ""; + this->web_server_->events_.send(this->web_server_->event_json(event, null_event_type, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index d0b8dda233..af84cb1d2b 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -62,6 +62,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_ALARM_CONTROL_PANEL bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; #endif +#ifdef USE_EVENT + bool on_event(event::Event *event) override; +#endif protected: WebServer *web_server_; diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 412f8816ee..0202038ffc 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1352,6 +1352,28 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques } #endif +#ifdef USE_EVENT +void WebServer::on_event(event::Event *obj, const std::string &event_type) { + this->events_.send(this->event_json(obj, event_type, DETAIL_STATE).c_str(), "state"); +} + +std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) { + return json::build_json([obj, event_type, start_config](JsonObject root) { + set_json_id(root, obj, "event-" + obj->get_object_id(), start_config); + if (!event_type.empty()) { + root["event_type"] = event_type; + } + if (start_config == DETAIL_ALL) { + JsonArray event_types = root.createNestedArray("event_types"); + for (auto const &event_type : obj->get_event_types()) { + event_types.add(event_type); + } + root["device_class"] = obj->get_device_class(); + } + }); +} +#endif + bool WebServer::canHandle(AsyncWebServerRequest *request) { if (request->url() == "/") return true; diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 9f807efc43..5e8f3f8236 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -297,6 +297,13 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { alarm_control_panel::AlarmControlPanelState value, JsonDetail start_config); #endif +#ifdef USE_EVENT + void on_event(event::Event *obj, const std::string &event_type) override; + + /// Dump the event details with its value as a JSON string. + std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config); +#endif + /// Override the web handler's canHandle method. bool canHandle(AsyncWebServerRequest *request) override; /// Override the web handler's handleRequest method. diff --git a/esphome/const.py b/esphome/const.py index 8410d36708..dfb7fe464c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -251,6 +251,8 @@ CONF_ESP8266_DISABLE_SSL_SUPPORT = "esp8266_disable_ssl_support" CONF_ESPHOME = "esphome" CONF_ETHERNET = "ethernet" CONF_EVENT = "event" +CONF_EVENT_TYPE = "event_type" +CONF_EVENT_TYPES = "event_types" CONF_EXPIRE_AFTER = "expire_after" CONF_EXPORT_ACTIVE_ENERGY = "export_active_energy" CONF_EXPORT_REACTIVE_ENERGY = "export_reactive_energy" @@ -517,6 +519,7 @@ CONF_ON_DOUBLE_CLICK = "on_double_click" CONF_ON_ENROLLMENT_DONE = "on_enrollment_done" CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed" CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan" +CONF_ON_EVENT = "on_event" CONF_ON_FINGER_SCAN_INVALID = "on_finger_scan_invalid" CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched" CONF_ON_FINGER_SCAN_MISPLACED = "on_finger_scan_misplaced" @@ -1024,6 +1027,7 @@ DEVICE_CLASS_AWNING = "awning" DEVICE_CLASS_BATTERY = "battery" DEVICE_CLASS_BATTERY_CHARGING = "battery_charging" DEVICE_CLASS_BLIND = "blind" +DEVICE_CLASS_BUTTON = "button" DEVICE_CLASS_CARBON_DIOXIDE = "carbon_dioxide" DEVICE_CLASS_CARBON_MONOXIDE = "carbon_monoxide" DEVICE_CLASS_COLD = "cold" @@ -1036,6 +1040,7 @@ DEVICE_CLASS_DATA_SIZE = "data_size" DEVICE_CLASS_DATE = "date" DEVICE_CLASS_DISTANCE = "distance" DEVICE_CLASS_DOOR = "door" +DEVICE_CLASS_DOORBELL = "doorbell" DEVICE_CLASS_DURATION = "duration" DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_ENERGY = "energy" diff --git a/esphome/core/application.h b/esphome/core/application.h index ee931282a6..35df350ec3 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -63,6 +63,9 @@ #ifdef USE_ALARM_CONTROL_PANEL #include "esphome/components/alarm_control_panel/alarm_control_panel.h" #endif +#ifdef USE_EVENT +#include "esphome/components/event/event.h" +#endif namespace esphome { @@ -164,6 +167,10 @@ class Application { } #endif +#ifdef USE_EVENT + void register_event(event::Event *event) { this->events_.push_back(event); } +#endif + /// Register the component in this Application instance. template C *register_component(C *c) { static_assert(std::is_base_of::value, "Only Component subclasses can be registered"); @@ -386,6 +393,16 @@ class Application { } #endif +#ifdef USE_EVENT + const std::vector &get_events() { return this->events_; } + event::Event *get_event_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->events_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif + Scheduler scheduler; protected: @@ -409,6 +426,9 @@ class Application { #ifdef USE_BUTTON std::vector buttons_{}; #endif +#ifdef USE_EVENT + std::vector events_{}; +#endif #ifdef USE_SENSOR std::vector sensors_{}; #endif diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index b00154c685..687f1f6e23 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -321,6 +321,21 @@ void ComponentIterator::advance() { } } break; +#endif +#ifdef USE_EVENT + case IteratorState::EVENT: + if (this->at_ >= App.get_events().size()) { + advance_platform = true; + } else { + auto *event = App.get_events()[this->at_]; + if (event->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_event(event); + } + } + break; #endif case IteratorState::MAX: if (this->on_end()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index 3fbbc0bc19..8f0398cbb3 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -80,6 +80,9 @@ class ComponentIterator { #endif #ifdef USE_ALARM_CONTROL_PANEL virtual bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) = 0; +#endif +#ifdef USE_EVENT + virtual bool on_event(event::Event *event) = 0; #endif virtual bool on_end(); @@ -146,6 +149,9 @@ class ComponentIterator { #endif #ifdef USE_ALARM_CONTROL_PANEL ALARM_CONTROL_PANEL, +#endif +#ifdef USE_EVENT + EVENT, #endif MAX, } state_{IteratorState::NONE}; diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index eab818bdb4..eb975eaf6f 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -109,6 +109,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_state_callback([this, obj]() { this->on_alarm_control_panel_update(obj); }); } #endif +#ifdef USE_EVENT + for (auto *obj : App.get_events()) { + if (include_internal || !obj->is_internal()) + obj->add_on_event_callback([this, obj](const std::string &event_type) { this->on_event(obj, event_type); }); + } +#endif } } // namespace esphome diff --git a/esphome/core/controller.h b/esphome/core/controller.h index 94a4acb7c7..da9dbc00a6 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -55,6 +55,9 @@ #ifdef USE_ALARM_CONTROL_PANEL #include "esphome/components/alarm_control_panel/alarm_control_panel.h" #endif +#ifdef USE_EVENT +#include "esphome/components/event/event.h" +#endif namespace esphome { @@ -112,6 +115,9 @@ class Controller { #ifdef USE_ALARM_CONTROL_PANEL virtual void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj){}; #endif +#ifdef USE_EVENT + virtual void on_event(event::Event *obj, const std::string &event_type){}; +#endif }; } // namespace esphome diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 2064ca1356..fed73098d2 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -24,6 +24,7 @@ #define USE_CLIMATE #define USE_COVER #define USE_DEEP_SLEEP +#define USE_EVENT #define USE_FAN #define USE_GRAPH #define USE_HOMEASSISTANT_TIME diff --git a/script/ci-custom.py b/script/ci-custom.py index c591bfe5c3..27fcd480f5 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -624,6 +624,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/datetime/date_entity.h", "esphome/components/datetime/time_entity.h", "esphome/components/display/display.h", + "esphome/components/event/event.h", "esphome/components/fan/fan.h", "esphome/components/i2c/i2c.h", "esphome/components/lock/lock.h", diff --git a/tests/components/event/test.esp32-c3-idf.yaml b/tests/components/event/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.esp32-c3-idf.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.esp32-c3.yaml b/tests/components/event/test.esp32-c3.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.esp32-c3.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.esp32-idf.yaml b/tests/components/event/test.esp32-idf.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.esp32-idf.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.esp32.yaml b/tests/components/event/test.esp32.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.esp32.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.esp8266.yaml b/tests/components/event/test.esp8266.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.esp8266.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.rp2040.yaml b/tests/components/event/test.rp2040.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/test.rp2040.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired From 1ac855f2e0d38564678ffddeb4a8182e2fea5721 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:49:16 +1200 Subject: [PATCH 1621/2607] Only check c/c++ files with clang-format (#6620) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 15e59b7eb7..6f4bb52104 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,4 +39,4 @@ repos: rev: v13.0.1 hooks: - id: clang-format - + types_or: [c, c++] From a7079f8fba599da736a033885dcb112f2dc8ee05 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 24 Apr 2024 05:07:07 +0200 Subject: [PATCH 1622/2607] Added base64 helper (#4866) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/helpers.cpp | 97 ++++++++++++++++++++++++++++++++++++++++ esphome/core/helpers.h | 10 +++++ 2 files changed, 107 insertions(+) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 0f7afc6a4e..4368576301 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -433,6 +433,103 @@ int8_t step_to_accuracy_decimals(float step) { return str.length() - dot_pos - 1; } +static inline bool is_base64(char c) { return (isalnum(c) || (c == '+') || (c == '/')); } + +std::string base64_encode(const std::vector &buf) { return base64_encode(buf.data(), buf.size()); } + +std::string base64_encode(const char *buf, unsigned int buf_len) { + std::string ret; + int i = 0; + int j = 0; + char char_array_3[3]; + char char_array_4[4]; + + while (buf_len--) { + char_array_3[i++] = *(buf++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; (i < 4); i++) + ret += BASE64_CHARS[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += BASE64_CHARS[char_array_4[j]]; + + while ((i++ < 3)) + ret += '='; + } + + return ret; +} + +size_t base64_decode(const std::string &encoded_string, uint8_t *buf, size_t buf_len) { + std::vector decoded = base64_decode(encoded_string); + if (decoded.size() > buf_len) { + ESP_LOGW(TAG, "Base64 decode: buffer too small, truncating"); + decoded.resize(buf_len); + } + memcpy(buf, decoded.data(), decoded.size()); + return decoded.size(); +} + +std::vector base64_decode(const std::string &encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in = 0; + uint8_t char_array_4[4], char_array_3[3]; + std::vector ret; + + while (in_len-- && (encoded_string[in] != '=') && is_base64(encoded_string[in])) { + char_array_4[i++] = encoded_string[in]; + in++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = BASE64_CHARS.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret.push_back(char_array_3[i]); + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = BASE64_CHARS.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) + ret.push_back(char_array_3[j]); + } + + return ret; +} + // Colors float gamma_correct(float value, float gamma) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index c3ed443bf0..b2d72b0fab 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -435,6 +435,16 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals); /// Derive accuracy in decimals from an increment step. int8_t step_to_accuracy_decimals(float step); +static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +std::string base64_encode(const uint8_t *buf, size_t buf_len); +std::string base64_encode(const std::vector &buf); + +std::vector base64_decode(const std::string &encoded_string); +size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len); + ///@} /// @name Colors From e2b0d561bc02c9b9707cb06aeae46bba522145a7 Mon Sep 17 00:00:00 2001 From: rforro Date: Wed, 24 Apr 2024 05:21:08 +0200 Subject: [PATCH 1623/2607] Add Roomba IR protocol (#4595) Co-authored-by: Richard Forro Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/remote_base/__init__.py | 39 +++++++++++++ .../remote_base/roomba_protocol.cpp | 56 +++++++++++++++++++ .../components/remote_base/roomba_protocol.h | 35 ++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 esphome/components/remote_base/roomba_protocol.cpp create mode 100644 esphome/components/remote_base/roomba_protocol.h diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 6deab63c60..8a1d50d1c6 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -881,6 +881,45 @@ async def pronto_action(var, config, args): cg.add(var.set_data(template_)) +# Roomba +( + RoombaData, + RoombaBinarySensor, + RoombaTrigger, + RoombaAction, + RoombaDumper, +) = declare_protocol("Roomba") +ROOMBA_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint8_t}) + + +@register_binary_sensor("roomba", RoombaBinarySensor, ROOMBA_SCHEMA) +def roomba_binary_sensor(var, config): + cg.add( + var.set_data( + cg.StructInitializer( + RoombaData, + ("data", config[CONF_DATA]), + ) + ) + ) + + +@register_trigger("roomba", RoombaTrigger, RoombaData) +def roomba_trigger(var, config): + pass + + +@register_dumper("roomba", RoombaDumper) +def roomba_dumper(var, config): + pass + + +@register_action("roomba", RoombaAction, ROOMBA_SCHEMA) +async def roomba_action(var, config, args): + template_ = await cg.templatable(config[CONF_DATA], args, cg.uint8) + cg.add(var.set_data(template_)) + + # Sony SonyData, SonyBinarySensor, SonyTrigger, SonyAction, SonyDumper = declare_protocol( "Sony" diff --git a/esphome/components/remote_base/roomba_protocol.cpp b/esphome/components/remote_base/roomba_protocol.cpp new file mode 100644 index 0000000000..2d2dde114a --- /dev/null +++ b/esphome/components/remote_base/roomba_protocol.cpp @@ -0,0 +1,56 @@ +#include "roomba_protocol.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace remote_base { + +static const char *const TAG = "remote.roomba"; + +static const uint8_t NBITS = 8; +static const uint32_t BIT_ONE_HIGH_US = 3000; +static const uint32_t BIT_ONE_LOW_US = 1000; +static const uint32_t BIT_ZERO_HIGH_US = BIT_ONE_LOW_US; +static const uint32_t BIT_ZERO_LOW_US = BIT_ONE_HIGH_US; + +void RoombaProtocol::encode(RemoteTransmitData *dst, const RoombaData &data) { + dst->set_carrier_frequency(38000); + dst->reserve(NBITS * 2u); + + for (uint32_t mask = 1UL << (NBITS - 1); mask != 0; mask >>= 1) { + if (data.data & mask) { + dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US); + } else { + dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US); + } + } +} +optional RoombaProtocol::decode(RemoteReceiveData src) { + RoombaData out{.data = 0}; + + for (uint8_t i = 0; i < (NBITS - 1); i++) { + out.data <<= 1UL; + if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) { + out.data |= 1UL; + } else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) { + out.data |= 0UL; + } else { + return {}; + } + } + + // not possible to measure space on last bit, check only mark + out.data <<= 1UL; + if (src.expect_mark(BIT_ONE_HIGH_US)) { + out.data |= 1UL; + } else if (src.expect_mark(BIT_ZERO_HIGH_US)) { + out.data |= 0UL; + } else { + return {}; + } + + return out; +} +void RoombaProtocol::dump(const RoombaData &data) { ESP_LOGD(TAG, "Received Roomba: data=0x%02X", data.data); } + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/remote_base/roomba_protocol.h b/esphome/components/remote_base/roomba_protocol.h new file mode 100644 index 0000000000..f94cb7df1b --- /dev/null +++ b/esphome/components/remote_base/roomba_protocol.h @@ -0,0 +1,35 @@ +#pragma once + +#include "remote_base.h" + +namespace esphome { +namespace remote_base { + +struct RoombaData { + uint8_t data; + + bool operator==(const RoombaData &rhs) const { return data == rhs.data; } +}; + +class RoombaProtocol : public RemoteProtocol { + public: + void encode(RemoteTransmitData *dst, const RoombaData &data) override; + optional decode(RemoteReceiveData src) override; + void dump(const RoombaData &data) override; +}; + +DECLARE_REMOTE_PROTOCOL(Roomba) + +template class RoombaAction : public RemoteTransmitterActionBase { + public: + TEMPLATABLE_VALUE(uint8_t, data) + + void encode(RemoteTransmitData *dst, Ts... x) override { + RoombaData data{}; + data.data = this->data_.value(x...); + RoombaProtocol().encode(dst, data); + } +}; + +} // namespace remote_base +} // namespace esphome From 1775c73e53f991194fdb318022ece516255c5ce6 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 24 Apr 2024 05:56:56 +0200 Subject: [PATCH 1624/2607] Fix issue when setting cw/ww brightness via temperature (#5976) --- esphome/components/light/light_call.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/esphome/components/light/light_call.cpp b/esphome/components/light/light_call.cpp index 8dc5d4fbe7..c2600d05c2 100644 --- a/esphome/components/light/light_call.cpp +++ b/esphome/components/light/light_call.cpp @@ -337,9 +337,12 @@ LightColorValues LightCall::validate_() { void LightCall::transform_parameters_() { auto traits = this->parent_->get_traits(); - // Allow CWWW modes to be set with a white value and/or color temperature. This is used by HA, - // which doesn't support CWWW modes (yet?), and for compatibility with the pre-colormode model, - // as CWWW and RGBWW lights used to represent their values as white + color temperature. + // Allow CWWW modes to be set with a white value and/or color temperature. + // This is used in three cases in HA: + // - CW/WW lights, which set the "brightness" and "color_temperature" + // - RGBWW lights with color_interlock=true, which also sets "brightness" and + // "color_temperature" (without color_interlock, CW/WW are set directly) + // - Legacy Home Assistant (pre-colormode), which sets "white" and "color_temperature" if (((this->white_.has_value() && *this->white_ > 0.0f) || this->color_temperature_.has_value()) && // (*this->color_mode_ & ColorCapability::COLD_WARM_WHITE) && // !(*this->color_mode_ & ColorCapability::WHITE) && // @@ -347,21 +350,17 @@ void LightCall::transform_parameters_() { traits.get_min_mireds() > 0.0f && traits.get_max_mireds() > 0.0f) { ESP_LOGD(TAG, "'%s' - Setting cold/warm white channels using white/color temperature values.", this->parent_->get_name().c_str()); - auto current_values = this->parent_->remote_values; if (this->color_temperature_.has_value()) { - const float white = - this->white_.value_or(fmaxf(current_values.get_cold_white(), current_values.get_warm_white())); const float color_temp = clamp(*this->color_temperature_, traits.get_min_mireds(), traits.get_max_mireds()); const float ww_fraction = (color_temp - traits.get_min_mireds()) / (traits.get_max_mireds() - traits.get_min_mireds()); const float cw_fraction = 1.0f - ww_fraction; const float max_cw_ww = std::max(ww_fraction, cw_fraction); - this->cold_white_ = white * gamma_uncorrect(cw_fraction / max_cw_ww, this->parent_->get_gamma_correct()); - this->warm_white_ = white * gamma_uncorrect(ww_fraction / max_cw_ww, this->parent_->get_gamma_correct()); - } else { - const float max_cw_ww = std::max(current_values.get_warm_white(), current_values.get_cold_white()); - this->cold_white_ = *this->white_ * current_values.get_cold_white() / max_cw_ww; - this->warm_white_ = *this->white_ * current_values.get_warm_white() / max_cw_ww; + this->cold_white_ = gamma_uncorrect(cw_fraction / max_cw_ww, this->parent_->get_gamma_correct()); + this->warm_white_ = gamma_uncorrect(ww_fraction / max_cw_ww, this->parent_->get_gamma_correct()); + } + if (this->white_.has_value()) { + this->brightness_ = *this->white_; } } } From 41b19504bc8490e318f3e35bb7e10386fd44ab0b Mon Sep 17 00:00:00 2001 From: Daniel Kent <129895318+danielkent-net@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:18:54 -0400 Subject: [PATCH 1625/2607] Add get/set color temperature functions in Kelvin (#5006) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/light/light_color_values.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/esphome/components/light/light_color_values.h b/esphome/components/light/light_color_values.h index 10a3c2f335..bad180ce6d 100644 --- a/esphome/components/light/light_color_values.h +++ b/esphome/components/light/light_color_values.h @@ -266,6 +266,21 @@ class LightColorValues { /// Set the color temperature property of these light color values in mired. void set_color_temperature(float color_temperature) { this->color_temperature_ = color_temperature; } + /// Get the color temperature property of these light color values in kelvin. + float get_color_temperature_kelvin() const { + if (this->color_temperature_ <= 0) { + return this->color_temperature_; + } + return 1000000.0 / this->color_temperature_; + } + /// Set the color temperature property of these light color values in kelvin. + void set_color_temperature_kelvin(float color_temperature) { + if (color_temperature <= 0) { + return; + } + this->color_temperature_ = 1000000.0 / color_temperature; + } + /// Get the cold white property of these light color values. In range 0.0 to 1.0. float get_cold_white() const { return this->cold_white_; } /// Set the cold white property of these light color values. In range 0.0 to 1.0. From bdc9c66f7e781d431cc507393877944313b80046 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 25 Apr 2024 11:50:41 +0200 Subject: [PATCH 1626/2607] Move CONF_PLATFORM_VERSION to global const.py (#6629) * remove duplicated definition * format --- esphome/components/esp32/__init__.py | 3 +-- esphome/components/esp8266/__init__.py | 2 +- esphome/components/rp2040/__init__.py | 3 +-- esphome/const.py | 1 + 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 8ae6262f2f..5d74838daa 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -32,6 +32,7 @@ from esphome.const import ( TYPE_GIT, TYPE_LOCAL, __version__, + CONF_PLATFORM_VERSION, ) from esphome.core import CORE, HexInt, TimePeriod import esphome.config_validation as cv @@ -365,8 +366,6 @@ def final_validate(config): return config -CONF_PLATFORM_VERSION = "platform_version" - ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 00729921a3..64b127bda3 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -12,6 +12,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_ESP8266, + CONF_PLATFORM_VERSION, ) from esphome.core import CORE, coroutine_with_priority import esphome.config_validation as cv @@ -146,7 +147,6 @@ def _parse_platform_version(value): return value -CONF_PLATFORM_VERSION = "platform_version" ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index b262a068fb..ace455add7 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -15,6 +15,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_RP2040, + CONF_PLATFORM_VERSION, ) from esphome.core import CORE, coroutine_with_priority, EsphomeError from esphome.helpers import mkdir_p, write_file, copy_file_if_changed @@ -125,8 +126,6 @@ def _parse_platform_version(value): return value -CONF_PLATFORM_VERSION = "platform_version" - ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/const.py b/esphome/const.py index dfb7fe464c..a64bc73f59 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -597,6 +597,7 @@ CONF_PIN_D = "pin_d" CONF_PINS = "pins" CONF_PIXEL_MAPPER = "pixel_mapper" CONF_PLATFORM = "platform" +CONF_PLATFORM_VERSION = "platform_version" CONF_PLATFORMIO_OPTIONS = "platformio_options" CONF_PM_0_3UM = "pm_0_3um" CONF_PM_0_5UM = "pm_0_5um" From 2fa58468939b1319b072f7fc3f123dcc1f916605 Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 25 Apr 2024 12:05:30 +0200 Subject: [PATCH 1627/2607] Ble client fixes for proxy (#6596) --- esphome/components/alpha3/alpha3.cpp | 8 +++-- .../components/am43/sensor/am43_sensor.cpp | 4 ++- .../bluetooth_proxy/bluetooth_connection.cpp | 33 +++++-------------- .../esp32_ble_client/ble_client_base.cpp | 2 +- .../display/pvvx_display.cpp | 6 ++-- 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/esphome/components/alpha3/alpha3.cpp b/esphome/components/alpha3/alpha3.cpp index 17899c31cb..344f2d5a03 100644 --- a/esphome/components/alpha3/alpha3.cpp +++ b/esphome/components/alpha3/alpha3.cpp @@ -97,9 +97,11 @@ void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) { void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { switch (event) { case ESP_GATTC_OPEN_EVT: { - this->response_offset_ = 0; - this->response_length_ = 0; - ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str()); + if (param->open.status == ESP_GATT_OK) { + this->response_offset_ = 0; + this->response_length_ = 0; + ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str()); + } break; } case ESP_GATTC_CONNECT_EVT: { diff --git a/esphome/components/am43/sensor/am43_sensor.cpp b/esphome/components/am43/sensor/am43_sensor.cpp index 008c7768ed..4cc99001ae 100644 --- a/esphome/components/am43/sensor/am43_sensor.cpp +++ b/esphome/components/am43/sensor/am43_sensor.cpp @@ -26,7 +26,9 @@ void Am43::setup() { void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { switch (event) { case ESP_GATTC_OPEN_EVT: { - this->logged_in_ = false; + if (param->open.status == ESP_GATT_OK) { + this->logged_in_ = false; + } break; } case ESP_GATTC_DISCONNECT_EVT: { diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 97a25262cb..543752853e 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -25,9 +25,13 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga this->proxy_->send_connections_free(); break; } + case ESP_GATTC_CLOSE_EVT: { + this->proxy_->send_device_connection(this->address_, false, 0, param->close.reason); + this->set_address(0); + this->proxy_->send_connections_free(); + break; + } case ESP_GATTC_OPEN_EVT: { - if (param->open.conn_id != this->conn_id_) - break; if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) { this->proxy_->send_device_connection(this->address_, false, 0, param->open.status); this->set_address(0); @@ -39,9 +43,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga this->seen_mtu_or_services_ = false; break; } - case ESP_GATTC_CFG_MTU_EVT: { - if (param->cfg_mtu.conn_id != this->conn_id_) - break; + case ESP_GATTC_CFG_MTU_EVT: + case ESP_GATTC_SEARCH_CMPL_EVT: { if (!this->seen_mtu_or_services_) { // We don't know if we will get the MTU or the services first, so // only send the device connection true if we have already received @@ -53,24 +56,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga this->proxy_->send_connections_free(); break; } - case ESP_GATTC_SEARCH_CMPL_EVT: { - if (param->search_cmpl.conn_id != this->conn_id_) - break; - if (!this->seen_mtu_or_services_) { - // We don't know if we will get the MTU or the services first, so - // only send the device connection true if we have already received - // the mtu. - this->seen_mtu_or_services_ = true; - break; - } - this->proxy_->send_device_connection(this->address_, true, this->mtu_); - this->proxy_->send_connections_free(); - break; - } case ESP_GATTC_READ_DESCR_EVT: case ESP_GATTC_READ_CHAR_EVT: { - if (param->read.conn_id != this->conn_id_) - break; if (param->read.status != ESP_GATT_OK) { ESP_LOGW(TAG, "[%d] [%s] Error reading char/descriptor at handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->read.handle, param->read.status); @@ -89,8 +76,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga } case ESP_GATTC_WRITE_CHAR_EVT: case ESP_GATTC_WRITE_DESCR_EVT: { - if (param->write.conn_id != this->conn_id_) - break; if (param->write.status != ESP_GATT_OK) { ESP_LOGW(TAG, "[%d] [%s] Error writing char/descriptor at handle 0x%2X, status=%d", this->connection_index_, this->address_str_.c_str(), param->write.handle, param->write.status); @@ -131,8 +116,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga break; } case ESP_GATTC_NOTIFY_EVT: { - if (param->notify.conn_id != this->conn_id_) - break; ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_NOTIFY_EVT: handle=0x%2X", this->connection_index_, this->address_str_.c_str(), param->notify.handle); api::BluetoothGATTNotifyDataResponse resp; diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index ae83715aea..98e7792792 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -142,7 +142,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(), param->open.status); this->set_state(espbt::ClientState::IDLE); - return false; + break; } auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id); if (ret) { diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp index d192e62430..1856a023cc 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp @@ -24,8 +24,10 @@ void PVVXDisplay::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_ble_gattc_cb_param_t *param) { switch (event) { case ESP_GATTC_OPEN_EVT: - ESP_LOGV(TAG, "[%s] Connected successfully!", this->parent_->address_str().c_str()); - this->delayed_disconnect_(); + if (param->open.status == ESP_GATT_OK) { + ESP_LOGV(TAG, "[%s] Connected successfully!", this->parent_->address_str().c_str()); + this->delayed_disconnect_(); + } break; case ESP_GATTC_DISCONNECT_EVT: ESP_LOGV(TAG, "[%s] Disconnected", this->parent_->address_str().c_str()); From 0662c5e0fb3e760fe488b80ab4cc312e6bd1011c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 26 Apr 2024 07:00:01 +1000 Subject: [PATCH 1628/2607] Fix for #6614- use background_color, improve anti-aliasing (#6618) --- esphome/components/font/font.cpp | 17 ++++++++++------- .../graphical_display_menu.cpp | 15 ++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/esphome/components/font/font.cpp b/esphome/components/font/font.cpp index 5a18429789..3b62b8ca66 100644 --- a/esphome/components/font/font.cpp +++ b/esphome/components/font/font.cpp @@ -129,7 +129,13 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo uint8_t bitmask = 0; uint8_t pixel_data = 0; - float bpp_max = (1 << this->bpp_) - 1; + uint8_t bpp_max = (1 << this->bpp_) - 1; + auto diff_r = (float) color.r - (float) background.r; + auto diff_g = (float) color.g - (float) background.g; + auto diff_b = (float) color.b - (float) background.b; + auto b_r = (float) background.r; + auto b_g = (float) background.g; + auto b_b = (float) background.g; for (int glyph_y = y_start + scan_y1; glyph_y != max_y; glyph_y++) { for (int glyph_x = x_at + scan_x1; glyph_x != max_x; glyph_x++) { uint8_t pixel = 0; @@ -146,12 +152,9 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo if (pixel == bpp_max) { display->draw_pixel_at(glyph_x, glyph_y, color); } else if (pixel != 0) { - float on = (float) pixel / bpp_max; - float off = 1.0 - on; - Color blended; - blended.r = color.r * on + background.r * off; - blended.g = color.r * on + background.g * off; - blended.b = color.r * on + background.b * off; + auto on = (float) pixel / (float) bpp_max; + auto blended = + Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g), (uint8_t) (diff_b * on + b_b)); display->draw_pixel_at(glyph_x, glyph_y, blended); } } diff --git a/esphome/components/graphical_display_menu/graphical_display_menu.cpp b/esphome/components/graphical_display_menu/graphical_display_menu.cpp index fcbad41388..4a4e519009 100644 --- a/esphome/components/graphical_display_menu/graphical_display_menu.cpp +++ b/esphome/components/graphical_display_menu/graphical_display_menu.cpp @@ -104,7 +104,8 @@ void GraphicalDisplayMenu::draw(display::Display *display, const display::Rect * } void GraphicalDisplayMenu::draw_menu_internal_(display::Display *display, const display::Rect *bounds) { - int total_height = 0; + int16_t total_height = 0; + int16_t max_width = 0; int y_padding = 2; bool scroll_menu_items = false; std::vector menu_dimensions; @@ -118,6 +119,7 @@ void GraphicalDisplayMenu::draw_menu_internal_(display::Display *display, const menu_dimensions.push_back(item_dimensions); total_height += item_dimensions.h + (i == 0 ? 0 : y_padding); + max_width = std::max(max_width, item_dimensions.w); if (total_height <= bounds->h) { number_items_fit_to_screen++; @@ -166,7 +168,8 @@ void GraphicalDisplayMenu::draw_menu_internal_(display::Display *display, const // Render the items into the view port display->start_clipping(*bounds); - int y_offset = bounds->y; + display->filled_rectangle(bounds->x, bounds->y, max_width, total_height, this->background_color_); + auto y_offset = bounds->y; for (size_t i = first_item_index; i <= last_item_index; i++) { const auto *item = this->displayed_item_->get_item(i); const bool selected = i == this->cursor_index_; @@ -176,7 +179,7 @@ void GraphicalDisplayMenu::draw_menu_internal_(display::Display *display, const dimensions.x = bounds->x; this->draw_item(display, item, &dimensions, selected); - y_offset = dimensions.y + dimensions.h + y_padding; + y_offset += dimensions.h + y_padding; } display->end_clipping(); @@ -219,9 +222,7 @@ inline void GraphicalDisplayMenu::draw_item(display::Display *display, const dis // int background_width = std::max(bounds->width, available_width); int background_width = bounds->w; - if (selected) { - display->filled_rectangle(bounds->x, bounds->y, background_width, bounds->h, background_color); - } + display->filled_rectangle(bounds->x, bounds->y, background_width, bounds->h, background_color); std::string label = item->get_text(); if (item->has_value()) { @@ -230,7 +231,7 @@ inline void GraphicalDisplayMenu::draw_item(display::Display *display, const dis } display->print(bounds->x, bounds->y, this->font_, foreground_color, display::TextAlign::TOP_LEFT, label.c_str(), - ~foreground_color); + background_color); } void GraphicalDisplayMenu::draw_item(const display_menu_base::MenuItem *item, const uint8_t row, const bool selected) { From de2a92e45de9444b7bcc88e8a0c8984c6240b53b Mon Sep 17 00:00:00 2001 From: chiahsing Date: Fri, 26 Apr 2024 05:01:51 +0800 Subject: [PATCH 1629/2607] Fix graph hangs when y <= 0 (#6593) --- esphome/components/graph/graph.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/graph/graph.cpp b/esphome/components/graph/graph.cpp index 0e437a3425..1178af911d 100644 --- a/esphome/components/graph/graph.cpp +++ b/esphome/components/graph/graph.cpp @@ -164,7 +164,7 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo ESP_LOGV(TAG, "Updating graph. ymin %f, ymax %f", ymin, ymax); for (auto *trace : traces_) { Color c = trace->get_line_color(); - uint16_t thick = trace->get_line_thickness(); + int16_t thick = trace->get_line_thickness(); bool continuous = trace->get_continuous(); bool has_prev = false; bool prev_b = false; @@ -178,20 +178,20 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo if (b) { int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0 - v)) - thick / 2 + y_offset; if (!continuous || !has_prev || !prev_b || (abs(y - prev_y) <= thick)) { - for (uint16_t t = 0; t < thick; t++) { + for (int16_t t = 0; t < thick; t++) { buff->draw_pixel_at(x, y + t, c); } } else { int16_t mid_y = (y + prev_y + thick) / 2; if (y > prev_y) { - for (uint16_t t = prev_y + thick; t <= mid_y; t++) + for (int16_t t = prev_y + thick; t <= mid_y; t++) buff->draw_pixel_at(x + 1, t, c); - for (uint16_t t = mid_y + 1; t < y + thick; t++) + for (int16_t t = mid_y + 1; t < y + thick; t++) buff->draw_pixel_at(x, t, c); } else { - for (uint16_t t = prev_y - 1; t >= mid_y; t--) + for (int16_t t = prev_y - 1; t >= mid_y; t--) buff->draw_pixel_at(x + 1, t, c); - for (uint16_t t = mid_y - 1; t >= y; t--) + for (int16_t t = mid_y - 1; t >= y; t--) buff->draw_pixel_at(x, t, c); } } From 5288d5ac9539cbb1d8e67e6094c7aeb35844c66e Mon Sep 17 00:00:00 2001 From: Nico Peter Date: Thu, 25 Apr 2024 23:04:20 +0200 Subject: [PATCH 1630/2607] Feature add last_operation to time based cover (#6084) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/time_based/time_based_cover.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/time_based/time_based_cover.h b/esphome/components/time_based/time_based_cover.h index b7a826d237..42cf66c2ab 100644 --- a/esphome/components/time_based/time_based_cover.h +++ b/esphome/components/time_based/time_based_cover.h @@ -23,6 +23,7 @@ class TimeBasedCover : public cover::Cover, public Component { void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; } void set_manual_control(bool value) { this->manual_control_ = value; } void set_assumed_state(bool value) { this->assumed_state_ = value; } + cover::CoverOperation get_last_operation() const { return this->last_operation_; } protected: void control(const cover::CoverCall &call) override; From bcef64a6fa67e8c85ae0a03f4f2986361be3e58d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 25 Apr 2024 16:04:48 -0500 Subject: [PATCH 1631/2607] Add `event`, `text_sensor` and `valve` device classes to sync script (#6624) --- script/sync-device_class.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/sync-device_class.py b/script/sync-device_class.py index 8f91b97997..26d271535f 100755 --- a/script/sync-device_class.py +++ b/script/sync-device_class.py @@ -6,9 +6,12 @@ import re from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.button import ButtonDeviceClass from homeassistant.components.cover import CoverDeviceClass +from homeassistant.components.event import EventDeviceClass from homeassistant.components.number import NumberDeviceClass from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.switch import SwitchDeviceClass +from homeassistant.components.text_sensor import TextSensorDeviceClass +from homeassistant.components.valve import ValveDeviceClass # pylint: enable=import-error @@ -21,9 +24,12 @@ DOMAINS = { "binary_sensor": BinarySensorDeviceClass, "button": ButtonDeviceClass, "cover": CoverDeviceClass, + "event": EventDeviceClass, "number": NumberDeviceClass, "sensor": SensorDeviceClass, "switch": SwitchDeviceClass, + "text_sensor": TextSensorDeviceClass, + "valve": ValveDeviceClass, } From 8ef7b41c91deefe9514cf6c6130e0fcbb99ecb6d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 26 Apr 2024 09:19:54 +1200 Subject: [PATCH 1632/2607] Add datetime entities (#6513) --- esphome/components/api/api.proto | 38 +++ esphome/components/api/api_connection.cpp | 38 +++ esphome/components/api/api_connection.h | 5 + esphome/components/api/api_pb2.cpp | 173 ++++++++++++ esphome/components/api/api_pb2.h | 45 ++++ esphome/components/api/api_pb2_service.cpp | 42 +++ esphome/components/api/api_pb2_service.h | 15 ++ esphome/components/api/api_server.cpp | 9 + esphome/components/api/api_server.h | 3 + esphome/components/api/list_entities.cpp | 6 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.cpp | 5 + esphome/components/api/subscribe_state.h | 3 + esphome/components/datetime/__init__.py | 129 ++++++--- esphome/components/datetime/date_entity.cpp | 3 + esphome/components/datetime/datetime_base.h | 7 + .../components/datetime/datetime_entity.cpp | 252 ++++++++++++++++++ esphome/components/datetime/datetime_entity.h | 150 +++++++++++ esphome/components/datetime/time_entity.cpp | 6 +- esphome/components/datetime/time_entity.h | 12 +- esphome/components/mqtt/__init__.py | 1 + esphome/components/mqtt/mqtt_datetime.cpp | 84 ++++++ esphome/components/mqtt/mqtt_datetime.h | 45 ++++ .../components/template/datetime/__init__.py | 22 ++ .../template/datetime/template_datetime.cpp | 150 +++++++++++ .../template/datetime/template_datetime.h | 46 ++++ esphome/components/time/real_time_clock.cpp | 2 + .../components/web_server/list_entities.cpp | 9 + esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 63 +++++ esphome/components/web_server/web_server.h | 9 + esphome/const.py | 1 + esphome/core/application.h | 19 ++ esphome/core/component_iterator.cpp | 15 ++ esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + esphome/core/time.cpp | 9 + esphome/core/time.h | 3 + script/ci-custom.py | 1 + tests/components/datetime/test.all.yaml | 2 + .../template/{test.all.yaml => common.yaml} | 22 ++ tests/components/template/test.bk72xx.yaml | 2 + .../template/test.esp32-c3-idf.yaml | 2 + tests/components/template/test.esp32-c3.yaml | 2 + tests/components/template/test.esp32-idf.yaml | 2 + .../template/test.esp32-s3-idf.yaml | 2 + tests/components/template/test.esp32.yaml | 2 + tests/components/template/test.esp8266.yaml | 2 + tests/components/template/test.rp2040.yaml | 2 + 51 files changed, 1430 insertions(+), 55 deletions(-) create mode 100644 esphome/components/datetime/datetime_entity.cpp create mode 100644 esphome/components/datetime/datetime_entity.h create mode 100644 esphome/components/mqtt/mqtt_datetime.cpp create mode 100644 esphome/components/mqtt/mqtt_datetime.h create mode 100644 esphome/components/template/datetime/template_datetime.cpp create mode 100644 esphome/components/template/datetime/template_datetime.h rename tests/components/template/{test.all.yaml => common.yaml} (88%) create mode 100644 tests/components/template/test.bk72xx.yaml create mode 100644 tests/components/template/test.esp32-c3-idf.yaml create mode 100644 tests/components/template/test.esp32-c3.yaml create mode 100644 tests/components/template/test.esp32-idf.yaml create mode 100644 tests/components/template/test.esp32-s3-idf.yaml create mode 100644 tests/components/template/test.esp32.yaml create mode 100644 tests/components/template/test.esp8266.yaml create mode 100644 tests/components/template/test.rp2040.yaml diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 17826ea7ed..b8073abc19 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -47,6 +47,7 @@ service APIConnection { rpc media_player_command (MediaPlayerCommandRequest) returns (void) {} rpc date_command (DateCommandRequest) returns (void) {} rpc time_command (TimeCommandRequest) returns (void) {} + rpc datetime_command (DateTimeCommandRequest) returns (void) {} rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {} @@ -1777,3 +1778,40 @@ message ValveCommandRequest { float position = 3; bool stop = 4; } + +// ==================== DATETIME DATETIME ==================== +message ListEntitiesDateTimeResponse { + option (id) = 112; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_DATETIME_DATETIME"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; +} +message DateTimeStateResponse { + option (id) = 113; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_DATETIME_DATETIME"; + option (no_delay) = true; + + fixed32 key = 1; + // If the datetime does not have a valid state yet. + // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller + bool missing_state = 2; + fixed32 epoch_seconds = 3; +} +message DateTimeCommandRequest { + option (id) = 114; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_DATETIME_DATETIME"; + option (no_delay) = true; + + fixed32 key = 1; + fixed32 epoch_seconds = 2; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index ec09604d95..b31212bbdb 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -772,6 +772,44 @@ void APIConnection::time_command(const TimeCommandRequest &msg) { } #endif +#ifdef USE_DATETIME_DATETIME +bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) { + if (!this->state_subscription_) + return false; + + DateTimeStateResponse resp{}; + resp.key = datetime->get_object_id_hash(); + resp.missing_state = !datetime->has_state(); + if (datetime->has_state()) { + ESPTime state = datetime->state_as_esptime(); + resp.epoch_seconds = state.timestamp; + } + return this->send_date_time_state_response(resp); +} +bool APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) { + ListEntitiesDateTimeResponse msg; + msg.key = datetime->get_object_id_hash(); + msg.object_id = datetime->get_object_id(); + if (datetime->has_own_name()) + msg.name = datetime->get_name(); + msg.unique_id = get_default_unique_id("datetime", datetime); + msg.icon = datetime->get_icon(); + msg.disabled_by_default = datetime->is_disabled_by_default(); + msg.entity_category = static_cast(datetime->get_entity_category()); + + return this->send_list_entities_date_time_response(msg); +} +void APIConnection::datetime_command(const DateTimeCommandRequest &msg) { + datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key); + if (datetime == nullptr) + return; + + auto call = datetime->make_call(); + call.set_datetime(msg.epoch_seconds); + call.perform(); +} +#endif + #ifdef USE_TEXT bool APIConnection::send_text_state(text::Text *text, std::string state) { if (!this->state_subscription_) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 2c1d733d3e..ee466c5d10 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -82,6 +82,11 @@ class APIConnection : public APIServerConnection { bool send_time_info(datetime::TimeEntity *time); void time_command(const TimeCommandRequest &msg) override; #endif +#ifdef USE_DATETIME_DATETIME + bool send_datetime_state(datetime::DateTimeEntity *datetime); + bool send_datetime_info(datetime::DateTimeEntity *datetime); + void datetime_command(const DateTimeCommandRequest &msg) override; +#endif #ifdef USE_TEXT bool send_text_state(text::Text *text, std::string state); bool send_text_info(text::Text *text); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 3f01d88c58..6ec1870d72 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -8093,6 +8093,179 @@ void ValveCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesDateTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ListEntitiesDateTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + default: + return false; + } +} +bool ListEntitiesDateTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesDateTimeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesDateTimeResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + out.append("}"); +} +#endif +bool DateTimeStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->missing_state = value.as_bool(); + return true; + } + default: + return false; + } +} +bool DateTimeStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + case 3: { + this->epoch_seconds = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void DateTimeStateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_bool(2, this->missing_state); + buffer.encode_fixed32(3, this->epoch_seconds); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void DateTimeStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateTimeStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" epoch_seconds: "); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +bool DateTimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + case 2: { + this->epoch_seconds = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void DateTimeCommandRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_fixed32(2, this->epoch_seconds); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void DateTimeCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateTimeCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" epoch_seconds: "); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 9a6aab254d..14fd95df37 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -2060,6 +2060,51 @@ class ValveCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class ListEntitiesDateTimeResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class DateTimeStateResponse : public ProtoMessage { + public: + uint32_t key{0}; + bool missing_state{false}; + uint32_t epoch_seconds{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class DateTimeCommandRequest : public ProtoMessage { + public: + uint32_t key{0}; + uint32_t epoch_seconds{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index ced81fa643..093fe917e0 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -591,6 +591,24 @@ bool APIServerConnectionBase::send_valve_state_response(const ValveStateResponse #endif #ifdef USE_VALVE #endif +#ifdef USE_DATETIME_DATETIME +bool APIServerConnectionBase::send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_date_time_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 112); +} +#endif +#ifdef USE_DATETIME_DATETIME +bool APIServerConnectionBase::send_date_time_state_response(const DateTimeStateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_date_time_state_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 113); +} +#endif +#ifdef USE_DATETIME_DATETIME +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -1064,6 +1082,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str()); #endif this->on_valve_command_request(msg); +#endif + break; + } + case 114: { +#ifdef USE_DATETIME_DATETIME + DateTimeCommandRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str()); +#endif + this->on_date_time_command_request(msg); #endif break; } @@ -1379,6 +1408,19 @@ void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) this->time_command(msg); } #endif +#ifdef USE_DATETIME_DATETIME +void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->datetime_command(msg); +} +#endif #ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &msg) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index c8b2bc5789..196d904aca 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -294,6 +294,15 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_VALVE virtual void on_valve_command_request(const ValveCommandRequest &value){}; +#endif +#ifdef USE_DATETIME_DATETIME + bool send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg); +#endif +#ifdef USE_DATETIME_DATETIME + bool send_date_time_state_response(const DateTimeStateResponse &msg); +#endif +#ifdef USE_DATETIME_DATETIME + virtual void on_date_time_command_request(const DateTimeCommandRequest &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -358,6 +367,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_TIME virtual void time_command(const TimeCommandRequest &msg) = 0; #endif +#ifdef USE_DATETIME_DATETIME + virtual void datetime_command(const DateTimeCommandRequest &msg) = 0; +#endif #ifdef USE_BLUETOOTH_PROXY virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; #endif @@ -453,6 +465,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_TIME void on_time_command_request(const TimeCommandRequest &msg) override; #endif +#ifdef USE_DATETIME_DATETIME + void on_date_time_command_request(const DateTimeCommandRequest &msg) override; +#endif #ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 6d4e4db1e8..0725547771 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -273,6 +273,15 @@ void APIServer::on_time_update(datetime::TimeEntity *obj) { } #endif +#ifdef USE_DATETIME_DATETIME +void APIServer::on_datetime_update(datetime::DateTimeEntity *obj) { + if (obj->is_internal()) + return; + for (auto &c : this->clients_) + c->send_datetime_state(obj); +} +#endif + #ifdef USE_TEXT void APIServer::on_text_update(text::Text *obj, const std::string &state) { if (obj->is_internal()) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index e9e03cde0d..2e1fbdf67c 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -72,6 +72,9 @@ class APIServer : public Component, public Controller { #ifdef USE_DATETIME_TIME void on_time_update(datetime::TimeEntity *obj) override; #endif +#ifdef USE_DATETIME_DATETIME + void on_datetime_update(datetime::DateTimeEntity *obj) override; +#endif #ifdef USE_TEXT void on_text_update(text::Text *obj, const std::string &state) override; #endif diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index 82bfd45333..a7dbf9a6e7 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -71,6 +71,12 @@ bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { return this->cl bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_info(time); } #endif +#ifdef USE_DATETIME_DATETIME +bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) { + return this->client_->send_datetime_info(datetime); +} +#endif + #ifdef USE_TEXT bool ListEntitiesIterator::on_text(text::Text *text) { return this->client_->send_text_info(text); } #endif diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index 19cd99ea01..c1fd8b82c4 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -52,6 +52,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_DATETIME_TIME bool on_time(datetime::TimeEntity *time) override; #endif +#ifdef USE_DATETIME_DATETIME + bool on_datetime(datetime::DateTimeEntity *datetime) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 7aa8e8ffac..005ab0e6da 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -48,6 +48,11 @@ bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->cl #ifdef USE_DATETIME_TIME bool InitialStateIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_state(time); } #endif +#ifdef USE_DATETIME_DATETIME +bool InitialStateIterator::on_datetime(datetime::DateTimeEntity *datetime) { + return this->client_->send_datetime_state(datetime); +} +#endif #ifdef USE_TEXT bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text, text->state); } #endif diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 17d444c441..8c725e422e 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -49,6 +49,9 @@ class InitialStateIterator : public ComponentIterator { #ifdef USE_DATETIME_TIME bool on_time(datetime::TimeEntity *time) override; #endif +#ifdef USE_DATETIME_DATETIME + bool on_datetime(datetime::DateTimeEntity *datetime) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index a22c60aae9..639a035159 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -1,6 +1,5 @@ import esphome.codegen as cg -# import cpp_generator as cpp import esphome.config_validation as cv from esphome import automation from esphome.components import mqtt, time @@ -13,6 +12,7 @@ from esphome.const import ( CONF_TYPE, CONF_MQTT_ID, CONF_DATE, + CONF_DATETIME, CONF_TIME, CONF_YEAR, CONF_MONTH, @@ -27,6 +27,7 @@ from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@rfdarter", "@jesserockz"] +DEPENDENCIES = ["time"] IS_PLATFORM_COMPONENT = True @@ -34,10 +35,12 @@ datetime_ns = cg.esphome_ns.namespace("datetime") DateTimeBase = datetime_ns.class_("DateTimeBase", cg.EntityBase) DateEntity = datetime_ns.class_("DateEntity", DateTimeBase) TimeEntity = datetime_ns.class_("TimeEntity", DateTimeBase) +DateTimeEntity = datetime_ns.class_("DateTimeEntity", DateTimeBase) # Actions DateSetAction = datetime_ns.class_("DateSetAction", automation.Action) TimeSetAction = datetime_ns.class_("TimeSetAction", automation.Action) +DateTimeSetAction = datetime_ns.class_("DateTimeSetAction", automation.Action) DateTimeStateTrigger = datetime_ns.class_( "DateTimeStateTrigger", automation.Trigger.template(cg.ESPTime) @@ -46,6 +49,12 @@ DateTimeStateTrigger = datetime_ns.class_( OnTimeTrigger = datetime_ns.class_( "OnTimeTrigger", automation.Trigger, cg.Component, cg.Parented.template(TimeEntity) ) +OnDateTimeTrigger = datetime_ns.class_( + "OnDateTimeTrigger", + automation.Trigger, + cg.Component, + cg.Parented.template(DateTimeEntity), +) DATETIME_MODES = [ "DATE", @@ -61,45 +70,55 @@ _DATETIME_SCHEMA = cv.Schema( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), } ), + cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), } ).extend(cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)) def date_schema(class_: MockObjClass) -> cv.Schema: - schema = { - cv.GenerateID(): cv.declare_id(class_), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTDateComponent), - cv.Optional(CONF_TYPE, default="DATE"): cv.one_of("DATE", upper=True), - } + schema = cv.Schema( + { + cv.GenerateID(): cv.declare_id(class_), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTDateComponent), + cv.Optional(CONF_TYPE, default="DATE"): cv.one_of("DATE", upper=True), + } + ) return _DATETIME_SCHEMA.extend(schema) def time_schema(class_: MockObjClass) -> cv.Schema: - schema = { - cv.GenerateID(): cv.declare_id(class_), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTimeComponent), - cv.Optional(CONF_TYPE, default="TIME"): cv.one_of("TIME", upper=True), - cv.Inclusive( - CONF_ON_TIME, - group_of_inclusion=CONF_ON_TIME, - msg="`on_time` and `time_id` must both be specified", - ): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnTimeTrigger), - } - ), - cv.Inclusive(CONF_TIME_ID, group_of_inclusion=CONF_ON_TIME): cv.use_id( - time.RealTimeClock - ), - } + schema = cv.Schema( + { + cv.GenerateID(): cv.declare_id(class_), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTimeComponent), + cv.Optional(CONF_TYPE, default="TIME"): cv.one_of("TIME", upper=True), + cv.Optional(CONF_ON_TIME): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnTimeTrigger), + } + ), + } + ) return _DATETIME_SCHEMA.extend(schema) def datetime_schema(class_: MockObjClass) -> cv.Schema: - schema = { - cv.GenerateID(): cv.declare_id(class_), - cv.Optional(CONF_TYPE, default="DATETIME"): cv.one_of("DATETIME", upper=True), - } + schema = cv.Schema( + { + cv.GenerateID(): cv.declare_id(class_), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( + mqtt.MQTTDateTimeComponent + ), + cv.Optional(CONF_TYPE, default="DATETIME"): cv.one_of( + "DATETIME", upper=True + ), + cv.Optional(CONF_ON_TIME): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnDateTimeTrigger), + } + ), + } + ) return _DATETIME_SCHEMA.extend(schema) @@ -113,13 +132,11 @@ async def setup_datetime_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) - rtc_id = config.get(CONF_TIME_ID) - rtc = None - if rtc_id is not None: - rtc = await cg.get_variable(rtc_id) + rtc = await cg.get_variable(config[CONF_TIME_ID]) + cg.add(var.set_rtc(rtc)) + for conf in config.get(CONF_ON_TIME, []): - assert rtc is not None - trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], rtc) + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await automation.build_automation(trigger, [], conf) await cg.register_component(trigger, conf) await cg.register_parented(trigger, var) @@ -161,16 +178,16 @@ async def datetime_date_set_to_code(config, action_id, template_arg, args): action_var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(action_var, config[CONF_ID]) - date = config[CONF_DATE] - if cg.is_template(date): - template_ = await cg.templatable(config[CONF_DATE], [], cg.ESPTime) + date_config = config[CONF_DATE] + if cg.is_template(date_config): + template_ = await cg.templatable(date_config, [], cg.ESPTime) cg.add(action_var.set_date(template_)) else: date_struct = cg.StructInitializer( cg.ESPTime, - ("day_of_month", date[CONF_DAY]), - ("month", date[CONF_MONTH]), - ("year", date[CONF_YEAR]), + ("day_of_month", date_config[CONF_DAY]), + ("month", date_config[CONF_MONTH]), + ("year", date_config[CONF_YEAR]), ) cg.add(action_var.set_date(date_struct)) return action_var @@ -194,7 +211,7 @@ async def datetime_time_set_to_code(config, action_id, template_arg, args): time_config = config[CONF_TIME] if cg.is_template(time_config): - template_ = await cg.templatable(config[CONF_TIME], [], cg.ESPTime) + template_ = await cg.templatable(time_config, [], cg.ESPTime) cg.add(action_var.set_time(template_)) else: time_struct = cg.StructInitializer( @@ -205,3 +222,35 @@ async def datetime_time_set_to_code(config, action_id, template_arg, args): ) cg.add(action_var.set_time(time_struct)) return action_var + + +@automation.register_action( + "datetime.datetime.set", + DateTimeSetAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(DateTimeEntity), + cv.Required(CONF_DATETIME): cv.Any(cv.returning_lambda, cv.date_time()), + }, + ), +) +async def datetime_datetime_set_to_code(config, action_id, template_arg, args): + action_var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(action_var, config[CONF_ID]) + + datetime_config = config[CONF_DATETIME] + if cg.is_template(datetime_config): + template_ = await cg.templatable(datetime_config, [], cg.ESPTime) + cg.add(action_var.set_datetime(template_)) + else: + datetime_struct = cg.StructInitializer( + cg.ESPTime, + ("second", datetime_config[CONF_SECOND]), + ("minute", datetime_config[CONF_MINUTE]), + ("hour", datetime_config[CONF_HOUR]), + ("day_of_month", datetime_config[CONF_DAY]), + ("month", datetime_config[CONF_MONTH]), + ("year", datetime_config[CONF_YEAR]), + ) + cg.add(action_var.set_datetime(datetime_struct)) + return action_var diff --git a/esphome/components/datetime/date_entity.cpp b/esphome/components/datetime/date_entity.cpp index 8b58a8faf7..19399c1e59 100644 --- a/esphome/components/datetime/date_entity.cpp +++ b/esphome/components/datetime/date_entity.cpp @@ -40,10 +40,13 @@ void DateCall::validate_() { if (this->year_.has_value() && (this->year_ < 1970 || this->year_ > 3000)) { ESP_LOGE(TAG, "Year must be between 1970 and 3000"); this->year_.reset(); + this->month_.reset(); + this->day_.reset(); } if (this->month_.has_value() && (this->month_ < 1 || this->month_ > 12)) { ESP_LOGE(TAG, "Month must be between 1 and 12"); this->month_.reset(); + this->day_.reset(); } if (this->day_.has_value()) { uint16_t year = 0; diff --git a/esphome/components/datetime/datetime_base.h b/esphome/components/datetime/datetime_base.h index 2f2d27e102..c8240390e3 100644 --- a/esphome/components/datetime/datetime_base.h +++ b/esphome/components/datetime/datetime_base.h @@ -5,6 +5,8 @@ #include "esphome/core/entity_base.h" #include "esphome/core/time.h" +#include "esphome/components/time/real_time_clock.h" + namespace esphome { namespace datetime { @@ -17,9 +19,14 @@ class DateTimeBase : public EntityBase { void add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } + void set_rtc(time::RealTimeClock *rtc) { this->rtc_ = rtc; } + time::RealTimeClock *get_rtc() const { return this->rtc_; } + protected: CallbackManager state_callback_; + time::RealTimeClock *rtc_; + bool has_state_{false}; }; diff --git a/esphome/components/datetime/datetime_entity.cpp b/esphome/components/datetime/datetime_entity.cpp new file mode 100644 index 0000000000..9a61d341e4 --- /dev/null +++ b/esphome/components/datetime/datetime_entity.cpp @@ -0,0 +1,252 @@ +#include "datetime_entity.h" + +#ifdef USE_DATETIME_DATETIME + +#include "esphome/core/log.h" + +namespace esphome { +namespace datetime { + +static const char *const TAG = "datetime.datetime_entity"; + +void DateTimeEntity::publish_state() { + if (this->year_ == 0 || this->month_ == 0 || this->day_ == 0) { + this->has_state_ = false; + return; + } + if (this->year_ < 1970 || this->year_ > 3000) { + this->has_state_ = false; + ESP_LOGE(TAG, "Year must be between 1970 and 3000"); + return; + } + if (this->month_ < 1 || this->month_ > 12) { + this->has_state_ = false; + ESP_LOGE(TAG, "Month must be between 1 and 12"); + return; + } + if (this->day_ > days_in_month(this->month_, this->year_)) { + this->has_state_ = false; + ESP_LOGE(TAG, "Day must be between 1 and %d for month %d", days_in_month(this->month_, this->year_), this->month_); + return; + } + if (this->hour_ > 23) { + this->has_state_ = false; + ESP_LOGE(TAG, "Hour must be between 0 and 23"); + return; + } + if (this->minute_ > 59) { + this->has_state_ = false; + ESP_LOGE(TAG, "Minute must be between 0 and 59"); + return; + } + if (this->second_ > 59) { + this->has_state_ = false; + ESP_LOGE(TAG, "Second must be between 0 and 59"); + return; + } + this->has_state_ = true; + ESP_LOGD(TAG, "'%s': Sending datetime %04u-%02u-%02u %02d:%02d:%02d", this->get_name().c_str(), this->year_, + this->month_, this->day_, this->hour_, this->minute_, this->second_); + this->state_callback_.call(); +} + +DateTimeCall DateTimeEntity::make_call() { return DateTimeCall(this); } + +ESPTime DateTimeEntity::state_as_esptime() const { + ESPTime obj; + obj.year = this->year_; + obj.month = this->month_; + obj.day_of_month = this->day_; + obj.hour = this->hour_; + obj.minute = this->minute_; + obj.second = this->second_; + obj.day_of_week = 1; // Required to be valid for recalc_timestamp_local but not used. + obj.day_of_year = 1; // Required to be valid for recalc_timestamp_local but not used. + obj.recalc_timestamp_local(false); + return obj; +} + +void DateTimeCall::validate_() { + if (this->year_.has_value() && (this->year_ < 1970 || this->year_ > 3000)) { + ESP_LOGE(TAG, "Year must be between 1970 and 3000"); + this->year_.reset(); + this->month_.reset(); + this->day_.reset(); + } + if (this->month_.has_value() && (this->month_ < 1 || this->month_ > 12)) { + ESP_LOGE(TAG, "Month must be between 1 and 12"); + this->month_.reset(); + this->day_.reset(); + } + if (this->day_.has_value()) { + uint16_t year = 0; + uint8_t month = 0; + if (this->month_.has_value()) { + month = *this->month_; + } else { + if (this->parent_->month != 0) { + month = this->parent_->month; + } else { + ESP_LOGE(TAG, "Month must be set to validate day"); + this->day_.reset(); + } + } + if (this->year_.has_value()) { + year = *this->year_; + } else { + if (this->parent_->year != 0) { + year = this->parent_->year; + } else { + ESP_LOGE(TAG, "Year must be set to validate day"); + this->day_.reset(); + } + } + if (this->day_.has_value() && *this->day_ > days_in_month(month, year)) { + ESP_LOGE(TAG, "Day must be between 1 and %d for month %d", days_in_month(month, year), month); + this->day_.reset(); + } + } + + if (this->hour_.has_value() && this->hour_ > 23) { + ESP_LOGE(TAG, "Hour must be between 0 and 23"); + this->hour_.reset(); + } + if (this->minute_.has_value() && this->minute_ > 59) { + ESP_LOGE(TAG, "Minute must be between 0 and 59"); + this->minute_.reset(); + } + if (this->second_.has_value() && this->second_ > 59) { + ESP_LOGE(TAG, "Second must be between 0 and 59"); + this->second_.reset(); + } +} + +void DateTimeCall::perform() { + this->validate_(); + ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str()); + + if (this->year_.has_value()) { + ESP_LOGD(TAG, " Year: %d", *this->year_); + } + if (this->month_.has_value()) { + ESP_LOGD(TAG, " Month: %d", *this->month_); + } + if (this->day_.has_value()) { + ESP_LOGD(TAG, " Day: %d", *this->day_); + } + if (this->hour_.has_value()) { + ESP_LOGD(TAG, " Hour: %d", *this->hour_); + } + if (this->minute_.has_value()) { + ESP_LOGD(TAG, " Minute: %d", *this->minute_); + } + if (this->second_.has_value()) { + ESP_LOGD(TAG, " Second: %d", *this->second_); + } + this->parent_->control(*this); +} + +DateTimeCall &DateTimeCall::set_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, + uint8_t second) { + this->year_ = year; + this->month_ = month; + this->day_ = day; + this->hour_ = hour; + this->minute_ = minute; + this->second_ = second; + return *this; +}; + +DateTimeCall &DateTimeCall::set_datetime(ESPTime datetime) { + return this->set_datetime(datetime.year, datetime.month, datetime.day_of_month, datetime.hour, datetime.minute, + datetime.second); +}; + +DateTimeCall &DateTimeCall::set_datetime(const std::string &datetime) { + ESPTime val{}; + if (!ESPTime::strptime(datetime, val)) { + ESP_LOGE(TAG, "Could not convert the time string to an ESPTime object"); + return *this; + } + return this->set_datetime(val); +} + +DateTimeCall &DateTimeCall::set_datetime(time_t epoch_seconds) { + ESPTime val = ESPTime::from_epoch_local(epoch_seconds); + return this->set_datetime(val); +} + +DateTimeCall DateTimeEntityRestoreState::to_call(DateTimeEntity *datetime) { + DateTimeCall call = datetime->make_call(); + call.set_datetime(this->year, this->month, this->day, this->hour, this->minute, this->second); + return call; +} + +void DateTimeEntityRestoreState::apply(DateTimeEntity *time) { + time->year_ = this->year; + time->month_ = this->month; + time->day_ = this->day; + time->hour_ = this->hour; + time->minute_ = this->minute; + time->second_ = this->second; + time->publish_state(); +} + +static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider + // there has been a drastic time synchronization + +void OnDateTimeTrigger::loop() { + if (!this->parent_->has_state()) { + return; + } + ESPTime time = this->parent_->rtc_->now(); + if (!time.is_valid()) { + return; + } + if (this->last_check_.has_value()) { + if (*this->last_check_ > time && this->last_check_->timestamp - time.timestamp > MAX_TIMESTAMP_DRIFT) { + // We went back in time (a lot), probably caused by time synchronization + ESP_LOGW(TAG, "Time has jumped back!"); + } else if (*this->last_check_ >= time) { + // already handled this one + return; + } else if (time > *this->last_check_ && time.timestamp - this->last_check_->timestamp > MAX_TIMESTAMP_DRIFT) { + // We went ahead in time (a lot), probably caused by time synchronization + ESP_LOGW(TAG, "Time has jumped ahead!"); + this->last_check_ = time; + return; + } + + while (true) { + this->last_check_->increment_second(); + if (*this->last_check_ >= time) + break; + + if (this->matches_(*this->last_check_)) { + this->trigger(); + break; + } + } + } + + this->last_check_ = time; + if (!time.fields_in_range()) { + ESP_LOGW(TAG, "Time is out of range!"); + ESP_LOGD(TAG, "Second=%02u Minute=%02u Hour=%02u Day=%02u Month=%02u Year=%04u", time.second, time.minute, + time.hour, time.day_of_month, time.month, time.year); + } + + if (this->matches_(time)) + this->trigger(); +} + +bool OnDateTimeTrigger::matches_(const ESPTime &time) const { + return time.is_valid() && time.year == this->parent_->year && time.month == this->parent_->month && + time.day_of_month == this->parent_->day && time.hour == this->parent_->hour && + time.minute == this->parent_->minute && time.second == this->parent_->second; +} + +} // namespace datetime +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/datetime/datetime_entity.h b/esphome/components/datetime/datetime_entity.h new file mode 100644 index 0000000000..d541fa96b1 --- /dev/null +++ b/esphome/components/datetime/datetime_entity.h @@ -0,0 +1,150 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_DATETIME_DATETIME + +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" +#include "esphome/core/time.h" + +#include "datetime_base.h" + +namespace esphome { +namespace datetime { + +#define LOG_DATETIME_DATETIME(prefix, type, obj) \ + if ((obj) != nullptr) { \ + ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ + if (!(obj)->get_icon().empty()) { \ + ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ + } \ + } + +class DateTimeCall; +class DateTimeEntity; + +struct DateTimeEntityRestoreState { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + + DateTimeCall to_call(DateTimeEntity *datetime); + void apply(DateTimeEntity *datetime); +} __attribute__((packed)); + +class DateTimeEntity : public DateTimeBase { + protected: + uint16_t year_; + uint8_t month_; + uint8_t day_; + uint8_t hour_; + uint8_t minute_; + uint8_t second_; + + public: + void publish_state(); + DateTimeCall make_call(); + + ESPTime state_as_esptime() const override; + + const uint16_t &year = year_; + const uint8_t &month = month_; + const uint8_t &day = day_; + const uint8_t &hour = hour_; + const uint8_t &minute = minute_; + const uint8_t &second = second_; + + protected: + friend class DateTimeCall; + friend struct DateTimeEntityRestoreState; + friend class OnDateTimeTrigger; + + virtual void control(const DateTimeCall &call) = 0; +}; + +class DateTimeCall { + public: + explicit DateTimeCall(DateTimeEntity *parent) : parent_(parent) {} + void perform(); + DateTimeCall &set_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); + DateTimeCall &set_datetime(ESPTime datetime); + DateTimeCall &set_datetime(const std::string &datetime); + DateTimeCall &set_datetime(time_t epoch_seconds); + + DateTimeCall &set_year(uint16_t year) { + this->year_ = year; + return *this; + } + DateTimeCall &set_month(uint8_t month) { + this->month_ = month; + return *this; + } + DateTimeCall &set_day(uint8_t day) { + this->day_ = day; + return *this; + } + DateTimeCall &set_hour(uint8_t hour) { + this->hour_ = hour; + return *this; + } + DateTimeCall &set_minute(uint8_t minute) { + this->minute_ = minute; + return *this; + } + DateTimeCall &set_second(uint8_t second) { + this->second_ = second; + return *this; + } + + optional get_year() const { return this->year_; } + optional get_month() const { return this->month_; } + optional get_day() const { return this->day_; } + optional get_hour() const { return this->hour_; } + optional get_minute() const { return this->minute_; } + optional get_second() const { return this->second_; } + + protected: + void validate_(); + + DateTimeEntity *parent_; + + optional year_; + optional month_; + optional day_; + optional hour_; + optional minute_; + optional second_; +}; + +template class DateTimeSetAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(ESPTime, datetime) + + void play(Ts... x) override { + auto call = this->parent_->make_call(); + + if (this->datetime_.has_value()) { + call.set_datetime(this->datetime_.value(x...)); + } + call.perform(); + } +}; + +class OnDateTimeTrigger : public Trigger<>, public Component, public Parented { + public: + void loop() override; + + protected: + bool matches_(const ESPTime &time) const; + + optional last_check_; +}; + +} // namespace datetime +} // namespace esphome + +#endif // USE_DATETIME_DATETIME diff --git a/esphome/components/datetime/time_entity.cpp b/esphome/components/datetime/time_entity.cpp index 98558152d7..ea5e6684d0 100644 --- a/esphome/components/datetime/time_entity.cpp +++ b/esphome/components/datetime/time_entity.cpp @@ -94,8 +94,6 @@ void TimeEntityRestoreState::apply(TimeEntity *time) { time->publish_state(); } -#ifdef USE_TIME - static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider // there has been a drastic time synchronization @@ -103,7 +101,7 @@ void OnTimeTrigger::loop() { if (!this->parent_->has_state()) { return; } - ESPTime time = this->rtc_->now(); + ESPTime time = this->parent_->rtc_->now(); if (!time.is_valid()) { return; } @@ -148,8 +146,6 @@ bool OnTimeTrigger::matches_(const ESPTime &time) const { time.second == this->parent_->second; } -#endif - } // namespace datetime } // namespace esphome diff --git a/esphome/components/datetime/time_entity.h b/esphome/components/datetime/time_entity.h index 956c09e2b4..62e593d28a 100644 --- a/esphome/components/datetime/time_entity.h +++ b/esphome/components/datetime/time_entity.h @@ -10,10 +10,6 @@ #include "datetime_base.h" -#ifdef USE_TIME -#include "esphome/components/time/real_time_clock.h" -#endif - namespace esphome { namespace datetime { @@ -27,6 +23,7 @@ namespace datetime { class TimeCall; class TimeEntity; +class OnTimeTrigger; struct TimeEntityRestoreState { uint8_t hour; @@ -62,6 +59,7 @@ class TimeEntity : public DateTimeBase { protected: friend class TimeCall; friend struct TimeEntityRestoreState; + friend class OnTimeTrigger; virtual void control(const TimeCall &call) = 0; }; @@ -115,22 +113,16 @@ template class TimeSetAction : public Action, public Pare } }; -#ifdef USE_TIME - class OnTimeTrigger : public Trigger<>, public Component, public Parented { public: - explicit OnTimeTrigger(time::RealTimeClock *rtc) : rtc_(rtc) {} void loop() override; protected: bool matches_(const ESPTime &time) const; - time::RealTimeClock *rtc_; optional last_check_; }; -#endif - } // namespace datetime } // namespace esphome diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 7a42140ef6..064362c619 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -115,6 +115,7 @@ MQTTTextSensor = mqtt_ns.class_("MQTTTextSensor", MQTTComponent) MQTTNumberComponent = mqtt_ns.class_("MQTTNumberComponent", MQTTComponent) MQTTDateComponent = mqtt_ns.class_("MQTTDateComponent", MQTTComponent) MQTTTimeComponent = mqtt_ns.class_("MQTTTimeComponent", MQTTComponent) +MQTTDateTimeComponent = mqtt_ns.class_("MQTTDateTimeComponent", MQTTComponent) MQTTTextComponent = mqtt_ns.class_("MQTTTextComponent", MQTTComponent) MQTTSelectComponent = mqtt_ns.class_("MQTTSelectComponent", MQTTComponent) MQTTButtonComponent = mqtt_ns.class_("MQTTButtonComponent", MQTTComponent) diff --git a/esphome/components/mqtt/mqtt_datetime.cpp b/esphome/components/mqtt/mqtt_datetime.cpp new file mode 100644 index 0000000000..4fa44aafb8 --- /dev/null +++ b/esphome/components/mqtt/mqtt_datetime.cpp @@ -0,0 +1,84 @@ +#include "mqtt_datetime.h" + +#include +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_DATETIME_TIME + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.datetime.time"; + +using namespace esphome::datetime; + +MQTTDateTimeComponent::MQTTDateTimeComponent(DateTimeEntity *datetime) : datetime_(datetime) {} + +void MQTTDateTimeComponent::setup() { + this->subscribe_json(this->get_command_topic_(), [this](const std::string &topic, JsonObject root) { + auto call = this->datetime_->make_call(); + if (root.containsKey("year")) { + call.set_year(root["year"]); + } + if (root.containsKey("month")) { + call.set_month(root["month"]); + } + if (root.containsKey("day")) { + call.set_day(root["day"]); + } + if (root.containsKey("hour")) { + call.set_hour(root["hour"]); + } + if (root.containsKey("minute")) { + call.set_minute(root["minute"]); + } + if (root.containsKey("second")) { + call.set_second(root["second"]); + } + call.perform(); + }); + this->datetime_->add_on_state_callback([this]() { + this->publish_state(this->datetime_->year, this->datetime_->month, this->datetime_->day, this->datetime_->hour, + this->datetime_->minute, this->datetime_->second); + }); +} + +void MQTTDateTimeComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT DateTime '%s':", this->datetime_->get_name().c_str()); + LOG_MQTT_COMPONENT(true, true) +} + +std::string MQTTDateTimeComponent::component_type() const { return "datetime"; } +const EntityBase *MQTTDateTimeComponent::get_entity() const { return this->datetime_; } + +void MQTTDateTimeComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + // Nothing extra to add here +} +bool MQTTDateTimeComponent::send_initial_state() { + if (this->datetime_->has_state()) { + return this->publish_state(this->datetime_->year, this->datetime_->month, this->datetime_->day, + this->datetime_->hour, this->datetime_->minute, this->datetime_->second); + } else { + return true; + } +} +bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, + uint8_t second) { + return this->publish_json(this->get_state_topic_(), [year, month, day, hour, minute, second](JsonObject root) { + root["year"] = year; + root["month"] = month; + root["day"] = day; + root["hour"] = hour; + root["minute"] = minute; + root["second"] = second; + }); +} + +} // namespace mqtt +} // namespace esphome + +#endif // USE_DATETIME_TIME +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_datetime.h b/esphome/components/mqtt/mqtt_datetime.h new file mode 100644 index 0000000000..f0d68ad2e1 --- /dev/null +++ b/esphome/components/mqtt/mqtt_datetime.h @@ -0,0 +1,45 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_MQTT +#ifdef USE_DATETIME_TIME + +#include "esphome/components/datetime/datetime_entity.h" +#include "mqtt_component.h" + +namespace esphome { +namespace mqtt { + +class MQTTDateTimeComponent : public mqtt::MQTTComponent { + public: + /** Construct this MQTTDateTimeComponent instance with the provided friendly_name and time + * + * @param time The time entity. + */ + explicit MQTTDateTimeComponent(datetime::DateTimeEntity *time); + + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + /// Override setup. + void setup() override; + void dump_config() override; + + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + bool send_initial_state() override; + + bool publish_state(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); + + protected: + std::string component_type() const override; + const EntityBase *get_entity() const override; + + datetime::DateTimeEntity *datetime_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif // USE_DATETIME_DATE +#endif // USE_MQTT diff --git a/esphome/components/template/datetime/__init__.py b/esphome/components/template/datetime/__init__.py index 53d9d1b9d3..bf7154ef76 100644 --- a/esphome/components/template/datetime/__init__.py +++ b/esphome/components/template/datetime/__init__.py @@ -31,6 +31,10 @@ TemplateTime = template_ns.class_( "TemplateTime", datetime.TimeEntity, cg.PollingComponent ) +TemplateDateTime = template_ns.class_( + "TemplateDateTime", datetime.DateTimeEntity, cg.PollingComponent +) + def validate(config): config = config.copy() @@ -78,6 +82,13 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_VALUE): cv.date_time(allowed_date=False), } ), + "DATETIME": datetime.datetime_schema(TemplateDateTime) + .extend(_BASE_SCHEMA) + .extend( + { + cv.Optional(CONF_INITIAL_VALUE): cv.date_time(), + } + ), }, upper=True, ), @@ -116,6 +127,17 @@ async def to_code(config): ("hour", initial_value[CONF_HOUR]), ) cg.add(var.set_initial_value(time_struct)) + elif config[CONF_TYPE] == "DATETIME": + datetime_struct = cg.StructInitializer( + cg.ESPTime, + ("second", initial_value[CONF_SECOND]), + ("minute", initial_value[CONF_MINUTE]), + ("hour", initial_value[CONF_HOUR]), + ("day_of_month", initial_value[CONF_DAY]), + ("month", initial_value[CONF_MONTH]), + ("year", initial_value[CONF_YEAR]), + ) + cg.add(var.set_initial_value(datetime_struct)) if CONF_SET_ACTION in config: await automation.build_automation( diff --git a/esphome/components/template/datetime/template_datetime.cpp b/esphome/components/template/datetime/template_datetime.cpp new file mode 100644 index 0000000000..3ab74e197f --- /dev/null +++ b/esphome/components/template/datetime/template_datetime.cpp @@ -0,0 +1,150 @@ +#include "template_datetime.h" + +#ifdef USE_DATETIME_DATETIME + +#include "esphome/core/log.h" + +namespace esphome { +namespace template_ { + +static const char *const TAG = "template.datetime"; + +void TemplateDateTime::setup() { + if (this->f_.has_value()) + return; + + ESPTime state{}; + + if (!this->restore_value_) { + state = this->initial_value_; + } else { + datetime::DateTimeEntityRestoreState temp; + this->pref_ = global_preferences->make_preference(194434090U ^ + this->get_object_id_hash()); + if (this->pref_.load(&temp)) { + temp.apply(this); + return; + } else { + // set to inital value if loading from pref failed + state = this->initial_value_; + } + } + + this->year_ = state.year; + this->month_ = state.month; + this->day_ = state.day_of_month; + this->hour_ = state.hour; + this->minute_ = state.minute; + this->second_ = state.second; + this->publish_state(); +} + +void TemplateDateTime::update() { + if (!this->f_.has_value()) + return; + + auto val = (*this->f_)(); + if (!val.has_value()) + return; + + this->year_ = val->year; + this->month_ = val->month; + this->day_ = val->day_of_month; + this->hour_ = val->hour; + this->minute_ = val->minute; + this->second_ = val->second; + this->publish_state(); +} + +void TemplateDateTime::control(const datetime::DateTimeCall &call) { + bool has_year = call.get_year().has_value(); + bool has_month = call.get_month().has_value(); + bool has_day = call.get_day().has_value(); + bool has_hour = call.get_hour().has_value(); + bool has_minute = call.get_minute().has_value(); + bool has_second = call.get_second().has_value(); + + ESPTime value = {}; + if (has_year) + value.year = *call.get_year(); + + if (has_month) + value.month = *call.get_month(); + + if (has_day) + value.day_of_month = *call.get_day(); + + if (has_hour) + value.hour = *call.get_hour(); + + if (has_minute) + value.minute = *call.get_minute(); + + if (has_second) + value.second = *call.get_second(); + + this->set_trigger_->trigger(value); + + if (this->optimistic_) { + if (has_year) + this->year_ = *call.get_year(); + if (has_month) + this->month_ = *call.get_month(); + if (has_day) + this->day_ = *call.get_day(); + if (has_hour) + this->hour_ = *call.get_hour(); + if (has_minute) + this->minute_ = *call.get_minute(); + if (has_second) + this->second_ = *call.get_second(); + this->publish_state(); + } + + if (this->restore_value_) { + datetime::DateTimeEntityRestoreState temp = {}; + if (has_year) { + temp.year = *call.get_year(); + } else { + temp.year = this->year_; + } + if (has_month) { + temp.month = *call.get_month(); + } else { + temp.month = this->month_; + } + if (has_day) { + temp.day = *call.get_day(); + } else { + temp.day = this->day_; + } + if (has_hour) { + temp.hour = *call.get_hour(); + } else { + temp.hour = this->hour_; + } + if (has_minute) { + temp.minute = *call.get_minute(); + } else { + temp.minute = this->minute_; + } + if (has_second) { + temp.second = *call.get_second(); + } else { + temp.second = this->second_; + } + + this->pref_.save(&temp); + } +} + +void TemplateDateTime::dump_config() { + LOG_DATETIME_DATETIME("", "Template DateTime", this); + ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); + LOG_UPDATE_INTERVAL(this); +} + +} // namespace template_ +} // namespace esphome + +#endif // USE_DATETIME_DATETIME diff --git a/esphome/components/template/datetime/template_datetime.h b/esphome/components/template/datetime/template_datetime.h new file mode 100644 index 0000000000..cb1fd01132 --- /dev/null +++ b/esphome/components/template/datetime/template_datetime.h @@ -0,0 +1,46 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_DATETIME_TIME + +#include "esphome/components/datetime/datetime_entity.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" +#include "esphome/core/time.h" + +namespace esphome { +namespace template_ { + +class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponent { + public: + void set_template(std::function()> &&f) { this->f_ = f; } + + void setup() override; + void update() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + Trigger *get_set_trigger() const { return this->set_trigger_; } + void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } + + void set_initial_value(ESPTime initial_value) { this->initial_value_ = initial_value; } + void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } + + protected: + void control(const datetime::DateTimeCall &call) override; + + bool optimistic_{false}; + ESPTime initial_value_{}; + bool restore_value_{false}; + Trigger *set_trigger_ = new Trigger(); + optional()>> f_; + + ESPPreferenceObject pref_; +}; + +} // namespace template_ +} // namespace esphome + +#endif // USE_DATETIME_TIME diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 9b903d098b..2b9a95c6bd 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -13,6 +13,8 @@ #endif #include +#include + namespace esphome { namespace time { diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 8d08783c8c..42af72e872 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -129,6 +129,15 @@ bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { } #endif +#ifdef USE_DATETIME_DATETIME +bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) { + if (this->web_server_->events_.count() == 0) + return true; + this->web_server_->events_.send(this->web_server_->datetime_json(datetime, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + #ifdef USE_TEXT bool ListEntitiesIterator::on_text(text::Text *text) { if (this->web_server_->events_.count() == 0) diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index af84cb1d2b..47d427d9b5 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -47,6 +47,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_DATETIME_TIME bool on_time(datetime::TimeEntity *time) override; #endif +#ifdef USE_DATETIME_DATETIME + bool on_datetime(datetime::DateTimeEntity *datetime) override; +#endif #ifdef USE_TEXT bool on_text(text::Text *text) override; #endif diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 0202038ffc..6a7b4121f0 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -926,6 +926,8 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con #ifdef USE_DATETIME_TIME void WebServer::on_time_update(datetime::TimeEntity *obj) { + if (this->events_.count() == 0) + return; this->events_.send(this->time_json(obj, DETAIL_STATE).c_str(), "state"); } void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match) { @@ -970,6 +972,55 @@ std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_con } #endif // USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME +void WebServer::on_datetime_update(datetime::DateTimeEntity *obj) { + if (this->events_.count() == 0) + return; + this->events_.send(this->datetime_json(obj, DETAIL_STATE).c_str(), "state"); +} +void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (auto *obj : App.get_datetimes()) { + if (obj->get_object_id() != match.id) + continue; + if (request->method() == HTTP_GET && match.method.empty()) { + std::string data = this->datetime_json(obj, DETAIL_STATE); + request->send(200, "application/json", data.c_str()); + return; + } + if (match.method != "set") { + request->send(404); + return; + } + + auto call = obj->make_call(); + + if (!request->hasParam("value")) { + request->send(409); + return; + } + + if (request->hasParam("value")) { + std::string value = request->getParam("value")->value().c_str(); + call.set_datetime(value); + } + + this->schedule_([call]() mutable { call.perform(); }); + request->send(200); + return; + } + request->send(404); +} +std::string WebServer::datetime_json(datetime::DateTimeEntity *obj, JsonDetail start_config) { + return json::build_json([obj, start_config](JsonObject root) { + set_json_id(root, obj, "datetime-" + obj->get_object_id(), start_config); + std::string value = str_sprintf("%d-%02d-%02d %02d:%02d:%02d", obj->year, obj->month, obj->day, obj->hour, + obj->minute, obj->second); + root["value"] = value; + root["state"] = value; + }); +} +#endif // USE_DATETIME_DATETIME + #ifdef USE_TEXT void WebServer::on_text_update(text::Text *obj, const std::string &state) { if (this->events_.count() == 0) @@ -1458,6 +1509,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_DATETIME_DATETIME + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "datetime") + return true; +#endif + #ifdef USE_TEXT if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "text") return true; @@ -1595,6 +1651,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { } #endif +#ifdef USE_DATETIME_DATETIME + if (match.domain == "datetime") { + this->handle_datetime_request(request, match); + return; + } +#endif + #ifdef USE_TEXT if (match.domain == "text") { this->handle_text_request(request, match); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 5e8f3f8236..dda14a7e05 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -239,6 +239,15 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string time_json(datetime::TimeEntity *obj, JsonDetail start_config); #endif +#ifdef USE_DATETIME_DATETIME + void on_datetime_update(datetime::DateTimeEntity *obj) override; + /// Handle a datetime request under '/datetime/'. + void handle_datetime_request(AsyncWebServerRequest *request, const UrlMatch &match); + + /// Dump the datetime state with its value as a JSON string. + std::string datetime_json(datetime::DateTimeEntity *obj, JsonDetail start_config); +#endif + #ifdef USE_TEXT void on_text_update(text::Text *obj, const std::string &state) override; /// Handle a text input request under '/text/'. diff --git a/esphome/const.py b/esphome/const.py index a64bc73f59..324b32e847 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -179,6 +179,7 @@ CONF_DATA_PINS = "data_pins" CONF_DATA_RATE = "data_rate" CONF_DATA_TEMPLATE = "data_template" CONF_DATE = "date" +CONF_DATETIME = "datetime" CONF_DAY = "day" CONF_DAYS_OF_MONTH = "days_of_month" CONF_DAYS_OF_WEEK = "days_of_week" diff --git a/esphome/core/application.h b/esphome/core/application.h index 35df350ec3..7487780412 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -45,6 +45,9 @@ #ifdef USE_DATETIME_TIME #include "esphome/components/datetime/time_entity.h" #endif +#ifdef USE_DATETIME_DATETIME +#include "esphome/components/datetime/datetime_entity.h" +#endif #ifdef USE_TEXT #include "esphome/components/text/text.h" #endif @@ -141,6 +144,10 @@ class Application { void register_time(datetime::TimeEntity *time) { this->times_.push_back(time); } #endif +#ifdef USE_DATETIME_DATETIME + void register_datetime(datetime::DateTimeEntity *datetime) { this->datetimes_.push_back(datetime); } +#endif + #ifdef USE_TEXT void register_text(text::Text *text) { this->texts_.push_back(text); } #endif @@ -335,6 +342,15 @@ class Application { return nullptr; } #endif +#ifdef USE_DATETIME_DATETIME + const std::vector &get_datetimes() { return this->datetimes_; } + datetime::DateTimeEntity *get_datetime_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->datetimes_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif #ifdef USE_TEXT const std::vector &get_texts() { return this->texts_; } text::Text *get_text_by_key(uint32_t key, bool include_internal = false) { @@ -456,6 +472,9 @@ class Application { #ifdef USE_DATETIME_TIME std::vector times_{}; #endif +#ifdef USE_DATETIME_DATETIME + std::vector datetimes_{}; +#endif #ifdef USE_SELECT std::vector selects_{}; #endif diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index 687f1f6e23..9b02bf527b 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -232,6 +232,21 @@ void ComponentIterator::advance() { } break; #endif +#ifdef USE_DATETIME_DATETIME + case IteratorState::DATETIME_DATETIME: + if (this->at_ >= App.get_datetimes().size()) { + advance_platform = true; + } else { + auto *datetime = App.get_datetimes()[this->at_]; + if (datetime->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_datetime(datetime); + } + } + break; +#endif #ifdef USE_TEXT case IteratorState::TEXT: if (this->at_ >= App.get_texts().size()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index 8f0398cbb3..2b847bc088 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -63,6 +63,9 @@ class ComponentIterator { #ifdef USE_DATETIME_TIME virtual bool on_time(datetime::TimeEntity *time) = 0; #endif +#ifdef USE_DATETIME_DATETIME + virtual bool on_datetime(datetime::DateTimeEntity *datetime) = 0; +#endif #ifdef USE_TEXT virtual bool on_text(text::Text *text) = 0; #endif @@ -132,6 +135,9 @@ class ComponentIterator { #ifdef USE_DATETIME_TIME DATETIME_TIME, #endif +#ifdef USE_DATETIME_DATETIME + DATETIME_DATETIME, +#endif #ifdef USE_TEXT TEXT, #endif diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index eb975eaf6f..0957329500 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -71,6 +71,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_state_callback([this, obj]() { this->on_time_update(obj); }); } #endif +#ifdef USE_DATETIME_DATETIME + for (auto *obj : App.get_datetimes()) { + if (include_internal || !obj->is_internal()) + obj->add_on_state_callback([this, obj]() { this->on_datetime_update(obj); }); + } +#endif #ifdef USE_TEXT for (auto *obj : App.get_texts()) { if (include_internal || !obj->is_internal()) diff --git a/esphome/core/controller.h b/esphome/core/controller.h index da9dbc00a6..e1bf93193a 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -37,6 +37,9 @@ #ifdef USE_DATETIME_TIME #include "esphome/components/datetime/time_entity.h" #endif +#ifdef USE_DATETIME_DATETIME +#include "esphome/components/datetime/datetime_entity.h" +#endif #ifdef USE_TEXT #include "esphome/components/text/text.h" #endif @@ -97,6 +100,9 @@ class Controller { #ifdef USE_DATETIME_TIME virtual void on_time_update(datetime::TimeEntity *obj){}; #endif +#ifdef USE_DATETIME_DATETIME + virtual void on_datetime_update(datetime::DateTimeEntity *obj){}; +#endif #ifdef USE_TEXT virtual void on_text_update(text::Text *obj, const std::string &state){}; #endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index fed73098d2..619a956071 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -39,6 +39,7 @@ #define USE_DATETIME #define USE_DATETIME_DATE #define USE_DATETIME_TIME +#define USE_DATETIME_DATETIME #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index 0004fc7e8e..add671701f 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -178,6 +178,15 @@ void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { this->timestamp = res; } +void ESPTime::recalc_timestamp_local(bool use_day_of_year) { + this->recalc_timestamp_utc(use_day_of_year); + this->timestamp -= ESPTime::timezone_offset(); + ESPTime temp = ESPTime::from_epoch_local(this->timestamp); + if (temp.is_dst) { + this->timestamp -= 3600; + } +} + int32_t ESPTime::timezone_offset() { int32_t offset = 0; time_t now = ::time(nullptr); diff --git a/esphome/core/time.h b/esphome/core/time.h index 4300cf26b7..bce1108d93 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -99,6 +99,9 @@ struct ESPTime { /// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC). void recalc_timestamp_utc(bool use_day_of_year = true); + /// Recalculate the timestamp field from the other fields of this ESPTime instance assuming local fields. + void recalc_timestamp_local(bool use_day_of_year = true); + /// Convert this ESPTime instance back to a tm struct. struct tm to_c_tm(); diff --git a/script/ci-custom.py b/script/ci-custom.py index 27fcd480f5..abe004dba3 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -623,6 +623,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/cover/cover.h", "esphome/components/datetime/date_entity.h", "esphome/components/datetime/time_entity.h", + "esphome/components/datetime/datetime_entity.h", "esphome/components/display/display.h", "esphome/components/event/event.h", "esphome/components/fan/fan.h", diff --git a/tests/components/datetime/test.all.yaml b/tests/components/datetime/test.all.yaml index 3f5996bb8b..4e26b68121 100644 --- a/tests/components/datetime/test.all.yaml +++ b/tests/components/datetime/test.all.yaml @@ -1 +1,3 @@ datetime: + +time: diff --git a/tests/components/template/test.all.yaml b/tests/components/template/common.yaml similarity index 88% rename from tests/components/template/test.all.yaml rename to tests/components/template/common.yaml index 64faec36c2..ba7167157b 100644 --- a/tests/components/template/test.all.yaml +++ b/tests/components/template/common.yaml @@ -183,3 +183,25 @@ datetime: - x.hour - x.minute - x.second + - platform: template + name: DateTime + id: test_datetime + type: datetime + set_action: + - logger.log: "set_value" + on_value: + - logger.log: + format: "DateTime: %04d-%02d-%02d %02d:%02d:%02d" + args: + - x.year + - x.month + - x.day_of_month + - x.hour + - x.minute + - x.second + +time: + - platform: sntp # Required for datetime + +wifi: # Required for sntp time + ap: diff --git a/tests/components/template/test.bk72xx.yaml b/tests/components/template/test.bk72xx.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.bk72xx.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp32-c3-idf.yaml b/tests/components/template/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp32-c3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp32-c3.yaml b/tests/components/template/test.esp32-c3.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp32-c3.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp32-idf.yaml b/tests/components/template/test.esp32-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp32-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp32-s3-idf.yaml b/tests/components/template/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp32-s3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp32.yaml b/tests/components/template/test.esp32.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp32.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.esp8266.yaml b/tests/components/template/test.esp8266.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.esp8266.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/template/test.rp2040.yaml b/tests/components/template/test.rp2040.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/template/test.rp2040.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml From 8fcfcccbc3f3bb5edb4706a6c4b55a677a5dda99 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 25 Apr 2024 23:20:21 +0200 Subject: [PATCH 1633/2607] Multiple Daly-BMS support (#6615) --- esphome/components/daly_bms/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/daly_bms/__init__.py b/esphome/components/daly_bms/__init__.py index 2cc2c512f3..669d40a68d 100644 --- a/esphome/components/daly_bms/__init__.py +++ b/esphome/components/daly_bms/__init__.py @@ -4,6 +4,7 @@ from esphome.components import uart from esphome.const import CONF_ID, CONF_ADDRESS CODEOWNERS = ["@s1lvi0"] +MULTI_CONF = True DEPENDENCIES = ["uart"] CONF_BMS_DALY_ID = "bms_daly_id" From 3997503071bae2f208f761f668036f3cc8e62452 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 25 Apr 2024 18:03:24 -0500 Subject: [PATCH 1634/2607] Remove text_sensor from sync-device-class job (#6637) --- script/sync-device_class.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/sync-device_class.py b/script/sync-device_class.py index 26d271535f..12e1bb6a9f 100755 --- a/script/sync-device_class.py +++ b/script/sync-device_class.py @@ -10,7 +10,6 @@ from homeassistant.components.event import EventDeviceClass from homeassistant.components.number import NumberDeviceClass from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.switch import SwitchDeviceClass -from homeassistant.components.text_sensor import TextSensorDeviceClass from homeassistant.components.valve import ValveDeviceClass # pylint: enable=import-error @@ -28,7 +27,6 @@ DOMAINS = { "number": NumberDeviceClass, "sensor": SensorDeviceClass, "switch": SwitchDeviceClass, - "text_sensor": TextSensorDeviceClass, "valve": ValveDeviceClass, } From 3ecb5fa57f71c199ffd18c017ea3ebda6e05da58 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Fri, 26 Apr 2024 11:40:19 +1200 Subject: [PATCH 1635/2607] Synchronise Device Classes from Home Assistant (#6638) --- esphome/components/event/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py index 789f121cf3..241e884386 100644 --- a/esphome/components/event/__init__.py +++ b/esphome/components/event/__init__.py @@ -25,8 +25,8 @@ IS_PLATFORM_COMPONENT = True DEVICE_CLASSES = [ DEVICE_CLASS_BUTTON, - DEVICE_CLASS_EMPTY, DEVICE_CLASS_DOORBELL, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_MOTION, ] From 031e26ad989fae720aae645bab9b6480336ac3e2 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Fri, 26 Apr 2024 05:23:28 +0200 Subject: [PATCH 1636/2607] Display: add diagnostic test_card option (#6608) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/display/__init__.py | 4 ++ esphome/components/display/display.cpp | 64 ++++++++++++++++++++++++-- esphome/components/display/display.h | 4 ++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index 992799008a..c4bb12b75d 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -38,6 +38,7 @@ DisplayOnPageChangeTrigger = display_ns.class_( ) CONF_ON_PAGE_CHANGE = "on_page_change" +CONF_SHOW_TEST_CARD = "show_test_card" DISPLAY_ROTATIONS = { 0: display_ns.DISPLAY_ROTATION_0_DEGREES, @@ -82,6 +83,7 @@ FULL_DISPLAY_SCHEMA = BASIC_DISPLAY_SCHEMA.extend( } ), cv.Optional(CONF_AUTO_CLEAR_ENABLED, default=True): cv.boolean, + cv.Optional(CONF_SHOW_TEST_CARD): cv.boolean, } ) @@ -113,6 +115,8 @@ async def setup_display_core_(var, config): await automation.build_automation( trigger, [(DisplayPagePtr, "from"), (DisplayPagePtr, "to")], conf ) + if config.get(CONF_SHOW_TEST_CARD): + cg.add(var.show_test_card()) async def register_display(var, config): diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 010e6eca0b..75205292f7 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -1,7 +1,7 @@ #include "display.h" - +#include "display_color_utils.h" #include - +#include "esphome/core/hal.h" #include "esphome/core/log.h" namespace esphome { @@ -507,7 +507,9 @@ void Display::do_update_() { if (this->auto_clear_enabled_) { this->clear(); } - if (this->page_ != nullptr) { + if (this->show_test_card_) { + this->test_card(); + } else if (this->page_ != nullptr) { this->page_->get_writer()(*this); } else if (this->writer_.has_value()) { (*this->writer_)(*this); @@ -608,6 +610,62 @@ bool Display::clamp_y_(int y, int h, int &min_y, int &max_y) { return min_y < max_y; } +const uint8_t TESTCARD_FONT[3][8] PROGMEM = {{0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00}, // 'R' + {0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00}, // 'G' + {0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00}}; // 'B' + +void Display::test_card() { + int w = get_width(), h = get_height(), image_w, image_h; + this->clear(); + this->show_test_card_ = false; + if (this->get_display_type() == DISPLAY_TYPE_COLOR) { + Color r(255, 0, 0), g(0, 255, 0), b(0, 0, 255); + image_w = std::min(w - 20, 310); + image_h = std::min(h - 20, 255); + + int shift_x = (w - image_w) / 2; + int shift_y = (h - image_h) / 2; + int line_w = (image_w - 6) / 6; + int image_c = image_w / 2; + for (auto i = 0; i <= image_h; i++) { + int c = esp_scale(i, image_h); + this->horizontal_line(shift_x + 0, shift_y + i, line_w, r.fade_to_white(c)); + this->horizontal_line(shift_x + line_w, shift_y + i, line_w, r.fade_to_black(c)); // + + this->horizontal_line(shift_x + image_c - line_w, shift_y + i, line_w, g.fade_to_white(c)); + this->horizontal_line(shift_x + image_c, shift_y + i, line_w, g.fade_to_black(c)); + + this->horizontal_line(shift_x + image_w - (line_w * 2), shift_y + i, line_w, b.fade_to_white(c)); + this->horizontal_line(shift_x + image_w - line_w, shift_y + i, line_w, b.fade_to_black(c)); + } + this->rectangle(shift_x, shift_y, image_w, image_h, Color(127, 127, 0)); + + uint16_t shift_r = shift_x + line_w - (8 * 3); + uint16_t shift_g = shift_x + image_c - (8 * 3); + uint16_t shift_b = shift_x + image_w - line_w - (8 * 3); + shift_y = h / 2 - (8 * 3); + for (auto i = 0; i < 8; i++) { + uint8_t ftr = progmem_read_byte(&TESTCARD_FONT[0][i]); + uint8_t ftg = progmem_read_byte(&TESTCARD_FONT[1][i]); + uint8_t ftb = progmem_read_byte(&TESTCARD_FONT[2][i]); + for (auto k = 0; k < 8; k++) { + if ((ftr & (1 << k)) != 0) { + this->filled_rectangle(shift_r + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF); + } + if ((ftg & (1 << k)) != 0) { + this->filled_rectangle(shift_g + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF); + } + if ((ftb & (1 << k)) != 0) { + this->filled_rectangle(shift_b + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF); + } + } + } + } + this->rectangle(0, 0, w, h, Color(127, 0, 127)); + this->filled_rectangle(0, 0, 10, 10, Color(255, 0, 255)); + this->stop_poller(); +} + DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {} void DisplayPage::show() { this->parent_->show_page(this); } void DisplayPage::show_next() { this->next_->show(); } diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index a30ba976b4..4ee7ef93cb 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -631,6 +631,9 @@ class Display : public PollingComponent { */ bool clip(int x, int y); + void test_card(); + void show_test_card() { this->show_test_card_ = true; } + protected: bool clamp_x_(int x, int w, int &min_x, int &max_x); bool clamp_y_(int y, int h, int &min_y, int &max_y); @@ -659,6 +662,7 @@ class Display : public PollingComponent { std::vector on_page_change_triggers_; bool auto_clear_enabled_{true}; std::vector clipping_rectangle_; + bool show_test_card_{false}; }; class DisplayPage { From cd91c7050c00dc8d7051f7870715dc4d8abdd537 Mon Sep 17 00:00:00 2001 From: polyfloyd Date: Fri, 26 Apr 2024 10:44:58 +0200 Subject: [PATCH 1637/2607] waveshare_epaper: Add 2.90in-dke (#6492) Co-authored-by: The_Niz --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.cpp | 125 ++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 24 ++++ .../waveshare_epaper/test.esp32.yaml | 18 +++ 4 files changed, 171 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index dc43cbf5a7..bba60efc0a 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -49,6 +49,9 @@ WaveshareEPaper2P9InV2R2 = waveshare_epaper_ns.class_( "WaveshareEPaper2P9InV2R2", WaveshareEPaper ) GDEY029T94 = waveshare_epaper_ns.class_("GDEY029T94", WaveshareEPaper) +WaveshareEPaper2P9InDKE = waveshare_epaper_ns.class_( + "WaveshareEPaper2P9InDKE", WaveshareEPaper +) WaveshareEPaper4P2In = waveshare_epaper_ns.class_( "WaveshareEPaper4P2In", WaveshareEPaper ) @@ -115,6 +118,7 @@ MODELS = { "2.90in-b": ("b", WaveshareEPaper2P9InB), "2.90in-bv3": ("b", WaveshareEPaper2P9InBV3), "2.90inv2-r2": ("c", WaveshareEPaper2P9InV2R2), + "2.90in-dke": ("c", WaveshareEPaper2P9InDKE), "4.20in": ("b", WaveshareEPaper4P2In), "4.20in-bv2": ("b", WaveshareEPaper4P2InBV2), "5.83in": ("b", WaveshareEPaper5P8In), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index cf43c4cc32..7224aa44ed 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1127,6 +1127,131 @@ void WaveshareEPaper2P9InB::dump_config() { LOG_UPDATE_INTERVAL(this); } +// DKE 2.9 +// https://www.badge.team/docs/badges/sha2017/hardware/#e-ink-display-the-dke-group-depg0290b1 +// https://www.badge.team/docs/badges/sha2017/hardware/DEPG0290B01V3.0.pdf +static const uint8_t LUT_SIZE_DKE = 70; +static const uint8_t UPDATE_LUT_DKE[LUT_SIZE_DKE] = { + 0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0xA0, 0x90, 0x50, 0x0, + 0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0xF, + 0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0x0, 0x0, 0x02, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; +static const uint8_t PART_UPDATE_LUT_DKE[LUT_SIZE_DKE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x08, 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, 0x00}; +static const uint8_t FULL_UPDATE_LUT_DKE[LUT_SIZE_DKE] = { + 0x90, 0x50, 0xa0, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x90, 0x50, 0xa0, 0x50, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x04, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, + 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +void WaveshareEPaper2P9InDKE::initialize() { + // Hardware reset + delay(10); + this->reset_pin_->digital_write(false); + delayMicroseconds(200); + this->reset_pin_->digital_write(true); + delayMicroseconds(200); + // Wait for busy low + this->wait_until_idle_(); + // Software reset + this->command(0x12); + // Wait for busy low + this->wait_until_idle_(); + // Set Analog Block Control + this->command(0x74); + this->data(0x54); + // Set Digital Block Control + this->command(0x7E); + this->data(0x3B); + // Set display size and driver output control + this->command(0x01); + // this->data(0x27); + // this->data(0x01); + // this->data(0x00); + this->data(this->get_height_internal() - 1); + this->data((this->get_height_internal() - 1) >> 8); + this->data(0x00); // ? GD = 0, SM = 0, TB = 0 + // Ram data entry mode + this->command(0x11); + this->data(0x03); + // Set Ram X address + this->command(0x44); + this->data(0x00); + this->data(0x0F); + // Set Ram Y address + this->command(0x45); + this->data(0x00); + this->data(0x00); + this->data(0x27); + this->data(0x01); + // Set border + this->command(0x3C); + // this->data(0x80); + this->data(0x01); + // Set VCOM value + this->command(0x2C); + this->data(0x26); + // Gate voltage setting + this->command(0x03); + this->data(0x17); + // Source voltage setting + this->command(0x04); + this->data(0x41); + this->data(0x00); + this->data(0x32); + // Frame setting 50hz + this->command(0x3A); + this->data(0x30); + this->command(0x3B); + this->data(0x0A); + // Load LUT + this->command(0x32); + for (uint8_t v : FULL_UPDATE_LUT_DKE) + this->data(v); +} + +void HOT WaveshareEPaper2P9InDKE::display() { + ESP_LOGI(TAG, "Performing e-paper update."); + // Set Ram X address counter + this->command(0x4e); + this->data(0); + // Set Ram Y address counter + this->command(0x4f); + this->data(0); + this->data(0); + // Load image (128/8*296) + this->command(0x24); + this->start_data_(); + this->write_array(this->buffer_, this->get_buffer_length_()); + this->end_data_(); + // Image update + this->command(0x22); + this->data(0xC7); + this->command(0x20); + // Wait for busy low + this->wait_until_idle_(); + // Enter deep sleep mode + this->command(0x10); + this->data(0x01); +} +int WaveshareEPaper2P9InDKE::get_width_internal() { return 128; } +int WaveshareEPaper2P9InDKE::get_height_internal() { return 296; } +void WaveshareEPaper2P9InDKE::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper", this); + ESP_LOGCONFIG(TAG, " Model: 2.9in DKE"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} +void WaveshareEPaper2P9InDKE::set_full_update_every(uint32_t full_update_every) { + this->full_update_every_ = full_update_every; +} + // ======================================================== // 2.90in Type B (LUT from OTP) // Datasheet: diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index ffc099ca56..3c4470c30c 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -373,6 +373,30 @@ class WaveshareEPaper2P9InV2R2 : public WaveshareEPaper { void reset_(); }; +class WaveshareEPaper2P9InDKE : public WaveshareEPaper { + public: + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + // COMMAND DEEP SLEEP + this->command(0x10); + this->data(0x01); + } + + void set_full_update_every(uint32_t full_update_every); + + protected: + uint32_t full_update_every_{30}; + uint32_t at_update_{0}; + int get_width_internal() override; + + int get_height_internal() override; +}; + class WaveshareEPaper4P2In : public WaveshareEPaper { public: void initialize() override; diff --git a/tests/components/waveshare_epaper/test.esp32.yaml b/tests/components/waveshare_epaper/test.esp32.yaml index cc6c665e7d..2f06c5c51b 100644 --- a/tests/components/waveshare_epaper/test.esp32.yaml +++ b/tests/components/waveshare_epaper/test.esp32.yaml @@ -83,6 +83,24 @@ display: full_update_every: 30 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + model: 2.90in-dke + spi_id: spi_id_1 + cs_pin: + allow_other_uses: true + number: GPIO25 + dc_pin: + allow_other_uses: true + number: GPIO26 + busy_pin: + allow_other_uses: true + number: GPIO27 + reset_pin: + allow_other_uses: true + number: GPIO32 + full_update_every: 1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: waveshare_epaper model: 2.70in-b spi_id: spi_id_1 From 9bfb36f58bcdaff1d5b62a2ea303d45a10af291e Mon Sep 17 00:00:00 2001 From: Alex Boyd Date: Fri, 26 Apr 2024 05:41:43 -0600 Subject: [PATCH 1638/2607] Extract core comments from #6241 (#6643) --- esphome/automation.py | 10 ++++++++++ esphome/config_validation.py | 2 +- esphome/core/component.h | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/esphome/automation.py b/esphome/automation.py index 8475858a9c..b25ffa5abe 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -18,10 +18,20 @@ from esphome.util import Registry def maybe_simple_id(*validators): + """Allow a raw ID to be specified in place of a config block. + If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's + wrapped in a dict that looks like ``{"id": }``, and that dict is then handed off to the specified validators. + """ return maybe_conf(CONF_ID, *validators) def maybe_conf(conf, *validators): + """Allow a raw value to be specified in place of a config block. + If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's + wrapped in a dict that looks like ``{: }``, and that dict is then handed off to the specified + validators. + (This is a general case of ``maybe_simple_id`` that allows the wrapping key to be something other than ``id``.) + """ validator = cv.All(*validators) @schema_extractor("maybe") diff --git a/esphome/config_validation.py b/esphome/config_validation.py index bc58979f33..198b44f38d 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -304,7 +304,7 @@ def string(value): """Validate that a configuration value is a string. If not, automatically converts to a string. Note that this can be lossy, for example the input value 60.00 (float) will be turned into - "60.0" (string). For values where this could be a problem `string_string` has to be used. + "60.0" (string). For values where this could be a problem `string_strict` has to be used. """ check_not_templatable(value) if isinstance(value, (dict, list)): diff --git a/esphome/core/component.h b/esphome/core/component.h index 4f244e5fcb..e6ffe96d1e 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -85,7 +85,7 @@ class Component { /** priority of setup(). higher -> executed earlier * - * Defaults to 0. + * Defaults to setup_priority::DATA, i.e. 600. * * @return The setup priority of this component */ From 76c55992aeee8fb416417efa0a9a33a1b5e27b25 Mon Sep 17 00:00:00 2001 From: tronikos Date: Sat, 27 Apr 2024 18:22:41 -0700 Subject: [PATCH 1639/2607] Revert #6458 (#6650) Reading the z-axis register is required. --- esphome/components/qmc5883l/qmc5883l.cpp | 46 ++++++++---------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 4946ad1b77..8541b41ff7 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -77,8 +77,17 @@ void QMC5883LComponent::dump_config() { float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } void QMC5883LComponent::update() { uint8_t status = false; - if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG) - this->read_byte(QMC5883L_REGISTER_STATUS, &status); + this->read_byte(QMC5883L_REGISTER_STATUS, &status); + + // Always request X,Y,Z regardless if there are sensors for them + // to avoid https://github.com/esphome/issues/issues/5731 + uint16_t raw_x, raw_y, raw_z; + if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x) || + !this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y) || + !this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { + this->status_set_warning(); + return; + } float mg_per_bit; switch (this->range_) { @@ -93,36 +102,11 @@ void QMC5883LComponent::update() { } // in µT - float x = NAN, y = NAN, z = NAN; - if (this->x_sensor_ != nullptr || this->heading_sensor_ != nullptr) { - uint16_t raw_x; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x)) { - this->status_set_warning(); - return; - } - x = int16_t(raw_x) * mg_per_bit * 0.1f; - } - if (this->y_sensor_ != nullptr || this->heading_sensor_ != nullptr) { - uint16_t raw_y; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y)) { - this->status_set_warning(); - return; - } - y = int16_t(raw_y) * mg_per_bit * 0.1f; - } - if (this->z_sensor_ != nullptr) { - uint16_t raw_z; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { - this->status_set_warning(); - return; - } - z = int16_t(raw_z) * mg_per_bit * 0.1f; - } + const float x = int16_t(raw_x) * mg_per_bit * 0.1f; + const float y = int16_t(raw_y) * mg_per_bit * 0.1f; + const float z = int16_t(raw_z) * mg_per_bit * 0.1f; - float heading = NAN; - if (this->heading_sensor_ != nullptr) { - heading = atan2f(0.0f - x, y) * 180.0f / M_PI; - } + float heading = atan2f(0.0f - x, y) * 180.0f / M_PI; float temp = NAN; if (this->temperature_sensor_ != nullptr) { From 0ef7781bb34f0b7f636942e16a0e638acdf597c5 Mon Sep 17 00:00:00 2001 From: optimusprimespace <62800678+optimusprimespace@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:22:14 +0200 Subject: [PATCH 1640/2607] [hm3301] Updated the AQI based on the airnow document (#6004) --- esphome/components/hm3301/aqi_calculator.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/esphome/components/hm3301/aqi_calculator.h b/esphome/components/hm3301/aqi_calculator.h index 6c830f9bad..c1b47826a2 100644 --- a/esphome/components/hm3301/aqi_calculator.h +++ b/esphome/components/hm3301/aqi_calculator.h @@ -1,6 +1,7 @@ #pragma once #include "abstract_aqi_calculator.h" +// https://www.airnow.gov/sites/default/files/2020-05/aqi-technical-assistance-document-sept2018.pdf namespace esphome { namespace hm3301 { @@ -15,14 +16,16 @@ class AQICalculator : public AbstractAQICalculator { } protected: - static const int AMOUNT_OF_LEVELS = 6; + static const int AMOUNT_OF_LEVELS = 7; - int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 51}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}}; + int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, + {201, 300}, {301, 400}, {401, 500}}; - int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150}, {151, 250}, {251, 500}}; + int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150}, + {151, 250}, {251, 350}, {351, 500}}; - int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254}, - {255, 354}, {355, 424}, {425, 604}}; + int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254}, {255, 354}, + {355, 424}, {425, 504}, {505, 604}}; int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) { int grid_index = get_grid_index_(value, array); From a700ae481d24ab9cb7c8ffb1b018967a25523823 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Apr 2024 07:33:52 +1200 Subject: [PATCH 1641/2607] Fix command line substitutions without any yaml substitutions (#6644) --- esphome/components/substitutions/__init__.py | 2 +- esphome/config.py | 4 ++-- script/test_build_components | 4 ++-- tests/test_build_components/build_components_base.bk72xx.yaml | 4 ---- .../build_components_base.esp32-ard.yaml | 4 ---- .../build_components_base.esp32-c3-ard.yaml | 4 ---- .../build_components_base.esp32-c3-idf.yaml | 4 ---- .../build_components_base.esp32-idf.yaml | 4 ---- .../build_components_base.esp32-s2-ard.yaml | 4 ---- .../build_components_base.esp32-s2-idf.yaml | 4 ---- .../build_components_base.esp32-s3-ard.yaml | 4 ---- .../build_components_base.esp32-s3-idf.yaml | 4 ---- .../test_build_components/build_components_base.esp8266.yaml | 4 ---- tests/test_build_components/build_components_base.host.yaml | 4 ---- tests/test_build_components/build_components_base.rp2040.yaml | 4 ---- 15 files changed, 5 insertions(+), 53 deletions(-) diff --git a/esphome/components/substitutions/__init__.py b/esphome/components/substitutions/__init__.py index ef368015b1..2d3a79ccae 100644 --- a/esphome/components/substitutions/__init__.py +++ b/esphome/components/substitutions/__init__.py @@ -116,7 +116,7 @@ def do_substitution_pass(config, command_line_substitutions, ignore_missing=Fals if CONF_SUBSTITUTIONS not in config and not command_line_substitutions: return - substitutions = config[CONF_SUBSTITUTIONS] + substitutions = config.get(CONF_SUBSTITUTIONS) if substitutions is None: substitutions = command_line_substitutions elif command_line_substitutions: diff --git a/esphome/config.py b/esphome/config.py index 1f6867eb59..73aa7077e0 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -756,11 +756,11 @@ def validate_config( CORE.raw_config = config # 1. Load substitutions - if CONF_SUBSTITUTIONS in config: + if CONF_SUBSTITUTIONS in config or command_line_substitutions: from esphome.components import substitutions result[CONF_SUBSTITUTIONS] = { - **config[CONF_SUBSTITUTIONS], + **config.get(CONF_SUBSTITUTIONS, {}), **command_line_substitutions, } result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS) diff --git a/script/test_build_components b/script/test_build_components index 2396353198..4d91256572 100755 --- a/script/test_build_components +++ b/script/test_build_components @@ -37,9 +37,9 @@ start_esphome() { # Start esphome process echo "> [$target_component] [$test_name] [$target_platform]" - echo "esphome -s component_name $target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file" + echo "esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file" # TODO: Validate escape of Command line substitution value - esphome -s component_name $target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file + esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file } # Find all test yaml files. diff --git a/tests/test_build_components/build_components_base.bk72xx.yaml b/tests/test_build_components/build_components_base.bk72xx.yaml index d74cc651eb..9fd9431826 100644 --- a/tests/test_build_components/build_components_base.bk72xx.yaml +++ b/tests/test_build_components/build_components_base.bk72xx.yaml @@ -12,8 +12,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-ard.yaml b/tests/test_build_components/build_components_base.esp32-ard.yaml index e345adcafc..31b7067acc 100644 --- a/tests/test_build_components/build_components_base.esp32-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-ard.yaml @@ -14,8 +14,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-c3-ard.yaml b/tests/test_build_components/build_components_base.esp32-c3-ard.yaml index 136ee62d4b..8aad447693 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-ard.yaml @@ -14,8 +14,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf.yaml index 4e809dd7ce..18584497f4 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-idf.yaml @@ -14,8 +14,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-idf.yaml b/tests/test_build_components/build_components_base.esp32-idf.yaml index 3c4532a958..a62a995e68 100644 --- a/tests/test_build_components/build_components_base.esp32-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-idf.yaml @@ -14,8 +14,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s2-ard.yaml b/tests/test_build_components/build_components_base.esp32-s2-ard.yaml index db62cdff6a..b8f2639127 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-ard.yaml @@ -15,8 +15,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml index 19fb657d8b..62f0f4f7bc 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml @@ -15,8 +15,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s3-ard.yaml b/tests/test_build_components/build_components_base.esp32-s3-ard.yaml index 39e12de08c..25cad038b6 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-ard.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-ard.yaml @@ -15,8 +15,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml index 95c73f917e..b1d08fcdf8 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml @@ -15,8 +15,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.esp8266.yaml b/tests/test_build_components/build_components_base.esp8266.yaml index 0019298ef0..ecf9acd2ba 100644 --- a/tests/test_build_components/build_components_base.esp8266.yaml +++ b/tests/test_build_components/build_components_base.esp8266.yaml @@ -12,8 +12,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.host.yaml b/tests/test_build_components/build_components_base.host.yaml index ec7570d99a..5492cfddd2 100644 --- a/tests/test_build_components/build_components_base.host.yaml +++ b/tests/test_build_components/build_components_base.host.yaml @@ -12,8 +12,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" diff --git a/tests/test_build_components/build_components_base.rp2040.yaml b/tests/test_build_components/build_components_base.rp2040.yaml index cb1cb6359b..335642374b 100644 --- a/tests/test_build_components/build_components_base.rp2040.yaml +++ b/tests/test_build_components/build_components_base.rp2040.yaml @@ -15,8 +15,4 @@ packages: component_under_test: !include file: $component_test_file vars: - component_name: $component_name - test_name: $test_name - target_platform: $target_platform component_test_file: $component_test_file - component_dir: "../../components/$component_name" From 8334934e0825884946f0e6a18b461d015c080c54 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 28 Apr 2024 14:44:40 -0500 Subject: [PATCH 1642/2607] Allow platform dependencies (#6623) --- esphome/config.py | 28 +++++++++++++++++++++++++--- script/list-components.py | 8 ++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index 73aa7077e0..36a81f677b 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -374,7 +374,10 @@ class LoadValidationStep(ConfigValidationStep): path + [CONF_ID], ) continue - result.add_str_error("No platform specified! See 'platform' key.", path) + result.add_str_error( + f"'{self.domain}' requires a 'platform' key but it was not specified.", + path, + ) continue # Remove temp output path and construct new one result.remove_output_path(path, p_domain) @@ -449,9 +452,28 @@ class MetadataValidationStep(ConfigValidationStep): success = True for dependency in self.comp.dependencies: - if dependency not in result: + dependency_parts = dependency.split(".") + if len(dependency_parts) > 2: result.add_str_error( - f"Component {self.domain} requires component {dependency}", + "Dependencies must be specified as a single component or in component.platform format only", + self.path, + ) + return + component_dep = dependency_parts[0] + platform_dep = dependency_parts[-1] + if component_dep not in result: + result.add_str_error( + f"Component {self.domain} requires component {component_dep}", + self.path, + ) + success = False + elif component_dep != platform_dep and ( + not isinstance(platform_list := result.get(component_dep), list) + or not any(CONF_PLATFORM in p for p in platform_list) + or not any(p[CONF_PLATFORM] == platform_dep for p in platform_list) + ): + result.add_str_error( + f"Component {self.domain} requires 'platform: {platform_dep}' in component '{component_dep}'", self.path, ) success = False diff --git a/script/list-components.py b/script/list-components.py index 8e2d47c6b3..5b5fa5811f 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -69,7 +69,9 @@ def create_components_graph(): sys.exit(1) for dependency in comp.dependencies: - add_item_to_components_graph(components_graph, dependency, name) + add_item_to_components_graph( + components_graph, dependency.split(".")[0], name + ) for target_config in TARGET_CONFIGURATIONS: CORE.data[KEY_CORE] = target_config @@ -87,7 +89,9 @@ def create_components_graph(): add_item_to_components_graph(components_graph, platform_name, name) for dependency in platform.dependencies: - add_item_to_components_graph(components_graph, dependency, name) + add_item_to_components_graph( + components_graph, dependency.split(".")[0], name + ) for target_config in TARGET_CONFIGURATIONS: CORE.data[KEY_CORE] = target_config From 5142d294f5204819fd6b5a858971b11a463620c3 Mon Sep 17 00:00:00 2001 From: Lucas Hartmann Date: Sun, 28 Apr 2024 16:47:15 -0300 Subject: [PATCH 1643/2607] [light] Add transition_length to strobe effect. (#6595) --- esphome/components/light/base_light_effects.h | 3 ++- esphome/components/light/effects.py | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/light/base_light_effects.h b/esphome/components/light/base_light_effects.h index c62ca43ca1..f7829a3f44 100644 --- a/esphome/components/light/base_light_effects.h +++ b/esphome/components/light/base_light_effects.h @@ -150,6 +150,7 @@ class AutomationLightEffect : public LightEffect { struct StrobeLightEffectColor { LightColorValues color; uint32_t duration; + uint32_t transition_length; }; class StrobeLightEffect : public LightEffect { @@ -174,7 +175,7 @@ class StrobeLightEffect : public LightEffect { } call.set_publish(false); call.set_save(false); - call.set_transition_length_if_supported(0); + call.set_transition_length_if_supported(this->colors_[this->at_color_].transition_length); call.perform(); this->last_switch_ = now; } diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index 5093ace949..be50f63321 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -266,6 +266,9 @@ async def random_effect_to_code(config, effect_id): cv.Required( CONF_DURATION ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TRANSITION_LENGTH, default="0s" + ): cv.positive_time_period_milliseconds, } ), cv.has_at_least_one_key( @@ -310,6 +313,7 @@ async def strobe_effect_to_code(config, effect_id): ), ), ("duration", color[CONF_DURATION]), + ("transition_length", color[CONF_TRANSITION_LENGTH]), ) ) cg.add(var.set_colors(colors)) From 8b6a35845250deee6021fcd993467023f35d7f49 Mon Sep 17 00:00:00 2001 From: chiahsing Date: Mon, 29 Apr 2024 03:49:27 +0800 Subject: [PATCH 1644/2607] Fixed the issue that graph draws out of the boundary. (#6651) --- esphome/components/graph/graph.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/esphome/components/graph/graph.cpp b/esphome/components/graph/graph.cpp index 1178af911d..09f7557714 100644 --- a/esphome/components/graph/graph.cpp +++ b/esphome/components/graph/graph.cpp @@ -177,22 +177,26 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo bool b = (trace->get_line_type() & bit) == bit; if (b) { int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0 - v)) - thick / 2 + y_offset; + auto draw_pixel_at = [&buff, c, y_offset, this](int16_t x, int16_t y) { + if (y >= y_offset && y < y_offset + this->height_) + buff->draw_pixel_at(x, y, c); + }; if (!continuous || !has_prev || !prev_b || (abs(y - prev_y) <= thick)) { for (int16_t t = 0; t < thick; t++) { - buff->draw_pixel_at(x, y + t, c); + draw_pixel_at(x, y + t); } } else { int16_t mid_y = (y + prev_y + thick) / 2; if (y > prev_y) { for (int16_t t = prev_y + thick; t <= mid_y; t++) - buff->draw_pixel_at(x + 1, t, c); + draw_pixel_at(x + 1, t); for (int16_t t = mid_y + 1; t < y + thick; t++) - buff->draw_pixel_at(x, t, c); + draw_pixel_at(x, t); } else { for (int16_t t = prev_y - 1; t >= mid_y; t--) - buff->draw_pixel_at(x + 1, t, c); + draw_pixel_at(x + 1, t); for (int16_t t = mid_y - 1; t >= y; t--) - buff->draw_pixel_at(x, t, c); + draw_pixel_at(x, t); } } prev_y = y; From 9ea442f3286ecb62b72f93133afb9f9a69d44fa2 Mon Sep 17 00:00:00 2001 From: Ulrich Date: Sun, 28 Apr 2024 21:56:13 +0200 Subject: [PATCH 1645/2607] Fix upload command. MQTT user and password is missing from configuration. #5093 (#5766) Co-authored-by: ulrich Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index dcd2dddb4b..b461dda4e7 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -768,7 +768,9 @@ def parse_args(argv): ) parser_upload = subparsers.add_parser( - "upload", help="Validate the configuration and upload the latest binary." + "upload", + help="Validate the configuration and upload the latest binary.", + parents=[mqtt_options], ) parser_upload.add_argument( "configuration", help="Your YAML configuration file(s).", nargs="+" From e7c1ddb4525031c90df0e76414cae81577d9d953 Mon Sep 17 00:00:00 2001 From: Matt Quigley Date: Sun, 28 Apr 2024 14:57:11 -0500 Subject: [PATCH 1646/2607] patch esphome cli to skip mqtt based device discovery if --device option is specified (#6371) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index b461dda4e7..54c1aa112a 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -343,9 +343,10 @@ def upload_program(config, args, host): password = ota_conf.get(CONF_PASSWORD, "") if ( - not is_ip_address(CORE.address) + not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) and CONF_MQTT in config + and (not args.device or args.device == "MQTT") ): from esphome import mqtt From 80a0b5b1b109b424b85b5b00d5af84cec482c7bd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:10:12 +1200 Subject: [PATCH 1647/2607] [i2s_audio.microphone] Fixing adc bug (#6654) --- .../microphone/i2s_audio_microphone.cpp | 65 +++++++++++++++++-- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 602d537bcb..1475df0975 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -61,28 +61,57 @@ void I2SAudioMicrophone::start_() { .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; + esp_err_t err; + #if SOC_I2S_SUPPORTS_ADC if (this->adc_) { config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN); - i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + + err = i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error setting ADC mode: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + err = i2s_adc_enable(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error enabling ADC: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } - i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); - i2s_adc_enable(this->parent_->get_port()); } else #endif { if (this->pdm_) config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM); - i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } i2s_pin_config_t pin_config = this->parent_->get_pin_config(); pin_config.data_in_num = this->din_pin_; - i2s_set_pin(this->parent_->get_port(), &pin_config); + err = i2s_set_pin(this->parent_->get_port(), &pin_config); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error setting I2S pin: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } } this->state_ = microphone::STATE_RUNNING; this->high_freq_.start(); + this->status_clear_error(); } void I2SAudioMicrophone::stop() { @@ -96,11 +125,33 @@ void I2SAudioMicrophone::stop() { } void I2SAudioMicrophone::stop_() { - i2s_stop(this->parent_->get_port()); - i2s_driver_uninstall(this->parent_->get_port()); + esp_err_t err; +#if SOC_I2S_SUPPORTS_ADC + if (this->adc_) { + err = i2s_adc_disable(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + } +#endif + err = i2s_stop(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error stopping I2S microphone: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + err = i2s_driver_uninstall(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error uninstalling I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } this->parent_->unlock(); this->state_ = microphone::STATE_STOPPED; this->high_freq_.stop(); + this->status_clear_error(); } size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { From c007593f729d96c34566d6c36a5fb9b817cbc692 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 29 Apr 2024 13:53:08 +1000 Subject: [PATCH 1648/2607] Fix for #4866 - inconsistent arguments (#6639) --- esphome/components/binary_sensor/automation.cpp | 6 +++--- esphome/core/helpers.cpp | 2 +- tests/components/host/test.host.yaml | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/components/host/test.host.yaml diff --git a/esphome/components/binary_sensor/automation.cpp b/esphome/components/binary_sensor/automation.cpp index bfec882e07..7ac201b2db 100644 --- a/esphome/components/binary_sensor/automation.cpp +++ b/esphome/components/binary_sensor/automation.cpp @@ -51,15 +51,15 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) { MultiClickTriggerEvent evt = this->timing_[*this->at_index_]; if (evt.max_length != 4294967294UL) { - ESP_LOGV(TAG, "A i=%u min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT + ESP_LOGV(TAG, "A i=%zu min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT this->schedule_is_valid_(evt.min_length); this->schedule_is_not_valid_(evt.max_length); } else if (*this->at_index_ + 1 != this->timing_.size()) { - ESP_LOGV(TAG, "B i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT + ESP_LOGV(TAG, "B i=%zu min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT this->cancel_timeout("is_not_valid"); this->schedule_is_valid_(evt.min_length); } else { - ESP_LOGV(TAG, "C i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT + ESP_LOGV(TAG, "C i=%zu min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT this->is_valid_ = false; this->cancel_timeout("is_not_valid"); this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); }); diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 4368576301..fdc0eed774 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -437,7 +437,7 @@ static inline bool is_base64(char c) { return (isalnum(c) || (c == '+') || (c == std::string base64_encode(const std::vector &buf) { return base64_encode(buf.data(), buf.size()); } -std::string base64_encode(const char *buf, unsigned int buf_len) { +std::string base64_encode(const uint8_t *buf, size_t buf_len) { std::string ret; int i = 0; int j = 0; diff --git a/tests/components/host/test.host.yaml b/tests/components/host/test.host.yaml new file mode 100644 index 0000000000..3d14c190a6 --- /dev/null +++ b/tests/components/host/test.host.yaml @@ -0,0 +1,15 @@ +time: + - platform: sntp + id: esptime + timezone: Australia/Sydney + +logger: + level: VERBOSE + logs: + lvgl: INFO + display: DEBUG + sensor: INFO + vnc: DEBUG + +host: + mac_address: "62:23:45:AF:B3:DD" From 73bb4aa4d5428cd4d1034d8dd7ad9800903d632f Mon Sep 17 00:00:00 2001 From: Anton Sergunov Date: Mon, 29 Apr 2024 16:40:03 +0600 Subject: [PATCH 1649/2607] [template/text] Fix lambda config (#6655) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/template/text/__init__.py | 2 +- tests/component_tests/text/test_text.py | 14 ++++++++++++++ tests/component_tests/text/test_text.yaml | 12 ++++++++++++ tests/components/template/common.yaml | 11 +++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/esphome/components/template/text/__init__.py b/esphome/components/template/text/__init__.py index 0f228a3c6b..f73b240197 100644 --- a/esphome/components/template/text/__init__.py +++ b/esphome/components/template/text/__init__.py @@ -28,7 +28,7 @@ def validate(config): raise cv.Invalid("optimistic cannot be used with lambda") if CONF_INITIAL_VALUE in config: raise cv.Invalid("initial_value cannot be used with lambda") - if CONF_RESTORE_VALUE in config: + if config[CONF_RESTORE_VALUE]: raise cv.Invalid("restore_value cannot be used with lambda") elif CONF_INITIAL_VALUE not in config: config[CONF_INITIAL_VALUE] = "" diff --git a/tests/component_tests/text/test_text.py b/tests/component_tests/text/test_text.py index 43f4ef2592..51fcb3d382 100644 --- a/tests/component_tests/text/test_text.py +++ b/tests/component_tests/text/test_text.py @@ -54,3 +54,17 @@ def test_text_config_value_mode_set(generate_main): # Then assert "it_1->traits.set_mode(text::TEXT_MODE_TEXT);" in main_cpp assert "it_3->traits.set_mode(text::TEXT_MODE_PASSWORD);" in main_cpp + + +def test_text_config_lamda_is_set(generate_main): + """ + Test if lambda is set for lambda mode + """ + # Given + + # When + main_cpp = generate_main("tests/component_tests/text/test_text.yaml") + + # Then + assert "it_4->set_template([=]() -> optional {" in main_cpp + assert 'return std::string{"Hello"};' in main_cpp diff --git a/tests/component_tests/text/test_text.yaml b/tests/component_tests/text/test_text.yaml index d0fdf5303f..d81c909f9d 100644 --- a/tests/component_tests/text/test_text.yaml +++ b/tests/component_tests/text/test_text.yaml @@ -31,3 +31,15 @@ text: optimistic: true internal: true max_length: 255 + + - platform: template + name: "test 4 key" + id: "it_4" + mode: text + set_action: + - then: + - logger.log: + format: Template text set to %s + args: ["x.c_str()"] + lambda: | + return std::string{"Hello"}; diff --git a/tests/components/template/common.yaml b/tests/components/template/common.yaml index ba7167157b..2b91225b5a 100644 --- a/tests/components/template/common.yaml +++ b/tests/components/template/common.yaml @@ -149,6 +149,17 @@ text: min_length: 0 max_length: 100 mode: text + - platform: template + name: "Template text lambda" + mode: text + update_interval: 1s + lambda: | + return std::string{"Hello!"}; + set_action: + then: + - logger.log: + format: Template Text set to %s + args: ["x.c_str()"] alarm_control_panel: - platform: template From 47c262832be69f7cd69ae93fde87c3e7931368eb Mon Sep 17 00:00:00 2001 From: Peter Zich Date: Mon, 29 Apr 2024 12:24:13 -0700 Subject: [PATCH 1650/2607] web_server: Add support for v3 local server_index (#6563) --- esphome/components/web_server/server_index.h | 605 --- .../components/web_server/server_index_v2.h | 633 +++ .../components/web_server/server_index_v3.h | 3995 +++++++++++++++++ esphome/components/web_server/web_server.cpp | 6 +- 4 files changed, 4633 insertions(+), 606 deletions(-) delete mode 100644 esphome/components/web_server/server_index.h create mode 100644 esphome/components/web_server/server_index_v2.h create mode 100644 esphome/components/web_server/server_index_v3.h diff --git a/esphome/components/web_server/server_index.h b/esphome/components/web_server/server_index.h deleted file mode 100644 index 180dffab67..0000000000 --- a/esphome/components/web_server/server_index.h +++ /dev/null @@ -1,605 +0,0 @@ -#pragma once -// Generated from https://github.com/esphome/esphome-webserver -#include "esphome/core/hal.h" -namespace esphome { - -namespace web_server { - -const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x7d, 0xd9, 0x76, 0xe3, 0xc6, 0x92, 0xe0, 0xf3, - 0x9c, 0x33, 0x7f, 0x30, 0x2f, 0x10, 0x4a, 0xad, 0x02, 0xae, 0x40, 0x88, 0xa4, 0x6a, 0x33, 0x28, 0x90, 0x57, 0xb5, - 0xd8, 0x55, 0x76, 0x6d, 0x2e, 0xa9, 0xec, 0x6b, 0xcb, 0xb4, 0x04, 0x91, 0x49, 0x11, 0x2e, 0x10, 0xa0, 0x81, 0xa4, - 0x16, 0x53, 0xe8, 0x33, 0x4f, 0xf3, 0xd4, 0xe7, 0xcc, 0xd6, 0x0f, 0xfd, 0x30, 0x7d, 0xba, 0x1f, 0xe6, 0x23, 0xe6, - 0xb9, 0x3f, 0xe5, 0xfe, 0xc0, 0xf4, 0x27, 0x4c, 0x44, 0xe4, 0x82, 0x04, 0x17, 0x49, 0x5e, 0xba, 0xe7, 0xd8, 0x2a, - 0x12, 0xb9, 0x46, 0x44, 0x46, 0xc6, 0x96, 0x91, 0xe0, 0xde, 0xc6, 0x30, 0x1b, 0xf0, 0xab, 0x29, 0xb3, 0xc6, 0x7c, - 0x92, 0x74, 0xf7, 0xe4, 0xbf, 0x2c, 0x1a, 0x76, 0xf7, 0x92, 0x38, 0xfd, 0x64, 0xe5, 0x2c, 0x09, 0xe3, 0x41, 0x96, - 0x5a, 0xe3, 0x9c, 0x8d, 0xc2, 0x61, 0xc4, 0xa3, 0x20, 0x9e, 0x44, 0x67, 0xcc, 0xda, 0xe9, 0xee, 0x4d, 0x18, 0x8f, - 0xac, 0xc1, 0x38, 0xca, 0x0b, 0xc6, 0xc3, 0x8f, 0x87, 0x9f, 0x37, 0x9e, 0x74, 0xf7, 0x8a, 0x41, 0x1e, 0x4f, 0xb9, - 0x85, 0x43, 0x86, 0x93, 0x6c, 0x38, 0x4b, 0x58, 0xf7, 0x3c, 0xca, 0xad, 0x17, 0x3c, 0x7c, 0x77, 0xfa, 0x13, 0x1b, - 0x70, 0x7f, 0xc8, 0x46, 0x71, 0xca, 0xde, 0xe7, 0xd9, 0x94, 0xe5, 0xfc, 0xca, 0x3b, 0x58, 0x5d, 0x11, 0xb3, 0xc2, - 0x7b, 0xa6, 0xab, 0xce, 0x18, 0x7f, 0x77, 0x91, 0xaa, 0x3e, 0xcf, 0x99, 0x98, 0x24, 0xcb, 0x0b, 0xaf, 0x58, 0xd3, - 0xe6, 0xe0, 0x6a, 0x72, 0x9a, 0x25, 0x85, 0xf7, 0x49, 0xd7, 0x4f, 0xf3, 0x8c, 0x67, 0x08, 0x96, 0x3f, 0x8e, 0x0a, - 0xa3, 0xa5, 0xf7, 0x6e, 0x45, 0x93, 0xa9, 0xac, 0x7c, 0x55, 0xbc, 0x48, 0x67, 0x13, 0x96, 0x47, 0xa7, 0x09, 0xf3, - 0x72, 0x1e, 0x3a, 0xdc, 0x63, 0x5e, 0xec, 0x86, 0x5d, 0x66, 0xc5, 0xa9, 0xc5, 0x7b, 0x2f, 0x38, 0x95, 0xcc, 0x99, - 0x6e, 0x15, 0x6c, 0x34, 0x3d, 0x20, 0xd7, 0x28, 0x3e, 0x9b, 0xe9, 0xe7, 0x8b, 0x3c, 0xe6, 0xea, 0xfb, 0x79, 0x94, - 0xcc, 0x58, 0x10, 0x97, 0x6e, 0xc0, 0x8f, 0x58, 0x3f, 0x8c, 0xbd, 0x4f, 0x34, 0x28, 0x0c, 0x39, 0x1f, 0x65, 0xb9, - 0x83, 0xb4, 0x8a, 0x71, 0x6c, 0x76, 0x7d, 0xed, 0xb0, 0x70, 0x5e, 0xba, 0xee, 0x27, 0xee, 0x0f, 0xa2, 0x24, 0x71, - 0x70, 0xe2, 0xad, 0xad, 0x1c, 0x67, 0x8c, 0x3d, 0x76, 0x14, 0xf7, 0xdd, 0x4e, 0x3c, 0x72, 0x0a, 0xee, 0x56, 0xfd, - 0xb2, 0x91, 0x55, 0x70, 0x87, 0xb9, 0xee, 0xbb, 0xf5, 0x7d, 0x72, 0xc6, 0x67, 0x39, 0xc0, 0x5e, 0x7a, 0xef, 0xd4, - 0xcc, 0x07, 0x58, 0xff, 0x8c, 0x3a, 0x76, 0x00, 0xf6, 0x82, 0x5b, 0x9f, 0x87, 0x17, 0x71, 0x3a, 0xcc, 0x2e, 0xfc, - 0x83, 0x71, 0x04, 0x1f, 0x1f, 0xb2, 0x8c, 0x6f, 0x6d, 0x39, 0xe7, 0x59, 0x3c, 0xb4, 0x9a, 0x61, 0x68, 0x56, 0x5e, - 0x3d, 0x3b, 0x38, 0xb8, 0xbe, 0x5e, 0x28, 0xf0, 0xd3, 0x88, 0xc7, 0xe7, 0x4c, 0x74, 0x06, 0x00, 0x6c, 0xf8, 0x9c, - 0x72, 0x36, 0x3c, 0xe0, 0x57, 0x09, 0x94, 0x32, 0xc6, 0x0b, 0x1b, 0x70, 0x7c, 0x9e, 0x0d, 0x80, 0x6c, 0xa9, 0x41, - 0x78, 0x68, 0x9a, 0xb3, 0x69, 0x12, 0x0d, 0x18, 0xd6, 0xc3, 0x48, 0x55, 0x8f, 0xaa, 0x91, 0xf7, 0x6d, 0x28, 0x96, - 0xd7, 0x71, 0xbd, 0x94, 0x87, 0x29, 0xbb, 0xb0, 0xde, 0x44, 0xd3, 0xce, 0x20, 0x89, 0x8a, 0xc2, 0xca, 0xf8, 0x9c, - 0x50, 0xc8, 0x67, 0x03, 0x60, 0x10, 0x42, 0x70, 0x0e, 0x64, 0xe2, 0xe3, 0xb8, 0xf0, 0x8f, 0x37, 0x07, 0x45, 0xf1, - 0x81, 0x15, 0xb3, 0x84, 0x6f, 0x86, 0xb0, 0x16, 0x6c, 0x23, 0x0c, 0xbf, 0x75, 0xf9, 0x38, 0xcf, 0x2e, 0xac, 0x17, - 0x79, 0x0e, 0xcd, 0x6d, 0x98, 0x52, 0x34, 0xb0, 0xe2, 0xc2, 0x4a, 0x33, 0x6e, 0xe9, 0xc1, 0x70, 0x01, 0x7d, 0xeb, - 0x63, 0xc1, 0xac, 0x93, 0x59, 0x5a, 0x44, 0x23, 0x06, 0x4d, 0x4f, 0xac, 0x2c, 0xb7, 0x4e, 0x60, 0xd0, 0x13, 0x58, - 0xb2, 0x82, 0xc3, 0xae, 0xf1, 0x6d, 0xb7, 0x43, 0x73, 0x41, 0xe1, 0x21, 0xbb, 0xe4, 0x21, 0x2f, 0x81, 0x31, 0x61, - 0x55, 0x14, 0x1a, 0x8e, 0x3b, 0x4f, 0xa0, 0x00, 0xc0, 0x26, 0x96, 0x75, 0xcc, 0xc6, 0x7a, 0x71, 0x3e, 0xdf, 0xda, - 0xd2, 0xb4, 0x46, 0xc2, 0x43, 0xdb, 0x62, 0xa1, 0xad, 0x27, 0x10, 0xaf, 0x91, 0xc8, 0xf5, 0xb8, 0x2f, 0xc9, 0x77, - 0x70, 0x95, 0x0e, 0xea, 0x63, 0x43, 0x65, 0xc9, 0xb3, 0x03, 0x9e, 0xc7, 0xe9, 0x19, 0x00, 0xa1, 0xd8, 0xc0, 0x68, - 0x52, 0x96, 0x62, 0xf1, 0xdf, 0x03, 0xd4, 0x61, 0x17, 0x47, 0xcf, 0xb8, 0x63, 0x17, 0xd4, 0xc3, 0x06, 0x40, 0x80, - 0xf4, 0xc0, 0x60, 0xbc, 0xc7, 0x03, 0xbe, 0x6d, 0xdb, 0xde, 0xb7, 0xae, 0x77, 0x81, 0x1c, 0xe4, 0xfb, 0x3e, 0xb1, - 0xaf, 0xe8, 0x1c, 0x87, 0x2d, 0x04, 0xda, 0x4f, 0x58, 0x7a, 0xc6, 0xc7, 0x3d, 0x7e, 0xd4, 0xec, 0x07, 0x0c, 0xa0, - 0x1a, 0xce, 0x06, 0xcc, 0x41, 0x7e, 0xf4, 0x0a, 0xdc, 0x3e, 0xdb, 0x0e, 0x4c, 0x81, 0x0b, 0xb3, 0x41, 0x38, 0xd6, - 0x96, 0xc6, 0x55, 0xb0, 0x29, 0xc0, 0x90, 0xcf, 0x6d, 0xd8, 0x61, 0xa7, 0x2c, 0x37, 0xe0, 0xd0, 0xcd, 0x3a, 0xb5, - 0x15, 0x9c, 0xc1, 0x0a, 0x41, 0x3f, 0x6b, 0x34, 0x4b, 0x07, 0x3c, 0x06, 0xc1, 0x65, 0x6f, 0x03, 0xb8, 0x62, 0xe5, - 0xf4, 0xc2, 0xd9, 0x6e, 0xe9, 0x3a, 0xb1, 0xbb, 0xcd, 0x8f, 0x8a, 0xed, 0x56, 0xdf, 0x43, 0x28, 0x35, 0xf1, 0x25, - 0xe2, 0x31, 0x20, 0x58, 0x7a, 0x1f, 0xb9, 0xde, 0x9e, 0x9f, 0xf7, 0xb8, 0xbf, 0xcc, 0xc7, 0x21, 0xf3, 0x27, 0xd1, - 0x14, 0xb1, 0xe1, 0xc4, 0x03, 0x51, 0x3a, 0x40, 0xe8, 0x6a, 0xeb, 0x82, 0x14, 0xf3, 0x2b, 0x16, 0x70, 0x81, 0x20, - 0xb0, 0x67, 0x5f, 0x44, 0x83, 0x31, 0x6c, 0xf1, 0x8a, 0x70, 0x43, 0xb5, 0x1d, 0x06, 0x39, 0x8b, 0x38, 0x7b, 0x91, - 0x30, 0x7c, 0xc2, 0x15, 0x80, 0x9e, 0xb6, 0xeb, 0x15, 0x6a, 0xdf, 0x25, 0x31, 0x7f, 0x9b, 0xc1, 0x3c, 0x1d, 0xc1, - 0x24, 0xc0, 0xc5, 0xc5, 0xd6, 0x56, 0x8c, 0x2c, 0xb2, 0xcf, 0x61, 0xb5, 0x4e, 0x67, 0x9c, 0x01, 0xbd, 0xb0, 0x85, - 0x0d, 0xd4, 0xf6, 0x62, 0x9f, 0x03, 0x11, 0x9f, 0x65, 0x29, 0x87, 0xe1, 0x00, 0x5e, 0xcd, 0x41, 0x7e, 0x34, 0x9d, - 0xb2, 0x74, 0xf8, 0x6c, 0x1c, 0x27, 0x43, 0xa0, 0x46, 0x09, 0xf8, 0x26, 0x3c, 0x04, 0x3c, 0x01, 0x99, 0xe0, 0x66, - 0x8c, 0x68, 0xf9, 0x90, 0x91, 0x59, 0x68, 0xdb, 0x1d, 0x94, 0x40, 0x12, 0x0b, 0x94, 0x41, 0xb4, 0x70, 0x1f, 0x40, - 0xf4, 0x17, 0x2e, 0xdb, 0x0e, 0x63, 0xbd, 0x8c, 0x92, 0xc0, 0xef, 0x51, 0xd2, 0x00, 0xfd, 0x81, 0x10, 0xbc, 0x83, - 0x82, 0xeb, 0x4b, 0x29, 0x75, 0x22, 0xae, 0x30, 0x04, 0x02, 0x0c, 0x50, 0x82, 0x48, 0x1a, 0xbc, 0xcf, 0x92, 0xab, - 0x51, 0x9c, 0x24, 0x07, 0xb3, 0xe9, 0x34, 0xcb, 0xb9, 0xf7, 0x55, 0x38, 0xe7, 0x59, 0x85, 0x2b, 0x6d, 0xf2, 0xe2, - 0x22, 0xe6, 0x48, 0x50, 0x77, 0x3e, 0x88, 0x60, 0xa9, 0x9f, 0x66, 0x59, 0xc2, 0xa2, 0x14, 0xd0, 0xe0, 0x3d, 0xdb, - 0x0e, 0xd2, 0x59, 0x92, 0x74, 0x4e, 0x61, 0xd8, 0x4f, 0x1d, 0xaa, 0x16, 0x12, 0x3f, 0xa0, 0xef, 0xfb, 0x79, 0x1e, - 0x5d, 0x41, 0x43, 0x6c, 0x03, 0xec, 0x05, 0xab, 0xf5, 0xe5, 0xc1, 0xbb, 0xb7, 0xbe, 0x60, 0xfc, 0x78, 0x74, 0x05, - 0x80, 0x96, 0x95, 0xd4, 0x1c, 0xe5, 0xd9, 0x64, 0x61, 0x6a, 0xa4, 0x43, 0x1c, 0xf2, 0xce, 0x1a, 0x10, 0x62, 0x1a, - 0x19, 0x56, 0x89, 0x9b, 0x10, 0xbc, 0x25, 0x7e, 0x96, 0x95, 0xb8, 0x07, 0x7a, 0xf8, 0x25, 0x10, 0xc5, 0x30, 0xe5, - 0x2d, 0xd0, 0xe6, 0x57, 0xf3, 0x38, 0x24, 0x38, 0xa7, 0xa8, 0x7f, 0x11, 0xc6, 0x41, 0x04, 0xb3, 0xcf, 0xc5, 0x80, - 0xa5, 0x82, 0x38, 0x2e, 0x4b, 0x6f, 0xac, 0x99, 0x18, 0x25, 0x1e, 0x0a, 0x14, 0x16, 0x86, 0xa0, 0x60, 0x38, 0x3c, - 0xb8, 0xde, 0xd7, 0xe1, 0x3c, 0x52, 0xf8, 0xa0, 0x86, 0xc2, 0xfd, 0x15, 0x08, 0x39, 0x81, 0x9a, 0xec, 0x1c, 0xf4, - 0x20, 0xc0, 0xf9, 0x95, 0x07, 0xfa, 0x3f, 0x41, 0x28, 0x36, 0x5a, 0x1e, 0x68, 0xd0, 0x67, 0xe3, 0x28, 0x3d, 0x63, - 0xc3, 0x60, 0xcc, 0x4b, 0x29, 0x79, 0xf7, 0x2d, 0x58, 0x63, 0x60, 0xa7, 0xc2, 0x7a, 0x79, 0xf8, 0xe6, 0xb5, 0x5c, - 0xb9, 0x9a, 0x30, 0x86, 0x45, 0x9a, 0x81, 0x5a, 0x05, 0xb1, 0x2d, 0xc5, 0xf1, 0x0b, 0x2d, 0xbd, 0x45, 0x49, 0x5c, - 0x7c, 0x9c, 0x82, 0x89, 0xc1, 0xde, 0xc3, 0x30, 0x30, 0x7d, 0x08, 0x53, 0x51, 0x39, 0xcc, 0x27, 0x2a, 0x86, 0xba, - 0x08, 0x3a, 0x0b, 0x4c, 0xc5, 0x63, 0xe6, 0xb8, 0x25, 0xb0, 0x2a, 0x8f, 0x07, 0x56, 0x34, 0x1c, 0xbe, 0x4a, 0x63, - 0x1e, 0x47, 0x49, 0xfc, 0x0b, 0x51, 0x72, 0x8e, 0x3c, 0xc6, 0x3a, 0x72, 0x11, 0x00, 0x77, 0xea, 0x91, 0xb8, 0x4a, - 0xc8, 0x6e, 0x10, 0x31, 0x84, 0xb4, 0x4c, 0xc2, 0xa3, 0xbe, 0x04, 0x2f, 0xf1, 0xa7, 0xb3, 0x62, 0x8c, 0x84, 0x95, - 0x03, 0xa3, 0x20, 0xcf, 0x4e, 0x0b, 0x96, 0x9f, 0xb3, 0xa1, 0xe6, 0x80, 0x02, 0xb0, 0xa2, 0xe6, 0x60, 0xbc, 0xd0, - 0x8c, 0x8e, 0xd2, 0xa1, 0x1c, 0x86, 0xea, 0x98, 0x62, 0x96, 0x49, 0x66, 0xd6, 0x16, 0x8e, 0x96, 0x02, 0x8e, 0x30, - 0x2a, 0xa4, 0x24, 0x28, 0x42, 0x85, 0xe1, 0x18, 0xa4, 0x10, 0x73, 0x6b, 0xdb, 0x5c, 0x69, 0xb2, 0x17, 0x33, 0x52, - 0x09, 0x05, 0x74, 0x84, 0x8d, 0x4c, 0x90, 0x16, 0x2e, 0xec, 0x2a, 0x90, 0xf2, 0x12, 0x5c, 0x21, 0x45, 0x94, 0x99, - 0x83, 0x0c, 0x10, 0x7e, 0x4d, 0xba, 0x90, 0xf9, 0xd8, 0x82, 0x21, 0x1b, 0xf8, 0x7a, 0xe5, 0x81, 0xb0, 0x12, 0xef, - 0x0a, 0x11, 0x6f, 0x0d, 0xd8, 0xa4, 0x8b, 0x00, 0x30, 0x6f, 0x83, 0xf9, 0x69, 0xb6, 0x3f, 0x18, 0xb0, 0xa2, 0xc8, - 0xf2, 0xad, 0xad, 0x0d, 0x6a, 0xbf, 0xce, 0xd0, 0x02, 0x4a, 0xba, 0x5a, 0xd6, 0xd9, 0x05, 0x69, 0x70, 0x53, 0xad, - 0x28, 0x9d, 0x1e, 0xd8, 0xc7, 0xc7, 0x20, 0xb3, 0x3d, 0x49, 0x06, 0xa0, 0xfa, 0xb2, 0xe1, 0x27, 0xec, 0x99, 0x3a, - 0x65, 0x56, 0xda, 0x97, 0x4e, 0x1d, 0x24, 0x0f, 0x86, 0x75, 0x4b, 0x63, 0x41, 0x57, 0x0e, 0x8d, 0xab, 0x21, 0x15, - 0xe4, 0xfc, 0x8c, 0x54, 0xb6, 0xb1, 0x8c, 0x60, 0xb5, 0x95, 0x1e, 0x91, 0x5e, 0x61, 0x93, 0x13, 0xa0, 0x47, 0xbc, - 0xdf, 0x91, 0xf5, 0x61, 0x21, 0x28, 0x97, 0xb3, 0x9f, 0x67, 0xac, 0xe0, 0x82, 0x75, 0x61, 0xdc, 0x1c, 0xc6, 0x2d, - 0x97, 0xac, 0xc3, 0x9a, 0xed, 0xb8, 0x0a, 0xb6, 0x77, 0x53, 0xd4, 0x63, 0x05, 0x72, 0xf2, 0xcd, 0xec, 0x44, 0xf6, - 0x84, 0x7b, 0x7d, 0xfd, 0xb5, 0x1a, 0xa4, 0x5a, 0x4a, 0x6d, 0x03, 0x2d, 0xac, 0x89, 0xad, 0x9a, 0x0c, 0x6d, 0x57, - 0x2a, 0xd4, 0x8d, 0x56, 0xa7, 0xc6, 0x07, 0xb0, 0xe7, 0x9a, 0x9a, 0xa5, 0x2b, 0x63, 0xfb, 0xbd, 0xa2, 0xe9, 0x3b, - 0x31, 0x32, 0x59, 0xa3, 0xfc, 0x76, 0xee, 0x51, 0x3b, 0x1e, 0xda, 0x2e, 0xd5, 0x55, 0x82, 0x61, 0x56, 0x17, 0x0c, - 0x8b, 0x50, 0x4f, 0x75, 0x17, 0x5b, 0x33, 0x15, 0x0f, 0xd5, 0x5a, 0x2b, 0x07, 0x82, 0x85, 0x47, 0x60, 0x9c, 0xac, - 0xf4, 0x0f, 0xde, 0x46, 0x13, 0x86, 0x14, 0xf5, 0xd6, 0x35, 0x90, 0x0e, 0x04, 0x34, 0xe9, 0x2f, 0xaa, 0x37, 0xe6, - 0x0a, 0xab, 0xa9, 0xbe, 0xbf, 0x62, 0xb0, 0x22, 0xc0, 0xbe, 0x2e, 0x57, 0x2c, 0x11, 0xe9, 0x4d, 0xc9, 0xce, 0x8a, - 0x3e, 0xa2, 0x4c, 0xac, 0x09, 0x29, 0x78, 0x40, 0x1e, 0x96, 0x7f, 0x61, 0xe1, 0x54, 0x2b, 0x85, 0x23, 0x43, 0x99, - 0x02, 0x74, 0x26, 0x25, 0x00, 0xe2, 0x92, 0x3e, 0x6b, 0x1b, 0x0b, 0xc9, 0x76, 0x80, 0x7c, 0xe0, 0x8f, 0x92, 0x88, - 0x3b, 0xad, 0x9d, 0xa6, 0x0b, 0x7c, 0x08, 0x42, 0x1c, 0x74, 0x04, 0x98, 0xf7, 0x15, 0x2a, 0x1c, 0x51, 0x89, 0x5d, - 0xe6, 0x83, 0x51, 0x34, 0x8e, 0x47, 0xdc, 0x49, 0x90, 0x79, 0xdc, 0x92, 0x25, 0xa0, 0x64, 0xf4, 0xbe, 0x02, 0x65, - 0xc1, 0x84, 0x74, 0x11, 0xd5, 0x4a, 0xa0, 0x31, 0x05, 0x29, 0x49, 0x29, 0xd2, 0x82, 0x0a, 0x02, 0x43, 0xa8, 0x74, - 0x14, 0x47, 0x81, 0x7e, 0x8b, 0x7b, 0x62, 0xd0, 0x60, 0xc9, 0xa2, 0x8c, 0x7b, 0xf1, 0x72, 0x21, 0xa8, 0x61, 0x9f, - 0x67, 0xaf, 0xb3, 0x0b, 0x96, 0x3f, 0x8b, 0x10, 0xf6, 0x40, 0x74, 0x2f, 0x41, 0xd2, 0x93, 0x40, 0xe7, 0x1d, 0xc5, - 0x2b, 0xe7, 0x84, 0x34, 0x2c, 0xc4, 0x24, 0x46, 0x45, 0x08, 0x76, 0x0b, 0xd1, 0x3e, 0xc5, 0x2d, 0x45, 0x7b, 0x0f, - 0x55, 0x09, 0xd7, 0xbc, 0xb5, 0xff, 0xba, 0xce, 0x5b, 0x30, 0xc2, 0x54, 0x71, 0x6b, 0x7d, 0xc7, 0x82, 0x7b, 0x21, - 0x74, 0xb3, 0x23, 0x79, 0xcb, 0x50, 0x66, 0xa0, 0x3f, 0xae, 0xaf, 0x2b, 0x23, 0x1d, 0x94, 0xa9, 0x96, 0xe6, 0x08, - 0x81, 0xd8, 0x12, 0x6e, 0x09, 0xca, 0x08, 0x0d, 0xaf, 0x3c, 0x4b, 0x12, 0x43, 0x17, 0x79, 0x71, 0xc7, 0x59, 0x50, - 0x47, 0x00, 0xc5, 0xa4, 0xa6, 0x91, 0x7a, 0x2c, 0xd0, 0x15, 0xa8, 0x94, 0x94, 0x36, 0xf2, 0xaa, 0xb5, 0x11, 0x10, - 0xa7, 0x43, 0x96, 0x0b, 0x07, 0x4d, 0xea, 0x50, 0x98, 0x30, 0x05, 0x86, 0x66, 0x43, 0xf4, 0x1c, 0x24, 0x02, 0x60, - 0x9e, 0xf8, 0xe3, 0xac, 0xe0, 0xba, 0xce, 0x84, 0x3e, 0xbe, 0xbe, 0x8e, 0x85, 0xbf, 0x88, 0x0c, 0x90, 0xb3, 0x49, - 0x76, 0xce, 0x56, 0x40, 0xdd, 0x51, 0x83, 0x99, 0x20, 0x1b, 0xc3, 0x80, 0x12, 0x05, 0xd5, 0x32, 0x4d, 0x62, 0xb0, - 0xf4, 0x75, 0x03, 0x1f, 0x0c, 0x3a, 0x76, 0x89, 0x32, 0xc2, 0xed, 0x76, 0xbb, 0x4d, 0xaf, 0xe5, 0x96, 0x82, 0xe0, - 0xf3, 0x25, 0x8a, 0xde, 0xa0, 0x1f, 0xa5, 0x09, 0xbe, 0x4a, 0x16, 0x30, 0xd7, 0x50, 0x8a, 0xc2, 0x4f, 0x62, 0x9e, - 0x14, 0xc4, 0xae, 0x37, 0x84, 0x41, 0x39, 0x53, 0x82, 0x1b, 0x4d, 0x5c, 0xb1, 0x6d, 0x3f, 0x68, 0xb2, 0x69, 0x76, - 0x52, 0x3b, 0x4c, 0x2d, 0x8c, 0x5c, 0xf3, 0x42, 0x7b, 0xc0, 0xe6, 0xf2, 0x90, 0x4d, 0x8f, 0xd5, 0xc0, 0xeb, 0x00, - 0xa1, 0xf0, 0x74, 0x9d, 0x25, 0x94, 0xaa, 0xce, 0x52, 0x88, 0xeb, 0x0d, 0xf4, 0x51, 0x81, 0xb9, 0x8a, 0x04, 0x07, - 0x52, 0x20, 0x30, 0xf4, 0xc8, 0xc4, 0x7a, 0x3d, 0x83, 0xe5, 0x39, 0x8d, 0x06, 0x9f, 0x34, 0xb8, 0x15, 0xef, 0x2d, - 0xb2, 0x81, 0xb3, 0x50, 0x12, 0x1a, 0xe2, 0xca, 0xc4, 0x5b, 0x49, 0xe8, 0xda, 0x46, 0x01, 0x87, 0x6c, 0x89, 0xed, - 0x17, 0x17, 0x7a, 0x91, 0xdb, 0x25, 0x7b, 0x28, 0xff, 0xa9, 0xe2, 0x92, 0xf5, 0x2c, 0xc7, 0x94, 0x34, 0x60, 0x8a, - 0xf1, 0x60, 0x69, 0x16, 0x20, 0x01, 0xbe, 0x2b, 0x87, 0x71, 0xb1, 0x9e, 0x04, 0x7f, 0x28, 0x98, 0xcf, 0x8d, 0x99, - 0x6e, 0x85, 0x54, 0x4b, 0x38, 0x69, 0x06, 0x6b, 0xd0, 0xa4, 0xf1, 0xa0, 0x44, 0xcd, 0x57, 0x68, 0xa8, 0x10, 0xc7, - 0x9f, 0x89, 0x2a, 0x34, 0xc1, 0x10, 0x8c, 0xc2, 0xcb, 0x25, 0xc3, 0xa5, 0xcb, 0xa2, 0x45, 0xca, 0xd4, 0x98, 0x54, - 0xaa, 0x66, 0xb9, 0x14, 0x0c, 0x2c, 0xda, 0xad, 0xbe, 0xb4, 0xc4, 0x95, 0xc8, 0xcd, 0x42, 0x2d, 0x4c, 0x72, 0xe5, - 0x4d, 0x38, 0x05, 0xfa, 0x5d, 0xca, 0x7a, 0x37, 0xf1, 0x29, 0x14, 0x3e, 0x85, 0x6f, 0xf8, 0x50, 0x26, 0x6f, 0xe7, - 0x3d, 0x30, 0xf7, 0x6b, 0x95, 0x68, 0x9f, 0xfa, 0x28, 0x98, 0x5d, 0x2d, 0x74, 0x41, 0xa0, 0x48, 0x36, 0xc9, 0x7a, - 0x92, 0xdf, 0x50, 0x6c, 0x54, 0x9e, 0x51, 0xea, 0x8a, 0x0d, 0x52, 0xf3, 0x4a, 0x53, 0x2f, 0x73, 0x17, 0xec, 0xf7, - 0xb2, 0x94, 0x74, 0x62, 0x82, 0x32, 0xb1, 0x77, 0x13, 0x6d, 0xbc, 0x2c, 0x4c, 0x85, 0xf5, 0x2b, 0x8c, 0x9d, 0x1a, - 0x85, 0x32, 0x29, 0x02, 0x71, 0x6c, 0x7c, 0xac, 0x2c, 0x83, 0xd4, 0x5f, 0x61, 0x4f, 0x01, 0x28, 0x09, 0x2c, 0xbe, - 0xa6, 0x92, 0x17, 0x85, 0x75, 0x3a, 0x6e, 0x10, 0x1d, 0x2b, 0x11, 0x5a, 0x13, 0xf9, 0x5a, 0x9f, 0xc5, 0x7e, 0xcd, - 0x25, 0x34, 0x29, 0x59, 0xf4, 0x8a, 0xc0, 0x56, 0x81, 0x88, 0x4a, 0xb7, 0x25, 0xbd, 0x84, 0x1c, 0xd2, 0x65, 0xa2, - 0xd7, 0x46, 0x32, 0x68, 0x9d, 0x09, 0x89, 0x96, 0xf5, 0xc3, 0x08, 0xc5, 0x86, 0x58, 0x8b, 0x25, 0x42, 0x2e, 0xda, - 0x9b, 0xc4, 0x8a, 0xe8, 0x9c, 0x16, 0x68, 0xc2, 0x99, 0x3a, 0xdd, 0x71, 0x00, 0x1d, 0x10, 0xfb, 0x4b, 0xac, 0xb7, - 0xd2, 0xec, 0x74, 0xfd, 0xca, 0xe1, 0xbb, 0xbe, 0x1e, 0x73, 0xd7, 0x91, 0x06, 0x2f, 0xac, 0x59, 0x4f, 0xc9, 0xde, - 0xfd, 0xd7, 0xd8, 0x8a, 0xec, 0xcf, 0xaa, 0xa4, 0xf2, 0x14, 0x6a, 0x9c, 0x5b, 0x5f, 0xa7, 0x5a, 0x68, 0x51, 0x55, - 0x1c, 0x18, 0x52, 0xfd, 0x40, 0x29, 0xec, 0x0a, 0xe5, 0x03, 0x39, 0x74, 0xec, 0xba, 0x6e, 0x50, 0x90, 0xf3, 0xb2, - 0xb1, 0xca, 0x85, 0xdc, 0xda, 0x32, 0x7d, 0xa6, 0x73, 0x3d, 0xfc, 0x33, 0x07, 0x95, 0x73, 0x71, 0x95, 0x92, 0x05, - 0xf3, 0x4c, 0xa9, 0xa3, 0x25, 0x07, 0xb4, 0xd9, 0x41, 0x4f, 0x3b, 0xba, 0x88, 0x62, 0x6e, 0xe9, 0x51, 0x84, 0xa7, - 0x8d, 0xf2, 0x49, 0x1a, 0x1d, 0x80, 0x17, 0x9a, 0x90, 0xe4, 0x84, 0x9b, 0xb6, 0x68, 0x31, 0x18, 0x33, 0x0c, 0x81, - 0x2b, 0x7b, 0xc2, 0x94, 0x3d, 0x1b, 0x88, 0xb7, 0x1c, 0x78, 0x35, 0xec, 0xe5, 0x62, 0xf7, 0x9a, 0xf9, 0x0f, 0x6b, - 0x04, 0xb2, 0x6d, 0xa2, 0xea, 0xca, 0x85, 0x67, 0x29, 0x22, 0x31, 0xc2, 0xb6, 0x6a, 0x6c, 0x69, 0xeb, 0x77, 0x16, - 0xdc, 0xeb, 0xca, 0x31, 0xaf, 0x29, 0xd5, 0x05, 0x3d, 0xac, 0xdc, 0x1c, 0x6e, 0x3a, 0xf2, 0x62, 0x05, 0xdd, 0x8e, - 0x08, 0x0a, 0x81, 0x13, 0xa1, 0xec, 0x41, 0xcd, 0x0d, 0x44, 0x4a, 0xa6, 0xb4, 0x6a, 0x36, 0x4b, 0x86, 0x12, 0x58, - 0x70, 0x61, 0x99, 0xe4, 0xa3, 0x8b, 0x38, 0x49, 0xaa, 0xd2, 0x3f, 0x54, 0xc0, 0x8b, 0x61, 0x6f, 0x13, 0xed, 0x02, - 0xa3, 0x99, 0x02, 0xc1, 0xd5, 0x46, 0xd8, 0x47, 0xc7, 0xad, 0xd6, 0x5d, 0x44, 0x1c, 0x99, 0x19, 0x8d, 0xf8, 0x88, - 0x36, 0x64, 0xc9, 0x34, 0x6b, 0xef, 0xbf, 0xc0, 0x90, 0x9a, 0x81, 0x0f, 0xaa, 0x33, 0x2a, 0xfe, 0x55, 0xf6, 0xd4, - 0xaf, 0x44, 0xef, 0x56, 0xd5, 0xb5, 0x18, 0x50, 0x51, 0x81, 0x0f, 0x33, 0xc4, 0xd2, 0x54, 0x81, 0x80, 0x5c, 0x0f, - 0xeb, 0x70, 0xb7, 0x46, 0x1a, 0x2c, 0x28, 0x05, 0xd6, 0x5a, 0xd9, 0xbd, 0xbe, 0x2d, 0x98, 0x43, 0xa1, 0x70, 0xd1, - 0xff, 0x59, 0x36, 0x99, 0xa2, 0x65, 0xb6, 0xc0, 0xd4, 0xd0, 0xe0, 0xe3, 0x42, 0x7d, 0xb9, 0xa2, 0xac, 0xd6, 0x87, - 0x76, 0x64, 0x8d, 0x9f, 0xb4, 0xa3, 0x0c, 0x0e, 0xd5, 0x4c, 0x17, 0xd5, 0xed, 0xe6, 0x45, 0x11, 0xb3, 0x8a, 0xc7, - 0x7d, 0xd2, 0xdb, 0xda, 0x9a, 0xf4, 0x34, 0x0d, 0x48, 0x26, 0x49, 0x86, 0x37, 0x19, 0xa0, 0xac, 0x88, 0x33, 0x2f, - 0x17, 0xc8, 0x37, 0x2f, 0x4b, 0x5c, 0xbf, 0xef, 0x3b, 0xfb, 0x35, 0xcf, 0xda, 0xdb, 0x5f, 0xef, 0x22, 0x57, 0x75, - 0xd2, 0x83, 0x3c, 0xea, 0x43, 0xd1, 0x92, 0x4d, 0x19, 0xce, 0x27, 0xd9, 0x90, 0x05, 0x36, 0x74, 0x4f, 0xed, 0x52, - 0x6e, 0x9a, 0x08, 0x36, 0x07, 0xf8, 0x7f, 0xf3, 0x0f, 0xf5, 0x48, 0x6a, 0xb0, 0x0f, 0x2c, 0xa0, 0xcd, 0x85, 0x2f, - 0xc3, 0xb3, 0x24, 0x3b, 0x8d, 0x92, 0x43, 0xa1, 0xc0, 0x6b, 0x2d, 0xbf, 0x01, 0x97, 0x91, 0x2c, 0x56, 0x43, 0x49, - 0x7d, 0xd9, 0xfb, 0x32, 0xb8, 0xbd, 0x47, 0xe5, 0xad, 0xd8, 0x2d, 0xbf, 0xe9, 0xb7, 0x6c, 0x15, 0x11, 0xfb, 0xc9, - 0x9c, 0x0e, 0x34, 0x4e, 0x01, 0x94, 0x39, 0x04, 0x4d, 0x56, 0x78, 0x03, 0x1e, 0xfe, 0xd4, 0xfb, 0x49, 0xb9, 0xd4, - 0x19, 0xb8, 0x10, 0xe0, 0xe4, 0x27, 0x31, 0x6f, 0xe0, 0x79, 0xa4, 0xed, 0xcd, 0x45, 0x05, 0xc6, 0x15, 0x29, 0x2e, - 0x5d, 0x2a, 0x6f, 0xd0, 0x3b, 0x0e, 0x4f, 0xa0, 0xd9, 0xe6, 0xe6, 0xdc, 0x79, 0x13, 0xf1, 0xb1, 0x9f, 0x47, 0xe9, - 0x30, 0x9b, 0x38, 0xee, 0xb6, 0x6d, 0xbb, 0x7e, 0x41, 0x9e, 0xc8, 0x67, 0x6e, 0xb9, 0x79, 0xe2, 0x0d, 0x79, 0x68, - 0xf7, 0xec, 0xed, 0x63, 0xef, 0x90, 0x87, 0x27, 0x7b, 0x9b, 0xf3, 0x21, 0x2f, 0xbb, 0x27, 0xde, 0xa5, 0x8e, 0xb9, - 0x7b, 0xef, 0x51, 0xca, 0x40, 0xaf, 0xb0, 0x7b, 0x29, 0xc1, 0x00, 0x76, 0xa3, 0xf8, 0x3b, 0x48, 0xb9, 0x8f, 0x74, - 0x20, 0x22, 0xe3, 0xb4, 0xd7, 0xd7, 0x76, 0x46, 0x11, 0x03, 0x7b, 0x43, 0x3b, 0xab, 0x5b, 0x5b, 0x95, 0x9a, 0xaf, - 0x4a, 0xbd, 0x19, 0x0f, 0x6b, 0x9e, 0xba, 0xf7, 0x92, 0x8e, 0x56, 0xea, 0x1b, 0x79, 0x26, 0x82, 0x36, 0xcb, 0x76, - 0x82, 0x63, 0x6c, 0xf1, 0xd5, 0xdb, 0xfa, 0x48, 0x44, 0x29, 0xfc, 0x18, 0xac, 0x97, 0x08, 0xd4, 0x37, 0x38, 0x38, - 0xde, 0x61, 0xb8, 0xb3, 0xe7, 0xf4, 0x02, 0x67, 0xa3, 0xd1, 0xb8, 0xfe, 0x61, 0xe7, 0xe8, 0xc7, 0xa8, 0xf1, 0xcb, - 0x7e, 0xe3, 0xfb, 0xbe, 0x7b, 0xed, 0xfc, 0xb0, 0xd3, 0x3b, 0x92, 0x4f, 0x47, 0x3f, 0x76, 0x7f, 0x28, 0xfa, 0x7f, - 0x12, 0x85, 0x9b, 0xae, 0xbb, 0x73, 0xe6, 0x4d, 0x79, 0xb8, 0xd3, 0x68, 0x74, 0xe1, 0xdb, 0x19, 0x7c, 0xc3, 0xcf, - 0x53, 0xf8, 0xb8, 0x3e, 0xb2, 0xfe, 0xc3, 0x0f, 0xe9, 0x7f, 0xfc, 0x21, 0xef, 0xe3, 0x98, 0x47, 0x3f, 0xfe, 0x50, - 0xd8, 0xf7, 0xbb, 0xe1, 0x4e, 0x7f, 0xdb, 0x75, 0x74, 0xcd, 0x9f, 0xc2, 0xea, 0x2b, 0xb4, 0x3a, 0xfa, 0x51, 0x3e, - 0xd9, 0xf7, 0x4f, 0xf6, 0xba, 0x61, 0xff, 0xda, 0xb1, 0xaf, 0xef, 0xbb, 0xd7, 0xae, 0x7b, 0xbd, 0x89, 0xf3, 0x9c, - 0xc3, 0xe8, 0xf7, 0xe1, 0x73, 0x04, 0x9f, 0x36, 0x7c, 0x6e, 0xc2, 0xe7, 0x8f, 0xd0, 0x4d, 0xc4, 0xdf, 0xae, 0x29, - 0x16, 0x72, 0x8d, 0x07, 0x16, 0x11, 0xac, 0x82, 0xbb, 0xb9, 0x13, 0x7b, 0x13, 0x22, 0x1a, 0xec, 0x43, 0xdf, 0xf7, - 0x31, 0x4c, 0xea, 0xcc, 0x8f, 0x37, 0x61, 0xd1, 0x91, 0x73, 0x36, 0x03, 0xee, 0x89, 0xc8, 0x41, 0x11, 0x30, 0x71, - 0xb6, 0x5a, 0xe0, 0xe1, 0xaa, 0x37, 0x0c, 0x27, 0xdc, 0x01, 0xa3, 0xe0, 0x03, 0xc7, 0x2f, 0x6d, 0xd7, 0x7b, 0x21, - 0xcf, 0x0c, 0x71, 0x9f, 0x0b, 0xd6, 0x4a, 0x33, 0x61, 0xd2, 0xd8, 0xae, 0x37, 0x5d, 0x51, 0x09, 0xdb, 0x3a, 0x3d, - 0x83, 0xba, 0x63, 0x11, 0xa3, 0xfe, 0x96, 0x45, 0x9f, 0x70, 0x4b, 0xbe, 0x35, 0x0e, 0x81, 0x97, 0x2c, 0xf9, 0x45, - 0xa3, 0xd1, 0xb0, 0x11, 0x85, 0x3b, 0xf6, 0x94, 0xc1, 0x0c, 0x4b, 0x26, 0x22, 0x23, 0xa5, 0x29, 0x2c, 0x5b, 0x98, - 0xfc, 0x7d, 0x94, 0xf3, 0xcd, 0xca, 0xb0, 0x0d, 0xeb, 0x96, 0xec, 0x82, 0xa5, 0x7f, 0x87, 0x29, 0xd0, 0xb4, 0xa4, - 0xf3, 0x0f, 0x73, 0xfc, 0x30, 0x23, 0xb4, 0x3e, 0x38, 0x0c, 0x3c, 0xf4, 0x02, 0xe4, 0x8e, 0xe8, 0xe7, 0xbc, 0x47, - 0x35, 0x06, 0xff, 0xcb, 0x30, 0x83, 0x27, 0xe6, 0xc3, 0x10, 0xcd, 0xbc, 0xd4, 0xc1, 0xad, 0x0c, 0xc5, 0xfd, 0x2b, - 0xdc, 0x19, 0x59, 0xe9, 0x1d, 0x84, 0x6a, 0xc7, 0x1c, 0xe6, 0x8c, 0x7d, 0x1b, 0x25, 0x9f, 0x58, 0xee, 0x5c, 0x7a, - 0xad, 0xf6, 0x67, 0xd4, 0xd9, 0x43, 0xdb, 0xec, 0x4d, 0x75, 0x8c, 0xa6, 0xcd, 0x02, 0x79, 0x44, 0xd8, 0x68, 0x79, - 0x28, 0x31, 0x88, 0x04, 0xb9, 0x97, 0x86, 0x6d, 0xe2, 0x70, 0x7b, 0xaf, 0x38, 0x3f, 0xeb, 0xda, 0x81, 0x6d, 0x83, - 0xc5, 0x7f, 0x48, 0x61, 0x2b, 0x61, 0x58, 0x34, 0x3b, 0x6c, 0x2f, 0xee, 0xb0, 0xed, 0xed, 0x2a, 0xe0, 0x84, 0x07, - 0xe9, 0xd4, 0x3d, 0xf1, 0x22, 0x6f, 0x1c, 0xc2, 0x80, 0x03, 0x68, 0x86, 0x5d, 0x3a, 0x83, 0xbd, 0x58, 0x4e, 0x03, - 0xb2, 0x3e, 0xf3, 0x93, 0xa8, 0xe0, 0xaf, 0x30, 0x1e, 0x11, 0x0e, 0xc0, 0xd8, 0xcf, 0x7c, 0x76, 0xc9, 0x06, 0xca, - 0xce, 0x00, 0x42, 0x45, 0x6e, 0xc7, 0x1d, 0x84, 0x46, 0x33, 0x98, 0x3b, 0x0c, 0x0f, 0x7b, 0x36, 0xec, 0x25, 0xd8, - 0x95, 0x61, 0x74, 0xd4, 0xea, 0xf7, 0xb2, 0x70, 0xca, 0x03, 0x4d, 0x5b, 0x59, 0x74, 0x56, 0x2b, 0x6a, 0xf7, 0x7b, - 0xce, 0x26, 0x18, 0xe9, 0x60, 0x8b, 0x3b, 0xf8, 0x84, 0x11, 0x8a, 0x3c, 0xfc, 0xc0, 0xce, 0x5e, 0x5c, 0x4e, 0x1d, - 0x7b, 0x6f, 0xc7, 0xde, 0xc6, 0x52, 0xcf, 0x06, 0xf6, 0x02, 0x0a, 0x86, 0xa7, 0xae, 0xd9, 0x79, 0xb7, 0x8f, 0xa0, - 0x62, 0x21, 0x4e, 0x7e, 0xda, 0xb3, 0xbb, 0x62, 0xea, 0x26, 0x0c, 0x9a, 0xc9, 0xe5, 0xc7, 0x15, 0x3d, 0x24, 0x54, - 0x55, 0x57, 0x05, 0x1d, 0x94, 0xb5, 0x03, 0x67, 0x6c, 0x22, 0xd1, 0xc0, 0xc9, 0x24, 0x15, 0xc0, 0xe1, 0xc1, 0x66, - 0x30, 0xa9, 0xd1, 0x6d, 0xb7, 0xdf, 0x3b, 0x0d, 0xee, 0xdb, 0xf7, 0xd5, 0xc3, 0x08, 0x90, 0xe1, 0x62, 0xfa, 0x11, - 0x48, 0x3b, 0xfc, 0x3c, 0xe7, 0x80, 0xe4, 0x29, 0x15, 0x4d, 0x65, 0xd1, 0x19, 0x16, 0x1d, 0x06, 0x08, 0xaa, 0x97, - 0x6b, 0xeb, 0x4f, 0xac, 0xc9, 0x30, 0x24, 0xd8, 0xc1, 0x16, 0x3a, 0x62, 0xdb, 0xad, 0x3e, 0x9e, 0x37, 0xe4, 0xbc, - 0xf8, 0x36, 0xe6, 0xa0, 0x12, 0x76, 0xba, 0xb6, 0xdb, 0xb3, 0x2d, 0x5c, 0xda, 0x4e, 0xba, 0x1d, 0x0a, 0x0a, 0xc7, - 0xdb, 0x87, 0x3c, 0x18, 0x77, 0xc3, 0x66, 0xcf, 0x29, 0x64, 0xb8, 0x11, 0xcf, 0x2d, 0x85, 0x04, 0x6f, 0x7a, 0x63, - 0x10, 0xe8, 0xc8, 0xb9, 0x9b, 0xf6, 0xb6, 0x2a, 0x84, 0xa2, 0xe3, 0xed, 0xa1, 0x1b, 0xc4, 0xf0, 0xe1, 0x34, 0x90, - 0x69, 0xc6, 0xba, 0xaf, 0xd2, 0xcc, 0xcc, 0x0d, 0x86, 0xca, 0x22, 0x4f, 0xc2, 0x74, 0xdb, 0xc1, 0x08, 0x2d, 0x48, - 0xda, 0xbd, 0x1e, 0xc0, 0xb0, 0xed, 0x28, 0x4e, 0xdb, 0x51, 0xac, 0xa6, 0xec, 0xf3, 0x23, 0xbd, 0x1c, 0x03, 0xde, - 0x1b, 0xa8, 0xf3, 0x58, 0xd4, 0x3e, 0x00, 0x56, 0x90, 0x78, 0x45, 0x5f, 0x9d, 0x79, 0xbd, 0xac, 0x9d, 0x6f, 0xcd, - 0x95, 0x28, 0xe2, 0x9e, 0x21, 0xa1, 0x58, 0xa9, 0xdd, 0x30, 0x61, 0x6e, 0x4f, 0x91, 0x18, 0x9a, 0xe5, 0x43, 0xd8, - 0x63, 0xa1, 0x0a, 0xb0, 0x67, 0xe6, 0xb6, 0x48, 0xc2, 0xaa, 0xb9, 0x77, 0x04, 0xac, 0xdd, 0x0f, 0xdf, 0x08, 0x77, - 0xaa, 0xa3, 0xa2, 0xf9, 0x2c, 0x09, 0x5f, 0x2e, 0x1c, 0x17, 0x47, 0x78, 0x22, 0x74, 0xe0, 0x0f, 0x66, 0x39, 0xc8, - 0x03, 0xfe, 0x16, 0x2c, 0x83, 0x50, 0x36, 0x45, 0x47, 0x0f, 0x8f, 0x80, 0x3d, 0x42, 0x7c, 0x21, 0x6c, 0x6e, 0x54, - 0xa3, 0x45, 0x49, 0xc6, 0x0b, 0x1d, 0x0c, 0x77, 0x98, 0x74, 0xed, 0x51, 0x30, 0xc8, 0x13, 0x63, 0x07, 0xcf, 0xfc, - 0xfd, 0x01, 0x56, 0xe3, 0x04, 0x85, 0x5b, 0xd2, 0x6e, 0xab, 0xc4, 0xdf, 0x81, 0x9f, 0x82, 0x04, 0xc7, 0x3a, 0xf0, - 0xb3, 0xb6, 0xb6, 0x12, 0x89, 0xd4, 0x5e, 0xd6, 0xa1, 0x93, 0x08, 0x8c, 0x07, 0x17, 0x7e, 0x0a, 0xd5, 0x48, 0x22, - 0x2a, 0x22, 0x0b, 0xd4, 0x3c, 0x55, 0xab, 0xe0, 0x3b, 0x32, 0x23, 0xf0, 0x8c, 0x92, 0x5c, 0xd0, 0x50, 0xd4, 0x8d, - 0x45, 0x2c, 0xdf, 0x75, 0xe9, 0x68, 0x0b, 0x0f, 0x20, 0x05, 0xa3, 0x09, 0x86, 0x71, 0x29, 0x28, 0x59, 0xf1, 0xdf, - 0xb1, 0x11, 0x2b, 0x1f, 0x1f, 0xa5, 0xdb, 0xdb, 0x7d, 0x71, 0x6e, 0x41, 0x8c, 0xc3, 0x8c, 0xe8, 0x6a, 0x5c, 0x01, - 0x50, 0x9f, 0xce, 0x89, 0xeb, 0x81, 0x69, 0xc5, 0x9a, 0x2e, 0xc5, 0x3e, 0x39, 0xcc, 0x00, 0x14, 0xdc, 0x71, 0x8e, - 0xfc, 0xde, 0x9f, 0xfb, 0xe0, 0x1e, 0xfb, 0x7f, 0x72, 0x77, 0x94, 0xa0, 0xe9, 0xc8, 0x33, 0xc5, 0x39, 0x9d, 0xb1, - 0xb6, 0x3c, 0x8a, 0x8d, 0x06, 0x20, 0xf5, 0x00, 0x03, 0xd0, 0xe6, 0x20, 0x13, 0x2a, 0x0e, 0x42, 0x8e, 0x0a, 0x6c, - 0x1f, 0x37, 0x3f, 0xc3, 0x9d, 0xfd, 0x9c, 0x07, 0x60, 0xc1, 0xa8, 0xa7, 0xd7, 0xf0, 0xf4, 0x67, 0xfd, 0xf4, 0x13, - 0x0f, 0x7e, 0x29, 0x65, 0xe8, 0xbe, 0x36, 0xc5, 0x23, 0x35, 0x45, 0x29, 0x96, 0xc8, 0xa0, 0x21, 0x77, 0x97, 0x63, - 0x36, 0xcc, 0x2d, 0x81, 0x18, 0x4a, 0x74, 0x81, 0x8d, 0x16, 0x9d, 0x21, 0x71, 0x5d, 0x93, 0x14, 0x46, 0x2e, 0x81, - 0x89, 0x70, 0xc5, 0xb7, 0x48, 0x4f, 0xd6, 0x6d, 0xba, 0xf3, 0x5a, 0x5b, 0xb2, 0xef, 0xd8, 0x64, 0xca, 0xaf, 0x0e, - 0x48, 0xd1, 0x07, 0x32, 0x6d, 0x40, 0x9c, 0x9d, 0x37, 0x3b, 0xf1, 0x1e, 0xeb, 0xc4, 0x20, 0xd5, 0x0b, 0xc5, 0x62, - 0xb8, 0x57, 0xbd, 0xf7, 0x18, 0xa5, 0x34, 0x99, 0xc9, 0xab, 0xa1, 0xd7, 0x96, 0xe8, 0x6d, 0x6f, 0x03, 0x82, 0x1d, - 0xa3, 0x2b, 0x13, 0x5d, 0xcb, 0x52, 0xd0, 0x04, 0x20, 0x7a, 0x52, 0x67, 0x39, 0xe2, 0x38, 0xcc, 0x66, 0x83, 0xe2, - 0x21, 0x77, 0x57, 0x8e, 0x8a, 0x63, 0x62, 0x77, 0x99, 0xb0, 0x03, 0x98, 0x11, 0x97, 0x37, 0x5a, 0x22, 0x3a, 0x2c, - 0xfa, 0xeb, 0xf8, 0xf6, 0xb1, 0xc7, 0xb7, 0x5b, 0x2e, 0x68, 0x90, 0xda, 0x58, 0x8f, 0xab, 0xb1, 0xa0, 0x3e, 0x3c, - 0xd6, 0x54, 0x2a, 0xf3, 0xed, 0xed, 0xb2, 0x7e, 0x54, 0xab, 0x76, 0x70, 0xed, 0x34, 0xe5, 0x72, 0x31, 0x1b, 0x84, - 0x03, 0x11, 0x13, 0x28, 0xd0, 0xd2, 0xca, 0x8a, 0x01, 0x86, 0x94, 0xe5, 0x28, 0x9f, 0x42, 0xee, 0xc5, 0x65, 0xa9, - 0x53, 0x5f, 0x9e, 0xc9, 0xa0, 0x23, 0x9e, 0x7a, 0x92, 0xb1, 0x02, 0xac, 0xe6, 0x65, 0x5e, 0x42, 0x4b, 0x04, 0x98, - 0xbf, 0x50, 0x39, 0x34, 0xc2, 0x02, 0x89, 0x42, 0xc3, 0x2c, 0x51, 0xc6, 0x67, 0x1e, 0xc6, 0xa0, 0xed, 0x9f, 0xd5, - 0x62, 0x5f, 0xb9, 0x32, 0x3a, 0xf2, 0xa3, 0xa2, 0x1f, 0x50, 0xfd, 0x4c, 0x4a, 0xb0, 0x71, 0xf8, 0x11, 0xd8, 0xa8, - 0x72, 0x3c, 0x49, 0x10, 0x3e, 0x8f, 0x73, 0x46, 0x9e, 0xc2, 0xa6, 0x84, 0x59, 0x9a, 0xb6, 0x91, 0x6a, 0x17, 0x99, - 0x41, 0x28, 0x17, 0xe6, 0x1f, 0x1b, 0x67, 0x17, 0x69, 0xb8, 0xd4, 0x1a, 0xcc, 0x8f, 0x77, 0x26, 0x40, 0xe9, 0xf5, - 0x75, 0x2a, 0x7c, 0xdc, 0x88, 0xec, 0x0d, 0x5d, 0x31, 0xee, 0x29, 0xa4, 0x02, 0x27, 0x22, 0x8b, 0x87, 0xce, 0x50, - 0x68, 0x84, 0x43, 0x3a, 0x45, 0x2e, 0x5c, 0x63, 0xd3, 0x17, 0x3d, 0xed, 0x1b, 0x65, 0xa1, 0x93, 0x80, 0x10, 0x10, - 0xb8, 0x1b, 0xd6, 0x54, 0xd6, 0xcb, 0x82, 0x84, 0x4a, 0xd1, 0xcf, 0x01, 0xfc, 0xc3, 0x48, 0x52, 0x00, 0xec, 0x87, - 0x6a, 0xa4, 0x88, 0xb2, 0x2c, 0x70, 0x01, 0x68, 0xae, 0x03, 0x5c, 0x09, 0x5f, 0x18, 0xa8, 0x30, 0x3d, 0xcd, 0xca, - 0x4a, 0xa1, 0x44, 0x9e, 0xae, 0x48, 0x59, 0x23, 0x99, 0x7c, 0x8e, 0x0e, 0x9f, 0xf2, 0xae, 0xdf, 0x4a, 0x3c, 0x74, - 0xc1, 0x73, 0x58, 0x56, 0xf5, 0xfd, 0x4d, 0xc8, 0xc8, 0xb9, 0x06, 0x5d, 0x21, 0x85, 0xfe, 0x92, 0x93, 0xbc, 0xff, - 0xc6, 0xaf, 0x6a, 0xa9, 0x31, 0x94, 0x7d, 0x5c, 0xd5, 0x0c, 0xcb, 0xcb, 0x69, 0x15, 0xa6, 0x20, 0xe0, 0xe6, 0x2c, - 0x09, 0xe6, 0x52, 0x43, 0x80, 0x85, 0xed, 0x91, 0x56, 0x0a, 0x8a, 0x52, 0x87, 0x77, 0x9e, 0x83, 0x15, 0x60, 0x1c, - 0x6a, 0xa9, 0x64, 0x1a, 0x49, 0x7c, 0xa9, 0x44, 0x81, 0x29, 0x0f, 0x06, 0xe0, 0xa7, 0x2e, 0x9e, 0x74, 0x5d, 0xba, - 0x7e, 0x3c, 0xc1, 0xd4, 0x1e, 0x02, 0x3d, 0xf6, 0x36, 0xc0, 0x94, 0xa8, 0xeb, 0xb0, 0x9c, 0x38, 0x34, 0xad, 0x69, - 0x16, 0x30, 0x63, 0x9a, 0xa0, 0x25, 0x9b, 0x60, 0xcb, 0x15, 0x60, 0x1f, 0x89, 0xed, 0x59, 0xad, 0x80, 0xd0, 0x35, - 0x68, 0x60, 0xc8, 0x5d, 0x2a, 0xb4, 0x30, 0xeb, 0xb4, 0xa9, 0x08, 0xf7, 0x67, 0x8f, 0x49, 0x2b, 0x38, 0xf5, 0x52, - 0x1a, 0xf8, 0x20, 0x3e, 0x4d, 0x30, 0xf1, 0x05, 0xb1, 0x02, 0x3b, 0x38, 0x68, 0x2d, 0x36, 0x05, 0x4e, 0xc5, 0x45, - 0x4a, 0x61, 0x59, 0x51, 0x6a, 0xc3, 0x87, 0x14, 0xd9, 0xba, 0xcb, 0x23, 0xdd, 0x85, 0x58, 0x00, 0x3b, 0xfd, 0xc2, - 0xa1, 0x83, 0xac, 0x97, 0x01, 0x83, 0x73, 0xad, 0x71, 0x10, 0xf8, 0xed, 0xed, 0xa4, 0x5f, 0x66, 0x48, 0xb9, 0x25, - 0x56, 0x17, 0x90, 0xe3, 0x76, 0x58, 0xc0, 0x1d, 0x84, 0xa5, 0xb2, 0xc7, 0xf3, 0x72, 0x82, 0xcb, 0xa5, 0x2c, 0xe4, - 0xc5, 0x74, 0x2c, 0x9a, 0xcf, 0xad, 0x34, 0x9b, 0x8e, 0xb7, 0xe2, 0x83, 0x82, 0xbf, 0xe7, 0xc4, 0xd2, 0xaa, 0xa7, - 0xd4, 0x0a, 0x8f, 0x32, 0xb7, 0x64, 0x9d, 0x92, 0x5a, 0x6d, 0x37, 0x50, 0x8d, 0xf0, 0x34, 0x0d, 0x1b, 0x81, 0x10, - 0x13, 0x5c, 0xfc, 0x61, 0x91, 0x89, 0x69, 0x6f, 0x09, 0xa9, 0x23, 0xec, 0x1e, 0xca, 0x09, 0x6e, 0x6b, 0x9e, 0x7d, - 0x19, 0x4e, 0xd7, 0x33, 0xf7, 0xbe, 0xc1, 0xdc, 0x4f, 0x43, 0x66, 0x30, 0x7a, 0x2c, 0x13, 0x7e, 0x64, 0xec, 0xa3, - 0x50, 0x55, 0xcf, 0xce, 0xc2, 0x4a, 0x64, 0x89, 0x6f, 0xc6, 0x51, 0x87, 0x71, 0x2a, 0x5a, 0x13, 0x64, 0xd7, 0xd7, - 0xb9, 0xb9, 0x17, 0x28, 0x68, 0xea, 0xb1, 0x7a, 0x9c, 0xb6, 0x62, 0x67, 0x23, 0x12, 0xb9, 0xff, 0xa6, 0x16, 0x89, - 0xac, 0xf8, 0x1c, 0x47, 0x5a, 0x73, 0x90, 0xfb, 0xec, 0x6c, 0x79, 0x93, 0x0a, 0xdd, 0xa2, 0xd1, 0x36, 0xf6, 0xa8, - 0x3e, 0x90, 0xd4, 0x33, 0x2a, 0xb0, 0xaa, 0xb1, 0xb7, 0xb6, 0x5a, 0x22, 0xdd, 0x52, 0x29, 0x36, 0x0c, 0x69, 0x85, - 0xcc, 0x18, 0x05, 0x83, 0x92, 0x22, 0x03, 0x35, 0xca, 0xd7, 0x08, 0x86, 0x7d, 0x6a, 0x00, 0x8a, 0x73, 0x75, 0xf5, - 0xd3, 0x52, 0xb2, 0x85, 0x80, 0x04, 0x64, 0x13, 0x8a, 0x35, 0x62, 0x66, 0xe4, 0x93, 0x8f, 0xc0, 0x79, 0x3d, 0x8e, - 0x8e, 0x01, 0xc8, 0x60, 0xb1, 0xe9, 0xc1, 0xc4, 0xb6, 0x89, 0x28, 0xfa, 0x6c, 0xe0, 0x25, 0x00, 0x3b, 0xad, 0x42, - 0xa3, 0x1f, 0xaa, 0x14, 0x30, 0x64, 0x03, 0x37, 0xe0, 0x55, 0x58, 0x6e, 0xff, 0x25, 0xb4, 0x83, 0xc7, 0x17, 0xb2, - 0xf9, 0x26, 0xe6, 0x09, 0x56, 0xb1, 0x3b, 0xbf, 0xb2, 0xac, 0xc5, 0xb9, 0xd3, 0xe1, 0x42, 0xbd, 0xa2, 0x84, 0xa8, - 0x3d, 0xc0, 0xda, 0x97, 0x9c, 0x60, 0xc4, 0xe7, 0x37, 0x94, 0x75, 0xa8, 0xc6, 0x2d, 0xf7, 0x35, 0x5a, 0x84, 0xe9, - 0x32, 0x69, 0x0c, 0x4a, 0xd6, 0xfd, 0x64, 0xc4, 0xbd, 0x3c, 0x10, 0xb1, 0xe0, 0x0a, 0x47, 0x23, 0x6c, 0xbe, 0x80, - 0x24, 0x7d, 0xdb, 0xa7, 0x03, 0xf6, 0xcd, 0xc5, 0x5e, 0x40, 0x99, 0x8f, 0x15, 0xa9, 0x24, 0xa4, 0x34, 0xbb, 0x21, - 0x92, 0x84, 0xb5, 0x22, 0x4f, 0x9d, 0x0f, 0x1c, 0xed, 0x73, 0x2b, 0x89, 0x60, 0x04, 0x27, 0x71, 0xba, 0xf2, 0x70, - 0x51, 0x80, 0xab, 0xe8, 0x88, 0xe9, 0x9b, 0xa0, 0xfc, 0x06, 0xb9, 0xbd, 0x94, 0x5c, 0x5b, 0x68, 0x18, 0x9e, 0x21, - 0xc1, 0xaa, 0x48, 0x04, 0x3a, 0x0a, 0x80, 0xe3, 0x4a, 0xcf, 0x03, 0x4c, 0xf8, 0xda, 0xde, 0x04, 0x80, 0x44, 0x56, - 0x90, 0xb3, 0x14, 0xe8, 0x06, 0x2c, 0x57, 0xc7, 0xa9, 0x51, 0x91, 0xb8, 0xb8, 0x31, 0x5d, 0xdd, 0xd2, 0x9f, 0xa0, - 0xe5, 0x4c, 0x86, 0x98, 0x0e, 0x82, 0x80, 0x4c, 0x7d, 0xca, 0x9d, 0x9c, 0xa6, 0x13, 0xd6, 0xe7, 0xd4, 0xa9, 0x4d, - 0xdd, 0xe1, 0xd4, 0xcd, 0x93, 0xd4, 0x62, 0x75, 0xda, 0x94, 0x12, 0x31, 0x29, 0x31, 0x8f, 0x65, 0x2a, 0xb6, 0x12, - 0x77, 0x6e, 0x7d, 0xa3, 0x85, 0xb4, 0xd1, 0x8e, 0x65, 0x0e, 0xb6, 0x96, 0xf7, 0x42, 0xb4, 0xbf, 0x24, 0xc2, 0xb3, - 0x12, 0x19, 0x6b, 0x3e, 0xe3, 0x8e, 0x89, 0x60, 0xf5, 0x60, 0x2a, 0xf2, 0x0f, 0x8e, 0x4e, 0xb3, 0x37, 0xe8, 0x41, - 0xea, 0x0d, 0x24, 0x66, 0x4d, 0x7c, 0xe7, 0xd2, 0x50, 0x47, 0x08, 0x54, 0x46, 0xb5, 0x4c, 0xc7, 0x89, 0xa5, 0xe2, - 0x92, 0x7c, 0xf5, 0x5e, 0x1f, 0xe7, 0x1b, 0xdf, 0x17, 0x56, 0x23, 0x88, 0xc1, 0x5b, 0x28, 0xfa, 0x9e, 0x14, 0xe1, - 0x39, 0x2c, 0xcf, 0xf6, 0x76, 0xa7, 0xd8, 0x63, 0x55, 0x88, 0xa4, 0x82, 0x31, 0xc6, 0x8c, 0x62, 0xdc, 0x13, 0x35, - 0xb5, 0x88, 0xc4, 0x96, 0xad, 0xc3, 0x02, 0x0f, 0x00, 0xa0, 0xa5, 0x29, 0xbd, 0xcc, 0xb6, 0xea, 0x3c, 0x97, 0xf0, - 0x31, 0xf2, 0x50, 0x64, 0xe3, 0xf7, 0x6b, 0x32, 0x50, 0x10, 0xee, 0x8d, 0x96, 0x87, 0x89, 0x71, 0xb0, 0x8a, 0x42, - 0x16, 0xe8, 0x0d, 0xda, 0xa9, 0x12, 0xa1, 0xb8, 0x39, 0x59, 0x87, 0x1b, 0x4e, 0x2a, 0xd8, 0x42, 0x25, 0x2c, 0x95, - 0x16, 0xf8, 0xd5, 0x46, 0x58, 0x3c, 0x65, 0xdc, 0x7f, 0x53, 0xe1, 0x0c, 0xfa, 0x83, 0x7b, 0xcb, 0x8c, 0xfa, 0x7e, - 0xe9, 0x44, 0xa6, 0x02, 0x13, 0x37, 0xb3, 0xd4, 0x7e, 0xbf, 0xac, 0xd2, 0x7e, 0x5e, 0x2e, 0xf7, 0x39, 0x69, 0xbe, - 0xd6, 0x1d, 0x34, 0x9f, 0x0c, 0xf7, 0x2b, 0xe5, 0x87, 0x16, 0x46, 0x4d, 0xf9, 0xd5, 0x97, 0x34, 0xcc, 0x3d, 0x15, - 0xde, 0xea, 0xb6, 0x51, 0xe8, 0xa2, 0x3e, 0x07, 0x43, 0x48, 0x7f, 0x05, 0xd7, 0xd0, 0xe0, 0x41, 0x91, 0x2c, 0x16, - 0x6b, 0x17, 0xc4, 0xf5, 0x31, 0xa7, 0xda, 0xa1, 0x8c, 0x31, 0xe2, 0x69, 0xc9, 0x41, 0x92, 0xc1, 0xc1, 0xf8, 0x0d, - 0x0c, 0x88, 0x49, 0x49, 0x48, 0x87, 0xd0, 0x59, 0x99, 0x89, 0xa8, 0xdc, 0xc5, 0xdb, 0x8d, 0xcb, 0x9a, 0x42, 0x11, - 0x76, 0x82, 0x99, 0x4a, 0xa9, 0x20, 0x90, 0x26, 0xdf, 0x46, 0xab, 0x16, 0x0c, 0x05, 0xd1, 0x60, 0x28, 0x20, 0x0f, - 0xd3, 0x55, 0xc2, 0x8d, 0x8f, 0xe2, 0xe0, 0x79, 0x85, 0x1a, 0xf1, 0x52, 0x83, 0xaf, 0x61, 0xf3, 0xd7, 0x44, 0x49, - 0x11, 0x72, 0x11, 0x7b, 0x05, 0x9f, 0x08, 0xd9, 0x94, 0x87, 0x39, 0xd0, 0x0f, 0xed, 0xca, 0x4e, 0xb6, 0x97, 0x57, - 0x2e, 0x2d, 0x1a, 0x5b, 0x89, 0x9a, 0xb5, 0x38, 0x8a, 0xb7, 0xb3, 0x3e, 0x4c, 0x4d, 0x09, 0x04, 0xa4, 0xa9, 0x9c, - 0xa4, 0x9a, 0xf7, 0x28, 0xeb, 0x03, 0x48, 0xb0, 0xfb, 0x09, 0x2c, 0xf4, 0x9b, 0x12, 0x13, 0x2c, 0xaa, 0xc6, 0x6e, - 0x53, 0xd0, 0x9a, 0x53, 0xd2, 0x7c, 0x53, 0x84, 0x70, 0x5b, 0x59, 0xcf, 0x98, 0x1d, 0x60, 0xdb, 0xee, 0x76, 0x7e, - 0x94, 0x6d, 0xb7, 0xfa, 0x86, 0xe0, 0xc2, 0xe3, 0xff, 0xa4, 0xc4, 0x34, 0x90, 0x42, 0xea, 0xc6, 0x4f, 0xa8, 0xc3, - 0x3e, 0x91, 0x3a, 0x11, 0x03, 0x9a, 0xab, 0xb1, 0xe8, 0xdc, 0x6b, 0x8e, 0x92, 0xcb, 0xaa, 0xda, 0xd5, 0x12, 0x34, - 0x74, 0x23, 0x19, 0x13, 0xc5, 0x3c, 0x27, 0x00, 0x46, 0xb1, 0xf9, 0x73, 0xae, 0x93, 0xbc, 0x7f, 0x59, 0x99, 0xda, - 0xed, 0xfb, 0x7e, 0x94, 0x9f, 0xd1, 0x91, 0x8a, 0xca, 0xe6, 0x24, 0xe6, 0xdf, 0x95, 0x60, 0x1a, 0x13, 0x1f, 0xe9, - 0xb9, 0xfa, 0xa1, 0x00, 0x5f, 0xd9, 0x50, 0x6a, 0xb6, 0xd7, 0xbf, 0x75, 0xb6, 0x07, 0x72, 0x36, 0xc1, 0x02, 0x0b, - 0x74, 0x59, 0x83, 0x2f, 0x60, 0x19, 0xdc, 0x91, 0x7e, 0x0a, 0xbe, 0x9f, 0xd6, 0xc1, 0x67, 0xec, 0x7f, 0x01, 0x68, - 0x55, 0x60, 0x40, 0xf9, 0x70, 0xd1, 0xb0, 0x12, 0xe2, 0x12, 0x15, 0x66, 0x15, 0xe7, 0x8f, 0xeb, 0xbc, 0x6e, 0x5a, - 0x96, 0x18, 0x94, 0x9f, 0xba, 0x86, 0x1b, 0xdf, 0x59, 0xc8, 0x1f, 0xdf, 0x7f, 0x09, 0xba, 0x9d, 0x48, 0xbb, 0xb5, - 0x55, 0x6c, 0x90, 0x85, 0x86, 0xf7, 0xc2, 0xa6, 0xd0, 0x16, 0x2f, 0x02, 0x14, 0xea, 0x3b, 0x16, 0xe3, 0x6d, 0x11, - 0x2a, 0xc3, 0x2f, 0x58, 0x30, 0x05, 0x0c, 0xc1, 0x63, 0xa7, 0x32, 0xf9, 0x1d, 0x36, 0x9a, 0x62, 0xd7, 0x42, 0x18, - 0x7c, 0x39, 0xa8, 0x4a, 0xc9, 0x8b, 0x75, 0xb2, 0xbd, 0x38, 0x87, 0xef, 0xaf, 0xe3, 0x02, 0xa8, 0x83, 0xe8, 0x6b, - 0x2a, 0x8b, 0x0d, 0xe4, 0xe2, 0xa6, 0xac, 0xf5, 0x8a, 0x86, 0xc3, 0x1b, 0xbb, 0xf0, 0xba, 0x02, 0x1f, 0x47, 0xe9, - 0x30, 0x11, 0x93, 0x98, 0x49, 0x95, 0x2b, 0x72, 0x6d, 0x74, 0x2f, 0x6d, 0xd1, 0xbc, 0x14, 0x12, 0xbc, 0x22, 0xf0, - 0x82, 0xd0, 0x57, 0xfa, 0x72, 0xb5, 0x81, 0x82, 0x47, 0xed, 0x8b, 0x8b, 0x60, 0x62, 0xe2, 0x71, 0x43, 0x6a, 0xfa, - 0x75, 0x38, 0xb5, 0xb2, 0x58, 0x72, 0xf8, 0x75, 0xce, 0xd8, 0x82, 0x02, 0x20, 0x3e, 0x79, 0xb4, 0xde, 0x4d, 0x7a, - 0xa3, 0xb4, 0x83, 0xd2, 0x08, 0xf1, 0x5d, 0x85, 0xaf, 0x3b, 0x57, 0x7c, 0xe5, 0xaa, 0x7b, 0x5f, 0x57, 0xdc, 0xb8, - 0x60, 0xf4, 0x92, 0x4f, 0x92, 0x85, 0x6b, 0x37, 0x74, 0x57, 0xe7, 0x3b, 0xef, 0x0b, 0x99, 0xb7, 0x70, 0x05, 0x76, - 0xfe, 0x15, 0x77, 0x5e, 0x7a, 0x1f, 0x8c, 0x13, 0xe5, 0xef, 0xcd, 0x23, 0x5e, 0x39, 0xcc, 0xaa, 0x93, 0xe4, 0xef, - 0x7b, 0xdf, 0x07, 0xeb, 0x5b, 0x1a, 0x27, 0xc8, 0x6d, 0x75, 0x82, 0x4c, 0x94, 0x1b, 0xe9, 0x0d, 0xb7, 0x7f, 0x57, - 0x81, 0x20, 0x4e, 0xc5, 0xf4, 0x51, 0x39, 0xae, 0x1f, 0x2d, 0x50, 0xa9, 0x88, 0xf8, 0x5c, 0xe5, 0xae, 0xac, 0x4d, - 0x0d, 0xf5, 0x98, 0x4e, 0x66, 0xa1, 0x69, 0x56, 0xe4, 0x52, 0x2e, 0x7a, 0x8c, 0x5c, 0xb3, 0x53, 0x6d, 0x7e, 0x77, - 0xed, 0x21, 0x1d, 0xc7, 0xfb, 0x9e, 0xb5, 0x5a, 0x70, 0xbf, 0xab, 0x28, 0xbc, 0xeb, 0xc5, 0x46, 0x2a, 0x43, 0xcd, - 0x7a, 0x14, 0x7d, 0x1c, 0x77, 0x31, 0x97, 0x47, 0xd9, 0x9f, 0x35, 0x00, 0x4c, 0x47, 0x58, 0x74, 0x37, 0x3d, 0x63, - 0x4f, 0xa0, 0xa7, 0x27, 0x32, 0x48, 0xf4, 0x56, 0xe7, 0xab, 0x56, 0x89, 0xa5, 0x2b, 0x08, 0xec, 0xde, 0x90, 0xb1, - 0x2a, 0x69, 0xb7, 0x5c, 0xbf, 0x9c, 0xe7, 0xf3, 0x9c, 0x2f, 0xe5, 0xf9, 0xd4, 0x2c, 0xba, 0x8d, 0xa6, 0x7b, 0x73, - 0x6a, 0xa8, 0x98, 0x6b, 0x75, 0x93, 0xdf, 0x30, 0x5d, 0x0b, 0x43, 0x2d, 0x82, 0xcc, 0x6a, 0x57, 0xbd, 0x28, 0xcb, - 0x51, 0x3d, 0x93, 0x63, 0x24, 0x7c, 0x53, 0xe9, 0x0e, 0xd1, 0x0d, 0x53, 0x35, 0xd3, 0x77, 0x0b, 0xdb, 0x42, 0xb6, - 0x79, 0x79, 0x35, 0xcc, 0x81, 0xd2, 0x72, 0x7f, 0x99, 0x30, 0x7c, 0x77, 0x7d, 0xfd, 0x9d, 0x90, 0x53, 0x55, 0x47, - 0x6f, 0xfe, 0x5a, 0xf7, 0x0c, 0x46, 0xa5, 0x72, 0x22, 0x4e, 0xf9, 0xea, 0xc1, 0x17, 0x77, 0xaf, 0x80, 0xe5, 0x14, - 0xb0, 0x3b, 0xe5, 0xce, 0xc2, 0x50, 0xd5, 0x06, 0xfe, 0x62, 0xf5, 0x60, 0xab, 0xf6, 0xf0, 0x17, 0xbd, 0x2f, 0x82, - 0x1b, 0x1b, 0x1b, 0xdb, 0x78, 0xb7, 0x96, 0x08, 0xf2, 0x16, 0x0f, 0xf4, 0xf1, 0xea, 0xa3, 0xa0, 0xe5, 0x0a, 0xb1, - 0xcd, 0x7a, 0x0e, 0x85, 0xad, 0x41, 0xbe, 0x49, 0x99, 0x34, 0x98, 0x15, 0x3c, 0x9b, 0xc8, 0x19, 0x0a, 0x79, 0xcd, - 0xc7, 0x41, 0xdb, 0x11, 0xfe, 0x0f, 0x9c, 0xda, 0xf1, 0xf2, 0xfc, 0x13, 0xf4, 0x01, 0x4f, 0x57, 0x4a, 0x53, 0x8a, - 0x53, 0xaa, 0xa0, 0xce, 0x72, 0x9d, 0x07, 0x23, 0xc5, 0xc5, 0x18, 0x16, 0x17, 0x5c, 0x96, 0x1b, 0x67, 0x23, 0xa7, - 0xbf, 0xc4, 0xab, 0x8b, 0x74, 0xf9, 0x48, 0x64, 0xab, 0x96, 0xde, 0x2b, 0x7d, 0xba, 0x6d, 0x4f, 0x18, 0x1f, 0x67, - 0x43, 0x3a, 0x98, 0xf1, 0x71, 0x22, 0xbc, 0x3e, 0x31, 0xd4, 0x77, 0x8b, 0xc0, 0x74, 0x73, 0x6c, 0xf2, 0xc3, 0xf1, - 0x7a, 0xb3, 0x59, 0xe3, 0xf6, 0xde, 0x39, 0x9f, 0x9c, 0x79, 0x89, 0x11, 0x95, 0xb9, 0x86, 0x07, 0xb4, 0x42, 0xbc, - 0x78, 0xcf, 0x04, 0xc6, 0x65, 0x57, 0x24, 0xb5, 0xdd, 0x40, 0xe0, 0x62, 0x8f, 0x62, 0x96, 0x0c, 0x6d, 0x0f, 0xca, - 0x03, 0x7d, 0x31, 0x9a, 0x6e, 0x01, 0xd3, 0xf2, 0xda, 0xd9, 0x45, 0x6a, 0x7b, 0xd5, 0x54, 0x01, 0xcc, 0x92, 0xe5, - 0xf1, 0x19, 0xb2, 0xee, 0x57, 0xd0, 0x45, 0x0c, 0x18, 0x1b, 0x57, 0xe6, 0xdc, 0xf9, 0xaa, 0x15, 0xf1, 0x8d, 0x26, - 0xd2, 0xa4, 0x3e, 0xa2, 0xbe, 0xfd, 0xb0, 0x56, 0x57, 0x39, 0x48, 0xe0, 0x1e, 0x79, 0x77, 0xc4, 0xa5, 0xa3, 0xcf, - 0x2c, 0x36, 0xab, 0xf4, 0x2d, 0x75, 0x2d, 0x6e, 0x31, 0xec, 0x15, 0xf7, 0xc0, 0xfe, 0xc0, 0xb8, 0x45, 0x2c, 0xe2, - 0xed, 0xac, 0x96, 0xc2, 0xba, 0x30, 0x47, 0x8e, 0xb1, 0xf6, 0xe0, 0x15, 0xaf, 0xd6, 0x0c, 0xcc, 0x30, 0xe3, 0x8c, - 0xe4, 0x8d, 0x71, 0xaf, 0x6a, 0xd3, 0x91, 0xab, 0x00, 0xa2, 0x6f, 0x4e, 0x97, 0xe4, 0xf0, 0x4a, 0x96, 0xab, 0xce, - 0x90, 0x7f, 0x86, 0x75, 0xd6, 0x8b, 0x13, 0x70, 0x93, 0xa6, 0xac, 0xc4, 0xc4, 0x14, 0x71, 0xb9, 0x59, 0xc6, 0x3c, - 0x4d, 0x9f, 0x45, 0x3b, 0x38, 0x85, 0x91, 0xc0, 0x11, 0xfb, 0xc6, 0x32, 0x2c, 0x26, 0x6c, 0xc4, 0x44, 0x1a, 0x95, - 0x52, 0xc2, 0x7a, 0x72, 0xa9, 0x25, 0x7f, 0x99, 0xcb, 0xab, 0x2f, 0xb7, 0x09, 0x0e, 0x28, 0x6a, 0x60, 0x39, 0x34, - 0x8e, 0x5b, 0x06, 0x12, 0xb1, 0x18, 0x10, 0xa3, 0x56, 0xe5, 0x72, 0x32, 0xaa, 0x93, 0xfa, 0x0a, 0xb9, 0x50, 0x91, - 0x07, 0xb7, 0x04, 0x4a, 0xfe, 0x02, 0x53, 0x07, 0xd3, 0x52, 0xbb, 0x69, 0xb1, 0x49, 0xf2, 0x8e, 0x19, 0x90, 0x5c, - 0x7d, 0x0d, 0x0f, 0x8d, 0x5f, 0x86, 0x37, 0x14, 0x3d, 0x1d, 0x23, 0xe4, 0xb4, 0x34, 0xe6, 0xd2, 0x7f, 0x23, 0xcf, - 0xbe, 0x24, 0x60, 0x3f, 0x83, 0x98, 0x32, 0x70, 0x89, 0x8d, 0x0b, 0x92, 0xf2, 0x5a, 0x9e, 0xb2, 0xfb, 0x16, 0x94, - 0xef, 0x92, 0x49, 0x57, 0xa9, 0xac, 0x35, 0x56, 0xdd, 0xcf, 0x33, 0x96, 0x5f, 0x1d, 0x30, 0xcc, 0x4d, 0x46, 0x83, - 0x6c, 0xc9, 0xcc, 0xa6, 0xfc, 0x6a, 0xef, 0xc6, 0xb7, 0x3c, 0x94, 0x74, 0xa8, 0x56, 0xe9, 0xe6, 0xa5, 0x1b, 0x8e, - 0xf1, 0xc2, 0x0d, 0xc7, 0xb8, 0x43, 0xe7, 0xca, 0x15, 0xa9, 0x75, 0xfe, 0xfb, 0x52, 0xf8, 0x49, 0xec, 0xb5, 0xbe, - 0xde, 0x75, 0xfd, 0x95, 0xe9, 0xe9, 0x37, 0xa0, 0x6a, 0x64, 0x09, 0xdd, 0x84, 0x2a, 0x26, 0x23, 0x51, 0x62, 0xba, - 0x4a, 0x79, 0xd4, 0xd7, 0x88, 0x0b, 0x10, 0x37, 0x94, 0xbf, 0xf8, 0x97, 0xf0, 0xe2, 0x24, 0x40, 0x23, 0x6a, 0x3e, - 0xca, 0x52, 0xde, 0x18, 0x45, 0x93, 0x38, 0xb9, 0x0a, 0x66, 0x71, 0x63, 0x92, 0xa5, 0x59, 0x31, 0x05, 0xae, 0xf4, - 0x8a, 0x2b, 0xb0, 0xe1, 0x27, 0x8d, 0x59, 0xec, 0xbd, 0x64, 0xc9, 0x39, 0xe3, 0xf1, 0x20, 0xf2, 0xec, 0xfd, 0x1c, - 0xc4, 0x83, 0xf5, 0x36, 0xca, 0xf3, 0xec, 0xc2, 0xf6, 0x3e, 0x64, 0xa7, 0xc0, 0xb4, 0xde, 0xbb, 0xcb, 0xab, 0x33, - 0x96, 0x7a, 0x1f, 0x4f, 0x67, 0x29, 0x9f, 0x79, 0x45, 0x94, 0x16, 0x8d, 0x82, 0xe5, 0xf1, 0x08, 0xd4, 0x44, 0x92, - 0xe5, 0x0d, 0xcc, 0x7f, 0x9e, 0xb0, 0x20, 0x89, 0xcf, 0xc6, 0xdc, 0x1a, 0x46, 0xf9, 0xa7, 0x4e, 0xa3, 0x31, 0xcd, - 0xe3, 0x49, 0x94, 0x5f, 0x35, 0xa8, 0x45, 0x70, 0xaf, 0xb9, 0x1b, 0x7d, 0x36, 0x7a, 0xd0, 0xe1, 0x39, 0xf4, 0x8d, - 0x91, 0x8a, 0x01, 0x08, 0x1f, 0x6b, 0xf7, 0x61, 0x73, 0x52, 0x6c, 0x88, 0x13, 0xa5, 0x28, 0xe5, 0xe5, 0x89, 0x77, - 0x01, 0xb6, 0xed, 0x89, 0x7f, 0xca, 0x53, 0x0f, 0x7c, 0x39, 0x9e, 0xa5, 0xf3, 0xc1, 0x2c, 0x2f, 0x60, 0x80, 0x69, - 0x16, 0xa7, 0x9c, 0xe5, 0x9d, 0xd3, 0x2c, 0x07, 0xb2, 0x35, 0xf2, 0x68, 0x18, 0xcf, 0x8a, 0xe0, 0xc1, 0xf4, 0xb2, - 0x83, 0xb6, 0xc2, 0x59, 0x9e, 0xcd, 0xd2, 0xa1, 0x9c, 0x2b, 0x4e, 0x61, 0x63, 0xc4, 0xdc, 0xac, 0xa0, 0x37, 0xa1, - 0x00, 0x7c, 0x29, 0x8b, 0xf2, 0xc6, 0x19, 0x76, 0x46, 0x43, 0xbf, 0x39, 0x64, 0x67, 0x5e, 0x7e, 0x76, 0x1a, 0x39, - 0xad, 0xf6, 0x63, 0x4f, 0xfd, 0xf9, 0x0f, 0x5d, 0x30, 0xdc, 0x57, 0x16, 0xb7, 0x9a, 0xcd, 0xbf, 0x71, 0x3b, 0x0b, - 0xb3, 0x10, 0x40, 0x41, 0x6b, 0x7a, 0x69, 0x15, 0x59, 0x02, 0xeb, 0xb3, 0xaa, 0x67, 0x67, 0x0a, 0x7e, 0x53, 0x9c, - 0x9e, 0x05, 0xed, 0xe9, 0x65, 0x89, 0xd8, 0x05, 0x22, 0x21, 0x53, 0x22, 0x29, 0x9f, 0xe6, 0xbf, 0x15, 0xe2, 0x27, - 0xab, 0x21, 0x6e, 0x2b, 0x88, 0x2b, 0xaa, 0x37, 0x86, 0xb0, 0x0f, 0x88, 0xfc, 0xad, 0x42, 0x00, 0x32, 0x06, 0x27, - 0x30, 0x57, 0x70, 0xd0, 0xc3, 0x6f, 0x06, 0xa3, 0xbd, 0x1a, 0x8c, 0x27, 0xb7, 0x81, 0x91, 0xa7, 0xc3, 0x79, 0x7d, - 0x5d, 0x5b, 0xe0, 0x9c, 0x76, 0xc6, 0x0c, 0xf9, 0x29, 0x68, 0xe3, 0xf7, 0x8b, 0x78, 0xc8, 0xc7, 0xe2, 0x2b, 0xb1, - 0xf3, 0x85, 0xa8, 0x7b, 0xd8, 0x6c, 0x8a, 0xe7, 0x02, 0x14, 0x5a, 0xd0, 0xf2, 0xb1, 0x01, 0x30, 0xd1, 0xe7, 0xeb, - 0x5e, 0x62, 0xf3, 0xed, 0xad, 0x6f, 0xaa, 0xf1, 0xb8, 0xca, 0x1b, 0x14, 0x2a, 0x42, 0xbd, 0xb3, 0x05, 0x33, 0xde, - 0x8a, 0x6e, 0x4b, 0x1f, 0x54, 0xf5, 0xbe, 0xe5, 0xa4, 0xf5, 0x02, 0xe6, 0x99, 0xb9, 0x40, 0x9d, 0xac, 0x8b, 0x21, - 0xa9, 0x46, 0xc3, 0x05, 0xbd, 0xc1, 0x31, 0x84, 0x44, 0x07, 0x82, 0x4e, 0xd1, 0xcb, 0xe9, 0x9d, 0x1a, 0xa9, 0x1b, - 0xe4, 0x4e, 0xea, 0xc2, 0x96, 0x4f, 0xb5, 0x5c, 0x2f, 0xb6, 0xb6, 0xc0, 0xcb, 0xfe, 0x9c, 0xcb, 0x06, 0x20, 0xbd, - 0x2b, 0x49, 0x6b, 0xbc, 0x87, 0x44, 0xb9, 0x7c, 0xd9, 0x80, 0x28, 0x07, 0xbe, 0x3e, 0x1f, 0xa3, 0xdf, 0xad, 0xaf, - 0xae, 0x1b, 0x29, 0x35, 0x3b, 0xb6, 0xdb, 0xe3, 0x3a, 0x2b, 0x0b, 0xb3, 0xcf, 0x78, 0x89, 0xa3, 0x7c, 0xc9, 0x43, - 0x1c, 0xd1, 0x7b, 0x15, 0x0a, 0x37, 0x4d, 0x39, 0x69, 0xa3, 0xbb, 0x3a, 0x69, 0xf0, 0x35, 0xa6, 0xcc, 0x67, 0x15, - 0x27, 0x07, 0x37, 0xe6, 0x78, 0x20, 0xae, 0x20, 0x16, 0x55, 0x96, 0x7d, 0x44, 0xd0, 0x0b, 0xbf, 0x0b, 0x94, 0x14, - 0x46, 0x2e, 0xbf, 0xe2, 0xbf, 0xc3, 0xe3, 0x70, 0x34, 0xfa, 0x45, 0x36, 0xcb, 0x07, 0x78, 0x39, 0x60, 0x45, 0x28, - 0xc2, 0x26, 0x4b, 0xc0, 0xf6, 0xb8, 0x56, 0x40, 0x0c, 0xf3, 0x2c, 0xcc, 0xb7, 0x2f, 0x30, 0x3a, 0x9d, 0x11, 0x97, - 0x1f, 0x64, 0xf8, 0x45, 0xa1, 0x84, 0x3a, 0x75, 0x48, 0x89, 0x78, 0x74, 0x31, 0xd4, 0x9f, 0xa5, 0x31, 0x88, 0xe0, - 0xe3, 0x78, 0x48, 0x17, 0x62, 0xe2, 0x21, 0x9d, 0x90, 0x34, 0x28, 0x23, 0x0a, 0x43, 0xee, 0x50, 0x20, 0x17, 0x06, - 0xbf, 0xcb, 0x0c, 0x1b, 0xbb, 0x61, 0xe3, 0x29, 0x87, 0xa1, 0xc3, 0x87, 0xd9, 0x24, 0x8a, 0xd3, 0x00, 0x5f, 0x5c, - 0xe2, 0xe9, 0x11, 0x03, 0xec, 0xe2, 0xc1, 0xa7, 0x5a, 0xa3, 0x96, 0xeb, 0xff, 0x04, 0x02, 0x8e, 0xfa, 0x63, 0x32, - 0x0b, 0x91, 0x55, 0x10, 0x31, 0x54, 0x64, 0xde, 0x57, 0x7a, 0xde, 0x33, 0xab, 0x55, 0xcc, 0xb4, 0xbe, 0x0e, 0xcd, - 0x85, 0xe5, 0xd2, 0x67, 0xd8, 0xf5, 0x52, 0x10, 0xac, 0x5c, 0xe7, 0xd1, 0x53, 0x10, 0x67, 0x8f, 0xd1, 0x47, 0xaf, - 0xd1, 0x0a, 0x5a, 0xda, 0x2f, 0xaf, 0x5d, 0xb5, 0x15, 0x89, 0x3a, 0xf2, 0xba, 0x26, 0xe1, 0xa1, 0xbf, 0x0b, 0x5c, - 0xab, 0x67, 0x8d, 0xaf, 0x27, 0x37, 0x1d, 0x46, 0xa7, 0xce, 0x52, 0xa7, 0x06, 0x04, 0x1d, 0x74, 0xac, 0x99, 0xca, - 0x2d, 0x2b, 0xbc, 0xb5, 0xf1, 0x67, 0x0b, 0xcd, 0x89, 0xaf, 0x1e, 0x90, 0x33, 0xd2, 0x2b, 0x9e, 0x56, 0xf0, 0x5d, - 0x29, 0x09, 0xb2, 0x78, 0x21, 0x7f, 0xa1, 0x99, 0x00, 0xe5, 0x4a, 0x1f, 0x64, 0x2f, 0xd4, 0x8a, 0x47, 0x26, 0x22, - 0xde, 0xab, 0x9b, 0x50, 0xd6, 0xd8, 0x32, 0x5c, 0xe8, 0x8b, 0x16, 0x5c, 0xc1, 0x8f, 0x06, 0xd3, 0x88, 0xe1, 0xbd, - 0x94, 0x93, 0xcd, 0xf9, 0x97, 0xbc, 0xdc, 0xd9, 0x9c, 0xab, 0x86, 0xe2, 0x7b, 0x3c, 0xc4, 0x4f, 0x06, 0xf2, 0x6b, - 0x2e, 0xac, 0xc7, 0xc0, 0x7e, 0xff, 0xee, 0xe0, 0xd0, 0xf6, 0x4e, 0xb3, 0xe1, 0x55, 0x60, 0xc3, 0xee, 0x64, 0x76, - 0xe9, 0xfa, 0x7c, 0xcc, 0x52, 0x47, 0xb1, 0x78, 0x96, 0x30, 0x90, 0x08, 0x67, 0xe2, 0xb2, 0xe3, 0xa2, 0xe7, 0x3b, - 0x3c, 0xd9, 0xa3, 0xb7, 0x21, 0x75, 0xf7, 0xb8, 0x78, 0x51, 0x18, 0xcf, 0xf1, 0x6b, 0x17, 0x63, 0xff, 0x7b, 0x3b, - 0xf0, 0x05, 0x1f, 0x0e, 0x70, 0xcf, 0xd0, 0xd3, 0xe6, 0x7c, 0x89, 0x93, 0x7a, 0x38, 0xc4, 0xb8, 0x2b, 0x50, 0x28, - 0xa8, 0xd5, 0x49, 0x30, 0x3c, 0x39, 0x29, 0xe1, 0x2b, 0x8c, 0xb5, 0xa3, 0xc6, 0x45, 0x08, 0x55, 0x7f, 0xcd, 0x5d, - 0xf2, 0x75, 0x3b, 0x38, 0x04, 0xce, 0x3b, 0xc4, 0x06, 0xc4, 0x5d, 0xd8, 0x7b, 0xa8, 0x4b, 0x68, 0xd3, 0x8a, 0xa2, - 0x75, 0x10, 0x88, 0x86, 0x15, 0xd3, 0x8b, 0x10, 0x61, 0xb5, 0xba, 0x0a, 0xa4, 0xa1, 0x09, 0xdd, 0x89, 0x8b, 0x9f, - 0x04, 0x19, 0x7c, 0x12, 0x1d, 0x4e, 0xcc, 0x37, 0x84, 0x88, 0xcb, 0xfc, 0x9a, 0x5a, 0x47, 0x7f, 0x01, 0xdb, 0xc3, - 0xbb, 0x38, 0xa1, 0x96, 0x4a, 0x1d, 0xa1, 0x9d, 0x84, 0x6a, 0xbb, 0xa9, 0xec, 0x0e, 0xd0, 0xfd, 0x49, 0x34, 0x2d, - 0x58, 0xa0, 0xbe, 0x48, 0xcd, 0x84, 0x0a, 0x6e, 0xd9, 0x14, 0x90, 0x79, 0x31, 0xcf, 0xd0, 0x60, 0x58, 0xb6, 0x53, - 0x40, 0xf4, 0x39, 0x8d, 0xc6, 0xa0, 0x71, 0x7a, 0xe6, 0x96, 0x7c, 0x3c, 0x37, 0xf5, 0xda, 0x23, 0xd0, 0x6b, 0x98, - 0x93, 0xd7, 0x00, 0x4f, 0xed, 0x2c, 0x0d, 0x12, 0x36, 0xe2, 0x25, 0xc7, 0x4b, 0x5f, 0x73, 0x65, 0x48, 0xf8, 0xed, - 0x87, 0xa0, 0xeb, 0x2c, 0x1f, 0xff, 0xbd, 0x79, 0x62, 0xe8, 0x18, 0xa4, 0xa0, 0x9b, 0x28, 0x0b, 0x14, 0x33, 0xec, - 0x01, 0x5c, 0xf3, 0x79, 0x6e, 0x4c, 0x34, 0x60, 0x68, 0x64, 0x95, 0x1c, 0x64, 0xf2, 0xd8, 0xe3, 0xb9, 0xd9, 0x2e, - 0x75, 0xe7, 0x4b, 0x18, 0x2c, 0xeb, 0xfa, 0x5d, 0xb7, 0x2c, 0xc8, 0x64, 0x5d, 0x6e, 0xac, 0x0c, 0xa6, 0xfa, 0xd3, - 0x12, 0xf9, 0x0c, 0xd3, 0xae, 0x14, 0xc1, 0xd2, 0xb9, 0xe8, 0x71, 0x17, 0x62, 0xd6, 0x8c, 0x4e, 0xcf, 0xec, 0xe1, - 0x96, 0x71, 0x3a, 0x9d, 0xf1, 0x23, 0x0a, 0xd4, 0xe6, 0x78, 0x9d, 0xa0, 0x3f, 0x17, 0x73, 0x83, 0x17, 0x3c, 0x70, - 0x10, 0x00, 0xab, 0x61, 0x3d, 0x01, 0x6a, 0xba, 0xca, 0xf0, 0xf0, 0x1f, 0x23, 0x71, 0x4b, 0x9f, 0x5a, 0xaf, 0xa0, - 0xd2, 0x09, 0x58, 0xdd, 0x1d, 0xce, 0x9d, 0xa3, 0x37, 0x8e, 0xdb, 0xf7, 0x5e, 0x19, 0x2f, 0x2f, 0xb1, 0xd5, 0x1e, - 0xb0, 0x3d, 0xa4, 0xf7, 0xca, 0x26, 0x26, 0x93, 0x53, 0xb3, 0x57, 0x21, 0x36, 0x7c, 0xeb, 0xd8, 0xac, 0x98, 0x36, - 0x84, 0x48, 0x6a, 0x10, 0x33, 0xda, 0xd8, 0x55, 0x05, 0x56, 0xbf, 0xe2, 0x73, 0x92, 0x36, 0x5c, 0xbf, 0x29, 0xe4, - 0x88, 0xf7, 0xcd, 0x5b, 0x2d, 0xb5, 0x80, 0x3a, 0xd4, 0xb9, 0x86, 0xe4, 0x83, 0x47, 0xf9, 0xd6, 0x1b, 0x25, 0x37, - 0x4e, 0xf6, 0xeb, 0x92, 0x0c, 0xf6, 0x59, 0xa9, 0xdf, 0xa8, 0x06, 0x5a, 0x18, 0xe7, 0x87, 0x8d, 0x24, 0xf7, 0xdd, - 0x53, 0xb2, 0x12, 0x55, 0x1c, 0x9c, 0xae, 0x2c, 0xaa, 0x13, 0x0d, 0xa1, 0x50, 0x63, 0x3c, 0x77, 0xad, 0x25, 0xdd, - 0x76, 0x2a, 0x59, 0x24, 0x6c, 0x4c, 0x8b, 0xf0, 0x08, 0x6d, 0x30, 0xfa, 0x6c, 0xeb, 0xcf, 0x03, 0x50, 0x7f, 0x9f, - 0x42, 0x7b, 0x73, 0xee, 0xb8, 0xab, 0xef, 0xcd, 0x29, 0xcf, 0x50, 0x49, 0x61, 0x23, 0x63, 0xb1, 0x26, 0x5c, 0xd1, - 0x41, 0xb5, 0xbb, 0x28, 0x3e, 0xf7, 0x76, 0xc4, 0x44, 0xb0, 0xdb, 0x8f, 0xe5, 0x8b, 0x9e, 0xb8, 0x29, 0x12, 0x91, - 0xbc, 0xa2, 0xdc, 0x22, 0x36, 0x09, 0xed, 0x5b, 0x79, 0xc7, 0xb6, 0x84, 0x94, 0x42, 0x40, 0x95, 0xc0, 0x02, 0xe0, - 0x75, 0x19, 0x93, 0xb0, 0xc7, 0x92, 0x0c, 0x36, 0xce, 0x05, 0x8a, 0x00, 0x03, 0x47, 0x3c, 0x8a, 0x13, 0xd1, 0x45, - 0x06, 0xf6, 0x94, 0x03, 0xa8, 0x31, 0xc2, 0x23, 0xf5, 0x3a, 0x2e, 0x75, 0x12, 0x12, 0x66, 0x7b, 0x3b, 0x15, 0xdc, - 0x84, 0x19, 0xed, 0x32, 0xf3, 0x00, 0xab, 0xc2, 0x50, 0xd4, 0x01, 0x71, 0xe9, 0xda, 0x0c, 0x02, 0x58, 0xa8, 0x60, - 0x87, 0x97, 0xaa, 0x2b, 0x2c, 0x02, 0x96, 0x1c, 0x13, 0x85, 0xc1, 0xc8, 0x63, 0x5c, 0x13, 0x36, 0x17, 0xd9, 0x8f, - 0x0a, 0xda, 0x74, 0x09, 0xda, 0xb4, 0x0e, 0xed, 0x09, 0x12, 0xbd, 0xb7, 0x39, 0x8f, 0xcb, 0x10, 0xbe, 0xa5, 0x83, - 0x6c, 0xc8, 0x3e, 0x7e, 0x78, 0x85, 0x77, 0x00, 0xa1, 0x3d, 0x38, 0x0b, 0x99, 0x5b, 0x9e, 0xc8, 0xc5, 0x31, 0x75, - 0x82, 0xd8, 0xdb, 0x16, 0xcd, 0x45, 0x74, 0x05, 0x8a, 0xf6, 0x04, 0xe4, 0x6c, 0x48, 0x05, 0x61, 0x98, 0x53, 0x2f, - 0x0e, 0x4b, 0x2a, 0x5a, 0x0b, 0x99, 0x2e, 0x1a, 0x21, 0x11, 0x68, 0x67, 0x56, 0x34, 0xc0, 0x9c, 0x59, 0x93, 0x0e, - 0xc3, 0xf8, 0x5c, 0x73, 0x1b, 0x5d, 0x20, 0xea, 0xee, 0x01, 0x43, 0xb3, 0x04, 0xc6, 0xcc, 0xaf, 0xaf, 0x9b, 0x30, - 0x94, 0x78, 0xb4, 0xf6, 0x48, 0x36, 0x88, 0x77, 0x61, 0xc2, 0xcc, 0x2d, 0x4c, 0x4f, 0xc2, 0xab, 0x7a, 0x3d, 0x95, - 0x6f, 0x13, 0xc8, 0x01, 0x00, 0x46, 0x3a, 0xea, 0x27, 0x3e, 0xd0, 0xe6, 0x0d, 0x94, 0xc6, 0xc3, 0xe5, 0x32, 0xb0, - 0x4a, 0xa7, 0x58, 0x9a, 0x5d, 0x5f, 0xb7, 0xe0, 0x71, 0x12, 0xa7, 0xf8, 0x04, 0x33, 0xd3, 0x0d, 0x38, 0x78, 0x04, - 0xd3, 0x1c, 0xd8, 0x16, 0x6a, 0xa2, 0x4b, 0xac, 0x49, 0x55, 0x4d, 0x74, 0x09, 0xf2, 0x48, 0x54, 0x69, 0xf2, 0x14, - 0xc8, 0x70, 0xff, 0x1f, 0x16, 0x34, 0x93, 0x8b, 0x67, 0x69, 0xd2, 0x01, 0x98, 0x20, 0x2d, 0x35, 0xf1, 0xf6, 0x76, - 0x80, 0xcc, 0xb0, 0x18, 0xd2, 0xfa, 0x91, 0x3b, 0xae, 0x7a, 0x8f, 0x91, 0x90, 0x64, 0x6e, 0x2d, 0x0d, 0x81, 0x8a, - 0xd0, 0x1a, 0x04, 0xdf, 0x62, 0x78, 0x4c, 0x9b, 0x03, 0xf4, 0xbc, 0xd4, 0xfe, 0x0b, 0xb2, 0xa6, 0xea, 0xe0, 0xd9, - 0x7f, 0xfd, 0xc7, 0xbf, 0xb3, 0x3d, 0xb1, 0xb9, 0xb2, 0xd1, 0x08, 0x4c, 0x65, 0xeb, 0x0e, 0x7d, 0xfe, 0xd7, 0xdf, - 0xff, 0xdf, 0xff, 0xf3, 0x5f, 0x75, 0xb7, 0x14, 0x7a, 0x9d, 0xc8, 0x83, 0x3f, 0x25, 0x1d, 0x0c, 0x30, 0x15, 0x1a, - 0xa3, 0x28, 0x5d, 0x87, 0xc3, 0x91, 0x89, 0x43, 0x31, 0x65, 0x6c, 0xe8, 0xd9, 0x96, 0xed, 0x2d, 0x95, 0x1e, 0x27, - 0xec, 0x9c, 0xc9, 0xb7, 0x9e, 0xad, 0x9a, 0x6a, 0x45, 0x8f, 0x01, 0x28, 0x34, 0x2e, 0xcf, 0x3f, 0x25, 0x6f, 0x9b, - 0xa8, 0x48, 0xa9, 0x52, 0xeb, 0x87, 0xb4, 0xab, 0x8b, 0x0b, 0xcf, 0x36, 0xa6, 0x5f, 0x0b, 0x57, 0x6f, 0x4d, 0x79, - 0xd0, 0xf4, 0x9a, 0xeb, 0x20, 0xf3, 0xc0, 0x8f, 0xb4, 0xed, 0xbe, 0xa2, 0x11, 0x85, 0x7b, 0xcc, 0x0b, 0xec, 0xeb, - 0x68, 0x75, 0x2b, 0xf6, 0xa7, 0x39, 0x0e, 0x95, 0xb2, 0xa2, 0xb8, 0x05, 0x79, 0x58, 0x3e, 0xcf, 0xae, 0x5a, 0xdb, - 0x6b, 0x46, 0x01, 0x14, 0xda, 0x0f, 0x1f, 0x0a, 0x70, 0x3d, 0x47, 0xbb, 0x90, 0x66, 0x63, 0x36, 0x1a, 0x81, 0x10, - 0x29, 0xdc, 0x2a, 0x1f, 0x74, 0x14, 0x27, 0x1c, 0xcf, 0xb3, 0xc3, 0xae, 0xfd, 0x16, 0x36, 0x06, 0x5e, 0x0f, 0x75, - 0xa5, 0x5f, 0xaf, 0x32, 0xfd, 0x94, 0xd0, 0x5d, 0x0d, 0x97, 0x18, 0xb2, 0x0e, 0x93, 0x9c, 0xe6, 0xfa, 0x5a, 0xf9, - 0xcb, 0xb5, 0xf2, 0x3a, 0x39, 0x33, 0x72, 0x88, 0x57, 0xef, 0x9b, 0xbb, 0xec, 0x8e, 0x7f, 0xfd, 0xa7, 0xbf, 0xff, - 0x6f, 0x00, 0x06, 0x8e, 0x73, 0xb7, 0xad, 0x01, 0x1d, 0xfe, 0x27, 0x74, 0x98, 0xa5, 0x77, 0xef, 0xf2, 0xd7, 0xff, - 0xf2, 0xdf, 0xa1, 0x07, 0x5d, 0x60, 0x86, 0x7d, 0xa4, 0x40, 0x1f, 0x60, 0xd8, 0xe8, 0x77, 0xc1, 0x5e, 0x1b, 0xf7, - 0x2e, 0x70, 0xfc, 0x03, 0xa2, 0x5a, 0xf0, 0x6c, 0x7a, 0x57, 0xb8, 0x11, 0xd3, 0x41, 0x92, 0x15, 0xcc, 0x04, 0x5c, - 0x58, 0x0a, 0xbf, 0x0f, 0x72, 0x82, 0x64, 0x0a, 0x12, 0xb4, 0xb0, 0xcc, 0xa1, 0x25, 0xaf, 0xdc, 0x28, 0x08, 0x57, - 0x32, 0x54, 0xc1, 0x38, 0x91, 0x82, 0xac, 0xb9, 0x1a, 0xd3, 0x88, 0xb2, 0x25, 0x5e, 0x22, 0xe9, 0xae, 0x25, 0x97, - 0xd0, 0x58, 0xb7, 0xcc, 0xbb, 0x62, 0x7f, 0x89, 0x69, 0xc5, 0x99, 0xd7, 0xf2, 0xf0, 0xb5, 0x12, 0x50, 0x5d, 0xc7, - 0x2b, 0x4a, 0xa3, 0xcb, 0x15, 0xa5, 0xa8, 0x04, 0x35, 0x6c, 0x60, 0xed, 0x4d, 0xc4, 0x4b, 0x2f, 0xf4, 0xeb, 0x2e, - 0x6a, 0xd0, 0x91, 0x2a, 0xc3, 0x53, 0xfc, 0xfa, 0x2b, 0x00, 0xe4, 0x50, 0x42, 0xad, 0x1d, 0xe3, 0xbd, 0x1a, 0xbc, - 0x45, 0x3d, 0xcb, 0x19, 0xec, 0x99, 0x0b, 0xf3, 0x68, 0xfe, 0xe6, 0xc6, 0x63, 0x10, 0x0f, 0x3d, 0xb0, 0x27, 0xf5, - 0xaa, 0xde, 0x38, 0x6e, 0xf9, 0x2f, 0xff, 0xec, 0xfb, 0xff, 0xf2, 0xcf, 0xb7, 0x36, 0xc5, 0x51, 0xc1, 0x65, 0xe7, - 0xd5, 0xb0, 0xeb, 0xa9, 0xbb, 0x7a, 0xa6, 0x3a, 0xb9, 0x57, 0xb7, 0x59, 0xa2, 0x3f, 0xd6, 0x2f, 0x91, 0x7f, 0xa9, - 0x50, 0x50, 0xdf, 0xfa, 0x2d, 0x80, 0x21, 0x5e, 0xb7, 0x42, 0x86, 0x8d, 0x7e, 0x17, 0x68, 0x27, 0x6e, 0x70, 0xa7, - 0x15, 0xf9, 0xed, 0x14, 0xbe, 0x0d, 0x87, 0xdf, 0x09, 0xbe, 0x48, 0x07, 0x06, 0xd0, 0x4e, 0xd4, 0x8d, 0xa9, 0x5a, - 0x57, 0xbc, 0x74, 0xd9, 0x5b, 0x2a, 0x91, 0x6a, 0x25, 0x68, 0xba, 0xdd, 0xe6, 0xd6, 0x96, 0x83, 0xdd, 0xdf, 0xe0, - 0x9b, 0x21, 0xf6, 0x4e, 0x73, 0x15, 0x03, 0xb9, 0x41, 0x34, 0xe0, 0x10, 0x75, 0xac, 0x68, 0xd0, 0x25, 0xb9, 0x80, - 0xa5, 0x98, 0x61, 0x8a, 0x60, 0x7a, 0x60, 0x0e, 0x0b, 0x7b, 0xed, 0x99, 0x70, 0x6c, 0x82, 0x45, 0xd6, 0x96, 0x0e, - 0x4f, 0x8d, 0xe8, 0x9e, 0x75, 0x48, 0xf4, 0xa2, 0xc6, 0xac, 0xb2, 0x97, 0xc9, 0x4b, 0x44, 0x03, 0xf1, 0x44, 0xbc, - 0x2b, 0xe3, 0xeb, 0x75, 0xf1, 0xf6, 0xef, 0x6f, 0x8f, 0xb7, 0xc7, 0x77, 0x8c, 0xb7, 0x7f, 0xff, 0x07, 0xc7, 0xdb, - 0xbf, 0x36, 0xe3, 0xed, 0xb8, 0x88, 0x3f, 0xdf, 0x29, 0x26, 0xae, 0x22, 0x95, 0xd9, 0x45, 0x11, 0xb6, 0xa4, 0xa5, - 0x04, 0x8e, 0x34, 0x06, 0xc4, 0xff, 0xed, 0xe3, 0xdb, 0x30, 0xd1, 0x42, 0x74, 0x9b, 0xc2, 0xd9, 0x92, 0x07, 0x99, - 0x0a, 0x26, 0x37, 0x75, 0xee, 0x77, 0xe3, 0x81, 0xba, 0xec, 0x0a, 0x2e, 0x8c, 0xab, 0x0f, 0x04, 0xda, 0x2a, 0xdc, - 0x1c, 0xd0, 0xdb, 0xaa, 0x75, 0xc7, 0xf6, 0xb6, 0x4a, 0x3a, 0x36, 0x47, 0xe8, 0xa8, 0xb3, 0x64, 0x71, 0x53, 0x72, - 0x6e, 0xff, 0xa7, 0xa3, 0x56, 0x67, 0xb7, 0x35, 0x81, 0xde, 0xc0, 0x87, 0xf0, 0xd4, 0xec, 0xec, 0xee, 0xe2, 0xd3, - 0x85, 0x7a, 0x6a, 0xe3, 0x53, 0xac, 0x9e, 0x1e, 0xe2, 0xd3, 0x40, 0x3d, 0x3d, 0xc2, 0xa7, 0xa1, 0x7a, 0x7a, 0x8c, - 0x4f, 0xe7, 0x76, 0x79, 0xc4, 0x34, 0x70, 0x8f, 0xdd, 0xbe, 0x27, 0x4c, 0x51, 0x55, 0xf6, 0xd8, 0x6b, 0x61, 0x40, - 0x3b, 0x3a, 0x0b, 0x62, 0x4f, 0x38, 0xd4, 0x41, 0xe1, 0x5d, 0x8c, 0x59, 0x1a, 0x50, 0x4e, 0xf4, 0x73, 0x7c, 0x5b, - 0x10, 0xd8, 0xc0, 0x87, 0xf1, 0x84, 0xa9, 0xd7, 0xa6, 0x2b, 0xac, 0x41, 0x25, 0x1f, 0x35, 0xfb, 0x65, 0x47, 0xaf, - 0x93, 0x88, 0x84, 0xab, 0xf4, 0x4e, 0x5a, 0xb9, 0xaa, 0x4e, 0x4c, 0xd7, 0xd0, 0x2b, 0xbc, 0x26, 0xa8, 0x6a, 0xf8, - 0x95, 0x23, 0x90, 0xcd, 0x8d, 0x4b, 0x70, 0x2c, 0x57, 0x06, 0x5a, 0x11, 0x22, 0x1d, 0x68, 0x25, 0x9c, 0xf4, 0xd3, - 0x61, 0x74, 0xa6, 0xbf, 0xbf, 0x01, 0xdb, 0x21, 0x3a, 0x93, 0x2d, 0xd7, 0x07, 0x56, 0x09, 0x44, 0x33, 0xa8, 0xaa, - 0x80, 0x40, 0xc7, 0x13, 0x97, 0x06, 0xc3, 0x04, 0x32, 0x56, 0x8a, 0xd4, 0xa9, 0x87, 0x59, 0x69, 0xfa, 0x7a, 0x11, - 0x50, 0xb4, 0x2a, 0xd8, 0x03, 0x13, 0x86, 0x4a, 0x05, 0x85, 0xa1, 0x02, 0x0b, 0x44, 0xf5, 0x9a, 0x70, 0xaa, 0x72, - 0xfd, 0xd6, 0x07, 0x55, 0x2d, 0x15, 0x4f, 0x35, 0xcf, 0xa0, 0xf5, 0x01, 0xf4, 0x72, 0x14, 0xef, 0x5e, 0x6b, 0x80, - 0xff, 0xc9, 0x18, 0xe1, 0xbd, 0xd1, 0x68, 0x74, 0x63, 0x7c, 0xf5, 0xde, 0x70, 0xc4, 0xda, 0xec, 0x61, 0x07, 0xcf, - 0x27, 0x1b, 0x32, 0x6a, 0xd7, 0x2a, 0x89, 0x76, 0xf3, 0xbb, 0x35, 0xc6, 0x00, 0x1f, 0x1f, 0xcf, 0xef, 0x1e, 0x6b, - 0x2d, 0x81, 0x2a, 0xf3, 0x09, 0x48, 0xc5, 0x38, 0x0d, 0x9a, 0xa5, 0x7f, 0x2e, 0x83, 0x93, 0xf7, 0x9e, 0x3c, 0x79, - 0x52, 0xfa, 0x43, 0xf5, 0xd4, 0x1c, 0x0e, 0x4b, 0x7f, 0x30, 0xd7, 0x68, 0x34, 0x9b, 0xa3, 0x51, 0xe9, 0xc7, 0xaa, - 0x60, 0xb7, 0x3d, 0x18, 0xee, 0xb6, 0x4b, 0xff, 0xc2, 0x68, 0x51, 0xfa, 0x4c, 0x3e, 0xe5, 0x6c, 0x58, 0x3b, 0xe4, - 0x7c, 0x0c, 0xde, 0xb6, 0x2f, 0x18, 0x6d, 0x8e, 0x86, 0xb6, 0xf8, 0x1a, 0x44, 0x33, 0x9e, 0xa1, 0x00, 0xee, 0x00, - 0x9f, 0x1f, 0x6d, 0xca, 0x6b, 0xcc, 0xe2, 0xad, 0xe4, 0x25, 0x6c, 0xa1, 0x9f, 0xcd, 0x60, 0x23, 0x32, 0x33, 0x05, - 0x19, 0x63, 0x15, 0x8b, 0xac, 0x55, 0x23, 0x67, 0x51, 0xf5, 0xcf, 0x61, 0x5c, 0xc5, 0x20, 0x51, 0xda, 0x60, 0x4b, - 0x91, 0x8c, 0xf3, 0xdd, 0x3a, 0x19, 0xff, 0xc5, 0xed, 0x32, 0xfe, 0xea, 0x6e, 0x22, 0xfe, 0x8b, 0x3f, 0x58, 0xc4, - 0x7f, 0x67, 0x8a, 0x78, 0x21, 0xc4, 0xf6, 0x79, 0x68, 0x0f, 0xc6, 0x6c, 0xf0, 0xe9, 0x34, 0xbb, 0x6c, 0xe0, 0x96, - 0xc8, 0x6d, 0x92, 0x9e, 0x93, 0xdf, 0x7a, 0x20, 0xaa, 0x06, 0x33, 0x5e, 0x71, 0x4e, 0x4a, 0xf2, 0x5d, 0x1a, 0xda, - 0xef, 0x94, 0xfd, 0x2e, 0x4a, 0x46, 0x23, 0x28, 0x1a, 0x8d, 0x6c, 0x75, 0x79, 0x03, 0xc4, 0x16, 0xb5, 0x7a, 0x5b, - 0x2b, 0xa1, 0x56, 0x9f, 0x7f, 0x6e, 0x96, 0x99, 0x05, 0x32, 0x64, 0x69, 0x86, 0x27, 0x65, 0xcd, 0x30, 0x2e, 0x70, - 0xab, 0xe1, 0x9b, 0xd7, 0x97, 0x5e, 0x69, 0x25, 0x02, 0xab, 0xcb, 0x00, 0x57, 0xf1, 0x55, 0xe3, 0xed, 0xa9, 0x55, - 0x84, 0x15, 0x16, 0x54, 0x66, 0xd6, 0x3d, 0xbd, 0x7a, 0x35, 0x74, 0xf6, 0xb9, 0x5b, 0xc6, 0xc5, 0xbb, 0x74, 0x21, - 0x63, 0x59, 0xc0, 0x18, 0x86, 0x26, 0x5a, 0x25, 0xcf, 0xce, 0xce, 0x92, 0xe5, 0x1c, 0x58, 0xd1, 0xbd, 0x57, 0xc3, - 0x37, 0x30, 0x3b, 0x4a, 0x5d, 0x46, 0x3f, 0x99, 0x21, 0x52, 0xfb, 0x28, 0x27, 0x5b, 0x1d, 0xed, 0xce, 0xa5, 0xfc, - 0x97, 0x49, 0x5f, 0x8c, 0x0e, 0x51, 0x69, 0xe0, 0x61, 0x59, 0xca, 0xcc, 0x5a, 0x20, 0xc4, 0x14, 0xdf, 0xff, 0x26, - 0x7a, 0xc6, 0xb7, 0x89, 0xf0, 0xe2, 0xc2, 0x88, 0x0b, 0xd6, 0x96, 0xab, 0x54, 0x81, 0x41, 0x11, 0xdd, 0xdb, 0xc7, - 0x10, 0xa5, 0x88, 0x11, 0x2a, 0x22, 0xda, 0x56, 0x8f, 0xbe, 0xca, 0x88, 0x65, 0x85, 0x21, 0x06, 0x33, 0xf5, 0x82, - 0xa8, 0x2a, 0x55, 0x50, 0x9a, 0x81, 0x6f, 0xaa, 0x11, 0xd4, 0xa2, 0x30, 0x1b, 0xc0, 0x9e, 0x0a, 0x31, 0x0a, 0xd3, - 0x90, 0x3c, 0xd8, 0x9c, 0x57, 0x2b, 0x0f, 0x5d, 0x25, 0xd8, 0x82, 0x79, 0x41, 0x06, 0x63, 0x87, 0xae, 0x55, 0x03, - 0x3d, 0x5d, 0x8a, 0xce, 0xdd, 0x7c, 0xee, 0x75, 0xe2, 0x17, 0x17, 0x1e, 0xfc, 0x59, 0x7f, 0x9a, 0x83, 0xd0, 0x39, - 0xfd, 0x14, 0xf3, 0x06, 0x8f, 0xa6, 0x0d, 0xb4, 0xee, 0x29, 0xc8, 0x23, 0xa5, 0x33, 0xe5, 0x6f, 0x88, 0x7b, 0x96, - 0x9d, 0x59, 0x81, 0xc7, 0x63, 0x64, 0xa3, 0x06, 0x69, 0x96, 0xb2, 0x4e, 0x3d, 0x4f, 0xc7, 0x3c, 0x6d, 0x51, 0xc4, - 0xea, 0xcf, 0x33, 0x3c, 0x4e, 0xe3, 0x57, 0x41, 0x53, 0x4a, 0xf5, 0xa6, 0x3a, 0x6a, 0x69, 0xae, 0x6c, 0x1f, 0x48, - 0xda, 0x6e, 0x93, 0xf2, 0xca, 0x97, 0x8f, 0x94, 0xd6, 0x1d, 0x09, 0xdd, 0x96, 0xb5, 0x82, 0xc1, 0x21, 0xf5, 0x67, - 0xa4, 0xfb, 0x2c, 0x16, 0x53, 0xd6, 0xca, 0x5d, 0x20, 0x0b, 0xa2, 0x11, 0xbe, 0x96, 0xf4, 0x2e, 0x2d, 0x4f, 0x29, - 0x65, 0x7c, 0x8e, 0x5a, 0x26, 0x68, 0x3d, 0x99, 0x5e, 0xde, 0x7d, 0xf8, 0x9b, 0xd1, 0x2f, 0x25, 0x8d, 0xd4, 0xcd, - 0x7f, 0xdb, 0xee, 0xe0, 0x3e, 0x48, 0xa2, 0xab, 0x20, 0x4e, 0x49, 0xe5, 0x9d, 0x62, 0x94, 0xa7, 0x33, 0xcd, 0x64, - 0xfa, 0x55, 0xce, 0x12, 0xfa, 0xed, 0x1f, 0xb9, 0x14, 0xbb, 0x8f, 0xa6, 0x97, 0x6a, 0x35, 0x5a, 0x0b, 0x69, 0x55, - 0x7f, 0x68, 0xf6, 0xd4, 0xfa, 0x74, 0xad, 0x7a, 0x06, 0xd0, 0x43, 0x80, 0x41, 0xe8, 0xd9, 0x46, 0x2e, 0xa0, 0x6a, - 0x42, 0x89, 0x91, 0x3f, 0x56, 0x0d, 0x64, 0xf9, 0xbb, 0x20, 0xb9, 0xa3, 0x82, 0x75, 0xf0, 0xfd, 0xb0, 0xf1, 0x20, - 0x4a, 0xa4, 0x2e, 0x9f, 0xc4, 0xc3, 0x61, 0xc2, 0x3a, 0x4a, 0x5d, 0x5b, 0xad, 0x47, 0x98, 0x7e, 0x65, 0x2e, 0x59, - 0x7d, 0x55, 0x0c, 0xe2, 0x69, 0x3a, 0x45, 0xa7, 0x60, 0x3e, 0xe0, 0x4b, 0x5e, 0x57, 0x92, 0x53, 0xe6, 0x25, 0x35, - 0x2b, 0xe2, 0xd1, 0xf7, 0x3a, 0x2e, 0x0f, 0xc1, 0x76, 0xa1, 0x05, 0x6f, 0x76, 0x78, 0x36, 0x0d, 0x1a, 0xbb, 0x75, - 0x44, 0xb0, 0x4a, 0xa3, 0xe0, 0xad, 0x40, 0xcb, 0x43, 0x65, 0x25, 0x04, 0xb4, 0xe5, 0xb7, 0x64, 0x19, 0x0d, 0x80, - 0x2f, 0x12, 0xd5, 0x45, 0x65, 0x1d, 0x99, 0x7f, 0x9b, 0xdd, 0xf2, 0xd9, 0xea, 0xdd, 0xf2, 0x99, 0xda, 0x2d, 0x37, - 0x73, 0xec, 0xbd, 0x51, 0x0b, 0xff, 0xeb, 0x54, 0x08, 0xc1, 0xaa, 0x00, 0x39, 0x2c, 0x34, 0xd3, 0x1a, 0x6d, 0xf8, - 0x87, 0x86, 0xc6, 0x18, 0x74, 0x13, 0xf3, 0xc9, 0xbc, 0xa6, 0x85, 0x85, 0xf8, 0xd7, 0xac, 0x55, 0xb5, 0x1e, 0x60, - 0x1d, 0xf6, 0x7a, 0xb8, 0x5c, 0xd7, 0xbe, 0x79, 0xd3, 0x82, 0xbc, 0xe2, 0x4e, 0xa0, 0x84, 0x31, 0x78, 0x0e, 0xd1, - 0xe9, 0x29, 0x94, 0x8e, 0xb2, 0xc1, 0xac, 0xf8, 0x5b, 0x09, 0xbf, 0x24, 0xe2, 0x8d, 0x5b, 0x7a, 0x61, 0x1c, 0xd5, - 0x55, 0xe4, 0xf2, 0xa9, 0x11, 0xe6, 0x7a, 0x9d, 0x82, 0x02, 0x18, 0x93, 0x39, 0x6d, 0xff, 0xc1, 0x8a, 0x4d, 0xf0, - 0xef, 0xb2, 0x36, 0x2b, 0x91, 0xf9, 0xbd, 0xc4, 0xb8, 0x91, 0x08, 0xbf, 0x8a, 0x06, 0xe6, 0x1a, 0x36, 0x9f, 0xac, - 0x06, 0xf7, 0x48, 0xcd, 0xd4, 0x57, 0x4a, 0x41, 0xea, 0x1d, 0x30, 0x4a, 0xa3, 0x59, 0xc2, 0x6f, 0x1e, 0x75, 0x1d, - 0x67, 0x2c, 0x8d, 0x7a, 0x83, 0x40, 0xaf, 0xda, 0xde, 0x51, 0x4a, 0xdf, 0xfb, 0xec, 0x01, 0xfe, 0x27, 0xd2, 0x05, - 0xae, 0x2a, 0x53, 0x5d, 0xb8, 0xaa, 0x68, 0xaa, 0x4f, 0x6a, 0xb6, 0xb8, 0xd0, 0xe0, 0x64, 0x8e, 0xdf, 0xb5, 0x35, - 0x1a, 0x95, 0x77, 0x6a, 0x2e, 0x8d, 0xac, 0x5f, 0xd5, 0xfa, 0xd7, 0x0d, 0x7e, 0xc7, 0xb6, 0x03, 0x61, 0xb8, 0xd6, - 0xdb, 0xca, 0xdf, 0x61, 0x5a, 0x6a, 0xac, 0x28, 0x4e, 0xed, 0x27, 0xe1, 0x95, 0xf6, 0x50, 0xc4, 0xb9, 0x12, 0x3a, - 0x29, 0x13, 0xe1, 0xa4, 0xfc, 0x85, 0x87, 0xf7, 0xf1, 0x85, 0x84, 0xd6, 0xe5, 0x24, 0x49, 0xc1, 0x48, 0x1a, 0x73, - 0x3e, 0x0d, 0x76, 0x76, 0x2e, 0x2e, 0x2e, 0xfc, 0x8b, 0x5d, 0x3f, 0xcb, 0xcf, 0x76, 0xda, 0xcd, 0x66, 0x13, 0xdf, - 0x23, 0x67, 0x5b, 0xe7, 0x31, 0xbb, 0x78, 0x0a, 0x76, 0xb0, 0xfd, 0xd8, 0x7a, 0x62, 0x3d, 0xde, 0xb5, 0x1e, 0x3e, - 0xb2, 0x2d, 0x12, 0xe7, 0x50, 0xb2, 0x6b, 0x5b, 0x42, 0x9c, 0x87, 0x36, 0x14, 0x77, 0xf7, 0xce, 0x94, 0x45, 0x86, - 0xf7, 0x74, 0x84, 0xbd, 0x03, 0xce, 0x41, 0xf6, 0x89, 0xd5, 0x37, 0xae, 0x28, 0x6b, 0x48, 0xa5, 0xa0, 0x1e, 0x71, - 0xf7, 0x0e, 0xa2, 0x69, 0x40, 0x4c, 0x61, 0x16, 0x62, 0x0c, 0x46, 0x94, 0xd2, 0x14, 0x68, 0x65, 0x9e, 0xc2, 0x37, - 0x4c, 0xec, 0xb4, 0xe0, 0xfb, 0x9b, 0xf6, 0x63, 0xd0, 0x58, 0xe7, 0x8d, 0x07, 0x83, 0x66, 0xa3, 0x65, 0xb5, 0x1a, - 0x6d, 0xff, 0xb1, 0xd5, 0x16, 0xff, 0x82, 0xc4, 0xdb, 0xb5, 0x5a, 0xf0, 0x6d, 0xd7, 0x82, 0xe7, 0xf3, 0x07, 0xe2, - 0x00, 0x3a, 0xb2, 0x77, 0xba, 0x7b, 0xf8, 0xb3, 0x6a, 0x80, 0xd4, 0x67, 0xb6, 0xf8, 0x21, 0x48, 0xfb, 0x9e, 0x59, - 0xda, 0x7a, 0xb2, 0xb2, 0xb8, 0xfd, 0x78, 0x65, 0xf1, 0xee, 0xa3, 0x95, 0xc5, 0x0f, 0x1e, 0xd6, 0x8b, 0x77, 0xce, - 0x44, 0x95, 0xde, 0xe5, 0xa1, 0x3d, 0x89, 0x60, 0xd9, 0x2f, 0x9d, 0x16, 0xc0, 0xd9, 0xb4, 0x1a, 0xf8, 0xf1, 0xb8, - 0xed, 0xea, 0x5e, 0xa7, 0xd8, 0x4b, 0x63, 0xf9, 0xf8, 0x09, 0x60, 0xf9, 0xb2, 0xfd, 0x68, 0x80, 0xed, 0x08, 0x51, - 0xf8, 0x3b, 0xdf, 0x7d, 0x32, 0x00, 0xf9, 0x6e, 0xe1, 0x1f, 0xfc, 0x37, 0x7e, 0xd8, 0x1e, 0x88, 0x87, 0x26, 0xd6, - 0x7f, 0xd3, 0x7a, 0x5c, 0x40, 0x53, 0xfc, 0xef, 0x17, 0x6d, 0x10, 0xa3, 0x39, 0x6e, 0x8e, 0xfb, 0x00, 0x68, 0xf4, - 0x64, 0xdc, 0xf6, 0x3f, 0x3b, 0x7f, 0xec, 0x3f, 0x19, 0xb7, 0x1e, 0x7f, 0x23, 0x9e, 0x12, 0xa0, 0xe0, 0x67, 0xf8, - 0xf7, 0xcd, 0x6e, 0x13, 0xbc, 0x4b, 0xff, 0xc9, 0xf9, 0xae, 0xbf, 0x9b, 0x34, 0x1e, 0xf9, 0x4f, 0xf0, 0xaf, 0x1a, - 0x6e, 0x9c, 0x4d, 0x98, 0x6d, 0xe1, 0x7a, 0x2f, 0x78, 0x5b, 0xe6, 0x1c, 0xed, 0x07, 0xd6, 0xc3, 0x07, 0x2f, 0x9f, - 0xc0, 0x1a, 0x8d, 0x5b, 0x6d, 0xf8, 0x77, 0xdd, 0xd7, 0x6f, 0x90, 0xf0, 0x72, 0xe0, 0x88, 0x61, 0x86, 0xbd, 0x22, - 0x1c, 0xbd, 0xd3, 0xf0, 0xbe, 0x07, 0x0e, 0xd4, 0x6a, 0xef, 0x9a, 0xb1, 0xdb, 0x23, 0xa8, 0xec, 0x6e, 0xee, 0x35, - 0x63, 0x7f, 0xac, 0x7b, 0xcd, 0xd9, 0x42, 0x04, 0xf5, 0x92, 0x2f, 0x79, 0xd1, 0x8b, 0xae, 0xd7, 0x07, 0xee, 0x1c, - 0xfd, 0x85, 0xf7, 0xf1, 0x36, 0x09, 0xb4, 0x8e, 0x99, 0x19, 0x6c, 0xc8, 0x70, 0x23, 0xe3, 0x8f, 0x2b, 0xd2, 0xdd, - 0x9f, 0x75, 0x04, 0xc9, 0x6f, 0x27, 0xc8, 0x37, 0x77, 0xa3, 0x47, 0xfe, 0x07, 0xd3, 0xa3, 0x30, 0xe9, 0x51, 0x0b, - 0xe7, 0x92, 0x3b, 0x4b, 0xee, 0xe8, 0x01, 0x3d, 0x3b, 0x98, 0x84, 0xbd, 0x6d, 0xef, 0x30, 0x2c, 0x2a, 0x6c, 0x71, - 0x88, 0xf0, 0xf4, 0xd7, 0xc4, 0x9f, 0xc5, 0x8d, 0x8b, 0xd0, 0x96, 0xbe, 0xff, 0x14, 0xdf, 0xdb, 0xad, 0x1e, 0xce, - 0xc5, 0xad, 0xbe, 0x90, 0xae, 0xe4, 0x3e, 0xd4, 0x71, 0x03, 0xbc, 0x04, 0x13, 0xce, 0x33, 0x1e, 0xe1, 0x0f, 0xc3, - 0x01, 0xb9, 0xe9, 0x27, 0xe4, 0x62, 0x9e, 0x30, 0x3c, 0x24, 0x1f, 0x88, 0x77, 0x28, 0xc3, 0x57, 0x79, 0xdd, 0x16, - 0x6f, 0x71, 0x7c, 0x8d, 0x37, 0x50, 0x54, 0x60, 0x7a, 0x82, 0x2e, 0xf5, 0x1b, 0x36, 0x8c, 0x23, 0xc7, 0x76, 0xa6, - 0xb0, 0x91, 0x61, 0x96, 0x46, 0xed, 0xfa, 0x07, 0xdd, 0xfc, 0x70, 0x6d, 0xf5, 0xeb, 0x64, 0x39, 0xbe, 0xed, 0x31, - 0x3c, 0x92, 0x41, 0x2d, 0x5b, 0x9a, 0xf9, 0x30, 0xbe, 0x2a, 0xc9, 0x51, 0xa2, 0x57, 0xa6, 0x81, 0x2d, 0x6c, 0x83, - 0x96, 0xdf, 0x06, 0x5f, 0x81, 0x8a, 0xf1, 0xed, 0x79, 0xdf, 0x39, 0x8d, 0x5d, 0xb0, 0x5d, 0x8c, 0x6e, 0x7a, 0xa0, - 0xbe, 0xfe, 0xb1, 0x2b, 0xfd, 0x83, 0x8c, 0xf5, 0x3b, 0x33, 0xb6, 0xe0, 0x88, 0x7b, 0x02, 0x77, 0x5b, 0xbc, 0xa5, - 0x84, 0xa8, 0x47, 0x77, 0x46, 0xa1, 0xcc, 0x31, 0x7f, 0x98, 0x4f, 0xbc, 0x9d, 0x4f, 0xfc, 0x06, 0x67, 0x59, 0x35, - 0xe1, 0xee, 0x9c, 0x02, 0xef, 0x98, 0x64, 0x8c, 0x57, 0x75, 0x31, 0x0e, 0x1b, 0x1a, 0x34, 0xc5, 0x67, 0xb7, 0x46, - 0x64, 0xee, 0x69, 0x80, 0x88, 0xc0, 0xa1, 0xfc, 0xac, 0x8a, 0xd5, 0x17, 0x19, 0x5d, 0x01, 0xb7, 0x1d, 0x7f, 0xf9, - 0x88, 0x3e, 0x96, 0x62, 0x37, 0xe2, 0xec, 0x60, 0xa1, 0xb4, 0x1a, 0xaa, 0x8a, 0xd1, 0x14, 0x4f, 0xaf, 0x0e, 0xe5, - 0x6b, 0x3f, 0x6c, 0x0c, 0x81, 0x52, 0xe8, 0xbb, 0x7a, 0xe5, 0xe0, 0x36, 0xa8, 0x46, 0xfa, 0x21, 0x60, 0xca, 0x60, - 0x42, 0xed, 0x87, 0xb7, 0x6e, 0x2c, 0xe9, 0xf3, 0x84, 0xb6, 0xd0, 0x7d, 0x43, 0x76, 0x1e, 0x0f, 0xa4, 0x0a, 0xf3, - 0x2c, 0x79, 0x5b, 0xb0, 0x41, 0x4b, 0x13, 0xb6, 0x3c, 0xe1, 0xf5, 0xc3, 0x03, 0xea, 0xe3, 0x30, 0xcd, 0xec, 0xee, - 0xfd, 0xce, 0x3a, 0xe2, 0xe3, 0xaf, 0x12, 0x1f, 0x81, 0x97, 0xf9, 0xb7, 0xe1, 0x7d, 0xfc, 0x5d, 0xe2, 0xfb, 0x7d, - 0xdb, 0xf5, 0x49, 0x01, 0xdc, 0xaf, 0x7e, 0x9c, 0x18, 0xa5, 0xdf, 0x36, 0xe8, 0x6a, 0xef, 0xae, 0x4a, 0x5b, 0x2a, - 0xe8, 0xf6, 0xc3, 0x4a, 0x41, 0xc3, 0x77, 0x43, 0x22, 0x83, 0xb2, 0x68, 0xfb, 0x0f, 0x0d, 0xb1, 0x7f, 0xde, 0xc0, - 0xcf, 0x9a, 0xe0, 0x7f, 0x00, 0x0d, 0x94, 0xe4, 0x7f, 0x0d, 0xcd, 0x77, 0x85, 0x92, 0x81, 0x7e, 0xdf, 0x93, 0x58, - 0x96, 0x22, 0xb9, 0xb6, 0x0d, 0x56, 0x9c, 0xc6, 0x88, 0x6c, 0x2c, 0xdb, 0x73, 0xf4, 0x2f, 0x1e, 0xc9, 0x5d, 0x29, - 0xe3, 0x40, 0xcf, 0xa1, 0xaf, 0xa3, 0xdf, 0xe4, 0xbf, 0xaa, 0xce, 0xab, 0x49, 0x89, 0x15, 0x53, 0xe0, 0xbe, 0x5e, - 0x38, 0xf1, 0xe9, 0x88, 0x2b, 0x0c, 0xfa, 0x55, 0x40, 0xeb, 0x19, 0x5a, 0xde, 0x75, 0x70, 0x0d, 0x11, 0xc1, 0xe8, - 0x6d, 0xc3, 0x34, 0xc9, 0xab, 0x61, 0xb9, 0x38, 0x3f, 0xa6, 0x83, 0xe5, 0x99, 0x71, 0xa7, 0x50, 0x46, 0xef, 0x30, - 0x59, 0x74, 0x18, 0xe7, 0xf4, 0x62, 0x04, 0x05, 0x7a, 0x2d, 0x02, 0x58, 0x51, 0x89, 0xa4, 0x04, 0x2b, 0x7a, 0x36, - 0x16, 0xd9, 0x81, 0x4d, 0xe1, 0x23, 0xdb, 0x7c, 0xdd, 0xbe, 0x79, 0x73, 0x9d, 0x38, 0x99, 0x12, 0xbb, 0x71, 0xaf, - 0x22, 0x7d, 0x6c, 0x90, 0xb6, 0x6b, 0x77, 0x09, 0xd9, 0x60, 0x88, 0x6b, 0xf5, 0xfb, 0x72, 0xa6, 0x00, 0xb2, 0x4d, - 0x42, 0xeb, 0x71, 0x89, 0x84, 0xae, 0xa4, 0xd3, 0x29, 0x8b, 0xb8, 0x1f, 0xa5, 0x22, 0x0b, 0xc1, 0x10, 0x53, 0x5e, - 0x8b, 0xed, 0xba, 0x25, 0xc8, 0x46, 0x23, 0x6f, 0x42, 0xee, 0x6e, 0x28, 0x54, 0x17, 0x3d, 0x18, 0xaf, 0xe5, 0xb3, - 0x8e, 0xdb, 0xdd, 0x77, 0x87, 0xfb, 0x96, 0xd8, 0x94, 0x7b, 0x3b, 0xf0, 0xb8, 0x47, 0xfe, 0xb8, 0x48, 0xde, 0x0f, - 0x45, 0xf2, 0xbe, 0x25, 0x6f, 0x71, 0x50, 0x86, 0xe3, 0x8e, 0x40, 0xdb, 0xb6, 0x58, 0x3a, 0x10, 0x81, 0xc4, 0x09, - 0xf8, 0x2c, 0x31, 0xbe, 0xa2, 0x71, 0x07, 0xbb, 0x36, 0x70, 0xc1, 0x80, 0x9b, 0x45, 0xd4, 0x51, 0xd9, 0x35, 0x3c, - 0x55, 0x61, 0x47, 0xb0, 0x46, 0x98, 0xca, 0x40, 0x94, 0x43, 0xe9, 0xe4, 0xc5, 0xe5, 0xd6, 0xc5, 0xec, 0x74, 0x02, - 0x72, 0x52, 0xe5, 0x10, 0x7e, 0x94, 0x1d, 0xf6, 0x68, 0xaa, 0xee, 0x49, 0x29, 0xe3, 0xa2, 0xea, 0xf5, 0xf9, 0x0b, - 0x3f, 0x35, 0x2c, 0xb0, 0x97, 0x7a, 0x01, 0xb3, 0xf0, 0xc7, 0xbb, 0x5d, 0x1d, 0x89, 0x34, 0xeb, 0x4a, 0x40, 0x7d, - 0xb7, 0x7b, 0x12, 0x4c, 0xe5, 0x78, 0xaf, 0xb3, 0xa5, 0x9f, 0x2d, 0xd6, 0x72, 0xb2, 0x47, 0xd9, 0xa9, 0xe2, 0x6a, - 0x93, 0x04, 0x18, 0x56, 0x10, 0x60, 0x92, 0x26, 0x80, 0x45, 0xe7, 0xaa, 0xf6, 0xc3, 0xa6, 0x4a, 0x78, 0x85, 0x32, - 0xdc, 0x90, 0xa2, 0x8b, 0x31, 0x49, 0x2d, 0x98, 0x3b, 0x6e, 0x75, 0xf7, 0x22, 0x69, 0x5c, 0xa2, 0xf0, 0x28, 0x40, - 0x7a, 0x40, 0x67, 0xb4, 0xe0, 0xfc, 0x38, 0xdb, 0xb9, 0x60, 0xa7, 0x8d, 0x68, 0x1a, 0x57, 0x91, 0x53, 0x34, 0x35, - 0xf4, 0x94, 0x59, 0x35, 0x13, 0x7e, 0x8d, 0x16, 0x90, 0x24, 0xc1, 0x5d, 0xca, 0xb0, 0x2c, 0x59, 0xe8, 0xc0, 0x42, - 0x40, 0x61, 0x92, 0xeb, 0x2a, 0x7c, 0x2b, 0x35, 0x6e, 0x69, 0x77, 0xff, 0xfa, 0x8f, 0xff, 0x5b, 0x46, 0x64, 0x81, - 0x2a, 0x2d, 0x35, 0xd6, 0x02, 0xa1, 0xcb, 0x3d, 0xba, 0xb5, 0xa2, 0x8f, 0x10, 0xd9, 0x25, 0xb8, 0xf6, 0xf1, 0xb0, - 0x31, 0x8e, 0x92, 0x11, 0x00, 0xb6, 0x96, 0x40, 0x66, 0x52, 0xb8, 0x84, 0xba, 0x5e, 0x84, 0x2c, 0xf8, 0x9b, 0xd2, - 0x9b, 0x55, 0x96, 0x2c, 0xed, 0x56, 0x33, 0xd9, 0xb9, 0xda, 0x50, 0xb5, 0x84, 0x67, 0xf5, 0xdb, 0x7d, 0x4a, 0xa8, - 0xd5, 0xf2, 0x9c, 0xa1, 0xa5, 0x3e, 0x02, 0xf9, 0xd7, 0x7f, 0xfa, 0xbb, 0xff, 0xa1, 0x1e, 0xf1, 0x64, 0xe3, 0xaf, - 0xff, 0xf0, 0x9f, 0x31, 0x1b, 0xd3, 0xd2, 0xa7, 0x1f, 0x24, 0x27, 0xac, 0xea, 0xe8, 0x43, 0x08, 0x0c, 0x0b, 0x53, - 0x9d, 0x26, 0x20, 0x06, 0xe3, 0x41, 0x3d, 0xf3, 0xf9, 0x80, 0x26, 0xa4, 0xcd, 0x26, 0xa1, 0xa3, 0x4d, 0x5b, 0x56, - 0x3c, 0x52, 0x23, 0x39, 0xf1, 0x22, 0x54, 0x22, 0xbd, 0xef, 0x74, 0xfb, 0xc3, 0xd7, 0xab, 0x31, 0x57, 0xf1, 0x3e, - 0x2c, 0x29, 0xab, 0x72, 0x0b, 0x03, 0xf1, 0x73, 0x7c, 0x0c, 0xda, 0x46, 0x31, 0x2d, 0x5e, 0xad, 0x4f, 0xe7, 0xa7, - 0x19, 0xc0, 0x3f, 0x42, 0x8a, 0x8b, 0xa8, 0x22, 0x9d, 0x79, 0x36, 0xd0, 0xe6, 0x4b, 0xae, 0x4a, 0x1a, 0x45, 0x38, - 0x8a, 0x0f, 0x9e, 0xfc, 0x4d, 0xf9, 0xe7, 0x09, 0x5a, 0x56, 0x96, 0x33, 0x89, 0x2e, 0xa5, 0xfb, 0xf8, 0xa8, 0xd9, - 0x9c, 0x5e, 0xba, 0xf3, 0x6a, 0x06, 0x6f, 0xdd, 0x64, 0x14, 0x89, 0x34, 0x07, 0xa4, 0xc3, 0x52, 0x1d, 0xf4, 0x04, - 0x8f, 0xa9, 0x89, 0x31, 0xb2, 0xb2, 0xfc, 0xd3, 0x9c, 0xe2, 0x6e, 0xf1, 0x2f, 0x78, 0xa8, 0x29, 0x43, 0x94, 0x50, - 0x62, 0x60, 0x31, 0x37, 0x7a, 0xb5, 0x45, 0xaf, 0x71, 0x6b, 0xf9, 0xea, 0x83, 0x79, 0x28, 0x6b, 0x1e, 0xa7, 0x3e, - 0xc0, 0x03, 0xd2, 0x71, 0xcb, 0x1b, 0xb7, 0xe7, 0x7a, 0x78, 0xce, 0xb3, 0x89, 0x79, 0x0a, 0xcb, 0x22, 0x36, 0x60, - 0x23, 0x15, 0xda, 0x95, 0xf5, 0xe2, 0x84, 0xb5, 0x1c, 0xef, 0xae, 0x98, 0x4b, 0x82, 0x44, 0xa7, 0xaf, 0x00, 0xcf, - 0x3d, 0xdc, 0x80, 0x40, 0xff, 0x2c, 0xe2, 0x01, 0xf1, 0x6b, 0xc7, 0x3c, 0xcb, 0x8d, 0x50, 0xca, 0x64, 0x73, 0x03, - 0x9e, 0x8e, 0x68, 0x8a, 0x41, 0xd6, 0xfa, 0xd5, 0x93, 0xd2, 0xa7, 0xee, 0xe6, 0x50, 0x22, 0x46, 0xf3, 0x8d, 0x3c, - 0x22, 0x7d, 0x5a, 0x0b, 0x6e, 0x48, 0x15, 0xd3, 0x76, 0xbd, 0x95, 0xf5, 0x42, 0x53, 0x8b, 0xda, 0x6f, 0xb8, 0x63, - 0x13, 0x98, 0xf6, 0x62, 0x2b, 0x2a, 0xc4, 0x56, 0x4f, 0xc3, 0x6f, 0xb4, 0xeb, 0x13, 0x4d, 0xa7, 0xd4, 0xd0, 0x05, - 0x26, 0x26, 0x83, 0x15, 0x65, 0x07, 0x1d, 0xff, 0x8b, 0xd3, 0x76, 0xd9, 0x46, 0x6e, 0x04, 0xf1, 0x4d, 0x9e, 0xc3, - 0xe3, 0xaf, 0xae, 0x74, 0xff, 0x1f, 0x1c, 0x1d, 0xa5, 0x5f, 0x1b, 0x82, 0x00, 0x00}; - -} // namespace web_server -} // namespace esphome diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h new file mode 100644 index 0000000000..21beecfff7 --- /dev/null +++ b/esphome/components/web_server/server_index_v2.h @@ -0,0 +1,633 @@ +#pragma once +// Generated from https://github.com/esphome/esphome-webserver +#ifdef USE_WEBSERVER_LOCAL +#if USE_WEBSERVER_VERSION == 2 +#include "esphome/core/hal.h" +namespace esphome { + +namespace web_server { + +const uint8_t INDEX_GZ[] PROGMEM = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x7d, 0xd9, 0x92, 0xdb, 0x46, 0xb6, 0xe0, 0xf3, + 0xdc, 0xaf, 0x40, 0xc1, 0xd5, 0x25, 0x64, 0x33, 0x89, 0x22, 0x59, 0xda, 0x0c, 0x56, 0x92, 0x5d, 0x2a, 0xc9, 0x2d, + 0xbb, 0xb5, 0xd8, 0x2a, 0xc9, 0x6e, 0x9b, 0x66, 0x57, 0xa1, 0x88, 0x24, 0x99, 0x16, 0x88, 0xa4, 0x13, 0xc9, 0x5a, + 0x4c, 0xe2, 0xc6, 0x7c, 0xc0, 0x44, 0x4c, 0xc4, 0x3c, 0xcd, 0xcb, 0xc4, 0xdc, 0x87, 0xf9, 0x88, 0x79, 0xbe, 0x9f, + 0x72, 0x7f, 0x60, 0xe6, 0x13, 0x26, 0x4e, 0x2e, 0x40, 0x82, 0x4b, 0xa9, 0xbc, 0xdc, 0x3b, 0xa1, 0x90, 0x44, 0xe4, + 0x7a, 0xf2, 0xe4, 0xc9, 0xb3, 0x27, 0x70, 0xbc, 0x97, 0xf0, 0x91, 0xbc, 0x9d, 0x53, 0x6f, 0x2a, 0x67, 0x69, 0xef, + 0xd8, 0xfc, 0x4b, 0xe3, 0xa4, 0x77, 0x9c, 0xb2, 0xec, 0xa3, 0x27, 0x68, 0x4a, 0xd8, 0x88, 0x67, 0xde, 0x54, 0xd0, + 0x31, 0x49, 0x62, 0x19, 0x47, 0x6c, 0x16, 0x4f, 0xa8, 0x77, 0xd8, 0x3b, 0x9e, 0x51, 0x19, 0x7b, 0xa3, 0x69, 0x2c, + 0x72, 0x2a, 0xc9, 0x87, 0xf7, 0x5f, 0x34, 0x9f, 0xf6, 0x8e, 0xf3, 0x91, 0x60, 0x73, 0xe9, 0xc1, 0x90, 0x64, 0xc6, + 0x93, 0x45, 0x4a, 0x7b, 0x87, 0x87, 0xd7, 0xd7, 0xd7, 0xe1, 0x4f, 0xf9, 0x3f, 0x8d, 0x78, 0x96, 0x4b, 0xef, 0x15, + 0xb9, 0x66, 0x59, 0xc2, 0xaf, 0x31, 0x95, 0xe4, 0x55, 0x78, 0x36, 0x8d, 0x13, 0x7e, 0xfd, 0x8e, 0x73, 0x79, 0x70, + 0x10, 0xe8, 0xc7, 0xdb, 0xd3, 0xb3, 0x33, 0x42, 0xc8, 0x15, 0x67, 0x89, 0xd7, 0x5a, 0xad, 0xaa, 0xc2, 0x30, 0x8b, + 0x25, 0xbb, 0xa2, 0xba, 0x0b, 0x3a, 0x38, 0xf0, 0xe3, 0x84, 0xcf, 0x25, 0x4d, 0xce, 0xe4, 0x6d, 0x4a, 0xcf, 0xa6, + 0x94, 0xca, 0xdc, 0x67, 0x99, 0xf7, 0x9c, 0x8f, 0x16, 0x33, 0x9a, 0xc9, 0x70, 0x2e, 0xb8, 0xe4, 0x00, 0xc9, 0xc1, + 0x81, 0x2f, 0xe8, 0x3c, 0x8d, 0x47, 0x14, 0xea, 0x4f, 0xcf, 0xce, 0xaa, 0x1e, 0x55, 0x23, 0xcc, 0x24, 0x39, 0xbb, + 0x9d, 0x5d, 0xf2, 0x34, 0x40, 0x38, 0x95, 0x24, 0xa3, 0xd7, 0xde, 0x77, 0x34, 0xfe, 0xf8, 0x3a, 0x9e, 0x77, 0x47, + 0x69, 0x9c, 0xe7, 0xde, 0xa5, 0x5c, 0xaa, 0x25, 0x88, 0xc5, 0x48, 0x72, 0x11, 0x48, 0x4c, 0x31, 0x43, 0x4b, 0x36, + 0x0e, 0xe4, 0x94, 0xe5, 0xe1, 0xf9, 0xfe, 0x28, 0xcf, 0xdf, 0xd1, 0x7c, 0x91, 0xca, 0x7d, 0xb2, 0xd7, 0xc2, 0x6c, + 0x8f, 0x10, 0x26, 0x91, 0x9c, 0x0a, 0x7e, 0xed, 0xbd, 0x10, 0x82, 0x8b, 0xc0, 0x3f, 0x3d, 0x3b, 0xd3, 0x2d, 0x3c, + 0x96, 0x7b, 0x19, 0x97, 0x5e, 0x39, 0x5e, 0x7c, 0x99, 0xd2, 0xd0, 0xfb, 0x90, 0x53, 0xef, 0x62, 0x91, 0xe5, 0xf1, + 0x98, 0x9e, 0x9e, 0x9d, 0x5d, 0x78, 0x5c, 0x78, 0x17, 0xa3, 0x3c, 0xbf, 0xf0, 0x58, 0x96, 0x4b, 0x1a, 0x27, 0xa1, + 0x8f, 0xba, 0x6a, 0xb2, 0x51, 0x9e, 0xbf, 0xa7, 0x37, 0x92, 0x48, 0xac, 0x1e, 0x25, 0xa1, 0xc5, 0x84, 0x4a, 0x2f, + 0x2f, 0xd7, 0x15, 0xa0, 0x65, 0x4a, 0xa5, 0x27, 0x89, 0xaa, 0xe7, 0x5d, 0x8d, 0x7b, 0xaa, 0x1f, 0x65, 0x97, 0x8d, + 0x03, 0x2a, 0x0f, 0x0e, 0x64, 0x89, 0x67, 0xa4, 0x97, 0xe6, 0x31, 0x42, 0xf7, 0x6c, 0xd9, 0xc1, 0x01, 0x0d, 0x53, + 0x9a, 0x4d, 0xe4, 0x94, 0x10, 0xd2, 0xee, 0xb2, 0x83, 0x83, 0x40, 0x92, 0x54, 0x86, 0x13, 0x2a, 0x03, 0x8a, 0x10, + 0xae, 0x7a, 0x1f, 0x1c, 0x04, 0x1a, 0x09, 0x9c, 0x68, 0xc4, 0xd5, 0x70, 0x8c, 0x42, 0x83, 0xfd, 0xb3, 0xdb, 0x6c, + 0x14, 0xb8, 0xf0, 0x23, 0xcc, 0x0e, 0x0e, 0x52, 0x19, 0xe6, 0x30, 0x22, 0x96, 0x08, 0x15, 0x82, 0xca, 0x85, 0xc8, + 0x3c, 0x59, 0x48, 0x7e, 0x26, 0x05, 0xcb, 0x26, 0x01, 0x5a, 0xda, 0x32, 0xa7, 0x63, 0x51, 0x68, 0x70, 0xbf, 0x96, + 0x44, 0x90, 0x1e, 0xcc, 0x78, 0x29, 0x03, 0xd8, 0x45, 0x3e, 0xf6, 0x04, 0x21, 0x7e, 0xae, 0xfa, 0xfa, 0x7d, 0x11, + 0x89, 0x86, 0xef, 0x63, 0x0d, 0x25, 0x66, 0x12, 0xe1, 0x8f, 0x24, 0x10, 0x38, 0x0c, 0x43, 0x89, 0x48, 0x6f, 0x69, + 0xb1, 0x22, 0x9c, 0x75, 0xf6, 0xc5, 0xa0, 0x35, 0x8c, 0x64, 0x28, 0x68, 0xb2, 0x18, 0xd1, 0x20, 0x60, 0x38, 0xc7, + 0x19, 0x22, 0x3d, 0xd6, 0x08, 0x38, 0xe9, 0xc1, 0x76, 0xf3, 0xfa, 0x5e, 0x13, 0xb2, 0xd7, 0x42, 0x06, 0x46, 0x6e, + 0x01, 0x04, 0x0c, 0x1b, 0x78, 0x38, 0x21, 0x7e, 0xb6, 0x98, 0x5d, 0x52, 0xe1, 0x97, 0xcd, 0xba, 0x35, 0xb2, 0x58, + 0xe4, 0xd4, 0x1b, 0xe5, 0xb9, 0x37, 0x5e, 0x64, 0x23, 0xc9, 0x78, 0xe6, 0xf9, 0x0d, 0xde, 0xf0, 0x35, 0x39, 0x94, + 0xd4, 0xe0, 0xa3, 0x02, 0x05, 0x39, 0x6a, 0x88, 0x41, 0xd6, 0x68, 0x0f, 0x31, 0x40, 0x89, 0xba, 0x66, 0x3c, 0x83, + 0x00, 0x8a, 0x05, 0xac, 0xb1, 0xc0, 0x1f, 0x24, 0xac, 0x52, 0x2d, 0x91, 0xca, 0xbe, 0x08, 0x37, 0x0f, 0x0a, 0x91, + 0xe1, 0x2c, 0x9e, 0x07, 0x94, 0xf4, 0xa8, 0x22, 0xae, 0x38, 0x1b, 0x01, 0xac, 0xb5, 0x7d, 0xeb, 0xd3, 0x88, 0x86, + 0x15, 0x49, 0xa1, 0x48, 0x86, 0x63, 0x2e, 0x5e, 0xc4, 0xa3, 0x29, 0xf4, 0x2b, 0x09, 0x26, 0xb1, 0xe7, 0x6d, 0x24, + 0x68, 0x2c, 0xe9, 0x8b, 0x94, 0xc2, 0x53, 0xe0, 0xab, 0x9e, 0x3e, 0xc2, 0x39, 0x79, 0x15, 0xa6, 0x4c, 0xbe, 0xe1, + 0xd9, 0x88, 0x76, 0x73, 0x87, 0xba, 0x18, 0xec, 0xfb, 0x89, 0x94, 0x82, 0x5d, 0x2e, 0x24, 0x0d, 0xfc, 0x0c, 0x5a, + 0xf8, 0x38, 0x47, 0x98, 0x85, 0x92, 0xde, 0xc8, 0x53, 0x9e, 0x49, 0x9a, 0x49, 0x42, 0x2d, 0x52, 0xb1, 0x08, 0xe3, + 0xf9, 0x9c, 0x66, 0xc9, 0xe9, 0x94, 0xa5, 0x49, 0xc0, 0x50, 0x81, 0x0a, 0x1c, 0x4b, 0x02, 0x6b, 0x24, 0x3d, 0x11, + 0xc1, 0x3f, 0xbb, 0x57, 0x13, 0x48, 0xd2, 0x53, 0x87, 0x82, 0x12, 0xdf, 0xef, 0x8e, 0xb9, 0x08, 0xcc, 0x0a, 0x3c, + 0x3e, 0xf6, 0x24, 0xcc, 0xf1, 0x6e, 0x91, 0xd2, 0x1c, 0xd1, 0x06, 0x61, 0xe5, 0x36, 0x1a, 0x04, 0x7f, 0x0d, 0x14, + 0x5f, 0xa0, 0x40, 0xa0, 0x48, 0x74, 0xaf, 0x62, 0xe1, 0x7d, 0x61, 0x4e, 0xd4, 0x4f, 0x96, 0x9b, 0x4d, 0x25, 0xf9, + 0x29, 0x94, 0x62, 0x91, 0x4b, 0x9a, 0xbc, 0xbf, 0x9d, 0xd3, 0x1c, 0xbf, 0x94, 0x64, 0x2a, 0xfb, 0x53, 0x19, 0xd2, + 0xd9, 0x5c, 0xde, 0x9e, 0x29, 0xc6, 0x18, 0xf9, 0x3e, 0x1e, 0x41, 0x4b, 0x41, 0xe3, 0x11, 0x30, 0x33, 0x83, 0xad, + 0xaf, 0x79, 0x7a, 0x3b, 0x66, 0x69, 0x7a, 0xb6, 0x98, 0xcf, 0xb9, 0x90, 0xf8, 0xaf, 0x64, 0x29, 0x79, 0x85, 0x1a, + 0xd8, 0xcb, 0x65, 0x7e, 0xcd, 0xe4, 0x68, 0x1a, 0x48, 0xb4, 0x1c, 0xc5, 0x39, 0xf5, 0x9e, 0x71, 0x9e, 0xd2, 0x38, + 0x8b, 0x04, 0x11, 0xfd, 0x97, 0x32, 0xca, 0x16, 0x69, 0xda, 0xbd, 0x14, 0x34, 0xfe, 0xd8, 0x55, 0xd5, 0x6f, 0x2f, + 0x7f, 0xa2, 0x23, 0x19, 0xa9, 0xdf, 0x27, 0x42, 0xc4, 0xb7, 0xd0, 0x90, 0x10, 0x68, 0xd6, 0x17, 0xd1, 0x57, 0x67, + 0x6f, 0xdf, 0x84, 0xfa, 0x90, 0xb0, 0xf1, 0x6d, 0x20, 0xca, 0x83, 0x27, 0x0a, 0x3c, 0x16, 0x7c, 0xb6, 0x36, 0xb5, + 0xc6, 0x9a, 0xe8, 0xee, 0x00, 0x81, 0x12, 0xb1, 0xa7, 0x87, 0x76, 0x21, 0x78, 0xa3, 0x68, 0x1e, 0x2a, 0x89, 0x99, + 0x17, 0xfe, 0x89, 0x74, 0x71, 0x20, 0xd0, 0xdd, 0xd0, 0x4a, 0x71, 0xbb, 0xa4, 0x44, 0xc1, 0x39, 0x07, 0x09, 0x03, + 0x30, 0x8e, 0x62, 0x39, 0x9a, 0x2e, 0xa9, 0x1a, 0xac, 0xb0, 0x10, 0xd3, 0xa2, 0xc0, 0xd7, 0x25, 0xbd, 0xcb, 0x3d, + 0x42, 0x84, 0x62, 0x54, 0x44, 0xae, 0x56, 0x82, 0x10, 0x81, 0xf0, 0x77, 0x64, 0x19, 0xdb, 0xf5, 0x44, 0x7b, 0x2d, + 0x0c, 0xe7, 0x32, 0xd2, 0xdc, 0x05, 0x8f, 0x78, 0x76, 0x45, 0x85, 0xa4, 0x22, 0xfa, 0x2b, 0x16, 0x74, 0x9c, 0x02, + 0x14, 0x7b, 0x6d, 0x3c, 0x8d, 0xf3, 0xd3, 0x69, 0x9c, 0x4d, 0x68, 0x12, 0x5d, 0xcb, 0x02, 0xff, 0x9d, 0xf8, 0x63, + 0x96, 0xc5, 0x29, 0xfb, 0x85, 0x26, 0xbe, 0x91, 0x06, 0x27, 0x1e, 0xbd, 0x91, 0x34, 0x4b, 0x72, 0xef, 0xe5, 0xfb, + 0xd7, 0xaf, 0xcc, 0x3e, 0xd6, 0x04, 0x04, 0x5a, 0xe6, 0x8b, 0x39, 0x15, 0x01, 0xc2, 0x46, 0x40, 0xbc, 0x60, 0x8a, + 0x39, 0xbe, 0x8e, 0xe7, 0xba, 0x84, 0xe5, 0x1f, 0xe6, 0x49, 0x2c, 0xe9, 0xd7, 0x34, 0x4b, 0x58, 0x36, 0x21, 0x7b, + 0x6d, 0x5d, 0x3e, 0x8d, 0x4d, 0x45, 0x52, 0x16, 0x9d, 0xef, 0xbf, 0x48, 0xd5, 0xba, 0xcb, 0xc7, 0x45, 0x80, 0x8a, + 0x5c, 0xc6, 0x92, 0x8d, 0xbc, 0x38, 0x49, 0xbe, 0xcc, 0x98, 0x64, 0x0a, 0x40, 0x01, 0xdb, 0x03, 0x24, 0x4a, 0xb5, + 0xa8, 0xb0, 0x80, 0x07, 0x08, 0x07, 0x81, 0x11, 0x00, 0x53, 0x64, 0xf6, 0xeb, 0xe0, 0xa0, 0x62, 0xf7, 0x7d, 0x1a, + 0xe9, 0x4a, 0x32, 0x18, 0xa2, 0x70, 0xbe, 0xc8, 0x61, 0xa3, 0xed, 0x14, 0x20, 0x5d, 0xf8, 0x65, 0x4e, 0xc5, 0x15, + 0x4d, 0x4a, 0xe2, 0xc8, 0x03, 0xb4, 0x5c, 0x9b, 0xc3, 0x1c, 0x0b, 0x49, 0x06, 0xc3, 0xae, 0xcb, 0xb7, 0xa9, 0xa1, + 0x73, 0xc1, 0xe7, 0x54, 0x48, 0x46, 0xf3, 0x92, 0x95, 0x04, 0x20, 0x45, 0x4b, 0x76, 0x92, 0x13, 0xbb, 0xbe, 0x79, + 0xc0, 0x30, 0x45, 0x35, 0x86, 0x61, 0x05, 0xed, 0x8b, 0x2b, 0x25, 0x31, 0x72, 0xcc, 0x10, 0x96, 0x1a, 0xd2, 0x1c, + 0xa1, 0x02, 0x61, 0x69, 0xc1, 0xd5, 0xac, 0xc8, 0xcc, 0x76, 0x0b, 0xa2, 0x9a, 0x7c, 0xa7, 0x44, 0x35, 0x30, 0xb4, + 0x58, 0xd2, 0x83, 0x83, 0x80, 0x86, 0x25, 0x51, 0x90, 0xbd, 0xb6, 0xd9, 0x23, 0x07, 0x59, 0x3b, 0xc0, 0x86, 0x89, + 0x25, 0xa6, 0x08, 0xef, 0xd1, 0x30, 0xe3, 0x27, 0xa3, 0x11, 0xcd, 0x73, 0x2e, 0x0e, 0x0e, 0xf6, 0x54, 0xfb, 0x52, + 0x9b, 0x80, 0x3d, 0x7c, 0x7b, 0x9d, 0x55, 0x10, 0xa0, 0x4a, 0xc2, 0x1a, 0xb9, 0x20, 0x41, 0x4e, 0x29, 0x85, 0xc3, + 0xef, 0x5b, 0xc5, 0x23, 0xf2, 0xcf, 0xcf, 0xfd, 0x86, 0xc4, 0x06, 0x0d, 0x13, 0x6a, 0xa7, 0xbe, 0x7d, 0x4e, 0xb5, + 0x6a, 0xa5, 0x14, 0x8f, 0x0d, 0xcc, 0xe8, 0xf3, 0x13, 0x26, 0x74, 0xcc, 0x32, 0x67, 0xd9, 0x35, 0x90, 0xb0, 0xc4, + 0x39, 0x2a, 0x9c, 0x0d, 0xdd, 0x3a, 0xb4, 0xd2, 0x69, 0xf4, 0xce, 0x2d, 0x27, 0x4a, 0x8f, 0x70, 0xb6, 0x71, 0x40, + 0x87, 0x05, 0x56, 0xa8, 0xb7, 0xab, 0xc9, 0x14, 0xa0, 0x03, 0x39, 0xec, 0x9a, 0x7a, 0x92, 0x6b, 0xcc, 0x09, 0xfa, + 0xf3, 0x82, 0xe6, 0x52, 0xd3, 0x71, 0x20, 0x71, 0x86, 0x19, 0x2a, 0xe0, 0xb8, 0x8d, 0xd9, 0x64, 0x21, 0x40, 0xdd, + 0x81, 0xa3, 0x48, 0xb3, 0xc5, 0x8c, 0xda, 0xa7, 0x6d, 0xb0, 0xbd, 0x9d, 0x83, 0x40, 0xcc, 0x81, 0xa6, 0xef, 0x26, + 0x27, 0x80, 0x55, 0xa2, 0xd5, 0xea, 0x3b, 0x3b, 0x48, 0xb5, 0x95, 0xa5, 0x8a, 0xb6, 0xb6, 0x27, 0x7f, 0x47, 0x46, + 0x1e, 0xef, 0xb5, 0x35, 0xf4, 0x7f, 0x1f, 0x92, 0xbd, 0x56, 0x49, 0xc1, 0x06, 0xa7, 0x1a, 0x18, 0x8d, 0xc2, 0xb7, + 0x7a, 0x20, 0xa4, 0xa4, 0x7b, 0x8d, 0x58, 0xc2, 0xe9, 0x06, 0x9d, 0x4e, 0xc9, 0x00, 0xf4, 0x8c, 0x70, 0x3a, 0xdc, + 0x45, 0x4c, 0x96, 0x1b, 0x04, 0x72, 0xb3, 0xae, 0x62, 0x1a, 0x57, 0x75, 0xa6, 0xb1, 0xb6, 0x08, 0x7f, 0x5e, 0x76, + 0xf1, 0x4b, 0x1a, 0x33, 0xc7, 0xbc, 0xaa, 0xc2, 0x4c, 0x01, 0x53, 0x2d, 0xc9, 0x19, 0xe2, 0x4d, 0x3c, 0xa3, 0x79, + 0x40, 0x11, 0xde, 0xd5, 0x40, 0x13, 0x27, 0x34, 0x19, 0x3a, 0x62, 0x33, 0x07, 0xb1, 0xc9, 0x90, 0xd6, 0xca, 0xea, + 0xc7, 0x2d, 0xc7, 0x74, 0x90, 0x0f, 0x2b, 0x65, 0xce, 0x59, 0xbc, 0x92, 0xc7, 0x86, 0xba, 0x2d, 0xfe, 0x74, 0x99, + 0x46, 0x9a, 0x52, 0x1a, 0x72, 0x84, 0xf7, 0x5a, 0xeb, 0xfb, 0x68, 0x5b, 0x55, 0x6b, 0x1c, 0x0c, 0x61, 0x1f, 0x94, + 0xb8, 0x08, 0x59, 0xae, 0xfe, 0xaf, 0x9d, 0x33, 0x40, 0xdb, 0x19, 0x90, 0x45, 0x38, 0x4e, 0x63, 0x19, 0xb4, 0x0f, + 0x5b, 0xa0, 0x89, 0x5e, 0x51, 0x90, 0x26, 0x08, 0x6d, 0x2e, 0x85, 0x86, 0x8b, 0x2c, 0x9f, 0xb2, 0xb1, 0x0c, 0x62, + 0xa9, 0x18, 0x0a, 0x4d, 0x73, 0xea, 0xc9, 0x9a, 0x3e, 0xac, 0x98, 0x4d, 0x0c, 0xa4, 0x56, 0x2a, 0x5f, 0xd4, 0x42, + 0xaa, 0x98, 0x16, 0xf0, 0x86, 0x4a, 0x97, 0xae, 0x78, 0x8c, 0x6d, 0xcd, 0x40, 0x5f, 0x6c, 0xf7, 0xf5, 0x88, 0x91, + 0x61, 0x05, 0xcc, 0x51, 0x59, 0x59, 0xe4, 0xf2, 0x07, 0x53, 0x28, 0x43, 0xc9, 0x5f, 0xf1, 0x6b, 0x2a, 0x4e, 0x63, + 0x00, 0x3e, 0xd2, 0xdd, 0x0b, 0x2d, 0x06, 0x14, 0xb7, 0x97, 0x5d, 0x4b, 0x2f, 0xe7, 0x6a, 0xe1, 0x5f, 0x0b, 0x3e, + 0x63, 0x39, 0x05, 0x4d, 0x4d, 0xe3, 0x3f, 0x83, 0x53, 0xa6, 0x8e, 0x23, 0x88, 0x1a, 0x5a, 0xd2, 0xd7, 0xc9, 0xab, + 0x3a, 0x7d, 0x9d, 0xef, 0xbf, 0x98, 0x58, 0xf6, 0x57, 0x3f, 0xc4, 0x08, 0x07, 0xc6, 0x9e, 0x70, 0xa4, 0x5c, 0x38, + 0x45, 0x46, 0xbc, 0xaf, 0x56, 0xd2, 0x31, 0xdb, 0x6a, 0xba, 0x22, 0xd5, 0xc7, 0x06, 0x15, 0x71, 0x92, 0x80, 0x56, + 0x27, 0x78, 0x9a, 0x3a, 0x82, 0x0a, 0xb3, 0x6e, 0x29, 0x9a, 0xce, 0xf7, 0x5f, 0x9c, 0xdd, 0x25, 0x9d, 0xa0, 0xde, + 0x15, 0x50, 0x16, 0xd0, 0x2c, 0xa1, 0x02, 0xcc, 0x48, 0x67, 0xb7, 0x8c, 0x8c, 0x3d, 0xe5, 0x59, 0x46, 0x47, 0x92, + 0x26, 0x60, 0xa5, 0x30, 0x22, 0xc3, 0x29, 0xcf, 0x65, 0x59, 0x58, 0x41, 0xcf, 0x1c, 0xe8, 0x59, 0x38, 0x8a, 0xd3, + 0x34, 0xd0, 0x16, 0xc9, 0x8c, 0x5f, 0xd1, 0x2d, 0x50, 0x77, 0x6b, 0x20, 0x97, 0xc3, 0x50, 0x67, 0x18, 0x1a, 0xe6, + 0xf3, 0x94, 0x8d, 0x68, 0x29, 0xb8, 0xce, 0x42, 0x96, 0x25, 0xf4, 0x06, 0xf8, 0x08, 0xea, 0xf5, 0x7a, 0x2d, 0xdc, + 0x46, 0x85, 0x46, 0xf8, 0x72, 0x03, 0xb1, 0x77, 0x88, 0x4c, 0x20, 0x32, 0xd2, 0x5b, 0x6e, 0xe3, 0x07, 0x14, 0x39, + 0x72, 0x92, 0x59, 0xcb, 0x4a, 0xf3, 0x66, 0x84, 0x13, 0x9a, 0x52, 0x49, 0x2d, 0x2f, 0x07, 0xfd, 0x59, 0x1f, 0xdd, + 0x77, 0x25, 0xfe, 0x4a, 0x72, 0xb2, 0xa7, 0xcc, 0xee, 0x79, 0x5e, 0x5a, 0xea, 0xd5, 0xf6, 0x54, 0xd8, 0xee, 0x4b, + 0xbd, 0x3d, 0xb1, 0x94, 0xf1, 0x68, 0xaa, 0x4d, 0xf4, 0x60, 0x63, 0x49, 0xd5, 0x18, 0x86, 0xaf, 0x97, 0x87, 0xe8, + 0x83, 0x05, 0x73, 0x1b, 0x0a, 0xce, 0x0c, 0x53, 0xa0, 0x60, 0xf5, 0xe9, 0x6d, 0x3b, 0x8d, 0xd3, 0xf4, 0x32, 0x1e, + 0x7d, 0xac, 0x53, 0x7f, 0x45, 0x06, 0x64, 0x9d, 0x1b, 0x3b, 0x55, 0x0e, 0xcb, 0x72, 0xd7, 0x6d, 0xb9, 0x74, 0xed, + 0xa0, 0x04, 0x7b, 0xad, 0x8a, 0xec, 0xeb, 0x1b, 0xbd, 0x93, 0xda, 0x15, 0x44, 0xcc, 0xac, 0x2c, 0x00, 0x2e, 0xf0, + 0x49, 0x8a, 0xb3, 0xfc, 0xc0, 0xd0, 0x1d, 0xd8, 0x1a, 0xc5, 0x1a, 0x20, 0x12, 0x2d, 0x8b, 0x84, 0xe5, 0xbb, 0x31, + 0xf0, 0x87, 0x40, 0xf9, 0xdc, 0x99, 0xe1, 0xbe, 0x80, 0x96, 0x3c, 0xce, 0xa8, 0xcc, 0x25, 0x64, 0x46, 0x9b, 0xb0, + 0x8c, 0xe6, 0x6f, 0xa0, 0xb9, 0x28, 0x7a, 0x7f, 0xab, 0xab, 0x40, 0x27, 0x03, 0x28, 0xf2, 0xae, 0xab, 0x4c, 0xd4, + 0x28, 0xc0, 0xf0, 0x54, 0xa6, 0x44, 0x6e, 0x56, 0x33, 0x1e, 0x8d, 0xba, 0xae, 0xed, 0x6f, 0xc3, 0x72, 0x39, 0x09, + 0x82, 0x20, 0x07, 0xfb, 0xcd, 0xea, 0xf5, 0xd5, 0x22, 0xf2, 0x8d, 0x45, 0xe4, 0xa1, 0x63, 0x64, 0xa1, 0x8a, 0x96, + 0x9d, 0xee, 0xd1, 0x5f, 0x91, 0xdb, 0x08, 0x94, 0xd5, 0x10, 0xf8, 0x33, 0x2a, 0xd9, 0x6d, 0x4a, 0x24, 0xe6, 0xc6, + 0xc0, 0x31, 0x94, 0x06, 0x0c, 0xa3, 0xea, 0x92, 0x21, 0x7d, 0x34, 0x6a, 0xc6, 0x6e, 0x86, 0x39, 0x5a, 0xd3, 0xec, + 0x8b, 0xc2, 0xe0, 0x88, 0x22, 0xb3, 0x37, 0x35, 0x95, 0xd8, 0xc1, 0x0a, 0xce, 0x88, 0x51, 0x83, 0xb5, 0xd6, 0xb3, + 0x8e, 0x9b, 0x72, 0x5c, 0x38, 0xa8, 0x15, 0x6a, 0x6a, 0xfa, 0xa4, 0x55, 0xac, 0x32, 0x84, 0xa7, 0x56, 0x23, 0xe5, + 0xd5, 0xba, 0x09, 0xf1, 0xad, 0x37, 0xc2, 0xef, 0x2f, 0x6b, 0x26, 0x61, 0xe4, 0x34, 0x2b, 0x22, 0x60, 0xa9, 0x7c, + 0x1b, 0xba, 0xb7, 0xd1, 0x4c, 0x6d, 0x1c, 0x07, 0xe1, 0xdc, 0x45, 0xb8, 0x83, 0xd9, 0x4c, 0x73, 0xae, 0x6c, 0x48, + 0xa6, 0xf5, 0xbe, 0x01, 0xc5, 0x5c, 0xef, 0xc3, 0x06, 0x12, 0xd7, 0x15, 0x4f, 0x45, 0x82, 0x60, 0xc0, 0xe6, 0xa0, + 0xdc, 0xb9, 0xf2, 0x21, 0x00, 0xd8, 0xd9, 0x6a, 0xb5, 0x41, 0x74, 0x5b, 0xf5, 0x4f, 0x14, 0x56, 0x46, 0xe1, 0x6a, + 0x75, 0x2d, 0x51, 0x60, 0x34, 0x5f, 0x4c, 0x51, 0xdf, 0x72, 0xdc, 0x93, 0x57, 0xd0, 0x4a, 0x29, 0xa2, 0x55, 0x49, + 0x69, 0x32, 0xd4, 0x69, 0xb6, 0xbe, 0x4f, 0xd2, 0x61, 0xdb, 0xa7, 0x1b, 0xdc, 0x4b, 0x15, 0x1a, 0x31, 0x5d, 0x2d, + 0xf9, 0xd4, 0x0c, 0xcd, 0x10, 0x42, 0x51, 0xae, 0xac, 0x98, 0xbd, 0x6d, 0x86, 0xe5, 0xc1, 0x41, 0xee, 0x0c, 0x74, + 0x5e, 0xb2, 0x89, 0x9f, 0x02, 0x10, 0xc9, 0xf9, 0x6d, 0xa6, 0x74, 0x97, 0x9f, 0xac, 0x10, 0xda, 0x30, 0x4b, 0x5b, + 0x5d, 0xb0, 0xc6, 0xe3, 0xeb, 0x98, 0x49, 0xaf, 0x1c, 0x45, 0x5b, 0xe3, 0x01, 0x45, 0x4b, 0xa3, 0x6a, 0x84, 0x82, + 0x82, 0xf2, 0x08, 0x3c, 0xc1, 0xaa, 0xd0, 0x9a, 0xee, 0x47, 0x53, 0x0a, 0x8e, 0x60, 0xab, 0x45, 0x94, 0x76, 0xe1, + 0x9e, 0x91, 0x22, 0x66, 0xe0, 0xed, 0xb0, 0x17, 0xeb, 0xdd, 0x6b, 0x76, 0xc0, 0x9c, 0x8a, 0x31, 0x17, 0x33, 0x5b, + 0x57, 0xac, 0x3d, 0x1b, 0xce, 0xc8, 0xc6, 0xc1, 0xd6, 0xb1, 0x8d, 0xfa, 0xdf, 0x5d, 0x33, 0xba, 0x2b, 0x73, 0xbd, + 0x26, 0x4a, 0x4b, 0xe9, 0xab, 0xfd, 0x81, 0x96, 0x32, 0x73, 0xd7, 0xbc, 0x37, 0xce, 0xd4, 0xae, 0x76, 0x98, 0xec, + 0xb5, 0xbb, 0xa5, 0xcd, 0x67, 0xa9, 0xa1, 0xab, 0x1d, 0x1b, 0x46, 0xa4, 0xf2, 0x45, 0x9a, 0x18, 0x60, 0x19, 0xc2, + 0xd4, 0xd0, 0xd1, 0x35, 0x4b, 0xd3, 0xaa, 0xf4, 0xd7, 0xf0, 0xf5, 0xdc, 0xf0, 0xf5, 0xcc, 0xf2, 0x75, 0xe0, 0x14, + 0xc0, 0xd7, 0xf5, 0x70, 0x55, 0xf7, 0x6c, 0xe3, 0x74, 0x66, 0x9a, 0xa3, 0xe7, 0xca, 0x8e, 0x86, 0xf9, 0x16, 0x16, + 0x02, 0x54, 0x6a, 0x5e, 0x1f, 0x03, 0xe3, 0x84, 0x01, 0x03, 0x50, 0xbb, 0x30, 0xa9, 0xeb, 0xa2, 0xf8, 0x18, 0x20, + 0x9c, 0x17, 0xb4, 0xa4, 0xec, 0x93, 0x17, 0xe0, 0xa4, 0x73, 0x96, 0x03, 0x42, 0x4c, 0x15, 0xff, 0x2a, 0x25, 0xca, + 0xae, 0x8e, 0x99, 0xd5, 0xe5, 0x76, 0x75, 0xc0, 0xe9, 0xab, 0xd5, 0x25, 0x77, 0xf3, 0x7a, 0xb5, 0x3c, 0x56, 0x2e, + 0xaf, 0xda, 0xef, 0xd5, 0x2a, 0x58, 0x2b, 0x01, 0xff, 0xbd, 0x31, 0x51, 0x44, 0x39, 0x3a, 0xf0, 0x00, 0x17, 0x33, + 0x50, 0x50, 0xe8, 0x45, 0x97, 0x22, 0xee, 0xd5, 0xa7, 0x1c, 0x3c, 0xca, 0x4d, 0xaf, 0xfb, 0x9f, 0xf2, 0xd9, 0x1c, + 0xb4, 0xb1, 0x35, 0x92, 0x9e, 0x50, 0x33, 0x61, 0x55, 0x5f, 0x6c, 0x29, 0xab, 0xf5, 0x51, 0xe7, 0xb1, 0x46, 0x4d, + 0xa5, 0xbd, 0xbc, 0xd7, 0x2a, 0x16, 0x65, 0x51, 0xc9, 0x38, 0xb6, 0x39, 0x55, 0x4e, 0xd7, 0x5d, 0x32, 0xb6, 0xe2, + 0x6d, 0xc0, 0x34, 0x1f, 0x66, 0xc0, 0xeb, 0x1c, 0xf6, 0x63, 0xc9, 0xdd, 0xdd, 0xff, 0xa2, 0x42, 0xce, 0xb2, 0x58, + 0x43, 0xdf, 0xb2, 0x28, 0x4e, 0xb4, 0x91, 0x8d, 0x4f, 0x76, 0x5b, 0xc3, 0x55, 0x9d, 0x31, 0x16, 0x07, 0x43, 0x7c, + 0xb2, 0xa9, 0x3a, 0x92, 0xe5, 0x8c, 0x27, 0x34, 0xf2, 0xf9, 0x9c, 0x66, 0x7e, 0x01, 0x5e, 0x55, 0xb3, 0xf7, 0x23, + 0x19, 0x2c, 0xdf, 0xd5, 0xdd, 0xab, 0xd1, 0x49, 0x01, 0xde, 0xaf, 0x2f, 0x36, 0x1d, 0xaf, 0xdf, 0x52, 0x91, 0x2b, + 0x45, 0xb4, 0xd4, 0x69, 0xbf, 0xa8, 0xc4, 0xd2, 0x17, 0xd1, 0xce, 0xf6, 0x95, 0x09, 0xe2, 0xb7, 0xc3, 0xc7, 0xe1, + 0x91, 0x8f, 0x94, 0x5b, 0xf8, 0x2b, 0x73, 0xe0, 0x9f, 0x5b, 0xb7, 0xf0, 0x0b, 0xf2, 0xbc, 0xee, 0x15, 0x4e, 0x24, + 0x79, 0xd1, 0x7f, 0x61, 0x2d, 0x66, 0x9e, 0xb2, 0xd1, 0x6d, 0xe0, 0xa7, 0x4c, 0x36, 0x21, 0xf4, 0xe6, 0xe3, 0xa5, + 0xae, 0x00, 0x97, 0xa2, 0x72, 0x67, 0x17, 0xd6, 0xd6, 0xc3, 0x52, 0x12, 0x7f, 0x3f, 0x65, 0x72, 0xdf, 0xc7, 0x33, + 0x72, 0x01, 0x3f, 0xf6, 0x97, 0xc1, 0xeb, 0x58, 0x4e, 0x43, 0x11, 0x67, 0x09, 0x9f, 0x05, 0xa8, 0xe1, 0xfb, 0x28, + 0xcc, 0x95, 0xbd, 0xf1, 0x39, 0x2a, 0xf6, 0x2f, 0xf0, 0x8d, 0x24, 0x7e, 0xdf, 0x6f, 0xcc, 0xf0, 0x1b, 0x49, 0x2e, + 0x8e, 0xf7, 0x97, 0x37, 0xb2, 0xe8, 0x5d, 0xe0, 0x9b, 0xd2, 0x63, 0x8f, 0xbf, 0x26, 0x01, 0x22, 0xbd, 0x1b, 0x03, + 0xcd, 0x29, 0x9f, 0x69, 0xcf, 0xbd, 0x8f, 0xf0, 0x07, 0x88, 0xab, 0x88, 0x8a, 0xdb, 0x98, 0xd0, 0xca, 0x1e, 0xf1, + 0xb9, 0x72, 0x11, 0xf8, 0x07, 0x07, 0x4e, 0x59, 0xa9, 0x2a, 0xe0, 0x13, 0x49, 0x6a, 0x06, 0x39, 0x7e, 0xaf, 0x22, + 0x34, 0x27, 0x32, 0x10, 0xc8, 0x0e, 0x13, 0x58, 0x3f, 0xb4, 0x39, 0x9a, 0x62, 0xa0, 0x3d, 0x0c, 0x21, 0x93, 0x54, + 0xc4, 0x92, 0x8b, 0x21, 0x72, 0xd5, 0x0f, 0xfc, 0x37, 0x72, 0x31, 0xf0, 0xfe, 0xd3, 0x3f, 0xfd, 0x38, 0xfe, 0x51, + 0x0c, 0x2f, 0xf0, 0x5b, 0x72, 0x78, 0x1c, 0xf4, 0xa3, 0x60, 0xaf, 0xd9, 0x5c, 0xfd, 0x78, 0x38, 0xf8, 0x47, 0xdc, + 0xfc, 0xe5, 0xa4, 0xf9, 0xc3, 0x10, 0xad, 0x82, 0x1f, 0x0f, 0xfb, 0x03, 0xf3, 0x34, 0xf8, 0x47, 0xef, 0xc7, 0x7c, + 0xf8, 0x67, 0x5d, 0xb8, 0x8f, 0xd0, 0xe1, 0x04, 0x2f, 0x24, 0x39, 0x6c, 0x36, 0x7b, 0x87, 0x13, 0x3c, 0x97, 0xe4, + 0x10, 0xfe, 0xbf, 0x24, 0xef, 0xe8, 0xe4, 0xc5, 0xcd, 0x3c, 0xb8, 0xe8, 0xad, 0xf6, 0x97, 0x7f, 0x2b, 0x60, 0xd4, + 0xc1, 0x3f, 0x7e, 0xfc, 0x31, 0xf7, 0x1f, 0xf4, 0xc8, 0xe1, 0xb0, 0x81, 0x02, 0x28, 0xfd, 0x33, 0x51, 0xff, 0x06, + 0xfd, 0x68, 0xf0, 0x0f, 0x03, 0x85, 0xff, 0xe0, 0xc7, 0x8b, 0xe3, 0x1e, 0x19, 0xae, 0x02, 0x7f, 0xf5, 0x00, 0xad, + 0x10, 0x5a, 0xed, 0xa3, 0x0b, 0xec, 0x4f, 0x7c, 0x84, 0x27, 0x92, 0x1c, 0x3e, 0x38, 0x9c, 0xe0, 0x2b, 0x49, 0x0e, + 0xfd, 0xc3, 0x09, 0x7e, 0x21, 0xc9, 0xe1, 0x3f, 0x82, 0x7e, 0xa4, 0x3d, 0x6c, 0x2b, 0xe5, 0xde, 0x58, 0x41, 0x70, + 0x23, 0x16, 0x34, 0x5e, 0x49, 0x26, 0x53, 0x8a, 0xf6, 0x0f, 0x19, 0x3e, 0x53, 0x68, 0x0a, 0x24, 0x38, 0x61, 0xc0, + 0xb6, 0x0b, 0x96, 0xe7, 0xb0, 0xd9, 0x40, 0x33, 0xfb, 0x91, 0xc0, 0xda, 0x0f, 0x90, 0x47, 0x12, 0x5f, 0xc5, 0xe9, + 0x82, 0xe6, 0x11, 0x2d, 0x10, 0x1e, 0x91, 0x33, 0x19, 0xb4, 0x11, 0x7e, 0x27, 0xe1, 0x47, 0x07, 0xe1, 0x33, 0x13, + 0xc0, 0x84, 0x83, 0xac, 0x89, 0x2a, 0xe3, 0x5a, 0x63, 0xf1, 0x11, 0x9e, 0x6f, 0xa9, 0x94, 0x53, 0xf0, 0x2e, 0x20, + 0x3c, 0xae, 0x85, 0x3b, 0xf1, 0x35, 0xb1, 0x24, 0xf1, 0x5e, 0x50, 0xfa, 0x5d, 0x9c, 0x7e, 0xa4, 0x22, 0xb8, 0xc1, + 0xed, 0xce, 0xe7, 0x58, 0xb9, 0xa0, 0xf7, 0xda, 0xa8, 0x5b, 0xc6, 0xaa, 0x4e, 0xa5, 0x8e, 0x11, 0x80, 0x90, 0xad, + 0xfb, 0x62, 0x60, 0xc7, 0xf7, 0xc4, 0x86, 0xc3, 0x4a, 0xc4, 0xd7, 0x3e, 0xaa, 0xc7, 0x45, 0x59, 0x76, 0x15, 0xa7, + 0x2c, 0xf1, 0x24, 0x9d, 0xcd, 0xd3, 0x58, 0x52, 0xcf, 0xac, 0xd7, 0x8b, 0x61, 0x20, 0xbf, 0x54, 0x19, 0x12, 0xc7, + 0xe0, 0x4c, 0x6c, 0xc0, 0x09, 0xce, 0x4a, 0x00, 0xd1, 0x29, 0xa3, 0x76, 0xbc, 0xae, 0x82, 0x5f, 0xeb, 0xf1, 0xbd, + 0x66, 0x1b, 0x1c, 0x61, 0x43, 0x25, 0x9e, 0x73, 0x9c, 0x11, 0x10, 0xa2, 0x9d, 0xbe, 0x7f, 0x9c, 0x5f, 0x4d, 0x7a, + 0x3e, 0xc4, 0x66, 0x38, 0x79, 0xab, 0xfc, 0x42, 0xd0, 0x60, 0x4a, 0x5a, 0xdd, 0xe9, 0x31, 0xed, 0x4e, 0x1b, 0x0d, + 0xab, 0x43, 0xa7, 0x44, 0x0c, 0xa6, 0xba, 0x7b, 0x8c, 0x13, 0xbc, 0x20, 0xcd, 0x36, 0x9e, 0x90, 0x96, 0xea, 0xd2, + 0x9d, 0x1c, 0xa7, 0x66, 0x9a, 0x83, 0x83, 0x80, 0x87, 0x69, 0x9c, 0xcb, 0x2f, 0xc1, 0xd8, 0x27, 0x13, 0x9c, 0x10, + 0x1e, 0xd2, 0x1b, 0x3a, 0x0a, 0x52, 0x84, 0x13, 0xc3, 0x69, 0x50, 0x17, 0x4d, 0x88, 0xd3, 0x0c, 0x8c, 0x08, 0xf2, + 0xb6, 0x9f, 0x0c, 0xda, 0x43, 0x42, 0x88, 0xbf, 0xd7, 0x6c, 0xfa, 0x7d, 0x4e, 0x16, 0x32, 0x82, 0x12, 0x47, 0x55, + 0x26, 0x73, 0x28, 0xea, 0x38, 0x45, 0xc1, 0x0b, 0x19, 0x4a, 0x9a, 0xcb, 0x00, 0x8a, 0xc1, 0xfc, 0xcf, 0x2d, 0x61, + 0xfb, 0xc7, 0x87, 0x7e, 0x03, 0x4a, 0x15, 0x71, 0x22, 0xcc, 0xc9, 0x25, 0x8a, 0x92, 0xc1, 0xd1, 0xd0, 0xe5, 0xff, + 0xaa, 0x10, 0x26, 0xbf, 0xec, 0x27, 0x83, 0x96, 0x9a, 0xbc, 0xe7, 0xf7, 0x03, 0x4e, 0x72, 0xad, 0xa0, 0xf5, 0xf3, + 0xe8, 0xad, 0x5a, 0x2a, 0x8a, 0x0c, 0x70, 0x66, 0xde, 0x05, 0x69, 0x76, 0xa2, 0x60, 0xe1, 0x2e, 0xa2, 0x09, 0x93, + 0x19, 0x2c, 0xe0, 0x98, 0x40, 0x7b, 0xcc, 0x09, 0xcc, 0x58, 0x75, 0xbb, 0x8c, 0xcc, 0xf3, 0x03, 0xff, 0x41, 0xff, + 0x4a, 0x46, 0x13, 0xa9, 0xa7, 0xbf, 0x92, 0xab, 0x15, 0xfc, 0x3f, 0x91, 0x7d, 0x4e, 0x2e, 0x55, 0xd1, 0xc2, 0x14, + 0xcd, 0xa1, 0xe8, 0x6d, 0x04, 0xa0, 0xe2, 0xbc, 0x54, 0xb2, 0xf4, 0x9e, 0x5c, 0x11, 0x05, 0xfb, 0xc1, 0x81, 0x18, + 0x4c, 0x1b, 0xed, 0x21, 0xf8, 0xf7, 0x85, 0xcc, 0xbf, 0x63, 0x72, 0x1a, 0xf8, 0x87, 0x3d, 0x1f, 0xf5, 0x7d, 0x0f, + 0xb6, 0xb6, 0x9b, 0x35, 0x88, 0xc6, 0x70, 0xda, 0x78, 0x23, 0xa3, 0x45, 0x8f, 0xb4, 0xfa, 0x01, 0x33, 0xfe, 0x3c, + 0x84, 0x53, 0xc3, 0x38, 0x5b, 0x78, 0x81, 0x1a, 0x52, 0x36, 0xec, 0xf3, 0x02, 0x35, 0x66, 0x8d, 0x2b, 0x14, 0xa5, + 0x8d, 0x59, 0x23, 0x58, 0x10, 0x42, 0x9a, 0x9d, 0xb2, 0x9b, 0x95, 0x7e, 0x53, 0x14, 0x5d, 0x59, 0x67, 0xe7, 0x40, + 0x1d, 0x87, 0xac, 0x11, 0x88, 0x01, 0x1d, 0xae, 0x56, 0xfe, 0x71, 0xbf, 0xe7, 0xa3, 0x46, 0x60, 0x09, 0xed, 0xd0, + 0x52, 0x1a, 0x42, 0x98, 0x0d, 0x0b, 0x13, 0x4a, 0x7a, 0x59, 0x0b, 0x1b, 0x2d, 0xab, 0xc3, 0xee, 0xf0, 0x00, 0x5a, + 0x94, 0x76, 0x8c, 0xd6, 0x57, 0xe7, 0xb0, 0x4c, 0x4b, 0xcc, 0x19, 0x69, 0x61, 0x4e, 0xac, 0xef, 0x7a, 0x4a, 0x64, + 0x45, 0xf0, 0x29, 0xa9, 0x9a, 0xe3, 0x41, 0x8c, 0x93, 0x21, 0x79, 0xad, 0xed, 0x91, 0xae, 0xf5, 0x8b, 0xd3, 0x94, + 0xbc, 0x5c, 0x8b, 0xde, 0xc6, 0x10, 0x5b, 0xb9, 0x0e, 0x47, 0x0b, 0x21, 0x68, 0x26, 0xdf, 0xf0, 0xc4, 0xa8, 0x69, + 0x34, 0x05, 0x4b, 0x09, 0xc2, 0xb2, 0x18, 0x74, 0xb4, 0x8e, 0x3d, 0x19, 0x8b, 0x8d, 0xea, 0x09, 0x59, 0x68, 0xf5, + 0x49, 0x05, 0x6b, 0xbb, 0x13, 0x63, 0x17, 0x07, 0x08, 0x2f, 0x4c, 0x14, 0x37, 0x08, 0xc3, 0x70, 0x12, 0x8e, 0xa0, + 0x1a, 0x26, 0xc8, 0x51, 0xa1, 0xce, 0x51, 0x90, 0x93, 0xeb, 0x30, 0xa3, 0x37, 0x6a, 0xd6, 0x00, 0x55, 0x92, 0xd9, + 0x1e, 0xaf, 0xe3, 0x69, 0x57, 0xb1, 0x9b, 0x3c, 0xcc, 0x78, 0x42, 0x01, 0x3d, 0x10, 0xb7, 0x37, 0x45, 0xd3, 0x38, + 0x77, 0xe3, 0x53, 0x15, 0x7c, 0x03, 0xd7, 0x79, 0x3d, 0x01, 0x8f, 0xaf, 0xd2, 0xb5, 0xca, 0xc6, 0xda, 0x0d, 0x8e, + 0x10, 0x1b, 0x07, 0x93, 0x10, 0xe2, 0x7a, 0x8a, 0x84, 0x24, 0x98, 0x72, 0x13, 0x97, 0xa8, 0x66, 0xe5, 0x98, 0x57, + 0x24, 0x19, 0xf0, 0x46, 0x43, 0x79, 0xa1, 0x17, 0x9a, 0x24, 0x26, 0x08, 0x5f, 0x95, 0x67, 0xcb, 0xb6, 0x7b, 0x2b, + 0x49, 0x7d, 0xaa, 0xe0, 0xaa, 0xee, 0xce, 0x6d, 0x48, 0x89, 0x94, 0xa7, 0x50, 0x06, 0x33, 0x84, 0x9f, 0x91, 0xc3, + 0x60, 0x10, 0xf6, 0xff, 0x32, 0x44, 0xfd, 0x20, 0xfc, 0x33, 0x3a, 0xd4, 0x9c, 0xe3, 0x0a, 0x75, 0x53, 0x3d, 0xc7, + 0x52, 0xc5, 0x2f, 0xdb, 0x58, 0x79, 0x12, 0xa3, 0x0c, 0x67, 0xf1, 0x8c, 0x46, 0xcf, 0xe0, 0x90, 0x5b, 0xc2, 0x79, + 0x2b, 0x31, 0x50, 0x52, 0xf4, 0xcc, 0xf0, 0x92, 0xd0, 0xef, 0xbf, 0x92, 0xe5, 0x53, 0xdf, 0xef, 0x3f, 0xaf, 0x9e, + 0xfe, 0xe2, 0xf7, 0x7f, 0x91, 0xd1, 0xcf, 0x85, 0xf1, 0x76, 0xd7, 0xe6, 0x78, 0x6c, 0xe7, 0x28, 0xf4, 0xd6, 0x38, + 0xb8, 0x5b, 0xa0, 0x4d, 0x47, 0xc7, 0x04, 0x15, 0x6c, 0x5c, 0x32, 0xa3, 0x3c, 0x94, 0xf1, 0x04, 0x90, 0xea, 0xec, + 0x41, 0xee, 0xc6, 0xf5, 0xab, 0x15, 0x03, 0xa9, 0x58, 0x7a, 0x05, 0x64, 0x4e, 0x7a, 0x2d, 0xb4, 0xac, 0xb5, 0x55, + 0x3a, 0x53, 0x3d, 0x8e, 0x5e, 0xf2, 0xe9, 0x2b, 0xd2, 0xea, 0x5e, 0x1d, 0x4f, 0xba, 0x57, 0x8d, 0x06, 0xca, 0x2d, + 0x69, 0x2d, 0x06, 0x57, 0x43, 0xfc, 0x35, 0x38, 0xf5, 0x5c, 0x5a, 0xc2, 0xb5, 0xe5, 0x75, 0xcc, 0xf2, 0x1a, 0x8d, + 0xac, 0x40, 0x5d, 0xa7, 0xeb, 0x44, 0x77, 0x2d, 0x0a, 0x8d, 0x93, 0x75, 0x52, 0x7b, 0x8a, 0x54, 0x09, 0x24, 0x43, + 0x11, 0x42, 0x6e, 0x24, 0xda, 0x3a, 0x2a, 0x8c, 0x09, 0xdd, 0xd5, 0x99, 0x05, 0xf6, 0xa9, 0xa5, 0x44, 0x00, 0x58, + 0x80, 0xae, 0xa5, 0x27, 0x78, 0x86, 0x17, 0x8d, 0xb6, 0x22, 0xf3, 0x66, 0xbb, 0x5b, 0x1f, 0xeb, 0x49, 0x35, 0x16, + 0x5e, 0x34, 0xc8, 0xac, 0xc4, 0x52, 0x91, 0x35, 0x1a, 0x45, 0x3d, 0xd8, 0x69, 0x4f, 0x6e, 0x2d, 0x00, 0x71, 0xb3, + 0x9e, 0x94, 0x61, 0x25, 0x6c, 0x25, 0x53, 0x59, 0xc8, 0xb2, 0x8c, 0x0a, 0x90, 0xa2, 0x44, 0x62, 0x56, 0x14, 0x95, + 0x64, 0x07, 0x31, 0x8a, 0x29, 0x11, 0xc0, 0x79, 0x94, 0xdd, 0x85, 0x33, 0xcc, 0xf1, 0x54, 0xf1, 0x0d, 0x42, 0xc8, + 0x99, 0x4d, 0x67, 0x91, 0x8a, 0x07, 0xa5, 0x84, 0x39, 0x32, 0x29, 0x27, 0x34, 0x3c, 0xdf, 0x3f, 0xe5, 0x77, 0xda, + 0x64, 0x03, 0x36, 0x8c, 0x54, 0xb3, 0xd4, 0x70, 0xae, 0x98, 0x7c, 0x08, 0x24, 0x2a, 0xa3, 0x23, 0xa1, 0x62, 0x80, + 0xcf, 0x99, 0xa0, 0x4a, 0x07, 0xdf, 0xb7, 0x76, 0x5f, 0x5a, 0x57, 0x20, 0x53, 0xd7, 0x7b, 0x03, 0x88, 0x8c, 0xc1, + 0xb9, 0x93, 0x91, 0x8d, 0x66, 0xe7, 0xfb, 0x27, 0x6f, 0xb7, 0xd9, 0xc0, 0xab, 0x95, 0xb1, 0x7e, 0x95, 0x6e, 0x83, + 0xe3, 0x0a, 0xd2, 0xd4, 0xfc, 0x88, 0x82, 0x54, 0xa9, 0x48, 0x71, 0x20, 0x80, 0x8a, 0xce, 0xf7, 0x4f, 0xde, 0x07, + 0x42, 0xf9, 0x96, 0x10, 0x76, 0x97, 0x1d, 0x70, 0x12, 0x4c, 0x09, 0x45, 0x7a, 0xed, 0x25, 0xeb, 0xe2, 0x8e, 0x00, + 0x8f, 0xa6, 0xaa, 0x12, 0x2c, 0x88, 0x01, 0x1b, 0x92, 0xd4, 0x60, 0x80, 0xa4, 0x08, 0xa7, 0x35, 0xbb, 0x8c, 0xc0, + 0x06, 0xa8, 0xb9, 0xce, 0x60, 0x27, 0x42, 0xad, 0xfa, 0x21, 0x9c, 0xaa, 0x59, 0x65, 0xa1, 0x85, 0xc7, 0xb3, 0x8d, + 0xac, 0xb4, 0xca, 0x1c, 0xfd, 0x16, 0x6c, 0x27, 0xfb, 0xf0, 0x86, 0x58, 0x4b, 0xc2, 0x14, 0x3c, 0xb7, 0xe9, 0x63, + 0xe7, 0xfb, 0x27, 0xaf, 0x4d, 0x06, 0xd9, 0x3c, 0xb6, 0xfc, 0x7e, 0xc3, 0xc4, 0x3c, 0x79, 0x1d, 0x56, 0xb5, 0xaa, + 0xf1, 0xf9, 0xfe, 0xc9, 0x87, 0x6d, 0xcd, 0xa0, 0xbc, 0x58, 0x54, 0x36, 0xbe, 0x82, 0x6f, 0x49, 0xd3, 0x68, 0x69, + 0x84, 0x43, 0xc4, 0x0a, 0xac, 0x04, 0x52, 0x94, 0x17, 0xa5, 0x6b, 0xe4, 0x39, 0xce, 0x88, 0x0a, 0x03, 0xd5, 0x77, + 0xcd, 0xa8, 0x79, 0x8c, 0x67, 0x67, 0x23, 0x3e, 0xa7, 0x3b, 0x62, 0x43, 0x37, 0x28, 0x64, 0x33, 0x48, 0x9d, 0x51, + 0xa0, 0x33, 0xbc, 0xd7, 0x42, 0xdd, 0xba, 0xf8, 0xca, 0x14, 0x91, 0xf2, 0x9a, 0x6c, 0xc1, 0x53, 0xd2, 0xc2, 0x29, + 0x69, 0xe1, 0x98, 0xe4, 0x83, 0x96, 0x16, 0x10, 0xdd, 0xb8, 0x1c, 0x57, 0x8b, 0x19, 0xc8, 0x0a, 0x33, 0xa7, 0x55, + 0x0b, 0xe0, 0xa4, 0x1b, 0x2b, 0xdf, 0xa3, 0x92, 0xe9, 0x89, 0x22, 0x8b, 0xf7, 0x01, 0xc7, 0x5c, 0x0d, 0x7c, 0xc6, + 0x2e, 0x53, 0x48, 0x2c, 0x81, 0x55, 0x61, 0x89, 0xa2, 0xb2, 0x69, 0xdb, 0x34, 0x8d, 0x43, 0xb5, 0x4f, 0x1c, 0xc7, + 0x21, 0x70, 0x6e, 0x1c, 0x9b, 0x3c, 0x9c, 0x7c, 0xb3, 0xcb, 0xe3, 0x83, 0x83, 0x40, 0x77, 0xfa, 0x52, 0x06, 0xdc, + 0xd6, 0x57, 0x91, 0xbb, 0x6f, 0x35, 0xaf, 0x48, 0x90, 0x82, 0xbf, 0xd1, 0x48, 0x87, 0x05, 0x84, 0xa1, 0x83, 0xb8, + 0x8e, 0x41, 0x0b, 0xbc, 0xd2, 0xf5, 0xea, 0xcb, 0x6f, 0x34, 0xca, 0x28, 0x6d, 0x1d, 0x5b, 0x37, 0x38, 0x2b, 0xae, + 0x82, 0x32, 0xf5, 0xa7, 0xb5, 0x91, 0x2f, 0x65, 0x41, 0x40, 0xcc, 0xa5, 0x59, 0x66, 0x17, 0xe3, 0x1c, 0x09, 0x06, + 0xed, 0xbe, 0x34, 0x59, 0x0b, 0x58, 0x65, 0x57, 0x99, 0x46, 0x96, 0x9d, 0x75, 0x50, 0x64, 0x1b, 0x41, 0x54, 0x0a, + 0x1a, 0x35, 0x0a, 0x43, 0xde, 0xef, 0x37, 0x73, 0x2e, 0x71, 0x8e, 0x8c, 0x93, 0x4b, 0x41, 0xa1, 0x90, 0xd5, 0x29, + 0x91, 0xf2, 0x92, 0xcc, 0x77, 0x93, 0xfc, 0x89, 0x43, 0xf2, 0xcf, 0x08, 0x75, 0xc8, 0x5f, 0xbb, 0x38, 0x42, 0x6e, + 0x9c, 0x0b, 0xb9, 0xad, 0x3a, 0x9d, 0x13, 0x70, 0xa2, 0xd5, 0x31, 0x5a, 0x0b, 0x2b, 0xee, 0x60, 0x28, 0xee, 0x09, + 0x51, 0x6e, 0x48, 0x6c, 0x63, 0xc0, 0x41, 0x15, 0x54, 0x83, 0xa9, 0xb7, 0xf9, 0xf4, 0x5c, 0x0e, 0x78, 0xf2, 0xe1, + 0xee, 0x78, 0xe8, 0xe9, 0x7c, 0xf3, 0xe4, 0x3a, 0xb9, 0x9f, 0xb0, 0x6a, 0xe7, 0xe0, 0xd6, 0x33, 0x41, 0x61, 0xfe, + 0x32, 0x8e, 0x5d, 0x67, 0x3e, 0x6b, 0x87, 0xd0, 0xca, 0x3f, 0x80, 0xb6, 0xdd, 0x56, 0x2d, 0xa8, 0x33, 0x2c, 0xf0, + 0x23, 0x9d, 0x81, 0x1a, 0x8b, 0x1d, 0xec, 0xe3, 0x44, 0x35, 0xa0, 0x59, 0xb2, 0xbd, 0xfa, 0x59, 0x61, 0xc8, 0x44, + 0x83, 0x86, 0x96, 0xc0, 0xff, 0x34, 0xc9, 0x03, 0xdd, 0x28, 0xb9, 0x00, 0x08, 0x9a, 0x2b, 0x3c, 0x55, 0x08, 0xf3, + 0xfd, 0xca, 0xfb, 0xfe, 0x72, 0x8f, 0x90, 0x79, 0xe5, 0x7d, 0x7c, 0x57, 0xa5, 0x5e, 0x01, 0x59, 0xa0, 0x08, 0xcc, + 0xc7, 0xb2, 0x40, 0x87, 0x2f, 0xcf, 0x6c, 0x73, 0x65, 0x42, 0x86, 0x95, 0xc6, 0xed, 0x84, 0x36, 0x95, 0x5b, 0x4e, + 0xd7, 0x5b, 0x34, 0xac, 0xd5, 0xee, 0x43, 0xed, 0x7b, 0xa9, 0x60, 0x84, 0xe7, 0xf7, 0xaa, 0xb5, 0x1d, 0xb7, 0xf8, + 0xb8, 0x9e, 0xbf, 0xb2, 0xb6, 0x29, 0x21, 0xcb, 0x72, 0x2a, 0xe4, 0x33, 0x3a, 0xe6, 0x02, 0x62, 0x16, 0x25, 0x4e, + 0x50, 0xb1, 0xef, 0xf8, 0xed, 0xd4, 0xfa, 0x9c, 0x40, 0xc1, 0xda, 0x02, 0xd5, 0xaf, 0x8f, 0x2a, 0x68, 0x7d, 0xbe, + 0xde, 0x6b, 0x7e, 0x70, 0xf0, 0xa1, 0x42, 0x93, 0x81, 0x52, 0x41, 0xe1, 0x30, 0x2d, 0xad, 0xd2, 0x98, 0x48, 0xee, + 0x7e, 0x50, 0x3a, 0x01, 0x2c, 0xc3, 0x70, 0x79, 0xcf, 0x4b, 0x22, 0x8b, 0xc9, 0x3a, 0x8b, 0x37, 0xce, 0x09, 0xe6, + 0x1a, 0x2e, 0xc0, 0xe1, 0xc1, 0xd4, 0xd6, 0xde, 0xa2, 0xbc, 0x4a, 0x86, 0x2d, 0x61, 0x38, 0x05, 0x64, 0x05, 0xca, + 0x0c, 0x71, 0x28, 0x70, 0xab, 0x59, 0x72, 0x0a, 0x7a, 0xe5, 0x14, 0xe7, 0xe1, 0x14, 0xd2, 0x5f, 0x6b, 0x47, 0x16, + 0x21, 0xac, 0x13, 0x73, 0x9c, 0x54, 0x82, 0x93, 0x97, 0xdb, 0x5c, 0xca, 0x96, 0xa8, 0xa9, 0x92, 0x3a, 0xaa, 0x05, + 0x2a, 0x3b, 0x84, 0x57, 0x01, 0x33, 0x8a, 0x9b, 0x8d, 0x9b, 0x01, 0x03, 0x7e, 0x26, 0x03, 0x1d, 0x8c, 0x02, 0x99, + 0xc1, 0xc3, 0x45, 0x50, 0x9b, 0xba, 0xcb, 0x55, 0x37, 0x6c, 0x10, 0x37, 0x75, 0xd1, 0xc4, 0x55, 0x5c, 0xef, 0xb4, + 0xe2, 0xa5, 0x63, 0x9d, 0x41, 0x2d, 0x2d, 0x17, 0xac, 0x12, 0x49, 0x9c, 0xe5, 0x8f, 0x75, 0x52, 0x74, 0xd9, 0x08, + 0x53, 0x05, 0xc6, 0x4b, 0xb5, 0x07, 0xb4, 0x00, 0xfa, 0x5a, 0x9e, 0x48, 0x67, 0x47, 0xad, 0x13, 0x5b, 0xcd, 0xe9, + 0x48, 0xfd, 0x77, 0x90, 0xea, 0xb2, 0x7e, 0xe6, 0x5f, 0x2a, 0x59, 0xc8, 0x70, 0x5e, 0x63, 0xec, 0x99, 0x62, 0xec, + 0x08, 0xf4, 0x34, 0x9b, 0xf8, 0xdd, 0x37, 0x19, 0x2f, 0xcc, 0x48, 0x39, 0x43, 0x62, 0x5f, 0x97, 0xd1, 0x72, 0xe7, + 0xf7, 0xda, 0x6e, 0x44, 0x8c, 0x40, 0x16, 0x10, 0x36, 0x9c, 0x3d, 0x43, 0x38, 0x6f, 0x34, 0xba, 0xf9, 0x31, 0xad, + 0x9c, 0x24, 0x15, 0x8c, 0x0c, 0x02, 0xba, 0x40, 0xf0, 0x35, 0x19, 0x0a, 0x21, 0x7f, 0x9b, 0x99, 0x9d, 0x83, 0xaf, + 0xfd, 0xe4, 0x5d, 0xe0, 0x72, 0x35, 0xb7, 0x6d, 0x19, 0x34, 0x85, 0xf5, 0x04, 0x55, 0xc0, 0xe5, 0xeb, 0xbb, 0x13, + 0x3c, 0x00, 0xee, 0xbd, 0x36, 0x86, 0x54, 0x34, 0xd4, 0x95, 0x9a, 0x25, 0x94, 0xa7, 0xaf, 0x8b, 0xaa, 0xac, 0x44, + 0x77, 0xb2, 0xae, 0xac, 0x8c, 0x59, 0x49, 0xf2, 0xa2, 0xc8, 0x69, 0x15, 0xde, 0x5f, 0x4b, 0xbf, 0x54, 0xc2, 0x65, + 0xd3, 0xdb, 0x7e, 0x3a, 0x27, 0x12, 0x3b, 0x84, 0xfa, 0xf5, 0xae, 0xd8, 0x47, 0x05, 0x26, 0x9c, 0x6b, 0x23, 0x14, + 0x7f, 0xde, 0x26, 0x14, 0x71, 0x66, 0x8e, 0xbc, 0x12, 0x88, 0xed, 0x7b, 0x08, 0x44, 0xe3, 0x66, 0xb7, 0x32, 0x11, + 0xd4, 0x91, 0x9a, 0x4c, 0xac, 0x6f, 0x29, 0xc9, 0x30, 0x33, 0xbb, 0xd1, 0xeb, 0xac, 0x56, 0x6c, 0xd0, 0x02, 0x37, + 0x92, 0xef, 0xc3, 0xcf, 0xb6, 0xfe, 0xe9, 0x70, 0x62, 0xed, 0x06, 0x0e, 0x58, 0x69, 0xb2, 0xa0, 0x10, 0x12, 0x9c, + 0x03, 0x95, 0x94, 0xa5, 0x68, 0xda, 0x50, 0x90, 0x21, 0x70, 0xc2, 0xca, 0x30, 0x13, 0x40, 0xac, 0x64, 0x85, 0x31, + 0x20, 0x83, 0xad, 0xb9, 0x7f, 0xd6, 0xbc, 0xfc, 0xb4, 0x26, 0x5a, 0x93, 0x2b, 0x5a, 0x7d, 0xa8, 0xe5, 0x1b, 0x18, + 0x08, 0x8c, 0x7e, 0xb8, 0xa7, 0x4c, 0xd0, 0x4a, 0x94, 0x23, 0x57, 0x0e, 0xe1, 0x16, 0x38, 0xd1, 0xf6, 0x3e, 0xe8, + 0x08, 0xef, 0x16, 0x69, 0x82, 0xb9, 0x43, 0xd7, 0x2f, 0x89, 0xac, 0xb1, 0x92, 0x29, 0x31, 0x96, 0x12, 0x8e, 0x15, + 0x99, 0x4a, 0x92, 0x0d, 0x5a, 0x43, 0x50, 0x40, 0xbb, 0xe9, 0x71, 0x56, 0x99, 0xc0, 0x69, 0xa3, 0x81, 0x62, 0x3b, + 0xeb, 0x74, 0xc0, 0x1a, 0xe9, 0x10, 0x53, 0x9c, 0x6a, 0xc3, 0xe4, 0xec, 0xe0, 0x20, 0x88, 0xab, 0x79, 0x07, 0xe9, + 0x10, 0x61, 0xbe, 0x5a, 0x05, 0x0a, 0xac, 0x18, 0xad, 0x56, 0xb1, 0x0b, 0x96, 0xaa, 0x86, 0x6e, 0xf3, 0xbe, 0x24, + 0x73, 0x25, 0x00, 0xe7, 0x00, 0x61, 0x83, 0x04, 0xb1, 0x71, 0xef, 0xc5, 0xe0, 0x8e, 0x6a, 0x64, 0x83, 0xb4, 0xd1, + 0x1e, 0x3a, 0x8c, 0x6b, 0x90, 0x0e, 0x49, 0x5c, 0xf0, 0x83, 0x83, 0xbd, 0xdc, 0x88, 0xc8, 0x9f, 0x40, 0x94, 0xfd, + 0xa4, 0x24, 0x8b, 0x1e, 0xd0, 0xdd, 0x8d, 0x75, 0x67, 0x40, 0x49, 0x51, 0x66, 0x5b, 0x6d, 0xbb, 0x5a, 0x16, 0x44, + 0xd9, 0x08, 0x9b, 0x60, 0x70, 0x1f, 0x2c, 0xfb, 0x92, 0xcc, 0x5f, 0xc9, 0x32, 0xc7, 0xfa, 0xe7, 0xad, 0x99, 0xd5, + 0x61, 0x18, 0xc6, 0x62, 0xa2, 0x62, 0x19, 0x36, 0x0c, 0xab, 0x88, 0xff, 0xc8, 0x80, 0xe9, 0x4c, 0x3c, 0x28, 0xe7, + 0x1a, 0x12, 0x0d, 0xbe, 0x55, 0x6d, 0xec, 0x5d, 0x92, 0x9f, 0xb6, 0x7a, 0x19, 0x34, 0x24, 0xcf, 0x7f, 0x2b, 0x24, + 0x0f, 0x0d, 0x24, 0x9a, 0x3c, 0xd6, 0x70, 0xb6, 0x03, 0x17, 0x3f, 0xc9, 0x35, 0x9c, 0xed, 0xc6, 0xad, 0xc5, 0xd4, + 0x2f, 0xbb, 0xe0, 0x73, 0x78, 0x83, 0x06, 0xb4, 0x2a, 0x70, 0xa0, 0x7c, 0xb4, 0xae, 0x7b, 0x69, 0x56, 0x0a, 0xc2, + 0x54, 0x92, 0x80, 0xd5, 0x0f, 0x40, 0xa5, 0x8d, 0x3a, 0x86, 0x2f, 0x8b, 0xe6, 0xc8, 0x71, 0x09, 0xd4, 0x53, 0x57, + 0x80, 0x9c, 0x8c, 0xb7, 0x7d, 0x7e, 0x70, 0x00, 0xb6, 0x01, 0x28, 0x71, 0xe1, 0x28, 0x9e, 0xcb, 0x85, 0x00, 0x55, + 0x2a, 0xb7, 0xbf, 0xa1, 0x18, 0x6e, 0x81, 0xa8, 0x32, 0xf8, 0x01, 0x05, 0xf3, 0x38, 0xcf, 0xd9, 0x95, 0x2e, 0x33, + 0xbf, 0x31, 0x27, 0x96, 0x94, 0x73, 0xad, 0x13, 0x66, 0xa8, 0x9b, 0x19, 0x3a, 0xad, 0xa3, 0xed, 0xc5, 0x15, 0xcd, + 0xe4, 0x2b, 0x96, 0x4b, 0x9a, 0xc1, 0xf2, 0x2b, 0x8a, 0x83, 0x15, 0xe5, 0x08, 0x0e, 0x6c, 0xad, 0x57, 0x9c, 0x24, + 0x77, 0x76, 0x91, 0x75, 0x1d, 0x68, 0x1a, 0x67, 0x49, 0xaa, 0x27, 0x71, 0xf3, 0x19, 0x6d, 0x0e, 0x67, 0xd9, 0xd2, + 0xcd, 0xa7, 0xa9, 0x94, 0x0d, 0xc5, 0xdd, 0x03, 0x46, 0xac, 0x24, 0xb0, 0xd2, 0xf3, 0x4e, 0xad, 0x05, 0x22, 0xde, + 0x3b, 0x36, 0xc1, 0x5d, 0x09, 0x96, 0x0e, 0x47, 0x0d, 0xeb, 0x70, 0x5a, 0xba, 0xf9, 0x72, 0xeb, 0x95, 0xb6, 0x6d, + 0xc2, 0x41, 0xd1, 0xc9, 0xe3, 0xdd, 0x96, 0xd5, 0x6b, 0x2b, 0x39, 0xac, 0xb4, 0x60, 0xf7, 0x65, 0xcc, 0x68, 0x69, + 0xc9, 0x0b, 0xd9, 0xa3, 0xb8, 0x2f, 0xc9, 0x73, 0xb8, 0x33, 0xf4, 0x52, 0xce, 0xd2, 0xb5, 0xab, 0x31, 0xdd, 0xfd, + 0x52, 0xfb, 0xdf, 0x97, 0xc1, 0x4b, 0xfc, 0x1e, 0x02, 0xbb, 0x5f, 0x55, 0xcd, 0x37, 0x03, 0xba, 0x5f, 0x55, 0x08, + 0xfa, 0x2a, 0xda, 0x68, 0xe7, 0x04, 0x72, 0x3b, 0xe1, 0xd3, 0xb0, 0xe5, 0x5b, 0x6d, 0xe9, 0x67, 0x1d, 0x46, 0xd2, + 0x99, 0x96, 0xea, 0x3c, 0xe0, 0x2a, 0x4f, 0x0d, 0xf2, 0xe5, 0xea, 0x16, 0x12, 0x35, 0x19, 0x86, 0x5a, 0x87, 0xdf, + 0xb5, 0x3d, 0x46, 0xc6, 0x64, 0xda, 0xce, 0xf8, 0x3a, 0x16, 0x72, 0x1f, 0x4e, 0x19, 0xdf, 0xb8, 0x87, 0x37, 0x25, + 0xe0, 0x41, 0xbb, 0xdf, 0x14, 0x8e, 0xb1, 0x9d, 0xeb, 0x7b, 0x40, 0xee, 0xf8, 0x84, 0x5b, 0xdd, 0xad, 0x6e, 0x65, + 0x7c, 0x0d, 0xf6, 0x3f, 0xc2, 0x53, 0x7b, 0x39, 0x8e, 0x1a, 0x0e, 0x4c, 0xa3, 0x65, 0x51, 0x3a, 0x05, 0xb8, 0x56, + 0xde, 0x04, 0xc2, 0xbc, 0x50, 0x01, 0xee, 0x1f, 0xf0, 0x37, 0x86, 0x25, 0x8e, 0x4b, 0x8e, 0x73, 0x72, 0x5f, 0x8e, + 0xa8, 0xc1, 0x2f, 0xe3, 0xf7, 0x40, 0xc7, 0x8a, 0x42, 0x0b, 0x4b, 0x45, 0xcf, 0xb9, 0x59, 0xc8, 0xce, 0xb4, 0x54, + 0x4c, 0xcb, 0x94, 0x1a, 0x35, 0xcd, 0x96, 0x3c, 0x4e, 0x6b, 0x65, 0xcb, 0xf2, 0x54, 0xd5, 0xe6, 0x45, 0x3b, 0xb0, + 0x58, 0x85, 0x16, 0x57, 0xab, 0xa0, 0x8e, 0x6a, 0xc2, 0x9c, 0x48, 0x06, 0xc2, 0xcc, 0xc9, 0xa8, 0xa8, 0x69, 0xd6, + 0xba, 0x4f, 0x80, 0xd6, 0x13, 0x8a, 0xac, 0x6e, 0x5e, 0x83, 0xc3, 0x75, 0x21, 0xe8, 0xee, 0xae, 0x4f, 0x01, 0xeb, + 0xd5, 0x95, 0x13, 0x39, 0x18, 0xfa, 0xb9, 0x4c, 0x95, 0xad, 0x72, 0x5a, 0xb7, 0xe0, 0x17, 0xdd, 0x91, 0x2c, 0x6b, + 0x50, 0xb7, 0x59, 0xef, 0x24, 0x1b, 0x3d, 0xe7, 0xbb, 0x92, 0x8d, 0x6a, 0xda, 0xee, 0x5e, 0x0b, 0xdd, 0x9d, 0x96, + 0xaa, 0xe7, 0xda, 0xde, 0xe4, 0x37, 0x4c, 0xd7, 0x06, 0xda, 0xd4, 0x68, 0xb6, 0x5c, 0xe5, 0xac, 0x28, 0xc6, 0xe5, + 0x65, 0x02, 0x95, 0xbb, 0x33, 0xd6, 0xf4, 0x6f, 0xac, 0x46, 0x75, 0x1d, 0x37, 0xf8, 0x81, 0x4c, 0x52, 0x7e, 0x19, + 0xa7, 0xef, 0x61, 0xbe, 0xaa, 0xf2, 0xe5, 0x6d, 0x22, 0x62, 0x49, 0x0d, 0x77, 0xa9, 0x60, 0xf8, 0xc1, 0x81, 0xe1, + 0x07, 0xcd, 0xa7, 0xab, 0xfe, 0x78, 0xf9, 0xaa, 0x1c, 0x20, 0x1a, 0x17, 0x96, 0x65, 0x9c, 0xcb, 0xed, 0x73, 0xac, + 0xb3, 0xb0, 0xf3, 0x92, 0x85, 0x9d, 0xcb, 0x60, 0x7d, 0xa8, 0x20, 0xf8, 0x66, 0xfb, 0x28, 0x9b, 0x9c, 0xed, 0x9b, + 0xea, 0xe0, 0x7f, 0x13, 0xdd, 0xd9, 0xc7, 0xe1, 0x72, 0x47, 0xe1, 0x91, 0x4a, 0x57, 0xd1, 0x20, 0xbf, 0x83, 0xb4, + 0x03, 0x49, 0x7a, 0xce, 0x9d, 0x83, 0x4a, 0x4e, 0xd9, 0x44, 0xa0, 0x60, 0xb4, 0xc8, 0x25, 0x9f, 0x99, 0x31, 0x73, + 0x73, 0xcd, 0x48, 0x55, 0x82, 0x2b, 0x5a, 0x45, 0xdb, 0xa3, 0xfa, 0x45, 0xae, 0xe5, 0x47, 0x96, 0x25, 0x51, 0x8e, + 0x8d, 0x14, 0xc9, 0xa3, 0xac, 0x20, 0x36, 0xd9, 0x78, 0xb3, 0x0e, 0x8f, 0x59, 0xc6, 0xf2, 0x29, 0x15, 0x01, 0x47, + 0xcb, 0x5d, 0x93, 0x71, 0x08, 0xc8, 0xe8, 0xc9, 0xf0, 0xb7, 0xd5, 0x85, 0xbf, 0x10, 0x46, 0x03, 0x3f, 0xd0, 0x8c, + 0xca, 0x29, 0x4f, 0x20, 0x31, 0x25, 0x4c, 0xca, 0x1b, 0x4d, 0x07, 0x07, 0x7b, 0x81, 0xaf, 0xdc, 0x12, 0x70, 0xf5, + 0xdb, 0xad, 0x41, 0xfd, 0x25, 0x5c, 0xcf, 0xa9, 0xa6, 0xa6, 0x68, 0x49, 0xd7, 0x6f, 0xb2, 0xc8, 0xf0, 0x23, 0xbd, + 0xc5, 0x02, 0x15, 0x45, 0xa4, 0xa1, 0xf6, 0xc7, 0x8c, 0xa6, 0x89, 0x8f, 0x3f, 0xd2, 0xdb, 0xa8, 0xbc, 0x2d, 0xae, + 0x2e, 0x37, 0xab, 0x0d, 0xf4, 0xf9, 0x75, 0xe6, 0xe3, 0x6a, 0x92, 0x68, 0x59, 0x60, 0x2e, 0xd8, 0x04, 0x88, 0xf3, + 0x6f, 0xf4, 0x36, 0xd2, 0xe3, 0x31, 0xe7, 0xb2, 0x1e, 0x5a, 0x5a, 0xd4, 0x87, 0x4e, 0xb1, 0xbb, 0x0d, 0xc6, 0xa0, + 0x18, 0xa8, 0xbe, 0x43, 0x52, 0x6b, 0x57, 0x99, 0x87, 0x08, 0x15, 0xf7, 0x5d, 0x0a, 0xfe, 0xc2, 0x15, 0x6d, 0xb2, + 0x96, 0xfa, 0xba, 0xd6, 0x89, 0x42, 0x87, 0x2a, 0xd7, 0xe3, 0x3c, 0x10, 0xf6, 0xd4, 0x99, 0x3b, 0x08, 0x8e, 0x23, + 0xec, 0x0b, 0x69, 0x06, 0x8d, 0xbe, 0xd5, 0x29, 0x21, 0x55, 0x24, 0xe9, 0x75, 0xd5, 0xcf, 0x3b, 0x0f, 0x00, 0xef, + 0x90, 0xd2, 0x12, 0xab, 0xeb, 0x98, 0x85, 0x4d, 0x17, 0xfd, 0x4e, 0x92, 0x60, 0x69, 0x97, 0x10, 0x09, 0x17, 0x8b, + 0xb2, 0x00, 0x2a, 0x34, 0xf4, 0xa5, 0x33, 0x00, 0xd9, 0x38, 0x60, 0x1b, 0x52, 0x33, 0x53, 0x52, 0x33, 0x74, 0x30, + 0xbe, 0x43, 0x4a, 0x52, 0x85, 0x0c, 0xa5, 0x44, 0x2a, 0xa1, 0x67, 0x36, 0xd7, 0x90, 0x90, 0xbb, 0xa1, 0xe5, 0xf5, + 0x39, 0xbd, 0xe7, 0x59, 0x0d, 0xac, 0x40, 0x8d, 0x83, 0x8a, 0x08, 0x96, 0x44, 0x75, 0x83, 0xc2, 0xba, 0x73, 0x84, + 0xcd, 0x6f, 0x0d, 0x78, 0x68, 0x97, 0x45, 0x2c, 0x4a, 0x82, 0x29, 0x5a, 0x8a, 0x60, 0x8a, 0x33, 0xc8, 0x47, 0xe4, + 0x45, 0x09, 0x3f, 0x75, 0x77, 0xa3, 0x96, 0xad, 0xbc, 0xfd, 0x8a, 0x1f, 0x28, 0xf3, 0x12, 0x72, 0x34, 0xb1, 0xb0, + 0x3c, 0x45, 0x04, 0xea, 0xae, 0x9d, 0xb3, 0x6d, 0x5f, 0x99, 0x14, 0x1d, 0x03, 0xd8, 0x77, 0x32, 0x58, 0x3a, 0xab, + 0x70, 0xef, 0x72, 0x9b, 0x2b, 0x7f, 0x26, 0xd8, 0x57, 0x25, 0x91, 0x06, 0x39, 0x59, 0x93, 0x38, 0x77, 0xe7, 0x5a, + 0xfe, 0xbc, 0xa0, 0xe2, 0xf6, 0x8c, 0x42, 0xae, 0x33, 0x87, 0xbb, 0xbe, 0xd5, 0x36, 0x54, 0x79, 0xea, 0xfd, 0x4c, + 0x29, 0x2b, 0x45, 0xfd, 0x12, 0xe0, 0xfa, 0x15, 0xc1, 0x42, 0x45, 0x1b, 0x1d, 0x47, 0x8c, 0x3e, 0x2d, 0x74, 0xe7, + 0xe5, 0x49, 0xda, 0x65, 0xe0, 0x5f, 0xab, 0x30, 0x6d, 0x82, 0x05, 0x98, 0xbb, 0x17, 0x52, 0x07, 0xf9, 0x70, 0xdd, + 0x2b, 0x03, 0x45, 0x10, 0xbe, 0xcb, 0x76, 0x2f, 0x75, 0x5b, 0xd6, 0xec, 0xee, 0xa5, 0xd6, 0x82, 0x7e, 0x2a, 0xe5, + 0x07, 0x9b, 0x79, 0xca, 0xcb, 0xcb, 0xac, 0x28, 0x50, 0x01, 0xe0, 0x7d, 0xdf, 0x0d, 0x82, 0xef, 0x4d, 0xd2, 0x60, + 0x08, 0xb1, 0xd8, 0xb3, 0x94, 0x5b, 0x26, 0x5e, 0xcd, 0xff, 0xfd, 0xc6, 0xfc, 0xdf, 0x3b, 0x57, 0x4e, 0xc1, 0x34, + 0x9a, 0x64, 0x34, 0xb1, 0xac, 0x13, 0x69, 0x02, 0x54, 0x7a, 0x5b, 0x2e, 0xc9, 0xc7, 0x8b, 0x08, 0x34, 0xae, 0xe5, + 0x98, 0x67, 0xb2, 0x39, 0x8e, 0x67, 0x2c, 0xbd, 0x8d, 0x16, 0xac, 0x39, 0xe3, 0x19, 0xcf, 0xe7, 0xf1, 0x88, 0xe2, + 0xfc, 0x36, 0x97, 0x74, 0xd6, 0x5c, 0x30, 0xfc, 0x92, 0xa6, 0x57, 0x54, 0xb2, 0x51, 0x8c, 0xfd, 0x13, 0xc1, 0xe2, + 0xd4, 0x7b, 0x13, 0x0b, 0xc1, 0xaf, 0x7d, 0xfc, 0x8e, 0x5f, 0x72, 0xc9, 0xf1, 0xdb, 0x9b, 0xdb, 0x09, 0xcd, 0xf0, + 0x87, 0xcb, 0x45, 0x26, 0x17, 0x38, 0x8f, 0xb3, 0xbc, 0x99, 0x53, 0xc1, 0xc6, 0xdd, 0x11, 0x4f, 0xb9, 0x68, 0x42, + 0xca, 0xf6, 0x8c, 0x46, 0x29, 0x9b, 0x4c, 0xa5, 0x97, 0xc4, 0xe2, 0x63, 0xb7, 0xd9, 0x9c, 0x0b, 0x36, 0x8b, 0xc5, + 0x6d, 0x53, 0xb5, 0x88, 0x3e, 0x6b, 0x1d, 0xc5, 0x9f, 0x8f, 0x1f, 0x76, 0xa5, 0x88, 0xb3, 0x9c, 0xc1, 0x36, 0x45, + 0x71, 0x9a, 0x7a, 0x47, 0x8f, 0x5a, 0xb3, 0x7c, 0x4f, 0x07, 0xf2, 0xe2, 0x4c, 0x16, 0x17, 0xf8, 0x23, 0xc0, 0x1d, + 0x5e, 0xca, 0x0c, 0x5f, 0x2e, 0xa4, 0xe4, 0xd9, 0x72, 0xb4, 0x10, 0x39, 0x17, 0xd1, 0x9c, 0xb3, 0x4c, 0x52, 0xd1, + 0xbd, 0xe4, 0x22, 0xa1, 0xa2, 0x29, 0xe2, 0x84, 0x2d, 0xf2, 0xe8, 0xe1, 0xfc, 0xa6, 0x0b, 0x9a, 0xc5, 0x44, 0xf0, + 0x45, 0x96, 0x98, 0xb9, 0x58, 0x36, 0xa5, 0x82, 0x49, 0xb7, 0x42, 0xbd, 0xc2, 0x24, 0x4a, 0x59, 0x46, 0x63, 0xd1, + 0x9c, 0x40, 0x67, 0x30, 0x8b, 0x5a, 0x09, 0x9d, 0x60, 0x31, 0xb9, 0x8c, 0x83, 0x76, 0xe7, 0x09, 0xb6, 0x7f, 0xc3, + 0x47, 0xc8, 0x6b, 0x6d, 0x2f, 0x6e, 0xb7, 0x5a, 0x7f, 0x42, 0xdd, 0xb5, 0x59, 0x14, 0x40, 0x51, 0x7b, 0x7e, 0xe3, + 0xe5, 0x1c, 0x72, 0xda, 0xb6, 0xf5, 0xec, 0xce, 0xe3, 0x04, 0x12, 0x82, 0xa3, 0xce, 0xfc, 0xa6, 0x80, 0xd5, 0x45, + 0x3a, 0xc9, 0xd4, 0x2c, 0xd2, 0x3c, 0x2d, 0x7f, 0x2b, 0xc4, 0x4f, 0xb7, 0x43, 0xdc, 0xb1, 0x10, 0x57, 0x58, 0x6f, + 0x26, 0x0b, 0xa1, 0x62, 0xab, 0x51, 0x3b, 0xd7, 0x80, 0x4c, 0xf9, 0x15, 0x15, 0x16, 0x0e, 0xf5, 0xf0, 0x9b, 0xc1, + 0xe8, 0x6c, 0x07, 0xe3, 0xe9, 0xa7, 0xc0, 0x10, 0x59, 0xb2, 0xac, 0xef, 0x6b, 0x5b, 0xd0, 0x59, 0x77, 0x4a, 0x81, + 0x9e, 0xa2, 0x0e, 0xfc, 0xbe, 0x66, 0x89, 0x9c, 0xea, 0x9f, 0x8a, 0x9c, 0xaf, 0x75, 0xdd, 0xa3, 0x56, 0x4b, 0x3f, + 0xe7, 0xec, 0x17, 0x1a, 0xb5, 0x43, 0x68, 0x50, 0x5c, 0xe0, 0xbf, 0x95, 0x97, 0x79, 0xeb, 0xdc, 0x13, 0xff, 0xe0, + 0xde, 0xf2, 0x75, 0x92, 0x14, 0xab, 0x1b, 0xd1, 0x58, 0x58, 0x59, 0xa9, 0x85, 0x0f, 0xb8, 0xed, 0xd4, 0x79, 0x22, + 0xac, 0x57, 0xde, 0xe2, 0x64, 0xfd, 0x1f, 0x74, 0xde, 0x45, 0x04, 0x91, 0x0e, 0x27, 0xd9, 0x90, 0x77, 0xb3, 0x1e, + 0x69, 0x75, 0xb3, 0x66, 0x13, 0x05, 0x9c, 0x88, 0x41, 0x66, 0xd2, 0xf3, 0x02, 0xd6, 0xe7, 0xca, 0xd8, 0xce, 0x51, + 0xc4, 0xe1, 0xaa, 0xe9, 0x6a, 0x55, 0x85, 0x01, 0x98, 0xba, 0xae, 0xf1, 0x37, 0x69, 0x1a, 0xe0, 0xdc, 0xe1, 0xe4, + 0x99, 0x7d, 0xb1, 0x8b, 0xb0, 0xbc, 0x22, 0xe5, 0x23, 0x85, 0xb9, 0x70, 0x1e, 0xcb, 0x29, 0x78, 0x29, 0x4a, 0xf1, + 0x53, 0x25, 0x31, 0xf9, 0x87, 0x3e, 0xea, 0x8b, 0x32, 0xc3, 0x0d, 0x32, 0xf9, 0x44, 0x01, 0xa3, 0x7c, 0x23, 0x09, + 0x8c, 0x88, 0x7f, 0x21, 0xda, 0xa6, 0xb3, 0x16, 0xdd, 0xf8, 0xbe, 0x16, 0x1d, 0xcd, 0x24, 0x53, 0xb9, 0xdb, 0x36, + 0xe2, 0x30, 0x8d, 0xf3, 0xf3, 0x91, 0xbe, 0x2b, 0x99, 0x57, 0x37, 0x03, 0x62, 0x05, 0xbd, 0x36, 0xd2, 0xa8, 0x50, + 0xf6, 0xe8, 0xf7, 0x72, 0xa7, 0x7d, 0x22, 0xee, 0xb2, 0x4f, 0xca, 0x85, 0xe7, 0x7c, 0x21, 0x46, 0x10, 0x8e, 0x34, + 0x52, 0x6f, 0xd3, 0x71, 0xe3, 0x2b, 0x15, 0xc3, 0xc7, 0xd2, 0xc9, 0x04, 0x95, 0x98, 0xb9, 0x2f, 0x95, 0xa0, 0x2a, + 0xe4, 0xa5, 0xef, 0x6b, 0x18, 0x11, 0x67, 0x97, 0x04, 0x32, 0x3b, 0x51, 0x49, 0x8d, 0x41, 0x46, 0x7a, 0x59, 0xb8, + 0xc8, 0xd8, 0xcf, 0x0b, 0x7a, 0xce, 0x40, 0xd7, 0x64, 0x21, 0x4b, 0x54, 0xac, 0x09, 0x64, 0x5f, 0xb3, 0x0d, 0xc1, + 0x0b, 0x96, 0xe8, 0x8d, 0xc9, 0x54, 0xa5, 0xc9, 0x6d, 0xf2, 0x9b, 0x3e, 0xf8, 0x8b, 0x41, 0x3b, 0x60, 0x38, 0xe1, + 0xb3, 0x98, 0x65, 0x91, 0x72, 0xf9, 0x96, 0x83, 0x45, 0xd0, 0x1a, 0xb3, 0x24, 0xca, 0xcc, 0xf6, 0xb4, 0x51, 0xf8, + 0x13, 0x67, 0x99, 0xea, 0x5a, 0x74, 0xb9, 0x42, 0xa8, 0x46, 0x1f, 0xb1, 0x08, 0x3e, 0xd1, 0x72, 0x8d, 0x23, 0xec, + 0x56, 0x97, 0xd7, 0xce, 0x6b, 0x3b, 0xd0, 0x5a, 0xdb, 0x28, 0x6d, 0x04, 0xf0, 0xf5, 0xd2, 0x9c, 0x0b, 0x19, 0x04, + 0x53, 0x9c, 0x22, 0xd2, 0x9b, 0x2a, 0x67, 0xd7, 0x71, 0xaa, 0xfe, 0xeb, 0x37, 0xdb, 0x51, 0xbb, 0x34, 0xdf, 0x6b, + 0xb7, 0x81, 0x75, 0x72, 0x94, 0xb9, 0x51, 0xaa, 0x96, 0x51, 0xfe, 0xd6, 0x4b, 0xad, 0x9e, 0xcb, 0xe5, 0x62, 0x73, + 0xdc, 0xb4, 0xa8, 0x0a, 0x6a, 0x40, 0xa8, 0x60, 0xd1, 0x8e, 0xa9, 0x50, 0x51, 0xad, 0xbb, 0x54, 0x25, 0x2f, 0xb4, + 0x88, 0x3e, 0xdf, 0x5f, 0x0a, 0x33, 0x63, 0x71, 0xc1, 0xac, 0x93, 0xa9, 0x4e, 0x72, 0x85, 0xc1, 0x88, 0xa3, 0x87, + 0x6e, 0x6b, 0xa6, 0x61, 0xb9, 0x25, 0x62, 0x2b, 0xdd, 0x86, 0xfa, 0x91, 0x0a, 0x52, 0x85, 0xbb, 0x36, 0x06, 0x80, + 0x5c, 0xbd, 0x6d, 0x80, 0x81, 0xd9, 0x9a, 0x4b, 0xbb, 0x04, 0xd0, 0xc6, 0xc6, 0x14, 0x2e, 0xd2, 0x5c, 0xec, 0x2f, + 0xbf, 0x91, 0xc5, 0xa1, 0xd3, 0x54, 0xfd, 0x66, 0x09, 0xfc, 0x0f, 0x12, 0x70, 0xa9, 0x95, 0xd2, 0xc8, 0xff, 0xfa, + 0xed, 0xd9, 0x7b, 0x1f, 0x5f, 0xf2, 0xe4, 0x36, 0xf2, 0xa5, 0x58, 0x50, 0xbf, 0x40, 0xa1, 0x9c, 0xd2, 0xac, 0x7c, + 0x19, 0x0f, 0x4f, 0x69, 0x98, 0xf2, 0x89, 0xbe, 0x94, 0xb9, 0x6e, 0x24, 0x8f, 0x2e, 0x8e, 0xd5, 0x4b, 0xa6, 0x7a, + 0xc7, 0x52, 0xbf, 0xde, 0x4b, 0x0a, 0xf8, 0xd9, 0x83, 0x10, 0xca, 0xf1, 0xa1, 0x9c, 0xaa, 0x87, 0x33, 0x38, 0x30, + 0xea, 0x69, 0x7f, 0xb9, 0x41, 0x4c, 0x7d, 0x18, 0x62, 0xda, 0xd3, 0x4b, 0xc8, 0x55, 0xab, 0x8b, 0x68, 0x74, 0x71, + 0x51, 0x1c, 0x1f, 0xc2, 0x58, 0x87, 0x76, 0x5c, 0x80, 0xd0, 0xf6, 0x2f, 0x09, 0x0c, 0x5e, 0x36, 0x24, 0x48, 0x0f, + 0x86, 0x80, 0x79, 0x93, 0x1e, 0x2c, 0x12, 0x08, 0x0c, 0x7a, 0x27, 0x65, 0x89, 0x3a, 0xb1, 0xba, 0x68, 0x17, 0x04, + 0xba, 0x61, 0x45, 0xf7, 0xda, 0x9b, 0x5a, 0xed, 0xaf, 0x05, 0x29, 0x71, 0xa1, 0xbb, 0x40, 0xf0, 0xbf, 0x82, 0xec, + 0xf8, 0x50, 0xe3, 0xe1, 0xc2, 0x7d, 0xb5, 0x89, 0x7e, 0xed, 0x40, 0x89, 0xad, 0x41, 0x2e, 0xf1, 0x47, 0x89, 0x3f, + 0x5e, 0xa8, 0xa6, 0x56, 0x18, 0x81, 0x96, 0x04, 0x42, 0xbb, 0x65, 0xb5, 0x8e, 0x11, 0x4f, 0xd3, 0x78, 0x9e, 0xd3, + 0xc8, 0xfe, 0x30, 0x72, 0x09, 0xc4, 0xdb, 0xa6, 0x22, 0x60, 0xd2, 0x6b, 0x4e, 0x41, 0x5d, 0xd8, 0xd4, 0x52, 0xae, + 0x62, 0x11, 0x34, 0x9b, 0xa3, 0xe6, 0xe5, 0x04, 0x15, 0x72, 0xba, 0x74, 0xa5, 0xda, 0xe3, 0x56, 0xab, 0x0b, 0xb9, + 0x90, 0xcd, 0x38, 0x65, 0x93, 0x2c, 0x4a, 0xe9, 0x58, 0x16, 0x12, 0x6e, 0xa9, 0x2d, 0xad, 0x1a, 0x11, 0x76, 0x1e, + 0x09, 0x3a, 0xf3, 0x42, 0xf8, 0xf7, 0xee, 0x89, 0x0b, 0x99, 0x44, 0x99, 0x9c, 0x36, 0x55, 0xd6, 0x2d, 0xdc, 0x19, + 0x90, 0xd3, 0xda, 0xf3, 0xd2, 0x99, 0x68, 0x44, 0x41, 0xc5, 0x2a, 0xa4, 0xf0, 0xe4, 0x14, 0x4b, 0xe1, 0xb6, 0xcb, + 0xd0, 0x72, 0x63, 0x05, 0x9b, 0x92, 0xfe, 0x08, 0x15, 0xb9, 0x52, 0x8c, 0x37, 0x1b, 0x5b, 0x75, 0xa9, 0xfe, 0xb4, + 0x81, 0x3e, 0x47, 0xb1, 0x2b, 0xb4, 0x63, 0x79, 0xa9, 0x7b, 0xdc, 0x07, 0x99, 0x35, 0x95, 0x13, 0xbb, 0x3d, 0x50, + 0xc1, 0xb2, 0xf9, 0x42, 0x0e, 0x94, 0x53, 0x5b, 0xc0, 0x05, 0x89, 0x21, 0x76, 0x4a, 0x00, 0x07, 0xc3, 0xa5, 0x06, + 0x66, 0x14, 0xa7, 0xa3, 0x00, 0x20, 0xf2, 0x9a, 0xde, 0x53, 0x41, 0x67, 0xa8, 0x3b, 0x63, 0x59, 0x53, 0xd7, 0x3d, + 0x72, 0xd4, 0x92, 0xf0, 0x09, 0x3c, 0x15, 0xa1, 0x1a, 0x0d, 0xab, 0xdc, 0xd5, 0x2d, 0xb8, 0xbc, 0x18, 0x16, 0x45, + 0x57, 0xc8, 0x60, 0xf0, 0x3a, 0x40, 0x43, 0xfc, 0x8b, 0xf3, 0x72, 0x16, 0xdf, 0x1e, 0x15, 0x1f, 0x77, 0xd0, 0x8e, + 0x26, 0xee, 0x59, 0x50, 0xcd, 0x7e, 0x21, 0xd0, 0xf0, 0x5d, 0xe0, 0xd3, 0x7c, 0xde, 0xd4, 0xbc, 0xab, 0xa9, 0x48, + 0xd6, 0x87, 0xae, 0xc8, 0x78, 0x6a, 0xbf, 0x97, 0x4b, 0xc5, 0x96, 0xcc, 0x25, 0x0d, 0xed, 0x4c, 0x18, 0x96, 0x97, + 0x7a, 0xcc, 0xb3, 0x7b, 0x8d, 0x07, 0xd5, 0xf8, 0xc9, 0xc5, 0x49, 0x9d, 0xc7, 0x01, 0x5f, 0x2a, 0x5f, 0x60, 0x17, + 0xa7, 0x29, 0x4c, 0x78, 0x61, 0xd5, 0x17, 0xf7, 0xa5, 0x1f, 0x03, 0x39, 0x0c, 0x50, 0x61, 0xce, 0xe9, 0x33, 0xa5, + 0x52, 0x3a, 0x6f, 0xcd, 0xdb, 0x93, 0x36, 0x58, 0xa4, 0xa5, 0x2f, 0x83, 0x70, 0x77, 0x2d, 0x2f, 0xba, 0x5b, 0xf1, + 0x2e, 0xad, 0x90, 0x7a, 0x6a, 0x41, 0xc4, 0x17, 0x59, 0xe2, 0x7b, 0x7f, 0x19, 0xa5, 0x6c, 0xf4, 0x91, 0xf8, 0xfb, + 0xcb, 0x00, 0x6d, 0x5e, 0x7b, 0x54, 0x5c, 0xc1, 0x32, 0x6c, 0x54, 0x77, 0xa4, 0x67, 0xa1, 0xc3, 0x8b, 0xf5, 0x5b, + 0x71, 0xfc, 0xde, 0xfe, 0x12, 0x18, 0x8f, 0x9e, 0xa7, 0x77, 0x51, 0x9c, 0x57, 0xef, 0xba, 0xaa, 0xa0, 0x00, 0x34, + 0xeb, 0x72, 0x4f, 0x11, 0x15, 0xf1, 0x3f, 0x49, 0x69, 0xbe, 0xa7, 0x99, 0x1a, 0xc0, 0x29, 0x0d, 0x7f, 0xf3, 0xbd, + 0xbf, 0x94, 0x65, 0xb4, 0xf4, 0x68, 0xa8, 0x94, 0x0c, 0xe2, 0xc3, 0x5c, 0x60, 0xc6, 0x86, 0x09, 0x95, 0x31, 0x4b, + 0x75, 0x97, 0xae, 0x35, 0xc0, 0xd7, 0x56, 0xb4, 0x5a, 0xe5, 0xf5, 0xb5, 0xb0, 0x3a, 0x06, 0xd5, 0xca, 0x8e, 0x0f, + 0x2b, 0xb8, 0xd5, 0xca, 0xd4, 0x99, 0x74, 0x43, 0x83, 0xd5, 0x0a, 0x75, 0x9d, 0xf7, 0x97, 0x91, 0xba, 0x36, 0x04, + 0x00, 0x72, 0x03, 0x20, 0x04, 0xad, 0xf5, 0xb5, 0x98, 0x20, 0x25, 0x3c, 0x94, 0xb1, 0x98, 0x50, 0xb9, 0x86, 0xd8, + 0x54, 0xe7, 0xa8, 0x76, 0x6d, 0x80, 0x7a, 0x03, 0xda, 0xb8, 0x0e, 0xed, 0x05, 0x20, 0xbd, 0xbf, 0xbf, 0x64, 0x05, + 0xd9, 0x5f, 0xd2, 0x6c, 0xc4, 0x13, 0xfa, 0xe1, 0xdd, 0x97, 0x70, 0xc9, 0x91, 0x67, 0x60, 0x58, 0x4c, 0x11, 0x08, + 0x4e, 0xb5, 0x39, 0x5a, 0x84, 0x70, 0x25, 0x42, 0x34, 0x27, 0xf0, 0xd4, 0x5c, 0x0a, 0xc4, 0xc2, 0xf7, 0xfa, 0x1a, + 0x72, 0x9a, 0x68, 0x98, 0x49, 0xa6, 0x7a, 0xf1, 0xe2, 0xf8, 0x50, 0xb7, 0xd6, 0x22, 0x40, 0x37, 0x02, 0x24, 0xa8, + 0x73, 0x5a, 0xe1, 0x00, 0xf2, 0x9a, 0x5d, 0x3c, 0x24, 0xec, 0xaa, 0x24, 0x36, 0x75, 0x81, 0xaa, 0x77, 0x9c, 0xc6, + 0x97, 0x34, 0xed, 0xed, 0x2f, 0xb3, 0xd5, 0xaa, 0x55, 0x1c, 0x1f, 0xea, 0x47, 0xef, 0x58, 0xf1, 0x0d, 0xfd, 0xc2, + 0x4b, 0xb5, 0xc5, 0x70, 0x2b, 0x11, 0xb2, 0x3d, 0x6d, 0x9a, 0x53, 0x64, 0x06, 0x28, 0x7c, 0x4f, 0x25, 0x58, 0xa8, + 0x46, 0xa5, 0x42, 0x54, 0xf8, 0x1e, 0x4b, 0x36, 0xcb, 0x72, 0x49, 0xe7, 0x50, 0x3a, 0x5d, 0xad, 0xda, 0x85, 0xef, + 0xcd, 0x58, 0x06, 0x4f, 0xd9, 0x6a, 0xa5, 0x2e, 0xfc, 0xcd, 0x58, 0x16, 0xb4, 0x80, 0x6c, 0x7d, 0x6f, 0x16, 0xdf, + 0xa8, 0x05, 0xdb, 0x9a, 0xf8, 0x26, 0x68, 0x9b, 0xaa, 0xb0, 0xc4, 0x4f, 0x0e, 0x14, 0x57, 0xed, 0x68, 0x6a, 0x76, + 0x34, 0xc1, 0x0b, 0x7d, 0x95, 0x89, 0x04, 0x09, 0x49, 0xb7, 0xef, 0x68, 0x62, 0x77, 0x74, 0xb1, 0x63, 0x47, 0x17, + 0x77, 0xec, 0x68, 0x6c, 0x76, 0xcf, 0x2b, 0x71, 0xc7, 0x57, 0xab, 0x76, 0xab, 0xc2, 0xde, 0xf1, 0x61, 0xc2, 0xae, + 0x60, 0x37, 0x40, 0xcd, 0x93, 0x6c, 0x46, 0xb7, 0x13, 0x65, 0x1d, 0xc5, 0xf4, 0x57, 0x61, 0xb2, 0x44, 0x42, 0x56, + 0x47, 0x82, 0x4b, 0xd6, 0x65, 0xc8, 0xed, 0x8f, 0x24, 0x6c, 0x06, 0x68, 0xc8, 0x01, 0x0d, 0x53, 0x83, 0x86, 0x8b, + 0xe2, 0x1c, 0x24, 0x82, 0x5a, 0xcd, 0xbd, 0x28, 0x0f, 0x5a, 0xfb, 0xbd, 0xdd, 0x14, 0x06, 0xc1, 0xf0, 0x6b, 0x2e, + 0x12, 0x3f, 0xd2, 0x4d, 0x7f, 0x15, 0x62, 0x66, 0x2c, 0x33, 0xa9, 0x55, 0x3b, 0x29, 0xab, 0xaa, 0x77, 0xe9, 0xab, + 0xf3, 0xe8, 0x91, 0x6e, 0x31, 0x8f, 0xa5, 0xa4, 0x22, 0x33, 0x74, 0xea, 0xfb, 0x2e, 0xb6, 0xff, 0x7f, 0x91, 0xdc, + 0x16, 0x26, 0x12, 0x5b, 0x26, 0x62, 0xa9, 0xcd, 0x68, 0xe7, 0x86, 0xc1, 0x6b, 0x59, 0xb4, 0x57, 0xa9, 0xab, 0xb7, + 0xc8, 0xb5, 0x10, 0x74, 0x11, 0x18, 0x2c, 0x8b, 0x19, 0x4d, 0xce, 0x15, 0x37, 0xee, 0x8f, 0x2e, 0x8c, 0x76, 0xba, + 0x26, 0xdb, 0xaa, 0x0e, 0xd8, 0xff, 0x71, 0xd1, 0x79, 0xf2, 0xf0, 0xd4, 0xc7, 0x9a, 0xa1, 0xf3, 0xf1, 0xd8, 0x47, + 0x85, 0x77, 0xbf, 0x6e, 0xed, 0x87, 0x3f, 0x2e, 0xbe, 0x78, 0xd1, 0xfa, 0xa2, 0xec, 0x9c, 0xf9, 0xa8, 0xb8, 0x30, + 0xc1, 0x7c, 0x2b, 0x97, 0x1c, 0x78, 0xed, 0x8a, 0xc6, 0x71, 0xb6, 0x7b, 0x39, 0x03, 0x77, 0x39, 0xf9, 0x9c, 0xd2, + 0x04, 0xfb, 0x9e, 0x8f, 0x37, 0x4a, 0xcf, 0x53, 0x7a, 0x45, 0xed, 0x6b, 0x06, 0xb7, 0x4c, 0xb6, 0xa5, 0xc7, 0x88, + 0x2f, 0x32, 0x69, 0xb2, 0x1a, 0x0c, 0x5f, 0x75, 0x96, 0x74, 0xa1, 0xd6, 0xe0, 0x1a, 0x04, 0xb7, 0x5a, 0xa8, 0xd5, + 0x45, 0x55, 0x71, 0x81, 0x7d, 0x07, 0x80, 0x9d, 0x90, 0xf5, 0x77, 0x94, 0x47, 0x2d, 0xdc, 0xda, 0x05, 0x1b, 0x6e, + 0xa3, 0xc8, 0xf7, 0x87, 0x16, 0x4f, 0xca, 0x31, 0x59, 0x7b, 0x3b, 0xc4, 0x4e, 0x7c, 0x7d, 0x12, 0x03, 0x97, 0x02, + 0x06, 0xcb, 0x68, 0x9e, 0xef, 0x44, 0x40, 0xb9, 0x89, 0xd8, 0xaf, 0x5a, 0xfb, 0x3b, 0x46, 0xc1, 0x2d, 0x0c, 0x07, + 0x4c, 0x01, 0x5c, 0x86, 0x47, 0x4d, 0x2b, 0x3a, 0x1e, 0xd3, 0x51, 0xe9, 0xd7, 0x85, 0x40, 0xd7, 0x98, 0xa5, 0x12, + 0xe2, 0x3d, 0x2a, 0x10, 0xe3, 0xbf, 0xe1, 0x19, 0xf5, 0x91, 0x4d, 0xdd, 0x34, 0xf0, 0x1b, 0x61, 0xbf, 0x1d, 0x1e, + 0x3d, 0x62, 0x1d, 0x16, 0x33, 0xcb, 0x6a, 0x65, 0x7d, 0x3a, 0xb5, 0xf2, 0x3a, 0x22, 0xb9, 0x72, 0xda, 0xec, 0x3a, + 0x40, 0xf7, 0x3b, 0x26, 0xcb, 0xf6, 0x17, 0x8f, 0xda, 0xad, 0xc2, 0xc7, 0x3e, 0x0c, 0x77, 0xdf, 0x53, 0xa2, 0x7a, + 0x1d, 0x41, 0xaf, 0x45, 0xf6, 0x6b, 0xfa, 0x75, 0xda, 0x9f, 0xb7, 0x7d, 0xac, 0xdf, 0x1a, 0x80, 0x8a, 0x92, 0x19, + 0x8c, 0xc0, 0xd3, 0xf9, 0xbb, 0x97, 0x52, 0x1f, 0xfc, 0x7e, 0xf0, 0x3c, 0x6e, 0xb7, 0x7c, 0xec, 0xe7, 0x92, 0xcf, + 0x7f, 0xc5, 0x12, 0x8e, 0x7c, 0xec, 0x8f, 0x52, 0x9e, 0x53, 0x77, 0x0d, 0x5a, 0x77, 0xfd, 0xfd, 0x8b, 0xd0, 0x10, + 0xcd, 0x05, 0xcd, 0x73, 0xcf, 0x1d, 0xdf, 0x90, 0xd2, 0x27, 0x18, 0xe6, 0x56, 0x8a, 0xcb, 0xa9, 0x54, 0x78, 0xd1, + 0x17, 0xfa, 0x5d, 0xaa, 0xd2, 0x65, 0x1b, 0xc4, 0xa6, 0x44, 0x40, 0xc9, 0xd8, 0xb4, 0x2a, 0xf5, 0xc9, 0x99, 0xb7, + 0x1c, 0x3d, 0x3d, 0xb1, 0x0e, 0x00, 0x6f, 0x4e, 0x50, 0x2b, 0x99, 0xb1, 0xec, 0x7c, 0x4b, 0x69, 0x7c, 0xb3, 0xa5, + 0x14, 0xf4, 0xb3, 0x12, 0x3a, 0xf3, 0xae, 0x99, 0x4f, 0x63, 0xbd, 0xd2, 0x72, 0x5c, 0x10, 0x13, 0xe5, 0xa4, 0xfc, + 0x04, 0xa4, 0xce, 0x36, 0xa8, 0x11, 0x7e, 0xfb, 0x74, 0x50, 0xf2, 0xab, 0xa6, 0xa3, 0x37, 0x9f, 0xde, 0x73, 0x47, + 0xaf, 0xf9, 0x1d, 0xd8, 0x37, 0xf7, 0xc6, 0xd7, 0xd1, 0xbf, 0xa5, 0xd8, 0xa8, 0x1e, 0xe5, 0x16, 0x8c, 0x52, 0x36, + 0xab, 0x76, 0x61, 0x13, 0x4c, 0xa5, 0x74, 0x40, 0xf2, 0x90, 0x3b, 0x88, 0xd6, 0x3e, 0xce, 0xe1, 0x4a, 0x24, 0xbc, + 0x77, 0x62, 0x21, 0xe8, 0x79, 0xca, 0xaf, 0xd7, 0xdf, 0xa3, 0xb5, 0xbb, 0xf1, 0x94, 0x4d, 0xa6, 0xce, 0x3d, 0x27, + 0x4a, 0x4a, 0xd4, 0xdf, 0x39, 0x41, 0xf1, 0xaf, 0xff, 0x12, 0x86, 0xff, 0xfa, 0x2f, 0x9f, 0x6c, 0x0a, 0xc3, 0x17, + 0x17, 0x58, 0x56, 0xc3, 0xee, 0x26, 0xf0, 0xed, 0x33, 0xd5, 0x71, 0xbe, 0xbd, 0xcd, 0xc6, 0x26, 0x40, 0xfd, 0xc6, + 0x16, 0x6c, 0x14, 0xea, 0x03, 0xe0, 0xfd, 0x16, 0xc0, 0x60, 0x5d, 0x9f, 0x84, 0x0c, 0x1a, 0xfd, 0x2e, 0xd0, 0x2e, + 0x50, 0x74, 0xaf, 0x1d, 0xf9, 0xed, 0x18, 0xfe, 0xd4, 0x1a, 0x7e, 0x27, 0xf8, 0xc6, 0x1f, 0x30, 0xba, 0xb8, 0x28, + 0x13, 0xda, 0xdc, 0xae, 0x70, 0x61, 0xbe, 0xbf, 0x51, 0x62, 0x64, 0x7f, 0xd4, 0x42, 0x3d, 0x75, 0x1d, 0x8f, 0x8c, + 0x2e, 0x5e, 0xc3, 0x5b, 0x72, 0x8e, 0x2f, 0x85, 0x75, 0xa8, 0xde, 0xc1, 0x9f, 0x61, 0x88, 0xfa, 0xaa, 0xd4, 0xa0, + 0x1b, 0xcc, 0x19, 0x4a, 0x41, 0xe1, 0x07, 0x30, 0xf1, 0xe8, 0xc2, 0x58, 0x77, 0xa7, 0xda, 0xed, 0x11, 0xad, 0x93, + 0xb6, 0x71, 0x87, 0xd4, 0x90, 0x8e, 0xbd, 0xf7, 0x0a, 0x5f, 0xaa, 0x31, 0xad, 0xac, 0x69, 0xe5, 0x5a, 0x02, 0x55, + 0xfe, 0xa2, 0x50, 0x61, 0xf1, 0xbf, 0xee, 0x8a, 0xdc, 0xfd, 0xfd, 0xd3, 0x91, 0x3b, 0x7e, 0xaf, 0xc8, 0xdd, 0xdf, + 0xff, 0xf0, 0xc8, 0xdd, 0x5f, 0xdd, 0xc8, 0x1d, 0x6c, 0xe2, 0x97, 0xf7, 0x8a, 0xae, 0xd9, 0xc8, 0x07, 0xbf, 0xce, + 0x49, 0xdb, 0x68, 0xb2, 0x29, 0x9f, 0x40, 0x68, 0xed, 0xdf, 0x3f, 0x52, 0x96, 0xf2, 0x89, 0x1b, 0x27, 0x83, 0xb7, + 0xa4, 0x42, 0x60, 0xac, 0x6b, 0x23, 0x5a, 0x26, 0x36, 0xd5, 0x2a, 0x6f, 0x80, 0x34, 0x1f, 0xda, 0x37, 0x16, 0xf8, + 0x51, 0xf9, 0xd6, 0xa1, 0x16, 0xee, 0xd8, 0xe8, 0x55, 0xa4, 0x02, 0x5f, 0x65, 0xc7, 0x4e, 0xc3, 0x5e, 0x6f, 0x70, + 0x47, 0xe8, 0xda, 0xb7, 0xaa, 0xe8, 0xdb, 0xee, 0x4b, 0xff, 0xc7, 0x9b, 0xf6, 0xb3, 0x41, 0xbb, 0x7b, 0xd4, 0x9e, + 0xf9, 0x91, 0x0f, 0x52, 0x4a, 0x15, 0xb4, 0xba, 0x47, 0x47, 0x50, 0x70, 0xed, 0x14, 0x74, 0xa0, 0x80, 0x39, 0x05, + 0x8f, 0xa0, 0x60, 0xe4, 0x14, 0x3c, 0x86, 0x82, 0xc4, 0x29, 0x78, 0x02, 0x05, 0x57, 0x7e, 0x31, 0x60, 0x25, 0xb8, + 0x4f, 0xd0, 0x10, 0x6b, 0xe3, 0xc1, 0x96, 0x3d, 0xc1, 0x6d, 0x08, 0x99, 0xc5, 0x13, 0x95, 0xe9, 0x03, 0x0e, 0xb8, + 0x88, 0xe3, 0xeb, 0x29, 0xcd, 0x22, 0x08, 0x5a, 0x3e, 0x57, 0x32, 0x26, 0x94, 0xfc, 0x3d, 0x9b, 0x51, 0xfb, 0x7d, + 0x0a, 0x8b, 0x07, 0xcf, 0x47, 0x83, 0xd6, 0xb0, 0xe8, 0x96, 0x3b, 0xa7, 0x63, 0x6d, 0x26, 0xeb, 0x43, 0xef, 0x65, + 0x55, 0xa7, 0xa7, 0x6b, 0x96, 0x7b, 0xbe, 0x23, 0x66, 0xe3, 0x78, 0x03, 0xc6, 0x29, 0xbf, 0x6e, 0xde, 0xf8, 0xbd, + 0xed, 0x71, 0x1c, 0x80, 0xa8, 0x8c, 0xe3, 0xa8, 0x35, 0x95, 0x4f, 0xef, 0xe3, 0x49, 0xf9, 0xfb, 0x35, 0xcd, 0xf3, + 0x78, 0x62, 0x5a, 0xee, 0x8e, 0xdb, 0x28, 0x10, 0xdd, 0x98, 0x8d, 0x05, 0x02, 0x62, 0x2f, 0xb0, 0x59, 0x60, 0x4e, + 0x9b, 0x50, 0x0c, 0x60, 0xa7, 0x1e, 0xc5, 0x51, 0xd3, 0xd7, 0x8b, 0x64, 0x3c, 0xa9, 0x0a, 0x8e, 0xe7, 0x82, 0xaa, + 0x52, 0x8d, 0xe1, 0xe2, 0xf8, 0x10, 0x0a, 0x74, 0xf5, 0x8e, 0x68, 0x8d, 0xb5, 0xdd, 0x77, 0xc7, 0x6c, 0x3c, 0x1b, + 0xad, 0x71, 0xf3, 0x5b, 0xca, 0xe4, 0x96, 0xcd, 0x18, 0xc1, 0x67, 0xed, 0x11, 0xfc, 0x31, 0x11, 0x88, 0xcf, 0xc6, + 0xe3, 0xf1, 0x9d, 0xd1, 0x9b, 0xcf, 0x92, 0x31, 0xed, 0xd0, 0x47, 0x5d, 0xc8, 0x7d, 0x68, 0x1a, 0x9f, 0x7f, 0xbb, + 0x50, 0xb8, 0x5b, 0xde, 0xaf, 0x31, 0x84, 0x07, 0xe4, 0x74, 0x79, 0xff, 0x48, 0x4e, 0x31, 0x17, 0x74, 0x39, 0x8b, + 0xc5, 0x84, 0x65, 0x51, 0xab, 0x08, 0xaf, 0x4c, 0xe8, 0xe3, 0xb3, 0xa7, 0x4f, 0x9f, 0x16, 0x61, 0x62, 0x9f, 0x5a, + 0x49, 0x52, 0x84, 0xa3, 0x65, 0xb9, 0x8c, 0x56, 0x6b, 0x3c, 0x2e, 0x42, 0x66, 0x0b, 0x8e, 0x3a, 0xa3, 0xe4, 0xa8, + 0x53, 0x84, 0xd7, 0x4e, 0x8b, 0x22, 0xa4, 0xe6, 0x49, 0xd0, 0xa4, 0x96, 0x40, 0xf1, 0xa4, 0xd5, 0x2a, 0x42, 0x4d, + 0x68, 0x4b, 0xb0, 0x88, 0xf4, 0xcf, 0x28, 0x5e, 0x48, 0x0e, 0x2c, 0xb9, 0xcb, 0x65, 0x30, 0x38, 0x37, 0x2f, 0xa7, + 0xd0, 0x1f, 0x72, 0x28, 0xd0, 0x10, 0x7f, 0xe9, 0x06, 0x29, 0x80, 0x98, 0x55, 0x70, 0x82, 0xdb, 0x18, 0x46, 0xad, + 0x1a, 0x28, 0x4b, 0x55, 0x7f, 0x49, 0x78, 0x15, 0xbb, 0x00, 0xfe, 0x03, 0x2d, 0xf5, 0x5b, 0xd4, 0x24, 0xdd, 0xc1, + 0xf5, 0x29, 0xfd, 0x24, 0xd7, 0xbf, 0xbd, 0x0f, 0xd3, 0xa7, 0xf4, 0x8f, 0x66, 0xfa, 0xe6, 0x55, 0xa3, 0x9a, 0xe9, + 0x6b, 0xb6, 0x36, 0x93, 0xc4, 0x1f, 0x4d, 0xe9, 0xe8, 0xe3, 0x25, 0xbf, 0x69, 0xc2, 0x91, 0x10, 0xbe, 0xe2, 0xa7, + 0xfb, 0xbf, 0x35, 0xd9, 0xc2, 0x0e, 0xe6, 0x7c, 0x07, 0x42, 0x89, 0xcd, 0xb7, 0x19, 0xf1, 0xdf, 0x5a, 0xb3, 0x4a, + 0x97, 0x8c, 0xc7, 0xc4, 0x7f, 0x3b, 0x1e, 0xfb, 0xf6, 0x8a, 0x5d, 0x2c, 0xa9, 0x6a, 0xf5, 0xa6, 0x56, 0xa2, 0x5a, + 0x7d, 0xf1, 0x85, 0x5b, 0xe6, 0x16, 0x98, 0x10, 0x87, 0x1b, 0xce, 0x30, 0x35, 0x09, 0xcb, 0xe1, 0xa8, 0xc1, 0xe7, + 0x29, 0xea, 0xef, 0xf8, 0x13, 0xb5, 0xd7, 0x31, 0x97, 0x00, 0x6f, 0x79, 0x87, 0xf4, 0xfa, 0xfd, 0xf2, 0x09, 0xb5, + 0xe9, 0x6e, 0xcf, 0x6e, 0xbf, 0x4c, 0x82, 0x99, 0x44, 0x05, 0xcb, 0xdf, 0x66, 0x6b, 0x77, 0x47, 0x34, 0x8c, 0x84, + 0xb8, 0xcb, 0x2a, 0x24, 0x9f, 0x4c, 0x52, 0xf8, 0x40, 0xc8, 0xb2, 0xf6, 0xde, 0x51, 0xdd, 0xbd, 0x5f, 0x5b, 0x6f, + 0xe4, 0x76, 0x34, 0x6f, 0xe9, 0x54, 0xdf, 0x2b, 0xd2, 0x39, 0xc7, 0x57, 0xe6, 0xc3, 0x35, 0xca, 0x22, 0x5b, 0x1a, + 0xfe, 0xbf, 0xd4, 0x99, 0xaa, 0x12, 0xb2, 0x34, 0xf4, 0xc0, 0x49, 0x51, 0x98, 0x1c, 0xff, 0x84, 0xe5, 0x73, 0x78, + 0x1f, 0xa6, 0xee, 0x49, 0x3f, 0xc5, 0xc2, 0xf3, 0x6b, 0x27, 0x8e, 0x50, 0xdb, 0xae, 0xc2, 0x06, 0x12, 0xb4, 0xab, + 0x76, 0x26, 0x0b, 0xdf, 0x78, 0x7c, 0x2d, 0x12, 0x7d, 0x4f, 0xe3, 0x53, 0x47, 0x38, 0x9c, 0x15, 0x82, 0xab, 0xbf, + 0xdc, 0x10, 0x5b, 0x65, 0x0b, 0x0a, 0x37, 0x4e, 0xa6, 0x6a, 0x34, 0xb6, 0x94, 0x57, 0x3e, 0x9f, 0xc7, 0x99, 0x66, + 0xa3, 0xc4, 0xd7, 0xfc, 0x60, 0x7f, 0x59, 0xed, 0x7c, 0xe1, 0x5b, 0xb0, 0x35, 0xf1, 0xf6, 0x8e, 0x0f, 0xa1, 0x43, + 0xcf, 0xab, 0x81, 0x9e, 0x6d, 0x38, 0xf3, 0x3f, 0x11, 0x56, 0xbf, 0x08, 0xf3, 0x6b, 0x1c, 0xe6, 0xd7, 0xde, 0x9f, + 0x97, 0xcd, 0x6b, 0x7a, 0xf9, 0x91, 0xc9, 0xa6, 0x8c, 0xe7, 0x4d, 0x50, 0xf8, 0x95, 0x5f, 0xce, 0xb0, 0x67, 0x95, + 0x1c, 0xa6, 0x6f, 0xc8, 0x77, 0x17, 0x39, 0x44, 0xdf, 0x95, 0xda, 0x1a, 0x65, 0x3c, 0xa3, 0xdd, 0x7a, 0x12, 0xa0, + 0x1b, 0xcc, 0xb5, 0xd8, 0x1a, 0x2e, 0x39, 0x44, 0xeb, 0xe5, 0x6d, 0xd4, 0x32, 0x6c, 0xbd, 0x65, 0x23, 0xb5, 0xad, + 0xad, 0xed, 0x23, 0x83, 0xdc, 0x86, 0x92, 0x5e, 0x62, 0x33, 0x62, 0xbd, 0x2b, 0xe2, 0xfc, 0xa9, 0x94, 0x38, 0xf0, + 0xe6, 0xd9, 0xbf, 0x4e, 0x2e, 0xe1, 0x7a, 0xb1, 0x4a, 0x89, 0xbb, 0x0f, 0x64, 0x51, 0x3c, 0x96, 0x54, 0xe0, 0xfb, + 0xb4, 0xbc, 0x54, 0xb7, 0x57, 0x96, 0x20, 0x66, 0xa2, 0xf6, 0xd3, 0xf9, 0xcd, 0xfd, 0x87, 0xbf, 0x7b, 0xf9, 0x85, + 0xc1, 0x91, 0x7d, 0x9b, 0x8b, 0xef, 0x77, 0xe1, 0x20, 0xa4, 0xf1, 0x6d, 0xc4, 0x32, 0x25, 0xf3, 0x2e, 0xc1, 0x25, + 0xd7, 0x9d, 0x73, 0x93, 0xdb, 0x29, 0x68, 0xaa, 0x3e, 0xdd, 0x66, 0xb6, 0xe2, 0xe8, 0xf1, 0xfc, 0xc6, 0xee, 0x46, + 0x7b, 0x2d, 0x67, 0xf3, 0x0f, 0x4d, 0xcd, 0xdc, 0x9d, 0x0b, 0x5a, 0x4f, 0x2f, 0x7c, 0x34, 0xbf, 0xe9, 0x6a, 0x41, + 0xdb, 0x14, 0x1a, 0xaa, 0xd6, 0xfc, 0xc6, 0x4d, 0x4e, 0xad, 0x06, 0xf2, 0xc2, 0xa3, 0xdc, 0xa3, 0x71, 0x4e, 0xbb, + 0xf0, 0xbe, 0x6a, 0x36, 0x8a, 0x53, 0x23, 0xcc, 0x67, 0x2c, 0x49, 0x52, 0xda, 0xb5, 0xf2, 0xda, 0x6b, 0x3f, 0x86, + 0xdc, 0x4e, 0x77, 0xcb, 0xea, 0xbb, 0xe2, 0x20, 0xaf, 0xc4, 0x53, 0x7c, 0x99, 0xf3, 0x14, 0x3e, 0x16, 0xb1, 0x15, + 0x9d, 0x26, 0xe9, 0xb1, 0x55, 0x21, 0x4f, 0xfd, 0xae, 0xaf, 0xe5, 0x51, 0xeb, 0x4f, 0x5d, 0xb5, 0xe1, 0xad, 0xae, + 0xe4, 0xf3, 0xa8, 0x79, 0x54, 0x5f, 0x08, 0x54, 0x95, 0x4b, 0xc0, 0x5b, 0x96, 0x85, 0x41, 0x5a, 0x69, 0x3e, 0xed, + 0x85, 0x6d, 0x53, 0xa6, 0x06, 0x80, 0x17, 0x2b, 0x97, 0x45, 0x45, 0x7d, 0x31, 0xff, 0x3e, 0xa7, 0xe5, 0xf3, 0xed, + 0xa7, 0xe5, 0x73, 0x7b, 0x5a, 0xee, 0xa6, 0xd8, 0xcf, 0xc6, 0x6d, 0xf8, 0xd3, 0xad, 0x16, 0x14, 0xb5, 0xbc, 0xa3, + 0xf9, 0x8d, 0x07, 0x7a, 0x5a, 0xb3, 0x33, 0xbf, 0xd1, 0xa9, 0xb9, 0x10, 0x36, 0x68, 0x41, 0xb2, 0x2a, 0x6e, 0x79, + 0x50, 0x08, 0x7f, 0x5b, 0xb5, 0xaa, 0xf6, 0x43, 0xa8, 0x83, 0x5e, 0x8f, 0x36, 0xeb, 0x3a, 0x77, 0x1f, 0xda, 0x28, + 0xe3, 0x32, 0x88, 0x2c, 0x37, 0x46, 0xa1, 0x8c, 0x2f, 0x2f, 0x69, 0x12, 0x8d, 0xf9, 0x68, 0x91, 0xff, 0xb3, 0x81, + 0xdf, 0x20, 0xf1, 0xce, 0x23, 0xbd, 0x36, 0x8e, 0xed, 0xaa, 0x13, 0x85, 0xed, 0x08, 0xcb, 0x72, 0x9f, 0xa2, 0x7c, + 0x14, 0xa7, 0x34, 0xe8, 0x84, 0x0f, 0xb7, 0x1c, 0x82, 0xff, 0x90, 0xbd, 0xd9, 0xba, 0x98, 0xdf, 0x8b, 0x8c, 0x3b, + 0x91, 0xf0, 0xab, 0x70, 0xe0, 0xee, 0x61, 0xeb, 0xe9, 0x76, 0x70, 0x07, 0x76, 0xa6, 0xa1, 0x15, 0x0a, 0x46, 0xee, + 0x24, 0x74, 0x1c, 0x2f, 0x52, 0x79, 0xf7, 0xa8, 0xbb, 0x28, 0x63, 0x63, 0xd4, 0x3b, 0x18, 0x7a, 0xd5, 0xf6, 0x9e, + 0x5c, 0xfa, 0xb3, 0xcf, 0x1f, 0xc2, 0x1f, 0x9d, 0x67, 0x74, 0x5b, 0xe9, 0xea, 0xda, 0x56, 0x05, 0x5d, 0x7d, 0xbf, + 0xa6, 0x8c, 0x6b, 0x11, 0xae, 0xf4, 0xf1, 0xfb, 0xb6, 0x06, 0xad, 0xf2, 0x5e, 0xcd, 0x8d, 0x96, 0xf5, 0xab, 0x5a, + 0xff, 0xba, 0xc1, 0xef, 0xd9, 0x76, 0xa4, 0x35, 0xd7, 0x7a, 0x5b, 0xf3, 0xed, 0xba, 0x8d, 0xc6, 0x16, 0xe3, 0xaa, + 0xfd, 0x3e, 0xb9, 0x2d, 0x4d, 0x14, 0x1d, 0x08, 0x04, 0x2b, 0x65, 0x5f, 0x5b, 0x29, 0x8c, 0x92, 0x07, 0xf0, 0xe6, + 0x58, 0xef, 0x66, 0x96, 0x66, 0x39, 0xf1, 0xa7, 0x52, 0xce, 0x23, 0xfd, 0xb1, 0xd3, 0xeb, 0xa3, 0x90, 0x8b, 0xc9, + 0x61, 0xa7, 0xd5, 0x6a, 0xc1, 0x1b, 0x3f, 0x7d, 0xef, 0x8a, 0xd1, 0xeb, 0x67, 0xfc, 0x86, 0xf8, 0x4f, 0xbc, 0xa7, + 0xde, 0x93, 0x23, 0xef, 0xd1, 0x63, 0xdf, 0x53, 0xec, 0x9c, 0xf8, 0x4f, 0x8e, 0x7c, 0x4f, 0xb3, 0x73, 0xe2, 0x3f, + 0x7a, 0xec, 0xf7, 0x8e, 0x27, 0x56, 0x25, 0x83, 0x2b, 0x83, 0x5a, 0xdf, 0xc9, 0xa5, 0xe0, 0x1f, 0x69, 0xfd, 0xe0, + 0xea, 0x32, 0x93, 0x89, 0xd6, 0xb1, 0x8f, 0x70, 0x7a, 0x47, 0xf1, 0x3c, 0x52, 0x44, 0xe1, 0x16, 0x82, 0x5b, 0x46, + 0x97, 0xaa, 0x29, 0x40, 0xcd, 0xbc, 0xf4, 0x7b, 0xc7, 0x90, 0x35, 0xee, 0x25, 0xc4, 0x7f, 0xdd, 0x79, 0xe2, 0xb5, + 0x1f, 0x5f, 0x35, 0x1f, 0x8e, 0x5a, 0xcd, 0xb6, 0xd7, 0x6e, 0x76, 0xc2, 0x27, 0x5e, 0x47, 0xff, 0xeb, 0xb5, 0xbc, + 0x23, 0xaf, 0x1d, 0x3e, 0xf1, 0x8e, 0xbc, 0x4e, 0xf8, 0xe4, 0xea, 0xa1, 0x4e, 0x27, 0x88, 0xfd, 0xc3, 0xde, 0x31, + 0x7c, 0xb8, 0xf2, 0x86, 0xf8, 0x9f, 0xfb, 0xfa, 0xf3, 0xb0, 0xfe, 0x67, 0x6e, 0x69, 0xfb, 0xe9, 0xd6, 0xe2, 0xce, + 0x93, 0xad, 0xc5, 0x47, 0x8f, 0xb7, 0x16, 0x3f, 0x7c, 0x54, 0x2f, 0x3e, 0x9c, 0xe8, 0xaa, 0xf2, 0x94, 0x13, 0x7f, + 0x16, 0x4b, 0xc1, 0x6e, 0x82, 0xb6, 0xd7, 0xf2, 0x5a, 0x5e, 0x13, 0xfe, 0x7b, 0xd2, 0x41, 0x65, 0xaf, 0x4b, 0xe8, + 0x55, 0xae, 0xf2, 0xc9, 0x53, 0xaf, 0xfd, 0xf8, 0x65, 0xe7, 0xf1, 0x08, 0xda, 0xa9, 0x85, 0xb6, 0xbd, 0xf6, 0xd5, + 0xd1, 0xd3, 0x51, 0xcb, 0x83, 0x8e, 0x6d, 0xf8, 0x33, 0x7d, 0xd4, 0x19, 0xe9, 0x87, 0x16, 0xd4, 0x7f, 0xdb, 0x7e, + 0x92, 0xb7, 0x9a, 0x6d, 0xf8, 0xf3, 0x4b, 0xa9, 0x11, 0x83, 0x3e, 0xee, 0x8e, 0xfb, 0xb0, 0xe5, 0x1d, 0x3d, 0x9d, + 0x76, 0xc2, 0xcf, 0xaf, 0x9e, 0x84, 0x4f, 0xa7, 0xed, 0x27, 0xdf, 0xea, 0xa7, 0xb4, 0xd9, 0x09, 0x3f, 0x87, 0xbf, + 0xdf, 0x1e, 0xb5, 0xa6, 0xcd, 0x76, 0xf8, 0xf4, 0xea, 0x28, 0x3c, 0x4a, 0x9b, 0x8f, 0xc3, 0xa7, 0xf0, 0xb7, 0x1a, + 0x6e, 0xca, 0x67, 0xd4, 0xf7, 0x60, 0xbf, 0xd7, 0xcc, 0x2d, 0x77, 0x8e, 0xce, 0x43, 0xef, 0xd1, 0xc3, 0x97, 0x4f, + 0xaf, 0x9a, 0x0f, 0xa7, 0xed, 0xce, 0x55, 0x73, 0xe7, 0xcf, 0x6f, 0x01, 0xf1, 0x66, 0xe0, 0x98, 0xc2, 0xf5, 0x1d, + 0x8b, 0x38, 0xf5, 0xf6, 0xd9, 0x07, 0x38, 0xdf, 0x65, 0x5e, 0x8b, 0x4f, 0x9b, 0xd7, 0x19, 0xbd, 0x8f, 0x7d, 0x2d, + 0xfe, 0x70, 0xfb, 0x3a, 0xa7, 0x6b, 0x4e, 0xd5, 0x5b, 0xb9, 0x61, 0x46, 0xaf, 0xdb, 0x5e, 0xef, 0x64, 0x30, 0x60, + 0xf0, 0x95, 0xa3, 0xa2, 0x7b, 0x0b, 0x2f, 0xb8, 0x76, 0xbd, 0x0d, 0x1c, 0x0e, 0xf2, 0xad, 0xd4, 0x27, 0x99, 0xef, + 0x42, 0x48, 0xfa, 0x69, 0x84, 0x7c, 0x7b, 0x1f, 0x7c, 0xa4, 0x7f, 0x38, 0x3e, 0xb8, 0x8b, 0x8f, 0x9a, 0x9f, 0x57, + 0xd9, 0xb3, 0xca, 0x1e, 0x3d, 0x53, 0xcf, 0x01, 0xdc, 0xf0, 0x68, 0xf8, 0x87, 0x14, 0x8a, 0x72, 0x5f, 0xc7, 0x15, + 0xde, 0xfc, 0x1a, 0x97, 0xb4, 0xbe, 0xce, 0x45, 0x7c, 0x63, 0xfc, 0xcf, 0xe1, 0x4b, 0x06, 0xf6, 0xe1, 0x4a, 0x5f, + 0x30, 0x26, 0x7e, 0x27, 0x6c, 0x85, 0xad, 0xd2, 0x71, 0x00, 0x57, 0xf8, 0xc8, 0x92, 0xcb, 0x18, 0x3e, 0xa6, 0x99, + 0xf2, 0x89, 0xfa, 0xec, 0x26, 0xbc, 0xec, 0x5c, 0x7d, 0x00, 0x55, 0xbf, 0x67, 0x3e, 0xf2, 0x7d, 0x73, 0xf1, 0x1f, + 0xae, 0x88, 0x7d, 0x03, 0xd7, 0xe8, 0xac, 0xc7, 0x7a, 0x06, 0x36, 0xf5, 0x6b, 0x9a, 0xb0, 0x38, 0xf0, 0x83, 0xb9, + 0xa0, 0x63, 0x2a, 0xf2, 0x66, 0xed, 0x6e, 0x99, 0xba, 0x56, 0x86, 0x7c, 0xfb, 0xd9, 0x46, 0x01, 0x2f, 0xef, 0x25, + 0x03, 0xe3, 0xd5, 0xf2, 0x8d, 0x9a, 0xef, 0x17, 0xd8, 0x96, 0x08, 0xe0, 0xe8, 0x95, 0x6a, 0xe0, 0x6b, 0xdd, 0xa0, + 0x1d, 0x76, 0x1e, 0x21, 0xcd, 0x4b, 0xe0, 0xa5, 0xa8, 0xdf, 0x07, 0xcd, 0xa3, 0xd6, 0x9f, 0x90, 0xd3, 0xad, 0x1c, + 0x68, 0x68, 0x9c, 0x3a, 0xa2, 0xfa, 0xdc, 0x6d, 0xfd, 0xe2, 0x9f, 0xaf, 0x29, 0xe2, 0x33, 0xbd, 0x76, 0x78, 0xbd, + 0xaa, 0x89, 0x1f, 0xea, 0xeb, 0xeb, 0x63, 0x36, 0x09, 0xdc, 0x8f, 0x99, 0xea, 0x97, 0xae, 0xaa, 0x6f, 0x20, 0xa3, + 0xa2, 0x6a, 0x22, 0xd0, 0x52, 0xf9, 0xe2, 0x59, 0xe6, 0x89, 0xd5, 0x2a, 0x10, 0xe0, 0x88, 0x25, 0x0e, 0x4e, 0xe1, + 0x19, 0xd5, 0x90, 0x2c, 0x70, 0x09, 0x90, 0x42, 0x30, 0x11, 0xfa, 0xff, 0xaa, 0xd8, 0xfe, 0x30, 0xee, 0x95, 0x30, + 0x8d, 0xb3, 0x09, 0x50, 0x61, 0x9c, 0x4d, 0x36, 0x9c, 0x37, 0x3a, 0x9c, 0xb0, 0x56, 0x5a, 0x0d, 0x55, 0x39, 0x69, + 0xf2, 0x67, 0xb7, 0xef, 0xcd, 0xdb, 0x99, 0x7c, 0xf0, 0x81, 0x2a, 0xdf, 0x77, 0xf5, 0x26, 0xd9, 0x06, 0x79, 0xa0, + 0x3f, 0x0f, 0xae, 0xf2, 0xd1, 0x40, 0xfa, 0xc1, 0x95, 0x3e, 0xcf, 0xd8, 0x3c, 0xc4, 0xd7, 0xb2, 0x2f, 0xa1, 0x57, + 0x6c, 0x64, 0x44, 0x18, 0xf6, 0xcc, 0xb5, 0xe6, 0xa6, 0xda, 0x1a, 0xd2, 0xc6, 0xda, 0xea, 0x1f, 0xc5, 0x2a, 0xbf, + 0x98, 0x64, 0xdc, 0xef, 0x3d, 0x28, 0xbf, 0xcd, 0xb8, 0x6b, 0x13, 0xe0, 0x9b, 0xe5, 0x03, 0x41, 0xd3, 0x7f, 0x26, + 0x0f, 0xe0, 0xab, 0xe5, 0x0f, 0x86, 0xf0, 0xc1, 0xec, 0x50, 0x89, 0x82, 0x07, 0xd5, 0xc7, 0xcb, 0x81, 0x0f, 0x36, + 0x6e, 0x66, 0x29, 0xbe, 0xaf, 0xf8, 0x36, 0xa2, 0xba, 0xf3, 0xa8, 0x12, 0xd5, 0x9d, 0x47, 0xae, 0xf4, 0x6c, 0x7b, + 0xed, 0x4e, 0xf8, 0xc8, 0x11, 0x00, 0x57, 0x4d, 0xf8, 0xbf, 0x26, 0x02, 0x1e, 0x86, 0x8f, 0x4a, 0x19, 0xf0, 0xaa, + 0xdd, 0x09, 0x8f, 0xb4, 0xb8, 0xe9, 0x84, 0x8f, 0x7e, 0x50, 0x0c, 0x5a, 0x33, 0xe7, 0xfa, 0x81, 0xd8, 0x12, 0xaa, + 0xd1, 0x49, 0x75, 0x3e, 0x0e, 0xca, 0x2f, 0xc0, 0x99, 0xf3, 0x69, 0x5c, 0x42, 0xcf, 0x63, 0x01, 0x9f, 0xe1, 0xa8, + 0x9f, 0xdd, 0x5a, 0x1d, 0xae, 0xf1, 0x8b, 0x2d, 0x53, 0xc0, 0x09, 0xf7, 0xb1, 0x7b, 0x2f, 0x18, 0x2e, 0xd5, 0xaa, + 0x97, 0x16, 0xdb, 0x77, 0xb7, 0xed, 0x26, 0x6d, 0xdd, 0xd0, 0xbe, 0x1f, 0x4e, 0x31, 0x0b, 0xa6, 0x5e, 0x10, 0xaf, + 0x26, 0xf9, 0x32, 0x29, 0xd6, 0xe7, 0x87, 0xdc, 0x3e, 0xc1, 0x9d, 0xab, 0xd1, 0xb4, 0x4a, 0x3f, 0x4f, 0x18, 0x5c, + 0x66, 0x2f, 0x0a, 0x0b, 0x7a, 0xcd, 0x19, 0x58, 0x61, 0x49, 0xf1, 0x0b, 0x9a, 0xf7, 0x7d, 0x28, 0xf2, 0x23, 0x5f, + 0x39, 0x92, 0xfc, 0xf2, 0x53, 0x24, 0x25, 0x61, 0x57, 0x05, 0x58, 0x5d, 0x21, 0x81, 0x53, 0x0b, 0xf8, 0xf1, 0xd1, + 0xc1, 0xc1, 0xce, 0xf3, 0xa2, 0xb4, 0x31, 0x58, 0x6b, 0xf5, 0x09, 0x03, 0x97, 0x15, 0xf9, 0x2e, 0xa2, 0xcb, 0x71, + 0x15, 0x0a, 0x91, 0xc1, 0xd3, 0x25, 0x8d, 0x65, 0x18, 0x67, 0x3a, 0x45, 0xc1, 0x61, 0x58, 0xb8, 0x4d, 0x8f, 0x50, + 0xc1, 0x65, 0xec, 0x7c, 0xa3, 0xd4, 0x9c, 0x73, 0x2e, 0x63, 0x7b, 0xd1, 0x2f, 0x93, 0xb5, 0x4c, 0xf8, 0x69, 0xa7, + 0xf7, 0xf6, 0xfd, 0x89, 0xa7, 0x8f, 0xe7, 0xf1, 0xe1, 0xb4, 0xd3, 0x3b, 0x56, 0x96, 0xb9, 0xbe, 0x26, 0x44, 0xf4, + 0x35, 0x21, 0xcf, 0x5c, 0x19, 0x83, 0x78, 0x4d, 0x71, 0xa8, 0x97, 0xed, 0x7b, 0x34, 0x1b, 0x69, 0x9f, 0xe2, 0x6c, + 0x91, 0x4a, 0x06, 0x2f, 0xe0, 0x3d, 0x84, 0xae, 0x4d, 0xd8, 0xb0, 0x32, 0xcf, 0xd4, 0x6a, 0x38, 0x32, 0xb3, 0x1e, + 0xc8, 0x31, 0x4b, 0xa9, 0xcd, 0x2c, 0x35, 0x43, 0x95, 0x79, 0xcf, 0x9b, 0xad, 0xf3, 0xc5, 0xe5, 0x8c, 0xc9, 0x32, + 0x15, 0xf4, 0x83, 0xe9, 0x70, 0xac, 0xa6, 0xea, 0x5d, 0x14, 0xc6, 0x45, 0x6a, 0x3f, 0x36, 0xb2, 0xf6, 0x79, 0x77, + 0xbd, 0x7a, 0x23, 0x21, 0xe0, 0xbe, 0xcf, 0xf4, 0xa8, 0x57, 0x3a, 0x25, 0xdd, 0xba, 0xe2, 0xf8, 0x70, 0x7a, 0xd4, + 0xbb, 0x88, 0xe6, 0x66, 0xbc, 0x57, 0x7c, 0xe3, 0x53, 0xf1, 0x25, 0xc7, 0xec, 0xab, 0xc4, 0x76, 0x7d, 0x83, 0xd2, + 0x00, 0x3c, 0xe2, 0xa9, 0xdf, 0x3b, 0x36, 0xca, 0x80, 0xa7, 0x82, 0xae, 0xfe, 0xa3, 0x96, 0xcd, 0x95, 0x4f, 0xb9, + 0xd2, 0x96, 0x74, 0x17, 0x67, 0x92, 0x9a, 0x5f, 0x77, 0xda, 0xee, 0x1d, 0xc7, 0x46, 0xcd, 0x04, 0xe6, 0x91, 0x47, + 0x87, 0xd0, 0x19, 0x74, 0xb9, 0x90, 0xf1, 0xc3, 0x6b, 0x7a, 0xd9, 0x8c, 0xe7, 0xac, 0x72, 0xa2, 0x82, 0xd2, 0x51, + 0x4e, 0xc9, 0xab, 0x99, 0xe0, 0x67, 0xbc, 0xb6, 0x48, 0xc5, 0xc2, 0x0b, 0xe3, 0xa1, 0x55, 0xba, 0x3a, 0x8d, 0xa5, + 0xef, 0x69, 0x0e, 0x6f, 0x3d, 0xb9, 0x46, 0xf6, 0x16, 0x7e, 0xef, 0xdf, 0xfe, 0xc7, 0xff, 0x32, 0xce, 0xd9, 0xe3, + 0xc3, 0x69, 0xdb, 0x8e, 0xb5, 0x86, 0xe8, 0xe2, 0x18, 0xae, 0x97, 0x55, 0xd1, 0x44, 0x7a, 0xd3, 0x9c, 0x08, 0x96, + 0x34, 0xa7, 0x71, 0x3a, 0xf6, 0x7b, 0xbb, 0x11, 0xe4, 0xde, 0x2b, 0x31, 0x50, 0xd7, 0x8b, 0x80, 0x04, 0x7f, 0xd3, + 0xcd, 0x08, 0x9b, 0x60, 0xaf, 0x4e, 0xab, 0x7b, 0x4f, 0xa2, 0x3a, 0x50, 0xb5, 0xbb, 0x12, 0xc2, 0x7c, 0x93, 0xc8, + 0x30, 0x35, 0x51, 0xbb, 0x22, 0x51, 0xf8, 0x5e, 0x19, 0x0d, 0xf9, 0xbf, 0xff, 0xf3, 0xbf, 0xfc, 0x37, 0xfb, 0x08, + 0x41, 0x8e, 0x7f, 0xfb, 0xef, 0xff, 0xf9, 0xff, 0xfc, 0xef, 0xff, 0x0a, 0x69, 0xf5, 0x26, 0x10, 0xa2, 0xf8, 0x84, + 0x57, 0x45, 0x41, 0x34, 0xc3, 0xf0, 0x20, 0x19, 0x6d, 0xc6, 0x72, 0xc9, 0x46, 0xf5, 0x4b, 0x13, 0x67, 0x6a, 0x42, + 0x75, 0xd8, 0x0c, 0x74, 0xea, 0xd0, 0x16, 0x15, 0x8d, 0xd4, 0x50, 0xae, 0x68, 0xb1, 0x38, 0x3e, 0x04, 0x7c, 0xdf, + 0xef, 0x9e, 0x59, 0x58, 0x6e, 0xc7, 0xd2, 0xba, 0xfe, 0xa0, 0xa4, 0xa8, 0xca, 0x3d, 0x70, 0xca, 0x2f, 0xe1, 0x31, + 0xea, 0x38, 0xc5, 0x6a, 0xf7, 0x6a, 0x7d, 0xba, 0x3f, 0x2d, 0x72, 0xc9, 0xc6, 0x80, 0x72, 0xed, 0x60, 0x54, 0xf1, + 0xcf, 0x26, 0xa8, 0x7f, 0xe9, 0x6d, 0xa1, 0x46, 0xd1, 0x36, 0xe3, 0xc3, 0xa7, 0x7f, 0x2a, 0xfe, 0x32, 0x03, 0x25, + 0xcb, 0x0b, 0x66, 0xf1, 0x8d, 0xb1, 0x24, 0x1f, 0xb7, 0x5a, 0xf3, 0x1b, 0xb4, 0xac, 0x66, 0xc0, 0xbb, 0x26, 0x53, + 0x4e, 0x49, 0x77, 0x40, 0x15, 0x38, 0x2d, 0xfd, 0x9f, 0x2d, 0x0f, 0x9c, 0xa8, 0x5e, 0xab, 0x28, 0xfe, 0xbc, 0x54, + 0x2e, 0x38, 0xf6, 0x0b, 0x04, 0x38, 0x8d, 0xb7, 0xf2, 0x92, 0xbb, 0x8b, 0x5b, 0x3a, 0xbd, 0x3a, 0xba, 0xd7, 0xb4, + 0xbd, 0x79, 0x7d, 0xca, 0x0d, 0xd0, 0xba, 0xa1, 0xd5, 0x87, 0x10, 0x2c, 0x9d, 0xb6, 0xf1, 0xb4, 0xb3, 0x2c, 0x87, + 0x97, 0x92, 0xcf, 0xdc, 0x88, 0x2c, 0x8d, 0xe9, 0x88, 0x8e, 0xad, 0x97, 0xd7, 0xd4, 0xeb, 0x68, 0x6b, 0x31, 0x3d, + 0xda, 0x32, 0x97, 0x01, 0x49, 0x45, 0x62, 0xbd, 0x56, 0xf1, 0x19, 0x9c, 0xc0, 0xe5, 0x38, 0xe5, 0xb1, 0x8c, 0x14, + 0xc1, 0x76, 0xdd, 0xb8, 0x6e, 0x0c, 0x6c, 0x86, 0x2f, 0x1d, 0x78, 0xba, 0xba, 0x29, 0xf8, 0x5b, 0xeb, 0x97, 0xdc, + 0x8a, 0x50, 0x75, 0x77, 0x87, 0xd2, 0xee, 0x9a, 0x6f, 0x4d, 0xb8, 0xf4, 0x4d, 0xcd, 0xcf, 0x61, 0x64, 0x4c, 0x07, + 0x6d, 0xaf, 0xd7, 0xa2, 0x5a, 0xd7, 0x7e, 0x25, 0x03, 0x5f, 0x81, 0xe9, 0xaf, 0xb7, 0x52, 0x85, 0xd0, 0xea, 0x0d, + 0xf9, 0xb6, 0xb4, 0x82, 0xe2, 0xf9, 0x5c, 0x35, 0x44, 0xdd, 0xe3, 0x43, 0xad, 0xbc, 0x02, 0xf7, 0x50, 0xb9, 0x00, + 0x3a, 0xf4, 0x6e, 0x1a, 0x99, 0xa3, 0xa0, 0x7f, 0x99, 0xa0, 0x3c, 0x7c, 0xac, 0xaa, 0xf7, 0xff, 0x00, 0xbb, 0x9f, + 0x49, 0x8d, 0x3d, 0x86, 0x00, 0x00}; + +} // namespace web_server +} // namespace esphome +#endif +#endif diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h new file mode 100644 index 0000000000..49de0cfab6 --- /dev/null +++ b/esphome/components/web_server/server_index_v3.h @@ -0,0 +1,3995 @@ +#pragma once +// Generated from https://github.com/esphome/esphome-webserver +#ifdef USE_WEBSERVER_LOCAL +#if USE_WEBSERVER_VERSION == 3 +#include "esphome/core/hal.h" +namespace esphome { + +namespace web_server { + +const uint8_t INDEX_GZ[] PROGMEM = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0xeb, 0x7a, 0x1b, 0xb7, 0xb2, 0x20, 0xfa, + 0xfb, 0xcc, 0x53, 0x48, 0xbd, 0x1d, 0xa5, 0x21, 0x82, 0x2d, 0x92, 0xba, 0x58, 0x6e, 0x0a, 0xe2, 0xf8, 0x1a, 0x3b, + 0x71, 0x6c, 0xc7, 0x72, 0xec, 0xd8, 0x0c, 0xb7, 0x02, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, + 0xe4, 0xbb, 0x9f, 0xaf, 0x70, 0xe9, 0x46, 0x93, 0xb4, 0xd7, 0x5a, 0x73, 0x66, 0xce, 0x37, 0x3b, 0x7b, 0x59, 0x6c, + 0xdc, 0x51, 0x28, 0x14, 0xaa, 0x0a, 0x55, 0x85, 0x8b, 0xfd, 0x91, 0xcc, 0xf4, 0xdd, 0x9c, 0xed, 0x4d, 0xf5, 0x2c, + 0xbf, 0xbc, 0x70, 0xff, 0x32, 0x3a, 0xba, 0xbc, 0xc8, 0xb9, 0xf8, 0xbc, 0x57, 0xb0, 0x9c, 0xf0, 0x4c, 0x8a, 0xbd, + 0x69, 0xc1, 0xc6, 0x64, 0x44, 0x35, 0x4d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xe5, 0xc5, 0x8c, 0x69, 0xba, 0x97, + 0x4d, 0x69, 0xa1, 0x98, 0x26, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbf, 0xbc, 0x50, 0x59, 0xc1, 0xe7, 0x7a, 0x0f, 0x9a, + 0x24, 0x33, 0x39, 0x5a, 0xe4, 0xec, 0xf2, 0xe8, 0xe8, 0xe6, 0xe6, 0x26, 0xf9, 0x5b, 0xfd, 0x8f, 0x2f, 0xb4, 0xd8, + 0xfb, 0xa5, 0x20, 0xaf, 0x87, 0x7f, 0xb3, 0x4c, 0x27, 0x23, 0x36, 0xe6, 0x82, 0xbd, 0x29, 0xe4, 0x9c, 0x15, 0xfa, + 0xae, 0x0b, 0x99, 0x3f, 0x15, 0x24, 0xe6, 0x58, 0x63, 0x86, 0xc8, 0xa5, 0xde, 0xe3, 0x62, 0x8f, 0xf7, 0x7e, 0x29, + 0x4c, 0xca, 0x92, 0x89, 0xc5, 0x8c, 0x15, 0x74, 0x98, 0xb3, 0x74, 0xbf, 0x85, 0x33, 0x29, 0xc6, 0x7c, 0xb2, 0x28, + 0xbf, 0x6f, 0x0a, 0xae, 0xfd, 0xef, 0x2f, 0x34, 0x5f, 0xb0, 0x94, 0xad, 0x51, 0xca, 0xfb, 0x7a, 0x40, 0x98, 0x69, + 0xf9, 0x73, 0xd5, 0x70, 0xfc, 0x93, 0x69, 0xf2, 0x6e, 0xce, 0xe4, 0x78, 0x4f, 0xef, 0x93, 0x48, 0xdd, 0xcd, 0x86, + 0x32, 0x8f, 0x7a, 0xba, 0x11, 0x45, 0x29, 0x94, 0xc1, 0x0c, 0x75, 0x33, 0x29, 0x94, 0xde, 0x13, 0x9c, 0xdc, 0x70, + 0x31, 0x92, 0x37, 0xf8, 0x46, 0x10, 0xc1, 0x93, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x83, 0x83, 0xd8, + 0x7d, 0xdf, 0x3d, 0xbe, 0xba, 0x22, 0x84, 0x7c, 0x91, 0x7c, 0xb4, 0xd7, 0x5a, 0xad, 0x82, 0xd4, 0x44, 0x50, 0xcd, + 0xbf, 0x30, 0x5b, 0x09, 0x1d, 0x1c, 0x44, 0x74, 0x24, 0xe7, 0x9a, 0x8d, 0xae, 0xf4, 0x5d, 0xce, 0xae, 0xa6, 0x8c, + 0x69, 0x15, 0x71, 0xb1, 0xf7, 0x44, 0x66, 0x8b, 0x19, 0x13, 0x3a, 0x99, 0x17, 0x52, 0x4b, 0x18, 0xd8, 0xc1, 0x41, + 0x54, 0xb0, 0x79, 0x4e, 0x33, 0x06, 0xf9, 0x8f, 0xaf, 0xae, 0xaa, 0x1a, 0x55, 0x21, 0xfc, 0x59, 0x90, 0x2b, 0x33, + 0xf4, 0x18, 0xe1, 0x0f, 0x82, 0x08, 0x76, 0xb3, 0xf7, 0x81, 0xd1, 0xcf, 0xbf, 0xd2, 0x79, 0x37, 0xcb, 0xa9, 0x52, + 0x7b, 0xcf, 0xe4, 0xd2, 0x4c, 0xa3, 0x58, 0x64, 0x5a, 0x16, 0xb1, 0xc6, 0x0c, 0x0b, 0xb4, 0xe4, 0xe3, 0x58, 0x4f, + 0xb9, 0x4a, 0xae, 0xef, 0x65, 0x4a, 0xbd, 0x65, 0x6a, 0x91, 0xeb, 0x7b, 0x64, 0xbf, 0x85, 0xc5, 0x3e, 0x21, 0x9f, + 0x05, 0xd2, 0xd3, 0x42, 0xde, 0xec, 0x3d, 0x2d, 0x0a, 0x59, 0xc4, 0xd1, 0xe3, 0xab, 0x2b, 0x5b, 0x62, 0x8f, 0xab, + 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0xbf, 0x16, 0x42, 0xd1, 0x31, 0x7b, + 0x7c, 0x75, 0xf5, 0xd7, 0x9e, 0x2c, 0xf6, 0xfe, 0xca, 0x94, 0xfa, 0x6b, 0x8f, 0x0b, 0xa5, 0x19, 0x1d, 0x25, 0x11, + 0xea, 0x9a, 0xce, 0x32, 0xa5, 0xde, 0xb1, 0x5b, 0x4d, 0x34, 0x36, 0x9f, 0x9a, 0xb0, 0xf5, 0x84, 0xe9, 0x3d, 0x55, + 0xce, 0x2b, 0x46, 0xcb, 0x9c, 0xe9, 0x3d, 0x4d, 0x4c, 0xbe, 0x74, 0xf0, 0x67, 0xf6, 0x53, 0x77, 0xf9, 0x38, 0xbe, + 0x11, 0x07, 0x07, 0xba, 0x04, 0x34, 0x5a, 0xba, 0x15, 0x22, 0x6c, 0xdf, 0xa7, 0x1d, 0x1c, 0xb0, 0x24, 0x67, 0x62, + 0xa2, 0xa7, 0x84, 0x90, 0x76, 0x57, 0x1c, 0x1c, 0xc4, 0x9a, 0x7c, 0x10, 0xc9, 0x84, 0xe9, 0x98, 0x21, 0x84, 0xab, + 0xda, 0x07, 0x07, 0xb1, 0x05, 0x82, 0x24, 0xda, 0x00, 0xae, 0x06, 0x63, 0x94, 0x38, 0xe8, 0x5f, 0xdd, 0x89, 0x2c, + 0x0e, 0xc7, 0x8f, 0xb0, 0x38, 0x38, 0xf8, 0x20, 0x12, 0x05, 0x2d, 0x62, 0x8d, 0xd0, 0xba, 0x60, 0x7a, 0x51, 0x88, + 0x3d, 0xbd, 0xd6, 0xf2, 0x4a, 0x17, 0x5c, 0x4c, 0x62, 0xb4, 0xf4, 0x69, 0x41, 0xc5, 0xf5, 0xda, 0x0e, 0xf7, 0xb7, + 0x82, 0x70, 0x72, 0x09, 0x3d, 0x3e, 0x93, 0xb1, 0xc3, 0x41, 0x4e, 0x48, 0xa4, 0x4c, 0xdd, 0xa8, 0xc7, 0x53, 0xde, + 0x88, 0x22, 0x6c, 0x47, 0x89, 0x3f, 0x0b, 0x84, 0xb9, 0x06, 0xd4, 0x4d, 0x92, 0x44, 0x23, 0x72, 0xb9, 0xf4, 0x60, + 0xe1, 0xc1, 0x44, 0x7b, 0xbc, 0xdf, 0x1a, 0xa4, 0x3a, 0x29, 0xd8, 0x68, 0x91, 0xb1, 0x38, 0x16, 0x58, 0x61, 0x89, + 0xc8, 0xa5, 0x68, 0xc4, 0x05, 0xb9, 0x84, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xb9, 0x41, 0x16, 0x7e, + 0x84, 0x00, 0x62, 0x37, 0xa0, 0x82, 0x90, 0x48, 0x2c, 0x66, 0x43, 0x56, 0x44, 0x65, 0xb1, 0x6e, 0x0d, 0x2f, 0x16, + 0x8a, 0xed, 0x65, 0x4a, 0xed, 0x8d, 0x17, 0x22, 0xd3, 0x5c, 0x8a, 0xbd, 0xa8, 0x51, 0x34, 0x22, 0x8b, 0x0f, 0x25, + 0x3a, 0x44, 0x68, 0x8d, 0x62, 0x85, 0x1a, 0xbc, 0x2f, 0x1b, 0xed, 0x01, 0x86, 0x51, 0xa2, 0xae, 0x6b, 0xcf, 0x41, + 0x80, 0x61, 0x0e, 0x93, 0x5c, 0xe3, 0x4f, 0x76, 0xe7, 0xc3, 0x14, 0x6f, 0x44, 0x8f, 0x27, 0xdb, 0x3b, 0x85, 0xe8, + 0x64, 0x46, 0xe7, 0x31, 0x23, 0x97, 0xcc, 0x60, 0x17, 0x15, 0x19, 0x8c, 0xb5, 0xb6, 0x70, 0x3d, 0x96, 0xb2, 0xa4, + 0xc2, 0x29, 0x94, 0xea, 0x64, 0x2c, 0x8b, 0xa7, 0x34, 0x9b, 0x42, 0xbd, 0x12, 0x63, 0x46, 0x7e, 0xc3, 0x65, 0x05, + 0xa3, 0x9a, 0x3d, 0xcd, 0x19, 0x7c, 0xc5, 0x91, 0xa9, 0x19, 0x21, 0xac, 0x60, 0xab, 0xe7, 0x5c, 0xbf, 0x92, 0x22, + 0x63, 0x5d, 0x15, 0xe0, 0x97, 0x59, 0xf9, 0x87, 0x5a, 0x17, 0x7c, 0xb8, 0xd0, 0x2c, 0x8e, 0x04, 0x94, 0x88, 0xb0, + 0x42, 0x58, 0x24, 0x9a, 0xdd, 0xea, 0xc7, 0x52, 0x68, 0x26, 0x34, 0x61, 0x1e, 0xaa, 0x98, 0x27, 0x74, 0x3e, 0x67, + 0x62, 0xf4, 0x78, 0xca, 0xf3, 0x51, 0x2c, 0xd0, 0x1a, 0xad, 0xf1, 0xef, 0x82, 0xc0, 0x24, 0xc9, 0x25, 0x4f, 0xe1, + 0x9f, 0x6f, 0x4f, 0x27, 0xd6, 0xe4, 0xd2, 0x6c, 0x0b, 0x46, 0xa2, 0xa8, 0x3b, 0x96, 0x45, 0xec, 0xa6, 0xb0, 0x07, + 0xa4, 0x0b, 0xfa, 0x78, 0xbb, 0xc8, 0x99, 0x42, 0xac, 0x41, 0x44, 0xb9, 0x8e, 0x0e, 0xc2, 0xbf, 0x15, 0x31, 0x83, + 0x05, 0xe0, 0x28, 0xe5, 0x86, 0x04, 0xbe, 0xe4, 0x6e, 0x53, 0x8d, 0x4a, 0xa2, 0xf6, 0x51, 0x90, 0x11, 0x4f, 0x74, + 0xb1, 0x50, 0x9a, 0x8d, 0xde, 0xdd, 0xcd, 0x99, 0xc2, 0x3f, 0x17, 0xe4, 0xa3, 0xe8, 0x7d, 0x14, 0x09, 0x9b, 0xcd, + 0xf5, 0xdd, 0x95, 0xa1, 0xe6, 0x69, 0x14, 0xe1, 0x7f, 0x4c, 0xd1, 0x82, 0xd1, 0x0c, 0x48, 0x9a, 0x03, 0xd9, 0x1b, + 0x99, 0xdf, 0x8d, 0x79, 0x9e, 0x5f, 0x2d, 0xe6, 0x73, 0x59, 0x68, 0xac, 0x05, 0x59, 0x6a, 0x59, 0xc1, 0x07, 0x56, + 0x74, 0xa9, 0x6e, 0xb8, 0xce, 0xa6, 0xb1, 0x46, 0xcb, 0x8c, 0x2a, 0xb6, 0xf7, 0x48, 0xca, 0x9c, 0x51, 0x91, 0x72, + 0xc2, 0x7b, 0x3f, 0x17, 0xa9, 0x58, 0xe4, 0x79, 0x77, 0x58, 0x30, 0xfa, 0xb9, 0x6b, 0xb2, 0xed, 0xe1, 0x90, 0x9a, + 0xdf, 0x0f, 0x8b, 0x82, 0xde, 0x41, 0x41, 0x42, 0xa0, 0x58, 0x8f, 0xa7, 0x3f, 0x5f, 0xbd, 0x7e, 0x95, 0xd8, 0xbd, + 0xc2, 0xc7, 0x77, 0x31, 0x2f, 0xf7, 0x1f, 0x5f, 0xe3, 0x71, 0x21, 0x67, 0x1b, 0x5d, 0x5b, 0xd0, 0xf1, 0xee, 0x37, + 0x86, 0xc0, 0x08, 0xdf, 0xb7, 0x4d, 0x87, 0x23, 0x78, 0x65, 0x30, 0x1f, 0x32, 0x89, 0xeb, 0x17, 0xfe, 0x49, 0x6d, + 0x72, 0xcc, 0xd1, 0xf7, 0x47, 0xab, 0x8b, 0xbb, 0x25, 0x23, 0x66, 0x9c, 0x73, 0x38, 0x18, 0x61, 0x8c, 0x19, 0xd5, + 0xd9, 0x74, 0xc9, 0x4c, 0x63, 0x6b, 0x3f, 0x62, 0xb6, 0x5e, 0xe3, 0xaf, 0xd2, 0x63, 0xbd, 0xde, 0x27, 0x84, 0x1b, + 0x7a, 0x45, 0xf4, 0x6a, 0xc5, 0x09, 0xe1, 0x08, 0xbf, 0xe5, 0x64, 0x49, 0xfd, 0x84, 0xe0, 0x64, 0x83, 0xed, 0x99, + 0x5a, 0x2a, 0x03, 0x27, 0xe0, 0x17, 0x56, 0x68, 0x56, 0xa4, 0x5a, 0xe0, 0x82, 0x8d, 0x73, 0x18, 0xc7, 0x7e, 0x1b, + 0x4f, 0xa9, 0x7a, 0x3c, 0xa5, 0x62, 0xc2, 0x46, 0xe9, 0x57, 0xb9, 0xc6, 0x4c, 0x90, 0x68, 0xcc, 0x05, 0xcd, 0xf9, + 0x57, 0x36, 0x8a, 0xdc, 0xb9, 0xf0, 0x48, 0xef, 0xb1, 0x5b, 0xcd, 0xc4, 0x48, 0xed, 0x3d, 0x7f, 0xf7, 0xeb, 0x4b, + 0xb7, 0x98, 0xb5, 0xb3, 0x02, 0x2d, 0xd5, 0x62, 0xce, 0x8a, 0x18, 0x61, 0x77, 0x56, 0x3c, 0xe5, 0x86, 0x4e, 0xfe, + 0x4a, 0xe7, 0x36, 0x85, 0xab, 0xdf, 0xe7, 0x23, 0xaa, 0xd9, 0x1b, 0x26, 0x46, 0x5c, 0x4c, 0xc8, 0x7e, 0xdb, 0xa6, + 0x4f, 0xa9, 0xcb, 0x18, 0x95, 0x49, 0xd7, 0xf7, 0x9e, 0xe6, 0x66, 0xee, 0xe5, 0xe7, 0x22, 0x46, 0x6b, 0xa5, 0xa9, + 0xe6, 0xd9, 0x1e, 0x1d, 0x8d, 0x5e, 0x08, 0xae, 0xb9, 0x19, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xec, 0xa9, 0xe1, + 0x47, 0x1e, 0x23, 0x1c, 0xc7, 0xee, 0x2c, 0x98, 0x22, 0xb7, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb1, 0xd4, 0x66, + 0x92, 0xfe, 0x00, 0x25, 0xf3, 0x85, 0x82, 0xc5, 0xf6, 0x5d, 0xc0, 0x41, 0x23, 0x87, 0x8a, 0x15, 0x5f, 0xd8, 0xa8, + 0x44, 0x10, 0x15, 0xa3, 0xe5, 0x46, 0x1f, 0x6e, 0x7b, 0x68, 0xd2, 0x1f, 0x74, 0x43, 0x12, 0xce, 0x1c, 0xb2, 0x5b, + 0x4e, 0x85, 0x33, 0x55, 0x12, 0x95, 0x18, 0x0e, 0xd4, 0x92, 0xb0, 0x28, 0xe2, 0xe7, 0x37, 0x8f, 0x05, 0xf0, 0x10, + 0x21, 0xe5, 0xf0, 0x67, 0xee, 0xd3, 0x2f, 0xe6, 0xf0, 0x50, 0x58, 0x20, 0xac, 0xed, 0x48, 0x15, 0x42, 0x6b, 0x84, + 0xb5, 0x1f, 0xae, 0x25, 0x4a, 0x9e, 0x2f, 0x82, 0x53, 0x9b, 0xbc, 0xe5, 0xe6, 0xd8, 0x06, 0xda, 0x46, 0x35, 0x3b, + 0x38, 0x88, 0x59, 0x52, 0x22, 0x06, 0xd9, 0x6f, 0xbb, 0x45, 0x0a, 0xa0, 0xf5, 0x8d, 0x71, 0x43, 0xcf, 0x86, 0xc1, + 0xd9, 0x67, 0x89, 0x90, 0x0f, 0xb3, 0x8c, 0x29, 0x25, 0x8b, 0x83, 0x83, 0x7d, 0x53, 0xbe, 0xe4, 0x2c, 0x60, 0x11, + 0x5f, 0xdf, 0x88, 0x6a, 0x08, 0xa8, 0x3a, 0x6d, 0x3d, 0xdf, 0x44, 0x2a, 0xbe, 0xc9, 0x33, 0x21, 0x69, 0x74, 0x7d, + 0x1d, 0x35, 0x34, 0x76, 0x70, 0x98, 0x30, 0xdf, 0xf5, 0xdd, 0x13, 0x66, 0xd9, 0x42, 0xc3, 0x84, 0x6c, 0x81, 0x66, + 0x27, 0x3f, 0x18, 0xd7, 0x87, 0x84, 0x35, 0x56, 0x68, 0x1d, 0xac, 0xe8, 0xce, 0xa6, 0x0d, 0x7f, 0x63, 0x97, 0x6e, + 0x39, 0x31, 0x3c, 0x45, 0xb0, 0x8e, 0x7d, 0x36, 0x58, 0x63, 0x03, 0x7b, 0x3f, 0x1b, 0x69, 0x06, 0xda, 0xd7, 0x83, + 0xae, 0xcb, 0x27, 0xca, 0x42, 0xae, 0x60, 0xff, 0x2c, 0x98, 0xd2, 0x16, 0x91, 0x63, 0x8d, 0x25, 0x86, 0x33, 0x6a, + 0x93, 0xe9, 0xac, 0xb1, 0xa4, 0xbb, 0xc6, 0xf6, 0x7a, 0x0e, 0x67, 0xa3, 0x02, 0xa4, 0xfe, 0x3e, 0x3e, 0xc1, 0x58, + 0x35, 0x5a, 0xad, 0xde, 0x72, 0xdf, 0x4a, 0xb5, 0x96, 0x25, 0xbf, 0xb6, 0xb1, 0x28, 0x4c, 0x20, 0x77, 0x38, 0xef, + 0xb7, 0xdd, 0xf8, 0xc5, 0x80, 0xec, 0xb7, 0x4a, 0x2c, 0x76, 0x60, 0xb5, 0xe3, 0xb1, 0x50, 0x7c, 0x6d, 0x9b, 0x42, + 0xe6, 0xac, 0xaf, 0xe1, 0x4b, 0x32, 0xdd, 0xc2, 0xd5, 0x29, 0xe9, 0x03, 0xd7, 0x91, 0x4c, 0x07, 0xdf, 0xc2, 0x27, + 0x4f, 0x11, 0x62, 0xbd, 0x9d, 0x57, 0x11, 0x8e, 0x2f, 0x75, 0xc2, 0xb1, 0x31, 0x8d, 0x68, 0x5e, 0x56, 0x89, 0x4a, + 0x34, 0x73, 0x5b, 0xbd, 0xca, 0xc2, 0xc2, 0x0c, 0xa6, 0x9a, 0x52, 0xd0, 0xc4, 0x2b, 0x3a, 0x63, 0x2a, 0x66, 0x08, + 0x7f, 0xab, 0x80, 0xc5, 0x4f, 0x28, 0x32, 0x08, 0xce, 0x50, 0x05, 0x67, 0x28, 0xb0, 0xbb, 0xc0, 0xa4, 0xd5, 0xb7, + 0x9c, 0xc2, 0xac, 0xaf, 0x06, 0x15, 0x6f, 0x17, 0x4c, 0xde, 0x1c, 0xce, 0x0e, 0xc1, 0x3d, 0xfc, 0x6c, 0x9a, 0x05, + 0x9a, 0x61, 0x21, 0x14, 0xc2, 0xfb, 0xad, 0xcd, 0x95, 0xf4, 0xa5, 0xaa, 0x39, 0xf6, 0x07, 0xb0, 0x0e, 0xe6, 0xd8, + 0x48, 0xb8, 0x32, 0x7f, 0x6b, 0x5b, 0x0d, 0xc0, 0x76, 0x05, 0x98, 0x91, 0x8c, 0x73, 0xaa, 0xe3, 0xf6, 0x51, 0x0b, + 0x18, 0xd3, 0x2f, 0x0c, 0x4e, 0x15, 0x84, 0xb6, 0xa7, 0xc2, 0x92, 0x85, 0x50, 0x53, 0x3e, 0xd6, 0xf1, 0xef, 0xc2, + 0x10, 0x15, 0x96, 0x2b, 0x06, 0x12, 0x4e, 0xc0, 0x1e, 0x1b, 0x82, 0xf3, 0xbb, 0x80, 0x7e, 0xba, 0xe5, 0x41, 0xe4, + 0x46, 0x6a, 0x08, 0x17, 0x90, 0x87, 0x8a, 0xb5, 0xae, 0xc8, 0x4c, 0xc9, 0xb8, 0x01, 0xf7, 0xd8, 0xee, 0xd9, 0x16, + 0x53, 0x47, 0x0d, 0x44, 0xc0, 0xc1, 0x8a, 0x34, 0x24, 0x11, 0x2e, 0x51, 0x27, 0x5a, 0xbe, 0x94, 0x37, 0xac, 0x78, + 0x4c, 0x61, 0xf0, 0xa9, 0xad, 0xbe, 0xb6, 0x47, 0x81, 0xa1, 0xf8, 0xba, 0xeb, 0xf1, 0xe5, 0xda, 0x4c, 0xfc, 0x4d, + 0x21, 0x67, 0x5c, 0x31, 0xe0, 0xdb, 0x2c, 0xfc, 0x05, 0x6c, 0x34, 0xb3, 0x23, 0xe1, 0xb8, 0x61, 0x25, 0x7e, 0x3d, + 0x7c, 0x59, 0xc7, 0xaf, 0xeb, 0x7b, 0x4f, 0x27, 0x9e, 0x02, 0xd6, 0xf7, 0x31, 0xc2, 0xb1, 0x13, 0x2f, 0x82, 0x93, + 0x2e, 0x99, 0x22, 0x77, 0xcc, 0xaf, 0x56, 0x3a, 0x10, 0xe3, 0x6a, 0x9c, 0x23, 0xb3, 0xdb, 0x06, 0xad, 0xe9, 0x68, + 0x04, 0x2c, 0x5e, 0x21, 0xf3, 0x3c, 0x38, 0xac, 0xb0, 0xe8, 0x96, 0xc7, 0xd3, 0xf5, 0xbd, 0xa7, 0x57, 0xdf, 0x3b, + 0xa1, 0x20, 0x3f, 0x3c, 0xa4, 0xfc, 0x40, 0xc5, 0x88, 0x15, 0x20, 0x57, 0x06, 0xab, 0xe5, 0xce, 0xd9, 0xc7, 0x52, + 0x08, 0x96, 0x69, 0x36, 0x02, 0xa1, 0x45, 0x10, 0x9d, 0x4c, 0xa5, 0xd2, 0x65, 0x62, 0x35, 0x7a, 0x11, 0x0a, 0xa1, + 0x49, 0x46, 0xf3, 0x3c, 0xb6, 0x02, 0xca, 0x4c, 0x7e, 0x61, 0x3b, 0x46, 0xdd, 0xad, 0x0d, 0xb9, 0x6c, 0x86, 0x05, + 0xcd, 0xb0, 0x44, 0xcd, 0x73, 0x9e, 0xb1, 0xf2, 0xf0, 0xba, 0x4a, 0xb8, 0x18, 0xb1, 0x5b, 0xa0, 0x23, 0xe8, 0xf2, + 0xf2, 0xb2, 0x85, 0xdb, 0x68, 0x6d, 0x01, 0xbe, 0xdc, 0x02, 0xec, 0x77, 0x8e, 0x4d, 0x2b, 0x88, 0x2f, 0x77, 0x92, + 0x35, 0x14, 0x9c, 0x95, 0xdc, 0x0b, 0x5a, 0x96, 0x3c, 0x23, 0x3c, 0x62, 0x39, 0xd3, 0xcc, 0x93, 0x73, 0x60, 0xa6, + 0xed, 0xd6, 0x7d, 0x5b, 0xc2, 0xaf, 0x44, 0x27, 0xbf, 0xcb, 0xfc, 0x9a, 0xab, 0x52, 0x74, 0xaf, 0x96, 0xa7, 0x82, + 0x76, 0x4f, 0xdb, 0xe5, 0xa1, 0x5a, 0xd3, 0x6c, 0x6a, 0x25, 0xf6, 0x78, 0x6b, 0x4a, 0x55, 0x1b, 0x8e, 0xb4, 0x97, + 0x9b, 0xe8, 0x53, 0xe1, 0x86, 0xb9, 0x0b, 0x04, 0x57, 0x8e, 0x28, 0x30, 0x10, 0x02, 0xed, 0xb2, 0x3d, 0xa6, 0x79, + 0x3e, 0xa4, 0xd9, 0xe7, 0x3a, 0xf6, 0x57, 0x68, 0x40, 0x36, 0xa9, 0x71, 0x90, 0x15, 0x90, 0xac, 0x70, 0xde, 0x9e, + 0x4a, 0xd7, 0x36, 0x4a, 0xbc, 0xdf, 0xaa, 0xd0, 0xbe, 0xbe, 0xd0, 0xdf, 0xc4, 0x76, 0x33, 0x22, 0xe1, 0x66, 0x16, + 0x03, 0x15, 0xf8, 0x97, 0x18, 0xe7, 0xe9, 0x81, 0xc3, 0x3b, 0x10, 0x3c, 0xd6, 0x1b, 0x03, 0xd1, 0x68, 0xb9, 0x1e, + 0x71, 0xf5, 0x6d, 0x08, 0xfc, 0x6f, 0x19, 0xe5, 0x93, 0xa0, 0x87, 0x7f, 0x77, 0xa0, 0x25, 0x8d, 0x73, 0x8c, 0x73, + 0x39, 0x32, 0xc7, 0x50, 0x78, 0x42, 0xf3, 0x0b, 0x30, 0x2f, 0x06, 0xdf, 0x5f, 0xdb, 0x2c, 0xc3, 0x97, 0xc1, 0x30, + 0x54, 0x37, 0x64, 0x28, 0x6a, 0x28, 0xe0, 0x88, 0xaa, 0x30, 0x67, 0xae, 0xac, 0x89, 0x92, 0x8e, 0x6b, 0xb7, 0xe2, + 0xb8, 0xa3, 0xb9, 0x05, 0x89, 0xe3, 0x58, 0x81, 0x34, 0xe7, 0xf9, 0xfb, 0x6a, 0x16, 0x6a, 0x6b, 0x16, 0x2a, 0x09, + 0xa4, 0x2d, 0x54, 0x21, 0x73, 0x50, 0x3d, 0xd5, 0x02, 0x85, 0xa5, 0x80, 0x65, 0x4d, 0x80, 0x42, 0xa3, 0x92, 0xe0, + 0xe6, 0x44, 0xe3, 0xc2, 0x89, 0x3a, 0x0e, 0xd7, 0x80, 0x64, 0x54, 0x55, 0x24, 0xb2, 0x9b, 0xa3, 0x26, 0xfb, 0x4a, + 0x5c, 0xa0, 0x0d, 0xfe, 0x7e, 0xbd, 0x76, 0x50, 0x62, 0xc8, 0xad, 0x4e, 0x8d, 0x31, 0x0e, 0xc0, 0x82, 0x25, 0x71, + 0xcc, 0xb0, 0x65, 0x7d, 0x36, 0x81, 0x53, 0xb6, 0xbb, 0x4f, 0x88, 0xac, 0x60, 0x53, 0x63, 0x2a, 0x3d, 0x77, 0x25, + 0x11, 0xa6, 0x9e, 0x2d, 0x2d, 0xaa, 0x89, 0x13, 0x12, 0x79, 0xed, 0x44, 0xd4, 0x5b, 0xd6, 0x84, 0xc3, 0x34, 0x28, + 0xb6, 0x4e, 0x81, 0xa8, 0x16, 0xbb, 0xe0, 0xbd, 0x0b, 0x6b, 0x6a, 0xed, 0x04, 0x10, 0x2f, 0x6a, 0x10, 0x0f, 0x40, + 0x2b, 0x2d, 0xf1, 0x92, 0x03, 0x42, 0xeb, 0x95, 0x63, 0x86, 0x0b, 0xbb, 0x10, 0x5b, 0x50, 0xdc, 0x64, 0x3f, 0x0d, + 0x16, 0x82, 0x2c, 0xab, 0x80, 0xbf, 0x0b, 0x8f, 0x88, 0x18, 0x06, 0x2f, 0x56, 0xab, 0x2d, 0xb4, 0xdb, 0xc9, 0x85, + 0xa2, 0xa4, 0x92, 0x0e, 0x57, 0xab, 0xaf, 0x12, 0xc5, 0x8e, 0xff, 0xc5, 0x0c, 0xf5, 0x3c, 0xd1, 0x7d, 0xf8, 0x12, + 0x4a, 0x19, 0x76, 0xb4, 0x4a, 0x29, 0x05, 0x87, 0x3a, 0xd6, 0xd6, 0x17, 0x4a, 0x07, 0x94, 0xfb, 0xf1, 0x16, 0x01, + 0x33, 0x89, 0xee, 0xa4, 0xae, 0xa6, 0xfc, 0xd8, 0x35, 0x2d, 0x10, 0x42, 0xa9, 0x32, 0xb2, 0xcc, 0xfe, 0x2e, 0xf9, + 0xf2, 0xe0, 0x40, 0x05, 0x0d, 0x5d, 0x97, 0x94, 0xe2, 0xef, 0x18, 0x4e, 0x65, 0x75, 0x27, 0x0c, 0xfb, 0xf2, 0xb7, + 0x3f, 0x87, 0xb6, 0xa4, 0xd3, 0x56, 0x17, 0x04, 0x73, 0x7a, 0x43, 0xb9, 0xde, 0x2b, 0x5b, 0xb1, 0x82, 0x79, 0xcc, + 0xd0, 0xd2, 0x71, 0x1b, 0x49, 0xc1, 0x80, 0x7f, 0x04, 0xb2, 0xe0, 0xb9, 0x68, 0x8b, 0xf8, 0xd9, 0x94, 0x81, 0x2a, + 0xdb, 0x33, 0x12, 0xa5, 0x78, 0xb8, 0xef, 0x0e, 0x12, 0xd7, 0xf0, 0xee, 0xb1, 0xaf, 0x37, 0xab, 0xd7, 0xa4, 0x81, + 0x39, 0x2b, 0xc6, 0xb2, 0x98, 0xf9, 0xbc, 0xf5, 0xc6, 0xb7, 0x23, 0x8e, 0x7c, 0x1c, 0xef, 0x6c, 0xdb, 0x89, 0x00, + 0xdd, 0x0d, 0xd9, 0xbb, 0x92, 0xda, 0x6b, 0xa7, 0x69, 0x79, 0x00, 0x5b, 0x05, 0xa1, 0xc7, 0x4c, 0x15, 0x4a, 0xf9, + 0x4e, 0xbd, 0xda, 0xb5, 0xba, 0x93, 0xfd, 0x76, 0xb7, 0x94, 0xfc, 0x3c, 0x36, 0x74, 0xad, 0x8e, 0xc3, 0x9d, 0xaa, + 0x72, 0x91, 0x8f, 0xdc, 0x60, 0x05, 0xc2, 0xcc, 0xe1, 0xd1, 0x0d, 0xcf, 0xf3, 0x2a, 0xf5, 0x3f, 0x21, 0xed, 0xca, + 0x91, 0x76, 0xe9, 0x49, 0x3b, 0x90, 0x0a, 0x20, 0xed, 0xb6, 0xb9, 0xaa, 0xba, 0xdc, 0xda, 0x9e, 0xd2, 0x12, 0x75, + 0x65, 0xc4, 0x69, 0xe8, 0x6f, 0xe1, 0x47, 0x80, 0x4a, 0xe6, 0xeb, 0x73, 0xec, 0xf4, 0x31, 0x20, 0x06, 0x5a, 0x9d, + 0x26, 0x0b, 0x35, 0x15, 0x9f, 0x63, 0x84, 0xd5, 0x9a, 0x95, 0x98, 0xfd, 0xf0, 0x29, 0x28, 0xed, 0x82, 0xe9, 0xc0, + 0x39, 0x66, 0x92, 0xff, 0x23, 0x3e, 0xca, 0xcf, 0x4e, 0xb8, 0xd9, 0x29, 0x3f, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0x46, + 0xdf, 0xa7, 0xf6, 0x66, 0x7a, 0xa2, 0x9c, 0x5e, 0xb5, 0xde, 0xab, 0x55, 0xbc, 0x91, 0x02, 0x1a, 0x7d, 0x27, 0xa5, + 0x14, 0x65, 0xeb, 0x40, 0x03, 0x42, 0xc8, 0x40, 0xc2, 0xda, 0x4e, 0xba, 0x3c, 0xe5, 0x5e, 0xfe, 0x2b, 0x3d, 0x8f, + 0x51, 0xdc, 0xdb, 0xfa, 0x8f, 0xe5, 0x6c, 0x0e, 0x0c, 0xd9, 0x06, 0x4a, 0x4f, 0x98, 0xeb, 0xb0, 0xca, 0x5f, 0xef, + 0x48, 0xab, 0xd5, 0x31, 0xfb, 0xb1, 0x86, 0x4d, 0xa5, 0xd4, 0xbc, 0xdf, 0x5a, 0x2f, 0xca, 0xa4, 0x92, 0x70, 0xec, + 0xd2, 0xad, 0x3c, 0xde, 0xd4, 0xcc, 0xf8, 0x8c, 0xd7, 0xb1, 0xb0, 0x74, 0x58, 0x00, 0xad, 0x0b, 0xc8, 0x8f, 0x47, + 0xf7, 0x70, 0xfd, 0xd7, 0x15, 0x70, 0x96, 0xeb, 0x0d, 0xf0, 0x2d, 0xd7, 0xeb, 0x47, 0xda, 0x49, 0xda, 0xf8, 0xd1, + 0x0e, 0xb9, 0xb7, 0x84, 0x5e, 0x95, 0xe9, 0x64, 0xc6, 0xfe, 0x00, 0xd2, 0xb6, 0x58, 0x48, 0xb2, 0x9c, 0xc9, 0x11, + 0x4b, 0x23, 0x39, 0x67, 0x22, 0x5a, 0x83, 0x9e, 0xd5, 0x21, 0xc0, 0x3f, 0x22, 0x5e, 0xbe, 0xad, 0xeb, 0x5b, 0xd3, + 0x47, 0x7a, 0x0d, 0xaa, 0xb0, 0x97, 0x7c, 0x87, 0x32, 0xf6, 0x3d, 0x2b, 0x94, 0xe1, 0x49, 0x4b, 0xf6, 0xf6, 0x25, + 0xaf, 0x0e, 0xa8, 0x97, 0x3c, 0xfd, 0x76, 0x95, 0x4a, 0x20, 0x89, 0xda, 0xc9, 0x59, 0x72, 0x1c, 0x21, 0xa3, 0x31, + 0x7e, 0xe6, 0x35, 0xc6, 0x8b, 0x52, 0x63, 0xfc, 0x5c, 0x93, 0xc5, 0x86, 0xc6, 0xf8, 0x0f, 0x41, 0x9e, 0xeb, 0xde, + 0x73, 0xaf, 0x4d, 0x7f, 0x23, 0x73, 0x9e, 0xdd, 0xc5, 0x51, 0xce, 0x75, 0x13, 0x6e, 0x13, 0x23, 0xbc, 0xb4, 0x19, + 0xa0, 0x6a, 0x34, 0xfa, 0xee, 0xb5, 0x97, 0xff, 0xb0, 0x10, 0x24, 0xba, 0x97, 0x73, 0x7d, 0x2f, 0xc2, 0x53, 0x4d, + 0xfe, 0x82, 0x5f, 0xf7, 0x96, 0xf1, 0xaf, 0x54, 0x4f, 0x93, 0x82, 0x8a, 0x91, 0x9c, 0xc5, 0xa8, 0x11, 0x45, 0x28, + 0x51, 0x46, 0x08, 0x79, 0x80, 0xd6, 0xf7, 0xfe, 0xc2, 0xaf, 0x24, 0x89, 0x7a, 0x51, 0x63, 0xaa, 0xb1, 0xa6, 0xe4, + 0xaf, 0x8b, 0x7b, 0xcb, 0x57, 0x72, 0x7d, 0xf9, 0x17, 0x7e, 0xaa, 0x4b, 0xb5, 0x3e, 0xbe, 0x65, 0x24, 0x46, 0xe4, + 0xf2, 0xa9, 0x1f, 0xd2, 0x63, 0x39, 0xb3, 0x0a, 0xfe, 0x08, 0xe1, 0x2f, 0xa0, 0xd7, 0xbd, 0xe4, 0x15, 0x11, 0x72, + 0x77, 0x30, 0xfb, 0x24, 0x92, 0x46, 0x79, 0x10, 0x1d, 0x1c, 0x04, 0x69, 0x25, 0x0b, 0x81, 0xff, 0x96, 0xa4, 0x26, + 0xaa, 0x63, 0x46, 0xa1, 0xa5, 0xbf, 0x65, 0xcc, 0x91, 0x6f, 0x26, 0xf6, 0x9a, 0x6a, 0xb7, 0x63, 0x79, 0xdf, 0xea, + 0x1e, 0x12, 0xae, 0x59, 0x41, 0xb5, 0x2c, 0x06, 0x28, 0x64, 0x4b, 0xf0, 0x57, 0x4e, 0xfe, 0xea, 0xef, 0xfd, 0x3f, + 0xff, 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xe0, 0x2f, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, + 0xfe, 0x3c, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x34, 0x40, 0xab, 0xf8, 0xcf, 0xa3, 0x5e, 0xdf, 0x7d, + 0xf5, 0xff, 0xfb, 0xf2, 0x4f, 0x35, 0x38, 0xb4, 0x89, 0xf7, 0x10, 0x3a, 0x9a, 0xe0, 0x5f, 0x04, 0x39, 0x6a, 0x36, + 0x2f, 0x8f, 0x26, 0xf8, 0x27, 0x41, 0x8e, 0xe0, 0xef, 0x9d, 0x26, 0x6f, 0xd9, 0xe4, 0xe9, 0xed, 0x3c, 0xfe, 0xeb, + 0x72, 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf9, 0xa7, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, + 0x06, 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0x3f, 0xff, 0xba, + 0xb8, 0x24, 0x83, 0x55, 0x1c, 0xad, 0x7e, 0x44, 0x2b, 0x84, 0x56, 0xf7, 0xd0, 0x5f, 0x38, 0x9a, 0x44, 0x08, 0xff, + 0x26, 0xc8, 0xd1, 0x8f, 0x47, 0x13, 0xfc, 0x49, 0x90, 0xa3, 0xe8, 0x68, 0x82, 0xdf, 0x4b, 0x72, 0xf4, 0xdf, 0x71, + 0x2f, 0xb5, 0x4a, 0xb8, 0x95, 0x51, 0x7f, 0xac, 0xe0, 0x26, 0x84, 0x16, 0x8c, 0xae, 0x34, 0xd7, 0x39, 0x43, 0xf7, + 0x8e, 0x38, 0x7e, 0x24, 0x01, 0x58, 0xb1, 0x06, 0x25, 0x8d, 0xb9, 0x84, 0x5d, 0x5e, 0xc3, 0xc2, 0x03, 0x06, 0xdd, + 0x4b, 0x39, 0xb6, 0x7a, 0x02, 0x95, 0x6a, 0x7b, 0x7b, 0xab, 0xe0, 0xfa, 0x16, 0x3f, 0x26, 0x8f, 0x64, 0xdc, 0x46, + 0x98, 0x53, 0xf8, 0xd1, 0x41, 0xf8, 0x83, 0x76, 0x17, 0x9e, 0xb0, 0xcd, 0x2d, 0x86, 0x09, 0x69, 0xf9, 0x99, 0x08, + 0xe1, 0x97, 0x3b, 0x32, 0xf5, 0x14, 0xd4, 0x0f, 0x08, 0xff, 0x5c, 0xbb, 0x1e, 0xc5, 0x8f, 0x35, 0x29, 0x91, 0xe3, + 0x5d, 0xc1, 0xd8, 0x07, 0x9a, 0x7f, 0x66, 0x45, 0xfc, 0x54, 0xe3, 0x76, 0xe7, 0x01, 0x36, 0xaa, 0xea, 0xfd, 0x36, + 0xea, 0x96, 0xb7, 0x5b, 0xcf, 0xa5, 0xbd, 0x4f, 0x80, 0x53, 0xb8, 0xae, 0xaf, 0x81, 0xb5, 0xdf, 0xe7, 0x5b, 0x4a, + 0xad, 0x82, 0xde, 0x44, 0xa8, 0x7e, 0x95, 0xca, 0xc5, 0x17, 0x9a, 0xf3, 0xd1, 0x9e, 0x66, 0xb3, 0x79, 0x4e, 0x35, + 0xdb, 0x73, 0x73, 0xde, 0xa3, 0xd0, 0x50, 0x54, 0xf2, 0x14, 0x7f, 0x88, 0x6a, 0xd3, 0xfe, 0x21, 0x92, 0x6a, 0xef, + 0xc4, 0x70, 0x9f, 0xe5, 0xf8, 0x12, 0x41, 0xcb, 0xeb, 0xb2, 0xcd, 0x1b, 0xc1, 0x66, 0x1b, 0x94, 0x65, 0x03, 0x73, + 0x7e, 0x2b, 0x0c, 0xf7, 0x9b, 0x84, 0x74, 0x7a, 0xd1, 0x85, 0xfa, 0x32, 0xb9, 0x8c, 0xe0, 0x26, 0xa7, 0x20, 0x82, + 0x19, 0xe5, 0x11, 0x94, 0xa0, 0xa4, 0xd5, 0xa5, 0x17, 0xac, 0x4b, 0x1b, 0x0d, 0xcf, 0x66, 0x67, 0x84, 0xf7, 0xa9, + 0xad, 0x9f, 0xe3, 0x29, 0x1e, 0x91, 0x66, 0x1b, 0x2f, 0x48, 0xcb, 0x54, 0xe9, 0x2e, 0x2e, 0x32, 0xd7, 0xcf, 0xc1, + 0x41, 0x5c, 0x24, 0x39, 0x55, 0xfa, 0x05, 0x68, 0x04, 0xc8, 0x02, 0x4f, 0x49, 0x91, 0xb0, 0x5b, 0x96, 0xc5, 0x19, + 0xc2, 0x53, 0x47, 0x83, 0x50, 0x17, 0x2d, 0x48, 0x50, 0x0c, 0xe4, 0x0c, 0x22, 0x58, 0x6f, 0xda, 0x6f, 0x0f, 0x08, + 0x21, 0xd1, 0x7e, 0xb3, 0x19, 0xf5, 0x0a, 0xf2, 0x8b, 0x48, 0x21, 0x25, 0x60, 0xa7, 0xc9, 0x4f, 0x90, 0xd4, 0x09, + 0x92, 0xe2, 0xf7, 0x32, 0xd1, 0x4c, 0xe9, 0x18, 0x92, 0x41, 0x49, 0xa0, 0x3c, 0x86, 0x47, 0x17, 0x47, 0x51, 0x03, + 0x52, 0x0d, 0x8a, 0x22, 0x5c, 0x90, 0x3b, 0x8d, 0xd2, 0x69, 0xff, 0x78, 0x10, 0x9e, 0x11, 0x36, 0x15, 0xfa, 0xbf, + 0xd3, 0xbd, 0x69, 0xbf, 0x65, 0xfa, 0xbf, 0x8c, 0x7a, 0x71, 0x41, 0x94, 0x65, 0xe3, 0x7a, 0x2a, 0x15, 0xcc, 0xcc, + 0x17, 0xa5, 0x6e, 0x80, 0xae, 0xef, 0x11, 0x69, 0x76, 0xd2, 0x78, 0x14, 0xce, 0xa4, 0x09, 0x1d, 0x3a, 0x50, 0xe0, + 0x9c, 0x40, 0x79, 0x5c, 0x10, 0xe8, 0xb4, 0xaa, 0x76, 0xa7, 0x53, 0x97, 0xf0, 0x63, 0xf4, 0x63, 0xef, 0x93, 0x48, + 0x7f, 0x13, 0x76, 0x04, 0x9f, 0xc4, 0x6a, 0x05, 0x7f, 0x7f, 0x13, 0x3d, 0x18, 0x96, 0x49, 0xfb, 0xc5, 0xa5, 0xfd, + 0x04, 0x69, 0x82, 0xa5, 0x66, 0xc0, 0x58, 0x95, 0xfc, 0x98, 0x5d, 0x9c, 0x31, 0xb1, 0x33, 0x38, 0x38, 0xe0, 0x7d, + 0xda, 0x68, 0x0f, 0xe0, 0x46, 0xa0, 0xd0, 0xea, 0x03, 0xd7, 0xd3, 0x38, 0x3a, 0xba, 0x8c, 0x50, 0x2f, 0xda, 0x83, + 0x55, 0xee, 0xca, 0x06, 0x71, 0xb0, 0xce, 0x1a, 0x9a, 0xa6, 0xa3, 0x4b, 0xd2, 0xea, 0xc5, 0xc2, 0x12, 0xf9, 0x1c, + 0xe1, 0xcc, 0xd1, 0xd4, 0x16, 0x1e, 0xa1, 0x86, 0x10, 0x0d, 0xff, 0x3d, 0x42, 0x8d, 0xa9, 0x6e, 0x8c, 0x51, 0x9a, + 0xc1, 0xdf, 0x78, 0x44, 0x08, 0x69, 0x76, 0xca, 0x8a, 0xfe, 0xb0, 0xa4, 0x28, 0x1d, 0x7b, 0xf5, 0x68, 0xdf, 0x6c, + 0x0e, 0xd9, 0x88, 0x79, 0x9f, 0x0d, 0x56, 0xab, 0xe8, 0xa2, 0x77, 0x19, 0xa1, 0x46, 0xec, 0xd1, 0xee, 0xc8, 0xe3, + 0x1d, 0x42, 0x58, 0x0c, 0xd6, 0xee, 0x06, 0xea, 0x86, 0xd5, 0x6e, 0x9b, 0x96, 0xd5, 0xfe, 0x0f, 0xc8, 0x02, 0x5b, + 0x97, 0x72, 0x8f, 0xe5, 0x6f, 0xe7, 0x30, 0x55, 0x8f, 0xdb, 0x92, 0xb4, 0x70, 0x41, 0xbc, 0xba, 0x9b, 0x12, 0x5d, + 0xe1, 0x7f, 0x46, 0xaa, 0xe2, 0xb8, 0x9f, 0xe3, 0xe9, 0x80, 0x08, 0x6a, 0xe4, 0x97, 0xae, 0x57, 0xa6, 0xb3, 0x9c, + 0xdc, 0xb0, 0x8d, 0xfb, 0xdf, 0x1c, 0xee, 0x64, 0x1e, 0xeb, 0x24, 0x5b, 0x14, 0x05, 0x13, 0xfa, 0x95, 0x1c, 0x39, + 0xc6, 0x8e, 0xe5, 0x20, 0x5b, 0xc1, 0xc5, 0x2e, 0x06, 0xae, 0xae, 0xe3, 0x77, 0xca, 0x68, 0x2b, 0x7b, 0x41, 0x46, + 0x96, 0xe1, 0x32, 0xd7, 0xbd, 0xdd, 0x85, 0x13, 0xa5, 0x63, 0x84, 0x47, 0xee, 0x1e, 0x38, 0x4e, 0x92, 0x64, 0x91, + 0x64, 0x90, 0x0d, 0x1d, 0x28, 0xb4, 0x36, 0xfb, 0x2a, 0x56, 0xe4, 0xb1, 0x4e, 0x04, 0xbb, 0x35, 0xdd, 0xc6, 0xa8, + 0x3a, 0xc4, 0xfd, 0x7e, 0xbb, 0xa0, 0x5d, 0x43, 0x80, 0x54, 0x22, 0xe4, 0x88, 0x01, 0x84, 0xe0, 0xee, 0xdf, 0x25, + 0x4d, 0xa9, 0x0a, 0x6f, 0xb6, 0xaa, 0x01, 0xf6, 0x43, 0x95, 0xf7, 0x02, 0xf4, 0xc4, 0x86, 0x3d, 0x2b, 0x0b, 0x5b, + 0xe5, 0x39, 0x42, 0x7c, 0x1c, 0x2f, 0x12, 0xb8, 0x11, 0x34, 0x98, 0x24, 0x04, 0x5a, 0xad, 0x16, 0x21, 0x6e, 0x4d, + 0x2b, 0xc5, 0xf4, 0x98, 0x4c, 0xfb, 0x45, 0xa3, 0x61, 0x94, 0xd7, 0x23, 0x8b, 0x17, 0x0b, 0x84, 0xc7, 0xe5, 0x5e, + 0xf3, 0xe5, 0xe6, 0xa4, 0xde, 0x55, 0x3c, 0xae, 0x2b, 0x81, 0x1b, 0x42, 0x20, 0xa3, 0x5f, 0xd4, 0xd0, 0x3a, 0x9e, + 0x90, 0xa3, 0xb8, 0x9f, 0xf4, 0xfe, 0xe7, 0x00, 0xf5, 0xe2, 0xe4, 0x10, 0x1d, 0x59, 0x5a, 0x32, 0x46, 0xdd, 0xcc, + 0xf6, 0xb1, 0x34, 0xb7, 0x9f, 0x6d, 0x6c, 0x14, 0x90, 0xa9, 0xc4, 0x82, 0xce, 0x58, 0x3a, 0x81, 0x5d, 0xef, 0x91, + 0x67, 0x8e, 0x01, 0x99, 0xd2, 0x89, 0xa3, 0x2d, 0x49, 0xd4, 0x93, 0xb4, 0xfc, 0xea, 0x45, 0x3d, 0x5a, 0x7d, 0xfd, + 0xcf, 0xa8, 0x97, 0xd1, 0xf4, 0x31, 0x5f, 0x3b, 0x25, 0x79, 0xad, 0x8f, 0x33, 0xdf, 0xc7, 0xda, 0x2e, 0x4e, 0x00, + 0xbc, 0x11, 0xda, 0xd6, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0xa4, 0x12, 0x4d, 0x27, 0x00, 0xd5, 0x60, 0x11, + 0x54, 0x68, 0x1b, 0x10, 0x4c, 0x19, 0xb0, 0xc5, 0x23, 0x2d, 0x40, 0x73, 0x71, 0xd9, 0x42, 0xcb, 0x5a, 0x61, 0xc7, + 0x59, 0xd5, 0xef, 0xe2, 0x4b, 0xe2, 0x3d, 0x06, 0xaa, 0x7c, 0xb1, 0xe8, 0x8e, 0x1b, 0x0d, 0xa4, 0x3c, 0x7e, 0x8d, + 0xfa, 0xe3, 0x01, 0xbe, 0x05, 0x14, 0xc2, 0x35, 0x8c, 0xc2, 0xb5, 0x39, 0x76, 0xdc, 0x1c, 0x1b, 0x0d, 0xb9, 0x46, + 0xdd, 0xa0, 0xf2, 0xc2, 0x55, 0x5e, 0xaf, 0x2d, 0x64, 0x36, 0x31, 0xee, 0x1c, 0x99, 0x14, 0x30, 0x04, 0x23, 0x84, + 0xbc, 0x92, 0x68, 0x67, 0xb3, 0xd0, 0x28, 0x54, 0x37, 0xbb, 0x17, 0x28, 0xaa, 0x3d, 0x3d, 0x62, 0x80, 0x05, 0x54, + 0x2d, 0xd5, 0xc8, 0x53, 0x8d, 0x47, 0x8d, 0xb6, 0x41, 0xf7, 0x66, 0xbb, 0x5b, 0x6f, 0xec, 0x7e, 0xd5, 0x18, 0x1e, + 0x35, 0xc8, 0xb4, 0xda, 0xe1, 0x6b, 0xd9, 0x68, 0xac, 0xeb, 0xf7, 0xa5, 0x7e, 0x13, 0xd7, 0xee, 0x2f, 0x9e, 0x6e, + 0x99, 0x78, 0xf8, 0xd3, 0xb7, 0x3a, 0x6f, 0x45, 0xc2, 0x85, 0x60, 0x05, 0x9c, 0xb0, 0x44, 0x63, 0xb1, 0x5e, 0x97, + 0xa7, 0xfe, 0xef, 0xda, 0xda, 0x8c, 0x11, 0x0e, 0x74, 0xc8, 0x48, 0x6d, 0x58, 0xe2, 0x02, 0x53, 0x43, 0x45, 0x08, + 0x21, 0x1f, 0xb4, 0x37, 0x8f, 0xd1, 0x86, 0x24, 0x65, 0x24, 0x38, 0xbb, 0x63, 0x45, 0x58, 0x72, 0x7d, 0xef, 0xb1, + 0xfc, 0xae, 0x48, 0xd7, 0x17, 0x83, 0xd4, 0x14, 0xcb, 0x1d, 0x21, 0xcb, 0xc9, 0x17, 0x90, 0x73, 0xca, 0x0b, 0x96, + 0xc4, 0x10, 0xc4, 0x27, 0xbc, 0x60, 0x86, 0x71, 0xbf, 0xe7, 0xe5, 0xc6, 0xac, 0xce, 0x69, 0x66, 0xa1, 0xf6, 0x07, + 0xa0, 0x99, 0x83, 0x72, 0x48, 0x92, 0xad, 0x62, 0xd7, 0xf7, 0x1e, 0xbe, 0xde, 0x25, 0x43, 0xaf, 0x56, 0x4e, 0x7a, + 0xce, 0x80, 0xf5, 0xc1, 0x79, 0x35, 0xd4, 0xcc, 0xfd, 0x48, 0xe3, 0xcc, 0x30, 0x51, 0x79, 0xcc, 0x01, 0x99, 0xae, + 0xef, 0x3d, 0x7c, 0x17, 0x73, 0xa3, 0x9b, 0x42, 0x38, 0x9c, 0x77, 0x5c, 0x90, 0x98, 0x12, 0x86, 0xec, 0xe4, 0x4b, + 0x3a, 0x56, 0x04, 0xa7, 0x7b, 0x4a, 0x4d, 0x26, 0x88, 0x1d, 0x7d, 0x31, 0x20, 0x99, 0x03, 0x01, 0xc9, 0x10, 0xce, + 0x6a, 0x72, 0x1d, 0x31, 0x6b, 0x60, 0x3a, 0xbb, 0x82, 0xc5, 0x48, 0x2c, 0x7b, 0x88, 0x70, 0x66, 0xba, 0xd5, 0x6b, + 0x7b, 0x9c, 0x28, 0xba, 0x69, 0xe8, 0x56, 0xc9, 0xb3, 0xef, 0x41, 0xf0, 0xf2, 0x1f, 0xaf, 0x5c, 0xdb, 0x65, 0xc2, + 0x13, 0x6f, 0x91, 0x76, 0x7d, 0xef, 0xe1, 0xaf, 0xce, 0x28, 0x6d, 0x4e, 0x3d, 0xf9, 0xdf, 0x92, 0x51, 0x1f, 0xfe, + 0x9a, 0x54, 0xb9, 0xa6, 0xf0, 0xf5, 0xbd, 0x87, 0xbf, 0xef, 0x2a, 0x06, 0xe9, 0xeb, 0x45, 0xa5, 0x24, 0x30, 0xe3, + 0x5b, 0xb2, 0x3c, 0x5d, 0xba, 0xb3, 0x22, 0x15, 0x6b, 0x6c, 0x4e, 0xa8, 0x54, 0xad, 0x4b, 0xdd, 0xca, 0x13, 0x2c, + 0x89, 0xb9, 0x4a, 0xaa, 0x2f, 0x9b, 0x43, 0x63, 0x2e, 0xc5, 0x55, 0x26, 0xe7, 0xec, 0x1b, 0xf7, 0x4b, 0x4f, 0x35, + 0x4a, 0xf8, 0x0c, 0x0c, 0x71, 0xcc, 0xd8, 0x05, 0xde, 0x6f, 0xa1, 0xee, 0xc6, 0x79, 0x26, 0x0d, 0xa2, 0x16, 0xf5, + 0xc3, 0x06, 0x53, 0xd2, 0xc2, 0x19, 0x69, 0xe1, 0x9c, 0xa8, 0x7e, 0xcb, 0x9e, 0x18, 0xdd, 0xbc, 0x6c, 0xda, 0x9e, + 0x3b, 0xb0, 0xdd, 0x73, 0xbb, 0x6f, 0xed, 0xa1, 0x3c, 0xed, 0xe6, 0x46, 0x7f, 0x69, 0x0e, 0xfa, 0xa9, 0x41, 0x8d, + 0x27, 0x2c, 0x2e, 0x70, 0x61, 0x5a, 0xbe, 0xe2, 0xc3, 0x1c, 0xec, 0x54, 0x60, 0x66, 0x58, 0xa3, 0xb4, 0x2c, 0xdb, + 0x76, 0x65, 0xf3, 0xc4, 0xac, 0x55, 0x81, 0xf3, 0x04, 0x48, 0x39, 0xce, 0x9d, 0x5d, 0x8f, 0xda, 0xae, 0x72, 0x76, + 0x70, 0x10, 0xbb, 0x4a, 0x34, 0x2e, 0x7c, 0x7e, 0x75, 0x03, 0xf8, 0xde, 0x52, 0x8d, 0x29, 0x32, 0x13, 0x68, 0x34, + 0xb2, 0xc1, 0x9a, 0xee, 0x13, 0x12, 0xe7, 0x75, 0x28, 0xfa, 0xd1, 0x1b, 0x66, 0x70, 0x03, 0x00, 0x8d, 0x46, 0x79, + 0xdd, 0xbb, 0x01, 0xb1, 0xa7, 0x1a, 0xcb, 0xf5, 0x97, 0xb8, 0xb4, 0x26, 0x6a, 0x6d, 0xd9, 0x61, 0xf9, 0x51, 0x20, + 0x11, 0xe2, 0xae, 0xf0, 0xf3, 0x09, 0xb6, 0x86, 0x80, 0x72, 0x2f, 0x9c, 0x0d, 0x04, 0x36, 0x56, 0x5b, 0xae, 0x90, + 0x27, 0x6d, 0x1d, 0x94, 0xfa, 0x42, 0x70, 0xc1, 0x05, 0x85, 0x1a, 0x6b, 0x87, 0xe5, 0x4f, 0xd8, 0xb6, 0x39, 0x27, + 0x56, 0xc8, 0x69, 0xcb, 0xcc, 0x30, 0x0c, 0xc0, 0x3a, 0x25, 0x60, 0x9e, 0x93, 0x97, 0xdf, 0x46, 0xfd, 0x87, 0x01, + 0xea, 0x3f, 0x22, 0x2c, 0xd8, 0x06, 0x56, 0x57, 0x92, 0x48, 0xa7, 0xa0, 0x50, 0x3e, 0xeb, 0xf1, 0x9c, 0x80, 0x36, + 0xae, 0x0e, 0xd5, 0xda, 0x15, 0xe5, 0x37, 0x28, 0x4b, 0xb8, 0x53, 0x8c, 0x3e, 0x13, 0xfb, 0xfb, 0xe4, 0xb8, 0xba, + 0xa0, 0x83, 0xae, 0x77, 0x29, 0x07, 0x43, 0x52, 0xf8, 0xf0, 0xf7, 0xef, 0xdf, 0xad, 0x3e, 0x9e, 0x6f, 0xef, 0xe0, + 0xc0, 0xac, 0x14, 0x66, 0x1d, 0x6c, 0xe0, 0xba, 0x91, 0x29, 0xf4, 0x5f, 0xde, 0x89, 0xd7, 0xa9, 0xd0, 0xc6, 0x66, + 0xf4, 0xc7, 0x21, 0x8c, 0xb6, 0xdd, 0x36, 0x25, 0x58, 0xd0, 0x2c, 0xd0, 0x25, 0x6b, 0xdc, 0x4a, 0x8b, 0x6f, 0x90, + 0x91, 0x87, 0xa6, 0x00, 0x13, 0xa3, 0xdd, 0xd9, 0x8f, 0xd6, 0x0e, 0x4f, 0xec, 0xd0, 0xd0, 0xd2, 0x10, 0x42, 0x8b, + 0xf7, 0x80, 0x39, 0xf6, 0x88, 0x00, 0x10, 0xbd, 0x34, 0x90, 0xaa, 0x40, 0x16, 0x45, 0x95, 0x22, 0xff, 0xf9, 0x3e, + 0x21, 0x2f, 0x2b, 0x45, 0xe6, 0xdb, 0xca, 0x98, 0x0b, 0x10, 0x03, 0xa5, 0x70, 0x91, 0x50, 0x26, 0xd8, 0xcb, 0xd0, + 0x0f, 0xda, 0x97, 0x37, 0xd2, 0x66, 0x52, 0x71, 0xe3, 0xc1, 0x4d, 0xa9, 0x51, 0xf1, 0xd9, 0x7c, 0x0f, 0x89, 0x8d, + 0xdc, 0x7b, 0x90, 0xcb, 0xa8, 0x19, 0x24, 0x7c, 0xbf, 0x33, 0xa5, 0x7d, 0xbb, 0xeb, 0xcf, 0x9b, 0x16, 0x31, 0x1b, + 0xeb, 0x92, 0x70, 0xa1, 0x58, 0xa1, 0x1f, 0xb1, 0xb1, 0x2c, 0xe0, 0xfe, 0xa3, 0x04, 0x0b, 0x5a, 0xdf, 0x0b, 0x74, + 0x80, 0x66, 0x82, 0xc1, 0xa5, 0xc3, 0xc6, 0x0c, 0xcd, 0xaf, 0xcf, 0xe6, 0x0e, 0xfc, 0x7a, 0xb3, 0xd6, 0xcb, 0x83, + 0x83, 0x2f, 0xac, 0x02, 0x94, 0x1b, 0xa6, 0x19, 0x46, 0x40, 0xbc, 0x2c, 0x97, 0xe3, 0x6e, 0x86, 0xef, 0xc5, 0x95, + 0xca, 0xc0, 0x13, 0x8e, 0x90, 0x08, 0x3d, 0x27, 0x7a, 0x3d, 0xd9, 0xa4, 0xf7, 0x4e, 0x9b, 0x21, 0x42, 0xb1, 0x06, + 0xc8, 0x3d, 0xc8, 0xe5, 0x56, 0xc9, 0xa4, 0x2a, 0x5b, 0xdb, 0x72, 0x10, 0x8f, 0x01, 0x5c, 0xb1, 0x11, 0x52, 0x02, + 0x34, 0xdc, 0x2d, 0xb4, 0x3c, 0x97, 0xc0, 0xfe, 0x63, 0x95, 0x80, 0x48, 0x8b, 0x6a, 0x1b, 0x17, 0x21, 0x6c, 0x4d, + 0x7d, 0x02, 0xe3, 0x84, 0x87, 0xcf, 0x77, 0x69, 0xa8, 0x3d, 0x6a, 0x33, 0x73, 0x06, 0x41, 0x09, 0x89, 0xca, 0x0a, + 0xc9, 0x97, 0x58, 0x38, 0x6e, 0xce, 0xdf, 0xc3, 0x01, 0x29, 0x56, 0x34, 0xb6, 0x77, 0x5b, 0x70, 0x7c, 0x14, 0xc9, + 0x22, 0xae, 0x75, 0xdd, 0x2d, 0x4c, 0x35, 0xec, 0x40, 0x47, 0x43, 0x38, 0x15, 0xe6, 0x9e, 0xf0, 0x71, 0x45, 0x52, + 0x7f, 0xb6, 0x26, 0xda, 0xda, 0x13, 0xc3, 0xca, 0x34, 0x25, 0x98, 0xff, 0xcf, 0xd6, 0xea, 0xba, 0x2c, 0x84, 0x99, + 0x19, 0xc6, 0x8d, 0x5d, 0x05, 0xb6, 0x06, 0x1c, 0x5b, 0xfe, 0x2d, 0x83, 0x45, 0xf5, 0x4a, 0x71, 0xd3, 0x69, 0xc0, + 0x04, 0xbc, 0x05, 0xeb, 0x99, 0xcd, 0xad, 0xff, 0xdc, 0x1c, 0x8c, 0x02, 0xab, 0x1a, 0x81, 0x97, 0x86, 0xc0, 0x23, + 0x60, 0xdc, 0xbc, 0x69, 0x79, 0xcf, 0x19, 0xd1, 0x08, 0x7f, 0xe2, 0x39, 0x3c, 0xb3, 0x2c, 0xf7, 0xd6, 0xc7, 0xc6, + 0x8a, 0xa4, 0x82, 0x80, 0x6d, 0x11, 0x76, 0x44, 0x5e, 0x22, 0xac, 0x1a, 0x8d, 0xae, 0xba, 0x60, 0x95, 0x56, 0xa5, + 0x1a, 0xa6, 0x80, 0x5b, 0x62, 0xc0, 0xfb, 0xda, 0x89, 0x0a, 0x86, 0x04, 0xde, 0xfa, 0x5b, 0x81, 0xfa, 0xfe, 0xe1, + 0xdb, 0x38, 0xa4, 0x6f, 0x61, 0xd9, 0xf2, 0x22, 0x16, 0xa6, 0x14, 0x57, 0x77, 0x38, 0x6f, 0xbe, 0x6f, 0x36, 0x02, + 0xe3, 0xde, 0x6f, 0x63, 0xb0, 0x71, 0x43, 0x5d, 0x6d, 0x49, 0x43, 0xb9, 0x09, 0xbb, 0xa8, 0xb2, 0x77, 0x0c, 0x3b, + 0xeb, 0xea, 0x4a, 0xda, 0xd5, 0x44, 0xad, 0xd7, 0x8a, 0x55, 0x46, 0x03, 0x1b, 0x86, 0x9d, 0xe6, 0x98, 0xd9, 0x56, + 0xe0, 0x3f, 0x9e, 0x13, 0x8d, 0x03, 0x64, 0x7d, 0xf3, 0xad, 0xeb, 0x94, 0x6a, 0x98, 0xb0, 0xbd, 0xdd, 0xf9, 0xf8, + 0x98, 0xef, 0x3a, 0x1f, 0xb1, 0x74, 0x5b, 0xdf, 0x9c, 0x8d, 0xed, 0x7f, 0xe3, 0x6c, 0x74, 0x6a, 0x7b, 0x7f, 0x3c, + 0x02, 0x77, 0x52, 0x3b, 0x1e, 0xeb, 0x6b, 0x4a, 0x24, 0x16, 0x6e, 0x39, 0x2e, 0x3b, 0xab, 0x95, 0xe8, 0xb7, 0x40, + 0xed, 0x14, 0x45, 0xf0, 0xb3, 0x6d, 0x7f, 0x06, 0x24, 0xd9, 0xea, 0x90, 0x63, 0x51, 0x8a, 0x32, 0x28, 0x01, 0x03, + 0xea, 0xd8, 0xd8, 0x7a, 0x19, 0xc4, 0x76, 0x38, 0xe4, 0xb0, 0x9c, 0x88, 0xf2, 0xea, 0x0a, 0x46, 0x6c, 0x8e, 0x0d, + 0x27, 0x60, 0xc6, 0x3b, 0xad, 0x0a, 0xbd, 0xf8, 0xf9, 0xaf, 0x99, 0xd3, 0xda, 0x11, 0x63, 0x39, 0x89, 0x9a, 0x15, + 0x83, 0x1b, 0x81, 0x63, 0x18, 0xf7, 0x8d, 0x84, 0x5a, 0x9d, 0xea, 0xa8, 0x76, 0x24, 0xe1, 0x16, 0xa8, 0xdd, 0xf6, + 0xcd, 0xb9, 0xb4, 0x5a, 0xed, 0x3c, 0x58, 0x70, 0x11, 0xe0, 0xf6, 0x73, 0xa2, 0x6b, 0x24, 0x85, 0x12, 0x27, 0x41, + 0xe1, 0xdc, 0xa0, 0xaa, 0x26, 0xb2, 0xdf, 0x1a, 0x00, 0x4f, 0xda, 0xcd, 0x2e, 0x64, 0x25, 0x24, 0x67, 0x8d, 0x06, + 0xca, 0xcb, 0x8e, 0x69, 0x5f, 0x34, 0xb2, 0x01, 0x66, 0x38, 0xb3, 0x02, 0x0b, 0x9c, 0x5e, 0x71, 0x5e, 0x75, 0xdd, + 0xcf, 0x06, 0x08, 0x17, 0xab, 0x55, 0x6c, 0x87, 0x96, 0xa3, 0xd5, 0x2a, 0x0f, 0x87, 0x66, 0xf2, 0xa1, 0xe2, 0xcb, + 0x9e, 0x26, 0x2f, 0xcd, 0x79, 0xf8, 0x12, 0x06, 0xd9, 0x20, 0x71, 0xee, 0x54, 0x82, 0x39, 0x68, 0xae, 0x1a, 0xb2, + 0x9f, 0x35, 0xda, 0x83, 0x80, 0x86, 0xf5, 0xb3, 0x01, 0xc9, 0xd7, 0x60, 0x39, 0xab, 0xdc, 0x81, 0xf9, 0x37, 0x1c, + 0x6c, 0x7f, 0x9b, 0x73, 0xc6, 0x36, 0x18, 0xae, 0xc9, 0xa6, 0xca, 0xa0, 0xc4, 0x2b, 0xb7, 0xb8, 0xbe, 0x5c, 0xcd, + 0xc0, 0xa2, 0x2c, 0x84, 0xdd, 0x35, 0x73, 0x0f, 0x84, 0xff, 0x12, 0xdb, 0x25, 0x2d, 0x8d, 0xb8, 0x37, 0x10, 0xdf, + 0xdb, 0x6e, 0x27, 0x49, 0x42, 0x8b, 0x89, 0xb9, 0x12, 0xf1, 0x37, 0xbc, 0x66, 0x0f, 0x1c, 0xbb, 0x71, 0x06, 0x3d, + 0xf7, 0xcb, 0xce, 0x06, 0xc4, 0x8e, 0xdf, 0x33, 0x3b, 0xde, 0x71, 0xa5, 0xa0, 0xbb, 0x75, 0x11, 0x76, 0x30, 0xf4, + 0x7f, 0x79, 0x30, 0x27, 0x6e, 0x30, 0x16, 0x4d, 0x36, 0xe0, 0xf6, 0x0d, 0x78, 0x14, 0x74, 0x03, 0x6e, 0xdf, 0x86, + 0xaf, 0x87, 0x56, 0xf6, 0xcd, 0x01, 0x06, 0x64, 0xc2, 0x8e, 0xb4, 0x4a, 0x08, 0x86, 0x79, 0xba, 0xc9, 0x91, 0x59, + 0xb2, 0x0a, 0x87, 0xab, 0x26, 0xb1, 0xd8, 0xd8, 0x0b, 0x15, 0x93, 0x1a, 0x08, 0xc6, 0x22, 0x7d, 0x89, 0x42, 0xa5, + 0x41, 0xdd, 0x38, 0x06, 0xb0, 0xca, 0x69, 0xeb, 0x5f, 0x1e, 0x1c, 0x80, 0xd0, 0x00, 0xac, 0x5d, 0x92, 0xd1, 0xb9, + 0x5e, 0x14, 0xc0, 0x5f, 0x29, 0xff, 0x1b, 0x92, 0xc1, 0xed, 0xc4, 0xa4, 0xc1, 0x0f, 0x48, 0x98, 0x53, 0xa5, 0xf8, + 0x17, 0x9b, 0xe6, 0x7e, 0xe3, 0x82, 0x78, 0x8c, 0x56, 0x96, 0x53, 0x94, 0xa8, 0x2b, 0x1d, 0xba, 0xd6, 0x21, 0xf7, + 0xf4, 0x0b, 0x13, 0xfa, 0x25, 0x57, 0x9a, 0x09, 0x00, 0x40, 0x85, 0x78, 0x30, 0x25, 0x85, 0x60, 0xeb, 0xd6, 0x6a, + 0xd1, 0xd1, 0xe8, 0xbb, 0x55, 0x74, 0x9d, 0x2d, 0x9a, 0x52, 0x31, 0xca, 0x6d, 0x27, 0xa1, 0xcd, 0xa4, 0xb7, 0x13, + 0x2d, 0x4b, 0x86, 0x16, 0x3b, 0x15, 0xfb, 0x61, 0x68, 0x7d, 0x2c, 0x88, 0x3f, 0x17, 0xfc, 0x59, 0xfa, 0x5d, 0x3e, + 0x06, 0xae, 0xd4, 0xbf, 0xb1, 0x0a, 0xe1, 0x4c, 0xb0, 0x0e, 0xc8, 0x6b, 0x52, 0x1f, 0xa7, 0x47, 0x9d, 0x7c, 0x4b, + 0xb9, 0x50, 0x1a, 0x85, 0x6d, 0x9c, 0x14, 0x06, 0x53, 0xce, 0xbe, 0x2d, 0x71, 0xfd, 0xea, 0x8f, 0x11, 0x7f, 0x74, + 0x88, 0x7f, 0x97, 0x4a, 0xa3, 0x65, 0x89, 0x60, 0xc8, 0xef, 0x48, 0xad, 0xe0, 0x2a, 0x36, 0xe7, 0xfa, 0xb9, 0x9e, + 0xe5, 0x1b, 0x9e, 0x38, 0x5d, 0xad, 0x4a, 0xa9, 0x40, 0xc5, 0x37, 0x0c, 0x3f, 0x61, 0x70, 0x6f, 0xfc, 0x8c, 0x07, + 0x55, 0xb6, 0xef, 0x8b, 0x9f, 0x05, 0xf7, 0xc5, 0xcf, 0x78, 0xba, 0x5d, 0x34, 0xb8, 0x27, 0xee, 0x24, 0xe7, 0x49, + 0x2b, 0xf2, 0x7c, 0xd4, 0x94, 0x56, 0xfe, 0x95, 0x76, 0x6b, 0xe0, 0xca, 0x26, 0x0e, 0x8c, 0xf3, 0xea, 0x22, 0x14, + 0x73, 0xe6, 0x8c, 0x96, 0xc3, 0xff, 0xd6, 0x3a, 0xb9, 0x93, 0x47, 0x5a, 0x29, 0xe4, 0x0d, 0x2d, 0xf4, 0x3d, 0xd8, + 0x70, 0xc5, 0x96, 0x0f, 0x20, 0x25, 0xa0, 0x6c, 0xfb, 0xf7, 0xba, 0x08, 0xc4, 0x71, 0x65, 0x9d, 0x8f, 0xc2, 0xf6, + 0x49, 0x51, 0x72, 0x75, 0x75, 0x21, 0xe4, 0xd6, 0x68, 0x09, 0x10, 0xa6, 0xde, 0x35, 0x8f, 0x39, 0x9a, 0xcc, 0xd2, + 0xe5, 0xba, 0x54, 0x1d, 0x14, 0x96, 0xab, 0xe3, 0x08, 0x17, 0x6b, 0x73, 0x83, 0xfe, 0x8a, 0xe3, 0xbf, 0xb9, 0xa3, + 0x91, 0x9f, 0x4a, 0x0a, 0xf4, 0x68, 0xb7, 0xaf, 0xcd, 0x0e, 0x12, 0x69, 0xe7, 0x50, 0x5a, 0x0a, 0x00, 0x56, 0x1b, + 0x7c, 0x5d, 0x7b, 0x9c, 0x7a, 0x22, 0xdd, 0x6c, 0xbe, 0x69, 0x08, 0x8b, 0x59, 0x69, 0xc1, 0x63, 0xba, 0xd9, 0x61, + 0x39, 0xea, 0x65, 0x71, 0x5d, 0xee, 0xb1, 0x5a, 0xbf, 0xe8, 0x1b, 0xa0, 0xac, 0x0c, 0xd1, 0x56, 0xab, 0xb8, 0x0e, + 0x6f, 0x22, 0x82, 0x6b, 0x10, 0x84, 0x45, 0x60, 0xc0, 0x51, 0x63, 0xbc, 0x6d, 0x9d, 0x18, 0x6d, 0xda, 0x2f, 0x79, + 0xd6, 0xbd, 0x36, 0x8e, 0x50, 0xd1, 0x60, 0xab, 0x87, 0x9a, 0x07, 0x6c, 0x67, 0x57, 0x76, 0x14, 0x40, 0x68, 0x4a, + 0xbd, 0x71, 0x6e, 0x65, 0x45, 0xbb, 0x03, 0xbe, 0xe8, 0x3b, 0xe6, 0xb9, 0x0e, 0x74, 0xdb, 0xf9, 0x81, 0x6d, 0xd3, + 0x13, 0xf9, 0x2d, 0xdb, 0xa6, 0x1a, 0x27, 0xbc, 0xdf, 0x42, 0xdf, 0x37, 0x84, 0xb5, 0x7d, 0xed, 0x2e, 0xf2, 0xbf, + 0xd0, 0x5d, 0x1b, 0xd0, 0xd3, 0x82, 0xd9, 0xd3, 0x98, 0x0f, 0x7a, 0xbd, 0xfe, 0x54, 0xfa, 0x2f, 0x18, 0x5b, 0xa1, + 0x4f, 0x76, 0x17, 0x38, 0xb1, 0xd2, 0x38, 0x04, 0xc7, 0xaf, 0x38, 0x99, 0xe4, 0x72, 0x48, 0xf3, 0x77, 0xd0, 0x63, + 0x95, 0xfb, 0xfc, 0x6e, 0x54, 0x50, 0xcd, 0x1c, 0xad, 0xa9, 0x46, 0xf1, 0x8a, 0x07, 0xc3, 0x78, 0xc5, 0x2d, 0xe5, + 0xae, 0x5a, 0xc0, 0xcb, 0x97, 0x65, 0x13, 0xe9, 0xa7, 0x75, 0x29, 0x83, 0xa9, 0xdd, 0xbd, 0x6c, 0x92, 0x34, 0x56, + 0x92, 0x34, 0xa6, 0xe2, 0xcd, 0xa6, 0xe2, 0xf8, 0xef, 0x6f, 0x0c, 0x76, 0x9b, 0xcc, 0xfd, 0x1d, 0x90, 0xb9, 0xbf, + 0x79, 0xfa, 0xdd, 0x5a, 0x01, 0xc5, 0x3b, 0x4e, 0x8e, 0x8d, 0x65, 0x8c, 0x1d, 0xf5, 0x5b, 0x0d, 0x06, 0x0d, 0x9a, + 0x5c, 0x06, 0xde, 0x0e, 0xd5, 0xe9, 0xe5, 0xed, 0x8f, 0xe2, 0x6c, 0xa1, 0xb4, 0x9c, 0xb9, 0x46, 0x95, 0xf3, 0x71, + 0x32, 0x99, 0xa0, 0xc0, 0x36, 0x77, 0xf8, 0x69, 0xdd, 0x8d, 0x6c, 0xf9, 0x99, 0x8b, 0x51, 0xaa, 0xb0, 0x3b, 0x5b, + 0x54, 0x2a, 0xd7, 0xc4, 0x9b, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0x17, 0x5c, 0x4d, 0x59, 0x11, 0x17, 0x68, 0xf9, 0xad, + 0xce, 0x0a, 0xb8, 0xcd, 0xb1, 0x9d, 0xe1, 0x51, 0x69, 0x39, 0xa0, 0x13, 0x68, 0x0d, 0x74, 0x46, 0x33, 0xa6, 0xa7, + 0x72, 0x04, 0x86, 0x2f, 0xc9, 0xa8, 0x74, 0xa7, 0x3a, 0x38, 0xd8, 0x8f, 0x23, 0xa3, 0xbf, 0x00, 0x1f, 0xf4, 0x30, + 0x07, 0xf5, 0x96, 0xe0, 0x18, 0x54, 0x75, 0xcd, 0xd0, 0x92, 0x6d, 0xfa, 0xd0, 0xe8, 0xe4, 0x33, 0xbb, 0xc3, 0x1c, + 0xad, 0xd7, 0xa9, 0x1d, 0x75, 0x34, 0xe6, 0x2c, 0x1f, 0x45, 0xf8, 0x33, 0xbb, 0x4b, 0x4b, 0xb7, 0x75, 0xe3, 0x65, + 0x6d, 0x16, 0x31, 0x92, 0x37, 0x22, 0xc2, 0x55, 0x27, 0xe9, 0x72, 0x8d, 0x65, 0xc1, 0x27, 0x80, 0xa3, 0xbf, 0xb0, + 0xbb, 0xd4, 0xb5, 0x17, 0xb8, 0x0a, 0xa2, 0xa5, 0x07, 0x7d, 0x12, 0x24, 0x87, 0xcb, 0xe0, 0x04, 0x8e, 0xbe, 0xa9, + 0x3b, 0x20, 0xb5, 0x72, 0x95, 0x08, 0x89, 0xd0, 0xfa, 0xdf, 0x9d, 0x0a, 0x5e, 0x84, 0xe7, 0x9c, 0xae, 0x59, 0xdc, + 0x6e, 0x54, 0x62, 0x50, 0xa1, 0xb2, 0x20, 0xf9, 0x18, 0x73, 0xbf, 0xfb, 0x9c, 0xf7, 0x43, 0xa0, 0x33, 0x5b, 0x50, + 0xd7, 0x68, 0x3a, 0x32, 0xbf, 0x50, 0x75, 0x07, 0x35, 0xd3, 0x55, 0xc5, 0xbd, 0x8f, 0x31, 0x00, 0x1e, 0xac, 0x65, + 0xa8, 0x71, 0x08, 0x5d, 0x7b, 0x33, 0xd5, 0x31, 0x25, 0xf1, 0xd2, 0xcf, 0x21, 0xe5, 0x21, 0x18, 0xf5, 0x1a, 0xd0, + 0xd0, 0x21, 0x98, 0xb5, 0x3c, 0xe4, 0xe3, 0x58, 0x6c, 0x9d, 0xa1, 0xd2, 0x9c, 0xa1, 0x49, 0x00, 0xf2, 0x6f, 0x9c, + 0x99, 0xcc, 0x40, 0xc3, 0xf0, 0x96, 0xe6, 0x00, 0x74, 0xab, 0xeb, 0x70, 0x28, 0x5c, 0xd1, 0xd2, 0x79, 0xcf, 0x2e, + 0xba, 0xac, 0x0d, 0x2b, 0x36, 0xed, 0xa0, 0x75, 0x0a, 0x53, 0x62, 0xb6, 0xc0, 0xda, 0xeb, 0x7d, 0xb8, 0xb7, 0xab, + 0x8d, 0x8b, 0xc4, 0x4f, 0x8b, 0x78, 0x98, 0xc4, 0x14, 0x2d, 0x79, 0x4c, 0xb1, 0x04, 0x3b, 0xc8, 0x62, 0x5d, 0x8e, + 0x9f, 0x85, 0xcb, 0x51, 0xb3, 0x92, 0xde, 0xed, 0x60, 0x08, 0x5c, 0xbe, 0x06, 0xdb, 0x50, 0xcc, 0x3d, 0x61, 0xe1, + 0xb1, 0xf1, 0xf4, 0x0b, 0xd6, 0x6d, 0x6e, 0x17, 0xc4, 0xaf, 0xc0, 0x98, 0xc6, 0xcb, 0x60, 0x16, 0xa1, 0x53, 0xb9, + 0x73, 0x38, 0x74, 0xd7, 0x84, 0x95, 0xf1, 0x6a, 0xac, 0xc8, 0xc6, 0xd1, 0xf3, 0x7d, 0x1b, 0xcf, 0x7f, 0x16, 0xac, + 0xb8, 0xbb, 0x62, 0x60, 0x63, 0x2d, 0xc1, 0xdd, 0xb8, 0x5a, 0x86, 0xca, 0x40, 0xbe, 0x27, 0x0d, 0xeb, 0xb2, 0xc6, + 0xdf, 0x8d, 0x8a, 0xb1, 0x36, 0xf7, 0x94, 0x81, 0xb6, 0xc6, 0x6e, 0x17, 0xf6, 0x4d, 0xd7, 0x4d, 0xd6, 0x35, 0x8a, + 0xb8, 0x0a, 0xd2, 0xee, 0x6e, 0x01, 0x17, 0xa1, 0x3f, 0x6c, 0x5f, 0x0d, 0x36, 0x55, 0x37, 0x90, 0x04, 0xd7, 0x7e, + 0xf2, 0xdb, 0x53, 0xdd, 0x65, 0xad, 0xfb, 0xed, 0xa9, 0xd6, 0x2e, 0x0b, 0x8d, 0x21, 0x11, 0x76, 0xfd, 0x94, 0xfe, + 0xd3, 0x62, 0xbd, 0x46, 0x6b, 0x18, 0xde, 0x7b, 0xde, 0x8d, 0xe3, 0xf7, 0xde, 0x42, 0x31, 0x81, 0x8b, 0xdc, 0xab, + 0x5c, 0x7a, 0x42, 0x5e, 0x8d, 0xe0, 0x3d, 0xdf, 0x1a, 0xc2, 0x7b, 0x1e, 0x38, 0xbd, 0x82, 0xd4, 0x34, 0x11, 0x6c, + 0xe4, 0xe9, 0x27, 0xb2, 0x48, 0x68, 0xf8, 0xb8, 0xd7, 0x9c, 0x70, 0xfd, 0x57, 0x0a, 0xfc, 0x17, 0x1e, 0x2e, 0xb4, + 0x96, 0x02, 0x73, 0x31, 0x5f, 0x68, 0xac, 0xcc, 0xe8, 0x97, 0x63, 0x29, 0x74, 0x73, 0x4c, 0x67, 0x3c, 0xbf, 0x4b, + 0x17, 0xbc, 0x39, 0x93, 0x42, 0xaa, 0x39, 0xcd, 0x18, 0x56, 0x77, 0x4a, 0xb3, 0x59, 0x73, 0xc1, 0xf1, 0x73, 0x96, + 0x7f, 0x61, 0x9a, 0x67, 0x14, 0xbf, 0x95, 0x43, 0xa9, 0x25, 0x7e, 0x7d, 0x7b, 0x37, 0x61, 0x02, 0xff, 0x3e, 0x5c, + 0x08, 0xbd, 0xc0, 0x8a, 0x0a, 0xd5, 0x54, 0xac, 0xe0, 0xe3, 0x6e, 0xb3, 0x39, 0x2f, 0xf8, 0x8c, 0x16, 0x77, 0xcd, + 0x4c, 0xe6, 0xb2, 0x48, 0xff, 0xab, 0x75, 0x4c, 0x1f, 0x8c, 0x4f, 0xba, 0xba, 0xa0, 0x42, 0x71, 0x58, 0x98, 0x94, + 0xe6, 0xf9, 0xde, 0xf1, 0x69, 0x6b, 0xa6, 0xf6, 0xed, 0x85, 0x1f, 0x15, 0x7a, 0xfd, 0x17, 0xfe, 0x20, 0x61, 0x94, + 0xc9, 0x50, 0x0b, 0x37, 0xc8, 0x65, 0xb6, 0x28, 0x94, 0x2c, 0xd2, 0xb9, 0xe4, 0x42, 0xb3, 0xa2, 0x3b, 0x94, 0xc5, + 0x88, 0x15, 0xcd, 0x82, 0x8e, 0xf8, 0x42, 0xa5, 0x27, 0xf3, 0xdb, 0x6e, 0xbd, 0x07, 0x9b, 0x9f, 0x0a, 0x29, 0x58, + 0x17, 0xf8, 0x8d, 0x49, 0x21, 0x17, 0x62, 0xe4, 0x86, 0xb1, 0x10, 0x8a, 0xe9, 0xee, 0x9c, 0x8e, 0xc0, 0x0e, 0x38, + 0x3d, 0x9f, 0xdf, 0x76, 0xcd, 0xac, 0x6f, 0x18, 0x9f, 0x4c, 0x75, 0x7a, 0xda, 0x6a, 0xd9, 0x6f, 0xc5, 0xbf, 0xb2, + 0xb4, 0xdd, 0x49, 0x3a, 0xa7, 0xf3, 0x5b, 0xe0, 0xe0, 0x35, 0x2b, 0x9a, 0x00, 0x0b, 0xa8, 0xd4, 0x4e, 0x5a, 0x0f, + 0x8e, 0xef, 0x43, 0x06, 0xd8, 0x38, 0x34, 0xcd, 0x84, 0xc0, 0xd8, 0x3d, 0x5d, 0xcc, 0xe7, 0xac, 0x00, 0x2f, 0xfa, + 0xee, 0x8c, 0x16, 0x13, 0x2e, 0x9a, 0x85, 0x69, 0xb4, 0x79, 0x3e, 0xbf, 0x5d, 0xc3, 0x7c, 0x52, 0x6b, 0xb6, 0xea, + 0xa6, 0xe5, 0xbe, 0x96, 0xc1, 0x10, 0x4d, 0x4c, 0x9a, 0xb4, 0x98, 0x0c, 0x69, 0xdc, 0xee, 0xdc, 0xc7, 0xfe, 0x7f, + 0x49, 0x07, 0x05, 0x60, 0x6b, 0x8e, 0x16, 0x85, 0xb9, 0x45, 0x4d, 0xdb, 0xca, 0x36, 0x3b, 0x95, 0x5f, 0x58, 0xe1, + 0x5b, 0x35, 0x1f, 0xcb, 0xad, 0x79, 0xff, 0x27, 0x8d, 0xfe, 0x85, 0x27, 0x14, 0xd6, 0xc0, 0x20, 0x47, 0xdf, 0xc8, + 0x83, 0x30, 0xd3, 0xc1, 0xf2, 0x86, 0x8f, 0xf4, 0x34, 0x6d, 0xb7, 0x5a, 0x3f, 0x54, 0x2b, 0xd6, 0x9d, 0x5a, 0xd0, + 0xb5, 0x0b, 0x36, 0xab, 0xad, 0xe3, 0x8c, 0x96, 0xd8, 0xb6, 0x9c, 0x4b, 0xb7, 0xe4, 0x05, 0xcb, 0x4d, 0x34, 0x99, + 0xb5, 0x43, 0xb9, 0xad, 0x71, 0x72, 0x31, 0x65, 0x05, 0xd7, 0xdd, 0xfa, 0x57, 0xd5, 0xf1, 0xf6, 0xea, 0xaf, 0xad, + 0x1c, 0xba, 0xb4, 0x35, 0xdc, 0xa5, 0xe7, 0x63, 0xf8, 0xd8, 0x5e, 0xfd, 0x2f, 0xb4, 0x88, 0x37, 0x10, 0x13, 0x87, + 0x35, 0xd0, 0x3a, 0x98, 0x73, 0x01, 0x26, 0x99, 0x03, 0xfc, 0x0d, 0x28, 0x64, 0x34, 0xcf, 0x62, 0x18, 0xd1, 0x5e, + 0x73, 0xef, 0xb8, 0x60, 0x33, 0xe4, 0x01, 0x91, 0xdc, 0x3f, 0x2d, 0xd8, 0x6c, 0x9d, 0x98, 0xea, 0x4b, 0x83, 0x22, + 0x34, 0xe7, 0x13, 0x91, 0x66, 0x0c, 0xd0, 0x77, 0x9d, 0x30, 0xa1, 0xb9, 0xbe, 0x6b, 0x16, 0xf2, 0x66, 0x39, 0xe2, + 0x6a, 0x9e, 0xd3, 0xbb, 0x74, 0x9c, 0xb3, 0xdb, 0xae, 0x29, 0xd5, 0xe4, 0x9a, 0xcd, 0x94, 0x2b, 0xdb, 0x85, 0xf4, + 0xe6, 0xc8, 0x9a, 0x4d, 0x00, 0xf4, 0xe4, 0xcd, 0xe6, 0xfe, 0x49, 0x8e, 0xd5, 0x1e, 0xa3, 0x8a, 0x35, 0xe5, 0x42, + 0xef, 0xb5, 0x54, 0x77, 0xc6, 0x45, 0xd3, 0x0d, 0xe4, 0xa4, 0x35, 0xbf, 0xed, 0x6e, 0x43, 0x3e, 0xe8, 0x3f, 0x61, + 0xb7, 0x73, 0x2a, 0x46, 0x6c, 0xb4, 0x0c, 0xaa, 0x75, 0xa0, 0x5e, 0x58, 0x2a, 0x15, 0x7a, 0xda, 0x34, 0xb6, 0x5e, + 0x71, 0x47, 0xa0, 0x6f, 0xa0, 0xd6, 0x83, 0x16, 0xb6, 0xff, 0x9f, 0xb4, 0x51, 0x58, 0x79, 0x0f, 0xc2, 0x2e, 0xf1, + 0xf1, 0x5d, 0x13, 0xfe, 0x2e, 0xc1, 0xb7, 0x88, 0x67, 0x34, 0x77, 0x10, 0x99, 0xf1, 0xd1, 0x28, 0xaf, 0x8d, 0xe8, + 0x32, 0xe8, 0xac, 0x8d, 0x96, 0x30, 0xff, 0xb4, 0xb5, 0xd7, 0xda, 0x33, 0x73, 0x71, 0xdb, 0xfc, 0xe4, 0xe4, 0xfe, + 0xf1, 0x03, 0xd6, 0xcd, 0xb9, 0x60, 0xb5, 0xa9, 0x7e, 0x17, 0xd4, 0x61, 0xc3, 0x1d, 0xd7, 0x70, 0x7b, 0xaf, 0xbd, + 0x77, 0xd2, 0xfa, 0xc1, 0xef, 0xd6, 0x9c, 0x8d, 0x75, 0xda, 0x3e, 0x9b, 0xdf, 0xd6, 0xb7, 0xef, 0xb9, 0x6f, 0xfa, + 0xa6, 0xa0, 0xf3, 0x54, 0x48, 0xf8, 0xd3, 0x85, 0x4d, 0x36, 0xce, 0xe5, 0x4d, 0x3a, 0xe5, 0xa3, 0x11, 0x13, 0xb6, + 0x40, 0x99, 0xc8, 0xf2, 0x9c, 0xcf, 0x15, 0xb7, 0xab, 0xe1, 0x70, 0xf7, 0x74, 0x03, 0xaa, 0xe1, 0x80, 0x8e, 0x83, + 0x01, 0x9d, 0x56, 0x03, 0xaa, 0xfa, 0x0f, 0x47, 0xd8, 0xd9, 0x98, 0xab, 0x29, 0xd5, 0xad, 0x61, 0xd2, 0xdf, 0x0b, + 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, + 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, + 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, + 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x70, 0xe7, 0x99, 0x76, 0x07, 0x69, 0xda, 0xbc, 0x61, + 0xc3, 0xcf, 0x5c, 0x5b, 0x3c, 0x6b, 0xaa, 0x1b, 0xf0, 0x78, 0x31, 0xcb, 0x30, 0x67, 0xc5, 0xd2, 0xd3, 0xf0, 0x56, + 0x8d, 0xea, 0x5c, 0x09, 0x73, 0x7a, 0x68, 0x3a, 0x6c, 0x42, 0xfc, 0x2f, 0x56, 0x94, 0x7b, 0x8c, 0x0b, 0x83, 0x31, + 0x06, 0x40, 0x9b, 0xbb, 0x24, 0x3c, 0x03, 0x4e, 0x5a, 0x2d, 0x7f, 0x3e, 0x34, 0x6d, 0x9d, 0xb4, 0x9d, 0x9c, 0xb2, + 0xd9, 0xae, 0xfd, 0x59, 0x27, 0x46, 0xed, 0xce, 0xfc, 0x76, 0xcf, 0xfc, 0xd3, 0xda, 0x6b, 0x6d, 0x13, 0x9f, 0x6d, + 0x38, 0x1d, 0x23, 0xbf, 0xb2, 0x5a, 0xce, 0xd3, 0x36, 0x9b, 0x75, 0x17, 0x0a, 0x0e, 0x1a, 0x43, 0x1b, 0xcd, 0x01, + 0xb6, 0x36, 0x33, 0x81, 0x75, 0xa4, 0x5c, 0x00, 0x5d, 0xb7, 0x67, 0x1b, 0xf4, 0xa1, 0x24, 0x18, 0x62, 0xef, 0x6c, + 0xb4, 0x3e, 0xac, 0xd6, 0x5e, 0x35, 0x30, 0xf8, 0x67, 0xfd, 0x57, 0xc5, 0x19, 0xbe, 0x60, 0x01, 0x67, 0xce, 0x1b, + 0xc9, 0xe9, 0xaa, 0xe5, 0xb8, 0xf1, 0x91, 0xae, 0x84, 0x04, 0xe3, 0xcb, 0x30, 0xa3, 0xb7, 0xd6, 0xa9, 0x61, 0xc6, + 0x05, 0x98, 0x4c, 0x21, 0xac, 0x03, 0xe3, 0xf2, 0x69, 0xd8, 0xd0, 0x48, 0xc7, 0xd0, 0xf0, 0x61, 0x27, 0x39, 0x3d, + 0x45, 0xb8, 0x85, 0x3b, 0xa7, 0xa7, 0x81, 0x34, 0x30, 0xd6, 0xbb, 0x8a, 0xee, 0x2a, 0xa9, 0x76, 0x94, 0x3c, 0x32, + 0x8d, 0x1e, 0xb5, 0x5b, 0x2d, 0x6c, 0x1c, 0xb7, 0xcb, 0xc2, 0x5c, 0xed, 0x68, 0xb6, 0xdd, 0x6a, 0x41, 0xb3, 0xf0, + 0xc7, 0xcd, 0xeb, 0x17, 0xb2, 0x6c, 0xa5, 0x2d, 0xdc, 0x4e, 0xdb, 0xb8, 0x93, 0x76, 0xf0, 0x71, 0x7a, 0x8c, 0x4f, + 0xd2, 0x13, 0x7c, 0x9a, 0x9e, 0xe2, 0xb3, 0xf4, 0x0c, 0xdf, 0x4f, 0xef, 0xe3, 0xf3, 0xf4, 0x1c, 0x3f, 0x48, 0x1f, + 0xe0, 0x87, 0x69, 0xbb, 0x85, 0x1f, 0xa5, 0xed, 0x36, 0x7e, 0x9c, 0xb6, 0x3b, 0xf8, 0x49, 0xda, 0x3e, 0xc6, 0x4f, + 0xd3, 0xf6, 0x09, 0x7e, 0x96, 0xb6, 0x4f, 0x31, 0x85, 0xdc, 0x21, 0xe4, 0x66, 0x90, 0x3b, 0x82, 0x5c, 0x06, 0xb9, + 0xe3, 0xb4, 0x7d, 0xba, 0xc6, 0xca, 0x06, 0x7b, 0x88, 0x5a, 0xed, 0xce, 0xf1, 0xc9, 0xe9, 0xd9, 0xfd, 0xf3, 0x07, + 0x0f, 0x1f, 0x3d, 0x7e, 0xf2, 0xf4, 0x59, 0x34, 0xc0, 0x43, 0xe3, 0x73, 0xa1, 0x44, 0x9f, 0x1f, 0xb4, 0x4f, 0x07, + 0xf8, 0xda, 0x7f, 0xc6, 0xfc, 0xa0, 0x73, 0xd2, 0x42, 0x97, 0x97, 0x27, 0x83, 0x46, 0x99, 0xfb, 0xde, 0xb8, 0x7a, + 0x54, 0x59, 0x84, 0x90, 0x18, 0x72, 0x10, 0xbe, 0x33, 0xf5, 0xde, 0xb3, 0x98, 0x27, 0x05, 0x3a, 0x38, 0x30, 0x3f, + 0x26, 0xfe, 0xc7, 0xd0, 0xff, 0xa0, 0xc1, 0x22, 0xdd, 0xd2, 0xd8, 0xf9, 0xfa, 0xea, 0xd2, 0xd2, 0xbe, 0x34, 0x62, + 0xd9, 0xe3, 0xce, 0x9c, 0xfc, 0xbf, 0x22, 0x6b, 0x2e, 0x42, 0x4e, 0xac, 0x4a, 0xe6, 0xb4, 0xc7, 0xc8, 0xb2, 0x48, + 0x3b, 0xa7, 0xa7, 0x07, 0xbf, 0xf4, 0x79, 0xbf, 0x3d, 0x18, 0x1c, 0xb6, 0xef, 0xe3, 0x49, 0x99, 0xd0, 0xb1, 0x09, + 0xc3, 0x32, 0xe1, 0xd8, 0x26, 0xd0, 0xd4, 0xd6, 0x86, 0xa4, 0x13, 0x93, 0x04, 0x25, 0xd6, 0xa9, 0x69, 0xfb, 0xbe, + 0x6d, 0xfb, 0x01, 0xd8, 0x31, 0x99, 0xe6, 0x5d, 0xd3, 0x17, 0x17, 0x27, 0x2b, 0xd7, 0x28, 0x9e, 0xa4, 0xae, 0x35, + 0x9f, 0x78, 0x32, 0x18, 0xe0, 0xa1, 0x49, 0x3c, 0xad, 0x12, 0xcf, 0x06, 0x03, 0xd7, 0xd5, 0x03, 0xd3, 0xd5, 0xfd, + 0x2a, 0xeb, 0x7c, 0x30, 0x30, 0x5d, 0x22, 0xe7, 0xb5, 0xae, 0xf4, 0xde, 0x97, 0x52, 0x73, 0xc0, 0x2f, 0x3a, 0xa7, + 0xa7, 0x3d, 0xc0, 0x30, 0x63, 0x8d, 0xea, 0x61, 0x74, 0x13, 0xc0, 0xe8, 0x0e, 0x7e, 0xf7, 0x86, 0x34, 0xbd, 0xa6, + 0x25, 0x90, 0x7a, 0xd1, 0x7f, 0x45, 0x0d, 0x6d, 0x60, 0x6e, 0xfe, 0x4c, 0xec, 0x9f, 0x21, 0x6a, 0x7c, 0xa1, 0x00, + 0x6e, 0xd0, 0x85, 0x78, 0x65, 0xa6, 0xe9, 0xf1, 0x33, 0x05, 0xe7, 0x92, 0xa9, 0xca, 0x69, 0x6f, 0x35, 0xbd, 0x19, + 0xae, 0xa6, 0xea, 0x0b, 0xfa, 0x33, 0xfe, 0x53, 0x1d, 0xc6, 0xfd, 0x66, 0x23, 0x61, 0x7f, 0x8e, 0xc0, 0x8b, 0xa5, + 0x97, 0x8e, 0xd8, 0x04, 0xf5, 0xfa, 0x7f, 0x2a, 0x3c, 0x68, 0x04, 0x19, 0x3f, 0x6c, 0xa7, 0x80, 0x8f, 0xcb, 0x66, + 0x62, 0xfc, 0x03, 0xea, 0xa1, 0xde, 0x9f, 0xea, 0xf0, 0x4f, 0x74, 0xef, 0xa8, 0x9a, 0xcb, 0xef, 0xd2, 0x6d, 0xe1, + 0x2a, 0xf0, 0xcd, 0x61, 0xb9, 0x85, 0x19, 0x6e, 0x37, 0x19, 0x84, 0x09, 0x03, 0x27, 0x68, 0x12, 0xcb, 0x06, 0x3f, + 0x3a, 0x6e, 0xa1, 0x1f, 0xda, 0x1d, 0x10, 0xeb, 0x9b, 0xe2, 0x70, 0x7b, 0xd3, 0x17, 0xcd, 0x63, 0xfc, 0xa0, 0x59, + 0xe0, 0x36, 0xc2, 0xcd, 0xb6, 0xd7, 0xb7, 0xf6, 0x55, 0xdc, 0x42, 0x58, 0xc5, 0xe7, 0xf0, 0xcf, 0x09, 0x1a, 0x54, + 0x1b, 0xf2, 0x8a, 0x6e, 0xf6, 0x0e, 0x1e, 0x9b, 0x24, 0x56, 0x0d, 0x7e, 0x74, 0xd6, 0x42, 0x3f, 0x9c, 0x99, 0x8e, + 0xd8, 0xa1, 0xde, 0xd1, 0x95, 0xc4, 0x27, 0x4d, 0x09, 0x1d, 0xb5, 0xca, 0x7e, 0x44, 0x7c, 0x8a, 0xb0, 0x88, 0x8f, + 0xe1, 0x9f, 0x76, 0xd8, 0xcf, 0xaf, 0x5b, 0xfd, 0x98, 0x79, 0xb7, 0x71, 0x72, 0x6a, 0x1d, 0x40, 0x95, 0xbd, 0x8d, + 0x6d, 0xb0, 0xcb, 0xb6, 0xb9, 0x46, 0x6a, 0x1f, 0xc1, 0x07, 0xc2, 0xfa, 0x90, 0x28, 0xcc, 0x0e, 0xc1, 0x73, 0x14, + 0x0c, 0x26, 0xd4, 0xc5, 0x71, 0x57, 0x35, 0x1a, 0x48, 0xf4, 0xd5, 0xe0, 0x90, 0xb4, 0x9b, 0xba, 0xc9, 0x30, 0xfc, + 0x6e, 0x90, 0x32, 0x1c, 0x99, 0xa8, 0x7a, 0x7d, 0xec, 0x7a, 0xb5, 0x77, 0xce, 0x1e, 0x3b, 0x08, 0x21, 0xaa, 0x17, + 0xeb, 0x26, 0x43, 0x47, 0xa2, 0x11, 0xeb, 0x0b, 0xd6, 0x3b, 0x4b, 0x5b, 0xc8, 0x60, 0xa7, 0xea, 0xc5, 0xac, 0xc9, + 0x21, 0xbd, 0x93, 0xc6, 0xbc, 0xa9, 0xe1, 0xd7, 0x49, 0x30, 0x0b, 0x01, 0x78, 0x57, 0xf9, 0xc1, 0x14, 0x47, 0x9d, + 0xd3, 0x53, 0x2c, 0x08, 0x4f, 0x26, 0xe6, 0x97, 0x22, 0x3c, 0x19, 0x9a, 0x5f, 0x92, 0x94, 0xf0, 0xb2, 0xbd, 0xe3, + 0x82, 0x04, 0xab, 0x6a, 0x52, 0x28, 0x2c, 0x68, 0x81, 0x8e, 0x3a, 0xfe, 0x42, 0x1a, 0x4f, 0xfd, 0x1c, 0x40, 0x00, + 0x2f, 0x8c, 0x2d, 0xa2, 0x6c, 0x16, 0x38, 0x27, 0xf4, 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, + 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, 0xb6, 0x86, 0xa7, 0x70, 0x8b, 0x98, 0x91, 0xec, 0xf0, 0xac, + 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, + 0xa5, 0x8e, 0x68, 0x33, 0x2a, 0x4c, 0x8f, 0xc7, 0x1a, 0x6e, 0xc4, 0x35, 0xf8, 0x99, 0x68, 0xf0, 0x80, 0x49, 0xb9, + 0xbb, 0x8a, 0x42, 0x26, 0x2e, 0xde, 0x38, 0xd4, 0x1a, 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x4d, 0xa3, 0x88, 0x7f, 0x97, + 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, + 0x03, 0x1d, 0x17, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, + 0xad, 0x34, 0xf9, 0x4c, 0xad, 0x95, 0x3f, 0xf7, 0xee, 0xc6, 0x66, 0xe1, 0xac, 0xb3, 0x73, 0xe9, 0xd9, 0xdc, 0x3f, + 0x05, 0x2b, 0x0a, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, + 0xa1, 0xf2, 0x32, 0xf5, 0xa3, 0x84, 0xa4, 0xce, 0x00, 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, + 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x95, 0xe1, 0x5c, 0x01, 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0xeb, + 0x6e, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0xb0, + 0xf4, 0xc0, 0x93, 0x14, 0xac, 0x3c, 0xf0, 0x30, 0x15, 0xe0, 0x89, 0x40, 0x53, 0x16, 0xd8, 0x8f, 0x3f, 0x74, 0xba, + 0x23, 0x73, 0xdf, 0x49, 0x0c, 0x96, 0x76, 0x19, 0x9c, 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, + 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, + 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0x5f, 0x21, 0x6b, 0xdb, 0x38, 0xdc, 0x4d, 0x43, 0x13, 0x82, 0x70, 0x15, + 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0xf0, 0x22, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, + 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, + 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x47, 0x34, 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, + 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, + 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0x26, 0x1c, 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x76, 0xf8, + 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, + 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, + 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, + 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, + 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, + 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, + 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, + 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, + 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, + 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, + 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, + 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, 0x26, 0x8d, 0x12, 0x7d, 0xcc, 0x86, 0xd9, 0x28, 0xc2, 0x66, + 0x30, 0x63, 0xf8, 0xfb, 0x85, 0xbf, 0x63, 0x3a, 0x8d, 0xce, 0x69, 0x67, 0xc8, 0x3a, 0x11, 0x1e, 0xbe, 0xb9, 0x11, + 0x69, 0x44, 0x4f, 0x3b, 0xb4, 0x43, 0x23, 0x3c, 0x5c, 0x14, 0xf9, 0xdd, 0x8d, 0x94, 0x23, 0x00, 0xc2, 0xf0, 0xfc, + 0xfc, 0x7e, 0x84, 0x33, 0xfa, 0xab, 0x86, 0xda, 0xa7, 0xe3, 0x07, 0x8c, 0xb6, 0x22, 0xfc, 0x0b, 0x2d, 0xf4, 0xc7, + 0x85, 0x72, 0x03, 0x6d, 0x41, 0x8a, 0xcc, 0xde, 0x81, 0x82, 0x39, 0x1a, 0x75, 0xce, 0x1e, 0xb4, 0x59, 0x84, 0xb3, + 0xab, 0xd7, 0xd0, 0xdb, 0xfd, 0xf1, 0x69, 0x0b, 0x3e, 0x04, 0x48, 0x6a, 0xac, 0x80, 0x46, 0xce, 0x4e, 0x1e, 0x9c, + 0xb2, 0x91, 0x49, 0x54, 0x3c, 0xff, 0x6c, 0x66, 0x7f, 0x0e, 0xf3, 0xc9, 0x0a, 0x3e, 0x53, 0x52, 0xa4, 0xd1, 0x28, + 0x6b, 0x9f, 0x1c, 0x43, 0xc2, 0x1d, 0x15, 0x1e, 0x38, 0xb7, 0x50, 0xf5, 0x7c, 0x18, 0xe1, 0x5b, 0x9b, 0x7a, 0x3e, + 0x34, 0x1f, 0x93, 0x77, 0xbf, 0x8a, 0x37, 0xa3, 0x34, 0x1a, 0x9e, 0x9f, 0x9f, 0xb5, 0x20, 0xe1, 0x03, 0xbd, 0x4b, + 0x23, 0xfa, 0x00, 0xfe, 0x83, 0xec, 0x8f, 0xcf, 0xa0, 0x43, 0x18, 0xe1, 0xed, 0xe4, 0x63, 0x98, 0xf3, 0x79, 0x4a, + 0x3f, 0xf3, 0x34, 0x1a, 0x8e, 0x86, 0xf7, 0xcf, 0xa0, 0xde, 0x8c, 0x4e, 0x9e, 0x69, 0x0a, 0xed, 0xb6, 0x5a, 0xa6, + 0xe5, 0x77, 0xfc, 0x0b, 0x33, 0xd5, 0x4f, 0x4f, 0xcf, 0x86, 0x1d, 0x18, 0xc1, 0x15, 0xa8, 0x18, 0x60, 0x3c, 0xe7, + 0x99, 0x69, 0xf0, 0x2a, 0x7b, 0x3a, 0x4a, 0xa3, 0x07, 0x0f, 0x8e, 0x3b, 0x59, 0x16, 0xe1, 0xdb, 0x8f, 0x23, 0x5b, + 0xdb, 0xe4, 0x29, 0x80, 0x7d, 0x1a, 0xb1, 0x07, 0x0f, 0xce, 0xee, 0x53, 0xf8, 0x7e, 0x6e, 0xda, 0x3a, 0x1f, 0x0f, + 0xb3, 0x73, 0x68, 0xeb, 0x77, 0x98, 0xce, 0xc9, 0xf9, 0xf1, 0xc8, 0xf4, 0xf5, 0xbb, 0x19, 0x75, 0x67, 0x7c, 0x32, + 0x3e, 0x31, 0x99, 0x66, 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x8d, 0x32, 0x36, 0x6a, 0x47, 0xf8, 0xd6, 0x2d, 0xdc, 0x83, + 0x93, 0x56, 0x6b, 0x74, 0x1c, 0xe1, 0xd1, 0xc3, 0xf9, 0xfc, 0xad, 0x81, 0x60, 0xfb, 0xe4, 0x81, 0xfd, 0x56, 0x9f, + 0xef, 0xa0, 0xe9, 0xa1, 0x01, 0xda, 0x88, 0xcf, 0x4c, 0xcb, 0x67, 0x0f, 0xe0, 0x3f, 0xf3, 0x6d, 0x9a, 0x2e, 0xbf, + 0xe5, 0x68, 0x62, 0x17, 0xa5, 0xcd, 0x1e, 0xb4, 0xa0, 0xc6, 0x98, 0x7f, 0x1c, 0x16, 0x1c, 0xd0, 0x68, 0xd8, 0x81, + 0xff, 0x8b, 0xf0, 0x38, 0xbf, 0x7a, 0xed, 0x70, 0x76, 0x3c, 0xa6, 0xe3, 0x56, 0x84, 0xc7, 0xf2, 0xa3, 0xd2, 0x1f, + 0x1e, 0x8a, 0x34, 0xea, 0x74, 0xce, 0x87, 0xa6, 0xcc, 0xe2, 0x17, 0xc5, 0x0d, 0x1e, 0xb7, 0x4c, 0x2b, 0x13, 0xfa, + 0x56, 0x0d, 0xaf, 0x24, 0xac, 0x24, 0xfc, 0x17, 0xe1, 0x09, 0xe8, 0xa5, 0x5c, 0x2b, 0xe7, 0x76, 0x3b, 0x4c, 0xde, + 0x19, 0xd4, 0x1c, 0xdd, 0x07, 0x78, 0xf9, 0x65, 0x1c, 0x51, 0x7a, 0xda, 0x69, 0x45, 0xd8, 0x8c, 0xfa, 0xbc, 0x05, + 0xff, 0x45, 0xd8, 0x42, 0xce, 0xc0, 0x75, 0xf2, 0xf1, 0xd9, 0xcb, 0x9b, 0x34, 0xa2, 0xa3, 0xf1, 0x18, 0x96, 0xc4, + 0x4c, 0xc6, 0x17, 0x9b, 0x4a, 0xc1, 0xee, 0x7e, 0xbd, 0x71, 0xdb, 0xc5, 0x24, 0x68, 0x07, 0x9d, 0xb3, 0x07, 0xc3, + 0x93, 0x08, 0xbf, 0x1d, 0x71, 0x2a, 0x60, 0x95, 0xb2, 0xd1, 0x69, 0x76, 0x9a, 0x99, 0x84, 0x89, 0x4c, 0xa3, 0x13, + 0x58, 0xf2, 0x4e, 0x84, 0xf9, 0x97, 0xab, 0x3b, 0x8b, 0x6e, 0x50, 0xdb, 0x21, 0xc8, 0xb8, 0xc5, 0xce, 0xce, 0xb3, + 0x08, 0xe7, 0xf4, 0xcb, 0xb3, 0x5f, 0x8b, 0x34, 0x62, 0x67, 0xec, 0x6c, 0x4c, 0xfd, 0xf7, 0x1f, 0x6a, 0x6a, 0x6a, + 0xb4, 0xc6, 0xa7, 0x90, 0x74, 0x23, 0xcc, 0x58, 0xef, 0x67, 0x63, 0x83, 0x21, 0xaf, 0x66, 0x52, 0x64, 0x4f, 0xc7, + 0x63, 0x69, 0xb1, 0x98, 0xc2, 0x26, 0xfc, 0x04, 0xd0, 0xa6, 0xa3, 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x27, 0xbb, 0x4b, + 0xdc, 0x04, 0x3e, 0x59, 0xcc, 0x66, 0x6e, 0xb7, 0x7f, 0xb2, 0x40, 0x81, 0xf9, 0x8e, 0xe9, 0x98, 0x8e, 0x3a, 0x11, + 0xfe, 0x64, 0xe0, 0x32, 0x3a, 0x86, 0xff, 0xa0, 0x00, 0x74, 0xf6, 0xa0, 0xc5, 0xd8, 0x83, 0x96, 0xf9, 0x0a, 0xf3, + 0xdc, 0xcc, 0x87, 0x67, 0x59, 0x3b, 0xc2, 0x9f, 0x1c, 0x3a, 0x8e, 0xc7, 0xb4, 0x05, 0xe8, 0xf8, 0xc9, 0xa1, 0x63, + 0xa7, 0x35, 0xec, 0x50, 0xf3, 0x6d, 0xb1, 0xe6, 0xfc, 0x7e, 0xc6, 0x60, 0x72, 0x9f, 0x2c, 0x42, 0xde, 0xbf, 0x7f, + 0x7e, 0xfe, 0xe0, 0x01, 0x7c, 0x9a, 0xb6, 0xcb, 0x4f, 0xa5, 0x1f, 0xe6, 0x06, 0xc9, 0x5a, 0xd9, 0x09, 0xd0, 0xc9, + 0x4f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, + 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, + 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, + 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, + 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, + 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, + 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, + 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, + 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, + 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, + 0x87, 0x23, 0xfc, 0x6e, 0x04, 0xd7, 0x60, 0x69, 0x34, 0x1e, 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, + 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, + 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, + 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, + 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, + 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, + 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, + 0x21, 0xdc, 0xf3, 0x2d, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, 0x08, 0x6e, 0xfd, 0xe4, 0xcd, 0xaf, 0x85, 0x45, 0x23, + 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, + 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, + 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, + 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, + 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, + 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, + 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, + 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, + 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, + 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, + 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, + 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, + 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, + 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0x3d, 0xe8, 0x13, 0x1a, 0x7b, 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xe1, 0x45, 0x3f, + 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x5c, 0x00, 0x9c, 0x41, 0xbd, 0xf3, 0x99, 0x04, 0x41, 0x52, + 0x90, 0x56, 0x57, 0x5c, 0x78, 0x3f, 0xce, 0xae, 0x80, 0xa0, 0x03, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0xc4, 0x66, 0xb1, + 0xc2, 0xa4, 0x37, 0x6f, 0x37, 0x32, 0xa5, 0xb4, 0x06, 0xf3, 0x94, 0x50, 0x1f, 0x95, 0x1d, 0x2e, 0x69, 0x21, 0x6e, + 0x11, 0xea, 0x4a, 0x62, 0x62, 0x2c, 0xbf, 0x10, 0x3a, 0x56, 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0x5e, + 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0x11, + 0xa3, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, + 0x47, 0x2c, 0x31, 0xb7, 0x06, 0xd6, 0x37, 0x85, 0xf4, 0x41, 0x73, 0xd6, 0xc2, 0x10, 0xc7, 0xdc, 0x73, 0xde, 0x8f, + 0x58, 0x9f, 0xd7, 0xfd, 0x9a, 0xab, 0xe0, 0xc1, 0x07, 0x07, 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, + 0x56, 0x4c, 0xd0, 0x55, 0xf8, 0xf6, 0x93, 0x1e, 0x48, 0x29, 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, + 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, + 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, 0x49, 0x23, 0x9a, 0xed, 0xdb, 0x48, 0x18, 0xba, 0x7f, + 0xdf, 0x08, 0x66, 0x55, 0x78, 0xb6, 0x06, 0x24, 0x75, 0x41, 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, + 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x45, 0xb4, 0x61, 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, + 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, + 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, + 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, + 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, + 0x46, 0x49, 0xf4, 0x97, 0x57, 0xa2, 0x3e, 0xe2, 0x26, 0xfe, 0xcc, 0x05, 0x49, 0x5a, 0xad, 0xe3, 0xf6, 0x71, 0xeb, + 0xbc, 0xc7, 0x0f, 0xdb, 0x9d, 0xe4, 0x41, 0x27, 0x35, 0x8a, 0x88, 0xb9, 0xbc, 0x01, 0x05, 0xcc, 0x51, 0x27, 0x39, + 0x41, 0x87, 0xed, 0xa4, 0x75, 0x7a, 0xda, 0x84, 0x7f, 0xf0, 0x7b, 0x5d, 0x56, 0x3b, 0x69, 0x9d, 0x9c, 0xf6, 0xf8, + 0xd1, 0x46, 0xa5, 0x98, 0x37, 0xa0, 0x20, 0x3a, 0x32, 0x95, 0x30, 0xd4, 0xaf, 0x96, 0xf7, 0xd9, 0x96, 0x9e, 0xe7, + 0xbd, 0x8e, 0x95, 0x55, 0xc5, 0x01, 0x54, 0xfd, 0xd7, 0xc4, 0x00, 0xd1, 0x7f, 0x0d, 0xcb, 0x18, 0xb1, 0xcb, 0x02, + 0x44, 0xed, 0x47, 0x3c, 0x16, 0x0d, 0x76, 0x18, 0xdb, 0x7c, 0x0d, 0x75, 0x9b, 0x10, 0xb7, 0x0d, 0x4f, 0x5c, 0xae, + 0x0a, 0x73, 0x27, 0x08, 0x35, 0x15, 0xe4, 0x0e, 0x5d, 0xae, 0x0c, 0x73, 0x87, 0x08, 0x35, 0x25, 0xe4, 0xd2, 0x94, + 0x27, 0x14, 0x72, 0x74, 0x42, 0x9b, 0x06, 0x92, 0xd5, 0xa2, 0x3c, 0x67, 0x7e, 0xd8, 0x7c, 0x0c, 0xcb, 0x63, 0x08, + 0x8a, 0x13, 0xa4, 0x05, 0xbc, 0xed, 0x51, 0x6a, 0x73, 0x5a, 0xb8, 0x54, 0xe3, 0x40, 0x46, 0x03, 0xfe, 0x39, 0x64, + 0xe6, 0xc1, 0x87, 0x56, 0xef, 0xf8, 0xac, 0x95, 0xb6, 0xc1, 0x49, 0x19, 0x64, 0x6d, 0x61, 0x65, 0x6d, 0xe1, 0x65, + 0x6d, 0xe1, 0x65, 0x6d, 0x10, 0xe0, 0x83, 0xbe, 0xff, 0x91, 0x35, 0xc3, 0x0f, 0x5e, 0x5a, 0x91, 0x58, 0x33, 0x81, + 0x58, 0xaf, 0x56, 0xcb, 0x35, 0xd8, 0xf8, 0x94, 0x35, 0xa4, 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, + 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, 0x3f, 0xa6, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, + 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, + 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0xf0, 0x79, 0xb1, 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x5c, 0x98, + 0x2d, 0xa9, 0x13, 0x6a, 0xbc, 0xa6, 0xcb, 0x31, 0x7f, 0xad, 0xa1, 0x7d, 0x02, 0x6f, 0xb9, 0x3c, 0xd4, 0x71, 0x0b, + 0x8c, 0x26, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, 0x8d, 0x33, 0x86, 0xfe, 0xbc, 0xe1, 0x83, 0x6a, 0x29, + 0x41, 0xf8, 0x82, 0xc1, 0x67, 0x56, 0x39, 0xc5, 0x97, 0xb6, 0x9e, 0xce, 0x50, 0xcb, 0x1e, 0x09, 0x5d, 0x30, 0xd8, + 0xf6, 0xd1, 0x96, 0x7a, 0x82, 0x48, 0x65, 0xdc, 0x05, 0x49, 0x15, 0x2f, 0x18, 0xdc, 0x67, 0xc9, 0x2d, 0x35, 0xce, + 0x24, 0x2f, 0xec, 0x9f, 0xaf, 0x34, 0xf0, 0xb6, 0x2b, 0x26, 0x43, 0xef, 0xa4, 0x7a, 0x6d, 0xa2, 0xea, 0x90, 0xfd, + 0x7d, 0x6b, 0x4b, 0x6d, 0xbe, 0x36, 0x8d, 0xa9, 0x4d, 0xa2, 0xc9, 0x86, 0x1d, 0xea, 0xd7, 0xe8, 0x1f, 0xef, 0x2b, + 0x56, 0x4c, 0x86, 0x28, 0xa0, 0xd9, 0x06, 0xac, 0xaa, 0x02, 0x96, 0x72, 0xf5, 0x4a, 0x17, 0x42, 0xe8, 0xdd, 0x8c, + 0x79, 0x5d, 0x4c, 0x86, 0x3b, 0x1f, 0xfd, 0xb0, 0x3d, 0xf6, 0xde, 0xd2, 0xa0, 0x07, 0xaf, 0xda, 0x9e, 0xb2, 0xdb, + 0xef, 0xd5, 0xb9, 0xd9, 0x59, 0x47, 0xe5, 0xdf, 0xab, 0xf3, 0x74, 0x57, 0x9d, 0x19, 0xbf, 0x8d, 0xfd, 0xde, 0xd1, + 0x81, 0x1a, 0xdb, 0x18, 0xe8, 0x4c, 0x86, 0x10, 0xa5, 0x1d, 0xfe, 0xda, 0x58, 0x2a, 0x5d, 0x4f, 0xc2, 0x61, 0x15, + 0x64, 0x2f, 0x39, 0x4d, 0x19, 0xa6, 0xa4, 0x73, 0x58, 0x98, 0x68, 0x2a, 0x22, 0xa1, 0x4d, 0x95, 0x50, 0x9c, 0x93, + 0x38, 0xa6, 0x87, 0x19, 0xc4, 0x84, 0x69, 0xf7, 0x68, 0x1a, 0xd3, 0x46, 0x86, 0x8e, 0xe2, 0x76, 0x83, 0x1e, 0x66, + 0x08, 0x35, 0xda, 0xa0, 0x33, 0x95, 0xa4, 0xdd, 0xcc, 0x21, 0x4a, 0xa4, 0x21, 0xc5, 0xf9, 0xa1, 0x48, 0x8a, 0x86, + 0x3c, 0x54, 0x49, 0xd1, 0x48, 0x4e, 0xb1, 0x48, 0x26, 0x65, 0xf2, 0xc4, 0x24, 0x4f, 0x6c, 0xf2, 0xb0, 0x4c, 0x1e, + 0x9a, 0xe4, 0xa1, 0x4d, 0xa6, 0xa4, 0x38, 0x14, 0x09, 0x6d, 0xc4, 0xed, 0x66, 0x81, 0x0e, 0x61, 0x04, 0x7e, 0xf4, + 0x44, 0x84, 0xc1, 0xb9, 0xd7, 0xc6, 0xba, 0x65, 0x2e, 0x73, 0x17, 0x2e, 0xb3, 0x02, 0x52, 0xe9, 0x72, 0x04, 0x75, + 0x9e, 0x05, 0x60, 0xc2, 0xda, 0xfe, 0xf1, 0xc1, 0xe0, 0xd6, 0x59, 0x2e, 0x45, 0xe0, 0x52, 0x05, 0x56, 0xe0, 0x9f, + 0x9d, 0x23, 0x09, 0x40, 0x75, 0x4d, 0xf3, 0xf9, 0x94, 0x6e, 0xf9, 0xad, 0x16, 0x93, 0xa1, 0xdb, 0x59, 0x65, 0x33, + 0x8c, 0x16, 0x36, 0xc8, 0x72, 0xdd, 0xc3, 0x10, 0x40, 0xed, 0xbd, 0x1a, 0x13, 0x6a, 0x94, 0xe4, 0xb6, 0xc6, 0xa4, + 0x60, 0x77, 0x2a, 0xa3, 0x39, 0x8b, 0xab, 0x03, 0xb8, 0x1a, 0x26, 0x23, 0x2f, 0xc0, 0x16, 0xbd, 0x38, 0x4c, 0x8e, + 0x1b, 0x3a, 0x99, 0x1c, 0x26, 0xa7, 0x0f, 0x1a, 0x3a, 0x19, 0x1e, 0x26, 0xed, 0x76, 0x85, 0xb3, 0x49, 0x41, 0x74, + 0x32, 0x21, 0x1a, 0x34, 0x86, 0xb6, 0x51, 0x39, 0xa7, 0x60, 0x5c, 0xf5, 0x6f, 0x0c, 0xa3, 0xe1, 0x86, 0x21, 0xd8, + 0xc4, 0xc6, 0x9b, 0xdc, 0x1a, 0x43, 0xd8, 0x4d, 0xe7, 0xf4, 0xb4, 0xa9, 0x93, 0x02, 0x6b, 0xbb, 0x92, 0x4d, 0x9d, + 0x4c, 0xb0, 0xb6, 0xcb, 0xd7, 0xd4, 0xc9, 0xd0, 0x36, 0x65, 0x74, 0x80, 0x4c, 0x04, 0xc0, 0x7a, 0xce, 0x02, 0xc8, + 0x77, 0xbc, 0x7b, 0xc8, 0x1a, 0xb4, 0x86, 0xdf, 0x2b, 0xd7, 0xf4, 0x05, 0x15, 0xd5, 0x60, 0x64, 0xc3, 0xbe, 0x55, + 0xb4, 0x5d, 0x35, 0xc9, 0xfe, 0x75, 0xd9, 0xb2, 0xd9, 0x42, 0xea, 0x7a, 0xc1, 0x87, 0x35, 0x0c, 0x71, 0xa5, 0xdc, + 0xc1, 0xfd, 0x8a, 0x92, 0x18, 0xa2, 0xca, 0x99, 0x53, 0x88, 0x13, 0xaf, 0x47, 0x86, 0x24, 0xde, 0x68, 0xac, 0x51, + 0x1c, 0x9c, 0xb7, 0x4f, 0x43, 0xaa, 0xba, 0x15, 0x6a, 0x8e, 0x90, 0x68, 0x21, 0xac, 0x31, 0xe2, 0x28, 0x0a, 0x58, + 0x10, 0xa7, 0xdd, 0xad, 0x1d, 0x10, 0x07, 0x07, 0x9b, 0xe7, 0x85, 0x0f, 0xfa, 0xbf, 0x15, 0xe8, 0xbf, 0xb2, 0x64, + 0xf3, 0x4f, 0x11, 0x59, 0x1b, 0x57, 0x1e, 0x20, 0x8a, 0x0f, 0xfa, 0x74, 0xdf, 0x50, 0xf8, 0x7e, 0x15, 0xf1, 0xce, + 0xe5, 0x34, 0xcf, 0x4c, 0x86, 0xe9, 0x6b, 0x10, 0x8c, 0xed, 0x4d, 0x38, 0xa1, 0xd2, 0x4a, 0xef, 0x5f, 0x76, 0x1c, + 0x74, 0xe2, 0x9e, 0x4a, 0x09, 0x1b, 0xfd, 0x3b, 0xb4, 0x89, 0xad, 0x60, 0xe3, 0xbc, 0xa1, 0x57, 0xab, 0xda, 0xc3, + 0x38, 0xf6, 0xf9, 0x15, 0x74, 0x70, 0xc0, 0xd5, 0x33, 0x30, 0xe3, 0x65, 0x71, 0x23, 0x3c, 0x7c, 0xff, 0xa9, 0x9d, + 0xd6, 0x7f, 0x9b, 0x73, 0x35, 0x0d, 0x0e, 0xba, 0x87, 0xb5, 0xfc, 0x9d, 0x2b, 0xd1, 0xd3, 0x29, 0x77, 0x6b, 0xfd, + 0x77, 0x65, 0x24, 0xbd, 0xf5, 0x44, 0xd3, 0xc1, 0x01, 0xaf, 0x02, 0x25, 0x45, 0x3f, 0x44, 0xa8, 0x67, 0x64, 0x90, + 0x67, 0xb9, 0xa4, 0x70, 0x23, 0x0a, 0x57, 0x0c, 0x69, 0x83, 0x1f, 0x69, 0xfc, 0x87, 0xfc, 0xff, 0xd4, 0xc8, 0xa1, + 0x4e, 0x1b, 0x3c, 0x10, 0xc0, 0x42, 0x56, 0xa8, 0x0a, 0x51, 0x68, 0x20, 0x1d, 0xda, 0x3c, 0xa3, 0xf2, 0x30, 0xa7, + 0xf3, 0x79, 0x7e, 0x67, 0x5e, 0xa9, 0x0a, 0x38, 0xaa, 0xea, 0xa2, 0xc9, 0xc5, 0x87, 0xc3, 0x05, 0xf0, 0xf4, 0x80, + 0x7b, 0xc8, 0xf8, 0x77, 0x96, 0x97, 0xdb, 0x02, 0x81, 0x64, 0xa6, 0x88, 0x6c, 0xb6, 0xbb, 0xea, 0x12, 0xe4, 0xb2, + 0x66, 0x13, 0x69, 0x17, 0x36, 0x1b, 0x73, 0x90, 0xc9, 0x94, 0xf5, 0xe1, 0xdc, 0xb3, 0x05, 0x41, 0x72, 0x93, 0x46, + 0x64, 0xdb, 0x5d, 0x8a, 0x8f, 0x63, 0x40, 0x23, 0x64, 0x05, 0xbe, 0x50, 0x58, 0xe4, 0xc0, 0x75, 0x16, 0xbe, 0xe3, + 0x6f, 0xb4, 0x54, 0xf4, 0xd5, 0x60, 0x80, 0x0b, 0xf3, 0x30, 0x43, 0x39, 0x9f, 0x42, 0x05, 0x0f, 0xfd, 0x04, 0x22, + 0x0a, 0x5f, 0xad, 0xf6, 0xe1, 0x1d, 0x1d, 0xd7, 0x26, 0x38, 0x7d, 0xba, 0x9f, 0xd5, 0x9b, 0x19, 0x30, 0x0e, 0x46, + 0x5a, 0xe6, 0xa2, 0xd0, 0xc9, 0x9b, 0xec, 0x42, 0x74, 0x1b, 0x0d, 0x66, 0x42, 0x1c, 0x11, 0x88, 0x67, 0x06, 0x1e, + 0x79, 0xf0, 0xc7, 0x46, 0x2d, 0x52, 0xcc, 0xc6, 0x7e, 0x83, 0xa0, 0xd4, 0xb5, 0x84, 0xd5, 0x4a, 0xd9, 0xd8, 0x22, + 0x26, 0xc7, 0x46, 0x19, 0x29, 0xfb, 0x29, 0x83, 0x98, 0x56, 0x66, 0x1c, 0xdc, 0x6d, 0xf5, 0xb7, 0xd5, 0x7e, 0xde, + 0xe3, 0xf6, 0x1a, 0x8f, 0x1b, 0x8f, 0x7d, 0x03, 0xa8, 0xe5, 0xc6, 0x06, 0xb7, 0x16, 0xe6, 0xb1, 0x35, 0x87, 0x65, + 0x9b, 0x10, 0x14, 0xa5, 0x87, 0xba, 0xbd, 0xb9, 0xf5, 0x11, 0xfb, 0x94, 0x99, 0x93, 0x42, 0xba, 0x0f, 0x72, 0xf4, + 0x80, 0x40, 0xe7, 0xf6, 0x67, 0x45, 0x17, 0x2a, 0x99, 0xb8, 0x1c, 0xe3, 0x2f, 0xc1, 0x6d, 0x5e, 0x3f, 0xba, 0xbe, + 0x36, 0x9b, 0xfc, 0xfa, 0x3a, 0xc2, 0xa1, 0x59, 0x77, 0x14, 0xf0, 0x82, 0xd1, 0xa0, 0x0c, 0xea, 0x64, 0x36, 0x7e, + 0xb3, 0x5d, 0x35, 0xf6, 0x9e, 0x56, 0x78, 0x07, 0xcb, 0x63, 0x1a, 0xdf, 0x72, 0x83, 0xec, 0x73, 0x80, 0x37, 0xeb, + 0xf3, 0x41, 0xf7, 0x4d, 0xac, 0xd0, 0xc1, 0xc1, 0x9b, 0x58, 0xa2, 0xde, 0x15, 0x33, 0x77, 0x6e, 0xe0, 0x07, 0xdd, + 0xe7, 0x66, 0xf8, 0x32, 0x40, 0x80, 0x2b, 0xb6, 0x29, 0xd9, 0xbc, 0x35, 0x51, 0x27, 0x52, 0x88, 0x6a, 0x0d, 0xb1, + 0x75, 0x1d, 0x48, 0xa0, 0xd7, 0x37, 0x21, 0xb4, 0xbb, 0x8c, 0x30, 0x60, 0xe1, 0x4b, 0x2f, 0x35, 0x96, 0xcc, 0x58, + 0x31, 0x61, 0xc5, 0x6a, 0xf5, 0x9e, 0x5a, 0xcf, 0xb3, 0x8d, 0x20, 0x89, 0xaa, 0xdb, 0x68, 0x50, 0x33, 0x7e, 0x10, + 0x1f, 0xe8, 0x00, 0xef, 0xbf, 0x89, 0x0b, 0x84, 0xc0, 0xc2, 0x88, 0x8b, 0x85, 0xf7, 0xb2, 0xca, 0x6a, 0xeb, 0x52, + 0xa0, 0xb2, 0x91, 0x9c, 0xb4, 0xf0, 0x94, 0x64, 0xe5, 0x1a, 0x5d, 0x4c, 0xbb, 0x8d, 0x46, 0x8e, 0x64, 0x9c, 0xf5, + 0xf3, 0x01, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0x72, 0xf3, 0x5d, 0xda, 0xb1, 0xa6, + 0x8f, 0xe8, 0x3a, 0x00, 0xc6, 0x23, 0x1a, 0x10, 0x89, 0x5d, 0x40, 0x16, 0x16, 0xc8, 0xca, 0x03, 0x59, 0x18, 0x20, + 0x2b, 0xd4, 0x9b, 0x43, 0xb8, 0x20, 0x85, 0xd2, 0x2d, 0x8a, 0x5e, 0x0f, 0x6c, 0xe9, 0x9c, 0x26, 0x30, 0x37, 0xb1, + 0x15, 0xdc, 0x72, 0x80, 0x03, 0x85, 0xf3, 0xc3, 0x53, 0x64, 0x19, 0x45, 0x26, 0xc6, 0x2b, 0xbe, 0x35, 0x7f, 0x92, + 0x5b, 0x7c, 0x67, 0x7f, 0xdc, 0x05, 0xca, 0xa4, 0xe7, 0x35, 0x6d, 0x03, 0x77, 0x11, 0xd1, 0xa2, 0x24, 0x02, 0xb4, + 0x76, 0xe1, 0xfd, 0x44, 0xfd, 0xc5, 0x33, 0x65, 0x03, 0x31, 0x88, 0x06, 0x51, 0x58, 0x04, 0xa4, 0xf3, 0xcf, 0x3f, + 0x23, 0xd4, 0x13, 0x10, 0x47, 0xc7, 0x9d, 0x6c, 0xcd, 0x36, 0x6a, 0x44, 0x49, 0x94, 0xc6, 0x3e, 0x4c, 0x03, 0xec, + 0x8c, 0x28, 0x0a, 0x5e, 0x3b, 0x29, 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x33, 0xa8, 0x2a, 0xf0, 0xc4, 0xe5, 0x72, 0x33, + 0xcc, 0x8f, 0x81, 0xaa, 0x30, 0x31, 0x56, 0x90, 0x7d, 0x02, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0xfa, 0x62, 0x10, 0xbc, + 0xe9, 0x55, 0x5d, 0x87, 0xeb, 0x70, 0xe1, 0x62, 0x0a, 0x71, 0xd6, 0x57, 0x2b, 0xfb, 0x97, 0x7c, 0x30, 0xd2, 0x0c, + 0x3c, 0xce, 0x16, 0x9c, 0xb1, 0x62, 0xb7, 0x2c, 0x96, 0x68, 0xf9, 0x3b, 0x98, 0xed, 0xb9, 0xa8, 0x79, 0xdc, 0x4d, + 0xb5, 0xed, 0xa1, 0x3e, 0x37, 0x1a, 0x85, 0x20, 0x66, 0x6d, 0x75, 0xa4, 0xe1, 0xb9, 0x0e, 0xf3, 0x6a, 0xb1, 0x67, + 0x33, 0x55, 0x86, 0x10, 0x85, 0x23, 0x25, 0x01, 0xbb, 0x6d, 0x43, 0x27, 0xe1, 0x47, 0x9d, 0x4a, 0x3a, 0x16, 0x12, + 0xa0, 0xc0, 0x91, 0xb9, 0x9c, 0x37, 0x21, 0xe2, 0x19, 0xda, 0x41, 0xe4, 0x02, 0x13, 0x9a, 0xba, 0x6c, 0xe9, 0x62, + 0x39, 0x45, 0x33, 0xb9, 0x50, 0x6c, 0x31, 0x87, 0xf3, 0xbd, 0x4c, 0xcb, 0x72, 0x9e, 0x7d, 0xae, 0xa7, 0x80, 0xfd, + 0xe5, 0xad, 0x9e, 0x31, 0xb1, 0x88, 0xdc, 0x3c, 0xbf, 0x5a, 0x71, 0xff, 0xcd, 0x0b, 0xfc, 0x88, 0x74, 0x0e, 0xbf, + 0xe2, 0x8f, 0x94, 0x3c, 0x6a, 0x7c, 0xc5, 0x13, 0x4e, 0x2c, 0x6f, 0x90, 0xbc, 0x79, 0x7d, 0xf5, 0xe2, 0xdd, 0x8b, + 0xf7, 0x4f, 0xaf, 0x5f, 0xbc, 0x7a, 0xf6, 0xe2, 0xd5, 0x8b, 0x77, 0x1f, 0xf1, 0x3f, 0x94, 0x7c, 0x3d, 0x6a, 0x9f, + 0xb7, 0xf0, 0x07, 0xf2, 0xf5, 0xa8, 0x83, 0x6f, 0x35, 0xf9, 0x7a, 0x74, 0x82, 0x73, 0x45, 0xbe, 0x1e, 0x76, 0x8e, + 0x8e, 0xf1, 0x42, 0xdb, 0x26, 0x73, 0x39, 0x69, 0xb7, 0xf0, 0x3f, 0xee, 0x0b, 0xc4, 0xfb, 0x6a, 0x16, 0x13, 0xb6, + 0x61, 0xfc, 0x60, 0xca, 0xd0, 0xa1, 0x32, 0x86, 0x28, 0x17, 0x01, 0x3a, 0x4d, 0x55, 0x88, 0x4e, 0x36, 0x88, 0x31, + 0xd8, 0x30, 0x02, 0x5a, 0x71, 0xe2, 0xda, 0xe1, 0x47, 0x6d, 0x76, 0x0c, 0xf4, 0x89, 0x97, 0xc2, 0x71, 0xa9, 0xc2, + 0x69, 0x3b, 0x2d, 0xc6, 0x38, 0x97, 0xb2, 0x88, 0x17, 0xc0, 0x08, 0x18, 0xad, 0x05, 0x3f, 0x2a, 0xa3, 0x25, 0x89, + 0x0b, 0xd2, 0xee, 0xb5, 0x53, 0x71, 0x41, 0x3a, 0xbd, 0x0e, 0xfc, 0x39, 0xed, 0x9d, 0xa6, 0xed, 0x16, 0x3a, 0x0c, + 0xc6, 0xf1, 0x47, 0x0d, 0xad, 0xfb, 0x03, 0xec, 0xba, 0x50, 0xff, 0x14, 0xda, 0xab, 0xf4, 0x84, 0x53, 0xc7, 0xb6, + 0xbb, 0xe2, 0x82, 0x19, 0x3d, 0x2c, 0xff, 0x01, 0x50, 0xdb, 0x38, 0x74, 0x94, 0x1b, 0xc7, 0xfd, 0xe2, 0x47, 0x02, + 0xd5, 0x42, 0xb2, 0xc4, 0x6c, 0xd5, 0x42, 0xc0, 0x34, 0x9a, 0x6c, 0x30, 0x07, 0x4a, 0x94, 0x2c, 0xb4, 0x0f, 0x2b, + 0xaf, 0x9a, 0x12, 0x25, 0x73, 0x39, 0x8f, 0x6b, 0xaa, 0x86, 0x5f, 0x03, 0x33, 0xc7, 0x7d, 0xae, 0x5e, 0xd1, 0x57, + 0x71, 0x8d, 0xe7, 0x09, 0x59, 0xbb, 0x70, 0x5b, 0xfc, 0xe2, 0xac, 0x28, 0x6a, 0xe0, 0x2a, 0x01, 0xeb, 0x47, 0xd5, + 0xd4, 0x17, 0xf0, 0x7e, 0x1e, 0x6b, 0xe8, 0x4b, 0x12, 0x50, 0xcf, 0x9f, 0x4a, 0x33, 0xae, 0x52, 0x19, 0xed, 0x15, + 0xd1, 0xc6, 0x2c, 0xc8, 0x2b, 0xa2, 0x2f, 0x94, 0x01, 0x82, 0x24, 0xbc, 0x2f, 0x06, 0x70, 0xe0, 0xdb, 0x01, 0x4a, + 0x43, 0xe7, 0x40, 0xad, 0x54, 0x99, 0x09, 0x99, 0x4f, 0x13, 0x1c, 0x00, 0x34, 0x4f, 0x95, 0x0a, 0xca, 0x7c, 0x62, + 0x89, 0x82, 0xa1, 0xff, 0x16, 0x6e, 0x80, 0xc3, 0xd8, 0xa0, 0x62, 0x90, 0x7d, 0x4f, 0xd4, 0xf3, 0xdb, 0xe7, 0xad, + 0xa3, 0xaf, 0x41, 0xfe, 0x48, 0x79, 0x7b, 0x8f, 0xbf, 0x03, 0x4a, 0x6e, 0xc3, 0x59, 0xb5, 0xb1, 0x8f, 0x44, 0xd6, + 0x0d, 0x01, 0x72, 0xa8, 0xd1, 0x91, 0x79, 0x4a, 0xb0, 0x8b, 0xf4, 0x21, 0x69, 0xb7, 0x20, 0x7c, 0xd8, 0x0e, 0xca, + 0xf7, 0xd3, 0x06, 0x4c, 0x75, 0x72, 0xdb, 0x04, 0x5a, 0x0d, 0xaf, 0x0b, 0xdd, 0x35, 0x79, 0x72, 0x87, 0x55, 0x80, + 0x33, 0xec, 0x90, 0x35, 0xc4, 0xa1, 0x40, 0x2e, 0xec, 0xaa, 0xdd, 0x00, 0x9a, 0x8a, 0x8e, 0x7d, 0xe5, 0xce, 0x1b, + 0x47, 0x5d, 0x34, 0x93, 0xd3, 0xc3, 0xaf, 0x07, 0x07, 0xb1, 0x6c, 0x90, 0x47, 0x08, 0x2f, 0x29, 0x58, 0x31, 0x83, + 0xd7, 0x17, 0xb7, 0x4c, 0x7c, 0xaa, 0x02, 0xea, 0xb8, 0x50, 0xb5, 0x63, 0xad, 0xea, 0xac, 0xdc, 0x0d, 0x7e, 0x4c, + 0x1d, 0xd4, 0x08, 0xd2, 0xec, 0xe8, 0x3a, 0x35, 0x28, 0xd7, 0x5c, 0xb4, 0x60, 0x5b, 0x36, 0x3e, 0x52, 0xf4, 0xc3, + 0xa3, 0xe6, 0xd7, 0x60, 0xc2, 0x35, 0xd3, 0xa4, 0x47, 0x8d, 0x47, 0xe8, 0x87, 0x47, 0x81, 0x93, 0x1d, 0xaf, 0xd8, + 0x13, 0xcf, 0x8d, 0xfc, 0x64, 0xb9, 0xd2, 0x9f, 0x40, 0xb2, 0x2f, 0xc8, 0x4f, 0x80, 0xe5, 0x94, 0xfc, 0x14, 0xcb, + 0x26, 0x04, 0x1f, 0x24, 0x3f, 0xc5, 0x05, 0xfc, 0xc8, 0xc9, 0x4f, 0x31, 0x60, 0x3b, 0x9e, 0x9a, 0x1f, 0x45, 0x09, + 0x0c, 0x70, 0xec, 0x92, 0xd6, 0xbf, 0xab, 0x58, 0xad, 0xc4, 0xc1, 0x81, 0xb4, 0xbf, 0xe8, 0x65, 0x76, 0x70, 0x90, + 0x5f, 0x4c, 0xab, 0xbe, 0x99, 0xde, 0x45, 0x5f, 0x0c, 0x42, 0xe1, 0xc0, 0x34, 0x8d, 0x87, 0x33, 0xfe, 0x14, 0x52, + 0x56, 0xd3, 0x40, 0xf3, 0xb8, 0x73, 0xff, 0xec, 0x1c, 0xc3, 0xbf, 0xf7, 0x83, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, + 0xb3, 0xe6, 0x59, 0x85, 0x6c, 0x97, 0x01, 0x3e, 0x63, 0x86, 0x9a, 0xe2, 0xe0, 0x80, 0x5f, 0x04, 0xb8, 0x8c, 0x19, + 0x6a, 0x04, 0x16, 0x7b, 0x0f, 0x4b, 0x7b, 0x32, 0xc3, 0x35, 0xc1, 0xb3, 0xb2, 0xbc, 0x5f, 0x0c, 0x2e, 0xb4, 0xa3, + 0x26, 0x61, 0xf0, 0x69, 0x45, 0x5a, 0x6e, 0x93, 0x75, 0x45, 0x53, 0x5d, 0xb6, 0xbb, 0x48, 0x12, 0xd5, 0x10, 0x97, + 0x97, 0x6d, 0x0c, 0x2a, 0xf9, 0x9e, 0x22, 0x32, 0x15, 0xc4, 0x3b, 0xc8, 0x2d, 0x73, 0x99, 0x2a, 0x3c, 0xe5, 0xa9, + 0xf0, 0x72, 0xf6, 0x6b, 0x6f, 0x3d, 0x6d, 0x5c, 0x16, 0x4d, 0xcf, 0x0c, 0x8b, 0x9e, 0x2a, 0x5d, 0xed, 0x60, 0x93, + 0xaa, 0x01, 0xbc, 0xda, 0x57, 0x62, 0x1e, 0xb3, 0xfe, 0x65, 0x0c, 0xa2, 0x22, 0xab, 0x46, 0x1b, 0x32, 0xe1, 0x73, + 0x9d, 0x2a, 0x18, 0xa8, 0x29, 0x7c, 0x01, 0x64, 0x2a, 0xab, 0x0c, 0xb3, 0x7d, 0xc3, 0x50, 0x40, 0x40, 0x81, 0x4b, + 0xc2, 0x02, 0x09, 0x1e, 0x6e, 0x3f, 0x02, 0xc2, 0x51, 0x27, 0x17, 0x76, 0x72, 0x17, 0x0a, 0xba, 0x13, 0x83, 0x0b, + 0xdd, 0x45, 0xa2, 0xd1, 0x70, 0xdc, 0xf6, 0xa5, 0x30, 0x83, 0x68, 0xb6, 0x07, 0x97, 0xac, 0x8b, 0x54, 0xb3, 0x59, + 0x1a, 0x40, 0x5e, 0xb6, 0x56, 0x2b, 0x75, 0xe1, 0x1b, 0xe9, 0xf9, 0x73, 0xdc, 0xf0, 0x5d, 0x5e, 0xf0, 0xfc, 0x4d, + 0x92, 0x7e, 0x04, 0x54, 0x15, 0xf8, 0x6c, 0x39, 0x8f, 0x70, 0x64, 0x1e, 0x74, 0x83, 0xbf, 0xe6, 0x21, 0xae, 0x08, + 0x47, 0xee, 0x8d, 0xb7, 0x68, 0x50, 0x0d, 0x96, 0x67, 0x65, 0x78, 0x72, 0x9e, 0x5c, 0x03, 0xe3, 0xa0, 0xff, 0x56, + 0x68, 0x59, 0xfd, 0x4e, 0x72, 0x17, 0xa8, 0x43, 0xf9, 0x67, 0xc7, 0xdc, 0xa8, 0xd6, 0xbb, 0x5d, 0x23, 0x39, 0x8e, + 0x7c, 0x55, 0x08, 0xdf, 0xff, 0x9d, 0x77, 0x0f, 0xdb, 0xee, 0xb9, 0xed, 0x65, 0xd9, 0x03, 0x70, 0xde, 0xeb, 0x35, + 0xc2, 0xbf, 0xc9, 0x9d, 0x6f, 0xef, 0x46, 0xd7, 0x52, 0x3c, 0xa1, 0x9a, 0x46, 0x8d, 0x37, 0xc6, 0xf0, 0xcd, 0xca, + 0x59, 0xdd, 0x6f, 0x8d, 0x83, 0xfd, 0x5b, 0xdd, 0x43, 0xe8, 0x84, 0xda, 0x33, 0x41, 0x56, 0xf6, 0x35, 0x01, 0x33, + 0x64, 0x60, 0xfa, 0xb6, 0x03, 0x1e, 0x7e, 0x8c, 0x14, 0x1c, 0x7a, 0x2d, 0x9f, 0x44, 0x21, 0x26, 0x69, 0xcd, 0x8d, + 0x18, 0x52, 0x6c, 0x1f, 0xc6, 0xe5, 0x74, 0x8d, 0x42, 0xae, 0x7b, 0xac, 0xea, 0xc4, 0xb4, 0xea, 0xc6, 0x48, 0x1d, + 0x6c, 0x93, 0x05, 0x67, 0x55, 0xef, 0x46, 0x42, 0xa9, 0x5e, 0x54, 0x33, 0xaf, 0x62, 0x36, 0xdb, 0xe6, 0x99, 0x61, + 0xfb, 0xee, 0x9a, 0x02, 0x43, 0xde, 0xfd, 0x32, 0x5c, 0xd4, 0x25, 0x1c, 0xbb, 0x71, 0x00, 0x59, 0x49, 0x2e, 0x97, + 0xee, 0x4d, 0x34, 0xde, 0x97, 0x83, 0x75, 0xf9, 0x42, 0x5a, 0x80, 0x07, 0xd5, 0x48, 0x45, 0x16, 0x72, 0x06, 0xfe, + 0x79, 0xc1, 0x9a, 0x7e, 0x88, 0x7f, 0x85, 0x03, 0xbe, 0x42, 0xd2, 0xd4, 0xaa, 0x9f, 0xe0, 0xe5, 0x22, 0x50, 0x78, + 0xdb, 0xba, 0x9f, 0x64, 0xe8, 0x22, 0x5a, 0xd7, 0xa9, 0x58, 0x2f, 0xcc, 0xba, 0x62, 0xa5, 0x2c, 0x1c, 0x1c, 0x77, + 0x31, 0x5a, 0xa7, 0xce, 0x63, 0xd3, 0x3d, 0x77, 0xf4, 0x50, 0xf0, 0x99, 0x71, 0xa4, 0x7b, 0x56, 0x40, 0xfc, 0xaa, + 0x50, 0x9f, 0xf6, 0xb3, 0x0c, 0xdf, 0xf3, 0xed, 0xc3, 0x3d, 0x61, 0xc9, 0x73, 0x96, 0x6f, 0x50, 0xc3, 0x02, 0x29, + 0xa0, 0x50, 0x0a, 0x8b, 0xd5, 0x2a, 0x16, 0x26, 0xaa, 0x81, 0x0b, 0x6a, 0xeb, 0x5e, 0xaf, 0x30, 0xfa, 0x3b, 0xa8, + 0x8b, 0xbd, 0x7a, 0xc4, 0x98, 0xb0, 0xa2, 0xf0, 0xd2, 0x49, 0x65, 0x41, 0x5f, 0xbb, 0xfa, 0x10, 0xd5, 0x94, 0x7b, + 0xb1, 0xd1, 0xf7, 0xbe, 0xe3, 0x33, 0x26, 0x17, 0xf0, 0x6c, 0x10, 0x66, 0x44, 0x31, 0xed, 0xbf, 0x81, 0x82, 0xc0, + 0xdb, 0x33, 0x3c, 0xc4, 0x47, 0xe0, 0xab, 0x3c, 0xad, 0x93, 0x99, 0x7f, 0x8c, 0x22, 0x32, 0xc1, 0x22, 0xa3, 0x5e, + 0x04, 0x5e, 0x43, 0x20, 0x42, 0x11, 0x12, 0x31, 0x31, 0x8a, 0x7a, 0x91, 0x71, 0x52, 0x8a, 0xc0, 0x6a, 0x0c, 0x94, + 0xdc, 0x11, 0x9e, 0xab, 0x8a, 0x88, 0x85, 0x35, 0x75, 0x50, 0x89, 0xa5, 0xc6, 0x4c, 0xfb, 0xa8, 0x53, 0x81, 0xb0, + 0xc8, 0x36, 0x05, 0x65, 0xbd, 0xa1, 0x2e, 0xc0, 0x92, 0x18, 0xd3, 0x5b, 0x9e, 0x5c, 0x03, 0x37, 0xc7, 0x46, 0xae, + 0xe8, 0x92, 0x5f, 0x81, 0x7a, 0x3a, 0x2d, 0xf0, 0xb5, 0x61, 0xd8, 0x46, 0x29, 0x5d, 0x13, 0x8e, 0x33, 0x52, 0x24, + 0xf4, 0x16, 0xa2, 0x3a, 0xcc, 0xb8, 0x48, 0x73, 0x3c, 0xa3, 0xb7, 0xe9, 0x14, 0xcf, 0xb8, 0x78, 0x62, 0x97, 0x3d, + 0x1d, 0x41, 0x92, 0xff, 0x58, 0xac, 0x89, 0x79, 0x94, 0xea, 0x77, 0xc5, 0x8a, 0x47, 0xc0, 0xab, 0xa8, 0x18, 0x75, + 0x47, 0xc6, 0xa6, 0x9c, 0xe9, 0xca, 0x78, 0xfd, 0xb5, 0x8e, 0x29, 0xce, 0x70, 0x8e, 0x92, 0x5c, 0x62, 0xd6, 0x13, + 0xe9, 0x6b, 0x88, 0xe8, 0x9c, 0x61, 0xfb, 0xa0, 0x15, 0xbf, 0x65, 0xf9, 0x33, 0x59, 0xbc, 0x37, 0x5b, 0x3e, 0x47, + 0x50, 0x08, 0x5c, 0x54, 0x44, 0x13, 0x6e, 0xf7, 0x16, 0x3d, 0x59, 0x35, 0x45, 0x6f, 0x6d, 0x53, 0x6e, 0x88, 0x53, + 0x08, 0x85, 0x9b, 0x4c, 0x79, 0xa3, 0x8d, 0x59, 0xaf, 0xf5, 0x9d, 0x46, 0xa7, 0xa8, 0x2c, 0x89, 0x30, 0xac, 0x55, + 0x53, 0xa5, 0x92, 0x88, 0xa6, 0x72, 0x12, 0xde, 0xd2, 0x00, 0x3b, 0x55, 0x38, 0x93, 0x0b, 0xa1, 0x53, 0x19, 0xe0, + 0x0d, 0xad, 0x36, 0xd7, 0xf2, 0xd6, 0x42, 0x4c, 0xe3, 0x3b, 0xfb, 0x83, 0xe1, 0x6b, 0xa3, 0xe2, 0x7f, 0x0b, 0x86, + 0x3d, 0x2a, 0x15, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x59, 0x7e, 0xf2, 0x16, 0xc0, 0x67, 0x59, 0xc8, 0x3b, 0x48, + 0x65, 0x26, 0xf5, 0x0e, 0x52, 0x19, 0xa4, 0x1a, 0x5f, 0xee, 0x7d, 0x51, 0x29, 0x8b, 0xc2, 0x06, 0x89, 0xc2, 0xa5, + 0x3a, 0x58, 0x12, 0x91, 0x40, 0xbb, 0x46, 0x94, 0x9b, 0x71, 0x01, 0x41, 0xfd, 0xa0, 0x71, 0xfb, 0x4d, 0x6f, 0xe1, + 0xfb, 0xce, 0xe6, 0x33, 0x9f, 0x7f, 0x67, 0xf3, 0x4d, 0x47, 0x1e, 0xe3, 0xeb, 0xb7, 0x9d, 0xc6, 0x32, 0x5e, 0x3a, + 0xac, 0xfd, 0x50, 0x3e, 0xa1, 0xd2, 0x32, 0x4f, 0x55, 0x93, 0x36, 0x9e, 0x04, 0x48, 0xd9, 0xac, 0x78, 0xb8, 0x0e, + 0x6e, 0xb7, 0x0e, 0x63, 0xde, 0x24, 0x6d, 0x84, 0x0e, 0x9d, 0x70, 0x25, 0x62, 0x23, 0x39, 0x1d, 0x3e, 0x3a, 0x82, + 0xbb, 0x97, 0x99, 0xda, 0xf0, 0x95, 0xb2, 0xd5, 0x9a, 0xed, 0xd6, 0x21, 0xdf, 0x59, 0xa5, 0xd1, 0xc6, 0x33, 0x46, + 0x96, 0xe0, 0x5c, 0x46, 0x0b, 0xab, 0x6a, 0x00, 0x27, 0xce, 0x17, 0xe2, 0xb7, 0x05, 0x1d, 0x99, 0xef, 0x43, 0x9b, + 0xf2, 0x7a, 0xa1, 0x7d, 0x52, 0x93, 0xc3, 0x20, 0x3a, 0xc8, 0x95, 0x0c, 0x72, 0x62, 0x7e, 0x44, 0x92, 0x53, 0x74, + 0xd1, 0xee, 0x25, 0xa7, 0x87, 0xfc, 0x90, 0xa7, 0xc0, 0xc3, 0xc6, 0x4d, 0x5f, 0xa1, 0xd9, 0xf6, 0x75, 0x1e, 0x2f, + 0x86, 0x3c, 0x73, 0xcd, 0x57, 0x1d, 0x94, 0xa9, 0x76, 0x8e, 0x90, 0x05, 0x28, 0xe6, 0x7b, 0x09, 0xb2, 0xeb, 0xdd, + 0x1c, 0xf2, 0x14, 0xfa, 0x81, 0x5a, 0x1d, 0x5b, 0xab, 0x1c, 0xdc, 0x6f, 0x0b, 0x40, 0x30, 0xdf, 0x51, 0x6d, 0x2e, + 0x36, 0xbd, 0x19, 0x57, 0x9d, 0x1d, 0xf2, 0x6a, 0x84, 0x61, 0x99, 0xed, 0xfe, 0xfc, 0xd4, 0xaa, 0x2e, 0x0f, 0x03, + 0x88, 0xfc, 0xb6, 0xe0, 0x22, 0xec, 0x34, 0xec, 0xd6, 0xe5, 0x84, 0x9d, 0xd6, 0x67, 0x19, 0x14, 0xd9, 0xee, 0x75, + 0x6b, 0xa6, 0xf5, 0xd9, 0x5e, 0x81, 0x8f, 0x20, 0x4c, 0xca, 0xac, 0x74, 0x06, 0x57, 0xe8, 0x87, 0x1f, 0x90, 0x6b, + 0xfd, 0xf5, 0x42, 0xfb, 0xfc, 0x12, 0x11, 0x20, 0xbb, 0xea, 0xba, 0xac, 0x0e, 0x7d, 0x94, 0x4d, 0x7c, 0x3d, 0xe4, + 0xc1, 0xca, 0x3d, 0xbd, 0x9d, 0xcb, 0xd4, 0xe3, 0x6b, 0xaf, 0x95, 0x6e, 0x21, 0x27, 0x10, 0x0f, 0xd7, 0x5d, 0x58, + 0x16, 0xe4, 0xec, 0xe6, 0x16, 0x4a, 0x86, 0x13, 0xf7, 0xa5, 0x3f, 0x30, 0x7b, 0xdd, 0xc0, 0x2f, 0x92, 0x53, 0x98, + 0xfa, 0x66, 0x0f, 0x87, 0x1d, 0xe8, 0xc3, 0xc0, 0x61, 0xb3, 0x41, 0x9f, 0x59, 0x41, 0xe4, 0x31, 0x2f, 0x2c, 0x9e, + 0x5d, 0x92, 0x76, 0x8f, 0xa7, 0x6e, 0x33, 0x19, 0xd1, 0xa8, 0xdd, 0xe4, 0xc1, 0xcc, 0x00, 0xbf, 0x5c, 0xd9, 0xb0, + 0x88, 0x5f, 0xa7, 0x00, 0x4a, 0xbe, 0x58, 0xb5, 0x3e, 0x15, 0xbc, 0xea, 0x0d, 0xa7, 0x9b, 0xe9, 0x7e, 0xdd, 0xe0, + 0x76, 0xd7, 0xc3, 0x13, 0x9e, 0x40, 0xb1, 0x68, 0xed, 0x27, 0x3e, 0x01, 0x0e, 0x28, 0x69, 0xdd, 0x3f, 0x05, 0x17, + 0xca, 0x12, 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x2c, 0x1c, 0x6d, 0xc9, 0x80, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, + 0xd8, 0xc1, 0x49, 0xbb, 0xdd, 0x39, 0xc5, 0xc9, 0xc9, 0x29, 0x0c, 0xb4, 0x91, 0x9c, 0x1e, 0xce, 0x94, 0x05, 0x60, + 0x90, 0xb3, 0x76, 0xed, 0x3e, 0x82, 0x70, 0x49, 0xa1, 0x78, 0xcd, 0x0f, 0xe3, 0xb8, 0x9d, 0xdc, 0x6f, 0xb5, 0x4f, + 0xcf, 0x1b, 0x00, 0xa0, 0xa6, 0xfb, 0x70, 0x35, 0x5e, 0x2f, 0x74, 0xbd, 0x4a, 0x89, 0xf0, 0xf5, 0x6a, 0x0d, 0x5f, + 0xad, 0xd1, 0x5e, 0x57, 0x53, 0xf0, 0x55, 0x9d, 0x70, 0x6e, 0x8b, 0x78, 0xa5, 0x4d, 0xb8, 0x2d, 0x62, 0x3b, 0x90, + 0x18, 0xa4, 0xf3, 0xe4, 0xb4, 0x73, 0x8a, 0xec, 0x58, 0xb4, 0xc3, 0x8f, 0x72, 0x9f, 0x6c, 0x15, 0x69, 0x68, 0x40, + 0x92, 0x72, 0x76, 0x72, 0x01, 0x12, 0x35, 0x27, 0x97, 0xed, 0xe6, 0x8c, 0x25, 0x7e, 0x02, 0x26, 0x15, 0x96, 0xb3, + 0x5c, 0x05, 0x97, 0x14, 0x00, 0xe2, 0x02, 0x8c, 0x8b, 0xee, 0x9f, 0xf6, 0xee, 0x27, 0xa7, 0x67, 0x1d, 0x4b, 0xf4, + 0xf8, 0x45, 0xa7, 0x96, 0x66, 0xa6, 0x9e, 0x9c, 0x9a, 0x34, 0xe8, 0x3a, 0xb9, 0x7f, 0x0a, 0x65, 0x5c, 0x4a, 0x58, + 0x0a, 0xc2, 0x3c, 0x54, 0xc5, 0x20, 0xb6, 0x43, 0x5a, 0xcb, 0x3d, 0xab, 0x65, 0x9f, 0x9f, 0x1c, 0xdf, 0x3f, 0x0d, + 0xa1, 0x56, 0xce, 0xc2, 0x2c, 0xb4, 0x9b, 0x88, 0x9f, 0x1d, 0x2c, 0x2d, 0x3a, 0x4c, 0x4e, 0xd3, 0xad, 0x09, 0xda, + 0x4d, 0x73, 0x68, 0x70, 0x20, 0x50, 0x38, 0x3e, 0x15, 0x4e, 0x5f, 0x12, 0xdc, 0x8f, 0x55, 0x86, 0x26, 0xa1, 0xc2, + 0xd9, 0xdf, 0x53, 0x06, 0x2f, 0x39, 0x86, 0x57, 0x95, 0x8f, 0xa9, 0xf8, 0x42, 0xd5, 0x1b, 0x0a, 0xb1, 0x2b, 0xc4, + 0x20, 0x72, 0x91, 0xb5, 0xeb, 0xb9, 0x3f, 0x81, 0x8b, 0x30, 0x13, 0x70, 0xa1, 0xe9, 0x95, 0xa0, 0x15, 0x2f, 0x30, + 0x0c, 0x1d, 0x6a, 0xcd, 0xb0, 0x7a, 0x3c, 0x75, 0x26, 0x05, 0xa1, 0x6e, 0xeb, 0x39, 0xff, 0x5e, 0xb9, 0xa4, 0xbc, + 0xca, 0x4e, 0x4e, 0x51, 0xe2, 0x2e, 0xcb, 0x93, 0x36, 0x4a, 0x02, 0x13, 0x12, 0x77, 0x24, 0x67, 0x19, 0xe9, 0x47, + 0xb7, 0x11, 0x8e, 0xee, 0x22, 0x1c, 0x59, 0x1f, 0xe6, 0x0f, 0xe0, 0x3c, 0x1f, 0xe1, 0xc8, 0xba, 0x32, 0x47, 0x38, + 0xd2, 0x4c, 0x40, 0x48, 0xab, 0x68, 0x80, 0x73, 0x28, 0x6d, 0x3c, 0xab, 0xcb, 0xd2, 0x8f, 0xfd, 0x57, 0xe9, 0x7a, + 0x6d, 0x53, 0x02, 0x29, 0x73, 0x6a, 0x76, 0xa8, 0x7d, 0x92, 0x39, 0xa2, 0x9e, 0x59, 0x8f, 0x30, 0x08, 0x20, 0xf4, + 0xce, 0x3f, 0xe9, 0x56, 0x45, 0xc3, 0x60, 0xc7, 0xb0, 0xd2, 0xe0, 0x67, 0x1e, 0x85, 0x67, 0x58, 0x84, 0xc7, 0xc2, + 0x17, 0x06, 0xb1, 0xc2, 0xff, 0xce, 0xa5, 0x9c, 0xfb, 0xdf, 0x5a, 0x96, 0xbf, 0xe0, 0x21, 0x10, 0x67, 0xd1, 0x02, + 0x96, 0x5b, 0x36, 0xf8, 0xce, 0x90, 0xd5, 0x47, 0x70, 0x3d, 0x76, 0x01, 0xd2, 0x40, 0x22, 0xbc, 0x36, 0x02, 0x95, + 0x97, 0x0f, 0xaf, 0x6d, 0xb0, 0x1e, 0xf3, 0x09, 0xd1, 0xba, 0x20, 0x20, 0xaf, 0x84, 0x0b, 0x8d, 0x49, 0xc1, 0x94, + 0x8a, 0x6c, 0x14, 0xbb, 0x48, 0x0a, 0xff, 0x2c, 0xa1, 0x4f, 0x19, 0x8b, 0xc8, 0x74, 0x58, 0x9f, 0xad, 0x15, 0x87, + 0x73, 0x59, 0xa8, 0xd4, 0xbe, 0x51, 0xe2, 0xc1, 0x58, 0x3d, 0x55, 0x9f, 0xe6, 0xd9, 0x1a, 0xdb, 0x3b, 0xec, 0xb2, + 0x90, 0xbb, 0xd2, 0x0e, 0x4b, 0x65, 0xd9, 0xfa, 0x5b, 0x13, 0x52, 0xb5, 0x19, 0x05, 0x13, 0xad, 0x06, 0x54, 0x85, + 0xb2, 0x80, 0xc2, 0x36, 0x1c, 0x4a, 0xba, 0x2c, 0x4b, 0xa6, 0xcb, 0x72, 0x19, 0x4e, 0x5a, 0xad, 0xf5, 0x1a, 0x17, + 0xcc, 0x84, 0x65, 0xd9, 0x59, 0x02, 0xf2, 0xd5, 0x54, 0xde, 0x04, 0xb9, 0x2a, 0x2d, 0x67, 0x69, 0x96, 0x28, 0x0a, + 0x8c, 0x60, 0xa3, 0x35, 0xfe, 0xc2, 0x15, 0x07, 0x78, 0xba, 0xd9, 0x0d, 0xa5, 0xcc, 0x19, 0x85, 0xe8, 0x5d, 0x41, + 0x93, 0x6b, 0x3c, 0xe5, 0x23, 0xb6, 0xbb, 0x4d, 0x30, 0x63, 0xfe, 0xf7, 0x5a, 0xf4, 0x08, 0x64, 0xd9, 0x3d, 0x83, + 0x3a, 0xb0, 0x88, 0x2b, 0xe8, 0x20, 0x94, 0xc1, 0x47, 0x21, 0x6e, 0xe6, 0xf4, 0x4e, 0x2e, 0x34, 0xc0, 0x65, 0xa1, + 0xe5, 0x1b, 0x17, 0xeb, 0x60, 0xbf, 0x85, 0x7d, 0xd8, 0x83, 0x25, 0x84, 0x0c, 0x68, 0x61, 0x1b, 0x23, 0xa2, 0x85, + 0x87, 0x52, 0x6b, 0x39, 0x4b, 0x5b, 0xd8, 0x04, 0x6c, 0x68, 0xad, 0xcb, 0xa8, 0x5a, 0xd7, 0xe5, 0x63, 0x8e, 0xd5, + 0x26, 0x58, 0x38, 0xe9, 0x50, 0x13, 0x1d, 0xdc, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbd, 0x7e, 0xe5, 0x62, 0x26, + 0xf3, 0x31, 0xb8, 0x6c, 0x3a, 0xd5, 0xd8, 0xb5, 0x79, 0x05, 0x29, 0xae, 0x14, 0xa5, 0x56, 0x38, 0x85, 0x96, 0x5f, + 0x08, 0x9d, 0x27, 0xf6, 0xf2, 0xe2, 0x99, 0x2c, 0x66, 0xd4, 0xde, 0x18, 0xe1, 0x6b, 0xe5, 0x9e, 0x3d, 0x37, 0x2f, + 0xab, 0x54, 0x93, 0x7c, 0xb7, 0x79, 0x15, 0xb1, 0xc8, 0x8c, 0xfc, 0x0a, 0xda, 0x00, 0x53, 0xb9, 0x7c, 0xb5, 0xb6, + 0x20, 0x2e, 0xf2, 0x7c, 0x40, 0x5e, 0xde, 0x5a, 0xea, 0x12, 0x45, 0x0d, 0x6e, 0xf0, 0x93, 0x15, 0x3c, 0x0b, 0xae, + 0x0b, 0x0d, 0x7b, 0xe4, 0xc4, 0x8b, 0xa8, 0x15, 0xd5, 0x5f, 0x7d, 0x35, 0xaa, 0x04, 0x1f, 0xb5, 0x34, 0xc9, 0x25, + 0x88, 0x1e, 0xe5, 0x03, 0x73, 0x1c, 0x44, 0x13, 0x7f, 0xf7, 0x7c, 0xd9, 0xf6, 0x74, 0x36, 0xaf, 0xd4, 0x89, 0xe5, + 0x95, 0x09, 0x78, 0x38, 0xda, 0x27, 0x5c, 0x10, 0x0e, 0x12, 0x59, 0xa9, 0x3d, 0xf4, 0xb9, 0xa8, 0x1b, 0xe7, 0x17, + 0x6d, 0xd6, 0x3c, 0x59, 0xad, 0xf2, 0xcb, 0x36, 0x6b, 0x9f, 0xda, 0x07, 0xdf, 0x22, 0x95, 0x01, 0xcd, 0xe5, 0x63, + 0x9e, 0x45, 0xa0, 0x9d, 0x1d, 0x67, 0x26, 0x9c, 0x82, 0x0f, 0x51, 0x4c, 0x16, 0xba, 0xea, 0x4b, 0x82, 0x71, 0x29, + 0xb1, 0x7a, 0xfc, 0x02, 0xf5, 0xda, 0xe9, 0xb6, 0xab, 0x74, 0xb3, 0x7d, 0x18, 0x5c, 0xb8, 0x14, 0x08, 0x77, 0x20, + 0xe4, 0x01, 0xe8, 0x77, 0x97, 0x02, 0x4c, 0x83, 0x00, 0x95, 0x15, 0x88, 0xb4, 0x7c, 0xb6, 0x98, 0x3d, 0x2b, 0xa8, + 0x59, 0x86, 0x27, 0x7c, 0xc2, 0xb5, 0x4a, 0x29, 0x48, 0xb7, 0xbb, 0xd2, 0xd7, 0xbb, 0x25, 0xa8, 0xac, 0x16, 0xf9, + 0x35, 0xd1, 0x3c, 0xfb, 0xac, 0xdc, 0xc2, 0x21, 0x6c, 0x56, 0x56, 0xe0, 0x0c, 0xad, 0x71, 0x2e, 0x27, 0xb4, 0xe0, + 0x7a, 0x3a, 0xfb, 0xb7, 0x56, 0x87, 0xf5, 0xf5, 0xc0, 0x5c, 0x58, 0x01, 0x48, 0xa8, 0x18, 0xad, 0x56, 0xfc, 0xe8, + 0xfb, 0xf7, 0x49, 0xde, 0x27, 0xbc, 0x8d, 0x3b, 0xf8, 0x18, 0x9f, 0xe2, 0x76, 0x0b, 0xb7, 0x4f, 0xe1, 0xea, 0x3e, + 0xcb, 0x17, 0x23, 0xa6, 0x62, 0x78, 0xf9, 0x4b, 0x5f, 0x26, 0xe7, 0x87, 0x65, 0xbc, 0x7b, 0x5d, 0x24, 0x0e, 0x5d, + 0x82, 0xb0, 0xeb, 0x2e, 0x5e, 0x5d, 0x14, 0x85, 0xc1, 0xd2, 0xc6, 0xa1, 0xea, 0xa4, 0xd4, 0x2f, 0x5c, 0x1e, 0xf7, + 0xc0, 0x9e, 0xdb, 0xae, 0x6c, 0x13, 0xcc, 0xbe, 0xed, 0xcf, 0xb4, 0xfa, 0xd9, 0xd4, 0x25, 0x62, 0x78, 0xe8, 0x55, + 0xe8, 0x81, 0x2e, 0x49, 0xfb, 0xe0, 0x00, 0xac, 0x8e, 0x82, 0xd9, 0x70, 0x1b, 0xfd, 0x80, 0x37, 0x6b, 0x69, 0x10, + 0xac, 0x00, 0x8c, 0x3b, 0xdf, 0x70, 0xb2, 0xb4, 0xb0, 0xd5, 0x40, 0x85, 0x75, 0x11, 0x46, 0x74, 0x0b, 0x49, 0x85, + 0x11, 0xa2, 0xe1, 0x08, 0x73, 0x91, 0x4e, 0xf6, 0x5b, 0x58, 0x8e, 0xc7, 0x8a, 0x69, 0x38, 0x3a, 0x0a, 0xf6, 0x85, + 0x15, 0xca, 0x9c, 0x22, 0x43, 0x36, 0xe1, 0xe2, 0xa1, 0xfe, 0xc4, 0x0a, 0x69, 0x3e, 0x8d, 0x06, 0x23, 0x8d, 0xcc, + 0x2a, 0x46, 0x38, 0xcb, 0xf9, 0x1c, 0xaa, 0x4e, 0x0a, 0x70, 0xfa, 0x81, 0xbf, 0x7c, 0x94, 0x86, 0x6d, 0x02, 0xf9, + 0xfa, 0x60, 0x83, 0xd9, 0xe0, 0x51, 0x41, 0x6f, 0x5e, 0x8b, 0xc7, 0xb0, 0xa3, 0x1e, 0x16, 0x8c, 0x42, 0x36, 0x24, + 0xbd, 0x83, 0xa6, 0xe0, 0x03, 0xda, 0x7c, 0x69, 0x00, 0x97, 0x9e, 0x9b, 0x0f, 0x5b, 0xd1, 0x47, 0x0d, 0x4c, 0xca, + 0xb6, 0x4c, 0xa6, 0x39, 0xa5, 0xab, 0x4c, 0x1b, 0x97, 0xa9, 0x9c, 0xc2, 0x1a, 0xbb, 0xa8, 0x27, 0xe1, 0x60, 0x46, + 0x54, 0x4d, 0xd3, 0xfe, 0xc0, 0xfc, 0x7d, 0x6d, 0x4b, 0xb6, 0xb0, 0x0b, 0xb5, 0xb3, 0xc6, 0xe6, 0xc9, 0xce, 0xa0, + 0x7c, 0x1b, 0xc3, 0x3d, 0x2c, 0xbc, 0x1b, 0x59, 0x23, 0x9f, 0x27, 0x9e, 0x6c, 0x9e, 0xac, 0xd7, 0x66, 0x20, 0x2a, + 0x05, 0x3d, 0xd0, 0x5b, 0xbf, 0x6d, 0x5a, 0xb0, 0x3d, 0xca, 0xaf, 0xd3, 0x16, 0x9e, 0x71, 0x78, 0x06, 0xd3, 0xb7, + 0x77, 0xa5, 0x0b, 0xf9, 0xd9, 0x81, 0xa4, 0x15, 0xa4, 0xd8, 0xe9, 0x04, 0x9d, 0x1d, 0xe3, 0x60, 0xe4, 0x40, 0xcf, + 0xaf, 0x3e, 0x5b, 0x58, 0xfb, 0xdf, 0x6f, 0xca, 0x82, 0x39, 0x1d, 0xb2, 0xbc, 0x9c, 0x50, 0xe6, 0xcf, 0xcf, 0x37, + 0x3c, 0xa9, 0x50, 0xc1, 0xbd, 0x1f, 0x05, 0x7b, 0xda, 0x86, 0x98, 0x9c, 0xd1, 0xbf, 0xed, 0x0f, 0x1b, 0x11, 0xa8, + 0xd4, 0xb2, 0x65, 0x85, 0x54, 0xea, 0xa1, 0x4d, 0xb3, 0x47, 0x0f, 0x1c, 0x91, 0x2f, 0xa1, 0x0b, 0xe0, 0xf5, 0x47, + 0x85, 0x9c, 0x1b, 0x44, 0x70, 0xbf, 0xdd, 0xb8, 0x8d, 0xaf, 0x00, 0x78, 0x3b, 0xec, 0x55, 0xff, 0xb4, 0x80, 0xfd, + 0x8d, 0xca, 0x92, 0x7e, 0xbc, 0x1d, 0x7b, 0xfc, 0x17, 0x12, 0xe2, 0x95, 0x5b, 0x3c, 0x4c, 0x1c, 0x3a, 0x95, 0xac, + 0x59, 0xf9, 0x73, 0xab, 0x24, 0x60, 0x58, 0xbd, 0x60, 0xc8, 0xc6, 0x6d, 0x15, 0xb7, 0x99, 0xff, 0x41, 0x05, 0x83, + 0x05, 0xdf, 0x1a, 0x49, 0xc5, 0xb2, 0xf8, 0xed, 0x53, 0xe7, 0xbf, 0xea, 0x1c, 0xd7, 0xbe, 0xae, 0xbd, 0x51, 0x39, + 0x34, 0xf1, 0x81, 0x23, 0x74, 0x70, 0xb0, 0x91, 0x41, 0xc7, 0x00, 0x78, 0xe4, 0xd8, 0x2f, 0xbf, 0x7c, 0x9e, 0x1d, + 0x33, 0x9a, 0xc7, 0x22, 0x0a, 0x99, 0x3b, 0xcf, 0xcd, 0xd9, 0x89, 0x3c, 0xa1, 0x6a, 0xea, 0x0b, 0x03, 0x1c, 0x1f, + 0x6d, 0xa5, 0x02, 0xbe, 0x47, 0xeb, 0x1d, 0x13, 0xd8, 0xe0, 0xb7, 0xec, 0xa4, 0x76, 0x15, 0xf4, 0x0b, 0xb4, 0xdc, + 0xc5, 0x54, 0x6e, 0x2c, 0x70, 0xb4, 0x39, 0x91, 0x9d, 0x43, 0xdf, 0xa8, 0x53, 0xb2, 0x1e, 0x4f, 0x76, 0x1b, 0x7d, + 0x49, 0xb1, 0x2b, 0xb9, 0xa2, 0x6d, 0x43, 0x56, 0xbd, 0x53, 0xab, 0x2b, 0x53, 0xa7, 0xea, 0x9a, 0xb7, 0xb2, 0xb4, + 0x29, 0xed, 0x92, 0xec, 0xdd, 0x16, 0x0b, 0xaf, 0xc2, 0x1b, 0x8d, 0xf2, 0x22, 0x14, 0xec, 0xb1, 0xc4, 0xa0, 0xcb, + 0x09, 0x5c, 0x2f, 0xac, 0x56, 0x31, 0xfc, 0xd9, 0x35, 0x86, 0x5d, 0xa6, 0x4b, 0x1f, 0xf8, 0x06, 0xbf, 0x12, 0x84, + 0xca, 0x75, 0x76, 0x90, 0x60, 0xdd, 0xe5, 0x06, 0x0d, 0xc7, 0x89, 0xff, 0x82, 0x87, 0x9a, 0xb5, 0x77, 0x39, 0x98, + 0x64, 0xdf, 0x78, 0xdc, 0xad, 0x64, 0x2d, 0x6b, 0x71, 0xd6, 0x37, 0x24, 0x18, 0x62, 0x37, 0xa5, 0x73, 0xdc, 0x4a, + 0xda, 0x28, 0x72, 0xc5, 0x2a, 0xf4, 0xff, 0x56, 0x91, 0xcc, 0x66, 0xfe, 0xd7, 0xd9, 0xd9, 0x99, 0x4b, 0x71, 0x36, + 0x7f, 0xca, 0x78, 0xc0, 0x99, 0x04, 0xf6, 0x85, 0x67, 0xcc, 0xe8, 0x90, 0xdf, 0xc2, 0x50, 0x88, 0x20, 0x97, 0xc2, + 0xb1, 0x4b, 0xf0, 0xce, 0x20, 0x50, 0x1e, 0x60, 0xff, 0x9e, 0x6c, 0x94, 0xf3, 0x0f, 0x15, 0xf9, 0x40, 0xbe, 0x65, + 0x83, 0xec, 0x8b, 0xf9, 0xec, 0x5b, 0x33, 0x19, 0x88, 0xcd, 0x1f, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, + 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, 0x0f, 0x53, 0xd6, 0x3d, 0x72, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0xc5, + 0xa3, 0x8c, 0x7e, 0x2c, 0x43, 0x4f, 0xee, 0xbd, 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, + 0x69, 0xfe, 0x23, 0xde, 0xab, 0x42, 0x50, 0x82, 0x2b, 0xa4, 0x89, 0xe2, 0x88, 0xcd, 0x83, 0xce, 0x69, 0x24, 0x80, + 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0xa8, 0x85, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0x16, 0xa9, 0x0d, 0xe1, + 0x0d, 0x91, 0xdc, 0xca, 0xd9, 0x98, 0xaf, 0x47, 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, + 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, + 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, 0x93, 0xdb, 0x60, 0xaa, 0x7f, 0x82, 0x1d, 0x08, 0x3d, 0x53, 0x3a, + 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, + 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, + 0xcc, 0x63, 0xd2, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, + 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, 0xde, 0x72, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, + 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, 0xcc, 0xc5, 0xc3, 0xf0, 0xd1, 0x77, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, + 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0x32, 0xdd, 0xd9, 0x0d, 0xa3, 0xb5, 0x79, 0x6e, 0x29, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, + 0x04, 0xd9, 0xda, 0x3c, 0xd8, 0x54, 0x66, 0x0d, 0x59, 0xf9, 0x3a, 0x41, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, + 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, + 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x22, 0xd7, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, + 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, 0x53, 0x70, 0xed, 0x43, 0xe4, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, + 0x18, 0x5d, 0x1b, 0xc8, 0xd7, 0x9b, 0x73, 0x9a, 0xb8, 0xb3, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, + 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, + 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x03, + 0x51, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, + 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, + 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, + 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, + 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0xa7, 0x1a, 0x35, 0x62, 0x9e, + 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, + 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, + 0xaa, 0x16, 0x85, 0x79, 0xba, 0x2d, 0x56, 0x28, 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0x52, 0x9a, 0x04, 0xc3, + 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, + 0x71, 0x38, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, + 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, 0xec, 0x9e, 0xae, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, + 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0xd7, 0xb5, 0xb8, 0x4b, 0x72, 0x0f, 0x64, 0x54, 0x6f, 0x60, 0xd7, 0x2c, 0xc0, + 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, 0x69, 0x9e, 0x52, 0xa2, 0xe6, 0x05, 0x25, 0x78, 0xb8, 0x99, 0xb0, + 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x68, 0x7b, 0xff, 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, + 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, + 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x67, 0x36, 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x0f, 0x6a, + 0x54, 0x0f, 0x9a, 0xfb, 0xe7, 0x9d, 0x8e, 0x3a, 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, + 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x9e, + 0xe0, 0xa8, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, 0xe6, 0xfe, 0x65, 0xcf, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, + 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, + 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, + 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, 0x5e, 0xdd, 0x01, 0x2b, 0x01, 0x1f, 0xfd, 0xd8, 0x24, 0x19, 0x43, + 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, + 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, + 0x20, 0x7e, 0x29, 0x74, 0x62, 0x22, 0x45, 0x5f, 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, + 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0x63, 0xc8, 0xe3, 0x52, + 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x71, 0xba, 0x5f, + 0x40, 0xd4, 0x66, 0x77, 0x2c, 0x81, 0x9e, 0x7d, 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, + 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0xde, 0x53, 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, + 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, + 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, + 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, + 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, 0x6c, 0x28, 0x5b, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, + 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, + 0x6d, 0xcb, 0x21, 0x18, 0x76, 0xa4, 0x0b, 0x6e, 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, + 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, + 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xd0, + 0xe5, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, + 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, + 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, + 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, + 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, + 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, + 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, + 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, + 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, + 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, + 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, + 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, + 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, + 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0xdf, + 0xe6, 0x84, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, + 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, + 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, + 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, + 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, + 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, + 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, 0xa9, 0x3e, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, + 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, + 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, + 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, + 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, + 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, + 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, + 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0xef, 0x6a, 0x01, 0x97, + 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, + 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x0b, 0xb3, 0x9f, + 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, + 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, + 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, + 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, + 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, + 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, + 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, + 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, + 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, 0x9a, 0xce, 0x3c, 0x8a, 0x5c, 0x7b, 0xef, 0x77, 0x53, 0xb4, 0xf5, + 0xaf, 0x0f, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, + 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, + 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, + 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, + 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, + 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, + 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, + 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, + 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, + 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, + 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, + 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, + 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0x3d, 0x45, 0xb7, 0x72, 0xef, 0xf4, + 0xac, 0xcc, 0xeb, 0x4a, 0xab, 0x58, 0x0e, 0x73, 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, + 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, + 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, + 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, + 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, + 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, + 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, 0x89, 0x17, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, + 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, + 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, + 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, + 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, + 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, + 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, + 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, + 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, 0xbd, 0xbb, 0xe1, 0xbb, 0x70, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, + 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0x3c, 0x15, 0x19, + 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, + 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, + 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, 0x67, 0xf7, 0x2e, 0x61, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, + 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, + 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, + 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, + 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, + 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, 0x55, 0x31, 0xdd, 0x0f, 0xdf, 0xd3, 0x0b, 0x3e, 0xbc, 0x43, 0xda, + 0xc6, 0xa3, 0x96, 0x94, 0x50, 0xbb, 0x83, 0xf6, 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, + 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, 0xca, 0x28, 0x18, 0xc2, 0x3e, 0x60, 0x1f, 0x8b, 0x24, 0xa3, 0xd9, + 0x94, 0x81, 0xba, 0xdf, 0x16, 0xad, 0xe6, 0xf6, 0xa4, 0xee, 0x37, 0x64, 0x9c, 0x7d, 0x84, 0x71, 0xf6, 0x51, 0xe0, + 0xc5, 0x22, 0xc9, 0x1f, 0x32, 0xd6, 0x38, 0x56, 0x4d, 0x81, 0x8e, 0x3a, 0xc0, 0x9d, 0x81, 0x03, 0x0f, 0xd8, 0xa2, + 0x1c, 0x1c, 0x50, 0x67, 0x71, 0x4f, 0x1b, 0x99, 0xf7, 0xf6, 0x84, 0xda, 0x45, 0x2c, 0x70, 0xb3, 0x66, 0xa6, 0x05, + 0xad, 0x15, 0xc6, 0x79, 0x3c, 0xe0, 0x6d, 0x9e, 0xd5, 0xe2, 0x27, 0x6c, 0x58, 0x53, 0xd5, 0x6f, 0xa0, 0x39, 0xaa, + 0x05, 0xb9, 0x79, 0x62, 0xbc, 0x55, 0x49, 0x3f, 0x8a, 0x06, 0x96, 0x53, 0x21, 0x86, 0x64, 0xf4, 0x5b, 0x83, 0xe0, + 0x56, 0x7b, 0xb5, 0xe2, 0x1e, 0xf1, 0x45, 0xcd, 0x5b, 0xcd, 0xdc, 0x02, 0xd0, 0x22, 0x8e, 0xca, 0x7b, 0x93, 0x08, + 0xbc, 0x6f, 0xcb, 0x08, 0x69, 0xcb, 0xbe, 0x7d, 0x34, 0xb1, 0x54, 0x6c, 0xbe, 0xa3, 0x93, 0x41, 0x1a, 0xd9, 0x11, + 0x45, 0xf8, 0xba, 0x84, 0x24, 0x5c, 0x25, 0x5d, 0xab, 0x4c, 0xce, 0x99, 0x4a, 0x39, 0xbe, 0x2e, 0xa4, 0xd4, 0x57, + 0xf6, 0x4b, 0xe2, 0xea, 0x4e, 0x46, 0xe0, 0xeb, 0x09, 0xd3, 0xef, 0x68, 0x31, 0x61, 0xe0, 0x57, 0xe4, 0x6f, 0xc7, + 0x52, 0x4a, 0x2e, 0x9f, 0x88, 0xb8, 0x4f, 0x31, 0xbc, 0xf8, 0x39, 0xc0, 0xda, 0x84, 0x40, 0x29, 0x71, 0x11, 0x2e, + 0x88, 0xde, 0x14, 0xf2, 0xf6, 0x2e, 0x2e, 0xb0, 0x73, 0x00, 0x2c, 0x9d, 0x26, 0x01, 0xfe, 0xe5, 0x63, 0x3e, 0x56, + 0x63, 0x4e, 0x8d, 0xae, 0xdf, 0xfd, 0x4e, 0xae, 0x81, 0xde, 0x96, 0x8e, 0x82, 0xfd, 0xd6, 0x00, 0x72, 0xe1, 0x2e, + 0x0c, 0x2e, 0xbe, 0xc2, 0xda, 0xb2, 0x30, 0xde, 0x58, 0x00, 0xbd, 0xbf, 0x33, 0xb0, 0x60, 0xc3, 0x1c, 0x53, 0x78, + 0x2e, 0x75, 0xc2, 0x74, 0x10, 0x15, 0xe4, 0x49, 0xf9, 0x20, 0x66, 0xad, 0xf6, 0x5b, 0x36, 0x86, 0x3b, 0x8c, 0xe4, + 0xdb, 0x85, 0x13, 0x07, 0x1e, 0x90, 0x69, 0x32, 0xdb, 0xec, 0x1b, 0x1f, 0x79, 0xe4, 0xf5, 0x38, 0xde, 0xd5, 0x52, + 0x98, 0x6f, 0x56, 0x74, 0x8d, 0x21, 0x14, 0x45, 0xd8, 0xef, 0x17, 0x15, 0x53, 0x54, 0x19, 0xb4, 0x41, 0xc3, 0xf2, + 0x46, 0xfc, 0x02, 0x67, 0x0c, 0xad, 0x17, 0xb2, 0x77, 0x74, 0xd6, 0xe1, 0xcc, 0x61, 0xc6, 0x94, 0xc0, 0xa8, 0xb4, + 0x2c, 0xe8, 0x04, 0x1c, 0x9d, 0xab, 0x0f, 0xa2, 0xe2, 0xea, 0x58, 0x01, 0x78, 0x92, 0x29, 0xfc, 0x93, 0x6f, 0x82, + 0x75, 0xbf, 0x55, 0x33, 0x4c, 0xfd, 0x45, 0x6f, 0xbb, 0x96, 0x2f, 0x43, 0x1c, 0x69, 0x63, 0x08, 0xad, 0x73, 0x7b, + 0x07, 0x28, 0xe2, 0x82, 0x5e, 0xa4, 0x1a, 0x5f, 0xab, 0xc5, 0xd0, 0xac, 0xaf, 0x71, 0x1d, 0xd3, 0x06, 0x51, 0xac, + 0xbb, 0x26, 0xbe, 0xae, 0xde, 0x1f, 0x55, 0xa9, 0x82, 0x33, 0x48, 0x20, 0xac, 0xca, 0xcb, 0x86, 0x54, 0x92, 0x4b, + 0xd3, 0xa9, 0x34, 0x9d, 0x56, 0x08, 0xe5, 0xd2, 0x93, 0xf2, 0xfe, 0x15, 0x42, 0x18, 0x98, 0x32, 0x3b, 0xb0, 0x4a, + 0x6d, 0x61, 0x15, 0xbc, 0x7a, 0xb1, 0x81, 0x55, 0x12, 0x8e, 0xe7, 0x12, 0x8d, 0x8a, 0x0a, 0x87, 0x0c, 0xe9, 0x0b, + 0xb1, 0x08, 0x12, 0x00, 0x8b, 0xde, 0x65, 0x2e, 0xef, 0x7b, 0x38, 0x14, 0xf6, 0x24, 0x93, 0x70, 0xba, 0x09, 0xcd, + 0xe1, 0x61, 0x5a, 0xd5, 0xf3, 0x08, 0x01, 0x4b, 0xcf, 0x31, 0x3c, 0x48, 0xfc, 0xfd, 0x87, 0x50, 0x9d, 0x05, 0x79, + 0xfa, 0x2f, 0x51, 0x12, 0x1a, 0xfb, 0xcf, 0xf1, 0xd0, 0x21, 0x61, 0x38, 0xf0, 0xcd, 0x11, 0x56, 0x38, 0xb8, 0x55, + 0xc4, 0x67, 0x70, 0x87, 0x8f, 0x75, 0xe8, 0x01, 0x60, 0x09, 0xc5, 0x21, 0xc8, 0x37, 0x50, 0xcc, 0xe0, 0x80, 0x26, + 0xcb, 0xf0, 0x02, 0x17, 0xac, 0x16, 0xca, 0xfb, 0xdb, 0x96, 0x97, 0xd2, 0x6a, 0x97, 0xbc, 0xc6, 0x1c, 0xa8, 0xfc, + 0x0c, 0x2f, 0x7c, 0x85, 0x79, 0x29, 0xd9, 0x7d, 0xe1, 0x6b, 0x07, 0xf4, 0x14, 0x02, 0x46, 0xba, 0xdf, 0x6b, 0xc2, + 0x3d, 0x45, 0x2f, 0x73, 0x71, 0xd8, 0x76, 0xd0, 0xbd, 0xc0, 0x5c, 0x5d, 0x55, 0x59, 0x73, 0x30, 0x85, 0x06, 0x07, + 0x55, 0x38, 0x23, 0x30, 0x57, 0x2f, 0xca, 0x82, 0x73, 0x10, 0xef, 0x7b, 0xc2, 0xe4, 0x94, 0xd1, 0x00, 0x5e, 0x64, + 0xe5, 0xa3, 0x53, 0x3d, 0x0e, 0x2e, 0xe3, 0x86, 0x4d, 0x7c, 0x21, 0x7c, 0x2a, 0xb0, 0x92, 0xd6, 0x38, 0x34, 0xa2, + 0x23, 0x3a, 0x07, 0xb3, 0x0d, 0xa0, 0xe0, 0xee, 0x7c, 0xd8, 0x58, 0xa8, 0xe0, 0x31, 0xd8, 0xda, 0xdb, 0xcd, 0x84, + 0x38, 0x93, 0xa6, 0xe0, 0x6e, 0xdb, 0x20, 0x83, 0x37, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, + 0x84, 0x27, 0x28, 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xa2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x3a, 0x6a, 0x20, + 0x2a, 0x6a, 0xa0, 0x02, 0x6a, 0x20, 0xeb, 0xdb, 0xbf, 0x80, 0x85, 0xb0, 0x11, 0xaa, 0x44, 0x10, 0x10, 0x61, 0xae, + 0x0d, 0x1f, 0x50, 0x24, 0x21, 0xe4, 0x0d, 0xa0, 0x62, 0x4a, 0x5e, 0x82, 0xd1, 0x38, 0xbc, 0xde, 0x03, 0xee, 0x97, + 0x96, 0x61, 0xf0, 0x9c, 0x82, 0xc9, 0x7f, 0xeb, 0xf3, 0xa1, 0x7a, 0xb9, 0x3a, 0x08, 0xe1, 0x17, 0x10, 0x2b, 0xc2, + 0xf1, 0x17, 0xbf, 0x00, 0xd9, 0x54, 0x58, 0x1e, 0x1c, 0x48, 0x10, 0xf8, 0x21, 0x8a, 0x70, 0xc0, 0x33, 0xbc, 0xcc, + 0x36, 0x88, 0x9e, 0x9f, 0x95, 0xaa, 0x66, 0x25, 0x83, 0x59, 0x15, 0x9e, 0xc6, 0xd1, 0x35, 0x61, 0x20, 0xb8, 0x50, + 0xbb, 0x6f, 0x10, 0x02, 0x65, 0xcb, 0x8d, 0xa1, 0x4b, 0x4f, 0xc1, 0x7c, 0x34, 0x8e, 0xde, 0x32, 0x78, 0xd2, 0xd6, + 0x98, 0xfc, 0x33, 0x6d, 0x1e, 0xb8, 0x4f, 0xf7, 0xa2, 0x46, 0xe0, 0xa4, 0x4e, 0x51, 0xf2, 0xb7, 0xe4, 0x22, 0x8e, + 0x9a, 0x97, 0x11, 0x6a, 0xc0, 0xbf, 0x0d, 0x8e, 0xba, 0x34, 0xa1, 0xa3, 0x91, 0x0f, 0x7e, 0x93, 0x11, 0xb3, 0xc9, + 0x56, 0x2b, 0x51, 0x11, 0xf4, 0xc4, 0x6e, 0x30, 0x60, 0x25, 0x5e, 0x00, 0xfb, 0x60, 0x39, 0x58, 0xf2, 0x4e, 0xc4, + 0xca, 0x9f, 0x52, 0x18, 0xac, 0x9e, 0x33, 0x84, 0x70, 0x16, 0xc4, 0x6c, 0xfc, 0xcf, 0x67, 0x1a, 0xae, 0x9f, 0x9f, + 0xaf, 0x63, 0x44, 0xa4, 0x0f, 0x22, 0x57, 0x63, 0x47, 0x44, 0x10, 0xb6, 0x4c, 0xf7, 0x5d, 0x99, 0x1f, 0xbc, 0x75, + 0xf5, 0xc0, 0x86, 0x8b, 0x03, 0x03, 0x6a, 0x14, 0x18, 0xad, 0xe0, 0x9c, 0x94, 0x03, 0x07, 0x25, 0x84, 0x66, 0x45, + 0x3c, 0x25, 0x97, 0x10, 0x09, 0x2f, 0x43, 0x5d, 0x30, 0x2c, 0x08, 0x24, 0xa8, 0x29, 0x48, 0x50, 0x99, 0xaf, 0x3d, + 0x82, 0x59, 0xe7, 0x66, 0xb6, 0x53, 0xd4, 0x75, 0x41, 0x7e, 0x7e, 0xd1, 0xf1, 0x08, 0x58, 0xda, 0x83, 0x83, 0x02, + 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, 0xc0, 0x40, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0xda, 0x78, 0x1d, 0x18, 0x5b, + 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x3d, 0x9d, 0x6e, 0x47, 0x48, 0xec, 0x7d, 0xd4, + 0x26, 0xd0, 0x98, 0x23, 0xdd, 0xd5, 0xc6, 0xfc, 0x5a, 0xd3, 0x23, 0x56, 0x93, 0x90, 0x2e, 0x48, 0x97, 0xe7, 0xd3, + 0x9e, 0xc1, 0x15, 0xab, 0x34, 0x72, 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x17, + 0x49, 0xc9, 0x86, 0x61, 0x06, 0x61, 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0xb3, 0x7f, 0x4a, 0x1f, + 0x6c, 0xba, 0xf6, 0xe6, 0x11, 0x40, 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x36, 0x2a, 0xb3, 0xb0, 0x96, 0xb1, 0x95, + 0xdb, 0xf6, 0x18, 0x7b, 0x27, 0xb6, 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x88, 0x75, 0x6d, + 0xc8, 0x46, 0x1b, 0xda, 0x37, 0x4f, 0xc2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x39, 0x2e, 0xc1, 0x21, 0xbc, 0xf0, 0x08, + 0x7f, 0x0b, 0x2c, 0x52, 0x81, 0x19, 0x96, 0xab, 0x15, 0xd4, 0xf3, 0x78, 0x9f, 0x6d, 0x06, 0x27, 0x95, 0x1b, 0x63, + 0x97, 0x76, 0xe2, 0x71, 0xd9, 0x84, 0xc4, 0x19, 0xf4, 0xeb, 0x2b, 0xa2, 0xde, 0x7e, 0x3b, 0x7d, 0xe2, 0xdf, 0x2b, + 0x73, 0x3b, 0x10, 0x1b, 0xd6, 0x1b, 0xac, 0x3e, 0x80, 0x96, 0xbf, 0xca, 0xfc, 0x43, 0x65, 0xc1, 0x4d, 0x82, 0xda, + 0x5c, 0xc4, 0x2e, 0xeb, 0x22, 0x46, 0x6a, 0x8b, 0xbb, 0x43, 0x88, 0x7f, 0xb5, 0x15, 0xc5, 0x80, 0x27, 0x15, 0xff, + 0x1c, 0xa3, 0x2e, 0x84, 0xa2, 0xb6, 0x1e, 0x36, 0x40, 0x69, 0x97, 0xeb, 0x4a, 0x8c, 0x0c, 0x09, 0xe4, 0x5b, 0x17, + 0x5e, 0xd0, 0x9c, 0x44, 0x0a, 0xe4, 0xe4, 0x20, 0x2a, 0x69, 0xb6, 0x21, 0xcc, 0x75, 0xb7, 0x70, 0xcc, 0x5c, 0x6d, + 0xd0, 0x22, 0x7e, 0x01, 0xec, 0x0c, 0x37, 0x92, 0xa5, 0x03, 0x9f, 0xaa, 0x81, 0xcf, 0xaf, 0xb9, 0xa1, 0x28, 0x0a, + 0xf5, 0xde, 0xd9, 0x47, 0xe6, 0xe0, 0x77, 0x1a, 0x88, 0x8f, 0xd4, 0xe9, 0x48, 0x36, 0x42, 0xad, 0x39, 0x3b, 0x5e, + 0xb6, 0x19, 0x61, 0x50, 0xd8, 0xe8, 0x7d, 0x15, 0xb2, 0x8a, 0x9d, 0x9d, 0x8a, 0x60, 0x4e, 0x5f, 0x54, 0xe5, 0x9c, + 0xca, 0x2d, 0xa3, 0x5a, 0x6a, 0x1a, 0x20, 0xc2, 0x95, 0x4f, 0x24, 0xef, 0x33, 0x13, 0xfe, 0xc1, 0x60, 0x5c, 0x3d, + 0x52, 0xf8, 0xfb, 0x5d, 0xb1, 0x43, 0xb6, 0xa3, 0xc3, 0x6d, 0x04, 0xcd, 0x0b, 0x15, 0x3c, 0xe0, 0xa8, 0x64, 0x09, + 0x91, 0x22, 0x97, 0xfb, 0xaa, 0x66, 0xca, 0x76, 0x1d, 0x21, 0x84, 0xb4, 0xc7, 0x59, 0x37, 0xb4, 0x7a, 0xe8, 0x91, + 0x2a, 0xca, 0xe1, 0x16, 0xcd, 0x75, 0x01, 0x2a, 0x8c, 0x40, 0xba, 0xfc, 0xcc, 0xee, 0x52, 0x09, 0xd1, 0xcb, 0xd7, + 0x2e, 0x84, 0xb1, 0xb3, 0xb2, 0xc4, 0x85, 0x19, 0xb5, 0x0d, 0xa3, 0xeb, 0x36, 0x86, 0xb3, 0x81, 0x31, 0xd3, 0xa0, + 0xa4, 0x05, 0xa1, 0xae, 0xbb, 0xf4, 0x22, 0x33, 0x81, 0x1e, 0x73, 0x42, 0x1b, 0x0c, 0x4f, 0x89, 0x06, 0xcb, 0xa6, + 0x02, 0x2c, 0xf8, 0x96, 0x45, 0x6a, 0x6d, 0x36, 0x59, 0xfc, 0x51, 0xc7, 0xe6, 0x69, 0xbf, 0xbc, 0x62, 0x9e, 0x0b, + 0x47, 0xdd, 0x9e, 0x67, 0x3e, 0x1e, 0xdd, 0xd3, 0x37, 0x57, 0x2f, 0x5e, 0xbe, 0x7e, 0xb5, 0x5a, 0xb5, 0x59, 0xb3, + 0x7d, 0x82, 0x7f, 0xd2, 0x65, 0x3c, 0xd8, 0x32, 0x0a, 0xd0, 0xc1, 0xc1, 0x3e, 0x37, 0x2e, 0x3c, 0x9f, 0xf9, 0x1c, + 0xe2, 0x06, 0xe9, 0x01, 0xce, 0x8a, 0x32, 0x26, 0xc8, 0x6d, 0xd4, 0x8b, 0xee, 0x22, 0x50, 0x42, 0x55, 0xe4, 0xef, + 0xc3, 0xe6, 0xec, 0xf7, 0x20, 0x30, 0x11, 0xd4, 0x87, 0x08, 0x20, 0x10, 0xaf, 0x14, 0x17, 0x84, 0xf9, 0x04, 0x88, + 0xe2, 0xbd, 0x00, 0xce, 0xd4, 0x44, 0xad, 0x5a, 0xa8, 0xb8, 0x00, 0x92, 0x68, 0xc3, 0x51, 0xd2, 0x23, 0x13, 0xc0, + 0x1b, 0x82, 0x52, 0xda, 0x5f, 0xdd, 0xdc, 0xb9, 0x4b, 0xe5, 0xa8, 0xd7, 0x4a, 0x73, 0x3c, 0x75, 0x9f, 0x53, 0xf8, + 0x9c, 0x76, 0xfd, 0xe9, 0x20, 0x0e, 0x73, 0xbc, 0x20, 0xe2, 0xd0, 0x3f, 0x8b, 0xb8, 0x9c, 0x17, 0xec, 0x0b, 0x97, + 0x0b, 0x95, 0x2e, 0x6f, 0x53, 0x99, 0xdc, 0x36, 0x47, 0x87, 0x71, 0x91, 0xdc, 0x36, 0x55, 0x72, 0x8b, 0xf0, 0x5d, + 0x2a, 0x93, 0x3b, 0x9b, 0x72, 0xd7, 0x54, 0x70, 0xf3, 0x85, 0x05, 0x1c, 0x8a, 0xb6, 0x68, 0x63, 0xb1, 0x59, 0xd4, + 0xa6, 0xb8, 0xa2, 0x01, 0x06, 0xff, 0xbe, 0x63, 0xe3, 0x87, 0xe1, 0x4b, 0x70, 0x69, 0xd2, 0x44, 0x7e, 0x02, 0xe9, + 0xa7, 0x55, 0x19, 0xb8, 0x4f, 0x49, 0xab, 0x3b, 0xbd, 0x10, 0xcd, 0x76, 0xb7, 0xd1, 0x98, 0xc2, 0xde, 0xcd, 0x48, + 0xee, 0x8b, 0x4d, 0x1b, 0x26, 0xbe, 0xce, 0x7e, 0xb6, 0x5a, 0xed, 0xe7, 0xc8, 0x6c, 0xb8, 0x09, 0x8b, 0x75, 0x7f, + 0x3a, 0xc0, 0x2d, 0xfc, 0x3c, 0x43, 0x68, 0xc9, 0xfa, 0xd3, 0x01, 0x61, 0xfd, 0x69, 0xa3, 0x3d, 0xb0, 0x86, 0x76, + 0x66, 0x2b, 0xae, 0x21, 0x84, 0xe6, 0x74, 0x70, 0x64, 0x4a, 0x4a, 0x97, 0x6f, 0xbf, 0x68, 0x15, 0xd0, 0x4f, 0xd5, + 0x82, 0x97, 0x49, 0xdc, 0x81, 0xbe, 0xe8, 0x85, 0x7d, 0xba, 0xb5, 0x20, 0xc7, 0x47, 0x95, 0xab, 0x3d, 0x45, 0xd8, + 0xf4, 0xa4, 0x0e, 0x8b, 0x43, 0xd3, 0x8c, 0xeb, 0x52, 0xba, 0xef, 0x50, 0x33, 0xf2, 0xd1, 0xc1, 0x02, 0x10, 0xa4, + 0x82, 0x47, 0x56, 0xb8, 0x70, 0x4a, 0x21, 0x5c, 0x1c, 0x54, 0xb6, 0x60, 0x92, 0x93, 0x56, 0x37, 0x37, 0x96, 0xfe, + 0xb9, 0x8b, 0x68, 0x4a, 0x31, 0x25, 0x99, 0x2f, 0x99, 0x1b, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x00, + 0x8f, 0x08, 0xc4, 0x43, 0xea, 0x16, 0xc6, 0xc0, 0x2b, 0x9e, 0x36, 0x8b, 0x3e, 0x1b, 0xa0, 0xa3, 0x63, 0x4c, 0xfb, + 0x7f, 0x65, 0xf3, 0x36, 0x3c, 0x16, 0xf8, 0xd7, 0x80, 0x4c, 0x9b, 0xb2, 0x4c, 0x10, 0x90, 0x30, 0x6a, 0xca, 0x43, + 0xd8, 0x4b, 0x08, 0x67, 0xb6, 0x62, 0xd6, 0x67, 0x83, 0xe6, 0xb4, 0xac, 0xd8, 0xf1, 0x15, 0x1b, 0xb2, 0x4c, 0xb0, + 0x15, 0x1b, 0xae, 0x62, 0xf8, 0x3a, 0x83, 0x01, 0x41, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x28, 0x88, 0xe6, 0x8b, 0x15, + 0xf1, 0x9b, 0xdd, 0xde, 0xe3, 0xb7, 0xc0, 0x02, 0xad, 0xb6, 0xff, 0x77, 0xa1, 0x0c, 0xd8, 0x53, 0x16, 0x26, 0x66, + 0x6e, 0x61, 0x55, 0x74, 0x00, 0x95, 0x12, 0x61, 0x0a, 0x03, 0x99, 0xfd, 0xcc, 0x40, 0x2d, 0xd0, 0x1a, 0xe4, 0x7d, + 0x3d, 0x68, 0x66, 0x70, 0xc4, 0xc0, 0x3b, 0x34, 0x64, 0x6a, 0x8c, 0x09, 0xe3, 0x1c, 0xa6, 0x98, 0x19, 0xf0, 0x4c, + 0xd3, 0xd6, 0x5a, 0x1a, 0x59, 0xae, 0x97, 0xf7, 0xfe, 0xd1, 0xb1, 0xea, 0x17, 0xcd, 0xf6, 0x00, 0xed, 0x13, 0x62, + 0x3f, 0x06, 0xb0, 0xc9, 0x5c, 0x6a, 0xc3, 0x7c, 0x1f, 0x75, 0x52, 0xfb, 0x09, 0x7f, 0x06, 0x6b, 0xb3, 0x03, 0x40, + 0x47, 0x86, 0xcd, 0xfa, 0xcb, 0x9a, 0xca, 0xeb, 0xe3, 0xce, 0x28, 0x95, 0xbb, 0xde, 0x9d, 0x0e, 0x34, 0xc5, 0xa1, + 0xb7, 0x1e, 0x2e, 0x1f, 0xea, 0x21, 0x60, 0xc6, 0x60, 0x6e, 0x99, 0xd1, 0xf7, 0x42, 0x24, 0x17, 0x44, 0x62, 0x69, + 0xb0, 0x86, 0xc1, 0xde, 0x3a, 0x38, 0x30, 0xd5, 0x58, 0x03, 0x9e, 0x27, 0x45, 0x20, 0x18, 0xf8, 0x08, 0xca, 0x80, + 0x26, 0xca, 0xdc, 0x86, 0x93, 0x8f, 0xcc, 0xfd, 0xc2, 0xe5, 0xed, 0x63, 0xe1, 0xb4, 0xad, 0xe6, 0x7a, 0xbc, 0x2c, + 0x70, 0x57, 0xde, 0x4b, 0x5a, 0x05, 0x37, 0xb2, 0x37, 0x79, 0xca, 0xdc, 0xad, 0xfb, 0x52, 0x9d, 0xdd, 0xcd, 0x74, + 0xca, 0x66, 0x3a, 0xdb, 0xcd, 0x84, 0x9a, 0x99, 0x6f, 0x59, 0x45, 0x9a, 0x93, 0x35, 0x51, 0x73, 0x2a, 0x7e, 0xa2, + 0x73, 0xd0, 0x8e, 0x72, 0x7b, 0xaf, 0x0a, 0x27, 0x57, 0x4e, 0x2e, 0xf7, 0x73, 0x43, 0x5c, 0x91, 0xb9, 0x50, 0x87, + 0x00, 0x2f, 0x2f, 0xca, 0xc7, 0x07, 0xb8, 0x14, 0xbf, 0xca, 0x91, 0x8b, 0x72, 0x2a, 0xa4, 0x96, 0x82, 0x45, 0xc8, + 0xa0, 0xaa, 0x8b, 0x81, 0xbd, 0xb4, 0x7b, 0x4f, 0xf4, 0x78, 0xbf, 0x8a, 0x98, 0x37, 0x30, 0xcf, 0x7d, 0x7c, 0x4f, + 0x53, 0xec, 0xd4, 0xc4, 0x19, 0xf9, 0x90, 0xc5, 0x39, 0xc8, 0x66, 0xfd, 0xea, 0xb5, 0xdf, 0x46, 0x1b, 0x17, 0xcd, + 0x58, 0xf4, 0xcc, 0x13, 0x27, 0x3f, 0x14, 0xc6, 0x38, 0xc0, 0x3a, 0xfa, 0x23, 0x4c, 0x2d, 0xd8, 0xb3, 0xc4, 0x53, + 0xe8, 0xe4, 0xd6, 0xa6, 0xdd, 0x85, 0x69, 0x77, 0x26, 0xad, 0x03, 0xe5, 0x80, 0x34, 0xbb, 0x32, 0x9d, 0x3b, 0xff, + 0x7d, 0x07, 0x2f, 0xdd, 0xae, 0x21, 0x12, 0xf7, 0xfc, 0x91, 0x31, 0x86, 0x78, 0x03, 0x36, 0xa2, 0xea, 0xe0, 0xe0, + 0x0f, 0xe7, 0x7d, 0x5b, 0xc9, 0x7d, 0xdf, 0x0a, 0x07, 0xb6, 0xc1, 0x54, 0xba, 0xbc, 0x91, 0xcc, 0x16, 0x60, 0xd7, + 0xb9, 0xff, 0x8d, 0x78, 0xf8, 0x22, 0x64, 0x5a, 0xac, 0xab, 0xf8, 0x2b, 0x39, 0x2a, 0x3d, 0x44, 0x35, 0x44, 0x20, + 0xad, 0xac, 0x4b, 0x43, 0xd3, 0xd1, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x81, 0x7d, 0x91, 0x5b, 0x27, + 0xf0, 0x68, 0x61, 0x8d, 0xa1, 0xb9, 0x2b, 0xbd, 0x93, 0x6c, 0x40, 0xd4, 0xfa, 0xb8, 0x43, 0x49, 0x24, 0x16, 0xd5, + 0x5d, 0x08, 0x87, 0xbb, 0x10, 0xcc, 0xcb, 0xa0, 0x6d, 0x10, 0xbb, 0xdd, 0x05, 0x6d, 0x03, 0xa7, 0x6e, 0x1b, 0xb8, + 0x3d, 0x18, 0x2c, 0xec, 0x7d, 0x78, 0x39, 0x96, 0x63, 0xe1, 0xaf, 0xc9, 0xec, 0x03, 0x40, 0xa0, 0xf6, 0x61, 0xc5, + 0x13, 0x07, 0x82, 0xc4, 0x19, 0x8e, 0xbe, 0xe7, 0xec, 0xc6, 0x5a, 0x0e, 0xcf, 0xe6, 0x0b, 0xcd, 0x46, 0xe6, 0x8e, + 0x1a, 0x54, 0x7c, 0x75, 0x3f, 0xaf, 0x9f, 0xb2, 0x9a, 0x6e, 0xfc, 0x1e, 0x84, 0x91, 0x70, 0xca, 0x0e, 0xa3, 0x90, + 0xb0, 0xc1, 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0x6d, 0xc2, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x08, 0xdb, + 0x78, 0x63, 0x41, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x45, 0xcd, 0xa8, 0xc1, 0x52, + 0x17, 0x94, 0xd9, 0x47, 0x18, 0x57, 0x17, 0x27, 0x26, 0x4e, 0x7b, 0xa9, 0x57, 0xff, 0x2d, 0x03, 0x03, 0x7c, 0x01, + 0x5e, 0x62, 0x61, 0x74, 0xd7, 0xbe, 0x6e, 0x40, 0x7d, 0xd9, 0x60, 0x03, 0xb4, 0x5a, 0xb5, 0xca, 0x67, 0xa0, 0xdc, + 0x35, 0x97, 0xb0, 0xd7, 0x5c, 0xc2, 0x5d, 0x73, 0x09, 0x7f, 0xcd, 0x25, 0xcc, 0x35, 0x97, 0xf0, 0xd7, 0x5c, 0x1e, + 0x84, 0x9f, 0x82, 0x38, 0x8e, 0x31, 0x87, 0xb8, 0x8a, 0xda, 0x46, 0xc6, 0x83, 0x0b, 0xcf, 0x7d, 0x96, 0xa8, 0x72, + 0xf9, 0xc3, 0x18, 0x72, 0x5b, 0xb6, 0x12, 0xc6, 0x6d, 0x8a, 0x29, 0x88, 0x9c, 0x7e, 0x70, 0x50, 0xba, 0x3b, 0x83, + 0x8f, 0x7a, 0xca, 0xf1, 0xd2, 0x3a, 0xd1, 0xfe, 0x01, 0x3a, 0x79, 0xf3, 0xeb, 0x63, 0x2a, 0xd7, 0x44, 0x38, 0x93, + 0xfb, 0xfd, 0xb6, 0xa7, 0x14, 0x9f, 0x32, 0x13, 0x9e, 0x9c, 0x27, 0xda, 0x88, 0x20, 0x08, 0x51, 0xa2, 0x70, 0x46, + 0xa4, 0xdd, 0xef, 0xde, 0x15, 0xde, 0xa8, 0xa2, 0xbc, 0x59, 0xc9, 0xe3, 0x1c, 0x9c, 0xd8, 0x8d, 0x15, 0x06, 0xea, + 0x82, 0x0b, 0x41, 0x66, 0x12, 0xfe, 0x68, 0xe6, 0x96, 0x9c, 0x65, 0x65, 0xd2, 0xc7, 0x66, 0x6e, 0x08, 0x58, 0x41, + 0xf6, 0x3d, 0xcc, 0x96, 0xb7, 0x29, 0xc5, 0x77, 0x69, 0x86, 0x87, 0xf2, 0x36, 0x2d, 0x42, 0x5b, 0x10, 0x7f, 0xf1, + 0x37, 0x8e, 0x23, 0x41, 0xc1, 0xdf, 0x27, 0xe2, 0x62, 0x8f, 0x6f, 0x78, 0x01, 0x2e, 0x33, 0x63, 0x51, 0x9d, 0x32, + 0xfc, 0x0d, 0x4b, 0x78, 0x08, 0x4e, 0xa6, 0xb1, 0x22, 0xf7, 0x38, 0xb0, 0x13, 0x92, 0x80, 0xc3, 0xd5, 0xed, 0x15, + 0xff, 0x0a, 0x17, 0x5f, 0xa5, 0xb3, 0x65, 0x73, 0x28, 0x6f, 0x23, 0x5c, 0x90, 0x37, 0xf0, 0xfa, 0xd6, 0xff, 0xcb, + 0xde, 0xdb, 0x36, 0xb7, 0x6d, 0x64, 0xeb, 0xa2, 0x7f, 0x45, 0x62, 0xd9, 0x0c, 0x60, 0x36, 0x29, 0xca, 0xe7, 0xcc, + 0x54, 0x5d, 0x50, 0x6d, 0x96, 0x63, 0xc7, 0x13, 0x67, 0x22, 0xdb, 0x63, 0x79, 0x32, 0xc9, 0xb0, 0x78, 0x19, 0x08, + 0x68, 0x0a, 0x70, 0x40, 0x80, 0x01, 0x40, 0x89, 0x34, 0x89, 0xff, 0x7e, 0x6a, 0xad, 0xd5, 0xaf, 0x20, 0x28, 0x7b, + 0xf6, 0x3e, 0xfb, 0xd3, 0xbd, 0x5f, 0x6c, 0xb1, 0xd1, 0x68, 0xf4, 0x7b, 0xaf, 0x5e, 0x2f, 0xcf, 0xd3, 0x93, 0xb1, + 0xba, 0x3d, 0x70, 0xd6, 0xa5, 0x14, 0x1d, 0x6f, 0x8a, 0xc3, 0xdb, 0xf3, 0xd9, 0x7e, 0x1b, 0x44, 0x6c, 0x17, 0x64, + 0x58, 0xeb, 0xa4, 0xe1, 0x3f, 0xd1, 0xd6, 0xc1, 0x62, 0x84, 0xfd, 0x5f, 0xd6, 0x03, 0x2f, 0x21, 0x35, 0x14, 0xb8, + 0x18, 0x6c, 0x38, 0x5a, 0xdb, 0x65, 0x1a, 0xb8, 0xa9, 0x41, 0xaf, 0xef, 0x29, 0x44, 0x79, 0xc9, 0x68, 0x6e, 0x04, + 0xeb, 0xc6, 0x90, 0x8b, 0xc3, 0x71, 0xb3, 0x1c, 0xf2, 0x92, 0xa6, 0xd3, 0x20, 0x94, 0xee, 0x2c, 0x6b, 0x48, 0xa2, + 0xec, 0x83, 0x50, 0xbb, 0xb6, 0xec, 0xb7, 0x81, 0xed, 0xcb, 0x1f, 0x0d, 0x63, 0xff, 0x62, 0xf9, 0x4c, 0x48, 0x17, + 0xf1, 0x1c, 0x04, 0x51, 0xfb, 0x79, 0x36, 0xdc, 0xf8, 0x17, 0xeb, 0x67, 0x42, 0xf9, 0x8d, 0xe7, 0xb6, 0x1c, 0x52, + 0x67, 0x2d, 0x7c, 0x61, 0x3c, 0x3c, 0xb8, 0x32, 0xb4, 0x1d, 0x0e, 0x42, 0xff, 0x6d, 0xd6, 0x08, 0x6e, 0x6c, 0x68, + 0x9f, 0x2f, 0x7c, 0xd8, 0xda, 0x68, 0xac, 0x29, 0xa6, 0x5b, 0xe8, 0xdf, 0x64, 0xb6, 0xb4, 0xa7, 0x51, 0xc9, 0x8b, + 0x53, 0xd3, 0x88, 0x85, 0x30, 0x60, 0xe8, 0x27, 0xf3, 0x01, 0x54, 0x73, 0xc7, 0x23, 0x90, 0xc9, 0x07, 0x7a, 0xb0, + 0x26, 0xb5, 0xea, 0xaf, 0x61, 0x26, 0xff, 0x8f, 0x54, 0x58, 0x8c, 0xee, 0xb6, 0x61, 0xa6, 0xfe, 0x88, 0xe4, 0x1f, + 0x2c, 0xe7, 0xbb, 0xd4, 0x0b, 0xb5, 0x1f, 0x0b, 0x2b, 0x30, 0x28, 0x51, 0x35, 0xa0, 0x07, 0x22, 0xa8, 0xca, 0x20, + 0xcd, 0xb0, 0x3a, 0x07, 0xfd, 0xee, 0x69, 0xd5, 0x91, 0x1c, 0xd2, 0x5a, 0x0d, 0xa9, 0x60, 0xaa, 0xd4, 0x20, 0x3f, + 0x1c, 0xee, 0x52, 0xa6, 0xcb, 0x80, 0x4b, 0xfa, 0x5d, 0xaa, 0x94, 0xc2, 0x7f, 0x22, 0x00, 0x9d, 0x83, 0x7b, 0x7c, + 0x39, 0x06, 0xd2, 0x0c, 0x0b, 0xbf, 0x35, 0x3b, 0xbe, 0x26, 0xe1, 0x36, 0x09, 0x2e, 0x06, 0x38, 0x47, 0x57, 0x61, + 0x79, 0x97, 0x42, 0x04, 0x55, 0x09, 0xf5, 0xad, 0x4c, 0x83, 0xd2, 0x56, 0x83, 0xb0, 0x26, 0xa1, 0xce, 0x24, 0x1b, + 0x95, 0xb6, 0x1b, 0x85, 0xd9, 0x22, 0xae, 0x67, 0x84, 0x35, 0x67, 0x33, 0xd5, 0xc0, 0xa4, 0xe1, 0xb8, 0x69, 0xb4, + 0x16, 0x15, 0x6a, 0x0a, 0xf3, 0x1a, 0x57, 0x95, 0xaa, 0xee, 0xe6, 0xd4, 0x52, 0x5a, 0xb6, 0x57, 0xdd, 0x24, 0x1b, + 0x72, 0x19, 0xca, 0x30, 0xd8, 0xc8, 0x11, 0x4c, 0x20, 0x49, 0xce, 0xfc, 0x8d, 0xfc, 0x43, 0x6d, 0xba, 0x16, 0x30, + 0xc7, 0x98, 0x65, 0xc3, 0x82, 0x5e, 0x81, 0x7b, 0xa0, 0x95, 0x9e, 0x4f, 0xb3, 0x8b, 0x3c, 0x48, 0x86, 0x85, 0x5e, + 0x36, 0x19, 0xff, 0x53, 0x18, 0x69, 0x32, 0x63, 0x25, 0x8b, 0x6c, 0x57, 0xa7, 0xc4, 0x79, 0x9c, 0xc0, 0xf6, 0x68, + 0x7a, 0xcb, 0xf7, 0x19, 0x44, 0x05, 0x81, 0x82, 0x19, 0xf3, 0x65, 0x17, 0xcf, 0x7d, 0x9f, 0x59, 0xa6, 0xee, 0xc3, + 0xc1, 0x98, 0xb1, 0xfd, 0x7e, 0x3f, 0xef, 0xf7, 0xd5, 0x7c, 0xeb, 0xf7, 0x93, 0x17, 0xe6, 0x6f, 0x0f, 0x18, 0x14, + 0xe4, 0x44, 0x34, 0x15, 0x22, 0xf8, 0x87, 0xe4, 0x19, 0x92, 0xd1, 0x1d, 0xf7, 0xb9, 0xe5, 0x6c, 0x59, 0x1d, 0x81, + 0x60, 0x1e, 0x0e, 0x97, 0x0a, 0xec, 0x5a, 0xa2, 0x48, 0xc8, 0xf2, 0x9f, 0x81, 0xf1, 0xcc, 0x7d, 0x80, 0x25, 0x03, + 0x10, 0xb6, 0xca, 0xd3, 0xf5, 0x9e, 0xaf, 0x82, 0x77, 0x3a, 0xde, 0x35, 0x56, 0x64, 0x20, 0x6e, 0x81, 0x8d, 0x58, + 0x6b, 0x0f, 0xc8, 0x99, 0x02, 0x1c, 0x2f, 0x0e, 0x87, 0x73, 0xf9, 0x4b, 0x37, 0x5b, 0x27, 0x50, 0x29, 0x70, 0x7b, + 0x74, 0x72, 0xf0, 0xdf, 0x81, 0x66, 0x50, 0x0e, 0xf3, 0x7a, 0xfb, 0x3b, 0x73, 0xf2, 0xd3, 0x53, 0xfc, 0x13, 0x1e, + 0xa2, 0xd3, 0x6f, 0xf7, 0xe6, 0x0f, 0x8a, 0xca, 0xc3, 0x41, 0x2d, 0xfe, 0x73, 0xce, 0x2b, 0xf8, 0x85, 0x6f, 0x02, + 0xb3, 0xc9, 0xd4, 0x3b, 0xf9, 0x26, 0xcf, 0x99, 0x7a, 0x8d, 0x57, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xed, + 0xc8, 0x89, 0x76, 0xca, 0x31, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, + 0x96, 0x78, 0x96, 0xce, 0x2f, 0x27, 0x75, 0xb9, 0xd3, 0x8a, 0xa7, 0x3d, 0xb0, 0xb8, 0xad, 0xc1, 0x0b, 0xe0, 0xde, + 0x62, 0xeb, 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, + 0x40, 0x30, 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, + 0x77, 0xf9, 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0x65, 0x6f, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, + 0x52, 0x3c, 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfc, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xbd, 0x7d, + 0x72, 0x61, 0x20, 0x81, 0xa6, 0x03, 0xf0, 0xe3, 0x55, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, + 0x05, 0xf7, 0xe9, 0x67, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa3, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x3c, + 0xfb, 0xa6, 0x02, 0x72, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, + 0x53, 0x71, 0x75, 0xa9, 0xd3, 0xc5, 0x8b, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, + 0x07, 0xf1, 0xb6, 0xb6, 0xa3, 0x3f, 0x76, 0x10, 0xe9, 0xb8, 0x27, 0x17, 0xea, 0x4b, 0x48, 0x25, 0x17, 0xea, 0x06, + 0x62, 0x17, 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0x75, 0x8d, 0x82, 0x95, 0x80, 0x33, 0xed, 0x1a, 0x0c, 0x36, 0xb0, + 0x6e, 0x59, 0x06, 0x7f, 0xc3, 0x35, 0x4d, 0xe0, 0x86, 0x45, 0xd6, 0x7b, 0x83, 0xad, 0x74, 0x0d, 0x8e, 0x96, 0x89, + 0x73, 0x29, 0xc9, 0xca, 0x16, 0x19, 0x57, 0x8f, 0x42, 0xaa, 0xa6, 0xfb, 0x5b, 0x51, 0x3f, 0x08, 0x91, 0x07, 0xab, + 0x94, 0x45, 0xc5, 0x0a, 0x64, 0xf6, 0xe0, 0x1f, 0x21, 0x23, 0x47, 0x39, 0x70, 0x14, 0xfa, 0x5b, 0x13, 0xe8, 0x3c, + 0x3f, 0x85, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, + 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, + 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, + 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, + 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, + 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, + 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, + 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, + 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, + 0x74, 0xe9, 0x7e, 0x66, 0xc7, 0x5d, 0xe8, 0x0e, 0xb0, 0xf1, 0xb6, 0x41, 0x47, 0xfe, 0xf5, 0x0e, 0x29, 0x75, 0x93, + 0x01, 0xd8, 0x8d, 0x06, 0x38, 0x64, 0xaa, 0x97, 0x22, 0xab, 0x97, 0x32, 0xd5, 0x4b, 0xb2, 0x72, 0x09, 0x16, 0x12, + 0x53, 0xe5, 0x36, 0xb2, 0x72, 0xcb, 0x86, 0xeb, 0xe1, 0x60, 0x6b, 0xc5, 0x65, 0x73, 0x07, 0xf7, 0x85, 0x15, 0x05, + 0xfe, 0xdf, 0xb2, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x35, 0x3a, 0x26, 0xc1, 0x05, 0xe2, 0x9e, 0xdd, 0x82, 0x1d, 0x16, + 0xfe, 0x82, 0xeb, 0xe4, 0x98, 0xed, 0xf0, 0x51, 0xe8, 0x15, 0xec, 0xd6, 0x27, 0xa0, 0x5d, 0xb0, 0x35, 0x40, 0x36, + 0xb6, 0xc5, 0x47, 0x77, 0x87, 0xc3, 0xb5, 0xe7, 0xb3, 0x07, 0xfc, 0x71, 0x7e, 0x77, 0x38, 0xec, 0x3c, 0xa3, 0xde, + 0xbb, 0xe1, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xcd, 0x15, 0x8f, 0x27, 0x83, 0xc1, 0x8d, 0xbf, 0xe0, 0xf5, 0xec, 0x06, + 0xb4, 0x03, 0xe7, 0x0b, 0xa9, 0x6b, 0xf6, 0x6e, 0x79, 0xe6, 0x2d, 0x70, 0x6c, 0x6e, 0xe1, 0xe8, 0xed, 0xf7, 0xbd, + 0x3b, 0x1e, 0x79, 0xb7, 0xa4, 0x62, 0x5a, 0x71, 0xc5, 0xf1, 0xb6, 0xc5, 0xfd, 0x74, 0xc5, 0x43, 0x78, 0x84, 0x55, + 0x99, 0xde, 0x04, 0xef, 0x7d, 0xb6, 0xd2, 0x2c, 0x70, 0x0f, 0x98, 0x63, 0x4d, 0x76, 0x42, 0x33, 0xf1, 0x57, 0xd8, + 0x3f, 0x37, 0xaa, 0x7f, 0x68, 0xfe, 0x97, 0xba, 0x9f, 0xc0, 0xed, 0x8b, 0x2c, 0x48, 0xec, 0x3d, 0xbf, 0x61, 0xf7, + 0xdc, 0xb0, 0xcd, 0x9e, 0x99, 0xb2, 0x4f, 0x94, 0x1a, 0x3f, 0x52, 0xea, 0xda, 0x32, 0xac, 0x64, 0xee, 0xbe, 0x8c, + 0xc0, 0xe1, 0x80, 0xfc, 0x74, 0x87, 0x38, 0x08, 0xad, 0x9b, 0xac, 0xe6, 0x8a, 0x72, 0x2e, 0xb4, 0x65, 0xe6, 0xe5, + 0xc0, 0x62, 0x96, 0x52, 0x68, 0x2c, 0x00, 0x10, 0x4c, 0x0a, 0xad, 0xbd, 0x97, 0x01, 0xe4, 0x04, 0x0d, 0x7f, 0x6c, + 0xae, 0x8a, 0xb2, 0x96, 0x2d, 0x09, 0x51, 0xb6, 0xeb, 0xe1, 0x25, 0x42, 0xa6, 0xf5, 0xfb, 0xe7, 0x44, 0xb2, 0x36, + 0xa9, 0xae, 0x6a, 0xb4, 0x04, 0x54, 0x64, 0x09, 0x98, 0xf8, 0x95, 0xe6, 0x13, 0x80, 0x27, 0x1d, 0x0f, 0xaa, 0xa7, + 0xbc, 0x66, 0x82, 0xc8, 0x36, 0x2a, 0x7f, 0x52, 0xbc, 0x40, 0x32, 0x82, 0xe2, 0x69, 0xad, 0x32, 0x16, 0x86, 0x79, + 0xa0, 0x80, 0xbc, 0x7b, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, + 0xe8, 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x39, 0x89, 0xae, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, + 0x67, 0xd1, 0xd3, 0x6a, 0x3e, 0x21, 0x25, 0xd9, 0xe1, 0x90, 0x8d, 0xaa, 0xba, 0x58, 0x4f, 0x43, 0xf9, 0xd3, 0x43, + 0xf0, 0xf5, 0x82, 0x7a, 0x4d, 0x56, 0xa9, 0x7e, 0x4a, 0x95, 0xf2, 0xa2, 0xe1, 0xa5, 0xff, 0xb4, 0x92, 0xfb, 0x1e, + 0x90, 0xd6, 0xf2, 0x92, 0xcb, 0xf7, 0x23, 0xc4, 0x18, 0xf1, 0x03, 0xaf, 0xe4, 0x11, 0x0b, 0xd5, 0x14, 0xae, 0x79, + 0x84, 0x20, 0x6f, 0x99, 0x0e, 0xfe, 0xd6, 0x13, 0xa7, 0xfb, 0x13, 0xa5, 0x5d, 0x7c, 0x61, 0x51, 0xf7, 0x64, 0x6d, + 0xdd, 0x80, 0x1c, 0x6c, 0x98, 0x2e, 0x0a, 0xb2, 0x4d, 0x69, 0x04, 0x6d, 0xb4, 0x1c, 0xd8, 0x70, 0x2a, 0xb5, 0xe1, + 0xcc, 0x35, 0x04, 0xf7, 0xf9, 0x79, 0x3a, 0x5a, 0xc0, 0x87, 0x54, 0xb7, 0x97, 0xf8, 0xf9, 0xb0, 0xe1, 0x11, 0x90, + 0xd9, 0x11, 0x9f, 0xd9, 0x44, 0xd2, 0x49, 0x9d, 0x2b, 0x60, 0xb7, 0xb3, 0x6b, 0x90, 0x23, 0x66, 0xee, 0x2b, 0x54, + 0xdf, 0xa2, 0x01, 0x57, 0xc6, 0xda, 0xd7, 0x24, 0x63, 0xe1, 0x55, 0x39, 0x0d, 0x07, 0x00, 0x43, 0x97, 0xd1, 0xd7, + 0x96, 0x9b, 0x2c, 0xfb, 0xb9, 0x80, 0x20, 0x88, 0x92, 0x78, 0x7c, 0xc0, 0xfb, 0xb2, 0x1a, 0x6a, 0x94, 0x7c, 0x2c, + 0x1b, 0xa9, 0xf4, 0x4a, 0xf4, 0x77, 0x63, 0x2e, 0x31, 0xe0, 0x75, 0xd5, 0x16, 0x14, 0xce, 0xf3, 0xc3, 0xe1, 0x3c, + 0x1f, 0x19, 0xcf, 0x32, 0x50, 0xad, 0x4c, 0xeb, 0x20, 0x36, 0xf3, 0xc5, 0xc2, 0x5f, 0xec, 0x9c, 0x44, 0x44, 0x41, + 0x60, 0x47, 0xc2, 0x83, 0x48, 0xfd, 0xaa, 0xf2, 0x74, 0xa7, 0xfa, 0x6c, 0xbf, 0xb0, 0x89, 0xf4, 0x82, 0x92, 0xc9, + 0x27, 0xc1, 0x5e, 0xf5, 0x77, 0x10, 0x36, 0x84, 0x37, 0xaf, 0x7a, 0x9d, 0x65, 0x6a, 0x56, 0x82, 0x84, 0x19, 0x73, + 0x04, 0x8f, 0xc3, 0x4e, 0x63, 0x1b, 0x1e, 0x5b, 0x70, 0x74, 0xde, 0x9a, 0xdd, 0xb1, 0x15, 0xbb, 0x55, 0x75, 0x5a, + 0xf0, 0x70, 0x3a, 0xbc, 0x0c, 0x70, 0xf5, 0xad, 0xcf, 0x39, 0xbf, 0xa3, 0x13, 0x6c, 0x3d, 0xe0, 0xd1, 0x44, 0xcc, + 0xd6, 0x4f, 0x23, 0xb5, 0x78, 0xd6, 0x43, 0xbe, 0xa0, 0xf5, 0x27, 0x66, 0x77, 0x26, 0xf9, 0x6e, 0xc0, 0x17, 0x93, + 0xf5, 0xd3, 0x08, 0x5e, 0x7d, 0x0a, 0x56, 0x8c, 0xcc, 0x99, 0x65, 0xeb, 0xa7, 0x11, 0x8e, 0xd9, 0xdd, 0xd3, 0x88, + 0x46, 0x6d, 0x25, 0xf7, 0xa5, 0xdb, 0x06, 0x84, 0x95, 0x5b, 0x16, 0xc3, 0x6b, 0x20, 0x9e, 0x69, 0x23, 0xe9, 0x5a, + 0x1a, 0x7a, 0x63, 0x1e, 0x4e, 0xe3, 0x60, 0x4d, 0xad, 0x90, 0x67, 0x86, 0x98, 0xc5, 0x4f, 0xa3, 0x39, 0x5b, 0x61, + 0x45, 0x36, 0x3c, 0x1e, 0x5c, 0x4e, 0x36, 0x57, 0x7c, 0x0d, 0xe4, 0x67, 0x93, 0x8d, 0xd9, 0xa2, 0x6e, 0xb9, 0x98, + 0x6d, 0x9e, 0x46, 0xf3, 0xc9, 0x0a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x0d, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, + 0x3d, 0xb6, 0x1e, 0x07, 0x77, 0x6c, 0x7d, 0x19, 0xdc, 0xb2, 0xf5, 0x18, 0x88, 0x38, 0xa8, 0xdf, 0xbd, 0x0d, 0x2c, + 0xbe, 0x88, 0xad, 0x2f, 0x4d, 0xda, 0xe6, 0x69, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xc9, 0xbc, 0x15, 0x83, + 0x4b, 0xc8, 0xd2, 0x8b, 0xd9, 0x66, 0x78, 0xc9, 0xd6, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0xee, 0xf8, 0x2d, 0x4b, 0xf8, + 0xaa, 0x89, 0xaf, 0x36, 0xa0, 0x11, 0x3d, 0xca, 0xa0, 0xaf, 0xa0, 0x66, 0xe6, 0xbc, 0xb2, 0x30, 0x2a, 0xf7, 0x2d, + 0x38, 0xa0, 0x20, 0x6d, 0x03, 0x04, 0x49, 0x3c, 0xbb, 0x57, 0xe1, 0xfa, 0x46, 0x0a, 0x03, 0x6e, 0x02, 0x33, 0x60, + 0x60, 0xfa, 0x19, 0xfc, 0xb0, 0xd2, 0x25, 0x42, 0x9c, 0xfd, 0x94, 0x92, 0x64, 0x9e, 0x9f, 0x8a, 0x34, 0x77, 0x0b, + 0xd7, 0x29, 0xcc, 0x8a, 0x02, 0xd5, 0x4f, 0x49, 0x69, 0x60, 0xa1, 0x12, 0x99, 0x4a, 0xc1, 0x2f, 0x9b, 0xf3, 0x28, + 0x3b, 0x46, 0xe7, 0x3a, 0xbf, 0x9c, 0x38, 0xa7, 0x93, 0xbe, 0xff, 0xc0, 0x31, 0x6c, 0x21, 0x03, 0x17, 0xfe, 0xd4, + 0x13, 0xc6, 0xa9, 0x15, 0x88, 0xa9, 0xe4, 0xd9, 0x53, 0xf8, 0x4c, 0x68, 0x75, 0x74, 0xe1, 0xfb, 0x41, 0xa1, 0x4d, + 0xd2, 0x2d, 0x48, 0x52, 0xf0, 0x14, 0x3d, 0xe7, 0xbc, 0x0d, 0x54, 0x8a, 0x11, 0x2d, 0x88, 0xb4, 0xb5, 0xcc, 0x1c, + 0xa4, 0x2d, 0xcd, 0x77, 0x4d, 0xfc, 0x1c, 0x16, 0x70, 0x11, 0x2d, 0x6c, 0x0d, 0x8f, 0xaa, 0x58, 0xb9, 0x37, 0x79, + 0x8e, 0x70, 0x46, 0x97, 0x32, 0x01, 0x70, 0xbd, 0x5f, 0x87, 0xb5, 0xc2, 0x2b, 0x6a, 0x16, 0x79, 0x51, 0xd3, 0x27, + 0x5b, 0xe0, 0x3e, 0x16, 0x25, 0x0a, 0x9c, 0xb5, 0x60, 0xc0, 0x56, 0x58, 0xb2, 0x93, 0xc2, 0xa6, 0x68, 0x09, 0xbd, + 0x3d, 0x7e, 0x3a, 0xa8, 0x99, 0x0c, 0xa0, 0x09, 0xa0, 0xf1, 0xf8, 0x17, 0x80, 0x9a, 0xde, 0xd4, 0x62, 0x5d, 0x05, + 0xa5, 0x52, 0x6e, 0xc2, 0xcf, 0xc0, 0x30, 0xc3, 0x0f, 0x85, 0xdc, 0x26, 0x4a, 0xe4, 0xfc, 0x58, 0x94, 0x62, 0x59, + 0x8a, 0x2a, 0x69, 0x37, 0x14, 0x3c, 0x22, 0xdc, 0x06, 0x8d, 0x99, 0xdb, 0x13, 0x5d, 0xb4, 0x22, 0x94, 0x63, 0xb3, + 0x8e, 0x91, 0x46, 0x99, 0x9d, 0xec, 0x3a, 0x59, 0x68, 0xbf, 0xaf, 0x72, 0xc8, 0x3a, 0x60, 0x8d, 0xe4, 0xeb, 0x35, + 0x87, 0x6e, 0x1b, 0xe5, 0xc5, 0x83, 0xe7, 0x2b, 0x38, 0xcd, 0xf1, 0xc4, 0xee, 0x7a, 0xdd, 0x29, 0x12, 0xf1, 0x0a, + 0x27, 0x55, 0x3e, 0x92, 0x85, 0xe3, 0xce, 0x9d, 0xd6, 0x62, 0x55, 0xb9, 0xac, 0xa7, 0x16, 0x47, 0x04, 0x3e, 0x95, + 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, 0x11, + 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0x8b, 0x5c, 0x0f, + 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, 0x3c, + 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, 0x5d, + 0x28, 0xe7, 0x4c, 0xc5, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, 0x8c, + 0x8e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x96, 0xab, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, 0xc6, + 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, 0x98, + 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x7b, 0x59, 0x14, 0x38, 0x80, 0xab, + 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0xf6, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, 0xcc, + 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, 0xb4, + 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x8f, 0x5f, 0xa7, + 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7e, 0x41, 0x11, 0x17, 0x35, 0xb8, 0xf2, + 0x4e, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, 0x0e, + 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x44, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xcc, 0x59, 0x35, 0x5a, 0xa8, 0xcc, 0x08, + 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xe3, 0x3d, 0xba, 0xab, 0xce, 0x32, + 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, 0x77, + 0x9d, 0xe5, 0xab, 0x9b, 0xad, 0xa1, 0xa8, 0xd4, 0x4a, 0x52, 0x1c, 0x64, 0xb8, 0x6e, 0x2b, 0x1f, 0x2e, 0x2e, 0xa0, + 0x67, 0x8c, 0x44, 0xe6, 0xf9, 0x13, 0xf9, 0x12, 0x9c, 0x33, 0xce, 0x0a, 0x81, 0x09, 0x63, 0xf5, 0xae, 0xb5, 0x54, + 0x1a, 0x52, 0x8c, 0x1d, 0x8d, 0xb2, 0xac, 0xb2, 0x74, 0x99, 0xad, 0x25, 0x6c, 0x59, 0x4e, 0x6e, 0x61, 0xcb, 0x4c, + 0x56, 0xf3, 0x7d, 0xc5, 0x1d, 0x94, 0x6f, 0xb6, 0xce, 0xf8, 0x5e, 0x22, 0x7b, 0xb7, 0x81, 0x12, 0x5e, 0x8c, 0xfe, + 0x82, 0xf4, 0xdb, 0x0c, 0xe3, 0x94, 0xdb, 0x4a, 0x5a, 0x80, 0xd3, 0x3f, 0x1c, 0xde, 0x57, 0x18, 0x34, 0x38, 0xc2, + 0x38, 0xb2, 0x7e, 0xff, 0xb6, 0xf2, 0x6a, 0x4c, 0xd4, 0xf1, 0x59, 0xfd, 0x7e, 0x45, 0x0f, 0xa7, 0xd5, 0x68, 0x95, + 0x6e, 0x91, 0x9d, 0xd0, 0xc6, 0xca, 0x0f, 0x6a, 0x05, 0xcc, 0xde, 0xfa, 0x7c, 0x3a, 0x00, 0x1d, 0x0b, 0x90, 0x68, + 0x36, 0x13, 0x89, 0x39, 0xe9, 0x9e, 0x84, 0xc7, 0x07, 0x16, 0x38, 0xc0, 0x54, 0xfc, 0x9f, 0xc2, 0x9b, 0x81, 0x0d, + 0x1a, 0x25, 0xfa, 0x1a, 0x5d, 0xd5, 0xe6, 0x46, 0xc7, 0x4b, 0x4f, 0x21, 0x91, 0x15, 0xac, 0x9a, 0xfb, 0x72, 0x03, + 0xa7, 0x3d, 0xd4, 0x1c, 0x2a, 0x4b, 0xf0, 0xb7, 0x5f, 0xe6, 0x87, 0xc3, 0x3a, 0x83, 0xc2, 0x76, 0x6b, 0xa1, 0xbd, + 0x31, 0x4b, 0x35, 0x54, 0x84, 0x83, 0xce, 0x57, 0x62, 0x56, 0x8f, 0xe8, 0xef, 0xf9, 0xe1, 0xb0, 0x22, 0x30, 0xe0, + 0xb0, 0x94, 0x99, 0x68, 0xa1, 0x58, 0x5a, 0x67, 0x33, 0xaa, 0x03, 0x0f, 0x4c, 0xcc, 0x59, 0xb8, 0x03, 0xd0, 0x26, + 0xb5, 0x0a, 0xf4, 0x2a, 0xa2, 0x9f, 0xb8, 0x5f, 0xdb, 0xaf, 0xd7, 0x23, 0xb3, 0x74, 0xe4, 0xc6, 0x58, 0x00, 0x70, + 0xe0, 0x79, 0x4d, 0xf2, 0x9c, 0x7c, 0x0d, 0xed, 0x9e, 0x5c, 0xc8, 0x9f, 0xa0, 0x6c, 0xe1, 0xb9, 0x6a, 0x5a, 0x59, + 0xac, 0xb8, 0xaa, 0x5e, 0x5d, 0xf0, 0xca, 0x64, 0x5a, 0xa5, 0x95, 0xa8, 0x94, 0x60, 0x40, 0x5d, 0xe2, 0xb5, 0xa6, + 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x7e, 0x69, 0x1c, 0x3e, + 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0x2b, 0x1f, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, 0xc5, 0xc4, + 0xee, 0xd0, 0xbc, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, 0x01, 0x2f, + 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x2a, 0x26, 0xc0, 0x0f, + 0x4a, 0xad, 0xe9, 0xbd, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, 0xe7, 0xe3, + 0xf9, 0xa5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x79, 0xab, 0x7f, 0x98, 0xea, 0x5b, 0xe8, 0x4e, + 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, 0x1c, 0xec, + 0x0d, 0x70, 0xe2, 0x97, 0x87, 0x83, 0xb8, 0xca, 0x7d, 0x76, 0xde, 0x35, 0xb2, 0x72, 0x00, 0x2b, 0x88, 0x82, 0x71, + 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xd5, 0xf8, 0xf8, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0xe4, 0x4f, 0x9f, + 0x03, 0x69, 0x59, 0xbf, 0x1f, 0xbd, 0xb8, 0x9c, 0x3e, 0x1f, 0x46, 0x01, 0x38, 0x76, 0xd9, 0xcb, 0xcb, 0x98, 0xaf, + 0x2e, 0x99, 0x65, 0x0a, 0x8b, 0x7c, 0x33, 0xa0, 0xba, 0x64, 0xb5, 0x74, 0xbd, 0x02, 0x2c, 0x5d, 0x7e, 0xf3, 0x10, + 0xa6, 0x06, 0x34, 0xb2, 0xe6, 0xee, 0x34, 0xd7, 0x02, 0xa5, 0x9e, 0xf7, 0x33, 0x43, 0xbe, 0x2e, 0x83, 0xae, 0x20, + 0xdd, 0xf3, 0x88, 0xf4, 0x72, 0x2f, 0x9d, 0xee, 0xf7, 0xa5, 0x00, 0x4b, 0x7d, 0x29, 0x3e, 0x83, 0xc2, 0xa2, 0xf1, + 0x8d, 0x00, 0x6d, 0x0d, 0xd5, 0xb4, 0x57, 0x8a, 0xaa, 0x17, 0xf4, 0x4a, 0xf1, 0xb9, 0xa7, 0x87, 0xca, 0x7c, 0x59, + 0x3a, 0xfa, 0x9f, 0x50, 0x73, 0xc1, 0x09, 0x31, 0x13, 0x73, 0x00, 0x95, 0xa0, 0x8d, 0x6f, 0x75, 0xb4, 0xf1, 0xa9, + 0x5e, 0xc5, 0x4d, 0x9f, 0xd7, 0xd6, 0x32, 0x27, 0x84, 0x4d, 0xf7, 0x12, 0xa0, 0x22, 0xaf, 0x84, 0x47, 0xb0, 0xfc, + 0xf2, 0x87, 0x3c, 0x5d, 0x21, 0x5a, 0xc7, 0x3d, 0xcb, 0x5c, 0x1a, 0xfb, 0x37, 0x06, 0xd3, 0xd7, 0xb7, 0xdb, 0x22, + 0x3f, 0x35, 0x31, 0x61, 0x3d, 0x56, 0xf4, 0xcd, 0xbb, 0x70, 0x25, 0x50, 0xe0, 0x50, 0x22, 0xb1, 0x4d, 0x15, 0x8a, + 0x78, 0x90, 0xf4, 0xe9, 0xa2, 0xf5, 0x69, 0x80, 0xa9, 0xb5, 0x1c, 0x98, 0x43, 0xb8, 0x8a, 0x0b, 0x1f, 0x3d, 0x7d, + 0x8b, 0x59, 0x38, 0x9f, 0x78, 0x1f, 0xbd, 0x62, 0x64, 0x3e, 0xee, 0xa3, 0x52, 0x49, 0xff, 0x3c, 0x1c, 0x66, 0xd5, + 0xdc, 0x77, 0xe8, 0x23, 0x3d, 0x54, 0xb9, 0xa0, 0xec, 0x8d, 0x31, 0x89, 0x40, 0x69, 0x8c, 0xf7, 0x71, 0x70, 0x9c, + 0xf7, 0x69, 0x00, 0xa9, 0x7d, 0xe2, 0x3d, 0x29, 0x39, 0x3c, 0xe7, 0x98, 0x13, 0x4a, 0x2b, 0xc2, 0x2a, 0xbe, 0xc8, + 0x50, 0xae, 0x3b, 0xa5, 0x60, 0x92, 0x43, 0x82, 0xe1, 0xaf, 0x9a, 0x37, 0xb1, 0x02, 0x61, 0xd7, 0xcc, 0xab, 0xd1, + 0x93, 0x2a, 0x09, 0x4b, 0x01, 0x47, 0x65, 0xe6, 0x19, 0xf6, 0x86, 0x27, 0x86, 0x91, 0x83, 0xe5, 0xfe, 0xa8, 0x4e, + 0x44, 0xee, 0xd1, 0x05, 0x46, 0x65, 0xe1, 0x79, 0x43, 0x57, 0x1a, 0x54, 0x92, 0x1d, 0x7f, 0xc5, 0x35, 0xa0, 0xb6, + 0xc6, 0x88, 0xa1, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, 0x95, 0xdc, 0xf5, + 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, 0x2c, 0x85, 0x23, + 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, 0x42, 0x9a, 0x6c, + 0x5f, 0xcf, 0xdf, 0x1b, 0x41, 0x56, 0x6e, 0x39, 0xc7, 0xc3, 0xe2, 0x1b, 0x67, 0x5f, 0xe5, 0xe4, 0x29, 0x66, 0x19, + 0xe9, 0x9d, 0x62, 0x5e, 0xc0, 0x9f, 0xca, 0x52, 0x9f, 0xa3, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, 0x97, 0xde, 0xa6, + 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0xf7, 0xf1, 0x48, 0x9e, 0x61, 0x1b, 0x96, 0xb0, 0xd0, 0x2a, 0x18, 0x03, 0x48, + 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x0e, 0x87, 0xf3, 0x8d, 0x39, 0x4b, 0xf6, 0xe0, 0xfa, 0xca, 0x13, 0xf3, 0x0e, + 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x1b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, 0x62, 0xad, 0x63, + 0xa9, 0xac, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0xbf, 0x77, 0x83, 0xab, 0x6b, 0x63, 0x50, + 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0xb3, 0x9c, 0x7c, 0xf9, 0xad, 0x9d, 0x03, 0x82, + 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, 0x33, 0xd8, 0xc4, + 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, 0xab, 0x85, 0x48, + 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, 0x5e, 0x27, 0x68, + 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, 0x7b, 0x99, 0x13, + 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, 0x74, 0x28, 0x59, + 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, 0x0a, 0x5c, 0x08, + 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xf9, 0xb4, 0x90, 0xa6, 0x81, 0x7c, 0x5a, 0x39, 0xe6, + 0x81, 0x9d, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0xe5, 0x1c, 0xab, 0x88, 0xde, 0xe7, 0x1f, 0x2a, 0x7b, + 0xfa, 0x20, 0xc2, 0x46, 0x05, 0x1a, 0x4b, 0x89, 0xb1, 0x91, 0xe3, 0xdf, 0x12, 0x65, 0x43, 0x86, 0x80, 0x10, 0xd2, + 0x46, 0x4e, 0x3f, 0xac, 0x2f, 0x6f, 0x33, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, 0xa9, 0x47, 0x3c, + 0x5e, 0x6b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, 0x28, 0x17, 0x3c, + 0xe7, 0x15, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xc8, 0xe9, 0xf3, 0x15, 0xf0, 0x4c, 0x40, 0xa0, 0x63, + 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0x37, 0x48, 0x94, 0xfa, 0x9a, + 0x94, 0xa4, 0xd7, 0xa2, 0xc6, 0x2b, 0xb1, 0x8a, 0x48, 0x20, 0x43, 0x0d, 0x11, 0xab, 0xea, 0xa9, 0x7b, 0x55, 0x4c, + 0x06, 0x83, 0xca, 0x97, 0xd3, 0x13, 0x6f, 0x68, 0xa8, 0xbc, 0xeb, 0x8a, 0x76, 0x7a, 0xa2, 0x95, 0xf2, 0x16, 0xd2, + 0x12, 0x34, 0x0d, 0x23, 0xcd, 0xa1, 0xd4, 0x95, 0x74, 0x37, 0x06, 0xf1, 0x25, 0x13, 0x3d, 0xdb, 0xa9, 0x1d, 0xa5, + 0x2d, 0x69, 0x0f, 0x21, 0x3d, 0x77, 0xc9, 0xc7, 0x2c, 0xe4, 0xea, 0x4e, 0x39, 0x29, 0xaf, 0x42, 0x74, 0x72, 0xdf, + 0x63, 0x48, 0x04, 0xfa, 0x9c, 0x63, 0x58, 0x17, 0x0d, 0x75, 0x0e, 0x2b, 0xc4, 0x6c, 0xa1, 0x84, 0xf9, 0x92, 0xf1, + 0x54, 0x32, 0x68, 0x00, 0x64, 0xc0, 0x67, 0x2f, 0x03, 0xcb, 0x5f, 0x41, 0xfc, 0x68, 0xe3, 0xc3, 0xe1, 0xcf, 0x9a, + 0x42, 0x6c, 0xff, 0x84, 0xcd, 0x10, 0x1e, 0xd5, 0x03, 0x9e, 0xf9, 0x26, 0x4e, 0xd0, 0x0a, 0x48, 0xca, 0xec, 0x68, + 0x22, 0x7b, 0xd5, 0x43, 0x38, 0x95, 0x15, 0xa8, 0xa3, 0xac, 0xb3, 0x12, 0x7e, 0x84, 0xa9, 0x6e, 0x25, 0xd6, 0x02, + 0x6d, 0xae, 0x56, 0xac, 0x05, 0x70, 0xe0, 0xe7, 0x10, 0x3c, 0x91, 0xcf, 0xc1, 0xc5, 0xa0, 0x00, 0x9f, 0x03, 0xe0, + 0x45, 0xee, 0xc2, 0x83, 0x79, 0x64, 0x59, 0x8d, 0x30, 0x1c, 0x55, 0xc4, 0xfa, 0x35, 0xdb, 0x91, 0x0f, 0xdc, 0x8e, + 0xf1, 0xb9, 0xf6, 0x58, 0xb2, 0x1c, 0x8c, 0x32, 0xf7, 0x6a, 0x89, 0x9e, 0x37, 0x69, 0xdc, 0x8c, 0x9e, 0xec, 0x6b, + 0xf9, 0xbf, 0xa0, 0x97, 0x41, 0x7f, 0x0b, 0xb7, 0xbc, 0xe6, 0x77, 0x0b, 0x22, 0xcd, 0xf4, 0x0a, 0x22, 0x65, 0xd4, + 0x88, 0x8c, 0x21, 0x6c, 0x52, 0xdd, 0xdc, 0x26, 0xd5, 0x85, 0x80, 0xa7, 0x23, 0x52, 0x5d, 0x0b, 0x69, 0x23, 0x9f, + 0xd6, 0x81, 0x8c, 0x45, 0x7a, 0xf7, 0xc3, 0xdf, 0x5e, 0x7e, 0x7a, 0xfb, 0xcb, 0x0f, 0x8b, 0xb7, 0xef, 0xde, 0xbc, + 0x7d, 0xf7, 0xf6, 0xd3, 0x6f, 0x04, 0xe1, 0x31, 0x15, 0x2a, 0xc3, 0x87, 0xf7, 0x37, 0x6f, 0x9d, 0x0c, 0xb6, 0x37, + 0x43, 0xd6, 0xbe, 0x91, 0x83, 0x21, 0x10, 0xd9, 0x20, 0x64, 0x90, 0x9d, 0xda, 0xf6, 0x67, 0x62, 0x8e, 0xb1, 0x77, + 0x02, 0x93, 0x2d, 0xe0, 0x1c, 0xcb, 0xbc, 0x64, 0x44, 0xae, 0x0a, 0xad, 0x1f, 0xd0, 0x82, 0x6b, 0x70, 0x91, 0x49, + 0xf3, 0xbb, 0x5f, 0x08, 0x62, 0x9f, 0x56, 0x52, 0xee, 0xab, 0x6d, 0xcd, 0xf3, 0xed, 0xfd, 0x5e, 0xc2, 0xf9, 0xcf, + 0xa5, 0x11, 0xb5, 0x00, 0x07, 0xe0, 0x73, 0xf8, 0xe3, 0x4a, 0x5b, 0xd2, 0x64, 0x16, 0xed, 0x67, 0x0c, 0x41, 0x97, + 0x06, 0x1f, 0xc4, 0x1e, 0x79, 0xa9, 0x4f, 0x16, 0x12, 0xb8, 0x23, 0x86, 0x4f, 0x2b, 0x82, 0x5e, 0x31, 0xa2, 0xb8, + 0xe4, 0x0a, 0x95, 0x52, 0xf2, 0x6f, 0x94, 0x5d, 0x54, 0xc8, 0x59, 0xc1, 0xee, 0x15, 0x39, 0x32, 0x7e, 0x10, 0x4c, + 0x7c, 0x39, 0xb8, 0xff, 0x12, 0xef, 0x70, 0xa6, 0x38, 0x92, 0x13, 0xfe, 0x90, 0x61, 0x60, 0x7f, 0x0e, 0x3e, 0xaf, + 0x0e, 0xf3, 0xf2, 0x46, 0x9f, 0x72, 0x4b, 0x3e, 0x9e, 0x2c, 0xaf, 0xc0, 0x60, 0xbf, 0x54, 0xcd, 0x5d, 0xf3, 0x7a, + 0xb6, 0x9c, 0xb3, 0xfd, 0x2c, 0x9a, 0x07, 0x77, 0x6c, 0x96, 0xcd, 0x83, 0x55, 0xc3, 0xd7, 0xec, 0x96, 0xaf, 0xad, + 0xaa, 0xad, 0xed, 0xaa, 0x4d, 0x36, 0xfc, 0x16, 0x24, 0x84, 0x9b, 0xcc, 0x03, 0xde, 0xe3, 0x3b, 0x9f, 0x6d, 0x40, + 0xa2, 0x5d, 0xb1, 0x0d, 0x5c, 0xc4, 0xd6, 0xfc, 0x87, 0xca, 0xdb, 0xb0, 0x92, 0x9d, 0x8f, 0x59, 0x8e, 0xf3, 0xcf, + 0x87, 0x07, 0xb4, 0x17, 0xea, 0x67, 0x97, 0xea, 0xd9, 0x44, 0xd9, 0xcd, 0x36, 0xa3, 0xc5, 0x7d, 0x5a, 0x6d, 0xc2, + 0x0c, 0x3d, 0xcb, 0xe1, 0xa3, 0xad, 0x14, 0xfc, 0xf4, 0x02, 0xbf, 0x64, 0x47, 0x6d, 0xa5, 0x6d, 0xbb, 0x2a, 0xb1, + 0x15, 0xb4, 0x28, 0xb2, 0x5a, 0xe1, 0x81, 0x39, 0x7f, 0x01, 0x0b, 0x18, 0x7b, 0x8e, 0x73, 0x5e, 0xfb, 0x23, 0x64, + 0xbc, 0x77, 0x00, 0xd0, 0x32, 0xc7, 0x01, 0x1e, 0xb1, 0x62, 0x14, 0x0d, 0xde, 0xf9, 0xa5, 0xb2, 0x5a, 0x69, 0x4e, + 0x42, 0xdb, 0x88, 0x55, 0xcb, 0x91, 0xaa, 0x19, 0x91, 0x3e, 0x48, 0xcf, 0xfb, 0x1e, 0x51, 0x0d, 0xf6, 0x64, 0x5e, + 0x07, 0xf6, 0xe9, 0x55, 0x6b, 0x55, 0x77, 0x7e, 0x4f, 0x95, 0x2e, 0x39, 0xb2, 0xe5, 0xa7, 0xcb, 0xf0, 0x41, 0xfd, + 0x29, 0xb9, 0x3e, 0x14, 0x38, 0xc2, 0x63, 0x15, 0x70, 0xbe, 0x5e, 0x89, 0x76, 0x27, 0xc2, 0xae, 0x5c, 0x02, 0x42, + 0x7c, 0x49, 0xd3, 0x1c, 0x8f, 0x23, 0x9a, 0x88, 0xb0, 0x89, 0xd1, 0x5f, 0xd8, 0x7d, 0x28, 0xb1, 0x9c, 0xe7, 0x1a, + 0x94, 0x5c, 0x32, 0x78, 0x4f, 0xda, 0x6b, 0xd0, 0x2c, 0xaf, 0x4a, 0x4d, 0x26, 0x72, 0x50, 0x3e, 0x1c, 0x0a, 0xd8, + 0x4b, 0x8d, 0x9f, 0x26, 0xfc, 0x84, 0xe5, 0xad, 0xbd, 0x35, 0xa5, 0xa8, 0xa4, 0x01, 0x2a, 0xf0, 0x31, 0x83, 0xff, + 0xdd, 0x19, 0x62, 0xc1, 0x14, 0x1d, 0x3f, 0x9c, 0x89, 0xb9, 0xf5, 0xdc, 0x2a, 0xeb, 0x28, 0x5b, 0xa3, 0x9c, 0x80, + 0x7f, 0x4b, 0x75, 0x9c, 0x24, 0xc2, 0xa9, 0xf7, 0x88, 0x8b, 0xba, 0x97, 0x43, 0xd4, 0x0d, 0x7b, 0x5b, 0xe9, 0x60, + 0xcb, 0x69, 0x1a, 0x1c, 0x89, 0x5f, 0xa9, 0xcf, 0xde, 0x67, 0x16, 0x8f, 0x3a, 0xb2, 0x11, 0x25, 0x69, 0x1c, 0x8b, + 0x1c, 0xb6, 0xf7, 0x85, 0xdc, 0xff, 0xfb, 0x7d, 0x08, 0x27, 0xad, 0x82, 0xa4, 0xf4, 0x04, 0x22, 0xc2, 0xd1, 0xe1, + 0x47, 0x84, 0x27, 0x52, 0x55, 0xf8, 0xa4, 0x3e, 0x71, 0x63, 0x76, 0x2f, 0xcc, 0x51, 0xbd, 0x05, 0x18, 0xc6, 0x7a, + 0x6b, 0x11, 0x92, 0x68, 0xa5, 0x19, 0x6d, 0x3d, 0x20, 0x46, 0xbc, 0x5f, 0x5b, 0x64, 0x30, 0xd6, 0x96, 0x44, 0x02, + 0xf8, 0x1d, 0x09, 0x19, 0xda, 0x36, 0x02, 0x33, 0x86, 0xb7, 0xb3, 0xe2, 0xd2, 0x75, 0xd8, 0xe6, 0x1c, 0xbe, 0x90, + 0x85, 0x66, 0x1d, 0x51, 0x9a, 0x20, 0xe4, 0x1f, 0x70, 0xb2, 0x50, 0x18, 0xcd, 0xeb, 0xa3, 0x74, 0x92, 0x58, 0xdf, + 0x77, 0x95, 0x0a, 0x36, 0x9b, 0x1b, 0xd4, 0x97, 0x1d, 0x25, 0xbf, 0x02, 0x27, 0x1d, 0x27, 0x59, 0xe4, 0x20, 0x6a, + 0x51, 0x39, 0x37, 0x49, 0x58, 0xda, 0xd5, 0xa9, 0x36, 0xeb, 0x75, 0x51, 0xd6, 0xd5, 0x6b, 0x11, 0x29, 0x7a, 0x1f, + 0xf5, 0xe8, 0x89, 0x84, 0x54, 0x68, 0x55, 0x6a, 0x97, 0x47, 0xe0, 0xb6, 0xa9, 0x15, 0xdb, 0x72, 0x09, 0x4b, 0xd4, + 0xf8, 0x4f, 0xd0, 0x47, 0xb9, 0x78, 0x90, 0x01, 0x1a, 0x1d, 0x4f, 0xcd, 0x5b, 0x8f, 0xbc, 0x72, 0x94, 0x5f, 0x5a, + 0x6d, 0xd2, 0x2f, 0x80, 0xcc, 0x68, 0xff, 0x68, 0x29, 0x81, 0xcc, 0xc0, 0x4c, 0x5a, 0x1a, 0x12, 0x39, 0x8a, 0x59, + 0x9a, 0xff, 0x81, 0x2b, 0xb6, 0x42, 0xa4, 0x61, 0x35, 0xf7, 0xf8, 0xcb, 0xca, 0xab, 0xe5, 0x5a, 0x66, 0x9a, 0x9b, + 0x25, 0x8e, 0x15, 0x8b, 0x8b, 0x7a, 0x5d, 0x89, 0x2c, 0x10, 0xe2, 0x08, 0xd3, 0x58, 0x4f, 0xbd, 0x51, 0x5a, 0x7d, + 0x40, 0x42, 0x99, 0x1f, 0xb0, 0xb7, 0x63, 0xaf, 0x07, 0x59, 0x88, 0x63, 0xcb, 0xc1, 0x66, 0xeb, 0x7d, 0x2a, 0x53, + 0x11, 0x9f, 0xd5, 0xc5, 0xd9, 0xa6, 0x12, 0x67, 0x75, 0x22, 0xce, 0xbe, 0x83, 0x9c, 0xdf, 0x9d, 0x51, 0xd1, 0x67, + 0x0f, 0x69, 0x9d, 0x14, 0x9b, 0x9a, 0x9e, 0xbc, 0xc1, 0x32, 0xbe, 0x3b, 0x23, 0xae, 0x9a, 0x33, 0x1a, 0xc9, 0x78, + 0x74, 0xf6, 0x21, 0x03, 0x92, 0xd7, 0xb3, 0x74, 0x05, 0x83, 0x77, 0x16, 0xe6, 0xf1, 0x59, 0x29, 0xee, 0xc0, 0xe2, + 0x54, 0x76, 0xbe, 0x07, 0x19, 0x56, 0xe1, 0x1f, 0xe2, 0x0c, 0xa0, 0x5d, 0xcf, 0xd2, 0xfa, 0x2c, 0xad, 0xce, 0xf2, + 0xa2, 0x3e, 0x53, 0x52, 0x38, 0x84, 0xf1, 0xc3, 0x7b, 0xfa, 0xca, 0x2e, 0x6f, 0xb3, 0xb8, 0xcb, 0x22, 0x7f, 0x8a, + 0x5e, 0x45, 0xc4, 0xa4, 0x51, 0x09, 0xaf, 0xdd, 0xdf, 0x36, 0xf7, 0x0f, 0xaf, 0x1b, 0xbb, 0x9f, 0xdd, 0x31, 0xa2, + 0x0b, 0xea, 0xf1, 0x4a, 0x52, 0x2a, 0x28, 0x20, 0x70, 0xa2, 0x59, 0xe3, 0xc1, 0x1d, 0x07, 0xbc, 0x1a, 0xd8, 0x92, + 0xad, 0x7d, 0xfe, 0x22, 0x96, 0x61, 0xda, 0x9b, 0x00, 0xff, 0x2a, 0x7b, 0xd3, 0x75, 0xb0, 0xc4, 0xfb, 0x16, 0xb2, + 0x0d, 0xbd, 0x7d, 0xcd, 0x5f, 0x7a, 0xb9, 0xfa, 0x9b, 0xfd, 0x13, 0x80, 0x30, 0x20, 0x66, 0xd5, 0x47, 0x13, 0xf7, + 0xce, 0xca, 0xb2, 0x73, 0xb2, 0xec, 0x7a, 0xe8, 0xd7, 0x24, 0x46, 0xa5, 0x95, 0xa5, 0x74, 0xb2, 0x94, 0x90, 0x05, + 0x7c, 0x62, 0x34, 0xb5, 0x11, 0x40, 0xd8, 0x8e, 0x52, 0xf9, 0x42, 0xe5, 0x45, 0x14, 0xce, 0x09, 0x9e, 0x27, 0x62, + 0x74, 0x6f, 0x25, 0x03, 0x86, 0x43, 0x08, 0xe6, 0xa0, 0x2d, 0xf6, 0x86, 0x6e, 0x22, 0xfe, 0x7a, 0x53, 0x94, 0x6f, + 0x63, 0xf2, 0x29, 0xd8, 0x9d, 0x7c, 0x5c, 0xc2, 0xe3, 0xf2, 0xe4, 0xe3, 0x10, 0x3d, 0x12, 0x4e, 0x3e, 0x06, 0xdf, + 0x23, 0x39, 0xaf, 0xbb, 0x1e, 0x27, 0xc8, 0x2d, 0xa4, 0xfb, 0xdb, 0x31, 0x09, 0xd0, 0xbc, 0x86, 0xe5, 0xa8, 0xa9, + 0xb8, 0x66, 0x66, 0x8c, 0xe7, 0x8d, 0xde, 0x1f, 0x3b, 0xde, 0x32, 0x85, 0x62, 0x16, 0xf3, 0x1a, 0x7e, 0xcf, 0xaa, + 0x40, 0xdd, 0xf5, 0x36, 0xc9, 0x2d, 0xb3, 0x7a, 0x8e, 0x76, 0xdf, 0xf7, 0x75, 0x22, 0xa8, 0xfd, 0x1d, 0xf6, 0x3c, + 0xb3, 0xde, 0x55, 0x31, 0x70, 0xa9, 0x92, 0x1d, 0x32, 0x55, 0x4d, 0x0f, 0x54, 0x4a, 0x83, 0xa7, 0x97, 0xd6, 0xe5, + 0x4b, 0xa5, 0x8d, 0x3c, 0xd3, 0xfc, 0x06, 0xf0, 0x62, 0xea, 0xb2, 0xd8, 0x7d, 0x75, 0x5f, 0xc1, 0x6d, 0xbc, 0xdf, + 0x5f, 0x56, 0x9e, 0xf9, 0x89, 0x0b, 0xc0, 0xde, 0x54, 0x68, 0x9d, 0x40, 0xa9, 0x61, 0x1d, 0xbe, 0x4a, 0x44, 0xf4, + 0x47, 0xbb, 0x5c, 0x67, 0xae, 0x03, 0x46, 0x14, 0xf1, 0xdb, 0x78, 0xf4, 0x07, 0x28, 0xae, 0x8d, 0x3d, 0x20, 0xac, + 0x43, 0x42, 0x9f, 0x11, 0x80, 0xd4, 0x63, 0x8e, 0x12, 0xd0, 0xac, 0x68, 0xee, 0x98, 0xfc, 0x5c, 0x5f, 0x29, 0xfd, + 0xfd, 0xb2, 0xf2, 0xc8, 0x9c, 0xd2, 0x36, 0xd3, 0x58, 0xad, 0xa9, 0x04, 0xc2, 0x2b, 0x2a, 0x59, 0x85, 0xcf, 0xe6, + 0x8d, 0xe8, 0xf7, 0xe5, 0x11, 0x9e, 0x56, 0x3f, 0x6c, 0x31, 0xbe, 0x15, 0x10, 0x8d, 0x04, 0x40, 0x3f, 0x01, 0xcc, + 0x8b, 0x6c, 0x66, 0xf7, 0x71, 0x40, 0x95, 0x12, 0x4d, 0xe3, 0x6c, 0x9e, 0xdf, 0xd2, 0x9b, 0xb2, 0x83, 0x4e, 0x9d, + 0x2a, 0x70, 0xc1, 0x55, 0xc9, 0x78, 0x65, 0x3d, 0x91, 0xcf, 0x6f, 0x6e, 0x37, 0x69, 0x16, 0xbf, 0x2f, 0xff, 0x89, + 0x63, 0xab, 0xeb, 0xf0, 0xc8, 0xd4, 0xe9, 0xda, 0x79, 0xa4, 0xb5, 0x17, 0x02, 0x22, 0xda, 0x35, 0xd4, 0x7a, 0x61, + 0xa1, 0x47, 0x7a, 0x22, 0x9c, 0x93, 0x44, 0x4d, 0x3b, 0xd0, 0xd2, 0x08, 0x7d, 0x7d, 0xcd, 0xe9, 0x2f, 0x0c, 0xd6, + 0x3e, 0x1f, 0x33, 0x20, 0x2b, 0xd1, 0x8f, 0xd5, 0x43, 0x63, 0x33, 0x87, 0x9e, 0xb5, 0x2a, 0xcf, 0xbc, 0xea, 0x70, + 0x40, 0x7c, 0x18, 0xfd, 0x25, 0xbf, 0xdf, 0x7f, 0x4d, 0xf3, 0x8f, 0x09, 0x35, 0x7e, 0xb6, 0x19, 0xa0, 0x6b, 0xdf, + 0x95, 0x07, 0xa2, 0x9e, 0x6b, 0x95, 0x20, 0xc4, 0x1b, 0xc4, 0x44, 0x33, 0x62, 0x0e, 0x4e, 0x3b, 0xd4, 0xfc, 0x93, + 0xd4, 0x80, 0x10, 0x25, 0x5e, 0xc7, 0x94, 0x05, 0x39, 0x6d, 0xe2, 0x48, 0x3f, 0x0a, 0x27, 0xf2, 0xa3, 0xa8, 0x8a, + 0xec, 0x1e, 0x2e, 0x18, 0x4c, 0xbd, 0xa7, 0xfd, 0x12, 0xfd, 0x96, 0x70, 0xe4, 0x1c, 0xad, 0x0a, 0x41, 0xe4, 0x84, + 0xb0, 0xd6, 0x10, 0x26, 0x88, 0x0d, 0xe2, 0x65, 0xdf, 0x25, 0x19, 0x8e, 0x14, 0x5c, 0xd6, 0xb1, 0x63, 0xcc, 0xd5, + 0x51, 0xf5, 0x1a, 0xc0, 0x78, 0xe5, 0x08, 0x9a, 0x8d, 0x22, 0xbb, 0x84, 0xa8, 0x22, 0xc7, 0x13, 0x50, 0x3b, 0x28, + 0x8d, 0xcd, 0xf4, 0x7c, 0x1c, 0xe4, 0xa3, 0x45, 0x85, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x73, 0xd5, 0xcf, + 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x8a, 0xe9, 0x72, + 0x60, 0xdc, 0x37, 0xbc, 0xa2, 0x38, 0xc3, 0x8f, 0x1e, 0x6c, 0x71, 0xfe, 0x74, 0x43, 0xed, 0xc7, 0xdc, 0xa8, 0x87, + 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, 0xfc, 0x43, + 0x99, 0xae, 0x52, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, 0xa2, 0xac, + 0xdf, 0x87, 0xdf, 0x57, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, 0x93, 0x41, + 0x0d, 0xda, 0xf0, 0x0d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, 0xec, 0x4f, + 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xe3, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xc7, 0x97, 0xfc, 0x06, 0xbd, + 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, 0x8f, 0x51, + 0xc9, 0x62, 0x4b, 0x8f, 0x55, 0xd1, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x05, 0xc1, 0x12, 0x18, + 0x17, 0xb1, 0xe6, 0x9b, 0x41, 0xce, 0xe2, 0xd9, 0x66, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1c, 0x0a, 0x09, 0x36, 0x93, + 0xcd, 0xd6, 0x73, 0xb6, 0xf6, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, 0x35, 0x58, + 0xad, 0xa6, 0x6c, 0x55, 0x53, 0x76, 0x4e, 0x53, 0x8e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, 0x88, 0x4d, + 0xa2, 0xab, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, 0x50, 0x85, + 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, 0xbe, 0xa5, + 0x8e, 0x7b, 0x94, 0x6d, 0xfe, 0x2e, 0x76, 0x41, 0x88, 0xdc, 0x8d, 0x3b, 0xf5, 0x33, 0xe2, 0xbd, 0xdd, 0x11, 0xc6, + 0x4f, 0x76, 0xdc, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8b, 0x79, 0x35, 0x49, 0x50, 0xcb, 0x92, 0xf8, 0x1b, + 0x9e, 0x0c, 0x72, 0xb6, 0x04, 0x0f, 0xda, 0x39, 0xcb, 0x00, 0x7f, 0xc5, 0x6a, 0xd1, 0x6f, 0xb5, 0xb7, 0x04, 0xf9, + 0x69, 0x63, 0x37, 0x0a, 0x13, 0x23, 0x48, 0xd4, 0xed, 0xca, 0x40, 0x7e, 0xf8, 0x80, 0xd3, 0xf1, 0xd8, 0x53, 0xc6, + 0xdc, 0xca, 0xf4, 0x32, 0x9d, 0x2b, 0xf9, 0x46, 0xee, 0xa5, 0x8f, 0xbd, 0x04, 0x3b, 0x07, 0xbc, 0x81, 0xb4, 0x81, + 0x37, 0xb0, 0x5d, 0x78, 0x6d, 0x90, 0x30, 0x23, 0xc0, 0x16, 0xc7, 0xc7, 0x48, 0x09, 0x0c, 0xe1, 0x38, 0x4b, 0x01, + 0x98, 0x46, 0x5f, 0x66, 0x2b, 0xfb, 0x32, 0xab, 0x35, 0x5b, 0x2a, 0xa7, 0x7b, 0xe7, 0xd6, 0xed, 0x7c, 0x22, 0x01, + 0xc0, 0xa4, 0xce, 0x81, 0x38, 0x33, 0xc1, 0x2e, 0x4d, 0x22, 0xcb, 0xc7, 0x30, 0xbf, 0x13, 0x6f, 0xca, 0x62, 0xa5, + 0xba, 0xa2, 0xed, 0x33, 0x93, 0xcf, 0x48, 0x27, 0xa1, 0x02, 0x0a, 0x0a, 0xb9, 0xd6, 0xa7, 0xef, 0xc2, 0x77, 0x41, + 0xa1, 0x81, 0xd9, 0x2a, 0xdc, 0xd3, 0x64, 0x8d, 0xd4, 0x1b, 0x55, 0xbf, 0x4f, 0xae, 0x81, 0x54, 0x67, 0x0e, 0x2d, + 0x7b, 0x52, 0x61, 0x80, 0xd8, 0x51, 0x9f, 0x91, 0x50, 0x07, 0x52, 0x0f, 0x18, 0x42, 0xb4, 0x4d, 0x1f, 0x7f, 0x32, + 0x24, 0xba, 0x00, 0x5b, 0x88, 0x36, 0xf0, 0xe3, 0x4f, 0xb0, 0xcf, 0x82, 0xf0, 0x98, 0xe6, 0xd7, 0x90, 0x74, 0x6c, + 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0xb9, 0x94, + 0xea, 0x58, 0xa9, 0xb7, 0x6d, 0xed, 0x07, 0xd1, 0x16, 0x1c, 0x59, 0xc4, 0xdf, 0x67, 0x88, 0x08, 0x66, 0x06, 0x11, + 0x76, 0x2d, 0xd4, 0xdd, 0x9e, 0x52, 0xcb, 0xa2, 0xde, 0xf6, 0x94, 0x52, 0xb7, 0x61, 0xf8, 0x6e, 0x82, 0x99, 0xe2, + 0x86, 0xff, 0x91, 0x79, 0xa1, 0xde, 0x78, 0x2c, 0x0a, 0x74, 0xcf, 0xdf, 0x2f, 0x79, 0x35, 0xdb, 0x28, 0x13, 0xe6, + 0x1d, 0x5f, 0xce, 0x42, 0xd9, 0xd5, 0xd2, 0xb8, 0xf3, 0xd9, 0x5b, 0xaa, 0xf9, 0xe0, 0x1f, 0x0e, 0x09, 0xc4, 0x1b, + 0xc5, 0x57, 0x77, 0x8d, 0xdc, 0xba, 0x26, 0x9b, 0xab, 0x12, 0x50, 0xbf, 0xcf, 0xd7, 0xb8, 0xdf, 0x62, 0xfd, 0xbb, + 0xa7, 0x41, 0xc6, 0x6a, 0x86, 0x2b, 0xa6, 0xf0, 0x29, 0x00, 0x0c, 0x0e, 0xa7, 0x82, 0xb4, 0xc0, 0x1b, 0x5e, 0x0e, + 0x2f, 0x27, 0x1b, 0x32, 0xe9, 0x6e, 0x7c, 0xe4, 0xce, 0x02, 0x55, 0xef, 0x37, 0x14, 0x27, 0x0d, 0x12, 0x8d, 0xbd, + 0x06, 0x5f, 0x66, 0x19, 0xe5, 0xa2, 0x89, 0xfb, 0x98, 0x7c, 0xa5, 0x07, 0x30, 0x57, 0xa1, 0x04, 0x88, 0x7e, 0x63, + 0x59, 0x6c, 0x44, 0xdb, 0x62, 0x03, 0x4b, 0xa9, 0x9a, 0xeb, 0xd5, 0xf4, 0xd9, 0x2b, 0xd1, 0xbc, 0x8f, 0x66, 0x9c, + 0xd2, 0x68, 0xc0, 0x71, 0x1a, 0x85, 0xdb, 0xf7, 0xf7, 0xa2, 0x5c, 0x66, 0x60, 0xc9, 0x56, 0xe1, 0x14, 0x97, 0x8d, + 0x3a, 0x23, 0x5e, 0xe6, 0xb1, 0x02, 0xe8, 0x78, 0x4c, 0x00, 0x54, 0x17, 0x04, 0x54, 0x44, 0x4b, 0xe9, 0xad, 0xd0, + 0x62, 0xa1, 0xde, 0x70, 0x94, 0xc2, 0x1f, 0xe9, 0xcf, 0x83, 0x7c, 0x0a, 0x40, 0xec, 0xfa, 0x38, 0x7a, 0x53, 0x94, + 0xf4, 0xa9, 0x62, 0x96, 0xcb, 0xc1, 0x04, 0x76, 0x75, 0x22, 0x43, 0xad, 0x20, 0x6f, 0xd5, 0x95, 0xb7, 0x32, 0x79, + 0x1b, 0xe3, 0x94, 0xfc, 0xc8, 0x4d, 0xc7, 0x1a, 0x31, 0xf0, 0xca, 0xd3, 0x3a, 0x4d, 0x90, 0x26, 0x17, 0xc0, 0x30, + 0xc4, 0xb7, 0x99, 0xf7, 0xd2, 0x73, 0xa4, 0x2a, 0x48, 0x66, 0xbb, 0xcc, 0x53, 0x17, 0x51, 0x7d, 0xe5, 0xd4, 0xd2, + 0x99, 0xd3, 0x8f, 0x00, 0xde, 0x63, 0x6a, 0xd2, 0x90, 0x8f, 0x70, 0x5b, 0x8a, 0xaf, 0xb7, 0xea, 0x1a, 0x2f, 0x8d, + 0xce, 0xdd, 0xcb, 0x97, 0xee, 0x34, 0xe8, 0xa7, 0x20, 0x28, 0xe7, 0xcb, 0x52, 0xc0, 0x9e, 0x32, 0x9b, 0xeb, 0xd5, + 0xaa, 0x15, 0x5a, 0x87, 0xc3, 0x58, 0x3b, 0x0a, 0x69, 0x75, 0x16, 0xb0, 0xd5, 0x48, 0xa7, 0x04, 0x08, 0xc1, 0x71, + 0x1a, 0x76, 0x82, 0x71, 0x97, 0x4e, 0x23, 0xb2, 0x5e, 0x29, 0x49, 0x17, 0x66, 0x90, 0xfc, 0x93, 0xbc, 0x9e, 0x01, + 0x2d, 0x01, 0x1c, 0x8a, 0x58, 0xc2, 0xc3, 0x49, 0x72, 0x05, 0xd0, 0xe9, 0x70, 0x50, 0x69, 0x68, 0xce, 0x6a, 0x96, + 0xcc, 0x27, 0xb1, 0x54, 0x55, 0x1e, 0x0e, 0x9e, 0x72, 0x33, 0xe8, 0xf7, 0xb3, 0x69, 0xa9, 0x5c, 0x00, 0x82, 0x58, + 0x17, 0x06, 0x88, 0x47, 0x5a, 0x78, 0xb2, 0xe8, 0x53, 0x12, 0xbf, 0x9c, 0x25, 0x73, 0x93, 0x0d, 0xef, 0xc0, 0x08, + 0x36, 0xe3, 0xba, 0xa4, 0x4c, 0x7b, 0x54, 0x7e, 0xcf, 0xe8, 0xa9, 0xed, 0x6b, 0xad, 0xb6, 0x88, 0x75, 0x1d, 0x5c, + 0x95, 0xa8, 0xa7, 0xf8, 0xa0, 0x24, 0xc1, 0xfb, 0xb5, 0x73, 0x33, 0x52, 0xbe, 0x16, 0xb9, 0x1f, 0xb4, 0x33, 0xb5, + 0x72, 0xe0, 0x08, 0xe4, 0x58, 0x45, 0x25, 0xaf, 0x77, 0x1d, 0x82, 0x47, 0x77, 0xa5, 0x02, 0xe5, 0xe0, 0x17, 0x20, + 0x46, 0xd7, 0x57, 0x9d, 0x35, 0xd4, 0x4c, 0xa3, 0xca, 0x23, 0xe8, 0xd4, 0x01, 0x3c, 0x29, 0x78, 0xa9, 0xd5, 0x8f, + 0x87, 0x83, 0x67, 0x7e, 0xf0, 0x57, 0x99, 0xbe, 0x85, 0x98, 0x28, 0xa7, 0x1a, 0x21, 0x71, 0xa5, 0x24, 0x11, 0x1f, + 0x2f, 0x5a, 0x56, 0x8c, 0xca, 0xf0, 0x81, 0x57, 0xaa, 0x7c, 0x75, 0xaa, 0xf2, 0x62, 0xa4, 0x6d, 0x09, 0xbc, 0x26, + 0xff, 0x10, 0xb9, 0xe6, 0xad, 0xaf, 0xbb, 0xca, 0xd0, 0x6b, 0x59, 0x81, 0x8e, 0x60, 0x2b, 0x4b, 0xc9, 0x01, 0x9f, + 0x54, 0x77, 0xd5, 0xaa, 0xf5, 0x39, 0x65, 0x1b, 0xe1, 0x26, 0xbf, 0x8e, 0x1d, 0x1c, 0x29, 0xbf, 0xc1, 0x73, 0x01, + 0xec, 0x35, 0x60, 0x6f, 0xce, 0x59, 0xd1, 0x3c, 0x3a, 0xa4, 0x6d, 0x81, 0x46, 0x66, 0x6e, 0xe7, 0xea, 0xbe, 0x2d, + 0x8f, 0xd2, 0x18, 0x22, 0xd3, 0x1e, 0x99, 0x0e, 0x36, 0xa3, 0xfc, 0xb7, 0x94, 0xdf, 0x2a, 0x1c, 0x03, 0xdf, 0x4e, + 0xbd, 0x03, 0xa8, 0x7a, 0xda, 0x20, 0x63, 0xcd, 0x30, 0xb4, 0xb2, 0xcb, 0xa5, 0xd0, 0x12, 0xb4, 0xd4, 0x4d, 0x10, + 0x9c, 0x1f, 0x11, 0xe5, 0x08, 0x40, 0x17, 0x29, 0x60, 0x82, 0x9f, 0xd2, 0x76, 0xf7, 0xfb, 0xeb, 0xd4, 0x23, 0xf7, + 0xae, 0x50, 0xa3, 0x84, 0x12, 0x8c, 0xfd, 0x44, 0x63, 0x06, 0x1d, 0x5d, 0x91, 0x13, 0x9e, 0xb5, 0x3a, 0xac, 0xeb, + 0xa6, 0x0c, 0xca, 0xe2, 0x98, 0x57, 0xd3, 0xd9, 0xef, 0x4f, 0xf6, 0x75, 0x83, 0x2c, 0xe4, 0xbf, 0xb3, 0x1e, 0x92, + 0x41, 0xf7, 0x20, 0x14, 0xa2, 0x37, 0x0f, 0x66, 0xf8, 0x1f, 0xdb, 0xf0, 0xec, 0x1b, 0x6e, 0xd4, 0x09, 0x60, 0x8e, + 0xb8, 0x5e, 0x7a, 0x8a, 0xb6, 0x1e, 0x6e, 0x81, 0x6c, 0x8d, 0x97, 0xb7, 0xf6, 0x1a, 0xc8, 0x29, 0x8e, 0xff, 0x8e, + 0x67, 0x6a, 0x65, 0x83, 0x9f, 0x9e, 0xb2, 0x1d, 0x78, 0x78, 0x11, 0x02, 0x8a, 0x61, 0xd9, 0xf8, 0x3b, 0xcb, 0x71, + 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, 0x5b, 0x79, 0x77, 0xe4, + 0x94, 0x79, 0xa7, 0x87, 0xd1, 0x75, 0x49, 0xfa, 0x26, 0xf9, 0xd8, 0x1a, 0xb6, 0xdf, 0xb5, 0xfb, 0xcd, 0x10, 0x41, + 0x08, 0xe5, 0xf8, 0x39, 0xa3, 0x13, 0x1a, 0x1f, 0x56, 0xb3, 0xd3, 0xeb, 0xf7, 0xce, 0xf1, 0x82, 0xad, 0xd1, 0x00, + 0x8f, 0x87, 0x2e, 0xe6, 0x89, 0x1a, 0x3a, 0x5d, 0xd7, 0xce, 0xc1, 0x03, 0x83, 0x2c, 0x4f, 0xbe, 0x61, 0x58, 0x62, + 0x7f, 0x12, 0xf1, 0xa4, 0xad, 0xda, 0xd8, 0x1c, 0xa9, 0x36, 0x6a, 0x06, 0x7e, 0xf0, 0x0a, 0x0a, 0x8c, 0x2e, 0x48, + 0x2b, 0x30, 0x0e, 0x47, 0x00, 0xb2, 0x62, 0x1c, 0x8f, 0x0c, 0x26, 0x30, 0xa4, 0x1b, 0x8a, 0x02, 0xf0, 0xf0, 0x38, + 0x1e, 0x84, 0x0c, 0x20, 0x5d, 0xf0, 0xd0, 0xb0, 0x4d, 0x42, 0xca, 0xcf, 0xf3, 0xbc, 0x56, 0x43, 0xe8, 0x3b, 0x0b, + 0xd5, 0xb1, 0x1f, 0x69, 0xaf, 0x58, 0xd7, 0xaa, 0x74, 0x64, 0xab, 0x03, 0xf4, 0x0d, 0x19, 0xf8, 0xd6, 0xb1, 0x05, + 0x40, 0xb4, 0xc4, 0x6f, 0xa9, 0x57, 0xfb, 0x32, 0x66, 0x85, 0x7a, 0x7d, 0x61, 0xda, 0xf5, 0x5a, 0x5a, 0x14, 0x50, + 0x71, 0xdb, 0xaa, 0xed, 0x91, 0x9c, 0xff, 0xf8, 0xae, 0xa3, 0x1d, 0x9f, 0x9d, 0x1a, 0x5b, 0x42, 0x99, 0x5b, 0x3c, + 0x91, 0xd5, 0xd1, 0x96, 0xea, 0x54, 0x1f, 0x70, 0xa9, 0x49, 0x75, 0x66, 0x60, 0x78, 0x8d, 0x00, 0xe5, 0x16, 0x22, + 0x69, 0x1c, 0xf6, 0xce, 0x27, 0x83, 0x82, 0xb9, 0x45, 0x02, 0x12, 0xd8, 0xc6, 0xd6, 0x2e, 0x9a, 0xeb, 0xd7, 0x6f, + 0xa9, 0x57, 0xb5, 0xa9, 0xea, 0xc1, 0x1b, 0x2f, 0x70, 0xf6, 0x4e, 0x6b, 0x01, 0x01, 0x14, 0xb6, 0x96, 0xe5, 0xe0, + 0xdc, 0xed, 0xaa, 0x96, 0x8a, 0x32, 0xea, 0xf7, 0xcf, 0x7f, 0x4b, 0x51, 0x11, 0x7b, 0xaa, 0x38, 0x65, 0xfd, 0x76, + 0xcb, 0x5c, 0x54, 0x96, 0xbc, 0x41, 0x15, 0xad, 0xd5, 0x51, 0x53, 0xb9, 0x6e, 0xae, 0x5a, 0x32, 0x41, 0x8c, 0xee, + 0xd3, 0xb5, 0xce, 0x9d, 0x7a, 0xef, 0x55, 0x1c, 0x31, 0x10, 0xdc, 0x74, 0x8f, 0x0f, 0x0e, 0x42, 0xa3, 0xa2, 0x5c, + 0x70, 0xa3, 0xb4, 0xaa, 0xa4, 0x14, 0xf2, 0x56, 0x45, 0x73, 0xa6, 0x8f, 0x00, 0x88, 0x00, 0xab, 0x44, 0xfd, 0x1f, + 0xbe, 0x34, 0xc6, 0x83, 0x07, 0xbe, 0x26, 0xd7, 0xb1, 0xf5, 0xfe, 0x69, 0x8d, 0xb4, 0xda, 0x38, 0x26, 0xb5, 0xea, + 0x65, 0xab, 0x78, 0xd9, 0xbd, 0x4e, 0xc5, 0xe0, 0xf9, 0xff, 0xdc, 0x07, 0xa8, 0x11, 0x2d, 0x65, 0x70, 0xeb, 0x6a, + 0x80, 0xc6, 0x87, 0x63, 0xe1, 0x1b, 0x3f, 0x64, 0x9c, 0x0f, 0x66, 0xe8, 0xa8, 0x36, 0x07, 0x07, 0x04, 0x47, 0x75, + 0x8f, 0xc6, 0x84, 0x59, 0x38, 0xf7, 0x20, 0x50, 0x7d, 0xe2, 0x3e, 0xe3, 0xda, 0x0b, 0xda, 0x04, 0x3e, 0x59, 0xd7, + 0x35, 0x45, 0x80, 0x8b, 0xd8, 0x98, 0x88, 0x21, 0x2e, 0x9b, 0x44, 0xea, 0x9b, 0x31, 0x28, 0x00, 0x8a, 0x17, 0x15, + 0xc9, 0xa5, 0x8b, 0x34, 0xaf, 0x44, 0x59, 0xeb, 0x66, 0x54, 0xac, 0x18, 0x02, 0xc0, 0x43, 0x50, 0x5c, 0x55, 0x66, + 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x6a, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, 0xd2, 0x3b, 0x1f, 0xb7, 0xce, + 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, 0x3f, 0xe3, 0x2f, 0x08, 0x4c, + 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x82, 0x97, 0x93, 0x70, 0x38, 0xf4, 0x41, 0x1f, + 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, 0x10, 0xd1, 0x42, 0x43, 0x1f, + 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, 0xda, 0xd0, 0x22, 0xc5, 0x45, + 0xa3, 0xcc, 0x66, 0xb9, 0xec, 0x84, 0x8d, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, 0x54, 0xad, 0xa7, 0x7a, 0x3d, + 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa4, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, 0xa3, 0x6a, 0x9d, 0xa5, 0x11, + 0x55, 0x6e, 0x92, 0xbb, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0x97, 0x29, 0x3b, 0x5b, 0x83, 0x13, 0x47, 0x9e, 0x4b, 0x6e, + 0xf9, 0xee, 0xbc, 0xa2, 0xbb, 0x53, 0xed, 0x5b, 0x80, 0x7b, 0x33, 0x6c, 0xc8, 0x9c, 0xd7, 0xd8, 0x69, 0x10, 0x26, + 0x81, 0x1f, 0xb1, 0x8f, 0x19, 0xb2, 0xc1, 0x80, 0x8e, 0x42, 0xfa, 0x5f, 0x5b, 0xe6, 0x48, 0xc0, 0xe4, 0xaf, 0xe7, + 0x7e, 0xb3, 0x28, 0x72, 0x58, 0x8c, 0x1f, 0x36, 0x18, 0x69, 0xac, 0xd6, 0x60, 0x58, 0xde, 0x21, 0xf2, 0xa7, 0x76, + 0xc7, 0x34, 0xd5, 0xf1, 0x66, 0xbd, 0xd6, 0xfc, 0xea, 0xe9, 0x53, 0x5d, 0x9f, 0xff, 0xf6, 0xfd, 0x65, 0x58, 0x33, + 0xfb, 0x43, 0x10, 0x4a, 0xbb, 0x77, 0x8b, 0x73, 0x47, 0xa2, 0x77, 0xac, 0x34, 0xb3, 0x4b, 0xbb, 0x64, 0x97, 0xa6, + 0xb4, 0x1b, 0x72, 0xbd, 0xfa, 0x4a, 0x79, 0x63, 0xe7, 0x15, 0xd3, 0xfd, 0x7b, 0xa1, 0x77, 0x94, 0x53, 0x35, 0x81, + 0x88, 0x26, 0xed, 0x48, 0xdc, 0xee, 0x95, 0xe1, 0xf3, 0x49, 0xde, 0x2e, 0xe1, 0xa8, 0x6b, 0x58, 0x6e, 0xbe, 0xfd, + 0xcf, 0xbc, 0xea, 0xac, 0x70, 0xfb, 0xa5, 0x31, 0x6b, 0x7f, 0x0a, 0xe2, 0xaa, 0xfe, 0xf0, 0x9e, 0xd4, 0x4c, 0xc9, + 0xff, 0x55, 0x8f, 0x81, 0xab, 0x9f, 0x4c, 0x3b, 0xba, 0xa7, 0x10, 0x36, 0x98, 0xfd, 0xfc, 0xf8, 0xa1, 0x05, 0xab, + 0xea, 0x02, 0x45, 0x72, 0x00, 0x9d, 0xbb, 0x64, 0x84, 0xf7, 0x3b, 0xc6, 0xb9, 0x7f, 0xf5, 0xbd, 0x9a, 0x1c, 0x21, + 0xa2, 0x5d, 0x84, 0x03, 0x80, 0xb8, 0xd3, 0x54, 0xd6, 0xa1, 0x06, 0xe8, 0x03, 0x02, 0xeb, 0xd0, 0xb7, 0x19, 0xc0, + 0x41, 0x1f, 0x6d, 0x9e, 0x45, 0x20, 0xaf, 0x7b, 0xf7, 0xec, 0x9a, 0xed, 0x7c, 0xfe, 0x62, 0x95, 0x7a, 0xf7, 0xe8, + 0x10, 0x7c, 0x3e, 0xf6, 0xa7, 0x97, 0x81, 0xc1, 0x85, 0x66, 0xd7, 0xcf, 0x04, 0xdb, 0xb1, 0xdd, 0x33, 0x44, 0x2a, + 0xea, 0xce, 0x3f, 0xbc, 0x34, 0xd1, 0xf3, 0xce, 0x0b, 0x77, 0x7c, 0x09, 0xe0, 0x81, 0x2c, 0x06, 0x14, 0x9f, 0xa5, + 0xf7, 0x2f, 0x96, 0x80, 0x9a, 0xfc, 0x96, 0xaf, 0xbd, 0x2f, 0x94, 0xba, 0x80, 0x3f, 0x07, 0x94, 0x3e, 0xc9, 0xb9, + 0x77, 0x37, 0xbc, 0xf5, 0x2f, 0x9e, 0x83, 0xf3, 0xc4, 0x6a, 0xb8, 0x80, 0xbf, 0x0a, 0x3e, 0xf4, 0xee, 0x06, 0x98, + 0x58, 0xf2, 0xa1, 0xb7, 0x1a, 0x40, 0xaa, 0xc2, 0x85, 0xc4, 0xd8, 0x87, 0x5f, 0x83, 0x9c, 0xe1, 0x1f, 0xbf, 0x69, + 0x0c, 0xd6, 0x5f, 0x83, 0x42, 0xa3, 0xb1, 0x96, 0x2a, 0x64, 0x29, 0x16, 0x67, 0x02, 0x6c, 0xc2, 0x71, 0xb7, 0x2f, + 0x56, 0xb5, 0x59, 0x0b, 0xfa, 0xf3, 0x11, 0xdf, 0xa3, 0xb1, 0xba, 0x2a, 0xe7, 0xa2, 0xfc, 0x88, 0xf4, 0xa9, 0x8e, + 0x8f, 0x51, 0xb1, 0xa9, 0xbb, 0xd3, 0xa9, 0x56, 0x1d, 0x69, 0xbf, 0x29, 0xd7, 0x60, 0xc7, 0xeb, 0xe4, 0xc8, 0x52, + 0x78, 0xd6, 0x61, 0xe7, 0xa5, 0x53, 0xa2, 0xc3, 0x30, 0xde, 0x6d, 0xd5, 0x33, 0x86, 0xf2, 0xdc, 0x60, 0x4c, 0x17, + 0x3c, 0xe2, 0x2f, 0x06, 0xb9, 0x0c, 0x8d, 0xf9, 0x80, 0x6c, 0x18, 0xca, 0x87, 0x16, 0x19, 0x12, 0x22, 0xde, 0x43, + 0x25, 0x60, 0xdb, 0x82, 0x32, 0x29, 0xe0, 0x2c, 0x1a, 0xfc, 0x56, 0x7b, 0x39, 0xf0, 0x1e, 0x44, 0x7e, 0x23, 0x5d, + 0xca, 0x25, 0x36, 0x3a, 0x71, 0x2c, 0x0b, 0xed, 0x3c, 0xae, 0xbf, 0x8e, 0x41, 0xfd, 0x5e, 0xe9, 0x37, 0x28, 0x67, + 0x7f, 0x94, 0xac, 0xd3, 0xc6, 0x13, 0xe3, 0x1f, 0xae, 0xf2, 0x4f, 0xd1, 0x52, 0x0f, 0xff, 0x9f, 0x31, 0x85, 0xd2, + 0xbf, 0x4a, 0xcb, 0x68, 0xb3, 0x5a, 0x8a, 0x52, 0xe4, 0x91, 0x38, 0xf9, 0x5a, 0x64, 0xe7, 0xf2, 0x9d, 0x4f, 0xa1, + 0x5f, 0x00, 0x5a, 0xf6, 0x09, 0x32, 0xfa, 0x7b, 0x26, 0xf8, 0xf0, 0x7b, 0xed, 0x5c, 0x9b, 0xf3, 0xf1, 0x24, 0xbf, + 0xb2, 0xf6, 0x6e, 0xc7, 0x8b, 0xc4, 0x28, 0xc6, 0x72, 0x5f, 0x75, 0xb3, 0x72, 0xa2, 0x92, 0x03, 0x23, 0x5d, 0x93, + 0xbd, 0x5c, 0xc9, 0xba, 0x9d, 0x6e, 0x25, 0x10, 0x51, 0x05, 0xde, 0x63, 0x5c, 0xc5, 0x3e, 0x82, 0xe9, 0xba, 0xe3, + 0x32, 0xda, 0xf1, 0x9e, 0xf1, 0xea, 0x44, 0x59, 0xc1, 0xed, 0x46, 0xb4, 0x27, 0x74, 0xf4, 0xd3, 0xa4, 0xb6, 0x2c, + 0x1c, 0x80, 0xdc, 0x25, 0x8c, 0x65, 0x43, 0xb0, 0x62, 0x50, 0xfa, 0x7a, 0x4d, 0xc9, 0xb2, 0x00, 0x8b, 0xce, 0x2e, + 0x23, 0x10, 0xc3, 0xba, 0x69, 0x4e, 0xe8, 0x78, 0xe9, 0xe2, 0xbc, 0xd7, 0x2a, 0x52, 0xf0, 0x8c, 0x16, 0x1d, 0x73, + 0xd3, 0x91, 0x6e, 0x8c, 0xf6, 0xf6, 0x7b, 0x83, 0x90, 0xe2, 0xf9, 0x03, 0x5b, 0xad, 0x8b, 0x8b, 0xc4, 0x2b, 0x64, + 0xa2, 0x05, 0xb1, 0x14, 0x81, 0x19, 0x2f, 0x34, 0x8d, 0x30, 0x41, 0x99, 0x12, 0x2c, 0x5a, 0xa3, 0x43, 0xfb, 0xc3, + 0x12, 0x76, 0x8f, 0x31, 0x02, 0x04, 0xaa, 0x4c, 0x9f, 0xc3, 0xd6, 0x84, 0xd9, 0xd4, 0xc5, 0x06, 0x68, 0xab, 0x18, + 0x1a, 0x84, 0xb5, 0x21, 0xe6, 0x63, 0x9a, 0xdf, 0xfd, 0x0b, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, 0xde, 0xed, 0x9a, 0x84, + 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xa8, 0x1d, 0x6b, 0xa9, 0x77, 0xac, 0xb5, + 0xde, 0xb1, 0xee, 0x1a, 0xfe, 0x21, 0xf3, 0x62, 0x96, 0x80, 0x7e, 0x77, 0xc5, 0x55, 0x83, 0xa0, 0x19, 0x1b, 0x76, + 0x0b, 0xbf, 0x25, 0xd6, 0x6e, 0xe9, 0x5f, 0x2c, 0xd9, 0xc2, 0xf4, 0x81, 0x6e, 0x1d, 0x60, 0x19, 0x51, 0x93, 0xef, + 0x91, 0x77, 0xd3, 0x59, 0x51, 0xb8, 0x3d, 0xb1, 0x85, 0xcf, 0xae, 0xcd, 0x9b, 0xf7, 0xcf, 0x22, 0xc8, 0xbd, 0xe3, + 0xde, 0xfd, 0xf0, 0xda, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, 0xea, 0x88, 0x4f, 0x10, 0xad, 0xec, 0x29, + 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, + 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, + 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, + 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, + 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, + 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, + 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0xbe, 0x3f, 0x2d, 0x94, 0x6b, 0x37, 0x6f, 0xe3, + 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x8e, 0x94, 0x5d, 0x2c, 0xe1, 0x1e, + 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf1, 0x9c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, 0x62, 0x5b, 0xb8, 0x78, + 0xce, 0x36, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0x8d, 0x6a, 0x8e, 0x35, 0xd4, 0x6c, 0x6d, + 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0xee, 0xda, 0x8a, 0x8f, 0x95, 0xb5, 0x2e, 0xdd, 0xeb, 0x3d, 0xaa, 0x0b, 0x60, + 0xeb, 0xbf, 0x3d, 0x5e, 0xb9, 0x9e, 0xcf, 0x08, 0xe0, 0x6b, 0xc1, 0xc7, 0x93, 0x05, 0x7a, 0x95, 0x2c, 0xfc, 0xdb, + 0x81, 0x1a, 0x7f, 0xa7, 0x73, 0x17, 0x00, 0x5d, 0x49, 0x79, 0x05, 0xe4, 0x1d, 0xe4, 0x98, 0x5b, 0x76, 0xe5, 0xfd, + 0xc9, 0x77, 0xd8, 0x35, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, + 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x84, 0x20, 0xae, 0xe0, 0x16, 0xe2, 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, + 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, + 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xd7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x40, 0xfc, 0x74, 0x3b, 0xe0, + 0xf7, 0x1d, 0x6b, 0xcb, 0xbb, 0x66, 0x0b, 0xb6, 0x83, 0x4b, 0x50, 0xd3, 0x5e, 0xf6, 0x27, 0x95, 0x0b, 0xda, 0xb1, + 0x4b, 0xe2, 0xe1, 0x8c, 0x59, 0xa5, 0xcc, 0xac, 0x93, 0xea, 0x4a, 0x74, 0xc6, 0x74, 0xd6, 0x7a, 0x3e, 0x57, 0xf3, + 0x49, 0xa1, 0x41, 0xfd, 0xce, 0x89, 0x8f, 0xa8, 0xe8, 0x3c, 0x81, 0xad, 0x65, 0x05, 0xb1, 0xda, 0xe7, 0x60, 0xad, + 0xd5, 0x2e, 0xfd, 0x5e, 0x3e, 0xe0, 0x36, 0xe5, 0xb0, 0x0e, 0x0c, 0x6a, 0x4e, 0xac, 0xa8, 0xc7, 0x6c, 0xc7, 0xb8, + 0xf9, 0xe9, 0xe5, 0x0f, 0x4e, 0x58, 0xb2, 0x62, 0xb5, 0x3f, 0xfd, 0xfe, 0x99, 0xa7, 0xbf, 0x53, 0xfb, 0x17, 0xc2, + 0x0f, 0xc6, 0xff, 0xa9, 0xdd, 0xd7, 0x5a, 0x8c, 0xca, 0x56, 0x39, 0x42, 0xe3, 0x6e, 0x25, 0x4d, 0x96, 0x9f, 0x84, + 0x27, 0xac, 0x05, 0xcf, 0x72, 0xbd, 0x44, 0xb3, 0x02, 0x56, 0x58, 0xcb, 0x24, 0x5c, 0x61, 0xac, 0x96, 0xb6, 0xfa, + 0x16, 0x4d, 0x73, 0x7c, 0x38, 0xd7, 0x06, 0x65, 0xca, 0xd9, 0x19, 0xb1, 0x1a, 0x2e, 0xc3, 0xd2, 0x84, 0x22, 0x64, + 0xf7, 0x76, 0x70, 0x63, 0xa7, 0x2c, 0xa5, 0x0c, 0xe7, 0x18, 0x4c, 0x78, 0x24, 0x46, 0x55, 0xbe, 0xbf, 0x2f, 0x29, + 0x72, 0xda, 0x96, 0x83, 0x2a, 0x84, 0x7d, 0x24, 0x51, 0x02, 0xb7, 0x22, 0x2d, 0x14, 0x29, 0x8b, 0xbf, 0x1d, 0xa0, + 0x0b, 0xbc, 0x80, 0xba, 0x1a, 0x75, 0xfb, 0xc3, 0x11, 0x0f, 0x1f, 0x99, 0xfa, 0xc0, 0x88, 0x25, 0x81, 0xda, 0x5e, + 0x66, 0xe9, 0x1d, 0xa8, 0xf0, 0x7b, 0xb8, 0x9a, 0x88, 0xfd, 0xdc, 0x92, 0xa2, 0x22, 0x1b, 0xe9, 0x0d, 0xad, 0xc1, + 0x23, 0xb4, 0xa6, 0x7c, 0xef, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, + 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0xef, + 0x55, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, 0xac, 0xd2, 0xd7, 0x24, 0x61, 0x4f, 0x0c, + 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, 0xd2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, + 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x57, 0xc4, 0x97, 0x23, 0x3c, 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, + 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, + 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, + 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, + 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, + 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, + 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, + 0x58, 0x1d, 0xf4, 0xfe, 0x32, 0x7e, 0xda, 0x33, 0x32, 0xf2, 0xb8, 0x75, 0x58, 0xfd, 0xaf, 0xbf, 0x42, 0x00, 0x1c, + 0x9e, 0x4d, 0xbd, 0xcb, 0x31, 0x64, 0x95, 0x65, 0x04, 0x92, 0x9f, 0x18, 0x7c, 0xf9, 0x02, 0xa0, 0xea, 0x33, 0x5d, + 0xab, 0xc9, 0x51, 0x7b, 0xcc, 0xa1, 0x2b, 0x06, 0x80, 0x6d, 0x58, 0xa2, 0xaa, 0x16, 0x36, 0x61, 0x71, 0xfb, 0x19, + 0x46, 0x73, 0xd9, 0xf4, 0x82, 0x06, 0xea, 0x11, 0x82, 0x5f, 0x5a, 0x0f, 0xad, 0xb5, 0x4c, 0x39, 0x74, 0x6d, 0x14, + 0x55, 0x36, 0xd4, 0x25, 0xac, 0xd6, 0x22, 0xaa, 0x89, 0x22, 0xe5, 0x92, 0x51, 0x14, 0x4b, 0x15, 0xec, 0x33, 0x71, + 0x07, 0x51, 0xf3, 0xb4, 0xd5, 0x56, 0xc1, 0xfe, 0x0e, 0x10, 0xd6, 0xc2, 0x5a, 0x48, 0x67, 0x50, 0x7b, 0xa7, 0x1f, + 0x29, 0x7f, 0x79, 0x21, 0xb7, 0x73, 0x0b, 0x45, 0xb8, 0x3d, 0x07, 0xe5, 0x4d, 0x5d, 0x95, 0x8a, 0x68, 0xb4, 0x04, + 0x4a, 0x99, 0x13, 0x44, 0x16, 0x20, 0x80, 0xe3, 0x06, 0x02, 0x9f, 0xd7, 0xf8, 0x04, 0x1a, 0x85, 0x40, 0x7e, 0x60, + 0x15, 0xae, 0x3d, 0xa4, 0xa5, 0xd6, 0x88, 0x28, 0x11, 0x3f, 0xba, 0x7a, 0x8e, 0xed, 0xab, 0xa7, 0xb1, 0xb6, 0x94, + 0x26, 0x88, 0x9f, 0x58, 0x6c, 0x21, 0x26, 0x88, 0xea, 0x10, 0x1d, 0xc1, 0x72, 0x42, 0x88, 0xc2, 0x1f, 0x42, 0x3f, + 0x35, 0xf0, 0x97, 0x6c, 0x59, 0xe4, 0x35, 0xc1, 0x62, 0x56, 0x0c, 0xd0, 0xaa, 0x08, 0x3c, 0xd3, 0xd9, 0x52, 0x99, + 0xd3, 0x3c, 0x3a, 0xb2, 0x83, 0xf3, 0xae, 0x83, 0xbd, 0xf4, 0x65, 0xec, 0x64, 0xd9, 0x34, 0x6a, 0x63, 0x43, 0x24, + 0xbc, 0x22, 0x7f, 0x95, 0xa5, 0xc6, 0x39, 0x32, 0x97, 0xeb, 0xbb, 0x2e, 0xee, 0xee, 0x68, 0x9b, 0xb0, 0x0a, 0x11, + 0xea, 0xb6, 0xa1, 0x72, 0x29, 0xcc, 0xc6, 0xa6, 0x69, 0x80, 0x2f, 0x14, 0x95, 0x4a, 0x55, 0x6a, 0x2b, 0x95, 0x9c, + 0xf0, 0xae, 0xaf, 0x6a, 0x91, 0xba, 0x22, 0xd8, 0xc6, 0x0c, 0xf5, 0x50, 0x6e, 0xd4, 0xd8, 0xd7, 0x1d, 0xab, 0xf4, + 0x0e, 0x13, 0xe4, 0x8c, 0xbc, 0xc8, 0xc1, 0x45, 0x49, 0x41, 0xe6, 0x6a, 0x08, 0xf3, 0x47, 0x0d, 0x9f, 0x16, 0x96, + 0x7b, 0x28, 0x01, 0xb3, 0xa3, 0x86, 0x97, 0x11, 0x02, 0x11, 0x97, 0xca, 0xbe, 0x62, 0xe2, 0xf7, 0x14, 0xcc, 0x92, + 0x09, 0xdd, 0x8b, 0x58, 0x18, 0xa1, 0x8d, 0x4f, 0x92, 0x64, 0xea, 0x69, 0x0a, 0x6e, 0xe4, 0x32, 0xcc, 0xd1, 0x08, + 0x2d, 0xf9, 0xc8, 0x81, 0xf4, 0xb5, 0x9c, 0x4a, 0xf0, 0x11, 0x75, 0x0a, 0x38, 0x9e, 0x9f, 0x17, 0xd6, 0x4f, 0x96, + 0x4b, 0xcc, 0x65, 0x6d, 0xfe, 0xcb, 0x8e, 0x8e, 0xc1, 0x2e, 0x4f, 0x13, 0xc7, 0xd5, 0x7f, 0x54, 0x25, 0xc5, 0xc3, + 0xcf, 0x69, 0x0e, 0x28, 0x82, 0x99, 0x3d, 0xc5, 0xf8, 0xd8, 0x67, 0x99, 0x02, 0xfe, 0x76, 0xbd, 0xb5, 0x64, 0x62, + 0x97, 0xb4, 0x9b, 0x2b, 0xe3, 0x97, 0xda, 0xb0, 0xe3, 0xe0, 0xdc, 0x00, 0x14, 0x67, 0x8d, 0x0e, 0xcb, 0x6b, 0xdd, + 0xb6, 0x2a, 0x54, 0xa0, 0xd6, 0xff, 0xd9, 0x2d, 0x4c, 0x79, 0x9b, 0x97, 0xca, 0xdb, 0x3c, 0x34, 0x01, 0x02, 0x91, + 0x19, 0xf2, 0xac, 0xe9, 0x98, 0x24, 0xee, 0x1d, 0x29, 0x69, 0xdf, 0x91, 0xe2, 0x47, 0xef, 0x48, 0xc8, 0xb7, 0x84, + 0x8e, 0xec, 0x4b, 0x4e, 0x4e, 0xa0, 0xcc, 0x60, 0x2f, 0xaf, 0x99, 0xec, 0x1f, 0xd0, 0x5e, 0x38, 0x97, 0xe5, 0x15, + 0xbf, 0x16, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, + 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, 0xf1, 0xf1, 0xd7, 0x1c, 0x45, 0x6c, 0xa5, 0x3c, 0x92, 0x2e, 0x54, + 0x62, 0x78, 0x69, 0xe0, 0x61, 0x76, 0x7c, 0x3c, 0xd9, 0x5d, 0xdd, 0x4f, 0x06, 0x83, 0x9d, 0xea, 0xdb, 0x2d, 0xaf, + 0x67, 0xbb, 0x39, 0x7b, 0xe0, 0xb7, 0xd3, 0x6d, 0xb0, 0x6f, 0x60, 0xdb, 0xdd, 0x5d, 0x89, 0xc3, 0x61, 0xf7, 0x82, + 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, + 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, + 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe5, 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, + 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, + 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xfa, + 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xf5, 0x6c, 0x33, + 0xf7, 0x5f, 0xac, 0xd8, 0x1d, 0x70, 0xa1, 0x28, 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, + 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, + 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, 0xd7, 0xfc, 0xa6, 0x39, 0x76, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, + 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0x95, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x57, 0x0b, + 0x39, 0xf3, 0xcc, 0x40, 0xdf, 0x56, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x6a, 0xa6, + 0x6d, 0x51, 0x97, 0xdf, 0xf6, 0x9e, 0xc9, 0x6f, 0x64, 0x60, 0x0b, 0x91, 0x14, 0x8e, 0xe3, 0x8b, 0xe7, 0x27, 0xfc, + 0x57, 0x2d, 0x8f, 0x5a, 0xed, 0x17, 0x4a, 0x7d, 0xfa, 0x8a, 0x8e, 0x68, 0xe2, 0x5e, 0xb4, 0x65, 0x58, 0xa3, 0xac, + 0xa9, 0xa5, 0xc3, 0x30, 0xae, 0x61, 0x5f, 0x1e, 0x38, 0xf4, 0x1d, 0x10, 0x68, 0xab, 0x54, 0x0a, 0xb4, 0x70, 0x0c, + 0xa3, 0x30, 0x0b, 0x29, 0x8f, 0x0b, 0xb3, 0x94, 0xf7, 0x58, 0xa0, 0xc5, 0xad, 0xba, 0xc7, 0xd4, 0x76, 0x0b, 0x22, + 0xac, 0xde, 0x32, 0xce, 0x2f, 0x1b, 0x55, 0xb8, 0x2d, 0x40, 0x51, 0x04, 0x65, 0xb0, 0x27, 0xb9, 0x6d, 0xa1, 0xa4, + 0xd9, 0x28, 0xac, 0xc5, 0x5d, 0x51, 0xee, 0x7a, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, 0x75, + 0x28, 0x17, 0xe9, 0x7f, 0x64, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xe7, 0x97, 0xf4, + 0x93, 0xc1, 0x32, 0x72, 0x4a, 0x7d, 0x1f, 0x8d, 0x6e, 0xd3, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, 0x0a, + 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, 0x26, + 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, 0x90, + 0xdc, 0xa9, 0x2b, 0x7f, 0x54, 0x4e, 0xfe, 0x13, 0x0d, 0x91, 0x57, 0x5c, 0x21, 0x56, 0x16, 0x5c, 0x62, 0x31, 0x54, + 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xcb, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, 0x11, + 0x3e, 0x6e, 0xad, 0x45, 0x08, 0x56, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, 0x14, + 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xa8, 0x48, 0xcf, 0x5f, 0x9a, 0x94, 0x5c, 0x1a, + 0x33, 0x3e, 0x88, 0x32, 0x12, 0x79, 0x1d, 0xde, 0x89, 0x69, 0x81, 0x7c, 0xa3, 0xc7, 0x0f, 0x82, 0x4b, 0x78, 0x37, + 0xe4, 0x5e, 0x01, 0xb6, 0x04, 0xec, 0x00, 0xf7, 0xca, 0x8c, 0x72, 0x9d, 0xd6, 0xf5, 0x5b, 0xeb, 0xa1, 0x18, 0x86, + 0xcf, 0x2c, 0x81, 0xed, 0x68, 0x1d, 0x1d, 0xe9, 0xe1, 0xc3, 0xff, 0xba, 0xaa, 0x39, 0xea, 0x54, 0x2e, 0x67, 0xc7, + 0x13, 0x96, 0x22, 0x66, 0xd0, 0xfd, 0x75, 0xfb, 0x4a, 0x00, 0xdd, 0x2e, 0x8b, 0x79, 0x36, 0xda, 0xc9, 0xbf, 0xa5, + 0x1b, 0x2b, 0x4a, 0x9b, 0x78, 0x97, 0xf5, 0xc6, 0xfe, 0x70, 0xf4, 0x97, 0x67, 0x5f, 0x26, 0x84, 0xaa, 0xb3, 0x61, + 0x6b, 0x1d, 0xe7, 0xf2, 0xbf, 0xfe, 0x3a, 0x26, 0x2b, 0x08, 0x0a, 0xc2, 0xb2, 0x53, 0x4c, 0x54, 0x30, 0x8a, 0x14, + 0x6b, 0x3e, 0x9e, 0xac, 0x51, 0x27, 0xbc, 0xf6, 0x97, 0x5a, 0x27, 0x4c, 0x8c, 0xac, 0x54, 0xfe, 0x9a, 0x55, 0xec, + 0x4e, 0x65, 0x16, 0x90, 0x79, 0x90, 0x4f, 0xd6, 0x46, 0x83, 0xb9, 0xe2, 0xf5, 0x6c, 0x3d, 0x97, 0xca, 0x67, 0x30, + 0xe5, 0x2c, 0x07, 0x27, 0x4b, 0x61, 0xf7, 0x24, 0x50, 0xb4, 0x66, 0xe8, 0xda, 0x9f, 0x62, 0xab, 0x5e, 0xa7, 0x55, + 0x0d, 0xf0, 0x80, 0x10, 0x03, 0x43, 0xed, 0xd5, 0xc2, 0x43, 0x6b, 0x01, 0xac, 0xfd, 0x51, 0xe9, 0x07, 0xe3, 0xc9, + 0x92, 0x2f, 0x90, 0x7f, 0x39, 0x72, 0xd4, 0xee, 0xfd, 0xbe, 0x77, 0x0f, 0x52, 0x70, 0xe4, 0x5a, 0x28, 0x90, 0x08, + 0x68, 0xc1, 0x37, 0xbe, 0xf2, 0xc1, 0xb8, 0x46, 0x6d, 0x35, 0x28, 0xa8, 0x1d, 0xdd, 0xf2, 0xd8, 0xd1, 0x3b, 0xdf, + 0x9f, 0xd0, 0x57, 0x2f, 0xb4, 0x70, 0xfc, 0x95, 0x33, 0x72, 0xcd, 0x56, 0x1d, 0x72, 0x44, 0x33, 0xe9, 0x10, 0x22, + 0x56, 0x6c, 0xcd, 0xae, 0x49, 0xe5, 0xdc, 0x39, 0x64, 0xa7, 0x8f, 0x50, 0xa5, 0xd7, 0x7a, 0x7c, 0x3b, 0x51, 0xba, + 0xdb, 0xe3, 0xdd, 0xe4, 0x5b, 0x36, 0x11, 0x31, 0x18, 0xd0, 0x06, 0xe1, 0x8c, 0xac, 0x43, 0xa4, 0xd2, 0x01, 0x42, + 0xe0, 0x98, 0x80, 0xa6, 0xff, 0xf8, 0x9a, 0x44, 0x01, 0x47, 0xda, 0x08, 0x59, 0xcb, 0x0e, 0x87, 0x1c, 0x34, 0xca, + 0xcd, 0x1f, 0x5e, 0xa1, 0x4e, 0x73, 0x60, 0x9e, 0x2e, 0x61, 0xcf, 0xc1, 0x23, 0xbd, 0x38, 0x3e, 0xd2, 0xff, 0x3b, + 0x9a, 0xa8, 0xf1, 0x7f, 0xae, 0x89, 0x52, 0x5a, 0x24, 0x47, 0xb5, 0xf4, 0x4d, 0xea, 0x28, 0xb8, 0xc8, 0x3b, 0x6a, + 0x21, 0x7b, 0x96, 0x8d, 0x1b, 0xd5, 0xbc, 0xff, 0x5f, 0x2b, 0xf3, 0xff, 0x35, 0xad, 0x0c, 0x53, 0xb2, 0x63, 0xa9, + 0x66, 0x1e, 0x68, 0x15, 0xc3, 0xec, 0x67, 0x92, 0x10, 0x19, 0x2e, 0x0d, 0xf8, 0x51, 0x05, 0xfb, 0x38, 0xad, 0xd6, + 0x59, 0xb8, 0x43, 0x25, 0xea, 0xad, 0xb8, 0x4b, 0xf3, 0x97, 0xf5, 0xbf, 0x45, 0x59, 0xc0, 0xd4, 0xbe, 0x2b, 0xd3, + 0x38, 0x20, 0x0b, 0x7f, 0x16, 0x96, 0x38, 0xb9, 0xb1, 0x8d, 0x3f, 0xcb, 0xf1, 0xb4, 0x5f, 0x75, 0x66, 0x1e, 0x48, + 0xa0, 0x06, 0xe2, 0x8f, 0x9c, 0xcb, 0xca, 0xe2, 0x01, 0xa1, 0x9b, 0x7f, 0x28, 0xcb, 0xa2, 0xf4, 0x7a, 0x9f, 0x92, + 0xb4, 0x3a, 0x5b, 0x89, 0x3a, 0x29, 0x62, 0x05, 0x65, 0x93, 0x02, 0x8c, 0x3e, 0xac, 0x3c, 0x11, 0x07, 0x67, 0x08, + 0xd4, 0x70, 0x56, 0x27, 0x21, 0x00, 0x0d, 0x2b, 0x84, 0xfd, 0x33, 0x68, 0xe1, 0x59, 0x18, 0x87, 0x6b, 0x80, 0xc9, + 0x49, 0xab, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, 0x88, 0x47, 0x3d, 0x45, 0xc9, 0xf2, 0x26, 0x77, 0xe5, 0x5c, 0x7f, + 0xff, 0x07, 0x05, 0xb0, 0x1b, 0x30, 0xdb, 0x16, 0xd8, 0x01, 0x40, 0x82, 0x02, 0xd9, 0x42, 0x9d, 0x46, 0x67, 0x6a, + 0xa9, 0xc0, 0x7b, 0xae, 0x07, 0xf8, 0x9b, 0x1c, 0xb0, 0x8c, 0xeb, 0x42, 0x06, 0x8c, 0x20, 0x80, 0x11, 0x38, 0x28, + 0x01, 0x43, 0x67, 0x88, 0xdb, 0xaa, 0x9c, 0xb5, 0xd0, 0x5c, 0xe9, 0xb6, 0xe4, 0xa6, 0x51, 0xce, 0x56, 0x22, 0x80, + 0xbe, 0xba, 0x29, 0x71, 0xba, 0x5c, 0xb6, 0x92, 0xb0, 0x6f, 0xdf, 0xb7, 0x53, 0x45, 0x1e, 0x1f, 0xa5, 0x21, 0xaf, + 0xc0, 0x93, 0x8c, 0x23, 0x49, 0x94, 0x08, 0xde, 0xe4, 0x8d, 0x19, 0x87, 0x97, 0x6d, 0xca, 0xa9, 0xbd, 0x59, 0x2f, + 0x00, 0xe7, 0x09, 0xda, 0x32, 0xc0, 0x58, 0xc0, 0xe0, 0x5c, 0x88, 0x25, 0x4f, 0x11, 0xfc, 0xd2, 0x89, 0x14, 0xc6, + 0x5d, 0x0e, 0xc3, 0x3c, 0x28, 0x7a, 0x97, 0xd4, 0x1f, 0xfd, 0x3e, 0x6a, 0x93, 0xc1, 0x10, 0x54, 0x02, 0xa8, 0xac, + 0x1b, 0x24, 0x06, 0x56, 0xa5, 0x85, 0xc4, 0x25, 0xc4, 0xcb, 0x7c, 0x35, 0xad, 0xa3, 0xe0, 0x7d, 0x3d, 0x21, 0x84, + 0x13, 0x8c, 0x0f, 0x71, 0x03, 0x04, 0x0c, 0x56, 0x71, 0x81, 0x41, 0xf2, 0x5c, 0xa2, 0xfb, 0xe3, 0xf9, 0x8e, 0x01, + 0xae, 0x9c, 0xf7, 0x54, 0xbb, 0x7a, 0x60, 0x2f, 0x57, 0xe9, 0x92, 0x11, 0xc2, 0x8a, 0xff, 0x8b, 0xc8, 0xfb, 0x76, + 0x98, 0x80, 0xda, 0x46, 0xfe, 0x18, 0x24, 0xe6, 0x32, 0x51, 0x04, 0xf1, 0x28, 0x2b, 0x58, 0x92, 0x06, 0x9b, 0x51, + 0x92, 0x82, 0x46, 0x13, 0x63, 0xc8, 0x54, 0x68, 0x87, 0xa4, 0xd1, 0x6c, 0x4c, 0xf6, 0x31, 0xe4, 0x35, 0x5c, 0x2c, + 0x16, 0x78, 0xdf, 0xcf, 0x42, 0x75, 0xb0, 0x2d, 0xcd, 0x21, 0xe0, 0x24, 0xc1, 0x9e, 0xba, 0x22, 0x25, 0x61, 0x36, + 0xfa, 0x14, 0x72, 0x6e, 0x40, 0xc7, 0x49, 0x63, 0xa8, 0x3e, 0x30, 0x09, 0xaf, 0x22, 0x74, 0x52, 0x56, 0x08, 0x0b, + 0xb8, 0x6f, 0x64, 0x34, 0x5a, 0x49, 0x83, 0xc0, 0xdb, 0x0c, 0x5b, 0x81, 0x4d, 0x68, 0xf8, 0xcb, 0xcc, 0xc3, 0xb4, + 0x9a, 0x95, 0x60, 0xce, 0x37, 0x50, 0x89, 0xf1, 0x64, 0x79, 0xc5, 0x37, 0x2e, 0x56, 0x62, 0x32, 0x5b, 0xce, 0x27, + 0x6b, 0x49, 0x35, 0x97, 0x7b, 0x6b, 0x96, 0xb1, 0x25, 0xec, 0x1f, 0x06, 0x86, 0xd2, 0x81, 0x1d, 0x4d, 0x35, 0x6d, + 0x12, 0x60, 0x32, 0x9d, 0x73, 0x3e, 0xbc, 0x44, 0x34, 0x59, 0x9d, 0xba, 0x93, 0xa9, 0x6a, 0x07, 0xd7, 0xe4, 0x4c, + 0x4e, 0x8f, 0xd4, 0x53, 0xad, 0x7b, 0xc9, 0x47, 0xdb, 0x61, 0x35, 0xda, 0xfa, 0x01, 0xb8, 0x75, 0x0a, 0x3b, 0x7d, + 0x37, 0xac, 0x46, 0x3b, 0x5f, 0xc3, 0xee, 0x92, 0x42, 0xa0, 0xfa, 0xb3, 0xac, 0xc9, 0x5c, 0xbc, 0x2e, 0x1e, 0xbc, + 0x82, 0x3d, 0xf7, 0x07, 0xfa, 0x57, 0xc9, 0x9e, 0xfb, 0x36, 0x93, 0xeb, 0x9f, 0x69, 0xd7, 0x68, 0xcc, 0x74, 0xbc, + 0x76, 0x05, 0x56, 0x68, 0x80, 0xfc, 0x82, 0x1d, 0xed, 0x6d, 0x0e, 0x02, 0x01, 0xba, 0x97, 0xe0, 0x28, 0x0a, 0x88, + 0x9a, 0x56, 0x95, 0x47, 0xa7, 0x7b, 0x7f, 0x8f, 0x6f, 0x94, 0x80, 0x4d, 0x9e, 0x5a, 0xf7, 0x96, 0xb1, 0x7f, 0x38, + 0x40, 0x08, 0xbd, 0x9c, 0x7e, 0xa3, 0x2d, 0xab, 0x47, 0x3b, 0x96, 0xfb, 0x86, 0x51, 0x4f, 0xc1, 0x18, 0x86, 0x2e, + 0xac, 0x62, 0x24, 0xcf, 0x80, 0xac, 0xf1, 0x1b, 0x44, 0x17, 0xb0, 0xe8, 0xf5, 0x5e, 0x1f, 0xd1, 0x20, 0x02, 0x2a, + 0xbd, 0xe6, 0x2f, 0x45, 0x3e, 0x57, 0x85, 0xe8, 0xbd, 0xb7, 0x76, 0xde, 0xcc, 0x48, 0x96, 0x49, 0x23, 0xd5, 0x6e, + 0x65, 0xb1, 0xae, 0xbc, 0xd9, 0x09, 0xe9, 0x62, 0x8e, 0xa1, 0x32, 0x78, 0x1c, 0x80, 0xd2, 0xf3, 0x6f, 0xa1, 0x57, + 0x32, 0x64, 0x9a, 0x25, 0x9a, 0xd9, 0x5d, 0xe3, 0x4f, 0x56, 0xa9, 0x17, 0x23, 0x62, 0x36, 0xb0, 0x85, 0xb8, 0x2d, + 0x2a, 0xdd, 0x16, 0x85, 0xb2, 0x45, 0x91, 0x3e, 0xd4, 0xce, 0x74, 0x67, 0x16, 0x3e, 0xab, 0x4c, 0xfb, 0xde, 0x66, + 0x66, 0x6c, 0x80, 0xb6, 0x8b, 0xf0, 0x0d, 0x74, 0xa0, 0x42, 0xc8, 0x7f, 0x40, 0x44, 0x24, 0x02, 0x76, 0x39, 0x75, + 0x27, 0x36, 0x1d, 0x92, 0x79, 0x88, 0x59, 0xa1, 0x46, 0x79, 0xc9, 0x93, 0xa3, 0x01, 0xa9, 0x08, 0x75, 0xbb, 0xdf, + 0x3f, 0x5f, 0xba, 0xa0, 0xf6, 0x6b, 0x8a, 0x1d, 0xa3, 0x9b, 0x02, 0xce, 0x05, 0x8f, 0xf2, 0x9e, 0x7b, 0xe7, 0x80, + 0xe6, 0xd8, 0x9e, 0x22, 0x6b, 0xc0, 0xe9, 0x6d, 0x17, 0x02, 0x6c, 0x9f, 0x35, 0x5b, 0xfb, 0x93, 0xd5, 0x55, 0x34, + 0xf5, 0x4a, 0x3e, 0xd3, 0x5d, 0x94, 0xb8, 0x5d, 0x14, 0xcb, 0x2e, 0xda, 0x34, 0x10, 0xec, 0xb8, 0xf2, 0x03, 0xe0, + 0x0d, 0x8d, 0xfa, 0xfd, 0xb2, 0xd5, 0xb3, 0x27, 0x5f, 0x3b, 0xee, 0xd9, 0xcc, 0x67, 0xa5, 0xe9, 0xd9, 0x5f, 0x53, + 0xb7, 0x67, 0xe5, 0x64, 0x2f, 0x3a, 0x27, 0xfb, 0x74, 0x36, 0x0f, 0x04, 0x97, 0x3b, 0xf7, 0x79, 0x3e, 0xd5, 0xd3, + 0xae, 0xf2, 0x83, 0xd6, 0x10, 0x99, 0x2f, 0x7c, 0xaa, 0xba, 0xd7, 0x15, 0x2c, 0x60, 0x09, 0xee, 0xd6, 0x4b, 0xf3, + 0x5f, 0xb1, 0xfb, 0x7b, 0x41, 0x2f, 0xcd, 0x7f, 0xa3, 0x3f, 0x29, 0x80, 0x03, 0xd0, 0x98, 0xda, 0x2d, 0xf0, 0x10, + 0x43, 0x05, 0x85, 0xbb, 0x59, 0x39, 0xf7, 0x6a, 0x80, 0xc3, 0x24, 0x7d, 0x43, 0xab, 0x57, 0x5a, 0xec, 0x7a, 0x99, + 0xec, 0x15, 0xe0, 0xa1, 0x0a, 0x79, 0x78, 0x38, 0x44, 0x1d, 0xc3, 0x0e, 0xea, 0x08, 0x18, 0xf6, 0x10, 0x1a, 0x5b, + 0xe0, 0xf9, 0xf8, 0x29, 0xe3, 0x7b, 0x01, 0x6a, 0x23, 0x84, 0xc7, 0xab, 0x45, 0x19, 0x62, 0xcb, 0xde, 0x22, 0x95, + 0xd4, 0xcf, 0x02, 0x51, 0x46, 0xab, 0x80, 0xb6, 0xda, 0x63, 0x96, 0xc6, 0x1b, 0x08, 0x15, 0x4b, 0x7d, 0x0c, 0xa1, + 0x81, 0xc3, 0xef, 0x70, 0x00, 0x09, 0xbe, 0xe4, 0x9a, 0x6c, 0xee, 0x6d, 0x7e, 0x4f, 0xfb, 0xfc, 0xe1, 0x70, 0x7e, + 0x89, 0xa0, 0x74, 0x29, 0x7c, 0xa4, 0x12, 0x51, 0x3d, 0xc5, 0x4d, 0x09, 0xd9, 0x2c, 0x59, 0xe9, 0x07, 0xbf, 0xaa, + 0x5f, 0x00, 0x20, 0x0b, 0x81, 0x36, 0x91, 0xd9, 0x9f, 0xce, 0x54, 0x74, 0x01, 0x70, 0x88, 0x3f, 0x7e, 0x82, 0xe8, + 0x1b, 0x5a, 0xa6, 0xe5, 0xe3, 0x84, 0x87, 0xa0, 0xb5, 0x25, 0x9d, 0x44, 0xac, 0x14, 0xd8, 0x10, 0x09, 0xdf, 0xef, + 0x9f, 0xc7, 0x92, 0x0e, 0x34, 0x6a, 0x75, 0x6f, 0xdc, 0xea, 0x5e, 0xf9, 0xba, 0xee, 0xe4, 0xc6, 0x07, 0x45, 0xfb, + 0x6c, 0xde, 0xa8, 0x7c, 0xdf, 0xd6, 0x39, 0xbb, 0xd3, 0xbd, 0x23, 0xe7, 0xc4, 0xb7, 0xf7, 0x10, 0x8a, 0x1e, 0x9a, + 0x22, 0xcb, 0x92, 0x30, 0xa0, 0xb5, 0x76, 0xed, 0x59, 0x46, 0x07, 0xaf, 0x7d, 0x43, 0x88, 0xc8, 0x53, 0x7c, 0x12, + 0x72, 0x8b, 0xe3, 0x83, 0x02, 0xfd, 0x33, 0xe3, 0xcf, 0x9c, 0xf8, 0x61, 0xab, 0x5f, 0x00, 0xe7, 0xa6, 0x7b, 0xef, + 0x4e, 0xcc, 0x7a, 0x0c, 0xa5, 0x6c, 0xfc, 0xdf, 0xef, 0x13, 0x59, 0xa0, 0xd3, 0x11, 0x0d, 0x03, 0xc1, 0x5d, 0x54, + 0xff, 0xf7, 0x8a, 0xd7, 0x3d, 0x6b, 0x75, 0xbe, 0xfc, 0xd4, 0xe9, 0x49, 0xaf, 0x5e, 0xc6, 0x3d, 0xa0, 0x42, 0x07, + 0x08, 0xe7, 0x75, 0xbf, 0x61, 0xbb, 0x6f, 0x7e, 0x79, 0x77, 0xf4, 0x32, 0xb0, 0x49, 0x91, 0xd8, 0x56, 0xf2, 0x59, + 0x0f, 0x14, 0x7e, 0x3d, 0xd6, 0xab, 0x8b, 0x75, 0x8f, 0xf5, 0x50, 0x0b, 0x88, 0x1e, 0x16, 0xa0, 0xfe, 0xeb, 0xd9, + 0xa7, 0xa1, 0x70, 0x90, 0x8d, 0x53, 0x05, 0x8a, 0x2c, 0xf8, 0x0b, 0x31, 0x5a, 0x17, 0x04, 0x88, 0x6c, 0x09, 0x69, + 0xd5, 0xc9, 0xec, 0x71, 0xa9, 0x25, 0x19, 0x7c, 0x13, 0x90, 0xd9, 0x81, 0x95, 0x13, 0x94, 0x8e, 0x5b, 0x03, 0xae, + 0x6c, 0xf1, 0x68, 0xb7, 0x3f, 0x0d, 0xb2, 0xb3, 0xe6, 0xa4, 0xd1, 0x3e, 0xec, 0xd3, 0x3c, 0x40, 0x20, 0x92, 0xa9, + 0x08, 0x72, 0xcd, 0xbd, 0x25, 0x7d, 0x74, 0x38, 0xe7, 0x85, 0xfc, 0x73, 0x2a, 0x75, 0x88, 0x43, 0x89, 0x35, 0x10, + 0xa8, 0x3c, 0x43, 0x95, 0xc3, 0x06, 0x39, 0xfe, 0xd9, 0x91, 0xcc, 0x24, 0x26, 0x8b, 0xdc, 0xad, 0x99, 0x0a, 0x3f, + 0x10, 0x7c, 0xcc, 0x72, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x02, 0x7f, 0x4c, 0xe1, 0x57, 0x3c, + 0x85, 0x9d, 0x76, 0xbf, 0x2e, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, + 0x3f, 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x65, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x06, + 0x15, 0x5b, 0x17, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xaa, 0x51, 0x5a, 0xfd, 0xa8, + 0x7f, 0x02, 0xf3, 0x36, 0x15, 0xa3, 0x5a, 0xc5, 0xe4, 0x37, 0xfa, 0xfd, 0x62, 0xd0, 0xfa, 0x90, 0xc1, 0x47, 0xaf, + 0x4d, 0x83, 0x3f, 0x3a, 0x0d, 0x76, 0x98, 0x68, 0x04, 0x40, 0x32, 0xa7, 0x96, 0x3c, 0x14, 0xfd, 0x11, 0xe4, 0x58, + 0xa3, 0xca, 0x29, 0x18, 0xac, 0xff, 0x78, 0xb4, 0x03, 0x53, 0x2f, 0x8e, 0xb6, 0x64, 0x07, 0xad, 0x7c, 0x03, 0xdc, + 0xaf, 0x91, 0x2d, 0x66, 0x39, 0x40, 0xb3, 0xd7, 0x88, 0x8c, 0x4f, 0x5e, 0x00, 0x63, 0xb6, 0xce, 0xc2, 0x48, 0xc4, + 0xc1, 0x58, 0x35, 0x66, 0xcc, 0xc0, 0xc0, 0x05, 0xba, 0x96, 0x49, 0x49, 0x1a, 0xd2, 0xc1, 0x80, 0x95, 0xb2, 0x85, + 0x03, 0x5e, 0x34, 0xc7, 0xed, 0x78, 0xd3, 0xa2, 0xf1, 0xc0, 0x76, 0xb1, 0xfd, 0xfd, 0xf7, 0xc5, 0xf6, 0x3a, 0xdc, + 0x92, 0x5e, 0x21, 0x67, 0x09, 0xfd, 0xfc, 0x51, 0xf6, 0x59, 0xc3, 0xc9, 0xa9, 0xd0, 0x0c, 0x2d, 0x45, 0x42, 0x29, + 0xde, 0xe9, 0x49, 0x81, 0xb1, 0x8c, 0x85, 0xbf, 0x07, 0xce, 0xe9, 0x42, 0x11, 0xb9, 0x03, 0xc7, 0xf1, 0x0d, 0x54, + 0x30, 0x6a, 0x38, 0x78, 0x19, 0xc3, 0xb6, 0x28, 0x66, 0x21, 0xe1, 0x14, 0xc2, 0xc5, 0x2a, 0xeb, 0xf7, 0xe5, 0x2f, + 0xea, 0xa2, 0x8b, 0x4c, 0xd6, 0x7d, 0x12, 0x8e, 0xcc, 0x58, 0x4e, 0xbd, 0x90, 0x3c, 0xef, 0x79, 0x32, 0x4d, 0x9e, + 0xe5, 0x41, 0x04, 0x90, 0xcf, 0xe1, 0x7d, 0x98, 0x66, 0x60, 0x95, 0x26, 0xe5, 0x47, 0x28, 0x7d, 0xf1, 0x79, 0xe5, + 0x07, 0x3a, 0x7b, 0x6e, 0x92, 0xe1, 0xcd, 0xaa, 0xf5, 0x26, 0xb5, 0xae, 0x8b, 0x07, 0xfc, 0x8b, 0x33, 0xd8, 0x38, + 0xd7, 0x99, 0xe0, 0xc0, 0x8b, 0xa4, 0xd6, 0x6b, 0xc6, 0x5f, 0x64, 0xb8, 0x2e, 0x55, 0x1b, 0x7d, 0x14, 0xa2, 0x73, + 0xc8, 0x54, 0x80, 0x42, 0x91, 0xf6, 0x0f, 0x4a, 0xad, 0x4c, 0x2a, 0x6d, 0x24, 0x80, 0xee, 0x61, 0xd2, 0x60, 0x8b, + 0xa1, 0x8c, 0xa5, 0x49, 0x94, 0x3b, 0x0d, 0xe2, 0xca, 0xfe, 0x5c, 0x49, 0x1c, 0x5a, 0x16, 0xc9, 0xbf, 0x77, 0x3d, + 0x7d, 0x85, 0xd4, 0x9d, 0x2c, 0x90, 0x19, 0xe3, 0x65, 0x1e, 0x7f, 0x02, 0xc2, 0x6c, 0xd0, 0x46, 0x45, 0x21, 0x84, + 0x6c, 0x10, 0x83, 0xc6, 0xcb, 0x3c, 0xfe, 0x5e, 0xd1, 0x78, 0xc8, 0x47, 0x91, 0xaf, 0xfe, 0x2a, 0xf5, 0x5f, 0xa1, + 0xcf, 0x4c, 0xf0, 0x08, 0xd5, 0x44, 0xff, 0xee, 0xf9, 0xec, 0x1e, 0xd4, 0x86, 0x51, 0x98, 0x99, 0xf2, 0x2b, 0xdf, + 0x14, 0x67, 0xaf, 0xbf, 0xa2, 0xab, 0x6c, 0xeb, 0x7e, 0xf4, 0xf1, 0x88, 0xc0, 0xda, 0x18, 0x5d, 0x71, 0x63, 0x00, + 0x39, 0x4c, 0xde, 0xaf, 0x28, 0x2d, 0x87, 0x34, 0x08, 0x1d, 0x34, 0x04, 0xbd, 0x92, 0xe8, 0x03, 0x89, 0x45, 0x8c, + 0xe1, 0x85, 0x78, 0x46, 0x6a, 0x32, 0xd1, 0x10, 0xaf, 0x88, 0xfd, 0x10, 0x2d, 0x39, 0x35, 0xd1, 0x8d, 0x30, 0xc5, + 0x40, 0x62, 0x67, 0x90, 0x9c, 0x24, 0xb5, 0xf2, 0x8b, 0x67, 0x92, 0xb0, 0xc4, 0xce, 0x43, 0x0c, 0x26, 0xb5, 0x74, + 0xa7, 0x37, 0x55, 0x7a, 0x77, 0xa4, 0xe5, 0xa0, 0x7d, 0x00, 0x76, 0x29, 0xe9, 0xfd, 0x93, 0x42, 0x11, 0x1f, 0xc2, + 0x38, 0x86, 0xf0, 0x2d, 0xa2, 0xba, 0x02, 0xe7, 0x5a, 0x81, 0xc6, 0x6a, 0xe0, 0xa1, 0x99, 0x55, 0xf3, 0x21, 0xa7, + 0x9f, 0x4a, 0xcb, 0x1f, 0x23, 0x1a, 0x1b, 0xad, 0x9b, 0xc3, 0x61, 0x4f, 0xab, 0x5e, 0x3a, 0x07, 0x5d, 0x36, 0x93, + 0x98, 0xb8, 0x81, 0x74, 0xfd, 0xe8, 0x37, 0x13, 0xf6, 0x22, 0x2a, 0xe4, 0x52, 0x08, 0x0a, 0x5a, 0x1d, 0x08, 0x1c, + 0x0a, 0x6f, 0x51, 0xe6, 0x8b, 0x98, 0x36, 0x10, 0x06, 0x9f, 0x1f, 0xc8, 0xcf, 0x37, 0x05, 0xa9, 0xd8, 0xb1, 0xae, + 0xfd, 0xfe, 0xa6, 0xf4, 0x00, 0x4f, 0xce, 0x24, 0x79, 0xda, 0x0c, 0x61, 0x45, 0x00, 0x8d, 0x59, 0x4d, 0x16, 0x27, + 0x5c, 0x99, 0xc3, 0x8f, 0x95, 0x57, 0xb2, 0x94, 0xa9, 0xf3, 0x54, 0x2f, 0x80, 0xa8, 0xe3, 0x0d, 0x5a, 0x91, 0xfa, + 0x15, 0x3a, 0x7b, 0xcd, 0x4a, 0xc8, 0x78, 0x78, 0xce, 0x79, 0x3a, 0x7a, 0x60, 0x09, 0x8f, 0xf0, 0xaf, 0x64, 0xa2, + 0x0f, 0xbf, 0x07, 0x0e, 0x37, 0xe3, 0x84, 0x47, 0x6e, 0xb3, 0xf7, 0x55, 0xb8, 0x82, 0x9b, 0x69, 0x01, 0x48, 0x6e, + 0x41, 0xd2, 0x04, 0x94, 0x90, 0xc8, 0x84, 0xcc, 0x9a, 0x92, 0x9f, 0x5b, 0xda, 0x06, 0x6b, 0x98, 0x74, 0x1e, 0xf0, + 0xa2, 0xd5, 0x47, 0xab, 0x89, 0x76, 0x99, 0xe5, 0xf3, 0x21, 0xce, 0x50, 0xcd, 0x71, 0x77, 0x06, 0x3f, 0x07, 0xbc, + 0x62, 0x55, 0x93, 0x8e, 0x76, 0x03, 0x2e, 0x3c, 0xb9, 0xce, 0xd3, 0xd1, 0x16, 0x7f, 0xc9, 0xfd, 0x01, 0xa0, 0x83, + 0xa9, 0x4b, 0xe0, 0x4f, 0xd5, 0x56, 0x53, 0xa9, 0x5f, 0x5a, 0xfb, 0x75, 0xdd, 0x59, 0xad, 0xdc, 0xb3, 0x2e, 0x43, + 0x7b, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, + 0x82, 0x7b, 0xc9, 0x5f, 0xec, 0x11, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, + 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xb1, 0x34, 0x26, 0x45, + 0x05, 0xe9, 0x9c, 0x0e, 0x37, 0xaf, 0x8e, 0xf3, 0x84, 0x65, 0x7c, 0xdc, 0x3e, 0x53, 0x20, 0xc4, 0x16, 0xcf, 0x90, + 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x38, 0xd4, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, + 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1a, 0xfe, 0x2e, 0x43, 0x75, 0x77, 0x08, + 0x4c, 0x6c, 0xd9, 0x81, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x1b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, + 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x11, 0x5e, 0x25, 0x5b, 0x79, 0x38, 0x24, 0xd6, 0x5d, 0xd8, 0xd1, + 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0xe4, 0x66, 0x17, 0x12, 0x83, 0x8a, 0xa5, 0xfa, + 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xd5, 0x71, 0x9f, 0x8a, 0xd1, 0x5a, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, + 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x5c, 0x1f, 0xc7, 0x87, 0x83, 0x14, 0x33, + 0x2e, 0x8f, 0xc4, 0x8c, 0xcb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xc3, 0xe1, 0x92, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, + 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4b, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x75, 0xea, 0x65, 0xe4, + 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x2a, 0xda, 0xad, 0x4b, 0x26, + 0xec, 0x2d, 0xa5, 0x92, 0x56, 0x79, 0xf9, 0x74, 0xe3, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, + 0x12, 0xb5, 0x32, 0x4c, 0x16, 0xce, 0x4b, 0xa6, 0x9e, 0x0c, 0x78, 0xcc, 0x4a, 0x1e, 0xc9, 0x4e, 0x6f, 0x0c, 0x82, + 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x74, 0x95, 0x0b, 0x0c, 0xb7, 0x5b, 0xb3, 0x8d, + 0xaa, 0xb3, 0xdc, 0xd4, 0x2a, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0x37, 0x10, 0x8c, + 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x05, 0x96, 0xd2, 0xd1, 0x8e, 0x97, + 0xa8, 0x52, 0xf8, 0xbb, 0xe0, 0xfb, 0x30, 0x8e, 0xbf, 0x2f, 0xb6, 0xea, 0x40, 0xbc, 0x2d, 0xb6, 0x48, 0xfb, 0x22, + 0xff, 0x42, 0x1c, 0xf0, 0x5a, 0xd7, 0x94, 0xd7, 0xd6, 0x9c, 0x06, 0xb6, 0x86, 0x91, 0x92, 0xc2, 0xb9, 0xf9, 0xf3, + 0x70, 0xa0, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x44, 0x09, 0x8e, 0x5c, + 0xf2, 0xaf, 0xc3, 0x41, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0xdb, 0x7f, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, + 0x24, 0xff, 0x6a, 0x9a, 0x79, 0xc3, 0x64, 0xcd, 0x14, 0x8e, 0x43, 0xc3, 0x08, 0x69, 0x40, 0xb7, 0x41, 0x6d, 0x78, + 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0x97, 0x13, 0x71, 0x4e, 0x97, 0x24, 0xf5, 0x54, 0x42, + 0x49, 0x08, 0x76, 0xe9, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, + 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xab, + 0x78, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8a, 0x4d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, + 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xac, 0xe4, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, + 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0x1f, 0x55, 0x36, 0x76, 0x07, 0xe4, 0x90, 0x64, 0xb2, 0xb8, 0x1b, 0xdd, + 0x8a, 0x65, 0x51, 0x8a, 0x9f, 0xb1, 0x1e, 0xae, 0xd9, 0xc2, 0x7d, 0x06, 0x84, 0xf6, 0x13, 0xa5, 0xbd, 0x89, 0x34, + 0x41, 0xf7, 0x1d, 0x5b, 0x01, 0xc8, 0x00, 0x8a, 0xba, 0xda, 0xad, 0xcf, 0xf9, 0x39, 0x92, 0x66, 0x38, 0x8c, 0x6e, + 0x9f, 0xde, 0x05, 0x77, 0x83, 0x4b, 0xd4, 0x4a, 0x5f, 0xb2, 0xb8, 0x85, 0x41, 0xb5, 0x37, 0x4b, 0x38, 0xa8, 0x99, + 0xb5, 0x36, 0x02, 0xc1, 0x64, 0x0f, 0x05, 0x15, 0x73, 0x05, 0xfb, 0xa0, 0x60, 0x2d, 0x79, 0x1d, 0x1c, 0x6e, 0xed, + 0xcb, 0x4a, 0x71, 0xf1, 0xfc, 0x22, 0x69, 0x5d, 0x58, 0xca, 0x8b, 0xe7, 0x0d, 0x18, 0x5c, 0x8e, 0xb0, 0xa9, 0x2a, + 0x7f, 0xb2, 0x01, 0xd0, 0xad, 0x90, 0x22, 0x5e, 0x94, 0xc2, 0xb6, 0x95, 0xcf, 0x9c, 0xb0, 0xc1, 0x86, 0x3d, 0xc0, + 0xbd, 0x32, 0x28, 0x19, 0x5c, 0x88, 0x71, 0xbb, 0xd9, 0x05, 0xb8, 0x82, 0xa1, 0x30, 0xb6, 0xe6, 0x6f, 0x32, 0x2f, + 0x52, 0x02, 0x6e, 0x86, 0x28, 0x5f, 0x1b, 0x38, 0x99, 0xf4, 0xe4, 0x5a, 0xb2, 0x18, 0xb0, 0xa0, 0xc1, 0x77, 0xd4, + 0xfa, 0x3b, 0x93, 0x7f, 0xe3, 0xe9, 0xa1, 0x1f, 0x7c, 0xce, 0xbc, 0xa5, 0xcf, 0xde, 0x54, 0x32, 0x5a, 0x93, 0x44, + 0x79, 0xf5, 0x70, 0x09, 0x72, 0xc3, 0x72, 0xf4, 0xc0, 0x96, 0x20, 0x4e, 0x2c, 0x47, 0x09, 0x65, 0x74, 0x85, 0x7b, + 0x95, 0xd9, 0x32, 0x11, 0x48, 0x71, 0x60, 0x29, 0xe5, 0xde, 0x62, 0x1d, 0x2c, 0x71, 0x7f, 0x22, 0xb9, 0x80, 0x92, + 0x07, 0x50, 0xae, 0x14, 0x10, 0xf0, 0xe9, 0x00, 0xca, 0x97, 0xf2, 0x22, 0xfc, 0x89, 0x13, 0x35, 0x58, 0x8e, 0x1e, + 0x1a, 0xf6, 0xa3, 0x17, 0x5a, 0xf6, 0x87, 0x3b, 0xad, 0x69, 0x58, 0xf1, 0x3b, 0x98, 0x16, 0x13, 0xb7, 0x2f, 0x57, + 0x76, 0x55, 0x7c, 0xb6, 0x52, 0x67, 0x37, 0x35, 0x24, 0x61, 0x5f, 0x91, 0x55, 0x80, 0x83, 0x55, 0x11, 0xf7, 0x2c, + 0xcb, 0x7d, 0x18, 0xfd, 0xb9, 0x49, 0x4b, 0x61, 0xa1, 0x4a, 0xfa, 0xfb, 0xa6, 0x14, 0x48, 0x65, 0xa2, 0x13, 0x2d, + 0x04, 0x57, 0x60, 0x10, 0xb8, 0x17, 0x79, 0x0d, 0x80, 0x31, 0xe0, 0x52, 0xa0, 0x2c, 0xdb, 0x12, 0x42, 0xaa, 0xfb, + 0x19, 0xa8, 0xed, 0xc4, 0x7d, 0x1a, 0x91, 0xb5, 0x10, 0x7d, 0x15, 0x8c, 0x99, 0xf3, 0x52, 0xba, 0xc5, 0xa6, 0xab, + 0xcd, 0xea, 0x06, 0x9d, 0x4b, 0x5b, 0x6e, 0x7e, 0xc2, 0x16, 0x6b, 0x05, 0xca, 0x26, 0x24, 0x6d, 0xe7, 0x3c, 0x47, + 0xd9, 0x84, 0x96, 0xf6, 0x9e, 0x7a, 0x54, 0xa8, 0x4e, 0xb6, 0x5e, 0xaa, 0xa6, 0x16, 0x61, 0xb5, 0xb8, 0xa8, 0xfc, + 0x00, 0x74, 0x53, 0x69, 0xf5, 0xb2, 0xae, 0xd1, 0x14, 0x6a, 0xb5, 0x70, 0xdc, 0x68, 0x67, 0xd3, 0x65, 0x7a, 0x87, + 0x38, 0xab, 0xd2, 0x0e, 0xfd, 0x7d, 0xa6, 0x5d, 0x2f, 0x3b, 0xfa, 0xcd, 0xb8, 0xba, 0xc0, 0x85, 0xd8, 0x80, 0xcf, + 0xb9, 0xbf, 0xbc, 0xde, 0xf3, 0xb8, 0xe7, 0x1f, 0x0e, 0xc8, 0x9e, 0xd4, 0xfe, 0x50, 0x7d, 0xec, 0x0a, 0x86, 0x2c, + 0x8c, 0x52, 0x7f, 0x91, 0xf2, 0xde, 0x13, 0x1c, 0xf7, 0xcf, 0x55, 0x8f, 0xfd, 0x98, 0xf1, 0x7d, 0x5d, 0x6c, 0xa2, + 0x84, 0xa2, 0x1a, 0x7a, 0xab, 0x62, 0x53, 0x89, 0xb8, 0x78, 0xc8, 0x7b, 0x0c, 0x93, 0x61, 0x2c, 0x64, 0x2a, 0xfc, + 0x29, 0x53, 0xc1, 0x23, 0x84, 0x12, 0x37, 0xeb, 0x1e, 0x69, 0x37, 0x21, 0x4e, 0xa9, 0x16, 0xa5, 0x4c, 0xc6, 0xbf, + 0xf5, 0x13, 0x28, 0xcf, 0x29, 0x5a, 0xa6, 0x1f, 0x15, 0x2e, 0xd3, 0x37, 0xeb, 0xe3, 0xd2, 0x33, 0x11, 0xea, 0xcc, + 0xc5, 0xa6, 0xd6, 0xe9, 0x18, 0x3b, 0xa5, 0x53, 0x1b, 0xf6, 0xa5, 0x52, 0x5c, 0x56, 0x14, 0xfe, 0x8d, 0x44, 0x56, + 0x3d, 0x23, 0x8e, 0xff, 0x2b, 0x6b, 0x9f, 0x61, 0x15, 0xf8, 0x65, 0x20, 0xef, 0x17, 0x00, 0x1f, 0xd7, 0x75, 0x99, + 0xde, 0x6e, 0x80, 0x36, 0x84, 0x86, 0xbf, 0xe7, 0x23, 0x03, 0xa6, 0xfb, 0x08, 0x67, 0x48, 0x0f, 0x75, 0xce, 0xe9, + 0xac, 0x4c, 0xe7, 0x5c, 0x85, 0xb5, 0x04, 0x7b, 0x39, 0x69, 0x72, 0xb9, 0x2e, 0x41, 0xcd, 0x04, 0x6e, 0x1f, 0xda, + 0x23, 0x42, 0xa8, 0x4d, 0x59, 0x4d, 0x2f, 0xa1, 0xe6, 0x9d, 0x9c, 0x76, 0x34, 0x29, 0xc1, 0x55, 0x43, 0x67, 0xe5, + 0xfa, 0xaf, 0xc3, 0xa1, 0x77, 0x9b, 0x15, 0xd1, 0x1f, 0x3d, 0xf4, 0x77, 0xdc, 0xde, 0xa4, 0x5f, 0x20, 0x5a, 0xc6, + 0xfa, 0x1b, 0x32, 0xa0, 0xe3, 0xc9, 0xf0, 0xb6, 0xd8, 0xf6, 0xd8, 0x17, 0xd4, 0x60, 0xe9, 0xeb, 0xc7, 0x1f, 0x20, + 0xa1, 0xea, 0xda, 0x17, 0x16, 0x4f, 0x98, 0xa7, 0x44, 0xdb, 0xc2, 0x87, 0xb0, 0xd0, 0x2f, 0x10, 0x19, 0x09, 0xe1, + 0xa6, 0xb2, 0x7b, 0x94, 0xb4, 0x0b, 0x7d, 0xe9, 0x6b, 0xd9, 0x57, 0xbe, 0x73, 0x01, 0xb0, 0xb2, 0xcf, 0x6d, 0xb8, + 0x27, 0xfd, 0x29, 0xd5, 0x87, 0xed, 0x6f, 0xc9, 0x02, 0x0a, 0x2d, 0xac, 0xa7, 0x72, 0x76, 0xae, 0x4b, 0x9e, 0x66, + 0xd3, 0xfd, 0x1a, 0xf6, 0xa8, 0x7b, 0xf4, 0x9a, 0x0a, 0xce, 0x2f, 0xcd, 0xe8, 0xfd, 0xd3, 0x50, 0xa8, 0x8e, 0x3a, + 0x77, 0x90, 0x75, 0x69, 0x5d, 0x72, 0x7e, 0xb3, 0x72, 0x47, 0x61, 0x7e, 0x1f, 0x82, 0x67, 0x58, 0xf7, 0xee, 0xe2, + 0xbc, 0xf7, 0x67, 0x6b, 0x8e, 0xfc, 0x98, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0xf6, 0xdb, + 0x20, 0x87, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, + 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xdb, 0x20, 0xd7, 0x5d, 0x30, 0xcd, 0x91, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x92, 0x0a, + 0xcd, 0x22, 0x6d, 0x95, 0x8c, 0x7f, 0x47, 0xda, 0x4c, 0xc9, 0x1e, 0x5b, 0x03, 0xef, 0x25, 0x28, 0x27, 0xc3, 0x14, + 0xc3, 0x77, 0x7c, 0xbd, 0xf3, 0x98, 0x7b, 0xce, 0x31, 0xdb, 0xa4, 0xec, 0x08, 0x26, 0xc9, 0xc6, 0x37, 0x14, 0x6f, + 0xf8, 0xfe, 0xb6, 0x12, 0x25, 0x80, 0x5e, 0x16, 0xfc, 0x85, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, + 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, + 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, + 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, + 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, + 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, + 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, + 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, + 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, 0xf3, 0xfd, 0x95, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, + 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, + 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, + 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, + 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, + 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, + 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, + 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, + 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, + 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, + 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, + 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, + 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, + 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, + 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, + 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, + 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, + 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, + 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, + 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, + 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, + 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, + 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, + 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd1, + 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, + 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe1, 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, + 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, + 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, + 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, + 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, + 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, + 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, + 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, + 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, + 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, + 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, + 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, + 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0x7c, 0xa1, 0x56, 0xda, 0x59, 0x99, + 0x78, 0x35, 0xcb, 0xc0, 0x59, 0xe0, 0xa2, 0xf2, 0x59, 0xa6, 0x55, 0x4f, 0x55, 0x82, 0x3e, 0xaf, 0xe4, 0x04, 0x57, + 0x82, 0x93, 0x0d, 0xc8, 0x2f, 0x40, 0x92, 0xa6, 0x94, 0x35, 0xe5, 0x8b, 0x4b, 0xba, 0x21, 0xa3, 0xe7, 0xbc, 0xe7, + 0x45, 0xc3, 0xd0, 0xbf, 0xf0, 0x4a, 0x08, 0xdf, 0xc4, 0x6d, 0x1b, 0xa5, 0xb0, 0xbf, 0x09, 0x2c, 0x3e, 0x61, 0x3f, + 0x78, 0x4b, 0x7f, 0x3a, 0x0e, 0xc2, 0x21, 0x72, 0x43, 0xc5, 0x1c, 0xd8, 0xd3, 0x80, 0xc5, 0x26, 0xbe, 0xda, 0x4c, + 0xe2, 0xc1, 0xc0, 0xd7, 0x19, 0x8b, 0x59, 0x0c, 0x34, 0xc8, 0xf1, 0xe0, 0x72, 0xae, 0x4f, 0x08, 0xfd, 0x30, 0xa2, + 0x72, 0x54, 0xa0, 0x73, 0x10, 0x0d, 0x96, 0x80, 0xa7, 0xde, 0xca, 0x06, 0x49, 0xc6, 0x24, 0x93, 0xb8, 0xd6, 0x24, + 0xd5, 0xe1, 0x84, 0xd6, 0x81, 0x8e, 0xab, 0x0b, 0xe8, 0x7c, 0x5c, 0xf7, 0x3e, 0x5e, 0x0d, 0x17, 0x54, 0xfa, 0x85, + 0x18, 0x78, 0xf5, 0x74, 0x1c, 0x5c, 0xd2, 0xad, 0x70, 0xb1, 0x0a, 0xb7, 0x3f, 0xcb, 0x07, 0x8e, 0x3b, 0x2a, 0x69, + 0x08, 0x0c, 0xde, 0x1e, 0xba, 0x9b, 0x19, 0x1a, 0xea, 0xa4, 0x7d, 0x18, 0x87, 0x72, 0x88, 0x55, 0x2b, 0x2e, 0xa4, + 0x37, 0x82, 0x6f, 0x17, 0x8a, 0xb1, 0x6c, 0xec, 0xd2, 0x50, 0x14, 0xfe, 0x0a, 0x60, 0x87, 0xda, 0x5f, 0xa9, 0xe4, + 0x63, 0x64, 0x54, 0xd3, 0x40, 0xc7, 0x00, 0x2c, 0x59, 0x9a, 0x48, 0xaa, 0x48, 0x23, 0xf1, 0x47, 0x66, 0xac, 0xa3, + 0xa6, 0xeb, 0x0b, 0xa6, 0xaa, 0x45, 0xd2, 0xed, 0x4c, 0x62, 0x39, 0x91, 0xa4, 0xb6, 0xfb, 0x88, 0x18, 0x0c, 0x7c, + 0xb0, 0x11, 0xd3, 0x4c, 0x84, 0x23, 0x1e, 0x95, 0xc8, 0xa2, 0xcb, 0x6f, 0xa3, 0x4c, 0xda, 0xbe, 0xac, 0xc8, 0x16, + 0x04, 0xd3, 0x93, 0xe8, 0x83, 0x24, 0xe5, 0x54, 0x24, 0xd2, 0x8c, 0x10, 0xe0, 0xc7, 0x93, 0xf2, 0x4a, 0x7f, 0x0e, + 0x9a, 0x56, 0x82, 0x97, 0x0c, 0x92, 0x47, 0xe2, 0x67, 0x52, 0x30, 0x8b, 0xb1, 0x6a, 0x30, 0xc0, 0x72, 0xaa, 0x67, + 0x8e, 0x49, 0xfa, 0x6f, 0x9d, 0x4e, 0xd8, 0x2f, 0xbd, 0xdc, 0xd6, 0xf2, 0xa6, 0xb9, 0xf7, 0xd2, 0xab, 0x58, 0xaa, + 0x61, 0x19, 0xf4, 0x5f, 0x13, 0xed, 0x82, 0xad, 0x2d, 0x63, 0xc2, 0xaa, 0x1f, 0x40, 0xda, 0x23, 0x5d, 0x5e, 0x35, + 0xcc, 0x99, 0xe0, 0xd1, 0x85, 0x35, 0x0f, 0xa2, 0x0b, 0xe1, 0x23, 0x97, 0xdd, 0x24, 0xb9, 0x1a, 0x4f, 0xfc, 0x70, + 0x30, 0x50, 0x00, 0xb4, 0xb4, 0x4e, 0x8a, 0x41, 0xf8, 0x4c, 0xc8, 0x81, 0x34, 0x3a, 0xaa, 0x02, 0x2c, 0x96, 0xd9, + 0x55, 0x39, 0xc9, 0x06, 0x03, 0x1f, 0xc4, 0xc6, 0xc4, 0x6e, 0x68, 0x36, 0xf7, 0xd9, 0x89, 0x82, 0xac, 0x36, 0x87, + 0xad, 0x99, 0x6e, 0x81, 0x01, 0xc0, 0x20, 0x22, 0x58, 0xee, 0x73, 0x23, 0x1f, 0x51, 0xa7, 0xa7, 0x30, 0x02, 0x82, + 0x5f, 0x4e, 0x04, 0x22, 0x17, 0x09, 0xd4, 0x03, 0xcc, 0x04, 0x98, 0x51, 0xc5, 0xf0, 0x12, 0xd8, 0xc5, 0x73, 0xf3, + 0x8a, 0x41, 0xff, 0xa2, 0x49, 0x96, 0x68, 0x2a, 0x71, 0x34, 0x46, 0x4e, 0xa5, 0x31, 0x32, 0x20, 0x76, 0x71, 0xfc, + 0x7b, 0x4a, 0x8f, 0x82, 0x94, 0x7d, 0xae, 0x0c, 0x71, 0x38, 0x8a, 0xaf, 0x60, 0xd5, 0x38, 0x1c, 0x6a, 0xf3, 0x7a, + 0x3a, 0xab, 0xe7, 0x03, 0x11, 0xc0, 0x7f, 0x43, 0xc1, 0x7e, 0xd1, 0x54, 0xe4, 0x06, 0xa9, 0xf3, 0x70, 0x48, 0x41, + 0x3e, 0xd5, 0x4d, 0xfe, 0xbe, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, + 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, + 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, + 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, + 0x7f, 0x95, 0xee, 0xcd, 0xa9, 0x0d, 0x72, 0x00, 0xdb, 0xbd, 0x87, 0xdb, 0x31, 0x7a, 0x20, 0x83, 0x37, 0x42, 0xce, + 0x39, 0xbf, 0x9c, 0x5a, 0x33, 0x26, 0x1a, 0x16, 0xac, 0x1c, 0x46, 0x7e, 0x80, 0x8c, 0x97, 0x53, 0x60, 0x65, 0x3f, + 0x2a, 0xe2, 0xd2, 0x1f, 0x46, 0xfe, 0xc5, 0xf3, 0x20, 0xe3, 0x5e, 0x34, 0xec, 0xf8, 0x02, 0xec, 0xd5, 0x17, 0xcf, + 0x59, 0x34, 0xe0, 0xd5, 0x55, 0x3d, 0xcd, 0x82, 0x61, 0xc6, 0xa2, 0xab, 0x62, 0x08, 0x3e, 0xb4, 0x2f, 0xca, 0x41, + 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x47, 0x70, 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, + 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x85, 0xd4, 0x6c, 0x14, 0x68, 0x4e, 0xae, 0xd0, 0x9c, + 0xac, 0x84, 0x5a, 0xf2, 0x49, 0x85, 0x13, 0x76, 0x3e, 0xc9, 0x95, 0xdd, 0x68, 0x8c, 0x81, 0x8b, 0xf6, 0xdc, 0x16, + 0x46, 0x66, 0x3a, 0x4b, 0xd1, 0x80, 0x85, 0x67, 0xe2, 0x94, 0xc6, 0x80, 0xf6, 0xe5, 0xc0, 0xd2, 0x86, 0xfc, 0x28, + 0x67, 0x06, 0xda, 0x86, 0x94, 0x46, 0xcd, 0xc0, 0x9f, 0xa9, 0x09, 0xf3, 0x2b, 0x58, 0x89, 0x20, 0xaa, 0x0b, 0x30, + 0x49, 0x72, 0x32, 0x1a, 0x29, 0x2b, 0x91, 0x9c, 0x03, 0xde, 0x47, 0xf0, 0x64, 0x11, 0xdb, 0xda, 0x9f, 0xd2, 0xff, + 0xea, 0xf0, 0xb9, 0xf4, 0x9f, 0x09, 0x60, 0x21, 0x97, 0x06, 0x91, 0x81, 0xc2, 0x21, 0x35, 0x95, 0x88, 0x13, 0xc7, + 0x33, 0xf0, 0x0d, 0x5c, 0xa0, 0x29, 0xa0, 0x3f, 0xa8, 0x19, 0x45, 0x64, 0xe1, 0xaf, 0x9e, 0xdd, 0xd4, 0x8d, 0x9e, + 0x67, 0xce, 0x6b, 0xd0, 0xcc, 0x40, 0x48, 0x8f, 0x53, 0xf5, 0x36, 0x24, 0x3a, 0x2f, 0x2f, 0xf5, 0xcb, 0x84, 0x48, + 0x56, 0x44, 0x9e, 0xbe, 0xcf, 0xc1, 0x3c, 0xa2, 0x08, 0x1d, 0x5c, 0x99, 0x87, 0xc3, 0xb9, 0xa0, 0xf0, 0x1d, 0xe5, + 0xf9, 0x80, 0xd3, 0x2c, 0x4a, 0x40, 0x1b, 0xc8, 0x72, 0x53, 0xe6, 0x3a, 0x69, 0x99, 0xba, 0xf7, 0x60, 0x25, 0xa8, + 0xd0, 0xcd, 0x29, 0x28, 0x94, 0x91, 0xa0, 0x94, 0x56, 0x83, 0x50, 0xaa, 0xc3, 0x22, 0x88, 0x1c, 0xb2, 0x10, 0x70, + 0x33, 0x15, 0x8d, 0x96, 0x34, 0x3c, 0xc2, 0xb9, 0x81, 0x42, 0x00, 0x12, 0x7b, 0xaa, 0x28, 0xe3, 0x72, 0x08, 0xf8, + 0x28, 0xe1, 0x10, 0x67, 0x4d, 0xda, 0xf2, 0x1c, 0xc4, 0xb1, 0x5c, 0xf2, 0x75, 0x85, 0x60, 0x10, 0xa1, 0xcf, 0x90, + 0x3f, 0x59, 0xce, 0xbf, 0x5b, 0x87, 0x69, 0x47, 0xf8, 0xb0, 0xab, 0x2d, 0xb8, 0x98, 0xdd, 0xce, 0x27, 0x10, 0xdf, + 0x72, 0x3b, 0x3f, 0xc6, 0x10, 0x59, 0xf8, 0x83, 0xbb, 0xa1, 0xe4, 0x8a, 0x42, 0x97, 0xf5, 0x88, 0x14, 0xd9, 0xd3, + 0x35, 0x47, 0x10, 0x1c, 0x68, 0xd5, 0x20, 0x43, 0x23, 0xf1, 0xc5, 0x73, 0xc8, 0x1a, 0xac, 0xf9, 0xe7, 0x8a, 0x9c, + 0xd5, 0xfd, 0xc9, 0x06, 0xaa, 0x49, 0x26, 0x6b, 0x45, 0xe5, 0xfc, 0xf5, 0xaa, 0x2c, 0x4f, 0x56, 0x65, 0xb8, 0x1a, + 0x74, 0x55, 0x65, 0xc9, 0x91, 0xda, 0x00, 0xad, 0xe9, 0x0a, 0x31, 0x14, 0xb2, 0x06, 0x4b, 0xab, 0x2a, 0x6b, 0xea, + 0x13, 0x08, 0xf4, 0x01, 0x96, 0x51, 0xb3, 0x9f, 0x0e, 0xff, 0x15, 0xfc, 0x4b, 0x85, 0x2c, 0xd5, 0x69, 0x9d, 0x89, + 0x5f, 0x83, 0x25, 0xc3, 0x3f, 0x7e, 0x0b, 0xd6, 0x80, 0x25, 0x40, 0x96, 0xbb, 0x8d, 0x8d, 0xd6, 0x2b, 0xaf, 0x10, + 0x5f, 0x6a, 0x7d, 0xd1, 0x6f, 0xdd, 0x26, 0x6a, 0x05, 0x18, 0xa1, 0xd0, 0x22, 0xc0, 0x56, 0x0f, 0xdc, 0x53, 0xf0, + 0x03, 0x31, 0x9c, 0x6b, 0xd2, 0x9a, 0x3a, 0xe1, 0x75, 0x36, 0x8e, 0x44, 0x54, 0x6f, 0xe1, 0xe2, 0x5e, 0x6f, 0x2d, + 0xfe, 0x46, 0x05, 0x02, 0x20, 0x8b, 0x29, 0xd6, 0xce, 0x1b, 0xd2, 0x2b, 0xc3, 0x4e, 0x42, 0xef, 0x0d, 0x3b, 0x81, + 0xbc, 0x38, 0xec, 0x14, 0xba, 0x44, 0xdb, 0x29, 0x52, 0x13, 0x6d, 0x27, 0x2d, 0x56, 0x61, 0x09, 0xc1, 0xaf, 0xda, + 0x5b, 0x47, 0xd9, 0xbe, 0xc8, 0x12, 0xa6, 0x2d, 0x60, 0x94, 0x5b, 0xf5, 0x99, 0x53, 0xc4, 0x4a, 0xd9, 0x3b, 0x9d, + 0x54, 0xb9, 0x8b, 0x7c, 0x6a, 0x35, 0x45, 0x26, 0x7f, 0x7f, 0xdc, 0x22, 0xf9, 0xe4, 0xe7, 0x76, 0xc3, 0x64, 0xfa, + 0xc7, 0xa3, 0x2f, 0xa0, 0x2b, 0xb2, 0xd3, 0x27, 0x10, 0x90, 0xa9, 0xa0, 0x5a, 0xdd, 0x2a, 0xa6, 0x79, 0xbb, 0xca, + 0x6e, 0x2f, 0x94, 0x18, 0x4e, 0x67, 0x27, 0xe1, 0xd1, 0x66, 0xc8, 0xc0, 0x21, 0x08, 0x14, 0x42, 0x45, 0x31, 0x3c, + 0x02, 0xb5, 0x46, 0xf2, 0x01, 0x7e, 0xb4, 0x3b, 0x15, 0x44, 0x6a, 0x37, 0x15, 0x37, 0x4e, 0x6e, 0xba, 0x5e, 0x0a, + 0xd4, 0x3a, 0x25, 0x2b, 0x80, 0x12, 0xa2, 0xfe, 0x24, 0xb6, 0xf5, 0x2b, 0xb8, 0x62, 0xf3, 0x7d, 0xa3, 0xe8, 0xc9, + 0xf5, 0x29, 0xea, 0x56, 0x5c, 0x9d, 0xa6, 0xad, 0xe6, 0xd8, 0x71, 0x86, 0x1c, 0x3c, 0x2b, 0x08, 0xb6, 0xa3, 0x12, + 0xe5, 0x75, 0xbb, 0xe9, 0x98, 0xd8, 0xea, 0x9f, 0x45, 0xb5, 0xb9, 0x83, 0x8a, 0x88, 0xf8, 0x28, 0xbb, 0x79, 0xd2, + 0x7e, 0x07, 0x7b, 0xac, 0xd5, 0x20, 0xb2, 0xcf, 0xe0, 0x2a, 0xd7, 0x69, 0x91, 0xdb, 0x32, 0x38, 0xff, 0xf0, 0x6a, + 0x57, 0x61, 0x93, 0x63, 0x5d, 0x5d, 0xcd, 0x54, 0x27, 0x15, 0x1b, 0x18, 0x6b, 0x5a, 0x4b, 0x35, 0x8f, 0x21, 0xe9, + 0xae, 0x2c, 0xce, 0xaa, 0xa4, 0x9b, 0x9e, 0x1b, 0x67, 0x0a, 0x31, 0x70, 0xb6, 0x1a, 0x2d, 0x67, 0x18, 0xa2, 0xeb, + 0xc3, 0x2c, 0xf1, 0x5b, 0x3d, 0xe5, 0x3e, 0x0f, 0xb7, 0x7e, 0x57, 0x2f, 0x38, 0x99, 0xec, 0x27, 0xc7, 0xb9, 0xdb, + 0x45, 0xda, 0x4f, 0x7c, 0x1b, 0xe6, 0x5f, 0xdf, 0x20, 0xee, 0x44, 0xfd, 0xcf, 0x0a, 0x80, 0x06, 0x37, 0x79, 0x2c, + 0x51, 0xea, 0xf7, 0xaa, 0xfa, 0x41, 0xcd, 0x54, 0x4d, 0x03, 0xc1, 0x9c, 0x4a, 0x01, 0x7f, 0xb8, 0x5d, 0xb8, 0xe2, + 0x11, 0x37, 0x2c, 0x8c, 0x7f, 0x7a, 0x35, 0x3b, 0x15, 0x54, 0x06, 0x6e, 0xc6, 0x7f, 0x7a, 0x82, 0x9d, 0xc2, 0x5a, + 0x01, 0x59, 0xe1, 0x4f, 0x2f, 0x7f, 0xe4, 0xfd, 0x8a, 0xff, 0xe9, 0x55, 0x8f, 0xbc, 0x8f, 0x38, 0x2f, 0x7f, 0x22, + 0xa9, 0x13, 0xa2, 0xba, 0xfc, 0x49, 0x98, 0x62, 0xab, 0x34, 0x7f, 0x4d, 0x0a, 0x9f, 0xe0, 0x33, 0xf0, 0x1d, 0xae, + 0xc2, 0xad, 0xf9, 0x0d, 0x1e, 0x3b, 0x16, 0xdb, 0x2e, 0xf5, 0x05, 0x94, 0x23, 0xb0, 0x88, 0xdc, 0x7e, 0xbb, 0xb2, + 0x5f, 0x2d, 0x8c, 0x32, 0xc6, 0xee, 0x4b, 0x56, 0xa2, 0x74, 0xd6, 0xef, 0x17, 0x52, 0x30, 0xb2, 0x0b, 0x6b, 0xb4, + 0x47, 0xa9, 0x7a, 0xf5, 0x3a, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, + 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, + 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, + 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0x5e, 0xe4, 0x18, 0x5b, 0x91, 0x03, 0x07, 0x32, 0xfc, 0x80, 0xc0, + 0x7b, 0xd9, 0xbf, 0x82, 0xc1, 0x30, 0xc1, 0x8d, 0x8c, 0x3a, 0x39, 0x67, 0x7f, 0x62, 0x60, 0x06, 0xf5, 0xa4, 0x76, + 0x9f, 0xdd, 0xab, 0xc0, 0x5e, 0x38, 0x03, 0xda, 0xbb, 0x31, 0xfa, 0x59, 0x15, 0x6b, 0x27, 0xfd, 0x53, 0xb1, 0x86, + 0x64, 0x3a, 0x2c, 0x8e, 0xb6, 0x69, 0x78, 0x24, 0x4f, 0x8e, 0xe3, 0x4d, 0xff, 0x70, 0x18, 0xe3, 0xc7, 0x51, 0x7e, + 0x6d, 0x01, 0xaf, 0xe2, 0x16, 0xd2, 0x58, 0xa4, 0xe8, 0x1d, 0x88, 0x39, 0x14, 0xbd, 0x64, 0xbf, 0x65, 0xbc, 0x9c, + 0x08, 0x4a, 0x49, 0x62, 0xc3, 0x3b, 0xd2, 0xd3, 0xb4, 0x1e, 0x6d, 0x65, 0xc0, 0x7e, 0x3d, 0xda, 0xd1, 0x5f, 0xa0, + 0x78, 0xb4, 0xf0, 0x97, 0xf4, 0x77, 0x71, 0x37, 0xf7, 0x9c, 0x6f, 0x1a, 0xdf, 0x11, 0x17, 0x28, 0xd6, 0xec, 0xfe, + 0x9a, 0x96, 0xce, 0x3a, 0x10, 0x1c, 0xf0, 0x16, 0xbb, 0x68, 0xdf, 0x6f, 0x5c, 0xa7, 0xa7, 0xfd, 0xb7, 0x6e, 0x8d, + 0xf2, 0xbd, 0x7f, 0x4a, 0x94, 0x83, 0xfd, 0x6b, 0x17, 0xcd, 0xdf, 0x7e, 0xca, 0x90, 0x54, 0x68, 0x6e, 0xb0, 0x9d, + 0x6c, 0x11, 0xd6, 0xc6, 0x38, 0xa8, 0xd8, 0x5d, 0x19, 0x46, 0xc0, 0xa0, 0x8e, 0xfd, 0x8f, 0x3e, 0x9b, 0x36, 0x64, + 0x1f, 0x00, 0x2a, 0x57, 0x21, 0x60, 0x0f, 0xc0, 0x89, 0x46, 0xb8, 0x01, 0x6e, 0x35, 0x5a, 0xd2, 0x41, 0xdd, 0x16, + 0x0c, 0x44, 0x4b, 0xd8, 0xc8, 0xdb, 0xae, 0x4e, 0x5f, 0x11, 0x3e, 0xd4, 0x4e, 0x4a, 0x87, 0xf2, 0x57, 0xcf, 0xd9, + 0xff, 0xec, 0xb0, 0xa6, 0xa6, 0xdc, 0x00, 0x66, 0xce, 0x4a, 0xe4, 0x15, 0x42, 0xa7, 0xc8, 0xef, 0x55, 0x5d, 0x89, + 0xe1, 0xb2, 0x16, 0x65, 0x67, 0x76, 0xeb, 0x44, 0xef, 0x9c, 0x82, 0x5a, 0x2a, 0x1b, 0xe4, 0x24, 0xd5, 0xe6, 0x23, + 0x6b, 0x05, 0x25, 0xea, 0x1a, 0x05, 0x8e, 0x4f, 0xb9, 0x76, 0xff, 0xef, 0x9c, 0x09, 0x6a, 0xb6, 0x51, 0xdd, 0x5f, + 0xeb, 0xa7, 0xaa, 0x26, 0xb1, 0x00, 0x97, 0x93, 0x34, 0xef, 0x78, 0x84, 0xd5, 0x3f, 0x4e, 0x96, 0x22, 0xd0, 0xeb, + 0x88, 0x76, 0x25, 0x20, 0x41, 0x3b, 0x39, 0x0b, 0x15, 0x81, 0x02, 0x7d, 0xfd, 0xfb, 0x4d, 0x9a, 0xc5, 0x72, 0x35, + 0xdb, 0xc3, 0x44, 0x59, 0xac, 0x87, 0x08, 0x72, 0x66, 0xea, 0x60, 0xbf, 0xa7, 0x19, 0xcd, 0xc2, 0x2b, 0x53, 0x82, + 0x4b, 0x71, 0x15, 0x15, 0x39, 0xf8, 0x1c, 0xe2, 0x0b, 0x9f, 0x0a, 0xb9, 0x41, 0x44, 0xd3, 0xef, 0x25, 0xaa, 0x1d, + 0x29, 0x90, 0x43, 0xc9, 0x4f, 0x88, 0xbf, 0x64, 0x6d, 0x8c, 0xfb, 0xa5, 0x53, 0xed, 0x57, 0x0a, 0xc1, 0xfd, 0x67, + 0x5b, 0x6c, 0x54, 0x79, 0xa2, 0x47, 0x9f, 0x62, 0xfd, 0x4f, 0x16, 0x50, 0xaa, 0xfb, 0x36, 0x38, 0x15, 0x8f, 0xc2, + 0x4d, 0x5d, 0xdc, 0x20, 0xb4, 0x40, 0x39, 0xaa, 0x8a, 0x4d, 0x19, 0x11, 0x27, 0xec, 0xa6, 0x2e, 0x7a, 0x9a, 0x03, + 0x9d, 0x3a, 0x2c, 0x4d, 0xe4, 0x89, 0xd0, 0x6e, 0x41, 0xf7, 0x34, 0xc7, 0x4a, 0xbc, 0x94, 0xa5, 0x83, 0xac, 0x13, + 0x69, 0x42, 0xe5, 0xae, 0xae, 0x3a, 0x2a, 0x95, 0xba, 0xe1, 0x4d, 0xaa, 0x19, 0x7f, 0x97, 0xe6, 0x4f, 0x2c, 0xfb, + 0x4d, 0xeb, 0xb7, 0x5a, 0xed, 0x8d, 0xd5, 0xa3, 0x92, 0x35, 0xc7, 0xd9, 0x84, 0xa4, 0xf4, 0x09, 0xdb, 0xcd, 0xa4, + 0x6b, 0x1d, 0x78, 0x12, 0x5c, 0x0e, 0x3d, 0x01, 0x15, 0x83, 0x26, 0xde, 0xee, 0x02, 0xf5, 0x08, 0x3c, 0x03, 0xe5, + 0x13, 0xb5, 0x0e, 0xf8, 0x79, 0xad, 0xe5, 0x29, 0x23, 0x0c, 0xab, 0x9d, 0x45, 0xcb, 0xc1, 0x79, 0xa7, 0x08, 0x5c, + 0xbb, 0x12, 0x78, 0x3e, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, 0xa7, + 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, 0x36, + 0x9f, 0x7d, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, 0xcf, + 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, 0x76, + 0x7c, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, 0x88, + 0xc2, 0x2c, 0xfb, 0xb1, 0x28, 0xfe, 0xa8, 0xf4, 0x1d, 0x81, 0x8e, 0xee, 0xbc, 0xa8, 0xd3, 0xe5, 0xee, 0x03, 0x61, + 0x3c, 0x79, 0xf5, 0x11, 0xd1, 0xad, 0xef, 0x33, 0xf7, 0x2b, 0xc0, 0x8d, 0xe0, 0x0e, 0xa2, 0xbd, 0x5b, 0xea, 0x93, + 0x5a, 0x7d, 0xad, 0xd7, 0xce, 0xd3, 0xf3, 0x9b, 0xce, 0xed, 0x77, 0xdf, 0x1c, 0x6d, 0xbd, 0xc7, 0x85, 0xb5, 0xb2, + 0xf4, 0x54, 0x15, 0xec, 0xcd, 0xf2, 0x54, 0x15, 0x4c, 0x1e, 0x78, 0xcd, 0x7e, 0x41, 0x83, 0x2b, 0x1d, 0x6d, 0xbc, + 0x27, 0x6a, 0xe0, 0x16, 0x85, 0xa5, 0xc3, 0x2f, 0xb9, 0x99, 0xbc, 0xc2, 0xfd, 0xa5, 0x22, 0x17, 0xfb, 0xce, 0x19, + 0xdd, 0x99, 0x59, 0xf7, 0xaa, 0xc2, 0xd5, 0x82, 0x5c, 0x1d, 0xd8, 0x5a, 0x76, 0x71, 0xb8, 0x61, 0x11, 0x05, 0x08, + 0xc4, 0xf4, 0x4a, 0xad, 0xfd, 0x11, 0x0d, 0x42, 0x3e, 0x18, 0xf8, 0x05, 0x06, 0xab, 0x02, 0x85, 0x0f, 0x14, 0xc9, + 0x5f, 0x7b, 0x02, 0x76, 0xf1, 0x0c, 0xd0, 0xad, 0xd8, 0xac, 0x18, 0x21, 0x42, 0x26, 0xcb, 0x59, 0x4d, 0x67, 0x90, + 0x4f, 0x7d, 0xf1, 0x8d, 0xad, 0x3a, 0x9d, 0xb7, 0x35, 0x55, 0x4e, 0x1d, 0x0a, 0xdd, 0xdd, 0xd4, 0x9d, 0x5b, 0x17, + 0x79, 0xea, 0x10, 0x72, 0xa5, 0x62, 0x25, 0xa6, 0xa1, 0xe6, 0x49, 0x9a, 0x51, 0x7f, 0xb1, 0xf7, 0x7b, 0x8d, 0xc2, + 0x29, 0x7f, 0x3a, 0x06, 0x55, 0xb8, 0xaa, 0x21, 0x8e, 0xa5, 0x2a, 0x1e, 0xd9, 0x20, 0xd0, 0xbc, 0xba, 0x55, 0x49, + 0x13, 0x32, 0xb9, 0x11, 0x3e, 0x35, 0x29, 0xe5, 0x69, 0xda, 0xa4, 0x95, 0x22, 0x75, 0xf0, 0x41, 0x9d, 0x6a, 0x3c, + 0x37, 0xab, 0x17, 0x00, 0x66, 0x9c, 0x5f, 0xf1, 0x4b, 0xc5, 0x65, 0xd4, 0x56, 0x66, 0xd2, 0xfe, 0xe4, 0x68, 0x6c, + 0xd4, 0xe5, 0xb4, 0x51, 0x46, 0x58, 0x29, 0xcd, 0x49, 0xb1, 0x1c, 0xcf, 0x3f, 0x60, 0xb0, 0xe6, 0x09, 0xec, 0x60, + 0xa2, 0x52, 0xde, 0x47, 0x40, 0x7c, 0x9d, 0xa4, 0x77, 0x09, 0xa4, 0x48, 0xff, 0xd2, 0x25, 0x77, 0x19, 0x1b, 0x88, + 0x31, 0x2b, 0x66, 0x46, 0xff, 0x83, 0xbb, 0xa4, 0x3f, 0x09, 0x01, 0x70, 0x13, 0x4d, 0xa1, 0x53, 0xe7, 0xc9, 0x45, + 0x1e, 0x2c, 0x2f, 0x3c, 0xb4, 0x62, 0xc4, 0x83, 0xbf, 0xbe, 0x08, 0x11, 0xc4, 0x1c, 0x53, 0x3c, 0xfd, 0xc2, 0xe8, + 0x2f, 0xc1, 0x25, 0x46, 0x10, 0xba, 0x7b, 0xe7, 0x30, 0x84, 0x9b, 0x3d, 0xc8, 0xa0, 0xfe, 0x50, 0x87, 0x44, 0x0d, + 0x7f, 0xac, 0x3c, 0xe8, 0xff, 0x3a, 0x13, 0x96, 0xda, 0x4f, 0x4f, 0x07, 0x50, 0xc1, 0xfb, 0x8a, 0xb7, 0x11, 0xf1, + 0x7d, 0xe2, 0x67, 0xf1, 0x60, 0xf3, 0x6c, 0x03, 0xd6, 0xba, 0x27, 0xb9, 0xb1, 0xae, 0x12, 0x36, 0x10, 0xf0, 0x35, + 0x8a, 0xda, 0xf3, 0xda, 0xed, 0x1e, 0xfc, 0xd5, 0xbf, 0x08, 0x19, 0x30, 0x71, 0xfa, 0x3e, 0x73, 0xb2, 0x46, 0x17, + 0x99, 0x4c, 0x1f, 0x3a, 0xe9, 0x1b, 0x9d, 0xee, 0x3b, 0xe1, 0x1f, 0x15, 0xb3, 0xf8, 0x70, 0x4b, 0x5f, 0x69, 0x52, + 0xdc, 0x01, 0x2b, 0x9b, 0x47, 0x05, 0xa1, 0xce, 0x45, 0xf4, 0x95, 0x29, 0xdf, 0x12, 0x6a, 0xf6, 0x8d, 0x25, 0xa5, + 0x74, 0xaf, 0xa1, 0x37, 0x69, 0xad, 0xdf, 0x46, 0x09, 0xc6, 0x44, 0xc7, 0x93, 0x97, 0xf1, 0x58, 0x79, 0x1f, 0x8f, + 0x1b, 0xa9, 0x90, 0x07, 0x20, 0x02, 0x15, 0xe3, 0x4f, 0x57, 0x9e, 0x9c, 0xf4, 0xc2, 0x78, 0x15, 0x4a, 0x41, 0x61, + 0x40, 0x57, 0x20, 0x05, 0x3c, 0x6a, 0x4f, 0x74, 0x16, 0x76, 0x09, 0xf7, 0xe8, 0x26, 0x60, 0xac, 0xcf, 0x3f, 0x02, + 0x9a, 0xbb, 0x70, 0x87, 0x17, 0x03, 0xd4, 0xa6, 0x5e, 0xdd, 0x7d, 0x5c, 0xab, 0x73, 0x38, 0x04, 0x07, 0xab, 0x41, + 0x04, 0xa7, 0xf3, 0xa9, 0xa3, 0x59, 0x16, 0xa0, 0x72, 0xb2, 0xdc, 0xc8, 0x9b, 0x47, 0x8b, 0x5e, 0xdd, 0xf7, 0x96, + 0x69, 0x59, 0xd5, 0x41, 0xc6, 0xb2, 0xb0, 0x02, 0x5c, 0x1d, 0x5a, 0x3f, 0x08, 0x97, 0x85, 0xf3, 0x07, 0x42, 0x10, + 0xbb, 0x57, 0xdb, 0x92, 0xe7, 0x6a, 0x0e, 0x3f, 0x7b, 0xce, 0xd6, 0x5c, 0xa2, 0x4e, 0x3a, 0x13, 0x01, 0x88, 0x3d, + 0x35, 0xab, 0xe8, 0x1a, 0x48, 0xea, 0x34, 0xab, 0xe8, 0x9a, 0x9a, 0x6d, 0x8c, 0x03, 0xf9, 0x68, 0x95, 0x02, 0xf6, + 0xdd, 0x74, 0x1c, 0xac, 0x9e, 0xc5, 0xf2, 0x3a, 0x74, 0xf7, 0x6c, 0xa3, 0x7c, 0x06, 0x75, 0xab, 0x8d, 0x31, 0xb1, + 0xdd, 0x7c, 0x39, 0xd7, 0x6f, 0x07, 0x4b, 0xdf, 0x0e, 0x9a, 0x73, 0xca, 0xbe, 0xd3, 0x65, 0xaf, 0xec, 0xb2, 0xa9, + 0xe7, 0x8e, 0x8a, 0x56, 0x63, 0x40, 0x6f, 0x60, 0xc1, 0xfa, 0x5c, 0xa4, 0xd9, 0xaa, 0x54, 0x25, 0xe0, 0x85, 0xb1, + 0x62, 0x77, 0x7e, 0x23, 0x33, 0x24, 0x61, 0x1e, 0x67, 0xe2, 0x9a, 0xee, 0xb5, 0x30, 0x39, 0x8e, 0x45, 0x32, 0x25, + 0x74, 0x4a, 0x77, 0xb6, 0xa1, 0x73, 0x15, 0x46, 0x11, 0xad, 0x95, 0x54, 0x1a, 0x09, 0x4c, 0xcd, 0x00, 0x25, 0x73, + 0x05, 0x4e, 0xe9, 0x72, 0xff, 0x3b, 0x12, 0xe3, 0xcc, 0x17, 0x25, 0x33, 0xa0, 0x5b, 0x7e, 0x5d, 0xac, 0x5b, 0x29, + 0x32, 0xc2, 0xbc, 0x39, 0x6e, 0xaf, 0xeb, 0x43, 0x20, 0x57, 0xcb, 0x1e, 0x45, 0xe3, 0xa0, 0xd0, 0xe1, 0x52, 0x25, + 0xc0, 0xbe, 0x48, 0xfc, 0x8c, 0xb0, 0xa5, 0x3d, 0x90, 0xdb, 0xa3, 0x33, 0x61, 0xce, 0x39, 0x29, 0xcb, 0xce, 0xa5, + 0x19, 0x5c, 0x4e, 0x5c, 0x09, 0x2e, 0xd2, 0xdb, 0xf6, 0x34, 0x69, 0x69, 0xfb, 0xd8, 0x70, 0x8e, 0x86, 0xb6, 0x41, + 0x77, 0xec, 0x0f, 0xcd, 0xc5, 0x22, 0xb6, 0x2e, 0x16, 0xc3, 0xce, 0xec, 0x47, 0x8b, 0x05, 0xc8, 0x01, 0xe0, 0xa8, + 0xdb, 0xf0, 0x31, 0x5b, 0x02, 0xa7, 0xd5, 0x34, 0x9b, 0x7a, 0x1b, 0x5e, 0x3d, 0x53, 0x3d, 0xbd, 0xe4, 0xf9, 0x33, + 0x61, 0xc6, 0x62, 0xc3, 0xf3, 0x67, 0xd6, 0x91, 0x53, 0x3d, 0x13, 0x4a, 0xb4, 0x2e, 0xa0, 0x19, 0x78, 0x4d, 0x01, + 0x23, 0x96, 0x4c, 0xa6, 0x54, 0x91, 0xc7, 0xbd, 0xe9, 0x46, 0x0d, 0x5e, 0x50, 0x38, 0x04, 0x52, 0x3a, 0xfd, 0xe2, + 0x39, 0xd3, 0xef, 0x5d, 0x3c, 0xef, 0x90, 0xb5, 0x0d, 0xd3, 0xe5, 0x66, 0x98, 0x0c, 0x4a, 0xff, 0x99, 0x99, 0x18, + 0x17, 0xd6, 0x24, 0x01, 0xc4, 0xbf, 0xb1, 0xdf, 0x21, 0x85, 0x9b, 0xf7, 0x97, 0xc3, 0xf8, 0x91, 0xf7, 0x63, 0x64, + 0x4f, 0xd2, 0x0c, 0xb1, 0x66, 0x52, 0x21, 0x77, 0x5f, 0xad, 0x7f, 0x4c, 0xec, 0x26, 0x7b, 0x60, 0x01, 0x88, 0xad, + 0x69, 0xab, 0x5b, 0xde, 0xef, 0x7b, 0xa6, 0x08, 0xf0, 0x83, 0xf2, 0x8f, 0xee, 0x0c, 0xc9, 0xa0, 0xec, 0xba, 0x21, + 0xc4, 0x83, 0xb2, 0x69, 0xda, 0xeb, 0x6d, 0xef, 0xcc, 0x63, 0x75, 0x9d, 0x76, 0x16, 0x57, 0x8b, 0x0c, 0xd2, 0xea, + 0x43, 0x76, 0x9c, 0xd9, 0x67, 0x47, 0x4b, 0xa5, 0xfb, 0x7d, 0x88, 0x88, 0x3b, 0xca, 0xda, 0x7e, 0xbb, 0x05, 0xd7, + 0x70, 0x34, 0x08, 0x5d, 0xd9, 0xdb, 0x65, 0xb4, 0x71, 0x21, 0x8e, 0x7b, 0xa6, 0xf3, 0x05, 0x5f, 0x1e, 0xa5, 0x9d, + 0x07, 0xa7, 0x7a, 0xa2, 0xcf, 0x4d, 0x77, 0x95, 0xc9, 0xb5, 0x0e, 0xab, 0x31, 0xa8, 0xcd, 0xc2, 0x16, 0xee, 0xc2, + 0x36, 0x3a, 0x68, 0xed, 0xcb, 0x82, 0x7f, 0xca, 0x00, 0x7c, 0xe9, 0xd9, 0xb2, 0xed, 0x35, 0x69, 0xf5, 0x46, 0x46, + 0x21, 0xb6, 0xb4, 0xbd, 0xfa, 0x74, 0x94, 0x8f, 0x9b, 0x13, 0x8a, 0x0b, 0x39, 0xca, 0x8f, 0x5e, 0x43, 0xd4, 0xb5, + 0xae, 0xe3, 0x62, 0xd1, 0xe1, 0xc6, 0x55, 0xb7, 0xdd, 0xb8, 0x7e, 0x40, 0xbc, 0x35, 0xda, 0xa4, 0x50, 0x2b, 0x63, + 0x47, 0xf0, 0xb2, 0x7c, 0x38, 0x64, 0x62, 0x38, 0x94, 0x90, 0xa9, 0x8f, 0xdd, 0x1b, 0x9a, 0xf6, 0xf9, 0x69, 0xeb, + 0x47, 0x2c, 0x35, 0x8e, 0x62, 0xc3, 0x3b, 0x7d, 0xe7, 0xb1, 0x35, 0xae, 0xe4, 0xcb, 0x60, 0xb6, 0x2b, 0xa8, 0xb6, + 0xc6, 0x1b, 0xf6, 0x72, 0xfe, 0x7d, 0x25, 0x95, 0xfc, 0xed, 0xcf, 0x70, 0x0d, 0x6f, 0x6d, 0xe9, 0xa0, 0xa9, 0x66, + 0x39, 0xcb, 0xf5, 0xbd, 0xe0, 0xf8, 0xe3, 0xee, 0x15, 0xc1, 0xe0, 0xf7, 0x74, 0x14, 0xe4, 0x62, 0xa9, 0xd6, 0x80, + 0x82, 0x74, 0x64, 0xc7, 0x54, 0x16, 0x18, 0x06, 0xf0, 0x86, 0x0c, 0x90, 0xc7, 0x14, 0xee, 0x86, 0x0a, 0x2f, 0xfc, + 0xa5, 0x22, 0xbb, 0x04, 0xb6, 0x35, 0xe3, 0x63, 0x86, 0x3b, 0x08, 0xf9, 0x47, 0xb0, 0x3b, 0xb6, 0x62, 0xb7, 0x6c, + 0xc1, 0x90, 0x6c, 0x1c, 0x87, 0x31, 0xe6, 0xe3, 0x49, 0x7c, 0x25, 0x26, 0xf1, 0x80, 0x47, 0xe8, 0x18, 0xb1, 0xe6, + 0xf5, 0x2c, 0x96, 0x03, 0xc8, 0xee, 0xb8, 0xd2, 0x01, 0x21, 0x34, 0x36, 0xb4, 0xe4, 0x4d, 0x61, 0x70, 0xb1, 0x63, + 0x9f, 0x91, 0x48, 0xc6, 0x21, 0x58, 0xb4, 0xaa, 0x81, 0x85, 0x89, 0xdd, 0xf2, 0x62, 0xb6, 0x9a, 0xe3, 0x3f, 0x87, + 0x03, 0x02, 0x60, 0x07, 0xfb, 0x86, 0xdd, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x77, 0x96, 0xa7, 0x0b, 0xbb, 0xe7, 0xd7, + 0x7c, 0xcc, 0xce, 0x7f, 0xf0, 0x20, 0x72, 0xf6, 0xfc, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xdb, 0xd4, 0xab, 0xd8, 0x2d, + 0x51, 0x10, 0xde, 0x82, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0x5e, 0xf3, 0x05, 0xc6, 0x8a, 0x9d, 0xa5, 0x4b, 0x0f, 0x33, + 0x42, 0xed, 0xe9, 0x7c, 0x59, 0xab, 0x49, 0xb8, 0xb9, 0x5a, 0x4e, 0x06, 0x83, 0x8d, 0xbf, 0xe3, 0x6b, 0xe0, 0x83, + 0x39, 0xff, 0xc1, 0xdb, 0x51, 0xb9, 0xf0, 0x9f, 0xd7, 0x59, 0xf2, 0xce, 0x67, 0xd7, 0x03, 0xbe, 0x00, 0xbc, 0x25, + 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0xbb, 0xd6, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0xbe, + 0x86, 0x08, 0x8c, 0x04, 0x7c, 0x5b, 0xb5, 0x47, 0xfc, 0x96, 0x1b, 0xc0, 0xaf, 0xcc, 0x67, 0x0f, 0x3c, 0xd4, 0x3f, + 0x13, 0x9f, 0xdd, 0xf0, 0xf7, 0xfc, 0x85, 0x27, 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, + 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, + 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, + 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, + 0xde, 0x14, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, + 0x7c, 0x38, 0xd4, 0x2f, 0x84, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, + 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, + 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, 0xaa, 0xda, 0xbf, 0x25, 0x49, 0xb5, 0xab, 0xb4, + 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, + 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, + 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, + 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, + 0x89, 0x17, 0xe3, 0x69, 0x4d, 0x2c, 0xa9, 0x5d, 0x81, 0x31, 0x7a, 0x5c, 0x15, 0xb5, 0x4f, 0xfd, 0x02, 0x42, 0x91, + 0x6a, 0xcd, 0x1c, 0x6b, 0xdc, 0x18, 0x11, 0x77, 0x58, 0xb9, 0x76, 0x6a, 0xaf, 0x03, 0xb0, 0xbc, 0x1a, 0x17, 0x84, + 0x4d, 0x72, 0xec, 0x5c, 0xc0, 0x6a, 0x34, 0xa4, 0xda, 0x0d, 0xb7, 0x5e, 0x76, 0x7e, 0xf3, 0x38, 0xb1, 0xb5, 0x11, + 0x6e, 0x29, 0xa0, 0x8c, 0xf2, 0x1b, 0xcb, 0x09, 0xbb, 0x53, 0xbd, 0x23, 0x55, 0x3b, 0xe2, 0xc4, 0x05, 0x2c, 0x37, + 0x3c, 0xb5, 0xfa, 0x26, 0x06, 0x27, 0x42, 0xd5, 0x4a, 0xc7, 0x6b, 0x3f, 0xe2, 0x7e, 0x75, 0x5f, 0xf7, 0x4a, 0xf0, + 0x93, 0x90, 0xd7, 0x6f, 0x79, 0x07, 0x80, 0x15, 0x1f, 0xf2, 0x62, 0x5a, 0x38, 0x5a, 0x97, 0x41, 0x19, 0x20, 0x42, + 0x33, 0x00, 0x3a, 0xb9, 0x3a, 0x88, 0xd2, 0xc0, 0x15, 0x77, 0x88, 0xf0, 0xd3, 0xe8, 0x59, 0xfe, 0x22, 0x7c, 0x56, + 0x4d, 0xc3, 0x8b, 0x3c, 0x88, 0x2e, 0xaa, 0x20, 0x7a, 0x56, 0x5d, 0x85, 0xcf, 0xf2, 0x69, 0x74, 0x91, 0x07, 0xe1, + 0x45, 0xd5, 0xd8, 0x77, 0xed, 0xee, 0x9e, 0x90, 0xb7, 0x5d, 0xfd, 0x91, 0x73, 0x65, 0x4f, 0x99, 0x9e, 0x9f, 0xd7, + 0x7a, 0xa5, 0x76, 0x9b, 0xeb, 0x35, 0x6a, 0xa6, 0x3e, 0xca, 0xfe, 0x66, 0x1b, 0x0b, 0x8f, 0xe6, 0x10, 0xfa, 0x8c, + 0xb4, 0x98, 0x7b, 0x9c, 0xeb, 0xcd, 0x9e, 0x14, 0x06, 0x46, 0x4c, 0x2a, 0x19, 0x39, 0xbd, 0xc0, 0x45, 0xa8, 0x42, + 0x0c, 0x6b, 0xe9, 0x6a, 0x9f, 0x75, 0xe9, 0x0d, 0xd4, 0x35, 0xc5, 0xbe, 0x86, 0x0c, 0xbc, 0x68, 0x7a, 0x19, 0x8c, + 0x01, 0x39, 0x02, 0xef, 0xf8, 0x6c, 0x09, 0x07, 0xe6, 0x1a, 0xa0, 0x6f, 0x1e, 0xf5, 0x75, 0xb9, 0xe3, 0x6b, 0xd5, + 0x37, 0xd3, 0xf5, 0x48, 0x29, 0x3f, 0x56, 0xfc, 0xee, 0xe2, 0x39, 0xbb, 0xe5, 0x1a, 0x15, 0xe5, 0x17, 0xbd, 0x58, + 0xef, 0x81, 0xab, 0xee, 0x17, 0xb8, 0xcd, 0xe2, 0xb1, 0x2b, 0x0f, 0x58, 0xb6, 0x65, 0x0f, 0xec, 0x86, 0xbd, 0x67, + 0x4f, 0xd8, 0x5b, 0xf6, 0x8e, 0xfd, 0x84, 0xaa, 0x0d, 0x25, 0xe4, 0xf9, 0x0b, 0x7e, 0x2b, 0x4d, 0x8f, 0x12, 0x95, + 0xec, 0xc1, 0x36, 0xd3, 0x0c, 0x37, 0xec, 0x3d, 0x5f, 0x0c, 0x57, 0xec, 0x2d, 0x64, 0x43, 0x99, 0x78, 0xb0, 0x62, + 0x3f, 0x71, 0x05, 0x62, 0xa6, 0xcf, 0xc2, 0xd2, 0x12, 0x15, 0x4d, 0x99, 0x28, 0x43, 0xbf, 0xe5, 0xf8, 0x22, 0xfb, + 0x09, 0x8b, 0x90, 0x9f, 0x19, 0xae, 0xd8, 0x03, 0x5f, 0x0c, 0x56, 0xec, 0xbd, 0x36, 0x10, 0x0d, 0x36, 0x6e, 0x69, + 0x84, 0x64, 0xa5, 0xcb, 0x92, 0xd2, 0xf4, 0xd6, 0xbe, 0x06, 0x6e, 0xd8, 0x0d, 0xd6, 0xee, 0x09, 0x16, 0x8d, 0x02, + 0xff, 0x60, 0xc5, 0xde, 0x71, 0x09, 0xa0, 0xe6, 0x96, 0x27, 0xbd, 0x42, 0x75, 0x81, 0x74, 0x3f, 0x78, 0xc2, 0xe9, + 0x45, 0xf6, 0x0e, 0xcb, 0xa0, 0xaf, 0x0c, 0x57, 0x6c, 0x8b, 0xb5, 0xbb, 0x31, 0x96, 0x2d, 0xab, 0x7a, 0x12, 0x11, + 0x18, 0x05, 0x95, 0xd2, 0xf2, 0x6f, 0xc4, 0xb2, 0xa9, 0x9b, 0x06, 0xb5, 0xa1, 0x3f, 0x1f, 0x8c, 0xfe, 0xe2, 0xeb, + 0x77, 0x3f, 0x78, 0xa5, 0xbe, 0xf6, 0xfe, 0xe2, 0xb8, 0x56, 0x96, 0xe8, 0x5a, 0xf9, 0x2b, 0x2f, 0x67, 0xbf, 0xcc, + 0x27, 0xba, 0x96, 0xb4, 0xc3, 0x90, 0xaf, 0xe9, 0xec, 0x97, 0x0e, 0x67, 0xcb, 0x5f, 0x7d, 0xbf, 0x31, 0x5d, 0xac, + 0x3e, 0xab, 0x7b, 0xf7, 0x61, 0xb0, 0x69, 0x9c, 0x7a, 0xef, 0x4e, 0xd7, 0x1b, 0x9b, 0x59, 0x6b, 0xcf, 0xcc, 0xff, + 0xe1, 0x4a, 0x6f, 0x71, 0xe8, 0x6e, 0xf8, 0x76, 0xb8, 0xb1, 0x47, 0x41, 0x7e, 0x5f, 0x2a, 0x8d, 0xb3, 0x9a, 0xbf, + 0xf4, 0x3a, 0xa5, 0x58, 0x40, 0x34, 0xfa, 0x64, 0x24, 0xa1, 0x4b, 0x66, 0xe2, 0x19, 0xe2, 0x8b, 0x0c, 0x90, 0xb9, + 0x40, 0x34, 0xbb, 0xe7, 0xe3, 0xc9, 0xfd, 0x55, 0x3c, 0xb9, 0x1f, 0xf0, 0x4f, 0xa6, 0x05, 0xed, 0xc5, 0x76, 0xef, + 0xb3, 0x5f, 0x79, 0x61, 0x2f, 0xc7, 0x5f, 0x7c, 0xf6, 0x45, 0xb8, 0x2b, 0xf4, 0x17, 0x9f, 0xbd, 0x13, 0xfc, 0xd7, + 0x91, 0x26, 0xca, 0x60, 0xef, 0x6a, 0xfe, 0xeb, 0x08, 0x19, 0x3f, 0xd8, 0x67, 0xc1, 0xbf, 0x80, 0xef, 0x77, 0x95, + 0xa0, 0x55, 0xfc, 0x73, 0xad, 0x7e, 0xbe, 0x97, 0x71, 0x39, 0xf0, 0x26, 0xb4, 0x82, 0xde, 0xbc, 0xad, 0xe5, 0x4f, + 0xe2, 0xe1, 0x48, 0xd5, 0x53, 0xc3, 0x3f, 0x8b, 0xc5, 0x2c, 0xea, 0xa3, 0x74, 0x2a, 0x6f, 0x72, 0xcd, 0x33, 0x69, + 0x5d, 0xbe, 0x87, 0x50, 0xe0, 0x6b, 0x1b, 0xa2, 0x60, 0xc7, 0x71, 0x23, 0xb8, 0x66, 0xef, 0x84, 0xcf, 0xb2, 0xe9, + 0x96, 0xdf, 0xf0, 0x27, 0xfc, 0x1d, 0xdf, 0x05, 0x0f, 0xfc, 0x3d, 0x7f, 0xcb, 0x7f, 0xe2, 0x3b, 0xb6, 0x94, 0x68, + 0xa7, 0xf5, 0xf6, 0x32, 0xd8, 0xb2, 0x7a, 0x77, 0x19, 0x3c, 0xb0, 0x7a, 0xfb, 0x3c, 0xb8, 0x61, 0xf5, 0xee, 0x79, + 0xf0, 0x9e, 0x6d, 0x2f, 0x83, 0x27, 0x6c, 0x77, 0x19, 0xbc, 0x65, 0xdb, 0xe7, 0xc1, 0x3b, 0xb6, 0x7b, 0x1e, 0xfc, + 0x24, 0x31, 0x1e, 0xde, 0x09, 0xc9, 0x71, 0xf2, 0xae, 0x66, 0x86, 0x4f, 0x37, 0xf8, 0x2c, 0xac, 0x5f, 0x54, 0xc7, + 0xe0, 0x73, 0xcd, 0x74, 0x8b, 0x03, 0x21, 0x98, 0x6e, 0x6f, 0x70, 0x4b, 0x4f, 0x4c, 0xab, 0x82, 0x54, 0xb0, 0xae, + 0x76, 0x06, 0x8b, 0xba, 0x69, 0x9d, 0xc9, 0x8e, 0x5f, 0x62, 0xdc, 0xe1, 0x97, 0xb8, 0x60, 0xcb, 0xa6, 0xd3, 0x49, + 0xe7, 0xf4, 0x49, 0xa0, 0x37, 0x7f, 0xbd, 0xeb, 0x57, 0xd2, 0x77, 0xa6, 0x68, 0x78, 0xae, 0xb4, 0xc6, 0xad, 0x9d, + 0x3e, 0xb4, 0x76, 0x7a, 0x26, 0x55, 0x68, 0x11, 0x8b, 0xca, 0xa2, 0xaa, 0x90, 0x49, 0x3c, 0xc8, 0xb4, 0x3e, 0x2d, + 0x61, 0xa4, 0xc8, 0x04, 0x34, 0xfa, 0x82, 0x8e, 0x81, 0x9c, 0x2c, 0x0a, 0x6c, 0xc9, 0x37, 0x83, 0x84, 0xad, 0x79, + 0x3c, 0x1d, 0x26, 0xc1, 0x92, 0xdd, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x52, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, + 0x79, 0x6f, 0x95, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x56, 0xe9, 0x0d, 0x7e, 0xeb, 0xec, 0xe7, 0x6b, 0xb5, 0xbf, 0x83, + 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xaf, 0xec, 0x2d, 0x7d, 0x6b, + 0xb6, 0xe9, 0xff, 0xb4, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xc6, 0x9f, 0x3c, + 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xc7, 0x3f, 0x8d, 0xb6, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, + 0x68, 0xef, 0xe4, 0x95, 0xbd, 0x23, 0x6e, 0x79, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, + 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xab, 0xd9, 0xa7, 0xf9, 0x64, 0xcb, 0x8f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, + 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x3b, 0x7e, 0xbc, 0x89, 0x0f, 0xff, 0xe3, + 0x4a, 0xef, 0xbe, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, + 0xf8, 0x13, 0xcd, 0xd2, 0x20, 0xb2, 0x14, 0x8a, 0x3f, 0x99, 0x69, 0xa7, 0xee, 0x54, 0x59, 0xdd, 0x2d, 0xdf, 0xe2, + 0x1e, 0x7f, 0xcb, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0x6f, 0xaf, 0x16, 0x93, 0xc1, 0xe0, 0xd6, 0xdf, 0xdf, 0xf3, 0x70, + 0x76, 0x3b, 0x67, 0xd7, 0xfc, 0x9e, 0x16, 0xd3, 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, + 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, + 0xde, 0xdb, 0x9a, 0x86, 0xb7, 0xfc, 0xa3, 0x77, 0xed, 0x4f, 0xaf, 0x75, 0xcc, 0xcd, 0x44, 0x1d, 0x49, 0x6f, 0x2f, + 0x9e, 0xb3, 0x5f, 0xf9, 0x27, 0x79, 0x9c, 0x7c, 0x11, 0x72, 0xd2, 0xde, 0x20, 0x77, 0x13, 0x9d, 0x12, 0xef, 0xdc, + 0x44, 0xc2, 0x82, 0x40, 0x18, 0x8e, 0x9a, 0x3f, 0x4c, 0xca, 0xa9, 0xb7, 0x03, 0x6e, 0x57, 0x6e, 0xeb, 0x9f, 0x6f, + 0x39, 0xe7, 0x8b, 0xe1, 0xe5, 0xf4, 0x5d, 0xb7, 0x4b, 0x8f, 0x8a, 0x66, 0x53, 0x81, 0x6e, 0xb7, 0x18, 0x7b, 0x75, + 0x32, 0xb3, 0xcc, 0x25, 0x5f, 0x7a, 0x57, 0x9b, 0x99, 0xc7, 0xf4, 0x7e, 0x33, 0xcd, 0x90, 0xc8, 0x17, 0x08, 0x99, + 0x0e, 0x87, 0xbb, 0x73, 0x2c, 0x8f, 0x0f, 0xdf, 0x3e, 0x7b, 0x32, 0x78, 0x82, 0x91, 0x5b, 0x56, 0x34, 0xc8, 0x3b, + 0x3e, 0xcc, 0xea, 0xd6, 0x6d, 0xe3, 0xe2, 0xf9, 0xf0, 0x17, 0xc8, 0x1b, 0x74, 0x3d, 0x34, 0x45, 0xb4, 0xca, 0xef, + 0x28, 0xfa, 0x44, 0xc9, 0x41, 0xc7, 0x13, 0xa8, 0x1d, 0x52, 0xe0, 0xbe, 0x7b, 0xc6, 0x41, 0xbf, 0x81, 0xa5, 0xf6, + 0xfb, 0xe7, 0x9f, 0x88, 0x47, 0x1a, 0xc6, 0xfb, 0xfb, 0x30, 0xfa, 0x23, 0x2e, 0x8b, 0x35, 0x9c, 0xae, 0x03, 0xf8, + 0xdc, 0x33, 0x7d, 0xfb, 0xba, 0xf3, 0x7d, 0x3f, 0xf0, 0xb6, 0xfc, 0x86, 0xbd, 0xe3, 0xde, 0xe5, 0xf0, 0xad, 0xff, + 0xec, 0x09, 0x88, 0x4e, 0x30, 0x2e, 0x9f, 0x31, 0x12, 0xb6, 0xa3, 0x18, 0xb5, 0x0a, 0x3f, 0xd7, 0x10, 0xa2, 0xf5, + 0x09, 0x19, 0xbb, 0x20, 0xfd, 0x83, 0x02, 0xf4, 0x13, 0x02, 0xab, 0x49, 0x6a, 0x14, 0x98, 0xc4, 0xb7, 0x35, 0x24, + 0x90, 0x82, 0x05, 0x42, 0x6f, 0xa0, 0xf8, 0x54, 0xf0, 0x77, 0xc3, 0xcf, 0x24, 0xf9, 0x2d, 0x6a, 0x3e, 0x86, 0xbf, + 0x61, 0x68, 0x26, 0xd5, 0x43, 0x5a, 0x47, 0x89, 0xf7, 0x93, 0xbf, 0x8f, 0xc2, 0x4a, 0xa8, 0x63, 0x21, 0x48, 0xc5, + 0x90, 0x0b, 0x71, 0xf1, 0x7c, 0x72, 0x5b, 0x8a, 0xf0, 0x8f, 0x09, 0x3e, 0x93, 0x0b, 0x4d, 0x3e, 0xa3, 0x27, 0x8d, + 0x7c, 0xff, 0x41, 0xbe, 0x2f, 0x3b, 0x35, 0x58, 0xd4, 0x43, 0x7e, 0x5b, 0xbb, 0xef, 0xcb, 0x29, 0x41, 0x8f, 0xec, + 0x07, 0x34, 0x05, 0x03, 0x35, 0x01, 0x29, 0x43, 0x70, 0x0b, 0x57, 0x7d, 0x4f, 0x15, 0xe4, 0xcb, 0xef, 0x7d, 0x16, + 0x32, 0x5c, 0x65, 0x41, 0x48, 0x72, 0xa9, 0x90, 0xc2, 0xc6, 0x6d, 0x3d, 0xf8, 0xac, 0x31, 0x49, 0x24, 0xe4, 0x94, + 0x80, 0x24, 0x69, 0x6f, 0x20, 0x49, 0xc4, 0xf4, 0x1f, 0xae, 0x93, 0xa6, 0x59, 0x49, 0xe9, 0x86, 0x38, 0x55, 0xaf, + 0x91, 0xe6, 0x2c, 0x78, 0xcf, 0x60, 0xe9, 0x48, 0xb1, 0xe2, 0x9d, 0x31, 0x18, 0xeb, 0x60, 0xa1, 0x3b, 0x59, 0xdc, + 0xaf, 0x92, 0x30, 0x8d, 0x44, 0x95, 0x2f, 0x42, 0xfe, 0xfc, 0x97, 0x12, 0x7f, 0xf4, 0x96, 0x06, 0x22, 0x10, 0xfc, + 0x00, 0xad, 0x07, 0xac, 0xf1, 0xe0, 0x27, 0x56, 0x97, 0x61, 0x5e, 0x65, 0x54, 0xde, 0x6c, 0xc7, 0xb6, 0x73, 0xa6, + 0xaa, 0x16, 0x7c, 0x16, 0x86, 0x16, 0xed, 0x6c, 0xd5, 0x9c, 0xdc, 0xe6, 0x0d, 0xbe, 0x33, 0x49, 0x22, 0xb5, 0x94, + 0x44, 0xda, 0xea, 0xfa, 0x74, 0xe9, 0x75, 0x8b, 0x0a, 0x1a, 0x23, 0x40, 0x2f, 0x49, 0x77, 0x95, 0x4f, 0x28, 0x5e, + 0x59, 0x0d, 0xab, 0xe1, 0xa5, 0x43, 0x11, 0xc6, 0xda, 0x9b, 0x2b, 0x79, 0x76, 0x07, 0xd6, 0x23, 0xb4, 0x76, 0x55, + 0xea, 0x10, 0xb6, 0x9f, 0xe8, 0x3d, 0xa7, 0x52, 0x7f, 0x03, 0xaa, 0xc0, 0xa9, 0xa3, 0xa1, 0x3e, 0x6a, 0xa7, 0x90, + 0xed, 0xdc, 0x5b, 0x12, 0x54, 0xae, 0xe4, 0xa6, 0x4a, 0x8b, 0x52, 0xca, 0x94, 0xaf, 0x65, 0xb6, 0xb2, 0xfb, 0x64, + 0x00, 0xf1, 0x6c, 0x50, 0x20, 0xb9, 0xa8, 0xad, 0xe6, 0x20, 0x7d, 0x34, 0x4b, 0x1c, 0x6b, 0x07, 0x85, 0x97, 0x55, + 0x60, 0xe6, 0x32, 0x97, 0xcb, 0x41, 0xc1, 0x72, 0xbd, 0xd5, 0x4c, 0x33, 0xd5, 0x17, 0xb9, 0xbd, 0xcd, 0x78, 0x99, + 0xfe, 0x9b, 0x25, 0x03, 0x1e, 0x5d, 0x3c, 0xf7, 0x03, 0x48, 0x93, 0xbc, 0x0e, 0x90, 0x04, 0x9b, 0x83, 0x5d, 0xec, + 0x30, 0x6c, 0x15, 0x2b, 0x7b, 0xf2, 0x74, 0xb9, 0x43, 0x53, 0x2e, 0x61, 0x24, 0x27, 0xe6, 0x52, 0xea, 0xfb, 0x92, + 0xea, 0x86, 0x82, 0x93, 0x4d, 0x13, 0x50, 0x0a, 0x68, 0xb7, 0xe0, 0xbf, 0xf0, 0xa9, 0xa1, 0xd3, 0x02, 0x2c, 0xb5, + 0xdd, 0x80, 0xff, 0x42, 0xbf, 0xd8, 0x3e, 0xa2, 0x7e, 0x60, 0x1e, 0xec, 0xcd, 0xda, 0xca, 0x18, 0x10, 0x91, 0xb8, + 0x82, 0x3c, 0x12, 0xfc, 0xa0, 0xd8, 0xd3, 0x65, 0xe2, 0xc0, 0x99, 0xe2, 0x62, 0x29, 0xb5, 0x99, 0x79, 0xed, 0xb7, + 0xd4, 0xc4, 0x9b, 0x28, 0x89, 0x0a, 0xdb, 0x21, 0x8d, 0x5e, 0x52, 0xc6, 0x54, 0xc1, 0x86, 0xe8, 0xbe, 0x6e, 0x82, + 0x29, 0xf0, 0xa6, 0xaa, 0x02, 0x22, 0xd4, 0x5e, 0x64, 0x79, 0x7e, 0xd3, 0x05, 0x56, 0x17, 0x7c, 0x6c, 0x4c, 0xb3, + 0x0b, 0x56, 0x72, 0x35, 0x93, 0x3e, 0xf3, 0x76, 0xa0, 0x85, 0xbc, 0xcb, 0xcb, 0xa2, 0x15, 0xba, 0x1e, 0x44, 0x0b, + 0x7f, 0xaf, 0x39, 0x1e, 0x3d, 0xdb, 0x56, 0x53, 0x9b, 0x7d, 0xad, 0xc5, 0x02, 0x19, 0x88, 0x86, 0xbe, 0x90, 0x33, + 0x0a, 0x77, 0x95, 0xe6, 0x6a, 0xb5, 0xaf, 0xca, 0x20, 0x81, 0x89, 0x20, 0x6b, 0x59, 0x78, 0x8f, 0xee, 0xd5, 0x23, + 0xcd, 0x2b, 0x09, 0x9e, 0xb9, 0xf8, 0x0b, 0x00, 0xa1, 0x3c, 0x49, 0xc8, 0x01, 0x39, 0x80, 0xbf, 0xa5, 0x28, 0x95, + 0x06, 0xf8, 0x67, 0x75, 0x39, 0xb6, 0xf5, 0xfd, 0x9d, 0x56, 0x31, 0xb8, 0xfe, 0x7c, 0xdd, 0xf5, 0xac, 0x1d, 0xe2, + 0x5c, 0xd9, 0xea, 0xb5, 0x65, 0x9a, 0xc7, 0x48, 0x5d, 0x03, 0x70, 0x27, 0xd2, 0x23, 0x10, 0xc9, 0x4c, 0x34, 0xc8, + 0xd9, 0x0b, 0x3e, 0x9e, 0x8a, 0xc7, 0xa4, 0xbd, 0xca, 0xf7, 0xcd, 0x85, 0x3e, 0x18, 0x63, 0xdf, 0x82, 0x06, 0xf1, + 0xd1, 0x6a, 0x6b, 0x05, 0x62, 0xbd, 0x55, 0xea, 0x43, 0x37, 0x46, 0x41, 0x07, 0x8f, 0xb8, 0x91, 0x0b, 0x8e, 0xed, + 0xae, 0xad, 0xa7, 0xf4, 0x15, 0x80, 0xb9, 0x0e, 0x54, 0x32, 0x0c, 0x52, 0xe7, 0x89, 0xc2, 0x24, 0x3f, 0x4f, 0x48, + 0x42, 0x44, 0x75, 0xb6, 0x1c, 0xa5, 0xdc, 0xb4, 0x80, 0xcb, 0x8c, 0x0c, 0x30, 0x9b, 0x34, 0xeb, 0x27, 0x97, 0x2f, + 0x41, 0x2a, 0x0d, 0x11, 0xdc, 0xb0, 0xbd, 0x64, 0x74, 0xeb, 0xa8, 0x1b, 0x54, 0x49, 0xe6, 0xfa, 0xcd, 0xed, 0x2c, + 0x52, 0xe6, 0xcd, 0x47, 0x18, 0x6b, 0xf2, 0x21, 0xac, 0x13, 0xfc, 0x36, 0x40, 0x25, 0x7d, 0x2a, 0xbc, 0x68, 0x04, + 0x10, 0xea, 0x3b, 0x55, 0xc6, 0xa7, 0xc2, 0xcb, 0x46, 0x5b, 0x96, 0x51, 0x0a, 0xd5, 0x05, 0xb3, 0x5b, 0xd3, 0x85, + 0xe8, 0x56, 0xd5, 0x40, 0x1b, 0xb8, 0x76, 0x1d, 0x28, 0xa0, 0xa1, 0xda, 0x95, 0x1b, 0x16, 0x80, 0xd5, 0x4c, 0x04, + 0x86, 0xcb, 0xbf, 0xcf, 0x5f, 0xa9, 0x18, 0x9e, 0x7e, 0x3f, 0xf4, 0xf6, 0xdb, 0x20, 0x1a, 0x6d, 0x2f, 0xd9, 0x2e, + 0x88, 0x46, 0xbb, 0xcb, 0x86, 0xd1, 0xef, 0xe7, 0xf4, 0xfb, 0x79, 0x03, 0x3a, 0x12, 0x61, 0xc2, 0xec, 0xf5, 0x1b, + 0xb5, 0x7c, 0xa5, 0xd6, 0xef, 0xd4, 0xf2, 0xa5, 0x1a, 0xde, 0xda, 0x93, 0x44, 0x10, 0x59, 0xaa, 0x9a, 0x07, 0x49, + 0x91, 0x6a, 0xe9, 0x72, 0x8c, 0x16, 0x23, 0x6a, 0x29, 0x6b, 0x8e, 0x75, 0x22, 0xed, 0x1c, 0x94, 0x0c, 0x70, 0xb4, + 0xb8, 0xaa, 0x31, 0xdd, 0xac, 0x68, 0x09, 0xc4, 0x08, 0x2b, 0xdb, 0x72, 0x71, 0x93, 0xfa, 0xe8, 0x9c, 0x7c, 0xdb, + 0x2a, 0xe5, 0xdb, 0x56, 0xf0, 0xfc, 0x2b, 0x0a, 0xe5, 0x92, 0x6b, 0xd7, 0xb2, 0x69, 0xa1, 0x14, 0xca, 0xb8, 0x06, + 0x5b, 0xfb, 0x26, 0x30, 0x64, 0x3e, 0x52, 0xd4, 0xd8, 0x5e, 0x34, 0xca, 0x21, 0xc8, 0xd6, 0xc1, 0xa8, 0x53, 0x16, + 0x2c, 0xbe, 0xdd, 0x21, 0x03, 0x19, 0xe8, 0xa8, 0x6a, 0xe3, 0xd5, 0xce, 0x4a, 0x7f, 0x58, 0x5e, 0x3c, 0x67, 0x89, + 0x95, 0x4e, 0x7e, 0x53, 0xa1, 0x3f, 0x08, 0xd1, 0x37, 0x65, 0xc3, 0xc1, 0x8b, 0x2e, 0xb6, 0x32, 0x20, 0xde, 0x30, + 0xbd, 0xb7, 0xb1, 0x92, 0xe5, 0xae, 0x29, 0x5f, 0xcc, 0x78, 0xc2, 0x71, 0xf4, 0xe5, 0x6a, 0x11, 0xd6, 0x6a, 0x91, + 0x9d, 0x00, 0x0f, 0xad, 0xd5, 0x52, 0xc8, 0xd5, 0x22, 0x9c, 0x99, 0x2e, 0xd4, 0x4c, 0xcf, 0x40, 0xf3, 0x28, 0xd4, + 0x2c, 0x4f, 0x00, 0x0b, 0x5e, 0x98, 0x19, 0x2e, 0xcc, 0x0c, 0xc7, 0x21, 0x35, 0x4e, 0x0f, 0x7a, 0xaf, 0x73, 0xcf, + 0x2d, 0x77, 0xa3, 0xd3, 0x30, 0x6f, 0x47, 0x1b, 0xcc, 0xf1, 0x41, 0x38, 0x81, 0xf8, 0xc0, 0x12, 0x01, 0x7a, 0x34, + 0xac, 0x8e, 0x1a, 0x2a, 0x47, 0xf1, 0x65, 0x01, 0x48, 0x96, 0x04, 0x20, 0xb9, 0x57, 0xe3, 0x5c, 0x5a, 0x7e, 0x5d, + 0x25, 0x21, 0x47, 0x64, 0xbc, 0x94, 0x76, 0xf7, 0x84, 0x97, 0x23, 0x23, 0x34, 0x4f, 0x16, 0xa9, 0x97, 0xb3, 0x8c, + 0x8d, 0x11, 0xb8, 0x28, 0xf4, 0x9b, 0xaa, 0xdf, 0x4f, 0x4b, 0x2f, 0xa7, 0x76, 0x7e, 0x02, 0x7f, 0xcb, 0x53, 0x67, + 0x91, 0x23, 0xe4, 0xd5, 0xc8, 0x24, 0x2c, 0x2f, 0x95, 0x7a, 0xfa, 0x12, 0x66, 0x50, 0x77, 0x6f, 0x14, 0x80, 0x6b, + 0x91, 0x4b, 0xa7, 0xda, 0x12, 0xae, 0x4c, 0xb9, 0xc1, 0x3e, 0x0f, 0x79, 0x4e, 0x42, 0xa8, 0x44, 0x1e, 0x29, 0xac, + 0xfb, 0xf6, 0xc5, 0xf3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x0e, 0x00, 0x73, 0x30, 0xf5, 0xa2, 0x01, 0x2f, + 0xd5, 0x9c, 0xf9, 0xe8, 0xe5, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x33, 0xf9, 0xc8, 0xf8, 0x96, 0xf9, + 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, 0x6c, 0x50, + 0x09, 0x36, 0x0d, 0x5f, 0x4b, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, 0x1b, 0xb3, + 0x31, 0x2b, 0xd4, 0xce, 0x93, 0xcb, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, 0x71, 0xce, + 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, 0xa6, 0x25, + 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, 0xe8, 0x95, + 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x73, 0xfe, 0x52, + 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd1, 0xb4, 0x04, 0x75, 0x80, + 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x39, 0xe7, 0x5f, 0x6a, 0x43, 0x84, 0x8c, + 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, 0xc0, 0xe3, + 0xbc, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x1c, 0xf7, 0x4e, 0xd3, 0xb0, 0xfd, 0x17, 0xa0, 0x29, 0x86, 0x72, 0x3c, 0xdf, + 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xca, 0x42, 0xda, 0x96, 0x63, 0xb4, + 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xdc, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x7d, 0xdd, 0x63, 0x36, 0xc9, 0x8a, + 0x45, 0xae, 0x22, 0x4e, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, 0x41, 0xc9, + 0x72, 0x5e, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xd5, 0x9c, 0x52, 0xa8, + 0x7d, 0xc5, 0xc3, 0xea, 0xf4, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, 0x7c, 0xe7, + 0xeb, 0xf4, 0x8e, 0x42, 0x77, 0x9c, 0x99, 0x78, 0xaa, 0x02, 0x63, 0xdf, 0xda, 0x11, 0x14, 0x0e, 0x4d, 0xd7, 0x01, + 0x87, 0x69, 0x74, 0xc2, 0xe2, 0x9f, 0xd2, 0x71, 0xf2, 0xa2, 0x56, 0x88, 0x24, 0xff, 0x10, 0x2e, 0x0c, 0x89, 0x05, + 0x79, 0x49, 0xa8, 0x23, 0x32, 0x62, 0x35, 0x2a, 0xd6, 0x42, 0x45, 0xc5, 0x29, 0x1e, 0x6f, 0x15, 0x14, 0x97, 0xa2, + 0x54, 0x29, 0x15, 0xb9, 0x51, 0x29, 0x20, 0x96, 0x0d, 0xbc, 0x5b, 0xc0, 0x01, 0x10, 0x74, 0x96, 0xbb, 0xb5, 0xed, + 0x6e, 0x23, 0xf3, 0x99, 0x69, 0x9e, 0x56, 0x1f, 0xd4, 0xdf, 0xef, 0x97, 0x18, 0x5b, 0xe3, 0xe9, 0xef, 0xdb, 0xb4, + 0xe0, 0xe6, 0x6f, 0x18, 0xa2, 0x3b, 0x40, 0xc4, 0x2c, 0xed, 0xa1, 0x90, 0x05, 0x13, 0x96, 0xa1, 0x2a, 0x4f, 0x39, + 0xea, 0xe5, 0x93, 0x5b, 0x80, 0x50, 0x43, 0xbf, 0x36, 0x3a, 0xd5, 0x55, 0x09, 0xc2, 0xf7, 0x5d, 0xa1, 0x1e, 0x9b, + 0x03, 0x9e, 0x0c, 0x80, 0xbf, 0x22, 0xaf, 0xf5, 0xd8, 0xfe, 0x41, 0x6f, 0xd4, 0x1b, 0x20, 0x88, 0xce, 0x79, 0xe1, + 0x1f, 0x71, 0xae, 0x53, 0x7f, 0xc6, 0x85, 0x20, 0xbe, 0xf5, 0x24, 0xbc, 0x17, 0x67, 0x69, 0x1c, 0x9c, 0xf5, 0x06, + 0xe6, 0x22, 0x50, 0x9c, 0xa5, 0xf9, 0x19, 0x88, 0xe5, 0x88, 0x89, 0x58, 0xb3, 0x3b, 0x80, 0x09, 0x2c, 0x75, 0x1c, + 0xb2, 0xea, 0xd8, 0x7e, 0xff, 0xcd, 0xc8, 0x90, 0xa5, 0x23, 0x0c, 0x8c, 0xfe, 0x5d, 0x81, 0x00, 0x05, 0xcb, 0xcc, + 0xf6, 0x60, 0xd2, 0xd5, 0x9e, 0xd5, 0xf3, 0x66, 0x93, 0x77, 0xf5, 0x8e, 0xd5, 0xb4, 0x9c, 0x9a, 0x56, 0x59, 0x4d, + 0x9b, 0xe4, 0x50, 0x33, 0xd1, 0xef, 0x6b, 0x50, 0xd4, 0x7c, 0x0e, 0x60, 0x6c, 0x98, 0xfc, 0x66, 0x56, 0xcd, 0xfb, + 0x7d, 0x4f, 0x3e, 0x82, 0x5f, 0xc8, 0x56, 0xe6, 0xd6, 0x58, 0x3e, 0x7d, 0x4d, 0x24, 0x66, 0x06, 0xe6, 0xe8, 0xee, + 0x08, 0xdf, 0xeb, 0x46, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x0d, 0x0c, 0x9e, 0x27, 0x7c, 0x70, 0x91, 0xa3, + 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x1b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, 0x78, 0x90, + 0xfd, 0xfe, 0x0a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0xd7, 0x75, 0x51, 0x56, 0xd0, 0xb1, 0xf4, 0xf3, + 0x56, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x92, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, 0x2e, 0x3e, + 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0xe7, 0x7c, 0xb4, 0x2e, 0xd6, 0x1e, 0xf8, 0xc1, 0xcc, 0xd2, 0xb9, + 0x22, 0xce, 0xc8, 0xfd, 0xd1, 0xe7, 0x22, 0xcd, 0x29, 0x0f, 0x70, 0x1f, 0x8a, 0xb9, 0xfd, 0x16, 0x48, 0x3f, 0xf4, + 0x16, 0xc8, 0x3e, 0x3a, 0xe7, 0xe4, 0x0d, 0x20, 0xd2, 0x21, 0x0c, 0x6e, 0x45, 0x82, 0x8e, 0x55, 0xc3, 0x5b, 0x0b, + 0xec, 0xb4, 0x97, 0xc6, 0xbd, 0x34, 0x3f, 0x4b, 0xfb, 0x7d, 0x83, 0x9a, 0x99, 0x22, 0x1c, 0x3c, 0xce, 0xc8, 0x45, + 0xd2, 0x82, 0x2d, 0xa5, 0xfd, 0x57, 0x03, 0x47, 0x10, 0xf2, 0xf7, 0x3f, 0x84, 0xf7, 0x04, 0x20, 0x36, 0x69, 0x03, + 0xae, 0x7a, 0x4c, 0x47, 0x63, 0x4b, 0xa2, 0x56, 0x9d, 0x0d, 0x90, 0x38, 0x55, 0x5a, 0x4f, 0xb9, 0x59, 0x53, 0x18, + 0xa4, 0xca, 0x42, 0xfd, 0xc6, 0x7a, 0x32, 0x59, 0xe5, 0x22, 0x23, 0x8e, 0xca, 0xf4, 0xa5, 0x66, 0x04, 0xd3, 0xa5, + 0x9f, 0x2f, 0x60, 0xc9, 0xc6, 0x1f, 0x71, 0xf2, 0x96, 0x80, 0x63, 0x3b, 0x6b, 0x57, 0xd5, 0x2e, 0xc7, 0xad, 0xdd, + 0x1c, 0xe0, 0x7b, 0xbd, 0xd1, 0x68, 0xa4, 0x9d, 0xe3, 0x04, 0x0c, 0x55, 0x4f, 0x2d, 0x85, 0x1e, 0xab, 0x15, 0xa0, + 0x6e, 0x47, 0x2e, 0xb3, 0x64, 0x30, 0x5f, 0x18, 0xc7, 0xaf, 0xcc, 0x47, 0x1f, 0x2f, 0x95, 0xb5, 0xeb, 0x88, 0xaf, + 0xff, 0x20, 0xab, 0xf5, 0x2d, 0xef, 0xaa, 0x26, 0xe0, 0x8b, 0x2a, 0xa0, 0xf4, 0x1b, 0xde, 0x93, 0xbd, 0x8b, 0xaf, + 0xdd, 0x60, 0x97, 0x7c, 0xcb, 0x5b, 0xd4, 0x79, 0xbe, 0x72, 0x70, 0xa3, 0x4a, 0xb7, 0xf7, 0x92, 0x05, 0xae, 0xbd, + 0xa3, 0xa6, 0xb1, 0x9e, 0xf9, 0xd1, 0xc3, 0x22, 0x64, 0x3b, 0x1f, 0x7b, 0x5f, 0x35, 0x4f, 0xcf, 0x1a, 0x7a, 0x93, + 0x1a, 0xfa, 0xd8, 0x8b, 0xb2, 0x7d, 0x6a, 0x1a, 0xd1, 0x6b, 0xd8, 0xd0, 0xc7, 0xde, 0x92, 0x93, 0x43, 0x22, 0xc0, + 0xa9, 0x31, 0x7f, 0x7c, 0x38, 0x9d, 0xe1, 0xef, 0x18, 0x50, 0x09, 0xc4, 0x7c, 0x7a, 0x4c, 0x3b, 0x0a, 0x30, 0xa3, + 0x4a, 0x6f, 0x9f, 0x1e, 0xd8, 0x8e, 0x97, 0xf5, 0xd0, 0xd2, 0xbb, 0x27, 0x47, 0xb7, 0xe3, 0x55, 0x35, 0xbe, 0x94, + 0x43, 0x9e, 0xe7, 0xb3, 0xd1, 0x68, 0x24, 0x0c, 0x24, 0x77, 0xa5, 0x37, 0xb0, 0x02, 0x69, 0x5b, 0x54, 0x1f, 0xca, + 0xa5, 0xb7, 0x53, 0x87, 0x76, 0xe5, 0x4f, 0xf2, 0xc3, 0xa1, 0x18, 0x99, 0x63, 0x1c, 0xc0, 0x4d, 0x0a, 0x25, 0x47, + 0xc9, 0x5a, 0x82, 0xe8, 0x94, 0xc6, 0x53, 0x59, 0xaf, 0xad, 0x88, 0xbc, 0x1a, 0x71, 0x1e, 0x82, 0x1f, 0x3d, 0x50, + 0x8b, 0xbf, 0xd0, 0x82, 0xd8, 0x63, 0x9f, 0x2a, 0xa5, 0x17, 0xbc, 0x2a, 0x20, 0x44, 0xec, 0xef, 0x06, 0xda, 0x41, + 0x09, 0x0e, 0x25, 0xdc, 0x07, 0x84, 0x85, 0x7e, 0xed, 0xe5, 0x33, 0x19, 0xa3, 0xdc, 0x1b, 0x54, 0x73, 0x06, 0x30, + 0x95, 0x3e, 0x03, 0xbf, 0x4b, 0x80, 0x3a, 0xc5, 0xa7, 0xe8, 0x54, 0x6f, 0x1e, 0x36, 0x5d, 0x9f, 0x96, 0x28, 0x8a, + 0xe8, 0xce, 0xcf, 0xc7, 0x80, 0xd8, 0xd9, 0xb5, 0x19, 0x69, 0xd7, 0x7e, 0x83, 0x06, 0x2b, 0x25, 0x89, 0x76, 0x4e, + 0x09, 0xbb, 0x9d, 0x8f, 0x6c, 0xe9, 0x47, 0x29, 0x10, 0x73, 0xc7, 0x89, 0x44, 0xf6, 0x60, 0x23, 0x27, 0x70, 0x8b, + 0xf6, 0x8e, 0x0e, 0x40, 0xe5, 0x46, 0x41, 0x7e, 0x35, 0x47, 0x72, 0xc7, 0x77, 0xbd, 0xef, 0x06, 0xf5, 0xe0, 0xbb, + 0xde, 0x59, 0x4a, 0x72, 0x47, 0x78, 0xa6, 0xa6, 0x84, 0x88, 0xcf, 0xbe, 0x1b, 0xe4, 0x03, 0x3c, 0x4b, 0xb4, 0x48, + 0x8b, 0x84, 0x6a, 0x75, 0x8d, 0x9b, 0xf0, 0x22, 0x91, 0xdc, 0x43, 0xbb, 0xce, 0x23, 0x62, 0x01, 0xc8, 0x58, 0x7c, + 0x36, 0x6f, 0x28, 0xd4, 0xdd, 0xc4, 0x6c, 0xd1, 0x5d, 0x16, 0xfb, 0xfd, 0x6d, 0x9e, 0xd6, 0x3d, 0x1d, 0x1f, 0x83, + 0x2f, 0x48, 0x35, 0x01, 0x1e, 0xed, 0xaf, 0xcd, 0xf1, 0xea, 0xd5, 0xe6, 0x48, 0x59, 0xa8, 0x12, 0xf5, 0x5b, 0xac, + 0x66, 0x3d, 0x84, 0xe1, 0xce, 0x32, 0x63, 0x6d, 0x2f, 0x78, 0x25, 0x67, 0x55, 0x6c, 0x97, 0xe3, 0x2b, 0x96, 0xda, + 0x4a, 0xa2, 0x72, 0xb4, 0x1e, 0x6b, 0x53, 0x8c, 0xfc, 0x4a, 0x21, 0x51, 0x16, 0x1d, 0x5b, 0x0b, 0x05, 0xc4, 0x0b, + 0xd0, 0x97, 0xec, 0x4c, 0x03, 0xac, 0x37, 0x7a, 0x15, 0x11, 0x5a, 0x3e, 0x52, 0xe1, 0x4d, 0x6e, 0xaa, 0xcc, 0xca, + 0x66, 0xd1, 0xee, 0xa7, 0x8a, 0x57, 0x08, 0x56, 0x6f, 0xd4, 0x1e, 0x05, 0xa8, 0x3d, 0xb4, 0x50, 0x06, 0x90, 0xd2, + 0x34, 0x03, 0x40, 0x06, 0x00, 0x99, 0x2a, 0xe2, 0x33, 0x01, 0x2a, 0x6d, 0x75, 0xa3, 0xc0, 0x89, 0xf4, 0x1a, 0x68, + 0x16, 0x58, 0xe9, 0x23, 0x05, 0x19, 0x2c, 0xb6, 0x08, 0xc0, 0xca, 0x91, 0x33, 0x4c, 0x63, 0xc8, 0x36, 0x9a, 0xb8, + 0x24, 0xcd, 0xef, 0xc3, 0x2c, 0x95, 0x78, 0x12, 0x3f, 0xc8, 0x1a, 0x23, 0x00, 0x90, 0xbe, 0x4f, 0x2f, 0x8a, 0x2c, + 0x26, 0x1c, 0x38, 0xeb, 0xa9, 0x83, 0xa2, 0x26, 0xe7, 0x5a, 0xd3, 0xea, 0x59, 0x6d, 0xf2, 0x90, 0x05, 0x3a, 0x7b, + 0x30, 0x26, 0xb5, 0x7c, 0xcf, 0x23, 0xfb, 0x2b, 0xc7, 0x33, 0xc2, 0x77, 0xdd, 0xc1, 0xa9, 0xff, 0x6e, 0x6a, 0x60, + 0x62, 0x4a, 0x00, 0x36, 0x06, 0x47, 0x13, 0xe2, 0x77, 0x3a, 0x26, 0x53, 0x9b, 0x14, 0x81, 0xc0, 0x43, 0xf0, 0x0a, + 0x9e, 0x1b, 0x2e, 0xb7, 0xdc, 0xd8, 0x59, 0xe4, 0x69, 0x02, 0x70, 0xe2, 0x05, 0xdf, 0x02, 0x1c, 0xa7, 0x5e, 0x15, + 0xb2, 0x67, 0xcf, 0xc5, 0x74, 0x36, 0x0f, 0x1e, 0x12, 0xda, 0xbf, 0x98, 0xf0, 0x9b, 0xee, 0x2a, 0xb9, 0x32, 0xb5, + 0xee, 0x4d, 0x74, 0x95, 0xcb, 0x9d, 0x3e, 0xad, 0x38, 0x86, 0x39, 0x83, 0x55, 0x40, 0xce, 0xd9, 0x90, 0xbf, 0x38, + 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0xfe, 0x22, 0x94, 0xd5, 0x02, 0xb8, 0x47, 0xce, 0x23, 0xf3, 0xcb, 0x57, 0xdb, + 0xa1, 0x9c, 0x53, 0x14, 0xc6, 0x72, 0x6a, 0x5a, 0x52, 0x9c, 0x0e, 0x3d, 0x05, 0x93, 0xa9, 0x2d, 0x7f, 0x6f, 0x13, + 0x97, 0xd9, 0x9b, 0x49, 0x38, 0x5f, 0x47, 0xb6, 0xad, 0x55, 0xf7, 0xd0, 0x0d, 0xc1, 0xa0, 0x8f, 0x11, 0xb4, 0x6c, + 0xae, 0xef, 0xd6, 0x83, 0x81, 0xc2, 0xf6, 0xad, 0xe9, 0xa6, 0x45, 0xa7, 0x38, 0xe0, 0xcc, 0x5a, 0xd7, 0xa8, 0x54, + 0x15, 0x87, 0x5e, 0xf2, 0x6e, 0x59, 0x95, 0x5d, 0x96, 0x5e, 0x08, 0x52, 0xa3, 0xae, 0x22, 0x44, 0x4a, 0xc5, 0x0e, + 0xef, 0xc9, 0xaf, 0x81, 0x89, 0x67, 0x56, 0x8e, 0xd2, 0x78, 0x0e, 0x30, 0x41, 0x0a, 0x7d, 0x53, 0x7e, 0x05, 0xb8, + 0xa1, 0x8b, 0x28, 0xcc, 0xde, 0xc6, 0x55, 0x50, 0x5b, 0x4d, 0xbf, 0x77, 0x70, 0x62, 0xcf, 0xeb, 0x7e, 0x3f, 0x25, + 0x1a, 0x3f, 0x0c, 0xbd, 0xc0, 0xbf, 0xc7, 0xd3, 0x7d, 0x13, 0xa4, 0xe6, 0x95, 0x07, 0x78, 0x45, 0x97, 0x5b, 0x9b, + 0x72, 0x45, 0xe3, 0x62, 0x5e, 0x23, 0x22, 0x7c, 0xea, 0x28, 0xb6, 0xdb, 0xfc, 0x38, 0xb5, 0x31, 0x18, 0x84, 0x70, + 0xdf, 0xca, 0xf8, 0x7d, 0xe2, 0xe5, 0xb3, 0x68, 0x0e, 0x8a, 0xd2, 0x4c, 0x93, 0x84, 0x14, 0xd2, 0x4b, 0x80, 0x3e, + 0x1a, 0x84, 0x5a, 0x5d, 0xf9, 0x47, 0xe2, 0xa5, 0x6a, 0x5a, 0x9b, 0xa7, 0x58, 0xa3, 0x40, 0xcc, 0xa2, 0x79, 0xc3, + 0x32, 0x3a, 0x24, 0xd5, 0xe5, 0xd2, 0x34, 0xe3, 0x0f, 0xab, 0x19, 0xaa, 0x15, 0x47, 0x4d, 0x50, 0xa3, 0x74, 0x03, + 0x17, 0xc0, 0xbf, 0xd3, 0x1d, 0x47, 0x35, 0x8a, 0x14, 0x0d, 0xf8, 0x04, 0x81, 0x61, 0xcd, 0xe6, 0x09, 0x6b, 0x4d, + 0x5d, 0x33, 0xfa, 0x7d, 0x19, 0x27, 0x64, 0x92, 0x90, 0x9c, 0x0f, 0x97, 0xeb, 0x47, 0x52, 0x5d, 0x00, 0xa9, 0x72, + 0xc5, 0x66, 0xbd, 0xde, 0x1c, 0x30, 0x7a, 0x61, 0xfd, 0xc2, 0xc6, 0x15, 0x9c, 0x5f, 0x12, 0xe6, 0xae, 0xfa, 0x11, + 0x66, 0x19, 0x54, 0x01, 0x69, 0x7e, 0x2c, 0x78, 0xf3, 0xdc, 0x05, 0xa2, 0x7e, 0x33, 0x52, 0x17, 0x94, 0x59, 0x3a, + 0xb7, 0x88, 0x40, 0xc0, 0x6b, 0x58, 0x3d, 0x81, 0x64, 0x5f, 0x3e, 0xf6, 0x69, 0x46, 0x81, 0xea, 0x08, 0x40, 0xd9, + 0xac, 0x1f, 0xc2, 0xfe, 0x01, 0xe1, 0x84, 0xfa, 0x9b, 0x37, 0x72, 0xd6, 0x90, 0x3c, 0x90, 0x6a, 0xc2, 0x63, 0x38, + 0x35, 0x16, 0xf8, 0xd2, 0xa2, 0x37, 0x15, 0xbc, 0x26, 0x38, 0xee, 0x05, 0x5a, 0xfb, 0x16, 0x70, 0x84, 0x08, 0x2e, + 0x43, 0x13, 0xa7, 0xbd, 0x5d, 0x2f, 0x40, 0x42, 0x73, 0x0b, 0xe7, 0xfa, 0xda, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, + 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, + 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, 0x2a, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, + 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, + 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xab, 0xc4, 0x33, 0xec, + 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, + 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x2a, 0xcc, 0x41, 0xde, + 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, + 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, + 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, + 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, + 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0x2f, 0xf2, 0xd1, + 0x96, 0xbe, 0x06, 0xdf, 0x3a, 0x1c, 0xf2, 0xd1, 0xce, 0xfc, 0xf4, 0xc9, 0x5a, 0x29, 0x83, 0x8d, 0x14, 0xa3, 0x10, + 0x12, 0xc5, 0x6d, 0x7b, 0x0c, 0x80, 0xff, 0xfd, 0xc3, 0x81, 0x7e, 0xef, 0xe4, 0x6f, 0xb5, 0x5b, 0x5a, 0xf5, 0xfc, + 0xd0, 0x22, 0xcc, 0x78, 0x5d, 0x1b, 0x76, 0xb6, 0xbd, 0x04, 0x94, 0xde, 0x37, 0x0d, 0x6a, 0x8a, 0xe8, 0x27, 0xac, + 0x26, 0x56, 0x71, 0x58, 0x90, 0x12, 0x87, 0x18, 0x8e, 0xd1, 0x0e, 0x3d, 0x4e, 0x17, 0x35, 0x4f, 0xee, 0x3b, 0x64, + 0xdc, 0xfa, 0x3e, 0x20, 0xb9, 0x14, 0xce, 0x3f, 0x78, 0xa1, 0xc1, 0x44, 0x2f, 0xf2, 0xaa, 0xc8, 0xc4, 0x48, 0xd0, + 0x28, 0xbf, 0x25, 0x71, 0xe6, 0x0c, 0x6b, 0x71, 0xa6, 0x10, 0xc2, 0x42, 0x42, 0xe5, 0x2e, 0x4a, 0x4a, 0x0f, 0xce, + 0x9e, 0xec, 0xcb, 0xe6, 0x77, 0xc2, 0x84, 0x18, 0x2d, 0x80, 0x06, 0x67, 0xd7, 0x2e, 0xef, 0x21, 0x2c, 0x73, 0xef, + 0xf7, 0xb7, 0x77, 0x79, 0x01, 0x71, 0x99, 0x67, 0x52, 0xb1, 0x5a, 0x9e, 0x01, 0x4d, 0x9e, 0x88, 0xcf, 0xc2, 0x4a, + 0x4e, 0x83, 0xaa, 0xa3, 0x58, 0xbd, 0x8d, 0xe7, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, 0xdd, 0x67, 0x6f, 0x94, + 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, 0xe7, 0x26, 0xc8, 0x3f, + 0xbe, 0x3e, 0xa1, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, 0x9b, 0x23, 0x35, 0x79, + 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, 0x67, 0x2b, 0x73, 0x2f, + 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xba, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, 0x62, 0x86, 0x29, 0xd6, + 0x5f, 0xd8, 0xf0, 0x9b, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x63, 0x16, 0xc2, 0xe1, 0xb0, 0x99, 0x14, + 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0x87, 0x43, 0x57, 0xcb, 0xd6, 0xc2, 0x83, 0x87, 0xaa, 0x85, 0x9b, 0x86, 0xe5, + 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, 0x1b, 0x6b, 0xe0, 0x1a, + 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, 0x09, 0xa3, 0x15, 0xc2, + 0xef, 0xbe, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, 0x4a, 0xb1, 0x34, 0x6f, + 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0x73, 0xdf, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, 0xcd, 0xe6, 0xc0, 0x7d, + 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x27, 0xcb, 0xe3, 0xf0, 0x2d, 0xfc, 0xcb, + 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xab, 0x14, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, 0x8d, 0xa8, 0x0d, 0x7f, + 0xc3, 0xbf, 0x85, 0x7d, 0x84, 0xfd, 0x86, 0x26, 0x08, 0x03, 0x58, 0x7f, 0x26, 0x10, 0x17, 0x16, 0x82, 0x04, 0x7f, + 0xab, 0x24, 0xff, 0x9c, 0xf0, 0xd9, 0xa2, 0x04, 0xb2, 0x3a, 0x8c, 0xe2, 0x13, 0x8a, 0x89, 0x42, 0x18, 0x6e, 0x09, + 0xbd, 0xa3, 0xff, 0x46, 0x94, 0x64, 0x93, 0xdc, 0x8a, 0xf5, 0x40, 0x26, 0x49, 0x30, 0xc1, 0xca, 0x0b, 0xe5, 0x4b, + 0xf7, 0x42, 0xa9, 0xb5, 0x16, 0xb4, 0x7e, 0xf9, 0x93, 0xc4, 0x33, 0xa0, 0x7b, 0x20, 0x63, 0xd0, 0x6d, 0x44, 0x35, + 0xc9, 0x31, 0x7d, 0x94, 0xce, 0x33, 0x50, 0x01, 0x9d, 0xad, 0xb3, 0xb0, 0x5e, 0x16, 0xe5, 0xaa, 0x15, 0x1e, 0x2a, + 0x4b, 0x1f, 0xa9, 0xc7, 0x98, 0x17, 0xe6, 0xc9, 0x89, 0x7c, 0xf0, 0x08, 0xd0, 0xf0, 0x28, 0x4f, 0xab, 0x8e, 0xd2, + 0xfa, 0x81, 0x65, 0xc0, 0x08, 0x9c, 0x28, 0x03, 0x1e, 0x61, 0x19, 0x98, 0xa7, 0x5d, 0x86, 0x1a, 0xc4, 0x1a, 0x55, + 0x57, 0x6a, 0x83, 0x39, 0x51, 0x94, 0x7c, 0x8a, 0xa5, 0x15, 0xc6, 0xd0, 0xd4, 0x95, 0x47, 0xd6, 0x4b, 0x4e, 0xd8, + 0x93, 0xdd, 0x40, 0xba, 0x85, 0x8d, 0x02, 0x17, 0x74, 0x2d, 0x4b, 0x94, 0x8b, 0x6e, 0x19, 0x51, 0x26, 0x42, 0xea, + 0x67, 0x0f, 0x67, 0x5a, 0xed, 0x37, 0x76, 0xd2, 0xbe, 0x3d, 0x52, 0xf4, 0x82, 0x81, 0xf8, 0xb4, 0x47, 0x4a, 0x3d, + 0x6b, 0xe4, 0x32, 0xb0, 0xa5, 0x4b, 0x55, 0xcf, 0x7f, 0x83, 0xf2, 0x1d, 0xcc, 0x8c, 0xb3, 0xd9, 0xef, 0x7a, 0x73, + 0x7b, 0xb2, 0xaf, 0x9b, 0xdf, 0x59, 0xaf, 0x07, 0x5b, 0x83, 0x4c, 0x7c, 0xa9, 0xa8, 0xa7, 0xac, 0x42, 0xac, 0xc8, + 0xec, 0x7f, 0x0b, 0xef, 0x77, 0x78, 0x6b, 0x84, 0x66, 0x65, 0x3c, 0xcc, 0x47, 0x4f, 0xf6, 0xa2, 0xf9, 0xbd, 0xb3, + 0x6c, 0x2b, 0x57, 0x25, 0xb3, 0xfd, 0x7e, 0x94, 0x34, 0x67, 0x8f, 0xd7, 0x48, 0xea, 0x00, 0x1f, 0xaf, 0xcf, 0xf0, + 0x91, 0x4a, 0x28, 0xb5, 0xa0, 0xaa, 0x41, 0xeb, 0x63, 0xbf, 0xb7, 0x9e, 0xd3, 0xc7, 0x8f, 0xe5, 0x74, 0x4b, 0x8a, + 0x30, 0x7e, 0x60, 0x30, 0x65, 0x27, 0x4e, 0x5d, 0xf2, 0x66, 0x48, 0xef, 0xba, 0x55, 0x52, 0x97, 0x3d, 0x4a, 0x04, + 0xa1, 0x0e, 0xd6, 0x2f, 0xf6, 0x43, 0x98, 0xd9, 0xa2, 0x3f, 0x6c, 0x56, 0x73, 0x42, 0x41, 0x04, 0x88, 0x56, 0x79, + 0x1f, 0x38, 0x26, 0x09, 0xb3, 0xe6, 0x86, 0x74, 0xeb, 0xcd, 0x95, 0xf6, 0x4a, 0x0a, 0xe8, 0xe7, 0x20, 0x73, 0xfb, + 0xe8, 0x96, 0xab, 0x96, 0x79, 0x2e, 0x6d, 0x39, 0x60, 0xd1, 0x42, 0x74, 0x66, 0xe7, 0xd2, 0xe1, 0xe0, 0x3f, 0xa8, + 0x2b, 0x51, 0x45, 0x04, 0x1d, 0x45, 0x0b, 0x46, 0xab, 0x55, 0xbb, 0x9c, 0x6c, 0x2a, 0x64, 0x4b, 0x22, 0x9c, 0x28, + 0xd9, 0x2b, 0xa1, 0x3e, 0xca, 0xd5, 0x9e, 0x69, 0x88, 0x3f, 0x13, 0xb0, 0x69, 0x83, 0xbf, 0x05, 0xee, 0x65, 0x70, + 0x66, 0xda, 0xa7, 0x61, 0x04, 0x44, 0xe6, 0x10, 0xec, 0xe7, 0x77, 0x3d, 0xa8, 0xe0, 0x41, 0x47, 0xfa, 0xeb, 0x7a, + 0x56, 0xe0, 0x99, 0x7b, 0xe2, 0xf9, 0x9b, 0x13, 0xe9, 0x45, 0x0e, 0x0f, 0x34, 0xf7, 0x61, 0xc6, 0x5f, 0x96, 0x65, + 0xb8, 0x1b, 0x2d, 0xcb, 0x62, 0xe5, 0x45, 0x7a, 0x1f, 0xcf, 0xa4, 0x18, 0x48, 0x74, 0x98, 0x19, 0x5d, 0xc5, 0x3a, + 0xce, 0x61, 0xdc, 0xdb, 0x93, 0xb0, 0x42, 0xfb, 0x67, 0x89, 0xbd, 0x2e, 0x00, 0xc0, 0x21, 0x6b, 0xd0, 0x0a, 0xef, + 0x74, 0x7b, 0xbb, 0xc7, 0x25, 0x25, 0x8a, 0x1b, 0x35, 0x3f, 0xab, 0xa1, 0x65, 0x82, 0x5a, 0x66, 0xdd, 0xc9, 0x64, + 0x8a, 0x24, 0xf0, 0x6d, 0xd8, 0x1b, 0x56, 0xe4, 0xf3, 0x46, 0x6e, 0x0f, 0xef, 0xc2, 0x95, 0x88, 0xb5, 0x05, 0x9d, + 0x74, 0x64, 0x1c, 0xee, 0x85, 0xe6, 0x46, 0xba, 0x7f, 0x52, 0x25, 0x61, 0x29, 0x62, 0xb8, 0x05, 0xb2, 0xbd, 0xda, + 0x56, 0x82, 0x12, 0x48, 0x60, 0x3f, 0x94, 0x62, 0x99, 0x6e, 0x05, 0x80, 0x39, 0xf0, 0x3f, 0x25, 0x0c, 0xa1, 0xbb, + 0xf3, 0x10, 0xaf, 0x1a, 0x79, 0xdf, 0x20, 0x04, 0xfb, 0x6b, 0x90, 0xd3, 0x80, 0x41, 0xa4, 0x18, 0xc9, 0x82, 0x81, + 0x04, 0x20, 0xe7, 0x6b, 0x30, 0xc9, 0x4d, 0x73, 0xcf, 0x0f, 0x72, 0xdd, 0xc1, 0xb4, 0x0f, 0xba, 0x17, 0xd7, 0x9a, + 0xe5, 0xe0, 0x15, 0x13, 0xf1, 0xbf, 0xd7, 0x5e, 0xc9, 0x72, 0x96, 0xf9, 0x8d, 0xb9, 0xe8, 0x64, 0x70, 0xd5, 0x10, + 0x7e, 0x31, 0xcb, 0xe6, 0x3c, 0x9a, 0x65, 0x3a, 0xd4, 0xbf, 0x68, 0x8e, 0x4a, 0x01, 0x0c, 0x75, 0xbc, 0x00, 0x6b, + 0xbc, 0x2b, 0xdd, 0xb4, 0xe2, 0x91, 0xc6, 0x18, 0x05, 0x15, 0x3a, 0x08, 0xfd, 0xbd, 0x06, 0x78, 0x0d, 0x26, 0xb9, + 0x11, 0x2a, 0x1f, 0x5c, 0xd0, 0x0d, 0xdd, 0x72, 0xe5, 0x12, 0xd4, 0xa4, 0x6a, 0xf9, 0xe5, 0x08, 0xf5, 0xae, 0x96, + 0x5c, 0xaa, 0xcd, 0xa7, 0x46, 0x59, 0x23, 0xc8, 0xe4, 0x28, 0xfd, 0x3e, 0xe5, 0xc2, 0xad, 0x8c, 0xc9, 0xfa, 0x70, + 0xf0, 0x0a, 0x6e, 0x6a, 0xfc, 0x3a, 0x27, 0x16, 0x51, 0x7b, 0x48, 0x84, 0xad, 0xdd, 0x0a, 0xdd, 0x7b, 0xdc, 0x28, + 0xcd, 0xa3, 0x6c, 0x13, 0x8b, 0xca, 0xeb, 0x25, 0x60, 0x2d, 0xee, 0x01, 0x19, 0x2a, 0x2d, 0xfd, 0x8a, 0x15, 0x00, + 0x19, 0x20, 0x85, 0x8d, 0x1f, 0x90, 0xf6, 0xea, 0x83, 0x97, 0xfa, 0xfd, 0xbe, 0x31, 0xe5, 0xbf, 0x7f, 0xc8, 0x81, + 0x99, 0x50, 0x94, 0xf5, 0x0e, 0x26, 0x10, 0x5c, 0x3b, 0x49, 0x7b, 0x56, 0xf3, 0x17, 0xeb, 0xda, 0x03, 0x52, 0x2b, + 0xdf, 0x62, 0xae, 0x7a, 0x6d, 0x5f, 0x6c, 0xf6, 0x69, 0x75, 0x63, 0x34, 0x0e, 0x82, 0xa5, 0xd5, 0x5b, 0xad, 0x72, + 0xc8, 0x1b, 0x5e, 0x81, 0x48, 0x65, 0x5d, 0x5d, 0x2b, 0xe7, 0xea, 0x5a, 0x70, 0x24, 0x90, 0x2d, 0x79, 0x0e, 0xff, + 0x85, 0xdc, 0x2b, 0x0f, 0x87, 0xc2, 0xef, 0xf7, 0xd3, 0x19, 0x69, 0x65, 0x81, 0x32, 0x6d, 0x5d, 0x7b, 0xa1, 0x7f, + 0x38, 0xfc, 0x00, 0x5e, 0x23, 0xfe, 0xe1, 0x50, 0xf6, 0xfb, 0x1f, 0xcd, 0x4d, 0xe6, 0x7c, 0xac, 0x94, 0xb2, 0x97, + 0xa8, 0x74, 0x7f, 0x9b, 0xf0, 0xde, 0xff, 0x1e, 0xfd, 0xef, 0xd1, 0x65, 0x4f, 0x05, 0x80, 0x25, 0x7c, 0x86, 0x37, + 0x74, 0xa6, 0x2e, 0xe7, 0x4c, 0xba, 0xbb, 0x2b, 0x3f, 0xf4, 0x9e, 0xc6, 0x87, 0xef, 0xcd, 0x4d, 0x1b, 0x7f, 0xad, + 0x8e, 0x34, 0x09, 0x1d, 0x17, 0xfd, 0xc3, 0xe1, 0x53, 0xa2, 0xf5, 0x69, 0xa9, 0xd2, 0xa7, 0x29, 0xf0, 0x24, 0xc3, + 0x86, 0xeb, 0x16, 0xa6, 0xa3, 0xf9, 0x71, 0xf3, 0x55, 0xf2, 0xe2, 0x2c, 0x85, 0x6b, 0x6f, 0x3e, 0x4b, 0xe7, 0x53, + 0xb0, 0xae, 0x0c, 0xf3, 0x59, 0x3d, 0x0f, 0x20, 0x75, 0x08, 0x69, 0xd6, 0x34, 0xfc, 0x5b, 0xe5, 0x0a, 0xde, 0xda, + 0xe3, 0xdd, 0x60, 0x44, 0xa9, 0x23, 0x7d, 0xd2, 0x86, 0xd0, 0x25, 0x95, 0xfc, 0x47, 0x91, 0xc7, 0x18, 0xb3, 0xf1, + 0x9a, 0xc8, 0x3e, 0x8b, 0xfc, 0x55, 0x01, 0x80, 0x45, 0x80, 0x80, 0x9c, 0xce, 0x1d, 0x49, 0xfc, 0xe7, 0xe4, 0xdb, + 0x3f, 0xa6, 0x4b, 0xfb, 0x50, 0x16, 0x77, 0xa5, 0xa8, 0xaa, 0xa3, 0xd2, 0x76, 0xb6, 0x5c, 0x0f, 0xf4, 0xa1, 0xfd, + 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, 0x58, 0x3f, 0xbf, + 0xdf, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, 0xc3, 0x54, 0xe2, + 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0x7f, 0x54, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, + 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0x17, 0xc2, 0x22, 0xf9, 0xf5, 0xc9, 0x91, + 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x91, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9e, 0xff, 0xb9, 0x99, 0xff, 0x03, 0x74, 0x86, + 0x2c, 0x5e, 0x70, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0x2f, 0x80, 0x83, 0xf9, 0x05, + 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0x37, 0x16, 0xcf, 0x95, 0x5c, 0x10, 0xfa, + 0xba, 0x0a, 0xb3, 0x71, 0x55, 0x6c, 0x2a, 0x51, 0x6c, 0xea, 0x1e, 0xa9, 0x65, 0xf3, 0x69, 0x6d, 0x2b, 0x64, 0x7f, + 0x12, 0x2d, 0xda, 0x2e, 0x43, 0x35, 0x19, 0x65, 0xe9, 0x7a, 0x0a, 0xa4, 0x7a, 0x01, 0x9c, 0x45, 0xe6, 0x95, 0x2f, + 0xce, 0x1e, 0xb0, 0x45, 0xe3, 0x29, 0x30, 0xa2, 0xd2, 0x1f, 0x79, 0x63, 0x74, 0x7a, 0xa2, 0xdf, 0xcf, 0xa7, 0x14, + 0xf2, 0xf5, 0x13, 0x60, 0x72, 0xd5, 0x72, 0x01, 0xfa, 0x32, 0xd4, 0x41, 0x25, 0x4a, 0xad, 0x18, 0x46, 0x2c, 0xfc, + 0x24, 0x90, 0xbd, 0x99, 0x82, 0x9a, 0x55, 0x94, 0x84, 0x4a, 0x54, 0x4a, 0xb6, 0x26, 0xa8, 0xa5, 0xf7, 0x45, 0x51, + 0xef, 0x2b, 0x70, 0x94, 0x8c, 0xb4, 0x59, 0x4e, 0x99, 0x71, 0x51, 0xe6, 0xa2, 0x1f, 0xec, 0xdf, 0x95, 0xe7, 0x37, + 0x32, 0x9f, 0xe5, 0xbe, 0xa3, 0x73, 0xda, 0x8e, 0x0b, 0x94, 0xb9, 0xe5, 0xb4, 0xd5, 0x92, 0xc7, 0xe4, 0x3d, 0x0b, + 0xb6, 0xfd, 0x97, 0x09, 0xf2, 0x2a, 0xc2, 0x7c, 0x42, 0x95, 0xcd, 0x3f, 0x20, 0xcc, 0x16, 0x07, 0xf6, 0xd8, 0x85, + 0x89, 0x48, 0x6f, 0xc1, 0x92, 0x18, 0x66, 0xa5, 0x08, 0xe3, 0x1d, 0x78, 0xff, 0x6c, 0x2a, 0x31, 0x3a, 0x43, 0x27, + 0xf7, 0xb3, 0x87, 0xb4, 0x4e, 0xce, 0xde, 0xbe, 0x3e, 0xfb, 0xae, 0x37, 0x28, 0x46, 0x69, 0x3c, 0xe8, 0x7d, 0x77, + 0xb6, 0xda, 0x00, 0x44, 0xa6, 0x38, 0x8b, 0xc9, 0x94, 0x26, 0xe2, 0x33, 0x32, 0x0c, 0x9e, 0xd5, 0x89, 0x38, 0xa3, + 0x89, 0xe9, 0xbe, 0x46, 0x69, 0xf2, 0xed, 0x28, 0xcc, 0xe1, 0xe5, 0x52, 0x6c, 0x2a, 0x11, 0x83, 0x9d, 0x52, 0xcd, + 0xb3, 0xbc, 0x7d, 0x16, 0xe7, 0xa3, 0x0e, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, 0x05, 0x84, 0x1e, + 0x00, 0x27, 0x5d, 0xf9, 0xf3, 0x70, 0x10, 0x09, 0x84, 0x5a, 0x30, 0x27, 0xd3, 0x88, 0x6e, 0x48, 0xaf, 0xb0, 0xcf, + 0xc0, 0x2c, 0xa4, 0x34, 0x0f, 0x6e, 0xae, 0x16, 0x2d, 0x77, 0xc5, 0xca, 0x51, 0x58, 0xad, 0x45, 0x54, 0x23, 0xd5, + 0x31, 0x38, 0xef, 0x40, 0x04, 0x80, 0x62, 0x04, 0xcf, 0x78, 0xd4, 0xef, 0x47, 0x2a, 0x28, 0x27, 0xa1, 0x5f, 0x14, + 0xfa, 0xa5, 0x31, 0x28, 0x63, 0xfe, 0x2e, 0xd4, 0xc4, 0x00, 0xf5, 0x96, 0x87, 0x8a, 0x23, 0x00, 0x97, 0x73, 0xc4, + 0x8c, 0xf3, 0x1e, 0x77, 0xd1, 0x38, 0x15, 0xef, 0x84, 0xba, 0x0e, 0x96, 0x0a, 0x75, 0xde, 0xd4, 0x47, 0x7a, 0x4e, + 0x9a, 0x04, 0x0d, 0xe2, 0x06, 0x1e, 0xaf, 0x86, 0x80, 0x6a, 0x25, 0xa4, 0xde, 0x42, 0xa7, 0x54, 0x75, 0x08, 0xac, + 0x01, 0x2e, 0x51, 0xd8, 0x56, 0x98, 0x1c, 0xd1, 0xa6, 0x2c, 0x45, 0x7e, 0xc4, 0x06, 0xed, 0x92, 0x91, 0xa9, 0x83, + 0xcb, 0xe5, 0x72, 0x22, 0xea, 0x5f, 0xf3, 0x2d, 0x80, 0xf3, 0x42, 0x7e, 0x6b, 0x37, 0x5b, 0x26, 0xd9, 0xae, 0x2b, + 0xc3, 0x59, 0x52, 0x8a, 0x6a, 0x5d, 0xe4, 0x55, 0x7a, 0x2f, 0x7e, 0xd6, 0x0f, 0x5d, 0x02, 0x29, 0xf4, 0x23, 0xbd, + 0x6e, 0x37, 0x47, 0xaa, 0x71, 0x74, 0x39, 0xb6, 0xa7, 0xd2, 0x4e, 0xf6, 0xaa, 0xc5, 0x9b, 0x2d, 0x73, 0x25, 0x69, + 0x1c, 0x8b, 0xfc, 0x6d, 0x1e, 0xa7, 0x91, 0x95, 0x1c, 0xfe, 0x1f, 0xde, 0xbe, 0x85, 0xbb, 0x6d, 0x1b, 0x5b, 0xf7, + 0xaf, 0x58, 0xbc, 0xa9, 0x4a, 0x44, 0x90, 0x2c, 0x39, 0x49, 0x67, 0x4a, 0x19, 0xd6, 0x71, 0xf3, 0x68, 0xd3, 0x36, + 0x71, 0x1a, 0xa7, 0x9d, 0xce, 0xe8, 0xea, 0xb8, 0x34, 0x09, 0x5b, 0x6c, 0x68, 0x40, 0x25, 0x29, 0x3f, 0x22, 0xf1, + 0xbf, 0xdf, 0xb5, 0x37, 0x9e, 0xa4, 0x68, 0x27, 0x33, 0xf7, 0xdc, 0xbb, 0xb2, 0x56, 0x2c, 0x82, 0x20, 0xde, 0xd8, + 0xd8, 0xd8, 0x8f, 0x6f, 0xeb, 0x00, 0xd5, 0x2e, 0xf2, 0x95, 0x8b, 0x8d, 0xfc, 0x22, 0x2b, 0x31, 0x60, 0x70, 0xa3, + 0x51, 0xad, 0x50, 0x53, 0x26, 0xf0, 0x85, 0x7c, 0x8f, 0x11, 0xb7, 0x59, 0x99, 0x00, 0xc3, 0x8f, 0x89, 0xfa, 0x92, + 0x9e, 0x42, 0x94, 0x07, 0x15, 0x8f, 0xfb, 0x05, 0x47, 0xc4, 0x6b, 0xab, 0x32, 0x07, 0x26, 0x5b, 0xab, 0x20, 0x11, + 0xec, 0x2e, 0x9b, 0xeb, 0x45, 0xb4, 0x50, 0x77, 0xa1, 0x5e, 0xbc, 0xdd, 0xf6, 0x12, 0x45, 0x07, 0x9c, 0xfc, 0x34, + 0x78, 0x15, 0x67, 0x39, 0x4f, 0xf7, 0x2a, 0xb9, 0xa7, 0x36, 0xd4, 0x9e, 0x72, 0xe6, 0x80, 0x9d, 0xf7, 0x75, 0xb5, + 0xa7, 0xd7, 0xf4, 0x9e, 0x6e, 0xe7, 0x1e, 0x5c, 0x30, 0x70, 0xe7, 0x5e, 0x66, 0xd7, 0x5c, 0xec, 0x81, 0x32, 0xd0, + 0x1a, 0x0f, 0xd4, 0xa2, 0x1a, 0xa9, 0x89, 0xd1, 0x81, 0xab, 0x13, 0x7d, 0x30, 0x07, 0xf4, 0x7b, 0x88, 0x15, 0xde, + 0x7a, 0xbb, 0xd2, 0x07, 0x6d, 0x40, 0x7f, 0x5e, 0x9a, 0x3e, 0xe8, 0x68, 0xf1, 0x2a, 0x24, 0x70, 0x63, 0x48, 0x35, + 0x52, 0xab, 0x91, 0x55, 0xa0, 0x78, 0xc3, 0x5b, 0xbc, 0x3b, 0xd7, 0x92, 0x8d, 0xf7, 0x12, 0x81, 0xbd, 0x32, 0x51, + 0xc5, 0x99, 0x38, 0xf6, 0x52, 0x79, 0xad, 0x9d, 0x64, 0x84, 0xf1, 0x2d, 0x2b, 0xa9, 0xbf, 0x43, 0xcc, 0x2d, 0xd2, + 0x1c, 0x06, 0x2f, 0xc3, 0x8a, 0xcc, 0x78, 0xbf, 0x2f, 0x67, 0x32, 0x2a, 0x67, 0x62, 0xbf, 0x8c, 0x14, 0x42, 0xdb, + 0x7d, 0x22, 0xa0, 0x07, 0x25, 0x40, 0xbe, 0x00, 0xa8, 0x7a, 0x48, 0xf8, 0xf3, 0x90, 0xd4, 0xa7, 0x53, 0xe8, 0x53, + 0x68, 0xeb, 0x15, 0xaf, 0xa0, 0xaa, 0x6e, 0x8c, 0x6c, 0xa3, 0x82, 0x16, 0x8f, 0xe5, 0x59, 0x6d, 0x18, 0x9b, 0x53, + 0xeb, 0x5d, 0x6f, 0x36, 0x98, 0xb2, 0xb9, 0x50, 0xab, 0x30, 0x24, 0xd1, 0x4d, 0xe9, 0x85, 0x0f, 0xb1, 0x58, 0x59, + 0xad, 0xcd, 0x6f, 0x62, 0x7f, 0x64, 0x22, 0xc5, 0xfd, 0x6c, 0x89, 0x73, 0x17, 0x8f, 0xe7, 0x55, 0x5f, 0x6b, 0x69, + 0x91, 0x69, 0xf3, 0x9d, 0xbe, 0x0c, 0x69, 0x2a, 0x6a, 0x48, 0xa3, 0xce, 0x0c, 0xba, 0x6f, 0x97, 0x57, 0x54, 0x23, + 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, 0x1e, 0x88, 0xa2, 0x1a, 0x15, 0x6b, 0x21, 0x10, 0x6d, 0x18, 0x72, 0xcc, + 0x2c, 0x21, 0xc9, 0x3e, 0xf1, 0xef, 0x54, 0x70, 0x85, 0x22, 0xbe, 0x31, 0x70, 0xde, 0x95, 0xf5, 0xec, 0xae, 0x23, + 0x3f, 0x27, 0x16, 0x56, 0xfb, 0x0f, 0xcd, 0xa3, 0xd6, 0x38, 0x0b, 0x68, 0x6b, 0x5a, 0xdd, 0x70, 0xb8, 0x47, 0x75, + 0x2c, 0x4a, 0x03, 0x48, 0xec, 0x91, 0xe5, 0xa2, 0x75, 0xcc, 0xa0, 0x01, 0xfd, 0x6d, 0x76, 0xb5, 0xbe, 0x42, 0xd4, + 0xb6, 0x12, 0x59, 0x27, 0xa9, 0xfc, 0x4b, 0xda, 0xa3, 0xae, 0xed, 0xa9, 0xfc, 0x6f, 0xdb, 0x54, 0x39, 0xb4, 0x40, + 0xf2, 0xd8, 0xcd, 0x59, 0xa0, 0x3a, 0x12, 0x44, 0x81, 0xda, 0x7a, 0xc1, 0xd4, 0x3b, 0x65, 0x8a, 0x0e, 0xe4, 0xe7, + 0xc2, 0x9c, 0x61, 0x5f, 0x70, 0xc4, 0x98, 0xa5, 0x12, 0x83, 0xa9, 0x8f, 0x31, 0xaa, 0x69, 0xad, 0x00, 0x5d, 0x3f, + 0xdd, 0xc0, 0x9f, 0xa8, 0xa8, 0xd1, 0x50, 0x6b, 0x24, 0x85, 0xa2, 0x89, 0x0a, 0x3a, 0x96, 0x16, 0x3a, 0x98, 0x42, + 0x27, 0x91, 0xb0, 0x04, 0x34, 0x4c, 0x88, 0x4e, 0x2a, 0xf0, 0xd6, 0x00, 0xce, 0x7c, 0x5c, 0x94, 0xeb, 0x42, 0x1b, + 0xcc, 0xfd, 0x10, 0x5f, 0xf3, 0xd7, 0x2f, 0x9c, 0x51, 0x7d, 0xcb, 0x5a, 0xdf, 0xd3, 0x82, 0xfc, 0x10, 0x72, 0x8a, + 0x0e, 0x4c, 0xec, 0x68, 0x83, 0xc6, 0x18, 0x65, 0xad, 0x43, 0x5d, 0x9c, 0xe8, 0xf8, 0x2b, 0xda, 0x04, 0xef, 0x01, + 0x4f, 0x11, 0x6d, 0x78, 0x28, 0x8c, 0x55, 0x35, 0x3e, 0x95, 0xac, 0xa5, 0x07, 0x2b, 0x78, 0xba, 0x4e, 0x78, 0x08, + 0x7a, 0x24, 0xc2, 0x8e, 0xc2, 0x62, 0x1e, 0x2f, 0xe0, 0x38, 0x29, 0x08, 0xa8, 0x1d, 0xf4, 0x15, 0x7c, 0xbe, 0x40, + 0xf7, 0x57, 0x89, 0x1e, 0x60, 0x68, 0x41, 0xdc, 0x0c, 0x7d, 0x3a, 0xba, 0x8a, 0x57, 0x0d, 0x15, 0x09, 0x9f, 0x17, + 0x60, 0x3b, 0xa4, 0xd4, 0x53, 0xa0, 0x85, 0x4a, 0x94, 0x7e, 0x18, 0xf8, 0x0e, 0x0d, 0x7c, 0xad, 0x75, 0x80, 0x86, + 0x7e, 0xc6, 0x34, 0xb5, 0xce, 0x50, 0xf9, 0xcc, 0xbb, 0x67, 0x46, 0xcb, 0x99, 0x05, 0x63, 0xd0, 0xb7, 0xd1, 0x14, + 0xc5, 0x39, 0xf9, 0x2c, 0x28, 0xe2, 0x34, 0x8b, 0x73, 0xf0, 0xdb, 0x8c, 0x0b, 0xcc, 0x98, 0xc4, 0x15, 0xbf, 0x94, + 0x05, 0x68, 0xbb, 0x73, 0x95, 0x5a, 0xd7, 0x20, 0x20, 0xfb, 0x01, 0xac, 0x5e, 0x1a, 0x3a, 0x2a, 0xe7, 0xdd, 0xa5, + 0x4d, 0x21, 0x62, 0x11, 0x82, 0x4d, 0x33, 0x5d, 0xb2, 0xe3, 0x50, 0x69, 0x73, 0x20, 0xbe, 0x11, 0x1a, 0xf7, 0x4f, + 0xc3, 0xd8, 0x6a, 0x8a, 0xad, 0xdd, 0xdb, 0x76, 0xfb, 0x7b, 0xe9, 0xa5, 0xd3, 0x9c, 0xf4, 0x18, 0xfb, 0xbd, 0x0c, + 0x8b, 0x91, 0xed, 0x08, 0x81, 0x25, 0xe7, 0x7d, 0xea, 0xbf, 0xa2, 0xe5, 0x3c, 0x01, 0xd3, 0x11, 0x1d, 0x21, 0x17, + 0x28, 0x3b, 0x46, 0x71, 0x07, 0x06, 0x57, 0xf4, 0xfb, 0x60, 0x95, 0x61, 0x2e, 0x24, 0x4b, 0x92, 0x32, 0x78, 0x9e, + 0x7a, 0x18, 0xf0, 0x6b, 0xa6, 0xcc, 0x5d, 0x94, 0xf5, 0xe9, 0x92, 0x4c, 0x53, 0x64, 0x20, 0xd6, 0xe1, 0x26, 0x4b, + 0xa3, 0x44, 0x89, 0xc8, 0x96, 0xe8, 0x1f, 0x69, 0x28, 0x96, 0x0e, 0xd7, 0x8b, 0x54, 0x89, 0x50, 0x31, 0x4f, 0xf1, + 0xa4, 0x4e, 0xeb, 0x74, 0x84, 0xf1, 0x26, 0x41, 0x29, 0x57, 0xc3, 0x40, 0x95, 0x54, 0x2f, 0x85, 0x4d, 0xb1, 0xdd, + 0xea, 0x8b, 0x95, 0x98, 0xc7, 0x0b, 0x7c, 0x29, 0x70, 0x14, 0x7f, 0xe2, 0x5e, 0xac, 0x29, 0xb5, 0x3d, 0xa8, 0x1d, + 0x51, 0x42, 0x7f, 0xe2, 0x70, 0x91, 0xf8, 0x4e, 0xea, 0xb8, 0x7f, 0x68, 0x11, 0x72, 0xa6, 0x0e, 0x52, 0xc3, 0x0d, + 0xed, 0x08, 0xff, 0x0d, 0xd7, 0x67, 0x9c, 0xd1, 0x9b, 0x6a, 0x46, 0x8d, 0xdf, 0xeb, 0xe1, 0x19, 0xa3, 0x3e, 0x1b, + 0x38, 0xac, 0x10, 0x85, 0x36, 0xec, 0xa8, 0x54, 0xa2, 0x85, 0xa1, 0x54, 0x7f, 0x09, 0x15, 0x47, 0xdc, 0x99, 0x51, + 0x96, 0x8c, 0x4f, 0xcb, 0x43, 0x31, 0x1d, 0x0c, 0x4a, 0x52, 0x19, 0x0b, 0x3d, 0xb8, 0x1e, 0x78, 0xfe, 0x3d, 0x70, + 0x0b, 0xf1, 0xe0, 0x90, 0xc5, 0x90, 0x1b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8d, 0x4a, 0x15, 0xbc, 0x9a, 0xa8, 0x16, + 0xfc, 0x54, 0x86, 0x01, 0xfa, 0x24, 0x05, 0x60, 0x32, 0x98, 0xf2, 0x5b, 0x90, 0x28, 0x9d, 0xa9, 0x1b, 0xd2, 0xaf, + 0xa2, 0xe0, 0x17, 0xbc, 0xe0, 0x22, 0x71, 0x05, 0x58, 0xde, 0xc1, 0xf6, 0x3a, 0xaa, 0xa8, 0x02, 0xe2, 0x35, 0x3d, + 0x8e, 0xb8, 0xf1, 0xfe, 0x33, 0x3d, 0xb6, 0x40, 0xad, 0xd6, 0xb1, 0xc1, 0x67, 0x8e, 0xc1, 0x05, 0x5d, 0x4b, 0x6c, + 0x0d, 0xd5, 0xb0, 0x22, 0x30, 0x70, 0x01, 0x07, 0x61, 0x89, 0xe2, 0xd8, 0x4a, 0x5e, 0x91, 0x86, 0x94, 0xf6, 0x81, + 0xe1, 0x68, 0x93, 0x1c, 0xdf, 0x66, 0xd9, 0x4d, 0xe0, 0x7c, 0xd1, 0x39, 0x69, 0x26, 0x96, 0x0d, 0xde, 0xe7, 0xcd, + 0xf9, 0x75, 0xff, 0x90, 0x50, 0x15, 0xec, 0x86, 0xb7, 0x83, 0xdd, 0x38, 0xe1, 0xd7, 0x5c, 0x2c, 0x74, 0x7c, 0x16, + 0x73, 0xc9, 0xf2, 0x5b, 0xeb, 0xdd, 0x92, 0xa4, 0x56, 0x40, 0xfb, 0x2c, 0x0b, 0x6a, 0x22, 0x00, 0xdd, 0x0f, 0x7f, + 0x81, 0xd0, 0x19, 0xfe, 0xf6, 0x18, 0x5c, 0x91, 0xc2, 0x7b, 0x87, 0x40, 0x58, 0xd3, 0xcd, 0x9d, 0xda, 0x80, 0x2f, + 0xc6, 0xfd, 0x19, 0x53, 0x4f, 0xbf, 0xcd, 0xe4, 0xae, 0xae, 0xdb, 0x23, 0xcb, 0xf0, 0x11, 0xae, 0x14, 0x00, 0xcb, + 0x84, 0xbf, 0x18, 0x5b, 0x52, 0x7d, 0x02, 0x70, 0x6a, 0x3a, 0xa2, 0x4f, 0x10, 0x18, 0x38, 0x25, 0x5a, 0x8c, 0xae, + 0x95, 0x23, 0x9a, 0x41, 0x5a, 0xd3, 0xad, 0x30, 0xde, 0x7a, 0xd0, 0x42, 0xcf, 0x34, 0x9c, 0xf8, 0x0f, 0x9a, 0x79, + 0x55, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0xd1, 0x1c, 0x21, 0x3e, 0x61, 0x49, 0x34, 0x61, 0xf1, 0x4c, 0xf1, + 0x63, 0x42, 0x37, 0x4d, 0x6d, 0xd3, 0x07, 0xa4, 0xbf, 0xb8, 0x66, 0xfd, 0x94, 0x65, 0xed, 0xdb, 0x43, 0xc5, 0x8b, + 0x69, 0x33, 0xf8, 0x61, 0xa2, 0x8a, 0xf1, 0xbf, 0xa8, 0x7c, 0xa9, 0x15, 0xc0, 0x30, 0x77, 0xd5, 0xd3, 0xef, 0x37, + 0xb3, 0xe5, 0x40, 0xa8, 0xfc, 0xce, 0x20, 0xe9, 0xd3, 0xf1, 0xfc, 0xc0, 0x26, 0x51, 0x5b, 0xe8, 0xf9, 0xe3, 0x52, + 0x37, 0xa1, 0xf2, 0xda, 0xd4, 0x88, 0x56, 0xc8, 0x50, 0xd9, 0x3a, 0x60, 0x7d, 0xff, 0x10, 0xee, 0x2e, 0x6a, 0x1a, + 0x6a, 0xdd, 0x73, 0xd7, 0xa2, 0xe0, 0xc4, 0x1f, 0x60, 0x2c, 0x2e, 0x24, 0xb5, 0x0e, 0xc2, 0xa4, 0x1f, 0x2d, 0x4e, + 0x72, 0xa3, 0xae, 0x4e, 0xce, 0x14, 0xf3, 0x04, 0x2e, 0xaa, 0x65, 0xdb, 0x5f, 0x51, 0xa9, 0x4b, 0xb9, 0xbd, 0xa2, + 0x34, 0x3d, 0xa4, 0xed, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x0b, 0x05, 0x17, 0xd6, 0xc1, 0xba, 0xe3, 0x4e, 0xd9, + 0x13, 0x9e, 0x28, 0xd3, 0xda, 0xe0, 0xae, 0x1b, 0x8c, 0x89, 0xb1, 0xdf, 0x5d, 0xf2, 0xe4, 0x23, 0xb2, 0xe0, 0xdf, + 0x65, 0x02, 0x3c, 0x93, 0xdd, 0x2b, 0x95, 0xff, 0x07, 0xff, 0x6a, 0x6b, 0xdf, 0x59, 0xf3, 0x4f, 0xcf, 0x7a, 0xb8, + 0x73, 0x98, 0xfc, 0x00, 0x9d, 0x01, 0xdd, 0x5c, 0xc9, 0x94, 0x03, 0x32, 0x80, 0xb5, 0x48, 0x46, 0x03, 0x3e, 0xb4, + 0xb2, 0x6c, 0xfb, 0x4e, 0xab, 0x0b, 0xc2, 0xbd, 0x04, 0x6e, 0x7a, 0x7f, 0x6d, 0x66, 0xe6, 0x74, 0xad, 0x44, 0xd3, + 0xa5, 0xb1, 0xb5, 0x2c, 0x55, 0xc0, 0xee, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x70, 0x39, 0xcd, 0x2d, 0x75, 0xdb, 0xb8, + 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0xb5, 0x22, 0xf4, 0x54, 0x89, 0xd0, + 0xa7, 0x69, 0xb3, 0x0f, 0x76, 0x55, 0xad, 0x1b, 0x71, 0x8e, 0x06, 0xa9, 0x66, 0xe4, 0x4f, 0xae, 0x79, 0x71, 0x91, + 0xcb, 0x1b, 0xc0, 0x40, 0x26, 0xb5, 0x51, 0x58, 0x5e, 0x81, 0x3b, 0x3f, 0x3a, 0x8e, 0x33, 0x31, 0xca, 0x31, 0x58, + 0x2b, 0xc2, 0x23, 0xeb, 0xc4, 0x19, 0x80, 0x20, 0xfb, 0x93, 0xa6, 0xe3, 0xb9, 0x16, 0x18, 0xd3, 0x17, 0xb8, 0xab, + 0x9c, 0x1d, 0x6d, 0x72, 0xbb, 0xe8, 0x9b, 0x33, 0xac, 0x3b, 0x52, 0x5a, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, 0x06, + 0x6d, 0x11, 0x4a, 0x3e, 0xe4, 0x4e, 0xda, 0x4f, 0x01, 0x0d, 0xce, 0xb2, 0xf4, 0xd6, 0x5a, 0xe5, 0x6f, 0xb4, 0x10, + 0x27, 0x8a, 0xa9, 0x13, 0xdf, 0x44, 0x89, 0x3e, 0x3f, 0x13, 0xe3, 0x06, 0x02, 0xa9, 0x3f, 0x60, 0x50, 0x8d, 0x22, + 0x4c, 0xe0, 0x3a, 0x10, 0xc5, 0xf6, 0x44, 0x6d, 0x2c, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x41, 0x19, 0xc6, 0xea, 0xe2, + 0x40, 0x1b, 0x2c, 0x7d, 0xdd, 0x5a, 0xe7, 0x86, 0x50, 0x18, 0x27, 0x30, 0xc5, 0x20, 0xa9, 0xb3, 0xce, 0x32, 0x41, + 0x95, 0x1d, 0x93, 0xce, 0xfb, 0x00, 0xdd, 0x5d, 0x8b, 0xa6, 0xf8, 0xba, 0x73, 0x07, 0xdd, 0xc7, 0xf5, 0x6b, 0x2d, + 0x72, 0x83, 0x3f, 0x6f, 0x89, 0xb0, 0x08, 0x9c, 0xb5, 0x26, 0x5f, 0x35, 0xc2, 0x81, 0x29, 0xc9, 0x34, 0xec, 0x25, + 0xca, 0xa6, 0x7b, 0xbb, 0xed, 0xf5, 0xee, 0x15, 0x71, 0xf5, 0x18, 0xab, 0xbc, 0x9b, 0xb9, 0xbd, 0x53, 0xad, 0xc5, + 0xee, 0x4d, 0xdb, 0x4f, 0xb1, 0xa3, 0xd6, 0xda, 0xed, 0x86, 0x13, 0x6a, 0xc8, 0xb7, 0xa2, 0x4a, 0xab, 0xd3, 0x8d, + 0x41, 0x3b, 0xc4, 0xb3, 0x16, 0x19, 0xdc, 0x28, 0x5f, 0x38, 0xa1, 0x93, 0x8a, 0xb3, 0xea, 0xd4, 0x05, 0x9b, 0x2b, + 0x5e, 0x2d, 0x65, 0x1a, 0x09, 0x8a, 0x36, 0xe7, 0x51, 0x49, 0x13, 0xb9, 0x16, 0x55, 0x24, 0x6b, 0xd4, 0x8b, 0x5a, + 0x8d, 0x01, 0x02, 0x32, 0x9d, 0x35, 0x3d, 0xa8, 0x82, 0xd9, 0x50, 0x46, 0x72, 0xfa, 0x1e, 0x2c, 0xed, 0x91, 0x63, + 0xad, 0xef, 0xab, 0xb3, 0xc5, 0xb7, 0x7a, 0x42, 0x30, 0x85, 0xd9, 0x03, 0x61, 0xe0, 0x9a, 0xc6, 0x90, 0xd3, 0x2e, + 0x71, 0x59, 0xd3, 0x2d, 0xe1, 0x1e, 0x6e, 0x57, 0xb2, 0x23, 0x37, 0x4f, 0x9a, 0x9b, 0x2b, 0xd8, 0x51, 0x31, 0x1f, + 0x83, 0xf6, 0x4b, 0xaa, 0x6b, 0x97, 0xe6, 0xd6, 0xe3, 0x41, 0x40, 0x83, 0x41, 0x61, 0xf8, 0xd7, 0x89, 0xf1, 0xf0, + 0xa4, 0x01, 0x41, 0x52, 0x2e, 0xc2, 0xb1, 0x6f, 0x44, 0x3f, 0x99, 0xca, 0x43, 0x8e, 0x16, 0xef, 0xd0, 0xea, 0x04, + 0xa2, 0x78, 0x89, 0x50, 0x12, 0xa3, 0x2a, 0x34, 0x22, 0x28, 0x4f, 0xcb, 0x5f, 0xaa, 0xea, 0x10, 0x50, 0x48, 0xfb, + 0x8a, 0x42, 0xd9, 0x26, 0x31, 0x34, 0xc3, 0x2f, 0xe7, 0x93, 0x85, 0x9e, 0x81, 0x81, 0x9c, 0x1f, 0x2c, 0xf4, 0x2c, + 0x0c, 0xe4, 0xfc, 0xc9, 0xa2, 0x76, 0xeb, 0x40, 0x13, 0x10, 0xcf, 0x85, 0xa3, 0x93, 0xd2, 0xaa, 0x6c, 0x01, 0xdd, + 0x3c, 0x44, 0xd0, 0x7f, 0xb2, 0x87, 0xa0, 0x93, 0x0b, 0xed, 0xc8, 0x0d, 0x68, 0x3b, 0x0e, 0x81, 0xbd, 0x62, 0x52, + 0x61, 0x02, 0x10, 0x1d, 0xb2, 0x31, 0x18, 0x62, 0xab, 0x0f, 0x0e, 0xd9, 0x78, 0xea, 0x93, 0x20, 0x60, 0x74, 0x7f, + 0x30, 0x90, 0xe0, 0xb7, 0x78, 0x95, 0x3e, 0xda, 0x08, 0x74, 0xd3, 0x77, 0x77, 0x43, 0xef, 0xe2, 0x0a, 0x4e, 0xd5, + 0xee, 0x9e, 0x84, 0x6e, 0x32, 0xed, 0x00, 0xbd, 0x86, 0xb8, 0x21, 0xbf, 0x32, 0x1a, 0x8d, 0x6c, 0x4a, 0x48, 0x88, + 0xe1, 0x1c, 0x9a, 0x39, 0x2d, 0x97, 0xaf, 0x6e, 0x3d, 0x1b, 0x90, 0x61, 0xa6, 0xb7, 0x4c, 0xd6, 0x0f, 0x50, 0x56, + 0x3d, 0x86, 0x76, 0xe8, 0x3d, 0x72, 0xfc, 0xf0, 0xe0, 0x9b, 0x8c, 0x9f, 0x39, 0x5c, 0x7b, 0x38, 0x17, 0xbe, 0xcb, + 0x9a, 0x91, 0x39, 0x74, 0x9e, 0x7d, 0x1c, 0xef, 0x61, 0x9c, 0x7c, 0x9e, 0x85, 0xf2, 0xc6, 0x6b, 0xfa, 0x1f, 0x95, + 0xde, 0xec, 0x70, 0xc8, 0xe9, 0x0a, 0x56, 0xdc, 0xac, 0x0a, 0x0d, 0x3f, 0x8b, 0xbc, 0x71, 0xc4, 0x6b, 0x12, 0x55, + 0xdd, 0xe7, 0xbd, 0x0d, 0x53, 0xda, 0x31, 0x0e, 0x00, 0x4e, 0xd4, 0xaa, 0x61, 0x57, 0x1a, 0xd7, 0xea, 0x20, 0x86, + 0xa1, 0x84, 0xad, 0x12, 0x47, 0x42, 0xf9, 0x1b, 0x80, 0xb0, 0x18, 0x8a, 0xe3, 0xad, 0x61, 0x7d, 0x80, 0xfd, 0xd0, + 0x05, 0x9a, 0xe6, 0x94, 0x6a, 0x06, 0x00, 0x49, 0xc0, 0x1f, 0x3d, 0xdd, 0x34, 0x54, 0xb6, 0x79, 0x1e, 0x5a, 0x56, + 0x57, 0xf0, 0x40, 0x4f, 0x5d, 0xc9, 0xc0, 0xb8, 0xaa, 0x63, 0x6f, 0x73, 0x7f, 0x7b, 0xb4, 0x8a, 0x7c, 0x67, 0x93, + 0xda, 0x66, 0x55, 0x68, 0xec, 0xe3, 0x09, 0x3d, 0x9d, 0x00, 0xad, 0xd7, 0x96, 0x8a, 0xf6, 0xfb, 0x28, 0x46, 0x8d, + 0x0b, 0x05, 0x56, 0x61, 0x22, 0xc1, 0x21, 0xc2, 0x08, 0xa1, 0xdf, 0x97, 0xe1, 0xc6, 0x17, 0x64, 0x10, 0x0d, 0xd7, + 0xa2, 0xe3, 0x0f, 0x39, 0x5e, 0xb4, 0x2d, 0x55, 0x35, 0x27, 0x4d, 0x5b, 0x02, 0x6f, 0xc2, 0x01, 0xb6, 0xf3, 0x4f, + 0x1b, 0x22, 0x57, 0xe1, 0xa2, 0x84, 0xef, 0x88, 0x6b, 0x41, 0x74, 0x53, 0x9b, 0x7a, 0x1b, 0x76, 0x88, 0x8e, 0xa6, + 0x78, 0x74, 0xc8, 0x3d, 0x77, 0xcf, 0x6d, 0x11, 0xdf, 0x7c, 0x86, 0xdc, 0x35, 0x9d, 0xbd, 0x14, 0x61, 0x50, 0xb7, + 0x6c, 0xa0, 0x58, 0x87, 0x4e, 0x50, 0x80, 0x51, 0x5b, 0x3e, 0x01, 0x1d, 0x1b, 0x0c, 0x2a, 0x82, 0x4f, 0x0a, 0xdb, + 0xa6, 0x41, 0xfe, 0x88, 0x77, 0x43, 0x87, 0xd7, 0x96, 0x3c, 0x10, 0xaf, 0xb0, 0xcf, 0x94, 0x70, 0xff, 0x82, 0x82, + 0xee, 0x28, 0x2f, 0x57, 0x85, 0xab, 0xd2, 0x00, 0x54, 0xd9, 0xf1, 0x5c, 0x6b, 0x4a, 0x5a, 0xc0, 0x4a, 0x49, 0xdd, + 0xf9, 0x4d, 0x44, 0xdc, 0x92, 0xa9, 0x98, 0xad, 0xba, 0x51, 0xe5, 0xa1, 0x44, 0x91, 0x8e, 0x3d, 0xdb, 0x39, 0x58, + 0x03, 0xe0, 0x29, 0x6c, 0x2f, 0xce, 0xb0, 0xa0, 0x8c, 0xcb, 0x96, 0xb9, 0x04, 0x8a, 0xfa, 0x61, 0x9c, 0x97, 0x1d, + 0x5f, 0xee, 0x8e, 0xb6, 0xf7, 0xd0, 0x1b, 0xb1, 0x31, 0x5e, 0x5f, 0x46, 0x4d, 0xbf, 0x78, 0x86, 0x2b, 0x4b, 0x41, + 0x1e, 0x68, 0xaa, 0x47, 0x18, 0x1d, 0x02, 0xd3, 0x94, 0x1f, 0xb1, 0xf1, 0x74, 0x38, 0x34, 0x64, 0xd0, 0x6b, 0x26, + 0xc6, 0xff, 0xfa, 0x02, 0x5a, 0x67, 0x26, 0xae, 0xf1, 0x69, 0xfb, 0x0a, 0x5a, 0xdd, 0xa2, 0x4c, 0xee, 0x0c, 0x0c, + 0x1f, 0x68, 0xc9, 0x14, 0x4c, 0x15, 0xde, 0x10, 0xa9, 0x64, 0x9f, 0x96, 0xd6, 0x61, 0xdf, 0x2e, 0x14, 0x5a, 0x68, + 0xe2, 0x57, 0x19, 0xe2, 0xa7, 0xae, 0x33, 0xff, 0x36, 0xed, 0x53, 0x83, 0x58, 0x58, 0x12, 0xa3, 0x10, 0xbf, 0x38, + 0x55, 0xb6, 0x13, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x55, 0xec, 0x49, 0xa1, 0xf1, 0xd4, 0x70, 0xdf, + 0x0b, 0x1d, 0xb3, 0x0e, 0xb3, 0xb8, 0xcd, 0x1a, 0x49, 0x8d, 0x71, 0x2a, 0x4c, 0x70, 0x4a, 0xb9, 0x8a, 0x04, 0x46, + 0xc7, 0xb3, 0x85, 0x41, 0x54, 0x49, 0x4c, 0x32, 0xb6, 0x16, 0xc2, 0xc4, 0xae, 0x73, 0x85, 0x69, 0xea, 0x22, 0xf5, + 0x9b, 0x81, 0xc9, 0x82, 0x86, 0xfc, 0x1e, 0x8d, 0xd6, 0x54, 0x4d, 0x01, 0x86, 0x71, 0x94, 0x6a, 0xfc, 0x5b, 0x84, + 0xda, 0x0c, 0x03, 0x00, 0xdb, 0xbc, 0x93, 0x99, 0xa8, 0x5e, 0x0b, 0x84, 0x40, 0x73, 0xf6, 0x53, 0x45, 0xb5, 0x33, + 0x0b, 0x46, 0xd1, 0x6e, 0xaf, 0x7c, 0x3e, 0x70, 0x42, 0x79, 0xac, 0x2e, 0x50, 0xaf, 0x64, 0xf1, 0x46, 0xa6, 0xbc, + 0x15, 0x17, 0x73, 0x4f, 0xb2, 0x0f, 0xf9, 0x08, 0xce, 0x2b, 0x74, 0x2a, 0x37, 0xdb, 0x44, 0x99, 0x25, 0x49, 0xc6, + 0x02, 0x63, 0xf3, 0x12, 0xcc, 0xa4, 0x66, 0xc6, 0xf0, 0x6b, 0x08, 0x2e, 0xb6, 0x73, 0x12, 0x6e, 0xee, 0xe7, 0x81, + 0x21, 0x34, 0xb9, 0x68, 0x89, 0x86, 0xad, 0x1d, 0xaf, 0x27, 0xd7, 0x84, 0xfb, 0xb0, 0x11, 0x6b, 0x32, 0xc6, 0xb8, + 0x36, 0x37, 0xb2, 0x7e, 0xb4, 0xc0, 0x83, 0x31, 0x65, 0xfd, 0x09, 0x64, 0x5a, 0x49, 0x59, 0xe7, 0x0b, 0x23, 0x66, + 0x52, 0x89, 0xde, 0xed, 0x1b, 0x9f, 0xd5, 0x5d, 0x44, 0xfd, 0xd6, 0x7e, 0x4f, 0xea, 0xe1, 0xce, 0x7f, 0x50, 0x58, + 0x83, 0xca, 0x88, 0xcb, 0x88, 0xf2, 0xcc, 0x81, 0x6e, 0x9a, 0x14, 0x71, 0x7a, 0xb6, 0x8a, 0x8b, 0x92, 0xa7, 0x50, + 0xa9, 0xa6, 0x6e, 0x51, 0x6f, 0x02, 0xf6, 0x86, 0x48, 0x92, 0xac, 0xa5, 0xb1, 0x15, 0xbb, 0x34, 0x48, 0xcf, 0xbd, + 0x61, 0x96, 0x5e, 0x55, 0x68, 0x48, 0x4b, 0xbd, 0xb3, 0x50, 0xc9, 0xfc, 0x15, 0xff, 0x19, 0xd4, 0x0a, 0x74, 0xb4, + 0x49, 0x31, 0x9e, 0x03, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x09, 0x4a, 0xbd, 0x23, 0x76, 0xfc, 0xdc, + 0xe4, 0xe1, 0x5d, 0xc8, 0x39, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0x48, 0x8c, 0xd4, 0x0c, 0xa0, 0xe9, 0xa0, + 0xcc, 0x79, 0x2c, 0x82, 0x59, 0xcf, 0x24, 0x46, 0x3d, 0xae, 0x7f, 0x81, 0x86, 0xda, 0x6f, 0x56, 0x96, 0x67, 0xd5, + 0xdd, 0x97, 0x70, 0x60, 0x53, 0x5b, 0x41, 0x8f, 0xd7, 0x95, 0xbc, 0xbc, 0x54, 0xdd, 0xf6, 0x0b, 0x31, 0x72, 0xba, + 0xc6, 0xb5, 0x74, 0x5e, 0x2d, 0x58, 0xaf, 0x3b, 0xdd, 0x2c, 0xee, 0x66, 0x19, 0x0d, 0x84, 0xb5, 0x9d, 0x4f, 0x34, + 0x7f, 0xd6, 0x6c, 0xbb, 0x8f, 0xb7, 0x20, 0x66, 0x01, 0x00, 0xa4, 0x07, 0x51, 0xb0, 0xcc, 0x52, 0x1e, 0x50, 0x79, + 0x1f, 0x47, 0x59, 0x28, 0xbd, 0x9c, 0x65, 0xfc, 0xb4, 0x69, 0xac, 0x75, 0x56, 0x28, 0x43, 0x6b, 0xa3, 0x3b, 0x5d, + 0x65, 0x88, 0xed, 0x27, 0x71, 0xb6, 0x00, 0xf7, 0xc7, 0x0c, 0x85, 0x86, 0xce, 0x32, 0xd2, 0x44, 0xc3, 0x77, 0xdd, + 0x33, 0xc8, 0x28, 0x4e, 0xd6, 0x79, 0x25, 0xdd, 0xe8, 0xb3, 0x36, 0x12, 0xe6, 0x1e, 0xa2, 0x5f, 0xc5, 0xe0, 0x51, + 0xee, 0xf3, 0xda, 0xe8, 0x64, 0x5a, 0x46, 0xda, 0x9d, 0x9f, 0xd4, 0xcb, 0x2c, 0xd5, 0x3a, 0x6c, 0x9f, 0x61, 0x6f, + 0x8d, 0x49, 0x6f, 0x42, 0x6a, 0x18, 0x89, 0xcf, 0x67, 0xd4, 0x08, 0x01, 0x6d, 0x39, 0xfe, 0x0e, 0x9f, 0x61, 0x68, + 0x0a, 0x2c, 0x55, 0xdc, 0xc2, 0x6e, 0xf8, 0x9a, 0x4f, 0x56, 0x2d, 0x00, 0x11, 0xac, 0x7c, 0xbd, 0x8b, 0x57, 0x42, + 0x7d, 0xa6, 0xcd, 0x00, 0x90, 0x05, 0xa5, 0xdc, 0xf1, 0x53, 0x2a, 0x1d, 0x2c, 0x51, 0xb4, 0xbd, 0x9c, 0xbe, 0xd1, + 0xb1, 0xf1, 0x43, 0x7a, 0x2e, 0x60, 0xbb, 0x90, 0xdf, 0xba, 0x57, 0x2f, 0x51, 0x91, 0xda, 0x36, 0xeb, 0x01, 0xbe, + 0xdc, 0xa0, 0x49, 0x18, 0x41, 0x99, 0x32, 0x05, 0x30, 0xb8, 0xa9, 0x46, 0xc1, 0xa4, 0xd5, 0x48, 0xd8, 0x52, 0x4f, + 0xb2, 0xdc, 0xf4, 0xc1, 0xa9, 0xee, 0x11, 0xf4, 0x68, 0x87, 0x93, 0x96, 0xfd, 0x5a, 0xc1, 0xd1, 0xc9, 0xd5, 0x10, + 0x35, 0xf3, 0x5e, 0xdb, 0x91, 0x21, 0xe5, 0x32, 0x0c, 0x04, 0x53, 0x8e, 0x79, 0x7a, 0x6c, 0x3d, 0x23, 0xa2, 0x07, + 0xce, 0x3e, 0xd3, 0xad, 0xba, 0x92, 0x80, 0xe8, 0xf8, 0xcd, 0xd3, 0xd7, 0x57, 0xf1, 0xa5, 0x41, 0x51, 0x6a, 0x58, + 0xc4, 0x28, 0xd3, 0xbe, 0x4a, 0xc2, 0xe0, 0xfd, 0xfa, 0xfe, 0x67, 0x95, 0xa5, 0xf6, 0x7b, 0xb0, 0xb1, 0xa2, 0xaa, + 0x5f, 0x4b, 0x5e, 0x34, 0x05, 0x58, 0xf7, 0x59, 0xa2, 0x40, 0xee, 0xf7, 0x36, 0xcd, 0x7c, 0x13, 0x35, 0x6e, 0x36, + 0xac, 0x37, 0xae, 0xdb, 0xa5, 0xb6, 0x64, 0x47, 0x56, 0x22, 0x67, 0x16, 0x83, 0x19, 0x3f, 0x2a, 0x0c, 0x4a, 0xc3, + 0x06, 0x55, 0xa9, 0xf8, 0xbd, 0x11, 0xc1, 0xa9, 0x63, 0x55, 0x61, 0x4c, 0x03, 0x66, 0x5b, 0x51, 0x6b, 0x50, 0x07, + 0xa5, 0xb4, 0x35, 0x51, 0xd8, 0x7e, 0x67, 0x05, 0x35, 0xbf, 0xff, 0x69, 0x0c, 0xf9, 0x9a, 0x52, 0x50, 0x49, 0xc0, + 0xce, 0xa0, 0xd1, 0x53, 0x25, 0x0c, 0xa4, 0x20, 0x78, 0x02, 0x94, 0x2f, 0xa2, 0xc6, 0x6a, 0xb7, 0xaf, 0x4e, 0x8d, + 0xd1, 0x16, 0x10, 0x5a, 0x48, 0x8f, 0x2e, 0xfb, 0xb8, 0x8d, 0x75, 0x20, 0xf1, 0xe0, 0x04, 0xdb, 0xb9, 0xba, 0x46, + 0x23, 0xa1, 0xf9, 0x43, 0xa3, 0x01, 0xaf, 0x69, 0x05, 0x0a, 0xf5, 0x1c, 0x47, 0x43, 0x67, 0x87, 0x14, 0x44, 0x6c, + 0xd0, 0xc2, 0xbe, 0x7b, 0x3e, 0x34, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x4d, 0xa5, 0xfb, 0xdc, 0x2d, 0x21, 0x6b, 0xd5, + 0xa1, 0xac, 0x3c, 0xc0, 0xf1, 0x42, 0xc9, 0xfc, 0x1d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x63, 0xc4, 0x02, 0x96, 0x04, + 0xed, 0xf5, 0x40, 0xfd, 0x32, 0x08, 0x15, 0xce, 0xf4, 0x44, 0xe2, 0x53, 0xca, 0xd5, 0xa7, 0x05, 0xa9, 0xa7, 0x05, + 0x73, 0xa0, 0x97, 0xbe, 0x95, 0x5f, 0xd9, 0xf8, 0x68, 0x77, 0xef, 0x9a, 0x0b, 0xeb, 0x18, 0x82, 0x61, 0x0b, 0xbf, + 0x39, 0x35, 0x05, 0x60, 0xc3, 0x63, 0x5d, 0x96, 0x6f, 0xd4, 0x44, 0x66, 0x71, 0x48, 0x22, 0x90, 0x6c, 0x37, 0x37, + 0xb7, 0x11, 0x6c, 0x7b, 0x0b, 0xb5, 0xa1, 0xfe, 0xf2, 0xb6, 0xfb, 0x3d, 0xc3, 0xcb, 0x3d, 0xb9, 0x77, 0xd3, 0x86, + 0xf2, 0x87, 0xfb, 0x57, 0xc9, 0xff, 0x55, 0x25, 0xf7, 0x5b, 0x65, 0xd6, 0x6d, 0xf1, 0x7e, 0xd7, 0x71, 0xcb, 0x31, + 0x1a, 0x04, 0xd6, 0x14, 0x18, 0x48, 0x4f, 0x1a, 0xd3, 0x44, 0x87, 0x54, 0x66, 0xcc, 0xe0, 0xd1, 0x05, 0x68, 0x0e, + 0xd3, 0x79, 0x1e, 0x03, 0x70, 0x80, 0x7f, 0xe4, 0x11, 0xea, 0x9f, 0xce, 0xf3, 0xe0, 0x2c, 0x18, 0x94, 0x83, 0x40, + 0x7f, 0xe2, 0x9a, 0x13, 0x2c, 0x40, 0xe7, 0x16, 0x33, 0x08, 0x36, 0x69, 0xcd, 0x1c, 0xe2, 0xc3, 0x64, 0x3a, 0x18, + 0xc4, 0x64, 0x03, 0x20, 0x7d, 0xf1, 0xc2, 0x3a, 0x07, 0x15, 0x7a, 0x41, 0xb6, 0xea, 0x2e, 0x9a, 0x15, 0x7b, 0xd5, + 0x4e, 0xf3, 0x7e, 0x3f, 0x9f, 0x97, 0x83, 0xa0, 0x51, 0x61, 0x61, 0xbc, 0xff, 0x68, 0xf3, 0x4b, 0xa3, 0x93, 0x26, + 0x18, 0xa6, 0xf6, 0x18, 0xd5, 0x2b, 0x9e, 0x66, 0xb4, 0x71, 0x3b, 0x56, 0xca, 0x17, 0x10, 0xc5, 0x03, 0x43, 0xd6, + 0xca, 0xbb, 0x73, 0xf0, 0xba, 0xdc, 0x78, 0x73, 0x44, 0x01, 0x76, 0x53, 0x18, 0x27, 0x35, 0x17, 0x5d, 0xd4, 0xc4, + 0x33, 0xd8, 0xe9, 0xea, 0xad, 0x44, 0xab, 0xf1, 0x5e, 0xbc, 0x6b, 0x36, 0xfe, 0x56, 0xee, 0xe9, 0x32, 0xf7, 0x2e, + 0x00, 0x71, 0x76, 0x2f, 0xae, 0xf6, 0xb0, 0xd4, 0xbd, 0x60, 0x60, 0x91, 0x43, 0xda, 0xd5, 0xea, 0xa1, 0x88, 0xd4, + 0x79, 0x0c, 0x06, 0x4c, 0xa6, 0x21, 0x35, 0x99, 0xf6, 0x0a, 0x05, 0x69, 0x63, 0xad, 0x05, 0xb4, 0xe1, 0xb0, 0xd8, + 0xb1, 0x1b, 0x76, 0xa7, 0x5b, 0x87, 0x42, 0x09, 0xa3, 0x57, 0xd7, 0xcd, 0x43, 0xad, 0xe1, 0x89, 0xa0, 0x07, 0xd5, + 0x68, 0x3f, 0x3d, 0x94, 0x27, 0xed, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0x52, 0xe0, 0x45, 0x7b, 0x07, 0x79, 0xce, + 0x7c, 0xaa, 0x7c, 0x10, 0x1b, 0x6e, 0x19, 0x3e, 0xb4, 0x8f, 0x6f, 0x05, 0x32, 0xa9, 0x3b, 0x9a, 0xda, 0xda, 0x1d, + 0x8d, 0x63, 0x02, 0xfd, 0xa6, 0x1c, 0xa5, 0x4c, 0x4c, 0x2d, 0x4b, 0x76, 0xd4, 0xcb, 0x95, 0x37, 0x54, 0xca, 0x8e, + 0x96, 0x6d, 0xce, 0x2f, 0x6d, 0x24, 0xf4, 0xfb, 0xda, 0x1d, 0x08, 0xdf, 0xa8, 0xf5, 0x86, 0xbc, 0x6c, 0x88, 0x58, + 0x0e, 0x31, 0x03, 0xc7, 0x0b, 0xa9, 0x5c, 0xbb, 0x8b, 0xa6, 0xaa, 0x6e, 0x67, 0x2b, 0x17, 0xb4, 0xc4, 0x5b, 0x29, + 0xb0, 0x8a, 0xd4, 0xe9, 0xf5, 0x54, 0xe2, 0x7d, 0x1f, 0xc5, 0xf6, 0x23, 0x60, 0x1b, 0x1b, 0x47, 0x63, 0xe3, 0x16, + 0xb1, 0xc1, 0x57, 0x51, 0x45, 0x0b, 0x0e, 0x10, 0xdc, 0x6d, 0x49, 0x2d, 0xcd, 0x1c, 0xe2, 0xbe, 0xe2, 0x01, 0xda, + 0x77, 0x71, 0xc4, 0xa9, 0x00, 0xdb, 0xba, 0xd6, 0x39, 0xab, 0xe5, 0x80, 0xcd, 0x44, 0xcf, 0x3f, 0xad, 0x1a, 0x89, + 0x18, 0x56, 0xd9, 0x48, 0x59, 0xa1, 0x3d, 0x28, 0x5d, 0xc2, 0xc5, 0x17, 0xe0, 0x65, 0xfb, 0x7e, 0x65, 0xf7, 0xd9, + 0x12, 0xfb, 0x87, 0x79, 0xd5, 0x04, 0x8f, 0xbc, 0xc6, 0xdb, 0x7b, 0x98, 0xf8, 0x52, 0x29, 0x84, 0x57, 0x29, 0x0d, + 0x25, 0x00, 0x83, 0x24, 0xa8, 0xe1, 0x4a, 0xdb, 0x66, 0x90, 0xca, 0x18, 0x76, 0xb7, 0x7a, 0xab, 0xff, 0xd3, 0x2a, + 0x5c, 0x54, 0xb2, 0x18, 0x93, 0x40, 0xe7, 0x54, 0xcb, 0x4d, 0x4c, 0xc1, 0xb3, 0x5d, 0x72, 0x04, 0x0a, 0x3b, 0x01, + 0xdc, 0x50, 0xc2, 0x7e, 0xc5, 0xdb, 0x50, 0xce, 0x5e, 0x59, 0xc9, 0x93, 0xdb, 0x97, 0x54, 0xd0, 0x84, 0x4c, 0x85, + 0xdd, 0xbf, 0xad, 0x0d, 0xfb, 0x22, 0x94, 0x23, 0x29, 0x70, 0x71, 0xd0, 0x39, 0x80, 0xfd, 0x41, 0x2e, 0x63, 0xf3, + 0x99, 0xf4, 0xfb, 0xea, 0xfd, 0xf3, 0x3c, 0x4b, 0x3e, 0xee, 0xbc, 0x37, 0x3c, 0xcd, 0x92, 0x01, 0x95, 0x88, 0xa9, + 0x75, 0x55, 0x0c, 0x97, 0xda, 0xc5, 0xb8, 0x41, 0x32, 0xe2, 0x7b, 0xa9, 0x43, 0x8c, 0x18, 0x5f, 0x64, 0x87, 0xa4, + 0xe4, 0x74, 0x59, 0x77, 0xf6, 0x5c, 0x8b, 0x66, 0xd0, 0x18, 0x6e, 0xc7, 0x7b, 0x49, 0xaf, 0x00, 0x15, 0x15, 0xba, + 0x67, 0x81, 0x6b, 0x78, 0x73, 0x49, 0x34, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xb8, 0x57, 0x26, 0x24, 0xd5, 0xc6, 0x01, + 0x16, 0xb1, 0xae, 0x3f, 0x86, 0x12, 0x80, 0x5a, 0x0d, 0xd2, 0x2b, 0x7d, 0x45, 0xa8, 0x4a, 0x42, 0x30, 0x3a, 0x91, + 0xf0, 0x32, 0xa0, 0x71, 0x66, 0x12, 0x2d, 0x6c, 0x70, 0x40, 0x5f, 0x54, 0x26, 0xd1, 0xd8, 0x90, 0x07, 0xb4, 0xb2, + 0x69, 0x00, 0x83, 0x0f, 0x92, 0x24, 0xfa, 0x7a, 0x69, 0x92, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x4b, 0xe9, 0xf9, + 0x58, 0xfe, 0xcb, 0x3b, 0x94, 0x7e, 0x08, 0x25, 0xc8, 0x14, 0x75, 0xc5, 0x34, 0x63, 0x47, 0x59, 0xb7, 0x31, 0x89, + 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x79, 0xbc, 0x62, 0xc7, 0x21, 0xd7, + 0x78, 0xe9, 0xcf, 0xe3, 0x15, 0xce, 0x10, 0xad, 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, + 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x4e, 0x92, 0xf9, 0xf2, + 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, + 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x5a, + 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1b, 0x50, 0x22, 0xa3, 0xb2, + 0xe2, 0xab, 0x15, 0x4f, 0x67, 0xb7, 0x49, 0x94, 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0x59, 0x9f, 0x67, + 0xc9, 0x6b, 0x88, 0x3d, 0xb0, 0x92, 0x0a, 0x8b, 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x76, + 0x9d, 0x44, 0x6f, 0x97, 0x1e, 0x92, 0x9a, 0x99, 0xb2, 0x4d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x1b, 0x6d, 0x01, + 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, + 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x0f, 0x8b, 0x7e, 0x5f, + 0x1e, 0x16, 0xdb, 0x6d, 0x79, 0x14, 0xf7, 0xfb, 0xf2, 0x28, 0x36, 0xfc, 0x83, 0x52, 0x6c, 0x1b, 0x73, 0x83, 0x84, + 0xe6, 0x12, 0xa2, 0x16, 0x8d, 0xe0, 0x0f, 0xcd, 0x72, 0x2e, 0xa2, 0xfc, 0x30, 0xe9, 0xf7, 0x7b, 0xcb, 0x99, 0x18, + 0xe4, 0xc3, 0x24, 0xca, 0x87, 0x89, 0xe7, 0x84, 0xf8, 0x9b, 0xe7, 0x84, 0xa8, 0x68, 0xe0, 0x0a, 0xce, 0x0c, 0x40, + 0x14, 0xf0, 0xe9, 0x1f, 0xd5, 0xb5, 0x14, 0xba, 0x96, 0x58, 0xd5, 0x92, 0xe8, 0x0a, 0x6a, 0x76, 0x5d, 0x84, 0x25, + 0x96, 0x42, 0x97, 0xec, 0xcf, 0x25, 0xf0, 0x44, 0x39, 0xaf, 0x36, 0xc0, 0xc0, 0x46, 0x78, 0xe7, 0x30, 0xe1, 0x24, + 0xd6, 0x35, 0xa0, 0x9d, 0x6e, 0x6a, 0x7a, 0x41, 0x57, 0xf4, 0x12, 0xf9, 0xd9, 0x0b, 0x30, 0x58, 0x3a, 0x64, 0xf9, + 0x74, 0x30, 0xb8, 0x20, 0x2b, 0x56, 0xce, 0xc3, 0x78, 0x10, 0xae, 0x67, 0xf9, 0xf0, 0x22, 0xba, 0x20, 0xe4, 0xab, + 0x62, 0x41, 0x7b, 0xab, 0x51, 0xf9, 0x31, 0x83, 0xe0, 0x7e, 0xe9, 0x2c, 0xcc, 0x4c, 0x9c, 0x8f, 0xd5, 0xe8, 0x96, + 0xae, 0x20, 0x7e, 0x0d, 0xdc, 0x48, 0x48, 0x04, 0x1d, 0xb9, 0xa4, 0x2b, 0xba, 0xa6, 0xd2, 0xcc, 0x30, 0x86, 0xe8, + 0xb6, 0xc7, 0x49, 0x02, 0x8e, 0xc9, 0xae, 0xf8, 0x68, 0xac, 0x0a, 0xef, 0xfa, 0x8e, 0xd0, 0x5e, 0x2f, 0x71, 0x83, + 0xf4, 0x5d, 0x7b, 0x90, 0x80, 0x11, 0x19, 0xa9, 0x81, 0x32, 0x23, 0x23, 0xa9, 0x99, 0x54, 0x1c, 0x92, 0xd8, 0x1f, + 0x12, 0x35, 0x0e, 0x89, 0x3f, 0x0e, 0xb9, 0x1e, 0x07, 0xe4, 0xee, 0x97, 0x6c, 0x4c, 0x53, 0x36, 0xa6, 0x6b, 0x35, + 0x2a, 0xf4, 0x8a, 0x9e, 0x6b, 0xea, 0x78, 0xc6, 0xde, 0xc0, 0x81, 0x3d, 0x08, 0xf3, 0x59, 0x3c, 0x7c, 0x13, 0xbd, + 0x21, 0xe4, 0x2b, 0x49, 0xaf, 0xd5, 0xa5, 0x0c, 0xc2, 0x20, 0x5e, 0x81, 0x73, 0xa9, 0x0b, 0x75, 0x72, 0x65, 0x76, + 0x1c, 0x3e, 0x5d, 0x36, 0x9e, 0xce, 0x21, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x05, 0x2b, 0xe7, 0x67, 0xe1, + 0x98, 0x00, 0x0e, 0x8f, 0x1e, 0xce, 0x8b, 0xd1, 0x2d, 0xbd, 0x18, 0xdd, 0x11, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0x87, + 0x2c, 0x9e, 0x0e, 0x06, 0x6b, 0xa4, 0xea, 0x2a, 0xf7, 0x9a, 0x2c, 0xe8, 0x05, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x13, + 0x6b, 0x43, 0xc3, 0xdf, 0x30, 0xf8, 0xf8, 0x8e, 0x5d, 0x8c, 0xee, 0xe8, 0x2d, 0x7b, 0xb3, 0x1d, 0x4f, 0x81, 0x99, + 0x5a, 0xcd, 0xc2, 0xbb, 0xc3, 0xcb, 0xd9, 0x25, 0xbb, 0x8b, 0xee, 0x8e, 0xa0, 0xa1, 0x57, 0xec, 0x0e, 0x01, 0x97, + 0xd2, 0xc7, 0xcb, 0xc1, 0x1b, 0xb2, 0x3f, 0x18, 0xa4, 0x24, 0x0a, 0xaf, 0x43, 0xaf, 0x95, 0x6f, 0xe8, 0x1d, 0xa1, + 0x2b, 0x76, 0x8b, 0xa3, 0x71, 0xc9, 0xf0, 0x83, 0x73, 0x76, 0x57, 0x5f, 0x87, 0xde, 0x6e, 0x4e, 0x44, 0x27, 0x88, + 0x11, 0xfa, 0x1a, 0x38, 0x9a, 0xe5, 0xc2, 0x4c, 0xc0, 0x93, 0xb9, 0xc8, 0x68, 0x51, 0x68, 0x06, 0xe2, 0xac, 0x04, + 0xc4, 0x92, 0xa8, 0xfb, 0xcd, 0x46, 0x67, 0xb0, 0x9c, 0xfb, 0xfd, 0x5e, 0x65, 0xe8, 0x01, 0x22, 0x67, 0x76, 0xd2, + 0x83, 0x9e, 0x4f, 0x0f, 0xf0, 0x13, 0xbd, 0x6a, 0x10, 0x27, 0xf3, 0xbb, 0x65, 0xf4, 0x9b, 0x47, 0x1f, 0x7e, 0xe8, + 0xa6, 0x3c, 0x22, 0xff, 0xf7, 0x29, 0x4f, 0x99, 0x47, 0x6f, 0x2a, 0x0f, 0x04, 0xcf, 0x5b, 0x93, 0x4a, 0x23, 0x51, + 0x8d, 0xce, 0x56, 0x31, 0x68, 0x23, 0x51, 0xdb, 0xa0, 0x9f, 0xd0, 0xc2, 0x0a, 0x22, 0xe4, 0x1c, 0xbc, 0x00, 0x83, + 0x54, 0x08, 0x95, 0xa3, 0x16, 0x25, 0x1a, 0x82, 0xe4, 0xb2, 0xe4, 0x2a, 0x7c, 0x0e, 0xa1, 0xea, 0xf4, 0x71, 0x26, + 0xc2, 0x86, 0x1e, 0x87, 0x3e, 0x00, 0xfc, 0xaf, 0x3b, 0xe4, 0xa2, 0xe4, 0x97, 0x78, 0x36, 0xb7, 0x09, 0x46, 0xc1, + 0x12, 0xd1, 0x0c, 0x6d, 0x83, 0xd8, 0x8f, 0x25, 0xc1, 0x7a, 0x24, 0x8d, 0x47, 0xa5, 0x39, 0x22, 0xfc, 0x28, 0x3e, + 0x8a, 0x9e, 0xc6, 0x86, 0x44, 0x72, 0x24, 0x91, 0x7c, 0x00, 0x84, 0x93, 0xa0, 0xbf, 0xb8, 0x6b, 0xb2, 0x6b, 0x21, + 0x31, 0xe8, 0x4f, 0x4b, 0xa6, 0x65, 0xf7, 0xaa, 0xc7, 0xbe, 0x22, 0xc8, 0x1d, 0xd3, 0x7f, 0x79, 0x7d, 0xf8, 0xe7, + 0x12, 0x67, 0xd0, 0x7a, 0xbe, 0xa8, 0xce, 0xcc, 0xbc, 0xc1, 0x8d, 0xbc, 0x2e, 0x6b, 0xd7, 0xe5, 0x0b, 0xbe, 0xc7, + 0x6f, 0x2b, 0x2e, 0xd2, 0x72, 0xef, 0x97, 0xaa, 0x8d, 0xe7, 0x54, 0xae, 0x57, 0x2e, 0xce, 0x8a, 0x32, 0x4e, 0xf5, + 0xa4, 0x2e, 0xc6, 0x1a, 0xb6, 0xe1, 0xf7, 0x88, 0xba, 0x92, 0x96, 0xa3, 0xa7, 0x94, 0xab, 0x66, 0xca, 0xc5, 0x3a, + 0xcf, 0x7f, 0xde, 0x49, 0xc5, 0x29, 0x6e, 0xa6, 0x20, 0x55, 0x6a, 0xb9, 0x80, 0xea, 0x39, 0x6a, 0xb9, 0x5b, 0x9a, + 0x1d, 0xe0, 0xdc, 0x36, 0xd5, 0xc7, 0xca, 0xec, 0xc2, 0x4b, 0x6e, 0xdc, 0x9f, 0x4c, 0x19, 0x16, 0x8c, 0x42, 0x9b, + 0x55, 0x57, 0xda, 0xbe, 0xd0, 0x3a, 0x0d, 0xc3, 0x95, 0x1f, 0x2f, 0x20, 0x5d, 0xc0, 0x38, 0x5e, 0x94, 0x4c, 0x8c, + 0xdb, 0xa3, 0xb7, 0x82, 0xf8, 0x92, 0xad, 0x40, 0xc0, 0x5c, 0xc3, 0xdb, 0x75, 0x1d, 0x6d, 0xf7, 0xc4, 0x29, 0xa3, + 0x72, 0x15, 0x8b, 0xef, 0xe3, 0x95, 0x81, 0x4c, 0x56, 0xc7, 0x63, 0x63, 0x4c, 0xa7, 0x3f, 0x25, 0xa1, 0x5f, 0x08, + 0x05, 0x9f, 0xf5, 0xd2, 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, + 0xe4, 0xab, 0xa6, 0x80, 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, + 0x9d, 0x1a, 0x53, 0x31, 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, + 0xa8, 0xdf, 0x02, 0x17, 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, + 0xbe, 0x85, 0x07, 0x88, 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, + 0xa9, 0xd2, 0xc4, 0x70, 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, + 0xe8, 0xa6, 0x74, 0xe9, 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, + 0xac, 0x95, 0xf0, 0xa6, 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, + 0x14, 0x0d, 0x1d, 0xd0, 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, + 0x35, 0x2b, 0xe6, 0xf9, 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, + 0x21, 0xc9, 0x26, 0x56, 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, + 0x32, 0x0c, 0xcb, 0xe1, 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x70, 0x3e, 0x09, 0x15, + 0xbb, 0x60, 0xf7, 0x02, 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, + 0x65, 0x16, 0xcf, 0xc7, 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, + 0xbe, 0xc1, 0x2a, 0xf2, 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, + 0xdc, 0x94, 0x33, 0xae, 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, + 0x49, 0xd3, 0x80, 0xee, 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, + 0xad, 0xd0, 0xab, 0x1a, 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, + 0x12, 0x06, 0x3f, 0xa4, 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, + 0x14, 0x62, 0x94, 0x50, 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, + 0x7c, 0x5d, 0x55, 0x81, 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, + 0x48, 0x08, 0x5e, 0xff, 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, + 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, + 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, + 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, + 0x4f, 0xae, 0xd8, 0x51, 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, + 0xf7, 0x1f, 0xcb, 0x5d, 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, + 0x84, 0x2d, 0xe6, 0x70, 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, + 0xb4, 0xcc, 0xaa, 0xf7, 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, + 0x02, 0xd0, 0x64, 0x23, 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, + 0x92, 0xa0, 0x84, 0x66, 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, + 0x07, 0xf6, 0x16, 0x04, 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, + 0x08, 0xf2, 0xd5, 0x18, 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, + 0xe4, 0xd0, 0x3e, 0x4b, 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb7, 0x2d, 0xb2, 0x24, 0xeb, + 0xc7, 0xd2, 0x28, 0x62, 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3e, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, + 0x0e, 0xe2, 0x36, 0x08, 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, + 0x6f, 0xb2, 0xd6, 0xa8, 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, + 0xdb, 0xed, 0x78, 0x2a, 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, + 0xa5, 0xb7, 0x7f, 0xe1, 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, + 0x4e, 0xff, 0x76, 0x6b, 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xb4, 0x81, 0x2b, 0xd5, 0x2a, 0x04, 0xec, 0x42, + 0x49, 0xf6, 0x0f, 0x20, 0x2a, 0x42, 0x33, 0xee, 0x66, 0xd9, 0x90, 0xc8, 0xf8, 0x71, 0x3a, 0xcb, 0x86, 0x60, 0x87, + 0x7b, 0x51, 0x89, 0xcb, 0x51, 0x6b, 0x83, 0xd3, 0xb3, 0x24, 0x84, 0x50, 0x0e, 0x58, 0xd9, 0xad, 0xfa, 0x73, 0xa7, + 0xcc, 0x84, 0xd4, 0x64, 0x75, 0x3b, 0xa5, 0x7b, 0x98, 0xe6, 0x7b, 0x66, 0x04, 0x07, 0xdc, 0xdb, 0x5f, 0xf5, 0xc7, + 0x30, 0xc9, 0x34, 0x39, 0x45, 0xf2, 0x8b, 0xf4, 0x14, 0x92, 0x76, 0xe8, 0xa9, 0x22, 0x80, 0x13, 0x6a, 0x3f, 0x86, + 0xdf, 0x30, 0xee, 0xdf, 0x35, 0x5f, 0xbb, 0xa9, 0x88, 0x9e, 0x52, 0x2c, 0x53, 0x93, 0xd3, 0x24, 0x2b, 0x12, 0x88, + 0xda, 0xa8, 0x9a, 0x11, 0x3d, 0x71, 0x31, 0x1f, 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, + 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xec, 0x29, 0xdd, 0x9b, 0x7c, 0x73, 0x40, 0xf7, 0x0e, 0x9e, 0x3c, 0x23, 0x00, + 0x8b, 0x76, 0x79, 0x1e, 0x1e, 0x3c, 0x7b, 0x46, 0xf7, 0xbe, 0xfd, 0x96, 0xee, 0x4d, 0x9e, 0x1c, 0x34, 0xd2, 0x26, + 0xcf, 0xbe, 0xa5, 0x7b, 0xdf, 0x3c, 0x6d, 0xa4, 0x1d, 0x8c, 0x9f, 0xd1, 0xbd, 0xbf, 0x7f, 0x63, 0xd2, 0xfe, 0x06, + 0xd9, 0xbe, 0x3d, 0xc0, 0xff, 0x4c, 0xda, 0xe4, 0xd9, 0x13, 0xba, 0x37, 0x19, 0x43, 0x25, 0xcf, 0x5c, 0x25, 0xe3, + 0x09, 0x7c, 0xfc, 0x04, 0xfe, 0xfb, 0x1b, 0x09, 0x16, 0xb4, 0x92, 0x2c, 0x17, 0xa8, 0x3f, 0x43, 0x11, 0x27, 0xaa, + 0x26, 0x12, 0x1e, 0x62, 0x66, 0xf5, 0x4d, 0x1c, 0x06, 0xc4, 0xa5, 0x43, 0x41, 0x74, 0x6f, 0x3c, 0x7a, 0x46, 0x02, + 0x1f, 0x9e, 0xee, 0xc6, 0x07, 0x19, 0xcb, 0xc5, 0x3c, 0xfb, 0x2a, 0x37, 0xb1, 0x15, 0x3c, 0x00, 0xab, 0x8f, 0x7e, + 0xae, 0x4a, 0xce, 0xb3, 0xaf, 0x2a, 0xb9, 0x9b, 0xeb, 0xf7, 0x16, 0xa0, 0xbc, 0xbf, 0x6a, 0xd9, 0x4d, 0xa1, 0x42, + 0xa7, 0xb5, 0x46, 0x9f, 0x7d, 0xc4, 0xf4, 0xc1, 0xc0, 0xbb, 0x61, 0xff, 0xb4, 0x53, 0x4e, 0xeb, 0x1b, 0x8d, 0x42, + 0x8d, 0xca, 0x43, 0xc2, 0x8e, 0xa0, 0xe8, 0xc1, 0x00, 0x78, 0x02, 0x0f, 0xf7, 0xed, 0xdf, 0x2c, 0xe3, 0x63, 0x47, + 0x19, 0xbf, 0xa0, 0x0c, 0x01, 0x8d, 0x7a, 0x98, 0xdd, 0xf4, 0xb0, 0xd1, 0xad, 0x5e, 0xb2, 0x54, 0x27, 0x53, 0xd3, + 0x33, 0xd8, 0xd7, 0xba, 0x96, 0x7b, 0x46, 0x14, 0x2d, 0x2f, 0xf6, 0x52, 0x3e, 0xab, 0xd8, 0x4f, 0x4b, 0x54, 0x6f, + 0x45, 0x8d, 0x37, 0x32, 0x9b, 0x55, 0xec, 0x7b, 0xf3, 0x06, 0xb8, 0x19, 0xf6, 0xbb, 0x7a, 0xf2, 0x03, 0x67, 0x70, + 0x69, 0xdb, 0xa3, 0x4c, 0x8c, 0x00, 0x2b, 0x20, 0x03, 0x07, 0x1e, 0x00, 0x1d, 0xf4, 0x47, 0x7b, 0xbb, 0x55, 0x29, + 0xcd, 0x3e, 0x5b, 0x18, 0x40, 0xc3, 0xbc, 0x4d, 0x5c, 0xd9, 0xff, 0x6a, 0xc8, 0x4b, 0x50, 0xb8, 0xd5, 0x2c, 0x6f, + 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x65, 0x40, 0xcd, 0x96, 0x8f, 0x36, + 0x5c, 0xa9, 0x27, 0x81, 0x33, 0xb8, 0x90, 0x45, 0xc2, 0x4f, 0xb4, 0xd8, 0x1f, 0xad, 0x1f, 0x7d, 0xdf, 0x1e, 0x0f, + 0xd6, 0xbe, 0xc7, 0x47, 0xfa, 0xb3, 0xc6, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0x17, 0xb5, 0x95, 0x78, 0x94, 0xc0, 0x1b, + 0x98, 0x88, 0x14, 0x06, 0xa9, 0x16, 0x38, 0x06, 0xe5, 0x8d, 0x85, 0x58, 0xaa, 0xae, 0x6e, 0xb0, 0x05, 0x91, 0x21, + 0x78, 0xb8, 0xfd, 0x6b, 0xa9, 0x02, 0x47, 0xf5, 0xfb, 0x5c, 0xfa, 0x6e, 0x4f, 0xc6, 0x8e, 0x1c, 0xa7, 0x7e, 0x2a, + 0x1c, 0xfc, 0x37, 0xa9, 0x6b, 0x63, 0xb9, 0x92, 0x32, 0xcb, 0xb2, 0xb0, 0xa3, 0x50, 0xcb, 0x3d, 0x2a, 0x0f, 0x92, + 0x2f, 0xe4, 0x10, 0xc9, 0x02, 0xa3, 0x50, 0x90, 0xe1, 0x84, 0x8a, 0xd1, 0x5a, 0x94, 0xcb, 0xec, 0xa2, 0x0a, 0x37, + 0x4a, 0xa1, 0xcc, 0x29, 0xfa, 0x76, 0x83, 0x03, 0x09, 0x89, 0xb2, 0xf2, 0x6d, 0xfc, 0x36, 0x44, 0xb0, 0x3a, 0xae, + 0x6d, 0xa1, 0xb8, 0xb7, 0x3f, 0x79, 0xda, 0xc5, 0x1f, 0x19, 0x17, 0x50, 0x17, 0x8b, 0x69, 0x38, 0xb1, 0xb1, 0x6f, + 0xdc, 0x17, 0x56, 0xd3, 0x03, 0x50, 0xdf, 0xa5, 0x12, 0x23, 0xa8, 0xaf, 0x8c, 0x7d, 0x6c, 0x8f, 0x31, 0x39, 0x83, + 0x58, 0xc3, 0x2a, 0x67, 0xa6, 0xfa, 0x46, 0xd8, 0x11, 0x00, 0x37, 0x42, 0x6b, 0x14, 0x04, 0x1e, 0xaf, 0x42, 0x3c, + 0x2f, 0x55, 0xf8, 0xd6, 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, + 0x61, 0xb5, 0x95, 0x65, 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, + 0x5c, 0x0a, 0xcb, 0xa0, 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, + 0x44, 0x23, 0xc4, 0xc3, 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, + 0xa3, 0x04, 0x97, 0xa9, 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, + 0x6a, 0x5f, 0x43, 0x31, 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, + 0x4d, 0xd8, 0xb9, 0x91, 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, + 0xdb, 0x22, 0x73, 0x44, 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, + 0xf1, 0x14, 0x11, 0x01, 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, + 0x81, 0x2c, 0x80, 0xbe, 0xfd, 0x9c, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, + 0x04, 0xbb, 0xba, 0x35, 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, + 0x44, 0x02, 0x32, 0xfb, 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, + 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, + 0x17, 0x7f, 0x5a, 0x75, 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, + 0x6d, 0x29, 0xc9, 0x55, 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, + 0xee, 0x0e, 0xbf, 0xc4, 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, + 0x2a, 0xca, 0x07, 0x13, 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, + 0xac, 0x77, 0xd3, 0x5a, 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, + 0x30, 0x20, 0xda, 0xa5, 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, + 0x9e, 0x01, 0x49, 0x26, 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, + 0xfb, 0x7a, 0xc6, 0x7f, 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, + 0x10, 0x43, 0x54, 0x7b, 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, + 0x43, 0xa3, 0xde, 0xc6, 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, + 0x88, 0x64, 0xbf, 0x3d, 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, + 0xb8, 0x2c, 0x22, 0xcb, 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, + 0xbf, 0x5e, 0xc9, 0x02, 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, + 0xe3, 0xce, 0x9e, 0x80, 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, + 0xb7, 0x80, 0x49, 0xc0, 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, + 0xd6, 0xfe, 0xd5, 0x5d, 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, + 0xa4, 0xb0, 0xe5, 0x31, 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, + 0x0d, 0xee, 0x47, 0x15, 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, + 0x72, 0xbc, 0xed, 0x76, 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, + 0x59, 0xef, 0x25, 0x60, 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, + 0x4b, 0xb2, 0x1f, 0xa6, 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, + 0x41, 0x6f, 0xe9, 0x0d, 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, + 0xfb, 0xfd, 0xde, 0x99, 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, + 0x9b, 0xf0, 0x2c, 0x0f, 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, + 0x93, 0x23, 0xd0, 0x9b, 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, + 0xde, 0xb5, 0x27, 0x63, 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, + 0x7f, 0xb3, 0xf0, 0x86, 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, + 0xd2, 0x53, 0x76, 0x45, 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0xa7, 0x38, 0x0c, 0xe3, 0x61, 0x41, + 0xf6, 0x25, 0xbd, 0xdb, 0x9f, 0xf0, 0x27, 0x64, 0x16, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, + 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0x4e, 0xe8, 0x0d, 0x2b, 0xe8, 0x29, 0x8b, 0x49, 0x74, 0x0d, 0xad, 0x38, 0x9f, + 0x15, 0xd1, 0x0d, 0x3d, 0x65, 0x67, 0xb3, 0x38, 0x3a, 0xa5, 0x27, 0x2c, 0x1f, 0x4e, 0x20, 0xef, 0xe9, 0xf0, 0x86, + 0xec, 0x9f, 0x90, 0x28, 0x3c, 0xd1, 0xbf, 0xef, 0xe8, 0x25, 0x0f, 0x4f, 0xa8, 0x57, 0xcd, 0x09, 0x31, 0xd5, 0x37, + 0x6a, 0x3f, 0x21, 0x91, 0x3f, 0x98, 0x27, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, + 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, 0x06, 0x74, 0xf6, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, + 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, 0xd7, 0xc1, 0x6b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0xeb, 0x7e, 0x1f, 0x22, + 0xdd, 0x17, 0x33, 0x13, 0xdb, 0xcd, 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0xd7, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, + 0xbc, 0x19, 0xbc, 0x7e, 0x7c, 0x47, 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x1b, 0x9a, 0x01, 0xe0, 0xd7, 0xeb, + 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, 0x7d, 0x7d, 0x78, 0x32, 0x1d, 0x0c, 0x5e, 0x9b, 0x6d, 0xf2, 0x96, 0xdd, 0x53, + 0x0a, 0xac, 0xbf, 0xb3, 0x7e, 0xff, 0xed, 0x51, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xd6, 0x45, + 0x55, 0x3b, 0xeb, 0xf7, 0xd7, 0xfd, 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9c, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x8e, 0x22, + 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, 0xac, 0xda, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, + 0xec, 0x9d, 0x6d, 0xb7, 0xa7, 0x8c, 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, + 0xcc, 0xe6, 0x66, 0x69, 0x0f, 0x81, 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0x2f, 0x00, + 0x42, 0x24, 0x59, 0xc8, 0x67, 0x38, 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xbb, + 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, 0xd1, 0xdf, 0x9e, 0x3d, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, + 0x61, 0x17, 0x6b, 0xb5, 0x0f, 0x46, 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0xbe, 0x98, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, + 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, 0x18, 0x4c, 0x2e, 0xd2, 0xcf, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, + 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, 0xdb, 0x6e, 0x2b, 0xff, 0x12, 0xf8, 0x16, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, + 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, + 0xba, 0xdc, 0xe3, 0xea, 0x5f, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, + 0x0c, 0xb7, 0x56, 0x22, 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, + 0x86, 0x07, 0xc9, 0xc4, 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, + 0x24, 0xd3, 0xe4, 0x10, 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, + 0x8e, 0x49, 0xad, 0xef, 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, + 0x78, 0x34, 0x7e, 0x46, 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, + 0x9b, 0x57, 0x3a, 0x36, 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, + 0xea, 0x23, 0x08, 0xb3, 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, + 0xa3, 0x52, 0xa6, 0xba, 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, + 0x10, 0xc0, 0xa3, 0x11, 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, + 0xde, 0x83, 0x30, 0x29, 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, + 0x57, 0x10, 0x27, 0x6c, 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, + 0x25, 0xf7, 0x26, 0xe3, 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, + 0x57, 0xdc, 0x1b, 0x17, 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, + 0x76, 0x3f, 0x31, 0x2b, 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xf6, 0xf2, 0xec, 0xf5, + 0xdb, 0x57, 0xaf, 0xdf, 0xbe, 0xfe, 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, + 0x6a, 0xf1, 0x85, 0xb3, 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, + 0x20, 0xa3, 0x51, 0x21, 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, + 0xdb, 0xd1, 0xd6, 0xac, 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, + 0xc8, 0x75, 0xf0, 0xbe, 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, + 0x13, 0x73, 0x6d, 0x74, 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, + 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, + 0xc2, 0xfc, 0x0c, 0x1b, 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, + 0xce, 0x17, 0xdf, 0x42, 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, + 0x31, 0x1e, 0x77, 0xf7, 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, + 0xbe, 0x5d, 0x24, 0xce, 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, + 0x35, 0xe7, 0x6d, 0x42, 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, + 0x17, 0x43, 0x9a, 0x72, 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, + 0xd7, 0xd9, 0xe6, 0x33, 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, + 0xc4, 0x40, 0x74, 0x01, 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, + 0x31, 0x8b, 0xad, 0x25, 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x84, 0x1d, 0x7d, + 0xf7, 0xb6, 0x01, 0x10, 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, + 0x2b, 0xb4, 0xec, 0x95, 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, + 0xa6, 0x12, 0xd5, 0x23, 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, + 0xee, 0xff, 0xe6, 0x42, 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, + 0x5d, 0xa6, 0x97, 0x5d, 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, + 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, + 0x7c, 0x89, 0x5f, 0x29, 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, + 0xfe, 0x17, 0x18, 0x0d, 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, + 0xeb, 0x67, 0x35, 0xcc, 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, + 0x29, 0x11, 0x83, 0x41, 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, + 0x1a, 0x5b, 0x92, 0x6c, 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, + 0x32, 0xd3, 0xc2, 0xa2, 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, + 0x4d, 0xac, 0xf1, 0x8b, 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, + 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, + 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, + 0xcc, 0xaf, 0x24, 0x19, 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, + 0xdc, 0x18, 0xd6, 0xf4, 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, + 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, + 0x60, 0x1c, 0xa5, 0x83, 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, + 0x0b, 0x68, 0xda, 0x97, 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, + 0x0b, 0xd7, 0xc2, 0x8b, 0xdd, 0x16, 0x0a, 0x4d, 0xb6, 0x0b, 0xf9, 0xff, 0xe3, 0x86, 0x71, 0xdf, 0x5d, 0xc2, 0x2c, + 0xae, 0xeb, 0x6c, 0xb4, 0x2a, 0x64, 0x25, 0xe1, 0x36, 0xa1, 0x44, 0x61, 0xa3, 0x78, 0xb5, 0xca, 0xb5, 0x8b, 0xd8, + 0xbc, 0xa2, 0x00, 0xee, 0x02, 0x71, 0x8a, 0x81, 0x85, 0x36, 0x06, 0x72, 0x9f, 0x78, 0x21, 0x99, 0x55, 0xfb, 0x98, + 0x7b, 0xe4, 0x9f, 0x21, 0x18, 0xa3, 0x8a, 0xa3, 0xf1, 0x4c, 0x61, 0x5d, 0x7c, 0x4e, 0xde, 0xfb, 0x6f, 0x1c, 0x45, + 0xf6, 0x68, 0x06, 0x3d, 0x41, 0xe4, 0x3c, 0xe2, 0xec, 0xc9, 0xe4, 0x65, 0xe0, 0x7e, 0x06, 0x2b, 0xfd, 0x75, 0xb7, + 0x19, 0x6b, 0xdb, 0xa3, 0x7b, 0x61, 0x84, 0xa2, 0x9f, 0xf0, 0x9d, 0xa9, 0x17, 0x70, 0x09, 0xd5, 0xc0, 0xae, 0x2f, + 0x2f, 0x79, 0x09, 0x20, 0x42, 0x99, 0xe8, 0xf7, 0x7b, 0x7f, 0x1a, 0x68, 0xd2, 0x92, 0x17, 0x6f, 0x32, 0x61, 0x9d, + 0x71, 0xa0, 0xa9, 0x40, 0xfd, 0x3f, 0x56, 0xf6, 0x99, 0x8e, 0xc9, 0xcc, 0x7f, 0x1c, 0x4e, 0x48, 0xd4, 0x7c, 0x4d, + 0x3e, 0x73, 0x9a, 0x7e, 0xe6, 0x8a, 0xf6, 0x1f, 0xc8, 0xcc, 0x0d, 0x87, 0x0c, 0xf5, 0x97, 0x8e, 0x79, 0x32, 0x7a, + 0x9d, 0x98, 0x1d, 0x09, 0x56, 0xcd, 0x20, 0x0a, 0x7b, 0x01, 0x0f, 0xea, 0x5a, 0x16, 0x4f, 0x61, 0xf6, 0x41, 0x8d, + 0x28, 0x0e, 0xd9, 0x78, 0x16, 0xca, 0x70, 0x02, 0xf6, 0xbd, 0x93, 0x31, 0xdc, 0x07, 0x64, 0xf8, 0xb1, 0x0a, 0xb1, + 0x73, 0x90, 0xf6, 0xb1, 0x42, 0xc5, 0x04, 0x40, 0x04, 0x42, 0xde, 0x7e, 0x5f, 0xaa, 0x24, 0x7c, 0x5d, 0x62, 0x4a, + 0xa1, 0x3e, 0xf8, 0x4f, 0xa4, 0xea, 0x8e, 0xe9, 0x57, 0xeb, 0xc7, 0x9f, 0x09, 0xc5, 0xa7, 0xbb, 0x94, 0xf8, 0x16, + 0x82, 0x3b, 0x4b, 0xd0, 0x41, 0x54, 0x68, 0xc6, 0xf6, 0x30, 0xbf, 0x2b, 0xee, 0xe7, 0x77, 0xc5, 0xff, 0x3b, 0x7e, + 0x57, 0x3c, 0xc4, 0x18, 0x56, 0x16, 0x1a, 0x7e, 0x16, 0x8c, 0x83, 0xe8, 0x3f, 0xe7, 0x13, 0xef, 0xe5, 0xa9, 0xaf, + 0x32, 0x31, 0xbd, 0x87, 0x69, 0xf6, 0x09, 0x0a, 0xc2, 0x2a, 0xee, 0xd2, 0x93, 0x75, 0x65, 0x6f, 0xad, 0x64, 0x88, + 0x79, 0x1e, 0x60, 0x8d, 0xc2, 0xca, 0x03, 0xba, 0x47, 0xd5, 0x06, 0x71, 0x22, 0x78, 0x18, 0x33, 0x2b, 0x7d, 0xdf, + 0x6e, 0x8d, 0x0a, 0xf3, 0x41, 0x2e, 0x0a, 0xb2, 0x9b, 0x8f, 0x67, 0xe3, 0x28, 0xc4, 0x06, 0xfc, 0xc7, 0x8c, 0x55, + 0x43, 0x36, 0xdf, 0xc9, 0x48, 0xed, 0x98, 0x3c, 0x4d, 0x76, 0x49, 0xef, 0x80, 0x77, 0xc8, 0xcf, 0xeb, 0x8f, 0x61, + 0x21, 0x0d, 0xbf, 0x25, 0x2f, 0xe3, 0x22, 0xab, 0x96, 0x57, 0x59, 0x82, 0x4c, 0x17, 0xbc, 0xf8, 0x62, 0xa6, 0xcb, + 0xfb, 0x58, 0x1f, 0x30, 0x9e, 0x52, 0xbc, 0x6e, 0x88, 0xd2, 0xd7, 0x2d, 0xcf, 0x0a, 0x75, 0x79, 0x52, 0x31, 0xdb, + 0xb3, 0x12, 0x9c, 0x4e, 0xc1, 0x04, 0x5f, 0xff, 0x74, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x0b, 0xb9, 0x32, + 0x58, 0x4e, 0x16, 0xba, 0x13, 0x30, 0x43, 0xa5, 0xc0, 0x0b, 0x14, 0xfc, 0x45, 0x03, 0x23, 0xfa, 0xca, 0xfd, 0x26, + 0x03, 0x83, 0x74, 0x69, 0x4e, 0x84, 0xb1, 0xe3, 0x76, 0x8a, 0xb4, 0x15, 0xe5, 0x8c, 0xb3, 0xf7, 0xea, 0x4a, 0x01, + 0x06, 0x78, 0x9b, 0x9b, 0xe8, 0x3c, 0x41, 0xaf, 0x05, 0xa5, 0xf3, 0x06, 0xee, 0x66, 0x19, 0x19, 0xe1, 0xe2, 0xe3, + 0xca, 0x63, 0xc1, 0x3d, 0xfb, 0x85, 0x58, 0x1a, 0xcd, 0x34, 0x18, 0xb3, 0x79, 0xc1, 0x02, 0x85, 0x0a, 0x14, 0x58, + 0xce, 0xb4, 0xa5, 0x69, 0x35, 0xe4, 0xfb, 0x07, 0x68, 0x6d, 0x5a, 0x0d, 0xf8, 0xfe, 0x41, 0x1d, 0x65, 0x87, 0x90, + 0xe5, 0xc8, 0xcf, 0xa0, 0x5e, 0xd7, 0x91, 0x49, 0x31, 0xd9, 0xfd, 0xfa, 0x52, 0x7f, 0x54, 0x37, 0xe0, 0xfa, 0x01, + 0x08, 0x60, 0x03, 0x70, 0x08, 0x54, 0x83, 0xa5, 0x11, 0xc1, 0xa2, 0x4c, 0xa1, 0x7d, 0x0d, 0xbd, 0x37, 0x1a, 0xfe, + 0x0b, 0xdc, 0x45, 0xe4, 0xca, 0xff, 0x04, 0x81, 0xbf, 0xa2, 0x4c, 0x2b, 0x53, 0xfc, 0x4f, 0xb4, 0x7a, 0x85, 0x72, + 0xd6, 0xb4, 0xe6, 0x83, 0x68, 0x4d, 0x84, 0x6a, 0xc6, 0x10, 0xfc, 0x5b, 0x59, 0xa6, 0x2d, 0x55, 0x95, 0xfa, 0xd0, + 0x78, 0xad, 0x15, 0xce, 0xf2, 0x71, 0xe4, 0xbd, 0xc6, 0xd0, 0xb1, 0x89, 0xb3, 0x94, 0x53, 0xa9, 0xb3, 0x4f, 0xfb, + 0x32, 0x72, 0x80, 0xd3, 0x09, 0x1b, 0x4f, 0x93, 0x43, 0x39, 0x4d, 0x1c, 0x64, 0x7e, 0xce, 0x30, 0xb2, 0xaa, 0x01, + 0x61, 0x51, 0x36, 0x94, 0xb6, 0x00, 0x93, 0x9c, 0x10, 0x32, 0xc5, 0x50, 0x14, 0xf9, 0x48, 0xf7, 0xc3, 0x7a, 0xb3, + 0xba, 0x2f, 0xde, 0x69, 0x80, 0xd3, 0x30, 0x81, 0x40, 0xe0, 0x45, 0x7c, 0x93, 0x89, 0x4b, 0xf0, 0x18, 0x1e, 0xc0, + 0x97, 0xe0, 0x26, 0x97, 0xb2, 0xdf, 0xab, 0x30, 0xc7, 0xb5, 0x05, 0x0c, 0x1a, 0xac, 0x1e, 0x44, 0x87, 0x4b, 0x69, + 0xb3, 0xab, 0x00, 0xb1, 0x31, 0x85, 0x58, 0x16, 0x6c, 0x6d, 0xd9, 0xb3, 0xef, 0x55, 0xd3, 0xd0, 0x3a, 0xe1, 0x58, + 0x5c, 0xe6, 0x10, 0x45, 0x65, 0x10, 0x83, 0x3b, 0x92, 0xc7, 0xe7, 0x3d, 0x12, 0xe1, 0x05, 0x01, 0xb7, 0xb2, 0x58, + 0x86, 0x2b, 0xba, 0x1c, 0xdd, 0xd2, 0xf5, 0xe8, 0x86, 0x8e, 0xe9, 0xe4, 0xef, 0x63, 0xb0, 0xc8, 0xd6, 0xa9, 0x77, + 0x74, 0x3d, 0x5a, 0xd2, 0x6f, 0xc7, 0xf4, 0xe0, 0x6f, 0x60, 0xc2, 0x87, 0x87, 0x09, 0xbd, 0x00, 0xc7, 0x2e, 0x52, + 0xa3, 0xa7, 0xa6, 0x6f, 0x70, 0x58, 0x8d, 0xf2, 0x21, 0x1f, 0xe5, 0x94, 0x8f, 0x8a, 0x61, 0x35, 0x02, 0x4f, 0xc7, + 0x6a, 0xc8, 0x47, 0x15, 0xe5, 0xa3, 0xf3, 0x61, 0x35, 0x3a, 0x27, 0xcd, 0xa6, 0xbf, 0xae, 0xf8, 0x55, 0xc9, 0x52, + 0xd8, 0x16, 0xb0, 0x7c, 0x3d, 0xaf, 0xa8, 0xd4, 0x5f, 0xd5, 0xe6, 0x64, 0xb6, 0x9c, 0xbd, 0xbd, 0xee, 0x72, 0x62, + 0xf1, 0xb8, 0x6d, 0x3a, 0x5c, 0x7d, 0x39, 0x51, 0x27, 0xbd, 0x42, 0x7e, 0x18, 0x4f, 0x85, 0x3a, 0x87, 0xc0, 0x4c, + 0x62, 0x16, 0xc6, 0x0c, 0x9b, 0xa9, 0xd3, 0x40, 0x81, 0x93, 0x8d, 0x3c, 0x17, 0xc5, 0x6c, 0x94, 0x53, 0x78, 0x1f, + 0x13, 0x12, 0x09, 0x38, 0xab, 0x8e, 0xaa, 0x51, 0x01, 0x31, 0x47, 0x58, 0x88, 0x8f, 0xd0, 0x2f, 0xf5, 0x91, 0x87, + 0x04, 0x9e, 0x61, 0x5f, 0x8b, 0x41, 0x0c, 0x47, 0xbc, 0xad, 0xac, 0x9a, 0x85, 0x09, 0x54, 0x56, 0x0d, 0x4b, 0x53, + 0x59, 0x41, 0xb3, 0x51, 0xe5, 0x57, 0x56, 0xe1, 0x18, 0x25, 0x84, 0x44, 0xa5, 0xae, 0x0c, 0xd4, 0x27, 0x09, 0x0b, + 0x4b, 0x5d, 0xd9, 0xb9, 0xfa, 0xe8, 0xdc, 0xaf, 0xec, 0x1c, 0x5c, 0x48, 0x07, 0x89, 0x7f, 0x95, 0xca, 0xd3, 0xf6, + 0x75, 0xb0, 0xb1, 0xaa, 0xe8, 0x86, 0xdf, 0x56, 0x45, 0x1c, 0x95, 0xd4, 0xc5, 0x80, 0xc6, 0x85, 0x11, 0x49, 0xaa, + 0xd7, 0x28, 0xf8, 0x43, 0x82, 0xa8, 0x34, 0x06, 0xaf, 0xce, 0xa4, 0x6b, 0xa5, 0x56, 0x54, 0x0c, 0xca, 0x41, 0x01, + 0xf7, 0xa7, 0xbc, 0xb5, 0x90, 0xbe, 0x87, 0x88, 0xca, 0x50, 0xde, 0xe0, 0x1f, 0x18, 0x3c, 0x99, 0xad, 0xd2, 0x30, + 0x19, 0xdd, 0xd1, 0x78, 0xb4, 0x44, 0x38, 0x18, 0xb6, 0x4e, 0x15, 0xde, 0xfa, 0x05, 0xa4, 0xdf, 0xd2, 0x78, 0x74, + 0x43, 0x53, 0x6b, 0x73, 0x6a, 0xa0, 0xae, 0x7a, 0x63, 0x7a, 0x1b, 0xc1, 0xeb, 0xbb, 0x68, 0x49, 0x61, 0x2b, 0x1d, + 0xe7, 0xd9, 0xa5, 0x88, 0x52, 0x8a, 0x08, 0x84, 0x6b, 0x44, 0x0e, 0x5c, 0x6a, 0xb4, 0xc1, 0xf5, 0x00, 0xca, 0xd0, + 0x70, 0x81, 0xcb, 0x41, 0x3c, 0x5a, 0x7a, 0x64, 0x6a, 0xa9, 0x2f, 0xb2, 0x08, 0x1f, 0xed, 0x6c, 0xb4, 0x14, 0xcf, + 0x88, 0x85, 0x71, 0x05, 0x43, 0xa8, 0x0b, 0x2b, 0x4d, 0x41, 0xd2, 0x05, 0x8e, 0xec, 0x85, 0x45, 0x15, 0x6e, 0xc0, + 0xb4, 0xe8, 0x0e, 0xcc, 0xa3, 0x40, 0xe1, 0xe0, 0x12, 0xa4, 0x9f, 0x50, 0xb6, 0x73, 0x94, 0x26, 0x87, 0x37, 0x41, + 0xe9, 0xce, 0x04, 0x21, 0xed, 0xea, 0x26, 0x5b, 0xd2, 0x37, 0xd8, 0xde, 0xa1, 0x53, 0x51, 0x41, 0xf5, 0xb9, 0x05, + 0x93, 0x25, 0x1b, 0x84, 0x2d, 0x61, 0x7a, 0xa6, 0xd7, 0x80, 0x3d, 0xbd, 0x7f, 0xb0, 0x33, 0xdf, 0xc5, 0xec, 0xd3, + 0x7e, 0x19, 0x8d, 0x95, 0x05, 0x6f, 0x6e, 0x89, 0xdd, 0x92, 0x8d, 0xa7, 0xcb, 0xc3, 0x72, 0xba, 0x44, 0x62, 0x67, + 0xe8, 0x16, 0xe3, 0xf3, 0xe5, 0x82, 0x26, 0x78, 0xb6, 0xb1, 0x6a, 0xbe, 0x34, 0x68, 0x29, 0x29, 0xc3, 0xf5, 0xb6, + 0x44, 0xff, 0x7f, 0x75, 0xf1, 0x4b, 0x01, 0x5e, 0x82, 0xb1, 0x00, 0x10, 0xee, 0xc1, 0xb4, 0x20, 0xb5, 0x51, 0x36, + 0x96, 0x69, 0x98, 0xe2, 0x22, 0x30, 0x29, 0xfd, 0x7e, 0x98, 0xb3, 0x94, 0x78, 0xd0, 0xa1, 0xee, 0xd4, 0x4e, 0x7d, + 0x21, 0x08, 0xf0, 0x48, 0xea, 0x1c, 0x9b, 0xfc, 0x7d, 0x3c, 0x0b, 0xd4, 0x40, 0x04, 0x51, 0x76, 0x88, 0x8f, 0x18, + 0xb8, 0x28, 0xd2, 0x71, 0x3b, 0x5d, 0x11, 0x17, 0xbb, 0xc7, 0x2c, 0xc4, 0x49, 0xc2, 0x5c, 0xb3, 0x6c, 0xc8, 0xaa, + 0x08, 0x13, 0x74, 0x61, 0x60, 0x96, 0x37, 0x64, 0xd5, 0xfe, 0x01, 0x44, 0x6a, 0xb5, 0x65, 0xac, 0xba, 0xca, 0xf8, + 0x16, 0x80, 0xac, 0x19, 0x63, 0x07, 0x7f, 0x1b, 0xcf, 0xd4, 0x37, 0x51, 0xc8, 0x8f, 0x0e, 0xfe, 0x06, 0xc9, 0x87, + 0xdf, 0x22, 0x33, 0x07, 0xc9, 0x8d, 0x82, 0x2e, 0x9b, 0xb3, 0xae, 0xa1, 0x34, 0x71, 0xed, 0x95, 0x7a, 0xed, 0x49, + 0xb3, 0xf6, 0x0a, 0x74, 0xa7, 0x36, 0xbc, 0x87, 0xb2, 0x9d, 0x05, 0x13, 0x74, 0x34, 0xbb, 0x03, 0x1d, 0xbc, 0x53, + 0x04, 0xbd, 0x4c, 0x42, 0xe3, 0x11, 0xaa, 0x8c, 0x7a, 0x61, 0x47, 0x76, 0xb3, 0x2e, 0x99, 0x67, 0xc0, 0x1c, 0xdb, + 0x73, 0x48, 0x0c, 0x73, 0x75, 0x50, 0xa7, 0xac, 0x1c, 0xe6, 0x78, 0x00, 0xaf, 0x99, 0x1c, 0x8a, 0x41, 0xae, 0x51, + 0xbe, 0x2f, 0x58, 0x31, 0x2c, 0x07, 0xb9, 0xe6, 0x66, 0xa6, 0xcd, 0xd8, 0xb4, 0x89, 0x0e, 0xcf, 0xbc, 0x62, 0x47, + 0xab, 0x1e, 0xf0, 0xb1, 0xe0, 0xc9, 0xec, 0x7b, 0x3e, 0xbe, 0x01, 0x4e, 0x66, 0x73, 0x1b, 0x2d, 0xe9, 0x5d, 0x94, + 0xd2, 0x9b, 0x68, 0x4d, 0x97, 0xd1, 0x85, 0x31, 0x31, 0x4e, 0x6a, 0x38, 0x07, 0xa0, 0x55, 0x00, 0x89, 0xa7, 0x7e, + 0xbd, 0xe7, 0x49, 0x15, 0x2e, 0x69, 0x0a, 0x6e, 0xc3, 0xbe, 0x7d, 0xe6, 0x95, 0x2f, 0x91, 0xda, 0x20, 0xc6, 0x9a, + 0x35, 0x54, 0xdc, 0x78, 0xeb, 0x3e, 0x12, 0x35, 0xec, 0x5c, 0x17, 0x9b, 0xa8, 0x1a, 0x4e, 0xa6, 0x25, 0x20, 0xb6, + 0x96, 0xc3, 0xa1, 0x3b, 0x42, 0x76, 0x8f, 0x1f, 0x1d, 0xe8, 0xb9, 0x27, 0x2d, 0xb6, 0x6d, 0xcb, 0x1f, 0x18, 0xc2, + 0x94, 0x7e, 0xfe, 0xc8, 0x07, 0xc4, 0x8a, 0x4b, 0x38, 0x1b, 0x81, 0x3a, 0x5a, 0xa1, 0xd3, 0xef, 0x55, 0x58, 0xe8, + 0x03, 0x7c, 0x73, 0x1b, 0x25, 0xf4, 0x2e, 0xca, 0x3d, 0xb2, 0xb6, 0xac, 0x99, 0x9c, 0x9e, 0x65, 0x21, 0x6f, 0x1f, + 0xe8, 0xe5, 0x02, 0x40, 0xb4, 0x06, 0xb1, 0x2f, 0x75, 0x3d, 0x00, 0xa7, 0x21, 0x34, 0x09, 0x8d, 0xe0, 0xaa, 0x82, + 0x30, 0x02, 0xae, 0x24, 0xfc, 0x0d, 0x26, 0x2a, 0xf0, 0x05, 0xb8, 0xc8, 0xa4, 0x69, 0xce, 0x83, 0xda, 0x1f, 0xc9, + 0xd3, 0xa2, 0xed, 0xed, 0x0a, 0xa3, 0x09, 0xc6, 0x9e, 0x68, 0x9f, 0x47, 0xca, 0x51, 0x5c, 0x24, 0x61, 0x36, 0xba, + 0x55, 0xe7, 0x39, 0xcd, 0x46, 0x77, 0xfa, 0x57, 0x45, 0xc7, 0xf4, 0x3b, 0x1d, 0xd0, 0x46, 0x49, 0xdf, 0x3a, 0xce, + 0x06, 0xb4, 0x5e, 0x2c, 0x8d, 0xff, 0xb5, 0x1c, 0xdd, 0x52, 0x39, 0xba, 0xf3, 0x2d, 0xa9, 0x26, 0xd3, 0xe2, 0x50, + 0xa0, 0x21, 0x55, 0xe7, 0xf7, 0x05, 0xf0, 0x73, 0xa5, 0xf1, 0x9d, 0x36, 0xdf, 0x7b, 0xed, 0x3f, 0xef, 0xe4, 0x09, + 0x14, 0x4b, 0x54, 0xb0, 0x6a, 0x04, 0x76, 0xec, 0xeb, 0x3c, 0x2e, 0xcc, 0x28, 0xc5, 0xd4, 0x9a, 0xf4, 0x63, 0xe0, + 0x8a, 0x69, 0xaf, 0x00, 0x57, 0xcb, 0xed, 0x56, 0xc5, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, + 0x36, 0xdc, 0x03, 0x62, 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, + 0x9d, 0xc7, 0x43, 0x9f, 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, + 0x3c, 0xd7, 0x5f, 0x69, 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, + 0x6e, 0x94, 0x79, 0x24, 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, + 0x3d, 0xf2, 0xa0, 0x9c, 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, + 0x12, 0x73, 0x27, 0x51, 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, + 0x13, 0x57, 0xe1, 0x5a, 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, + 0x1a, 0x56, 0x9a, 0x80, 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, + 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, + 0x02, 0x33, 0x57, 0x72, 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, + 0x5a, 0x62, 0x42, 0xb4, 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, + 0xda, 0x55, 0x20, 0xb4, 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, + 0xb2, 0x69, 0xc8, 0x5c, 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, + 0x2d, 0x3f, 0x82, 0x17, 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, + 0xb9, 0xdd, 0x96, 0x68, 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, + 0x2b, 0xd0, 0xf7, 0xf8, 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, + 0xfc, 0x4a, 0x76, 0xd6, 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, + 0x2d, 0x85, 0x05, 0xc7, 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, + 0xb2, 0x33, 0xd7, 0x07, 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, + 0xe1, 0xce, 0x3c, 0x6a, 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, + 0xf7, 0x7d, 0x58, 0x3d, 0xe6, 0x83, 0x5f, 0x70, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, + 0x53, 0xbe, 0xd0, 0xad, 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, + 0x18, 0xd7, 0xc0, 0x6d, 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, + 0x31, 0xf7, 0xa5, 0x6b, 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, + 0xe7, 0x91, 0xf9, 0x62, 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, + 0x43, 0x2f, 0x03, 0x17, 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, + 0xa8, 0x10, 0xac, 0xeb, 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x63, 0x20, + 0x9c, 0x5b, 0xa2, 0x67, 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, + 0x5f, 0xf0, 0x5a, 0x0a, 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, + 0x8a, 0xde, 0xbf, 0xe6, 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, + 0x4a, 0x50, 0xc9, 0x5a, 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, + 0x7c, 0x8e, 0x7e, 0x98, 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, + 0xc6, 0xf0, 0x60, 0x36, 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, + 0x7d, 0x89, 0x36, 0xaf, 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, + 0xab, 0x96, 0x8a, 0x06, 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, + 0x59, 0xda, 0xa6, 0xe8, 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, + 0x51, 0x6a, 0x37, 0x48, 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, + 0x1d, 0x47, 0x43, 0xbf, 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, + 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, + 0x4d, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, + 0xe9, 0xb9, 0x6e, 0xe7, 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, + 0xf5, 0x98, 0x15, 0xc3, 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, + 0xb4, 0x0b, 0xa4, 0x6d, 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, + 0xd8, 0x88, 0x7a, 0x7c, 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, + 0x5a, 0xb5, 0xb9, 0xfb, 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, + 0x5a, 0xb0, 0x9c, 0x75, 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, + 0x92, 0x67, 0x9a, 0xfe, 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, + 0x12, 0x57, 0xbe, 0xc2, 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, + 0x6e, 0x92, 0x1b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, + 0x28, 0x73, 0x13, 0x73, 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, + 0x3a, 0xd1, 0x5c, 0x86, 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, + 0xdc, 0xcc, 0x52, 0xb3, 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, + 0x2c, 0x0d, 0xd7, 0x28, 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, + 0x90, 0x8d, 0xd2, 0x38, 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, + 0x15, 0xdd, 0x96, 0x98, 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0xc5, 0xd0, 0xde, 0x1d, + 0x81, 0x51, 0xe5, 0x04, 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, + 0x24, 0x10, 0x18, 0x15, 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, + 0xb7, 0x88, 0x8e, 0xe9, 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, + 0x9e, 0xba, 0x14, 0xfd, 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, + 0xb2, 0x2a, 0x07, 0xed, 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, + 0x6f, 0xc4, 0xa8, 0xbd, 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, + 0x9f, 0x39, 0xb2, 0x33, 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, + 0xda, 0xcf, 0x9d, 0xe9, 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, + 0x35, 0xd5, 0xd1, 0x01, 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, + 0x53, 0x5b, 0x55, 0xc1, 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, + 0xa7, 0xa6, 0x3f, 0x68, 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, + 0x57, 0x95, 0x0f, 0xa0, 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, + 0x58, 0x4f, 0xe4, 0x79, 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, + 0x68, 0x2e, 0xa3, 0x09, 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, + 0x15, 0xdf, 0xc9, 0xf4, 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, + 0x73, 0xf0, 0xb4, 0xa6, 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, + 0xf9, 0x47, 0x97, 0x69, 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, + 0xa2, 0x0e, 0xbe, 0x39, 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, + 0x71, 0x7f, 0xfb, 0xfb, 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, + 0x7f, 0xab, 0x6b, 0xfa, 0x2b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, + 0x06, 0x90, 0x4b, 0xab, 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, + 0xe3, 0xac, 0x02, 0x38, 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x07, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, + 0x46, 0x45, 0x06, 0x3a, 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, + 0xc1, 0x44, 0x58, 0x10, 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, + 0x10, 0x44, 0x77, 0x91, 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, + 0x10, 0x14, 0xff, 0x86, 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, + 0x82, 0x06, 0xba, 0xed, 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, + 0xf5, 0x5f, 0x0d, 0xeb, 0xe8, 0xc2, 0x8f, 0xfe, 0x6a, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, + 0x0c, 0xa4, 0x8b, 0xe3, 0x76, 0x9c, 0xcd, 0x7f, 0x9d, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, + 0xd2, 0xce, 0x07, 0x6f, 0x8e, 0x7f, 0x3f, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, + 0x0a, 0xee, 0xae, 0xe6, 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, + 0x40, 0x0e, 0x99, 0x85, 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, + 0x6f, 0xb9, 0x0d, 0xb2, 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, + 0xce, 0xe6, 0xc5, 0xc2, 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, + 0xa6, 0x51, 0x85, 0x6b, 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, + 0x03, 0x3a, 0x98, 0x50, 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x75, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, + 0x54, 0x5e, 0xc9, 0x6b, 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, + 0x93, 0x4b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, + 0x7c, 0x2e, 0x16, 0x11, 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, + 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, + 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, + 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, + 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, + 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, + 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, + 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, + 0xb3, 0x5c, 0x1d, 0x7a, 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, + 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, 0x42, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, + 0x91, 0x9e, 0x67, 0x9f, 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, + 0x3f, 0x57, 0x1c, 0xaf, 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, + 0x97, 0x3c, 0xac, 0x46, 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, + 0xff, 0x0a, 0x99, 0x8c, 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, + 0x93, 0x66, 0xa1, 0x4c, 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, + 0xf7, 0xd0, 0xe1, 0xff, 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, + 0x7d, 0x33, 0xf1, 0x0b, 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, + 0xc3, 0x76, 0x8b, 0x0b, 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, + 0x67, 0x6a, 0x98, 0x93, 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, + 0xd0, 0x5e, 0xec, 0x67, 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, + 0x1e, 0x83, 0xf7, 0x06, 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, + 0xb7, 0x95, 0xf1, 0xb7, 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, + 0x5a, 0x60, 0xf8, 0xec, 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, + 0xac, 0x01, 0x88, 0xe4, 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, + 0xeb, 0x60, 0xe2, 0x4c, 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, + 0xa9, 0x42, 0xa9, 0x36, 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, + 0x67, 0xf7, 0xb9, 0xed, 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, + 0x15, 0x63, 0x8c, 0xde, 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, + 0xc5, 0xf5, 0xf2, 0x4b, 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, + 0x5d, 0x69, 0x64, 0x20, 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, + 0x6d, 0x09, 0x1d, 0xb2, 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, + 0x0b, 0x67, 0x59, 0x1c, 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, + 0x81, 0xdd, 0xc9, 0xe9, 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, + 0x42, 0x9b, 0xeb, 0xfa, 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, + 0xfa, 0x40, 0x39, 0x96, 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, + 0xb1, 0x00, 0x58, 0xe8, 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, + 0xee, 0x8a, 0x65, 0x58, 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, + 0x6a, 0x0c, 0x20, 0x72, 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, + 0x5e, 0x4f, 0x4a, 0x02, 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, + 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, + 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, + 0xfb, 0xbf, 0x99, 0x2c, 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, + 0x82, 0xc0, 0x70, 0xc3, 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, + 0x1a, 0x33, 0x3a, 0x78, 0x06, 0xa0, 0xb0, 0x10, 0x10, 0x7d, 0x0c, 0x32, 0x5a, 0x01, 0xbf, 0x85, 0xfa, 0xdd, 0x3a, + 0xf1, 0x7d, 0xe8, 0x57, 0x41, 0x2f, 0x62, 0x60, 0x38, 0xa2, 0xc9, 0x7e, 0xc8, 0x07, 0x93, 0x01, 0x68, 0x4b, 0xbc, + 0xdd, 0xd7, 0xd2, 0x8a, 0x9b, 0xd3, 0xa5, 0xd3, 0xfd, 0x93, 0x36, 0x41, 0x12, 0xa9, 0x64, 0xa5, 0x22, 0x06, 0x10, + 0xca, 0x52, 0x6d, 0x93, 0x25, 0x58, 0x56, 0x98, 0x25, 0xcd, 0x0d, 0x4a, 0xe2, 0xee, 0x66, 0xe0, 0x18, 0x35, 0xeb, + 0x38, 0x2c, 0x5b, 0x6e, 0xd4, 0x00, 0x9f, 0x93, 0xb0, 0xc2, 0xde, 0x70, 0x66, 0xd2, 0x3b, 0xd3, 0xe1, 0xea, 0x98, + 0xb3, 0x37, 0x1c, 0xc1, 0x38, 0x12, 0xbc, 0xf1, 0xd0, 0x25, 0xd3, 0x50, 0x91, 0x29, 0xe3, 0x60, 0xda, 0x03, 0xdc, + 0x7b, 0x0e, 0xc6, 0x61, 0x6c, 0x50, 0x59, 0x52, 0x9f, 0x7a, 0x77, 0x21, 0x10, 0xa4, 0xb5, 0x5e, 0xe6, 0x33, 0x3c, + 0x3d, 0x23, 0x94, 0xfd, 0x21, 0x87, 0x2f, 0xc0, 0x8e, 0x82, 0x1c, 0x4d, 0xf8, 0xb3, 0xc7, 0xbb, 0x81, 0xaa, 0xf8, + 0x20, 0xd8, 0x8b, 0x45, 0xba, 0x17, 0x0c, 0x04, 0xfc, 0x2a, 0xf8, 0x5e, 0x25, 0xe5, 0xde, 0x45, 0x5c, 0xec, 0xc5, + 0xab, 0xb8, 0xa8, 0xf6, 0x6e, 0xb2, 0x6a, 0xb9, 0x67, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x7b, 0xc1, + 0xa0, 0x30, 0x53, 0xbb, 0x62, 0x65, 0xe3, 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, + 0xea, 0x9a, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, 0x88, 0xe9, 0x1a, 0xfa, 0x00, 0x3c, 0xf2, 0x9a, 0xc6, 0xb0, 0x04, 0x2e, + 0x06, 0x03, 0xb2, 0x86, 0xc8, 0x05, 0x6b, 0x6a, 0x83, 0x38, 0x84, 0x6b, 0x65, 0xa7, 0xbd, 0x0b, 0xcc, 0xb4, 0xdd, + 0x02, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, 0x1b, 0xea, 0x5f, 0xb0, 0x97, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, + 0xe6, 0xfb, 0x92, 0x1d, 0x0d, 0x54, 0xc4, 0xe1, 0x1d, 0x47, 0x8a, 0x36, 0x2a, 0x97, 0x65, 0x4f, 0x96, 0x0d, 0x5f, + 0x89, 0x2b, 0xee, 0xfc, 0xb8, 0x2a, 0x29, 0xf3, 0x2a, 0x5b, 0x29, 0xf6, 0x6f, 0xc6, 0x35, 0xf7, 0x07, 0xd6, 0x9f, + 0xcd, 0x57, 0x70, 0x6d, 0xf5, 0xde, 0x35, 0xb9, 0x46, 0xe4, 0x2c, 0xa1, 0x5c, 0x52, 0xdb, 0x3c, 0xbc, 0xa5, 0xef, + 0xf3, 0xab, 0x6f, 0x33, 0x9d, 0xc6, 0x67, 0x15, 0x16, 0x2e, 0x44, 0x2b, 0x82, 0x43, 0x43, 0x2e, 0x9a, 0x47, 0x80, + 0xb9, 0xf6, 0xd9, 0x0a, 0x0a, 0x52, 0x9f, 0x55, 0xe8, 0xdd, 0x0a, 0x09, 0xaf, 0x34, 0xbb, 0xf4, 0x30, 0x90, 0x32, + 0x6e, 0x0f, 0x2d, 0x61, 0xd2, 0xf2, 0x22, 0xbc, 0xf7, 0x9a, 0x9b, 0xdc, 0x8b, 0x10, 0xa3, 0x17, 0x79, 0x76, 0x02, + 0xc6, 0xba, 0x4b, 0x76, 0x36, 0x3c, 0xf1, 0x1b, 0x9e, 0xb3, 0x16, 0x8d, 0xa6, 0x4b, 0x96, 0xf4, 0xfb, 0x31, 0x98, + 0x78, 0xa7, 0x2c, 0x87, 0x5f, 0xf9, 0x82, 0xae, 0x19, 0x60, 0x8a, 0xd1, 0x0b, 0x48, 0x48, 0x11, 0x89, 0x64, 0xad, + 0x4e, 0x92, 0xcf, 0x74, 0x17, 0x80, 0xd1, 0x2f, 0x66, 0x69, 0xb4, 0xbc, 0xd7, 0xcc, 0x02, 0xc9, 0x33, 0xf4, 0x5d, + 0x07, 0xdb, 0x1b, 0xfb, 0x20, 0xe5, 0xfc, 0x50, 0x4c, 0x07, 0x03, 0x4e, 0x34, 0xdc, 0x78, 0xa9, 0xc4, 0xb5, 0xba, + 0xc5, 0x1d, 0xc3, 0x58, 0xea, 0xdb, 0x22, 0x06, 0x07, 0xec, 0xa2, 0x95, 0xdd, 0x3e, 0xc0, 0xbe, 0x72, 0xbc, 0x4b, + 0x95, 0xdd, 0xe9, 0x31, 0xd3, 0x5c, 0xb6, 0x9a, 0x74, 0x52, 0x71, 0x3f, 0x91, 0x6f, 0x72, 0x07, 0x5d, 0x2e, 0xc7, + 0x9a, 0xb7, 0x1c, 0x80, 0x8a, 0x7e, 0xa4, 0xa8, 0xee, 0x17, 0x38, 0xc2, 0x3c, 0x58, 0xb7, 0xf9, 0x64, 0xdf, 0x14, + 0x38, 0x44, 0x9e, 0xb4, 0xd1, 0x14, 0xd0, 0xbd, 0x8b, 0xc7, 0x5d, 0xfd, 0xb6, 0x74, 0x17, 0x28, 0xd1, 0x4e, 0xc5, + 0x0d, 0x3f, 0x26, 0xea, 0x74, 0xa6, 0x0d, 0xa1, 0x7f, 0x65, 0xc4, 0xfd, 0xa5, 0x71, 0x15, 0x6f, 0x7a, 0x97, 0xcf, + 0x38, 0xd4, 0xd9, 0x0d, 0xa1, 0x00, 0x5c, 0xb5, 0xa7, 0x53, 0x37, 0x86, 0xf4, 0x4a, 0x89, 0x6e, 0x83, 0x83, 0xdd, + 0xeb, 0x33, 0x8e, 0xa2, 0x1f, 0xa3, 0x46, 0xbe, 0x89, 0xc4, 0x63, 0x39, 0x88, 0x1f, 0x17, 0x74, 0x19, 0x89, 0xc7, + 0xc5, 0x20, 0x7e, 0x2c, 0xeb, 0x7a, 0xf7, 0x5c, 0xb9, 0xbf, 0x8f, 0xc8, 0xb3, 0xee, 0xec, 0xa5, 0x12, 0x36, 0x06, + 0x9e, 0x5d, 0x0b, 0x08, 0xa7, 0xe0, 0x89, 0x6c, 0x2d, 0x7d, 0xe8, 0xdc, 0xee, 0x63, 0xcb, 0x24, 0x41, 0xd0, 0xf3, + 0x36, 0x9b, 0x44, 0xb1, 0xb3, 0xcd, 0xa3, 0x0f, 0xa7, 0x40, 0x42, 0xb7, 0xdb, 0x66, 0x5d, 0xad, 0x01, 0xc5, 0x34, + 0x1c, 0xf3, 0xfd, 0x62, 0x74, 0xe3, 0xbb, 0xeb, 0xef, 0x17, 0xa3, 0x25, 0x19, 0x4e, 0xcc, 0xe4, 0xc7, 0x47, 0xe3, + 0x59, 0x1c, 0x4d, 0xea, 0x8e, 0xd3, 0x42, 0xe3, 0x9f, 0x7a, 0xb7, 0x50, 0x04, 0x4e, 0xc5, 0x08, 0x8e, 0x9c, 0x0a, + 0xe5, 0xa4, 0xd4, 0xc0, 0xf0, 0xdf, 0xab, 0x76, 0xb4, 0x69, 0x6f, 0xe2, 0x2a, 0x59, 0x66, 0xe2, 0x52, 0x87, 0x0f, + 0xd7, 0xd1, 0xc5, 0x6d, 0x40, 0x3b, 0xef, 0x32, 0xed, 0xf8, 0x75, 0xd2, 0xa0, 0x27, 0xae, 0x66, 0x06, 0xdc, 0xba, + 0x1f, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, 0xc4, 0xdc, 0xfe, 0x4d, 0xd9, 0xfc, 0x2a, 0xda, 0xe7, 0xc8, 0x48, + 0xd9, 0x26, 0x23, 0x15, 0x18, 0x61, 0x4a, 0x91, 0xc4, 0x55, 0x08, 0x81, 0xec, 0xbf, 0xa4, 0xb8, 0x16, 0x4b, 0xef, + 0x35, 0x08, 0x13, 0x6c, 0x17, 0xb4, 0x5f, 0xdd, 0xce, 0x6d, 0xa5, 0xc5, 0x1e, 0xa9, 0xef, 0x73, 0x67, 0xbb, 0xa2, + 0xc9, 0xdf, 0x97, 0x0d, 0x68, 0x03, 0x88, 0xf2, 0xbe, 0x3e, 0x2a, 0x81, 0x93, 0x11, 0x37, 0x94, 0x18, 0xbd, 0xa0, + 0xab, 0x13, 0xb9, 0x67, 0xa7, 0xe6, 0x4d, 0xc5, 0x4c, 0xc5, 0x95, 0x6f, 0xf6, 0xcc, 0x7f, 0x30, 0x14, 0x54, 0x80, + 0x81, 0xb7, 0x39, 0xe3, 0xd1, 0x81, 0xee, 0xc6, 0xe8, 0xb4, 0x60, 0xb3, 0xa0, 0x2e, 0xeb, 0xa6, 0x8d, 0x07, 0x8d, + 0x38, 0x28, 0x8a, 0x55, 0xa1, 0x46, 0xc2, 0x13, 0x81, 0x80, 0x29, 0xbb, 0xe2, 0x91, 0x11, 0xd4, 0xf4, 0x26, 0x14, + 0x36, 0x14, 0xfc, 0x55, 0xa2, 0x9a, 0xde, 0x84, 0x36, 0x99, 0x38, 0xcd, 0x20, 0x82, 0x19, 0xb1, 0xdd, 0x6f, 0x01, + 0x6d, 0x6e, 0xcd, 0x68, 0x53, 0xd7, 0x56, 0x5b, 0x85, 0x5c, 0x52, 0xa4, 0x2c, 0xff, 0x9d, 0x9a, 0x0a, 0x4a, 0x6a, + 0xb9, 0xe8, 0x4d, 0x9a, 0x2e, 0x7a, 0x3c, 0x33, 0x92, 0x40, 0xe5, 0x96, 0x3b, 0x46, 0x7f, 0x08, 0x0b, 0x3c, 0x62, + 0xe2, 0xc4, 0x82, 0xb9, 0xd5, 0x11, 0xcb, 0xe6, 0x62, 0x31, 0x5a, 0x49, 0x08, 0x1b, 0x7c, 0xc8, 0xb2, 0x79, 0xa9, + 0x1f, 0x42, 0x5f, 0x58, 0x7a, 0x02, 0x76, 0xb1, 0xc1, 0x4a, 0x96, 0x01, 0xf8, 0x5e, 0xd0, 0xcd, 0x4a, 0x96, 0x91, + 0x54, 0xdd, 0x8f, 0x6b, 0x2c, 0x41, 0xa5, 0x15, 0x2a, 0x2d, 0xa9, 0xb1, 0x20, 0xf0, 0x55, 0xd5, 0xe5, 0x43, 0xb2, + 0xab, 0x40, 0x3d, 0x75, 0xd4, 0x80, 0x53, 0xa0, 0xaa, 0xc0, 0x82, 0x24, 0xa8, 0x0c, 0x5d, 0x15, 0x98, 0x56, 0x60, + 0x9a, 0xa9, 0xc2, 0x45, 0x99, 0x1d, 0x4a, 0xb3, 0x5e, 0xf2, 0x59, 0x3c, 0x08, 0x93, 0x61, 0x4c, 0x1e, 0x23, 0xd4, + 0xfe, 0x7e, 0x1e, 0xc5, 0x5a, 0x2e, 0xb9, 0x72, 0x7e, 0xf1, 0x37, 0x9f, 0xb1, 0xd7, 0x3d, 0xc3, 0x60, 0x01, 0xce, + 0xd2, 0xf6, 0x2a, 0x13, 0xef, 0x64, 0x2b, 0x38, 0x0e, 0x66, 0x51, 0x0e, 0xab, 0x9e, 0x1c, 0xd1, 0x5c, 0xe4, 0xda, + 0xbb, 0x08, 0x91, 0x83, 0xcc, 0x1e, 0x03, 0xec, 0x46, 0xf8, 0x3a, 0xb4, 0x36, 0xb7, 0xba, 0x42, 0xfc, 0x8d, 0x12, + 0x89, 0x9f, 0xa5, 0xfc, 0xb8, 0x5e, 0xa9, 0x5c, 0x95, 0xc1, 0x63, 0xd5, 0xcd, 0xe0, 0x99, 0xf6, 0x3d, 0xd6, 0xfe, + 0xad, 0xed, 0xe6, 0x78, 0xef, 0xc1, 0x83, 0xd6, 0xff, 0xd6, 0x93, 0x10, 0xda, 0x2b, 0x27, 0xa9, 0x3b, 0x6a, 0xf4, + 0xcc, 0x64, 0x8d, 0xa8, 0x84, 0xa9, 0xdd, 0xa9, 0x1c, 0x03, 0x35, 0x1d, 0xc0, 0xb5, 0x44, 0x4d, 0xd0, 0x93, 0x82, + 0x8d, 0xe1, 0x88, 0xb3, 0x38, 0x68, 0x87, 0x31, 0x8a, 0x97, 0x73, 0x25, 0x5e, 0xce, 0x8f, 0x18, 0x07, 0x68, 0x2d, + 0x40, 0xaa, 0xd7, 0xb0, 0x9f, 0xb9, 0x82, 0x05, 0x36, 0x77, 0xbe, 0x03, 0x0b, 0x64, 0x88, 0x93, 0xcd, 0x71, 0xb2, + 0xc7, 0xb5, 0x9e, 0x7b, 0x81, 0x8f, 0x93, 0x7a, 0xe1, 0xd5, 0x55, 0xb6, 0xeb, 0x5a, 0xb2, 0x72, 0x5e, 0x0c, 0x26, + 0x10, 0x94, 0xa5, 0x9c, 0x17, 0xc3, 0xc9, 0x82, 0xe6, 0xf0, 0x63, 0xd1, 0x40, 0x87, 0x58, 0x0e, 0x12, 0xb8, 0x74, + 0xf6, 0x18, 0xf0, 0x86, 0x52, 0x8b, 0xbb, 0xb1, 0x8e, 0x1c, 0xeb, 0x28, 0xf6, 0xc3, 0x18, 0x70, 0x65, 0x9d, 0xc0, + 0xfb, 0xfe, 0xeb, 0x63, 0x13, 0x90, 0x55, 0xbb, 0xc2, 0xab, 0x51, 0xee, 0xba, 0xd2, 0xe8, 0x4b, 0x4a, 0x4f, 0x78, + 0xc1, 0x53, 0xc9, 0x76, 0xdb, 0x33, 0x70, 0xb6, 0xc4, 0x43, 0xe2, 0x1d, 0x23, 0x7a, 0x31, 0x6d, 0x64, 0xe6, 0x04, + 0xce, 0x6c, 0x77, 0xd9, 0xc6, 0xfc, 0xd8, 0x01, 0x0e, 0x16, 0x41, 0x48, 0xdc, 0x10, 0x86, 0x89, 0x1d, 0x95, 0x43, + 0x2d, 0x84, 0xeb, 0x5a, 0x78, 0x1d, 0xa7, 0x65, 0x0c, 0x2e, 0xd2, 0xda, 0x36, 0xf1, 0x1e, 0xba, 0xee, 0xf9, 0x31, + 0xb7, 0x3a, 0x46, 0x5b, 0x48, 0xbf, 0x1d, 0x9d, 0xde, 0x73, 0x18, 0x80, 0xa6, 0x07, 0xb3, 0xaa, 0x7d, 0x26, 0x71, + 0x73, 0xda, 0x09, 0x42, 0x22, 0x10, 0x45, 0xe9, 0x8c, 0x30, 0xfd, 0x3b, 0xcd, 0x65, 0x15, 0xad, 0x1e, 0xe4, 0x99, + 0x43, 0x9e, 0x85, 0xde, 0xf6, 0xa0, 0x55, 0x73, 0x37, 0x18, 0x27, 0x6e, 0xb7, 0x77, 0xfe, 0xdf, 0xb2, 0xae, 0xad, + 0xd6, 0x88, 0xc7, 0xed, 0xea, 0x07, 0x8d, 0xbd, 0xda, 0x53, 0x31, 0x60, 0x56, 0xd2, 0x3b, 0xa3, 0x4a, 0x5e, 0x64, + 0xbc, 0xc4, 0x93, 0x6a, 0xd5, 0xf0, 0xf1, 0xbe, 0xc9, 0x46, 0xe6, 0x81, 0x4c, 0x01, 0xf1, 0xfc, 0x26, 0x35, 0xea, + 0xe3, 0x14, 0x25, 0xe0, 0xef, 0x74, 0x7c, 0x23, 0xfa, 0xd1, 0xbe, 0xb8, 0xe4, 0xd5, 0xc9, 0x8d, 0x30, 0x2f, 0x5e, + 0x58, 0x9d, 0x3f, 0x7d, 0x53, 0xf8, 0xd0, 0xe1, 0xa8, 0xbd, 0x83, 0x22, 0x4b, 0x26, 0x8e, 0x26, 0x46, 0xd6, 0x26, + 0x66, 0x1f, 0x15, 0x5c, 0x4c, 0x54, 0xa1, 0x67, 0x9d, 0x3d, 0x61, 0x0a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x16, + 0x0c, 0xd4, 0x69, 0x4a, 0x88, 0x1e, 0x8a, 0x19, 0xc6, 0x2b, 0x06, 0x50, 0x98, 0x42, 0x81, 0x28, 0x3a, 0xfb, 0x70, + 0xa0, 0x09, 0xfd, 0xfe, 0x4d, 0xaa, 0x33, 0xd0, 0xb2, 0x9e, 0x4a, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, + 0x2e, 0x69, 0x99, 0xd1, 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, + 0x21, 0xec, 0xff, 0x6a, 0xd0, 0xf5, 0x56, 0xac, 0x35, 0xb4, 0x3b, 0x41, 0x46, 0x68, 0xbe, 0xd0, 0x41, 0xc8, 0x50, + 0x39, 0x09, 0x5d, 0xab, 0x34, 0x5e, 0x81, 0x4b, 0xa6, 0xd9, 0x68, 0x19, 0x97, 0x61, 0x60, 0xbf, 0x0a, 0x2c, 0x26, + 0x07, 0x26, 0x9d, 0xae, 0xcf, 0x9f, 0xcb, 0xab, 0x95, 0x14, 0x5c, 0x54, 0x0a, 0xa2, 0xdf, 0xe0, 0xbe, 0x9b, 0xb8, + 0xea, 0xac, 0x59, 0x2b, 0x7d, 0xe8, 0x5b, 0x9f, 0xb5, 0x71, 0x5f, 0x18, 0x1c, 0x83, 0x9d, 0x8f, 0x88, 0x81, 0x34, + 0xa8, 0x74, 0x8b, 0x43, 0x13, 0xa0, 0x4b, 0x87, 0x14, 0xb2, 0x64, 0x2a, 0x53, 0x25, 0xa8, 0xf8, 0xc6, 0xef, 0xa5, + 0xac, 0x46, 0x7f, 0xad, 0x79, 0x71, 0x77, 0xca, 0x73, 0x8e, 0x63, 0x14, 0x24, 0xb1, 0xb8, 0x8e, 0xcb, 0x80, 0xf8, + 0x96, 0x57, 0xc1, 0x41, 0x6a, 0xc2, 0xc6, 0xec, 0x54, 0x8d, 0x5a, 0x2f, 0x89, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, + 0x13, 0x51, 0x05, 0x7d, 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, + 0x6e, 0x98, 0x08, 0x41, 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, + 0xf1, 0x39, 0x73, 0xa1, 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, + 0xd9, 0x91, 0x76, 0x69, 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, + 0x2a, 0xce, 0xc4, 0x71, 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, + 0x61, 0x30, 0x35, 0x15, 0xf7, 0xd8, 0x19, 0x5c, 0x54, 0x7f, 0x44, 0x4b, 0x89, 0xb1, 0x50, 0x75, 0xf1, 0xf1, 0x79, + 0x29, 0xf3, 0x75, 0x05, 0xda, 0xdd, 0x8b, 0x2a, 0x3a, 0x78, 0xba, 0xba, 0x9d, 0xaa, 0x1b, 0x4c, 0xf4, 0xf4, 0x60, + 0x75, 0xdb, 0xcb, 0xae, 0x56, 0xb2, 0xa8, 0x62, 0x51, 0x4d, 0x15, 0x22, 0x59, 0x12, 0xe7, 0x49, 0x38, 0x19, 0x8f, + 0xbf, 0xda, 0x1b, 0xee, 0x41, 0x06, 0x32, 0xfd, 0x34, 0x54, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x95, 0xea, 0x6e, + 0x17, 0x8d, 0x26, 0x35, 0xd6, 0x33, 0x4c, 0xf4, 0xcc, 0x8c, 0xf8, 0xed, 0x2a, 0x16, 0x29, 0xc4, 0xaf, 0xd3, 0xc5, + 0x1f, 0x3c, 0x1d, 0x37, 0xca, 0xb7, 0x9f, 0x3e, 0xab, 0xff, 0xa8, 0x4d, 0x58, 0x6b, 0xd3, 0xee, 0xe7, 0x7f, 0x1c, + 0xaa, 0xf9, 0x3e, 0x3a, 0xdc, 0xd7, 0x3f, 0xfe, 0xa8, 0xeb, 0xe9, 0x9b, 0x22, 0x9c, 0xff, 0x33, 0x54, 0xf3, 0x79, + 0x5c, 0x14, 0xf1, 0x5d, 0x0d, 0x91, 0x3c, 0x85, 0xf3, 0x26, 0xa1, 0xde, 0x36, 0xa0, 0x07, 0x64, 0x7a, 0x21, 0x18, + 0x7c, 0xf3, 0xbe, 0x0a, 0x03, 0x5e, 0xae, 0x86, 0x5c, 0x54, 0x59, 0x75, 0x37, 0xc4, 0x3c, 0x01, 0x7e, 0x6a, 0x78, + 0xb3, 0xe7, 0x85, 0x21, 0x36, 0x17, 0x05, 0xe7, 0x9f, 0x78, 0xa8, 0x8c, 0xa3, 0xc7, 0x68, 0x1c, 0x3d, 0xa6, 0x6a, + 0x30, 0x26, 0xdf, 0x50, 0xdd, 0x99, 0xc9, 0x37, 0x60, 0x82, 0x94, 0xb5, 0xbf, 0x51, 0xc6, 0x89, 0xd1, 0x98, 0x5e, + 0xbf, 0xca, 0xb3, 0x15, 0x30, 0xc1, 0x4b, 0xfd, 0xa3, 0x26, 0xf4, 0x3d, 0x6f, 0x67, 0x1f, 0x8d, 0x46, 0xcf, 0x0b, + 0x3a, 0x1a, 0x8d, 0x3e, 0x66, 0x35, 0xa1, 0x2b, 0xd1, 0xf1, 0xfe, 0x3d, 0xa7, 0xe7, 0x32, 0xbd, 0x8b, 0x82, 0x80, + 0x2e, 0xb3, 0x34, 0xe5, 0x42, 0x95, 0x75, 0x9a, 0xb6, 0xf3, 0xaa, 0x16, 0x22, 0xf0, 0x8f, 0x6e, 0x23, 0x42, 0x10, + 0x11, 0x7a, 0xb2, 0xd3, 0xb3, 0xd1, 0x68, 0x74, 0x9a, 0x9a, 0x6a, 0x1d, 0x43, 0xfe, 0x06, 0xcd, 0x07, 0x9c, 0x5d, + 0x3e, 0x58, 0xdf, 0x98, 0x68, 0x27, 0xfb, 0xff, 0x3d, 0x9c, 0xcd, 0xc7, 0xc3, 0x6f, 0x47, 0x8b, 0xc7, 0xfb, 0x34, + 0x08, 0x7c, 0xd0, 0xea, 0x50, 0x5b, 0x73, 0x4c, 0xcb, 0xc3, 0xf1, 0x94, 0x94, 0x03, 0xf6, 0xd4, 0xfa, 0xd2, 0x7c, + 0xf5, 0x14, 0x90, 0x48, 0x51, 0x84, 0x1a, 0x38, 0xe9, 0x1f, 0x5e, 0x45, 0x5e, 0x0b, 0xc0, 0x47, 0xb3, 0x91, 0x0c, + 0x8c, 0x16, 0x70, 0x1c, 0x41, 0x79, 0xb5, 0x35, 0x8d, 0xe8, 0x31, 0x96, 0x99, 0xa8, 0xa0, 0xe3, 0x69, 0x79, 0x93, + 0x55, 0xc9, 0x12, 0x03, 0x1b, 0xc5, 0x25, 0x0f, 0xbe, 0x0a, 0xa2, 0x92, 0x1d, 0x3c, 0x9b, 0x2a, 0x78, 0x5f, 0x4c, + 0x4a, 0xf9, 0x25, 0x24, 0x7e, 0x3b, 0x46, 0x08, 0x54, 0xa2, 0x3d, 0x16, 0xb1, 0xc6, 0x57, 0xb9, 0x8c, 0xc1, 0x83, + 0xb3, 0xd4, 0x3c, 0x8b, 0x3d, 0x09, 0xac, 0xfd, 0x45, 0xab, 0x39, 0x12, 0x9a, 0x13, 0x4a, 0x26, 0xf7, 0x4b, 0x2a, + 0xbf, 0x9a, 0xa0, 0x57, 0x10, 0xb8, 0x55, 0x47, 0x70, 0xdc, 0x59, 0xcb, 0x06, 0xbd, 0x7c, 0x52, 0xb6, 0x3f, 0xff, + 0xdf, 0x25, 0x5d, 0x0c, 0xf6, 0xdd, 0xd0, 0x9c, 0x68, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x9e, 0x12, 0x6b, + 0x7c, 0xca, 0xd9, 0xd1, 0xc6, 0x74, 0x67, 0x54, 0x15, 0xd9, 0x55, 0x48, 0x74, 0xaf, 0x1c, 0x28, 0x66, 0x10, 0x65, + 0x23, 0x5c, 0x3f, 0x60, 0x2d, 0xe2, 0x75, 0xf2, 0x9a, 0x17, 0x55, 0x96, 0xa8, 0xf7, 0xd7, 0x8d, 0xf7, 0x40, 0x0d, + 0x54, 0x83, 0xde, 0x15, 0x0c, 0xe6, 0xf9, 0xa4, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, + 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, + 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xae, 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, + 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x93, 0x86, 0x10, + 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, 0x9e, 0xe0, 0xa9, 0x1a, 0x06, 0x17, 0x79, 0xb6, 0xd2, 0x49, 0xd5, 0xa8, + 0xa3, 0xf9, 0x50, 0x6a, 0x47, 0x72, 0x40, 0xbd, 0xf4, 0x18, 0xd3, 0x0b, 0x95, 0xae, 0x8a, 0x72, 0x46, 0x28, 0xef, + 0xf4, 0xc4, 0xb8, 0x30, 0x7d, 0x1c, 0x22, 0xbf, 0xbc, 0x2b, 0x54, 0xe8, 0x17, 0xbe, 0x00, 0xf0, 0x2b, 0xb8, 0xdd, + 0xef, 0xc6, 0x77, 0x51, 0xd9, 0xcf, 0x38, 0xdb, 0xff, 0xef, 0x79, 0x3c, 0xfc, 0x34, 0x1e, 0x7e, 0xbb, 0x18, 0x84, + 0x43, 0xfb, 0x93, 0x3c, 0x7e, 0xb4, 0x4f, 0x5f, 0x71, 0xcb, 0x95, 0xc0, 0xc2, 0x6f, 0x04, 0xb7, 0x51, 0x2b, 0x21, + 0x88, 0x02, 0xbc, 0x51, 0xb8, 0xd5, 0x38, 0x01, 0x80, 0xbf, 0xe0, 0xbf, 0x02, 0x34, 0x12, 0x72, 0x17, 0x0d, 0xd0, + 0x0f, 0xa8, 0xdf, 0x47, 0x4f, 0x1a, 0x06, 0x72, 0x20, 0x9e, 0x50, 0x31, 0x50, 0x88, 0x2e, 0x63, 0xa2, 0x60, 0x7f, + 0x6d, 0xf6, 0xed, 0xb6, 0xd7, 0x96, 0xfc, 0xe0, 0x97, 0x7e, 0xa6, 0x89, 0x99, 0x77, 0xb8, 0xa1, 0xac, 0xe4, 0x2a, + 0x44, 0x6c, 0x3c, 0xfd, 0x2b, 0x67, 0x10, 0x6b, 0xf2, 0x3a, 0x03, 0x1f, 0x06, 0xfb, 0xc5, 0x78, 0x06, 0x6c, 0x03, + 0xdc, 0x71, 0x0a, 0x7e, 0x91, 0x81, 0x5b, 0xb3, 0x88, 0xf1, 0x82, 0x6d, 0x97, 0x44, 0xbf, 0xdf, 0xcb, 0xb3, 0x30, + 0xd7, 0x38, 0xcb, 0x79, 0x6d, 0xc4, 0xee, 0xa8, 0x13, 0x06, 0x71, 0xbb, 0x1e, 0x82, 0xa1, 0x1a, 0x82, 0xa2, 0xa3, + 0x2d, 0xae, 0x5e, 0x5b, 0x4f, 0x61, 0x7a, 0xab, 0xea, 0x2b, 0x46, 0x7f, 0xca, 0x4c, 0x60, 0x21, 0xed, 0x9a, 0x63, + 0x5d, 0x73, 0x8c, 0xb4, 0xa7, 0xdf, 0x17, 0x0d, 0xf2, 0xd3, 0x59, 0x78, 0x10, 0xa8, 0x52, 0xe5, 0x4e, 0x59, 0x94, + 0xdb, 0xd2, 0xbc, 0x31, 0xac, 0x69, 0x9e, 0xd9, 0xb8, 0x2e, 0xb3, 0x5e, 0x2f, 0x0c, 0xd1, 0xa1, 0x11, 0x4b, 0xc5, + 0xda, 0x20, 0xbc, 0x8f, 0x49, 0x18, 0x5d, 0x81, 0xac, 0x2e, 0x3c, 0xe3, 0x04, 0xf9, 0x32, 0x30, 0x59, 0x53, 0xd5, + 0x7a, 0x39, 0xe1, 0xb1, 0x91, 0x2f, 0x1b, 0x41, 0x83, 0xbc, 0xa4, 0xa8, 0x37, 0x71, 0x3b, 0xf6, 0x51, 0x0b, 0xa9, + 0x71, 0x53, 0x4f, 0x7b, 0x9a, 0x54, 0xf4, 0x58, 0xaf, 0x52, 0xbf, 0xc0, 0xb2, 0xc0, 0x92, 0x0f, 0x42, 0x7b, 0x9a, + 0x56, 0x60, 0x86, 0x6b, 0x9b, 0xc1, 0xd0, 0x0f, 0x87, 0xb6, 0x08, 0x9d, 0x51, 0xdb, 0x12, 0xc2, 0xb6, 0x0d, 0xc2, + 0xca, 0x7b, 0x22, 0x5f, 0x3d, 0xf5, 0x18, 0xe1, 0x90, 0x9b, 0xcd, 0x2c, 0x1a, 0x18, 0xe6, 0x57, 0xb2, 0xd9, 0x3c, + 0xdd, 0x5c, 0x2f, 0x2a, 0xa6, 0x80, 0xed, 0xb6, 0x12, 0x04, 0xff, 0x7e, 0xcc, 0x66, 0xf8, 0x37, 0xeb, 0xf7, 0x7b, + 0x21, 0xfe, 0xe2, 0x18, 0xbc, 0x67, 0x2e, 0x16, 0xec, 0x23, 0xc8, 0x54, 0x48, 0x84, 0xa9, 0xca, 0xf8, 0x8d, 0x55, + 0x60, 0x01, 0x67, 0x3e, 0x50, 0xb9, 0x30, 0x93, 0xbd, 0xbc, 0xb8, 0x86, 0x1c, 0xb7, 0xc6, 0x29, 0x1b, 0x65, 0x89, + 0x72, 0x5d, 0xc8, 0x46, 0x71, 0x9e, 0xc5, 0x25, 0x2f, 0xb7, 0x5b, 0x7d, 0x38, 0x26, 0x05, 0x07, 0xf6, 0x54, 0x51, + 0xa9, 0x92, 0x75, 0xa4, 0xba, 0xf1, 0x97, 0x61, 0x81, 0xfb, 0x94, 0xcf, 0x0b, 0x43, 0x23, 0xf6, 0xe0, 0xf2, 0xce, + 0xd4, 0xad, 0xb4, 0x17, 0x16, 0xd0, 0xbc, 0x92, 0x90, 0x0d, 0xa6, 0x7a, 0x16, 0xad, 0x31, 0x13, 0xf3, 0x62, 0x01, + 0x61, 0x64, 0x8a, 0x05, 0xd8, 0x4c, 0x71, 0x01, 0x5e, 0x24, 0x31, 0xc0, 0xc4, 0xc5, 0x64, 0x0a, 0xf1, 0xcc, 0x55, + 0x39, 0xf1, 0xc2, 0xdc, 0x2f, 0x13, 0x87, 0x94, 0x01, 0xaf, 0x6a, 0x83, 0x26, 0x66, 0x1b, 0x8e, 0x3a, 0x41, 0x4e, + 0x4c, 0x7e, 0x3f, 0x55, 0x10, 0xe2, 0x4e, 0x1c, 0x09, 0x97, 0x15, 0xdb, 0x85, 0x97, 0x1d, 0x88, 0x31, 0x6a, 0x70, + 0xca, 0xcf, 0x0c, 0x8e, 0xc6, 0xe0, 0xdc, 0x78, 0x27, 0x48, 0x11, 0xc6, 0x64, 0x23, 0xd9, 0x95, 0x0c, 0xc5, 0x3c, + 0x5e, 0x80, 0xb2, 0x2e, 0x5e, 0x80, 0x65, 0x8d, 0x31, 0xc0, 0x04, 0x79, 0x15, 0xf7, 0x42, 0x3f, 0x51, 0x5c, 0x21, + 0xd2, 0xb3, 0x72, 0x7d, 0x54, 0xb4, 0x43, 0x5f, 0xe0, 0xf5, 0x5e, 0x99, 0xe3, 0x66, 0x3d, 0x16, 0x48, 0x6c, 0x08, + 0x18, 0x1b, 0xe9, 0x34, 0xd5, 0x5a, 0xf7, 0xc6, 0xcc, 0x03, 0x9f, 0x66, 0x23, 0x21, 0xab, 0xb3, 0x0b, 0x10, 0xa1, + 0xf8, 0x68, 0xf0, 0xc8, 0x2f, 0xe2, 0xce, 0x32, 0x6f, 0x6d, 0x8b, 0x4a, 0x76, 0xb4, 0x01, 0x90, 0x3e, 0x1d, 0x2d, + 0x4a, 0xc9, 0x29, 0x4a, 0x52, 0xbb, 0x4d, 0x01, 0x2b, 0xc9, 0x5f, 0xc0, 0x10, 0x6c, 0x6c, 0x4f, 0x38, 0x9d, 0x22, + 0xc4, 0x27, 0x9a, 0x22, 0xb2, 0x62, 0x58, 0x52, 0x1c, 0xdb, 0x12, 0x51, 0x3f, 0x6d, 0x59, 0x76, 0x30, 0x4c, 0x54, + 0xdc, 0x17, 0xa9, 0x47, 0x89, 0x82, 0x80, 0xea, 0x21, 0x07, 0x89, 0xad, 0x6d, 0x20, 0x3c, 0x20, 0x8f, 0xe8, 0x8d, + 0xf5, 0xf7, 0x59, 0xe7, 0xd9, 0x85, 0xe6, 0xa8, 0x5c, 0xef, 0x0a, 0x33, 0x46, 0x78, 0x92, 0x19, 0x98, 0x7c, 0xef, + 0x3c, 0x33, 0x6a, 0x8a, 0x9e, 0x87, 0x4f, 0x76, 0x8c, 0x11, 0xe9, 0xee, 0x19, 0x74, 0x13, 0xbc, 0xaa, 0xc3, 0x46, + 0xbb, 0x52, 0x10, 0x12, 0xa6, 0x16, 0x4d, 0xcc, 0x7a, 0xd6, 0x80, 0x7a, 0xbb, 0xed, 0xe9, 0xb9, 0xba, 0x7f, 0xee, + 0xb6, 0xdb, 0x1e, 0x76, 0xeb, 0x45, 0xda, 0x6d, 0x05, 0x5e, 0xa9, 0x0f, 0xda, 0xe3, 0xcf, 0xdd, 0xf8, 0x73, 0x83, + 0xe4, 0x51, 0x3a, 0x9a, 0x69, 0xeb, 0x83, 0x70, 0xb8, 0xe9, 0x5d, 0xa3, 0x49, 0xdf, 0x67, 0xa1, 0xa4, 0x2b, 0xd1, + 0xa8, 0xae, 0x76, 0x26, 0x95, 0x0f, 0xae, 0xff, 0x87, 0x57, 0x01, 0x1e, 0x71, 0x6a, 0x67, 0xdf, 0xdb, 0xa0, 0xa2, + 0xd1, 0x16, 0x8e, 0x14, 0xa1, 0x07, 0x24, 0xe1, 0xbe, 0x96, 0xb5, 0xb8, 0xcd, 0xd3, 0xec, 0x61, 0xfa, 0xf4, 0x3a, + 0xf5, 0xad, 0xee, 0xdd, 0x32, 0xcb, 0xcc, 0x81, 0x57, 0x51, 0x1c, 0xd0, 0xa8, 0x8b, 0xf6, 0x5d, 0x65, 0x65, 0x09, + 0x5e, 0x1e, 0x70, 0x7d, 0x3e, 0xe5, 0x3e, 0xdc, 0xdc, 0x65, 0xd5, 0xdc, 0xa4, 0xa7, 0xd9, 0x3c, 0x5b, 0x6c, 0xb7, + 0x21, 0xfe, 0xed, 0x6a, 0x91, 0xa3, 0xc9, 0x73, 0xd0, 0xe1, 0x61, 0xe4, 0x1e, 0xa6, 0x1b, 0xe7, 0x6d, 0xfe, 0x4f, + 0xa2, 0xe1, 0x24, 0x70, 0x0c, 0xf4, 0x62, 0xf6, 0x08, 0x64, 0x30, 0xc6, 0xa9, 0x5f, 0xcc, 0xf4, 0x9a, 0x81, 0xe8, + 0x5b, 0x22, 0x02, 0x1c, 0x5d, 0x6c, 0x24, 0x1a, 0x59, 0x70, 0x52, 0x13, 0xb0, 0xd8, 0xb4, 0xe5, 0x7d, 0xb0, 0xb4, + 0xad, 0x2a, 0xee, 0xbc, 0x25, 0xcd, 0x71, 0x1d, 0x38, 0xdb, 0x7e, 0x33, 0xc4, 0xa6, 0xec, 0x6a, 0x81, 0xdc, 0x2f, + 0xaf, 0x69, 0x6f, 0x5c, 0x27, 0x30, 0x6b, 0x9b, 0xda, 0x32, 0x7e, 0xb6, 0xf4, 0x9f, 0xf5, 0xe0, 0x2a, 0xe3, 0xa7, + 0xb9, 0xb1, 0x4a, 0xb0, 0xfb, 0xc6, 0xf3, 0x1d, 0x80, 0x70, 0x6c, 0x3e, 0x3d, 0x3e, 0xcd, 0x3c, 0x7a, 0x0c, 0x44, + 0xc7, 0x7c, 0x54, 0xba, 0x8f, 0xec, 0xee, 0xf5, 0x03, 0xe0, 0xcd, 0xab, 0x76, 0x41, 0xf3, 0x72, 0x01, 0x81, 0x44, + 0xbd, 0xf2, 0x0a, 0xcb, 0x67, 0xc6, 0xec, 0x12, 0xc8, 0x50, 0x41, 0xc0, 0x26, 0xa9, 0xeb, 0x5c, 0x88, 0x55, 0x87, + 0x95, 0xf9, 0x48, 0xc2, 0x8e, 0x42, 0x34, 0xe7, 0x0c, 0x66, 0xc1, 0x7f, 0x05, 0x83, 0x72, 0x10, 0x44, 0x41, 0x14, + 0x04, 0x64, 0x50, 0xc0, 0x2f, 0xc4, 0x19, 0x23, 0x18, 0xa3, 0x04, 0x3a, 0xfc, 0x8e, 0x33, 0x9f, 0x11, 0x79, 0xd9, + 0x08, 0x63, 0xe9, 0x06, 0xe0, 0x5c, 0xca, 0x9c, 0xc7, 0xe8, 0x63, 0xf1, 0x8e, 0xb3, 0x8c, 0xd0, 0x77, 0xde, 0xa9, + 0xfc, 0x88, 0x37, 0x82, 0xdb, 0xed, 0x0e, 0xdb, 0x2b, 0x1e, 0x66, 0xb4, 0x37, 0xa6, 0xef, 0x38, 0x89, 0xb2, 0x86, + 0xf3, 0x30, 0x87, 0x9e, 0x55, 0x96, 0xb5, 0xa2, 0x86, 0xdc, 0xa0, 0x58, 0x17, 0x59, 0x26, 0x27, 0xc3, 0x55, 0x73, + 0x2a, 0x70, 0xdd, 0xd9, 0xf5, 0x02, 0x92, 0x32, 0xa1, 0x59, 0x3a, 0x1b, 0xbe, 0xda, 0xb6, 0xec, 0x45, 0xeb, 0x14, + 0xf2, 0x1a, 0xa2, 0xa2, 0x1f, 0x3a, 0x02, 0x6a, 0x68, 0xc5, 0x65, 0x05, 0x2e, 0xbb, 0xa6, 0x3d, 0xdc, 0xb4, 0xc7, + 0x34, 0xe3, 0x03, 0xc4, 0x88, 0xe3, 0xd8, 0x32, 0xb0, 0x9b, 0x70, 0x78, 0x36, 0xce, 0xf7, 0x65, 0x97, 0xde, 0xba, + 0x5a, 0x3c, 0xc2, 0xda, 0xf3, 0x56, 0x48, 0x08, 0x90, 0x96, 0xa6, 0xd2, 0xed, 0x36, 0x08, 0x60, 0x80, 0xfb, 0xfd, + 0x1e, 0x70, 0xad, 0x86, 0x9d, 0x34, 0xb7, 0x66, 0x4b, 0xec, 0x15, 0x85, 0xc7, 0x40, 0x94, 0x9a, 0xff, 0x0c, 0x02, + 0x8a, 0xe7, 0x6e, 0x08, 0xf6, 0x95, 0xec, 0x68, 0x53, 0xf4, 0xfb, 0x2f, 0x0a, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, + 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, + 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x9f, 0x00, 0x16, 0x3c, 0xf3, 0x86, 0xe5, + 0xbd, 0x07, 0x00, 0xd6, 0xeb, 0xe1, 0x42, 0x71, 0x2f, 0x5f, 0x35, 0xd0, 0x27, 0xf1, 0xa5, 0x65, 0xd7, 0x67, 0x5a, + 0x56, 0x32, 0x1a, 0x8d, 0xaa, 0x5a, 0x49, 0x3e, 0x1c, 0x79, 0x69, 0xa1, 0x56, 0xca, 0x38, 0xe5, 0x29, 0x58, 0x7a, + 0x1b, 0x4a, 0x37, 0x5f, 0xd0, 0x15, 0x17, 0xa9, 0xfa, 0xe9, 0xa1, 0x4d, 0x36, 0x88, 0x6b, 0xd6, 0xd4, 0x59, 0xd8, + 0xe1, 0x87, 0x80, 0x8f, 0xf6, 0x61, 0xe6, 0xd2, 0x35, 0x2c, 0x2d, 0x88, 0x23, 0xe3, 0x82, 0x87, 0x2e, 0x0f, 0x60, + 0xfd, 0x99, 0x43, 0x12, 0x3f, 0x85, 0x9f, 0x33, 0x93, 0xd6, 0xf1, 0x19, 0xce, 0x66, 0x54, 0xaa, 0x1b, 0x41, 0xfb, + 0x35, 0x24, 0x12, 0x83, 0x6c, 0xdc, 0x60, 0x28, 0x5a, 0x77, 0x1b, 0xb8, 0xf2, 0x5b, 0x7a, 0xe7, 0xd3, 0x20, 0xc0, + 0xb6, 0xc6, 0x62, 0x00, 0x30, 0x14, 0x7f, 0xa0, 0xaa, 0xc6, 0x5c, 0x51, 0x4c, 0xc3, 0x54, 0xa2, 0xbd, 0xe3, 0xb8, + 0x8e, 0x1a, 0x57, 0x59, 0xc1, 0x4a, 0x6b, 0xcb, 0xeb, 0xde, 0xd2, 0xc2, 0x96, 0x80, 0x6a, 0x30, 0xdc, 0x09, 0xe0, + 0x33, 0x22, 0xd5, 0x81, 0x20, 0xbb, 0x0f, 0x0e, 0x9a, 0xb3, 0x04, 0xcf, 0xc3, 0x10, 0xfe, 0xc0, 0xc2, 0x81, 0x65, + 0xa9, 0xfa, 0xb9, 0x9c, 0xc6, 0x70, 0xee, 0xe6, 0x6a, 0x87, 0xcf, 0x96, 0xa0, 0xc8, 0x53, 0x73, 0x6a, 0x2e, 0x5f, + 0x79, 0x63, 0xbf, 0xc7, 0x04, 0xf3, 0x98, 0xd9, 0x86, 0xdf, 0x7a, 0xba, 0xad, 0x2f, 0xac, 0x1b, 0x38, 0x69, 0x2f, + 0x9c, 0xf6, 0x62, 0xbb, 0x34, 0x10, 0x77, 0x75, 0x43, 0x88, 0xf0, 0x5a, 0x13, 0x8b, 0xac, 0x21, 0xd3, 0xb1, 0xd8, + 0x18, 0xaa, 0x4d, 0xc5, 0x73, 0xad, 0x10, 0x2f, 0xa7, 0xea, 0xc2, 0xd4, 0x4a, 0x65, 0xc2, 0x20, 0xcc, 0x94, 0xb0, + 0xa8, 0x32, 0xf0, 0xd9, 0xaf, 0x90, 0xe2, 0xda, 0x7a, 0xde, 0xe2, 0xf2, 0xcd, 0x4c, 0x9b, 0xed, 0xa7, 0xaf, 0xf2, + 0xf8, 0x72, 0xbb, 0x0d, 0xbb, 0x5f, 0x80, 0xf9, 0x65, 0xa9, 0x34, 0x6a, 0xe0, 0xf4, 0x10, 0xa2, 0x9f, 0xf3, 0x3d, + 0x39, 0x27, 0x8e, 0x93, 0x6b, 0x37, 0x6f, 0xb6, 0x93, 0x62, 0x04, 0x16, 0x70, 0xe2, 0x22, 0x1d, 0x68, 0xa9, 0xe0, + 0xb4, 0x65, 0xbc, 0xb7, 0xe9, 0x1d, 0xa5, 0xc2, 0xab, 0x85, 0x26, 0x21, 0x95, 0xbb, 0x97, 0xd8, 0x51, 0x03, 0xce, + 0x49, 0xdd, 0x41, 0xc0, 0x49, 0x4d, 0x37, 0xd6, 0x2a, 0x4e, 0x4d, 0x82, 0xf7, 0x4a, 0x0f, 0x5d, 0xa2, 0x9d, 0xb8, + 0xdd, 0xb6, 0x2a, 0x5b, 0xa8, 0x8f, 0x7b, 0x39, 0x4b, 0xd4, 0xf1, 0x80, 0x42, 0x17, 0x75, 0x34, 0xe4, 0x0b, 0x52, + 0xe8, 0x95, 0xa3, 0x55, 0xab, 0xbb, 0x92, 0x81, 0x52, 0xad, 0x82, 0xbc, 0x26, 0xd6, 0x5d, 0x2b, 0x6b, 0x2c, 0xae, + 0x9c, 0x90, 0xc2, 0x26, 0x7c, 0x69, 0x29, 0x16, 0x56, 0xb0, 0x37, 0xa6, 0xbe, 0x70, 0x89, 0xd0, 0x76, 0xb7, 0x21, + 0x26, 0x19, 0xac, 0x9b, 0xed, 0xf6, 0x75, 0x11, 0xce, 0xb3, 0x05, 0x95, 0xa3, 0x2c, 0x45, 0x08, 0x31, 0xe3, 0xa1, + 0x6b, 0xbb, 0x60, 0x26, 0x86, 0xba, 0xf6, 0x78, 0x49, 0xa6, 0x58, 0x9b, 0x24, 0x47, 0xf1, 0xb9, 0x2c, 0xd4, 0x5a, + 0x23, 0x04, 0x0f, 0xf7, 0x3f, 0x53, 0x88, 0xe1, 0x66, 0xd6, 0xdd, 0x6f, 0x3b, 0x37, 0xc4, 0x3f, 0x21, 0x90, 0x40, + 0xc9, 0x5e, 0x17, 0xa3, 0xf3, 0x4c, 0xa4, 0xb8, 0x53, 0x55, 0x54, 0x5c, 0xb5, 0x0e, 0x9a, 0x2d, 0xb7, 0xf7, 0x62, + 0x4b, 0x14, 0x20, 0xae, 0xb1, 0xd0, 0x8c, 0x67, 0xe5, 0x2c, 0x45, 0x32, 0x8a, 0x0d, 0x89, 0x4a, 0x2f, 0x2a, 0xba, + 0xcf, 0xd3, 0x98, 0x1e, 0xba, 0x35, 0x08, 0xae, 0x9a, 0x3b, 0x1b, 0x69, 0xbe, 0x20, 0x44, 0x4d, 0x80, 0x84, 0x8d, + 0x6a, 0x4e, 0xad, 0x4b, 0xf1, 0x30, 0xab, 0x7c, 0xa6, 0x0f, 0xe2, 0x4b, 0x01, 0x3c, 0xac, 0xb7, 0xbd, 0xaf, 0x84, + 0xc7, 0xda, 0xe0, 0xdb, 0xed, 0xf6, 0x52, 0xcc, 0x83, 0xc0, 0x63, 0x34, 0xbf, 0x53, 0x12, 0xf3, 0xde, 0x98, 0xc2, + 0x8a, 0xf7, 0x5d, 0xda, 0xba, 0x49, 0xad, 0xb5, 0x40, 0xdd, 0xe1, 0xfa, 0x80, 0xe7, 0x29, 0x71, 0xb4, 0xa3, 0x72, + 0x2a, 0xad, 0xae, 0x1c, 0xbb, 0x22, 0x30, 0x30, 0xf4, 0x0f, 0x29, 0xdb, 0x80, 0x39, 0x1e, 0x58, 0xdb, 0xa0, 0x9f, + 0x92, 0xd2, 0xc2, 0x8c, 0xd1, 0x98, 0x45, 0xae, 0xab, 0xe8, 0x80, 0xeb, 0xe8, 0xed, 0x3c, 0xfa, 0xdb, 0xb3, 0x31, + 0x2d, 0x62, 0x91, 0xca, 0x2b, 0x50, 0x41, 0x80, 0x32, 0x04, 0x0d, 0xff, 0x35, 0x35, 0x00, 0x0d, 0x82, 0x1b, 0x80, + 0x7f, 0x74, 0x3a, 0x0d, 0xda, 0x9a, 0x7c, 0x4c, 0x52, 0x55, 0xe4, 0xac, 0x0d, 0x65, 0xa6, 0x92, 0x43, 0xf2, 0xb8, + 0x04, 0x3c, 0x47, 0x6c, 0x96, 0xb2, 0xb9, 0x50, 0x9b, 0x4d, 0xbd, 0x56, 0xec, 0xc8, 0x6d, 0xa3, 0x68, 0xb3, 0x16, + 0xb5, 0x9d, 0xc4, 0x7c, 0x31, 0xbd, 0xb5, 0xc2, 0xc0, 0xa9, 0x69, 0xcd, 0xcd, 0x0e, 0x74, 0x9a, 0xad, 0xcf, 0xe4, + 0x26, 0x40, 0x1c, 0x60, 0xb8, 0x6e, 0xe7, 0x37, 0x0b, 0x42, 0x6f, 0xd9, 0xad, 0x15, 0xab, 0xde, 0x58, 0xb9, 0x88, + 0x49, 0xbb, 0x19, 0x4c, 0xe0, 0x32, 0xce, 0x0a, 0xfb, 0x42, 0xab, 0x1b, 0x8a, 0x8e, 0xb6, 0x49, 0xfb, 0x79, 0x47, + 0xbb, 0xe1, 0x82, 0x6f, 0xc5, 0x3a, 0xce, 0x0d, 0x69, 0xaa, 0xd0, 0xa3, 0x03, 0xbd, 0x1d, 0x02, 0x9a, 0xb3, 0x31, + 0x5d, 0xd2, 0x14, 0x2f, 0xd0, 0x74, 0x0d, 0x66, 0x29, 0x17, 0xd0, 0xd7, 0x6e, 0x9f, 0xe4, 0x0b, 0xd5, 0x13, 0xe1, + 0x2d, 0x51, 0xf0, 0xe5, 0x48, 0xc1, 0x2b, 0x2b, 0xe7, 0xb1, 0x99, 0x43, 0xc0, 0x63, 0x51, 0x25, 0x7a, 0x27, 0xc5, + 0x25, 0x28, 0x53, 0xe1, 0x08, 0x34, 0x55, 0x23, 0x96, 0x70, 0x80, 0xdb, 0x8b, 0xa7, 0x01, 0xa1, 0x20, 0xd5, 0x5d, + 0xdb, 0x15, 0x79, 0xcb, 0x8e, 0x36, 0xb7, 0x60, 0x16, 0x5b, 0xad, 0xcb, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, + 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, 0x43, 0x36, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, + 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x55, 0x7c, 0x07, 0x9b, + 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, + 0x5e, 0x6d, 0x6d, 0xd6, 0x66, 0xb9, 0x3e, 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, + 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x36, 0xce, + 0xdc, 0xeb, 0x90, 0x6c, 0xfe, 0xc7, 0x06, 0xea, 0x4d, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x3e, 0x61, 0x10, 0x1b, 0x33, + 0x28, 0xd7, 0x49, 0xc2, 0xcb, 0x32, 0x30, 0x4a, 0xad, 0x35, 0x5b, 0x9b, 0xf3, 0xec, 0x11, 0x3b, 0x7a, 0xd4, 0x63, + 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x04, 0x85, + 0x2c, 0xed, 0x7d, 0x6e, 0x4e, 0x64, 0xf5, 0x8d, 0x36, 0xba, 0x88, 0x54, 0x22, 0xc8, 0xc6, 0x6f, 0x10, 0xb0, 0x17, + 0x9a, 0x1d, 0x90, 0xcd, 0x92, 0x9d, 0xd2, 0x33, 0x6b, 0x02, 0x03, 0xaf, 0x4f, 0x54, 0xa2, 0x19, 0x65, 0x45, 0x74, + 0x95, 0x91, 0xcb, 0x5d, 0x48, 0xa2, 0xb3, 0x90, 0xf8, 0xb9, 0x61, 0x69, 0x5d, 0x87, 0x28, 0x66, 0x36, 0x1b, 0x5e, + 0x75, 0xf7, 0x51, 0x63, 0x5b, 0x19, 0x9f, 0xea, 0x5b, 0x9b, 0x46, 0xa6, 0xd0, 0xd7, 0xe1, 0xa4, 0xdf, 0x87, 0xbf, + 0x9a, 0x7e, 0xe0, 0x2d, 0x05, 0x7f, 0xb1, 0x47, 0xa4, 0x4e, 0x58, 0x00, 0x70, 0x84, 0x39, 0xaf, 0x9a, 0x13, 0xf8, + 0x88, 0x1d, 0x6d, 0x1e, 0x85, 0xa7, 0x8d, 0x99, 0xbb, 0x0b, 0xf1, 0x52, 0x95, 0xf4, 0xbc, 0x79, 0x32, 0x03, 0xb1, + 0x0a, 0xcd, 0x7e, 0xbd, 0x65, 0x56, 0x9f, 0x00, 0x44, 0xea, 0xd6, 0x3a, 0x94, 0xe2, 0xc7, 0xa6, 0xcb, 0x64, 0x93, + 0xb2, 0x36, 0x13, 0xa5, 0x54, 0x24, 0xcd, 0x45, 0x00, 0xfd, 0x86, 0xe1, 0xa8, 0x01, 0xde, 0x5b, 0x8f, 0xbd, 0x19, + 0x1a, 0x6f, 0x4c, 0x0d, 0x3d, 0xdb, 0xe8, 0xe5, 0xed, 0x28, 0x84, 0x19, 0x8b, 0xe8, 0xd6, 0x1d, 0x8b, 0xe1, 0x29, + 0x3d, 0x81, 0x0a, 0xdf, 0x84, 0x18, 0x4d, 0x97, 0xd4, 0xf5, 0x74, 0xad, 0xb6, 0xd2, 0x0d, 0xa1, 0x39, 0x46, 0xf1, + 0xf1, 0xda, 0x76, 0x47, 0x8d, 0xd0, 0x9e, 0x50, 0x1e, 0xde, 0xd2, 0x8a, 0xde, 0x58, 0x16, 0xc1, 0xc9, 0x8f, 0xbd, + 0xfc, 0x84, 0x9e, 0x7b, 0x02, 0x93, 0xa2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x3d, 0xb5, 0x52, 0x0e, 0x4f, + 0xe1, 0x4b, 0x36, 0x20, 0x57, 0xd0, 0x8b, 0x35, 0x66, 0x47, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x37, 0x29, 0x65, + 0x88, 0xd6, 0x77, 0x0e, 0xe2, 0xe9, 0x1f, 0xa0, 0xe9, 0x83, 0xb4, 0x30, 0xa5, 0x6b, 0x14, 0xf0, 0x80, 0xbe, 0xa9, + 0xdf, 0xcf, 0xf1, 0xb9, 0xf6, 0x2c, 0xb1, 0xb0, 0xc7, 0x4b, 0x42, 0x97, 0x5e, 0xdc, 0x28, 0x90, 0x36, 0x3b, 0x56, + 0x01, 0x58, 0x91, 0x04, 0x1a, 0x91, 0x80, 0xa5, 0x8e, 0x27, 0x2e, 0xdb, 0xa0, 0x01, 0x49, 0x54, 0x52, 0xc8, 0x12, + 0x49, 0xe0, 0x87, 0x11, 0x84, 0x28, 0x8a, 0x41, 0xdc, 0xab, 0x97, 0x57, 0x5c, 0x53, 0x03, 0x4e, 0x14, 0xc1, 0x04, + 0xeb, 0x74, 0x0a, 0xc4, 0x56, 0xac, 0x57, 0xe0, 0x79, 0xe9, 0x38, 0x71, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x97, 0x4e, + 0xbb, 0xe5, 0xed, 0x89, 0x96, 0x2a, 0x36, 0xf7, 0x5e, 0x2c, 0x2c, 0xf7, 0x58, 0xf9, 0xdb, 0x81, 0xf6, 0xc2, 0x6a, + 0x47, 0x44, 0x0d, 0x56, 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xea, 0x5e, 0x39, 0x26, 0xa0, 0xa2, 0xab, 0xb8, 0x5a, + 0x46, 0xd9, 0x08, 0xfe, 0x6c, 0xb7, 0xc1, 0x7e, 0x00, 0x16, 0x90, 0xbf, 0xbe, 0xff, 0x39, 0xc2, 0xf0, 0x4c, 0xbf, + 0xbe, 0xff, 0x79, 0xbb, 0x7d, 0x36, 0x1e, 0x1b, 0xae, 0xc0, 0xa9, 0x75, 0x80, 0x3f, 0x30, 0x6c, 0x83, 0x5d, 0xb2, + 0xdb, 0xed, 0x33, 0xe0, 0x20, 0x14, 0xdb, 0x60, 0x76, 0xb1, 0x72, 0xe4, 0x52, 0xac, 0x86, 0xde, 0x91, 0x80, 0x55, + 0xb7, 0xc3, 0x52, 0xec, 0x52, 0x1f, 0x15, 0x82, 0x51, 0x2f, 0xfa, 0x97, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, + 0xb2, 0xaa, 0x56, 0x65, 0xb4, 0xbf, 0x1f, 0xaf, 0xb2, 0x51, 0x99, 0xc1, 0x36, 0x2f, 0xaf, 0x2f, 0x01, 0x50, 0x21, + 0xa0, 0x8d, 0x77, 0x6b, 0x91, 0x99, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0xad, 0x6e, 0x72, + 0x4a, 0xec, 0x03, 0xd8, 0x1c, 0x6e, 0xb7, 0x0d, 0x7e, 0xe1, 0x68, 0xf4, 0x6c, 0xb6, 0xcc, 0xb4, 0x41, 0x27, 0x37, + 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, 0xc9, 0xf4, 0x65, 0x06, 0x7c, 0x1e, 0x7b, 0x2b, 0x42, 0x9f, 0xe5, 0x6a, + 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x32, 0x23, 0xbe, 0x4d, + 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x56, 0x78, 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x12, 0x85, 0xa8, + 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x9a, 0x3a, 0x73, 0x19, 0x5f, 0xb8, + 0xf7, 0xd2, 0x97, 0x99, 0xdc, 0x4a, 0x00, 0x45, 0x52, 0xb5, 0xff, 0xf2, 0x19, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, + 0xe8, 0xfd, 0x02, 0x35, 0x39, 0x82, 0x80, 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, + 0x6d, 0x54, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, 0x4f, 0xd7, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, + 0x1b, 0x21, 0xeb, 0x97, 0x66, 0x17, 0x7e, 0x2e, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, + 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, 0x1e, 0x73, 0x82, 0x3f, 0x3d, 0x78, 0x4a, 0xe8, 0xad, 0x9c, 0x96, 0x08, + 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, + 0x6c, 0xd9, 0x6f, 0x4d, 0xd9, 0x92, 0x6c, 0x04, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbc, 0xdf, 0xa0, + 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, + 0x9c, 0x85, 0xed, 0x76, 0x42, 0x7c, 0x09, 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, + 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x20, 0xa0, 0xc7, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x8e, 0xf9, 0x20, 0x18, + 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x57, 0x05, 0x43, 0x58, 0xa1, 0xbf, + 0x52, 0x36, 0xf9, 0xe6, 0xef, 0x6e, 0x7e, 0xcf, 0xb5, 0x98, 0x1d, 0x84, 0xe2, 0xf6, 0x7a, 0x02, 0xc4, 0xaf, 0xe2, + 0x57, 0x60, 0x5d, 0xad, 0x25, 0xde, 0x6e, 0x7a, 0xfe, 0x14, 0xbe, 0x1c, 0xdd, 0x7e, 0x52, 0x9a, 0x4f, 0x20, 0x48, + 0x8d, 0x93, 0x94, 0xbb, 0xef, 0x3e, 0x4a, 0x57, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xdd, 0x5b, 0xc9, 0x59, 0x53, 0xf8, + 0x8f, 0x75, 0xbe, 0xc7, 0xd8, 0x21, 0xf2, 0x14, 0xa7, 0xbf, 0x01, 0x86, 0x7d, 0xe7, 0xdf, 0xca, 0xac, 0x21, 0xd1, + 0xb9, 0xfa, 0x08, 0xe8, 0xff, 0x58, 0x8f, 0xdf, 0x31, 0x4a, 0xfa, 0x92, 0x38, 0x47, 0xb8, 0x22, 0x5e, 0xa2, 0xa9, + 0x5e, 0x6f, 0x5c, 0xd3, 0x4f, 0x85, 0x79, 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0x9b, 0x68, + 0x08, 0xba, 0x7f, 0xc7, 0xbd, 0xf1, 0x9b, 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, + 0x1b, 0xc6, 0x82, 0xb5, 0x50, 0xe6, 0xab, 0x69, 0x30, 0xdb, 0xd4, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x6d, 0x9c, 0xb0, + 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, + 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x71, 0x05, 0xbb, 0xcc, + 0x57, 0x52, 0xfc, 0xd9, 0x92, 0x64, 0x63, 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, + 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, + 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x63, 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0xa7, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, + 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, 0x53, 0xba, 0x9b, 0xd3, 0xfe, 0xab, 0x82, 0x0c, 0xff, 0x02, 0xef, 0xae, + 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, + 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, 0xe4, 0xad, 0xc6, 0x6c, 0xca, 0xfd, 0x0f, 0x60, 0x44, 0xb5, 0xb4, 0xdd, + 0x0e, 0xf8, 0x72, 0x84, 0x06, 0xdb, 0xa9, 0x1b, 0xec, 0x7e, 0xdf, 0xa4, 0x1d, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, + 0x51, 0xda, 0x2c, 0x95, 0x41, 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x92, 0xc6, 0x56, + 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, + 0xed, 0x36, 0x84, 0x08, 0x1c, 0xc5, 0x70, 0x32, 0x0b, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0xa9, 0x98, + 0x67, 0x0b, 0x85, 0xd8, 0xe3, 0xef, 0xa4, 0xdf, 0x0a, 0xc5, 0x29, 0xf7, 0x7e, 0x13, 0x64, 0xf3, 0x7b, 0x8a, 0x31, + 0x07, 0x9d, 0x66, 0x33, 0x03, 0x09, 0xeb, 0x71, 0x45, 0xd4, 0x3a, 0xb2, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, + 0x75, 0x8b, 0x27, 0xd6, 0x33, 0x7a, 0x0f, 0x2a, 0x41, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x3e, 0x89, 0x50, 0x52, + 0x4e, 0x9a, 0xcc, 0x8c, 0x15, 0x0d, 0x16, 0x20, 0x24, 0x8d, 0xcb, 0xea, 0x8d, 0x4c, 0xb3, 0x8b, 0x0c, 0x10, 0x13, + 0x9c, 0xff, 0x9c, 0x6c, 0xbc, 0x79, 0xae, 0xe6, 0xa5, 0x2b, 0x71, 0x66, 0x61, 0x3e, 0xba, 0xde, 0xd2, 0x82, 0x44, + 0x05, 0xd0, 0x28, 0x5f, 0xcb, 0xf3, 0xd3, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x65, 0x3b, 0xc4, 0x8f, 0x58, 0x45, + 0xbc, 0xd3, 0xba, 0x52, 0x22, 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xa8, 0xe1, 0x83, 0x30, 0x83, 0x4e, + 0xf2, 0x83, 0x9e, 0xd1, 0xb1, 0x35, 0x90, 0xf4, 0xb5, 0x08, 0xbe, 0x46, 0x47, 0x3a, 0x51, 0xa6, 0x91, 0x98, 0x42, + 0xa2, 0x5f, 0x2f, 0xb4, 0xc6, 0x32, 0xca, 0xbe, 0x22, 0xff, 0x7b, 0xdd, 0xbd, 0xdf, 0xc4, 0x76, 0x0b, 0x93, 0xec, + 0x79, 0x5c, 0xc1, 0xa6, 0x46, 0xad, 0x10, 0xce, 0xce, 0x71, 0x85, 0xda, 0xb1, 0x5e, 0x58, 0x02, 0x79, 0x00, 0x5b, + 0x91, 0x06, 0x65, 0x90, 0xec, 0x53, 0x31, 0x17, 0x0b, 0x27, 0xca, 0x91, 0x0a, 0xef, 0x4b, 0x8e, 0x52, 0x0e, 0x57, + 0xb1, 0xb0, 0x60, 0xc8, 0xaf, 0x8e, 0x2e, 0x0a, 0x79, 0x05, 0x92, 0x12, 0xc3, 0x50, 0x59, 0x5e, 0x17, 0x57, 0x6d, + 0x49, 0x68, 0xef, 0x0c, 0x40, 0x58, 0x0a, 0x10, 0xbc, 0x34, 0x6a, 0x88, 0xd9, 0x46, 0xed, 0xae, 0xe8, 0x5e, 0x72, + 0x40, 0x9d, 0xee, 0xda, 0xad, 0x37, 0x65, 0x9b, 0x6d, 0xc5, 0x85, 0x7f, 0x42, 0xe9, 0xc7, 0x7c, 0x50, 0xf8, 0x54, + 0x02, 0x37, 0xbe, 0xda, 0x64, 0xd9, 0xc5, 0x1d, 0x2e, 0xfd, 0xaa, 0x31, 0x7e, 0xfd, 0x7e, 0x4f, 0x2d, 0x84, 0x46, + 0x2a, 0x30, 0xdf, 0x3e, 0x33, 0x55, 0x19, 0x4d, 0xa9, 0xbd, 0x04, 0x57, 0xce, 0x7e, 0x04, 0x15, 0x71, 0x5d, 0x91, + 0xc9, 0xd4, 0x00, 0xed, 0x79, 0x59, 0xe1, 0x56, 0x16, 0xe0, 0xb1, 0x13, 0x90, 0xed, 0x96, 0x87, 0x81, 0x3e, 0x74, + 0x02, 0x7f, 0x4b, 0x9e, 0x22, 0xb3, 0x66, 0x1f, 0x7f, 0xd1, 0x82, 0x7f, 0x6c, 0xc1, 0xcf, 0x28, 0xee, 0xb4, 0x32, + 0xff, 0x56, 0x5a, 0xb7, 0xb8, 0x7f, 0x27, 0xd3, 0x84, 0xa2, 0x32, 0xa1, 0xf6, 0x2b, 0xfd, 0x97, 0x09, 0x96, 0xa4, + 0xb2, 0x7f, 0x90, 0xf0, 0xc1, 0xac, 0xf1, 0xc4, 0x1a, 0x4f, 0x86, 0xd3, 0xad, 0x34, 0x0c, 0x01, 0x0a, 0xfd, 0xbc, + 0xcc, 0x15, 0xd5, 0xcf, 0xbf, 0xac, 0xf9, 0x9a, 0x37, 0x5b, 0x6c, 0x93, 0x1e, 0x68, 0xb0, 0x97, 0x47, 0x53, 0x0a, + 0x27, 0x51, 0xe7, 0x46, 0xa2, 0x2e, 0x6a, 0x96, 0xa1, 0x3a, 0xc1, 0xab, 0x79, 0xaa, 0x87, 0xbd, 0x99, 0x88, 0xd6, + 0x4a, 0xca, 0x12, 0x03, 0xd6, 0x3a, 0xf2, 0x90, 0xdc, 0xad, 0x75, 0xdc, 0x69, 0xa8, 0x4b, 0x53, 0x28, 0x01, 0x56, + 0xb8, 0x00, 0x47, 0xd0, 0xcf, 0x45, 0xc8, 0xe1, 0x9a, 0xaa, 0xf4, 0x0b, 0x9a, 0x92, 0x27, 0x9e, 0xa2, 0x56, 0x2b, + 0xd2, 0xed, 0x47, 0x39, 0x76, 0xc3, 0x37, 0x4e, 0xc8, 0x89, 0x11, 0xfa, 0xbb, 0x63, 0x29, 0x67, 0x68, 0xf1, 0xa0, + 0x4e, 0xb0, 0x5e, 0xde, 0x52, 0xa0, 0x98, 0xa3, 0xcb, 0xaa, 0x6b, 0x5e, 0xa3, 0xed, 0xcb, 0xb2, 0xdf, 0xcf, 0x6d, + 0x3d, 0x29, 0x3b, 0xda, 0x2c, 0xcd, 0x3e, 0x44, 0xc5, 0x14, 0xee, 0xfa, 0x44, 0xf3, 0x57, 0xa1, 0xbe, 0x6a, 0xcb, + 0x9c, 0x8f, 0x38, 0xe2, 0x62, 0xe4, 0xa4, 0xfe, 0x45, 0x4d, 0xbd, 0x12, 0xf7, 0xab, 0x4a, 0xbe, 0x13, 0xc6, 0x8a, + 0xd1, 0x01, 0xf5, 0xa7, 0x4a, 0xe5, 0xfd, 0xb2, 0x00, 0xb8, 0x27, 0xc1, 0x3e, 0x81, 0x7d, 0x85, 0x46, 0xf8, 0x6d, + 0x09, 0xf8, 0x37, 0x8a, 0x1b, 0xb0, 0x0a, 0x0c, 0x30, 0x9a, 0x6c, 0xcf, 0x69, 0x02, 0x07, 0x9c, 0xd0, 0x2a, 0x0a, + 0x2a, 0xcc, 0xd0, 0x50, 0x5b, 0x18, 0x3d, 0x45, 0x19, 0xb7, 0xca, 0xec, 0xdd, 0x18, 0x3b, 0x2d, 0xf0, 0x1a, 0xfe, + 0x7c, 0x5e, 0xe8, 0x61, 0xa3, 0x0e, 0xd2, 0xa3, 0x93, 0x98, 0xfe, 0xb8, 0x85, 0x93, 0x9b, 0x85, 0xb3, 0xac, 0x59, + 0x02, 0xdd, 0x81, 0x0b, 0x62, 0xdc, 0xef, 0xe7, 0x70, 0x64, 0x9a, 0x91, 0x2f, 0x58, 0x4e, 0x63, 0xb6, 0xa4, 0xda, + 0xd3, 0xee, 0xb2, 0x0a, 0x73, 0xba, 0xb4, 0x32, 0xde, 0x94, 0x81, 0xca, 0x68, 0xbb, 0x0d, 0xe1, 0x4f, 0xb7, 0xb5, + 0x4b, 0x3a, 0x5f, 0x42, 0x06, 0xf8, 0x03, 0x12, 0x51, 0xc4, 0xbe, 0xfe, 0xb7, 0x1a, 0xa7, 0xf4, 0x44, 0x69, 0xcd, + 0x12, 0xba, 0x66, 0xba, 0x7e, 0x7a, 0xc1, 0xd6, 0x8d, 0xa5, 0xb0, 0xdd, 0x86, 0xcd, 0x04, 0xa6, 0x39, 0x57, 0x32, + 0xbd, 0x40, 0x9d, 0x14, 0x50, 0xb1, 0xf0, 0x02, 0x97, 0x5f, 0x4a, 0x28, 0x34, 0x77, 0xbe, 0x5c, 0x18, 0x25, 0x26, + 0xb4, 0x4a, 0x7e, 0xf9, 0x50, 0x99, 0xaf, 0x8d, 0x47, 0xdc, 0xbf, 0xd2, 0x30, 0x31, 0x45, 0xa2, 0x42, 0x74, 0xf6, + 0x1b, 0xc8, 0x72, 0x04, 0xe0, 0x58, 0x9e, 0xca, 0x9a, 0xfe, 0x98, 0x42, 0x1c, 0x74, 0x68, 0xd0, 0xbb, 0x42, 0x5e, + 0x65, 0x25, 0x0f, 0xf1, 0x9e, 0xe0, 0x69, 0x46, 0xef, 0x37, 0xf8, 0xd0, 0xd6, 0x1e, 0x3d, 0x41, 0x36, 0x9e, 0x72, + 0xbf, 0xfe, 0x4e, 0x84, 0x73, 0x88, 0x56, 0xb9, 0xa0, 0x5a, 0x5d, 0xed, 0x00, 0xa8, 0x3c, 0xdb, 0xab, 0x47, 0x70, + 0xba, 0xe9, 0xeb, 0x5b, 0x15, 0x3a, 0x73, 0x00, 0x69, 0x0f, 0xc9, 0xba, 0xe6, 0x7a, 0x07, 0xb8, 0x23, 0xb1, 0x5a, + 0x03, 0x8d, 0x75, 0x5b, 0xb3, 0xd3, 0x1e, 0xc5, 0x63, 0x22, 0x33, 0x63, 0x91, 0x62, 0xcc, 0xdd, 0x3a, 0x2d, 0x8a, + 0x36, 0x68, 0x86, 0xb0, 0x7b, 0xd7, 0xe1, 0xeb, 0x56, 0x84, 0xf5, 0xfb, 0x6d, 0x5f, 0x60, 0x34, 0x8c, 0xb9, 0x76, + 0xcf, 0x33, 0x74, 0xc3, 0x06, 0xdb, 0xc8, 0x79, 0x88, 0x7c, 0x98, 0xa9, 0x03, 0x51, 0xd6, 0xd6, 0x80, 0xed, 0x11, + 0xd7, 0x9b, 0x56, 0xf1, 0xf3, 0x2a, 0xe6, 0x6c, 0xcf, 0x1a, 0xa7, 0xb4, 0xbe, 0xc6, 0x35, 0xc7, 0x55, 0x21, 0xa2, + 0xb6, 0x9e, 0xf1, 0x30, 0xec, 0x7c, 0x81, 0x3b, 0xb3, 0xc2, 0xe0, 0x45, 0x58, 0x2a, 0xd9, 0xa9, 0x5c, 0x7f, 0x0e, + 0x5b, 0x1c, 0xa4, 0xf2, 0xa5, 0xd7, 0xdf, 0x7f, 0xf9, 0xe2, 0x0b, 0x74, 0x53, 0x73, 0x7e, 0x04, 0x41, 0x26, 0xd0, + 0x21, 0x4b, 0xa9, 0x1e, 0xbf, 0x2b, 0x80, 0xda, 0xc3, 0x3c, 0x7c, 0x57, 0x30, 0x11, 0x5f, 0x67, 0x97, 0x71, 0x25, + 0x8b, 0xd1, 0x35, 0x17, 0xa9, 0x2c, 0xac, 0xd4, 0x38, 0x38, 0x5e, 0xad, 0x72, 0x1e, 0x80, 0xa9, 0xbc, 0x65, 0x94, + 0x6d, 0x65, 0x99, 0x1e, 0x5c, 0x2d, 0x4f, 0xaf, 0xb4, 0xe8, 0xbc, 0xbc, 0xbe, 0x0c, 0x22, 0xfc, 0x75, 0x6e, 0x7e, + 0x5c, 0xc5, 0xe5, 0xc7, 0x20, 0xb2, 0x36, 0x75, 0xe6, 0x07, 0x4a, 0xe5, 0xc1, 0x7f, 0x0a, 0x64, 0xba, 0xdf, 0x15, + 0x60, 0x99, 0x6d, 0x2b, 0x3e, 0x8c, 0xb1, 0xd6, 0xe1, 0x84, 0xcc, 0x54, 0x89, 0xde, 0xbb, 0x64, 0x5d, 0x80, 0xb5, + 0x9f, 0xc2, 0x32, 0x56, 0xb9, 0x66, 0x58, 0x99, 0xaa, 0xc8, 0xcc, 0xca, 0x9a, 0xed, 0x87, 0xd6, 0x89, 0x66, 0x8e, + 0xde, 0x02, 0xfa, 0x81, 0xec, 0x5f, 0xd2, 0x72, 0xcd, 0x3c, 0x1f, 0x9b, 0xc6, 0xeb, 0x47, 0xfb, 0x97, 0x6e, 0xc1, + 0xde, 0xda, 0x3b, 0x39, 0x0a, 0x13, 0xc1, 0xb3, 0xd6, 0x8c, 0x2f, 0xf2, 0xac, 0x80, 0x95, 0x33, 0x19, 0x8f, 0xa9, + 0xb7, 0xb4, 0x5a, 0x37, 0x47, 0x87, 0xe4, 0x9a, 0x3d, 0xae, 0x1e, 0x73, 0xb2, 0xcf, 0x5b, 0xa6, 0xb6, 0x6d, 0xeb, + 0x38, 0x4f, 0x93, 0xaf, 0x4c, 0xf7, 0xc5, 0xda, 0x46, 0x44, 0x57, 0xce, 0x7d, 0xce, 0x2b, 0xb8, 0xf5, 0x4d, 0x69, + 0xe8, 0xb5, 0x04, 0x20, 0x3a, 0x6d, 0xc0, 0x5f, 0xb0, 0x72, 0x3d, 0xaa, 0x78, 0x59, 0x81, 0x84, 0x05, 0x45, 0x78, + 0x53, 0xec, 0x4d, 0xe1, 0x6e, 0x9c, 0x9e, 0xc3, 0x0e, 0x5c, 0x4c, 0xd1, 0x1d, 0x27, 0x26, 0xb3, 0xd2, 0x68, 0x45, + 0x23, 0xfd, 0xcb, 0xf5, 0x25, 0xd6, 0x7d, 0xd1, 0xca, 0x3c, 0x9b, 0x53, 0x61, 0xb1, 0xbb, 0xca, 0xa5, 0x13, 0xf5, + 0x5b, 0x26, 0x5c, 0xb9, 0x12, 0x04, 0x64, 0x5a, 0xb0, 0x5e, 0x61, 0x76, 0x91, 0x5c, 0x03, 0x21, 0x03, 0xc3, 0xd7, + 0x60, 0x2d, 0x4a, 0x6e, 0xac, 0x60, 0xbd, 0x7b, 0xbe, 0x4e, 0x10, 0x52, 0xf0, 0xc0, 0x4d, 0xd0, 0x0f, 0xad, 0x9b, + 0xb7, 0xa3, 0x44, 0x19, 0xc4, 0xe3, 0xd6, 0x4e, 0x39, 0x48, 0x20, 0x00, 0xf7, 0x54, 0x85, 0xe0, 0x50, 0x20, 0xeb, + 0xe0, 0x6a, 0xc6, 0x11, 0x5c, 0x5d, 0x39, 0x73, 0x71, 0x03, 0xb0, 0xae, 0xfc, 0xb9, 0x6c, 0x70, 0x61, 0x3d, 0xa2, + 0xca, 0x9c, 0x71, 0x8a, 0x41, 0x8c, 0x2c, 0x41, 0x5f, 0x59, 0x4a, 0x7b, 0x09, 0x9a, 0xc6, 0x2b, 0xb6, 0x52, 0x3e, + 0x00, 0xf4, 0x9c, 0xad, 0x94, 0xb1, 0x3f, 0x7e, 0x7d, 0xc6, 0x56, 0x5a, 0x1a, 0x3c, 0xbd, 0x9a, 0x9d, 0xcf, 0xce, + 0x06, 0xec, 0x20, 0x0a, 0xb5, 0x01, 0x43, 0xe0, 0x90, 0xf8, 0x83, 0x41, 0xa8, 0xf1, 0x4e, 0x06, 0x2a, 0x20, 0x16, + 0xf1, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, 0x43, 0x0c, 0x7e, 0xd5, 0x7c, 0x41, 0x02, 0x42, 0x4d, 0x69, 0xe8, 0xf2, + 0x18, 0x0e, 0x27, 0x7b, 0x13, 0x48, 0xc5, 0xcc, 0x4c, 0x15, 0xc6, 0xc6, 0x24, 0x82, 0x78, 0xa7, 0x9d, 0xf5, 0x42, + 0xb9, 0xdd, 0x35, 0x1a, 0xc8, 0x95, 0xc1, 0x17, 0x55, 0x3c, 0xd9, 0x1b, 0x76, 0x55, 0x8c, 0xa3, 0x70, 0x6d, 0x94, + 0x6f, 0x67, 0x87, 0x00, 0x5e, 0x7b, 0x36, 0xf4, 0xe5, 0x12, 0x67, 0xfb, 0x4f, 0xc9, 0xe3, 0xa7, 0x84, 0x9e, 0xb1, + 0xb3, 0xaf, 0x9e, 0xd2, 0x33, 0x45, 0x4e, 0xf6, 0x26, 0xd1, 0x35, 0xb3, 0x98, 0x2f, 0x07, 0xaa, 0x09, 0xf4, 0x72, + 0xb4, 0x16, 0x6a, 0x81, 0x69, 0x87, 0xa6, 0xf0, 0xdb, 0xf1, 0x5e, 0x30, 0xb8, 0x6e, 0x37, 0xfd, 0xba, 0xdd, 0x56, + 0xcf, 0xab, 0x6b, 0xef, 0x20, 0xda, 0x2d, 0x66, 0xf2, 0xf7, 0xf1, 0x9e, 0x9b, 0x03, 0xac, 0xef, 0xe1, 0x31, 0x31, + 0x4d, 0xda, 0x19, 0x15, 0xbf, 0xa6, 0x27, 0xd8, 0x87, 0x66, 0x91, 0x1d, 0x7d, 0x18, 0xfe, 0x5b, 0x9d, 0xa8, 0xcf, + 0xbe, 0x3a, 0x00, 0x72, 0x04, 0x32, 0x50, 0x2c, 0x11, 0xcc, 0x70, 0xa0, 0x29, 0xa0, 0x20, 0xd3, 0xe3, 0x4e, 0xf5, + 0xf0, 0xab, 0x51, 0x53, 0x33, 0x72, 0x0d, 0x53, 0x83, 0x6d, 0xc1, 0x0f, 0x54, 0x37, 0xf4, 0x37, 0x1a, 0xdd, 0x48, + 0x3b, 0x99, 0x99, 0x97, 0xd4, 0xc6, 0x75, 0xbb, 0x86, 0x00, 0xc6, 0x0e, 0x5e, 0x50, 0xb2, 0xaf, 0x0f, 0x2f, 0xf7, + 0x70, 0x15, 0x01, 0x4a, 0x16, 0x0b, 0xbe, 0x1e, 0x5c, 0xea, 0xcd, 0xbd, 0x17, 0x90, 0xc1, 0xd7, 0xc1, 0xd1, 0xd7, + 0x03, 0x39, 0x08, 0x0e, 0xf7, 0x2f, 0x8f, 0x02, 0x67, 0xdc, 0x0f, 0x21, 0x1e, 0x55, 0x45, 0x31, 0x13, 0xa6, 0x8a, + 0xc4, 0xd6, 0x9e, 0xdb, 0x7a, 0x95, 0xf1, 0x19, 0x4d, 0xa7, 0x16, 0xf9, 0x3b, 0x4c, 0x59, 0x6c, 0x7e, 0x07, 0x13, + 0x7e, 0x15, 0x44, 0x2e, 0x08, 0xea, 0x2c, 0x8f, 0x62, 0xba, 0x64, 0xb7, 0x22, 0x4c, 0x69, 0xb2, 0x9f, 0x13, 0x12, + 0x85, 0x4b, 0x05, 0x9e, 0xa7, 0x5e, 0x27, 0x10, 0xc7, 0xd5, 0x7d, 0x7e, 0x2b, 0xc2, 0x25, 0xcd, 0xf7, 0x13, 0xd2, + 0x2a, 0xc2, 0x45, 0x64, 0xd9, 0xd4, 0xf4, 0x82, 0x85, 0x2b, 0x7a, 0x09, 0xcc, 0x94, 0x5c, 0x87, 0x97, 0xc0, 0xe5, + 0xad, 0xe7, 0xab, 0x05, 0xbb, 0x6c, 0x48, 0xdf, 0x0c, 0x5f, 0x7c, 0x61, 0x7d, 0xf2, 0x80, 0x87, 0x74, 0x7e, 0x78, + 0x29, 0xd8, 0x00, 0x5c, 0x67, 0xfc, 0xe6, 0x3b, 0x79, 0xab, 0xe7, 0xa5, 0x3d, 0xc5, 0x38, 0x33, 0xed, 0xc4, 0xa4, + 0x9d, 0x90, 0xfb, 0xf7, 0xed, 0x4d, 0x6c, 0x4e, 0xf6, 0x32, 0x5a, 0x2b, 0x97, 0x55, 0xcb, 0x90, 0x14, 0x6b, 0x86, + 0xfc, 0x3d, 0x4a, 0x4e, 0xad, 0xc0, 0x93, 0x5d, 0xf0, 0x2a, 0x59, 0xfa, 0x07, 0x95, 0xb5, 0x1a, 0xb0, 0xc7, 0x88, + 0x65, 0xa1, 0x70, 0xec, 0xdf, 0x64, 0xac, 0x58, 0xfb, 0x02, 0x8d, 0x18, 0xb9, 0xb7, 0x37, 0x19, 0xf3, 0x62, 0xae, + 0x26, 0x6b, 0x2f, 0x54, 0x9d, 0x97, 0x9e, 0xb7, 0x78, 0x2f, 0xa7, 0xd4, 0x30, 0x12, 0xd1, 0xbd, 0xb1, 0x32, 0xa3, + 0x54, 0x89, 0x5a, 0x83, 0x46, 0x04, 0x1b, 0xbb, 0xe0, 0x97, 0xe0, 0x84, 0xca, 0x3d, 0x75, 0xb6, 0x6f, 0xa7, 0x54, + 0x7a, 0xc0, 0xb2, 0xd4, 0xa8, 0xca, 0xdd, 0x32, 0x93, 0xac, 0x1a, 0x04, 0xa3, 0x3f, 0x4b, 0x29, 0x66, 0x78, 0x67, + 0x64, 0xc1, 0x14, 0xac, 0x04, 0x55, 0x2d, 0xc3, 0x72, 0xc8, 0x51, 0x8b, 0x67, 0x7c, 0x52, 0xa5, 0xfe, 0xd1, 0x11, + 0x24, 0x77, 0xb9, 0x6e, 0x05, 0xc9, 0x7d, 0x3a, 0x7e, 0xaa, 0x07, 0x3a, 0x5d, 0x6b, 0xc7, 0x43, 0x9f, 0xdf, 0x46, + 0x7c, 0x6d, 0xdd, 0x7b, 0xaa, 0xb5, 0x0a, 0x65, 0xa0, 0xc5, 0x8a, 0xca, 0x95, 0x5a, 0xd2, 0xfb, 0x5d, 0x04, 0xc0, + 0x22, 0x36, 0x66, 0xe3, 0x5d, 0xdb, 0xac, 0x10, 0x34, 0xba, 0xec, 0x68, 0x13, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, + 0xd0, 0xf8, 0x88, 0x95, 0xfd, 0x7e, 0x7e, 0x04, 0xf4, 0x54, 0x1b, 0x31, 0x15, 0x70, 0xe4, 0x7f, 0x69, 0x45, 0xa6, + 0x28, 0xb0, 0x59, 0x53, 0x77, 0x6b, 0x2c, 0x23, 0xd1, 0x97, 0x29, 0x5d, 0x9e, 0xf0, 0x0c, 0x98, 0xd6, 0xeb, 0x96, + 0xe3, 0xca, 0xae, 0xe2, 0xc8, 0x53, 0x61, 0x59, 0x71, 0x5e, 0x85, 0xe3, 0xad, 0xc7, 0x37, 0xd8, 0x37, 0x6c, 0xda, + 0x85, 0x3f, 0x84, 0xb0, 0x10, 0xde, 0x64, 0x70, 0x1b, 0xd1, 0x76, 0x12, 0xa8, 0xbc, 0x31, 0xd7, 0x09, 0x65, 0x73, + 0xbb, 0x5e, 0x7b, 0x06, 0xe9, 0xc4, 0x1c, 0x28, 0xd5, 0x08, 0x5a, 0xa3, 0x59, 0x50, 0x35, 0xe2, 0x91, 0xe3, 0xe1, + 0x9d, 0x41, 0xac, 0x96, 0x2f, 0x69, 0x2a, 0x45, 0x03, 0x30, 0x2e, 0x80, 0xcb, 0xd3, 0xaf, 0xef, 0x7f, 0x3e, 0xe5, + 0x71, 0x91, 0x2c, 0xdf, 0xc5, 0x45, 0x7c, 0x55, 0x86, 0x1b, 0x35, 0x46, 0x71, 0x4d, 0xa6, 0x62, 0xc0, 0xa4, 0x59, + 0x49, 0xcd, 0x5d, 0xa9, 0x09, 0x31, 0xd6, 0x99, 0xac, 0xcb, 0x4a, 0x5e, 0x35, 0x2a, 0x5d, 0x17, 0x19, 0x7e, 0xdc, + 0xf2, 0x39, 0xdd, 0x07, 0x20, 0x4f, 0xe3, 0x42, 0x1a, 0x49, 0x5d, 0x88, 0x31, 0x17, 0xf1, 0xba, 0x3e, 0x1e, 0x37, + 0xba, 0x5e, 0xb2, 0x67, 0xe3, 0x27, 0xd3, 0x37, 0x59, 0x98, 0x0d, 0x04, 0x19, 0x55, 0x4b, 0x2e, 0x5a, 0xa6, 0x9c, + 0xca, 0x24, 0x00, 0x7d, 0x3c, 0x7b, 0x8c, 0x1d, 0x8c, 0xc7, 0x64, 0xd3, 0x16, 0x0f, 0xf0, 0x70, 0xb9, 0x0e, 0x0b, + 0x32, 0xd3, 0x75, 0x44, 0x81, 0xe0, 0xb7, 0x55, 0x00, 0x48, 0x8e, 0xb6, 0x2a, 0xc3, 0xa5, 0xb1, 0x67, 0xe3, 0x09, + 0x95, 0xd8, 0xed, 0x90, 0xd4, 0x5e, 0x85, 0x6e, 0xe6, 0xa5, 0xef, 0x51, 0x24, 0x8d, 0xcb, 0xd2, 0x4e, 0xa5, 0x52, + 0xed, 0x99, 0x99, 0xeb, 0x1a, 0xc4, 0x60, 0x08, 0x75, 0xdd, 0xa5, 0x57, 0xf7, 0x6e, 0x73, 0xad, 0xd9, 0x0e, 0x78, + 0xaf, 0x41, 0x33, 0x94, 0xbc, 0xc5, 0xbc, 0x75, 0x45, 0xd4, 0x74, 0xb5, 0x06, 0xb3, 0x62, 0x94, 0x2d, 0x45, 0xe9, + 0x9a, 0x82, 0x52, 0x30, 0xba, 0x58, 0x7b, 0x0b, 0xf7, 0x8d, 0x6c, 0x5c, 0x58, 0x32, 0xbd, 0x5a, 0x94, 0x94, 0x50, + 0xdd, 0x54, 0x8c, 0x94, 0x30, 0x52, 0x1a, 0x9e, 0xca, 0xf7, 0x02, 0x8f, 0xf3, 0x3c, 0x88, 0x5a, 0x5e, 0x60, 0xc7, + 0x15, 0x39, 0x06, 0x47, 0x2f, 0x93, 0xd3, 0x50, 0xe0, 0x1f, 0x33, 0x05, 0x62, 0x3a, 0x54, 0xf7, 0x1b, 0xdc, 0xfc, + 0xff, 0x28, 0x58, 0xe0, 0xf1, 0xad, 0x97, 0xb8, 0x8d, 0xfe, 0x51, 0xf8, 0xb4, 0xf4, 0xb9, 0xf4, 0x5d, 0x5d, 0x3c, + 0x69, 0x6f, 0x36, 0x4a, 0x96, 0x59, 0x9e, 0xbe, 0x95, 0x29, 0x07, 0x91, 0x19, 0x5a, 0x83, 0xb2, 0x23, 0xd1, 0xb8, + 0xe1, 0x81, 0x11, 0x63, 0xe3, 0xc6, 0xf7, 0x63, 0x06, 0xb2, 0x61, 0xb0, 0xfa, 0x66, 0xa9, 0x4c, 0xd6, 0x57, 0x80, + 0x29, 0xa2, 0xe4, 0x27, 0x2f, 0x73, 0x0e, 0x4f, 0xa1, 0xbe, 0x7e, 0x81, 0xdb, 0x5c, 0xe9, 0xfb, 0x9c, 0xff, 0x98, + 0xd1, 0x1f, 0x11, 0xe8, 0x24, 0x5e, 0x81, 0xdc, 0xe3, 0x39, 0xd4, 0x8d, 0x30, 0xb5, 0x1c, 0x83, 0x03, 0x21, 0x1a, + 0x88, 0xa8, 0x58, 0xa0, 0xa0, 0x2e, 0x0c, 0xb0, 0x86, 0xba, 0x60, 0x0e, 0xcf, 0x73, 0x99, 0x7c, 0x9c, 0x1a, 0x9f, + 0xf9, 0x61, 0x8c, 0x31, 0x93, 0x83, 0x41, 0x58, 0xcd, 0x82, 0xe1, 0x78, 0x34, 0x39, 0x78, 0x06, 0xe7, 0x76, 0x30, + 0x0e, 0xc8, 0x20, 0xa8, 0xcb, 0x55, 0x2c, 0x68, 0x79, 0x7d, 0x69, 0xcb, 0xc0, 0x8f, 0xeb, 0x60, 0xf0, 0x8f, 0xc2, + 0x53, 0xbc, 0x83, 0xe6, 0xe4, 0x4c, 0x86, 0x60, 0x63, 0xbf, 0x26, 0x20, 0x29, 0xeb, 0x69, 0x7e, 0x52, 0x1f, 0x6e, + 0x4c, 0x69, 0xff, 0xcc, 0xe1, 0x05, 0x87, 0x1d, 0x12, 0x28, 0x90, 0xc6, 0xd3, 0x6c, 0xf4, 0x5a, 0x29, 0x72, 0xdf, + 0x15, 0x1c, 0xee, 0xcc, 0x3d, 0x67, 0x7a, 0xe4, 0x14, 0x12, 0xcd, 0x2c, 0xe0, 0x46, 0xfe, 0x5a, 0x5c, 0xc7, 0x79, + 0x96, 0xee, 0x35, 0xdf, 0xec, 0x95, 0x77, 0xa2, 0x8a, 0x6f, 0x47, 0x81, 0xb1, 0x26, 0xe4, 0xbe, 0xea, 0x09, 0xd0, + 0x13, 0x60, 0x0b, 0x80, 0x01, 0xf1, 0x8e, 0x99, 0xc9, 0x8c, 0x47, 0xe0, 0x11, 0xd8, 0xf4, 0x81, 0x2c, 0xee, 0x9c, + 0x4b, 0x92, 0xbf, 0x99, 0x4a, 0x7b, 0xd5, 0x2b, 0x77, 0x0a, 0xb2, 0x5e, 0x6d, 0xe5, 0xae, 0x5b, 0x9f, 0x7d, 0xd3, + 0xe1, 0x15, 0x78, 0x2e, 0xc1, 0x2d, 0xb2, 0xdf, 0x6f, 0x0a, 0x2a, 0x85, 0x51, 0x11, 0xef, 0x24, 0xd7, 0xe8, 0xdf, + 0xee, 0x8d, 0x8d, 0x22, 0xb9, 0xe5, 0xc3, 0x03, 0xa8, 0x33, 0x79, 0x57, 0xdc, 0xce, 0x21, 0x6a, 0xeb, 0x6e, 0x3c, + 0xb0, 0xda, 0xa0, 0x5d, 0xd6, 0x1c, 0xc1, 0x85, 0x17, 0x7b, 0x19, 0x8c, 0x05, 0xce, 0xca, 0x48, 0xa9, 0x71, 0x0d, + 0xa9, 0x05, 0x9f, 0xe4, 0xe9, 0x3d, 0x64, 0xa9, 0x27, 0x41, 0x91, 0xe3, 0x59, 0x0c, 0x99, 0xc6, 0xdb, 0xc0, 0xe3, + 0x77, 0x32, 0x04, 0x69, 0xda, 0x76, 0xdb, 0x1c, 0x81, 0xb2, 0x7b, 0x60, 0x4a, 0x52, 0xd7, 0xc6, 0xd4, 0x40, 0x43, + 0xed, 0xa1, 0x46, 0x2a, 0xe2, 0xec, 0xe8, 0x0d, 0xe8, 0x10, 0xc1, 0xf7, 0x3b, 0xcd, 0xca, 0x8e, 0x17, 0x13, 0x82, + 0x27, 0xef, 0xcb, 0xdb, 0xac, 0xac, 0xca, 0xe8, 0x7d, 0x8a, 0x86, 0x50, 0x89, 0x14, 0xd1, 0x2b, 0x88, 0xa7, 0x57, + 0xe2, 0xef, 0x32, 0xfa, 0x39, 0xa5, 0x71, 0x9a, 0x62, 0xfa, 0x8b, 0x02, 0x7e, 0x3e, 0x07, 0x54, 0x47, 0xdc, 0x09, + 0xd1, 0xb9, 0x04, 0x7b, 0x35, 0x88, 0x66, 0x55, 0x71, 0xc0, 0xd0, 0x8c, 0x6e, 0x05, 0x45, 0x8c, 0x36, 0xcc, 0xfe, + 0x43, 0x81, 0x42, 0x21, 0x55, 0xcc, 0x77, 0xc2, 0x3e, 0x44, 0x3f, 0x62, 0x91, 0xc7, 0xef, 0x5e, 0x9b, 0x21, 0x8d, + 0xee, 0x24, 0xd5, 0x5b, 0x1b, 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xae, 0xe9, 0x59, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, + 0x4f, 0xbc, 0x7b, 0xfd, 0x5c, 0x59, 0x98, 0xbc, 0xc8, 0x40, 0x71, 0x70, 0xfc, 0xee, 0xf5, 0x1b, 0x99, 0xae, 0x73, + 0x1e, 0x9d, 0x49, 0x24, 0xad, 0xc7, 0xef, 0x5e, 0xff, 0x82, 0xe6, 0x5e, 0x3f, 0x17, 0xf0, 0xfe, 0x15, 0xf0, 0x96, + 0x51, 0xbc, 0x86, 0x3e, 0xa9, 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd5, 0x5a, 0x46, 0xbf, 0xa6, 0xb5, 0x27, 0xad, 0xfa, + 0x67, 0xe1, 0x53, 0x3b, 0x4f, 0xc0, 0x73, 0x9b, 0x67, 0xe2, 0x63, 0x64, 0x45, 0x3b, 0x41, 0xf4, 0xf5, 0xde, 0xed, + 0x55, 0x2e, 0xca, 0x08, 0x5f, 0x30, 0xb4, 0x0b, 0x8a, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0x46, 0x37, 0x4f, 0x46, 0xb2, + 0xb8, 0xdc, 0x9f, 0x7c, 0xfb, 0xed, 0xb7, 0xfb, 0xf8, 0x36, 0xf8, 0xba, 0xed, 0xf6, 0x5e, 0x11, 0x3e, 0x60, 0x01, + 0x22, 0x54, 0x7f, 0x0d, 0x57, 0x14, 0xd0, 0xc2, 0x0d, 0xbe, 0x0e, 0xbe, 0xd6, 0x87, 0xce, 0xd7, 0x87, 0xe5, 0xf5, + 0xa5, 0x2a, 0xbf, 0xab, 0xe4, 0x83, 0xf1, 0x78, 0xbc, 0x0f, 0x12, 0xa8, 0xaf, 0x07, 0x7c, 0x10, 0x1c, 0x05, 0x83, + 0x0c, 0x2e, 0x34, 0xe5, 0xf5, 0xe5, 0x51, 0xe0, 0x99, 0xe6, 0x36, 0x58, 0x44, 0x07, 0xe2, 0x12, 0xec, 0x5f, 0xd2, + 0xe0, 0xeb, 0x80, 0xb8, 0x94, 0xaf, 0x20, 0xe5, 0xab, 0x83, 0x67, 0x7e, 0xda, 0xff, 0x52, 0x69, 0x4f, 0xfc, 0xb4, + 0x43, 0x4c, 0x7b, 0xf2, 0xdc, 0x4f, 0x3b, 0x52, 0x69, 0x2f, 0xfd, 0xb4, 0xff, 0x5d, 0x0e, 0x20, 0x75, 0xcf, 0xb7, + 0xfe, 0x3b, 0xf7, 0x5a, 0x83, 0xa7, 0x50, 0x94, 0x5d, 0xc5, 0x97, 0x1c, 0x1a, 0x3d, 0xb8, 0xbd, 0xca, 0x69, 0x30, + 0xc0, 0xf6, 0x7a, 0x26, 0x21, 0xde, 0x07, 0x5f, 0xaf, 0x8b, 0x3c, 0x0c, 0xbe, 0x1e, 0x60, 0x21, 0x83, 0xaf, 0x03, + 0xf2, 0xb5, 0x31, 0x90, 0x11, 0x6c, 0x13, 0xb8, 0x50, 0xa4, 0x43, 0x1b, 0x20, 0xcc, 0x97, 0xc6, 0xd5, 0xf4, 0xaf, + 0xa2, 0x3b, 0x1b, 0xde, 0x12, 0x95, 0x9b, 0x6e, 0x50, 0xd3, 0x13, 0xf0, 0x4e, 0x80, 0x46, 0x45, 0xc1, 0x75, 0x5c, + 0x84, 0xc3, 0x61, 0x79, 0x7d, 0x49, 0xc0, 0x2e, 0x73, 0xc5, 0xe3, 0x2a, 0x0a, 0x84, 0x1c, 0xaa, 0x9f, 0x81, 0x8a, + 0x7c, 0x15, 0x20, 0x20, 0x12, 0xfc, 0x17, 0xd4, 0xf4, 0x9d, 0x64, 0x9b, 0x60, 0x78, 0xc3, 0xcf, 0x3f, 0x66, 0xd5, + 0x50, 0x89, 0x16, 0xaf, 0x05, 0x85, 0x1f, 0xf0, 0xd7, 0x55, 0x1d, 0xfd, 0x05, 0x6e, 0xdc, 0x4d, 0x0d, 0xfb, 0x3b, + 0xe9, 0x58, 0xd4, 0x77, 0x72, 0x9e, 0x2d, 0xa6, 0xad, 0x03, 0xfd, 0x44, 0x92, 0x6a, 0x9e, 0x0d, 0x82, 0x61, 0x30, + 0xe0, 0x0b, 0x76, 0x22, 0xe7, 0xdc, 0x33, 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x65, 0x03, 0xf0, 0x4d, 0x41, 0x7e, + 0x64, 0xff, 0xbf, 0xe7, 0x43, 0x14, 0x1e, 0x0e, 0x1e, 0xed, 0x93, 0x59, 0xb0, 0xba, 0x45, 0x8f, 0xce, 0x28, 0xc8, + 0xc4, 0x92, 0x17, 0x59, 0xe5, 0x2d, 0x95, 0xbb, 0x75, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x15, 0x8b, 0x40, 0x9d, + 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb0, 0x37, 0x1c, + 0xee, 0x05, 0x03, 0xa7, 0xce, 0x1d, 0x04, 0x7b, 0xc3, 0xe1, 0x51, 0xe0, 0xee, 0x43, 0xd9, 0xc8, 0xdd, 0x19, 0x69, + 0xc1, 0xfe, 0x59, 0x84, 0x25, 0x05, 0xf1, 0x98, 0xd4, 0xe2, 0x2f, 0x0d, 0x2e, 0x33, 0x00, 0xe8, 0x23, 0x25, 0x01, + 0x33, 0xb0, 0x32, 0x03, 0x08, 0xcd, 0x4d, 0x63, 0x76, 0x06, 0xcc, 0x23, 0x70, 0xcc, 0x23, 0x64, 0x1c, 0x00, 0xb1, + 0x24, 0xc0, 0xb9, 0x0b, 0xa2, 0x58, 0x17, 0xf2, 0x08, 0x40, 0xef, 0xf1, 0x27, 0x31, 0xa5, 0x60, 0x92, 0x8e, 0x55, + 0x08, 0x82, 0x38, 0x3e, 0xbb, 0x16, 0xad, 0xc9, 0x59, 0xa2, 0x83, 0x19, 0x49, 0x80, 0x0d, 0x31, 0xb0, 0x73, 0x70, + 0x3f, 0x07, 0xa5, 0x87, 0xd5, 0x3b, 0x21, 0x17, 0x7c, 0xc7, 0x3d, 0xd9, 0x2c, 0x5c, 0x3d, 0xe1, 0x20, 0xb8, 0xe3, + 0x9a, 0x05, 0x18, 0x55, 0xc5, 0xba, 0xac, 0x78, 0xfa, 0xe1, 0x6e, 0x05, 0xb1, 0xef, 0x70, 0x40, 0xdf, 0xc9, 0x3c, + 0x4b, 0xee, 0x42, 0x67, 0xcf, 0xb5, 0x51, 0xe9, 0x3f, 0x7c, 0x78, 0xf3, 0x73, 0x04, 0x22, 0xc7, 0xda, 0x50, 0xfa, + 0x3b, 0x8e, 0x67, 0x93, 0x1f, 0xe1, 0xc9, 0xdf, 0xd8, 0x77, 0xdc, 0x9e, 0x1e, 0xfd, 0x3e, 0xd4, 0x4d, 0xef, 0xf8, + 0xec, 0x8e, 0x8f, 0x5c, 0x71, 0xa8, 0xae, 0x70, 0x5f, 0xdf, 0xac, 0x7d, 0x23, 0xa4, 0x87, 0xe7, 0x99, 0xf2, 0xc6, + 0xfc, 0x68, 0x07, 0xc3, 0x20, 0x98, 0x6a, 0xa1, 0x24, 0x44, 0xdd, 0x60, 0x4a, 0xc0, 0x10, 0xed, 0xe9, 0x65, 0x35, + 0x45, 0xce, 0x4d, 0x8d, 0x2c, 0xbc, 0x1f, 0x30, 0x2d, 0x74, 0x68, 0xe4, 0x50, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc2, + 0x6f, 0x95, 0x30, 0xfd, 0x6a, 0x51, 0x39, 0x07, 0xd1, 0x3d, 0x30, 0xc6, 0x15, 0xbc, 0x80, 0xae, 0xb0, 0xeb, 0xb5, + 0x8a, 0x8a, 0x81, 0xe0, 0x71, 0xc8, 0x01, 0x7a, 0xd8, 0x05, 0x2d, 0x2b, 0x4b, 0x75, 0xab, 0x72, 0x96, 0x2a, 0xea, + 0x32, 0x94, 0x95, 0xb1, 0xc2, 0x7c, 0x2f, 0xd9, 0x0f, 0x05, 0x7a, 0x96, 0x4f, 0x45, 0x17, 0xbc, 0x10, 0x4a, 0xb0, + 0x5c, 0xd7, 0x3b, 0x11, 0x88, 0x3a, 0x3f, 0xf4, 0xae, 0xfa, 0x1a, 0xc7, 0x8e, 0xa7, 0x6f, 0x64, 0xca, 0xb5, 0x09, + 0x85, 0xe6, 0xf3, 0xa5, 0xaf, 0x98, 0x28, 0xd8, 0x0d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd6, 0x7a, 0x33, 0x28, + 0xd1, 0x31, 0xaf, 0x51, 0x70, 0xad, 0x14, 0x0a, 0x46, 0x7b, 0x1b, 0x7f, 0x86, 0x23, 0xb7, 0xba, 0x3d, 0xf4, 0x7e, + 0xab, 0xe2, 0xcb, 0xb7, 0xe8, 0xdb, 0x69, 0x7f, 0x8e, 0x2a, 0xf9, 0xeb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, + 0xe2, 0xd2, 0x42, 0x3d, 0xa7, 0xef, 0x8e, 0xdf, 0x82, 0x1f, 0x25, 0xfe, 0xfe, 0xed, 0xfb, 0xa0, 0x26, 0xd3, 0x78, + 0x56, 0x98, 0x0f, 0x6d, 0x0e, 0x08, 0x4d, 0xe2, 0xd2, 0xec, 0xfb, 0x59, 0xdc, 0x64, 0xdf, 0x35, 0x5b, 0x4f, 0x8b, + 0x26, 0x92, 0x94, 0xe1, 0xf6, 0xc1, 0x80, 0x40, 0x1f, 0x20, 0x8a, 0xb3, 0x2f, 0x68, 0x0c, 0x69, 0x3e, 0xb3, 0xef, + 0x47, 0xc4, 0x7b, 0xb9, 0x13, 0x42, 0x8c, 0x2b, 0x2c, 0x1a, 0x3d, 0xe4, 0x33, 0x1e, 0x29, 0xc3, 0xa2, 0xf7, 0x98, + 0x40, 0x9c, 0xe1, 0xb4, 0x7a, 0x8f, 0x98, 0xc7, 0x78, 0x37, 0xd0, 0xb2, 0x87, 0x28, 0xa3, 0x2e, 0x7b, 0xc3, 0xe2, + 0xfb, 0xe3, 0x3a, 0xcc, 0xac, 0xe5, 0xe5, 0x10, 0xfe, 0x06, 0xda, 0x00, 0x9c, 0x72, 0x64, 0xf9, 0x2a, 0xb3, 0xd1, + 0xd5, 0x12, 0xd3, 0x9b, 0x08, 0x62, 0xf1, 0xe8, 0x74, 0x58, 0xbb, 0x3a, 0x55, 0xef, 0x6a, 0xe7, 0x33, 0xd1, 0xab, + 0x40, 0x2b, 0xd7, 0xb6, 0xc7, 0x43, 0xb8, 0x4b, 0x2d, 0xad, 0xb0, 0x11, 0xe5, 0x5c, 0x3c, 0xdd, 0x39, 0x36, 0x27, + 0xa0, 0xc1, 0x95, 0x4c, 0x01, 0x38, 0x4b, 0xab, 0xd1, 0xa8, 0x11, 0xf6, 0x59, 0x39, 0x9f, 0xc3, 0xd6, 0x42, 0x3c, + 0x2d, 0x00, 0xc3, 0x6d, 0x62, 0x50, 0xf2, 0x6e, 0x0c, 0xca, 0xe9, 0x47, 0x05, 0x6f, 0x1d, 0x9c, 0x95, 0xcb, 0x38, + 0x95, 0x37, 0x80, 0xc5, 0x18, 0xf8, 0xa9, 0x58, 0xaa, 0x97, 0x90, 0x2c, 0x79, 0xf2, 0x11, 0xad, 0x36, 0xd2, 0x00, + 0xb8, 0xca, 0xa9, 0xb1, 0xdc, 0x53, 0x20, 0xa1, 0xae, 0x14, 0x95, 0x10, 0x57, 0x55, 0x9c, 0x2c, 0x4f, 0x31, 0x35, + 0xdc, 0x40, 0x2f, 0xa2, 0x40, 0xae, 0xb8, 0x00, 0x92, 0x9e, 0xb3, 0x7f, 0x65, 0x1a, 0x6b, 0xfc, 0xb9, 0x44, 0x01, + 0x93, 0x46, 0x0d, 0xc6, 0x4a, 0xd9, 0x4b, 0x69, 0xa2, 0xbd, 0x05, 0x41, 0xed, 0x5e, 0xfe, 0x05, 0x75, 0x3f, 0x87, + 0x56, 0x84, 0x0d, 0x30, 0x44, 0x79, 0x8e, 0x3b, 0x34, 0xb5, 0x4b, 0xce, 0x03, 0x46, 0x74, 0xde, 0x67, 0xb5, 0xdd, + 0xea, 0xcf, 0x97, 0x80, 0x6d, 0x9a, 0x1a, 0x9f, 0xc2, 0x30, 0x21, 0x26, 0x36, 0xb0, 0x55, 0x56, 0xda, 0x0d, 0x65, + 0xda, 0x49, 0x97, 0xcc, 0x6b, 0xe1, 0x34, 0xef, 0x31, 0xb6, 0x1c, 0xa9, 0xdc, 0xfd, 0x7e, 0x68, 0x7e, 0xb2, 0x9c, + 0x3e, 0xd7, 0x21, 0x9b, 0xbd, 0xf1, 0xa0, 0x39, 0xd1, 0xea, 0xaa, 0x8e, 0x7e, 0x40, 0x07, 0x60, 0xa6, 0x2d, 0x40, + 0xa6, 0x0b, 0x36, 0xed, 0x2b, 0x51, 0x71, 0x49, 0xc2, 0x52, 0x49, 0x60, 0x67, 0x37, 0x25, 0x3b, 0x9b, 0x80, 0x78, + 0x86, 0xbb, 0x9e, 0x16, 0x3b, 0x21, 0x4d, 0x78, 0x8b, 0xbd, 0x04, 0x44, 0x1d, 0xaa, 0xba, 0x84, 0x6c, 0x8c, 0xa1, + 0x8b, 0x7f, 0x51, 0x0a, 0x13, 0xd6, 0x32, 0xa9, 0x4a, 0x4c, 0x10, 0xa4, 0x72, 0xb7, 0x45, 0x60, 0x89, 0x82, 0x1d, + 0xc0, 0xde, 0xbb, 0x51, 0x37, 0xa3, 0xa6, 0xaa, 0x53, 0x2f, 0xc1, 0xc7, 0x69, 0xd6, 0x55, 0x90, 0x59, 0xd8, 0x55, + 0xb1, 0xe6, 0x81, 0x8e, 0x4d, 0xa5, 0x8c, 0x89, 0xbb, 0xb4, 0xc8, 0x10, 0x0f, 0x18, 0x63, 0xe9, 0x42, 0x20, 0xdf, + 0x6c, 0x77, 0xdc, 0xf4, 0x04, 0xa1, 0x9f, 0xb0, 0xa1, 0x04, 0x6e, 0x3a, 0xdb, 0x53, 0xd3, 0xcc, 0x07, 0x44, 0x1c, + 0x06, 0x14, 0x48, 0x36, 0x0e, 0x69, 0x8e, 0xf4, 0x05, 0x49, 0x13, 0x06, 0x86, 0x56, 0x3c, 0x27, 0xc8, 0x8a, 0x42, + 0xcf, 0xd6, 0x55, 0x1b, 0xe7, 0xca, 0x30, 0x47, 0x4b, 0x4e, 0x85, 0xcf, 0x09, 0x32, 0xb1, 0x7b, 0xda, 0x66, 0x26, + 0xc3, 0x51, 0xb2, 0xc0, 0xfc, 0x0a, 0xa2, 0xc4, 0x9d, 0x69, 0x56, 0xe5, 0x60, 0x5c, 0xc0, 0x02, 0xad, 0x7c, 0x0f, + 0xea, 0xc6, 0x1a, 0xda, 0x68, 0x18, 0x62, 0xb7, 0x3f, 0xc1, 0x7e, 0xad, 0x9d, 0xd6, 0x65, 0x8a, 0xe5, 0x65, 0x0a, + 0xd1, 0x5e, 0xc8, 0xfc, 0x46, 0x91, 0xe8, 0x4e, 0x11, 0x86, 0x84, 0x75, 0x94, 0x3d, 0x69, 0x53, 0x03, 0xe8, 0xa9, + 0x17, 0xf0, 0xbc, 0x73, 0x2d, 0xc3, 0x2e, 0xd2, 0xfd, 0x55, 0xc1, 0xa7, 0x74, 0x83, 0x20, 0x45, 0x6f, 0x52, 0x30, + 0xe7, 0xf5, 0x28, 0xa9, 0x37, 0xa7, 0x2d, 0x33, 0xaa, 0x8e, 0x8a, 0x90, 0x72, 0x82, 0xff, 0xe4, 0xa5, 0xd4, 0xc4, + 0x26, 0x4c, 0xf0, 0xc0, 0x87, 0x79, 0x86, 0x0d, 0xbc, 0xdd, 0xbe, 0x4b, 0xc3, 0xa4, 0xcd, 0x36, 0xa4, 0x20, 0xad, + 0x30, 0x71, 0x31, 0xa0, 0xb2, 0xd7, 0xb8, 0x5f, 0xb0, 0x9d, 0x34, 0x05, 0x0f, 0xc2, 0x46, 0x03, 0x13, 0xb7, 0xba, + 0xf8, 0x3a, 0x4c, 0x68, 0xb8, 0xa4, 0xda, 0xd9, 0x49, 0x4b, 0x9a, 0xdb, 0xeb, 0xf2, 0xc2, 0xf6, 0x41, 0xc7, 0x0e, + 0xeb, 0x1a, 0x1e, 0x68, 0x5e, 0xb3, 0x8b, 0x2b, 0xa6, 0x69, 0xa2, 0xb1, 0x1e, 0x52, 0x96, 0x1c, 0xeb, 0x7a, 0xba, + 0xc2, 0xd5, 0x32, 0xd3, 0xc0, 0xee, 0x12, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x81, 0xcd, 0x66, 0xab, + 0x9a, 0x4c, 0xf3, 0xfb, 0xb2, 0xe5, 0x26, 0x20, 0x9c, 0xa5, 0xbe, 0xb9, 0x4f, 0x8e, 0x35, 0x6d, 0xf3, 0x93, 0x00, + 0xc7, 0xdb, 0x2b, 0x20, 0xe9, 0x58, 0x82, 0x2e, 0xbe, 0xa5, 0x3f, 0x88, 0xd4, 0x4c, 0x05, 0xbd, 0x77, 0xbe, 0x48, + 0xdd, 0xfc, 0x02, 0x6c, 0xa3, 0x36, 0xc6, 0x34, 0x2b, 0x5b, 0x87, 0x89, 0xb2, 0xb0, 0x46, 0x16, 0x72, 0x09, 0x3e, + 0x98, 0xbb, 0x4d, 0x9d, 0x1e, 0x77, 0x10, 0x61, 0xbf, 0x8b, 0x1e, 0x8f, 0x30, 0x56, 0xac, 0x41, 0x62, 0x58, 0x85, + 0x35, 0x6d, 0x2e, 0x87, 0x28, 0xa7, 0x66, 0xc9, 0x44, 0x4b, 0xea, 0x53, 0x8a, 0x28, 0x05, 0x73, 0xe3, 0x69, 0xd9, + 0x30, 0x25, 0x44, 0xc8, 0x0a, 0xe9, 0x80, 0x6a, 0x2d, 0xb4, 0x54, 0x13, 0xf4, 0x3a, 0xf4, 0xb2, 0xd0, 0x98, 0x82, + 0xe8, 0x23, 0x32, 0xdc, 0x88, 0x23, 0xa3, 0xbb, 0x63, 0x14, 0x13, 0x08, 0x55, 0xed, 0xe5, 0x85, 0xd5, 0xa7, 0x65, + 0x5b, 0x1d, 0xc4, 0x15, 0x22, 0xdf, 0x77, 0x13, 0xd4, 0x18, 0x05, 0x6d, 0x4e, 0x37, 0xfa, 0x6b, 0x11, 0xfa, 0x76, + 0xe1, 0xd8, 0x8d, 0x82, 0x48, 0x88, 0xc0, 0xea, 0x35, 0x15, 0x03, 0xb2, 0xce, 0x63, 0x17, 0xa1, 0x49, 0x77, 0x0b, + 0x51, 0xde, 0xa8, 0xac, 0x3f, 0xae, 0x43, 0xb2, 0xdd, 0x62, 0x59, 0xe0, 0xcb, 0x7e, 0xba, 0xbe, 0x07, 0xf2, 0xfb, + 0xcd, 0xfa, 0xb3, 0x90, 0xdf, 0xaf, 0xb3, 0x2f, 0x81, 0xfc, 0x7e, 0xb3, 0xfe, 0x9f, 0x86, 0xfc, 0x3e, 0x5d, 0x7b, + 0x90, 0xdf, 0x6a, 0x30, 0x7e, 0x2f, 0x58, 0x70, 0xf2, 0x36, 0xa0, 0x2f, 0x24, 0x0b, 0x4e, 0x5e, 0xbd, 0xf2, 0x8d, + 0x40, 0x84, 0x46, 0xae, 0x37, 0xb2, 0x60, 0xc4, 0x6d, 0x81, 0x57, 0xa8, 0x75, 0xf2, 0x81, 0x8a, 0x32, 0x00, 0x5e, + 0x2f, 0xff, 0x91, 0x55, 0xcb, 0x30, 0xd8, 0x0f, 0xc8, 0xcc, 0x41, 0x82, 0x0e, 0x27, 0x70, 0x7b, 0x43, 0x23, 0xcb, + 0xea, 0x8b, 0xe0, 0xc3, 0x47, 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0xa5, 0xce, 0x6c, 0x24, 0x04, 0x3c, 0xce, 0x78, 0x69, + 0x43, 0x44, 0x2c, 0xe3, 0xf2, 0x4c, 0xc7, 0x66, 0x29, 0xed, 0x56, 0x84, 0x88, 0xf3, 0x67, 0x80, 0x53, 0x6f, 0xf7, + 0x66, 0x8c, 0xfd, 0x50, 0x1c, 0xb1, 0x0e, 0x20, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, + 0x06, 0xbd, 0x84, 0xbb, 0x88, 0xe0, 0x49, 0xe5, 0xb1, 0x4d, 0x0a, 0xa8, 0x3c, 0xd3, 0x40, 0xe5, 0x1d, 0xef, 0x69, + 0x68, 0x87, 0x45, 0xfb, 0x00, 0x1b, 0xe9, 0x72, 0x06, 0x46, 0x8b, 0x2f, 0xaf, 0xb9, 0xa8, 0x7e, 0x06, 0x3c, 0x75, + 0xc1, 0x0b, 0xb8, 0x25, 0x20, 0x17, 0xdb, 0x70, 0x42, 0xa0, 0xc2, 0xf7, 0xec, 0x50, 0x51, 0x63, 0x8c, 0x68, 0xa2, + 0xd1, 0x6f, 0xbc, 0x09, 0xa1, 0x77, 0x27, 0xe8, 0x8a, 0x30, 0x12, 0xde, 0x5f, 0x6b, 0x7e, 0x96, 0x81, 0xf9, 0xbc, + 0x00, 0x28, 0x0d, 0x84, 0x43, 0x65, 0x4a, 0x6e, 0x81, 0x09, 0x1b, 0x63, 0xae, 0x94, 0xa5, 0x1e, 0x52, 0x29, 0x55, + 0x70, 0xba, 0x82, 0xa6, 0x12, 0x70, 0xb8, 0x23, 0x09, 0x60, 0xa6, 0xb6, 0x30, 0x88, 0x6e, 0x9b, 0xd2, 0x2c, 0x8d, + 0x9c, 0x22, 0xcd, 0xe1, 0x93, 0x52, 0x05, 0x3a, 0x7d, 0x96, 0xc4, 0x15, 0xbf, 0x94, 0x05, 0x84, 0xc2, 0x6d, 0xa5, + 0x50, 0xa4, 0xdf, 0x67, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0x39, 0x5b, 0x66, 0x65, 0x05, 0xf9, 0xe6, 0xfa, 0xf4, 0x5b, + 0xd4, 0xd3, 0x02, 0xe7, 0x4d, 0x4d, 0x0a, 0x33, 0xf3, 0x78, 0xac, 0x76, 0x3a, 0xa8, 0x57, 0xbd, 0xd7, 0x06, 0xfb, + 0xbd, 0x39, 0xd1, 0xe3, 0xd6, 0x7a, 0xb0, 0x9a, 0xd4, 0x66, 0xaa, 0x82, 0x38, 0x02, 0xea, 0xc0, 0x8e, 0xe2, 0x76, + 0x33, 0x0f, 0x93, 0x76, 0xca, 0x76, 0xbb, 0x93, 0x09, 0x0e, 0xee, 0x56, 0x12, 0xdc, 0x12, 0x61, 0xc5, 0x1f, 0x2a, + 0x08, 0x96, 0xd9, 0x70, 0x12, 0x99, 0x70, 0xac, 0x05, 0xff, 0x6b, 0xcd, 0x0d, 0x16, 0x7c, 0xa8, 0x1d, 0xf2, 0x9c, + 0xe4, 0x5c, 0x0f, 0x80, 0x67, 0xc3, 0xa6, 0x67, 0x67, 0x0e, 0xf6, 0x53, 0x7e, 0xcb, 0x21, 0x60, 0x4b, 0xe7, 0x28, + 0x2e, 0xa6, 0xda, 0x9a, 0xd7, 0xb0, 0x12, 0xf4, 0xcb, 0xbe, 0xd3, 0x38, 0xb5, 0x09, 0x0f, 0x87, 0xcf, 0xc6, 0xa4, + 0xd6, 0xa6, 0xe5, 0x38, 0xcf, 0xf6, 0xb7, 0x5a, 0x0b, 0xee, 0xd9, 0xae, 0x07, 0xda, 0x74, 0x0a, 0x68, 0xd7, 0x48, + 0xc5, 0x3d, 0xdd, 0xaf, 0x49, 0xed, 0xe6, 0xd5, 0x0a, 0x7a, 0xfe, 0x50, 0x87, 0xcb, 0xd9, 0xa3, 0x4d, 0xa6, 0xab, + 0xac, 0xff, 0xc8, 0x6c, 0x58, 0xb8, 0xc6, 0x46, 0xad, 0xf5, 0x8c, 0xfb, 0xa8, 0x6c, 0x1d, 0xd9, 0xf4, 0x0c, 0xb1, + 0xac, 0x73, 0xb7, 0x8f, 0xd4, 0x23, 0x57, 0x51, 0xb2, 0xba, 0xb3, 0xf0, 0x5b, 0x9e, 0x84, 0x5d, 0x0d, 0x53, 0x8c, + 0xb8, 0xe9, 0x02, 0x02, 0x55, 0x82, 0xf8, 0x3d, 0xfc, 0xe3, 0xd1, 0xa6, 0x49, 0x3d, 0xea, 0x7d, 0xef, 0x33, 0xfc, + 0x9d, 0xa5, 0xf0, 0xb7, 0xaa, 0xff, 0xa0, 0x9b, 0x2b, 0x5e, 0x2d, 0x65, 0x1a, 0x05, 0xef, 0x4e, 0x4e, 0x3f, 0x04, + 0x1a, 0x00, 0x1d, 0xaf, 0x01, 0x46, 0xf1, 0x6b, 0xa0, 0x96, 0x40, 0x11, 0x92, 0xcb, 0x4b, 0xc4, 0x00, 0xd4, 0x20, + 0xf2, 0xa7, 0x4b, 0x79, 0x73, 0x9c, 0xe7, 0x3e, 0xaf, 0x6a, 0xe8, 0x9b, 0x66, 0xdf, 0x1a, 0xc4, 0x21, 0x04, 0x91, + 0xdb, 0x28, 0x2b, 0xcf, 0xb4, 0x92, 0x24, 0x3d, 0x3b, 0xbf, 0x3b, 0xd3, 0x82, 0x18, 0x0b, 0xc2, 0xf8, 0xfc, 0x8f, + 0xc3, 0x34, 0xbb, 0xde, 0x43, 0x22, 0xcc, 0x02, 0xb0, 0x60, 0xcf, 0xf9, 0xf9, 0xba, 0xaa, 0xa4, 0x18, 0x16, 0xf2, + 0x26, 0x38, 0x3a, 0x54, 0x0f, 0x26, 0x43, 0xac, 0x1e, 0x83, 0xbd, 0xff, 0x4a, 0xf2, 0x2c, 0xf9, 0xc8, 0x82, 0x47, + 0x9b, 0x8c, 0x1d, 0xb5, 0x48, 0xed, 0xb8, 0x0e, 0x8e, 0xa0, 0xad, 0x7b, 0xc7, 0x79, 0x7e, 0xb8, 0xaf, 0xbe, 0x38, + 0x3a, 0xdc, 0x4f, 0xb3, 0xeb, 0x23, 0x0f, 0x0f, 0xdf, 0x99, 0xb7, 0x22, 0xf2, 0x98, 0xbb, 0xbe, 0x82, 0x1f, 0x6b, + 0xc2, 0x43, 0x7b, 0xe0, 0x83, 0xd0, 0xc4, 0x44, 0x13, 0x41, 0x41, 0x4b, 0x18, 0xc3, 0xf1, 0xb6, 0xdd, 0x86, 0xd6, + 0xf6, 0x26, 0xf1, 0x80, 0x69, 0x0a, 0x60, 0x08, 0x30, 0x0b, 0x4d, 0x08, 0x4d, 0x6a, 0x12, 0x1a, 0xf8, 0x9c, 0x98, + 0xd0, 0xa2, 0xa6, 0x40, 0xf1, 0xdf, 0xc4, 0x2b, 0x23, 0x6b, 0xd2, 0x77, 0x77, 0xd3, 0xfa, 0x59, 0x63, 0x1c, 0xa3, + 0xf6, 0xa8, 0x1a, 0x40, 0xab, 0x5e, 0x79, 0xdf, 0xc0, 0x82, 0x78, 0x31, 0xac, 0x68, 0xd0, 0x22, 0x15, 0x20, 0x1e, + 0xf4, 0xa5, 0x5a, 0x9c, 0x86, 0xf3, 0x92, 0xca, 0x05, 0x61, 0x47, 0xe1, 0x06, 0xb9, 0xdb, 0x52, 0x11, 0xcb, 0x48, + 0xd6, 0x0e, 0x5d, 0x52, 0xcd, 0xce, 0xd1, 0xa3, 0x8d, 0x40, 0x40, 0xc3, 0x92, 0x1d, 0x35, 0xe7, 0xab, 0x8a, 0xcf, + 0x87, 0x4b, 0x0e, 0x6e, 0x30, 0xc1, 0xde, 0x7f, 0xa5, 0xe7, 0xb9, 0x9d, 0x14, 0xb5, 0x22, 0x97, 0xb1, 0x48, 0x73, + 0xfe, 0x21, 0x3e, 0xff, 0x01, 0xf3, 0xbc, 0x38, 0xcf, 0x9f, 0x43, 0x86, 0x3a, 0x38, 0x7a, 0xb4, 0x49, 0xaa, 0xd1, + 0xcb, 0xb7, 0x1f, 0x5e, 0x7f, 0xf8, 0xe7, 0xd9, 0xf3, 0xe3, 0x0f, 0x2f, 0xbf, 0x3f, 0x79, 0xff, 0xfa, 0xe5, 0xe9, + 0xdc, 0xfa, 0x9d, 0x2a, 0x38, 0x33, 0xb2, 0xd8, 0x6e, 0x5d, 0xbe, 0x5f, 0xdf, 0xbe, 0x78, 0xf9, 0xea, 0xf5, 0xdb, + 0x97, 0x2f, 0x6a, 0x35, 0x97, 0xed, 0x86, 0xc0, 0x0e, 0x8d, 0x33, 0xc1, 0x0b, 0x28, 0x5e, 0x07, 0x55, 0xc4, 0x66, + 0x6b, 0x14, 0xbe, 0x66, 0xd3, 0x75, 0xc0, 0x02, 0x58, 0x64, 0x7b, 0x7a, 0xb3, 0x40, 0xc3, 0xa5, 0xd9, 0x38, 0xfe, + 0x12, 0xf3, 0x7b, 0xf3, 0x12, 0xbf, 0x7b, 0x2f, 0x6f, 0x4c, 0x57, 0xf4, 0x08, 0x29, 0x80, 0xad, 0xd9, 0xf3, 0x3f, + 0x0e, 0x7d, 0xa1, 0x16, 0xde, 0xfc, 0x55, 0xb9, 0xf0, 0xab, 0x0e, 0xf6, 0xb4, 0x81, 0x5d, 0x00, 0xf1, 0x21, 0x82, + 0xa3, 0xc3, 0x7d, 0x3f, 0xf7, 0xd1, 0x1f, 0xd1, 0xcf, 0x5e, 0xe7, 0xb0, 0x54, 0x18, 0x87, 0x66, 0xda, 0xce, 0x21, + 0x04, 0x11, 0x8c, 0xdc, 0x31, 0xa5, 0x56, 0x90, 0x21, 0x57, 0x92, 0x44, 0x76, 0x12, 0x95, 0xe1, 0x88, 0x29, 0xed, + 0x0f, 0xfd, 0xd7, 0xf5, 0x19, 0x2f, 0xe2, 0x5c, 0x94, 0xb2, 0x08, 0xa0, 0x1f, 0xed, 0xb0, 0x0e, 0x7b, 0x5e, 0xf8, + 0x14, 0xec, 0x51, 0x27, 0x79, 0x87, 0x11, 0xd9, 0x6f, 0x7f, 0xea, 0x75, 0xec, 0x0f, 0xe2, 0x7e, 0xec, 0xe9, 0xce, + 0xb4, 0xc8, 0x8b, 0x6d, 0xe0, 0xfd, 0xe1, 0x37, 0xe6, 0x27, 0x19, 0xfd, 0x87, 0xa4, 0x97, 0x31, 0xbd, 0x8a, 0xe9, + 0xa9, 0x58, 0xd4, 0x9d, 0xb3, 0x63, 0x43, 0xbb, 0x50, 0x3e, 0x0d, 0x01, 0x20, 0x42, 0xb3, 0xed, 0x9a, 0x99, 0xcd, + 0x46, 0x5a, 0xa5, 0xf5, 0x21, 0x2e, 0x2e, 0xb9, 0x89, 0xa8, 0x62, 0xde, 0x56, 0x7a, 0x54, 0x88, 0x37, 0x2c, 0x80, + 0x9e, 0xd2, 0xd3, 0x9a, 0xff, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xe6, 0xaa, 0xac, 0xe4, 0x0a, 0x58, + 0xea, 0xf8, 0x52, 0x8b, 0x48, 0x68, 0xc8, 0xbf, 0xac, 0xba, 0xed, 0x96, 0x8f, 0x70, 0x49, 0x02, 0x5f, 0x36, 0xaa, + 0xe4, 0xe5, 0x65, 0xce, 0xc3, 0xc0, 0xc4, 0xf8, 0x08, 0xa8, 0xad, 0x66, 0xf6, 0x7f, 0x8a, 0x3b, 0xda, 0xe5, 0xb6, + 0x6d, 0xe4, 0xff, 0x7b, 0x0a, 0x86, 0xc9, 0xa5, 0x62, 0x42, 0xd2, 0xa4, 0x64, 0xd9, 0x8e, 0x64, 0xd9, 0x6d, 0x93, + 0x74, 0xce, 0x1d, 0xb7, 0xe9, 0x24, 0xbe, 0xcc, 0x5d, 0x5d, 0x8f, 0x45, 0x51, 0x90, 0xc4, 0x0b, 0x45, 0x6a, 0x48, + 0xca, 0x96, 0xab, 0xf2, 0x9e, 0xa5, 0xcf, 0x72, 0x4f, 0x76, 0xb3, 0xbb, 0x00, 0x08, 0x7e, 0xe8, 0xc3, 0x4d, 0x7a, + 0x37, 0x3d, 0x5f, 0x44, 0x10, 0x00, 0x81, 0x05, 0xb0, 0xbb, 0xd8, 0xcf, 0x27, 0x8e, 0x08, 0xac, 0x69, 0xe4, 0x9b, + 0x8e, 0x96, 0x98, 0x31, 0x93, 0x91, 0xe7, 0x88, 0xc1, 0x44, 0x11, 0xea, 0x1d, 0x6a, 0x21, 0xf8, 0xba, 0x14, 0x47, + 0xd7, 0x1a, 0xc7, 0xcb, 0x51, 0xc8, 0x2c, 0xdc, 0xee, 0xf0, 0xc9, 0xf5, 0x68, 0x39, 0x1a, 0x41, 0x32, 0x95, 0x27, + 0x8e, 0x09, 0xe1, 0x61, 0xe2, 0x14, 0xaf, 0x6d, 0xb9, 0xd1, 0x87, 0x49, 0xd9, 0x59, 0x75, 0xf8, 0x60, 0xd2, 0x01, + 0x12, 0x19, 0xfa, 0x40, 0x06, 0x57, 0xb4, 0x86, 0x53, 0x3b, 0xd0, 0x3f, 0xc0, 0xee, 0x4b, 0xf5, 0x7e, 0xd3, 0xd1, + 0x1f, 0x5c, 0xeb, 0x1f, 0x10, 0xc6, 0x98, 0x64, 0xf8, 0x35, 0xed, 0x5e, 0xdd, 0xd4, 0x49, 0x37, 0xbd, 0xc4, 0x74, + 0x03, 0x20, 0x9b, 0x7d, 0x13, 0x78, 0xd3, 0x28, 0x4e, 0xb3, 0xc0, 0xd7, 0x6f, 0xfa, 0x17, 0x41, 0xeb, 0x7a, 0x9e, + 0xb5, 0x8c, 0x1b, 0xd3, 0xcf, 0xd4, 0x4c, 0x25, 0x02, 0x61, 0x62, 0xa2, 0x92, 0x4d, 0x95, 0xd4, 0x13, 0xb4, 0xb5, + 0xa2, 0x40, 0xcd, 0x58, 0xc9, 0xcf, 0x06, 0x50, 0xaf, 0x92, 0xf6, 0x04, 0xf3, 0x37, 0xe9, 0xd8, 0xd2, 0xe8, 0xd3, + 0x85, 0xe2, 0xf5, 0x72, 0x8d, 0xa4, 0x3c, 0x2b, 0xa8, 0x25, 0x86, 0xea, 0x15, 0xfe, 0x2d, 0xf4, 0xfc, 0x44, 0xb5, + 0xcd, 0x2c, 0xd1, 0xdd, 0xe1, 0x37, 0x65, 0xbe, 0x00, 0xe8, 0x37, 0x18, 0x46, 0x44, 0x71, 0xa6, 0x41, 0xfc, 0x19, + 0xf8, 0xe2, 0xb0, 0x6a, 0xcb, 0xc5, 0x7b, 0x6d, 0x19, 0x39, 0x47, 0x06, 0xdf, 0x22, 0xf1, 0x6b, 0xf1, 0x28, 0x64, + 0xa5, 0x40, 0x13, 0xc4, 0xd3, 0x47, 0xb0, 0x80, 0x59, 0x7c, 0x19, 0xdf, 0x57, 0xd5, 0x15, 0xaf, 0x87, 0xbb, 0x69, + 0x2f, 0x12, 0x40, 0xd8, 0x6f, 0x22, 0xf9, 0x5e, 0x8b, 0xe7, 0x0f, 0x15, 0x8c, 0x4e, 0xe5, 0x4c, 0xa1, 0x7d, 0x86, + 0xe0, 0x61, 0x32, 0x30, 0xe7, 0x42, 0x5a, 0x00, 0x28, 0x89, 0x93, 0xe9, 0x61, 0x7e, 0x2b, 0x32, 0x1c, 0x8b, 0xfc, + 0xc2, 0x0a, 0x71, 0x06, 0xec, 0x1a, 0x2d, 0x96, 0x19, 0x46, 0xc4, 0x85, 0x01, 0xb0, 0x5c, 0xd7, 0x30, 0xc2, 0x26, + 0x60, 0xe9, 0x82, 0x4d, 0xcc, 0x75, 0x2d, 0x18, 0xd7, 0xcb, 0x88, 0xe7, 0x05, 0xdc, 0x85, 0xe8, 0x1d, 0xc5, 0x49, + 0xf0, 0x98, 0xf0, 0x59, 0xf8, 0x66, 0x11, 0x4d, 0xbe, 0xe5, 0xa3, 0xda, 0xa5, 0x01, 0x31, 0xf8, 0x84, 0xf8, 0xfa, + 0xad, 0xb0, 0x71, 0xae, 0x10, 0x24, 0xb3, 0x34, 0xcb, 0xe1, 0xb3, 0x75, 0x94, 0x9f, 0x3f, 0x5b, 0xa7, 0xf9, 0xe0, + 0xd9, 0xda, 0x03, 0x46, 0x2e, 0xd7, 0x61, 0x9e, 0x85, 0x3b, 0x4d, 0x31, 0x3b, 0xd8, 0x53, 0x54, 0xae, 0xa1, 0x3e, + 0x7d, 0xc0, 0xb5, 0xe6, 0x8b, 0x24, 0x98, 0x7b, 0xc9, 0x03, 0x29, 0xd9, 0x4d, 0x55, 0x13, 0x6f, 0xe8, 0x1a, 0xa1, + 0x75, 0x9a, 0x2e, 0x61, 0x78, 0x5d, 0xfb, 0x5a, 0x96, 0x31, 0x3e, 0x39, 0xa9, 0x69, 0x84, 0x6f, 0xdd, 0xea, 0x2f, + 0x99, 0x3d, 0x66, 0x99, 0x17, 0x84, 0xd4, 0xa4, 0x2f, 0x52, 0xc8, 0xd7, 0x66, 0x93, 0x96, 0x67, 0x13, 0x95, 0x77, + 0x0b, 0x4e, 0x86, 0x10, 0x3e, 0x8d, 0x1b, 0x67, 0x86, 0xa9, 0xa5, 0x9a, 0xd7, 0x8f, 0xde, 0xfd, 0x4f, 0xa1, 0xcf, + 0x00, 0xfa, 0x11, 0x40, 0x9f, 0x45, 0x7e, 0x3c, 0x66, 0x7f, 0x7f, 0x7f, 0x21, 0x73, 0x59, 0x81, 0x58, 0x66, 0xc8, + 0xb7, 0x61, 0x8a, 0xdc, 0x42, 0x82, 0x9c, 0x02, 0x65, 0x9d, 0x2a, 0x76, 0x4c, 0x92, 0xeb, 0xda, 0x39, 0x8d, 0x9d, + 0x8d, 0x69, 0xd4, 0x83, 0x18, 0x5b, 0x25, 0xf9, 0xe9, 0x01, 0xd5, 0x26, 0xda, 0x46, 0x95, 0x00, 0x0c, 0x09, 0xcc, + 0xb0, 0x80, 0x02, 0xa4, 0xdd, 0x1c, 0xb8, 0xc5, 0xf5, 0xc1, 0x9e, 0xa3, 0xf0, 0xdb, 0x3d, 0x2f, 0x33, 0x26, 0xd8, + 0x4a, 0x3f, 0x3b, 0xc5, 0x44, 0x5a, 0x40, 0x9d, 0x21, 0xf4, 0xc6, 0xe9, 0x01, 0x3d, 0x6a, 0x95, 0xfd, 0x5f, 0x74, + 0x22, 0x2e, 0x72, 0x3d, 0xde, 0xc1, 0xa3, 0x0e, 0x06, 0xe4, 0x6d, 0x87, 0x52, 0x2f, 0xd7, 0xb5, 0x39, 0x67, 0x84, + 0x78, 0x8c, 0x1f, 0x08, 0x00, 0xe0, 0xc0, 0x49, 0xd5, 0xb5, 0xb9, 0xb7, 0xc2, 0x99, 0x8b, 0x37, 0xde, 0xaa, 0xe5, + 0xf2, 0x57, 0xb6, 0x04, 0x54, 0x5a, 0x3e, 0x5a, 0x3e, 0x5f, 0x5c, 0xb0, 0xee, 0x17, 0x42, 0xdb, 0xd6, 0x0c, 0xb5, + 0xa6, 0x0d, 0x8b, 0x3b, 0x13, 0x8b, 0x3b, 0xde, 0xb0, 0xb8, 0xe3, 0x2d, 0x8b, 0x1b, 0xf2, 0x85, 0xd4, 0x24, 0xe8, + 0x12, 0xf4, 0xd8, 0x92, 0xc0, 0xe3, 0x6c, 0x45, 0x8f, 0x9f, 0x33, 0x84, 0x93, 0x95, 0x86, 0x60, 0xb1, 0xb4, 0x01, + 0x56, 0x4d, 0x70, 0x51, 0x00, 0xa1, 0xa2, 0x94, 0xb4, 0x74, 0xe8, 0xc4, 0xb4, 0x21, 0x2f, 0x66, 0x2b, 0xac, 0x4e, + 0x17, 0x36, 0x29, 0xe5, 0xfc, 0x6e, 0xcd, 0x36, 0x4c, 0x74, 0xb6, 0x65, 0xa2, 0x7e, 0xe9, 0xe4, 0xf2, 0x59, 0xd3, + 0x19, 0x54, 0xe7, 0x04, 0x5b, 0x10, 0x8c, 0x38, 0x71, 0xc7, 0x94, 0xb7, 0xe1, 0x66, 0x84, 0xaa, 0x6c, 0xa8, 0x85, + 0x97, 0xa6, 0xf7, 0x71, 0x02, 0x5a, 0x10, 0xe8, 0xe6, 0x71, 0x3b, 0x6a, 0x1e, 0x44, 0x3c, 0xc0, 0xca, 0xc6, 0xbd, + 0x54, 0xbc, 0x57, 0x77, 0x54, 0xbb, 0xdb, 0xa5, 0x1a, 0x0b, 0x2f, 0xcb, 0x58, 0x82, 0x30, 0xf7, 0x20, 0x12, 0x77, + 0x0d, 0xd8, 0xff, 0x97, 0x4d, 0xd6, 0x80, 0x41, 0x42, 0xa3, 0xc0, 0xe9, 0x88, 0x9f, 0x17, 0xc0, 0x47, 0x25, 0x82, + 0xe8, 0x2a, 0xb1, 0xda, 0x12, 0x09, 0xf7, 0x1f, 0xf1, 0xb0, 0xb6, 0x12, 0xc5, 0x9b, 0xc8, 0x3d, 0x32, 0xec, 0x85, + 0x37, 0xfe, 0x00, 0xba, 0xb6, 0x56, 0xdb, 0x04, 0xbb, 0x59, 0x35, 0x32, 0x5b, 0x42, 0x8c, 0x9d, 0x5f, 0xa0, 0x48, + 0xc4, 0x91, 0xdc, 0x2a, 0x09, 0x1c, 0x1a, 0x3d, 0x6b, 0x72, 0xb3, 0x6e, 0xe7, 0x07, 0xd3, 0xc0, 0xa8, 0xe1, 0x4c, + 0x40, 0x6c, 0xe1, 0xe0, 0x4c, 0xde, 0xaf, 0x42, 0xd3, 0x3d, 0x32, 0x40, 0x18, 0x7b, 0x0d, 0x29, 0x46, 0x1d, 0x71, + 0x79, 0x1d, 0x26, 0x40, 0xa2, 0xae, 0x9d, 0x9b, 0xfc, 0xf9, 0x14, 0x7f, 0xb9, 0x37, 0xf9, 0xf3, 0x11, 0xfe, 0x6a, + 0xdf, 0x60, 0x32, 0xb9, 0x86, 0x4b, 0xbb, 0x32, 0x67, 0xfd, 0xac, 0xb4, 0x9d, 0xc8, 0x24, 0xec, 0xf1, 0x04, 0xfa, + 0xe9, 0xb3, 0x75, 0x0a, 0x4e, 0x90, 0xea, 0x1c, 0x22, 0x3b, 0x31, 0xf2, 0xc6, 0xf2, 0xe9, 0x86, 0xf2, 0x91, 0xf1, + 0x3f, 0xa6, 0xf2, 0xb8, 0x4b, 0xe2, 0x82, 0xa2, 0x94, 0x45, 0x0e, 0xb7, 0xa3, 0x20, 0xf2, 0x92, 0x87, 0x5b, 0xba, + 0x4a, 0xb4, 0x04, 0x9f, 0x2e, 0x45, 0x29, 0xc4, 0x4a, 0x96, 0x35, 0x50, 0x99, 0x22, 0x73, 0x7d, 0xe0, 0x64, 0x7e, + 0xf0, 0x8f, 0x44, 0x61, 0xd1, 0x4a, 0x97, 0x4d, 0xbe, 0x20, 0xa5, 0x0f, 0xdd, 0x3e, 0x5b, 0xb7, 0x58, 0xbd, 0x9b, + 0xca, 0x6c, 0x2b, 0x3c, 0x20, 0x2c, 0x0f, 0x5e, 0x5c, 0xe7, 0xe3, 0xa0, 0x87, 0x2a, 0xa6, 0x51, 0xbc, 0xb2, 0x9e, + 0xad, 0xb3, 0x73, 0x7d, 0xee, 0x25, 0x9f, 0xd8, 0xd8, 0xf2, 0x83, 0xc4, 0x0f, 0x99, 0xde, 0xd3, 0x47, 0xa1, 0x17, + 0x7d, 0xe2, 0x8f, 0x56, 0xbc, 0xcc, 0x50, 0x69, 0xbc, 0xf3, 0x9e, 0x2b, 0x60, 0x42, 0xe2, 0x39, 0x64, 0x4c, 0x1b, + 0xa0, 0xa0, 0xbd, 0x96, 0xc2, 0xad, 0x82, 0x29, 0x2c, 0x6a, 0x99, 0x60, 0xf3, 0x08, 0x7a, 0x6c, 0x70, 0x22, 0x35, + 0x75, 0x5c, 0x2f, 0xdd, 0x54, 0xa7, 0x4a, 0x82, 0x49, 0x99, 0x05, 0xf1, 0x16, 0x7b, 0xf8, 0xe3, 0x9f, 0xa3, 0xfc, + 0xd4, 0xfb, 0x7f, 0x8e, 0x73, 0x78, 0x9b, 0x3f, 0xa8, 0x36, 0xf6, 0xd2, 0x74, 0x39, 0x67, 0x63, 0xd2, 0x97, 0x9d, + 0x17, 0x43, 0x29, 0x33, 0xf2, 0xea, 0x70, 0x7e, 0x59, 0xb6, 0x8f, 0x0f, 0x5f, 0x83, 0x1e, 0x1f, 0x38, 0xba, 0x78, + 0x32, 0xd1, 0x8b, 0x2b, 0xf5, 0x8e, 0x66, 0xee, 0xe1, 0x2f, 0xcb, 0xef, 0xde, 0x3a, 0xdf, 0xc9, 0xc6, 0x91, 0x6e, + 0xe4, 0x43, 0xa1, 0x94, 0xe4, 0x8c, 0xa9, 0x32, 0x5e, 0x31, 0xa3, 0x89, 0x17, 0x6d, 0x9e, 0xce, 0x75, 0x69, 0x97, + 0x2d, 0x18, 0x1b, 0x83, 0xbd, 0xaa, 0x59, 0x2b, 0xbd, 0x0d, 0xd9, 0x1d, 0x93, 0x0a, 0xcf, 0xfa, 0xc7, 0x1a, 0x5a, + 0x60, 0x44, 0x36, 0xae, 0x48, 0xe5, 0x6c, 0x95, 0x32, 0xa5, 0x21, 0xce, 0x81, 0xcf, 0x5c, 0xdd, 0xe5, 0x95, 0x5d, + 0x3d, 0x34, 0x75, 0x65, 0x00, 0x1b, 0x47, 0x76, 0xbe, 0xa1, 0xbc, 0x87, 0xe9, 0x98, 0x9b, 0xc7, 0x66, 0xba, 0x46, + 0x0f, 0x22, 0x58, 0x73, 0x38, 0x85, 0xb0, 0xf9, 0x5b, 0x85, 0xf4, 0x61, 0x13, 0xc4, 0x9a, 0x64, 0x52, 0xba, 0x90, + 0xf1, 0x34, 0x2e, 0x84, 0x56, 0x9e, 0xe6, 0x08, 0x73, 0x9a, 0x46, 0x2c, 0x4d, 0x37, 0x42, 0x47, 0xae, 0xb0, 0xa9, + 0x17, 0xb5, 0xcb, 0x93, 0x2f, 0xca, 0x4d, 0xc7, 0x04, 0x0a, 0x8c, 0xb3, 0xa9, 0x7e, 0x0b, 0xd1, 0xf9, 0xed, 0x9c, + 0x9b, 0x6c, 0x24, 0xd3, 0x91, 0xce, 0xd5, 0xe9, 0x9b, 0xde, 0xdf, 0xeb, 0x7c, 0x50, 0x25, 0xb2, 0xd8, 0x38, 0xb4, + 0x56, 0x09, 0xd5, 0xd5, 0x44, 0x31, 0xd8, 0x81, 0x18, 0x53, 0x05, 0x9f, 0xb1, 0xc9, 0x84, 0xf9, 0x59, 0x6a, 0x08, + 0xc1, 0x8c, 0x0c, 0xa0, 0x0a, 0x8e, 0x33, 0x4f, 0x06, 0xfa, 0x8f, 0xe0, 0x46, 0x2e, 0xe2, 0x0c, 0xf1, 0x01, 0x89, + 0x1b, 0x4a, 0x33, 0x98, 0xa8, 0xc7, 0x32, 0x88, 0xf8, 0x57, 0x20, 0x3f, 0x76, 0x43, 0x39, 0x0e, 0x8d, 0xe3, 0xfb, + 0x62, 0x13, 0xc4, 0xd2, 0xb0, 0x63, 0x3b, 0xb6, 0xd9, 0x76, 0x56, 0xd7, 0xee, 0x77, 0x5d, 0xd7, 0xc9, 0x75, 0x13, + 0xdc, 0x97, 0x3e, 0xed, 0x7b, 0xc2, 0xb1, 0x55, 0x07, 0x5a, 0x2d, 0xa3, 0xc7, 0xb4, 0x6b, 0xbb, 0xaf, 0x5c, 0xdd, + 0x24, 0xab, 0x31, 0x05, 0x91, 0xf9, 0xf1, 0x1d, 0x4b, 0x3e, 0x7b, 0x2a, 0xe5, 0xce, 0xf7, 0x1b, 0xcf, 0x91, 0xeb, + 0x00, 0xc6, 0xcd, 0xe2, 0xc5, 0x23, 0xa6, 0xd0, 0xd1, 0x4d, 0xdd, 0x0f, 0xe3, 0x94, 0xa9, 0x73, 0x20, 0x01, 0xc3, + 0x67, 0x4e, 0xe2, 0xa7, 0xf7, 0x6f, 0x3f, 0x7c, 0xd0, 0x4d, 0x4c, 0x86, 0x99, 0xaa, 0xbd, 0xf3, 0x0d, 0xb5, 0x03, + 0xd5, 0x37, 0xee, 0x3b, 0x22, 0x27, 0x74, 0x85, 0x2c, 0xef, 0x39, 0x2a, 0xab, 0x6d, 0x39, 0x4e, 0x66, 0xf8, 0x97, + 0xe9, 0xde, 0xb7, 0xd7, 0xbc, 0x1a, 0x70, 0xc3, 0x76, 0x5a, 0x56, 0x2a, 0x99, 0x07, 0xd1, 0x6d, 0x43, 0xa9, 0xb7, + 0x6a, 0x28, 0x85, 0x8b, 0x53, 0x0d, 0x57, 0x2d, 0xe3, 0xb9, 0x42, 0x8a, 0x21, 0x97, 0xf1, 0x2e, 0x70, 0x29, 0xd7, + 0x97, 0xcf, 0x18, 0x34, 0x0f, 0x66, 0x5e, 0x1d, 0x75, 0x43, 0x31, 0xbf, 0x73, 0x48, 0xd8, 0xfa, 0x21, 0xd8, 0xbc, + 0x31, 0x55, 0xe3, 0x55, 0x66, 0xd3, 0xa4, 0xc5, 0xaa, 0xd2, 0x09, 0xb1, 0x93, 0xb7, 0x19, 0x9b, 0x2f, 0x58, 0xe2, + 0x65, 0xcb, 0x84, 0xdd, 0x86, 0xf1, 0xfd, 0x93, 0xc2, 0xa2, 0x7c, 0x47, 0xe5, 0x59, 0x30, 0x9d, 0xc9, 0xda, 0xe7, + 0x2d, 0x36, 0x90, 0x0b, 0xb8, 0xf5, 0x03, 0xf9, 0x7f, 0x7e, 0xb7, 0xed, 0xff, 0xfc, 0xbe, 0xb3, 0x2a, 0x74, 0x9f, + 0x0f, 0xcd, 0x6c, 0xb0, 0xc7, 0xbe, 0x68, 0xfe, 0x52, 0x19, 0xe6, 0xcd, 0x75, 0x6a, 0x8b, 0x00, 0xef, 0x6b, 0x4b, + 0x50, 0x2b, 0x2c, 0xef, 0x9b, 0x47, 0x0d, 0x0c, 0xe6, 0xb5, 0x73, 0x64, 0x50, 0xe9, 0xb3, 0x86, 0x36, 0x34, 0x7a, + 0x7b, 0xad, 0xc8, 0x1f, 0x87, 0xf0, 0xae, 0x39, 0x7c, 0xe6, 0xf0, 0xb9, 0x14, 0xf0, 0xf5, 0x70, 0x28, 0xd3, 0xab, + 0xa9, 0x4d, 0xc1, 0xca, 0xfd, 0xbc, 0x56, 0xc2, 0x89, 0x67, 0xcf, 0x31, 0xc8, 0xfd, 0x7c, 0xf0, 0x7a, 0x88, 0xf6, + 0x58, 0xa7, 0xa3, 0xa4, 0x60, 0x56, 0x36, 0xa2, 0x36, 0xb2, 0xa7, 0xae, 0x75, 0x5a, 0xc3, 0x6b, 0x50, 0x8a, 0x39, + 0xb7, 0xf2, 0xa1, 0x61, 0xbe, 0x1e, 0x72, 0x31, 0x0e, 0x37, 0x01, 0xed, 0x55, 0xb7, 0x36, 0x17, 0x82, 0x96, 0x80, + 0x6e, 0x6a, 0xa4, 0x5b, 0xc1, 0xca, 0xac, 0x90, 0x9a, 0xa1, 0xf0, 0x1c, 0x6e, 0xf0, 0xc3, 0x1c, 0x53, 0x7e, 0xbc, + 0xdb, 0x64, 0x26, 0xf5, 0xd3, 0x6e, 0x33, 0xa9, 0xab, 0xbd, 0xcc, 0xa4, 0x7e, 0xfa, 0xe2, 0x66, 0x52, 0xef, 0x54, + 0x33, 0x29, 0x58, 0xc4, 0xb7, 0x6c, 0x2f, 0xdb, 0x25, 0x61, 0x11, 0x11, 0xdf, 0xa7, 0x03, 0x97, 0xf3, 0xaf, 0xa9, + 0x3f, 0x63, 0x70, 0x27, 0xe7, 0xab, 0x12, 0xc6, 0x53, 0xb0, 0x63, 0xfa, 0xf3, 0x2d, 0x8e, 0xc2, 0x78, 0xaa, 0xda, + 0x1b, 0x45, 0x3c, 0xe8, 0x69, 0x11, 0xc8, 0x88, 0x6c, 0x7c, 0x1c, 0x53, 0x84, 0x3d, 0xb2, 0x0e, 0x0d, 0x25, 0xb1, + 0xb3, 0x34, 0xe0, 0x6a, 0x0b, 0x2b, 0xa0, 0x1e, 0x1a, 0x10, 0xc9, 0x86, 0xed, 0x97, 0x22, 0xbc, 0x83, 0xda, 0x83, + 0x34, 0x94, 0xa5, 0x50, 0x09, 0x6b, 0xfd, 0x97, 0x95, 0xfb, 0xed, 0xb5, 0xdb, 0xef, 0xb8, 0xe0, 0x9f, 0x0c, 0x37, + 0x3a, 0x2c, 0x70, 0xfa, 0x9d, 0x0e, 0x14, 0xdc, 0x2b, 0x05, 0x6d, 0x28, 0x08, 0x94, 0x82, 0x2e, 0x14, 0xf8, 0x4a, + 0xc1, 0x11, 0x14, 0x8c, 0x95, 0x82, 0x63, 0x28, 0xb8, 0xd3, 0xf3, 0xeb, 0x48, 0x0e, 0xf7, 0xd8, 0xb8, 0x31, 0xe9, + 0x06, 0x21, 0xca, 0x8e, 0x4d, 0x17, 0x0c, 0x87, 0xbc, 0x69, 0x2f, 0x36, 0x49, 0x98, 0xd7, 0x4b, 0xcc, 0xfb, 0x19, + 0xa3, 0x58, 0xc9, 0x6f, 0x90, 0xe6, 0xd8, 0x59, 0x0c, 0xa6, 0xc3, 0x22, 0x06, 0x81, 0x80, 0x83, 0xa6, 0x1b, 0x20, + 0xa0, 0xe9, 0xcb, 0x95, 0x13, 0x71, 0x1c, 0x94, 0xb5, 0x2c, 0xde, 0xd1, 0xe7, 0x2c, 0xb9, 0x05, 0x0a, 0x6b, 0x8e, + 0x96, 0x2a, 0x04, 0xfc, 0x12, 0x3a, 0xfd, 0x37, 0x6c, 0xb4, 0x9c, 0x6a, 0x97, 0xf1, 0x74, 0xa7, 0x7a, 0x5e, 0x7d, + 0x05, 0xa3, 0xd4, 0x49, 0xd9, 0x61, 0x89, 0x6d, 0xc9, 0xbf, 0x45, 0x8f, 0x79, 0xb9, 0x7e, 0x06, 0x63, 0xd3, 0x32, + 0x32, 0x0e, 0x81, 0xef, 0x00, 0x8c, 0x14, 0xfd, 0xf8, 0x25, 0xc0, 0x59, 0x79, 0xbe, 0xf2, 0x94, 0xf1, 0x9c, 0xfd, + 0xc0, 0xd2, 0xd4, 0x9b, 0x8a, 0xfa, 0xf5, 0x71, 0x82, 0x41, 0x8c, 0xbc, 0x7f, 0x21, 0x00, 0x41, 0x72, 0x16, 0xd4, + 0xec, 0x1e, 0x92, 0xf8, 0x5e, 0x03, 0xcb, 0x1a, 0xd8, 0x50, 0x85, 0x0d, 0x40, 0x60, 0xc3, 0x12, 0x96, 0xb5, 0xf5, + 0x70, 0xf8, 0xef, 0x58, 0x58, 0x2d, 0xcc, 0xbc, 0x69, 0xb5, 0x88, 0xf6, 0x41, 0xae, 0x8e, 0x4d, 0x2a, 0xcb, 0x4b, + 0x85, 0x9f, 0xa3, 0xfd, 0x0d, 0xe3, 0xe9, 0x9f, 0xaa, 0xfa, 0xdd, 0xa2, 0xb2, 0xff, 0x10, 0x99, 0x41, 0x36, 0xb4, + 0x11, 0xc6, 0x9a, 0x0d, 0x20, 0xec, 0x45, 0xd9, 0xcc, 0x42, 0xef, 0xaa, 0x56, 0x3b, 0x32, 0x4c, 0x1b, 0xd7, 0x76, + 0x5d, 0xf5, 0x29, 0xed, 0x25, 0xd3, 0x91, 0xd7, 0x72, 0xdb, 0xc7, 0xa6, 0xf8, 0xb3, 0x9d, 0xae, 0x91, 0x63, 0x0f, + 0xda, 0x38, 0xb8, 0x5b, 0x4f, 0xe2, 0x28, 0xb3, 0x26, 0xde, 0x3c, 0x08, 0x1f, 0x7a, 0xf3, 0x38, 0x8a, 0xd3, 0x85, + 0xe7, 0xb3, 0x3e, 0x79, 0xd0, 0x81, 0x2b, 0x69, 0x1f, 0xa3, 0x15, 0x70, 0x87, 0x39, 0xd7, 0x6e, 0x27, 0x6c, 0x4e, + 0xad, 0x65, 0x30, 0x82, 0x49, 0xc8, 0x56, 0x39, 0xff, 0x7c, 0xa9, 0x32, 0x55, 0xc5, 0x2d, 0x47, 0x2d, 0x80, 0x23, + 0xe5, 0x91, 0x0e, 0x20, 0xbe, 0x4f, 0x7f, 0xe1, 0x8d, 0x31, 0x38, 0x9f, 0xdd, 0xee, 0x26, 0x6c, 0xae, 0xd9, 0xdd, + 0x8d, 0x9d, 0x27, 0xf1, 0xfd, 0x19, 0x8c, 0x16, 0x1b, 0x5b, 0x29, 0x0b, 0x27, 0xf8, 0xc6, 0x42, 0xe7, 0x0a, 0xd1, + 0x8f, 0x85, 0x17, 0x71, 0xe8, 0x8d, 0xcd, 0xfb, 0xf0, 0xba, 0xd7, 0xd6, 0x9c, 0xfe, 0x3c, 0x88, 0x2c, 0x9a, 0xce, + 0xb1, 0xb3, 0x50, 0xfa, 0x52, 0xe1, 0x67, 0xac, 0xb1, 0xba, 0xab, 0x39, 0x7d, 0xb8, 0xac, 0x4d, 0xc2, 0xf8, 0xbe, + 0x37, 0x0b, 0xc6, 0x63, 0x16, 0xf5, 0x71, 0xcc, 0xb2, 0x90, 0x85, 0x61, 0xb0, 0x48, 0x83, 0xb4, 0x3f, 0xf7, 0x56, + 0xbc, 0xd7, 0xc3, 0x4d, 0xbd, 0x76, 0x78, 0xaf, 0x9d, 0xbd, 0x7b, 0x55, 0xba, 0x01, 0x47, 0x0e, 0xea, 0x87, 0x0f, + 0xad, 0xab, 0x39, 0x95, 0x79, 0xee, 0xdd, 0xeb, 0x22, 0x61, 0xeb, 0xb9, 0x97, 0x4c, 0x83, 0xa8, 0xe7, 0xe4, 0xf6, + 0xdd, 0x9a, 0x36, 0xc6, 0xd3, 0x93, 0x93, 0x93, 0xdc, 0x1e, 0x8b, 0x27, 0x67, 0x3c, 0xce, 0x6d, 0x5f, 0x3c, 0x4d, + 0x26, 0x8e, 0x33, 0x99, 0xe4, 0x76, 0x20, 0x0a, 0x3a, 0x6d, 0x7f, 0xdc, 0x69, 0xe7, 0xf6, 0xbd, 0x52, 0x23, 0xb7, + 0x19, 0x7f, 0x4a, 0xd8, 0xb8, 0x8f, 0x1b, 0xe9, 0x9e, 0x96, 0xfe, 0xd8, 0x71, 0x72, 0xc4, 0x00, 0xd7, 0x25, 0xdc, + 0x84, 0x82, 0x9d, 0x9b, 0xf5, 0xde, 0x35, 0xb5, 0xe2, 0x73, 0xbe, 0xdf, 0x58, 0x6f, 0xec, 0x25, 0x9f, 0x6e, 0x34, + 0x65, 0x16, 0x9e, 0x47, 0xd5, 0xd6, 0x02, 0x0c, 0xd6, 0xaa, 0x07, 0x51, 0xab, 0xfa, 0xa3, 0x38, 0x81, 0x33, 0x9b, + 0x78, 0xe3, 0x60, 0x99, 0xf6, 0xdc, 0xf6, 0x62, 0x25, 0x8a, 0xf8, 0x5e, 0x2f, 0x0a, 0xf0, 0xec, 0xf5, 0xd2, 0x38, + 0x0c, 0xc6, 0xa2, 0x68, 0xd3, 0x59, 0x72, 0xdb, 0x46, 0x1f, 0x7d, 0xb6, 0x03, 0x8c, 0x3c, 0xe0, 0x85, 0xa1, 0x66, + 0x77, 0x52, 0x8d, 0x79, 0x29, 0xca, 0x73, 0x35, 0x27, 0x25, 0xb8, 0xa0, 0x7f, 0xb6, 0x7b, 0xb8, 0x58, 0xc9, 0x3d, + 0xef, 0x1e, 0x2d, 0x56, 0xf9, 0xd7, 0x73, 0x36, 0x0e, 0x3c, 0xad, 0x55, 0xec, 0x26, 0xd7, 0x01, 0x99, 0xaf, 0xb1, + 0xde, 0xb0, 0x4d, 0xc5, 0xb1, 0x80, 0xe8, 0x7e, 0x4f, 0x82, 0xf9, 0x22, 0x4e, 0x32, 0x2f, 0xca, 0xf2, 0x7c, 0x78, + 0x93, 0xe7, 0xfd, 0xab, 0xa0, 0x75, 0xfd, 0xcf, 0x16, 0xd1, 0x69, 0xd2, 0x91, 0xe4, 0xc6, 0x8d, 0xf9, 0x96, 0xa9, + 0xf6, 0x18, 0x40, 0xc6, 0xd0, 0x16, 0x43, 0xad, 0x4c, 0x54, 0xb2, 0x5e, 0x99, 0x80, 0x2c, 0xab, 0x93, 0x7d, 0x47, + 0xb9, 0x0a, 0x52, 0x20, 0xa8, 0xf0, 0x96, 0x0d, 0xae, 0x14, 0xdb, 0x0e, 0x60, 0x56, 0xb0, 0x32, 0x99, 0xd6, 0x3f, + 0xdb, 0xc4, 0x33, 0x7e, 0xb3, 0x9b, 0x67, 0xfc, 0x39, 0xdb, 0x87, 0x67, 0xfc, 0xe6, 0x8b, 0xf3, 0x8c, 0xcf, 0xea, + 0xa6, 0xf5, 0x17, 0xf1, 0x40, 0x97, 0x12, 0x7d, 0x20, 0x4d, 0x09, 0x05, 0xad, 0xb9, 0xf8, 0xc3, 0x96, 0xf0, 0xa2, + 0x37, 0x4a, 0xc3, 0x46, 0x94, 0x1b, 0x84, 0xaf, 0xef, 0xa2, 0xc1, 0x3f, 0x12, 0xf5, 0x79, 0x32, 0x19, 0xbc, 0x89, + 0x95, 0x02, 0xf9, 0xc4, 0x4d, 0x1d, 0x4a, 0x01, 0x06, 0xe8, 0x8d, 0xb0, 0x70, 0xc4, 0x14, 0x0c, 0xe0, 0x9f, 0x4c, + 0x16, 0xbd, 0x63, 0x69, 0xd9, 0xd5, 0x2f, 0x0f, 0xa1, 0x25, 0xcd, 0x29, 0x85, 0x17, 0x4a, 0x4d, 0x94, 0x38, 0x65, + 0x19, 0x77, 0x1b, 0xfd, 0xf6, 0xe1, 0x62, 0xdc, 0xba, 0x88, 0x8d, 0x3c, 0x48, 0xdf, 0x55, 0x7d, 0x40, 0xb8, 0xae, + 0x65, 0xa0, 0x4e, 0x27, 0xe7, 0xd6, 0x59, 0x6a, 0x8e, 0x65, 0x78, 0x4d, 0xcd, 0xcf, 0x4b, 0x33, 0xed, 0xa9, 0x0d, + 0x79, 0xae, 0xa7, 0x1a, 0x31, 0xe6, 0x06, 0xf8, 0x6b, 0xce, 0x01, 0x62, 0xfa, 0x2a, 0x74, 0x9d, 0x1d, 0x53, 0xf3, + 0x60, 0x9c, 0xe7, 0x46, 0x5f, 0x00, 0x42, 0x21, 0xb4, 0x6c, 0x17, 0x13, 0x97, 0xde, 0x4b, 0x0b, 0x02, 0xae, 0x91, + 0x23, 0x75, 0xdb, 0x05, 0xa8, 0xaf, 0xb9, 0x72, 0x8e, 0xc3, 0x4c, 0xd7, 0x08, 0x7c, 0x64, 0xd6, 0xa0, 0x4c, 0x08, + 0xd4, 0xfa, 0x12, 0xfe, 0xe2, 0x95, 0x28, 0xa8, 0xdb, 0x47, 0x12, 0x70, 0x50, 0xff, 0x0e, 0x8e, 0xee, 0x44, 0xfe, + 0xb9, 0x0e, 0xb0, 0xc7, 0xeb, 0xe0, 0x43, 0xae, 0x4b, 0xde, 0x0f, 0xb7, 0xdf, 0xd9, 0xe9, 0x01, 0x34, 0x38, 0xab, + 0xa8, 0xe9, 0x77, 0x58, 0xff, 0x01, 0x2b, 0x91, 0xde, 0x9b, 0x76, 0x7a, 0xaf, 0xbd, 0x58, 0x8b, 0x20, 0x11, 0x99, + 0xb7, 0xb0, 0xe0, 0x8a, 0x8f, 0xb8, 0x97, 0x63, 0x3c, 0x25, 0x1e, 0x45, 0x7f, 0x99, 0x02, 0x6e, 0xc4, 0x8b, 0x2a, + 0xe2, 0x9f, 0xbe, 0xbf, 0x4c, 0xd2, 0x38, 0xe9, 0x2d, 0xe2, 0x20, 0xca, 0x58, 0x92, 0x23, 0xa8, 0xae, 0x11, 0x3e, + 0x02, 0x3c, 0x37, 0xeb, 0x78, 0xe1, 0xf9, 0x41, 0xf6, 0xd0, 0x73, 0x38, 0x4b, 0xe1, 0xf4, 0x39, 0x77, 0xe0, 0x34, + 0xd6, 0xef, 0x71, 0x68, 0xbe, 0x44, 0xc6, 0x2f, 0xa9, 0xb3, 0x33, 0xea, 0x36, 0xef, 0x2b, 0x6f, 0x29, 0x4c, 0x06, + 0xb0, 0x1f, 0x5e, 0x62, 0x4d, 0x01, 0xcb, 0xc3, 0x52, 0x3b, 0x63, 0x36, 0x35, 0x11, 0x6b, 0x83, 0x5c, 0x5e, 0xfc, + 0xd9, 0x5d, 0x43, 0x73, 0x9a, 0x8b, 0x81, 0xe3, 0x31, 0xf6, 0x19, 0x59, 0xcf, 0x83, 0xa4, 0x52, 0xe6, 0x3e, 0x35, + 0x47, 0x6c, 0x12, 0x27, 0x8c, 0x42, 0xaa, 0xba, 0x27, 0x8b, 0xd5, 0xfe, 0xdd, 0x6f, 0x9f, 0x7e, 0x73, 0x3f, 0x51, + 0x9c, 0xb5, 0x44, 0x67, 0xc6, 0x8e, 0xde, 0xea, 0xf4, 0x0c, 0x58, 0x43, 0x82, 0xbc, 0x4f, 0xd1, 0xab, 0x7a, 0xba, + 0xde, 0x6f, 0x8c, 0x5c, 0xb5, 0x88, 0x39, 0xcd, 0x4b, 0x58, 0xe8, 0x65, 0xc1, 0x9d, 0xe0, 0x19, 0x3b, 0x47, 0x8b, + 0x95, 0x58, 0x63, 0x24, 0x78, 0x8f, 0x58, 0xa4, 0xca, 0x50, 0xc4, 0x22, 0x55, 0x8b, 0x71, 0x91, 0xfa, 0xb5, 0xd9, + 0x88, 0x60, 0x0e, 0x15, 0x4a, 0xdf, 0x5d, 0xac, 0x54, 0x12, 0x5d, 0x34, 0x93, 0x94, 0xba, 0x1a, 0x85, 0x6b, 0x1e, + 0x8c, 0xc7, 0x21, 0xcb, 0x4b, 0x0b, 0x5d, 0x5e, 0x4b, 0x05, 0x38, 0x12, 0x0e, 0xde, 0x28, 0x8d, 0xc3, 0x65, 0xc6, + 0x9a, 0xc1, 0x45, 0xc0, 0x69, 0x3b, 0x05, 0x70, 0xf0, 0x77, 0x79, 0xac, 0x5d, 0x60, 0xb7, 0x61, 0x9b, 0x38, 0x7d, + 0x08, 0xba, 0x6b, 0x75, 0xca, 0x43, 0x87, 0x57, 0x72, 0xd0, 0x66, 0xc3, 0x44, 0x4c, 0x20, 0x4b, 0x84, 0xbd, 0x35, + 0xdb, 0xe5, 0x65, 0x32, 0xf0, 0xa8, 0x2c, 0xca, 0xcb, 0x93, 0xf9, 0x73, 0xce, 0xd8, 0xab, 0xe6, 0x33, 0xf6, 0x4a, + 0x9c, 0xb1, 0xed, 0x3b, 0xf3, 0xe9, 0xc4, 0x85, 0xff, 0xfa, 0xc5, 0x84, 0x7a, 0x8e, 0xd6, 0x59, 0xac, 0x34, 0x77, + 0xb1, 0xd2, 0xac, 0xf6, 0x62, 0xa5, 0x61, 0xd7, 0x68, 0x7f, 0x61, 0xda, 0x6d, 0xc3, 0x74, 0x34, 0x28, 0x84, 0x3f, + 0xa7, 0xf4, 0xca, 0x3d, 0x84, 0x77, 0xd0, 0xaa, 0x5b, 0x7f, 0xd7, 0xde, 0x7e, 0xd4, 0xe9, 0x2c, 0x09, 0xa4, 0x6d, + 0xd8, 0x99, 0x37, 0x1a, 0xb1, 0x71, 0x6f, 0x12, 0xfb, 0xcb, 0xf4, 0xdf, 0x7c, 0xfc, 0x1c, 0x88, 0x5b, 0x11, 0x41, + 0xa5, 0x1f, 0xd1, 0x14, 0x14, 0x25, 0x77, 0x4c, 0xf4, 0xb0, 0x96, 0xeb, 0xd4, 0xa3, 0x08, 0xc1, 0x6d, 0xfb, 0xb0, + 0x61, 0x93, 0x37, 0x03, 0xfa, 0x4f, 0x5b, 0xa5, 0xcd, 0x28, 0xe6, 0x33, 0xc0, 0xb2, 0x15, 0x1c, 0x8f, 0x87, 0x06, + 0x5f, 0x4d, 0xe7, 0xa4, 0x79, 0xb8, 0xd7, 0xe2, 0x4b, 0x37, 0x82, 0xa8, 0x70, 0xba, 0xc5, 0x9d, 0x3e, 0xb6, 0xf7, + 0xba, 0x69, 0x8f, 0xd4, 0x7a, 0xdd, 0x42, 0x10, 0x8a, 0xba, 0x7b, 0x62, 0xf9, 0xa7, 0xaf, 0x0e, 0xe1, 0x3f, 0xe2, + 0xea, 0x7f, 0xce, 0x9a, 0x18, 0xf5, 0x8b, 0xb2, 0x95, 0x35, 0xb1, 0x4a, 0xc8, 0x88, 0xef, 0x5f, 0x7f, 0x32, 0x79, + 0x5c, 0x83, 0xbd, 0x6b, 0x93, 0xe9, 0x52, 0xb5, 0xf6, 0xb7, 0x71, 0x0c, 0xd9, 0x2b, 0xeb, 0xd5, 0x05, 0x78, 0xc8, + 0x90, 0x3c, 0x1b, 0x40, 0x23, 0x71, 0x8f, 0x20, 0x2d, 0xbe, 0x8e, 0x6d, 0xe8, 0x2a, 0xf1, 0x76, 0xd3, 0x55, 0xe2, + 0xcd, 0xee, 0xab, 0xc4, 0xf7, 0x7b, 0x5d, 0x25, 0xde, 0x7c, 0xf1, 0xab, 0xc4, 0xdb, 0xfa, 0x55, 0xe2, 0x2a, 0x16, + 0xd6, 0xaa, 0xe6, 0xc5, 0x92, 0xff, 0xfc, 0x48, 0x4a, 0xb9, 0xcb, 0x78, 0xd0, 0x75, 0x28, 0xea, 0xef, 0xd5, 0x1f, + 0xbe, 0x58, 0xe0, 0x46, 0x7c, 0x8f, 0xe6, 0x5b, 0xc5, 0xd5, 0x82, 0x63, 0x76, 0xfc, 0x8e, 0x52, 0x1c, 0xc6, 0xd1, + 0xf4, 0x27, 0x50, 0xca, 0x82, 0x38, 0x30, 0x51, 0x5e, 0x04, 0xe9, 0x4f, 0xf1, 0x62, 0xb9, 0xb8, 0x80, 0xbe, 0x3e, + 0x06, 0x69, 0x30, 0x0a, 0x99, 0x74, 0xc6, 0x25, 0x73, 0x33, 0x2e, 0x13, 0x07, 0xfb, 0x4e, 0xf1, 0xd3, 0x5b, 0x89, + 0x9f, 0x68, 0x01, 0xca, 0x7f, 0x93, 0x1d, 0x9b, 0xde, 0x7c, 0x11, 0x11, 0x4a, 0x40, 0x65, 0xd0, 0x8f, 0xbf, 0x8c, + 0x5c, 0xc5, 0x46, 0xc3, 0x2c, 0x85, 0xbd, 0xc3, 0xc6, 0x7e, 0x58, 0xed, 0x52, 0xb3, 0x34, 0x4c, 0x19, 0x85, 0xaa, + 0x2e, 0x86, 0x9f, 0xc7, 0xcb, 0x94, 0x8d, 0xe3, 0xfb, 0x48, 0x37, 0x23, 0x69, 0xc0, 0x0f, 0x1a, 0x4e, 0xd9, 0x06, + 0xf3, 0x27, 0x7e, 0x40, 0x46, 0x39, 0x4e, 0x5a, 0x3a, 0xa4, 0xef, 0x5c, 0x2e, 0x2c, 0x52, 0x35, 0x5b, 0x38, 0x45, + 0x5d, 0x26, 0xfa, 0x79, 0xd2, 0x6a, 0xc5, 0x83, 0xc7, 0xb5, 0x14, 0xa6, 0x1a, 0xb1, 0xcd, 0xa5, 0xc2, 0x69, 0x2b, + 0x12, 0xc2, 0x45, 0x11, 0x0a, 0xa2, 0x61, 0xe1, 0xf8, 0x1b, 0x72, 0x0b, 0x2d, 0xde, 0x42, 0x20, 0x8d, 0x7c, 0xc9, + 0xd7, 0x83, 0x07, 0x46, 0xa0, 0xc7, 0xd7, 0x0a, 0x18, 0xdf, 0xdd, 0xb1, 0x24, 0xf4, 0x1e, 0x5a, 0x46, 0x1e, 0x47, + 0x3f, 0x00, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0xf3, 0x95, 0x34, 0xec, 0xa5, 0xc6, 0x10, 0x1e, 0xe0, 0x14, + 0xa2, 0x8c, 0x00, 0x32, 0xc5, 0x4e, 0xd9, 0x3f, 0x4c, 0xfa, 0xf7, 0x9f, 0x46, 0x6e, 0x5e, 0xc6, 0xf2, 0x43, 0x7f, + 0x5f, 0xec, 0xf1, 0x99, 0xe7, 0xcf, 0x9f, 0x6c, 0x9e, 0x76, 0x39, 0x43, 0x79, 0x43, 0x6b, 0x63, 0xe3, 0x29, 0x80, + 0x51, 0x5c, 0xc5, 0x4b, 0x7f, 0x86, 0x86, 0xa5, 0x5f, 0x6e, 0xbe, 0x19, 0xf4, 0x89, 0x89, 0x3a, 0xe5, 0xd4, 0x2b, + 0x45, 0x05, 0x14, 0xf0, 0xfb, 0x6f, 0x21, 0x06, 0xe5, 0xff, 0x11, 0x0c, 0xf5, 0x5d, 0xc3, 0x6f, 0xf1, 0xc1, 0xe3, + 0x36, 0x6f, 0x1f, 0xf2, 0x49, 0xf2, 0xe8, 0x0e, 0x42, 0xb9, 0xd6, 0x8c, 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0x48, 0x6a, + 0x9b, 0x82, 0xc4, 0x89, 0xaf, 0x30, 0x9b, 0xae, 0xe9, 0xdc, 0xac, 0xdf, 0x64, 0x1c, 0x5b, 0x55, 0x90, 0x0c, 0x37, + 0x79, 0x60, 0x88, 0xbe, 0xaa, 0xef, 0xe6, 0x41, 0x64, 0x62, 0x20, 0xf4, 0xfa, 0x1b, 0x6f, 0x05, 0xa1, 0x80, 0x01, + 0xb9, 0x55, 0x5f, 0x41, 0xa1, 0xa9, 0xfa, 0xa4, 0x41, 0xb6, 0x23, 0xbd, 0x11, 0x12, 0x42, 0x8b, 0x37, 0xfc, 0x8b, + 0xa6, 0x69, 0x9a, 0xbc, 0x46, 0x68, 0xf2, 0x1e, 0x81, 0xe5, 0x78, 0x1d, 0x00, 0x6d, 0x49, 0xbe, 0x58, 0x51, 0x09, + 0xdc, 0x0c, 0x50, 0x27, 0x2b, 0x0a, 0x78, 0xb4, 0xbb, 0xae, 0x23, 0x0a, 0xc4, 0x85, 0x1e, 0x22, 0x95, 0x79, 0x09, + 0x04, 0xc5, 0xed, 0x69, 0x78, 0x61, 0xc7, 0xb7, 0x5c, 0x12, 0xac, 0x39, 0xf4, 0x38, 0xec, 0xb3, 0xe6, 0xb0, 0x68, + 0x91, 0x82, 0x05, 0x41, 0xeb, 0x50, 0x89, 0x72, 0x6c, 0xb2, 0x06, 0xdc, 0x88, 0xf7, 0xa2, 0x55, 0x36, 0x67, 0xd1, + 0x52, 0xc7, 0xb4, 0x48, 0x18, 0xa6, 0x0e, 0xea, 0xbc, 0x21, 0x66, 0x0b, 0xb0, 0x4d, 0x73, 0xcb, 0x19, 0xd1, 0xc2, + 0x94, 0xa3, 0x54, 0xcf, 0xf4, 0xb9, 0x62, 0x33, 0xe5, 0xb8, 0xad, 0x4a, 0x21, 0xf8, 0x92, 0xc6, 0x55, 0x27, 0x29, + 0xb2, 0x3c, 0x86, 0x3e, 0x28, 0x40, 0x04, 0x17, 0x17, 0x09, 0xb0, 0xb7, 0xbc, 0xea, 0xa2, 0x49, 0x8d, 0x8c, 0x57, + 0x11, 0x14, 0x25, 0x46, 0xbd, 0x1b, 0x3e, 0x4e, 0x88, 0xcd, 0xb3, 0xb1, 0x1f, 0xbf, 0xd6, 0xcf, 0x86, 0x49, 0x7f, + 0x62, 0x0f, 0x44, 0x48, 0x08, 0x54, 0x9f, 0xd8, 0x03, 0xd8, 0xfe, 0xbd, 0x05, 0x69, 0x8a, 0xbe, 0x05, 0x5d, 0x9b, + 0x10, 0xed, 0xde, 0x87, 0x78, 0x4d, 0x5b, 0x0e, 0x90, 0x93, 0x6f, 0xc1, 0xe2, 0x08, 0x62, 0x48, 0x6c, 0x2c, 0x0e, + 0x31, 0x37, 0xa9, 0x6f, 0x35, 0xc2, 0xd8, 0x6a, 0x38, 0x1a, 0xc6, 0x0b, 0xd7, 0x71, 0x0e, 0x6a, 0xf5, 0x41, 0x90, + 0xdd, 0x54, 0xdb, 0x30, 0xb3, 0x81, 0xeb, 0x58, 0xc1, 0x0b, 0xbb, 0xdd, 0xaf, 0xd1, 0x68, 0x25, 0x9c, 0xe2, 0x10, + 0xc5, 0x5f, 0x67, 0xcf, 0xd6, 0xad, 0xda, 0x81, 0x34, 0xaa, 0x26, 0xea, 0x38, 0xb6, 0x9c, 0xcb, 0xbf, 0x86, 0x75, + 0xd2, 0x4f, 0xc1, 0x1c, 0x29, 0xb5, 0xc7, 0x10, 0x02, 0x02, 0xb7, 0xe0, 0x18, 0xfd, 0x55, 0x7b, 0xa9, 0xb5, 0xe8, + 0xf8, 0x18, 0xc6, 0x50, 0x66, 0x8c, 0x16, 0x1e, 0x5c, 0x6a, 0x07, 0x95, 0x2f, 0xa6, 0x55, 0x0c, 0xc7, 0x43, 0x8f, + 0xb2, 0x42, 0xa3, 0xb7, 0x95, 0x5b, 0xc0, 0xfe, 0x37, 0x90, 0x4f, 0x7b, 0x04, 0x3e, 0xff, 0x50, 0x03, 0xc2, 0x87, + 0xef, 0xec, 0x70, 0xb9, 0x28, 0x77, 0x57, 0x26, 0x92, 0xfb, 0x77, 0x86, 0x44, 0x07, 0x75, 0x68, 0xb2, 0xbf, 0x66, + 0x72, 0xf7, 0xc8, 0x2e, 0x59, 0x34, 0x2e, 0x77, 0x58, 0xa1, 0x5f, 0xfb, 0x77, 0x57, 0xc2, 0x28, 0x10, 0x57, 0x3f, + 0x6e, 0xc0, 0x28, 0x79, 0x1c, 0xe1, 0xe6, 0xa7, 0xe3, 0x16, 0xec, 0xc5, 0xc5, 0x60, 0x03, 0x0a, 0x8a, 0x25, 0x9b, + 0x29, 0x42, 0x71, 0x08, 0xde, 0x8c, 0x2e, 0xb7, 0x2d, 0xc1, 0x88, 0x6e, 0xdc, 0x89, 0x99, 0xb0, 0x29, 0x2c, 0xda, + 0x04, 0x3c, 0x1c, 0xe3, 0xbe, 0x52, 0xeb, 0x60, 0xb7, 0xd4, 0x3a, 0xdb, 0x25, 0xb5, 0x26, 0xef, 0xa5, 0xfb, 0xc4, + 0x5b, 0x28, 0xfe, 0x6f, 0x82, 0x39, 0x57, 0xdd, 0xe0, 0x4a, 0xa2, 0x6e, 0x74, 0x76, 0x12, 0xad, 0x6a, 0xbd, 0x91, + 0x95, 0x20, 0x8a, 0xbf, 0x95, 0x0b, 0x8a, 0x50, 0xa8, 0xab, 0xb2, 0xf1, 0xab, 0x42, 0x36, 0x4e, 0xb7, 0x9a, 0xc2, + 0x71, 0x45, 0x70, 0xff, 0x8a, 0x4b, 0x98, 0xbc, 0x1d, 0x14, 0xae, 0x61, 0xc5, 0x48, 0x15, 0x6f, 0xa7, 0xe2, 0xa2, + 0xa1, 0xb8, 0xd0, 0x89, 0x5b, 0x46, 0xd9, 0x93, 0xae, 0x5c, 0xb5, 0x70, 0xa9, 0x2b, 0xca, 0x41, 0xea, 0x8e, 0x43, + 0x96, 0xc5, 0xea, 0xb6, 0x29, 0xbb, 0xbb, 0xa8, 0xaf, 0x95, 0x4d, 0x22, 0xfd, 0x52, 0x08, 0xc0, 0x42, 0x4c, 0x5f, + 0xd1, 0x6b, 0x4b, 0x1b, 0x08, 0x1c, 0x64, 0x83, 0x13, 0xdd, 0x6e, 0xe9, 0x3c, 0xa5, 0x0c, 0x28, 0xb4, 0xf0, 0xaa, + 0x0c, 0x02, 0xe1, 0x7b, 0xb3, 0x6e, 0xa0, 0xf2, 0x48, 0xe4, 0x39, 0x7d, 0x07, 0xf1, 0xa2, 0xe6, 0xa8, 0x8a, 0x7c, + 0x3c, 0x99, 0x16, 0x99, 0xe7, 0x62, 0xd5, 0x7a, 0xa7, 0x24, 0xc4, 0x59, 0x73, 0x4f, 0x94, 0xb2, 0x8c, 0x9e, 0xd7, + 0xe8, 0x89, 0xef, 0xf2, 0xad, 0x93, 0x2c, 0x23, 0x0c, 0xef, 0x6e, 0x65, 0x89, 0xe7, 0x7f, 0x52, 0x86, 0x2c, 0xe4, + 0x9c, 0x20, 0x03, 0x2e, 0x6b, 0x0a, 0xfa, 0x1e, 0x46, 0x43, 0x64, 0x3d, 0xbb, 0x9d, 0x2a, 0xd2, 0x97, 0xde, 0x53, + 0xa7, 0xe3, 0xbd, 0x9a, 0x1c, 0x56, 0x84, 0xa2, 0xed, 0x6e, 0x59, 0x64, 0xbe, 0x61, 0x1c, 0xd9, 0x6c, 0x39, 0x1f, + 0xad, 0x55, 0xd9, 0xaa, 0x22, 0x72, 0xad, 0x8b, 0x59, 0xd5, 0xcf, 0x4e, 0x26, 0x93, 0xb2, 0xa0, 0xd1, 0xd1, 0x0e, + 0x51, 0x58, 0xf8, 0xd4, 0x71, 0x9c, 0xea, 0xd8, 0xb7, 0x83, 0xdd, 0x42, 0xb9, 0xed, 0x49, 0xe3, 0x88, 0x11, 0xb6, + 0xbb, 0xe0, 0x57, 0x07, 0x47, 0x6e, 0x17, 0x27, 0xbb, 0x64, 0x16, 0xd1, 0x27, 0x63, 0x88, 0x20, 0x63, 0xf3, 0xb4, + 0xe7, 0x33, 0xd4, 0xc1, 0xd8, 0xca, 0x81, 0x46, 0xc3, 0x01, 0x6b, 0x0a, 0xa6, 0x22, 0xae, 0xd8, 0x15, 0x8e, 0x86, + 0xf2, 0xf0, 0x9a, 0xf0, 0x5e, 0x7c, 0x04, 0x0f, 0xca, 0xba, 0x2e, 0xd3, 0xc6, 0x69, 0x75, 0x9d, 0xbf, 0x96, 0xea, + 0x69, 0x40, 0x00, 0xd7, 0x42, 0xa1, 0x4d, 0xf2, 0x59, 0xfc, 0x7f, 0x29, 0xff, 0x7f, 0xb5, 0x58, 0x95, 0xed, 0x47, + 0x4e, 0x40, 0xa2, 0x5d, 0x9c, 0x16, 0x1a, 0x75, 0xd3, 0x1e, 0x90, 0x56, 0x06, 0x13, 0x55, 0x81, 0x0e, 0x4a, 0xfa, + 0x52, 0x0e, 0x8c, 0x06, 0xf1, 0x3b, 0x72, 0xcc, 0xb0, 0xc4, 0x85, 0x08, 0xb1, 0xc8, 0xe0, 0x06, 0x73, 0x30, 0x5f, + 0x9e, 0xa0, 0xfe, 0xa0, 0xb4, 0x27, 0x40, 0x1b, 0x5f, 0x9b, 0xdb, 0x5e, 0xe2, 0xfe, 0xaa, 0x5e, 0x4b, 0x74, 0x0c, + 0x20, 0x73, 0xe1, 0x10, 0xa2, 0x21, 0x81, 0x56, 0xd9, 0xdc, 0x34, 0x4a, 0xf9, 0x56, 0xd5, 0xb3, 0x89, 0x81, 0x61, + 0x77, 0xcd, 0x55, 0xa8, 0x6f, 0xa1, 0x2d, 0x80, 0xc9, 0xf2, 0xed, 0x87, 0xcf, 0x16, 0x2c, 0xb1, 0xba, 0x1f, 0x5d, + 0x5c, 0x72, 0xdc, 0xbf, 0x16, 0xd2, 0xce, 0x94, 0xce, 0x3f, 0xca, 0x17, 0xbf, 0x6f, 0x14, 0xe8, 0x5d, 0x95, 0x24, + 0x74, 0xdc, 0x5a, 0xbc, 0x6d, 0xec, 0x55, 0x7b, 0x1e, 0x44, 0xfb, 0xd7, 0xf5, 0x56, 0x7b, 0xd7, 0x05, 0x82, 0xb1, + 0x77, 0x65, 0xa0, 0x38, 0x64, 0xb9, 0x90, 0x0d, 0xbe, 0x57, 0x04, 0x8a, 0xaa, 0x93, 0xaf, 0x8e, 0xad, 0x88, 0xcb, + 0xbf, 0x5a, 0x02, 0xf3, 0xb9, 0x57, 0x8e, 0x03, 0x4d, 0xa4, 0x29, 0xd3, 0x8f, 0xb5, 0x13, 0xed, 0xb8, 0xa3, 0x1d, + 0x39, 0x3a, 0xdd, 0xc2, 0x06, 0x7a, 0xb7, 0x5d, 0x78, 0xef, 0x1d, 0x3a, 0xfa, 0xd9, 0xe9, 0x54, 0x10, 0x89, 0x49, + 0x10, 0x86, 0x84, 0x2a, 0xd2, 0x2c, 0x89, 0x3f, 0xb1, 0xb2, 0x9a, 0x85, 0xca, 0xb8, 0x11, 0x48, 0x5b, 0x3c, 0xc2, + 0xd9, 0xf1, 0xbd, 0x45, 0x0f, 0xcf, 0x86, 0x5a, 0x08, 0x06, 0x9c, 0x54, 0x8a, 0x9f, 0x00, 0x1a, 0x3c, 0xd2, 0xcf, + 0x4e, 0x21, 0x8a, 0x9f, 0x36, 0x1e, 0xe8, 0x3f, 0xb4, 0x8f, 0x35, 0xb7, 0x7b, 0x67, 0x75, 0x7c, 0xc7, 0x72, 0xed, + 0x43, 0xcd, 0xb1, 0x8f, 0xac, 0xb6, 0x7d, 0xac, 0xb5, 0xed, 0x2e, 0xfc, 0xeb, 0xbb, 0xf6, 0x2b, 0xcd, 0x81, 0x27, + 0xcd, 0xb5, 0x3b, 0xf8, 0x6f, 0xdb, 0x3e, 0xbe, 0xeb, 0x10, 0xa5, 0xf7, 0x74, 0x31, 0xe4, 0xca, 0x28, 0xc0, 0x09, + 0x44, 0x3f, 0x38, 0x3b, 0x5d, 0xa6, 0x4c, 0x5b, 0x0d, 0xf4, 0x57, 0xba, 0x36, 0x4b, 0xd8, 0x64, 0xa0, 0x3f, 0xf5, + 0x94, 0x52, 0xf7, 0xa4, 0xb1, 0xb8, 0x7d, 0xdc, 0x58, 0xdc, 0x39, 0x6a, 0x2c, 0x3e, 0xec, 0x96, 0x8b, 0x0f, 0xa6, + 0xf4, 0x4a, 0x49, 0xa2, 0x37, 0xf7, 0xb2, 0x24, 0x58, 0xb5, 0x5c, 0x0d, 0xd0, 0xb5, 0x05, 0xff, 0x1c, 0xb7, 0x0d, + 0xd9, 0x6a, 0x04, 0xad, 0x24, 0x34, 0x8e, 0x4f, 0x34, 0xf7, 0xe8, 0x6f, 0xed, 0x23, 0x1f, 0xea, 0x41, 0xca, 0x47, + 0xf8, 0xbb, 0xeb, 0x9c, 0xf8, 0x8e, 0x06, 0x0d, 0x5d, 0xf8, 0x6f, 0xd6, 0x6d, 0xfb, 0xf4, 0xe0, 0xc0, 0xfb, 0x8f, + 0xee, 0x71, 0xea, 0x58, 0x2e, 0xfc, 0xf7, 0xab, 0x54, 0xb9, 0x83, 0xc2, 0x5f, 0xed, 0xf7, 0xd0, 0xd1, 0x3a, 0x27, + 0xb3, 0xb6, 0xfd, 0xea, 0xee, 0xd8, 0x3e, 0x99, 0xb9, 0xc7, 0x1f, 0xe9, 0x29, 0xb4, 0xda, 0xf6, 0x2b, 0xf8, 0xfb, + 0xd8, 0x71, 0x66, 0x96, 0x6b, 0x9f, 0xdc, 0x75, 0xec, 0x4e, 0x68, 0x1d, 0xd9, 0x27, 0xf0, 0xf7, 0x2b, 0x80, 0x17, + 0xe0, 0xca, 0x73, 0x74, 0x6a, 0xb0, 0x31, 0x2a, 0xf6, 0x1b, 0xea, 0x47, 0xda, 0x87, 0x5a, 0xf7, 0xf0, 0x6f, 0x27, + 0x77, 0xd6, 0xe1, 0xcc, 0x6d, 0xdf, 0x59, 0x1b, 0x7f, 0x7e, 0x04, 0xc8, 0x6f, 0x5f, 0x38, 0x00, 0x23, 0x26, 0xe5, + 0xf8, 0xcb, 0xd0, 0xbc, 0xdc, 0x24, 0x46, 0x7f, 0xbf, 0x5b, 0x8c, 0xfe, 0xdd, 0x72, 0x1f, 0x31, 0xfa, 0xfb, 0x2f, + 0x2e, 0x46, 0xbf, 0xac, 0x5a, 0x71, 0xbf, 0xaf, 0x06, 0x0f, 0xff, 0x79, 0x5d, 0x65, 0x92, 0x03, 0xaf, 0x75, 0x7d, + 0xb5, 0xbc, 0x81, 0xb8, 0x3a, 0xef, 0xe3, 0xc1, 0x77, 0xcb, 0x92, 0x89, 0x52, 0x0c, 0x18, 0xe0, 0x7d, 0x4c, 0x18, + 0xe0, 0xd7, 0xe5, 0x00, 0xec, 0x22, 0x38, 0xd5, 0x0c, 0xc6, 0xd6, 0xcc, 0x0b, 0x27, 0x92, 0xe2, 0x42, 0x49, 0x1f, + 0x8b, 0xc1, 0x66, 0x1e, 0x88, 0x09, 0x28, 0x6b, 0x96, 0xf3, 0x28, 0xed, 0x1d, 0x39, 0x80, 0xe6, 0xdb, 0x93, 0x24, + 0xaf, 0x34, 0xb6, 0x45, 0x24, 0xa2, 0x5b, 0x6e, 0xd3, 0xbf, 0xf1, 0x3d, 0x9a, 0xac, 0x35, 0xf7, 0xee, 0xd6, 0xfb, + 0xd5, 0xc0, 0x16, 0x44, 0x98, 0xf4, 0x01, 0xb3, 0xd1, 0xf4, 0xbe, 0x6c, 0x38, 0x56, 0x31, 0x15, 0xdc, 0x3c, 0x52, + 0x18, 0x49, 0xb5, 0xbd, 0x5b, 0x36, 0x3c, 0xdb, 0x35, 0xcd, 0x86, 0xcf, 0x97, 0x9a, 0x6f, 0xb1, 0x7a, 0x93, 0x1d, + 0x57, 0x41, 0x55, 0x49, 0x7d, 0xd5, 0x08, 0x90, 0x82, 0xf7, 0x2c, 0x4c, 0xe3, 0x0a, 0xc6, 0xc7, 0xd1, 0x90, 0x1a, + 0x3b, 0xca, 0xbb, 0x52, 0x9f, 0xaa, 0x39, 0xdd, 0x8b, 0x35, 0xf2, 0x83, 0xc1, 0xaf, 0xc0, 0xd8, 0x70, 0x7a, 0x3c, + 0x8a, 0x55, 0x38, 0xaf, 0x95, 0x7e, 0x89, 0xd5, 0xce, 0x67, 0xee, 0xba, 0xce, 0xda, 0x6c, 0x34, 0xa4, 0x75, 0xd9, + 0x5c, 0xd0, 0x68, 0xfc, 0x3c, 0x99, 0xad, 0xe6, 0x64, 0x5a, 0x8c, 0x96, 0xb9, 0xdb, 0x3a, 0x13, 0xf5, 0x9e, 0xc2, + 0x26, 0x36, 0xf9, 0x83, 0xea, 0x25, 0xbe, 0x9e, 0x40, 0x9a, 0xe2, 0x1e, 0x32, 0x11, 0x0a, 0x07, 0xd5, 0x46, 0x1b, + 0xdb, 0xfe, 0x16, 0xf3, 0x0f, 0xb5, 0x63, 0xde, 0x09, 0xda, 0xea, 0x6e, 0xb3, 0x18, 0x91, 0xae, 0x0d, 0xeb, 0x92, + 0x02, 0xd5, 0xed, 0x1e, 0x9b, 0xee, 0x91, 0x69, 0x1f, 0x77, 0x8d, 0x5c, 0x1c, 0x38, 0xb5, 0xcb, 0x12, 0x40, 0xc0, + 0x64, 0x57, 0x0e, 0x33, 0x88, 0x82, 0x2c, 0xf0, 0xc2, 0x1c, 0x50, 0x7d, 0x99, 0xe7, 0xfd, 0xd7, 0x32, 0xcd, 0x60, + 0x8e, 0x82, 0x25, 0x43, 0x73, 0x65, 0x6b, 0xc4, 0xb2, 0x7b, 0xc6, 0xa2, 0x0d, 0xaa, 0xdc, 0xaa, 0xf5, 0xf3, 0x9f, + 0x67, 0x0b, 0x9a, 0x93, 0x9d, 0xc5, 0x28, 0x8b, 0xf8, 0xfe, 0x10, 0xa6, 0xba, 0xf9, 0xd0, 0xfc, 0x71, 0x13, 0xc2, + 0xfd, 0xd7, 0x6e, 0x84, 0x9b, 0xb1, 0x7d, 0x10, 0xee, 0xbf, 0xbe, 0x38, 0xc2, 0xfd, 0x51, 0x45, 0xb8, 0x25, 0x4f, + 0x95, 0x42, 0x26, 0xfa, 0x01, 0x9f, 0x5b, 0x10, 0x75, 0xf7, 0xa5, 0x7e, 0x40, 0xec, 0xa5, 0xae, 0x64, 0x43, 0xfd, + 0x58, 0x4a, 0xef, 0x82, 0x57, 0x76, 0x0c, 0x3f, 0x4a, 0xa9, 0x24, 0x20, 0x53, 0xa8, 0xcc, 0x79, 0x0d, 0x7d, 0x5e, + 0x44, 0x59, 0x68, 0xbf, 0xe7, 0xd7, 0x12, 0x50, 0x41, 0x7c, 0x17, 0x27, 0x73, 0x0f, 0x43, 0xaf, 0xe9, 0x98, 0x16, + 0x0e, 0x1e, 0x1c, 0xf0, 0x8e, 0xf2, 0xe3, 0x68, 0x2c, 0xe5, 0xe8, 0x6c, 0x70, 0x4d, 0xfc, 0xa0, 0xfe, 0xc0, 0xbc, + 0x44, 0x37, 0xe9, 0x35, 0x2c, 0xee, 0x8b, 0x8e, 0xf3, 0xa2, 0x7d, 0xf8, 0xe2, 0xc8, 0x81, 0xff, 0xb9, 0xac, 0x93, + 0x9b, 0xbc, 0xe2, 0x3c, 0x8e, 0x20, 0x33, 0x85, 0xa8, 0xb9, 0xa9, 0xda, 0x3d, 0x63, 0x9f, 0x8a, 0x5a, 0xc7, 0xcd, + 0x95, 0xc6, 0xde, 0x43, 0x51, 0xa7, 0xb1, 0xc6, 0x2c, 0x5e, 0x2a, 0xc3, 0x6a, 0x18, 0x4d, 0x10, 0x2d, 0x41, 0x32, + 0xa4, 0xd4, 0x50, 0x5f, 0xf3, 0xe9, 0x16, 0xf3, 0x62, 0x9d, 0xfc, 0xa6, 0x48, 0x7f, 0x23, 0xd2, 0x70, 0xec, 0x84, + 0x20, 0x17, 0xaa, 0x3b, 0x18, 0x3c, 0x1b, 0x13, 0xc0, 0x68, 0x90, 0x7c, 0xae, 0xc8, 0x71, 0x8e, 0x0b, 0x94, 0x25, + 0xcb, 0xc8, 0xa7, 0x34, 0xe6, 0xde, 0x28, 0x6d, 0x05, 0x07, 0x10, 0x97, 0x13, 0x3f, 0x6c, 0xe0, 0xaa, 0x79, 0x67, + 0x4e, 0x91, 0x2b, 0x20, 0x15, 0xab, 0xe2, 0xbd, 0xc8, 0xcc, 0x84, 0x32, 0x8c, 0xe2, 0xd2, 0x5a, 0x03, 0xef, 0x85, + 0x6c, 0xf8, 0x22, 0x33, 0x21, 0xcb, 0x27, 0x2c, 0xf7, 0xf3, 0xe7, 0x54, 0x0b, 0xf2, 0xee, 0xd1, 0xb4, 0xce, 0x7d, + 0x99, 0xab, 0x4b, 0xd7, 0xbc, 0x69, 0xac, 0x63, 0xae, 0xae, 0x9e, 0x6f, 0xc6, 0x2f, 0x5f, 0x9e, 0x0d, 0x5c, 0x83, + 0x67, 0x8d, 0x2c, 0xa5, 0x38, 0xba, 0xdc, 0x4f, 0x35, 0x6e, 0x34, 0x3a, 0x6d, 0x2d, 0x82, 0x68, 0x2a, 0x34, 0xd3, + 0x12, 0x7b, 0x41, 0xca, 0x01, 0x52, 0x81, 0x79, 0x42, 0x45, 0x2d, 0xea, 0xdc, 0xb1, 0x04, 0x32, 0x5e, 0x0e, 0xf4, + 0x8e, 0xed, 0xd8, 0x8e, 0x2e, 0x1b, 0x4e, 0x82, 0xe9, 0x60, 0x1d, 0x67, 0x1e, 0x24, 0x6f, 0x09, 0xe3, 0x29, 0x78, + 0x7e, 0x64, 0x41, 0x16, 0x42, 0x26, 0x10, 0x70, 0x01, 0x99, 0xd3, 0xad, 0x31, 0xe7, 0xf6, 0xb8, 0x5e, 0xf2, 0x09, + 0xb3, 0xc1, 0x09, 0xa7, 0x2f, 0x8c, 0x3f, 0xf3, 0x03, 0x10, 0xc3, 0x96, 0xde, 0x82, 0x5c, 0x84, 0x2c, 0x49, 0x2d, + 0xd5, 0xbe, 0xbd, 0xa7, 0x41, 0x1b, 0xc8, 0x13, 0x8e, 0x1d, 0x4c, 0x12, 0x6f, 0x0e, 0x41, 0xb3, 0xd7, 0xb9, 0xc9, + 0x31, 0xad, 0xce, 0x51, 0xad, 0xe6, 0xbe, 0x3a, 0x32, 0xb5, 0xb6, 0x6b, 0x6a, 0x0e, 0xa0, 0x5b, 0x3d, 0x37, 0xd7, + 0xf9, 0x4d, 0x7f, 0x97, 0x8a, 0x8e, 0xf0, 0xcb, 0x53, 0x9a, 0x07, 0x29, 0xe7, 0xb8, 0xf0, 0x33, 0xa3, 0xd0, 0x81, + 0x2d, 0x25, 0x9c, 0x75, 0x40, 0x62, 0xfa, 0x2b, 0xb6, 0xca, 0x0c, 0xcc, 0x94, 0xc1, 0xab, 0x04, 0xc6, 0x1a, 0x5d, + 0xd3, 0x82, 0x48, 0x0b, 0x7e, 0xfb, 0xad, 0x15, 0x80, 0xf9, 0xfd, 0x40, 0x81, 0x0f, 0x3c, 0x1b, 0x25, 0x80, 0x05, + 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0x2c, 0x7e, 0x70, 0xc5, 0x9e, 0x1d, 0x7a, 0xd1, 0x14, + 0x50, 0x9a, 0x17, 0x4d, 0x6b, 0x06, 0x04, 0xe4, 0x5d, 0x57, 0x29, 0x2d, 0xba, 0x2a, 0x94, 0xfb, 0xe9, 0xb7, 0x0f, + 0x57, 0x94, 0x09, 0x08, 0xb2, 0x4e, 0x7b, 0x63, 0x74, 0x05, 0x2b, 0x74, 0x0f, 0x2f, 0x07, 0x5f, 0x9d, 0xce, 0x59, + 0xe6, 0x91, 0xe0, 0x12, 0xae, 0x78, 0xc0, 0x0e, 0x68, 0xbe, 0xc8, 0xe2, 0x49, 0x17, 0xbc, 0x31, 0xbb, 0x0b, 0x7c, + 0x7e, 0x4f, 0x33, 0x35, 0x4e, 0xa7, 0x2c, 0xb4, 0x51, 0x1a, 0xb8, 0x26, 0x99, 0xc8, 0xfa, 0x1e, 0x06, 0x18, 0x1c, + 0x44, 0xb1, 0x7e, 0xf6, 0x95, 0xf4, 0x26, 0xda, 0xb4, 0x08, 0x90, 0x8e, 0xef, 0x3a, 0x61, 0xe1, 0xbf, 0x07, 0x5f, + 0x01, 0xe1, 0xfe, 0xea, 0x46, 0x37, 0xfa, 0x99, 0x8d, 0xf7, 0x98, 0xaf, 0x1a, 0xd2, 0xd2, 0xe1, 0x1d, 0x95, 0x5f, + 0x36, 0x3b, 0xca, 0x65, 0x13, 0x7e, 0xef, 0xbe, 0xba, 0x9e, 0x9d, 0x22, 0x41, 0x3b, 0x83, 0xdb, 0xc5, 0xba, 0x74, + 0xe7, 0x74, 0xfb, 0x78, 0x41, 0x1d, 0x85, 0x9e, 0xff, 0x49, 0xdc, 0x50, 0xd5, 0x87, 0x7d, 0xee, 0xa2, 0x92, 0xb3, + 0x6b, 0xdc, 0xcb, 0xb8, 0x95, 0xd7, 0xf8, 0x65, 0xfc, 0xd4, 0xfd, 0x2c, 0xc8, 0xe4, 0x65, 0x18, 0x1f, 0x72, 0xd0, + 0xe6, 0xe0, 0xf8, 0x8a, 0xeb, 0x0f, 0x5c, 0x50, 0xdd, 0x93, 0xbf, 0x75, 0xef, 0x5c, 0x67, 0xd6, 0x76, 0x6d, 0xb8, + 0xe6, 0xcc, 0x3a, 0xf6, 0x71, 0x68, 0x75, 0xec, 0x63, 0xf8, 0xfb, 0x08, 0x57, 0x2f, 0xab, 0x6d, 0x1f, 0x7e, 0x74, + 0xdb, 0xa1, 0x75, 0x62, 0x1f, 0xc3, 0xdf, 0x25, 0xb5, 0xfa, 0x19, 0x2f, 0x3d, 0x70, 0xe1, 0xf9, 0xaa, 0x84, 0x05, + 0x94, 0xdf, 0x52, 0x8b, 0x60, 0x96, 0xc8, 0x5b, 0x83, 0x26, 0x02, 0x50, 0x86, 0x6e, 0x8a, 0x80, 0x80, 0x51, 0xbf, + 0x05, 0x79, 0xb2, 0x31, 0xc2, 0xbb, 0x30, 0xc8, 0x88, 0x8a, 0x9c, 0xef, 0x9b, 0x8f, 0x11, 0x6f, 0xd3, 0x1c, 0x6a, + 0x5b, 0xa4, 0x0e, 0x22, 0xd5, 0xc5, 0xdf, 0x17, 0x18, 0x45, 0x47, 0x04, 0x07, 0x57, 0xb0, 0x52, 0x91, 0xbe, 0x2e, + 0xdf, 0x3d, 0x70, 0xf4, 0x1b, 0x65, 0x32, 0x7d, 0xca, 0x17, 0xed, 0x9b, 0xab, 0x33, 0x64, 0xef, 0x7f, 0xb4, 0x1f, + 0xcc, 0x1a, 0x4a, 0xfd, 0x88, 0x38, 0x9e, 0xe3, 0x20, 0x91, 0xc3, 0x53, 0x50, 0xb4, 0xdb, 0x1c, 0xa3, 0xdc, 0x80, + 0x3c, 0x13, 0x17, 0xc0, 0x25, 0xdf, 0x79, 0xa1, 0x62, 0x7a, 0xa1, 0xb4, 0x7c, 0x22, 0x31, 0xff, 0xf3, 0xe7, 0xc5, + 0xe0, 0xac, 0xca, 0xb8, 0x4f, 0xdd, 0x2e, 0x90, 0xdd, 0x2e, 0xeb, 0x6c, 0xb5, 0x02, 0xda, 0x1d, 0x08, 0xb6, 0x08, + 0x1d, 0x29, 0x34, 0xfd, 0x42, 0xc7, 0xb8, 0xd1, 0x14, 0xa9, 0xa6, 0x61, 0x84, 0x10, 0xba, 0x95, 0xab, 0x8e, 0x6e, + 0xf4, 0x23, 0xa1, 0x30, 0x8b, 0xb6, 0x04, 0xbf, 0xe5, 0x77, 0x31, 0x1d, 0x40, 0xb3, 0x65, 0x1e, 0x3b, 0x5c, 0x1a, + 0xff, 0xdf, 0x93, 0x40, 0xf7, 0x22, 0xd0, 0xf0, 0x55, 0x4e, 0x6b, 0xc9, 0xdd, 0x44, 0xd2, 0x55, 0x22, 0xa8, 0x2c, + 0x3d, 0xd7, 0xa1, 0x08, 0x12, 0x10, 0x61, 0xce, 0x31, 0x69, 0xde, 0x24, 0xa9, 0x45, 0x51, 0x60, 0x06, 0x10, 0xfd, + 0xb9, 0x25, 0x5c, 0x9d, 0x8c, 0xe7, 0xcf, 0x37, 0x12, 0x21, 0x52, 0x27, 0xab, 0xa9, 0x17, 0x75, 0x15, 0xbf, 0xe9, + 0x2a, 0x8a, 0x91, 0xfd, 0x22, 0xd6, 0x10, 0x56, 0x59, 0xb4, 0xf7, 0xf0, 0xe7, 0x88, 0x79, 0x99, 0xcd, 0xf5, 0x20, + 0x2d, 0x85, 0xb8, 0x9b, 0x2e, 0xeb, 0x80, 0x3d, 0x16, 0x0f, 0xb6, 0xc5, 0x23, 0xcb, 0x3d, 0x5b, 0x7f, 0x5c, 0x72, + 0x3f, 0x64, 0xe8, 0xe3, 0x37, 0xa7, 0x08, 0x9e, 0xf2, 0x2e, 0xf3, 0x28, 0xc2, 0x86, 0x4a, 0x72, 0xe3, 0xcc, 0x13, + 0x89, 0x3e, 0x80, 0x2f, 0xef, 0x37, 0x2a, 0x0c, 0x15, 0x5f, 0xe5, 0xb3, 0x77, 0x57, 0xdf, 0x68, 0x7c, 0xff, 0x93, + 0x7e, 0x0b, 0x2f, 0x32, 0x14, 0xef, 0x7e, 0x40, 0xf1, 0xee, 0x35, 0x9e, 0xe7, 0x01, 0xa2, 0xc6, 0xe7, 0x07, 0x04, + 0x41, 0x5d, 0x63, 0x91, 0x4f, 0x5a, 0xbf, 0xf9, 0x32, 0xcc, 0x82, 0x85, 0x97, 0x64, 0x07, 0xd0, 0xd4, 0x02, 0x24, + 0xa7, 0x6f, 0xf2, 0x60, 0x26, 0xc5, 0xa1, 0x10, 0xaa, 0x65, 0x91, 0xd0, 0x1c, 0x4e, 0x82, 0x50, 0x2a, 0x0e, 0xc5, + 0x07, 0x3c, 0xdf, 0x67, 0x8b, 0x6c, 0xa0, 0x7b, 0x0b, 0xc8, 0x7b, 0x80, 0x91, 0x8c, 0x0f, 0x62, 0x3f, 0x63, 0x99, + 0x95, 0x66, 0x09, 0xf3, 0xe6, 0xba, 0x0c, 0xeb, 0x59, 0xef, 0x2f, 0x5d, 0x8e, 0xe6, 0x41, 0x26, 0x23, 0xe3, 0xd1, + 0x04, 0x41, 0x85, 0x07, 0x43, 0x3c, 0x1b, 0xe6, 0x1c, 0x84, 0x97, 0xf1, 0xb4, 0xb2, 0xa3, 0x0a, 0xce, 0xe5, 0x1c, + 0xa3, 0xae, 0xf2, 0x58, 0xf7, 0x63, 0xf4, 0xc8, 0xb9, 0xe5, 0x5e, 0xd7, 0x32, 0x80, 0x9f, 0x7e, 0x76, 0xca, 0xaf, + 0xb7, 0x1a, 0x06, 0x0a, 0xd0, 0xbb, 0x0e, 0xc4, 0x95, 0xdd, 0xe4, 0x8f, 0x7d, 0xc0, 0x2b, 0x03, 0x69, 0xa2, 0x9e, + 0x31, 0xc2, 0x37, 0x8d, 0xe5, 0x0a, 0x18, 0xa1, 0x92, 0x8a, 0x77, 0xe6, 0x9e, 0x49, 0x07, 0x20, 0x1c, 0x15, 0xf2, + 0x4a, 0xbf, 0xfd, 0xf6, 0x7a, 0xf8, 0x9f, 0xdf, 0x21, 0x0c, 0xf9, 0xcc, 0x15, 0x5e, 0xd0, 0xd7, 0x6a, 0x2d, 0xce, + 0x7d, 0x9a, 0x43, 0x54, 0xef, 0xb3, 0xb1, 0x08, 0x0b, 0x22, 0xb6, 0x56, 0x3e, 0xbc, 0x11, 0xa1, 0x9e, 0x20, 0xd5, + 0x80, 0x21, 0x7c, 0xb5, 0x87, 0xb0, 0xbc, 0x43, 0x11, 0x22, 0x40, 0xfb, 0x65, 0xf5, 0xed, 0x31, 0xa4, 0xcd, 0xad, + 0x65, 0x00, 0x50, 0x06, 0x88, 0x7b, 0xe8, 0xec, 0xd4, 0xe3, 0xc2, 0x57, 0x60, 0x3f, 0xd2, 0xde, 0x01, 0x4c, 0x73, + 0x16, 0xcf, 0x99, 0x1d, 0xc4, 0x07, 0xf7, 0x6c, 0x64, 0x79, 0x8b, 0x80, 0xe4, 0xcb, 0x28, 0x77, 0xd3, 0x88, 0xf3, + 0x93, 0x0a, 0x5a, 0xe2, 0xaf, 0xf3, 0x02, 0x94, 0x71, 0x01, 0x28, 0xf8, 0xe9, 0x9d, 0x95, 0xa3, 0xf5, 0xd9, 0x22, + 0x36, 0x7c, 0x19, 0xcb, 0x9f, 0x53, 0xd0, 0x3d, 0x11, 0x5f, 0xaf, 0x78, 0xb0, 0xe2, 0xc9, 0x44, 0x8d, 0xb0, 0x67, + 0x97, 0xbf, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0x41, 0x5f, 0xaa, 0x7f, 0x42, 0xfe, 0x84, 0xf4, 0xb5, 0x3c, 0x18, + 0x23, 0x9c, 0xe7, 0x5a, 0xa4, 0x3e, 0x09, 0x92, 0xa7, 0x54, 0x89, 0x23, 0x8a, 0x6a, 0x0c, 0xe8, 0x0d, 0xac, 0xc9, + 0x93, 0xc1, 0x80, 0xf0, 0x58, 0x15, 0x9d, 0x01, 0x94, 0x1a, 0xe2, 0xe4, 0xc3, 0x64, 0x33, 0x68, 0x68, 0x91, 0x07, + 0x17, 0x36, 0xaa, 0x4e, 0xa7, 0x3e, 0xc6, 0x03, 0x4f, 0xec, 0xaf, 0xd2, 0x0e, 0x84, 0x9d, 0xc5, 0x17, 0x16, 0x10, + 0xb8, 0xe8, 0xa7, 0x82, 0xc7, 0xb5, 0xaf, 0x09, 0x65, 0x5b, 0xa1, 0xf7, 0x10, 0x2b, 0x9a, 0x75, 0xee, 0x64, 0x7f, + 0x89, 0xa5, 0x57, 0xc2, 0xb9, 0xad, 0x76, 0x92, 0x64, 0xac, 0xf1, 0xfa, 0x69, 0x52, 0x83, 0x83, 0xef, 0x3a, 0x4c, + 0x6a, 0xdd, 0xf2, 0x64, 0x10, 0x3b, 0xe6, 0xc5, 0x41, 0x2b, 0xbd, 0xc4, 0x73, 0x9f, 0x9f, 0x1e, 0xc0, 0xfc, 0x20, + 0x30, 0x40, 0x89, 0x33, 0x0a, 0x0c, 0x88, 0x3e, 0xe0, 0xa5, 0x64, 0x1d, 0x70, 0x31, 0x16, 0x4c, 0x1d, 0xde, 0x1c, + 0x65, 0x28, 0xd0, 0x52, 0x95, 0x3a, 0xb3, 0xe2, 0x34, 0x73, 0x79, 0xbb, 0x63, 0xf3, 0xff, 0xba, 0xc4, 0xc0, 0xfc, + 0x79, 0x3f, 0x63, 0xc2, 0xef, 0xf6, 0x32, 0xdb, 0xe0, 0x9a, 0xbb, 0xa9, 0x0a, 0x31, 0xac, 0x5b, 0x2a, 0x14, 0xfb, + 0x78, 0x5b, 0xad, 0x82, 0x35, 0x92, 0xd5, 0x16, 0x5e, 0x4b, 0x7f, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, + 0x65, 0x36, 0x80, 0xaa, 0x42, 0xd8, 0xee, 0x2d, 0x16, 0x54, 0xd9, 0xe8, 0x9f, 0x1e, 0xd0, 0xbd, 0xf3, 0x8c, 0x76, + 0xd8, 0xd9, 0x29, 0x58, 0x17, 0xd2, 0xa2, 0x7b, 0x8b, 0x05, 0x5f, 0x52, 0xfa, 0x45, 0x6f, 0x0e, 0x66, 0xd9, 0x3c, + 0x3c, 0xfb, 0x2f, 0x85, 0x07, 0xd6, 0xc5, 0xa2, 0x59, 0x03, 0x00}; + +} // namespace web_server +} // namespace esphome +#endif +#endif diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 6a7b4121f0..d72307991f 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -27,7 +27,11 @@ #endif #ifdef USE_WEBSERVER_LOCAL -#include "server_index.h" +#if USE_WEBSERVER_VERSION == 2 +#include "server_index_v2.h" +#elif USE_WEBSERVER_VERSION == 3 +#include "server_index_v3.h" +#endif #endif namespace esphome { From 989a64bdcf9ae9a1b0723d77b20ba6c26d74d89d Mon Sep 17 00:00:00 2001 From: esphomebot Date: Tue, 30 Apr 2024 09:45:03 +1200 Subject: [PATCH 1651/2607] Update webserver local assets to 20240429-211523 (#6657) --- .../components/captive_portal/captive_index.h | 196 +-- .../components/web_server/server_index_v2.h | 1237 +++++++++-------- .../components/web_server/server_index_v3.h | 725 +++++----- 3 files changed, 1083 insertions(+), 1075 deletions(-) diff --git a/esphome/components/captive_portal/captive_index.h b/esphome/components/captive_portal/captive_index.h index d262a89b09..8835762fb3 100644 --- a/esphome/components/captive_portal/captive_index.h +++ b/esphome/components/captive_portal/captive_index.h @@ -1,106 +1,108 @@ #pragma once // Generated from https://github.com/esphome/esphome-webserver -#include "esphome/core/hal.h" -namespace esphome { +#include "esphome/core/hal.h" + +namespace esphome { namespace captive_portal { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x69, 0x6f, 0xdc, 0x36, 0x1a, 0xfe, 0xde, - 0x5f, 0xc1, 0x2a, 0x49, 0x47, 0xd3, 0x58, 0xd4, 0x35, 0x9a, 0x53, 0x9a, 0xc2, 0xf1, 0xa6, 0x68, 0x81, 0xa4, 0x0d, - 0x60, 0xb7, 0xfd, 0x10, 0x04, 0x30, 0x47, 0xa2, 0x46, 0x8c, 0x25, 0x4a, 0x2b, 0x72, 0xae, 0x0c, 0x66, 0x7f, 0xfb, - 0xbe, 0x24, 0x35, 0xe3, 0xb1, 0x37, 0x5e, 0x6c, 0x8a, 0x2d, 0x8a, 0xd6, 0x71, 0x68, 0x1e, 0xef, 0xf9, 0x88, 0xef, - 0x21, 0xc5, 0x5f, 0x67, 0x75, 0x2a, 0x77, 0x0d, 0x45, 0x85, 0xac, 0xca, 0x79, 0xac, 0x46, 0x54, 0x12, 0xbe, 0x4c, - 0x28, 0x87, 0x15, 0x25, 0xd9, 0x3c, 0xae, 0xa8, 0x24, 0x28, 0x2d, 0x48, 0x2b, 0xa8, 0x4c, 0x7e, 0xb9, 0xf9, 0xde, - 0x19, 0x23, 0x77, 0x1e, 0x97, 0x8c, 0xdf, 0xa1, 0x96, 0x96, 0x09, 0x4b, 0x6b, 0x8e, 0x8a, 0x96, 0xe6, 0x49, 0x46, - 0x24, 0x99, 0xb2, 0x8a, 0x2c, 0xa9, 0x22, 0xd0, 0x6c, 0x9c, 0x54, 0x34, 0x59, 0x33, 0xba, 0x69, 0xea, 0x56, 0x22, - 0xa0, 0x94, 0x94, 0xcb, 0xc4, 0xda, 0xb0, 0x4c, 0x16, 0x49, 0x46, 0xd7, 0x2c, 0xa5, 0x8e, 0x5e, 0x5c, 0x30, 0xce, - 0x24, 0x23, 0xa5, 0x23, 0x52, 0x52, 0xd2, 0xc4, 0xbf, 0x58, 0x09, 0xda, 0xea, 0x05, 0x59, 0xc0, 0x9a, 0xd7, 0x16, - 0x88, 0x14, 0x69, 0xcb, 0x1a, 0x89, 0x94, 0xbd, 0x49, 0x55, 0x67, 0xab, 0x92, 0xce, 0x5d, 0x97, 0x08, 0xb0, 0x4b, - 0xb8, 0x8c, 0x67, 0x74, 0x8b, 0x87, 0x61, 0x98, 0x06, 0x64, 0x94, 0xe3, 0x8f, 0xe2, 0x2b, 0xf0, 0x6c, 0x55, 0x81, - 0x3a, 0x5c, 0xd6, 0x29, 0x91, 0xac, 0xe6, 0x58, 0x50, 0xd2, 0xa6, 0x45, 0x92, 0x24, 0xd6, 0x77, 0x82, 0xac, 0xa9, - 0xf5, 0xcd, 0x37, 0xf6, 0x89, 0x68, 0x49, 0xe5, 0xeb, 0x92, 0xaa, 0xa9, 0x78, 0xb5, 0xbb, 0x21, 0xcb, 0x9f, 0xc0, - 0x72, 0xdb, 0x22, 0x82, 0x65, 0xd4, 0xea, 0xbf, 0xf7, 0x3e, 0x60, 0x21, 0x77, 0x25, 0xc5, 0x19, 0x13, 0x4d, 0x49, - 0x76, 0x89, 0xb5, 0x00, 0xa9, 0x77, 0x56, 0x7f, 0x96, 0xaf, 0x78, 0xaa, 0x84, 0x23, 0x61, 0xd3, 0xfe, 0xbe, 0xa4, - 0x60, 0x5e, 0xf2, 0x96, 0xc8, 0x02, 0x57, 0x64, 0x6b, 0x9b, 0x09, 0xe3, 0x76, 0xf0, 0xad, 0x4d, 0x5f, 0xfa, 0x9e, - 0xd7, 0xbf, 0xd0, 0x83, 0xd7, 0x77, 0xe1, 0xef, 0xac, 0xa5, 0x72, 0xd5, 0x72, 0x44, 0xec, 0xdb, 0xb8, 0x01, 0x4a, - 0x94, 0x25, 0x56, 0xe5, 0x07, 0xd8, 0xf3, 0xc6, 0xc8, 0x9f, 0xe0, 0x20, 0x72, 0x7c, 0x1f, 0x87, 0x8e, 0x1f, 0xa5, - 0x23, 0x27, 0x42, 0xfe, 0x00, 0x86, 0x20, 0xc0, 0x11, 0xf2, 0x3e, 0x59, 0x28, 0x67, 0x65, 0x99, 0x58, 0xbc, 0xe6, - 0xd4, 0x42, 0x42, 0xb6, 0xf5, 0x1d, 0x4d, 0xac, 0x74, 0xd5, 0xb6, 0x60, 0xff, 0x55, 0x5d, 0xd6, 0x2d, 0xc0, 0xf5, - 0x15, 0x7a, 0xf0, 0xf3, 0xc5, 0x2a, 0x64, 0x4b, 0xb8, 0xc8, 0xeb, 0xb6, 0x4a, 0x2c, 0xfd, 0x50, 0xec, 0xe7, 0x7b, - 0x79, 0x40, 0x6a, 0xe8, 0x9f, 0x1d, 0x3a, 0x75, 0xcb, 0x96, 0x8c, 0x27, 0x96, 0x1f, 0x20, 0x7f, 0x0c, 0x6a, 0x6f, - 0xfb, 0x87, 0x13, 0x26, 0x44, 0x61, 0xd2, 0x79, 0x59, 0xdb, 0xef, 0x6f, 0x63, 0xb1, 0x5e, 0xa2, 0x6d, 0x55, 0x72, - 0x91, 0x58, 0x85, 0x94, 0xcd, 0xd4, 0x75, 0x37, 0x9b, 0x0d, 0xde, 0x84, 0xb8, 0x6e, 0x97, 0x6e, 0xe0, 0x79, 0x9e, - 0x0b, 0x14, 0x16, 0x32, 0xf7, 0xc3, 0x0a, 0x06, 0x16, 0x2a, 0x28, 0x5b, 0x16, 0x52, 0xcf, 0xe7, 0xcf, 0xf7, 0xf4, - 0x10, 0x2b, 0x8a, 0xf9, 0xed, 0x87, 0x33, 0x2d, 0xec, 0x4c, 0x0b, 0xfd, 0xee, 0x0c, 0xcd, 0xde, 0x5b, 0x65, 0xd4, - 0x88, 0x04, 0x28, 0x40, 0x9e, 0xfe, 0x17, 0x38, 0x6a, 0xde, 0xad, 0x9c, 0x47, 0x2b, 0x74, 0xb6, 0x82, 0xbf, 0x80, - 0x5f, 0x50, 0x0d, 0x9d, 0xc9, 0x89, 0xdd, 0x57, 0xc7, 0x6b, 0xdf, 0xbb, 0xdf, 0x50, 0x3c, 0x3f, 0x0c, 0xcf, 0xd7, - 0x4e, 0xf0, 0xab, 0x22, 0x50, 0xd8, 0x9f, 0x98, 0x9c, 0xa0, 0xf0, 0x7f, 0x1d, 0x92, 0x08, 0x45, 0xdd, 0x4e, 0xe4, - 0xa8, 0xf9, 0x69, 0xa5, 0x34, 0xa1, 0x68, 0x0d, 0x54, 0x95, 0x33, 0x74, 0x22, 0x12, 0xa2, 0xb0, 0x33, 0x09, 0x66, - 0xb0, 0x3d, 0x04, 0xe6, 0xb3, 0x3d, 0x27, 0xfc, 0xd4, 0x53, 0x30, 0x4f, 0x2d, 0xeb, 0x1e, 0x83, 0xfa, 0x1c, 0x03, - 0xfc, 0xb1, 0x86, 0x3b, 0x67, 0x59, 0x80, 0x11, 0x95, 0x69, 0x61, 0x5b, 0x2e, 0x44, 0x5e, 0xce, 0x96, 0x10, 0x15, - 0x35, 0xb7, 0xfa, 0x58, 0x16, 0x94, 0xdb, 0x47, 0x56, 0xc5, 0x48, 0xf5, 0x89, 0xfd, 0xf8, 0x44, 0xf6, 0xf7, 0xa7, - 0xf8, 0x90, 0x4c, 0x42, 0x1c, 0x4a, 0xac, 0x22, 0xfa, 0xe2, 0xb4, 0xbb, 0xa8, 0xb3, 0xdd, 0x13, 0xa1, 0x53, 0xf8, - 0x26, 0x6e, 0x18, 0xe7, 0xb4, 0xbd, 0xa1, 0x5b, 0x78, 0x86, 0x6f, 0x2f, 0xaf, 0xd0, 0x65, 0x96, 0xb5, 0x54, 0x88, - 0x29, 0xb2, 0x5e, 0x4a, 0x88, 0x91, 0xf4, 0x7f, 0x97, 0xe5, 0x3f, 0x90, 0xf5, 0x1b, 0xfb, 0x9e, 0xa1, 0x9f, 0xa8, - 0xdc, 0xd4, 0xed, 0x5d, 0x27, 0x4d, 0x99, 0x36, 0x53, 0x11, 0xd8, 0x82, 0x9d, 0xa4, 0x11, 0x58, 0x94, 0x90, 0x5f, - 0x6c, 0xbf, 0x0f, 0x7a, 0x9a, 0x7b, 0xaf, 0xf8, 0x11, 0xa8, 0xdb, 0x38, 0x63, 0x6b, 0x94, 0x96, 0x90, 0x41, 0x20, - 0x94, 0x8c, 0x28, 0x0b, 0x75, 0x61, 0x53, 0xf3, 0x14, 0xb8, 0xef, 0x12, 0xeb, 0x33, 0x19, 0xe2, 0xd5, 0xee, 0xc7, - 0xcc, 0xee, 0x09, 0xc8, 0x0d, 0xbd, 0x3e, 0x5e, 0x93, 0x72, 0x45, 0x51, 0x82, 0x64, 0xc1, 0xc4, 0xbd, 0x81, 0xb3, - 0x27, 0xd9, 0x1a, 0x71, 0x07, 0x5c, 0x39, 0x1c, 0x0b, 0xbb, 0x6f, 0x1d, 0xa3, 0x34, 0x26, 0x26, 0x87, 0x5a, 0xcf, - 0xac, 0x47, 0x16, 0x39, 0x25, 0xcd, 0xa5, 0x75, 0x1f, 0xcd, 0xcf, 0xf7, 0xc2, 0xe6, 0xb8, 0x05, 0xed, 0xfd, 0xc3, - 0x69, 0x33, 0x16, 0x0d, 0xe1, 0x8f, 0x19, 0x95, 0x81, 0x2a, 0x68, 0x20, 0xf1, 0xc1, 0x4c, 0x45, 0x0e, 0x10, 0x9d, - 0x14, 0xba, 0xe4, 0x38, 0x7d, 0xbe, 0x67, 0x20, 0x51, 0xe5, 0xb3, 0x93, 0xc4, 0xd8, 0x05, 0x68, 0xe6, 0xb7, 0x87, - 0xfe, 0xbd, 0x1f, 0xff, 0x5c, 0xd1, 0x76, 0x77, 0x4d, 0x4b, 0x9a, 0xca, 0xba, 0xb5, 0xad, 0x67, 0xa0, 0x05, 0xae, - 0x92, 0x76, 0xf8, 0x87, 0x9b, 0xb7, 0x6f, 0x92, 0xda, 0x6e, 0xfb, 0x17, 0x4f, 0x51, 0xab, 0x6a, 0xf1, 0x1e, 0xaa, - 0xc5, 0xbf, 0x92, 0x9e, 0xaa, 0x17, 0xbd, 0x0f, 0xc0, 0xaa, 0xfd, 0xbd, 0xbd, 0x2f, 0x1a, 0x2a, 0xb0, 0x5f, 0x42, - 0x72, 0xb8, 0x50, 0x1e, 0x3a, 0xc3, 0xa8, 0x7f, 0x00, 0xfd, 0x60, 0x01, 0xd8, 0xad, 0xf3, 0x3e, 0xe4, 0x7f, 0x95, - 0x82, 0xe7, 0xdf, 0xee, 0x17, 0xf5, 0xd6, 0x11, 0xec, 0x13, 0xe3, 0xcb, 0x29, 0xe3, 0x05, 0x6d, 0x99, 0x3c, 0x80, - 0xb9, 0x50, 0x42, 0x9a, 0x95, 0xdc, 0x37, 0x24, 0xcb, 0xd4, 0x49, 0xd4, 0x6c, 0x67, 0x39, 0x14, 0x1c, 0x45, 0x49, - 0xa7, 0x3e, 0xad, 0x0e, 0xe6, 0x5c, 0xe7, 0x96, 0xe9, 0x24, 0x7a, 0x71, 0x50, 0x17, 0x6e, 0x2f, 0xe1, 0x61, 0x39, - 0xa4, 0x64, 0x4b, 0x3e, 0x4d, 0xc1, 0x70, 0xda, 0x1a, 0xa6, 0x9c, 0x54, 0xac, 0xdc, 0x4d, 0x05, 0x64, 0x39, 0x07, - 0x2a, 0x11, 0xcb, 0x0f, 0x8b, 0x95, 0x94, 0x35, 0x07, 0xdd, 0x6d, 0x46, 0xdb, 0xa9, 0x37, 0x33, 0x13, 0xa7, 0x25, - 0x19, 0x5b, 0x89, 0x29, 0x0e, 0x5b, 0x5a, 0xcd, 0x16, 0x24, 0xbd, 0x5b, 0xb6, 0xf5, 0x8a, 0x67, 0x4e, 0xaa, 0xb2, - 0xf0, 0xf4, 0x99, 0x9f, 0x93, 0x90, 0xa6, 0xb3, 0x6e, 0x95, 0xe7, 0xf9, 0x0c, 0xa0, 0xa0, 0x8e, 0xc9, 0x6a, 0xd3, - 0x00, 0x0f, 0x14, 0xdb, 0x99, 0x99, 0x38, 0x50, 0x1b, 0xc6, 0x46, 0x28, 0x11, 0x2f, 0x66, 0x47, 0x77, 0xbc, 0x19, - 0xa4, 0x77, 0x01, 0x42, 0x1a, 0x88, 0x6d, 0x30, 0xf3, 0x50, 0x11, 0xc6, 0xcf, 0xad, 0x57, 0xd7, 0x64, 0xd6, 0x95, - 0x27, 0x80, 0x45, 0xab, 0xd1, 0x45, 0x6a, 0x06, 0x05, 0xc8, 0x14, 0xd9, 0x69, 0x30, 0xf4, 0x9a, 0xed, 0x01, 0x77, - 0x17, 0x64, 0x7f, 0xa4, 0xce, 0x4b, 0xba, 0x9d, 0x7d, 0x5c, 0x09, 0xc9, 0xf2, 0x9d, 0xd3, 0x15, 0xe9, 0x29, 0x5c, - 0x16, 0x28, 0xce, 0x0b, 0x20, 0xa5, 0x94, 0xcf, 0xb4, 0x0e, 0x87, 0x49, 0x5a, 0x89, 0x0e, 0xa7, 0x93, 0x18, 0x7d, - 0x41, 0x1f, 0xca, 0xfa, 0x6f, 0xd4, 0xea, 0x2e, 0xee, 0x2b, 0xd2, 0x42, 0xd1, 0x70, 0x16, 0x35, 0x60, 0x5a, 0x4d, - 0x9d, 0x11, 0x3c, 0xab, 0x6e, 0x4b, 0x09, 0x03, 0xcf, 0xc1, 0x4c, 0x5d, 0x7b, 0x8f, 0x78, 0xfb, 0xcd, 0x16, 0x89, - 0xba, 0x64, 0x59, 0x47, 0xa7, 0x49, 0x90, 0x77, 0x82, 0xc7, 0x87, 0xc7, 0x8d, 0xd4, 0xde, 0x11, 0xea, 0x41, 0x3e, - 0x26, 0xbe, 0xf7, 0x99, 0x27, 0x92, 0xe5, 0x79, 0xb0, 0xc8, 0x4f, 0x48, 0xa9, 0x12, 0x7a, 0x60, 0xdd, 0xad, 0x08, - 0x06, 0x20, 0xe0, 0xf8, 0x6c, 0x60, 0x7e, 0x60, 0x3a, 0x2c, 0xf6, 0x67, 0x52, 0xf4, 0x55, 0x9d, 0xae, 0xda, 0xd2, - 0xb6, 0x3e, 0x73, 0x75, 0x5f, 0x84, 0x57, 0xf7, 0x25, 0xae, 0xf7, 0x74, 0x89, 0xeb, 0x21, 0xd5, 0x14, 0xbd, 0xaa, - 0xb7, 0x49, 0x4f, 0x17, 0x9b, 0x01, 0xfc, 0xf6, 0x5e, 0x84, 0xaf, 0x81, 0xff, 0xff, 0x52, 0xbb, 0x7e, 0x77, 0xe1, - 0xfa, 0x82, 0xaa, 0xf5, 0x85, 0x15, 0xcb, 0x78, 0xa7, 0x9c, 0x87, 0x19, 0x94, 0x26, 0x86, 0x05, 0x5b, 0xfa, 0x7f, - 0x04, 0xb4, 0xff, 0x89, 0x63, 0x78, 0xe9, 0x8f, 0xf1, 0x04, 0xe9, 0xc1, 0x40, 0x84, 0xc3, 0x31, 0x1a, 0x5d, 0x0d, - 0xf0, 0xc0, 0x47, 0xaa, 0x1d, 0x1a, 0xa2, 0x11, 0x1e, 0x03, 0xc1, 0x10, 0x87, 0x23, 0xd8, 0x40, 0x81, 0x8f, 0xa3, - 0x37, 0x41, 0x88, 0x87, 0x11, 0x50, 0x05, 0x1e, 0x0e, 0x03, 0x64, 0x68, 0x87, 0x38, 0x00, 0x71, 0x8a, 0x24, 0xac, - 0x00, 0xe8, 0x34, 0xc4, 0xde, 0x08, 0xc4, 0x0d, 0xb1, 0x37, 0xc1, 0xe3, 0x21, 0x1a, 0xe3, 0x11, 0x40, 0x87, 0x07, - 0x51, 0xe9, 0x44, 0xd8, 0x87, 0xed, 0x70, 0x48, 0xc6, 0x78, 0x10, 0x22, 0x3d, 0x18, 0x38, 0x46, 0x20, 0xc2, 0xc1, - 0x9e, 0xff, 0x26, 0xc4, 0xc1, 0x08, 0xf4, 0x0e, 0x06, 0x97, 0x20, 0x76, 0x32, 0x40, 0x66, 0x34, 0xf0, 0x82, 0x82, - 0xe8, 0x29, 0xd0, 0x82, 0xbf, 0x2f, 0x68, 0x00, 0x89, 0x8f, 0x42, 0x3c, 0x81, 0xd8, 0xf5, 0x15, 0xbf, 0x19, 0x0d, - 0x6e, 0xbe, 0x8f, 0xbc, 0xdf, 0x8d, 0x59, 0xf8, 0xf7, 0xc5, 0xcc, 0x57, 0x08, 0xc0, 0x14, 0x74, 0x83, 0x1c, 0xa4, - 0x07, 0xa3, 0x1b, 0x98, 0xc7, 0x57, 0x13, 0x34, 0x06, 0xae, 0xe1, 0x18, 0x4d, 0x50, 0xa4, 0xd0, 0x05, 0xf6, 0x81, - 0x61, 0x72, 0x80, 0xe9, 0x0b, 0x61, 0x1c, 0xfc, 0x85, 0x61, 0x7c, 0xca, 0xa7, 0xbf, 0xb0, 0x4b, 0x7f, 0x46, 0x0a, - 0x82, 0x76, 0x4c, 0xb7, 0x61, 0xb1, 0x6b, 0x3e, 0x0f, 0xa8, 0x2e, 0x0a, 0xde, 0xf6, 0xa1, 0x1b, 0x99, 0xc7, 0x85, - 0x8f, 0x58, 0x96, 0x40, 0x57, 0x3f, 0x3f, 0x6b, 0xf5, 0x81, 0xd0, 0x3f, 0x1e, 0xc1, 0xec, 0x41, 0xe3, 0x6e, 0xce, - 0x74, 0xa5, 0x9f, 0xdf, 0x14, 0x14, 0xbd, 0xbe, 0x7e, 0x07, 0x2f, 0x7f, 0x65, 0x89, 0x78, 0xbd, 0x81, 0x77, 0xcc, - 0x1d, 0x92, 0xb5, 0xfa, 0x6a, 0xc0, 0xa1, 0x8d, 0x54, 0x53, 0x78, 0x3d, 0x41, 0x5d, 0x1f, 0x81, 0x31, 0x8e, 0x17, - 0xed, 0xfc, 0x5d, 0x49, 0x89, 0xa0, 0x68, 0xc9, 0xd6, 0x14, 0x31, 0x09, 0x2d, 0x42, 0x45, 0x91, 0x64, 0x6a, 0x38, - 0x31, 0x6a, 0x3a, 0x68, 0x77, 0xb5, 0x12, 0xd3, 0x28, 0x83, 0x25, 0x20, 0x66, 0xde, 0x75, 0xc4, 0x71, 0x11, 0x1a, - 0xab, 0xae, 0xa9, 0x94, 0xd0, 0x4c, 0x28, 0xab, 0xc2, 0x79, 0xac, 0xde, 0x6e, 0x11, 0xd1, 0xef, 0x0c, 0x89, 0xbb, - 0x61, 0x39, 0x53, 0xdf, 0x0c, 0xe6, 0xb1, 0xee, 0x22, 0x95, 0x04, 0xd5, 0xc8, 0x98, 0x0f, 0x1c, 0x7a, 0x56, 0x52, - 0xbe, 0x84, 0x97, 0x56, 0x78, 0x4c, 0xd0, 0x57, 0xa4, 0xb4, 0xa8, 0x4b, 0xe8, 0x5b, 0x92, 0xeb, 0xeb, 0x1f, 0xff, - 0xa1, 0xbe, 0x86, 0x28, 0x13, 0x4e, 0x9c, 0xf0, 0x0a, 0x60, 0x18, 0xd5, 0xa4, 0xe3, 0x1b, 0x0e, 0xcc, 0x77, 0x8d, - 0x06, 0x5a, 0x78, 0xf0, 0x2f, 0x7b, 0x20, 0xe5, 0xdd, 0x71, 0xb3, 0x93, 0xa4, 0xff, 0xeb, 0x7e, 0xd4, 0x30, 0x89, - 0xd5, 0xa2, 0x62, 0x72, 0x7e, 0x0d, 0x06, 0xc6, 0xae, 0x39, 0x00, 0xe7, 0x94, 0x03, 0x86, 0xb6, 0xe8, 0x78, 0x00, - 0xec, 0x9f, 0x6f, 0x2e, 0xd1, 0x2f, 0x0d, 0x5c, 0x6e, 0x6a, 0xb0, 0xd7, 0x5e, 0x56, 0x54, 0x16, 0x75, 0x96, 0xbc, - 0xfb, 0xf9, 0xfa, 0xe6, 0xe4, 0xf1, 0x4a, 0x13, 0x21, 0xca, 0x53, 0xf3, 0xbd, 0x65, 0x55, 0x4a, 0xd6, 0x90, 0x56, - 0x6a, 0xb1, 0x8e, 0x8a, 0x8e, 0xa3, 0x47, 0xfa, 0x3c, 0x67, 0x25, 0x35, 0x4e, 0x75, 0x8c, 0xee, 0x1c, 0x7d, 0xce, - 0xc6, 0xa3, 0xee, 0x47, 0x56, 0xba, 0xe6, 0x02, 0xb9, 0xe6, 0x36, 0xb9, 0xfa, 0x6b, 0xd4, 0xbf, 0x01, 0x14, 0xee, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x58, 0x6d, 0x6f, 0xdb, 0x38, 0x12, 0xfe, 0xde, + 0x5f, 0x31, 0xa7, 0x36, 0x6b, 0x6b, 0x1b, 0x51, 0x22, 0xe5, 0xb7, 0xd8, 0x92, 0x16, 0x69, 0xae, 0x8b, 0x5d, 0xa0, + 0xdd, 0x2d, 0x90, 0x6c, 0xef, 0x43, 0x51, 0x20, 0xb4, 0x34, 0xb2, 0xd8, 0x48, 0xa4, 0x4e, 0xa4, 0x5f, 0x52, 0xc3, + 0xf7, 0xdb, 0x0f, 0x94, 0x6c, 0xc7, 0xe9, 0x35, 0x87, 0xeb, 0xe2, 0x0e, 0x87, 0xdd, 0x18, 0x21, 0x86, 0xe4, 0xcc, + 0x70, 0xe6, 0xf1, 0x0c, 0x67, 0xcc, 0xe8, 0x2f, 0x99, 0x4a, 0xcd, 0x7d, 0x8d, 0x50, 0x98, 0xaa, 0x4c, 0x22, 0x3b, + 0x42, 0xc9, 0xe5, 0x22, 0x46, 0x99, 0x44, 0x05, 0xf2, 0x2c, 0x89, 0x2a, 0x34, 0x1c, 0xd2, 0x82, 0x37, 0x1a, 0x4d, + 0xfc, 0xdb, 0xcd, 0x8f, 0xde, 0x04, 0xfc, 0x24, 0x2a, 0x85, 0xbc, 0x83, 0x06, 0xcb, 0x58, 0xa4, 0x4a, 0x42, 0xd1, + 0x60, 0x1e, 0x67, 0xdc, 0xf0, 0xa9, 0xa8, 0xf8, 0x02, 0x2d, 0x43, 0x2b, 0x26, 0x79, 0x85, 0xf1, 0x4a, 0xe0, 0xba, + 0x56, 0x8d, 0x81, 0x54, 0x49, 0x83, 0xd2, 0xc4, 0xce, 0x5a, 0x64, 0xa6, 0x88, 0x33, 0x5c, 0x89, 0x14, 0xbd, 0x76, + 0x72, 0x2e, 0xa4, 0x30, 0x82, 0x97, 0x9e, 0x4e, 0x79, 0x89, 0x31, 0x3d, 0x5f, 0x6a, 0x6c, 0xda, 0x09, 0x9f, 0x97, + 0x18, 0x4b, 0xe5, 0xf8, 0x49, 0xa4, 0xd3, 0x46, 0xd4, 0x06, 0xac, 0xbd, 0x71, 0xa5, 0xb2, 0x65, 0x89, 0x89, 0xef, + 0x73, 0xad, 0xd1, 0x68, 0x5f, 0xc8, 0x0c, 0x37, 0x64, 0x14, 0x86, 0x29, 0xe3, 0xe3, 0x9c, 0x7c, 0xd2, 0xcf, 0x32, + 0x95, 0x2e, 0x2b, 0x94, 0x86, 0x94, 0x2a, 0xe5, 0x46, 0x28, 0x49, 0x34, 0xf2, 0x26, 0x2d, 0xe2, 0x38, 0x76, 0x7e, + 0xd0, 0x7c, 0x85, 0xce, 0x77, 0xdf, 0xf5, 0x8f, 0x4c, 0x0b, 0x34, 0xaf, 0x4b, 0xb4, 0xa4, 0x7e, 0x75, 0x7f, 0xc3, + 0x17, 0xbf, 0xf0, 0x0a, 0xfb, 0x0e, 0xd7, 0x22, 0x43, 0xc7, 0xfd, 0x10, 0x7c, 0x24, 0xda, 0xdc, 0x97, 0x48, 0x32, + 0xa1, 0xeb, 0x92, 0xdf, 0xc7, 0xce, 0xbc, 0x54, 0xe9, 0x9d, 0xe3, 0xce, 0xf2, 0xa5, 0x4c, 0xad, 0x72, 0xd0, 0x7d, + 0x74, 0xb7, 0x25, 0x1a, 0x30, 0xf1, 0x5b, 0x6e, 0x0a, 0x52, 0xf1, 0x4d, 0xbf, 0x23, 0x84, 0xec, 0xb3, 0xef, 0xfb, + 0xf8, 0x92, 0x06, 0x81, 0x7b, 0xde, 0x0e, 0x81, 0xeb, 0xd3, 0x20, 0x98, 0x35, 0x68, 0x96, 0x8d, 0x04, 0xde, 0xbf, + 0x8d, 0x6a, 0x6e, 0x0a, 0xc8, 0x62, 0xa7, 0xa2, 0x8c, 0x04, 0xc1, 0x04, 0xe8, 0x05, 0x61, 0x43, 0x8f, 0x52, 0x12, + 0x7a, 0x74, 0x98, 0x8e, 0xbd, 0x21, 0xd0, 0x81, 0x37, 0x04, 0xc6, 0xc8, 0x10, 0x82, 0xcf, 0x0e, 0xe4, 0xa2, 0x2c, + 0x63, 0x47, 0x2a, 0x89, 0x0e, 0x68, 0xd3, 0xa8, 0x3b, 0x8c, 0x9d, 0x74, 0xd9, 0x34, 0x28, 0xcd, 0x95, 0x2a, 0x55, + 0xe3, 0xf8, 0xc9, 0x33, 0x78, 0xf4, 0xf7, 0xcd, 0x47, 0x98, 0x86, 0x4b, 0x9d, 0xab, 0xa6, 0x8a, 0x9d, 0xf6, 0x4b, + 0xe9, 0xbf, 0xd8, 0x9a, 0x1d, 0xd8, 0xc1, 0x3d, 0xd9, 0xf4, 0x54, 0x23, 0x16, 0x42, 0xc6, 0x0e, 0x65, 0x40, 0x27, + 0x8e, 0x9f, 0xdc, 0xba, 0xbb, 0x23, 0x26, 0xdc, 0x62, 0xb2, 0xf7, 0x52, 0xf5, 0x3f, 0xdc, 0x46, 0x7a, 0xb5, 0x80, + 0x4d, 0x55, 0x4a, 0x1d, 0x3b, 0x85, 0x31, 0xf5, 0xd4, 0xf7, 0xd7, 0xeb, 0x35, 0x59, 0x87, 0x44, 0x35, 0x0b, 0x9f, + 0x05, 0x41, 0xe0, 0xeb, 0xd5, 0xc2, 0x81, 0x2e, 0x3e, 0x1c, 0x36, 0x70, 0xa0, 0x40, 0xb1, 0x28, 0x4c, 0x4b, 0x27, + 0x2f, 0xb6, 0xb8, 0x8b, 0x2c, 0x47, 0x72, 0xfb, 0xf1, 0xe4, 0x14, 0x71, 0x72, 0x0a, 0xfe, 0x70, 0x82, 0x66, 0xef, + 0xad, 0x35, 0x6a, 0xcc, 0x19, 0x30, 0x08, 0xda, 0x0f, 0xf3, 0x2c, 0xbd, 0x9f, 0x79, 0x5f, 0xcc, 0xe0, 0x64, 0x06, + 0x0c, 0x9e, 0x01, 0xb0, 0x6a, 0xe4, 0x5d, 0x1c, 0xc5, 0xa9, 0xdd, 0x5e, 0xd1, 0xe0, 0x61, 0xc1, 0xca, 0xfc, 0x34, + 0x3a, 0x9d, 0x7b, 0xec, 0xbd, 0x65, 0xb0, 0xd8, 0x1f, 0x85, 0x3c, 0x56, 0xd0, 0xf7, 0x23, 0x3e, 0x84, 0xe1, 0x7e, + 0x65, 0xe8, 0x59, 0xfa, 0x38, 0xb3, 0x27, 0xc1, 0x70, 0xc5, 0x0a, 0x5a, 0x79, 0x23, 0x6f, 0xc8, 0x43, 0x08, 0xf7, + 0x26, 0x85, 0x10, 0xae, 0x58, 0x31, 0x7a, 0x3f, 0x3a, 0x5d, 0xf3, 0xc2, 0xcf, 0x3d, 0x0b, 0xf3, 0xd4, 0x71, 0x1e, + 0x30, 0x50, 0xa7, 0x18, 0x90, 0x4f, 0x4a, 0xc8, 0xbe, 0xe3, 0xb8, 0xbb, 0x1c, 0x4d, 0x5a, 0xf4, 0x1d, 0x3f, 0x55, + 0x32, 0x17, 0x0b, 0xf2, 0x49, 0x2b, 0xe9, 0xb8, 0xc4, 0x14, 0x28, 0xfb, 0x07, 0x51, 0x2b, 0x88, 0xed, 0x4e, 0xff, + 0xcb, 0x1d, 0xe3, 0x6e, 0x8f, 0xf9, 0x61, 0x84, 0x29, 0x31, 0x36, 0xc4, 0x66, 0xf4, 0xf9, 0x71, 0x75, 0xae, 0xb2, + 0xfb, 0x27, 0x52, 0xa7, 0xa0, 0x5d, 0xde, 0x08, 0x29, 0xb1, 0xb9, 0xc1, 0x8d, 0x89, 0x9d, 0xb7, 0x97, 0x57, 0x70, + 0x99, 0x65, 0x0d, 0x6a, 0x3d, 0x05, 0xe7, 0xa5, 0x21, 0x15, 0x4f, 0xff, 0x73, 0x5d, 0xf4, 0x91, 0xae, 0xbf, 0x89, + 0x1f, 0x05, 0xfc, 0x82, 0x66, 0xad, 0x9a, 0xbb, 0xbd, 0x36, 0x6b, 0xda, 0xcc, 0x66, 0x60, 0x13, 0x1b, 0xc2, 0x6b, + 0x4d, 0x74, 0x29, 0x52, 0xec, 0x53, 0x97, 0x54, 0xbc, 0x7e, 0xf0, 0x4a, 0x1e, 0x80, 0xba, 0x8d, 0x32, 0xb1, 0x82, + 0xb4, 0xe4, 0x5a, 0xc7, 0x8e, 0xec, 0x54, 0x39, 0xb0, 0x4f, 0x1b, 0x25, 0xd3, 0x52, 0xa4, 0x77, 0xb1, 0xf3, 0x95, + 0x1b, 0xe2, 0xd5, 0xfd, 0xcf, 0x59, 0xbf, 0xa7, 0xb5, 0xc8, 0x7a, 0x2e, 0x59, 0xf1, 0x72, 0x89, 0x10, 0x83, 0x29, + 0x84, 0x7e, 0x30, 0x70, 0xf6, 0xa4, 0x58, 0xad, 0xef, 0x7a, 0x2e, 0xc9, 0x55, 0xba, 0xd4, 0x7d, 0xd7, 0x39, 0x64, + 0x69, 0xc4, 0xbb, 0x3b, 0xd4, 0x79, 0xee, 0x7c, 0x61, 0x91, 0x57, 0x62, 0x6e, 0x9c, 0x87, 0x6c, 0x7e, 0xb1, 0xd5, + 0x7d, 0x49, 0x1a, 0xad, 0x85, 0xbb, 0x3b, 0x2e, 0x46, 0xba, 0xe6, 0xf2, 0x4b, 0x41, 0x6b, 0xa0, 0x4d, 0x1a, 0x49, + 0x2c, 0x65, 0x33, 0xa7, 0xe6, 0xf2, 0x78, 0xa0, 0xcf, 0x0f, 0xe4, 0x8b, 0xad, 0xe8, 0x4b, 0x7b, 0x4b, 0xde, 0x1d, + 0x35, 0x46, 0x7e, 0x26, 0x56, 0xc9, 0xed, 0xce, 0x7d, 0xf0, 0xe3, 0xef, 0x4b, 0x6c, 0xee, 0xaf, 0xb1, 0xc4, 0xd4, + 0xa8, 0xa6, 0xef, 0x3c, 0x97, 0x68, 0x1c, 0xb7, 0x73, 0xf8, 0xa7, 0x9b, 0xb7, 0x6f, 0x62, 0xd5, 0x6f, 0xdc, 0xf3, + 0xa7, 0xb8, 0x6d, 0xb5, 0xf8, 0xd0, 0x60, 0xf9, 0x8f, 0xb8, 0x67, 0xeb, 0x45, 0xef, 0xa3, 0xe3, 0x92, 0xd6, 0xdf, + 0xdb, 0x87, 0xa2, 0x61, 0x13, 0xfb, 0xe5, 0xa6, 0x2a, 0xcf, 0xad, 0x87, 0xde, 0x68, 0xe8, 0xee, 0x6e, 0x77, 0xee, + 0xce, 0x9d, 0x45, 0x7e, 0x77, 0xef, 0x27, 0x51, 0x7b, 0x05, 0x27, 0xdf, 0x6f, 0xe7, 0x6a, 0xe3, 0x69, 0xf1, 0x59, + 0xc8, 0xc5, 0x54, 0xc8, 0x02, 0x1b, 0x61, 0x76, 0x99, 0x58, 0x9d, 0x0b, 0x59, 0x2f, 0xcd, 0xb6, 0xe6, 0x59, 0x66, + 0x77, 0x86, 0xf5, 0x66, 0x96, 0x2b, 0x69, 0x2c, 0x27, 0x4e, 0x29, 0x56, 0xbb, 0x6e, 0xbf, 0xbd, 0x5b, 0xa6, 0x17, + 0xc3, 0xb3, 0x9d, 0x0d, 0xb8, 0xad, 0xc1, 0x8d, 0xf1, 0x78, 0x29, 0x16, 0x72, 0x9a, 0xa2, 0x34, 0xd8, 0x74, 0x42, + 0x39, 0xaf, 0x44, 0x79, 0x3f, 0xd5, 0x5c, 0x6a, 0x4f, 0x63, 0x23, 0xf2, 0xdd, 0x7c, 0x69, 0x8c, 0x92, 0xdb, 0xb9, + 0x6a, 0x32, 0x6c, 0xa6, 0xc1, 0xac, 0x23, 0xbc, 0x86, 0x67, 0x62, 0xa9, 0xa7, 0x24, 0x6c, 0xb0, 0x9a, 0xcd, 0x79, + 0x7a, 0xb7, 0x68, 0xd4, 0x52, 0x66, 0x5e, 0x6a, 0x6f, 0xe1, 0xe9, 0x73, 0x9a, 0xf3, 0x10, 0xd3, 0xd9, 0x7e, 0x96, + 0xe7, 0xf9, 0xac, 0x14, 0x12, 0xbd, 0xee, 0x56, 0x9b, 0x32, 0x32, 0xb0, 0x62, 0x27, 0x66, 0x12, 0x66, 0x17, 0x3a, + 0x1b, 0x69, 0x10, 0x9c, 0xcd, 0x0e, 0xee, 0x04, 0xb3, 0x74, 0xd9, 0x68, 0xd5, 0x4c, 0x6b, 0x25, 0xac, 0x99, 0xbb, + 0x8a, 0x0b, 0x79, 0x6a, 0xbd, 0x0d, 0x93, 0xd9, 0xbe, 0x3c, 0x4d, 0x85, 0x6c, 0x8f, 0x69, 0x8b, 0xd4, 0xac, 0x12, + 0xb2, 0x2b, 0xb2, 0x53, 0x36, 0x0a, 0xea, 0xcd, 0x8e, 0xec, 0x03, 0x64, 0x7b, 0xe0, 0xce, 0x4b, 0xdc, 0xcc, 0x3e, + 0x2d, 0xb5, 0x11, 0xf9, 0xbd, 0xb7, 0x2f, 0xd2, 0x53, 0x5d, 0xf3, 0x14, 0xbd, 0x39, 0x9a, 0x35, 0xa2, 0x9c, 0xb5, + 0x67, 0x78, 0xc2, 0x60, 0xa5, 0xf7, 0x38, 0x1d, 0xd5, 0xb4, 0x01, 0xfa, 0x58, 0xd7, 0xbf, 0xe3, 0xb6, 0xb1, 0xb8, + 0xad, 0x78, 0xb3, 0x10, 0xd2, 0x9b, 0x2b, 0x63, 0x54, 0x35, 0xf5, 0xc6, 0xf5, 0x66, 0xb6, 0x5f, 0xb2, 0xca, 0xa6, + 0xd4, 0x9a, 0xd9, 0xd6, 0xde, 0x03, 0xde, 0xb4, 0xde, 0x80, 0x56, 0xa5, 0xc8, 0xf6, 0x7c, 0x2d, 0x0b, 0x04, 0x47, + 0x78, 0xe8, 0xb0, 0xde, 0x80, 0x5d, 0x3b, 0x40, 0x3d, 0xc8, 0x27, 0x9c, 0x06, 0x5f, 0xf9, 0x46, 0xb2, 0x3c, 0x67, + 0xf3, 0xfc, 0x88, 0x94, 0x2d, 0xa1, 0x3b, 0xb1, 0x8f, 0x0a, 0x36, 0xa8, 0x37, 0xb3, 0xc3, 0x77, 0x33, 0xa8, 0x37, + 0x3b, 0xd1, 0xa6, 0xc5, 0xf6, 0x44, 0x4b, 0x1b, 0xaa, 0xd3, 0x65, 0x53, 0xf6, 0x9d, 0xaf, 0x84, 0xee, 0x59, 0x78, + 0xf5, 0x50, 0xe2, 0x7a, 0x4f, 0x97, 0xb8, 0x1e, 0xd8, 0xa6, 0xe8, 0x95, 0xda, 0xc4, 0xbd, 0xb6, 0xd8, 0x0c, 0x80, + 0x0d, 0x7a, 0x67, 0xe1, 0xeb, 0xb3, 0xf0, 0xea, 0xbf, 0x52, 0xbb, 0x7e, 0x77, 0xe1, 0xfa, 0x86, 0xaa, 0xf5, 0x8d, + 0x15, 0xab, 0xf3, 0xce, 0x3a, 0x7f, 0x16, 0xbe, 0x76, 0xdc, 0x9d, 0x20, 0x5a, 0x2c, 0xe8, 0xff, 0x02, 0xda, 0x7f, + 0xc5, 0x31, 0xbc, 0xa4, 0x13, 0x72, 0x01, 0xed, 0xd0, 0x41, 0x44, 0xc2, 0x09, 0x8c, 0xaf, 0x06, 0x64, 0x40, 0xc1, + 0xb6, 0x43, 0x23, 0x18, 0x93, 0xc9, 0x05, 0xd0, 0x11, 0x09, 0xc7, 0x40, 0x19, 0x30, 0x4a, 0x86, 0x6f, 0x58, 0x48, + 0x46, 0x43, 0x18, 0x5f, 0xb1, 0x80, 0x84, 0x0c, 0x3a, 0xde, 0x11, 0x61, 0x0c, 0x42, 0xcb, 0x12, 0x56, 0x01, 0xb0, + 0x34, 0x24, 0xc1, 0x18, 0x02, 0x18, 0x91, 0xe0, 0x82, 0x4c, 0x46, 0x30, 0x21, 0x63, 0x0a, 0x8c, 0x0c, 0x86, 0xa5, + 0x37, 0x24, 0x14, 0x46, 0x24, 0x1c, 0xf1, 0x09, 0x19, 0x84, 0xd0, 0x0e, 0x1d, 0x1c, 0x63, 0xc2, 0x98, 0x47, 0x02, + 0xfa, 0x26, 0x24, 0x6c, 0x0c, 0x63, 0x32, 0x18, 0x5c, 0xd2, 0x11, 0xb9, 0x18, 0x40, 0x37, 0x76, 0xf0, 0x52, 0x06, + 0xc3, 0xa7, 0x40, 0x63, 0x7f, 0x5e, 0xd0, 0x42, 0xc2, 0x28, 0x84, 0xe4, 0x62, 0xc2, 0x6d, 0x5f, 0xca, 0xa0, 0x1b, + 0x3b, 0xdc, 0x28, 0x85, 0xe0, 0x77, 0x63, 0x16, 0xfe, 0x79, 0x31, 0xa3, 0x16, 0x01, 0x46, 0x06, 0xe1, 0x25, 0x0d, + 0xc9, 0x08, 0xda, 0xa1, 0x3b, 0x9b, 0x32, 0x98, 0x5c, 0x5d, 0xc0, 0x04, 0x46, 0x64, 0x34, 0x81, 0x0b, 0x18, 0x5a, + 0x74, 0x2f, 0xc8, 0x64, 0xd0, 0x09, 0x79, 0x8c, 0x7c, 0x2b, 0x8c, 0x83, 0x3f, 0x30, 0x8c, 0x4f, 0xf9, 0xf4, 0x07, + 0x76, 0xe9, 0xff, 0x71, 0x05, 0x45, 0x7e, 0xd7, 0x86, 0x45, 0x7e, 0xf7, 0x3c, 0x60, 0xbb, 0xa8, 0x24, 0xb2, 0xdd, + 0x48, 0x12, 0x15, 0x14, 0x44, 0x16, 0x57, 0x3c, 0x4d, 0x4e, 0x5a, 0xfd, 0xc8, 0x2f, 0xe8, 0x61, 0xab, 0xa0, 0xc9, + 0xa3, 0xc6, 0xbd, 0xdb, 0x6b, 0x2b, 0x7d, 0x72, 0x53, 0x20, 0xbc, 0xbe, 0x7e, 0x07, 0x6b, 0x51, 0x96, 0x20, 0xd5, + 0x1a, 0x4c, 0x73, 0x0f, 0x46, 0xd9, 0x57, 0x03, 0x89, 0xa9, 0xb1, 0xa4, 0x29, 0x10, 0xf6, 0x7d, 0x04, 0x21, 0x24, + 0x9a, 0x37, 0xc9, 0xbb, 0x12, 0xb9, 0x46, 0x58, 0x88, 0x15, 0x82, 0x30, 0xa0, 0x55, 0x85, 0x60, 0x84, 0x1d, 0x8e, + 0x82, 0x2d, 0x5f, 0xe4, 0x77, 0x87, 0x74, 0x8d, 0xb2, 0xc8, 0x62, 0x89, 0x26, 0xd9, 0x77, 0xc4, 0x51, 0x11, 0x76, + 0x56, 0x5d, 0xa3, 0x31, 0x42, 0x2e, 0xac, 0x55, 0x61, 0x12, 0xd9, 0x5f, 0xb7, 0xc0, 0xdb, 0xdf, 0x0c, 0xb1, 0xbf, + 0x16, 0xb9, 0xb0, 0x6f, 0x06, 0x49, 0xd4, 0x76, 0x91, 0x56, 0x83, 0x6d, 0x64, 0xba, 0x07, 0x8e, 0x96, 0x2a, 0x51, + 0x2e, 0x4c, 0x11, 0x87, 0x0c, 0xea, 0x92, 0xa7, 0x58, 0xa8, 0x32, 0xc3, 0x26, 0xbe, 0xbe, 0xfe, 0xf9, 0xaf, 0xf6, + 0x35, 0xc4, 0x9a, 0x70, 0x94, 0xac, 0xf5, 0x5d, 0x27, 0x68, 0x89, 0xbd, 0xdc, 0x68, 0xd0, 0xbd, 0x6b, 0xd4, 0x5c, + 0xeb, 0xb5, 0x6a, 0xb2, 0x47, 0x5a, 0xde, 0x1d, 0x16, 0xf7, 0x9a, 0xda, 0xff, 0xb6, 0x1f, 0xed, 0x84, 0xf4, 0x72, + 0x5e, 0x09, 0x93, 0x5c, 0xf3, 0x15, 0x46, 0x7e, 0xb7, 0x91, 0x44, 0xbe, 0x75, 0xa0, 0xe3, 0x2d, 0xf6, 0x32, 0x05, + 0x4d, 0x7e, 0xbd, 0xb9, 0x84, 0xdf, 0xea, 0x8c, 0x1b, 0xec, 0xb0, 0x6f, 0xbd, 0xac, 0xd0, 0x14, 0x2a, 0x8b, 0xdf, + 0xfd, 0x7a, 0x7d, 0x73, 0xf4, 0x78, 0xd9, 0x32, 0x01, 0xca, 0xb4, 0x7b, 0x6f, 0x59, 0x96, 0x46, 0xd4, 0xbc, 0x31, + 0xad, 0x5a, 0xcf, 0x66, 0xc7, 0xc1, 0xa3, 0x76, 0x3f, 0x17, 0x25, 0x76, 0x4e, 0xed, 0x05, 0xfd, 0x04, 0xbe, 0x66, + 0xe3, 0xe1, 0xec, 0x2f, 0xac, 0xf4, 0xbb, 0x00, 0xf2, 0xbb, 0x68, 0xf2, 0xdb, 0xd7, 0xa8, 0x7f, 0x02, 0x14, 0xee, 0xbc, 0x64, 0x9d, 0x12, 0x00, 0x00}; } // namespace captive_portal diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index 21beecfff7..31c2d1fd85 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -1,633 +1,636 @@ #pragma once // Generated from https://github.com/esphome/esphome-webserver + #ifdef USE_WEBSERVER_LOCAL #if USE_WEBSERVER_VERSION == 2 -#include "esphome/core/hal.h" -namespace esphome { +#include "esphome/core/hal.h" + +namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x7d, 0xd9, 0x92, 0xdb, 0x46, 0xb6, 0xe0, 0xf3, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xd9, 0x92, 0xdb, 0x46, 0xb6, 0xe0, 0xf3, 0xdc, 0xaf, 0x40, 0xc1, 0xd5, 0x25, 0x64, 0x33, 0x89, 0x22, 0x59, 0xda, 0x0c, 0x56, 0x92, 0x5d, 0x2a, 0xc9, 0x2d, 0xbb, 0xb5, 0xd8, 0x2a, 0xc9, 0x6e, 0x9b, 0x66, 0x57, 0xa1, 0x88, 0x24, 0x99, 0x16, 0x88, 0xa4, 0x13, 0xc9, 0x5a, 0x4c, 0xe2, 0xc6, 0x7c, 0xc0, 0x44, 0x4c, 0xc4, 0x3c, 0xcd, 0xcb, 0xc4, 0xdc, 0x87, 0xf9, 0x88, 0x79, 0xbe, 0x9f, - 0x72, 0x7f, 0x60, 0xe6, 0x13, 0x26, 0x4e, 0x2e, 0x40, 0x82, 0x4b, 0xa9, 0xbc, 0xdc, 0x3b, 0xa1, 0x90, 0x44, 0xe4, - 0x7a, 0xf2, 0xe4, 0xc9, 0xb3, 0x27, 0x70, 0xbc, 0x97, 0xf0, 0x91, 0xbc, 0x9d, 0x53, 0x6f, 0x2a, 0x67, 0x69, 0xef, - 0xd8, 0xfc, 0x4b, 0xe3, 0xa4, 0x77, 0x9c, 0xb2, 0xec, 0xa3, 0x27, 0x68, 0x4a, 0xd8, 0x88, 0x67, 0xde, 0x54, 0xd0, - 0x31, 0x49, 0x62, 0x19, 0x47, 0x6c, 0x16, 0x4f, 0xa8, 0x77, 0xd8, 0x3b, 0x9e, 0x51, 0x19, 0x7b, 0xa3, 0x69, 0x2c, - 0x72, 0x2a, 0xc9, 0x87, 0xf7, 0x5f, 0x34, 0x9f, 0xf6, 0x8e, 0xf3, 0x91, 0x60, 0x73, 0xe9, 0xc1, 0x90, 0x64, 0xc6, - 0x93, 0x45, 0x4a, 0x7b, 0x87, 0x87, 0xd7, 0xd7, 0xd7, 0xe1, 0x4f, 0xf9, 0x3f, 0x8d, 0x78, 0x96, 0x4b, 0xef, 0x15, - 0xb9, 0x66, 0x59, 0xc2, 0xaf, 0x31, 0x95, 0xe4, 0x55, 0x78, 0x36, 0x8d, 0x13, 0x7e, 0xfd, 0x8e, 0x73, 0x79, 0x70, - 0x10, 0xe8, 0xc7, 0xdb, 0xd3, 0xb3, 0x33, 0x42, 0xc8, 0x15, 0x67, 0x89, 0xd7, 0x5a, 0xad, 0xaa, 0xc2, 0x30, 0x8b, - 0x25, 0xbb, 0xa2, 0xba, 0x0b, 0x3a, 0x38, 0xf0, 0xe3, 0x84, 0xcf, 0x25, 0x4d, 0xce, 0xe4, 0x6d, 0x4a, 0xcf, 0xa6, - 0x94, 0xca, 0xdc, 0x67, 0x99, 0xf7, 0x9c, 0x8f, 0x16, 0x33, 0x9a, 0xc9, 0x70, 0x2e, 0xb8, 0xe4, 0x00, 0xc9, 0xc1, - 0x81, 0x2f, 0xe8, 0x3c, 0x8d, 0x47, 0x14, 0xea, 0x4f, 0xcf, 0xce, 0xaa, 0x1e, 0x55, 0x23, 0xcc, 0x24, 0x39, 0xbb, - 0x9d, 0x5d, 0xf2, 0x34, 0x40, 0x38, 0x95, 0x24, 0xa3, 0xd7, 0xde, 0x77, 0x34, 0xfe, 0xf8, 0x3a, 0x9e, 0x77, 0x47, - 0x69, 0x9c, 0xe7, 0xde, 0xa5, 0x5c, 0xaa, 0x25, 0x88, 0xc5, 0x48, 0x72, 0x11, 0x48, 0x4c, 0x31, 0x43, 0x4b, 0x36, - 0x0e, 0xe4, 0x94, 0xe5, 0xe1, 0xf9, 0xfe, 0x28, 0xcf, 0xdf, 0xd1, 0x7c, 0x91, 0xca, 0x7d, 0xb2, 0xd7, 0xc2, 0x6c, - 0x8f, 0x10, 0x26, 0x91, 0x9c, 0x0a, 0x7e, 0xed, 0xbd, 0x10, 0x82, 0x8b, 0xc0, 0x3f, 0x3d, 0x3b, 0xd3, 0x2d, 0x3c, - 0x96, 0x7b, 0x19, 0x97, 0x5e, 0x39, 0x5e, 0x7c, 0x99, 0xd2, 0xd0, 0xfb, 0x90, 0x53, 0xef, 0x62, 0x91, 0xe5, 0xf1, - 0x98, 0x9e, 0x9e, 0x9d, 0x5d, 0x78, 0x5c, 0x78, 0x17, 0xa3, 0x3c, 0xbf, 0xf0, 0x58, 0x96, 0x4b, 0x1a, 0x27, 0xa1, - 0x8f, 0xba, 0x6a, 0xb2, 0x51, 0x9e, 0xbf, 0xa7, 0x37, 0x92, 0x48, 0xac, 0x1e, 0x25, 0xa1, 0xc5, 0x84, 0x4a, 0x2f, - 0x2f, 0xd7, 0x15, 0xa0, 0x65, 0x4a, 0xa5, 0x27, 0x89, 0xaa, 0xe7, 0x5d, 0x8d, 0x7b, 0xaa, 0x1f, 0x65, 0x97, 0x8d, - 0x03, 0x2a, 0x0f, 0x0e, 0x64, 0x89, 0x67, 0xa4, 0x97, 0xe6, 0x31, 0x42, 0xf7, 0x6c, 0xd9, 0xc1, 0x01, 0x0d, 0x53, - 0x9a, 0x4d, 0xe4, 0x94, 0x10, 0xd2, 0xee, 0xb2, 0x83, 0x83, 0x40, 0x92, 0x54, 0x86, 0x13, 0x2a, 0x03, 0x8a, 0x10, - 0xae, 0x7a, 0x1f, 0x1c, 0x04, 0x1a, 0x09, 0x9c, 0x68, 0xc4, 0xd5, 0x70, 0x8c, 0x42, 0x83, 0xfd, 0xb3, 0xdb, 0x6c, - 0x14, 0xb8, 0xf0, 0x23, 0xcc, 0x0e, 0x0e, 0x52, 0x19, 0xe6, 0x30, 0x22, 0x96, 0x08, 0x15, 0x82, 0xca, 0x85, 0xc8, - 0x3c, 0x59, 0x48, 0x7e, 0x26, 0x05, 0xcb, 0x26, 0x01, 0x5a, 0xda, 0x32, 0xa7, 0x63, 0x51, 0x68, 0x70, 0xbf, 0x96, - 0x44, 0x90, 0x1e, 0xcc, 0x78, 0x29, 0x03, 0xd8, 0x45, 0x3e, 0xf6, 0x04, 0x21, 0x7e, 0xae, 0xfa, 0xfa, 0x7d, 0x11, - 0x89, 0x86, 0xef, 0x63, 0x0d, 0x25, 0x66, 0x12, 0xe1, 0x8f, 0x24, 0x10, 0x38, 0x0c, 0x43, 0x89, 0x48, 0x6f, 0x69, - 0xb1, 0x22, 0x9c, 0x75, 0xf6, 0xc5, 0xa0, 0x35, 0x8c, 0x64, 0x28, 0x68, 0xb2, 0x18, 0xd1, 0x20, 0x60, 0x38, 0xc7, - 0x19, 0x22, 0x3d, 0xd6, 0x08, 0x38, 0xe9, 0xc1, 0x76, 0xf3, 0xfa, 0x5e, 0x13, 0xb2, 0xd7, 0x42, 0x06, 0x46, 0x6e, - 0x01, 0x04, 0x0c, 0x1b, 0x78, 0x38, 0x21, 0x7e, 0xb6, 0x98, 0x5d, 0x52, 0xe1, 0x97, 0xcd, 0xba, 0x35, 0xb2, 0x58, - 0xe4, 0xd4, 0x1b, 0xe5, 0xb9, 0x37, 0x5e, 0x64, 0x23, 0xc9, 0x78, 0xe6, 0xf9, 0x0d, 0xde, 0xf0, 0x35, 0x39, 0x94, - 0xd4, 0xe0, 0xa3, 0x02, 0x05, 0x39, 0x6a, 0x88, 0x41, 0xd6, 0x68, 0x0f, 0x31, 0x40, 0x89, 0xba, 0x66, 0x3c, 0x83, - 0x00, 0x8a, 0x05, 0xac, 0xb1, 0xc0, 0x1f, 0x24, 0xac, 0x52, 0x2d, 0x91, 0xca, 0xbe, 0x08, 0x37, 0x0f, 0x0a, 0x91, - 0xe1, 0x2c, 0x9e, 0x07, 0x94, 0xf4, 0xa8, 0x22, 0xae, 0x38, 0x1b, 0x01, 0xac, 0xb5, 0x7d, 0xeb, 0xd3, 0x88, 0x86, - 0x15, 0x49, 0xa1, 0x48, 0x86, 0x63, 0x2e, 0x5e, 0xc4, 0xa3, 0x29, 0xf4, 0x2b, 0x09, 0x26, 0xb1, 0xe7, 0x6d, 0x24, - 0x68, 0x2c, 0xe9, 0x8b, 0x94, 0xc2, 0x53, 0xe0, 0xab, 0x9e, 0x3e, 0xc2, 0x39, 0x79, 0x15, 0xa6, 0x4c, 0xbe, 0xe1, - 0xd9, 0x88, 0x76, 0x73, 0x87, 0xba, 0x18, 0xec, 0xfb, 0x89, 0x94, 0x82, 0x5d, 0x2e, 0x24, 0x0d, 0xfc, 0x0c, 0x5a, - 0xf8, 0x38, 0x47, 0x98, 0x85, 0x92, 0xde, 0xc8, 0x53, 0x9e, 0x49, 0x9a, 0x49, 0x42, 0x2d, 0x52, 0xb1, 0x08, 0xe3, - 0xf9, 0x9c, 0x66, 0xc9, 0xe9, 0x94, 0xa5, 0x49, 0xc0, 0x50, 0x81, 0x0a, 0x1c, 0x4b, 0x02, 0x6b, 0x24, 0x3d, 0x11, - 0xc1, 0x3f, 0xbb, 0x57, 0x13, 0x48, 0xd2, 0x53, 0x87, 0x82, 0x12, 0xdf, 0xef, 0x8e, 0xb9, 0x08, 0xcc, 0x0a, 0x3c, - 0x3e, 0xf6, 0x24, 0xcc, 0xf1, 0x6e, 0x91, 0xd2, 0x1c, 0xd1, 0x06, 0x61, 0xe5, 0x36, 0x1a, 0x04, 0x7f, 0x0d, 0x14, - 0x5f, 0xa0, 0x40, 0xa0, 0x48, 0x74, 0xaf, 0x62, 0xe1, 0x7d, 0x61, 0x4e, 0xd4, 0x4f, 0x96, 0x9b, 0x4d, 0x25, 0xf9, - 0x29, 0x94, 0x62, 0x91, 0x4b, 0x9a, 0xbc, 0xbf, 0x9d, 0xd3, 0x1c, 0xbf, 0x94, 0x64, 0x2a, 0xfb, 0x53, 0x19, 0xd2, - 0xd9, 0x5c, 0xde, 0x9e, 0x29, 0xc6, 0x18, 0xf9, 0x3e, 0x1e, 0x41, 0x4b, 0x41, 0xe3, 0x11, 0x30, 0x33, 0x83, 0xad, - 0xaf, 0x79, 0x7a, 0x3b, 0x66, 0x69, 0x7a, 0xb6, 0x98, 0xcf, 0xb9, 0x90, 0xf8, 0xaf, 0x64, 0x29, 0x79, 0x85, 0x1a, - 0xd8, 0xcb, 0x65, 0x7e, 0xcd, 0xe4, 0x68, 0x1a, 0x48, 0xb4, 0x1c, 0xc5, 0x39, 0xf5, 0x9e, 0x71, 0x9e, 0xd2, 0x38, - 0x8b, 0x04, 0x11, 0xfd, 0x97, 0x32, 0xca, 0x16, 0x69, 0xda, 0xbd, 0x14, 0x34, 0xfe, 0xd8, 0x55, 0xd5, 0x6f, 0x2f, - 0x7f, 0xa2, 0x23, 0x19, 0xa9, 0xdf, 0x27, 0x42, 0xc4, 0xb7, 0xd0, 0x90, 0x10, 0x68, 0xd6, 0x17, 0xd1, 0x57, 0x67, - 0x6f, 0xdf, 0x84, 0xfa, 0x90, 0xb0, 0xf1, 0x6d, 0x20, 0xca, 0x83, 0x27, 0x0a, 0x3c, 0x16, 0x7c, 0xb6, 0x36, 0xb5, - 0xc6, 0x9a, 0xe8, 0xee, 0x00, 0x81, 0x12, 0xb1, 0xa7, 0x87, 0x76, 0x21, 0x78, 0xa3, 0x68, 0x1e, 0x2a, 0x89, 0x99, - 0x17, 0xfe, 0x89, 0x74, 0x71, 0x20, 0xd0, 0xdd, 0xd0, 0x4a, 0x71, 0xbb, 0xa4, 0x44, 0xc1, 0x39, 0x07, 0x09, 0x03, - 0x30, 0x8e, 0x62, 0x39, 0x9a, 0x2e, 0xa9, 0x1a, 0xac, 0xb0, 0x10, 0xd3, 0xa2, 0xc0, 0xd7, 0x25, 0xbd, 0xcb, 0x3d, - 0x42, 0x84, 0x62, 0x54, 0x44, 0xae, 0x56, 0x82, 0x10, 0x81, 0xf0, 0x77, 0x64, 0x19, 0xdb, 0xf5, 0x44, 0x7b, 0x2d, - 0x0c, 0xe7, 0x32, 0xd2, 0xdc, 0x05, 0x8f, 0x78, 0x76, 0x45, 0x85, 0xa4, 0x22, 0xfa, 0x2b, 0x16, 0x74, 0x9c, 0x02, - 0x14, 0x7b, 0x6d, 0x3c, 0x8d, 0xf3, 0xd3, 0x69, 0x9c, 0x4d, 0x68, 0x12, 0x5d, 0xcb, 0x02, 0xff, 0x9d, 0xf8, 0x63, - 0x96, 0xc5, 0x29, 0xfb, 0x85, 0x26, 0xbe, 0x91, 0x06, 0x27, 0x1e, 0xbd, 0x91, 0x34, 0x4b, 0x72, 0xef, 0xe5, 0xfb, - 0xd7, 0xaf, 0xcc, 0x3e, 0xd6, 0x04, 0x04, 0x5a, 0xe6, 0x8b, 0x39, 0x15, 0x01, 0xc2, 0x46, 0x40, 0xbc, 0x60, 0x8a, - 0x39, 0xbe, 0x8e, 0xe7, 0xba, 0x84, 0xe5, 0x1f, 0xe6, 0x49, 0x2c, 0xe9, 0xd7, 0x34, 0x4b, 0x58, 0x36, 0x21, 0x7b, - 0x6d, 0x5d, 0x3e, 0x8d, 0x4d, 0x45, 0x52, 0x16, 0x9d, 0xef, 0xbf, 0x48, 0xd5, 0xba, 0xcb, 0xc7, 0x45, 0x80, 0x8a, - 0x5c, 0xc6, 0x92, 0x8d, 0xbc, 0x38, 0x49, 0xbe, 0xcc, 0x98, 0x64, 0x0a, 0x40, 0x01, 0xdb, 0x03, 0x24, 0x4a, 0xb5, - 0xa8, 0xb0, 0x80, 0x07, 0x08, 0x07, 0x81, 0x11, 0x00, 0x53, 0x64, 0xf6, 0xeb, 0xe0, 0xa0, 0x62, 0xf7, 0x7d, 0x1a, - 0xe9, 0x4a, 0x32, 0x18, 0xa2, 0x70, 0xbe, 0xc8, 0x61, 0xa3, 0xed, 0x14, 0x20, 0x5d, 0xf8, 0x65, 0x4e, 0xc5, 0x15, - 0x4d, 0x4a, 0xe2, 0xc8, 0x03, 0xb4, 0x5c, 0x9b, 0xc3, 0x1c, 0x0b, 0x49, 0x06, 0xc3, 0xae, 0xcb, 0xb7, 0xa9, 0xa1, - 0x73, 0xc1, 0xe7, 0x54, 0x48, 0x46, 0xf3, 0x92, 0x95, 0x04, 0x20, 0x45, 0x4b, 0x76, 0x92, 0x13, 0xbb, 0xbe, 0x79, - 0xc0, 0x30, 0x45, 0x35, 0x86, 0x61, 0x05, 0xed, 0x8b, 0x2b, 0x25, 0x31, 0x72, 0xcc, 0x10, 0x96, 0x1a, 0xd2, 0x1c, - 0xa1, 0x02, 0x61, 0x69, 0xc1, 0xd5, 0xac, 0xc8, 0xcc, 0x76, 0x0b, 0xa2, 0x9a, 0x7c, 0xa7, 0x44, 0x35, 0x30, 0xb4, - 0x58, 0xd2, 0x83, 0x83, 0x80, 0x86, 0x25, 0x51, 0x90, 0xbd, 0xb6, 0xd9, 0x23, 0x07, 0x59, 0x3b, 0xc0, 0x86, 0x89, - 0x25, 0xa6, 0x08, 0xef, 0xd1, 0x30, 0xe3, 0x27, 0xa3, 0x11, 0xcd, 0x73, 0x2e, 0x0e, 0x0e, 0xf6, 0x54, 0xfb, 0x52, - 0x9b, 0x80, 0x3d, 0x7c, 0x7b, 0x9d, 0x55, 0x10, 0xa0, 0x4a, 0xc2, 0x1a, 0xb9, 0x20, 0x41, 0x4e, 0x29, 0x85, 0xc3, - 0xef, 0x5b, 0xc5, 0x23, 0xf2, 0xcf, 0xcf, 0xfd, 0x86, 0xc4, 0x06, 0x0d, 0x13, 0x6a, 0xa7, 0xbe, 0x7d, 0x4e, 0xb5, - 0x6a, 0xa5, 0x14, 0x8f, 0x0d, 0xcc, 0xe8, 0xf3, 0x13, 0x26, 0x74, 0xcc, 0x32, 0x67, 0xd9, 0x35, 0x90, 0xb0, 0xc4, - 0x39, 0x2a, 0x9c, 0x0d, 0xdd, 0x3a, 0xb4, 0xd2, 0x69, 0xf4, 0xce, 0x2d, 0x27, 0x4a, 0x8f, 0x70, 0xb6, 0x71, 0x40, - 0x87, 0x05, 0x56, 0xa8, 0xb7, 0xab, 0xc9, 0x14, 0xa0, 0x03, 0x39, 0xec, 0x9a, 0x7a, 0x92, 0x6b, 0xcc, 0x09, 0xfa, - 0xf3, 0x82, 0xe6, 0x52, 0xd3, 0x71, 0x20, 0x71, 0x86, 0x19, 0x2a, 0xe0, 0xb8, 0x8d, 0xd9, 0x64, 0x21, 0x40, 0xdd, - 0x81, 0xa3, 0x48, 0xb3, 0xc5, 0x8c, 0xda, 0xa7, 0x6d, 0xb0, 0xbd, 0x9d, 0x83, 0x40, 0xcc, 0x81, 0xa6, 0xef, 0x26, - 0x27, 0x80, 0x55, 0xa2, 0xd5, 0xea, 0x3b, 0x3b, 0x48, 0xb5, 0x95, 0xa5, 0x8a, 0xb6, 0xb6, 0x27, 0x7f, 0x47, 0x46, - 0x1e, 0xef, 0xb5, 0x35, 0xf4, 0x7f, 0x1f, 0x92, 0xbd, 0x56, 0x49, 0xc1, 0x06, 0xa7, 0x1a, 0x18, 0x8d, 0xc2, 0xb7, - 0x7a, 0x20, 0xa4, 0xa4, 0x7b, 0x8d, 0x58, 0xc2, 0xe9, 0x06, 0x9d, 0x4e, 0xc9, 0x00, 0xf4, 0x8c, 0x70, 0x3a, 0xdc, - 0x45, 0x4c, 0x96, 0x1b, 0x04, 0x72, 0xb3, 0xae, 0x62, 0x1a, 0x57, 0x75, 0xa6, 0xb1, 0xb6, 0x08, 0x7f, 0x5e, 0x76, - 0xf1, 0x4b, 0x1a, 0x33, 0xc7, 0xbc, 0xaa, 0xc2, 0x4c, 0x01, 0x53, 0x2d, 0xc9, 0x19, 0xe2, 0x4d, 0x3c, 0xa3, 0x79, - 0x40, 0x11, 0xde, 0xd5, 0x40, 0x13, 0x27, 0x34, 0x19, 0x3a, 0x62, 0x33, 0x07, 0xb1, 0xc9, 0x90, 0xd6, 0xca, 0xea, - 0xc7, 0x2d, 0xc7, 0x74, 0x90, 0x0f, 0x2b, 0x65, 0xce, 0x59, 0xbc, 0x92, 0xc7, 0x86, 0xba, 0x2d, 0xfe, 0x74, 0x99, - 0x46, 0x9a, 0x52, 0x1a, 0x72, 0x84, 0xf7, 0x5a, 0xeb, 0xfb, 0x68, 0x5b, 0x55, 0x6b, 0x1c, 0x0c, 0x61, 0x1f, 0x94, - 0xb8, 0x08, 0x59, 0xae, 0xfe, 0xaf, 0x9d, 0x33, 0x40, 0xdb, 0x19, 0x90, 0x45, 0x38, 0x4e, 0x63, 0x19, 0xb4, 0x0f, - 0x5b, 0xa0, 0x89, 0x5e, 0x51, 0x90, 0x26, 0x08, 0x6d, 0x2e, 0x85, 0x86, 0x8b, 0x2c, 0x9f, 0xb2, 0xb1, 0x0c, 0x62, - 0xa9, 0x18, 0x0a, 0x4d, 0x73, 0xea, 0xc9, 0x9a, 0x3e, 0xac, 0x98, 0x4d, 0x0c, 0xa4, 0x56, 0x2a, 0x5f, 0xd4, 0x42, - 0xaa, 0x98, 0x16, 0xf0, 0x86, 0x4a, 0x97, 0xae, 0x78, 0x8c, 0x6d, 0xcd, 0x40, 0x5f, 0x6c, 0xf7, 0xf5, 0x88, 0x91, - 0x61, 0x05, 0xcc, 0x51, 0x59, 0x59, 0xe4, 0xf2, 0x07, 0x53, 0x28, 0x43, 0xc9, 0x5f, 0xf1, 0x6b, 0x2a, 0x4e, 0x63, - 0x00, 0x3e, 0xd2, 0xdd, 0x0b, 0x2d, 0x06, 0x14, 0xb7, 0x97, 0x5d, 0x4b, 0x2f, 0xe7, 0x6a, 0xe1, 0x5f, 0x0b, 0x3e, - 0x63, 0x39, 0x05, 0x4d, 0x4d, 0xe3, 0x3f, 0x83, 0x53, 0xa6, 0x8e, 0x23, 0x88, 0x1a, 0x5a, 0xd2, 0xd7, 0xc9, 0xab, - 0x3a, 0x7d, 0x9d, 0xef, 0xbf, 0x98, 0x58, 0xf6, 0x57, 0x3f, 0xc4, 0x08, 0x07, 0xc6, 0x9e, 0x70, 0xa4, 0x5c, 0x38, - 0x45, 0x46, 0xbc, 0xaf, 0x56, 0xd2, 0x31, 0xdb, 0x6a, 0xba, 0x22, 0xd5, 0xc7, 0x06, 0x15, 0x71, 0x92, 0x80, 0x56, - 0x27, 0x78, 0x9a, 0x3a, 0x82, 0x0a, 0xb3, 0x6e, 0x29, 0x9a, 0xce, 0xf7, 0x5f, 0x9c, 0xdd, 0x25, 0x9d, 0xa0, 0xde, - 0x15, 0x50, 0x16, 0xd0, 0x2c, 0xa1, 0x02, 0xcc, 0x48, 0x67, 0xb7, 0x8c, 0x8c, 0x3d, 0xe5, 0x59, 0x46, 0x47, 0x92, - 0x26, 0x60, 0xa5, 0x30, 0x22, 0xc3, 0x29, 0xcf, 0x65, 0x59, 0x58, 0x41, 0xcf, 0x1c, 0xe8, 0x59, 0x38, 0x8a, 0xd3, - 0x34, 0xd0, 0x16, 0xc9, 0x8c, 0x5f, 0xd1, 0x2d, 0x50, 0x77, 0x6b, 0x20, 0x97, 0xc3, 0x50, 0x67, 0x18, 0x1a, 0xe6, - 0xf3, 0x94, 0x8d, 0x68, 0x29, 0xb8, 0xce, 0x42, 0x96, 0x25, 0xf4, 0x06, 0xf8, 0x08, 0xea, 0xf5, 0x7a, 0x2d, 0xdc, - 0x46, 0x85, 0x46, 0xf8, 0x72, 0x03, 0xb1, 0x77, 0x88, 0x4c, 0x20, 0x32, 0xd2, 0x5b, 0x6e, 0xe3, 0x07, 0x14, 0x39, - 0x72, 0x92, 0x59, 0xcb, 0x4a, 0xf3, 0x66, 0x84, 0x13, 0x9a, 0x52, 0x49, 0x2d, 0x2f, 0x07, 0xfd, 0x59, 0x1f, 0xdd, - 0x77, 0x25, 0xfe, 0x4a, 0x72, 0xb2, 0xa7, 0xcc, 0xee, 0x79, 0x5e, 0x5a, 0xea, 0xd5, 0xf6, 0x54, 0xd8, 0xee, 0x4b, - 0xbd, 0x3d, 0xb1, 0x94, 0xf1, 0x68, 0xaa, 0x4d, 0xf4, 0x60, 0x63, 0x49, 0xd5, 0x18, 0x86, 0xaf, 0x97, 0x87, 0xe8, - 0x83, 0x05, 0x73, 0x1b, 0x0a, 0xce, 0x0c, 0x53, 0xa0, 0x60, 0xf5, 0xe9, 0x6d, 0x3b, 0x8d, 0xd3, 0xf4, 0x32, 0x1e, - 0x7d, 0xac, 0x53, 0x7f, 0x45, 0x06, 0x64, 0x9d, 0x1b, 0x3b, 0x55, 0x0e, 0xcb, 0x72, 0xd7, 0x6d, 0xb9, 0x74, 0xed, - 0xa0, 0x04, 0x7b, 0xad, 0x8a, 0xec, 0xeb, 0x1b, 0xbd, 0x93, 0xda, 0x15, 0x44, 0xcc, 0xac, 0x2c, 0x00, 0x2e, 0xf0, - 0x49, 0x8a, 0xb3, 0xfc, 0xc0, 0xd0, 0x1d, 0xd8, 0x1a, 0xc5, 0x1a, 0x20, 0x12, 0x2d, 0x8b, 0x84, 0xe5, 0xbb, 0x31, - 0xf0, 0x87, 0x40, 0xf9, 0xdc, 0x99, 0xe1, 0xbe, 0x80, 0x96, 0x3c, 0xce, 0xa8, 0xcc, 0x25, 0x64, 0x46, 0x9b, 0xb0, - 0x8c, 0xe6, 0x6f, 0xa0, 0xb9, 0x28, 0x7a, 0x7f, 0xab, 0xab, 0x40, 0x27, 0x03, 0x28, 0xf2, 0xae, 0xab, 0x4c, 0xd4, - 0x28, 0xc0, 0xf0, 0x54, 0xa6, 0x44, 0x6e, 0x56, 0x33, 0x1e, 0x8d, 0xba, 0xae, 0xed, 0x6f, 0xc3, 0x72, 0x39, 0x09, - 0x82, 0x20, 0x07, 0xfb, 0xcd, 0xea, 0xf5, 0xd5, 0x22, 0xf2, 0x8d, 0x45, 0xe4, 0xa1, 0x63, 0x64, 0xa1, 0x8a, 0x96, - 0x9d, 0xee, 0xd1, 0x5f, 0x91, 0xdb, 0x08, 0x94, 0xd5, 0x10, 0xf8, 0x33, 0x2a, 0xd9, 0x6d, 0x4a, 0x24, 0xe6, 0xc6, - 0xc0, 0x31, 0x94, 0x06, 0x0c, 0xa3, 0xea, 0x92, 0x21, 0x7d, 0x34, 0x6a, 0xc6, 0x6e, 0x86, 0x39, 0x5a, 0xd3, 0xec, - 0x8b, 0xc2, 0xe0, 0x88, 0x22, 0xb3, 0x37, 0x35, 0x95, 0xd8, 0xc1, 0x0a, 0xce, 0x88, 0x51, 0x83, 0xb5, 0xd6, 0xb3, - 0x8e, 0x9b, 0x72, 0x5c, 0x38, 0xa8, 0x15, 0x6a, 0x6a, 0xfa, 0xa4, 0x55, 0xac, 0x32, 0x84, 0xa7, 0x56, 0x23, 0xe5, - 0xd5, 0xba, 0x09, 0xf1, 0xad, 0x37, 0xc2, 0xef, 0x2f, 0x6b, 0x26, 0x61, 0xe4, 0x34, 0x2b, 0x22, 0x60, 0xa9, 0x7c, - 0x1b, 0xba, 0xb7, 0xd1, 0x4c, 0x6d, 0x1c, 0x07, 0xe1, 0xdc, 0x45, 0xb8, 0x83, 0xd9, 0x4c, 0x73, 0xae, 0x6c, 0x48, - 0xa6, 0xf5, 0xbe, 0x01, 0xc5, 0x5c, 0xef, 0xc3, 0x06, 0x12, 0xd7, 0x15, 0x4f, 0x45, 0x82, 0x60, 0xc0, 0xe6, 0xa0, - 0xdc, 0xb9, 0xf2, 0x21, 0x00, 0xd8, 0xd9, 0x6a, 0xb5, 0x41, 0x74, 0x5b, 0xf5, 0x4f, 0x14, 0x56, 0x46, 0xe1, 0x6a, - 0x75, 0x2d, 0x51, 0x60, 0x34, 0x5f, 0x4c, 0x51, 0xdf, 0x72, 0xdc, 0x93, 0x57, 0xd0, 0x4a, 0x29, 0xa2, 0x55, 0x49, - 0x69, 0x32, 0xd4, 0x69, 0xb6, 0xbe, 0x4f, 0xd2, 0x61, 0xdb, 0xa7, 0x1b, 0xdc, 0x4b, 0x15, 0x1a, 0x31, 0x5d, 0x2d, - 0xf9, 0xd4, 0x0c, 0xcd, 0x10, 0x42, 0x51, 0xae, 0xac, 0x98, 0xbd, 0x6d, 0x86, 0xe5, 0xc1, 0x41, 0xee, 0x0c, 0x74, - 0x5e, 0xb2, 0x89, 0x9f, 0x02, 0x10, 0xc9, 0xf9, 0x6d, 0xa6, 0x74, 0x97, 0x9f, 0xac, 0x10, 0xda, 0x30, 0x4b, 0x5b, - 0x5d, 0xb0, 0xc6, 0xe3, 0xeb, 0x98, 0x49, 0xaf, 0x1c, 0x45, 0x5b, 0xe3, 0x01, 0x45, 0x4b, 0xa3, 0x6a, 0x84, 0x82, - 0x82, 0xf2, 0x08, 0x3c, 0xc1, 0xaa, 0xd0, 0x9a, 0xee, 0x47, 0x53, 0x0a, 0x8e, 0x60, 0xab, 0x45, 0x94, 0x76, 0xe1, - 0x9e, 0x91, 0x22, 0x66, 0xe0, 0xed, 0xb0, 0x17, 0xeb, 0xdd, 0x6b, 0x76, 0xc0, 0x9c, 0x8a, 0x31, 0x17, 0x33, 0x5b, - 0x57, 0xac, 0x3d, 0x1b, 0xce, 0xc8, 0xc6, 0xc1, 0xd6, 0xb1, 0x8d, 0xfa, 0xdf, 0x5d, 0x33, 0xba, 0x2b, 0x73, 0xbd, - 0x26, 0x4a, 0x4b, 0xe9, 0xab, 0xfd, 0x81, 0x96, 0x32, 0x73, 0xd7, 0xbc, 0x37, 0xce, 0xd4, 0xae, 0x76, 0x98, 0xec, - 0xb5, 0xbb, 0xa5, 0xcd, 0x67, 0xa9, 0xa1, 0xab, 0x1d, 0x1b, 0x46, 0xa4, 0xf2, 0x45, 0x9a, 0x18, 0x60, 0x19, 0xc2, - 0xd4, 0xd0, 0xd1, 0x35, 0x4b, 0xd3, 0xaa, 0xf4, 0xd7, 0xf0, 0xf5, 0xdc, 0xf0, 0xf5, 0xcc, 0xf2, 0x75, 0xe0, 0x14, - 0xc0, 0xd7, 0xf5, 0x70, 0x55, 0xf7, 0x6c, 0xe3, 0x74, 0x66, 0x9a, 0xa3, 0xe7, 0xca, 0x8e, 0x86, 0xf9, 0x16, 0x16, - 0x02, 0x54, 0x6a, 0x5e, 0x1f, 0x03, 0xe3, 0x84, 0x01, 0x03, 0x50, 0xbb, 0x30, 0xa9, 0xeb, 0xa2, 0xf8, 0x18, 0x20, - 0x9c, 0x17, 0xb4, 0xa4, 0xec, 0x93, 0x17, 0xe0, 0xa4, 0x73, 0x96, 0x03, 0x42, 0x4c, 0x15, 0xff, 0x2a, 0x25, 0xca, - 0xae, 0x8e, 0x99, 0xd5, 0xe5, 0x76, 0x75, 0xc0, 0xe9, 0xab, 0xd5, 0x25, 0x77, 0xf3, 0x7a, 0xb5, 0x3c, 0x56, 0x2e, - 0xaf, 0xda, 0xef, 0xd5, 0x2a, 0x58, 0x2b, 0x01, 0xff, 0xbd, 0x31, 0x51, 0x44, 0x39, 0x3a, 0xf0, 0x00, 0x17, 0x33, - 0x50, 0x50, 0xe8, 0x45, 0x97, 0x22, 0xee, 0xd5, 0xa7, 0x1c, 0x3c, 0xca, 0x4d, 0xaf, 0xfb, 0x9f, 0xf2, 0xd9, 0x1c, - 0xb4, 0xb1, 0x35, 0x92, 0x9e, 0x50, 0x33, 0x61, 0x55, 0x5f, 0x6c, 0x29, 0xab, 0xf5, 0x51, 0xe7, 0xb1, 0x46, 0x4d, - 0xa5, 0xbd, 0xbc, 0xd7, 0x2a, 0x16, 0x65, 0x51, 0xc9, 0x38, 0xb6, 0x39, 0x55, 0x4e, 0xd7, 0x5d, 0x32, 0xb6, 0xe2, - 0x6d, 0xc0, 0x34, 0x1f, 0x66, 0xc0, 0xeb, 0x1c, 0xf6, 0x63, 0xc9, 0xdd, 0xdd, 0xff, 0xa2, 0x42, 0xce, 0xb2, 0x58, - 0x43, 0xdf, 0xb2, 0x28, 0x4e, 0xb4, 0x91, 0x8d, 0x4f, 0x76, 0x5b, 0xc3, 0x55, 0x9d, 0x31, 0x16, 0x07, 0x43, 0x7c, - 0xb2, 0xa9, 0x3a, 0x92, 0xe5, 0x8c, 0x27, 0x34, 0xf2, 0xf9, 0x9c, 0x66, 0x7e, 0x01, 0x5e, 0x55, 0xb3, 0xf7, 0x23, - 0x19, 0x2c, 0xdf, 0xd5, 0xdd, 0xab, 0xd1, 0x49, 0x01, 0xde, 0xaf, 0x2f, 0x36, 0x1d, 0xaf, 0xdf, 0x52, 0x91, 0x2b, - 0x45, 0xb4, 0xd4, 0x69, 0xbf, 0xa8, 0xc4, 0xd2, 0x17, 0xd1, 0xce, 0xf6, 0x95, 0x09, 0xe2, 0xb7, 0xc3, 0xc7, 0xe1, - 0x91, 0x8f, 0x94, 0x5b, 0xf8, 0x2b, 0x73, 0xe0, 0x9f, 0x5b, 0xb7, 0xf0, 0x0b, 0xf2, 0xbc, 0xee, 0x15, 0x4e, 0x24, - 0x79, 0xd1, 0x7f, 0x61, 0x2d, 0x66, 0x9e, 0xb2, 0xd1, 0x6d, 0xe0, 0xa7, 0x4c, 0x36, 0x21, 0xf4, 0xe6, 0xe3, 0xa5, - 0xae, 0x00, 0x97, 0xa2, 0x72, 0x67, 0x17, 0xd6, 0xd6, 0xc3, 0x52, 0x12, 0x7f, 0x3f, 0x65, 0x72, 0xdf, 0xc7, 0x33, - 0x72, 0x01, 0x3f, 0xf6, 0x97, 0xc1, 0xeb, 0x58, 0x4e, 0x43, 0x11, 0x67, 0x09, 0x9f, 0x05, 0xa8, 0xe1, 0xfb, 0x28, - 0xcc, 0x95, 0xbd, 0xf1, 0x39, 0x2a, 0xf6, 0x2f, 0xf0, 0x8d, 0x24, 0x7e, 0xdf, 0x6f, 0xcc, 0xf0, 0x1b, 0x49, 0x2e, - 0x8e, 0xf7, 0x97, 0x37, 0xb2, 0xe8, 0x5d, 0xe0, 0x9b, 0xd2, 0x63, 0x8f, 0xbf, 0x26, 0x01, 0x22, 0xbd, 0x1b, 0x03, - 0xcd, 0x29, 0x9f, 0x69, 0xcf, 0xbd, 0x8f, 0xf0, 0x07, 0x88, 0xab, 0x88, 0x8a, 0xdb, 0x98, 0xd0, 0xca, 0x1e, 0xf1, - 0xb9, 0x72, 0x11, 0xf8, 0x07, 0x07, 0x4e, 0x59, 0xa9, 0x2a, 0xe0, 0x13, 0x49, 0x6a, 0x06, 0x39, 0x7e, 0xaf, 0x22, - 0x34, 0x27, 0x32, 0x10, 0xc8, 0x0e, 0x13, 0x58, 0x3f, 0xb4, 0x39, 0x9a, 0x62, 0xa0, 0x3d, 0x0c, 0x21, 0x93, 0x54, - 0xc4, 0x92, 0x8b, 0x21, 0x72, 0xd5, 0x0f, 0xfc, 0x37, 0x72, 0x31, 0xf0, 0xfe, 0xd3, 0x3f, 0xfd, 0x38, 0xfe, 0x51, - 0x0c, 0x2f, 0xf0, 0x5b, 0x72, 0x78, 0x1c, 0xf4, 0xa3, 0x60, 0xaf, 0xd9, 0x5c, 0xfd, 0x78, 0x38, 0xf8, 0x47, 0xdc, - 0xfc, 0xe5, 0xa4, 0xf9, 0xc3, 0x10, 0xad, 0x82, 0x1f, 0x0f, 0xfb, 0x03, 0xf3, 0x34, 0xf8, 0x47, 0xef, 0xc7, 0x7c, - 0xf8, 0x67, 0x5d, 0xb8, 0x8f, 0xd0, 0xe1, 0x04, 0x2f, 0x24, 0x39, 0x6c, 0x36, 0x7b, 0x87, 0x13, 0x3c, 0x97, 0xe4, - 0x10, 0xfe, 0xbf, 0x24, 0xef, 0xe8, 0xe4, 0xc5, 0xcd, 0x3c, 0xb8, 0xe8, 0xad, 0xf6, 0x97, 0x7f, 0x2b, 0x60, 0xd4, - 0xc1, 0x3f, 0x7e, 0xfc, 0x31, 0xf7, 0x1f, 0xf4, 0xc8, 0xe1, 0xb0, 0x81, 0x02, 0x28, 0xfd, 0x33, 0x51, 0xff, 0x06, - 0xfd, 0x68, 0xf0, 0x0f, 0x03, 0x85, 0xff, 0xe0, 0xc7, 0x8b, 0xe3, 0x1e, 0x19, 0xae, 0x02, 0x7f, 0xf5, 0x00, 0xad, - 0x10, 0x5a, 0xed, 0xa3, 0x0b, 0xec, 0x4f, 0x7c, 0x84, 0x27, 0x92, 0x1c, 0x3e, 0x38, 0x9c, 0xe0, 0x2b, 0x49, 0x0e, - 0xfd, 0xc3, 0x09, 0x7e, 0x21, 0xc9, 0xe1, 0x3f, 0x82, 0x7e, 0xa4, 0x3d, 0x6c, 0x2b, 0xe5, 0xde, 0x58, 0x41, 0x70, - 0x23, 0x16, 0x34, 0x5e, 0x49, 0x26, 0x53, 0x8a, 0xf6, 0x0f, 0x19, 0x3e, 0x53, 0x68, 0x0a, 0x24, 0x38, 0x61, 0xc0, - 0xb6, 0x0b, 0x96, 0xe7, 0xb0, 0xd9, 0x40, 0x33, 0xfb, 0x91, 0xc0, 0xda, 0x0f, 0x90, 0x47, 0x12, 0x5f, 0xc5, 0xe9, - 0x82, 0xe6, 0x11, 0x2d, 0x10, 0x1e, 0x91, 0x33, 0x19, 0xb4, 0x11, 0x7e, 0x27, 0xe1, 0x47, 0x07, 0xe1, 0x33, 0x13, - 0xc0, 0x84, 0x83, 0xac, 0x89, 0x2a, 0xe3, 0x5a, 0x63, 0xf1, 0x11, 0x9e, 0x6f, 0xa9, 0x94, 0x53, 0xf0, 0x2e, 0x20, - 0x3c, 0xae, 0x85, 0x3b, 0xf1, 0x35, 0xb1, 0x24, 0xf1, 0x5e, 0x50, 0xfa, 0x5d, 0x9c, 0x7e, 0xa4, 0x22, 0xb8, 0xc1, - 0xed, 0xce, 0xe7, 0x58, 0xb9, 0xa0, 0xf7, 0xda, 0xa8, 0x5b, 0xc6, 0xaa, 0x4e, 0xa5, 0x8e, 0x11, 0x80, 0x90, 0xad, - 0xfb, 0x62, 0x60, 0xc7, 0xf7, 0xc4, 0x86, 0xc3, 0x4a, 0xc4, 0xd7, 0x3e, 0xaa, 0xc7, 0x45, 0x59, 0x76, 0x15, 0xa7, - 0x2c, 0xf1, 0x24, 0x9d, 0xcd, 0xd3, 0x58, 0x52, 0xcf, 0xac, 0xd7, 0x8b, 0x61, 0x20, 0xbf, 0x54, 0x19, 0x12, 0xc7, - 0xe0, 0x4c, 0x6c, 0xc0, 0x09, 0xce, 0x4a, 0x00, 0xd1, 0x29, 0xa3, 0x76, 0xbc, 0xae, 0x82, 0x5f, 0xeb, 0xf1, 0xbd, - 0x66, 0x1b, 0x1c, 0x61, 0x43, 0x25, 0x9e, 0x73, 0x9c, 0x11, 0x10, 0xa2, 0x9d, 0xbe, 0x7f, 0x9c, 0x5f, 0x4d, 0x7a, - 0x3e, 0xc4, 0x66, 0x38, 0x79, 0xab, 0xfc, 0x42, 0xd0, 0x60, 0x4a, 0x5a, 0xdd, 0xe9, 0x31, 0xed, 0x4e, 0x1b, 0x0d, - 0xab, 0x43, 0xa7, 0x44, 0x0c, 0xa6, 0xba, 0x7b, 0x8c, 0x13, 0xbc, 0x20, 0xcd, 0x36, 0x9e, 0x90, 0x96, 0xea, 0xd2, - 0x9d, 0x1c, 0xa7, 0x66, 0x9a, 0x83, 0x83, 0x80, 0x87, 0x69, 0x9c, 0xcb, 0x2f, 0xc1, 0xd8, 0x27, 0x13, 0x9c, 0x10, - 0x1e, 0xd2, 0x1b, 0x3a, 0x0a, 0x52, 0x84, 0x13, 0xc3, 0x69, 0x50, 0x17, 0x4d, 0x88, 0xd3, 0x0c, 0x8c, 0x08, 0xf2, - 0xb6, 0x9f, 0x0c, 0xda, 0x43, 0x42, 0x88, 0xbf, 0xd7, 0x6c, 0xfa, 0x7d, 0x4e, 0x16, 0x32, 0x82, 0x12, 0x47, 0x55, - 0x26, 0x73, 0x28, 0xea, 0x38, 0x45, 0xc1, 0x0b, 0x19, 0x4a, 0x9a, 0xcb, 0x00, 0x8a, 0xc1, 0xfc, 0xcf, 0x2d, 0x61, - 0xfb, 0xc7, 0x87, 0x7e, 0x03, 0x4a, 0x15, 0x71, 0x22, 0xcc, 0xc9, 0x25, 0x8a, 0x92, 0xc1, 0xd1, 0xd0, 0xe5, 0xff, - 0xaa, 0x10, 0x26, 0xbf, 0xec, 0x27, 0x83, 0x96, 0x9a, 0xbc, 0xe7, 0xf7, 0x03, 0x4e, 0x72, 0xad, 0xa0, 0xf5, 0xf3, - 0xe8, 0xad, 0x5a, 0x2a, 0x8a, 0x0c, 0x70, 0x66, 0xde, 0x05, 0x69, 0x76, 0xa2, 0x60, 0xe1, 0x2e, 0xa2, 0x09, 0x93, - 0x19, 0x2c, 0xe0, 0x98, 0x40, 0x7b, 0xcc, 0x09, 0xcc, 0x58, 0x75, 0xbb, 0x8c, 0xcc, 0xf3, 0x03, 0xff, 0x41, 0xff, - 0x4a, 0x46, 0x13, 0xa9, 0xa7, 0xbf, 0x92, 0xab, 0x15, 0xfc, 0x3f, 0x91, 0x7d, 0x4e, 0x2e, 0x55, 0xd1, 0xc2, 0x14, - 0xcd, 0xa1, 0xe8, 0x6d, 0x04, 0xa0, 0xe2, 0xbc, 0x54, 0xb2, 0xf4, 0x9e, 0x5c, 0x11, 0x05, 0xfb, 0xc1, 0x81, 0x18, - 0x4c, 0x1b, 0xed, 0x21, 0xf8, 0xf7, 0x85, 0xcc, 0xbf, 0x63, 0x72, 0x1a, 0xf8, 0x87, 0x3d, 0x1f, 0xf5, 0x7d, 0x0f, - 0xb6, 0xb6, 0x9b, 0x35, 0x88, 0xc6, 0x70, 0xda, 0x78, 0x23, 0xa3, 0x45, 0x8f, 0xb4, 0xfa, 0x01, 0x33, 0xfe, 0x3c, - 0x84, 0x53, 0xc3, 0x38, 0x5b, 0x78, 0x81, 0x1a, 0x52, 0x36, 0xec, 0xf3, 0x02, 0x35, 0x66, 0x8d, 0x2b, 0x14, 0xa5, - 0x8d, 0x59, 0x23, 0x58, 0x10, 0x42, 0x9a, 0x9d, 0xb2, 0x9b, 0x95, 0x7e, 0x53, 0x14, 0x5d, 0x59, 0x67, 0xe7, 0x40, - 0x1d, 0x87, 0xac, 0x11, 0x88, 0x01, 0x1d, 0xae, 0x56, 0xfe, 0x71, 0xbf, 0xe7, 0xa3, 0x46, 0x60, 0x09, 0xed, 0xd0, - 0x52, 0x1a, 0x42, 0x98, 0x0d, 0x0b, 0x13, 0x4a, 0x7a, 0x59, 0x0b, 0x1b, 0x2d, 0xab, 0xc3, 0xee, 0xf0, 0x00, 0x5a, - 0x94, 0x76, 0x8c, 0xd6, 0x57, 0xe7, 0xb0, 0x4c, 0x4b, 0xcc, 0x19, 0x69, 0x61, 0x4e, 0xac, 0xef, 0x7a, 0x4a, 0x64, - 0x45, 0xf0, 0x29, 0xa9, 0x9a, 0xe3, 0x41, 0x8c, 0x93, 0x21, 0x79, 0xad, 0xed, 0x91, 0xae, 0xf5, 0x8b, 0xd3, 0x94, - 0xbc, 0x5c, 0x8b, 0xde, 0xc6, 0x10, 0x5b, 0xb9, 0x0e, 0x47, 0x0b, 0x21, 0x68, 0x26, 0xdf, 0xf0, 0xc4, 0xa8, 0x69, - 0x34, 0x05, 0x4b, 0x09, 0xc2, 0xb2, 0x18, 0x74, 0xb4, 0x8e, 0x3d, 0x19, 0x8b, 0x8d, 0xea, 0x09, 0x59, 0x68, 0xf5, - 0x49, 0x05, 0x6b, 0xbb, 0x13, 0x63, 0x17, 0x07, 0x08, 0x2f, 0x4c, 0x14, 0x37, 0x08, 0xc3, 0x70, 0x12, 0x8e, 0xa0, - 0x1a, 0x26, 0xc8, 0x51, 0xa1, 0xce, 0x51, 0x90, 0x93, 0xeb, 0x30, 0xa3, 0x37, 0x6a, 0xd6, 0x00, 0x55, 0x92, 0xd9, - 0x1e, 0xaf, 0xe3, 0x69, 0x57, 0xb1, 0x9b, 0x3c, 0xcc, 0x78, 0x42, 0x01, 0x3d, 0x10, 0xb7, 0x37, 0x45, 0xd3, 0x38, - 0x77, 0xe3, 0x53, 0x15, 0x7c, 0x03, 0xd7, 0x79, 0x3d, 0x01, 0x8f, 0xaf, 0xd2, 0xb5, 0xca, 0xc6, 0xda, 0x0d, 0x8e, - 0x10, 0x1b, 0x07, 0x93, 0x10, 0xe2, 0x7a, 0x8a, 0x84, 0x24, 0x98, 0x72, 0x13, 0x97, 0xa8, 0x66, 0xe5, 0x98, 0x57, - 0x24, 0x19, 0xf0, 0x46, 0x43, 0x79, 0xa1, 0x17, 0x9a, 0x24, 0x26, 0x08, 0x5f, 0x95, 0x67, 0xcb, 0xb6, 0x7b, 0x2b, - 0x49, 0x7d, 0xaa, 0xe0, 0xaa, 0xee, 0xce, 0x6d, 0x48, 0x89, 0x94, 0xa7, 0x50, 0x06, 0x33, 0x84, 0x9f, 0x91, 0xc3, - 0x60, 0x10, 0xf6, 0xff, 0x32, 0x44, 0xfd, 0x20, 0xfc, 0x33, 0x3a, 0xd4, 0x9c, 0xe3, 0x0a, 0x75, 0x53, 0x3d, 0xc7, - 0x52, 0xc5, 0x2f, 0xdb, 0x58, 0x79, 0x12, 0xa3, 0x0c, 0x67, 0xf1, 0x8c, 0x46, 0xcf, 0xe0, 0x90, 0x5b, 0xc2, 0x79, - 0x2b, 0x31, 0x50, 0x52, 0xf4, 0xcc, 0xf0, 0x92, 0xd0, 0xef, 0xbf, 0x92, 0xe5, 0x53, 0xdf, 0xef, 0x3f, 0xaf, 0x9e, - 0xfe, 0xe2, 0xf7, 0x7f, 0x91, 0xd1, 0xcf, 0x85, 0xf1, 0x76, 0xd7, 0xe6, 0x78, 0x6c, 0xe7, 0x28, 0xf4, 0xd6, 0x38, - 0xb8, 0x5b, 0xa0, 0x4d, 0x47, 0xc7, 0x04, 0x15, 0x6c, 0x5c, 0x32, 0xa3, 0x3c, 0x94, 0xf1, 0x04, 0x90, 0xea, 0xec, - 0x41, 0xee, 0xc6, 0xf5, 0xab, 0x15, 0x03, 0xa9, 0x58, 0x7a, 0x05, 0x64, 0x4e, 0x7a, 0x2d, 0xb4, 0xac, 0xb5, 0x55, - 0x3a, 0x53, 0x3d, 0x8e, 0x5e, 0xf2, 0xe9, 0x2b, 0xd2, 0xea, 0x5e, 0x1d, 0x4f, 0xba, 0x57, 0x8d, 0x06, 0xca, 0x2d, - 0x69, 0x2d, 0x06, 0x57, 0x43, 0xfc, 0x35, 0x38, 0xf5, 0x5c, 0x5a, 0xc2, 0xb5, 0xe5, 0x75, 0xcc, 0xf2, 0x1a, 0x8d, - 0xac, 0x40, 0x5d, 0xa7, 0xeb, 0x44, 0x77, 0x2d, 0x0a, 0x8d, 0x93, 0x75, 0x52, 0x7b, 0x8a, 0x54, 0x09, 0x24, 0x43, - 0x11, 0x42, 0x6e, 0x24, 0xda, 0x3a, 0x2a, 0x8c, 0x09, 0xdd, 0xd5, 0x99, 0x05, 0xf6, 0xa9, 0xa5, 0x44, 0x00, 0x58, - 0x80, 0xae, 0xa5, 0x27, 0x78, 0x86, 0x17, 0x8d, 0xb6, 0x22, 0xf3, 0x66, 0xbb, 0x5b, 0x1f, 0xeb, 0x49, 0x35, 0x16, - 0x5e, 0x34, 0xc8, 0xac, 0xc4, 0x52, 0x91, 0x35, 0x1a, 0x45, 0x3d, 0xd8, 0x69, 0x4f, 0x6e, 0x2d, 0x00, 0x71, 0xb3, - 0x9e, 0x94, 0x61, 0x25, 0x6c, 0x25, 0x53, 0x59, 0xc8, 0xb2, 0x8c, 0x0a, 0x90, 0xa2, 0x44, 0x62, 0x56, 0x14, 0x95, - 0x64, 0x07, 0x31, 0x8a, 0x29, 0x11, 0xc0, 0x79, 0x94, 0xdd, 0x85, 0x33, 0xcc, 0xf1, 0x54, 0xf1, 0x0d, 0x42, 0xc8, - 0x99, 0x4d, 0x67, 0x91, 0x8a, 0x07, 0xa5, 0x84, 0x39, 0x32, 0x29, 0x27, 0x34, 0x3c, 0xdf, 0x3f, 0xe5, 0x77, 0xda, - 0x64, 0x03, 0x36, 0x8c, 0x54, 0xb3, 0xd4, 0x70, 0xae, 0x98, 0x7c, 0x08, 0x24, 0x2a, 0xa3, 0x23, 0xa1, 0x62, 0x80, - 0xcf, 0x99, 0xa0, 0x4a, 0x07, 0xdf, 0xb7, 0x76, 0x5f, 0x5a, 0x57, 0x20, 0x53, 0xd7, 0x7b, 0x03, 0x88, 0x8c, 0xc1, - 0xb9, 0x93, 0x91, 0x8d, 0x66, 0xe7, 0xfb, 0x27, 0x6f, 0xb7, 0xd9, 0xc0, 0xab, 0x95, 0xb1, 0x7e, 0x95, 0x6e, 0x83, - 0xe3, 0x0a, 0xd2, 0xd4, 0xfc, 0x88, 0x82, 0x54, 0xa9, 0x48, 0x71, 0x20, 0x80, 0x8a, 0xce, 0xf7, 0x4f, 0xde, 0x07, - 0x42, 0xf9, 0x96, 0x10, 0x76, 0x97, 0x1d, 0x70, 0x12, 0x4c, 0x09, 0x45, 0x7a, 0xed, 0x25, 0xeb, 0xe2, 0x8e, 0x00, - 0x8f, 0xa6, 0xaa, 0x12, 0x2c, 0x88, 0x01, 0x1b, 0x92, 0xd4, 0x60, 0x80, 0xa4, 0x08, 0xa7, 0x35, 0xbb, 0x8c, 0xc0, - 0x06, 0xa8, 0xb9, 0xce, 0x60, 0x27, 0x42, 0xad, 0xfa, 0x21, 0x9c, 0xaa, 0x59, 0x65, 0xa1, 0x85, 0xc7, 0xb3, 0x8d, - 0xac, 0xb4, 0xca, 0x1c, 0xfd, 0x16, 0x6c, 0x27, 0xfb, 0xf0, 0x86, 0x58, 0x4b, 0xc2, 0x14, 0x3c, 0xb7, 0xe9, 0x63, - 0xe7, 0xfb, 0x27, 0xaf, 0x4d, 0x06, 0xd9, 0x3c, 0xb6, 0xfc, 0x7e, 0xc3, 0xc4, 0x3c, 0x79, 0x1d, 0x56, 0xb5, 0xaa, - 0xf1, 0xf9, 0xfe, 0xc9, 0x87, 0x6d, 0xcd, 0xa0, 0xbc, 0x58, 0x54, 0x36, 0xbe, 0x82, 0x6f, 0x49, 0xd3, 0x68, 0x69, - 0x84, 0x43, 0xc4, 0x0a, 0xac, 0x04, 0x52, 0x94, 0x17, 0xa5, 0x6b, 0xe4, 0x39, 0xce, 0x88, 0x0a, 0x03, 0xd5, 0x77, - 0xcd, 0xa8, 0x79, 0x8c, 0x67, 0x67, 0x23, 0x3e, 0xa7, 0x3b, 0x62, 0x43, 0x37, 0x28, 0x64, 0x33, 0x48, 0x9d, 0x51, - 0xa0, 0x33, 0xbc, 0xd7, 0x42, 0xdd, 0xba, 0xf8, 0xca, 0x14, 0x91, 0xf2, 0x9a, 0x6c, 0xc1, 0x53, 0xd2, 0xc2, 0x29, - 0x69, 0xe1, 0x98, 0xe4, 0x83, 0x96, 0x16, 0x10, 0xdd, 0xb8, 0x1c, 0x57, 0x8b, 0x19, 0xc8, 0x0a, 0x33, 0xa7, 0x55, - 0x0b, 0xe0, 0xa4, 0x1b, 0x2b, 0xdf, 0xa3, 0x92, 0xe9, 0x89, 0x22, 0x8b, 0xf7, 0x01, 0xc7, 0x5c, 0x0d, 0x7c, 0xc6, - 0x2e, 0x53, 0x48, 0x2c, 0x81, 0x55, 0x61, 0x89, 0xa2, 0xb2, 0x69, 0xdb, 0x34, 0x8d, 0x43, 0xb5, 0x4f, 0x1c, 0xc7, - 0x21, 0x70, 0x6e, 0x1c, 0x9b, 0x3c, 0x9c, 0x7c, 0xb3, 0xcb, 0xe3, 0x83, 0x83, 0x40, 0x77, 0xfa, 0x52, 0x06, 0xdc, - 0xd6, 0x57, 0x91, 0xbb, 0x6f, 0x35, 0xaf, 0x48, 0x90, 0x82, 0xbf, 0xd1, 0x48, 0x87, 0x05, 0x84, 0xa1, 0x83, 0xb8, - 0x8e, 0x41, 0x0b, 0xbc, 0xd2, 0xf5, 0xea, 0xcb, 0x6f, 0x34, 0xca, 0x28, 0x6d, 0x1d, 0x5b, 0x37, 0x38, 0x2b, 0xae, - 0x82, 0x32, 0xf5, 0xa7, 0xb5, 0x91, 0x2f, 0x65, 0x41, 0x40, 0xcc, 0xa5, 0x59, 0x66, 0x17, 0xe3, 0x1c, 0x09, 0x06, - 0xed, 0xbe, 0x34, 0x59, 0x0b, 0x58, 0x65, 0x57, 0x99, 0x46, 0x96, 0x9d, 0x75, 0x50, 0x64, 0x1b, 0x41, 0x54, 0x0a, - 0x1a, 0x35, 0x0a, 0x43, 0xde, 0xef, 0x37, 0x73, 0x2e, 0x71, 0x8e, 0x8c, 0x93, 0x4b, 0x41, 0xa1, 0x90, 0xd5, 0x29, - 0x91, 0xf2, 0x92, 0xcc, 0x77, 0x93, 0xfc, 0x89, 0x43, 0xf2, 0xcf, 0x08, 0x75, 0xc8, 0x5f, 0xbb, 0x38, 0x42, 0x6e, - 0x9c, 0x0b, 0xb9, 0xad, 0x3a, 0x9d, 0x13, 0x70, 0xa2, 0xd5, 0x31, 0x5a, 0x0b, 0x2b, 0xee, 0x60, 0x28, 0xee, 0x09, - 0x51, 0x6e, 0x48, 0x6c, 0x63, 0xc0, 0x41, 0x15, 0x54, 0x83, 0xa9, 0xb7, 0xf9, 0xf4, 0x5c, 0x0e, 0x78, 0xf2, 0xe1, - 0xee, 0x78, 0xe8, 0xe9, 0x7c, 0xf3, 0xe4, 0x3a, 0xb9, 0x9f, 0xb0, 0x6a, 0xe7, 0xe0, 0xd6, 0x33, 0x41, 0x61, 0xfe, - 0x32, 0x8e, 0x5d, 0x67, 0x3e, 0x6b, 0x87, 0xd0, 0xca, 0x3f, 0x80, 0xb6, 0xdd, 0x56, 0x2d, 0xa8, 0x33, 0x2c, 0xf0, - 0x23, 0x9d, 0x81, 0x1a, 0x8b, 0x1d, 0xec, 0xe3, 0x44, 0x35, 0xa0, 0x59, 0xb2, 0xbd, 0xfa, 0x59, 0x61, 0xc8, 0x44, - 0x83, 0x86, 0x96, 0xc0, 0xff, 0x34, 0xc9, 0x03, 0xdd, 0x28, 0xb9, 0x00, 0x08, 0x9a, 0x2b, 0x3c, 0x55, 0x08, 0xf3, - 0xfd, 0xca, 0xfb, 0xfe, 0x72, 0x8f, 0x90, 0x79, 0xe5, 0x7d, 0x7c, 0x57, 0xa5, 0x5e, 0x01, 0x59, 0xa0, 0x08, 0xcc, - 0xc7, 0xb2, 0x40, 0x87, 0x2f, 0xcf, 0x6c, 0x73, 0x65, 0x42, 0x86, 0x95, 0xc6, 0xed, 0x84, 0x36, 0x95, 0x5b, 0x4e, - 0xd7, 0x5b, 0x34, 0xac, 0xd5, 0xee, 0x43, 0xed, 0x7b, 0xa9, 0x60, 0x84, 0xe7, 0xf7, 0xaa, 0xb5, 0x1d, 0xb7, 0xf8, - 0xb8, 0x9e, 0xbf, 0xb2, 0xb6, 0x29, 0x21, 0xcb, 0x72, 0x2a, 0xe4, 0x33, 0x3a, 0xe6, 0x02, 0x62, 0x16, 0x25, 0x4e, - 0x50, 0xb1, 0xef, 0xf8, 0xed, 0xd4, 0xfa, 0x9c, 0x40, 0xc1, 0xda, 0x02, 0xd5, 0xaf, 0x8f, 0x2a, 0x68, 0x7d, 0xbe, - 0xde, 0x6b, 0x7e, 0x70, 0xf0, 0xa1, 0x42, 0x93, 0x81, 0x52, 0x41, 0xe1, 0x30, 0x2d, 0xad, 0xd2, 0x98, 0x48, 0xee, - 0x7e, 0x50, 0x3a, 0x01, 0x2c, 0xc3, 0x70, 0x79, 0xcf, 0x4b, 0x22, 0x8b, 0xc9, 0x3a, 0x8b, 0x37, 0xce, 0x09, 0xe6, - 0x1a, 0x2e, 0xc0, 0xe1, 0xc1, 0xd4, 0xd6, 0xde, 0xa2, 0xbc, 0x4a, 0x86, 0x2d, 0x61, 0x38, 0x05, 0x64, 0x05, 0xca, - 0x0c, 0x71, 0x28, 0x70, 0xab, 0x59, 0x72, 0x0a, 0x7a, 0xe5, 0x14, 0xe7, 0xe1, 0x14, 0xd2, 0x5f, 0x6b, 0x47, 0x16, - 0x21, 0xac, 0x13, 0x73, 0x9c, 0x54, 0x82, 0x93, 0x97, 0xdb, 0x5c, 0xca, 0x96, 0xa8, 0xa9, 0x92, 0x3a, 0xaa, 0x05, - 0x2a, 0x3b, 0x84, 0x57, 0x01, 0x33, 0x8a, 0x9b, 0x8d, 0x9b, 0x01, 0x03, 0x7e, 0x26, 0x03, 0x1d, 0x8c, 0x02, 0x99, - 0xc1, 0xc3, 0x45, 0x50, 0x9b, 0xba, 0xcb, 0x55, 0x37, 0x6c, 0x10, 0x37, 0x75, 0xd1, 0xc4, 0x55, 0x5c, 0xef, 0xb4, - 0xe2, 0xa5, 0x63, 0x9d, 0x41, 0x2d, 0x2d, 0x17, 0xac, 0x12, 0x49, 0x9c, 0xe5, 0x8f, 0x75, 0x52, 0x74, 0xd9, 0x08, - 0x53, 0x05, 0xc6, 0x4b, 0xb5, 0x07, 0xb4, 0x00, 0xfa, 0x5a, 0x9e, 0x48, 0x67, 0x47, 0xad, 0x13, 0x5b, 0xcd, 0xe9, - 0x48, 0xfd, 0x77, 0x90, 0xea, 0xb2, 0x7e, 0xe6, 0x5f, 0x2a, 0x59, 0xc8, 0x70, 0x5e, 0x63, 0xec, 0x99, 0x62, 0xec, - 0x08, 0xf4, 0x34, 0x9b, 0xf8, 0xdd, 0x37, 0x19, 0x2f, 0xcc, 0x48, 0x39, 0x43, 0x62, 0x5f, 0x97, 0xd1, 0x72, 0xe7, - 0xf7, 0xda, 0x6e, 0x44, 0x8c, 0x40, 0x16, 0x10, 0x36, 0x9c, 0x3d, 0x43, 0x38, 0x6f, 0x34, 0xba, 0xf9, 0x31, 0xad, - 0x9c, 0x24, 0x15, 0x8c, 0x0c, 0x02, 0xba, 0x40, 0xf0, 0x35, 0x19, 0x0a, 0x21, 0x7f, 0x9b, 0x99, 0x9d, 0x83, 0xaf, - 0xfd, 0xe4, 0x5d, 0xe0, 0x72, 0x35, 0xb7, 0x6d, 0x19, 0x34, 0x85, 0xf5, 0x04, 0x55, 0xc0, 0xe5, 0xeb, 0xbb, 0x13, - 0x3c, 0x00, 0xee, 0xbd, 0x36, 0x86, 0x54, 0x34, 0xd4, 0x95, 0x9a, 0x25, 0x94, 0xa7, 0xaf, 0x8b, 0xaa, 0xac, 0x44, - 0x77, 0xb2, 0xae, 0xac, 0x8c, 0x59, 0x49, 0xf2, 0xa2, 0xc8, 0x69, 0x15, 0xde, 0x5f, 0x4b, 0xbf, 0x54, 0xc2, 0x65, - 0xd3, 0xdb, 0x7e, 0x3a, 0x27, 0x12, 0x3b, 0x84, 0xfa, 0xf5, 0xae, 0xd8, 0x47, 0x05, 0x26, 0x9c, 0x6b, 0x23, 0x14, - 0x7f, 0xde, 0x26, 0x14, 0x71, 0x66, 0x8e, 0xbc, 0x12, 0x88, 0xed, 0x7b, 0x08, 0x44, 0xe3, 0x66, 0xb7, 0x32, 0x11, - 0xd4, 0x91, 0x9a, 0x4c, 0xac, 0x6f, 0x29, 0xc9, 0x30, 0x33, 0xbb, 0xd1, 0xeb, 0xac, 0x56, 0x6c, 0xd0, 0x02, 0x37, - 0x92, 0xef, 0xc3, 0xcf, 0xb6, 0xfe, 0xe9, 0x70, 0x62, 0xed, 0x06, 0x0e, 0x58, 0x69, 0xb2, 0xa0, 0x10, 0x12, 0x9c, - 0x03, 0x95, 0x94, 0xa5, 0x68, 0xda, 0x50, 0x90, 0x21, 0x70, 0xc2, 0xca, 0x30, 0x13, 0x40, 0xac, 0x64, 0x85, 0x31, - 0x20, 0x83, 0xad, 0xb9, 0x7f, 0xd6, 0xbc, 0xfc, 0xb4, 0x26, 0x5a, 0x93, 0x2b, 0x5a, 0x7d, 0xa8, 0xe5, 0x1b, 0x18, - 0x08, 0x8c, 0x7e, 0xb8, 0xa7, 0x4c, 0xd0, 0x4a, 0x94, 0x23, 0x57, 0x0e, 0xe1, 0x16, 0x38, 0xd1, 0xf6, 0x3e, 0xe8, - 0x08, 0xef, 0x16, 0x69, 0x82, 0xb9, 0x43, 0xd7, 0x2f, 0x89, 0xac, 0xb1, 0x92, 0x29, 0x31, 0x96, 0x12, 0x8e, 0x15, - 0x99, 0x4a, 0x92, 0x0d, 0x5a, 0x43, 0x50, 0x40, 0xbb, 0xe9, 0x71, 0x56, 0x99, 0xc0, 0x69, 0xa3, 0x81, 0x62, 0x3b, - 0xeb, 0x74, 0xc0, 0x1a, 0xe9, 0x10, 0x53, 0x9c, 0x6a, 0xc3, 0xe4, 0xec, 0xe0, 0x20, 0x88, 0xab, 0x79, 0x07, 0xe9, - 0x10, 0x61, 0xbe, 0x5a, 0x05, 0x0a, 0xac, 0x18, 0xad, 0x56, 0xb1, 0x0b, 0x96, 0xaa, 0x86, 0x6e, 0xf3, 0xbe, 0x24, - 0x73, 0x25, 0x00, 0xe7, 0x00, 0x61, 0x83, 0x04, 0xb1, 0x71, 0xef, 0xc5, 0xe0, 0x8e, 0x6a, 0x64, 0x83, 0xb4, 0xd1, - 0x1e, 0x3a, 0x8c, 0x6b, 0x90, 0x0e, 0x49, 0x5c, 0xf0, 0x83, 0x83, 0xbd, 0xdc, 0x88, 0xc8, 0x9f, 0x40, 0x94, 0xfd, - 0xa4, 0x24, 0x8b, 0x1e, 0xd0, 0xdd, 0x8d, 0x75, 0x67, 0x40, 0x49, 0x51, 0x66, 0x5b, 0x6d, 0xbb, 0x5a, 0x16, 0x44, - 0xd9, 0x08, 0x9b, 0x60, 0x70, 0x1f, 0x2c, 0xfb, 0x92, 0xcc, 0x5f, 0xc9, 0x32, 0xc7, 0xfa, 0xe7, 0xad, 0x99, 0xd5, - 0x61, 0x18, 0xc6, 0x62, 0xa2, 0x62, 0x19, 0x36, 0x0c, 0xab, 0x88, 0xff, 0xc8, 0x80, 0xe9, 0x4c, 0x3c, 0x28, 0xe7, - 0x1a, 0x12, 0x0d, 0xbe, 0x55, 0x6d, 0xec, 0x5d, 0x92, 0x9f, 0xb6, 0x7a, 0x19, 0x34, 0x24, 0xcf, 0x7f, 0x2b, 0x24, - 0x0f, 0x0d, 0x24, 0x9a, 0x3c, 0xd6, 0x70, 0xb6, 0x03, 0x17, 0x3f, 0xc9, 0x35, 0x9c, 0xed, 0xc6, 0xad, 0xc5, 0xd4, - 0x2f, 0xbb, 0xe0, 0x73, 0x78, 0x83, 0x06, 0xb4, 0x2a, 0x70, 0xa0, 0x7c, 0xb4, 0xae, 0x7b, 0x69, 0x56, 0x0a, 0xc2, - 0x54, 0x92, 0x80, 0xd5, 0x0f, 0x40, 0xa5, 0x8d, 0x3a, 0x86, 0x2f, 0x8b, 0xe6, 0xc8, 0x71, 0x09, 0xd4, 0x53, 0x57, - 0x80, 0x9c, 0x8c, 0xb7, 0x7d, 0x7e, 0x70, 0x00, 0xb6, 0x01, 0x28, 0x71, 0xe1, 0x28, 0x9e, 0xcb, 0x85, 0x00, 0x55, - 0x2a, 0xb7, 0xbf, 0xa1, 0x18, 0x6e, 0x81, 0xa8, 0x32, 0xf8, 0x01, 0x05, 0xf3, 0x38, 0xcf, 0xd9, 0x95, 0x2e, 0x33, - 0xbf, 0x31, 0x27, 0x96, 0x94, 0x73, 0xad, 0x13, 0x66, 0xa8, 0x9b, 0x19, 0x3a, 0xad, 0xa3, 0xed, 0xc5, 0x15, 0xcd, - 0xe4, 0x2b, 0x96, 0x4b, 0x9a, 0xc1, 0xf2, 0x2b, 0x8a, 0x83, 0x15, 0xe5, 0x08, 0x0e, 0x6c, 0xad, 0x57, 0x9c, 0x24, - 0x77, 0x76, 0x91, 0x75, 0x1d, 0x68, 0x1a, 0x67, 0x49, 0xaa, 0x27, 0x71, 0xf3, 0x19, 0x6d, 0x0e, 0x67, 0xd9, 0xd2, - 0xcd, 0xa7, 0xa9, 0x94, 0x0d, 0xc5, 0xdd, 0x03, 0x46, 0xac, 0x24, 0xb0, 0xd2, 0xf3, 0x4e, 0xad, 0x05, 0x22, 0xde, - 0x3b, 0x36, 0xc1, 0x5d, 0x09, 0x96, 0x0e, 0x47, 0x0d, 0xeb, 0x70, 0x5a, 0xba, 0xf9, 0x72, 0xeb, 0x95, 0xb6, 0x6d, - 0xc2, 0x41, 0xd1, 0xc9, 0xe3, 0xdd, 0x96, 0xd5, 0x6b, 0x2b, 0x39, 0xac, 0xb4, 0x60, 0xf7, 0x65, 0xcc, 0x68, 0x69, - 0xc9, 0x0b, 0xd9, 0xa3, 0xb8, 0x2f, 0xc9, 0x73, 0xb8, 0x33, 0xf4, 0x52, 0xce, 0xd2, 0xb5, 0xab, 0x31, 0xdd, 0xfd, - 0x52, 0xfb, 0xdf, 0x97, 0xc1, 0x4b, 0xfc, 0x1e, 0x02, 0xbb, 0x5f, 0x55, 0xcd, 0x37, 0x03, 0xba, 0x5f, 0x55, 0x08, - 0xfa, 0x2a, 0xda, 0x68, 0xe7, 0x04, 0x72, 0x3b, 0xe1, 0xd3, 0xb0, 0xe5, 0x5b, 0x6d, 0xe9, 0x67, 0x1d, 0x46, 0xd2, - 0x99, 0x96, 0xea, 0x3c, 0xe0, 0x2a, 0x4f, 0x0d, 0xf2, 0xe5, 0xea, 0x16, 0x12, 0x35, 0x19, 0x86, 0x5a, 0x87, 0xdf, - 0xb5, 0x3d, 0x46, 0xc6, 0x64, 0xda, 0xce, 0xf8, 0x3a, 0x16, 0x72, 0x1f, 0x4e, 0x19, 0xdf, 0xb8, 0x87, 0x37, 0x25, - 0xe0, 0x41, 0xbb, 0xdf, 0x14, 0x8e, 0xb1, 0x9d, 0xeb, 0x7b, 0x40, 0xee, 0xf8, 0x84, 0x5b, 0xdd, 0xad, 0x6e, 0x65, - 0x7c, 0x0d, 0xf6, 0x3f, 0xc2, 0x53, 0x7b, 0x39, 0x8e, 0x1a, 0x0e, 0x4c, 0xa3, 0x65, 0x51, 0x3a, 0x05, 0xb8, 0x56, - 0xde, 0x04, 0xc2, 0xbc, 0x50, 0x01, 0xee, 0x1f, 0xf0, 0x37, 0x86, 0x25, 0x8e, 0x4b, 0x8e, 0x73, 0x72, 0x5f, 0x8e, - 0xa8, 0xc1, 0x2f, 0xe3, 0xf7, 0x40, 0xc7, 0x8a, 0x42, 0x0b, 0x4b, 0x45, 0xcf, 0xb9, 0x59, 0xc8, 0xce, 0xb4, 0x54, - 0x4c, 0xcb, 0x94, 0x1a, 0x35, 0xcd, 0x96, 0x3c, 0x4e, 0x6b, 0x65, 0xcb, 0xf2, 0x54, 0xd5, 0xe6, 0x45, 0x3b, 0xb0, - 0x58, 0x85, 0x16, 0x57, 0xab, 0xa0, 0x8e, 0x6a, 0xc2, 0x9c, 0x48, 0x06, 0xc2, 0xcc, 0xc9, 0xa8, 0xa8, 0x69, 0xd6, - 0xba, 0x4f, 0x80, 0xd6, 0x13, 0x8a, 0xac, 0x6e, 0x5e, 0x83, 0xc3, 0x75, 0x21, 0xe8, 0xee, 0xae, 0x4f, 0x01, 0xeb, - 0xd5, 0x95, 0x13, 0x39, 0x18, 0xfa, 0xb9, 0x4c, 0x95, 0xad, 0x72, 0x5a, 0xb7, 0xe0, 0x17, 0xdd, 0x91, 0x2c, 0x6b, - 0x50, 0xb7, 0x59, 0xef, 0x24, 0x1b, 0x3d, 0xe7, 0xbb, 0x92, 0x8d, 0x6a, 0xda, 0xee, 0x5e, 0x0b, 0xdd, 0x9d, 0x96, - 0xaa, 0xe7, 0xda, 0xde, 0xe4, 0x37, 0x4c, 0xd7, 0x06, 0xda, 0xd4, 0x68, 0xb6, 0x5c, 0xe5, 0xac, 0x28, 0xc6, 0xe5, - 0x65, 0x02, 0x95, 0xbb, 0x33, 0xd6, 0xf4, 0x6f, 0xac, 0x46, 0x75, 0x1d, 0x37, 0xf8, 0x81, 0x4c, 0x52, 0x7e, 0x19, - 0xa7, 0xef, 0x61, 0xbe, 0xaa, 0xf2, 0xe5, 0x6d, 0x22, 0x62, 0x49, 0x0d, 0x77, 0xa9, 0x60, 0xf8, 0xc1, 0x81, 0xe1, - 0x07, 0xcd, 0xa7, 0xab, 0xfe, 0x78, 0xf9, 0xaa, 0x1c, 0x20, 0x1a, 0x17, 0x96, 0x65, 0x9c, 0xcb, 0xed, 0x73, 0xac, - 0xb3, 0xb0, 0xf3, 0x92, 0x85, 0x9d, 0xcb, 0x60, 0x7d, 0xa8, 0x20, 0xf8, 0x66, 0xfb, 0x28, 0x9b, 0x9c, 0xed, 0x9b, - 0xea, 0xe0, 0x7f, 0x13, 0xdd, 0xd9, 0xc7, 0xe1, 0x72, 0x47, 0xe1, 0x91, 0x4a, 0x57, 0xd1, 0x20, 0xbf, 0x83, 0xb4, - 0x03, 0x49, 0x7a, 0xce, 0x9d, 0x83, 0x4a, 0x4e, 0xd9, 0x44, 0xa0, 0x60, 0xb4, 0xc8, 0x25, 0x9f, 0x99, 0x31, 0x73, - 0x73, 0xcd, 0x48, 0x55, 0x82, 0x2b, 0x5a, 0x45, 0xdb, 0xa3, 0xfa, 0x45, 0xae, 0xe5, 0x47, 0x96, 0x25, 0x51, 0x8e, - 0x8d, 0x14, 0xc9, 0xa3, 0xac, 0x20, 0x36, 0xd9, 0x78, 0xb3, 0x0e, 0x8f, 0x59, 0xc6, 0xf2, 0x29, 0x15, 0x01, 0x47, - 0xcb, 0x5d, 0x93, 0x71, 0x08, 0xc8, 0xe8, 0xc9, 0xf0, 0xb7, 0xd5, 0x85, 0xbf, 0x10, 0x46, 0x03, 0x3f, 0xd0, 0x8c, - 0xca, 0x29, 0x4f, 0x20, 0x31, 0x25, 0x4c, 0xca, 0x1b, 0x4d, 0x07, 0x07, 0x7b, 0x81, 0xaf, 0xdc, 0x12, 0x70, 0xf5, - 0xdb, 0xad, 0x41, 0xfd, 0x25, 0x5c, 0xcf, 0xa9, 0xa6, 0xa6, 0x68, 0x49, 0xd7, 0x6f, 0xb2, 0xc8, 0xf0, 0x23, 0xbd, - 0xc5, 0x02, 0x15, 0x45, 0xa4, 0xa1, 0xf6, 0xc7, 0x8c, 0xa6, 0x89, 0x8f, 0x3f, 0xd2, 0xdb, 0xa8, 0xbc, 0x2d, 0xae, - 0x2e, 0x37, 0xab, 0x0d, 0xf4, 0xf9, 0x75, 0xe6, 0xe3, 0x6a, 0x92, 0x68, 0x59, 0x60, 0x2e, 0xd8, 0x04, 0x88, 0xf3, - 0x6f, 0xf4, 0x36, 0xd2, 0xe3, 0x31, 0xe7, 0xb2, 0x1e, 0x5a, 0x5a, 0xd4, 0x87, 0x4e, 0xb1, 0xbb, 0x0d, 0xc6, 0xa0, - 0x18, 0xa8, 0xbe, 0x43, 0x52, 0x6b, 0x57, 0x99, 0x87, 0x08, 0x15, 0xf7, 0x5d, 0x0a, 0xfe, 0xc2, 0x15, 0x6d, 0xb2, - 0x96, 0xfa, 0xba, 0xd6, 0x89, 0x42, 0x87, 0x2a, 0xd7, 0xe3, 0x3c, 0x10, 0xf6, 0xd4, 0x99, 0x3b, 0x08, 0x8e, 0x23, - 0xec, 0x0b, 0x69, 0x06, 0x8d, 0xbe, 0xd5, 0x29, 0x21, 0x55, 0x24, 0xe9, 0x75, 0xd5, 0xcf, 0x3b, 0x0f, 0x00, 0xef, - 0x90, 0xd2, 0x12, 0xab, 0xeb, 0x98, 0x85, 0x4d, 0x17, 0xfd, 0x4e, 0x92, 0x60, 0x69, 0x97, 0x10, 0x09, 0x17, 0x8b, - 0xb2, 0x00, 0x2a, 0x34, 0xf4, 0xa5, 0x33, 0x00, 0xd9, 0x38, 0x60, 0x1b, 0x52, 0x33, 0x53, 0x52, 0x33, 0x74, 0x30, - 0xbe, 0x43, 0x4a, 0x52, 0x85, 0x0c, 0xa5, 0x44, 0x2a, 0xa1, 0x67, 0x36, 0xd7, 0x90, 0x90, 0xbb, 0xa1, 0xe5, 0xf5, - 0x39, 0xbd, 0xe7, 0x59, 0x0d, 0xac, 0x40, 0x8d, 0x83, 0x8a, 0x08, 0x96, 0x44, 0x75, 0x83, 0xc2, 0xba, 0x73, 0x84, - 0xcd, 0x6f, 0x0d, 0x78, 0x68, 0x97, 0x45, 0x2c, 0x4a, 0x82, 0x29, 0x5a, 0x8a, 0x60, 0x8a, 0x33, 0xc8, 0x47, 0xe4, - 0x45, 0x09, 0x3f, 0x75, 0x77, 0xa3, 0x96, 0xad, 0xbc, 0xfd, 0x8a, 0x1f, 0x28, 0xf3, 0x12, 0x72, 0x34, 0xb1, 0xb0, - 0x3c, 0x45, 0x04, 0xea, 0xae, 0x9d, 0xb3, 0x6d, 0x5f, 0x99, 0x14, 0x1d, 0x03, 0xd8, 0x77, 0x32, 0x58, 0x3a, 0xab, - 0x70, 0xef, 0x72, 0x9b, 0x2b, 0x7f, 0x26, 0xd8, 0x57, 0x25, 0x91, 0x06, 0x39, 0x59, 0x93, 0x38, 0x77, 0xe7, 0x5a, - 0xfe, 0xbc, 0xa0, 0xe2, 0xf6, 0x8c, 0x42, 0xae, 0x33, 0x87, 0xbb, 0xbe, 0xd5, 0x36, 0x54, 0x79, 0xea, 0xfd, 0x4c, - 0x29, 0x2b, 0x45, 0xfd, 0x12, 0xe0, 0xfa, 0x15, 0xc1, 0x42, 0x45, 0x1b, 0x1d, 0x47, 0x8c, 0x3e, 0x2d, 0x74, 0xe7, - 0xe5, 0x49, 0xda, 0x65, 0xe0, 0x5f, 0xab, 0x30, 0x6d, 0x82, 0x05, 0x98, 0xbb, 0x17, 0x52, 0x07, 0xf9, 0x70, 0xdd, - 0x2b, 0x03, 0x45, 0x10, 0xbe, 0xcb, 0x76, 0x2f, 0x75, 0x5b, 0xd6, 0xec, 0xee, 0xa5, 0xd6, 0x82, 0x7e, 0x2a, 0xe5, - 0x07, 0x9b, 0x79, 0xca, 0xcb, 0xcb, 0xac, 0x28, 0x50, 0x01, 0xe0, 0x7d, 0xdf, 0x0d, 0x82, 0xef, 0x4d, 0xd2, 0x60, - 0x08, 0xb1, 0xd8, 0xb3, 0x94, 0x5b, 0x26, 0x5e, 0xcd, 0xff, 0xfd, 0xc6, 0xfc, 0xdf, 0x3b, 0x57, 0x4e, 0xc1, 0x34, - 0x9a, 0x64, 0x34, 0xb1, 0xac, 0x13, 0x69, 0x02, 0x54, 0x7a, 0x5b, 0x2e, 0xc9, 0xc7, 0x8b, 0x08, 0x34, 0xae, 0xe5, - 0x98, 0x67, 0xb2, 0x39, 0x8e, 0x67, 0x2c, 0xbd, 0x8d, 0x16, 0xac, 0x39, 0xe3, 0x19, 0xcf, 0xe7, 0xf1, 0x88, 0xe2, - 0xfc, 0x36, 0x97, 0x74, 0xd6, 0x5c, 0x30, 0xfc, 0x92, 0xa6, 0x57, 0x54, 0xb2, 0x51, 0x8c, 0xfd, 0x13, 0xc1, 0xe2, - 0xd4, 0x7b, 0x13, 0x0b, 0xc1, 0xaf, 0x7d, 0xfc, 0x8e, 0x5f, 0x72, 0xc9, 0xf1, 0xdb, 0x9b, 0xdb, 0x09, 0xcd, 0xf0, - 0x87, 0xcb, 0x45, 0x26, 0x17, 0x38, 0x8f, 0xb3, 0xbc, 0x99, 0x53, 0xc1, 0xc6, 0xdd, 0x11, 0x4f, 0xb9, 0x68, 0x42, - 0xca, 0xf6, 0x8c, 0x46, 0x29, 0x9b, 0x4c, 0xa5, 0x97, 0xc4, 0xe2, 0x63, 0xb7, 0xd9, 0x9c, 0x0b, 0x36, 0x8b, 0xc5, - 0x6d, 0x53, 0xb5, 0x88, 0x3e, 0x6b, 0x1d, 0xc5, 0x9f, 0x8f, 0x1f, 0x76, 0xa5, 0x88, 0xb3, 0x9c, 0xc1, 0x36, 0x45, - 0x71, 0x9a, 0x7a, 0x47, 0x8f, 0x5a, 0xb3, 0x7c, 0x4f, 0x07, 0xf2, 0xe2, 0x4c, 0x16, 0x17, 0xf8, 0x23, 0xc0, 0x1d, - 0x5e, 0xca, 0x0c, 0x5f, 0x2e, 0xa4, 0xe4, 0xd9, 0x72, 0xb4, 0x10, 0x39, 0x17, 0xd1, 0x9c, 0xb3, 0x4c, 0x52, 0xd1, - 0xbd, 0xe4, 0x22, 0xa1, 0xa2, 0x29, 0xe2, 0x84, 0x2d, 0xf2, 0xe8, 0xe1, 0xfc, 0xa6, 0x0b, 0x9a, 0xc5, 0x44, 0xf0, - 0x45, 0x96, 0x98, 0xb9, 0x58, 0x36, 0xa5, 0x82, 0x49, 0xb7, 0x42, 0xbd, 0xc2, 0x24, 0x4a, 0x59, 0x46, 0x63, 0xd1, - 0x9c, 0x40, 0x67, 0x30, 0x8b, 0x5a, 0x09, 0x9d, 0x60, 0x31, 0xb9, 0x8c, 0x83, 0x76, 0xe7, 0x09, 0xb6, 0x7f, 0xc3, - 0x47, 0xc8, 0x6b, 0x6d, 0x2f, 0x6e, 0xb7, 0x5a, 0x7f, 0x42, 0xdd, 0xb5, 0x59, 0x14, 0x40, 0x51, 0x7b, 0x7e, 0xe3, - 0xe5, 0x1c, 0x72, 0xda, 0xb6, 0xf5, 0xec, 0xce, 0xe3, 0x04, 0x12, 0x82, 0xa3, 0xce, 0xfc, 0xa6, 0x80, 0xd5, 0x45, - 0x3a, 0xc9, 0xd4, 0x2c, 0xd2, 0x3c, 0x2d, 0x7f, 0x2b, 0xc4, 0x4f, 0xb7, 0x43, 0xdc, 0xb1, 0x10, 0x57, 0x58, 0x6f, - 0x26, 0x0b, 0xa1, 0x62, 0xab, 0x51, 0x3b, 0xd7, 0x80, 0x4c, 0xf9, 0x15, 0x15, 0x16, 0x0e, 0xf5, 0xf0, 0x9b, 0xc1, - 0xe8, 0x6c, 0x07, 0xe3, 0xe9, 0xa7, 0xc0, 0x10, 0x59, 0xb2, 0xac, 0xef, 0x6b, 0x5b, 0xd0, 0x59, 0x77, 0x4a, 0x81, - 0x9e, 0xa2, 0x0e, 0xfc, 0xbe, 0x66, 0x89, 0x9c, 0xea, 0x9f, 0x8a, 0x9c, 0xaf, 0x75, 0xdd, 0xa3, 0x56, 0x4b, 0x3f, - 0xe7, 0xec, 0x17, 0x1a, 0xb5, 0x43, 0x68, 0x50, 0x5c, 0xe0, 0xbf, 0x95, 0x97, 0x79, 0xeb, 0xdc, 0x13, 0xff, 0xe0, - 0xde, 0xf2, 0x75, 0x92, 0x14, 0xab, 0x1b, 0xd1, 0x58, 0x58, 0x59, 0xa9, 0x85, 0x0f, 0xb8, 0xed, 0xd4, 0x79, 0x22, - 0xac, 0x57, 0xde, 0xe2, 0x64, 0xfd, 0x1f, 0x74, 0xde, 0x45, 0x04, 0x91, 0x0e, 0x27, 0xd9, 0x90, 0x77, 0xb3, 0x1e, - 0x69, 0x75, 0xb3, 0x66, 0x13, 0x05, 0x9c, 0x88, 0x41, 0x66, 0xd2, 0xf3, 0x02, 0xd6, 0xe7, 0xca, 0xd8, 0xce, 0x51, - 0xc4, 0xe1, 0xaa, 0xe9, 0x6a, 0x55, 0x85, 0x01, 0x98, 0xba, 0xae, 0xf1, 0x37, 0x69, 0x1a, 0xe0, 0xdc, 0xe1, 0xe4, - 0x99, 0x7d, 0xb1, 0x8b, 0xb0, 0xbc, 0x22, 0xe5, 0x23, 0x85, 0xb9, 0x70, 0x1e, 0xcb, 0x29, 0x78, 0x29, 0x4a, 0xf1, - 0x53, 0x25, 0x31, 0xf9, 0x87, 0x3e, 0xea, 0x8b, 0x32, 0xc3, 0x0d, 0x32, 0xf9, 0x44, 0x01, 0xa3, 0x7c, 0x23, 0x09, - 0x8c, 0x88, 0x7f, 0x21, 0xda, 0xa6, 0xb3, 0x16, 0xdd, 0xf8, 0xbe, 0x16, 0x1d, 0xcd, 0x24, 0x53, 0xb9, 0xdb, 0x36, - 0xe2, 0x30, 0x8d, 0xf3, 0xf3, 0x91, 0xbe, 0x2b, 0x99, 0x57, 0x37, 0x03, 0x62, 0x05, 0xbd, 0x36, 0xd2, 0xa8, 0x50, - 0xf6, 0xe8, 0xf7, 0x72, 0xa7, 0x7d, 0x22, 0xee, 0xb2, 0x4f, 0xca, 0x85, 0xe7, 0x7c, 0x21, 0x46, 0x10, 0x8e, 0x34, - 0x52, 0x6f, 0xd3, 0x71, 0xe3, 0x2b, 0x15, 0xc3, 0xc7, 0xd2, 0xc9, 0x04, 0x95, 0x98, 0xb9, 0x2f, 0x95, 0xa0, 0x2a, - 0xe4, 0xa5, 0xef, 0x6b, 0x18, 0x11, 0x67, 0x97, 0x04, 0x32, 0x3b, 0x51, 0x49, 0x8d, 0x41, 0x46, 0x7a, 0x59, 0xb8, - 0xc8, 0xd8, 0xcf, 0x0b, 0x7a, 0xce, 0x40, 0xd7, 0x64, 0x21, 0x4b, 0x54, 0xac, 0x09, 0x64, 0x5f, 0xb3, 0x0d, 0xc1, - 0x0b, 0x96, 0xe8, 0x8d, 0xc9, 0x54, 0xa5, 0xc9, 0x6d, 0xf2, 0x9b, 0x3e, 0xf8, 0x8b, 0x41, 0x3b, 0x60, 0x38, 0xe1, - 0xb3, 0x98, 0x65, 0x91, 0x72, 0xf9, 0x96, 0x83, 0x45, 0xd0, 0x1a, 0xb3, 0x24, 0xca, 0xcc, 0xf6, 0xb4, 0x51, 0xf8, - 0x13, 0x67, 0x99, 0xea, 0x5a, 0x74, 0xb9, 0x42, 0xa8, 0x46, 0x1f, 0xb1, 0x08, 0x3e, 0xd1, 0x72, 0x8d, 0x23, 0xec, - 0x56, 0x97, 0xd7, 0xce, 0x6b, 0x3b, 0xd0, 0x5a, 0xdb, 0x28, 0x6d, 0x04, 0xf0, 0xf5, 0xd2, 0x9c, 0x0b, 0x19, 0x04, - 0x53, 0x9c, 0x22, 0xd2, 0x9b, 0x2a, 0x67, 0xd7, 0x71, 0xaa, 0xfe, 0xeb, 0x37, 0xdb, 0x51, 0xbb, 0x34, 0xdf, 0x6b, - 0xb7, 0x81, 0x75, 0x72, 0x94, 0xb9, 0x51, 0xaa, 0x96, 0x51, 0xfe, 0xd6, 0x4b, 0xad, 0x9e, 0xcb, 0xe5, 0x62, 0x73, - 0xdc, 0xb4, 0xa8, 0x0a, 0x6a, 0x40, 0xa8, 0x60, 0xd1, 0x8e, 0xa9, 0x50, 0x51, 0xad, 0xbb, 0x54, 0x25, 0x2f, 0xb4, - 0x88, 0x3e, 0xdf, 0x5f, 0x0a, 0x33, 0x63, 0x71, 0xc1, 0xac, 0x93, 0xa9, 0x4e, 0x72, 0x85, 0xc1, 0x88, 0xa3, 0x87, - 0x6e, 0x6b, 0xa6, 0x61, 0xb9, 0x25, 0x62, 0x2b, 0xdd, 0x86, 0xfa, 0x91, 0x0a, 0x52, 0x85, 0xbb, 0x36, 0x06, 0x80, - 0x5c, 0xbd, 0x6d, 0x80, 0x81, 0xd9, 0x9a, 0x4b, 0xbb, 0x04, 0xd0, 0xc6, 0xc6, 0x14, 0x2e, 0xd2, 0x5c, 0xec, 0x2f, - 0xbf, 0x91, 0xc5, 0xa1, 0xd3, 0x54, 0xfd, 0x66, 0x09, 0xfc, 0x0f, 0x12, 0x70, 0xa9, 0x95, 0xd2, 0xc8, 0xff, 0xfa, - 0xed, 0xd9, 0x7b, 0x1f, 0x5f, 0xf2, 0xe4, 0x36, 0xf2, 0xa5, 0x58, 0x50, 0xbf, 0x40, 0xa1, 0x9c, 0xd2, 0xac, 0x7c, - 0x19, 0x0f, 0x4f, 0x69, 0x98, 0xf2, 0x89, 0xbe, 0x94, 0xb9, 0x6e, 0x24, 0x8f, 0x2e, 0x8e, 0xd5, 0x4b, 0xa6, 0x7a, - 0xc7, 0x52, 0xbf, 0xde, 0x4b, 0x0a, 0xf8, 0xd9, 0x83, 0x10, 0xca, 0xf1, 0xa1, 0x9c, 0xaa, 0x87, 0x33, 0x38, 0x30, - 0xea, 0x69, 0x7f, 0xb9, 0x41, 0x4c, 0x7d, 0x18, 0x62, 0xda, 0xd3, 0x4b, 0xc8, 0x55, 0xab, 0x8b, 0x68, 0x74, 0x71, - 0x51, 0x1c, 0x1f, 0xc2, 0x58, 0x87, 0x76, 0x5c, 0x80, 0xd0, 0xf6, 0x2f, 0x09, 0x0c, 0x5e, 0x36, 0x24, 0x48, 0x0f, - 0x86, 0x80, 0x79, 0x93, 0x1e, 0x2c, 0x12, 0x08, 0x0c, 0x7a, 0x27, 0x65, 0x89, 0x3a, 0xb1, 0xba, 0x68, 0x17, 0x04, - 0xba, 0x61, 0x45, 0xf7, 0xda, 0x9b, 0x5a, 0xed, 0xaf, 0x05, 0x29, 0x71, 0xa1, 0xbb, 0x40, 0xf0, 0xbf, 0x82, 0xec, - 0xf8, 0x50, 0xe3, 0xe1, 0xc2, 0x7d, 0xb5, 0x89, 0x7e, 0xed, 0x40, 0x89, 0xad, 0x41, 0x2e, 0xf1, 0x47, 0x89, 0x3f, - 0x5e, 0xa8, 0xa6, 0x56, 0x18, 0x81, 0x96, 0x04, 0x42, 0xbb, 0x65, 0xb5, 0x8e, 0x11, 0x4f, 0xd3, 0x78, 0x9e, 0xd3, - 0xc8, 0xfe, 0x30, 0x72, 0x09, 0xc4, 0xdb, 0xa6, 0x22, 0x60, 0xd2, 0x6b, 0x4e, 0x41, 0x5d, 0xd8, 0xd4, 0x52, 0xae, - 0x62, 0x11, 0x34, 0x9b, 0xa3, 0xe6, 0xe5, 0x04, 0x15, 0x72, 0xba, 0x74, 0xa5, 0xda, 0xe3, 0x56, 0xab, 0x0b, 0xb9, - 0x90, 0xcd, 0x38, 0x65, 0x93, 0x2c, 0x4a, 0xe9, 0x58, 0x16, 0x12, 0x6e, 0xa9, 0x2d, 0xad, 0x1a, 0x11, 0x76, 0x1e, - 0x09, 0x3a, 0xf3, 0x42, 0xf8, 0xf7, 0xee, 0x89, 0x0b, 0x99, 0x44, 0x99, 0x9c, 0x36, 0x55, 0xd6, 0x2d, 0xdc, 0x19, - 0x90, 0xd3, 0xda, 0xf3, 0xd2, 0x99, 0x68, 0x44, 0x41, 0xc5, 0x2a, 0xa4, 0xf0, 0xe4, 0x14, 0x4b, 0xe1, 0xb6, 0xcb, - 0xd0, 0x72, 0x63, 0x05, 0x9b, 0x92, 0xfe, 0x08, 0x15, 0xb9, 0x52, 0x8c, 0x37, 0x1b, 0x5b, 0x75, 0xa9, 0xfe, 0xb4, - 0x81, 0x3e, 0x47, 0xb1, 0x2b, 0xb4, 0x63, 0x79, 0xa9, 0x7b, 0xdc, 0x07, 0x99, 0x35, 0x95, 0x13, 0xbb, 0x3d, 0x50, - 0xc1, 0xb2, 0xf9, 0x42, 0x0e, 0x94, 0x53, 0x5b, 0xc0, 0x05, 0x89, 0x21, 0x76, 0x4a, 0x00, 0x07, 0xc3, 0xa5, 0x06, - 0x66, 0x14, 0xa7, 0xa3, 0x00, 0x20, 0xf2, 0x9a, 0xde, 0x53, 0x41, 0x67, 0xa8, 0x3b, 0x63, 0x59, 0x53, 0xd7, 0x3d, - 0x72, 0xd4, 0x92, 0xf0, 0x09, 0x3c, 0x15, 0xa1, 0x1a, 0x0d, 0xab, 0xdc, 0xd5, 0x2d, 0xb8, 0xbc, 0x18, 0x16, 0x45, - 0x57, 0xc8, 0x60, 0xf0, 0x3a, 0x40, 0x43, 0xfc, 0x8b, 0xf3, 0x72, 0x16, 0xdf, 0x1e, 0x15, 0x1f, 0x77, 0xd0, 0x8e, - 0x26, 0xee, 0x59, 0x50, 0xcd, 0x7e, 0x21, 0xd0, 0xf0, 0x5d, 0xe0, 0xd3, 0x7c, 0xde, 0xd4, 0xbc, 0xab, 0xa9, 0x48, - 0xd6, 0x87, 0xae, 0xc8, 0x78, 0x6a, 0xbf, 0x97, 0x4b, 0xc5, 0x96, 0xcc, 0x25, 0x0d, 0xed, 0x4c, 0x18, 0x96, 0x97, - 0x7a, 0xcc, 0xb3, 0x7b, 0x8d, 0x07, 0xd5, 0xf8, 0xc9, 0xc5, 0x49, 0x9d, 0xc7, 0x01, 0x5f, 0x2a, 0x5f, 0x60, 0x17, - 0xa7, 0x29, 0x4c, 0x78, 0x61, 0xd5, 0x17, 0xf7, 0xa5, 0x1f, 0x03, 0x39, 0x0c, 0x50, 0x61, 0xce, 0xe9, 0x33, 0xa5, - 0x52, 0x3a, 0x6f, 0xcd, 0xdb, 0x93, 0x36, 0x58, 0xa4, 0xa5, 0x2f, 0x83, 0x70, 0x77, 0x2d, 0x2f, 0xba, 0x5b, 0xf1, - 0x2e, 0xad, 0x90, 0x7a, 0x6a, 0x41, 0xc4, 0x17, 0x59, 0xe2, 0x7b, 0x7f, 0x19, 0xa5, 0x6c, 0xf4, 0x91, 0xf8, 0xfb, - 0xcb, 0x00, 0x6d, 0x5e, 0x7b, 0x54, 0x5c, 0xc1, 0x32, 0x6c, 0x54, 0x77, 0xa4, 0x67, 0xa1, 0xc3, 0x8b, 0xf5, 0x5b, - 0x71, 0xfc, 0xde, 0xfe, 0x12, 0x18, 0x8f, 0x9e, 0xa7, 0x77, 0x51, 0x9c, 0x57, 0xef, 0xba, 0xaa, 0xa0, 0x00, 0x34, - 0xeb, 0x72, 0x4f, 0x11, 0x15, 0xf1, 0x3f, 0x49, 0x69, 0xbe, 0xa7, 0x99, 0x1a, 0xc0, 0x29, 0x0d, 0x7f, 0xf3, 0xbd, - 0xbf, 0x94, 0x65, 0xb4, 0xf4, 0x68, 0xa8, 0x94, 0x0c, 0xe2, 0xc3, 0x5c, 0x60, 0xc6, 0x86, 0x09, 0x95, 0x31, 0x4b, - 0x75, 0x97, 0xae, 0x35, 0xc0, 0xd7, 0x56, 0xb4, 0x5a, 0xe5, 0xf5, 0xb5, 0xb0, 0x3a, 0x06, 0xd5, 0xca, 0x8e, 0x0f, - 0x2b, 0xb8, 0xd5, 0xca, 0xd4, 0x99, 0x74, 0x43, 0x83, 0xd5, 0x0a, 0x75, 0x9d, 0xf7, 0x97, 0x91, 0xba, 0x36, 0x04, - 0x00, 0x72, 0x03, 0x20, 0x04, 0xad, 0xf5, 0xb5, 0x98, 0x20, 0x25, 0x3c, 0x94, 0xb1, 0x98, 0x50, 0xb9, 0x86, 0xd8, - 0x54, 0xe7, 0xa8, 0x76, 0x6d, 0x80, 0x7a, 0x03, 0xda, 0xb8, 0x0e, 0xed, 0x05, 0x20, 0xbd, 0xbf, 0xbf, 0x64, 0x05, - 0xd9, 0x5f, 0xd2, 0x6c, 0xc4, 0x13, 0xfa, 0xe1, 0xdd, 0x97, 0x70, 0xc9, 0x91, 0x67, 0x60, 0x58, 0x4c, 0x11, 0x08, - 0x4e, 0xb5, 0x39, 0x5a, 0x84, 0x70, 0x25, 0x42, 0x34, 0x27, 0xf0, 0xd4, 0x5c, 0x0a, 0xc4, 0xc2, 0xf7, 0xfa, 0x1a, - 0x72, 0x9a, 0x68, 0x98, 0x49, 0xa6, 0x7a, 0xf1, 0xe2, 0xf8, 0x50, 0xb7, 0xd6, 0x22, 0x40, 0x37, 0x02, 0x24, 0xa8, - 0x73, 0x5a, 0xe1, 0x00, 0xf2, 0x9a, 0x5d, 0x3c, 0x24, 0xec, 0xaa, 0x24, 0x36, 0x75, 0x81, 0xaa, 0x77, 0x9c, 0xc6, - 0x97, 0x34, 0xed, 0xed, 0x2f, 0xb3, 0xd5, 0xaa, 0x55, 0x1c, 0x1f, 0xea, 0x47, 0xef, 0x58, 0xf1, 0x0d, 0xfd, 0xc2, - 0x4b, 0xb5, 0xc5, 0x70, 0x2b, 0x11, 0xb2, 0x3d, 0x6d, 0x9a, 0x53, 0x64, 0x06, 0x28, 0x7c, 0x4f, 0x25, 0x58, 0xa8, - 0x46, 0xa5, 0x42, 0x54, 0xf8, 0x1e, 0x4b, 0x36, 0xcb, 0x72, 0x49, 0xe7, 0x50, 0x3a, 0x5d, 0xad, 0xda, 0x85, 0xef, - 0xcd, 0x58, 0x06, 0x4f, 0xd9, 0x6a, 0xa5, 0x2e, 0xfc, 0xcd, 0x58, 0x16, 0xb4, 0x80, 0x6c, 0x7d, 0x6f, 0x16, 0xdf, - 0xa8, 0x05, 0xdb, 0x9a, 0xf8, 0x26, 0x68, 0x9b, 0xaa, 0xb0, 0xc4, 0x4f, 0x0e, 0x14, 0x57, 0xed, 0x68, 0x6a, 0x76, - 0x34, 0xc1, 0x0b, 0x7d, 0x95, 0x89, 0x04, 0x09, 0x49, 0xb7, 0xef, 0x68, 0x62, 0x77, 0x74, 0xb1, 0x63, 0x47, 0x17, - 0x77, 0xec, 0x68, 0x6c, 0x76, 0xcf, 0x2b, 0x71, 0xc7, 0x57, 0xab, 0x76, 0xab, 0xc2, 0xde, 0xf1, 0x61, 0xc2, 0xae, - 0x60, 0x37, 0x40, 0xcd, 0x93, 0x6c, 0x46, 0xb7, 0x13, 0x65, 0x1d, 0xc5, 0xf4, 0x57, 0x61, 0xb2, 0x44, 0x42, 0x56, - 0x47, 0x82, 0x4b, 0xd6, 0x65, 0xc8, 0xed, 0x8f, 0x24, 0x6c, 0x06, 0x68, 0xc8, 0x01, 0x0d, 0x53, 0x83, 0x86, 0x8b, - 0xe2, 0x1c, 0x24, 0x82, 0x5a, 0xcd, 0xbd, 0x28, 0x0f, 0x5a, 0xfb, 0xbd, 0xdd, 0x14, 0x06, 0xc1, 0xf0, 0x6b, 0x2e, - 0x12, 0x3f, 0xd2, 0x4d, 0x7f, 0x15, 0x62, 0x66, 0x2c, 0x33, 0xa9, 0x55, 0x3b, 0x29, 0xab, 0xaa, 0x77, 0xe9, 0xab, - 0xf3, 0xe8, 0x91, 0x6e, 0x31, 0x8f, 0xa5, 0xa4, 0x22, 0x33, 0x74, 0xea, 0xfb, 0x2e, 0xb6, 0xff, 0x7f, 0x91, 0xdc, - 0x16, 0x26, 0x12, 0x5b, 0x26, 0x62, 0xa9, 0xcd, 0x68, 0xe7, 0x86, 0xc1, 0x6b, 0x59, 0xb4, 0x57, 0xa9, 0xab, 0xb7, - 0xc8, 0xb5, 0x10, 0x74, 0x11, 0x18, 0x2c, 0x8b, 0x19, 0x4d, 0xce, 0x15, 0x37, 0xee, 0x8f, 0x2e, 0x8c, 0x76, 0xba, - 0x26, 0xdb, 0xaa, 0x0e, 0xd8, 0xff, 0x71, 0xd1, 0x79, 0xf2, 0xf0, 0xd4, 0xc7, 0x9a, 0xa1, 0xf3, 0xf1, 0xd8, 0x47, - 0x85, 0x77, 0xbf, 0x6e, 0xed, 0x87, 0x3f, 0x2e, 0xbe, 0x78, 0xd1, 0xfa, 0xa2, 0xec, 0x9c, 0xf9, 0xa8, 0xb8, 0x30, - 0xc1, 0x7c, 0x2b, 0x97, 0x1c, 0x78, 0xed, 0x8a, 0xc6, 0x71, 0xb6, 0x7b, 0x39, 0x03, 0x77, 0x39, 0xf9, 0x9c, 0xd2, - 0x04, 0xfb, 0x9e, 0x8f, 0x37, 0x4a, 0xcf, 0x53, 0x7a, 0x45, 0xed, 0x6b, 0x06, 0xb7, 0x4c, 0xb6, 0xa5, 0xc7, 0x88, - 0x2f, 0x32, 0x69, 0xb2, 0x1a, 0x0c, 0x5f, 0x75, 0x96, 0x74, 0xa1, 0xd6, 0xe0, 0x1a, 0x04, 0xb7, 0x5a, 0xa8, 0xd5, - 0x45, 0x55, 0x71, 0x81, 0x7d, 0x07, 0x80, 0x9d, 0x90, 0xf5, 0x77, 0x94, 0x47, 0x2d, 0xdc, 0xda, 0x05, 0x1b, 0x6e, - 0xa3, 0xc8, 0xf7, 0x87, 0x16, 0x4f, 0xca, 0x31, 0x59, 0x7b, 0x3b, 0xc4, 0x4e, 0x7c, 0x7d, 0x12, 0x03, 0x97, 0x02, - 0x06, 0xcb, 0x68, 0x9e, 0xef, 0x44, 0x40, 0xb9, 0x89, 0xd8, 0xaf, 0x5a, 0xfb, 0x3b, 0x46, 0xc1, 0x2d, 0x0c, 0x07, - 0x4c, 0x01, 0x5c, 0x86, 0x47, 0x4d, 0x2b, 0x3a, 0x1e, 0xd3, 0x51, 0xe9, 0xd7, 0x85, 0x40, 0xd7, 0x98, 0xa5, 0x12, - 0xe2, 0x3d, 0x2a, 0x10, 0xe3, 0xbf, 0xe1, 0x19, 0xf5, 0x91, 0x4d, 0xdd, 0x34, 0xf0, 0x1b, 0x61, 0xbf, 0x1d, 0x1e, - 0x3d, 0x62, 0x1d, 0x16, 0x33, 0xcb, 0x6a, 0x65, 0x7d, 0x3a, 0xb5, 0xf2, 0x3a, 0x22, 0xb9, 0x72, 0xda, 0xec, 0x3a, - 0x40, 0xf7, 0x3b, 0x26, 0xcb, 0xf6, 0x17, 0x8f, 0xda, 0xad, 0xc2, 0xc7, 0x3e, 0x0c, 0x77, 0xdf, 0x53, 0xa2, 0x7a, - 0x1d, 0x41, 0xaf, 0x45, 0xf6, 0x6b, 0xfa, 0x75, 0xda, 0x9f, 0xb7, 0x7d, 0xac, 0xdf, 0x1a, 0x80, 0x8a, 0x92, 0x19, - 0x8c, 0xc0, 0xd3, 0xf9, 0xbb, 0x97, 0x52, 0x1f, 0xfc, 0x7e, 0xf0, 0x3c, 0x6e, 0xb7, 0x7c, 0xec, 0xe7, 0x92, 0xcf, - 0x7f, 0xc5, 0x12, 0x8e, 0x7c, 0xec, 0x8f, 0x52, 0x9e, 0x53, 0x77, 0x0d, 0x5a, 0x77, 0xfd, 0xfd, 0x8b, 0xd0, 0x10, - 0xcd, 0x05, 0xcd, 0x73, 0xcf, 0x1d, 0xdf, 0x90, 0xd2, 0x27, 0x18, 0xe6, 0x56, 0x8a, 0xcb, 0xa9, 0x54, 0x78, 0xd1, - 0x17, 0xfa, 0x5d, 0xaa, 0xd2, 0x65, 0x1b, 0xc4, 0xa6, 0x44, 0x40, 0xc9, 0xd8, 0xb4, 0x2a, 0xf5, 0xc9, 0x99, 0xb7, - 0x1c, 0x3d, 0x3d, 0xb1, 0x0e, 0x00, 0x6f, 0x4e, 0x50, 0x2b, 0x99, 0xb1, 0xec, 0x7c, 0x4b, 0x69, 0x7c, 0xb3, 0xa5, - 0x14, 0xf4, 0xb3, 0x12, 0x3a, 0xf3, 0xae, 0x99, 0x4f, 0x63, 0xbd, 0xd2, 0x72, 0x5c, 0x10, 0x13, 0xe5, 0xa4, 0xfc, - 0x04, 0xa4, 0xce, 0x36, 0xa8, 0x11, 0x7e, 0xfb, 0x74, 0x50, 0xf2, 0xab, 0xa6, 0xa3, 0x37, 0x9f, 0xde, 0x73, 0x47, - 0xaf, 0xf9, 0x1d, 0xd8, 0x37, 0xf7, 0xc6, 0xd7, 0xd1, 0xbf, 0xa5, 0xd8, 0xa8, 0x1e, 0xe5, 0x16, 0x8c, 0x52, 0x36, - 0xab, 0x76, 0x61, 0x13, 0x4c, 0xa5, 0x74, 0x40, 0xf2, 0x90, 0x3b, 0x88, 0xd6, 0x3e, 0xce, 0xe1, 0x4a, 0x24, 0xbc, - 0x77, 0x62, 0x21, 0xe8, 0x79, 0xca, 0xaf, 0xd7, 0xdf, 0xa3, 0xb5, 0xbb, 0xf1, 0x94, 0x4d, 0xa6, 0xce, 0x3d, 0x27, - 0x4a, 0x4a, 0xd4, 0xdf, 0x39, 0x41, 0xf1, 0xaf, 0xff, 0x12, 0x86, 0xff, 0xfa, 0x2f, 0x9f, 0x6c, 0x0a, 0xc3, 0x17, - 0x17, 0x58, 0x56, 0xc3, 0xee, 0x26, 0xf0, 0xed, 0x33, 0xd5, 0x71, 0xbe, 0xbd, 0xcd, 0xc6, 0x26, 0x40, 0xfd, 0xc6, - 0x16, 0x6c, 0x14, 0xea, 0x03, 0xe0, 0xfd, 0x16, 0xc0, 0x60, 0x5d, 0x9f, 0x84, 0x0c, 0x1a, 0xfd, 0x2e, 0xd0, 0x2e, - 0x50, 0x74, 0xaf, 0x1d, 0xf9, 0xed, 0x18, 0xfe, 0xd4, 0x1a, 0x7e, 0x27, 0xf8, 0xc6, 0x1f, 0x30, 0xba, 0xb8, 0x28, - 0x13, 0xda, 0xdc, 0xae, 0x70, 0x61, 0xbe, 0xbf, 0x51, 0x62, 0x64, 0x7f, 0xd4, 0x42, 0x3d, 0x75, 0x1d, 0x8f, 0x8c, - 0x2e, 0x5e, 0xc3, 0x5b, 0x72, 0x8e, 0x2f, 0x85, 0x75, 0xa8, 0xde, 0xc1, 0x9f, 0x61, 0x88, 0xfa, 0xaa, 0xd4, 0xa0, - 0x1b, 0xcc, 0x19, 0x4a, 0x41, 0xe1, 0x07, 0x30, 0xf1, 0xe8, 0xc2, 0x58, 0x77, 0xa7, 0xda, 0xed, 0x11, 0xad, 0x93, - 0xb6, 0x71, 0x87, 0xd4, 0x90, 0x8e, 0xbd, 0xf7, 0x0a, 0x5f, 0xaa, 0x31, 0xad, 0xac, 0x69, 0xe5, 0x5a, 0x02, 0x55, - 0xfe, 0xa2, 0x50, 0x61, 0xf1, 0xbf, 0xee, 0x8a, 0xdc, 0xfd, 0xfd, 0xd3, 0x91, 0x3b, 0x7e, 0xaf, 0xc8, 0xdd, 0xdf, - 0xff, 0xf0, 0xc8, 0xdd, 0x5f, 0xdd, 0xc8, 0x1d, 0x6c, 0xe2, 0x97, 0xf7, 0x8a, 0xae, 0xd9, 0xc8, 0x07, 0xbf, 0xce, - 0x49, 0xdb, 0x68, 0xb2, 0x29, 0x9f, 0x40, 0x68, 0xed, 0xdf, 0x3f, 0x52, 0x96, 0xf2, 0x89, 0x1b, 0x27, 0x83, 0xb7, - 0xa4, 0x42, 0x60, 0xac, 0x6b, 0x23, 0x5a, 0x26, 0x36, 0xd5, 0x2a, 0x6f, 0x80, 0x34, 0x1f, 0xda, 0x37, 0x16, 0xf8, - 0x51, 0xf9, 0xd6, 0xa1, 0x16, 0xee, 0xd8, 0xe8, 0x55, 0xa4, 0x02, 0x5f, 0x65, 0xc7, 0x4e, 0xc3, 0x5e, 0x6f, 0x70, - 0x47, 0xe8, 0xda, 0xb7, 0xaa, 0xe8, 0xdb, 0xee, 0x4b, 0xff, 0xc7, 0x9b, 0xf6, 0xb3, 0x41, 0xbb, 0x7b, 0xd4, 0x9e, - 0xf9, 0x91, 0x0f, 0x52, 0x4a, 0x15, 0xb4, 0xba, 0x47, 0x47, 0x50, 0x70, 0xed, 0x14, 0x74, 0xa0, 0x80, 0x39, 0x05, - 0x8f, 0xa0, 0x60, 0xe4, 0x14, 0x3c, 0x86, 0x82, 0xc4, 0x29, 0x78, 0x02, 0x05, 0x57, 0x7e, 0x31, 0x60, 0x25, 0xb8, - 0x4f, 0xd0, 0x10, 0x6b, 0xe3, 0xc1, 0x96, 0x3d, 0xc1, 0x6d, 0x08, 0x99, 0xc5, 0x13, 0x95, 0xe9, 0x03, 0x0e, 0xb8, - 0x88, 0xe3, 0xeb, 0x29, 0xcd, 0x22, 0x08, 0x5a, 0x3e, 0x57, 0x32, 0x26, 0x94, 0xfc, 0x3d, 0x9b, 0x51, 0xfb, 0x7d, - 0x0a, 0x8b, 0x07, 0xcf, 0x47, 0x83, 0xd6, 0xb0, 0xe8, 0x96, 0x3b, 0xa7, 0x63, 0x6d, 0x26, 0xeb, 0x43, 0xef, 0x65, - 0x55, 0xa7, 0xa7, 0x6b, 0x96, 0x7b, 0xbe, 0x23, 0x66, 0xe3, 0x78, 0x03, 0xc6, 0x29, 0xbf, 0x6e, 0xde, 0xf8, 0xbd, - 0xed, 0x71, 0x1c, 0x80, 0xa8, 0x8c, 0xe3, 0xa8, 0x35, 0x95, 0x4f, 0xef, 0xe3, 0x49, 0xf9, 0xfb, 0x35, 0xcd, 0xf3, - 0x78, 0x62, 0x5a, 0xee, 0x8e, 0xdb, 0x28, 0x10, 0xdd, 0x98, 0x8d, 0x05, 0x02, 0x62, 0x2f, 0xb0, 0x59, 0x60, 0x4e, - 0x9b, 0x50, 0x0c, 0x60, 0xa7, 0x1e, 0xc5, 0x51, 0xd3, 0xd7, 0x8b, 0x64, 0x3c, 0xa9, 0x0a, 0x8e, 0xe7, 0x82, 0xaa, - 0x52, 0x8d, 0xe1, 0xe2, 0xf8, 0x10, 0x0a, 0x74, 0xf5, 0x8e, 0x68, 0x8d, 0xb5, 0xdd, 0x77, 0xc7, 0x6c, 0x3c, 0x1b, - 0xad, 0x71, 0xf3, 0x5b, 0xca, 0xe4, 0x96, 0xcd, 0x18, 0xc1, 0x67, 0xed, 0x11, 0xfc, 0x31, 0x11, 0x88, 0xcf, 0xc6, - 0xe3, 0xf1, 0x9d, 0xd1, 0x9b, 0xcf, 0x92, 0x31, 0xed, 0xd0, 0x47, 0x5d, 0xc8, 0x7d, 0x68, 0x1a, 0x9f, 0x7f, 0xbb, - 0x50, 0xb8, 0x5b, 0xde, 0xaf, 0x31, 0x84, 0x07, 0xe4, 0x74, 0x79, 0xff, 0x48, 0x4e, 0x31, 0x17, 0x74, 0x39, 0x8b, - 0xc5, 0x84, 0x65, 0x51, 0xab, 0x08, 0xaf, 0x4c, 0xe8, 0xe3, 0xb3, 0xa7, 0x4f, 0x9f, 0x16, 0x61, 0x62, 0x9f, 0x5a, - 0x49, 0x52, 0x84, 0xa3, 0x65, 0xb9, 0x8c, 0x56, 0x6b, 0x3c, 0x2e, 0x42, 0x66, 0x0b, 0x8e, 0x3a, 0xa3, 0xe4, 0xa8, - 0x53, 0x84, 0xd7, 0x4e, 0x8b, 0x22, 0xa4, 0xe6, 0x49, 0xd0, 0xa4, 0x96, 0x40, 0xf1, 0xa4, 0xd5, 0x2a, 0x42, 0x4d, - 0x68, 0x4b, 0xb0, 0x88, 0xf4, 0xcf, 0x28, 0x5e, 0x48, 0x0e, 0x2c, 0xb9, 0xcb, 0x65, 0x30, 0x38, 0x37, 0x2f, 0xa7, - 0xd0, 0x1f, 0x72, 0x28, 0xd0, 0x10, 0x7f, 0xe9, 0x06, 0x29, 0x80, 0x98, 0x55, 0x70, 0x82, 0xdb, 0x18, 0x46, 0xad, - 0x1a, 0x28, 0x4b, 0x55, 0x7f, 0x49, 0x78, 0x15, 0xbb, 0x00, 0xfe, 0x03, 0x2d, 0xf5, 0x5b, 0xd4, 0x24, 0xdd, 0xc1, - 0xf5, 0x29, 0xfd, 0x24, 0xd7, 0xbf, 0xbd, 0x0f, 0xd3, 0xa7, 0xf4, 0x8f, 0x66, 0xfa, 0xe6, 0x55, 0xa3, 0x9a, 0xe9, - 0x6b, 0xb6, 0x36, 0x93, 0xc4, 0x1f, 0x4d, 0xe9, 0xe8, 0xe3, 0x25, 0xbf, 0x69, 0xc2, 0x91, 0x10, 0xbe, 0xe2, 0xa7, - 0xfb, 0xbf, 0x35, 0xd9, 0xc2, 0x0e, 0xe6, 0x7c, 0x07, 0x42, 0x89, 0xcd, 0xb7, 0x19, 0xf1, 0xdf, 0x5a, 0xb3, 0x4a, - 0x97, 0x8c, 0xc7, 0xc4, 0x7f, 0x3b, 0x1e, 0xfb, 0xf6, 0x8a, 0x5d, 0x2c, 0xa9, 0x6a, 0xf5, 0xa6, 0x56, 0xa2, 0x5a, - 0x7d, 0xf1, 0x85, 0x5b, 0xe6, 0x16, 0x98, 0x10, 0x87, 0x1b, 0xce, 0x30, 0x35, 0x09, 0xcb, 0xe1, 0xa8, 0xc1, 0xe7, - 0x29, 0xea, 0xef, 0xf8, 0x13, 0xb5, 0xd7, 0x31, 0x97, 0x00, 0x6f, 0x79, 0x87, 0xf4, 0xfa, 0xfd, 0xf2, 0x09, 0xb5, - 0xe9, 0x6e, 0xcf, 0x6e, 0xbf, 0x4c, 0x82, 0x99, 0x44, 0x05, 0xcb, 0xdf, 0x66, 0x6b, 0x77, 0x47, 0x34, 0x8c, 0x84, - 0xb8, 0xcb, 0x2a, 0x24, 0x9f, 0x4c, 0x52, 0xf8, 0x40, 0xc8, 0xb2, 0xf6, 0xde, 0x51, 0xdd, 0xbd, 0x5f, 0x5b, 0x6f, - 0xe4, 0x76, 0x34, 0x6f, 0xe9, 0x54, 0xdf, 0x2b, 0xd2, 0x39, 0xc7, 0x57, 0xe6, 0xc3, 0x35, 0xca, 0x22, 0x5b, 0x1a, - 0xfe, 0xbf, 0xd4, 0x99, 0xaa, 0x12, 0xb2, 0x34, 0xf4, 0xc0, 0x49, 0x51, 0x98, 0x1c, 0xff, 0x84, 0xe5, 0x73, 0x78, - 0x1f, 0xa6, 0xee, 0x49, 0x3f, 0xc5, 0xc2, 0xf3, 0x6b, 0x27, 0x8e, 0x50, 0xdb, 0xae, 0xc2, 0x06, 0x12, 0xb4, 0xab, - 0x76, 0x26, 0x0b, 0xdf, 0x78, 0x7c, 0x2d, 0x12, 0x7d, 0x4f, 0xe3, 0x53, 0x47, 0x38, 0x9c, 0x15, 0x82, 0xab, 0xbf, - 0xdc, 0x10, 0x5b, 0x65, 0x0b, 0x0a, 0x37, 0x4e, 0xa6, 0x6a, 0x34, 0xb6, 0x94, 0x57, 0x3e, 0x9f, 0xc7, 0x99, 0x66, - 0xa3, 0xc4, 0xd7, 0xfc, 0x60, 0x7f, 0x59, 0xed, 0x7c, 0xe1, 0x5b, 0xb0, 0x35, 0xf1, 0xf6, 0x8e, 0x0f, 0xa1, 0x43, - 0xcf, 0xab, 0x81, 0x9e, 0x6d, 0x38, 0xf3, 0x3f, 0x11, 0x56, 0xbf, 0x08, 0xf3, 0x6b, 0x1c, 0xe6, 0xd7, 0xde, 0x9f, - 0x97, 0xcd, 0x6b, 0x7a, 0xf9, 0x91, 0xc9, 0xa6, 0x8c, 0xe7, 0x4d, 0x50, 0xf8, 0x95, 0x5f, 0xce, 0xb0, 0x67, 0x95, - 0x1c, 0xa6, 0x6f, 0xc8, 0x77, 0x17, 0x39, 0x44, 0xdf, 0x95, 0xda, 0x1a, 0x65, 0x3c, 0xa3, 0xdd, 0x7a, 0x12, 0xa0, - 0x1b, 0xcc, 0xb5, 0xd8, 0x1a, 0x2e, 0x39, 0x44, 0xeb, 0xe5, 0x6d, 0xd4, 0x32, 0x6c, 0xbd, 0x65, 0x23, 0xb5, 0xad, - 0xad, 0xed, 0x23, 0x83, 0xdc, 0x86, 0x92, 0x5e, 0x62, 0x33, 0x62, 0xbd, 0x2b, 0xe2, 0xfc, 0xa9, 0x94, 0x38, 0xf0, - 0xe6, 0xd9, 0xbf, 0x4e, 0x2e, 0xe1, 0x7a, 0xb1, 0x4a, 0x89, 0xbb, 0x0f, 0x64, 0x51, 0x3c, 0x96, 0x54, 0xe0, 0xfb, - 0xb4, 0xbc, 0x54, 0xb7, 0x57, 0x96, 0x20, 0x66, 0xa2, 0xf6, 0xd3, 0xf9, 0xcd, 0xfd, 0x87, 0xbf, 0x7b, 0xf9, 0x85, - 0xc1, 0x91, 0x7d, 0x9b, 0x8b, 0xef, 0x77, 0xe1, 0x20, 0xa4, 0xf1, 0x6d, 0xc4, 0x32, 0x25, 0xf3, 0x2e, 0xc1, 0x25, - 0xd7, 0x9d, 0x73, 0x93, 0xdb, 0x29, 0x68, 0xaa, 0x3e, 0xdd, 0x66, 0xb6, 0xe2, 0xe8, 0xf1, 0xfc, 0xc6, 0xee, 0x46, - 0x7b, 0x2d, 0x67, 0xf3, 0x0f, 0x4d, 0xcd, 0xdc, 0x9d, 0x0b, 0x5a, 0x4f, 0x2f, 0x7c, 0x34, 0xbf, 0xe9, 0x6a, 0x41, - 0xdb, 0x14, 0x1a, 0xaa, 0xd6, 0xfc, 0xc6, 0x4d, 0x4e, 0xad, 0x06, 0xf2, 0xc2, 0xa3, 0xdc, 0xa3, 0x71, 0x4e, 0xbb, - 0xf0, 0xbe, 0x6a, 0x36, 0x8a, 0x53, 0x23, 0xcc, 0x67, 0x2c, 0x49, 0x52, 0xda, 0xb5, 0xf2, 0xda, 0x6b, 0x3f, 0x86, - 0xdc, 0x4e, 0x77, 0xcb, 0xea, 0xbb, 0xe2, 0x20, 0xaf, 0xc4, 0x53, 0x7c, 0x99, 0xf3, 0x14, 0x3e, 0x16, 0xb1, 0x15, - 0x9d, 0x26, 0xe9, 0xb1, 0x55, 0x21, 0x4f, 0xfd, 0xae, 0xaf, 0xe5, 0x51, 0xeb, 0x4f, 0x5d, 0xb5, 0xe1, 0xad, 0xae, - 0xe4, 0xf3, 0xa8, 0x79, 0x54, 0x5f, 0x08, 0x54, 0x95, 0x4b, 0xc0, 0x5b, 0x96, 0x85, 0x41, 0x5a, 0x69, 0x3e, 0xed, - 0x85, 0x6d, 0x53, 0xa6, 0x06, 0x80, 0x17, 0x2b, 0x97, 0x45, 0x45, 0x7d, 0x31, 0xff, 0x3e, 0xa7, 0xe5, 0xf3, 0xed, - 0xa7, 0xe5, 0x73, 0x7b, 0x5a, 0xee, 0xa6, 0xd8, 0xcf, 0xc6, 0x6d, 0xf8, 0xd3, 0xad, 0x16, 0x14, 0xb5, 0xbc, 0xa3, - 0xf9, 0x8d, 0x07, 0x7a, 0x5a, 0xb3, 0x33, 0xbf, 0xd1, 0xa9, 0xb9, 0x10, 0x36, 0x68, 0x41, 0xb2, 0x2a, 0x6e, 0x79, - 0x50, 0x08, 0x7f, 0x5b, 0xb5, 0xaa, 0xf6, 0x43, 0xa8, 0x83, 0x5e, 0x8f, 0x36, 0xeb, 0x3a, 0x77, 0x1f, 0xda, 0x28, - 0xe3, 0x32, 0x88, 0x2c, 0x37, 0x46, 0xa1, 0x8c, 0x2f, 0x2f, 0x69, 0x12, 0x8d, 0xf9, 0x68, 0x91, 0xff, 0xb3, 0x81, - 0xdf, 0x20, 0xf1, 0xce, 0x23, 0xbd, 0x36, 0x8e, 0xed, 0xaa, 0x13, 0x85, 0xed, 0x08, 0xcb, 0x72, 0x9f, 0xa2, 0x7c, - 0x14, 0xa7, 0x34, 0xe8, 0x84, 0x0f, 0xb7, 0x1c, 0x82, 0xff, 0x90, 0xbd, 0xd9, 0xba, 0x98, 0xdf, 0x8b, 0x8c, 0x3b, - 0x91, 0xf0, 0xab, 0x70, 0xe0, 0xee, 0x61, 0xeb, 0xe9, 0x76, 0x70, 0x07, 0x76, 0xa6, 0xa1, 0x15, 0x0a, 0x46, 0xee, - 0x24, 0x74, 0x1c, 0x2f, 0x52, 0x79, 0xf7, 0xa8, 0xbb, 0x28, 0x63, 0x63, 0xd4, 0x3b, 0x18, 0x7a, 0xd5, 0xf6, 0x9e, - 0x5c, 0xfa, 0xb3, 0xcf, 0x1f, 0xc2, 0x1f, 0x9d, 0x67, 0x74, 0x5b, 0xe9, 0xea, 0xda, 0x56, 0x05, 0x5d, 0x7d, 0xbf, - 0xa6, 0x8c, 0x6b, 0x11, 0xae, 0xf4, 0xf1, 0xfb, 0xb6, 0x06, 0xad, 0xf2, 0x5e, 0xcd, 0x8d, 0x96, 0xf5, 0xab, 0x5a, - 0xff, 0xba, 0xc1, 0xef, 0xd9, 0x76, 0xa4, 0x35, 0xd7, 0x7a, 0x5b, 0xf3, 0xed, 0xba, 0x8d, 0xc6, 0x16, 0xe3, 0xaa, - 0xfd, 0x3e, 0xb9, 0x2d, 0x4d, 0x14, 0x1d, 0x08, 0x04, 0x2b, 0x65, 0x5f, 0x5b, 0x29, 0x8c, 0x92, 0x07, 0xf0, 0xe6, - 0x58, 0xef, 0x66, 0x96, 0x66, 0x39, 0xf1, 0xa7, 0x52, 0xce, 0x23, 0xfd, 0xb1, 0xd3, 0xeb, 0xa3, 0x90, 0x8b, 0xc9, - 0x61, 0xa7, 0xd5, 0x6a, 0xc1, 0x1b, 0x3f, 0x7d, 0xef, 0x8a, 0xd1, 0xeb, 0x67, 0xfc, 0x86, 0xf8, 0x4f, 0xbc, 0xa7, - 0xde, 0x93, 0x23, 0xef, 0xd1, 0x63, 0xdf, 0x53, 0xec, 0x9c, 0xf8, 0x4f, 0x8e, 0x7c, 0x4f, 0xb3, 0x73, 0xe2, 0x3f, - 0x7a, 0xec, 0xf7, 0x8e, 0x27, 0x56, 0x25, 0x83, 0x2b, 0x83, 0x5a, 0xdf, 0xc9, 0xa5, 0xe0, 0x1f, 0x69, 0xfd, 0xe0, - 0xea, 0x32, 0x93, 0x89, 0xd6, 0xb1, 0x8f, 0x70, 0x7a, 0x47, 0xf1, 0x3c, 0x52, 0x44, 0xe1, 0x16, 0x82, 0x5b, 0x46, - 0x97, 0xaa, 0x29, 0x40, 0xcd, 0xbc, 0xf4, 0x7b, 0xc7, 0x90, 0x35, 0xee, 0x25, 0xc4, 0x7f, 0xdd, 0x79, 0xe2, 0xb5, - 0x1f, 0x5f, 0x35, 0x1f, 0x8e, 0x5a, 0xcd, 0xb6, 0xd7, 0x6e, 0x76, 0xc2, 0x27, 0x5e, 0x47, 0xff, 0xeb, 0xb5, 0xbc, - 0x23, 0xaf, 0x1d, 0x3e, 0xf1, 0x8e, 0xbc, 0x4e, 0xf8, 0xe4, 0xea, 0xa1, 0x4e, 0x27, 0x88, 0xfd, 0xc3, 0xde, 0x31, - 0x7c, 0xb8, 0xf2, 0x86, 0xf8, 0x9f, 0xfb, 0xfa, 0xf3, 0xb0, 0xfe, 0x67, 0x6e, 0x69, 0xfb, 0xe9, 0xd6, 0xe2, 0xce, - 0x93, 0xad, 0xc5, 0x47, 0x8f, 0xb7, 0x16, 0x3f, 0x7c, 0x54, 0x2f, 0x3e, 0x9c, 0xe8, 0xaa, 0xf2, 0x94, 0x13, 0x7f, - 0x16, 0x4b, 0xc1, 0x6e, 0x82, 0xb6, 0xd7, 0xf2, 0x5a, 0x5e, 0x13, 0xfe, 0x7b, 0xd2, 0x41, 0x65, 0xaf, 0x4b, 0xe8, - 0x55, 0xae, 0xf2, 0xc9, 0x53, 0xaf, 0xfd, 0xf8, 0x65, 0xe7, 0xf1, 0x08, 0xda, 0xa9, 0x85, 0xb6, 0xbd, 0xf6, 0xd5, - 0xd1, 0xd3, 0x51, 0xcb, 0x83, 0x8e, 0x6d, 0xf8, 0x33, 0x7d, 0xd4, 0x19, 0xe9, 0x87, 0x16, 0xd4, 0x7f, 0xdb, 0x7e, - 0x92, 0xb7, 0x9a, 0x6d, 0xf8, 0xf3, 0x4b, 0xa9, 0x11, 0x83, 0x3e, 0xee, 0x8e, 0xfb, 0xb0, 0xe5, 0x1d, 0x3d, 0x9d, - 0x76, 0xc2, 0xcf, 0xaf, 0x9e, 0x84, 0x4f, 0xa7, 0xed, 0x27, 0xdf, 0xea, 0xa7, 0xb4, 0xd9, 0x09, 0x3f, 0x87, 0xbf, - 0xdf, 0x1e, 0xb5, 0xa6, 0xcd, 0x76, 0xf8, 0xf4, 0xea, 0x28, 0x3c, 0x4a, 0x9b, 0x8f, 0xc3, 0xa7, 0xf0, 0xb7, 0x1a, - 0x6e, 0xca, 0x67, 0xd4, 0xf7, 0x60, 0xbf, 0xd7, 0xcc, 0x2d, 0x77, 0x8e, 0xce, 0x43, 0xef, 0xd1, 0xc3, 0x97, 0x4f, - 0xaf, 0x9a, 0x0f, 0xa7, 0xed, 0xce, 0x55, 0x73, 0xe7, 0xcf, 0x6f, 0x01, 0xf1, 0x66, 0xe0, 0x98, 0xc2, 0xf5, 0x1d, - 0x8b, 0x38, 0xf5, 0xf6, 0xd9, 0x07, 0x38, 0xdf, 0x65, 0x5e, 0x8b, 0x4f, 0x9b, 0xd7, 0x19, 0xbd, 0x8f, 0x7d, 0x2d, - 0xfe, 0x70, 0xfb, 0x3a, 0xa7, 0x6b, 0x4e, 0xd5, 0x5b, 0xb9, 0x61, 0x46, 0xaf, 0xdb, 0x5e, 0xef, 0x64, 0x30, 0x60, - 0xf0, 0x95, 0xa3, 0xa2, 0x7b, 0x0b, 0x2f, 0xb8, 0x76, 0xbd, 0x0d, 0x1c, 0x0e, 0xf2, 0xad, 0xd4, 0x27, 0x99, 0xef, - 0x42, 0x48, 0xfa, 0x69, 0x84, 0x7c, 0x7b, 0x1f, 0x7c, 0xa4, 0x7f, 0x38, 0x3e, 0xb8, 0x8b, 0x8f, 0x9a, 0x9f, 0x57, - 0xd9, 0xb3, 0xca, 0x1e, 0x3d, 0x53, 0xcf, 0x01, 0xdc, 0xf0, 0x68, 0xf8, 0x87, 0x14, 0x8a, 0x72, 0x5f, 0xc7, 0x15, - 0xde, 0xfc, 0x1a, 0x97, 0xb4, 0xbe, 0xce, 0x45, 0x7c, 0x63, 0xfc, 0xcf, 0xe1, 0x4b, 0x06, 0xf6, 0xe1, 0x4a, 0x5f, - 0x30, 0x26, 0x7e, 0x27, 0x6c, 0x85, 0xad, 0xd2, 0x71, 0x00, 0x57, 0xf8, 0xc8, 0x92, 0xcb, 0x18, 0x3e, 0xa6, 0x99, - 0xf2, 0x89, 0xfa, 0xec, 0x26, 0xbc, 0xec, 0x5c, 0x7d, 0x00, 0x55, 0xbf, 0x67, 0x3e, 0xf2, 0x7d, 0x73, 0xf1, 0x1f, - 0xae, 0x88, 0x7d, 0x03, 0xd7, 0xe8, 0xac, 0xc7, 0x7a, 0x06, 0x36, 0xf5, 0x6b, 0x9a, 0xb0, 0x38, 0xf0, 0x83, 0xb9, - 0xa0, 0x63, 0x2a, 0xf2, 0x66, 0xed, 0x6e, 0x99, 0xba, 0x56, 0x86, 0x7c, 0xfb, 0xd9, 0x46, 0x01, 0x2f, 0xef, 0x25, - 0x03, 0xe3, 0xd5, 0xf2, 0x8d, 0x9a, 0xef, 0x17, 0xd8, 0x96, 0x08, 0xe0, 0xe8, 0x95, 0x6a, 0xe0, 0x6b, 0xdd, 0xa0, - 0x1d, 0x76, 0x1e, 0x21, 0xcd, 0x4b, 0xe0, 0xa5, 0xa8, 0xdf, 0x07, 0xcd, 0xa3, 0xd6, 0x9f, 0x90, 0xd3, 0xad, 0x1c, - 0x68, 0x68, 0x9c, 0x3a, 0xa2, 0xfa, 0xdc, 0x6d, 0xfd, 0xe2, 0x9f, 0xaf, 0x29, 0xe2, 0x33, 0xbd, 0x76, 0x78, 0xbd, - 0xaa, 0x89, 0x1f, 0xea, 0xeb, 0xeb, 0x63, 0x36, 0x09, 0xdc, 0x8f, 0x99, 0xea, 0x97, 0xae, 0xaa, 0x6f, 0x20, 0xa3, - 0xa2, 0x6a, 0x22, 0xd0, 0x52, 0xf9, 0xe2, 0x59, 0xe6, 0x89, 0xd5, 0x2a, 0x10, 0xe0, 0x88, 0x25, 0x0e, 0x4e, 0xe1, - 0x19, 0xd5, 0x90, 0x2c, 0x70, 0x09, 0x90, 0x42, 0x30, 0x11, 0xfa, 0xff, 0xaa, 0xd8, 0xfe, 0x30, 0xee, 0x95, 0x30, - 0x8d, 0xb3, 0x09, 0x50, 0x61, 0x9c, 0x4d, 0x36, 0x9c, 0x37, 0x3a, 0x9c, 0xb0, 0x56, 0x5a, 0x0d, 0x55, 0x39, 0x69, - 0xf2, 0x67, 0xb7, 0xef, 0xcd, 0xdb, 0x99, 0x7c, 0xf0, 0x81, 0x2a, 0xdf, 0x77, 0xf5, 0x26, 0xd9, 0x06, 0x79, 0xa0, - 0x3f, 0x0f, 0xae, 0xf2, 0xd1, 0x40, 0xfa, 0xc1, 0x95, 0x3e, 0xcf, 0xd8, 0x3c, 0xc4, 0xd7, 0xb2, 0x2f, 0xa1, 0x57, - 0x6c, 0x64, 0x44, 0x18, 0xf6, 0xcc, 0xb5, 0xe6, 0xa6, 0xda, 0x1a, 0xd2, 0xc6, 0xda, 0xea, 0x1f, 0xc5, 0x2a, 0xbf, - 0x98, 0x64, 0xdc, 0xef, 0x3d, 0x28, 0xbf, 0xcd, 0xb8, 0x6b, 0x13, 0xe0, 0x9b, 0xe5, 0x03, 0x41, 0xd3, 0x7f, 0x26, - 0x0f, 0xe0, 0xab, 0xe5, 0x0f, 0x86, 0xf0, 0xc1, 0xec, 0x50, 0x89, 0x82, 0x07, 0xd5, 0xc7, 0xcb, 0x81, 0x0f, 0x36, - 0x6e, 0x66, 0x29, 0xbe, 0xaf, 0xf8, 0x36, 0xa2, 0xba, 0xf3, 0xa8, 0x12, 0xd5, 0x9d, 0x47, 0xae, 0xf4, 0x6c, 0x7b, - 0xed, 0x4e, 0xf8, 0xc8, 0x11, 0x00, 0x57, 0x4d, 0xf8, 0xbf, 0x26, 0x02, 0x1e, 0x86, 0x8f, 0x4a, 0x19, 0xf0, 0xaa, - 0xdd, 0x09, 0x8f, 0xb4, 0xb8, 0xe9, 0x84, 0x8f, 0x7e, 0x50, 0x0c, 0x5a, 0x33, 0xe7, 0xfa, 0x81, 0xd8, 0x12, 0xaa, - 0xd1, 0x49, 0x75, 0x3e, 0x0e, 0xca, 0x2f, 0xc0, 0x99, 0xf3, 0x69, 0x5c, 0x42, 0xcf, 0x63, 0x01, 0x9f, 0xe1, 0xa8, - 0x9f, 0xdd, 0x5a, 0x1d, 0xae, 0xf1, 0x8b, 0x2d, 0x53, 0xc0, 0x09, 0xf7, 0xb1, 0x7b, 0x2f, 0x18, 0x2e, 0xd5, 0xaa, - 0x97, 0x16, 0xdb, 0x77, 0xb7, 0xed, 0x26, 0x6d, 0xdd, 0xd0, 0xbe, 0x1f, 0x4e, 0x31, 0x0b, 0xa6, 0x5e, 0x10, 0xaf, - 0x26, 0xf9, 0x32, 0x29, 0xd6, 0xe7, 0x87, 0xdc, 0x3e, 0xc1, 0x9d, 0xab, 0xd1, 0xb4, 0x4a, 0x3f, 0x4f, 0x18, 0x5c, - 0x66, 0x2f, 0x0a, 0x0b, 0x7a, 0xcd, 0x19, 0x58, 0x61, 0x49, 0xf1, 0x0b, 0x9a, 0xf7, 0x7d, 0x28, 0xf2, 0x23, 0x5f, - 0x39, 0x92, 0xfc, 0xf2, 0x53, 0x24, 0x25, 0x61, 0x57, 0x05, 0x58, 0x5d, 0x21, 0x81, 0x53, 0x0b, 0xf8, 0xf1, 0xd1, - 0xc1, 0xc1, 0xce, 0xf3, 0xa2, 0xb4, 0x31, 0x58, 0x6b, 0xf5, 0x09, 0x03, 0x97, 0x15, 0xf9, 0x2e, 0xa2, 0xcb, 0x71, - 0x15, 0x0a, 0x91, 0xc1, 0xd3, 0x25, 0x8d, 0x65, 0x18, 0x67, 0x3a, 0x45, 0xc1, 0x61, 0x58, 0xb8, 0x4d, 0x8f, 0x50, - 0xc1, 0x65, 0xec, 0x7c, 0xa3, 0xd4, 0x9c, 0x73, 0x2e, 0x63, 0x7b, 0xd1, 0x2f, 0x93, 0xb5, 0x4c, 0xf8, 0x69, 0xa7, - 0xf7, 0xf6, 0xfd, 0x89, 0xa7, 0x8f, 0xe7, 0xf1, 0xe1, 0xb4, 0xd3, 0x3b, 0x56, 0x96, 0xb9, 0xbe, 0x26, 0x44, 0xf4, - 0x35, 0x21, 0xcf, 0x5c, 0x19, 0x83, 0x78, 0x4d, 0x71, 0xa8, 0x97, 0xed, 0x7b, 0x34, 0x1b, 0x69, 0x9f, 0xe2, 0x6c, - 0x91, 0x4a, 0x06, 0x2f, 0xe0, 0x3d, 0x84, 0xae, 0x4d, 0xd8, 0xb0, 0x32, 0xcf, 0xd4, 0x6a, 0x38, 0x32, 0xb3, 0x1e, - 0xc8, 0x31, 0x4b, 0xa9, 0xcd, 0x2c, 0x35, 0x43, 0x95, 0x79, 0xcf, 0x9b, 0xad, 0xf3, 0xc5, 0xe5, 0x8c, 0xc9, 0x32, - 0x15, 0xf4, 0x83, 0xe9, 0x70, 0xac, 0xa6, 0xea, 0x5d, 0x14, 0xc6, 0x45, 0x6a, 0x3f, 0x36, 0xb2, 0xf6, 0x79, 0x77, - 0xbd, 0x7a, 0x23, 0x21, 0xe0, 0xbe, 0xcf, 0xf4, 0xa8, 0x57, 0x3a, 0x25, 0xdd, 0xba, 0xe2, 0xf8, 0x70, 0x7a, 0xd4, - 0xbb, 0x88, 0xe6, 0x66, 0xbc, 0x57, 0x7c, 0xe3, 0x53, 0xf1, 0x25, 0xc7, 0xec, 0xab, 0xc4, 0x76, 0x7d, 0x83, 0xd2, - 0x00, 0x3c, 0xe2, 0xa9, 0xdf, 0x3b, 0x36, 0xca, 0x80, 0xa7, 0x82, 0xae, 0xfe, 0xa3, 0x96, 0xcd, 0x95, 0x4f, 0xb9, - 0xd2, 0x96, 0x74, 0x17, 0x67, 0x92, 0x9a, 0x5f, 0x77, 0xda, 0xee, 0x1d, 0xc7, 0x46, 0xcd, 0x04, 0xe6, 0x91, 0x47, - 0x87, 0xd0, 0x19, 0x74, 0xb9, 0x90, 0xf1, 0xc3, 0x6b, 0x7a, 0xd9, 0x8c, 0xe7, 0xac, 0x72, 0xa2, 0x82, 0xd2, 0x51, - 0x4e, 0xc9, 0xab, 0x99, 0xe0, 0x67, 0xbc, 0xb6, 0x48, 0xc5, 0xc2, 0x0b, 0xe3, 0xa1, 0x55, 0xba, 0x3a, 0x8d, 0xa5, - 0xef, 0x69, 0x0e, 0x6f, 0x3d, 0xb9, 0x46, 0xf6, 0x16, 0x7e, 0xef, 0xdf, 0xfe, 0xc7, 0xff, 0x32, 0xce, 0xd9, 0xe3, - 0xc3, 0x69, 0xdb, 0x8e, 0xb5, 0x86, 0xe8, 0xe2, 0x18, 0xae, 0x97, 0x55, 0xd1, 0x44, 0x7a, 0xd3, 0x9c, 0x08, 0x96, - 0x34, 0xa7, 0x71, 0x3a, 0xf6, 0x7b, 0xbb, 0x11, 0xe4, 0xde, 0x2b, 0x31, 0x50, 0xd7, 0x8b, 0x80, 0x04, 0x7f, 0xd3, - 0xcd, 0x08, 0x9b, 0x60, 0xaf, 0x4e, 0xab, 0x7b, 0x4f, 0xa2, 0x3a, 0x50, 0xb5, 0xbb, 0x12, 0xc2, 0x7c, 0x93, 0xc8, - 0x30, 0x35, 0x51, 0xbb, 0x22, 0x51, 0xf8, 0x5e, 0x19, 0x0d, 0xf9, 0xbf, 0xff, 0xf3, 0xbf, 0xfc, 0x37, 0xfb, 0x08, - 0x41, 0x8e, 0x7f, 0xfb, 0xef, 0xff, 0xf9, 0xff, 0xfc, 0xef, 0xff, 0x0a, 0x69, 0xf5, 0x26, 0x10, 0xa2, 0xf8, 0x84, - 0x57, 0x45, 0x41, 0x34, 0xc3, 0xf0, 0x20, 0x19, 0x6d, 0xc6, 0x72, 0xc9, 0x46, 0xf5, 0x4b, 0x13, 0x67, 0x6a, 0x42, - 0x75, 0xd8, 0x0c, 0x74, 0xea, 0xd0, 0x16, 0x15, 0x8d, 0xd4, 0x50, 0xae, 0x68, 0xb1, 0x38, 0x3e, 0x04, 0x7c, 0xdf, - 0xef, 0x9e, 0x59, 0x58, 0x6e, 0xc7, 0xd2, 0xba, 0xfe, 0xa0, 0xa4, 0xa8, 0xca, 0x3d, 0x70, 0xca, 0x2f, 0xe1, 0x31, - 0xea, 0x38, 0xc5, 0x6a, 0xf7, 0x6a, 0x7d, 0xba, 0x3f, 0x2d, 0x72, 0xc9, 0xc6, 0x80, 0x72, 0xed, 0x60, 0x54, 0xf1, - 0xcf, 0x26, 0xa8, 0x7f, 0xe9, 0x6d, 0xa1, 0x46, 0xd1, 0x36, 0xe3, 0xc3, 0xa7, 0x7f, 0x2a, 0xfe, 0x32, 0x03, 0x25, - 0xcb, 0x0b, 0x66, 0xf1, 0x8d, 0xb1, 0x24, 0x1f, 0xb7, 0x5a, 0xf3, 0x1b, 0xb4, 0xac, 0x66, 0xc0, 0xbb, 0x26, 0x53, - 0x4e, 0x49, 0x77, 0x40, 0x15, 0x38, 0x2d, 0xfd, 0x9f, 0x2d, 0x0f, 0x9c, 0xa8, 0x5e, 0xab, 0x28, 0xfe, 0xbc, 0x54, - 0x2e, 0x38, 0xf6, 0x0b, 0x04, 0x38, 0x8d, 0xb7, 0xf2, 0x92, 0xbb, 0x8b, 0x5b, 0x3a, 0xbd, 0x3a, 0xba, 0xd7, 0xb4, - 0xbd, 0x79, 0x7d, 0xca, 0x0d, 0xd0, 0xba, 0xa1, 0xd5, 0x87, 0x10, 0x2c, 0x9d, 0xb6, 0xf1, 0xb4, 0xb3, 0x2c, 0x87, - 0x97, 0x92, 0xcf, 0xdc, 0x88, 0x2c, 0x8d, 0xe9, 0x88, 0x8e, 0xad, 0x97, 0xd7, 0xd4, 0xeb, 0x68, 0x6b, 0x31, 0x3d, - 0xda, 0x32, 0x97, 0x01, 0x49, 0x45, 0x62, 0xbd, 0x56, 0xf1, 0x19, 0x9c, 0xc0, 0xe5, 0x38, 0xe5, 0xb1, 0x8c, 0x14, - 0xc1, 0x76, 0xdd, 0xb8, 0x6e, 0x0c, 0x6c, 0x86, 0x2f, 0x1d, 0x78, 0xba, 0xba, 0x29, 0xf8, 0x5b, 0xeb, 0x97, 0xdc, - 0x8a, 0x50, 0x75, 0x77, 0x87, 0xd2, 0xee, 0x9a, 0x6f, 0x4d, 0xb8, 0xf4, 0x4d, 0xcd, 0xcf, 0x61, 0x64, 0x4c, 0x07, - 0x6d, 0xaf, 0xd7, 0xa2, 0x5a, 0xd7, 0x7e, 0x25, 0x03, 0x5f, 0x81, 0xe9, 0xaf, 0xb7, 0x52, 0x85, 0xd0, 0xea, 0x0d, - 0xf9, 0xb6, 0xb4, 0x82, 0xe2, 0xf9, 0x5c, 0x35, 0x44, 0xdd, 0xe3, 0x43, 0xad, 0xbc, 0x02, 0xf7, 0x50, 0xb9, 0x00, - 0x3a, 0xf4, 0x6e, 0x1a, 0x99, 0xa3, 0xa0, 0x7f, 0x99, 0xa0, 0x3c, 0x7c, 0xac, 0xaa, 0xf7, 0xff, 0x00, 0xbb, 0x9f, - 0x49, 0x8d, 0x3d, 0x86, 0x00, 0x00}; + 0x72, 0x7f, 0x60, 0xe6, 0x13, 0x26, 0x4e, 0x2e, 0x40, 0x82, 0x4b, 0xa9, 0xbc, 0xdc, 0x1b, 0x13, 0x0a, 0x49, 0x44, + 0xae, 0x27, 0x4f, 0x9e, 0x3c, 0x7b, 0x02, 0xc7, 0x7b, 0x09, 0x1f, 0xc9, 0xdb, 0x39, 0xf5, 0xa6, 0x72, 0x96, 0xf6, + 0x8e, 0xcd, 0xbf, 0x34, 0x4e, 0x7a, 0xc7, 0x29, 0xcb, 0x3e, 0x7a, 0x82, 0xa6, 0x84, 0x8d, 0x78, 0xe6, 0x4d, 0x05, + 0x1d, 0x93, 0x24, 0x96, 0x71, 0xc4, 0x66, 0xf1, 0x84, 0x7a, 0x87, 0xbd, 0xe3, 0x19, 0x95, 0xb1, 0x37, 0x9a, 0xc6, + 0x22, 0xa7, 0x92, 0x7c, 0x78, 0xff, 0x45, 0xf3, 0x69, 0xef, 0x38, 0x1f, 0x09, 0x36, 0x97, 0x1e, 0x0c, 0x49, 0x66, + 0x3c, 0x59, 0xa4, 0xb4, 0x77, 0x78, 0x78, 0x7d, 0x7d, 0x1d, 0xfe, 0x94, 0xff, 0xd3, 0x88, 0x67, 0xb9, 0xf4, 0x5e, + 0x91, 0x6b, 0x96, 0x25, 0xfc, 0x1a, 0x53, 0x49, 0x5e, 0x85, 0x67, 0xd3, 0x38, 0xe1, 0xd7, 0xef, 0x38, 0x97, 0x07, + 0x07, 0x81, 0x7e, 0xbc, 0x3d, 0x3d, 0x3b, 0x23, 0x84, 0x5c, 0x71, 0x96, 0x78, 0xad, 0xd5, 0xaa, 0x2a, 0x0c, 0xb3, + 0x58, 0xb2, 0x2b, 0xaa, 0xbb, 0xa0, 0x83, 0x03, 0x3f, 0x4e, 0xf8, 0x5c, 0xd2, 0xe4, 0x4c, 0xde, 0xa6, 0xf4, 0x6c, + 0x4a, 0xa9, 0xcc, 0x7d, 0x96, 0x79, 0xcf, 0xf9, 0x68, 0x31, 0xa3, 0x99, 0x0c, 0xe7, 0x82, 0x4b, 0x0e, 0x90, 0x1c, + 0x1c, 0xf8, 0x82, 0xce, 0xd3, 0x78, 0x44, 0xa1, 0xfe, 0xf4, 0xec, 0xac, 0xea, 0x51, 0x35, 0xc2, 0x4c, 0x92, 0xb3, + 0xdb, 0xd9, 0x25, 0x4f, 0x03, 0x84, 0x53, 0x49, 0x32, 0x7a, 0xed, 0x7d, 0x47, 0xe3, 0x8f, 0xaf, 0xe3, 0x79, 0x77, + 0x94, 0xc6, 0x79, 0xee, 0x5d, 0xca, 0xa5, 0x5a, 0x82, 0x58, 0x8c, 0x24, 0x17, 0x81, 0xc4, 0x14, 0x33, 0xb4, 0x64, + 0xe3, 0x40, 0x4e, 0x59, 0x1e, 0x9e, 0xef, 0x8f, 0xf2, 0xfc, 0x1d, 0xcd, 0x17, 0xa9, 0xdc, 0x27, 0x7b, 0x2d, 0xcc, + 0xf6, 0x08, 0x61, 0x12, 0xc9, 0xa9, 0xe0, 0xd7, 0xde, 0x0b, 0x21, 0xb8, 0x08, 0xfc, 0xd3, 0xb3, 0x33, 0xdd, 0xc2, + 0x63, 0xb9, 0x97, 0x71, 0xe9, 0x95, 0xe3, 0xc5, 0x97, 0x29, 0x0d, 0xbd, 0x0f, 0x39, 0xf5, 0x2e, 0x16, 0x59, 0x1e, + 0x8f, 0xe9, 0xe9, 0xd9, 0xd9, 0x85, 0xc7, 0x85, 0x77, 0x31, 0xca, 0xf3, 0x0b, 0x8f, 0x65, 0xb9, 0xa4, 0x71, 0x12, + 0xfa, 0xa8, 0xab, 0x26, 0x1b, 0xe5, 0xf9, 0x7b, 0x7a, 0x23, 0x89, 0xc4, 0xea, 0x51, 0x12, 0x5a, 0x4c, 0xa8, 0xf4, + 0xf2, 0x72, 0x5d, 0x01, 0x5a, 0xa6, 0x54, 0x7a, 0x92, 0xa8, 0x7a, 0xde, 0xd5, 0xb8, 0xa7, 0xfa, 0x51, 0x76, 0xd9, + 0x38, 0xa0, 0xf2, 0xe0, 0x40, 0x96, 0x78, 0x46, 0x7a, 0x69, 0x1e, 0x23, 0x74, 0xcf, 0x96, 0x1d, 0x1c, 0xd0, 0x30, + 0xa5, 0xd9, 0x44, 0x4e, 0x09, 0x21, 0xed, 0x2e, 0x3b, 0x38, 0x08, 0x24, 0x49, 0x65, 0x38, 0xa1, 0x32, 0xa0, 0x08, + 0xe1, 0xaa, 0xf7, 0xc1, 0x41, 0xa0, 0x91, 0xc0, 0x89, 0x46, 0x5c, 0x0d, 0xc7, 0x28, 0x34, 0xd8, 0x3f, 0xbb, 0xcd, + 0x46, 0x81, 0x0b, 0x3f, 0xc2, 0xec, 0xe0, 0x20, 0x95, 0x61, 0x0e, 0x23, 0x62, 0x89, 0x50, 0x21, 0xa8, 0x5c, 0x88, + 0xcc, 0x93, 0x85, 0xe4, 0x67, 0x52, 0xb0, 0x6c, 0x12, 0xa0, 0xa5, 0x2d, 0x73, 0x3a, 0x16, 0x85, 0x06, 0xf7, 0x6b, + 0x49, 0x04, 0xe9, 0xc1, 0x8c, 0x97, 0x32, 0x80, 0x5d, 0xe4, 0x63, 0x4f, 0x10, 0xe2, 0xe7, 0xaa, 0xaf, 0xdf, 0x17, + 0x91, 0x68, 0xf8, 0x3e, 0xd6, 0x50, 0x62, 0x26, 0x11, 0xfe, 0x48, 0x02, 0x81, 0xc3, 0x30, 0x94, 0x88, 0xf4, 0x96, + 0x16, 0x2b, 0xc2, 0x59, 0x67, 0x5f, 0x0c, 0x5a, 0xc3, 0x48, 0x86, 0x82, 0x26, 0x8b, 0x11, 0x0d, 0x02, 0x86, 0x73, + 0x9c, 0x21, 0xd2, 0x63, 0x8d, 0x80, 0x93, 0x1e, 0x6c, 0x37, 0xaf, 0xef, 0x35, 0x21, 0x7b, 0x2d, 0x64, 0x60, 0xe4, + 0x16, 0x40, 0xc0, 0xb0, 0x81, 0x87, 0x13, 0xe2, 0x67, 0x8b, 0xd9, 0x25, 0x15, 0x7e, 0xd9, 0xac, 0x5b, 0x23, 0x8b, + 0x45, 0x4e, 0xbd, 0x51, 0x9e, 0x7b, 0xe3, 0x45, 0x36, 0x92, 0x8c, 0x67, 0x9e, 0xdf, 0xe0, 0x0d, 0x5f, 0x93, 0x43, + 0x49, 0x0d, 0x3e, 0x2a, 0x50, 0x90, 0xa3, 0x86, 0x18, 0x64, 0x8d, 0xf6, 0x10, 0x03, 0x94, 0xa8, 0x6b, 0xc6, 0x33, + 0x08, 0xa0, 0x58, 0xc0, 0x1a, 0x0b, 0xfc, 0x41, 0xc2, 0x2a, 0xd5, 0x12, 0xa9, 0xec, 0x8b, 0x70, 0xf3, 0xa0, 0x10, + 0x19, 0xce, 0xe2, 0x79, 0x40, 0x49, 0x8f, 0x2a, 0xe2, 0x8a, 0xb3, 0x11, 0xc0, 0x5a, 0xdb, 0xb7, 0x3e, 0x8d, 0x68, + 0x58, 0x91, 0x14, 0x8a, 0x64, 0x38, 0xe6, 0xe2, 0x45, 0x3c, 0x9a, 0x42, 0xbf, 0x92, 0x60, 0x12, 0x7b, 0xde, 0x46, + 0x82, 0xc6, 0x92, 0xbe, 0x48, 0x29, 0x3c, 0x05, 0xbe, 0xea, 0xe9, 0x23, 0x9c, 0x93, 0x57, 0x61, 0xca, 0xe4, 0x1b, + 0x9e, 0x8d, 0x68, 0x37, 0x77, 0xa8, 0x8b, 0xc1, 0xbe, 0x9f, 0x48, 0x29, 0xd8, 0xe5, 0x42, 0xd2, 0xc0, 0xcf, 0xa0, + 0x85, 0x8f, 0x73, 0x84, 0x59, 0x28, 0xe9, 0x8d, 0x3c, 0xe5, 0x99, 0xa4, 0x99, 0x24, 0xd4, 0x22, 0x15, 0x8b, 0x30, + 0x9e, 0xcf, 0x69, 0x96, 0x9c, 0x4e, 0x59, 0x9a, 0x04, 0x0c, 0x15, 0xa8, 0xc0, 0xb1, 0x24, 0xb0, 0x46, 0xd2, 0x13, + 0x11, 0xfc, 0xb3, 0x7b, 0x35, 0x81, 0x24, 0x3d, 0x75, 0x28, 0x28, 0xf1, 0xfd, 0xee, 0x98, 0x8b, 0xc0, 0xac, 0xc0, + 0xe3, 0x63, 0x4f, 0xc2, 0x1c, 0xef, 0x16, 0x29, 0xcd, 0x11, 0x6d, 0x10, 0x56, 0x6e, 0xa3, 0x41, 0xf0, 0xd7, 0x40, + 0xf1, 0x05, 0x0a, 0x04, 0x8a, 0x44, 0xf7, 0x2a, 0x16, 0xde, 0x17, 0xe6, 0x44, 0xfd, 0x64, 0xb9, 0xd9, 0x54, 0x92, + 0x9f, 0x42, 0x29, 0x16, 0xb9, 0xa4, 0xc9, 0xfb, 0xdb, 0x39, 0xcd, 0xf1, 0x4b, 0x49, 0xa6, 0xb2, 0x3f, 0x95, 0x21, + 0x9d, 0xcd, 0xe5, 0xed, 0x99, 0x62, 0x8c, 0x91, 0xef, 0xe3, 0x11, 0xb4, 0x14, 0x34, 0x1e, 0x01, 0x33, 0x33, 0xd8, + 0xfa, 0x9a, 0xa7, 0xb7, 0x63, 0x96, 0xa6, 0x67, 0x8b, 0xf9, 0x9c, 0x0b, 0x89, 0xff, 0x4a, 0x96, 0x92, 0x57, 0xa8, + 0x81, 0xbd, 0x5c, 0xe6, 0xd7, 0x4c, 0x8e, 0xa6, 0x81, 0x44, 0xcb, 0x51, 0x9c, 0x53, 0xef, 0x19, 0xe7, 0x29, 0x8d, + 0xb3, 0x48, 0x10, 0xd1, 0x7f, 0x29, 0xa3, 0x6c, 0x91, 0xa6, 0xdd, 0x4b, 0x41, 0xe3, 0x8f, 0x5d, 0x55, 0xfd, 0xf6, + 0xf2, 0x27, 0x3a, 0x92, 0x91, 0xfa, 0x7d, 0x22, 0x44, 0x7c, 0x0b, 0x0d, 0x09, 0x81, 0x66, 0x7d, 0x11, 0x7d, 0x75, + 0xf6, 0xf6, 0x4d, 0xa8, 0x0f, 0x09, 0x1b, 0xdf, 0x06, 0xa2, 0x3c, 0x78, 0xa2, 0xc0, 0x63, 0xc1, 0x67, 0x6b, 0x53, + 0x6b, 0xac, 0x89, 0xee, 0x0e, 0x10, 0x28, 0x11, 0x7b, 0x7a, 0x68, 0x17, 0x82, 0x37, 0x8a, 0xe6, 0xa1, 0x92, 0x98, + 0x79, 0xe1, 0x9f, 0x48, 0x17, 0x07, 0x02, 0xdd, 0x0d, 0xad, 0x14, 0xb7, 0x4b, 0x4a, 0x14, 0x9c, 0x73, 0x90, 0x30, + 0x00, 0xe3, 0x28, 0x96, 0xa3, 0xe9, 0x92, 0xaa, 0xc1, 0x0a, 0x0b, 0x31, 0x2d, 0x0a, 0x7c, 0x5d, 0xd2, 0xbb, 0xdc, + 0x23, 0x44, 0x28, 0x46, 0x45, 0xe4, 0x6a, 0x25, 0x08, 0x11, 0x08, 0x7f, 0x47, 0x96, 0xb1, 0x5d, 0x4f, 0xb4, 0xd7, + 0xc2, 0x70, 0x2e, 0x23, 0xcd, 0x5d, 0xf0, 0x88, 0x67, 0x57, 0x54, 0x48, 0x2a, 0xa2, 0xbf, 0x62, 0x41, 0xc7, 0x29, + 0x40, 0xb1, 0xd7, 0xc6, 0xd3, 0x38, 0x3f, 0x9d, 0xc6, 0xd9, 0x84, 0x26, 0xd1, 0xb5, 0x2c, 0xf0, 0xdf, 0x89, 0x3f, + 0x66, 0x59, 0x9c, 0xb2, 0x5f, 0x68, 0xe2, 0x1b, 0x69, 0x70, 0xe2, 0xd1, 0x1b, 0x49, 0xb3, 0x24, 0xf7, 0x5e, 0xbe, + 0x7f, 0xfd, 0xca, 0xec, 0x63, 0x4d, 0x40, 0xa0, 0x65, 0xbe, 0x98, 0x53, 0x11, 0x20, 0x6c, 0x04, 0xc4, 0x0b, 0xa6, + 0x98, 0xe3, 0xeb, 0x78, 0xae, 0x4b, 0x58, 0xfe, 0x61, 0x9e, 0xc4, 0x92, 0x7e, 0x4d, 0xb3, 0x84, 0x65, 0x13, 0xb2, + 0xd7, 0xd6, 0xe5, 0xd3, 0xd8, 0x54, 0x24, 0x65, 0xd1, 0xf9, 0xfe, 0x8b, 0x54, 0xad, 0xbb, 0x7c, 0x5c, 0x04, 0xa8, + 0xc8, 0x65, 0x2c, 0xd9, 0xc8, 0x8b, 0x93, 0xe4, 0xcb, 0x8c, 0x49, 0xa6, 0x00, 0x14, 0xb0, 0x3d, 0x40, 0xa2, 0x54, + 0x8b, 0x0a, 0x0b, 0x78, 0x80, 0x70, 0x10, 0x18, 0x01, 0x30, 0x45, 0x66, 0xbf, 0x0e, 0x0e, 0x2a, 0x76, 0xdf, 0xa7, + 0x91, 0xae, 0x24, 0x83, 0x21, 0x0a, 0xe7, 0x8b, 0x1c, 0x36, 0xda, 0x4e, 0x01, 0xd2, 0x85, 0x5f, 0xe6, 0x54, 0x5c, + 0xd1, 0xa4, 0x24, 0x8e, 0x3c, 0x40, 0xcb, 0xb5, 0x39, 0xcc, 0xb1, 0x90, 0x64, 0x30, 0xec, 0xba, 0x7c, 0x9b, 0x1a, + 0x3a, 0x17, 0x7c, 0x4e, 0x85, 0x64, 0x34, 0x2f, 0x59, 0x49, 0x00, 0x52, 0xb4, 0x64, 0x27, 0x39, 0xb1, 0xeb, 0x9b, + 0x07, 0x0c, 0x53, 0x54, 0x63, 0x18, 0x56, 0xd0, 0xbe, 0xb8, 0x52, 0x12, 0x23, 0xc7, 0x0c, 0x61, 0xa9, 0x21, 0xcd, + 0x11, 0x2a, 0x10, 0x96, 0x16, 0x5c, 0xcd, 0x8a, 0xcc, 0x6c, 0xb7, 0x20, 0xaa, 0xc9, 0x77, 0x4a, 0x54, 0x03, 0x43, + 0x8b, 0x25, 0x3d, 0x38, 0x08, 0x68, 0x58, 0x12, 0x05, 0xd9, 0x6b, 0x9b, 0x3d, 0x72, 0x90, 0xb5, 0x03, 0x6c, 0x98, + 0x58, 0x62, 0x8a, 0xf0, 0x1e, 0x0d, 0x33, 0x7e, 0x32, 0x1a, 0xd1, 0x3c, 0xe7, 0xe2, 0xe0, 0x60, 0x4f, 0xb5, 0x2f, + 0xb5, 0x09, 0xd8, 0xc3, 0xb7, 0xd7, 0x59, 0x05, 0x01, 0xaa, 0x24, 0xac, 0x91, 0x0b, 0x12, 0xe4, 0x94, 0x52, 0x38, + 0xfc, 0xbe, 0x55, 0x3c, 0x22, 0xff, 0xfc, 0xdc, 0x6f, 0x48, 0x6c, 0xd0, 0x30, 0xa1, 0x76, 0xea, 0xdb, 0xe7, 0x54, + 0xab, 0x56, 0x4a, 0xf1, 0xd8, 0xc0, 0x8c, 0x3e, 0x3f, 0x61, 0x42, 0xc7, 0x2c, 0x73, 0x96, 0x5d, 0x03, 0x09, 0x4b, + 0x9c, 0xa3, 0xc2, 0xd9, 0xd0, 0xad, 0x43, 0x2b, 0x9d, 0x46, 0xef, 0xdc, 0x72, 0xa2, 0xf4, 0x08, 0x67, 0x1b, 0x07, + 0x74, 0x58, 0x60, 0x85, 0x7a, 0xbb, 0x9a, 0x4c, 0x01, 0x3a, 0x90, 0xc3, 0xae, 0xa9, 0x27, 0xb9, 0xc6, 0x9c, 0xa0, + 0x3f, 0x2f, 0x68, 0x2e, 0x35, 0x1d, 0x07, 0x12, 0x67, 0x98, 0xa1, 0x02, 0x8e, 0xdb, 0x98, 0x4d, 0x16, 0x02, 0xd4, + 0x1d, 0x38, 0x8a, 0x34, 0x5b, 0xcc, 0xa8, 0x7d, 0xda, 0x06, 0xdb, 0xdb, 0x39, 0x08, 0xc4, 0x1c, 0x68, 0xfa, 0x6e, + 0x72, 0x02, 0x58, 0x25, 0x5a, 0xad, 0xbe, 0xb3, 0x83, 0x54, 0x5b, 0x59, 0xaa, 0x68, 0x6b, 0x7b, 0xf2, 0x77, 0x64, + 0xe4, 0xf1, 0x5e, 0x5b, 0x43, 0xff, 0xf7, 0x21, 0xd9, 0x6b, 0x95, 0x14, 0x6c, 0x70, 0xaa, 0x81, 0xd1, 0x28, 0x7c, + 0xab, 0x07, 0x42, 0x4a, 0xba, 0xd7, 0x88, 0x25, 0x9c, 0x6e, 0xd0, 0xe9, 0x94, 0x0c, 0x40, 0xcf, 0x08, 0xa7, 0xc3, + 0x5d, 0xc4, 0x64, 0xb9, 0x41, 0x20, 0x37, 0xeb, 0x2a, 0xa6, 0x71, 0x55, 0x67, 0x1a, 0x6b, 0x8b, 0xf0, 0xe7, 0x65, + 0x17, 0xbf, 0xa4, 0x31, 0x73, 0xcc, 0xab, 0x2a, 0xcc, 0x14, 0x30, 0xd5, 0x92, 0x9c, 0x21, 0xde, 0xc4, 0x33, 0x9a, + 0x07, 0x14, 0xe1, 0x5d, 0x0d, 0x34, 0x71, 0x42, 0x93, 0xa1, 0x23, 0x36, 0x73, 0x10, 0x9b, 0x0c, 0x69, 0xad, 0xac, + 0x7e, 0xdc, 0x72, 0x4c, 0x07, 0xf9, 0xb0, 0x52, 0xe6, 0x9c, 0xc5, 0x2b, 0x79, 0x6c, 0xa8, 0xdb, 0xe2, 0x4f, 0x97, + 0x69, 0xa4, 0x29, 0xa5, 0x21, 0x47, 0x78, 0xaf, 0xb5, 0xbe, 0x8f, 0xb6, 0x55, 0xb5, 0xc6, 0xc1, 0x10, 0xf6, 0x41, + 0x89, 0x8b, 0x90, 0xe5, 0xea, 0xff, 0xda, 0x39, 0x03, 0xb4, 0x9d, 0x01, 0x59, 0x84, 0xe3, 0x34, 0x96, 0x41, 0xfb, + 0xb0, 0x05, 0x9a, 0xe8, 0x15, 0x05, 0x69, 0x82, 0xd0, 0xe6, 0x52, 0x68, 0xb8, 0xc8, 0xf2, 0x29, 0x1b, 0xcb, 0x20, + 0x96, 0x8a, 0xa1, 0xd0, 0x34, 0xa7, 0x9e, 0xac, 0xe9, 0xc3, 0x8a, 0xd9, 0xc4, 0x40, 0x6a, 0xa5, 0xf2, 0x45, 0x2d, + 0xa4, 0x8a, 0x69, 0x01, 0x6f, 0xa8, 0x74, 0xe9, 0x8a, 0xc7, 0xd8, 0xd6, 0x0c, 0xf4, 0xc5, 0x76, 0x5f, 0x8f, 0x18, + 0x19, 0x56, 0xc0, 0x1c, 0x95, 0x95, 0x45, 0x2e, 0x7f, 0x30, 0x85, 0x32, 0x94, 0xfc, 0x15, 0xbf, 0xa6, 0xe2, 0x34, + 0x06, 0xe0, 0x23, 0xdd, 0xbd, 0xd0, 0x62, 0x40, 0x71, 0x7b, 0xd9, 0xb5, 0xf4, 0x72, 0xae, 0x16, 0xfe, 0xb5, 0xe0, + 0x33, 0x96, 0x53, 0xd0, 0xd4, 0x34, 0xfe, 0x33, 0x38, 0x65, 0xea, 0x38, 0x82, 0xa8, 0xa1, 0x25, 0x7d, 0x9d, 0xbc, + 0xaa, 0xd3, 0xd7, 0xf9, 0xfe, 0x8b, 0x89, 0x65, 0x7f, 0xf5, 0x43, 0x8c, 0x70, 0x60, 0xec, 0x09, 0x47, 0xca, 0x85, + 0x53, 0x64, 0xc4, 0xfb, 0x6a, 0x25, 0x1d, 0xb3, 0xad, 0xa6, 0x2b, 0x52, 0x7d, 0x6c, 0x50, 0x11, 0x27, 0x09, 0x68, + 0x75, 0x82, 0xa7, 0xa9, 0x23, 0xa8, 0x30, 0xeb, 0x96, 0xa2, 0xe9, 0x7c, 0xff, 0xc5, 0xd9, 0x5d, 0xd2, 0x09, 0xea, + 0x5d, 0x01, 0x65, 0x01, 0xcd, 0x12, 0x2a, 0xc0, 0x8c, 0x74, 0x76, 0xcb, 0xc8, 0xd8, 0x53, 0x9e, 0x65, 0x74, 0x24, + 0x69, 0x02, 0x56, 0x0a, 0x23, 0x32, 0x9c, 0xf2, 0x5c, 0x96, 0x85, 0x15, 0xf4, 0xcc, 0x81, 0x9e, 0x85, 0xa3, 0x38, + 0x4d, 0x03, 0x6d, 0x91, 0xcc, 0xf8, 0x15, 0xdd, 0x02, 0x75, 0xb7, 0x06, 0x72, 0x39, 0x0c, 0x75, 0x86, 0xa1, 0x61, + 0x3e, 0x4f, 0xd9, 0x88, 0x96, 0x82, 0xeb, 0x2c, 0x64, 0x59, 0x42, 0x6f, 0x80, 0x8f, 0xa0, 0x5e, 0xaf, 0xd7, 0xc2, + 0x6d, 0x54, 0x68, 0x84, 0x2f, 0x37, 0x10, 0x7b, 0x87, 0xc8, 0x04, 0x22, 0x23, 0xbd, 0xe5, 0x36, 0x7e, 0x40, 0x91, + 0x23, 0x27, 0x99, 0xb5, 0xac, 0x34, 0x6f, 0x46, 0x38, 0xa1, 0x29, 0x95, 0xd4, 0xf2, 0x72, 0xd0, 0x9f, 0xf5, 0xd1, + 0x7d, 0x57, 0xe2, 0xaf, 0x24, 0x27, 0x7b, 0xca, 0xec, 0x9e, 0xe7, 0xa5, 0xa5, 0x5e, 0x6d, 0x4f, 0x85, 0xed, 0xbe, + 0xd4, 0xdb, 0x13, 0x4b, 0x19, 0x8f, 0xa6, 0xda, 0x44, 0x0f, 0x36, 0x96, 0x54, 0x8d, 0x61, 0xf8, 0x7a, 0x79, 0x88, + 0x3e, 0x58, 0x30, 0xb7, 0xa1, 0xe0, 0xcc, 0x30, 0x05, 0x0a, 0x56, 0x9f, 0xde, 0xb6, 0xd3, 0x38, 0x4d, 0x2f, 0xe3, + 0xd1, 0xc7, 0x3a, 0xf5, 0x57, 0x64, 0x40, 0xd6, 0xb9, 0xb1, 0x53, 0xe5, 0xb0, 0x2c, 0x77, 0xdd, 0x96, 0x4b, 0xd7, + 0x0e, 0x4a, 0xb0, 0xd7, 0xaa, 0xc8, 0xbe, 0xbe, 0xd1, 0x3b, 0xa9, 0x5d, 0x41, 0xc4, 0xcc, 0xca, 0x02, 0xe0, 0x02, + 0x9f, 0xa4, 0x38, 0xcb, 0x0f, 0x0c, 0xdd, 0x81, 0xad, 0x51, 0xac, 0x01, 0x22, 0xd1, 0xb2, 0x48, 0x58, 0xbe, 0x1b, + 0x03, 0x7f, 0x08, 0x94, 0xcf, 0x9d, 0x19, 0xee, 0x0b, 0x68, 0xc9, 0xe3, 0x8c, 0xca, 0x5c, 0x42, 0x66, 0xb4, 0x09, + 0xcb, 0x68, 0xfe, 0x06, 0x9a, 0x8b, 0xa2, 0xf7, 0xb7, 0xba, 0x0a, 0x74, 0x32, 0x80, 0x22, 0xef, 0xba, 0xca, 0x44, + 0x8d, 0x02, 0x0c, 0x4f, 0x65, 0x4a, 0xe4, 0x66, 0x35, 0xe3, 0xd1, 0xa8, 0xeb, 0xda, 0xfe, 0x36, 0x2c, 0x97, 0x93, + 0x20, 0x08, 0x72, 0xb0, 0xdf, 0xac, 0x5e, 0x5f, 0x2d, 0x22, 0xdf, 0x58, 0x44, 0x1e, 0x3a, 0x46, 0x16, 0xaa, 0x68, + 0xd9, 0xe9, 0x1e, 0xfd, 0x15, 0xb9, 0x8d, 0x40, 0x59, 0x0d, 0x81, 0x3f, 0xa3, 0x92, 0xdd, 0xa6, 0x44, 0x62, 0x6e, + 0x0c, 0x1c, 0x43, 0x69, 0xc0, 0x30, 0xaa, 0x2e, 0x19, 0xd2, 0x47, 0xa3, 0x66, 0xec, 0x66, 0x98, 0xa3, 0x35, 0xcd, + 0xbe, 0x28, 0x0c, 0x8e, 0x28, 0x32, 0x7b, 0x53, 0x53, 0x89, 0x1d, 0xac, 0xe0, 0x8c, 0x18, 0x35, 0x58, 0x6b, 0x3d, + 0xeb, 0xb8, 0x29, 0xc7, 0x85, 0x83, 0x5a, 0xa1, 0xa6, 0xa6, 0x4f, 0x5a, 0xc5, 0x2a, 0x43, 0x78, 0x6a, 0x35, 0x52, + 0x5e, 0xad, 0x9b, 0x10, 0xdf, 0x7a, 0x23, 0xfc, 0xfe, 0xb2, 0x66, 0x12, 0x46, 0x4e, 0xb3, 0x22, 0x02, 0x96, 0xca, + 0xb7, 0xa1, 0x7b, 0x1b, 0xcd, 0xd4, 0xc6, 0x71, 0x10, 0xce, 0x5d, 0x84, 0x3b, 0x98, 0xcd, 0x34, 0xe7, 0xca, 0x86, + 0x64, 0x5a, 0xef, 0x1b, 0x50, 0xcc, 0xf5, 0x3e, 0x6c, 0x20, 0x71, 0x5d, 0xf1, 0x54, 0x24, 0x08, 0x06, 0x6c, 0x0e, + 0xca, 0x9d, 0x2b, 0x1f, 0x02, 0x80, 0x9d, 0xad, 0x56, 0x1b, 0x44, 0xb7, 0x55, 0xff, 0x44, 0x61, 0x65, 0x14, 0xae, + 0x56, 0xd7, 0x12, 0x05, 0x46, 0xf3, 0xc5, 0x14, 0xf5, 0x2d, 0xc7, 0x3d, 0x79, 0x05, 0xad, 0x94, 0x22, 0x5a, 0x95, + 0x94, 0x26, 0x43, 0x9d, 0x66, 0xeb, 0xfb, 0x24, 0x1d, 0xb6, 0x7d, 0xba, 0xc1, 0xbd, 0x54, 0xa1, 0x11, 0xd3, 0xd5, + 0x92, 0x4f, 0xcd, 0xd0, 0x0c, 0x21, 0x14, 0xe5, 0xca, 0x8a, 0xd9, 0xdb, 0x66, 0x58, 0x1e, 0x1c, 0xe4, 0xce, 0x40, + 0xe7, 0x25, 0x9b, 0xf8, 0x29, 0x00, 0x91, 0x9c, 0xdf, 0x66, 0x4a, 0x77, 0xf9, 0xc9, 0x0a, 0xa1, 0x0d, 0xb3, 0xb4, + 0xd5, 0x05, 0x6b, 0x3c, 0xbe, 0x8e, 0x99, 0xf4, 0xca, 0x51, 0xb4, 0x35, 0x1e, 0x50, 0xb4, 0x34, 0xaa, 0x46, 0x28, + 0x28, 0x28, 0x8f, 0xc0, 0x13, 0xac, 0x0a, 0xad, 0xe9, 0x7e, 0x34, 0xa5, 0xe0, 0x08, 0xb6, 0x5a, 0x44, 0x69, 0x17, + 0xee, 0x19, 0x29, 0x62, 0x06, 0xde, 0x0e, 0x7b, 0xb1, 0xde, 0xbd, 0x66, 0x07, 0xcc, 0xa9, 0x18, 0x73, 0x31, 0xb3, + 0x75, 0xc5, 0xda, 0xb3, 0xe1, 0x8c, 0x6c, 0x1c, 0x6c, 0x1d, 0xdb, 0xa8, 0xff, 0xdd, 0x35, 0xa3, 0xbb, 0x32, 0xd7, + 0x6b, 0xa2, 0xb4, 0x94, 0xbe, 0xda, 0x1f, 0x68, 0x29, 0x33, 0x77, 0xcd, 0x7b, 0xe3, 0x4c, 0xed, 0x6a, 0x87, 0xc9, + 0x5e, 0xbb, 0x5b, 0xda, 0x7c, 0x96, 0x1a, 0xba, 0xda, 0xb1, 0x61, 0x44, 0x2a, 0x5f, 0xa4, 0x89, 0x01, 0x96, 0x21, + 0x4c, 0x0d, 0x1d, 0x5d, 0xb3, 0x34, 0xad, 0x4a, 0x7f, 0x0d, 0x5f, 0xcf, 0x0d, 0x5f, 0xcf, 0x2c, 0x5f, 0x07, 0x4e, + 0x01, 0x7c, 0x5d, 0x0f, 0x57, 0x75, 0xcf, 0x36, 0x4e, 0x67, 0xa6, 0x39, 0x7a, 0xae, 0xec, 0x68, 0x98, 0x6f, 0x61, + 0x21, 0x40, 0xa5, 0xe6, 0xf5, 0x31, 0x30, 0x4e, 0x18, 0x30, 0x00, 0xb5, 0x0b, 0x93, 0xba, 0x2e, 0x8a, 0x8f, 0x01, + 0xc2, 0x79, 0x41, 0x4b, 0xca, 0x3e, 0x79, 0x01, 0x4e, 0x3a, 0x67, 0x39, 0x20, 0xc4, 0x54, 0xf1, 0xaf, 0x52, 0xa2, + 0xec, 0xea, 0x98, 0x59, 0x5d, 0x6e, 0x57, 0x07, 0x9c, 0xbe, 0x5a, 0x5d, 0x72, 0x37, 0xaf, 0x57, 0xcb, 0x63, 0xe5, + 0xf2, 0xaa, 0xfd, 0x5e, 0xad, 0x82, 0xb5, 0x12, 0xf0, 0xdf, 0x1b, 0x13, 0x45, 0x94, 0xa3, 0x03, 0x0f, 0x70, 0x31, + 0x03, 0x05, 0x85, 0x5e, 0x74, 0x29, 0xe2, 0x5e, 0x7d, 0xca, 0xc1, 0xa3, 0xdc, 0xf4, 0xba, 0xff, 0x29, 0x9f, 0xcd, + 0x41, 0x1b, 0x5b, 0x23, 0xe9, 0x09, 0x35, 0x13, 0x56, 0xf5, 0xc5, 0x96, 0xb2, 0x5a, 0x1f, 0x75, 0x1e, 0x6b, 0xd4, + 0x54, 0xda, 0xcb, 0x7b, 0xad, 0x62, 0x51, 0x16, 0x95, 0x8c, 0x63, 0x9b, 0x53, 0xe5, 0x74, 0xdd, 0x25, 0x63, 0x2b, + 0xde, 0x06, 0x4c, 0xf3, 0x61, 0x06, 0xbc, 0xce, 0x61, 0x3f, 0x96, 0xdc, 0xdd, 0xfd, 0x2f, 0x2a, 0xe4, 0x2c, 0x8b, + 0x35, 0xf4, 0x2d, 0x8b, 0xe2, 0x44, 0x1b, 0xd9, 0xf8, 0x64, 0xb7, 0x35, 0x5c, 0xd5, 0x19, 0x63, 0x71, 0x30, 0xc4, + 0x27, 0x9b, 0xaa, 0x23, 0x59, 0xce, 0x78, 0x42, 0x23, 0x9f, 0xcf, 0x69, 0xe6, 0x17, 0xe0, 0x55, 0x35, 0x7b, 0x3f, + 0x92, 0xc1, 0xf2, 0x5d, 0xdd, 0xbd, 0x1a, 0x9d, 0x14, 0xe0, 0xfd, 0xfa, 0x62, 0xd3, 0xf1, 0xfa, 0x2d, 0x15, 0xb9, + 0x52, 0x44, 0x4b, 0x9d, 0xf6, 0x8b, 0x4a, 0x2c, 0x7d, 0x11, 0xed, 0x6c, 0x5f, 0x99, 0x20, 0x7e, 0x3b, 0x7c, 0x1c, + 0x1e, 0xf9, 0x48, 0xb9, 0x85, 0xbf, 0x32, 0x07, 0xfe, 0xb9, 0x75, 0x0b, 0xbf, 0x20, 0xcf, 0xeb, 0x5e, 0xe1, 0x44, + 0x92, 0x17, 0xfd, 0x17, 0xd6, 0x62, 0xe6, 0x29, 0x1b, 0xdd, 0x06, 0x7e, 0xca, 0x64, 0x13, 0x42, 0x6f, 0x3e, 0x5e, + 0xea, 0x0a, 0x70, 0x29, 0x2a, 0x77, 0x76, 0x61, 0x6d, 0x3d, 0x2c, 0x25, 0xf1, 0xf7, 0x53, 0x26, 0xf7, 0x7d, 0x3c, + 0x23, 0x17, 0xf0, 0x63, 0x7f, 0x19, 0xbc, 0x8e, 0xe5, 0x34, 0x14, 0x71, 0x96, 0xf0, 0x59, 0x80, 0x1a, 0xbe, 0x8f, + 0xc2, 0x5c, 0xd9, 0x1b, 0x9f, 0xa3, 0x62, 0xff, 0x02, 0xdf, 0x48, 0xe2, 0xf7, 0xfd, 0xc6, 0x0c, 0xbf, 0x91, 0xe4, + 0xe2, 0x78, 0x7f, 0x79, 0x23, 0x8b, 0xde, 0x05, 0xbe, 0x29, 0x3d, 0xf6, 0xf8, 0x6b, 0x12, 0x20, 0xd2, 0xbb, 0x31, + 0xd0, 0x9c, 0xf2, 0x99, 0xf6, 0xdc, 0xfb, 0x08, 0x7f, 0x80, 0xb8, 0x8a, 0xa8, 0xb8, 0x8d, 0x09, 0xad, 0xec, 0x11, + 0x9f, 0x2b, 0x17, 0x81, 0x7f, 0x70, 0xe0, 0x94, 0x95, 0xaa, 0x02, 0x3e, 0x91, 0xa4, 0x66, 0x90, 0xe3, 0xf7, 0x2a, + 0x42, 0x73, 0x22, 0x03, 0x81, 0xec, 0x30, 0x81, 0xf5, 0x43, 0x9b, 0xa3, 0x29, 0x06, 0xda, 0xc3, 0x10, 0x32, 0x49, + 0x45, 0x2c, 0xb9, 0x18, 0x22, 0x57, 0xfd, 0xc0, 0x7f, 0x23, 0x17, 0x03, 0xef, 0x3f, 0xfd, 0xd3, 0x8f, 0xe3, 0x1f, + 0xc5, 0xf0, 0x02, 0xbf, 0x25, 0x87, 0xc7, 0x41, 0x3f, 0x0a, 0xf6, 0x9a, 0xcd, 0xd5, 0x8f, 0x87, 0x83, 0x7f, 0xc4, + 0xcd, 0x5f, 0x4e, 0x9a, 0x3f, 0x0c, 0xd1, 0x2a, 0xf8, 0xf1, 0xb0, 0x3f, 0x30, 0x4f, 0x83, 0x7f, 0xf4, 0x7e, 0xcc, + 0x87, 0x7f, 0xd6, 0x85, 0xfb, 0x08, 0x1d, 0x4e, 0xf0, 0x42, 0x92, 0xc3, 0x66, 0xb3, 0x77, 0x38, 0xc1, 0x73, 0x49, + 0x0e, 0xe1, 0xff, 0x4b, 0xf2, 0x8e, 0x4e, 0x5e, 0xdc, 0xcc, 0x83, 0x8b, 0xde, 0x6a, 0x7f, 0xf9, 0xb7, 0x02, 0x46, + 0x1d, 0xfc, 0xe3, 0xc7, 0x1f, 0x73, 0xff, 0x41, 0x8f, 0x1c, 0x0e, 0x1b, 0x28, 0x80, 0xd2, 0x3f, 0x13, 0xf5, 0x6f, + 0xd0, 0x8f, 0x06, 0xff, 0x30, 0x50, 0xf8, 0x0f, 0x7e, 0xbc, 0x38, 0xee, 0x91, 0xe1, 0x2a, 0xf0, 0x57, 0x0f, 0xd0, + 0x0a, 0xa1, 0xd5, 0x3e, 0xba, 0xc0, 0xfe, 0xc4, 0x47, 0x78, 0x22, 0xc9, 0xe1, 0x83, 0xc3, 0x09, 0xbe, 0x92, 0xe4, + 0xd0, 0x3f, 0x9c, 0xe0, 0x17, 0x92, 0x1c, 0xfe, 0x23, 0xe8, 0x47, 0xda, 0xc3, 0xb6, 0x52, 0xee, 0x8d, 0x15, 0x04, + 0x37, 0x62, 0x41, 0xe3, 0x95, 0x64, 0x32, 0xa5, 0x68, 0xff, 0x90, 0xe1, 0x33, 0x85, 0xa6, 0x40, 0x82, 0x13, 0x06, + 0x6c, 0xbb, 0x60, 0x79, 0x0e, 0x9b, 0x0d, 0x34, 0xb3, 0x1f, 0x09, 0xac, 0xfd, 0x00, 0x79, 0x24, 0xf1, 0x55, 0x9c, + 0x2e, 0x68, 0x1e, 0xd1, 0x02, 0xe1, 0x11, 0x39, 0x93, 0x41, 0x1b, 0xe1, 0x77, 0x12, 0x7e, 0x74, 0x10, 0x3e, 0x33, + 0x01, 0x4c, 0x38, 0xc8, 0x9a, 0xa8, 0x32, 0xae, 0x35, 0x16, 0x1f, 0xe1, 0xf9, 0x96, 0x4a, 0x39, 0x05, 0xef, 0x02, + 0xc2, 0xe3, 0x5a, 0xb8, 0x13, 0x5f, 0x13, 0x4b, 0x12, 0xef, 0x05, 0xa5, 0xdf, 0xc5, 0xe9, 0x47, 0x2a, 0x82, 0x1b, + 0xdc, 0xee, 0x7c, 0x8e, 0x95, 0x0b, 0x7a, 0xaf, 0x8d, 0xba, 0x65, 0xac, 0xea, 0x54, 0xea, 0x18, 0x01, 0x08, 0xd9, + 0xba, 0x2f, 0x06, 0x76, 0x7c, 0x4f, 0x6c, 0x38, 0xac, 0x44, 0x7c, 0xed, 0xa3, 0x7a, 0x5c, 0x94, 0x65, 0x57, 0x71, + 0xca, 0x12, 0x4f, 0xd2, 0xd9, 0x3c, 0x8d, 0x25, 0xf5, 0xcc, 0x7a, 0xbd, 0x18, 0x06, 0xf2, 0x4b, 0x95, 0x21, 0x71, + 0x0c, 0xce, 0xc4, 0x06, 0x9c, 0xe0, 0xac, 0x04, 0x10, 0x9d, 0x32, 0x6a, 0xc7, 0xeb, 0x2a, 0xf8, 0xb5, 0x1e, 0xdf, + 0x6b, 0xb6, 0xc1, 0x11, 0x36, 0x54, 0xe2, 0x39, 0xc7, 0x19, 0x01, 0x21, 0xda, 0xe9, 0xfb, 0xc7, 0xf9, 0xd5, 0xa4, + 0xe7, 0x43, 0x6c, 0x86, 0x93, 0xb7, 0xca, 0x2f, 0x04, 0x0d, 0xa6, 0xa4, 0xd5, 0x9d, 0x1e, 0xd3, 0xee, 0xb4, 0xd1, + 0xb0, 0x3a, 0x74, 0x4a, 0xc4, 0x60, 0xaa, 0xbb, 0xc7, 0x38, 0xc1, 0x0b, 0xd2, 0x6c, 0xe3, 0x09, 0x69, 0xa9, 0x2e, + 0xdd, 0xc9, 0x71, 0x6a, 0xa6, 0x39, 0x38, 0x08, 0x78, 0x98, 0xc6, 0xb9, 0xfc, 0x12, 0x8c, 0x7d, 0x32, 0xc1, 0x09, + 0xe1, 0x21, 0xbd, 0xa1, 0xa3, 0x20, 0x45, 0x38, 0x31, 0x9c, 0x06, 0x75, 0xd1, 0x84, 0x38, 0xcd, 0xc0, 0x88, 0x20, + 0x6f, 0xfb, 0xc9, 0xa0, 0x3d, 0x24, 0x84, 0xf8, 0x7b, 0xcd, 0xa6, 0xdf, 0xe7, 0x64, 0x21, 0x23, 0x28, 0x71, 0x54, + 0x65, 0x32, 0x87, 0xa2, 0x8e, 0x53, 0x14, 0xbc, 0x90, 0xa1, 0xa4, 0xb9, 0x0c, 0xa0, 0x18, 0xcc, 0xff, 0xdc, 0x12, + 0xb6, 0x7f, 0x7c, 0xe8, 0x37, 0xa0, 0x54, 0x11, 0x27, 0xc2, 0x9c, 0x5c, 0xa2, 0x28, 0x19, 0x1c, 0x0d, 0x5d, 0xfe, + 0xaf, 0x0a, 0x61, 0xf2, 0xcb, 0x7e, 0x32, 0x68, 0xa9, 0xc9, 0x7b, 0x7e, 0x3f, 0xe0, 0x24, 0xd7, 0x0a, 0x5a, 0x3f, + 0x8f, 0xde, 0xaa, 0xa5, 0xa2, 0xc8, 0x00, 0x67, 0xe6, 0x5d, 0x90, 0x66, 0x27, 0x0a, 0x16, 0xee, 0x22, 0x9a, 0x30, + 0x99, 0xc1, 0x02, 0x8e, 0x09, 0xb4, 0xc7, 0x9c, 0xc0, 0x8c, 0x55, 0xb7, 0xcb, 0xc8, 0x3c, 0x3f, 0xf0, 0x1f, 0xf4, + 0xaf, 0x64, 0x34, 0x91, 0x7a, 0xfa, 0x2b, 0xb9, 0x5a, 0xc1, 0xff, 0x13, 0xd9, 0xe7, 0xe4, 0x52, 0x15, 0x2d, 0x4c, + 0xd1, 0x1c, 0x8a, 0xde, 0x46, 0x00, 0x2a, 0xce, 0x4b, 0x25, 0x4b, 0xef, 0xc9, 0x15, 0x51, 0xb0, 0x1f, 0x1c, 0x88, + 0xc1, 0xb4, 0xd1, 0x1e, 0x82, 0x7f, 0x5f, 0xc8, 0xfc, 0x3b, 0x26, 0xa7, 0x81, 0x7f, 0xd8, 0xf3, 0x51, 0xdf, 0xf7, + 0x60, 0x6b, 0xbb, 0x59, 0x83, 0x68, 0x0c, 0xa7, 0x8d, 0x37, 0x32, 0x5a, 0xf4, 0x48, 0xab, 0x1f, 0x30, 0xe3, 0xcf, + 0x43, 0x38, 0x35, 0x8c, 0xb3, 0x85, 0x17, 0xa8, 0x21, 0x65, 0xc3, 0x3e, 0x2f, 0x50, 0x63, 0xd6, 0xb8, 0x42, 0x51, + 0xda, 0x98, 0x35, 0x82, 0x05, 0x21, 0xa4, 0xd9, 0x29, 0xbb, 0x59, 0xe9, 0x37, 0x45, 0xd1, 0x95, 0x75, 0x76, 0x0e, + 0xd4, 0x71, 0xc8, 0x1a, 0x81, 0x18, 0xd0, 0xe1, 0x6a, 0xe5, 0x1f, 0xf7, 0x7b, 0x3e, 0x6a, 0x04, 0x96, 0xd0, 0x0e, + 0x2d, 0xa5, 0x21, 0x84, 0xd9, 0xb0, 0x30, 0xa1, 0xa4, 0x97, 0xb5, 0xb0, 0xd1, 0xb2, 0x3a, 0xec, 0x0e, 0x0f, 0xa0, + 0x45, 0x69, 0xc7, 0x68, 0x7d, 0x75, 0x0e, 0xcb, 0xb4, 0xc4, 0x9c, 0x91, 0x16, 0xe6, 0xc4, 0xfa, 0xae, 0xa7, 0x44, + 0x56, 0x04, 0x9f, 0x92, 0xaa, 0x39, 0x1e, 0xc4, 0x38, 0x19, 0x92, 0xd7, 0xda, 0x1e, 0xe9, 0x5a, 0xbf, 0x38, 0x4d, + 0xc9, 0xcb, 0xb5, 0xe8, 0x6d, 0x0c, 0xb1, 0x95, 0xeb, 0x70, 0xb4, 0x10, 0x82, 0x66, 0xf2, 0x0d, 0x4f, 0x8c, 0x9a, + 0x46, 0x53, 0xb0, 0x94, 0x20, 0x2c, 0x8b, 0x41, 0x47, 0xeb, 0xd8, 0x93, 0xb1, 0xd8, 0xa8, 0x9e, 0x90, 0x85, 0x56, + 0x9f, 0x54, 0xb0, 0xb6, 0x3b, 0x31, 0x76, 0x71, 0x80, 0xf0, 0xc2, 0x44, 0x71, 0x83, 0x30, 0x0c, 0x27, 0xe1, 0x08, + 0xaa, 0x61, 0x82, 0x1c, 0x15, 0xea, 0x1c, 0x05, 0x39, 0xb9, 0x0e, 0x33, 0x7a, 0xa3, 0x66, 0x0d, 0x50, 0x25, 0x99, + 0xed, 0xf1, 0x3a, 0x9e, 0x76, 0x15, 0xbb, 0xc9, 0xc3, 0x8c, 0x27, 0x14, 0xd0, 0x03, 0x71, 0x7b, 0x53, 0x34, 0x8d, + 0x73, 0x37, 0x3e, 0x55, 0xc1, 0x37, 0x70, 0x9d, 0xd7, 0x13, 0xf0, 0xf8, 0x2a, 0x5d, 0xab, 0x6c, 0xac, 0xdd, 0xe0, + 0x08, 0xb1, 0x71, 0x30, 0x09, 0x21, 0xae, 0xa7, 0x48, 0x48, 0x82, 0x29, 0x37, 0x71, 0x89, 0x6a, 0x56, 0x8e, 0x79, + 0x45, 0x92, 0x01, 0x6f, 0x34, 0x94, 0x17, 0x7a, 0xa1, 0x49, 0x62, 0x82, 0xf0, 0x55, 0x79, 0xb6, 0x6c, 0xbb, 0xb7, + 0x92, 0xd4, 0xa7, 0x0a, 0xae, 0xea, 0xee, 0xdc, 0x86, 0x94, 0x48, 0x79, 0x0a, 0x65, 0x30, 0x43, 0xf8, 0x19, 0x39, + 0x0c, 0x06, 0x61, 0xff, 0x2f, 0x43, 0xd4, 0x0f, 0xc2, 0x3f, 0xa3, 0x43, 0xcd, 0x39, 0xae, 0x50, 0x37, 0xd5, 0x73, + 0x2c, 0x55, 0xfc, 0xb2, 0x8d, 0x95, 0x27, 0x31, 0xca, 0x70, 0x16, 0xcf, 0x68, 0xf4, 0x0c, 0x0e, 0xb9, 0x25, 0x9c, + 0xb7, 0x12, 0x03, 0x25, 0x45, 0xcf, 0x0c, 0x2f, 0x09, 0xfd, 0xfe, 0x2b, 0x59, 0x3e, 0xf5, 0xfd, 0xfe, 0xf3, 0xea, + 0xe9, 0x2f, 0x7e, 0xff, 0x17, 0x19, 0xfd, 0x5c, 0x18, 0x6f, 0x77, 0x6d, 0x8e, 0xc7, 0x76, 0x8e, 0x42, 0x6f, 0x8d, + 0x83, 0xbb, 0x05, 0xda, 0x74, 0x74, 0x4c, 0x50, 0xc1, 0xc6, 0x25, 0x33, 0xca, 0x43, 0x19, 0x4f, 0x00, 0xa9, 0xce, + 0x1e, 0xe4, 0x6e, 0x5c, 0xbf, 0x5a, 0x31, 0x90, 0x8a, 0xa5, 0x57, 0x40, 0xe6, 0xa4, 0xd7, 0x42, 0xcb, 0x5a, 0x5b, + 0xa5, 0x33, 0xd5, 0xe3, 0xe8, 0x25, 0x9f, 0xbe, 0x22, 0xad, 0xee, 0xd5, 0xf1, 0xa4, 0x7b, 0xd5, 0x68, 0xa0, 0xdc, + 0x92, 0xd6, 0x62, 0x70, 0x35, 0xc4, 0x5f, 0x83, 0x53, 0xcf, 0xa5, 0x25, 0x5c, 0x5b, 0x5e, 0xc7, 0x2c, 0xaf, 0xd1, + 0xc8, 0x0a, 0xd4, 0x75, 0xba, 0x4e, 0x74, 0xd7, 0xa2, 0xd0, 0x38, 0x59, 0x27, 0xb5, 0xa7, 0x48, 0x95, 0x40, 0x32, + 0x14, 0x21, 0xe4, 0x46, 0xa2, 0xad, 0xa3, 0xc2, 0x98, 0xd0, 0x5d, 0x9d, 0x59, 0x60, 0x9f, 0x5a, 0x4a, 0x04, 0x80, + 0x05, 0xe8, 0x5a, 0x7a, 0x82, 0x67, 0x78, 0xd1, 0x68, 0x2b, 0x32, 0x6f, 0xb6, 0xbb, 0xf5, 0xb1, 0x9e, 0x54, 0x63, + 0xe1, 0x45, 0x83, 0xcc, 0x4a, 0x2c, 0x15, 0x59, 0xa3, 0x51, 0xd4, 0x83, 0x9d, 0xf6, 0xe4, 0xd6, 0x02, 0x10, 0x37, + 0xeb, 0x49, 0x19, 0x56, 0xc2, 0x56, 0x32, 0x95, 0x85, 0x2c, 0xcb, 0xa8, 0x00, 0x29, 0x4a, 0x24, 0x66, 0x45, 0x51, + 0x49, 0x76, 0x10, 0xa3, 0x98, 0x12, 0x01, 0x9c, 0x47, 0xd9, 0x5d, 0x38, 0xc3, 0x1c, 0x4f, 0x15, 0xdf, 0x20, 0x84, + 0x9c, 0xd9, 0x74, 0x16, 0xa9, 0x78, 0x50, 0x4a, 0x98, 0x23, 0x93, 0x72, 0x42, 0xc3, 0xf3, 0xfd, 0x53, 0x7e, 0xa7, + 0x4d, 0x36, 0x60, 0xc3, 0x48, 0x35, 0x4b, 0x0d, 0xe7, 0x8a, 0xc9, 0x87, 0x40, 0xa2, 0x32, 0x3a, 0x12, 0x2a, 0x06, + 0xf8, 0x9c, 0x09, 0xaa, 0x74, 0xf0, 0x7d, 0x6b, 0xf7, 0xa5, 0x75, 0x05, 0x32, 0x75, 0xbd, 0x37, 0x80, 0xc8, 0x18, + 0x9c, 0x3b, 0x19, 0xd9, 0x68, 0x76, 0xbe, 0x7f, 0xf2, 0x76, 0x9b, 0x0d, 0xbc, 0x5a, 0x19, 0xeb, 0x57, 0xe9, 0x36, + 0x38, 0xae, 0x20, 0x4d, 0xcd, 0x8f, 0x28, 0x48, 0x95, 0x8a, 0x14, 0x07, 0x02, 0xa8, 0xe8, 0x7c, 0xff, 0xe4, 0x7d, + 0x20, 0x94, 0x6f, 0x09, 0x61, 0x77, 0xd9, 0x01, 0x27, 0xc1, 0x94, 0x50, 0xa4, 0xd7, 0x5e, 0xb2, 0x2e, 0xee, 0x08, + 0xf0, 0x68, 0xaa, 0x2a, 0xc1, 0x82, 0x18, 0xb0, 0x21, 0x49, 0x0d, 0x06, 0x48, 0x8a, 0x70, 0x5a, 0xb3, 0xcb, 0x08, + 0x6c, 0x80, 0x9a, 0xeb, 0x0c, 0x76, 0x22, 0xd4, 0xaa, 0x1f, 0xc2, 0xa9, 0x9a, 0x55, 0x16, 0x5a, 0x78, 0x3c, 0xdb, + 0xc8, 0x4a, 0xab, 0xcc, 0xd1, 0x6f, 0xc1, 0x76, 0xb2, 0x0f, 0x6f, 0x88, 0xb5, 0x24, 0x4c, 0xc1, 0x73, 0x9b, 0x3e, + 0x76, 0xbe, 0x7f, 0xf2, 0xda, 0x64, 0x90, 0xcd, 0x63, 0xcb, 0xef, 0x37, 0x4c, 0xcc, 0x93, 0xd7, 0x61, 0x55, 0xab, + 0x1a, 0x9f, 0xef, 0x9f, 0x7c, 0xd8, 0xd6, 0x0c, 0xca, 0x8b, 0x45, 0x65, 0xe3, 0x2b, 0xf8, 0x96, 0x34, 0x8d, 0x96, + 0x46, 0x38, 0x44, 0xac, 0xc0, 0x4a, 0x20, 0x45, 0x79, 0x51, 0xba, 0x46, 0x9e, 0xe3, 0x8c, 0xa8, 0x30, 0x50, 0x7d, + 0xd7, 0x8c, 0x9a, 0xc7, 0x78, 0x76, 0x36, 0xe2, 0x73, 0xba, 0x23, 0x36, 0x74, 0x83, 0x42, 0x36, 0x83, 0xd4, 0x19, + 0x05, 0x3a, 0xc3, 0x7b, 0x2d, 0xd4, 0xad, 0x8b, 0xaf, 0x4c, 0x11, 0x29, 0xaf, 0xc9, 0x16, 0x3c, 0x25, 0x2d, 0x9c, + 0x92, 0x16, 0x8e, 0x49, 0x3e, 0x68, 0x69, 0x01, 0xd1, 0x8d, 0xcb, 0x71, 0xb5, 0x98, 0x81, 0xac, 0x30, 0x73, 0x5a, + 0xb5, 0x00, 0x4e, 0xba, 0xb1, 0xf2, 0x3d, 0x2a, 0x99, 0x9e, 0x28, 0xb2, 0x78, 0x1f, 0x70, 0xcc, 0xd5, 0xc0, 0x67, + 0xec, 0x32, 0x85, 0xc4, 0x12, 0x58, 0x15, 0x96, 0x28, 0x2a, 0x9b, 0xb6, 0x4d, 0xd3, 0x38, 0x54, 0xfb, 0xc4, 0x71, + 0x1c, 0x02, 0xe7, 0xc6, 0xb1, 0xc9, 0xc3, 0xc9, 0x37, 0xbb, 0x3c, 0x3e, 0x38, 0x08, 0x74, 0xa7, 0x2f, 0x65, 0xc0, + 0x6d, 0x7d, 0x15, 0xb9, 0xfb, 0x56, 0xf3, 0x8a, 0x04, 0x29, 0xf8, 0x1b, 0x8d, 0x74, 0x58, 0x40, 0x18, 0x3a, 0x88, + 0xeb, 0x18, 0xb4, 0xc0, 0x2b, 0x5d, 0xaf, 0xbe, 0xfc, 0x46, 0xa3, 0x8c, 0xd2, 0xd6, 0xb1, 0x75, 0x83, 0xb3, 0xe2, + 0x2a, 0x28, 0x53, 0x7f, 0x5a, 0x1b, 0xf9, 0x52, 0x16, 0x04, 0xc4, 0x5c, 0x9a, 0x65, 0x76, 0x31, 0xce, 0x91, 0x60, + 0xd0, 0xee, 0x4b, 0x93, 0xb5, 0x80, 0x55, 0x76, 0x95, 0x69, 0x64, 0xd9, 0x59, 0x07, 0x45, 0xb6, 0x11, 0x44, 0xa5, + 0xa0, 0x51, 0xa3, 0x30, 0xe4, 0xfd, 0x7e, 0x33, 0xe7, 0x12, 0xe7, 0xc8, 0x38, 0xb9, 0x14, 0x14, 0x0a, 0x59, 0x9d, + 0x12, 0x29, 0x2f, 0xc9, 0x7c, 0x37, 0xc9, 0x9f, 0x38, 0x24, 0xff, 0x8c, 0x50, 0x87, 0xfc, 0xb5, 0x8b, 0x23, 0xe4, + 0xc6, 0xb9, 0x90, 0xdb, 0xaa, 0xd3, 0x39, 0x01, 0x27, 0x5a, 0x1d, 0xa3, 0xb5, 0xb0, 0xe2, 0x0e, 0x86, 0xe2, 0x9e, + 0x10, 0xe5, 0x86, 0xc4, 0x36, 0x06, 0x1c, 0x54, 0x41, 0x35, 0x98, 0x7a, 0x9b, 0x4f, 0xcf, 0xe5, 0x80, 0x27, 0x1f, + 0xee, 0x8e, 0x87, 0x9e, 0xce, 0x37, 0x4f, 0xae, 0x93, 0xfb, 0x09, 0xab, 0x76, 0x0e, 0x6e, 0x3d, 0x13, 0x14, 0xe6, + 0x2f, 0xe3, 0xd8, 0x75, 0xe6, 0xb3, 0x76, 0x08, 0xad, 0xfc, 0x03, 0x68, 0xdb, 0x6d, 0xd5, 0x82, 0x3a, 0xc3, 0x02, + 0x3f, 0xd2, 0x19, 0xa8, 0xb1, 0xd8, 0xc1, 0x3e, 0x4e, 0x54, 0x03, 0x9a, 0x25, 0xdb, 0xab, 0x9f, 0x15, 0x86, 0x4c, + 0x34, 0x68, 0x68, 0x09, 0xfc, 0x4f, 0x93, 0x3c, 0xd0, 0x8d, 0x92, 0x0b, 0x80, 0xa0, 0xb9, 0xc2, 0x53, 0x85, 0x30, + 0xdf, 0xaf, 0xbc, 0xef, 0x2f, 0xf7, 0x08, 0x99, 0x57, 0xde, 0xc7, 0x77, 0x55, 0xea, 0x15, 0x90, 0x05, 0x8a, 0xc0, + 0x7c, 0x2c, 0x0b, 0x74, 0xf8, 0xf2, 0xcc, 0x36, 0x57, 0x26, 0x64, 0x58, 0x69, 0xdc, 0x4e, 0x68, 0x53, 0xb9, 0xe5, + 0x74, 0xbd, 0x45, 0xc3, 0x5a, 0xed, 0x3e, 0xd4, 0xbe, 0x97, 0x0a, 0x46, 0x78, 0x7e, 0xaf, 0x5a, 0xdb, 0x71, 0x8b, + 0x8f, 0xeb, 0xf9, 0x2b, 0x6b, 0x9b, 0x12, 0xb2, 0x2c, 0xa7, 0x42, 0x3e, 0xa3, 0x63, 0x2e, 0x20, 0x66, 0x51, 0xe2, + 0x04, 0x15, 0xfb, 0x8e, 0xdf, 0x4e, 0xad, 0xcf, 0x09, 0x14, 0xac, 0x2d, 0x50, 0xfd, 0xfa, 0xa8, 0x82, 0xd6, 0xe7, + 0xeb, 0xbd, 0xe6, 0x07, 0x07, 0x1f, 0x2a, 0x34, 0x19, 0x28, 0x15, 0x14, 0x0e, 0xd3, 0xd2, 0x2a, 0x8d, 0x89, 0xe4, + 0xee, 0x07, 0xa5, 0x13, 0xc0, 0x32, 0x0c, 0x97, 0xf7, 0xbc, 0x24, 0xb2, 0x98, 0xac, 0xb3, 0x78, 0xe3, 0x9c, 0x60, + 0xae, 0xe1, 0x02, 0x1c, 0x1e, 0x4c, 0x6d, 0xed, 0x2d, 0xca, 0xab, 0x64, 0xd8, 0x12, 0x86, 0x53, 0x40, 0x56, 0xa0, + 0xcc, 0x10, 0x87, 0x02, 0xb7, 0x9a, 0x25, 0xa7, 0xa0, 0x57, 0x4e, 0x71, 0x1e, 0x4e, 0x21, 0xfd, 0xb5, 0x76, 0x64, + 0x11, 0xc2, 0x3a, 0x31, 0xc7, 0x49, 0x25, 0x38, 0x79, 0xb9, 0xcd, 0xa5, 0x6c, 0x89, 0x9a, 0x2a, 0xa9, 0xa3, 0x5a, + 0xa0, 0xb2, 0x43, 0x78, 0x15, 0x30, 0xa3, 0xb8, 0xd9, 0xb8, 0x19, 0x30, 0xe0, 0x67, 0x32, 0xd0, 0xc1, 0x28, 0x90, + 0x19, 0x3c, 0x5c, 0x04, 0xb5, 0xa9, 0xbb, 0x5c, 0x75, 0xc3, 0x06, 0x71, 0x53, 0x17, 0x4d, 0x5c, 0xc5, 0xf5, 0x4e, + 0x2b, 0x5e, 0x3a, 0xd6, 0x19, 0xd4, 0xd2, 0x72, 0xc1, 0x2a, 0x91, 0xc4, 0x59, 0xfe, 0x58, 0x27, 0x45, 0x97, 0x8d, + 0x30, 0x55, 0x60, 0xbc, 0x54, 0x7b, 0x40, 0x0b, 0xa0, 0xaf, 0xe5, 0x89, 0x74, 0x76, 0xd4, 0x3a, 0xb1, 0xd5, 0x9c, + 0x8e, 0xd4, 0x7f, 0x07, 0xa9, 0x2e, 0xeb, 0x67, 0xfe, 0xa5, 0x92, 0x85, 0x0c, 0xe7, 0x35, 0xc6, 0x9e, 0x29, 0xc6, + 0x8e, 0x40, 0x4f, 0xb3, 0x89, 0xdf, 0x7d, 0x93, 0xf1, 0xc2, 0x8c, 0x94, 0x33, 0x24, 0xf6, 0x75, 0x19, 0x2d, 0x77, + 0x7e, 0xaf, 0xed, 0x46, 0xc4, 0x08, 0x64, 0x01, 0x61, 0xc3, 0xd9, 0x33, 0x84, 0xf3, 0x46, 0xa3, 0x9b, 0x1f, 0xd3, + 0xca, 0x49, 0x52, 0xc1, 0xc8, 0x20, 0xa0, 0x0b, 0x04, 0x5f, 0x93, 0xa1, 0x10, 0xf2, 0xb7, 0x99, 0xd9, 0x39, 0xf8, + 0xda, 0x4f, 0xde, 0x05, 0x2e, 0x57, 0x73, 0xdb, 0x96, 0x41, 0x53, 0x58, 0x4f, 0x50, 0x05, 0x5c, 0xbe, 0xbe, 0x3b, + 0xc1, 0x03, 0xe0, 0xde, 0x6b, 0x63, 0x48, 0x45, 0x43, 0x5d, 0xa9, 0x59, 0x42, 0x79, 0xfa, 0xba, 0xa8, 0xca, 0x4a, + 0x74, 0x27, 0xeb, 0xca, 0xca, 0x98, 0x95, 0x24, 0x2f, 0x8a, 0x9c, 0x56, 0xe1, 0xfd, 0xb5, 0xf4, 0x4b, 0x25, 0x5c, + 0x36, 0xbd, 0xed, 0xa7, 0x73, 0x22, 0xb1, 0x43, 0xa8, 0x5f, 0xef, 0x8a, 0x7d, 0x54, 0x60, 0xc2, 0xb9, 0x36, 0x42, + 0xf1, 0xe7, 0x6d, 0x42, 0x11, 0x67, 0xe6, 0xc8, 0x2b, 0x81, 0xd8, 0xbe, 0x87, 0x40, 0x34, 0x6e, 0x76, 0x2b, 0x13, + 0x41, 0x1d, 0xa9, 0xc9, 0xc4, 0xfa, 0x96, 0x92, 0x0c, 0x33, 0xb3, 0x1b, 0xbd, 0xce, 0x6a, 0xc5, 0x06, 0x2d, 0x70, + 0x23, 0xf9, 0x3e, 0xfc, 0x6c, 0xeb, 0x9f, 0x0e, 0x27, 0xd6, 0x6e, 0xe0, 0x80, 0x95, 0x26, 0x0b, 0x0a, 0x21, 0xc1, + 0x39, 0x50, 0x49, 0x59, 0x8a, 0xa6, 0x0d, 0x05, 0x19, 0x02, 0x27, 0xac, 0x0c, 0x33, 0x01, 0xc4, 0x4a, 0x56, 0x18, + 0x03, 0x32, 0xd8, 0x9a, 0xfb, 0x67, 0xcd, 0xcb, 0x4f, 0x6b, 0xa2, 0x35, 0xb9, 0xa2, 0xd5, 0x87, 0x5a, 0xbe, 0x81, + 0x81, 0xc0, 0xe8, 0x87, 0x7b, 0xca, 0x04, 0xad, 0x44, 0x39, 0x72, 0xe5, 0x10, 0x6e, 0x81, 0x13, 0x6d, 0xef, 0x83, + 0x8e, 0xf0, 0x6e, 0x91, 0x26, 0x98, 0x3b, 0x74, 0xfd, 0x92, 0xc8, 0x1a, 0x2b, 0x99, 0x12, 0x63, 0x29, 0xe1, 0x58, + 0x91, 0xa9, 0x24, 0xd9, 0xa0, 0x35, 0x04, 0x05, 0xb4, 0x9b, 0x1e, 0x67, 0x95, 0x09, 0x9c, 0x36, 0x1a, 0x28, 0xb6, + 0xb3, 0x4e, 0x07, 0xac, 0x91, 0x0e, 0x31, 0xc5, 0xa9, 0x36, 0x4c, 0xce, 0x0e, 0x0e, 0x82, 0xb8, 0x9a, 0x77, 0x90, + 0x0e, 0x11, 0xe6, 0xab, 0x55, 0xa0, 0xc0, 0x8a, 0xd1, 0x6a, 0x15, 0xbb, 0x60, 0xa9, 0x6a, 0xe8, 0x36, 0xef, 0x4b, + 0x32, 0x57, 0x02, 0x70, 0x0e, 0x10, 0x36, 0x48, 0x10, 0x1b, 0xf7, 0x5e, 0x0c, 0xee, 0xa8, 0x46, 0x36, 0x48, 0x1b, + 0xed, 0xa1, 0xc3, 0xb8, 0x06, 0xe9, 0x90, 0xc4, 0x05, 0x3f, 0x38, 0xd8, 0xcb, 0x8d, 0x88, 0xfc, 0x09, 0x44, 0xd9, + 0x4f, 0x4a, 0xb2, 0xe8, 0x01, 0xdd, 0xdd, 0x58, 0x77, 0x06, 0x94, 0x14, 0x65, 0xb6, 0xd5, 0xb6, 0xab, 0x65, 0x41, + 0x94, 0x8d, 0xb0, 0x09, 0x06, 0xf7, 0xc1, 0xb2, 0x2f, 0xc9, 0xfc, 0x95, 0x2c, 0x73, 0xac, 0x7f, 0xde, 0x9a, 0x59, + 0x1d, 0x86, 0x61, 0x2c, 0x26, 0x2a, 0x96, 0x61, 0xc3, 0xb0, 0x8a, 0xf8, 0x8f, 0x0c, 0x98, 0xce, 0xc4, 0x83, 0x72, + 0xae, 0x21, 0xd1, 0xe0, 0x5b, 0xd5, 0xc6, 0xde, 0x25, 0xf9, 0x69, 0xab, 0x97, 0x41, 0x43, 0xf2, 0xfc, 0xb7, 0x42, + 0xf2, 0xd0, 0x40, 0xa2, 0xc9, 0x63, 0x0d, 0x67, 0x3b, 0x70, 0xf1, 0x93, 0x5c, 0xc3, 0xd9, 0x6e, 0xdc, 0x5a, 0x4c, + 0xfd, 0xb2, 0x0b, 0x3e, 0x87, 0x37, 0x68, 0x40, 0xab, 0x02, 0x07, 0xca, 0x47, 0xeb, 0xba, 0x97, 0x66, 0xa5, 0x20, + 0x4c, 0x25, 0x09, 0x58, 0xfd, 0x00, 0x54, 0xda, 0xa8, 0x63, 0xf8, 0xb2, 0x68, 0x8e, 0x1c, 0x97, 0x40, 0x3d, 0x75, + 0x05, 0xc8, 0xc9, 0x78, 0xdb, 0xe7, 0x07, 0x07, 0x60, 0x1b, 0x80, 0x12, 0x17, 0x8e, 0xe2, 0xb9, 0x5c, 0x08, 0x50, + 0xa5, 0x72, 0xfb, 0x1b, 0x8a, 0xe1, 0x16, 0x88, 0x2a, 0x83, 0x1f, 0x50, 0x30, 0x8f, 0xf3, 0x9c, 0x5d, 0xe9, 0x32, + 0xf3, 0x1b, 0x73, 0x62, 0x49, 0x39, 0xd7, 0x3a, 0x61, 0x86, 0xba, 0x99, 0xa1, 0xd3, 0x3a, 0xda, 0x5e, 0x5c, 0xd1, + 0x4c, 0xbe, 0x62, 0xb9, 0xa4, 0x19, 0x2c, 0xbf, 0xa2, 0x38, 0x58, 0x51, 0x8e, 0xe0, 0xc0, 0xd6, 0x7a, 0xc5, 0x49, + 0x72, 0x67, 0x17, 0x59, 0xd7, 0x81, 0xa6, 0x71, 0x96, 0xa4, 0x7a, 0x12, 0x37, 0x9f, 0xd1, 0xe6, 0x70, 0x96, 0x2d, + 0xdd, 0x7c, 0x9a, 0x4a, 0xd9, 0x50, 0xdc, 0x3d, 0x60, 0xc4, 0x4a, 0x02, 0x2b, 0x3d, 0xef, 0xd4, 0x5a, 0x20, 0xe2, + 0xbd, 0x63, 0x13, 0xdc, 0x95, 0x60, 0xe9, 0x70, 0xd4, 0xb0, 0x0e, 0xa7, 0xa5, 0x9b, 0x2f, 0xb7, 0x5e, 0x69, 0xdb, + 0x26, 0x1c, 0x14, 0x9d, 0x3c, 0xde, 0x6d, 0x59, 0xbd, 0xb6, 0x92, 0xc3, 0x4a, 0x0b, 0x76, 0x5f, 0xc6, 0x8c, 0x96, + 0x96, 0xbc, 0x90, 0x3d, 0x8a, 0xfb, 0x92, 0x3c, 0x87, 0x3b, 0x43, 0x2f, 0xe5, 0x2c, 0x5d, 0xbb, 0x1a, 0xd3, 0xdd, + 0x2f, 0xb5, 0xff, 0x7d, 0x19, 0xbc, 0xc4, 0xef, 0x21, 0xb0, 0xfb, 0x55, 0xd5, 0x7c, 0x33, 0xa0, 0xfb, 0x55, 0x85, + 0xa0, 0xaf, 0xa2, 0x8d, 0x76, 0x4e, 0x20, 0xb7, 0x13, 0x3e, 0x0d, 0x5b, 0xbe, 0xd5, 0x96, 0x7e, 0xd6, 0x61, 0x24, + 0x9d, 0x69, 0xa9, 0xce, 0x03, 0xae, 0xf2, 0xd4, 0x20, 0x5f, 0xae, 0x6e, 0x21, 0x51, 0x93, 0x61, 0xa8, 0x75, 0xf8, + 0x5d, 0xdb, 0x63, 0x64, 0x4c, 0xa6, 0xed, 0x8c, 0xaf, 0x63, 0x21, 0xf7, 0xe1, 0x94, 0xf1, 0x8d, 0x7b, 0x78, 0x53, + 0x02, 0x1e, 0xb4, 0xfb, 0x4d, 0xe1, 0x18, 0xdb, 0xb9, 0xbe, 0x07, 0xe4, 0x8e, 0x4f, 0xb8, 0xd5, 0xdd, 0xea, 0x56, + 0xc6, 0xd7, 0x60, 0xff, 0x23, 0x3c, 0xb5, 0x97, 0xe3, 0xa8, 0xe1, 0xc0, 0x34, 0x5a, 0x16, 0xa5, 0x53, 0x80, 0x6b, + 0xe5, 0x4d, 0x20, 0xcc, 0x0b, 0x15, 0xe0, 0xfe, 0x01, 0x7f, 0x63, 0x58, 0xe2, 0xb8, 0xe4, 0x38, 0x27, 0xf7, 0xe5, + 0x88, 0x1a, 0xfc, 0x32, 0x7e, 0x0f, 0x74, 0xac, 0x28, 0xb4, 0xb0, 0x54, 0xf4, 0x9c, 0x9b, 0x85, 0xec, 0x4c, 0x4b, + 0xc5, 0xb4, 0x4c, 0xa9, 0x51, 0xd3, 0x6c, 0xc9, 0xe3, 0xb4, 0x56, 0xb6, 0x2c, 0x4f, 0x55, 0x6d, 0x5e, 0xb4, 0x03, + 0x8b, 0x55, 0x68, 0x71, 0xb5, 0x0a, 0xea, 0xa8, 0x26, 0xcc, 0x89, 0x64, 0x20, 0xcc, 0x9c, 0x8c, 0x8a, 0x9a, 0x66, + 0xad, 0xfb, 0x04, 0x68, 0x3d, 0xa1, 0xc8, 0xea, 0xe6, 0x35, 0x38, 0x5c, 0x17, 0x82, 0xee, 0xee, 0xfa, 0x14, 0xb0, + 0x5e, 0x5d, 0x39, 0x91, 0x83, 0xa1, 0x9f, 0xcb, 0x54, 0xd9, 0x2a, 0xa7, 0x75, 0x0b, 0x7e, 0xd1, 0x1d, 0xc9, 0xb2, + 0x06, 0x75, 0x9b, 0xf5, 0x4e, 0xb2, 0xd1, 0x73, 0xbe, 0x2b, 0xd9, 0xa8, 0xa6, 0xed, 0xee, 0xb5, 0xd0, 0xdd, 0x69, + 0xa9, 0x7a, 0xae, 0xed, 0x4d, 0x7e, 0xc3, 0x74, 0x6d, 0xa0, 0x4d, 0x8d, 0x66, 0xcb, 0x55, 0xce, 0x8a, 0x62, 0x5c, + 0x5e, 0x26, 0x50, 0xb9, 0x3b, 0x63, 0x4d, 0xff, 0xc6, 0x6a, 0x54, 0xd7, 0x71, 0x83, 0x1f, 0xc8, 0x24, 0xe5, 0x97, + 0x71, 0xfa, 0x1e, 0xe6, 0xab, 0x2a, 0x5f, 0xde, 0x26, 0x22, 0x96, 0xd4, 0x70, 0x97, 0x0a, 0x86, 0x1f, 0x1c, 0x18, + 0x7e, 0xd0, 0x7c, 0xba, 0xea, 0x8f, 0x97, 0xaf, 0xca, 0x01, 0xa2, 0x71, 0x61, 0x59, 0xc6, 0xb9, 0xdc, 0x3e, 0xc7, + 0x3a, 0x0b, 0x3b, 0x2f, 0x59, 0xd8, 0xb9, 0x0c, 0xd6, 0x87, 0x0a, 0x82, 0x6f, 0xb6, 0x8f, 0xb2, 0xc9, 0xd9, 0xbe, + 0xa9, 0x0e, 0xfe, 0x37, 0xd1, 0x9d, 0x7d, 0x1c, 0x2e, 0x77, 0x14, 0x1e, 0xa9, 0x74, 0x15, 0x0d, 0xf2, 0x3b, 0x48, + 0x3b, 0x90, 0xa4, 0xe7, 0xdc, 0x39, 0xa8, 0xe4, 0x94, 0x4d, 0x04, 0x0a, 0x46, 0x8b, 0x5c, 0xf2, 0x99, 0x19, 0x33, + 0x37, 0xd7, 0x8c, 0x54, 0x25, 0xb8, 0xa2, 0x55, 0xb4, 0x3d, 0xaa, 0x5f, 0xe4, 0x5a, 0x7e, 0x64, 0x59, 0x12, 0xe5, + 0xd8, 0x48, 0x91, 0x3c, 0xca, 0x0a, 0x62, 0x93, 0x8d, 0x37, 0xeb, 0xf0, 0x98, 0x65, 0x2c, 0x9f, 0x52, 0x11, 0x70, + 0xb4, 0xdc, 0x35, 0x19, 0x87, 0x80, 0x8c, 0x9e, 0x0c, 0x7f, 0x5b, 0x5d, 0xf8, 0x0b, 0x61, 0x34, 0xf0, 0x03, 0xcd, + 0xa8, 0x9c, 0xf2, 0x04, 0x12, 0x53, 0xc2, 0xa4, 0xbc, 0xd1, 0x74, 0x70, 0xb0, 0x17, 0xf8, 0xca, 0x2d, 0x01, 0x57, + 0xbf, 0xdd, 0x1a, 0xd4, 0x5f, 0xc2, 0xf5, 0x9c, 0x6a, 0x6a, 0x8a, 0x96, 0x74, 0xfd, 0x26, 0x8b, 0x0c, 0x3f, 0xd2, + 0x5b, 0x2c, 0x50, 0x51, 0x44, 0x1a, 0x6a, 0x7f, 0xcc, 0x68, 0x9a, 0xf8, 0xf8, 0x23, 0xbd, 0x8d, 0xca, 0xdb, 0xe2, + 0xea, 0x72, 0xb3, 0xda, 0x40, 0x9f, 0x5f, 0x67, 0x3e, 0xae, 0x26, 0x89, 0x96, 0x05, 0xe6, 0x82, 0x4d, 0x80, 0x38, + 0xff, 0x46, 0x6f, 0x23, 0x3d, 0x1e, 0x73, 0x2e, 0xeb, 0xa1, 0xa5, 0x45, 0x7d, 0xe8, 0x14, 0xbb, 0xdb, 0x60, 0x0c, + 0x8a, 0x81, 0xea, 0x3b, 0x24, 0xb5, 0x76, 0x95, 0x79, 0x88, 0x50, 0x71, 0xdf, 0xa5, 0xe0, 0x2f, 0x5c, 0xd1, 0x26, + 0x6b, 0xa9, 0xaf, 0x6b, 0x9d, 0x28, 0x74, 0xa8, 0x72, 0x3d, 0xce, 0x03, 0x61, 0x4f, 0x9d, 0xb9, 0x83, 0xe0, 0x38, + 0xc2, 0xbe, 0x90, 0x66, 0xd0, 0xe8, 0x5b, 0x9d, 0x12, 0x52, 0x45, 0x92, 0x5e, 0x57, 0xfd, 0xbc, 0xf3, 0x00, 0xf0, + 0x0e, 0x29, 0x2d, 0xb1, 0xba, 0x8e, 0x59, 0xd8, 0x74, 0xd1, 0xef, 0x24, 0x09, 0x96, 0x76, 0x09, 0x91, 0x70, 0xb1, + 0x28, 0x0b, 0xa0, 0x42, 0x43, 0x5f, 0x3a, 0x03, 0x90, 0x8d, 0x03, 0xb6, 0x21, 0x35, 0x33, 0x25, 0x35, 0x43, 0x07, + 0xe3, 0x3b, 0xa4, 0x24, 0x55, 0xc8, 0x50, 0x4a, 0xa4, 0x12, 0x7a, 0x66, 0x73, 0x0d, 0x09, 0xb9, 0x1b, 0x5a, 0x5e, + 0x9f, 0xd3, 0x7b, 0x9e, 0xd5, 0xc0, 0x0a, 0xd4, 0x38, 0xa8, 0x88, 0x60, 0x49, 0x54, 0x37, 0x28, 0xac, 0x3b, 0x47, + 0xd8, 0xfc, 0xd6, 0x80, 0x87, 0x76, 0x59, 0xc4, 0xa2, 0x24, 0x98, 0xa2, 0xa5, 0x08, 0xa6, 0x38, 0x83, 0x7c, 0x44, + 0x5e, 0x94, 0xf0, 0x53, 0x77, 0x37, 0x6a, 0xd9, 0xca, 0xdb, 0xaf, 0xf8, 0x81, 0x32, 0x2f, 0x21, 0x47, 0x13, 0x0b, + 0xcb, 0x53, 0x44, 0xa0, 0xee, 0xda, 0x39, 0xdb, 0xf6, 0x95, 0x49, 0xd1, 0x31, 0x80, 0x7d, 0x27, 0x83, 0xa5, 0xb3, + 0x0a, 0xf7, 0x2e, 0xb7, 0xb9, 0xf2, 0x67, 0x82, 0x7d, 0x55, 0x12, 0x69, 0x90, 0x93, 0x35, 0x89, 0x73, 0x77, 0xae, + 0xe5, 0xcf, 0x0b, 0x2a, 0x6e, 0xcf, 0x28, 0xe4, 0x3a, 0x73, 0xb8, 0xeb, 0x5b, 0x6d, 0x43, 0x95, 0xa7, 0xde, 0xcf, + 0x94, 0xb2, 0x52, 0xd4, 0x2f, 0x01, 0xae, 0x5f, 0x11, 0x2c, 0x54, 0xb4, 0xd1, 0x71, 0xc4, 0xe8, 0xd3, 0x42, 0x77, + 0x5e, 0x9e, 0xa4, 0x5d, 0x06, 0xfe, 0xb5, 0x0a, 0xd3, 0x26, 0x58, 0x80, 0xb9, 0x7b, 0x21, 0x75, 0x90, 0x0f, 0xd7, + 0xbd, 0x32, 0x50, 0x04, 0xe1, 0xbb, 0x6c, 0xf7, 0x52, 0xb7, 0x65, 0xcd, 0xee, 0x5e, 0x6a, 0x2d, 0xe8, 0xa7, 0x52, + 0x7e, 0xb0, 0x99, 0xa7, 0xbc, 0xbc, 0xcc, 0x8a, 0x02, 0x15, 0x00, 0xde, 0xf7, 0xdd, 0x20, 0xf8, 0xde, 0x24, 0x0d, + 0x86, 0x10, 0x8b, 0x3d, 0x4b, 0xb9, 0x65, 0xe2, 0xd5, 0xfc, 0xdf, 0x6f, 0xcc, 0xff, 0xbd, 0x73, 0xe5, 0x14, 0x4c, + 0xa3, 0x49, 0x46, 0x13, 0xcb, 0x3a, 0x91, 0x26, 0x40, 0xa5, 0xb7, 0xe5, 0x92, 0x7c, 0xbc, 0x88, 0x40, 0xe3, 0x5a, + 0x8e, 0x79, 0x26, 0x9b, 0xe3, 0x78, 0xc6, 0xd2, 0xdb, 0x68, 0xc1, 0x9a, 0x33, 0x9e, 0xf1, 0x7c, 0x1e, 0x8f, 0x28, + 0xce, 0x6f, 0x73, 0x49, 0x67, 0xcd, 0x05, 0xc3, 0x2f, 0x69, 0x7a, 0x45, 0x25, 0x1b, 0xc5, 0xd8, 0x3f, 0x11, 0x2c, + 0x4e, 0xbd, 0x37, 0xb1, 0x10, 0xfc, 0xda, 0xc7, 0xef, 0xf8, 0x25, 0x97, 0x1c, 0xbf, 0xbd, 0xb9, 0x9d, 0xd0, 0x0c, + 0x7f, 0xb8, 0x5c, 0x64, 0x72, 0x81, 0xf3, 0x38, 0xcb, 0x9b, 0x39, 0x15, 0x6c, 0xdc, 0x1d, 0xf1, 0x94, 0x8b, 0x26, + 0xa4, 0x6c, 0xcf, 0x68, 0x94, 0xb2, 0xc9, 0x54, 0x7a, 0x49, 0x2c, 0x3e, 0x76, 0x9b, 0xcd, 0xb9, 0x60, 0xb3, 0x58, + 0xdc, 0x36, 0x55, 0x8b, 0xe8, 0xb3, 0xd6, 0x51, 0xfc, 0xf9, 0xf8, 0x61, 0x57, 0x8a, 0x38, 0xcb, 0x19, 0x6c, 0x53, + 0x14, 0xa7, 0xa9, 0x77, 0xf4, 0xa8, 0x35, 0xcb, 0xf7, 0x74, 0x20, 0x2f, 0xce, 0x64, 0x71, 0x81, 0x3f, 0x02, 0xdc, + 0xe1, 0xa5, 0xcc, 0xf0, 0xe5, 0x42, 0x4a, 0x9e, 0x2d, 0x47, 0x0b, 0x91, 0x73, 0x11, 0xcd, 0x39, 0xcb, 0x24, 0x15, + 0xdd, 0x4b, 0x2e, 0x12, 0x2a, 0x9a, 0x22, 0x4e, 0xd8, 0x22, 0x8f, 0x1e, 0xce, 0x6f, 0xba, 0xa0, 0x59, 0x4c, 0x04, + 0x5f, 0x64, 0x89, 0x99, 0x8b, 0x65, 0x53, 0x2a, 0x98, 0x74, 0x2b, 0xd4, 0x2b, 0x4c, 0xa2, 0x94, 0x65, 0x34, 0x16, + 0xcd, 0x09, 0x74, 0x06, 0xb3, 0xa8, 0x95, 0xd0, 0x09, 0x16, 0x93, 0xcb, 0x38, 0x68, 0x77, 0x9e, 0x60, 0xfb, 0x37, + 0x7c, 0x84, 0xbc, 0xd6, 0xf6, 0xe2, 0x76, 0xab, 0xf5, 0x27, 0xd4, 0x5d, 0x9b, 0x45, 0x01, 0x14, 0xb5, 0xe7, 0x37, + 0x5e, 0xce, 0x21, 0xa7, 0x6d, 0x5b, 0xcf, 0xee, 0x3c, 0x4e, 0x20, 0x21, 0x38, 0xea, 0xcc, 0x6f, 0x0a, 0x58, 0x5d, + 0xa4, 0x93, 0x4c, 0xcd, 0x22, 0xcd, 0xd3, 0xf2, 0xb7, 0x42, 0xfc, 0x74, 0x3b, 0xc4, 0x1d, 0x0b, 0x71, 0x85, 0xf5, + 0x66, 0xb2, 0x10, 0x2a, 0xb6, 0x1a, 0xb5, 0x73, 0x0d, 0xc8, 0x94, 0x5f, 0x51, 0x61, 0xe1, 0x50, 0x0f, 0xbf, 0x19, + 0x8c, 0xce, 0x76, 0x30, 0x9e, 0x7e, 0x0a, 0x0c, 0x91, 0x25, 0xcb, 0xfa, 0xbe, 0xb6, 0x05, 0x9d, 0x75, 0xa7, 0x14, + 0xe8, 0x29, 0xea, 0xc0, 0xef, 0x6b, 0x96, 0xc8, 0xa9, 0xfe, 0xa9, 0xc8, 0xf9, 0x5a, 0xd7, 0x3d, 0x6a, 0xb5, 0xf4, + 0x73, 0xce, 0x7e, 0xa1, 0x51, 0x3b, 0x84, 0x06, 0xc5, 0x05, 0xfe, 0x5b, 0x79, 0x99, 0xb7, 0xce, 0x3d, 0xf1, 0x0f, + 0xee, 0x2d, 0x5f, 0x27, 0x49, 0xb1, 0xba, 0x11, 0x8d, 0x85, 0x95, 0x95, 0x5a, 0xf8, 0x80, 0xdb, 0x4e, 0x9d, 0x27, + 0xc2, 0x7a, 0xe5, 0x2d, 0x4e, 0xd6, 0xff, 0x41, 0xe7, 0x5d, 0x44, 0x10, 0xe9, 0x70, 0x92, 0x0d, 0x79, 0x37, 0xeb, + 0x91, 0x56, 0x37, 0x6b, 0x36, 0x51, 0xc0, 0x89, 0x18, 0x64, 0x26, 0x3d, 0x2f, 0x60, 0x7d, 0xae, 0x8c, 0xed, 0x1c, + 0x45, 0x1c, 0xae, 0x9a, 0xae, 0x56, 0x55, 0x18, 0x80, 0xa9, 0xeb, 0x1a, 0x7f, 0x93, 0xa6, 0x01, 0xce, 0x1d, 0x4e, + 0x9e, 0xd9, 0x17, 0xbb, 0x08, 0xcb, 0x2b, 0x52, 0x3e, 0x52, 0x98, 0x0b, 0xe7, 0xb1, 0x9c, 0x82, 0x97, 0xa2, 0x14, + 0x3f, 0x55, 0x12, 0x93, 0x7f, 0xe8, 0xa3, 0xbe, 0x28, 0x33, 0xdc, 0x20, 0x93, 0x4f, 0x14, 0x30, 0xca, 0x37, 0x92, + 0xc0, 0x88, 0xf8, 0x17, 0xa2, 0x6d, 0x3a, 0x6b, 0xd1, 0x8d, 0xef, 0x6b, 0xd1, 0xd1, 0x4c, 0x32, 0x95, 0xbb, 0x6d, + 0x23, 0x0e, 0xd3, 0x38, 0x3f, 0x1f, 0xe9, 0xbb, 0x92, 0x79, 0x75, 0x33, 0x20, 0x56, 0xd0, 0x6b, 0x23, 0x8d, 0x0a, + 0x65, 0x8f, 0x7e, 0x2f, 0x77, 0xda, 0x27, 0xe2, 0x2e, 0xfb, 0xa4, 0x5c, 0x78, 0xce, 0x17, 0x62, 0x04, 0xe1, 0x48, + 0x23, 0xf5, 0x36, 0x1d, 0x37, 0xbe, 0x52, 0x31, 0x7c, 0x2c, 0x9d, 0x4c, 0x50, 0x89, 0x99, 0xfb, 0x52, 0x09, 0xaa, + 0x42, 0x5e, 0xfa, 0xbe, 0x86, 0x11, 0x71, 0x76, 0x49, 0x20, 0xb3, 0x13, 0x95, 0xd4, 0x18, 0x64, 0xa4, 0x97, 0x85, + 0x8b, 0x8c, 0xfd, 0xbc, 0xa0, 0xe7, 0x0c, 0x74, 0x4d, 0x16, 0xb2, 0x44, 0xc5, 0x9a, 0x40, 0xf6, 0x35, 0xdb, 0x10, + 0xbc, 0x60, 0x89, 0xde, 0x98, 0x4c, 0x55, 0x9a, 0xdc, 0x26, 0xbf, 0xe9, 0x83, 0xbf, 0x18, 0xb4, 0x03, 0x86, 0x13, + 0x3e, 0x8b, 0x59, 0x16, 0x29, 0x97, 0x6f, 0x39, 0x58, 0x04, 0xad, 0x31, 0x4b, 0xa2, 0xcc, 0x6c, 0x4f, 0x1b, 0x85, + 0x3f, 0x71, 0x96, 0xa9, 0xae, 0x45, 0x97, 0x2b, 0x84, 0x6a, 0xf4, 0x11, 0x8b, 0xe0, 0x13, 0x2d, 0xd7, 0x38, 0xc2, + 0x6e, 0x75, 0x79, 0xed, 0xbc, 0xb6, 0x03, 0xad, 0xb5, 0x8d, 0xd2, 0x46, 0x00, 0x5f, 0x2f, 0xcd, 0xb9, 0x90, 0x41, + 0x30, 0xc5, 0x29, 0x22, 0xbd, 0xa9, 0x72, 0x76, 0x1d, 0xa7, 0xea, 0xbf, 0x7e, 0xb3, 0x1d, 0xb5, 0x4b, 0xf3, 0xbd, + 0x76, 0x1b, 0x58, 0x27, 0x47, 0x99, 0x1b, 0xa5, 0x6a, 0x19, 0xe5, 0x6f, 0xbd, 0xd4, 0xea, 0xb9, 0x5c, 0x2e, 0x36, + 0xc7, 0x4d, 0x8b, 0xaa, 0xa0, 0x06, 0x84, 0x0a, 0x16, 0xed, 0x98, 0x0a, 0x15, 0xd5, 0xba, 0x4b, 0x55, 0xf2, 0x42, + 0x8b, 0xe8, 0xf3, 0xfd, 0xa5, 0x30, 0x33, 0x16, 0x17, 0xcc, 0x3a, 0x99, 0xea, 0x24, 0x57, 0x18, 0x8c, 0x38, 0x7a, + 0xe8, 0xb6, 0x66, 0x1a, 0x96, 0x5b, 0x22, 0xb6, 0xd2, 0x6d, 0xa8, 0x1f, 0xa9, 0x20, 0x55, 0xb8, 0x6b, 0x63, 0x00, + 0xc8, 0xd5, 0xdb, 0x06, 0x18, 0x98, 0xad, 0xb9, 0xb4, 0x4b, 0x00, 0x6d, 0x6c, 0x4c, 0xe1, 0x22, 0xcd, 0xc5, 0xfe, + 0xf2, 0x1b, 0x59, 0x1c, 0x3a, 0x4d, 0xd5, 0x6f, 0x96, 0xc0, 0xff, 0x20, 0x01, 0x97, 0x5a, 0x29, 0x8d, 0xfc, 0xaf, + 0xdf, 0x9e, 0xbd, 0xf7, 0xf1, 0x25, 0x4f, 0x6e, 0x23, 0x5f, 0x8a, 0x05, 0xf5, 0x0b, 0x14, 0xca, 0x29, 0xcd, 0xca, + 0x97, 0xf1, 0xf0, 0x94, 0x86, 0x29, 0x9f, 0xe8, 0x4b, 0x99, 0xeb, 0x46, 0xf2, 0xe8, 0xe2, 0x58, 0xbd, 0x64, 0xaa, + 0x77, 0x2c, 0xf5, 0xeb, 0xbd, 0xa4, 0x80, 0x9f, 0x3d, 0x08, 0xa1, 0x1c, 0x1f, 0xca, 0xa9, 0x7a, 0x38, 0x83, 0x03, + 0xa3, 0x9e, 0xf6, 0x97, 0x1b, 0xc4, 0xd4, 0x87, 0x21, 0xa6, 0x3d, 0xbd, 0x84, 0x5c, 0xb5, 0xba, 0x88, 0x46, 0x17, + 0x17, 0xc5, 0xf1, 0x21, 0x8c, 0x75, 0x68, 0xc7, 0x05, 0x08, 0x6d, 0xff, 0x92, 0xc0, 0xe0, 0x65, 0x43, 0x82, 0xf4, + 0x60, 0x08, 0x98, 0x37, 0xe9, 0xc1, 0x22, 0x81, 0xc0, 0xa0, 0x77, 0x52, 0x96, 0xa8, 0x13, 0xab, 0x8b, 0x76, 0x41, + 0xa0, 0x1b, 0x56, 0x74, 0xaf, 0xbd, 0xa9, 0xd5, 0xfe, 0x5a, 0x90, 0x12, 0x17, 0xba, 0x0b, 0x04, 0xff, 0x2b, 0xc8, + 0x8e, 0x0f, 0x35, 0x1e, 0x2e, 0xdc, 0x57, 0x9b, 0xe8, 0xd7, 0x0e, 0x94, 0xd8, 0x1a, 0xe4, 0x12, 0x7f, 0x94, 0xf8, + 0xe3, 0x85, 0x6a, 0x6a, 0x85, 0x11, 0x68, 0x49, 0x20, 0xb4, 0x5b, 0x56, 0xeb, 0x18, 0xf1, 0x34, 0x8d, 0xe7, 0x39, + 0x8d, 0xec, 0x0f, 0x23, 0x97, 0x40, 0xbc, 0x6d, 0x2a, 0x02, 0x26, 0xbd, 0xe6, 0x14, 0xd4, 0x85, 0x4d, 0x2d, 0xe5, + 0x2a, 0x16, 0x41, 0xb3, 0x39, 0x6a, 0x5e, 0x4e, 0x50, 0x21, 0xa7, 0x4b, 0x57, 0xaa, 0x3d, 0x6e, 0xb5, 0xba, 0x90, + 0x0b, 0xd9, 0x8c, 0x53, 0x36, 0xc9, 0xa2, 0x94, 0x8e, 0x65, 0x21, 0xe1, 0x96, 0xda, 0xd2, 0xaa, 0x11, 0x61, 0xe7, + 0x91, 0xa0, 0x33, 0x2f, 0x84, 0x7f, 0xef, 0x9e, 0xb8, 0x90, 0x49, 0x94, 0xc9, 0x69, 0x53, 0x65, 0xdd, 0xc2, 0x9d, + 0x01, 0x39, 0xad, 0x3d, 0x2f, 0x9d, 0x89, 0x46, 0x14, 0x54, 0xac, 0x42, 0x0a, 0x4f, 0x4e, 0xb1, 0x14, 0x6e, 0xbb, + 0x0c, 0x2d, 0x37, 0x56, 0xb0, 0x29, 0xe9, 0x8f, 0x50, 0x91, 0x2b, 0xc5, 0x78, 0xb3, 0xb1, 0x55, 0x97, 0xea, 0x4f, + 0x1b, 0xe8, 0x73, 0x14, 0xbb, 0x42, 0x3b, 0x96, 0x97, 0xba, 0xc7, 0x7d, 0x90, 0x59, 0x53, 0x39, 0xb1, 0xdb, 0x03, + 0x15, 0x2c, 0x9b, 0x2f, 0xe4, 0x40, 0x39, 0xb5, 0x05, 0x5c, 0x90, 0x18, 0x62, 0xa7, 0x04, 0x70, 0x30, 0x5c, 0x6a, + 0x60, 0x46, 0x71, 0x3a, 0x0a, 0x00, 0x22, 0xaf, 0xe9, 0x3d, 0x15, 0x74, 0x86, 0xba, 0x33, 0x96, 0x35, 0x75, 0xdd, + 0x23, 0x47, 0x2d, 0x09, 0x9f, 0xc0, 0x53, 0x11, 0xaa, 0xd1, 0xb0, 0xca, 0x5d, 0xdd, 0x82, 0xcb, 0x8b, 0x61, 0x51, + 0x74, 0x85, 0x0c, 0x06, 0xaf, 0x03, 0x34, 0xc4, 0xbf, 0x38, 0x2f, 0x67, 0xf1, 0xed, 0x51, 0xf1, 0x71, 0x07, 0xed, + 0x68, 0xe2, 0x9e, 0x05, 0xd5, 0xec, 0x17, 0x02, 0x0d, 0xdf, 0x05, 0x3e, 0xcd, 0xe7, 0x4d, 0xcd, 0xbb, 0x9a, 0x8a, + 0x64, 0x7d, 0xe8, 0x8a, 0x8c, 0xa7, 0xf6, 0x7b, 0xb9, 0x54, 0x6c, 0xc9, 0x5c, 0xd2, 0xd0, 0xce, 0x84, 0x61, 0x79, + 0xa9, 0xc7, 0x3c, 0xbb, 0xd7, 0x78, 0x50, 0x8d, 0x9f, 0x5c, 0x9c, 0xd4, 0x79, 0x1c, 0xf0, 0xa5, 0xf2, 0x05, 0x76, + 0x71, 0x9a, 0xc2, 0x84, 0x17, 0x56, 0x7d, 0x71, 0x5f, 0xfa, 0x31, 0x90, 0xc3, 0x00, 0x15, 0xe6, 0x9c, 0x3e, 0x53, + 0x2a, 0xa5, 0xf3, 0xd6, 0xbc, 0x3d, 0x69, 0x83, 0x45, 0x5a, 0xfa, 0x32, 0x08, 0x77, 0xd7, 0xf2, 0xa2, 0xbb, 0x15, + 0xef, 0xd2, 0x0a, 0xa9, 0xa7, 0x16, 0x44, 0x7c, 0x91, 0x25, 0xbe, 0xf7, 0x97, 0x51, 0xca, 0x46, 0x1f, 0x89, 0xbf, + 0xbf, 0x0c, 0xd0, 0xe6, 0xb5, 0x47, 0xc5, 0x15, 0x2c, 0xc3, 0x46, 0x75, 0x47, 0x7a, 0x16, 0x3a, 0xbc, 0x58, 0xbf, + 0x15, 0xc7, 0xef, 0xed, 0x2f, 0x81, 0xf1, 0xe8, 0x79, 0x7a, 0x17, 0xc5, 0x79, 0xf5, 0xae, 0xab, 0x0a, 0x0a, 0x40, + 0xb3, 0x2e, 0xf7, 0x14, 0x51, 0x11, 0xff, 0x93, 0x94, 0xe6, 0x7b, 0x9a, 0xa9, 0x01, 0x9c, 0xd2, 0xf0, 0x37, 0xdf, + 0xfb, 0x4b, 0x59, 0x46, 0x4b, 0x8f, 0x86, 0x4a, 0xc9, 0x20, 0x3e, 0xcc, 0x05, 0x66, 0x6c, 0x98, 0x50, 0x19, 0xb3, + 0x54, 0x77, 0xe9, 0x5a, 0x03, 0x7c, 0x6d, 0x45, 0xab, 0x55, 0x5e, 0x5f, 0x0b, 0xab, 0x63, 0x50, 0xad, 0xec, 0xf8, + 0xb0, 0x82, 0x5b, 0xad, 0x4c, 0x9d, 0x49, 0x37, 0x34, 0x58, 0xad, 0x50, 0xd7, 0x79, 0x7f, 0x19, 0xa9, 0x6b, 0x43, + 0x00, 0x20, 0x37, 0x00, 0x42, 0xd0, 0x5a, 0x5f, 0x8b, 0x09, 0x52, 0xc2, 0x43, 0x19, 0x8b, 0x09, 0x95, 0x6b, 0x88, + 0x4d, 0x75, 0x8e, 0x6a, 0xd7, 0x06, 0xa8, 0x37, 0xa0, 0x8d, 0xeb, 0xd0, 0x5e, 0x00, 0xd2, 0xfb, 0xfb, 0x4b, 0x56, + 0x90, 0xfd, 0x25, 0xcd, 0x46, 0x3c, 0xa1, 0x1f, 0xde, 0x7d, 0x09, 0x97, 0x1c, 0x79, 0x06, 0x86, 0xc5, 0x14, 0x81, + 0xe0, 0x54, 0x9b, 0xa3, 0x45, 0x08, 0x57, 0x22, 0x44, 0x73, 0x02, 0x4f, 0xcd, 0xa5, 0x40, 0x2c, 0x7c, 0xaf, 0xaf, + 0x21, 0xa7, 0x89, 0x86, 0x99, 0x64, 0xaa, 0x17, 0x2f, 0x8e, 0x0f, 0x75, 0x6b, 0x2d, 0x02, 0x74, 0x23, 0x40, 0x82, + 0x3a, 0xa7, 0x15, 0x0e, 0x20, 0xaf, 0xd9, 0xc5, 0x43, 0xc2, 0xae, 0x4a, 0x62, 0x53, 0x17, 0xa8, 0x7a, 0xc7, 0x69, + 0x7c, 0x49, 0xd3, 0xde, 0xfe, 0x32, 0x5b, 0xad, 0x5a, 0xc5, 0xf1, 0xa1, 0x7e, 0xf4, 0x8e, 0x15, 0xdf, 0xd0, 0x2f, + 0xbc, 0x54, 0x5b, 0x0c, 0xb7, 0x12, 0x21, 0xdb, 0xd3, 0xa6, 0x39, 0x45, 0x66, 0x80, 0xc2, 0xf7, 0x54, 0x82, 0x85, + 0x6a, 0x54, 0x2a, 0x44, 0x85, 0xef, 0xb1, 0x64, 0xb3, 0x2c, 0x97, 0x74, 0x0e, 0xa5, 0xd3, 0xd5, 0xaa, 0x5d, 0xf8, + 0xde, 0x8c, 0x65, 0xf0, 0x94, 0xad, 0x56, 0xea, 0xc2, 0xdf, 0x8c, 0x65, 0x41, 0x0b, 0xc8, 0xd6, 0xf7, 0x66, 0xf1, + 0x8d, 0x5a, 0xb0, 0xad, 0x89, 0x6f, 0x82, 0xb6, 0xa9, 0x0a, 0x4b, 0xfc, 0xe4, 0x40, 0x71, 0xd5, 0x8e, 0xa6, 0x66, + 0x47, 0x13, 0xbc, 0xd0, 0x57, 0x99, 0x48, 0x90, 0x90, 0x74, 0xfb, 0x8e, 0x26, 0x76, 0x47, 0x17, 0x3b, 0x76, 0x74, + 0x71, 0xc7, 0x8e, 0xc6, 0x66, 0xf7, 0xbc, 0x12, 0x77, 0x7c, 0xb5, 0x6a, 0xb7, 0x2a, 0xec, 0x1d, 0x1f, 0x26, 0xec, + 0x0a, 0x76, 0x03, 0xd4, 0x3c, 0xc9, 0x66, 0x74, 0x3b, 0x51, 0xd6, 0x51, 0x4c, 0x7f, 0x15, 0x26, 0x2b, 0x2c, 0x64, + 0x75, 0x2c, 0xb8, 0x74, 0x5d, 0xc6, 0xdc, 0xfe, 0x48, 0xca, 0x66, 0x80, 0x87, 0x1c, 0xf0, 0x30, 0x35, 0x78, 0xb8, + 0x28, 0xce, 0x41, 0x24, 0xa8, 0xe5, 0xdc, 0x8b, 0xf4, 0xa0, 0xb5, 0xdf, 0xdb, 0x4d, 0x62, 0x10, 0x0d, 0xbf, 0xe6, + 0x22, 0xf1, 0x23, 0xdd, 0xf4, 0x57, 0x61, 0x66, 0xc6, 0x32, 0x93, 0x5b, 0xb5, 0x93, 0xb4, 0xaa, 0x7a, 0x97, 0xc0, + 0x3a, 0x8f, 0x1e, 0xe9, 0x16, 0xf3, 0x58, 0x4a, 0x2a, 0x32, 0x43, 0xa8, 0xbe, 0xff, 0xff, 0x05, 0xd1, 0x6d, 0x61, + 0x23, 0xb1, 0x65, 0x23, 0x96, 0xde, 0x8c, 0x7e, 0x6e, 0x58, 0xbc, 0x96, 0x46, 0x7b, 0x95, 0xc2, 0x7a, 0x8b, 0x5c, + 0x1b, 0x41, 0x17, 0x81, 0xc9, 0xb2, 0x98, 0xd1, 0xe4, 0x5c, 0xf1, 0xe3, 0xfe, 0xe8, 0xc2, 0xe8, 0xa7, 0x6b, 0xd2, + 0xad, 0xea, 0x80, 0xfd, 0x1f, 0x17, 0x9d, 0x27, 0x0f, 0x4f, 0x7d, 0xac, 0x59, 0x3a, 0x1f, 0x8f, 0x7d, 0x54, 0x78, + 0xf7, 0xeb, 0xd6, 0x7e, 0xf8, 0xe3, 0xe2, 0x8b, 0x17, 0xad, 0x2f, 0xca, 0xce, 0x99, 0x8f, 0x8a, 0x0b, 0x13, 0xce, + 0xb7, 0x92, 0xc9, 0x81, 0xd7, 0xae, 0x68, 0x1c, 0x67, 0xbb, 0x97, 0x33, 0x70, 0x97, 0x93, 0xcf, 0x29, 0x4d, 0xb0, + 0xef, 0xf9, 0x78, 0xa3, 0xf4, 0x3c, 0xa5, 0x57, 0xd4, 0xbe, 0x68, 0x70, 0xcb, 0x64, 0x5b, 0x7a, 0x8c, 0xf8, 0x22, + 0x93, 0x26, 0xaf, 0xc1, 0x70, 0x56, 0x67, 0x49, 0x17, 0x6a, 0x0d, 0xae, 0x49, 0x70, 0xab, 0xc5, 0x5a, 0x5d, 0x58, + 0x15, 0x17, 0xd8, 0x77, 0x00, 0xd8, 0x09, 0x59, 0x7f, 0x47, 0x79, 0xd4, 0xc2, 0xad, 0x5d, 0xb0, 0xe1, 0x36, 0x8a, + 0x7c, 0x7f, 0x68, 0xf1, 0xa4, 0x5c, 0x93, 0xb5, 0xf7, 0x43, 0xec, 0xc4, 0xd7, 0x27, 0x31, 0x70, 0x29, 0x60, 0xb0, + 0x8c, 0xe6, 0xf9, 0x4e, 0x04, 0x94, 0x9b, 0x88, 0xfd, 0xaa, 0xb5, 0xbf, 0x63, 0x14, 0xdc, 0xc2, 0x70, 0xc2, 0x14, + 0xc0, 0x65, 0x80, 0xd4, 0xb4, 0xa2, 0xe3, 0x31, 0x1d, 0x95, 0x9e, 0x5d, 0x08, 0x75, 0x8d, 0x59, 0x2a, 0x21, 0xe2, + 0xa3, 0x42, 0x31, 0xfe, 0x1b, 0x9e, 0x51, 0x1f, 0xd9, 0xe4, 0x4d, 0x03, 0xbf, 0x11, 0xf7, 0xdb, 0xe1, 0xd1, 0x23, + 0xd6, 0x61, 0x31, 0xb3, 0xac, 0x56, 0xd6, 0xab, 0x53, 0x2b, 0xaf, 0x23, 0x92, 0x2b, 0xb7, 0xcd, 0xae, 0x03, 0x74, + 0xbf, 0x63, 0xb2, 0x6c, 0x7f, 0xf1, 0xa8, 0xdd, 0x2a, 0x7c, 0xec, 0xc3, 0x70, 0xf7, 0x3d, 0x25, 0xaa, 0xd7, 0x11, + 0xf4, 0x5a, 0x64, 0xbf, 0xa6, 0x5f, 0xa7, 0xfd, 0x79, 0xdb, 0xc7, 0xfa, 0xbd, 0x01, 0xa8, 0x28, 0x99, 0xc1, 0x08, + 0x7c, 0x9d, 0xbf, 0x7b, 0x29, 0xf5, 0xc1, 0xef, 0x07, 0xcf, 0xe3, 0x76, 0xcb, 0xc7, 0x7e, 0x2e, 0xf9, 0xfc, 0x57, + 0x2c, 0xe1, 0xc8, 0xc7, 0xfe, 0x28, 0xe5, 0x39, 0x75, 0xd7, 0xa0, 0xb5, 0xd7, 0xdf, 0xbf, 0x08, 0x0d, 0xd1, 0x5c, + 0xd0, 0x3c, 0xf7, 0xdc, 0xf1, 0x0d, 0x29, 0x7d, 0x82, 0x61, 0x6e, 0xa5, 0xb8, 0x9c, 0x4a, 0x85, 0x17, 0x7d, 0xa5, + 0xdf, 0xa5, 0x2a, 0x5d, 0xb6, 0x41, 0x6c, 0x4a, 0x04, 0x94, 0x8c, 0x4d, 0x2b, 0x53, 0x9f, 0x9c, 0x79, 0xcb, 0xd1, + 0xd3, 0x13, 0xeb, 0x10, 0xf0, 0xe6, 0x04, 0xb5, 0x92, 0x19, 0xcb, 0xce, 0xb7, 0x94, 0xc6, 0x37, 0x5b, 0x4a, 0x41, + 0x43, 0x2b, 0xa1, 0x33, 0x6f, 0x9b, 0xf9, 0x34, 0xd6, 0x2b, 0x3d, 0xc7, 0x05, 0x31, 0x51, 0x6e, 0xca, 0x4f, 0x40, + 0xea, 0x6c, 0x83, 0x1a, 0xe1, 0xb7, 0x4f, 0x07, 0x25, 0xbf, 0x6a, 0x3a, 0x7a, 0xf3, 0xe9, 0x3d, 0x77, 0x14, 0x9b, + 0xdf, 0x81, 0x7d, 0x73, 0x73, 0x7c, 0x1d, 0xfd, 0x5b, 0x8a, 0x8d, 0xee, 0x51, 0x6e, 0xc1, 0x28, 0x65, 0xb3, 0x6a, + 0x17, 0x36, 0xc1, 0x54, 0x4a, 0x07, 0xa4, 0x0f, 0xb9, 0x83, 0x68, 0xed, 0xe3, 0x1c, 0x2e, 0x45, 0xc2, 0x9b, 0x27, + 0x16, 0x82, 0x9e, 0xa7, 0xfc, 0x7a, 0xfd, 0x4d, 0x5a, 0xbb, 0x1b, 0x4f, 0xd9, 0x64, 0xea, 0xdc, 0x74, 0xa2, 0xa4, + 0x44, 0xfd, 0x9d, 0x13, 0x14, 0xff, 0xfa, 0x2f, 0x61, 0xf8, 0xaf, 0xff, 0xf2, 0xc9, 0xa6, 0x30, 0x7c, 0x71, 0x81, + 0x65, 0x35, 0xec, 0x6e, 0x02, 0xdf, 0x3e, 0x53, 0x1d, 0xe7, 0xdb, 0xdb, 0x6c, 0x6c, 0x02, 0xd4, 0x6f, 0x6c, 0xc1, + 0x46, 0xa1, 0x3e, 0x00, 0xde, 0x6f, 0x01, 0x0c, 0xd6, 0xf5, 0x49, 0xc8, 0xa0, 0xd1, 0xef, 0x02, 0xed, 0x02, 0x45, + 0xf7, 0xda, 0x91, 0xdf, 0x8e, 0xe1, 0x4f, 0xad, 0xe1, 0x77, 0x82, 0x6f, 0x3c, 0x02, 0xa3, 0x8b, 0x8b, 0x32, 0xa5, + 0xcd, 0xed, 0x0a, 0x57, 0xe6, 0xfb, 0x1b, 0x25, 0x46, 0xf6, 0x47, 0x2d, 0xd4, 0x53, 0x17, 0xf2, 0xc8, 0xe8, 0xe2, + 0x35, 0xbc, 0x27, 0xe7, 0xf8, 0x52, 0x58, 0x97, 0xea, 0x1d, 0xfc, 0x19, 0x86, 0xa8, 0xaf, 0x4a, 0x0d, 0xba, 0xc1, + 0x9c, 0xa1, 0x14, 0x34, 0x7e, 0x00, 0x13, 0x8f, 0x2e, 0x8c, 0x7d, 0x77, 0xaa, 0x1d, 0x1f, 0xd1, 0x3a, 0x69, 0x1b, + 0x87, 0x48, 0x0d, 0xe9, 0xd8, 0x7b, 0xaf, 0xf0, 0xa5, 0x1a, 0xd3, 0xca, 0x9e, 0x56, 0xce, 0x25, 0x50, 0xe5, 0x2f, + 0x0a, 0x15, 0x18, 0xff, 0xeb, 0xae, 0xd8, 0xdd, 0xdf, 0x3f, 0x1d, 0xbb, 0xe3, 0xf7, 0x8a, 0xdd, 0xfd, 0xfd, 0x0f, + 0x8f, 0xdd, 0xfd, 0xd5, 0x8d, 0xdd, 0xc1, 0x26, 0x7e, 0x79, 0xaf, 0xf8, 0x9a, 0x8d, 0x7d, 0xf0, 0xeb, 0x9c, 0xb4, + 0x8d, 0x26, 0x9b, 0xf2, 0x09, 0x04, 0xd7, 0xfe, 0xfd, 0x63, 0x65, 0x29, 0x9f, 0xb8, 0x91, 0x32, 0x78, 0x4f, 0x2a, + 0x84, 0xc6, 0xba, 0x36, 0xa6, 0x65, 0xa2, 0x53, 0xad, 0xf2, 0x0e, 0x48, 0xf3, 0xa1, 0x7d, 0x67, 0x81, 0x1f, 0x95, + 0xef, 0x1d, 0x6a, 0xe1, 0x8e, 0x8d, 0x5f, 0x45, 0x2a, 0xf4, 0x55, 0x76, 0xec, 0x34, 0xec, 0x05, 0x07, 0x77, 0x84, + 0xae, 0x7d, 0xaf, 0x8a, 0xbe, 0xef, 0xbe, 0xf4, 0x7f, 0xbc, 0x69, 0x3f, 0x1b, 0xb4, 0xbb, 0x47, 0xed, 0x99, 0x1f, + 0xf9, 0x20, 0xa5, 0x54, 0x41, 0xab, 0x7b, 0x74, 0x04, 0x05, 0xd7, 0x4e, 0x41, 0x07, 0x0a, 0x98, 0x53, 0xf0, 0x08, + 0x0a, 0x46, 0x4e, 0xc1, 0x63, 0x28, 0x48, 0x9c, 0x82, 0x27, 0x50, 0x70, 0xe5, 0x17, 0x03, 0x56, 0x82, 0xfb, 0x04, + 0x0d, 0xb1, 0x36, 0x1e, 0x6c, 0xd9, 0x13, 0xdc, 0x86, 0xa0, 0x59, 0x3c, 0x51, 0xb9, 0x3e, 0xe0, 0x82, 0x8b, 0x38, + 0xbe, 0x9e, 0xd2, 0x2c, 0x82, 0xb0, 0xe5, 0x73, 0x25, 0x63, 0x42, 0xc9, 0xdf, 0xb3, 0x19, 0xb5, 0x5f, 0xa8, 0xb0, + 0x78, 0xf0, 0x7c, 0x34, 0x68, 0x0d, 0x8b, 0x6e, 0xb9, 0x73, 0x3a, 0xda, 0x66, 0xf2, 0x3e, 0xf4, 0x5e, 0x56, 0x75, + 0x7a, 0xba, 0x66, 0xb9, 0xe7, 0x3b, 0xa2, 0x36, 0x8e, 0x3b, 0x60, 0x9c, 0xf2, 0xeb, 0xe6, 0x8d, 0xdf, 0xdb, 0x1e, + 0xc9, 0x01, 0x88, 0xca, 0x48, 0x8e, 0x5a, 0x53, 0xf9, 0xf4, 0x3e, 0x9e, 0x94, 0xbf, 0x5f, 0xd3, 0x3c, 0x8f, 0x27, + 0xa6, 0xe5, 0xee, 0xc8, 0x8d, 0x02, 0xd1, 0x8d, 0xda, 0x58, 0x20, 0x20, 0xfa, 0x02, 0x9b, 0x05, 0xe6, 0xb4, 0x09, + 0xc6, 0x00, 0x76, 0xea, 0x71, 0x1c, 0x35, 0x7d, 0xbd, 0x48, 0xc6, 0x93, 0xaa, 0xe0, 0x78, 0x2e, 0xa8, 0x2a, 0xd5, + 0x18, 0x2e, 0x8e, 0x0f, 0xa1, 0x40, 0x57, 0xef, 0x88, 0xd7, 0x58, 0xdb, 0x7d, 0x77, 0xd4, 0xc6, 0xb3, 0xf1, 0x1a, + 0x37, 0xc3, 0xa5, 0x4c, 0x6f, 0xd9, 0x8c, 0x12, 0x7c, 0xd6, 0x1e, 0xc1, 0x1f, 0x13, 0x83, 0xf8, 0x6c, 0x3c, 0x1e, + 0xdf, 0x19, 0xbf, 0xf9, 0x2c, 0x19, 0xd3, 0x0e, 0x7d, 0xd4, 0x85, 0xec, 0x87, 0xa6, 0xf1, 0xfa, 0xb7, 0x0b, 0x85, + 0xbb, 0xe5, 0xfd, 0x1a, 0x43, 0x80, 0x40, 0x4e, 0x97, 0xf7, 0x8f, 0xe5, 0x14, 0x73, 0x41, 0x97, 0xb3, 0x58, 0x4c, + 0x58, 0x16, 0xb5, 0x8a, 0xf0, 0xca, 0x04, 0x3f, 0x3e, 0x7b, 0xfa, 0xf4, 0x69, 0x11, 0x26, 0xf6, 0xa9, 0x95, 0x24, + 0x45, 0x38, 0x5a, 0x96, 0xcb, 0x68, 0xb5, 0xc6, 0xe3, 0x22, 0x64, 0xb6, 0xe0, 0xa8, 0x33, 0x4a, 0x8e, 0x3a, 0x45, + 0x78, 0xed, 0xb4, 0x28, 0x42, 0x6a, 0x9e, 0x04, 0x4d, 0x6a, 0x29, 0x14, 0x4f, 0x5a, 0xad, 0x22, 0xd4, 0x84, 0xb6, + 0x04, 0x8b, 0x48, 0xff, 0x8c, 0xe2, 0x85, 0xe4, 0xc0, 0x92, 0xbb, 0x5c, 0x06, 0x83, 0x73, 0xf3, 0x7a, 0x0a, 0xfd, + 0x29, 0x87, 0x02, 0x0d, 0xf1, 0x97, 0x6e, 0x98, 0x02, 0x88, 0x59, 0x85, 0x27, 0xb8, 0x8d, 0x62, 0xd4, 0xaa, 0x81, + 0xb2, 0x54, 0xf5, 0x97, 0x84, 0x57, 0xd1, 0x0b, 0xe0, 0x3f, 0xd0, 0x52, 0xbf, 0x47, 0x4d, 0xd2, 0x1d, 0x5c, 0x9f, + 0xd2, 0x4f, 0x72, 0xfd, 0xdb, 0xfb, 0x30, 0x7d, 0x4a, 0xff, 0x68, 0xa6, 0x6f, 0x5e, 0x36, 0xaa, 0x99, 0xbe, 0x66, + 0x6b, 0x33, 0x49, 0xfc, 0xd1, 0x94, 0x8e, 0x3e, 0x5e, 0xf2, 0x9b, 0x26, 0x1c, 0x09, 0xe1, 0x2b, 0x7e, 0xba, 0xff, + 0x5b, 0xd3, 0x2d, 0xec, 0x60, 0xce, 0x97, 0x20, 0x94, 0xd8, 0x7c, 0x9b, 0x11, 0xff, 0xad, 0x35, 0xab, 0x74, 0xc9, + 0x78, 0x4c, 0xfc, 0xb7, 0xe3, 0xb1, 0x6f, 0x2f, 0xd9, 0xc5, 0x92, 0xaa, 0x56, 0x6f, 0x6a, 0x25, 0xaa, 0xd5, 0x17, + 0x5f, 0xb8, 0x65, 0x6e, 0x81, 0x09, 0x72, 0xb8, 0x01, 0x0d, 0x53, 0x93, 0xb0, 0x1c, 0x8e, 0x1a, 0x7c, 0xa0, 0xa2, + 0xfe, 0x96, 0x3f, 0x51, 0x7b, 0x21, 0x73, 0x09, 0xf0, 0x96, 0xb7, 0x48, 0xaf, 0xdf, 0x30, 0x9f, 0x50, 0x9b, 0xf0, + 0xf6, 0xec, 0xf6, 0xcb, 0x24, 0x98, 0x49, 0x54, 0xb0, 0xfc, 0x6d, 0xb6, 0x76, 0x7b, 0x44, 0xc3, 0x48, 0x88, 0xbb, + 0xac, 0x42, 0xf2, 0xc9, 0x24, 0x85, 0x4f, 0x84, 0x2c, 0x6b, 0x6f, 0x1e, 0xd5, 0xdd, 0xfb, 0xb5, 0xf5, 0x46, 0x6e, + 0x47, 0xf3, 0x9e, 0x4e, 0xf5, 0xc5, 0x22, 0x9d, 0x75, 0x7c, 0x65, 0x3e, 0x5d, 0xa3, 0x2c, 0xb2, 0xa5, 0xe1, 0xff, + 0x4b, 0x9d, 0xab, 0x2a, 0x21, 0x4f, 0x43, 0x0f, 0x9c, 0x14, 0x85, 0xc9, 0xf2, 0x4f, 0x58, 0x3e, 0x87, 0x37, 0x62, + 0xea, 0x9e, 0xf4, 0x53, 0x2c, 0x3c, 0xbf, 0x76, 0x22, 0x09, 0xb5, 0xed, 0x2a, 0x6c, 0x28, 0x41, 0xfb, 0x6a, 0x67, + 0xb2, 0xf0, 0x8d, 0xcb, 0xd7, 0x22, 0xd1, 0xf7, 0x34, 0x3e, 0x75, 0x8c, 0xc3, 0x59, 0x21, 0xf8, 0x5d, 0xcb, 0x0d, + 0xb1, 0x55, 0xb6, 0xa0, 0x70, 0x23, 0x65, 0xaa, 0x46, 0x63, 0x4b, 0xf9, 0xe5, 0xf3, 0x79, 0x9c, 0x69, 0x36, 0x4a, + 0x7c, 0xcd, 0x0f, 0xf6, 0x97, 0xd5, 0xce, 0x17, 0xbe, 0x05, 0x5b, 0x13, 0x6f, 0xef, 0xf8, 0x10, 0x3a, 0xf4, 0xbc, + 0x1a, 0xe8, 0xd9, 0x86, 0x3b, 0xff, 0x13, 0x81, 0xf5, 0x8b, 0x30, 0xbf, 0xc6, 0x61, 0x7e, 0xed, 0xfd, 0x79, 0xd9, + 0xbc, 0xa6, 0x97, 0x1f, 0x99, 0x6c, 0xca, 0x78, 0xde, 0x04, 0x85, 0x5f, 0xf9, 0xe5, 0x0c, 0x7b, 0x56, 0xe9, 0x61, + 0xfa, 0x8e, 0x7c, 0x77, 0x91, 0x43, 0xfc, 0x5d, 0xa9, 0xad, 0x51, 0xc6, 0x33, 0xda, 0xad, 0xa7, 0x01, 0xba, 0xe1, + 0x5c, 0x8b, 0xad, 0xe1, 0x92, 0x43, 0xbc, 0x5e, 0xde, 0x46, 0x2d, 0xc3, 0xd6, 0x5b, 0x36, 0x56, 0xdb, 0xda, 0xda, + 0x3e, 0x32, 0xc8, 0x6d, 0x28, 0xe9, 0x25, 0x36, 0x63, 0xd6, 0xbb, 0x62, 0xce, 0x9f, 0x4a, 0x8a, 0x03, 0x6f, 0x9e, + 0xfd, 0xeb, 0x64, 0x13, 0xae, 0x17, 0xab, 0xa4, 0xb8, 0xfb, 0x40, 0x16, 0xc5, 0x63, 0x49, 0x05, 0xbe, 0x4f, 0xcb, + 0x4b, 0x75, 0x7f, 0x65, 0x09, 0x62, 0x26, 0x6a, 0x3f, 0x9d, 0xdf, 0xdc, 0x7f, 0xf8, 0xbb, 0x97, 0x5f, 0x18, 0x1c, + 0xd9, 0xf7, 0xb9, 0xf8, 0x7e, 0x17, 0x0e, 0x42, 0x1a, 0xdf, 0x46, 0x2c, 0x53, 0x32, 0xef, 0x12, 0x5c, 0x72, 0xdd, + 0x39, 0x37, 0xd9, 0x9d, 0x82, 0xa6, 0xea, 0xe3, 0x6d, 0x66, 0x2b, 0x8e, 0x1e, 0xcf, 0x6f, 0xec, 0x6e, 0xb4, 0xd7, + 0xb2, 0x36, 0xff, 0xd0, 0xe4, 0xcc, 0xdd, 0xd9, 0xa0, 0xf5, 0x04, 0xc3, 0x47, 0xf3, 0x9b, 0xae, 0x16, 0xb4, 0x4d, + 0xa1, 0xa1, 0x6a, 0xcd, 0x6f, 0xdc, 0xf4, 0xd4, 0x6a, 0x20, 0x2f, 0x3c, 0xca, 0x3d, 0x1a, 0xe7, 0xb4, 0x0b, 0x6f, + 0xac, 0x66, 0xa3, 0x38, 0x35, 0xc2, 0x7c, 0xc6, 0x92, 0x24, 0xa5, 0x5d, 0x2b, 0xaf, 0xbd, 0xf6, 0x63, 0xc8, 0xee, + 0x74, 0xb7, 0xac, 0xbe, 0x2b, 0x0e, 0xf2, 0x4a, 0x3c, 0xc5, 0x97, 0x39, 0x4f, 0xe1, 0x73, 0x11, 0x5b, 0xd1, 0x69, + 0xd2, 0x1e, 0x5b, 0x15, 0xf2, 0xd4, 0xef, 0xfa, 0x5a, 0x1e, 0xb5, 0xfe, 0xd4, 0x55, 0x1b, 0xde, 0xea, 0x4a, 0x3e, + 0x8f, 0x9a, 0x47, 0xf5, 0x85, 0x40, 0x55, 0xb9, 0x04, 0xbc, 0x65, 0x59, 0x18, 0xa4, 0x95, 0xe6, 0xd3, 0x5e, 0xd8, + 0x36, 0x65, 0x6a, 0x00, 0x78, 0xb5, 0x72, 0x59, 0x54, 0xd4, 0x17, 0xf3, 0xef, 0x73, 0x5a, 0x3e, 0xdf, 0x7e, 0x5a, + 0x3e, 0xb7, 0xa7, 0xe5, 0x6e, 0x8a, 0xfd, 0x6c, 0xdc, 0x86, 0x3f, 0xdd, 0x6a, 0x41, 0x51, 0xcb, 0x3b, 0x9a, 0xdf, + 0x78, 0xa0, 0xa7, 0x35, 0x3b, 0xf3, 0x1b, 0x9d, 0x9c, 0x0b, 0x61, 0x83, 0x16, 0xa4, 0xab, 0xe2, 0x96, 0x07, 0x85, + 0xf0, 0xb7, 0x55, 0xab, 0x6a, 0x3f, 0x84, 0x3a, 0xe8, 0xf5, 0x68, 0xb3, 0xae, 0x73, 0xf7, 0xa1, 0x8d, 0x32, 0x2e, + 0x83, 0xc8, 0x72, 0x63, 0x14, 0xca, 0xf8, 0xf2, 0x92, 0x26, 0xd1, 0x98, 0x8f, 0x16, 0xf9, 0x3f, 0x1b, 0xf8, 0x0d, + 0x12, 0xef, 0x3c, 0xd2, 0x6b, 0xe3, 0xd8, 0xae, 0x3a, 0x55, 0xd8, 0x8e, 0xb0, 0x2c, 0xf7, 0x29, 0xca, 0x47, 0x71, + 0x4a, 0x83, 0x4e, 0xf8, 0x70, 0xcb, 0x21, 0xf8, 0x0f, 0xd9, 0x9b, 0xad, 0x8b, 0xf9, 0xbd, 0xc8, 0xb8, 0x13, 0x09, + 0xbf, 0x0a, 0x07, 0xee, 0x1e, 0xb6, 0x9e, 0x6e, 0x07, 0x77, 0x60, 0x67, 0x1a, 0x5a, 0xa1, 0x60, 0xe4, 0x4e, 0x42, + 0xc7, 0xf1, 0x22, 0x95, 0x77, 0x8f, 0xba, 0x8b, 0x32, 0x36, 0x46, 0xbd, 0x83, 0xa1, 0x57, 0x6d, 0xef, 0xc9, 0xa5, + 0x3f, 0xfb, 0xfc, 0x21, 0xfc, 0xd1, 0x99, 0x46, 0xb7, 0x95, 0xae, 0xae, 0x6d, 0x55, 0xd0, 0xd5, 0xf7, 0x6b, 0xca, + 0xb8, 0x16, 0xe1, 0x4a, 0x1f, 0xbf, 0x6f, 0x6b, 0xd0, 0x2a, 0xef, 0xd5, 0xdc, 0x68, 0x59, 0xbf, 0xaa, 0xf5, 0xaf, + 0x1b, 0xfc, 0x9e, 0x6d, 0x47, 0x5a, 0x73, 0xad, 0xb7, 0x35, 0x5f, 0xaf, 0xdb, 0x68, 0x6c, 0x31, 0xae, 0xda, 0xef, + 0x93, 0xdb, 0xd2, 0x44, 0xd1, 0x81, 0x40, 0xb0, 0x52, 0xf6, 0xb5, 0x95, 0xc2, 0x28, 0x79, 0x00, 0xef, 0x8e, 0xf5, + 0x6e, 0x66, 0x69, 0x96, 0x13, 0x7f, 0x2a, 0xe5, 0x3c, 0xd2, 0x9f, 0x3b, 0xbd, 0x3e, 0x0a, 0xb9, 0x98, 0x1c, 0x76, + 0x5a, 0xad, 0x16, 0xbc, 0xf3, 0xd3, 0xf7, 0xae, 0x18, 0xbd, 0x7e, 0xc6, 0x6f, 0x88, 0xff, 0xc4, 0x7b, 0xea, 0x3d, + 0x39, 0xf2, 0x1e, 0x3d, 0xf6, 0x3d, 0xc5, 0xce, 0x89, 0xff, 0xe4, 0xc8, 0xf7, 0x34, 0x3b, 0x27, 0xfe, 0xa3, 0xc7, + 0x7e, 0xef, 0x78, 0x62, 0x55, 0x32, 0xb8, 0x34, 0xa8, 0xf5, 0x9d, 0x5c, 0x0a, 0xfe, 0x91, 0xd6, 0x0f, 0xae, 0x2e, + 0x33, 0xb9, 0x68, 0x1d, 0xfb, 0x08, 0xa7, 0x77, 0x14, 0xcf, 0x23, 0x45, 0x14, 0x6e, 0x21, 0xb8, 0x65, 0x74, 0xa9, + 0x9a, 0x02, 0xd4, 0xcc, 0x4b, 0xbf, 0x77, 0x0c, 0x79, 0xe3, 0x5e, 0x42, 0xfc, 0xd7, 0x9d, 0x27, 0x5e, 0xfb, 0xf1, + 0x55, 0xf3, 0xe1, 0xa8, 0xd5, 0x6c, 0x7b, 0xed, 0x66, 0x27, 0x7c, 0xe2, 0x75, 0xf4, 0xbf, 0x5e, 0xcb, 0x3b, 0xf2, + 0xda, 0xe1, 0x13, 0xef, 0xc8, 0xeb, 0x84, 0x4f, 0xae, 0x1e, 0xea, 0x7c, 0x82, 0xd8, 0x3f, 0xec, 0x1d, 0xc3, 0xa7, + 0x2b, 0x6f, 0x88, 0xff, 0xb9, 0xaf, 0x3f, 0x10, 0xeb, 0x7f, 0xe6, 0x96, 0xb6, 0x9f, 0x6e, 0x2d, 0xee, 0x3c, 0xd9, + 0x5a, 0x7c, 0xf4, 0x78, 0x6b, 0xf1, 0xc3, 0x47, 0xf5, 0xe2, 0xc3, 0x89, 0xae, 0x2a, 0x4f, 0x39, 0xf1, 0x67, 0xb1, + 0x14, 0xec, 0x26, 0x68, 0x7b, 0x2d, 0xaf, 0xe5, 0x35, 0xe1, 0xbf, 0x27, 0x1d, 0x54, 0xf6, 0xba, 0x84, 0x5e, 0xe5, + 0x2a, 0x9f, 0x3c, 0xf5, 0xda, 0x8f, 0x5f, 0x76, 0x1e, 0x8f, 0xa0, 0x9d, 0x5a, 0x68, 0xdb, 0x6b, 0x5f, 0x1d, 0x3d, + 0x1d, 0xb5, 0x3c, 0xe8, 0xd8, 0x86, 0x3f, 0xd3, 0x47, 0x9d, 0x91, 0x7e, 0x68, 0x41, 0xfd, 0xb7, 0xed, 0x27, 0x79, + 0xab, 0xd9, 0x86, 0x3f, 0xbf, 0x94, 0x1a, 0x31, 0xe8, 0xe3, 0xee, 0xb8, 0x0f, 0x5b, 0xde, 0xd1, 0xd3, 0x69, 0x27, + 0xfc, 0xfc, 0xea, 0x49, 0xf8, 0x74, 0xda, 0x7e, 0xf2, 0xad, 0x7e, 0x4a, 0x9b, 0x9d, 0xf0, 0x73, 0xf8, 0xfb, 0xed, + 0x51, 0x6b, 0xda, 0x6c, 0x87, 0x4f, 0xaf, 0x8e, 0xc2, 0xa3, 0xb4, 0xf9, 0x38, 0x7c, 0x0a, 0x7f, 0xab, 0xe1, 0xa6, + 0x7c, 0x46, 0x7d, 0x0f, 0xf6, 0x7b, 0xcd, 0xdc, 0x72, 0xe7, 0xe8, 0x3c, 0xf4, 0x1e, 0x3d, 0x7c, 0xf9, 0xf4, 0xaa, + 0xf9, 0x70, 0xda, 0xee, 0x5c, 0x35, 0x77, 0xfe, 0xfc, 0x16, 0x10, 0x6f, 0x06, 0x8e, 0x29, 0x5c, 0xe0, 0xb1, 0x88, + 0x53, 0xef, 0x9f, 0x7d, 0x80, 0xf3, 0x5d, 0xe6, 0xb5, 0xf8, 0xb4, 0x79, 0x9d, 0xd1, 0xfb, 0xd8, 0xd7, 0xe2, 0x0f, + 0xb7, 0xaf, 0x73, 0xba, 0xe6, 0x54, 0xbd, 0x95, 0x1b, 0x66, 0xf4, 0xba, 0xed, 0xf5, 0x4e, 0x06, 0x03, 0x06, 0xdf, + 0x39, 0x2a, 0xba, 0xb7, 0xf0, 0x8a, 0x6b, 0xd7, 0xdb, 0xc0, 0xe1, 0x20, 0xdf, 0x4a, 0x7d, 0x92, 0xf9, 0x2e, 0x84, + 0xa4, 0x9f, 0x46, 0xc8, 0xb7, 0xf7, 0xc1, 0x47, 0xfa, 0x87, 0xe3, 0x83, 0xbb, 0xf8, 0xa8, 0xf9, 0x79, 0x95, 0x3d, + 0xab, 0xec, 0xd1, 0x33, 0xf5, 0x1c, 0xc0, 0x1d, 0x8f, 0x86, 0x7f, 0x48, 0xa1, 0x28, 0xf7, 0x75, 0x5c, 0xe1, 0xcd, + 0xaf, 0x71, 0x49, 0xeb, 0x0b, 0x5d, 0xc4, 0x37, 0xc6, 0xff, 0x1c, 0xbe, 0x65, 0x60, 0x1f, 0xae, 0xf4, 0x15, 0x63, + 0xe2, 0x77, 0xc2, 0x56, 0xd8, 0x2a, 0x1d, 0x07, 0x70, 0x89, 0x8f, 0x2c, 0xb9, 0x8c, 0xe1, 0x73, 0x9a, 0x29, 0x9f, + 0xa8, 0x0f, 0x6f, 0xc2, 0xeb, 0xce, 0xd5, 0x27, 0x50, 0xf5, 0x9b, 0xe6, 0x23, 0xdf, 0x37, 0x57, 0xff, 0xe1, 0x92, + 0xd8, 0x37, 0x70, 0x91, 0xce, 0x7a, 0xac, 0x67, 0x60, 0x53, 0xbf, 0xa6, 0x09, 0x8b, 0x03, 0x3f, 0x98, 0x0b, 0x3a, + 0xa6, 0x22, 0x6f, 0xd6, 0x6e, 0x97, 0xa9, 0x8b, 0x65, 0xc8, 0xb7, 0x1f, 0x6e, 0x14, 0xf0, 0xfa, 0x5e, 0x32, 0x30, + 0x5e, 0x2d, 0xdf, 0xa8, 0xf9, 0x7e, 0x81, 0x6d, 0x89, 0x00, 0x8e, 0x5e, 0xa9, 0x06, 0xbe, 0xd6, 0x0d, 0xda, 0x61, + 0xe7, 0x11, 0xd2, 0xbc, 0x04, 0x5e, 0x8b, 0xfa, 0x7d, 0xd0, 0x3c, 0x6a, 0xfd, 0x09, 0x39, 0xdd, 0xca, 0x81, 0x86, + 0xc6, 0xa9, 0x23, 0xaa, 0x0f, 0xde, 0xd6, 0xaf, 0xfe, 0xf9, 0x9a, 0x22, 0x3e, 0xd3, 0x6b, 0x87, 0x17, 0xac, 0x9a, + 0xf8, 0xa1, 0xbe, 0xc0, 0x3e, 0x66, 0x93, 0xc0, 0xfd, 0x9c, 0xa9, 0x7e, 0xed, 0xaa, 0xfa, 0x0a, 0x32, 0x2a, 0xaa, + 0x26, 0x02, 0x2d, 0x95, 0x2f, 0x9e, 0x65, 0x9e, 0x58, 0xad, 0x02, 0x01, 0x8e, 0x58, 0xe2, 0xe0, 0x14, 0x9e, 0x51, + 0x0d, 0xc9, 0x02, 0x97, 0x00, 0x29, 0x04, 0x13, 0xa1, 0xff, 0xaf, 0x8a, 0xed, 0x0f, 0xe3, 0x5e, 0x09, 0xd3, 0x38, + 0x9b, 0x00, 0x15, 0xc6, 0xd9, 0x64, 0xc3, 0x79, 0xa3, 0xc3, 0x09, 0x6b, 0xa5, 0xd5, 0x50, 0x95, 0x93, 0x26, 0x7f, + 0x76, 0xfb, 0xde, 0xbc, 0x9f, 0xc9, 0x07, 0x1f, 0xa8, 0xf2, 0x7d, 0x57, 0xef, 0x92, 0x6d, 0x90, 0x07, 0xfa, 0x03, + 0xe1, 0x2a, 0x21, 0x0d, 0xa4, 0x1f, 0x5c, 0xea, 0xf3, 0x8c, 0xcd, 0x43, 0x7c, 0x2d, 0xfb, 0x12, 0x7a, 0xc5, 0x46, + 0x46, 0x84, 0x61, 0xcf, 0x5c, 0x6c, 0x6e, 0xaa, 0xad, 0x21, 0x6d, 0xac, 0xad, 0xfe, 0x51, 0xac, 0x32, 0x8c, 0x49, + 0xc6, 0xfd, 0xde, 0x83, 0xf2, 0xeb, 0x8c, 0xbb, 0x36, 0x01, 0xbe, 0x5a, 0x3e, 0x10, 0x34, 0xfd, 0x67, 0xf2, 0x00, + 0xbe, 0x5b, 0xfe, 0x60, 0x08, 0x9f, 0xcc, 0x0e, 0x95, 0x28, 0x78, 0x50, 0x7d, 0xbe, 0x1c, 0xf8, 0x60, 0xe3, 0x66, + 0x96, 0xe2, 0xfb, 0x8a, 0x6f, 0x23, 0xaa, 0x3b, 0x8f, 0x2a, 0x51, 0xdd, 0x79, 0xe4, 0x4a, 0xcf, 0xb6, 0xd7, 0xee, + 0x84, 0x8f, 0x1c, 0x01, 0x70, 0xd5, 0x84, 0xff, 0x6b, 0x22, 0xe0, 0x61, 0xf8, 0xa8, 0x94, 0x01, 0xaf, 0xda, 0x9d, + 0xf0, 0x48, 0x8b, 0x9b, 0x4e, 0xf8, 0xe8, 0x07, 0xc5, 0xa0, 0x35, 0x73, 0xae, 0x1f, 0x88, 0x2d, 0xa1, 0x1a, 0x9d, + 0x54, 0xe7, 0xe3, 0xa0, 0xfc, 0x06, 0x9c, 0x39, 0x9f, 0xc6, 0x25, 0xf4, 0x3c, 0x16, 0xf0, 0x21, 0x8e, 0xfa, 0xd9, + 0xad, 0xd5, 0xe1, 0x1a, 0xbf, 0xd8, 0x32, 0x05, 0x9c, 0x70, 0x1f, 0xbb, 0x37, 0x83, 0xe1, 0x5a, 0xad, 0x7a, 0x6d, + 0xb1, 0x7d, 0x7b, 0xdb, 0x6e, 0xd2, 0xd6, 0x0d, 0xed, 0x1b, 0xe2, 0x14, 0xb3, 0x60, 0xea, 0x15, 0xf1, 0x6a, 0x92, + 0x2f, 0x93, 0x62, 0x7d, 0x7e, 0xc8, 0xed, 0x13, 0xdc, 0xb9, 0x1c, 0x4d, 0xab, 0x04, 0xf4, 0x84, 0xc1, 0x75, 0xf6, + 0xa2, 0xb0, 0xa0, 0xd7, 0x9c, 0x81, 0x15, 0x96, 0x14, 0xbf, 0xa0, 0x79, 0xdf, 0x87, 0x22, 0x3f, 0xf2, 0x95, 0x23, + 0xc9, 0x2f, 0x3f, 0x46, 0x52, 0x12, 0x76, 0x55, 0x80, 0xd5, 0x25, 0x12, 0x38, 0xb5, 0x80, 0x1f, 0x1f, 0x1d, 0x1c, + 0xec, 0x3c, 0x2f, 0x4a, 0x1b, 0x83, 0xb5, 0x56, 0x1f, 0x31, 0x70, 0x59, 0x91, 0xef, 0x22, 0xba, 0x1c, 0x57, 0xa1, + 0x10, 0x19, 0x3c, 0x5d, 0xd2, 0x58, 0x86, 0x71, 0xa6, 0x53, 0x14, 0x1c, 0x86, 0x85, 0xdb, 0xf4, 0x08, 0x15, 0x5c, + 0xc6, 0xce, 0x57, 0x4a, 0xcd, 0x39, 0xe7, 0x32, 0xb6, 0x57, 0xfd, 0x32, 0x59, 0xcb, 0x85, 0x9f, 0x76, 0x7a, 0x6f, + 0xdf, 0x9f, 0x78, 0xfa, 0x78, 0x1e, 0x1f, 0x4e, 0x3b, 0xbd, 0x63, 0x65, 0x99, 0xeb, 0x8b, 0x42, 0x44, 0x5f, 0x14, + 0xf2, 0xcc, 0xa5, 0x31, 0x88, 0xd7, 0x14, 0x87, 0x7a, 0xd9, 0xbe, 0x47, 0xb3, 0x91, 0xf6, 0x29, 0xce, 0x16, 0xa9, + 0x64, 0xf0, 0x0a, 0xde, 0x43, 0xe8, 0xda, 0x84, 0x0d, 0x2b, 0x13, 0x4d, 0xad, 0x86, 0x23, 0x33, 0xeb, 0x81, 0x1c, + 0xb3, 0x94, 0xda, 0xd4, 0x52, 0x33, 0x54, 0x99, 0xf9, 0xbc, 0xd9, 0x3a, 0x5f, 0x5c, 0xce, 0x98, 0xf4, 0x6d, 0x7e, + 0xf6, 0x07, 0xd3, 0xe1, 0x58, 0x4d, 0xd5, 0xbb, 0x28, 0x8c, 0x8b, 0xd4, 0x7e, 0x6e, 0x64, 0xed, 0x03, 0xef, 0x7a, + 0xf5, 0x46, 0x42, 0xc0, 0x8d, 0x9f, 0xe9, 0x51, 0xaf, 0x74, 0x4a, 0xba, 0x75, 0xc5, 0xf1, 0xe1, 0xf4, 0xa8, 0x77, + 0x11, 0xcd, 0xcd, 0x78, 0xaf, 0xf8, 0xc6, 0xc7, 0xe2, 0x4b, 0x8e, 0xd9, 0x57, 0xa9, 0xed, 0xfa, 0x0e, 0xa5, 0x01, + 0x78, 0xc4, 0x53, 0xbf, 0x77, 0x6c, 0x94, 0x01, 0x4f, 0x05, 0x5d, 0xfd, 0x47, 0x2d, 0x9b, 0x2d, 0x9f, 0x72, 0xa5, + 0x2d, 0xe9, 0x2e, 0xce, 0x24, 0x35, 0xbf, 0xee, 0xb4, 0xdd, 0x3b, 0x8e, 0x8d, 0x9a, 0x09, 0xcc, 0x23, 0x8f, 0x0e, + 0xa1, 0x33, 0xe8, 0x72, 0x21, 0xe3, 0x87, 0xd7, 0xf4, 0xb2, 0x19, 0xcf, 0x59, 0xe5, 0x44, 0x05, 0xa5, 0xa3, 0x9c, + 0x92, 0x57, 0x33, 0xc1, 0xcf, 0x78, 0x6d, 0x91, 0x8a, 0x85, 0x17, 0xc6, 0x43, 0xab, 0x74, 0x75, 0x1a, 0x4b, 0xdf, + 0xd3, 0x1c, 0xde, 0x7a, 0x72, 0x8d, 0xec, 0x2d, 0xfc, 0xde, 0xbf, 0xfd, 0x8f, 0xff, 0x65, 0x9c, 0xb3, 0xc7, 0x87, + 0xd3, 0xb6, 0x1d, 0x6b, 0x0d, 0xd1, 0xc5, 0x31, 0x5c, 0x30, 0xab, 0xa2, 0x89, 0xf4, 0xa6, 0x39, 0x11, 0x2c, 0x69, + 0x4e, 0xe3, 0x74, 0xec, 0xf7, 0x76, 0x23, 0xc8, 0xbd, 0x59, 0x62, 0xa0, 0xae, 0x17, 0x01, 0x09, 0xfe, 0xa6, 0xbb, + 0x11, 0x36, 0xc5, 0x5e, 0x9d, 0x56, 0xf7, 0xa6, 0x44, 0x75, 0xa0, 0x6a, 0xb7, 0x25, 0x84, 0xf9, 0x2a, 0x91, 0x61, + 0x6a, 0xa2, 0x76, 0x49, 0xa2, 0xf0, 0xbd, 0x32, 0x1a, 0xf2, 0x7f, 0xff, 0xe7, 0x7f, 0xf9, 0x6f, 0xf6, 0x11, 0x82, + 0x1c, 0xff, 0xf6, 0xdf, 0xff, 0xf3, 0xff, 0xf9, 0xdf, 0xff, 0x15, 0x12, 0xeb, 0x4d, 0x20, 0x44, 0xf1, 0x09, 0xaf, + 0x8a, 0x82, 0x68, 0x86, 0xe1, 0x41, 0x32, 0xda, 0x8c, 0xe5, 0x92, 0x8d, 0xea, 0xd7, 0x26, 0xce, 0xd4, 0x84, 0xea, + 0xb0, 0x19, 0xe8, 0xd4, 0xa1, 0x2d, 0x2a, 0x1a, 0xa9, 0xa1, 0x5c, 0xd1, 0x62, 0x71, 0x7c, 0x08, 0xf8, 0xbe, 0xdf, + 0x4d, 0xb3, 0xb0, 0xdc, 0x8e, 0xa5, 0x75, 0xfd, 0x41, 0x49, 0x51, 0x95, 0x7b, 0xe0, 0x94, 0x5f, 0xc2, 0x63, 0xd4, + 0x71, 0x8a, 0xd5, 0xee, 0xd5, 0xfa, 0x74, 0x7f, 0x5a, 0xe4, 0x92, 0x8d, 0x01, 0xe5, 0xda, 0xc1, 0xa8, 0xe2, 0x9f, + 0x4d, 0x50, 0xff, 0xd2, 0xdb, 0x42, 0x8d, 0xa2, 0x6d, 0xc6, 0x87, 0x4f, 0xff, 0x54, 0xfc, 0x65, 0x06, 0x4a, 0x96, + 0x17, 0xcc, 0xe2, 0x1b, 0x63, 0x49, 0x3e, 0x6e, 0xb5, 0xe6, 0x37, 0x68, 0x59, 0xcd, 0x80, 0x77, 0x4d, 0xa6, 0x9c, + 0x92, 0xee, 0x80, 0x2a, 0x70, 0x5a, 0xfa, 0x3f, 0x5b, 0x1e, 0x38, 0x51, 0xbd, 0x56, 0x51, 0xfc, 0x79, 0xa9, 0x5c, + 0x70, 0xec, 0x17, 0x08, 0x70, 0x1a, 0x6f, 0xe5, 0x25, 0x77, 0x17, 0xb7, 0x74, 0x7a, 0x75, 0x74, 0xaf, 0x69, 0x7b, + 0xf3, 0x02, 0x95, 0x1b, 0xa0, 0x75, 0x43, 0xab, 0x0f, 0x21, 0x58, 0x3a, 0x6d, 0xe3, 0x69, 0x67, 0x59, 0x0e, 0x2f, + 0x25, 0x9f, 0xb9, 0x11, 0x59, 0x1a, 0xd3, 0x11, 0x1d, 0x5b, 0x2f, 0xaf, 0xa9, 0xd7, 0xd1, 0xd6, 0x62, 0x7a, 0xb4, + 0x65, 0x2e, 0x03, 0x92, 0x8a, 0xc4, 0x7a, 0xad, 0xe2, 0x33, 0x38, 0x81, 0xcb, 0x71, 0xca, 0x63, 0x19, 0x29, 0x82, + 0xed, 0xba, 0x71, 0xdd, 0x18, 0xd8, 0x0c, 0x5f, 0x3a, 0xf0, 0x74, 0x75, 0x53, 0xf0, 0xb7, 0xd6, 0xaf, 0xb9, 0x15, + 0xa1, 0xea, 0xee, 0x0e, 0xa5, 0xdd, 0x35, 0xdf, 0x9a, 0x70, 0xe9, 0x9b, 0x9a, 0x9f, 0xc3, 0xc8, 0x98, 0x0e, 0xda, + 0x5e, 0xaf, 0x45, 0xb5, 0xae, 0xfd, 0x4a, 0x06, 0xbe, 0x02, 0xd3, 0x5f, 0x6f, 0xa5, 0x0a, 0xa1, 0xd5, 0x1b, 0xf2, + 0x6d, 0x69, 0x05, 0xc5, 0xf3, 0xb9, 0x6a, 0x88, 0xba, 0xc7, 0x87, 0x5a, 0x79, 0x05, 0xee, 0xa1, 0x72, 0x01, 0x74, + 0xe8, 0xdd, 0x34, 0x32, 0x47, 0x41, 0xff, 0x32, 0x41, 0x79, 0xf8, 0x5c, 0x55, 0xef, 0xff, 0x01, 0xb9, 0x37, 0x65, + 0xfc, 0x3f, 0x86, 0x00, 0x00}; } // namespace web_server } // namespace esphome + #endif #endif diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 49de0cfab6..a7ad3ab543 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -1,10 +1,12 @@ #pragma once // Generated from https://github.com/esphome/esphome-webserver + #ifdef USE_WEBSERVER_LOCAL #if USE_WEBSERVER_VERSION == 3 -#include "esphome/core/hal.h" -namespace esphome { +#include "esphome/core/hal.h" + +namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { @@ -3629,367 +3631,368 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x46, 0x5a, 0xa5, 0xf5, 0x21, 0x2e, 0x2e, 0xb9, 0x89, 0xa8, 0x62, 0xde, 0x56, 0x7a, 0x54, 0x88, 0x37, 0x2c, 0x80, 0x9e, 0xd2, 0xd3, 0x9a, 0xff, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xe6, 0xaa, 0xac, 0xe4, 0x0a, 0x58, 0xea, 0xf8, 0x52, 0x8b, 0x48, 0x68, 0xc8, 0xbf, 0xac, 0xba, 0xed, 0x96, 0x8f, 0x70, 0x49, 0x02, 0x5f, 0x36, 0xaa, - 0xe4, 0xe5, 0x65, 0xce, 0xc3, 0xc0, 0xc4, 0xf8, 0x08, 0xa8, 0xad, 0x66, 0xf6, 0x7f, 0x8a, 0x3b, 0xda, 0xe5, 0xb6, - 0x6d, 0xe4, 0xff, 0x7b, 0x0a, 0x86, 0xc9, 0xa5, 0x62, 0x42, 0xd2, 0xa4, 0x64, 0xd9, 0x8e, 0x64, 0xd9, 0x6d, 0x93, - 0x74, 0xce, 0x1d, 0xb7, 0xe9, 0x24, 0xbe, 0xcc, 0x5d, 0x5d, 0x8f, 0x45, 0x51, 0x90, 0xc4, 0x0b, 0x45, 0x6a, 0x48, - 0xca, 0x96, 0xab, 0xf2, 0x9e, 0xa5, 0xcf, 0x72, 0x4f, 0x76, 0xb3, 0xbb, 0x00, 0x08, 0x7e, 0xe8, 0xc3, 0x4d, 0x7a, - 0x37, 0x3d, 0x5f, 0x44, 0x10, 0x00, 0x81, 0x05, 0xb0, 0xbb, 0xd8, 0xcf, 0x27, 0x8e, 0x08, 0xac, 0x69, 0xe4, 0x9b, - 0x8e, 0x96, 0x98, 0x31, 0x93, 0x91, 0xe7, 0x88, 0xc1, 0x44, 0x11, 0xea, 0x1d, 0x6a, 0x21, 0xf8, 0xba, 0x14, 0x47, - 0xd7, 0x1a, 0xc7, 0xcb, 0x51, 0xc8, 0x2c, 0xdc, 0xee, 0xf0, 0xc9, 0xf5, 0x68, 0x39, 0x1a, 0x41, 0x32, 0x95, 0x27, - 0x8e, 0x09, 0xe1, 0x61, 0xe2, 0x14, 0xaf, 0x6d, 0xb9, 0xd1, 0x87, 0x49, 0xd9, 0x59, 0x75, 0xf8, 0x60, 0xd2, 0x01, - 0x12, 0x19, 0xfa, 0x40, 0x06, 0x57, 0xb4, 0x86, 0x53, 0x3b, 0xd0, 0x3f, 0xc0, 0xee, 0x4b, 0xf5, 0x7e, 0xd3, 0xd1, - 0x1f, 0x5c, 0xeb, 0x1f, 0x10, 0xc6, 0x98, 0x64, 0xf8, 0x35, 0xed, 0x5e, 0xdd, 0xd4, 0x49, 0x37, 0xbd, 0xc4, 0x74, - 0x03, 0x20, 0x9b, 0x7d, 0x13, 0x78, 0xd3, 0x28, 0x4e, 0xb3, 0xc0, 0xd7, 0x6f, 0xfa, 0x17, 0x41, 0xeb, 0x7a, 0x9e, - 0xb5, 0x8c, 0x1b, 0xd3, 0xcf, 0xd4, 0x4c, 0x25, 0x02, 0x61, 0x62, 0xa2, 0x92, 0x4d, 0x95, 0xd4, 0x13, 0xb4, 0xb5, - 0xa2, 0x40, 0xcd, 0x58, 0xc9, 0xcf, 0x06, 0x50, 0xaf, 0x92, 0xf6, 0x04, 0xf3, 0x37, 0xe9, 0xd8, 0xd2, 0xe8, 0xd3, - 0x85, 0xe2, 0xf5, 0x72, 0x8d, 0xa4, 0x3c, 0x2b, 0xa8, 0x25, 0x86, 0xea, 0x15, 0xfe, 0x2d, 0xf4, 0xfc, 0x44, 0xb5, - 0xcd, 0x2c, 0xd1, 0xdd, 0xe1, 0x37, 0x65, 0xbe, 0x00, 0xe8, 0x37, 0x18, 0x46, 0x44, 0x71, 0xa6, 0x41, 0xfc, 0x19, - 0xf8, 0xe2, 0xb0, 0x6a, 0xcb, 0xc5, 0x7b, 0x6d, 0x19, 0x39, 0x47, 0x06, 0xdf, 0x22, 0xf1, 0x6b, 0xf1, 0x28, 0x64, - 0xa5, 0x40, 0x13, 0xc4, 0xd3, 0x47, 0xb0, 0x80, 0x59, 0x7c, 0x19, 0xdf, 0x57, 0xd5, 0x15, 0xaf, 0x87, 0xbb, 0x69, - 0x2f, 0x12, 0x40, 0xd8, 0x6f, 0x22, 0xf9, 0x5e, 0x8b, 0xe7, 0x0f, 0x15, 0x8c, 0x4e, 0xe5, 0x4c, 0xa1, 0x7d, 0x86, - 0xe0, 0x61, 0x32, 0x30, 0xe7, 0x42, 0x5a, 0x00, 0x28, 0x89, 0x93, 0xe9, 0x61, 0x7e, 0x2b, 0x32, 0x1c, 0x8b, 0xfc, - 0xc2, 0x0a, 0x71, 0x06, 0xec, 0x1a, 0x2d, 0x96, 0x19, 0x46, 0xc4, 0x85, 0x01, 0xb0, 0x5c, 0xd7, 0x30, 0xc2, 0x26, - 0x60, 0xe9, 0x82, 0x4d, 0xcc, 0x75, 0x2d, 0x18, 0xd7, 0xcb, 0x88, 0xe7, 0x05, 0xdc, 0x85, 0xe8, 0x1d, 0xc5, 0x49, - 0xf0, 0x98, 0xf0, 0x59, 0xf8, 0x66, 0x11, 0x4d, 0xbe, 0xe5, 0xa3, 0xda, 0xa5, 0x01, 0x31, 0xf8, 0x84, 0xf8, 0xfa, - 0xad, 0xb0, 0x71, 0xae, 0x10, 0x24, 0xb3, 0x34, 0xcb, 0xe1, 0xb3, 0x75, 0x94, 0x9f, 0x3f, 0x5b, 0xa7, 0xf9, 0xe0, - 0xd9, 0xda, 0x03, 0x46, 0x2e, 0xd7, 0x61, 0x9e, 0x85, 0x3b, 0x4d, 0x31, 0x3b, 0xd8, 0x53, 0x54, 0xae, 0xa1, 0x3e, - 0x7d, 0xc0, 0xb5, 0xe6, 0x8b, 0x24, 0x98, 0x7b, 0xc9, 0x03, 0x29, 0xd9, 0x4d, 0x55, 0x13, 0x6f, 0xe8, 0x1a, 0xa1, - 0x75, 0x9a, 0x2e, 0x61, 0x78, 0x5d, 0xfb, 0x5a, 0x96, 0x31, 0x3e, 0x39, 0xa9, 0x69, 0x84, 0x6f, 0xdd, 0xea, 0x2f, - 0x99, 0x3d, 0x66, 0x99, 0x17, 0x84, 0xd4, 0xa4, 0x2f, 0x52, 0xc8, 0xd7, 0x66, 0x93, 0x96, 0x67, 0x13, 0x95, 0x77, - 0x0b, 0x4e, 0x86, 0x10, 0x3e, 0x8d, 0x1b, 0x67, 0x86, 0xa9, 0xa5, 0x9a, 0xd7, 0x8f, 0xde, 0xfd, 0x4f, 0xa1, 0xcf, - 0x00, 0xfa, 0x11, 0x40, 0x9f, 0x45, 0x7e, 0x3c, 0x66, 0x7f, 0x7f, 0x7f, 0x21, 0x73, 0x59, 0x81, 0x58, 0x66, 0xc8, - 0xb7, 0x61, 0x8a, 0xdc, 0x42, 0x82, 0x9c, 0x02, 0x65, 0x9d, 0x2a, 0x76, 0x4c, 0x92, 0xeb, 0xda, 0x39, 0x8d, 0x9d, - 0x8d, 0x69, 0xd4, 0x83, 0x18, 0x5b, 0x25, 0xf9, 0xe9, 0x01, 0xd5, 0x26, 0xda, 0x46, 0x95, 0x00, 0x0c, 0x09, 0xcc, - 0xb0, 0x80, 0x02, 0xa4, 0xdd, 0x1c, 0xb8, 0xc5, 0xf5, 0xc1, 0x9e, 0xa3, 0xf0, 0xdb, 0x3d, 0x2f, 0x33, 0x26, 0xd8, - 0x4a, 0x3f, 0x3b, 0xc5, 0x44, 0x5a, 0x40, 0x9d, 0x21, 0xf4, 0xc6, 0xe9, 0x01, 0x3d, 0x6a, 0x95, 0xfd, 0x5f, 0x74, - 0x22, 0x2e, 0x72, 0x3d, 0xde, 0xc1, 0xa3, 0x0e, 0x06, 0xe4, 0x6d, 0x87, 0x52, 0x2f, 0xd7, 0xb5, 0x39, 0x67, 0x84, - 0x78, 0x8c, 0x1f, 0x08, 0x00, 0xe0, 0xc0, 0x49, 0xd5, 0xb5, 0xb9, 0xb7, 0xc2, 0x99, 0x8b, 0x37, 0xde, 0xaa, 0xe5, - 0xf2, 0x57, 0xb6, 0x04, 0x54, 0x5a, 0x3e, 0x5a, 0x3e, 0x5f, 0x5c, 0xb0, 0xee, 0x17, 0x42, 0xdb, 0xd6, 0x0c, 0xb5, - 0xa6, 0x0d, 0x8b, 0x3b, 0x13, 0x8b, 0x3b, 0xde, 0xb0, 0xb8, 0xe3, 0x2d, 0x8b, 0x1b, 0xf2, 0x85, 0xd4, 0x24, 0xe8, - 0x12, 0xf4, 0xd8, 0x92, 0xc0, 0xe3, 0x6c, 0x45, 0x8f, 0x9f, 0x33, 0x84, 0x93, 0x95, 0x86, 0x60, 0xb1, 0xb4, 0x01, - 0x56, 0x4d, 0x70, 0x51, 0x00, 0xa1, 0xa2, 0x94, 0xb4, 0x74, 0xe8, 0xc4, 0xb4, 0x21, 0x2f, 0x66, 0x2b, 0xac, 0x4e, - 0x17, 0x36, 0x29, 0xe5, 0xfc, 0x6e, 0xcd, 0x36, 0x4c, 0x74, 0xb6, 0x65, 0xa2, 0x7e, 0xe9, 0xe4, 0xf2, 0x59, 0xd3, - 0x19, 0x54, 0xe7, 0x04, 0x5b, 0x10, 0x8c, 0x38, 0x71, 0xc7, 0x94, 0xb7, 0xe1, 0x66, 0x84, 0xaa, 0x6c, 0xa8, 0x85, - 0x97, 0xa6, 0xf7, 0x71, 0x02, 0x5a, 0x10, 0xe8, 0xe6, 0x71, 0x3b, 0x6a, 0x1e, 0x44, 0x3c, 0xc0, 0xca, 0xc6, 0xbd, - 0x54, 0xbc, 0x57, 0x77, 0x54, 0xbb, 0xdb, 0xa5, 0x1a, 0x0b, 0x2f, 0xcb, 0x58, 0x82, 0x30, 0xf7, 0x20, 0x12, 0x77, - 0x0d, 0xd8, 0xff, 0x97, 0x4d, 0xd6, 0x80, 0x41, 0x42, 0xa3, 0xc0, 0xe9, 0x88, 0x9f, 0x17, 0xc0, 0x47, 0x25, 0x82, - 0xe8, 0x2a, 0xb1, 0xda, 0x12, 0x09, 0xf7, 0x1f, 0xf1, 0xb0, 0xb6, 0x12, 0xc5, 0x9b, 0xc8, 0x3d, 0x32, 0xec, 0x85, - 0x37, 0xfe, 0x00, 0xba, 0xb6, 0x56, 0xdb, 0x04, 0xbb, 0x59, 0x35, 0x32, 0x5b, 0x42, 0x8c, 0x9d, 0x5f, 0xa0, 0x48, - 0xc4, 0x91, 0xdc, 0x2a, 0x09, 0x1c, 0x1a, 0x3d, 0x6b, 0x72, 0xb3, 0x6e, 0xe7, 0x07, 0xd3, 0xc0, 0xa8, 0xe1, 0x4c, - 0x40, 0x6c, 0xe1, 0xe0, 0x4c, 0xde, 0xaf, 0x42, 0xd3, 0x3d, 0x32, 0x40, 0x18, 0x7b, 0x0d, 0x29, 0x46, 0x1d, 0x71, - 0x79, 0x1d, 0x26, 0x40, 0xa2, 0xae, 0x9d, 0x9b, 0xfc, 0xf9, 0x14, 0x7f, 0xb9, 0x37, 0xf9, 0xf3, 0x11, 0xfe, 0x6a, - 0xdf, 0x60, 0x32, 0xb9, 0x86, 0x4b, 0xbb, 0x32, 0x67, 0xfd, 0xac, 0xb4, 0x9d, 0xc8, 0x24, 0xec, 0xf1, 0x04, 0xfa, - 0xe9, 0xb3, 0x75, 0x0a, 0x4e, 0x90, 0xea, 0x1c, 0x22, 0x3b, 0x31, 0xf2, 0xc6, 0xf2, 0xe9, 0x86, 0xf2, 0x91, 0xf1, - 0x3f, 0xa6, 0xf2, 0xb8, 0x4b, 0xe2, 0x82, 0xa2, 0x94, 0x45, 0x0e, 0xb7, 0xa3, 0x20, 0xf2, 0x92, 0x87, 0x5b, 0xba, - 0x4a, 0xb4, 0x04, 0x9f, 0x2e, 0x45, 0x29, 0xc4, 0x4a, 0x96, 0x35, 0x50, 0x99, 0x22, 0x73, 0x7d, 0xe0, 0x64, 0x7e, - 0xf0, 0x8f, 0x44, 0x61, 0xd1, 0x4a, 0x97, 0x4d, 0xbe, 0x20, 0xa5, 0x0f, 0xdd, 0x3e, 0x5b, 0xb7, 0x58, 0xbd, 0x9b, - 0xca, 0x6c, 0x2b, 0x3c, 0x20, 0x2c, 0x0f, 0x5e, 0x5c, 0xe7, 0xe3, 0xa0, 0x87, 0x2a, 0xa6, 0x51, 0xbc, 0xb2, 0x9e, - 0xad, 0xb3, 0x73, 0x7d, 0xee, 0x25, 0x9f, 0xd8, 0xd8, 0xf2, 0x83, 0xc4, 0x0f, 0x99, 0xde, 0xd3, 0x47, 0xa1, 0x17, - 0x7d, 0xe2, 0x8f, 0x56, 0xbc, 0xcc, 0x50, 0x69, 0xbc, 0xf3, 0x9e, 0x2b, 0x60, 0x42, 0xe2, 0x39, 0x64, 0x4c, 0x1b, - 0xa0, 0xa0, 0xbd, 0x96, 0xc2, 0xad, 0x82, 0x29, 0x2c, 0x6a, 0x99, 0x60, 0xf3, 0x08, 0x7a, 0x6c, 0x70, 0x22, 0x35, - 0x75, 0x5c, 0x2f, 0xdd, 0x54, 0xa7, 0x4a, 0x82, 0x49, 0x99, 0x05, 0xf1, 0x16, 0x7b, 0xf8, 0xe3, 0x9f, 0xa3, 0xfc, - 0xd4, 0xfb, 0x7f, 0x8e, 0x73, 0x78, 0x9b, 0x3f, 0xa8, 0x36, 0xf6, 0xd2, 0x74, 0x39, 0x67, 0x63, 0xd2, 0x97, 0x9d, - 0x17, 0x43, 0x29, 0x33, 0xf2, 0xea, 0x70, 0x7e, 0x59, 0xb6, 0x8f, 0x0f, 0x5f, 0x83, 0x1e, 0x1f, 0x38, 0xba, 0x78, - 0x32, 0xd1, 0x8b, 0x2b, 0xf5, 0x8e, 0x66, 0xee, 0xe1, 0x2f, 0xcb, 0xef, 0xde, 0x3a, 0xdf, 0xc9, 0xc6, 0x91, 0x6e, - 0xe4, 0x43, 0xa1, 0x94, 0xe4, 0x8c, 0xa9, 0x32, 0x5e, 0x31, 0xa3, 0x89, 0x17, 0x6d, 0x9e, 0xce, 0x75, 0x69, 0x97, - 0x2d, 0x18, 0x1b, 0x83, 0xbd, 0xaa, 0x59, 0x2b, 0xbd, 0x0d, 0xd9, 0x1d, 0x93, 0x0a, 0xcf, 0xfa, 0xc7, 0x1a, 0x5a, - 0x60, 0x44, 0x36, 0xae, 0x48, 0xe5, 0x6c, 0x95, 0x32, 0xa5, 0x21, 0xce, 0x81, 0xcf, 0x5c, 0xdd, 0xe5, 0x95, 0x5d, - 0x3d, 0x34, 0x75, 0x65, 0x00, 0x1b, 0x47, 0x76, 0xbe, 0xa1, 0xbc, 0x87, 0xe9, 0x98, 0x9b, 0xc7, 0x66, 0xba, 0x46, - 0x0f, 0x22, 0x58, 0x73, 0x38, 0x85, 0xb0, 0xf9, 0x5b, 0x85, 0xf4, 0x61, 0x13, 0xc4, 0x9a, 0x64, 0x52, 0xba, 0x90, - 0xf1, 0x34, 0x2e, 0x84, 0x56, 0x9e, 0xe6, 0x08, 0x73, 0x9a, 0x46, 0x2c, 0x4d, 0x37, 0x42, 0x47, 0xae, 0xb0, 0xa9, - 0x17, 0xb5, 0xcb, 0x93, 0x2f, 0xca, 0x4d, 0xc7, 0x04, 0x0a, 0x8c, 0xb3, 0xa9, 0x7e, 0x0b, 0xd1, 0xf9, 0xed, 0x9c, - 0x9b, 0x6c, 0x24, 0xd3, 0x91, 0xce, 0xd5, 0xe9, 0x9b, 0xde, 0xdf, 0xeb, 0x7c, 0x50, 0x25, 0xb2, 0xd8, 0x38, 0xb4, - 0x56, 0x09, 0xd5, 0xd5, 0x44, 0x31, 0xd8, 0x81, 0x18, 0x53, 0x05, 0x9f, 0xb1, 0xc9, 0x84, 0xf9, 0x59, 0x6a, 0x08, - 0xc1, 0x8c, 0x0c, 0xa0, 0x0a, 0x8e, 0x33, 0x4f, 0x06, 0xfa, 0x8f, 0xe0, 0x46, 0x2e, 0xe2, 0x0c, 0xf1, 0x01, 0x89, - 0x1b, 0x4a, 0x33, 0x98, 0xa8, 0xc7, 0x32, 0x88, 0xf8, 0x57, 0x20, 0x3f, 0x76, 0x43, 0x39, 0x0e, 0x8d, 0xe3, 0xfb, - 0x62, 0x13, 0xc4, 0xd2, 0xb0, 0x63, 0x3b, 0xb6, 0xd9, 0x76, 0x56, 0xd7, 0xee, 0x77, 0x5d, 0xd7, 0xc9, 0x75, 0x13, - 0xdc, 0x97, 0x3e, 0xed, 0x7b, 0xc2, 0xb1, 0x55, 0x07, 0x5a, 0x2d, 0xa3, 0xc7, 0xb4, 0x6b, 0xbb, 0xaf, 0x5c, 0xdd, - 0x24, 0xab, 0x31, 0x05, 0x91, 0xf9, 0xf1, 0x1d, 0x4b, 0x3e, 0x7b, 0x2a, 0xe5, 0xce, 0xf7, 0x1b, 0xcf, 0x91, 0xeb, - 0x00, 0xc6, 0xcd, 0xe2, 0xc5, 0x23, 0xa6, 0xd0, 0xd1, 0x4d, 0xdd, 0x0f, 0xe3, 0x94, 0xa9, 0x73, 0x20, 0x01, 0xc3, - 0x67, 0x4e, 0xe2, 0xa7, 0xf7, 0x6f, 0x3f, 0x7c, 0xd0, 0x4d, 0x4c, 0x86, 0x99, 0xaa, 0xbd, 0xf3, 0x0d, 0xb5, 0x03, - 0xd5, 0x37, 0xee, 0x3b, 0x22, 0x27, 0x74, 0x85, 0x2c, 0xef, 0x39, 0x2a, 0xab, 0x6d, 0x39, 0x4e, 0x66, 0xf8, 0x97, - 0xe9, 0xde, 0xb7, 0xd7, 0xbc, 0x1a, 0x70, 0xc3, 0x76, 0x5a, 0x56, 0x2a, 0x99, 0x07, 0xd1, 0x6d, 0x43, 0xa9, 0xb7, - 0x6a, 0x28, 0x85, 0x8b, 0x53, 0x0d, 0x57, 0x2d, 0xe3, 0xb9, 0x42, 0x8a, 0x21, 0x97, 0xf1, 0x2e, 0x70, 0x29, 0xd7, - 0x97, 0xcf, 0x18, 0x34, 0x0f, 0x66, 0x5e, 0x1d, 0x75, 0x43, 0x31, 0xbf, 0x73, 0x48, 0xd8, 0xfa, 0x21, 0xd8, 0xbc, - 0x31, 0x55, 0xe3, 0x55, 0x66, 0xd3, 0xa4, 0xc5, 0xaa, 0xd2, 0x09, 0xb1, 0x93, 0xb7, 0x19, 0x9b, 0x2f, 0x58, 0xe2, - 0x65, 0xcb, 0x84, 0xdd, 0x86, 0xf1, 0xfd, 0x93, 0xc2, 0xa2, 0x7c, 0x47, 0xe5, 0x59, 0x30, 0x9d, 0xc9, 0xda, 0xe7, - 0x2d, 0x36, 0x90, 0x0b, 0xb8, 0xf5, 0x03, 0xf9, 0x7f, 0x7e, 0xb7, 0xed, 0xff, 0xfc, 0xbe, 0xb3, 0x2a, 0x74, 0x9f, - 0x0f, 0xcd, 0x6c, 0xb0, 0xc7, 0xbe, 0x68, 0xfe, 0x52, 0x19, 0xe6, 0xcd, 0x75, 0x6a, 0x8b, 0x00, 0xef, 0x6b, 0x4b, - 0x50, 0x2b, 0x2c, 0xef, 0x9b, 0x47, 0x0d, 0x0c, 0xe6, 0xb5, 0x73, 0x64, 0x50, 0xe9, 0xb3, 0x86, 0x36, 0x34, 0x7a, - 0x7b, 0xad, 0xc8, 0x1f, 0x87, 0xf0, 0xae, 0x39, 0x7c, 0xe6, 0xf0, 0xb9, 0x14, 0xf0, 0xf5, 0x70, 0x28, 0xd3, 0xab, - 0xa9, 0x4d, 0xc1, 0xca, 0xfd, 0xbc, 0x56, 0xc2, 0x89, 0x67, 0xcf, 0x31, 0xc8, 0xfd, 0x7c, 0xf0, 0x7a, 0x88, 0xf6, - 0x58, 0xa7, 0xa3, 0xa4, 0x60, 0x56, 0x36, 0xa2, 0x36, 0xb2, 0xa7, 0xae, 0x75, 0x5a, 0xc3, 0x6b, 0x50, 0x8a, 0x39, - 0xb7, 0xf2, 0xa1, 0x61, 0xbe, 0x1e, 0x72, 0x31, 0x0e, 0x37, 0x01, 0xed, 0x55, 0xb7, 0x36, 0x17, 0x82, 0x96, 0x80, - 0x6e, 0x6a, 0xa4, 0x5b, 0xc1, 0xca, 0xac, 0x90, 0x9a, 0xa1, 0xf0, 0x1c, 0x6e, 0xf0, 0xc3, 0x1c, 0x53, 0x7e, 0xbc, - 0xdb, 0x64, 0x26, 0xf5, 0xd3, 0x6e, 0x33, 0xa9, 0xab, 0xbd, 0xcc, 0xa4, 0x7e, 0xfa, 0xe2, 0x66, 0x52, 0xef, 0x54, - 0x33, 0x29, 0x58, 0xc4, 0xb7, 0x6c, 0x2f, 0xdb, 0x25, 0x61, 0x11, 0x11, 0xdf, 0xa7, 0x03, 0x97, 0xf3, 0xaf, 0xa9, - 0x3f, 0x63, 0x70, 0x27, 0xe7, 0xab, 0x12, 0xc6, 0x53, 0xb0, 0x63, 0xfa, 0xf3, 0x2d, 0x8e, 0xc2, 0x78, 0xaa, 0xda, - 0x1b, 0x45, 0x3c, 0xe8, 0x69, 0x11, 0xc8, 0x88, 0x6c, 0x7c, 0x1c, 0x53, 0x84, 0x3d, 0xb2, 0x0e, 0x0d, 0x25, 0xb1, - 0xb3, 0x34, 0xe0, 0x6a, 0x0b, 0x2b, 0xa0, 0x1e, 0x1a, 0x10, 0xc9, 0x86, 0xed, 0x97, 0x22, 0xbc, 0x83, 0xda, 0x83, - 0x34, 0x94, 0xa5, 0x50, 0x09, 0x6b, 0xfd, 0x97, 0x95, 0xfb, 0xed, 0xb5, 0xdb, 0xef, 0xb8, 0xe0, 0x9f, 0x0c, 0x37, - 0x3a, 0x2c, 0x70, 0xfa, 0x9d, 0x0e, 0x14, 0xdc, 0x2b, 0x05, 0x6d, 0x28, 0x08, 0x94, 0x82, 0x2e, 0x14, 0xf8, 0x4a, - 0xc1, 0x11, 0x14, 0x8c, 0x95, 0x82, 0x63, 0x28, 0xb8, 0xd3, 0xf3, 0xeb, 0x48, 0x0e, 0xf7, 0xd8, 0xb8, 0x31, 0xe9, - 0x06, 0x21, 0xca, 0x8e, 0x4d, 0x17, 0x0c, 0x87, 0xbc, 0x69, 0x2f, 0x36, 0x49, 0x98, 0xd7, 0x4b, 0xcc, 0xfb, 0x19, - 0xa3, 0x58, 0xc9, 0x6f, 0x90, 0xe6, 0xd8, 0x59, 0x0c, 0xa6, 0xc3, 0x22, 0x06, 0x81, 0x80, 0x83, 0xa6, 0x1b, 0x20, - 0xa0, 0xe9, 0xcb, 0x95, 0x13, 0x71, 0x1c, 0x94, 0xb5, 0x2c, 0xde, 0xd1, 0xe7, 0x2c, 0xb9, 0x05, 0x0a, 0x6b, 0x8e, - 0x96, 0x2a, 0x04, 0xfc, 0x12, 0x3a, 0xfd, 0x37, 0x6c, 0xb4, 0x9c, 0x6a, 0x97, 0xf1, 0x74, 0xa7, 0x7a, 0x5e, 0x7d, - 0x05, 0xa3, 0xd4, 0x49, 0xd9, 0x61, 0x89, 0x6d, 0xc9, 0xbf, 0x45, 0x8f, 0x79, 0xb9, 0x7e, 0x06, 0x63, 0xd3, 0x32, - 0x32, 0x0e, 0x81, 0xef, 0x00, 0x8c, 0x14, 0xfd, 0xf8, 0x25, 0xc0, 0x59, 0x79, 0xbe, 0xf2, 0x94, 0xf1, 0x9c, 0xfd, - 0xc0, 0xd2, 0xd4, 0x9b, 0x8a, 0xfa, 0xf5, 0x71, 0x82, 0x41, 0x8c, 0xbc, 0x7f, 0x21, 0x00, 0x41, 0x72, 0x16, 0xd4, - 0xec, 0x1e, 0x92, 0xf8, 0x5e, 0x03, 0xcb, 0x1a, 0xd8, 0x50, 0x85, 0x0d, 0x40, 0x60, 0xc3, 0x12, 0x96, 0xb5, 0xf5, - 0x70, 0xf8, 0xef, 0x58, 0x58, 0x2d, 0xcc, 0xbc, 0x69, 0xb5, 0x88, 0xf6, 0x41, 0xae, 0x8e, 0x4d, 0x2a, 0xcb, 0x4b, - 0x85, 0x9f, 0xa3, 0xfd, 0x0d, 0xe3, 0xe9, 0x9f, 0xaa, 0xfa, 0xdd, 0xa2, 0xb2, 0xff, 0x10, 0x99, 0x41, 0x36, 0xb4, - 0x11, 0xc6, 0x9a, 0x0d, 0x20, 0xec, 0x45, 0xd9, 0xcc, 0x42, 0xef, 0xaa, 0x56, 0x3b, 0x32, 0x4c, 0x1b, 0xd7, 0x76, - 0x5d, 0xf5, 0x29, 0xed, 0x25, 0xd3, 0x91, 0xd7, 0x72, 0xdb, 0xc7, 0xa6, 0xf8, 0xb3, 0x9d, 0xae, 0x91, 0x63, 0x0f, - 0xda, 0x38, 0xb8, 0x5b, 0x4f, 0xe2, 0x28, 0xb3, 0x26, 0xde, 0x3c, 0x08, 0x1f, 0x7a, 0xf3, 0x38, 0x8a, 0xd3, 0x85, - 0xe7, 0xb3, 0x3e, 0x79, 0xd0, 0x81, 0x2b, 0x69, 0x1f, 0xa3, 0x15, 0x70, 0x87, 0x39, 0xd7, 0x6e, 0x27, 0x6c, 0x4e, - 0xad, 0x65, 0x30, 0x82, 0x49, 0xc8, 0x56, 0x39, 0xff, 0x7c, 0xa9, 0x32, 0x55, 0xc5, 0x2d, 0x47, 0x2d, 0x80, 0x23, - 0xe5, 0x91, 0x0e, 0x20, 0xbe, 0x4f, 0x7f, 0xe1, 0x8d, 0x31, 0x38, 0x9f, 0xdd, 0xee, 0x26, 0x6c, 0xae, 0xd9, 0xdd, - 0x8d, 0x9d, 0x27, 0xf1, 0xfd, 0x19, 0x8c, 0x16, 0x1b, 0x5b, 0x29, 0x0b, 0x27, 0xf8, 0xc6, 0x42, 0xe7, 0x0a, 0xd1, - 0x8f, 0x85, 0x17, 0x71, 0xe8, 0x8d, 0xcd, 0xfb, 0xf0, 0xba, 0xd7, 0xd6, 0x9c, 0xfe, 0x3c, 0x88, 0x2c, 0x9a, 0xce, - 0xb1, 0xb3, 0x50, 0xfa, 0x52, 0xe1, 0x67, 0xac, 0xb1, 0xba, 0xab, 0x39, 0x7d, 0xb8, 0xac, 0x4d, 0xc2, 0xf8, 0xbe, - 0x37, 0x0b, 0xc6, 0x63, 0x16, 0xf5, 0x71, 0xcc, 0xb2, 0x90, 0x85, 0x61, 0xb0, 0x48, 0x83, 0xb4, 0x3f, 0xf7, 0x56, - 0xbc, 0xd7, 0xc3, 0x4d, 0xbd, 0x76, 0x78, 0xaf, 0x9d, 0xbd, 0x7b, 0x55, 0xba, 0x01, 0x47, 0x0e, 0xea, 0x87, 0x0f, - 0xad, 0xab, 0x39, 0x95, 0x79, 0xee, 0xdd, 0xeb, 0x22, 0x61, 0xeb, 0xb9, 0x97, 0x4c, 0x83, 0xa8, 0xe7, 0xe4, 0xf6, - 0xdd, 0x9a, 0x36, 0xc6, 0xd3, 0x93, 0x93, 0x93, 0xdc, 0x1e, 0x8b, 0x27, 0x67, 0x3c, 0xce, 0x6d, 0x5f, 0x3c, 0x4d, - 0x26, 0x8e, 0x33, 0x99, 0xe4, 0x76, 0x20, 0x0a, 0x3a, 0x6d, 0x7f, 0xdc, 0x69, 0xe7, 0xf6, 0xbd, 0x52, 0x23, 0xb7, - 0x19, 0x7f, 0x4a, 0xd8, 0xb8, 0x8f, 0x1b, 0xe9, 0x9e, 0x96, 0xfe, 0xd8, 0x71, 0x72, 0xc4, 0x00, 0xd7, 0x25, 0xdc, - 0x84, 0x82, 0x9d, 0x9b, 0xf5, 0xde, 0x35, 0xb5, 0xe2, 0x73, 0xbe, 0xdf, 0x58, 0x6f, 0xec, 0x25, 0x9f, 0x6e, 0x34, - 0x65, 0x16, 0x9e, 0x47, 0xd5, 0xd6, 0x02, 0x0c, 0xd6, 0xaa, 0x07, 0x51, 0xab, 0xfa, 0xa3, 0x38, 0x81, 0x33, 0x9b, - 0x78, 0xe3, 0x60, 0x99, 0xf6, 0xdc, 0xf6, 0x62, 0x25, 0x8a, 0xf8, 0x5e, 0x2f, 0x0a, 0xf0, 0xec, 0xf5, 0xd2, 0x38, - 0x0c, 0xc6, 0xa2, 0x68, 0xd3, 0x59, 0x72, 0xdb, 0x46, 0x1f, 0x7d, 0xb6, 0x03, 0x8c, 0x3c, 0xe0, 0x85, 0xa1, 0x66, - 0x77, 0x52, 0x8d, 0x79, 0x29, 0xca, 0x73, 0x35, 0x27, 0x25, 0xb8, 0xa0, 0x7f, 0xb6, 0x7b, 0xb8, 0x58, 0xc9, 0x3d, - 0xef, 0x1e, 0x2d, 0x56, 0xf9, 0xd7, 0x73, 0x36, 0x0e, 0x3c, 0xad, 0x55, 0xec, 0x26, 0xd7, 0x01, 0x99, 0xaf, 0xb1, - 0xde, 0xb0, 0x4d, 0xc5, 0xb1, 0x80, 0xe8, 0x7e, 0x4f, 0x82, 0xf9, 0x22, 0x4e, 0x32, 0x2f, 0xca, 0xf2, 0x7c, 0x78, - 0x93, 0xe7, 0xfd, 0xab, 0xa0, 0x75, 0xfd, 0xcf, 0x16, 0xd1, 0x69, 0xd2, 0x91, 0xe4, 0xc6, 0x8d, 0xf9, 0x96, 0xa9, - 0xf6, 0x18, 0x40, 0xc6, 0xd0, 0x16, 0x43, 0xad, 0x4c, 0x54, 0xb2, 0x5e, 0x99, 0x80, 0x2c, 0xab, 0x93, 0x7d, 0x47, - 0xb9, 0x0a, 0x52, 0x20, 0xa8, 0xf0, 0x96, 0x0d, 0xae, 0x14, 0xdb, 0x0e, 0x60, 0x56, 0xb0, 0x32, 0x99, 0xd6, 0x3f, - 0xdb, 0xc4, 0x33, 0x7e, 0xb3, 0x9b, 0x67, 0xfc, 0x39, 0xdb, 0x87, 0x67, 0xfc, 0xe6, 0x8b, 0xf3, 0x8c, 0xcf, 0xea, - 0xa6, 0xf5, 0x17, 0xf1, 0x40, 0x97, 0x12, 0x7d, 0x20, 0x4d, 0x09, 0x05, 0xad, 0xb9, 0xf8, 0xc3, 0x96, 0xf0, 0xa2, - 0x37, 0x4a, 0xc3, 0x46, 0x94, 0x1b, 0x84, 0xaf, 0xef, 0xa2, 0xc1, 0x3f, 0x12, 0xf5, 0x79, 0x32, 0x19, 0xbc, 0x89, - 0x95, 0x02, 0xf9, 0xc4, 0x4d, 0x1d, 0x4a, 0x01, 0x06, 0xe8, 0x8d, 0xb0, 0x70, 0xc4, 0x14, 0x0c, 0xe0, 0x9f, 0x4c, - 0x16, 0xbd, 0x63, 0x69, 0xd9, 0xd5, 0x2f, 0x0f, 0xa1, 0x25, 0xcd, 0x29, 0x85, 0x17, 0x4a, 0x4d, 0x94, 0x38, 0x65, - 0x19, 0x77, 0x1b, 0xfd, 0xf6, 0xe1, 0x62, 0xdc, 0xba, 0x88, 0x8d, 0x3c, 0x48, 0xdf, 0x55, 0x7d, 0x40, 0xb8, 0xae, - 0x65, 0xa0, 0x4e, 0x27, 0xe7, 0xd6, 0x59, 0x6a, 0x8e, 0x65, 0x78, 0x4d, 0xcd, 0xcf, 0x4b, 0x33, 0xed, 0xa9, 0x0d, - 0x79, 0xae, 0xa7, 0x1a, 0x31, 0xe6, 0x06, 0xf8, 0x6b, 0xce, 0x01, 0x62, 0xfa, 0x2a, 0x74, 0x9d, 0x1d, 0x53, 0xf3, - 0x60, 0x9c, 0xe7, 0x46, 0x5f, 0x00, 0x42, 0x21, 0xb4, 0x6c, 0x17, 0x13, 0x97, 0xde, 0x4b, 0x0b, 0x02, 0xae, 0x91, - 0x23, 0x75, 0xdb, 0x05, 0xa8, 0xaf, 0xb9, 0x72, 0x8e, 0xc3, 0x4c, 0xd7, 0x08, 0x7c, 0x64, 0xd6, 0xa0, 0x4c, 0x08, - 0xd4, 0xfa, 0x12, 0xfe, 0xe2, 0x95, 0x28, 0xa8, 0xdb, 0x47, 0x12, 0x70, 0x50, 0xff, 0x0e, 0x8e, 0xee, 0x44, 0xfe, - 0xb9, 0x0e, 0xb0, 0xc7, 0xeb, 0xe0, 0x43, 0xae, 0x4b, 0xde, 0x0f, 0xb7, 0xdf, 0xd9, 0xe9, 0x01, 0x34, 0x38, 0xab, - 0xa8, 0xe9, 0x77, 0x58, 0xff, 0x01, 0x2b, 0x91, 0xde, 0x9b, 0x76, 0x7a, 0xaf, 0xbd, 0x58, 0x8b, 0x20, 0x11, 0x99, - 0xb7, 0xb0, 0xe0, 0x8a, 0x8f, 0xb8, 0x97, 0x63, 0x3c, 0x25, 0x1e, 0x45, 0x7f, 0x99, 0x02, 0x6e, 0xc4, 0x8b, 0x2a, - 0xe2, 0x9f, 0xbe, 0xbf, 0x4c, 0xd2, 0x38, 0xe9, 0x2d, 0xe2, 0x20, 0xca, 0x58, 0x92, 0x23, 0xa8, 0xae, 0x11, 0x3e, - 0x02, 0x3c, 0x37, 0xeb, 0x78, 0xe1, 0xf9, 0x41, 0xf6, 0xd0, 0x73, 0x38, 0x4b, 0xe1, 0xf4, 0x39, 0x77, 0xe0, 0x34, - 0xd6, 0xef, 0x71, 0x68, 0xbe, 0x44, 0xc6, 0x2f, 0xa9, 0xb3, 0x33, 0xea, 0x36, 0xef, 0x2b, 0x6f, 0x29, 0x4c, 0x06, - 0xb0, 0x1f, 0x5e, 0x62, 0x4d, 0x01, 0xcb, 0xc3, 0x52, 0x3b, 0x63, 0x36, 0x35, 0x11, 0x6b, 0x83, 0x5c, 0x5e, 0xfc, - 0xd9, 0x5d, 0x43, 0x73, 0x9a, 0x8b, 0x81, 0xe3, 0x31, 0xf6, 0x19, 0x59, 0xcf, 0x83, 0xa4, 0x52, 0xe6, 0x3e, 0x35, - 0x47, 0x6c, 0x12, 0x27, 0x8c, 0x42, 0xaa, 0xba, 0x27, 0x8b, 0xd5, 0xfe, 0xdd, 0x6f, 0x9f, 0x7e, 0x73, 0x3f, 0x51, - 0x9c, 0xb5, 0x44, 0x67, 0xc6, 0x8e, 0xde, 0xea, 0xf4, 0x0c, 0x58, 0x43, 0x82, 0xbc, 0x4f, 0xd1, 0xab, 0x7a, 0xba, - 0xde, 0x6f, 0x8c, 0x5c, 0xb5, 0x88, 0x39, 0xcd, 0x4b, 0x58, 0xe8, 0x65, 0xc1, 0x9d, 0xe0, 0x19, 0x3b, 0x47, 0x8b, - 0x95, 0x58, 0x63, 0x24, 0x78, 0x8f, 0x58, 0xa4, 0xca, 0x50, 0xc4, 0x22, 0x55, 0x8b, 0x71, 0x91, 0xfa, 0xb5, 0xd9, - 0x88, 0x60, 0x0e, 0x15, 0x4a, 0xdf, 0x5d, 0xac, 0x54, 0x12, 0x5d, 0x34, 0x93, 0x94, 0xba, 0x1a, 0x85, 0x6b, 0x1e, - 0x8c, 0xc7, 0x21, 0xcb, 0x4b, 0x0b, 0x5d, 0x5e, 0x4b, 0x05, 0x38, 0x12, 0x0e, 0xde, 0x28, 0x8d, 0xc3, 0x65, 0xc6, - 0x9a, 0xc1, 0x45, 0xc0, 0x69, 0x3b, 0x05, 0x70, 0xf0, 0x77, 0x79, 0xac, 0x5d, 0x60, 0xb7, 0x61, 0x9b, 0x38, 0x7d, - 0x08, 0xba, 0x6b, 0x75, 0xca, 0x43, 0x87, 0x57, 0x72, 0xd0, 0x66, 0xc3, 0x44, 0x4c, 0x20, 0x4b, 0x84, 0xbd, 0x35, - 0xdb, 0xe5, 0x65, 0x32, 0xf0, 0xa8, 0x2c, 0xca, 0xcb, 0x93, 0xf9, 0x73, 0xce, 0xd8, 0xab, 0xe6, 0x33, 0xf6, 0x4a, - 0x9c, 0xb1, 0xed, 0x3b, 0xf3, 0xe9, 0xc4, 0x85, 0xff, 0xfa, 0xc5, 0x84, 0x7a, 0x8e, 0xd6, 0x59, 0xac, 0x34, 0x77, - 0xb1, 0xd2, 0xac, 0xf6, 0x62, 0xa5, 0x61, 0xd7, 0x68, 0x7f, 0x61, 0xda, 0x6d, 0xc3, 0x74, 0x34, 0x28, 0x84, 0x3f, - 0xa7, 0xf4, 0xca, 0x3d, 0x84, 0x77, 0xd0, 0xaa, 0x5b, 0x7f, 0xd7, 0xde, 0x7e, 0xd4, 0xe9, 0x2c, 0x09, 0xa4, 0x6d, - 0xd8, 0x99, 0x37, 0x1a, 0xb1, 0x71, 0x6f, 0x12, 0xfb, 0xcb, 0xf4, 0xdf, 0x7c, 0xfc, 0x1c, 0x88, 0x5b, 0x11, 0x41, - 0xa5, 0x1f, 0xd1, 0x14, 0x14, 0x25, 0x77, 0x4c, 0xf4, 0xb0, 0x96, 0xeb, 0xd4, 0xa3, 0x08, 0xc1, 0x6d, 0xfb, 0xb0, - 0x61, 0x93, 0x37, 0x03, 0xfa, 0x4f, 0x5b, 0xa5, 0xcd, 0x28, 0xe6, 0x33, 0xc0, 0xb2, 0x15, 0x1c, 0x8f, 0x87, 0x06, - 0x5f, 0x4d, 0xe7, 0xa4, 0x79, 0xb8, 0xd7, 0xe2, 0x4b, 0x37, 0x82, 0xa8, 0x70, 0xba, 0xc5, 0x9d, 0x3e, 0xb6, 0xf7, - 0xba, 0x69, 0x8f, 0xd4, 0x7a, 0xdd, 0x42, 0x10, 0x8a, 0xba, 0x7b, 0x62, 0xf9, 0xa7, 0xaf, 0x0e, 0xe1, 0x3f, 0xe2, - 0xea, 0x7f, 0xce, 0x9a, 0x18, 0xf5, 0x8b, 0xb2, 0x95, 0x35, 0xb1, 0x4a, 0xc8, 0x88, 0xef, 0x5f, 0x7f, 0x32, 0x79, - 0x5c, 0x83, 0xbd, 0x6b, 0x93, 0xe9, 0x52, 0xb5, 0xf6, 0xb7, 0x71, 0x0c, 0xd9, 0x2b, 0xeb, 0xd5, 0x05, 0x78, 0xc8, - 0x90, 0x3c, 0x1b, 0x40, 0x23, 0x71, 0x8f, 0x20, 0x2d, 0xbe, 0x8e, 0x6d, 0xe8, 0x2a, 0xf1, 0x76, 0xd3, 0x55, 0xe2, - 0xcd, 0xee, 0xab, 0xc4, 0xf7, 0x7b, 0x5d, 0x25, 0xde, 0x7c, 0xf1, 0xab, 0xc4, 0xdb, 0xfa, 0x55, 0xe2, 0x2a, 0x16, - 0xd6, 0xaa, 0xe6, 0xc5, 0x92, 0xff, 0xfc, 0x48, 0x4a, 0xb9, 0xcb, 0x78, 0xd0, 0x75, 0x28, 0xea, 0xef, 0xd5, 0x1f, - 0xbe, 0x58, 0xe0, 0x46, 0x7c, 0x8f, 0xe6, 0x5b, 0xc5, 0xd5, 0x82, 0x63, 0x76, 0xfc, 0x8e, 0x52, 0x1c, 0xc6, 0xd1, - 0xf4, 0x27, 0x50, 0xca, 0x82, 0x38, 0x30, 0x51, 0x5e, 0x04, 0xe9, 0x4f, 0xf1, 0x62, 0xb9, 0xb8, 0x80, 0xbe, 0x3e, - 0x06, 0x69, 0x30, 0x0a, 0x99, 0x74, 0xc6, 0x25, 0x73, 0x33, 0x2e, 0x13, 0x07, 0xfb, 0x4e, 0xf1, 0xd3, 0x5b, 0x89, - 0x9f, 0x68, 0x01, 0xca, 0x7f, 0x93, 0x1d, 0x9b, 0xde, 0x7c, 0x11, 0x11, 0x4a, 0x40, 0x65, 0xd0, 0x8f, 0xbf, 0x8c, - 0x5c, 0xc5, 0x46, 0xc3, 0x2c, 0x85, 0xbd, 0xc3, 0xc6, 0x7e, 0x58, 0xed, 0x52, 0xb3, 0x34, 0x4c, 0x19, 0x85, 0xaa, - 0x2e, 0x86, 0x9f, 0xc7, 0xcb, 0x94, 0x8d, 0xe3, 0xfb, 0x48, 0x37, 0x23, 0x69, 0xc0, 0x0f, 0x1a, 0x4e, 0xd9, 0x06, - 0xf3, 0x27, 0x7e, 0x40, 0x46, 0x39, 0x4e, 0x5a, 0x3a, 0xa4, 0xef, 0x5c, 0x2e, 0x2c, 0x52, 0x35, 0x5b, 0x38, 0x45, - 0x5d, 0x26, 0xfa, 0x79, 0xd2, 0x6a, 0xc5, 0x83, 0xc7, 0xb5, 0x14, 0xa6, 0x1a, 0xb1, 0xcd, 0xa5, 0xc2, 0x69, 0x2b, - 0x12, 0xc2, 0x45, 0x11, 0x0a, 0xa2, 0x61, 0xe1, 0xf8, 0x1b, 0x72, 0x0b, 0x2d, 0xde, 0x42, 0x20, 0x8d, 0x7c, 0xc9, - 0xd7, 0x83, 0x07, 0x46, 0xa0, 0xc7, 0xd7, 0x0a, 0x18, 0xdf, 0xdd, 0xb1, 0x24, 0xf4, 0x1e, 0x5a, 0x46, 0x1e, 0x47, - 0x3f, 0x00, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0xf3, 0x95, 0x34, 0xec, 0xa5, 0xc6, 0x10, 0x1e, 0xe0, 0x14, - 0xa2, 0x8c, 0x00, 0x32, 0xc5, 0x4e, 0xd9, 0x3f, 0x4c, 0xfa, 0xf7, 0x9f, 0x46, 0x6e, 0x5e, 0xc6, 0xf2, 0x43, 0x7f, - 0x5f, 0xec, 0xf1, 0x99, 0xe7, 0xcf, 0x9f, 0x6c, 0x9e, 0x76, 0x39, 0x43, 0x79, 0x43, 0x6b, 0x63, 0xe3, 0x29, 0x80, - 0x51, 0x5c, 0xc5, 0x4b, 0x7f, 0x86, 0x86, 0xa5, 0x5f, 0x6e, 0xbe, 0x19, 0xf4, 0x89, 0x89, 0x3a, 0xe5, 0xd4, 0x2b, - 0x45, 0x05, 0x14, 0xf0, 0xfb, 0x6f, 0x21, 0x06, 0xe5, 0xff, 0x11, 0x0c, 0xf5, 0x5d, 0xc3, 0x6f, 0xf1, 0xc1, 0xe3, - 0x36, 0x6f, 0x1f, 0xf2, 0x49, 0xf2, 0xe8, 0x0e, 0x42, 0xb9, 0xd6, 0x8c, 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0x48, 0x6a, - 0x9b, 0x82, 0xc4, 0x89, 0xaf, 0x30, 0x9b, 0xae, 0xe9, 0xdc, 0xac, 0xdf, 0x64, 0x1c, 0x5b, 0x55, 0x90, 0x0c, 0x37, - 0x79, 0x60, 0x88, 0xbe, 0xaa, 0xef, 0xe6, 0x41, 0x64, 0x62, 0x20, 0xf4, 0xfa, 0x1b, 0x6f, 0x05, 0xa1, 0x80, 0x01, - 0xb9, 0x55, 0x5f, 0x41, 0xa1, 0xa9, 0xfa, 0xa4, 0x41, 0xb6, 0x23, 0xbd, 0x11, 0x12, 0x42, 0x8b, 0x37, 0xfc, 0x8b, - 0xa6, 0x69, 0x9a, 0xbc, 0x46, 0x68, 0xf2, 0x1e, 0x81, 0xe5, 0x78, 0x1d, 0x00, 0x6d, 0x49, 0xbe, 0x58, 0x51, 0x09, - 0xdc, 0x0c, 0x50, 0x27, 0x2b, 0x0a, 0x78, 0xb4, 0xbb, 0xae, 0x23, 0x0a, 0xc4, 0x85, 0x1e, 0x22, 0x95, 0x79, 0x09, - 0x04, 0xc5, 0xed, 0x69, 0x78, 0x61, 0xc7, 0xb7, 0x5c, 0x12, 0xac, 0x39, 0xf4, 0x38, 0xec, 0xb3, 0xe6, 0xb0, 0x68, - 0x91, 0x82, 0x05, 0x41, 0xeb, 0x50, 0x89, 0x72, 0x6c, 0xb2, 0x06, 0xdc, 0x88, 0xf7, 0xa2, 0x55, 0x36, 0x67, 0xd1, - 0x52, 0xc7, 0xb4, 0x48, 0x18, 0xa6, 0x0e, 0xea, 0xbc, 0x21, 0x66, 0x0b, 0xb0, 0x4d, 0x73, 0xcb, 0x19, 0xd1, 0xc2, - 0x94, 0xa3, 0x54, 0xcf, 0xf4, 0xb9, 0x62, 0x33, 0xe5, 0xb8, 0xad, 0x4a, 0x21, 0xf8, 0x92, 0xc6, 0x55, 0x27, 0x29, - 0xb2, 0x3c, 0x86, 0x3e, 0x28, 0x40, 0x04, 0x17, 0x17, 0x09, 0xb0, 0xb7, 0xbc, 0xea, 0xa2, 0x49, 0x8d, 0x8c, 0x57, - 0x11, 0x14, 0x25, 0x46, 0xbd, 0x1b, 0x3e, 0x4e, 0x88, 0xcd, 0xb3, 0xb1, 0x1f, 0xbf, 0xd6, 0xcf, 0x86, 0x49, 0x7f, - 0x62, 0x0f, 0x44, 0x48, 0x08, 0x54, 0x9f, 0xd8, 0x03, 0xd8, 0xfe, 0xbd, 0x05, 0x69, 0x8a, 0xbe, 0x05, 0x5d, 0x9b, - 0x10, 0xed, 0xde, 0x87, 0x78, 0x4d, 0x5b, 0x0e, 0x90, 0x93, 0x6f, 0xc1, 0xe2, 0x08, 0x62, 0x48, 0x6c, 0x2c, 0x0e, - 0x31, 0x37, 0xa9, 0x6f, 0x35, 0xc2, 0xd8, 0x6a, 0x38, 0x1a, 0xc6, 0x0b, 0xd7, 0x71, 0x0e, 0x6a, 0xf5, 0x41, 0x90, - 0xdd, 0x54, 0xdb, 0x30, 0xb3, 0x81, 0xeb, 0x58, 0xc1, 0x0b, 0xbb, 0xdd, 0xaf, 0xd1, 0x68, 0x25, 0x9c, 0xe2, 0x10, - 0xc5, 0x5f, 0x67, 0xcf, 0xd6, 0xad, 0xda, 0x81, 0x34, 0xaa, 0x26, 0xea, 0x38, 0xb6, 0x9c, 0xcb, 0xbf, 0x86, 0x75, - 0xd2, 0x4f, 0xc1, 0x1c, 0x29, 0xb5, 0xc7, 0x10, 0x02, 0x02, 0xb7, 0xe0, 0x18, 0xfd, 0x55, 0x7b, 0xa9, 0xb5, 0xe8, - 0xf8, 0x18, 0xc6, 0x50, 0x66, 0x8c, 0x16, 0x1e, 0x5c, 0x6a, 0x07, 0x95, 0x2f, 0xa6, 0x55, 0x0c, 0xc7, 0x43, 0x8f, - 0xb2, 0x42, 0xa3, 0xb7, 0x95, 0x5b, 0xc0, 0xfe, 0x37, 0x90, 0x4f, 0x7b, 0x04, 0x3e, 0xff, 0x50, 0x03, 0xc2, 0x87, - 0xef, 0xec, 0x70, 0xb9, 0x28, 0x77, 0x57, 0x26, 0x92, 0xfb, 0x77, 0x86, 0x44, 0x07, 0x75, 0x68, 0xb2, 0xbf, 0x66, - 0x72, 0xf7, 0xc8, 0x2e, 0x59, 0x34, 0x2e, 0x77, 0x58, 0xa1, 0x5f, 0xfb, 0x77, 0x57, 0xc2, 0x28, 0x10, 0x57, 0x3f, - 0x6e, 0xc0, 0x28, 0x79, 0x1c, 0xe1, 0xe6, 0xa7, 0xe3, 0x16, 0xec, 0xc5, 0xc5, 0x60, 0x03, 0x0a, 0x8a, 0x25, 0x9b, - 0x29, 0x42, 0x71, 0x08, 0xde, 0x8c, 0x2e, 0xb7, 0x2d, 0xc1, 0x88, 0x6e, 0xdc, 0x89, 0x99, 0xb0, 0x29, 0x2c, 0xda, - 0x04, 0x3c, 0x1c, 0xe3, 0xbe, 0x52, 0xeb, 0x60, 0xb7, 0xd4, 0x3a, 0xdb, 0x25, 0xb5, 0x26, 0xef, 0xa5, 0xfb, 0xc4, - 0x5b, 0x28, 0xfe, 0x6f, 0x82, 0x39, 0x57, 0xdd, 0xe0, 0x4a, 0xa2, 0x6e, 0x74, 0x76, 0x12, 0xad, 0x6a, 0xbd, 0x91, - 0x95, 0x20, 0x8a, 0xbf, 0x95, 0x0b, 0x8a, 0x50, 0xa8, 0xab, 0xb2, 0xf1, 0xab, 0x42, 0x36, 0x4e, 0xb7, 0x9a, 0xc2, - 0x71, 0x45, 0x70, 0xff, 0x8a, 0x4b, 0x98, 0xbc, 0x1d, 0x14, 0xae, 0x61, 0xc5, 0x48, 0x15, 0x6f, 0xa7, 0xe2, 0xa2, - 0xa1, 0xb8, 0xd0, 0x89, 0x5b, 0x46, 0xd9, 0x93, 0xae, 0x5c, 0xb5, 0x70, 0xa9, 0x2b, 0xca, 0x41, 0xea, 0x8e, 0x43, - 0x96, 0xc5, 0xea, 0xb6, 0x29, 0xbb, 0xbb, 0xa8, 0xaf, 0x95, 0x4d, 0x22, 0xfd, 0x52, 0x08, 0xc0, 0x42, 0x4c, 0x5f, - 0xd1, 0x6b, 0x4b, 0x1b, 0x08, 0x1c, 0x64, 0x83, 0x13, 0xdd, 0x6e, 0xe9, 0x3c, 0xa5, 0x0c, 0x28, 0xb4, 0xf0, 0xaa, - 0x0c, 0x02, 0xe1, 0x7b, 0xb3, 0x6e, 0xa0, 0xf2, 0x48, 0xe4, 0x39, 0x7d, 0x07, 0xf1, 0xa2, 0xe6, 0xa8, 0x8a, 0x7c, - 0x3c, 0x99, 0x16, 0x99, 0xe7, 0x62, 0xd5, 0x7a, 0xa7, 0x24, 0xc4, 0x59, 0x73, 0x4f, 0x94, 0xb2, 0x8c, 0x9e, 0xd7, - 0xe8, 0x89, 0xef, 0xf2, 0xad, 0x93, 0x2c, 0x23, 0x0c, 0xef, 0x6e, 0x65, 0x89, 0xe7, 0x7f, 0x52, 0x86, 0x2c, 0xe4, - 0x9c, 0x20, 0x03, 0x2e, 0x6b, 0x0a, 0xfa, 0x1e, 0x46, 0x43, 0x64, 0x3d, 0xbb, 0x9d, 0x2a, 0xd2, 0x97, 0xde, 0x53, - 0xa7, 0xe3, 0xbd, 0x9a, 0x1c, 0x56, 0x84, 0xa2, 0xed, 0x6e, 0x59, 0x64, 0xbe, 0x61, 0x1c, 0xd9, 0x6c, 0x39, 0x1f, - 0xad, 0x55, 0xd9, 0xaa, 0x22, 0x72, 0xad, 0x8b, 0x59, 0xd5, 0xcf, 0x4e, 0x26, 0x93, 0xb2, 0xa0, 0xd1, 0xd1, 0x0e, - 0x51, 0x58, 0xf8, 0xd4, 0x71, 0x9c, 0xea, 0xd8, 0xb7, 0x83, 0xdd, 0x42, 0xb9, 0xed, 0x49, 0xe3, 0x88, 0x11, 0xb6, - 0xbb, 0xe0, 0x57, 0x07, 0x47, 0x6e, 0x17, 0x27, 0xbb, 0x64, 0x16, 0xd1, 0x27, 0x63, 0x88, 0x20, 0x63, 0xf3, 0xb4, - 0xe7, 0x33, 0xd4, 0xc1, 0xd8, 0xca, 0x81, 0x46, 0xc3, 0x01, 0x6b, 0x0a, 0xa6, 0x22, 0xae, 0xd8, 0x15, 0x8e, 0x86, - 0xf2, 0xf0, 0x9a, 0xf0, 0x5e, 0x7c, 0x04, 0x0f, 0xca, 0xba, 0x2e, 0xd3, 0xc6, 0x69, 0x75, 0x9d, 0xbf, 0x96, 0xea, - 0x69, 0x40, 0x00, 0xd7, 0x42, 0xa1, 0x4d, 0xf2, 0x59, 0xfc, 0x7f, 0x29, 0xff, 0x7f, 0xb5, 0x58, 0x95, 0xed, 0x47, - 0x4e, 0x40, 0xa2, 0x5d, 0x9c, 0x16, 0x1a, 0x75, 0xd3, 0x1e, 0x90, 0x56, 0x06, 0x13, 0x55, 0x81, 0x0e, 0x4a, 0xfa, - 0x52, 0x0e, 0x8c, 0x06, 0xf1, 0x3b, 0x72, 0xcc, 0xb0, 0xc4, 0x85, 0x08, 0xb1, 0xc8, 0xe0, 0x06, 0x73, 0x30, 0x5f, - 0x9e, 0xa0, 0xfe, 0xa0, 0xb4, 0x27, 0x40, 0x1b, 0x5f, 0x9b, 0xdb, 0x5e, 0xe2, 0xfe, 0xaa, 0x5e, 0x4b, 0x74, 0x0c, - 0x20, 0x73, 0xe1, 0x10, 0xa2, 0x21, 0x81, 0x56, 0xd9, 0xdc, 0x34, 0x4a, 0xf9, 0x56, 0xd5, 0xb3, 0x89, 0x81, 0x61, - 0x77, 0xcd, 0x55, 0xa8, 0x6f, 0xa1, 0x2d, 0x80, 0xc9, 0xf2, 0xed, 0x87, 0xcf, 0x16, 0x2c, 0xb1, 0xba, 0x1f, 0x5d, - 0x5c, 0x72, 0xdc, 0xbf, 0x16, 0xd2, 0xce, 0x94, 0xce, 0x3f, 0xca, 0x17, 0xbf, 0x6f, 0x14, 0xe8, 0x5d, 0x95, 0x24, - 0x74, 0xdc, 0x5a, 0xbc, 0x6d, 0xec, 0x55, 0x7b, 0x1e, 0x44, 0xfb, 0xd7, 0xf5, 0x56, 0x7b, 0xd7, 0x05, 0x82, 0xb1, - 0x77, 0x65, 0xa0, 0x38, 0x64, 0xb9, 0x90, 0x0d, 0xbe, 0x57, 0x04, 0x8a, 0xaa, 0x93, 0xaf, 0x8e, 0xad, 0x88, 0xcb, - 0xbf, 0x5a, 0x02, 0xf3, 0xb9, 0x57, 0x8e, 0x03, 0x4d, 0xa4, 0x29, 0xd3, 0x8f, 0xb5, 0x13, 0xed, 0xb8, 0xa3, 0x1d, - 0x39, 0x3a, 0xdd, 0xc2, 0x06, 0x7a, 0xb7, 0x5d, 0x78, 0xef, 0x1d, 0x3a, 0xfa, 0xd9, 0xe9, 0x54, 0x10, 0x89, 0x49, - 0x10, 0x86, 0x84, 0x2a, 0xd2, 0x2c, 0x89, 0x3f, 0xb1, 0xb2, 0x9a, 0x85, 0xca, 0xb8, 0x11, 0x48, 0x5b, 0x3c, 0xc2, - 0xd9, 0xf1, 0xbd, 0x45, 0x0f, 0xcf, 0x86, 0x5a, 0x08, 0x06, 0x9c, 0x54, 0x8a, 0x9f, 0x00, 0x1a, 0x3c, 0xd2, 0xcf, - 0x4e, 0x21, 0x8a, 0x9f, 0x36, 0x1e, 0xe8, 0x3f, 0xb4, 0x8f, 0x35, 0xb7, 0x7b, 0x67, 0x75, 0x7c, 0xc7, 0x72, 0xed, - 0x43, 0xcd, 0xb1, 0x8f, 0xac, 0xb6, 0x7d, 0xac, 0xb5, 0xed, 0x2e, 0xfc, 0xeb, 0xbb, 0xf6, 0x2b, 0xcd, 0x81, 0x27, - 0xcd, 0xb5, 0x3b, 0xf8, 0x6f, 0xdb, 0x3e, 0xbe, 0xeb, 0x10, 0xa5, 0xf7, 0x74, 0x31, 0xe4, 0xca, 0x28, 0xc0, 0x09, - 0x44, 0x3f, 0x38, 0x3b, 0x5d, 0xa6, 0x4c, 0x5b, 0x0d, 0xf4, 0x57, 0xba, 0x36, 0x4b, 0xd8, 0x64, 0xa0, 0x3f, 0xf5, - 0x94, 0x52, 0xf7, 0xa4, 0xb1, 0xb8, 0x7d, 0xdc, 0x58, 0xdc, 0x39, 0x6a, 0x2c, 0x3e, 0xec, 0x96, 0x8b, 0x0f, 0xa6, - 0xf4, 0x4a, 0x49, 0xa2, 0x37, 0xf7, 0xb2, 0x24, 0x58, 0xb5, 0x5c, 0x0d, 0xd0, 0xb5, 0x05, 0xff, 0x1c, 0xb7, 0x0d, - 0xd9, 0x6a, 0x04, 0xad, 0x24, 0x34, 0x8e, 0x4f, 0x34, 0xf7, 0xe8, 0x6f, 0xed, 0x23, 0x1f, 0xea, 0x41, 0xca, 0x47, - 0xf8, 0xbb, 0xeb, 0x9c, 0xf8, 0x8e, 0x06, 0x0d, 0x5d, 0xf8, 0x6f, 0xd6, 0x6d, 0xfb, 0xf4, 0xe0, 0xc0, 0xfb, 0x8f, - 0xee, 0x71, 0xea, 0x58, 0x2e, 0xfc, 0xf7, 0xab, 0x54, 0xb9, 0x83, 0xc2, 0x5f, 0xed, 0xf7, 0xd0, 0xd1, 0x3a, 0x27, - 0xb3, 0xb6, 0xfd, 0xea, 0xee, 0xd8, 0x3e, 0x99, 0xb9, 0xc7, 0x1f, 0xe9, 0x29, 0xb4, 0xda, 0xf6, 0x2b, 0xf8, 0xfb, - 0xd8, 0x71, 0x66, 0x96, 0x6b, 0x9f, 0xdc, 0x75, 0xec, 0x4e, 0x68, 0x1d, 0xd9, 0x27, 0xf0, 0xf7, 0x2b, 0x80, 0x17, - 0xe0, 0xca, 0x73, 0x74, 0x6a, 0xb0, 0x31, 0x2a, 0xf6, 0x1b, 0xea, 0x47, 0xda, 0x87, 0x5a, 0xf7, 0xf0, 0x6f, 0x27, - 0x77, 0xd6, 0xe1, 0xcc, 0x6d, 0xdf, 0x59, 0x1b, 0x7f, 0x7e, 0x04, 0xc8, 0x6f, 0x5f, 0x38, 0x00, 0x23, 0x26, 0xe5, - 0xf8, 0xcb, 0xd0, 0xbc, 0xdc, 0x24, 0x46, 0x7f, 0xbf, 0x5b, 0x8c, 0xfe, 0xdd, 0x72, 0x1f, 0x31, 0xfa, 0xfb, 0x2f, - 0x2e, 0x46, 0xbf, 0xac, 0x5a, 0x71, 0xbf, 0xaf, 0x06, 0x0f, 0xff, 0x79, 0x5d, 0x65, 0x92, 0x03, 0xaf, 0x75, 0x7d, - 0xb5, 0xbc, 0x81, 0xb8, 0x3a, 0xef, 0xe3, 0xc1, 0x77, 0xcb, 0x92, 0x89, 0x52, 0x0c, 0x18, 0xe0, 0x7d, 0x4c, 0x18, - 0xe0, 0xd7, 0xe5, 0x00, 0xec, 0x22, 0x38, 0xd5, 0x0c, 0xc6, 0xd6, 0xcc, 0x0b, 0x27, 0x92, 0xe2, 0x42, 0x49, 0x1f, - 0x8b, 0xc1, 0x66, 0x1e, 0x88, 0x09, 0x28, 0x6b, 0x96, 0xf3, 0x28, 0xed, 0x1d, 0x39, 0x80, 0xe6, 0xdb, 0x93, 0x24, - 0xaf, 0x34, 0xb6, 0x45, 0x24, 0xa2, 0x5b, 0x6e, 0xd3, 0xbf, 0xf1, 0x3d, 0x9a, 0xac, 0x35, 0xf7, 0xee, 0xd6, 0xfb, - 0xd5, 0xc0, 0x16, 0x44, 0x98, 0xf4, 0x01, 0xb3, 0xd1, 0xf4, 0xbe, 0x6c, 0x38, 0x56, 0x31, 0x15, 0xdc, 0x3c, 0x52, - 0x18, 0x49, 0xb5, 0xbd, 0x5b, 0x36, 0x3c, 0xdb, 0x35, 0xcd, 0x86, 0xcf, 0x97, 0x9a, 0x6f, 0xb1, 0x7a, 0x93, 0x1d, - 0x57, 0x41, 0x55, 0x49, 0x7d, 0xd5, 0x08, 0x90, 0x82, 0xf7, 0x2c, 0x4c, 0xe3, 0x0a, 0xc6, 0xc7, 0xd1, 0x90, 0x1a, - 0x3b, 0xca, 0xbb, 0x52, 0x9f, 0xaa, 0x39, 0xdd, 0x8b, 0x35, 0xf2, 0x83, 0xc1, 0xaf, 0xc0, 0xd8, 0x70, 0x7a, 0x3c, - 0x8a, 0x55, 0x38, 0xaf, 0x95, 0x7e, 0x89, 0xd5, 0xce, 0x67, 0xee, 0xba, 0xce, 0xda, 0x6c, 0x34, 0xa4, 0x75, 0xd9, - 0x5c, 0xd0, 0x68, 0xfc, 0x3c, 0x99, 0xad, 0xe6, 0x64, 0x5a, 0x8c, 0x96, 0xb9, 0xdb, 0x3a, 0x13, 0xf5, 0x9e, 0xc2, - 0x26, 0x36, 0xf9, 0x83, 0xea, 0x25, 0xbe, 0x9e, 0x40, 0x9a, 0xe2, 0x1e, 0x32, 0x11, 0x0a, 0x07, 0xd5, 0x46, 0x1b, - 0xdb, 0xfe, 0x16, 0xf3, 0x0f, 0xb5, 0x63, 0xde, 0x09, 0xda, 0xea, 0x6e, 0xb3, 0x18, 0x91, 0xae, 0x0d, 0xeb, 0x92, - 0x02, 0xd5, 0xed, 0x1e, 0x9b, 0xee, 0x91, 0x69, 0x1f, 0x77, 0x8d, 0x5c, 0x1c, 0x38, 0xb5, 0xcb, 0x12, 0x40, 0xc0, - 0x64, 0x57, 0x0e, 0x33, 0x88, 0x82, 0x2c, 0xf0, 0xc2, 0x1c, 0x50, 0x7d, 0x99, 0xe7, 0xfd, 0xd7, 0x32, 0xcd, 0x60, - 0x8e, 0x82, 0x25, 0x43, 0x73, 0x65, 0x6b, 0xc4, 0xb2, 0x7b, 0xc6, 0xa2, 0x0d, 0xaa, 0xdc, 0xaa, 0xf5, 0xf3, 0x9f, - 0x67, 0x0b, 0x9a, 0x93, 0x9d, 0xc5, 0x28, 0x8b, 0xf8, 0xfe, 0x10, 0xa6, 0xba, 0xf9, 0xd0, 0xfc, 0x71, 0x13, 0xc2, - 0xfd, 0xd7, 0x6e, 0x84, 0x9b, 0xb1, 0x7d, 0x10, 0xee, 0xbf, 0xbe, 0x38, 0xc2, 0xfd, 0x51, 0x45, 0xb8, 0x25, 0x4f, - 0x95, 0x42, 0x26, 0xfa, 0x01, 0x9f, 0x5b, 0x10, 0x75, 0xf7, 0xa5, 0x7e, 0x40, 0xec, 0xa5, 0xae, 0x64, 0x43, 0xfd, - 0x58, 0x4a, 0xef, 0x82, 0x57, 0x76, 0x0c, 0x3f, 0x4a, 0xa9, 0x24, 0x20, 0x53, 0xa8, 0xcc, 0x79, 0x0d, 0x7d, 0x5e, - 0x44, 0x59, 0x68, 0xbf, 0xe7, 0xd7, 0x12, 0x50, 0x41, 0x7c, 0x17, 0x27, 0x73, 0x0f, 0x43, 0xaf, 0xe9, 0x98, 0x16, - 0x0e, 0x1e, 0x1c, 0xf0, 0x8e, 0xf2, 0xe3, 0x68, 0x2c, 0xe5, 0xe8, 0x6c, 0x70, 0x4d, 0xfc, 0xa0, 0xfe, 0xc0, 0xbc, - 0x44, 0x37, 0xe9, 0x35, 0x2c, 0xee, 0x8b, 0x8e, 0xf3, 0xa2, 0x7d, 0xf8, 0xe2, 0xc8, 0x81, 0xff, 0xb9, 0xac, 0x93, - 0x9b, 0xbc, 0xe2, 0x3c, 0x8e, 0x20, 0x33, 0x85, 0xa8, 0xb9, 0xa9, 0xda, 0x3d, 0x63, 0x9f, 0x8a, 0x5a, 0xc7, 0xcd, - 0x95, 0xc6, 0xde, 0x43, 0x51, 0xa7, 0xb1, 0xc6, 0x2c, 0x5e, 0x2a, 0xc3, 0x6a, 0x18, 0x4d, 0x10, 0x2d, 0x41, 0x32, - 0xa4, 0xd4, 0x50, 0x5f, 0xf3, 0xe9, 0x16, 0xf3, 0x62, 0x9d, 0xfc, 0xa6, 0x48, 0x7f, 0x23, 0xd2, 0x70, 0xec, 0x84, - 0x20, 0x17, 0xaa, 0x3b, 0x18, 0x3c, 0x1b, 0x13, 0xc0, 0x68, 0x90, 0x7c, 0xae, 0xc8, 0x71, 0x8e, 0x0b, 0x94, 0x25, - 0xcb, 0xc8, 0xa7, 0x34, 0xe6, 0xde, 0x28, 0x6d, 0x05, 0x07, 0x10, 0x97, 0x13, 0x3f, 0x6c, 0xe0, 0xaa, 0x79, 0x67, - 0x4e, 0x91, 0x2b, 0x20, 0x15, 0xab, 0xe2, 0xbd, 0xc8, 0xcc, 0x84, 0x32, 0x8c, 0xe2, 0xd2, 0x5a, 0x03, 0xef, 0x85, - 0x6c, 0xf8, 0x22, 0x33, 0x21, 0xcb, 0x27, 0x2c, 0xf7, 0xf3, 0xe7, 0x54, 0x0b, 0xf2, 0xee, 0xd1, 0xb4, 0xce, 0x7d, - 0x99, 0xab, 0x4b, 0xd7, 0xbc, 0x69, 0xac, 0x63, 0xae, 0xae, 0x9e, 0x6f, 0xc6, 0x2f, 0x5f, 0x9e, 0x0d, 0x5c, 0x83, - 0x67, 0x8d, 0x2c, 0xa5, 0x38, 0xba, 0xdc, 0x4f, 0x35, 0x6e, 0x34, 0x3a, 0x6d, 0x2d, 0x82, 0x68, 0x2a, 0x34, 0xd3, - 0x12, 0x7b, 0x41, 0xca, 0x01, 0x52, 0x81, 0x79, 0x42, 0x45, 0x2d, 0xea, 0xdc, 0xb1, 0x04, 0x32, 0x5e, 0x0e, 0xf4, - 0x8e, 0xed, 0xd8, 0x8e, 0x2e, 0x1b, 0x4e, 0x82, 0xe9, 0x60, 0x1d, 0x67, 0x1e, 0x24, 0x6f, 0x09, 0xe3, 0x29, 0x78, - 0x7e, 0x64, 0x41, 0x16, 0x42, 0x26, 0x10, 0x70, 0x01, 0x99, 0xd3, 0xad, 0x31, 0xe7, 0xf6, 0xb8, 0x5e, 0xf2, 0x09, - 0xb3, 0xc1, 0x09, 0xa7, 0x2f, 0x8c, 0x3f, 0xf3, 0x03, 0x10, 0xc3, 0x96, 0xde, 0x82, 0x5c, 0x84, 0x2c, 0x49, 0x2d, - 0xd5, 0xbe, 0xbd, 0xa7, 0x41, 0x1b, 0xc8, 0x13, 0x8e, 0x1d, 0x4c, 0x12, 0x6f, 0x0e, 0x41, 0xb3, 0xd7, 0xb9, 0xc9, - 0x31, 0xad, 0xce, 0x51, 0xad, 0xe6, 0xbe, 0x3a, 0x32, 0xb5, 0xb6, 0x6b, 0x6a, 0x0e, 0xa0, 0x5b, 0x3d, 0x37, 0xd7, - 0xf9, 0x4d, 0x7f, 0x97, 0x8a, 0x8e, 0xf0, 0xcb, 0x53, 0x9a, 0x07, 0x29, 0xe7, 0xb8, 0xf0, 0x33, 0xa3, 0xd0, 0x81, - 0x2d, 0x25, 0x9c, 0x75, 0x40, 0x62, 0xfa, 0x2b, 0xb6, 0xca, 0x0c, 0xcc, 0x94, 0xc1, 0xab, 0x04, 0xc6, 0x1a, 0x5d, - 0xd3, 0x82, 0x48, 0x0b, 0x7e, 0xfb, 0xad, 0x15, 0x80, 0xf9, 0xfd, 0x40, 0x81, 0x0f, 0x3c, 0x1b, 0x25, 0x80, 0x05, - 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0x2c, 0x7e, 0x70, 0xc5, 0x9e, 0x1d, 0x7a, 0xd1, 0x14, - 0x50, 0x9a, 0x17, 0x4d, 0x6b, 0x06, 0x04, 0xe4, 0x5d, 0x57, 0x29, 0x2d, 0xba, 0x2a, 0x94, 0xfb, 0xe9, 0xb7, 0x0f, - 0x57, 0x94, 0x09, 0x08, 0xb2, 0x4e, 0x7b, 0x63, 0x74, 0x05, 0x2b, 0x74, 0x0f, 0x2f, 0x07, 0x5f, 0x9d, 0xce, 0x59, - 0xe6, 0x91, 0xe0, 0x12, 0xae, 0x78, 0xc0, 0x0e, 0x68, 0xbe, 0xc8, 0xe2, 0x49, 0x17, 0xbc, 0x31, 0xbb, 0x0b, 0x7c, - 0x7e, 0x4f, 0x33, 0x35, 0x4e, 0xa7, 0x2c, 0xb4, 0x51, 0x1a, 0xb8, 0x26, 0x99, 0xc8, 0xfa, 0x1e, 0x06, 0x18, 0x1c, - 0x44, 0xb1, 0x7e, 0xf6, 0x95, 0xf4, 0x26, 0xda, 0xb4, 0x08, 0x90, 0x8e, 0xef, 0x3a, 0x61, 0xe1, 0xbf, 0x07, 0x5f, - 0x01, 0xe1, 0xfe, 0xea, 0x46, 0x37, 0xfa, 0x99, 0x8d, 0xf7, 0x98, 0xaf, 0x1a, 0xd2, 0xd2, 0xe1, 0x1d, 0x95, 0x5f, - 0x36, 0x3b, 0xca, 0x65, 0x13, 0x7e, 0xef, 0xbe, 0xba, 0x9e, 0x9d, 0x22, 0x41, 0x3b, 0x83, 0xdb, 0xc5, 0xba, 0x74, - 0xe7, 0x74, 0xfb, 0x78, 0x41, 0x1d, 0x85, 0x9e, 0xff, 0x49, 0xdc, 0x50, 0xd5, 0x87, 0x7d, 0xee, 0xa2, 0x92, 0xb3, - 0x6b, 0xdc, 0xcb, 0xb8, 0x95, 0xd7, 0xf8, 0x65, 0xfc, 0xd4, 0xfd, 0x2c, 0xc8, 0xe4, 0x65, 0x18, 0x1f, 0x72, 0xd0, - 0xe6, 0xe0, 0xf8, 0x8a, 0xeb, 0x0f, 0x5c, 0x50, 0xdd, 0x93, 0xbf, 0x75, 0xef, 0x5c, 0x67, 0xd6, 0x76, 0x6d, 0xb8, - 0xe6, 0xcc, 0x3a, 0xf6, 0x71, 0x68, 0x75, 0xec, 0x63, 0xf8, 0xfb, 0x08, 0x57, 0x2f, 0xab, 0x6d, 0x1f, 0x7e, 0x74, - 0xdb, 0xa1, 0x75, 0x62, 0x1f, 0xc3, 0xdf, 0x25, 0xb5, 0xfa, 0x19, 0x2f, 0x3d, 0x70, 0xe1, 0xf9, 0xaa, 0x84, 0x05, - 0x94, 0xdf, 0x52, 0x8b, 0x60, 0x96, 0xc8, 0x5b, 0x83, 0x26, 0x02, 0x50, 0x86, 0x6e, 0x8a, 0x80, 0x80, 0x51, 0xbf, - 0x05, 0x79, 0xb2, 0x31, 0xc2, 0xbb, 0x30, 0xc8, 0x88, 0x8a, 0x9c, 0xef, 0x9b, 0x8f, 0x11, 0x6f, 0xd3, 0x1c, 0x6a, - 0x5b, 0xa4, 0x0e, 0x22, 0xd5, 0xc5, 0xdf, 0x17, 0x18, 0x45, 0x47, 0x04, 0x07, 0x57, 0xb0, 0x52, 0x91, 0xbe, 0x2e, - 0xdf, 0x3d, 0x70, 0xf4, 0x1b, 0x65, 0x32, 0x7d, 0xca, 0x17, 0xed, 0x9b, 0xab, 0x33, 0x64, 0xef, 0x7f, 0xb4, 0x1f, - 0xcc, 0x1a, 0x4a, 0xfd, 0x88, 0x38, 0x9e, 0xe3, 0x20, 0x91, 0xc3, 0x53, 0x50, 0xb4, 0xdb, 0x1c, 0xa3, 0xdc, 0x80, - 0x3c, 0x13, 0x17, 0xc0, 0x25, 0xdf, 0x79, 0xa1, 0x62, 0x7a, 0xa1, 0xb4, 0x7c, 0x22, 0x31, 0xff, 0xf3, 0xe7, 0xc5, - 0xe0, 0xac, 0xca, 0xb8, 0x4f, 0xdd, 0x2e, 0x90, 0xdd, 0x2e, 0xeb, 0x6c, 0xb5, 0x02, 0xda, 0x1d, 0x08, 0xb6, 0x08, - 0x1d, 0x29, 0x34, 0xfd, 0x42, 0xc7, 0xb8, 0xd1, 0x14, 0xa9, 0xa6, 0x61, 0x84, 0x10, 0xba, 0x95, 0xab, 0x8e, 0x6e, - 0xf4, 0x23, 0xa1, 0x30, 0x8b, 0xb6, 0x04, 0xbf, 0xe5, 0x77, 0x31, 0x1d, 0x40, 0xb3, 0x65, 0x1e, 0x3b, 0x5c, 0x1a, - 0xff, 0xdf, 0x93, 0x40, 0xf7, 0x22, 0xd0, 0xf0, 0x55, 0x4e, 0x6b, 0xc9, 0xdd, 0x44, 0xd2, 0x55, 0x22, 0xa8, 0x2c, - 0x3d, 0xd7, 0xa1, 0x08, 0x12, 0x10, 0x61, 0xce, 0x31, 0x69, 0xde, 0x24, 0xa9, 0x45, 0x51, 0x60, 0x06, 0x10, 0xfd, - 0xb9, 0x25, 0x5c, 0x9d, 0x8c, 0xe7, 0xcf, 0x37, 0x12, 0x21, 0x52, 0x27, 0xab, 0xa9, 0x17, 0x75, 0x15, 0xbf, 0xe9, - 0x2a, 0x8a, 0x91, 0xfd, 0x22, 0xd6, 0x10, 0x56, 0x59, 0xb4, 0xf7, 0xf0, 0xe7, 0x88, 0x79, 0x99, 0xcd, 0xf5, 0x20, - 0x2d, 0x85, 0xb8, 0x9b, 0x2e, 0xeb, 0x80, 0x3d, 0x16, 0x0f, 0xb6, 0xc5, 0x23, 0xcb, 0x3d, 0x5b, 0x7f, 0x5c, 0x72, - 0x3f, 0x64, 0xe8, 0xe3, 0x37, 0xa7, 0x08, 0x9e, 0xf2, 0x2e, 0xf3, 0x28, 0xc2, 0x86, 0x4a, 0x72, 0xe3, 0xcc, 0x13, - 0x89, 0x3e, 0x80, 0x2f, 0xef, 0x37, 0x2a, 0x0c, 0x15, 0x5f, 0xe5, 0xb3, 0x77, 0x57, 0xdf, 0x68, 0x7c, 0xff, 0x93, - 0x7e, 0x0b, 0x2f, 0x32, 0x14, 0xef, 0x7e, 0x40, 0xf1, 0xee, 0x35, 0x9e, 0xe7, 0x01, 0xa2, 0xc6, 0xe7, 0x07, 0x04, - 0x41, 0x5d, 0x63, 0x91, 0x4f, 0x5a, 0xbf, 0xf9, 0x32, 0xcc, 0x82, 0x85, 0x97, 0x64, 0x07, 0xd0, 0xd4, 0x02, 0x24, - 0xa7, 0x6f, 0xf2, 0x60, 0x26, 0xc5, 0xa1, 0x10, 0xaa, 0x65, 0x91, 0xd0, 0x1c, 0x4e, 0x82, 0x50, 0x2a, 0x0e, 0xc5, - 0x07, 0x3c, 0xdf, 0x67, 0x8b, 0x6c, 0xa0, 0x7b, 0x0b, 0xc8, 0x7b, 0x80, 0x91, 0x8c, 0x0f, 0x62, 0x3f, 0x63, 0x99, - 0x95, 0x66, 0x09, 0xf3, 0xe6, 0xba, 0x0c, 0xeb, 0x59, 0xef, 0x2f, 0x5d, 0x8e, 0xe6, 0x41, 0x26, 0x23, 0xe3, 0xd1, - 0x04, 0x41, 0x85, 0x07, 0x43, 0x3c, 0x1b, 0xe6, 0x1c, 0x84, 0x97, 0xf1, 0xb4, 0xb2, 0xa3, 0x0a, 0xce, 0xe5, 0x1c, - 0xa3, 0xae, 0xf2, 0x58, 0xf7, 0x63, 0xf4, 0xc8, 0xb9, 0xe5, 0x5e, 0xd7, 0x32, 0x80, 0x9f, 0x7e, 0x76, 0xca, 0xaf, - 0xb7, 0x1a, 0x06, 0x0a, 0xd0, 0xbb, 0x0e, 0xc4, 0x95, 0xdd, 0xe4, 0x8f, 0x7d, 0xc0, 0x2b, 0x03, 0x69, 0xa2, 0x9e, - 0x31, 0xc2, 0x37, 0x8d, 0xe5, 0x0a, 0x18, 0xa1, 0x92, 0x8a, 0x77, 0xe6, 0x9e, 0x49, 0x07, 0x20, 0x1c, 0x15, 0xf2, - 0x4a, 0xbf, 0xfd, 0xf6, 0x7a, 0xf8, 0x9f, 0xdf, 0x21, 0x0c, 0xf9, 0xcc, 0x15, 0x5e, 0xd0, 0xd7, 0x6a, 0x2d, 0xce, - 0x7d, 0x9a, 0x43, 0x54, 0xef, 0xb3, 0xb1, 0x08, 0x0b, 0x22, 0xb6, 0x56, 0x3e, 0xbc, 0x11, 0xa1, 0x9e, 0x20, 0xd5, - 0x80, 0x21, 0x7c, 0xb5, 0x87, 0xb0, 0xbc, 0x43, 0x11, 0x22, 0x40, 0xfb, 0x65, 0xf5, 0xed, 0x31, 0xa4, 0xcd, 0xad, - 0x65, 0x00, 0x50, 0x06, 0x88, 0x7b, 0xe8, 0xec, 0xd4, 0xe3, 0xc2, 0x57, 0x60, 0x3f, 0xd2, 0xde, 0x01, 0x4c, 0x73, - 0x16, 0xcf, 0x99, 0x1d, 0xc4, 0x07, 0xf7, 0x6c, 0x64, 0x79, 0x8b, 0x80, 0xe4, 0xcb, 0x28, 0x77, 0xd3, 0x88, 0xf3, - 0x93, 0x0a, 0x5a, 0xe2, 0xaf, 0xf3, 0x02, 0x94, 0x71, 0x01, 0x28, 0xf8, 0xe9, 0x9d, 0x95, 0xa3, 0xf5, 0xd9, 0x22, - 0x36, 0x7c, 0x19, 0xcb, 0x9f, 0x53, 0xd0, 0x3d, 0x11, 0x5f, 0xaf, 0x78, 0xb0, 0xe2, 0xc9, 0x44, 0x8d, 0xb0, 0x67, - 0x97, 0xbf, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0x41, 0x5f, 0xaa, 0x7f, 0x42, 0xfe, 0x84, 0xf4, 0xb5, 0x3c, 0x18, - 0x23, 0x9c, 0xe7, 0x5a, 0xa4, 0x3e, 0x09, 0x92, 0xa7, 0x54, 0x89, 0x23, 0x8a, 0x6a, 0x0c, 0xe8, 0x0d, 0xac, 0xc9, - 0x93, 0xc1, 0x80, 0xf0, 0x58, 0x15, 0x9d, 0x01, 0x94, 0x1a, 0xe2, 0xe4, 0xc3, 0x64, 0x33, 0x68, 0x68, 0x91, 0x07, - 0x17, 0x36, 0xaa, 0x4e, 0xa7, 0x3e, 0xc6, 0x03, 0x4f, 0xec, 0xaf, 0xd2, 0x0e, 0x84, 0x9d, 0xc5, 0x17, 0x16, 0x10, - 0xb8, 0xe8, 0xa7, 0x82, 0xc7, 0xb5, 0xaf, 0x09, 0x65, 0x5b, 0xa1, 0xf7, 0x10, 0x2b, 0x9a, 0x75, 0xee, 0x64, 0x7f, - 0x89, 0xa5, 0x57, 0xc2, 0xb9, 0xad, 0x76, 0x92, 0x64, 0xac, 0xf1, 0xfa, 0x69, 0x52, 0x83, 0x83, 0xef, 0x3a, 0x4c, - 0x6a, 0xdd, 0xf2, 0x64, 0x10, 0x3b, 0xe6, 0xc5, 0x41, 0x2b, 0xbd, 0xc4, 0x73, 0x9f, 0x9f, 0x1e, 0xc0, 0xfc, 0x20, - 0x30, 0x40, 0x89, 0x33, 0x0a, 0x0c, 0x88, 0x3e, 0xe0, 0xa5, 0x64, 0x1d, 0x70, 0x31, 0x16, 0x4c, 0x1d, 0xde, 0x1c, - 0x65, 0x28, 0xd0, 0x52, 0x95, 0x3a, 0xb3, 0xe2, 0x34, 0x73, 0x79, 0xbb, 0x63, 0xf3, 0xff, 0xba, 0xc4, 0xc0, 0xfc, - 0x79, 0x3f, 0x63, 0xc2, 0xef, 0xf6, 0x32, 0xdb, 0xe0, 0x9a, 0xbb, 0xa9, 0x0a, 0x31, 0xac, 0x5b, 0x2a, 0x14, 0xfb, - 0x78, 0x5b, 0xad, 0x82, 0x35, 0x92, 0xd5, 0x16, 0x5e, 0x4b, 0x7f, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, - 0x65, 0x36, 0x80, 0xaa, 0x42, 0xd8, 0xee, 0x2d, 0x16, 0x54, 0xd9, 0xe8, 0x9f, 0x1e, 0xd0, 0xbd, 0xf3, 0x8c, 0x76, - 0xd8, 0xd9, 0x29, 0x58, 0x17, 0xd2, 0xa2, 0x7b, 0x8b, 0x05, 0x5f, 0x52, 0xfa, 0x45, 0x6f, 0x0e, 0x66, 0xd9, 0x3c, - 0x3c, 0xfb, 0x2f, 0x85, 0x07, 0xd6, 0xc5, 0xa2, 0x59, 0x03, 0x00}; + 0xe4, 0xe5, 0x65, 0xce, 0xc3, 0xc0, 0xc4, 0xf8, 0x08, 0xa8, 0xad, 0x66, 0xf6, 0x7f, 0x9a, 0x7b, 0xfa, 0xe5, 0xb6, + 0x6d, 0xe4, 0xff, 0xbf, 0xa7, 0x60, 0x98, 0x5c, 0x2a, 0x26, 0x24, 0x4d, 0x4a, 0x96, 0xed, 0x48, 0x96, 0xdd, 0x36, + 0x49, 0xe7, 0xdc, 0x71, 0x9b, 0x4e, 0xe2, 0xcb, 0xdc, 0xd5, 0xf5, 0x58, 0x14, 0x05, 0x49, 0xbc, 0x50, 0xa4, 0x86, + 0xa4, 0x6c, 0xb9, 0x2a, 0xef, 0x59, 0xfa, 0x2c, 0xf7, 0x64, 0xbf, 0xd9, 0x5d, 0x00, 0x04, 0x3f, 0xf4, 0xe1, 0x26, + 0xbd, 0xfb, 0x4d, 0xcf, 0x17, 0x11, 0x04, 0x40, 0x60, 0x01, 0x2c, 0xf6, 0x7b, 0x9f, 0x38, 0x22, 0xb0, 0xa6, 0x91, + 0x6f, 0x3a, 0x5a, 0x62, 0xc6, 0x4c, 0x46, 0x9e, 0x23, 0x02, 0x13, 0x45, 0xa8, 0x77, 0xa8, 0x85, 0xe0, 0xeb, 0x52, + 0x1c, 0x5d, 0x6b, 0x1c, 0x2f, 0x47, 0x21, 0xb3, 0x70, 0xbb, 0xc3, 0x27, 0xd7, 0xa3, 0xe5, 0x68, 0x04, 0xc9, 0x54, + 0x9e, 0x38, 0x26, 0x84, 0x87, 0x89, 0x53, 0x64, 0xdb, 0x72, 0xa3, 0x0f, 0x93, 0xb2, 0xb3, 0xea, 0xf0, 0xc1, 0xa4, + 0x03, 0x24, 0x32, 0xf4, 0x81, 0x0c, 0x58, 0xb4, 0x86, 0x53, 0x3b, 0xd0, 0x3f, 0xc0, 0xee, 0x4b, 0xf5, 0x7e, 0xd3, + 0xd1, 0x1f, 0x5c, 0xeb, 0x1f, 0x10, 0xc6, 0x98, 0x64, 0xf8, 0x35, 0xed, 0x5e, 0xdd, 0xd4, 0x49, 0x37, 0xbd, 0xc4, + 0x74, 0x03, 0x20, 0x9b, 0x7d, 0x13, 0x78, 0xd3, 0x28, 0x4e, 0xb3, 0xc0, 0xd7, 0x6f, 0xfa, 0x17, 0x41, 0xeb, 0x7a, + 0x9e, 0xb5, 0x8c, 0x1b, 0xd3, 0xcf, 0xd4, 0x4c, 0x25, 0x02, 0x61, 0x62, 0xa2, 0x92, 0x4d, 0x95, 0xd4, 0x13, 0xb4, + 0xb5, 0xa2, 0x40, 0xcd, 0x58, 0xc9, 0xcf, 0x06, 0x50, 0xaf, 0x92, 0xf6, 0x04, 0xf3, 0x37, 0xe9, 0xd8, 0xd2, 0xe8, + 0x13, 0x43, 0xf1, 0x7a, 0xb9, 0xc6, 0xab, 0x3c, 0x2b, 0x6e, 0x4b, 0x0c, 0xd5, 0x2b, 0xfc, 0x5b, 0xe8, 0xf9, 0x89, + 0x6a, 0x9b, 0x59, 0xba, 0x77, 0x87, 0xdf, 0x94, 0xe9, 0x02, 0xb8, 0xbf, 0xc1, 0x30, 0x22, 0x8a, 0x33, 0x0d, 0xe2, + 0xcf, 0xc0, 0x17, 0x87, 0x55, 0x5b, 0x2e, 0xde, 0x6b, 0xcb, 0xc8, 0x39, 0x32, 0xf8, 0x16, 0x2f, 0xbf, 0x16, 0x8f, + 0x42, 0x56, 0x0a, 0x34, 0x41, 0x34, 0x7d, 0x04, 0x0b, 0x98, 0xc5, 0x97, 0xf1, 0x7d, 0x55, 0x5d, 0xf1, 0x7a, 0xb8, + 0xfb, 0xee, 0xc5, 0x0b, 0x10, 0xf6, 0x9b, 0x48, 0xbe, 0xd7, 0xe2, 0xf9, 0x43, 0x05, 0xa1, 0x53, 0x39, 0x53, 0x68, + 0x9f, 0x21, 0x68, 0x98, 0x0c, 0xcc, 0xb9, 0xf0, 0x2e, 0x00, 0x94, 0xc4, 0xaf, 0xe9, 0x61, 0x7e, 0x2b, 0x32, 0x1c, + 0x8b, 0xfc, 0xc2, 0xca, 0xe5, 0x0c, 0xd8, 0x35, 0x5a, 0x2c, 0x33, 0x8c, 0x88, 0x0b, 0x03, 0x60, 0xb9, 0xae, 0x61, + 0x84, 0x4d, 0xc0, 0xd2, 0x05, 0x99, 0x98, 0xeb, 0x5a, 0x30, 0xae, 0x97, 0x71, 0xa2, 0x17, 0x90, 0x17, 0xe2, 0x77, + 0x94, 0x27, 0xc1, 0x63, 0xc2, 0xa7, 0xe1, 0x9b, 0x45, 0x38, 0xf9, 0x96, 0x8f, 0x7a, 0x97, 0x06, 0xcc, 0xe0, 0x53, + 0x3f, 0xfd, 0x56, 0xd8, 0x38, 0x59, 0x88, 0x92, 0x59, 0x9a, 0xe6, 0xf0, 0xd9, 0x3a, 0xca, 0xcf, 0x9f, 0xad, 0xd3, + 0x7c, 0xf0, 0x6c, 0xed, 0x01, 0x25, 0x97, 0xeb, 0x30, 0xd1, 0xc2, 0x9f, 0xa6, 0x98, 0x1e, 0x6c, 0x2a, 0x2a, 0xd7, + 0x50, 0xa1, 0x3e, 0xe0, 0x6a, 0xf3, 0x45, 0x12, 0xcc, 0xbd, 0xe4, 0x81, 0xb4, 0xec, 0xa6, 0xaa, 0x8a, 0x37, 0x74, + 0x8d, 0xf0, 0x3a, 0xcd, 0x97, 0x50, 0xbc, 0xae, 0x7d, 0x2d, 0xcb, 0x18, 0x9f, 0x9c, 0x54, 0x35, 0xc2, 0xb7, 0x6e, + 0xf5, 0x97, 0xcc, 0x1e, 0xb3, 0xcc, 0x0b, 0x42, 0x6a, 0xd2, 0x17, 0x39, 0xe4, 0x6b, 0xb3, 0x49, 0xcb, 0xb3, 0x89, + 0xca, 0xdb, 0x05, 0x27, 0x43, 0x18, 0x9f, 0xc6, 0x8d, 0x33, 0xc3, 0xdc, 0x52, 0xcd, 0x0b, 0x48, 0xef, 0xfe, 0xab, + 0xd0, 0x67, 0x00, 0xfd, 0x08, 0xa0, 0xcf, 0x22, 0x3f, 0x1e, 0xb3, 0xbf, 0xbf, 0xbf, 0x90, 0xc9, 0xac, 0x40, 0x2e, + 0x33, 0xe4, 0xfb, 0x30, 0x45, 0x72, 0x21, 0x41, 0x52, 0x81, 0xd2, 0x4e, 0x69, 0x72, 0xc7, 0x24, 0xb9, 0xae, 0x9d, + 0xd3, 0xd8, 0xd9, 0x98, 0x46, 0x3d, 0x88, 0xb1, 0x55, 0x92, 0x9f, 0x1e, 0x50, 0x6d, 0xba, 0xdc, 0xa8, 0x12, 0x80, + 0x21, 0x81, 0x19, 0x16, 0x50, 0x80, 0xbc, 0x9b, 0x03, 0xb7, 0xe0, 0x1f, 0xec, 0x39, 0x4a, 0xbf, 0xdd, 0xf3, 0x32, + 0x65, 0x82, 0xad, 0xf4, 0xb3, 0x53, 0xcc, 0xa4, 0x05, 0xd7, 0x33, 0xc4, 0xde, 0x38, 0x3d, 0xa0, 0x47, 0xad, 0x72, + 0x00, 0x8a, 0x4e, 0x04, 0x27, 0xd7, 0xe3, 0x1d, 0x3c, 0xea, 0x64, 0x40, 0xe2, 0x76, 0x28, 0xf5, 0x72, 0x5d, 0x9b, + 0x73, 0x4a, 0x88, 0x07, 0xf9, 0x81, 0x08, 0x00, 0x0e, 0x1c, 0x55, 0x5d, 0x9b, 0x7b, 0x2b, 0x9c, 0xb9, 0x78, 0xe3, + 0xad, 0x5a, 0x2e, 0x7f, 0x55, 0x1c, 0xad, 0xb4, 0x7c, 0xb4, 0x7c, 0xbe, 0xb8, 0x60, 0xde, 0x2f, 0xa4, 0xb6, 0xad, + 0x19, 0xaa, 0x4d, 0x1b, 0x16, 0x77, 0x26, 0x16, 0x77, 0xbc, 0x61, 0x71, 0xc7, 0x5b, 0x16, 0x37, 0xe4, 0x0b, 0xa9, + 0x49, 0xd0, 0x25, 0xe8, 0xb2, 0x25, 0x81, 0xc7, 0xe9, 0x8a, 0x1e, 0x3f, 0x67, 0x08, 0x27, 0x2b, 0x0d, 0xc1, 0x64, + 0x69, 0x03, 0xac, 0x9a, 0xe0, 0xa2, 0x00, 0xa2, 0x3e, 0x71, 0x79, 0xea, 0xc4, 0xbc, 0x21, 0x33, 0x66, 0x2b, 0xac, + 0xce, 0x17, 0x76, 0x29, 0x65, 0xfd, 0x6e, 0xcd, 0x36, 0xcc, 0x74, 0xb6, 0x65, 0xa6, 0x7e, 0xe9, 0xe8, 0xf2, 0x69, + 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0xcc, 0x38, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x94, 0xaa, 0xec, 0xa8, + 0x85, 0x97, 0xa6, 0xf7, 0x71, 0x02, 0x7a, 0x10, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x1e, 0x44, 0x3c, 0xc4, 0xca, 0xc6, + 0xcd, 0x54, 0xbc, 0x57, 0xb7, 0x54, 0xbb, 0xdb, 0xa5, 0x1a, 0x0b, 0x2f, 0xcb, 0x58, 0x82, 0x40, 0xf7, 0x20, 0x16, + 0x77, 0xae, 0x6b, 0xff, 0x0f, 0x76, 0x59, 0x03, 0x0a, 0x09, 0x8d, 0x02, 0xa9, 0x23, 0x82, 0x5e, 0x00, 0x25, 0x95, + 0x88, 0x6b, 0x57, 0x89, 0xd6, 0x96, 0x48, 0xb8, 0xff, 0x88, 0xa7, 0xb5, 0x95, 0x28, 0xfe, 0x44, 0xee, 0x91, 0x61, + 0x2f, 0xbc, 0xf1, 0x07, 0xd0, 0xb6, 0xb5, 0xda, 0x26, 0x58, 0xce, 0xaa, 0xb1, 0xd9, 0x12, 0x22, 0xed, 0xfc, 0x02, + 0x47, 0x22, 0x92, 0xe4, 0x76, 0x49, 0xe0, 0xd2, 0xe8, 0x59, 0x93, 0x9b, 0x75, 0x3b, 0x3f, 0x98, 0x06, 0x46, 0x0d, + 0x69, 0x02, 0x66, 0x0b, 0x07, 0x67, 0x92, 0xc3, 0x0a, 0x4d, 0xf7, 0xc8, 0x00, 0x71, 0xec, 0x35, 0x24, 0x19, 0x75, + 0x04, 0xfb, 0x3a, 0x4c, 0xe0, 0x8e, 0xba, 0x76, 0x6e, 0xf2, 0xe7, 0x53, 0xfc, 0xe5, 0xde, 0xe4, 0xcf, 0x47, 0xf8, + 0xab, 0x7d, 0x83, 0xe9, 0xe4, 0x1a, 0xd8, 0x76, 0x65, 0xce, 0xfa, 0x59, 0x69, 0x3b, 0x91, 0x51, 0xd8, 0x23, 0x76, + 0x0d, 0x5f, 0xe0, 0xa7, 0xcf, 0xd6, 0x29, 0xb8, 0x41, 0xaa, 0x73, 0x88, 0xec, 0xc4, 0xc8, 0x1b, 0xcb, 0xa7, 0x1b, + 0xca, 0x47, 0xc6, 0x7f, 0xf9, 0x9a, 0xc7, 0x5d, 0x12, 0x17, 0x57, 0x4a, 0x59, 0xe8, 0x70, 0x3b, 0x0a, 0x22, 0x2f, + 0x79, 0xb8, 0x25, 0x66, 0xa2, 0x25, 0x28, 0x75, 0x29, 0x4c, 0x21, 0x62, 0xb2, 0xac, 0x83, 0xca, 0x14, 0xa9, 0xeb, + 0x03, 0xbf, 0xe7, 0x07, 0xff, 0x48, 0x14, 0x22, 0xad, 0xc4, 0x6e, 0xf2, 0x05, 0x29, 0x7d, 0xe8, 0xf6, 0xd9, 0xba, + 0xc5, 0xea, 0xdd, 0x54, 0x66, 0x5b, 0xa1, 0x02, 0x61, 0x79, 0x90, 0x75, 0x9d, 0x8f, 0x83, 0x1e, 0x2a, 0x99, 0x46, + 0xf1, 0xca, 0x7a, 0xb6, 0xce, 0xce, 0xf5, 0xb9, 0x97, 0x7c, 0x62, 0x63, 0xcb, 0x0f, 0x12, 0x3f, 0x64, 0x7a, 0x4f, + 0x1f, 0x85, 0x5e, 0xf4, 0x89, 0x3f, 0x5a, 0xf1, 0x32, 0x43, 0xb5, 0xf1, 0x4e, 0x4e, 0x57, 0xc0, 0x84, 0x04, 0x74, + 0x48, 0x9a, 0x36, 0x40, 0x41, 0x7b, 0x2d, 0xc5, 0x5b, 0x05, 0x59, 0x58, 0xd4, 0x32, 0xc1, 0xea, 0x11, 0x34, 0xd9, + 0xe0, 0x46, 0x6a, 0xea, 0xb8, 0x5e, 0xba, 0xa9, 0x4e, 0x95, 0x44, 0x93, 0x32, 0x0f, 0xe2, 0x2d, 0xf6, 0xf0, 0xc7, + 0x3f, 0x47, 0x19, 0xaa, 0xf7, 0xff, 0x1c, 0x27, 0xf1, 0x36, 0x7f, 0x50, 0x6d, 0xec, 0xa5, 0xe9, 0x72, 0xce, 0xc6, + 0xa4, 0x31, 0x3b, 0x2f, 0x86, 0x52, 0x26, 0xe5, 0xd5, 0xe1, 0xfc, 0xb2, 0x6c, 0x1f, 0x1f, 0xbe, 0x06, 0x4d, 0x3e, + 0x90, 0x74, 0xf1, 0x64, 0xa2, 0x17, 0x4c, 0xf5, 0x8e, 0x66, 0xee, 0xe1, 0x2f, 0xcb, 0xef, 0xde, 0x3a, 0xdf, 0xc9, + 0xc6, 0x91, 0x6e, 0xe4, 0x43, 0xa1, 0x96, 0xe4, 0x94, 0xa9, 0x32, 0x5e, 0x31, 0xa3, 0x89, 0x17, 0x6d, 0x9e, 0xce, + 0x75, 0x69, 0x97, 0x2d, 0x18, 0x1b, 0x83, 0xc5, 0xaa, 0x59, 0x2b, 0xbd, 0x0d, 0xd9, 0x1d, 0x93, 0x2a, 0xcf, 0xfa, + 0xc7, 0x1a, 0x5a, 0x60, 0x4c, 0x36, 0xae, 0x4a, 0xe5, 0x74, 0x95, 0x32, 0xa5, 0x21, 0xce, 0x81, 0xcf, 0x5c, 0xdd, + 0xe5, 0x95, 0x5d, 0x3d, 0x34, 0x75, 0x65, 0x00, 0x1b, 0x47, 0x76, 0xbe, 0xa1, 0xbc, 0x87, 0x09, 0x99, 0x9b, 0xc7, + 0x66, 0xba, 0x46, 0x0f, 0x62, 0x58, 0x73, 0x38, 0x85, 0xb0, 0xf9, 0x5b, 0x85, 0xfc, 0x61, 0x13, 0xc4, 0x9a, 0xa4, + 0x52, 0x3a, 0x89, 0x3b, 0x84, 0x15, 0x20, 0x9a, 0xc3, 0x0a, 0xc1, 0x4f, 0xe3, 0xda, 0x68, 0xe5, 0x99, 0x8f, 0x30, + 0xd1, 0x69, 0xc4, 0xd2, 0x74, 0x23, 0xc0, 0xe4, 0xa2, 0x9b, 0x7a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0x74, 0x4c, + 0xb8, 0x94, 0x71, 0x82, 0xd5, 0x6f, 0x21, 0x86, 0xbf, 0x9d, 0x73, 0x3b, 0x8e, 0x64, 0x3a, 0xd2, 0xb9, 0x8e, 0x7d, + 0xd3, 0xfb, 0x7b, 0x9d, 0x0f, 0xaa, 0x74, 0x53, 0x36, 0x0e, 0xad, 0x55, 0xc2, 0x7e, 0x35, 0xf9, 0x0c, 0x76, 0x20, + 0xc6, 0x54, 0x41, 0x71, 0x6c, 0x32, 0x61, 0x7e, 0x96, 0x1a, 0x42, 0x5a, 0x23, 0xa3, 0xaa, 0x82, 0x37, 0xcd, 0x93, + 0x81, 0xfe, 0x23, 0xf8, 0x96, 0x8b, 0xe0, 0x43, 0x7c, 0x40, 0x82, 0x6b, 0x69, 0x06, 0x13, 0xf5, 0x58, 0x06, 0x11, + 0xff, 0x0a, 0x24, 0xcd, 0x6e, 0x28, 0xc7, 0xa1, 0xf1, 0x2b, 0xa0, 0xd8, 0x17, 0xb1, 0xb4, 0xf6, 0xd8, 0x8e, 0x80, + 0xb6, 0x1d, 0xdf, 0xb5, 0xfb, 0x5d, 0xd7, 0x75, 0x72, 0xdd, 0x04, 0x9f, 0xa6, 0x4f, 0xfb, 0x1e, 0x7a, 0x6c, 0xd5, + 0x81, 0x56, 0xcb, 0xe8, 0x31, 0xed, 0xda, 0xee, 0x2b, 0x57, 0x37, 0xc9, 0x94, 0x4c, 0xc1, 0x6d, 0x7e, 0x7c, 0xc7, + 0x92, 0xcf, 0x9e, 0x4a, 0xb9, 0xf3, 0xfd, 0xc6, 0x73, 0xe4, 0x3a, 0x80, 0x84, 0xb3, 0x78, 0xf1, 0x88, 0x29, 0x74, + 0x74, 0x53, 0xf7, 0xc3, 0x38, 0x65, 0xea, 0x1c, 0x48, 0xea, 0xf0, 0x99, 0x93, 0xf8, 0xe9, 0xfd, 0xdb, 0x0f, 0x1f, + 0x74, 0x13, 0x33, 0x64, 0xa6, 0x6a, 0xef, 0x7c, 0x43, 0xed, 0xc0, 0xfe, 0x8d, 0xfb, 0x8e, 0x6e, 0x18, 0x62, 0x2b, + 0xcb, 0x7b, 0x8e, 0xca, 0x6a, 0x5b, 0x8e, 0xdf, 0x3c, 0xfc, 0xcb, 0xc4, 0x0b, 0xee, 0x35, 0xaf, 0x06, 0xdc, 0xb0, + 0xfd, 0x7a, 0x2b, 0x95, 0xcc, 0x83, 0xe8, 0xb6, 0xa1, 0xd4, 0x5b, 0x35, 0x94, 0x02, 0x33, 0x55, 0xc3, 0x55, 0xcb, + 0x78, 0xae, 0xdc, 0xce, 0x90, 0xe0, 0x78, 0x17, 0xb8, 0x14, 0x8e, 0xe6, 0x33, 0x06, 0xcd, 0x23, 0x9c, 0x57, 0x47, + 0xdd, 0x50, 0xcc, 0xd9, 0x10, 0x09, 0x5b, 0x3f, 0x04, 0x43, 0x38, 0xa6, 0xaa, 0xc1, 0xca, 0x94, 0x9b, 0x34, 0x63, + 0x55, 0x3a, 0x21, 0x0a, 0xf3, 0x36, 0x63, 0xf3, 0x05, 0x4b, 0xbc, 0x6c, 0x99, 0xb0, 0xdb, 0x30, 0xbe, 0x7f, 0x52, + 0x98, 0x99, 0xef, 0xa8, 0x3c, 0x0b, 0xa6, 0x33, 0x59, 0xfb, 0xbc, 0xc5, 0x06, 0x72, 0x01, 0xb7, 0x7e, 0x20, 0xff, + 0xcf, 0xef, 0xb6, 0xfd, 0x9f, 0xdf, 0x77, 0x56, 0x85, 0xee, 0xf3, 0xa1, 0x99, 0x0d, 0xf6, 0xd8, 0x17, 0xcd, 0x5f, + 0x2a, 0xc3, 0xbc, 0xb9, 0x4e, 0x6d, 0x11, 0xe0, 0x7d, 0x6d, 0x09, 0x6a, 0x85, 0xe5, 0x7d, 0xf3, 0xa8, 0x81, 0xc1, + 0xbc, 0x76, 0x8e, 0x0c, 0x2a, 0x7d, 0xd6, 0xd0, 0x86, 0x46, 0x6f, 0xaf, 0x15, 0xf9, 0xe3, 0x10, 0xde, 0x35, 0x87, + 0xcf, 0x1c, 0x3e, 0x97, 0x0c, 0xbe, 0x1e, 0x0e, 0x65, 0xce, 0x35, 0xb5, 0x29, 0x98, 0xbe, 0x9f, 0xd7, 0x4a, 0xf8, + 0xe5, 0xd9, 0x73, 0x0c, 0xf2, 0x49, 0x1f, 0xbc, 0x1e, 0xa2, 0x91, 0xd6, 0xe9, 0x28, 0x29, 0x88, 0x95, 0x8d, 0xa8, + 0x8d, 0x8c, 0xac, 0x6b, 0x9d, 0xd6, 0xf0, 0x1a, 0x94, 0x62, 0x22, 0xae, 0x7c, 0x68, 0x98, 0xaf, 0x87, 0x5c, 0xb4, + 0xc3, 0xed, 0x42, 0x7b, 0xd5, 0xad, 0xcd, 0x05, 0xa3, 0x25, 0xa0, 0x9b, 0x1a, 0x29, 0x5c, 0xb0, 0x32, 0x2b, 0x24, + 0x69, 0x28, 0x51, 0x07, 0xa6, 0x7e, 0x98, 0x63, 0x1e, 0x90, 0x77, 0x9b, 0x6c, 0xa7, 0x7e, 0xda, 0x6d, 0x3b, 0x75, + 0xb5, 0x97, 0xed, 0xd4, 0x4f, 0x5f, 0xdc, 0x76, 0xea, 0x9d, 0x6a, 0x3b, 0x05, 0x8b, 0xf8, 0x96, 0xed, 0x65, 0xd0, + 0x24, 0xcc, 0x24, 0xe2, 0xfb, 0x74, 0xe0, 0x72, 0x92, 0x36, 0xf5, 0x67, 0x0c, 0xd8, 0x74, 0xbe, 0x2a, 0x61, 0x3c, + 0x05, 0xe3, 0xa6, 0x3f, 0xdf, 0x0c, 0x29, 0x8c, 0xa7, 0xaa, 0x11, 0x52, 0xc4, 0x23, 0xa1, 0x16, 0xd1, 0x8d, 0xc8, + 0xf0, 0xc7, 0x31, 0x45, 0x2c, 0x24, 0xeb, 0xd0, 0x50, 0xb2, 0x3d, 0x4b, 0xab, 0xae, 0xb6, 0x30, 0x0d, 0xea, 0xa1, + 0x55, 0x91, 0x6c, 0xd8, 0x7e, 0x29, 0x62, 0x3e, 0xa8, 0x3d, 0x48, 0xeb, 0x59, 0x8a, 0x9f, 0xb0, 0xd6, 0x7f, 0x59, + 0xb9, 0xdf, 0x5e, 0xbb, 0xfd, 0x8e, 0x0b, 0x4e, 0xcb, 0xc0, 0xe4, 0x61, 0x81, 0xd3, 0xef, 0x74, 0xa0, 0xe0, 0x5e, + 0x29, 0x68, 0x43, 0x41, 0xa0, 0x14, 0x74, 0xa1, 0xc0, 0x57, 0x0a, 0x8e, 0xa0, 0x60, 0xac, 0x14, 0x1c, 0x43, 0xc1, + 0x9d, 0x9e, 0x5f, 0x47, 0x72, 0xb8, 0xc7, 0xc6, 0x8d, 0x49, 0x4c, 0x85, 0x28, 0x3b, 0x36, 0x5d, 0xb0, 0x26, 0xf2, + 0xa6, 0xbd, 0xd8, 0x24, 0xf9, 0x5e, 0x2f, 0x31, 0xef, 0x67, 0x8c, 0x02, 0x28, 0xbf, 0xc1, 0x3b, 0xc7, 0xce, 0x62, + 0xb0, 0x27, 0x16, 0x81, 0x09, 0x04, 0x1c, 0x34, 0xdd, 0x00, 0x99, 0x4d, 0x5f, 0xae, 0x9c, 0x08, 0xee, 0xa0, 0xac, + 0x65, 0xf1, 0x8e, 0x3e, 0x67, 0xc9, 0x2d, 0x50, 0x98, 0x78, 0xb4, 0x54, 0xb9, 0xe0, 0x97, 0x50, 0xf4, 0xbf, 0x61, + 0xa3, 0xe5, 0x54, 0xbb, 0x8c, 0xa7, 0x3b, 0x75, 0xf6, 0xea, 0x2b, 0x18, 0xa5, 0x4e, 0x0a, 0x10, 0x4b, 0x6c, 0x4b, + 0xfe, 0x2d, 0x7a, 0xcc, 0xcb, 0xf5, 0x33, 0x18, 0x9b, 0x96, 0x91, 0xc5, 0x08, 0x7c, 0x07, 0x60, 0xa4, 0x28, 0xcd, + 0x2f, 0x01, 0xce, 0xca, 0xf3, 0x95, 0xa7, 0x8c, 0xe7, 0xec, 0x07, 0x96, 0xa6, 0xde, 0x54, 0xd4, 0xaf, 0x8f, 0x13, + 0xac, 0x64, 0x24, 0xff, 0x85, 0x00, 0x04, 0x61, 0x5a, 0x50, 0x33, 0x86, 0x48, 0xe2, 0x7b, 0x0d, 0xcc, 0x6d, 0x60, + 0x43, 0x15, 0x86, 0x01, 0x81, 0x0d, 0x4b, 0x58, 0x56, 0xe1, 0xc3, 0xe1, 0xbf, 0x63, 0x61, 0xb5, 0x30, 0xf3, 0xa6, + 0xd5, 0x22, 0xda, 0x07, 0xb9, 0x3a, 0x36, 0xa9, 0x41, 0x2f, 0x15, 0x7e, 0x8e, 0x4a, 0x38, 0x8c, 0xa7, 0x7f, 0xaa, + 0x3e, 0x78, 0x8b, 0x1e, 0xff, 0x43, 0x64, 0x06, 0xd9, 0xd0, 0x46, 0x18, 0x6b, 0x36, 0x80, 0xb0, 0x17, 0x65, 0x33, + 0x0b, 0x5d, 0xae, 0x5a, 0xed, 0xc8, 0x30, 0x6d, 0x5c, 0xdb, 0x75, 0xd5, 0xd1, 0xb4, 0x97, 0x4c, 0x47, 0x5e, 0xcb, + 0x6d, 0x1f, 0x9b, 0xe2, 0xcf, 0x76, 0xba, 0x46, 0x8e, 0x3d, 0x68, 0xe3, 0xe0, 0x6e, 0x3d, 0x89, 0xa3, 0xcc, 0x9a, + 0x78, 0xf3, 0x20, 0x7c, 0xe8, 0xcd, 0xe3, 0x28, 0x4e, 0x17, 0x9e, 0xcf, 0xfa, 0x05, 0x43, 0xdd, 0xc7, 0x10, 0x06, + 0xdc, 0x8b, 0xce, 0xb5, 0xdb, 0x09, 0x9b, 0x53, 0x6b, 0x19, 0xa1, 0x60, 0x12, 0xb2, 0x55, 0xce, 0x3f, 0x5f, 0xaa, + 0x4c, 0x55, 0x71, 0xcb, 0x51, 0x0b, 0xa0, 0x48, 0x79, 0xf8, 0x03, 0x08, 0xfa, 0xd3, 0x5f, 0x78, 0x63, 0x8c, 0xd8, + 0x67, 0xb7, 0xbb, 0x09, 0x9b, 0x6b, 0x76, 0x77, 0x63, 0xe7, 0x49, 0x7c, 0x7f, 0x06, 0xa3, 0xc5, 0xc6, 0x56, 0xca, + 0xc2, 0x09, 0xbe, 0xb1, 0xd0, 0xe3, 0x42, 0xf4, 0x63, 0x21, 0x23, 0x0e, 0xbd, 0xb1, 0x79, 0x1f, 0x5e, 0xf7, 0xda, + 0x9a, 0xd3, 0x9f, 0x07, 0x91, 0x45, 0xd3, 0x39, 0x76, 0x16, 0x4a, 0x5f, 0x2a, 0xfc, 0x8c, 0x35, 0x56, 0x77, 0x35, + 0xa7, 0x0f, 0xcc, 0xda, 0x24, 0x8c, 0xef, 0x7b, 0xb3, 0x60, 0x3c, 0x66, 0x51, 0x1f, 0xc7, 0x2c, 0x0b, 0x59, 0x18, + 0x06, 0x8b, 0x34, 0x48, 0xfb, 0x73, 0x6f, 0xc5, 0x7b, 0x3d, 0xdc, 0xd4, 0x6b, 0x87, 0xf7, 0xda, 0xd9, 0xbb, 0x57, + 0xa5, 0x1b, 0xf0, 0xee, 0xa0, 0x7e, 0xf8, 0xd0, 0xba, 0x9a, 0x53, 0x99, 0xe7, 0xde, 0xbd, 0x2e, 0x12, 0xb6, 0x9e, + 0x7b, 0xc9, 0x34, 0x88, 0x7a, 0x4e, 0x6e, 0xdf, 0xad, 0x69, 0x63, 0x3c, 0x3d, 0x39, 0x39, 0xc9, 0xed, 0xb1, 0x78, + 0x72, 0xc6, 0xe3, 0xdc, 0xf6, 0xc5, 0xd3, 0x64, 0xe2, 0x38, 0x93, 0x49, 0x6e, 0x07, 0xa2, 0xa0, 0xd3, 0xf6, 0xc7, + 0x9d, 0x76, 0x6e, 0xdf, 0x2b, 0x35, 0x72, 0x9b, 0xf1, 0xa7, 0x84, 0x8d, 0xfb, 0xb8, 0x91, 0xee, 0x69, 0xe9, 0x8f, + 0x1d, 0x27, 0x47, 0x0c, 0x70, 0x5d, 0xc2, 0x4d, 0x28, 0xeb, 0xb9, 0x59, 0xef, 0x5d, 0x53, 0x2b, 0x3e, 0xe7, 0xfb, + 0x8d, 0xf5, 0xc6, 0x5e, 0xf2, 0xe9, 0x46, 0x53, 0x66, 0xe1, 0x79, 0x54, 0x6d, 0x2d, 0xc0, 0x60, 0xad, 0x7a, 0x10, + 0xca, 0xaa, 0x3f, 0x8a, 0x13, 0x38, 0xb3, 0x89, 0x37, 0x0e, 0x96, 0x69, 0xcf, 0x6d, 0x2f, 0x56, 0xa2, 0x88, 0xef, + 0xf5, 0xa2, 0x00, 0xcf, 0x5e, 0x2f, 0x8d, 0xc3, 0x60, 0x2c, 0x8a, 0x36, 0x9d, 0x25, 0xb7, 0x6d, 0xf4, 0xd1, 0x91, + 0x3b, 0xc0, 0x70, 0x04, 0x5e, 0x18, 0x6a, 0x76, 0x27, 0xd5, 0x98, 0x97, 0xa2, 0x88, 0x57, 0x73, 0x52, 0x82, 0x0b, + 0x3a, 0x6d, 0xbb, 0x87, 0x8b, 0x95, 0xdc, 0xf3, 0xee, 0xd1, 0x62, 0x95, 0x7f, 0x3d, 0x67, 0xe3, 0xc0, 0xd3, 0x5a, + 0xc5, 0x6e, 0x72, 0x1d, 0x10, 0x03, 0x1b, 0xeb, 0x0d, 0xdb, 0x54, 0x1c, 0x0b, 0x08, 0xf9, 0xf7, 0x24, 0x98, 0x2f, + 0xe2, 0x24, 0xf3, 0xa2, 0x2c, 0xcf, 0x87, 0x37, 0x79, 0xde, 0xbf, 0x0a, 0x5a, 0xd7, 0xff, 0x6c, 0xd1, 0x3d, 0x4d, + 0x6a, 0x93, 0xdc, 0xb8, 0x31, 0xdf, 0x32, 0xd5, 0x48, 0x03, 0xae, 0x31, 0x34, 0xd0, 0x50, 0x2b, 0xd3, 0x2d, 0x59, + 0xaf, 0x4c, 0x40, 0x96, 0xd5, 0xc9, 0xe8, 0xa3, 0x5c, 0x05, 0x6f, 0x20, 0xa8, 0xf0, 0x96, 0x0d, 0xae, 0x14, 0x83, + 0x0f, 0x20, 0x56, 0xb0, 0x32, 0xd9, 0xdb, 0x3f, 0xdb, 0x44, 0x33, 0x7e, 0xb3, 0x9b, 0x66, 0xfc, 0x39, 0xdb, 0x87, + 0x66, 0xfc, 0xe6, 0x8b, 0xd3, 0x8c, 0xcf, 0xea, 0xf6, 0xf6, 0x17, 0xf1, 0x40, 0x97, 0x42, 0x7e, 0xb8, 0x9a, 0x12, + 0x8a, 0x64, 0x73, 0xf1, 0x87, 0xcd, 0xe3, 0x45, 0x6f, 0x94, 0x9b, 0x8d, 0x6e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0x06, + 0xff, 0x48, 0xd4, 0xe7, 0xc9, 0x64, 0xf0, 0x26, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0x7f, 0x28, 0x45, 0x1d, 0xa0, 0x37, + 0xc2, 0xec, 0x11, 0xf3, 0x32, 0x80, 0xd3, 0x32, 0x99, 0xf9, 0x8e, 0xa5, 0xb9, 0x57, 0xbf, 0x3c, 0x84, 0x96, 0xb4, + 0xb1, 0x14, 0xae, 0x29, 0x35, 0x51, 0xe2, 0x94, 0x65, 0xdc, 0x97, 0xf4, 0xdb, 0x87, 0x8b, 0x71, 0xeb, 0x22, 0x36, + 0xf2, 0x20, 0x7d, 0x57, 0x75, 0x0c, 0xe1, 0xea, 0x97, 0x81, 0x3a, 0x9d, 0x9c, 0x9b, 0x6c, 0xa9, 0x89, 0x97, 0xe1, + 0x35, 0x35, 0x3f, 0x2f, 0xcd, 0xb4, 0xa7, 0x36, 0xe4, 0x09, 0xa0, 0x6a, 0x97, 0x31, 0xb7, 0xca, 0x5f, 0x73, 0x0a, + 0x10, 0x73, 0x5a, 0xa1, 0x3f, 0xed, 0x98, 0x9a, 0x07, 0xe3, 0x3c, 0x37, 0xfa, 0x02, 0x10, 0xca, 0x45, 0xcb, 0x76, + 0x11, 0x71, 0xe9, 0xbd, 0xb4, 0x2a, 0xe0, 0x4a, 0x3a, 0xd2, 0xc0, 0x5d, 0x80, 0x4a, 0x9b, 0xeb, 0xeb, 0x38, 0xcc, + 0x74, 0x8d, 0xc0, 0x47, 0xa6, 0x0e, 0xca, 0x84, 0x40, 0xe3, 0x2d, 0xe1, 0x2f, 0x5e, 0x89, 0x82, 0xba, 0xd1, 0x24, + 0x01, 0x07, 0x75, 0xf2, 0xe0, 0xfd, 0x2e, 0xe4, 0xda, 0x84, 0x76, 0x78, 0x1d, 0x7c, 0xc8, 0x75, 0x49, 0xfb, 0xe1, + 0xf6, 0x3b, 0x3b, 0x3d, 0x80, 0x06, 0x67, 0x15, 0xd5, 0xfd, 0x0e, 0x93, 0x40, 0x20, 0x25, 0xd2, 0x7b, 0xd3, 0x4e, + 0xef, 0xb5, 0x17, 0x6b, 0x11, 0x39, 0x22, 0xf3, 0x16, 0x16, 0xb0, 0xf8, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x82, 0x54, + 0xf4, 0x97, 0x29, 0xe0, 0x46, 0x64, 0x54, 0x11, 0xff, 0xf4, 0xfd, 0x65, 0x92, 0xc6, 0x49, 0x6f, 0x11, 0x07, 0x51, + 0xc6, 0x92, 0x1c, 0x41, 0x75, 0x8d, 0xf0, 0x11, 0xe0, 0xb9, 0x59, 0xc7, 0x0b, 0xcf, 0x0f, 0xb2, 0x87, 0x9e, 0xc3, + 0x49, 0x0a, 0xa7, 0xcf, 0xa9, 0x03, 0xa7, 0xb1, 0x7e, 0x8f, 0x43, 0xf3, 0x25, 0x12, 0x7e, 0x49, 0x9d, 0x9c, 0x51, + 0xb7, 0x79, 0x5f, 0x79, 0x4b, 0xb1, 0x33, 0x80, 0xfc, 0xf0, 0x12, 0x6b, 0x0a, 0x58, 0x1e, 0x96, 0xda, 0x19, 0xb3, + 0xa9, 0x89, 0x58, 0x1b, 0xe4, 0xf2, 0xe2, 0xcf, 0xee, 0x1a, 0x9a, 0xd3, 0x5c, 0x0c, 0x14, 0x8f, 0xb1, 0xcf, 0xc8, + 0x7a, 0x1e, 0x64, 0x9a, 0x32, 0xf7, 0xa9, 0x39, 0x62, 0x93, 0x38, 0x61, 0x14, 0x67, 0xd5, 0x3d, 0x59, 0xac, 0xf6, + 0xef, 0x7e, 0xfb, 0xf4, 0x9b, 0xfb, 0x89, 0xe2, 0xac, 0x25, 0x3a, 0x33, 0x76, 0xf4, 0x56, 0xbf, 0xcf, 0x80, 0x34, + 0x24, 0xc8, 0xfb, 0x14, 0xd2, 0xaa, 0xa7, 0xeb, 0xfd, 0xc6, 0x70, 0x56, 0x8b, 0x98, 0xdf, 0x79, 0x09, 0x0b, 0xbd, + 0x2c, 0xb8, 0x13, 0x34, 0x63, 0xe7, 0x68, 0xb1, 0x12, 0x6b, 0x8c, 0x17, 0xde, 0x23, 0x16, 0xa9, 0x32, 0x14, 0xb1, + 0x48, 0xd5, 0x62, 0x5c, 0xa4, 0x7e, 0x6d, 0x36, 0x22, 0xc2, 0x43, 0xe5, 0xa6, 0xef, 0x2e, 0x56, 0xea, 0x15, 0x5d, + 0x34, 0x93, 0x37, 0x75, 0x35, 0x34, 0xd7, 0x3c, 0x18, 0x8f, 0x43, 0x96, 0x97, 0x16, 0xba, 0xbc, 0x96, 0x0a, 0x70, + 0x24, 0x1c, 0xbc, 0x51, 0x1a, 0x87, 0xcb, 0x8c, 0x35, 0x83, 0x8b, 0x80, 0xd3, 0x76, 0x0a, 0xe0, 0xe0, 0xef, 0xf2, + 0x58, 0xbb, 0x40, 0x6e, 0xc3, 0x36, 0x71, 0xfa, 0x10, 0x89, 0xd7, 0xea, 0x94, 0x87, 0x0e, 0xaf, 0xe4, 0xa0, 0xcd, + 0x86, 0x89, 0x98, 0x70, 0x2d, 0x11, 0xf6, 0xd6, 0x6c, 0x97, 0x97, 0xc9, 0x68, 0xa4, 0xb2, 0x28, 0x2f, 0x4f, 0xe6, + 0xcf, 0x39, 0x63, 0xaf, 0x9a, 0xcf, 0xd8, 0x2b, 0x71, 0xc6, 0xb6, 0xef, 0xcc, 0xa7, 0x13, 0x17, 0xfe, 0xeb, 0x17, + 0x13, 0xea, 0x39, 0x5a, 0x67, 0xb1, 0xd2, 0xdc, 0xc5, 0x4a, 0xb3, 0xda, 0x8b, 0x95, 0x86, 0x5d, 0xa3, 0x49, 0x86, + 0x69, 0xb7, 0x0d, 0xd3, 0xd1, 0xa0, 0x10, 0xfe, 0x9c, 0xd2, 0x2b, 0xf7, 0x10, 0xde, 0x41, 0xab, 0x6e, 0xfd, 0x5d, + 0x7b, 0xfb, 0x51, 0xa7, 0xb3, 0x24, 0x90, 0xb6, 0x61, 0x67, 0xde, 0x68, 0xc4, 0xc6, 0xbd, 0x49, 0xec, 0x2f, 0xd3, + 0x7f, 0xf3, 0xf1, 0x73, 0x20, 0x6e, 0x45, 0x04, 0x95, 0x7e, 0x44, 0x53, 0x50, 0x94, 0xdc, 0x31, 0xd1, 0xc3, 0x5a, + 0xae, 0x53, 0x8f, 0xc2, 0x06, 0xb7, 0xed, 0xc3, 0x86, 0x4d, 0xde, 0x0c, 0xe8, 0x3f, 0x6d, 0x95, 0x36, 0xa3, 0x98, + 0xcf, 0x00, 0xcb, 0x56, 0x70, 0x3c, 0x1e, 0x1a, 0x7c, 0x35, 0x9d, 0x93, 0xe6, 0xe1, 0x5e, 0x8b, 0x2f, 0xdd, 0x88, + 0x4b, 0x85, 0xdf, 0x5b, 0xdc, 0x13, 0x64, 0x7b, 0xaf, 0x9b, 0xf6, 0x48, 0xad, 0xd7, 0x2d, 0x17, 0x42, 0x51, 0x77, + 0x4f, 0x2c, 0xff, 0xf4, 0xd5, 0x21, 0xfc, 0x47, 0x54, 0xfd, 0xcf, 0x59, 0x13, 0xa1, 0x7e, 0x51, 0x36, 0xbd, 0x26, + 0x52, 0x09, 0x09, 0xf1, 0xfd, 0xeb, 0x4f, 0x26, 0x8f, 0x6b, 0xb0, 0x77, 0x6d, 0xb2, 0x66, 0xaa, 0xd6, 0xfe, 0x36, + 0x8e, 0x21, 0xa5, 0x65, 0xbd, 0xba, 0x00, 0x0f, 0x59, 0x97, 0x67, 0x03, 0x68, 0x24, 0xf8, 0x08, 0xd2, 0xe2, 0xeb, + 0xd8, 0x86, 0x58, 0x89, 0xb7, 0x9b, 0x58, 0x89, 0x37, 0xbb, 0x59, 0x89, 0xef, 0xf7, 0x62, 0x25, 0xde, 0x7c, 0x71, + 0x56, 0xe2, 0x6d, 0x9d, 0x95, 0xb8, 0x8a, 0x85, 0x05, 0xab, 0x79, 0xb1, 0xe4, 0x3f, 0x3f, 0x92, 0x52, 0xee, 0x32, + 0x1e, 0x74, 0x1d, 0x0a, 0x05, 0x7c, 0xf5, 0x87, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd1, 0xa2, 0xab, 0x60, 0x2d, 0x38, + 0x66, 0xc7, 0xef, 0x28, 0xc5, 0x61, 0x1c, 0x4d, 0x7f, 0x02, 0xa5, 0x2c, 0x88, 0x03, 0x13, 0xe5, 0x45, 0x90, 0xfe, + 0x14, 0x2f, 0x96, 0x8b, 0x0b, 0xe8, 0xeb, 0x63, 0x90, 0x06, 0xa3, 0x90, 0x49, 0x0f, 0x5d, 0xb2, 0x40, 0xe3, 0x32, + 0x71, 0xb0, 0xf9, 0x14, 0x3f, 0xbd, 0x95, 0xf8, 0x89, 0x56, 0xa1, 0xfc, 0x37, 0x99, 0xb6, 0xe9, 0xcd, 0x8c, 0x88, + 0x50, 0x02, 0x2a, 0x83, 0x7e, 0x3c, 0x33, 0x72, 0x15, 0x1b, 0x0d, 0xb3, 0x14, 0xf6, 0x0e, 0x1b, 0xfb, 0x61, 0x35, + 0xa6, 0x66, 0x69, 0x98, 0x32, 0x34, 0x55, 0x5d, 0x0c, 0x3f, 0x8f, 0x97, 0x29, 0x1b, 0xc7, 0xf7, 0x91, 0x6e, 0x46, + 0xd2, 0xaa, 0x1f, 0x34, 0x9c, 0xb2, 0x0d, 0x26, 0x55, 0xfc, 0x80, 0x84, 0x72, 0x9c, 0xb4, 0x74, 0xc8, 0xe9, 0xb9, + 0x5c, 0x58, 0xa4, 0x6a, 0xb6, 0x70, 0x8a, 0xba, 0xcc, 0xfe, 0xf3, 0xa4, 0xd5, 0x8a, 0x07, 0x8f, 0x6b, 0x29, 0x4c, + 0x35, 0x62, 0x9b, 0x4b, 0x85, 0xd3, 0x56, 0x24, 0x84, 0x8b, 0x22, 0x3e, 0x44, 0xc3, 0xc2, 0xf1, 0x37, 0xe4, 0x2b, + 0x5a, 0xbc, 0x85, 0xe8, 0x1a, 0xf9, 0x92, 0xaf, 0x07, 0x8f, 0x96, 0x40, 0x8f, 0xaf, 0x15, 0x30, 0xbe, 0xbb, 0x63, + 0x49, 0xe8, 0x3d, 0xb4, 0x8c, 0x3c, 0x8e, 0x7e, 0x00, 0x00, 0xbc, 0x89, 0xef, 0x23, 0xb5, 0x02, 0x26, 0x31, 0x69, + 0xd8, 0x4b, 0x8d, 0x71, 0x3d, 0xc0, 0x53, 0x44, 0x19, 0x01, 0xa4, 0x8f, 0x9d, 0xb2, 0x7f, 0x98, 0xf4, 0xef, 0x3f, + 0x8d, 0xdc, 0xbc, 0x8c, 0xe5, 0x87, 0xfe, 0xbe, 0xd8, 0xe3, 0x33, 0xcf, 0x9f, 0x3f, 0xd9, 0x3c, 0xed, 0x72, 0xda, + 0xf2, 0x86, 0xd6, 0xc6, 0xc6, 0x53, 0x00, 0xa3, 0xb8, 0x8a, 0x97, 0xfe, 0x0c, 0x6d, 0x4d, 0xbf, 0xdc, 0x7c, 0x33, + 0xe8, 0x13, 0xb3, 0x77, 0xca, 0xa9, 0x57, 0x8a, 0x0a, 0x28, 0xe0, 0xf7, 0xdf, 0x42, 0x60, 0xca, 0xff, 0x21, 0x18, + 0xea, 0xbb, 0x86, 0x73, 0xf1, 0xc1, 0xe3, 0x36, 0x6f, 0x1f, 0x92, 0x4c, 0xf2, 0x90, 0x0f, 0x42, 0xb9, 0xd6, 0x8c, + 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0xf0, 0x6a, 0x9b, 0x22, 0xc7, 0x89, 0xaf, 0x30, 0x9b, 0xd8, 0x74, 0x6e, 0xea, 0x6f, + 0x32, 0x8e, 0xad, 0x2a, 0x48, 0x86, 0x9b, 0x3c, 0x30, 0x44, 0x5f, 0xd5, 0x77, 0xf3, 0x20, 0x32, 0x31, 0x3a, 0x7a, + 0xfd, 0x8d, 0xb7, 0x82, 0xf8, 0xc0, 0x80, 0xdc, 0xaa, 0xaf, 0xa0, 0xd0, 0x54, 0x1d, 0xd5, 0x20, 0x05, 0x92, 0xde, + 0x08, 0x09, 0xa1, 0xc5, 0x1b, 0xfe, 0x45, 0xd3, 0x34, 0x4d, 0xb2, 0x11, 0x9a, 0xe4, 0x23, 0xb0, 0x1c, 0xd9, 0x01, + 0xd0, 0x96, 0xe4, 0x8b, 0x15, 0x95, 0x00, 0x67, 0x80, 0x3a, 0x59, 0x51, 0xc0, 0x43, 0xe0, 0x75, 0x1d, 0x51, 0x20, + 0x18, 0x7a, 0x08, 0x5f, 0xe6, 0x25, 0x10, 0x29, 0xb7, 0xa7, 0x21, 0xc3, 0x8e, 0x6f, 0xb9, 0x24, 0x58, 0x73, 0xe8, + 0x71, 0xd8, 0x67, 0xcd, 0xb1, 0xd2, 0x22, 0x05, 0x0b, 0x82, 0xd6, 0xa1, 0x12, 0xfa, 0xd8, 0x64, 0x0d, 0xb8, 0x11, + 0xf9, 0xa2, 0x55, 0x36, 0x67, 0xd1, 0x52, 0xc7, 0x5c, 0x49, 0x18, 0xbb, 0x0e, 0xea, 0xbc, 0x21, 0x62, 0x0b, 0xb0, + 0x4d, 0x73, 0xcb, 0x19, 0xdd, 0x85, 0x29, 0x47, 0xa9, 0x9e, 0xe9, 0x73, 0xc5, 0x66, 0xca, 0x71, 0x5b, 0xf5, 0x86, + 0xe0, 0x4b, 0x1a, 0x57, 0x3d, 0xa7, 0xc8, 0x18, 0x19, 0xfa, 0xa0, 0xa8, 0x11, 0x5c, 0x5c, 0x24, 0xc0, 0xde, 0xf2, + 0xaa, 0x8b, 0x26, 0x35, 0x32, 0x5e, 0x45, 0x50, 0x94, 0x18, 0xf5, 0x6e, 0xf8, 0x38, 0x21, 0x60, 0xcf, 0xc6, 0x7e, + 0xfc, 0x5a, 0x3f, 0x1b, 0x26, 0xfd, 0x89, 0x3d, 0xd0, 0x45, 0x42, 0xa0, 0xfa, 0xc4, 0x1e, 0xc0, 0xf6, 0xef, 0x2d, + 0x48, 0x53, 0xf4, 0x2d, 0xe8, 0xda, 0x84, 0x10, 0xf8, 0x3e, 0x04, 0x71, 0xda, 0x72, 0x80, 0x9c, 0x7c, 0x0b, 0x16, + 0x47, 0x10, 0x43, 0xb6, 0x63, 0x71, 0x88, 0xb9, 0x95, 0x7d, 0xab, 0x11, 0xc6, 0x56, 0xc3, 0xd1, 0x30, 0x5e, 0xb8, + 0x8e, 0x73, 0x50, 0xab, 0x0f, 0x82, 0xec, 0xa6, 0xda, 0x86, 0x99, 0x0d, 0x5c, 0xc7, 0x0a, 0x5e, 0xd8, 0xed, 0x7e, + 0xed, 0x8e, 0x56, 0x62, 0x2c, 0x0e, 0x51, 0xfc, 0x75, 0xf6, 0x6c, 0xdd, 0xaa, 0x1d, 0x48, 0xa3, 0x6a, 0xb5, 0x8e, + 0x63, 0xcb, 0xb9, 0xfc, 0x6b, 0x58, 0xbf, 0xfa, 0x29, 0xc2, 0x23, 0xe5, 0xfb, 0x18, 0x42, 0x94, 0xe0, 0x16, 0x1c, + 0xa3, 0xbf, 0x6a, 0x2f, 0xb5, 0x16, 0x1d, 0x1f, 0xc3, 0x18, 0xca, 0x34, 0xd2, 0xc2, 0xab, 0x4b, 0xed, 0xa0, 0xf2, + 0xc5, 0xb4, 0x8a, 0xe1, 0x78, 0x3c, 0x52, 0x56, 0x68, 0xf4, 0xb6, 0x52, 0x0b, 0xd8, 0xff, 0x86, 0xeb, 0xd3, 0x1e, + 0x41, 0x20, 0x00, 0xa8, 0x01, 0x31, 0xc5, 0x77, 0x76, 0xb8, 0x5c, 0x94, 0xbb, 0x2b, 0x5f, 0x92, 0xfb, 0x77, 0x86, + 0x97, 0x0e, 0xea, 0xd0, 0x64, 0x7f, 0xcd, 0xd7, 0xdd, 0x23, 0xbb, 0x64, 0xd1, 0xb8, 0xdc, 0x61, 0xe5, 0xfe, 0xda, + 0xbf, 0xbb, 0x12, 0x46, 0x81, 0x60, 0xfb, 0x71, 0x03, 0x46, 0xc9, 0xe3, 0x08, 0x37, 0x3f, 0x1d, 0xb7, 0x60, 0x2f, + 0x2a, 0x06, 0x1b, 0x50, 0xa4, 0x2c, 0xd9, 0x4c, 0x11, 0x8a, 0x43, 0x44, 0x67, 0xf4, 0xc3, 0x6d, 0x09, 0x42, 0x74, + 0xe3, 0x4e, 0xcc, 0x84, 0x4d, 0x61, 0xd1, 0x26, 0xe0, 0x31, 0x1a, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, 0xd9, + 0x2e, 0xa9, 0x35, 0x39, 0x34, 0xdd, 0x27, 0xde, 0x42, 0xf1, 0x89, 0x13, 0xc4, 0xb9, 0xea, 0x1a, 0x57, 0x12, 0x75, + 0xa3, 0xff, 0x93, 0x68, 0x55, 0xeb, 0x8d, 0xac, 0x04, 0x51, 0xfc, 0xad, 0x30, 0x28, 0x42, 0xa1, 0xae, 0xca, 0xc6, + 0xaf, 0x0a, 0xd9, 0x38, 0x71, 0x35, 0x85, 0x2f, 0x8b, 0xa0, 0xfe, 0x15, 0x37, 0x31, 0xc9, 0x1d, 0x14, 0xee, 0x62, + 0xc5, 0x48, 0x15, 0x07, 0xa8, 0x82, 0xd1, 0x50, 0xdc, 0xea, 0x04, 0x97, 0x51, 0xf6, 0xae, 0x2b, 0x57, 0x2d, 0xbc, + 0xcd, 0x8a, 0x72, 0x90, 0xba, 0xe3, 0x90, 0x65, 0xb1, 0xba, 0x6d, 0xca, 0x1e, 0x30, 0xea, 0x6b, 0x65, 0x93, 0x48, + 0x57, 0x15, 0x02, 0xb0, 0x10, 0xd3, 0x57, 0xf4, 0xda, 0xd2, 0x06, 0x02, 0x07, 0xd9, 0xe0, 0x58, 0xb7, 0x5b, 0x3a, + 0x4f, 0x79, 0x04, 0x0a, 0x2d, 0xbc, 0x2a, 0x83, 0x40, 0xf8, 0xde, 0xac, 0x1b, 0x6e, 0x79, 0xbc, 0xe4, 0xf9, 0xfd, + 0x0e, 0xe2, 0x45, 0xcd, 0x51, 0x15, 0xf9, 0x78, 0x32, 0x2d, 0x32, 0xcf, 0xc5, 0xaa, 0xf5, 0x4e, 0x49, 0x88, 0xb3, + 0xe6, 0xce, 0x29, 0x65, 0x19, 0x3d, 0xaf, 0xd1, 0x13, 0xdf, 0xe5, 0x5b, 0x27, 0x59, 0x46, 0x18, 0xf3, 0xdd, 0xca, + 0x12, 0xcf, 0xff, 0xa4, 0x0c, 0x59, 0xc8, 0x39, 0x41, 0x06, 0x5c, 0xd6, 0x14, 0xf4, 0x3d, 0x0c, 0x91, 0xc8, 0x7a, + 0x76, 0x3b, 0x55, 0xa4, 0x2f, 0xbd, 0xa7, 0x4e, 0xc7, 0x7b, 0x35, 0x39, 0xac, 0x08, 0x45, 0xdb, 0xdd, 0xb2, 0xc8, + 0x7c, 0xc3, 0x38, 0xb2, 0xd9, 0x72, 0x3e, 0x5a, 0xab, 0xb2, 0x55, 0x45, 0xe4, 0x5a, 0x17, 0xb3, 0xaa, 0x9f, 0x9d, + 0x4c, 0x26, 0x65, 0x41, 0xa3, 0xa3, 0x1d, 0xa2, 0xb0, 0xf0, 0xa9, 0xe3, 0x38, 0xd5, 0xb1, 0x6f, 0x07, 0xbb, 0x85, + 0x72, 0xdb, 0x93, 0xc6, 0x11, 0x23, 0x6c, 0x77, 0xc1, 0xaf, 0x0e, 0x8e, 0xdc, 0x2e, 0x4e, 0x76, 0xc9, 0x2c, 0xa2, + 0x4f, 0xc6, 0x10, 0x41, 0xc6, 0xe6, 0x69, 0xcf, 0x67, 0xa8, 0x83, 0xb1, 0x95, 0x03, 0x8d, 0x86, 0x03, 0xd6, 0x14, + 0x4c, 0x45, 0x5c, 0xb1, 0x2b, 0x1c, 0x0d, 0xe5, 0xe1, 0x35, 0xe1, 0xbd, 0xf8, 0x08, 0x1e, 0x94, 0x75, 0x5d, 0xa6, + 0x8d, 0xd3, 0xea, 0x3a, 0x7f, 0x2d, 0xd5, 0xd3, 0xe0, 0x02, 0x5c, 0x0b, 0x85, 0x36, 0xc9, 0x67, 0xf1, 0xff, 0xa5, + 0xfc, 0xff, 0xd5, 0x62, 0x55, 0xb6, 0x1f, 0x39, 0x01, 0x89, 0x76, 0x71, 0x5a, 0x68, 0xd4, 0x4d, 0x7b, 0x40, 0x5a, + 0x19, 0x4c, 0x54, 0x05, 0x3a, 0x28, 0xe9, 0x4b, 0x89, 0x31, 0x1a, 0xc4, 0xef, 0x48, 0x31, 0xc3, 0x12, 0x17, 0x22, + 0xc4, 0x22, 0xad, 0x1b, 0xcc, 0xc1, 0x7c, 0x79, 0x82, 0xfa, 0x83, 0xd2, 0x9e, 0x00, 0x6d, 0x7c, 0x6d, 0x6e, 0x7b, + 0x89, 0xfb, 0xab, 0x7a, 0x2d, 0xd1, 0x31, 0x80, 0xcc, 0x85, 0x43, 0x88, 0x86, 0x04, 0x5a, 0x65, 0x73, 0xd3, 0x28, + 0xe5, 0x5b, 0x55, 0xcf, 0x26, 0x06, 0x86, 0xdd, 0x35, 0x57, 0xa1, 0xbe, 0x85, 0xb6, 0x00, 0x26, 0xcb, 0xb7, 0x1f, + 0x3e, 0x5b, 0xb0, 0xc4, 0xea, 0x7e, 0x74, 0x71, 0xc9, 0x71, 0xff, 0x5a, 0x78, 0x77, 0xa6, 0x74, 0xfe, 0x51, 0xbe, + 0xf8, 0x7d, 0xa3, 0x40, 0xef, 0xaa, 0x24, 0xa1, 0xe3, 0xd6, 0xe2, 0x6d, 0x63, 0xaf, 0xda, 0xf3, 0x20, 0xda, 0xbf, + 0xae, 0xb7, 0xda, 0xbb, 0x2e, 0x5c, 0x18, 0x7b, 0x57, 0x86, 0x1b, 0x87, 0x2c, 0x17, 0xb2, 0xc1, 0xf7, 0x8a, 0x40, + 0x51, 0xf5, 0xfb, 0xd5, 0xb1, 0x15, 0x51, 0xf9, 0x57, 0x4b, 0x20, 0x3e, 0xf7, 0x4a, 0x7c, 0xa0, 0x89, 0xdc, 0x65, + 0xfa, 0xb1, 0x76, 0xa2, 0x1d, 0x77, 0xb4, 0x23, 0x47, 0x27, 0x2e, 0x6c, 0xa0, 0x77, 0xdb, 0x85, 0x43, 0xdf, 0xa1, + 0xa3, 0x9f, 0x9d, 0x4e, 0xc5, 0x25, 0x31, 0x09, 0xc2, 0x90, 0x50, 0x45, 0x9a, 0x25, 0xf1, 0x27, 0x56, 0x56, 0xb3, + 0x50, 0x19, 0x37, 0x02, 0x69, 0x8b, 0x47, 0x38, 0x3b, 0xbe, 0xb7, 0xe8, 0xe1, 0xd9, 0x50, 0x0b, 0xc1, 0x80, 0x93, + 0x4a, 0xf1, 0x13, 0x70, 0x07, 0x8f, 0xf4, 0xb3, 0x53, 0x08, 0xed, 0xa7, 0x8d, 0x07, 0xfa, 0x0f, 0xed, 0x63, 0xcd, + 0xed, 0xde, 0x59, 0x1d, 0xdf, 0xb1, 0x5c, 0xfb, 0x50, 0x73, 0xec, 0x23, 0xab, 0x6d, 0x1f, 0x6b, 0x6d, 0xbb, 0x0b, + 0xff, 0xfa, 0xae, 0xfd, 0x4a, 0x73, 0xe0, 0x49, 0x73, 0xed, 0x0e, 0xfe, 0xdb, 0xb6, 0x8f, 0xef, 0x3a, 0x74, 0xd3, + 0x7b, 0xd2, 0xad, 0xaa, 0x32, 0x0a, 0x70, 0x02, 0xd1, 0x0f, 0xce, 0x4e, 0x97, 0x29, 0xd3, 0x56, 0x03, 0xfd, 0x95, + 0xae, 0xcd, 0x12, 0x36, 0x19, 0xe8, 0x4f, 0x3d, 0xa5, 0xd4, 0x3d, 0x69, 0x2c, 0x6e, 0x1f, 0x37, 0x16, 0x77, 0x8e, + 0x1a, 0x8b, 0x0f, 0xbb, 0xe5, 0xe2, 0x83, 0x29, 0xbd, 0x52, 0x32, 0xeb, 0xcd, 0xbd, 0x2c, 0x09, 0x56, 0x2d, 0x57, + 0x03, 0x74, 0x6d, 0xc1, 0x3f, 0xc7, 0x6d, 0x43, 0xb6, 0x1a, 0x41, 0x2b, 0x09, 0x8d, 0xe3, 0x13, 0xcd, 0x3d, 0xfa, + 0x5b, 0xfb, 0xc8, 0x87, 0x7a, 0x90, 0x07, 0x12, 0xfe, 0xee, 0x3a, 0x27, 0xbe, 0xa3, 0x41, 0x43, 0x17, 0xfe, 0x9b, + 0x75, 0xdb, 0x3e, 0x3d, 0x38, 0xf0, 0xfe, 0xa3, 0x7b, 0x9c, 0x3a, 0x96, 0x0b, 0xff, 0xfd, 0x2a, 0x55, 0xee, 0xa0, + 0xf0, 0x57, 0xfb, 0x3d, 0x74, 0xb4, 0xce, 0xc9, 0xac, 0x6d, 0xbf, 0xba, 0x3b, 0xb6, 0x4f, 0x66, 0xee, 0xf1, 0x47, + 0x7a, 0x0a, 0xad, 0xb6, 0xfd, 0x0a, 0xfe, 0x3e, 0x76, 0x9c, 0x99, 0xe5, 0xda, 0x27, 0x77, 0x1d, 0xbb, 0x13, 0x5a, + 0x47, 0xf6, 0x09, 0xfc, 0xfd, 0x0a, 0xe0, 0x05, 0xb8, 0xf2, 0xc4, 0x9d, 0x1a, 0x6c, 0x8c, 0x8a, 0xfd, 0x86, 0xfa, + 0x91, 0xf6, 0xa1, 0xd6, 0x3d, 0xfc, 0xdb, 0xc9, 0x9d, 0x75, 0x38, 0x73, 0xdb, 0x77, 0xd6, 0xc6, 0x9f, 0x1f, 0x01, + 0xf2, 0xdb, 0x17, 0x0e, 0xc0, 0x88, 0x99, 0x3a, 0xfe, 0x32, 0x34, 0x2f, 0x37, 0x89, 0xd1, 0xdf, 0xef, 0x16, 0xa3, + 0x7f, 0xb7, 0xdc, 0x47, 0x8c, 0xfe, 0xfe, 0x8b, 0x8b, 0xd1, 0x2f, 0xab, 0x56, 0xdc, 0xef, 0xab, 0x11, 0xc5, 0x7f, + 0x5e, 0x57, 0x89, 0xe4, 0xc0, 0x6b, 0x5d, 0x5f, 0x2d, 0x6f, 0x20, 0xd8, 0xce, 0xfb, 0x78, 0xf0, 0xdd, 0xb2, 0x64, + 0xa2, 0x14, 0x03, 0x06, 0x78, 0x1f, 0x13, 0x06, 0xf8, 0x75, 0x39, 0x00, 0xbb, 0x08, 0x7e, 0x6b, 0x06, 0x63, 0x6b, + 0xe6, 0x85, 0x13, 0x79, 0xe3, 0x42, 0x49, 0x1f, 0x8b, 0xc1, 0x66, 0x1e, 0x2e, 0x13, 0x50, 0xd6, 0x2c, 0xe7, 0x51, + 0xda, 0x3b, 0x72, 0x00, 0xcd, 0xb7, 0x27, 0x49, 0x5e, 0x69, 0x6c, 0x8b, 0xf0, 0x44, 0xb7, 0xdc, 0xa6, 0x7f, 0xe3, + 0x7b, 0x34, 0x59, 0x6b, 0xee, 0xdd, 0xad, 0xf7, 0xab, 0x81, 0x2d, 0x88, 0x30, 0xe9, 0x03, 0x62, 0xa3, 0xe9, 0x7d, + 0xd9, 0x70, 0xac, 0x62, 0x2a, 0xb8, 0x79, 0xa4, 0x30, 0x92, 0x6a, 0x7b, 0xb7, 0x6c, 0x78, 0xb6, 0x6b, 0x9a, 0x0d, + 0x9f, 0x2f, 0x35, 0xdf, 0x62, 0xf5, 0x26, 0x3b, 0xae, 0x82, 0xaa, 0x92, 0x0f, 0xab, 0x11, 0x20, 0x05, 0xed, 0x59, + 0x98, 0xc6, 0x15, 0x84, 0x8f, 0xa3, 0xe1, 0x6d, 0xec, 0x28, 0xef, 0x4a, 0x7d, 0xaa, 0xe6, 0x74, 0x2f, 0xd6, 0x48, + 0x0f, 0x06, 0xbf, 0x02, 0x61, 0xc3, 0xef, 0xe3, 0x51, 0xac, 0xc2, 0x79, 0xad, 0xf4, 0x4b, 0xa4, 0x76, 0x3e, 0x73, + 0xd7, 0x75, 0xd2, 0x66, 0xa3, 0x21, 0xad, 0xcb, 0xe6, 0xe2, 0x8e, 0xc6, 0xcf, 0x93, 0xd9, 0x6a, 0x4e, 0xa6, 0xc5, + 0x68, 0x99, 0xbb, 0xad, 0x33, 0x51, 0xef, 0x29, 0x6c, 0x62, 0x93, 0x3f, 0xa8, 0x8e, 0xe3, 0xeb, 0x09, 0xe4, 0x2e, + 0xee, 0x21, 0x11, 0xa1, 0x50, 0x50, 0x6d, 0xb4, 0xb1, 0xed, 0x6f, 0x31, 0xff, 0x50, 0x3b, 0xe6, 0x9d, 0xa0, 0xad, + 0xee, 0x36, 0x8b, 0x11, 0xe9, 0xda, 0xb0, 0x2e, 0x29, 0x50, 0xdd, 0xee, 0xb1, 0xe9, 0x1e, 0x99, 0xf6, 0x71, 0xd7, + 0xc8, 0xc5, 0x81, 0x53, 0xbb, 0x2c, 0x01, 0x04, 0x4c, 0x76, 0xe5, 0x30, 0x83, 0x28, 0xc8, 0x02, 0x2f, 0xcc, 0x01, + 0xd5, 0x97, 0x69, 0xde, 0x7f, 0x2d, 0xd3, 0x0c, 0xe6, 0x28, 0x48, 0x32, 0x34, 0x57, 0xb6, 0x46, 0x2c, 0xbb, 0x67, + 0x2c, 0xda, 0xa0, 0xca, 0xad, 0x5a, 0x3f, 0xff, 0x79, 0xb6, 0xa0, 0x39, 0xd9, 0x59, 0x8c, 0xb2, 0x88, 0xef, 0x0f, + 0x61, 0xaa, 0x9b, 0x0f, 0xcd, 0x1f, 0x37, 0x21, 0xdc, 0x7f, 0xed, 0x46, 0xb8, 0x19, 0xdb, 0x07, 0xe1, 0xfe, 0xeb, + 0x8b, 0x23, 0xdc, 0x1f, 0x55, 0x84, 0x5b, 0xf2, 0x54, 0x29, 0x64, 0xa2, 0x1f, 0xf0, 0xb9, 0x05, 0xa1, 0x78, 0x5f, + 0xea, 0x07, 0x44, 0x5e, 0xea, 0x4a, 0x8a, 0xd4, 0x8f, 0xa5, 0x9c, 0x2f, 0xc8, 0xb2, 0x63, 0x4c, 0x52, 0xca, 0x2f, + 0x01, 0xe9, 0x43, 0x65, 0x22, 0x6c, 0xe8, 0xf3, 0x22, 0xca, 0x42, 0xfb, 0x3d, 0x67, 0x4b, 0x40, 0x05, 0xf1, 0x5d, + 0x9c, 0xcc, 0x3d, 0x8c, 0xc7, 0xa6, 0x63, 0xae, 0x38, 0x78, 0x70, 0xc0, 0x3b, 0xca, 0x8f, 0xa3, 0xb1, 0x94, 0xa3, + 0xb3, 0xc1, 0x35, 0xd1, 0x83, 0xfa, 0x03, 0xf3, 0x12, 0xdd, 0xa4, 0xd7, 0xb0, 0xb8, 0x2f, 0x3a, 0xce, 0x8b, 0xf6, + 0xe1, 0x8b, 0x23, 0x07, 0xfe, 0xe7, 0xb2, 0x4e, 0x6e, 0xf2, 0x8a, 0xf3, 0x38, 0x82, 0x74, 0x15, 0xa2, 0xe6, 0xa6, + 0x6a, 0xf7, 0x8c, 0x7d, 0x2a, 0x6a, 0x1d, 0x37, 0x57, 0x1a, 0x7b, 0x0f, 0x45, 0x9d, 0xc6, 0x1a, 0xb3, 0x78, 0xa9, + 0x0c, 0xab, 0x61, 0x34, 0x41, 0xb4, 0x04, 0xc9, 0x90, 0x52, 0x43, 0x7d, 0xcd, 0xa7, 0x5b, 0xcc, 0x8b, 0x75, 0xf2, + 0x9b, 0x22, 0x27, 0x8e, 0xc8, 0xcd, 0xb1, 0x13, 0x82, 0x5c, 0xa8, 0xee, 0x60, 0x44, 0x6d, 0xcc, 0x0a, 0xa3, 0x41, + 0x46, 0xba, 0x22, 0xf1, 0x39, 0x2e, 0x50, 0x96, 0x2c, 0x23, 0x9f, 0x72, 0x9b, 0x7b, 0xa3, 0xb4, 0x15, 0x1c, 0x40, + 0xb0, 0x4e, 0xfc, 0xb0, 0x81, 0xab, 0xe6, 0x9d, 0x39, 0x45, 0x02, 0x81, 0x54, 0xac, 0x8a, 0xf7, 0x22, 0x33, 0x13, + 0x4a, 0x3b, 0x8a, 0x4b, 0x6b, 0x0d, 0xbc, 0x17, 0xb2, 0xe1, 0x8b, 0xcc, 0x84, 0xd4, 0x9f, 0xb0, 0xdc, 0xcf, 0x9f, + 0x53, 0x2d, 0x48, 0xc6, 0x47, 0xd3, 0x3a, 0xf7, 0x65, 0x02, 0x2f, 0x5d, 0xf3, 0xa6, 0xb1, 0x8e, 0x09, 0xbc, 0x7a, + 0xbe, 0x19, 0xbf, 0x7c, 0x79, 0x36, 0x70, 0x0d, 0x9e, 0x4a, 0xb2, 0x94, 0xf7, 0xe8, 0x72, 0x3f, 0xd5, 0xb8, 0xd1, + 0xe8, 0xb4, 0xb5, 0x08, 0xa2, 0xa9, 0xd0, 0x4c, 0x4b, 0xec, 0x05, 0x79, 0x08, 0x48, 0x05, 0xe6, 0x09, 0x15, 0xb5, + 0xa8, 0x73, 0xc7, 0x12, 0x48, 0x83, 0x39, 0xd0, 0x3b, 0xb6, 0x63, 0x3b, 0xba, 0x6c, 0x38, 0x09, 0xa6, 0x83, 0x75, + 0x9c, 0x79, 0x90, 0xd1, 0x25, 0x8c, 0xa7, 0xe0, 0xf9, 0x91, 0x05, 0x59, 0x08, 0xe9, 0x41, 0xc0, 0x05, 0x64, 0x4e, + 0x5c, 0x63, 0xce, 0xed, 0x71, 0xbd, 0xe4, 0x13, 0xa6, 0x88, 0x13, 0x4e, 0x5f, 0x18, 0x92, 0xe6, 0x07, 0xb8, 0x0c, + 0x5b, 0x7a, 0x0b, 0x12, 0x14, 0xb2, 0x24, 0xb5, 0x54, 0xfb, 0xf6, 0x9e, 0x06, 0x6d, 0x20, 0x79, 0x38, 0x76, 0x30, + 0x49, 0xbc, 0x39, 0x44, 0xd2, 0x5e, 0xe7, 0x26, 0xc7, 0xb4, 0x3a, 0x47, 0xb5, 0x9a, 0xfb, 0xea, 0xc8, 0xd4, 0xda, + 0xae, 0xa9, 0x39, 0x80, 0x6e, 0xf5, 0xdc, 0x5c, 0xe7, 0x37, 0xfd, 0x5d, 0x2a, 0x3a, 0xc2, 0x2f, 0x4f, 0x69, 0x1e, + 0xa4, 0x9c, 0xe3, 0xc2, 0xcf, 0x8c, 0xe2, 0x09, 0xb6, 0x94, 0x18, 0xd7, 0x01, 0x89, 0xe9, 0xaf, 0xd8, 0x2a, 0x33, + 0x30, 0x7d, 0x06, 0xaf, 0x12, 0x18, 0x6b, 0x74, 0x4d, 0x0b, 0x22, 0x2d, 0xf8, 0xed, 0xb7, 0x56, 0x00, 0xe6, 0xf7, + 0x03, 0x05, 0x3e, 0xf0, 0x6c, 0x94, 0x00, 0x16, 0x14, 0x8a, 0x25, 0x04, 0x16, 0xf8, 0xc6, 0xc0, 0xbf, 0x45, 0xb1, + 0xf8, 0xc1, 0x15, 0x7b, 0x76, 0xe8, 0x45, 0x53, 0x40, 0x69, 0x5e, 0x34, 0xad, 0x19, 0x10, 0x90, 0x77, 0x5d, 0xa5, + 0xb4, 0xe8, 0xaa, 0x50, 0xee, 0xa7, 0xdf, 0x3e, 0x5c, 0x51, 0x7a, 0x20, 0x48, 0x45, 0xed, 0x8d, 0xd1, 0x15, 0xac, + 0xd0, 0x3d, 0xbc, 0x1c, 0x7c, 0x75, 0x3a, 0x67, 0x99, 0x47, 0x82, 0x4b, 0x60, 0xf1, 0x80, 0x1c, 0xd0, 0x7c, 0x91, + 0xda, 0x93, 0x18, 0xbc, 0x31, 0xbb, 0x0b, 0x7c, 0xce, 0xa7, 0x99, 0x1a, 0xbf, 0xa7, 0x2c, 0xb4, 0x51, 0x1a, 0xb8, + 0x26, 0x99, 0xc8, 0xfa, 0x1e, 0x46, 0x1d, 0x1c, 0x44, 0xb1, 0x7e, 0xf6, 0x95, 0xf4, 0x26, 0xda, 0xb4, 0x08, 0x90, + 0xa3, 0xef, 0x3a, 0x61, 0xe1, 0xbf, 0x07, 0x5f, 0xc1, 0xc5, 0xfd, 0xd5, 0x8d, 0x6e, 0xf4, 0x33, 0x1b, 0xf9, 0x98, + 0xaf, 0x1a, 0x72, 0xd5, 0x21, 0x8f, 0xca, 0x99, 0xcd, 0x8e, 0xc2, 0x6c, 0xc2, 0xef, 0xdd, 0xac, 0xeb, 0xd9, 0x29, + 0x5e, 0x68, 0x67, 0xc0, 0x5d, 0xac, 0x4b, 0x3c, 0xa7, 0xdb, 0x47, 0x06, 0x75, 0x14, 0x7a, 0xfe, 0x27, 0xc1, 0xa1, + 0xaa, 0x0f, 0xfb, 0xf0, 0xa2, 0x92, 0xb2, 0x6b, 0xdc, 0xcb, 0xb8, 0x95, 0xd7, 0xf8, 0x65, 0xfc, 0xd4, 0xfd, 0x2c, + 0xc8, 0x24, 0x33, 0x8c, 0x0f, 0x39, 0x68, 0x73, 0x70, 0x7c, 0x05, 0xfb, 0x03, 0x0c, 0xaa, 0x7b, 0xf2, 0xb7, 0xee, + 0x9d, 0xeb, 0xcc, 0xda, 0xae, 0x0d, 0x6c, 0xce, 0xac, 0x63, 0x1f, 0x87, 0x56, 0xc7, 0x3e, 0x86, 0xbf, 0x8f, 0xc0, + 0x7a, 0x59, 0x6d, 0xfb, 0xf0, 0xa3, 0xdb, 0x0e, 0xad, 0x13, 0xfb, 0x18, 0xfe, 0x2e, 0xa9, 0xd5, 0xcf, 0xc8, 0xf4, + 0x00, 0xc3, 0xf3, 0x55, 0x09, 0x0b, 0x28, 0xbf, 0xa5, 0x16, 0xc1, 0x2c, 0x5d, 0x6f, 0x0d, 0x9a, 0x08, 0x40, 0x19, + 0xba, 0x29, 0x82, 0x04, 0x46, 0xfd, 0x16, 0x24, 0xcf, 0xc6, 0xb0, 0xef, 0xc2, 0x20, 0x23, 0x2a, 0x12, 0xc1, 0x6f, + 0x3e, 0x46, 0xbc, 0x4d, 0x73, 0xfc, 0x6d, 0x91, 0x4f, 0x88, 0x54, 0x17, 0x7f, 0x5f, 0x60, 0x60, 0x1d, 0x11, 0x31, + 0x5c, 0xc1, 0x4a, 0x45, 0x4e, 0xbb, 0x7c, 0xf7, 0xc0, 0xd1, 0x6f, 0x94, 0xc9, 0x9c, 0x2a, 0x5f, 0xb4, 0x6f, 0xae, + 0xce, 0x90, 0xbd, 0xff, 0xd1, 0x7e, 0x30, 0x95, 0x28, 0xf5, 0x23, 0x82, 0x7b, 0x8e, 0x83, 0x44, 0x0e, 0x4f, 0x41, + 0xd1, 0x6e, 0x73, 0xe0, 0x72, 0x03, 0x92, 0x4f, 0x5c, 0x00, 0x95, 0x7c, 0xe7, 0x85, 0x8a, 0xe9, 0x85, 0xd2, 0xf2, + 0x89, 0xc4, 0xfc, 0xcf, 0x9f, 0x17, 0x83, 0xb3, 0x2a, 0xe3, 0x3e, 0x75, 0xbb, 0x70, 0xed, 0x76, 0x59, 0x67, 0xab, + 0x15, 0xd0, 0xee, 0xe8, 0xb0, 0x45, 0x38, 0x49, 0xa1, 0xe9, 0x17, 0x3a, 0xc6, 0x8d, 0xa6, 0x48, 0x35, 0x0d, 0x23, + 0xc4, 0xd5, 0xad, 0xb0, 0x3a, 0xba, 0xd1, 0x8f, 0x84, 0xc2, 0x2c, 0xda, 0x12, 0x11, 0x97, 0xf3, 0x62, 0x3a, 0x80, + 0x66, 0xcb, 0x3c, 0x76, 0xb8, 0x34, 0xfe, 0xaf, 0x27, 0x81, 0xee, 0x45, 0xa0, 0xe1, 0xab, 0x9c, 0xd6, 0x92, 0xbb, + 0x89, 0xbc, 0x57, 0xe9, 0x42, 0x65, 0xe9, 0xb9, 0x0e, 0x45, 0x90, 0x95, 0x08, 0x13, 0x91, 0x49, 0xf3, 0x26, 0x79, + 0x5b, 0x14, 0x05, 0x66, 0x00, 0x21, 0xa1, 0x5b, 0xc2, 0xd5, 0xc9, 0x78, 0xfe, 0x7c, 0xe3, 0x25, 0x44, 0xea, 0x64, + 0x35, 0x1f, 0xa3, 0xae, 0xe2, 0x37, 0x5d, 0x45, 0x31, 0xb2, 0x5f, 0xc4, 0x1a, 0xc2, 0x2a, 0x8b, 0xf6, 0x1e, 0xfe, + 0x1c, 0x31, 0x2f, 0xb3, 0xb9, 0x1e, 0xa4, 0xa5, 0x5c, 0xee, 0xa6, 0xcb, 0x3a, 0x60, 0x8f, 0xc5, 0xe3, 0x6f, 0xf1, + 0x60, 0x73, 0xcf, 0xd6, 0x1f, 0x97, 0xdc, 0x0f, 0x19, 0xfa, 0xf8, 0xcd, 0x29, 0x82, 0xa7, 0xbc, 0xcb, 0x3c, 0x8a, + 0xb0, 0xa1, 0x5e, 0xb9, 0x71, 0xe6, 0x89, 0xec, 0x1f, 0x40, 0x97, 0xf7, 0x1b, 0x15, 0x86, 0x8a, 0xaf, 0xf2, 0xd9, + 0xbb, 0xab, 0x6f, 0x34, 0xbe, 0xff, 0x49, 0xbf, 0x85, 0x8c, 0x0c, 0x05, 0xc1, 0x1f, 0x50, 0x10, 0x7c, 0x8d, 0x27, + 0x7f, 0x80, 0x50, 0xf2, 0xf9, 0x01, 0x41, 0x50, 0xd7, 0x58, 0xe4, 0x93, 0xd6, 0x6f, 0xbe, 0x0c, 0xb3, 0x60, 0xe1, + 0x25, 0xd9, 0x01, 0x34, 0xb5, 0x00, 0xc9, 0xe9, 0x9b, 0x3c, 0x98, 0x49, 0x71, 0x28, 0x84, 0x6a, 0x59, 0x24, 0x34, + 0x87, 0x93, 0x20, 0x94, 0x8a, 0x43, 0xf1, 0x01, 0xcf, 0xf7, 0xd9, 0x22, 0x1b, 0xe8, 0xde, 0x02, 0x92, 0x21, 0x60, + 0x78, 0xe3, 0x83, 0xd8, 0xcf, 0x58, 0x66, 0xa5, 0x59, 0xc2, 0xbc, 0xb9, 0x2e, 0x43, 0x7d, 0xd6, 0xfb, 0x4b, 0x97, + 0xa3, 0x79, 0x90, 0xc9, 0x60, 0x79, 0x34, 0x41, 0x50, 0xe1, 0xc1, 0x10, 0xcf, 0x86, 0x39, 0x07, 0xe1, 0x65, 0x3c, + 0xad, 0xec, 0xa8, 0x82, 0x72, 0x39, 0xc7, 0x48, 0xac, 0x3c, 0x00, 0xfe, 0x18, 0x3d, 0x72, 0x6e, 0xb9, 0xd7, 0xb5, + 0x8c, 0xe9, 0xa7, 0x9f, 0x9d, 0x72, 0xf6, 0x56, 0xc3, 0x40, 0x01, 0x7a, 0xd7, 0x81, 0x58, 0xb3, 0x9b, 0xfc, 0xb1, + 0x0f, 0x78, 0x65, 0xb8, 0x9a, 0xa8, 0x67, 0x0c, 0xfb, 0x4d, 0x63, 0xb9, 0x02, 0x42, 0xa8, 0xa4, 0xe2, 0x9d, 0xb9, + 0x67, 0xd2, 0x01, 0x08, 0x47, 0x85, 0xb4, 0xd2, 0x6f, 0xbf, 0xbd, 0x1e, 0xfe, 0xe7, 0x77, 0x88, 0x4d, 0x3e, 0x73, + 0x85, 0x17, 0xf4, 0xb5, 0x5a, 0x8b, 0x53, 0x9f, 0xe6, 0x10, 0xd5, 0xfb, 0x6c, 0x2c, 0xc2, 0x82, 0x88, 0xad, 0x95, + 0x0f, 0x6f, 0x44, 0xa8, 0x27, 0xc8, 0x3f, 0x60, 0x08, 0x5f, 0xed, 0x21, 0x2c, 0xef, 0x50, 0x84, 0x08, 0xd0, 0x7e, + 0x59, 0x7d, 0x7b, 0x0c, 0xb9, 0x74, 0x6b, 0x69, 0x01, 0x94, 0x01, 0xe2, 0x1e, 0x3a, 0x3b, 0xf5, 0xb8, 0xf0, 0x15, + 0xc8, 0x8f, 0xb4, 0x77, 0x00, 0xd3, 0x9c, 0xc5, 0x73, 0x66, 0x07, 0xf1, 0xc1, 0x3d, 0x1b, 0x59, 0xde, 0x22, 0x20, + 0xf9, 0x32, 0xca, 0xdd, 0x34, 0xa2, 0xfc, 0xa4, 0x82, 0x96, 0xe8, 0xeb, 0xbc, 0x00, 0x65, 0x5c, 0x00, 0x0a, 0x7e, + 0x7a, 0x67, 0xe5, 0x00, 0x7e, 0xb6, 0x08, 0x18, 0x5f, 0xc6, 0xf2, 0xe7, 0x14, 0x87, 0x4f, 0x84, 0xdc, 0x2b, 0x1e, + 0xac, 0x78, 0x32, 0x51, 0x83, 0xee, 0xd9, 0xe5, 0xef, 0x4b, 0xa8, 0x14, 0x7b, 0x36, 0x5e, 0xd0, 0x97, 0xea, 0x9f, + 0x90, 0x3f, 0x21, 0xa7, 0x2d, 0x8f, 0xcf, 0x08, 0xe7, 0xb9, 0x16, 0xbc, 0x4f, 0x82, 0xe4, 0x29, 0x55, 0xe2, 0x88, + 0xa2, 0x1a, 0x18, 0x7a, 0x03, 0x69, 0xf2, 0x64, 0x30, 0x20, 0x3c, 0x56, 0x45, 0x67, 0x00, 0xa5, 0x86, 0xe0, 0xf9, + 0x30, 0xd9, 0x0c, 0x1a, 0x5a, 0xe4, 0xc1, 0x85, 0x8d, 0xaa, 0xd3, 0xa9, 0x8f, 0xf1, 0xc0, 0x13, 0xfb, 0xab, 0xb4, + 0x03, 0x61, 0x67, 0xf1, 0x85, 0x05, 0x04, 0x2e, 0xfa, 0xa9, 0xe0, 0x71, 0xed, 0x6b, 0x42, 0xd9, 0x56, 0xe8, 0x3d, + 0xc4, 0x8a, 0x66, 0x9d, 0x3b, 0xd9, 0x5f, 0x62, 0xe9, 0x95, 0x70, 0x6e, 0xab, 0x9d, 0x24, 0x19, 0x80, 0xbc, 0x7e, + 0x9a, 0xd4, 0x88, 0xe1, 0xbb, 0x0e, 0x93, 0x5a, 0xb7, 0x3c, 0x19, 0xc4, 0x8e, 0x79, 0x71, 0xd0, 0x4a, 0x2f, 0xf1, + 0xdc, 0xe7, 0xa7, 0x07, 0x30, 0x3f, 0x08, 0x0c, 0x50, 0xa2, 0x8c, 0x02, 0x03, 0xa2, 0x0f, 0x78, 0x29, 0x59, 0x07, + 0x5c, 0x8c, 0x05, 0x51, 0x87, 0x9c, 0xa3, 0x8c, 0x0e, 0x5a, 0xaa, 0x52, 0x27, 0x56, 0x9c, 0x66, 0x2a, 0x6f, 0x77, + 0xc0, 0xfe, 0x5f, 0x97, 0x18, 0xad, 0x3f, 0xef, 0x67, 0x4c, 0xf8, 0xdd, 0x5e, 0x66, 0x1b, 0x5c, 0x73, 0x37, 0x55, + 0x21, 0x82, 0x75, 0x4b, 0x85, 0x62, 0x1f, 0x6f, 0xab, 0x55, 0x90, 0x46, 0xb2, 0xda, 0xc2, 0x6b, 0xe9, 0x4f, 0x71, + 0xc7, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0xbb, 0xcc, 0x06, 0x50, 0x55, 0x08, 0xdb, 0xbd, 0xc5, 0x82, 0x2a, 0x1b, 0xfd, + 0xd3, 0x03, 0xe2, 0x3b, 0xcf, 0x68, 0x87, 0x9d, 0x9d, 0x82, 0x75, 0x21, 0x2d, 0xba, 0xb7, 0x58, 0xf0, 0x25, 0xa5, + 0x5f, 0xf4, 0xe6, 0x60, 0x96, 0xcd, 0xc3, 0xb3, 0xff, 0x03, 0x30, 0x11, 0x13, 0xf1, 0xb7, 0x59, 0x03, 0x00}; } // namespace web_server } // namespace esphome + #endif #endif From 05fbb260eea1d0f873e095aa10efdcdd8eb1e0dd Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Tue, 30 Apr 2024 00:09:35 +0200 Subject: [PATCH 1652/2607] [nextion] Exit reparse before update TFT (#6589) --- esphome/components/nextion/nextion.h | 6 +++++- esphome/components/nextion/nextion_upload_arduino.cpp | 11 ++++++++++- esphome/components/nextion/nextion_upload_idf.cpp | 11 ++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index a8f0ea8ba9..833db675fc 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -993,9 +993,13 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe /** * Upload the tft file and soft reset Nextion + * @param exit_reparse If true, the function exits reparse mode before uploading the TFT file. This parameter + * defaults to true, ensuring that the display is ready to receive and apply the new TFT file without needing + * to manually reset or reconfigure. Exiting reparse mode is recommended for most upload scenarios to ensure + * the display properly processes the uploaded file command. * @return bool True: Transfer completed successfuly, False: Transfer failed. */ - bool upload_tft(); + bool upload_tft(bool exit_reparse = true); void dump_config() override; diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index e3d0903d09..4f8df67006 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -141,8 +141,9 @@ int Nextion::upload_by_chunks_(HTTPClient *http, int range_start) { return range_end + 1; } -bool Nextion::upload_tft() { +bool Nextion::upload_tft(bool exit_reparse) { ESP_LOGD(TAG, "Nextion TFT upload requested"); + ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); if (this->is_updating_) { @@ -157,6 +158,14 @@ bool Nextion::upload_tft() { this->is_updating_ = true; + if (exit_reparse) { + ESP_LOGD(TAG, "Exiting Nextion reparse mode"); + if (!this->set_protocol_reparse_mode(false)) { + ESP_LOGW(TAG, "Failed to request Nextion to exit reparse mode"); + return false; + } + } + HTTPClient http; http.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along bool begin_status = false; diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index 14b1b6cfaf..d08f970551 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -160,8 +160,9 @@ int Nextion::upload_range(const std::string &url, int range_start) { return range_end + 1; } -bool Nextion::upload_tft() { +bool Nextion::upload_tft(bool exit_reparse) { ESP_LOGD(TAG, "Nextion TFT upload requested"); + ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str()); if (this->is_updating_) { @@ -176,6 +177,14 @@ bool Nextion::upload_tft() { this->is_updating_ = true; + if (exit_reparse) { + ESP_LOGD(TAG, "Exiting Nextion reparse mode"); + if (!this->set_protocol_reparse_mode(false)) { + ESP_LOGW(TAG, "Failed to request Nextion to exit reparse mode"); + return false; + } + } + // Define the configuration for the HTTP client ESP_LOGV(TAG, "Establishing connection to HTTP server"); ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); From 33e9881830fa13b53c8a4314c91c9817747cdab1 Mon Sep 17 00:00:00 2001 From: mrtoy-me <118446898+mrtoy-me@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:16:55 +1000 Subject: [PATCH 1653/2607] Fix SHT3xd fails sometimes in 2024.4.0 (#6592) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sht3xd/sht3xd.cpp | 34 +++++++++++++++++++++++----- esphome/components/sht3xd/sht3xd.h | 7 ++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/esphome/components/sht3xd/sht3xd.cpp b/esphome/components/sht3xd/sht3xd.cpp index 888e954c6b..ffaf5db322 100644 --- a/esphome/components/sht3xd/sht3xd.cpp +++ b/esphome/components/sht3xd/sht3xd.cpp @@ -6,9 +6,14 @@ namespace sht3xd { static const char *const TAG = "sht3xd"; -// use read serial number register with clock stretching disabled as per other SHT3XD_COMMAND registers -// which provides support for SHT85 sensor -// SHT85 does not support clock stretching and uses same registers as SHT3xd with clock stretching disabled +// https://sensirion.com/media/documents/E5762713/63D103C2/Sensirion_electronic_identification_code_SHT3x.pdf +// indicates two possible read serial number registers either with clock stretching enabled or disabled. +// Other SHT3XD_COMMAND registers use the clock stretching disabled register. +// To ensure compatibility, reading serial number using the register with clock stretching register enabled +// (used originally in this component) is tried first and if that fails the alternate register address +// with clock stretching disabled is read. + +static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER_CLOCK_STRETCHING = 0x3780; static const uint16_t SHT3XD_COMMAND_READ_SERIAL_NUMBER = 0x3682; static const uint16_t SHT3XD_COMMAND_READ_STATUS = 0xF32D; @@ -22,13 +27,19 @@ static const uint16_t SHT3XD_COMMAND_FETCH_DATA = 0xE000; void SHT3XDComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SHT3xD..."); uint16_t raw_serial_number[2]; - if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER, raw_serial_number, 2)) { - this->mark_failed(); - return; + if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER_CLOCK_STRETCHING, raw_serial_number, 2)) { + this->error_code_ = READ_SERIAL_STRETCHED_FAILED; + if (!this->get_register(SHT3XD_COMMAND_READ_SERIAL_NUMBER, raw_serial_number, 2)) { + this->error_code_ = READ_SERIAL_FAILED; + this->mark_failed(); + return; + } } + this->serial_number_ = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); if (!this->write_command(heater_enabled_ ? SHT3XD_COMMAND_HEATER_ENABLE : SHT3XD_COMMAND_HEATER_DISABLE)) { + this->error_code_ = WRITE_HEATER_MODE_FAILED; this->mark_failed(); return; } @@ -36,10 +47,21 @@ void SHT3XDComponent::setup() { void SHT3XDComponent::dump_config() { ESP_LOGCONFIG(TAG, "SHT3xD:"); + switch (this->error_code_) { + case READ_SERIAL_FAILED: + ESP_LOGD(TAG, " Error reading serial number"); + break; + case WRITE_HEATER_MODE_FAILED: + ESP_LOGD(TAG, " Error writing heater mode"); + break; + default: + break; + } if (this->is_failed()) { ESP_LOGE(TAG, " Communication with SHT3xD failed!"); return; } + ESP_LOGD(TAG, " Setup successful"); ESP_LOGD(TAG, " Serial Number: 0x%08" PRIX32, this->serial_number_); ESP_LOGD(TAG, " Heater Enabled: %s", this->heater_enabled_ ? "true" : "false"); diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h index d1a3360e69..74f155121b 100644 --- a/esphome/components/sht3xd/sht3xd.h +++ b/esphome/components/sht3xd/sht3xd.h @@ -22,6 +22,13 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir void set_heater_enabled(bool heater_enabled) { heater_enabled_ = heater_enabled; } protected: + enum ErrorCode { + NONE = 0, + READ_SERIAL_STRETCHED_FAILED, + READ_SERIAL_FAILED, + WRITE_HEATER_MODE_FAILED, + } error_code_{NONE}; + sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr}; bool heater_enabled_{true}; From 5838af646b5523ab51721f09306a5242a475115d Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 22 Apr 2024 23:43:11 -0700 Subject: [PATCH 1654/2607] allow defaults with no include vars (#6613) --- esphome/yaml_util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index c7aa78201f..06bfd8b217 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -321,8 +321,9 @@ class ESPHomeLoaderMixin: file, vars = node.value, None result = _load_yaml_internal(self._rel_path(file)) - if vars: - result = substitute_vars(result, vars) + if not vars: + vars = {} + result = substitute_vars(result, vars) return result @_add_data_ref From 9832fa4d76f75acb679360c2215eba0921e871e6 Mon Sep 17 00:00:00 2001 From: tronikos Date: Sat, 27 Apr 2024 18:22:41 -0700 Subject: [PATCH 1655/2607] Revert #6458 (#6650) Reading the z-axis register is required. --- esphome/components/qmc5883l/qmc5883l.cpp | 46 ++++++++---------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 4946ad1b77..8541b41ff7 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -77,8 +77,17 @@ void QMC5883LComponent::dump_config() { float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } void QMC5883LComponent::update() { uint8_t status = false; - if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG) - this->read_byte(QMC5883L_REGISTER_STATUS, &status); + this->read_byte(QMC5883L_REGISTER_STATUS, &status); + + // Always request X,Y,Z regardless if there are sensors for them + // to avoid https://github.com/esphome/issues/issues/5731 + uint16_t raw_x, raw_y, raw_z; + if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x) || + !this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y) || + !this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { + this->status_set_warning(); + return; + } float mg_per_bit; switch (this->range_) { @@ -93,36 +102,11 @@ void QMC5883LComponent::update() { } // in µT - float x = NAN, y = NAN, z = NAN; - if (this->x_sensor_ != nullptr || this->heading_sensor_ != nullptr) { - uint16_t raw_x; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x)) { - this->status_set_warning(); - return; - } - x = int16_t(raw_x) * mg_per_bit * 0.1f; - } - if (this->y_sensor_ != nullptr || this->heading_sensor_ != nullptr) { - uint16_t raw_y; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y)) { - this->status_set_warning(); - return; - } - y = int16_t(raw_y) * mg_per_bit * 0.1f; - } - if (this->z_sensor_ != nullptr) { - uint16_t raw_z; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { - this->status_set_warning(); - return; - } - z = int16_t(raw_z) * mg_per_bit * 0.1f; - } + const float x = int16_t(raw_x) * mg_per_bit * 0.1f; + const float y = int16_t(raw_y) * mg_per_bit * 0.1f; + const float z = int16_t(raw_z) * mg_per_bit * 0.1f; - float heading = NAN; - if (this->heading_sensor_ != nullptr) { - heading = atan2f(0.0f - x, y) * 180.0f / M_PI; - } + float heading = atan2f(0.0f - x, y) * 180.0f / M_PI; float temp = NAN; if (this->temperature_sensor_ != nullptr) { From 4936cbec0d8428ebab0f939c83863d4810848d20 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:10:12 +1200 Subject: [PATCH 1656/2607] [i2s_audio.microphone] Fixing adc bug (#6654) --- .../microphone/i2s_audio_microphone.cpp | 65 +++++++++++++++++-- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 602d537bcb..1475df0975 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -61,28 +61,57 @@ void I2SAudioMicrophone::start_() { .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; + esp_err_t err; + #if SOC_I2S_SUPPORTS_ADC if (this->adc_) { config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN); - i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + + err = i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error setting ADC mode: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + err = i2s_adc_enable(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error enabling ADC: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } - i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); - i2s_adc_enable(this->parent_->get_port()); } else #endif { if (this->pdm_) config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM); - i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } i2s_pin_config_t pin_config = this->parent_->get_pin_config(); pin_config.data_in_num = this->din_pin_; - i2s_set_pin(this->parent_->get_port(), &pin_config); + err = i2s_set_pin(this->parent_->get_port(), &pin_config); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error setting I2S pin: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } } this->state_ = microphone::STATE_RUNNING; this->high_freq_.start(); + this->status_clear_error(); } void I2SAudioMicrophone::stop() { @@ -96,11 +125,33 @@ void I2SAudioMicrophone::stop() { } void I2SAudioMicrophone::stop_() { - i2s_stop(this->parent_->get_port()); - i2s_driver_uninstall(this->parent_->get_port()); + esp_err_t err; +#if SOC_I2S_SUPPORTS_ADC + if (this->adc_) { + err = i2s_adc_disable(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + } +#endif + err = i2s_stop(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error stopping I2S microphone: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } + err = i2s_driver_uninstall(this->parent_->get_port()); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Error uninstalling I2S driver: %s", esp_err_to_name(err)); + this->status_set_error(); + return; + } this->parent_->unlock(); this->state_ = microphone::STATE_STOPPED; this->high_freq_.stop(); + this->status_clear_error(); } size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { From 516971a255407aac9878ad4e790621126858d5fd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:47:40 +1200 Subject: [PATCH 1657/2607] Bump version to 2024.4.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 69949dc086..f11345527e 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.4.1" +__version__ = "2024.4.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 74fd52e05fdc6f63ef64ada77f8a7b8d63de8c45 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:29:57 +0200 Subject: [PATCH 1658/2607] [nextion] Set alternative TFT update baud rate (#6587) --- esphome/components/nextion/nextion.h | 16 +++++++++-- .../nextion/nextion_upload_arduino.cpp | 27 +++++++++++++++++-- .../components/nextion/nextion_upload_idf.cpp | 27 +++++++++++++++++-- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 833db675fc..b6a6204cd4 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -992,14 +992,26 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe #endif /** - * Upload the tft file and soft reset Nextion + * @brief Uploads the TFT file to the Nextion display. + * + * This function initiates the upload of a TFT file to the Nextion display. Users can specify a target baud rate for + * the transfer. If the provided baud rate is not supported by Nextion, the function defaults to using the current + * baud rate set for the display. If no baud rate is specified (or if 0 is passed), the current baud rate is used. + * + * Supported baud rates are: 2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200, 230400, 250000, 256000, 512000 + * and 921600. Selecting a baud rate supported by both the Nextion display and the host hardware is essential for + * ensuring a successful upload process. + * + * @param baud_rate The desired baud rate for the TFT file transfer, specified as an unsigned 32-bit integer. + * If the specified baud rate is not supported, or if 0 is passed, the function will use the current baud rate. + * The default value is 0, which implies using the current baud rate. * @param exit_reparse If true, the function exits reparse mode before uploading the TFT file. This parameter * defaults to true, ensuring that the display is ready to receive and apply the new TFT file without needing * to manually reset or reconfigure. Exiting reparse mode is recommended for most upload scenarios to ensure * the display properly processes the uploaded file command. * @return bool True: Transfer completed successfuly, False: Transfer failed. */ - bool upload_tft(bool exit_reparse = true); + bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true); void dump_config() override; diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index 4f8df67006..6e7c8b9563 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -141,7 +141,7 @@ int Nextion::upload_by_chunks_(HTTPClient *http, int range_start) { return range_end + 1; } -bool Nextion::upload_tft(bool exit_reparse) { +bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Nextion TFT upload requested"); ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); @@ -166,6 +166,15 @@ bool Nextion::upload_tft(bool exit_reparse) { } } + // Check if baud rate is supported + this->original_baud_rate_ = this->parent_->get_baud_rate(); + static const std::vector SUPPORTED_BAUD_RATES = {2400, 4800, 9600, 19200, 31250, 38400, 57600, + 115200, 230400, 250000, 256000, 512000, 921600}; + if (std::find(SUPPORTED_BAUD_RATES.begin(), SUPPORTED_BAUD_RATES.end(), baud_rate) == SUPPORTED_BAUD_RATES.end()) { + baud_rate = this->original_baud_rate_; + } + ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); + HTTPClient http; http.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along bool begin_status = false; @@ -244,7 +253,7 @@ bool Nextion::upload_tft(bool exit_reparse) { // Tells the Nextion the content length of the tft file and baud rate it will be sent at // Once the Nextion accepts the command it will wait until the file is successfully uploaded // If it fails for any reason a power cycle of the display will be needed - sprintf(command, "whmi-wris %d,%d,1", this->content_length_, this->parent_->get_baud_rate()); + sprintf(command, "whmi-wris %d,%d,1", this->content_length_, baud_rate); // Clear serial receive buffer uint8_t d; @@ -254,6 +263,12 @@ bool Nextion::upload_tft(bool exit_reparse) { this->send_command_(command); + if (baud_rate != this->original_baud_rate_) { + ESP_LOGD(TAG, "Changing baud rate from %" PRIu32 " to %" PRIu32 " bps", this->original_baud_rate_, baud_rate); + this->parent_->set_baud_rate(baud_rate); + this->parent_->load_settings(); + } + App.feed_wdt(); std::string response; @@ -335,6 +350,14 @@ bool Nextion::upload_tft(bool exit_reparse) { bool Nextion::upload_end_(bool successful) { this->is_updating_ = false; + + uint32_t baud_rate = this->parent_->get_baud_rate(); + if (baud_rate != this->original_baud_rate_) { + ESP_LOGD(TAG, "Changing baud rate back from %" PRIu32 " to %" PRIu32 " bps", baud_rate, this->original_baud_rate_); + this->parent_->set_baud_rate(this->original_baud_rate_); + this->parent_->load_settings(); + } + ESP_LOGD(TAG, "Restarting Nextion"); this->soft_reset(); if (successful) { diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index d08f970551..163b497d3b 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -160,7 +160,7 @@ int Nextion::upload_range(const std::string &url, int range_start) { return range_end + 1; } -bool Nextion::upload_tft(bool exit_reparse) { +bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Nextion TFT upload requested"); ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str()); @@ -185,6 +185,15 @@ bool Nextion::upload_tft(bool exit_reparse) { } } + // Check if baud rate is supported + this->original_baud_rate_ = this->parent_->get_baud_rate(); + static const std::vector SUPPORTED_BAUD_RATES = {2400, 4800, 9600, 19200, 31250, 38400, 57600, + 115200, 230400, 250000, 256000, 512000, 921600}; + if (std::find(SUPPORTED_BAUD_RATES.begin(), SUPPORTED_BAUD_RATES.end(), baud_rate) == SUPPORTED_BAUD_RATES.end()) { + baud_rate = this->original_baud_rate_; + } + ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); + // Define the configuration for the HTTP client ESP_LOGV(TAG, "Establishing connection to HTTP server"); ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); @@ -254,7 +263,7 @@ bool Nextion::upload_tft(bool exit_reparse) { // Tells the Nextion the content length of the tft file and baud rate it will be sent at // Once the Nextion accepts the command it will wait until the file is successfully uploaded // If it fails for any reason a power cycle of the display will be needed - sprintf(command, "whmi-wris %d,%" PRIu32 ",1", this->content_length_, this->parent_->get_baud_rate()); + sprintf(command, "whmi-wris %d,%" PRIu32 ",1", this->content_length_, baud_rate); // Clear serial receive buffer ESP_LOGV(TAG, "Clear serial receive buffer"); @@ -268,6 +277,12 @@ bool Nextion::upload_tft(bool exit_reparse) { ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); this->send_command_(command); + if (baud_rate != this->original_baud_rate_) { + ESP_LOGD(TAG, "Changing baud rate from %" PRIu32 " to %" PRIu32 " bps", this->original_baud_rate_, baud_rate); + this->parent_->set_baud_rate(baud_rate); + this->parent_->load_settings(); + } + std::string response; ESP_LOGV(TAG, "Waiting for upgrade response"); this->recv_ret_string_(response, 5000, true); // This can take some time to return @@ -308,6 +323,14 @@ bool Nextion::upload_tft(bool exit_reparse) { bool Nextion::upload_end(bool successful) { this->is_updating_ = false; + + uint32_t baud_rate = this->parent_->get_baud_rate(); + if (baud_rate != this->original_baud_rate_) { + ESP_LOGD(TAG, "Changing baud rate back from %" PRIu32 " to %" PRIu32 " bps", baud_rate, this->original_baud_rate_); + this->parent_->set_baud_rate(this->original_baud_rate_); + this->parent_->load_settings(); + } + ESP_LOGD(TAG, "Restarting Nextion"); this->soft_reset(); vTaskDelay(pdMS_TO_TICKS(1500)); // NOLINT From 6fe328ef2bb9d50efe612d2176df8f562b8bd1a5 Mon Sep 17 00:00:00 2001 From: Anton Sergunov Date: Tue, 30 Apr 2024 16:35:41 +0600 Subject: [PATCH 1659/2607] [TM1637] Let turn off the display (#6656) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/tm1637/tm1637.cpp | 2 +- esphome/components/tm1637/tm1637.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 8d7630bd1d..2f2d4b707a 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -225,7 +225,7 @@ void TM1637Display::display() { // Write display CTRL CMND + brightness this->start_(); - this->send_byte_(TM1637_CMD_CTRL + ((this->intensity_ & 0x7) | 0x08)); + this->send_byte_(TM1637_CMD_CTRL + ((this->intensity_ & 0x7) | (this->on_ ? 0x08 : 0x00))); this->stop_(); } bool TM1637Display::send_byte_(uint8_t b) { diff --git a/esphome/components/tm1637/tm1637.h b/esphome/components/tm1637/tm1637.h index aba0071b12..d44680c623 100644 --- a/esphome/components/tm1637/tm1637.h +++ b/esphome/components/tm1637/tm1637.h @@ -49,6 +49,7 @@ class TM1637Display : public PollingComponent { void set_intensity(uint8_t intensity) { this->intensity_ = intensity; } void set_inverted(bool inverted) { this->inverted_ = inverted; } void set_length(uint8_t length) { this->length_ = length; } + void set_on(bool on) { this->on_ = on; } void display(); @@ -76,6 +77,7 @@ class TM1637Display : public PollingComponent { uint8_t intensity_; uint8_t length_; bool inverted_; + bool on_{true}; optional writer_{}; uint8_t buffer_[6] = {0}; #ifdef USE_BINARY_SENSOR From c299dff124937f4a2253956f72bac77f6c4c79ee Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Tue, 30 Apr 2024 23:43:49 +0200 Subject: [PATCH 1660/2607] [nextion] Use persistent http connection for TFT upload (Arduino) (#6582) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/nextion/nextion.h | 40 +- .../nextion/nextion_upload_arduino.cpp | 397 +++++++++--------- 2 files changed, 213 insertions(+), 224 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index b6a6204cd4..7938af0ea5 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -976,6 +976,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return Whether the send was successful. */ bool send_command(const char *command); + /** * Manually send a raw formatted command to the display. * @param format The printf-style command format, like "vis %s,0" @@ -989,7 +990,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Set the tft file URL. https seems problematic with arduino.. */ void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } -#endif /** * @brief Uploads the TFT file to the Nextion display. @@ -1013,6 +1013,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true); +#endif + void dump_config() override; /** @@ -1134,6 +1136,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void all_components_send_state_(bool force_update = false); uint64_t comok_sent_ = 0; bool remove_from_q_(bool report_empty = true); + /** * @brief * Sends commands ignoring of the Nextion has been setup. @@ -1175,20 +1178,16 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe void check_pending_waveform_(); #ifdef USE_NEXTION_TFT_UPLOAD - uint32_t content_length_ = 0; - int tft_size_ = 0; - uint32_t original_baud_rate_ = 0; - bool upload_first_chunk_sent_ = false; - - std::string tft_url_; - uint8_t *transfer_buffer_{nullptr}; - size_t transfer_buffer_size_; - #ifdef USE_ESP8266 WiFiClient *wifi_client_{nullptr}; BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr}; WiFiClient *get_wifi_client_(); #endif + std::string tft_url_; + uint32_t content_length_ = 0; + int tft_size_ = 0; + uint32_t original_baud_rate_ = 0; + bool upload_first_chunk_sent_ = false; #ifdef ARDUINO /** @@ -1198,18 +1197,8 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @param int range_start Position of next byte to transfer. * @return position of last byte transferred, -1 for failure. */ - int upload_by_chunks_(HTTPClient *http, int range_start); + int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start); - bool upload_with_range_(uint32_t range_start, uint32_t range_end); - - /** - * start update tft file to nextion. - * - * @param const uint8_t *file_buf - * @param size_t buf_size - * @return true if success, false for failure. - */ - bool upload_from_buffer_(const uint8_t *file_buf, size_t buf_size); /** * Ends the upload process, restart Nextion and, if successful, * restarts ESP @@ -1217,6 +1206,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return bool True: Transfer completed successfuly, False: Transfer failed. */ bool upload_end_(bool successful); + #elif defined(USE_ESP_IDF) /** * will request 4096 bytes chunks from the web server @@ -1226,6 +1216,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return position of last byte transferred, -1 for failure. */ int upload_range(const std::string &url, int range_start); + /** * Ends the upload process, restart Nextion and, if successful, * restarts ESP @@ -1233,7 +1224,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return bool True: Transfer completed successfuly, False: Transfer failed. */ bool upload_end(bool successful); -#endif // ARDUINO vs ESP-IDF +#endif // ARDUINO vs USE_ESP_IDF + /** + * Returns the ESP Free Heap memory. This is framework independent. + * @return Free Heap in bytes. + */ + uint32_t get_free_heap_(); #endif // USE_NEXTION_TFT_UPLOAD diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index 6e7c8b9563..b199db91b7 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -1,13 +1,14 @@ #include "nextion.h" -#ifdef ARDUINO #ifdef USE_NEXTION_TFT_UPLOAD +#ifdef ARDUINO #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/util.h" #include "esphome/core/log.h" #include "esphome/components/network/util.h" +#include #ifdef USE_ESP32 #include @@ -20,124 +21,132 @@ static const char *const TAG = "nextion.upload.arduino"; // Followed guide // https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2 -int Nextion::upload_by_chunks_(HTTPClient *http, int range_start) { - int range_end = 0; +inline uint32_t Nextion::get_free_heap_() { +#if defined(USE_ESP32) + return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +#elif defined(USE_ESP8266) + return EspClass::getFreeHeap(); +#endif // USE_ESP32 vs USE_ESP8266 +} - if (range_start == 0 && this->transfer_buffer_size_ > 16384) { // Start small at the first run in case of a big skip - range_end = 16384 - 1; - } else { - range_end = range_start + this->transfer_buffer_size_ - 1; +int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { + uint32_t range_size = this->tft_size_ - range_start; + ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1; + ESP_LOGD(TAG, "Range start: %" PRIu32, range_start); + if (range_size <= 0 or range_end <= range_start) { + ESP_LOGD(TAG, "Range end: %" PRIu32, range_end); + ESP_LOGD(TAG, "Range size: %" PRIu32, range_size); + ESP_LOGE(TAG, "Invalid range"); + return -1; } - if (range_end > this->tft_size_) - range_end = this->tft_size_; - -#ifdef USE_ESP8266 -#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0) - http->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); -#elif USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0) - http->setFollowRedirects(true); -#endif -#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0) - http->setRedirectLimit(3); -#endif -#endif // USE_ESP8266 - - char range_header[64]; - sprintf(range_header, "bytes=%d-%d", range_start, range_end); - - ESP_LOGD(TAG, "Requesting range: %s", range_header); - - int tries = 1; - int code = 0; - bool begin_status = false; - while (tries <= 5) { -#ifdef USE_ESP32 - begin_status = http->begin(this->tft_url_.c_str()); -#endif -#ifdef USE_ESP8266 - begin_status = http->begin(*this->get_wifi_client_(), this->tft_url_.c_str()); -#endif - - ++tries; - if (!begin_status) { - ESP_LOGD(TAG, "upload_by_chunks_: connection failed"); - delay(500); // NOLINT - continue; - } - - http->addHeader("Range", range_header); - - code = http->GET(); - if (code == 200 || code == 206) { - break; - } - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s, retries(%d/5)", this->tft_url_.c_str(), - HTTPClient::errorToString(code).c_str(), tries); - http->end(); - App.feed_wdt(); - delay(500); // NOLINT + char range_header[32]; + sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end); + ESP_LOGV(TAG, "Requesting range: %s", range_header); + http_client.addHeader("Range", range_header); + int code = http_client.GET(); + if (code != HTTP_CODE_OK and code != HTTP_CODE_PARTIAL_CONTENT) { + ESP_LOGW(TAG, "HTTP Request failed; Error: %s", HTTPClient::errorToString(code).c_str()); + return -1; } - if (tries > 5) { + // Allocate the buffer dynamically + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + uint8_t *buffer = allocator.allocate(4096); + if (!buffer) { + ESP_LOGE(TAG, "Failed to allocate upload buffer"); return -1; } std::string recv_string; - size_t size = 0; - int fetched = 0; - int range = range_end - range_start; - - while (fetched < range) { - size = http->getStreamPtr()->available(); - if (!size) { - App.feed_wdt(); - delay(0); - continue; - } - int c = http->getStreamPtr()->readBytes( - &this->transfer_buffer_[fetched], ((size > this->transfer_buffer_size_) ? this->transfer_buffer_size_ : size)); - fetched += c; - } - http->end(); - ESP_LOGN(TAG, "Fetched %d of %d bytes", fetched, this->content_length_); - - // upload fetched segments to the display in 4KB chunks - int write_len; - for (int i = 0; i < range; i += 4096) { + while (true) { App.feed_wdt(); - write_len = this->content_length_ < 4096 ? this->content_length_ : 4096; - this->write_array(&this->transfer_buffer_[i], write_len); - this->content_length_ -= write_len; - ESP_LOGD(TAG, "Uploaded %0.2f %%; %d bytes remaining", - 100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_); - - if (!this->upload_first_chunk_sent_) { - this->upload_first_chunk_sent_ = true; - delay(500); // NOLINT - } - - this->recv_ret_string_(recv_string, 4096, true); - if (recv_string[0] != 0x05) { // 0x05 == "ok" - ESP_LOGD(TAG, "recv_string [%s]", - format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); - } - - // handle partial upload request - if (recv_string[0] == 0x08 && recv_string.size() == 5) { - uint32_t result = 0; - for (int j = 0; j < 4; ++j) { - result += static_cast(recv_string[j + 1]) << (8 * j); - } - if (result > 0) { - ESP_LOGD(TAG, "Nextion reported new range %d", result); - this->content_length_ = this->tft_size_ - result; - return result; + const uint16_t buffer_size = + this->content_length_ < 4096 ? this->content_length_ : 4096; // Limits buffer to the remaining data + ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size); + uint16_t read_len = 0; + int partial_read_len = 0; + const uint32_t start_time = millis(); + while (read_len < buffer_size && millis() - start_time < 5000) { + if (http_client.getStreamPtr()->available() > 0) { + partial_read_len = + http_client.getStreamPtr()->readBytes(reinterpret_cast(buffer) + read_len, buffer_size - read_len); + read_len += partial_read_len; + if (partial_read_len > 0) { + App.feed_wdt(); + delay(2); + } } } - recv_string.clear(); + if (read_len != buffer_size) { + // Did not receive the full package within the timeout period + ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len, + buffer_size); + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return -1; + } + ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len); + if (read_len > 0) { + recv_string.clear(); + this->write_array(buffer, buffer_size); + App.feed_wdt(); + this->recv_ret_string_(recv_string, upload_first_chunk_sent_ ? 500 : 5000, true); + this->content_length_ -= read_len; + const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_; +#if defined(USE_ESP32) && defined(USE_PSRAM) + ESP_LOGD( + TAG, + "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes", + upload_percentage, this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), + static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); +#else + ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage, + this->content_length_, this->get_free_heap_()); +#endif + upload_first_chunk_sent_ = true; + if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request + ESP_LOGD(TAG, "recv_string [%s]", + format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); + uint32_t result = 0; + for (int j = 0; j < 4; ++j) { + result += static_cast(recv_string[j + 1]) << (8 * j); + } + if (result > 0) { + ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); + this->content_length_ = this->tft_size_ - result; + range_start = result; + } else { + range_start = range_end + 1; + } + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return range_end + 1; + } else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok" + ESP_LOGE(TAG, "Invalid response from Nextion: [%s]", + format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return -1; + } + + recv_string.clear(); + } else if (read_len == 0) { + ESP_LOGV(TAG, "End of HTTP response reached"); + break; // Exit the loop if there is no more data to read + } else { + ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len); + break; // Exit the loop on error + } } - + range_start = range_end + 1; + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; return range_end + 1; } @@ -147,12 +156,12 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); if (this->is_updating_) { - ESP_LOGD(TAG, "Currently updating"); + ESP_LOGW(TAG, "Currently uploading"); return false; } if (!network::is_connected()) { - ESP_LOGD(TAG, "network is not connected"); + ESP_LOGE(TAG, "Network is not connected"); return false; } @@ -175,43 +184,42 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { } ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); - HTTPClient http; - http.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along + // Define the configuration for the HTTP client + ESP_LOGV(TAG, "Initializing HTTP client"); + ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + HTTPClient http_client; + http_client.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along + bool begin_status = false; #ifdef USE_ESP32 - begin_status = http.begin(this->tft_url_.c_str()); + begin_status = http_client.begin(this->tft_url_.c_str()); #endif #ifdef USE_ESP8266 #if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0) - http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + http_client.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); #elif USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0) - http.setFollowRedirects(true); + http_client.setFollowRedirects(true); #endif #if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0) - http.setRedirectLimit(3); + http_client.setRedirectLimit(3); #endif - begin_status = http.begin(*this->get_wifi_client_(), this->tft_url_.c_str()); -#endif - + begin_status = http_client.begin(*this->get_wifi_client_(), this->tft_url_.c_str()); +#endif // USE_ESP8266 if (!begin_status) { this->is_updating_ = false; ESP_LOGD(TAG, "Connection failed"); - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - allocator.deallocate(this->transfer_buffer_, this->transfer_buffer_size_); return false; } else { ESP_LOGD(TAG, "Connected"); } - - http.addHeader("Range", "bytes=0-255"); + http_client.addHeader("Range", "bytes=0-255"); const char *header_names[] = {"Content-Range"}; - http.collectHeaders(header_names, 1); + http_client.collectHeaders(header_names, 1); ESP_LOGD(TAG, "Requesting URL: %s", this->tft_url_.c_str()); - - http.setReuse(true); + http_client.setReuse(true); // try up to 5 times. DNS sometimes needs a second try or so int tries = 1; - int code = http.GET(); + int code = http_client.GET(); delay(100); // NOLINT App.feed_wdt(); @@ -221,34 +229,41 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { delay(250); // NOLINT App.feed_wdt(); - code = http.GET(); + code = http_client.GET(); ++tries; } - if ((code != 200 && code != 206) || tries > 5) { + if (code != 200 and code != 206) { return this->upload_end_(false); } - String content_range_string = http.header("Content-Range"); + String content_range_string = http_client.header("Content-Range"); content_range_string.remove(0, 12); - this->content_length_ = content_range_string.toInt(); - this->tft_size_ = content_length_; - http.end(); + this->tft_size_ = content_range_string.toInt(); - if (this->content_length_ < 4096) { - ESP_LOGE(TAG, "Failed to get file size"); + ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_); + if (this->tft_size_ < 4096) { + ESP_LOGE(TAG, "File size check failed."); + ESP_LOGD(TAG, "Close HTTP connection"); + http_client.end(); + ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); + } else { + ESP_LOGV(TAG, "File size check passed. Proceeding..."); } + this->content_length_ = this->tft_size_; - ESP_LOGD(TAG, "Updating Nextion %s...", this->device_model_.c_str()); - // The Nextion will ignore the update command if it is sleeping + ESP_LOGD(TAG, "Uploading Nextion"); + // The Nextion will ignore the upload command if it is sleeping + ESP_LOGV(TAG, "Wake-up Nextion"); + this->ignore_is_setup_ = true; this->send_command_("sleep=0"); - this->set_backlight_brightness(1.0); + this->send_command_("dim=100"); delay(250); // NOLINT + ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); App.feed_wdt(); - char command[128]; // Tells the Nextion the content length of the tft file and baud rate it will be sent at // Once the Nextion accepts the command it will wait until the file is successfully uploaded @@ -256,11 +271,12 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { sprintf(command, "whmi-wris %d,%d,1", this->content_length_, baud_rate); // Clear serial receive buffer - uint8_t d; - while (this->available()) { - this->read_byte(&d); - }; + ESP_LOGV(TAG, "Clear serial receive buffer"); + this->reset_(false); + delay(250); // NOLINT + ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Send upload instruction: %s", command); this->send_command_(command); if (baud_rate != this->original_baud_rate_) { @@ -272,84 +288,60 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { App.feed_wdt(); std::string response; - ESP_LOGD(TAG, "Waiting for upgrade response"); - this->recv_ret_string_(response, 2000, true); // This can take some time to return + ESP_LOGV(TAG, "Waiting for upgrade response"); + this->recv_ret_string_(response, 5000, true); // This can take some time to return // The Nextion display will, if it's ready to accept data, send a 0x05 byte. - ESP_LOGD(TAG, "Upgrade response is [%s] - %zu bytes", + ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)", format_hex_pretty(reinterpret_cast(response.data()), response.size()).c_str(), response.length()); - - for (size_t i = 0; i < response.length(); i++) { - ESP_LOGD(TAG, "Available %d : 0x%02X", i, response[i]); - } + ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); if (response.find(0x05) != std::string::npos) { - ESP_LOGD(TAG, "preparation for tft update done"); + ESP_LOGV(TAG, "Preparation for TFT upload done"); } else { - ESP_LOGD(TAG, "preparation for tft update failed %d \"%s\"", response[0], response.c_str()); + ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str()); + ESP_LOGD(TAG, "Close HTTP connection"); + http_client.end(); + ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } - // Nextion wants 4096 bytes at a time. Make chunk_size a multiple of 4096 -#ifdef USE_ESP32 - uint32_t chunk_size = 8192; - if (heap_caps_get_free_size(MALLOC_CAP_SPIRAM) > 0) { - chunk_size = this->content_length_; - } else { - if (ESP.getFreeHeap() > 81920) { // Ensure some FreeHeap to other things and limit chunk size - chunk_size = ESP.getFreeHeap() - 65536; - chunk_size = int(chunk_size / 4096) * 4096; - chunk_size = chunk_size > 65536 ? 65536 : chunk_size; - } else if (ESP.getFreeHeap() < 32768) { - chunk_size = 4096; - } - } -#else - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - uint32_t chunk_size = ESP.getFreeHeap() < 16384 ? 4096 : 8192; -#endif + ESP_LOGD(TAG, "Uploading TFT to Nextion:"); + ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, " File size: %d bytes", this->content_length_); + ESP_LOGD(TAG, " Free heap: %" PRIu32, this->get_free_heap_()); - if (this->transfer_buffer_ == nullptr) { - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - ESP_LOGD(TAG, "Allocating buffer size %d, Heap size is %u", chunk_size, ESP.getFreeHeap()); - this->transfer_buffer_ = allocator.allocate(chunk_size); - if (this->transfer_buffer_ == nullptr) { // Try a smaller size - ESP_LOGD(TAG, "Could not allocate buffer size: %d trying 4096 instead", chunk_size); - chunk_size = 4096; - ESP_LOGD(TAG, "Allocating %d buffer", chunk_size); - this->transfer_buffer_ = allocator.allocate(chunk_size); + // Proceed with the content download as before - if (!this->transfer_buffer_) - return this->upload_end_(false); - } + ESP_LOGV(TAG, "Starting transfer by chunks loop"); - this->transfer_buffer_size_ = chunk_size; - } - - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d using %zu chunksize, Heap Size %d", - this->tft_url_.c_str(), this->content_length_, this->transfer_buffer_size_, ESP.getFreeHeap()); - - int result = 0; + uint32_t position = 0; while (this->content_length_ > 0) { - result = this->upload_by_chunks_(&http, result); - if (result < 0) { - ESP_LOGD(TAG, "Error updating Nextion!"); + int upload_result = upload_by_chunks_(http_client, position); + if (upload_result < 0) { + ESP_LOGE(TAG, "Error uploading TFT to Nextion!"); + ESP_LOGD(TAG, "Close HTTP connection"); + http_client.end(); + ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } App.feed_wdt(); - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - ESP_LOGD(TAG, "Heap Size %d, Bytes left %d", ESP.getFreeHeap(), this->content_length_); + ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, this->get_free_heap_(), this->content_length_); } - ESP_LOGD(TAG, "Successfully updated Nextion!"); - return this->upload_end_(true); + ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!"); + + ESP_LOGD(TAG, "Close HTTP connection"); + http_client.end(); + ESP_LOGV(TAG, "Connection closed"); + return upload_end_(true); } bool Nextion::upload_end_(bool successful) { + ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful)); this->is_updating_ = false; + this->ignore_is_setup_ = false; uint32_t baud_rate = this->parent_->get_baud_rate(); if (baud_rate != this->original_baud_rate_) { @@ -358,12 +350,12 @@ bool Nextion::upload_end_(bool successful) { this->parent_->load_settings(); } - ESP_LOGD(TAG, "Restarting Nextion"); - this->soft_reset(); if (successful) { + ESP_LOGD(TAG, "Restarting ESPHome"); delay(1500); // NOLINT - ESP_LOGD(TAG, "Restarting esphome"); - ESP.restart(); // NOLINT(readability-static-accessed-through-instance) + arch_restart(); + } else { + ESP_LOGE(TAG, "Nextion TFT upload failed"); } return successful; } @@ -386,9 +378,10 @@ WiFiClient *Nextion::get_wifi_client_() { } return this->wifi_client_; } -#endif +#endif // USE_ESP8266 + } // namespace nextion } // namespace esphome -#endif // USE_NEXTION_TFT_UPLOAD #endif // ARDUINO +#endif // USE_NEXTION_TFT_UPLOAD From c69cdec0521147ec3d1a594c9c5121cab9710c33 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 30 Apr 2024 23:49:20 -0500 Subject: [PATCH 1661/2607] Extend MQTT tests (#6648) --- esphome/components/mqtt/__init__.py | 7 +- tests/components/mqtt/common.yaml | 428 +++++++++++++++++++ tests/components/mqtt/test.bk72xx.yaml | 2 + tests/components/mqtt/test.esp32-c3-idf.yaml | 18 +- tests/components/mqtt/test.esp32-c3.yaml | 17 +- tests/components/mqtt/test.esp32-idf.yaml | 18 +- tests/components/mqtt/test.esp32.yaml | 17 +- tests/components/mqtt/test.esp8266.yaml | 17 +- 8 files changed, 446 insertions(+), 78 deletions(-) create mode 100644 tests/components/mqtt/common.yaml create mode 100644 tests/components/mqtt/test.bk72xx.yaml diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 064362c619..31cbb2cf97 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -54,7 +54,12 @@ from esphome.components.esp32 import add_idf_sdkconfig_option DEPENDENCIES = ["network"] -AUTO_LOAD = ["json"] + +def AUTO_LOAD(): + if CORE.is_esp8266 or CORE.is_libretiny: + return ["async_tcp", "json"] + return ["json"] + CONF_IDF_SEND_ASYNC = "idf_send_async" CONF_SKIP_CERT_CN_CHECK = "skip_cert_cn_check" diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml new file mode 100644 index 0000000000..a2a751df63 --- /dev/null +++ b/tests/components/mqtt/common.yaml @@ -0,0 +1,428 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + +mqtt: + broker: "192.168.178.84" + port: 1883 + username: debug + password: debug + client_id: someclient + use_abbreviations: false + discovery: true + discovery_retain: false + discovery_prefix: discovery + discovery_unique_id_generator: legacy + topic_prefix: helloworld + log_topic: + topic: helloworld/hi + level: INFO + birth_message: + will_message: + shutdown_message: + topic: topic/to/send/to + payload: hi + qos: 2 + retain: true + keepalive: 60s + reboot_timeout: 60s + on_message: + - topic: my/custom/topic + qos: 0 + then: + - lambda: >- + ESP_LOGD("main", "Got message %s", x.c_str()); + - topic: bedroom/ota_mode + then: + - logger.log: Got bedroom/ota_mode + - topic: livingroom/ota_mode + then: + - logger.log: Got livingroom/ota_mode + on_json_message: + topic: the/topic + then: + - if: + condition: + - wifi.connected: + - mqtt.connected: + then: + - logger.log: on_json_message + on_connect: + - mqtt.publish: + topic: some/topic + payload: Hello + on_disconnect: + - mqtt.publish: + topic: some/topic + payload: Good-bye + +binary_sensor: + - platform: template + id: some_binary_sensor + name: Garage Door Open + state_topic: some/topic/binary_sensor + qos: 2 + lambda: |- + if (id(template_sens).state > 30) { + // Garage Door is open. + return true; + } else { + // Garage Door is closed. + return false; + } + on_state: + - mqtt.publish: + topic: some/topic/binary_sensor + payload: Hello + qos: 2 + retain: true + +button: + - platform: template + name: "Template Button" + state_topic: some/topic/button + qos: 2 + on_press: + - mqtt.publish: + topic: some/topic/button + payload: Hello + qos: 2 + retain: true + +climate: + - platform: thermostat + name: Test Thermostat + sensor: template_sens + humidity_sensor: template_sens + action_state_topic: some/topicaction_state + current_temperature_state_topic: some/topiccurrent_temperature_state + current_humidity_state_topic: some/topiccurrent_humidity_state + fan_mode_state_topic: some/topicfan_mode_state + fan_mode_command_topic: some/topicfan_mode_command + mode_state_topic: some/topicmode_state + mode_command_topic: some/topicmode_command + preset_state_topic: some/topicpreset_state + preset_command_topic: some/topicpreset_command + swing_mode_state_topic: some/topicswing_mode_state + swing_mode_command_topic: some/topicswing_mode_command + target_temperature_state_topic: some/topictarget_temperature_state + target_temperature_command_topic: some/topictarget_temperature_command + target_temperature_high_state_topic: some/topictarget_temperature_high_state + target_temperature_high_command_topic: some/topictarget_temperature_high_command + target_temperature_low_state_topic: some/topictarget_temperature_low_state + target_temperature_low_command_topic: some/topictarget_temperature_low_command + target_humidity_state_topic: some/topictarget_humidity_state + target_humidity_command_topic: some/topictarget_humidity_command + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true + +cover: + - platform: template + name: Template Cover + state_topic: some/topic/cover + qos: 2 + lambda: |- + if (id(some_binary_sensor).state) { + return COVER_OPEN; + } else { + return COVER_CLOSED; + } + open_action: + - logger.log: open_action + close_action: + - logger.log: close_action + stop_action: + - logger.log: stop_action + optimistic: true + +datetime: + - platform: template + name: Date + id: test_date + type: date + state_topic: some/topic/date + qos: 2 + set_action: + - logger.log: "set_value" + on_value: + - logger.log: + format: "Date: %04d-%02d-%02d" + args: + - x.year + - x.month + - x.day_of_month + - platform: template + name: Time + id: test_time + type: time + state_topic: some/topic/time + qos: 2 + set_action: + - logger.log: "set_value" + on_value: + - logger.log: + format: "Time: %02d:%02d:%02d" + args: + - x.hour + - x.minute + - x.second + - platform: template + name: DateTime + id: test_datetime + type: datetime + state_topic: some/topic/datetime + qos: 2 + set_action: + - logger.log: set_value + on_value: + - logger.log: + format: "DateTime: %04d-%02d-%02d %02d:%02d:%02d" + args: + - x.year + - x.month + - x.day_of_month + - x.hour + - x.minute + - x.second + +event: + - platform: template + name: Template Event + state_topic: some/topic/event + qos: 2 + event_types: + - "custom_event_1" + - "custom_event_2" + +fan: + - platform: template + name: Template Fan + state_topic: some/topic/fan + qos: 2 + on_state: + - logger.log: on_state + on_speed_set: + - logger.log: on_speed_set + +light: + - platform: binary + name: Desk Lamp + output: light_output + state_topic: some/topic/light + qos: 2 + +output: + - id: light_output + platform: gpio + pin: 0 + +lock: + - platform: template + name: "Template Lock" + state_topic: some/topic/lock + qos: 2 + lambda: |- + if (id(some_binary_sensor).state) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + lock_action: + - logger.log: lock_action + unlock_action: + - logger.log: unlock_action + open_action: + - logger.log: open_action + +number: + - platform: template + name: "Template number" + state_topic: some/topic/number + qos: 2 + optimistic: true + min_value: 0 + max_value: 100 + step: 1 + +select: + - platform: template + name: "Template select" + state_topic: some/topic/select + qos: 2 + optimistic: true + options: + - one + - two + - three + initial_option: two + +sensor: + - platform: template + name: Template Sensor + id: template_sens + lambda: |- + if (id(some_binary_sensor).state) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + on_value: + - mqtt.publish: + topic: some/topic/sensor + payload: Hello + qos: 2 + retain: true + - platform: mqtt_subscribe + name: MQTT Subscribe Sensor + topic: mqtt/topic + id: the_sensor + qos: 2 + on_value: + - mqtt.publish_json: + topic: the/topic + payload: |- + root["key"] = id(template_sens).state; + root["greeting"] = "Hello World"; + +switch: + - platform: template + name: Template Switch + state_topic: some/topic/switch + qos: 2 + lambda: |- + if (id(some_binary_sensor).state) { + return true; + } else { + return false; + } + turn_on_action: + - logger.log: turn_on_action + turn_off_action: + - logger.log: turn_off_action + +text_sensor: + - platform: template + name: Template Text Sensor + id: tts_text + state_topic: some/topic/text_sensor + qos: 2 + - platform: mqtt_subscribe + name: MQTT Subscribe Text + topic: some/topic/text_sensor + qos: 2 + on_value: + - text_sensor.template.publish: + id: tts_text + state: Hello World + - text_sensor.template.publish: + id: tts_text + state: |- + return "Hello World2"; + +text: + - platform: template + name: Template Text + optimistic: true + min_length: 0 + max_length: 100 + mode: text + state_topic: some/topic/text + qos: 2 + +valve: + - platform: template + name: Template Valve + state_topic: some/topic/valve + qos: 2 + optimistic: true + lambda: |- + if (id(some_binary_sensor).state) { + return VALVE_OPEN; + } else { + return VALVE_CLOSED; + } diff --git a/tests/components/mqtt/test.bk72xx.yaml b/tests/components/mqtt/test.bk72xx.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/mqtt/test.bk72xx.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/mqtt/test.esp32-c3-idf.yaml b/tests/components/mqtt/test.esp32-c3-idf.yaml index 7702ed5610..25cb37a0b4 100644 --- a/tests/components/mqtt/test.esp32-c3-idf.yaml +++ b/tests/components/mqtt/test.esp32-c3-idf.yaml @@ -1,16 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - idf_send_async: false - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - - logger.log: Mqtt Test +packages: + common: !include common.yaml diff --git a/tests/components/mqtt/test.esp32-c3.yaml b/tests/components/mqtt/test.esp32-c3.yaml index 692d504d6d..25cb37a0b4 100644 --- a/tests/components/mqtt/test.esp32-c3.yaml +++ b/tests/components/mqtt/test.esp32-c3.yaml @@ -1,15 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - - logger.log: Mqtt Test +packages: + common: !include common.yaml diff --git a/tests/components/mqtt/test.esp32-idf.yaml b/tests/components/mqtt/test.esp32-idf.yaml index 7702ed5610..25cb37a0b4 100644 --- a/tests/components/mqtt/test.esp32-idf.yaml +++ b/tests/components/mqtt/test.esp32-idf.yaml @@ -1,16 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - idf_send_async: false - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - - logger.log: Mqtt Test +packages: + common: !include common.yaml diff --git a/tests/components/mqtt/test.esp32.yaml b/tests/components/mqtt/test.esp32.yaml index 692d504d6d..25cb37a0b4 100644 --- a/tests/components/mqtt/test.esp32.yaml +++ b/tests/components/mqtt/test.esp32.yaml @@ -1,15 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - - logger.log: Mqtt Test +packages: + common: !include common.yaml diff --git a/tests/components/mqtt/test.esp8266.yaml b/tests/components/mqtt/test.esp8266.yaml index 692d504d6d..25cb37a0b4 100644 --- a/tests/components/mqtt/test.esp8266.yaml +++ b/tests/components/mqtt/test.esp8266.yaml @@ -1,15 +1,2 @@ -wifi: - ssid: MySSID - password: password1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - - logger.log: Mqtt Test +packages: + common: !include common.yaml From 5ddad2647605b28da208029e7959aa12701904bd Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 1 May 2024 14:17:11 -0500 Subject: [PATCH 1662/2607] Extend and consolidate `script` tests (#6663) --- tests/components/script/common.yaml | 55 +++++++++++++++++++ tests/components/script/test.bk72xx.yaml | 1 + .../components/script/test.esp32-c3-idf.yaml | 27 +-------- tests/components/script/test.esp32-c3.yaml | 27 +-------- tests/components/script/test.esp32-idf.yaml | 27 +-------- tests/components/script/test.esp32.yaml | 27 +-------- tests/components/script/test.esp8266.yaml | 27 +-------- tests/components/script/test.rp2040.yaml | 27 +-------- 8 files changed, 62 insertions(+), 156 deletions(-) create mode 100644 tests/components/script/common.yaml create mode 100644 tests/components/script/test.bk72xx.yaml diff --git a/tests/components/script/common.yaml b/tests/components/script/common.yaml new file mode 100644 index 0000000000..bfd5d0e7ff --- /dev/null +++ b/tests/components/script/common.yaml @@ -0,0 +1,55 @@ +esphome: + on_boot: + then: + - script.execute: my_script + - script.execute: + id: my_script_with_params + prefix: "Test" + param2: 0 + param3: true + - script.wait: my_script + - script.stop: my_script + - if: + condition: + - script.is_running: my_script + then: + - logger.log: my_script is running + +script: + - id: my_script + mode: single + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_queued + mode: queued + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_parallel + mode: parallel + max_runs: 2 + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_restart + mode: restart + then: + - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: my_script_with_params + parameters: + prefix: string + param2: uint8_t + param3: bool + then: + - lambda: 'ESP_LOGD(prefix.c_str(), "Hello World! %u %u", param2, param3);' + - if: + condition: + for: + time: !lambda "return param2;" + condition: + script.is_running: my_script + then: + - lambda: 'ESP_LOGD("main", "API has stayed connected for at least %u minutes", param2);' + - repeat: + count: 5 + then: + - logger.log: looping! diff --git a/tests/components/script/test.bk72xx.yaml b/tests/components/script/test.bk72xx.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/script/test.bk72xx.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/script/test.esp32-c3-idf.yaml b/tests/components/script/test.esp32-c3-idf.yaml index 3872c690ff..dade44d145 100644 --- a/tests/components/script/test.esp32-c3-idf.yaml +++ b/tests/components/script/test.esp32-c3-idf.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' +<<: !include common.yaml diff --git a/tests/components/script/test.esp32-c3.yaml b/tests/components/script/test.esp32-c3.yaml index 3872c690ff..dade44d145 100644 --- a/tests/components/script/test.esp32-c3.yaml +++ b/tests/components/script/test.esp32-c3.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' +<<: !include common.yaml diff --git a/tests/components/script/test.esp32-idf.yaml b/tests/components/script/test.esp32-idf.yaml index 3872c690ff..dade44d145 100644 --- a/tests/components/script/test.esp32-idf.yaml +++ b/tests/components/script/test.esp32-idf.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' +<<: !include common.yaml diff --git a/tests/components/script/test.esp32.yaml b/tests/components/script/test.esp32.yaml index 3872c690ff..dade44d145 100644 --- a/tests/components/script/test.esp32.yaml +++ b/tests/components/script/test.esp32.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' +<<: !include common.yaml diff --git a/tests/components/script/test.esp8266.yaml b/tests/components/script/test.esp8266.yaml index ce0e40e7ee..dade44d145 100644 --- a/tests/components/script/test.esp8266.yaml +++ b/tests/components/script/test.esp8266.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD(prefix.c_str(), "Hello World! %i %i", param2, param3);' +<<: !include common.yaml diff --git a/tests/components/script/test.rp2040.yaml b/tests/components/script/test.rp2040.yaml index 3872c690ff..dade44d145 100644 --- a/tests/components/script/test.rp2040.yaml +++ b/tests/components/script/test.rp2040.yaml @@ -1,26 +1 @@ -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' +<<: !include common.yaml From a4a23d73b32b0b485ccfbd8209b787a6785d5dd9 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 2 May 2024 00:05:37 +0200 Subject: [PATCH 1663/2607] [nextion] Use persistent http connection for TFT upload (ESP-IDF) (#6576) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 +- esphome/components/nextion/display.py | 2 +- esphome/components/nextion/nextion.h | 37 +- .../components/nextion/nextion_upload_idf.cpp | 395 +++++++++--------- esphome/core/defines.h | 2 +- 5 files changed, 225 insertions(+), 213 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a60a5c3099..d0e920fe1d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -242,7 +242,7 @@ esphome/components/mpl3115a2/* @kbickar esphome/components/mpu6886/* @fabaff esphome/components/ms8607/* @e28eta esphome/components/network/* @esphome/core -esphome/components/nextion/* @senexcrenshaw +esphome/components/nextion/* @edwardtfn @senexcrenshaw esphome/components/nextion/binary_sensor/* @senexcrenshaw esphome/components/nextion/sensor/* @senexcrenshaw esphome/components/nextion/switch/* @senexcrenshaw diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index 6487c12f36..ce45d25e7b 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -25,7 +25,7 @@ from .base_component import ( CONF_EXIT_REPARSE_ON_START, ) -CODEOWNERS = ["@senexcrenshaw"] +CODEOWNERS = ["@senexcrenshaw", "@edwardtfn"] DEPENDENCIES = ["uart"] AUTO_LOAD = ["binary_sensor", "switch", "sensor", "text_sensor"] diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 7938af0ea5..6435e2b4e2 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -1013,7 +1013,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true); -#endif +#endif // USE_NEXTION_TFT_UPLOAD void dump_config() override; @@ -1142,6 +1142,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * Sends commands ignoring of the Nextion has been setup. */ bool ignore_is_setup_ = false; + bool nextion_reports_is_setup_ = false; uint8_t nextion_event_; @@ -1182,7 +1183,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe WiFiClient *wifi_client_{nullptr}; BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr}; WiFiClient *get_wifi_client_(); -#endif +#endif // USE_ESP8266 std::string tft_url_; uint32_t content_length_ = 0; int tft_size_ = 0; @@ -1193,11 +1194,21 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe /** * will request chunk_size chunks from the web server * and send each to the nextion - * @param HTTPClient http HTTP client handler. + * @param HTTPClient http_client HTTP client handler. * @param int range_start Position of next byte to transfer. * @return position of last byte transferred, -1 for failure. */ int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start); +#elif defined(USE_ESP_IDF) + /** + * will request 4096 bytes chunks from the web server + * and send each to Nextion + * @param esp_http_client_handle_t http_client HTTP client handler. + * @param int range_start Position of next byte to transfer. + * @return position of last byte transferred, -1 for failure. + */ + int upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start); +#endif // ARDUINO vs USE_ESP_IDF /** * Ends the upload process, restart Nextion and, if successful, @@ -1207,24 +1218,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ bool upload_end_(bool successful); -#elif defined(USE_ESP_IDF) - /** - * will request 4096 bytes chunks from the web server - * and send each to Nextion - * @param std::string url Full url for download. - * @param int range_start Position of next byte to transfer. - * @return position of last byte transferred, -1 for failure. - */ - int upload_range(const std::string &url, int range_start); - - /** - * Ends the upload process, restart Nextion and, if successful, - * restarts ESP - * @param bool url successful True: Transfer completed successfuly, False: Transfer failed. - * @return bool True: Transfer completed successfuly, False: Transfer failed. - */ - bool upload_end(bool successful); -#endif // ARDUINO vs USE_ESP_IDF /** * Returns the ESP Free Heap memory. This is framework independent. * @return Free Heap in bytes. @@ -1260,7 +1253,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe #ifdef NEXTION_PROTOCOL_LOG void print_queue_members_(); -#endif +#endif // NEXTION_PROTOCOL_LOG void reset_(bool reset_nextion = true); std::string command_data_; diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index 163b497d3b..448b6fc0ff 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -1,17 +1,16 @@ #include "nextion.h" -#ifdef USE_ESP_IDF #ifdef USE_NEXTION_TFT_UPLOAD +#ifdef USE_ESP_IDF #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/util.h" #include "esphome/core/log.h" #include "esphome/components/network/util.h" - +#include #include #include -#include namespace esphome { namespace nextion { @@ -20,153 +19,147 @@ static const char *const TAG = "nextion.upload.idf"; // Followed guide // https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2 -int Nextion::upload_range(const std::string &url, int range_start) { - ESP_LOGVV(TAG, "url: %s", url.c_str()); - uint range_size = this->tft_size_ - range_start; - ESP_LOGVV(TAG, "tft_size_: %i", this->tft_size_); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - int range_end = (range_start == 0) ? std::min(this->tft_size_, 16383) : this->tft_size_; +int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start) { + uint32_t range_size = this->tft_size_ - range_start; + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1; + ESP_LOGD(TAG, "Range start: %" PRIu32, range_start); if (range_size <= 0 or range_end <= range_start) { + ESP_LOGD(TAG, "Range end: %" PRIu32, range_end); + ESP_LOGD(TAG, "Range size: %" PRIu32, range_size); ESP_LOGE(TAG, "Invalid range"); - ESP_LOGD(TAG, "Range start: %i", range_start); - ESP_LOGD(TAG, "Range end: %i", range_end); - ESP_LOGD(TAG, "Range size: %i", range_size); return -1; } - esp_http_client_config_t config = { - .url = url.c_str(), - .cert_pem = nullptr, - .disable_auto_redirect = false, - .max_redirection_count = 10, - }; - esp_http_client_handle_t client = esp_http_client_init(&config); - - char range_header[64]; - sprintf(range_header, "bytes=%d-%d", range_start, range_end); + char range_header[32]; + sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end); ESP_LOGV(TAG, "Requesting range: %s", range_header); - esp_http_client_set_header(client, "Range", range_header); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - - ESP_LOGV(TAG, "Opening http connetion"); + esp_http_client_set_header(http_client, "Range", range_header); + ESP_LOGV(TAG, "Opening HTTP connetion"); esp_err_t err; - if ((err = esp_http_client_open(client, 0)) != ESP_OK) { + if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); - esp_http_client_cleanup(client); return -1; } ESP_LOGV(TAG, "Fetch content length"); - int content_length = esp_http_client_fetch_headers(client); - ESP_LOGV(TAG, "content_length = %d", content_length); - if (content_length <= 0) { - ESP_LOGE(TAG, "Failed to get content length: %d", content_length); - esp_http_client_cleanup(client); + const int chunk_size = esp_http_client_fetch_headers(http_client); + ESP_LOGV(TAG, "content_length = %d", chunk_size); + if (chunk_size <= 0) { + ESP_LOGE(TAG, "Failed to get chunk's content length: %d", chunk_size); return -1; } - int total_read_len = 0, read_len; - - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - ESP_LOGV(TAG, "Allocate buffer"); - uint8_t *buffer = new uint8_t[4096]; - std::string recv_string; - if (buffer == nullptr) { - ESP_LOGE(TAG, "Failed to allocate memory for buffer"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - } else { - ESP_LOGV(TAG, "Memory for buffer allocated successfully"); - - while (true) { - App.feed_wdt(); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - int read_len = esp_http_client_read(client, reinterpret_cast(buffer), 4096); - ESP_LOGVV(TAG, "Read %d bytes from HTTP client, writing to UART", read_len); - if (read_len > 0) { - this->write_array(buffer, read_len); - ESP_LOGVV(TAG, "Write to UART successful"); - this->recv_ret_string_(recv_string, 5000, true); - this->content_length_ -= read_len; - ESP_LOGD(TAG, "Uploaded %0.2f %%, remaining %d bytes, heap is %" PRIu32 " bytes", - 100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_, - esp_get_free_heap_size()); - - if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request - ESP_LOGD( - TAG, "recv_string [%s]", - format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); - uint32_t result = 0; - for (int j = 0; j < 4; ++j) { - result += static_cast(recv_string[j + 1]) << (8 * j); - } - if (result > 0) { - ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); - this->content_length_ = this->tft_size_ - result; - // Deallocate the buffer when done - ESP_LOGV(TAG, "Deallocate buffer"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - delete[] buffer; - ESP_LOGVV(TAG, "Memory for buffer deallocated"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - ESP_LOGV(TAG, "Close http client"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_http_client_close(client); - esp_http_client_cleanup(client); - ESP_LOGVV(TAG, "Client closed"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - return result; - } - } else if (recv_string[0] != 0x05) { // 0x05 == "ok" - ESP_LOGE( - TAG, "Invalid response from Nextion: [%s]", - format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); - ESP_LOGV(TAG, "Deallocate buffer"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - delete[] buffer; - ESP_LOGVV(TAG, "Memory for buffer deallocated"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - ESP_LOGV(TAG, "Close http client"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_http_client_close(client); - esp_http_client_cleanup(client); - ESP_LOGVV(TAG, "Client closed"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - return -1; - } - - recv_string.clear(); - } else if (read_len == 0) { - ESP_LOGV(TAG, "End of HTTP response reached"); - break; // Exit the loop if there is no more data to read - } else { - ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len); - break; // Exit the loop on error - } - } - - // Deallocate the buffer when done - ESP_LOGV(TAG, "Deallocate buffer"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - delete[] buffer; - ESP_LOGVV(TAG, "Memory for buffer deallocated"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + // Allocate the buffer dynamically + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + uint8_t *buffer = allocator.allocate(4096); + if (!buffer) { + ESP_LOGE(TAG, "Failed to allocate upload buffer"); + return -1; } - ESP_LOGV(TAG, "Close http client"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_http_client_close(client); - esp_http_client_cleanup(client); - ESP_LOGVV(TAG, "Client closed"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + + std::string recv_string; + while (true) { + App.feed_wdt(); + const uint16_t buffer_size = + this->content_length_ < 4096 ? this->content_length_ : 4096; // Limits buffer to the remaining data + ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size); + uint16_t read_len = 0; + int partial_read_len = 0; + uint8_t retries = 0; + // Attempt to read the chunk with retries. + while (retries < 5 && read_len < buffer_size) { + partial_read_len = + esp_http_client_read(http_client, reinterpret_cast(buffer) + read_len, buffer_size - read_len); + if (partial_read_len > 0) { + read_len += partial_read_len; // Accumulate the total read length. + // Reset retries on successful read. + retries = 0; + } else { + // If no data was read, increment retries. + retries++; + vTaskDelay(pdMS_TO_TICKS(2)); // NOLINT + } + App.feed_wdt(); // Feed the watchdog timer. + } + if (read_len != buffer_size) { + // Did not receive the full package within the timeout period + ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len, + buffer_size); + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return -1; + } + ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len); + if (read_len > 0) { + recv_string.clear(); + this->write_array(buffer, buffer_size); + App.feed_wdt(); + this->recv_ret_string_(recv_string, upload_first_chunk_sent_ ? 500 : 5000, true); + this->content_length_ -= read_len; + const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_; +#ifdef USE_PSRAM + ESP_LOGD( + TAG, + "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes", + upload_percentage, this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), + static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); +#else + ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage, + this->content_length_, static_cast(esp_get_free_heap_size())); +#endif + upload_first_chunk_sent_ = true; + if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request + ESP_LOGD(TAG, "recv_string [%s]", + format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); + uint32_t result = 0; + for (int j = 0; j < 4; ++j) { + result += static_cast(recv_string[j + 1]) << (8 * j); + } + if (result > 0) { + ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); + this->content_length_ = this->tft_size_ - result; + range_start = result; + } else { + range_start = range_end + 1; + } + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return range_end + 1; + } else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok" + ESP_LOGE(TAG, "Invalid response from Nextion: [%s]", + format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; + return -1; + } + + recv_string.clear(); + } else if (read_len == 0) { + ESP_LOGV(TAG, "End of HTTP response reached"); + break; // Exit the loop if there is no more data to read + } else { + ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %" PRIu16, read_len); + break; // Exit the loop on error + } + } + range_start = range_end + 1; + // Deallocate buffer + allocator.deallocate(buffer, 4096); + buffer = nullptr; return range_end + 1; } bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Nextion TFT upload requested"); ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); - ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); if (this->is_updating_) { - ESP_LOGW(TAG, "Currently updating"); + ESP_LOGW(TAG, "Currently uploading"); return false; } @@ -195,8 +188,8 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); // Define the configuration for the HTTP client - ESP_LOGV(TAG, "Establishing connection to HTTP server"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Initializing HTTP client"); + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); esp_http_client_config_t config = { .url = this->tft_url_.c_str(), .cert_pem = nullptr, @@ -205,58 +198,62 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { .disable_auto_redirect = false, .max_redirection_count = 10, }; - // Initialize the HTTP client with the configuration - ESP_LOGV(TAG, "Initializing HTTP client"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_http_client_handle_t http = esp_http_client_init(&config); - if (!http) { + esp_http_client_handle_t http_client = esp_http_client_init(&config); + if (!http_client) { ESP_LOGE(TAG, "Failed to initialize HTTP client."); - return this->upload_end(false); + return this->upload_end_(false); + } + + esp_err_t err = esp_http_client_set_header(http_client, "Connection", "keep-alive"); + if (err != ESP_OK) { + ESP_LOGE(TAG, "HTTP set header failed: %s", esp_err_to_name(err)); + esp_http_client_cleanup(http_client); + return this->upload_end_(false); } // Perform the HTTP request ESP_LOGV(TAG, "Check if the client could connect"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_err_t err = esp_http_client_perform(http); + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + err = esp_http_client_perform(http_client); if (err != ESP_OK) { ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); - esp_http_client_cleanup(http); - return this->upload_end(false); + esp_http_client_cleanup(http_client); + return this->upload_end_(false); } // Check the HTTP Status Code ESP_LOGV(TAG, "Check the HTTP Status Code"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - int status_code = esp_http_client_get_status_code(http); - ESP_LOGV(TAG, "HTTP Status Code: %d", status_code); - size_t tft_file_size = esp_http_client_get_content_length(http); - ESP_LOGD(TAG, "TFT file size: %zu", tft_file_size); + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + int status_code = esp_http_client_get_status_code(http_client); + if (status_code != 200 && status_code != 206) { + return this->upload_end_(false); + } - ESP_LOGD(TAG, "Close HTTP connection"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - esp_http_client_close(http); - esp_http_client_cleanup(http); - ESP_LOGVV(TAG, "Connection closed"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + this->tft_size_ = esp_http_client_get_content_length(http_client); - if (tft_file_size < 4096) { - ESP_LOGE(TAG, "File size check failed. Size: %zu", tft_file_size); - return this->upload_end(false); + ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_); + if (this->tft_size_ < 4096 || this->tft_size_ > 134217728) { + ESP_LOGE(TAG, "File size check failed."); + ESP_LOGD(TAG, "Close HTTP connection"); + esp_http_client_close(http_client); + esp_http_client_cleanup(http_client); + ESP_LOGV(TAG, "Connection closed"); + return this->upload_end_(false); } else { ESP_LOGV(TAG, "File size check passed. Proceeding..."); } - this->content_length_ = tft_file_size; - this->tft_size_ = tft_file_size; + this->content_length_ = this->tft_size_; - ESP_LOGD(TAG, "Updating Nextion"); + ESP_LOGD(TAG, "Uploading Nextion"); - // The Nextion will ignore the update command if it is sleeping + // The Nextion will ignore the upload command if it is sleeping ESP_LOGV(TAG, "Wake-up Nextion"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + this->ignore_is_setup_ = true; this->send_command_("sleep=0"); - this->set_backlight_brightness(1.0); + this->send_command_("dim=100"); vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); App.feed_wdt(); char command[128]; @@ -267,14 +264,11 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { // Clear serial receive buffer ESP_LOGV(TAG, "Clear serial receive buffer"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - uint8_t d; - while (this->available()) { - this->read_byte(&d); - }; + this->reset_(false); + vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); - ESP_LOGV(TAG, "Send update instruction: %s", command); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Send upload instruction: %s", command); this->send_command_(command); if (baud_rate != this->original_baud_rate_) { @@ -288,41 +282,66 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { this->recv_ret_string_(response, 5000, true); // This can take some time to return // The Nextion display will, if it's ready to accept data, send a 0x05 byte. - ESP_LOGD(TAG, "Upgrade response is [%s] - %zu bytes", + ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)", format_hex_pretty(reinterpret_cast(response.data()), response.size()).c_str(), response.length()); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); if (response.find(0x05) != std::string::npos) { - ESP_LOGV(TAG, "Preparation for tft update done"); + ESP_LOGV(TAG, "Preparation for TFT upload done"); } else { - ESP_LOGE(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str()); - return this->upload_end(false); + ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str()); + ESP_LOGD(TAG, "Close HTTP connection"); + esp_http_client_close(http_client); + esp_http_client_cleanup(http_client); + ESP_LOGV(TAG, "Connection closed"); + return this->upload_end_(false); } - ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d, Heap Size %" PRIu32, this->tft_url_.c_str(), - content_length_, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Change the method to GET before starting the download"); + esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET); + if (set_method_result != ESP_OK) { + ESP_LOGE(TAG, "Failed to set HTTP method to GET: %s", esp_err_to_name(set_method_result)); + return this->upload_end_(false); + } + + ESP_LOGD(TAG, "Uploading TFT to Nextion:"); + ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, " File size: %" PRIu32 " bytes", this->content_length_); + ESP_LOGD(TAG, " Free heap: %" PRIu32, esp_get_free_heap_size()); + + // Proceed with the content download as before ESP_LOGV(TAG, "Starting transfer by chunks loop"); - ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size()); - int result = 0; - while (content_length_ > 0) { - result = upload_range(this->tft_url_.c_str(), result); - if (result < 0) { - ESP_LOGE(TAG, "Error updating Nextion!"); - return this->upload_end(false); + + uint32_t position = 0; + while (this->content_length_ > 0) { + int upload_result = upload_by_chunks_(http_client, position); + if (upload_result < 0) { + ESP_LOGE(TAG, "Error uploading TFT to Nextion!"); + ESP_LOGD(TAG, "Close HTTP connection"); + esp_http_client_close(http_client); + esp_http_client_cleanup(http_client); + ESP_LOGV(TAG, "Connection closed"); + return this->upload_end_(false); } App.feed_wdt(); - ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_); + ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, esp_get_free_heap_size(), this->content_length_); } - ESP_LOGD(TAG, "Successfully updated Nextion!"); + ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!"); - return upload_end(true); + ESP_LOGD(TAG, "Close HTTP connection"); + esp_http_client_close(http_client); + esp_http_client_cleanup(http_client); + ESP_LOGV(TAG, "Connection closed"); + return this->upload_end_(true); } -bool Nextion::upload_end(bool successful) { +bool Nextion::upload_end_(bool successful) { + ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful)); this->is_updating_ = false; + this->ignore_is_setup_ = false; uint32_t baud_rate = this->parent_->get_baud_rate(); if (baud_rate != this->original_baud_rate_) { @@ -331,12 +350,12 @@ bool Nextion::upload_end(bool successful) { this->parent_->load_settings(); } - ESP_LOGD(TAG, "Restarting Nextion"); - this->soft_reset(); - vTaskDelay(pdMS_TO_TICKS(1500)); // NOLINT if (successful) { ESP_LOGD(TAG, "Restarting ESPHome"); - esp_restart(); // NOLINT(readability-static-accessed-through-instance) + delay(1500); // NOLINT + arch_restart(); + } else { + ESP_LOGE(TAG, "Nextion TFT upload failed"); } return successful; } @@ -344,5 +363,5 @@ bool Nextion::upload_end(bool successful) { } // namespace nextion } // namespace esphome -#endif // USE_NEXTION_TFT_UPLOAD #endif // USE_ESP_IDF +#endif // USE_NEXTION_TFT_UPLOAD diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 619a956071..b09373bcde 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -35,6 +35,7 @@ #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT +#define USE_NEXTION_TFT_UPLOAD #define USE_NUMBER #define USE_DATETIME #define USE_DATETIME_DATE @@ -64,7 +65,6 @@ // Arduino-specific feature flags #ifdef USE_ARDUINO #define USE_CAPTIVE_PORTAL -#define USE_NEXTION_TFT_UPLOAD #define USE_PROMETHEUS #define USE_WEBSERVER #define USE_WEBSERVER_PORT 80 // NOLINT From 539c369eea0c07a89d0b0fbc877d3b14fe17fbdc Mon Sep 17 00:00:00 2001 From: tronikos Date: Wed, 1 May 2024 17:39:15 -0700 Subject: [PATCH 1664/2607] Add a function to return the loop_interval (#6666) --- esphome/core/application.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/application.h b/esphome/core/application.h index 7487780412..c4c745b687 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -222,6 +222,8 @@ class Application { */ void set_loop_interval(uint32_t loop_interval) { this->loop_interval_ = loop_interval; } + uint32_t get_loop_interval() const { return this->loop_interval_; } + void schedule_dump_config() { this->dump_config_at_ = 0; } void feed_wdt(); From 1b9a30e921f129f5c9aa3dd1032387722a7babc9 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Thu, 2 May 2024 01:21:57 +0000 Subject: [PATCH 1665/2607] Remote receiver improvements (#4642) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/remote_base/remote_base.cpp | 6 +- esphome/components/remote_base/remote_base.h | 45 +++++++++-- .../components/remote_receiver/__init__.py | 75 +++++++++++++++++-- .../remote_receiver/remote_receiver.h | 6 +- .../remote_receiver/remote_receiver_esp32.cpp | 16 ++-- .../remote_receiver_esp8266.cpp | 3 +- .../remote_receiver_libretiny.cpp | 3 +- 7 files changed, 125 insertions(+), 29 deletions(-) diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index 0e9cef8cca..fdfd0b43cc 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -108,18 +108,18 @@ void RemoteReceiverBase::register_dumper(RemoteReceiverDumperBase *dumper) { void RemoteReceiverBase::call_listeners_() { for (auto *listener : this->listeners_) - listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_)); + listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_)); } void RemoteReceiverBase::call_dumpers_() { bool success = false; for (auto *dumper : this->dumpers_) { - if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_))) + if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_))) success = true; } if (!success) { for (auto *dumper : this->secondary_dumpers_) - dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_)); + dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_)); } } diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index b2a4b543ea..c31127735a 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -15,6 +15,11 @@ namespace esphome { namespace remote_base { +enum ToleranceMode : uint8_t { + TOLERANCE_MODE_PERCENTAGE = 0, + TOLERANCE_MODE_TIME = 1, +}; + using RawTimings = std::vector; class RemoteTransmitData { @@ -42,8 +47,8 @@ class RemoteTransmitData { class RemoteReceiveData { public: - explicit RemoteReceiveData(const RawTimings &data, uint8_t tolerance) - : data_(data), index_(0), tolerance_(tolerance) {} + explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode) + : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {} const RawTimings &get_raw_data() const { return this->data_; } uint32_t get_index() const { return index_; } @@ -65,13 +70,35 @@ class RemoteReceiveData { void advance(uint32_t amount = 1) { this->index_ += amount; } void reset() { this->index_ = 0; } + void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) { + this->tolerance_ = tolerance; + this->tolerance_mode_ = tolerance_mode; + } + uint32_t get_tolerance() { return tolerance_; } + ToleranceMode get_tolerance_mode() { return this->tolerance_mode_; } + protected: - int32_t lower_bound_(uint32_t length) const { return int32_t(100 - this->tolerance_) * length / 100U; } - int32_t upper_bound_(uint32_t length) const { return int32_t(100 + this->tolerance_) * length / 100U; } + int32_t lower_bound_(uint32_t length) const { + if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) { + return int32_t(length - this->tolerance_); + } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) { + return int32_t(100 - this->tolerance_) * length / 100U; + } + return 0; + } + int32_t upper_bound_(uint32_t length) const { + if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) { + return int32_t(length + this->tolerance_); + } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) { + return int32_t(100 + this->tolerance_) * length / 100U; + } + return 0; + } const RawTimings &data_; uint32_t index_; - uint8_t tolerance_; + uint32_t tolerance_; + ToleranceMode tolerance_mode_; }; class RemoteComponentBase { @@ -162,7 +189,10 @@ class RemoteReceiverBase : public RemoteComponentBase { RemoteReceiverBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {} void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); } void register_dumper(RemoteReceiverDumperBase *dumper); - void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; } + void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) { + this->tolerance_ = tolerance; + this->tolerance_mode_ = tolerance_mode; + } protected: void call_listeners_(); @@ -176,7 +206,8 @@ class RemoteReceiverBase : public RemoteComponentBase { std::vector dumpers_; std::vector secondary_dumpers_; RawTimings temp_; - uint8_t tolerance_; + uint32_t tolerance_{25}; + ToleranceMode tolerance_mode_{TOLERANCE_MODE_PERCENTAGE}; }; class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff, diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 6a68c8b254..6fe20153f4 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -10,17 +10,69 @@ from esphome.const import ( CONF_IDLE, CONF_PIN, CONF_TOLERANCE, + CONF_TYPE, CONF_MEMORY_BLOCKS, CONF_RMT_CHANNEL, + CONF_VALUE, ) from esphome.core import CORE, TimePeriod +CONF_CLOCK_DIVIDER = "clock_divider" + AUTO_LOAD = ["remote_base"] remote_receiver_ns = cg.esphome_ns.namespace("remote_receiver") +remote_base_ns = cg.esphome_ns.namespace("remote_base") + +ToleranceMode = remote_base_ns.enum("ToleranceMode") + +TYPE_PERCENTAGE = "percentage" +TYPE_TIME = "time" + +TOLERANCE_MODE = { + TYPE_PERCENTAGE: ToleranceMode.TOLERANCE_MODE_PERCENTAGE, + TYPE_TIME: ToleranceMode.TOLERANCE_MODE_TIME, +} + +TOLERANCE_SCHEMA = cv.typed_schema( + { + TYPE_PERCENTAGE: cv.Schema( + {cv.Required(CONF_VALUE): cv.All(cv.percentage_int, cv.uint32_t)} + ), + TYPE_TIME: cv.Schema( + { + cv.Required(CONF_VALUE): cv.All( + cv.positive_time_period_microseconds, + cv.Range(max=TimePeriod(microseconds=4294967295)), + ) + } + ), + }, + lower=True, + enum=TOLERANCE_MODE, +) + RemoteReceiverComponent = remote_receiver_ns.class_( "RemoteReceiverComponent", remote_base.RemoteReceiverBase, cg.Component ) + +def validate_tolerance(value): + if isinstance(value, dict): + return TOLERANCE_SCHEMA(value) + + if "%" in str(value): + type_ = TYPE_PERCENTAGE + else: + type_ = TYPE_TIME + + return TOLERANCE_SCHEMA( + { + CONF_VALUE: value, + CONF_TYPE: type_, + } + ) + + MULTI_CONF = True CONFIG_SCHEMA = remote_base.validate_triggers( cv.Schema( @@ -28,9 +80,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers( cv.GenerateID(): cv.declare_id(RemoteReceiverComponent), cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema), cv.Optional(CONF_DUMP, default=[]): remote_base.validate_dumpers, - cv.Optional(CONF_TOLERANCE, default=25): cv.All( - cv.percentage_int, cv.Range(min=0) - ), + cv.Optional(CONF_TOLERANCE, default="25%"): validate_tolerance, cv.SplitDefault( CONF_BUFFER_SIZE, esp32="10000b", @@ -40,11 +90,15 @@ CONFIG_SCHEMA = remote_base.validate_triggers( ): cv.validate_bytes, cv.Optional(CONF_FILTER, default="50us"): cv.All( cv.positive_time_period_microseconds, - cv.Range(max=TimePeriod(microseconds=255)), + cv.Range(max=TimePeriod(microseconds=4294967295)), + ), + cv.SplitDefault(CONF_CLOCK_DIVIDER, esp32=80): cv.All( + cv.only_on_esp32, cv.Range(min=1, max=255) + ), + cv.Optional(CONF_IDLE, default="10ms"): cv.All( + cv.positive_time_period_microseconds, + cv.Range(max=TimePeriod(microseconds=4294967295)), ), - cv.Optional( - CONF_IDLE, default="10ms" - ): cv.positive_time_period_microseconds, cv.Optional(CONF_MEMORY_BLOCKS, default=3): cv.Range(min=1, max=8), cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=False), } @@ -61,6 +115,7 @@ async def to_code(config): ) else: var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS]) + cg.add(var.set_clock_divider(config[CONF_CLOCK_DIVIDER])) else: var = cg.new_Pvariable(config[CONF_ID], pin) @@ -73,7 +128,11 @@ async def to_code(config): cg.add(var.register_listener(trigger)) await cg.register_component(var, config) - cg.add(var.set_tolerance(config[CONF_TOLERANCE])) + cg.add( + var.set_tolerance( + config[CONF_TOLERANCE][CONF_VALUE], config[CONF_TOLERANCE][CONF_TYPE] + ) + ) cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE])) cg.add(var.set_filter_us(config[CONF_FILTER])) cg.add(var.set_idle_us(config[CONF_IDLE])) diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index f29145a59e..a1db671e5c 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -22,7 +22,7 @@ struct RemoteReceiverComponentStore { uint32_t buffer_read_at{0}; bool overflow{false}; uint32_t buffer_size{1000}; - uint8_t filter_us{10}; + uint32_t filter_us{10}; ISRInternalGPIOPin pin; }; #endif @@ -50,7 +50,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, float get_setup_priority() const override { return setup_priority::DATA; } void set_buffer_size(uint32_t buffer_size) { this->buffer_size_ = buffer_size; } - void set_filter_us(uint8_t filter_us) { this->filter_us_ = filter_us; } + void set_filter_us(uint32_t filter_us) { this->filter_us_ = filter_us; } void set_idle_us(uint32_t idle_us) { this->idle_us_ = idle_us; } protected: @@ -66,7 +66,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, #endif uint32_t buffer_size_{}; - uint8_t filter_us_{10}; + uint32_t filter_us_{10}; uint32_t idle_us_{10000}; }; diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index d19ab695e1..c0bfb0222f 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -20,9 +20,11 @@ void RemoteReceiverComponent::setup() { rmt.rx_config.filter_en = false; } else { rmt.rx_config.filter_en = true; - rmt.rx_config.filter_ticks_thresh = this->from_microseconds_(this->filter_us_); + rmt.rx_config.filter_ticks_thresh = static_cast( + std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255)); } - rmt.rx_config.idle_threshold = this->from_microseconds_(this->idle_us_); + rmt.rx_config.idle_threshold = + static_cast(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535)); esp_err_t error = rmt_config(&rmt); if (error != ESP_OK) { @@ -60,8 +62,9 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); - ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); - ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); + ESP_LOGCONFIG(TAG, " Tolerance: %" PRIu32 "%s", this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); + ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_); ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_); if (this->is_failed()) { ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); @@ -88,6 +91,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) { this->temp_.clear(); int32_t multiplier = this->pin_->is_inverted() ? -1 : 1; size_t item_count = len / sizeof(rmt_item32_t); + uint32_t filter_ticks = this->from_microseconds_(this->filter_us_); ESP_LOGVV(TAG, "START:"); for (size_t i = 0; i < item_count; i++) { @@ -112,7 +116,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) { for (size_t i = 0; i < item_count; i++) { if (item[i].duration0 == 0u) { // Do nothing - } else if (bool(item[i].level0) == prev_level) { + } else if ((bool(item[i].level0) == prev_level) || (item[i].duration0 < filter_ticks)) { prev_length += item[i].duration0; } else { if (prev_length > 0) { @@ -128,7 +132,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) { if (item[i].duration1 == 0u) { // Do nothing - } else if (bool(item[i].level1) == prev_level) { + } else if ((bool(item[i].level1) == prev_level) || (item[i].duration1 < filter_ticks)) { prev_length += item[i].duration1; } else { if (prev_length > 0) { diff --git a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp index 8700fcf0bb..c92a134bd8 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp @@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() { "invert the signal using 'inverted: True' in the pin schema!"); } ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); - ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); + ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); } diff --git a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp index ac85b6b520..bfc29b4211 100644 --- a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp +++ b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp @@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() { "invert the signal using 'inverted: True' in the pin schema!"); } ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); - ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); + ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); } From bc65e6e914ea29da8bbb02ca5f5f3d948823dbd7 Mon Sep 17 00:00:00 2001 From: tronikos Date: Wed, 1 May 2024 18:24:18 -0700 Subject: [PATCH 1666/2607] Make fast update intervals in qmc5883l work (#6647) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/qmc5883l/qmc5883l.cpp | 5 +++++ esphome/components/qmc5883l/qmc5883l.h | 1 + 2 files changed, 6 insertions(+) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 8541b41ff7..49a67d4e09 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -1,4 +1,5 @@ #include "qmc5883l.h" +#include "esphome/core/application.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" #include @@ -59,6 +60,10 @@ void QMC5883LComponent::setup() { this->mark_failed(); return; } + + if (this->get_update_interval() < App.get_loop_interval()) { + high_freq_.start(); + } } void QMC5883LComponent::dump_config() { ESP_LOGCONFIG(TAG, "QMC5883L:"); diff --git a/esphome/components/qmc5883l/qmc5883l.h b/esphome/components/qmc5883l/qmc5883l.h index b0c0af40d2..dd2008d453 100644 --- a/esphome/components/qmc5883l/qmc5883l.h +++ b/esphome/components/qmc5883l/qmc5883l.h @@ -56,6 +56,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice { COMMUNICATION_FAILED, } error_code_; bool read_byte_16_(uint8_t a_register, uint16_t *data); + HighFrequencyLoopRequester high_freq_; }; } // namespace qmc5883l From c7c0d97a5ecbaa235636ba9e527f8c9ff7b4c4b0 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 2 May 2024 03:49:01 +0200 Subject: [PATCH 1667/2607] SPI and I2C for BMP390 and BMP380 (#6652) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 5 +- esphome/components/bmp3xx/sensor.py | 105 +----------------- esphome/components/bmp3xx_base/__init__.py | 95 ++++++++++++++++ .../bmp3xx_base.cpp} | 7 +- .../bmp3xx.h => bmp3xx_base/bmp3xx_base.h} | 15 ++- esphome/components/bmp3xx_i2c/__init__.py | 0 esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp | 29 +++++ esphome/components/bmp3xx_i2c/bmp3xx_i2c.h | 17 +++ esphome/components/bmp3xx_i2c/sensor.py | 22 ++++ esphome/components/bmp3xx_spi/__init__.py | 0 esphome/components/bmp3xx_spi/bmp3xx_spi.cpp | 57 ++++++++++ esphome/components/bmp3xx_spi/bmp3xx_spi.h | 19 ++++ esphome/components/bmp3xx_spi/sensor.py | 22 ++++ .../components/bmp3xx/test.esp32-c3-idf.yaml | 14 --- tests/components/bmp3xx/test.esp32-c3.yaml | 14 --- tests/components/bmp3xx/test.esp32.yaml | 14 --- tests/components/bmp3xx/test.esp8266.yaml | 14 --- tests/components/bmp3xx/test.rp2040.yaml | 14 --- .../common.yaml} | 7 +- .../bmp3xx_i2c/test.esp32-c3-idf.yaml | 5 + .../components/bmp3xx_i2c/test.esp32-c3.yaml | 5 + .../components/bmp3xx_i2c/test.esp32-idf.yaml | 5 + tests/components/bmp3xx_i2c/test.esp32.yaml | 5 + tests/components/bmp3xx_i2c/test.esp8266.yaml | 5 + tests/components/bmp3xx_i2c/test.rp2040.yaml | 5 + tests/components/bmp3xx_spi/common.yaml | 16 +++ .../bmp3xx_spi/test.esp32-c3-idf.yaml | 7 ++ .../components/bmp3xx_spi/test.esp32-c3.yaml | 7 ++ .../components/bmp3xx_spi/test.esp32-idf.yaml | 7 ++ tests/components/bmp3xx_spi/test.esp32.yaml | 7 ++ tests/components/bmp3xx_spi/test.esp8266.yaml | 7 ++ tests/components/bmp3xx_spi/test.rp2040.yaml | 7 ++ tests/test11.5.yaml | 9 -- tests/test5.yaml | 9 -- 34 files changed, 375 insertions(+), 201 deletions(-) create mode 100644 esphome/components/bmp3xx_base/__init__.py rename esphome/components/{bmp3xx/bmp3xx.cpp => bmp3xx_base/bmp3xx_base.cpp} (99%) rename esphome/components/{bmp3xx/bmp3xx.h => bmp3xx_base/bmp3xx_base.h} (94%) create mode 100644 esphome/components/bmp3xx_i2c/__init__.py create mode 100644 esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp create mode 100644 esphome/components/bmp3xx_i2c/bmp3xx_i2c.h create mode 100644 esphome/components/bmp3xx_i2c/sensor.py create mode 100644 esphome/components/bmp3xx_spi/__init__.py create mode 100644 esphome/components/bmp3xx_spi/bmp3xx_spi.cpp create mode 100644 esphome/components/bmp3xx_spi/bmp3xx_spi.h create mode 100644 esphome/components/bmp3xx_spi/sensor.py delete mode 100644 tests/components/bmp3xx/test.esp32-c3-idf.yaml delete mode 100644 tests/components/bmp3xx/test.esp32-c3.yaml delete mode 100644 tests/components/bmp3xx/test.esp32.yaml delete mode 100644 tests/components/bmp3xx/test.esp8266.yaml delete mode 100644 tests/components/bmp3xx/test.rp2040.yaml rename tests/components/{bmp3xx/test.esp32-idf.yaml => bmp3xx_i2c/common.yaml} (66%) create mode 100644 tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/bmp3xx_i2c/test.esp32-c3.yaml create mode 100644 tests/components/bmp3xx_i2c/test.esp32-idf.yaml create mode 100644 tests/components/bmp3xx_i2c/test.esp32.yaml create mode 100644 tests/components/bmp3xx_i2c/test.esp8266.yaml create mode 100644 tests/components/bmp3xx_i2c/test.rp2040.yaml create mode 100644 tests/components/bmp3xx_spi/common.yaml create mode 100644 tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/bmp3xx_spi/test.esp32-c3.yaml create mode 100644 tests/components/bmp3xx_spi/test.esp32-idf.yaml create mode 100644 tests/components/bmp3xx_spi/test.esp32.yaml create mode 100644 tests/components/bmp3xx_spi/test.esp8266.yaml create mode 100644 tests/components/bmp3xx_spi/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index d0e920fe1d..c630db7948 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -63,7 +63,10 @@ esphome/components/bme280_base/* @esphome/core esphome/components/bme280_spi/* @apbodrov esphome/components/bme680_bsec/* @trvrnrth esphome/components/bmi160/* @flaviut -esphome/components/bmp3xx/* @martgras +esphome/components/bmp3xx/* @latonita +esphome/components/bmp3xx_base/* @latonita @martgras +esphome/components/bmp3xx_i2c/* @latonita +esphome/components/bmp3xx_spi/* @latonita esphome/components/bmp581/* @kahrendt esphome/components/bp1658cj/* @Cossid esphome/components/bp5758d/* @Cossid diff --git a/esphome/components/bmp3xx/sensor.py b/esphome/components/bmp3xx/sensor.py index 6f90173c7b..89753768c3 100644 --- a/esphome/components/bmp3xx/sensor.py +++ b/esphome/components/bmp3xx/sensor.py @@ -1,102 +1,7 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import i2c, sensor -from esphome.const import ( - CONF_ID, - CONF_IIR_FILTER, - CONF_OVERSAMPLING, - CONF_PRESSURE, - CONF_TEMPERATURE, - DEVICE_CLASS_PRESSURE, - DEVICE_CLASS_TEMPERATURE, - STATE_CLASS_MEASUREMENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, + +CODEOWNERS = ["@latonita"] + +CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( + "The bmp3xx sensor component has been renamed to bmp3xx_i2c." ) - -CODEOWNERS = ["@martgras"] -DEPENDENCIES = ["i2c"] - -bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx") -Oversampling = bmp3xx_ns.enum("Oversampling") -OVERSAMPLING_OPTIONS = { - "NONE": Oversampling.OVERSAMPLING_NONE, - "2X": Oversampling.OVERSAMPLING_X2, - "4X": Oversampling.OVERSAMPLING_X4, - "8X": Oversampling.OVERSAMPLING_X8, - "16X": Oversampling.OVERSAMPLING_X16, - "32X": Oversampling.OVERSAMPLING_X32, -} - -IIRFilter = bmp3xx_ns.enum("IIRFilter") -IIR_FILTER_OPTIONS = { - "OFF": IIRFilter.IIR_FILTER_OFF, - "2X": IIRFilter.IIR_FILTER_2, - "4X": IIRFilter.IIR_FILTER_4, - "8X": IIRFilter.IIR_FILTER_8, - "16X": IIRFilter.IIR_FILTER_16, - "32X": IIRFilter.IIR_FILTER_32, - "64X": IIRFilter.IIR_FILTER_64, - "128X": IIRFilter.IIR_FILTER_128, -} - -BMP3XXComponent = bmp3xx_ns.class_( - "BMP3XXComponent", cg.PollingComponent, i2c.I2CDevice -) - -CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(BMP3XXComponent), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=1, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( - IIR_FILTER_OPTIONS, upper=True - ), - } - ) - .extend(cv.polling_component_schema("60s")) - .extend(i2c.i2c_device_schema(0x77)) -) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await i2c.register_i2c_device(var, config) - cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER])) - if temperature_config := config.get(CONF_TEMPERATURE): - sens = await sensor.new_sensor(temperature_config) - cg.add(var.set_temperature_sensor(sens)) - cg.add( - var.set_temperature_oversampling_config( - temperature_config[CONF_OVERSAMPLING] - ) - ) - - if pressure_config := config.get(CONF_PRESSURE): - sens = await sensor.new_sensor(pressure_config) - cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING])) diff --git a/esphome/components/bmp3xx_base/__init__.py b/esphome/components/bmp3xx_base/__init__.py new file mode 100644 index 0000000000..589d170907 --- /dev/null +++ b/esphome/components/bmp3xx_base/__init__.py @@ -0,0 +1,95 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_ID, + CONF_IIR_FILTER, + CONF_OVERSAMPLING, + CONF_PRESSURE, + CONF_TEMPERATURE, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, +) + +CODEOWNERS = ["@martgras", "@latonita"] + +bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_base") +Oversampling = bmp3xx_ns.enum("Oversampling") +OVERSAMPLING_OPTIONS = { + "NONE": Oversampling.OVERSAMPLING_NONE, + "2X": Oversampling.OVERSAMPLING_X2, + "4X": Oversampling.OVERSAMPLING_X4, + "8X": Oversampling.OVERSAMPLING_X8, + "16X": Oversampling.OVERSAMPLING_X16, + "32X": Oversampling.OVERSAMPLING_X32, +} + +IIRFilter = bmp3xx_ns.enum("IIRFilter") +IIR_FILTER_OPTIONS = { + "OFF": IIRFilter.IIR_FILTER_OFF, + "2X": IIRFilter.IIR_FILTER_2, + "4X": IIRFilter.IIR_FILTER_4, + "8X": IIRFilter.IIR_FILTER_8, + "16X": IIRFilter.IIR_FILTER_16, + "32X": IIRFilter.IIR_FILTER_32, + "64X": IIRFilter.IIR_FILTER_64, + "128X": IIRFilter.IIR_FILTER_128, +} + + +CONFIG_SCHEMA_BASE = cv.Schema( + { + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( + IIR_FILTER_OPTIONS, upper=True + ), + } +).extend(cv.polling_component_schema("60s")) + + +async def to_code_base(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER])) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + cg.add( + var.set_temperature_oversampling_config( + temperature_config[CONF_OVERSAMPLING] + ) + ) + + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) + cg.add(var.set_pressure_sensor(sens)) + cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING])) + + return var diff --git a/esphome/components/bmp3xx/bmp3xx.cpp b/esphome/components/bmp3xx_base/bmp3xx_base.cpp similarity index 99% rename from esphome/components/bmp3xx/bmp3xx.cpp rename to esphome/components/bmp3xx_base/bmp3xx_base.cpp index de28fd76ff..75b6812f81 100644 --- a/esphome/components/bmp3xx/bmp3xx.cpp +++ b/esphome/components/bmp3xx_base/bmp3xx_base.cpp @@ -5,13 +5,13 @@ http://github.com/MartinL1/BMP388_DEV */ -#include "bmp3xx.h" +#include "bmp3xx_base.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" #include namespace esphome { -namespace bmp3xx { +namespace bmp3xx_base { static const char *const TAG = "bmp3xx.sensor"; @@ -150,7 +150,6 @@ void BMP3XXComponent::setup() { void BMP3XXComponent::dump_config() { ESP_LOGCONFIG(TAG, "BMP3XX:"); ESP_LOGCONFIG(TAG, " Type: %s (0x%X)", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg); - LOG_I2C_DEVICE(this); switch (this->error_code_) { case NONE: break; @@ -386,5 +385,5 @@ float BMP3XXComponent::bmp388_compensate_pressure_(float uncomp_press, float t_l return partial_out1 + partial_out2 + partial_data4; } -} // namespace bmp3xx +} // namespace bmp3xx_base } // namespace esphome diff --git a/esphome/components/bmp3xx/bmp3xx.h b/esphome/components/bmp3xx_base/bmp3xx_base.h similarity index 94% rename from esphome/components/bmp3xx/bmp3xx.h rename to esphome/components/bmp3xx_base/bmp3xx_base.h index d3b15f601d..50f92e04c1 100644 --- a/esphome/components/bmp3xx/bmp3xx.h +++ b/esphome/components/bmp3xx_base/bmp3xx_base.h @@ -9,10 +9,9 @@ #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" -#include "esphome/components/i2c/i2c.h" namespace esphome { -namespace bmp3xx { +namespace bmp3xx_base { static const uint8_t BMP388_ID = 0x50; // The BMP388 device ID static const uint8_t BMP390_ID = 0x60; // The BMP390 device ID @@ -69,8 +68,8 @@ enum IIRFilter { IIR_FILTER_128 = 0x07 }; -/// This class implements support for the BMP3XX Temperature+Pressure i2c sensor. -class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice { +/// This class implements support for the BMP3XX Temperature+Pressure sensor. +class BMP3XXComponent : public PollingComponent { public: void setup() override; void dump_config() override; @@ -231,7 +230,13 @@ class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice { float bmp388_compensate_temperature_(float uncomp_temp); // Bosch pressure compensation function float bmp388_compensate_pressure_(float uncomp_press, float t_lin); + + // interface specific functions + virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0; + virtual bool write_byte(uint8_t a_register, uint8_t data) = 0; + virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0; + virtual bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0; }; -} // namespace bmp3xx +} // namespace bmp3xx_base } // namespace esphome diff --git a/esphome/components/bmp3xx_i2c/__init__.py b/esphome/components/bmp3xx_i2c/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp new file mode 100644 index 0000000000..7531090185 --- /dev/null +++ b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp @@ -0,0 +1,29 @@ +#include "esphome/components/i2c/i2c.h" +#include "bmp3xx_i2c.h" +#include + +namespace esphome { +namespace bmp3xx_i2c { + +static const char *const TAG = "bmp3xx_i2c.sensor"; + +bool BMP3XXI2CComponent::read_byte(uint8_t a_register, uint8_t *data) { + return I2CDevice::read_byte(a_register, data); +}; +bool BMP3XXI2CComponent::write_byte(uint8_t a_register, uint8_t data) { + return I2CDevice::write_byte(a_register, data); +}; +bool BMP3XXI2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + return I2CDevice::read_bytes(a_register, data, len); +}; +bool BMP3XXI2CComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) { + return I2CDevice::write_bytes(a_register, data, len); +}; + +void BMP3XXI2CComponent::dump_config() { + LOG_I2C_DEVICE(this); + BMP3XXComponent::dump_config(); +} + +} // namespace bmp3xx_i2c +} // namespace esphome diff --git a/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h new file mode 100644 index 0000000000..d8b95cf843 --- /dev/null +++ b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h @@ -0,0 +1,17 @@ +#pragma once +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/bmp3xx_base/bmp3xx_base.h" + +namespace esphome { +namespace bmp3xx_i2c { + +class BMP3XXI2CComponent : public bmp3xx_base::BMP3XXComponent, public i2c::I2CDevice { + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + void dump_config() override; +}; + +} // namespace bmp3xx_i2c +} // namespace esphome diff --git a/esphome/components/bmp3xx_i2c/sensor.py b/esphome/components/bmp3xx_i2c/sensor.py new file mode 100644 index 0000000000..ae59d29e89 --- /dev/null +++ b/esphome/components/bmp3xx_i2c/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +from esphome.components import i2c +from ..bmp3xx_base import to_code_base, cv, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["bmp3xx_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_i2c") + +BMP3XXI2CComponent = bmp3xx_ns.class_( + "BMP3XXI2CComponent", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( + i2c.i2c_device_schema(default_address=0x77) +).extend({cv.GenerateID(): cv.declare_id(BMP3XXI2CComponent)}) + + +async def to_code(config): + var = await to_code_base(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp3xx_spi/__init__.py b/esphome/components/bmp3xx_spi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp b/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp new file mode 100644 index 0000000000..2084530125 --- /dev/null +++ b/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp @@ -0,0 +1,57 @@ +#include "bmp3xx_spi.h" +#include + +namespace esphome { +namespace bmp3xx_spi { + +static const char *const TAG = "bmp3xx_spi.sensor"; + +uint8_t set_bit(uint8_t num, int position) { + int mask = 1 << position; + return num | mask; +} + +uint8_t clear_bit(uint8_t num, int position) { + int mask = 1 << position; + return num & ~mask; +} + +void BMP3XXSPIComponent::setup() { + this->spi_setup(); + BMP3XXComponent::setup(); +} + +bool BMP3XXSPIComponent::read_byte(uint8_t a_register, uint8_t *data) { + this->enable(); + this->transfer_byte(set_bit(a_register, 7)); + *data = this->transfer_byte(0); + this->disable(); + return true; +} + +bool BMP3XXSPIComponent::write_byte(uint8_t a_register, uint8_t data) { + this->enable(); + this->transfer_byte(clear_bit(a_register, 7)); + this->transfer_byte(data); + this->disable(); + return true; +} + +bool BMP3XXSPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + this->enable(); + this->transfer_byte(set_bit(a_register, 7)); + this->read_array(data, len); + this->disable(); + return true; +} + +bool BMP3XXSPIComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) { + this->enable(); + this->transfer_byte(clear_bit(a_register, 7)); + this->transfer_array(data, len); + this->disable(); + return true; +} + +} // namespace bmp3xx_spi +} // namespace esphome diff --git a/esphome/components/bmp3xx_spi/bmp3xx_spi.h b/esphome/components/bmp3xx_spi/bmp3xx_spi.h new file mode 100644 index 0000000000..2183994abe --- /dev/null +++ b/esphome/components/bmp3xx_spi/bmp3xx_spi.h @@ -0,0 +1,19 @@ +#pragma once +#include "esphome/components/bmp3xx_base/bmp3xx_base.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace bmp3xx_spi { + +class BMP3XXSPIComponent : public bmp3xx_base::BMP3XXComponent, + public spi::SPIDevice { + void setup() override; + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override; +}; + +} // namespace bmp3xx_spi +} // namespace esphome diff --git a/esphome/components/bmp3xx_spi/sensor.py b/esphome/components/bmp3xx_spi/sensor.py new file mode 100644 index 0000000000..3d1acd3c1b --- /dev/null +++ b/esphome/components/bmp3xx_spi/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +from esphome.components import spi +from ..bmp3xx_base import to_code_base, cv, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["bmp3xx_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["spi"] + +bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_spi") + +BMP3XXSPIComponent = bmp3xx_ns.class_( + "BMP3XXSPIComponent", cg.PollingComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( + {cv.GenerateID(): cv.declare_id(BMP3XXSPIComponent)} +) + + +async def to_code(config): + var = await to_code_base(config) + await spi.register_spi_device(var, config) diff --git a/tests/components/bmp3xx/test.esp32-c3-idf.yaml b/tests/components/bmp3xx/test.esp32-c3-idf.yaml deleted file mode 100644 index 3b244eccf9..0000000000 --- a/tests/components/bmp3xx/test.esp32-c3-idf.yaml +++ /dev/null @@ -1,14 +0,0 @@ -i2c: - - id: i2c_bmp3xx - scl: 5 - sda: 4 - -sensor: - - platform: bmp3xx - address: 0x77 - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - iir_filter: 2X diff --git a/tests/components/bmp3xx/test.esp32-c3.yaml b/tests/components/bmp3xx/test.esp32-c3.yaml deleted file mode 100644 index 3b244eccf9..0000000000 --- a/tests/components/bmp3xx/test.esp32-c3.yaml +++ /dev/null @@ -1,14 +0,0 @@ -i2c: - - id: i2c_bmp3xx - scl: 5 - sda: 4 - -sensor: - - platform: bmp3xx - address: 0x77 - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - iir_filter: 2X diff --git a/tests/components/bmp3xx/test.esp32.yaml b/tests/components/bmp3xx/test.esp32.yaml deleted file mode 100644 index 677ed8a22d..0000000000 --- a/tests/components/bmp3xx/test.esp32.yaml +++ /dev/null @@ -1,14 +0,0 @@ -i2c: - - id: i2c_bmp3xx - scl: 16 - sda: 17 - -sensor: - - platform: bmp3xx - address: 0x77 - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - iir_filter: 2X diff --git a/tests/components/bmp3xx/test.esp8266.yaml b/tests/components/bmp3xx/test.esp8266.yaml deleted file mode 100644 index 3b244eccf9..0000000000 --- a/tests/components/bmp3xx/test.esp8266.yaml +++ /dev/null @@ -1,14 +0,0 @@ -i2c: - - id: i2c_bmp3xx - scl: 5 - sda: 4 - -sensor: - - platform: bmp3xx - address: 0x77 - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - iir_filter: 2X diff --git a/tests/components/bmp3xx/test.rp2040.yaml b/tests/components/bmp3xx/test.rp2040.yaml deleted file mode 100644 index 3b244eccf9..0000000000 --- a/tests/components/bmp3xx/test.rp2040.yaml +++ /dev/null @@ -1,14 +0,0 @@ -i2c: - - id: i2c_bmp3xx - scl: 5 - sda: 4 - -sensor: - - platform: bmp3xx - address: 0x77 - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - iir_filter: 2X diff --git a/tests/components/bmp3xx/test.esp32-idf.yaml b/tests/components/bmp3xx_i2c/common.yaml similarity index 66% rename from tests/components/bmp3xx/test.esp32-idf.yaml rename to tests/components/bmp3xx_i2c/common.yaml index 677ed8a22d..6641b7a1b8 100644 --- a/tests/components/bmp3xx/test.esp32-idf.yaml +++ b/tests/components/bmp3xx_i2c/common.yaml @@ -1,10 +1,11 @@ i2c: - id: i2c_bmp3xx - scl: 16 - sda: 17 + scl: ${scl_pin} + sda: ${sda_pin} sensor: - - platform: bmp3xx + - platform: bmp3xx_i2c + i2c_id: i2c_bmp3xx address: 0x77 temperature: name: BMP Temperature diff --git a/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml b/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp32-c3.yaml b/tests/components/bmp3xx_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp32-idf.yaml b/tests/components/bmp3xx_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp32.yaml b/tests/components/bmp3xx_i2c/test.esp32.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp8266.yaml b/tests/components/bmp3xx_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_i2c/test.rp2040.yaml b/tests/components/bmp3xx_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp3xx_i2c/test.rp2040.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/common.yaml b/tests/components/bmp3xx_spi/common.yaml new file mode 100644 index 0000000000..8d5f897661 --- /dev/null +++ b/tests/components/bmp3xx_spi/common.yaml @@ -0,0 +1,16 @@ +spi: + - id: spi_bmp3xx + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +sensor: + - platform: bmp3xx_spi + spi_id: spi_bmp3xx + cs_pin: ${cs_pin} + temperature: + name: BMP Temperature + oversampling: 16x + pressure: + name: BMP Pressure + iir_filter: 2X diff --git a/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml b/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/test.esp32-c3.yaml b/tests/components/bmp3xx_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/bmp3xx_spi/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/test.esp32-idf.yaml b/tests/components/bmp3xx_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/bmp3xx_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/test.esp32.yaml b/tests/components/bmp3xx_spi/test.esp32.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/bmp3xx_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/test.esp8266.yaml b/tests/components/bmp3xx_spi/test.esp8266.yaml new file mode 100644 index 0000000000..dbd158d030 --- /dev/null +++ b/tests/components/bmp3xx_spi/test.esp8266.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + cs_pin: GPIO15 + +<<: !include common.yaml diff --git a/tests/components/bmp3xx_spi/test.rp2040.yaml b/tests/components/bmp3xx_spi/test.rp2040.yaml new file mode 100644 index 0000000000..f6c3f1eeca --- /dev/null +++ b/tests/components/bmp3xx_spi/test.rp2040.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO2 + mosi_pin: GPIO3 + miso_pin: GPIO4 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml index ef260d79c0..13de7f1929 100644 --- a/tests/test11.5.yaml +++ b/tests/test11.5.yaml @@ -498,15 +498,6 @@ sensor: co2: name: CO2 Sensor - - platform: bmp3xx - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - address: 0x77 - iir_filter: 2X - - platform: sen5x id: sen54 temperature: diff --git a/tests/test5.yaml b/tests/test5.yaml index 81615b24b0..afd3359098 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -474,15 +474,6 @@ sensor: co2: name: CO2 Sensor - - platform: bmp3xx - temperature: - name: BMP Temperature - oversampling: 16x - pressure: - name: BMP Pressure - address: 0x77 - iir_filter: 2X - - platform: ms8607 temperature: name: Temperature From ccbf5148aac29dade376483084bf7c092f613e35 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 5 May 2024 17:32:47 +1200 Subject: [PATCH 1668/2607] Set "CONF_" CI counter to fail on 3 or more definitions (#6668) --- esphome/components/ade7880/sensor.py | 2 +- esphome/components/ade7953_base/__init__.py | 2 +- esphome/components/at581x/__init__.py | 1 - esphome/components/bl0940/sensor.py | 2 +- esphome/components/bme680_bsec/__init__.py | 3 +-- esphome/components/cs5460a/sensor.py | 2 +- esphome/components/daikin_brc/climate.py | 3 +-- .../components/dfrobot_sen0395/__init__.py | 4 +--- esphome/components/emc2101/sensor/__init__.py | 2 +- esphome/components/ens160/sensor.py | 2 +- esphome/components/esp32_ble/__init__.py | 3 +-- esphome/components/esp32_camera/__init__.py | 2 +- .../graphical_display_menu/__init__.py | 3 +-- esphome/components/haier/climate.py | 4 ++-- esphome/components/haier/sensor/__init__.py | 2 +- esphome/components/hmc5883l/sensor.py | 2 +- esphome/components/inkplate6/display.py | 2 +- esphome/components/kmeteriso/sensor.py | 2 +- esphome/components/ld2410/binary_sensor.py | 6 +++--- esphome/components/ld2410/button/__init__.py | 4 ++-- .../ld2420/binary_sensor/__init__.py | 3 +-- esphome/components/ld2420/button/__init__.py | 2 +- esphome/components/mcp3008/sensor/__init__.py | 2 +- esphome/components/mcp3204/__init__.py | 3 +-- esphome/components/midea/climate.py | 2 +- esphome/components/midea_ir/climate.py | 3 +-- esphome/components/mmc5603/sensor.py | 3 +-- esphome/components/pn532/__init__.py | 9 ++++++-- esphome/components/pn7150/__init__.py | 4 ++-- esphome/components/pn7160/__init__.py | 4 ++-- esphome/components/power_supply/__init__.py | 10 ++++++--- esphome/components/qmc5883l/sensor.py | 3 +-- esphome/components/resistance/sensor.py | 2 +- esphome/components/rpi_dpi_rgb/display.py | 4 ++-- esphome/components/scd30/sensor.py | 2 +- esphome/components/scd4x/sensor.py | 2 +- esphome/components/script/__init__.py | 3 +-- .../seeed_mr24hpc1/binary_sensor.py | 2 +- .../seeed_mr24hpc1/button/__init__.py | 2 +- .../seeed_mr24hpc1/number/__init__.py | 2 +- esphome/components/sgp30/sensor.py | 2 +- esphome/components/sgp4x/sensor.py | 2 +- esphome/components/sim800l/__init__.py | 2 +- esphome/components/sn74hc595/__init__.py | 2 +- esphome/components/st7701s/display.py | 4 ++-- esphome/components/tlc5947/__init__.py | 2 +- esphome/components/touchscreen/__init__.py | 2 +- esphome/components/whynter/climate.py | 3 +-- esphome/components/wifi/__init__.py | 2 +- esphome/components/wireguard/__init__.py | 2 ++ esphome/components/wireguard/binary_sensor.py | 3 +-- esphome/components/wireguard/sensor.py | 3 +-- esphome/components/wireguard/text_sensor.py | 4 +--- esphome/const.py | 21 +++++++++++++++++++ script/ci-custom.py | 2 +- 55 files changed, 95 insertions(+), 81 deletions(-) diff --git a/esphome/components/ade7880/sensor.py b/esphome/components/ade7880/sensor.py index 42a2b0d3fc..e075adb04c 100644 --- a/esphome/components/ade7880/sensor.py +++ b/esphome/components/ade7880/sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( CONF_RESET_PIN, CONF_REVERSE_ACTIVE_ENERGY, CONF_VOLTAGE, + CONF_VOLTAGE_GAIN, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, @@ -47,7 +48,6 @@ CONF_CURRENT_GAIN = "current_gain" CONF_IRQ0_PIN = "irq0_pin" CONF_IRQ1_PIN = "irq1_pin" CONF_POWER_GAIN = "power_gain" -CONF_VOLTAGE_GAIN = "voltage_gain" CONF_NEUTRAL = "neutral" diff --git a/esphome/components/ade7953_base/__init__.py b/esphome/components/ade7953_base/__init__.py index 28014ef142..af3f629ca8 100644 --- a/esphome/components/ade7953_base/__init__.py +++ b/esphome/components/ade7953_base/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_IRQ_PIN, CONF_VOLTAGE, CONF_FREQUENCY, + CONF_VOLTAGE_GAIN, DEVICE_CLASS_CURRENT, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_POWER, @@ -36,7 +37,6 @@ CONF_POWER_FACTOR_B = "power_factor_b" CONF_VOLTAGE_PGA_GAIN = "voltage_pga_gain" CONF_CURRENT_PGA_GAIN_A = "current_pga_gain_a" CONF_CURRENT_PGA_GAIN_B = "current_pga_gain_b" -CONF_VOLTAGE_GAIN = "voltage_gain" CONF_CURRENT_GAIN_A = "current_gain_a" CONF_CURRENT_GAIN_B = "current_gain_b" CONF_ACTIVE_POWER_GAIN_A = "active_power_gain_a" diff --git a/esphome/components/at581x/__init__.py b/esphome/components/at581x/__init__.py index 2860d21f6c..e636510a4b 100644 --- a/esphome/components/at581x/__init__.py +++ b/esphome/components/at581x/__init__.py @@ -22,7 +22,6 @@ CONF_AT581X_ID = "at581x_id" CONF_SENSING_DISTANCE = "sensing_distance" -CONF_SENSITIVITY = "sensitivity" CONF_POWERON_SELFCHECK_TIME = "poweron_selfcheck_time" CONF_PROTECT_TIME = "protect_time" CONF_TRIGGER_BASE = "trigger_base" diff --git a/esphome/components/bl0940/sensor.py b/esphome/components/bl0940/sensor.py index fc2b04f976..5cb1472d76 100644 --- a/esphome/components/bl0940/sensor.py +++ b/esphome/components/bl0940/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ENERGY, CONF_EXTERNAL_TEMPERATURE, CONF_ID, + CONF_INTERNAL_TEMPERATURE, CONF_POWER, CONF_VOLTAGE, DEVICE_CLASS_CURRENT, @@ -24,7 +25,6 @@ from esphome.const import ( DEPENDENCIES = ["uart"] -CONF_INTERNAL_TEMPERATURE = "internal_temperature" bl0940_ns = cg.esphome_ns.namespace("bl0940") BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index 15c17f4064..62ab50b8f7 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, esp32 -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_TEMPERATURE_OFFSET CODEOWNERS = ["@trvrnrth"] DEPENDENCIES = ["i2c"] @@ -9,7 +9,6 @@ AUTO_LOAD = ["sensor", "text_sensor"] MULTI_CONF = True CONF_BME680_BSEC_ID = "bme680_bsec_id" -CONF_TEMPERATURE_OFFSET = "temperature_offset" CONF_IAQ_MODE = "iaq_mode" CONF_SUPPLY_VOLTAGE = "supply_voltage" CONF_SAMPLE_RATE = "sample_rate" diff --git a/esphome/components/cs5460a/sensor.py b/esphome/components/cs5460a/sensor.py index c27fc5fc3c..d8219e1df1 100644 --- a/esphome/components/cs5460a/sensor.py +++ b/esphome/components/cs5460a/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ID, CONF_POWER, CONF_VOLTAGE, + CONF_VOLTAGE_GAIN, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -33,7 +34,6 @@ CONF_SAMPLES = "samples" CONF_PHASE_OFFSET = "phase_offset" CONF_PGA_GAIN = "pga_gain" CONF_CURRENT_GAIN = "current_gain" -CONF_VOLTAGE_GAIN = "voltage_gain" CONF_CURRENT_HPF = "current_hpf" CONF_VOLTAGE_HPF = "voltage_hpf" CONF_PULSE_ENERGY = "pulse_energy" diff --git a/esphome/components/daikin_brc/climate.py b/esphome/components/daikin_brc/climate.py index 3468b6533c..7a5bd9b14d 100644 --- a/esphome/components/daikin_brc/climate.py +++ b/esphome/components/daikin_brc/climate.py @@ -1,14 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import climate_ir -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_USE_FAHRENHEIT AUTO_LOAD = ["climate_ir"] daikin_brc_ns = cg.esphome_ns.namespace("daikin_brc") DaikinBrcClimate = daikin_brc_ns.class_("DaikinBrcClimate", climate_ir.ClimateIR) -CONF_USE_FAHRENHEIT = "use_fahrenheit" CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( { diff --git a/esphome/components/dfrobot_sen0395/__init__.py b/esphome/components/dfrobot_sen0395/__init__.py index 2197ee5ef8..39787ca66b 100644 --- a/esphome/components/dfrobot_sen0395/__init__.py +++ b/esphome/components/dfrobot_sen0395/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID +from esphome.const import CONF_FACTORY_RESET, CONF_ID, CONF_SENSITIVITY from esphome.components import uart CODEOWNERS = ["@niklasweber"] @@ -28,8 +28,6 @@ CONF_DELAY_AFTER_DETECT = "delay_after_detect" CONF_DELAY_AFTER_DISAPPEAR = "delay_after_disappear" CONF_DETECTION_SEGMENTS = "detection_segments" CONF_OUTPUT_LATENCY = "output_latency" -CONF_FACTORY_RESET = "factory_reset" -CONF_SENSITIVITY = "sensitivity" CONFIG_SCHEMA = cv.All( cv.Schema( diff --git a/esphome/components/emc2101/sensor/__init__.py b/esphome/components/emc2101/sensor/__init__.py index 9f3fbdce00..10ea3dfae6 100644 --- a/esphome/components/emc2101/sensor/__init__.py +++ b/esphome/components/emc2101/sensor/__init__.py @@ -4,6 +4,7 @@ from esphome.components import sensor from esphome.const import ( CONF_EXTERNAL_TEMPERATURE, CONF_ID, + CONF_INTERNAL_TEMPERATURE, CONF_SPEED, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, @@ -16,7 +17,6 @@ from .. import EMC2101_COMPONENT_SCHEMA, CONF_EMC2101_ID, emc2101_ns DEPENDENCIES = ["emc2101"] -CONF_INTERNAL_TEMPERATURE = "internal_temperature" CONF_DUTY_CYCLE = "duty_cycle" EMC2101Sensor = emc2101_ns.class_("EMC2101Sensor", cg.PollingComponent) diff --git a/esphome/components/ens160/sensor.py b/esphome/components/ens160/sensor.py index 393b63bae1..6572c4e397 100644 --- a/esphome/components/ens160/sensor.py +++ b/esphome/components/ens160/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( + CONF_COMPENSATION, CONF_ECO2, CONF_HUMIDITY, CONF_ID, @@ -27,7 +28,6 @@ ENS160Component = ens160_ns.class_( ) CONF_AQI = "aqi" -CONF_COMPENSATION = "compensation" UNIT_INDEX = "index" CONFIG_SCHEMA = ( diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 088a3b6d1e..d88161e3e0 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.const import CONF_ID +from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID from esphome.core import CORE from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const @@ -11,7 +11,6 @@ CONFLICTS_WITH = ["esp32_ble_beacon"] CONF_BLE_ID = "ble_id" CONF_IO_CAPABILITY = "io_capability" -CONF_ENABLE_ON_BOOT = "enable_on_boot" NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index ee8a889f4c..462900d401 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_BRIGHTNESS, CONF_CONTRAST, CONF_TRIGGER_ID, + CONF_VSYNC_PIN, ) from esphome.core import CORE from esphome.components.esp32 import add_idf_sdkconfig_option @@ -112,7 +113,6 @@ ENUM_SPECIAL_EFFECT = { } # pin assignment -CONF_VSYNC_PIN = "vsync_pin" CONF_HREF_PIN = "href_pin" CONF_PIXEL_CLOCK_PIN = "pixel_clock_pin" CONF_EXTERNAL_CLOCK = "external_clock" diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index 3849449523..1b3ed7f8cd 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import display, font, color -from esphome.const import CONF_ID, CONF_TRIGGER_ID +from esphome.const import CONF_DISPLAY, CONF_ID, CONF_TRIGGER_ID from esphome import automation, core from esphome.components.display_menu_base import ( @@ -10,7 +10,6 @@ from esphome.components.display_menu_base import ( display_menu_to_code, ) -CONF_DISPLAY = "display" CONF_FONT = "font" CONF_MENU_ITEM_VALUE = "menu_item_value" CONF_FOREGROUND_COLOR = "foreground_color" diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index a700be8be2..b16244fd90 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -6,12 +6,14 @@ from esphome.components import uart, climate, logger from esphome import automation from esphome.const import ( CONF_BEEPER, + CONF_DISPLAY, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, CONF_MAX_TEMPERATURE, CONF_MIN_TEMPERATURE, + CONF_OUTDOOR_TEMPERATURE, CONF_PROTOCOL, CONF_SUPPORTED_MODES, CONF_SUPPORTED_PRESETS, @@ -43,11 +45,9 @@ CONF_ALTERNATIVE_SWING_CONTROL = "alternative_swing_control" CONF_ANSWER_TIMEOUT = "answer_timeout" CONF_CONTROL_METHOD = "control_method" CONF_CONTROL_PACKET_SIZE = "control_packet_size" -CONF_DISPLAY = "display" CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow" CONF_ON_ALARM_START = "on_alarm_start" CONF_ON_ALARM_END = "on_alarm_end" -CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_VERTICAL_AIRFLOW = "vertical_airflow" CONF_WIFI_SIGNAL = "wifi_signal" diff --git a/esphome/components/haier/sensor/__init__.py b/esphome/components/haier/sensor/__init__.py index 9a4965493d..01f997baa5 100644 --- a/esphome/components/haier/sensor/__init__.py +++ b/esphome/components/haier/sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor from esphome.const import ( + CONF_OUTDOOR_TEMPERATURE, CONF_POWER, CONF_HUMIDITY, DEVICE_CLASS_CURRENT, @@ -41,7 +42,6 @@ CONF_OUTDOOR_COIL_TEMPERATURE = "outdoor_coil_temperature" CONF_OUTDOOR_DEFROST_TEMPERATURE = "outdoor_defrost_temperature" CONF_OUTDOOR_IN_AIR_TEMPERATURE = "outdoor_in_air_temperature" CONF_OUTDOOR_OUT_AIR_TEMPERATURE = "outdoor_out_air_temperature" -CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" # Additional icons ICON_SNOWFLAKE_THERMOMETER = "mdi:snowflake-thermometer" diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py index 7edd13965e..f2decea150 100644 --- a/esphome/components/hmc5883l/sensor.py +++ b/esphome/components/hmc5883l/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Z, + CONF_HEADING, CONF_ID, CONF_OVERSAMPLING, CONF_RANGE, @@ -21,7 +22,6 @@ DEPENDENCIES = ["i2c"] hmc5883l_ns = cg.esphome_ns.namespace("hmc5883l") -CONF_HEADING = "heading" HMC5883LComponent = hmc5883l_ns.class_( "HMC5883LComponent", cg.PollingComponent, i2c.I2CDevice diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index bcd9580448..58a146d2fd 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_ID, CONF_LAMBDA, CONF_MODEL, + CONF_OE_PIN, CONF_PAGES, CONF_WAKEUP_PIN, ) @@ -29,7 +30,6 @@ CONF_GREYSCALE = "greyscale" CONF_GMOD_PIN = "gmod_pin" CONF_GPIO0_ENABLE_PIN = "gpio0_enable_pin" CONF_LE_PIN = "le_pin" -CONF_OE_PIN = "oe_pin" CONF_PARTIAL_UPDATING = "partial_updating" CONF_POWERUP_PIN = "powerup_pin" CONF_SPH_PIN = "sph_pin" diff --git a/esphome/components/kmeteriso/sensor.py b/esphome/components/kmeteriso/sensor.py index e730e446ae..082a055701 100644 --- a/esphome/components/kmeteriso/sensor.py +++ b/esphome/components/kmeteriso/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ID, + CONF_INTERNAL_TEMPERATURE, CONF_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, @@ -10,7 +11,6 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ) -CONF_INTERNAL_TEMPERATURE = "internal_temperature" DEPENDENCIES = ["i2c"] kmeteriso_ns = cg.esphome_ns.namespace("kmeteriso") diff --git a/esphome/components/ld2410/binary_sensor.py b/esphome/components/ld2410/binary_sensor.py index 3057480d25..e00ab93be2 100644 --- a/esphome/components/ld2410/binary_sensor.py +++ b/esphome/components/ld2410/binary_sensor.py @@ -8,13 +8,13 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ICON_MOTION_SENSOR, ICON_ACCOUNT, + CONF_HAS_TARGET, + CONF_HAS_MOVING_TARGET, + CONF_HAS_STILL_TARGET, ) from . import CONF_LD2410_ID, LD2410Component DEPENDENCIES = ["ld2410"] -CONF_HAS_TARGET = "has_target" -CONF_HAS_MOVING_TARGET = "has_moving_target" -CONF_HAS_STILL_TARGET = "has_still_target" CONF_OUT_PIN_PRESENCE_STATUS = "out_pin_presence_status" CONFIG_SCHEMA = { diff --git a/esphome/components/ld2410/button/__init__.py b/esphome/components/ld2410/button/__init__.py index 3567114c2c..34b18e8bdd 100644 --- a/esphome/components/ld2410/button/__init__.py +++ b/esphome/components/ld2410/button/__init__.py @@ -2,6 +2,8 @@ import esphome.codegen as cg from esphome.components import button import esphome.config_validation as cv from esphome.const import ( + CONF_FACTORY_RESET, + CONF_RESTART, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_CONFIG, @@ -15,8 +17,6 @@ QueryButton = ld2410_ns.class_("QueryButton", button.Button) ResetButton = ld2410_ns.class_("ResetButton", button.Button) RestartButton = ld2410_ns.class_("RestartButton", button.Button) -CONF_FACTORY_RESET = "factory_reset" -CONF_RESTART = "restart" CONF_QUERY_PARAMS = "query_params" CONFIG_SCHEMA = { diff --git a/esphome/components/ld2420/binary_sensor/__init__.py b/esphome/components/ld2420/binary_sensor/__init__.py index f94e4d969f..43e22d0348 100644 --- a/esphome/components/ld2420/binary_sensor/__init__.py +++ b/esphome/components/ld2420/binary_sensor/__init__.py @@ -1,14 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor -from esphome.const import CONF_ID, DEVICE_CLASS_OCCUPANCY +from esphome.const import CONF_ID, DEVICE_CLASS_OCCUPANCY, CONF_HAS_TARGET from .. import ld2420_ns, LD2420Component, CONF_LD2420_ID LD2420BinarySensor = ld2420_ns.class_( "LD2420BinarySensor", binary_sensor.BinarySensor, cg.Component ) -CONF_HAS_TARGET = "has_target" CONFIG_SCHEMA = cv.All( cv.COMPONENT_SCHEMA.extend( diff --git a/esphome/components/ld2420/button/__init__.py b/esphome/components/ld2420/button/__init__.py index 675e041dd4..df774ad7bc 100644 --- a/esphome/components/ld2420/button/__init__.py +++ b/esphome/components/ld2420/button/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import button import esphome.config_validation as cv from esphome.const import ( + CONF_FACTORY_RESET, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_CONFIG, @@ -19,7 +20,6 @@ LD2420FactoryResetButton = ld2420_ns.class_("LD2420FactoryResetButton", button.B CONF_APPLY_CONFIG = "apply_config" CONF_REVERT_CONFIG = "revert_config" CONF_RESTART_MODULE = "restart_module" -CONF_FACTORY_RESET = "factory_reset" CONFIG_SCHEMA = { diff --git a/esphome/components/mcp3008/sensor/__init__.py b/esphome/components/mcp3008/sensor/__init__.py index c56965d517..8ae00ef29e 100644 --- a/esphome/components/mcp3008/sensor/__init__.py +++ b/esphome/components/mcp3008/sensor/__init__.py @@ -4,6 +4,7 @@ from esphome.components import sensor, voltage_sampler from esphome.const import ( CONF_ID, CONF_NUMBER, + CONF_REFERENCE_VOLTAGE, UNIT_VOLT, STATE_CLASS_MEASUREMENT, DEVICE_CLASS_VOLTAGE, @@ -22,7 +23,6 @@ MCP3008Sensor = mcp3008_ns.class_( voltage_sampler.VoltageSampler, cg.Parented.template(MCP3008), ) -CONF_REFERENCE_VOLTAGE = "reference_voltage" CONF_MCP3008_ID = "mcp3008_id" CONFIG_SCHEMA = ( diff --git a/esphome/components/mcp3204/__init__.py b/esphome/components/mcp3204/__init__.py index 0536166e56..98129fc389 100644 --- a/esphome/components/mcp3204/__init__.py +++ b/esphome/components/mcp3204/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import spi -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_REFERENCE_VOLTAGE DEPENDENCIES = ["spi"] MULTI_CONF = True @@ -10,7 +10,6 @@ CODEOWNERS = ["@rsumner"] mcp3204_ns = cg.esphome_ns.namespace("mcp3204") MCP3204 = mcp3204_ns.class_("MCP3204", cg.Component, spi.SPIDevice) -CONF_REFERENCE_VOLTAGE = "reference_voltage" CONFIG_SCHEMA = cv.Schema( { diff --git a/esphome/components/midea/climate.py b/esphome/components/midea/climate.py index 074ab8abb2..83540a061a 100644 --- a/esphome/components/midea/climate.py +++ b/esphome/components/midea/climate.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_CUSTOM_PRESETS, CONF_ID, CONF_NUM_ATTEMPTS, + CONF_OUTDOOR_TEMPERATURE, CONF_PERIOD, CONF_SUPPORTED_MODES, CONF_SUPPORTED_PRESETS, @@ -37,7 +38,6 @@ from esphome.components.climate import ( CODEOWNERS = ["@dudanov"] DEPENDENCIES = ["climate", "uart"] AUTO_LOAD = ["sensor"] -CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_POWER_USAGE = "power_usage" CONF_HUMIDITY_SETPOINT = "humidity_setpoint" midea_ac_ns = cg.esphome_ns.namespace("midea").namespace("ac") diff --git a/esphome/components/midea_ir/climate.py b/esphome/components/midea_ir/climate.py index 140e4ee4e0..8fea6b192b 100644 --- a/esphome/components/midea_ir/climate.py +++ b/esphome/components/midea_ir/climate.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import climate_ir -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_USE_FAHRENHEIT AUTO_LOAD = ["climate_ir", "coolix"] CODEOWNERS = ["@dudanov"] @@ -9,7 +9,6 @@ CODEOWNERS = ["@dudanov"] midea_ir_ns = cg.esphome_ns.namespace("midea_ir") MideaIR = midea_ir_ns.class_("MideaIR", climate_ir.ClimateIR) -CONF_USE_FAHRENHEIT = "use_fahrenheit" CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( { diff --git a/esphome/components/mmc5603/sensor.py b/esphome/components/mmc5603/sensor.py index db4e5cbf26..cf16132470 100644 --- a/esphome/components/mmc5603/sensor.py +++ b/esphome/components/mmc5603/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Z, + CONF_HEADING, CONF_ID, ICON_MAGNET, STATE_CLASS_MEASUREMENT, @@ -19,8 +20,6 @@ DEPENDENCIES = ["i2c"] mmc5603_ns = cg.esphome_ns.namespace("mmc5603") -CONF_HEADING = "heading" - MMC5603Component = mmc5603_ns.class_( "MMC5603Component", cg.PollingComponent, i2c.I2CDevice ) diff --git a/esphome/components/pn532/__init__.py b/esphome/components/pn532/__init__.py index 2f120bc983..cdcaf4267c 100644 --- a/esphome/components/pn532/__init__.py +++ b/esphome/components/pn532/__init__.py @@ -2,14 +2,19 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.components import nfc -from esphome.const import CONF_ID, CONF_ON_TAG_REMOVED, CONF_ON_TAG, CONF_TRIGGER_ID +from esphome.const import ( + CONF_ID, + CONF_ON_FINISHED_WRITE, + CONF_ON_TAG_REMOVED, + CONF_ON_TAG, + CONF_TRIGGER_ID, +) CODEOWNERS = ["@OttoWinter", "@jesserockz"] AUTO_LOAD = ["binary_sensor", "nfc"] MULTI_CONF = True CONF_PN532_ID = "pn532_id" -CONF_ON_FINISHED_WRITE = "on_finished_write" pn532_ns = cg.esphome_ns.namespace("pn532") PN532 = pn532_ns.class_("PN532", cg.PollingComponent) diff --git a/esphome/components/pn7150/__init__.py b/esphome/components/pn7150/__init__.py index a136028011..e3589ea449 100644 --- a/esphome/components/pn7150/__init__.py +++ b/esphome/components/pn7150/__init__.py @@ -6,6 +6,8 @@ from esphome.components import nfc from esphome.const import ( CONF_ID, CONF_IRQ_PIN, + CONF_MESSAGE, + CONF_ON_FINISHED_WRITE, CONF_ON_TAG_REMOVED, CONF_ON_TAG, CONF_TRIGGER_ID, @@ -18,8 +20,6 @@ CONF_EMULATION_MESSAGE = "emulation_message" CONF_EMULATION_OFF = "emulation_off" CONF_EMULATION_ON = "emulation_on" CONF_INCLUDE_ANDROID_APP_RECORD = "include_android_app_record" -CONF_MESSAGE = "message" -CONF_ON_FINISHED_WRITE = "on_finished_write" CONF_ON_EMULATED_TAG_SCAN = "on_emulated_tag_scan" CONF_PN7150_ID = "pn7150_id" CONF_POLLING_OFF = "polling_off" diff --git a/esphome/components/pn7160/__init__.py b/esphome/components/pn7160/__init__.py index 1639041b9e..b102b38f98 100644 --- a/esphome/components/pn7160/__init__.py +++ b/esphome/components/pn7160/__init__.py @@ -6,6 +6,8 @@ from esphome.components import nfc from esphome.const import ( CONF_ID, CONF_IRQ_PIN, + CONF_MESSAGE, + CONF_ON_FINISHED_WRITE, CONF_ON_TAG_REMOVED, CONF_ON_TAG, CONF_TRIGGER_ID, @@ -19,8 +21,6 @@ CONF_EMULATION_MESSAGE = "emulation_message" CONF_EMULATION_OFF = "emulation_off" CONF_EMULATION_ON = "emulation_on" CONF_INCLUDE_ANDROID_APP_RECORD = "include_android_app_record" -CONF_MESSAGE = "message" -CONF_ON_FINISHED_WRITE = "on_finished_write" CONF_ON_EMULATED_TAG_SCAN = "on_emulated_tag_scan" CONF_PN7160_ID = "pn7160_id" CONF_POLLING_OFF = "polling_off" diff --git a/esphome/components/power_supply/__init__.py b/esphome/components/power_supply/__init__.py index 6735eddff3..01b541e4b5 100644 --- a/esphome/components/power_supply/__init__.py +++ b/esphome/components/power_supply/__init__.py @@ -1,15 +1,19 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN +from esphome.const import ( + CONF_ENABLE_ON_BOOT, + CONF_ENABLE_TIME, + CONF_ID, + CONF_KEEP_ON_TIME, + CONF_PIN, +) CODEOWNERS = ["@esphome/core"] power_supply_ns = cg.esphome_ns.namespace("power_supply") PowerSupply = power_supply_ns.class_("PowerSupply", cg.Component) MULTI_CONF = True -CONF_ENABLE_ON_BOOT = "enable_on_boot" - CONFIG_SCHEMA = cv.Schema( { cv.Required(CONF_ID): cv.declare_id(PowerSupply), diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py index 24e1019507..341c0c3f8a 100644 --- a/esphome/components/qmc5883l/sensor.py +++ b/esphome/components/qmc5883l/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Z, + CONF_HEADING, CONF_TEMPERATURE, CONF_ID, CONF_OVERSAMPLING, @@ -24,8 +25,6 @@ DEPENDENCIES = ["i2c"] qmc5883l_ns = cg.esphome_ns.namespace("qmc5883l") -CONF_HEADING = "heading" - QMC5883LComponent = qmc5883l_ns.class_( "QMC5883LComponent", cg.PollingComponent, i2c.I2CDevice ) diff --git a/esphome/components/resistance/sensor.py b/esphome/components/resistance/sensor.py index a84b439497..ce4459fc6d 100644 --- a/esphome/components/resistance/sensor.py +++ b/esphome/components/resistance/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor, resistance_sampler from esphome.const import ( + CONF_REFERENCE_VOLTAGE, CONF_SENSOR, STATE_CLASS_MEASUREMENT, UNIT_OHM, @@ -18,7 +19,6 @@ ResistanceSensor = resistance_ns.class_( resistance_sampler.ResistanceSampler, ) -CONF_REFERENCE_VOLTAGE = "reference_voltage" CONF_CONFIGURATION = "configuration" CONF_RESISTOR = "resistor" diff --git a/esphome/components/rpi_dpi_rgb/display.py b/esphome/components/rpi_dpi_rgb/display.py index 0cde16e0fb..969b9db78e 100644 --- a/esphome/components/rpi_dpi_rgb/display.py +++ b/esphome/components/rpi_dpi_rgb/display.py @@ -3,11 +3,13 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import display from esphome.const import ( + CONF_HSYNC_PIN, CONF_RESET_PIN, CONF_DATA_PINS, CONF_ID, CONF_IGNORE_STRAPPING_WARNING, CONF_DIMENSIONS, + CONF_VSYNC_PIN, CONF_WIDTH, CONF_HEIGHT, CONF_LAMBDA, @@ -29,8 +31,6 @@ DEPENDENCIES = ["esp32"] CONF_DE_PIN = "de_pin" CONF_PCLK_PIN = "pclk_pin" -CONF_HSYNC_PIN = "hsync_pin" -CONF_VSYNC_PIN = "vsync_pin" CONF_HSYNC_FRONT_PORCH = "hsync_front_porch" CONF_HSYNC_PULSE_WIDTH = "hsync_pulse_width" diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index f72b43fd37..a900c51a58 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_HUMIDITY, CONF_TEMPERATURE, CONF_CO2, + CONF_TEMPERATURE_OFFSET, CONF_UPDATE_INTERVAL, CONF_VALUE, DEVICE_CLASS_CARBON_DIOXIDE, @@ -36,7 +37,6 @@ ForceRecalibrationWithReference = scd30_ns.class_( CONF_AUTOMATIC_SELF_CALIBRATION = "automatic_self_calibration" CONF_ALTITUDE_COMPENSATION = "altitude_compensation" CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" -CONF_TEMPERATURE_OFFSET = "temperature_offset" CONFIG_SCHEMA = ( diff --git a/esphome/components/scd4x/sensor.py b/esphome/components/scd4x/sensor.py index 4c94d4257f..13027b6f88 100644 --- a/esphome/components/scd4x/sensor.py +++ b/esphome/components/scd4x/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_CO2, CONF_HUMIDITY, CONF_TEMPERATURE, + CONF_TEMPERATURE_OFFSET, CONF_VALUE, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, @@ -52,7 +53,6 @@ CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE = "ambient_pressure_compensation_source" CONF_AUTOMATIC_SELF_CALIBRATION = "automatic_self_calibration" CONF_MEASUREMENT_MODE = "measurement_mode" -CONF_TEMPERATURE_OFFSET = "temperature_offset" CONFIG_SCHEMA = ( diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py index 78b23e7b5e..483357f85b 100644 --- a/esphome/components/script/__init__.py +++ b/esphome/components/script/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID, CONF_MODE, CONF_PARAMETERS +from esphome.const import CONF_ID, CONF_MODE, CONF_PARAMETERS, CONF_RESTART from esphome.core import CORE, EsphomeError CODEOWNERS = ["@esphome/core"] @@ -19,7 +19,6 @@ ParallelScript = script_ns.class_("ParallelScript", Script) CONF_SCRIPT = "script" CONF_SINGLE = "single" -CONF_RESTART = "restart" CONF_QUEUED = "queued" CONF_PARALLEL = "parallel" CONF_MAX_RUNS = "max_runs" diff --git a/esphome/components/seeed_mr24hpc1/binary_sensor.py b/esphome/components/seeed_mr24hpc1/binary_sensor.py index e3e54d03f9..003db9f4a3 100644 --- a/esphome/components/seeed_mr24hpc1/binary_sensor.py +++ b/esphome/components/seeed_mr24hpc1/binary_sensor.py @@ -3,10 +3,10 @@ from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import ( DEVICE_CLASS_OCCUPANCY, + CONF_HAS_TARGET, ) from . import CONF_MR24HPC1_ID, MR24HPC1Component -CONF_HAS_TARGET = "has_target" CONFIG_SCHEMA = { cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), diff --git a/esphome/components/seeed_mr24hpc1/button/__init__.py b/esphome/components/seeed_mr24hpc1/button/__init__.py index 0a0e7a1865..59372e4100 100644 --- a/esphome/components/seeed_mr24hpc1/button/__init__.py +++ b/esphome/components/seeed_mr24hpc1/button/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import button import esphome.config_validation as cv from esphome.const import ( + CONF_RESTART, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_CONFIG, ICON_RESTART_ALERT, @@ -11,7 +12,6 @@ from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns RestartButton = mr24hpc1_ns.class_("RestartButton", button.Button) CustomSetEndButton = mr24hpc1_ns.class_("CustomSetEndButton", button.Button) -CONF_RESTART = "restart" CONF_CUSTOM_SET_END = "custom_set_end" CONFIG_SCHEMA = { diff --git a/esphome/components/seeed_mr24hpc1/number/__init__.py b/esphome/components/seeed_mr24hpc1/number/__init__.py index d9dfcb19a5..2055fc548c 100644 --- a/esphome/components/seeed_mr24hpc1/number/__init__.py +++ b/esphome/components/seeed_mr24hpc1/number/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import number import esphome.config_validation as cv from esphome.const import ( + CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG, ) from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns @@ -14,7 +15,6 @@ MotionTriggerTimeNumber = mr24hpc1_ns.class_("MotionTriggerTimeNumber", number.N MotionToRestTimeNumber = mr24hpc1_ns.class_("MotionToRestTimeNumber", number.Number) CustomUnmanTimeNumber = mr24hpc1_ns.class_("CustomUnmanTimeNumber", number.Number) -CONF_SENSITIVITY = "sensitivity" CONF_CUSTOM_MODE = "custom_mode" CONF_EXISTENCE_THRESHOLD = "existence_threshold" CONF_MOTION_THRESHOLD = "motion_threshold" diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 6f8ed42d25..13e859cc09 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor, sensirion_common from esphome.const import ( + CONF_COMPENSATION, CONF_ID, CONF_BASELINE, CONF_ECO2, @@ -30,7 +31,6 @@ SGP30Component = sgp30_ns.class_( CONF_ECO2_BASELINE = "eco2_baseline" CONF_TVOC_BASELINE = "tvoc_baseline" CONF_UPTIME = "uptime" -CONF_COMPENSATION = "compensation" CONF_HUMIDITY_SOURCE = "humidity_source" diff --git a/esphome/components/sgp4x/sensor.py b/esphome/components/sgp4x/sensor.py index 3d24f6c409..b7cec542bf 100644 --- a/esphome/components/sgp4x/sensor.py +++ b/esphome/components/sgp4x/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor, sensirion_common from esphome.const import ( + CONF_COMPENSATION, CONF_ID, CONF_STORE_BASELINE, CONF_TEMPERATURE_SOURCE, @@ -23,7 +24,6 @@ SGP4xComponent = sgp4x_ns.class_( ) CONF_ALGORITHM_TUNING = "algorithm_tuning" -CONF_COMPENSATION = "compensation" CONF_GAIN_FACTOR = "gain_factor" CONF_GATING_MAX_DURATION_MINUTES = "gating_max_duration_minutes" CONF_HUMIDITY_SOURCE = "humidity_source" diff --git a/esphome/components/sim800l/__init__.py b/esphome/components/sim800l/__init__.py index 698e3cda9e..faa6cefe27 100644 --- a/esphome/components/sim800l/__init__.py +++ b/esphome/components/sim800l/__init__.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome import automation from esphome.const import ( CONF_ID, + CONF_MESSAGE, CONF_TRIGGER_ID, ) from esphome.components import uart @@ -52,7 +53,6 @@ CONF_ON_INCOMING_CALL = "on_incoming_call" CONF_ON_CALL_CONNECTED = "on_call_connected" CONF_ON_CALL_DISCONNECTED = "on_call_disconnected" CONF_RECIPIENT = "recipient" -CONF_MESSAGE = "message" CONF_USSD = "ussd" CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/sn74hc595/__init__.py b/esphome/components/sn74hc595/__init__.py index e0cd5e70ad..2fd49f6824 100644 --- a/esphome/components/sn74hc595/__init__.py +++ b/esphome/components/sn74hc595/__init__.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_INVERTED, CONF_DATA_PIN, CONF_CLOCK_PIN, + CONF_OE_PIN, CONF_OUTPUT, CONF_TYPE, ) @@ -30,7 +31,6 @@ SN74HC595GPIOPin = sn74hc595_ns.class_( CONF_SN74HC595 = "sn74hc595" CONF_LATCH_PIN = "latch_pin" -CONF_OE_PIN = "oe_pin" CONF_SR_COUNT = "sr_count" TYPE_GPIO = "gpio" diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py index e33eeb89ae..516d770f8b 100644 --- a/esphome/components/st7701s/display.py +++ b/esphome/components/st7701s/display.py @@ -7,10 +7,12 @@ from esphome.components import ( ) from esphome.const import ( CONF_DC_PIN, + CONF_HSYNC_PIN, CONF_RESET_PIN, CONF_DATA_PINS, CONF_ID, CONF_DIMENSIONS, + CONF_VSYNC_PIN, CONF_WIDTH, CONF_HEIGHT, CONF_LAMBDA, @@ -44,8 +46,6 @@ from .init_sequences import ( CONF_INIT_SEQUENCE = "init_sequence" CONF_DE_PIN = "de_pin" CONF_PCLK_PIN = "pclk_pin" -CONF_HSYNC_PIN = "hsync_pin" -CONF_VSYNC_PIN = "vsync_pin" CONF_HSYNC_PULSE_WIDTH = "hsync_pulse_width" CONF_HSYNC_BACK_PORCH = "hsync_back_porch" diff --git a/esphome/components/tlc5947/__init__.py b/esphome/components/tlc5947/__init__.py index 8a4bd5e0ce..528d690fab 100644 --- a/esphome/components/tlc5947/__init__.py +++ b/esphome/components/tlc5947/__init__.py @@ -9,10 +9,10 @@ from esphome.const import ( CONF_DATA_PIN, CONF_ID, CONF_NUM_CHIPS, + CONF_OE_PIN, ) CONF_LAT_PIN = "lat_pin" -CONF_OE_PIN = "oe_pin" CODEOWNERS = ["@rnauber"] diff --git a/esphome/components/touchscreen/__init__.py b/esphome/components/touchscreen/__init__.py index 400ba7d5ad..b2d3f60d2b 100644 --- a/esphome/components/touchscreen/__init__.py +++ b/esphome/components/touchscreen/__init__.py @@ -5,6 +5,7 @@ from esphome.components import display from esphome import automation from esphome.const import ( + CONF_DISPLAY, CONF_ON_TOUCH, CONF_ON_RELEASE, CONF_ON_UPDATE, @@ -31,7 +32,6 @@ TouchPoints_t = cg.std_vector.template(TouchPoint) TouchPoints_t_const_ref = TouchPoints_t.operator("ref").operator("const") TouchListener = touchscreen_ns.class_("TouchListener") -CONF_DISPLAY = "display" CONF_TOUCHSCREEN_ID = "touchscreen_id" CONF_REPORT_INTERVAL = "report_interval" # not used yet: CONF_TOUCH_TIMEOUT = "touch_timeout" diff --git a/esphome/components/whynter/climate.py b/esphome/components/whynter/climate.py index b9dc5868bc..1d576344e6 100644 --- a/esphome/components/whynter/climate.py +++ b/esphome/components/whynter/climate.py @@ -1,14 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import climate_ir -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_USE_FAHRENHEIT AUTO_LOAD = ["climate_ir"] whynter_ns = cg.esphome_ns.namespace("whynter") Whynter = whynter_ns.class_("Whynter", climate_ir.ClimateIR) -CONF_USE_FAHRENHEIT = "use_fahrenheit" CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( { diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 32c9d07046..e0a17e9a2a 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_DNS2, CONF_DOMAIN, CONF_ENABLE_BTM, + CONF_ENABLE_ON_BOOT, CONF_ENABLE_RRM, CONF_FAST_CONNECT, CONF_GATEWAY, @@ -268,7 +269,6 @@ def _validate(config): CONF_OUTPUT_POWER = "output_power" CONF_PASSIVE_SCAN = "passive_scan" -CONF_ENABLE_ON_BOOT = "enable_on_boot" CONFIG_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 2d68cd001e..7612c7d964 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -22,6 +22,8 @@ CONF_PEER_ALLOWED_IPS = "peer_allowed_ips" CONF_PEER_PERSISTENT_KEEPALIVE = "peer_persistent_keepalive" CONF_REQUIRE_CONNECTION_TO_PROCEED = "require_connection_to_proceed" +CONF_WIREGUARD_ID = "wireguard_id" + DEPENDENCIES = ["time"] CODEOWNERS = ["@lhoracek", "@droscy", "@thomas0bernard"] diff --git a/esphome/components/wireguard/binary_sensor.py b/esphome/components/wireguard/binary_sensor.py index bf60aaa1d6..7344558659 100644 --- a/esphome/components/wireguard/binary_sensor.py +++ b/esphome/components/wireguard/binary_sensor.py @@ -7,9 +7,8 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ) -from . import Wireguard +from . import CONF_WIREGUARD_ID, Wireguard -CONF_WIREGUARD_ID = "wireguard_id" CONF_ENABLED = "enabled" DEPENDENCIES = ["wireguard"] diff --git a/esphome/components/wireguard/sensor.py b/esphome/components/wireguard/sensor.py index 78cb619701..85703d24b3 100644 --- a/esphome/components/wireguard/sensor.py +++ b/esphome/components/wireguard/sensor.py @@ -6,9 +6,8 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ) -from . import Wireguard +from . import CONF_WIREGUARD_ID, Wireguard -CONF_WIREGUARD_ID = "wireguard_id" CONF_LATEST_HANDSHAKE = "latest_handshake" DEPENDENCIES = ["wireguard"] diff --git a/esphome/components/wireguard/text_sensor.py b/esphome/components/wireguard/text_sensor.py index 3b05f6173e..51614a1a28 100644 --- a/esphome/components/wireguard/text_sensor.py +++ b/esphome/components/wireguard/text_sensor.py @@ -6,9 +6,7 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ) -from . import Wireguard - -CONF_WIREGUARD_ID = "wireguard_id" +from . import CONF_WIREGUARD_ID, Wireguard DEPENDENCIES = ["wireguard"] diff --git a/esphome/const.py b/esphome/const.py index 324b32e847..1a8f9a06e1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -141,6 +141,7 @@ CONF_COMMAND_RETAIN = "command_retain" CONF_COMMAND_TOPIC = "command_topic" CONF_COMMENT = "comment" CONF_COMMIT = "commit" +CONF_COMPENSATION = "compensation" CONF_COMPILE_PROCESS_LIMIT = "compile_process_limit" CONF_COMPONENT_ID = "component_id" CONF_COMPONENTS = "components" @@ -216,6 +217,7 @@ CONF_DISCOVERY_OBJECT_ID_GENERATOR = "discovery_object_id_generator" CONF_DISCOVERY_PREFIX = "discovery_prefix" CONF_DISCOVERY_RETAIN = "discovery_retain" CONF_DISCOVERY_UNIQUE_ID_GENERATOR = "discovery_unique_id_generator" +CONF_DISPLAY = "display" CONF_DISTANCE = "distance" CONF_DITHER = "dither" CONF_DIV_RATIO = "div_ratio" @@ -239,6 +241,7 @@ CONF_EFFECTS = "effects" CONF_ELSE = "else" CONF_ENABLE_BTM = "enable_btm" CONF_ENABLE_IPV6 = "enable_ipv6" +CONF_ENABLE_ON_BOOT = "enable_on_boot" CONF_ENABLE_PIN = "enable_pin" CONF_ENABLE_PRIVATE_NETWORK_ACCESS = "enable_private_network_access" CONF_ENABLE_RRM = "enable_rrm" @@ -261,6 +264,7 @@ CONF_EXTERNAL_CLOCK_INPUT = "external_clock_input" CONF_EXTERNAL_COMPONENTS = "external_components" CONF_EXTERNAL_TEMPERATURE = "external_temperature" CONF_EXTERNAL_VCC = "external_vcc" +CONF_FACTORY_RESET = "factory_reset" CONF_FALLING_EDGE = "falling_edge" CONF_FAMILY = "family" CONF_FAN_MODE = "fan_mode" @@ -323,7 +327,11 @@ CONF_GYROSCOPE_X = "gyroscope_x" CONF_GYROSCOPE_Y = "gyroscope_y" CONF_GYROSCOPE_Z = "gyroscope_z" CONF_HARDWARE_UART = "hardware_uart" +CONF_HAS_MOVING_TARGET = "has_moving_target" +CONF_HAS_STILL_TARGET = "has_still_target" +CONF_HAS_TARGET = "has_target" CONF_HEAD = "head" +CONF_HEADING = "heading" CONF_HEARTBEAT = "heartbeat" CONF_HEAT_ACTION = "heat_action" CONF_HEAT_DEADBAND = "heat_deadband" @@ -337,6 +345,7 @@ CONF_HIGH = "high" CONF_HIGH_VOLTAGE_REFERENCE = "high_voltage_reference" CONF_HOUR = "hour" CONF_HOURS = "hours" +CONF_HSYNC_PIN = "hsync_pin" CONF_HUMIDITY = "humidity" CONF_HUMIDITY_SENSOR = "humidity_sensor" CONF_HYSTERESIS = "hysteresis" @@ -377,6 +386,7 @@ CONF_INTERLOCK = "interlock" CONF_INTERNAL = "internal" CONF_INTERNAL_FILTER = "internal_filter" CONF_INTERNAL_FILTER_MODE = "internal_filter_mode" +CONF_INTERNAL_TEMPERATURE = "internal_temperature" CONF_INTERRUPT = "interrupt" CONF_INTERRUPT_PIN = "interrupt_pin" CONF_INTERVAL = "interval" @@ -446,6 +456,7 @@ CONF_MEASUREMENT_SEQUENCE_NUMBER = "measurement_sequence_number" CONF_MEDIA_PLAYER = "media_player" CONF_MEDIUM = "medium" CONF_MEMORY_BLOCKS = "memory_blocks" +CONF_MESSAGE = "message" CONF_METHOD = "method" CONF_MICROPHONE = "microphone" CONF_MIN_BRIGHTNESS = "min_brightness" @@ -499,6 +510,7 @@ CONF_NUM_LEDS = "num_leds" CONF_NUM_SCANS = "num_scans" CONF_NUMBER = "number" CONF_NUMBER_DATAPOINT = "number_datapoint" +CONF_OE_PIN = "oe_pin" CONF_OFF_MODE = "off_mode" CONF_OFF_SPEED_CYCLE = "off_speed_cycle" CONF_OFFSET = "offset" @@ -526,6 +538,7 @@ CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched" CONF_ON_FINGER_SCAN_MISPLACED = "on_finger_scan_misplaced" CONF_ON_FINGER_SCAN_START = "on_finger_scan_start" CONF_ON_FINGER_SCAN_UNMATCHED = "on_finger_scan_unmatched" +CONF_ON_FINISHED_WRITE = "on_finished_write" CONF_ON_JSON_MESSAGE = "on_json_message" CONF_ON_LOCK = "on_lock" CONF_ON_LOOP = "on_loop" @@ -568,6 +581,7 @@ CONF_OSCILLATION_COMMAND_TOPIC = "oscillation_command_topic" CONF_OSCILLATION_OUTPUT = "oscillation_output" CONF_OSCILLATION_STATE_TOPIC = "oscillation_state_topic" CONF_OTA = "ota" +CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_OUTPUT = "output" CONF_OUTPUT_ID = "output_id" CONF_OUTPUTS = "outputs" @@ -666,6 +680,7 @@ CONF_RED = "red" CONF_REF = "ref" CONF_REFERENCE_RESISTANCE = "reference_resistance" CONF_REFERENCE_TEMPERATURE = "reference_temperature" +CONF_REFERENCE_VOLTAGE = "reference_voltage" CONF_REFRESH = "refresh" CONF_RELABEL = "relabel" CONF_REPEAT = "repeat" @@ -674,6 +689,7 @@ CONF_RESET_DURATION = "reset_duration" CONF_RESET_PIN = "reset_pin" CONF_RESIZE = "resize" CONF_RESOLUTION = "resolution" +CONF_RESTART = "restart" CONF_RESTORE = "restore" CONF_RESTORE_MODE = "restore_mode" CONF_RESTORE_STATE = "restore_state" @@ -711,6 +727,7 @@ CONF_SEL_PIN = "sel_pin" CONF_SEND_EVERY = "send_every" CONF_SEND_FIRST_AT = "send_first_at" CONF_SENSING_PIN = "sensing_pin" +CONF_SENSITIVITY = "sensitivity" CONF_SENSOR = "sensor" CONF_SENSOR_DATAPOINT = "sensor_datapoint" CONF_SENSOR_ID = "sensor_id" @@ -804,6 +821,7 @@ CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC = "target_temperature_low_command_topi CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC = "target_temperature_low_state_topic" CONF_TARGET_TEMPERATURE_STATE_TOPIC = "target_temperature_state_topic" CONF_TEMPERATURE = "temperature" +CONF_TEMPERATURE_OFFSET = "temperature_offset" CONF_TEMPERATURE_SOURCE = "temperature_source" CONF_TEMPERATURE_STEP = "temperature_step" CONF_TEXT_SENSORS = "text_sensors" @@ -852,6 +870,7 @@ CONF_UPDATE_ON_BOOT = "update_on_boot" CONF_URL = "url" CONF_USE_ABBREVIATIONS = "use_abbreviations" CONF_USE_ADDRESS = "use_address" +CONF_USE_FAHRENHEIT = "use_fahrenheit" CONF_USERNAME = "username" CONF_UUID = "uuid" CONF_VALIDITY_PERIOD = "validity_period" @@ -865,7 +884,9 @@ CONF_VISUAL = "visual" CONF_VOLTAGE = "voltage" CONF_VOLTAGE_ATTENUATION = "voltage_attenuation" CONF_VOLTAGE_DIVIDER = "voltage_divider" +CONF_VOLTAGE_GAIN = "voltage_gain" CONF_VOLUME = "volume" +CONF_VSYNC_PIN = "vsync_pin" CONF_WAIT_TIME = "wait_time" CONF_WAIT_UNTIL = "wait_until" CONF_WAKEUP_PIN = "wakeup_pin" diff --git a/script/ci-custom.py b/script/ci-custom.py index abe004dba3..704962fa97 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -476,7 +476,7 @@ def lint_no_byte_datatype(fname, match): def lint_constants_usage(): errs = [] for constant, uses in CONSTANTS_USES.items(): - if len(uses) < 4: + if len(uses) < 3: continue errs.append( f"Constant {highlight(constant)} is defined in {len(uses)} files. Please move all definitions of the " From f1584205afcaf4863446f140d19f87e1f8192e4e Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 5 May 2024 21:52:47 +0200 Subject: [PATCH 1669/2607] [core] Rename ALWAYS_INLINE to ESPHOME_ALWAYS_INLINE (#6636) --- esphome/components/display/rect.h | 4 +- .../components/light/esp_color_correction.h | 20 +++---- esphome/components/light/esp_hsv_color.h | 8 +-- esphome/core/color.h | 52 ++++++++++--------- esphome/core/helpers.h | 2 +- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/esphome/components/display/rect.h b/esphome/components/display/rect.h index a728ddd132..f55c2fe201 100644 --- a/esphome/components/display/rect.h +++ b/esphome/components/display/rect.h @@ -15,11 +15,11 @@ class Rect { int16_t h; ///< Height of region Rect() : x(VALUE_NO_SET), y(VALUE_NO_SET), w(VALUE_NO_SET), h(VALUE_NO_SET) {} // NOLINT - inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE : x(x), y(y), w(w), h(h) {} + inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ESPHOME_ALWAYS_INLINE : x(x), y(y), w(w), h(h) {} inline int16_t x2() const { return this->x + this->w; }; ///< X coordinate of corner inline int16_t y2() const { return this->y + this->h; }; ///< Y coordinate of corner - inline bool is_set() const ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } + inline bool is_set() const ESPHOME_ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); } void expand(int16_t horizontal, int16_t vertical); diff --git a/esphome/components/light/esp_color_correction.h b/esphome/components/light/esp_color_correction.h index 8788246cfc..eedd71ab27 100644 --- a/esphome/components/light/esp_color_correction.h +++ b/esphome/components/light/esp_color_correction.h @@ -11,54 +11,54 @@ class ESPColorCorrection { void set_max_brightness(const Color &max_brightness) { this->max_brightness_ = max_brightness; } void set_local_brightness(uint8_t local_brightness) { this->local_brightness_ = local_brightness; } void calculate_gamma_table(float gamma); - inline Color color_correct(Color color) const ALWAYS_INLINE { + inline Color color_correct(Color color) const ESPHOME_ALWAYS_INLINE { // corrected = (uncorrected * max_brightness * local_brightness) ^ gamma return Color(this->color_correct_red(color.red), this->color_correct_green(color.green), this->color_correct_blue(color.blue), this->color_correct_white(color.white)); } - inline uint8_t color_correct_red(uint8_t red) const ALWAYS_INLINE { + inline uint8_t color_correct_red(uint8_t red) const ESPHOME_ALWAYS_INLINE { uint8_t res = esp_scale8(esp_scale8(red, this->max_brightness_.red), this->local_brightness_); return this->gamma_table_[res]; } - inline uint8_t color_correct_green(uint8_t green) const ALWAYS_INLINE { + inline uint8_t color_correct_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { uint8_t res = esp_scale8(esp_scale8(green, this->max_brightness_.green), this->local_brightness_); return this->gamma_table_[res]; } - inline uint8_t color_correct_blue(uint8_t blue) const ALWAYS_INLINE { + inline uint8_t color_correct_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { uint8_t res = esp_scale8(esp_scale8(blue, this->max_brightness_.blue), this->local_brightness_); return this->gamma_table_[res]; } - inline uint8_t color_correct_white(uint8_t white) const ALWAYS_INLINE { + inline uint8_t color_correct_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { uint8_t res = esp_scale8(esp_scale8(white, this->max_brightness_.white), this->local_brightness_); return this->gamma_table_[res]; } - inline Color color_uncorrect(Color color) const ALWAYS_INLINE { + inline Color color_uncorrect(Color color) const ESPHOME_ALWAYS_INLINE { // uncorrected = corrected^(1/gamma) / (max_brightness * local_brightness) return Color(this->color_uncorrect_red(color.red), this->color_uncorrect_green(color.green), this->color_uncorrect_blue(color.blue), this->color_uncorrect_white(color.white)); } - inline uint8_t color_uncorrect_red(uint8_t red) const ALWAYS_INLINE { + inline uint8_t color_uncorrect_red(uint8_t red) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL; uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; return res; } - inline uint8_t color_uncorrect_green(uint8_t green) const ALWAYS_INLINE { + inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.green == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL; uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; return res; } - inline uint8_t color_uncorrect_blue(uint8_t blue) const ALWAYS_INLINE { + inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL; uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; return res; } - inline uint8_t color_uncorrect_white(uint8_t white) const ALWAYS_INLINE { + inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.white == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL; diff --git a/esphome/components/light/esp_hsv_color.h b/esphome/components/light/esp_hsv_color.h index e0aa388875..39f5e55707 100644 --- a/esphome/components/light/esp_hsv_color.h +++ b/esphome/components/light/esp_hsv_color.h @@ -24,11 +24,11 @@ struct ESPHSVColor { }; uint8_t raw[3]; }; - inline ESPHSVColor() ALWAYS_INLINE : h(0), s(0), v(0) { // NOLINT + inline ESPHSVColor() ESPHOME_ALWAYS_INLINE : h(0), s(0), v(0) { // NOLINT } - inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ALWAYS_INLINE : hue(hue), - saturation(saturation), - value(value) {} + inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ESPHOME_ALWAYS_INLINE : hue(hue), + saturation(saturation), + value(value) {} Color to_rgb() const; }; diff --git a/esphome/core/color.h b/esphome/core/color.h index fb72973017..8965d9fc83 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -31,19 +31,19 @@ struct Color { uint32_t raw_32; }; - inline Color() ALWAYS_INLINE : r(0), g(0), b(0), w(0) {} // NOLINT - inline Color(uint8_t red, uint8_t green, uint8_t blue) ALWAYS_INLINE : r(red), g(green), b(blue), w(0) {} + inline Color() ESPHOME_ALWAYS_INLINE : r(0), g(0), b(0), w(0) {} // NOLINT + inline Color(uint8_t red, uint8_t green, uint8_t blue) ESPHOME_ALWAYS_INLINE : r(red), g(green), b(blue), w(0) {} - inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ALWAYS_INLINE : r(red), - g(green), - b(blue), - w(white) {} - inline explicit Color(uint32_t colorcode) ALWAYS_INLINE : r((colorcode >> 16) & 0xFF), - g((colorcode >> 8) & 0xFF), - b((colorcode >> 0) & 0xFF), - w((colorcode >> 24) & 0xFF) {} + inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ESPHOME_ALWAYS_INLINE : r(red), + g(green), + b(blue), + w(white) {} + inline explicit Color(uint32_t colorcode) ESPHOME_ALWAYS_INLINE : r((colorcode >> 16) & 0xFF), + g((colorcode >> 8) & 0xFF), + b((colorcode >> 0) & 0xFF), + w((colorcode >> 24) & 0xFF) {} - inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; } + inline bool is_on() ESPHOME_ALWAYS_INLINE { return this->raw_32 != 0; } inline bool operator==(const Color &rhs) { // NOLINT return this->raw_32 == rhs.raw_32; @@ -57,31 +57,33 @@ struct Color { inline bool operator!=(uint32_t colorcode) { // NOLINT return this->raw_32 != colorcode; } - inline uint8_t &operator[](uint8_t x) ALWAYS_INLINE { return this->raw[x]; } - inline Color operator*(uint8_t scale) const ALWAYS_INLINE { + inline uint8_t &operator[](uint8_t x) ESPHOME_ALWAYS_INLINE { return this->raw[x]; } + inline Color operator*(uint8_t scale) const ESPHOME_ALWAYS_INLINE { return Color(esp_scale8(this->red, scale), esp_scale8(this->green, scale), esp_scale8(this->blue, scale), esp_scale8(this->white, scale)); } - inline Color operator~() const ALWAYS_INLINE { return Color(255 - this->red, 255 - this->green, 255 - this->blue); } - inline Color &operator*=(uint8_t scale) ALWAYS_INLINE { + inline Color operator~() const ESPHOME_ALWAYS_INLINE { + return Color(255 - this->red, 255 - this->green, 255 - this->blue); + } + inline Color &operator*=(uint8_t scale) ESPHOME_ALWAYS_INLINE { this->red = esp_scale8(this->red, scale); this->green = esp_scale8(this->green, scale); this->blue = esp_scale8(this->blue, scale); this->white = esp_scale8(this->white, scale); return *this; } - inline Color operator*(const Color &scale) const ALWAYS_INLINE { + inline Color operator*(const Color &scale) const ESPHOME_ALWAYS_INLINE { return Color(esp_scale8(this->red, scale.red), esp_scale8(this->green, scale.green), esp_scale8(this->blue, scale.blue), esp_scale8(this->white, scale.white)); } - inline Color &operator*=(const Color &scale) ALWAYS_INLINE { + inline Color &operator*=(const Color &scale) ESPHOME_ALWAYS_INLINE { this->red = esp_scale8(this->red, scale.red); this->green = esp_scale8(this->green, scale.green); this->blue = esp_scale8(this->blue, scale.blue); this->white = esp_scale8(this->white, scale.white); return *this; } - inline Color operator+(const Color &add) const ALWAYS_INLINE { + inline Color operator+(const Color &add) const ESPHOME_ALWAYS_INLINE { Color ret; if (uint8_t(add.r + this->r) < this->r) ret.r = 255; @@ -101,10 +103,10 @@ struct Color { ret.w = this->w + add.w; return ret; } - inline Color &operator+=(const Color &add) ALWAYS_INLINE { return *this = (*this) + add; } - inline Color operator+(uint8_t add) const ALWAYS_INLINE { return (*this) + Color(add, add, add, add); } - inline Color &operator+=(uint8_t add) ALWAYS_INLINE { return *this = (*this) + add; } - inline Color operator-(const Color &subtract) const ALWAYS_INLINE { + inline Color &operator+=(const Color &add) ESPHOME_ALWAYS_INLINE { return *this = (*this) + add; } + inline Color operator+(uint8_t add) const ESPHOME_ALWAYS_INLINE { return (*this) + Color(add, add, add, add); } + inline Color &operator+=(uint8_t add) ESPHOME_ALWAYS_INLINE { return *this = (*this) + add; } + inline Color operator-(const Color &subtract) const ESPHOME_ALWAYS_INLINE { Color ret; if (subtract.r > this->r) ret.r = 0; @@ -124,11 +126,11 @@ struct Color { ret.w = this->w - subtract.w; return ret; } - inline Color &operator-=(const Color &subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } - inline Color operator-(uint8_t subtract) const ALWAYS_INLINE { + inline Color &operator-=(const Color &subtract) ESPHOME_ALWAYS_INLINE { return *this = (*this) - subtract; } + inline Color operator-(uint8_t subtract) const ESPHOME_ALWAYS_INLINE { return (*this) - Color(subtract, subtract, subtract, subtract); } - inline Color &operator-=(uint8_t subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } + inline Color &operator-=(uint8_t subtract) ESPHOME_ALWAYS_INLINE { return *this = (*this) - subtract; } static Color random_color() { uint32_t rand = random_uint32(); uint8_t w = rand >> 24; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index b2d72b0fab..809e7d6767 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -24,7 +24,7 @@ #define HOT __attribute__((hot)) #define ESPDEPRECATED(msg, when) __attribute__((deprecated(msg))) -#define ALWAYS_INLINE __attribute__((always_inline)) +#define ESPHOME_ALWAYS_INLINE __attribute__((always_inline)) #define PACKED __attribute__((packed)) // Various functions can be constexpr in C++14, but not in C++11 (because their body isn't just a return statement). From 8796a4c1a7b0446f77aa439692a2ca0aab6648ee Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 6 May 2024 00:10:49 +0200 Subject: [PATCH 1670/2607] print task name if logger is called from other than main thread (#6630) --- esphome/components/logger/logger.cpp | 21 ++++++++++++++++++++- esphome/components/logger/logger.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 166fe2693d..dac08fbbce 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -39,7 +39,23 @@ void Logger::write_header_(int level, const char *tag, int line) { const char *color = LOG_LEVEL_COLORS[level]; const char *letter = LOG_LEVEL_LETTERS[level]; - this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line); +#if defined(USE_ESP32) || defined(USE_LIBRETINY) + TaskHandle_t current_task = xTaskGetCurrentTaskHandle(); +#else + void *current_task = nullptr; +#endif + if (current_task == main_task_) { + this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line); + } else { + const char *thread_name = ""; +#if defined(USE_ESP32) + thread_name = pcTaskGetName(current_task); +#elif defined(USE_LIBRETINY) + thread_name = pcTaskGetTaskName(current_task); +#endif + this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line, + ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), thread_name, color); + } } void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) { // NOLINT @@ -127,6 +143,9 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate), tx_buffer_size_(tx_buffer_size) { // add 1 to buffer size for null terminator this->tx_buffer_ = new char[this->tx_buffer_size_ + 1]; // NOLINT +#if defined(USE_ESP32) || defined(USE_LIBRETINY) + this->main_task_ = xTaskGetCurrentTaskHandle(); +#endif } #ifdef USE_LOGGER_USB_CDC diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index f6c1574ffb..b55cfb0771 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -167,6 +167,7 @@ class Logger : public Component { CallbackManager log_callback_{}; /// Prevents recursive log calls, if true a log message is already being processed. bool recursion_guard_ = false; + void *main_task_ = nullptr; }; extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) From f78397c77e4403f510d7b02bd3b5a0f54b5b284d Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Mon, 6 May 2024 00:12:09 +0200 Subject: [PATCH 1671/2607] Fix recent definitions into `defines.h` (#6667) Co-authored-by: Keith Burzinski --- esphome/core/defines.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index b09373bcde..c2ad0f641c 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -15,18 +15,23 @@ #define ESPHOME_VARIANT "ESP32" // Feature flags +#define USE_ALARM_CONTROL_PANEL #define USE_API #define USE_API_NOISE #define USE_API_PLAINTEXT -#define USE_ALARM_CONTROL_PANEL #define USE_BINARY_SENSOR #define USE_BUTTON #define USE_CLIMATE #define USE_COVER +#define USE_DATETIME +#define USE_DATETIME_DATE +#define USE_DATETIME_DATETIME +#define USE_DATETIME_TIME #define USE_DEEP_SLEEP #define USE_EVENT #define USE_FAN #define USE_GRAPH +#define USE_GRAPHICAL_DISPLAY_MENU #define USE_HOMEASSISTANT_TIME #define USE_JSON #define USE_LIGHT @@ -37,10 +42,6 @@ #define USE_MQTT #define USE_NEXTION_TFT_UPLOAD #define USE_NUMBER -#define USE_DATETIME -#define USE_DATETIME_DATE -#define USE_DATETIME_TIME -#define USE_DATETIME_DATETIME #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK @@ -60,7 +61,6 @@ #define USE_VALVE #define USE_WIFI #define USE_WIFI_AP -#define USE_GRAPHICAL_DISPLAY_MENU // Arduino-specific feature flags #ifdef USE_ARDUINO @@ -78,17 +78,19 @@ // ESP32-specific feature flags #ifdef USE_ESP32 +#define USE_BLUETOOTH_PROXY +#define USE_ESP32_BLE #define USE_ESP32_BLE_CLIENT #define USE_ESP32_BLE_SERVER #define USE_ESP32_CAMERA #define USE_IMPROV -#define USE_SOCKET_IMPL_BSD_SOCKETS -#define USE_WIFI_11KV_SUPPORT -#define USE_BLUETOOTH_PROXY -#define USE_VOICE_ASSISTANT #define USE_MICROPHONE +#define USE_PSRAM +#define USE_SOCKET_IMPL_BSD_SOCKETS #define USE_SPEAKER #define USE_SPI +#define USE_VOICE_ASSISTANT +#define USE_WIFI_11KV_SUPPORT #ifdef USE_ARDUINO #define USE_ARDUINO_VERSION_CODE VERSION_CODE(2, 0, 5) From 833d31ef7a0fdef1c434ec1d188b13a9e74d0091 Mon Sep 17 00:00:00 2001 From: mkmer Date: Sun, 5 May 2024 18:48:09 -0400 Subject: [PATCH 1672/2607] Add fast update to HMC5883L (#6669) --- esphome/components/hmc5883l/hmc5883l.cpp | 5 +++++ esphome/components/hmc5883l/hmc5883l.h | 1 + 2 files changed, 6 insertions(+) diff --git a/esphome/components/hmc5883l/hmc5883l.cpp b/esphome/components/hmc5883l/hmc5883l.cpp index de3903d7e2..24f4b3f8f1 100644 --- a/esphome/components/hmc5883l/hmc5883l.cpp +++ b/esphome/components/hmc5883l/hmc5883l.cpp @@ -1,5 +1,6 @@ #include "hmc5883l.h" #include "esphome/core/log.h" +#include "esphome/core/application.h" namespace esphome { namespace hmc5883l { @@ -31,6 +32,10 @@ void HMC5883LComponent::setup() { return; } + if (this->get_update_interval() < App.get_loop_interval()) { + high_freq_.start(); + } + if (id[0] != 0x48 || id[1] != 0x34 || id[2] != 0x33) { this->error_code_ = ID_REGISTERS; this->mark_failed(); diff --git a/esphome/components/hmc5883l/hmc5883l.h b/esphome/components/hmc5883l/hmc5883l.h index 3481f45dc8..06fba2af9d 100644 --- a/esphome/components/hmc5883l/hmc5883l.h +++ b/esphome/components/hmc5883l/hmc5883l.h @@ -63,6 +63,7 @@ class HMC5883LComponent : public PollingComponent, public i2c::I2CDevice { COMMUNICATION_FAILED, ID_REGISTERS, } error_code_; + HighFrequencyLoopRequester high_freq_; }; } // namespace hmc5883l From 599dbf27e068e4c69ad60b78ec11c5e46bb32992 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Mon, 6 May 2024 04:19:25 +0200 Subject: [PATCH 1673/2607] Minor tidy up of BME280 code (#6672) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bme280_base/__init__.py | 107 ++++++++++++++++++ esphome/components/bme280_base/sensor.py | 106 ----------------- esphome/components/bme280_i2c/sensor.py | 8 +- esphome/components/bme280_spi/__init__.py | 1 - esphome/components/bme280_spi/bme280_spi.cpp | 29 +++-- esphome/components/bme280_spi/sensor.py | 13 +-- tests/components/bme280_i2c/common.yaml | 19 ++++ .../bme280_i2c/test.esp32-c3-idf.yaml | 21 +--- .../components/bme280_i2c/test.esp32-c3.yaml | 21 +--- .../components/bme280_i2c/test.esp32-idf.yaml | 21 +--- tests/components/bme280_i2c/test.esp32.yaml | 21 +--- tests/components/bme280_i2c/test.esp8266.yaml | 21 +--- tests/components/bme280_i2c/test.rp2040.yaml | 21 +--- tests/components/bme280_spi/common.yaml | 20 ++++ .../bme280_spi/test.esp32-c3-idf.yaml | 24 +--- .../components/bme280_spi/test.esp32-c3.yaml | 24 +--- .../components/bme280_spi/test.esp32-idf.yaml | 24 +--- tests/components/bme280_spi/test.esp32.yaml | 24 +--- tests/components/bme280_spi/test.esp8266.yaml | 24 +--- tests/components/bme280_spi/test.rp2040.yaml | 24 +--- tests/test1.yaml | 29 ----- 21 files changed, 231 insertions(+), 371 deletions(-) delete mode 100644 esphome/components/bme280_base/sensor.py create mode 100644 tests/components/bme280_i2c/common.yaml create mode 100644 tests/components/bme280_spi/common.yaml diff --git a/esphome/components/bme280_base/__init__.py b/esphome/components/bme280_base/__init__.py index f70ffa9520..6a5f7e1127 100644 --- a/esphome/components/bme280_base/__init__.py +++ b/esphome/components/bme280_base/__init__.py @@ -1 +1,108 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_HUMIDITY, + CONF_ID, + CONF_IIR_FILTER, + CONF_OVERSAMPLING, + CONF_PRESSURE, + CONF_TEMPERATURE, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, + UNIT_PERCENT, +) + CODEOWNERS = ["@esphome/core"] + +bme280_ns = cg.esphome_ns.namespace("bme280_base") +BME280Oversampling = bme280_ns.enum("BME280Oversampling") +OVERSAMPLING_OPTIONS = { + "NONE": BME280Oversampling.BME280_OVERSAMPLING_NONE, + "1X": BME280Oversampling.BME280_OVERSAMPLING_1X, + "2X": BME280Oversampling.BME280_OVERSAMPLING_2X, + "4X": BME280Oversampling.BME280_OVERSAMPLING_4X, + "8X": BME280Oversampling.BME280_OVERSAMPLING_8X, + "16X": BME280Oversampling.BME280_OVERSAMPLING_16X, +} + +BME280IIRFilter = bme280_ns.enum("BME280IIRFilter") +IIR_FILTER_OPTIONS = { + "OFF": BME280IIRFilter.BME280_IIR_FILTER_OFF, + "2X": BME280IIRFilter.BME280_IIR_FILTER_2X, + "4X": BME280IIRFilter.BME280_IIR_FILTER_4X, + "8X": BME280IIRFilter.BME280_IIR_FILTER_8X, + "16X": BME280IIRFilter.BME280_IIR_FILTER_16X, +} + +CONFIG_SCHEMA_BASE = cv.Schema( + { + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=1, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( + IIR_FILTER_OPTIONS, upper=True + ), + } +).extend(cv.polling_component_schema("60s")) + + +async def to_code_base(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) + + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) + cg.add(var.set_pressure_sensor(sens)) + cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) + + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) + cg.add(var.set_humidity_sensor(sens)) + cg.add(var.set_humidity_oversampling(humidity_config[CONF_OVERSAMPLING])) + + cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) + + return var diff --git a/esphome/components/bme280_base/sensor.py b/esphome/components/bme280_base/sensor.py deleted file mode 100644 index 3a745ed348..0000000000 --- a/esphome/components/bme280_base/sensor.py +++ /dev/null @@ -1,106 +0,0 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import sensor -from esphome.const import ( - CONF_HUMIDITY, - CONF_ID, - CONF_IIR_FILTER, - CONF_OVERSAMPLING, - CONF_PRESSURE, - CONF_TEMPERATURE, - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_PRESSURE, - DEVICE_CLASS_TEMPERATURE, - STATE_CLASS_MEASUREMENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, - UNIT_PERCENT, -) - -bme280_ns = cg.esphome_ns.namespace("bme280_base") -BME280Oversampling = bme280_ns.enum("BME280Oversampling") -OVERSAMPLING_OPTIONS = { - "NONE": BME280Oversampling.BME280_OVERSAMPLING_NONE, - "1X": BME280Oversampling.BME280_OVERSAMPLING_1X, - "2X": BME280Oversampling.BME280_OVERSAMPLING_2X, - "4X": BME280Oversampling.BME280_OVERSAMPLING_4X, - "8X": BME280Oversampling.BME280_OVERSAMPLING_8X, - "16X": BME280Oversampling.BME280_OVERSAMPLING_16X, -} - -BME280IIRFilter = bme280_ns.enum("BME280IIRFilter") -IIR_FILTER_OPTIONS = { - "OFF": BME280IIRFilter.BME280_IIR_FILTER_OFF, - "2X": BME280IIRFilter.BME280_IIR_FILTER_2X, - "4X": BME280IIRFilter.BME280_IIR_FILTER_4X, - "8X": BME280IIRFilter.BME280_IIR_FILTER_8X, - "16X": BME280IIRFilter.BME280_IIR_FILTER_16X, -} - -CONFIG_SCHEMA_BASE = cv.Schema( - { - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=1, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - unit_of_measurement=UNIT_PERCENT, - accuracy_decimals=1, - device_class=DEVICE_CLASS_HUMIDITY, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( - IIR_FILTER_OPTIONS, upper=True - ), - } -).extend(cv.polling_component_schema("60s")) - - -async def to_code(config, func=None): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - if func is not None: - await func(var, config) - - if temperature_config := config.get(CONF_TEMPERATURE): - sens = await sensor.new_sensor(temperature_config) - cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) - - if pressure_config := config.get(CONF_PRESSURE): - sens = await sensor.new_sensor(pressure_config) - cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) - - if humidity_config := config.get(CONF_HUMIDITY): - sens = await sensor.new_sensor(humidity_config) - cg.add(var.set_humidity_sensor(sens)) - cg.add(var.set_humidity_oversampling(humidity_config[CONF_OVERSAMPLING])) - - cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) diff --git a/esphome/components/bme280_i2c/sensor.py b/esphome/components/bme280_i2c/sensor.py index 489c52969d..f3007ebaac 100644 --- a/esphome/components/bme280_i2c/sensor.py +++ b/esphome/components/bme280_i2c/sensor.py @@ -1,9 +1,10 @@ import esphome.codegen as cg +import esphome.config_validation as cv from esphome.components import i2c -from ..bme280_base.sensor import to_code as to_code_base, cv, CONFIG_SCHEMA_BASE +from ..bme280_base import to_code_base, CONFIG_SCHEMA_BASE -DEPENDENCIES = ["i2c"] AUTO_LOAD = ["bme280_base"] +DEPENDENCIES = ["i2c"] bme280_ns = cg.esphome_ns.namespace("bme280_i2c") BME280I2CComponent = bme280_ns.class_( @@ -16,4 +17,5 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( async def to_code(config): - await to_code_base(config, func=i2c.register_i2c_device) + var = await to_code_base(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bme280_spi/__init__.py b/esphome/components/bme280_spi/__init__.py index a1d33e4d7a..e69de29bb2 100644 --- a/esphome/components/bme280_spi/__init__.py +++ b/esphome/components/bme280_spi/__init__.py @@ -1 +0,0 @@ -CODEOWNERS = ["@apbodrov"] diff --git a/esphome/components/bme280_spi/bme280_spi.cpp b/esphome/components/bme280_spi/bme280_spi.cpp index 921128c8f5..c6ebfdfd0b 100644 --- a/esphome/components/bme280_spi/bme280_spi.cpp +++ b/esphome/components/bme280_spi/bme280_spi.cpp @@ -4,19 +4,19 @@ #include "bme280_spi.h" #include -int set_bit(uint8_t num, int position) { +namespace esphome { +namespace bme280_spi { + +uint8_t set_bit(uint8_t num, int position) { int mask = 1 << position; return num | mask; } -int clear_bit(uint8_t num, int position) { +uint8_t clear_bit(uint8_t num, int position) { int mask = 1 << position; return num & ~mask; } -namespace esphome { -namespace bme280_spi { - void BME280SPIComponent::setup() { this->spi_setup(); BME280Component::setup(); @@ -30,34 +30,33 @@ void BME280SPIComponent::setup() { bool BME280SPIComponent::read_byte(uint8_t a_register, uint8_t *data) { this->enable(); - // cause: *data = this->delegate_->transfer(tmp) doesnt work - this->delegate_->transfer(set_bit(a_register, 7)); - *data = this->delegate_->transfer(0); + this->transfer_byte(set_bit(a_register, 7)); + *data = this->transfer_byte(0); this->disable(); return true; } bool BME280SPIComponent::write_byte(uint8_t a_register, uint8_t data) { this->enable(); - this->delegate_->transfer(clear_bit(a_register, 7)); - this->delegate_->transfer(data); + this->transfer_byte(clear_bit(a_register, 7)); + this->transfer_byte(data); this->disable(); return true; } bool BME280SPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { this->enable(); - this->delegate_->transfer(set_bit(a_register, 7)); - this->delegate_->read_array(data, len); + this->transfer_byte(set_bit(a_register, 7)); + this->read_array(data, len); this->disable(); return true; } bool BME280SPIComponent::read_byte_16(uint8_t a_register, uint16_t *data) { this->enable(); - this->delegate_->transfer(set_bit(a_register, 7)); - ((uint8_t *) data)[1] = this->delegate_->transfer(0); - ((uint8_t *) data)[0] = this->delegate_->transfer(0); + this->transfer_byte(set_bit(a_register, 7)); + ((uint8_t *) data)[1] = this->transfer_byte(0); + ((uint8_t *) data)[0] = this->transfer_byte(0); this->disable(); return true; } diff --git a/esphome/components/bme280_spi/sensor.py b/esphome/components/bme280_spi/sensor.py index 3cfe1b3cdd..33a12318a5 100644 --- a/esphome/components/bme280_spi/sensor.py +++ b/esphome/components/bme280_spi/sensor.py @@ -1,13 +1,11 @@ import esphome.codegen as cg +import esphome.config_validation as cv from esphome.components import spi -from esphome.components.bme280_base.sensor import ( - to_code as to_code_base, - cv, - CONFIG_SCHEMA_BASE, -) +from ..bme280_base import to_code_base, CONFIG_SCHEMA_BASE -DEPENDENCIES = ["spi"] AUTO_LOAD = ["bme280_base"] +CODEOWNERS = ["@apbodrov"] +DEPENDENCIES = ["spi"] bme280_spi_ns = cg.esphome_ns.namespace("bme280_spi") @@ -21,4 +19,5 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( async def to_code(config): - await to_code_base(config, func=spi.register_spi_device) + var = await to_code_base(config) + await spi.register_spi_device(var, config) diff --git a/tests/components/bme280_i2c/common.yaml b/tests/components/bme280_i2c/common.yaml new file mode 100644 index 0000000000..e74ce9bf6d --- /dev/null +++ b/tests/components/bme280_i2c/common.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_bme280 + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: bme280_i2c + i2c_id: i2c_bme280 + address: 0x76 + temperature: + id: bme280_temperature + name: BME280 Temperature + humidity: + id: bme280_humidity + name: BME280 Humidity + pressure: + id: bme280_pressure + name: BME280 Pressure + update_interval: 15s diff --git a/tests/components/bme280_i2c/test.esp32-c3-idf.yaml b/tests/components/bme280_i2c/test.esp32-c3-idf.yaml index 070c2845d9..ee2c29ca4e 100644 --- a/tests/components/bme280_i2c/test.esp32-c3-idf.yaml +++ b/tests/components/bme280_i2c/test.esp32-c3-idf.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 5 - sda: 4 +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_i2c/test.esp32-c3.yaml b/tests/components/bme280_i2c/test.esp32-c3.yaml index 070c2845d9..ee2c29ca4e 100644 --- a/tests/components/bme280_i2c/test.esp32-c3.yaml +++ b/tests/components/bme280_i2c/test.esp32-c3.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 5 - sda: 4 +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_i2c/test.esp32-idf.yaml b/tests/components/bme280_i2c/test.esp32-idf.yaml index e379b98874..63c3bd6afd 100644 --- a/tests/components/bme280_i2c/test.esp32-idf.yaml +++ b/tests/components/bme280_i2c/test.esp32-idf.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 16 - sda: 17 +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_i2c/test.esp32.yaml b/tests/components/bme280_i2c/test.esp32.yaml index e379b98874..63c3bd6afd 100644 --- a/tests/components/bme280_i2c/test.esp32.yaml +++ b/tests/components/bme280_i2c/test.esp32.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 16 - sda: 17 +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_i2c/test.esp8266.yaml b/tests/components/bme280_i2c/test.esp8266.yaml index 070c2845d9..ee2c29ca4e 100644 --- a/tests/components/bme280_i2c/test.esp8266.yaml +++ b/tests/components/bme280_i2c/test.esp8266.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 5 - sda: 4 +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_i2c/test.rp2040.yaml b/tests/components/bme280_i2c/test.rp2040.yaml index 070c2845d9..ee2c29ca4e 100644 --- a/tests/components/bme280_i2c/test.rp2040.yaml +++ b/tests/components/bme280_i2c/test.rp2040.yaml @@ -1,18 +1,5 @@ -i2c: - - id: i2c_bme280 - scl: 5 - sda: 4 +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 -sensor: - - platform: bme280_i2c - address: 0x76 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/common.yaml b/tests/components/bme280_spi/common.yaml new file mode 100644 index 0000000000..303ecf9f73 --- /dev/null +++ b/tests/components/bme280_spi/common.yaml @@ -0,0 +1,20 @@ +spi: + - id: spi_bme280 + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +sensor: + - platform: bme280_spi + spi_id: spi_bme280 + cs_pin: ${cs_pin} + temperature: + id: bme280_temperature + name: BME280 Temperature + humidity: + id: bme280_humidity + name: BME280 Humidity + pressure: + id: bme280_pressure + name: BME280 Pressure + update_interval: 15s diff --git a/tests/components/bme280_spi/test.esp32-c3-idf.yaml b/tests/components/bme280_spi/test.esp32-c3-idf.yaml index 4bc7c14e6c..2415ba5dc6 100644 --- a/tests/components/bme280_spi/test.esp32-c3-idf.yaml +++ b/tests/components/bme280_spi/test.esp32-c3-idf.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 6 - mosi_pin: 7 - miso_pin: 5 +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 -sensor: - - platform: bme280_spi - cs_pin: 8 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/test.esp32-c3.yaml b/tests/components/bme280_spi/test.esp32-c3.yaml index 4bc7c14e6c..2415ba5dc6 100644 --- a/tests/components/bme280_spi/test.esp32-c3.yaml +++ b/tests/components/bme280_spi/test.esp32-c3.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 6 - mosi_pin: 7 - miso_pin: 5 +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 -sensor: - - platform: bme280_spi - cs_pin: 8 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/test.esp32-idf.yaml b/tests/components/bme280_spi/test.esp32-idf.yaml index ebb3d98213..54e027a614 100644 --- a/tests/components/bme280_spi/test.esp32-idf.yaml +++ b/tests/components/bme280_spi/test.esp32-idf.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 16 - mosi_pin: 17 - miso_pin: 15 +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 -sensor: - - platform: bme280_spi - cs_pin: 12 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/test.esp32.yaml b/tests/components/bme280_spi/test.esp32.yaml index ebb3d98213..54e027a614 100644 --- a/tests/components/bme280_spi/test.esp32.yaml +++ b/tests/components/bme280_spi/test.esp32.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 16 - mosi_pin: 17 - miso_pin: 15 +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 -sensor: - - platform: bme280_spi - cs_pin: 12 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/test.esp8266.yaml b/tests/components/bme280_spi/test.esp8266.yaml index 63013abb87..dbd158d030 100644 --- a/tests/components/bme280_spi/test.esp8266.yaml +++ b/tests/components/bme280_spi/test.esp8266.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 14 - mosi_pin: 13 - miso_pin: 12 +substitutions: + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + cs_pin: GPIO15 -sensor: - - platform: bme280_spi - cs_pin: 15 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/bme280_spi/test.rp2040.yaml b/tests/components/bme280_spi/test.rp2040.yaml index ba5cb483c6..f6c3f1eeca 100644 --- a/tests/components/bme280_spi/test.rp2040.yaml +++ b/tests/components/bme280_spi/test.rp2040.yaml @@ -1,19 +1,7 @@ -spi: - - id: spi_bme280 - clk_pin: 2 - mosi_pin: 3 - miso_pin: 4 +substitutions: + clk_pin: GPIO2 + mosi_pin: GPIO3 + miso_pin: GPIO4 + cs_pin: GPIO5 -sensor: - - platform: bme280_spi - cs_pin: 6 - temperature: - id: bme280_temperature - name: BME280 Temperature - humidity: - id: bme280_humidity - name: BME280 Humidity - pressure: - id: bme280_pressure - name: BME280 Pressure - update_interval: 15s +<<: !include common.yaml diff --git a/tests/test1.yaml b/tests/test1.yaml index 09994afa42..79b836da4a 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -705,35 +705,6 @@ sensor: update_interval: 30s mode: low_power i2c_id: i2c_bus - - platform: bme280_i2c - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - oversampling: none - humidity: - name: Outside Humidity - oversampling: 8x - address: 0x77 - iir_filter: 16x - update_interval: 15s - i2c_id: i2c_bus - - platform: bme280_spi - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - oversampling: none - humidity: - name: Outside Humidity - oversampling: 8x - cs_pin: - allow_other_uses: true - number: GPIO23 - iir_filter: 16x - update_interval: 15s - platform: bme680 temperature: name: Outside Temperature From f2caaf85c89f35fb65d136f38f558da62eb442fa Mon Sep 17 00:00:00 2001 From: Tomek Wasilczyk Date: Sun, 5 May 2024 20:19:13 -0700 Subject: [PATCH 1674/2607] External components: optional configurable path for git source (#6677) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/external_components/__init__.py | 11 ++++++++++- esphome/config_validation.py | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/esphome/components/external_components/__init__.py b/esphome/components/external_components/__init__.py index bbb703dc5c..f4432a0362 100644 --- a/esphome/components/external_components/__init__.py +++ b/esphome/components/external_components/__init__.py @@ -49,7 +49,16 @@ def _process_git_config(config: dict, refresh) -> str: password=config.get(CONF_PASSWORD), ) - if (repo_dir / "esphome" / "components").is_dir(): + if path := config.get(CONF_PATH): + if (repo_dir / path).is_dir(): + components_dir = repo_dir / path + else: + raise cv.Invalid( + "Could not find components folder for source. Please check the source contains a '" + + path + + "' folder" + ) + elif (repo_dir / "esphome" / "components").is_dir(): components_dir = repo_dir / "esphome" / "components" elif (repo_dir / "components").is_dir(): components_dir = repo_dir / "components" diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 198b44f38d..3554f03836 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -2124,6 +2124,7 @@ GIT_SCHEMA = Schema( Optional(CONF_REF): git_ref, Optional(CONF_USERNAME): string, Optional(CONF_PASSWORD): string, + Optional(CONF_PATH): string, } ) LOCAL_SCHEMA = Schema( From d1758a46bd24c9631e55d500d61da7ff522627e7 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Mon, 6 May 2024 21:17:03 +0200 Subject: [PATCH 1675/2607] Use clang-apply-replacements when clang-apply-replacements-14 does not exist (#6684) --- script/clang-tidy | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/script/clang-tidy b/script/clang-tidy index 97e4ba0d48..84b02306d5 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -266,7 +266,12 @@ def main(): if args.fix and failed_files: print("Applying fixes ...") try: - subprocess.call(["clang-apply-replacements-14", tmpdir]) + try: + subprocess.call(["clang-apply-replacements-14", tmpdir]) + except FileNotFoundError: + subprocess.call(["clang-apply-replacements", tmpdir]) + except FileNotFoundError: + print("Error please install clang-apply-replacements-14 or clang-apply-replacements.\n", file=sys.stderr) except: print("Error applying fixes.\n", file=sys.stderr) raise From 8463f897e1a7992c87c608270394563dee6e9a66 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 6 May 2024 21:20:01 +0200 Subject: [PATCH 1676/2607] fix conflict with EMPTY macro in zephyr (#6679) --- esphome/core/automation.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index 8c3da5e7e8..9b62640a0c 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -24,7 +24,7 @@ template struct gens<0, S...> { using type = seq; }; // NOLINT template class TemplatableValue { public: - TemplatableValue() : type_(EMPTY) {} + TemplatableValue() : type_(NONE) {} template::value, int> = 0> TemplatableValue(F value) : type_(VALUE), value_(value) {} @@ -32,13 +32,13 @@ template class TemplatableValue { template::value, int> = 0> TemplatableValue(F f) : type_(LAMBDA), f_(f) {} - bool has_value() { return this->type_ != EMPTY; } + bool has_value() { return this->type_ != NONE; } T value(X... x) { if (this->type_ == LAMBDA) { return this->f_(x...); } - // return value also when empty + // return value also when none return this->value_; } @@ -58,7 +58,7 @@ template class TemplatableValue { protected: enum { - EMPTY, + NONE, VALUE, LAMBDA, } type_; From 594769be3ca9bb082fea9c56cc8922b69a483f0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 09:09:04 +1200 Subject: [PATCH 1677/2607] Bump actions/checkout from 4.1.1 to 4.1.5 (#6685) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 32 +++++++++++------------ .github/workflows/release.yml | 8 +++--- .github/workflows/sync-device-classes.yml | 4 +-- .github/workflows/yaml-lint.yml | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 40766ad728..448d0fd10f 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 6063d1e052..72a16233fb 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.5 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd7a45ff50..fbebc55676 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -66,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -87,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -108,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -129,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -150,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -199,7 +199,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -229,7 +229,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -254,7 +254,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Find all YAML test files id: set-matrix run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT @@ -271,7 +271,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -303,7 +303,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -358,7 +358,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -402,7 +402,7 @@ jobs: count: ${{ steps.list-components.outputs.count }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 with: # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. fetch-depth: 500 @@ -450,7 +450,7 @@ jobs: run: sudo apt-get install libsodium-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -476,7 +476,7 @@ jobs: matrix: ${{ steps.split.outputs.components }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Split components into 20 groups id: split run: | @@ -504,7 +504,7 @@ jobs: run: sudo apt-get install libsodium-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72b06ab4fe..6d91d00b85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: tag: ${{ steps.tag.outputs.tag }} branch_build: ${{ steps.tag.outputs.branch_build }} steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.5 - name: Get tag id: tag # yamllint disable rule:line-length @@ -51,7 +51,7 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.5 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -81,7 +81,7 @@ jobs: - linux/arm/v7 - linux/arm64 steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.5 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -159,7 +159,7 @@ jobs: - ghcr - dockerhub steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.5 - name: Download digests uses: actions/download-artifact@v3.0.2 with: diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index c9614618d5..7d67999b77 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -13,10 +13,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Checkout Home Assistant - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 with: repository: home-assistant/core path: lib/home-assistant diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index a3c1937e56..761247529b 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.5 - name: Run yamllint uses: frenck/action-yamllint@v1.5.0 with: From 5ee2a5f9352ded83fbd080923c44b3f98ce2d0f2 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Tue, 7 May 2024 00:44:49 +0200 Subject: [PATCH 1678/2607] Fix Datetime-Datetime compiler error (#6686) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/template/datetime/template_datetime.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/template/datetime/template_datetime.h b/esphome/components/template/datetime/template_datetime.h index cb1fd01132..ef80ded89a 100644 --- a/esphome/components/template/datetime/template_datetime.h +++ b/esphome/components/template/datetime/template_datetime.h @@ -2,7 +2,7 @@ #include "esphome/core/defines.h" -#ifdef USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME #include "esphome/components/datetime/datetime_entity.h" #include "esphome/core/automation.h" @@ -43,4 +43,4 @@ class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponen } // namespace template_ } // namespace esphome -#endif // USE_DATETIME_TIME +#endif // USE_DATETIME_DATETIME From 7b0536fda35b49478e2b764997ec689b8d844175 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 7 May 2024 11:54:01 +1200 Subject: [PATCH 1679/2607] Bump esphome/ESPAsyncWebServer-esphome to 3.2.0 (#6687) --- esphome/components/web_server_base/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 6491446bcc..1970b5a0c5 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -37,4 +37,4 @@ async def to_code(config): cg.add_library("FS", None) cg.add_library("Update", None) # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json - cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.1.0") + cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.2.0") diff --git a/platformio.ini b/platformio.ini index 5fedd14086..e699057fa3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,7 +58,7 @@ lib_deps = SPI ; spi (Arduino built-in) Wire ; i2c (Arduino built-int) heman/AsyncMqttClient-esphome@1.0.0 ; mqtt - esphome/ESPAsyncWebServer-esphome@2.1.0 ; web_server_base + esphome/ESPAsyncWebServer-esphome@3.2.0 ; web_server_base fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps freekode/TM1651@1.0.1 ; tm1651 From 1e196bac985e44a9121c937c60b1ada4e54772a8 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Tue, 7 May 2024 02:47:07 +0200 Subject: [PATCH 1680/2607] fix date_time validation (#6688) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/datetime/__init__.py | 8 +- .../components/template/datetime/__init__.py | 10 ++- esphome/config_validation.py | 75 +++++++++---------- tests/components/template/common.yaml | 3 + 4 files changed, 49 insertions(+), 47 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 639a035159..3d08e4a6d0 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -169,7 +169,7 @@ async def to_code(config): { cv.Required(CONF_ID): cv.use_id(DateEntity), cv.Required(CONF_DATE): cv.Any( - cv.returning_lambda, cv.date_time(allowed_time=False) + cv.returning_lambda, cv.date_time(date=True, time=False) ), } ), @@ -200,7 +200,7 @@ async def datetime_date_set_to_code(config, action_id, template_arg, args): { cv.Required(CONF_ID): cv.use_id(TimeEntity), cv.Required(CONF_TIME): cv.Any( - cv.returning_lambda, cv.date_time(allowed_date=False) + cv.returning_lambda, cv.date_time(date=False, time=True) ), } ), @@ -230,7 +230,9 @@ async def datetime_time_set_to_code(config, action_id, template_arg, args): cv.Schema( { cv.Required(CONF_ID): cv.use_id(DateTimeEntity), - cv.Required(CONF_DATETIME): cv.Any(cv.returning_lambda, cv.date_time()), + cv.Required(CONF_DATETIME): cv.Any( + cv.returning_lambda, cv.date_time(date=True, time=True) + ), }, ), ) diff --git a/esphome/components/template/datetime/__init__.py b/esphome/components/template/datetime/__init__.py index bf7154ef76..0c9447116f 100644 --- a/esphome/components/template/datetime/__init__.py +++ b/esphome/components/template/datetime/__init__.py @@ -72,21 +72,25 @@ CONFIG_SCHEMA = cv.All( .extend(_BASE_SCHEMA) .extend( { - cv.Optional(CONF_INITIAL_VALUE): cv.date_time(allowed_time=False), + cv.Optional(CONF_INITIAL_VALUE): cv.date_time( + date=True, time=False + ), } ), "TIME": datetime.time_schema(TemplateTime) .extend(_BASE_SCHEMA) .extend( { - cv.Optional(CONF_INITIAL_VALUE): cv.date_time(allowed_date=False), + cv.Optional(CONF_INITIAL_VALUE): cv.date_time( + date=False, time=True + ), } ), "DATETIME": datetime.datetime_schema(TemplateDateTime) .extend(_BASE_SCHEMA) .extend( { - cv.Optional(CONF_INITIAL_VALUE): cv.date_time(), + cv.Optional(CONF_INITIAL_VALUE): cv.date_time(date=True, time=True), } ), }, diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 3554f03836..512f1d8f67 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -821,57 +821,50 @@ positive_not_null_time_period = All( def time_of_day(value): - return date_time(allowed_date=False, allowed_time=True)(value) + return date_time(date=False, time=True)(value) -def date_time(allowed_date: bool = True, allowed_time: bool = True): +def date_time(date: bool, time: bool): pattern_str = r"^" # Start of string - if allowed_date: + if date: + pattern_str += r"\d{4}-\d{1,2}-\d{1,2}" + if time: + pattern_str += r" " + if time: pattern_str += ( - r"(" # 1. Optional Date group - r"\d{4}-\d{1,2}-\d{1,2}" # Date - r"(?:\s(?=.+))?" # Space after date only if time is following - r")?" # End optional Date group - ) - if allowed_time: - pattern_str += ( - r"(" # 2. Optional Time group - r"(\d{1,2}:\d{2})" # 3. Hour/Minute - r"(:\d{2})?" # 4. Seconds - r"(" # 5. Optional AM/PM group - r"(\s)?" # 6. Optional Space + r"\d{1,2}:\d{2}" # Hour/Minute + r"(:\d{2})?" # 1. Seconds + r"(" # 2. Optional AM/PM group + r"(\s)?" # 3. Optional Space r"(?:AM|PM|am|pm)" # AM/PM string matching r")?" # End optional AM/PM group - r")?" # End optional Time group ) pattern_str += r"$" # End of string pattern = re.compile(pattern_str) exc_message = "" - if allowed_date: + if date: exc_message += "date" - if allowed_time: - exc_message += "/" - if allowed_time: + if time: exc_message += "time" schema = Schema({}) - if allowed_date: + if date: schema = schema.extend( { - Optional(CONF_YEAR): int_range(min=1970, max=3000), - Optional(CONF_MONTH): int_range(min=1, max=12), - Optional(CONF_DAY): int_range(min=1, max=31), + Required(CONF_YEAR): int_range(min=1970, max=3000), + Required(CONF_MONTH): int_range(min=1, max=12), + Required(CONF_DAY): int_range(min=1, max=31), } ) - if allowed_time: + if time: schema = schema.extend( { - Optional(CONF_HOUR): int_range(min=0, max=23), - Optional(CONF_MINUTE): int_range(min=0, max=59), - Optional(CONF_SECOND): int_range(min=0, max=59), + Required(CONF_HOUR): int_range(min=0, max=23), + Required(CONF_MINUTE): int_range(min=0, max=59), + Required(CONF_SECOND): int_range(min=0, max=59), } ) @@ -885,21 +878,21 @@ def date_time(allowed_date: bool = True, allowed_time: bool = True): # pylint: disable=raise-missing-from raise Invalid(f"Invalid {exc_message}: {value}") - if allowed_date: - has_date = match[1] is not None - if allowed_time: - has_time = match[2] is not None - has_seconds = match[3] is not None - has_ampm = match[4] is not None - has_ampm_space = match[5] is not None + if time: + has_seconds = match[1] is not None + has_ampm = match[2] is not None + has_ampm_space = match[3] is not None format = "" - if allowed_date and has_date: + if date: format += "%Y-%m-%d" - if allowed_time and has_time: + if time: format += " " - if allowed_time and has_time: - format += "%H:%M" + if time: + if has_ampm: + format += "%I:%M" + else: + format += "%H:%M" if has_seconds: format += ":%S" if has_ampm_space: @@ -914,12 +907,12 @@ def date_time(allowed_date: bool = True, allowed_time: bool = True): raise Invalid(f"Invalid {exc_message}: {err}") return_value = {} - if allowed_date and has_date: + if date: return_value[CONF_YEAR] = date_obj.year return_value[CONF_MONTH] = date_obj.month return_value[CONF_DAY] = date_obj.day - if allowed_time and has_time: + if time: return_value[CONF_HOUR] = date_obj.hour return_value[CONF_MINUTE] = date_obj.minute return_value[CONF_SECOND] = date_obj.second if has_seconds else 0 diff --git a/tests/components/template/common.yaml b/tests/components/template/common.yaml index 2b91225b5a..9e89424d8a 100644 --- a/tests/components/template/common.yaml +++ b/tests/components/template/common.yaml @@ -172,6 +172,7 @@ datetime: name: Date id: test_date type: date + initial_value: "2000-1-2" set_action: - logger.log: "set_value" on_value: @@ -185,6 +186,7 @@ datetime: name: Time id: test_time type: time + initial_value: "12:34:56am" set_action: - logger.log: "set_value" on_value: @@ -198,6 +200,7 @@ datetime: name: DateTime id: test_datetime type: datetime + initial_value: "2000-1-2 12:34:56" set_action: - logger.log: "set_value" on_value: From 5edf4970bde1d2d5dda2fa34c1ba062a8f3aa8a1 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 6 May 2024 20:44:36 -0700 Subject: [PATCH 1681/2607] proceed if AP mode is set up (#6631) --- esphome/components/wifi/wifi_component.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 075e683bb5..7e245d3e86 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -694,7 +694,7 @@ void WiFiComponent::retry_connect() { } bool WiFiComponent::can_proceed() { - if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED) { + if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED || this->ap_setup_) { return true; } return this->is_connected(); From 829bfbdaa446e4f9e959e50754cc55b88fb60c3f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 8 May 2024 05:26:04 +1000 Subject: [PATCH 1682/2607] Migrate some constants to core code (#6692) --- esphome/components/as5600/__init__.py | 1 - esphome/components/as5600/sensor/__init__.py | 2 +- esphome/components/display_menu_base/__init__.py | 1 - esphome/components/lcd_menu/__init__.py | 3 +-- .../components/matrix_keypad/binary_sensor/__init__.py | 5 +---- esphome/components/media_player/__init__.py | 9 +++++++-- esphome/components/sx1509/binary_sensor/__init__.py | 4 +--- esphome/components/voice_assistant/__init__.py | 2 +- esphome/const.py | 5 +++++ 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/esphome/components/as5600/__init__.py b/esphome/components/as5600/__init__.py index 1840b22768..feeae107a7 100644 --- a/esphome/components/as5600/__init__.py +++ b/esphome/components/as5600/__init__.py @@ -54,7 +54,6 @@ FAST_FILTER = { "LSB10": 7, } -CONF_ANGLE = "angle" CONF_RAW_ANGLE = "raw_angle" CONF_RAW_POSITION = "raw_position" CONF_WATCHDOG = "watchdog" diff --git a/esphome/components/as5600/sensor/__init__.py b/esphome/components/as5600/sensor/__init__.py index 589a66950a..30337ab61b 100644 --- a/esphome/components/as5600/sensor/__init__.py +++ b/esphome/components/as5600/sensor/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_MAGNITUDE, CONF_STATUS, CONF_POSITION, + CONF_ANGLE, ) from .. import as5600_ns, AS5600Component @@ -19,7 +20,6 @@ DEPENDENCIES = ["as5600"] AS5600Sensor = as5600_ns.class_("AS5600Sensor", sensor.Sensor, cg.PollingComponent) -CONF_ANGLE = "angle" CONF_RAW_ANGLE = "raw_angle" CONF_RAW_POSITION = "raw_position" CONF_WATCHDOG = "watchdog" diff --git a/esphome/components/display_menu_base/__init__.py b/esphome/components/display_menu_base/__init__.py index d7326cdc65..0c738ba838 100644 --- a/esphome/components/display_menu_base/__init__.py +++ b/esphome/components/display_menu_base/__init__.py @@ -23,7 +23,6 @@ CODEOWNERS = ["@numo68"] display_menu_base_ns = cg.esphome_ns.namespace("display_menu_base") -CONF_DISPLAY_ID = "display_id" CONF_ROTARY = "rotary" CONF_JOYSTICK = "joystick" diff --git a/esphome/components/lcd_menu/__init__.py b/esphome/components/lcd_menu/__init__.py index a356c85ba7..b57a4a0f6c 100644 --- a/esphome/components/lcd_menu/__init__.py +++ b/esphome/components/lcd_menu/__init__.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.const import ( CONF_ID, CONF_DIMENSIONS, + CONF_DISPLAY_ID, ) from esphome.core.entity_helpers import inherit_property_from from esphome.components import lcd_base @@ -18,8 +19,6 @@ AUTO_LOAD = ["display_menu_base"] lcd_menu_ns = cg.esphome_ns.namespace("lcd_menu") -CONF_DISPLAY_ID = "display_id" - CONF_MARK_SELECTED = "mark_selected" CONF_MARK_EDITING = "mark_editing" CONF_MARK_SUBMENU = "mark_submenu" diff --git a/esphome/components/matrix_keypad/binary_sensor/__init__.py b/esphome/components/matrix_keypad/binary_sensor/__init__.py index 9ad909f60a..edebf7b772 100644 --- a/esphome/components/matrix_keypad/binary_sensor/__init__.py +++ b/esphome/components/matrix_keypad/binary_sensor/__init__.py @@ -1,12 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor -from esphome.const import CONF_ID, CONF_KEY +from esphome.const import CONF_ID, CONF_KEY, CONF_ROW, CONF_COL from .. import MatrixKeypad, matrix_keypad_ns, CONF_KEYPAD_ID -CONF_ROW = "row" -CONF_COL = "col" - DEPENDENCIES = ["matrix_keypad"] MatrixKeypadBinarySensor = matrix_keypad_ns.class_( diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 86e038d76d..5db78150bb 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -3,7 +3,13 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID, CONF_VOLUME +from esphome.const import ( + CONF_ID, + CONF_ON_STATE, + CONF_TRIGGER_ID, + CONF_VOLUME, + CONF_ON_IDLE, +) from esphome.core import CORE from esphome.coroutine import coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -43,7 +49,6 @@ VolumeSetAction = media_player_ns.class_( ) -CONF_ON_IDLE = "on_idle" CONF_ON_PLAY = "on_play" CONF_ON_PAUSE = "on_pause" CONF_MEDIA_URL = "media_url" diff --git a/esphome/components/sx1509/binary_sensor/__init__.py b/esphome/components/sx1509/binary_sensor/__init__.py index fa620fa202..280b5ad90c 100644 --- a/esphome/components/sx1509/binary_sensor/__init__.py +++ b/esphome/components/sx1509/binary_sensor/__init__.py @@ -1,12 +1,10 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor +from esphome.const import CONF_ROW, CONF_COL from .. import SX1509Component, sx1509_ns, CONF_SX1509_ID -CONF_ROW = "row" -CONF_COL = "col" - DEPENDENCIES = ["sx1509"] SX1509BinarySensor = sx1509_ns.class_("SX1509BinarySensor", binary_sensor.BinarySensor) diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index 17bdffd9da..3ba0c58ce4 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_MEDIA_PLAYER, CONF_ON_CLIENT_CONNECTED, CONF_ON_CLIENT_DISCONNECTED, + CONF_ON_IDLE, ) from esphome import automation from esphome.automation import register_action, register_condition @@ -32,7 +33,6 @@ CONF_ON_TTS_START = "on_tts_start" CONF_ON_TTS_STREAM_START = "on_tts_stream_start" CONF_ON_TTS_STREAM_END = "on_tts_stream_end" CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected" -CONF_ON_IDLE = "on_idle" CONF_SILENCE_DETECTION = "silence_detection" CONF_USE_WAKE_WORD = "use_wake_word" diff --git a/esphome/const.py b/esphome/const.py index 1a8f9a06e1..c0d27337d6 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -51,6 +51,7 @@ CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" CONF_ANALOG = "analog" CONF_AND = "and" +CONF_ANGLE = "angle" CONF_AP = "ap" CONF_APPARENT_POWER = "apparent_power" CONF_ARDUINO_VERSION = "arduino_version" @@ -124,6 +125,7 @@ CONF_CLOSE_DURATION = "close_duration" CONF_CLOSE_ENDSTOP = "close_endstop" CONF_CO2 = "co2" CONF_CODE = "code" +CONF_COL = "col" CONF_COLD_WHITE = "cold_white" CONF_COLD_WHITE_COLOR_TEMPERATURE = "cold_white_color_temperature" CONF_COLOR = "color" @@ -218,6 +220,7 @@ CONF_DISCOVERY_PREFIX = "discovery_prefix" CONF_DISCOVERY_RETAIN = "discovery_retain" CONF_DISCOVERY_UNIQUE_ID_GENERATOR = "discovery_unique_id_generator" CONF_DISPLAY = "display" +CONF_DISPLAY_ID = "display_id" CONF_DISTANCE = "distance" CONF_DITHER = "dither" CONF_DIV_RATIO = "div_ratio" @@ -539,6 +542,7 @@ CONF_ON_FINGER_SCAN_MISPLACED = "on_finger_scan_misplaced" CONF_ON_FINGER_SCAN_START = "on_finger_scan_start" CONF_ON_FINGER_SCAN_UNMATCHED = "on_finger_scan_unmatched" CONF_ON_FINISHED_WRITE = "on_finished_write" +CONF_ON_IDLE = "on_idle" CONF_ON_JSON_MESSAGE = "on_json_message" CONF_ON_LOCK = "on_lock" CONF_ON_LOOP = "on_loop" @@ -702,6 +706,7 @@ CONF_RGBW = "rgbw" CONF_RISING_EDGE = "rising_edge" CONF_RMT_CHANNEL = "rmt_channel" CONF_ROTATION = "rotation" +CONF_ROW = "row" CONF_RS_PIN = "rs_pin" CONF_RTD_NOMINAL_RESISTANCE = "rtd_nominal_resistance" CONF_RTD_WIRES = "rtd_wires" From f6a3784ebac1b669f2bf0edea6743a86c12e3a85 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 7 May 2024 14:33:37 -0500 Subject: [PATCH 1683/2607] Consolidate test files where all tests are identical (#6690) --- .../components/absolute_humidity/common.yaml | 21 ++++ .../absolute_humidity/test.esp32-c3-idf.yaml | 22 +--- .../absolute_humidity/test.esp32-c3.yaml | 22 +--- .../absolute_humidity/test.esp32-idf.yaml | 22 +--- .../absolute_humidity/test.esp32.yaml | 22 +--- .../absolute_humidity/test.esp8266.yaml | 22 +--- .../absolute_humidity/test.rp2040.yaml | 22 +--- .../airthings_wave_mini/common.yaml | 22 ++++ .../test.esp32-c3-idf.yaml | 23 +--- .../airthings_wave_mini/test.esp32-c3.yaml | 23 +--- .../airthings_wave_mini/test.esp32-idf.yaml | 23 +--- .../airthings_wave_mini/test.esp32.yaml | 23 +--- .../airthings_wave_plus/common.yaml | 28 +++++ .../test.esp32-c3-idf.yaml | 29 +---- .../airthings_wave_plus/test.esp32-c3.yaml | 29 +---- .../airthings_wave_plus/test.esp32-idf.yaml | 29 +---- .../airthings_wave_plus/test.esp32.yaml | 29 +---- .../alarm_control_panel/common.yaml | 64 ++++++++++ .../test.esp32-c3-idf.yaml | 65 +--------- .../alarm_control_panel/test.esp32-c3.yaml | 65 +--------- .../alarm_control_panel/test.esp32-idf.yaml | 65 +--------- .../alarm_control_panel/test.esp32.yaml | 65 +--------- .../alarm_control_panel/test.esp8266.yaml | 65 +--------- .../alarm_control_panel/test.rp2040.yaml | 65 +--------- tests/components/alpha3/common.yaml | 17 +++ .../components/alpha3/test.esp32-c3-idf.yaml | 18 +-- tests/components/alpha3/test.esp32-c3.yaml | 18 +-- tests/components/alpha3/test.esp32-idf.yaml | 18 +-- tests/components/alpha3/test.esp32.yaml | 18 +-- tests/components/am43/common.yaml | 19 +++ tests/components/am43/test.esp32-c3-idf.yaml | 20 +-- tests/components/am43/test.esp32-c3.yaml | 20 +-- tests/components/am43/test.esp32-idf.yaml | 20 +-- tests/components/am43/test.esp32.yaml | 20 +-- tests/components/analog_threshold/common.yaml | 28 +++++ .../analog_threshold/test.esp32-c3-idf.yaml | 29 +---- .../analog_threshold/test.esp32-c3.yaml | 29 +---- .../analog_threshold/test.esp32-idf.yaml | 29 +---- .../analog_threshold/test.esp32.yaml | 29 +---- .../analog_threshold/test.esp8266.yaml | 29 +---- .../analog_threshold/test.rp2040.yaml | 29 +---- tests/components/anova/common.yaml | 11 ++ tests/components/anova/test.esp32-c3-idf.yaml | 12 +- tests/components/anova/test.esp32-c3.yaml | 12 +- tests/components/anova/test.esp32-idf.yaml | 12 +- tests/components/anova/test.esp32.yaml | 12 +- tests/components/api/common.yaml | 63 ++++++++++ tests/components/api/test.esp32-c3-idf.yaml | 64 +--------- tests/components/api/test.esp32-c3.yaml | 64 +--------- tests/components/api/test.esp32-idf.yaml | 64 +--------- tests/components/api/test.esp32.yaml | 64 +--------- tests/components/api/test.esp8266.yaml | 64 +--------- tests/components/api/test.rp2040.yaml | 64 +--------- .../components/atc_mithermometer/common.yaml | 13 ++ .../atc_mithermometer/test.esp32-c3-idf.yaml | 14 +-- .../atc_mithermometer/test.esp32-c3.yaml | 14 +-- .../atc_mithermometer/test.esp32-idf.yaml | 14 +-- .../atc_mithermometer/test.esp32.yaml | 14 +-- tests/components/b_parasite/common.yaml | 15 +++ .../b_parasite/test.esp32-c3-idf.yaml | 16 +-- .../components/b_parasite/test.esp32-c3.yaml | 16 +-- .../components/b_parasite/test.esp32-idf.yaml | 16 +-- tests/components/b_parasite/test.esp32.yaml | 16 +-- tests/components/bang_bang/common.yaml | 35 ++++++ .../bang_bang/test.esp32-c3-idf.yaml | 36 +----- tests/components/bang_bang/test.esp32-c3.yaml | 36 +----- .../components/bang_bang/test.esp32-idf.yaml | 36 +----- tests/components/bang_bang/test.esp32.yaml | 36 +----- tests/components/bang_bang/test.esp8266.yaml | 36 +----- tests/components/bang_bang/test.rp2040.yaml | 36 +----- tests/components/bedjet/common.yaml | 33 +++++ .../components/bedjet/test.esp32-c3-idf.yaml | 34 +---- tests/components/bedjet/test.esp32-c3.yaml | 34 +---- tests/components/bedjet/test.esp32-idf.yaml | 34 +---- tests/components/bedjet/test.esp32.yaml | 34 +---- .../components/binary_sensor_map/common.yaml | 61 +++++++++ .../binary_sensor_map/test.esp32-c3-idf.yaml | 62 +-------- .../binary_sensor_map/test.esp32-c3.yaml | 62 +-------- .../binary_sensor_map/test.esp32-idf.yaml | 62 +-------- .../binary_sensor_map/test.esp32.yaml | 62 +-------- .../binary_sensor_map/test.esp8266.yaml | 62 +-------- .../binary_sensor_map/test.rp2040.yaml | 62 +-------- tests/components/ble_client/common.yaml | 5 + .../ble_client/test.esp32-c3-idf.yaml | 6 +- .../components/ble_client/test.esp32-c3.yaml | 6 +- .../components/ble_client/test.esp32-idf.yaml | 6 +- tests/components/ble_client/test.esp32.yaml | 6 +- tests/components/ble_presence/common.yaml | 24 ++++ .../ble_presence/test.esp32-c3-idf.yaml | 25 +--- .../ble_presence/test.esp32-c3.yaml | 25 +--- .../ble_presence/test.esp32-idf.yaml | 25 +--- tests/components/ble_presence/test.esp32.yaml | 25 +--- tests/components/ble_rssi/common.yaml | 18 +++ .../ble_rssi/test.esp32-c3-idf.yaml | 19 +-- tests/components/ble_rssi/test.esp32-c3.yaml | 19 +-- tests/components/ble_rssi/test.esp32-idf.yaml | 19 +-- tests/components/ble_rssi/test.esp32.yaml | 19 +-- tests/components/ble_scanner/common.yaml | 5 + .../ble_scanner/test.esp32-c3-idf.yaml | 6 +- .../components/ble_scanner/test.esp32-c3.yaml | 6 +- .../ble_scanner/test.esp32-idf.yaml | 6 +- tests/components/ble_scanner/test.esp32.yaml | 6 +- tests/components/button/common.yaml | 6 + .../components/button/test.esp32-c3-idf.yaml | 7 +- tests/components/button/test.esp32-c3.yaml | 7 +- tests/components/button/test.esp32-idf.yaml | 7 +- tests/components/button/test.esp32.yaml | 7 +- tests/components/button/test.esp8266.yaml | 7 +- tests/components/button/test.rp2040.yaml | 7 +- tests/components/canbus/common.yaml | 46 +++++++ .../components/canbus/test.esp32-c3-idf.yaml | 47 +------ tests/components/canbus/test.esp32-c3.yaml | 47 +------ tests/components/canbus/test.esp32-idf.yaml | 47 +------ tests/components/canbus/test.esp32.yaml | 47 +------ tests/components/captive_portal/common.yaml | 5 + .../captive_portal/test.esp32-c3-idf.yaml | 6 +- .../captive_portal/test.esp32-c3.yaml | 6 +- .../captive_portal/test.esp32-idf.yaml | 6 +- .../components/captive_portal/test.esp32.yaml | 6 +- .../captive_portal/test.esp8266.yaml | 6 +- tests/components/color/common.yaml | 11 ++ tests/components/color/test.esp32-c3-idf.yaml | 12 +- tests/components/color/test.esp32-c3.yaml | 12 +- tests/components/color/test.esp32-idf.yaml | 12 +- tests/components/color/test.esp32.yaml | 12 +- tests/components/color/test.esp8266.yaml | 12 +- tests/components/color/test.rp2040.yaml | 12 +- tests/components/combination/common.yaml | 76 +++++++++++ .../combination/test.esp32-c3-idf.yaml | 77 +----------- .../components/combination/test.esp32-c3.yaml | 77 +----------- .../combination/test.esp32-idf.yaml | 77 +----------- tests/components/combination/test.esp32.yaml | 77 +----------- .../components/combination/test.esp8266.yaml | 77 +----------- tests/components/combination/test.rp2040.yaml | 77 +----------- tests/components/cst226/common.yaml | 24 ++++ tests/components/cst226/test.esp32-c3.yaml | 25 +--- tests/components/cst816/common.yaml | 36 ++++++ tests/components/cst816/test.esp32.yaml | 37 +----- tests/components/dallas/common.yaml | 11 ++ .../components/dallas/test.esp32-c3-idf.yaml | 12 +- tests/components/dallas/test.esp32-c3.yaml | 12 +- tests/components/dallas/test.esp32-idf.yaml | 12 +- tests/components/dallas/test.esp32.yaml | 12 +- tests/components/dallas/test.esp8266.yaml | 12 +- tests/components/dallas/test.rp2040.yaml | 12 +- tests/components/datetime/common.yaml | 3 + tests/components/datetime/test.all.yaml | 4 +- tests/components/debug/common.yaml | 1 + tests/components/debug/test.esp32-c3-idf.yaml | 2 +- tests/components/debug/test.esp32-c3.yaml | 2 +- tests/components/debug/test.esp32-idf.yaml | 2 +- tests/components/debug/test.esp32.yaml | 2 +- tests/components/debug/test.esp8266.yaml | 2 +- tests/components/debug/test.host.yaml | 2 +- tests/components/debug/test.rp2040.yaml | 2 +- tests/components/dht/common.yaml | 11 ++ tests/components/dht/test.esp32-c3-idf.yaml | 12 +- tests/components/dht/test.esp32-c3.yaml | 12 +- tests/components/dht/test.esp32-idf.yaml | 12 +- tests/components/dht/test.esp32.yaml | 12 +- tests/components/dht/test.esp8266.yaml | 12 +- tests/components/dht/test.rp2040.yaml | 12 +- tests/components/display/common.yaml | 35 ++++++ tests/components/display/test.esp32.yaml | 36 +----- tests/components/duty_cycle/common.yaml | 4 + .../duty_cycle/test.esp32-c3-idf.yaml | 5 +- .../components/duty_cycle/test.esp32-c3.yaml | 5 +- .../components/duty_cycle/test.esp32-idf.yaml | 5 +- tests/components/duty_cycle/test.esp32.yaml | 5 +- tests/components/duty_cycle/test.esp8266.yaml | 5 +- tests/components/duty_cycle/test.rp2040.yaml | 5 +- tests/components/duty_time/common.yaml | 14 +++ .../duty_time/test.esp32-c3-idf.yaml | 15 +-- tests/components/duty_time/test.esp32-c3.yaml | 15 +-- .../components/duty_time/test.esp32-idf.yaml | 15 +-- tests/components/duty_time/test.esp32.yaml | 15 +-- tests/components/duty_time/test.esp8266.yaml | 15 +-- tests/components/duty_time/test.rp2040.yaml | 15 +-- tests/components/endstop/common.yaml | 33 +++++ .../components/endstop/test.esp32-c3-idf.yaml | 34 +---- tests/components/endstop/test.esp32-c3.yaml | 34 +---- tests/components/endstop/test.esp32-idf.yaml | 34 +---- tests/components/endstop/test.esp32.yaml | 34 +---- tests/components/endstop/test.esp8266.yaml | 34 +---- tests/components/endstop/test.rp2040.yaml | 34 +---- tests/components/esp32_ble/common.yaml | 2 + .../esp32_ble/test.esp32-c3-idf.yaml | 3 +- tests/components/esp32_ble/test.esp32-c3.yaml | 3 +- .../components/esp32_ble/test.esp32-idf.yaml | 3 +- tests/components/esp32_ble/test.esp32.yaml | 3 +- tests/components/esp32_ble_beacon/common.yaml | 3 + .../esp32_ble_beacon/test.esp32-c3-idf.yaml | 4 +- .../esp32_ble_beacon/test.esp32-c3.yaml | 4 +- .../esp32_ble_beacon/test.esp32-idf.yaml | 4 +- .../esp32_ble_beacon/test.esp32.yaml | 4 +- tests/components/esp32_ble_client/common.yaml | 5 + .../esp32_ble_client/test.esp32-c3-idf.yaml | 6 +- .../esp32_ble_client/test.esp32-c3.yaml | 6 +- .../esp32_ble_client/test.esp32-idf.yaml | 6 +- .../esp32_ble_client/test.esp32.yaml | 6 +- tests/components/esp32_ble_server/common.yaml | 3 + .../esp32_ble_server/test.esp32-c3-idf.yaml | 4 +- .../esp32_ble_server/test.esp32-c3.yaml | 4 +- .../esp32_ble_server/test.esp32-idf.yaml | 4 +- .../esp32_ble_server/test.esp32.yaml | 4 +- .../components/esp32_ble_tracker/common.yaml | 41 ++++++ .../esp32_ble_tracker/test.esp32-c3-idf.yaml | 42 +------ .../esp32_ble_tracker/test.esp32-c3.yaml | 42 +------ .../esp32_ble_tracker/test.esp32-idf.yaml | 42 +------ .../esp32_ble_tracker/test.esp32.yaml | 42 +------ tests/components/esp32_camera/common.yaml | 28 +++++ .../esp32_camera/test.esp32-idf.yaml | 29 +---- tests/components/esp32_camera/test.esp32.yaml | 29 +---- .../esp32_camera_web_server/common.yaml | 34 +++++ .../test.esp32-idf.yaml | 35 +----- .../esp32_camera_web_server/test.esp32.yaml | 35 +----- tests/components/esp32_dac/common.yaml | 4 + .../components/esp32_dac/test.esp32-idf.yaml | 5 +- tests/components/esp32_dac/test.esp32.yaml | 5 +- tests/components/esp32_hall/common.yaml | 3 + .../components/esp32_hall/test.esp32-idf.yaml | 4 +- tests/components/esp32_hall/test.esp32.yaml | 4 +- tests/components/esp32_improv/common.yaml | 18 +++ .../esp32_improv/test.esp32-c3-idf.yaml | 19 +-- .../esp32_improv/test.esp32-c3.yaml | 19 +-- .../esp32_improv/test.esp32-idf.yaml | 19 +-- tests/components/esp32_improv/test.esp32.yaml | 19 +-- tests/components/esp32_touch/common.yaml | 16 +++ .../esp32_touch/test.esp32-idf.yaml | 17 +-- tests/components/esp32_touch/test.esp32.yaml | 17 +-- tests/components/esp8266_pwm/common.yaml | 8 ++ .../components/esp8266_pwm/test.esp8266.yaml | 9 +- tests/components/ethernet/common.yaml | 12 ++ tests/components/ethernet/test.esp32-idf.yaml | 13 +- tests/components/ethernet/test.esp32.yaml | 13 +- tests/components/ethernet_info/common.yaml | 19 +++ .../ethernet_info/test.esp32-idf.yaml | 20 +-- .../components/ethernet_info/test.esp32.yaml | 20 +-- tests/components/event/common.yaml | 9 ++ tests/components/event/test.esp32-c3-idf.yaml | 10 +- tests/components/event/test.esp32-c3.yaml | 10 +- tests/components/event/test.esp32-idf.yaml | 10 +- tests/components/event/test.esp32.yaml | 10 +- tests/components/event/test.esp8266.yaml | 10 +- tests/components/event/test.rp2040.yaml | 10 +- .../exposure_notifications/common.yaml | 9 ++ .../test.esp32-c3-idf.yaml | 10 +- .../exposure_notifications/test.esp32-c3.yaml | 10 +- .../test.esp32-idf.yaml | 10 +- .../exposure_notifications/test.esp32.yaml | 10 +- .../external_components/common.yaml | 6 + .../test.esp32-c3-idf.yaml | 7 +- .../external_components/test.esp32-c3.yaml | 7 +- .../external_components/test.esp32-idf.yaml | 7 +- .../external_components/test.esp32.yaml | 7 +- .../external_components/test.esp8266.yaml | 7 +- .../external_components/test.rp2040.yaml | 7 +- tests/components/factory_reset/common.yaml | 3 + .../factory_reset/test.esp32-c3-idf.yaml | 4 +- .../factory_reset/test.esp32-c3.yaml | 4 +- .../factory_reset/test.esp32-idf.yaml | 4 +- .../components/factory_reset/test.esp32.yaml | 4 +- .../factory_reset/test.esp8266.yaml | 4 +- .../components/factory_reset/test.rp2040.yaml | 4 +- .../components/fastled_clockless/common.yaml | 71 +++++++++++ .../fastled_clockless/test.esp32.yaml | 72 +---------- tests/components/fastled_spi/common.yaml | 71 +++++++++++ tests/components/fastled_spi/test.esp32.yaml | 72 +---------- tests/components/feedback/common.yaml | 39 ++++++ .../feedback/test.esp32-c3-idf.yaml | 40 +----- tests/components/feedback/test.esp32-c3.yaml | 40 +----- tests/components/feedback/test.esp32-idf.yaml | 40 +----- tests/components/feedback/test.esp32.yaml | 40 +----- tests/components/feedback/test.esp8266.yaml | 40 +----- tests/components/feedback/test.rp2040.yaml | 40 +----- tests/components/globals/common.yaml | 28 +++++ .../components/globals/test.esp32-c3-idf.yaml | 29 +---- tests/components/globals/test.esp32-c3.yaml | 29 +---- tests/components/globals/test.esp32-idf.yaml | 29 +---- tests/components/globals/test.esp32.yaml | 29 +---- tests/components/globals/test.esp8266.yaml | 29 +---- tests/components/globals/test.rp2040.yaml | 29 +---- tests/components/host/common.yaml | 15 +++ tests/components/host/test.host.yaml | 16 +-- tests/components/improv_serial/common.yaml | 5 + .../improv_serial/test.esp32-c3-idf.yaml | 6 +- .../improv_serial/test.esp32-c3.yaml | 6 +- .../improv_serial/test.esp32-idf.yaml | 6 +- .../components/improv_serial/test.esp32.yaml | 6 +- .../improv_serial/test.esp8266.yaml | 6 +- .../components/improv_serial/test.rp2040.yaml | 6 +- .../inkbird_ibsth1_mini/common.yaml | 11 ++ .../test.esp32-c3-idf.yaml | 12 +- .../inkbird_ibsth1_mini/test.esp32-c3.yaml | 12 +- .../inkbird_ibsth1_mini/test.esp32-idf.yaml | 12 +- .../inkbird_ibsth1_mini/test.esp32.yaml | 12 +- tests/components/inkplate6/common.yaml | 62 +++++++++ tests/components/inkplate6/test.esp32.yaml | 63 +--------- tests/components/interval/common.yaml | 4 + .../interval/test.esp32-c3-idf.yaml | 5 +- tests/components/interval/test.esp32-c3.yaml | 5 +- tests/components/interval/test.esp32-idf.yaml | 5 +- tests/components/interval/test.esp32.yaml | 5 +- tests/components/interval/test.esp8266.yaml | 5 +- tests/components/interval/test.rp2040.yaml | 5 +- tests/components/ledc/common.yaml | 11 ++ tests/components/ledc/test.esp32-c3-idf.yaml | 12 +- tests/components/ledc/test.esp32-c3.yaml | 12 +- tests/components/ledc/test.esp32-idf.yaml | 12 +- tests/components/ledc/test.esp32.yaml | 12 +- tests/components/lightwaverf/common.yaml | 13 ++ .../components/lightwaverf/test.esp8266.yaml | 14 +-- tests/components/lock/common.yaml | 36 ++++++ tests/components/lock/test.esp32-c3-idf.yaml | 37 +----- tests/components/lock/test.esp32-c3.yaml | 37 +----- tests/components/lock/test.esp32-idf.yaml | 37 +----- tests/components/lock/test.esp32.yaml | 37 +----- tests/components/lock/test.esp8266.yaml | 37 +----- tests/components/lock/test.rp2040.yaml | 37 +----- tests/components/logger/common.yaml | 7 ++ .../components/logger/test.esp32-c3-idf.yaml | 8 +- tests/components/logger/test.esp32-c3.yaml | 8 +- tests/components/logger/test.esp32-idf.yaml | 8 +- tests/components/logger/test.esp32.yaml | 8 +- tests/components/logger/test.esp8266.yaml | 8 +- tests/components/logger/test.rp2040.yaml | 8 +- tests/components/mdns/common.yaml | 6 + tests/components/mdns/test.esp32-c3-idf.yaml | 7 +- tests/components/mdns/test.esp32-c3.yaml | 7 +- tests/components/mdns/test.esp32-idf.yaml | 7 +- tests/components/mdns/test.esp32.yaml | 7 +- tests/components/mdns/test.esp8266.yaml | 7 +- tests/components/mdns/test.rp2040.yaml | 7 +- tests/components/media_player/common.yaml | 32 +++++ tests/components/media_player/test.esp32.yaml | 33 +---- tests/components/micro_wake_word/common.yaml | 15 +++ .../micro_wake_word/test.esp32-s3-idf.yaml | 16 +-- tests/components/midea_ir/common.yaml | 8 ++ .../midea_ir/test.esp32-c3-idf.yaml | 9 +- tests/components/midea_ir/test.esp32-c3.yaml | 9 +- tests/components/midea_ir/test.esp32-idf.yaml | 9 +- tests/components/midea_ir/test.esp32.yaml | 9 +- tests/components/midea_ir/test.esp8266.yaml | 9 +- tests/components/mitsubishi/common.yaml | 7 ++ .../mitsubishi/test.esp32-c3-idf.yaml | 8 +- .../components/mitsubishi/test.esp32-c3.yaml | 8 +- .../components/mitsubishi/test.esp32-idf.yaml | 8 +- tests/components/mitsubishi/test.esp32.yaml | 8 +- tests/components/mitsubishi/test.esp8266.yaml | 8 +- tests/components/mopeka_ble/common.yaml | 3 + .../mopeka_ble/test.esp32-c3-idf.yaml | 4 +- .../components/mopeka_ble/test.esp32-c3.yaml | 4 +- .../components/mopeka_ble/test.esp32-idf.yaml | 4 +- tests/components/mopeka_ble/test.esp32.yaml | 4 +- tests/components/mopeka_pro_check/common.yaml | 16 +++ .../mopeka_pro_check/test.esp32-c3-idf.yaml | 17 +-- .../mopeka_pro_check/test.esp32-c3.yaml | 17 +-- .../mopeka_pro_check/test.esp32-idf.yaml | 17 +-- .../mopeka_pro_check/test.esp32.yaml | 17 +-- tests/components/mopeka_std_check/common.yaml | 15 +++ .../mopeka_std_check/test.esp32-c3-idf.yaml | 16 +-- .../mopeka_std_check/test.esp32-c3.yaml | 16 +-- .../mopeka_std_check/test.esp32-idf.yaml | 16 +-- .../mopeka_std_check/test.esp32.yaml | 16 +-- tests/components/my9231/common.yaml | 26 ++++ .../components/my9231/test.esp32-c3-idf.yaml | 27 +--- tests/components/my9231/test.esp32-c3.yaml | 27 +--- tests/components/my9231/test.esp32-idf.yaml | 27 +--- tests/components/my9231/test.esp32.yaml | 27 +--- tests/components/my9231/test.esp8266.yaml | 27 +--- tests/components/my9231/test.rp2040.yaml | 27 +--- tests/components/network/common.yaml | 6 + .../components/network/test.esp32-c3-idf.yaml | 7 +- tests/components/network/test.esp32-c3.yaml | 7 +- tests/components/network/test.esp32-idf.yaml | 7 +- tests/components/network/test.esp32.yaml | 7 +- tests/components/network/test.esp8266.yaml | 7 +- tests/components/network/test.rp2040.yaml | 7 +- tests/components/noblex/common.yaml | 20 +++ .../components/noblex/test.esp32-c3-idf.yaml | 21 +--- tests/components/noblex/test.esp32-c3.yaml | 21 +--- tests/components/noblex/test.esp32-idf.yaml | 21 +--- tests/components/noblex/test.esp32.yaml | 21 +--- tests/components/noblex/test.esp8266.yaml | 21 +--- tests/components/ota/common.yaml | 30 +++++ tests/components/ota/test.esp32-c3-idf.yaml | 31 +---- tests/components/ota/test.esp32-c3.yaml | 31 +---- tests/components/ota/test.esp32-idf.yaml | 31 +---- tests/components/ota/test.esp32.yaml | 31 +---- tests/components/ota/test.esp8266.yaml | 31 +---- tests/components/ota/test.rp2040.yaml | 31 +---- tests/components/pid/common.yaml | 56 +++++++++ tests/components/pid/test.esp32-c3-idf.yaml | 57 +-------- tests/components/pid/test.esp32-c3.yaml | 57 +-------- tests/components/pid/test.esp32-idf.yaml | 57 +-------- tests/components/pid/test.esp32.yaml | 57 +-------- tests/components/pid/test.esp8266.yaml | 57 +-------- tests/components/pid/test.rp2040.yaml | 57 +-------- tests/components/power_supply/common.yaml | 6 + .../power_supply/test.esp32-c3-idf.yaml | 7 +- .../power_supply/test.esp32-c3.yaml | 7 +- .../power_supply/test.esp32-idf.yaml | 7 +- tests/components/power_supply/test.esp32.yaml | 7 +- .../components/power_supply/test.esp8266.yaml | 7 +- .../components/power_supply/test.rp2040.yaml | 7 +- tests/components/prometheus/common.yaml | 21 ++++ .../prometheus/test.esp32-c3-idf.yaml | 22 +--- .../components/prometheus/test.esp32-c3.yaml | 22 +--- .../components/prometheus/test.esp32-idf.yaml | 22 +--- tests/components/prometheus/test.esp32.yaml | 22 +--- tests/components/prometheus/test.esp8266.yaml | 22 +--- tests/components/psram/common.yaml | 3 + tests/components/psram/test.esp32-c3-idf.yaml | 4 +- tests/components/psram/test.esp32-c3.yaml | 4 +- tests/components/psram/test.esp32-idf.yaml | 4 +- tests/components/psram/test.esp32.yaml | 4 +- tests/components/pulse_counter/common.yaml | 9 ++ .../pulse_counter/test.esp32-c3-idf.yaml | 10 +- .../pulse_counter/test.esp32-c3.yaml | 10 +- .../pulse_counter/test.esp32-idf.yaml | 10 +- .../components/pulse_counter/test.esp32.yaml | 10 +- .../pulse_counter/test.esp8266.yaml | 10 +- .../components/pulse_counter/test.rp2040.yaml | 10 +- tests/components/pulse_meter/common.yaml | 13 ++ .../pulse_meter/test.esp32-c3-idf.yaml | 14 +-- .../components/pulse_meter/test.esp32-c3.yaml | 14 +-- .../pulse_meter/test.esp32-idf.yaml | 14 +-- tests/components/pulse_meter/test.esp32.yaml | 14 +-- .../components/pulse_meter/test.esp8266.yaml | 14 +-- tests/components/pulse_meter/test.rp2040.yaml | 14 +-- tests/components/pulse_width/common.yaml | 4 + .../pulse_width/test.esp32-c3-idf.yaml | 5 +- .../components/pulse_width/test.esp32-c3.yaml | 5 +- .../pulse_width/test.esp32-idf.yaml | 5 +- tests/components/pulse_width/test.esp32.yaml | 5 +- .../components/pulse_width/test.esp8266.yaml | 5 +- tests/components/pulse_width/test.rp2040.yaml | 5 +- .../components/pvvx_mithermometer/common.yaml | 44 +++++++ .../pvvx_mithermometer/test.esp32-c3-idf.yaml | 45 +------ .../pvvx_mithermometer/test.esp32-c3.yaml | 45 +------ .../pvvx_mithermometer/test.esp32-idf.yaml | 45 +------ .../pvvx_mithermometer/test.esp32.yaml | 45 +------ tests/components/qspi_amoled/common.yaml | 36 ++++++ .../qspi_amoled/test.esp32-s3-idf.yaml | 37 +----- tests/components/radon_eye_ble/common.yaml | 3 + .../radon_eye_ble/test.esp32-c3-idf.yaml | 4 +- .../radon_eye_ble/test.esp32-c3.yaml | 4 +- .../radon_eye_ble/test.esp32-idf.yaml | 4 +- .../components/radon_eye_ble/test.esp32.yaml | 4 +- tests/components/radon_eye_rd200/common.yaml | 14 +++ .../radon_eye_rd200/test.esp32-c3-idf.yaml | 15 +-- .../radon_eye_rd200/test.esp32-c3.yaml | 15 +-- .../radon_eye_rd200/test.esp32-idf.yaml | 15 +-- .../radon_eye_rd200/test.esp32.yaml | 15 +-- tests/components/restart/common.yaml | 7 ++ .../components/restart/test.esp32-c3-idf.yaml | 8 +- tests/components/restart/test.esp32-c3.yaml | 8 +- tests/components/restart/test.esp32-idf.yaml | 8 +- tests/components/restart/test.esp32.yaml | 8 +- tests/components/restart/test.esp8266.yaml | 8 +- tests/components/restart/test.rp2040.yaml | 8 +- .../rp2040_pio_led_strip/common.yaml | 18 +++ .../rp2040_pio_led_strip/test.rp2040.yaml | 19 +-- tests/components/rp2040_pwm/common.yaml | 7 ++ tests/components/rp2040_pwm/test.rp2040.yaml | 8 +- tests/components/rpi_dpi_rgb/common.yaml | 40 ++++++ .../rpi_dpi_rgb/test.esp32-s3-idf.yaml | 41 +----- tests/components/ruuvi_ble/common.yaml | 3 + .../ruuvi_ble/test.esp32-c3-idf.yaml | 4 +- tests/components/ruuvi_ble/test.esp32-c3.yaml | 4 +- .../components/ruuvi_ble/test.esp32-idf.yaml | 4 +- tests/components/ruuvi_ble/test.esp32.yaml | 4 +- tests/components/ruuvitag/common.yaml | 27 ++++ .../ruuvitag/test.esp32-c3-idf.yaml | 28 +---- tests/components/ruuvitag/test.esp32-c3.yaml | 28 +---- tests/components/ruuvitag/test.esp32-idf.yaml | 28 +---- tests/components/ruuvitag/test.esp32.yaml | 28 +---- tests/components/safe_mode/common.yaml | 13 ++ .../safe_mode/test.esp32-c3-idf.yaml | 14 +-- tests/components/safe_mode/test.esp32-c3.yaml | 14 +-- .../components/safe_mode/test.esp32-idf.yaml | 14 +-- tests/components/safe_mode/test.esp32.yaml | 14 +-- tests/components/safe_mode/test.esp8266.yaml | 14 +-- tests/components/safe_mode/test.rp2040.yaml | 14 +-- tests/components/shelly_dimmer/common.yaml | 19 +++ .../shelly_dimmer/test.esp8266.yaml | 20 +-- tests/components/shutdown/common.yaml | 7 ++ .../shutdown/test.esp32-c3-idf.yaml | 8 +- tests/components/shutdown/test.esp32-c3.yaml | 8 +- tests/components/shutdown/test.esp32-idf.yaml | 8 +- tests/components/shutdown/test.esp32.yaml | 8 +- tests/components/shutdown/test.esp8266.yaml | 8 +- tests/components/shutdown/test.rp2040.yaml | 8 +- .../components/sigma_delta_output/common.yaml | 16 +++ .../sigma_delta_output/test.esp32-c3-idf.yaml | 17 +-- .../sigma_delta_output/test.esp32-c3.yaml | 17 +-- .../sigma_delta_output/test.esp32-idf.yaml | 17 +-- .../sigma_delta_output/test.esp32.yaml | 17 +-- .../sigma_delta_output/test.esp8266.yaml | 17 +-- .../sigma_delta_output/test.rp2040.yaml | 17 +-- tests/components/slow_pwm/common.yaml | 6 + .../slow_pwm/test.esp32-c3-idf.yaml | 7 +- tests/components/slow_pwm/test.esp32-c3.yaml | 7 +- tests/components/slow_pwm/test.esp32-idf.yaml | 7 +- tests/components/slow_pwm/test.esp32.yaml | 7 +- tests/components/slow_pwm/test.esp8266.yaml | 7 +- tests/components/slow_pwm/test.rp2040.yaml | 7 +- tests/components/sm16716/common.yaml | 16 +++ .../components/sm16716/test.esp32-c3-idf.yaml | 17 +-- tests/components/sm16716/test.esp32-c3.yaml | 17 +-- tests/components/sm16716/test.esp32-idf.yaml | 17 +-- tests/components/sm16716/test.esp32.yaml | 17 +-- tests/components/sm16716/test.esp8266.yaml | 17 +-- tests/components/sm16716/test.rp2040.yaml | 17 +-- tests/components/sm2135/common.yaml | 22 ++++ .../components/sm2135/test.esp32-c3-idf.yaml | 23 +--- tests/components/sm2135/test.esp32-c3.yaml | 23 +--- tests/components/sm2135/test.esp32-idf.yaml | 23 +--- tests/components/sm2135/test.esp32.yaml | 23 +--- tests/components/sm2135/test.esp8266.yaml | 23 +--- tests/components/sm2135/test.rp2040.yaml | 23 +--- tests/components/sm2235/common.yaml | 22 ++++ .../components/sm2235/test.esp32-c3-idf.yaml | 23 +--- tests/components/sm2235/test.esp32-c3.yaml | 23 +--- tests/components/sm2235/test.esp32-idf.yaml | 23 +--- tests/components/sm2235/test.esp32.yaml | 23 +--- tests/components/sm2235/test.esp8266.yaml | 23 +--- tests/components/sm2235/test.rp2040.yaml | 23 +--- tests/components/sm2335/common.yaml | 22 ++++ .../components/sm2335/test.esp32-c3-idf.yaml | 23 +--- tests/components/sm2335/test.esp32-c3.yaml | 23 +--- tests/components/sm2335/test.esp32-idf.yaml | 23 +--- tests/components/sm2335/test.esp32.yaml | 23 +--- tests/components/sm2335/test.esp8266.yaml | 23 +--- tests/components/sm2335/test.rp2040.yaml | 23 +--- tests/components/sntp/common.yaml | 15 +++ tests/components/sntp/test.esp32-c3-idf.yaml | 16 +-- tests/components/sntp/test.esp32-c3.yaml | 16 +-- tests/components/sntp/test.esp32-idf.yaml | 16 +-- tests/components/sntp/test.esp32.yaml | 16 +-- tests/components/sntp/test.esp8266.yaml | 16 +-- tests/components/sntp/test.rp2040.yaml | 16 +-- tests/components/sprinkler/common.yaml | 83 ++++++++++++ .../sprinkler/test.esp32-c3-idf.yaml | 84 +------------ tests/components/sprinkler/test.esp32-c3.yaml | 84 +------------ .../components/sprinkler/test.esp32-idf.yaml | 84 +------------ tests/components/sprinkler/test.esp32.yaml | 84 +------------ tests/components/sprinkler/test.esp8266.yaml | 84 +------------ tests/components/sprinkler/test.rp2040.yaml | 84 +------------ tests/components/st7701s/common.yaml | 60 +++++++++ .../components/st7701s/test.esp32-s3-idf.yaml | 61 +-------- tests/components/status/common.yaml | 10 ++ .../components/status/test.esp32-c3-idf.yaml | 11 +- tests/components/status/test.esp32-c3.yaml | 11 +- tests/components/status/test.esp32-idf.yaml | 11 +- tests/components/status/test.esp32.yaml | 11 +- tests/components/status/test.esp8266.yaml | 11 +- tests/components/status/test.rp2040.yaml | 11 +- tests/components/status_led/common.yaml | 10 ++ .../status_led/test.esp32-c3-idf.yaml | 11 +- .../components/status_led/test.esp32-c3.yaml | 11 +- .../components/status_led/test.esp32-idf.yaml | 11 +- tests/components/status_led/test.esp32.yaml | 11 +- tests/components/status_led/test.esp8266.yaml | 11 +- tests/components/status_led/test.rp2040.yaml | 11 +- tests/components/stepper/common.yaml | 27 ++++ .../components/stepper/test.esp32-c3-idf.yaml | 28 +---- tests/components/stepper/test.esp32-c3.yaml | 28 +---- tests/components/stepper/test.esp32-idf.yaml | 28 +---- tests/components/stepper/test.esp32.yaml | 28 +---- tests/components/stepper/test.esp8266.yaml | 28 +---- tests/components/stepper/test.rp2040.yaml | 28 +---- tests/components/sun/common.yaml | 38 ++++++ tests/components/sun/test.esp32-c3-idf.yaml | 39 +----- tests/components/sun/test.esp32-c3.yaml | 39 +----- tests/components/sun/test.esp32-idf.yaml | 39 +----- tests/components/sun/test.esp32.yaml | 39 +----- tests/components/sun/test.esp8266.yaml | 39 +----- tests/components/sun/test.rp2040.yaml | 39 +----- tests/components/thermostat/common.yaml | 93 ++++++++++++++ .../thermostat/test.esp32-c3-idf.yaml | 94 +------------- .../components/thermostat/test.esp32-c3.yaml | 94 +------------- .../components/thermostat/test.esp32-idf.yaml | 94 +------------- tests/components/thermostat/test.esp32.yaml | 94 +------------- tests/components/thermostat/test.esp8266.yaml | 94 +------------- tests/components/thermostat/test.rp2040.yaml | 94 +------------- tests/components/time/common.yaml | 10 ++ tests/components/time/test.esp32-c3-idf.yaml | 11 +- tests/components/time/test.esp32-c3.yaml | 11 +- tests/components/time/test.esp32-idf.yaml | 11 +- tests/components/time/test.esp32.yaml | 11 +- tests/components/time/test.esp8266.yaml | 11 +- tests/components/time/test.rp2040.yaml | 11 +- tests/components/time_based/common.yaml | 12 ++ .../time_based/test.esp32-c3-idf.yaml | 13 +- .../components/time_based/test.esp32-c3.yaml | 13 +- .../components/time_based/test.esp32-idf.yaml | 13 +- tests/components/time_based/test.esp32.yaml | 13 +- tests/components/time_based/test.esp8266.yaml | 13 +- tests/components/time_based/test.rp2040.yaml | 13 +- tests/components/tm1638/common.yaml | 118 +++++++++++++++++ .../components/tm1638/test.esp32-c3-idf.yaml | 119 +----------------- tests/components/tm1638/test.esp32-c3.yaml | 119 +----------------- tests/components/tm1638/test.esp32-idf.yaml | 119 +----------------- tests/components/tm1638/test.esp32.yaml | 119 +----------------- tests/components/tm1638/test.esp8266.yaml | 119 +----------------- tests/components/tm1638/test.rp2040.yaml | 119 +----------------- tests/components/tm1651/common.yaml | 21 ++++ tests/components/tm1651/test.esp32-c3.yaml | 22 +--- tests/components/tm1651/test.esp32.yaml | 22 +--- tests/components/tm1651/test.esp8266.yaml | 22 +--- tests/components/tm1651/test.rp2040.yaml | 22 +--- tests/components/tx20/common.yaml | 7 ++ tests/components/tx20/test.esp32-c3-idf.yaml | 8 +- tests/components/tx20/test.esp32-c3.yaml | 8 +- tests/components/tx20/test.esp32-idf.yaml | 8 +- tests/components/tx20/test.esp32.yaml | 8 +- tests/components/tx20/test.esp8266.yaml | 8 +- tests/components/tx20/test.rp2040.yaml | 8 +- tests/components/ultrasonic/common.yaml | 7 ++ .../ultrasonic/test.esp32-c3-idf.yaml | 8 +- .../components/ultrasonic/test.esp32-c3.yaml | 8 +- .../components/ultrasonic/test.esp32-idf.yaml | 8 +- tests/components/ultrasonic/test.esp32.yaml | 8 +- tests/components/ultrasonic/test.esp8266.yaml | 8 +- tests/components/ultrasonic/test.rp2040.yaml | 8 +- tests/components/uptime/common.yaml | 3 + .../components/uptime/test.esp32-c3-idf.yaml | 4 +- tests/components/uptime/test.esp32-c3.yaml | 4 +- tests/components/uptime/test.esp32-idf.yaml | 4 +- tests/components/uptime/test.esp32.yaml | 4 +- tests/components/uptime/test.esp8266.yaml | 4 +- tests/components/uptime/test.rp2040.yaml | 4 +- tests/components/version/common.yaml | 3 + .../components/version/test.esp32-c3-idf.yaml | 4 +- tests/components/version/test.esp32-c3.yaml | 4 +- tests/components/version/test.esp32-idf.yaml | 4 +- tests/components/version/test.esp32.yaml | 4 +- tests/components/version/test.esp8266.yaml | 4 +- tests/components/version/test.rp2040.yaml | 4 +- tests/components/wake_on_lan/common.yaml | 9 ++ .../components/wake_on_lan/test.esp32-c3.yaml | 10 +- tests/components/wake_on_lan/test.esp32.yaml | 10 +- .../components/wake_on_lan/test.esp8266.yaml | 10 +- tests/components/wake_on_lan/test.rp2040.yaml | 10 +- tests/components/web_server/common.yaml | 7 ++ .../web_server/test.esp32-c3-idf.yaml | 8 +- .../components/web_server/test.esp32-c3.yaml | 8 +- .../components/web_server/test.esp32-idf.yaml | 8 +- tests/components/web_server/test.esp32.yaml | 8 +- tests/components/web_server/test.esp8266.yaml | 8 +- tests/components/wiegand/common.yaml | 10 ++ .../components/wiegand/test.esp32-c3-idf.yaml | 11 +- tests/components/wiegand/test.esp32-c3.yaml | 11 +- tests/components/wiegand/test.esp32-idf.yaml | 11 +- tests/components/wiegand/test.esp32.yaml | 11 +- tests/components/wiegand/test.esp8266.yaml | 11 +- tests/components/wiegand/test.rp2040.yaml | 11 +- tests/components/wifi/common.yaml | 9 ++ tests/components/wifi/test.esp32-c3-idf.yaml | 10 +- tests/components/wifi/test.esp32-c3.yaml | 10 +- tests/components/wifi/test.esp32-idf.yaml | 10 +- tests/components/wifi/test.esp32.yaml | 10 +- tests/components/wifi/test.esp8266.yaml | 10 +- tests/components/wifi/test.rp2040.yaml | 10 +- tests/components/wifi_info/common.yaml | 18 +++ .../wifi_info/test.esp32-c3-idf.yaml | 19 +-- tests/components/wifi_info/test.esp32-c3.yaml | 19 +-- .../components/wifi_info/test.esp32-idf.yaml | 19 +-- tests/components/wifi_info/test.esp32.yaml | 19 +-- tests/components/wifi_info/test.esp8266.yaml | 19 +-- tests/components/wifi_info/test.rp2040.yaml | 19 +-- tests/components/wifi_signal/common.yaml | 8 ++ .../wifi_signal/test.esp32-c3-idf.yaml | 9 +- .../components/wifi_signal/test.esp32-c3.yaml | 9 +- .../wifi_signal/test.esp32-idf.yaml | 9 +- tests/components/wifi_signal/test.esp32.yaml | 9 +- .../components/wifi_signal/test.esp8266.yaml | 9 +- tests/components/wifi_signal/test.rp2040.yaml | 9 +- tests/components/xiaomi_ble/common.yaml | 3 + .../xiaomi_ble/test.esp32-c3-idf.yaml | 4 +- .../components/xiaomi_ble/test.esp32-c3.yaml | 4 +- .../components/xiaomi_ble/test.esp32-idf.yaml | 4 +- tests/components/xiaomi_ble/test.esp32.yaml | 4 +- tests/components/xiaomi_cgd1/common.yaml | 12 ++ .../xiaomi_cgd1/test.esp32-c3-idf.yaml | 13 +- .../components/xiaomi_cgd1/test.esp32-c3.yaml | 13 +- .../xiaomi_cgd1/test.esp32-idf.yaml | 13 +- tests/components/xiaomi_cgd1/test.esp32.yaml | 13 +- tests/components/xiaomi_cgdk2/common.yaml | 12 ++ .../xiaomi_cgdk2/test.esp32-c3-idf.yaml | 13 +- .../xiaomi_cgdk2/test.esp32-c3.yaml | 13 +- .../xiaomi_cgdk2/test.esp32-idf.yaml | 13 +- tests/components/xiaomi_cgdk2/test.esp32.yaml | 13 +- tests/components/xiaomi_cgg1/common.yaml | 12 ++ .../xiaomi_cgg1/test.esp32-c3-idf.yaml | 13 +- .../components/xiaomi_cgg1/test.esp32-c3.yaml | 13 +- .../xiaomi_cgg1/test.esp32-idf.yaml | 13 +- tests/components/xiaomi_cgg1/test.esp32.yaml | 13 +- tests/components/xiaomi_cgpr1/common.yaml | 13 ++ .../xiaomi_cgpr1/test.esp32-c3-idf.yaml | 14 +-- .../xiaomi_cgpr1/test.esp32-c3.yaml | 14 +-- .../xiaomi_cgpr1/test.esp32-idf.yaml | 14 +-- tests/components/xiaomi_cgpr1/test.esp32.yaml | 14 +-- tests/components/xiaomi_gcls002/common.yaml | 13 ++ .../xiaomi_gcls002/test.esp32-c3-idf.yaml | 14 +-- .../xiaomi_gcls002/test.esp32-c3.yaml | 14 +-- .../xiaomi_gcls002/test.esp32-idf.yaml | 14 +-- .../components/xiaomi_gcls002/test.esp32.yaml | 14 +-- tests/components/xiaomi_hhccjcy01/common.yaml | 15 +++ .../xiaomi_hhccjcy01/test.esp32-c3-idf.yaml | 16 +-- .../xiaomi_hhccjcy01/test.esp32-c3.yaml | 16 +-- .../xiaomi_hhccjcy01/test.esp32-idf.yaml | 16 +-- .../xiaomi_hhccjcy01/test.esp32.yaml | 16 +-- .../components/xiaomi_hhccpot002/common.yaml | 9 ++ .../xiaomi_hhccpot002/test.esp32-c3-idf.yaml | 10 +- .../xiaomi_hhccpot002/test.esp32-c3.yaml | 10 +- .../xiaomi_hhccpot002/test.esp32-idf.yaml | 10 +- .../xiaomi_hhccpot002/test.esp32.yaml | 10 +- tests/components/xiaomi_jqjcy01ym/common.yaml | 13 ++ .../xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml | 14 +-- .../xiaomi_jqjcy01ym/test.esp32-c3.yaml | 14 +-- .../xiaomi_jqjcy01ym/test.esp32-idf.yaml | 14 +-- .../xiaomi_jqjcy01ym/test.esp32.yaml | 14 +-- tests/components/xiaomi_lywsd02/common.yaml | 11 ++ .../xiaomi_lywsd02/test.esp32-c3-idf.yaml | 12 +- .../xiaomi_lywsd02/test.esp32-c3.yaml | 12 +- .../xiaomi_lywsd02/test.esp32-idf.yaml | 12 +- .../components/xiaomi_lywsd02/test.esp32.yaml | 12 +- .../components/xiaomi_lywsd03mmc/common.yaml | 12 ++ .../xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml | 13 +- .../xiaomi_lywsd03mmc/test.esp32-c3.yaml | 13 +- .../xiaomi_lywsd03mmc/test.esp32-idf.yaml | 13 +- .../xiaomi_lywsd03mmc/test.esp32.yaml | 13 +- tests/components/xiaomi_lywsdcgq/common.yaml | 11 ++ .../xiaomi_lywsdcgq/test.esp32-c3-idf.yaml | 12 +- .../xiaomi_lywsdcgq/test.esp32-c3.yaml | 12 +- .../xiaomi_lywsdcgq/test.esp32-idf.yaml | 12 +- .../xiaomi_lywsdcgq/test.esp32.yaml | 12 +- tests/components/xiaomi_mhoc303/common.yaml | 11 ++ .../xiaomi_mhoc303/test.esp32-c3-idf.yaml | 12 +- .../xiaomi_mhoc303/test.esp32-c3.yaml | 12 +- .../xiaomi_mhoc303/test.esp32-idf.yaml | 12 +- .../components/xiaomi_mhoc303/test.esp32.yaml | 12 +- tests/components/xiaomi_mhoc401/common.yaml | 12 ++ .../xiaomi_mhoc401/test.esp32-c3-idf.yaml | 13 +- .../xiaomi_mhoc401/test.esp32-c3.yaml | 13 +- .../xiaomi_mhoc401/test.esp32-idf.yaml | 13 +- .../components/xiaomi_mhoc401/test.esp32.yaml | 13 +- .../xiaomi_miscale copy/common.yaml | 9 ++ .../test.esp32-c3-idf.yaml | 10 +- .../xiaomi_miscale copy/test.esp32-c3.yaml | 10 +- .../xiaomi_miscale copy/test.esp32-idf.yaml | 10 +- .../xiaomi_miscale copy/test.esp32.yaml | 10 +- tests/components/xiaomi_miscale/common.yaml | 9 ++ .../xiaomi_miscale/test.esp32-c3-idf.yaml | 10 +- .../xiaomi_miscale/test.esp32-c3.yaml | 10 +- .../xiaomi_miscale/test.esp32-idf.yaml | 10 +- .../components/xiaomi_miscale/test.esp32.yaml | 10 +- tests/components/xiaomi_mjyd02yla/common.yaml | 13 ++ .../xiaomi_mjyd02yla/test.esp32-c3-idf.yaml | 14 +-- .../xiaomi_mjyd02yla/test.esp32-c3.yaml | 14 +-- .../xiaomi_mjyd02yla/test.esp32-idf.yaml | 14 +-- .../xiaomi_mjyd02yla/test.esp32.yaml | 14 +-- tests/components/xiaomi_mue4094rt/common.yaml | 7 ++ .../xiaomi_mue4094rt/test.esp32-c3-idf.yaml | 8 +- .../xiaomi_mue4094rt/test.esp32-c3.yaml | 8 +- .../xiaomi_mue4094rt/test.esp32-idf.yaml | 8 +- .../xiaomi_mue4094rt/test.esp32.yaml | 8 +- tests/components/xiaomi_rtcgq02lm/common.yaml | 22 ++++ .../xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml | 23 +--- .../xiaomi_rtcgq02lm/test.esp32-c3.yaml | 23 +--- .../xiaomi_rtcgq02lm/test.esp32-idf.yaml | 23 +--- .../xiaomi_rtcgq02lm/test.esp32.yaml | 23 +--- tests/components/xiaomi_wx08zm/common.yaml | 10 ++ .../xiaomi_wx08zm/test.esp32-c3-idf.yaml | 11 +- .../xiaomi_wx08zm/test.esp32-c3.yaml | 11 +- .../xiaomi_wx08zm/test.esp32-idf.yaml | 11 +- .../components/xiaomi_wx08zm/test.esp32.yaml | 11 +- 779 files changed, 3474 insertions(+), 12186 deletions(-) create mode 100644 tests/components/absolute_humidity/common.yaml create mode 100644 tests/components/airthings_wave_mini/common.yaml create mode 100644 tests/components/airthings_wave_plus/common.yaml create mode 100644 tests/components/alarm_control_panel/common.yaml create mode 100644 tests/components/alpha3/common.yaml create mode 100644 tests/components/am43/common.yaml create mode 100644 tests/components/analog_threshold/common.yaml create mode 100644 tests/components/anova/common.yaml create mode 100644 tests/components/api/common.yaml create mode 100644 tests/components/atc_mithermometer/common.yaml create mode 100644 tests/components/b_parasite/common.yaml create mode 100644 tests/components/bang_bang/common.yaml create mode 100644 tests/components/bedjet/common.yaml create mode 100644 tests/components/binary_sensor_map/common.yaml create mode 100644 tests/components/ble_client/common.yaml create mode 100644 tests/components/ble_presence/common.yaml create mode 100644 tests/components/ble_rssi/common.yaml create mode 100644 tests/components/ble_scanner/common.yaml create mode 100644 tests/components/button/common.yaml create mode 100644 tests/components/canbus/common.yaml create mode 100644 tests/components/captive_portal/common.yaml create mode 100644 tests/components/color/common.yaml create mode 100644 tests/components/combination/common.yaml create mode 100644 tests/components/cst226/common.yaml create mode 100644 tests/components/cst816/common.yaml create mode 100644 tests/components/dallas/common.yaml create mode 100644 tests/components/datetime/common.yaml create mode 100644 tests/components/debug/common.yaml create mode 100644 tests/components/dht/common.yaml create mode 100644 tests/components/display/common.yaml create mode 100644 tests/components/duty_cycle/common.yaml create mode 100644 tests/components/duty_time/common.yaml create mode 100644 tests/components/endstop/common.yaml create mode 100644 tests/components/esp32_ble/common.yaml create mode 100644 tests/components/esp32_ble_beacon/common.yaml create mode 100644 tests/components/esp32_ble_client/common.yaml create mode 100644 tests/components/esp32_ble_server/common.yaml create mode 100644 tests/components/esp32_ble_tracker/common.yaml create mode 100644 tests/components/esp32_camera/common.yaml create mode 100644 tests/components/esp32_camera_web_server/common.yaml create mode 100644 tests/components/esp32_dac/common.yaml create mode 100644 tests/components/esp32_hall/common.yaml create mode 100644 tests/components/esp32_improv/common.yaml create mode 100644 tests/components/esp32_touch/common.yaml create mode 100644 tests/components/esp8266_pwm/common.yaml create mode 100644 tests/components/ethernet/common.yaml create mode 100644 tests/components/ethernet_info/common.yaml create mode 100644 tests/components/event/common.yaml create mode 100644 tests/components/exposure_notifications/common.yaml create mode 100644 tests/components/external_components/common.yaml create mode 100644 tests/components/factory_reset/common.yaml create mode 100644 tests/components/fastled_clockless/common.yaml create mode 100644 tests/components/fastled_spi/common.yaml create mode 100644 tests/components/feedback/common.yaml create mode 100644 tests/components/globals/common.yaml create mode 100644 tests/components/host/common.yaml create mode 100644 tests/components/improv_serial/common.yaml create mode 100644 tests/components/inkbird_ibsth1_mini/common.yaml create mode 100644 tests/components/inkplate6/common.yaml create mode 100644 tests/components/interval/common.yaml create mode 100644 tests/components/ledc/common.yaml create mode 100644 tests/components/lightwaverf/common.yaml create mode 100644 tests/components/lock/common.yaml create mode 100644 tests/components/logger/common.yaml create mode 100644 tests/components/mdns/common.yaml create mode 100644 tests/components/media_player/common.yaml create mode 100644 tests/components/micro_wake_word/common.yaml create mode 100644 tests/components/midea_ir/common.yaml create mode 100644 tests/components/mitsubishi/common.yaml create mode 100644 tests/components/mopeka_ble/common.yaml create mode 100644 tests/components/mopeka_pro_check/common.yaml create mode 100644 tests/components/mopeka_std_check/common.yaml create mode 100644 tests/components/my9231/common.yaml create mode 100644 tests/components/network/common.yaml create mode 100644 tests/components/noblex/common.yaml create mode 100644 tests/components/ota/common.yaml create mode 100644 tests/components/pid/common.yaml create mode 100644 tests/components/power_supply/common.yaml create mode 100644 tests/components/prometheus/common.yaml create mode 100644 tests/components/psram/common.yaml create mode 100644 tests/components/pulse_counter/common.yaml create mode 100644 tests/components/pulse_meter/common.yaml create mode 100644 tests/components/pulse_width/common.yaml create mode 100644 tests/components/pvvx_mithermometer/common.yaml create mode 100644 tests/components/qspi_amoled/common.yaml create mode 100644 tests/components/radon_eye_ble/common.yaml create mode 100644 tests/components/radon_eye_rd200/common.yaml create mode 100644 tests/components/restart/common.yaml create mode 100644 tests/components/rp2040_pio_led_strip/common.yaml create mode 100644 tests/components/rp2040_pwm/common.yaml create mode 100644 tests/components/rpi_dpi_rgb/common.yaml create mode 100644 tests/components/ruuvi_ble/common.yaml create mode 100644 tests/components/ruuvitag/common.yaml create mode 100644 tests/components/safe_mode/common.yaml create mode 100644 tests/components/shelly_dimmer/common.yaml create mode 100644 tests/components/shutdown/common.yaml create mode 100644 tests/components/sigma_delta_output/common.yaml create mode 100644 tests/components/slow_pwm/common.yaml create mode 100644 tests/components/sm16716/common.yaml create mode 100644 tests/components/sm2135/common.yaml create mode 100644 tests/components/sm2235/common.yaml create mode 100644 tests/components/sm2335/common.yaml create mode 100644 tests/components/sntp/common.yaml create mode 100644 tests/components/sprinkler/common.yaml create mode 100644 tests/components/st7701s/common.yaml create mode 100644 tests/components/status/common.yaml create mode 100644 tests/components/status_led/common.yaml create mode 100644 tests/components/stepper/common.yaml create mode 100644 tests/components/sun/common.yaml create mode 100644 tests/components/thermostat/common.yaml create mode 100644 tests/components/time/common.yaml create mode 100644 tests/components/time_based/common.yaml create mode 100644 tests/components/tm1638/common.yaml create mode 100644 tests/components/tm1651/common.yaml create mode 100644 tests/components/tx20/common.yaml create mode 100644 tests/components/ultrasonic/common.yaml create mode 100644 tests/components/uptime/common.yaml create mode 100644 tests/components/version/common.yaml create mode 100644 tests/components/wake_on_lan/common.yaml create mode 100644 tests/components/web_server/common.yaml create mode 100644 tests/components/wiegand/common.yaml create mode 100644 tests/components/wifi/common.yaml create mode 100644 tests/components/wifi_info/common.yaml create mode 100644 tests/components/wifi_signal/common.yaml create mode 100644 tests/components/xiaomi_ble/common.yaml create mode 100644 tests/components/xiaomi_cgd1/common.yaml create mode 100644 tests/components/xiaomi_cgdk2/common.yaml create mode 100644 tests/components/xiaomi_cgg1/common.yaml create mode 100644 tests/components/xiaomi_cgpr1/common.yaml create mode 100644 tests/components/xiaomi_gcls002/common.yaml create mode 100644 tests/components/xiaomi_hhccjcy01/common.yaml create mode 100644 tests/components/xiaomi_hhccpot002/common.yaml create mode 100644 tests/components/xiaomi_jqjcy01ym/common.yaml create mode 100644 tests/components/xiaomi_lywsd02/common.yaml create mode 100644 tests/components/xiaomi_lywsd03mmc/common.yaml create mode 100644 tests/components/xiaomi_lywsdcgq/common.yaml create mode 100644 tests/components/xiaomi_mhoc303/common.yaml create mode 100644 tests/components/xiaomi_mhoc401/common.yaml create mode 100644 tests/components/xiaomi_miscale copy/common.yaml create mode 100644 tests/components/xiaomi_miscale/common.yaml create mode 100644 tests/components/xiaomi_mjyd02yla/common.yaml create mode 100644 tests/components/xiaomi_mue4094rt/common.yaml create mode 100644 tests/components/xiaomi_rtcgq02lm/common.yaml create mode 100644 tests/components/xiaomi_wx08zm/common.yaml diff --git a/tests/components/absolute_humidity/common.yaml b/tests/components/absolute_humidity/common.yaml new file mode 100644 index 0000000000..87a99f5206 --- /dev/null +++ b/tests/components/absolute_humidity/common.yaml @@ -0,0 +1,21 @@ +sensor: + - platform: absolute_humidity + name: Absolute Humidity + temperature: template_temperature + humidity: template_humidity + - platform: template + id: template_humidity + lambda: |- + if (millis() > 10000) { + return 0.6; + } else { + return 0.0; + } + - platform: template + id: template_temperature + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } diff --git a/tests/components/absolute_humidity/test.esp32-c3-idf.yaml b/tests/components/absolute_humidity/test.esp32-c3-idf.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.esp32-c3-idf.yaml +++ b/tests/components/absolute_humidity/test.esp32-c3-idf.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/absolute_humidity/test.esp32-c3.yaml b/tests/components/absolute_humidity/test.esp32-c3.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.esp32-c3.yaml +++ b/tests/components/absolute_humidity/test.esp32-c3.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/absolute_humidity/test.esp32-idf.yaml b/tests/components/absolute_humidity/test.esp32-idf.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.esp32-idf.yaml +++ b/tests/components/absolute_humidity/test.esp32-idf.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/absolute_humidity/test.esp32.yaml b/tests/components/absolute_humidity/test.esp32.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.esp32.yaml +++ b/tests/components/absolute_humidity/test.esp32.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/absolute_humidity/test.esp8266.yaml b/tests/components/absolute_humidity/test.esp8266.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.esp8266.yaml +++ b/tests/components/absolute_humidity/test.esp8266.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/absolute_humidity/test.rp2040.yaml b/tests/components/absolute_humidity/test.rp2040.yaml index 87a99f5206..dade44d145 100644 --- a/tests/components/absolute_humidity/test.rp2040.yaml +++ b/tests/components/absolute_humidity/test.rp2040.yaml @@ -1,21 +1 @@ -sensor: - - platform: absolute_humidity - name: Absolute Humidity - temperature: template_temperature - humidity: template_humidity - - platform: template - id: template_humidity - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } +<<: !include common.yaml diff --git a/tests/components/airthings_wave_mini/common.yaml b/tests/components/airthings_wave_mini/common.yaml new file mode 100644 index 0000000000..87902e6c66 --- /dev/null +++ b/tests/components/airthings_wave_mini/common.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: airthingsmini01 + +sensor: + - id: airthingswm + platform: airthings_wave_mini + ble_client_id: airthingsmini01 + update_interval: 5min + battery_update_interval: 12h + temperature: + name: Wave Mini Temperature + humidity: + name: Wave Mini Humidity + pressure: + name: Wave Mini Pressure + tvoc: + name: Wave Mini VOC + battery_voltage: + name: Wave Mini Battery Voltage diff --git a/tests/components/airthings_wave_mini/test.esp32-c3-idf.yaml b/tests/components/airthings_wave_mini/test.esp32-c3-idf.yaml index 87902e6c66..dade44d145 100644 --- a/tests/components/airthings_wave_mini/test.esp32-c3-idf.yaml +++ b/tests/components/airthings_wave_mini/test.esp32-c3-idf.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthingsmini01 - -sensor: - - id: airthingswm - platform: airthings_wave_mini - ble_client_id: airthingsmini01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Mini Temperature - humidity: - name: Wave Mini Humidity - pressure: - name: Wave Mini Pressure - tvoc: - name: Wave Mini VOC - battery_voltage: - name: Wave Mini Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_mini/test.esp32-c3.yaml b/tests/components/airthings_wave_mini/test.esp32-c3.yaml index 87902e6c66..dade44d145 100644 --- a/tests/components/airthings_wave_mini/test.esp32-c3.yaml +++ b/tests/components/airthings_wave_mini/test.esp32-c3.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthingsmini01 - -sensor: - - id: airthingswm - platform: airthings_wave_mini - ble_client_id: airthingsmini01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Mini Temperature - humidity: - name: Wave Mini Humidity - pressure: - name: Wave Mini Pressure - tvoc: - name: Wave Mini VOC - battery_voltage: - name: Wave Mini Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_mini/test.esp32-idf.yaml b/tests/components/airthings_wave_mini/test.esp32-idf.yaml index 87902e6c66..dade44d145 100644 --- a/tests/components/airthings_wave_mini/test.esp32-idf.yaml +++ b/tests/components/airthings_wave_mini/test.esp32-idf.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthingsmini01 - -sensor: - - id: airthingswm - platform: airthings_wave_mini - ble_client_id: airthingsmini01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Mini Temperature - humidity: - name: Wave Mini Humidity - pressure: - name: Wave Mini Pressure - tvoc: - name: Wave Mini VOC - battery_voltage: - name: Wave Mini Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_mini/test.esp32.yaml b/tests/components/airthings_wave_mini/test.esp32.yaml index 87902e6c66..dade44d145 100644 --- a/tests/components/airthings_wave_mini/test.esp32.yaml +++ b/tests/components/airthings_wave_mini/test.esp32.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthingsmini01 - -sensor: - - id: airthingswm - platform: airthings_wave_mini - ble_client_id: airthingsmini01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Mini Temperature - humidity: - name: Wave Mini Humidity - pressure: - name: Wave Mini Pressure - tvoc: - name: Wave Mini VOC - battery_voltage: - name: Wave Mini Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_plus/common.yaml b/tests/components/airthings_wave_plus/common.yaml new file mode 100644 index 0000000000..2124fcdaec --- /dev/null +++ b/tests/components/airthings_wave_plus/common.yaml @@ -0,0 +1,28 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: airthings01 + +sensor: + - id: airthingswp + platform: airthings_wave_plus + ble_client_id: airthings01 + update_interval: 5min + battery_update_interval: 12h + temperature: + name: Wave Plus Temperature + radon: + name: Wave Plus Radon + radon_long_term: + name: Wave Plus Radon Long Term + pressure: + name: Wave Plus Pressure + humidity: + name: Wave Plus Humidity + co2: + name: Wave Plus CO2 + tvoc: + name: Wave Plus VOC + battery_voltage: + name: Wave Plus Battery Voltage diff --git a/tests/components/airthings_wave_plus/test.esp32-c3-idf.yaml b/tests/components/airthings_wave_plus/test.esp32-c3-idf.yaml index 2124fcdaec..dade44d145 100644 --- a/tests/components/airthings_wave_plus/test.esp32-c3-idf.yaml +++ b/tests/components/airthings_wave_plus/test.esp32-c3-idf.yaml @@ -1,28 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthings01 - -sensor: - - id: airthingswp - platform: airthings_wave_plus - ble_client_id: airthings01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Plus Temperature - radon: - name: Wave Plus Radon - radon_long_term: - name: Wave Plus Radon Long Term - pressure: - name: Wave Plus Pressure - humidity: - name: Wave Plus Humidity - co2: - name: Wave Plus CO2 - tvoc: - name: Wave Plus VOC - battery_voltage: - name: Wave Plus Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_plus/test.esp32-c3.yaml b/tests/components/airthings_wave_plus/test.esp32-c3.yaml index 2124fcdaec..dade44d145 100644 --- a/tests/components/airthings_wave_plus/test.esp32-c3.yaml +++ b/tests/components/airthings_wave_plus/test.esp32-c3.yaml @@ -1,28 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthings01 - -sensor: - - id: airthingswp - platform: airthings_wave_plus - ble_client_id: airthings01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Plus Temperature - radon: - name: Wave Plus Radon - radon_long_term: - name: Wave Plus Radon Long Term - pressure: - name: Wave Plus Pressure - humidity: - name: Wave Plus Humidity - co2: - name: Wave Plus CO2 - tvoc: - name: Wave Plus VOC - battery_voltage: - name: Wave Plus Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_plus/test.esp32-idf.yaml b/tests/components/airthings_wave_plus/test.esp32-idf.yaml index 2124fcdaec..dade44d145 100644 --- a/tests/components/airthings_wave_plus/test.esp32-idf.yaml +++ b/tests/components/airthings_wave_plus/test.esp32-idf.yaml @@ -1,28 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthings01 - -sensor: - - id: airthingswp - platform: airthings_wave_plus - ble_client_id: airthings01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Plus Temperature - radon: - name: Wave Plus Radon - radon_long_term: - name: Wave Plus Radon Long Term - pressure: - name: Wave Plus Pressure - humidity: - name: Wave Plus Humidity - co2: - name: Wave Plus CO2 - tvoc: - name: Wave Plus VOC - battery_voltage: - name: Wave Plus Battery Voltage +<<: !include common.yaml diff --git a/tests/components/airthings_wave_plus/test.esp32.yaml b/tests/components/airthings_wave_plus/test.esp32.yaml index 2124fcdaec..dade44d145 100644 --- a/tests/components/airthings_wave_plus/test.esp32.yaml +++ b/tests/components/airthings_wave_plus/test.esp32.yaml @@ -1,28 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthings01 - -sensor: - - id: airthingswp - platform: airthings_wave_plus - ble_client_id: airthings01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Plus Temperature - radon: - name: Wave Plus Radon - radon_long_term: - name: Wave Plus Radon Long Term - pressure: - name: Wave Plus Pressure - humidity: - name: Wave Plus Humidity - co2: - name: Wave Plus CO2 - tvoc: - name: Wave Plus VOC - battery_voltage: - name: Wave Plus Battery Voltage +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/common.yaml b/tests/components/alarm_control_panel/common.yaml new file mode 100644 index 0000000000..218274bad4 --- /dev/null +++ b/tests/components/alarm_control_panel/common.yaml @@ -0,0 +1,64 @@ +binary_sensor: + - platform: gpio + id: bin1 + pin: 1 + +alarm_control_panel: + - platform: template + id: alarmcontrolpanel1 + name: Alarm Panel + codes: + - "1234" + requires_code_to_arm: true + arming_home_time: 1s + arming_night_time: 1s + arming_away_time: 15s + pending_time: 15s + trigger_time: 30s + binary_sensors: + - input: bin1 + bypass_armed_home: true + bypass_armed_night: true + on_state: + then: + - lambda: !lambda |- + ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); + - platform: template + id: alarmcontrolpanel2 + name: Alarm Panel + codes: + - "1234" + requires_code_to_arm: true + arming_home_time: 1s + arming_night_time: 1s + arming_away_time: 15s + pending_time: 15s + trigger_time: 30s + binary_sensors: + - input: bin1 + bypass_armed_home: true + bypass_armed_night: true + on_disarmed: + then: + - logger.log: "### DISARMED ###" + on_pending: + then: + - logger.log: "### PENDING ###" + on_arming: + then: + - logger.log: "### ARMING ###" + on_armed_home: + then: + - logger.log: "### ARMED HOME ###" + on_armed_night: + then: + - logger.log: "### ARMED NIGHT ###" + on_armed_away: + then: + - logger.log: "### ARMED AWAY ###" + on_triggered: + then: + - logger.log: "### TRIGGERED ###" + on_cleared: + then: + - logger.log: "### CLEARED ###" diff --git a/tests/components/alarm_control_panel/test.esp32-c3-idf.yaml b/tests/components/alarm_control_panel/test.esp32-c3-idf.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.esp32-c3-idf.yaml +++ b/tests/components/alarm_control_panel/test.esp32-c3-idf.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/test.esp32-c3.yaml b/tests/components/alarm_control_panel/test.esp32-c3.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.esp32-c3.yaml +++ b/tests/components/alarm_control_panel/test.esp32-c3.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/test.esp32-idf.yaml b/tests/components/alarm_control_panel/test.esp32-idf.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.esp32-idf.yaml +++ b/tests/components/alarm_control_panel/test.esp32-idf.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/test.esp32.yaml b/tests/components/alarm_control_panel/test.esp32.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.esp32.yaml +++ b/tests/components/alarm_control_panel/test.esp32.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/test.esp8266.yaml b/tests/components/alarm_control_panel/test.esp8266.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.esp8266.yaml +++ b/tests/components/alarm_control_panel/test.esp8266.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alarm_control_panel/test.rp2040.yaml b/tests/components/alarm_control_panel/test.rp2040.yaml index 218274bad4..dade44d145 100644 --- a/tests/components/alarm_control_panel/test.rp2040.yaml +++ b/tests/components/alarm_control_panel/test.rp2040.yaml @@ -1,64 +1 @@ -binary_sensor: - - platform: gpio - id: bin1 - pin: 1 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state()))); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" +<<: !include common.yaml diff --git a/tests/components/alpha3/common.yaml b/tests/components/alpha3/common.yaml new file mode 100644 index 0000000000..913f086ac4 --- /dev/null +++ b/tests/components/alpha3/common.yaml @@ -0,0 +1,17 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: alpha3_blec + +sensor: + - platform: alpha3 + ble_client_id: alpha3_blec + flow: + name: "Radiator Pump Flow" + head: + name: "Radiator Pump Head" + power: + name: "Radiator Pump Power" + speed: + name: "Radiator Pump Speed" diff --git a/tests/components/alpha3/test.esp32-c3-idf.yaml b/tests/components/alpha3/test.esp32-c3-idf.yaml index 913f086ac4..dade44d145 100644 --- a/tests/components/alpha3/test.esp32-c3-idf.yaml +++ b/tests/components/alpha3/test.esp32-c3-idf.yaml @@ -1,17 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: alpha3_blec - -sensor: - - platform: alpha3 - ble_client_id: alpha3_blec - flow: - name: "Radiator Pump Flow" - head: - name: "Radiator Pump Head" - power: - name: "Radiator Pump Power" - speed: - name: "Radiator Pump Speed" +<<: !include common.yaml diff --git a/tests/components/alpha3/test.esp32-c3.yaml b/tests/components/alpha3/test.esp32-c3.yaml index 913f086ac4..dade44d145 100644 --- a/tests/components/alpha3/test.esp32-c3.yaml +++ b/tests/components/alpha3/test.esp32-c3.yaml @@ -1,17 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: alpha3_blec - -sensor: - - platform: alpha3 - ble_client_id: alpha3_blec - flow: - name: "Radiator Pump Flow" - head: - name: "Radiator Pump Head" - power: - name: "Radiator Pump Power" - speed: - name: "Radiator Pump Speed" +<<: !include common.yaml diff --git a/tests/components/alpha3/test.esp32-idf.yaml b/tests/components/alpha3/test.esp32-idf.yaml index 913f086ac4..dade44d145 100644 --- a/tests/components/alpha3/test.esp32-idf.yaml +++ b/tests/components/alpha3/test.esp32-idf.yaml @@ -1,17 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: alpha3_blec - -sensor: - - platform: alpha3 - ble_client_id: alpha3_blec - flow: - name: "Radiator Pump Flow" - head: - name: "Radiator Pump Head" - power: - name: "Radiator Pump Power" - speed: - name: "Radiator Pump Speed" +<<: !include common.yaml diff --git a/tests/components/alpha3/test.esp32.yaml b/tests/components/alpha3/test.esp32.yaml index 913f086ac4..dade44d145 100644 --- a/tests/components/alpha3/test.esp32.yaml +++ b/tests/components/alpha3/test.esp32.yaml @@ -1,17 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: alpha3_blec - -sensor: - - platform: alpha3 - ble_client_id: alpha3_blec - flow: - name: "Radiator Pump Flow" - head: - name: "Radiator Pump Head" - power: - name: "Radiator Pump Power" - speed: - name: "Radiator Pump Speed" +<<: !include common.yaml diff --git a/tests/components/am43/common.yaml b/tests/components/am43/common.yaml new file mode 100644 index 0000000000..60b7d81a55 --- /dev/null +++ b/tests/components/am43/common.yaml @@ -0,0 +1,19 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: am43_blec + +cover: + - platform: am43 + name: Test AM43 Cover + id: am43_test + ble_client_id: am43_blec + +sensor: + - platform: am43 + ble_client_id: am43_blec + battery_level: + name: Kitchen blinds battery + illuminance: + name: Kitchen blinds light diff --git a/tests/components/am43/test.esp32-c3-idf.yaml b/tests/components/am43/test.esp32-c3-idf.yaml index 60b7d81a55..dade44d145 100644 --- a/tests/components/am43/test.esp32-c3-idf.yaml +++ b/tests/components/am43/test.esp32-c3-idf.yaml @@ -1,19 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: am43_blec - -cover: - - platform: am43 - name: Test AM43 Cover - id: am43_test - ble_client_id: am43_blec - -sensor: - - platform: am43 - ble_client_id: am43_blec - battery_level: - name: Kitchen blinds battery - illuminance: - name: Kitchen blinds light +<<: !include common.yaml diff --git a/tests/components/am43/test.esp32-c3.yaml b/tests/components/am43/test.esp32-c3.yaml index 60b7d81a55..dade44d145 100644 --- a/tests/components/am43/test.esp32-c3.yaml +++ b/tests/components/am43/test.esp32-c3.yaml @@ -1,19 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: am43_blec - -cover: - - platform: am43 - name: Test AM43 Cover - id: am43_test - ble_client_id: am43_blec - -sensor: - - platform: am43 - ble_client_id: am43_blec - battery_level: - name: Kitchen blinds battery - illuminance: - name: Kitchen blinds light +<<: !include common.yaml diff --git a/tests/components/am43/test.esp32-idf.yaml b/tests/components/am43/test.esp32-idf.yaml index 60b7d81a55..dade44d145 100644 --- a/tests/components/am43/test.esp32-idf.yaml +++ b/tests/components/am43/test.esp32-idf.yaml @@ -1,19 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: am43_blec - -cover: - - platform: am43 - name: Test AM43 Cover - id: am43_test - ble_client_id: am43_blec - -sensor: - - platform: am43 - ble_client_id: am43_blec - battery_level: - name: Kitchen blinds battery - illuminance: - name: Kitchen blinds light +<<: !include common.yaml diff --git a/tests/components/am43/test.esp32.yaml b/tests/components/am43/test.esp32.yaml index 60b7d81a55..dade44d145 100644 --- a/tests/components/am43/test.esp32.yaml +++ b/tests/components/am43/test.esp32.yaml @@ -1,19 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: am43_blec - -cover: - - platform: am43 - name: Test AM43 Cover - id: am43_test - ble_client_id: am43_blec - -sensor: - - platform: am43 - ble_client_id: am43_blec - battery_level: - name: Kitchen blinds battery - illuminance: - name: Kitchen blinds light +<<: !include common.yaml diff --git a/tests/components/analog_threshold/common.yaml b/tests/components/analog_threshold/common.yaml new file mode 100644 index 0000000000..b5c14dfe56 --- /dev/null +++ b/tests/components/analog_threshold/common.yaml @@ -0,0 +1,28 @@ +sensor: + - platform: template + id: template_sensor + name: Template Sensor + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 15s + +binary_sensor: + - platform: analog_threshold + name: Analog Threshold 1 + sensor_id: template_sensor + threshold: + upper: 110 + lower: 90 + filters: + - delayed_on: 0s + - delayed_off: 10s + - platform: analog_threshold + name: Analog Threshold 2 + sensor_id: template_sensor + threshold: 100 + filters: + - invert: diff --git a/tests/components/analog_threshold/test.esp32-c3-idf.yaml b/tests/components/analog_threshold/test.esp32-c3-idf.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.esp32-c3-idf.yaml +++ b/tests/components/analog_threshold/test.esp32-c3-idf.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/analog_threshold/test.esp32-c3.yaml b/tests/components/analog_threshold/test.esp32-c3.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.esp32-c3.yaml +++ b/tests/components/analog_threshold/test.esp32-c3.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/analog_threshold/test.esp32-idf.yaml b/tests/components/analog_threshold/test.esp32-idf.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.esp32-idf.yaml +++ b/tests/components/analog_threshold/test.esp32-idf.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/analog_threshold/test.esp32.yaml b/tests/components/analog_threshold/test.esp32.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.esp32.yaml +++ b/tests/components/analog_threshold/test.esp32.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/analog_threshold/test.esp8266.yaml b/tests/components/analog_threshold/test.esp8266.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.esp8266.yaml +++ b/tests/components/analog_threshold/test.esp8266.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/analog_threshold/test.rp2040.yaml b/tests/components/analog_threshold/test.rp2040.yaml index b5c14dfe56..dade44d145 100644 --- a/tests/components/analog_threshold/test.rp2040.yaml +++ b/tests/components/analog_threshold/test.rp2040.yaml @@ -1,28 +1 @@ -sensor: - - platform: template - id: template_sensor - name: Template Sensor - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 15s - -binary_sensor: - - platform: analog_threshold - name: Analog Threshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Threshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: +<<: !include common.yaml diff --git a/tests/components/anova/common.yaml b/tests/components/anova/common.yaml new file mode 100644 index 0000000000..c4162fe71e --- /dev/null +++ b/tests/components/anova/common.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: anova_blec + +climate: + - platform: anova + name: Anova cooker + ble_client_id: anova_blec + unit_of_measurement: c diff --git a/tests/components/anova/test.esp32-c3-idf.yaml b/tests/components/anova/test.esp32-c3-idf.yaml index c4162fe71e..dade44d145 100644 --- a/tests/components/anova/test.esp32-c3-idf.yaml +++ b/tests/components/anova/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: anova_blec - -climate: - - platform: anova - name: Anova cooker - ble_client_id: anova_blec - unit_of_measurement: c +<<: !include common.yaml diff --git a/tests/components/anova/test.esp32-c3.yaml b/tests/components/anova/test.esp32-c3.yaml index c4162fe71e..dade44d145 100644 --- a/tests/components/anova/test.esp32-c3.yaml +++ b/tests/components/anova/test.esp32-c3.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: anova_blec - -climate: - - platform: anova - name: Anova cooker - ble_client_id: anova_blec - unit_of_measurement: c +<<: !include common.yaml diff --git a/tests/components/anova/test.esp32-idf.yaml b/tests/components/anova/test.esp32-idf.yaml index c4162fe71e..dade44d145 100644 --- a/tests/components/anova/test.esp32-idf.yaml +++ b/tests/components/anova/test.esp32-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: anova_blec - -climate: - - platform: anova - name: Anova cooker - ble_client_id: anova_blec - unit_of_measurement: c +<<: !include common.yaml diff --git a/tests/components/anova/test.esp32.yaml b/tests/components/anova/test.esp32.yaml index c4162fe71e..dade44d145 100644 --- a/tests/components/anova/test.esp32.yaml +++ b/tests/components/anova/test.esp32.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: anova_blec - -climate: - - platform: anova - name: Anova cooker - ble_client_id: anova_blec - unit_of_measurement: c +<<: !include common.yaml diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml new file mode 100644 index 0000000000..3c56811b95 --- /dev/null +++ b/tests/components/api/common.yaml @@ -0,0 +1,63 @@ +esphome: + on_boot: + then: + - homeassistant.event: + event: esphome.button_pressed + data: + message: Button was pressed + - homeassistant.service: + service: notify.html5 + data: + message: Button was pressed + - homeassistant.tag_scanned: pulse + +wifi: + ssid: MySSID + password: password1 + +api: + port: 8000 + password: pwd + reboot_timeout: 0min + encryption: + key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= + services: + - service: hello_world + variables: + name: string + then: + - logger.log: + format: Hello World %s! + args: + - name.c_str() + - service: empty_service + then: + - logger.log: Service Called + - service: all_types + variables: + bool_: bool + int_: int + float_: float + string_: string + then: + - logger.log: Something happened + - service: array_types + variables: + bool_arr: bool[] + int_arr: int[] + float_arr: float[] + string_arr: string[] + then: + - logger.log: + # yamllint disable rule:line-length + format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" + # yamllint enable rule:line-length + args: + - YESNO(bool_arr[0]) + - bool_arr.size() + - int_arr[0] + - int_arr.size() + - float_arr[0] + - float_arr.size() + - string_arr[0].c_str() + - string_arr.size() diff --git a/tests/components/api/test.esp32-c3-idf.yaml b/tests/components/api/test.esp32-c3-idf.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.esp32-c3-idf.yaml +++ b/tests/components/api/test.esp32-c3-idf.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/api/test.esp32-c3.yaml b/tests/components/api/test.esp32-c3.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.esp32-c3.yaml +++ b/tests/components/api/test.esp32-c3.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/api/test.esp32-idf.yaml b/tests/components/api/test.esp32-idf.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.esp32-idf.yaml +++ b/tests/components/api/test.esp32-idf.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/api/test.esp32.yaml b/tests/components/api/test.esp32.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.esp32.yaml +++ b/tests/components/api/test.esp32.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/api/test.esp8266.yaml b/tests/components/api/test.esp8266.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.esp8266.yaml +++ b/tests/components/api/test.esp8266.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/api/test.rp2040.yaml b/tests/components/api/test.rp2040.yaml index 3c56811b95..dade44d145 100644 --- a/tests/components/api/test.rp2040.yaml +++ b/tests/components/api/test.rp2040.yaml @@ -1,63 +1 @@ -esphome: - on_boot: - then: - - homeassistant.event: - event: esphome.button_pressed - data: - message: Button was pressed - - homeassistant.service: - service: notify.html5 - data: - message: Button was pressed - - homeassistant.tag_scanned: pulse - -wifi: - ssid: MySSID - password: password1 - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() +<<: !include common.yaml diff --git a/tests/components/atc_mithermometer/common.yaml b/tests/components/atc_mithermometer/common.yaml new file mode 100644 index 0000000000..0248090c23 --- /dev/null +++ b/tests/components/atc_mithermometer/common.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: atc_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: ATC Temperature + humidity: + name: ATC Humidity + battery_level: + name: ATC Battery-Level + battery_voltage: + name: ATC Battery-Voltage diff --git a/tests/components/atc_mithermometer/test.esp32-c3-idf.yaml b/tests/components/atc_mithermometer/test.esp32-c3-idf.yaml index 0248090c23..dade44d145 100644 --- a/tests/components/atc_mithermometer/test.esp32-c3-idf.yaml +++ b/tests/components/atc_mithermometer/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: atc_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: ATC Temperature - humidity: - name: ATC Humidity - battery_level: - name: ATC Battery-Level - battery_voltage: - name: ATC Battery-Voltage +<<: !include common.yaml diff --git a/tests/components/atc_mithermometer/test.esp32-c3.yaml b/tests/components/atc_mithermometer/test.esp32-c3.yaml index 0248090c23..dade44d145 100644 --- a/tests/components/atc_mithermometer/test.esp32-c3.yaml +++ b/tests/components/atc_mithermometer/test.esp32-c3.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: atc_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: ATC Temperature - humidity: - name: ATC Humidity - battery_level: - name: ATC Battery-Level - battery_voltage: - name: ATC Battery-Voltage +<<: !include common.yaml diff --git a/tests/components/atc_mithermometer/test.esp32-idf.yaml b/tests/components/atc_mithermometer/test.esp32-idf.yaml index 0248090c23..dade44d145 100644 --- a/tests/components/atc_mithermometer/test.esp32-idf.yaml +++ b/tests/components/atc_mithermometer/test.esp32-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: atc_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: ATC Temperature - humidity: - name: ATC Humidity - battery_level: - name: ATC Battery-Level - battery_voltage: - name: ATC Battery-Voltage +<<: !include common.yaml diff --git a/tests/components/atc_mithermometer/test.esp32.yaml b/tests/components/atc_mithermometer/test.esp32.yaml index 0248090c23..dade44d145 100644 --- a/tests/components/atc_mithermometer/test.esp32.yaml +++ b/tests/components/atc_mithermometer/test.esp32.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: atc_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: ATC Temperature - humidity: - name: ATC Humidity - battery_level: - name: ATC Battery-Level - battery_voltage: - name: ATC Battery-Voltage +<<: !include common.yaml diff --git a/tests/components/b_parasite/common.yaml b/tests/components/b_parasite/common.yaml new file mode 100644 index 0000000000..262e891bb2 --- /dev/null +++ b/tests/components/b_parasite/common.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: b_parasite + mac_address: F0:CA:F0:CA:01:01 + humidity: + name: b-parasite Air Humidity + temperature: + name: b-parasite Air Temperature + moisture: + name: b-parasite Soil Moisture + battery_voltage: + name: b-parasite Battery Voltage + illuminance: + name: b-parasite Illuminance diff --git a/tests/components/b_parasite/test.esp32-c3-idf.yaml b/tests/components/b_parasite/test.esp32-c3-idf.yaml index 262e891bb2..dade44d145 100644 --- a/tests/components/b_parasite/test.esp32-c3-idf.yaml +++ b/tests/components/b_parasite/test.esp32-c3-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: b_parasite - mac_address: F0:CA:F0:CA:01:01 - humidity: - name: b-parasite Air Humidity - temperature: - name: b-parasite Air Temperature - moisture: - name: b-parasite Soil Moisture - battery_voltage: - name: b-parasite Battery Voltage - illuminance: - name: b-parasite Illuminance +<<: !include common.yaml diff --git a/tests/components/b_parasite/test.esp32-c3.yaml b/tests/components/b_parasite/test.esp32-c3.yaml index 262e891bb2..dade44d145 100644 --- a/tests/components/b_parasite/test.esp32-c3.yaml +++ b/tests/components/b_parasite/test.esp32-c3.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: b_parasite - mac_address: F0:CA:F0:CA:01:01 - humidity: - name: b-parasite Air Humidity - temperature: - name: b-parasite Air Temperature - moisture: - name: b-parasite Soil Moisture - battery_voltage: - name: b-parasite Battery Voltage - illuminance: - name: b-parasite Illuminance +<<: !include common.yaml diff --git a/tests/components/b_parasite/test.esp32-idf.yaml b/tests/components/b_parasite/test.esp32-idf.yaml index 262e891bb2..dade44d145 100644 --- a/tests/components/b_parasite/test.esp32-idf.yaml +++ b/tests/components/b_parasite/test.esp32-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: b_parasite - mac_address: F0:CA:F0:CA:01:01 - humidity: - name: b-parasite Air Humidity - temperature: - name: b-parasite Air Temperature - moisture: - name: b-parasite Soil Moisture - battery_voltage: - name: b-parasite Battery Voltage - illuminance: - name: b-parasite Illuminance +<<: !include common.yaml diff --git a/tests/components/b_parasite/test.esp32.yaml b/tests/components/b_parasite/test.esp32.yaml index 262e891bb2..dade44d145 100644 --- a/tests/components/b_parasite/test.esp32.yaml +++ b/tests/components/b_parasite/test.esp32.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: b_parasite - mac_address: F0:CA:F0:CA:01:01 - humidity: - name: b-parasite Air Humidity - temperature: - name: b-parasite Air Temperature - moisture: - name: b-parasite Soil Moisture - battery_voltage: - name: b-parasite Battery Voltage - illuminance: - name: b-parasite Illuminance +<<: !include common.yaml diff --git a/tests/components/bang_bang/common.yaml b/tests/components/bang_bang/common.yaml new file mode 100644 index 0000000000..5882025191 --- /dev/null +++ b/tests/components/bang_bang/common.yaml @@ -0,0 +1,35 @@ +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: bang_bang + name: Bang Bang Climate + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + idle_action: + - switch.turn_on: template_switch1 + cool_action: + - switch.turn_on: template_switch2 + heat_action: + - switch.turn_on: template_switch1 + away_config: + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C diff --git a/tests/components/bang_bang/test.esp32-c3-idf.yaml b/tests/components/bang_bang/test.esp32-c3-idf.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.esp32-c3-idf.yaml +++ b/tests/components/bang_bang/test.esp32-c3-idf.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bang_bang/test.esp32-c3.yaml b/tests/components/bang_bang/test.esp32-c3.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.esp32-c3.yaml +++ b/tests/components/bang_bang/test.esp32-c3.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bang_bang/test.esp32-idf.yaml b/tests/components/bang_bang/test.esp32-idf.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.esp32-idf.yaml +++ b/tests/components/bang_bang/test.esp32-idf.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bang_bang/test.esp32.yaml b/tests/components/bang_bang/test.esp32.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.esp32.yaml +++ b/tests/components/bang_bang/test.esp32.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bang_bang/test.esp8266.yaml b/tests/components/bang_bang/test.esp8266.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.esp8266.yaml +++ b/tests/components/bang_bang/test.esp8266.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bang_bang/test.rp2040.yaml b/tests/components/bang_bang/test.rp2040.yaml index 5882025191..dade44d145 100644 --- a/tests/components/bang_bang/test.rp2040.yaml +++ b/tests/components/bang_bang/test.rp2040.yaml @@ -1,35 +1 @@ -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: template_switch1 - cool_action: - - switch.turn_on: template_switch2 - heat_action: - - switch.turn_on: template_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C +<<: !include common.yaml diff --git a/tests/components/bedjet/common.yaml b/tests/components/bedjet/common.yaml new file mode 100644 index 0000000000..c2be04a49a --- /dev/null +++ b/tests/components/bedjet/common.yaml @@ -0,0 +1,33 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: bedjet_blec + +bedjet: + - id: bedjet_hub + ble_client_id: bedjet_blec + time_id: sntp_time + +climate: + - platform: bedjet + name: My Bedjet + bedjet_id: bedjet_hub + heat_mode: extended + +fan: + - platform: bedjet + name: My Bedjet fan + bedjet_id: bedjet_hub diff --git a/tests/components/bedjet/test.esp32-c3-idf.yaml b/tests/components/bedjet/test.esp32-c3-idf.yaml index c2be04a49a..dade44d145 100644 --- a/tests/components/bedjet/test.esp32-c3-idf.yaml +++ b/tests/components/bedjet/test.esp32-c3-idf.yaml @@ -1,33 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: bedjet_blec - -bedjet: - - id: bedjet_hub - ble_client_id: bedjet_blec - time_id: sntp_time - -climate: - - platform: bedjet - name: My Bedjet - bedjet_id: bedjet_hub - heat_mode: extended - -fan: - - platform: bedjet - name: My Bedjet fan - bedjet_id: bedjet_hub +<<: !include common.yaml diff --git a/tests/components/bedjet/test.esp32-c3.yaml b/tests/components/bedjet/test.esp32-c3.yaml index c2be04a49a..dade44d145 100644 --- a/tests/components/bedjet/test.esp32-c3.yaml +++ b/tests/components/bedjet/test.esp32-c3.yaml @@ -1,33 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: bedjet_blec - -bedjet: - - id: bedjet_hub - ble_client_id: bedjet_blec - time_id: sntp_time - -climate: - - platform: bedjet - name: My Bedjet - bedjet_id: bedjet_hub - heat_mode: extended - -fan: - - platform: bedjet - name: My Bedjet fan - bedjet_id: bedjet_hub +<<: !include common.yaml diff --git a/tests/components/bedjet/test.esp32-idf.yaml b/tests/components/bedjet/test.esp32-idf.yaml index c2be04a49a..dade44d145 100644 --- a/tests/components/bedjet/test.esp32-idf.yaml +++ b/tests/components/bedjet/test.esp32-idf.yaml @@ -1,33 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: bedjet_blec - -bedjet: - - id: bedjet_hub - ble_client_id: bedjet_blec - time_id: sntp_time - -climate: - - platform: bedjet - name: My Bedjet - bedjet_id: bedjet_hub - heat_mode: extended - -fan: - - platform: bedjet - name: My Bedjet fan - bedjet_id: bedjet_hub +<<: !include common.yaml diff --git a/tests/components/bedjet/test.esp32.yaml b/tests/components/bedjet/test.esp32.yaml index c2be04a49a..dade44d145 100644 --- a/tests/components/bedjet/test.esp32.yaml +++ b/tests/components/bedjet/test.esp32.yaml @@ -1,33 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: bedjet_blec - -bedjet: - - id: bedjet_hub - ble_client_id: bedjet_blec - time_id: sntp_time - -climate: - - platform: bedjet - name: My Bedjet - bedjet_id: bedjet_hub - heat_mode: extended - -fan: - - platform: bedjet - name: My Bedjet fan - bedjet_id: bedjet_hub +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/common.yaml b/tests/components/binary_sensor_map/common.yaml new file mode 100644 index 0000000000..8ffdd1f379 --- /dev/null +++ b/tests/components/binary_sensor_map/common.yaml @@ -0,0 +1,61 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + - platform: template + id: bin2 + lambda: |- + if (millis() > 20000) { + return true; + } else { + return false; + } + - platform: template + id: bin3 + lambda: |- + if (millis() > 30000) { + return true; + } else { + return false; + } + +sensor: + - platform: binary_sensor_map + name: Binary Sensor Map + type: group + channels: + - binary_sensor: bin1 + value: 10.0 + - binary_sensor: bin2 + value: 15.0 + - binary_sensor: bin3 + value: 100.0 + - platform: binary_sensor_map + name: Binary Sensor Map + type: sum + channels: + - binary_sensor: bin1 + value: 10.0 + - binary_sensor: bin2 + value: 15.0 + - binary_sensor: bin3 + value: 100.0 + - platform: binary_sensor_map + name: Binary Sensor Map + type: bayesian + prior: 0.4 + observations: + - binary_sensor: bin1 + prob_given_true: 0.9 + prob_given_false: 0.4 + - binary_sensor: bin2 + prob_given_true: 0.7 + prob_given_false: 0.05 + - binary_sensor: bin3 + prob_given_true: 0.8 + prob_given_false: 0.2 diff --git a/tests/components/binary_sensor_map/test.esp32-c3-idf.yaml b/tests/components/binary_sensor_map/test.esp32-c3-idf.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.esp32-c3-idf.yaml +++ b/tests/components/binary_sensor_map/test.esp32-c3-idf.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/test.esp32-c3.yaml b/tests/components/binary_sensor_map/test.esp32-c3.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.esp32-c3.yaml +++ b/tests/components/binary_sensor_map/test.esp32-c3.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/test.esp32-idf.yaml b/tests/components/binary_sensor_map/test.esp32-idf.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.esp32-idf.yaml +++ b/tests/components/binary_sensor_map/test.esp32-idf.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/test.esp32.yaml b/tests/components/binary_sensor_map/test.esp32.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.esp32.yaml +++ b/tests/components/binary_sensor_map/test.esp32.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/test.esp8266.yaml b/tests/components/binary_sensor_map/test.esp8266.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.esp8266.yaml +++ b/tests/components/binary_sensor_map/test.esp8266.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/binary_sensor_map/test.rp2040.yaml b/tests/components/binary_sensor_map/test.rp2040.yaml index 8ffdd1f379..dade44d145 100644 --- a/tests/components/binary_sensor_map/test.rp2040.yaml +++ b/tests/components/binary_sensor_map/test.rp2040.yaml @@ -1,61 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - - platform: template - id: bin2 - lambda: |- - if (millis() > 20000) { - return true; - } else { - return false; - } - - platform: template - id: bin3 - lambda: |- - if (millis() > 30000) { - return true; - } else { - return false; - } - -sensor: - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 +<<: !include common.yaml diff --git a/tests/components/ble_client/common.yaml b/tests/components/ble_client/common.yaml new file mode 100644 index 0000000000..b5272d01f0 --- /dev/null +++ b/tests/components/ble_client/common.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: test_blec diff --git a/tests/components/ble_client/test.esp32-c3-idf.yaml b/tests/components/ble_client/test.esp32-c3-idf.yaml index b5272d01f0..dade44d145 100644 --- a/tests/components/ble_client/test.esp32-c3-idf.yaml +++ b/tests/components/ble_client/test.esp32-c3-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: test_blec +<<: !include common.yaml diff --git a/tests/components/ble_client/test.esp32-c3.yaml b/tests/components/ble_client/test.esp32-c3.yaml index b5272d01f0..dade44d145 100644 --- a/tests/components/ble_client/test.esp32-c3.yaml +++ b/tests/components/ble_client/test.esp32-c3.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: test_blec +<<: !include common.yaml diff --git a/tests/components/ble_client/test.esp32-idf.yaml b/tests/components/ble_client/test.esp32-idf.yaml index b5272d01f0..dade44d145 100644 --- a/tests/components/ble_client/test.esp32-idf.yaml +++ b/tests/components/ble_client/test.esp32-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: test_blec +<<: !include common.yaml diff --git a/tests/components/ble_client/test.esp32.yaml b/tests/components/ble_client/test.esp32.yaml index b5272d01f0..dade44d145 100644 --- a/tests/components/ble_client/test.esp32.yaml +++ b/tests/components/ble_client/test.esp32.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: test_blec +<<: !include common.yaml diff --git a/tests/components/ble_presence/common.yaml b/tests/components/ble_presence/common.yaml new file mode 100644 index 0000000000..6e5173eed8 --- /dev/null +++ b/tests/components/ble_presence/common.yaml @@ -0,0 +1,24 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: ble_presence + mac_address: AC:37:43:77:5F:4C + name: ESP32 BLE Tracker Google Home Mini + - platform: ble_presence + service_uuid: 11aa + name: BLE Test Service 16 Presence + - platform: ble_presence + service_uuid: "11223344" + name: BLE Test Service 32 Presence + - platform: ble_presence + service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 + name: BLE Test Service 128 Presence + - platform: ble_presence + ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 + ibeacon_major: 100 + ibeacon_minor: 1 + name: BLE Test iBeacon Presence + - platform: ble_presence + irk: 1234567890abcdef1234567890abcdef + name: "ESP32 BLE Tracker with Identity Resolving Key" + diff --git a/tests/components/ble_presence/test.esp32-c3-idf.yaml b/tests/components/ble_presence/test.esp32-c3-idf.yaml index 6e5173eed8..dade44d145 100644 --- a/tests/components/ble_presence/test.esp32-c3-idf.yaml +++ b/tests/components/ble_presence/test.esp32-c3-idf.yaml @@ -1,24 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: ble_presence - mac_address: AC:37:43:77:5F:4C - name: ESP32 BLE Tracker Google Home Mini - - platform: ble_presence - service_uuid: 11aa - name: BLE Test Service 16 Presence - - platform: ble_presence - service_uuid: "11223344" - name: BLE Test Service 32 Presence - - platform: ble_presence - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 Presence - - platform: ble_presence - ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - ibeacon_major: 100 - ibeacon_minor: 1 - name: BLE Test iBeacon Presence - - platform: ble_presence - irk: 1234567890abcdef1234567890abcdef - name: "ESP32 BLE Tracker with Identity Resolving Key" - +<<: !include common.yaml diff --git a/tests/components/ble_presence/test.esp32-c3.yaml b/tests/components/ble_presence/test.esp32-c3.yaml index 6e5173eed8..dade44d145 100644 --- a/tests/components/ble_presence/test.esp32-c3.yaml +++ b/tests/components/ble_presence/test.esp32-c3.yaml @@ -1,24 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: ble_presence - mac_address: AC:37:43:77:5F:4C - name: ESP32 BLE Tracker Google Home Mini - - platform: ble_presence - service_uuid: 11aa - name: BLE Test Service 16 Presence - - platform: ble_presence - service_uuid: "11223344" - name: BLE Test Service 32 Presence - - platform: ble_presence - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 Presence - - platform: ble_presence - ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - ibeacon_major: 100 - ibeacon_minor: 1 - name: BLE Test iBeacon Presence - - platform: ble_presence - irk: 1234567890abcdef1234567890abcdef - name: "ESP32 BLE Tracker with Identity Resolving Key" - +<<: !include common.yaml diff --git a/tests/components/ble_presence/test.esp32-idf.yaml b/tests/components/ble_presence/test.esp32-idf.yaml index 6e5173eed8..dade44d145 100644 --- a/tests/components/ble_presence/test.esp32-idf.yaml +++ b/tests/components/ble_presence/test.esp32-idf.yaml @@ -1,24 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: ble_presence - mac_address: AC:37:43:77:5F:4C - name: ESP32 BLE Tracker Google Home Mini - - platform: ble_presence - service_uuid: 11aa - name: BLE Test Service 16 Presence - - platform: ble_presence - service_uuid: "11223344" - name: BLE Test Service 32 Presence - - platform: ble_presence - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 Presence - - platform: ble_presence - ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - ibeacon_major: 100 - ibeacon_minor: 1 - name: BLE Test iBeacon Presence - - platform: ble_presence - irk: 1234567890abcdef1234567890abcdef - name: "ESP32 BLE Tracker with Identity Resolving Key" - +<<: !include common.yaml diff --git a/tests/components/ble_presence/test.esp32.yaml b/tests/components/ble_presence/test.esp32.yaml index 6e5173eed8..dade44d145 100644 --- a/tests/components/ble_presence/test.esp32.yaml +++ b/tests/components/ble_presence/test.esp32.yaml @@ -1,24 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: ble_presence - mac_address: AC:37:43:77:5F:4C - name: ESP32 BLE Tracker Google Home Mini - - platform: ble_presence - service_uuid: 11aa - name: BLE Test Service 16 Presence - - platform: ble_presence - service_uuid: "11223344" - name: BLE Test Service 32 Presence - - platform: ble_presence - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 Presence - - platform: ble_presence - ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - ibeacon_major: 100 - ibeacon_minor: 1 - name: BLE Test iBeacon Presence - - platform: ble_presence - irk: 1234567890abcdef1234567890abcdef - name: "ESP32 BLE Tracker with Identity Resolving Key" - +<<: !include common.yaml diff --git a/tests/components/ble_rssi/common.yaml b/tests/components/ble_rssi/common.yaml new file mode 100644 index 0000000000..52e5b865c6 --- /dev/null +++ b/tests/components/ble_rssi/common.yaml @@ -0,0 +1,18 @@ +esp32_ble_tracker: + +sensor: + - platform: ble_rssi + mac_address: AC:37:43:77:5F:4C + name: BLE Google Home Mini RSSI value + - platform: ble_rssi + service_uuid: 11aa + name: BLE Test Service 16 + - platform: ble_rssi + service_uuid: "11223344" + name: BLE Test Service 32 + - platform: ble_rssi + service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 + name: BLE Test Service 128 + - platform: ble_rssi + service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 + name: BLE Test iBeacon UUID diff --git a/tests/components/ble_rssi/test.esp32-c3-idf.yaml b/tests/components/ble_rssi/test.esp32-c3-idf.yaml index 52e5b865c6..dade44d145 100644 --- a/tests/components/ble_rssi/test.esp32-c3-idf.yaml +++ b/tests/components/ble_rssi/test.esp32-c3-idf.yaml @@ -1,18 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ble_rssi - mac_address: AC:37:43:77:5F:4C - name: BLE Google Home Mini RSSI value - - platform: ble_rssi - service_uuid: 11aa - name: BLE Test Service 16 - - platform: ble_rssi - service_uuid: "11223344" - name: BLE Test Service 32 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test iBeacon UUID +<<: !include common.yaml diff --git a/tests/components/ble_rssi/test.esp32-c3.yaml b/tests/components/ble_rssi/test.esp32-c3.yaml index 52e5b865c6..dade44d145 100644 --- a/tests/components/ble_rssi/test.esp32-c3.yaml +++ b/tests/components/ble_rssi/test.esp32-c3.yaml @@ -1,18 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ble_rssi - mac_address: AC:37:43:77:5F:4C - name: BLE Google Home Mini RSSI value - - platform: ble_rssi - service_uuid: 11aa - name: BLE Test Service 16 - - platform: ble_rssi - service_uuid: "11223344" - name: BLE Test Service 32 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test iBeacon UUID +<<: !include common.yaml diff --git a/tests/components/ble_rssi/test.esp32-idf.yaml b/tests/components/ble_rssi/test.esp32-idf.yaml index 52e5b865c6..dade44d145 100644 --- a/tests/components/ble_rssi/test.esp32-idf.yaml +++ b/tests/components/ble_rssi/test.esp32-idf.yaml @@ -1,18 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ble_rssi - mac_address: AC:37:43:77:5F:4C - name: BLE Google Home Mini RSSI value - - platform: ble_rssi - service_uuid: 11aa - name: BLE Test Service 16 - - platform: ble_rssi - service_uuid: "11223344" - name: BLE Test Service 32 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test iBeacon UUID +<<: !include common.yaml diff --git a/tests/components/ble_rssi/test.esp32.yaml b/tests/components/ble_rssi/test.esp32.yaml index 52e5b865c6..dade44d145 100644 --- a/tests/components/ble_rssi/test.esp32.yaml +++ b/tests/components/ble_rssi/test.esp32.yaml @@ -1,18 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ble_rssi - mac_address: AC:37:43:77:5F:4C - name: BLE Google Home Mini RSSI value - - platform: ble_rssi - service_uuid: 11aa - name: BLE Test Service 16 - - platform: ble_rssi - service_uuid: "11223344" - name: BLE Test Service 32 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test iBeacon UUID +<<: !include common.yaml diff --git a/tests/components/ble_scanner/common.yaml b/tests/components/ble_scanner/common.yaml new file mode 100644 index 0000000000..935a5a5a19 --- /dev/null +++ b/tests/components/ble_scanner/common.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +text_sensor: + - platform: ble_scanner + name: Scanner diff --git a/tests/components/ble_scanner/test.esp32-c3-idf.yaml b/tests/components/ble_scanner/test.esp32-c3-idf.yaml index 935a5a5a19..dade44d145 100644 --- a/tests/components/ble_scanner/test.esp32-c3-idf.yaml +++ b/tests/components/ble_scanner/test.esp32-c3-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -text_sensor: - - platform: ble_scanner - name: Scanner +<<: !include common.yaml diff --git a/tests/components/ble_scanner/test.esp32-c3.yaml b/tests/components/ble_scanner/test.esp32-c3.yaml index 935a5a5a19..dade44d145 100644 --- a/tests/components/ble_scanner/test.esp32-c3.yaml +++ b/tests/components/ble_scanner/test.esp32-c3.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -text_sensor: - - platform: ble_scanner - name: Scanner +<<: !include common.yaml diff --git a/tests/components/ble_scanner/test.esp32-idf.yaml b/tests/components/ble_scanner/test.esp32-idf.yaml index 935a5a5a19..dade44d145 100644 --- a/tests/components/ble_scanner/test.esp32-idf.yaml +++ b/tests/components/ble_scanner/test.esp32-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -text_sensor: - - platform: ble_scanner - name: Scanner +<<: !include common.yaml diff --git a/tests/components/ble_scanner/test.esp32.yaml b/tests/components/ble_scanner/test.esp32.yaml index 935a5a5a19..dade44d145 100644 --- a/tests/components/ble_scanner/test.esp32.yaml +++ b/tests/components/ble_scanner/test.esp32.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -text_sensor: - - platform: ble_scanner - name: Scanner +<<: !include common.yaml diff --git a/tests/components/button/common.yaml b/tests/components/button/common.yaml new file mode 100644 index 0000000000..d5978601f4 --- /dev/null +++ b/tests/components/button/common.yaml @@ -0,0 +1,6 @@ +button: + - platform: template + name: Button + id: some_button + on_press: + - logger.log: Button pressed diff --git a/tests/components/button/test.esp32-c3-idf.yaml b/tests/components/button/test.esp32-c3-idf.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.esp32-c3-idf.yaml +++ b/tests/components/button/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/button/test.esp32-c3.yaml b/tests/components/button/test.esp32-c3.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.esp32-c3.yaml +++ b/tests/components/button/test.esp32-c3.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/button/test.esp32-idf.yaml b/tests/components/button/test.esp32-idf.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.esp32-idf.yaml +++ b/tests/components/button/test.esp32-idf.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/button/test.esp32.yaml b/tests/components/button/test.esp32.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.esp32.yaml +++ b/tests/components/button/test.esp32.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/button/test.esp8266.yaml b/tests/components/button/test.esp8266.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.esp8266.yaml +++ b/tests/components/button/test.esp8266.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/button/test.rp2040.yaml b/tests/components/button/test.rp2040.yaml index d5978601f4..dade44d145 100644 --- a/tests/components/button/test.rp2040.yaml +++ b/tests/components/button/test.rp2040.yaml @@ -1,6 +1 @@ -button: - - platform: template - name: Button - id: some_button - on_press: - - logger.log: Button pressed +<<: !include common.yaml diff --git a/tests/components/canbus/common.yaml b/tests/components/canbus/common.yaml new file mode 100644 index 0000000000..fd146cc3a3 --- /dev/null +++ b/tests/components/canbus/common.yaml @@ -0,0 +1,46 @@ +canbus: + - platform: esp32_can + id: esp32_internal_can + rx_pin: 4 + tx_pin: 5 + can_id: 4 + bit_rate: 50kbps + on_frame: + - can_id: 500 + then: + - lambda: |- + std::string b(x.begin(), x.end()); + ESP_LOGD("canid 500", "%s", b.c_str()); + - can_id: 23 + then: + - if: + condition: + lambda: "return x[0] == 0x11;" + then: + logger.log: Truth + - can_id: 0b00000000000000000000001000000 + can_id_mask: 0b11111000000000011111111000000 + use_extended_id: true + then: + - lambda: |- + auto pdo_id = can_id >> 14; + switch (pdo_id) + { + case 117: + ESP_LOGD("canbus", "exhaust_fan_duty"); + break; + case 118: + ESP_LOGD("canbus", "supply_fan_duty"); + break; + case 119: + ESP_LOGD("canbus", "supply_fan_flow"); + break; + } + +button: + - platform: template + name: Canbus Actions + on_press: + - canbus.send: "abc" + - canbus.send: [0, 1, 2] + - canbus.send: !lambda return {0, 1, 2}; diff --git a/tests/components/canbus/test.esp32-c3-idf.yaml b/tests/components/canbus/test.esp32-c3-idf.yaml index fd146cc3a3..dade44d145 100644 --- a/tests/components/canbus/test.esp32-c3-idf.yaml +++ b/tests/components/canbus/test.esp32-c3-idf.yaml @@ -1,46 +1 @@ -canbus: - - platform: esp32_can - id: esp32_internal_can - rx_pin: 4 - tx_pin: 5 - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str()); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - logger.log: Truth - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - } - -button: - - platform: template - name: Canbus Actions - on_press: - - canbus.send: "abc" - - canbus.send: [0, 1, 2] - - canbus.send: !lambda return {0, 1, 2}; +<<: !include common.yaml diff --git a/tests/components/canbus/test.esp32-c3.yaml b/tests/components/canbus/test.esp32-c3.yaml index fd146cc3a3..dade44d145 100644 --- a/tests/components/canbus/test.esp32-c3.yaml +++ b/tests/components/canbus/test.esp32-c3.yaml @@ -1,46 +1 @@ -canbus: - - platform: esp32_can - id: esp32_internal_can - rx_pin: 4 - tx_pin: 5 - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str()); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - logger.log: Truth - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - } - -button: - - platform: template - name: Canbus Actions - on_press: - - canbus.send: "abc" - - canbus.send: [0, 1, 2] - - canbus.send: !lambda return {0, 1, 2}; +<<: !include common.yaml diff --git a/tests/components/canbus/test.esp32-idf.yaml b/tests/components/canbus/test.esp32-idf.yaml index fd146cc3a3..dade44d145 100644 --- a/tests/components/canbus/test.esp32-idf.yaml +++ b/tests/components/canbus/test.esp32-idf.yaml @@ -1,46 +1 @@ -canbus: - - platform: esp32_can - id: esp32_internal_can - rx_pin: 4 - tx_pin: 5 - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str()); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - logger.log: Truth - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - } - -button: - - platform: template - name: Canbus Actions - on_press: - - canbus.send: "abc" - - canbus.send: [0, 1, 2] - - canbus.send: !lambda return {0, 1, 2}; +<<: !include common.yaml diff --git a/tests/components/canbus/test.esp32.yaml b/tests/components/canbus/test.esp32.yaml index fd146cc3a3..dade44d145 100644 --- a/tests/components/canbus/test.esp32.yaml +++ b/tests/components/canbus/test.esp32.yaml @@ -1,46 +1 @@ -canbus: - - platform: esp32_can - id: esp32_internal_can - rx_pin: 4 - tx_pin: 5 - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str()); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - logger.log: Truth - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - } - -button: - - platform: template - name: Canbus Actions - on_press: - - canbus.send: "abc" - - canbus.send: [0, 1, 2] - - canbus.send: !lambda return {0, 1, 2}; +<<: !include common.yaml diff --git a/tests/components/captive_portal/common.yaml b/tests/components/captive_portal/common.yaml new file mode 100644 index 0000000000..25bc4a887a --- /dev/null +++ b/tests/components/captive_portal/common.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +captive_portal: diff --git a/tests/components/captive_portal/test.esp32-c3-idf.yaml b/tests/components/captive_portal/test.esp32-c3-idf.yaml index 25bc4a887a..dade44d145 100644 --- a/tests/components/captive_portal/test.esp32-c3-idf.yaml +++ b/tests/components/captive_portal/test.esp32-c3-idf.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -captive_portal: +<<: !include common.yaml diff --git a/tests/components/captive_portal/test.esp32-c3.yaml b/tests/components/captive_portal/test.esp32-c3.yaml index 25bc4a887a..dade44d145 100644 --- a/tests/components/captive_portal/test.esp32-c3.yaml +++ b/tests/components/captive_portal/test.esp32-c3.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -captive_portal: +<<: !include common.yaml diff --git a/tests/components/captive_portal/test.esp32-idf.yaml b/tests/components/captive_portal/test.esp32-idf.yaml index 25bc4a887a..dade44d145 100644 --- a/tests/components/captive_portal/test.esp32-idf.yaml +++ b/tests/components/captive_portal/test.esp32-idf.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -captive_portal: +<<: !include common.yaml diff --git a/tests/components/captive_portal/test.esp32.yaml b/tests/components/captive_portal/test.esp32.yaml index 25bc4a887a..dade44d145 100644 --- a/tests/components/captive_portal/test.esp32.yaml +++ b/tests/components/captive_portal/test.esp32.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -captive_portal: +<<: !include common.yaml diff --git a/tests/components/captive_portal/test.esp8266.yaml b/tests/components/captive_portal/test.esp8266.yaml index 25bc4a887a..dade44d145 100644 --- a/tests/components/captive_portal/test.esp8266.yaml +++ b/tests/components/captive_portal/test.esp8266.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -captive_portal: +<<: !include common.yaml diff --git a/tests/components/color/common.yaml b/tests/components/color/common.yaml new file mode 100644 index 0000000000..7aa308bb63 --- /dev/null +++ b/tests/components/color/common.yaml @@ -0,0 +1,11 @@ +color: + - id: kbx_red + red: 100% + green_int: 123 + blue: 2% + - id: kbx_blue + red: 0% + green: 1% + blue: 100% + - id: kbx_green + hex: "3DEC55" diff --git a/tests/components/color/test.esp32-c3-idf.yaml b/tests/components/color/test.esp32-c3-idf.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.esp32-c3-idf.yaml +++ b/tests/components/color/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/color/test.esp32-c3.yaml b/tests/components/color/test.esp32-c3.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.esp32-c3.yaml +++ b/tests/components/color/test.esp32-c3.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/color/test.esp32-idf.yaml b/tests/components/color/test.esp32-idf.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.esp32-idf.yaml +++ b/tests/components/color/test.esp32-idf.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/color/test.esp32.yaml b/tests/components/color/test.esp32.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.esp32.yaml +++ b/tests/components/color/test.esp32.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/color/test.esp8266.yaml b/tests/components/color/test.esp8266.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.esp8266.yaml +++ b/tests/components/color/test.esp8266.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/color/test.rp2040.yaml b/tests/components/color/test.rp2040.yaml index 7aa308bb63..dade44d145 100644 --- a/tests/components/color/test.rp2040.yaml +++ b/tests/components/color/test.rp2040.yaml @@ -1,11 +1 @@ -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" +<<: !include common.yaml diff --git a/tests/components/combination/common.yaml b/tests/components/combination/common.yaml new file mode 100644 index 0000000000..62246190af --- /dev/null +++ b/tests/components/combination/common.yaml @@ -0,0 +1,76 @@ +sensor: + - platform: template + id: template_temperature1 + lambda: |- + if (millis() > 10000) { + return 0.6; + } else { + return 0.0; + } + - platform: template + id: template_temperature2 + lambda: |- + if (millis() > 20000) { + return 0.8; + } else { + return 0.0; + } + - platform: combination + type: kalman + name: Kalman-filtered temperature + process_std_dev: 0.00139 + sources: + - source: template_temperature1 + error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" + - source: template_temperature2 + error: 1.5 + - platform: combination + type: linear + name: Linearly combined temperatures + sources: + - source: template_temperature1 + coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" + - source: template_temperature2 + coeffecient: 1.5 + - platform: combination + type: max + name: Max of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: mean + name: Mean of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: median + name: Median of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: min + name: Min of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: most_recently_updated + name: Most recently updated of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: range + name: Range of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 + - platform: combination + type: sum + name: Sum of combined temperatures + sources: + - source: template_temperature1 + - source: template_temperature2 diff --git a/tests/components/combination/test.esp32-c3-idf.yaml b/tests/components/combination/test.esp32-c3-idf.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.esp32-c3-idf.yaml +++ b/tests/components/combination/test.esp32-c3-idf.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/combination/test.esp32-c3.yaml b/tests/components/combination/test.esp32-c3.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.esp32-c3.yaml +++ b/tests/components/combination/test.esp32-c3.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/combination/test.esp32-idf.yaml b/tests/components/combination/test.esp32-idf.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.esp32-idf.yaml +++ b/tests/components/combination/test.esp32-idf.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/combination/test.esp32.yaml b/tests/components/combination/test.esp32.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.esp32.yaml +++ b/tests/components/combination/test.esp32.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/combination/test.esp8266.yaml b/tests/components/combination/test.esp8266.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.esp8266.yaml +++ b/tests/components/combination/test.esp8266.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/combination/test.rp2040.yaml b/tests/components/combination/test.rp2040.yaml index 62246190af..dade44d145 100644 --- a/tests/components/combination/test.rp2040.yaml +++ b/tests/components/combination/test.rp2040.yaml @@ -1,76 +1 @@ -sensor: - - platform: template - id: template_temperature1 - lambda: |- - if (millis() > 10000) { - return 0.6; - } else { - return 0.0; - } - - platform: template - id: template_temperature2 - lambda: |- - if (millis() > 20000) { - return 0.8; - } else { - return 0.0; - } - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: template_temperature1 - error: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: template_temperature1 - coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;" - - source: template_temperature2 - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: template_temperature1 - - source: template_temperature2 +<<: !include common.yaml diff --git a/tests/components/cst226/common.yaml b/tests/components/cst226/common.yaml new file mode 100644 index 0000000000..4cbf38ef50 --- /dev/null +++ b/tests/components/cst226/common.yaml @@ -0,0 +1,24 @@ +spi: + - id: spi_id_1 + clk_pin: GPIO7 + mosi_pin: GPIO6 + interface: any + +display: + - platform: ili9xxx + id: displ8 + model: ili9342 + cs_pin: GPIO5 + dc_pin: GPIO4 + reset_pin: + number: GPIO21 + +i2c: + scl: GPIO18 + sda: GPIO8 + +touchscreen: + - platform: cst226 + interrupt_pin: GPIO3 + reset_pin: GPIO20 + diff --git a/tests/components/cst226/test.esp32-c3.yaml b/tests/components/cst226/test.esp32-c3.yaml index 4cbf38ef50..dade44d145 100644 --- a/tests/components/cst226/test.esp32-c3.yaml +++ b/tests/components/cst226/test.esp32-c3.yaml @@ -1,24 +1 @@ -spi: - - id: spi_id_1 - clk_pin: GPIO7 - mosi_pin: GPIO6 - interface: any - -display: - - platform: ili9xxx - id: displ8 - model: ili9342 - cs_pin: GPIO5 - dc_pin: GPIO4 - reset_pin: - number: GPIO21 - -i2c: - scl: GPIO18 - sda: GPIO8 - -touchscreen: - - platform: cst226 - interrupt_pin: GPIO3 - reset_pin: GPIO20 - +<<: !include common.yaml diff --git a/tests/components/cst816/common.yaml b/tests/components/cst816/common.yaml new file mode 100644 index 0000000000..f8deea6e98 --- /dev/null +++ b/tests/components/cst816/common.yaml @@ -0,0 +1,36 @@ +touchscreen: + - platform: cst816 + id: my_touchscreen + interrupt_pin: + number: 21 + reset_pin: GPIO16 + transform: + mirror_x: false + mirror_y: false + swap_xy: false + +i2c: + sda: 3 + scl: 2 + +display: + - id: my_display + platform: ili9xxx + dimensions: 480x320 + model: ST7796 + cs_pin: 15 + dc_pin: 20 + reset_pin: 22 + transform: + swap_xy: true + mirror_x: true + mirror_y: true + auto_clear_enabled: false + +spi: + clk_pin: 14 + mosi_pin: 13 + +binary_sensor: + - platform: cst816 + name: Home Button diff --git a/tests/components/cst816/test.esp32.yaml b/tests/components/cst816/test.esp32.yaml index f8deea6e98..dade44d145 100644 --- a/tests/components/cst816/test.esp32.yaml +++ b/tests/components/cst816/test.esp32.yaml @@ -1,36 +1 @@ -touchscreen: - - platform: cst816 - id: my_touchscreen - interrupt_pin: - number: 21 - reset_pin: GPIO16 - transform: - mirror_x: false - mirror_y: false - swap_xy: false - -i2c: - sda: 3 - scl: 2 - -display: - - id: my_display - platform: ili9xxx - dimensions: 480x320 - model: ST7796 - cs_pin: 15 - dc_pin: 20 - reset_pin: 22 - transform: - swap_xy: true - mirror_x: true - mirror_y: true - auto_clear_enabled: false - -spi: - clk_pin: 14 - mosi_pin: 13 - -binary_sensor: - - platform: cst816 - name: Home Button +<<: !include common.yaml diff --git a/tests/components/dallas/common.yaml b/tests/components/dallas/common.yaml new file mode 100644 index 0000000000..7975977107 --- /dev/null +++ b/tests/components/dallas/common.yaml @@ -0,0 +1,11 @@ +dallas: + pin: 4 + +sensor: + - platform: dallas + address: 0x1C0000031EDD2A28 + name: Dallas Temperature + resolution: 9 + - platform: dallas + index: 1 + name: Dallas Temperature diff --git a/tests/components/dallas/test.esp32-c3-idf.yaml b/tests/components/dallas/test.esp32-c3-idf.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.esp32-c3-idf.yaml +++ b/tests/components/dallas/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/dallas/test.esp32-c3.yaml b/tests/components/dallas/test.esp32-c3.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.esp32-c3.yaml +++ b/tests/components/dallas/test.esp32-c3.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/dallas/test.esp32-idf.yaml b/tests/components/dallas/test.esp32-idf.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.esp32-idf.yaml +++ b/tests/components/dallas/test.esp32-idf.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/dallas/test.esp32.yaml b/tests/components/dallas/test.esp32.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.esp32.yaml +++ b/tests/components/dallas/test.esp32.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/dallas/test.esp8266.yaml b/tests/components/dallas/test.esp8266.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.esp8266.yaml +++ b/tests/components/dallas/test.esp8266.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/dallas/test.rp2040.yaml b/tests/components/dallas/test.rp2040.yaml index 7975977107..dade44d145 100644 --- a/tests/components/dallas/test.rp2040.yaml +++ b/tests/components/dallas/test.rp2040.yaml @@ -1,11 +1 @@ -dallas: - pin: 4 - -sensor: - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Dallas Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Dallas Temperature +<<: !include common.yaml diff --git a/tests/components/datetime/common.yaml b/tests/components/datetime/common.yaml new file mode 100644 index 0000000000..4e26b68121 --- /dev/null +++ b/tests/components/datetime/common.yaml @@ -0,0 +1,3 @@ +datetime: + +time: diff --git a/tests/components/datetime/test.all.yaml b/tests/components/datetime/test.all.yaml index 4e26b68121..dade44d145 100644 --- a/tests/components/datetime/test.all.yaml +++ b/tests/components/datetime/test.all.yaml @@ -1,3 +1 @@ -datetime: - -time: +<<: !include common.yaml diff --git a/tests/components/debug/common.yaml b/tests/components/debug/common.yaml new file mode 100644 index 0000000000..5845beaa80 --- /dev/null +++ b/tests/components/debug/common.yaml @@ -0,0 +1 @@ +debug: diff --git a/tests/components/debug/test.esp32-c3-idf.yaml b/tests/components/debug/test.esp32-c3-idf.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.esp32-c3-idf.yaml +++ b/tests/components/debug/test.esp32-c3-idf.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.esp32-c3.yaml b/tests/components/debug/test.esp32-c3.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.esp32-c3.yaml +++ b/tests/components/debug/test.esp32-c3.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.esp32-idf.yaml b/tests/components/debug/test.esp32-idf.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.esp32-idf.yaml +++ b/tests/components/debug/test.esp32-idf.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.esp32.yaml b/tests/components/debug/test.esp32.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.esp32.yaml +++ b/tests/components/debug/test.esp32.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.esp8266.yaml b/tests/components/debug/test.esp8266.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.esp8266.yaml +++ b/tests/components/debug/test.esp8266.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.host.yaml b/tests/components/debug/test.host.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.host.yaml +++ b/tests/components/debug/test.host.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/debug/test.rp2040.yaml b/tests/components/debug/test.rp2040.yaml index 5845beaa80..dade44d145 100644 --- a/tests/components/debug/test.rp2040.yaml +++ b/tests/components/debug/test.rp2040.yaml @@ -1 +1 @@ -debug: +<<: !include common.yaml diff --git a/tests/components/dht/common.yaml b/tests/components/dht/common.yaml new file mode 100644 index 0000000000..f134a324ca --- /dev/null +++ b/tests/components/dht/common.yaml @@ -0,0 +1,11 @@ +sensor: + - platform: dht + pin: 4 + model: AM2302 + update_interval: 15s + temperature: + id: dht_temperature + name: DHT Temperature + humidity: + id: dht_humidity + name: DHT Humidity diff --git a/tests/components/dht/test.esp32-c3-idf.yaml b/tests/components/dht/test.esp32-c3-idf.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.esp32-c3-idf.yaml +++ b/tests/components/dht/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/dht/test.esp32-c3.yaml b/tests/components/dht/test.esp32-c3.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.esp32-c3.yaml +++ b/tests/components/dht/test.esp32-c3.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/dht/test.esp32-idf.yaml b/tests/components/dht/test.esp32-idf.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.esp32-idf.yaml +++ b/tests/components/dht/test.esp32-idf.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/dht/test.esp32.yaml b/tests/components/dht/test.esp32.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.esp32.yaml +++ b/tests/components/dht/test.esp32.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/dht/test.esp8266.yaml b/tests/components/dht/test.esp8266.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.esp8266.yaml +++ b/tests/components/dht/test.esp8266.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/dht/test.rp2040.yaml b/tests/components/dht/test.rp2040.yaml index f134a324ca..dade44d145 100644 --- a/tests/components/dht/test.rp2040.yaml +++ b/tests/components/dht/test.rp2040.yaml @@ -1,11 +1 @@ -sensor: - - platform: dht - pin: 4 - model: AM2302 - update_interval: 15s - temperature: - id: dht_temperature - name: DHT Temperature - humidity: - id: dht_humidity - name: DHT Humidity +<<: !include common.yaml diff --git a/tests/components/display/common.yaml b/tests/components/display/common.yaml new file mode 100644 index 0000000000..a22aa76780 --- /dev/null +++ b/tests/components/display/common.yaml @@ -0,0 +1,35 @@ +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + lambda: |- + // Draw an analog clock in the center of the screen + int centerX = it.get_width() / 2; + int centerY = it.get_height() / 2; + int radius = min(it.get_width(), it.get_height()) / 4; + + // Draw border + it.circle(centerX, centerY, radius); + + // Draw hour ticks + for(int h = 0; h < 12; h++) { + int hourAngle = (h * 30) - 90; + + it.line_at_angle(centerX, centerY, hourAngle, radius - 10, radius); + } + + // Draw minute ticks + for(int m = 0; m < 60; m++) { + int minuteAngle = (m * 6) - 90; + + it.line_at_angle(centerX, centerY, minuteAngle, radius - 5, radius); + } diff --git a/tests/components/display/test.esp32.yaml b/tests/components/display/test.esp32.yaml index a22aa76780..dade44d145 100644 --- a/tests/components/display/test.esp32.yaml +++ b/tests/components/display/test.esp32.yaml @@ -1,35 +1 @@ -spi: - - id: spi_main_lcd - clk_pin: 16 - mosi_pin: 17 - miso_pin: 15 - -display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 12 - dc_pin: 13 - reset_pin: 21 - lambda: |- - // Draw an analog clock in the center of the screen - int centerX = it.get_width() / 2; - int centerY = it.get_height() / 2; - int radius = min(it.get_width(), it.get_height()) / 4; - - // Draw border - it.circle(centerX, centerY, radius); - - // Draw hour ticks - for(int h = 0; h < 12; h++) { - int hourAngle = (h * 30) - 90; - - it.line_at_angle(centerX, centerY, hourAngle, radius - 10, radius); - } - - // Draw minute ticks - for(int m = 0; m < 60; m++) { - int minuteAngle = (m * 6) - 90; - - it.line_at_angle(centerX, centerY, minuteAngle, radius - 5, radius); - } +<<: !include common.yaml diff --git a/tests/components/duty_cycle/common.yaml b/tests/components/duty_cycle/common.yaml new file mode 100644 index 0000000000..2b7f31efbd --- /dev/null +++ b/tests/components/duty_cycle/common.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: duty_cycle + pin: 4 + name: Duty Cycle Sensor diff --git a/tests/components/duty_cycle/test.esp32-c3-idf.yaml b/tests/components/duty_cycle/test.esp32-c3-idf.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.esp32-c3-idf.yaml +++ b/tests/components/duty_cycle/test.esp32-c3-idf.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_cycle/test.esp32-c3.yaml b/tests/components/duty_cycle/test.esp32-c3.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.esp32-c3.yaml +++ b/tests/components/duty_cycle/test.esp32-c3.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_cycle/test.esp32-idf.yaml b/tests/components/duty_cycle/test.esp32-idf.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.esp32-idf.yaml +++ b/tests/components/duty_cycle/test.esp32-idf.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_cycle/test.esp32.yaml b/tests/components/duty_cycle/test.esp32.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.esp32.yaml +++ b/tests/components/duty_cycle/test.esp32.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_cycle/test.esp8266.yaml b/tests/components/duty_cycle/test.esp8266.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.esp8266.yaml +++ b/tests/components/duty_cycle/test.esp8266.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_cycle/test.rp2040.yaml b/tests/components/duty_cycle/test.rp2040.yaml index 2b7f31efbd..dade44d145 100644 --- a/tests/components/duty_cycle/test.rp2040.yaml +++ b/tests/components/duty_cycle/test.rp2040.yaml @@ -1,4 +1 @@ -sensor: - - platform: duty_cycle - pin: 4 - name: Duty Cycle Sensor +<<: !include common.yaml diff --git a/tests/components/duty_time/common.yaml b/tests/components/duty_time/common.yaml new file mode 100644 index 0000000000..28fa4afd1c --- /dev/null +++ b/tests/components/duty_time/common.yaml @@ -0,0 +1,14 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +sensor: + - platform: duty_time + name: Duty Time + sensor: bin1 diff --git a/tests/components/duty_time/test.esp32-c3-idf.yaml b/tests/components/duty_time/test.esp32-c3-idf.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.esp32-c3-idf.yaml +++ b/tests/components/duty_time/test.esp32-c3-idf.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/duty_time/test.esp32-c3.yaml b/tests/components/duty_time/test.esp32-c3.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.esp32-c3.yaml +++ b/tests/components/duty_time/test.esp32-c3.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/duty_time/test.esp32-idf.yaml b/tests/components/duty_time/test.esp32-idf.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.esp32-idf.yaml +++ b/tests/components/duty_time/test.esp32-idf.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/duty_time/test.esp32.yaml b/tests/components/duty_time/test.esp32.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.esp32.yaml +++ b/tests/components/duty_time/test.esp32.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/duty_time/test.esp8266.yaml b/tests/components/duty_time/test.esp8266.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.esp8266.yaml +++ b/tests/components/duty_time/test.esp8266.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/duty_time/test.rp2040.yaml b/tests/components/duty_time/test.rp2040.yaml index 28fa4afd1c..dade44d145 100644 --- a/tests/components/duty_time/test.rp2040.yaml +++ b/tests/components/duty_time/test.rp2040.yaml @@ -1,14 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -sensor: - - platform: duty_time - name: Duty Time - sensor: bin1 +<<: !include common.yaml diff --git a/tests/components/endstop/common.yaml b/tests/components/endstop/common.yaml new file mode 100644 index 0000000000..341fbf7260 --- /dev/null +++ b/tests/components/endstop/common.yaml @@ -0,0 +1,33 @@ +binary_sensor: + - platform: template + id: bin1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + optimistic: true + - platform: template + id: template_switch2 + optimistic: true + +cover: + - platform: endstop + id: endstop_cover + name: Endstop Cover + stop_action: + - switch.turn_on: template_switch1 + open_endstop: bin1 + open_action: + - switch.turn_on: template_switch1 + open_duration: 5min + close_endstop: bin1 + close_action: + - switch.turn_on: template_switch2 + close_duration: 4.5min + max_duration: 10min diff --git a/tests/components/endstop/test.esp32-c3-idf.yaml b/tests/components/endstop/test.esp32-c3-idf.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.esp32-c3-idf.yaml +++ b/tests/components/endstop/test.esp32-c3-idf.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/endstop/test.esp32-c3.yaml b/tests/components/endstop/test.esp32-c3.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.esp32-c3.yaml +++ b/tests/components/endstop/test.esp32-c3.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/endstop/test.esp32-idf.yaml b/tests/components/endstop/test.esp32-idf.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.esp32-idf.yaml +++ b/tests/components/endstop/test.esp32-idf.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/endstop/test.esp32.yaml b/tests/components/endstop/test.esp32.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.esp32.yaml +++ b/tests/components/endstop/test.esp32.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/endstop/test.esp8266.yaml b/tests/components/endstop/test.esp8266.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.esp8266.yaml +++ b/tests/components/endstop/test.esp8266.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/endstop/test.rp2040.yaml b/tests/components/endstop/test.rp2040.yaml index 341fbf7260..dade44d145 100644 --- a/tests/components/endstop/test.rp2040.yaml +++ b/tests/components/endstop/test.rp2040.yaml @@ -1,33 +1 @@ -binary_sensor: - - platform: template - id: bin1 - lambda: |- - if (millis() > 10000) { - return true; - } else { - return false; - } - -switch: - - platform: template - id: template_switch1 - optimistic: true - - platform: template - id: template_switch2 - optimistic: true - -cover: - - platform: endstop - id: endstop_cover - name: Endstop Cover - stop_action: - - switch.turn_on: template_switch1 - open_endstop: bin1 - open_action: - - switch.turn_on: template_switch1 - open_duration: 5min - close_endstop: bin1 - close_action: - - switch.turn_on: template_switch2 - close_duration: 4.5min - max_duration: 10min +<<: !include common.yaml diff --git a/tests/components/esp32_ble/common.yaml b/tests/components/esp32_ble/common.yaml new file mode 100644 index 0000000000..76b35fc8f8 --- /dev/null +++ b/tests/components/esp32_ble/common.yaml @@ -0,0 +1,2 @@ +esp32_ble: + io_capability: keyboard_only diff --git a/tests/components/esp32_ble/test.esp32-c3-idf.yaml b/tests/components/esp32_ble/test.esp32-c3-idf.yaml index 76b35fc8f8..dade44d145 100644 --- a/tests/components/esp32_ble/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble/test.esp32-c3-idf.yaml @@ -1,2 +1 @@ -esp32_ble: - io_capability: keyboard_only +<<: !include common.yaml diff --git a/tests/components/esp32_ble/test.esp32-c3.yaml b/tests/components/esp32_ble/test.esp32-c3.yaml index 76b35fc8f8..dade44d145 100644 --- a/tests/components/esp32_ble/test.esp32-c3.yaml +++ b/tests/components/esp32_ble/test.esp32-c3.yaml @@ -1,2 +1 @@ -esp32_ble: - io_capability: keyboard_only +<<: !include common.yaml diff --git a/tests/components/esp32_ble/test.esp32-idf.yaml b/tests/components/esp32_ble/test.esp32-idf.yaml index 76b35fc8f8..dade44d145 100644 --- a/tests/components/esp32_ble/test.esp32-idf.yaml +++ b/tests/components/esp32_ble/test.esp32-idf.yaml @@ -1,2 +1 @@ -esp32_ble: - io_capability: keyboard_only +<<: !include common.yaml diff --git a/tests/components/esp32_ble/test.esp32.yaml b/tests/components/esp32_ble/test.esp32.yaml index 76b35fc8f8..dade44d145 100644 --- a/tests/components/esp32_ble/test.esp32.yaml +++ b/tests/components/esp32_ble/test.esp32.yaml @@ -1,2 +1 @@ -esp32_ble: - io_capability: keyboard_only +<<: !include common.yaml diff --git a/tests/components/esp32_ble_beacon/common.yaml b/tests/components/esp32_ble_beacon/common.yaml new file mode 100644 index 0000000000..aafb0341d7 --- /dev/null +++ b/tests/components/esp32_ble_beacon/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_beacon: + type: iBeacon + uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' diff --git a/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml index aafb0341d7..dade44d145 100644 --- a/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble_beacon/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_beacon: - type: iBeacon - uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' +<<: !include common.yaml diff --git a/tests/components/esp32_ble_beacon/test.esp32-c3.yaml b/tests/components/esp32_ble_beacon/test.esp32-c3.yaml index aafb0341d7..dade44d145 100644 --- a/tests/components/esp32_ble_beacon/test.esp32-c3.yaml +++ b/tests/components/esp32_ble_beacon/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_beacon: - type: iBeacon - uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' +<<: !include common.yaml diff --git a/tests/components/esp32_ble_beacon/test.esp32-idf.yaml b/tests/components/esp32_ble_beacon/test.esp32-idf.yaml index aafb0341d7..dade44d145 100644 --- a/tests/components/esp32_ble_beacon/test.esp32-idf.yaml +++ b/tests/components/esp32_ble_beacon/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_beacon: - type: iBeacon - uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' +<<: !include common.yaml diff --git a/tests/components/esp32_ble_beacon/test.esp32.yaml b/tests/components/esp32_ble_beacon/test.esp32.yaml index aafb0341d7..dade44d145 100644 --- a/tests/components/esp32_ble_beacon/test.esp32.yaml +++ b/tests/components/esp32_ble_beacon/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_beacon: - type: iBeacon - uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' +<<: !include common.yaml diff --git a/tests/components/esp32_ble_client/common.yaml b/tests/components/esp32_ble_client/common.yaml new file mode 100644 index 0000000000..33b7205bf2 --- /dev/null +++ b/tests/components/esp32_ble_client/common.yaml @@ -0,0 +1,5 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: blec diff --git a/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml index 33b7205bf2..dade44d145 100644 --- a/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble_client/test.esp32-c3-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: blec +<<: !include common.yaml diff --git a/tests/components/esp32_ble_client/test.esp32-c3.yaml b/tests/components/esp32_ble_client/test.esp32-c3.yaml index 33b7205bf2..dade44d145 100644 --- a/tests/components/esp32_ble_client/test.esp32-c3.yaml +++ b/tests/components/esp32_ble_client/test.esp32-c3.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: blec +<<: !include common.yaml diff --git a/tests/components/esp32_ble_client/test.esp32-idf.yaml b/tests/components/esp32_ble_client/test.esp32-idf.yaml index 33b7205bf2..dade44d145 100644 --- a/tests/components/esp32_ble_client/test.esp32-idf.yaml +++ b/tests/components/esp32_ble_client/test.esp32-idf.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: blec +<<: !include common.yaml diff --git a/tests/components/esp32_ble_client/test.esp32.yaml b/tests/components/esp32_ble_client/test.esp32.yaml index 33b7205bf2..dade44d145 100644 --- a/tests/components/esp32_ble_client/test.esp32.yaml +++ b/tests/components/esp32_ble_client/test.esp32.yaml @@ -1,5 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: blec +<<: !include common.yaml diff --git a/tests/components/esp32_ble_server/common.yaml b/tests/components/esp32_ble_server/common.yaml new file mode 100644 index 0000000000..29a5407f84 --- /dev/null +++ b/tests/components/esp32_ble_server/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_server: + id: ble + manufacturer_data: [0x72, 0x4, 0x00, 0x23] diff --git a/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml index 29a5407f84..dade44d145 100644 --- a/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble_server/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_server: - id: ble - manufacturer_data: [0x72, 0x4, 0x00, 0x23] +<<: !include common.yaml diff --git a/tests/components/esp32_ble_server/test.esp32-c3.yaml b/tests/components/esp32_ble_server/test.esp32-c3.yaml index 29a5407f84..dade44d145 100644 --- a/tests/components/esp32_ble_server/test.esp32-c3.yaml +++ b/tests/components/esp32_ble_server/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_server: - id: ble - manufacturer_data: [0x72, 0x4, 0x00, 0x23] +<<: !include common.yaml diff --git a/tests/components/esp32_ble_server/test.esp32-idf.yaml b/tests/components/esp32_ble_server/test.esp32-idf.yaml index 29a5407f84..dade44d145 100644 --- a/tests/components/esp32_ble_server/test.esp32-idf.yaml +++ b/tests/components/esp32_ble_server/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_server: - id: ble - manufacturer_data: [0x72, 0x4, 0x00, 0x23] +<<: !include common.yaml diff --git a/tests/components/esp32_ble_server/test.esp32.yaml b/tests/components/esp32_ble_server/test.esp32.yaml index 29a5407f84..dade44d145 100644 --- a/tests/components/esp32_ble_server/test.esp32.yaml +++ b/tests/components/esp32_ble_server/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_server: - id: ble - manufacturer_data: [0x72, 0x4, 0x00, 0x23] +<<: !include common.yaml diff --git a/tests/components/esp32_ble_tracker/common.yaml b/tests/components/esp32_ble_tracker/common.yaml new file mode 100644 index 0000000000..ef23635c9e --- /dev/null +++ b/tests/components/esp32_ble_tracker/common.yaml @@ -0,0 +1,41 @@ +esphome: + on_boot: + then: + - esp32_ble_tracker.start_scan + - esp32_ble_tracker.stop_scan + +esp32_ble_tracker: + on_ble_advertise: + - mac_address: + - AA:BB:CC:DD:EE:FF + - FF:EE:DD:CC:BB:AA + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); + # yamllint enable rule:line-length + - mac_address: AC:37:43:77:5F:4C + then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + - then: + # yamllint disable rule:line-length + - lambda: !lambda |- + ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); + # yamllint enable rule:line-length + on_ble_service_data_advertise: + - service_uuid: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of service data is %i", x.size()); + on_ble_manufacturer_data_advertise: + - manufacturer_id: ABCD + then: + - lambda: !lambda |- + ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); + on_scan_end: + - then: + - lambda: |- + ESP_LOGD("ble_auto", "The scan has ended!"); diff --git a/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml b/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml index ef23635c9e..dade44d145 100644 --- a/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble_tracker/test.esp32-c3-idf.yaml @@ -1,41 +1 @@ -esphome: - on_boot: - then: - - esp32_ble_tracker.start_scan - - esp32_ble_tracker.stop_scan - -esp32_ble_tracker: - on_ble_advertise: - - mac_address: - - AA:BB:CC:DD:EE:FF - - FF:EE:DD:CC:BB:AA - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); - # yamllint enable rule:line-length - - mac_address: AC:37:43:77:5F:4C - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - on_ble_service_data_advertise: - - service_uuid: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of service data is %i", x.size()); - on_ble_manufacturer_data_advertise: - - manufacturer_id: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); - on_scan_end: - - then: - - lambda: |- - ESP_LOGD("ble_auto", "The scan has ended!"); +<<: !include common.yaml diff --git a/tests/components/esp32_ble_tracker/test.esp32-c3.yaml b/tests/components/esp32_ble_tracker/test.esp32-c3.yaml index ef23635c9e..dade44d145 100644 --- a/tests/components/esp32_ble_tracker/test.esp32-c3.yaml +++ b/tests/components/esp32_ble_tracker/test.esp32-c3.yaml @@ -1,41 +1 @@ -esphome: - on_boot: - then: - - esp32_ble_tracker.start_scan - - esp32_ble_tracker.stop_scan - -esp32_ble_tracker: - on_ble_advertise: - - mac_address: - - AA:BB:CC:DD:EE:FF - - FF:EE:DD:CC:BB:AA - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); - # yamllint enable rule:line-length - - mac_address: AC:37:43:77:5F:4C - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - on_ble_service_data_advertise: - - service_uuid: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of service data is %i", x.size()); - on_ble_manufacturer_data_advertise: - - manufacturer_id: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); - on_scan_end: - - then: - - lambda: |- - ESP_LOGD("ble_auto", "The scan has ended!"); +<<: !include common.yaml diff --git a/tests/components/esp32_ble_tracker/test.esp32-idf.yaml b/tests/components/esp32_ble_tracker/test.esp32-idf.yaml index ef23635c9e..dade44d145 100644 --- a/tests/components/esp32_ble_tracker/test.esp32-idf.yaml +++ b/tests/components/esp32_ble_tracker/test.esp32-idf.yaml @@ -1,41 +1 @@ -esphome: - on_boot: - then: - - esp32_ble_tracker.start_scan - - esp32_ble_tracker.stop_scan - -esp32_ble_tracker: - on_ble_advertise: - - mac_address: - - AA:BB:CC:DD:EE:FF - - FF:EE:DD:CC:BB:AA - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); - # yamllint enable rule:line-length - - mac_address: AC:37:43:77:5F:4C - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - on_ble_service_data_advertise: - - service_uuid: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of service data is %i", x.size()); - on_ble_manufacturer_data_advertise: - - manufacturer_id: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); - on_scan_end: - - then: - - lambda: |- - ESP_LOGD("ble_auto", "The scan has ended!"); +<<: !include common.yaml diff --git a/tests/components/esp32_ble_tracker/test.esp32.yaml b/tests/components/esp32_ble_tracker/test.esp32.yaml index ef23635c9e..dade44d145 100644 --- a/tests/components/esp32_ble_tracker/test.esp32.yaml +++ b/tests/components/esp32_ble_tracker/test.esp32.yaml @@ -1,41 +1 @@ -esphome: - on_boot: - then: - - esp32_ble_tracker.start_scan - - esp32_ble_tracker.stop_scan - -esp32_ble_tracker: - on_ble_advertise: - - mac_address: - - AA:BB:CC:DD:EE:FF - - FF:EE:DD:CC:BB:AA - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); - # yamllint enable rule:line-length - - mac_address: AC:37:43:77:5F:4C - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - on_ble_service_data_advertise: - - service_uuid: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of service data is %i", x.size()); - on_ble_manufacturer_data_advertise: - - manufacturer_id: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); - on_scan_end: - - then: - - lambda: |- - ESP_LOGD("ble_auto", "The scan has ended!"); +<<: !include common.yaml diff --git a/tests/components/esp32_camera/common.yaml b/tests/components/esp32_camera/common.yaml new file mode 100644 index 0000000000..2f5f792f1c --- /dev/null +++ b/tests/components/esp32_camera/common.yaml @@ -0,0 +1,28 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); diff --git a/tests/components/esp32_camera/test.esp32-idf.yaml b/tests/components/esp32_camera/test.esp32-idf.yaml index 2f5f792f1c..dade44d145 100644 --- a/tests/components/esp32_camera/test.esp32-idf.yaml +++ b/tests/components/esp32_camera/test.esp32-idf.yaml @@ -1,28 +1 @@ -esp32_camera: - name: ESP32 Camera - data_pins: - - number: 17 - - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 - vsync_pin: 22 - href_pin: 26 - pixel_clock_pin: 21 - external_clock: - pin: 27 - frequency: 20MHz - i2c_pins: - sda: 25 - scl: 23 - reset_pin: 15 - power_down_pin: 1 - resolution: 640x480 - jpeg_quality: 10 - on_image: - then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); +<<: !include common.yaml diff --git a/tests/components/esp32_camera/test.esp32.yaml b/tests/components/esp32_camera/test.esp32.yaml index 2f5f792f1c..dade44d145 100644 --- a/tests/components/esp32_camera/test.esp32.yaml +++ b/tests/components/esp32_camera/test.esp32.yaml @@ -1,28 +1 @@ -esp32_camera: - name: ESP32 Camera - data_pins: - - number: 17 - - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 - vsync_pin: 22 - href_pin: 26 - pixel_clock_pin: 21 - external_clock: - pin: 27 - frequency: 20MHz - i2c_pins: - sda: 25 - scl: 23 - reset_pin: 15 - power_down_pin: 1 - resolution: 640x480 - jpeg_quality: 10 - on_image: - then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); +<<: !include common.yaml diff --git a/tests/components/esp32_camera_web_server/common.yaml b/tests/components/esp32_camera_web_server/common.yaml new file mode 100644 index 0000000000..5edefdf0a8 --- /dev/null +++ b/tests/components/esp32_camera_web_server/common.yaml @@ -0,0 +1,34 @@ +esp32_camera: + name: ESP32 Camera + data_pins: + - number: 17 + - number: 35 + - number: 34 + - number: 5 + - number: 39 + - number: 18 + - number: 36 + - number: 19 + vsync_pin: 22 + href_pin: 26 + pixel_clock_pin: 21 + external_clock: + pin: 27 + frequency: 20MHz + i2c_pins: + sda: 25 + scl: 23 + reset_pin: 15 + power_down_pin: 1 + resolution: 640x480 + jpeg_quality: 10 + on_image: + then: + - lambda: |- + ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); + +esp32_camera_web_server: + - port: 8080 + mode: stream + - port: 8081 + mode: snapshot diff --git a/tests/components/esp32_camera_web_server/test.esp32-idf.yaml b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml index 5edefdf0a8..dade44d145 100644 --- a/tests/components/esp32_camera_web_server/test.esp32-idf.yaml +++ b/tests/components/esp32_camera_web_server/test.esp32-idf.yaml @@ -1,34 +1 @@ -esp32_camera: - name: ESP32 Camera - data_pins: - - number: 17 - - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 - vsync_pin: 22 - href_pin: 26 - pixel_clock_pin: 21 - external_clock: - pin: 27 - frequency: 20MHz - i2c_pins: - sda: 25 - scl: 23 - reset_pin: 15 - power_down_pin: 1 - resolution: 640x480 - jpeg_quality: 10 - on_image: - then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); - -esp32_camera_web_server: - - port: 8080 - mode: stream - - port: 8081 - mode: snapshot +<<: !include common.yaml diff --git a/tests/components/esp32_camera_web_server/test.esp32.yaml b/tests/components/esp32_camera_web_server/test.esp32.yaml index 5edefdf0a8..dade44d145 100644 --- a/tests/components/esp32_camera_web_server/test.esp32.yaml +++ b/tests/components/esp32_camera_web_server/test.esp32.yaml @@ -1,34 +1 @@ -esp32_camera: - name: ESP32 Camera - data_pins: - - number: 17 - - number: 35 - - number: 34 - - number: 5 - - number: 39 - - number: 18 - - number: 36 - - number: 19 - vsync_pin: 22 - href_pin: 26 - pixel_clock_pin: 21 - external_clock: - pin: 27 - frequency: 20MHz - i2c_pins: - sda: 25 - scl: 23 - reset_pin: 15 - power_down_pin: 1 - resolution: 640x480 - jpeg_quality: 10 - on_image: - then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); - -esp32_camera_web_server: - - port: 8080 - mode: stream - - port: 8081 - mode: snapshot +<<: !include common.yaml diff --git a/tests/components/esp32_dac/common.yaml b/tests/components/esp32_dac/common.yaml new file mode 100644 index 0000000000..225627f5af --- /dev/null +++ b/tests/components/esp32_dac/common.yaml @@ -0,0 +1,4 @@ +output: + - platform: esp32_dac + id: dac_output + pin: 25 diff --git a/tests/components/esp32_dac/test.esp32-idf.yaml b/tests/components/esp32_dac/test.esp32-idf.yaml index 225627f5af..dade44d145 100644 --- a/tests/components/esp32_dac/test.esp32-idf.yaml +++ b/tests/components/esp32_dac/test.esp32-idf.yaml @@ -1,4 +1 @@ -output: - - platform: esp32_dac - id: dac_output - pin: 25 +<<: !include common.yaml diff --git a/tests/components/esp32_dac/test.esp32.yaml b/tests/components/esp32_dac/test.esp32.yaml index 225627f5af..dade44d145 100644 --- a/tests/components/esp32_dac/test.esp32.yaml +++ b/tests/components/esp32_dac/test.esp32.yaml @@ -1,4 +1 @@ -output: - - platform: esp32_dac - id: dac_output - pin: 25 +<<: !include common.yaml diff --git a/tests/components/esp32_hall/common.yaml b/tests/components/esp32_hall/common.yaml new file mode 100644 index 0000000000..f8429f5aa0 --- /dev/null +++ b/tests/components/esp32_hall/common.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: esp32_hall + name: ESP32 Hall Sensor diff --git a/tests/components/esp32_hall/test.esp32-idf.yaml b/tests/components/esp32_hall/test.esp32-idf.yaml index f8429f5aa0..dade44d145 100644 --- a/tests/components/esp32_hall/test.esp32-idf.yaml +++ b/tests/components/esp32_hall/test.esp32-idf.yaml @@ -1,3 +1 @@ -sensor: - - platform: esp32_hall - name: ESP32 Hall Sensor +<<: !include common.yaml diff --git a/tests/components/esp32_hall/test.esp32.yaml b/tests/components/esp32_hall/test.esp32.yaml index f8429f5aa0..dade44d145 100644 --- a/tests/components/esp32_hall/test.esp32.yaml +++ b/tests/components/esp32_hall/test.esp32.yaml @@ -1,3 +1 @@ -sensor: - - platform: esp32_hall - name: ESP32 Hall Sensor +<<: !include common.yaml diff --git a/tests/components/esp32_improv/common.yaml b/tests/components/esp32_improv/common.yaml new file mode 100644 index 0000000000..7eb3f9c0be --- /dev/null +++ b/tests/components/esp32_improv/common.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +binary_sensor: + - platform: gpio + pin: 0 + id: io0_button + +output: + - platform: gpio + pin: 2 + id: built_in_led + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led diff --git a/tests/components/esp32_improv/test.esp32-c3-idf.yaml b/tests/components/esp32_improv/test.esp32-c3-idf.yaml index 7eb3f9c0be..dade44d145 100644 --- a/tests/components/esp32_improv/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_improv/test.esp32-c3-idf.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -binary_sensor: - - platform: gpio - pin: 0 - id: io0_button - -output: - - platform: gpio - pin: 2 - id: built_in_led - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led +<<: !include common.yaml diff --git a/tests/components/esp32_improv/test.esp32-c3.yaml b/tests/components/esp32_improv/test.esp32-c3.yaml index 7eb3f9c0be..dade44d145 100644 --- a/tests/components/esp32_improv/test.esp32-c3.yaml +++ b/tests/components/esp32_improv/test.esp32-c3.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -binary_sensor: - - platform: gpio - pin: 0 - id: io0_button - -output: - - platform: gpio - pin: 2 - id: built_in_led - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led +<<: !include common.yaml diff --git a/tests/components/esp32_improv/test.esp32-idf.yaml b/tests/components/esp32_improv/test.esp32-idf.yaml index 7eb3f9c0be..dade44d145 100644 --- a/tests/components/esp32_improv/test.esp32-idf.yaml +++ b/tests/components/esp32_improv/test.esp32-idf.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -binary_sensor: - - platform: gpio - pin: 0 - id: io0_button - -output: - - platform: gpio - pin: 2 - id: built_in_led - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led +<<: !include common.yaml diff --git a/tests/components/esp32_improv/test.esp32.yaml b/tests/components/esp32_improv/test.esp32.yaml index 7eb3f9c0be..dade44d145 100644 --- a/tests/components/esp32_improv/test.esp32.yaml +++ b/tests/components/esp32_improv/test.esp32.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -binary_sensor: - - platform: gpio - pin: 0 - id: io0_button - -output: - - platform: gpio - pin: 2 - id: built_in_led - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led +<<: !include common.yaml diff --git a/tests/components/esp32_touch/common.yaml b/tests/components/esp32_touch/common.yaml new file mode 100644 index 0000000000..691cce8d86 --- /dev/null +++ b/tests/components/esp32_touch/common.yaml @@ -0,0 +1,16 @@ +esp32_touch: + setup_mode: false + iir_filter: 10ms + sleep_duration: 27ms + measurement_duration: 8ms + low_voltage_reference: 0.5V + high_voltage_reference: 2.7V + voltage_attenuation: 1.5V + +binary_sensor: + - platform: esp32_touch + name: ESP32 Touch Pad + pin: 27 + threshold: 1000 + on_press: + - logger.log: "I'm touched!" diff --git a/tests/components/esp32_touch/test.esp32-idf.yaml b/tests/components/esp32_touch/test.esp32-idf.yaml index 691cce8d86..dade44d145 100644 --- a/tests/components/esp32_touch/test.esp32-idf.yaml +++ b/tests/components/esp32_touch/test.esp32-idf.yaml @@ -1,16 +1 @@ -esp32_touch: - setup_mode: false - iir_filter: 10ms - sleep_duration: 27ms - measurement_duration: 8ms - low_voltage_reference: 0.5V - high_voltage_reference: 2.7V - voltage_attenuation: 1.5V - -binary_sensor: - - platform: esp32_touch - name: ESP32 Touch Pad - pin: 27 - threshold: 1000 - on_press: - - logger.log: "I'm touched!" +<<: !include common.yaml diff --git a/tests/components/esp32_touch/test.esp32.yaml b/tests/components/esp32_touch/test.esp32.yaml index 691cce8d86..dade44d145 100644 --- a/tests/components/esp32_touch/test.esp32.yaml +++ b/tests/components/esp32_touch/test.esp32.yaml @@ -1,16 +1 @@ -esp32_touch: - setup_mode: false - iir_filter: 10ms - sleep_duration: 27ms - measurement_duration: 8ms - low_voltage_reference: 0.5V - high_voltage_reference: 2.7V - voltage_attenuation: 1.5V - -binary_sensor: - - platform: esp32_touch - name: ESP32 Touch Pad - pin: 27 - threshold: 1000 - on_press: - - logger.log: "I'm touched!" +<<: !include common.yaml diff --git a/tests/components/esp8266_pwm/common.yaml b/tests/components/esp8266_pwm/common.yaml new file mode 100644 index 0000000000..52b290f91b --- /dev/null +++ b/tests/components/esp8266_pwm/common.yaml @@ -0,0 +1,8 @@ +output: + - platform: esp8266_pwm + id: out + pin: 4 + frequency: 50Hz + - platform: esp8266_pwm + id: out2 + pin: 5 diff --git a/tests/components/esp8266_pwm/test.esp8266.yaml b/tests/components/esp8266_pwm/test.esp8266.yaml index 52b290f91b..dade44d145 100644 --- a/tests/components/esp8266_pwm/test.esp8266.yaml +++ b/tests/components/esp8266_pwm/test.esp8266.yaml @@ -1,8 +1 @@ -output: - - platform: esp8266_pwm - id: out - pin: 4 - frequency: 50Hz - - platform: esp8266_pwm - id: out2 - pin: 5 +<<: !include common.yaml diff --git a/tests/components/ethernet/common.yaml b/tests/components/ethernet/common.yaml new file mode 100644 index 0000000000..b9ed9cb036 --- /dev/null +++ b/tests/components/ethernet/common.yaml @@ -0,0 +1,12 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/test.esp32-idf.yaml b/tests/components/ethernet/test.esp32-idf.yaml index b9ed9cb036..dade44d145 100644 --- a/tests/components/ethernet/test.esp32-idf.yaml +++ b/tests/components/ethernet/test.esp32-idf.yaml @@ -1,12 +1 @@ -ethernet: - type: LAN8720 - mdc_pin: 23 - mdio_pin: 25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: 26 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local +<<: !include common.yaml diff --git a/tests/components/ethernet/test.esp32.yaml b/tests/components/ethernet/test.esp32.yaml index b9ed9cb036..dade44d145 100644 --- a/tests/components/ethernet/test.esp32.yaml +++ b/tests/components/ethernet/test.esp32.yaml @@ -1,12 +1 @@ -ethernet: - type: LAN8720 - mdc_pin: 23 - mdio_pin: 25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: 26 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local +<<: !include common.yaml diff --git a/tests/components/ethernet_info/common.yaml b/tests/components/ethernet_info/common.yaml new file mode 100644 index 0000000000..dade4d7ca5 --- /dev/null +++ b/tests/components/ethernet_info/common.yaml @@ -0,0 +1,19 @@ +ethernet: + type: LAN8720 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local + +text_sensor: + - platform: ethernet_info + ip_address: + name: IP Address + dns_address: + name: DNS Address diff --git a/tests/components/ethernet_info/test.esp32-idf.yaml b/tests/components/ethernet_info/test.esp32-idf.yaml index dade4d7ca5..dade44d145 100644 --- a/tests/components/ethernet_info/test.esp32-idf.yaml +++ b/tests/components/ethernet_info/test.esp32-idf.yaml @@ -1,19 +1 @@ -ethernet: - type: LAN8720 - mdc_pin: 23 - mdio_pin: 25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: 26 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local - -text_sensor: - - platform: ethernet_info - ip_address: - name: IP Address - dns_address: - name: DNS Address +<<: !include common.yaml diff --git a/tests/components/ethernet_info/test.esp32.yaml b/tests/components/ethernet_info/test.esp32.yaml index dade4d7ca5..dade44d145 100644 --- a/tests/components/ethernet_info/test.esp32.yaml +++ b/tests/components/ethernet_info/test.esp32.yaml @@ -1,19 +1 @@ -ethernet: - type: LAN8720 - mdc_pin: 23 - mdio_pin: 25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: 26 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local - -text_sensor: - - platform: ethernet_info - ip_address: - name: IP Address - dns_address: - name: DNS Address +<<: !include common.yaml diff --git a/tests/components/event/common.yaml b/tests/components/event/common.yaml new file mode 100644 index 0000000000..71cc19a6b0 --- /dev/null +++ b/tests/components/event/common.yaml @@ -0,0 +1,9 @@ +event: + - platform: template + name: Event + id: some_event + event_types: + - template_event_type1 + - template_event_type2 + on_event: + - logger.log: Event fired diff --git a/tests/components/event/test.esp32-c3-idf.yaml b/tests/components/event/test.esp32-c3-idf.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.esp32-c3-idf.yaml +++ b/tests/components/event/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/event/test.esp32-c3.yaml b/tests/components/event/test.esp32-c3.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.esp32-c3.yaml +++ b/tests/components/event/test.esp32-c3.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/event/test.esp32-idf.yaml b/tests/components/event/test.esp32-idf.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.esp32-idf.yaml +++ b/tests/components/event/test.esp32-idf.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/event/test.esp32.yaml b/tests/components/event/test.esp32.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.esp32.yaml +++ b/tests/components/event/test.esp32.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/event/test.esp8266.yaml b/tests/components/event/test.esp8266.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.esp8266.yaml +++ b/tests/components/event/test.esp8266.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/event/test.rp2040.yaml b/tests/components/event/test.rp2040.yaml index 71cc19a6b0..dade44d145 100644 --- a/tests/components/event/test.rp2040.yaml +++ b/tests/components/event/test.rp2040.yaml @@ -1,9 +1 @@ -event: - - platform: template - name: Event - id: some_event - event_types: - - template_event_type1 - - template_event_type2 - on_event: - - logger.log: Event fired +<<: !include common.yaml diff --git a/tests/components/exposure_notifications/common.yaml b/tests/components/exposure_notifications/common.yaml new file mode 100644 index 0000000000..faba5bb2d1 --- /dev/null +++ b/tests/components/exposure_notifications/common.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +exposure_notifications: + on_exposure_notification: + then: + - lambda: | + ESP_LOGD("main", "Got notification:"); + ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); + ESP_LOGD("main", " RSSI: %d", x.rssi); diff --git a/tests/components/exposure_notifications/test.esp32-c3-idf.yaml b/tests/components/exposure_notifications/test.esp32-c3-idf.yaml index faba5bb2d1..dade44d145 100644 --- a/tests/components/exposure_notifications/test.esp32-c3-idf.yaml +++ b/tests/components/exposure_notifications/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -exposure_notifications: - on_exposure_notification: - then: - - lambda: | - ESP_LOGD("main", "Got notification:"); - ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); - ESP_LOGD("main", " RSSI: %d", x.rssi); +<<: !include common.yaml diff --git a/tests/components/exposure_notifications/test.esp32-c3.yaml b/tests/components/exposure_notifications/test.esp32-c3.yaml index faba5bb2d1..dade44d145 100644 --- a/tests/components/exposure_notifications/test.esp32-c3.yaml +++ b/tests/components/exposure_notifications/test.esp32-c3.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -exposure_notifications: - on_exposure_notification: - then: - - lambda: | - ESP_LOGD("main", "Got notification:"); - ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); - ESP_LOGD("main", " RSSI: %d", x.rssi); +<<: !include common.yaml diff --git a/tests/components/exposure_notifications/test.esp32-idf.yaml b/tests/components/exposure_notifications/test.esp32-idf.yaml index faba5bb2d1..dade44d145 100644 --- a/tests/components/exposure_notifications/test.esp32-idf.yaml +++ b/tests/components/exposure_notifications/test.esp32-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -exposure_notifications: - on_exposure_notification: - then: - - lambda: | - ESP_LOGD("main", "Got notification:"); - ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); - ESP_LOGD("main", " RSSI: %d", x.rssi); +<<: !include common.yaml diff --git a/tests/components/exposure_notifications/test.esp32.yaml b/tests/components/exposure_notifications/test.esp32.yaml index faba5bb2d1..dade44d145 100644 --- a/tests/components/exposure_notifications/test.esp32.yaml +++ b/tests/components/exposure_notifications/test.esp32.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -exposure_notifications: - on_exposure_notification: - then: - - lambda: | - ESP_LOGD("main", "Got notification:"); - ESP_LOGD("main", " RPI: %s", format_hex(x.rolling_proximity_identifier).c_str()); - ESP_LOGD("main", " RSSI: %d", x.rssi); +<<: !include common.yaml diff --git a/tests/components/external_components/common.yaml b/tests/components/external_components/common.yaml new file mode 100644 index 0000000000..2b51267ec6 --- /dev/null +++ b/tests/components/external_components/common.yaml @@ -0,0 +1,6 @@ +external_components: + - source: github://esphome/esphome@dev + refresh: 1d + components: [bh1750] + - source: ../../../esphome/components + components: [sntp] diff --git a/tests/components/external_components/test.esp32-c3-idf.yaml b/tests/components/external_components/test.esp32-c3-idf.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.esp32-c3-idf.yaml +++ b/tests/components/external_components/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/external_components/test.esp32-c3.yaml b/tests/components/external_components/test.esp32-c3.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.esp32-c3.yaml +++ b/tests/components/external_components/test.esp32-c3.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/external_components/test.esp32-idf.yaml b/tests/components/external_components/test.esp32-idf.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.esp32-idf.yaml +++ b/tests/components/external_components/test.esp32-idf.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/external_components/test.esp32.yaml b/tests/components/external_components/test.esp32.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.esp32.yaml +++ b/tests/components/external_components/test.esp32.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/external_components/test.esp8266.yaml b/tests/components/external_components/test.esp8266.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.esp8266.yaml +++ b/tests/components/external_components/test.esp8266.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/external_components/test.rp2040.yaml b/tests/components/external_components/test.rp2040.yaml index 2b51267ec6..dade44d145 100644 --- a/tests/components/external_components/test.rp2040.yaml +++ b/tests/components/external_components/test.rp2040.yaml @@ -1,6 +1 @@ -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../../../esphome/components - components: [sntp] +<<: !include common.yaml diff --git a/tests/components/factory_reset/common.yaml b/tests/components/factory_reset/common.yaml new file mode 100644 index 0000000000..ad3abd603e --- /dev/null +++ b/tests/components/factory_reset/common.yaml @@ -0,0 +1,3 @@ +button: + - platform: factory_reset + name: Reset to Factory Default Settings diff --git a/tests/components/factory_reset/test.esp32-c3-idf.yaml b/tests/components/factory_reset/test.esp32-c3-idf.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.esp32-c3-idf.yaml +++ b/tests/components/factory_reset/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/factory_reset/test.esp32-c3.yaml b/tests/components/factory_reset/test.esp32-c3.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.esp32-c3.yaml +++ b/tests/components/factory_reset/test.esp32-c3.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/factory_reset/test.esp32-idf.yaml b/tests/components/factory_reset/test.esp32-idf.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.esp32-idf.yaml +++ b/tests/components/factory_reset/test.esp32-idf.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/factory_reset/test.esp32.yaml b/tests/components/factory_reset/test.esp32.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.esp32.yaml +++ b/tests/components/factory_reset/test.esp32.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/factory_reset/test.esp8266.yaml b/tests/components/factory_reset/test.esp8266.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.esp8266.yaml +++ b/tests/components/factory_reset/test.esp8266.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/factory_reset/test.rp2040.yaml b/tests/components/factory_reset/test.rp2040.yaml index ad3abd603e..dade44d145 100644 --- a/tests/components/factory_reset/test.rp2040.yaml +++ b/tests/components/factory_reset/test.rp2040.yaml @@ -1,3 +1 @@ -button: - - platform: factory_reset - name: Reset to Factory Default Settings +<<: !include common.yaml diff --git a/tests/components/fastled_clockless/common.yaml b/tests/components/fastled_clockless/common.yaml new file mode 100644 index 0000000000..8b1447a17a --- /dev/null +++ b/tests/components/fastled_clockless/common.yaml @@ -0,0 +1,71 @@ +light: + - platform: fastled_clockless + id: addr1 + chipset: WS2811 + pin: 13 + num_leds: 100 + rgb_order: BRG + max_refresh_rate: 20ms + color_correct: [75%, 100%, 50%] + name: FastLED WS2811 Light + effects: + - addressable_color_wipe: + - addressable_color_wipe: + name: Color Wipe Effect With Custom Values + colors: + - red: 100% + green: 100% + blue: 100% + num_leds: 1 + - red: 0% + green: 0% + blue: 0% + num_leds: 1 + add_led_interval: 100ms + reverse: false + - addressable_scan: + - addressable_scan: + name: Scan Effect With Custom Values + move_interval: 100ms + - addressable_twinkle: + - addressable_twinkle: + name: Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 4ms + - addressable_random_twinkle: + - addressable_random_twinkle: + name: Random Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 32ms + - addressable_fireworks: + - addressable_fireworks: + name: Fireworks Effect With Custom Values + update_interval: 32ms + spark_probability: 10% + use_random_color: false + fade_out_rate: 120 + - addressable_flicker: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + - addressable_lambda: + name: Test For Custom Lambda Effect + lambda: |- + if (initial_run) { + it[0] = current_color; + } + - automation: + name: Custom Effect + sequence: + - light.addressable_set: + id: addr1 + red: 100% + green: 100% + blue: 0% + - delay: 100ms + - light.addressable_set: + id: addr1 + red: 0% + green: 100% + blue: 0% diff --git a/tests/components/fastled_clockless/test.esp32.yaml b/tests/components/fastled_clockless/test.esp32.yaml index 8b1447a17a..dade44d145 100644 --- a/tests/components/fastled_clockless/test.esp32.yaml +++ b/tests/components/fastled_clockless/test.esp32.yaml @@ -1,71 +1 @@ -light: - - platform: fastled_clockless - id: addr1 - chipset: WS2811 - pin: 13 - num_leds: 100 - rgb_order: BRG - max_refresh_rate: 20ms - color_correct: [75%, 100%, 50%] - name: FastLED WS2811 Light - effects: - - addressable_color_wipe: - - addressable_color_wipe: - name: Color Wipe Effect With Custom Values - colors: - - red: 100% - green: 100% - blue: 100% - num_leds: 1 - - red: 0% - green: 0% - blue: 0% - num_leds: 1 - add_led_interval: 100ms - reverse: false - - addressable_scan: - - addressable_scan: - name: Scan Effect With Custom Values - move_interval: 100ms - - addressable_twinkle: - - addressable_twinkle: - name: Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 4ms - - addressable_random_twinkle: - - addressable_random_twinkle: - name: Random Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 32ms - - addressable_fireworks: - - addressable_fireworks: - name: Fireworks Effect With Custom Values - update_interval: 32ms - spark_probability: 10% - use_random_color: false - fade_out_rate: 120 - - addressable_flicker: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - - addressable_lambda: - name: Test For Custom Lambda Effect - lambda: |- - if (initial_run) { - it[0] = current_color; - } - - automation: - name: Custom Effect - sequence: - - light.addressable_set: - id: addr1 - red: 100% - green: 100% - blue: 0% - - delay: 100ms - - light.addressable_set: - id: addr1 - red: 0% - green: 100% - blue: 0% +<<: !include common.yaml diff --git a/tests/components/fastled_spi/common.yaml b/tests/components/fastled_spi/common.yaml new file mode 100644 index 0000000000..f6f7c5553b --- /dev/null +++ b/tests/components/fastled_spi/common.yaml @@ -0,0 +1,71 @@ +light: + - platform: fastled_spi + id: addr1 + chipset: WS2801 + clock_pin: 22 + data_pin: 23 + data_rate: 2MHz + num_leds: 60 + rgb_order: BRG + name: FastLED SPI Light + effects: + - addressable_color_wipe: + - addressable_color_wipe: + name: Color Wipe Effect With Custom Values + colors: + - red: 100% + green: 100% + blue: 100% + num_leds: 1 + - red: 0% + green: 0% + blue: 0% + num_leds: 1 + add_led_interval: 100ms + reverse: false + - addressable_scan: + - addressable_scan: + name: Scan Effect With Custom Values + move_interval: 100ms + - addressable_twinkle: + - addressable_twinkle: + name: Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 4ms + - addressable_random_twinkle: + - addressable_random_twinkle: + name: Random Twinkle Effect With Custom Values + twinkle_probability: 5% + progress_interval: 32ms + - addressable_fireworks: + - addressable_fireworks: + name: Fireworks Effect With Custom Values + update_interval: 32ms + spark_probability: 10% + use_random_color: false + fade_out_rate: 120 + - addressable_flicker: + - addressable_flicker: + name: Flicker Effect With Custom Values + update_interval: 16ms + intensity: 5% + - addressable_lambda: + name: Test For Custom Lambda Effect + lambda: |- + if (initial_run) { + it[0] = current_color; + } + - automation: + name: Custom Effect + sequence: + - light.addressable_set: + id: addr1 + red: 100% + green: 100% + blue: 0% + - delay: 100ms + - light.addressable_set: + id: addr1 + red: 0% + green: 100% + blue: 0% diff --git a/tests/components/fastled_spi/test.esp32.yaml b/tests/components/fastled_spi/test.esp32.yaml index f6f7c5553b..dade44d145 100644 --- a/tests/components/fastled_spi/test.esp32.yaml +++ b/tests/components/fastled_spi/test.esp32.yaml @@ -1,71 +1 @@ -light: - - platform: fastled_spi - id: addr1 - chipset: WS2801 - clock_pin: 22 - data_pin: 23 - data_rate: 2MHz - num_leds: 60 - rgb_order: BRG - name: FastLED SPI Light - effects: - - addressable_color_wipe: - - addressable_color_wipe: - name: Color Wipe Effect With Custom Values - colors: - - red: 100% - green: 100% - blue: 100% - num_leds: 1 - - red: 0% - green: 0% - blue: 0% - num_leds: 1 - add_led_interval: 100ms - reverse: false - - addressable_scan: - - addressable_scan: - name: Scan Effect With Custom Values - move_interval: 100ms - - addressable_twinkle: - - addressable_twinkle: - name: Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 4ms - - addressable_random_twinkle: - - addressable_random_twinkle: - name: Random Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 32ms - - addressable_fireworks: - - addressable_fireworks: - name: Fireworks Effect With Custom Values - update_interval: 32ms - spark_probability: 10% - use_random_color: false - fade_out_rate: 120 - - addressable_flicker: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - - addressable_lambda: - name: Test For Custom Lambda Effect - lambda: |- - if (initial_run) { - it[0] = current_color; - } - - automation: - name: Custom Effect - sequence: - - light.addressable_set: - id: addr1 - red: 100% - green: 100% - blue: 0% - - delay: 100ms - - light.addressable_set: - id: addr1 - red: 0% - green: 100% - blue: 0% +<<: !include common.yaml diff --git a/tests/components/feedback/common.yaml b/tests/components/feedback/common.yaml new file mode 100644 index 0000000000..f93d54e8b6 --- /dev/null +++ b/tests/components/feedback/common.yaml @@ -0,0 +1,39 @@ +binary_sensor: + - platform: template + id: open_endstop_sensor + - platform: template + id: open_sensor + - platform: template + id: open_obstacle_sensor + - platform: template + id: close_endstop_sensor + - platform: template + id: close_sensor + - platform: template + id: close_obstacle_sensor + +cover: + - platform: feedback + name: Feedback Cover + id: gate + device_class: gate + infer_endstop_from_movement: false + has_built_in_endstop: false + max_duration: 30s + direction_change_wait_time: 300ms + acceleration_wait_time: 150ms + obstacle_rollback: 10% + open_duration: 22.1s + open_endstop: open_endstop_sensor + open_sensor: open_sensor + open_obstacle_sensor: open_obstacle_sensor + close_duration: 22.4s + close_endstop: close_endstop_sensor + close_sensor: close_sensor + close_obstacle_sensor: close_obstacle_sensor + open_action: + - logger.log: Open Action + close_action: + - logger.log: Close Action + stop_action: + - logger.log: Stop Action diff --git a/tests/components/feedback/test.esp32-c3-idf.yaml b/tests/components/feedback/test.esp32-c3-idf.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.esp32-c3-idf.yaml +++ b/tests/components/feedback/test.esp32-c3-idf.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/feedback/test.esp32-c3.yaml b/tests/components/feedback/test.esp32-c3.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.esp32-c3.yaml +++ b/tests/components/feedback/test.esp32-c3.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/feedback/test.esp32-idf.yaml b/tests/components/feedback/test.esp32-idf.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.esp32-idf.yaml +++ b/tests/components/feedback/test.esp32-idf.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/feedback/test.esp32.yaml b/tests/components/feedback/test.esp32.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.esp32.yaml +++ b/tests/components/feedback/test.esp32.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/feedback/test.esp8266.yaml b/tests/components/feedback/test.esp8266.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.esp8266.yaml +++ b/tests/components/feedback/test.esp8266.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/feedback/test.rp2040.yaml b/tests/components/feedback/test.rp2040.yaml index f93d54e8b6..dade44d145 100644 --- a/tests/components/feedback/test.rp2040.yaml +++ b/tests/components/feedback/test.rp2040.yaml @@ -1,39 +1 @@ -binary_sensor: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - -cover: - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - open_action: - - logger.log: Open Action - close_action: - - logger.log: Close Action - stop_action: - - logger.log: Stop Action +<<: !include common.yaml diff --git a/tests/components/globals/common.yaml b/tests/components/globals/common.yaml new file mode 100644 index 0000000000..224a91a270 --- /dev/null +++ b/tests/components/globals/common.yaml @@ -0,0 +1,28 @@ +esphome: + on_boot: + then: + - globals.set: + id: glob_int + value: "10" + +globals: + - id: glob_int + type: int + restore_value: true + initial_value: "0" + - id: glob_float + type: float + restore_value: true + initial_value: "0.0f" + - id: glob_bool + type: bool + restore_value: false + initial_value: "true" + - id: glob_string + type: std::string + restore_value: false + # initial_value: "" + - id: glob_bool_processed + type: bool + restore_value: false + initial_value: "false" diff --git a/tests/components/globals/test.esp32-c3-idf.yaml b/tests/components/globals/test.esp32-c3-idf.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.esp32-c3-idf.yaml +++ b/tests/components/globals/test.esp32-c3-idf.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/globals/test.esp32-c3.yaml b/tests/components/globals/test.esp32-c3.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.esp32-c3.yaml +++ b/tests/components/globals/test.esp32-c3.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/globals/test.esp32-idf.yaml b/tests/components/globals/test.esp32-idf.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.esp32-idf.yaml +++ b/tests/components/globals/test.esp32-idf.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/globals/test.esp32.yaml b/tests/components/globals/test.esp32.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.esp32.yaml +++ b/tests/components/globals/test.esp32.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/globals/test.esp8266.yaml b/tests/components/globals/test.esp8266.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.esp8266.yaml +++ b/tests/components/globals/test.esp8266.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/globals/test.rp2040.yaml b/tests/components/globals/test.rp2040.yaml index 224a91a270..dade44d145 100644 --- a/tests/components/globals/test.rp2040.yaml +++ b/tests/components/globals/test.rp2040.yaml @@ -1,28 +1 @@ -esphome: - on_boot: - then: - - globals.set: - id: glob_int - value: "10" - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" +<<: !include common.yaml diff --git a/tests/components/host/common.yaml b/tests/components/host/common.yaml new file mode 100644 index 0000000000..3d14c190a6 --- /dev/null +++ b/tests/components/host/common.yaml @@ -0,0 +1,15 @@ +time: + - platform: sntp + id: esptime + timezone: Australia/Sydney + +logger: + level: VERBOSE + logs: + lvgl: INFO + display: DEBUG + sensor: INFO + vnc: DEBUG + +host: + mac_address: "62:23:45:AF:B3:DD" diff --git a/tests/components/host/test.host.yaml b/tests/components/host/test.host.yaml index 3d14c190a6..dade44d145 100644 --- a/tests/components/host/test.host.yaml +++ b/tests/components/host/test.host.yaml @@ -1,15 +1 @@ -time: - - platform: sntp - id: esptime - timezone: Australia/Sydney - -logger: - level: VERBOSE - logs: - lvgl: INFO - display: DEBUG - sensor: INFO - vnc: DEBUG - -host: - mac_address: "62:23:45:AF:B3:DD" +<<: !include common.yaml diff --git a/tests/components/improv_serial/common.yaml b/tests/components/improv_serial/common.yaml new file mode 100644 index 0000000000..b36fe5a4a7 --- /dev/null +++ b/tests/components/improv_serial/common.yaml @@ -0,0 +1,5 @@ +wifi: + ssid: MySSID + password: password1 + +improv_serial: diff --git a/tests/components/improv_serial/test.esp32-c3-idf.yaml b/tests/components/improv_serial/test.esp32-c3-idf.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.esp32-c3-idf.yaml +++ b/tests/components/improv_serial/test.esp32-c3-idf.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32-c3.yaml b/tests/components/improv_serial/test.esp32-c3.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.esp32-c3.yaml +++ b/tests/components/improv_serial/test.esp32-c3.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32-idf.yaml b/tests/components/improv_serial/test.esp32-idf.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.esp32-idf.yaml +++ b/tests/components/improv_serial/test.esp32-idf.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32.yaml b/tests/components/improv_serial/test.esp32.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.esp32.yaml +++ b/tests/components/improv_serial/test.esp32.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp8266.yaml b/tests/components/improv_serial/test.esp8266.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.esp8266.yaml +++ b/tests/components/improv_serial/test.esp8266.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/improv_serial/test.rp2040.yaml b/tests/components/improv_serial/test.rp2040.yaml index b36fe5a4a7..dade44d145 100644 --- a/tests/components/improv_serial/test.rp2040.yaml +++ b/tests/components/improv_serial/test.rp2040.yaml @@ -1,5 +1 @@ -wifi: - ssid: MySSID - password: password1 - -improv_serial: +<<: !include common.yaml diff --git a/tests/components/inkbird_ibsth1_mini/common.yaml b/tests/components/inkbird_ibsth1_mini/common.yaml new file mode 100644 index 0000000000..ba46b7dbf6 --- /dev/null +++ b/tests/components/inkbird_ibsth1_mini/common.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: inkbird_ibsth1_mini + mac_address: 38:81:D7:0A:9C:11 + temperature: + name: Inkbird IBS-TH1 Temperature + humidity: + name: Inkbird IBS-TH1 Humidity + battery_level: + name: Inkbird IBS-TH1 Battery Level diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml index ba46b7dbf6..dade44d145 100644 --- a/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: inkbird_ibsth1_mini - mac_address: 38:81:D7:0A:9C:11 - temperature: - name: Inkbird IBS-TH1 Temperature - humidity: - name: Inkbird IBS-TH1 Humidity - battery_level: - name: Inkbird IBS-TH1 Battery Level +<<: !include common.yaml diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml index ba46b7dbf6..dade44d145 100644 --- a/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: inkbird_ibsth1_mini - mac_address: 38:81:D7:0A:9C:11 - temperature: - name: Inkbird IBS-TH1 Temperature - humidity: - name: Inkbird IBS-TH1 Humidity - battery_level: - name: Inkbird IBS-TH1 Battery Level +<<: !include common.yaml diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml index ba46b7dbf6..dade44d145 100644 --- a/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml +++ b/tests/components/inkbird_ibsth1_mini/test.esp32-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: inkbird_ibsth1_mini - mac_address: 38:81:D7:0A:9C:11 - temperature: - name: Inkbird IBS-TH1 Temperature - humidity: - name: Inkbird IBS-TH1 Humidity - battery_level: - name: Inkbird IBS-TH1 Battery Level +<<: !include common.yaml diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32.yaml index ba46b7dbf6..dade44d145 100644 --- a/tests/components/inkbird_ibsth1_mini/test.esp32.yaml +++ b/tests/components/inkbird_ibsth1_mini/test.esp32.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: inkbird_ibsth1_mini - mac_address: 38:81:D7:0A:9C:11 - temperature: - name: Inkbird IBS-TH1 Temperature - humidity: - name: Inkbird IBS-TH1 Humidity - battery_level: - name: Inkbird IBS-TH1 Battery Level +<<: !include common.yaml diff --git a/tests/components/inkplate6/common.yaml b/tests/components/inkplate6/common.yaml new file mode 100644 index 0000000000..31b14e6c73 --- /dev/null +++ b/tests/components/inkplate6/common.yaml @@ -0,0 +1,62 @@ +i2c: + - id: i2c_inkplate6 + scl: 16 + sda: 17 + +display: + - platform: inkplate6 + id: inkplate_display + greyscale: false + partial_updating: false + update_interval: 60s + display_data_0_pin: + number: 1 + allow_other_uses: true + display_data_1_pin: + number: 1 + allow_other_uses: true + display_data_2_pin: + number: 1 + allow_other_uses: true + display_data_3_pin: + number: 1 + allow_other_uses: true + display_data_5_pin: + number: 1 + allow_other_uses: true + display_data_4_pin: + number: 1 + allow_other_uses: true + display_data_6_pin: + number: 1 + allow_other_uses: true + display_data_7_pin: + number: 1 + allow_other_uses: true + ckv_pin: + number: 1 + allow_other_uses: true + sph_pin: + number: 1 + allow_other_uses: true + gmod_pin: + number: 1 + allow_other_uses: true + gpio0_enable_pin: + number: 1 + allow_other_uses: true + oe_pin: + number: 1 + allow_other_uses: true + spv_pin: + number: 1 + allow_other_uses: true + powerup_pin: + number: 1 + allow_other_uses: true + wakeup_pin: + number: 1 + allow_other_uses: true + vcom_pin: + number: 1 + allow_other_uses: true diff --git a/tests/components/inkplate6/test.esp32.yaml b/tests/components/inkplate6/test.esp32.yaml index 31b14e6c73..dade44d145 100644 --- a/tests/components/inkplate6/test.esp32.yaml +++ b/tests/components/inkplate6/test.esp32.yaml @@ -1,62 +1 @@ -i2c: - - id: i2c_inkplate6 - scl: 16 - sda: 17 - -display: - - platform: inkplate6 - id: inkplate_display - greyscale: false - partial_updating: false - update_interval: 60s - display_data_0_pin: - number: 1 - allow_other_uses: true - display_data_1_pin: - number: 1 - allow_other_uses: true - display_data_2_pin: - number: 1 - allow_other_uses: true - display_data_3_pin: - number: 1 - allow_other_uses: true - display_data_5_pin: - number: 1 - allow_other_uses: true - display_data_4_pin: - number: 1 - allow_other_uses: true - display_data_6_pin: - number: 1 - allow_other_uses: true - display_data_7_pin: - number: 1 - allow_other_uses: true - ckv_pin: - number: 1 - allow_other_uses: true - sph_pin: - number: 1 - allow_other_uses: true - gmod_pin: - number: 1 - allow_other_uses: true - gpio0_enable_pin: - number: 1 - allow_other_uses: true - oe_pin: - number: 1 - allow_other_uses: true - spv_pin: - number: 1 - allow_other_uses: true - powerup_pin: - number: 1 - allow_other_uses: true - wakeup_pin: - number: 1 - allow_other_uses: true - vcom_pin: - number: 1 - allow_other_uses: true +<<: !include common.yaml diff --git a/tests/components/interval/common.yaml b/tests/components/interval/common.yaml new file mode 100644 index 0000000000..2a3c979ae2 --- /dev/null +++ b/tests/components/interval/common.yaml @@ -0,0 +1,4 @@ +interval: + - interval: 1s + then: + - logger.log: Tick diff --git a/tests/components/interval/test.esp32-c3-idf.yaml b/tests/components/interval/test.esp32-c3-idf.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.esp32-c3-idf.yaml +++ b/tests/components/interval/test.esp32-c3-idf.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/interval/test.esp32-c3.yaml b/tests/components/interval/test.esp32-c3.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.esp32-c3.yaml +++ b/tests/components/interval/test.esp32-c3.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/interval/test.esp32-idf.yaml b/tests/components/interval/test.esp32-idf.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.esp32-idf.yaml +++ b/tests/components/interval/test.esp32-idf.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/interval/test.esp32.yaml b/tests/components/interval/test.esp32.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.esp32.yaml +++ b/tests/components/interval/test.esp32.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/interval/test.esp8266.yaml b/tests/components/interval/test.esp8266.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.esp8266.yaml +++ b/tests/components/interval/test.esp8266.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/interval/test.rp2040.yaml b/tests/components/interval/test.rp2040.yaml index 2a3c979ae2..dade44d145 100644 --- a/tests/components/interval/test.rp2040.yaml +++ b/tests/components/interval/test.rp2040.yaml @@ -1,4 +1 @@ -interval: - - interval: 1s - then: - - logger.log: Tick +<<: !include common.yaml diff --git a/tests/components/ledc/common.yaml b/tests/components/ledc/common.yaml new file mode 100644 index 0000000000..70352b4519 --- /dev/null +++ b/tests/components/ledc/common.yaml @@ -0,0 +1,11 @@ +esphome: + on_boot: + then: + - output.ledc.set_frequency: + id: test_ledc + frequency: 100Hz + +output: + - platform: ledc + id: test_ledc + pin: 4 diff --git a/tests/components/ledc/test.esp32-c3-idf.yaml b/tests/components/ledc/test.esp32-c3-idf.yaml index 70352b4519..dade44d145 100644 --- a/tests/components/ledc/test.esp32-c3-idf.yaml +++ b/tests/components/ledc/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esphome: - on_boot: - then: - - output.ledc.set_frequency: - id: test_ledc - frequency: 100Hz - -output: - - platform: ledc - id: test_ledc - pin: 4 +<<: !include common.yaml diff --git a/tests/components/ledc/test.esp32-c3.yaml b/tests/components/ledc/test.esp32-c3.yaml index 70352b4519..dade44d145 100644 --- a/tests/components/ledc/test.esp32-c3.yaml +++ b/tests/components/ledc/test.esp32-c3.yaml @@ -1,11 +1 @@ -esphome: - on_boot: - then: - - output.ledc.set_frequency: - id: test_ledc - frequency: 100Hz - -output: - - platform: ledc - id: test_ledc - pin: 4 +<<: !include common.yaml diff --git a/tests/components/ledc/test.esp32-idf.yaml b/tests/components/ledc/test.esp32-idf.yaml index 70352b4519..dade44d145 100644 --- a/tests/components/ledc/test.esp32-idf.yaml +++ b/tests/components/ledc/test.esp32-idf.yaml @@ -1,11 +1 @@ -esphome: - on_boot: - then: - - output.ledc.set_frequency: - id: test_ledc - frequency: 100Hz - -output: - - platform: ledc - id: test_ledc - pin: 4 +<<: !include common.yaml diff --git a/tests/components/ledc/test.esp32.yaml b/tests/components/ledc/test.esp32.yaml index 70352b4519..dade44d145 100644 --- a/tests/components/ledc/test.esp32.yaml +++ b/tests/components/ledc/test.esp32.yaml @@ -1,11 +1 @@ -esphome: - on_boot: - then: - - output.ledc.set_frequency: - id: test_ledc - frequency: 100Hz - -output: - - platform: ledc - id: test_ledc - pin: 4 +<<: !include common.yaml diff --git a/tests/components/lightwaverf/common.yaml b/tests/components/lightwaverf/common.yaml new file mode 100644 index 0000000000..7ed8000271 --- /dev/null +++ b/tests/components/lightwaverf/common.yaml @@ -0,0 +1,13 @@ +lightwaverf: + read_pin: 5 + write_pin: 4 + +button: + - platform: template + name: "Turn off sofa" + id: light_off_ceiling_sofa + on_press: + lightwaverf.send_raw: + code: [0x04, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x0d, 0x09, 0x08, 0x08] + name: "Sofa" + repeat: 1 diff --git a/tests/components/lightwaverf/test.esp8266.yaml b/tests/components/lightwaverf/test.esp8266.yaml index 7ed8000271..dade44d145 100644 --- a/tests/components/lightwaverf/test.esp8266.yaml +++ b/tests/components/lightwaverf/test.esp8266.yaml @@ -1,13 +1 @@ -lightwaverf: - read_pin: 5 - write_pin: 4 - -button: - - platform: template - name: "Turn off sofa" - id: light_off_ceiling_sofa - on_press: - lightwaverf.send_raw: - code: [0x04, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x0d, 0x09, 0x08, 0x08] - name: "Sofa" - repeat: 1 +<<: !include common.yaml diff --git a/tests/components/lock/common.yaml b/tests/components/lock/common.yaml new file mode 100644 index 0000000000..82297a3da4 --- /dev/null +++ b/tests/components/lock/common.yaml @@ -0,0 +1,36 @@ +esphome: + on_boot: + then: + - lock.lock: test_lock1 + - lock.unlock: test_lock1 + - lock.open: test_lock1 + +output: + - platform: gpio + id: test_binary + pin: 4 + +lock: + - platform: template + id: test_lock1 + name: Template Lock + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + assumed_state: false + on_unlock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_UNLOCKED;" + on_lock: + - lock.template.publish: + id: test_lock1 + state: !lambda "return LOCK_STATE_LOCKED;" + - platform: output + name: Generic Output Lock + id: test_lock2 + output: test_binary diff --git a/tests/components/lock/test.esp32-c3-idf.yaml b/tests/components/lock/test.esp32-c3-idf.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.esp32-c3-idf.yaml +++ b/tests/components/lock/test.esp32-c3-idf.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/lock/test.esp32-c3.yaml b/tests/components/lock/test.esp32-c3.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.esp32-c3.yaml +++ b/tests/components/lock/test.esp32-c3.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/lock/test.esp32-idf.yaml b/tests/components/lock/test.esp32-idf.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.esp32-idf.yaml +++ b/tests/components/lock/test.esp32-idf.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/lock/test.esp32.yaml b/tests/components/lock/test.esp32.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.esp32.yaml +++ b/tests/components/lock/test.esp32.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/lock/test.esp8266.yaml b/tests/components/lock/test.esp8266.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.esp8266.yaml +++ b/tests/components/lock/test.esp8266.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/lock/test.rp2040.yaml b/tests/components/lock/test.rp2040.yaml index 82297a3da4..dade44d145 100644 --- a/tests/components/lock/test.rp2040.yaml +++ b/tests/components/lock/test.rp2040.yaml @@ -1,36 +1 @@ -esphome: - on_boot: - then: - - lock.lock: test_lock1 - - lock.unlock: test_lock1 - - lock.open: test_lock1 - -output: - - platform: gpio - id: test_binary - pin: 4 - -lock: - - platform: template - id: test_lock1 - name: Template Lock - lambda: |- - if (millis() > 10000) { - return LOCK_STATE_LOCKED; - } else { - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: test_binary +<<: !include common.yaml diff --git a/tests/components/logger/common.yaml b/tests/components/logger/common.yaml new file mode 100644 index 0000000000..70b485daac --- /dev/null +++ b/tests/components/logger/common.yaml @@ -0,0 +1,7 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG diff --git a/tests/components/logger/test.esp32-c3-idf.yaml b/tests/components/logger/test.esp32-c3-idf.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.esp32-c3-idf.yaml +++ b/tests/components/logger/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/logger/test.esp32-c3.yaml b/tests/components/logger/test.esp32-c3.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.esp32-c3.yaml +++ b/tests/components/logger/test.esp32-c3.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/logger/test.esp32-idf.yaml b/tests/components/logger/test.esp32-idf.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.esp32-idf.yaml +++ b/tests/components/logger/test.esp32-idf.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/logger/test.esp32.yaml b/tests/components/logger/test.esp32.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.esp32.yaml +++ b/tests/components/logger/test.esp32.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/logger/test.esp8266.yaml b/tests/components/logger/test.esp8266.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.esp8266.yaml +++ b/tests/components/logger/test.esp8266.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/logger/test.rp2040.yaml b/tests/components/logger/test.rp2040.yaml index 70b485daac..dade44d145 100644 --- a/tests/components/logger/test.rp2040.yaml +++ b/tests/components/logger/test.rp2040.yaml @@ -1,7 +1 @@ -esphome: - on_boot: - then: - - logger.log: Hello world - -logger: - level: DEBUG +<<: !include common.yaml diff --git a/tests/components/mdns/common.yaml b/tests/components/mdns/common.yaml new file mode 100644 index 0000000000..bc31e32783 --- /dev/null +++ b/tests/components/mdns/common.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: false diff --git a/tests/components/mdns/test.esp32-c3-idf.yaml b/tests/components/mdns/test.esp32-c3-idf.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.esp32-c3-idf.yaml +++ b/tests/components/mdns/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32-c3.yaml b/tests/components/mdns/test.esp32-c3.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.esp32-c3.yaml +++ b/tests/components/mdns/test.esp32-c3.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32-idf.yaml b/tests/components/mdns/test.esp32-idf.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.esp32-idf.yaml +++ b/tests/components/mdns/test.esp32-idf.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32.yaml b/tests/components/mdns/test.esp32.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.esp32.yaml +++ b/tests/components/mdns/test.esp32.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/mdns/test.esp8266.yaml b/tests/components/mdns/test.esp8266.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.esp8266.yaml +++ b/tests/components/mdns/test.esp8266.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/mdns/test.rp2040.yaml b/tests/components/mdns/test.rp2040.yaml index bc31e32783..dade44d145 100644 --- a/tests/components/mdns/test.rp2040.yaml +++ b/tests/components/mdns/test.rp2040.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -mdns: - disabled: false +<<: !include common.yaml diff --git a/tests/components/media_player/common.yaml b/tests/components/media_player/common.yaml new file mode 100644 index 0000000000..24b85cd474 --- /dev/null +++ b/tests/components/media_player/common.yaml @@ -0,0 +1,32 @@ +wifi: + ssid: MySSID + password: password1 + +i2s_audio: + i2s_lrclk_pin: 13 + i2s_bclk_pin: 14 + i2s_mclk_pin: 15 + +media_player: + - platform: i2s_audio + name: None + dac_type: external + i2s_dout_pin: 18 + mute_pin: 19 + on_state: + - media_player.play: + - media_player.play_media: http://localhost/media.mp3 + - media_player.play_media: !lambda 'return "http://localhost/media.mp3";' + on_idle: + - media_player.pause: + on_play: + - media_player.stop: + on_pause: + - media_player.toggle: + - wait_until: + media_player.is_idle: + - wait_until: + media_player.is_playing: + - media_player.volume_up: + - media_player.volume_down: + - media_player.volume_set: 50% diff --git a/tests/components/media_player/test.esp32.yaml b/tests/components/media_player/test.esp32.yaml index 24b85cd474..dade44d145 100644 --- a/tests/components/media_player/test.esp32.yaml +++ b/tests/components/media_player/test.esp32.yaml @@ -1,32 +1 @@ -wifi: - ssid: MySSID - password: password1 - -i2s_audio: - i2s_lrclk_pin: 13 - i2s_bclk_pin: 14 - i2s_mclk_pin: 15 - -media_player: - - platform: i2s_audio - name: None - dac_type: external - i2s_dout_pin: 18 - mute_pin: 19 - on_state: - - media_player.play: - - media_player.play_media: http://localhost/media.mp3 - - media_player.play_media: !lambda 'return "http://localhost/media.mp3";' - on_idle: - - media_player.pause: - on_play: - - media_player.stop: - on_pause: - - media_player.toggle: - - wait_until: - media_player.is_idle: - - wait_until: - media_player.is_playing: - - media_player.volume_up: - - media_player.volume_down: - - media_player.volume_set: 50% +<<: !include common.yaml diff --git a/tests/components/micro_wake_word/common.yaml b/tests/components/micro_wake_word/common.yaml new file mode 100644 index 0000000000..c0f3593cc6 --- /dev/null +++ b/tests/components/micro_wake_word/common.yaml @@ -0,0 +1,15 @@ +i2s_audio: + i2s_lrclk_pin: GPIO18 + i2s_bclk_pin: GPIO19 + +microphone: + - platform: i2s_audio + id: echo_microphone + i2s_din_pin: GPIO17 + adc_type: external + pdm: true + +micro_wake_word: + model: hey_jarvis + on_wake_word_detected: + - logger.log: "Wake word detected" diff --git a/tests/components/micro_wake_word/test.esp32-s3-idf.yaml b/tests/components/micro_wake_word/test.esp32-s3-idf.yaml index c0f3593cc6..dade44d145 100644 --- a/tests/components/micro_wake_word/test.esp32-s3-idf.yaml +++ b/tests/components/micro_wake_word/test.esp32-s3-idf.yaml @@ -1,15 +1 @@ -i2s_audio: - i2s_lrclk_pin: GPIO18 - i2s_bclk_pin: GPIO19 - -microphone: - - platform: i2s_audio - id: echo_microphone - i2s_din_pin: GPIO17 - adc_type: external - pdm: true - -micro_wake_word: - model: hey_jarvis - on_wake_word_detected: - - logger.log: "Wake word detected" +<<: !include common.yaml diff --git a/tests/components/midea_ir/common.yaml b/tests/components/midea_ir/common.yaml new file mode 100644 index 0000000000..e8d89cecc2 --- /dev/null +++ b/tests/components/midea_ir/common.yaml @@ -0,0 +1,8 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: midea_ir + name: Midea IR + use_fahrenheit: true diff --git a/tests/components/midea_ir/test.esp32-c3-idf.yaml b/tests/components/midea_ir/test.esp32-c3-idf.yaml index e8d89cecc2..dade44d145 100644 --- a/tests/components/midea_ir/test.esp32-c3-idf.yaml +++ b/tests/components/midea_ir/test.esp32-c3-idf.yaml @@ -1,8 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: midea_ir - name: Midea IR - use_fahrenheit: true +<<: !include common.yaml diff --git a/tests/components/midea_ir/test.esp32-c3.yaml b/tests/components/midea_ir/test.esp32-c3.yaml index e8d89cecc2..dade44d145 100644 --- a/tests/components/midea_ir/test.esp32-c3.yaml +++ b/tests/components/midea_ir/test.esp32-c3.yaml @@ -1,8 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: midea_ir - name: Midea IR - use_fahrenheit: true +<<: !include common.yaml diff --git a/tests/components/midea_ir/test.esp32-idf.yaml b/tests/components/midea_ir/test.esp32-idf.yaml index e8d89cecc2..dade44d145 100644 --- a/tests/components/midea_ir/test.esp32-idf.yaml +++ b/tests/components/midea_ir/test.esp32-idf.yaml @@ -1,8 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: midea_ir - name: Midea IR - use_fahrenheit: true +<<: !include common.yaml diff --git a/tests/components/midea_ir/test.esp32.yaml b/tests/components/midea_ir/test.esp32.yaml index e8d89cecc2..dade44d145 100644 --- a/tests/components/midea_ir/test.esp32.yaml +++ b/tests/components/midea_ir/test.esp32.yaml @@ -1,8 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: midea_ir - name: Midea IR - use_fahrenheit: true +<<: !include common.yaml diff --git a/tests/components/midea_ir/test.esp8266.yaml b/tests/components/midea_ir/test.esp8266.yaml index e8d89cecc2..dade44d145 100644 --- a/tests/components/midea_ir/test.esp8266.yaml +++ b/tests/components/midea_ir/test.esp8266.yaml @@ -1,8 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: midea_ir - name: Midea IR - use_fahrenheit: true +<<: !include common.yaml diff --git a/tests/components/mitsubishi/common.yaml b/tests/components/mitsubishi/common.yaml new file mode 100644 index 0000000000..c0fc959c5b --- /dev/null +++ b/tests/components/mitsubishi/common.yaml @@ -0,0 +1,7 @@ +remote_transmitter: + pin: 4 + carrier_duty_percent: 50% + +climate: + - platform: mitsubishi + name: Mitsubishi diff --git a/tests/components/mitsubishi/test.esp32-c3-idf.yaml b/tests/components/mitsubishi/test.esp32-c3-idf.yaml index c0fc959c5b..dade44d145 100644 --- a/tests/components/mitsubishi/test.esp32-c3-idf.yaml +++ b/tests/components/mitsubishi/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: mitsubishi - name: Mitsubishi +<<: !include common.yaml diff --git a/tests/components/mitsubishi/test.esp32-c3.yaml b/tests/components/mitsubishi/test.esp32-c3.yaml index c0fc959c5b..dade44d145 100644 --- a/tests/components/mitsubishi/test.esp32-c3.yaml +++ b/tests/components/mitsubishi/test.esp32-c3.yaml @@ -1,7 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: mitsubishi - name: Mitsubishi +<<: !include common.yaml diff --git a/tests/components/mitsubishi/test.esp32-idf.yaml b/tests/components/mitsubishi/test.esp32-idf.yaml index c0fc959c5b..dade44d145 100644 --- a/tests/components/mitsubishi/test.esp32-idf.yaml +++ b/tests/components/mitsubishi/test.esp32-idf.yaml @@ -1,7 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: mitsubishi - name: Mitsubishi +<<: !include common.yaml diff --git a/tests/components/mitsubishi/test.esp32.yaml b/tests/components/mitsubishi/test.esp32.yaml index c0fc959c5b..dade44d145 100644 --- a/tests/components/mitsubishi/test.esp32.yaml +++ b/tests/components/mitsubishi/test.esp32.yaml @@ -1,7 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: mitsubishi - name: Mitsubishi +<<: !include common.yaml diff --git a/tests/components/mitsubishi/test.esp8266.yaml b/tests/components/mitsubishi/test.esp8266.yaml index c0fc959c5b..dade44d145 100644 --- a/tests/components/mitsubishi/test.esp8266.yaml +++ b/tests/components/mitsubishi/test.esp8266.yaml @@ -1,7 +1 @@ -remote_transmitter: - pin: 4 - carrier_duty_percent: 50% - -climate: - - platform: mitsubishi - name: Mitsubishi +<<: !include common.yaml diff --git a/tests/components/mopeka_ble/common.yaml b/tests/components/mopeka_ble/common.yaml new file mode 100644 index 0000000000..a115404f1c --- /dev/null +++ b/tests/components/mopeka_ble/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +mopeka_ble: diff --git a/tests/components/mopeka_ble/test.esp32-c3-idf.yaml b/tests/components/mopeka_ble/test.esp32-c3-idf.yaml index a115404f1c..dade44d145 100644 --- a/tests/components/mopeka_ble/test.esp32-c3-idf.yaml +++ b/tests/components/mopeka_ble/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -mopeka_ble: +<<: !include common.yaml diff --git a/tests/components/mopeka_ble/test.esp32-c3.yaml b/tests/components/mopeka_ble/test.esp32-c3.yaml index a115404f1c..dade44d145 100644 --- a/tests/components/mopeka_ble/test.esp32-c3.yaml +++ b/tests/components/mopeka_ble/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -mopeka_ble: +<<: !include common.yaml diff --git a/tests/components/mopeka_ble/test.esp32-idf.yaml b/tests/components/mopeka_ble/test.esp32-idf.yaml index a115404f1c..dade44d145 100644 --- a/tests/components/mopeka_ble/test.esp32-idf.yaml +++ b/tests/components/mopeka_ble/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -mopeka_ble: +<<: !include common.yaml diff --git a/tests/components/mopeka_ble/test.esp32.yaml b/tests/components/mopeka_ble/test.esp32.yaml index a115404f1c..dade44d145 100644 --- a/tests/components/mopeka_ble/test.esp32.yaml +++ b/tests/components/mopeka_ble/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -mopeka_ble: +<<: !include common.yaml diff --git a/tests/components/mopeka_pro_check/common.yaml b/tests/components/mopeka_pro_check/common.yaml new file mode 100644 index 0000000000..147cbcb9de --- /dev/null +++ b/tests/components/mopeka_pro_check/common.yaml @@ -0,0 +1,16 @@ +esp32_ble_tracker: + +sensor: + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: Propane test temp + level: + name: Propane test level + distance: + name: Propane test distance + battery_level: + name: Propane test battery level diff --git a/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml b/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml index 147cbcb9de..dade44d145 100644 --- a/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml +++ b/tests/components/mopeka_pro_check/test.esp32-c3-idf.yaml @@ -1,16 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level +<<: !include common.yaml diff --git a/tests/components/mopeka_pro_check/test.esp32-c3.yaml b/tests/components/mopeka_pro_check/test.esp32-c3.yaml index 147cbcb9de..dade44d145 100644 --- a/tests/components/mopeka_pro_check/test.esp32-c3.yaml +++ b/tests/components/mopeka_pro_check/test.esp32-c3.yaml @@ -1,16 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level +<<: !include common.yaml diff --git a/tests/components/mopeka_pro_check/test.esp32-idf.yaml b/tests/components/mopeka_pro_check/test.esp32-idf.yaml index 147cbcb9de..dade44d145 100644 --- a/tests/components/mopeka_pro_check/test.esp32-idf.yaml +++ b/tests/components/mopeka_pro_check/test.esp32-idf.yaml @@ -1,16 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level +<<: !include common.yaml diff --git a/tests/components/mopeka_pro_check/test.esp32.yaml b/tests/components/mopeka_pro_check/test.esp32.yaml index 147cbcb9de..dade44d145 100644 --- a/tests/components/mopeka_pro_check/test.esp32.yaml +++ b/tests/components/mopeka_pro_check/test.esp32.yaml @@ -1,16 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level +<<: !include common.yaml diff --git a/tests/components/mopeka_std_check/common.yaml b/tests/components/mopeka_std_check/common.yaml new file mode 100644 index 0000000000..383e2e2a19 --- /dev/null +++ b/tests/components/mopeka_std_check/common.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + # Example using 11kg 100% propane tank. + - platform: mopeka_std_check + mac_address: D3:75:F2:DC:16:91 + tank_type: Europe_11kg + temperature: + name: "Propane test temp" + level: + name: "Propane test level" + distance: + name: "Propane test distance" + battery_level: + name: "Propane test battery level" diff --git a/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml index 383e2e2a19..dade44d145 100644 --- a/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml +++ b/tests/components/mopeka_std_check/test.esp32-c3-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - # Example using 11kg 100% propane tank. - - platform: mopeka_std_check - mac_address: D3:75:F2:DC:16:91 - tank_type: Europe_11kg - temperature: - name: "Propane test temp" - level: - name: "Propane test level" - distance: - name: "Propane test distance" - battery_level: - name: "Propane test battery level" +<<: !include common.yaml diff --git a/tests/components/mopeka_std_check/test.esp32-c3.yaml b/tests/components/mopeka_std_check/test.esp32-c3.yaml index 383e2e2a19..dade44d145 100644 --- a/tests/components/mopeka_std_check/test.esp32-c3.yaml +++ b/tests/components/mopeka_std_check/test.esp32-c3.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - # Example using 11kg 100% propane tank. - - platform: mopeka_std_check - mac_address: D3:75:F2:DC:16:91 - tank_type: Europe_11kg - temperature: - name: "Propane test temp" - level: - name: "Propane test level" - distance: - name: "Propane test distance" - battery_level: - name: "Propane test battery level" +<<: !include common.yaml diff --git a/tests/components/mopeka_std_check/test.esp32-idf.yaml b/tests/components/mopeka_std_check/test.esp32-idf.yaml index 383e2e2a19..dade44d145 100644 --- a/tests/components/mopeka_std_check/test.esp32-idf.yaml +++ b/tests/components/mopeka_std_check/test.esp32-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - # Example using 11kg 100% propane tank. - - platform: mopeka_std_check - mac_address: D3:75:F2:DC:16:91 - tank_type: Europe_11kg - temperature: - name: "Propane test temp" - level: - name: "Propane test level" - distance: - name: "Propane test distance" - battery_level: - name: "Propane test battery level" +<<: !include common.yaml diff --git a/tests/components/mopeka_std_check/test.esp32.yaml b/tests/components/mopeka_std_check/test.esp32.yaml index 383e2e2a19..dade44d145 100644 --- a/tests/components/mopeka_std_check/test.esp32.yaml +++ b/tests/components/mopeka_std_check/test.esp32.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - # Example using 11kg 100% propane tank. - - platform: mopeka_std_check - mac_address: D3:75:F2:DC:16:91 - tank_type: Europe_11kg - temperature: - name: "Propane test temp" - level: - name: "Propane test level" - distance: - name: "Propane test distance" - battery_level: - name: "Propane test battery level" +<<: !include common.yaml diff --git a/tests/components/my9231/common.yaml b/tests/components/my9231/common.yaml new file mode 100644 index 0000000000..3f2e81ef98 --- /dev/null +++ b/tests/components/my9231/common.yaml @@ -0,0 +1,26 @@ +my9231: + clock_pin: 5 + data_pin: 4 + num_channels: 6 + num_chips: 2 + bit_depth: 16 + +output: + - platform: my9231 + id: my_0 + channel: 0 + - platform: my9231 + id: my_1 + channel: 1 + - platform: my9231 + id: my_2 + channel: 2 + - platform: my9231 + id: my_3 + channel: 3 + - platform: my9231 + id: my_4 + channel: 4 + - platform: my9231 + id: my_5 + channel: 5 diff --git a/tests/components/my9231/test.esp32-c3-idf.yaml b/tests/components/my9231/test.esp32-c3-idf.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.esp32-c3-idf.yaml +++ b/tests/components/my9231/test.esp32-c3-idf.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/my9231/test.esp32-c3.yaml b/tests/components/my9231/test.esp32-c3.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.esp32-c3.yaml +++ b/tests/components/my9231/test.esp32-c3.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/my9231/test.esp32-idf.yaml b/tests/components/my9231/test.esp32-idf.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.esp32-idf.yaml +++ b/tests/components/my9231/test.esp32-idf.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/my9231/test.esp32.yaml b/tests/components/my9231/test.esp32.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.esp32.yaml +++ b/tests/components/my9231/test.esp32.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/my9231/test.esp8266.yaml b/tests/components/my9231/test.esp8266.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.esp8266.yaml +++ b/tests/components/my9231/test.esp8266.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/my9231/test.rp2040.yaml b/tests/components/my9231/test.rp2040.yaml index 3f2e81ef98..dade44d145 100644 --- a/tests/components/my9231/test.rp2040.yaml +++ b/tests/components/my9231/test.rp2040.yaml @@ -1,26 +1 @@ -my9231: - clock_pin: 5 - data_pin: 4 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -output: - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 +<<: !include common.yaml diff --git a/tests/components/network/common.yaml b/tests/components/network/common.yaml new file mode 100644 index 0000000000..147afd1e81 --- /dev/null +++ b/tests/components/network/common.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +network: + enable_ipv6: true diff --git a/tests/components/network/test.esp32-c3-idf.yaml b/tests/components/network/test.esp32-c3-idf.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.esp32-c3-idf.yaml +++ b/tests/components/network/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/network/test.esp32-c3.yaml b/tests/components/network/test.esp32-c3.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.esp32-c3.yaml +++ b/tests/components/network/test.esp32-c3.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/network/test.esp32-idf.yaml b/tests/components/network/test.esp32-idf.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.esp32-idf.yaml +++ b/tests/components/network/test.esp32-idf.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/network/test.esp32.yaml b/tests/components/network/test.esp32.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.esp32.yaml +++ b/tests/components/network/test.esp32.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/network/test.esp8266.yaml b/tests/components/network/test.esp8266.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.esp8266.yaml +++ b/tests/components/network/test.esp8266.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/network/test.rp2040.yaml b/tests/components/network/test.rp2040.yaml index 147afd1e81..dade44d145 100644 --- a/tests/components/network/test.rp2040.yaml +++ b/tests/components/network/test.rp2040.yaml @@ -1,6 +1 @@ -wifi: - ssid: MySSID - password: password1 - -network: - enable_ipv6: true +<<: !include common.yaml diff --git a/tests/components/noblex/common.yaml b/tests/components/noblex/common.yaml new file mode 100644 index 0000000000..f5e471a9a7 --- /dev/null +++ b/tests/components/noblex/common.yaml @@ -0,0 +1,20 @@ +remote_receiver: + id: rcvr + pin: 4 + dump: all + +remote_transmitter: + pin: 2 + carrier_duty_percent: 50% + +sensor: + - platform: template + id: noblex_ac_sensor + lambda: "return 21;" + +climate: + - platform: noblex + name: AC Living + id: noblex_ac + sensor: noblex_ac_sensor + receiver_id: rcvr diff --git a/tests/components/noblex/test.esp32-c3-idf.yaml b/tests/components/noblex/test.esp32-c3-idf.yaml index f5e471a9a7..dade44d145 100644 --- a/tests/components/noblex/test.esp32-c3-idf.yaml +++ b/tests/components/noblex/test.esp32-c3-idf.yaml @@ -1,20 +1 @@ -remote_receiver: - id: rcvr - pin: 4 - dump: all - -remote_transmitter: - pin: 2 - carrier_duty_percent: 50% - -sensor: - - platform: template - id: noblex_ac_sensor - lambda: "return 21;" - -climate: - - platform: noblex - name: AC Living - id: noblex_ac - sensor: noblex_ac_sensor - receiver_id: rcvr +<<: !include common.yaml diff --git a/tests/components/noblex/test.esp32-c3.yaml b/tests/components/noblex/test.esp32-c3.yaml index f5e471a9a7..dade44d145 100644 --- a/tests/components/noblex/test.esp32-c3.yaml +++ b/tests/components/noblex/test.esp32-c3.yaml @@ -1,20 +1 @@ -remote_receiver: - id: rcvr - pin: 4 - dump: all - -remote_transmitter: - pin: 2 - carrier_duty_percent: 50% - -sensor: - - platform: template - id: noblex_ac_sensor - lambda: "return 21;" - -climate: - - platform: noblex - name: AC Living - id: noblex_ac - sensor: noblex_ac_sensor - receiver_id: rcvr +<<: !include common.yaml diff --git a/tests/components/noblex/test.esp32-idf.yaml b/tests/components/noblex/test.esp32-idf.yaml index f5e471a9a7..dade44d145 100644 --- a/tests/components/noblex/test.esp32-idf.yaml +++ b/tests/components/noblex/test.esp32-idf.yaml @@ -1,20 +1 @@ -remote_receiver: - id: rcvr - pin: 4 - dump: all - -remote_transmitter: - pin: 2 - carrier_duty_percent: 50% - -sensor: - - platform: template - id: noblex_ac_sensor - lambda: "return 21;" - -climate: - - platform: noblex - name: AC Living - id: noblex_ac - sensor: noblex_ac_sensor - receiver_id: rcvr +<<: !include common.yaml diff --git a/tests/components/noblex/test.esp32.yaml b/tests/components/noblex/test.esp32.yaml index f5e471a9a7..dade44d145 100644 --- a/tests/components/noblex/test.esp32.yaml +++ b/tests/components/noblex/test.esp32.yaml @@ -1,20 +1 @@ -remote_receiver: - id: rcvr - pin: 4 - dump: all - -remote_transmitter: - pin: 2 - carrier_duty_percent: 50% - -sensor: - - platform: template - id: noblex_ac_sensor - lambda: "return 21;" - -climate: - - platform: noblex - name: AC Living - id: noblex_ac - sensor: noblex_ac_sensor - receiver_id: rcvr +<<: !include common.yaml diff --git a/tests/components/noblex/test.esp8266.yaml b/tests/components/noblex/test.esp8266.yaml index f5e471a9a7..dade44d145 100644 --- a/tests/components/noblex/test.esp8266.yaml +++ b/tests/components/noblex/test.esp8266.yaml @@ -1,20 +1 @@ -remote_receiver: - id: rcvr - pin: 4 - dump: all - -remote_transmitter: - pin: 2 - carrier_duty_percent: 50% - -sensor: - - platform: template - id: noblex_ac_sensor - lambda: "return 21;" - -climate: - - platform: noblex - name: AC Living - id: noblex_ac - sensor: noblex_ac_sensor - receiver_id: rcvr +<<: !include common.yaml diff --git a/tests/components/ota/common.yaml b/tests/components/ota/common.yaml new file mode 100644 index 0000000000..367454995f --- /dev/null +++ b/tests/components/ota/common.yaml @@ -0,0 +1,30 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/ota/test.esp32-c3-idf.yaml b/tests/components/ota/test.esp32-c3-idf.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.esp32-c3-idf.yaml +++ b/tests/components/ota/test.esp32-c3-idf.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/ota/test.esp32-c3.yaml b/tests/components/ota/test.esp32-c3.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.esp32-c3.yaml +++ b/tests/components/ota/test.esp32-c3.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/ota/test.esp32-idf.yaml b/tests/components/ota/test.esp32-idf.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.esp32-idf.yaml +++ b/tests/components/ota/test.esp32-idf.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/ota/test.esp32.yaml b/tests/components/ota/test.esp32.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.esp32.yaml +++ b/tests/components/ota/test.esp32.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/ota/test.esp8266.yaml b/tests/components/ota/test.esp8266.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.esp8266.yaml +++ b/tests/components/ota/test.esp8266.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/ota/test.rp2040.yaml b/tests/components/ota/test.rp2040.yaml index 367454995f..dade44d145 100644 --- a/tests/components/ota/test.rp2040.yaml +++ b/tests/components/ota/test.rp2040.yaml @@ -1,30 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); +<<: !include common.yaml diff --git a/tests/components/pid/common.yaml b/tests/components/pid/common.yaml new file mode 100644 index 0000000000..5f7762872f --- /dev/null +++ b/tests/components/pid/common.yaml @@ -0,0 +1,56 @@ +esphome: + on_boot: + then: + - climate.pid.autotune: pid_climate + - climate.pid.autotune: + id: pid_climate + noiseband: 0.25 + positive_output: 25% + negative_output: -25% + - climate.pid.set_control_parameters: + id: pid_climate + kp: 0.0 + ki: 0.0 + kd: 0.0 + - climate.pid.reset_integral_term: pid_climate + +output: + - platform: slow_pwm + pin: 4 + id: pid_slow_pwm + period: 15s + restart_cycle_on_state_change: false + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +climate: + - platform: pid + id: pid_climate + name: PID Climate Controller + sensor: template_sensor1 + humidity_sensor: template_sensor1 + default_target_temperature: 21°C + heat_output: pid_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + max_integral: 0.0 + output_averaging_samples: 1 + derivative_averaging_samples: 1 + deadband_parameters: + threshold_high: 0.4 + threshold_low: -2.0 + kp_multiplier: 0.0 + ki_multiplier: 0.0 + kd_multiplier: 0.0 + deadband_output_averaging_samples: 1 diff --git a/tests/components/pid/test.esp32-c3-idf.yaml b/tests/components/pid/test.esp32-c3-idf.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.esp32-c3-idf.yaml +++ b/tests/components/pid/test.esp32-c3-idf.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/pid/test.esp32-c3.yaml b/tests/components/pid/test.esp32-c3.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.esp32-c3.yaml +++ b/tests/components/pid/test.esp32-c3.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/pid/test.esp32-idf.yaml b/tests/components/pid/test.esp32-idf.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.esp32-idf.yaml +++ b/tests/components/pid/test.esp32-idf.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/pid/test.esp32.yaml b/tests/components/pid/test.esp32.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.esp32.yaml +++ b/tests/components/pid/test.esp32.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/pid/test.esp8266.yaml b/tests/components/pid/test.esp8266.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.esp8266.yaml +++ b/tests/components/pid/test.esp8266.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/pid/test.rp2040.yaml b/tests/components/pid/test.rp2040.yaml index 5f7762872f..dade44d145 100644 --- a/tests/components/pid/test.rp2040.yaml +++ b/tests/components/pid/test.rp2040.yaml @@ -1,56 +1 @@ -esphome: - on_boot: - then: - - climate.pid.autotune: pid_climate - - climate.pid.autotune: - id: pid_climate - noiseband: 0.25 - positive_output: 25% - negative_output: -25% - - climate.pid.set_control_parameters: - id: pid_climate - kp: 0.0 - ki: 0.0 - kd: 0.0 - - climate.pid.reset_integral_term: pid_climate - -output: - - platform: slow_pwm - pin: 4 - id: pid_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -climate: - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: template_sensor1 - humidity_sensor: template_sensor1 - default_target_temperature: 21°C - heat_output: pid_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 +<<: !include common.yaml diff --git a/tests/components/power_supply/common.yaml b/tests/components/power_supply/common.yaml new file mode 100644 index 0000000000..3fefc4d425 --- /dev/null +++ b/tests/components/power_supply/common.yaml @@ -0,0 +1,6 @@ +power_supply: + - id: atx_power_supply + enable_time: 20ms + keep_on_time: 10s + enable_on_boot: true + pin: 4 diff --git a/tests/components/power_supply/test.esp32-c3-idf.yaml b/tests/components/power_supply/test.esp32-c3-idf.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.esp32-c3-idf.yaml +++ b/tests/components/power_supply/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/power_supply/test.esp32-c3.yaml b/tests/components/power_supply/test.esp32-c3.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.esp32-c3.yaml +++ b/tests/components/power_supply/test.esp32-c3.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/power_supply/test.esp32-idf.yaml b/tests/components/power_supply/test.esp32-idf.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.esp32-idf.yaml +++ b/tests/components/power_supply/test.esp32-idf.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/power_supply/test.esp32.yaml b/tests/components/power_supply/test.esp32.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.esp32.yaml +++ b/tests/components/power_supply/test.esp32.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/power_supply/test.esp8266.yaml b/tests/components/power_supply/test.esp8266.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.esp8266.yaml +++ b/tests/components/power_supply/test.esp8266.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/power_supply/test.rp2040.yaml b/tests/components/power_supply/test.rp2040.yaml index 3fefc4d425..dade44d145 100644 --- a/tests/components/power_supply/test.rp2040.yaml +++ b/tests/components/power_supply/test.rp2040.yaml @@ -1,6 +1 @@ -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: 4 +<<: !include common.yaml diff --git a/tests/components/prometheus/common.yaml b/tests/components/prometheus/common.yaml new file mode 100644 index 0000000000..c8ce17da88 --- /dev/null +++ b/tests/components/prometheus/common.yaml @@ -0,0 +1,21 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: template + id: template_sensor1 + lambda: |- + if (millis() > 10000) { + return 42.0; + } else { + return 0.0; + } + update_interval: 60s + +prometheus: + include_internal: true + relabel: + template_sensor1: + id: hellow_world + name: Hello World diff --git a/tests/components/prometheus/test.esp32-c3-idf.yaml b/tests/components/prometheus/test.esp32-c3-idf.yaml index c8ce17da88..dade44d145 100644 --- a/tests/components/prometheus/test.esp32-c3-idf.yaml +++ b/tests/components/prometheus/test.esp32-c3-idf.yaml @@ -1,21 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -prometheus: - include_internal: true - relabel: - template_sensor1: - id: hellow_world - name: Hello World +<<: !include common.yaml diff --git a/tests/components/prometheus/test.esp32-c3.yaml b/tests/components/prometheus/test.esp32-c3.yaml index c8ce17da88..dade44d145 100644 --- a/tests/components/prometheus/test.esp32-c3.yaml +++ b/tests/components/prometheus/test.esp32-c3.yaml @@ -1,21 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -prometheus: - include_internal: true - relabel: - template_sensor1: - id: hellow_world - name: Hello World +<<: !include common.yaml diff --git a/tests/components/prometheus/test.esp32-idf.yaml b/tests/components/prometheus/test.esp32-idf.yaml index c8ce17da88..dade44d145 100644 --- a/tests/components/prometheus/test.esp32-idf.yaml +++ b/tests/components/prometheus/test.esp32-idf.yaml @@ -1,21 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -prometheus: - include_internal: true - relabel: - template_sensor1: - id: hellow_world - name: Hello World +<<: !include common.yaml diff --git a/tests/components/prometheus/test.esp32.yaml b/tests/components/prometheus/test.esp32.yaml index c8ce17da88..dade44d145 100644 --- a/tests/components/prometheus/test.esp32.yaml +++ b/tests/components/prometheus/test.esp32.yaml @@ -1,21 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -prometheus: - include_internal: true - relabel: - template_sensor1: - id: hellow_world - name: Hello World +<<: !include common.yaml diff --git a/tests/components/prometheus/test.esp8266.yaml b/tests/components/prometheus/test.esp8266.yaml index c8ce17da88..dade44d145 100644 --- a/tests/components/prometheus/test.esp8266.yaml +++ b/tests/components/prometheus/test.esp8266.yaml @@ -1,21 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: template - id: template_sensor1 - lambda: |- - if (millis() > 10000) { - return 42.0; - } else { - return 0.0; - } - update_interval: 60s - -prometheus: - include_internal: true - relabel: - template_sensor1: - id: hellow_world - name: Hello World +<<: !include common.yaml diff --git a/tests/components/psram/common.yaml b/tests/components/psram/common.yaml new file mode 100644 index 0000000000..cfd39f77fe --- /dev/null +++ b/tests/components/psram/common.yaml @@ -0,0 +1,3 @@ +psram: + mode: octal + speed: 80MHz diff --git a/tests/components/psram/test.esp32-c3-idf.yaml b/tests/components/psram/test.esp32-c3-idf.yaml index cfd39f77fe..dade44d145 100644 --- a/tests/components/psram/test.esp32-c3-idf.yaml +++ b/tests/components/psram/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -psram: - mode: octal - speed: 80MHz +<<: !include common.yaml diff --git a/tests/components/psram/test.esp32-c3.yaml b/tests/components/psram/test.esp32-c3.yaml index cfd39f77fe..dade44d145 100644 --- a/tests/components/psram/test.esp32-c3.yaml +++ b/tests/components/psram/test.esp32-c3.yaml @@ -1,3 +1 @@ -psram: - mode: octal - speed: 80MHz +<<: !include common.yaml diff --git a/tests/components/psram/test.esp32-idf.yaml b/tests/components/psram/test.esp32-idf.yaml index cfd39f77fe..dade44d145 100644 --- a/tests/components/psram/test.esp32-idf.yaml +++ b/tests/components/psram/test.esp32-idf.yaml @@ -1,3 +1 @@ -psram: - mode: octal - speed: 80MHz +<<: !include common.yaml diff --git a/tests/components/psram/test.esp32.yaml b/tests/components/psram/test.esp32.yaml index cfd39f77fe..dade44d145 100644 --- a/tests/components/psram/test.esp32.yaml +++ b/tests/components/psram/test.esp32.yaml @@ -1,3 +1 @@ -psram: - mode: octal - speed: 80MHz +<<: !include common.yaml diff --git a/tests/components/pulse_counter/common.yaml b/tests/components/pulse_counter/common.yaml new file mode 100644 index 0000000000..556b43ee6f --- /dev/null +++ b/tests/components/pulse_counter/common.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: pulse_counter + name: Pulse Counter + pin: 4 + count_mode: + rising_edge: INCREMENT + falling_edge: DECREMENT + internal_filter: 13us + update_interval: 15s diff --git a/tests/components/pulse_counter/test.esp32-c3-idf.yaml b/tests/components/pulse_counter/test.esp32-c3-idf.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.esp32-c3-idf.yaml +++ b/tests/components/pulse_counter/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_counter/test.esp32-c3.yaml b/tests/components/pulse_counter/test.esp32-c3.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.esp32-c3.yaml +++ b/tests/components/pulse_counter/test.esp32-c3.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_counter/test.esp32-idf.yaml b/tests/components/pulse_counter/test.esp32-idf.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.esp32-idf.yaml +++ b/tests/components/pulse_counter/test.esp32-idf.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_counter/test.esp32.yaml b/tests/components/pulse_counter/test.esp32.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.esp32.yaml +++ b/tests/components/pulse_counter/test.esp32.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_counter/test.esp8266.yaml b/tests/components/pulse_counter/test.esp8266.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.esp8266.yaml +++ b/tests/components/pulse_counter/test.esp8266.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_counter/test.rp2040.yaml b/tests/components/pulse_counter/test.rp2040.yaml index 556b43ee6f..dade44d145 100644 --- a/tests/components/pulse_counter/test.rp2040.yaml +++ b/tests/components/pulse_counter/test.rp2040.yaml @@ -1,9 +1 @@ -sensor: - - platform: pulse_counter - name: Pulse Counter - pin: 4 - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/pulse_meter/common.yaml b/tests/components/pulse_meter/common.yaml new file mode 100644 index 0000000000..a83ec478bb --- /dev/null +++ b/tests/components/pulse_meter/common.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: pulse_meter + id: pulse_meter_sensor + name: Pulse Meter + pin: 4 + internal_filter: 100ms + timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 + total: + name: Pulse Meter Total diff --git a/tests/components/pulse_meter/test.esp32-c3-idf.yaml b/tests/components/pulse_meter/test.esp32-c3-idf.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.esp32-c3-idf.yaml +++ b/tests/components/pulse_meter/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_meter/test.esp32-c3.yaml b/tests/components/pulse_meter/test.esp32-c3.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.esp32-c3.yaml +++ b/tests/components/pulse_meter/test.esp32-c3.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_meter/test.esp32-idf.yaml b/tests/components/pulse_meter/test.esp32-idf.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.esp32-idf.yaml +++ b/tests/components/pulse_meter/test.esp32-idf.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_meter/test.esp32.yaml b/tests/components/pulse_meter/test.esp32.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.esp32.yaml +++ b/tests/components/pulse_meter/test.esp32.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_meter/test.esp8266.yaml b/tests/components/pulse_meter/test.esp8266.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.esp8266.yaml +++ b/tests/components/pulse_meter/test.esp8266.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_meter/test.rp2040.yaml b/tests/components/pulse_meter/test.rp2040.yaml index a83ec478bb..dade44d145 100644 --- a/tests/components/pulse_meter/test.rp2040.yaml +++ b/tests/components/pulse_meter/test.rp2040.yaml @@ -1,13 +1 @@ -sensor: - - platform: pulse_meter - id: pulse_meter_sensor - name: Pulse Meter - pin: 4 - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total +<<: !include common.yaml diff --git a/tests/components/pulse_width/common.yaml b/tests/components/pulse_width/common.yaml new file mode 100644 index 0000000000..fbda7cda28 --- /dev/null +++ b/tests/components/pulse_width/common.yaml @@ -0,0 +1,4 @@ +sensor: + - platform: pulse_width + name: Pulse Width + pin: 4 diff --git a/tests/components/pulse_width/test.esp32-c3-idf.yaml b/tests/components/pulse_width/test.esp32-c3-idf.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.esp32-c3-idf.yaml +++ b/tests/components/pulse_width/test.esp32-c3-idf.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pulse_width/test.esp32-c3.yaml b/tests/components/pulse_width/test.esp32-c3.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.esp32-c3.yaml +++ b/tests/components/pulse_width/test.esp32-c3.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pulse_width/test.esp32-idf.yaml b/tests/components/pulse_width/test.esp32-idf.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.esp32-idf.yaml +++ b/tests/components/pulse_width/test.esp32-idf.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pulse_width/test.esp32.yaml b/tests/components/pulse_width/test.esp32.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.esp32.yaml +++ b/tests/components/pulse_width/test.esp32.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pulse_width/test.esp8266.yaml b/tests/components/pulse_width/test.esp8266.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.esp8266.yaml +++ b/tests/components/pulse_width/test.esp8266.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pulse_width/test.rp2040.yaml b/tests/components/pulse_width/test.rp2040.yaml index fbda7cda28..dade44d145 100644 --- a/tests/components/pulse_width/test.rp2040.yaml +++ b/tests/components/pulse_width/test.rp2040.yaml @@ -1,4 +1 @@ -sensor: - - platform: pulse_width - name: Pulse Width - pin: 4 +<<: !include common.yaml diff --git a/tests/components/pvvx_mithermometer/common.yaml b/tests/components/pvvx_mithermometer/common.yaml new file mode 100644 index 0000000000..972f23122c --- /dev/null +++ b/tests/components/pvvx_mithermometer/common.yaml @@ -0,0 +1,44 @@ +wifi: + ssid: MySSID + password: password1 + +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: pvvx_ble_display + +display: + - platform: pvvx_mithermometer + ble_client_id: pvvx_ble_display + time_id: sntp_time + disconnect_delay: 3s + update_interval: 10min + validity_period: 20min + lambda: |- + it.print_bignum(188.8); + it.print_unit(pvvx_mithermometer::UNIT_DEG_E); + it.print_smallnum(88); + it.print_percent(true); + it.print_happy(true); + it.print_sad(true); + it.print_bracket(true); + it.print_battery(true); + +sensor: + - platform: pvvx_mithermometer + mac_address: A4:C1:38:4E:16:78 + temperature: + name: PVVX Temperature + humidity: + name: PVVX Humidity + battery_level: + name: PVVX Battery-Level + battery_voltage: + name: PVVX Battery-Voltage + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org diff --git a/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml b/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml index 972f23122c..dade44d145 100644 --- a/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml +++ b/tests/components/pvvx_mithermometer/test.esp32-c3-idf.yaml @@ -1,44 +1 @@ -wifi: - ssid: MySSID - password: password1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: pvvx_ble_display - -display: - - platform: pvvx_mithermometer - ble_client_id: pvvx_ble_display - time_id: sntp_time - disconnect_delay: 3s - update_interval: 10min - validity_period: 20min - lambda: |- - it.print_bignum(188.8); - it.print_unit(pvvx_mithermometer::UNIT_DEG_E); - it.print_smallnum(88); - it.print_percent(true); - it.print_happy(true); - it.print_sad(true); - it.print_bracket(true); - it.print_battery(true); - -sensor: - - platform: pvvx_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: PVVX Temperature - humidity: - name: PVVX Humidity - battery_level: - name: PVVX Battery-Level - battery_voltage: - name: PVVX Battery-Voltage - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org +<<: !include common.yaml diff --git a/tests/components/pvvx_mithermometer/test.esp32-c3.yaml b/tests/components/pvvx_mithermometer/test.esp32-c3.yaml index 972f23122c..dade44d145 100644 --- a/tests/components/pvvx_mithermometer/test.esp32-c3.yaml +++ b/tests/components/pvvx_mithermometer/test.esp32-c3.yaml @@ -1,44 +1 @@ -wifi: - ssid: MySSID - password: password1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: pvvx_ble_display - -display: - - platform: pvvx_mithermometer - ble_client_id: pvvx_ble_display - time_id: sntp_time - disconnect_delay: 3s - update_interval: 10min - validity_period: 20min - lambda: |- - it.print_bignum(188.8); - it.print_unit(pvvx_mithermometer::UNIT_DEG_E); - it.print_smallnum(88); - it.print_percent(true); - it.print_happy(true); - it.print_sad(true); - it.print_bracket(true); - it.print_battery(true); - -sensor: - - platform: pvvx_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: PVVX Temperature - humidity: - name: PVVX Humidity - battery_level: - name: PVVX Battery-Level - battery_voltage: - name: PVVX Battery-Voltage - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org +<<: !include common.yaml diff --git a/tests/components/pvvx_mithermometer/test.esp32-idf.yaml b/tests/components/pvvx_mithermometer/test.esp32-idf.yaml index 972f23122c..dade44d145 100644 --- a/tests/components/pvvx_mithermometer/test.esp32-idf.yaml +++ b/tests/components/pvvx_mithermometer/test.esp32-idf.yaml @@ -1,44 +1 @@ -wifi: - ssid: MySSID - password: password1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: pvvx_ble_display - -display: - - platform: pvvx_mithermometer - ble_client_id: pvvx_ble_display - time_id: sntp_time - disconnect_delay: 3s - update_interval: 10min - validity_period: 20min - lambda: |- - it.print_bignum(188.8); - it.print_unit(pvvx_mithermometer::UNIT_DEG_E); - it.print_smallnum(88); - it.print_percent(true); - it.print_happy(true); - it.print_sad(true); - it.print_bracket(true); - it.print_battery(true); - -sensor: - - platform: pvvx_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: PVVX Temperature - humidity: - name: PVVX Humidity - battery_level: - name: PVVX Battery-Level - battery_voltage: - name: PVVX Battery-Voltage - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org +<<: !include common.yaml diff --git a/tests/components/pvvx_mithermometer/test.esp32.yaml b/tests/components/pvvx_mithermometer/test.esp32.yaml index 972f23122c..dade44d145 100644 --- a/tests/components/pvvx_mithermometer/test.esp32.yaml +++ b/tests/components/pvvx_mithermometer/test.esp32.yaml @@ -1,44 +1 @@ -wifi: - ssid: MySSID - password: password1 - -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: pvvx_ble_display - -display: - - platform: pvvx_mithermometer - ble_client_id: pvvx_ble_display - time_id: sntp_time - disconnect_delay: 3s - update_interval: 10min - validity_period: 20min - lambda: |- - it.print_bignum(188.8); - it.print_unit(pvvx_mithermometer::UNIT_DEG_E); - it.print_smallnum(88); - it.print_percent(true); - it.print_happy(true); - it.print_sad(true); - it.print_bracket(true); - it.print_battery(true); - -sensor: - - platform: pvvx_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: PVVX Temperature - humidity: - name: PVVX Humidity - battery_level: - name: PVVX Battery-Level - battery_voltage: - name: PVVX Battery-Voltage - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org +<<: !include common.yaml diff --git a/tests/components/qspi_amoled/common.yaml b/tests/components/qspi_amoled/common.yaml new file mode 100644 index 0000000000..01d1a63bcb --- /dev/null +++ b/tests/components/qspi_amoled/common.yaml @@ -0,0 +1,36 @@ +spi: + id: quad_spi + clk_pin: 15 + type: quad + data_pins: [14, 10, 16, 12] + +display: + - platform: qspi_amoled + model: RM690B0 + data_rate: 80MHz + spi_mode: mode0 + dimensions: + width: 450 + height: 600 + offset_width: 16 + color_order: rgb + invert_colors: false + brightness: 255 + cs_pin: 11 + reset_pin: 13 + enable_pin: 9 + + - platform: qspi_amoled + model: RM67162 + id: main_lcd + dimensions: + height: 240 + width: 536 + transform: + mirror_x: true + swap_xy: true + color_order: rgb + brightness: 255 + cs_pin: 6 + reset_pin: 17 + enable_pin: 38 diff --git a/tests/components/qspi_amoled/test.esp32-s3-idf.yaml b/tests/components/qspi_amoled/test.esp32-s3-idf.yaml index 01d1a63bcb..dade44d145 100644 --- a/tests/components/qspi_amoled/test.esp32-s3-idf.yaml +++ b/tests/components/qspi_amoled/test.esp32-s3-idf.yaml @@ -1,36 +1 @@ -spi: - id: quad_spi - clk_pin: 15 - type: quad - data_pins: [14, 10, 16, 12] - -display: - - platform: qspi_amoled - model: RM690B0 - data_rate: 80MHz - spi_mode: mode0 - dimensions: - width: 450 - height: 600 - offset_width: 16 - color_order: rgb - invert_colors: false - brightness: 255 - cs_pin: 11 - reset_pin: 13 - enable_pin: 9 - - - platform: qspi_amoled - model: RM67162 - id: main_lcd - dimensions: - height: 240 - width: 536 - transform: - mirror_x: true - swap_xy: true - color_order: rgb - brightness: 255 - cs_pin: 6 - reset_pin: 17 - enable_pin: 38 +<<: !include common.yaml diff --git a/tests/components/radon_eye_ble/common.yaml b/tests/components/radon_eye_ble/common.yaml new file mode 100644 index 0000000000..85638d5c0e --- /dev/null +++ b/tests/components/radon_eye_ble/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +radon_eye_ble: diff --git a/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml b/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml index 85638d5c0e..dade44d145 100644 --- a/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml +++ b/tests/components/radon_eye_ble/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -radon_eye_ble: +<<: !include common.yaml diff --git a/tests/components/radon_eye_ble/test.esp32-c3.yaml b/tests/components/radon_eye_ble/test.esp32-c3.yaml index 85638d5c0e..dade44d145 100644 --- a/tests/components/radon_eye_ble/test.esp32-c3.yaml +++ b/tests/components/radon_eye_ble/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -radon_eye_ble: +<<: !include common.yaml diff --git a/tests/components/radon_eye_ble/test.esp32-idf.yaml b/tests/components/radon_eye_ble/test.esp32-idf.yaml index 85638d5c0e..dade44d145 100644 --- a/tests/components/radon_eye_ble/test.esp32-idf.yaml +++ b/tests/components/radon_eye_ble/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -radon_eye_ble: +<<: !include common.yaml diff --git a/tests/components/radon_eye_ble/test.esp32.yaml b/tests/components/radon_eye_ble/test.esp32.yaml index 85638d5c0e..dade44d145 100644 --- a/tests/components/radon_eye_ble/test.esp32.yaml +++ b/tests/components/radon_eye_ble/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -radon_eye_ble: +<<: !include common.yaml diff --git a/tests/components/radon_eye_rd200/common.yaml b/tests/components/radon_eye_rd200/common.yaml new file mode 100644 index 0000000000..d06979be6f --- /dev/null +++ b/tests/components/radon_eye_rd200/common.yaml @@ -0,0 +1,14 @@ +esp32_ble_tracker: + +ble_client: + - mac_address: 01:02:03:04:05:06 + id: radon_eye_blec + +sensor: + - platform: radon_eye_rd200 + ble_client_id: radon_eye_blec + radon: + name: RD200 Radon + radon_long_term: + name: RD200 Radon Long Term + update_interval: 10min diff --git a/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml b/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml index d06979be6f..dade44d145 100644 --- a/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml +++ b/tests/components/radon_eye_rd200/test.esp32-c3-idf.yaml @@ -1,14 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: radon_eye_blec - -sensor: - - platform: radon_eye_rd200 - ble_client_id: radon_eye_blec - radon: - name: RD200 Radon - radon_long_term: - name: RD200 Radon Long Term - update_interval: 10min +<<: !include common.yaml diff --git a/tests/components/radon_eye_rd200/test.esp32-c3.yaml b/tests/components/radon_eye_rd200/test.esp32-c3.yaml index d06979be6f..dade44d145 100644 --- a/tests/components/radon_eye_rd200/test.esp32-c3.yaml +++ b/tests/components/radon_eye_rd200/test.esp32-c3.yaml @@ -1,14 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: radon_eye_blec - -sensor: - - platform: radon_eye_rd200 - ble_client_id: radon_eye_blec - radon: - name: RD200 Radon - radon_long_term: - name: RD200 Radon Long Term - update_interval: 10min +<<: !include common.yaml diff --git a/tests/components/radon_eye_rd200/test.esp32-idf.yaml b/tests/components/radon_eye_rd200/test.esp32-idf.yaml index d06979be6f..dade44d145 100644 --- a/tests/components/radon_eye_rd200/test.esp32-idf.yaml +++ b/tests/components/radon_eye_rd200/test.esp32-idf.yaml @@ -1,14 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: radon_eye_blec - -sensor: - - platform: radon_eye_rd200 - ble_client_id: radon_eye_blec - radon: - name: RD200 Radon - radon_long_term: - name: RD200 Radon Long Term - update_interval: 10min +<<: !include common.yaml diff --git a/tests/components/radon_eye_rd200/test.esp32.yaml b/tests/components/radon_eye_rd200/test.esp32.yaml index d06979be6f..dade44d145 100644 --- a/tests/components/radon_eye_rd200/test.esp32.yaml +++ b/tests/components/radon_eye_rd200/test.esp32.yaml @@ -1,14 +1 @@ -esp32_ble_tracker: - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: radon_eye_blec - -sensor: - - platform: radon_eye_rd200 - ble_client_id: radon_eye_blec - radon: - name: RD200 Radon - radon_long_term: - name: RD200 Radon Long Term - update_interval: 10min +<<: !include common.yaml diff --git a/tests/components/restart/common.yaml b/tests/components/restart/common.yaml new file mode 100644 index 0000000000..f0d25809ac --- /dev/null +++ b/tests/components/restart/common.yaml @@ -0,0 +1,7 @@ +button: + - platform: restart + name: Restart Button + +switch: + - platform: restart + name: Restart Switch diff --git a/tests/components/restart/test.esp32-c3-idf.yaml b/tests/components/restart/test.esp32-c3-idf.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.esp32-c3-idf.yaml +++ b/tests/components/restart/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/restart/test.esp32-c3.yaml b/tests/components/restart/test.esp32-c3.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.esp32-c3.yaml +++ b/tests/components/restart/test.esp32-c3.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/restart/test.esp32-idf.yaml b/tests/components/restart/test.esp32-idf.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.esp32-idf.yaml +++ b/tests/components/restart/test.esp32-idf.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/restart/test.esp32.yaml b/tests/components/restart/test.esp32.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.esp32.yaml +++ b/tests/components/restart/test.esp32.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/restart/test.esp8266.yaml b/tests/components/restart/test.esp8266.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.esp8266.yaml +++ b/tests/components/restart/test.esp8266.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/restart/test.rp2040.yaml b/tests/components/restart/test.rp2040.yaml index f0d25809ac..dade44d145 100644 --- a/tests/components/restart/test.rp2040.yaml +++ b/tests/components/restart/test.rp2040.yaml @@ -1,7 +1 @@ -button: - - platform: restart - name: Restart Button - -switch: - - platform: restart - name: Restart Switch +<<: !include common.yaml diff --git a/tests/components/rp2040_pio_led_strip/common.yaml b/tests/components/rp2040_pio_led_strip/common.yaml new file mode 100644 index 0000000000..b9b1436cdb --- /dev/null +++ b/tests/components/rp2040_pio_led_strip/common.yaml @@ -0,0 +1,18 @@ +light: + - platform: rp2040_pio_led_strip + id: led_strip + pin: 4 + num_leds: 60 + pio: 0 + rgb_order: GRB + chipset: WS2812 + - platform: rp2040_pio_led_strip + id: led_strip_custom_timings + pin: 5 + num_leds: 60 + pio: 1 + rgb_order: GRB + bit0_high: .1us + bit0_low: 1.2us + bit1_high: .69us + bit1_low: .4us diff --git a/tests/components/rp2040_pio_led_strip/test.rp2040.yaml b/tests/components/rp2040_pio_led_strip/test.rp2040.yaml index b9b1436cdb..dade44d145 100644 --- a/tests/components/rp2040_pio_led_strip/test.rp2040.yaml +++ b/tests/components/rp2040_pio_led_strip/test.rp2040.yaml @@ -1,18 +1 @@ -light: - - platform: rp2040_pio_led_strip - id: led_strip - pin: 4 - num_leds: 60 - pio: 0 - rgb_order: GRB - chipset: WS2812 - - platform: rp2040_pio_led_strip - id: led_strip_custom_timings - pin: 5 - num_leds: 60 - pio: 1 - rgb_order: GRB - bit0_high: .1us - bit0_low: 1.2us - bit1_high: .69us - bit1_low: .4us +<<: !include common.yaml diff --git a/tests/components/rp2040_pwm/common.yaml b/tests/components/rp2040_pwm/common.yaml new file mode 100644 index 0000000000..45c039106f --- /dev/null +++ b/tests/components/rp2040_pwm/common.yaml @@ -0,0 +1,7 @@ +output: + - platform: rp2040_pwm + id: light_output_1 + pin: 2 + - platform: rp2040_pwm + id: light_output_2 + pin: 3 diff --git a/tests/components/rp2040_pwm/test.rp2040.yaml b/tests/components/rp2040_pwm/test.rp2040.yaml index 45c039106f..dade44d145 100644 --- a/tests/components/rp2040_pwm/test.rp2040.yaml +++ b/tests/components/rp2040_pwm/test.rp2040.yaml @@ -1,7 +1 @@ -output: - - platform: rp2040_pwm - id: light_output_1 - pin: 2 - - platform: rp2040_pwm - id: light_output_2 - pin: 3 +<<: !include common.yaml diff --git a/tests/components/rpi_dpi_rgb/common.yaml b/tests/components/rpi_dpi_rgb/common.yaml new file mode 100644 index 0000000000..9ce2d9b9fd --- /dev/null +++ b/tests/components/rpi_dpi_rgb/common.yaml @@ -0,0 +1,40 @@ +psram: + mode: octal + speed: 80MHz +display: + - platform: rpi_dpi_rgb + update_interval: never + auto_clear_enabled: false + id: rpi_display + color_order: RGB + rotation: 90 + dimensions: + width: 800 + height: 480 + de_pin: + number: 40 + hsync_pin: 39 + vsync_pin: 41 + pclk_pin: 42 + data_pins: + red: + - number: 45 # r1 + ignore_strapping_warning: true + - 48 # r2 + - 47 # r3 + - 21 # r4 + - number: 14 # r5 + ignore_strapping_warning: false + green: + - 5 # g0 + - 6 # g1 + - 7 # g2 + - 15 # g3 + - 16 # g4 + - 4 # g5 + blue: + - 8 # b1 + - 3 # b2 + - 46 # b3 + - 9 # b4 + - 1 # b5 diff --git a/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml b/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml index 9ce2d9b9fd..dade44d145 100644 --- a/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml +++ b/tests/components/rpi_dpi_rgb/test.esp32-s3-idf.yaml @@ -1,40 +1 @@ -psram: - mode: octal - speed: 80MHz -display: - - platform: rpi_dpi_rgb - update_interval: never - auto_clear_enabled: false - id: rpi_display - color_order: RGB - rotation: 90 - dimensions: - width: 800 - height: 480 - de_pin: - number: 40 - hsync_pin: 39 - vsync_pin: 41 - pclk_pin: 42 - data_pins: - red: - - number: 45 # r1 - ignore_strapping_warning: true - - 48 # r2 - - 47 # r3 - - 21 # r4 - - number: 14 # r5 - ignore_strapping_warning: false - green: - - 5 # g0 - - 6 # g1 - - 7 # g2 - - 15 # g3 - - 16 # g4 - - 4 # g5 - blue: - - 8 # b1 - - 3 # b2 - - 46 # b3 - - 9 # b4 - - 1 # b5 +<<: !include common.yaml diff --git a/tests/components/ruuvi_ble/common.yaml b/tests/components/ruuvi_ble/common.yaml new file mode 100644 index 0000000000..1f155fd8e1 --- /dev/null +++ b/tests/components/ruuvi_ble/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +ruuvi_ble: diff --git a/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml b/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml index 1f155fd8e1..dade44d145 100644 --- a/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml +++ b/tests/components/ruuvi_ble/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -ruuvi_ble: +<<: !include common.yaml diff --git a/tests/components/ruuvi_ble/test.esp32-c3.yaml b/tests/components/ruuvi_ble/test.esp32-c3.yaml index 1f155fd8e1..dade44d145 100644 --- a/tests/components/ruuvi_ble/test.esp32-c3.yaml +++ b/tests/components/ruuvi_ble/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -ruuvi_ble: +<<: !include common.yaml diff --git a/tests/components/ruuvi_ble/test.esp32-idf.yaml b/tests/components/ruuvi_ble/test.esp32-idf.yaml index 1f155fd8e1..dade44d145 100644 --- a/tests/components/ruuvi_ble/test.esp32-idf.yaml +++ b/tests/components/ruuvi_ble/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -ruuvi_ble: +<<: !include common.yaml diff --git a/tests/components/ruuvi_ble/test.esp32.yaml b/tests/components/ruuvi_ble/test.esp32.yaml index 1f155fd8e1..dade44d145 100644 --- a/tests/components/ruuvi_ble/test.esp32.yaml +++ b/tests/components/ruuvi_ble/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -ruuvi_ble: +<<: !include common.yaml diff --git a/tests/components/ruuvitag/common.yaml b/tests/components/ruuvitag/common.yaml new file mode 100644 index 0000000000..7990617710 --- /dev/null +++ b/tests/components/ruuvitag/common.yaml @@ -0,0 +1,27 @@ +esp32_ble_tracker: + +sensor: + - platform: ruuvitag + mac_address: FF:56:D3:2F:7D:E8 + humidity: + name: RuuviTag Humidity + temperature: + name: RuuviTag Temperature + pressure: + name: RuuviTag Pressure + acceleration: + name: RuuviTag Acceleration + acceleration_x: + name: RuuviTag Acceleration X + acceleration_y: + name: RuuviTag Acceleration Y + acceleration_z: + name: RuuviTag Acceleration Z + battery_voltage: + name: RuuviTag Battery Voltage + tx_power: + name: RuuviTag TX Power + movement_counter: + name: RuuviTag Movement Counter + measurement_sequence_number: + name: RuuviTag Measurement Sequence Number diff --git a/tests/components/ruuvitag/test.esp32-c3-idf.yaml b/tests/components/ruuvitag/test.esp32-c3-idf.yaml index 7990617710..dade44d145 100644 --- a/tests/components/ruuvitag/test.esp32-c3-idf.yaml +++ b/tests/components/ruuvitag/test.esp32-c3-idf.yaml @@ -1,27 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ruuvitag - mac_address: FF:56:D3:2F:7D:E8 - humidity: - name: RuuviTag Humidity - temperature: - name: RuuviTag Temperature - pressure: - name: RuuviTag Pressure - acceleration: - name: RuuviTag Acceleration - acceleration_x: - name: RuuviTag Acceleration X - acceleration_y: - name: RuuviTag Acceleration Y - acceleration_z: - name: RuuviTag Acceleration Z - battery_voltage: - name: RuuviTag Battery Voltage - tx_power: - name: RuuviTag TX Power - movement_counter: - name: RuuviTag Movement Counter - measurement_sequence_number: - name: RuuviTag Measurement Sequence Number +<<: !include common.yaml diff --git a/tests/components/ruuvitag/test.esp32-c3.yaml b/tests/components/ruuvitag/test.esp32-c3.yaml index 7990617710..dade44d145 100644 --- a/tests/components/ruuvitag/test.esp32-c3.yaml +++ b/tests/components/ruuvitag/test.esp32-c3.yaml @@ -1,27 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ruuvitag - mac_address: FF:56:D3:2F:7D:E8 - humidity: - name: RuuviTag Humidity - temperature: - name: RuuviTag Temperature - pressure: - name: RuuviTag Pressure - acceleration: - name: RuuviTag Acceleration - acceleration_x: - name: RuuviTag Acceleration X - acceleration_y: - name: RuuviTag Acceleration Y - acceleration_z: - name: RuuviTag Acceleration Z - battery_voltage: - name: RuuviTag Battery Voltage - tx_power: - name: RuuviTag TX Power - movement_counter: - name: RuuviTag Movement Counter - measurement_sequence_number: - name: RuuviTag Measurement Sequence Number +<<: !include common.yaml diff --git a/tests/components/ruuvitag/test.esp32-idf.yaml b/tests/components/ruuvitag/test.esp32-idf.yaml index 7990617710..dade44d145 100644 --- a/tests/components/ruuvitag/test.esp32-idf.yaml +++ b/tests/components/ruuvitag/test.esp32-idf.yaml @@ -1,27 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ruuvitag - mac_address: FF:56:D3:2F:7D:E8 - humidity: - name: RuuviTag Humidity - temperature: - name: RuuviTag Temperature - pressure: - name: RuuviTag Pressure - acceleration: - name: RuuviTag Acceleration - acceleration_x: - name: RuuviTag Acceleration X - acceleration_y: - name: RuuviTag Acceleration Y - acceleration_z: - name: RuuviTag Acceleration Z - battery_voltage: - name: RuuviTag Battery Voltage - tx_power: - name: RuuviTag TX Power - movement_counter: - name: RuuviTag Movement Counter - measurement_sequence_number: - name: RuuviTag Measurement Sequence Number +<<: !include common.yaml diff --git a/tests/components/ruuvitag/test.esp32.yaml b/tests/components/ruuvitag/test.esp32.yaml index 7990617710..dade44d145 100644 --- a/tests/components/ruuvitag/test.esp32.yaml +++ b/tests/components/ruuvitag/test.esp32.yaml @@ -1,27 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: ruuvitag - mac_address: FF:56:D3:2F:7D:E8 - humidity: - name: RuuviTag Humidity - temperature: - name: RuuviTag Temperature - pressure: - name: RuuviTag Pressure - acceleration: - name: RuuviTag Acceleration - acceleration_x: - name: RuuviTag Acceleration X - acceleration_y: - name: RuuviTag Acceleration Y - acceleration_z: - name: RuuviTag Acceleration Z - battery_voltage: - name: RuuviTag Battery Voltage - tx_power: - name: RuuviTag TX Power - movement_counter: - name: RuuviTag Movement Counter - measurement_sequence_number: - name: RuuviTag Measurement Sequence Number +<<: !include common.yaml diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml new file mode 100644 index 0000000000..df0abd9aec --- /dev/null +++ b/tests/components/safe_mode/common.yaml @@ -0,0 +1,13 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + +button: + - platform: safe_mode + name: Safe Mode Button + +switch: + - platform: safe_mode + name: Safe Mode Switch diff --git a/tests/components/safe_mode/test.esp32-c3-idf.yaml b/tests/components/safe_mode/test.esp32-c3-idf.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.esp32-c3-idf.yaml +++ b/tests/components/safe_mode/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32-c3.yaml b/tests/components/safe_mode/test.esp32-c3.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.esp32-c3.yaml +++ b/tests/components/safe_mode/test.esp32-c3.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32-idf.yaml b/tests/components/safe_mode/test.esp32-idf.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.esp32-idf.yaml +++ b/tests/components/safe_mode/test.esp32-idf.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32.yaml b/tests/components/safe_mode/test.esp32.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.esp32.yaml +++ b/tests/components/safe_mode/test.esp32.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp8266.yaml b/tests/components/safe_mode/test.esp8266.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.esp8266.yaml +++ b/tests/components/safe_mode/test.esp8266.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/safe_mode/test.rp2040.yaml b/tests/components/safe_mode/test.rp2040.yaml index df0abd9aec..dade44d145 100644 --- a/tests/components/safe_mode/test.rp2040.yaml +++ b/tests/components/safe_mode/test.rp2040.yaml @@ -1,13 +1 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - -button: - - platform: safe_mode - name: Safe Mode Button - -switch: - - platform: safe_mode - name: Safe Mode Switch +<<: !include common.yaml diff --git a/tests/components/shelly_dimmer/common.yaml b/tests/components/shelly_dimmer/common.yaml new file mode 100644 index 0000000000..3acd0260d5 --- /dev/null +++ b/tests/components/shelly_dimmer/common.yaml @@ -0,0 +1,19 @@ +uart: + - id: uart_shelly_dimmer + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + +light: + - platform: shelly_dimmer + name: Shelly Dimmer Light + power: + name: Shelly Dimmer Power + voltage: + name: Shelly Dimmer Voltage + current: + name: Shelly Dimmer Current + max_brightness: 500 + firmware: "51.6" + nrst_pin: 13 + boot0_pin: 14 diff --git a/tests/components/shelly_dimmer/test.esp8266.yaml b/tests/components/shelly_dimmer/test.esp8266.yaml index 3acd0260d5..dade44d145 100644 --- a/tests/components/shelly_dimmer/test.esp8266.yaml +++ b/tests/components/shelly_dimmer/test.esp8266.yaml @@ -1,19 +1 @@ -uart: - - id: uart_shelly_dimmer - tx_pin: 4 - rx_pin: 5 - baud_rate: 9600 - -light: - - platform: shelly_dimmer - name: Shelly Dimmer Light - power: - name: Shelly Dimmer Power - voltage: - name: Shelly Dimmer Voltage - current: - name: Shelly Dimmer Current - max_brightness: 500 - firmware: "51.6" - nrst_pin: 13 - boot0_pin: 14 +<<: !include common.yaml diff --git a/tests/components/shutdown/common.yaml b/tests/components/shutdown/common.yaml new file mode 100644 index 0000000000..f47e7da85d --- /dev/null +++ b/tests/components/shutdown/common.yaml @@ -0,0 +1,7 @@ +button: + - platform: shutdown + name: Shutdown Button + +switch: + - platform: shutdown + name: Shutdown Switch diff --git a/tests/components/shutdown/test.esp32-c3-idf.yaml b/tests/components/shutdown/test.esp32-c3-idf.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.esp32-c3-idf.yaml +++ b/tests/components/shutdown/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/shutdown/test.esp32-c3.yaml b/tests/components/shutdown/test.esp32-c3.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.esp32-c3.yaml +++ b/tests/components/shutdown/test.esp32-c3.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/shutdown/test.esp32-idf.yaml b/tests/components/shutdown/test.esp32-idf.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.esp32-idf.yaml +++ b/tests/components/shutdown/test.esp32-idf.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/shutdown/test.esp32.yaml b/tests/components/shutdown/test.esp32.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.esp32.yaml +++ b/tests/components/shutdown/test.esp32.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/shutdown/test.esp8266.yaml b/tests/components/shutdown/test.esp8266.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.esp8266.yaml +++ b/tests/components/shutdown/test.esp8266.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/shutdown/test.rp2040.yaml b/tests/components/shutdown/test.rp2040.yaml index f47e7da85d..dade44d145 100644 --- a/tests/components/shutdown/test.rp2040.yaml +++ b/tests/components/shutdown/test.rp2040.yaml @@ -1,7 +1 @@ -button: - - platform: shutdown - name: Shutdown Button - -switch: - - platform: shutdown - name: Shutdown Switch +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/common.yaml b/tests/components/sigma_delta_output/common.yaml new file mode 100644 index 0000000000..2a9a5d2c3b --- /dev/null +++ b/tests/components/sigma_delta_output/common.yaml @@ -0,0 +1,16 @@ +output: + - platform: sigma_delta_output + id: sddac + pin: 4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + update_interval: 60s diff --git a/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml b/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml +++ b/tests/components/sigma_delta_output/test.esp32-c3-idf.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/test.esp32-c3.yaml b/tests/components/sigma_delta_output/test.esp32-c3.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.esp32-c3.yaml +++ b/tests/components/sigma_delta_output/test.esp32-c3.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/test.esp32-idf.yaml b/tests/components/sigma_delta_output/test.esp32-idf.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.esp32-idf.yaml +++ b/tests/components/sigma_delta_output/test.esp32-idf.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/test.esp32.yaml b/tests/components/sigma_delta_output/test.esp32.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.esp32.yaml +++ b/tests/components/sigma_delta_output/test.esp32.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/test.esp8266.yaml b/tests/components/sigma_delta_output/test.esp8266.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.esp8266.yaml +++ b/tests/components/sigma_delta_output/test.esp8266.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/sigma_delta_output/test.rp2040.yaml b/tests/components/sigma_delta_output/test.rp2040.yaml index 2a9a5d2c3b..dade44d145 100644 --- a/tests/components/sigma_delta_output/test.rp2040.yaml +++ b/tests/components/sigma_delta_output/test.rp2040.yaml @@ -1,16 +1 @@ -output: - - platform: sigma_delta_output - id: sddac - pin: 4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - update_interval: 60s +<<: !include common.yaml diff --git a/tests/components/slow_pwm/common.yaml b/tests/components/slow_pwm/common.yaml new file mode 100644 index 0000000000..6bfb2f8ac5 --- /dev/null +++ b/tests/components/slow_pwm/common.yaml @@ -0,0 +1,6 @@ +output: + - platform: slow_pwm + id: test_slow_pwm + pin: 4 + period: 15s + restart_cycle_on_state_change: false diff --git a/tests/components/slow_pwm/test.esp32-c3-idf.yaml b/tests/components/slow_pwm/test.esp32-c3-idf.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.esp32-c3-idf.yaml +++ b/tests/components/slow_pwm/test.esp32-c3-idf.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/slow_pwm/test.esp32-c3.yaml b/tests/components/slow_pwm/test.esp32-c3.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.esp32-c3.yaml +++ b/tests/components/slow_pwm/test.esp32-c3.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/slow_pwm/test.esp32-idf.yaml b/tests/components/slow_pwm/test.esp32-idf.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.esp32-idf.yaml +++ b/tests/components/slow_pwm/test.esp32-idf.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/slow_pwm/test.esp32.yaml b/tests/components/slow_pwm/test.esp32.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.esp32.yaml +++ b/tests/components/slow_pwm/test.esp32.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/slow_pwm/test.esp8266.yaml b/tests/components/slow_pwm/test.esp8266.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.esp8266.yaml +++ b/tests/components/slow_pwm/test.esp8266.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/slow_pwm/test.rp2040.yaml b/tests/components/slow_pwm/test.rp2040.yaml index 6bfb2f8ac5..dade44d145 100644 --- a/tests/components/slow_pwm/test.rp2040.yaml +++ b/tests/components/slow_pwm/test.rp2040.yaml @@ -1,6 +1 @@ -output: - - platform: slow_pwm - id: test_slow_pwm - pin: 4 - period: 15s - restart_cycle_on_state_change: false +<<: !include common.yaml diff --git a/tests/components/sm16716/common.yaml b/tests/components/sm16716/common.yaml new file mode 100644 index 0000000000..3bf2712f4e --- /dev/null +++ b/tests/components/sm16716/common.yaml @@ -0,0 +1,16 @@ +sm16716: + clock_pin: 4 + data_pin: 5 + num_channels: 3 + num_chips: 1 + +output: + - platform: sm16716 + id: sm16716_red + channel: 1 + - platform: sm16716 + id: sm16716_green + channel: 0 + - platform: sm16716 + id: sm16716_blue + channel: 2 diff --git a/tests/components/sm16716/test.esp32-c3-idf.yaml b/tests/components/sm16716/test.esp32-c3-idf.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.esp32-c3-idf.yaml +++ b/tests/components/sm16716/test.esp32-c3-idf.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm16716/test.esp32-c3.yaml b/tests/components/sm16716/test.esp32-c3.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.esp32-c3.yaml +++ b/tests/components/sm16716/test.esp32-c3.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm16716/test.esp32-idf.yaml b/tests/components/sm16716/test.esp32-idf.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.esp32-idf.yaml +++ b/tests/components/sm16716/test.esp32-idf.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm16716/test.esp32.yaml b/tests/components/sm16716/test.esp32.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.esp32.yaml +++ b/tests/components/sm16716/test.esp32.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm16716/test.esp8266.yaml b/tests/components/sm16716/test.esp8266.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.esp8266.yaml +++ b/tests/components/sm16716/test.esp8266.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm16716/test.rp2040.yaml b/tests/components/sm16716/test.rp2040.yaml index 3bf2712f4e..dade44d145 100644 --- a/tests/components/sm16716/test.rp2040.yaml +++ b/tests/components/sm16716/test.rp2040.yaml @@ -1,16 +1 @@ -sm16716: - clock_pin: 4 - data_pin: 5 - num_channels: 3 - num_chips: 1 - -output: - - platform: sm16716 - id: sm16716_red - channel: 1 - - platform: sm16716 - id: sm16716_green - channel: 0 - - platform: sm16716 - id: sm16716_blue - channel: 2 +<<: !include common.yaml diff --git a/tests/components/sm2135/common.yaml b/tests/components/sm2135/common.yaml new file mode 100644 index 0000000000..9a0de60839 --- /dev/null +++ b/tests/components/sm2135/common.yaml @@ -0,0 +1,22 @@ +sm2135: + clock_pin: 4 + data_pin: 5 + rgb_current: 20mA + cw_current: 60mA + +output: + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 diff --git a/tests/components/sm2135/test.esp32-c3-idf.yaml b/tests/components/sm2135/test.esp32-c3-idf.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.esp32-c3-idf.yaml +++ b/tests/components/sm2135/test.esp32-c3-idf.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2135/test.esp32-c3.yaml b/tests/components/sm2135/test.esp32-c3.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.esp32-c3.yaml +++ b/tests/components/sm2135/test.esp32-c3.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2135/test.esp32-idf.yaml b/tests/components/sm2135/test.esp32-idf.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.esp32-idf.yaml +++ b/tests/components/sm2135/test.esp32-idf.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2135/test.esp32.yaml b/tests/components/sm2135/test.esp32.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.esp32.yaml +++ b/tests/components/sm2135/test.esp32.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2135/test.esp8266.yaml b/tests/components/sm2135/test.esp8266.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.esp8266.yaml +++ b/tests/components/sm2135/test.esp8266.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2135/test.rp2040.yaml b/tests/components/sm2135/test.rp2040.yaml index 9a0de60839..dade44d145 100644 --- a/tests/components/sm2135/test.rp2040.yaml +++ b/tests/components/sm2135/test.rp2040.yaml @@ -1,22 +1 @@ -sm2135: - clock_pin: 4 - data_pin: 5 - rgb_current: 20mA - cw_current: 60mA - -output: - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 +<<: !include common.yaml diff --git a/tests/components/sm2235/common.yaml b/tests/components/sm2235/common.yaml new file mode 100644 index 0000000000..043d43d6f1 --- /dev/null +++ b/tests/components/sm2235/common.yaml @@ -0,0 +1,22 @@ +sm2235: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2235 + id: sm2235_red + channel: 1 + - platform: sm2235 + id: sm2235_green + channel: 0 + - platform: sm2235 + id: sm2235_blue + channel: 2 + - platform: sm2235 + id: sm2235_coldwhite + channel: 4 + - platform: sm2235 + id: sm2235_warmwhite + channel: 3 diff --git a/tests/components/sm2235/test.esp32-c3-idf.yaml b/tests/components/sm2235/test.esp32-c3-idf.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.esp32-c3-idf.yaml +++ b/tests/components/sm2235/test.esp32-c3-idf.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2235/test.esp32-c3.yaml b/tests/components/sm2235/test.esp32-c3.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.esp32-c3.yaml +++ b/tests/components/sm2235/test.esp32-c3.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2235/test.esp32-idf.yaml b/tests/components/sm2235/test.esp32-idf.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.esp32-idf.yaml +++ b/tests/components/sm2235/test.esp32-idf.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2235/test.esp32.yaml b/tests/components/sm2235/test.esp32.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.esp32.yaml +++ b/tests/components/sm2235/test.esp32.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2235/test.esp8266.yaml b/tests/components/sm2235/test.esp8266.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.esp8266.yaml +++ b/tests/components/sm2235/test.esp8266.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2235/test.rp2040.yaml b/tests/components/sm2235/test.rp2040.yaml index 043d43d6f1..dade44d145 100644 --- a/tests/components/sm2235/test.rp2040.yaml +++ b/tests/components/sm2235/test.rp2040.yaml @@ -1,22 +1 @@ -sm2235: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/common.yaml b/tests/components/sm2335/common.yaml new file mode 100644 index 0000000000..a5b2aedeb5 --- /dev/null +++ b/tests/components/sm2335/common.yaml @@ -0,0 +1,22 @@ +sm2335: + clock_pin: 4 + data_pin: 5 + max_power_color_channels: 9 + max_power_white_channels: 9 + +output: + - platform: sm2335 + id: sm2335_red + channel: 1 + - platform: sm2335 + id: sm2335_green + channel: 0 + - platform: sm2335 + id: sm2335_blue + channel: 2 + - platform: sm2335 + id: sm2335_coldwhite + channel: 4 + - platform: sm2335 + id: sm2335_warmwhite + channel: 3 diff --git a/tests/components/sm2335/test.esp32-c3-idf.yaml b/tests/components/sm2335/test.esp32-c3-idf.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.esp32-c3-idf.yaml +++ b/tests/components/sm2335/test.esp32-c3-idf.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/test.esp32-c3.yaml b/tests/components/sm2335/test.esp32-c3.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.esp32-c3.yaml +++ b/tests/components/sm2335/test.esp32-c3.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/test.esp32-idf.yaml b/tests/components/sm2335/test.esp32-idf.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.esp32-idf.yaml +++ b/tests/components/sm2335/test.esp32-idf.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/test.esp32.yaml b/tests/components/sm2335/test.esp32.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.esp32.yaml +++ b/tests/components/sm2335/test.esp32.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/test.esp8266.yaml b/tests/components/sm2335/test.esp8266.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.esp8266.yaml +++ b/tests/components/sm2335/test.esp8266.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sm2335/test.rp2040.yaml b/tests/components/sm2335/test.rp2040.yaml index a5b2aedeb5..dade44d145 100644 --- a/tests/components/sm2335/test.rp2040.yaml +++ b/tests/components/sm2335/test.rp2040.yaml @@ -1,22 +1 @@ -sm2335: - clock_pin: 4 - data_pin: 5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -output: - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 +<<: !include common.yaml diff --git a/tests/components/sntp/common.yaml b/tests/components/sntp/common.yaml new file mode 100644 index 0000000000..3e9e465296 --- /dev/null +++ b/tests/components/sntp/common.yaml @@ -0,0 +1,15 @@ +wifi: + ssid: MySSID + password: password1 + +time: + - platform: sntp + id: sntp_time + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 192.168.178.1 + on_time: + cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" + then: + - lambda: 'ESP_LOGD("main", "time");' diff --git a/tests/components/sntp/test.esp32-c3-idf.yaml b/tests/components/sntp/test.esp32-c3-idf.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.esp32-c3-idf.yaml +++ b/tests/components/sntp/test.esp32-c3-idf.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sntp/test.esp32-c3.yaml b/tests/components/sntp/test.esp32-c3.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.esp32-c3.yaml +++ b/tests/components/sntp/test.esp32-c3.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sntp/test.esp32-idf.yaml b/tests/components/sntp/test.esp32-idf.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.esp32-idf.yaml +++ b/tests/components/sntp/test.esp32-idf.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sntp/test.esp32.yaml b/tests/components/sntp/test.esp32.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.esp32.yaml +++ b/tests/components/sntp/test.esp32.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sntp/test.esp8266.yaml b/tests/components/sntp/test.esp8266.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.esp8266.yaml +++ b/tests/components/sntp/test.esp8266.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sntp/test.rp2040.yaml b/tests/components/sntp/test.rp2040.yaml index 3e9e465296..dade44d145 100644 --- a/tests/components/sntp/test.rp2040.yaml +++ b/tests/components/sntp/test.rp2040.yaml @@ -1,15 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' +<<: !include common.yaml diff --git a/tests/components/sprinkler/common.yaml b/tests/components/sprinkler/common.yaml new file mode 100644 index 0000000000..f099f77729 --- /dev/null +++ b/tests/components/sprinkler/common.yaml @@ -0,0 +1,83 @@ +esphome: + on_boot: + then: + - sprinkler.start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.start_from_queue: yard_sprinkler_ctrlr + - sprinkler.start_single_valve: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + - sprinkler.shutdown: yard_sprinkler_ctrlr + - sprinkler.next_valve: yard_sprinkler_ctrlr + - sprinkler.previous_valve: yard_sprinkler_ctrlr + - sprinkler.pause: yard_sprinkler_ctrlr + - sprinkler.resume: yard_sprinkler_ctrlr + - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr + - sprinkler.queue_valve: + id: yard_sprinkler_ctrlr + valve_number: 2 + run_duration: 900s + - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr + - sprinkler.set_multiplier: + id: yard_sprinkler_ctrlr + multiplier: 1.5 + - sprinkler.set_repeat: + id: yard_sprinkler_ctrlr + repeat: 2 + - sprinkler.set_divider: + id: yard_sprinkler_ctrlr + divider: 2 + - sprinkler.set_valve_run_duration: + id: yard_sprinkler_ctrlr + valve_number: 0 + run_duration: 600s + +switch: + - platform: template + id: switch1 + optimistic: true + - platform: template + id: switch2 + optimistic: true + +sprinkler: + - id: yard_sprinkler_ctrlr + main_switch: Yard Sprinklers + auto_advance_switch: Yard Sprinklers Auto Advance + reverse_switch: Yard Sprinklers Reverse + pump_start_pump_delay: 2s + pump_stop_valve_delay: 4s + pump_switch_off_during_valve_open_delay: true + valve_open_delay: 5s + valves: + - valve_switch: Yard Valve 0 + enable_switch: Enable Yard Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 1 + enable_switch: Enable Yard Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Yard Valve 2 + enable_switch: Enable Yard Valve 2 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - id: garden_sprinkler_ctrlr + main_switch: Garden Sprinklers + auto_advance_switch: Garden Sprinklers Auto Advance + reverse_switch: Garden Sprinklers Reverse + valve_overlap: 5s + valves: + - valve_switch: Garden Valve 0 + enable_switch: Enable Garden Valve 0 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 + - valve_switch: Garden Valve 1 + enable_switch: Enable Garden Valve 1 + pump_switch_id: switch1 + run_duration: 10s + valve_switch_id: switch2 diff --git a/tests/components/sprinkler/test.esp32-c3-idf.yaml b/tests/components/sprinkler/test.esp32-c3-idf.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.esp32-c3-idf.yaml +++ b/tests/components/sprinkler/test.esp32-c3-idf.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/sprinkler/test.esp32-c3.yaml b/tests/components/sprinkler/test.esp32-c3.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.esp32-c3.yaml +++ b/tests/components/sprinkler/test.esp32-c3.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/sprinkler/test.esp32-idf.yaml b/tests/components/sprinkler/test.esp32-idf.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.esp32-idf.yaml +++ b/tests/components/sprinkler/test.esp32-idf.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/sprinkler/test.esp32.yaml b/tests/components/sprinkler/test.esp32.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.esp32.yaml +++ b/tests/components/sprinkler/test.esp32.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/sprinkler/test.esp8266.yaml b/tests/components/sprinkler/test.esp8266.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.esp8266.yaml +++ b/tests/components/sprinkler/test.esp8266.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/sprinkler/test.rp2040.yaml b/tests/components/sprinkler/test.rp2040.yaml index f099f77729..dade44d145 100644 --- a/tests/components/sprinkler/test.rp2040.yaml +++ b/tests/components/sprinkler/test.rp2040.yaml @@ -1,83 +1 @@ -esphome: - on_boot: - then: - - sprinkler.start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.start_from_queue: yard_sprinkler_ctrlr - - sprinkler.start_single_valve: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - - sprinkler.shutdown: yard_sprinkler_ctrlr - - sprinkler.next_valve: yard_sprinkler_ctrlr - - sprinkler.previous_valve: yard_sprinkler_ctrlr - - sprinkler.pause: yard_sprinkler_ctrlr - - sprinkler.resume: yard_sprinkler_ctrlr - - sprinkler.resume_or_start_full_cycle: yard_sprinkler_ctrlr - - sprinkler.queue_valve: - id: yard_sprinkler_ctrlr - valve_number: 2 - run_duration: 900s - - sprinkler.clear_queued_valves: yard_sprinkler_ctrlr - - sprinkler.set_multiplier: - id: yard_sprinkler_ctrlr - multiplier: 1.5 - - sprinkler.set_repeat: - id: yard_sprinkler_ctrlr - repeat: 2 - - sprinkler.set_divider: - id: yard_sprinkler_ctrlr - divider: 2 - - sprinkler.set_valve_run_duration: - id: yard_sprinkler_ctrlr - valve_number: 0 - run_duration: 600s - -switch: - - platform: template - id: switch1 - optimistic: true - - platform: template - id: switch2 - optimistic: true - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: switch1 - run_duration: 10s - valve_switch_id: switch2 +<<: !include common.yaml diff --git a/tests/components/st7701s/common.yaml b/tests/components/st7701s/common.yaml new file mode 100644 index 0000000000..497df8c8ce --- /dev/null +++ b/tests/components/st7701s/common.yaml @@ -0,0 +1,60 @@ +psram: + mode: octal + speed: 80MHz +spi: + - id: lcd_spi + clk_pin: 41 + mosi_pin: 48 + +i2c: + sda: 39 + scl: 40 + scan: false + id: bus_a + +pca9554: + - id: p_c_a + pin_count: 16 + address: 0x20 + +display: + - platform: st7701s + spi_mode: MODE3 + color_order: RGB + dimensions: + width: 480 + height: 480 + invert_colors: true + transform: + mirror_x: true + mirror_y: true + cs_pin: + pca9554: p_c_a + number: 4 + reset_pin: + pca9554: p_c_a + number: 5 + de_pin: 18 + hsync_pin: 16 + vsync_pin: 17 + pclk_pin: 21 + init_sequence: 1 + data_pins: + - number: 0 + ignore_strapping_warning: true + - 1 + - 2 + - 3 + - number: 4 + ignore_strapping_warning: false + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 diff --git a/tests/components/st7701s/test.esp32-s3-idf.yaml b/tests/components/st7701s/test.esp32-s3-idf.yaml index 497df8c8ce..dade44d145 100644 --- a/tests/components/st7701s/test.esp32-s3-idf.yaml +++ b/tests/components/st7701s/test.esp32-s3-idf.yaml @@ -1,60 +1 @@ -psram: - mode: octal - speed: 80MHz -spi: - - id: lcd_spi - clk_pin: 41 - mosi_pin: 48 - -i2c: - sda: 39 - scl: 40 - scan: false - id: bus_a - -pca9554: - - id: p_c_a - pin_count: 16 - address: 0x20 - -display: - - platform: st7701s - spi_mode: MODE3 - color_order: RGB - dimensions: - width: 480 - height: 480 - invert_colors: true - transform: - mirror_x: true - mirror_y: true - cs_pin: - pca9554: p_c_a - number: 4 - reset_pin: - pca9554: p_c_a - number: 5 - de_pin: 18 - hsync_pin: 16 - vsync_pin: 17 - pclk_pin: 21 - init_sequence: 1 - data_pins: - - number: 0 - ignore_strapping_warning: true - - 1 - - 2 - - 3 - - number: 4 - ignore_strapping_warning: false - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 +<<: !include common.yaml diff --git a/tests/components/status/common.yaml b/tests/components/status/common.yaml new file mode 100644 index 0000000000..c14157566b --- /dev/null +++ b/tests/components/status/common.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +binary_sensor: + - platform: status + id: node_status + name: Node Status diff --git a/tests/components/status/test.esp32-c3-idf.yaml b/tests/components/status/test.esp32-c3-idf.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.esp32-c3-idf.yaml +++ b/tests/components/status/test.esp32-c3-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status/test.esp32-c3.yaml b/tests/components/status/test.esp32-c3.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.esp32-c3.yaml +++ b/tests/components/status/test.esp32-c3.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status/test.esp32-idf.yaml b/tests/components/status/test.esp32-idf.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.esp32-idf.yaml +++ b/tests/components/status/test.esp32-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status/test.esp32.yaml b/tests/components/status/test.esp32.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.esp32.yaml +++ b/tests/components/status/test.esp32.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status/test.esp8266.yaml b/tests/components/status/test.esp8266.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.esp8266.yaml +++ b/tests/components/status/test.esp8266.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status/test.rp2040.yaml b/tests/components/status/test.rp2040.yaml index c14157566b..dade44d145 100644 --- a/tests/components/status/test.rp2040.yaml +++ b/tests/components/status/test.rp2040.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -binary_sensor: - - platform: status - id: node_status - name: Node Status +<<: !include common.yaml diff --git a/tests/components/status_led/common.yaml b/tests/components/status_led/common.yaml new file mode 100644 index 0000000000..ec66c219d3 --- /dev/null +++ b/tests/components/status_led/common.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +light: + - platform: status_led + name: Switch State + pin: 4 diff --git a/tests/components/status_led/test.esp32-c3-idf.yaml b/tests/components/status_led/test.esp32-c3-idf.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.esp32-c3-idf.yaml +++ b/tests/components/status_led/test.esp32-c3-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/status_led/test.esp32-c3.yaml b/tests/components/status_led/test.esp32-c3.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.esp32-c3.yaml +++ b/tests/components/status_led/test.esp32-c3.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/status_led/test.esp32-idf.yaml b/tests/components/status_led/test.esp32-idf.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.esp32-idf.yaml +++ b/tests/components/status_led/test.esp32-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/status_led/test.esp32.yaml b/tests/components/status_led/test.esp32.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.esp32.yaml +++ b/tests/components/status_led/test.esp32.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/status_led/test.esp8266.yaml b/tests/components/status_led/test.esp8266.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.esp8266.yaml +++ b/tests/components/status_led/test.esp8266.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/status_led/test.rp2040.yaml b/tests/components/status_led/test.rp2040.yaml index ec66c219d3..dade44d145 100644 --- a/tests/components/status_led/test.rp2040.yaml +++ b/tests/components/status_led/test.rp2040.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -light: - - platform: status_led - name: Switch State - pin: 4 +<<: !include common.yaml diff --git a/tests/components/stepper/common.yaml b/tests/components/stepper/common.yaml new file mode 100644 index 0000000000..fcf5759618 --- /dev/null +++ b/tests/components/stepper/common.yaml @@ -0,0 +1,27 @@ +stepper: + - platform: a4988 + id: test_stepper + step_pin: 3 + dir_pin: 4 + sleep_pin: 5 + max_speed: 250 steps/s + acceleration: 100 steps/s^2 + deceleration: 200 steps/s^2 + +switch: + - platform: template + name: Stepper Switch + assumed_state: true + turn_on_action: + - stepper.set_target: + id: test_stepper + target: !lambda |- + static int32_t i = 0; + i += 1000; + if (i > 5000) { + i = -5000; + } + return i; + - stepper.report_position: + id: test_stepper + position: 0 diff --git a/tests/components/stepper/test.esp32-c3-idf.yaml b/tests/components/stepper/test.esp32-c3-idf.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.esp32-c3-idf.yaml +++ b/tests/components/stepper/test.esp32-c3-idf.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/stepper/test.esp32-c3.yaml b/tests/components/stepper/test.esp32-c3.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.esp32-c3.yaml +++ b/tests/components/stepper/test.esp32-c3.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/stepper/test.esp32-idf.yaml b/tests/components/stepper/test.esp32-idf.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.esp32-idf.yaml +++ b/tests/components/stepper/test.esp32-idf.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/stepper/test.esp32.yaml b/tests/components/stepper/test.esp32.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.esp32.yaml +++ b/tests/components/stepper/test.esp32.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/stepper/test.esp8266.yaml b/tests/components/stepper/test.esp8266.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.esp8266.yaml +++ b/tests/components/stepper/test.esp8266.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/stepper/test.rp2040.yaml b/tests/components/stepper/test.rp2040.yaml index fcf5759618..dade44d145 100644 --- a/tests/components/stepper/test.rp2040.yaml +++ b/tests/components/stepper/test.rp2040.yaml @@ -1,27 +1 @@ -stepper: - - platform: a4988 - id: test_stepper - step_pin: 3 - dir_pin: 4 - sleep_pin: 5 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -switch: - - platform: template - name: Stepper Switch - assumed_state: true - turn_on_action: - - stepper.set_target: - id: test_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: test_stepper - position: 0 +<<: !include common.yaml diff --git a/tests/components/sun/common.yaml b/tests/components/sun/common.yaml new file mode 100644 index 0000000000..e0157424a0 --- /dev/null +++ b/tests/components/sun/common.yaml @@ -0,0 +1,38 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + id: homeassistant_time + +sun: + latitude: 48.8584° + longitude: 2.2945° + on_sunrise: + - then: + - logger.log: Good morning + - elevation: 5° + then: + - logger.log: Good morning again + on_sunset: + - then: + - logger.log: Good evening + +sensor: + - platform: sun + name: Sun Elevation + type: elevation + - platform: sun + name: Sun Azimuth + type: azimuth + +text_sensor: + - platform: sun + name: Sun Next Sunrise + type: sunrise + - platform: sun + name: Sun Next Sunset + type: sunset diff --git a/tests/components/sun/test.esp32-c3-idf.yaml b/tests/components/sun/test.esp32-c3-idf.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.esp32-c3-idf.yaml +++ b/tests/components/sun/test.esp32-c3-idf.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/sun/test.esp32-c3.yaml b/tests/components/sun/test.esp32-c3.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.esp32-c3.yaml +++ b/tests/components/sun/test.esp32-c3.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/sun/test.esp32-idf.yaml b/tests/components/sun/test.esp32-idf.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.esp32-idf.yaml +++ b/tests/components/sun/test.esp32-idf.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/sun/test.esp32.yaml b/tests/components/sun/test.esp32.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.esp32.yaml +++ b/tests/components/sun/test.esp32.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/sun/test.esp8266.yaml b/tests/components/sun/test.esp8266.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.esp8266.yaml +++ b/tests/components/sun/test.esp8266.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/sun/test.rp2040.yaml b/tests/components/sun/test.rp2040.yaml index e0157424a0..dade44d145 100644 --- a/tests/components/sun/test.rp2040.yaml +++ b/tests/components/sun/test.rp2040.yaml @@ -1,38 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - id: homeassistant_time - -sun: - latitude: 48.8584° - longitude: 2.2945° - on_sunrise: - - then: - - logger.log: Good morning - - elevation: 5° - then: - - logger.log: Good morning again - on_sunset: - - then: - - logger.log: Good evening - -sensor: - - platform: sun - name: Sun Elevation - type: elevation - - platform: sun - name: Sun Azimuth - type: azimuth - -text_sensor: - - platform: sun - name: Sun Next Sunrise - type: sunrise - - platform: sun - name: Sun Next Sunset - type: sunset +<<: !include common.yaml diff --git a/tests/components/thermostat/common.yaml b/tests/components/thermostat/common.yaml new file mode 100644 index 0000000000..d630a93efc --- /dev/null +++ b/tests/components/thermostat/common.yaml @@ -0,0 +1,93 @@ +sensor: + - platform: template + id: thermostat_sensor + lambda: "return 21;" + +climate: + - platform: thermostat + name: Test Thermostat + sensor: thermostat_sensor + humidity_sensor: thermostat_sensor + preset: + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C + idle_action: + - logger.log: idle_action + cool_action: + - logger.log: cool_action + supplemental_cooling_action: + - logger.log: supplemental_cooling_action + heat_action: + - logger.log: heat_action + supplemental_heating_action: + - logger.log: supplemental_heating_action + dry_action: + - logger.log: dry_action + fan_only_action: + - logger.log: fan_only_action + auto_mode: + - logger.log: auto_mode + off_mode: + - logger.log: off_mode + heat_mode: + - logger.log: heat_mode + cool_mode: + - logger.log: cool_mode + dry_mode: + - logger.log: dry_mode + fan_only_mode: + - logger.log: fan_only_mode + fan_mode_auto_action: + - logger.log: fan_mode_auto_action + fan_mode_on_action: + - logger.log: fan_mode_on_action + fan_mode_off_action: + - logger.log: fan_mode_off_action + fan_mode_low_action: + - logger.log: fan_mode_low_action + fan_mode_medium_action: + - logger.log: fan_mode_medium_action + fan_mode_high_action: + - logger.log: fan_mode_high_action + fan_mode_middle_action: + - logger.log: fan_mode_middle_action + fan_mode_focus_action: + - logger.log: fan_mode_focus_action + fan_mode_diffuse_action: + - logger.log: fan_mode_diffuse_action + fan_mode_quiet_action: + - logger.log: fan_mode_quiet_action + swing_off_action: + - logger.log: swing_off_action + swing_horizontal_action: + - logger.log: swing_horizontal_action + swing_vertical_action: + - logger.log: swing_vertical_action + swing_both_action: + - logger.log: swing_both_action + startup_delay: true + supplemental_cooling_delta: 2.0 + cool_deadband: 0.5 + cool_overrun: 0.5 + min_cooling_off_time: 300s + min_cooling_run_time: 300s + max_cooling_run_time: 600s + supplemental_heating_delta: 2.0 + heat_deadband: 0.5 + heat_overrun: 0.5 + min_heating_off_time: 300s + min_heating_run_time: 300s + max_heating_run_time: 600s + min_fanning_off_time: 30s + min_fanning_run_time: 30s + min_fan_mode_switching_time: 15s + min_idle_time: 30s + set_point_minimum_differential: 0.5 + fan_only_action_uses_fan_mode_timer: true + fan_only_cooling: true + fan_with_cooling: true + fan_with_heating: true diff --git a/tests/components/thermostat/test.esp32-c3-idf.yaml b/tests/components/thermostat/test.esp32-c3-idf.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.esp32-c3-idf.yaml +++ b/tests/components/thermostat/test.esp32-c3-idf.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/thermostat/test.esp32-c3.yaml b/tests/components/thermostat/test.esp32-c3.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.esp32-c3.yaml +++ b/tests/components/thermostat/test.esp32-c3.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/thermostat/test.esp32-idf.yaml b/tests/components/thermostat/test.esp32-idf.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.esp32-idf.yaml +++ b/tests/components/thermostat/test.esp32-idf.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/thermostat/test.esp32.yaml b/tests/components/thermostat/test.esp32.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.esp32.yaml +++ b/tests/components/thermostat/test.esp32.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/thermostat/test.esp8266.yaml b/tests/components/thermostat/test.esp8266.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.esp8266.yaml +++ b/tests/components/thermostat/test.esp8266.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/thermostat/test.rp2040.yaml b/tests/components/thermostat/test.rp2040.yaml index d630a93efc..dade44d145 100644 --- a/tests/components/thermostat/test.rp2040.yaml +++ b/tests/components/thermostat/test.rp2040.yaml @@ -1,93 +1 @@ -sensor: - - platform: template - id: thermostat_sensor - lambda: "return 21;" - -climate: - - platform: thermostat - name: Test Thermostat - sensor: thermostat_sensor - humidity_sensor: thermostat_sensor - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - logger.log: idle_action - cool_action: - - logger.log: cool_action - supplemental_cooling_action: - - logger.log: supplemental_cooling_action - heat_action: - - logger.log: heat_action - supplemental_heating_action: - - logger.log: supplemental_heating_action - dry_action: - - logger.log: dry_action - fan_only_action: - - logger.log: fan_only_action - auto_mode: - - logger.log: auto_mode - off_mode: - - logger.log: off_mode - heat_mode: - - logger.log: heat_mode - cool_mode: - - logger.log: cool_mode - dry_mode: - - logger.log: dry_mode - fan_only_mode: - - logger.log: fan_only_mode - fan_mode_auto_action: - - logger.log: fan_mode_auto_action - fan_mode_on_action: - - logger.log: fan_mode_on_action - fan_mode_off_action: - - logger.log: fan_mode_off_action - fan_mode_low_action: - - logger.log: fan_mode_low_action - fan_mode_medium_action: - - logger.log: fan_mode_medium_action - fan_mode_high_action: - - logger.log: fan_mode_high_action - fan_mode_middle_action: - - logger.log: fan_mode_middle_action - fan_mode_focus_action: - - logger.log: fan_mode_focus_action - fan_mode_diffuse_action: - - logger.log: fan_mode_diffuse_action - fan_mode_quiet_action: - - logger.log: fan_mode_quiet_action - swing_off_action: - - logger.log: swing_off_action - swing_horizontal_action: - - logger.log: swing_horizontal_action - swing_vertical_action: - - logger.log: swing_vertical_action - swing_both_action: - - logger.log: swing_both_action - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true +<<: !include common.yaml diff --git a/tests/components/time/common.yaml b/tests/components/time/common.yaml new file mode 100644 index 0000000000..465be045db --- /dev/null +++ b/tests/components/time/common.yaml @@ -0,0 +1,10 @@ +wifi: + ssid: MySSID + password: password1 + +api: + +time: + - platform: homeassistant + - platform: sntp + id: sntp_time diff --git a/tests/components/time/test.esp32-c3-idf.yaml b/tests/components/time/test.esp32-c3-idf.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.esp32-c3-idf.yaml +++ b/tests/components/time/test.esp32-c3-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time/test.esp32-c3.yaml b/tests/components/time/test.esp32-c3.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.esp32-c3.yaml +++ b/tests/components/time/test.esp32-c3.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time/test.esp32-idf.yaml b/tests/components/time/test.esp32-idf.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.esp32-idf.yaml +++ b/tests/components/time/test.esp32-idf.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time/test.esp32.yaml b/tests/components/time/test.esp32.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.esp32.yaml +++ b/tests/components/time/test.esp32.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time/test.esp8266.yaml b/tests/components/time/test.esp8266.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.esp8266.yaml +++ b/tests/components/time/test.esp8266.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time/test.rp2040.yaml b/tests/components/time/test.rp2040.yaml index 465be045db..dade44d145 100644 --- a/tests/components/time/test.rp2040.yaml +++ b/tests/components/time/test.rp2040.yaml @@ -1,10 +1 @@ -wifi: - ssid: MySSID - password: password1 - -api: - -time: - - platform: homeassistant - - platform: sntp - id: sntp_time +<<: !include common.yaml diff --git a/tests/components/time_based/common.yaml b/tests/components/time_based/common.yaml new file mode 100644 index 0000000000..48c86de90f --- /dev/null +++ b/tests/components/time_based/common.yaml @@ -0,0 +1,12 @@ +cover: + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - logger.log: stop_action + open_action: + - logger.log: open_action + open_duration: 5min + close_action: + - logger.log: close_action + close_duration: 4.5min diff --git a/tests/components/time_based/test.esp32-c3-idf.yaml b/tests/components/time_based/test.esp32-c3-idf.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.esp32-c3-idf.yaml +++ b/tests/components/time_based/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/time_based/test.esp32-c3.yaml b/tests/components/time_based/test.esp32-c3.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.esp32-c3.yaml +++ b/tests/components/time_based/test.esp32-c3.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/time_based/test.esp32-idf.yaml b/tests/components/time_based/test.esp32-idf.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.esp32-idf.yaml +++ b/tests/components/time_based/test.esp32-idf.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/time_based/test.esp32.yaml b/tests/components/time_based/test.esp32.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.esp32.yaml +++ b/tests/components/time_based/test.esp32.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/time_based/test.esp8266.yaml b/tests/components/time_based/test.esp8266.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.esp8266.yaml +++ b/tests/components/time_based/test.esp8266.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/time_based/test.rp2040.yaml b/tests/components/time_based/test.rp2040.yaml index 48c86de90f..dade44d145 100644 --- a/tests/components/time_based/test.rp2040.yaml +++ b/tests/components/time_based/test.rp2040.yaml @@ -1,12 +1 @@ -cover: - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - logger.log: stop_action - open_action: - - logger.log: open_action - open_duration: 5min - close_action: - - logger.log: close_action - close_duration: 4.5min +<<: !include common.yaml diff --git a/tests/components/tm1638/common.yaml b/tests/components/tm1638/common.yaml new file mode 100644 index 0000000000..b0c5cef528 --- /dev/null +++ b/tests/components/tm1638/common.yaml @@ -0,0 +1,118 @@ +display: + - platform: tm1638 + id: tm1638_display + stb_pin: 2 + clk_pin: 5 + dio_pin: 4 + update_interval: 5s + intensity: 5 + lambda: |- + it.print("81818181"); + +binary_sensor: + - platform: tm1638 + id: Button0 + key: 0 + filters: + - delayed_on: 10ms + on_press: + then: + - switch.turn_on: Led0 + on_release: + then: + - switch.turn_off: Led0 + - platform: tm1638 + id: Button1 + key: 1 + on_press: + then: + - switch.turn_on: Led1 + on_release: + then: + - switch.turn_off: Led1 + - platform: tm1638 + id: Button2 + key: 2 + on_press: + then: + - switch.turn_on: Led2 + on_release: + then: + - switch.turn_off: Led2 + - platform: tm1638 + id: Button3 + key: 3 + on_press: + then: + - switch.turn_on: Led3 + on_release: + then: + - switch.turn_off: Led3 + - platform: tm1638 + id: Button4 + key: 4 + on_press: + then: + - output.turn_on: Led4 + on_release: + then: + - output.turn_off: Led4 + - platform: tm1638 + id: Button5 + key: 5 + on_press: + then: + - output.turn_on: Led5 + on_release: + then: + - output.turn_off: Led5 + - platform: tm1638 + id: Button6 + key: 6 + on_press: + then: + - output.turn_on: Led6 + on_release: + then: + - output.turn_off: Led6 + - platform: tm1638 + id: Button7 + key: 7 + on_press: + then: + - output.turn_on: Led7 + on_release: + then: + - output.turn_off: Led7 + +switch: + - platform: tm1638 + id: Led0 + led: 0 + name: TM1638Led0 + - platform: tm1638 + id: Led1 + led: 1 + name: TM1638Led1 + - platform: tm1638 + id: Led2 + led: 2 + name: TM1638Led2 + - platform: tm1638 + id: Led3 + led: 3 + name: TM1638Led3 + +output: + - platform: tm1638 + id: Led4 + led: 4 + - platform: tm1638 + id: Led5 + led: 5 + - platform: tm1638 + id: Led6 + led: 6 + - platform: tm1638 + id: Led7 + led: 7 diff --git a/tests/components/tm1638/test.esp32-c3-idf.yaml b/tests/components/tm1638/test.esp32-c3-idf.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.esp32-c3-idf.yaml +++ b/tests/components/tm1638/test.esp32-c3-idf.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1638/test.esp32-c3.yaml b/tests/components/tm1638/test.esp32-c3.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.esp32-c3.yaml +++ b/tests/components/tm1638/test.esp32-c3.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1638/test.esp32-idf.yaml b/tests/components/tm1638/test.esp32-idf.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.esp32-idf.yaml +++ b/tests/components/tm1638/test.esp32-idf.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1638/test.esp32.yaml b/tests/components/tm1638/test.esp32.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.esp32.yaml +++ b/tests/components/tm1638/test.esp32.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1638/test.esp8266.yaml b/tests/components/tm1638/test.esp8266.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.esp8266.yaml +++ b/tests/components/tm1638/test.esp8266.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1638/test.rp2040.yaml b/tests/components/tm1638/test.rp2040.yaml index b0c5cef528..dade44d145 100644 --- a/tests/components/tm1638/test.rp2040.yaml +++ b/tests/components/tm1638/test.rp2040.yaml @@ -1,118 +1 @@ -display: - - platform: tm1638 - id: tm1638_display - stb_pin: 2 - clk_pin: 5 - dio_pin: 4 - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -binary_sensor: - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - -switch: - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -output: - - platform: tm1638 - id: Led4 - led: 4 - - platform: tm1638 - id: Led5 - led: 5 - - platform: tm1638 - id: Led6 - led: 6 - - platform: tm1638 - id: Led7 - led: 7 +<<: !include common.yaml diff --git a/tests/components/tm1651/common.yaml b/tests/components/tm1651/common.yaml new file mode 100644 index 0000000000..667648f4d6 --- /dev/null +++ b/tests/components/tm1651/common.yaml @@ -0,0 +1,21 @@ +tm1651: + id: tm1651_battery + clk_pin: 5 + dio_pin: 4 + +esphome: + on_boot: + then: + - tm1651.set_level_percent: + id: tm1651_battery + level_percent: 50 + - tm1651.set_level: + id: tm1651_battery + level: 5 + - tm1651.set_brightness: + id: tm1651_battery + brightness: 2 + - tm1651.turn_on: + id: tm1651_battery + - tm1651.turn_off: + id: tm1651_battery diff --git a/tests/components/tm1651/test.esp32-c3.yaml b/tests/components/tm1651/test.esp32-c3.yaml index 667648f4d6..dade44d145 100644 --- a/tests/components/tm1651/test.esp32-c3.yaml +++ b/tests/components/tm1651/test.esp32-c3.yaml @@ -1,21 +1 @@ -tm1651: - id: tm1651_battery - clk_pin: 5 - dio_pin: 4 - -esphome: - on_boot: - then: - - tm1651.set_level_percent: - id: tm1651_battery - level_percent: 50 - - tm1651.set_level: - id: tm1651_battery - level: 5 - - tm1651.set_brightness: - id: tm1651_battery - brightness: 2 - - tm1651.turn_on: - id: tm1651_battery - - tm1651.turn_off: - id: tm1651_battery +<<: !include common.yaml diff --git a/tests/components/tm1651/test.esp32.yaml b/tests/components/tm1651/test.esp32.yaml index 667648f4d6..dade44d145 100644 --- a/tests/components/tm1651/test.esp32.yaml +++ b/tests/components/tm1651/test.esp32.yaml @@ -1,21 +1 @@ -tm1651: - id: tm1651_battery - clk_pin: 5 - dio_pin: 4 - -esphome: - on_boot: - then: - - tm1651.set_level_percent: - id: tm1651_battery - level_percent: 50 - - tm1651.set_level: - id: tm1651_battery - level: 5 - - tm1651.set_brightness: - id: tm1651_battery - brightness: 2 - - tm1651.turn_on: - id: tm1651_battery - - tm1651.turn_off: - id: tm1651_battery +<<: !include common.yaml diff --git a/tests/components/tm1651/test.esp8266.yaml b/tests/components/tm1651/test.esp8266.yaml index 667648f4d6..dade44d145 100644 --- a/tests/components/tm1651/test.esp8266.yaml +++ b/tests/components/tm1651/test.esp8266.yaml @@ -1,21 +1 @@ -tm1651: - id: tm1651_battery - clk_pin: 5 - dio_pin: 4 - -esphome: - on_boot: - then: - - tm1651.set_level_percent: - id: tm1651_battery - level_percent: 50 - - tm1651.set_level: - id: tm1651_battery - level: 5 - - tm1651.set_brightness: - id: tm1651_battery - brightness: 2 - - tm1651.turn_on: - id: tm1651_battery - - tm1651.turn_off: - id: tm1651_battery +<<: !include common.yaml diff --git a/tests/components/tm1651/test.rp2040.yaml b/tests/components/tm1651/test.rp2040.yaml index 667648f4d6..dade44d145 100644 --- a/tests/components/tm1651/test.rp2040.yaml +++ b/tests/components/tm1651/test.rp2040.yaml @@ -1,21 +1 @@ -tm1651: - id: tm1651_battery - clk_pin: 5 - dio_pin: 4 - -esphome: - on_boot: - then: - - tm1651.set_level_percent: - id: tm1651_battery - level_percent: 50 - - tm1651.set_level: - id: tm1651_battery - level: 5 - - tm1651.set_brightness: - id: tm1651_battery - brightness: 2 - - tm1651.turn_on: - id: tm1651_battery - - tm1651.turn_off: - id: tm1651_battery +<<: !include common.yaml diff --git a/tests/components/tx20/common.yaml b/tests/components/tx20/common.yaml new file mode 100644 index 0000000000..d826059320 --- /dev/null +++ b/tests/components/tx20/common.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: tx20 + wind_speed: + name: Windspeed + wind_direction_degrees: + name: Winddirection Degrees + pin: 4 diff --git a/tests/components/tx20/test.esp32-c3-idf.yaml b/tests/components/tx20/test.esp32-c3-idf.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.esp32-c3-idf.yaml +++ b/tests/components/tx20/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/tx20/test.esp32-c3.yaml b/tests/components/tx20/test.esp32-c3.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.esp32-c3.yaml +++ b/tests/components/tx20/test.esp32-c3.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/tx20/test.esp32-idf.yaml b/tests/components/tx20/test.esp32-idf.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.esp32-idf.yaml +++ b/tests/components/tx20/test.esp32-idf.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/tx20/test.esp32.yaml b/tests/components/tx20/test.esp32.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.esp32.yaml +++ b/tests/components/tx20/test.esp32.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/tx20/test.esp8266.yaml b/tests/components/tx20/test.esp8266.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.esp8266.yaml +++ b/tests/components/tx20/test.esp8266.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/tx20/test.rp2040.yaml b/tests/components/tx20/test.rp2040.yaml index d826059320..dade44d145 100644 --- a/tests/components/tx20/test.rp2040.yaml +++ b/tests/components/tx20/test.rp2040.yaml @@ -1,7 +1 @@ -sensor: - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: 4 +<<: !include common.yaml diff --git a/tests/components/ultrasonic/common.yaml b/tests/components/ultrasonic/common.yaml new file mode 100644 index 0000000000..f1f673d918 --- /dev/null +++ b/tests/components/ultrasonic/common.yaml @@ -0,0 +1,7 @@ +sensor: + - platform: ultrasonic + id: ultrasonic_sensor1 + name: Ultrasonic Sensor + echo_pin: 4 + trigger_pin: 5 + timeout: 5.5m diff --git a/tests/components/ultrasonic/test.esp32-c3-idf.yaml b/tests/components/ultrasonic/test.esp32-c3-idf.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.esp32-c3-idf.yaml +++ b/tests/components/ultrasonic/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/ultrasonic/test.esp32-c3.yaml b/tests/components/ultrasonic/test.esp32-c3.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.esp32-c3.yaml +++ b/tests/components/ultrasonic/test.esp32-c3.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/ultrasonic/test.esp32-idf.yaml b/tests/components/ultrasonic/test.esp32-idf.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.esp32-idf.yaml +++ b/tests/components/ultrasonic/test.esp32-idf.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/ultrasonic/test.esp32.yaml b/tests/components/ultrasonic/test.esp32.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.esp32.yaml +++ b/tests/components/ultrasonic/test.esp32.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/ultrasonic/test.esp8266.yaml b/tests/components/ultrasonic/test.esp8266.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.esp8266.yaml +++ b/tests/components/ultrasonic/test.esp8266.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/ultrasonic/test.rp2040.yaml b/tests/components/ultrasonic/test.rp2040.yaml index f1f673d918..dade44d145 100644 --- a/tests/components/ultrasonic/test.rp2040.yaml +++ b/tests/components/ultrasonic/test.rp2040.yaml @@ -1,7 +1 @@ -sensor: - - platform: ultrasonic - id: ultrasonic_sensor1 - name: Ultrasonic Sensor - echo_pin: 4 - trigger_pin: 5 - timeout: 5.5m +<<: !include common.yaml diff --git a/tests/components/uptime/common.yaml b/tests/components/uptime/common.yaml new file mode 100644 index 0000000000..872a0e7402 --- /dev/null +++ b/tests/components/uptime/common.yaml @@ -0,0 +1,3 @@ +sensor: + - platform: uptime + name: Uptime Sensor diff --git a/tests/components/uptime/test.esp32-c3-idf.yaml b/tests/components/uptime/test.esp32-c3-idf.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.esp32-c3-idf.yaml +++ b/tests/components/uptime/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/uptime/test.esp32-c3.yaml b/tests/components/uptime/test.esp32-c3.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.esp32-c3.yaml +++ b/tests/components/uptime/test.esp32-c3.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/uptime/test.esp32-idf.yaml b/tests/components/uptime/test.esp32-idf.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.esp32-idf.yaml +++ b/tests/components/uptime/test.esp32-idf.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/uptime/test.esp32.yaml b/tests/components/uptime/test.esp32.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.esp32.yaml +++ b/tests/components/uptime/test.esp32.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/uptime/test.esp8266.yaml b/tests/components/uptime/test.esp8266.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.esp8266.yaml +++ b/tests/components/uptime/test.esp8266.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/uptime/test.rp2040.yaml b/tests/components/uptime/test.rp2040.yaml index 872a0e7402..dade44d145 100644 --- a/tests/components/uptime/test.rp2040.yaml +++ b/tests/components/uptime/test.rp2040.yaml @@ -1,3 +1 @@ -sensor: - - platform: uptime - name: Uptime Sensor +<<: !include common.yaml diff --git a/tests/components/version/common.yaml b/tests/components/version/common.yaml new file mode 100644 index 0000000000..7713afc37c --- /dev/null +++ b/tests/components/version/common.yaml @@ -0,0 +1,3 @@ +text_sensor: + - platform: version + name: "ESPHome Version" diff --git a/tests/components/version/test.esp32-c3-idf.yaml b/tests/components/version/test.esp32-c3-idf.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.esp32-c3-idf.yaml +++ b/tests/components/version/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/version/test.esp32-c3.yaml b/tests/components/version/test.esp32-c3.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.esp32-c3.yaml +++ b/tests/components/version/test.esp32-c3.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/version/test.esp32-idf.yaml b/tests/components/version/test.esp32-idf.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.esp32-idf.yaml +++ b/tests/components/version/test.esp32-idf.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/version/test.esp32.yaml b/tests/components/version/test.esp32.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.esp32.yaml +++ b/tests/components/version/test.esp32.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/version/test.esp8266.yaml b/tests/components/version/test.esp8266.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.esp8266.yaml +++ b/tests/components/version/test.esp8266.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/version/test.rp2040.yaml b/tests/components/version/test.rp2040.yaml index 7713afc37c..dade44d145 100644 --- a/tests/components/version/test.rp2040.yaml +++ b/tests/components/version/test.rp2040.yaml @@ -1,3 +1 @@ -text_sensor: - - platform: version - name: "ESPHome Version" +<<: !include common.yaml diff --git a/tests/components/wake_on_lan/common.yaml b/tests/components/wake_on_lan/common.yaml new file mode 100644 index 0000000000..6a5351b624 --- /dev/null +++ b/tests/components/wake_on_lan/common.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: MySSID + password: password1 + +button: + - platform: wake_on_lan + id: wol_1 + name: wol_test_1 + target_mac_address: 12:34:56:78:90:ab diff --git a/tests/components/wake_on_lan/test.esp32-c3.yaml b/tests/components/wake_on_lan/test.esp32-c3.yaml index 6a5351b624..dade44d145 100644 --- a/tests/components/wake_on_lan/test.esp32-c3.yaml +++ b/tests/components/wake_on_lan/test.esp32-c3.yaml @@ -1,9 +1 @@ -wifi: - ssid: MySSID - password: password1 - -button: - - platform: wake_on_lan - id: wol_1 - name: wol_test_1 - target_mac_address: 12:34:56:78:90:ab +<<: !include common.yaml diff --git a/tests/components/wake_on_lan/test.esp32.yaml b/tests/components/wake_on_lan/test.esp32.yaml index 6a5351b624..dade44d145 100644 --- a/tests/components/wake_on_lan/test.esp32.yaml +++ b/tests/components/wake_on_lan/test.esp32.yaml @@ -1,9 +1 @@ -wifi: - ssid: MySSID - password: password1 - -button: - - platform: wake_on_lan - id: wol_1 - name: wol_test_1 - target_mac_address: 12:34:56:78:90:ab +<<: !include common.yaml diff --git a/tests/components/wake_on_lan/test.esp8266.yaml b/tests/components/wake_on_lan/test.esp8266.yaml index 6a5351b624..dade44d145 100644 --- a/tests/components/wake_on_lan/test.esp8266.yaml +++ b/tests/components/wake_on_lan/test.esp8266.yaml @@ -1,9 +1 @@ -wifi: - ssid: MySSID - password: password1 - -button: - - platform: wake_on_lan - id: wol_1 - name: wol_test_1 - target_mac_address: 12:34:56:78:90:ab +<<: !include common.yaml diff --git a/tests/components/wake_on_lan/test.rp2040.yaml b/tests/components/wake_on_lan/test.rp2040.yaml index 6a5351b624..dade44d145 100644 --- a/tests/components/wake_on_lan/test.rp2040.yaml +++ b/tests/components/wake_on_lan/test.rp2040.yaml @@ -1,9 +1 @@ -wifi: - ssid: MySSID - password: password1 - -button: - - platform: wake_on_lan - id: wol_1 - name: wol_test_1 - target_mac_address: 12:34:56:78:90:ab +<<: !include common.yaml diff --git a/tests/components/web_server/common.yaml b/tests/components/web_server/common.yaml new file mode 100644 index 0000000000..94388726c3 --- /dev/null +++ b/tests/components/web_server/common.yaml @@ -0,0 +1,7 @@ +wifi: + ssid: MySSID + password: password1 + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp32-c3-idf.yaml b/tests/components/web_server/test.esp32-c3-idf.yaml index 94388726c3..dade44d145 100644 --- a/tests/components/web_server/test.esp32-c3-idf.yaml +++ b/tests/components/web_server/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -wifi: - ssid: MySSID - password: password1 - -web_server: - port: 8080 - version: 2 +<<: !include common.yaml diff --git a/tests/components/web_server/test.esp32-c3.yaml b/tests/components/web_server/test.esp32-c3.yaml index 94388726c3..dade44d145 100644 --- a/tests/components/web_server/test.esp32-c3.yaml +++ b/tests/components/web_server/test.esp32-c3.yaml @@ -1,7 +1 @@ -wifi: - ssid: MySSID - password: password1 - -web_server: - port: 8080 - version: 2 +<<: !include common.yaml diff --git a/tests/components/web_server/test.esp32-idf.yaml b/tests/components/web_server/test.esp32-idf.yaml index 94388726c3..dade44d145 100644 --- a/tests/components/web_server/test.esp32-idf.yaml +++ b/tests/components/web_server/test.esp32-idf.yaml @@ -1,7 +1 @@ -wifi: - ssid: MySSID - password: password1 - -web_server: - port: 8080 - version: 2 +<<: !include common.yaml diff --git a/tests/components/web_server/test.esp32.yaml b/tests/components/web_server/test.esp32.yaml index 94388726c3..dade44d145 100644 --- a/tests/components/web_server/test.esp32.yaml +++ b/tests/components/web_server/test.esp32.yaml @@ -1,7 +1 @@ -wifi: - ssid: MySSID - password: password1 - -web_server: - port: 8080 - version: 2 +<<: !include common.yaml diff --git a/tests/components/web_server/test.esp8266.yaml b/tests/components/web_server/test.esp8266.yaml index 94388726c3..dade44d145 100644 --- a/tests/components/web_server/test.esp8266.yaml +++ b/tests/components/web_server/test.esp8266.yaml @@ -1,7 +1 @@ -wifi: - ssid: MySSID - password: password1 - -web_server: - port: 8080 - version: 2 +<<: !include common.yaml diff --git a/tests/components/wiegand/common.yaml b/tests/components/wiegand/common.yaml new file mode 100644 index 0000000000..4e15a44b89 --- /dev/null +++ b/tests/components/wiegand/common.yaml @@ -0,0 +1,10 @@ +wiegand: + - id: test_wiegand + d0: 5 + d1: 4 + on_key: + - lambda: ESP_LOGI("KEY", "Received key %d", x); + on_tag: + - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); + on_raw: + - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); diff --git a/tests/components/wiegand/test.esp32-c3-idf.yaml b/tests/components/wiegand/test.esp32-c3-idf.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.esp32-c3-idf.yaml +++ b/tests/components/wiegand/test.esp32-c3-idf.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wiegand/test.esp32-c3.yaml b/tests/components/wiegand/test.esp32-c3.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.esp32-c3.yaml +++ b/tests/components/wiegand/test.esp32-c3.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wiegand/test.esp32-idf.yaml b/tests/components/wiegand/test.esp32-idf.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.esp32-idf.yaml +++ b/tests/components/wiegand/test.esp32-idf.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wiegand/test.esp32.yaml b/tests/components/wiegand/test.esp32.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.esp32.yaml +++ b/tests/components/wiegand/test.esp32.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wiegand/test.esp8266.yaml b/tests/components/wiegand/test.esp8266.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.esp8266.yaml +++ b/tests/components/wiegand/test.esp8266.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wiegand/test.rp2040.yaml b/tests/components/wiegand/test.rp2040.yaml index 4e15a44b89..dade44d145 100644 --- a/tests/components/wiegand/test.rp2040.yaml +++ b/tests/components/wiegand/test.rp2040.yaml @@ -1,10 +1 @@ -wiegand: - - id: test_wiegand - d0: 5 - d1: 4 - on_key: - - lambda: ESP_LOGI("KEY", "Received key %d", x); - on_tag: - - lambda: ESP_LOGI("TAG", "Received tag %s", x.c_str()); - on_raw: - - lambda: ESP_LOGI("RAW", "Received raw %d bits, value %llx", bits, value); +<<: !include common.yaml diff --git a/tests/components/wifi/common.yaml b/tests/components/wifi/common.yaml new file mode 100644 index 0000000000..003f6347be --- /dev/null +++ b/tests/components/wifi/common.yaml @@ -0,0 +1,9 @@ +esphome: + on_boot: + then: + - wifi.disable + - wifi.enable + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/wifi/test.esp32-c3-idf.yaml b/tests/components/wifi/test.esp32-c3-idf.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.esp32-c3-idf.yaml +++ b/tests/components/wifi/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi/test.esp32-c3.yaml b/tests/components/wifi/test.esp32-c3.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.esp32-c3.yaml +++ b/tests/components/wifi/test.esp32-c3.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi/test.esp32-idf.yaml b/tests/components/wifi/test.esp32-idf.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.esp32-idf.yaml +++ b/tests/components/wifi/test.esp32-idf.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi/test.esp32.yaml b/tests/components/wifi/test.esp32.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.esp32.yaml +++ b/tests/components/wifi/test.esp32.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi/test.esp8266.yaml b/tests/components/wifi/test.esp8266.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.esp8266.yaml +++ b/tests/components/wifi/test.esp8266.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi/test.rp2040.yaml b/tests/components/wifi/test.rp2040.yaml index 003f6347be..dade44d145 100644 --- a/tests/components/wifi/test.rp2040.yaml +++ b/tests/components/wifi/test.rp2040.yaml @@ -1,9 +1 @@ -esphome: - on_boot: - then: - - wifi.disable - - wifi.enable - -wifi: - ssid: MySSID - password: password1 +<<: !include common.yaml diff --git a/tests/components/wifi_info/common.yaml b/tests/components/wifi_info/common.yaml new file mode 100644 index 0000000000..cf5ea563ba --- /dev/null +++ b/tests/components/wifi_info/common.yaml @@ -0,0 +1,18 @@ +wifi: + ssid: MySSID + password: password1 + +text_sensor: + - platform: wifi_info + scan_results: + name: Scan Results + ip_address: + name: IP Address + ssid: + name: SSID + bssid: + name: BSSID + mac_address: + name: Mac Address + dns_address: + name: DNS ADdress diff --git a/tests/components/wifi_info/test.esp32-c3-idf.yaml b/tests/components/wifi_info/test.esp32-c3-idf.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.esp32-c3-idf.yaml +++ b/tests/components/wifi_info/test.esp32-c3-idf.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_info/test.esp32-c3.yaml b/tests/components/wifi_info/test.esp32-c3.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.esp32-c3.yaml +++ b/tests/components/wifi_info/test.esp32-c3.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_info/test.esp32-idf.yaml b/tests/components/wifi_info/test.esp32-idf.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.esp32-idf.yaml +++ b/tests/components/wifi_info/test.esp32-idf.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_info/test.esp32.yaml b/tests/components/wifi_info/test.esp32.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.esp32.yaml +++ b/tests/components/wifi_info/test.esp32.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_info/test.esp8266.yaml b/tests/components/wifi_info/test.esp8266.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.esp8266.yaml +++ b/tests/components/wifi_info/test.esp8266.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_info/test.rp2040.yaml b/tests/components/wifi_info/test.rp2040.yaml index cf5ea563ba..dade44d145 100644 --- a/tests/components/wifi_info/test.rp2040.yaml +++ b/tests/components/wifi_info/test.rp2040.yaml @@ -1,18 +1 @@ -wifi: - ssid: MySSID - password: password1 - -text_sensor: - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress +<<: !include common.yaml diff --git a/tests/components/wifi_signal/common.yaml b/tests/components/wifi_signal/common.yaml new file mode 100644 index 0000000000..58d1cab244 --- /dev/null +++ b/tests/components/wifi_signal/common.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_signal + name: WiFi Signal Sensor + update_interval: 15s diff --git a/tests/components/wifi_signal/test.esp32-c3-idf.yaml b/tests/components/wifi_signal/test.esp32-c3-idf.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.esp32-c3-idf.yaml +++ b/tests/components/wifi_signal/test.esp32-c3-idf.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/wifi_signal/test.esp32-c3.yaml b/tests/components/wifi_signal/test.esp32-c3.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.esp32-c3.yaml +++ b/tests/components/wifi_signal/test.esp32-c3.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/wifi_signal/test.esp32-idf.yaml b/tests/components/wifi_signal/test.esp32-idf.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.esp32-idf.yaml +++ b/tests/components/wifi_signal/test.esp32-idf.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/wifi_signal/test.esp32.yaml b/tests/components/wifi_signal/test.esp32.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.esp32.yaml +++ b/tests/components/wifi_signal/test.esp32.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/wifi_signal/test.esp8266.yaml b/tests/components/wifi_signal/test.esp8266.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.esp8266.yaml +++ b/tests/components/wifi_signal/test.esp8266.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/wifi_signal/test.rp2040.yaml b/tests/components/wifi_signal/test.rp2040.yaml index 58d1cab244..dade44d145 100644 --- a/tests/components/wifi_signal/test.rp2040.yaml +++ b/tests/components/wifi_signal/test.rp2040.yaml @@ -1,8 +1 @@ -wifi: - ssid: MySSID - password: password1 - -sensor: - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s +<<: !include common.yaml diff --git a/tests/components/xiaomi_ble/common.yaml b/tests/components/xiaomi_ble/common.yaml new file mode 100644 index 0000000000..9d10393177 --- /dev/null +++ b/tests/components/xiaomi_ble/common.yaml @@ -0,0 +1,3 @@ +esp32_ble_tracker: + +xiaomi_ble: diff --git a/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml b/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml index 9d10393177..dade44d145 100644 --- a/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_ble/test.esp32-c3-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -xiaomi_ble: +<<: !include common.yaml diff --git a/tests/components/xiaomi_ble/test.esp32-c3.yaml b/tests/components/xiaomi_ble/test.esp32-c3.yaml index 9d10393177..dade44d145 100644 --- a/tests/components/xiaomi_ble/test.esp32-c3.yaml +++ b/tests/components/xiaomi_ble/test.esp32-c3.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -xiaomi_ble: +<<: !include common.yaml diff --git a/tests/components/xiaomi_ble/test.esp32-idf.yaml b/tests/components/xiaomi_ble/test.esp32-idf.yaml index 9d10393177..dade44d145 100644 --- a/tests/components/xiaomi_ble/test.esp32-idf.yaml +++ b/tests/components/xiaomi_ble/test.esp32-idf.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -xiaomi_ble: +<<: !include common.yaml diff --git a/tests/components/xiaomi_ble/test.esp32.yaml b/tests/components/xiaomi_ble/test.esp32.yaml index 9d10393177..dade44d145 100644 --- a/tests/components/xiaomi_ble/test.esp32.yaml +++ b/tests/components/xiaomi_ble/test.esp32.yaml @@ -1,3 +1 @@ -esp32_ble_tracker: - -xiaomi_ble: +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgd1/common.yaml b/tests/components/xiaomi_cgd1/common.yaml new file mode 100644 index 0000000000..94ed09e8f2 --- /dev/null +++ b/tests/components/xiaomi_cgd1/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgd1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml index 94ed09e8f2..dade44d145 100644 --- a/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_cgd1/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgd1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgd1/test.esp32-c3.yaml b/tests/components/xiaomi_cgd1/test.esp32-c3.yaml index 94ed09e8f2..dade44d145 100644 --- a/tests/components/xiaomi_cgd1/test.esp32-c3.yaml +++ b/tests/components/xiaomi_cgd1/test.esp32-c3.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgd1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgd1/test.esp32-idf.yaml b/tests/components/xiaomi_cgd1/test.esp32-idf.yaml index 94ed09e8f2..dade44d145 100644 --- a/tests/components/xiaomi_cgd1/test.esp32-idf.yaml +++ b/tests/components/xiaomi_cgd1/test.esp32-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgd1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgd1/test.esp32.yaml b/tests/components/xiaomi_cgd1/test.esp32.yaml index 94ed09e8f2..dade44d145 100644 --- a/tests/components/xiaomi_cgd1/test.esp32.yaml +++ b/tests/components/xiaomi_cgd1/test.esp32.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgd1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgdk2/common.yaml b/tests/components/xiaomi_cgdk2/common.yaml new file mode 100644 index 0000000000..dddca56222 --- /dev/null +++ b/tests/components/xiaomi_cgdk2/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgdk2 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml index dddca56222..dade44d145 100644 --- a/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_cgdk2/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgdk2 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml b/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml index dddca56222..dade44d145 100644 --- a/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml +++ b/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgdk2 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml b/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml index dddca56222..dade44d145 100644 --- a/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml +++ b/tests/components/xiaomi_cgdk2/test.esp32-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgdk2 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgdk2/test.esp32.yaml b/tests/components/xiaomi_cgdk2/test.esp32.yaml index dddca56222..dade44d145 100644 --- a/tests/components/xiaomi_cgdk2/test.esp32.yaml +++ b/tests/components/xiaomi_cgdk2/test.esp32.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgdk2 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgg1/common.yaml b/tests/components/xiaomi_cgg1/common.yaml new file mode 100644 index 0000000000..170aebfbde --- /dev/null +++ b/tests/components/xiaomi_cgg1/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_cgg1 + mac_address: A4:C1:38:D1:61:7D + bindkey: c99d2313182473b38001086febf781bd + temperature: + name: Xiaomi CGD1 Temperature + humidity: + name: Xiaomi CGD1 Humidity + battery_level: + name: Xiaomi CGD1 Battery Level diff --git a/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml index 170aebfbde..dade44d145 100644 --- a/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_cgg1/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgg1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgg1/test.esp32-c3.yaml b/tests/components/xiaomi_cgg1/test.esp32-c3.yaml index 170aebfbde..dade44d145 100644 --- a/tests/components/xiaomi_cgg1/test.esp32-c3.yaml +++ b/tests/components/xiaomi_cgg1/test.esp32-c3.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgg1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgg1/test.esp32-idf.yaml b/tests/components/xiaomi_cgg1/test.esp32-idf.yaml index 170aebfbde..dade44d145 100644 --- a/tests/components/xiaomi_cgg1/test.esp32-idf.yaml +++ b/tests/components/xiaomi_cgg1/test.esp32-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgg1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgg1/test.esp32.yaml b/tests/components/xiaomi_cgg1/test.esp32.yaml index 170aebfbde..dade44d145 100644 --- a/tests/components/xiaomi_cgg1/test.esp32.yaml +++ b/tests/components/xiaomi_cgg1/test.esp32.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_cgg1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgpr1/common.yaml b/tests/components/xiaomi_cgpr1/common.yaml new file mode 100644 index 0000000000..48082a886c --- /dev/null +++ b/tests/components/xiaomi_cgpr1/common.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_cgpr1 + name: CGPR1 Motion + mac_address: "12:34:56:12:34:56" + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + battery_level: + name: CGPR1 battery Level + idle_time: + name: CGPR1 Idle Time + illuminance: + name: CGPR1 Illuminance diff --git a/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml b/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml index 48082a886c..dade44d145 100644 --- a/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_cgpr1/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_cgpr1 - name: CGPR1 Motion - mac_address: "12:34:56:12:34:56" - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - battery_level: - name: CGPR1 battery Level - idle_time: - name: CGPR1 Idle Time - illuminance: - name: CGPR1 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml b/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml index 48082a886c..dade44d145 100644 --- a/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml +++ b/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_cgpr1 - name: CGPR1 Motion - mac_address: "12:34:56:12:34:56" - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - battery_level: - name: CGPR1 battery Level - idle_time: - name: CGPR1 Idle Time - illuminance: - name: CGPR1 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml b/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml index 48082a886c..dade44d145 100644 --- a/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml +++ b/tests/components/xiaomi_cgpr1/test.esp32-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_cgpr1 - name: CGPR1 Motion - mac_address: "12:34:56:12:34:56" - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - battery_level: - name: CGPR1 battery Level - idle_time: - name: CGPR1 Idle Time - illuminance: - name: CGPR1 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_cgpr1/test.esp32.yaml b/tests/components/xiaomi_cgpr1/test.esp32.yaml index 48082a886c..dade44d145 100644 --- a/tests/components/xiaomi_cgpr1/test.esp32.yaml +++ b/tests/components/xiaomi_cgpr1/test.esp32.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_cgpr1 - name: CGPR1 Motion - mac_address: "12:34:56:12:34:56" - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - battery_level: - name: CGPR1 battery Level - idle_time: - name: CGPR1 Idle Time - illuminance: - name: CGPR1 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_gcls002/common.yaml b/tests/components/xiaomi_gcls002/common.yaml new file mode 100644 index 0000000000..32990708cc --- /dev/null +++ b/tests/components/xiaomi_gcls002/common.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_gcls002 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: GCLS02 Temperature + moisture: + name: GCLS02 Moisture + conductivity: + name: GCLS02 Soil Conductivity + illuminance: + name: GCLS02 Illuminance diff --git a/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml b/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml index 32990708cc..dade44d145 100644 --- a/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_gcls002/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_gcls002 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: GCLS02 Temperature - moisture: - name: GCLS02 Moisture - conductivity: - name: GCLS02 Soil Conductivity - illuminance: - name: GCLS02 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_gcls002/test.esp32-c3.yaml b/tests/components/xiaomi_gcls002/test.esp32-c3.yaml index 32990708cc..dade44d145 100644 --- a/tests/components/xiaomi_gcls002/test.esp32-c3.yaml +++ b/tests/components/xiaomi_gcls002/test.esp32-c3.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_gcls002 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: GCLS02 Temperature - moisture: - name: GCLS02 Moisture - conductivity: - name: GCLS02 Soil Conductivity - illuminance: - name: GCLS02 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_gcls002/test.esp32-idf.yaml b/tests/components/xiaomi_gcls002/test.esp32-idf.yaml index 32990708cc..dade44d145 100644 --- a/tests/components/xiaomi_gcls002/test.esp32-idf.yaml +++ b/tests/components/xiaomi_gcls002/test.esp32-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_gcls002 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: GCLS02 Temperature - moisture: - name: GCLS02 Moisture - conductivity: - name: GCLS02 Soil Conductivity - illuminance: - name: GCLS02 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_gcls002/test.esp32.yaml b/tests/components/xiaomi_gcls002/test.esp32.yaml index 32990708cc..dade44d145 100644 --- a/tests/components/xiaomi_gcls002/test.esp32.yaml +++ b/tests/components/xiaomi_gcls002/test.esp32.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_gcls002 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: GCLS02 Temperature - moisture: - name: GCLS02 Moisture - conductivity: - name: GCLS02 Soil Conductivity - illuminance: - name: GCLS02 Illuminance +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccjcy01/common.yaml b/tests/components/xiaomi_hhccjcy01/common.yaml new file mode 100644 index 0000000000..0def909488 --- /dev/null +++ b/tests/components/xiaomi_hhccjcy01/common.yaml @@ -0,0 +1,15 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccjcy01 + mac_address: 94:2B:FF:5C:91:61 + temperature: + name: Xiaomi HHCCJCY01 Temperature + moisture: + name: Xiaomi HHCCJCY01 Moisture + illuminance: + name: Xiaomi HHCCJCY01 Illuminance + conductivity: + name: Xiaomi HHCCJCY01 Soil Conductivity + battery_level: + name: Xiaomi HHCCJCY01 Battery Level diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml index 0def909488..dade44d145 100644 --- a/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-c3-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccjcy01 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: Xiaomi HHCCJCY01 Temperature - moisture: - name: Xiaomi HHCCJCY01 Moisture - illuminance: - name: Xiaomi HHCCJCY01 Illuminance - conductivity: - name: Xiaomi HHCCJCY01 Soil Conductivity - battery_level: - name: Xiaomi HHCCJCY01 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml index 0def909488..dade44d145 100644 --- a/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccjcy01 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: Xiaomi HHCCJCY01 Temperature - moisture: - name: Xiaomi HHCCJCY01 Moisture - illuminance: - name: Xiaomi HHCCJCY01 Illuminance - conductivity: - name: Xiaomi HHCCJCY01 Soil Conductivity - battery_level: - name: Xiaomi HHCCJCY01 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml index 0def909488..dade44d145 100644 --- a/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml +++ b/tests/components/xiaomi_hhccjcy01/test.esp32-idf.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccjcy01 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: Xiaomi HHCCJCY01 Temperature - moisture: - name: Xiaomi HHCCJCY01 Moisture - illuminance: - name: Xiaomi HHCCJCY01 Illuminance - conductivity: - name: Xiaomi HHCCJCY01 Soil Conductivity - battery_level: - name: Xiaomi HHCCJCY01 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32.yaml index 0def909488..dade44d145 100644 --- a/tests/components/xiaomi_hhccjcy01/test.esp32.yaml +++ b/tests/components/xiaomi_hhccjcy01/test.esp32.yaml @@ -1,15 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccjcy01 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: Xiaomi HHCCJCY01 Temperature - moisture: - name: Xiaomi HHCCJCY01 Moisture - illuminance: - name: Xiaomi HHCCJCY01 Illuminance - conductivity: - name: Xiaomi HHCCJCY01 Soil Conductivity - battery_level: - name: Xiaomi HHCCJCY01 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccpot002/common.yaml b/tests/components/xiaomi_hhccpot002/common.yaml new file mode 100644 index 0000000000..2e5fa14620 --- /dev/null +++ b/tests/components/xiaomi_hhccpot002/common.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_hhccpot002 + mac_address: 94:2B:FF:5C:91:61 + moisture: + name: HHCCPOT002 Moisture + conductivity: + name: HHCCPOT002 Soil Conductivity diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml index 2e5fa14620..dade44d145 100644 --- a/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_hhccpot002/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccpot002 - mac_address: 94:2B:FF:5C:91:61 - moisture: - name: HHCCPOT002 Moisture - conductivity: - name: HHCCPOT002 Soil Conductivity +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml index 2e5fa14620..dade44d145 100644 --- a/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml +++ b/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccpot002 - mac_address: 94:2B:FF:5C:91:61 - moisture: - name: HHCCPOT002 Moisture - conductivity: - name: HHCCPOT002 Soil Conductivity +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml index 2e5fa14620..dade44d145 100644 --- a/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml +++ b/tests/components/xiaomi_hhccpot002/test.esp32-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccpot002 - mac_address: 94:2B:FF:5C:91:61 - moisture: - name: HHCCPOT002 Moisture - conductivity: - name: HHCCPOT002 Soil Conductivity +<<: !include common.yaml diff --git a/tests/components/xiaomi_hhccpot002/test.esp32.yaml b/tests/components/xiaomi_hhccpot002/test.esp32.yaml index 2e5fa14620..dade44d145 100644 --- a/tests/components/xiaomi_hhccpot002/test.esp32.yaml +++ b/tests/components/xiaomi_hhccpot002/test.esp32.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_hhccpot002 - mac_address: 94:2B:FF:5C:91:61 - moisture: - name: HHCCPOT002 Moisture - conductivity: - name: HHCCPOT002 Soil Conductivity +<<: !include common.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/common.yaml b/tests/components/xiaomi_jqjcy01ym/common.yaml new file mode 100644 index 0000000000..54c4b33dcd --- /dev/null +++ b/tests/components/xiaomi_jqjcy01ym/common.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_jqjcy01ym + mac_address: 7A:80:8E:19:36:BA + temperature: + name: JQJCY01YM Temperature + humidity: + name: JQJCY01YM Humidity + formaldehyde: + name: JQJCY01YM Formaldehyde + battery_level: + name: JQJCY01YM Battery Level diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml index 54c4b33dcd..dade44d145 100644 --- a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_jqjcy01ym - mac_address: 7A:80:8E:19:36:BA - temperature: - name: JQJCY01YM Temperature - humidity: - name: JQJCY01YM Humidity - formaldehyde: - name: JQJCY01YM Formaldehyde - battery_level: - name: JQJCY01YM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml index 54c4b33dcd..dade44d145 100644 --- a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_jqjcy01ym - mac_address: 7A:80:8E:19:36:BA - temperature: - name: JQJCY01YM Temperature - humidity: - name: JQJCY01YM Humidity - formaldehyde: - name: JQJCY01YM Formaldehyde - battery_level: - name: JQJCY01YM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml index 54c4b33dcd..dade44d145 100644 --- a/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_jqjcy01ym - mac_address: 7A:80:8E:19:36:BA - temperature: - name: JQJCY01YM Temperature - humidity: - name: JQJCY01YM Humidity - formaldehyde: - name: JQJCY01YM Formaldehyde - battery_level: - name: JQJCY01YM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml index 54c4b33dcd..dade44d145 100644 --- a/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml +++ b/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_jqjcy01ym - mac_address: 7A:80:8E:19:36:BA - temperature: - name: JQJCY01YM Temperature - humidity: - name: JQJCY01YM Humidity - formaldehyde: - name: JQJCY01YM Formaldehyde - battery_level: - name: JQJCY01YM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02/common.yaml b/tests/components/xiaomi_lywsd02/common.yaml new file mode 100644 index 0000000000..3e40ab8d70 --- /dev/null +++ b/tests/components/xiaomi_lywsd02/common.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02 + mac_address: 3F:5B:7D:82:58:4E + temperature: + name: Xiaomi LYWSD02 Temperature + humidity: + name: Xiaomi LYWSD02 Humidity + battery_level: + name: Xiaomi LYWSD02 Battery Level diff --git a/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml index 3e40ab8d70..dade44d145 100644 --- a/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_lywsd02/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd02 - mac_address: 3F:5B:7D:82:58:4E - temperature: - name: Xiaomi LYWSD02 Temperature - humidity: - name: Xiaomi LYWSD02 Humidity - battery_level: - name: Xiaomi LYWSD02 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml index 3e40ab8d70..dade44d145 100644 --- a/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml +++ b/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd02 - mac_address: 3F:5B:7D:82:58:4E - temperature: - name: Xiaomi LYWSD02 Temperature - humidity: - name: Xiaomi LYWSD02 Humidity - battery_level: - name: Xiaomi LYWSD02 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml b/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml index 3e40ab8d70..dade44d145 100644 --- a/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml +++ b/tests/components/xiaomi_lywsd02/test.esp32-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd02 - mac_address: 3F:5B:7D:82:58:4E - temperature: - name: Xiaomi LYWSD02 Temperature - humidity: - name: Xiaomi LYWSD02 Humidity - battery_level: - name: Xiaomi LYWSD02 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02/test.esp32.yaml b/tests/components/xiaomi_lywsd02/test.esp32.yaml index 3e40ab8d70..dade44d145 100644 --- a/tests/components/xiaomi_lywsd02/test.esp32.yaml +++ b/tests/components/xiaomi_lywsd02/test.esp32.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd02 - mac_address: 3F:5B:7D:82:58:4E - temperature: - name: Xiaomi LYWSD02 Temperature - humidity: - name: Xiaomi LYWSD02 Humidity - battery_level: - name: Xiaomi LYWSD02 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/common.yaml b/tests/components/xiaomi_lywsd03mmc/common.yaml new file mode 100644 index 0000000000..d10a859c56 --- /dev/null +++ b/tests/components/xiaomi_lywsd03mmc/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd03mmc + mac_address: A4:C1:38:4E:16:78 + bindkey: e9efaa6873f9f9c87a5e75a5f814801c + temperature: + name: Xiaomi LYWSD03MMC Temperature + humidity: + name: Xiaomi LYWSD03MMC Humidity + battery_level: + name: Xiaomi LYWSD03MMC Battery Level diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml index d10a859c56..dade44d145 100644 --- a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd03mmc - mac_address: A4:C1:38:4E:16:78 - bindkey: e9efaa6873f9f9c87a5e75a5f814801c - temperature: - name: Xiaomi LYWSD03MMC Temperature - humidity: - name: Xiaomi LYWSD03MMC Humidity - battery_level: - name: Xiaomi LYWSD03MMC Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml index d10a859c56..dade44d145 100644 --- a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd03mmc - mac_address: A4:C1:38:4E:16:78 - bindkey: e9efaa6873f9f9c87a5e75a5f814801c - temperature: - name: Xiaomi LYWSD03MMC Temperature - humidity: - name: Xiaomi LYWSD03MMC Humidity - battery_level: - name: Xiaomi LYWSD03MMC Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml index d10a859c56..dade44d145 100644 --- a/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd03mmc - mac_address: A4:C1:38:4E:16:78 - bindkey: e9efaa6873f9f9c87a5e75a5f814801c - temperature: - name: Xiaomi LYWSD03MMC Temperature - humidity: - name: Xiaomi LYWSD03MMC Humidity - battery_level: - name: Xiaomi LYWSD03MMC Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml index d10a859c56..dade44d145 100644 --- a/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml +++ b/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsd03mmc - mac_address: A4:C1:38:4E:16:78 - bindkey: e9efaa6873f9f9c87a5e75a5f814801c - temperature: - name: Xiaomi LYWSD03MMC Temperature - humidity: - name: Xiaomi LYWSD03MMC Humidity - battery_level: - name: Xiaomi LYWSD03MMC Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsdcgq/common.yaml b/tests/components/xiaomi_lywsdcgq/common.yaml new file mode 100644 index 0000000000..d8422b4c0c --- /dev/null +++ b/tests/components/xiaomi_lywsdcgq/common.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsdcgq + mac_address: 7A:80:8E:19:36:BA + temperature: + name: Xiaomi LYWSDCGQ Temperature + humidity: + name: Xiaomi LYWSDCGQ Humidity + battery_level: + name: Xiaomi LYWSDCGQ Battery Level diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml index d8422b4c0c..dade44d145 100644 --- a/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsdcgq - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi LYWSDCGQ Temperature - humidity: - name: Xiaomi LYWSDCGQ Humidity - battery_level: - name: Xiaomi LYWSDCGQ Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml index d8422b4c0c..dade44d145 100644 --- a/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsdcgq - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi LYWSDCGQ Temperature - humidity: - name: Xiaomi LYWSDCGQ Humidity - battery_level: - name: Xiaomi LYWSDCGQ Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml index d8422b4c0c..dade44d145 100644 --- a/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml +++ b/tests/components/xiaomi_lywsdcgq/test.esp32-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsdcgq - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi LYWSDCGQ Temperature - humidity: - name: Xiaomi LYWSDCGQ Humidity - battery_level: - name: Xiaomi LYWSDCGQ Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32.yaml index d8422b4c0c..dade44d145 100644 --- a/tests/components/xiaomi_lywsdcgq/test.esp32.yaml +++ b/tests/components/xiaomi_lywsdcgq/test.esp32.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_lywsdcgq - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi LYWSDCGQ Temperature - humidity: - name: Xiaomi LYWSDCGQ Humidity - battery_level: - name: Xiaomi LYWSDCGQ Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc303/common.yaml b/tests/components/xiaomi_mhoc303/common.yaml new file mode 100644 index 0000000000..e4353d3c6a --- /dev/null +++ b/tests/components/xiaomi_mhoc303/common.yaml @@ -0,0 +1,11 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc303 + mac_address: E7:50:59:32:A0:1C + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml index e4353d3c6a..dade44d145 100644 --- a/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_mhoc303/test.esp32-c3-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc303 - mac_address: E7:50:59:32:A0:1C - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml index e4353d3c6a..dade44d145 100644 --- a/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml +++ b/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc303 - mac_address: E7:50:59:32:A0:1C - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml b/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml index e4353d3c6a..dade44d145 100644 --- a/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml +++ b/tests/components/xiaomi_mhoc303/test.esp32-idf.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc303 - mac_address: E7:50:59:32:A0:1C - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc303/test.esp32.yaml b/tests/components/xiaomi_mhoc303/test.esp32.yaml index e4353d3c6a..dade44d145 100644 --- a/tests/components/xiaomi_mhoc303/test.esp32.yaml +++ b/tests/components/xiaomi_mhoc303/test.esp32.yaml @@ -1,11 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc303 - mac_address: E7:50:59:32:A0:1C - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc401/common.yaml b/tests/components/xiaomi_mhoc401/common.yaml new file mode 100644 index 0000000000..ae378f5604 --- /dev/null +++ b/tests/components/xiaomi_mhoc401/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_mhoc401 + mac_address: E7:50:59:32:A0:1C + bindkey: "eef418daf699a0c188f3bfd17e4565d9" + temperature: + name: MHO-C303 Temperature + humidity: + name: MHO-C303 Humidity + battery_level: + name: MHO-C303 Battery Level diff --git a/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml index ae378f5604..dade44d145 100644 --- a/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_mhoc401/test.esp32-c3-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc401 - mac_address: E7:50:59:32:A0:1C - bindkey: "eef418daf699a0c188f3bfd17e4565d9" - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml index ae378f5604..dade44d145 100644 --- a/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml +++ b/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc401 - mac_address: E7:50:59:32:A0:1C - bindkey: "eef418daf699a0c188f3bfd17e4565d9" - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml b/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml index ae378f5604..dade44d145 100644 --- a/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml +++ b/tests/components/xiaomi_mhoc401/test.esp32-idf.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc401 - mac_address: E7:50:59:32:A0:1C - bindkey: "eef418daf699a0c188f3bfd17e4565d9" - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mhoc401/test.esp32.yaml b/tests/components/xiaomi_mhoc401/test.esp32.yaml index ae378f5604..dade44d145 100644 --- a/tests/components/xiaomi_mhoc401/test.esp32.yaml +++ b/tests/components/xiaomi_mhoc401/test.esp32.yaml @@ -1,12 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_mhoc401 - mac_address: E7:50:59:32:A0:1C - bindkey: "eef418daf699a0c188f3bfd17e4565d9" - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale copy/common.yaml b/tests/components/xiaomi_miscale copy/common.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale copy/common.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml b/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_miscale copy/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml b/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml +++ b/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml b/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml +++ b/tests/components/xiaomi_miscale copy/test.esp32-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale copy/test.esp32.yaml b/tests/components/xiaomi_miscale copy/test.esp32.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale copy/test.esp32.yaml +++ b/tests/components/xiaomi_miscale copy/test.esp32.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale/common.yaml b/tests/components/xiaomi_miscale/common.yaml new file mode 100644 index 0000000000..89f32ad199 --- /dev/null +++ b/tests/components/xiaomi_miscale/common.yaml @@ -0,0 +1,9 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_miscale + mac_address: '5C:CA:D3:70:D4:A2' + weight: + name: "Xiaomi Mi Scale Weight" + impedance: + name: "Xiaomi Mi Scale Impedance" diff --git a/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml b/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_miscale/test.esp32-c3-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale/test.esp32-c3.yaml b/tests/components/xiaomi_miscale/test.esp32-c3.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale/test.esp32-c3.yaml +++ b/tests/components/xiaomi_miscale/test.esp32-c3.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale/test.esp32-idf.yaml b/tests/components/xiaomi_miscale/test.esp32-idf.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale/test.esp32-idf.yaml +++ b/tests/components/xiaomi_miscale/test.esp32-idf.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_miscale/test.esp32.yaml b/tests/components/xiaomi_miscale/test.esp32.yaml index 89f32ad199..dade44d145 100644 --- a/tests/components/xiaomi_miscale/test.esp32.yaml +++ b/tests/components/xiaomi_miscale/test.esp32.yaml @@ -1,9 +1 @@ -esp32_ble_tracker: - -sensor: - - platform: xiaomi_miscale - mac_address: '5C:CA:D3:70:D4:A2' - weight: - name: "Xiaomi Mi Scale Weight" - impedance: - name: "Xiaomi Mi Scale Impedance" +<<: !include common.yaml diff --git a/tests/components/xiaomi_mjyd02yla/common.yaml b/tests/components/xiaomi_mjyd02yla/common.yaml new file mode 100644 index 0000000000..dffcef84c4 --- /dev/null +++ b/tests/components/xiaomi_mjyd02yla/common.yaml @@ -0,0 +1,13 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mjyd02yla + name: MJYD02YL-A Motion + mac_address: 50:EC:50:CD:32:02 + bindkey: 48403ebe2d385db8d0c187f81e62cb64 + idle_time: + name: MJYD02YL-A Idle Time + light: + name: MJYD02YL-A Light Status + battery_level: + name: MJYD02YL-A Battery Level diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml index dffcef84c4..dade44d145 100644 --- a/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-c3-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mjyd02yla - name: MJYD02YL-A Motion - mac_address: 50:EC:50:CD:32:02 - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - idle_time: - name: MJYD02YL-A Idle Time - light: - name: MJYD02YL-A Light Status - battery_level: - name: MJYD02YL-A Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml index dffcef84c4..dade44d145 100644 --- a/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mjyd02yla - name: MJYD02YL-A Motion - mac_address: 50:EC:50:CD:32:02 - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - idle_time: - name: MJYD02YL-A Idle Time - light: - name: MJYD02YL-A Light Status - battery_level: - name: MJYD02YL-A Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml index dffcef84c4..dade44d145 100644 --- a/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml +++ b/tests/components/xiaomi_mjyd02yla/test.esp32-idf.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mjyd02yla - name: MJYD02YL-A Motion - mac_address: 50:EC:50:CD:32:02 - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - idle_time: - name: MJYD02YL-A Idle Time - light: - name: MJYD02YL-A Light Status - battery_level: - name: MJYD02YL-A Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32.yaml index dffcef84c4..dade44d145 100644 --- a/tests/components/xiaomi_mjyd02yla/test.esp32.yaml +++ b/tests/components/xiaomi_mjyd02yla/test.esp32.yaml @@ -1,13 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mjyd02yla - name: MJYD02YL-A Motion - mac_address: 50:EC:50:CD:32:02 - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - idle_time: - name: MJYD02YL-A Idle Time - light: - name: MJYD02YL-A Light Status - battery_level: - name: MJYD02YL-A Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_mue4094rt/common.yaml b/tests/components/xiaomi_mue4094rt/common.yaml new file mode 100644 index 0000000000..4f0e5ccbae --- /dev/null +++ b/tests/components/xiaomi_mue4094rt/common.yaml @@ -0,0 +1,7 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_mue4094rt + name: MUE4094RT Motion + mac_address: 7A:80:8E:19:36:BA + timeout: 5s diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml index 4f0e5ccbae..dade44d145 100644 --- a/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_mue4094rt/test.esp32-c3-idf.yaml @@ -1,7 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mue4094rt - name: MUE4094RT Motion - mac_address: 7A:80:8E:19:36:BA - timeout: 5s +<<: !include common.yaml diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml index 4f0e5ccbae..dade44d145 100644 --- a/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml +++ b/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml @@ -1,7 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mue4094rt - name: MUE4094RT Motion - mac_address: 7A:80:8E:19:36:BA - timeout: 5s +<<: !include common.yaml diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml index 4f0e5ccbae..dade44d145 100644 --- a/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml +++ b/tests/components/xiaomi_mue4094rt/test.esp32-idf.yaml @@ -1,7 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mue4094rt - name: MUE4094RT Motion - mac_address: 7A:80:8E:19:36:BA - timeout: 5s +<<: !include common.yaml diff --git a/tests/components/xiaomi_mue4094rt/test.esp32.yaml b/tests/components/xiaomi_mue4094rt/test.esp32.yaml index 4f0e5ccbae..dade44d145 100644 --- a/tests/components/xiaomi_mue4094rt/test.esp32.yaml +++ b/tests/components/xiaomi_mue4094rt/test.esp32.yaml @@ -1,7 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_mue4094rt - name: MUE4094RT Motion - mac_address: 7A:80:8E:19:36:BA - timeout: 5s +<<: !include common.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/common.yaml b/tests/components/xiaomi_rtcgq02lm/common.yaml new file mode 100644 index 0000000000..a2e0c66ba5 --- /dev/null +++ b/tests/components/xiaomi_rtcgq02lm/common.yaml @@ -0,0 +1,22 @@ +esp32_ble_tracker: + +xiaomi_rtcgq02lm: + - id: motion_rtcgq02lm + mac_address: 01:02:03:04:05:06 + bindkey: "48403ebe2d385db8d0c187f81e62cb64" + +binary_sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + motion: + name: Mi Motion Sensor 2 + light: + name: Mi Motion Sensor 2 Light + button: + name: Mi Motion Sensor 2 Button + +sensor: + - platform: xiaomi_rtcgq02lm + id: motion_rtcgq02lm + battery_level: + name: Mi Motion Sensor 2 Battery level diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml index a2e0c66ba5..dade44d145 100644 --- a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-idf.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -xiaomi_rtcgq02lm: - - id: motion_rtcgq02lm - mac_address: 01:02:03:04:05:06 - bindkey: "48403ebe2d385db8d0c187f81e62cb64" - -binary_sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - motion: - name: Mi Motion Sensor 2 - light: - name: Mi Motion Sensor 2 Light - button: - name: Mi Motion Sensor 2 Button - -sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - battery_level: - name: Mi Motion Sensor 2 Battery level +<<: !include common.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml index a2e0c66ba5..dade44d145 100644 --- a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -xiaomi_rtcgq02lm: - - id: motion_rtcgq02lm - mac_address: 01:02:03:04:05:06 - bindkey: "48403ebe2d385db8d0c187f81e62cb64" - -binary_sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - motion: - name: Mi Motion Sensor 2 - light: - name: Mi Motion Sensor 2 Light - button: - name: Mi Motion Sensor 2 Button - -sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - battery_level: - name: Mi Motion Sensor 2 Battery level +<<: !include common.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml index a2e0c66ba5..dade44d145 100644 --- a/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32-idf.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -xiaomi_rtcgq02lm: - - id: motion_rtcgq02lm - mac_address: 01:02:03:04:05:06 - bindkey: "48403ebe2d385db8d0c187f81e62cb64" - -binary_sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - motion: - name: Mi Motion Sensor 2 - light: - name: Mi Motion Sensor 2 Light - button: - name: Mi Motion Sensor 2 Button - -sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - battery_level: - name: Mi Motion Sensor 2 Battery level +<<: !include common.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml index a2e0c66ba5..dade44d145 100644 --- a/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml +++ b/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml @@ -1,22 +1 @@ -esp32_ble_tracker: - -xiaomi_rtcgq02lm: - - id: motion_rtcgq02lm - mac_address: 01:02:03:04:05:06 - bindkey: "48403ebe2d385db8d0c187f81e62cb64" - -binary_sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - motion: - name: Mi Motion Sensor 2 - light: - name: Mi Motion Sensor 2 Light - button: - name: Mi Motion Sensor 2 Button - -sensor: - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - battery_level: - name: Mi Motion Sensor 2 Battery level +<<: !include common.yaml diff --git a/tests/components/xiaomi_wx08zm/common.yaml b/tests/components/xiaomi_wx08zm/common.yaml new file mode 100644 index 0000000000..3e83ad3e95 --- /dev/null +++ b/tests/components/xiaomi_wx08zm/common.yaml @@ -0,0 +1,10 @@ +esp32_ble_tracker: + +binary_sensor: + - platform: xiaomi_wx08zm + name: WX08ZM Activation State + mac_address: 74:a3:4a:b5:07:34 + tablet: + name: WX08ZM Tablet Resource + battery_level: + name: WX08ZM Battery Level diff --git a/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml b/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml index 3e83ad3e95..dade44d145 100644 --- a/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml +++ b/tests/components/xiaomi_wx08zm/test.esp32-c3-idf.yaml @@ -1,10 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_wx08zm - name: WX08ZM Activation State - mac_address: 74:a3:4a:b5:07:34 - tablet: - name: WX08ZM Tablet Resource - battery_level: - name: WX08ZM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml b/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml index 3e83ad3e95..dade44d145 100644 --- a/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml +++ b/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml @@ -1,10 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_wx08zm - name: WX08ZM Activation State - mac_address: 74:a3:4a:b5:07:34 - tablet: - name: WX08ZM Tablet Resource - battery_level: - name: WX08ZM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml b/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml index 3e83ad3e95..dade44d145 100644 --- a/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml +++ b/tests/components/xiaomi_wx08zm/test.esp32-idf.yaml @@ -1,10 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_wx08zm - name: WX08ZM Activation State - mac_address: 74:a3:4a:b5:07:34 - tablet: - name: WX08ZM Tablet Resource - battery_level: - name: WX08ZM Battery Level +<<: !include common.yaml diff --git a/tests/components/xiaomi_wx08zm/test.esp32.yaml b/tests/components/xiaomi_wx08zm/test.esp32.yaml index 3e83ad3e95..dade44d145 100644 --- a/tests/components/xiaomi_wx08zm/test.esp32.yaml +++ b/tests/components/xiaomi_wx08zm/test.esp32.yaml @@ -1,10 +1 @@ -esp32_ble_tracker: - -binary_sensor: - - platform: xiaomi_wx08zm - name: WX08ZM Activation State - mac_address: 74:a3:4a:b5:07:34 - tablet: - name: WX08ZM Tablet Resource - battery_level: - name: WX08ZM Battery Level +<<: !include common.yaml From b545d5723672f14aacfa839f91f8333df27fa83d Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Wed, 8 May 2024 08:13:15 +1000 Subject: [PATCH 1684/2607] Make `pulse_meter` PULSE filter report the pulse as soon as it can (#6014) --- .../components/pulse_meter/pulse_filter.md | 61 ++++++++++++++++ .../pulse_meter/pulse_meter_sensor.cpp | 73 +++++++++++-------- .../pulse_meter/pulse_meter_sensor.h | 20 ++++- 3 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 esphome/components/pulse_meter/pulse_filter.md diff --git a/esphome/components/pulse_meter/pulse_filter.md b/esphome/components/pulse_meter/pulse_filter.md new file mode 100644 index 0000000000..240c479d54 --- /dev/null +++ b/esphome/components/pulse_meter/pulse_filter.md @@ -0,0 +1,61 @@ +# PULSE Filter + +The PULSE filter filters noisy pulses by ensuring that the pulse is in a steady state for at least `filter_length` before allowing the state change to occur. +It counts the pulse time from the rising edge that stayed high for at least `filter_length`, so noise before this won't be considered the start of a pulse. +It then must see a low pulse that is at least `filter_length` long before a subsequent rising edge is considered a new pulse start. + +It's operation should be the same as delayed_on_off from the Binary Sensor component. + +There are three moving parts in the algorithm that are used to determine the state of the filter. + +1. The time between interrupts, measured from the last interrupt, this is compared to filter_length to determine if the pulse has been in a steady state for long enough. +2. A latch variable that is set true when a high pulse is long enough to be considered a valid pulse and is reset when a low pulse is long enough to allow for another pulse to begin. +3. The previous and current state of the pin used to determine if the pulse is rising or falling. + +## Ghost interrupts + +Observations from the devices show that even though the interrupt should trigger on every rising or falling edge, sometimes interrupts show the same state twice in a row. +The current theory is an interprets occurs, but then the pin changing back faster than the ISR can be called and read the value, meaning it sees the same state twice in a row. +The algorithm interprets these when it sees them as two edges in a row, so will potentially reset a pulse if + +## Pulse Filter Truth table + +The following is all of the possible states of the filter along with the new inputs. +It also shows a diagram of a possible series of interrupts that would cause the filter to enter that state. +It then has the action that the filter should take and a description of what is happening. + +Diagram legend + +- `/` rising edge +- `\` falling edge +- `‾` high steady state of at least `filter_length` +- `_` low steady state of at least `filter_length` +- `¦` ghost interrupt + +| Length | Latch | From | To | Diagram | Action | Description | +| ------ | ----- | ---- | --- | ------- | ------------------ | ---------------------------------------------------------------------------------------------------- | +| T | 1 | 0 | 0 | `‾\_¦ ` | Reset | `filter_length` low, reset the latch | +| T | 1 | 0 | 1 | `‾\_/ ` | Reset, Rising Edge | `filter_length` low, reset the latch, rising edge could be a new pulse | +| T | 1 | 1 | 0 | `‾\/‾\` | - | Already latched from a previous `filter_length` high | +| T | 1 | 1 | 1 | `‾\/‾¦` | - | Already latched from a previous `filter_length` high | +| T | 0 | 1 | 1 | `_/‾¦` | Set and Publish | `filter_length` high, set the latch and publish the pulse | +| T | 0 | 1 | 0 | `_/‾\ ` | Set and Publish | `filter_length` high, set the latch and publish the pulse | +| T | 0 | 0 | 1 | `_/\_/` | Rising Edge | Already unlatched from a previous `filter_length` low | +| T | 0 | 0 | 0 | `_/\_¦` | - | Already unlatched from a previous `filter_length` low | +| F | 1 | 0 | 0 | `‾\¦ ` | - | Low was not long enough to reset the latch | +| F | 1 | 0 | 1 | `‾\/ ` | - | Low was not long enough to reset the latch | +| F | 1 | 1 | 0 | `‾\/\ ` | - | Low was not long enough to reset the latch | +| F | 1 | 1 | 1 | `‾¦ ` | - | Ghost of 0 length definitely was not long was not long enough to reset the latch | +| F | 0 | 1 | 1 | `_/¦ ` | Rising Edge | High was not long enough to set the latch, but the second half of the ghost can be a new rising edge | +| F | 0 | 1 | 0 | `_/\ ` | - | High was not long enough to set the latch | +| F | 0 | 0 | 1 | `_/\/ ` | Rising Edge | High was not long enough to set the latch, but this may be a rising edge | +| F | 0 | 0 | 0 | `_¦ ` | - | Ghost of 0 length definitely was not long was not long enough to set the latch | + +## Startup + +On startup the filter should not consider whatever state it is in as valid so it does not count a strange pulse. +There are two possible starting configurations, either the pin is high or the pin is low. +If the pin is high, the subsequent falling edge should not count as a pulse as we never saw the rising edge. +Therefore we start in the latched state. +If the pin is low, the subsequent rising edge can be counted as the first pulse. +Therefore we start in the unlatched state. diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 14f8e508b5..530425563c 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -24,11 +24,16 @@ void PulseMeterSensor::setup() { if (this->filter_mode_ == FILTER_EDGE) { this->pin_->attach_interrupt(PulseMeterSensor::edge_intr, this, gpio::INTERRUPT_RISING_EDGE); } else if (this->filter_mode_ == FILTER_PULSE) { + // Set the pin value to the current value to avoid a false edge + this->pulse_state_.last_pin_val_ = this->isr_pin_.digital_read(); + this->pulse_state_.latched_ = this->pulse_state_.last_pin_val_; this->pin_->attach_interrupt(PulseMeterSensor::pulse_intr, this, gpio::INTERRUPT_ANY_EDGE); } } void PulseMeterSensor::loop() { + const uint32_t now = micros(); + // Reset the count in get before we pass it back to the ISR as set this->get_->count_ = 0; @@ -38,6 +43,20 @@ void PulseMeterSensor::loop() { this->set_ = this->get_; this->get_ = temp; + // If an edge was peeked, repay the debt + if (this->peeked_edge_ && this->get_->count_ > 0) { + this->peeked_edge_ = false; + this->get_->count_--; + } + + // If there is an unprocessed edge, and filter_us_ has passed since, count this edge early + if (this->get_->last_rising_edge_us_ != this->get_->last_detected_edge_us_ && + now - this->get_->last_rising_edge_us_ >= this->filter_us_) { + this->peeked_edge_ = true; + this->get_->last_detected_edge_us_ = this->get_->last_rising_edge_us_; + this->get_->count_++; + } + // Check if we detected a pulse this loop if (this->get_->count_ > 0) { // Keep a running total of pulses if a total sensor is configured @@ -64,7 +83,6 @@ void PulseMeterSensor::loop() { } // No detected edges this loop else { - const uint32_t now = micros(); const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_; switch (this->meter_state_) { @@ -102,11 +120,14 @@ void IRAM_ATTR PulseMeterSensor::edge_intr(PulseMeterSensor *sensor) { // This is an interrupt handler - we can't call any virtual method from this method // Get the current time before we do anything else so the measurements are consistent const uint32_t now = micros(); + auto &state = sensor->edge_state_; + auto &set = *sensor->set_; - if ((now - sensor->last_edge_candidate_us_) >= sensor->filter_us_) { - sensor->last_edge_candidate_us_ = now; - sensor->set_->last_detected_edge_us_ = now; - sensor->set_->count_++; + if ((now - state.last_sent_edge_us_) >= sensor->filter_us_) { + state.last_sent_edge_us_ = now; + set.last_detected_edge_us_ = now; + set.last_rising_edge_us_ = now; + set.count_++; } } @@ -115,33 +136,27 @@ void IRAM_ATTR PulseMeterSensor::pulse_intr(PulseMeterSensor *sensor) { // Get the current time before we do anything else so the measurements are consistent const uint32_t now = micros(); const bool pin_val = sensor->isr_pin_.digital_read(); + auto &state = sensor->pulse_state_; + auto &set = *sensor->set_; - // A pulse occurred faster than we can detect - if (sensor->last_pin_val_ == pin_val) { - // If we haven't reached the filter length yet we need to reset our last_intr_ to now - // otherwise we can consider this noise as the "pulse" was certainly less than filter_us_ - if (now - sensor->last_intr_ < sensor->filter_us_) { - sensor->last_intr_ = now; - } - } else { - // Check if the last interrupt was long enough in the past - if (now - sensor->last_intr_ > sensor->filter_us_) { - // High pulse of filter length now falling (therefore last_intr_ was the rising edge) - if (!sensor->in_pulse_ && sensor->last_pin_val_) { - sensor->last_edge_candidate_us_ = sensor->last_intr_; - sensor->in_pulse_ = true; - } - // Low pulse of filter length now rising (therefore last_intr_ was the falling edge) - else if (sensor->in_pulse_ && !sensor->last_pin_val_) { - sensor->set_->last_detected_edge_us_ = sensor->last_edge_candidate_us_; - sensor->set_->count_++; - sensor->in_pulse_ = false; - } - } + // Filter length has passed since the last interrupt + const bool length = now - state.last_intr_ >= sensor->filter_us_; - sensor->last_intr_ = now; - sensor->last_pin_val_ = pin_val; + if (length && state.latched_ && !state.last_pin_val_) { // Long enough low edge + state.latched_ = false; + } else if (length && !state.latched_ && state.last_pin_val_) { // Long enough high edge + state.latched_ = true; + set.last_detected_edge_us_ = state.last_intr_; + set.count_++; } + + // Due to order of operations this includes + // length && latched && rising (just reset from a long low edge) + // !latched && (rising || high) (noise on the line resetting the potential rising edge) + set.last_rising_edge_us_ = !state.latched_ && pin_val ? now : set.last_detected_edge_us_; + + state.last_intr_ = now; + state.last_pin_val_ = pin_val; } } // namespace pulse_meter diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index 1cd02e3ca2..76c4a35f03 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -43,6 +43,7 @@ class PulseMeterSensor : public sensor::Sensor, public Component { // Variables used in the loop enum class MeterState { INITIAL, RUNNING, TIMED_OUT }; MeterState meter_state_ = MeterState::INITIAL; + bool peeked_edge_ = false; uint32_t total_pulses_ = 0; uint32_t last_processed_edge_us_ = 0; @@ -53,6 +54,7 @@ class PulseMeterSensor : public sensor::Sensor, public Component { // (except for resetting the values) struct State { uint32_t last_detected_edge_us_ = 0; + uint32_t last_rising_edge_us_ = 0; uint32_t count_ = 0; }; State state_[2]; @@ -61,10 +63,20 @@ class PulseMeterSensor : public sensor::Sensor, public Component { // Only use these variables in the ISR ISRInternalGPIOPin isr_pin_; - uint32_t last_edge_candidate_us_ = 0; - uint32_t last_intr_ = 0; - bool in_pulse_ = false; - bool last_pin_val_ = false; + + /// Filter state for edge mode + struct EdgeState { + uint32_t last_sent_edge_us_ = 0; + }; + EdgeState edge_state_{}; + + /// Filter state for pulse mode + struct PulseState { + uint32_t last_intr_ = 0; + bool latched_ = false; + bool last_pin_val_ = false; + }; + PulseState pulse_state_{}; }; } // namespace pulse_meter From d9fca585a2972d4d4d041d87c9ee1bc4a41b925c Mon Sep 17 00:00:00 2001 From: esphomebot Date: Wed, 8 May 2024 11:57:03 +1200 Subject: [PATCH 1685/2607] Update webserver local assets to 20240507-231331 (#6696) --- .../components/web_server/server_index_v3.h | 7968 +++++++++-------- 1 file changed, 3993 insertions(+), 3975 deletions(-) diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index a7ad3ab543..66cd9de47a 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -10,3986 +10,4004 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0xeb, 0x7a, 0x1b, 0xb7, 0xb2, 0x20, 0xfa, - 0xfb, 0xcc, 0x53, 0x48, 0xbd, 0x1d, 0xa5, 0x21, 0x82, 0x2d, 0x92, 0xba, 0x58, 0x6e, 0x0a, 0xe2, 0xf8, 0x1a, 0x3b, - 0x71, 0x6c, 0xc7, 0x72, 0xec, 0xd8, 0x0c, 0xb7, 0x02, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, - 0xe4, 0xbb, 0x9f, 0xaf, 0x70, 0xe9, 0x46, 0x93, 0xb4, 0xd7, 0x5a, 0x73, 0x66, 0xce, 0x37, 0x3b, 0x7b, 0x59, 0x6c, - 0xdc, 0x51, 0x28, 0x14, 0xaa, 0x0a, 0x55, 0x85, 0x8b, 0xfd, 0x91, 0xcc, 0xf4, 0xdd, 0x9c, 0xed, 0x4d, 0xf5, 0x2c, - 0xbf, 0xbc, 0x70, 0xff, 0x32, 0x3a, 0xba, 0xbc, 0xc8, 0xb9, 0xf8, 0xbc, 0x57, 0xb0, 0x9c, 0xf0, 0x4c, 0x8a, 0xbd, - 0x69, 0xc1, 0xc6, 0x64, 0x44, 0x35, 0x4d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xe5, 0xc5, 0x8c, 0x69, 0xba, 0x97, - 0x4d, 0x69, 0xa1, 0x98, 0x26, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbf, 0xbc, 0x50, 0x59, 0xc1, 0xe7, 0x7a, 0x0f, 0x9a, - 0x24, 0x33, 0x39, 0x5a, 0xe4, 0xec, 0xf2, 0xe8, 0xe8, 0xe6, 0xe6, 0x26, 0xf9, 0x5b, 0xfd, 0x8f, 0x2f, 0xb4, 0xd8, - 0xfb, 0xa5, 0x20, 0xaf, 0x87, 0x7f, 0xb3, 0x4c, 0x27, 0x23, 0x36, 0xe6, 0x82, 0xbd, 0x29, 0xe4, 0x9c, 0x15, 0xfa, - 0xae, 0x0b, 0x99, 0x3f, 0x15, 0x24, 0xe6, 0x58, 0x63, 0x86, 0xc8, 0xa5, 0xde, 0xe3, 0x62, 0x8f, 0xf7, 0x7e, 0x29, - 0x4c, 0xca, 0x92, 0x89, 0xc5, 0x8c, 0x15, 0x74, 0x98, 0xb3, 0x74, 0xbf, 0x85, 0x33, 0x29, 0xc6, 0x7c, 0xb2, 0x28, - 0xbf, 0x6f, 0x0a, 0xae, 0xfd, 0xef, 0x2f, 0x34, 0x5f, 0xb0, 0x94, 0xad, 0x51, 0xca, 0xfb, 0x7a, 0x40, 0x98, 0x69, - 0xf9, 0x73, 0xd5, 0x70, 0xfc, 0x93, 0x69, 0xf2, 0x6e, 0xce, 0xe4, 0x78, 0x4f, 0xef, 0x93, 0x48, 0xdd, 0xcd, 0x86, - 0x32, 0x8f, 0x7a, 0xba, 0x11, 0x45, 0x29, 0x94, 0xc1, 0x0c, 0x75, 0x33, 0x29, 0x94, 0xde, 0x13, 0x9c, 0xdc, 0x70, - 0x31, 0x92, 0x37, 0xf8, 0x46, 0x10, 0xc1, 0x93, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x83, 0x83, 0xd8, - 0x7d, 0xdf, 0x3d, 0xbe, 0xba, 0x22, 0x84, 0x7c, 0x91, 0x7c, 0xb4, 0xd7, 0x5a, 0xad, 0x82, 0xd4, 0x44, 0x50, 0xcd, - 0xbf, 0x30, 0x5b, 0x09, 0x1d, 0x1c, 0x44, 0x74, 0x24, 0xe7, 0x9a, 0x8d, 0xae, 0xf4, 0x5d, 0xce, 0xae, 0xa6, 0x8c, - 0x69, 0x15, 0x71, 0xb1, 0xf7, 0x44, 0x66, 0x8b, 0x19, 0x13, 0x3a, 0x99, 0x17, 0x52, 0x4b, 0x18, 0xd8, 0xc1, 0x41, - 0x54, 0xb0, 0x79, 0x4e, 0x33, 0x06, 0xf9, 0x8f, 0xaf, 0xae, 0xaa, 0x1a, 0x55, 0x21, 0xfc, 0x59, 0x90, 0x2b, 0x33, - 0xf4, 0x18, 0xe1, 0x0f, 0x82, 0x08, 0x76, 0xb3, 0xf7, 0x81, 0xd1, 0xcf, 0xbf, 0xd2, 0x79, 0x37, 0xcb, 0xa9, 0x52, - 0x7b, 0xcf, 0xe4, 0xd2, 0x4c, 0xa3, 0x58, 0x64, 0x5a, 0x16, 0xb1, 0xc6, 0x0c, 0x0b, 0xb4, 0xe4, 0xe3, 0x58, 0x4f, - 0xb9, 0x4a, 0xae, 0xef, 0x65, 0x4a, 0xbd, 0x65, 0x6a, 0x91, 0xeb, 0x7b, 0x64, 0xbf, 0x85, 0xc5, 0x3e, 0x21, 0x9f, - 0x05, 0xd2, 0xd3, 0x42, 0xde, 0xec, 0x3d, 0x2d, 0x0a, 0x59, 0xc4, 0xd1, 0xe3, 0xab, 0x2b, 0x5b, 0x62, 0x8f, 0xab, - 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0xbf, 0x16, 0x42, 0xd1, 0x31, 0x7b, - 0x7c, 0x75, 0xf5, 0xd7, 0x9e, 0x2c, 0xf6, 0xfe, 0xca, 0x94, 0xfa, 0x6b, 0x8f, 0x0b, 0xa5, 0x19, 0x1d, 0x25, 0x11, - 0xea, 0x9a, 0xce, 0x32, 0xa5, 0xde, 0xb1, 0x5b, 0x4d, 0x34, 0x36, 0x9f, 0x9a, 0xb0, 0xf5, 0x84, 0xe9, 0x3d, 0x55, - 0xce, 0x2b, 0x46, 0xcb, 0x9c, 0xe9, 0x3d, 0x4d, 0x4c, 0xbe, 0x74, 0xf0, 0x67, 0xf6, 0x53, 0x77, 0xf9, 0x38, 0xbe, - 0x11, 0x07, 0x07, 0xba, 0x04, 0x34, 0x5a, 0xba, 0x15, 0x22, 0x6c, 0xdf, 0xa7, 0x1d, 0x1c, 0xb0, 0x24, 0x67, 0x62, - 0xa2, 0xa7, 0x84, 0x90, 0x76, 0x57, 0x1c, 0x1c, 0xc4, 0x9a, 0x7c, 0x10, 0xc9, 0x84, 0xe9, 0x98, 0x21, 0x84, 0xab, - 0xda, 0x07, 0x07, 0xb1, 0x05, 0x82, 0x24, 0xda, 0x00, 0xae, 0x06, 0x63, 0x94, 0x38, 0xe8, 0x5f, 0xdd, 0x89, 0x2c, - 0x0e, 0xc7, 0x8f, 0xb0, 0x38, 0x38, 0xf8, 0x20, 0x12, 0x05, 0x2d, 0x62, 0x8d, 0xd0, 0xba, 0x60, 0x7a, 0x51, 0x88, - 0x3d, 0xbd, 0xd6, 0xf2, 0x4a, 0x17, 0x5c, 0x4c, 0x62, 0xb4, 0xf4, 0x69, 0x41, 0xc5, 0xf5, 0xda, 0x0e, 0xf7, 0xb7, - 0x82, 0x70, 0x72, 0x09, 0x3d, 0x3e, 0x93, 0xb1, 0xc3, 0x41, 0x4e, 0x48, 0xa4, 0x4c, 0xdd, 0xa8, 0xc7, 0x53, 0xde, - 0x88, 0x22, 0x6c, 0x47, 0x89, 0x3f, 0x0b, 0x84, 0xb9, 0x06, 0xd4, 0x4d, 0x92, 0x44, 0x23, 0x72, 0xb9, 0xf4, 0x60, - 0xe1, 0xc1, 0x44, 0x7b, 0xbc, 0xdf, 0x1a, 0xa4, 0x3a, 0x29, 0xd8, 0x68, 0x91, 0xb1, 0x38, 0x16, 0x58, 0x61, 0x89, - 0xc8, 0xa5, 0x68, 0xc4, 0x05, 0xb9, 0x84, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xb9, 0x41, 0x16, 0x7e, - 0x84, 0x00, 0x62, 0x37, 0xa0, 0x82, 0x90, 0x48, 0x2c, 0x66, 0x43, 0x56, 0x44, 0x65, 0xb1, 0x6e, 0x0d, 0x2f, 0x16, - 0x8a, 0xed, 0x65, 0x4a, 0xed, 0x8d, 0x17, 0x22, 0xd3, 0x5c, 0x8a, 0xbd, 0xa8, 0x51, 0x34, 0x22, 0x8b, 0x0f, 0x25, - 0x3a, 0x44, 0x68, 0x8d, 0x62, 0x85, 0x1a, 0xbc, 0x2f, 0x1b, 0xed, 0x01, 0x86, 0x51, 0xa2, 0xae, 0x6b, 0xcf, 0x41, - 0x80, 0x61, 0x0e, 0x93, 0x5c, 0xe3, 0x4f, 0x76, 0xe7, 0xc3, 0x14, 0x6f, 0x44, 0x8f, 0x27, 0xdb, 0x3b, 0x85, 0xe8, - 0x64, 0x46, 0xe7, 0x31, 0x23, 0x97, 0xcc, 0x60, 0x17, 0x15, 0x19, 0x8c, 0xb5, 0xb6, 0x70, 0x3d, 0x96, 0xb2, 0xa4, - 0xc2, 0x29, 0x94, 0xea, 0x64, 0x2c, 0x8b, 0xa7, 0x34, 0x9b, 0x42, 0xbd, 0x12, 0x63, 0x46, 0x7e, 0xc3, 0x65, 0x05, - 0xa3, 0x9a, 0x3d, 0xcd, 0x19, 0x7c, 0xc5, 0x91, 0xa9, 0x19, 0x21, 0xac, 0x60, 0xab, 0xe7, 0x5c, 0xbf, 0x92, 0x22, - 0x63, 0x5d, 0x15, 0xe0, 0x97, 0x59, 0xf9, 0x87, 0x5a, 0x17, 0x7c, 0xb8, 0xd0, 0x2c, 0x8e, 0x04, 0x94, 0x88, 0xb0, - 0x42, 0x58, 0x24, 0x9a, 0xdd, 0xea, 0xc7, 0x52, 0x68, 0x26, 0x34, 0x61, 0x1e, 0xaa, 0x98, 0x27, 0x74, 0x3e, 0x67, - 0x62, 0xf4, 0x78, 0xca, 0xf3, 0x51, 0x2c, 0xd0, 0x1a, 0xad, 0xf1, 0xef, 0x82, 0xc0, 0x24, 0xc9, 0x25, 0x4f, 0xe1, - 0x9f, 0x6f, 0x4f, 0x27, 0xd6, 0xe4, 0xd2, 0x6c, 0x0b, 0x46, 0xa2, 0xa8, 0x3b, 0x96, 0x45, 0xec, 0xa6, 0xb0, 0x07, - 0xa4, 0x0b, 0xfa, 0x78, 0xbb, 0xc8, 0x99, 0x42, 0xac, 0x41, 0x44, 0xb9, 0x8e, 0x0e, 0xc2, 0xbf, 0x15, 0x31, 0x83, - 0x05, 0xe0, 0x28, 0xe5, 0x86, 0x04, 0xbe, 0xe4, 0x6e, 0x53, 0x8d, 0x4a, 0xa2, 0xf6, 0x51, 0x90, 0x11, 0x4f, 0x74, - 0xb1, 0x50, 0x9a, 0x8d, 0xde, 0xdd, 0xcd, 0x99, 0xc2, 0x3f, 0x17, 0xe4, 0xa3, 0xe8, 0x7d, 0x14, 0x09, 0x9b, 0xcd, - 0xf5, 0xdd, 0x95, 0xa1, 0xe6, 0x69, 0x14, 0xe1, 0x7f, 0x4c, 0xd1, 0x82, 0xd1, 0x0c, 0x48, 0x9a, 0x03, 0xd9, 0x1b, - 0x99, 0xdf, 0x8d, 0x79, 0x9e, 0x5f, 0x2d, 0xe6, 0x73, 0x59, 0x68, 0xac, 0x05, 0x59, 0x6a, 0x59, 0xc1, 0x07, 0x56, - 0x74, 0xa9, 0x6e, 0xb8, 0xce, 0xa6, 0xb1, 0x46, 0xcb, 0x8c, 0x2a, 0xb6, 0xf7, 0x48, 0xca, 0x9c, 0x51, 0x91, 0x72, - 0xc2, 0x7b, 0x3f, 0x17, 0xa9, 0x58, 0xe4, 0x79, 0x77, 0x58, 0x30, 0xfa, 0xb9, 0x6b, 0xb2, 0xed, 0xe1, 0x90, 0x9a, - 0xdf, 0x0f, 0x8b, 0x82, 0xde, 0x41, 0x41, 0x42, 0xa0, 0x58, 0x8f, 0xa7, 0x3f, 0x5f, 0xbd, 0x7e, 0x95, 0xd8, 0xbd, - 0xc2, 0xc7, 0x77, 0x31, 0x2f, 0xf7, 0x1f, 0x5f, 0xe3, 0x71, 0x21, 0x67, 0x1b, 0x5d, 0x5b, 0xd0, 0xf1, 0xee, 0x37, - 0x86, 0xc0, 0x08, 0xdf, 0xb7, 0x4d, 0x87, 0x23, 0x78, 0x65, 0x30, 0x1f, 0x32, 0x89, 0xeb, 0x17, 0xfe, 0x49, 0x6d, - 0x72, 0xcc, 0xd1, 0xf7, 0x47, 0xab, 0x8b, 0xbb, 0x25, 0x23, 0x66, 0x9c, 0x73, 0x38, 0x18, 0x61, 0x8c, 0x19, 0xd5, - 0xd9, 0x74, 0xc9, 0x4c, 0x63, 0x6b, 0x3f, 0x62, 0xb6, 0x5e, 0xe3, 0xaf, 0xd2, 0x63, 0xbd, 0xde, 0x27, 0x84, 0x1b, - 0x7a, 0x45, 0xf4, 0x6a, 0xc5, 0x09, 0xe1, 0x08, 0xbf, 0xe5, 0x64, 0x49, 0xfd, 0x84, 0xe0, 0x64, 0x83, 0xed, 0x99, - 0x5a, 0x2a, 0x03, 0x27, 0xe0, 0x17, 0x56, 0x68, 0x56, 0xa4, 0x5a, 0xe0, 0x82, 0x8d, 0x73, 0x18, 0xc7, 0x7e, 0x1b, - 0x4f, 0xa9, 0x7a, 0x3c, 0xa5, 0x62, 0xc2, 0x46, 0xe9, 0x57, 0xb9, 0xc6, 0x4c, 0x90, 0x68, 0xcc, 0x05, 0xcd, 0xf9, - 0x57, 0x36, 0x8a, 0xdc, 0xb9, 0xf0, 0x48, 0xef, 0xb1, 0x5b, 0xcd, 0xc4, 0x48, 0xed, 0x3d, 0x7f, 0xf7, 0xeb, 0x4b, - 0xb7, 0x98, 0xb5, 0xb3, 0x02, 0x2d, 0xd5, 0x62, 0xce, 0x8a, 0x18, 0x61, 0x77, 0x56, 0x3c, 0xe5, 0x86, 0x4e, 0xfe, - 0x4a, 0xe7, 0x36, 0x85, 0xab, 0xdf, 0xe7, 0x23, 0xaa, 0xd9, 0x1b, 0x26, 0x46, 0x5c, 0x4c, 0xc8, 0x7e, 0xdb, 0xa6, - 0x4f, 0xa9, 0xcb, 0x18, 0x95, 0x49, 0xd7, 0xf7, 0x9e, 0xe6, 0x66, 0xee, 0xe5, 0xe7, 0x22, 0x46, 0x6b, 0xa5, 0xa9, - 0xe6, 0xd9, 0x1e, 0x1d, 0x8d, 0x5e, 0x08, 0xae, 0xb9, 0x19, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xec, 0xa9, 0xe1, - 0x47, 0x1e, 0x23, 0x1c, 0xc7, 0xee, 0x2c, 0x98, 0x22, 0xb7, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb1, 0xd4, 0x66, - 0x92, 0xfe, 0x00, 0x25, 0xf3, 0x85, 0x82, 0xc5, 0xf6, 0x5d, 0xc0, 0x41, 0x23, 0x87, 0x8a, 0x15, 0x5f, 0xd8, 0xa8, - 0x44, 0x10, 0x15, 0xa3, 0xe5, 0x46, 0x1f, 0x6e, 0x7b, 0x68, 0xd2, 0x1f, 0x74, 0x43, 0x12, 0xce, 0x1c, 0xb2, 0x5b, - 0x4e, 0x85, 0x33, 0x55, 0x12, 0x95, 0x18, 0x0e, 0xd4, 0x92, 0xb0, 0x28, 0xe2, 0xe7, 0x37, 0x8f, 0x05, 0xf0, 0x10, - 0x21, 0xe5, 0xf0, 0x67, 0xee, 0xd3, 0x2f, 0xe6, 0xf0, 0x50, 0x58, 0x20, 0xac, 0xed, 0x48, 0x15, 0x42, 0x6b, 0x84, - 0xb5, 0x1f, 0xae, 0x25, 0x4a, 0x9e, 0x2f, 0x82, 0x53, 0x9b, 0xbc, 0xe5, 0xe6, 0xd8, 0x06, 0xda, 0x46, 0x35, 0x3b, - 0x38, 0x88, 0x59, 0x52, 0x22, 0x06, 0xd9, 0x6f, 0xbb, 0x45, 0x0a, 0xa0, 0xf5, 0x8d, 0x71, 0x43, 0xcf, 0x86, 0xc1, - 0xd9, 0x67, 0x89, 0x90, 0x0f, 0xb3, 0x8c, 0x29, 0x25, 0x8b, 0x83, 0x83, 0x7d, 0x53, 0xbe, 0xe4, 0x2c, 0x60, 0x11, - 0x5f, 0xdf, 0x88, 0x6a, 0x08, 0xa8, 0x3a, 0x6d, 0x3d, 0xdf, 0x44, 0x2a, 0xbe, 0xc9, 0x33, 0x21, 0x69, 0x74, 0x7d, - 0x1d, 0x35, 0x34, 0x76, 0x70, 0x98, 0x30, 0xdf, 0xf5, 0xdd, 0x13, 0x66, 0xd9, 0x42, 0xc3, 0x84, 0x6c, 0x81, 0x66, - 0x27, 0x3f, 0x18, 0xd7, 0x87, 0x84, 0x35, 0x56, 0x68, 0x1d, 0xac, 0xe8, 0xce, 0xa6, 0x0d, 0x7f, 0x63, 0x97, 0x6e, - 0x39, 0x31, 0x3c, 0x45, 0xb0, 0x8e, 0x7d, 0x36, 0x58, 0x63, 0x03, 0x7b, 0x3f, 0x1b, 0x69, 0x06, 0xda, 0xd7, 0x83, - 0xae, 0xcb, 0x27, 0xca, 0x42, 0xae, 0x60, 0xff, 0x2c, 0x98, 0xd2, 0x16, 0x91, 0x63, 0x8d, 0x25, 0x86, 0x33, 0x6a, - 0x93, 0xe9, 0xac, 0xb1, 0xa4, 0xbb, 0xc6, 0xf6, 0x7a, 0x0e, 0x67, 0xa3, 0x02, 0xa4, 0xfe, 0x3e, 0x3e, 0xc1, 0x58, - 0x35, 0x5a, 0xad, 0xde, 0x72, 0xdf, 0x4a, 0xb5, 0x96, 0x25, 0xbf, 0xb6, 0xb1, 0x28, 0x4c, 0x20, 0x77, 0x38, 0xef, - 0xb7, 0xdd, 0xf8, 0xc5, 0x80, 0xec, 0xb7, 0x4a, 0x2c, 0x76, 0x60, 0xb5, 0xe3, 0xb1, 0x50, 0x7c, 0x6d, 0x9b, 0x42, - 0xe6, 0xac, 0xaf, 0xe1, 0x4b, 0x32, 0xdd, 0xc2, 0xd5, 0x29, 0xe9, 0x03, 0xd7, 0x91, 0x4c, 0x07, 0xdf, 0xc2, 0x27, - 0x4f, 0x11, 0x62, 0xbd, 0x9d, 0x57, 0x11, 0x8e, 0x2f, 0x75, 0xc2, 0xb1, 0x31, 0x8d, 0x68, 0x5e, 0x56, 0x89, 0x4a, - 0x34, 0x73, 0x5b, 0xbd, 0xca, 0xc2, 0xc2, 0x0c, 0xa6, 0x9a, 0x52, 0xd0, 0xc4, 0x2b, 0x3a, 0x63, 0x2a, 0x66, 0x08, - 0x7f, 0xab, 0x80, 0xc5, 0x4f, 0x28, 0x32, 0x08, 0xce, 0x50, 0x05, 0x67, 0x28, 0xb0, 0xbb, 0xc0, 0xa4, 0xd5, 0xb7, - 0x9c, 0xc2, 0xac, 0xaf, 0x06, 0x15, 0x6f, 0x17, 0x4c, 0xde, 0x1c, 0xce, 0x0e, 0xc1, 0x3d, 0xfc, 0x6c, 0x9a, 0x05, - 0x9a, 0x61, 0x21, 0x14, 0xc2, 0xfb, 0xad, 0xcd, 0x95, 0xf4, 0xa5, 0xaa, 0x39, 0xf6, 0x07, 0xb0, 0x0e, 0xe6, 0xd8, - 0x48, 0xb8, 0x32, 0x7f, 0x6b, 0x5b, 0x0d, 0xc0, 0x76, 0x05, 0x98, 0x91, 0x8c, 0x73, 0xaa, 0xe3, 0xf6, 0x51, 0x0b, - 0x18, 0xd3, 0x2f, 0x0c, 0x4e, 0x15, 0x84, 0xb6, 0xa7, 0xc2, 0x92, 0x85, 0x50, 0x53, 0x3e, 0xd6, 0xf1, 0xef, 0xc2, - 0x10, 0x15, 0x96, 0x2b, 0x06, 0x12, 0x4e, 0xc0, 0x1e, 0x1b, 0x82, 0xf3, 0xbb, 0x80, 0x7e, 0xba, 0xe5, 0x41, 0xe4, - 0x46, 0x6a, 0x08, 0x17, 0x90, 0x87, 0x8a, 0xb5, 0xae, 0xc8, 0x4c, 0xc9, 0xb8, 0x01, 0xf7, 0xd8, 0xee, 0xd9, 0x16, - 0x53, 0x47, 0x0d, 0x44, 0xc0, 0xc1, 0x8a, 0x34, 0x24, 0x11, 0x2e, 0x51, 0x27, 0x5a, 0xbe, 0x94, 0x37, 0xac, 0x78, - 0x4c, 0x61, 0xf0, 0xa9, 0xad, 0xbe, 0xb6, 0x47, 0x81, 0xa1, 0xf8, 0xba, 0xeb, 0xf1, 0xe5, 0xda, 0x4c, 0xfc, 0x4d, - 0x21, 0x67, 0x5c, 0x31, 0xe0, 0xdb, 0x2c, 0xfc, 0x05, 0x6c, 0x34, 0xb3, 0x23, 0xe1, 0xb8, 0x61, 0x25, 0x7e, 0x3d, - 0x7c, 0x59, 0xc7, 0xaf, 0xeb, 0x7b, 0x4f, 0x27, 0x9e, 0x02, 0xd6, 0xf7, 0x31, 0xc2, 0xb1, 0x13, 0x2f, 0x82, 0x93, - 0x2e, 0x99, 0x22, 0x77, 0xcc, 0xaf, 0x56, 0x3a, 0x10, 0xe3, 0x6a, 0x9c, 0x23, 0xb3, 0xdb, 0x06, 0xad, 0xe9, 0x68, - 0x04, 0x2c, 0x5e, 0x21, 0xf3, 0x3c, 0x38, 0xac, 0xb0, 0xe8, 0x96, 0xc7, 0xd3, 0xf5, 0xbd, 0xa7, 0x57, 0xdf, 0x3b, - 0xa1, 0x20, 0x3f, 0x3c, 0xa4, 0xfc, 0x40, 0xc5, 0x88, 0x15, 0x20, 0x57, 0x06, 0xab, 0xe5, 0xce, 0xd9, 0xc7, 0x52, - 0x08, 0x96, 0x69, 0x36, 0x02, 0xa1, 0x45, 0x10, 0x9d, 0x4c, 0xa5, 0xd2, 0x65, 0x62, 0x35, 0x7a, 0x11, 0x0a, 0xa1, - 0x49, 0x46, 0xf3, 0x3c, 0xb6, 0x02, 0xca, 0x4c, 0x7e, 0x61, 0x3b, 0x46, 0xdd, 0xad, 0x0d, 0xb9, 0x6c, 0x86, 0x05, - 0xcd, 0xb0, 0x44, 0xcd, 0x73, 0x9e, 0xb1, 0xf2, 0xf0, 0xba, 0x4a, 0xb8, 0x18, 0xb1, 0x5b, 0xa0, 0x23, 0xe8, 0xf2, - 0xf2, 0xb2, 0x85, 0xdb, 0x68, 0x6d, 0x01, 0xbe, 0xdc, 0x02, 0xec, 0x77, 0x8e, 0x4d, 0x2b, 0x88, 0x2f, 0x77, 0x92, - 0x35, 0x14, 0x9c, 0x95, 0xdc, 0x0b, 0x5a, 0x96, 0x3c, 0x23, 0x3c, 0x62, 0x39, 0xd3, 0xcc, 0x93, 0x73, 0x60, 0xa6, - 0xed, 0xd6, 0x7d, 0x5b, 0xc2, 0xaf, 0x44, 0x27, 0xbf, 0xcb, 0xfc, 0x9a, 0xab, 0x52, 0x74, 0xaf, 0x96, 0xa7, 0x82, - 0x76, 0x4f, 0xdb, 0xe5, 0xa1, 0x5a, 0xd3, 0x6c, 0x6a, 0x25, 0xf6, 0x78, 0x6b, 0x4a, 0x55, 0x1b, 0x8e, 0xb4, 0x97, - 0x9b, 0xe8, 0x53, 0xe1, 0x86, 0xb9, 0x0b, 0x04, 0x57, 0x8e, 0x28, 0x30, 0x10, 0x02, 0xed, 0xb2, 0x3d, 0xa6, 0x79, - 0x3e, 0xa4, 0xd9, 0xe7, 0x3a, 0xf6, 0x57, 0x68, 0x40, 0x36, 0xa9, 0x71, 0x90, 0x15, 0x90, 0xac, 0x70, 0xde, 0x9e, - 0x4a, 0xd7, 0x36, 0x4a, 0xbc, 0xdf, 0xaa, 0xd0, 0xbe, 0xbe, 0xd0, 0xdf, 0xc4, 0x76, 0x33, 0x22, 0xe1, 0x66, 0x16, - 0x03, 0x15, 0xf8, 0x97, 0x18, 0xe7, 0xe9, 0x81, 0xc3, 0x3b, 0x10, 0x3c, 0xd6, 0x1b, 0x03, 0xd1, 0x68, 0xb9, 0x1e, - 0x71, 0xf5, 0x6d, 0x08, 0xfc, 0x6f, 0x19, 0xe5, 0x93, 0xa0, 0x87, 0x7f, 0x77, 0xa0, 0x25, 0x8d, 0x73, 0x8c, 0x73, - 0x39, 0x32, 0xc7, 0x50, 0x78, 0x42, 0xf3, 0x0b, 0x30, 0x2f, 0x06, 0xdf, 0x5f, 0xdb, 0x2c, 0xc3, 0x97, 0xc1, 0x30, - 0x54, 0x37, 0x64, 0x28, 0x6a, 0x28, 0xe0, 0x88, 0xaa, 0x30, 0x67, 0xae, 0xac, 0x89, 0x92, 0x8e, 0x6b, 0xb7, 0xe2, - 0xb8, 0xa3, 0xb9, 0x05, 0x89, 0xe3, 0x58, 0x81, 0x34, 0xe7, 0xf9, 0xfb, 0x6a, 0x16, 0x6a, 0x6b, 0x16, 0x2a, 0x09, - 0xa4, 0x2d, 0x54, 0x21, 0x73, 0x50, 0x3d, 0xd5, 0x02, 0x85, 0xa5, 0x80, 0x65, 0x4d, 0x80, 0x42, 0xa3, 0x92, 0xe0, - 0xe6, 0x44, 0xe3, 0xc2, 0x89, 0x3a, 0x0e, 0xd7, 0x80, 0x64, 0x54, 0x55, 0x24, 0xb2, 0x9b, 0xa3, 0x26, 0xfb, 0x4a, - 0x5c, 0xa0, 0x0d, 0xfe, 0x7e, 0xbd, 0x76, 0x50, 0x62, 0xc8, 0xad, 0x4e, 0x8d, 0x31, 0x0e, 0xc0, 0x82, 0x25, 0x71, - 0xcc, 0xb0, 0x65, 0x7d, 0x36, 0x81, 0x53, 0xb6, 0xbb, 0x4f, 0x88, 0xac, 0x60, 0x53, 0x63, 0x2a, 0x3d, 0x77, 0x25, - 0x11, 0xa6, 0x9e, 0x2d, 0x2d, 0xaa, 0x89, 0x13, 0x12, 0x79, 0xed, 0x44, 0xd4, 0x5b, 0xd6, 0x84, 0xc3, 0x34, 0x28, - 0xb6, 0x4e, 0x81, 0xa8, 0x16, 0xbb, 0xe0, 0xbd, 0x0b, 0x6b, 0x6a, 0xed, 0x04, 0x10, 0x2f, 0x6a, 0x10, 0x0f, 0x40, - 0x2b, 0x2d, 0xf1, 0x92, 0x03, 0x42, 0xeb, 0x95, 0x63, 0x86, 0x0b, 0xbb, 0x10, 0x5b, 0x50, 0xdc, 0x64, 0x3f, 0x0d, - 0x16, 0x82, 0x2c, 0xab, 0x80, 0xbf, 0x0b, 0x8f, 0x88, 0x18, 0x06, 0x2f, 0x56, 0xab, 0x2d, 0xb4, 0xdb, 0xc9, 0x85, - 0xa2, 0xa4, 0x92, 0x0e, 0x57, 0xab, 0xaf, 0x12, 0xc5, 0x8e, 0xff, 0xc5, 0x0c, 0xf5, 0x3c, 0xd1, 0x7d, 0xf8, 0x12, - 0x4a, 0x19, 0x76, 0xb4, 0x4a, 0x29, 0x05, 0x87, 0x3a, 0xd6, 0xd6, 0x17, 0x4a, 0x07, 0x94, 0xfb, 0xf1, 0x16, 0x01, - 0x33, 0x89, 0xee, 0xa4, 0xae, 0xa6, 0xfc, 0xd8, 0x35, 0x2d, 0x10, 0x42, 0xa9, 0x32, 0xb2, 0xcc, 0xfe, 0x2e, 0xf9, - 0xf2, 0xe0, 0x40, 0x05, 0x0d, 0x5d, 0x97, 0x94, 0xe2, 0xef, 0x18, 0x4e, 0x65, 0x75, 0x27, 0x0c, 0xfb, 0xf2, 0xb7, - 0x3f, 0x87, 0xb6, 0xa4, 0xd3, 0x56, 0x17, 0x04, 0x73, 0x7a, 0x43, 0xb9, 0xde, 0x2b, 0x5b, 0xb1, 0x82, 0x79, 0xcc, - 0xd0, 0xd2, 0x71, 0x1b, 0x49, 0xc1, 0x80, 0x7f, 0x04, 0xb2, 0xe0, 0xb9, 0x68, 0x8b, 0xf8, 0xd9, 0x94, 0x81, 0x2a, - 0xdb, 0x33, 0x12, 0xa5, 0x78, 0xb8, 0xef, 0x0e, 0x12, 0xd7, 0xf0, 0xee, 0xb1, 0xaf, 0x37, 0xab, 0xd7, 0xa4, 0x81, - 0x39, 0x2b, 0xc6, 0xb2, 0x98, 0xf9, 0xbc, 0xf5, 0xc6, 0xb7, 0x23, 0x8e, 0x7c, 0x1c, 0xef, 0x6c, 0xdb, 0x89, 0x00, - 0xdd, 0x0d, 0xd9, 0xbb, 0x92, 0xda, 0x6b, 0xa7, 0x69, 0x79, 0x00, 0x5b, 0x05, 0xa1, 0xc7, 0x4c, 0x15, 0x4a, 0xf9, - 0x4e, 0xbd, 0xda, 0xb5, 0xba, 0x93, 0xfd, 0x76, 0xb7, 0x94, 0xfc, 0x3c, 0x36, 0x74, 0xad, 0x8e, 0xc3, 0x9d, 0xaa, - 0x72, 0x91, 0x8f, 0xdc, 0x60, 0x05, 0xc2, 0xcc, 0xe1, 0xd1, 0x0d, 0xcf, 0xf3, 0x2a, 0xf5, 0x3f, 0x21, 0xed, 0xca, - 0x91, 0x76, 0xe9, 0x49, 0x3b, 0x90, 0x0a, 0x20, 0xed, 0xb6, 0xb9, 0xaa, 0xba, 0xdc, 0xda, 0x9e, 0xd2, 0x12, 0x75, - 0x65, 0xc4, 0x69, 0xe8, 0x6f, 0xe1, 0x47, 0x80, 0x4a, 0xe6, 0xeb, 0x73, 0xec, 0xf4, 0x31, 0x20, 0x06, 0x5a, 0x9d, - 0x26, 0x0b, 0x35, 0x15, 0x9f, 0x63, 0x84, 0xd5, 0x9a, 0x95, 0x98, 0xfd, 0xf0, 0x29, 0x28, 0xed, 0x82, 0xe9, 0xc0, - 0x39, 0x66, 0x92, 0xff, 0x23, 0x3e, 0xca, 0xcf, 0x4e, 0xb8, 0xd9, 0x29, 0x3f, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0x46, - 0xdf, 0xa7, 0xf6, 0x66, 0x7a, 0xa2, 0x9c, 0x5e, 0xb5, 0xde, 0xab, 0x55, 0xbc, 0x91, 0x02, 0x1a, 0x7d, 0x27, 0xa5, - 0x14, 0x65, 0xeb, 0x40, 0x03, 0x42, 0xc8, 0x40, 0xc2, 0xda, 0x4e, 0xba, 0x3c, 0xe5, 0x5e, 0xfe, 0x2b, 0x3d, 0x8f, - 0x51, 0xdc, 0xdb, 0xfa, 0x8f, 0xe5, 0x6c, 0x0e, 0x0c, 0xd9, 0x06, 0x4a, 0x4f, 0x98, 0xeb, 0xb0, 0xca, 0x5f, 0xef, - 0x48, 0xab, 0xd5, 0x31, 0xfb, 0xb1, 0x86, 0x4d, 0xa5, 0xd4, 0xbc, 0xdf, 0x5a, 0x2f, 0xca, 0xa4, 0x92, 0x70, 0xec, - 0xd2, 0xad, 0x3c, 0xde, 0xd4, 0xcc, 0xf8, 0x8c, 0xd7, 0xb1, 0xb0, 0x74, 0x58, 0x00, 0xad, 0x0b, 0xc8, 0x8f, 0x47, - 0xf7, 0x70, 0xfd, 0xd7, 0x15, 0x70, 0x96, 0xeb, 0x0d, 0xf0, 0x2d, 0xd7, 0xeb, 0x47, 0xda, 0x49, 0xda, 0xf8, 0xd1, - 0x0e, 0xb9, 0xb7, 0x84, 0x5e, 0x95, 0xe9, 0x64, 0xc6, 0xfe, 0x00, 0xd2, 0xb6, 0x58, 0x48, 0xb2, 0x9c, 0xc9, 0x11, - 0x4b, 0x23, 0x39, 0x67, 0x22, 0x5a, 0x83, 0x9e, 0xd5, 0x21, 0xc0, 0x3f, 0x22, 0x5e, 0xbe, 0xad, 0xeb, 0x5b, 0xd3, - 0x47, 0x7a, 0x0d, 0xaa, 0xb0, 0x97, 0x7c, 0x87, 0x32, 0xf6, 0x3d, 0x2b, 0x94, 0xe1, 0x49, 0x4b, 0xf6, 0xf6, 0x25, - 0xaf, 0x0e, 0xa8, 0x97, 0x3c, 0xfd, 0x76, 0x95, 0x4a, 0x20, 0x89, 0xda, 0xc9, 0x59, 0x72, 0x1c, 0x21, 0xa3, 0x31, - 0x7e, 0xe6, 0x35, 0xc6, 0x8b, 0x52, 0x63, 0xfc, 0x5c, 0x93, 0xc5, 0x86, 0xc6, 0xf8, 0x0f, 0x41, 0x9e, 0xeb, 0xde, - 0x73, 0xaf, 0x4d, 0x7f, 0x23, 0x73, 0x9e, 0xdd, 0xc5, 0x51, 0xce, 0x75, 0x13, 0x6e, 0x13, 0x23, 0xbc, 0xb4, 0x19, - 0xa0, 0x6a, 0x34, 0xfa, 0xee, 0xb5, 0x97, 0xff, 0xb0, 0x10, 0x24, 0xba, 0x97, 0x73, 0x7d, 0x2f, 0xc2, 0x53, 0x4d, - 0xfe, 0x82, 0x5f, 0xf7, 0x96, 0xf1, 0xaf, 0x54, 0x4f, 0x93, 0x82, 0x8a, 0x91, 0x9c, 0xc5, 0xa8, 0x11, 0x45, 0x28, - 0x51, 0x46, 0x08, 0x79, 0x80, 0xd6, 0xf7, 0xfe, 0xc2, 0xaf, 0x24, 0x89, 0x7a, 0x51, 0x63, 0xaa, 0xb1, 0xa6, 0xe4, - 0xaf, 0x8b, 0x7b, 0xcb, 0x57, 0x72, 0x7d, 0xf9, 0x17, 0x7e, 0xaa, 0x4b, 0xb5, 0x3e, 0xbe, 0x65, 0x24, 0x46, 0xe4, - 0xf2, 0xa9, 0x1f, 0xd2, 0x63, 0x39, 0xb3, 0x0a, 0xfe, 0x08, 0xe1, 0x2f, 0xa0, 0xd7, 0xbd, 0xe4, 0x15, 0x11, 0x72, - 0x77, 0x30, 0xfb, 0x24, 0x92, 0x46, 0x79, 0x10, 0x1d, 0x1c, 0x04, 0x69, 0x25, 0x0b, 0x81, 0xff, 0x96, 0xa4, 0x26, - 0xaa, 0x63, 0x46, 0xa1, 0xa5, 0xbf, 0x65, 0xcc, 0x91, 0x6f, 0x26, 0xf6, 0x9a, 0x6a, 0xb7, 0x63, 0x79, 0xdf, 0xea, - 0x1e, 0x12, 0xae, 0x59, 0x41, 0xb5, 0x2c, 0x06, 0x28, 0x64, 0x4b, 0xf0, 0x57, 0x4e, 0xfe, 0xea, 0xef, 0xfd, 0x3f, - 0xff, 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xe0, 0x2f, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, - 0xfe, 0x3c, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x34, 0x40, 0xab, 0xf8, 0xcf, 0xa3, 0x5e, 0xdf, 0x7d, - 0xf5, 0xff, 0xfb, 0xf2, 0x4f, 0x35, 0x38, 0xb4, 0x89, 0xf7, 0x10, 0x3a, 0x9a, 0xe0, 0x5f, 0x04, 0x39, 0x6a, 0x36, - 0x2f, 0x8f, 0x26, 0xf8, 0x27, 0x41, 0x8e, 0xe0, 0xef, 0x9d, 0x26, 0x6f, 0xd9, 0xe4, 0xe9, 0xed, 0x3c, 0xfe, 0xeb, - 0x72, 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf9, 0xa7, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, - 0x06, 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0x3f, 0xff, 0xba, - 0xb8, 0x24, 0x83, 0x55, 0x1c, 0xad, 0x7e, 0x44, 0x2b, 0x84, 0x56, 0xf7, 0xd0, 0x5f, 0x38, 0x9a, 0x44, 0x08, 0xff, - 0x26, 0xc8, 0xd1, 0x8f, 0x47, 0x13, 0xfc, 0x49, 0x90, 0xa3, 0xe8, 0x68, 0x82, 0xdf, 0x4b, 0x72, 0xf4, 0xdf, 0x71, - 0x2f, 0xb5, 0x4a, 0xb8, 0x95, 0x51, 0x7f, 0xac, 0xe0, 0x26, 0x84, 0x16, 0x8c, 0xae, 0x34, 0xd7, 0x39, 0x43, 0xf7, - 0x8e, 0x38, 0x7e, 0x24, 0x01, 0x58, 0xb1, 0x06, 0x25, 0x8d, 0xb9, 0x84, 0x5d, 0x5e, 0xc3, 0xc2, 0x03, 0x06, 0xdd, - 0x4b, 0x39, 0xb6, 0x7a, 0x02, 0x95, 0x6a, 0x7b, 0x7b, 0xab, 0xe0, 0xfa, 0x16, 0x3f, 0x26, 0x8f, 0x64, 0xdc, 0x46, - 0x98, 0x53, 0xf8, 0xd1, 0x41, 0xf8, 0x83, 0x76, 0x17, 0x9e, 0xb0, 0xcd, 0x2d, 0x86, 0x09, 0x69, 0xf9, 0x99, 0x08, - 0xe1, 0x97, 0x3b, 0x32, 0xf5, 0x14, 0xd4, 0x0f, 0x08, 0xff, 0x5c, 0xbb, 0x1e, 0xc5, 0x8f, 0x35, 0x29, 0x91, 0xe3, - 0x5d, 0xc1, 0xd8, 0x07, 0x9a, 0x7f, 0x66, 0x45, 0xfc, 0x54, 0xe3, 0x76, 0xe7, 0x01, 0x36, 0xaa, 0xea, 0xfd, 0x36, - 0xea, 0x96, 0xb7, 0x5b, 0xcf, 0xa5, 0xbd, 0x4f, 0x80, 0x53, 0xb8, 0xae, 0xaf, 0x81, 0xb5, 0xdf, 0xe7, 0x5b, 0x4a, - 0xad, 0x82, 0xde, 0x44, 0xa8, 0x7e, 0x95, 0xca, 0xc5, 0x17, 0x9a, 0xf3, 0xd1, 0x9e, 0x66, 0xb3, 0x79, 0x4e, 0x35, - 0xdb, 0x73, 0x73, 0xde, 0xa3, 0xd0, 0x50, 0x54, 0xf2, 0x14, 0x7f, 0x88, 0x6a, 0xd3, 0xfe, 0x21, 0x92, 0x6a, 0xef, - 0xc4, 0x70, 0x9f, 0xe5, 0xf8, 0x12, 0x41, 0xcb, 0xeb, 0xb2, 0xcd, 0x1b, 0xc1, 0x66, 0x1b, 0x94, 0x65, 0x03, 0x73, - 0x7e, 0x2b, 0x0c, 0xf7, 0x9b, 0x84, 0x74, 0x7a, 0xd1, 0x85, 0xfa, 0x32, 0xb9, 0x8c, 0xe0, 0x26, 0xa7, 0x20, 0x82, - 0x19, 0xe5, 0x11, 0x94, 0xa0, 0xa4, 0xd5, 0xa5, 0x17, 0xac, 0x4b, 0x1b, 0x0d, 0xcf, 0x66, 0x67, 0x84, 0xf7, 0xa9, - 0xad, 0x9f, 0xe3, 0x29, 0x1e, 0x91, 0x66, 0x1b, 0x2f, 0x48, 0xcb, 0x54, 0xe9, 0x2e, 0x2e, 0x32, 0xd7, 0xcf, 0xc1, - 0x41, 0x5c, 0x24, 0x39, 0x55, 0xfa, 0x05, 0x68, 0x04, 0xc8, 0x02, 0x4f, 0x49, 0x91, 0xb0, 0x5b, 0x96, 0xc5, 0x19, - 0xc2, 0x53, 0x47, 0x83, 0x50, 0x17, 0x2d, 0x48, 0x50, 0x0c, 0xe4, 0x0c, 0x22, 0x58, 0x6f, 0xda, 0x6f, 0x0f, 0x08, - 0x21, 0xd1, 0x7e, 0xb3, 0x19, 0xf5, 0x0a, 0xf2, 0x8b, 0x48, 0x21, 0x25, 0x60, 0xa7, 0xc9, 0x4f, 0x90, 0xd4, 0x09, - 0x92, 0xe2, 0xf7, 0x32, 0xd1, 0x4c, 0xe9, 0x18, 0x92, 0x41, 0x49, 0xa0, 0x3c, 0x86, 0x47, 0x17, 0x47, 0x51, 0x03, - 0x52, 0x0d, 0x8a, 0x22, 0x5c, 0x90, 0x3b, 0x8d, 0xd2, 0x69, 0xff, 0x78, 0x10, 0x9e, 0x11, 0x36, 0x15, 0xfa, 0xbf, - 0xd3, 0xbd, 0x69, 0xbf, 0x65, 0xfa, 0xbf, 0x8c, 0x7a, 0x71, 0x41, 0x94, 0x65, 0xe3, 0x7a, 0x2a, 0x15, 0xcc, 0xcc, - 0x17, 0xa5, 0x6e, 0x80, 0xae, 0xef, 0x11, 0x69, 0x76, 0xd2, 0x78, 0x14, 0xce, 0xa4, 0x09, 0x1d, 0x3a, 0x50, 0xe0, - 0x9c, 0x40, 0x79, 0x5c, 0x10, 0xe8, 0xb4, 0xaa, 0x76, 0xa7, 0x53, 0x97, 0xf0, 0x63, 0xf4, 0x63, 0xef, 0x93, 0x48, - 0x7f, 0x13, 0x76, 0x04, 0x9f, 0xc4, 0x6a, 0x05, 0x7f, 0x7f, 0x13, 0x3d, 0x18, 0x96, 0x49, 0xfb, 0xc5, 0xa5, 0xfd, - 0x04, 0x69, 0x82, 0xa5, 0x66, 0xc0, 0x58, 0x95, 0xfc, 0x98, 0x5d, 0x9c, 0x31, 0xb1, 0x33, 0x38, 0x38, 0xe0, 0x7d, - 0xda, 0x68, 0x0f, 0xe0, 0x46, 0xa0, 0xd0, 0xea, 0x03, 0xd7, 0xd3, 0x38, 0x3a, 0xba, 0x8c, 0x50, 0x2f, 0xda, 0x83, - 0x55, 0xee, 0xca, 0x06, 0x71, 0xb0, 0xce, 0x1a, 0x9a, 0xa6, 0xa3, 0x4b, 0xd2, 0xea, 0xc5, 0xc2, 0x12, 0xf9, 0x1c, - 0xe1, 0xcc, 0xd1, 0xd4, 0x16, 0x1e, 0xa1, 0x86, 0x10, 0x0d, 0xff, 0x3d, 0x42, 0x8d, 0xa9, 0x6e, 0x8c, 0x51, 0x9a, - 0xc1, 0xdf, 0x78, 0x44, 0x08, 0x69, 0x76, 0xca, 0x8a, 0xfe, 0xb0, 0xa4, 0x28, 0x1d, 0x7b, 0xf5, 0x68, 0xdf, 0x6c, - 0x0e, 0xd9, 0x88, 0x79, 0x9f, 0x0d, 0x56, 0xab, 0xe8, 0xa2, 0x77, 0x19, 0xa1, 0x46, 0xec, 0xd1, 0xee, 0xc8, 0xe3, - 0x1d, 0x42, 0x58, 0x0c, 0xd6, 0xee, 0x06, 0xea, 0x86, 0xd5, 0x6e, 0x9b, 0x96, 0xd5, 0xfe, 0x0f, 0xc8, 0x02, 0x5b, - 0x97, 0x72, 0x8f, 0xe5, 0x6f, 0xe7, 0x30, 0x55, 0x8f, 0xdb, 0x92, 0xb4, 0x70, 0x41, 0xbc, 0xba, 0x9b, 0x12, 0x5d, - 0xe1, 0x7f, 0x46, 0xaa, 0xe2, 0xb8, 0x9f, 0xe3, 0xe9, 0x80, 0x08, 0x6a, 0xe4, 0x97, 0xae, 0x57, 0xa6, 0xb3, 0x9c, - 0xdc, 0xb0, 0x8d, 0xfb, 0xdf, 0x1c, 0xee, 0x64, 0x1e, 0xeb, 0x24, 0x5b, 0x14, 0x05, 0x13, 0xfa, 0x95, 0x1c, 0x39, - 0xc6, 0x8e, 0xe5, 0x20, 0x5b, 0xc1, 0xc5, 0x2e, 0x06, 0xae, 0xae, 0xe3, 0x77, 0xca, 0x68, 0x2b, 0x7b, 0x41, 0x46, - 0x96, 0xe1, 0x32, 0xd7, 0xbd, 0xdd, 0x85, 0x13, 0xa5, 0x63, 0x84, 0x47, 0xee, 0x1e, 0x38, 0x4e, 0x92, 0x64, 0x91, - 0x64, 0x90, 0x0d, 0x1d, 0x28, 0xb4, 0x36, 0xfb, 0x2a, 0x56, 0xe4, 0xb1, 0x4e, 0x04, 0xbb, 0x35, 0xdd, 0xc6, 0xa8, - 0x3a, 0xc4, 0xfd, 0x7e, 0xbb, 0xa0, 0x5d, 0x43, 0x80, 0x54, 0x22, 0xe4, 0x88, 0x01, 0x84, 0xe0, 0xee, 0xdf, 0x25, - 0x4d, 0xa9, 0x0a, 0x6f, 0xb6, 0xaa, 0x01, 0xf6, 0x43, 0x95, 0xf7, 0x02, 0xf4, 0xc4, 0x86, 0x3d, 0x2b, 0x0b, 0x5b, - 0xe5, 0x39, 0x42, 0x7c, 0x1c, 0x2f, 0x12, 0xb8, 0x11, 0x34, 0x98, 0x24, 0x04, 0x5a, 0xad, 0x16, 0x21, 0x6e, 0x4d, - 0x2b, 0xc5, 0xf4, 0x98, 0x4c, 0xfb, 0x45, 0xa3, 0x61, 0x94, 0xd7, 0x23, 0x8b, 0x17, 0x0b, 0x84, 0xc7, 0xe5, 0x5e, - 0xf3, 0xe5, 0xe6, 0xa4, 0xde, 0x55, 0x3c, 0xae, 0x2b, 0x81, 0x1b, 0x42, 0x20, 0xa3, 0x5f, 0xd4, 0xd0, 0x3a, 0x9e, - 0x90, 0xa3, 0xb8, 0x9f, 0xf4, 0xfe, 0xe7, 0x00, 0xf5, 0xe2, 0xe4, 0x10, 0x1d, 0x59, 0x5a, 0x32, 0x46, 0xdd, 0xcc, - 0xf6, 0xb1, 0x34, 0xb7, 0x9f, 0x6d, 0x6c, 0x14, 0x90, 0xa9, 0xc4, 0x82, 0xce, 0x58, 0x3a, 0x81, 0x5d, 0xef, 0x91, - 0x67, 0x8e, 0x01, 0x99, 0xd2, 0x89, 0xa3, 0x2d, 0x49, 0xd4, 0x93, 0xb4, 0xfc, 0xea, 0x45, 0x3d, 0x5a, 0x7d, 0xfd, - 0xcf, 0xa8, 0x97, 0xd1, 0xf4, 0x31, 0x5f, 0x3b, 0x25, 0x79, 0xad, 0x8f, 0x33, 0xdf, 0xc7, 0xda, 0x2e, 0x4e, 0x00, - 0xbc, 0x11, 0xda, 0xd6, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0xa4, 0x12, 0x4d, 0x27, 0x00, 0xd5, 0x60, 0x11, - 0x54, 0x68, 0x1b, 0x10, 0x4c, 0x19, 0xb0, 0xc5, 0x23, 0x2d, 0x40, 0x73, 0x71, 0xd9, 0x42, 0xcb, 0x5a, 0x61, 0xc7, - 0x59, 0xd5, 0xef, 0xe2, 0x4b, 0xe2, 0x3d, 0x06, 0xaa, 0x7c, 0xb1, 0xe8, 0x8e, 0x1b, 0x0d, 0xa4, 0x3c, 0x7e, 0x8d, - 0xfa, 0xe3, 0x01, 0xbe, 0x05, 0x14, 0xc2, 0x35, 0x8c, 0xc2, 0xb5, 0x39, 0x76, 0xdc, 0x1c, 0x1b, 0x0d, 0xb9, 0x46, - 0xdd, 0xa0, 0xf2, 0xc2, 0x55, 0x5e, 0xaf, 0x2d, 0x64, 0x36, 0x31, 0xee, 0x1c, 0x99, 0x14, 0x30, 0x04, 0x23, 0x84, - 0xbc, 0x92, 0x68, 0x67, 0xb3, 0xd0, 0x28, 0x54, 0x37, 0xbb, 0x17, 0x28, 0xaa, 0x3d, 0x3d, 0x62, 0x80, 0x05, 0x54, - 0x2d, 0xd5, 0xc8, 0x53, 0x8d, 0x47, 0x8d, 0xb6, 0x41, 0xf7, 0x66, 0xbb, 0x5b, 0x6f, 0xec, 0x7e, 0xd5, 0x18, 0x1e, - 0x35, 0xc8, 0xb4, 0xda, 0xe1, 0x6b, 0xd9, 0x68, 0xac, 0xeb, 0xf7, 0xa5, 0x7e, 0x13, 0xd7, 0xee, 0x2f, 0x9e, 0x6e, - 0x99, 0x78, 0xf8, 0xd3, 0xb7, 0x3a, 0x6f, 0x45, 0xc2, 0x85, 0x60, 0x05, 0x9c, 0xb0, 0x44, 0x63, 0xb1, 0x5e, 0x97, - 0xa7, 0xfe, 0xef, 0xda, 0xda, 0x8c, 0x11, 0x0e, 0x74, 0xc8, 0x48, 0x6d, 0x58, 0xe2, 0x02, 0x53, 0x43, 0x45, 0x08, - 0x21, 0x1f, 0xb4, 0x37, 0x8f, 0xd1, 0x86, 0x24, 0x65, 0x24, 0x38, 0xbb, 0x63, 0x45, 0x58, 0x72, 0x7d, 0xef, 0xb1, - 0xfc, 0xae, 0x48, 0xd7, 0x17, 0x83, 0xd4, 0x14, 0xcb, 0x1d, 0x21, 0xcb, 0xc9, 0x17, 0x90, 0x73, 0xca, 0x0b, 0x96, - 0xc4, 0x10, 0xc4, 0x27, 0xbc, 0x60, 0x86, 0x71, 0xbf, 0xe7, 0xe5, 0xc6, 0xac, 0xce, 0x69, 0x66, 0xa1, 0xf6, 0x07, - 0xa0, 0x99, 0x83, 0x72, 0x48, 0x92, 0xad, 0x62, 0xd7, 0xf7, 0x1e, 0xbe, 0xde, 0x25, 0x43, 0xaf, 0x56, 0x4e, 0x7a, - 0xce, 0x80, 0xf5, 0xc1, 0x79, 0x35, 0xd4, 0xcc, 0xfd, 0x48, 0xe3, 0xcc, 0x30, 0x51, 0x79, 0xcc, 0x01, 0x99, 0xae, - 0xef, 0x3d, 0x7c, 0x17, 0x73, 0xa3, 0x9b, 0x42, 0x38, 0x9c, 0x77, 0x5c, 0x90, 0x98, 0x12, 0x86, 0xec, 0xe4, 0x4b, - 0x3a, 0x56, 0x04, 0xa7, 0x7b, 0x4a, 0x4d, 0x26, 0x88, 0x1d, 0x7d, 0x31, 0x20, 0x99, 0x03, 0x01, 0xc9, 0x10, 0xce, - 0x6a, 0x72, 0x1d, 0x31, 0x6b, 0x60, 0x3a, 0xbb, 0x82, 0xc5, 0x48, 0x2c, 0x7b, 0x88, 0x70, 0x66, 0xba, 0xd5, 0x6b, - 0x7b, 0x9c, 0x28, 0xba, 0x69, 0xe8, 0x56, 0xc9, 0xb3, 0xef, 0x41, 0xf0, 0xf2, 0x1f, 0xaf, 0x5c, 0xdb, 0x65, 0xc2, - 0x13, 0x6f, 0x91, 0x76, 0x7d, 0xef, 0xe1, 0xaf, 0xce, 0x28, 0x6d, 0x4e, 0x3d, 0xf9, 0xdf, 0x92, 0x51, 0x1f, 0xfe, - 0x9a, 0x54, 0xb9, 0xa6, 0xf0, 0xf5, 0xbd, 0x87, 0xbf, 0xef, 0x2a, 0x06, 0xe9, 0xeb, 0x45, 0xa5, 0x24, 0x30, 0xe3, - 0x5b, 0xb2, 0x3c, 0x5d, 0xba, 0xb3, 0x22, 0x15, 0x6b, 0x6c, 0x4e, 0xa8, 0x54, 0xad, 0x4b, 0xdd, 0xca, 0x13, 0x2c, - 0x89, 0xb9, 0x4a, 0xaa, 0x2f, 0x9b, 0x43, 0x63, 0x2e, 0xc5, 0x55, 0x26, 0xe7, 0xec, 0x1b, 0xf7, 0x4b, 0x4f, 0x35, - 0x4a, 0xf8, 0x0c, 0x0c, 0x71, 0xcc, 0xd8, 0x05, 0xde, 0x6f, 0xa1, 0xee, 0xc6, 0x79, 0x26, 0x0d, 0xa2, 0x16, 0xf5, - 0xc3, 0x06, 0x53, 0xd2, 0xc2, 0x19, 0x69, 0xe1, 0x9c, 0xa8, 0x7e, 0xcb, 0x9e, 0x18, 0xdd, 0xbc, 0x6c, 0xda, 0x9e, - 0x3b, 0xb0, 0xdd, 0x73, 0xbb, 0x6f, 0xed, 0xa1, 0x3c, 0xed, 0xe6, 0x46, 0x7f, 0x69, 0x0e, 0xfa, 0xa9, 0x41, 0x8d, - 0x27, 0x2c, 0x2e, 0x70, 0x61, 0x5a, 0xbe, 0xe2, 0xc3, 0x1c, 0xec, 0x54, 0x60, 0x66, 0x58, 0xa3, 0xb4, 0x2c, 0xdb, - 0x76, 0x65, 0xf3, 0xc4, 0xac, 0x55, 0x81, 0xf3, 0x04, 0x48, 0x39, 0xce, 0x9d, 0x5d, 0x8f, 0xda, 0xae, 0x72, 0x76, - 0x70, 0x10, 0xbb, 0x4a, 0x34, 0x2e, 0x7c, 0x7e, 0x75, 0x03, 0xf8, 0xde, 0x52, 0x8d, 0x29, 0x32, 0x13, 0x68, 0x34, - 0xb2, 0xc1, 0x9a, 0xee, 0x13, 0x12, 0xe7, 0x75, 0x28, 0xfa, 0xd1, 0x1b, 0x66, 0x70, 0x03, 0x00, 0x8d, 0x46, 0x79, - 0xdd, 0xbb, 0x01, 0xb1, 0xa7, 0x1a, 0xcb, 0xf5, 0x97, 0xb8, 0xb4, 0x26, 0x6a, 0x6d, 0xd9, 0x61, 0xf9, 0x51, 0x20, - 0x11, 0xe2, 0xae, 0xf0, 0xf3, 0x09, 0xb6, 0x86, 0x80, 0x72, 0x2f, 0x9c, 0x0d, 0x04, 0x36, 0x56, 0x5b, 0xae, 0x90, - 0x27, 0x6d, 0x1d, 0x94, 0xfa, 0x42, 0x70, 0xc1, 0x05, 0x85, 0x1a, 0x6b, 0x87, 0xe5, 0x4f, 0xd8, 0xb6, 0x39, 0x27, - 0x56, 0xc8, 0x69, 0xcb, 0xcc, 0x30, 0x0c, 0xc0, 0x3a, 0x25, 0x60, 0x9e, 0x93, 0x97, 0xdf, 0x46, 0xfd, 0x87, 0x01, - 0xea, 0x3f, 0x22, 0x2c, 0xd8, 0x06, 0x56, 0x57, 0x92, 0x48, 0xa7, 0xa0, 0x50, 0x3e, 0xeb, 0xf1, 0x9c, 0x80, 0x36, - 0xae, 0x0e, 0xd5, 0xda, 0x15, 0xe5, 0x37, 0x28, 0x4b, 0xb8, 0x53, 0x8c, 0x3e, 0x13, 0xfb, 0xfb, 0xe4, 0xb8, 0xba, - 0xa0, 0x83, 0xae, 0x77, 0x29, 0x07, 0x43, 0x52, 0xf8, 0xf0, 0xf7, 0xef, 0xdf, 0xad, 0x3e, 0x9e, 0x6f, 0xef, 0xe0, - 0xc0, 0xac, 0x14, 0x66, 0x1d, 0x6c, 0xe0, 0xba, 0x91, 0x29, 0xf4, 0x5f, 0xde, 0x89, 0xd7, 0xa9, 0xd0, 0xc6, 0x66, - 0xf4, 0xc7, 0x21, 0x8c, 0xb6, 0xdd, 0x36, 0x25, 0x58, 0xd0, 0x2c, 0xd0, 0x25, 0x6b, 0xdc, 0x4a, 0x8b, 0x6f, 0x90, - 0x91, 0x87, 0xa6, 0x00, 0x13, 0xa3, 0xdd, 0xd9, 0x8f, 0xd6, 0x0e, 0x4f, 0xec, 0xd0, 0xd0, 0xd2, 0x10, 0x42, 0x8b, - 0xf7, 0x80, 0x39, 0xf6, 0x88, 0x00, 0x10, 0xbd, 0x34, 0x90, 0xaa, 0x40, 0x16, 0x45, 0x95, 0x22, 0xff, 0xf9, 0x3e, - 0x21, 0x2f, 0x2b, 0x45, 0xe6, 0xdb, 0xca, 0x98, 0x0b, 0x10, 0x03, 0xa5, 0x70, 0x91, 0x50, 0x26, 0xd8, 0xcb, 0xd0, - 0x0f, 0xda, 0x97, 0x37, 0xd2, 0x66, 0x52, 0x71, 0xe3, 0xc1, 0x4d, 0xa9, 0x51, 0xf1, 0xd9, 0x7c, 0x0f, 0x89, 0x8d, - 0xdc, 0x7b, 0x90, 0xcb, 0xa8, 0x19, 0x24, 0x7c, 0xbf, 0x33, 0xa5, 0x7d, 0xbb, 0xeb, 0xcf, 0x9b, 0x16, 0x31, 0x1b, - 0xeb, 0x92, 0x70, 0xa1, 0x58, 0xa1, 0x1f, 0xb1, 0xb1, 0x2c, 0xe0, 0xfe, 0xa3, 0x04, 0x0b, 0x5a, 0xdf, 0x0b, 0x74, - 0x80, 0x66, 0x82, 0xc1, 0xa5, 0xc3, 0xc6, 0x0c, 0xcd, 0xaf, 0xcf, 0xe6, 0x0e, 0xfc, 0x7a, 0xb3, 0xd6, 0xcb, 0x83, - 0x83, 0x2f, 0xac, 0x02, 0x94, 0x1b, 0xa6, 0x19, 0x46, 0x40, 0xbc, 0x2c, 0x97, 0xe3, 0x6e, 0x86, 0xef, 0xc5, 0x95, - 0xca, 0xc0, 0x13, 0x8e, 0x90, 0x08, 0x3d, 0x27, 0x7a, 0x3d, 0xd9, 0xa4, 0xf7, 0x4e, 0x9b, 0x21, 0x42, 0xb1, 0x06, - 0xc8, 0x3d, 0xc8, 0xe5, 0x56, 0xc9, 0xa4, 0x2a, 0x5b, 0xdb, 0x72, 0x10, 0x8f, 0x01, 0x5c, 0xb1, 0x11, 0x52, 0x02, - 0x34, 0xdc, 0x2d, 0xb4, 0x3c, 0x97, 0xc0, 0xfe, 0x63, 0x95, 0x80, 0x48, 0x8b, 0x6a, 0x1b, 0x17, 0x21, 0x6c, 0x4d, - 0x7d, 0x02, 0xe3, 0x84, 0x87, 0xcf, 0x77, 0x69, 0xa8, 0x3d, 0x6a, 0x33, 0x73, 0x06, 0x41, 0x09, 0x89, 0xca, 0x0a, - 0xc9, 0x97, 0x58, 0x38, 0x6e, 0xce, 0xdf, 0xc3, 0x01, 0x29, 0x56, 0x34, 0xb6, 0x77, 0x5b, 0x70, 0x7c, 0x14, 0xc9, - 0x22, 0xae, 0x75, 0xdd, 0x2d, 0x4c, 0x35, 0xec, 0x40, 0x47, 0x43, 0x38, 0x15, 0xe6, 0x9e, 0xf0, 0x71, 0x45, 0x52, - 0x7f, 0xb6, 0x26, 0xda, 0xda, 0x13, 0xc3, 0xca, 0x34, 0x25, 0x98, 0xff, 0xcf, 0xd6, 0xea, 0xba, 0x2c, 0x84, 0x99, - 0x19, 0xc6, 0x8d, 0x5d, 0x05, 0xb6, 0x06, 0x1c, 0x5b, 0xfe, 0x2d, 0x83, 0x45, 0xf5, 0x4a, 0x71, 0xd3, 0x69, 0xc0, - 0x04, 0xbc, 0x05, 0xeb, 0x99, 0xcd, 0xad, 0xff, 0xdc, 0x1c, 0x8c, 0x02, 0xab, 0x1a, 0x81, 0x97, 0x86, 0xc0, 0x23, - 0x60, 0xdc, 0xbc, 0x69, 0x79, 0xcf, 0x19, 0xd1, 0x08, 0x7f, 0xe2, 0x39, 0x3c, 0xb3, 0x2c, 0xf7, 0xd6, 0xc7, 0xc6, - 0x8a, 0xa4, 0x82, 0x80, 0x6d, 0x11, 0x76, 0x44, 0x5e, 0x22, 0xac, 0x1a, 0x8d, 0xae, 0xba, 0x60, 0x95, 0x56, 0xa5, - 0x1a, 0xa6, 0x80, 0x5b, 0x62, 0xc0, 0xfb, 0xda, 0x89, 0x0a, 0x86, 0x04, 0xde, 0xfa, 0x5b, 0x81, 0xfa, 0xfe, 0xe1, - 0xdb, 0x38, 0xa4, 0x6f, 0x61, 0xd9, 0xf2, 0x22, 0x16, 0xa6, 0x14, 0x57, 0x77, 0x38, 0x6f, 0xbe, 0x6f, 0x36, 0x02, - 0xe3, 0xde, 0x6f, 0x63, 0xb0, 0x71, 0x43, 0x5d, 0x6d, 0x49, 0x43, 0xb9, 0x09, 0xbb, 0xa8, 0xb2, 0x77, 0x0c, 0x3b, - 0xeb, 0xea, 0x4a, 0xda, 0xd5, 0x44, 0xad, 0xd7, 0x8a, 0x55, 0x46, 0x03, 0x1b, 0x86, 0x9d, 0xe6, 0x98, 0xd9, 0x56, - 0xe0, 0x3f, 0x9e, 0x13, 0x8d, 0x03, 0x64, 0x7d, 0xf3, 0xad, 0xeb, 0x94, 0x6a, 0x98, 0xb0, 0xbd, 0xdd, 0xf9, 0xf8, - 0x98, 0xef, 0x3a, 0x1f, 0xb1, 0x74, 0x5b, 0xdf, 0x9c, 0x8d, 0xed, 0x7f, 0xe3, 0x6c, 0x74, 0x6a, 0x7b, 0x7f, 0x3c, - 0x02, 0x77, 0x52, 0x3b, 0x1e, 0xeb, 0x6b, 0x4a, 0x24, 0x16, 0x6e, 0x39, 0x2e, 0x3b, 0xab, 0x95, 0xe8, 0xb7, 0x40, - 0xed, 0x14, 0x45, 0xf0, 0xb3, 0x6d, 0x7f, 0x06, 0x24, 0xd9, 0xea, 0x90, 0x63, 0x51, 0x8a, 0x32, 0x28, 0x01, 0x03, - 0xea, 0xd8, 0xd8, 0x7a, 0x19, 0xc4, 0x76, 0x38, 0xe4, 0xb0, 0x9c, 0x88, 0xf2, 0xea, 0x0a, 0x46, 0x6c, 0x8e, 0x0d, - 0x27, 0x60, 0xc6, 0x3b, 0xad, 0x0a, 0xbd, 0xf8, 0xf9, 0xaf, 0x99, 0xd3, 0xda, 0x11, 0x63, 0x39, 0x89, 0x9a, 0x15, - 0x83, 0x1b, 0x81, 0x63, 0x18, 0xf7, 0x8d, 0x84, 0x5a, 0x9d, 0xea, 0xa8, 0x76, 0x24, 0xe1, 0x16, 0xa8, 0xdd, 0xf6, - 0xcd, 0xb9, 0xb4, 0x5a, 0xed, 0x3c, 0x58, 0x70, 0x11, 0xe0, 0xf6, 0x73, 0xa2, 0x6b, 0x24, 0x85, 0x12, 0x27, 0x41, - 0xe1, 0xdc, 0xa0, 0xaa, 0x26, 0xb2, 0xdf, 0x1a, 0x00, 0x4f, 0xda, 0xcd, 0x2e, 0x64, 0x25, 0x24, 0x67, 0x8d, 0x06, - 0xca, 0xcb, 0x8e, 0x69, 0x5f, 0x34, 0xb2, 0x01, 0x66, 0x38, 0xb3, 0x02, 0x0b, 0x9c, 0x5e, 0x71, 0x5e, 0x75, 0xdd, - 0xcf, 0x06, 0x08, 0x17, 0xab, 0x55, 0x6c, 0x87, 0x96, 0xa3, 0xd5, 0x2a, 0x0f, 0x87, 0x66, 0xf2, 0xa1, 0xe2, 0xcb, - 0x9e, 0x26, 0x2f, 0xcd, 0x79, 0xf8, 0x12, 0x06, 0xd9, 0x20, 0x71, 0xee, 0x54, 0x82, 0x39, 0x68, 0xae, 0x1a, 0xb2, - 0x9f, 0x35, 0xda, 0x83, 0x80, 0x86, 0xf5, 0xb3, 0x01, 0xc9, 0xd7, 0x60, 0x39, 0xab, 0xdc, 0x81, 0xf9, 0x37, 0x1c, - 0x6c, 0x7f, 0x9b, 0x73, 0xc6, 0x36, 0x18, 0xae, 0xc9, 0xa6, 0xca, 0xa0, 0xc4, 0x2b, 0xb7, 0xb8, 0xbe, 0x5c, 0xcd, - 0xc0, 0xa2, 0x2c, 0x84, 0xdd, 0x35, 0x73, 0x0f, 0x84, 0xff, 0x12, 0xdb, 0x25, 0x2d, 0x8d, 0xb8, 0x37, 0x10, 0xdf, - 0xdb, 0x6e, 0x27, 0x49, 0x42, 0x8b, 0x89, 0xb9, 0x12, 0xf1, 0x37, 0xbc, 0x66, 0x0f, 0x1c, 0xbb, 0x71, 0x06, 0x3d, - 0xf7, 0xcb, 0xce, 0x06, 0xc4, 0x8e, 0xdf, 0x33, 0x3b, 0xde, 0x71, 0xa5, 0xa0, 0xbb, 0x75, 0x11, 0x76, 0x30, 0xf4, - 0x7f, 0x79, 0x30, 0x27, 0x6e, 0x30, 0x16, 0x4d, 0x36, 0xe0, 0xf6, 0x0d, 0x78, 0x14, 0x74, 0x03, 0x6e, 0xdf, 0x86, - 0xaf, 0x87, 0x56, 0xf6, 0xcd, 0x01, 0x06, 0x64, 0xc2, 0x8e, 0xb4, 0x4a, 0x08, 0x86, 0x79, 0xba, 0xc9, 0x91, 0x59, - 0xb2, 0x0a, 0x87, 0xab, 0x26, 0xb1, 0xd8, 0xd8, 0x0b, 0x15, 0x93, 0x1a, 0x08, 0xc6, 0x22, 0x7d, 0x89, 0x42, 0xa5, - 0x41, 0xdd, 0x38, 0x06, 0xb0, 0xca, 0x69, 0xeb, 0x5f, 0x1e, 0x1c, 0x80, 0xd0, 0x00, 0xac, 0x5d, 0x92, 0xd1, 0xb9, - 0x5e, 0x14, 0xc0, 0x5f, 0x29, 0xff, 0x1b, 0x92, 0xc1, 0xed, 0xc4, 0xa4, 0xc1, 0x0f, 0x48, 0x98, 0x53, 0xa5, 0xf8, - 0x17, 0x9b, 0xe6, 0x7e, 0xe3, 0x82, 0x78, 0x8c, 0x56, 0x96, 0x53, 0x94, 0xa8, 0x2b, 0x1d, 0xba, 0xd6, 0x21, 0xf7, - 0xf4, 0x0b, 0x13, 0xfa, 0x25, 0x57, 0x9a, 0x09, 0x00, 0x40, 0x85, 0x78, 0x30, 0x25, 0x85, 0x60, 0xeb, 0xd6, 0x6a, - 0xd1, 0xd1, 0xe8, 0xbb, 0x55, 0x74, 0x9d, 0x2d, 0x9a, 0x52, 0x31, 0xca, 0x6d, 0x27, 0xa1, 0xcd, 0xa4, 0xb7, 0x13, - 0x2d, 0x4b, 0x86, 0x16, 0x3b, 0x15, 0xfb, 0x61, 0x68, 0x7d, 0x2c, 0x88, 0x3f, 0x17, 0xfc, 0x59, 0xfa, 0x5d, 0x3e, - 0x06, 0xae, 0xd4, 0xbf, 0xb1, 0x0a, 0xe1, 0x4c, 0xb0, 0x0e, 0xc8, 0x6b, 0x52, 0x1f, 0xa7, 0x47, 0x9d, 0x7c, 0x4b, - 0xb9, 0x50, 0x1a, 0x85, 0x6d, 0x9c, 0x14, 0x06, 0x53, 0xce, 0xbe, 0x2d, 0x71, 0xfd, 0xea, 0x8f, 0x11, 0x7f, 0x74, - 0x88, 0x7f, 0x97, 0x4a, 0xa3, 0x65, 0x89, 0x60, 0xc8, 0xef, 0x48, 0xad, 0xe0, 0x2a, 0x36, 0xe7, 0xfa, 0xb9, 0x9e, - 0xe5, 0x1b, 0x9e, 0x38, 0x5d, 0xad, 0x4a, 0xa9, 0x40, 0xc5, 0x37, 0x0c, 0x3f, 0x61, 0x70, 0x6f, 0xfc, 0x8c, 0x07, - 0x55, 0xb6, 0xef, 0x8b, 0x9f, 0x05, 0xf7, 0xc5, 0xcf, 0x78, 0xba, 0x5d, 0x34, 0xb8, 0x27, 0xee, 0x24, 0xe7, 0x49, - 0x2b, 0xf2, 0x7c, 0xd4, 0x94, 0x56, 0xfe, 0x95, 0x76, 0x6b, 0xe0, 0xca, 0x26, 0x0e, 0x8c, 0xf3, 0xea, 0x22, 0x14, - 0x73, 0xe6, 0x8c, 0x96, 0xc3, 0xff, 0xd6, 0x3a, 0xb9, 0x93, 0x47, 0x5a, 0x29, 0xe4, 0x0d, 0x2d, 0xf4, 0x3d, 0xd8, - 0x70, 0xc5, 0x96, 0x0f, 0x20, 0x25, 0xa0, 0x6c, 0xfb, 0xf7, 0xba, 0x08, 0xc4, 0x71, 0x65, 0x9d, 0x8f, 0xc2, 0xf6, - 0x49, 0x51, 0x72, 0x75, 0x75, 0x21, 0xe4, 0xd6, 0x68, 0x09, 0x10, 0xa6, 0xde, 0x35, 0x8f, 0x39, 0x9a, 0xcc, 0xd2, - 0xe5, 0xba, 0x54, 0x1d, 0x14, 0x96, 0xab, 0xe3, 0x08, 0x17, 0x6b, 0x73, 0x83, 0xfe, 0x8a, 0xe3, 0xbf, 0xb9, 0xa3, - 0x91, 0x9f, 0x4a, 0x0a, 0xf4, 0x68, 0xb7, 0xaf, 0xcd, 0x0e, 0x12, 0x69, 0xe7, 0x50, 0x5a, 0x0a, 0x00, 0x56, 0x1b, - 0x7c, 0x5d, 0x7b, 0x9c, 0x7a, 0x22, 0xdd, 0x6c, 0xbe, 0x69, 0x08, 0x8b, 0x59, 0x69, 0xc1, 0x63, 0xba, 0xd9, 0x61, - 0x39, 0xea, 0x65, 0x71, 0x5d, 0xee, 0xb1, 0x5a, 0xbf, 0xe8, 0x1b, 0xa0, 0xac, 0x0c, 0xd1, 0x56, 0xab, 0xb8, 0x0e, - 0x6f, 0x22, 0x82, 0x6b, 0x10, 0x84, 0x45, 0x60, 0xc0, 0x51, 0x63, 0xbc, 0x6d, 0x9d, 0x18, 0x6d, 0xda, 0x2f, 0x79, - 0xd6, 0xbd, 0x36, 0x8e, 0x50, 0xd1, 0x60, 0xab, 0x87, 0x9a, 0x07, 0x6c, 0x67, 0x57, 0x76, 0x14, 0x40, 0x68, 0x4a, - 0xbd, 0x71, 0x6e, 0x65, 0x45, 0xbb, 0x03, 0xbe, 0xe8, 0x3b, 0xe6, 0xb9, 0x0e, 0x74, 0xdb, 0xf9, 0x81, 0x6d, 0xd3, - 0x13, 0xf9, 0x2d, 0xdb, 0xa6, 0x1a, 0x27, 0xbc, 0xdf, 0x42, 0xdf, 0x37, 0x84, 0xb5, 0x7d, 0xed, 0x2e, 0xf2, 0xbf, - 0xd0, 0x5d, 0x1b, 0xd0, 0xd3, 0x82, 0xd9, 0xd3, 0x98, 0x0f, 0x7a, 0xbd, 0xfe, 0x54, 0xfa, 0x2f, 0x18, 0x5b, 0xa1, - 0x4f, 0x76, 0x17, 0x38, 0xb1, 0xd2, 0x38, 0x04, 0xc7, 0xaf, 0x38, 0x99, 0xe4, 0x72, 0x48, 0xf3, 0x77, 0xd0, 0x63, - 0x95, 0xfb, 0xfc, 0x6e, 0x54, 0x50, 0xcd, 0x1c, 0xad, 0xa9, 0x46, 0xf1, 0x8a, 0x07, 0xc3, 0x78, 0xc5, 0x2d, 0xe5, - 0xae, 0x5a, 0xc0, 0xcb, 0x97, 0x65, 0x13, 0xe9, 0xa7, 0x75, 0x29, 0x83, 0xa9, 0xdd, 0xbd, 0x6c, 0x92, 0x34, 0x56, - 0x92, 0x34, 0xa6, 0xe2, 0xcd, 0xa6, 0xe2, 0xf8, 0xef, 0x6f, 0x0c, 0x76, 0x9b, 0xcc, 0xfd, 0x1d, 0x90, 0xb9, 0xbf, - 0x79, 0xfa, 0xdd, 0x5a, 0x01, 0xc5, 0x3b, 0x4e, 0x8e, 0x8d, 0x65, 0x8c, 0x1d, 0xf5, 0x5b, 0x0d, 0x06, 0x0d, 0x9a, - 0x5c, 0x06, 0xde, 0x0e, 0xd5, 0xe9, 0xe5, 0xed, 0x8f, 0xe2, 0x6c, 0xa1, 0xb4, 0x9c, 0xb9, 0x46, 0x95, 0xf3, 0x71, - 0x32, 0x99, 0xa0, 0xc0, 0x36, 0x77, 0xf8, 0x69, 0xdd, 0x8d, 0x6c, 0xf9, 0x99, 0x8b, 0x51, 0xaa, 0xb0, 0x3b, 0x5b, - 0x54, 0x2a, 0xd7, 0xc4, 0x9b, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0x17, 0x5c, 0x4d, 0x59, 0x11, 0x17, 0x68, 0xf9, 0xad, - 0xce, 0x0a, 0xb8, 0xcd, 0xb1, 0x9d, 0xe1, 0x51, 0x69, 0x39, 0xa0, 0x13, 0x68, 0x0d, 0x74, 0x46, 0x33, 0xa6, 0xa7, - 0x72, 0x04, 0x86, 0x2f, 0xc9, 0xa8, 0x74, 0xa7, 0x3a, 0x38, 0xd8, 0x8f, 0x23, 0xa3, 0xbf, 0x00, 0x1f, 0xf4, 0x30, - 0x07, 0xf5, 0x96, 0xe0, 0x18, 0x54, 0x75, 0xcd, 0xd0, 0x92, 0x6d, 0xfa, 0xd0, 0xe8, 0xe4, 0x33, 0xbb, 0xc3, 0x1c, - 0xad, 0xd7, 0xa9, 0x1d, 0x75, 0x34, 0xe6, 0x2c, 0x1f, 0x45, 0xf8, 0x33, 0xbb, 0x4b, 0x4b, 0xb7, 0x75, 0xe3, 0x65, - 0x6d, 0x16, 0x31, 0x92, 0x37, 0x22, 0xc2, 0x55, 0x27, 0xe9, 0x72, 0x8d, 0x65, 0xc1, 0x27, 0x80, 0xa3, 0xbf, 0xb0, - 0xbb, 0xd4, 0xb5, 0x17, 0xb8, 0x0a, 0xa2, 0xa5, 0x07, 0x7d, 0x12, 0x24, 0x87, 0xcb, 0xe0, 0x04, 0x8e, 0xbe, 0xa9, - 0x3b, 0x20, 0xb5, 0x72, 0x95, 0x08, 0x89, 0xd0, 0xfa, 0xdf, 0x9d, 0x0a, 0x5e, 0x84, 0xe7, 0x9c, 0xae, 0x59, 0xdc, - 0x6e, 0x54, 0x62, 0x50, 0xa1, 0xb2, 0x20, 0xf9, 0x18, 0x73, 0xbf, 0xfb, 0x9c, 0xf7, 0x43, 0xa0, 0x33, 0x5b, 0x50, - 0xd7, 0x68, 0x3a, 0x32, 0xbf, 0x50, 0x75, 0x07, 0x35, 0xd3, 0x55, 0xc5, 0xbd, 0x8f, 0x31, 0x00, 0x1e, 0xac, 0x65, - 0xa8, 0x71, 0x08, 0x5d, 0x7b, 0x33, 0xd5, 0x31, 0x25, 0xf1, 0xd2, 0xcf, 0x21, 0xe5, 0x21, 0x18, 0xf5, 0x1a, 0xd0, - 0xd0, 0x21, 0x98, 0xb5, 0x3c, 0xe4, 0xe3, 0x58, 0x6c, 0x9d, 0xa1, 0xd2, 0x9c, 0xa1, 0x49, 0x00, 0xf2, 0x6f, 0x9c, - 0x99, 0xcc, 0x40, 0xc3, 0xf0, 0x96, 0xe6, 0x00, 0x74, 0xab, 0xeb, 0x70, 0x28, 0x5c, 0xd1, 0xd2, 0x79, 0xcf, 0x2e, - 0xba, 0xac, 0x0d, 0x2b, 0x36, 0xed, 0xa0, 0x75, 0x0a, 0x53, 0x62, 0xb6, 0xc0, 0xda, 0xeb, 0x7d, 0xb8, 0xb7, 0xab, - 0x8d, 0x8b, 0xc4, 0x4f, 0x8b, 0x78, 0x98, 0xc4, 0x14, 0x2d, 0x79, 0x4c, 0xb1, 0x04, 0x3b, 0xc8, 0x62, 0x5d, 0x8e, - 0x9f, 0x85, 0xcb, 0x51, 0xb3, 0x92, 0xde, 0xed, 0x60, 0x08, 0x5c, 0xbe, 0x06, 0xdb, 0x50, 0xcc, 0x3d, 0x61, 0xe1, - 0xb1, 0xf1, 0xf4, 0x0b, 0xd6, 0x6d, 0x6e, 0x17, 0xc4, 0xaf, 0xc0, 0x98, 0xc6, 0xcb, 0x60, 0x16, 0xa1, 0x53, 0xb9, - 0x73, 0x38, 0x74, 0xd7, 0x84, 0x95, 0xf1, 0x6a, 0xac, 0xc8, 0xc6, 0xd1, 0xf3, 0x7d, 0x1b, 0xcf, 0x7f, 0x16, 0xac, - 0xb8, 0xbb, 0x62, 0x60, 0x63, 0x2d, 0xc1, 0xdd, 0xb8, 0x5a, 0x86, 0xca, 0x40, 0xbe, 0x27, 0x0d, 0xeb, 0xb2, 0xc6, - 0xdf, 0x8d, 0x8a, 0xb1, 0x36, 0xf7, 0x94, 0x81, 0xb6, 0xc6, 0x6e, 0x17, 0xf6, 0x4d, 0xd7, 0x4d, 0xd6, 0x35, 0x8a, - 0xb8, 0x0a, 0xd2, 0xee, 0x6e, 0x01, 0x17, 0xa1, 0x3f, 0x6c, 0x5f, 0x0d, 0x36, 0x55, 0x37, 0x90, 0x04, 0xd7, 0x7e, - 0xf2, 0xdb, 0x53, 0xdd, 0x65, 0xad, 0xfb, 0xed, 0xa9, 0xd6, 0x2e, 0x0b, 0x8d, 0x21, 0x11, 0x76, 0xfd, 0x94, 0xfe, - 0xd3, 0x62, 0xbd, 0x46, 0x6b, 0x18, 0xde, 0x7b, 0xde, 0x8d, 0xe3, 0xf7, 0xde, 0x42, 0x31, 0x81, 0x8b, 0xdc, 0xab, - 0x5c, 0x7a, 0x42, 0x5e, 0x8d, 0xe0, 0x3d, 0xdf, 0x1a, 0xc2, 0x7b, 0x1e, 0x38, 0xbd, 0x82, 0xd4, 0x34, 0x11, 0x6c, - 0xe4, 0xe9, 0x27, 0xb2, 0x48, 0x68, 0xf8, 0xb8, 0xd7, 0x9c, 0x70, 0xfd, 0x57, 0x0a, 0xfc, 0x17, 0x1e, 0x2e, 0xb4, - 0x96, 0x02, 0x73, 0x31, 0x5f, 0x68, 0xac, 0xcc, 0xe8, 0x97, 0x63, 0x29, 0x74, 0x73, 0x4c, 0x67, 0x3c, 0xbf, 0x4b, - 0x17, 0xbc, 0x39, 0x93, 0x42, 0xaa, 0x39, 0xcd, 0x18, 0x56, 0x77, 0x4a, 0xb3, 0x59, 0x73, 0xc1, 0xf1, 0x73, 0x96, - 0x7f, 0x61, 0x9a, 0x67, 0x14, 0xbf, 0x95, 0x43, 0xa9, 0x25, 0x7e, 0x7d, 0x7b, 0x37, 0x61, 0x02, 0xff, 0x3e, 0x5c, - 0x08, 0xbd, 0xc0, 0x8a, 0x0a, 0xd5, 0x54, 0xac, 0xe0, 0xe3, 0x6e, 0xb3, 0x39, 0x2f, 0xf8, 0x8c, 0x16, 0x77, 0xcd, - 0x4c, 0xe6, 0xb2, 0x48, 0xff, 0xab, 0x75, 0x4c, 0x1f, 0x8c, 0x4f, 0xba, 0xba, 0xa0, 0x42, 0x71, 0x58, 0x98, 0x94, - 0xe6, 0xf9, 0xde, 0xf1, 0x69, 0x6b, 0xa6, 0xf6, 0xed, 0x85, 0x1f, 0x15, 0x7a, 0xfd, 0x17, 0xfe, 0x20, 0x61, 0x94, - 0xc9, 0x50, 0x0b, 0x37, 0xc8, 0x65, 0xb6, 0x28, 0x94, 0x2c, 0xd2, 0xb9, 0xe4, 0x42, 0xb3, 0xa2, 0x3b, 0x94, 0xc5, - 0x88, 0x15, 0xcd, 0x82, 0x8e, 0xf8, 0x42, 0xa5, 0x27, 0xf3, 0xdb, 0x6e, 0xbd, 0x07, 0x9b, 0x9f, 0x0a, 0x29, 0x58, - 0x17, 0xf8, 0x8d, 0x49, 0x21, 0x17, 0x62, 0xe4, 0x86, 0xb1, 0x10, 0x8a, 0xe9, 0xee, 0x9c, 0x8e, 0xc0, 0x0e, 0x38, - 0x3d, 0x9f, 0xdf, 0x76, 0xcd, 0xac, 0x6f, 0x18, 0x9f, 0x4c, 0x75, 0x7a, 0xda, 0x6a, 0xd9, 0x6f, 0xc5, 0xbf, 0xb2, - 0xb4, 0xdd, 0x49, 0x3a, 0xa7, 0xf3, 0x5b, 0xe0, 0xe0, 0x35, 0x2b, 0x9a, 0x00, 0x0b, 0xa8, 0xd4, 0x4e, 0x5a, 0x0f, - 0x8e, 0xef, 0x43, 0x06, 0xd8, 0x38, 0x34, 0xcd, 0x84, 0xc0, 0xd8, 0x3d, 0x5d, 0xcc, 0xe7, 0xac, 0x00, 0x2f, 0xfa, - 0xee, 0x8c, 0x16, 0x13, 0x2e, 0x9a, 0x85, 0x69, 0xb4, 0x79, 0x3e, 0xbf, 0x5d, 0xc3, 0x7c, 0x52, 0x6b, 0xb6, 0xea, - 0xa6, 0xe5, 0xbe, 0x96, 0xc1, 0x10, 0x4d, 0x4c, 0x9a, 0xb4, 0x98, 0x0c, 0x69, 0xdc, 0xee, 0xdc, 0xc7, 0xfe, 0x7f, - 0x49, 0x07, 0x05, 0x60, 0x6b, 0x8e, 0x16, 0x85, 0xb9, 0x45, 0x4d, 0xdb, 0xca, 0x36, 0x3b, 0x95, 0x5f, 0x58, 0xe1, - 0x5b, 0x35, 0x1f, 0xcb, 0xad, 0x79, 0xff, 0x27, 0x8d, 0xfe, 0x85, 0x27, 0x14, 0xd6, 0xc0, 0x20, 0x47, 0xdf, 0xc8, - 0x83, 0x30, 0xd3, 0xc1, 0xf2, 0x86, 0x8f, 0xf4, 0x34, 0x6d, 0xb7, 0x5a, 0x3f, 0x54, 0x2b, 0xd6, 0x9d, 0x5a, 0xd0, - 0xb5, 0x0b, 0x36, 0xab, 0xad, 0xe3, 0x8c, 0x96, 0xd8, 0xb6, 0x9c, 0x4b, 0xb7, 0xe4, 0x05, 0xcb, 0x4d, 0x34, 0x99, - 0xb5, 0x43, 0xb9, 0xad, 0x71, 0x72, 0x31, 0x65, 0x05, 0xd7, 0xdd, 0xfa, 0x57, 0xd5, 0xf1, 0xf6, 0xea, 0xaf, 0xad, - 0x1c, 0xba, 0xb4, 0x35, 0xdc, 0xa5, 0xe7, 0x63, 0xf8, 0xd8, 0x5e, 0xfd, 0x2f, 0xb4, 0x88, 0x37, 0x10, 0x13, 0x87, - 0x35, 0xd0, 0x3a, 0x98, 0x73, 0x01, 0x26, 0x99, 0x03, 0xfc, 0x0d, 0x28, 0x64, 0x34, 0xcf, 0x62, 0x18, 0xd1, 0x5e, - 0x73, 0xef, 0xb8, 0x60, 0x33, 0xe4, 0x01, 0x91, 0xdc, 0x3f, 0x2d, 0xd8, 0x6c, 0x9d, 0x98, 0xea, 0x4b, 0x83, 0x22, - 0x34, 0xe7, 0x13, 0x91, 0x66, 0x0c, 0xd0, 0x77, 0x9d, 0x30, 0xa1, 0xb9, 0xbe, 0x6b, 0x16, 0xf2, 0x66, 0x39, 0xe2, - 0x6a, 0x9e, 0xd3, 0xbb, 0x74, 0x9c, 0xb3, 0xdb, 0xae, 0x29, 0xd5, 0xe4, 0x9a, 0xcd, 0x94, 0x2b, 0xdb, 0x85, 0xf4, - 0xe6, 0xc8, 0x9a, 0x4d, 0x00, 0xf4, 0xe4, 0xcd, 0xe6, 0xfe, 0x49, 0x8e, 0xd5, 0x1e, 0xa3, 0x8a, 0x35, 0xe5, 0x42, - 0xef, 0xb5, 0x54, 0x77, 0xc6, 0x45, 0xd3, 0x0d, 0xe4, 0xa4, 0x35, 0xbf, 0xed, 0x6e, 0x43, 0x3e, 0xe8, 0x3f, 0x61, - 0xb7, 0x73, 0x2a, 0x46, 0x6c, 0xb4, 0x0c, 0xaa, 0x75, 0xa0, 0x5e, 0x58, 0x2a, 0x15, 0x7a, 0xda, 0x34, 0xb6, 0x5e, - 0x71, 0x47, 0xa0, 0x6f, 0xa0, 0xd6, 0x83, 0x16, 0xb6, 0xff, 0x9f, 0xb4, 0x51, 0x58, 0x79, 0x0f, 0xc2, 0x2e, 0xf1, - 0xf1, 0x5d, 0x13, 0xfe, 0x2e, 0xc1, 0xb7, 0x88, 0x67, 0x34, 0x77, 0x10, 0x99, 0xf1, 0xd1, 0x28, 0xaf, 0x8d, 0xe8, - 0x32, 0xe8, 0xac, 0x8d, 0x96, 0x30, 0xff, 0xb4, 0xb5, 0xd7, 0xda, 0x33, 0x73, 0x71, 0xdb, 0xfc, 0xe4, 0xe4, 0xfe, - 0xf1, 0x03, 0xd6, 0xcd, 0xb9, 0x60, 0xb5, 0xa9, 0x7e, 0x17, 0xd4, 0x61, 0xc3, 0x1d, 0xd7, 0x70, 0x7b, 0xaf, 0xbd, - 0x77, 0xd2, 0xfa, 0xc1, 0xef, 0xd6, 0x9c, 0x8d, 0x75, 0xda, 0x3e, 0x9b, 0xdf, 0xd6, 0xb7, 0xef, 0xb9, 0x6f, 0xfa, - 0xa6, 0xa0, 0xf3, 0x54, 0x48, 0xf8, 0xd3, 0x85, 0x4d, 0x36, 0xce, 0xe5, 0x4d, 0x3a, 0xe5, 0xa3, 0x11, 0x13, 0xb6, - 0x40, 0x99, 0xc8, 0xf2, 0x9c, 0xcf, 0x15, 0xb7, 0xab, 0xe1, 0x70, 0xf7, 0x74, 0x03, 0xaa, 0xe1, 0x80, 0x8e, 0x83, - 0x01, 0x9d, 0x56, 0x03, 0xaa, 0xfa, 0x0f, 0x47, 0xd8, 0xd9, 0x98, 0xab, 0x29, 0xd5, 0xad, 0x61, 0xd2, 0xdf, 0x0b, - 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, - 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, - 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, - 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x70, 0xe7, 0x99, 0x76, 0x07, 0x69, 0xda, 0xbc, 0x61, - 0xc3, 0xcf, 0x5c, 0x5b, 0x3c, 0x6b, 0xaa, 0x1b, 0xf0, 0x78, 0x31, 0xcb, 0x30, 0x67, 0xc5, 0xd2, 0xd3, 0xf0, 0x56, - 0x8d, 0xea, 0x5c, 0x09, 0x73, 0x7a, 0x68, 0x3a, 0x6c, 0x42, 0xfc, 0x2f, 0x56, 0x94, 0x7b, 0x8c, 0x0b, 0x83, 0x31, - 0x06, 0x40, 0x9b, 0xbb, 0x24, 0x3c, 0x03, 0x4e, 0x5a, 0x2d, 0x7f, 0x3e, 0x34, 0x6d, 0x9d, 0xb4, 0x9d, 0x9c, 0xb2, - 0xd9, 0xae, 0xfd, 0x59, 0x27, 0x46, 0xed, 0xce, 0xfc, 0x76, 0xcf, 0xfc, 0xd3, 0xda, 0x6b, 0x6d, 0x13, 0x9f, 0x6d, - 0x38, 0x1d, 0x23, 0xbf, 0xb2, 0x5a, 0xce, 0xd3, 0x36, 0x9b, 0x75, 0x17, 0x0a, 0x0e, 0x1a, 0x43, 0x1b, 0xcd, 0x01, - 0xb6, 0x36, 0x33, 0x81, 0x75, 0xa4, 0x5c, 0x00, 0x5d, 0xb7, 0x67, 0x1b, 0xf4, 0xa1, 0x24, 0x18, 0x62, 0xef, 0x6c, - 0xb4, 0x3e, 0xac, 0xd6, 0x5e, 0x35, 0x30, 0xf8, 0x67, 0xfd, 0x57, 0xc5, 0x19, 0xbe, 0x60, 0x01, 0x67, 0xce, 0x1b, - 0xc9, 0xe9, 0xaa, 0xe5, 0xb8, 0xf1, 0x91, 0xae, 0x84, 0x04, 0xe3, 0xcb, 0x30, 0xa3, 0xb7, 0xd6, 0xa9, 0x61, 0xc6, - 0x05, 0x98, 0x4c, 0x21, 0xac, 0x03, 0xe3, 0xf2, 0x69, 0xd8, 0xd0, 0x48, 0xc7, 0xd0, 0xf0, 0x61, 0x27, 0x39, 0x3d, - 0x45, 0xb8, 0x85, 0x3b, 0xa7, 0xa7, 0x81, 0x34, 0x30, 0xd6, 0xbb, 0x8a, 0xee, 0x2a, 0xa9, 0x76, 0x94, 0x3c, 0x32, - 0x8d, 0x1e, 0xb5, 0x5b, 0x2d, 0x6c, 0x1c, 0xb7, 0xcb, 0xc2, 0x5c, 0xed, 0x68, 0xb6, 0xdd, 0x6a, 0x41, 0xb3, 0xf0, - 0xc7, 0xcd, 0xeb, 0x17, 0xb2, 0x6c, 0xa5, 0x2d, 0xdc, 0x4e, 0xdb, 0xb8, 0x93, 0x76, 0xf0, 0x71, 0x7a, 0x8c, 0x4f, - 0xd2, 0x13, 0x7c, 0x9a, 0x9e, 0xe2, 0xb3, 0xf4, 0x0c, 0xdf, 0x4f, 0xef, 0xe3, 0xf3, 0xf4, 0x1c, 0x3f, 0x48, 0x1f, - 0xe0, 0x87, 0x69, 0xbb, 0x85, 0x1f, 0xa5, 0xed, 0x36, 0x7e, 0x9c, 0xb6, 0x3b, 0xf8, 0x49, 0xda, 0x3e, 0xc6, 0x4f, - 0xd3, 0xf6, 0x09, 0x7e, 0x96, 0xb6, 0x4f, 0x31, 0x85, 0xdc, 0x21, 0xe4, 0x66, 0x90, 0x3b, 0x82, 0x5c, 0x06, 0xb9, - 0xe3, 0xb4, 0x7d, 0xba, 0xc6, 0xca, 0x06, 0x7b, 0x88, 0x5a, 0xed, 0xce, 0xf1, 0xc9, 0xe9, 0xd9, 0xfd, 0xf3, 0x07, - 0x0f, 0x1f, 0x3d, 0x7e, 0xf2, 0xf4, 0x59, 0x34, 0xc0, 0x43, 0xe3, 0x73, 0xa1, 0x44, 0x9f, 0x1f, 0xb4, 0x4f, 0x07, - 0xf8, 0xda, 0x7f, 0xc6, 0xfc, 0xa0, 0x73, 0xd2, 0x42, 0x97, 0x97, 0x27, 0x83, 0x46, 0x99, 0xfb, 0xde, 0xb8, 0x7a, - 0x54, 0x59, 0x84, 0x90, 0x18, 0x72, 0x10, 0xbe, 0x33, 0xf5, 0xde, 0xb3, 0x98, 0x27, 0x05, 0x3a, 0x38, 0x30, 0x3f, - 0x26, 0xfe, 0xc7, 0xd0, 0xff, 0xa0, 0xc1, 0x22, 0xdd, 0xd2, 0xd8, 0xf9, 0xfa, 0xea, 0xd2, 0xd2, 0xbe, 0x34, 0x62, - 0xd9, 0xe3, 0xce, 0x9c, 0xfc, 0xbf, 0x22, 0x6b, 0x2e, 0x42, 0x4e, 0xac, 0x4a, 0xe6, 0xb4, 0xc7, 0xc8, 0xb2, 0x48, - 0x3b, 0xa7, 0xa7, 0x07, 0xbf, 0xf4, 0x79, 0xbf, 0x3d, 0x18, 0x1c, 0xb6, 0xef, 0xe3, 0x49, 0x99, 0xd0, 0xb1, 0x09, - 0xc3, 0x32, 0xe1, 0xd8, 0x26, 0xd0, 0xd4, 0xd6, 0x86, 0xa4, 0x13, 0x93, 0x04, 0x25, 0xd6, 0xa9, 0x69, 0xfb, 0xbe, - 0x6d, 0xfb, 0x01, 0xd8, 0x31, 0x99, 0xe6, 0x5d, 0xd3, 0x17, 0x17, 0x27, 0x2b, 0xd7, 0x28, 0x9e, 0xa4, 0xae, 0x35, - 0x9f, 0x78, 0x32, 0x18, 0xe0, 0xa1, 0x49, 0x3c, 0xad, 0x12, 0xcf, 0x06, 0x03, 0xd7, 0xd5, 0x03, 0xd3, 0xd5, 0xfd, - 0x2a, 0xeb, 0x7c, 0x30, 0x30, 0x5d, 0x22, 0xe7, 0xb5, 0xae, 0xf4, 0xde, 0x97, 0x52, 0x73, 0xc0, 0x2f, 0x3a, 0xa7, - 0xa7, 0x3d, 0xc0, 0x30, 0x63, 0x8d, 0xea, 0x61, 0x74, 0x13, 0xc0, 0xe8, 0x0e, 0x7e, 0xf7, 0x86, 0x34, 0xbd, 0xa6, - 0x25, 0x90, 0x7a, 0xd1, 0x7f, 0x45, 0x0d, 0x6d, 0x60, 0x6e, 0xfe, 0x4c, 0xec, 0x9f, 0x21, 0x6a, 0x7c, 0xa1, 0x00, - 0x6e, 0xd0, 0x85, 0x78, 0x65, 0xa6, 0xe9, 0xf1, 0x33, 0x05, 0xe7, 0x92, 0xa9, 0xca, 0x69, 0x6f, 0x35, 0xbd, 0x19, - 0xae, 0xa6, 0xea, 0x0b, 0xfa, 0x33, 0xfe, 0x53, 0x1d, 0xc6, 0xfd, 0x66, 0x23, 0x61, 0x7f, 0x8e, 0xc0, 0x8b, 0xa5, - 0x97, 0x8e, 0xd8, 0x04, 0xf5, 0xfa, 0x7f, 0x2a, 0x3c, 0x68, 0x04, 0x19, 0x3f, 0x6c, 0xa7, 0x80, 0x8f, 0xcb, 0x66, - 0x62, 0xfc, 0x03, 0xea, 0xa1, 0xde, 0x9f, 0xea, 0xf0, 0x4f, 0x74, 0xef, 0xa8, 0x9a, 0xcb, 0xef, 0xd2, 0x6d, 0xe1, - 0x2a, 0xf0, 0xcd, 0x61, 0xb9, 0x85, 0x19, 0x6e, 0x37, 0x19, 0x84, 0x09, 0x03, 0x27, 0x68, 0x12, 0xcb, 0x06, 0x3f, - 0x3a, 0x6e, 0xa1, 0x1f, 0xda, 0x1d, 0x10, 0xeb, 0x9b, 0xe2, 0x70, 0x7b, 0xd3, 0x17, 0xcd, 0x63, 0xfc, 0xa0, 0x59, - 0xe0, 0x36, 0xc2, 0xcd, 0xb6, 0xd7, 0xb7, 0xf6, 0x55, 0xdc, 0x42, 0x58, 0xc5, 0xe7, 0xf0, 0xcf, 0x09, 0x1a, 0x54, - 0x1b, 0xf2, 0x8a, 0x6e, 0xf6, 0x0e, 0x1e, 0x9b, 0x24, 0x56, 0x0d, 0x7e, 0x74, 0xd6, 0x42, 0x3f, 0x9c, 0x99, 0x8e, - 0xd8, 0xa1, 0xde, 0xd1, 0x95, 0xc4, 0x27, 0x4d, 0x09, 0x1d, 0xb5, 0xca, 0x7e, 0x44, 0x7c, 0x8a, 0xb0, 0x88, 0x8f, - 0xe1, 0x9f, 0x76, 0xd8, 0xcf, 0xaf, 0x5b, 0xfd, 0x98, 0x79, 0xb7, 0x71, 0x72, 0x6a, 0x1d, 0x40, 0x95, 0xbd, 0x8d, - 0x6d, 0xb0, 0xcb, 0xb6, 0xb9, 0x46, 0x6a, 0x1f, 0xc1, 0x07, 0xc2, 0xfa, 0x90, 0x28, 0xcc, 0x0e, 0xc1, 0x73, 0x14, - 0x0c, 0x26, 0xd4, 0xc5, 0x71, 0x57, 0x35, 0x1a, 0x48, 0xf4, 0xd5, 0xe0, 0x90, 0xb4, 0x9b, 0xba, 0xc9, 0x30, 0xfc, - 0x6e, 0x90, 0x32, 0x1c, 0x99, 0xa8, 0x7a, 0x7d, 0xec, 0x7a, 0xb5, 0x77, 0xce, 0x1e, 0x3b, 0x08, 0x21, 0xaa, 0x17, - 0xeb, 0x26, 0x43, 0x47, 0xa2, 0x11, 0xeb, 0x0b, 0xd6, 0x3b, 0x4b, 0x5b, 0xc8, 0x60, 0xa7, 0xea, 0xc5, 0xac, 0xc9, - 0x21, 0xbd, 0x93, 0xc6, 0xbc, 0xa9, 0xe1, 0xd7, 0x49, 0x30, 0x0b, 0x01, 0x78, 0x57, 0xf9, 0xc1, 0x14, 0x47, 0x9d, - 0xd3, 0x53, 0x2c, 0x08, 0x4f, 0x26, 0xe6, 0x97, 0x22, 0x3c, 0x19, 0x9a, 0x5f, 0x92, 0x94, 0xf0, 0xb2, 0xbd, 0xe3, - 0x82, 0x04, 0xab, 0x6a, 0x52, 0x28, 0x2c, 0x68, 0x81, 0x8e, 0x3a, 0xfe, 0x42, 0x1a, 0x4f, 0xfd, 0x1c, 0x40, 0x00, - 0x2f, 0x8c, 0x2d, 0xa2, 0x6c, 0x16, 0x38, 0x27, 0xf4, 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, - 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, 0xb6, 0x86, 0xa7, 0x70, 0x8b, 0x98, 0x91, 0xec, 0xf0, 0xac, - 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, - 0xa5, 0x8e, 0x68, 0x33, 0x2a, 0x4c, 0x8f, 0xc7, 0x1a, 0x6e, 0xc4, 0x35, 0xf8, 0x99, 0x68, 0xf0, 0x80, 0x49, 0xb9, - 0xbb, 0x8a, 0x42, 0x26, 0x2e, 0xde, 0x38, 0xd4, 0x1a, 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x4d, 0xa3, 0x88, 0x7f, 0x97, - 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, - 0x03, 0x1d, 0x17, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, - 0xad, 0x34, 0xf9, 0x4c, 0xad, 0x95, 0x3f, 0xf7, 0xee, 0xc6, 0x66, 0xe1, 0xac, 0xb3, 0x73, 0xe9, 0xd9, 0xdc, 0x3f, - 0x05, 0x2b, 0x0a, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, - 0xa1, 0xf2, 0x32, 0xf5, 0xa3, 0x84, 0xa4, 0xce, 0x00, 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, - 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x95, 0xe1, 0x5c, 0x01, 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0xeb, - 0x6e, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0xb0, - 0xf4, 0xc0, 0x93, 0x14, 0xac, 0x3c, 0xf0, 0x30, 0x15, 0xe0, 0x89, 0x40, 0x53, 0x16, 0xd8, 0x8f, 0x3f, 0x74, 0xba, - 0x23, 0x73, 0xdf, 0x49, 0x0c, 0x96, 0x76, 0x19, 0x9c, 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, - 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, - 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0x5f, 0x21, 0x6b, 0xdb, 0x38, 0xdc, 0x4d, 0x43, 0x13, 0x82, 0x70, 0x15, - 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0xf0, 0x22, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, - 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, - 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x47, 0x34, 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, - 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, - 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0x26, 0x1c, 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x76, 0xf8, - 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, - 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, - 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, - 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, - 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, - 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, - 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, - 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, - 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, - 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, - 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, - 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, 0x26, 0x8d, 0x12, 0x7d, 0xcc, 0x86, 0xd9, 0x28, 0xc2, 0x66, - 0x30, 0x63, 0xf8, 0xfb, 0x85, 0xbf, 0x63, 0x3a, 0x8d, 0xce, 0x69, 0x67, 0xc8, 0x3a, 0x11, 0x1e, 0xbe, 0xb9, 0x11, - 0x69, 0x44, 0x4f, 0x3b, 0xb4, 0x43, 0x23, 0x3c, 0x5c, 0x14, 0xf9, 0xdd, 0x8d, 0x94, 0x23, 0x00, 0xc2, 0xf0, 0xfc, - 0xfc, 0x7e, 0x84, 0x33, 0xfa, 0xab, 0x86, 0xda, 0xa7, 0xe3, 0x07, 0x8c, 0xb6, 0x22, 0xfc, 0x0b, 0x2d, 0xf4, 0xc7, - 0x85, 0x72, 0x03, 0x6d, 0x41, 0x8a, 0xcc, 0xde, 0x81, 0x82, 0x39, 0x1a, 0x75, 0xce, 0x1e, 0xb4, 0x59, 0x84, 0xb3, - 0xab, 0xd7, 0xd0, 0xdb, 0xfd, 0xf1, 0x69, 0x0b, 0x3e, 0x04, 0x48, 0x6a, 0xac, 0x80, 0x46, 0xce, 0x4e, 0x1e, 0x9c, - 0xb2, 0x91, 0x49, 0x54, 0x3c, 0xff, 0x6c, 0x66, 0x7f, 0x0e, 0xf3, 0xc9, 0x0a, 0x3e, 0x53, 0x52, 0xa4, 0xd1, 0x28, - 0x6b, 0x9f, 0x1c, 0x43, 0xc2, 0x1d, 0x15, 0x1e, 0x38, 0xb7, 0x50, 0xf5, 0x7c, 0x18, 0xe1, 0x5b, 0x9b, 0x7a, 0x3e, - 0x34, 0x1f, 0x93, 0x77, 0xbf, 0x8a, 0x37, 0xa3, 0x34, 0x1a, 0x9e, 0x9f, 0x9f, 0xb5, 0x20, 0xe1, 0x03, 0xbd, 0x4b, - 0x23, 0xfa, 0x00, 0xfe, 0x83, 0xec, 0x8f, 0xcf, 0xa0, 0x43, 0x18, 0xe1, 0xed, 0xe4, 0x63, 0x98, 0xf3, 0x79, 0x4a, - 0x3f, 0xf3, 0x34, 0x1a, 0x8e, 0x86, 0xf7, 0xcf, 0xa0, 0xde, 0x8c, 0x4e, 0x9e, 0x69, 0x0a, 0xed, 0xb6, 0x5a, 0xa6, - 0xe5, 0x77, 0xfc, 0x0b, 0x33, 0xd5, 0x4f, 0x4f, 0xcf, 0x86, 0x1d, 0x18, 0xc1, 0x15, 0xa8, 0x18, 0x60, 0x3c, 0xe7, - 0x99, 0x69, 0xf0, 0x2a, 0x7b, 0x3a, 0x4a, 0xa3, 0x07, 0x0f, 0x8e, 0x3b, 0x59, 0x16, 0xe1, 0xdb, 0x8f, 0x23, 0x5b, - 0xdb, 0xe4, 0x29, 0x80, 0x7d, 0x1a, 0xb1, 0x07, 0x0f, 0xce, 0xee, 0x53, 0xf8, 0x7e, 0x6e, 0xda, 0x3a, 0x1f, 0x0f, - 0xb3, 0x73, 0x68, 0xeb, 0x77, 0x98, 0xce, 0xc9, 0xf9, 0xf1, 0xc8, 0xf4, 0xf5, 0xbb, 0x19, 0x75, 0x67, 0x7c, 0x32, - 0x3e, 0x31, 0x99, 0x66, 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x8d, 0x32, 0x36, 0x6a, 0x47, 0xf8, 0xd6, 0x2d, 0xdc, 0x83, - 0x93, 0x56, 0x6b, 0x74, 0x1c, 0xe1, 0xd1, 0xc3, 0xf9, 0xfc, 0xad, 0x81, 0x60, 0xfb, 0xe4, 0x81, 0xfd, 0x56, 0x9f, - 0xef, 0xa0, 0xe9, 0xa1, 0x01, 0xda, 0x88, 0xcf, 0x4c, 0xcb, 0x67, 0x0f, 0xe0, 0x3f, 0xf3, 0x6d, 0x9a, 0x2e, 0xbf, - 0xe5, 0x68, 0x62, 0x17, 0xa5, 0xcd, 0x1e, 0xb4, 0xa0, 0xc6, 0x98, 0x7f, 0x1c, 0x16, 0x1c, 0xd0, 0x68, 0xd8, 0x81, - 0xff, 0x8b, 0xf0, 0x38, 0xbf, 0x7a, 0xed, 0x70, 0x76, 0x3c, 0xa6, 0xe3, 0x56, 0x84, 0xc7, 0xf2, 0xa3, 0xd2, 0x1f, - 0x1e, 0x8a, 0x34, 0xea, 0x74, 0xce, 0x87, 0xa6, 0xcc, 0xe2, 0x17, 0xc5, 0x0d, 0x1e, 0xb7, 0x4c, 0x2b, 0x13, 0xfa, - 0x56, 0x0d, 0xaf, 0x24, 0xac, 0x24, 0xfc, 0x17, 0xe1, 0x09, 0xe8, 0xa5, 0x5c, 0x2b, 0xe7, 0x76, 0x3b, 0x4c, 0xde, - 0x19, 0xd4, 0x1c, 0xdd, 0x07, 0x78, 0xf9, 0x65, 0x1c, 0x51, 0x7a, 0xda, 0x69, 0x45, 0xd8, 0x8c, 0xfa, 0xbc, 0x05, - 0xff, 0x45, 0xd8, 0x42, 0xce, 0xc0, 0x75, 0xf2, 0xf1, 0xd9, 0xcb, 0x9b, 0x34, 0xa2, 0xa3, 0xf1, 0x18, 0x96, 0xc4, - 0x4c, 0xc6, 0x17, 0x9b, 0x4a, 0xc1, 0xee, 0x7e, 0xbd, 0x71, 0xdb, 0xc5, 0x24, 0x68, 0x07, 0x9d, 0xb3, 0x07, 0xc3, - 0x93, 0x08, 0xbf, 0x1d, 0x71, 0x2a, 0x60, 0x95, 0xb2, 0xd1, 0x69, 0x76, 0x9a, 0x99, 0x84, 0x89, 0x4c, 0xa3, 0x13, - 0x58, 0xf2, 0x4e, 0x84, 0xf9, 0x97, 0xab, 0x3b, 0x8b, 0x6e, 0x50, 0xdb, 0x21, 0xc8, 0xb8, 0xc5, 0xce, 0xce, 0xb3, - 0x08, 0xe7, 0xf4, 0xcb, 0xb3, 0x5f, 0x8b, 0x34, 0x62, 0x67, 0xec, 0x6c, 0x4c, 0xfd, 0xf7, 0x1f, 0x6a, 0x6a, 0x6a, - 0xb4, 0xc6, 0xa7, 0x90, 0x74, 0x23, 0xcc, 0x58, 0xef, 0x67, 0x63, 0x83, 0x21, 0xaf, 0x66, 0x52, 0x64, 0x4f, 0xc7, - 0x63, 0x69, 0xb1, 0x98, 0xc2, 0x26, 0xfc, 0x04, 0xd0, 0xa6, 0xa3, 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x27, 0xbb, 0x4b, - 0xdc, 0x04, 0x3e, 0x59, 0xcc, 0x66, 0x6e, 0xb7, 0x7f, 0xb2, 0x40, 0x81, 0xf9, 0x8e, 0xe9, 0x98, 0x8e, 0x3a, 0x11, - 0xfe, 0x64, 0xe0, 0x32, 0x3a, 0x86, 0xff, 0xa0, 0x00, 0x74, 0xf6, 0xa0, 0xc5, 0xd8, 0x83, 0x96, 0xf9, 0x0a, 0xf3, - 0xdc, 0xcc, 0x87, 0x67, 0x59, 0x3b, 0xc2, 0x9f, 0x1c, 0x3a, 0x8e, 0xc7, 0xb4, 0x05, 0xe8, 0xf8, 0xc9, 0xa1, 0x63, - 0xa7, 0x35, 0xec, 0x50, 0xf3, 0x6d, 0xb1, 0xe6, 0xfc, 0x7e, 0xc6, 0x60, 0x72, 0x9f, 0x2c, 0x42, 0xde, 0xbf, 0x7f, - 0x7e, 0xfe, 0xe0, 0x01, 0x7c, 0x9a, 0xb6, 0xcb, 0x4f, 0xa5, 0x1f, 0xe6, 0x06, 0xc9, 0x5a, 0xd9, 0x09, 0xd0, 0xc9, - 0x4f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, - 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, - 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, - 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, - 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, - 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, - 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, - 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, - 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, - 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, - 0x87, 0x23, 0xfc, 0x6e, 0x04, 0xd7, 0x60, 0x69, 0x34, 0x1e, 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, - 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, - 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, - 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, - 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, - 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, - 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, - 0x21, 0xdc, 0xf3, 0x2d, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, 0x08, 0x6e, 0xfd, 0xe4, 0xcd, 0xaf, 0x85, 0x45, 0x23, - 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, - 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, - 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, - 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, - 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, - 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, - 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, - 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, - 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, - 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, - 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, - 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, - 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, - 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0x3d, 0xe8, 0x13, 0x1a, 0x7b, 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xe1, 0x45, 0x3f, - 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x5c, 0x00, 0x9c, 0x41, 0xbd, 0xf3, 0x99, 0x04, 0x41, 0x52, - 0x90, 0x56, 0x57, 0x5c, 0x78, 0x3f, 0xce, 0xae, 0x80, 0xa0, 0x03, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0xc4, 0x66, 0xb1, - 0xc2, 0xa4, 0x37, 0x6f, 0x37, 0x32, 0xa5, 0xb4, 0x06, 0xf3, 0x94, 0x50, 0x1f, 0x95, 0x1d, 0x2e, 0x69, 0x21, 0x6e, - 0x11, 0xea, 0x4a, 0x62, 0x62, 0x2c, 0xbf, 0x10, 0x3a, 0x56, 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0x5e, - 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0x11, - 0xa3, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, - 0x47, 0x2c, 0x31, 0xb7, 0x06, 0xd6, 0x37, 0x85, 0xf4, 0x41, 0x73, 0xd6, 0xc2, 0x10, 0xc7, 0xdc, 0x73, 0xde, 0x8f, - 0x58, 0x9f, 0xd7, 0xfd, 0x9a, 0xab, 0xe0, 0xc1, 0x07, 0x07, 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, - 0x56, 0x4c, 0xd0, 0x55, 0xf8, 0xf6, 0x93, 0x1e, 0x48, 0x29, 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, - 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, - 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, 0x49, 0x23, 0x9a, 0xed, 0xdb, 0x48, 0x18, 0xba, 0x7f, - 0xdf, 0x08, 0x66, 0x55, 0x78, 0xb6, 0x06, 0x24, 0x75, 0x41, 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, - 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x45, 0xb4, 0x61, 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, - 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, - 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, - 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, - 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, - 0x46, 0x49, 0xf4, 0x97, 0x57, 0xa2, 0x3e, 0xe2, 0x26, 0xfe, 0xcc, 0x05, 0x49, 0x5a, 0xad, 0xe3, 0xf6, 0x71, 0xeb, - 0xbc, 0xc7, 0x0f, 0xdb, 0x9d, 0xe4, 0x41, 0x27, 0x35, 0x8a, 0x88, 0xb9, 0xbc, 0x01, 0x05, 0xcc, 0x51, 0x27, 0x39, - 0x41, 0x87, 0xed, 0xa4, 0x75, 0x7a, 0xda, 0x84, 0x7f, 0xf0, 0x7b, 0x5d, 0x56, 0x3b, 0x69, 0x9d, 0x9c, 0xf6, 0xf8, - 0xd1, 0x46, 0xa5, 0x98, 0x37, 0xa0, 0x20, 0x3a, 0x32, 0x95, 0x30, 0xd4, 0xaf, 0x96, 0xf7, 0xd9, 0x96, 0x9e, 0xe7, - 0xbd, 0x8e, 0x95, 0x55, 0xc5, 0x01, 0x54, 0xfd, 0xd7, 0xc4, 0x00, 0xd1, 0x7f, 0x0d, 0xcb, 0x18, 0xb1, 0xcb, 0x02, - 0x44, 0xed, 0x47, 0x3c, 0x16, 0x0d, 0x76, 0x18, 0xdb, 0x7c, 0x0d, 0x75, 0x9b, 0x10, 0xb7, 0x0d, 0x4f, 0x5c, 0xae, - 0x0a, 0x73, 0x27, 0x08, 0x35, 0x15, 0xe4, 0x0e, 0x5d, 0xae, 0x0c, 0x73, 0x87, 0x08, 0x35, 0x25, 0xe4, 0xd2, 0x94, - 0x27, 0x14, 0x72, 0x74, 0x42, 0x9b, 0x06, 0x92, 0xd5, 0xa2, 0x3c, 0x67, 0x7e, 0xd8, 0x7c, 0x0c, 0xcb, 0x63, 0x08, - 0x8a, 0x13, 0xa4, 0x05, 0xbc, 0xed, 0x51, 0x6a, 0x73, 0x5a, 0xb8, 0x54, 0xe3, 0x40, 0x46, 0x03, 0xfe, 0x39, 0x64, - 0xe6, 0xc1, 0x87, 0x56, 0xef, 0xf8, 0xac, 0x95, 0xb6, 0xc1, 0x49, 0x19, 0x64, 0x6d, 0x61, 0x65, 0x6d, 0xe1, 0x65, - 0x6d, 0xe1, 0x65, 0x6d, 0x10, 0xe0, 0x83, 0xbe, 0xff, 0x91, 0x35, 0xc3, 0x0f, 0x5e, 0x5a, 0x91, 0x58, 0x33, 0x81, - 0x58, 0xaf, 0x56, 0xcb, 0x35, 0xd8, 0xf8, 0x94, 0x35, 0xa4, 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, - 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, 0x3f, 0xa6, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, - 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, - 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0xf0, 0x79, 0xb1, 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x5c, 0x98, - 0x2d, 0xa9, 0x13, 0x6a, 0xbc, 0xa6, 0xcb, 0x31, 0x7f, 0xad, 0xa1, 0x7d, 0x02, 0x6f, 0xb9, 0x3c, 0xd4, 0x71, 0x0b, - 0x8c, 0x26, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, 0x8d, 0x33, 0x86, 0xfe, 0xbc, 0xe1, 0x83, 0x6a, 0x29, - 0x41, 0xf8, 0x82, 0xc1, 0x67, 0x56, 0x39, 0xc5, 0x97, 0xb6, 0x9e, 0xce, 0x50, 0xcb, 0x1e, 0x09, 0x5d, 0x30, 0xd8, - 0xf6, 0xd1, 0x96, 0x7a, 0x82, 0x48, 0x65, 0xdc, 0x05, 0x49, 0x15, 0x2f, 0x18, 0xdc, 0x67, 0xc9, 0x2d, 0x35, 0xce, - 0x24, 0x2f, 0xec, 0x9f, 0xaf, 0x34, 0xf0, 0xb6, 0x2b, 0x26, 0x43, 0xef, 0xa4, 0x7a, 0x6d, 0xa2, 0xea, 0x90, 0xfd, - 0x7d, 0x6b, 0x4b, 0x6d, 0xbe, 0x36, 0x8d, 0xa9, 0x4d, 0xa2, 0xc9, 0x86, 0x1d, 0xea, 0xd7, 0xe8, 0x1f, 0xef, 0x2b, - 0x56, 0x4c, 0x86, 0x28, 0xa0, 0xd9, 0x06, 0xac, 0xaa, 0x02, 0x96, 0x72, 0xf5, 0x4a, 0x17, 0x42, 0xe8, 0xdd, 0x8c, - 0x79, 0x5d, 0x4c, 0x86, 0x3b, 0x1f, 0xfd, 0xb0, 0x3d, 0xf6, 0xde, 0xd2, 0xa0, 0x07, 0xaf, 0xda, 0x9e, 0xb2, 0xdb, - 0xef, 0xd5, 0xb9, 0xd9, 0x59, 0x47, 0xe5, 0xdf, 0xab, 0xf3, 0x74, 0x57, 0x9d, 0x19, 0xbf, 0x8d, 0xfd, 0xde, 0xd1, - 0x81, 0x1a, 0xdb, 0x18, 0xe8, 0x4c, 0x86, 0x10, 0xa5, 0x1d, 0xfe, 0xda, 0x58, 0x2a, 0x5d, 0x4f, 0xc2, 0x61, 0x15, - 0x64, 0x2f, 0x39, 0x4d, 0x19, 0xa6, 0xa4, 0x73, 0x58, 0x98, 0x68, 0x2a, 0x22, 0xa1, 0x4d, 0x95, 0x50, 0x9c, 0x93, - 0x38, 0xa6, 0x87, 0x19, 0xc4, 0x84, 0x69, 0xf7, 0x68, 0x1a, 0xd3, 0x46, 0x86, 0x8e, 0xe2, 0x76, 0x83, 0x1e, 0x66, - 0x08, 0x35, 0xda, 0xa0, 0x33, 0x95, 0xa4, 0xdd, 0xcc, 0x21, 0x4a, 0xa4, 0x21, 0xc5, 0xf9, 0xa1, 0x48, 0x8a, 0x86, - 0x3c, 0x54, 0x49, 0xd1, 0x48, 0x4e, 0xb1, 0x48, 0x26, 0x65, 0xf2, 0xc4, 0x24, 0x4f, 0x6c, 0xf2, 0xb0, 0x4c, 0x1e, - 0x9a, 0xe4, 0xa1, 0x4d, 0xa6, 0xa4, 0x38, 0x14, 0x09, 0x6d, 0xc4, 0xed, 0x66, 0x81, 0x0e, 0x61, 0x04, 0x7e, 0xf4, - 0x44, 0x84, 0xc1, 0xb9, 0xd7, 0xc6, 0xba, 0x65, 0x2e, 0x73, 0x17, 0x2e, 0xb3, 0x02, 0x52, 0xe9, 0x72, 0x04, 0x75, - 0x9e, 0x05, 0x60, 0xc2, 0xda, 0xfe, 0xf1, 0xc1, 0xe0, 0xd6, 0x59, 0x2e, 0x45, 0xe0, 0x52, 0x05, 0x56, 0xe0, 0x9f, - 0x9d, 0x23, 0x09, 0x40, 0x75, 0x4d, 0xf3, 0xf9, 0x94, 0x6e, 0xf9, 0xad, 0x16, 0x93, 0xa1, 0xdb, 0x59, 0x65, 0x33, - 0x8c, 0x16, 0x36, 0xc8, 0x72, 0xdd, 0xc3, 0x10, 0x40, 0xed, 0xbd, 0x1a, 0x13, 0x6a, 0x94, 0xe4, 0xb6, 0xc6, 0xa4, - 0x60, 0x77, 0x2a, 0xa3, 0x39, 0x8b, 0xab, 0x03, 0xb8, 0x1a, 0x26, 0x23, 0x2f, 0xc0, 0x16, 0xbd, 0x38, 0x4c, 0x8e, - 0x1b, 0x3a, 0x99, 0x1c, 0x26, 0xa7, 0x0f, 0x1a, 0x3a, 0x19, 0x1e, 0x26, 0xed, 0x76, 0x85, 0xb3, 0x49, 0x41, 0x74, - 0x32, 0x21, 0x1a, 0x34, 0x86, 0xb6, 0x51, 0x39, 0xa7, 0x60, 0x5c, 0xf5, 0x6f, 0x0c, 0xa3, 0xe1, 0x86, 0x21, 0xd8, - 0xc4, 0xc6, 0x9b, 0xdc, 0x1a, 0x43, 0xd8, 0x4d, 0xe7, 0xf4, 0xb4, 0xa9, 0x93, 0x02, 0x6b, 0xbb, 0x92, 0x4d, 0x9d, - 0x4c, 0xb0, 0xb6, 0xcb, 0xd7, 0xd4, 0xc9, 0xd0, 0x36, 0x65, 0x74, 0x80, 0x4c, 0x04, 0xc0, 0x7a, 0xce, 0x02, 0xc8, - 0x77, 0xbc, 0x7b, 0xc8, 0x1a, 0xb4, 0x86, 0xdf, 0x2b, 0xd7, 0xf4, 0x05, 0x15, 0xd5, 0x60, 0x64, 0xc3, 0xbe, 0x55, - 0xb4, 0x5d, 0x35, 0xc9, 0xfe, 0x75, 0xd9, 0xb2, 0xd9, 0x42, 0xea, 0x7a, 0xc1, 0x87, 0x35, 0x0c, 0x71, 0xa5, 0xdc, - 0xc1, 0xfd, 0x8a, 0x92, 0x18, 0xa2, 0xca, 0x99, 0x53, 0x88, 0x13, 0xaf, 0x47, 0x86, 0x24, 0xde, 0x68, 0xac, 0x51, - 0x1c, 0x9c, 0xb7, 0x4f, 0x43, 0xaa, 0xba, 0x15, 0x6a, 0x8e, 0x90, 0x68, 0x21, 0xac, 0x31, 0xe2, 0x28, 0x0a, 0x58, - 0x10, 0xa7, 0xdd, 0xad, 0x1d, 0x10, 0x07, 0x07, 0x9b, 0xe7, 0x85, 0x0f, 0xfa, 0xbf, 0x15, 0xe8, 0xbf, 0xb2, 0x64, - 0xf3, 0x4f, 0x11, 0x59, 0x1b, 0x57, 0x1e, 0x20, 0x8a, 0x0f, 0xfa, 0x74, 0xdf, 0x50, 0xf8, 0x7e, 0x15, 0xf1, 0xce, - 0xe5, 0x34, 0xcf, 0x4c, 0x86, 0xe9, 0x6b, 0x10, 0x8c, 0xed, 0x4d, 0x38, 0xa1, 0xd2, 0x4a, 0xef, 0x5f, 0x76, 0x1c, - 0x74, 0xe2, 0x9e, 0x4a, 0x09, 0x1b, 0xfd, 0x3b, 0xb4, 0x89, 0xad, 0x60, 0xe3, 0xbc, 0xa1, 0x57, 0xab, 0xda, 0xc3, - 0x38, 0xf6, 0xf9, 0x15, 0x74, 0x70, 0xc0, 0xd5, 0x33, 0x30, 0xe3, 0x65, 0x71, 0x23, 0x3c, 0x7c, 0xff, 0xa9, 0x9d, - 0xd6, 0x7f, 0x9b, 0x73, 0x35, 0x0d, 0x0e, 0xba, 0x87, 0xb5, 0xfc, 0x9d, 0x2b, 0xd1, 0xd3, 0x29, 0x77, 0x6b, 0xfd, - 0x77, 0x65, 0x24, 0xbd, 0xf5, 0x44, 0xd3, 0xc1, 0x01, 0xaf, 0x02, 0x25, 0x45, 0x3f, 0x44, 0xa8, 0x67, 0x64, 0x90, - 0x67, 0xb9, 0xa4, 0x70, 0x23, 0x0a, 0x57, 0x0c, 0x69, 0x83, 0x1f, 0x69, 0xfc, 0x87, 0xfc, 0xff, 0xd4, 0xc8, 0xa1, - 0x4e, 0x1b, 0x3c, 0x10, 0xc0, 0x42, 0x56, 0xa8, 0x0a, 0x51, 0x68, 0x20, 0x1d, 0xda, 0x3c, 0xa3, 0xf2, 0x30, 0xa7, - 0xf3, 0x79, 0x7e, 0x67, 0x5e, 0xa9, 0x0a, 0x38, 0xaa, 0xea, 0xa2, 0xc9, 0xc5, 0x87, 0xc3, 0x05, 0xf0, 0xf4, 0x80, - 0x7b, 0xc8, 0xf8, 0x77, 0x96, 0x97, 0xdb, 0x02, 0x81, 0x64, 0xa6, 0x88, 0x6c, 0xb6, 0xbb, 0xea, 0x12, 0xe4, 0xb2, - 0x66, 0x13, 0x69, 0x17, 0x36, 0x1b, 0x73, 0x90, 0xc9, 0x94, 0xf5, 0xe1, 0xdc, 0xb3, 0x05, 0x41, 0x72, 0x93, 0x46, - 0x64, 0xdb, 0x5d, 0x8a, 0x8f, 0x63, 0x40, 0x23, 0x64, 0x05, 0xbe, 0x50, 0x58, 0xe4, 0xc0, 0x75, 0x16, 0xbe, 0xe3, - 0x6f, 0xb4, 0x54, 0xf4, 0xd5, 0x60, 0x80, 0x0b, 0xf3, 0x30, 0x43, 0x39, 0x9f, 0x42, 0x05, 0x0f, 0xfd, 0x04, 0x22, - 0x0a, 0x5f, 0xad, 0xf6, 0xe1, 0x1d, 0x1d, 0xd7, 0x26, 0x38, 0x7d, 0xba, 0x9f, 0xd5, 0x9b, 0x19, 0x30, 0x0e, 0x46, - 0x5a, 0xe6, 0xa2, 0xd0, 0xc9, 0x9b, 0xec, 0x42, 0x74, 0x1b, 0x0d, 0x66, 0x42, 0x1c, 0x11, 0x88, 0x67, 0x06, 0x1e, - 0x79, 0xf0, 0xc7, 0x46, 0x2d, 0x52, 0xcc, 0xc6, 0x7e, 0x83, 0xa0, 0xd4, 0xb5, 0x84, 0xd5, 0x4a, 0xd9, 0xd8, 0x22, - 0x26, 0xc7, 0x46, 0x19, 0x29, 0xfb, 0x29, 0x83, 0x98, 0x56, 0x66, 0x1c, 0xdc, 0x6d, 0xf5, 0xb7, 0xd5, 0x7e, 0xde, - 0xe3, 0xf6, 0x1a, 0x8f, 0x1b, 0x8f, 0x7d, 0x03, 0xa8, 0xe5, 0xc6, 0x06, 0xb7, 0x16, 0xe6, 0xb1, 0x35, 0x87, 0x65, - 0x9b, 0x10, 0x14, 0xa5, 0x87, 0xba, 0xbd, 0xb9, 0xf5, 0x11, 0xfb, 0x94, 0x99, 0x93, 0x42, 0xba, 0x0f, 0x72, 0xf4, - 0x80, 0x40, 0xe7, 0xf6, 0x67, 0x45, 0x17, 0x2a, 0x99, 0xb8, 0x1c, 0xe3, 0x2f, 0xc1, 0x6d, 0x5e, 0x3f, 0xba, 0xbe, - 0x36, 0x9b, 0xfc, 0xfa, 0x3a, 0xc2, 0xa1, 0x59, 0x77, 0x14, 0xf0, 0x82, 0xd1, 0xa0, 0x0c, 0xea, 0x64, 0x36, 0x7e, - 0xb3, 0x5d, 0x35, 0xf6, 0x9e, 0x56, 0x78, 0x07, 0xcb, 0x63, 0x1a, 0xdf, 0x72, 0x83, 0xec, 0x73, 0x80, 0x37, 0xeb, - 0xf3, 0x41, 0xf7, 0x4d, 0xac, 0xd0, 0xc1, 0xc1, 0x9b, 0x58, 0xa2, 0xde, 0x15, 0x33, 0x77, 0x6e, 0xe0, 0x07, 0xdd, - 0xe7, 0x66, 0xf8, 0x32, 0x40, 0x80, 0x2b, 0xb6, 0x29, 0xd9, 0xbc, 0x35, 0x51, 0x27, 0x52, 0x88, 0x6a, 0x0d, 0xb1, - 0x75, 0x1d, 0x48, 0xa0, 0xd7, 0x37, 0x21, 0xb4, 0xbb, 0x8c, 0x30, 0x60, 0xe1, 0x4b, 0x2f, 0x35, 0x96, 0xcc, 0x58, - 0x31, 0x61, 0xc5, 0x6a, 0xf5, 0x9e, 0x5a, 0xcf, 0xb3, 0x8d, 0x20, 0x89, 0xaa, 0xdb, 0x68, 0x50, 0x33, 0x7e, 0x10, - 0x1f, 0xe8, 0x00, 0xef, 0xbf, 0x89, 0x0b, 0x84, 0xc0, 0xc2, 0x88, 0x8b, 0x85, 0xf7, 0xb2, 0xca, 0x6a, 0xeb, 0x52, - 0xa0, 0xb2, 0x91, 0x9c, 0xb4, 0xf0, 0x94, 0x64, 0xe5, 0x1a, 0x5d, 0x4c, 0xbb, 0x8d, 0x46, 0x8e, 0x64, 0x9c, 0xf5, - 0xf3, 0x01, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0x72, 0xf3, 0x5d, 0xda, 0xb1, 0xa6, - 0x8f, 0xe8, 0x3a, 0x00, 0xc6, 0x23, 0x1a, 0x10, 0x89, 0x5d, 0x40, 0x16, 0x16, 0xc8, 0xca, 0x03, 0x59, 0x18, 0x20, - 0x2b, 0xd4, 0x9b, 0x43, 0xb8, 0x20, 0x85, 0xd2, 0x2d, 0x8a, 0x5e, 0x0f, 0x6c, 0xe9, 0x9c, 0x26, 0x30, 0x37, 0xb1, - 0x15, 0xdc, 0x72, 0x80, 0x03, 0x85, 0xf3, 0xc3, 0x53, 0x64, 0x19, 0x45, 0x26, 0xc6, 0x2b, 0xbe, 0x35, 0x7f, 0x92, - 0x5b, 0x7c, 0x67, 0x7f, 0xdc, 0x05, 0xca, 0xa4, 0xe7, 0x35, 0x6d, 0x03, 0x77, 0x11, 0xd1, 0xa2, 0x24, 0x02, 0xb4, - 0x76, 0xe1, 0xfd, 0x44, 0xfd, 0xc5, 0x33, 0x65, 0x03, 0x31, 0x88, 0x06, 0x51, 0x58, 0x04, 0xa4, 0xf3, 0xcf, 0x3f, - 0x23, 0xd4, 0x13, 0x10, 0x47, 0xc7, 0x9d, 0x6c, 0xcd, 0x36, 0x6a, 0x44, 0x49, 0x94, 0xc6, 0x3e, 0x4c, 0x03, 0xec, - 0x8c, 0x28, 0x0a, 0x5e, 0x3b, 0x29, 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x33, 0xa8, 0x2a, 0xf0, 0xc4, 0xe5, 0x72, 0x33, - 0xcc, 0x8f, 0x81, 0xaa, 0x30, 0x31, 0x56, 0x90, 0x7d, 0x02, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0xfa, 0x62, 0x10, 0xbc, - 0xe9, 0x55, 0x5d, 0x87, 0xeb, 0x70, 0xe1, 0x62, 0x0a, 0x71, 0xd6, 0x57, 0x2b, 0xfb, 0x97, 0x7c, 0x30, 0xd2, 0x0c, - 0x3c, 0xce, 0x16, 0x9c, 0xb1, 0x62, 0xb7, 0x2c, 0x96, 0x68, 0xf9, 0x3b, 0x98, 0xed, 0xb9, 0xa8, 0x79, 0xdc, 0x4d, - 0xb5, 0xed, 0xa1, 0x3e, 0x37, 0x1a, 0x85, 0x20, 0x66, 0x6d, 0x75, 0xa4, 0xe1, 0xb9, 0x0e, 0xf3, 0x6a, 0xb1, 0x67, - 0x33, 0x55, 0x86, 0x10, 0x85, 0x23, 0x25, 0x01, 0xbb, 0x6d, 0x43, 0x27, 0xe1, 0x47, 0x9d, 0x4a, 0x3a, 0x16, 0x12, - 0xa0, 0xc0, 0x91, 0xb9, 0x9c, 0x37, 0x21, 0xe2, 0x19, 0xda, 0x41, 0xe4, 0x02, 0x13, 0x9a, 0xba, 0x6c, 0xe9, 0x62, - 0x39, 0x45, 0x33, 0xb9, 0x50, 0x6c, 0x31, 0x87, 0xf3, 0xbd, 0x4c, 0xcb, 0x72, 0x9e, 0x7d, 0xae, 0xa7, 0x80, 0xfd, - 0xe5, 0xad, 0x9e, 0x31, 0xb1, 0x88, 0xdc, 0x3c, 0xbf, 0x5a, 0x71, 0xff, 0xcd, 0x0b, 0xfc, 0x88, 0x74, 0x0e, 0xbf, - 0xe2, 0x8f, 0x94, 0x3c, 0x6a, 0x7c, 0xc5, 0x13, 0x4e, 0x2c, 0x6f, 0x90, 0xbc, 0x79, 0x7d, 0xf5, 0xe2, 0xdd, 0x8b, - 0xf7, 0x4f, 0xaf, 0x5f, 0xbc, 0x7a, 0xf6, 0xe2, 0xd5, 0x8b, 0x77, 0x1f, 0xf1, 0x3f, 0x94, 0x7c, 0x3d, 0x6a, 0x9f, - 0xb7, 0xf0, 0x07, 0xf2, 0xf5, 0xa8, 0x83, 0x6f, 0x35, 0xf9, 0x7a, 0x74, 0x82, 0x73, 0x45, 0xbe, 0x1e, 0x76, 0x8e, - 0x8e, 0xf1, 0x42, 0xdb, 0x26, 0x73, 0x39, 0x69, 0xb7, 0xf0, 0x3f, 0xee, 0x0b, 0xc4, 0xfb, 0x6a, 0x16, 0x13, 0xb6, - 0x61, 0xfc, 0x60, 0xca, 0xd0, 0xa1, 0x32, 0x86, 0x28, 0x17, 0x01, 0x3a, 0x4d, 0x55, 0x88, 0x4e, 0x36, 0x88, 0x31, - 0xd8, 0x30, 0x02, 0x5a, 0x71, 0xe2, 0xda, 0xe1, 0x47, 0x6d, 0x76, 0x0c, 0xf4, 0x89, 0x97, 0xc2, 0x71, 0xa9, 0xc2, - 0x69, 0x3b, 0x2d, 0xc6, 0x38, 0x97, 0xb2, 0x88, 0x17, 0xc0, 0x08, 0x18, 0xad, 0x05, 0x3f, 0x2a, 0xa3, 0x25, 0x89, - 0x0b, 0xd2, 0xee, 0xb5, 0x53, 0x71, 0x41, 0x3a, 0xbd, 0x0e, 0xfc, 0x39, 0xed, 0x9d, 0xa6, 0xed, 0x16, 0x3a, 0x0c, - 0xc6, 0xf1, 0x47, 0x0d, 0xad, 0xfb, 0x03, 0xec, 0xba, 0x50, 0xff, 0x14, 0xda, 0xab, 0xf4, 0x84, 0x53, 0xc7, 0xb6, - 0xbb, 0xe2, 0x82, 0x19, 0x3d, 0x2c, 0xff, 0x01, 0x50, 0xdb, 0x38, 0x74, 0x94, 0x1b, 0xc7, 0xfd, 0xe2, 0x47, 0x02, - 0xd5, 0x42, 0xb2, 0xc4, 0x6c, 0xd5, 0x42, 0xc0, 0x34, 0x9a, 0x6c, 0x30, 0x07, 0x4a, 0x94, 0x2c, 0xb4, 0x0f, 0x2b, - 0xaf, 0x9a, 0x12, 0x25, 0x73, 0x39, 0x8f, 0x6b, 0xaa, 0x86, 0x5f, 0x03, 0x33, 0xc7, 0x7d, 0xae, 0x5e, 0xd1, 0x57, - 0x71, 0x8d, 0xe7, 0x09, 0x59, 0xbb, 0x70, 0x5b, 0xfc, 0xe2, 0xac, 0x28, 0x6a, 0xe0, 0x2a, 0x01, 0xeb, 0x47, 0xd5, - 0xd4, 0x17, 0xf0, 0x7e, 0x1e, 0x6b, 0xe8, 0x4b, 0x12, 0x50, 0xcf, 0x9f, 0x4a, 0x33, 0xae, 0x52, 0x19, 0xed, 0x15, - 0xd1, 0xc6, 0x2c, 0xc8, 0x2b, 0xa2, 0x2f, 0x94, 0x01, 0x82, 0x24, 0xbc, 0x2f, 0x06, 0x70, 0xe0, 0xdb, 0x01, 0x4a, - 0x43, 0xe7, 0x40, 0xad, 0x54, 0x99, 0x09, 0x99, 0x4f, 0x13, 0x1c, 0x00, 0x34, 0x4f, 0x95, 0x0a, 0xca, 0x7c, 0x62, - 0x89, 0x82, 0xa1, 0xff, 0x16, 0x6e, 0x80, 0xc3, 0xd8, 0xa0, 0x62, 0x90, 0x7d, 0x4f, 0xd4, 0xf3, 0xdb, 0xe7, 0xad, - 0xa3, 0xaf, 0x41, 0xfe, 0x48, 0x79, 0x7b, 0x8f, 0xbf, 0x03, 0x4a, 0x6e, 0xc3, 0x59, 0xb5, 0xb1, 0x8f, 0x44, 0xd6, - 0x0d, 0x01, 0x72, 0xa8, 0xd1, 0x91, 0x79, 0x4a, 0xb0, 0x8b, 0xf4, 0x21, 0x69, 0xb7, 0x20, 0x7c, 0xd8, 0x0e, 0xca, - 0xf7, 0xd3, 0x06, 0x4c, 0x75, 0x72, 0xdb, 0x04, 0x5a, 0x0d, 0xaf, 0x0b, 0xdd, 0x35, 0x79, 0x72, 0x87, 0x55, 0x80, - 0x33, 0xec, 0x90, 0x35, 0xc4, 0xa1, 0x40, 0x2e, 0xec, 0xaa, 0xdd, 0x00, 0x9a, 0x8a, 0x8e, 0x7d, 0xe5, 0xce, 0x1b, - 0x47, 0x5d, 0x34, 0x93, 0xd3, 0xc3, 0xaf, 0x07, 0x07, 0xb1, 0x6c, 0x90, 0x47, 0x08, 0x2f, 0x29, 0x58, 0x31, 0x83, - 0xd7, 0x17, 0xb7, 0x4c, 0x7c, 0xaa, 0x02, 0xea, 0xb8, 0x50, 0xb5, 0x63, 0xad, 0xea, 0xac, 0xdc, 0x0d, 0x7e, 0x4c, - 0x1d, 0xd4, 0x08, 0xd2, 0xec, 0xe8, 0x3a, 0x35, 0x28, 0xd7, 0x5c, 0xb4, 0x60, 0x5b, 0x36, 0x3e, 0x52, 0xf4, 0xc3, - 0xa3, 0xe6, 0xd7, 0x60, 0xc2, 0x35, 0xd3, 0xa4, 0x47, 0x8d, 0x47, 0xe8, 0x87, 0x47, 0x81, 0x93, 0x1d, 0xaf, 0xd8, - 0x13, 0xcf, 0x8d, 0xfc, 0x64, 0xb9, 0xd2, 0x9f, 0x40, 0xb2, 0x2f, 0xc8, 0x4f, 0x80, 0xe5, 0x94, 0xfc, 0x14, 0xcb, - 0x26, 0x04, 0x1f, 0x24, 0x3f, 0xc5, 0x05, 0xfc, 0xc8, 0xc9, 0x4f, 0x31, 0x60, 0x3b, 0x9e, 0x9a, 0x1f, 0x45, 0x09, - 0x0c, 0x70, 0xec, 0x92, 0xd6, 0xbf, 0xab, 0x58, 0xad, 0xc4, 0xc1, 0x81, 0xb4, 0xbf, 0xe8, 0x65, 0x76, 0x70, 0x90, - 0x5f, 0x4c, 0xab, 0xbe, 0x99, 0xde, 0x45, 0x5f, 0x0c, 0x42, 0xe1, 0xc0, 0x34, 0x8d, 0x87, 0x33, 0xfe, 0x14, 0x52, - 0x56, 0xd3, 0x40, 0xf3, 0xb8, 0x73, 0xff, 0xec, 0x1c, 0xc3, 0xbf, 0xf7, 0x83, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, - 0xb3, 0xe6, 0x59, 0x85, 0x6c, 0x97, 0x01, 0x3e, 0x63, 0x86, 0x9a, 0xe2, 0xe0, 0x80, 0x5f, 0x04, 0xb8, 0x8c, 0x19, - 0x6a, 0x04, 0x16, 0x7b, 0x0f, 0x4b, 0x7b, 0x32, 0xc3, 0x35, 0xc1, 0xb3, 0xb2, 0xbc, 0x5f, 0x0c, 0x2e, 0xb4, 0xa3, - 0x26, 0x61, 0xf0, 0x69, 0x45, 0x5a, 0x6e, 0x93, 0x75, 0x45, 0x53, 0x5d, 0xb6, 0xbb, 0x48, 0x12, 0xd5, 0x10, 0x97, - 0x97, 0x6d, 0x0c, 0x2a, 0xf9, 0x9e, 0x22, 0x32, 0x15, 0xc4, 0x3b, 0xc8, 0x2d, 0x73, 0x99, 0x2a, 0x3c, 0xe5, 0xa9, - 0xf0, 0x72, 0xf6, 0x6b, 0x6f, 0x3d, 0x6d, 0x5c, 0x16, 0x4d, 0xcf, 0x0c, 0x8b, 0x9e, 0x2a, 0x5d, 0xed, 0x60, 0x93, - 0xaa, 0x01, 0xbc, 0xda, 0x57, 0x62, 0x1e, 0xb3, 0xfe, 0x65, 0x0c, 0xa2, 0x22, 0xab, 0x46, 0x1b, 0x32, 0xe1, 0x73, - 0x9d, 0x2a, 0x18, 0xa8, 0x29, 0x7c, 0x01, 0x64, 0x2a, 0xab, 0x0c, 0xb3, 0x7d, 0xc3, 0x50, 0x40, 0x40, 0x81, 0x4b, - 0xc2, 0x02, 0x09, 0x1e, 0x6e, 0x3f, 0x02, 0xc2, 0x51, 0x27, 0x17, 0x76, 0x72, 0x17, 0x0a, 0xba, 0x13, 0x83, 0x0b, - 0xdd, 0x45, 0xa2, 0xd1, 0x70, 0xdc, 0xf6, 0xa5, 0x30, 0x83, 0x68, 0xb6, 0x07, 0x97, 0xac, 0x8b, 0x54, 0xb3, 0x59, - 0x1a, 0x40, 0x5e, 0xb6, 0x56, 0x2b, 0x75, 0xe1, 0x1b, 0xe9, 0xf9, 0x73, 0xdc, 0xf0, 0x5d, 0x5e, 0xf0, 0xfc, 0x4d, - 0x92, 0x7e, 0x04, 0x54, 0x15, 0xf8, 0x6c, 0x39, 0x8f, 0x70, 0x64, 0x1e, 0x74, 0x83, 0xbf, 0xe6, 0x21, 0xae, 0x08, - 0x47, 0xee, 0x8d, 0xb7, 0x68, 0x50, 0x0d, 0x96, 0x67, 0x65, 0x78, 0x72, 0x9e, 0x5c, 0x03, 0xe3, 0xa0, 0xff, 0x56, - 0x68, 0x59, 0xfd, 0x4e, 0x72, 0x17, 0xa8, 0x43, 0xf9, 0x67, 0xc7, 0xdc, 0xa8, 0xd6, 0xbb, 0x5d, 0x23, 0x39, 0x8e, - 0x7c, 0x55, 0x08, 0xdf, 0xff, 0x9d, 0x77, 0x0f, 0xdb, 0xee, 0xb9, 0xed, 0x65, 0xd9, 0x03, 0x70, 0xde, 0xeb, 0x35, - 0xc2, 0xbf, 0xc9, 0x9d, 0x6f, 0xef, 0x46, 0xd7, 0x52, 0x3c, 0xa1, 0x9a, 0x46, 0x8d, 0x37, 0xc6, 0xf0, 0xcd, 0xca, - 0x59, 0xdd, 0x6f, 0x8d, 0x83, 0xfd, 0x5b, 0xdd, 0x43, 0xe8, 0x84, 0xda, 0x33, 0x41, 0x56, 0xf6, 0x35, 0x01, 0x33, - 0x64, 0x60, 0xfa, 0xb6, 0x03, 0x1e, 0x7e, 0x8c, 0x14, 0x1c, 0x7a, 0x2d, 0x9f, 0x44, 0x21, 0x26, 0x69, 0xcd, 0x8d, - 0x18, 0x52, 0x6c, 0x1f, 0xc6, 0xe5, 0x74, 0x8d, 0x42, 0xae, 0x7b, 0xac, 0xea, 0xc4, 0xb4, 0xea, 0xc6, 0x48, 0x1d, - 0x6c, 0x93, 0x05, 0x67, 0x55, 0xef, 0x46, 0x42, 0xa9, 0x5e, 0x54, 0x33, 0xaf, 0x62, 0x36, 0xdb, 0xe6, 0x99, 0x61, - 0xfb, 0xee, 0x9a, 0x02, 0x43, 0xde, 0xfd, 0x32, 0x5c, 0xd4, 0x25, 0x1c, 0xbb, 0x71, 0x00, 0x59, 0x49, 0x2e, 0x97, - 0xee, 0x4d, 0x34, 0xde, 0x97, 0x83, 0x75, 0xf9, 0x42, 0x5a, 0x80, 0x07, 0xd5, 0x48, 0x45, 0x16, 0x72, 0x06, 0xfe, - 0x79, 0xc1, 0x9a, 0x7e, 0x88, 0x7f, 0x85, 0x03, 0xbe, 0x42, 0xd2, 0xd4, 0xaa, 0x9f, 0xe0, 0xe5, 0x22, 0x50, 0x78, - 0xdb, 0xba, 0x9f, 0x64, 0xe8, 0x22, 0x5a, 0xd7, 0xa9, 0x58, 0x2f, 0xcc, 0xba, 0x62, 0xa5, 0x2c, 0x1c, 0x1c, 0x77, - 0x31, 0x5a, 0xa7, 0xce, 0x63, 0xd3, 0x3d, 0x77, 0xf4, 0x50, 0xf0, 0x99, 0x71, 0xa4, 0x7b, 0x56, 0x40, 0xfc, 0xaa, - 0x50, 0x9f, 0xf6, 0xb3, 0x0c, 0xdf, 0xf3, 0xed, 0xc3, 0x3d, 0x61, 0xc9, 0x73, 0x96, 0x6f, 0x50, 0xc3, 0x02, 0x29, - 0xa0, 0x50, 0x0a, 0x8b, 0xd5, 0x2a, 0x16, 0x26, 0xaa, 0x81, 0x0b, 0x6a, 0xeb, 0x5e, 0xaf, 0x30, 0xfa, 0x3b, 0xa8, - 0x8b, 0xbd, 0x7a, 0xc4, 0x98, 0xb0, 0xa2, 0xf0, 0xd2, 0x49, 0x65, 0x41, 0x5f, 0xbb, 0xfa, 0x10, 0xd5, 0x94, 0x7b, - 0xb1, 0xd1, 0xf7, 0xbe, 0xe3, 0x33, 0x26, 0x17, 0xf0, 0x6c, 0x10, 0x66, 0x44, 0x31, 0xed, 0xbf, 0x81, 0x82, 0xc0, - 0xdb, 0x33, 0x3c, 0xc4, 0x47, 0xe0, 0xab, 0x3c, 0xad, 0x93, 0x99, 0x7f, 0x8c, 0x22, 0x32, 0xc1, 0x22, 0xa3, 0x5e, - 0x04, 0x5e, 0x43, 0x20, 0x42, 0x11, 0x12, 0x31, 0x31, 0x8a, 0x7a, 0x91, 0x71, 0x52, 0x8a, 0xc0, 0x6a, 0x0c, 0x94, - 0xdc, 0x11, 0x9e, 0xab, 0x8a, 0x88, 0x85, 0x35, 0x75, 0x50, 0x89, 0xa5, 0xc6, 0x4c, 0xfb, 0xa8, 0x53, 0x81, 0xb0, - 0xc8, 0x36, 0x05, 0x65, 0xbd, 0xa1, 0x2e, 0xc0, 0x92, 0x18, 0xd3, 0x5b, 0x9e, 0x5c, 0x03, 0x37, 0xc7, 0x46, 0xae, - 0xe8, 0x92, 0x5f, 0x81, 0x7a, 0x3a, 0x2d, 0xf0, 0xb5, 0x61, 0xd8, 0x46, 0x29, 0x5d, 0x13, 0x8e, 0x33, 0x52, 0x24, - 0xf4, 0x16, 0xa2, 0x3a, 0xcc, 0xb8, 0x48, 0x73, 0x3c, 0xa3, 0xb7, 0xe9, 0x14, 0xcf, 0xb8, 0x78, 0x62, 0x97, 0x3d, - 0x1d, 0x41, 0x92, 0xff, 0x58, 0xac, 0x89, 0x79, 0x94, 0xea, 0x77, 0xc5, 0x8a, 0x47, 0xc0, 0xab, 0xa8, 0x18, 0x75, - 0x47, 0xc6, 0xa6, 0x9c, 0xe9, 0xca, 0x78, 0xfd, 0xb5, 0x8e, 0x29, 0xce, 0x70, 0x8e, 0x92, 0x5c, 0x62, 0xd6, 0x13, - 0xe9, 0x6b, 0x88, 0xe8, 0x9c, 0x61, 0xfb, 0xa0, 0x15, 0xbf, 0x65, 0xf9, 0x33, 0x59, 0xbc, 0x37, 0x5b, 0x3e, 0x47, - 0x50, 0x08, 0x5c, 0x54, 0x44, 0x13, 0x6e, 0xf7, 0x16, 0x3d, 0x59, 0x35, 0x45, 0x6f, 0x6d, 0x53, 0x6e, 0x88, 0x53, - 0x08, 0x85, 0x9b, 0x4c, 0x79, 0xa3, 0x8d, 0x59, 0xaf, 0xf5, 0x9d, 0x46, 0xa7, 0xa8, 0x2c, 0x89, 0x30, 0xac, 0x55, - 0x53, 0xa5, 0x92, 0x88, 0xa6, 0x72, 0x12, 0xde, 0xd2, 0x00, 0x3b, 0x55, 0x38, 0x93, 0x0b, 0xa1, 0x53, 0x19, 0xe0, - 0x0d, 0xad, 0x36, 0xd7, 0xf2, 0xd6, 0x42, 0x4c, 0xe3, 0x3b, 0xfb, 0x83, 0xe1, 0x6b, 0xa3, 0xe2, 0x7f, 0x0b, 0x86, - 0x3d, 0x2a, 0x15, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x59, 0x7e, 0xf2, 0x16, 0xc0, 0x67, 0x59, 0xc8, 0x3b, 0x48, - 0x65, 0x26, 0xf5, 0x0e, 0x52, 0x19, 0xa4, 0x1a, 0x5f, 0xee, 0x7d, 0x51, 0x29, 0x8b, 0xc2, 0x06, 0x89, 0xc2, 0xa5, - 0x3a, 0x58, 0x12, 0x91, 0x40, 0xbb, 0x46, 0x94, 0x9b, 0x71, 0x01, 0x41, 0xfd, 0xa0, 0x71, 0xfb, 0x4d, 0x6f, 0xe1, - 0xfb, 0xce, 0xe6, 0x33, 0x9f, 0x7f, 0x67, 0xf3, 0x4d, 0x47, 0x1e, 0xe3, 0xeb, 0xb7, 0x9d, 0xc6, 0x32, 0x5e, 0x3a, - 0xac, 0xfd, 0x50, 0x3e, 0xa1, 0xd2, 0x32, 0x4f, 0x55, 0x93, 0x36, 0x9e, 0x04, 0x48, 0xd9, 0xac, 0x78, 0xb8, 0x0e, - 0x6e, 0xb7, 0x0e, 0x63, 0xde, 0x24, 0x6d, 0x84, 0x0e, 0x9d, 0x70, 0x25, 0x62, 0x23, 0x39, 0x1d, 0x3e, 0x3a, 0x82, - 0xbb, 0x97, 0x99, 0xda, 0xf0, 0x95, 0xb2, 0xd5, 0x9a, 0xed, 0xd6, 0x21, 0xdf, 0x59, 0xa5, 0xd1, 0xc6, 0x33, 0x46, - 0x96, 0xe0, 0x5c, 0x46, 0x0b, 0xab, 0x6a, 0x00, 0x27, 0xce, 0x17, 0xe2, 0xb7, 0x05, 0x1d, 0x99, 0xef, 0x43, 0x9b, - 0xf2, 0x7a, 0xa1, 0x7d, 0x52, 0x93, 0xc3, 0x20, 0x3a, 0xc8, 0x95, 0x0c, 0x72, 0x62, 0x7e, 0x44, 0x92, 0x53, 0x74, - 0xd1, 0xee, 0x25, 0xa7, 0x87, 0xfc, 0x90, 0xa7, 0xc0, 0xc3, 0xc6, 0x4d, 0x5f, 0xa1, 0xd9, 0xf6, 0x75, 0x1e, 0x2f, - 0x86, 0x3c, 0x73, 0xcd, 0x57, 0x1d, 0x94, 0xa9, 0x76, 0x8e, 0x90, 0x05, 0x28, 0xe6, 0x7b, 0x09, 0xb2, 0xeb, 0xdd, - 0x1c, 0xf2, 0x14, 0xfa, 0x81, 0x5a, 0x1d, 0x5b, 0xab, 0x1c, 0xdc, 0x6f, 0x0b, 0x40, 0x30, 0xdf, 0x51, 0x6d, 0x2e, - 0x36, 0xbd, 0x19, 0x57, 0x9d, 0x1d, 0xf2, 0x6a, 0x84, 0x61, 0x99, 0xed, 0xfe, 0xfc, 0xd4, 0xaa, 0x2e, 0x0f, 0x03, - 0x88, 0xfc, 0xb6, 0xe0, 0x22, 0xec, 0x34, 0xec, 0xd6, 0xe5, 0x84, 0x9d, 0xd6, 0x67, 0x19, 0x14, 0xd9, 0xee, 0x75, - 0x6b, 0xa6, 0xf5, 0xd9, 0x5e, 0x81, 0x8f, 0x20, 0x4c, 0xca, 0xac, 0x74, 0x06, 0x57, 0xe8, 0x87, 0x1f, 0x90, 0x6b, - 0xfd, 0xf5, 0x42, 0xfb, 0xfc, 0x12, 0x11, 0x20, 0xbb, 0xea, 0xba, 0xac, 0x0e, 0x7d, 0x94, 0x4d, 0x7c, 0x3d, 0xe4, - 0xc1, 0xca, 0x3d, 0xbd, 0x9d, 0xcb, 0xd4, 0xe3, 0x6b, 0xaf, 0x95, 0x6e, 0x21, 0x27, 0x10, 0x0f, 0xd7, 0x5d, 0x58, - 0x16, 0xe4, 0xec, 0xe6, 0x16, 0x4a, 0x86, 0x13, 0xf7, 0xa5, 0x3f, 0x30, 0x7b, 0xdd, 0xc0, 0x2f, 0x92, 0x53, 0x98, - 0xfa, 0x66, 0x0f, 0x87, 0x1d, 0xe8, 0xc3, 0xc0, 0x61, 0xb3, 0x41, 0x9f, 0x59, 0x41, 0xe4, 0x31, 0x2f, 0x2c, 0x9e, - 0x5d, 0x92, 0x76, 0x8f, 0xa7, 0x6e, 0x33, 0x19, 0xd1, 0xa8, 0xdd, 0xe4, 0xc1, 0xcc, 0x00, 0xbf, 0x5c, 0xd9, 0xb0, - 0x88, 0x5f, 0xa7, 0x00, 0x4a, 0xbe, 0x58, 0xb5, 0x3e, 0x15, 0xbc, 0xea, 0x0d, 0xa7, 0x9b, 0xe9, 0x7e, 0xdd, 0xe0, - 0x76, 0xd7, 0xc3, 0x13, 0x9e, 0x40, 0xb1, 0x68, 0xed, 0x27, 0x3e, 0x01, 0x0e, 0x28, 0x69, 0xdd, 0x3f, 0x05, 0x17, - 0xca, 0x12, 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x2c, 0x1c, 0x6d, 0xc9, 0x80, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, - 0xd8, 0xc1, 0x49, 0xbb, 0xdd, 0x39, 0xc5, 0xc9, 0xc9, 0x29, 0x0c, 0xb4, 0x91, 0x9c, 0x1e, 0xce, 0x94, 0x05, 0x60, - 0x90, 0xb3, 0x76, 0xed, 0x3e, 0x82, 0x70, 0x49, 0xa1, 0x78, 0xcd, 0x0f, 0xe3, 0xb8, 0x9d, 0xdc, 0x6f, 0xb5, 0x4f, - 0xcf, 0x1b, 0x00, 0xa0, 0xa6, 0xfb, 0x70, 0x35, 0x5e, 0x2f, 0x74, 0xbd, 0x4a, 0x89, 0xf0, 0xf5, 0x6a, 0x0d, 0x5f, - 0xad, 0xd1, 0x5e, 0x57, 0x53, 0xf0, 0x55, 0x9d, 0x70, 0x6e, 0x8b, 0x78, 0xa5, 0x4d, 0xb8, 0x2d, 0x62, 0x3b, 0x90, - 0x18, 0xa4, 0xf3, 0xe4, 0xb4, 0x73, 0x8a, 0xec, 0x58, 0xb4, 0xc3, 0x8f, 0x72, 0x9f, 0x6c, 0x15, 0x69, 0x68, 0x40, - 0x92, 0x72, 0x76, 0x72, 0x01, 0x12, 0x35, 0x27, 0x97, 0xed, 0xe6, 0x8c, 0x25, 0x7e, 0x02, 0x26, 0x15, 0x96, 0xb3, - 0x5c, 0x05, 0x97, 0x14, 0x00, 0xe2, 0x02, 0x8c, 0x8b, 0xee, 0x9f, 0xf6, 0xee, 0x27, 0xa7, 0x67, 0x1d, 0x4b, 0xf4, - 0xf8, 0x45, 0xa7, 0x96, 0x66, 0xa6, 0x9e, 0x9c, 0x9a, 0x34, 0xe8, 0x3a, 0xb9, 0x7f, 0x0a, 0x65, 0x5c, 0x4a, 0x58, - 0x0a, 0xc2, 0x3c, 0x54, 0xc5, 0x20, 0xb6, 0x43, 0x5a, 0xcb, 0x3d, 0xab, 0x65, 0x9f, 0x9f, 0x1c, 0xdf, 0x3f, 0x0d, - 0xa1, 0x56, 0xce, 0xc2, 0x2c, 0xb4, 0x9b, 0x88, 0x9f, 0x1d, 0x2c, 0x2d, 0x3a, 0x4c, 0x4e, 0xd3, 0xad, 0x09, 0xda, - 0x4d, 0x73, 0x68, 0x70, 0x20, 0x50, 0x38, 0x3e, 0x15, 0x4e, 0x5f, 0x12, 0xdc, 0x8f, 0x55, 0x86, 0x26, 0xa1, 0xc2, - 0xd9, 0xdf, 0x53, 0x06, 0x2f, 0x39, 0x86, 0x57, 0x95, 0x8f, 0xa9, 0xf8, 0x42, 0xd5, 0x1b, 0x0a, 0xb1, 0x2b, 0xc4, - 0x20, 0x72, 0x91, 0xb5, 0xeb, 0xb9, 0x3f, 0x81, 0x8b, 0x30, 0x13, 0x70, 0xa1, 0xe9, 0x95, 0xa0, 0x15, 0x2f, 0x30, - 0x0c, 0x1d, 0x6a, 0xcd, 0xb0, 0x7a, 0x3c, 0x75, 0x26, 0x05, 0xa1, 0x6e, 0xeb, 0x39, 0xff, 0x5e, 0xb9, 0xa4, 0xbc, - 0xca, 0x4e, 0x4e, 0x51, 0xe2, 0x2e, 0xcb, 0x93, 0x36, 0x4a, 0x02, 0x13, 0x12, 0x77, 0x24, 0x67, 0x19, 0xe9, 0x47, - 0xb7, 0x11, 0x8e, 0xee, 0x22, 0x1c, 0x59, 0x1f, 0xe6, 0x0f, 0xe0, 0x3c, 0x1f, 0xe1, 0xc8, 0xba, 0x32, 0x47, 0x38, - 0xd2, 0x4c, 0x40, 0x48, 0xab, 0x68, 0x80, 0x73, 0x28, 0x6d, 0x3c, 0xab, 0xcb, 0xd2, 0x8f, 0xfd, 0x57, 0xe9, 0x7a, - 0x6d, 0x53, 0x02, 0x29, 0x73, 0x6a, 0x76, 0xa8, 0x7d, 0x92, 0x39, 0xa2, 0x9e, 0x59, 0x8f, 0x30, 0x08, 0x20, 0xf4, - 0xce, 0x3f, 0xe9, 0x56, 0x45, 0xc3, 0x60, 0xc7, 0xb0, 0xd2, 0xe0, 0x67, 0x1e, 0x85, 0x67, 0x58, 0x84, 0xc7, 0xc2, - 0x17, 0x06, 0xb1, 0xc2, 0xff, 0xce, 0xa5, 0x9c, 0xfb, 0xdf, 0x5a, 0x96, 0xbf, 0xe0, 0x21, 0x10, 0x67, 0xd1, 0x02, - 0x96, 0x5b, 0x36, 0xf8, 0xce, 0x90, 0xd5, 0x47, 0x70, 0x3d, 0x76, 0x01, 0xd2, 0x40, 0x22, 0xbc, 0x36, 0x02, 0x95, - 0x97, 0x0f, 0xaf, 0x6d, 0xb0, 0x1e, 0xf3, 0x09, 0xd1, 0xba, 0x20, 0x20, 0xaf, 0x84, 0x0b, 0x8d, 0x49, 0xc1, 0x94, - 0x8a, 0x6c, 0x14, 0xbb, 0x48, 0x0a, 0xff, 0x2c, 0xa1, 0x4f, 0x19, 0x8b, 0xc8, 0x74, 0x58, 0x9f, 0xad, 0x15, 0x87, - 0x73, 0x59, 0xa8, 0xd4, 0xbe, 0x51, 0xe2, 0xc1, 0x58, 0x3d, 0x55, 0x9f, 0xe6, 0xd9, 0x1a, 0xdb, 0x3b, 0xec, 0xb2, - 0x90, 0xbb, 0xd2, 0x0e, 0x4b, 0x65, 0xd9, 0xfa, 0x5b, 0x13, 0x52, 0xb5, 0x19, 0x05, 0x13, 0xad, 0x06, 0x54, 0x85, - 0xb2, 0x80, 0xc2, 0x36, 0x1c, 0x4a, 0xba, 0x2c, 0x4b, 0xa6, 0xcb, 0x72, 0x19, 0x4e, 0x5a, 0xad, 0xf5, 0x1a, 0x17, - 0xcc, 0x84, 0x65, 0xd9, 0x59, 0x02, 0xf2, 0xd5, 0x54, 0xde, 0x04, 0xb9, 0x2a, 0x2d, 0x67, 0x69, 0x96, 0x28, 0x0a, - 0x8c, 0x60, 0xa3, 0x35, 0xfe, 0xc2, 0x15, 0x07, 0x78, 0xba, 0xd9, 0x0d, 0xa5, 0xcc, 0x19, 0x85, 0xe8, 0x5d, 0x41, - 0x93, 0x6b, 0x3c, 0xe5, 0x23, 0xb6, 0xbb, 0x4d, 0x30, 0x63, 0xfe, 0xf7, 0x5a, 0xf4, 0x08, 0x64, 0xd9, 0x3d, 0x83, - 0x3a, 0xb0, 0x88, 0x2b, 0xe8, 0x20, 0x94, 0xc1, 0x47, 0x21, 0x6e, 0xe6, 0xf4, 0x4e, 0x2e, 0x34, 0xc0, 0x65, 0xa1, - 0xe5, 0x1b, 0x17, 0xeb, 0x60, 0xbf, 0x85, 0x7d, 0xd8, 0x83, 0x25, 0x84, 0x0c, 0x68, 0x61, 0x1b, 0x23, 0xa2, 0x85, - 0x87, 0x52, 0x6b, 0x39, 0x4b, 0x5b, 0xd8, 0x04, 0x6c, 0x68, 0xad, 0xcb, 0xa8, 0x5a, 0xd7, 0xe5, 0x63, 0x8e, 0xd5, - 0x26, 0x58, 0x38, 0xe9, 0x50, 0x13, 0x1d, 0xdc, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbd, 0x7e, 0xe5, 0x62, 0x26, - 0xf3, 0x31, 0xb8, 0x6c, 0x3a, 0xd5, 0xd8, 0xb5, 0x79, 0x05, 0x29, 0xae, 0x14, 0xa5, 0x56, 0x38, 0x85, 0x96, 0x5f, - 0x08, 0x9d, 0x27, 0xf6, 0xf2, 0xe2, 0x99, 0x2c, 0x66, 0xd4, 0xde, 0x18, 0xe1, 0x6b, 0xe5, 0x9e, 0x3d, 0x37, 0x2f, - 0xab, 0x54, 0x93, 0x7c, 0xb7, 0x79, 0x15, 0xb1, 0xc8, 0x8c, 0xfc, 0x0a, 0xda, 0x00, 0x53, 0xb9, 0x7c, 0xb5, 0xb6, - 0x20, 0x2e, 0xf2, 0x7c, 0x40, 0x5e, 0xde, 0x5a, 0xea, 0x12, 0x45, 0x0d, 0x6e, 0xf0, 0x93, 0x15, 0x3c, 0x0b, 0xae, - 0x0b, 0x0d, 0x7b, 0xe4, 0xc4, 0x8b, 0xa8, 0x15, 0xd5, 0x5f, 0x7d, 0x35, 0xaa, 0x04, 0x1f, 0xb5, 0x34, 0xc9, 0x25, - 0x88, 0x1e, 0xe5, 0x03, 0x73, 0x1c, 0x44, 0x13, 0x7f, 0xf7, 0x7c, 0xd9, 0xf6, 0x74, 0x36, 0xaf, 0xd4, 0x89, 0xe5, - 0x95, 0x09, 0x78, 0x38, 0xda, 0x27, 0x5c, 0x10, 0x0e, 0x12, 0x59, 0xa9, 0x3d, 0xf4, 0xb9, 0xa8, 0x1b, 0xe7, 0x17, - 0x6d, 0xd6, 0x3c, 0x59, 0xad, 0xf2, 0xcb, 0x36, 0x6b, 0x9f, 0xda, 0x07, 0xdf, 0x22, 0x95, 0x01, 0xcd, 0xe5, 0x63, - 0x9e, 0x45, 0xa0, 0x9d, 0x1d, 0x67, 0x26, 0x9c, 0x82, 0x0f, 0x51, 0x4c, 0x16, 0xba, 0xea, 0x4b, 0x82, 0x71, 0x29, - 0xb1, 0x7a, 0xfc, 0x02, 0xf5, 0xda, 0xe9, 0xb6, 0xab, 0x74, 0xb3, 0x7d, 0x18, 0x5c, 0xb8, 0x14, 0x08, 0x77, 0x20, - 0xe4, 0x01, 0xe8, 0x77, 0x97, 0x02, 0x4c, 0x83, 0x00, 0x95, 0x15, 0x88, 0xb4, 0x7c, 0xb6, 0x98, 0x3d, 0x2b, 0xa8, - 0x59, 0x86, 0x27, 0x7c, 0xc2, 0xb5, 0x4a, 0x29, 0x48, 0xb7, 0xbb, 0xd2, 0xd7, 0xbb, 0x25, 0xa8, 0xac, 0x16, 0xf9, - 0x35, 0xd1, 0x3c, 0xfb, 0xac, 0xdc, 0xc2, 0x21, 0x6c, 0x56, 0x56, 0xe0, 0x0c, 0xad, 0x71, 0x2e, 0x27, 0xb4, 0xe0, - 0x7a, 0x3a, 0xfb, 0xb7, 0x56, 0x87, 0xf5, 0xf5, 0xc0, 0x5c, 0x58, 0x01, 0x48, 0xa8, 0x18, 0xad, 0x56, 0xfc, 0xe8, - 0xfb, 0xf7, 0x49, 0xde, 0x27, 0xbc, 0x8d, 0x3b, 0xf8, 0x18, 0x9f, 0xe2, 0x76, 0x0b, 0xb7, 0x4f, 0xe1, 0xea, 0x3e, - 0xcb, 0x17, 0x23, 0xa6, 0x62, 0x78, 0xf9, 0x4b, 0x5f, 0x26, 0xe7, 0x87, 0x65, 0xbc, 0x7b, 0x5d, 0x24, 0x0e, 0x5d, - 0x82, 0xb0, 0xeb, 0x2e, 0x5e, 0x5d, 0x14, 0x85, 0xc1, 0xd2, 0xc6, 0xa1, 0xea, 0xa4, 0xd4, 0x2f, 0x5c, 0x1e, 0xf7, - 0xc0, 0x9e, 0xdb, 0xae, 0x6c, 0x13, 0xcc, 0xbe, 0xed, 0xcf, 0xb4, 0xfa, 0xd9, 0xd4, 0x25, 0x62, 0x78, 0xe8, 0x55, - 0xe8, 0x81, 0x2e, 0x49, 0xfb, 0xe0, 0x00, 0xac, 0x8e, 0x82, 0xd9, 0x70, 0x1b, 0xfd, 0x80, 0x37, 0x6b, 0x69, 0x10, - 0xac, 0x00, 0x8c, 0x3b, 0xdf, 0x70, 0xb2, 0xb4, 0xb0, 0xd5, 0x40, 0x85, 0x75, 0x11, 0x46, 0x74, 0x0b, 0x49, 0x85, - 0x11, 0xa2, 0xe1, 0x08, 0x73, 0x91, 0x4e, 0xf6, 0x5b, 0x58, 0x8e, 0xc7, 0x8a, 0x69, 0x38, 0x3a, 0x0a, 0xf6, 0x85, - 0x15, 0xca, 0x9c, 0x22, 0x43, 0x36, 0xe1, 0xe2, 0xa1, 0xfe, 0xc4, 0x0a, 0x69, 0x3e, 0x8d, 0x06, 0x23, 0x8d, 0xcc, - 0x2a, 0x46, 0x38, 0xcb, 0xf9, 0x1c, 0xaa, 0x4e, 0x0a, 0x70, 0xfa, 0x81, 0xbf, 0x7c, 0x94, 0x86, 0x6d, 0x02, 0xf9, - 0xfa, 0x60, 0x83, 0xd9, 0xe0, 0x51, 0x41, 0x6f, 0x5e, 0x8b, 0xc7, 0xb0, 0xa3, 0x1e, 0x16, 0x8c, 0x42, 0x36, 0x24, - 0xbd, 0x83, 0xa6, 0xe0, 0x03, 0xda, 0x7c, 0x69, 0x00, 0x97, 0x9e, 0x9b, 0x0f, 0x5b, 0xd1, 0x47, 0x0d, 0x4c, 0xca, - 0xb6, 0x4c, 0xa6, 0x39, 0xa5, 0xab, 0x4c, 0x1b, 0x97, 0xa9, 0x9c, 0xc2, 0x1a, 0xbb, 0xa8, 0x27, 0xe1, 0x60, 0x46, - 0x54, 0x4d, 0xd3, 0xfe, 0xc0, 0xfc, 0x7d, 0x6d, 0x4b, 0xb6, 0xb0, 0x0b, 0xb5, 0xb3, 0xc6, 0xe6, 0xc9, 0xce, 0xa0, - 0x7c, 0x1b, 0xc3, 0x3d, 0x2c, 0xbc, 0x1b, 0x59, 0x23, 0x9f, 0x27, 0x9e, 0x6c, 0x9e, 0xac, 0xd7, 0x66, 0x20, 0x2a, - 0x05, 0x3d, 0xd0, 0x5b, 0xbf, 0x6d, 0x5a, 0xb0, 0x3d, 0xca, 0xaf, 0xd3, 0x16, 0x9e, 0x71, 0x78, 0x06, 0xd3, 0xb7, - 0x77, 0xa5, 0x0b, 0xf9, 0xd9, 0x81, 0xa4, 0x15, 0xa4, 0xd8, 0xe9, 0x04, 0x9d, 0x1d, 0xe3, 0x60, 0xe4, 0x40, 0xcf, - 0xaf, 0x3e, 0x5b, 0x58, 0xfb, 0xdf, 0x6f, 0xca, 0x82, 0x39, 0x1d, 0xb2, 0xbc, 0x9c, 0x50, 0xe6, 0xcf, 0xcf, 0x37, - 0x3c, 0xa9, 0x50, 0xc1, 0xbd, 0x1f, 0x05, 0x7b, 0xda, 0x86, 0x98, 0x9c, 0xd1, 0xbf, 0xed, 0x0f, 0x1b, 0x11, 0xa8, - 0xd4, 0xb2, 0x65, 0x85, 0x54, 0xea, 0xa1, 0x4d, 0xb3, 0x47, 0x0f, 0x1c, 0x91, 0x2f, 0xa1, 0x0b, 0xe0, 0xf5, 0x47, - 0x85, 0x9c, 0x1b, 0x44, 0x70, 0xbf, 0xdd, 0xb8, 0x8d, 0xaf, 0x00, 0x78, 0x3b, 0xec, 0x55, 0xff, 0xb4, 0x80, 0xfd, - 0x8d, 0xca, 0x92, 0x7e, 0xbc, 0x1d, 0x7b, 0xfc, 0x17, 0x12, 0xe2, 0x95, 0x5b, 0x3c, 0x4c, 0x1c, 0x3a, 0x95, 0xac, - 0x59, 0xf9, 0x73, 0xab, 0x24, 0x60, 0x58, 0xbd, 0x60, 0xc8, 0xc6, 0x6d, 0x15, 0xb7, 0x99, 0xff, 0x41, 0x05, 0x83, - 0x05, 0xdf, 0x1a, 0x49, 0xc5, 0xb2, 0xf8, 0xed, 0x53, 0xe7, 0xbf, 0xea, 0x1c, 0xd7, 0xbe, 0xae, 0xbd, 0x51, 0x39, - 0x34, 0xf1, 0x81, 0x23, 0x74, 0x70, 0xb0, 0x91, 0x41, 0xc7, 0x00, 0x78, 0xe4, 0xd8, 0x2f, 0xbf, 0x7c, 0x9e, 0x1d, - 0x33, 0x9a, 0xc7, 0x22, 0x0a, 0x99, 0x3b, 0xcf, 0xcd, 0xd9, 0x89, 0x3c, 0xa1, 0x6a, 0xea, 0x0b, 0x03, 0x1c, 0x1f, - 0x6d, 0xa5, 0x02, 0xbe, 0x47, 0xeb, 0x1d, 0x13, 0xd8, 0xe0, 0xb7, 0xec, 0xa4, 0x76, 0x15, 0xf4, 0x0b, 0xb4, 0xdc, - 0xc5, 0x54, 0x6e, 0x2c, 0x70, 0xb4, 0x39, 0x91, 0x9d, 0x43, 0xdf, 0xa8, 0x53, 0xb2, 0x1e, 0x4f, 0x76, 0x1b, 0x7d, - 0x49, 0xb1, 0x2b, 0xb9, 0xa2, 0x6d, 0x43, 0x56, 0xbd, 0x53, 0xab, 0x2b, 0x53, 0xa7, 0xea, 0x9a, 0xb7, 0xb2, 0xb4, - 0x29, 0xed, 0x92, 0xec, 0xdd, 0x16, 0x0b, 0xaf, 0xc2, 0x1b, 0x8d, 0xf2, 0x22, 0x14, 0xec, 0xb1, 0xc4, 0xa0, 0xcb, - 0x09, 0x5c, 0x2f, 0xac, 0x56, 0x31, 0xfc, 0xd9, 0x35, 0x86, 0x5d, 0xa6, 0x4b, 0x1f, 0xf8, 0x06, 0xbf, 0x12, 0x84, - 0xca, 0x75, 0x76, 0x90, 0x60, 0xdd, 0xe5, 0x06, 0x0d, 0xc7, 0x89, 0xff, 0x82, 0x87, 0x9a, 0xb5, 0x77, 0x39, 0x98, - 0x64, 0xdf, 0x78, 0xdc, 0xad, 0x64, 0x2d, 0x6b, 0x71, 0xd6, 0x37, 0x24, 0x18, 0x62, 0x37, 0xa5, 0x73, 0xdc, 0x4a, - 0xda, 0x28, 0x72, 0xc5, 0x2a, 0xf4, 0xff, 0x56, 0x91, 0xcc, 0x66, 0xfe, 0xd7, 0xd9, 0xd9, 0x99, 0x4b, 0x71, 0x36, - 0x7f, 0xca, 0x78, 0xc0, 0x99, 0x04, 0xf6, 0x85, 0x67, 0xcc, 0xe8, 0x90, 0xdf, 0xc2, 0x50, 0x88, 0x20, 0x97, 0xc2, - 0xb1, 0x4b, 0xf0, 0xce, 0x20, 0x50, 0x1e, 0x60, 0xff, 0x9e, 0x6c, 0x94, 0xf3, 0x0f, 0x15, 0xf9, 0x40, 0xbe, 0x65, - 0x83, 0xec, 0x8b, 0xf9, 0xec, 0x5b, 0x33, 0x19, 0x88, 0xcd, 0x1f, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, - 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, 0x0f, 0x53, 0xd6, 0x3d, 0x72, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0xc5, - 0xa3, 0x8c, 0x7e, 0x2c, 0x43, 0x4f, 0xee, 0xbd, 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, - 0x69, 0xfe, 0x23, 0xde, 0xab, 0x42, 0x50, 0x82, 0x2b, 0xa4, 0x89, 0xe2, 0x88, 0xcd, 0x83, 0xce, 0x69, 0x24, 0x80, - 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0xa8, 0x85, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0x16, 0xa9, 0x0d, 0xe1, - 0x0d, 0x91, 0xdc, 0xca, 0xd9, 0x98, 0xaf, 0x47, 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, - 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, - 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, 0x93, 0xdb, 0x60, 0xaa, 0x7f, 0x82, 0x1d, 0x08, 0x3d, 0x53, 0x3a, - 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, - 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, - 0xcc, 0x63, 0xd2, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, - 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, 0xde, 0x72, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, - 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, 0xcc, 0xc5, 0xc3, 0xf0, 0xd1, 0x77, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, - 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0x32, 0xdd, 0xd9, 0x0d, 0xa3, 0xb5, 0x79, 0x6e, 0x29, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, - 0x04, 0xd9, 0xda, 0x3c, 0xd8, 0x54, 0x66, 0x0d, 0x59, 0xf9, 0x3a, 0x41, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, - 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, - 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x22, 0xd7, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, - 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, 0x53, 0x70, 0xed, 0x43, 0xe4, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, - 0x18, 0x5d, 0x1b, 0xc8, 0xd7, 0x9b, 0x73, 0x9a, 0xb8, 0xb3, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, - 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, - 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x03, - 0x51, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, - 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, - 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, - 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, - 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0xa7, 0x1a, 0x35, 0x62, 0x9e, - 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, - 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, - 0xaa, 0x16, 0x85, 0x79, 0xba, 0x2d, 0x56, 0x28, 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0x52, 0x9a, 0x04, 0xc3, - 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, - 0x71, 0x38, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, - 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, 0xec, 0x9e, 0xae, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, - 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0xd7, 0xb5, 0xb8, 0x4b, 0x72, 0x0f, 0x64, 0x54, 0x6f, 0x60, 0xd7, 0x2c, 0xc0, - 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, 0x69, 0x9e, 0x52, 0xa2, 0xe6, 0x05, 0x25, 0x78, 0xb8, 0x99, 0xb0, - 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x68, 0x7b, 0xff, 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, - 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, - 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x67, 0x36, 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x0f, 0x6a, - 0x54, 0x0f, 0x9a, 0xfb, 0xe7, 0x9d, 0x8e, 0x3a, 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, - 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x9e, - 0xe0, 0xa8, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, 0xe6, 0xfe, 0x65, 0xcf, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, - 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, - 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, - 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, 0x5e, 0xdd, 0x01, 0x2b, 0x01, 0x1f, 0xfd, 0xd8, 0x24, 0x19, 0x43, - 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, - 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, - 0x20, 0x7e, 0x29, 0x74, 0x62, 0x22, 0x45, 0x5f, 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, - 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0x63, 0xc8, 0xe3, 0x52, - 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x71, 0xba, 0x5f, - 0x40, 0xd4, 0x66, 0x77, 0x2c, 0x81, 0x9e, 0x7d, 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, - 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0xde, 0x53, 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, - 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, - 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, - 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, - 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, 0x6c, 0x28, 0x5b, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, - 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, - 0x6d, 0xcb, 0x21, 0x18, 0x76, 0xa4, 0x0b, 0x6e, 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, - 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, - 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xd0, - 0xe5, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, - 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, - 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, - 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, - 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, - 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, - 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, - 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, - 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, - 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, - 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, - 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, - 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, - 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0xdf, - 0xe6, 0x84, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, - 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, - 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, - 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, - 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, - 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, - 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, 0xa9, 0x3e, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, - 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, - 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, - 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, - 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, - 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, - 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, - 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0xef, 0x6a, 0x01, 0x97, - 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, - 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x0b, 0xb3, 0x9f, - 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, - 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, - 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, - 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, - 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, - 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, - 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, - 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, - 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, 0x9a, 0xce, 0x3c, 0x8a, 0x5c, 0x7b, 0xef, 0x77, 0x53, 0xb4, 0xf5, - 0xaf, 0x0f, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, - 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, - 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, - 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, - 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, - 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, - 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, - 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, - 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, - 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, - 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, - 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, - 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0x3d, 0x45, 0xb7, 0x72, 0xef, 0xf4, - 0xac, 0xcc, 0xeb, 0x4a, 0xab, 0x58, 0x0e, 0x73, 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, - 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, - 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, - 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, - 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, - 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, - 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, 0x89, 0x17, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, - 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, - 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, - 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, - 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, - 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, - 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, - 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, - 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, 0xbd, 0xbb, 0xe1, 0xbb, 0x70, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, - 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0x3c, 0x15, 0x19, - 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, - 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, - 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, 0x67, 0xf7, 0x2e, 0x61, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, - 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, - 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, - 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, - 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, - 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, 0x55, 0x31, 0xdd, 0x0f, 0xdf, 0xd3, 0x0b, 0x3e, 0xbc, 0x43, 0xda, - 0xc6, 0xa3, 0x96, 0x94, 0x50, 0xbb, 0x83, 0xf6, 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, - 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, 0xca, 0x28, 0x18, 0xc2, 0x3e, 0x60, 0x1f, 0x8b, 0x24, 0xa3, 0xd9, - 0x94, 0x81, 0xba, 0xdf, 0x16, 0xad, 0xe6, 0xf6, 0xa4, 0xee, 0x37, 0x64, 0x9c, 0x7d, 0x84, 0x71, 0xf6, 0x51, 0xe0, - 0xc5, 0x22, 0xc9, 0x1f, 0x32, 0xd6, 0x38, 0x56, 0x4d, 0x81, 0x8e, 0x3a, 0xc0, 0x9d, 0x81, 0x03, 0x0f, 0xd8, 0xa2, - 0x1c, 0x1c, 0x50, 0x67, 0x71, 0x4f, 0x1b, 0x99, 0xf7, 0xf6, 0x84, 0xda, 0x45, 0x2c, 0x70, 0xb3, 0x66, 0xa6, 0x05, - 0xad, 0x15, 0xc6, 0x79, 0x3c, 0xe0, 0x6d, 0x9e, 0xd5, 0xe2, 0x27, 0x6c, 0x58, 0x53, 0xd5, 0x6f, 0xa0, 0x39, 0xaa, - 0x05, 0xb9, 0x79, 0x62, 0xbc, 0x55, 0x49, 0x3f, 0x8a, 0x06, 0x96, 0x53, 0x21, 0x86, 0x64, 0xf4, 0x5b, 0x83, 0xe0, - 0x56, 0x7b, 0xb5, 0xe2, 0x1e, 0xf1, 0x45, 0xcd, 0x5b, 0xcd, 0xdc, 0x02, 0xd0, 0x22, 0x8e, 0xca, 0x7b, 0x93, 0x08, - 0xbc, 0x6f, 0xcb, 0x08, 0x69, 0xcb, 0xbe, 0x7d, 0x34, 0xb1, 0x54, 0x6c, 0xbe, 0xa3, 0x93, 0x41, 0x1a, 0xd9, 0x11, - 0x45, 0xf8, 0xba, 0x84, 0x24, 0x5c, 0x25, 0x5d, 0xab, 0x4c, 0xce, 0x99, 0x4a, 0x39, 0xbe, 0x2e, 0xa4, 0xd4, 0x57, - 0xf6, 0x4b, 0xe2, 0xea, 0x4e, 0x46, 0xe0, 0xeb, 0x09, 0xd3, 0xef, 0x68, 0x31, 0x61, 0xe0, 0x57, 0xe4, 0x6f, 0xc7, - 0x52, 0x4a, 0x2e, 0x9f, 0x88, 0xb8, 0x4f, 0x31, 0xbc, 0xf8, 0x39, 0xc0, 0xda, 0x84, 0x40, 0x29, 0x71, 0x11, 0x2e, - 0x88, 0xde, 0x14, 0xf2, 0xf6, 0x2e, 0x2e, 0xb0, 0x73, 0x00, 0x2c, 0x9d, 0x26, 0x01, 0xfe, 0xe5, 0x63, 0x3e, 0x56, - 0x63, 0x4e, 0x8d, 0xae, 0xdf, 0xfd, 0x4e, 0xae, 0x81, 0xde, 0x96, 0x8e, 0x82, 0xfd, 0xd6, 0x00, 0x72, 0xe1, 0x2e, - 0x0c, 0x2e, 0xbe, 0xc2, 0xda, 0xb2, 0x30, 0xde, 0x58, 0x00, 0xbd, 0xbf, 0x33, 0xb0, 0x60, 0xc3, 0x1c, 0x53, 0x78, - 0x2e, 0x75, 0xc2, 0x74, 0x10, 0x15, 0xe4, 0x49, 0xf9, 0x20, 0x66, 0xad, 0xf6, 0x5b, 0x36, 0x86, 0x3b, 0x8c, 0xe4, - 0xdb, 0x85, 0x13, 0x07, 0x1e, 0x90, 0x69, 0x32, 0xdb, 0xec, 0x1b, 0x1f, 0x79, 0xe4, 0xf5, 0x38, 0xde, 0xd5, 0x52, - 0x98, 0x6f, 0x56, 0x74, 0x8d, 0x21, 0x14, 0x45, 0xd8, 0xef, 0x17, 0x15, 0x53, 0x54, 0x19, 0xb4, 0x41, 0xc3, 0xf2, - 0x46, 0xfc, 0x02, 0x67, 0x0c, 0xad, 0x17, 0xb2, 0x77, 0x74, 0xd6, 0xe1, 0xcc, 0x61, 0xc6, 0x94, 0xc0, 0xa8, 0xb4, - 0x2c, 0xe8, 0x04, 0x1c, 0x9d, 0xab, 0x0f, 0xa2, 0xe2, 0xea, 0x58, 0x01, 0x78, 0x92, 0x29, 0xfc, 0x93, 0x6f, 0x82, - 0x75, 0xbf, 0x55, 0x33, 0x4c, 0xfd, 0x45, 0x6f, 0xbb, 0x96, 0x2f, 0x43, 0x1c, 0x69, 0x63, 0x08, 0xad, 0x73, 0x7b, - 0x07, 0x28, 0xe2, 0x82, 0x5e, 0xa4, 0x1a, 0x5f, 0xab, 0xc5, 0xd0, 0xac, 0xaf, 0x71, 0x1d, 0xd3, 0x06, 0x51, 0xac, - 0xbb, 0x26, 0xbe, 0xae, 0xde, 0x1f, 0x55, 0xa9, 0x82, 0x33, 0x48, 0x20, 0xac, 0xca, 0xcb, 0x86, 0x54, 0x92, 0x4b, - 0xd3, 0xa9, 0x34, 0x9d, 0x56, 0x08, 0xe5, 0xd2, 0x93, 0xf2, 0xfe, 0x15, 0x42, 0x18, 0x98, 0x32, 0x3b, 0xb0, 0x4a, - 0x6d, 0x61, 0x15, 0xbc, 0x7a, 0xb1, 0x81, 0x55, 0x12, 0x8e, 0xe7, 0x12, 0x8d, 0x8a, 0x0a, 0x87, 0x0c, 0xe9, 0x0b, - 0xb1, 0x08, 0x12, 0x00, 0x8b, 0xde, 0x65, 0x2e, 0xef, 0x7b, 0x38, 0x14, 0xf6, 0x24, 0x93, 0x70, 0xba, 0x09, 0xcd, - 0xe1, 0x61, 0x5a, 0xd5, 0xf3, 0x08, 0x01, 0x4b, 0xcf, 0x31, 0x3c, 0x48, 0xfc, 0xfd, 0x87, 0x50, 0x9d, 0x05, 0x79, - 0xfa, 0x2f, 0x51, 0x12, 0x1a, 0xfb, 0xcf, 0xf1, 0xd0, 0x21, 0x61, 0x38, 0xf0, 0xcd, 0x11, 0x56, 0x38, 0xb8, 0x55, - 0xc4, 0x67, 0x70, 0x87, 0x8f, 0x75, 0xe8, 0x01, 0x60, 0x09, 0xc5, 0x21, 0xc8, 0x37, 0x50, 0xcc, 0xe0, 0x80, 0x26, - 0xcb, 0xf0, 0x02, 0x17, 0xac, 0x16, 0xca, 0xfb, 0xdb, 0x96, 0x97, 0xd2, 0x6a, 0x97, 0xbc, 0xc6, 0x1c, 0xa8, 0xfc, - 0x0c, 0x2f, 0x7c, 0x85, 0x79, 0x29, 0xd9, 0x7d, 0xe1, 0x6b, 0x07, 0xf4, 0x14, 0x02, 0x46, 0xba, 0xdf, 0x6b, 0xc2, - 0x3d, 0x45, 0x2f, 0x73, 0x71, 0xd8, 0x76, 0xd0, 0xbd, 0xc0, 0x5c, 0x5d, 0x55, 0x59, 0x73, 0x30, 0x85, 0x06, 0x07, - 0x55, 0x38, 0x23, 0x30, 0x57, 0x2f, 0xca, 0x82, 0x73, 0x10, 0xef, 0x7b, 0xc2, 0xe4, 0x94, 0xd1, 0x00, 0x5e, 0x64, - 0xe5, 0xa3, 0x53, 0x3d, 0x0e, 0x2e, 0xe3, 0x86, 0x4d, 0x7c, 0x21, 0x7c, 0x2a, 0xb0, 0x92, 0xd6, 0x38, 0x34, 0xa2, - 0x23, 0x3a, 0x07, 0xb3, 0x0d, 0xa0, 0xe0, 0xee, 0x7c, 0xd8, 0x58, 0xa8, 0xe0, 0x31, 0xd8, 0xda, 0xdb, 0xcd, 0x84, - 0x38, 0x93, 0xa6, 0xe0, 0x6e, 0xdb, 0x20, 0x83, 0x37, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, - 0x84, 0x27, 0x28, 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xa2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x3a, 0x6a, 0x20, - 0x2a, 0x6a, 0xa0, 0x02, 0x6a, 0x20, 0xeb, 0xdb, 0xbf, 0x80, 0x85, 0xb0, 0x11, 0xaa, 0x44, 0x10, 0x10, 0x61, 0xae, - 0x0d, 0x1f, 0x50, 0x24, 0x21, 0xe4, 0x0d, 0xa0, 0x62, 0x4a, 0x5e, 0x82, 0xd1, 0x38, 0xbc, 0xde, 0x03, 0xee, 0x97, - 0x96, 0x61, 0xf0, 0x9c, 0x82, 0xc9, 0x7f, 0xeb, 0xf3, 0xa1, 0x7a, 0xb9, 0x3a, 0x08, 0xe1, 0x17, 0x10, 0x2b, 0xc2, - 0xf1, 0x17, 0xbf, 0x00, 0xd9, 0x54, 0x58, 0x1e, 0x1c, 0x48, 0x10, 0xf8, 0x21, 0x8a, 0x70, 0xc0, 0x33, 0xbc, 0xcc, - 0x36, 0x88, 0x9e, 0x9f, 0x95, 0xaa, 0x66, 0x25, 0x83, 0x59, 0x15, 0x9e, 0xc6, 0xd1, 0x35, 0x61, 0x20, 0xb8, 0x50, - 0xbb, 0x6f, 0x10, 0x02, 0x65, 0xcb, 0x8d, 0xa1, 0x4b, 0x4f, 0xc1, 0x7c, 0x34, 0x8e, 0xde, 0x32, 0x78, 0xd2, 0xd6, - 0x98, 0xfc, 0x33, 0x6d, 0x1e, 0xb8, 0x4f, 0xf7, 0xa2, 0x46, 0xe0, 0xa4, 0x4e, 0x51, 0xf2, 0xb7, 0xe4, 0x22, 0x8e, - 0x9a, 0x97, 0x11, 0x6a, 0xc0, 0xbf, 0x0d, 0x8e, 0xba, 0x34, 0xa1, 0xa3, 0x91, 0x0f, 0x7e, 0x93, 0x11, 0xb3, 0xc9, - 0x56, 0x2b, 0x51, 0x11, 0xf4, 0xc4, 0x6e, 0x30, 0x60, 0x25, 0x5e, 0x00, 0xfb, 0x60, 0x39, 0x58, 0xf2, 0x4e, 0xc4, - 0xca, 0x9f, 0x52, 0x18, 0xac, 0x9e, 0x33, 0x84, 0x70, 0x16, 0xc4, 0x6c, 0xfc, 0xcf, 0x67, 0x1a, 0xae, 0x9f, 0x9f, - 0xaf, 0x63, 0x44, 0xa4, 0x0f, 0x22, 0x57, 0x63, 0x47, 0x44, 0x10, 0xb6, 0x4c, 0xf7, 0x5d, 0x99, 0x1f, 0xbc, 0x75, - 0xf5, 0xc0, 0x86, 0x8b, 0x03, 0x03, 0x6a, 0x14, 0x18, 0xad, 0xe0, 0x9c, 0x94, 0x03, 0x07, 0x25, 0x84, 0x66, 0x45, - 0x3c, 0x25, 0x97, 0x10, 0x09, 0x2f, 0x43, 0x5d, 0x30, 0x2c, 0x08, 0x24, 0xa8, 0x29, 0x48, 0x50, 0x99, 0xaf, 0x3d, - 0x82, 0x59, 0xe7, 0x66, 0xb6, 0x53, 0xd4, 0x75, 0x41, 0x7e, 0x7e, 0xd1, 0xf1, 0x08, 0x58, 0xda, 0x83, 0x83, 0x02, - 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, 0xc0, 0x40, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0xda, 0x78, 0x1d, 0x18, 0x5b, - 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x3d, 0x9d, 0x6e, 0x47, 0x48, 0xec, 0x7d, 0xd4, - 0x26, 0xd0, 0x98, 0x23, 0xdd, 0xd5, 0xc6, 0xfc, 0x5a, 0xd3, 0x23, 0x56, 0x93, 0x90, 0x2e, 0x48, 0x97, 0xe7, 0xd3, - 0x9e, 0xc1, 0x15, 0xab, 0x34, 0x72, 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x17, - 0x49, 0xc9, 0x86, 0x61, 0x06, 0x61, 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0xb3, 0x7f, 0x4a, 0x1f, - 0x6c, 0xba, 0xf6, 0xe6, 0x11, 0x40, 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x36, 0x2a, 0xb3, 0xb0, 0x96, 0xb1, 0x95, - 0xdb, 0xf6, 0x18, 0x7b, 0x27, 0xb6, 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x88, 0x75, 0x6d, - 0xc8, 0x46, 0x1b, 0xda, 0x37, 0x4f, 0xc2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x39, 0x2e, 0xc1, 0x21, 0xbc, 0xf0, 0x08, - 0x7f, 0x0b, 0x2c, 0x52, 0x81, 0x19, 0x96, 0xab, 0x15, 0xd4, 0xf3, 0x78, 0x9f, 0x6d, 0x06, 0x27, 0x95, 0x1b, 0x63, - 0x97, 0x76, 0xe2, 0x71, 0xd9, 0x84, 0xc4, 0x19, 0xf4, 0xeb, 0x2b, 0xa2, 0xde, 0x7e, 0x3b, 0x7d, 0xe2, 0xdf, 0x2b, - 0x73, 0x3b, 0x10, 0x1b, 0xd6, 0x1b, 0xac, 0x3e, 0x80, 0x96, 0xbf, 0xca, 0xfc, 0x43, 0x65, 0xc1, 0x4d, 0x82, 0xda, - 0x5c, 0xc4, 0x2e, 0xeb, 0x22, 0x46, 0x6a, 0x8b, 0xbb, 0x43, 0x88, 0x7f, 0xb5, 0x15, 0xc5, 0x80, 0x27, 0x15, 0xff, - 0x1c, 0xa3, 0x2e, 0x84, 0xa2, 0xb6, 0x1e, 0x36, 0x40, 0x69, 0x97, 0xeb, 0x4a, 0x8c, 0x0c, 0x09, 0xe4, 0x5b, 0x17, - 0x5e, 0xd0, 0x9c, 0x44, 0x0a, 0xe4, 0xe4, 0x20, 0x2a, 0x69, 0xb6, 0x21, 0xcc, 0x75, 0xb7, 0x70, 0xcc, 0x5c, 0x6d, - 0xd0, 0x22, 0x7e, 0x01, 0xec, 0x0c, 0x37, 0x92, 0xa5, 0x03, 0x9f, 0xaa, 0x81, 0xcf, 0xaf, 0xb9, 0xa1, 0x28, 0x0a, - 0xf5, 0xde, 0xd9, 0x47, 0xe6, 0xe0, 0x77, 0x1a, 0x88, 0x8f, 0xd4, 0xe9, 0x48, 0x36, 0x42, 0xad, 0x39, 0x3b, 0x5e, - 0xb6, 0x19, 0x61, 0x50, 0xd8, 0xe8, 0x7d, 0x15, 0xb2, 0x8a, 0x9d, 0x9d, 0x8a, 0x60, 0x4e, 0x5f, 0x54, 0xe5, 0x9c, - 0xca, 0x2d, 0xa3, 0x5a, 0x6a, 0x1a, 0x20, 0xc2, 0x95, 0x4f, 0x24, 0xef, 0x33, 0x13, 0xfe, 0xc1, 0x60, 0x5c, 0x3d, - 0x52, 0xf8, 0xfb, 0x5d, 0xb1, 0x43, 0xb6, 0xa3, 0xc3, 0x6d, 0x04, 0xcd, 0x0b, 0x15, 0x3c, 0xe0, 0xa8, 0x64, 0x09, - 0x91, 0x22, 0x97, 0xfb, 0xaa, 0x66, 0xca, 0x76, 0x1d, 0x21, 0x84, 0xb4, 0xc7, 0x59, 0x37, 0xb4, 0x7a, 0xe8, 0x91, - 0x2a, 0xca, 0xe1, 0x16, 0xcd, 0x75, 0x01, 0x2a, 0x8c, 0x40, 0xba, 0xfc, 0xcc, 0xee, 0x52, 0x09, 0xd1, 0xcb, 0xd7, - 0x2e, 0x84, 0xb1, 0xb3, 0xb2, 0xc4, 0x85, 0x19, 0xb5, 0x0d, 0xa3, 0xeb, 0x36, 0x86, 0xb3, 0x81, 0x31, 0xd3, 0xa0, - 0xa4, 0x05, 0xa1, 0xae, 0xbb, 0xf4, 0x22, 0x33, 0x81, 0x1e, 0x73, 0x42, 0x1b, 0x0c, 0x4f, 0x89, 0x06, 0xcb, 0xa6, - 0x02, 0x2c, 0xf8, 0x96, 0x45, 0x6a, 0x6d, 0x36, 0x59, 0xfc, 0x51, 0xc7, 0xe6, 0x69, 0xbf, 0xbc, 0x62, 0x9e, 0x0b, - 0x47, 0xdd, 0x9e, 0x67, 0x3e, 0x1e, 0xdd, 0xd3, 0x37, 0x57, 0x2f, 0x5e, 0xbe, 0x7e, 0xb5, 0x5a, 0xb5, 0x59, 0xb3, - 0x7d, 0x82, 0x7f, 0xd2, 0x65, 0x3c, 0xd8, 0x32, 0x0a, 0xd0, 0xc1, 0xc1, 0x3e, 0x37, 0x2e, 0x3c, 0x9f, 0xf9, 0x1c, - 0xe2, 0x06, 0xe9, 0x01, 0xce, 0x8a, 0x32, 0x26, 0xc8, 0x6d, 0xd4, 0x8b, 0xee, 0x22, 0x50, 0x42, 0x55, 0xe4, 0xef, - 0xc3, 0xe6, 0xec, 0xf7, 0x20, 0x30, 0x11, 0xd4, 0x87, 0x08, 0x20, 0x10, 0xaf, 0x14, 0x17, 0x84, 0xf9, 0x04, 0x88, - 0xe2, 0xbd, 0x00, 0xce, 0xd4, 0x44, 0xad, 0x5a, 0xa8, 0xb8, 0x00, 0x92, 0x68, 0xc3, 0x51, 0xd2, 0x23, 0x13, 0xc0, - 0x1b, 0x82, 0x52, 0xda, 0x5f, 0xdd, 0xdc, 0xb9, 0x4b, 0xe5, 0xa8, 0xd7, 0x4a, 0x73, 0x3c, 0x75, 0x9f, 0x53, 0xf8, - 0x9c, 0x76, 0xfd, 0xe9, 0x20, 0x0e, 0x73, 0xbc, 0x20, 0xe2, 0xd0, 0x3f, 0x8b, 0xb8, 0x9c, 0x17, 0xec, 0x0b, 0x97, - 0x0b, 0x95, 0x2e, 0x6f, 0x53, 0x99, 0xdc, 0x36, 0x47, 0x87, 0x71, 0x91, 0xdc, 0x36, 0x55, 0x72, 0x8b, 0xf0, 0x5d, - 0x2a, 0x93, 0x3b, 0x9b, 0x72, 0xd7, 0x54, 0x70, 0xf3, 0x85, 0x05, 0x1c, 0x8a, 0xb6, 0x68, 0x63, 0xb1, 0x59, 0xd4, - 0xa6, 0xb8, 0xa2, 0x01, 0x06, 0xff, 0xbe, 0x63, 0xe3, 0x87, 0xe1, 0x4b, 0x70, 0x69, 0xd2, 0x44, 0x7e, 0x02, 0xe9, - 0xa7, 0x55, 0x19, 0xb8, 0x4f, 0x49, 0xab, 0x3b, 0xbd, 0x10, 0xcd, 0x76, 0xb7, 0xd1, 0x98, 0xc2, 0xde, 0xcd, 0x48, - 0xee, 0x8b, 0x4d, 0x1b, 0x26, 0xbe, 0xce, 0x7e, 0xb6, 0x5a, 0xed, 0xe7, 0xc8, 0x6c, 0xb8, 0x09, 0x8b, 0x75, 0x7f, - 0x3a, 0xc0, 0x2d, 0xfc, 0x3c, 0x43, 0x68, 0xc9, 0xfa, 0xd3, 0x01, 0x61, 0xfd, 0x69, 0xa3, 0x3d, 0xb0, 0x86, 0x76, - 0x66, 0x2b, 0xae, 0x21, 0x84, 0xe6, 0x74, 0x70, 0x64, 0x4a, 0x4a, 0x97, 0x6f, 0xbf, 0x68, 0x15, 0xd0, 0x4f, 0xd5, - 0x82, 0x97, 0x49, 0xdc, 0x81, 0xbe, 0xe8, 0x85, 0x7d, 0xba, 0xb5, 0x20, 0xc7, 0x47, 0x95, 0xab, 0x3d, 0x45, 0xd8, - 0xf4, 0xa4, 0x0e, 0x8b, 0x43, 0xd3, 0x8c, 0xeb, 0x52, 0xba, 0xef, 0x50, 0x33, 0xf2, 0xd1, 0xc1, 0x02, 0x10, 0xa4, - 0x82, 0x47, 0x56, 0xb8, 0x70, 0x4a, 0x21, 0x5c, 0x1c, 0x54, 0xb6, 0x60, 0x92, 0x93, 0x56, 0x37, 0x37, 0x96, 0xfe, - 0xb9, 0x8b, 0x68, 0x4a, 0x31, 0x25, 0x99, 0x2f, 0x99, 0x1b, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x00, - 0x8f, 0x08, 0xc4, 0x43, 0xea, 0x16, 0xc6, 0xc0, 0x2b, 0x9e, 0x36, 0x8b, 0x3e, 0x1b, 0xa0, 0xa3, 0x63, 0x4c, 0xfb, - 0x7f, 0x65, 0xf3, 0x36, 0x3c, 0x16, 0xf8, 0xd7, 0x80, 0x4c, 0x9b, 0xb2, 0x4c, 0x10, 0x90, 0x30, 0x6a, 0xca, 0x43, - 0xd8, 0x4b, 0x08, 0x67, 0xb6, 0x62, 0xd6, 0x67, 0x83, 0xe6, 0xb4, 0xac, 0xd8, 0xf1, 0x15, 0x1b, 0xb2, 0x4c, 0xb0, - 0x15, 0x1b, 0xae, 0x62, 0xf8, 0x3a, 0x83, 0x01, 0x41, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x28, 0x88, 0xe6, 0x8b, 0x15, - 0xf1, 0x9b, 0xdd, 0xde, 0xe3, 0xb7, 0xc0, 0x02, 0xad, 0xb6, 0xff, 0x77, 0xa1, 0x0c, 0xd8, 0x53, 0x16, 0x26, 0x66, - 0x6e, 0x61, 0x55, 0x74, 0x00, 0x95, 0x12, 0x61, 0x0a, 0x03, 0x99, 0xfd, 0xcc, 0x40, 0x2d, 0xd0, 0x1a, 0xe4, 0x7d, - 0x3d, 0x68, 0x66, 0x70, 0xc4, 0xc0, 0x3b, 0x34, 0x64, 0x6a, 0x8c, 0x09, 0xe3, 0x1c, 0xa6, 0x98, 0x19, 0xf0, 0x4c, - 0xd3, 0xd6, 0x5a, 0x1a, 0x59, 0xae, 0x97, 0xf7, 0xfe, 0xd1, 0xb1, 0xea, 0x17, 0xcd, 0xf6, 0x00, 0xed, 0x13, 0x62, - 0x3f, 0x06, 0xb0, 0xc9, 0x5c, 0x6a, 0xc3, 0x7c, 0x1f, 0x75, 0x52, 0xfb, 0x09, 0x7f, 0x06, 0x6b, 0xb3, 0x03, 0x40, - 0x47, 0x86, 0xcd, 0xfa, 0xcb, 0x9a, 0xca, 0xeb, 0xe3, 0xce, 0x28, 0x95, 0xbb, 0xde, 0x9d, 0x0e, 0x34, 0xc5, 0xa1, - 0xb7, 0x1e, 0x2e, 0x1f, 0xea, 0x21, 0x60, 0xc6, 0x60, 0x6e, 0x99, 0xd1, 0xf7, 0x42, 0x24, 0x17, 0x44, 0x62, 0x69, - 0xb0, 0x86, 0xc1, 0xde, 0x3a, 0x38, 0x30, 0xd5, 0x58, 0x03, 0x9e, 0x27, 0x45, 0x20, 0x18, 0xf8, 0x08, 0xca, 0x80, - 0x26, 0xca, 0xdc, 0x86, 0x93, 0x8f, 0xcc, 0xfd, 0xc2, 0xe5, 0xed, 0x63, 0xe1, 0xb4, 0xad, 0xe6, 0x7a, 0xbc, 0x2c, - 0x70, 0x57, 0xde, 0x4b, 0x5a, 0x05, 0x37, 0xb2, 0x37, 0x79, 0xca, 0xdc, 0xad, 0xfb, 0x52, 0x9d, 0xdd, 0xcd, 0x74, - 0xca, 0x66, 0x3a, 0xdb, 0xcd, 0x84, 0x9a, 0x99, 0x6f, 0x59, 0x45, 0x9a, 0x93, 0x35, 0x51, 0x73, 0x2a, 0x7e, 0xa2, - 0x73, 0xd0, 0x8e, 0x72, 0x7b, 0xaf, 0x0a, 0x27, 0x57, 0x4e, 0x2e, 0xf7, 0x73, 0x43, 0x5c, 0x91, 0xb9, 0x50, 0x87, - 0x00, 0x2f, 0x2f, 0xca, 0xc7, 0x07, 0xb8, 0x14, 0xbf, 0xca, 0x91, 0x8b, 0x72, 0x2a, 0xa4, 0x96, 0x82, 0x45, 0xc8, - 0xa0, 0xaa, 0x8b, 0x81, 0xbd, 0xb4, 0x7b, 0x4f, 0xf4, 0x78, 0xbf, 0x8a, 0x98, 0x37, 0x30, 0xcf, 0x7d, 0x7c, 0x4f, - 0x53, 0xec, 0xd4, 0xc4, 0x19, 0xf9, 0x90, 0xc5, 0x39, 0xc8, 0x66, 0xfd, 0xea, 0xb5, 0xdf, 0x46, 0x1b, 0x17, 0xcd, - 0x58, 0xf4, 0xcc, 0x13, 0x27, 0x3f, 0x14, 0xc6, 0x38, 0xc0, 0x3a, 0xfa, 0x23, 0x4c, 0x2d, 0xd8, 0xb3, 0xc4, 0x53, - 0xe8, 0xe4, 0xd6, 0xa6, 0xdd, 0x85, 0x69, 0x77, 0x26, 0xad, 0x03, 0xe5, 0x80, 0x34, 0xbb, 0x32, 0x9d, 0x3b, 0xff, - 0x7d, 0x07, 0x2f, 0xdd, 0xae, 0x21, 0x12, 0xf7, 0xfc, 0x91, 0x31, 0x86, 0x78, 0x03, 0x36, 0xa2, 0xea, 0xe0, 0xe0, - 0x0f, 0xe7, 0x7d, 0x5b, 0xc9, 0x7d, 0xdf, 0x0a, 0x07, 0xb6, 0xc1, 0x54, 0xba, 0xbc, 0x91, 0xcc, 0x16, 0x60, 0xd7, - 0xb9, 0xff, 0x8d, 0x78, 0xf8, 0x22, 0x64, 0x5a, 0xac, 0xab, 0xf8, 0x2b, 0x39, 0x2a, 0x3d, 0x44, 0x35, 0x44, 0x20, - 0xad, 0xac, 0x4b, 0x43, 0xd3, 0xd1, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x81, 0x7d, 0x91, 0x5b, 0x27, - 0xf0, 0x68, 0x61, 0x8d, 0xa1, 0xb9, 0x2b, 0xbd, 0x93, 0x6c, 0x40, 0xd4, 0xfa, 0xb8, 0x43, 0x49, 0x24, 0x16, 0xd5, - 0x5d, 0x08, 0x87, 0xbb, 0x10, 0xcc, 0xcb, 0xa0, 0x6d, 0x10, 0xbb, 0xdd, 0x05, 0x6d, 0x03, 0xa7, 0x6e, 0x1b, 0xb8, - 0x3d, 0x18, 0x2c, 0xec, 0x7d, 0x78, 0x39, 0x96, 0x63, 0xe1, 0xaf, 0xc9, 0xec, 0x03, 0x40, 0xa0, 0xf6, 0x61, 0xc5, - 0x13, 0x07, 0x82, 0xc4, 0x19, 0x8e, 0xbe, 0xe7, 0xec, 0xc6, 0x5a, 0x0e, 0xcf, 0xe6, 0x0b, 0xcd, 0x46, 0xe6, 0x8e, - 0x1a, 0x54, 0x7c, 0x75, 0x3f, 0xaf, 0x9f, 0xb2, 0x9a, 0x6e, 0xfc, 0x1e, 0x84, 0x91, 0x70, 0xca, 0x0e, 0xa3, 0x90, - 0xb0, 0xc1, 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0x6d, 0xc2, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x08, 0xdb, - 0x78, 0x63, 0x41, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x45, 0xcd, 0xa8, 0xc1, 0x52, - 0x17, 0x94, 0xd9, 0x47, 0x18, 0x57, 0x17, 0x27, 0x26, 0x4e, 0x7b, 0xa9, 0x57, 0xff, 0x2d, 0x03, 0x03, 0x7c, 0x01, - 0x5e, 0x62, 0x61, 0x74, 0xd7, 0xbe, 0x6e, 0x40, 0x7d, 0xd9, 0x60, 0x03, 0xb4, 0x5a, 0xb5, 0xca, 0x67, 0xa0, 0xdc, - 0x35, 0x97, 0xb0, 0xd7, 0x5c, 0xc2, 0x5d, 0x73, 0x09, 0x7f, 0xcd, 0x25, 0xcc, 0x35, 0x97, 0xf0, 0xd7, 0x5c, 0x1e, - 0x84, 0x9f, 0x82, 0x38, 0x8e, 0x31, 0x87, 0xb8, 0x8a, 0xda, 0x46, 0xc6, 0x83, 0x0b, 0xcf, 0x7d, 0x96, 0xa8, 0x72, - 0xf9, 0xc3, 0x18, 0x72, 0x5b, 0xb6, 0x12, 0xc6, 0x6d, 0x8a, 0x29, 0x88, 0x9c, 0x7e, 0x70, 0x50, 0xba, 0x3b, 0x83, - 0x8f, 0x7a, 0xca, 0xf1, 0xd2, 0x3a, 0xd1, 0xfe, 0x01, 0x3a, 0x79, 0xf3, 0xeb, 0x63, 0x2a, 0xd7, 0x44, 0x38, 0x93, - 0xfb, 0xfd, 0xb6, 0xa7, 0x14, 0x9f, 0x32, 0x13, 0x9e, 0x9c, 0x27, 0xda, 0x88, 0x20, 0x08, 0x51, 0xa2, 0x70, 0x46, - 0xa4, 0xdd, 0xef, 0xde, 0x15, 0xde, 0xa8, 0xa2, 0xbc, 0x59, 0xc9, 0xe3, 0x1c, 0x9c, 0xd8, 0x8d, 0x15, 0x06, 0xea, - 0x82, 0x0b, 0x41, 0x66, 0x12, 0xfe, 0x68, 0xe6, 0x96, 0x9c, 0x65, 0x65, 0xd2, 0xc7, 0x66, 0x6e, 0x08, 0x58, 0x41, - 0xf6, 0x3d, 0xcc, 0x96, 0xb7, 0x29, 0xc5, 0x77, 0x69, 0x86, 0x87, 0xf2, 0x36, 0x2d, 0x42, 0x5b, 0x10, 0x7f, 0xf1, - 0x37, 0x8e, 0x23, 0x41, 0xc1, 0xdf, 0x27, 0xe2, 0x62, 0x8f, 0x6f, 0x78, 0x01, 0x2e, 0x33, 0x63, 0x51, 0x9d, 0x32, - 0xfc, 0x0d, 0x4b, 0x78, 0x08, 0x4e, 0xa6, 0xb1, 0x22, 0xf7, 0x38, 0xb0, 0x13, 0x92, 0x80, 0xc3, 0xd5, 0xed, 0x15, - 0xff, 0x0a, 0x17, 0x5f, 0xa5, 0xb3, 0x65, 0x73, 0x28, 0x6f, 0x23, 0x5c, 0x90, 0x37, 0xf0, 0xfa, 0xd6, 0xff, 0xcb, - 0xde, 0xdb, 0x36, 0xb7, 0x6d, 0x64, 0xeb, 0xa2, 0x7f, 0x45, 0x62, 0xd9, 0x0c, 0x60, 0x36, 0x29, 0xca, 0xe7, 0xcc, - 0x54, 0x5d, 0x50, 0x6d, 0x96, 0x63, 0xc7, 0x13, 0x67, 0x22, 0xdb, 0x63, 0x79, 0x32, 0xc9, 0xb0, 0x78, 0x19, 0x08, - 0x68, 0x0a, 0x70, 0x40, 0x80, 0x01, 0x40, 0x89, 0x34, 0x89, 0xff, 0x7e, 0x6a, 0xad, 0xd5, 0xaf, 0x20, 0x28, 0x7b, - 0xf6, 0x3e, 0xfb, 0xd3, 0xbd, 0x5f, 0x6c, 0xb1, 0xd1, 0x68, 0xf4, 0x7b, 0xaf, 0x5e, 0x2f, 0xcf, 0xd3, 0x93, 0xb1, - 0xba, 0x3d, 0x70, 0xd6, 0xa5, 0x14, 0x1d, 0x6f, 0x8a, 0xc3, 0xdb, 0xf3, 0xd9, 0x7e, 0x1b, 0x44, 0x6c, 0x17, 0x64, - 0x58, 0xeb, 0xa4, 0xe1, 0x3f, 0xd1, 0xd6, 0xc1, 0x62, 0x84, 0xfd, 0x5f, 0xd6, 0x03, 0x2f, 0x21, 0x35, 0x14, 0xb8, - 0x18, 0x6c, 0x38, 0x5a, 0xdb, 0x65, 0x1a, 0xb8, 0xa9, 0x41, 0xaf, 0xef, 0x29, 0x44, 0x79, 0xc9, 0x68, 0x6e, 0x04, - 0xeb, 0xc6, 0x90, 0x8b, 0xc3, 0x71, 0xb3, 0x1c, 0xf2, 0x92, 0xa6, 0xd3, 0x20, 0x94, 0xee, 0x2c, 0x6b, 0x48, 0xa2, - 0xec, 0x83, 0x50, 0xbb, 0xb6, 0xec, 0xb7, 0x81, 0xed, 0xcb, 0x1f, 0x0d, 0x63, 0xff, 0x62, 0xf9, 0x4c, 0x48, 0x17, - 0xf1, 0x1c, 0x04, 0x51, 0xfb, 0x79, 0x36, 0xdc, 0xf8, 0x17, 0xeb, 0x67, 0x42, 0xf9, 0x8d, 0xe7, 0xb6, 0x1c, 0x52, - 0x67, 0x2d, 0x7c, 0x61, 0x3c, 0x3c, 0xb8, 0x32, 0xb4, 0x1d, 0x0e, 0x42, 0xff, 0x6d, 0xd6, 0x08, 0x6e, 0x6c, 0x68, - 0x9f, 0x2f, 0x7c, 0xd8, 0xda, 0x68, 0xac, 0x29, 0xa6, 0x5b, 0xe8, 0xdf, 0x64, 0xb6, 0xb4, 0xa7, 0x51, 0xc9, 0x8b, - 0x53, 0xd3, 0x88, 0x85, 0x30, 0x60, 0xe8, 0x27, 0xf3, 0x01, 0x54, 0x73, 0xc7, 0x23, 0x90, 0xc9, 0x07, 0x7a, 0xb0, - 0x26, 0xb5, 0xea, 0xaf, 0x61, 0x26, 0xff, 0x8f, 0x54, 0x58, 0x8c, 0xee, 0xb6, 0x61, 0xa6, 0xfe, 0x88, 0xe4, 0x1f, - 0x2c, 0xe7, 0xbb, 0xd4, 0x0b, 0xb5, 0x1f, 0x0b, 0x2b, 0x30, 0x28, 0x51, 0x35, 0xa0, 0x07, 0x22, 0xa8, 0xca, 0x20, - 0xcd, 0xb0, 0x3a, 0x07, 0xfd, 0xee, 0x69, 0xd5, 0x91, 0x1c, 0xd2, 0x5a, 0x0d, 0xa9, 0x60, 0xaa, 0xd4, 0x20, 0x3f, - 0x1c, 0xee, 0x52, 0xa6, 0xcb, 0x80, 0x4b, 0xfa, 0x5d, 0xaa, 0x94, 0xc2, 0x7f, 0x22, 0x00, 0x9d, 0x83, 0x7b, 0x7c, - 0x39, 0x06, 0xd2, 0x0c, 0x0b, 0xbf, 0x35, 0x3b, 0xbe, 0x26, 0xe1, 0x36, 0x09, 0x2e, 0x06, 0x38, 0x47, 0x57, 0x61, - 0x79, 0x97, 0x42, 0x04, 0x55, 0x09, 0xf5, 0xad, 0x4c, 0x83, 0xd2, 0x56, 0x83, 0xb0, 0x26, 0xa1, 0xce, 0x24, 0x1b, - 0x95, 0xb6, 0x1b, 0x85, 0xd9, 0x22, 0xae, 0x67, 0x84, 0x35, 0x67, 0x33, 0xd5, 0xc0, 0xa4, 0xe1, 0xb8, 0x69, 0xb4, - 0x16, 0x15, 0x6a, 0x0a, 0xf3, 0x1a, 0x57, 0x95, 0xaa, 0xee, 0xe6, 0xd4, 0x52, 0x5a, 0xb6, 0x57, 0xdd, 0x24, 0x1b, - 0x72, 0x19, 0xca, 0x30, 0xd8, 0xc8, 0x11, 0x4c, 0x20, 0x49, 0xce, 0xfc, 0x8d, 0xfc, 0x43, 0x6d, 0xba, 0x16, 0x30, - 0xc7, 0x98, 0x65, 0xc3, 0x82, 0x5e, 0x81, 0x7b, 0xa0, 0x95, 0x9e, 0x4f, 0xb3, 0x8b, 0x3c, 0x48, 0x86, 0x85, 0x5e, - 0x36, 0x19, 0xff, 0x53, 0x18, 0x69, 0x32, 0x63, 0x25, 0x8b, 0x6c, 0x57, 0xa7, 0xc4, 0x79, 0x9c, 0xc0, 0xf6, 0x68, - 0x7a, 0xcb, 0xf7, 0x19, 0x44, 0x05, 0x81, 0x82, 0x19, 0xf3, 0x65, 0x17, 0xcf, 0x7d, 0x9f, 0x59, 0xa6, 0xee, 0xc3, - 0xc1, 0x98, 0xb1, 0xfd, 0x7e, 0x3f, 0xef, 0xf7, 0xd5, 0x7c, 0xeb, 0xf7, 0x93, 0x17, 0xe6, 0x6f, 0x0f, 0x18, 0x14, - 0xe4, 0x44, 0x34, 0x15, 0x22, 0xf8, 0x87, 0xe4, 0x19, 0x92, 0xd1, 0x1d, 0xf7, 0xb9, 0xe5, 0x6c, 0x59, 0x1d, 0x81, - 0x60, 0x1e, 0x0e, 0x97, 0x0a, 0xec, 0x5a, 0xa2, 0x48, 0xc8, 0xf2, 0x9f, 0x81, 0xf1, 0xcc, 0x7d, 0x80, 0x25, 0x03, - 0x10, 0xb6, 0xca, 0xd3, 0xf5, 0x9e, 0xaf, 0x82, 0x77, 0x3a, 0xde, 0x35, 0x56, 0x64, 0x20, 0x6e, 0x81, 0x8d, 0x58, - 0x6b, 0x0f, 0xc8, 0x99, 0x02, 0x1c, 0x2f, 0x0e, 0x87, 0x73, 0xf9, 0x4b, 0x37, 0x5b, 0x27, 0x50, 0x29, 0x70, 0x7b, - 0x74, 0x72, 0xf0, 0xdf, 0x81, 0x66, 0x50, 0x0e, 0xf3, 0x7a, 0xfb, 0x3b, 0x73, 0xf2, 0xd3, 0x53, 0xfc, 0x13, 0x1e, - 0xa2, 0xd3, 0x6f, 0xf7, 0xe6, 0x0f, 0x8a, 0xca, 0xc3, 0x41, 0x2d, 0xfe, 0x73, 0xce, 0x2b, 0xf8, 0x85, 0x6f, 0x02, - 0xb3, 0xc9, 0xd4, 0x3b, 0xf9, 0x26, 0xcf, 0x99, 0x7a, 0x8d, 0x57, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xed, - 0xc8, 0x89, 0x76, 0xca, 0x31, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, - 0x96, 0x78, 0x96, 0xce, 0x2f, 0x27, 0x75, 0xb9, 0xd3, 0x8a, 0xa7, 0x3d, 0xb0, 0xb8, 0xad, 0xc1, 0x0b, 0xe0, 0xde, - 0x62, 0xeb, 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, - 0x40, 0x30, 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, - 0x77, 0xf9, 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0x65, 0x6f, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, - 0x52, 0x3c, 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfc, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xbd, 0x7d, - 0x72, 0x61, 0x20, 0x81, 0xa6, 0x03, 0xf0, 0xe3, 0x55, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, - 0x05, 0xf7, 0xe9, 0x67, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa3, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x3c, - 0xfb, 0xa6, 0x02, 0x72, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, - 0x53, 0x71, 0x75, 0xa9, 0xd3, 0xc5, 0x8b, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, - 0x07, 0xf1, 0xb6, 0xb6, 0xa3, 0x3f, 0x76, 0x10, 0xe9, 0xb8, 0x27, 0x17, 0xea, 0x4b, 0x48, 0x25, 0x17, 0xea, 0x06, - 0x62, 0x17, 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0x75, 0x8d, 0x82, 0x95, 0x80, 0x33, 0xed, 0x1a, 0x0c, 0x36, 0xb0, - 0x6e, 0x59, 0x06, 0x7f, 0xc3, 0x35, 0x4d, 0xe0, 0x86, 0x45, 0xd6, 0x7b, 0x83, 0xad, 0x74, 0x0d, 0x8e, 0x96, 0x89, - 0x73, 0x29, 0xc9, 0xca, 0x16, 0x19, 0x57, 0x8f, 0x42, 0xaa, 0xa6, 0xfb, 0x5b, 0x51, 0x3f, 0x08, 0x91, 0x07, 0xab, - 0x94, 0x45, 0xc5, 0x0a, 0x64, 0xf6, 0xe0, 0x1f, 0x21, 0x23, 0x47, 0x39, 0x70, 0x14, 0xfa, 0x5b, 0x13, 0xe8, 0x3c, - 0x3f, 0x85, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, - 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, - 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, - 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, - 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, - 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, - 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, - 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, - 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, - 0x74, 0xe9, 0x7e, 0x66, 0xc7, 0x5d, 0xe8, 0x0e, 0xb0, 0xf1, 0xb6, 0x41, 0x47, 0xfe, 0xf5, 0x0e, 0x29, 0x75, 0x93, - 0x01, 0xd8, 0x8d, 0x06, 0x38, 0x64, 0xaa, 0x97, 0x22, 0xab, 0x97, 0x32, 0xd5, 0x4b, 0xb2, 0x72, 0x09, 0x16, 0x12, - 0x53, 0xe5, 0x36, 0xb2, 0x72, 0xcb, 0x86, 0xeb, 0xe1, 0x60, 0x6b, 0xc5, 0x65, 0x73, 0x07, 0xf7, 0x85, 0x15, 0x05, - 0xfe, 0xdf, 0xb2, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x35, 0x3a, 0x26, 0xc1, 0x05, 0xe2, 0x9e, 0xdd, 0x82, 0x1d, 0x16, - 0xfe, 0x82, 0xeb, 0xe4, 0x98, 0xed, 0xf0, 0x51, 0xe8, 0x15, 0xec, 0xd6, 0x27, 0xa0, 0x5d, 0xb0, 0x35, 0x40, 0x36, - 0xb6, 0xc5, 0x47, 0x77, 0x87, 0xc3, 0xb5, 0xe7, 0xb3, 0x07, 0xfc, 0x71, 0x7e, 0x77, 0x38, 0xec, 0x3c, 0xa3, 0xde, - 0xbb, 0xe1, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xcd, 0x15, 0x8f, 0x27, 0x83, 0xc1, 0x8d, 0xbf, 0xe0, 0xf5, 0xec, 0x06, - 0xb4, 0x03, 0xe7, 0x0b, 0xa9, 0x6b, 0xf6, 0x6e, 0x79, 0xe6, 0x2d, 0x70, 0x6c, 0x6e, 0xe1, 0xe8, 0xed, 0xf7, 0xbd, - 0x3b, 0x1e, 0x79, 0xb7, 0xa4, 0x62, 0x5a, 0x71, 0xc5, 0xf1, 0xb6, 0xc5, 0xfd, 0x74, 0xc5, 0x43, 0x78, 0x84, 0x55, - 0x99, 0xde, 0x04, 0xef, 0x7d, 0xb6, 0xd2, 0x2c, 0x70, 0x0f, 0x98, 0x63, 0x4d, 0x76, 0x42, 0x33, 0xf1, 0x57, 0xd8, - 0x3f, 0x37, 0xaa, 0x7f, 0x68, 0xfe, 0x97, 0xba, 0x9f, 0xc0, 0xed, 0x8b, 0x2c, 0x48, 0xec, 0x3d, 0xbf, 0x61, 0xf7, - 0xdc, 0xb0, 0xcd, 0x9e, 0x99, 0xb2, 0x4f, 0x94, 0x1a, 0x3f, 0x52, 0xea, 0xda, 0x32, 0xac, 0x64, 0xee, 0xbe, 0x8c, - 0xc0, 0xe1, 0x80, 0xfc, 0x74, 0x87, 0x38, 0x08, 0xad, 0x9b, 0xac, 0xe6, 0x8a, 0x72, 0x2e, 0xb4, 0x65, 0xe6, 0xe5, - 0xc0, 0x62, 0x96, 0x52, 0x68, 0x2c, 0x00, 0x10, 0x4c, 0x0a, 0xad, 0xbd, 0x97, 0x01, 0xe4, 0x04, 0x0d, 0x7f, 0x6c, - 0xae, 0x8a, 0xb2, 0x96, 0x2d, 0x09, 0x51, 0xb6, 0xeb, 0xe1, 0x25, 0x42, 0xa6, 0xf5, 0xfb, 0xe7, 0x44, 0xb2, 0x36, - 0xa9, 0xae, 0x6a, 0xb4, 0x04, 0x54, 0x64, 0x09, 0x98, 0xf8, 0x95, 0xe6, 0x13, 0x80, 0x27, 0x1d, 0x0f, 0xaa, 0xa7, - 0xbc, 0x66, 0x82, 0xc8, 0x36, 0x2a, 0x7f, 0x52, 0xbc, 0x40, 0x32, 0x82, 0xe2, 0x69, 0xad, 0x32, 0x16, 0x86, 0x79, - 0xa0, 0x80, 0xbc, 0x7b, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, - 0xe8, 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x39, 0x89, 0xae, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, - 0x67, 0xd1, 0xd3, 0x6a, 0x3e, 0x21, 0x25, 0xd9, 0xe1, 0x90, 0x8d, 0xaa, 0xba, 0x58, 0x4f, 0x43, 0xf9, 0xd3, 0x43, - 0xf0, 0xf5, 0x82, 0x7a, 0x4d, 0x56, 0xa9, 0x7e, 0x4a, 0x95, 0xf2, 0xa2, 0xe1, 0xa5, 0xff, 0xb4, 0x92, 0xfb, 0x1e, - 0x90, 0xd6, 0xf2, 0x92, 0xcb, 0xf7, 0x23, 0xc4, 0x18, 0xf1, 0x03, 0xaf, 0xe4, 0x11, 0x0b, 0xd5, 0x14, 0xae, 0x79, - 0x84, 0x20, 0x6f, 0x99, 0x0e, 0xfe, 0xd6, 0x13, 0xa7, 0xfb, 0x13, 0xa5, 0x5d, 0x7c, 0x61, 0x51, 0xf7, 0x64, 0x6d, - 0xdd, 0x80, 0x1c, 0x6c, 0x98, 0x2e, 0x0a, 0xb2, 0x4d, 0x69, 0x04, 0x6d, 0xb4, 0x1c, 0xd8, 0x70, 0x2a, 0xb5, 0xe1, - 0xcc, 0x35, 0x04, 0xf7, 0xf9, 0x79, 0x3a, 0x5a, 0xc0, 0x87, 0x54, 0xb7, 0x97, 0xf8, 0xf9, 0xb0, 0xe1, 0x11, 0x90, - 0xd9, 0x11, 0x9f, 0xd9, 0x44, 0xd2, 0x49, 0x9d, 0x2b, 0x60, 0xb7, 0xb3, 0x6b, 0x90, 0x23, 0x66, 0xee, 0x2b, 0x54, - 0xdf, 0xa2, 0x01, 0x57, 0xc6, 0xda, 0xd7, 0x24, 0x63, 0xe1, 0x55, 0x39, 0x0d, 0x07, 0x00, 0x43, 0x97, 0xd1, 0xd7, - 0x96, 0x9b, 0x2c, 0xfb, 0xb9, 0x80, 0x20, 0x88, 0x92, 0x78, 0x7c, 0xc0, 0xfb, 0xb2, 0x1a, 0x6a, 0x94, 0x7c, 0x2c, - 0x1b, 0xa9, 0xf4, 0x4a, 0xf4, 0x77, 0x63, 0x2e, 0x31, 0xe0, 0x75, 0xd5, 0x16, 0x14, 0xce, 0xf3, 0xc3, 0xe1, 0x3c, - 0x1f, 0x19, 0xcf, 0x32, 0x50, 0xad, 0x4c, 0xeb, 0x20, 0x36, 0xf3, 0xc5, 0xc2, 0x5f, 0xec, 0x9c, 0x44, 0x44, 0x41, - 0x60, 0x47, 0xc2, 0x83, 0x48, 0xfd, 0xaa, 0xf2, 0x74, 0xa7, 0xfa, 0x6c, 0xbf, 0xb0, 0x89, 0xf4, 0x82, 0x92, 0xc9, - 0x27, 0xc1, 0x5e, 0xf5, 0x77, 0x10, 0x36, 0x84, 0x37, 0xaf, 0x7a, 0x9d, 0x65, 0x6a, 0x56, 0x82, 0x84, 0x19, 0x73, - 0x04, 0x8f, 0xc3, 0x4e, 0x63, 0x1b, 0x1e, 0x5b, 0x70, 0x74, 0xde, 0x9a, 0xdd, 0xb1, 0x15, 0xbb, 0x55, 0x75, 0x5a, - 0xf0, 0x70, 0x3a, 0xbc, 0x0c, 0x70, 0xf5, 0xad, 0xcf, 0x39, 0xbf, 0xa3, 0x13, 0x6c, 0x3d, 0xe0, 0xd1, 0x44, 0xcc, - 0xd6, 0x4f, 0x23, 0xb5, 0x78, 0xd6, 0x43, 0xbe, 0xa0, 0xf5, 0x27, 0x66, 0x77, 0x26, 0xf9, 0x6e, 0xc0, 0x17, 0x93, - 0xf5, 0xd3, 0x08, 0x5e, 0x7d, 0x0a, 0x56, 0x8c, 0xcc, 0x99, 0x65, 0xeb, 0xa7, 0x11, 0x8e, 0xd9, 0xdd, 0xd3, 0x88, - 0x46, 0x6d, 0x25, 0xf7, 0xa5, 0xdb, 0x06, 0x84, 0x95, 0x5b, 0x16, 0xc3, 0x6b, 0x20, 0x9e, 0x69, 0x23, 0xe9, 0x5a, - 0x1a, 0x7a, 0x63, 0x1e, 0x4e, 0xe3, 0x60, 0x4d, 0xad, 0x90, 0x67, 0x86, 0x98, 0xc5, 0x4f, 0xa3, 0x39, 0x5b, 0x61, - 0x45, 0x36, 0x3c, 0x1e, 0x5c, 0x4e, 0x36, 0x57, 0x7c, 0x0d, 0xe4, 0x67, 0x93, 0x8d, 0xd9, 0xa2, 0x6e, 0xb9, 0x98, - 0x6d, 0x9e, 0x46, 0xf3, 0xc9, 0x0a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x0d, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, - 0x3d, 0xb6, 0x1e, 0x07, 0x77, 0x6c, 0x7d, 0x19, 0xdc, 0xb2, 0xf5, 0x18, 0x88, 0x38, 0xa8, 0xdf, 0xbd, 0x0d, 0x2c, - 0xbe, 0x88, 0xad, 0x2f, 0x4d, 0xda, 0xe6, 0x69, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xc9, 0xbc, 0x15, 0x83, - 0x4b, 0xc8, 0xd2, 0x8b, 0xd9, 0x66, 0x78, 0xc9, 0xd6, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0xee, 0xf8, 0x2d, 0x4b, 0xf8, - 0xaa, 0x89, 0xaf, 0x36, 0xa0, 0x11, 0x3d, 0xca, 0xa0, 0xaf, 0xa0, 0x66, 0xe6, 0xbc, 0xb2, 0x30, 0x2a, 0xf7, 0x2d, - 0x38, 0xa0, 0x20, 0x6d, 0x03, 0x04, 0x49, 0x3c, 0xbb, 0x57, 0xe1, 0xfa, 0x46, 0x0a, 0x03, 0x6e, 0x02, 0x33, 0x60, - 0x60, 0xfa, 0x19, 0xfc, 0xb0, 0xd2, 0x25, 0x42, 0x9c, 0xfd, 0x94, 0x92, 0x64, 0x9e, 0x9f, 0x8a, 0x34, 0x77, 0x0b, - 0xd7, 0x29, 0xcc, 0x8a, 0x02, 0xd5, 0x4f, 0x49, 0x69, 0x60, 0xa1, 0x12, 0x99, 0x4a, 0xc1, 0x2f, 0x9b, 0xf3, 0x28, - 0x3b, 0x46, 0xe7, 0x3a, 0xbf, 0x9c, 0x38, 0xa7, 0x93, 0xbe, 0xff, 0xc0, 0x31, 0x6c, 0x21, 0x03, 0x17, 0xfe, 0xd4, - 0x13, 0xc6, 0xa9, 0x15, 0x88, 0xa9, 0xe4, 0xd9, 0x53, 0xf8, 0x4c, 0x68, 0x75, 0x74, 0xe1, 0xfb, 0x41, 0xa1, 0x4d, - 0xd2, 0x2d, 0x48, 0x52, 0xf0, 0x14, 0x3d, 0xe7, 0xbc, 0x0d, 0x54, 0x8a, 0x11, 0x2d, 0x88, 0xb4, 0xb5, 0xcc, 0x1c, - 0xa4, 0x2d, 0xcd, 0x77, 0x4d, 0xfc, 0x1c, 0x16, 0x70, 0x11, 0x2d, 0x6c, 0x0d, 0x8f, 0xaa, 0x58, 0xb9, 0x37, 0x79, - 0x8e, 0x70, 0x46, 0x97, 0x32, 0x01, 0x70, 0xbd, 0x5f, 0x87, 0xb5, 0xc2, 0x2b, 0x6a, 0x16, 0x79, 0x51, 0xd3, 0x27, - 0x5b, 0xe0, 0x3e, 0x16, 0x25, 0x0a, 0x9c, 0xb5, 0x60, 0xc0, 0x56, 0x58, 0xb2, 0x93, 0xc2, 0xa6, 0x68, 0x09, 0xbd, - 0x3d, 0x7e, 0x3a, 0xa8, 0x99, 0x0c, 0xa0, 0x09, 0xa0, 0xf1, 0xf8, 0x17, 0x80, 0x9a, 0xde, 0xd4, 0x62, 0x5d, 0x05, - 0xa5, 0x52, 0x6e, 0xc2, 0xcf, 0xc0, 0x30, 0xc3, 0x0f, 0x85, 0xdc, 0x26, 0x4a, 0xe4, 0xfc, 0x58, 0x94, 0x62, 0x59, - 0x8a, 0x2a, 0x69, 0x37, 0x14, 0x3c, 0x22, 0xdc, 0x06, 0x8d, 0x99, 0xdb, 0x13, 0x5d, 0xb4, 0x22, 0x94, 0x63, 0xb3, - 0x8e, 0x91, 0x46, 0x99, 0x9d, 0xec, 0x3a, 0x59, 0x68, 0xbf, 0xaf, 0x72, 0xc8, 0x3a, 0x60, 0x8d, 0xe4, 0xeb, 0x35, - 0x87, 0x6e, 0x1b, 0xe5, 0xc5, 0x83, 0xe7, 0x2b, 0x38, 0xcd, 0xf1, 0xc4, 0xee, 0x7a, 0xdd, 0x29, 0x12, 0xf1, 0x0a, - 0x27, 0x55, 0x3e, 0x92, 0x85, 0xe3, 0xce, 0x9d, 0xd6, 0x62, 0x55, 0xb9, 0xac, 0xa7, 0x16, 0x47, 0x04, 0x3e, 0x95, - 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, 0x11, - 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0x8b, 0x5c, 0x0f, - 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, 0x3c, - 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, 0x5d, - 0x28, 0xe7, 0x4c, 0xc5, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, 0x8c, - 0x8e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x96, 0xab, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, 0xc6, - 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, 0x98, - 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x7b, 0x59, 0x14, 0x38, 0x80, 0xab, - 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0xf6, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, 0xcc, - 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, 0xb4, - 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x8f, 0x5f, 0xa7, - 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7e, 0x41, 0x11, 0x17, 0x35, 0xb8, 0xf2, - 0x4e, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, 0x0e, - 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x44, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xcc, 0x59, 0x35, 0x5a, 0xa8, 0xcc, 0x08, - 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xe3, 0x3d, 0xba, 0xab, 0xce, 0x32, - 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, 0x77, - 0x9d, 0xe5, 0xab, 0x9b, 0xad, 0xa1, 0xa8, 0xd4, 0x4a, 0x52, 0x1c, 0x64, 0xb8, 0x6e, 0x2b, 0x1f, 0x2e, 0x2e, 0xa0, - 0x67, 0x8c, 0x44, 0xe6, 0xf9, 0x13, 0xf9, 0x12, 0x9c, 0x33, 0xce, 0x0a, 0x81, 0x09, 0x63, 0xf5, 0xae, 0xb5, 0x54, - 0x1a, 0x52, 0x8c, 0x1d, 0x8d, 0xb2, 0xac, 0xb2, 0x74, 0x99, 0xad, 0x25, 0x6c, 0x59, 0x4e, 0x6e, 0x61, 0xcb, 0x4c, - 0x56, 0xf3, 0x7d, 0xc5, 0x1d, 0x94, 0x6f, 0xb6, 0xce, 0xf8, 0x5e, 0x22, 0x7b, 0xb7, 0x81, 0x12, 0x5e, 0x8c, 0xfe, - 0x82, 0xf4, 0xdb, 0x0c, 0xe3, 0x94, 0xdb, 0x4a, 0x5a, 0x80, 0xd3, 0x3f, 0x1c, 0xde, 0x57, 0x18, 0x34, 0x38, 0xc2, - 0x38, 0xb2, 0x7e, 0xff, 0xb6, 0xf2, 0x6a, 0x4c, 0xd4, 0xf1, 0x59, 0xfd, 0x7e, 0x45, 0x0f, 0xa7, 0xd5, 0x68, 0x95, - 0x6e, 0x91, 0x9d, 0xd0, 0xc6, 0xca, 0x0f, 0x6a, 0x05, 0xcc, 0xde, 0xfa, 0x7c, 0x3a, 0x00, 0x1d, 0x0b, 0x90, 0x68, - 0x36, 0x13, 0x89, 0x39, 0xe9, 0x9e, 0x84, 0xc7, 0x07, 0x16, 0x38, 0xc0, 0x54, 0xfc, 0x9f, 0xc2, 0x9b, 0x81, 0x0d, - 0x1a, 0x25, 0xfa, 0x1a, 0x5d, 0xd5, 0xe6, 0x46, 0xc7, 0x4b, 0x4f, 0x21, 0x91, 0x15, 0xac, 0x9a, 0xfb, 0x72, 0x03, - 0xa7, 0x3d, 0xd4, 0x1c, 0x2a, 0x4b, 0xf0, 0xb7, 0x5f, 0xe6, 0x87, 0xc3, 0x3a, 0x83, 0xc2, 0x76, 0x6b, 0xa1, 0xbd, - 0x31, 0x4b, 0x35, 0x54, 0x84, 0x83, 0xce, 0x57, 0x62, 0x56, 0x8f, 0xe8, 0xef, 0xf9, 0xe1, 0xb0, 0x22, 0x30, 0xe0, - 0xb0, 0x94, 0x99, 0x68, 0xa1, 0x58, 0x5a, 0x67, 0x33, 0xaa, 0x03, 0x0f, 0x4c, 0xcc, 0x59, 0xb8, 0x03, 0xd0, 0x26, - 0xb5, 0x0a, 0xf4, 0x2a, 0xa2, 0x9f, 0xb8, 0x5f, 0xdb, 0xaf, 0xd7, 0x23, 0xb3, 0x74, 0xe4, 0xc6, 0x58, 0x00, 0x70, - 0xe0, 0x79, 0x4d, 0xf2, 0x9c, 0x7c, 0x0d, 0xed, 0x9e, 0x5c, 0xc8, 0x9f, 0xa0, 0x6c, 0xe1, 0xb9, 0x6a, 0x5a, 0x59, - 0xac, 0xb8, 0xaa, 0x5e, 0x5d, 0xf0, 0xca, 0x64, 0x5a, 0xa5, 0x95, 0xa8, 0x94, 0x60, 0x40, 0x5d, 0xe2, 0xb5, 0xa6, - 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x7e, 0x69, 0x1c, 0x3e, - 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0x2b, 0x1f, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, 0xc5, 0xc4, - 0xee, 0xd0, 0xbc, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, 0x01, 0x2f, - 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x2a, 0x26, 0xc0, 0x0f, - 0x4a, 0xad, 0xe9, 0xbd, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, 0xe7, 0xe3, - 0xf9, 0xa5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x79, 0xab, 0x7f, 0x98, 0xea, 0x5b, 0xe8, 0x4e, - 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, 0x1c, 0xec, - 0x0d, 0x70, 0xe2, 0x97, 0x87, 0x83, 0xb8, 0xca, 0x7d, 0x76, 0xde, 0x35, 0xb2, 0x72, 0x00, 0x2b, 0x88, 0x82, 0x71, - 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xd5, 0xf8, 0xf8, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0xe4, 0x4f, 0x9f, - 0x03, 0x69, 0x59, 0xbf, 0x1f, 0xbd, 0xb8, 0x9c, 0x3e, 0x1f, 0x46, 0x01, 0x38, 0x76, 0xd9, 0xcb, 0xcb, 0x98, 0xaf, - 0x2e, 0x99, 0x65, 0x0a, 0x8b, 0x7c, 0x33, 0xa0, 0xba, 0x64, 0xb5, 0x74, 0xbd, 0x02, 0x2c, 0x5d, 0x7e, 0xf3, 0x10, - 0xa6, 0x06, 0x34, 0xb2, 0xe6, 0xee, 0x34, 0xd7, 0x02, 0xa5, 0x9e, 0xf7, 0x33, 0x43, 0xbe, 0x2e, 0x83, 0xae, 0x20, - 0xdd, 0xf3, 0x88, 0xf4, 0x72, 0x2f, 0x9d, 0xee, 0xf7, 0xa5, 0x00, 0x4b, 0x7d, 0x29, 0x3e, 0x83, 0xc2, 0xa2, 0xf1, - 0x8d, 0x00, 0x6d, 0x0d, 0xd5, 0xb4, 0x57, 0x8a, 0xaa, 0x17, 0xf4, 0x4a, 0xf1, 0xb9, 0xa7, 0x87, 0xca, 0x7c, 0x59, - 0x3a, 0xfa, 0x9f, 0x50, 0x73, 0xc1, 0x09, 0x31, 0x13, 0x73, 0x00, 0x95, 0xa0, 0x8d, 0x6f, 0x75, 0xb4, 0xf1, 0xa9, - 0x5e, 0xc5, 0x4d, 0x9f, 0xd7, 0xd6, 0x32, 0x27, 0x84, 0x4d, 0xf7, 0x12, 0xa0, 0x22, 0xaf, 0x84, 0x47, 0xb0, 0xfc, - 0xf2, 0x87, 0x3c, 0x5d, 0x21, 0x5a, 0xc7, 0x3d, 0xcb, 0x5c, 0x1a, 0xfb, 0x37, 0x06, 0xd3, 0xd7, 0xb7, 0xdb, 0x22, - 0x3f, 0x35, 0x31, 0x61, 0x3d, 0x56, 0xf4, 0xcd, 0xbb, 0x70, 0x25, 0x50, 0xe0, 0x50, 0x22, 0xb1, 0x4d, 0x15, 0x8a, - 0x78, 0x90, 0xf4, 0xe9, 0xa2, 0xf5, 0x69, 0x80, 0xa9, 0xb5, 0x1c, 0x98, 0x43, 0xb8, 0x8a, 0x0b, 0x1f, 0x3d, 0x7d, - 0x8b, 0x59, 0x38, 0x9f, 0x78, 0x1f, 0xbd, 0x62, 0x64, 0x3e, 0xee, 0xa3, 0x52, 0x49, 0xff, 0x3c, 0x1c, 0x66, 0xd5, - 0xdc, 0x77, 0xe8, 0x23, 0x3d, 0x54, 0xb9, 0xa0, 0xec, 0x8d, 0x31, 0x89, 0x40, 0x69, 0x8c, 0xf7, 0x71, 0x70, 0x9c, - 0xf7, 0x69, 0x00, 0xa9, 0x7d, 0xe2, 0x3d, 0x29, 0x39, 0x3c, 0xe7, 0x98, 0x13, 0x4a, 0x2b, 0xc2, 0x2a, 0xbe, 0xc8, - 0x50, 0xae, 0x3b, 0xa5, 0x60, 0x92, 0x43, 0x82, 0xe1, 0xaf, 0x9a, 0x37, 0xb1, 0x02, 0x61, 0xd7, 0xcc, 0xab, 0xd1, - 0x93, 0x2a, 0x09, 0x4b, 0x01, 0x47, 0x65, 0xe6, 0x19, 0xf6, 0x86, 0x27, 0x86, 0x91, 0x83, 0xe5, 0xfe, 0xa8, 0x4e, - 0x44, 0xee, 0xd1, 0x05, 0x46, 0x65, 0xe1, 0x79, 0x43, 0x57, 0x1a, 0x54, 0x92, 0x1d, 0x7f, 0xc5, 0x35, 0xa0, 0xb6, - 0xc6, 0x88, 0xa1, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, 0x95, 0xdc, 0xf5, - 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, 0x2c, 0x85, 0x23, - 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, 0x42, 0x9a, 0x6c, - 0x5f, 0xcf, 0xdf, 0x1b, 0x41, 0x56, 0x6e, 0x39, 0xc7, 0xc3, 0xe2, 0x1b, 0x67, 0x5f, 0xe5, 0xe4, 0x29, 0x66, 0x19, - 0xe9, 0x9d, 0x62, 0x5e, 0xc0, 0x9f, 0xca, 0x52, 0x9f, 0xa3, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, 0x97, 0xde, 0xa6, - 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0xf7, 0xf1, 0x48, 0x9e, 0x61, 0x1b, 0x96, 0xb0, 0xd0, 0x2a, 0x18, 0x03, 0x48, - 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x0e, 0x87, 0xf3, 0x8d, 0x39, 0x4b, 0xf6, 0xe0, 0xfa, 0xca, 0x13, 0xf3, 0x0e, - 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x1b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, 0x62, 0xad, 0x63, - 0xa9, 0xac, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0xbf, 0x77, 0x83, 0xab, 0x6b, 0x63, 0x50, - 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0xb3, 0x9c, 0x7c, 0xf9, 0xad, 0x9d, 0x03, 0x82, - 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, 0x33, 0xd8, 0xc4, - 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, 0xab, 0x85, 0x48, - 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, 0x5e, 0x27, 0x68, - 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, 0x7b, 0x99, 0x13, - 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, 0x74, 0x28, 0x59, - 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, 0x0a, 0x5c, 0x08, - 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xf9, 0xb4, 0x90, 0xa6, 0x81, 0x7c, 0x5a, 0x39, 0xe6, - 0x81, 0x9d, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0xe5, 0x1c, 0xab, 0x88, 0xde, 0xe7, 0x1f, 0x2a, 0x7b, - 0xfa, 0x20, 0xc2, 0x46, 0x05, 0x1a, 0x4b, 0x89, 0xb1, 0x91, 0xe3, 0xdf, 0x12, 0x65, 0x43, 0x86, 0x80, 0x10, 0xd2, - 0x46, 0x4e, 0x3f, 0xac, 0x2f, 0x6f, 0x33, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, 0xa9, 0x47, 0x3c, - 0x5e, 0x6b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, 0x28, 0x17, 0x3c, - 0xe7, 0x15, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xc8, 0xe9, 0xf3, 0x15, 0xf0, 0x4c, 0x40, 0xa0, 0x63, - 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0x37, 0x48, 0x94, 0xfa, 0x9a, - 0x94, 0xa4, 0xd7, 0xa2, 0xc6, 0x2b, 0xb1, 0x8a, 0x48, 0x20, 0x43, 0x0d, 0x11, 0xab, 0xea, 0xa9, 0x7b, 0x55, 0x4c, - 0x06, 0x83, 0xca, 0x97, 0xd3, 0x13, 0x6f, 0x68, 0xa8, 0xbc, 0xeb, 0x8a, 0x76, 0x7a, 0xa2, 0x95, 0xf2, 0x16, 0xd2, - 0x12, 0x34, 0x0d, 0x23, 0xcd, 0xa1, 0xd4, 0x95, 0x74, 0x37, 0x06, 0xf1, 0x25, 0x13, 0x3d, 0xdb, 0xa9, 0x1d, 0xa5, - 0x2d, 0x69, 0x0f, 0x21, 0x3d, 0x77, 0xc9, 0xc7, 0x2c, 0xe4, 0xea, 0x4e, 0x39, 0x29, 0xaf, 0x42, 0x74, 0x72, 0xdf, - 0x63, 0x48, 0x04, 0xfa, 0x9c, 0x63, 0x58, 0x17, 0x0d, 0x75, 0x0e, 0x2b, 0xc4, 0x6c, 0xa1, 0x84, 0xf9, 0x92, 0xf1, - 0x54, 0x32, 0x68, 0x00, 0x64, 0xc0, 0x67, 0x2f, 0x03, 0xcb, 0x5f, 0x41, 0xfc, 0x68, 0xe3, 0xc3, 0xe1, 0xcf, 0x9a, - 0x42, 0x6c, 0xff, 0x84, 0xcd, 0x10, 0x1e, 0xd5, 0x03, 0x9e, 0xf9, 0x26, 0x4e, 0xd0, 0x0a, 0x48, 0xca, 0xec, 0x68, - 0x22, 0x7b, 0xd5, 0x43, 0x38, 0x95, 0x15, 0xa8, 0xa3, 0xac, 0xb3, 0x12, 0x7e, 0x84, 0xa9, 0x6e, 0x25, 0xd6, 0x02, - 0x6d, 0xae, 0x56, 0xac, 0x05, 0x70, 0xe0, 0xe7, 0x10, 0x3c, 0x91, 0xcf, 0xc1, 0xc5, 0xa0, 0x00, 0x9f, 0x03, 0xe0, - 0x45, 0xee, 0xc2, 0x83, 0x79, 0x64, 0x59, 0x8d, 0x30, 0x1c, 0x55, 0xc4, 0xfa, 0x35, 0xdb, 0x91, 0x0f, 0xdc, 0x8e, - 0xf1, 0xb9, 0xf6, 0x58, 0xb2, 0x1c, 0x8c, 0x32, 0xf7, 0x6a, 0x89, 0x9e, 0x37, 0x69, 0xdc, 0x8c, 0x9e, 0xec, 0x6b, - 0xf9, 0xbf, 0xa0, 0x97, 0x41, 0x7f, 0x0b, 0xb7, 0xbc, 0xe6, 0x77, 0x0b, 0x22, 0xcd, 0xf4, 0x0a, 0x22, 0x65, 0xd4, - 0x88, 0x8c, 0x21, 0x6c, 0x52, 0xdd, 0xdc, 0x26, 0xd5, 0x85, 0x80, 0xa7, 0x23, 0x52, 0x5d, 0x0b, 0x69, 0x23, 0x9f, - 0xd6, 0x81, 0x8c, 0x45, 0x7a, 0xf7, 0xc3, 0xdf, 0x5e, 0x7e, 0x7a, 0xfb, 0xcb, 0x0f, 0x8b, 0xb7, 0xef, 0xde, 0xbc, - 0x7d, 0xf7, 0xf6, 0xd3, 0x6f, 0x04, 0xe1, 0x31, 0x15, 0x2a, 0xc3, 0x87, 0xf7, 0x37, 0x6f, 0x9d, 0x0c, 0xb6, 0x37, - 0x43, 0xd6, 0xbe, 0x91, 0x83, 0x21, 0x10, 0xd9, 0x20, 0x64, 0x90, 0x9d, 0xda, 0xf6, 0x67, 0x62, 0x8e, 0xb1, 0x77, - 0x02, 0x93, 0x2d, 0xe0, 0x1c, 0xcb, 0xbc, 0x64, 0x44, 0xae, 0x0a, 0xad, 0x1f, 0xd0, 0x82, 0x6b, 0x70, 0x91, 0x49, - 0xf3, 0xbb, 0x5f, 0x08, 0x62, 0x9f, 0x56, 0x52, 0xee, 0xab, 0x6d, 0xcd, 0xf3, 0xed, 0xfd, 0x5e, 0xc2, 0xf9, 0xcf, - 0xa5, 0x11, 0xb5, 0x00, 0x07, 0xe0, 0x73, 0xf8, 0xe3, 0x4a, 0x5b, 0xd2, 0x64, 0x16, 0xed, 0x67, 0x0c, 0x41, 0x97, - 0x06, 0x1f, 0xc4, 0x1e, 0x79, 0xa9, 0x4f, 0x16, 0x12, 0xb8, 0x23, 0x86, 0x4f, 0x2b, 0x82, 0x5e, 0x31, 0xa2, 0xb8, - 0xe4, 0x0a, 0x95, 0x52, 0xf2, 0x6f, 0x94, 0x5d, 0x54, 0xc8, 0x59, 0xc1, 0xee, 0x15, 0x39, 0x32, 0x7e, 0x10, 0x4c, - 0x7c, 0x39, 0xb8, 0xff, 0x12, 0xef, 0x70, 0xa6, 0x38, 0x92, 0x13, 0xfe, 0x90, 0x61, 0x60, 0x7f, 0x0e, 0x3e, 0xaf, - 0x0e, 0xf3, 0xf2, 0x46, 0x9f, 0x72, 0x4b, 0x3e, 0x9e, 0x2c, 0xaf, 0xc0, 0x60, 0xbf, 0x54, 0xcd, 0x5d, 0xf3, 0x7a, - 0xb6, 0x9c, 0xb3, 0xfd, 0x2c, 0x9a, 0x07, 0x77, 0x6c, 0x96, 0xcd, 0x83, 0x55, 0xc3, 0xd7, 0xec, 0x96, 0xaf, 0xad, - 0xaa, 0xad, 0xed, 0xaa, 0x4d, 0x36, 0xfc, 0x16, 0x24, 0x84, 0x9b, 0xcc, 0x03, 0xde, 0xe3, 0x3b, 0x9f, 0x6d, 0x40, - 0xa2, 0x5d, 0xb1, 0x0d, 0x5c, 0xc4, 0xd6, 0xfc, 0x87, 0xca, 0xdb, 0xb0, 0x92, 0x9d, 0x8f, 0x59, 0x8e, 0xf3, 0xcf, - 0x87, 0x07, 0xb4, 0x17, 0xea, 0x67, 0x97, 0xea, 0xd9, 0x44, 0xd9, 0xcd, 0x36, 0xa3, 0xc5, 0x7d, 0x5a, 0x6d, 0xc2, - 0x0c, 0x3d, 0xcb, 0xe1, 0xa3, 0xad, 0x14, 0xfc, 0xf4, 0x02, 0xbf, 0x64, 0x47, 0x6d, 0xa5, 0x6d, 0xbb, 0x2a, 0xb1, - 0x15, 0xb4, 0x28, 0xb2, 0x5a, 0xe1, 0x81, 0x39, 0x7f, 0x01, 0x0b, 0x18, 0x7b, 0x8e, 0x73, 0x5e, 0xfb, 0x23, 0x64, - 0xbc, 0x77, 0x00, 0xd0, 0x32, 0xc7, 0x01, 0x1e, 0xb1, 0x62, 0x14, 0x0d, 0xde, 0xf9, 0xa5, 0xb2, 0x5a, 0x69, 0x4e, - 0x42, 0xdb, 0x88, 0x55, 0xcb, 0x91, 0xaa, 0x19, 0x91, 0x3e, 0x48, 0xcf, 0xfb, 0x1e, 0x51, 0x0d, 0xf6, 0x64, 0x5e, - 0x07, 0xf6, 0xe9, 0x55, 0x6b, 0x55, 0x77, 0x7e, 0x4f, 0x95, 0x2e, 0x39, 0xb2, 0xe5, 0xa7, 0xcb, 0xf0, 0x41, 0xfd, - 0x29, 0xb9, 0x3e, 0x14, 0x38, 0xc2, 0x63, 0x15, 0x70, 0xbe, 0x5e, 0x89, 0x76, 0x27, 0xc2, 0xae, 0x5c, 0x02, 0x42, - 0x7c, 0x49, 0xd3, 0x1c, 0x8f, 0x23, 0x9a, 0x88, 0xb0, 0x89, 0xd1, 0x5f, 0xd8, 0x7d, 0x28, 0xb1, 0x9c, 0xe7, 0x1a, - 0x94, 0x5c, 0x32, 0x78, 0x4f, 0xda, 0x6b, 0xd0, 0x2c, 0xaf, 0x4a, 0x4d, 0x26, 0x72, 0x50, 0x3e, 0x1c, 0x0a, 0xd8, - 0x4b, 0x8d, 0x9f, 0x26, 0xfc, 0x84, 0xe5, 0xad, 0xbd, 0x35, 0xa5, 0xa8, 0xa4, 0x01, 0x2a, 0xf0, 0x31, 0x83, 0xff, - 0xdd, 0x19, 0x62, 0xc1, 0x14, 0x1d, 0x3f, 0x9c, 0x89, 0xb9, 0xf5, 0xdc, 0x2a, 0xeb, 0x28, 0x5b, 0xa3, 0x9c, 0x80, - 0x7f, 0x4b, 0x75, 0x9c, 0x24, 0xc2, 0xa9, 0xf7, 0x88, 0x8b, 0xba, 0x97, 0x43, 0xd4, 0x0d, 0x7b, 0x5b, 0xe9, 0x60, - 0xcb, 0x69, 0x1a, 0x1c, 0x89, 0x5f, 0xa9, 0xcf, 0xde, 0x67, 0x16, 0x8f, 0x3a, 0xb2, 0x11, 0x25, 0x69, 0x1c, 0x8b, - 0x1c, 0xb6, 0xf7, 0x85, 0xdc, 0xff, 0xfb, 0x7d, 0x08, 0x27, 0xad, 0x82, 0xa4, 0xf4, 0x04, 0x22, 0xc2, 0xd1, 0xe1, - 0x47, 0x84, 0x27, 0x52, 0x55, 0xf8, 0xa4, 0x3e, 0x71, 0x63, 0x76, 0x2f, 0xcc, 0x51, 0xbd, 0x05, 0x18, 0xc6, 0x7a, - 0x6b, 0x11, 0x92, 0x68, 0xa5, 0x19, 0x6d, 0x3d, 0x20, 0x46, 0xbc, 0x5f, 0x5b, 0x64, 0x30, 0xd6, 0x96, 0x44, 0x02, - 0xf8, 0x1d, 0x09, 0x19, 0xda, 0x36, 0x02, 0x33, 0x86, 0xb7, 0xb3, 0xe2, 0xd2, 0x75, 0xd8, 0xe6, 0x1c, 0xbe, 0x90, - 0x85, 0x66, 0x1d, 0x51, 0x9a, 0x20, 0xe4, 0x1f, 0x70, 0xb2, 0x50, 0x18, 0xcd, 0xeb, 0xa3, 0x74, 0x92, 0x58, 0xdf, - 0x77, 0x95, 0x0a, 0x36, 0x9b, 0x1b, 0xd4, 0x97, 0x1d, 0x25, 0xbf, 0x02, 0x27, 0x1d, 0x27, 0x59, 0xe4, 0x20, 0x6a, - 0x51, 0x39, 0x37, 0x49, 0x58, 0xda, 0xd5, 0xa9, 0x36, 0xeb, 0x75, 0x51, 0xd6, 0xd5, 0x6b, 0x11, 0x29, 0x7a, 0x1f, - 0xf5, 0xe8, 0x89, 0x84, 0x54, 0x68, 0x55, 0x6a, 0x97, 0x47, 0xe0, 0xb6, 0xa9, 0x15, 0xdb, 0x72, 0x09, 0x4b, 0xd4, - 0xf8, 0x4f, 0xd0, 0x47, 0xb9, 0x78, 0x90, 0x01, 0x1a, 0x1d, 0x4f, 0xcd, 0x5b, 0x8f, 0xbc, 0x72, 0x94, 0x5f, 0x5a, - 0x6d, 0xd2, 0x2f, 0x80, 0xcc, 0x68, 0xff, 0x68, 0x29, 0x81, 0xcc, 0xc0, 0x4c, 0x5a, 0x1a, 0x12, 0x39, 0x8a, 0x59, - 0x9a, 0xff, 0x81, 0x2b, 0xb6, 0x42, 0xa4, 0x61, 0x35, 0xf7, 0xf8, 0xcb, 0xca, 0xab, 0xe5, 0x5a, 0x66, 0x9a, 0x9b, - 0x25, 0x8e, 0x15, 0x8b, 0x8b, 0x7a, 0x5d, 0x89, 0x2c, 0x10, 0xe2, 0x08, 0xd3, 0x58, 0x4f, 0xbd, 0x51, 0x5a, 0x7d, - 0x40, 0x42, 0x99, 0x1f, 0xb0, 0xb7, 0x63, 0xaf, 0x07, 0x59, 0x88, 0x63, 0xcb, 0xc1, 0x66, 0xeb, 0x7d, 0x2a, 0x53, - 0x11, 0x9f, 0xd5, 0xc5, 0xd9, 0xa6, 0x12, 0x67, 0x75, 0x22, 0xce, 0xbe, 0x83, 0x9c, 0xdf, 0x9d, 0x51, 0xd1, 0x67, - 0x0f, 0x69, 0x9d, 0x14, 0x9b, 0x9a, 0x9e, 0xbc, 0xc1, 0x32, 0xbe, 0x3b, 0x23, 0xae, 0x9a, 0x33, 0x1a, 0xc9, 0x78, - 0x74, 0xf6, 0x21, 0x03, 0x92, 0xd7, 0xb3, 0x74, 0x05, 0x83, 0x77, 0x16, 0xe6, 0xf1, 0x59, 0x29, 0xee, 0xc0, 0xe2, - 0x54, 0x76, 0xbe, 0x07, 0x19, 0x56, 0xe1, 0x1f, 0xe2, 0x0c, 0xa0, 0x5d, 0xcf, 0xd2, 0xfa, 0x2c, 0xad, 0xce, 0xf2, - 0xa2, 0x3e, 0x53, 0x52, 0x38, 0x84, 0xf1, 0xc3, 0x7b, 0xfa, 0xca, 0x2e, 0x6f, 0xb3, 0xb8, 0xcb, 0x22, 0x7f, 0x8a, - 0x5e, 0x45, 0xc4, 0xa4, 0x51, 0x09, 0xaf, 0xdd, 0xdf, 0x36, 0xf7, 0x0f, 0xaf, 0x1b, 0xbb, 0x9f, 0xdd, 0x31, 0xa2, - 0x0b, 0xea, 0xf1, 0x4a, 0x52, 0x2a, 0x28, 0x20, 0x70, 0xa2, 0x59, 0xe3, 0xc1, 0x1d, 0x07, 0xbc, 0x1a, 0xd8, 0x92, - 0xad, 0x7d, 0xfe, 0x22, 0x96, 0x61, 0xda, 0x9b, 0x00, 0xff, 0x2a, 0x7b, 0xd3, 0x75, 0xb0, 0xc4, 0xfb, 0x16, 0xb2, - 0x0d, 0xbd, 0x7d, 0xcd, 0x5f, 0x7a, 0xb9, 0xfa, 0x9b, 0xfd, 0x13, 0x80, 0x30, 0x20, 0x66, 0xd5, 0x47, 0x13, 0xf7, - 0xce, 0xca, 0xb2, 0x73, 0xb2, 0xec, 0x7a, 0xe8, 0xd7, 0x24, 0x46, 0xa5, 0x95, 0xa5, 0x74, 0xb2, 0x94, 0x90, 0x05, - 0x7c, 0x62, 0x34, 0xb5, 0x11, 0x40, 0xd8, 0x8e, 0x52, 0xf9, 0x42, 0xe5, 0x45, 0x14, 0xce, 0x09, 0x9e, 0x27, 0x62, - 0x74, 0x6f, 0x25, 0x03, 0x86, 0x43, 0x08, 0xe6, 0xa0, 0x2d, 0xf6, 0x86, 0x6e, 0x22, 0xfe, 0x7a, 0x53, 0x94, 0x6f, - 0x63, 0xf2, 0x29, 0xd8, 0x9d, 0x7c, 0x5c, 0xc2, 0xe3, 0xf2, 0xe4, 0xe3, 0x10, 0x3d, 0x12, 0x4e, 0x3e, 0x06, 0xdf, - 0x23, 0x39, 0xaf, 0xbb, 0x1e, 0x27, 0xc8, 0x2d, 0xa4, 0xfb, 0xdb, 0x31, 0x09, 0xd0, 0xbc, 0x86, 0xe5, 0xa8, 0xa9, - 0xb8, 0x66, 0x66, 0x8c, 0xe7, 0x8d, 0xde, 0x1f, 0x3b, 0xde, 0x32, 0x85, 0x62, 0x16, 0xf3, 0x1a, 0x7e, 0xcf, 0xaa, - 0x40, 0xdd, 0xf5, 0x36, 0xc9, 0x2d, 0xb3, 0x7a, 0x8e, 0x76, 0xdf, 0xf7, 0x75, 0x22, 0xa8, 0xfd, 0x1d, 0xf6, 0x3c, - 0xb3, 0xde, 0x55, 0x31, 0x70, 0xa9, 0x92, 0x1d, 0x32, 0x55, 0x4d, 0x0f, 0x54, 0x4a, 0x83, 0xa7, 0x97, 0xd6, 0xe5, - 0x4b, 0xa5, 0x8d, 0x3c, 0xd3, 0xfc, 0x06, 0xf0, 0x62, 0xea, 0xb2, 0xd8, 0x7d, 0x75, 0x5f, 0xc1, 0x6d, 0xbc, 0xdf, - 0x5f, 0x56, 0x9e, 0xf9, 0x89, 0x0b, 0xc0, 0xde, 0x54, 0x68, 0x9d, 0x40, 0xa9, 0x61, 0x1d, 0xbe, 0x4a, 0x44, 0xf4, - 0x47, 0xbb, 0x5c, 0x67, 0xae, 0x03, 0x46, 0x14, 0xf1, 0xdb, 0x78, 0xf4, 0x07, 0x28, 0xae, 0x8d, 0x3d, 0x20, 0xac, - 0x43, 0x42, 0x9f, 0x11, 0x80, 0xd4, 0x63, 0x8e, 0x12, 0xd0, 0xac, 0x68, 0xee, 0x98, 0xfc, 0x5c, 0x5f, 0x29, 0xfd, - 0xfd, 0xb2, 0xf2, 0xc8, 0x9c, 0xd2, 0x36, 0xd3, 0x58, 0xad, 0xa9, 0x04, 0xc2, 0x2b, 0x2a, 0x59, 0x85, 0xcf, 0xe6, - 0x8d, 0xe8, 0xf7, 0xe5, 0x11, 0x9e, 0x56, 0x3f, 0x6c, 0x31, 0xbe, 0x15, 0x10, 0x8d, 0x04, 0x40, 0x3f, 0x01, 0xcc, - 0x8b, 0x6c, 0x66, 0xf7, 0x71, 0x40, 0x95, 0x12, 0x4d, 0xe3, 0x6c, 0x9e, 0xdf, 0xd2, 0x9b, 0xb2, 0x83, 0x4e, 0x9d, - 0x2a, 0x70, 0xc1, 0x55, 0xc9, 0x78, 0x65, 0x3d, 0x91, 0xcf, 0x6f, 0x6e, 0x37, 0x69, 0x16, 0xbf, 0x2f, 0xff, 0x89, - 0x63, 0xab, 0xeb, 0xf0, 0xc8, 0xd4, 0xe9, 0xda, 0x79, 0xa4, 0xb5, 0x17, 0x02, 0x22, 0xda, 0x35, 0xd4, 0x7a, 0x61, - 0xa1, 0x47, 0x7a, 0x22, 0x9c, 0x93, 0x44, 0x4d, 0x3b, 0xd0, 0xd2, 0x08, 0x7d, 0x7d, 0xcd, 0xe9, 0x2f, 0x0c, 0xd6, - 0x3e, 0x1f, 0x33, 0x20, 0x2b, 0xd1, 0x8f, 0xd5, 0x43, 0x63, 0x33, 0x87, 0x9e, 0xb5, 0x2a, 0xcf, 0xbc, 0xea, 0x70, - 0x40, 0x7c, 0x18, 0xfd, 0x25, 0xbf, 0xdf, 0x7f, 0x4d, 0xf3, 0x8f, 0x09, 0x35, 0x7e, 0xb6, 0x19, 0xa0, 0x6b, 0xdf, - 0x95, 0x07, 0xa2, 0x9e, 0x6b, 0x95, 0x20, 0xc4, 0x1b, 0xc4, 0x44, 0x33, 0x62, 0x0e, 0x4e, 0x3b, 0xd4, 0xfc, 0x93, - 0xd4, 0x80, 0x10, 0x25, 0x5e, 0xc7, 0x94, 0x05, 0x39, 0x6d, 0xe2, 0x48, 0x3f, 0x0a, 0x27, 0xf2, 0xa3, 0xa8, 0x8a, - 0xec, 0x1e, 0x2e, 0x18, 0x4c, 0xbd, 0xa7, 0xfd, 0x12, 0xfd, 0x96, 0x70, 0xe4, 0x1c, 0xad, 0x0a, 0x41, 0xe4, 0x84, - 0xb0, 0xd6, 0x10, 0x26, 0x88, 0x0d, 0xe2, 0x65, 0xdf, 0x25, 0x19, 0x8e, 0x14, 0x5c, 0xd6, 0xb1, 0x63, 0xcc, 0xd5, - 0x51, 0xf5, 0x1a, 0xc0, 0x78, 0xe5, 0x08, 0x9a, 0x8d, 0x22, 0xbb, 0x84, 0xa8, 0x22, 0xc7, 0x13, 0x50, 0x3b, 0x28, - 0x8d, 0xcd, 0xf4, 0x7c, 0x1c, 0xe4, 0xa3, 0x45, 0x85, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x73, 0xd5, 0xcf, - 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x8a, 0xe9, 0x72, - 0x60, 0xdc, 0x37, 0xbc, 0xa2, 0x38, 0xc3, 0x8f, 0x1e, 0x6c, 0x71, 0xfe, 0x74, 0x43, 0xed, 0xc7, 0xdc, 0xa8, 0x87, - 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, 0xfc, 0x43, - 0x99, 0xae, 0x52, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, 0xa2, 0xac, - 0xdf, 0x87, 0xdf, 0x57, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, 0x93, 0x41, - 0x0d, 0xda, 0xf0, 0x0d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, 0xec, 0x4f, - 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xe3, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xc7, 0x97, 0xfc, 0x06, 0xbd, - 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, 0x8f, 0x51, - 0xc9, 0x62, 0x4b, 0x8f, 0x55, 0xd1, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x05, 0xc1, 0x12, 0x18, - 0x17, 0xb1, 0xe6, 0x9b, 0x41, 0xce, 0xe2, 0xd9, 0x66, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1c, 0x0a, 0x09, 0x36, 0x93, - 0xcd, 0xd6, 0x73, 0xb6, 0xf6, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, 0x35, 0x58, - 0xad, 0xa6, 0x6c, 0x55, 0x53, 0x76, 0x4e, 0x53, 0x8e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, 0x88, 0x4d, - 0xa2, 0xab, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, 0x50, 0x85, - 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, 0xbe, 0xa5, - 0x8e, 0x7b, 0x94, 0x6d, 0xfe, 0x2e, 0x76, 0x41, 0x88, 0xdc, 0x8d, 0x3b, 0xf5, 0x33, 0xe2, 0xbd, 0xdd, 0x11, 0xc6, - 0x4f, 0x76, 0xdc, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8b, 0x79, 0x35, 0x49, 0x50, 0xcb, 0x92, 0xf8, 0x1b, - 0x9e, 0x0c, 0x72, 0xb6, 0x04, 0x0f, 0xda, 0x39, 0xcb, 0x00, 0x7f, 0xc5, 0x6a, 0xd1, 0x6f, 0xb5, 0xb7, 0x04, 0xf9, - 0x69, 0x63, 0x37, 0x0a, 0x13, 0x23, 0x48, 0xd4, 0xed, 0xca, 0x40, 0x7e, 0xf8, 0x80, 0xd3, 0xf1, 0xd8, 0x53, 0xc6, - 0xdc, 0xca, 0xf4, 0x32, 0x9d, 0x2b, 0xf9, 0x46, 0xee, 0xa5, 0x8f, 0xbd, 0x04, 0x3b, 0x07, 0xbc, 0x81, 0xb4, 0x81, - 0x37, 0xb0, 0x5d, 0x78, 0x6d, 0x90, 0x30, 0x23, 0xc0, 0x16, 0xc7, 0xc7, 0x48, 0x09, 0x0c, 0xe1, 0x38, 0x4b, 0x01, - 0x98, 0x46, 0x5f, 0x66, 0x2b, 0xfb, 0x32, 0xab, 0x35, 0x5b, 0x2a, 0xa7, 0x7b, 0xe7, 0xd6, 0xed, 0x7c, 0x22, 0x01, - 0xc0, 0xa4, 0xce, 0x81, 0x38, 0x33, 0xc1, 0x2e, 0x4d, 0x22, 0xcb, 0xc7, 0x30, 0xbf, 0x13, 0x6f, 0xca, 0x62, 0xa5, - 0xba, 0xa2, 0xed, 0x33, 0x93, 0xcf, 0x48, 0x27, 0xa1, 0x02, 0x0a, 0x0a, 0xb9, 0xd6, 0xa7, 0xef, 0xc2, 0x77, 0x41, - 0xa1, 0x81, 0xd9, 0x2a, 0xdc, 0xd3, 0x64, 0x8d, 0xd4, 0x1b, 0x55, 0xbf, 0x4f, 0xae, 0x81, 0x54, 0x67, 0x0e, 0x2d, - 0x7b, 0x52, 0x61, 0x80, 0xd8, 0x51, 0x9f, 0x91, 0x50, 0x07, 0x52, 0x0f, 0x18, 0x42, 0xb4, 0x4d, 0x1f, 0x7f, 0x32, - 0x24, 0xba, 0x00, 0x5b, 0x88, 0x36, 0xf0, 0xe3, 0x4f, 0xb0, 0xcf, 0x82, 0xf0, 0x98, 0xe6, 0xd7, 0x90, 0x74, 0x6c, - 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0xb9, 0x94, - 0xea, 0x58, 0xa9, 0xb7, 0x6d, 0xed, 0x07, 0xd1, 0x16, 0x1c, 0x59, 0xc4, 0xdf, 0x67, 0x88, 0x08, 0x66, 0x06, 0x11, - 0x76, 0x2d, 0xd4, 0xdd, 0x9e, 0x52, 0xcb, 0xa2, 0xde, 0xf6, 0x94, 0x52, 0xb7, 0x61, 0xf8, 0x6e, 0x82, 0x99, 0xe2, - 0x86, 0xff, 0x91, 0x79, 0xa1, 0xde, 0x78, 0x2c, 0x0a, 0x74, 0xcf, 0xdf, 0x2f, 0x79, 0x35, 0xdb, 0x28, 0x13, 0xe6, - 0x1d, 0x5f, 0xce, 0x42, 0xd9, 0xd5, 0xd2, 0xb8, 0xf3, 0xd9, 0x5b, 0xaa, 0xf9, 0xe0, 0x1f, 0x0e, 0x09, 0xc4, 0x1b, - 0xc5, 0x57, 0x77, 0x8d, 0xdc, 0xba, 0x26, 0x9b, 0xab, 0x12, 0x50, 0xbf, 0xcf, 0xd7, 0xb8, 0xdf, 0x62, 0xfd, 0xbb, - 0xa7, 0x41, 0xc6, 0x6a, 0x86, 0x2b, 0xa6, 0xf0, 0x29, 0x00, 0x0c, 0x0e, 0xa7, 0x82, 0xb4, 0xc0, 0x1b, 0x5e, 0x0e, - 0x2f, 0x27, 0x1b, 0x32, 0xe9, 0x6e, 0x7c, 0xe4, 0xce, 0x02, 0x55, 0xef, 0x37, 0x14, 0x27, 0x0d, 0x12, 0x8d, 0xbd, - 0x06, 0x5f, 0x66, 0x19, 0xe5, 0xa2, 0x89, 0xfb, 0x98, 0x7c, 0xa5, 0x07, 0x30, 0x57, 0xa1, 0x04, 0x88, 0x7e, 0x63, - 0x59, 0x6c, 0x44, 0xdb, 0x62, 0x03, 0x4b, 0xa9, 0x9a, 0xeb, 0xd5, 0xf4, 0xd9, 0x2b, 0xd1, 0xbc, 0x8f, 0x66, 0x9c, - 0xd2, 0x68, 0xc0, 0x71, 0x1a, 0x85, 0xdb, 0xf7, 0xf7, 0xa2, 0x5c, 0x66, 0x60, 0xc9, 0x56, 0xe1, 0x14, 0x97, 0x8d, - 0x3a, 0x23, 0x5e, 0xe6, 0xb1, 0x02, 0xe8, 0x78, 0x4c, 0x00, 0x54, 0x17, 0x04, 0x54, 0x44, 0x4b, 0xe9, 0xad, 0xd0, - 0x62, 0xa1, 0xde, 0x70, 0x94, 0xc2, 0x1f, 0xe9, 0xcf, 0x83, 0x7c, 0x0a, 0x40, 0xec, 0xfa, 0x38, 0x7a, 0x53, 0x94, - 0xf4, 0xa9, 0x62, 0x96, 0xcb, 0xc1, 0x04, 0x76, 0x75, 0x22, 0x43, 0xad, 0x20, 0x6f, 0xd5, 0x95, 0xb7, 0x32, 0x79, - 0x1b, 0xe3, 0x94, 0xfc, 0xc8, 0x4d, 0xc7, 0x1a, 0x31, 0xf0, 0xca, 0xd3, 0x3a, 0x4d, 0x90, 0x26, 0x17, 0xc0, 0x30, - 0xc4, 0xb7, 0x99, 0xf7, 0xd2, 0x73, 0xa4, 0x2a, 0x48, 0x66, 0xbb, 0xcc, 0x53, 0x17, 0x51, 0x7d, 0xe5, 0xd4, 0xd2, - 0x99, 0xd3, 0x8f, 0x00, 0xde, 0x63, 0x6a, 0xd2, 0x90, 0x8f, 0x70, 0x5b, 0x8a, 0xaf, 0xb7, 0xea, 0x1a, 0x2f, 0x8d, - 0xce, 0xdd, 0xcb, 0x97, 0xee, 0x34, 0xe8, 0xa7, 0x20, 0x28, 0xe7, 0xcb, 0x52, 0xc0, 0x9e, 0x32, 0x9b, 0xeb, 0xd5, - 0xaa, 0x15, 0x5a, 0x87, 0xc3, 0x58, 0x3b, 0x0a, 0x69, 0x75, 0x16, 0xb0, 0xd5, 0x48, 0xa7, 0x04, 0x08, 0xc1, 0x71, - 0x1a, 0x76, 0x82, 0x71, 0x97, 0x4e, 0x23, 0xb2, 0x5e, 0x29, 0x49, 0x17, 0x66, 0x90, 0xfc, 0x93, 0xbc, 0x9e, 0x01, - 0x2d, 0x01, 0x1c, 0x8a, 0x58, 0xc2, 0xc3, 0x49, 0x72, 0x05, 0xd0, 0xe9, 0x70, 0x50, 0x69, 0x68, 0xce, 0x6a, 0x96, - 0xcc, 0x27, 0xb1, 0x54, 0x55, 0x1e, 0x0e, 0x9e, 0x72, 0x33, 0xe8, 0xf7, 0xb3, 0x69, 0xa9, 0x5c, 0x00, 0x82, 0x58, - 0x17, 0x06, 0x88, 0x47, 0x5a, 0x78, 0xb2, 0xe8, 0x53, 0x12, 0xbf, 0x9c, 0x25, 0x73, 0x93, 0x0d, 0xef, 0xc0, 0x08, - 0x36, 0xe3, 0xba, 0xa4, 0x4c, 0x7b, 0x54, 0x7e, 0xcf, 0xe8, 0xa9, 0xed, 0x6b, 0xad, 0xb6, 0x88, 0x75, 0x1d, 0x5c, - 0x95, 0xa8, 0xa7, 0xf8, 0xa0, 0x24, 0xc1, 0xfb, 0xb5, 0x73, 0x33, 0x52, 0xbe, 0x16, 0xb9, 0x1f, 0xb4, 0x33, 0xb5, - 0x72, 0xe0, 0x08, 0xe4, 0x58, 0x45, 0x25, 0xaf, 0x77, 0x1d, 0x82, 0x47, 0x77, 0xa5, 0x02, 0xe5, 0xe0, 0x17, 0x20, - 0x46, 0xd7, 0x57, 0x9d, 0x35, 0xd4, 0x4c, 0xa3, 0xca, 0x23, 0xe8, 0xd4, 0x01, 0x3c, 0x29, 0x78, 0xa9, 0xd5, 0x8f, - 0x87, 0x83, 0x67, 0x7e, 0xf0, 0x57, 0x99, 0xbe, 0x85, 0x98, 0x28, 0xa7, 0x1a, 0x21, 0x71, 0xa5, 0x24, 0x11, 0x1f, - 0x2f, 0x5a, 0x56, 0x8c, 0xca, 0xf0, 0x81, 0x57, 0xaa, 0x7c, 0x75, 0xaa, 0xf2, 0x62, 0xa4, 0x6d, 0x09, 0xbc, 0x26, - 0xff, 0x10, 0xb9, 0xe6, 0xad, 0xaf, 0xbb, 0xca, 0xd0, 0x6b, 0x59, 0x81, 0x8e, 0x60, 0x2b, 0x4b, 0xc9, 0x01, 0x9f, - 0x54, 0x77, 0xd5, 0xaa, 0xf5, 0x39, 0x65, 0x1b, 0xe1, 0x26, 0xbf, 0x8e, 0x1d, 0x1c, 0x29, 0xbf, 0xc1, 0x73, 0x01, - 0xec, 0x35, 0x60, 0x6f, 0xce, 0x59, 0xd1, 0x3c, 0x3a, 0xa4, 0x6d, 0x81, 0x46, 0x66, 0x6e, 0xe7, 0xea, 0xbe, 0x2d, - 0x8f, 0xd2, 0x18, 0x22, 0xd3, 0x1e, 0x99, 0x0e, 0x36, 0xa3, 0xfc, 0xb7, 0x94, 0xdf, 0x2a, 0x1c, 0x03, 0xdf, 0x4e, - 0xbd, 0x03, 0xa8, 0x7a, 0xda, 0x20, 0x63, 0xcd, 0x30, 0xb4, 0xb2, 0xcb, 0xa5, 0xd0, 0x12, 0xb4, 0xd4, 0x4d, 0x10, - 0x9c, 0x1f, 0x11, 0xe5, 0x08, 0x40, 0x17, 0x29, 0x60, 0x82, 0x9f, 0xd2, 0x76, 0xf7, 0xfb, 0xeb, 0xd4, 0x23, 0xf7, - 0xae, 0x50, 0xa3, 0x84, 0x12, 0x8c, 0xfd, 0x44, 0x63, 0x06, 0x1d, 0x5d, 0x91, 0x13, 0x9e, 0xb5, 0x3a, 0xac, 0xeb, - 0xa6, 0x0c, 0xca, 0xe2, 0x98, 0x57, 0xd3, 0xd9, 0xef, 0x4f, 0xf6, 0x75, 0x83, 0x2c, 0xe4, 0xbf, 0xb3, 0x1e, 0x92, - 0x41, 0xf7, 0x20, 0x14, 0xa2, 0x37, 0x0f, 0x66, 0xf8, 0x1f, 0xdb, 0xf0, 0xec, 0x1b, 0x6e, 0xd4, 0x09, 0x60, 0x8e, - 0xb8, 0x5e, 0x7a, 0x8a, 0xb6, 0x1e, 0x6e, 0x81, 0x6c, 0x8d, 0x97, 0xb7, 0xf6, 0x1a, 0xc8, 0x29, 0x8e, 0xff, 0x8e, - 0x67, 0x6a, 0x65, 0x83, 0x9f, 0x9e, 0xb2, 0x1d, 0x78, 0x78, 0x11, 0x02, 0x8a, 0x61, 0xd9, 0xf8, 0x3b, 0xcb, 0x71, - 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, 0x5b, 0x79, 0x77, 0xe4, - 0x94, 0x79, 0xa7, 0x87, 0xd1, 0x75, 0x49, 0xfa, 0x26, 0xf9, 0xd8, 0x1a, 0xb6, 0xdf, 0xb5, 0xfb, 0xcd, 0x10, 0x41, - 0x08, 0xe5, 0xf8, 0x39, 0xa3, 0x13, 0x1a, 0x1f, 0x56, 0xb3, 0xd3, 0xeb, 0xf7, 0xce, 0xf1, 0x82, 0xad, 0xd1, 0x00, - 0x8f, 0x87, 0x2e, 0xe6, 0x89, 0x1a, 0x3a, 0x5d, 0xd7, 0xce, 0xc1, 0x03, 0x83, 0x2c, 0x4f, 0xbe, 0x61, 0x58, 0x62, - 0x7f, 0x12, 0xf1, 0xa4, 0xad, 0xda, 0xd8, 0x1c, 0xa9, 0x36, 0x6a, 0x06, 0x7e, 0xf0, 0x0a, 0x0a, 0x8c, 0x2e, 0x48, - 0x2b, 0x30, 0x0e, 0x47, 0x00, 0xb2, 0x62, 0x1c, 0x8f, 0x0c, 0x26, 0x30, 0xa4, 0x1b, 0x8a, 0x02, 0xf0, 0xf0, 0x38, - 0x1e, 0x84, 0x0c, 0x20, 0x5d, 0xf0, 0xd0, 0xb0, 0x4d, 0x42, 0xca, 0xcf, 0xf3, 0xbc, 0x56, 0x43, 0xe8, 0x3b, 0x0b, - 0xd5, 0xb1, 0x1f, 0x69, 0xaf, 0x58, 0xd7, 0xaa, 0x74, 0x64, 0xab, 0x03, 0xf4, 0x0d, 0x19, 0xf8, 0xd6, 0xb1, 0x05, - 0x40, 0xb4, 0xc4, 0x6f, 0xa9, 0x57, 0xfb, 0x32, 0x66, 0x85, 0x7a, 0x7d, 0x61, 0xda, 0xf5, 0x5a, 0x5a, 0x14, 0x50, - 0x71, 0xdb, 0xaa, 0xed, 0x91, 0x9c, 0xff, 0xf8, 0xae, 0xa3, 0x1d, 0x9f, 0x9d, 0x1a, 0x5b, 0x42, 0x99, 0x5b, 0x3c, - 0x91, 0xd5, 0xd1, 0x96, 0xea, 0x54, 0x1f, 0x70, 0xa9, 0x49, 0x75, 0x66, 0x60, 0x78, 0x8d, 0x00, 0xe5, 0x16, 0x22, - 0x69, 0x1c, 0xf6, 0xce, 0x27, 0x83, 0x82, 0xb9, 0x45, 0x02, 0x12, 0xd8, 0xc6, 0xd6, 0x2e, 0x9a, 0xeb, 0xd7, 0x6f, - 0xa9, 0x57, 0xb5, 0xa9, 0xea, 0xc1, 0x1b, 0x2f, 0x70, 0xf6, 0x4e, 0x6b, 0x01, 0x01, 0x14, 0xb6, 0x96, 0xe5, 0xe0, - 0xdc, 0xed, 0xaa, 0x96, 0x8a, 0x32, 0xea, 0xf7, 0xcf, 0x7f, 0x4b, 0x51, 0x11, 0x7b, 0xaa, 0x38, 0x65, 0xfd, 0x76, - 0xcb, 0x5c, 0x54, 0x96, 0xbc, 0x41, 0x15, 0xad, 0xd5, 0x51, 0x53, 0xb9, 0x6e, 0xae, 0x5a, 0x32, 0x41, 0x8c, 0xee, - 0xd3, 0xb5, 0xce, 0x9d, 0x7a, 0xef, 0x55, 0x1c, 0x31, 0x10, 0xdc, 0x74, 0x8f, 0x0f, 0x0e, 0x42, 0xa3, 0xa2, 0x5c, - 0x70, 0xa3, 0xb4, 0xaa, 0xa4, 0x14, 0xf2, 0x56, 0x45, 0x73, 0xa6, 0x8f, 0x00, 0x88, 0x00, 0xab, 0x44, 0xfd, 0x1f, - 0xbe, 0x34, 0xc6, 0x83, 0x07, 0xbe, 0x26, 0xd7, 0xb1, 0xf5, 0xfe, 0x69, 0x8d, 0xb4, 0xda, 0x38, 0x26, 0xb5, 0xea, - 0x65, 0xab, 0x78, 0xd9, 0xbd, 0x4e, 0xc5, 0xe0, 0xf9, 0xff, 0xdc, 0x07, 0xa8, 0x11, 0x2d, 0x65, 0x70, 0xeb, 0x6a, - 0x80, 0xc6, 0x87, 0x63, 0xe1, 0x1b, 0x3f, 0x64, 0x9c, 0x0f, 0x66, 0xe8, 0xa8, 0x36, 0x07, 0x07, 0x04, 0x47, 0x75, - 0x8f, 0xc6, 0x84, 0x59, 0x38, 0xf7, 0x20, 0x50, 0x7d, 0xe2, 0x3e, 0xe3, 0xda, 0x0b, 0xda, 0x04, 0x3e, 0x59, 0xd7, - 0x35, 0x45, 0x80, 0x8b, 0xd8, 0x98, 0x88, 0x21, 0x2e, 0x9b, 0x44, 0xea, 0x9b, 0x31, 0x28, 0x00, 0x8a, 0x17, 0x15, - 0xc9, 0xa5, 0x8b, 0x34, 0xaf, 0x44, 0x59, 0xeb, 0x66, 0x54, 0xac, 0x18, 0x02, 0xc0, 0x43, 0x50, 0x5c, 0x55, 0x66, - 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x6a, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, 0xd2, 0x3b, 0x1f, 0xb7, 0xce, - 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, 0x3f, 0xe3, 0x2f, 0x08, 0x4c, - 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x82, 0x97, 0x93, 0x70, 0x38, 0xf4, 0x41, 0x1f, - 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, 0x10, 0xd1, 0x42, 0x43, 0x1f, - 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, 0xda, 0xd0, 0x22, 0xc5, 0x45, - 0xa3, 0xcc, 0x66, 0xb9, 0xec, 0x84, 0x8d, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, 0x54, 0xad, 0xa7, 0x7a, 0x3d, - 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa4, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, 0xa3, 0x6a, 0x9d, 0xa5, 0x11, - 0x55, 0x6e, 0x92, 0xbb, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0x97, 0x29, 0x3b, 0x5b, 0x83, 0x13, 0x47, 0x9e, 0x4b, 0x6e, - 0xf9, 0xee, 0xbc, 0xa2, 0xbb, 0x53, 0xed, 0x5b, 0x80, 0x7b, 0x33, 0x6c, 0xc8, 0x9c, 0xd7, 0xd8, 0x69, 0x10, 0x26, - 0x81, 0x1f, 0xb1, 0x8f, 0x19, 0xb2, 0xc1, 0x80, 0x8e, 0x42, 0xfa, 0x5f, 0x5b, 0xe6, 0x48, 0xc0, 0xe4, 0xaf, 0xe7, - 0x7e, 0xb3, 0x28, 0x72, 0x58, 0x8c, 0x1f, 0x36, 0x18, 0x69, 0xac, 0xd6, 0x60, 0x58, 0xde, 0x21, 0xf2, 0xa7, 0x76, - 0xc7, 0x34, 0xd5, 0xf1, 0x66, 0xbd, 0xd6, 0xfc, 0xea, 0xe9, 0x53, 0x5d, 0x9f, 0xff, 0xf6, 0xfd, 0x65, 0x58, 0x33, - 0xfb, 0x43, 0x10, 0x4a, 0xbb, 0x77, 0x8b, 0x73, 0x47, 0xa2, 0x77, 0xac, 0x34, 0xb3, 0x4b, 0xbb, 0x64, 0x97, 0xa6, - 0xb4, 0x1b, 0x72, 0xbd, 0xfa, 0x4a, 0x79, 0x63, 0xe7, 0x15, 0xd3, 0xfd, 0x7b, 0xa1, 0x77, 0x94, 0x53, 0x35, 0x81, - 0x88, 0x26, 0xed, 0x48, 0xdc, 0xee, 0x95, 0xe1, 0xf3, 0x49, 0xde, 0x2e, 0xe1, 0xa8, 0x6b, 0x58, 0x6e, 0xbe, 0xfd, - 0xcf, 0xbc, 0xea, 0xac, 0x70, 0xfb, 0xa5, 0x31, 0x6b, 0x7f, 0x0a, 0xe2, 0xaa, 0xfe, 0xf0, 0x9e, 0xd4, 0x4c, 0xc9, - 0xff, 0x55, 0x8f, 0x81, 0xab, 0x9f, 0x4c, 0x3b, 0xba, 0xa7, 0x10, 0x36, 0x98, 0xfd, 0xfc, 0xf8, 0xa1, 0x05, 0xab, - 0xea, 0x02, 0x45, 0x72, 0x00, 0x9d, 0xbb, 0x64, 0x84, 0xf7, 0x3b, 0xc6, 0xb9, 0x7f, 0xf5, 0xbd, 0x9a, 0x1c, 0x21, - 0xa2, 0x5d, 0x84, 0x03, 0x80, 0xb8, 0xd3, 0x54, 0xd6, 0xa1, 0x06, 0xe8, 0x03, 0x02, 0xeb, 0xd0, 0xb7, 0x19, 0xc0, - 0x41, 0x1f, 0x6d, 0x9e, 0x45, 0x20, 0xaf, 0x7b, 0xf7, 0xec, 0x9a, 0xed, 0x7c, 0xfe, 0x62, 0x95, 0x7a, 0xf7, 0xe8, - 0x10, 0x7c, 0x3e, 0xf6, 0xa7, 0x97, 0x81, 0xc1, 0x85, 0x66, 0xd7, 0xcf, 0x04, 0xdb, 0xb1, 0xdd, 0x33, 0x44, 0x2a, - 0xea, 0xce, 0x3f, 0xbc, 0x34, 0xd1, 0xf3, 0xce, 0x0b, 0x77, 0x7c, 0x09, 0xe0, 0x81, 0x2c, 0x06, 0x14, 0x9f, 0xa5, - 0xf7, 0x2f, 0x96, 0x80, 0x9a, 0xfc, 0x96, 0xaf, 0xbd, 0x2f, 0x94, 0xba, 0x80, 0x3f, 0x07, 0x94, 0x3e, 0xc9, 0xb9, - 0x77, 0x37, 0xbc, 0xf5, 0x2f, 0x9e, 0x83, 0xf3, 0xc4, 0x6a, 0xb8, 0x80, 0xbf, 0x0a, 0x3e, 0xf4, 0xee, 0x06, 0x98, - 0x58, 0xf2, 0xa1, 0xb7, 0x1a, 0x40, 0xaa, 0xc2, 0x85, 0xc4, 0xd8, 0x87, 0x5f, 0x83, 0x9c, 0xe1, 0x1f, 0xbf, 0x69, - 0x0c, 0xd6, 0x5f, 0x83, 0x42, 0xa3, 0xb1, 0x96, 0x2a, 0x64, 0x29, 0x16, 0x67, 0x02, 0x6c, 0xc2, 0x71, 0xb7, 0x2f, - 0x56, 0xb5, 0x59, 0x0b, 0xfa, 0xf3, 0x11, 0xdf, 0xa3, 0xb1, 0xba, 0x2a, 0xe7, 0xa2, 0xfc, 0x88, 0xf4, 0xa9, 0x8e, - 0x8f, 0x51, 0xb1, 0xa9, 0xbb, 0xd3, 0xa9, 0x56, 0x1d, 0x69, 0xbf, 0x29, 0xd7, 0x60, 0xc7, 0xeb, 0xe4, 0xc8, 0x52, - 0x78, 0xd6, 0x61, 0xe7, 0xa5, 0x53, 0xa2, 0xc3, 0x30, 0xde, 0x6d, 0xd5, 0x33, 0x86, 0xf2, 0xdc, 0x60, 0x4c, 0x17, - 0x3c, 0xe2, 0x2f, 0x06, 0xb9, 0x0c, 0x8d, 0xf9, 0x80, 0x6c, 0x18, 0xca, 0x87, 0x16, 0x19, 0x12, 0x22, 0xde, 0x43, - 0x25, 0x60, 0xdb, 0x82, 0x32, 0x29, 0xe0, 0x2c, 0x1a, 0xfc, 0x56, 0x7b, 0x39, 0xf0, 0x1e, 0x44, 0x7e, 0x23, 0x5d, - 0xca, 0x25, 0x36, 0x3a, 0x71, 0x2c, 0x0b, 0xed, 0x3c, 0xae, 0xbf, 0x8e, 0x41, 0xfd, 0x5e, 0xe9, 0x37, 0x28, 0x67, - 0x7f, 0x94, 0xac, 0xd3, 0xc6, 0x13, 0xe3, 0x1f, 0xae, 0xf2, 0x4f, 0xd1, 0x52, 0x0f, 0xff, 0x9f, 0x31, 0x85, 0xd2, - 0xbf, 0x4a, 0xcb, 0x68, 0xb3, 0x5a, 0x8a, 0x52, 0xe4, 0x91, 0x38, 0xf9, 0x5a, 0x64, 0xe7, 0xf2, 0x9d, 0x4f, 0xa1, - 0x5f, 0x00, 0x5a, 0xf6, 0x09, 0x32, 0xfa, 0x7b, 0x26, 0xf8, 0xf0, 0x7b, 0xed, 0x5c, 0x9b, 0xf3, 0xf1, 0x24, 0xbf, - 0xb2, 0xf6, 0x6e, 0xc7, 0x8b, 0xc4, 0x28, 0xc6, 0x72, 0x5f, 0x75, 0xb3, 0x72, 0xa2, 0x92, 0x03, 0x23, 0x5d, 0x93, - 0xbd, 0x5c, 0xc9, 0xba, 0x9d, 0x6e, 0x25, 0x10, 0x51, 0x05, 0xde, 0x63, 0x5c, 0xc5, 0x3e, 0x82, 0xe9, 0xba, 0xe3, - 0x32, 0xda, 0xf1, 0x9e, 0xf1, 0xea, 0x44, 0x59, 0xc1, 0xed, 0x46, 0xb4, 0x27, 0x74, 0xf4, 0xd3, 0xa4, 0xb6, 0x2c, - 0x1c, 0x80, 0xdc, 0x25, 0x8c, 0x65, 0x43, 0xb0, 0x62, 0x50, 0xfa, 0x7a, 0x4d, 0xc9, 0xb2, 0x00, 0x8b, 0xce, 0x2e, - 0x23, 0x10, 0xc3, 0xba, 0x69, 0x4e, 0xe8, 0x78, 0xe9, 0xe2, 0xbc, 0xd7, 0x2a, 0x52, 0xf0, 0x8c, 0x16, 0x1d, 0x73, - 0xd3, 0x91, 0x6e, 0x8c, 0xf6, 0xf6, 0x7b, 0x83, 0x90, 0xe2, 0xf9, 0x03, 0x5b, 0xad, 0x8b, 0x8b, 0xc4, 0x2b, 0x64, - 0xa2, 0x05, 0xb1, 0x14, 0x81, 0x19, 0x2f, 0x34, 0x8d, 0x30, 0x41, 0x99, 0x12, 0x2c, 0x5a, 0xa3, 0x43, 0xfb, 0xc3, - 0x12, 0x76, 0x8f, 0x31, 0x02, 0x04, 0xaa, 0x4c, 0x9f, 0xc3, 0xd6, 0x84, 0xd9, 0xd4, 0xc5, 0x06, 0x68, 0xab, 0x18, - 0x1a, 0x84, 0xb5, 0x21, 0xe6, 0x63, 0x9a, 0xdf, 0xfd, 0x0b, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, 0xde, 0xed, 0x9a, 0x84, - 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xa8, 0x1d, 0x6b, 0xa9, 0x77, 0xac, 0xb5, - 0xde, 0xb1, 0xee, 0x1a, 0xfe, 0x21, 0xf3, 0x62, 0x96, 0x80, 0x7e, 0x77, 0xc5, 0x55, 0x83, 0xa0, 0x19, 0x1b, 0x76, - 0x0b, 0xbf, 0x25, 0xd6, 0x6e, 0xe9, 0x5f, 0x2c, 0xd9, 0xc2, 0xf4, 0x81, 0x6e, 0x1d, 0x60, 0x19, 0x51, 0x93, 0xef, - 0x91, 0x77, 0xd3, 0x59, 0x51, 0xb8, 0x3d, 0xb1, 0x85, 0xcf, 0xae, 0xcd, 0x9b, 0xf7, 0xcf, 0x22, 0xc8, 0xbd, 0xe3, - 0xde, 0xfd, 0xf0, 0xda, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, 0xea, 0x88, 0x4f, 0x10, 0xad, 0xec, 0x29, - 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, - 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, - 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, - 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, - 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, - 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, - 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0xbe, 0x3f, 0x2d, 0x94, 0x6b, 0x37, 0x6f, 0xe3, - 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x8e, 0x94, 0x5d, 0x2c, 0xe1, 0x1e, - 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf1, 0x9c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, 0x62, 0x5b, 0xb8, 0x78, - 0xce, 0x36, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0x8d, 0x6a, 0x8e, 0x35, 0xd4, 0x6c, 0x6d, - 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0xee, 0xda, 0x8a, 0x8f, 0x95, 0xb5, 0x2e, 0xdd, 0xeb, 0x3d, 0xaa, 0x0b, 0x60, - 0xeb, 0xbf, 0x3d, 0x5e, 0xb9, 0x9e, 0xcf, 0x08, 0xe0, 0x6b, 0xc1, 0xc7, 0x93, 0x05, 0x7a, 0x95, 0x2c, 0xfc, 0xdb, - 0x81, 0x1a, 0x7f, 0xa7, 0x73, 0x17, 0x00, 0x5d, 0x49, 0x79, 0x05, 0xe4, 0x1d, 0xe4, 0x98, 0x5b, 0x76, 0xe5, 0xfd, - 0xc9, 0x77, 0xd8, 0x35, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, - 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x84, 0x20, 0xae, 0xe0, 0x16, 0xe2, 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, - 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, - 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xd7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x40, 0xfc, 0x74, 0x3b, 0xe0, - 0xf7, 0x1d, 0x6b, 0xcb, 0xbb, 0x66, 0x0b, 0xb6, 0x83, 0x4b, 0x50, 0xd3, 0x5e, 0xf6, 0x27, 0x95, 0x0b, 0xda, 0xb1, - 0x4b, 0xe2, 0xe1, 0x8c, 0x59, 0xa5, 0xcc, 0xac, 0x93, 0xea, 0x4a, 0x74, 0xc6, 0x74, 0xd6, 0x7a, 0x3e, 0x57, 0xf3, - 0x49, 0xa1, 0x41, 0xfd, 0xce, 0x89, 0x8f, 0xa8, 0xe8, 0x3c, 0x81, 0xad, 0x65, 0x05, 0xb1, 0xda, 0xe7, 0x60, 0xad, - 0xd5, 0x2e, 0xfd, 0x5e, 0x3e, 0xe0, 0x36, 0xe5, 0xb0, 0x0e, 0x0c, 0x6a, 0x4e, 0xac, 0xa8, 0xc7, 0x6c, 0xc7, 0xb8, - 0xf9, 0xe9, 0xe5, 0x0f, 0x4e, 0x58, 0xb2, 0x62, 0xb5, 0x3f, 0xfd, 0xfe, 0x99, 0xa7, 0xbf, 0x53, 0xfb, 0x17, 0xc2, - 0x0f, 0xc6, 0xff, 0xa9, 0xdd, 0xd7, 0x5a, 0x8c, 0xca, 0x56, 0x39, 0x42, 0xe3, 0x6e, 0x25, 0x4d, 0x96, 0x9f, 0x84, - 0x27, 0xac, 0x05, 0xcf, 0x72, 0xbd, 0x44, 0xb3, 0x02, 0x56, 0x58, 0xcb, 0x24, 0x5c, 0x61, 0xac, 0x96, 0xb6, 0xfa, - 0x16, 0x4d, 0x73, 0x7c, 0x38, 0xd7, 0x06, 0x65, 0xca, 0xd9, 0x19, 0xb1, 0x1a, 0x2e, 0xc3, 0xd2, 0x84, 0x22, 0x64, - 0xf7, 0x76, 0x70, 0x63, 0xa7, 0x2c, 0xa5, 0x0c, 0xe7, 0x18, 0x4c, 0x78, 0x24, 0x46, 0x55, 0xbe, 0xbf, 0x2f, 0x29, - 0x72, 0xda, 0x96, 0x83, 0x2a, 0x84, 0x7d, 0x24, 0x51, 0x02, 0xb7, 0x22, 0x2d, 0x14, 0x29, 0x8b, 0xbf, 0x1d, 0xa0, - 0x0b, 0xbc, 0x80, 0xba, 0x1a, 0x75, 0xfb, 0xc3, 0x11, 0x0f, 0x1f, 0x99, 0xfa, 0xc0, 0x88, 0x25, 0x81, 0xda, 0x5e, - 0x66, 0xe9, 0x1d, 0xa8, 0xf0, 0x7b, 0xb8, 0x9a, 0x88, 0xfd, 0xdc, 0x92, 0xa2, 0x22, 0x1b, 0xe9, 0x0d, 0xad, 0xc1, - 0x23, 0xb4, 0xa6, 0x7c, 0xef, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, - 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0xef, - 0x55, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, 0xac, 0xd2, 0xd7, 0x24, 0x61, 0x4f, 0x0c, - 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, 0xd2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, - 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x57, 0xc4, 0x97, 0x23, 0x3c, 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, - 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, - 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, - 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, - 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, - 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, - 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, - 0x58, 0x1d, 0xf4, 0xfe, 0x32, 0x7e, 0xda, 0x33, 0x32, 0xf2, 0xb8, 0x75, 0x58, 0xfd, 0xaf, 0xbf, 0x42, 0x00, 0x1c, - 0x9e, 0x4d, 0xbd, 0xcb, 0x31, 0x64, 0x95, 0x65, 0x04, 0x92, 0x9f, 0x18, 0x7c, 0xf9, 0x02, 0xa0, 0xea, 0x33, 0x5d, - 0xab, 0xc9, 0x51, 0x7b, 0xcc, 0xa1, 0x2b, 0x06, 0x80, 0x6d, 0x58, 0xa2, 0xaa, 0x16, 0x36, 0x61, 0x71, 0xfb, 0x19, - 0x46, 0x73, 0xd9, 0xf4, 0x82, 0x06, 0xea, 0x11, 0x82, 0x5f, 0x5a, 0x0f, 0xad, 0xb5, 0x4c, 0x39, 0x74, 0x6d, 0x14, - 0x55, 0x36, 0xd4, 0x25, 0xac, 0xd6, 0x22, 0xaa, 0x89, 0x22, 0xe5, 0x92, 0x51, 0x14, 0x4b, 0x15, 0xec, 0x33, 0x71, - 0x07, 0x51, 0xf3, 0xb4, 0xd5, 0x56, 0xc1, 0xfe, 0x0e, 0x10, 0xd6, 0xc2, 0x5a, 0x48, 0x67, 0x50, 0x7b, 0xa7, 0x1f, - 0x29, 0x7f, 0x79, 0x21, 0xb7, 0x73, 0x0b, 0x45, 0xb8, 0x3d, 0x07, 0xe5, 0x4d, 0x5d, 0x95, 0x8a, 0x68, 0xb4, 0x04, - 0x4a, 0x99, 0x13, 0x44, 0x16, 0x20, 0x80, 0xe3, 0x06, 0x02, 0x9f, 0xd7, 0xf8, 0x04, 0x1a, 0x85, 0x40, 0x7e, 0x60, - 0x15, 0xae, 0x3d, 0xa4, 0xa5, 0xd6, 0x88, 0x28, 0x11, 0x3f, 0xba, 0x7a, 0x8e, 0xed, 0xab, 0xa7, 0xb1, 0xb6, 0x94, - 0x26, 0x88, 0x9f, 0x58, 0x6c, 0x21, 0x26, 0x88, 0xea, 0x10, 0x1d, 0xc1, 0x72, 0x42, 0x88, 0xc2, 0x1f, 0x42, 0x3f, - 0x35, 0xf0, 0x97, 0x6c, 0x59, 0xe4, 0x35, 0xc1, 0x62, 0x56, 0x0c, 0xd0, 0xaa, 0x08, 0x3c, 0xd3, 0xd9, 0x52, 0x99, - 0xd3, 0x3c, 0x3a, 0xb2, 0x83, 0xf3, 0xae, 0x83, 0xbd, 0xf4, 0x65, 0xec, 0x64, 0xd9, 0x34, 0x6a, 0x63, 0x43, 0x24, - 0xbc, 0x22, 0x7f, 0x95, 0xa5, 0xc6, 0x39, 0x32, 0x97, 0xeb, 0xbb, 0x2e, 0xee, 0xee, 0x68, 0x9b, 0xb0, 0x0a, 0x11, - 0xea, 0xb6, 0xa1, 0x72, 0x29, 0xcc, 0xc6, 0xa6, 0x69, 0x80, 0x2f, 0x14, 0x95, 0x4a, 0x55, 0x6a, 0x2b, 0x95, 0x9c, - 0xf0, 0xae, 0xaf, 0x6a, 0x91, 0xba, 0x22, 0xd8, 0xc6, 0x0c, 0xf5, 0x50, 0x6e, 0xd4, 0xd8, 0xd7, 0x1d, 0xab, 0xf4, - 0x0e, 0x13, 0xe4, 0x8c, 0xbc, 0xc8, 0xc1, 0x45, 0x49, 0x41, 0xe6, 0x6a, 0x08, 0xf3, 0x47, 0x0d, 0x9f, 0x16, 0x96, - 0x7b, 0x28, 0x01, 0xb3, 0xa3, 0x86, 0x97, 0x11, 0x02, 0x11, 0x97, 0xca, 0xbe, 0x62, 0xe2, 0xf7, 0x14, 0xcc, 0x92, - 0x09, 0xdd, 0x8b, 0x58, 0x18, 0xa1, 0x8d, 0x4f, 0x92, 0x64, 0xea, 0x69, 0x0a, 0x6e, 0xe4, 0x32, 0xcc, 0xd1, 0x08, - 0x2d, 0xf9, 0xc8, 0x81, 0xf4, 0xb5, 0x9c, 0x4a, 0xf0, 0x11, 0x75, 0x0a, 0x38, 0x9e, 0x9f, 0x17, 0xd6, 0x4f, 0x96, - 0x4b, 0xcc, 0x65, 0x6d, 0xfe, 0xcb, 0x8e, 0x8e, 0xc1, 0x2e, 0x4f, 0x13, 0xc7, 0xd5, 0x7f, 0x54, 0x25, 0xc5, 0xc3, - 0xcf, 0x69, 0x0e, 0x28, 0x82, 0x99, 0x3d, 0xc5, 0xf8, 0xd8, 0x67, 0x99, 0x02, 0xfe, 0x76, 0xbd, 0xb5, 0x64, 0x62, - 0x97, 0xb4, 0x9b, 0x2b, 0xe3, 0x97, 0xda, 0xb0, 0xe3, 0xe0, 0xdc, 0x00, 0x14, 0x67, 0x8d, 0x0e, 0xcb, 0x6b, 0xdd, - 0xb6, 0x2a, 0x54, 0xa0, 0xd6, 0xff, 0xd9, 0x2d, 0x4c, 0x79, 0x9b, 0x97, 0xca, 0xdb, 0x3c, 0x34, 0x01, 0x02, 0x91, - 0x19, 0xf2, 0xac, 0xe9, 0x98, 0x24, 0xee, 0x1d, 0x29, 0x69, 0xdf, 0x91, 0xe2, 0x47, 0xef, 0x48, 0xc8, 0xb7, 0x84, - 0x8e, 0xec, 0x4b, 0x4e, 0x4e, 0xa0, 0xcc, 0x60, 0x2f, 0xaf, 0x99, 0xec, 0x1f, 0xd0, 0x5e, 0x38, 0x97, 0xe5, 0x15, - 0xbf, 0x16, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, - 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, 0xf1, 0xf1, 0xd7, 0x1c, 0x45, 0x6c, 0xa5, 0x3c, 0x92, 0x2e, 0x54, - 0x62, 0x78, 0x69, 0xe0, 0x61, 0x76, 0x7c, 0x3c, 0xd9, 0x5d, 0xdd, 0x4f, 0x06, 0x83, 0x9d, 0xea, 0xdb, 0x2d, 0xaf, - 0x67, 0xbb, 0x39, 0x7b, 0xe0, 0xb7, 0xd3, 0x6d, 0xb0, 0x6f, 0x60, 0xdb, 0xdd, 0x5d, 0x89, 0xc3, 0x61, 0xf7, 0x82, - 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, - 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, - 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe5, 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, - 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, - 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xfa, - 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xf5, 0x6c, 0x33, - 0xf7, 0x5f, 0xac, 0xd8, 0x1d, 0x70, 0xa1, 0x28, 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, - 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, - 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, 0xd7, 0xfc, 0xa6, 0x39, 0x76, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, - 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0x95, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x57, 0x0b, - 0x39, 0xf3, 0xcc, 0x40, 0xdf, 0x56, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x6a, 0xa6, - 0x6d, 0x51, 0x97, 0xdf, 0xf6, 0x9e, 0xc9, 0x6f, 0x64, 0x60, 0x0b, 0x91, 0x14, 0x8e, 0xe3, 0x8b, 0xe7, 0x27, 0xfc, - 0x57, 0x2d, 0x8f, 0x5a, 0xed, 0x17, 0x4a, 0x7d, 0xfa, 0x8a, 0x8e, 0x68, 0xe2, 0x5e, 0xb4, 0x65, 0x58, 0xa3, 0xac, - 0xa9, 0xa5, 0xc3, 0x30, 0xae, 0x61, 0x5f, 0x1e, 0x38, 0xf4, 0x1d, 0x10, 0x68, 0xab, 0x54, 0x0a, 0xb4, 0x70, 0x0c, - 0xa3, 0x30, 0x0b, 0x29, 0x8f, 0x0b, 0xb3, 0x94, 0xf7, 0x58, 0xa0, 0xc5, 0xad, 0xba, 0xc7, 0xd4, 0x76, 0x0b, 0x22, - 0xac, 0xde, 0x32, 0xce, 0x2f, 0x1b, 0x55, 0xb8, 0x2d, 0x40, 0x51, 0x04, 0x65, 0xb0, 0x27, 0xb9, 0x6d, 0xa1, 0xa4, - 0xd9, 0x28, 0xac, 0xc5, 0x5d, 0x51, 0xee, 0x7a, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, 0x75, - 0x28, 0x17, 0xe9, 0x7f, 0x64, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xe7, 0x97, 0xf4, - 0x93, 0xc1, 0x32, 0x72, 0x4a, 0x7d, 0x1f, 0x8d, 0x6e, 0xd3, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, 0x0a, - 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, 0x26, - 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, 0x90, - 0xdc, 0xa9, 0x2b, 0x7f, 0x54, 0x4e, 0xfe, 0x13, 0x0d, 0x91, 0x57, 0x5c, 0x21, 0x56, 0x16, 0x5c, 0x62, 0x31, 0x54, - 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xcb, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, 0x11, - 0x3e, 0x6e, 0xad, 0x45, 0x08, 0x56, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, 0x14, - 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xa8, 0x48, 0xcf, 0x5f, 0x9a, 0x94, 0x5c, 0x1a, - 0x33, 0x3e, 0x88, 0x32, 0x12, 0x79, 0x1d, 0xde, 0x89, 0x69, 0x81, 0x7c, 0xa3, 0xc7, 0x0f, 0x82, 0x4b, 0x78, 0x37, - 0xe4, 0x5e, 0x01, 0xb6, 0x04, 0xec, 0x00, 0xf7, 0xca, 0x8c, 0x72, 0x9d, 0xd6, 0xf5, 0x5b, 0xeb, 0xa1, 0x18, 0x86, - 0xcf, 0x2c, 0x81, 0xed, 0x68, 0x1d, 0x1d, 0xe9, 0xe1, 0xc3, 0xff, 0xba, 0xaa, 0x39, 0xea, 0x54, 0x2e, 0x67, 0xc7, - 0x13, 0x96, 0x22, 0x66, 0xd0, 0xfd, 0x75, 0xfb, 0x4a, 0x00, 0xdd, 0x2e, 0x8b, 0x79, 0x36, 0xda, 0xc9, 0xbf, 0xa5, - 0x1b, 0x2b, 0x4a, 0x9b, 0x78, 0x97, 0xf5, 0xc6, 0xfe, 0x70, 0xf4, 0x97, 0x67, 0x5f, 0x26, 0x84, 0xaa, 0xb3, 0x61, - 0x6b, 0x1d, 0xe7, 0xf2, 0xbf, 0xfe, 0x3a, 0x26, 0x2b, 0x08, 0x0a, 0xc2, 0xb2, 0x53, 0x4c, 0x54, 0x30, 0x8a, 0x14, - 0x6b, 0x3e, 0x9e, 0xac, 0x51, 0x27, 0xbc, 0xf6, 0x97, 0x5a, 0x27, 0x4c, 0x8c, 0xac, 0x54, 0xfe, 0x9a, 0x55, 0xec, - 0x4e, 0x65, 0x16, 0x90, 0x79, 0x90, 0x4f, 0xd6, 0x46, 0x83, 0xb9, 0xe2, 0xf5, 0x6c, 0x3d, 0x97, 0xca, 0x67, 0x30, - 0xe5, 0x2c, 0x07, 0x27, 0x4b, 0x61, 0xf7, 0x24, 0x50, 0xb4, 0x66, 0xe8, 0xda, 0x9f, 0x62, 0xab, 0x5e, 0xa7, 0x55, - 0x0d, 0xf0, 0x80, 0x10, 0x03, 0x43, 0xed, 0xd5, 0xc2, 0x43, 0x6b, 0x01, 0xac, 0xfd, 0x51, 0xe9, 0x07, 0xe3, 0xc9, - 0x92, 0x2f, 0x90, 0x7f, 0x39, 0x72, 0xd4, 0xee, 0xfd, 0xbe, 0x77, 0x0f, 0x52, 0x70, 0xe4, 0x5a, 0x28, 0x90, 0x08, - 0x68, 0xc1, 0x37, 0xbe, 0xf2, 0xc1, 0xb8, 0x46, 0x6d, 0x35, 0x28, 0xa8, 0x1d, 0xdd, 0xf2, 0xd8, 0xd1, 0x3b, 0xdf, - 0x9f, 0xd0, 0x57, 0x2f, 0xb4, 0x70, 0xfc, 0x95, 0x33, 0x72, 0xcd, 0x56, 0x1d, 0x72, 0x44, 0x33, 0xe9, 0x10, 0x22, - 0x56, 0x6c, 0xcd, 0xae, 0x49, 0xe5, 0xdc, 0x39, 0x64, 0xa7, 0x8f, 0x50, 0xa5, 0xd7, 0x7a, 0x7c, 0x3b, 0x51, 0xba, - 0xdb, 0xe3, 0xdd, 0xe4, 0x5b, 0x36, 0x11, 0x31, 0x18, 0xd0, 0x06, 0xe1, 0x8c, 0xac, 0x43, 0xa4, 0xd2, 0x01, 0x42, - 0xe0, 0x98, 0x80, 0xa6, 0xff, 0xf8, 0x9a, 0x44, 0x01, 0x47, 0xda, 0x08, 0x59, 0xcb, 0x0e, 0x87, 0x1c, 0x34, 0xca, - 0xcd, 0x1f, 0x5e, 0xa1, 0x4e, 0x73, 0x60, 0x9e, 0x2e, 0x61, 0xcf, 0xc1, 0x23, 0xbd, 0x38, 0x3e, 0xd2, 0xff, 0x3b, - 0x9a, 0xa8, 0xf1, 0x7f, 0xae, 0x89, 0x52, 0x5a, 0x24, 0x47, 0xb5, 0xf4, 0x4d, 0xea, 0x28, 0xb8, 0xc8, 0x3b, 0x6a, - 0x21, 0x7b, 0x96, 0x8d, 0x1b, 0xd5, 0xbc, 0xff, 0x5f, 0x2b, 0xf3, 0xff, 0x35, 0xad, 0x0c, 0x53, 0xb2, 0x63, 0xa9, - 0x66, 0x1e, 0x68, 0x15, 0xc3, 0xec, 0x67, 0x92, 0x10, 0x19, 0x2e, 0x0d, 0xf8, 0x51, 0x05, 0xfb, 0x38, 0xad, 0xd6, - 0x59, 0xb8, 0x43, 0x25, 0xea, 0xad, 0xb8, 0x4b, 0xf3, 0x97, 0xf5, 0xbf, 0x45, 0x59, 0xc0, 0xd4, 0xbe, 0x2b, 0xd3, - 0x38, 0x20, 0x0b, 0x7f, 0x16, 0x96, 0x38, 0xb9, 0xb1, 0x8d, 0x3f, 0xcb, 0xf1, 0xb4, 0x5f, 0x75, 0x66, 0x1e, 0x48, - 0xa0, 0x06, 0xe2, 0x8f, 0x9c, 0xcb, 0xca, 0xe2, 0x01, 0xa1, 0x9b, 0x7f, 0x28, 0xcb, 0xa2, 0xf4, 0x7a, 0x9f, 0x92, - 0xb4, 0x3a, 0x5b, 0x89, 0x3a, 0x29, 0x62, 0x05, 0x65, 0x93, 0x02, 0x8c, 0x3e, 0xac, 0x3c, 0x11, 0x07, 0x67, 0x08, - 0xd4, 0x70, 0x56, 0x27, 0x21, 0x00, 0x0d, 0x2b, 0x84, 0xfd, 0x33, 0x68, 0xe1, 0x59, 0x18, 0x87, 0x6b, 0x80, 0xc9, - 0x49, 0xab, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, 0x88, 0x47, 0x3d, 0x45, 0xc9, 0xf2, 0x26, 0x77, 0xe5, 0x5c, 0x7f, - 0xff, 0x07, 0x05, 0xb0, 0x1b, 0x30, 0xdb, 0x16, 0xd8, 0x01, 0x40, 0x82, 0x02, 0xd9, 0x42, 0x9d, 0x46, 0x67, 0x6a, - 0xa9, 0xc0, 0x7b, 0xae, 0x07, 0xf8, 0x9b, 0x1c, 0xb0, 0x8c, 0xeb, 0x42, 0x06, 0x8c, 0x20, 0x80, 0x11, 0x38, 0x28, - 0x01, 0x43, 0x67, 0x88, 0xdb, 0xaa, 0x9c, 0xb5, 0xd0, 0x5c, 0xe9, 0xb6, 0xe4, 0xa6, 0x51, 0xce, 0x56, 0x22, 0x80, - 0xbe, 0xba, 0x29, 0x71, 0xba, 0x5c, 0xb6, 0x92, 0xb0, 0x6f, 0xdf, 0xb7, 0x53, 0x45, 0x1e, 0x1f, 0xa5, 0x21, 0xaf, - 0xc0, 0x93, 0x8c, 0x23, 0x49, 0x94, 0x08, 0xde, 0xe4, 0x8d, 0x19, 0x87, 0x97, 0x6d, 0xca, 0xa9, 0xbd, 0x59, 0x2f, - 0x00, 0xe7, 0x09, 0xda, 0x32, 0xc0, 0x58, 0xc0, 0xe0, 0x5c, 0x88, 0x25, 0x4f, 0x11, 0xfc, 0xd2, 0x89, 0x14, 0xc6, - 0x5d, 0x0e, 0xc3, 0x3c, 0x28, 0x7a, 0x97, 0xd4, 0x1f, 0xfd, 0x3e, 0x6a, 0x93, 0xc1, 0x10, 0x54, 0x02, 0xa8, 0xac, - 0x1b, 0x24, 0x06, 0x56, 0xa5, 0x85, 0xc4, 0x25, 0xc4, 0xcb, 0x7c, 0x35, 0xad, 0xa3, 0xe0, 0x7d, 0x3d, 0x21, 0x84, - 0x13, 0x8c, 0x0f, 0x71, 0x03, 0x04, 0x0c, 0x56, 0x71, 0x81, 0x41, 0xf2, 0x5c, 0xa2, 0xfb, 0xe3, 0xf9, 0x8e, 0x01, - 0xae, 0x9c, 0xf7, 0x54, 0xbb, 0x7a, 0x60, 0x2f, 0x57, 0xe9, 0x92, 0x11, 0xc2, 0x8a, 0xff, 0x8b, 0xc8, 0xfb, 0x76, - 0x98, 0x80, 0xda, 0x46, 0xfe, 0x18, 0x24, 0xe6, 0x32, 0x51, 0x04, 0xf1, 0x28, 0x2b, 0x58, 0x92, 0x06, 0x9b, 0x51, - 0x92, 0x82, 0x46, 0x13, 0x63, 0xc8, 0x54, 0x68, 0x87, 0xa4, 0xd1, 0x6c, 0x4c, 0xf6, 0x31, 0xe4, 0x35, 0x5c, 0x2c, - 0x16, 0x78, 0xdf, 0xcf, 0x42, 0x75, 0xb0, 0x2d, 0xcd, 0x21, 0xe0, 0x24, 0xc1, 0x9e, 0xba, 0x22, 0x25, 0x61, 0x36, - 0xfa, 0x14, 0x72, 0x6e, 0x40, 0xc7, 0x49, 0x63, 0xa8, 0x3e, 0x30, 0x09, 0xaf, 0x22, 0x74, 0x52, 0x56, 0x08, 0x0b, - 0xb8, 0x6f, 0x64, 0x34, 0x5a, 0x49, 0x83, 0xc0, 0xdb, 0x0c, 0x5b, 0x81, 0x4d, 0x68, 0xf8, 0xcb, 0xcc, 0xc3, 0xb4, - 0x9a, 0x95, 0x60, 0xce, 0x37, 0x50, 0x89, 0xf1, 0x64, 0x79, 0xc5, 0x37, 0x2e, 0x56, 0x62, 0x32, 0x5b, 0xce, 0x27, - 0x6b, 0x49, 0x35, 0x97, 0x7b, 0x6b, 0x96, 0xb1, 0x25, 0xec, 0x1f, 0x06, 0x86, 0xd2, 0x81, 0x1d, 0x4d, 0x35, 0x6d, - 0x12, 0x60, 0x32, 0x9d, 0x73, 0x3e, 0xbc, 0x44, 0x34, 0x59, 0x9d, 0xba, 0x93, 0xa9, 0x6a, 0x07, 0xd7, 0xe4, 0x4c, - 0x4e, 0x8f, 0xd4, 0x53, 0xad, 0x7b, 0xc9, 0x47, 0xdb, 0x61, 0x35, 0xda, 0xfa, 0x01, 0xb8, 0x75, 0x0a, 0x3b, 0x7d, - 0x37, 0xac, 0x46, 0x3b, 0x5f, 0xc3, 0xee, 0x92, 0x42, 0xa0, 0xfa, 0xb3, 0xac, 0xc9, 0x5c, 0xbc, 0x2e, 0x1e, 0xbc, - 0x82, 0x3d, 0xf7, 0x07, 0xfa, 0x57, 0xc9, 0x9e, 0xfb, 0x36, 0x93, 0xeb, 0x9f, 0x69, 0xd7, 0x68, 0xcc, 0x74, 0xbc, - 0x76, 0x05, 0x56, 0x68, 0x80, 0xfc, 0x82, 0x1d, 0xed, 0x6d, 0x0e, 0x02, 0x01, 0xba, 0x97, 0xe0, 0x28, 0x0a, 0x88, - 0x9a, 0x56, 0x95, 0x47, 0xa7, 0x7b, 0x7f, 0x8f, 0x6f, 0x94, 0x80, 0x4d, 0x9e, 0x5a, 0xf7, 0x96, 0xb1, 0x7f, 0x38, - 0x40, 0x08, 0xbd, 0x9c, 0x7e, 0xa3, 0x2d, 0xab, 0x47, 0x3b, 0x96, 0xfb, 0x86, 0x51, 0x4f, 0xc1, 0x18, 0x86, 0x2e, - 0xac, 0x62, 0x24, 0xcf, 0x80, 0xac, 0xf1, 0x1b, 0x44, 0x17, 0xb0, 0xe8, 0xf5, 0x5e, 0x1f, 0xd1, 0x20, 0x02, 0x2a, - 0xbd, 0xe6, 0x2f, 0x45, 0x3e, 0x57, 0x85, 0xe8, 0xbd, 0xb7, 0x76, 0xde, 0xcc, 0x48, 0x96, 0x49, 0x23, 0xd5, 0x6e, - 0x65, 0xb1, 0xae, 0xbc, 0xd9, 0x09, 0xe9, 0x62, 0x8e, 0xa1, 0x32, 0x78, 0x1c, 0x80, 0xd2, 0xf3, 0x6f, 0xa1, 0x57, - 0x32, 0x64, 0x9a, 0x25, 0x9a, 0xd9, 0x5d, 0xe3, 0x4f, 0x56, 0xa9, 0x17, 0x23, 0x62, 0x36, 0xb0, 0x85, 0xb8, 0x2d, - 0x2a, 0xdd, 0x16, 0x85, 0xb2, 0x45, 0x91, 0x3e, 0xd4, 0xce, 0x74, 0x67, 0x16, 0x3e, 0xab, 0x4c, 0xfb, 0xde, 0x66, - 0x66, 0x6c, 0x80, 0xb6, 0x8b, 0xf0, 0x0d, 0x74, 0xa0, 0x42, 0xc8, 0x7f, 0x40, 0x44, 0x24, 0x02, 0x76, 0x39, 0x75, - 0x27, 0x36, 0x1d, 0x92, 0x79, 0x88, 0x59, 0xa1, 0x46, 0x79, 0xc9, 0x93, 0xa3, 0x01, 0xa9, 0x08, 0x75, 0xbb, 0xdf, - 0x3f, 0x5f, 0xba, 0xa0, 0xf6, 0x6b, 0x8a, 0x1d, 0xa3, 0x9b, 0x02, 0xce, 0x05, 0x8f, 0xf2, 0x9e, 0x7b, 0xe7, 0x80, - 0xe6, 0xd8, 0x9e, 0x22, 0x6b, 0xc0, 0xe9, 0x6d, 0x17, 0x02, 0x6c, 0x9f, 0x35, 0x5b, 0xfb, 0x93, 0xd5, 0x55, 0x34, - 0xf5, 0x4a, 0x3e, 0xd3, 0x5d, 0x94, 0xb8, 0x5d, 0x14, 0xcb, 0x2e, 0xda, 0x34, 0x10, 0xec, 0xb8, 0xf2, 0x03, 0xe0, - 0x0d, 0x8d, 0xfa, 0xfd, 0xb2, 0xd5, 0xb3, 0x27, 0x5f, 0x3b, 0xee, 0xd9, 0xcc, 0x67, 0xa5, 0xe9, 0xd9, 0x5f, 0x53, - 0xb7, 0x67, 0xe5, 0x64, 0x2f, 0x3a, 0x27, 0xfb, 0x74, 0x36, 0x0f, 0x04, 0x97, 0x3b, 0xf7, 0x79, 0x3e, 0xd5, 0xd3, - 0xae, 0xf2, 0x83, 0xd6, 0x10, 0x99, 0x2f, 0x7c, 0xaa, 0xba, 0xd7, 0x15, 0x2c, 0x60, 0x09, 0xee, 0xd6, 0x4b, 0xf3, - 0x5f, 0xb1, 0xfb, 0x7b, 0x41, 0x2f, 0xcd, 0x7f, 0xa3, 0x3f, 0x29, 0x80, 0x03, 0xd0, 0x98, 0xda, 0x2d, 0xf0, 0x10, - 0x43, 0x05, 0x85, 0xbb, 0x59, 0x39, 0xf7, 0x6a, 0x80, 0xc3, 0x24, 0x7d, 0x43, 0xab, 0x57, 0x5a, 0xec, 0x7a, 0x99, - 0xec, 0x15, 0xe0, 0xa1, 0x0a, 0x79, 0x78, 0x38, 0x44, 0x1d, 0xc3, 0x0e, 0xea, 0x08, 0x18, 0xf6, 0x10, 0x1a, 0x5b, - 0xe0, 0xf9, 0xf8, 0x29, 0xe3, 0x7b, 0x01, 0x6a, 0x23, 0x84, 0xc7, 0xab, 0x45, 0x19, 0x62, 0xcb, 0xde, 0x22, 0x95, - 0xd4, 0xcf, 0x02, 0x51, 0x46, 0xab, 0x80, 0xb6, 0xda, 0x63, 0x96, 0xc6, 0x1b, 0x08, 0x15, 0x4b, 0x7d, 0x0c, 0xa1, - 0x81, 0xc3, 0xef, 0x70, 0x00, 0x09, 0xbe, 0xe4, 0x9a, 0x6c, 0xee, 0x6d, 0x7e, 0x4f, 0xfb, 0xfc, 0xe1, 0x70, 0x7e, - 0x89, 0xa0, 0x74, 0x29, 0x7c, 0xa4, 0x12, 0x51, 0x3d, 0xc5, 0x4d, 0x09, 0xd9, 0x2c, 0x59, 0xe9, 0x07, 0xbf, 0xaa, - 0x5f, 0x00, 0x20, 0x0b, 0x81, 0x36, 0x91, 0xd9, 0x9f, 0xce, 0x54, 0x74, 0x01, 0x70, 0x88, 0x3f, 0x7e, 0x82, 0xe8, - 0x1b, 0x5a, 0xa6, 0xe5, 0xe3, 0x84, 0x87, 0xa0, 0xb5, 0x25, 0x9d, 0x44, 0xac, 0x14, 0xd8, 0x10, 0x09, 0xdf, 0xef, - 0x9f, 0xc7, 0x92, 0x0e, 0x34, 0x6a, 0x75, 0x6f, 0xdc, 0xea, 0x5e, 0xf9, 0xba, 0xee, 0xe4, 0xc6, 0x07, 0x45, 0xfb, - 0x6c, 0xde, 0xa8, 0x7c, 0xdf, 0xd6, 0x39, 0xbb, 0xd3, 0xbd, 0x23, 0xe7, 0xc4, 0xb7, 0xf7, 0x10, 0x8a, 0x1e, 0x9a, - 0x22, 0xcb, 0x92, 0x30, 0xa0, 0xb5, 0x76, 0xed, 0x59, 0x46, 0x07, 0xaf, 0x7d, 0x43, 0x88, 0xc8, 0x53, 0x7c, 0x12, - 0x72, 0x8b, 0xe3, 0x83, 0x02, 0xfd, 0x33, 0xe3, 0xcf, 0x9c, 0xf8, 0x61, 0xab, 0x5f, 0x00, 0xe7, 0xa6, 0x7b, 0xef, - 0x4e, 0xcc, 0x7a, 0x0c, 0xa5, 0x6c, 0xfc, 0xdf, 0xef, 0x13, 0x59, 0xa0, 0xd3, 0x11, 0x0d, 0x03, 0xc1, 0x5d, 0x54, - 0xff, 0xf7, 0x8a, 0xd7, 0x3d, 0x6b, 0x75, 0xbe, 0xfc, 0xd4, 0xe9, 0x49, 0xaf, 0x5e, 0xc6, 0x3d, 0xa0, 0x42, 0x07, - 0x08, 0xe7, 0x75, 0xbf, 0x61, 0xbb, 0x6f, 0x7e, 0x79, 0x77, 0xf4, 0x32, 0xb0, 0x49, 0x91, 0xd8, 0x56, 0xf2, 0x59, - 0x0f, 0x14, 0x7e, 0x3d, 0xd6, 0xab, 0x8b, 0x75, 0x8f, 0xf5, 0x50, 0x0b, 0x88, 0x1e, 0x16, 0xa0, 0xfe, 0xeb, 0xd9, - 0xa7, 0xa1, 0x70, 0x90, 0x8d, 0x53, 0x05, 0x8a, 0x2c, 0xf8, 0x0b, 0x31, 0x5a, 0x17, 0x04, 0x88, 0x6c, 0x09, 0x69, - 0xd5, 0xc9, 0xec, 0x71, 0xa9, 0x25, 0x19, 0x7c, 0x13, 0x90, 0xd9, 0x81, 0x95, 0x13, 0x94, 0x8e, 0x5b, 0x03, 0xae, - 0x6c, 0xf1, 0x68, 0xb7, 0x3f, 0x0d, 0xb2, 0xb3, 0xe6, 0xa4, 0xd1, 0x3e, 0xec, 0xd3, 0x3c, 0x40, 0x20, 0x92, 0xa9, - 0x08, 0x72, 0xcd, 0xbd, 0x25, 0x7d, 0x74, 0x38, 0xe7, 0x85, 0xfc, 0x73, 0x2a, 0x75, 0x88, 0x43, 0x89, 0x35, 0x10, - 0xa8, 0x3c, 0x43, 0x95, 0xc3, 0x06, 0x39, 0xfe, 0xd9, 0x91, 0xcc, 0x24, 0x26, 0x8b, 0xdc, 0xad, 0x99, 0x0a, 0x3f, - 0x10, 0x7c, 0xcc, 0x72, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x02, 0x7f, 0x4c, 0xe1, 0x57, 0x3c, - 0x85, 0x9d, 0x76, 0xbf, 0x2e, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, - 0x3f, 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x65, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x06, - 0x15, 0x5b, 0x17, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xaa, 0x51, 0x5a, 0xfd, 0xa8, - 0x7f, 0x02, 0xf3, 0x36, 0x15, 0xa3, 0x5a, 0xc5, 0xe4, 0x37, 0xfa, 0xfd, 0x62, 0xd0, 0xfa, 0x90, 0xc1, 0x47, 0xaf, - 0x4d, 0x83, 0x3f, 0x3a, 0x0d, 0x76, 0x98, 0x68, 0x04, 0x40, 0x32, 0xa7, 0x96, 0x3c, 0x14, 0xfd, 0x11, 0xe4, 0x58, - 0xa3, 0xca, 0x29, 0x18, 0xac, 0xff, 0x78, 0xb4, 0x03, 0x53, 0x2f, 0x8e, 0xb6, 0x64, 0x07, 0xad, 0x7c, 0x03, 0xdc, - 0xaf, 0x91, 0x2d, 0x66, 0x39, 0x40, 0xb3, 0xd7, 0x88, 0x8c, 0x4f, 0x5e, 0x00, 0x63, 0xb6, 0xce, 0xc2, 0x48, 0xc4, - 0xc1, 0x58, 0x35, 0x66, 0xcc, 0xc0, 0xc0, 0x05, 0xba, 0x96, 0x49, 0x49, 0x1a, 0xd2, 0xc1, 0x80, 0x95, 0xb2, 0x85, - 0x03, 0x5e, 0x34, 0xc7, 0xed, 0x78, 0xd3, 0xa2, 0xf1, 0xc0, 0x76, 0xb1, 0xfd, 0xfd, 0xf7, 0xc5, 0xf6, 0x3a, 0xdc, - 0x92, 0x5e, 0x21, 0x67, 0x09, 0xfd, 0xfc, 0x51, 0xf6, 0x59, 0xc3, 0xc9, 0xa9, 0xd0, 0x0c, 0x2d, 0x45, 0x42, 0x29, - 0xde, 0xe9, 0x49, 0x81, 0xb1, 0x8c, 0x85, 0xbf, 0x07, 0xce, 0xe9, 0x42, 0x11, 0xb9, 0x03, 0xc7, 0xf1, 0x0d, 0x54, - 0x30, 0x6a, 0x38, 0x78, 0x19, 0xc3, 0xb6, 0x28, 0x66, 0x21, 0xe1, 0x14, 0xc2, 0xc5, 0x2a, 0xeb, 0xf7, 0xe5, 0x2f, - 0xea, 0xa2, 0x8b, 0x4c, 0xd6, 0x7d, 0x12, 0x8e, 0xcc, 0x58, 0x4e, 0xbd, 0x90, 0x3c, 0xef, 0x79, 0x32, 0x4d, 0x9e, - 0xe5, 0x41, 0x04, 0x90, 0xcf, 0xe1, 0x7d, 0x98, 0x66, 0x60, 0x95, 0x26, 0xe5, 0x47, 0x28, 0x7d, 0xf1, 0x79, 0xe5, - 0x07, 0x3a, 0x7b, 0x6e, 0x92, 0xe1, 0xcd, 0xaa, 0xf5, 0x26, 0xb5, 0xae, 0x8b, 0x07, 0xfc, 0x8b, 0x33, 0xd8, 0x38, - 0xd7, 0x99, 0xe0, 0xc0, 0x8b, 0xa4, 0xd6, 0x6b, 0xc6, 0x5f, 0x64, 0xb8, 0x2e, 0x55, 0x1b, 0x7d, 0x14, 0xa2, 0x73, - 0xc8, 0x54, 0x80, 0x42, 0x91, 0xf6, 0x0f, 0x4a, 0xad, 0x4c, 0x2a, 0x6d, 0x24, 0x80, 0xee, 0x61, 0xd2, 0x60, 0x8b, - 0xa1, 0x8c, 0xa5, 0x49, 0x94, 0x3b, 0x0d, 0xe2, 0xca, 0xfe, 0x5c, 0x49, 0x1c, 0x5a, 0x16, 0xc9, 0xbf, 0x77, 0x3d, - 0x7d, 0x85, 0xd4, 0x9d, 0x2c, 0x90, 0x19, 0xe3, 0x65, 0x1e, 0x7f, 0x02, 0xc2, 0x6c, 0xd0, 0x46, 0x45, 0x21, 0x84, - 0x6c, 0x10, 0x83, 0xc6, 0xcb, 0x3c, 0xfe, 0x5e, 0xd1, 0x78, 0xc8, 0x47, 0x91, 0xaf, 0xfe, 0x2a, 0xf5, 0x5f, 0xa1, - 0xcf, 0x4c, 0xf0, 0x08, 0xd5, 0x44, 0xff, 0xee, 0xf9, 0xec, 0x1e, 0xd4, 0x86, 0x51, 0x98, 0x99, 0xf2, 0x2b, 0xdf, - 0x14, 0x67, 0xaf, 0xbf, 0xa2, 0xab, 0x6c, 0xeb, 0x7e, 0xf4, 0xf1, 0x88, 0xc0, 0xda, 0x18, 0x5d, 0x71, 0x63, 0x00, - 0x39, 0x4c, 0xde, 0xaf, 0x28, 0x2d, 0x87, 0x34, 0x08, 0x1d, 0x34, 0x04, 0xbd, 0x92, 0xe8, 0x03, 0x89, 0x45, 0x8c, - 0xe1, 0x85, 0x78, 0x46, 0x6a, 0x32, 0xd1, 0x10, 0xaf, 0x88, 0xfd, 0x10, 0x2d, 0x39, 0x35, 0xd1, 0x8d, 0x30, 0xc5, - 0x40, 0x62, 0x67, 0x90, 0x9c, 0x24, 0xb5, 0xf2, 0x8b, 0x67, 0x92, 0xb0, 0xc4, 0xce, 0x43, 0x0c, 0x26, 0xb5, 0x74, - 0xa7, 0x37, 0x55, 0x7a, 0x77, 0xa4, 0xe5, 0xa0, 0x7d, 0x00, 0x76, 0x29, 0xe9, 0xfd, 0x93, 0x42, 0x11, 0x1f, 0xc2, - 0x38, 0x86, 0xf0, 0x2d, 0xa2, 0xba, 0x02, 0xe7, 0x5a, 0x81, 0xc6, 0x6a, 0xe0, 0xa1, 0x99, 0x55, 0xf3, 0x21, 0xa7, - 0x9f, 0x4a, 0xcb, 0x1f, 0x23, 0x1a, 0x1b, 0xad, 0x9b, 0xc3, 0x61, 0x4f, 0xab, 0x5e, 0x3a, 0x07, 0x5d, 0x36, 0x93, - 0x98, 0xb8, 0x81, 0x74, 0xfd, 0xe8, 0x37, 0x13, 0xf6, 0x22, 0x2a, 0xe4, 0x52, 0x08, 0x0a, 0x5a, 0x1d, 0x08, 0x1c, - 0x0a, 0x6f, 0x51, 0xe6, 0x8b, 0x98, 0x36, 0x10, 0x06, 0x9f, 0x1f, 0xc8, 0xcf, 0x37, 0x05, 0xa9, 0xd8, 0xb1, 0xae, - 0xfd, 0xfe, 0xa6, 0xf4, 0x00, 0x4f, 0xce, 0x24, 0x79, 0xda, 0x0c, 0x61, 0x45, 0x00, 0x8d, 0x59, 0x4d, 0x16, 0x27, - 0x5c, 0x99, 0xc3, 0x8f, 0x95, 0x57, 0xb2, 0x94, 0xa9, 0xf3, 0x54, 0x2f, 0x80, 0xa8, 0xe3, 0x0d, 0x5a, 0x91, 0xfa, - 0x15, 0x3a, 0x7b, 0xcd, 0x4a, 0xc8, 0x78, 0x78, 0xce, 0x79, 0x3a, 0x7a, 0x60, 0x09, 0x8f, 0xf0, 0xaf, 0x64, 0xa2, - 0x0f, 0xbf, 0x07, 0x0e, 0x37, 0xe3, 0x84, 0x47, 0x6e, 0xb3, 0xf7, 0x55, 0xb8, 0x82, 0x9b, 0x69, 0x01, 0x48, 0x6e, - 0x41, 0xd2, 0x04, 0x94, 0x90, 0xc8, 0x84, 0xcc, 0x9a, 0x92, 0x9f, 0x5b, 0xda, 0x06, 0x6b, 0x98, 0x74, 0x1e, 0xf0, - 0xa2, 0xd5, 0x47, 0xab, 0x89, 0x76, 0x99, 0xe5, 0xf3, 0x21, 0xce, 0x50, 0xcd, 0x71, 0x77, 0x06, 0x3f, 0x07, 0xbc, - 0x62, 0x55, 0x93, 0x8e, 0x76, 0x03, 0x2e, 0x3c, 0xb9, 0xce, 0xd3, 0xd1, 0x16, 0x7f, 0xc9, 0xfd, 0x01, 0xa0, 0x83, - 0xa9, 0x4b, 0xe0, 0x4f, 0xd5, 0x56, 0x53, 0xa9, 0x5f, 0x5a, 0xfb, 0x75, 0xdd, 0x59, 0xad, 0xdc, 0xb3, 0x2e, 0x43, - 0x7b, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, - 0x82, 0x7b, 0xc9, 0x5f, 0xec, 0x11, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, - 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xb1, 0x34, 0x26, 0x45, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0x6d, 0x7b, 0xdb, 0xb6, 0xb2, 0x28, 0xfa, + 0xf9, 0x9e, 0x5f, 0x61, 0x73, 0xa7, 0x2e, 0x61, 0x41, 0xb4, 0x24, 0x5b, 0x8e, 0x43, 0x19, 0xd6, 0x71, 0x9c, 0xa4, + 0x49, 0x9b, 0x26, 0x69, 0x9c, 0x26, 0x4d, 0x54, 0x6d, 0x07, 0x22, 0x21, 0x09, 0x0d, 0x45, 0xa8, 0x04, 0x14, 0xdb, + 0x95, 0xf4, 0xdf, 0xef, 0x33, 0x78, 0x21, 0x41, 0x49, 0xc9, 0x5a, 0xeb, 0xdc, 0x73, 0xee, 0x73, 0x76, 0xf7, 0x8a, + 0x45, 0xbc, 0x63, 0x30, 0x18, 0xcc, 0x0c, 0x66, 0x06, 0xe7, 0xfb, 0xa9, 0x48, 0xd4, 0xfd, 0x9c, 0xed, 0x4d, 0xd5, + 0x2c, 0xbb, 0x38, 0xb7, 0xff, 0x32, 0x9a, 0x5e, 0x9c, 0x67, 0x3c, 0xff, 0xb2, 0x57, 0xb0, 0x8c, 0xf0, 0x44, 0xe4, + 0x7b, 0xd3, 0x82, 0x8d, 0x49, 0x4a, 0x15, 0x8d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xc5, 0xf9, 0x8c, 0x29, 0xba, + 0x97, 0x4c, 0x69, 0x21, 0x99, 0x22, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbb, 0x38, 0x97, 0x49, 0xc1, 0xe7, 0x6a, 0x0f, + 0x9a, 0x24, 0x33, 0x91, 0x2e, 0x32, 0x76, 0x71, 0x74, 0x74, 0x7b, 0x7b, 0x1b, 0xfd, 0x25, 0xff, 0xc7, 0x57, 0x5a, + 0xec, 0xfd, 0x52, 0x90, 0xd7, 0xa3, 0xbf, 0x58, 0xa2, 0xa2, 0x94, 0x8d, 0x79, 0xce, 0xde, 0x14, 0x62, 0xce, 0x0a, + 0x75, 0xdf, 0x83, 0xcc, 0x9f, 0x0a, 0x12, 0x72, 0xac, 0x30, 0x43, 0xe4, 0x42, 0xed, 0xf1, 0x7c, 0x8f, 0xf7, 0x7f, + 0x29, 0x74, 0xca, 0x92, 0xe5, 0x8b, 0x19, 0x2b, 0xe8, 0x28, 0x63, 0xf1, 0x7e, 0x0b, 0x27, 0x22, 0x1f, 0xf3, 0xc9, + 0xa2, 0xfc, 0xbe, 0x2d, 0xb8, 0x72, 0xbf, 0xbf, 0xd2, 0x6c, 0xc1, 0x62, 0xb6, 0x46, 0x31, 0x1f, 0xa8, 0x21, 0x61, + 0xba, 0xe5, 0x2f, 0x55, 0xc3, 0xe1, 0x4f, 0xba, 0xc9, 0xfb, 0x39, 0x13, 0xe3, 0x3d, 0xb5, 0x4f, 0x02, 0x79, 0x3f, + 0x1b, 0x89, 0x2c, 0xe8, 0xab, 0x46, 0x10, 0xc4, 0x50, 0x06, 0x33, 0xd4, 0x4b, 0x44, 0x2e, 0xd5, 0x9e, 0xe4, 0xe4, + 0x96, 0xe7, 0xa9, 0xb8, 0xc5, 0x5f, 0x25, 0x91, 0x3c, 0xba, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x1d, 0x1c, + 0x84, 0xf6, 0xfb, 0xfe, 0xea, 0xfa, 0x9a, 0x10, 0xf2, 0x55, 0xf0, 0x74, 0xaf, 0xb5, 0x5a, 0x79, 0xa9, 0x51, 0x4e, + 0x15, 0xff, 0xca, 0x4c, 0x25, 0x74, 0x70, 0x10, 0xd0, 0x54, 0xcc, 0x15, 0x4b, 0xaf, 0xd5, 0x7d, 0xc6, 0xae, 0xa7, + 0x8c, 0x29, 0x19, 0xf0, 0x7c, 0xef, 0x89, 0x48, 0x16, 0x33, 0x96, 0xab, 0x68, 0x5e, 0x08, 0x25, 0x60, 0x60, 0x07, + 0x07, 0x41, 0xc1, 0xe6, 0x19, 0x4d, 0x18, 0xe4, 0x5f, 0x5d, 0x5f, 0x57, 0x35, 0xaa, 0x42, 0xf8, 0x56, 0x92, 0x6b, + 0x3d, 0xf4, 0x10, 0xe1, 0xe7, 0x92, 0xe4, 0xec, 0x76, 0xef, 0x03, 0xa3, 0x5f, 0x7e, 0xa5, 0xf3, 0x5e, 0x92, 0x51, + 0x29, 0xf7, 0x9e, 0x89, 0xa5, 0x9e, 0x46, 0xb1, 0x48, 0x94, 0x28, 0x42, 0x85, 0x19, 0x96, 0x68, 0xc9, 0xc7, 0xa1, + 0x9a, 0x72, 0x19, 0xdd, 0x3c, 0x48, 0xa4, 0x7c, 0xcb, 0xe4, 0x22, 0x53, 0x0f, 0xc8, 0x7e, 0x0b, 0xcb, 0x7d, 0x42, + 0x6e, 0x25, 0x52, 0xd3, 0x42, 0xdc, 0xee, 0x3d, 0x2d, 0x0a, 0x51, 0x84, 0xc1, 0xd5, 0xf5, 0xb5, 0x29, 0xb1, 0xc7, + 0xe5, 0x5e, 0x2e, 0xd4, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xda, 0xfb, 0x5d, 0xb2, 0xbd, 0xcf, 0x8b, 0x5c, 0xd2, 0x31, + 0xbb, 0xba, 0xbe, 0xfe, 0xbc, 0x27, 0x8a, 0xbd, 0xcf, 0x89, 0x94, 0x9f, 0xf7, 0x78, 0x2e, 0x15, 0xa3, 0x69, 0x14, + 0xa0, 0x9e, 0xee, 0x2c, 0x91, 0xf2, 0x1d, 0xbb, 0x53, 0x44, 0x61, 0xfd, 0xa9, 0x08, 0x5b, 0x4f, 0x98, 0xda, 0x93, + 0xe5, 0xbc, 0x42, 0xb4, 0xcc, 0x98, 0xda, 0x53, 0x44, 0xe7, 0x0b, 0x0b, 0x7f, 0x66, 0x3e, 0x55, 0x8f, 0x8f, 0xc3, + 0xaf, 0xf2, 0xe0, 0x40, 0x95, 0x80, 0x46, 0x4b, 0xbb, 0x42, 0x84, 0xed, 0xbb, 0xb4, 0x83, 0x03, 0x16, 0x65, 0x2c, + 0x9f, 0xa8, 0x29, 0x21, 0xa4, 0xdd, 0x93, 0x07, 0x07, 0xa1, 0x22, 0xcf, 0x65, 0x34, 0x61, 0x2a, 0x64, 0x08, 0xe1, + 0xaa, 0xf6, 0xc1, 0x41, 0x68, 0x80, 0x20, 0x88, 0xd2, 0x80, 0xab, 0xc1, 0x18, 0x45, 0x16, 0xfa, 0xd7, 0xf7, 0x79, + 0x12, 0xfa, 0xe3, 0x47, 0x58, 0x1e, 0x1c, 0x3c, 0x97, 0x91, 0x84, 0x16, 0xb1, 0x42, 0x68, 0x5d, 0x30, 0xb5, 0x28, + 0xf2, 0x3d, 0xb5, 0x56, 0xe2, 0x5a, 0x15, 0x3c, 0x9f, 0x84, 0x68, 0xe9, 0xd2, 0xbc, 0x8a, 0xeb, 0xb5, 0x19, 0xee, + 0x6f, 0x05, 0xe1, 0xe4, 0x02, 0x7a, 0x7c, 0x26, 0x42, 0x8b, 0x83, 0x9c, 0x90, 0x40, 0xea, 0xba, 0x41, 0x9f, 0xc7, + 0xbc, 0x11, 0x04, 0xd8, 0x8c, 0x12, 0xdf, 0x4a, 0x84, 0xb9, 0x02, 0xd4, 0x8d, 0xa2, 0x48, 0x21, 0x72, 0xb1, 0x74, + 0x60, 0xe1, 0xde, 0x44, 0xfb, 0x7c, 0xd0, 0x1a, 0xc6, 0x2a, 0x2a, 0x58, 0xba, 0x48, 0x58, 0x18, 0x4a, 0x9c, 0x63, + 0x81, 0xc8, 0x85, 0x6c, 0x84, 0x05, 0xb9, 0x80, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xd9, 0x41, 0x16, + 0x6e, 0x84, 0x00, 0x62, 0x3b, 0xa0, 0x82, 0x90, 0x20, 0x5f, 0xcc, 0x46, 0xac, 0x08, 0xca, 0x62, 0xbd, 0x1a, 0x5e, + 0x2c, 0x24, 0xdb, 0x4b, 0xa4, 0xdc, 0x1b, 0x2f, 0xf2, 0x44, 0x71, 0x91, 0xef, 0x05, 0x8d, 0xa2, 0x11, 0x18, 0x7c, + 0x28, 0xd1, 0x21, 0x40, 0x6b, 0x14, 0xe6, 0xa8, 0xc1, 0x07, 0xa2, 0xd1, 0x1e, 0x62, 0x18, 0x25, 0xea, 0xd9, 0xf6, + 0x2c, 0x04, 0x18, 0xe6, 0x30, 0xc9, 0x35, 0xfe, 0x64, 0x76, 0x3e, 0x4c, 0xf1, 0xab, 0xec, 0xf3, 0x68, 0x7b, 0xa7, + 0x10, 0x15, 0xcd, 0xe8, 0x3c, 0x64, 0xe4, 0x82, 0x69, 0xec, 0xa2, 0x79, 0x02, 0x63, 0xad, 0x2d, 0x5c, 0x9f, 0xc5, + 0x2c, 0xaa, 0x70, 0x0a, 0xc5, 0x2a, 0x1a, 0x8b, 0xe2, 0x29, 0x4d, 0xa6, 0x50, 0xaf, 0xc4, 0x98, 0xd4, 0x6d, 0xb8, + 0xa4, 0x60, 0x54, 0xb1, 0xa7, 0x19, 0x83, 0xaf, 0x30, 0xd0, 0x35, 0x03, 0x84, 0x73, 0xd8, 0xea, 0x19, 0x57, 0xaf, + 0x44, 0x9e, 0xb0, 0x5e, 0xee, 0xe1, 0x97, 0x5e, 0xf9, 0x4b, 0xa5, 0x0a, 0x3e, 0x5a, 0x28, 0x16, 0x06, 0x39, 0x94, + 0x08, 0x70, 0x8e, 0xb0, 0x8c, 0x14, 0xbb, 0x53, 0x57, 0x22, 0x57, 0x2c, 0x57, 0x84, 0x39, 0xa8, 0x62, 0x1e, 0xd1, + 0xf9, 0x9c, 0xe5, 0xe9, 0xd5, 0x94, 0x67, 0x69, 0x28, 0xd1, 0x1a, 0xad, 0xf1, 0x07, 0x49, 0x60, 0x92, 0xe4, 0x82, + 0xc7, 0xf0, 0xcf, 0xb7, 0xa7, 0x13, 0x2a, 0x72, 0xa1, 0xb7, 0x05, 0x23, 0x41, 0xd0, 0x1b, 0x8b, 0x22, 0xb4, 0x53, + 0xd8, 0x03, 0xd2, 0x05, 0x7d, 0xbc, 0x5d, 0x64, 0x4c, 0x22, 0xd6, 0x20, 0x25, 0xa6, 0x39, 0x08, 0xff, 0x56, 0x84, + 0x0c, 0x16, 0x80, 0xa3, 0x98, 0x6b, 0x12, 0xf8, 0x92, 0xdb, 0x4d, 0x95, 0x96, 0x44, 0xed, 0x77, 0x49, 0x52, 0x1e, + 0xa9, 0x62, 0x21, 0x15, 0x4b, 0xdf, 0xdd, 0xcf, 0x99, 0xc4, 0x3f, 0x17, 0xe4, 0x77, 0xd9, 0xff, 0x5d, 0x46, 0x6c, + 0x36, 0x57, 0xf7, 0xd7, 0x9a, 0x9a, 0xc7, 0x41, 0x80, 0x3f, 0xea, 0xa2, 0x05, 0xa3, 0x09, 0x90, 0x34, 0x0b, 0xb2, + 0x37, 0x22, 0xbb, 0x1f, 0xf3, 0x2c, 0xbb, 0x5e, 0xcc, 0xe7, 0xa2, 0x50, 0x58, 0x49, 0xb2, 0x54, 0xa2, 0x82, 0x0f, + 0xac, 0xe8, 0x52, 0xde, 0x72, 0x95, 0x4c, 0x43, 0x85, 0x96, 0x09, 0x95, 0x6c, 0xef, 0xb1, 0x10, 0x19, 0xa3, 0x79, + 0xcc, 0x09, 0xef, 0xff, 0x5c, 0xc4, 0xf9, 0x22, 0xcb, 0x7a, 0xa3, 0x82, 0xd1, 0x2f, 0x3d, 0x9d, 0x6d, 0x0e, 0x87, + 0x58, 0xff, 0xbe, 0x2c, 0x0a, 0x7a, 0x0f, 0x05, 0x09, 0x81, 0x62, 0x7d, 0x1e, 0xff, 0x7c, 0xfd, 0xfa, 0x55, 0x64, + 0xf6, 0x0a, 0x1f, 0xdf, 0x87, 0xbc, 0xdc, 0x7f, 0x7c, 0x8d, 0xc7, 0x85, 0x98, 0x6d, 0x74, 0x6d, 0x40, 0xc7, 0x7b, + 0xdf, 0x18, 0x02, 0x23, 0x7c, 0xdf, 0x34, 0xed, 0x8f, 0xe0, 0x95, 0xc6, 0x7c, 0xc8, 0x24, 0xb6, 0x5f, 0xf8, 0x27, + 0x36, 0xc9, 0x21, 0x47, 0xdf, 0x1f, 0xad, 0x2a, 0xee, 0x97, 0x8c, 0xe8, 0x71, 0xce, 0xe1, 0x60, 0x84, 0x31, 0x26, + 0x54, 0x25, 0xd3, 0x25, 0xd3, 0x8d, 0xad, 0xdd, 0x88, 0xd9, 0x7a, 0x8d, 0x5f, 0x09, 0x87, 0xf5, 0x6a, 0x9f, 0x10, + 0xae, 0xe9, 0x15, 0x51, 0xab, 0x15, 0x27, 0x84, 0x23, 0xfc, 0x96, 0x93, 0x25, 0x75, 0x13, 0x82, 0x93, 0x0d, 0xb6, + 0x67, 0x6c, 0xa8, 0x0c, 0x9c, 0x80, 0x5f, 0x59, 0xa1, 0x58, 0x11, 0x2b, 0x89, 0x0b, 0x36, 0xce, 0x60, 0x1c, 0xfb, + 0x6d, 0x3c, 0xa5, 0xf2, 0x6a, 0x4a, 0xf3, 0x09, 0x4b, 0xe3, 0x57, 0x62, 0x8d, 0x99, 0x24, 0xc1, 0x98, 0xe7, 0x34, + 0xe3, 0xff, 0xb0, 0x34, 0xb0, 0xe7, 0xc2, 0x63, 0xb5, 0xc7, 0xee, 0x14, 0xcb, 0x53, 0xb9, 0xf7, 0xfc, 0xdd, 0xaf, + 0x2f, 0xed, 0x62, 0xd6, 0xce, 0x0a, 0xb4, 0x94, 0x8b, 0x39, 0x2b, 0x42, 0x84, 0xed, 0x59, 0xf1, 0x94, 0x6b, 0x3a, + 0xf9, 0x2b, 0x9d, 0x9b, 0x14, 0x2e, 0x7f, 0x9f, 0xa7, 0x54, 0xb1, 0x37, 0x2c, 0x4f, 0x79, 0x3e, 0x21, 0xfb, 0x6d, + 0x93, 0x3e, 0xa5, 0x36, 0x23, 0x2d, 0x93, 0x6e, 0x1e, 0x3c, 0xcd, 0xf4, 0xdc, 0xcb, 0xcf, 0x45, 0x88, 0xd6, 0x52, + 0x51, 0xc5, 0x93, 0x3d, 0x9a, 0xa6, 0x2f, 0x72, 0xae, 0xb8, 0x1e, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xcc, 0xa9, + 0xe1, 0x46, 0x1e, 0x22, 0x1c, 0x86, 0xf6, 0x2c, 0x98, 0x22, 0xbb, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb3, 0xd8, + 0x64, 0x92, 0xc1, 0x10, 0x45, 0xf3, 0x85, 0x84, 0xc5, 0x76, 0x5d, 0xc0, 0x41, 0x23, 0x46, 0x92, 0x15, 0x5f, 0x59, + 0x5a, 0x22, 0x88, 0x0c, 0xd1, 0x72, 0xa3, 0x0f, 0xbb, 0x3d, 0x14, 0x19, 0x0c, 0x7b, 0x3e, 0x09, 0x67, 0x16, 0xd9, + 0x0d, 0xa7, 0xc2, 0x99, 0x2c, 0x89, 0x4a, 0x08, 0x07, 0x6a, 0x49, 0x58, 0x72, 0xe2, 0xe6, 0x37, 0x0f, 0x25, 0xf0, + 0x10, 0x3e, 0xe5, 0x70, 0x67, 0xee, 0xd3, 0xaf, 0xfa, 0xf0, 0xc8, 0xb1, 0x44, 0x58, 0x99, 0x91, 0xe6, 0x08, 0xad, + 0x11, 0x56, 0x6e, 0xb8, 0x86, 0x28, 0x39, 0xbe, 0x08, 0x4e, 0x6d, 0xf2, 0x96, 0xeb, 0x63, 0x1b, 0x68, 0x1b, 0x55, + 0xec, 0xe0, 0x20, 0x64, 0x51, 0x89, 0x18, 0x64, 0xbf, 0x6d, 0x17, 0xc9, 0x83, 0xd6, 0x37, 0xc6, 0x0d, 0x3d, 0x6b, + 0x06, 0x67, 0x9f, 0x45, 0xb9, 0xb8, 0x4c, 0x12, 0x26, 0xa5, 0x28, 0x0e, 0x0e, 0xf6, 0x75, 0xf9, 0x92, 0xb3, 0x80, + 0x45, 0x7c, 0x7d, 0x9b, 0x57, 0x43, 0x40, 0xd5, 0x69, 0xeb, 0xf8, 0x26, 0x52, 0xf1, 0x4d, 0x8e, 0x09, 0x89, 0x83, + 0x9b, 0x9b, 0xa0, 0xa1, 0xb0, 0x85, 0xc3, 0x84, 0xb9, 0xae, 0xef, 0x9f, 0x30, 0xc3, 0x16, 0x6a, 0x26, 0x64, 0x0b, + 0x34, 0x3b, 0xf9, 0xc1, 0xb0, 0x3e, 0x24, 0xac, 0x70, 0x8e, 0xd6, 0xde, 0x8a, 0xee, 0x6c, 0x5a, 0xf3, 0x37, 0x66, + 0xe9, 0x96, 0x13, 0xcd, 0x53, 0x78, 0xeb, 0x38, 0x60, 0xc3, 0x35, 0xd6, 0xb0, 0x77, 0xb3, 0x11, 0x7a, 0xa0, 0x03, + 0x35, 0xec, 0xd9, 0x7c, 0x92, 0x1b, 0xc8, 0x15, 0xec, 0xef, 0x05, 0x93, 0xca, 0x20, 0x72, 0xa8, 0xb0, 0xc0, 0x70, + 0x46, 0x6d, 0x32, 0x9d, 0x35, 0x96, 0x74, 0xd7, 0xd8, 0x5e, 0xcf, 0xe1, 0x6c, 0x94, 0x80, 0xd4, 0xdf, 0xc7, 0x27, + 0x18, 0xab, 0x42, 0xab, 0xd5, 0x5b, 0xee, 0x5a, 0xa9, 0xd6, 0xb2, 0xe4, 0xd7, 0x36, 0x16, 0x85, 0x49, 0x64, 0x0f, + 0xe7, 0xfd, 0xb6, 0x1d, 0xbf, 0x1c, 0x92, 0xfd, 0x56, 0x89, 0xc5, 0x16, 0xac, 0x66, 0x3c, 0x06, 0x8a, 0xaf, 0x4d, + 0x53, 0x48, 0x9f, 0xf5, 0x35, 0x7c, 0x89, 0xa6, 0x5b, 0xb8, 0x3a, 0x25, 0x03, 0xe0, 0x3a, 0xa2, 0xe9, 0xf0, 0x5b, + 0xf8, 0xe4, 0x28, 0x42, 0xa8, 0xb6, 0xf3, 0x2a, 0xc2, 0xf1, 0xb5, 0x4e, 0x38, 0x36, 0xa6, 0x11, 0xcc, 0xcb, 0x2a, + 0x41, 0x89, 0x66, 0x76, 0xab, 0x57, 0x59, 0x58, 0xea, 0xc1, 0x54, 0x53, 0xf2, 0x9a, 0x78, 0x45, 0x67, 0x4c, 0x86, + 0x0c, 0xe1, 0x6f, 0x15, 0x30, 0xf8, 0x09, 0x45, 0x86, 0xde, 0x19, 0x9a, 0xc3, 0x19, 0x0a, 0xec, 0x2e, 0x30, 0x69, + 0xf5, 0x2d, 0x97, 0x63, 0x36, 0xc8, 0x87, 0x15, 0x6f, 0xe7, 0x4d, 0x5e, 0x1f, 0xce, 0x92, 0xd4, 0xf6, 0x9b, 0x49, + 0x33, 0x40, 0xd3, 0x2c, 0x84, 0x44, 0x78, 0xbf, 0xb5, 0xb9, 0x92, 0xae, 0x54, 0x35, 0xc7, 0xc1, 0x10, 0xd6, 0x41, + 0x1f, 0x1b, 0x11, 0x97, 0xfa, 0x6f, 0x6d, 0xab, 0x01, 0xd8, 0xae, 0x01, 0x33, 0xa2, 0x71, 0x46, 0x55, 0xd8, 0x3e, + 0x6a, 0x01, 0x63, 0xfa, 0x95, 0xc1, 0xa9, 0x82, 0xd0, 0xf6, 0x54, 0x58, 0xb4, 0xc8, 0xe5, 0x94, 0x8f, 0x55, 0xf8, + 0x41, 0x6a, 0xa2, 0xc2, 0x32, 0xc9, 0x40, 0xc2, 0xf1, 0xd8, 0x63, 0x4d, 0x70, 0x3e, 0xc0, 0x30, 0x4a, 0x56, 0x8c, + 0xb9, 0x91, 0x6a, 0xc2, 0x05, 0xe4, 0xa1, 0x62, 0xad, 0x2b, 0x32, 0xe3, 0x4a, 0x4b, 0xe0, 0x1e, 0xdb, 0x7d, 0xd3, + 0x62, 0x6c, 0xa9, 0x81, 0xf4, 0x38, 0x58, 0x19, 0xfb, 0x24, 0xc2, 0x26, 0xaa, 0x48, 0x89, 0x97, 0xe2, 0x96, 0x15, + 0x57, 0x14, 0x06, 0x1f, 0x9b, 0xea, 0x6b, 0x73, 0x14, 0x68, 0x8a, 0xaf, 0x7a, 0x0e, 0x5f, 0x6e, 0xf4, 0xc4, 0xdf, + 0x14, 0x62, 0xc6, 0x25, 0x03, 0xbe, 0xcd, 0xc0, 0x3f, 0x87, 0x8d, 0xa6, 0x77, 0x24, 0x1c, 0x37, 0xac, 0xc4, 0xaf, + 0xcb, 0x97, 0x75, 0xfc, 0xba, 0x79, 0xf0, 0x74, 0xe2, 0x28, 0x60, 0x7d, 0x1f, 0x23, 0x1c, 0x5a, 0xf1, 0xc2, 0x3b, + 0xe9, 0xa2, 0x29, 0xb2, 0xc7, 0xfc, 0x6a, 0xa5, 0x3c, 0x31, 0xae, 0xc6, 0x39, 0x32, 0xb3, 0x6d, 0xd0, 0x9a, 0xa6, + 0x29, 0xb0, 0x78, 0x85, 0xc8, 0x32, 0xef, 0xb0, 0xc2, 0xb2, 0x57, 0x1e, 0x4f, 0x37, 0x0f, 0x9e, 0x5e, 0x7f, 0xef, + 0x84, 0x82, 0x7c, 0xff, 0x90, 0x72, 0x03, 0xcd, 0x53, 0x56, 0x80, 0x5c, 0xe9, 0xad, 0x96, 0x3d, 0x67, 0xaf, 0x44, + 0x9e, 0xb3, 0x44, 0xb1, 0x14, 0x84, 0x16, 0x60, 0x83, 0xa7, 0x42, 0xaa, 0x32, 0xb1, 0x1a, 0xbd, 0xf4, 0x85, 0xd0, + 0x28, 0xa1, 0x59, 0x16, 0x1a, 0x01, 0x65, 0x26, 0xbe, 0xb2, 0x1d, 0xa3, 0xee, 0xd5, 0x86, 0x5c, 0x36, 0xc3, 0xbc, + 0x66, 0x58, 0x24, 0xe7, 0x19, 0x4f, 0x58, 0x79, 0x78, 0x5d, 0x47, 0x3c, 0x4f, 0xd9, 0x1d, 0xd0, 0x11, 0x74, 0x71, + 0x71, 0xd1, 0xc2, 0x6d, 0xb4, 0x36, 0x00, 0x5f, 0x6e, 0x01, 0xf6, 0x3b, 0xc7, 0xa6, 0x11, 0xc4, 0x97, 0x3b, 0xc9, + 0x1a, 0xf2, 0xce, 0x4a, 0xee, 0x04, 0x2d, 0x43, 0x9e, 0x11, 0x4e, 0x59, 0xc6, 0x14, 0x73, 0xe4, 0x1c, 0x98, 0x69, + 0xb3, 0x75, 0xdf, 0x96, 0xf0, 0x2b, 0xd1, 0xc9, 0xed, 0x32, 0xb7, 0xe6, 0xb2, 0x14, 0xdd, 0xab, 0xe5, 0xa9, 0xa0, + 0xdd, 0x57, 0x66, 0x79, 0xa8, 0x52, 0x34, 0x99, 0x1a, 0x89, 0x3d, 0xdc, 0x9a, 0x52, 0xd5, 0x86, 0x25, 0xed, 0xe5, + 0x26, 0xfa, 0x54, 0xd8, 0x61, 0xee, 0x02, 0xc1, 0xb5, 0x25, 0x0a, 0x0c, 0x84, 0x40, 0xb3, 0x6c, 0x57, 0x34, 0xcb, + 0x46, 0x34, 0xf9, 0x52, 0xc7, 0xfe, 0x0a, 0x0d, 0xc8, 0x26, 0x35, 0xf6, 0xb2, 0x3c, 0x92, 0xe5, 0xcf, 0xdb, 0x51, + 0xe9, 0xda, 0x46, 0x09, 0xf7, 0x5b, 0x15, 0xda, 0xd7, 0x17, 0xfa, 0x9b, 0xd8, 0xae, 0x47, 0x24, 0xed, 0xcc, 0x42, + 0xa0, 0x02, 0xff, 0x12, 0xe3, 0x1c, 0x3d, 0xb0, 0x78, 0x07, 0x82, 0xc7, 0x7a, 0x63, 0x20, 0x0a, 0x2d, 0xd7, 0x29, + 0x97, 0xdf, 0x86, 0xc0, 0xff, 0x96, 0x51, 0x3e, 0xf1, 0x7a, 0xf8, 0x77, 0x07, 0x5a, 0xd2, 0x38, 0xcb, 0x38, 0x97, + 0x23, 0xb3, 0x0c, 0x85, 0x23, 0x34, 0xbf, 0x00, 0xf3, 0xa2, 0xf1, 0xfd, 0xb5, 0xc9, 0xd2, 0x7c, 0x19, 0x0c, 0x23, + 0xef, 0xf9, 0x0c, 0x45, 0x0d, 0x05, 0x2c, 0x51, 0x35, 0x67, 0xae, 0xa8, 0x89, 0x92, 0x96, 0x6b, 0x37, 0xe2, 0xb8, + 0xa5, 0xb9, 0x05, 0x09, 0xc3, 0x30, 0x27, 0xba, 0x0d, 0xc3, 0xdf, 0x57, 0xb3, 0xc8, 0xb7, 0x66, 0x91, 0x47, 0x9e, + 0xb4, 0x85, 0x2a, 0x64, 0xf6, 0xaa, 0xc7, 0x4a, 0x22, 0xbf, 0x14, 0xb0, 0xac, 0x11, 0x50, 0x68, 0x54, 0x12, 0xdc, + 0x8c, 0x28, 0x5c, 0x58, 0x51, 0xc7, 0xe2, 0x1a, 0x90, 0x8c, 0xaa, 0x8a, 0x40, 0x66, 0x73, 0xd4, 0x64, 0x5f, 0x81, + 0x0b, 0xb4, 0xc1, 0xdf, 0xaf, 0xd7, 0x16, 0x4a, 0x0c, 0xd9, 0xd5, 0xa9, 0x31, 0xc6, 0x1e, 0x58, 0xb0, 0x20, 0xb9, + 0x61, 0x86, 0x0d, 0xeb, 0xb3, 0x09, 0x9c, 0xb2, 0xdd, 0x7d, 0x42, 0x44, 0x05, 0x9b, 0x3c, 0xda, 0xc1, 0x5d, 0x09, + 0x84, 0xa9, 0x63, 0x4b, 0x8b, 0x6a, 0xe2, 0x84, 0x04, 0x4e, 0x3b, 0x11, 0xf4, 0x97, 0x35, 0xe1, 0x30, 0xf6, 0x8a, + 0xad, 0x63, 0x20, 0xaa, 0xc5, 0x2e, 0x78, 0xef, 0xc2, 0x9a, 0x5a, 0x3b, 0x1e, 0xc4, 0x8b, 0x1a, 0xc4, 0x3d, 0xd0, + 0x0a, 0x43, 0xbc, 0xc4, 0x90, 0xd0, 0x7a, 0xe5, 0x90, 0xe1, 0xc2, 0x2c, 0xc4, 0x16, 0x14, 0x37, 0xd9, 0x4f, 0x8d, + 0x85, 0x20, 0xcb, 0xe6, 0xc0, 0xdf, 0xf9, 0x47, 0x44, 0x08, 0x83, 0x97, 0xab, 0xd5, 0x16, 0xda, 0xed, 0xe4, 0x42, + 0x51, 0x54, 0x49, 0x87, 0xab, 0xd5, 0x2b, 0x81, 0x42, 0xcb, 0xff, 0x62, 0x86, 0xfa, 0x8e, 0xe8, 0x5e, 0xbe, 0x84, + 0x52, 0x9a, 0x1d, 0xad, 0x52, 0x4a, 0xc1, 0xa1, 0x8e, 0xb5, 0xf5, 0x85, 0x52, 0x1e, 0xe5, 0xbe, 0xda, 0x22, 0x60, + 0x3a, 0xd1, 0x9e, 0xd4, 0xd5, 0x94, 0xaf, 0x6c, 0xd3, 0x12, 0x21, 0x14, 0xe7, 0x5a, 0x96, 0xd9, 0xdf, 0x25, 0x5f, + 0x1e, 0x1c, 0xe4, 0x5e, 0x43, 0x37, 0x25, 0xa5, 0xf8, 0x2b, 0x84, 0x53, 0x59, 0xde, 0xe7, 0x9a, 0x7d, 0xf9, 0xcb, + 0x9d, 0x43, 0x5b, 0xd2, 0x69, 0xab, 0x07, 0x82, 0x39, 0xbd, 0xa5, 0x5c, 0xed, 0x95, 0xad, 0x18, 0xc1, 0x3c, 0x64, + 0x68, 0x69, 0xb9, 0x8d, 0xa8, 0x60, 0xc0, 0x3f, 0x02, 0x59, 0x70, 0x5c, 0xb4, 0x41, 0xfc, 0x64, 0xca, 0x40, 0x95, + 0xed, 0x18, 0x89, 0x52, 0x3c, 0xdc, 0xb7, 0x07, 0x89, 0x6d, 0x78, 0xf7, 0xd8, 0xd7, 0x9b, 0xd5, 0x6b, 0xd2, 0xc0, + 0x9c, 0x15, 0x63, 0x51, 0xcc, 0x5c, 0xde, 0x7a, 0xe3, 0xdb, 0x12, 0x47, 0x3e, 0x0e, 0x77, 0xb6, 0x6d, 0x45, 0x80, + 0xde, 0x86, 0xec, 0x5d, 0x49, 0xed, 0xb5, 0xd3, 0xb4, 0x3c, 0x80, 0x8d, 0x82, 0xd0, 0x61, 0x66, 0xee, 0x4b, 0xf9, + 0x56, 0xbd, 0xda, 0x33, 0xba, 0x93, 0xfd, 0x76, 0xaf, 0x94, 0xfc, 0x1c, 0x36, 0xf4, 0x8c, 0x8e, 0xc3, 0x9e, 0xaa, + 0x62, 0x91, 0xa5, 0x76, 0xb0, 0x70, 0xc4, 0x59, 0x3c, 0xba, 0xe5, 0x59, 0x56, 0xa5, 0xfe, 0x27, 0xa4, 0x3d, 0xb7, + 0xa4, 0x5d, 0x38, 0xd2, 0x0e, 0xa4, 0x02, 0x48, 0xbb, 0x69, 0xae, 0xaa, 0x2e, 0xb6, 0xb6, 0xa7, 0x30, 0x44, 0x3d, + 0xd7, 0xe2, 0x34, 0xf4, 0xb7, 0x70, 0x23, 0x40, 0x25, 0xf3, 0xf5, 0x25, 0xb4, 0xfa, 0x18, 0x10, 0x03, 0x8d, 0x4e, + 0x93, 0xf9, 0x9a, 0x8a, 0x2f, 0x21, 0xc2, 0xf9, 0x9a, 0x95, 0x98, 0x7d, 0xf9, 0x14, 0x94, 0x76, 0xde, 0x74, 0xe0, + 0x1c, 0xd3, 0xc9, 0xff, 0x11, 0x1f, 0xe5, 0x66, 0x27, 0xed, 0xec, 0x72, 0x37, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0xd2, + 0xef, 0x53, 0x7b, 0x3d, 0x3d, 0x59, 0x4e, 0xaf, 0x5a, 0xef, 0xd5, 0x2a, 0xdc, 0x48, 0x01, 0x8d, 0xbe, 0x95, 0x52, + 0x8a, 0xb2, 0x75, 0xa0, 0x01, 0x3e, 0x64, 0x20, 0x61, 0x6d, 0x26, 0x5d, 0x9e, 0x72, 0x2f, 0xff, 0x95, 0x9e, 0x47, + 0x2b, 0xee, 0x4d, 0xfd, 0x2b, 0x31, 0x9b, 0x03, 0x43, 0xb6, 0x81, 0xd2, 0x13, 0x66, 0x3b, 0xac, 0xf2, 0xd7, 0x3b, + 0xd2, 0x6a, 0x75, 0xf4, 0x7e, 0xac, 0x61, 0x53, 0x29, 0x35, 0xef, 0xb7, 0xd6, 0x8b, 0x32, 0xa9, 0x24, 0x1c, 0xbb, + 0x74, 0x2b, 0x57, 0x9b, 0x9a, 0x19, 0x97, 0xf1, 0x3a, 0x94, 0x86, 0x0e, 0x4b, 0xa0, 0x75, 0x1e, 0xf9, 0x71, 0xe8, + 0xee, 0xaf, 0xff, 0xba, 0x02, 0xce, 0x72, 0xbd, 0x01, 0xbe, 0xe5, 0x7a, 0xfd, 0x58, 0x59, 0x49, 0x1b, 0x3f, 0xde, + 0x21, 0xf7, 0x96, 0xd0, 0xab, 0x32, 0xad, 0xcc, 0x38, 0x18, 0x42, 0xda, 0x16, 0x0b, 0x49, 0x96, 0x33, 0x91, 0xb2, + 0x38, 0x10, 0x73, 0x96, 0x07, 0x6b, 0xd0, 0xb3, 0x5a, 0x04, 0xf8, 0x28, 0xc3, 0xe5, 0xdb, 0xba, 0xbe, 0x35, 0x7e, + 0xac, 0xd6, 0xa0, 0x0a, 0x7b, 0xc9, 0x77, 0x28, 0x63, 0xdf, 0xb3, 0x42, 0x6a, 0x9e, 0xb4, 0x64, 0x6f, 0x5f, 0xf2, + 0xea, 0x80, 0x7a, 0xc9, 0xe3, 0x6f, 0x57, 0xa9, 0x04, 0x92, 0xa0, 0x1d, 0x9d, 0x46, 0xc7, 0x01, 0xd2, 0x1a, 0xe3, + 0x67, 0x4e, 0x63, 0xbc, 0x28, 0x35, 0xc6, 0xcf, 0x15, 0x59, 0x6c, 0x68, 0x8c, 0xff, 0x96, 0xe4, 0xb9, 0xea, 0x3f, + 0x77, 0xda, 0xf4, 0x37, 0x22, 0xe3, 0xc9, 0x7d, 0x18, 0x64, 0x5c, 0x35, 0xe1, 0x36, 0x31, 0xc0, 0x4b, 0x93, 0x01, + 0xaa, 0x46, 0xad, 0xef, 0x5e, 0x3b, 0xf9, 0x0f, 0x73, 0x49, 0x82, 0x07, 0x19, 0x57, 0x0f, 0x02, 0x3c, 0x55, 0xe4, + 0x33, 0xfc, 0x7a, 0xb0, 0x0c, 0x7f, 0xa5, 0x6a, 0x1a, 0x15, 0x34, 0x4f, 0xc5, 0x2c, 0x44, 0x8d, 0x20, 0x40, 0x91, + 0xd4, 0x42, 0xc8, 0x23, 0xb4, 0x7e, 0xf0, 0x19, 0xff, 0x23, 0x48, 0xd0, 0x0f, 0x1a, 0x53, 0x85, 0x15, 0x25, 0x9f, + 0xcf, 0x1f, 0x2c, 0xff, 0x11, 0xeb, 0x8b, 0xcf, 0xf8, 0xa9, 0x2a, 0xd5, 0xfa, 0xf8, 0x8e, 0x91, 0x10, 0x91, 0x8b, + 0xa7, 0x6e, 0x48, 0x57, 0x62, 0x66, 0x14, 0xfc, 0x01, 0xc2, 0x5f, 0x41, 0xaf, 0x7b, 0xc1, 0x2b, 0x22, 0x64, 0xef, + 0x60, 0xf6, 0x49, 0x20, 0xb4, 0xf2, 0x20, 0x38, 0x38, 0xf0, 0xd2, 0x4a, 0x16, 0x02, 0xff, 0x25, 0x48, 0x4d, 0x54, + 0xc7, 0x8c, 0x42, 0x4b, 0x7f, 0x89, 0x90, 0x23, 0xd7, 0x4c, 0xe8, 0x34, 0xd5, 0x76, 0xc7, 0xf2, 0x81, 0xd1, 0x3d, + 0x44, 0x5c, 0xb1, 0x82, 0x2a, 0x51, 0x0c, 0x91, 0xcf, 0x96, 0xe0, 0x57, 0x9c, 0x7c, 0x1e, 0xec, 0xfd, 0x3f, 0xff, + 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xf0, 0x33, 0x96, 0x8c, 0x1c, 0x9d, 0x87, 0xfd, 0x38, 0xdc, 0x6f, 0x36, 0x57, 0x7f, + 0x1e, 0x0d, 0xfe, 0x9b, 0x36, 0xff, 0xb9, 0x6c, 0x7e, 0x1a, 0xa2, 0x55, 0xf8, 0xe7, 0x51, 0x7f, 0x60, 0xbf, 0x06, + 0xff, 0x7d, 0xf1, 0xa7, 0x1c, 0x1e, 0x9a, 0xc4, 0x07, 0x08, 0x1d, 0x4d, 0xf0, 0x1f, 0x92, 0x1c, 0x35, 0x9b, 0x17, + 0x47, 0x13, 0xfc, 0x8b, 0x24, 0x47, 0xf0, 0xf7, 0x5e, 0x91, 0xb7, 0x6c, 0xf2, 0xf4, 0x6e, 0x1e, 0x7e, 0xbe, 0x58, + 0x3d, 0x58, 0xbe, 0xe2, 0x6b, 0x68, 0x77, 0xf0, 0xdf, 0x7f, 0xfe, 0x29, 0x83, 0x1f, 0x2f, 0xc8, 0xd1, 0xb0, 0x81, + 0x42, 0x9d, 0x7c, 0x48, 0xcc, 0x9f, 0xb0, 0x1f, 0x0f, 0xfe, 0xdb, 0x0e, 0x25, 0xf8, 0xf1, 0xcf, 0xcf, 0xe7, 0x17, + 0x64, 0xb8, 0x0a, 0x83, 0xd5, 0x8f, 0x68, 0x85, 0xd0, 0xea, 0x01, 0xfa, 0x8c, 0x83, 0x49, 0x80, 0xf0, 0x4f, 0x92, + 0x1c, 0xfd, 0x78, 0x34, 0xc1, 0xbf, 0x49, 0x72, 0x14, 0x1c, 0x4d, 0xf0, 0x7b, 0x41, 0x8e, 0xfe, 0x3b, 0xec, 0xc7, + 0x46, 0x09, 0xb7, 0xd2, 0xea, 0x8f, 0x15, 0xdc, 0x84, 0xd0, 0x82, 0xd1, 0x95, 0xe2, 0x2a, 0x63, 0xe8, 0xc1, 0x11, + 0xc7, 0x8f, 0x05, 0x00, 0x2b, 0x54, 0xa0, 0xa4, 0xd1, 0x97, 0xb0, 0xcb, 0x1b, 0x58, 0x78, 0xc0, 0xa0, 0x07, 0x31, + 0xc7, 0x46, 0x4f, 0x20, 0x63, 0x65, 0x6e, 0x6f, 0x25, 0x5c, 0xdf, 0xe2, 0x2b, 0xf2, 0x58, 0x84, 0x6d, 0x84, 0x39, + 0x85, 0x1f, 0x1d, 0x84, 0x3f, 0x28, 0x7b, 0xe1, 0x09, 0xdb, 0xdc, 0x60, 0x58, 0x2e, 0x0c, 0x3f, 0x13, 0x20, 0xfc, + 0x72, 0x47, 0xa6, 0x9a, 0x82, 0xfa, 0x01, 0xe1, 0x4f, 0xb5, 0xeb, 0x51, 0x7c, 0xa5, 0x48, 0x89, 0x1c, 0xef, 0x0a, + 0xc6, 0x3e, 0xd0, 0xec, 0x0b, 0x2b, 0xc2, 0xa7, 0x0a, 0xb7, 0x3b, 0x8f, 0xb0, 0x56, 0x55, 0xef, 0xb7, 0x51, 0xaf, + 0xbc, 0xdd, 0x7a, 0x2e, 0xcc, 0x7d, 0x02, 0x9c, 0xc2, 0x75, 0x7d, 0x0d, 0xac, 0xfd, 0x3e, 0xdf, 0x52, 0x6a, 0x15, + 0xf4, 0x36, 0x40, 0xf5, 0xab, 0x54, 0x9e, 0x7f, 0xa5, 0x19, 0x4f, 0xf7, 0x14, 0x9b, 0xcd, 0x33, 0xaa, 0xd8, 0x9e, + 0x9d, 0xf3, 0x1e, 0x85, 0x86, 0x82, 0x92, 0xa7, 0xf8, 0x5b, 0x56, 0x9b, 0xf6, 0x6f, 0x27, 0xe7, 0xc1, 0xde, 0x09, + 0xe1, 0x3e, 0xcb, 0xf2, 0x25, 0x92, 0x96, 0xd7, 0x65, 0x9b, 0x37, 0x82, 0xcd, 0x36, 0x28, 0xcb, 0x86, 0xfa, 0xfc, + 0xce, 0x31, 0xdc, 0x6f, 0x12, 0xd2, 0xe9, 0x07, 0xe7, 0xf2, 0xeb, 0xe4, 0x22, 0x80, 0x9b, 0x9c, 0x82, 0x48, 0xa6, + 0x95, 0x47, 0x50, 0x82, 0x92, 0x56, 0x8f, 0x9e, 0xb3, 0x1e, 0x6d, 0x34, 0x1c, 0x9b, 0x9d, 0x10, 0x3e, 0xa0, 0xa6, + 0x7e, 0x86, 0xa7, 0x38, 0x25, 0xcd, 0x36, 0x5e, 0x90, 0x96, 0xae, 0xd2, 0x5b, 0x9c, 0x27, 0xb6, 0x9f, 0x83, 0x83, + 0xb0, 0x88, 0x32, 0x2a, 0xd5, 0x0b, 0xd0, 0x08, 0x90, 0x05, 0x9e, 0x92, 0x22, 0x62, 0x77, 0x2c, 0x09, 0x13, 0x84, + 0xa7, 0x96, 0x06, 0xa1, 0x1e, 0x5a, 0x10, 0xaf, 0x18, 0xc8, 0x19, 0x44, 0xb2, 0xfe, 0x74, 0xd0, 0x1e, 0x12, 0x42, + 0x82, 0xfd, 0x66, 0x33, 0xe8, 0x17, 0xe4, 0x0f, 0x19, 0x43, 0x8a, 0xc7, 0x4e, 0x93, 0x5f, 0x20, 0xa9, 0xe3, 0x25, + 0x85, 0xef, 0x45, 0xa4, 0x98, 0x54, 0x21, 0x24, 0x83, 0x92, 0x20, 0x77, 0x18, 0x1e, 0x9c, 0x1f, 0x05, 0x0d, 0x48, + 0xd5, 0x28, 0x8a, 0x70, 0x41, 0xee, 0x15, 0x8a, 0xa7, 0x83, 0xe3, 0xa1, 0x7f, 0x46, 0x98, 0x54, 0xe8, 0xff, 0x5e, + 0xf5, 0xa7, 0x83, 0x96, 0xee, 0xff, 0x22, 0xe8, 0x87, 0x05, 0xc9, 0xf7, 0xed, 0x3d, 0x4f, 0x2c, 0x99, 0x9e, 0x2f, + 0x8a, 0xed, 0x00, 0x6d, 0xdf, 0x29, 0x69, 0x76, 0xe2, 0x30, 0xf5, 0x67, 0xd2, 0x84, 0x0e, 0x2d, 0x28, 0x70, 0x46, + 0xa0, 0x3c, 0x2e, 0x08, 0x74, 0x5a, 0x55, 0xbb, 0x57, 0xb1, 0x4d, 0xf8, 0x31, 0xf8, 0xb1, 0xff, 0x9b, 0x8c, 0x7f, + 0x92, 0x66, 0x04, 0xbf, 0xc9, 0xd5, 0x0a, 0xfe, 0xfe, 0x24, 0xfb, 0x30, 0x2c, 0x9d, 0xf6, 0x87, 0x4d, 0xfb, 0x05, + 0xd2, 0x24, 0x8b, 0xf5, 0x80, 0x71, 0x5e, 0xf2, 0x63, 0x66, 0x71, 0xc6, 0xc4, 0xcc, 0xe0, 0xe0, 0x80, 0x0f, 0x68, + 0xa3, 0x3d, 0x84, 0x1b, 0x81, 0x42, 0xc9, 0x0f, 0x5c, 0x4d, 0xc3, 0xe0, 0xe8, 0x22, 0x40, 0xfd, 0x60, 0x0f, 0x56, + 0xb9, 0x27, 0x1a, 0xc4, 0xc2, 0x3a, 0x69, 0x28, 0x1a, 0xa7, 0x17, 0xa4, 0xd5, 0x0f, 0xa5, 0x21, 0xf2, 0x19, 0xc2, + 0x89, 0xa5, 0xa9, 0x2d, 0x9c, 0xa2, 0x06, 0x97, 0x0d, 0xf7, 0x9d, 0xa2, 0xc6, 0x54, 0x35, 0xc6, 0x28, 0x4e, 0xe0, + 0x6f, 0x98, 0x12, 0x42, 0x9a, 0x9d, 0xb2, 0xa2, 0x3b, 0x2c, 0x29, 0x8a, 0xc7, 0x4e, 0x3d, 0x3a, 0xd0, 0x9b, 0x43, + 0x34, 0x42, 0x3e, 0x60, 0xc3, 0xd5, 0x2a, 0x38, 0xef, 0x5f, 0x04, 0xa8, 0x11, 0x3a, 0xb4, 0x3b, 0x72, 0x78, 0x87, + 0x10, 0x96, 0xc3, 0xb5, 0xbd, 0x81, 0xba, 0x65, 0xb5, 0xdb, 0xa6, 0x65, 0xb5, 0xff, 0x3d, 0xb2, 0xc0, 0xd6, 0xa5, + 0xdc, 0x63, 0xf8, 0xdb, 0x39, 0x4c, 0xd5, 0xe1, 0xb6, 0x20, 0x2d, 0x5c, 0x10, 0xa7, 0xee, 0xa6, 0x44, 0x55, 0xf8, + 0x9f, 0x90, 0xaa, 0x38, 0x1e, 0x64, 0x78, 0x3a, 0x24, 0x92, 0x6a, 0xf9, 0xa5, 0xe7, 0x94, 0xe9, 0x2c, 0x23, 0xb7, + 0x6c, 0xe3, 0xfe, 0x37, 0x83, 0x3b, 0x99, 0x2b, 0x15, 0x25, 0x8b, 0xa2, 0x60, 0xb9, 0x7a, 0x25, 0x52, 0xcb, 0xd8, + 0xb1, 0x0c, 0x64, 0x2b, 0xb8, 0xd8, 0xc5, 0xc0, 0xd5, 0x75, 0xdc, 0x4e, 0x49, 0xb7, 0xb2, 0x17, 0x24, 0x35, 0x0c, + 0x97, 0xbe, 0xee, 0xed, 0x2d, 0xac, 0x28, 0x1d, 0x22, 0x9c, 0xda, 0x7b, 0xe0, 0x30, 0x8a, 0xa2, 0x45, 0x94, 0x40, + 0x36, 0x74, 0x20, 0xd1, 0x5a, 0xef, 0xab, 0x30, 0x27, 0x57, 0x2a, 0xca, 0xd9, 0x9d, 0xee, 0x36, 0x44, 0xd5, 0x21, + 0xee, 0xf6, 0xdb, 0x39, 0xed, 0x69, 0x02, 0x94, 0x47, 0xb9, 0x48, 0x19, 0x40, 0x08, 0xee, 0xfe, 0x6d, 0xd2, 0x94, + 0x4a, 0xff, 0x66, 0xab, 0x1a, 0xe0, 0xc0, 0x57, 0x79, 0x2f, 0x40, 0x4f, 0xac, 0x65, 0xe8, 0xb2, 0xb0, 0x51, 0x9e, + 0x23, 0xc4, 0xc7, 0xe1, 0x22, 0x82, 0x1b, 0x41, 0x8d, 0x49, 0x5c, 0xa2, 0xd5, 0x6a, 0xe1, 0xe3, 0xd6, 0xb4, 0x52, + 0x4c, 0x8f, 0xc9, 0x74, 0x50, 0x34, 0x1a, 0x5a, 0x79, 0x9d, 0x1a, 0xbc, 0x58, 0x20, 0x3c, 0x2e, 0xf7, 0x9a, 0x2b, + 0x37, 0x27, 0xf5, 0xae, 0xc2, 0x71, 0x5d, 0x09, 0xdc, 0xe0, 0x12, 0x69, 0xfd, 0xa2, 0x82, 0xd6, 0xf1, 0x84, 0x1c, + 0x85, 0x83, 0xa8, 0xff, 0x3f, 0x87, 0xa8, 0x1f, 0x46, 0x87, 0xe8, 0xc8, 0xd0, 0x92, 0x31, 0xea, 0x25, 0xa6, 0x8f, + 0xa5, 0xbe, 0xfd, 0x6c, 0x63, 0xad, 0x80, 0x8c, 0x05, 0xce, 0xe9, 0x8c, 0xc5, 0x13, 0xd8, 0xf5, 0x0e, 0x79, 0xe6, + 0x18, 0x90, 0x29, 0x9e, 0x58, 0xda, 0x12, 0x05, 0x7d, 0x41, 0xcb, 0xaf, 0x7e, 0xd0, 0xa7, 0xd5, 0xd7, 0xff, 0x0c, + 0xfa, 0x09, 0x8d, 0xaf, 0xf8, 0xda, 0x2a, 0xc9, 0x6b, 0x7d, 0x9c, 0xba, 0x3e, 0xd6, 0x66, 0x71, 0x3c, 0xe0, 0xa5, + 0x28, 0xdf, 0xd2, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0x94, 0x47, 0x8a, 0x4e, 0x00, 0xaa, 0xde, 0x22, 0xe4, + 0xbe, 0x6d, 0x80, 0x37, 0x65, 0xc0, 0x16, 0x87, 0xb4, 0x00, 0xcd, 0xc5, 0x45, 0x0b, 0x2d, 0x6b, 0x85, 0x2d, 0x67, + 0x55, 0xbf, 0x8b, 0x2f, 0x89, 0xf7, 0x18, 0xa8, 0xf2, 0xf9, 0xa2, 0x37, 0x6e, 0x34, 0x50, 0xee, 0xf0, 0x2b, 0x1d, + 0x8c, 0x87, 0xf8, 0x0e, 0x50, 0x08, 0xd7, 0x30, 0x0a, 0xd7, 0xe6, 0xd8, 0xb1, 0x73, 0x6c, 0x34, 0xc4, 0x1a, 0xf5, + 0xbc, 0xca, 0x0b, 0x5b, 0x79, 0xbd, 0x36, 0x90, 0xd9, 0xc4, 0xb8, 0x33, 0xa4, 0x53, 0xc0, 0x10, 0x8c, 0x10, 0xf2, + 0x8f, 0x40, 0x3b, 0x9b, 0x85, 0x46, 0xa1, 0xba, 0xde, 0xbd, 0x40, 0x51, 0xcd, 0xe9, 0x11, 0x02, 0x2c, 0xa0, 0x6a, + 0xa9, 0x46, 0x9e, 0x2a, 0x9c, 0x36, 0xda, 0x1a, 0xdd, 0x9b, 0xed, 0x5e, 0xbd, 0xb1, 0x87, 0x55, 0x63, 0x38, 0x6d, + 0x90, 0x69, 0xb5, 0xc3, 0xd7, 0xa2, 0xd1, 0x58, 0xd7, 0xef, 0x4b, 0xdd, 0x26, 0xae, 0xdd, 0x5f, 0x3c, 0xdd, 0x32, + 0xf1, 0x70, 0xa7, 0x6f, 0x75, 0xde, 0xca, 0x88, 0xe7, 0x39, 0x2b, 0xe0, 0x84, 0x25, 0x0a, 0xcb, 0xf5, 0xba, 0x3c, + 0xf5, 0x7f, 0x57, 0xc6, 0x66, 0x8c, 0x70, 0xa0, 0x43, 0x5a, 0x6a, 0xc3, 0x02, 0x17, 0x98, 0x6a, 0x2a, 0x42, 0x08, + 0xf9, 0xa0, 0x9c, 0x79, 0x8c, 0xd2, 0x24, 0x29, 0x21, 0xde, 0xd9, 0x1d, 0xe6, 0x84, 0x45, 0x37, 0x0f, 0xae, 0xc4, + 0x77, 0x45, 0xba, 0x81, 0x1c, 0xc6, 0xba, 0x58, 0x66, 0x09, 0x59, 0x46, 0xbe, 0x82, 0x9c, 0x53, 0x5e, 0xb0, 0x44, + 0x9a, 0x20, 0x3e, 0xe1, 0x05, 0xd3, 0x8c, 0xfb, 0x03, 0x27, 0x37, 0x26, 0x75, 0x4e, 0x33, 0xf1, 0xb5, 0x3f, 0x00, + 0xcd, 0x0c, 0x94, 0x43, 0x82, 0x6c, 0x15, 0xbb, 0x79, 0x70, 0xf9, 0x7a, 0x97, 0x0c, 0xbd, 0x5a, 0x59, 0xe9, 0x39, + 0x01, 0xd6, 0x07, 0x67, 0xd5, 0x50, 0x13, 0xfb, 0x23, 0x0e, 0x13, 0xcd, 0x44, 0x65, 0x21, 0x07, 0x64, 0xba, 0x79, + 0x70, 0xf9, 0x2e, 0xe4, 0x5a, 0x37, 0x85, 0xb0, 0x3f, 0xef, 0xb0, 0x20, 0x21, 0x25, 0x0c, 0x99, 0xc9, 0x97, 0x74, + 0xac, 0xf0, 0x4e, 0xf7, 0x98, 0xea, 0x4c, 0x10, 0x3b, 0x06, 0x72, 0x48, 0x12, 0x0b, 0x02, 0x92, 0x20, 0x9c, 0xd4, + 0xe4, 0x3a, 0xa2, 0xd7, 0x40, 0x77, 0x76, 0x0d, 0x8b, 0x11, 0x19, 0xf6, 0x10, 0xe1, 0x44, 0x77, 0xab, 0xd6, 0xe6, + 0x38, 0xc9, 0xe9, 0xa6, 0xa1, 0x5b, 0x25, 0xcf, 0xbe, 0x07, 0xc1, 0xcb, 0x7d, 0xbc, 0xb2, 0x6d, 0x97, 0x09, 0x4f, + 0x9c, 0x45, 0xda, 0xcd, 0x83, 0xcb, 0x5f, 0xad, 0x51, 0xda, 0x9c, 0x3a, 0xf2, 0xbf, 0x25, 0xa3, 0x5e, 0xfe, 0x1a, + 0x55, 0xb9, 0xba, 0xf0, 0xcd, 0x83, 0xcb, 0xdf, 0x77, 0x15, 0x83, 0xf4, 0xf5, 0xa2, 0x52, 0x12, 0xe8, 0xf1, 0x2d, + 0x59, 0x16, 0x2f, 0xed, 0x59, 0x11, 0xcb, 0x35, 0xd6, 0x27, 0x54, 0x9c, 0xaf, 0x4b, 0xdd, 0xca, 0x13, 0x2c, 0x88, + 0xbe, 0x4a, 0xaa, 0x2f, 0x9b, 0x45, 0x63, 0x2e, 0xf2, 0xeb, 0x44, 0xcc, 0xd9, 0x37, 0xee, 0x97, 0x9e, 0x2a, 0x14, + 0xf1, 0x19, 0x18, 0xe2, 0xe8, 0xb1, 0x4b, 0xbc, 0xdf, 0x42, 0xbd, 0x8d, 0xf3, 0x4c, 0x68, 0x44, 0x2d, 0xea, 0x87, + 0x0d, 0xa6, 0xa4, 0x85, 0x13, 0xd2, 0xc2, 0x19, 0xc9, 0x07, 0x2d, 0x73, 0x62, 0xf4, 0xb2, 0xb2, 0x69, 0x73, 0xee, + 0xc0, 0x76, 0xcf, 0xcc, 0xbe, 0x35, 0x87, 0xf2, 0xb4, 0x97, 0x69, 0xfd, 0xa5, 0x3e, 0xe8, 0xa7, 0x1a, 0x35, 0x9e, + 0xb0, 0xb0, 0xc0, 0x85, 0x6e, 0xf9, 0x9a, 0x8f, 0x32, 0xb0, 0x53, 0x81, 0x99, 0x61, 0x85, 0xe2, 0xb2, 0x6c, 0xdb, + 0x96, 0xcd, 0x22, 0xbd, 0x56, 0x05, 0xce, 0x22, 0x20, 0xe5, 0x38, 0xb3, 0x76, 0x3d, 0x72, 0xbb, 0xca, 0xe9, 0xc1, + 0x41, 0x68, 0x2b, 0xd1, 0xb0, 0x70, 0xf9, 0xd5, 0x0d, 0xe0, 0x7b, 0x43, 0x35, 0xa6, 0x48, 0x4f, 0xa0, 0xd1, 0x48, + 0x86, 0x6b, 0xba, 0x4f, 0x48, 0x98, 0xd5, 0xa1, 0xe8, 0x46, 0xaf, 0x99, 0xc1, 0x0d, 0x00, 0x34, 0x1a, 0xe5, 0x75, + 0xef, 0x06, 0xc4, 0x9e, 0x2a, 0x2c, 0xd6, 0x5f, 0xc3, 0xd2, 0x9a, 0xa8, 0xb5, 0x65, 0x87, 0xe5, 0x46, 0x81, 0xa4, + 0x8f, 0xbb, 0xd2, 0xcd, 0xc7, 0xdb, 0x1a, 0xba, 0xdc, 0x0b, 0x6b, 0x03, 0x81, 0xb5, 0xd5, 0x96, 0x2d, 0xe4, 0x48, + 0x5b, 0x07, 0xc5, 0xae, 0x10, 0x5c, 0x70, 0x41, 0xa1, 0xc6, 0xda, 0x62, 0xf9, 0x13, 0xb6, 0x6d, 0xce, 0x89, 0x73, + 0x64, 0xb5, 0x65, 0x7a, 0x18, 0x1a, 0x60, 0x9d, 0x12, 0x30, 0xcf, 0xc9, 0xcb, 0x6f, 0xa3, 0xfe, 0xa5, 0x87, 0xfa, + 0x8f, 0x09, 0xf3, 0xb6, 0x81, 0x59, 0x82, 0x48, 0x58, 0x05, 0x45, 0xee, 0xb2, 0xae, 0xe6, 0x04, 0xb4, 0x71, 0x75, + 0xa8, 0xe6, 0xfe, 0x15, 0xe5, 0x37, 0x28, 0x8b, 0xbf, 0x53, 0xb4, 0x3e, 0x13, 0xbb, 0xfb, 0xe4, 0xb0, 0xba, 0xa0, + 0x83, 0xae, 0x77, 0x29, 0x07, 0x7d, 0x52, 0x78, 0xf9, 0xfb, 0xf7, 0xef, 0x56, 0xaf, 0xe6, 0xdb, 0x3b, 0xd8, 0x33, + 0x2b, 0x85, 0x59, 0x7b, 0x1b, 0xb8, 0x6e, 0x64, 0x0a, 0xfd, 0x97, 0x77, 0xe2, 0x75, 0x2a, 0xb4, 0xb1, 0x19, 0xdd, + 0x71, 0x08, 0xa3, 0x6d, 0xb7, 0x75, 0x09, 0xe6, 0x35, 0x0b, 0x74, 0xc9, 0x18, 0xb7, 0xd2, 0xe2, 0x1b, 0x64, 0xe4, + 0x52, 0x17, 0x60, 0x79, 0xba, 0x3b, 0xfb, 0xf1, 0xda, 0xe2, 0x89, 0x19, 0x1a, 0x5a, 0x6a, 0x42, 0x68, 0xf0, 0x1e, + 0x30, 0xc7, 0x1c, 0x11, 0x00, 0xa2, 0x97, 0x1a, 0x52, 0x15, 0xc8, 0x82, 0xa0, 0x52, 0xe4, 0x3f, 0xdf, 0x27, 0xe4, + 0x65, 0xa5, 0xc8, 0x7c, 0x5b, 0x19, 0x73, 0x01, 0x62, 0xa0, 0x18, 0x2e, 0x12, 0xca, 0x04, 0x73, 0x19, 0xfa, 0x41, + 0xb9, 0xf2, 0x5a, 0xda, 0x8c, 0x2a, 0x6e, 0xdc, 0xbb, 0x29, 0xd5, 0x2a, 0x3e, 0x93, 0xef, 0x20, 0xb1, 0x91, 0xfb, + 0x00, 0x72, 0x19, 0xd5, 0x83, 0x84, 0xef, 0x77, 0xba, 0xb4, 0x6b, 0x77, 0xfd, 0x65, 0xd3, 0x22, 0x66, 0x63, 0x5d, + 0x22, 0x9e, 0x4b, 0x56, 0xa8, 0xc7, 0x6c, 0x2c, 0x0a, 0xb8, 0xff, 0x28, 0xc1, 0x82, 0xd6, 0x0f, 0x3c, 0x1d, 0xa0, + 0x9e, 0xa0, 0x77, 0xe9, 0xb0, 0x31, 0x43, 0xfd, 0xeb, 0x8b, 0xbe, 0x03, 0xbf, 0xd9, 0xac, 0xf5, 0xf2, 0xe0, 0xe0, + 0x2b, 0xab, 0x00, 0x65, 0x87, 0xa9, 0x87, 0xe1, 0x11, 0x2f, 0xc3, 0xe5, 0xd8, 0x9b, 0xe1, 0x07, 0x61, 0xa5, 0x32, + 0x70, 0x84, 0xc3, 0x27, 0x42, 0xcf, 0x89, 0x5a, 0x4f, 0x36, 0xe9, 0xbd, 0xd5, 0x66, 0x48, 0x5f, 0xac, 0x01, 0x72, + 0x0f, 0x72, 0xb9, 0x51, 0x32, 0xe5, 0x95, 0xad, 0x6d, 0x39, 0x88, 0x2b, 0x00, 0x57, 0x98, 0x83, 0x90, 0xe2, 0xa1, + 0x61, 0xbe, 0x53, 0x68, 0x79, 0x2e, 0x80, 0xfd, 0xc7, 0x79, 0x04, 0x22, 0x2d, 0xaa, 0x6d, 0x5c, 0x84, 0x70, 0xae, + 0x25, 0x1e, 0xcf, 0x38, 0xe1, 0xf2, 0xf9, 0x2e, 0x0d, 0xb5, 0x43, 0x6d, 0xa6, 0xcf, 0x20, 0x28, 0x21, 0x50, 0x59, + 0x21, 0xfa, 0x1a, 0x4a, 0xcb, 0xcd, 0x95, 0xf7, 0x70, 0xec, 0x76, 0x2f, 0xa7, 0xa1, 0xb9, 0xdb, 0x82, 0xe3, 0xa3, + 0x88, 0x16, 0x61, 0xad, 0xeb, 0x5e, 0xa1, 0xab, 0x61, 0x0b, 0x3a, 0xea, 0xc3, 0xa9, 0xd0, 0xf7, 0x84, 0x57, 0x15, + 0x49, 0xfd, 0x64, 0x2d, 0xa0, 0x1c, 0x31, 0xac, 0x4c, 0x53, 0xbc, 0xf9, 0x7f, 0xb2, 0xe6, 0x6b, 0xe5, 0x31, 0xc1, + 0xf4, 0x30, 0x6e, 0xcd, 0x2a, 0xb0, 0x35, 0xe0, 0xd8, 0xf2, 0x2f, 0xe1, 0x2d, 0xaa, 0x53, 0x8a, 0xeb, 0x4e, 0x3d, + 0x26, 0xe0, 0x2d, 0x58, 0xcf, 0x6c, 0x6e, 0xfd, 0xe7, 0xfa, 0x60, 0x94, 0x38, 0xaf, 0x11, 0x78, 0xa1, 0x09, 0x3c, + 0x02, 0xc6, 0xcd, 0x99, 0x96, 0xf7, 0xad, 0x11, 0x8d, 0x74, 0x27, 0x9e, 0xc5, 0x33, 0xc3, 0x72, 0x6f, 0x7d, 0x6c, + 0xac, 0x48, 0x2c, 0x09, 0xd8, 0x16, 0x61, 0x4b, 0xe4, 0x05, 0xc2, 0x79, 0xa3, 0xd1, 0xcb, 0xcf, 0x59, 0xa5, 0x55, + 0xa9, 0x86, 0x29, 0xe1, 0x96, 0x18, 0xf0, 0xbe, 0x76, 0xa2, 0xe6, 0x08, 0x97, 0x66, 0xee, 0x39, 0xa8, 0xef, 0x2f, + 0xdf, 0x86, 0x3e, 0x7d, 0xf3, 0xcb, 0x96, 0x17, 0xb1, 0x30, 0xa5, 0xb0, 0xba, 0xc3, 0x79, 0xf3, 0x7d, 0xb3, 0x11, + 0x18, 0xf7, 0x7e, 0x1b, 0x83, 0x8d, 0x1b, 0xea, 0x29, 0x43, 0x1a, 0xca, 0x4d, 0xd8, 0x43, 0x95, 0xbd, 0xa3, 0xdf, + 0x59, 0x4f, 0x55, 0xd2, 0xae, 0x22, 0xf9, 0x7a, 0x2d, 0x59, 0x65, 0x34, 0xb0, 0x61, 0xd8, 0xa9, 0x8f, 0x99, 0x6d, + 0x05, 0xfe, 0xd5, 0x9c, 0x28, 0xec, 0x21, 0xeb, 0x9b, 0x6f, 0x5d, 0xa7, 0x54, 0xc3, 0x84, 0xed, 0x6d, 0xcf, 0xc7, + 0x2b, 0xbe, 0xeb, 0x7c, 0xc4, 0xc2, 0x6e, 0x7d, 0x7d, 0x36, 0xb6, 0xff, 0x8d, 0xb3, 0xd1, 0xaa, 0xed, 0xdd, 0xf1, + 0x08, 0xdc, 0x49, 0xed, 0x78, 0xcc, 0xeb, 0xc7, 0xa3, 0xc0, 0xee, 0xf4, 0xbe, 0xe8, 0xac, 0x56, 0x72, 0xd0, 0x02, + 0xb5, 0x53, 0x10, 0xc0, 0xcf, 0xb6, 0xf9, 0xe9, 0x91, 0x64, 0xa3, 0x43, 0x0e, 0xcb, 0xf3, 0xbe, 0x8d, 0x22, 0x30, + 0xa0, 0x0e, 0xb5, 0xad, 0x97, 0x46, 0x6c, 0x8b, 0x43, 0x16, 0xcb, 0x89, 0x2c, 0xaf, 0xae, 0x60, 0xc4, 0xfa, 0xd8, + 0xb0, 0x02, 0x66, 0xb8, 0xd3, 0xaa, 0xd0, 0x89, 0x9f, 0xff, 0x9a, 0x39, 0xad, 0x1d, 0x31, 0x86, 0x93, 0xa8, 0x59, + 0x31, 0xd8, 0x11, 0x58, 0x86, 0x71, 0x5f, 0x4b, 0xa8, 0xd5, 0xa9, 0x8e, 0x6a, 0x47, 0x12, 0x6e, 0x81, 0xda, 0x6d, + 0x5f, 0x9f, 0x4b, 0xab, 0xd5, 0xce, 0x83, 0x05, 0x17, 0x1e, 0x6e, 0x3f, 0x27, 0xaa, 0x46, 0x52, 0x28, 0xb1, 0x12, + 0x14, 0xce, 0x34, 0xaa, 0x2a, 0x22, 0x06, 0xad, 0x21, 0xf0, 0xa4, 0xbd, 0xe4, 0x5c, 0x54, 0x42, 0x72, 0xd2, 0x68, + 0xa0, 0xac, 0xec, 0x98, 0x0e, 0x64, 0x23, 0x19, 0x62, 0x86, 0x13, 0x23, 0xb0, 0xc0, 0xe9, 0x15, 0x66, 0x55, 0xd7, + 0x83, 0x64, 0x88, 0x70, 0xb1, 0x5a, 0x85, 0x66, 0x68, 0x19, 0x5a, 0xad, 0x32, 0x7f, 0x68, 0x3a, 0x1f, 0x2a, 0xbe, + 0xec, 0x2b, 0xf2, 0x52, 0x9f, 0x87, 0x2f, 0x61, 0x90, 0x0d, 0x12, 0x66, 0x56, 0x25, 0x98, 0x81, 0xe6, 0xaa, 0x21, + 0x06, 0x49, 0xa3, 0x3d, 0xf4, 0x68, 0xd8, 0x20, 0x19, 0x92, 0x6c, 0x0d, 0x96, 0xb3, 0xb9, 0x3d, 0x30, 0xff, 0x82, + 0x83, 0xed, 0x2f, 0x7d, 0xce, 0x98, 0x06, 0xfd, 0x35, 0xd9, 0x54, 0x19, 0x94, 0x78, 0x65, 0x17, 0xd7, 0x95, 0xab, + 0x19, 0x58, 0x94, 0x85, 0xb0, 0xbd, 0x66, 0xee, 0x83, 0xf0, 0x5f, 0x62, 0xbb, 0xa0, 0xa5, 0x11, 0xf7, 0x06, 0xe2, + 0x3b, 0xdb, 0xed, 0x28, 0x8a, 0x68, 0x31, 0xd1, 0x57, 0x22, 0x8e, 0x12, 0xeb, 0x3d, 0x70, 0x6c, 0xc7, 0xe9, 0xf5, + 0x3c, 0x28, 0x3b, 0x1b, 0x12, 0x33, 0x7e, 0xc7, 0xec, 0x38, 0xc7, 0x95, 0x82, 0xee, 0xd6, 0x45, 0x98, 0xc1, 0xd0, + 0xff, 0xe5, 0xc1, 0x9c, 0xd8, 0xc1, 0x18, 0x34, 0xd9, 0x80, 0xdb, 0x37, 0xe0, 0x51, 0xd0, 0x0d, 0xb8, 0x7d, 0x1b, + 0xbe, 0x0e, 0x5a, 0xc9, 0x37, 0x07, 0xe8, 0x91, 0x09, 0x33, 0xd2, 0x2a, 0xc1, 0x1b, 0x66, 0x77, 0x93, 0x23, 0x33, + 0x64, 0x15, 0x0e, 0x57, 0x45, 0x42, 0xb9, 0xb1, 0x17, 0x2a, 0x26, 0xd5, 0xe3, 0xfe, 0x65, 0xfc, 0x12, 0xf9, 0x4a, + 0x83, 0xba, 0x71, 0x0c, 0x60, 0x95, 0xd5, 0xd6, 0xbf, 0x3c, 0x38, 0x00, 0xf3, 0x68, 0x60, 0xed, 0xa2, 0x84, 0xce, + 0xd5, 0xa2, 0x00, 0xfe, 0x2a, 0x77, 0xbf, 0x21, 0x19, 0xdc, 0x4e, 0x74, 0x1a, 0xfc, 0x80, 0x84, 0x39, 0x95, 0x92, + 0x7f, 0x35, 0x69, 0xf6, 0x37, 0x2e, 0x88, 0xc3, 0xe8, 0xdc, 0x70, 0x8a, 0x02, 0xf5, 0x84, 0x45, 0xd7, 0x3a, 0xe4, + 0x9e, 0x7e, 0x65, 0xb9, 0x7a, 0xc9, 0xa5, 0x62, 0x39, 0x00, 0xa0, 0x42, 0x3c, 0x98, 0x52, 0x8e, 0x60, 0xeb, 0xd6, + 0x6a, 0xd1, 0x34, 0xfd, 0x6e, 0x15, 0x55, 0x67, 0x8b, 0xa6, 0x34, 0x4f, 0x33, 0xd3, 0x89, 0x6f, 0x33, 0xe9, 0xec, + 0x44, 0xcb, 0x92, 0xbe, 0xc5, 0x4e, 0xc5, 0x7e, 0x68, 0x5a, 0x1f, 0x4a, 0xe2, 0xce, 0x05, 0x77, 0x96, 0x7e, 0x97, + 0x8f, 0x81, 0x2b, 0xf5, 0x6f, 0xac, 0x82, 0x3f, 0x13, 0xac, 0x3c, 0xf2, 0x1a, 0xd5, 0xc7, 0xe9, 0x50, 0x27, 0xdb, + 0x52, 0x2e, 0x94, 0x46, 0x61, 0x1b, 0x27, 0x85, 0xc6, 0x94, 0xd3, 0x6f, 0x4b, 0x5c, 0xbf, 0xba, 0x63, 0xc4, 0x1d, + 0x1d, 0xf2, 0xdf, 0xa5, 0xd2, 0x68, 0x59, 0x22, 0x18, 0x72, 0x3b, 0xf2, 0x67, 0x09, 0x57, 0xb1, 0x19, 0x57, 0xcf, + 0xd5, 0x2c, 0xdb, 0xf0, 0xc4, 0xe9, 0xfd, 0x5c, 0x5e, 0x23, 0xff, 0x2c, 0xc3, 0x5b, 0x86, 0x9f, 0x30, 0xb8, 0x37, + 0x7e, 0xc6, 0xbd, 0x2a, 0xdb, 0xf7, 0xc5, 0xcf, 0xbc, 0xfb, 0xe2, 0x67, 0x3c, 0xde, 0x2e, 0xea, 0xdd, 0x13, 0x77, + 0xa2, 0xb3, 0xa8, 0x15, 0x38, 0x3e, 0x6a, 0x4a, 0x2b, 0xff, 0x4a, 0xb3, 0x35, 0x70, 0x65, 0x13, 0x07, 0xc6, 0x79, + 0x75, 0x11, 0x8a, 0x59, 0x73, 0x46, 0xc3, 0xe1, 0x7f, 0x6b, 0x9d, 0xec, 0xc9, 0x23, 0x8c, 0x14, 0xf2, 0x86, 0x16, + 0xea, 0x01, 0x6c, 0xb8, 0x62, 0xcb, 0x07, 0x90, 0x12, 0x50, 0xb6, 0xfd, 0x7b, 0x5d, 0x54, 0x8e, 0x07, 0xfd, 0xdc, + 0x38, 0x1f, 0xf9, 0xed, 0x93, 0xa2, 0xe4, 0xea, 0xea, 0x42, 0xc8, 0x9d, 0xd6, 0x12, 0x20, 0x4c, 0x9d, 0x6b, 0x1e, + 0xb3, 0x34, 0x99, 0xc5, 0xcb, 0x75, 0xa9, 0x3a, 0x28, 0x0c, 0x57, 0xc7, 0x11, 0x2e, 0xd6, 0xfa, 0x06, 0xfd, 0x1f, + 0x8e, 0xff, 0xe2, 0x96, 0x46, 0x7e, 0x2a, 0x29, 0xd0, 0xe3, 0xdd, 0xbe, 0x36, 0x3b, 0x48, 0xa4, 0x99, 0x43, 0x69, + 0x29, 0x00, 0x58, 0xad, 0xf1, 0x75, 0xed, 0x70, 0xea, 0x89, 0xb0, 0xb3, 0xf9, 0xa6, 0x21, 0x2c, 0x66, 0xa5, 0x05, + 0x8f, 0xee, 0x66, 0x87, 0xe5, 0xa8, 0x93, 0xc5, 0x55, 0xb9, 0xc7, 0x6a, 0xfd, 0xa2, 0x6f, 0x80, 0xb2, 0x32, 0x44, + 0x5b, 0xad, 0xc2, 0x3a, 0xbc, 0x89, 0xf4, 0xae, 0x41, 0x10, 0x96, 0x9e, 0x01, 0x47, 0x8d, 0xf1, 0x36, 0x75, 0x42, + 0xb4, 0x69, 0xbf, 0xe4, 0x58, 0xf7, 0xda, 0x38, 0x7c, 0x45, 0x83, 0xa9, 0xee, 0x6b, 0x1e, 0xb0, 0x99, 0x5d, 0xd9, + 0x91, 0x07, 0xa1, 0x29, 0x75, 0xc6, 0xb9, 0x95, 0x15, 0xed, 0x0e, 0xf8, 0xa2, 0xef, 0x98, 0xe7, 0x5a, 0xd0, 0x6d, + 0xe7, 0x7b, 0xb6, 0x4d, 0x4f, 0xc4, 0xb7, 0x6c, 0x9b, 0x6a, 0x9c, 0xf0, 0x7e, 0x0b, 0x7d, 0xdf, 0x10, 0xd6, 0xf4, + 0xb5, 0xbb, 0xc8, 0xff, 0x42, 0x77, 0x6d, 0x40, 0x4f, 0x03, 0x66, 0x47, 0x63, 0x3e, 0xa8, 0xf5, 0xfa, 0x53, 0xe9, + 0xbf, 0xa0, 0x6d, 0x85, 0x3e, 0x99, 0x5d, 0x60, 0xc5, 0x4a, 0xed, 0x10, 0x1c, 0xfe, 0xc3, 0xc9, 0x24, 0x13, 0x23, + 0x9a, 0xbd, 0x83, 0x1e, 0xab, 0xdc, 0xe7, 0xf7, 0x69, 0x41, 0x15, 0xb3, 0xb4, 0xa6, 0x1a, 0xc5, 0x3f, 0xdc, 0x1b, + 0xc6, 0x3f, 0xdc, 0x50, 0xee, 0xaa, 0x05, 0xbc, 0x7c, 0x59, 0x36, 0x11, 0x7f, 0x5a, 0x97, 0xfe, 0x56, 0xf9, 0xee, + 0x5e, 0x36, 0x49, 0x9a, 0xca, 0xcb, 0xd9, 0xe6, 0xe1, 0x66, 0x53, 0x61, 0xf8, 0xd7, 0x37, 0x06, 0xbb, 0x4d, 0xe6, + 0xfe, 0xf2, 0xc8, 0xdc, 0x5f, 0x3c, 0xfe, 0x6e, 0x2d, 0x8f, 0xe2, 0x1d, 0x47, 0xc7, 0xda, 0x32, 0xc6, 0x8c, 0xfa, + 0xad, 0x02, 0x83, 0x06, 0x45, 0x2e, 0x3c, 0x6f, 0x87, 0xea, 0xf4, 0x72, 0xf6, 0x47, 0x61, 0xb2, 0x90, 0x4a, 0xcc, + 0x6c, 0xa3, 0xd2, 0xfa, 0x38, 0xe9, 0x4c, 0x50, 0x60, 0xeb, 0x3b, 0xfc, 0xb8, 0xee, 0x46, 0xb6, 0xfc, 0xc2, 0xf3, + 0x34, 0xce, 0xb1, 0x3d, 0x5b, 0x64, 0x2c, 0xd6, 0xc4, 0x99, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0xcf, 0xb9, 0x9c, 0xb2, + 0x22, 0x2c, 0xd0, 0xf2, 0x5b, 0x9d, 0x15, 0x70, 0x9b, 0x63, 0x3a, 0xc3, 0x69, 0x69, 0x39, 0xa0, 0x22, 0x68, 0x0d, + 0x74, 0x46, 0x33, 0xa6, 0xa6, 0x22, 0x05, 0xc3, 0x97, 0x28, 0x2d, 0xdd, 0xa9, 0x0e, 0x0e, 0xf6, 0xc3, 0x40, 0xeb, + 0x2f, 0xc0, 0x07, 0xdd, 0xcf, 0x41, 0xfd, 0x25, 0x38, 0x06, 0x55, 0x5d, 0x33, 0xb4, 0x64, 0x9b, 0x3e, 0x34, 0x2a, + 0xfa, 0xc2, 0xee, 0x31, 0x47, 0xeb, 0x75, 0x6c, 0x46, 0x1d, 0x8c, 0x39, 0xcb, 0xd2, 0x00, 0x7f, 0x61, 0xf7, 0x71, + 0xe9, 0xb6, 0xae, 0xbd, 0xac, 0xf5, 0x22, 0x06, 0xe2, 0x36, 0x0f, 0x70, 0xd5, 0x49, 0xbc, 0x5c, 0x63, 0x51, 0xf0, + 0x09, 0xe0, 0xe8, 0x2f, 0xec, 0x3e, 0xb6, 0xed, 0x79, 0xae, 0x82, 0x68, 0xe9, 0x40, 0x1f, 0x79, 0xc9, 0xfe, 0x32, + 0x58, 0x81, 0x63, 0xa0, 0xeb, 0x0e, 0x49, 0xad, 0x5c, 0x25, 0x42, 0x22, 0xb4, 0xfe, 0x77, 0xa7, 0x82, 0x17, 0xfe, + 0x39, 0xa7, 0x6a, 0x16, 0xb7, 0x1b, 0x95, 0x18, 0x54, 0xa8, 0x2c, 0x48, 0x3e, 0x86, 0xdc, 0xed, 0x3e, 0xeb, 0xfd, + 0xe0, 0xe9, 0xcc, 0x16, 0xd4, 0x36, 0x1a, 0xa7, 0xfa, 0x17, 0xaa, 0xee, 0xa0, 0x66, 0xaa, 0xaa, 0xb8, 0xf7, 0x31, + 0x04, 0xc0, 0x83, 0xb5, 0x0c, 0xd5, 0x0e, 0xa1, 0x6b, 0x67, 0xa6, 0x3a, 0xa6, 0x24, 0x5c, 0xba, 0x39, 0xc4, 0xdc, + 0x07, 0xa3, 0x5a, 0x03, 0x1a, 0x5a, 0x04, 0x33, 0x96, 0x87, 0x7c, 0x1c, 0xca, 0xad, 0x33, 0x54, 0xe8, 0x33, 0x34, + 0xf2, 0x40, 0xfe, 0x8d, 0x33, 0x93, 0x69, 0x68, 0x68, 0xde, 0x52, 0x1f, 0x80, 0x76, 0x75, 0x2d, 0x0e, 0xf9, 0x2b, + 0x5a, 0x3a, 0xef, 0x99, 0x45, 0x17, 0xb5, 0x61, 0x85, 0xba, 0x1d, 0xb4, 0x8e, 0x61, 0x4a, 0xcc, 0x14, 0x58, 0x3b, + 0xbd, 0x0f, 0x77, 0x76, 0xb5, 0x61, 0x11, 0xb9, 0x69, 0x11, 0x07, 0x93, 0x90, 0xa2, 0x25, 0x0f, 0x29, 0x16, 0x60, + 0x07, 0x59, 0xac, 0xcb, 0xf1, 0x33, 0x7f, 0x39, 0x6a, 0x56, 0xd2, 0xbb, 0x1d, 0x0c, 0x81, 0xcb, 0x57, 0x60, 0x1b, + 0x8a, 0xb9, 0x23, 0x2c, 0x3c, 0xd4, 0x9e, 0x7e, 0xde, 0xba, 0xcd, 0xcd, 0x82, 0xb8, 0x15, 0x18, 0xd3, 0x70, 0xe9, + 0xcd, 0xc2, 0x77, 0x2a, 0xb7, 0x0e, 0x87, 0xf6, 0x9a, 0xb0, 0x32, 0x5e, 0x0d, 0x73, 0xb2, 0x71, 0xf4, 0x7c, 0xdf, + 0xc6, 0xf3, 0xef, 0x05, 0x2b, 0xee, 0xaf, 0x19, 0xd8, 0x58, 0x0b, 0x70, 0x37, 0xae, 0x96, 0xa1, 0x32, 0x90, 0xef, + 0x0b, 0xcd, 0xba, 0xac, 0xf1, 0x77, 0xa3, 0x62, 0xac, 0xf5, 0x3d, 0xa5, 0xa7, 0xad, 0x31, 0xdb, 0x85, 0x7d, 0xd3, + 0x75, 0x93, 0xf5, 0xb4, 0x22, 0xae, 0x82, 0xb4, 0xbd, 0x5b, 0xc0, 0x85, 0xef, 0x0f, 0x3b, 0xc8, 0x87, 0x9b, 0xaa, + 0x1b, 0x48, 0x82, 0x6b, 0x3f, 0xf1, 0xed, 0xa9, 0xee, 0xb2, 0xd6, 0xfd, 0xf6, 0x54, 0x6b, 0x97, 0x85, 0xda, 0x90, + 0x08, 0xdb, 0x7e, 0x4a, 0xff, 0x69, 0xb9, 0x5e, 0xa3, 0x35, 0x0c, 0xef, 0x3d, 0xef, 0x85, 0xe1, 0x7b, 0x67, 0xa1, + 0x18, 0xc1, 0x45, 0xee, 0x75, 0x26, 0x1c, 0x21, 0xaf, 0x46, 0xf0, 0x9e, 0x6f, 0x0d, 0xe1, 0x3d, 0xf7, 0x9c, 0x5e, + 0x41, 0x6a, 0x9a, 0xe4, 0x2c, 0x75, 0xf4, 0x13, 0x19, 0x24, 0xd4, 0x7c, 0xdc, 0x6b, 0x4e, 0xb8, 0xfa, 0x1c, 0x03, + 0xff, 0x85, 0x47, 0x0b, 0xa5, 0x44, 0x8e, 0x79, 0x3e, 0x5f, 0x28, 0x2c, 0xf5, 0xe8, 0x97, 0x63, 0x91, 0xab, 0xe6, + 0x98, 0xce, 0x78, 0x76, 0x1f, 0x2f, 0x78, 0x73, 0x26, 0x72, 0x21, 0xe7, 0x34, 0x61, 0x58, 0xde, 0x4b, 0xc5, 0x66, + 0xcd, 0x05, 0xc7, 0xcf, 0x59, 0xf6, 0x95, 0x29, 0x9e, 0x50, 0xfc, 0x56, 0x8c, 0x84, 0x12, 0xf8, 0xf5, 0xdd, 0xfd, + 0x84, 0xe5, 0xf8, 0xf7, 0xd1, 0x22, 0x57, 0x0b, 0x2c, 0x69, 0x2e, 0x9b, 0x92, 0x15, 0x7c, 0xdc, 0x6b, 0x36, 0xe7, + 0x05, 0x9f, 0xd1, 0xe2, 0xbe, 0x99, 0x88, 0x4c, 0x14, 0xf1, 0x7f, 0xb5, 0x8e, 0xe9, 0xa3, 0xf1, 0x49, 0x4f, 0x15, + 0x34, 0x97, 0x1c, 0x16, 0x26, 0xa6, 0x59, 0xb6, 0x77, 0xdc, 0x6d, 0xcd, 0xe4, 0xbe, 0xb9, 0xf0, 0xa3, 0xb9, 0x5a, + 0x7f, 0xc6, 0x1f, 0x04, 0x8c, 0x32, 0x1a, 0xa9, 0xdc, 0x0e, 0x72, 0x99, 0x2c, 0x0a, 0x29, 0x8a, 0x78, 0x2e, 0x78, + 0xae, 0x58, 0xd1, 0x1b, 0x89, 0x22, 0x65, 0x45, 0xb3, 0xa0, 0x29, 0x5f, 0xc8, 0xf8, 0x64, 0x7e, 0xd7, 0xab, 0xf7, + 0x60, 0xf2, 0xe3, 0x5c, 0xe4, 0xac, 0x07, 0xfc, 0xc6, 0xa4, 0x10, 0x8b, 0x3c, 0xb5, 0xc3, 0x58, 0xe4, 0x92, 0xa9, + 0xde, 0x9c, 0xa6, 0x60, 0x07, 0x1c, 0x9f, 0xcd, 0xef, 0x7a, 0x7a, 0xd6, 0xb7, 0x8c, 0x4f, 0xa6, 0x2a, 0xee, 0xb6, + 0x5a, 0xe6, 0x5b, 0xf2, 0x7f, 0x58, 0xdc, 0xee, 0x44, 0x9d, 0xee, 0xfc, 0x0e, 0x38, 0x78, 0xc5, 0x8a, 0x26, 0xc0, + 0x02, 0x2a, 0xb5, 0xa3, 0xd6, 0xa3, 0xe3, 0x87, 0x90, 0x01, 0x36, 0x0e, 0x4d, 0x3d, 0x21, 0x30, 0x76, 0x8f, 0x17, + 0xf3, 0x39, 0x2b, 0xc0, 0x8b, 0xbe, 0x37, 0xa3, 0xc5, 0x84, 0xe7, 0xcd, 0x42, 0x37, 0xda, 0x3c, 0x9b, 0xdf, 0xad, + 0x61, 0x3e, 0xb1, 0x31, 0x5b, 0xb5, 0xd3, 0xb2, 0x5f, 0x4b, 0x6f, 0x88, 0x3a, 0x26, 0x4d, 0x5c, 0x4c, 0x46, 0x34, + 0x6c, 0x77, 0x1e, 0x62, 0xf7, 0xbf, 0xa8, 0x83, 0x3c, 0xb0, 0x35, 0xd3, 0x45, 0xa1, 0x6f, 0x51, 0xe3, 0xb6, 0x34, + 0xcd, 0x4e, 0xc5, 0x57, 0x56, 0xb8, 0x56, 0xf5, 0xc7, 0x72, 0x6b, 0xde, 0xff, 0x49, 0xa3, 0x9f, 0xf1, 0x84, 0xc2, + 0x1a, 0x68, 0xe4, 0x18, 0x68, 0x79, 0x10, 0x66, 0x3a, 0x5c, 0xde, 0xf2, 0x54, 0x4d, 0xe3, 0x76, 0xab, 0xf5, 0x43, + 0xb5, 0x62, 0xbd, 0xa9, 0x01, 0x5d, 0xbb, 0x60, 0xb3, 0xda, 0x3a, 0xce, 0x68, 0x89, 0x6d, 0xcb, 0xb9, 0xb0, 0x4b, + 0x5e, 0xb0, 0x4c, 0x47, 0x93, 0x59, 0x5b, 0x94, 0xdb, 0x1a, 0x27, 0xcf, 0xa7, 0xac, 0xe0, 0xaa, 0x57, 0xff, 0xaa, + 0x3a, 0xde, 0x5e, 0xfd, 0xb5, 0x91, 0x43, 0x97, 0xa6, 0x86, 0xbd, 0xf4, 0xbc, 0x82, 0x8f, 0xed, 0xd5, 0xff, 0x4a, + 0x8b, 0x70, 0x03, 0x31, 0xb1, 0x5f, 0x03, 0xad, 0xbd, 0x39, 0x17, 0x60, 0x92, 0x39, 0xc4, 0xdf, 0x80, 0x42, 0x42, + 0xb3, 0x24, 0x84, 0x11, 0xed, 0x35, 0xf7, 0x8e, 0x0b, 0x36, 0x43, 0x0e, 0x10, 0xd1, 0xc3, 0x6e, 0xc1, 0x66, 0xeb, + 0x48, 0x57, 0x5f, 0x6a, 0x14, 0xa1, 0x19, 0x9f, 0xe4, 0x71, 0xc2, 0x00, 0x7d, 0xd7, 0x11, 0xcb, 0x15, 0x57, 0xf7, + 0xcd, 0x42, 0xdc, 0x2e, 0x53, 0x2e, 0xe7, 0x19, 0xbd, 0x8f, 0xc7, 0x19, 0xbb, 0xeb, 0xe9, 0x52, 0x4d, 0xae, 0xd8, + 0x4c, 0xda, 0xb2, 0x3d, 0x48, 0x6f, 0xa6, 0xc6, 0x6c, 0x02, 0xa0, 0x27, 0x6e, 0x37, 0xf7, 0x4f, 0x74, 0x2c, 0xf7, + 0x18, 0x95, 0xac, 0x29, 0x16, 0x6a, 0xaf, 0x25, 0x7b, 0x33, 0x9e, 0x37, 0xed, 0x40, 0x4e, 0x5a, 0xf3, 0xbb, 0xde, + 0x36, 0xe4, 0xbd, 0xfe, 0x23, 0x76, 0x37, 0xa7, 0x79, 0xca, 0xd2, 0xa5, 0x57, 0xad, 0x03, 0xf5, 0xfc, 0x52, 0x71, + 0xae, 0xa6, 0x4d, 0x6d, 0xeb, 0x15, 0x76, 0x72, 0xf4, 0x0d, 0xd4, 0x7a, 0xd4, 0xc2, 0xe6, 0xff, 0xa3, 0x36, 0xf2, + 0x2b, 0xef, 0x41, 0xd8, 0x25, 0x3e, 0xbe, 0x6f, 0xc2, 0xdf, 0x25, 0xf8, 0x16, 0xf1, 0x84, 0x66, 0x16, 0x22, 0x33, + 0x9e, 0xa6, 0x59, 0x6d, 0x44, 0x17, 0x5e, 0x67, 0x6d, 0xb4, 0x84, 0xf9, 0xc7, 0xad, 0xbd, 0xd6, 0x9e, 0x9e, 0x8b, + 0xdd, 0xe6, 0x27, 0x27, 0x0f, 0x8f, 0x1f, 0xb1, 0x5e, 0xc6, 0x73, 0x56, 0x9b, 0xea, 0x77, 0x41, 0xed, 0x37, 0xdc, + 0xb1, 0x0d, 0xb7, 0xf7, 0xda, 0x7b, 0x27, 0xad, 0x1f, 0xdc, 0x6e, 0xcd, 0xd8, 0x58, 0xc5, 0xed, 0xd3, 0xf9, 0x5d, + 0x7d, 0xfb, 0x9e, 0xb9, 0xa6, 0x6f, 0x0b, 0x3a, 0x8f, 0x73, 0x01, 0x7f, 0x7a, 0xb0, 0xc9, 0xc6, 0x99, 0xb8, 0x8d, + 0xa7, 0x3c, 0x4d, 0x59, 0x6e, 0x0a, 0x94, 0x89, 0x2c, 0xcb, 0xf8, 0x5c, 0x72, 0xb3, 0x1a, 0x16, 0x77, 0xbb, 0x1b, + 0x50, 0xf5, 0x07, 0x74, 0xec, 0x0d, 0xa8, 0x5b, 0x0d, 0xa8, 0xea, 0xdf, 0x1f, 0x61, 0x67, 0x63, 0xae, 0xba, 0x54, + 0xaf, 0x86, 0x49, 0x7f, 0x2d, 0xa4, 0x02, 0x98, 0x97, 0x46, 0x1a, 0x40, 0xc5, 0x9b, 0x23, 0xa6, 0x6e, 0x19, 0xcb, + 0xbf, 0x3d, 0x88, 0x8b, 0x58, 0xe4, 0xd9, 0xbd, 0xf9, 0x5c, 0xfa, 0x5d, 0xd2, 0x85, 0x12, 0xeb, 0x68, 0xc4, 0x73, + 0x5a, 0xdc, 0xdf, 0x48, 0x96, 0x4b, 0x51, 0xdc, 0x88, 0xf1, 0x78, 0xf9, 0x2d, 0xd2, 0xf2, 0x10, 0xad, 0x23, 0xc9, + 0xf3, 0x49, 0xc6, 0x0c, 0x51, 0xd2, 0x88, 0x60, 0x89, 0xb9, 0x69, 0x57, 0x37, 0x59, 0x1b, 0xb4, 0xbf, 0xf3, 0x74, + 0xbb, 0xc3, 0x38, 0x6e, 0xde, 0xb2, 0xd1, 0x17, 0xae, 0x0c, 0x9e, 0x35, 0xe5, 0x2d, 0x78, 0xbc, 0xe8, 0x65, 0x98, + 0xb3, 0x62, 0xe9, 0x68, 0x78, 0xcb, 0xa3, 0x3a, 0x51, 0x92, 0xf1, 0x19, 0x55, 0xcc, 0xa3, 0x54, 0x65, 0x27, 0x93, + 0x82, 0xa7, 0xdb, 0x38, 0xd2, 0x83, 0xe4, 0xa6, 0x33, 0xa8, 0x82, 0x9e, 0x16, 0xb3, 0x5c, 0xc6, 0x05, 0x9b, 0x33, + 0xaa, 0xc2, 0x63, 0xdc, 0x1e, 0x17, 0xa8, 0x37, 0xa1, 0xf3, 0x18, 0xf0, 0xc2, 0x75, 0xd9, 0x86, 0x25, 0xd8, 0xde, + 0xae, 0xeb, 0xcf, 0xf8, 0x8b, 0xd4, 0x87, 0x97, 0xa2, 0xa3, 0x26, 0x84, 0x1f, 0x63, 0x45, 0xb9, 0xc5, 0x79, 0xae, + 0x11, 0x56, 0xaf, 0xcf, 0xe6, 0x26, 0xf5, 0x8f, 0xa0, 0x93, 0x56, 0xcb, 0xf5, 0xd3, 0x34, 0x75, 0xe2, 0x76, 0xd4, + 0x65, 0xb3, 0x5d, 0xe4, 0xa1, 0x4e, 0x0b, 0xdb, 0x9d, 0xf9, 0xdd, 0x9e, 0xfe, 0xa7, 0xb5, 0xd7, 0xda, 0xa6, 0x7d, + 0xdb, 0xcb, 0x74, 0x8c, 0x1c, 0x62, 0x29, 0x31, 0x8f, 0xdb, 0x6c, 0xd6, 0x5b, 0x48, 0x38, 0xe7, 0x34, 0x69, 0xd6, + 0xe7, 0xe7, 0x5a, 0xcf, 0x04, 0xd0, 0x88, 0xf2, 0x1c, 0x8e, 0x15, 0x73, 0xb4, 0x42, 0x1f, 0x52, 0x80, 0x1d, 0xf8, + 0xce, 0x46, 0xeb, 0xc3, 0x6a, 0xed, 0x55, 0x03, 0x83, 0x7f, 0xd6, 0x9f, 0x2b, 0xc6, 0xf4, 0x05, 0xf3, 0x04, 0x03, + 0xde, 0x88, 0xba, 0xab, 0x96, 0x15, 0x06, 0x52, 0x55, 0xc9, 0x28, 0xda, 0x95, 0x62, 0x46, 0xef, 0x8c, 0x4f, 0xc5, + 0x8c, 0xe7, 0x60, 0xb1, 0x85, 0xb0, 0xf2, 0x6c, 0xdb, 0xa7, 0x7e, 0x43, 0xa9, 0x0a, 0xa1, 0xe1, 0xc3, 0x4e, 0xd4, + 0xed, 0x22, 0xdc, 0xc2, 0x9d, 0x6e, 0xd7, 0x13, 0x46, 0xc6, 0x6a, 0x57, 0xd1, 0x5d, 0x25, 0xf3, 0x1d, 0x25, 0x8f, + 0x74, 0xa3, 0x47, 0xed, 0x56, 0x0b, 0x6b, 0xbf, 0xf1, 0xb2, 0x30, 0xcb, 0x77, 0x34, 0xdb, 0x6e, 0xb5, 0xa0, 0x59, + 0xf8, 0x63, 0xe7, 0xf5, 0x0b, 0x59, 0xb6, 0xe2, 0x16, 0x6e, 0xc7, 0x6d, 0xdc, 0x89, 0x3b, 0xf8, 0x38, 0x3e, 0xc6, + 0x27, 0xf1, 0x09, 0xee, 0xc6, 0x5d, 0x7c, 0x1a, 0x9f, 0xe2, 0x87, 0xf1, 0x43, 0x7c, 0x16, 0x9f, 0xe1, 0x47, 0xf1, + 0x23, 0x7c, 0x19, 0xb7, 0x5b, 0xf8, 0x71, 0xdc, 0x6e, 0xe3, 0xab, 0xb8, 0xdd, 0xc1, 0x4f, 0xe2, 0xf6, 0x31, 0x7e, + 0x1a, 0xb7, 0x4f, 0xf0, 0xb3, 0xb8, 0xdd, 0xc5, 0x14, 0x72, 0x47, 0x90, 0x9b, 0x40, 0x6e, 0x0a, 0xb9, 0x0c, 0x72, + 0xc7, 0x71, 0xbb, 0xbb, 0xc6, 0xd2, 0xc4, 0x9a, 0x08, 0x5a, 0xed, 0xce, 0xf1, 0x49, 0xf7, 0xf4, 0xe1, 0xd9, 0xa3, + 0xcb, 0xc7, 0x57, 0x4f, 0x9e, 0x3e, 0x0b, 0x86, 0x78, 0xa4, 0x5d, 0x3e, 0xa4, 0x1c, 0xf0, 0x83, 0x76, 0x77, 0x88, + 0x6f, 0xdc, 0x67, 0xc8, 0x0f, 0x3a, 0x27, 0x2d, 0x74, 0x71, 0x71, 0x32, 0x6c, 0x94, 0xb9, 0xef, 0xb5, 0xa7, 0x49, + 0x95, 0x45, 0x08, 0x09, 0x21, 0x07, 0xe1, 0x7b, 0x5d, 0xef, 0x3d, 0x0b, 0x79, 0x54, 0xa0, 0x83, 0x03, 0xfd, 0x63, + 0xe2, 0x7e, 0x8c, 0xdc, 0x0f, 0xea, 0x2d, 0xd2, 0x1d, 0x0d, 0xad, 0xab, 0xb1, 0x2a, 0x0d, 0xfd, 0x4b, 0x1b, 0x9a, + 0x3d, 0x6e, 0xad, 0xd9, 0xff, 0x2b, 0x30, 0xd6, 0x2a, 0xe4, 0xc4, 0x68, 0x84, 0xba, 0x7d, 0x46, 0x96, 0x45, 0xdc, + 0xe9, 0x76, 0x0f, 0x7e, 0x19, 0xf0, 0x41, 0x7b, 0x38, 0x3c, 0x6c, 0x3f, 0xc4, 0x93, 0x32, 0xa1, 0x63, 0x12, 0x46, + 0x65, 0xc2, 0xb1, 0x49, 0xa0, 0xb1, 0xa9, 0x0d, 0x49, 0x27, 0x3a, 0x09, 0x4a, 0xac, 0x63, 0xdd, 0xf6, 0x43, 0xd3, + 0xf6, 0x23, 0x30, 0xa3, 0xd2, 0xcd, 0xdb, 0xa6, 0xcf, 0xcf, 0x4f, 0x56, 0xb6, 0x51, 0x3c, 0x89, 0x6d, 0x6b, 0x2e, + 0xf1, 0x64, 0x38, 0xc4, 0x23, 0x9d, 0xd8, 0xad, 0x12, 0x4f, 0x87, 0x43, 0xdb, 0xd5, 0x23, 0xdd, 0xd5, 0xc3, 0x2a, + 0xeb, 0x6c, 0x38, 0xd4, 0x5d, 0x22, 0xeb, 0x34, 0x2f, 0xd5, 0xde, 0xd7, 0x52, 0x71, 0xc1, 0xcf, 0x3b, 0xdd, 0x6e, + 0x1f, 0x30, 0x4c, 0x1b, 0xc3, 0x3a, 0x18, 0xdd, 0x7a, 0x30, 0xba, 0x87, 0xdf, 0xfd, 0x11, 0x8d, 0x6f, 0x68, 0x09, + 0xa4, 0x7e, 0xf0, 0x5f, 0x41, 0x43, 0x69, 0x98, 0xeb, 0x3f, 0x13, 0xf3, 0x67, 0x84, 0x1a, 0x5f, 0x29, 0x80, 0x1b, + 0x54, 0x31, 0x4e, 0x97, 0xaa, 0x7b, 0xfc, 0x42, 0xc1, 0xb7, 0x65, 0x2a, 0x33, 0xda, 0x5f, 0x4d, 0x6f, 0x47, 0xab, + 0xa9, 0xfc, 0x8a, 0xfe, 0x0c, 0xff, 0x94, 0x87, 0xe1, 0xa0, 0xd9, 0x88, 0xd8, 0x9f, 0x29, 0x38, 0xd1, 0xf4, 0xe3, + 0x94, 0x4d, 0x50, 0x7f, 0xf0, 0xa7, 0xc4, 0xc3, 0x86, 0x97, 0xf1, 0xc3, 0x76, 0x0a, 0xb8, 0xd8, 0x6c, 0x26, 0x86, + 0x3f, 0xa0, 0x3e, 0xea, 0xff, 0x29, 0x0f, 0xff, 0x44, 0x0f, 0x8e, 0xaa, 0xb9, 0xfc, 0x2e, 0xec, 0x16, 0xae, 0xe2, + 0xee, 0x1c, 0x96, 0x5b, 0x98, 0xe1, 0x76, 0x93, 0x41, 0x94, 0x32, 0xf0, 0xc1, 0x26, 0xa1, 0x68, 0xf0, 0xa3, 0xe3, + 0x16, 0xfa, 0xa1, 0xdd, 0x01, 0xad, 0x42, 0x53, 0x1e, 0x6e, 0x6f, 0xfa, 0xa2, 0x79, 0x8c, 0x1f, 0x35, 0x0b, 0xdc, + 0x46, 0xb8, 0xd9, 0x76, 0xea, 0xde, 0x41, 0x1e, 0xb6, 0x10, 0xce, 0xc3, 0x33, 0xf8, 0xe7, 0x04, 0x0d, 0xab, 0x0d, + 0x79, 0x4d, 0x37, 0x7b, 0x07, 0x87, 0x51, 0x12, 0xe6, 0x0d, 0x7e, 0x74, 0xda, 0x42, 0x3f, 0x9c, 0xea, 0x8e, 0xd8, + 0xa1, 0xda, 0xd1, 0x95, 0xc0, 0x27, 0x4d, 0x01, 0x1d, 0xb5, 0xca, 0x7e, 0x64, 0xd8, 0x45, 0x58, 0x86, 0xc7, 0xf0, + 0x4f, 0xdb, 0xef, 0xe7, 0xd7, 0xad, 0x7e, 0xf4, 0xbc, 0xdb, 0x38, 0xea, 0x1a, 0xff, 0xd3, 0xdc, 0x5c, 0x06, 0x37, + 0xd8, 0x45, 0x5b, 0xdf, 0x62, 0xb5, 0x8f, 0xe0, 0x03, 0x61, 0x75, 0x48, 0x72, 0xcc, 0x0e, 0xc1, 0x71, 0x15, 0xec, + 0x35, 0xf2, 0xf3, 0xe3, 0x5e, 0xde, 0x68, 0x20, 0x90, 0x0f, 0x0f, 0x49, 0xbb, 0xa9, 0x9a, 0x0c, 0xc3, 0xef, 0x06, + 0x29, 0xa3, 0xa1, 0xc9, 0xaa, 0xd7, 0x2b, 0xdb, 0xab, 0xb9, 0xf2, 0x76, 0xd8, 0x01, 0x62, 0x62, 0x3f, 0x54, 0x4d, + 0x86, 0x8e, 0x64, 0x23, 0x54, 0xe7, 0xac, 0x7f, 0x1a, 0xb7, 0x90, 0xc6, 0xce, 0xbc, 0x1f, 0xb2, 0x26, 0x87, 0xf4, + 0x4e, 0x1c, 0xf2, 0xa6, 0x82, 0x5f, 0x27, 0x1e, 0xb4, 0x24, 0xe0, 0x5d, 0xe5, 0x86, 0x53, 0x1c, 0x75, 0xba, 0x5d, + 0x2c, 0x09, 0x8f, 0x26, 0xfa, 0x57, 0x4e, 0x78, 0x34, 0xd2, 0xbf, 0x04, 0x29, 0xe1, 0x65, 0x7a, 0xc7, 0x05, 0xf1, + 0x56, 0x55, 0xa7, 0x50, 0x58, 0xd0, 0x02, 0x1d, 0x75, 0xdc, 0x7d, 0x38, 0x9e, 0xba, 0x39, 0x80, 0xfc, 0x5f, 0x68, + 0x53, 0x48, 0xd1, 0x2c, 0x70, 0x46, 0xe8, 0x45, 0xd4, 0xed, 0x4f, 0x8f, 0xc2, 0x4e, 0x53, 0x34, 0x0b, 0x14, 0x4f, + 0x8f, 0x74, 0x4d, 0x9c, 0x90, 0x2b, 0x6a, 0x5a, 0xc3, 0x53, 0xb8, 0xc4, 0x4c, 0x48, 0x72, 0x78, 0xda, 0x6a, 0x44, + 0x5d, 0x84, 0x07, 0xc9, 0xaa, 0x85, 0xb3, 0xd5, 0xaa, 0x85, 0xa9, 0xbf, 0x0c, 0xd2, 0x01, 0xa4, 0x54, 0x51, 0x6d, + 0x06, 0xa5, 0xe9, 0xf3, 0x50, 0xc1, 0x85, 0xbc, 0x02, 0x37, 0x17, 0x05, 0x0e, 0x38, 0x31, 0xb7, 0x37, 0x61, 0x48, + 0x87, 0xe5, 0x1b, 0xfb, 0x4a, 0xab, 0x2b, 0xe9, 0xd6, 0xd5, 0x8e, 0xfc, 0x57, 0x19, 0xfe, 0x2e, 0xb0, 0x49, 0xab, + 0x8a, 0xbd, 0xa6, 0xdb, 0xc5, 0x7e, 0xa5, 0x5b, 0xc5, 0xde, 0xec, 0x28, 0x76, 0xbd, 0x5d, 0xec, 0xa3, 0xf0, 0x54, + 0x6c, 0xfc, 0x87, 0xe3, 0xd3, 0x56, 0xe3, 0x18, 0x90, 0xf5, 0xf8, 0xb4, 0x55, 0x15, 0x7a, 0x40, 0xab, 0xb5, 0x52, + 0xe4, 0x0b, 0x35, 0x4e, 0x06, 0xdc, 0x79, 0x3b, 0xeb, 0x85, 0x33, 0xbe, 0xd6, 0xa5, 0x63, 0xf5, 0xa0, 0x0b, 0x46, + 0x1c, 0x52, 0x53, 0x3b, 0x35, 0x38, 0x1d, 0xf6, 0xa7, 0x2c, 0x6c, 0x40, 0x2a, 0x8a, 0xc7, 0xca, 0xfe, 0x42, 0xe5, + 0x5d, 0xee, 0x47, 0x01, 0x49, 0x9d, 0x21, 0xc2, 0x82, 0x34, 0xd4, 0xe0, 0x78, 0xa8, 0xcf, 0xbb, 0x02, 0x7e, 0x9f, + 0xe8, 0xdf, 0xa5, 0x26, 0xc5, 0x7a, 0x22, 0x4c, 0x6f, 0x47, 0x41, 0x5f, 0x92, 0xd7, 0x34, 0xd4, 0xc6, 0xe5, 0x28, + 0x2e, 0x33, 0xe4, 0x57, 0xc8, 0x78, 0x53, 0x66, 0x48, 0x72, 0x25, 0xed, 0x6f, 0xbc, 0x2c, 0x62, 0x30, 0x34, 0xc1, + 0x93, 0x18, 0x8c, 0x4c, 0xf0, 0x28, 0x96, 0xe0, 0x08, 0x41, 0x63, 0xe6, 0x99, 0xaf, 0x5f, 0x5a, 0xd5, 0x95, 0xbe, + 0x6e, 0x25, 0x1a, 0x4b, 0x7b, 0x0c, 0x4e, 0x8a, 0x8f, 0x22, 0x84, 0xbf, 0x0d, 0x85, 0x30, 0x83, 0x36, 0x19, 0xc2, + 0x3c, 0x2a, 0x08, 0xa4, 0x61, 0x1e, 0x4d, 0x08, 0x83, 0x26, 0x79, 0x34, 0x22, 0x6c, 0xd0, 0xf1, 0xd0, 0xe4, 0xa9, + 0x86, 0x1d, 0x00, 0x87, 0xd7, 0x6f, 0xb0, 0x95, 0x69, 0x1c, 0xae, 0xc6, 0xa1, 0x09, 0x49, 0x58, 0x1e, 0xc2, 0x2c, + 0x60, 0x73, 0xea, 0x9f, 0x9d, 0x2a, 0xee, 0x23, 0x8f, 0xa8, 0xa6, 0xde, 0x9f, 0x81, 0xac, 0x86, 0x0f, 0x96, 0x6c, + 0x8d, 0xf7, 0x1e, 0x2c, 0xe5, 0xfa, 0x07, 0xf8, 0x93, 0xdb, 0x3f, 0x4a, 0x9f, 0x7e, 0x6b, 0xf4, 0x39, 0x86, 0x62, + 0x3b, 0x4a, 0xa1, 0xcf, 0xce, 0x0f, 0x2e, 0x27, 0xcb, 0xbb, 0x38, 0x48, 0x69, 0xf1, 0x25, 0xc0, 0x9f, 0xe2, 0x20, + 0x03, 0x46, 0x30, 0xc0, 0x1f, 0xe3, 0xa0, 0x60, 0x01, 0xfe, 0x23, 0x0e, 0x46, 0xd9, 0x22, 0xc0, 0x1f, 0xe2, 0x60, + 0x52, 0x04, 0xf8, 0x3d, 0x68, 0x29, 0x53, 0xbe, 0x98, 0x05, 0xf8, 0xf7, 0x38, 0x90, 0xda, 0x0d, 0x00, 0x5f, 0xc6, + 0x01, 0x63, 0x01, 0x7e, 0x17, 0x07, 0x22, 0x0b, 0xf0, 0x75, 0x1c, 0x88, 0x22, 0xc0, 0x8f, 0xe3, 0xa0, 0xa0, 0x01, + 0xbe, 0x8a, 0x03, 0x28, 0x34, 0x09, 0xf0, 0x93, 0x38, 0x80, 0x96, 0x65, 0x80, 0xdf, 0xc6, 0x01, 0xcf, 0x03, 0xfc, + 0x5b, 0x1c, 0xa8, 0x45, 0xf1, 0xf7, 0x42, 0x70, 0x19, 0xe0, 0xa7, 0x71, 0x30, 0xe5, 0x01, 0x7e, 0x13, 0x07, 0x85, + 0x08, 0xf0, 0xeb, 0x38, 0xa0, 0x59, 0x80, 0x5f, 0xc5, 0x41, 0xc6, 0x02, 0xfc, 0x6b, 0x1c, 0xa4, 0x2c, 0xc0, 0x2f, + 0xe3, 0xe0, 0x9e, 0x65, 0x99, 0x08, 0xf0, 0xb3, 0x38, 0x60, 0x79, 0x80, 0x7f, 0x89, 0x83, 0x64, 0x1a, 0xe0, 0x9f, + 0xe2, 0x80, 0x16, 0x5f, 0x64, 0x80, 0x9f, 0xc7, 0x01, 0xa3, 0x01, 0x7e, 0x61, 0x3a, 0x9a, 0x04, 0xf8, 0xe7, 0x38, + 0xb8, 0x9d, 0x06, 0x6b, 0x9c, 0xe7, 0x64, 0xf9, 0x9a, 0x27, 0xec, 0x0f, 0x16, 0x07, 0xe3, 0xd6, 0xf8, 0x6c, 0x3c, + 0x0e, 0x30, 0xcd, 0x15, 0xff, 0x7b, 0xc1, 0x6e, 0x9f, 0x2a, 0x48, 0xa4, 0x6c, 0x94, 0x3e, 0x0c, 0x30, 0xfd, 0x7b, + 0x41, 0xe3, 0x60, 0x3c, 0xd6, 0x05, 0xfe, 0x5e, 0xd0, 0x19, 0x2d, 0xde, 0xb2, 0x38, 0x78, 0x38, 0x1e, 0x8f, 0xd3, + 0x93, 0x00, 0xd3, 0x7f, 0x16, 0x1f, 0x75, 0x0b, 0xba, 0xc0, 0x88, 0xf1, 0x09, 0xd4, 0xed, 0x8e, 0xbb, 0x69, 0x12, + 0xe0, 0x11, 0x97, 0x7f, 0x2f, 0xe0, 0x7b, 0xcc, 0x4e, 0x92, 0x93, 0x00, 0x8f, 0x32, 0x9a, 0x7c, 0x89, 0x83, 0x96, + 0xfe, 0x95, 0xff, 0xc2, 0xd2, 0xd7, 0x33, 0xa1, 0x75, 0xf8, 0x63, 0x36, 0x4a, 0xd2, 0x00, 0xeb, 0xc1, 0x8c, 0xe1, + 0xef, 0x57, 0xfe, 0x8e, 0xa9, 0x38, 0x38, 0xa3, 0x9d, 0x11, 0xeb, 0x04, 0x78, 0xf4, 0xe6, 0x36, 0x8f, 0x03, 0xda, + 0xed, 0xd0, 0x0e, 0x0d, 0xf0, 0x68, 0x51, 0x64, 0xf7, 0xb7, 0x42, 0xa4, 0x00, 0x84, 0xd1, 0xd9, 0xd9, 0xc3, 0x00, + 0x27, 0xf4, 0x57, 0x05, 0xb5, 0xbb, 0xe3, 0x47, 0x8c, 0xb6, 0x02, 0xfc, 0x0b, 0x2d, 0xd4, 0xc7, 0x85, 0xb4, 0x03, + 0x6d, 0x41, 0x8a, 0x48, 0xde, 0x81, 0x7e, 0x3b, 0x48, 0x3b, 0xa7, 0x8f, 0xda, 0x2c, 0xc0, 0xc9, 0xf5, 0x6b, 0xe8, + 0xed, 0xe1, 0xb8, 0xdb, 0x82, 0x8f, 0x1c, 0x04, 0x45, 0x56, 0x40, 0x23, 0xa7, 0x27, 0x8f, 0xba, 0x2c, 0xd5, 0x89, + 0x92, 0x67, 0x5f, 0xf4, 0xec, 0xcf, 0x60, 0x3e, 0x49, 0xc1, 0x67, 0x52, 0xe4, 0x71, 0x90, 0x26, 0xed, 0x93, 0x63, + 0x48, 0xb8, 0xa7, 0xb9, 0x03, 0xce, 0x1d, 0x54, 0x3d, 0x1b, 0x05, 0xf8, 0xce, 0xa4, 0x9e, 0x8d, 0xf4, 0xc7, 0xe4, + 0xdd, 0xaf, 0xf9, 0x9b, 0x34, 0x0e, 0x46, 0x67, 0x67, 0xa7, 0x2d, 0x48, 0xf8, 0x40, 0xef, 0xe3, 0x80, 0x3e, 0x82, + 0xff, 0x20, 0xfb, 0xe3, 0x33, 0xe8, 0x10, 0x46, 0x78, 0x37, 0xf9, 0xe8, 0xe7, 0x7c, 0x99, 0xd2, 0x2f, 0x3c, 0x0e, + 0x46, 0xe9, 0xe8, 0xe1, 0x29, 0xd4, 0x9b, 0xd1, 0xc9, 0x33, 0x45, 0xa1, 0xdd, 0x56, 0x4b, 0xb7, 0xfc, 0x8e, 0x7f, + 0x65, 0xba, 0x7a, 0xb7, 0x7b, 0x3a, 0xea, 0xc0, 0x08, 0xae, 0x41, 0xc3, 0x01, 0xe3, 0x39, 0x4b, 0x74, 0x83, 0xd7, + 0xc9, 0xd3, 0x34, 0x0e, 0x1e, 0x3d, 0x3a, 0xee, 0x24, 0x49, 0x80, 0xef, 0x3e, 0xa6, 0xa6, 0xb6, 0xce, 0x93, 0x00, + 0xfb, 0x38, 0x60, 0x8f, 0x1e, 0x9d, 0x3e, 0xa4, 0xf0, 0xfd, 0x5c, 0xb7, 0x75, 0x36, 0x1e, 0x25, 0x67, 0xd0, 0xd6, + 0xef, 0x30, 0x9d, 0x93, 0xb3, 0xe3, 0x54, 0xf7, 0xf5, 0xbb, 0x1e, 0x75, 0x67, 0x7c, 0x32, 0x3e, 0xd1, 0x99, 0x7a, + 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x0e, 0x12, 0x96, 0xb6, 0x03, 0x7c, 0x67, 0x17, 0xee, 0xd1, 0x49, 0xab, 0x95, 0x1e, + 0x07, 0x38, 0xbd, 0x9c, 0xcf, 0xdf, 0x6a, 0x08, 0xb6, 0x4f, 0x1e, 0x99, 0x6f, 0xf9, 0xe5, 0x1e, 0x9a, 0x1e, 0x69, + 0xa0, 0xa5, 0x7c, 0xa6, 0x5b, 0x3e, 0x7d, 0x04, 0xff, 0xe9, 0x6f, 0xdd, 0x74, 0xf9, 0x2d, 0xd2, 0x89, 0x59, 0x94, + 0x36, 0x7b, 0xd4, 0x82, 0x1a, 0x63, 0xfe, 0x71, 0x54, 0x70, 0x40, 0xa3, 0x51, 0x07, 0xfe, 0x2f, 0xc0, 0xe3, 0xec, + 0xfa, 0xb5, 0xc5, 0xd9, 0xf1, 0x98, 0x8e, 0x5b, 0x01, 0x1e, 0x8b, 0x8f, 0x52, 0x7d, 0xb8, 0xcc, 0xe3, 0xa0, 0xd3, + 0x39, 0x1b, 0xe9, 0x32, 0x8b, 0x5f, 0x24, 0xd7, 0x78, 0xdc, 0xd2, 0xad, 0x4c, 0xe8, 0x5b, 0x39, 0xba, 0x16, 0xb0, + 0x92, 0xf0, 0x5f, 0x80, 0x27, 0xa0, 0x16, 0xb3, 0xad, 0x9c, 0x99, 0xed, 0x30, 0x79, 0xa7, 0x51, 0x33, 0x7d, 0x08, + 0xf0, 0x72, 0xcb, 0x98, 0x52, 0xda, 0xed, 0xb4, 0x02, 0xac, 0x47, 0x7d, 0xd6, 0x82, 0xff, 0x02, 0x6c, 0x20, 0xa7, + 0xe1, 0x3a, 0xf9, 0xf8, 0xec, 0xe5, 0x6d, 0x1c, 0xd0, 0x74, 0x3c, 0x86, 0x25, 0xd1, 0x93, 0x71, 0xc5, 0xa6, 0x22, + 0x67, 0xf7, 0xbf, 0xde, 0xda, 0xed, 0xa2, 0x13, 0x94, 0x85, 0xce, 0xe9, 0xa3, 0xd1, 0x49, 0x80, 0xdf, 0xa6, 0x9c, + 0xe6, 0xb0, 0x4a, 0x49, 0xda, 0x4d, 0xba, 0x89, 0x4e, 0x98, 0x88, 0x38, 0x38, 0x81, 0x25, 0xef, 0x04, 0x98, 0x7f, + 0xbd, 0xbe, 0x37, 0xe8, 0x06, 0xb5, 0x2d, 0x82, 0x8c, 0x5b, 0xec, 0xf4, 0x2c, 0x09, 0x70, 0x46, 0xbf, 0x3e, 0xfb, + 0xb5, 0x88, 0x03, 0x76, 0xca, 0x4e, 0xc7, 0xd4, 0x7d, 0xff, 0x21, 0xa7, 0xba, 0x46, 0x6b, 0xdc, 0x85, 0xa4, 0xdb, + 0x5c, 0x8f, 0xf5, 0x61, 0x32, 0xd6, 0x18, 0xf2, 0x6a, 0x26, 0xf2, 0xe4, 0xe9, 0x78, 0x2c, 0x0c, 0x16, 0x53, 0xd8, + 0x84, 0x9f, 0x00, 0xda, 0x34, 0x4d, 0xcf, 0xd8, 0x69, 0x80, 0x3f, 0x99, 0x5d, 0x62, 0x27, 0xf0, 0xc9, 0x60, 0x36, + 0xb3, 0xbb, 0xfd, 0x93, 0x01, 0x0a, 0xcc, 0x77, 0x4c, 0xc7, 0x34, 0xed, 0x04, 0xf8, 0x93, 0x86, 0x4b, 0x7a, 0x0c, + 0xff, 0x41, 0x01, 0xe8, 0xec, 0x51, 0x8b, 0xb1, 0x47, 0x2d, 0xfd, 0xe5, 0xe7, 0xd9, 0x99, 0x8f, 0x4e, 0x93, 0x76, + 0x80, 0x3f, 0x59, 0x74, 0x1c, 0x8f, 0x69, 0x0b, 0xd0, 0xf1, 0x93, 0x45, 0xc7, 0x4e, 0x6b, 0xd4, 0xa1, 0xfa, 0xdb, + 0x60, 0xcd, 0xd9, 0xc3, 0x84, 0xc1, 0xe4, 0x3e, 0x19, 0x84, 0x7c, 0xf8, 0xf0, 0xec, 0xec, 0xd1, 0x23, 0xf8, 0xd4, + 0x6d, 0x97, 0x9f, 0x52, 0x5d, 0x66, 0x1a, 0xc9, 0x5a, 0xc9, 0x09, 0xd0, 0xc9, 0x4f, 0x7a, 0x8c, 0xe3, 0xf1, 0x98, + 0xb5, 0x02, 0x9c, 0xf1, 0x19, 0x33, 0x98, 0x60, 0x7e, 0xeb, 0x8e, 0x8e, 0x3b, 0x49, 0x7a, 0xdc, 0x09, 0x70, 0xf6, + 0xf6, 0x99, 0x9e, 0x4d, 0x0b, 0x66, 0xef, 0xb6, 0x9c, 0xc3, 0x9a, 0x19, 0x7d, 0x03, 0x83, 0x84, 0x95, 0x86, 0xca, + 0xef, 0x3d, 0x7a, 0x78, 0x7a, 0x9a, 0xa4, 0x30, 0xd0, 0xf7, 0xd0, 0x2d, 0x80, 0xf1, 0xbd, 0xd9, 0x7c, 0x23, 0xda, + 0xed, 0xc2, 0x74, 0xdf, 0xcf, 0x17, 0xc5, 0xfc, 0x55, 0x1c, 0x3c, 0x3a, 0x7e, 0xd8, 0x4a, 0x47, 0x01, 0x7e, 0x6f, + 0x27, 0x78, 0x9c, 0x8c, 0x8e, 0x1f, 0xb6, 0x03, 0xfc, 0x5e, 0xef, 0xb7, 0x87, 0xa3, 0xd3, 0x33, 0x38, 0x37, 0xde, + 0xcb, 0x79, 0xf1, 0x76, 0xa2, 0x0b, 0x8c, 0xe9, 0x23, 0x68, 0xf6, 0x37, 0xbd, 0x1b, 0xd3, 0x36, 0x6c, 0xe4, 0xf7, + 0x7a, 0x93, 0x69, 0x3c, 0x79, 0xd8, 0xee, 0x9e, 0x75, 0x03, 0x3c, 0xe3, 0x69, 0x0e, 0x04, 0x5e, 0x6f, 0x94, 0x47, + 0xed, 0x47, 0x0f, 0x5b, 0x01, 0x9e, 0xbd, 0x55, 0xc9, 0x47, 0x3a, 0xd3, 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa9, + 0xee, 0xdf, 0x48, 0x4b, 0x8f, 0x59, 0x3b, 0xc0, 0x33, 0x91, 0x24, 0x54, 0xbe, 0x35, 0x09, 0xa3, 0x6e, 0x80, 0x73, + 0xfa, 0x95, 0xfe, 0x25, 0xdc, 0x66, 0x4a, 0x19, 0x4d, 0x75, 0x9a, 0xc6, 0xe1, 0x00, 0xbf, 0x4b, 0xe1, 0x16, 0x2e, + 0x0e, 0xc6, 0xe9, 0xb8, 0x0b, 0xe0, 0x01, 0x02, 0x64, 0xb0, 0x1b, 0xa0, 0x01, 0x5f, 0xe9, 0xe3, 0x51, 0x1c, 0x9c, + 0x8e, 0xce, 0x58, 0xe7, 0x38, 0xc0, 0x25, 0x35, 0xa2, 0x5d, 0xc8, 0xd7, 0x9f, 0x1f, 0xf5, 0x96, 0x3a, 0x31, 0x09, + 0x1a, 0x40, 0x29, 0x7d, 0xd8, 0x4a, 0x4f, 0x03, 0x3c, 0x7f, 0xcd, 0xdc, 0x1e, 0x63, 0x8c, 0x9d, 0x01, 0x2c, 0x21, + 0x49, 0x23, 0xd0, 0xd9, 0x78, 0xf4, 0xe8, 0x4c, 0x7f, 0x03, 0x18, 0xe8, 0x98, 0x31, 0x00, 0xd2, 0xfc, 0x35, 0x2b, + 0x01, 0x91, 0x8e, 0x1e, 0xb6, 0x80, 0xbe, 0xcc, 0xe9, 0x9c, 0xde, 0xd3, 0xdb, 0xa7, 0x73, 0x3d, 0xa7, 0x71, 0xda, + 0x0d, 0xf0, 0xfc, 0xf9, 0x2f, 0xf3, 0xc5, 0x78, 0xac, 0x27, 0x44, 0x47, 0x8f, 0x02, 0x3c, 0x67, 0xc5, 0x02, 0xd6, + 0xe8, 0xac, 0x7b, 0x3c, 0x0e, 0xb0, 0x45, 0xc3, 0xa4, 0x95, 0x8c, 0xe0, 0x9a, 0x71, 0x31, 0x8b, 0x83, 0x34, 0xa5, + 0xad, 0x14, 0x2e, 0x1d, 0xc5, 0xed, 0xaf, 0x85, 0x41, 0x23, 0xa6, 0xf1, 0xc1, 0xae, 0x21, 0xcc, 0x17, 0xe0, 0xf1, + 0x71, 0xc4, 0x92, 0x84, 0xda, 0xc4, 0xd3, 0xd3, 0xe3, 0x63, 0xc0, 0x3d, 0x33, 0x43, 0x83, 0x20, 0x6f, 0xe4, 0xfd, + 0xa8, 0x10, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, 0xfe, 0xb5, 0xa6, 0xab, 0xed, 0xd3, 0x47, 0xb0, 0x00, + 0x92, 0xa6, 0xe9, 0x2b, 0x73, 0xb8, 0x9d, 0x8d, 0x4e, 0xba, 0xed, 0xe3, 0x00, 0xbb, 0x8d, 0x40, 0xcf, 0x5a, 0x0f, + 0x3b, 0x50, 0x22, 0x4f, 0xef, 0x4d, 0x89, 0xf1, 0x09, 0x3d, 0x39, 0x6d, 0x05, 0xd8, 0x6d, 0x0d, 0x76, 0x36, 0xea, + 0x3e, 0x84, 0x4f, 0x39, 0x65, 0x59, 0xa6, 0xf1, 0xbb, 0x0b, 0x70, 0x91, 0xfc, 0x59, 0x4e, 0xe3, 0x80, 0xb6, 0xba, + 0x9d, 0x4e, 0x0a, 0x9f, 0xd9, 0x57, 0x56, 0xc4, 0x41, 0xd2, 0x82, 0xff, 0x02, 0xec, 0xed, 0x24, 0x36, 0x0a, 0xb0, + 0xc6, 0xbb, 0x53, 0xda, 0xd5, 0x7b, 0xdf, 0xee, 0xaa, 0xd6, 0x59, 0x0b, 0x36, 0xac, 0xdd, 0x54, 0xf6, 0x4b, 0xe6, + 0xe2, 0xd6, 0x92, 0x58, 0x1a, 0x60, 0x0f, 0x41, 0xc7, 0x0f, 0xc7, 0x01, 0x76, 0x3b, 0xee, 0xe4, 0xf4, 0xac, 0x03, + 0xa4, 0x4c, 0x01, 0xa1, 0x48, 0x3b, 0xa3, 0x13, 0x20, 0x4d, 0x8a, 0xbd, 0x36, 0x78, 0x12, 0x60, 0xf5, 0x54, 0xaa, + 0x57, 0x71, 0x90, 0x9e, 0x8d, 0xc6, 0xe9, 0x59, 0x80, 0x95, 0x98, 0x51, 0x25, 0x34, 0x05, 0x3c, 0x3e, 0x79, 0x18, + 0x60, 0x8d, 0xe6, 0x2d, 0xd6, 0x4a, 0x5b, 0x01, 0xb6, 0x47, 0x09, 0x63, 0x67, 0x1d, 0x98, 0xd6, 0xcf, 0xcf, 0x15, + 0xe0, 0x72, 0xca, 0x46, 0xc7, 0x01, 0x2e, 0xe9, 0xbd, 0x26, 0x44, 0xf0, 0x25, 0x67, 0xe2, 0x8b, 0x65, 0x3d, 0x80, + 0xd4, 0xb9, 0x0d, 0x0f, 0xcb, 0xf0, 0xf2, 0xd6, 0xa0, 0x11, 0xd5, 0x5b, 0xdc, 0xbb, 0x86, 0x7d, 0x42, 0x43, 0xc7, + 0xb6, 0x73, 0xb2, 0x5c, 0xe3, 0x32, 0xba, 0xe9, 0x17, 0x76, 0x2f, 0xc3, 0x1c, 0x4c, 0xe2, 0x6b, 0x29, 0x32, 0x47, + 0xce, 0x9e, 0xdf, 0xba, 0x6c, 0x82, 0x20, 0x29, 0x49, 0xab, 0x27, 0xcf, 0x9d, 0x1b, 0x69, 0x4f, 0x42, 0xcc, 0x03, + 0x48, 0x2f, 0x08, 0x25, 0x0a, 0x42, 0xc3, 0x18, 0x61, 0xd2, 0x59, 0xd7, 0x6b, 0x99, 0x52, 0x18, 0x7b, 0x7d, 0x4a, + 0xa8, 0x0b, 0x0a, 0x0f, 0x77, 0xc4, 0xf9, 0x40, 0x0c, 0x51, 0x4f, 0x10, 0x1d, 0xe2, 0xf9, 0x45, 0xae, 0xc2, 0x3c, + 0x1f, 0x14, 0x43, 0xdc, 0x3e, 0x45, 0x18, 0x82, 0x27, 0x90, 0x81, 0xb8, 0xb8, 0x68, 0x9f, 0x1e, 0x68, 0xa1, 0xef, + 0xe2, 0xe2, 0xcc, 0xfc, 0x80, 0x7f, 0x87, 0x55, 0xc0, 0x6a, 0x18, 0xdf, 0x63, 0xe6, 0x69, 0xf4, 0x34, 0x7f, 0xfd, + 0x98, 0xad, 0x56, 0xe1, 0x63, 0x46, 0x60, 0xc6, 0xf8, 0x31, 0x8b, 0xf4, 0xa5, 0x85, 0x71, 0x8d, 0x21, 0x03, 0xd0, + 0x9c, 0xb5, 0x30, 0x84, 0x51, 0x77, 0x9c, 0xf7, 0x63, 0x36, 0xe0, 0x75, 0xb7, 0xea, 0x2a, 0x76, 0xf1, 0xc1, 0xc1, + 0xb2, 0x88, 0x95, 0x11, 0x13, 0x94, 0x11, 0x13, 0x94, 0x11, 0x13, 0x54, 0x15, 0x3d, 0xfe, 0xa4, 0x0f, 0x52, 0x8a, + 0x56, 0xb6, 0x58, 0x9e, 0xfa, 0x1d, 0xa8, 0x3d, 0x40, 0x3b, 0xd9, 0xaf, 0x94, 0x1d, 0xa5, 0xae, 0x62, 0xa7, 0x02, + 0x63, 0x67, 0xa2, 0xd5, 0x76, 0x1c, 0xfd, 0x3b, 0xea, 0x8e, 0x97, 0x35, 0xb1, 0xec, 0xdd, 0x4e, 0xb1, 0x0c, 0x56, + 0x52, 0x8b, 0x66, 0xfb, 0x26, 0x10, 0x87, 0x1a, 0x3c, 0xd4, 0x82, 0x59, 0x15, 0x1d, 0xae, 0x01, 0x49, 0x3d, 0x90, + 0x42, 0xce, 0xb4, 0x94, 0x56, 0xa0, 0x38, 0x55, 0x61, 0x01, 0x1a, 0x4a, 0xa7, 0xa0, 0x2c, 0x83, 0x98, 0x36, 0x34, + 0x40, 0x72, 0x23, 0xa3, 0x19, 0x59, 0xad, 0x0b, 0xa2, 0x0b, 0x68, 0xc2, 0xb4, 0xc4, 0x02, 0x0d, 0x48, 0xdd, 0x80, + 0xb4, 0x95, 0x41, 0x9c, 0xb1, 0xd9, 0x27, 0x3a, 0x3b, 0xd7, 0xd9, 0x79, 0x99, 0x2d, 0x5c, 0xb6, 0x11, 0x12, 0x85, + 0xce, 0x16, 0x65, 0x36, 0xc8, 0x6c, 0x78, 0x12, 0xe7, 0x78, 0x14, 0x0b, 0x23, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0xea, + 0x6b, 0x73, 0x0f, 0x0e, 0xc2, 0x52, 0x4e, 0xd2, 0x6a, 0xe2, 0x07, 0x4b, 0x1e, 0x15, 0x5a, 0x06, 0xe2, 0xd1, 0xc4, + 0xfe, 0x1d, 0xad, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfa, 0x46, 0x49, 0xf4, 0xd9, 0x29, 0x51, 0x1f, 0x73, 0x1d, 0xfe, + 0xe6, 0x9c, 0x44, 0xad, 0xd6, 0x71, 0xfb, 0xb8, 0x75, 0xd6, 0xe7, 0x87, 0xed, 0x4e, 0xf4, 0xa8, 0x13, 0x6b, 0x45, + 0xc4, 0x5c, 0xdc, 0x82, 0x02, 0xe6, 0xa8, 0x13, 0x9d, 0xa0, 0xc3, 0x76, 0xd4, 0xea, 0x76, 0x9b, 0xf0, 0x0f, 0x7e, + 0xaf, 0xca, 0x6a, 0x27, 0xad, 0x93, 0x6e, 0x9f, 0x1f, 0x6d, 0x54, 0x0a, 0x79, 0x03, 0x0a, 0xa2, 0x23, 0x5d, 0x09, + 0x43, 0xfd, 0x6a, 0x79, 0x9f, 0x6d, 0xe9, 0x79, 0xde, 0xab, 0x30, 0x37, 0xaa, 0x38, 0x80, 0xaa, 0xfb, 0x9a, 0x68, + 0x20, 0xba, 0xaf, 0x51, 0x19, 0xa2, 0x76, 0x59, 0x80, 0xa8, 0xfd, 0x98, 0x87, 0xb2, 0xc1, 0x0e, 0x43, 0x93, 0xaf, + 0xa0, 0x6e, 0x13, 0xc2, 0xc6, 0xe1, 0x89, 0xcd, 0xcd, 0xfd, 0xdc, 0x09, 0x42, 0xcd, 0x1c, 0x72, 0x47, 0x36, 0x57, + 0xf8, 0xb9, 0x23, 0x84, 0x9a, 0x02, 0x72, 0x69, 0xcc, 0x23, 0x0a, 0x39, 0x2a, 0xa2, 0x4d, 0x0d, 0xc9, 0x6a, 0x51, + 0x9e, 0x33, 0x37, 0x6c, 0x3e, 0x86, 0xe5, 0xd1, 0x04, 0xc5, 0x0a, 0xd2, 0x10, 0x35, 0xaf, 0xd2, 0xe6, 0xb4, 0x70, + 0xa9, 0xc6, 0x81, 0x8c, 0x06, 0xfc, 0x73, 0xc8, 0xf4, 0x7b, 0x13, 0xad, 0xfe, 0xf1, 0x69, 0x2b, 0x6e, 0x83, 0x8f, + 0x34, 0xc8, 0xda, 0xd2, 0xc8, 0xda, 0xd2, 0xc9, 0xda, 0xd2, 0xc9, 0xda, 0x20, 0xc0, 0x7b, 0x7d, 0xff, 0x2d, 0x6a, + 0x76, 0x27, 0xbc, 0x34, 0x62, 0x31, 0x56, 0x0a, 0xa1, 0x5a, 0xad, 0x96, 0x6b, 0x30, 0x31, 0x2a, 0x6b, 0x88, 0xbc, + 0x52, 0x7f, 0x2e, 0x8b, 0xb8, 0x85, 0x27, 0x31, 0x68, 0xb9, 0x5b, 0x98, 0xea, 0xcd, 0xed, 0xa8, 0xc2, 0x66, 0xf8, + 0x9a, 0xbe, 0x53, 0x27, 0x5f, 0x90, 0x63, 0xad, 0x3d, 0x5e, 0x16, 0x31, 0x37, 0x34, 0x83, 0x1b, 0x9a, 0xc1, 0x0d, + 0xcd, 0x80, 0x46, 0x70, 0x59, 0x58, 0x97, 0x8d, 0x28, 0x81, 0x2b, 0x81, 0xc1, 0xf1, 0x10, 0xa2, 0xf7, 0x85, 0x8a, + 0xe8, 0x51, 0x6f, 0x74, 0xde, 0x86, 0x68, 0x65, 0xa6, 0xa4, 0x8a, 0xa8, 0x76, 0xda, 0x2e, 0xc7, 0xfc, 0xaa, 0x86, + 0xf6, 0x11, 0x3c, 0x25, 0x73, 0xa9, 0xc2, 0x16, 0xd8, 0x6c, 0x04, 0x45, 0xd0, 0xd7, 0x64, 0x21, 0xd6, 0x3a, 0x1b, + 0x6b, 0x8b, 0xfd, 0x65, 0xc3, 0x05, 0xd6, 0x50, 0x02, 0xff, 0x01, 0x85, 0x2f, 0xac, 0xf2, 0xc9, 0x2f, 0x4d, 0x4d, + 0xad, 0x9d, 0x98, 0x39, 0x12, 0x7a, 0x60, 0x2f, 0xee, 0x82, 0x3d, 0xf5, 0x25, 0x11, 0xb9, 0xf6, 0x56, 0x24, 0x55, + 0xb8, 0x62, 0xf0, 0xde, 0x25, 0x77, 0x54, 0xfb, 0xb2, 0xbc, 0x30, 0x7f, 0x5e, 0x51, 0xcf, 0xd9, 0xaf, 0x98, 0x8c, + 0x9c, 0x8f, 0xec, 0x8d, 0x0e, 0xea, 0x43, 0xf6, 0xf7, 0x8d, 0x29, 0xb7, 0xfe, 0xda, 0xb4, 0xe5, 0xd6, 0x89, 0x3a, + 0x1b, 0x76, 0xa8, 0x5b, 0xa3, 0xbf, 0x9d, 0xab, 0x5a, 0x31, 0x19, 0x21, 0x8f, 0x66, 0x6b, 0xb0, 0xe6, 0x15, 0xb0, + 0xa4, 0xad, 0x57, 0x7a, 0x30, 0x42, 0xef, 0x7a, 0xcc, 0xeb, 0x62, 0x32, 0xda, 0xf9, 0xe6, 0x88, 0xe9, 0xb1, 0xff, + 0x96, 0x7a, 0x3d, 0x38, 0xd5, 0xf6, 0x94, 0xdd, 0x7d, 0xaf, 0xce, 0xed, 0xce, 0x3a, 0x32, 0xfb, 0x5e, 0x9d, 0xa7, + 0xbb, 0xea, 0xcc, 0xf8, 0x5d, 0xe8, 0xf6, 0x8e, 0xf2, 0xd4, 0xd8, 0xda, 0x3e, 0x68, 0x32, 0x82, 0x20, 0xf1, 0xf0, + 0xd7, 0x84, 0x72, 0xe9, 0x39, 0x12, 0x0e, 0xab, 0x20, 0xfa, 0x51, 0x37, 0x66, 0x98, 0x92, 0xce, 0x61, 0xa1, 0x83, + 0xb9, 0xc8, 0x88, 0x36, 0xf3, 0x88, 0xe2, 0x8c, 0x84, 0x21, 0x3d, 0x4c, 0x20, 0x24, 0x4d, 0xbb, 0x4f, 0xe3, 0x90, + 0x36, 0x12, 0x74, 0x14, 0xb6, 0x1b, 0xf4, 0x30, 0x41, 0xa8, 0xd1, 0x06, 0x9d, 0xa9, 0x20, 0xed, 0x66, 0x06, 0x41, + 0x2a, 0x35, 0x29, 0xce, 0x0e, 0x65, 0x54, 0x34, 0xc4, 0x61, 0x1e, 0x15, 0x8d, 0xa8, 0x8b, 0x65, 0x34, 0x29, 0x93, + 0x27, 0x3a, 0x79, 0x62, 0x92, 0x47, 0x65, 0xf2, 0x48, 0x27, 0x8f, 0x4c, 0x32, 0x25, 0xc5, 0xa1, 0x8c, 0x68, 0x23, + 0x6c, 0x37, 0x0b, 0x74, 0x08, 0x23, 0x70, 0xa3, 0x27, 0xd2, 0x8f, 0x0d, 0xbe, 0xd6, 0xc6, 0x35, 0x73, 0x91, 0xd9, + 0x68, 0x9d, 0x15, 0x90, 0x4a, 0x8f, 0x27, 0xa8, 0xf3, 0xcc, 0x03, 0x13, 0x56, 0xe6, 0x8f, 0x8b, 0x45, 0xb7, 0x4e, + 0x32, 0x91, 0x7b, 0x1e, 0x5d, 0x60, 0x84, 0xfe, 0xc5, 0xfa, 0xb1, 0x00, 0x54, 0xd7, 0x34, 0x9b, 0x4f, 0xe9, 0x96, + 0xdb, 0x6c, 0x31, 0x19, 0xd9, 0x9d, 0x55, 0x36, 0xc3, 0x68, 0x61, 0x62, 0x3c, 0xd7, 0x1d, 0x1c, 0x01, 0xd4, 0xce, + 0xa9, 0x32, 0xa2, 0x5a, 0x49, 0x6e, 0x6a, 0x4c, 0x0a, 0x76, 0x2f, 0x13, 0x9a, 0xb1, 0xb0, 0x3a, 0x80, 0xab, 0x61, + 0x32, 0xf2, 0x02, 0x4c, 0xe1, 0x8b, 0xc3, 0xe8, 0xb8, 0xa1, 0xa2, 0xc9, 0x61, 0xd4, 0x7d, 0xd4, 0x50, 0xd1, 0xe8, + 0x30, 0x6a, 0xb7, 0x2b, 0x9c, 0x8d, 0x0a, 0xa2, 0xa2, 0x09, 0x51, 0xa0, 0x31, 0x34, 0x8d, 0x8a, 0x39, 0x05, 0xdb, + 0xae, 0x7f, 0x63, 0x18, 0x0d, 0x3b, 0x8c, 0x9c, 0x4d, 0x4c, 0xb8, 0xcb, 0xad, 0x31, 0xf8, 0xdd, 0x74, 0xba, 0xdd, + 0xa6, 0x8a, 0x0a, 0xac, 0xcc, 0x4a, 0x36, 0x55, 0x34, 0xc1, 0xca, 0x2c, 0x5f, 0x53, 0x45, 0x23, 0xd3, 0x94, 0xd6, + 0x01, 0x82, 0xde, 0xb1, 0x04, 0xd6, 0x73, 0xe6, 0x41, 0xbe, 0xe3, 0xbc, 0x53, 0xd6, 0xa0, 0x35, 0xfc, 0x5e, 0xb9, + 0xa6, 0x2b, 0x28, 0xa9, 0x02, 0x1b, 0x1f, 0xf6, 0xad, 0xa2, 0xed, 0xaa, 0x49, 0xf6, 0xaf, 0xcb, 0x96, 0xcd, 0x16, + 0x42, 0xd5, 0x0b, 0x5e, 0xd6, 0x30, 0xc4, 0x96, 0xb2, 0x07, 0xf7, 0x3f, 0x94, 0x84, 0x10, 0xd4, 0x4e, 0x9f, 0x42, + 0x9c, 0x38, 0x3d, 0x32, 0x24, 0xf1, 0x46, 0x63, 0x8d, 0x42, 0xef, 0xbc, 0x7d, 0xea, 0x53, 0xd5, 0xad, 0x48, 0x77, + 0x84, 0x04, 0x8b, 0xdc, 0xd8, 0x42, 0xa6, 0x81, 0xc7, 0x82, 0x58, 0xed, 0x6e, 0xed, 0x80, 0x38, 0x38, 0xd8, 0x3c, + 0x2f, 0xdc, 0x9b, 0x03, 0x5b, 0xef, 0x0c, 0x54, 0x86, 0x74, 0xee, 0x25, 0x24, 0x63, 0x62, 0xcb, 0x3d, 0x44, 0x71, + 0x31, 0xa7, 0x1e, 0x6a, 0x0a, 0x3f, 0xa8, 0x02, 0xee, 0xd9, 0x9c, 0xe6, 0xa9, 0xce, 0xd0, 0x7d, 0x0d, 0xbd, 0xb1, + 0xbd, 0xf1, 0x27, 0x54, 0x1a, 0x09, 0xfe, 0xcb, 0x8e, 0xbd, 0x4e, 0xec, 0x4b, 0x2d, 0x7e, 0xa3, 0x7f, 0xf9, 0x26, + 0xb9, 0x15, 0x6c, 0xac, 0x33, 0xf6, 0x6a, 0x55, 0x7b, 0x97, 0xc7, 0xbc, 0xfe, 0x82, 0x0e, 0x0e, 0xb8, 0x7c, 0x06, + 0x56, 0xc4, 0x2c, 0x6c, 0xf8, 0x87, 0xef, 0xdf, 0xb5, 0xd3, 0xfa, 0x2f, 0x7d, 0xae, 0xc6, 0xde, 0x41, 0x77, 0x59, + 0xcb, 0xdf, 0xb9, 0x12, 0x7d, 0x15, 0x73, 0xbb, 0xd6, 0x7f, 0x55, 0x36, 0xda, 0x5b, 0x2f, 0x44, 0x1d, 0x1c, 0xf0, + 0x2a, 0x4e, 0x53, 0xf0, 0x43, 0x80, 0xfa, 0x5a, 0x06, 0x79, 0x96, 0x09, 0x0a, 0x37, 0xa2, 0x70, 0xc5, 0x10, 0x37, + 0xf8, 0x91, 0xc2, 0x7f, 0x88, 0xff, 0x4f, 0x8d, 0x1c, 0xaa, 0xb8, 0xc1, 0x3d, 0x01, 0xcc, 0x67, 0x85, 0xaa, 0x08, + 0x89, 0x1a, 0xd2, 0xbe, 0xc9, 0x35, 0x2a, 0x0f, 0x73, 0x3a, 0x9f, 0x67, 0xf7, 0xfa, 0x91, 0x2c, 0x8f, 0xa3, 0xaa, + 0x2e, 0x9a, 0x6c, 0x78, 0x3a, 0x5c, 0x00, 0x4f, 0x0f, 0xb8, 0x87, 0xb4, 0x7b, 0x69, 0x79, 0xb9, 0x2d, 0x11, 0x48, + 0x66, 0x39, 0x11, 0xcd, 0x76, 0x2f, 0xbf, 0x00, 0xb9, 0xac, 0xd9, 0x44, 0xca, 0x46, 0xed, 0xc6, 0x1c, 0x64, 0xb2, + 0xdc, 0xb8, 0x90, 0xee, 0x99, 0x82, 0x20, 0xb9, 0x09, 0x2d, 0xb2, 0xed, 0x2e, 0xc5, 0xc7, 0x21, 0xa0, 0x11, 0x32, + 0x02, 0x9f, 0x2f, 0x2c, 0x72, 0xe0, 0x3a, 0x0b, 0xd7, 0xf1, 0x37, 0x5a, 0x2a, 0x06, 0xf9, 0x70, 0x88, 0x0b, 0xfd, + 0x2e, 0x44, 0x39, 0x1f, 0xb8, 0x69, 0x2a, 0xdf, 0x19, 0xf2, 0x44, 0x14, 0xbe, 0x5a, 0xed, 0xc3, 0x33, 0x3e, 0xb6, + 0x4d, 0xf0, 0x39, 0xb5, 0x3f, 0xab, 0x27, 0x3b, 0x60, 0x1c, 0x8c, 0xb4, 0xf4, 0x45, 0xa1, 0x95, 0x37, 0xd9, 0xb9, + 0xec, 0x35, 0x1a, 0x4c, 0x47, 0x58, 0x22, 0x10, 0x4e, 0x0d, 0x1c, 0x02, 0xe1, 0x8f, 0x09, 0x9a, 0x24, 0x99, 0x09, + 0x3d, 0x07, 0x31, 0xb1, 0x6b, 0x09, 0xab, 0x55, 0x6e, 0x42, 0x9b, 0xe8, 0x1c, 0x13, 0xe4, 0xa4, 0xec, 0xa7, 0x8c, + 0xa1, 0x5a, 0x99, 0x71, 0x70, 0xbb, 0xd5, 0xdf, 0x56, 0xfb, 0x79, 0x8f, 0x9b, 0x6b, 0x3c, 0xae, 0x03, 0x06, 0x68, + 0x40, 0x2d, 0x37, 0x36, 0xb8, 0x31, 0x70, 0x0f, 0x8d, 0x35, 0x2e, 0xdb, 0x84, 0xa0, 0x2c, 0x1d, 0xe4, 0xcd, 0xcd, + 0xad, 0x0b, 0x18, 0x98, 0xeb, 0x39, 0xe5, 0x48, 0x0d, 0x40, 0x8e, 0x1e, 0x12, 0xe8, 0xdc, 0xfc, 0xac, 0xe8, 0x42, + 0x25, 0x13, 0x97, 0x63, 0xfc, 0xc5, 0xbb, 0xcd, 0x1b, 0x04, 0x37, 0x37, 0x7a, 0x93, 0xdf, 0xdc, 0x04, 0xd8, 0xb7, + 0x2a, 0x0f, 0x3c, 0x5e, 0x30, 0x18, 0x96, 0x31, 0xa5, 0xf4, 0xc6, 0x6f, 0xb6, 0xab, 0xc6, 0xde, 0xd3, 0x0a, 0xef, + 0x60, 0x79, 0x74, 0xe3, 0x5b, 0x5e, 0x98, 0x03, 0x0e, 0xf0, 0x66, 0x03, 0x3e, 0xec, 0xbd, 0x09, 0x73, 0x74, 0x70, + 0xf0, 0x26, 0x14, 0xa8, 0x7f, 0xcd, 0xf4, 0x9d, 0x1b, 0xb8, 0x61, 0x0f, 0xb8, 0x1e, 0xbe, 0xf0, 0x10, 0xe0, 0x9a, + 0x6d, 0x4a, 0x36, 0x6f, 0x75, 0xd0, 0x8b, 0x18, 0x82, 0x6a, 0x43, 0x68, 0x5f, 0x0b, 0x12, 0xe8, 0xf5, 0x8d, 0x0f, + 0xed, 0x1e, 0x23, 0x0c, 0x58, 0xf8, 0xd2, 0x49, 0x8e, 0x45, 0x33, 0x56, 0x4c, 0x58, 0xb1, 0x5a, 0xbd, 0xa7, 0xc6, + 0xf1, 0x6d, 0x23, 0x46, 0x63, 0xde, 0x6b, 0x34, 0xa8, 0x1e, 0x3f, 0x88, 0x0f, 0x74, 0x88, 0xf7, 0xdf, 0x84, 0x05, + 0x42, 0x60, 0x61, 0xc4, 0xf3, 0x85, 0x73, 0xf2, 0x4a, 0x6a, 0xeb, 0x52, 0xa0, 0xb2, 0x91, 0x8c, 0xb4, 0xf0, 0x94, + 0x24, 0xe5, 0x1a, 0x9d, 0x4f, 0x7b, 0x8d, 0x46, 0x86, 0x44, 0x98, 0x0c, 0xb2, 0x21, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, + 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0xb2, 0xf3, 0x5d, 0x9a, 0xb1, 0xc6, 0x8f, 0xe9, 0xda, 0x03, 0xc6, 0x63, 0xea, + 0x11, 0x89, 0x5d, 0x40, 0x96, 0x06, 0xc8, 0xb9, 0x03, 0xb2, 0xd4, 0x40, 0xce, 0x51, 0x7f, 0x0e, 0xd1, 0x8a, 0x72, + 0x14, 0x6f, 0x51, 0xf4, 0x7a, 0x5c, 0x4d, 0xeb, 0xb3, 0x81, 0xb9, 0x0e, 0xed, 0x60, 0x97, 0x03, 0x1e, 0x3a, 0xb1, + 0x6e, 0x80, 0x39, 0x59, 0x06, 0x81, 0x0e, 0x31, 0x8b, 0xef, 0xf4, 0x9f, 0xe8, 0x0e, 0xdf, 0x9b, 0x1f, 0xf7, 0x9e, + 0x32, 0xe9, 0x79, 0x4d, 0xdb, 0xc0, 0x6d, 0x40, 0xb6, 0x20, 0x0a, 0x00, 0xad, 0x6d, 0x74, 0x41, 0x59, 0x7f, 0x70, + 0x2d, 0x37, 0x71, 0x20, 0x64, 0x83, 0xe4, 0x58, 0x7a, 0xa4, 0xf3, 0xcf, 0x3f, 0x03, 0xd4, 0x97, 0x10, 0xc6, 0xc7, + 0x9e, 0x6c, 0xcd, 0x36, 0x6a, 0x04, 0x51, 0x10, 0x87, 0x2e, 0x4a, 0x04, 0xec, 0x8c, 0x20, 0xf0, 0x1e, 0x5b, 0x29, + 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x3d, 0xa8, 0x2a, 0xee, 0xc5, 0xc5, 0x72, 0x33, 0xca, 0x90, 0x86, 0xaa, 0xd4, 0x21, + 0x5e, 0x90, 0x79, 0x81, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0x06, 0x72, 0xe8, 0x3d, 0x29, 0x56, 0x5d, 0x87, 0x2b, 0x7f, + 0xe1, 0x42, 0x9a, 0x0f, 0xd4, 0x70, 0xb5, 0x32, 0x7f, 0xc9, 0x07, 0x2d, 0xcd, 0xc0, 0xdb, 0x70, 0xde, 0x6d, 0xbc, + 0xdc, 0x2d, 0x8b, 0x45, 0x4a, 0xfc, 0x0e, 0x56, 0x83, 0x2e, 0x68, 0x9f, 0x9d, 0x6a, 0xdb, 0x41, 0x7d, 0xae, 0x35, + 0x0a, 0x5e, 0xc8, 0xdc, 0xea, 0x48, 0xc3, 0x73, 0xe5, 0xe7, 0xd5, 0x42, 0xdf, 0x26, 0x79, 0x19, 0xc1, 0x14, 0x8e, + 0x94, 0x08, 0xcc, 0xc6, 0x35, 0x9d, 0x84, 0x1f, 0x75, 0x2a, 0x69, 0x59, 0x48, 0x80, 0x02, 0x47, 0xfa, 0x72, 0x5e, + 0x47, 0xa8, 0x67, 0x68, 0x07, 0x91, 0xf3, 0x4c, 0x68, 0xea, 0xb2, 0xa5, 0x0d, 0x25, 0x15, 0xcc, 0xc4, 0x42, 0xb2, + 0xc5, 0x1c, 0xce, 0xf7, 0x32, 0x2d, 0xc9, 0x78, 0xf2, 0xa5, 0x9e, 0x02, 0xe6, 0x9f, 0x77, 0x6a, 0xc6, 0xf2, 0x45, + 0x60, 0xe7, 0xf9, 0xca, 0x88, 0xfb, 0x6f, 0x5e, 0xe0, 0xc7, 0xa4, 0x73, 0xf8, 0x0a, 0x7f, 0xa4, 0xe4, 0x71, 0xe3, + 0x15, 0x9e, 0x70, 0x62, 0x78, 0x83, 0xe8, 0xcd, 0xeb, 0xeb, 0x17, 0xef, 0x5e, 0xbc, 0x7f, 0x7a, 0xf3, 0xe2, 0xd5, + 0xb3, 0x17, 0xaf, 0x5e, 0xbc, 0xfb, 0x88, 0xff, 0xa6, 0xe4, 0xd5, 0x51, 0xfb, 0xac, 0x85, 0x3f, 0x90, 0x57, 0x47, + 0x1d, 0x7c, 0xa7, 0xc8, 0xab, 0xa3, 0x13, 0x9c, 0xe5, 0xe4, 0xd5, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0x94, 0x69, 0x32, + 0x13, 0x93, 0x76, 0x0b, 0xff, 0x6d, 0xbf, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x9b, 0xc6, 0x0f, 0x50, 0x86, 0x8e, + 0xa4, 0x36, 0x44, 0x39, 0xf7, 0xd0, 0x69, 0x9a, 0xfb, 0xe8, 0x64, 0x62, 0x28, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, + 0xb6, 0x1d, 0x7e, 0xd4, 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd5, 0x62, 0x8c, 0x33, + 0x21, 0x8a, 0x70, 0x01, 0x8c, 0x80, 0xd6, 0x5a, 0xf0, 0xa3, 0x32, 0x58, 0x93, 0x3c, 0x27, 0xed, 0x7e, 0x3b, 0x96, + 0xe7, 0xa4, 0xd3, 0xef, 0xc0, 0x9f, 0x6e, 0xbf, 0x1b, 0xb7, 0x5b, 0xe8, 0xd0, 0x1b, 0xc7, 0x1f, 0x35, 0xb4, 0x1e, + 0x0c, 0xb1, 0xed, 0x42, 0xfe, 0x5d, 0x28, 0xa7, 0xd2, 0x93, 0x56, 0x1d, 0xdb, 0xee, 0xc9, 0x73, 0xa6, 0xf5, 0xb0, + 0xfc, 0x07, 0x40, 0x6d, 0xed, 0x4f, 0x52, 0x6e, 0x1c, 0xfb, 0x8b, 0x1f, 0x49, 0x54, 0x8b, 0x08, 0x13, 0xb2, 0x55, + 0x0b, 0x01, 0xd3, 0xa8, 0xb3, 0xc1, 0x1c, 0x28, 0x92, 0xa2, 0x50, 0x2e, 0xaa, 0x7d, 0xde, 0x14, 0x28, 0x9a, 0x8b, + 0x79, 0x58, 0x53, 0x35, 0xfc, 0xea, 0x99, 0x39, 0xee, 0x73, 0xf9, 0x8a, 0xbe, 0x0a, 0x6b, 0x3c, 0x8f, 0xcf, 0xda, + 0xf9, 0xdb, 0xe2, 0x17, 0x6b, 0x45, 0x51, 0x03, 0x57, 0x09, 0x58, 0x37, 0xaa, 0xa6, 0x3a, 0x87, 0xe7, 0xfb, 0x58, + 0x43, 0x5d, 0x10, 0x8f, 0x7a, 0xfe, 0x54, 0x9a, 0x71, 0x95, 0xca, 0x68, 0xa7, 0x88, 0xd6, 0x66, 0x41, 0x4e, 0x11, + 0x7d, 0x9e, 0x6b, 0x20, 0x08, 0xc2, 0x07, 0x72, 0x08, 0x07, 0xbe, 0x19, 0xa0, 0xd0, 0x74, 0x0e, 0xd4, 0x4a, 0x95, + 0x99, 0x90, 0xfe, 0xd4, 0xb1, 0x09, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xf4, 0x27, 0x16, 0xc8, 0x1b, 0xfa, 0x6f, 0xfe, + 0x06, 0x38, 0x0c, 0x35, 0x2a, 0xfa, 0x76, 0x35, 0xb2, 0x9e, 0xdf, 0x3e, 0x6b, 0x1d, 0xbd, 0xf2, 0xf2, 0xd3, 0xdc, + 0xd9, 0x7b, 0xfc, 0xe5, 0x51, 0x72, 0x13, 0x4d, 0xab, 0x8d, 0x5d, 0x20, 0xb4, 0x9e, 0x0f, 0x90, 0x43, 0x85, 0x8e, + 0xf4, 0x4b, 0x86, 0x3d, 0xa4, 0x0e, 0x49, 0xbb, 0x05, 0xd1, 0xcb, 0x76, 0x50, 0xbe, 0x9f, 0x36, 0x60, 0xaa, 0xa2, + 0xbb, 0x26, 0xd0, 0x6a, 0x78, 0xdc, 0xe8, 0xbe, 0xc9, 0xa3, 0x7b, 0x9c, 0x7b, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1e, + 0x4a, 0x64, 0xa3, 0xbe, 0x9a, 0x0d, 0xa0, 0x68, 0xde, 0x31, 0x8f, 0xec, 0x39, 0xe3, 0xa8, 0xf3, 0x66, 0xd4, 0x3d, + 0x7c, 0x75, 0x70, 0x10, 0x8a, 0x06, 0x79, 0x8c, 0xf0, 0x92, 0x82, 0x11, 0x35, 0x38, 0x9d, 0x71, 0xc3, 0xc4, 0xc7, + 0xb9, 0x47, 0x1d, 0x17, 0x79, 0xed, 0x58, 0xab, 0x3a, 0x2b, 0x77, 0x83, 0x1b, 0x53, 0x07, 0x35, 0xbc, 0x34, 0x33, + 0xba, 0x4e, 0x0d, 0xca, 0x35, 0x0f, 0x31, 0xd8, 0x96, 0x8d, 0x8f, 0x14, 0xfd, 0xf0, 0xb8, 0xf9, 0xca, 0x9b, 0x70, + 0xcd, 0x34, 0xe9, 0x71, 0xe3, 0x31, 0xfa, 0xe1, 0xb1, 0xe7, 0xe3, 0xc7, 0x2b, 0xf6, 0xc4, 0x71, 0x23, 0x3f, 0x19, + 0xae, 0xf4, 0x27, 0x90, 0xec, 0x0b, 0xf2, 0x13, 0x60, 0x39, 0x25, 0x3f, 0x85, 0xa2, 0x99, 0x83, 0x41, 0xd7, 0x4f, + 0x61, 0x01, 0x3f, 0x32, 0xf2, 0x53, 0x08, 0xd8, 0x8e, 0xa7, 0xfa, 0x47, 0x51, 0xbd, 0xae, 0x0a, 0x6a, 0x14, 0xe3, + 0x5e, 0x56, 0xac, 0x56, 0xf2, 0xe0, 0x40, 0x98, 0x5f, 0xf4, 0x22, 0x39, 0x38, 0xc8, 0xce, 0xa7, 0x9e, 0xed, 0xad, + 0xda, 0x45, 0x5f, 0x34, 0x42, 0x61, 0xcf, 0x34, 0x8d, 0xfb, 0x33, 0xfe, 0xe4, 0x53, 0x56, 0xdd, 0x40, 0xf3, 0xb8, + 0xf3, 0xf0, 0xf4, 0x0c, 0xc3, 0xbf, 0x0f, 0xbd, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, 0xb3, 0xe6, 0x69, 0x85, 0x6c, + 0x17, 0x1e, 0x3e, 0x63, 0x86, 0x9a, 0xf2, 0xe0, 0x80, 0x9f, 0x7b, 0xb8, 0x8c, 0x19, 0x6a, 0x78, 0x16, 0x7b, 0x0f, + 0x4a, 0x7b, 0x32, 0xcd, 0x35, 0xc1, 0xab, 0xb6, 0x7c, 0x50, 0x0c, 0xcf, 0x95, 0xa5, 0x26, 0x7e, 0xec, 0xeb, 0x9c, + 0xb4, 0xec, 0x26, 0xeb, 0xc9, 0x66, 0x7e, 0xd1, 0xee, 0x21, 0x41, 0xf2, 0x86, 0xbc, 0xb8, 0x68, 0x63, 0x50, 0xc9, + 0xf7, 0x73, 0x22, 0x62, 0x49, 0x9c, 0x7f, 0xde, 0x32, 0x13, 0x71, 0x8e, 0xa7, 0x3c, 0x2e, 0xe5, 0xec, 0xd7, 0xce, + 0x7a, 0x5a, 0x7b, 0x4c, 0xea, 0x9e, 0x19, 0x96, 0xfd, 0xbc, 0xf4, 0xf4, 0x83, 0x4d, 0x9a, 0x0f, 0xe1, 0xd1, 0xc0, + 0x12, 0xf3, 0x98, 0x71, 0x6f, 0x63, 0x10, 0x94, 0x39, 0x6f, 0xb4, 0x21, 0x13, 0x3e, 0xd7, 0x71, 0x0e, 0x03, 0xd5, + 0x85, 0xcf, 0x81, 0x4c, 0x25, 0x95, 0x61, 0xb6, 0x6b, 0x18, 0x0a, 0x48, 0x28, 0x70, 0x41, 0x98, 0x27, 0xc1, 0xc3, + 0xed, 0x87, 0x47, 0x38, 0xea, 0xe4, 0xc2, 0x4c, 0xee, 0x3c, 0x87, 0xee, 0xe4, 0xf0, 0x5c, 0xf5, 0x90, 0x6c, 0x34, + 0x2c, 0xb7, 0x7d, 0x21, 0xf5, 0x20, 0x9a, 0xed, 0xe1, 0x05, 0xeb, 0xa1, 0xbc, 0xd9, 0x2c, 0x0d, 0x20, 0x2f, 0x5a, + 0xab, 0x55, 0x7e, 0xee, 0x1a, 0xe9, 0xbb, 0x73, 0x5c, 0xf3, 0x5d, 0x4e, 0xf0, 0xfc, 0x4d, 0x90, 0x41, 0x00, 0x54, + 0x15, 0xf8, 0x6c, 0x31, 0x0f, 0x70, 0xa0, 0xdf, 0x93, 0x83, 0xbf, 0xfa, 0x1d, 0xb0, 0x00, 0x07, 0xf6, 0x89, 0xb9, + 0x60, 0x58, 0x0d, 0x96, 0x27, 0x65, 0x74, 0x74, 0x1e, 0xdd, 0x00, 0xe3, 0xa0, 0xfe, 0x02, 0x4e, 0xbb, 0xfc, 0x1d, + 0x65, 0x36, 0x4e, 0x88, 0x74, 0xaf, 0x9e, 0xd9, 0x51, 0xad, 0x77, 0x7b, 0x66, 0x72, 0x1c, 0xb8, 0xaa, 0xf0, 0x7a, + 0xc0, 0x77, 0x9e, 0x5d, 0x6c, 0xdb, 0xd7, 0xbe, 0x97, 0x65, 0x0f, 0xc0, 0x79, 0xaf, 0xd7, 0x08, 0xff, 0x26, 0x76, + 0x3e, 0xfd, 0x1b, 0xdc, 0x88, 0xfc, 0x09, 0x55, 0x34, 0x68, 0xbc, 0xd6, 0x86, 0x6f, 0x46, 0xce, 0xea, 0x7d, 0x6b, + 0x1c, 0xec, 0xdf, 0xea, 0x1e, 0x22, 0x37, 0xd4, 0x5e, 0x29, 0x32, 0xb2, 0xaf, 0x8e, 0xd7, 0x21, 0x3c, 0xd3, 0xb7, + 0x1d, 0xf0, 0x70, 0x63, 0xa4, 0xe0, 0x4f, 0x6c, 0xf8, 0x24, 0x0a, 0x21, 0x51, 0x6b, 0x5e, 0xcc, 0x90, 0x62, 0xfa, + 0xd0, 0x1e, 0xaf, 0x6b, 0xe4, 0x73, 0xdd, 0xe3, 0xbc, 0x4e, 0x4c, 0xab, 0x6e, 0xb4, 0xd4, 0xc1, 0x36, 0x59, 0x70, + 0x56, 0xf5, 0xae, 0x25, 0x94, 0xea, 0x41, 0x37, 0xfd, 0x28, 0x67, 0xb3, 0xad, 0x5f, 0x39, 0x36, 0xcf, 0xbe, 0xe5, + 0x60, 0xc8, 0xbb, 0x5f, 0x46, 0xab, 0xba, 0x80, 0x63, 0x37, 0xf4, 0x20, 0x2b, 0xc8, 0xc5, 0xd2, 0x3e, 0xc9, 0xc6, + 0x07, 0x62, 0xb8, 0x2e, 0x1f, 0x68, 0xf3, 0xf0, 0xa0, 0x1a, 0xa9, 0x4c, 0x7c, 0xce, 0xc0, 0xbd, 0x6e, 0x58, 0xd3, + 0x0f, 0xf1, 0x7f, 0xe0, 0x80, 0xaf, 0x90, 0x34, 0x36, 0xea, 0x27, 0x78, 0x38, 0x09, 0x14, 0xde, 0xa6, 0xee, 0x27, + 0xe1, 0x7b, 0xa8, 0xd6, 0x75, 0x2a, 0xc6, 0x09, 0xb4, 0xae, 0x58, 0x29, 0x0b, 0x7b, 0xc7, 0x5d, 0x88, 0xd6, 0xb1, + 0x75, 0x18, 0xb5, 0xaf, 0x2d, 0x5d, 0xe6, 0xe0, 0xff, 0xc2, 0x45, 0xfe, 0xac, 0x80, 0xf0, 0x59, 0xbe, 0x3e, 0xed, + 0x67, 0xe1, 0x3f, 0x27, 0x3c, 0x80, 0x7b, 0xc2, 0x92, 0xe7, 0x2c, 0x9f, 0xc0, 0x86, 0x05, 0xca, 0x81, 0x42, 0xe5, + 0x58, 0xae, 0x56, 0xa1, 0xd4, 0x41, 0x15, 0x6c, 0x4c, 0x5d, 0xfb, 0x78, 0x86, 0xd6, 0xdf, 0x41, 0x5d, 0xec, 0xd4, + 0x23, 0xda, 0x84, 0x15, 0xf9, 0x97, 0x4e, 0x79, 0xe2, 0xf5, 0xb5, 0xab, 0x0f, 0x59, 0x4d, 0xb9, 0x1f, 0x6a, 0x7d, + 0xef, 0x3b, 0x3e, 0x63, 0x62, 0x01, 0xaf, 0x16, 0x61, 0x46, 0x24, 0x53, 0xee, 0x1b, 0x28, 0x08, 0x84, 0x9c, 0xe3, + 0x3e, 0x3e, 0x02, 0x5f, 0xe5, 0x68, 0x9d, 0x48, 0xdc, 0x5b, 0x18, 0x81, 0x8e, 0x55, 0x19, 0xf4, 0x03, 0x70, 0x5a, + 0x02, 0x11, 0x8a, 0x90, 0x80, 0xe5, 0x69, 0xd0, 0x0f, 0xb4, 0x8f, 0x54, 0x00, 0x56, 0x63, 0xa0, 0xe4, 0x0e, 0xf0, + 0x3c, 0xaf, 0x88, 0x98, 0x5f, 0x53, 0x79, 0x95, 0x58, 0xac, 0xcd, 0xb4, 0x8f, 0x3a, 0x15, 0x08, 0x8b, 0x64, 0x53, + 0x50, 0x56, 0x1b, 0xea, 0x02, 0x2c, 0x88, 0xc6, 0x58, 0x1e, 0xdd, 0x00, 0x37, 0xc7, 0x52, 0x5b, 0x74, 0xc9, 0xaf, + 0x41, 0x3d, 0x1d, 0x17, 0xf8, 0x46, 0x33, 0x6c, 0x69, 0x4c, 0xd7, 0x84, 0xe3, 0x84, 0x14, 0x11, 0xbd, 0x83, 0xa0, + 0x12, 0x33, 0x9e, 0xc7, 0x19, 0x9e, 0xd1, 0xbb, 0x78, 0x8a, 0x67, 0x3c, 0x7f, 0x62, 0x96, 0x3d, 0x4e, 0x21, 0xc9, + 0x7d, 0x2c, 0xd6, 0x44, 0xbf, 0x89, 0xf5, 0xbb, 0x64, 0xc5, 0x63, 0xe0, 0x55, 0x64, 0x88, 0x7a, 0xa9, 0xb6, 0x29, + 0x67, 0xaa, 0x32, 0x5e, 0x7f, 0xad, 0x42, 0x8a, 0x13, 0x9c, 0xa1, 0x28, 0x13, 0x98, 0xf5, 0x65, 0xfc, 0x1a, 0x02, + 0x4a, 0x27, 0xd8, 0xbc, 0xa7, 0xc5, 0xef, 0x58, 0xf6, 0x4c, 0x14, 0xef, 0xf5, 0x96, 0xcf, 0x10, 0x14, 0x02, 0x17, + 0x15, 0xd9, 0x84, 0xdb, 0xbd, 0x45, 0x5f, 0x54, 0x4d, 0xd1, 0x3b, 0xd3, 0x94, 0x1d, 0xe2, 0x14, 0x22, 0xf1, 0x46, + 0x53, 0xde, 0x68, 0x63, 0xd6, 0x6f, 0x7d, 0xa7, 0xd1, 0x29, 0x2a, 0x4b, 0x22, 0x0c, 0x4f, 0x04, 0x37, 0xf3, 0x58, + 0x10, 0xd9, 0xcc, 0xad, 0x84, 0xb7, 0xd4, 0xc0, 0x8e, 0x73, 0x9c, 0x88, 0x45, 0xae, 0x62, 0xe1, 0xe1, 0x0d, 0xad, + 0x36, 0xd7, 0xf2, 0xce, 0x40, 0x4c, 0xe1, 0x7b, 0xf3, 0x83, 0xe1, 0x1b, 0xad, 0xe2, 0x7f, 0x0b, 0x86, 0x3d, 0x32, + 0x96, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x19, 0x7e, 0xf2, 0x0e, 0xc0, 0x67, 0x58, 0xc8, 0x7b, 0x48, 0x65, 0x3a, + 0xf5, 0x1e, 0x52, 0x19, 0xa4, 0x6a, 0x57, 0xf2, 0x7d, 0x59, 0x29, 0x8b, 0xfc, 0x06, 0x49, 0x8e, 0x4b, 0x75, 0xb0, + 0x20, 0x32, 0x82, 0x76, 0xb5, 0x28, 0x37, 0xe3, 0x39, 0xc4, 0x14, 0x84, 0xc6, 0xcd, 0x37, 0xbd, 0x83, 0xef, 0x7b, + 0x93, 0xcf, 0x5c, 0xfe, 0xbd, 0xc9, 0xd7, 0x1d, 0x39, 0x8c, 0xaf, 0xdf, 0x76, 0x6a, 0xcb, 0x78, 0x61, 0xb1, 0xf6, + 0x43, 0xf9, 0x82, 0x4b, 0x4b, 0xbf, 0x94, 0x4d, 0xda, 0x78, 0xe2, 0x21, 0x65, 0xb3, 0xe2, 0xe1, 0x3a, 0xb8, 0xdd, + 0x3a, 0x0c, 0x79, 0x93, 0xb4, 0x11, 0x3a, 0xb4, 0xc2, 0x55, 0x1e, 0x6a, 0xc9, 0xe9, 0xf0, 0xf1, 0x11, 0xdc, 0xbd, + 0xcc, 0xf2, 0x0d, 0x5f, 0x29, 0x53, 0xad, 0xd9, 0x6e, 0x1d, 0xf2, 0x9d, 0x55, 0x1a, 0x6d, 0x3c, 0x63, 0x64, 0x09, + 0xce, 0x65, 0xb4, 0x30, 0xaa, 0x06, 0xf0, 0x21, 0x7d, 0x91, 0xff, 0xb6, 0xa0, 0xa9, 0xfe, 0x3e, 0x34, 0x29, 0xaf, + 0x17, 0xca, 0x25, 0x35, 0x39, 0x0c, 0xa2, 0x83, 0x6c, 0x49, 0x2f, 0x27, 0xe4, 0x47, 0x24, 0xea, 0xa2, 0xf3, 0x76, + 0x3f, 0xea, 0x1e, 0xf2, 0x43, 0x1e, 0x03, 0x0f, 0x1b, 0x36, 0x5d, 0x85, 0x66, 0xdb, 0xd5, 0xb9, 0x5a, 0x8c, 0x78, + 0x62, 0x9b, 0xaf, 0x3a, 0x28, 0x53, 0xcd, 0x1c, 0x21, 0x0b, 0x50, 0xcc, 0xf5, 0xe2, 0x65, 0xd7, 0xbb, 0x39, 0xe4, + 0x31, 0xf4, 0x03, 0xb5, 0x3a, 0xa6, 0x56, 0x39, 0xb8, 0xdf, 0x16, 0x80, 0x60, 0xae, 0xa3, 0xda, 0x5c, 0x4c, 0x7a, + 0x33, 0xac, 0x3a, 0x3b, 0xe4, 0xd5, 0x08, 0xfd, 0x32, 0xdb, 0xfd, 0xb9, 0xa9, 0x55, 0x5d, 0x1e, 0x7a, 0x10, 0xf9, + 0x6d, 0xc1, 0x73, 0xbf, 0x53, 0xbf, 0x5b, 0x9b, 0xe3, 0x77, 0x5a, 0x9f, 0xa5, 0x57, 0x64, 0xbb, 0xd7, 0xad, 0x99, + 0xd6, 0x67, 0x7b, 0x0d, 0x3e, 0x82, 0x30, 0x29, 0xbd, 0xd2, 0x89, 0x90, 0x21, 0x3f, 0xfc, 0x80, 0x6c, 0xeb, 0xaf, + 0x17, 0xca, 0xe5, 0x97, 0x88, 0x00, 0xd9, 0x55, 0xd7, 0x65, 0x75, 0xe8, 0xa3, 0x6c, 0xe2, 0xd5, 0x21, 0xf7, 0x56, + 0xee, 0xe9, 0xdd, 0x5c, 0xc4, 0x0e, 0x5f, 0xfb, 0xad, 0x78, 0x0b, 0x39, 0x81, 0x78, 0xd8, 0xee, 0xfc, 0xb2, 0x20, + 0x67, 0x37, 0xb7, 0x50, 0xd2, 0x9f, 0xb8, 0x2b, 0xfd, 0x81, 0x99, 0xeb, 0x06, 0x7e, 0x1e, 0x75, 0x61, 0xea, 0x9b, + 0x3d, 0x1c, 0x76, 0xa0, 0x0f, 0x0d, 0x87, 0xcd, 0x06, 0x5d, 0x66, 0x05, 0x91, 0x2b, 0x5e, 0x18, 0x3c, 0xbb, 0x20, + 0xed, 0x3e, 0x8f, 0xed, 0x66, 0xd2, 0xa2, 0x51, 0xbb, 0xc9, 0xbd, 0x99, 0x01, 0x7e, 0xd9, 0xb2, 0x7e, 0x11, 0xb7, + 0x4e, 0x1e, 0x94, 0x5c, 0xb1, 0x6a, 0x7d, 0x2a, 0x78, 0xd5, 0x1b, 0x8e, 0x37, 0xd3, 0xdd, 0xba, 0xc1, 0xed, 0xae, + 0x83, 0x27, 0xbc, 0xc0, 0x62, 0xd0, 0xda, 0x4d, 0x7c, 0x02, 0x1c, 0x50, 0xd4, 0x7a, 0xd8, 0x05, 0x17, 0xca, 0x12, + 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x0c, 0x1c, 0x4d, 0x49, 0x8f, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, 0xd8, 0xc1, + 0x51, 0xbb, 0xdd, 0xe9, 0xe2, 0xe8, 0xa4, 0x0b, 0x03, 0x6d, 0x44, 0xdd, 0xc3, 0x59, 0x6e, 0x00, 0xe8, 0xe5, 0xac, + 0x6d, 0xbb, 0x8f, 0x21, 0x5a, 0x93, 0x2f, 0x5e, 0xf3, 0xc3, 0x30, 0x6c, 0x47, 0x0f, 0x5b, 0xed, 0xee, 0x59, 0x03, + 0x00, 0xd4, 0xb4, 0x1f, 0xb6, 0xc6, 0xeb, 0x85, 0xaa, 0x57, 0x29, 0x11, 0xbe, 0x5e, 0xad, 0xe1, 0xaa, 0x35, 0xda, + 0xeb, 0x6a, 0x0a, 0xae, 0xaa, 0x15, 0xce, 0x4d, 0x11, 0xa7, 0xb4, 0xf1, 0xb7, 0x45, 0x68, 0x06, 0x12, 0x82, 0x74, + 0x1e, 0x75, 0x3b, 0x5d, 0x64, 0xc6, 0xa2, 0x2c, 0x7e, 0x94, 0xfb, 0x64, 0xab, 0x48, 0x43, 0x01, 0x92, 0x94, 0xb3, + 0x13, 0x0b, 0x90, 0xa8, 0x39, 0xb9, 0x68, 0x37, 0x67, 0x2c, 0x72, 0x13, 0xd0, 0xa9, 0xb0, 0x9c, 0xe5, 0x2a, 0xd8, + 0x24, 0x0f, 0x10, 0xe7, 0x60, 0x5c, 0xf4, 0xb0, 0xdb, 0x7f, 0x18, 0x75, 0x4f, 0x3b, 0x86, 0xe8, 0xf1, 0xf3, 0x4e, + 0x2d, 0x4d, 0x4f, 0x3d, 0xea, 0xea, 0x34, 0xe8, 0x3a, 0x7a, 0xd8, 0x85, 0x32, 0x36, 0xc5, 0x2f, 0x05, 0x51, 0x26, + 0xaa, 0x62, 0x10, 0x5a, 0x22, 0xae, 0xe5, 0x9e, 0xd6, 0xb2, 0xcf, 0x4e, 0x8e, 0x1f, 0x76, 0x7d, 0xa8, 0x95, 0xb3, + 0xd0, 0x0b, 0x6d, 0x27, 0xe2, 0x66, 0x07, 0x4b, 0x8b, 0x0e, 0xa3, 0x6e, 0xbc, 0x35, 0x41, 0xb3, 0x69, 0x0e, 0x35, + 0x0e, 0x78, 0x0a, 0xc7, 0x4b, 0x69, 0xf5, 0x25, 0xde, 0xfd, 0x58, 0x65, 0x68, 0xe2, 0x2b, 0x9c, 0xdd, 0x3d, 0xa5, + 0xf7, 0x90, 0xa4, 0x7f, 0x55, 0x79, 0x45, 0xf3, 0xaf, 0x54, 0xbe, 0xa1, 0x10, 0x3a, 0x23, 0x1f, 0x06, 0x36, 0xb0, + 0x77, 0x3d, 0xf7, 0x27, 0x70, 0x11, 0x66, 0x39, 0x5c, 0x68, 0x3a, 0x25, 0x68, 0xc5, 0x0b, 0x8c, 0x7c, 0x56, 0x57, + 0x0f, 0xab, 0xcf, 0x63, 0x6b, 0x52, 0xe0, 0xeb, 0xb6, 0x9e, 0xf3, 0xef, 0x95, 0x8b, 0xca, 0xab, 0xec, 0xa8, 0x8b, + 0x22, 0x7b, 0x59, 0x1e, 0xb5, 0x51, 0xe4, 0x99, 0x90, 0xd8, 0x23, 0x39, 0x49, 0xc8, 0x20, 0xb8, 0x0b, 0x70, 0x70, + 0x1f, 0xe0, 0xc0, 0xf8, 0x30, 0x7f, 0x00, 0x37, 0xf2, 0x00, 0x07, 0xc6, 0x95, 0x39, 0xc0, 0x81, 0x62, 0x39, 0x44, + 0xd4, 0x0a, 0x86, 0x38, 0x83, 0xd2, 0xda, 0xb3, 0xba, 0x2c, 0x7d, 0xe5, 0xbe, 0x4a, 0xd7, 0x6b, 0x93, 0xe2, 0x49, + 0x99, 0x53, 0xbd, 0x43, 0xcd, 0x8b, 0xd0, 0x01, 0x75, 0xcc, 0x7a, 0x80, 0x41, 0x00, 0xa1, 0xf7, 0xee, 0x45, 0xb9, + 0x2a, 0x18, 0x07, 0x3b, 0x86, 0x95, 0x06, 0x9f, 0xf3, 0xc0, 0x3f, 0xc3, 0x02, 0x3c, 0xce, 0x5d, 0x61, 0x10, 0x2b, + 0xdc, 0xef, 0x4c, 0x88, 0xb9, 0xfb, 0xad, 0x44, 0xf9, 0x0b, 0xde, 0x21, 0xb1, 0x16, 0x2d, 0x60, 0xb9, 0x65, 0x62, + 0xff, 0x8c, 0x58, 0x7d, 0x04, 0x37, 0x63, 0x1b, 0x9f, 0x0d, 0x24, 0xc2, 0x1b, 0x2d, 0x50, 0x39, 0xf9, 0xf0, 0xc6, + 0xc4, 0x0a, 0xd2, 0x9f, 0x10, 0x2c, 0x0c, 0xe2, 0x01, 0x0b, 0xb8, 0xd0, 0x98, 0x14, 0x4c, 0xca, 0xc0, 0x04, 0xd1, + 0x0b, 0x44, 0xee, 0x5e, 0x45, 0x74, 0x29, 0xe3, 0x3c, 0xd0, 0x1d, 0xd6, 0x67, 0x6b, 0xc4, 0xe1, 0x4c, 0x14, 0x32, + 0x36, 0x4f, 0xa4, 0x38, 0x30, 0xce, 0xcb, 0xf7, 0x07, 0xe3, 0x2c, 0x59, 0x63, 0x73, 0x87, 0x5d, 0x16, 0xb2, 0x57, + 0xda, 0x7e, 0xa9, 0x24, 0x59, 0x7f, 0x6b, 0x42, 0xb2, 0x36, 0x23, 0x6f, 0xa2, 0xd5, 0x80, 0xaa, 0x48, 0x1a, 0x50, + 0xd8, 0x44, 0x63, 0x89, 0x97, 0x65, 0xc9, 0x78, 0x59, 0x2e, 0xc3, 0x49, 0xab, 0xb5, 0x5e, 0xe3, 0x82, 0xe9, 0xa8, + 0x30, 0x3b, 0x4b, 0x40, 0xbe, 0x9c, 0x8a, 0x5b, 0x2f, 0x57, 0xc6, 0xe5, 0x2c, 0xf5, 0x12, 0x05, 0x9e, 0x11, 0x6c, + 0xb0, 0xc6, 0x5f, 0xb9, 0xe4, 0x00, 0x4f, 0x3b, 0xbb, 0x91, 0x10, 0x19, 0xa3, 0x10, 0x3c, 0xcc, 0x6b, 0x72, 0x8d, + 0xa7, 0x3c, 0x65, 0xbb, 0xdb, 0x04, 0x33, 0xe6, 0x7f, 0xaf, 0x45, 0x87, 0x40, 0x86, 0xdd, 0xd3, 0xa8, 0x03, 0x8b, + 0xb8, 0x82, 0x0e, 0x7c, 0x19, 0x3c, 0xf5, 0x71, 0x33, 0xa3, 0xf7, 0x62, 0xa1, 0x00, 0x2e, 0x0b, 0x25, 0xde, 0xd8, + 0xb8, 0x07, 0xfb, 0x2d, 0xec, 0x42, 0x20, 0x2c, 0x21, 0x64, 0x40, 0x0b, 0x9b, 0x10, 0x15, 0x2d, 0x3c, 0x12, 0x4a, + 0x89, 0x59, 0xdc, 0xc2, 0x3a, 0x5e, 0x44, 0x6b, 0x5d, 0x06, 0xf5, 0xba, 0xc9, 0xdd, 0x5b, 0x92, 0xd5, 0x26, 0x58, + 0x58, 0xe9, 0x50, 0x11, 0xe5, 0xdd, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbf, 0x7e, 0x65, 0x43, 0x36, 0xf3, 0x31, + 0xb8, 0x6c, 0x5a, 0xd5, 0xd8, 0x8d, 0x7e, 0x84, 0x29, 0xac, 0x14, 0xa5, 0x46, 0x38, 0x85, 0x96, 0x5f, 0xe4, 0x2a, + 0x8b, 0xcc, 0xe5, 0xc5, 0x33, 0x51, 0xcc, 0xa8, 0xb9, 0x31, 0xc2, 0x37, 0xb9, 0x7d, 0x75, 0x5d, 0x3f, 0xec, 0x52, + 0x4d, 0xf2, 0xdd, 0xe6, 0x55, 0xc4, 0x22, 0xd1, 0xf2, 0x2b, 0x68, 0x03, 0x74, 0xe5, 0xf2, 0xd1, 0xdc, 0x82, 0xd8, + 0xc0, 0xf7, 0x1e, 0x79, 0x79, 0x6b, 0xa8, 0x4b, 0x10, 0x34, 0xb8, 0xc6, 0x4f, 0x56, 0xf0, 0xc4, 0xbb, 0x2e, 0xd4, + 0xec, 0x91, 0x15, 0x2f, 0x82, 0x56, 0x50, 0x7f, 0x74, 0x56, 0xab, 0x12, 0x5c, 0xd0, 0xd4, 0x28, 0x13, 0x20, 0x7a, + 0x94, 0xef, 0xdb, 0x71, 0x10, 0x4d, 0xdc, 0xdd, 0xf3, 0x45, 0xdb, 0xd1, 0xd9, 0xac, 0x52, 0x27, 0x96, 0x57, 0x26, + 0xe0, 0xe1, 0x68, 0x5e, 0x90, 0x41, 0xd8, 0x4b, 0x64, 0xa5, 0xf6, 0xd0, 0xe5, 0xa2, 0x5e, 0x98, 0x9d, 0xb7, 0x59, + 0xf3, 0x64, 0xb5, 0xca, 0x2e, 0xda, 0xac, 0xdd, 0x35, 0xef, 0xcd, 0x05, 0x32, 0x01, 0x9a, 0xcb, 0xc7, 0x3c, 0x09, + 0x40, 0x3b, 0x3b, 0x4e, 0x74, 0x38, 0x05, 0x17, 0x21, 0x99, 0x2c, 0x54, 0xd5, 0x97, 0x00, 0xe3, 0x52, 0x62, 0xf4, + 0xf8, 0x05, 0xea, 0xb7, 0xe3, 0x6d, 0x57, 0xe9, 0x66, 0xfb, 0xd0, 0xbb, 0x70, 0x29, 0x10, 0xee, 0x40, 0xc8, 0x03, + 0xd0, 0xef, 0x2e, 0x73, 0x30, 0x0d, 0x02, 0x54, 0xce, 0x41, 0xa4, 0xe5, 0xb3, 0xc5, 0xec, 0x59, 0x41, 0xf5, 0x32, + 0x3c, 0xe1, 0x13, 0xae, 0x64, 0x4c, 0x41, 0xba, 0xdd, 0x95, 0xbe, 0xde, 0x2d, 0x41, 0x25, 0xb5, 0xc0, 0xb3, 0x91, + 0xe2, 0xc9, 0x17, 0x69, 0x17, 0x0e, 0x61, 0xbd, 0xb2, 0x12, 0x27, 0x68, 0x8d, 0x33, 0x31, 0xa1, 0x05, 0x57, 0xd3, + 0xd9, 0xbf, 0xb5, 0x3a, 0x6c, 0xa0, 0x86, 0xfa, 0xc2, 0x0a, 0x40, 0x42, 0xf3, 0x74, 0xb5, 0xe2, 0x47, 0xdf, 0xbf, + 0x4f, 0x72, 0x3e, 0xe1, 0x6d, 0xdc, 0xc1, 0xc7, 0xb8, 0x8b, 0xdb, 0x2d, 0xdc, 0xee, 0xc2, 0xd5, 0x7d, 0x92, 0x2d, + 0x52, 0x06, 0xf6, 0xb1, 0xab, 0x95, 0xba, 0x88, 0xce, 0x0e, 0xcb, 0x70, 0xfb, 0xaa, 0x88, 0x2c, 0xba, 0x78, 0x51, + 0xdf, 0x6d, 0xb8, 0xbc, 0x20, 0xf0, 0x63, 0xb5, 0x8d, 0x7d, 0xd5, 0x49, 0xa9, 0x5f, 0xb8, 0x38, 0xee, 0x83, 0x3d, + 0xb7, 0x59, 0xd9, 0x26, 0x98, 0x7d, 0x9b, 0x9f, 0x71, 0xf5, 0xb3, 0xa9, 0x4a, 0xc4, 0x70, 0xd0, 0xab, 0xd0, 0x03, + 0x5d, 0x90, 0xf6, 0xc1, 0x01, 0x58, 0x1d, 0x79, 0xb3, 0xe1, 0x26, 0xfa, 0x01, 0x6f, 0xd6, 0xd2, 0x20, 0x58, 0x01, + 0x18, 0x77, 0xbe, 0xe1, 0x64, 0x69, 0x60, 0xab, 0x80, 0x0a, 0xab, 0xc2, 0x0f, 0x28, 0xe7, 0x93, 0x0a, 0x2d, 0x44, + 0xc3, 0x11, 0x66, 0x23, 0x9d, 0xec, 0xb7, 0xb0, 0x18, 0x8f, 0x25, 0x53, 0x70, 0x74, 0x14, 0xec, 0x2b, 0x2b, 0xa4, + 0x3e, 0x45, 0x46, 0x6c, 0xc2, 0xf3, 0x4b, 0xf5, 0x89, 0x15, 0x42, 0x7f, 0x6a, 0x0d, 0x46, 0x1c, 0xe8, 0x55, 0x0c, + 0x70, 0x92, 0xf1, 0x39, 0x54, 0x9d, 0x14, 0xe0, 0xf4, 0x03, 0x7f, 0x79, 0x1a, 0xfb, 0x6d, 0x02, 0xf9, 0xfa, 0x60, + 0xc2, 0xba, 0xe0, 0xb4, 0xa0, 0xb7, 0xaf, 0xf3, 0x2b, 0xd8, 0x51, 0x97, 0x05, 0xa3, 0x90, 0x0d, 0x49, 0xef, 0xa0, + 0x29, 0xf8, 0x80, 0x36, 0x5f, 0x6a, 0xc0, 0xc5, 0x67, 0xfa, 0xc3, 0x54, 0x74, 0x41, 0x0b, 0xa3, 0xb2, 0x2d, 0x9d, + 0xa9, 0x4f, 0xe9, 0x2a, 0xd3, 0x84, 0x85, 0x2a, 0xa7, 0xb0, 0xc6, 0x36, 0xea, 0x89, 0x3f, 0x98, 0x94, 0xca, 0x69, + 0x3c, 0x18, 0xea, 0xbf, 0xaf, 0x4d, 0xc9, 0x16, 0xb6, 0x41, 0x67, 0xd6, 0x58, 0xbf, 0x18, 0xea, 0x95, 0x6f, 0x63, + 0xb8, 0x87, 0x85, 0x67, 0x2b, 0x6b, 0xe4, 0xf3, 0xc4, 0x91, 0xcd, 0x93, 0xf5, 0x5a, 0x0f, 0x44, 0xc6, 0xa0, 0x07, + 0x7a, 0xeb, 0xb6, 0x4d, 0x0b, 0xb6, 0x47, 0xf9, 0xd5, 0x6d, 0xe1, 0x19, 0x87, 0x57, 0x38, 0x5d, 0x7b, 0xd7, 0xaa, + 0x10, 0x5f, 0x2c, 0x48, 0x5a, 0x5e, 0x8a, 0x99, 0x8e, 0xd7, 0xd9, 0x31, 0xf6, 0x46, 0x0e, 0xf4, 0xfc, 0xfa, 0x8b, + 0x81, 0xb5, 0xfb, 0xfd, 0xa6, 0x2c, 0x98, 0xd1, 0x11, 0xcb, 0xca, 0x09, 0x25, 0xee, 0xfc, 0x7c, 0xc3, 0xa3, 0x0a, + 0x15, 0xec, 0xf3, 0x55, 0xb0, 0xa7, 0x4d, 0x84, 0xcb, 0x19, 0xfd, 0xcb, 0xfc, 0x30, 0x81, 0x75, 0x4a, 0x2d, 0x5b, + 0x52, 0x08, 0x29, 0x2f, 0x4d, 0x9a, 0x39, 0x7a, 0xe0, 0x88, 0x7c, 0x09, 0x5d, 0x00, 0xaf, 0x9f, 0x16, 0x62, 0xae, + 0x11, 0xc1, 0xfe, 0xb6, 0xe3, 0xd6, 0xbe, 0x02, 0xe0, 0xed, 0xb0, 0x57, 0xfd, 0xd3, 0x02, 0xf6, 0x37, 0x28, 0x4b, + 0xba, 0xf1, 0x76, 0xcc, 0xf1, 0x5f, 0x08, 0x08, 0x97, 0x6e, 0xf0, 0x30, 0xb2, 0xe8, 0x54, 0xb2, 0x66, 0xe5, 0xcf, + 0xad, 0x92, 0x80, 0x61, 0xf5, 0x82, 0x3e, 0x1b, 0xb7, 0x55, 0xdc, 0x64, 0xfe, 0x07, 0x15, 0x34, 0x16, 0x7c, 0x6b, + 0x24, 0x15, 0xcb, 0xe2, 0xb6, 0x4f, 0x9d, 0xff, 0xaa, 0x73, 0x5c, 0xfb, 0xaa, 0xf6, 0x44, 0xe6, 0x48, 0x87, 0x27, + 0x0e, 0xd0, 0xc1, 0xc1, 0x46, 0x06, 0x1d, 0x03, 0xe0, 0x91, 0x65, 0xbf, 0xdc, 0xf2, 0x39, 0x76, 0x4c, 0x6b, 0x1e, + 0x8b, 0xc0, 0x67, 0xee, 0x1c, 0x37, 0x67, 0x26, 0xf2, 0x84, 0xca, 0xa9, 0x2b, 0x0c, 0x70, 0x7c, 0xbc, 0x95, 0x0a, + 0xf8, 0x1e, 0xac, 0x77, 0x4c, 0x60, 0x83, 0xdf, 0x32, 0x93, 0xda, 0x55, 0xd0, 0x2d, 0xd0, 0x72, 0x17, 0x53, 0xb9, + 0xb1, 0xc0, 0xc1, 0xe6, 0x44, 0x76, 0x0e, 0x7d, 0xa3, 0x4e, 0xc9, 0x7a, 0x3c, 0xd9, 0x6d, 0xf4, 0x95, 0xcb, 0x5d, + 0xc9, 0x15, 0x6d, 0x1b, 0xb1, 0xea, 0x99, 0x5c, 0x55, 0x99, 0x3a, 0x55, 0xd7, 0xbc, 0x95, 0xa5, 0x4d, 0x69, 0x97, + 0x64, 0xee, 0xb6, 0x98, 0x7f, 0x15, 0xde, 0x68, 0x94, 0x17, 0xa1, 0x60, 0x8f, 0x25, 0x87, 0x3d, 0x4e, 0xe0, 0x7a, + 0x61, 0xb5, 0x0a, 0xe1, 0xcf, 0xae, 0x31, 0xec, 0x32, 0x5d, 0xfa, 0xc0, 0x37, 0xf8, 0x15, 0x2f, 0x52, 0xaf, 0xb5, + 0x83, 0x04, 0xeb, 0x2e, 0x3b, 0x68, 0x38, 0x4e, 0xdc, 0x17, 0xbc, 0x13, 0xad, 0x9c, 0xcb, 0xc1, 0x24, 0xf9, 0xc6, + 0xdb, 0x72, 0x25, 0x6b, 0x59, 0x0b, 0xf3, 0xbe, 0x21, 0xc1, 0x10, 0xb3, 0x29, 0xad, 0xe3, 0x56, 0xd4, 0x46, 0x81, + 0x2d, 0x56, 0xa1, 0xff, 0xb7, 0x8a, 0x24, 0x26, 0xf3, 0xbf, 0x4e, 0x4f, 0x4f, 0x6d, 0x8a, 0xb5, 0xf9, 0x93, 0xda, + 0x03, 0x4e, 0x27, 0xb0, 0xaf, 0x3c, 0x61, 0x5a, 0x87, 0xfc, 0x16, 0x86, 0x42, 0x24, 0xb9, 0x70, 0xec, 0x12, 0x44, + 0xe5, 0x02, 0xca, 0x03, 0xec, 0xdf, 0x93, 0x8d, 0x72, 0xee, 0x9d, 0x24, 0x17, 0x47, 0xb8, 0x6c, 0x90, 0x7d, 0xd5, + 0x9f, 0x03, 0x63, 0x26, 0x03, 0x4f, 0x03, 0x04, 0xd8, 0xfc, 0xd6, 0x2c, 0xad, 0xb5, 0x94, 0xc1, 0x81, 0x12, 0x8b, + 0x64, 0x6a, 0x34, 0xff, 0xf6, 0x43, 0x97, 0xb5, 0x6f, 0xec, 0x40, 0x50, 0x2e, 0xb2, 0xb4, 0xe1, 0x30, 0x83, 0x1f, + 0xcb, 0xc8, 0x97, 0x7b, 0xaf, 0xd8, 0x82, 0xfd, 0x88, 0xf7, 0xaa, 0x14, 0xf8, 0xb8, 0x2c, 0x38, 0xcd, 0x7e, 0xc4, + 0x7b, 0x55, 0x04, 0x4c, 0x70, 0x85, 0xd4, 0x41, 0x24, 0xb1, 0x7e, 0x4f, 0x3a, 0x0e, 0x72, 0xa0, 0xa0, 0x59, 0xa0, + 0x0f, 0xb2, 0xe7, 0x36, 0x68, 0x62, 0xd4, 0xc1, 0x36, 0xee, 0x97, 0x09, 0x85, 0x6a, 0x22, 0x88, 0x43, 0x20, 0xb9, + 0x72, 0x36, 0xfa, 0xeb, 0xf1, 0xc6, 0x82, 0x68, 0x65, 0x32, 0xb9, 0x78, 0xce, 0xc3, 0x7c, 0x73, 0xb1, 0x90, 0x5f, + 0xcd, 0x5b, 0xa0, 0x5a, 0x95, 0x2a, 0xdd, 0x2f, 0xbe, 0x5d, 0x30, 0xf1, 0x8a, 0xe8, 0xad, 0x77, 0x79, 0x07, 0xcf, + 0x9d, 0xdf, 0x05, 0x2e, 0x09, 0x9e, 0x04, 0xd7, 0x98, 0xea, 0x5e, 0x80, 0x07, 0x42, 0xcf, 0xa4, 0x0a, 0xb0, 0xce, + 0x93, 0x10, 0x49, 0x6c, 0xbf, 0x85, 0x2d, 0x6b, 0xf4, 0x22, 0x77, 0x42, 0x0a, 0x9c, 0xab, 0xba, 0x89, 0x19, 0xe5, + 0x3a, 0xba, 0xd8, 0xa5, 0x9c, 0xb3, 0x44, 0x19, 0x04, 0xd8, 0xb7, 0x68, 0x28, 0xf2, 0xe7, 0x1a, 0x14, 0xfa, 0x2d, + 0x6b, 0x9b, 0x72, 0x05, 0x8b, 0xe7, 0xa5, 0x00, 0x51, 0xe3, 0xf9, 0xa4, 0xac, 0x33, 0xcf, 0x16, 0x13, 0x9e, 0x57, + 0xc8, 0x50, 0x30, 0x39, 0x17, 0x39, 0x3c, 0x25, 0x51, 0x16, 0xd1, 0x74, 0xa8, 0x86, 0xef, 0x86, 0x84, 0x95, 0x75, + 0xf4, 0x31, 0xc5, 0xf3, 0xaa, 0x06, 0x30, 0x17, 0x97, 0xfe, 0x9b, 0xf3, 0xf2, 0x75, 0xfe, 0x4e, 0xcc, 0xab, 0x7c, + 0x47, 0xe3, 0x5c, 0xc4, 0x76, 0x6b, 0x37, 0x8c, 0xd6, 0xfa, 0xb5, 0x27, 0x6f, 0xfb, 0x7e, 0xe0, 0xd5, 0x0b, 0x68, + 0x6b, 0xfd, 0x5e, 0x54, 0x99, 0x35, 0x62, 0xe5, 0xe3, 0x08, 0x55, 0x7b, 0xf5, 0xaa, 0xb9, 0xad, 0x08, 0x50, 0x29, + 0x78, 0xba, 0x95, 0xff, 0x44, 0x99, 0x7c, 0x73, 0x0e, 0x95, 0xe1, 0x81, 0x1c, 0x19, 0xaa, 0x7a, 0xc0, 0x45, 0xf9, + 0xa1, 0x9f, 0xbe, 0x0a, 0x74, 0xe0, 0xdc, 0x5d, 0x17, 0xc8, 0x9c, 0xc9, 0x50, 0xe0, 0xe5, 0x80, 0x0e, 0x63, 0x23, + 0x0f, 0xc5, 0x02, 0x6c, 0x7b, 0x6e, 0x0b, 0xae, 0x5c, 0x84, 0x5e, 0x3c, 0x60, 0xc3, 0x78, 0x59, 0x8f, 0xe2, 0x6b, + 0xe2, 0x08, 0x3b, 0x73, 0x4e, 0x1d, 0xf6, 0x96, 0x0e, 0x71, 0x46, 0xc0, 0xf6, 0xd8, 0xb1, 0xa7, 0x6f, 0xc2, 0x04, + 0xf5, 0xeb, 0x1c, 0xfe, 0x72, 0x8d, 0x33, 0x9c, 0xa0, 0xf8, 0x32, 0x84, 0x0b, 0xac, 0x35, 0x06, 0xf0, 0x25, 0x86, + 0x54, 0x81, 0x47, 0x6a, 0xa2, 0x25, 0x56, 0x7b, 0x11, 0x88, 0x96, 0xca, 0xbf, 0x1d, 0x67, 0x2e, 0x0e, 0xb6, 0xe6, + 0x5e, 0x9f, 0x69, 0xe1, 0x70, 0x92, 0x84, 0xb5, 0x73, 0x86, 0x93, 0x8b, 0x7d, 0x5e, 0x3b, 0x31, 0xc1, 0xda, 0xdb, + 0x3f, 0x55, 0x40, 0x8f, 0x06, 0xa7, 0x8a, 0xa1, 0x21, 0x10, 0x33, 0x01, 0xbc, 0x99, 0xfd, 0xa3, 0xcd, 0xc3, 0xf9, + 0x60, 0x8d, 0xbd, 0xaf, 0xb8, 0xd6, 0xd5, 0xa6, 0x12, 0x65, 0xbd, 0xc6, 0x83, 0x69, 0x82, 0xd3, 0x04, 0xcf, 0x93, + 0xa1, 0x77, 0xdc, 0xcc, 0x12, 0xdf, 0xa4, 0x6b, 0xb5, 0x7a, 0x6a, 0xcd, 0x08, 0x91, 0xf9, 0x69, 0xe8, 0x0f, 0xea, + 0x03, 0xc2, 0xc7, 0x90, 0x05, 0xb4, 0xa4, 0x6f, 0xff, 0x36, 0xcc, 0x33, 0xd9, 0xa8, 0x11, 0xf2, 0xc8, 0x90, 0x91, + 0xbe, 0xfb, 0x51, 0x66, 0x99, 0xd6, 0x1a, 0xc1, 0xfc, 0x6e, 0x2f, 0x68, 0xb8, 0xf6, 0x3c, 0x2d, 0x5b, 0x69, 0xb6, + 0x03, 0x88, 0x62, 0x8c, 0x93, 0x94, 0xb7, 0x46, 0x62, 0xb5, 0x0a, 0x4d, 0x0a, 0xe1, 0xd1, 0x8c, 0x51, 0xb9, 0x28, + 0xf4, 0xcb, 0x71, 0x61, 0x8e, 0x22, 0xcd, 0xef, 0x62, 0x6b, 0x23, 0x9a, 0x83, 0xdb, 0x23, 0x18, 0x6e, 0x84, 0x92, + 0x88, 0x9a, 0xc8, 0x3d, 0x4a, 0x2a, 0xcb, 0x20, 0x49, 0xa4, 0x16, 0xf9, 0xcd, 0x75, 0xa9, 0x39, 0x0c, 0xec, 0x1f, + 0xed, 0x0b, 0x08, 0x37, 0x6f, 0x13, 0x5a, 0x8c, 0xe8, 0x04, 0xd8, 0x58, 0x88, 0x43, 0xb8, 0x95, 0xb0, 0x5a, 0x0d, + 0x86, 0x3d, 0x43, 0x9e, 0xed, 0xcb, 0x79, 0x65, 0x43, 0xbb, 0x1b, 0x80, 0xab, 0x6e, 0x43, 0xcd, 0x95, 0xd6, 0xfd, + 0x50, 0xfd, 0xb8, 0x17, 0xb7, 0x49, 0xf6, 0x7d, 0x8e, 0xea, 0x09, 0xee, 0x9a, 0x05, 0xb8, 0x0e, 0x5d, 0x85, 0x53, + 0xbc, 0x30, 0x36, 0x9c, 0xfa, 0x25, 0x27, 0xaa, 0x1f, 0x70, 0x82, 0x77, 0xa3, 0x09, 0x1b, 0x24, 0x43, 0x9c, 0xba, + 0x38, 0xdf, 0xfb, 0x6f, 0xc3, 0x14, 0xa1, 0x82, 0x68, 0x98, 0x1a, 0x97, 0xed, 0xb4, 0xb2, 0xdb, 0xd7, 0x99, 0x9a, + 0x61, 0xd0, 0x46, 0xcc, 0xa9, 0x6f, 0xc4, 0x9c, 0x35, 0x1a, 0x68, 0x41, 0x52, 0x30, 0x62, 0x5e, 0x78, 0xad, 0x2d, + 0xcc, 0x2b, 0x9f, 0x5e, 0x7b, 0x0b, 0x84, 0x7a, 0x1c, 0x68, 0x9a, 0x82, 0xf7, 0x3c, 0xaa, 0xf7, 0xd4, 0xdd, 0xeb, + 0x52, 0x47, 0x1d, 0x50, 0x24, 0x8c, 0x2f, 0xdc, 0x24, 0x8c, 0x6b, 0xb8, 0x19, 0xf7, 0x58, 0x8f, 0xdb, 0xda, 0x36, + 0xe4, 0x03, 0x31, 0x48, 0x86, 0xc3, 0x9e, 0x70, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x5e, 0x00, 0xa9, 0x16, 0xef, 0xab, + 0xda, 0xbc, 0xf2, 0xe6, 0xee, 0x61, 0xd1, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, 0x1f, 0xaa, 0xe2, 0x83, 0x1d, + 0x75, 0x20, 0x0a, 0x5a, 0xdc, 0xaa, 0x09, 0xa4, 0xc6, 0xcc, 0x2e, 0x54, 0xcd, 0x1c, 0x1d, 0x4a, 0x08, 0x43, 0x96, + 0x57, 0xdd, 0xdd, 0xe7, 0x9e, 0x6a, 0x88, 0xc3, 0xa9, 0x7f, 0x65, 0x8c, 0x58, 0xc3, 0xa0, 0x93, 0x06, 0xda, 0x48, + 0xd2, 0x2c, 0x1f, 0x3c, 0xfa, 0x03, 0x56, 0x02, 0x2e, 0xf8, 0xb2, 0x4e, 0xd2, 0x86, 0x04, 0x6f, 0x59, 0xa2, 0x34, + 0x1f, 0xc2, 0x2d, 0x82, 0xf2, 0xc8, 0xc4, 0xda, 0xb4, 0x95, 0x0c, 0xe4, 0xaa, 0x2e, 0x6f, 0x3c, 0xf4, 0xbc, 0x4f, + 0xaa, 0xdd, 0x00, 0x1c, 0x99, 0x37, 0xb0, 0x64, 0x6b, 0x9f, 0x80, 0x47, 0x3e, 0xae, 0x10, 0xc4, 0x2d, 0x85, 0x8a, + 0x74, 0xa0, 0xea, 0x6b, 0xd8, 0xa0, 0x78, 0x0e, 0x0e, 0x82, 0x56, 0x82, 0xc3, 0xe0, 0x5d, 0x66, 0x34, 0xc9, 0x1a, + 0xb7, 0x66, 0x24, 0x9c, 0xaf, 0x56, 0x2d, 0x74, 0xf8, 0xb7, 0x7e, 0x8b, 0x79, 0x5c, 0x2a, 0xdc, 0xc7, 0x95, 0xc2, + 0x1d, 0x2c, 0x01, 0xc9, 0xd8, 0xd3, 0xb5, 0x63, 0xe1, 0xab, 0xd1, 0x21, 0x4c, 0xf8, 0x0b, 0x08, 0x1a, 0x6d, 0x8f, + 0x25, 0xd0, 0xb3, 0x6f, 0x15, 0x30, 0xba, 0xf6, 0xb2, 0x04, 0xd2, 0x82, 0xbb, 0xdb, 0x04, 0x5a, 0x85, 0xa8, 0x7d, + 0xfe, 0xf4, 0x73, 0x0e, 0x3c, 0xb2, 0xfe, 0x5c, 0x33, 0xcd, 0xba, 0x17, 0xf4, 0x56, 0x37, 0x1f, 0x8e, 0x71, 0x73, + 0x6c, 0xc0, 0x79, 0xd4, 0x81, 0x9f, 0x06, 0xa2, 0x47, 0x1d, 0x6c, 0x53, 0xf1, 0xb8, 0x04, 0xb2, 0x8f, 0x9e, 0xd6, + 0x40, 0x0a, 0x58, 0xe9, 0xd0, 0x68, 0x91, 0x26, 0x68, 0xb5, 0x9a, 0x9c, 0x93, 0x16, 0x42, 0x4b, 0x79, 0xcb, 0x55, + 0x32, 0x05, 0x1f, 0x69, 0x50, 0x0c, 0xbc, 0xa1, 0x6a, 0x1a, 0x22, 0x3c, 0x46, 0xcb, 0x94, 0x8d, 0xe9, 0x22, 0x53, + 0x71, 0xde, 0xe7, 0x91, 0x89, 0xa4, 0xcb, 0x4c, 0x24, 0xb8, 0xa3, 0x0e, 0x9e, 0x68, 0xfe, 0xf2, 0xb1, 0x36, 0x07, + 0x29, 0x12, 0x9d, 0x3c, 0xd1, 0x09, 0x98, 0x47, 0x49, 0x26, 0x24, 0x33, 0xcd, 0xf4, 0x8c, 0x6d, 0x39, 0xc4, 0xe2, + 0x0e, 0x54, 0xc1, 0xb5, 0x15, 0x65, 0x10, 0x4f, 0x49, 0xde, 0xcf, 0x8f, 0x3a, 0xf1, 0x04, 0xf3, 0x08, 0x38, 0xbd, + 0x77, 0x22, 0x64, 0x8d, 0xf2, 0x56, 0x74, 0x86, 0x0e, 0xa7, 0x58, 0x56, 0x97, 0xa8, 0x33, 0x74, 0x38, 0x41, 0x78, + 0xd6, 0x20, 0x59, 0x0e, 0x1e, 0xc3, 0x3c, 0xff, 0x3f, 0x52, 0xfe, 0x9b, 0xc3, 0x86, 0x98, 0xcf, 0x6f, 0x61, 0xa7, + 0xb0, 0x34, 0x88, 0x33, 0x02, 0x5e, 0x8b, 0xed, 0x53, 0x9c, 0x90, 0x49, 0x33, 0x73, 0x01, 0xf7, 0x74, 0x2b, 0x8d, + 0x3b, 0x85, 0x0e, 0x13, 0x9c, 0x6e, 0x26, 0x85, 0x7a, 0xae, 0xcd, 0x2c, 0x4e, 0xe0, 0x7c, 0xaf, 0x46, 0x61, 0xcb, + 0x2f, 0x36, 0x93, 0xfc, 0xf2, 0x16, 0xb8, 0xcd, 0x14, 0xcb, 0x26, 0xc5, 0x19, 0x9e, 0x35, 0x5f, 0xe1, 0x59, 0xf3, + 0x43, 0x99, 0xd1, 0x58, 0x60, 0x09, 0xc1, 0xfb, 0x20, 0x11, 0xcf, 0xaa, 0xe4, 0x14, 0xcb, 0x86, 0x2e, 0x8f, 0x67, + 0x8d, 0xaa, 0x74, 0x73, 0x81, 0x65, 0x43, 0x97, 0x6e, 0x7c, 0xc0, 0xb3, 0xc6, 0xab, 0x7f, 0x31, 0xe9, 0x20, 0x06, + 0x74, 0x99, 0xa3, 0x65, 0x62, 0x86, 0x78, 0xfd, 0xdb, 0xdb, 0x77, 0xed, 0x9b, 0xce, 0xe1, 0x04, 0xbb, 0xf5, 0x4b, + 0x34, 0x8e, 0x25, 0x2a, 0x64, 0x4d, 0x80, 0x68, 0x82, 0x3b, 0x87, 0x53, 0xdc, 0x39, 0x4c, 0x6c, 0x53, 0xeb, 0x59, + 0x83, 0xdc, 0x29, 0x1f, 0x8a, 0x2a, 0x88, 0x7d, 0xf8, 0xb8, 0xc9, 0xc6, 0x13, 0x54, 0x03, 0x25, 0x3a, 0x9c, 0xd4, + 0x40, 0x05, 0xdf, 0x8b, 0xda, 0x77, 0x55, 0xaf, 0xc2, 0x20, 0x03, 0x25, 0xe4, 0xaf, 0xb9, 0x06, 0x4f, 0x2d, 0x45, + 0x43, 0xc6, 0x4f, 0x31, 0x40, 0xf9, 0x0e, 0x28, 0xb4, 0xf2, 0x44, 0x0f, 0xdd, 0x9b, 0x8e, 0x4e, 0xfc, 0xff, 0x79, + 0x32, 0xe5, 0xd0, 0xcb, 0x2d, 0xb3, 0x35, 0x3d, 0x3b, 0x19, 0x7f, 0xf8, 0xc0, 0x63, 0xfd, 0x5f, 0x3b, 0x50, 0xac, + 0x41, 0x8a, 0xff, 0x2f, 0x1d, 0x9d, 0x0f, 0x46, 0xc8, 0x0a, 0xe2, 0xc2, 0x22, 0xfe, 0xf7, 0x87, 0xe5, 0x75, 0x5f, + 0x6c, 0x75, 0x5f, 0xe8, 0xee, 0xfd, 0xa6, 0xb5, 0x2a, 0x27, 0xae, 0x2a, 0x19, 0xf2, 0x5f, 0xa7, 0x5b, 0x5b, 0xa0, + 0x91, 0x35, 0x7a, 0x36, 0xf1, 0x1b, 0xdc, 0x6f, 0xc7, 0x3b, 0x90, 0x79, 0xcd, 0xcd, 0xd3, 0xa0, 0x70, 0xf8, 0x7a, + 0x77, 0xaa, 0x17, 0x2d, 0xf0, 0xde, 0x94, 0x5a, 0x5f, 0x19, 0xfa, 0x96, 0x83, 0xc5, 0xa6, 0x29, 0xb7, 0x36, 0x96, + 0x8e, 0xba, 0x58, 0xbb, 0x22, 0x42, 0xa5, 0xbb, 0x0b, 0x50, 0x8a, 0x8f, 0x55, 0x93, 0xe9, 0xaf, 0x73, 0x15, 0xe9, + 0x4b, 0xa8, 0x86, 0xfe, 0xbc, 0xbf, 0x50, 0x91, 0x12, 0x73, 0x93, 0x77, 0x7f, 0x0e, 0x7d, 0x82, 0x86, 0xb5, 0xe1, + 0xd9, 0xed, 0xb3, 0xc2, 0xea, 0x77, 0xaa, 0x43, 0xd0, 0x3f, 0x80, 0x2c, 0x69, 0x31, 0x7d, 0x60, 0xdd, 0x1a, 0xb6, + 0x5d, 0x34, 0xcb, 0x44, 0xd3, 0x6a, 0x53, 0xe7, 0x9a, 0x3d, 0xcc, 0xe7, 0x3e, 0x4f, 0xc1, 0x0b, 0xa3, 0x1f, 0xdf, + 0xc1, 0x6e, 0xdc, 0xd5, 0x18, 0x89, 0xba, 0x92, 0xa9, 0x84, 0x7e, 0x74, 0x87, 0x59, 0x74, 0xaf, 0xbd, 0x18, 0x73, + 0xed, 0xef, 0xa3, 0x03, 0xe5, 0x07, 0x95, 0x24, 0x07, 0x96, 0xfd, 0x0d, 0x16, 0xdd, 0x81, 0x79, 0x62, 0x59, 0x4d, + 0x60, 0x15, 0xdd, 0x7b, 0x8b, 0x28, 0x74, 0x23, 0x6b, 0xcd, 0x80, 0xea, 0x66, 0x8c, 0x7a, 0x70, 0x1f, 0x02, 0x3d, + 0xf4, 0xcb, 0x52, 0xca, 0x76, 0x16, 0xd7, 0xba, 0x57, 0xba, 0xfb, 0xcd, 0x01, 0x79, 0x7c, 0xa1, 0xc7, 0x35, 0xfd, + 0xab, 0x49, 0x44, 0x23, 0xf6, 0x0f, 0x67, 0xc5, 0xd5, 0xa2, 0xd0, 0x98, 0x26, 0xfb, 0x2a, 0x4a, 0xe6, 0x6d, 0x30, + 0xd5, 0x4b, 0xe6, 0x9d, 0x3b, 0x6c, 0xbf, 0xef, 0xcd, 0xf7, 0x3d, 0x96, 0x7d, 0xa6, 0x33, 0x62, 0xa6, 0x8b, 0xb9, + 0xef, 0x7b, 0xf3, 0x7d, 0x8f, 0xb7, 0x07, 0x73, 0xeb, 0x2e, 0x14, 0x4b, 0x76, 0x86, 0x0b, 0x30, 0x2c, 0xf7, 0xb8, + 0x9b, 0x5a, 0x96, 0x0e, 0x02, 0x5b, 0x4b, 0x80, 0x38, 0x9f, 0x4f, 0xc3, 0x8a, 0x57, 0x43, 0xc0, 0x7d, 0x3a, 0xd7, + 0xf6, 0x2a, 0x15, 0x78, 0x4c, 0xd0, 0x88, 0xe8, 0xd8, 0x36, 0xfa, 0x59, 0x2f, 0xe0, 0xf2, 0x88, 0x2a, 0xf5, 0x24, + 0x11, 0xf0, 0xaa, 0x5a, 0xe5, 0xad, 0x8b, 0x94, 0x5f, 0xc4, 0xcb, 0x71, 0xc5, 0x1e, 0x53, 0xc9, 0x00, 0x56, 0x65, + 0x49, 0x97, 0x40, 0xea, 0xf9, 0xde, 0x44, 0xbf, 0x6c, 0x22, 0x4f, 0xae, 0x6f, 0x4b, 0xbf, 0x30, 0x35, 0x2d, 0xc4, + 0x62, 0x32, 0x05, 0x1f, 0x5a, 0x60, 0x19, 0x0a, 0x5d, 0xaf, 0xb2, 0xf5, 0xaf, 0x49, 0x6e, 0x12, 0x28, 0x9c, 0x6a, + 0x8a, 0x88, 0x26, 0x6a, 0x41, 0x33, 0x6d, 0x49, 0xca, 0xf3, 0xc9, 0x63, 0x71, 0xf7, 0x12, 0xb0, 0x9b, 0x12, 0xd5, + 0xd8, 0x91, 0xf7, 0x16, 0x76, 0x00, 0x4e, 0x08, 0xdb, 0x55, 0xf1, 0x52, 0x82, 0xce, 0x1f, 0x67, 0x84, 0xed, 0xaa, + 0xfa, 0x84, 0x99, 0xec, 0x29, 0xd9, 0x18, 0x6e, 0x3f, 0x4c, 0x1a, 0x19, 0x3a, 0xea, 0xc4, 0x59, 0xcf, 0x11, 0x03, + 0x03, 0x50, 0x0f, 0xb8, 0x5b, 0xdb, 0xb3, 0xbc, 0xbb, 0x21, 0x79, 0x94, 0xb2, 0x44, 0x98, 0xeb, 0x72, 0x9d, 0xb2, + 0x5a, 0x75, 0x2a, 0x2a, 0x58, 0xe0, 0xa9, 0xb7, 0x17, 0xa8, 0xf9, 0xda, 0x41, 0x71, 0xae, 0x93, 0x4d, 0xd3, 0xf3, + 0xb2, 0xef, 0xde, 0x8e, 0x45, 0xc6, 0x26, 0xed, 0xed, 0x0e, 0x22, 0x61, 0x38, 0x61, 0xe5, 0x71, 0xc2, 0x55, 0x6d, + 0x8f, 0x00, 0xdd, 0x78, 0x22, 0x37, 0x16, 0x64, 0xb9, 0xae, 0x8c, 0xee, 0x3d, 0xbf, 0x5b, 0x4a, 0x84, 0x1d, 0x6d, + 0x49, 0x30, 0x5d, 0x82, 0x56, 0xd3, 0xe9, 0x37, 0x99, 0x6b, 0xcf, 0x0d, 0x6f, 0x8a, 0xb6, 0xb9, 0xbd, 0x49, 0xc7, + 0x7a, 0x7b, 0xe8, 0x18, 0xca, 0x20, 0x06, 0x3a, 0x1f, 0xf1, 0x5e, 0xa3, 0x91, 0x20, 0x50, 0xc8, 0x24, 0x43, 0x2c, + 0x22, 0xa7, 0x45, 0x3f, 0x38, 0xd0, 0xf0, 0xa8, 0x12, 0x10, 0xa6, 0x20, 0x84, 0xf8, 0x5d, 0x6b, 0x84, 0xf5, 0x97, + 0xab, 0x96, 0x0b, 0x1b, 0xa9, 0x36, 0x74, 0xf0, 0xff, 0xf2, 0x97, 0xad, 0x9e, 0x59, 0x2e, 0x8a, 0xc6, 0xcd, 0x4c, + 0x83, 0x45, 0x80, 0xf4, 0x68, 0xb2, 0x1d, 0x14, 0x77, 0xe7, 0x62, 0xbd, 0x21, 0x20, 0x31, 0x83, 0x09, 0xca, 0x86, + 0x75, 0x63, 0x0c, 0xf3, 0xa8, 0xd2, 0xb2, 0xd6, 0x24, 0x66, 0xcf, 0x97, 0xce, 0x5f, 0xf7, 0xe5, 0x5d, 0xcc, 0xf0, + 0x7d, 0x2c, 0xf1, 0x2d, 0x78, 0xd2, 0xc4, 0x02, 0xdb, 0xc7, 0x0b, 0x8a, 0x35, 0x51, 0x3d, 0xc7, 0xde, 0x16, 0xb0, + 0xce, 0x7a, 0x8f, 0x48, 0xef, 0x77, 0xf5, 0xab, 0x0d, 0xbe, 0x5b, 0xf8, 0x15, 0x58, 0x3f, 0x7b, 0x27, 0x29, 0x96, + 0x0d, 0xd1, 0x2c, 0xec, 0x91, 0x01, 0xe5, 0x2a, 0x7e, 0xd9, 0x4f, 0xdd, 0x2a, 0x86, 0x6b, 0x1f, 0xaf, 0xf0, 0x87, + 0x8d, 0x76, 0x1b, 0x79, 0x59, 0xdc, 0xec, 0x4d, 0xd9, 0x10, 0x55, 0xd3, 0x3b, 0x32, 0x37, 0x52, 0xea, 0x5f, 0x1f, + 0x70, 0x6b, 0xab, 0x7d, 0x37, 0xcd, 0xb7, 0x0e, 0x9d, 0xab, 0xa6, 0x5d, 0x6a, 0xad, 0x08, 0xf6, 0x7e, 0xb6, 0x70, + 0x73, 0x6b, 0xc0, 0x1e, 0xfc, 0xdc, 0x1d, 0xcd, 0x55, 0x02, 0xd1, 0xe9, 0x8d, 0x66, 0x7c, 0x15, 0xfe, 0x99, 0x36, + 0xc2, 0x7e, 0xfc, 0x67, 0xf4, 0x67, 0xda, 0x40, 0x7d, 0x14, 0xce, 0xef, 0x56, 0x6c, 0xb6, 0x82, 0x60, 0x6b, 0x0f, + 0x8e, 0xf0, 0x6b, 0xbf, 0x24, 0x57, 0x34, 0xe3, 0xc9, 0xca, 0xbe, 0x84, 0xb7, 0xb2, 0xcf, 0x04, 0xad, 0xf4, 0xe3, + 0x4e, 0xab, 0x50, 0x8c, 0x32, 0x08, 0x2c, 0x1c, 0xee, 0x35, 0xfb, 0x83, 0x56, 0xf3, 0xd1, 0xd0, 0xfc, 0xab, 0x23, + 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x04, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, 0xe9, 0x55, 0x82, + 0x8c, 0xef, 0xc9, 0x6a, 0xc5, 0x6c, 0x34, 0x6b, 0xab, 0xc1, 0x2f, 0x63, 0x33, 0x1d, 0xb6, 0xa3, 0x4e, 0xcf, 0x89, + 0xb1, 0xa4, 0x01, 0x91, 0xa6, 0x31, 0x83, 0x40, 0x52, 0x4b, 0xcd, 0x61, 0xcd, 0xef, 0x82, 0xb8, 0xba, 0x3f, 0x82, + 0x94, 0x1f, 0x82, 0x98, 0x1f, 0x11, 0x08, 0xa0, 0x6d, 0x98, 0xa3, 0xb2, 0x21, 0xe7, 0xbb, 0xf4, 0x40, 0x3b, 0x33, + 0x34, 0xf8, 0x6a, 0xd5, 0xaa, 0x86, 0x29, 0x8b, 0xfa, 0x30, 0x97, 0x6b, 0x2c, 0xc9, 0x1b, 0xd0, 0x35, 0xe7, 0x44, + 0xf6, 0x7d, 0x57, 0x79, 0x78, 0x08, 0x18, 0x0b, 0x02, 0x4e, 0xfa, 0x7d, 0xd9, 0x2f, 0xc8, 0xc5, 0x65, 0x08, 0x3e, + 0x66, 0x98, 0x0f, 0xd4, 0xa0, 0x18, 0x0e, 0x51, 0x6c, 0x9d, 0xce, 0x62, 0x1d, 0x71, 0xc5, 0xf3, 0x4b, 0x2e, 0xc0, + 0x2f, 0x39, 0x47, 0x6c, 0x50, 0x0c, 0xc9, 0x83, 0x24, 0x14, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, 0xd2, 0x37, 0x30, + 0xd5, 0xc3, 0xd2, 0x17, 0xd9, 0x60, 0x31, 0x67, 0x2c, 0x81, 0xe0, 0x66, 0xc0, 0x5e, 0x6a, 0x43, 0xa2, 0xb6, 0x06, + 0x0a, 0xee, 0x02, 0xdf, 0xcc, 0xe8, 0xe9, 0x56, 0x1b, 0x83, 0xc0, 0xe2, 0x85, 0xbe, 0x86, 0x31, 0x08, 0xa4, 0x2f, + 0x57, 0x1d, 0xf6, 0x97, 0x1f, 0x26, 0xcb, 0x0f, 0x5e, 0xa1, 0x4d, 0x76, 0x4a, 0xab, 0x44, 0x3d, 0xbe, 0xca, 0x13, + 0x47, 0x13, 0x64, 0x62, 0xa8, 0x74, 0xc3, 0x32, 0x71, 0x25, 0x7d, 0x26, 0x9a, 0x6c, 0x37, 0x1c, 0x33, 0xe7, 0xbb, + 0xd9, 0xfe, 0x61, 0xdd, 0xce, 0x39, 0xe1, 0x5a, 0x2b, 0xa9, 0xb5, 0x51, 0xcf, 0x34, 0x55, 0xb5, 0xc1, 0xfc, 0x2e, + 0xad, 0x96, 0x16, 0x5b, 0x57, 0xef, 0x9e, 0xff, 0x2c, 0x5d, 0x19, 0x7f, 0x8b, 0x55, 0xa1, 0x15, 0x19, 0x6e, 0xb7, + 0x90, 0x33, 0x67, 0xba, 0x74, 0x8a, 0x5c, 0xa8, 0x0e, 0x7f, 0x51, 0x4f, 0xea, 0x97, 0x2a, 0x83, 0x86, 0x74, 0xe8, + 0xf7, 0x3a, 0x01, 0xe5, 0x1f, 0x4c, 0x4c, 0x64, 0x2c, 0xba, 0xa5, 0x45, 0x1e, 0xfe, 0xf8, 0x22, 0xd7, 0xb1, 0xaa, + 0xf6, 0x60, 0x20, 0x7b, 0xba, 0xe2, 0x1e, 0xdc, 0x9a, 0xf0, 0x31, 0x67, 0x69, 0xbc, 0x17, 0xfc, 0xd8, 0x90, 0x8d, + 0x1f, 0x83, 0x1f, 0xc1, 0xdd, 0xd9, 0x3e, 0x8b, 0x58, 0xc6, 0x85, 0x70, 0xf7, 0x58, 0x97, 0xa5, 0x4a, 0x19, 0x2b, + 0xa7, 0x5b, 0xf6, 0x2f, 0xa4, 0xde, 0x24, 0xe1, 0xa5, 0x25, 0xd6, 0x26, 0x05, 0x2b, 0x9f, 0x92, 0xc2, 0xb3, 0x2b, + 0xfa, 0x56, 0x8b, 0xd9, 0x4b, 0x2d, 0xe9, 0xae, 0xaf, 0x2e, 0x4b, 0x15, 0x34, 0x1c, 0x84, 0xb6, 0xb4, 0x81, 0x04, + 0x18, 0xb8, 0x94, 0x3e, 0x9d, 0xf6, 0x4c, 0x22, 0xb3, 0x24, 0x84, 0x77, 0x0f, 0x2a, 0x98, 0xff, 0xce, 0x36, 0xc2, + 0xaa, 0xc0, 0xe5, 0x4a, 0x15, 0xf5, 0x52, 0x10, 0x08, 0x40, 0x5f, 0x7a, 0x0f, 0x8a, 0xf3, 0xa2, 0xd7, 0x68, 0x08, + 0xd0, 0xc2, 0x52, 0x7d, 0xad, 0x8a, 0xe9, 0xbe, 0xff, 0x9c, 0x9f, 0xf7, 0xe1, 0x1c, 0xd2, 0x36, 0xde, 0xd4, 0xa4, + 0x84, 0x9a, 0x1d, 0xb4, 0x0f, 0x56, 0xd9, 0x5e, 0xf9, 0xb7, 0x21, 0x45, 0x26, 0x7f, 0xc0, 0x7e, 0xa0, 0xb6, 0xc3, + 0xa1, 0x2d, 0x58, 0xf5, 0x52, 0x46, 0xc1, 0x80, 0x95, 0x03, 0x6e, 0x4f, 0x46, 0x09, 0x4d, 0xa6, 0x0c, 0xd4, 0xfd, + 0xa6, 0x68, 0x35, 0xb7, 0x27, 0x75, 0xbf, 0x21, 0xed, 0xec, 0x23, 0xb5, 0xb3, 0x4f, 0x0e, 0x5e, 0x2c, 0x82, 0xfc, + 0x21, 0x42, 0x85, 0xc3, 0xbc, 0x29, 0xd1, 0x51, 0x07, 0xb8, 0x33, 0x70, 0xe0, 0x01, 0x5b, 0x94, 0x83, 0x03, 0x6a, + 0x2d, 0xee, 0x69, 0x23, 0x71, 0xde, 0x9e, 0x50, 0xbb, 0x08, 0x25, 0x6e, 0xd6, 0xcc, 0xb4, 0xa0, 0xb5, 0x42, 0x3b, + 0x8f, 0x7b, 0xbc, 0xcd, 0xb3, 0x5a, 0xfc, 0x84, 0x0d, 0x6b, 0xaa, 0xfa, 0x0d, 0x34, 0x47, 0xb5, 0x20, 0x37, 0x4f, + 0xb5, 0xb7, 0x2a, 0x19, 0x04, 0xc1, 0xd0, 0x70, 0x2a, 0x44, 0x93, 0x8c, 0x41, 0x6b, 0xe8, 0xdd, 0x6a, 0xaf, 0x56, + 0xdc, 0x21, 0xbe, 0xac, 0x79, 0xab, 0xe9, 0x5b, 0x00, 0x5a, 0x84, 0x41, 0x79, 0x6f, 0x12, 0x80, 0xf7, 0x6d, 0x19, + 0x21, 0x6d, 0x39, 0x30, 0x6f, 0x36, 0x96, 0x8a, 0xcd, 0x77, 0x74, 0x32, 0x8c, 0x03, 0x33, 0xa2, 0x00, 0xdf, 0x94, + 0x90, 0x84, 0xab, 0xa4, 0x1b, 0x99, 0x88, 0x39, 0x93, 0x31, 0xc7, 0x37, 0x85, 0x10, 0xea, 0xda, 0x7c, 0x09, 0x5c, + 0xdd, 0xc9, 0x48, 0x7c, 0x33, 0x61, 0xea, 0x1d, 0x2d, 0x26, 0x0c, 0xfc, 0x8a, 0xdc, 0xed, 0x58, 0x4c, 0xc9, 0xc5, + 0x53, 0x19, 0x0e, 0x28, 0x86, 0x07, 0x47, 0x87, 0x58, 0xe9, 0x10, 0x28, 0x15, 0x2e, 0xb2, 0xdb, 0xbd, 0x37, 0x85, + 0xb8, 0xbb, 0x0f, 0x0b, 0x6c, 0x1d, 0x00, 0x4b, 0xa7, 0x49, 0x80, 0x7f, 0xf9, 0x98, 0x8f, 0xd1, 0x98, 0x53, 0xad, + 0xeb, 0xb7, 0xbf, 0xa3, 0x1b, 0xa0, 0xb7, 0xa5, 0xa3, 0xe0, 0xa0, 0x35, 0x84, 0x5c, 0xb8, 0x0b, 0x83, 0x8b, 0x2f, + 0xbf, 0xb6, 0x28, 0xb4, 0x37, 0x16, 0x40, 0xef, 0xaf, 0x04, 0x2c, 0xd8, 0x30, 0xc7, 0x14, 0x5e, 0x6b, 0x9d, 0x30, + 0xe5, 0x45, 0x05, 0x79, 0x52, 0xbe, 0xc7, 0x59, 0xab, 0xfd, 0x96, 0x8d, 0xe1, 0x0e, 0x23, 0xfa, 0x76, 0xe1, 0xc8, + 0x82, 0x07, 0x64, 0x9a, 0xc4, 0x34, 0xfb, 0xc6, 0x45, 0x1e, 0x79, 0x3d, 0x0e, 0x77, 0xb5, 0xe4, 0xe7, 0xeb, 0x15, + 0x5d, 0x63, 0x08, 0x45, 0xe1, 0xf7, 0xfb, 0x15, 0x1e, 0x28, 0xad, 0x0c, 0xda, 0xa0, 0x61, 0x71, 0x9b, 0xff, 0x02, + 0x67, 0x0c, 0xad, 0x17, 0x32, 0x77, 0x74, 0xc6, 0xe1, 0xcc, 0x62, 0xc6, 0x94, 0xc0, 0xa8, 0x94, 0x28, 0xe8, 0x04, + 0x1c, 0x9d, 0xab, 0x0f, 0x92, 0x87, 0xd5, 0xb1, 0x02, 0xf0, 0x24, 0x53, 0xf8, 0x27, 0xdb, 0x04, 0xeb, 0x7e, 0xab, + 0x66, 0x98, 0xfa, 0x8b, 0xda, 0x76, 0x2d, 0x5f, 0xfa, 0x38, 0xd2, 0xc6, 0x10, 0x5a, 0xe7, 0xee, 0x1e, 0x50, 0xc4, + 0x06, 0xbd, 0x88, 0x15, 0xbe, 0x91, 0x8b, 0x91, 0x5e, 0x5f, 0xed, 0x3a, 0xa6, 0x00, 0x51, 0xac, 0xbb, 0x26, 0xbe, + 0xa9, 0x9e, 0x3f, 0x95, 0x71, 0x0e, 0x67, 0x10, 0x84, 0x38, 0x29, 0x2f, 0x1b, 0x62, 0x41, 0x2e, 0x74, 0xa7, 0x42, + 0x77, 0x5a, 0x21, 0x94, 0x4d, 0x8f, 0xca, 0xfb, 0x57, 0x08, 0x61, 0xa0, 0xcb, 0xec, 0xc0, 0xaa, 0x7c, 0x0b, 0xab, + 0xe0, 0xd5, 0x8b, 0x0d, 0xac, 0x12, 0x70, 0x3c, 0x97, 0x68, 0x54, 0x54, 0x38, 0xa4, 0x49, 0x9f, 0x8f, 0x45, 0x90, + 0x00, 0x58, 0xf4, 0x2e, 0xb1, 0x79, 0xdf, 0xc3, 0x21, 0xbf, 0x27, 0x11, 0xf9, 0xd3, 0x8d, 0x68, 0x06, 0xef, 0xe2, + 0xca, 0xbe, 0x43, 0x08, 0x58, 0x7a, 0x8e, 0xe1, 0x3d, 0xe4, 0xef, 0xbf, 0xc3, 0x6a, 0x2d, 0xc8, 0xe3, 0x7f, 0x89, + 0x92, 0xd0, 0xd8, 0x7f, 0x8e, 0x87, 0x16, 0x09, 0xfd, 0x81, 0x6f, 0x8e, 0xb0, 0xc2, 0xc1, 0xad, 0x22, 0x2e, 0x83, + 0x5b, 0x7c, 0xac, 0x43, 0x0f, 0x00, 0x4b, 0x28, 0xf6, 0x41, 0xbe, 0x81, 0x62, 0x1a, 0x07, 0x14, 0x59, 0xfa, 0x17, + 0xb8, 0x60, 0xb5, 0x50, 0xde, 0xdf, 0xb6, 0x9c, 0x94, 0x56, 0xbb, 0xe4, 0xd5, 0xe6, 0x40, 0xe5, 0xa7, 0x7f, 0xe1, + 0x2b, 0xf5, 0x43, 0xcd, 0xf6, 0x0b, 0xdf, 0x58, 0xa0, 0xc7, 0xa0, 0x08, 0xb0, 0xbf, 0xd7, 0x84, 0x3b, 0x8a, 0x5e, + 0xe6, 0x62, 0xbf, 0x6d, 0xaf, 0x7b, 0x89, 0xb9, 0xbc, 0xae, 0xb2, 0xe6, 0x60, 0x0a, 0x0d, 0x0e, 0xaa, 0x70, 0x46, + 0x60, 0x2e, 0x5f, 0x94, 0x05, 0xe7, 0x20, 0xde, 0xf7, 0xa5, 0xce, 0x29, 0xa3, 0x01, 0xbc, 0x48, 0xca, 0x47, 0xa7, + 0xfa, 0x1c, 0x5c, 0xc6, 0x35, 0x9b, 0xf8, 0x44, 0xba, 0x54, 0x60, 0x25, 0x8d, 0x71, 0x68, 0x40, 0x53, 0x3a, 0x07, + 0xb3, 0x0d, 0xa0, 0xe0, 0xf6, 0x7c, 0xd8, 0x58, 0x28, 0xef, 0x2d, 0xda, 0xda, 0xd3, 0xd1, 0x84, 0x58, 0x93, 0x26, + 0xef, 0x6e, 0x5b, 0x23, 0x83, 0x33, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, 0x84, 0x27, 0x28, + 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xb2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x5a, 0x6a, 0x20, 0x2b, 0x6a, 0x90, + 0x7b, 0xd4, 0x40, 0xd4, 0xb7, 0x7f, 0x01, 0x0b, 0x61, 0x22, 0x54, 0x49, 0x2f, 0x20, 0xc2, 0x5c, 0x69, 0x3e, 0xa0, + 0x88, 0x7c, 0xc8, 0x6b, 0x40, 0x85, 0x94, 0xbc, 0x04, 0xa3, 0x71, 0x78, 0xbd, 0x07, 0xdc, 0x2f, 0x0d, 0xc3, 0xe0, + 0x38, 0x05, 0x9d, 0xff, 0xd6, 0xe5, 0x43, 0xf5, 0x72, 0x75, 0x10, 0xc2, 0x4f, 0x24, 0x64, 0x98, 0x46, 0x7e, 0x01, + 0xb2, 0x99, 0x63, 0x71, 0x70, 0x20, 0x40, 0xe0, 0x87, 0x28, 0xc2, 0x1e, 0xcf, 0xf0, 0x32, 0xd9, 0x20, 0x7a, 0x6e, + 0x56, 0x79, 0x35, 0x2b, 0xe1, 0xcd, 0xaa, 0x70, 0x34, 0x8e, 0xae, 0x09, 0x03, 0xc1, 0x85, 0x9a, 0x7d, 0x83, 0x10, + 0x28, 0x5b, 0x6e, 0x35, 0x5d, 0x7a, 0x0a, 0xe6, 0xa3, 0x61, 0xf0, 0x96, 0xc1, 0x8b, 0xba, 0xda, 0xe4, 0x9f, 0x29, + 0x96, 0x28, 0xcd, 0x3c, 0x36, 0x3c, 0x27, 0x75, 0x8a, 0xa2, 0xbf, 0x04, 0xcf, 0xc3, 0xa0, 0x79, 0x11, 0xa0, 0x06, + 0xfc, 0xdb, 0xe0, 0xa8, 0x47, 0x23, 0x9a, 0xa6, 0x2e, 0xf8, 0x4d, 0x42, 0xf4, 0x26, 0x5b, 0xad, 0x64, 0x45, 0xd0, + 0x23, 0xb3, 0xc1, 0x80, 0x95, 0x78, 0x02, 0x3b, 0xd6, 0x70, 0xb0, 0xe4, 0x85, 0x0c, 0x73, 0x77, 0x4a, 0xe1, 0x1c, + 0x43, 0x3a, 0xc2, 0x89, 0x17, 0xb3, 0xf1, 0x3f, 0x9f, 0xa9, 0xbf, 0x7e, 0x6e, 0xbe, 0x96, 0x11, 0x11, 0x2e, 0x88, + 0x5c, 0x8d, 0x1d, 0x91, 0x5e, 0xd8, 0x32, 0x35, 0xb0, 0x65, 0x7e, 0x70, 0xd6, 0xd5, 0x43, 0x13, 0x2e, 0x0e, 0x0c, + 0xa8, 0x91, 0x67, 0xb4, 0x82, 0x33, 0x52, 0x0e, 0x1c, 0x94, 0x10, 0x8a, 0x15, 0xe1, 0x94, 0x5c, 0x40, 0x24, 0xbc, + 0x04, 0xf5, 0xc0, 0xb0, 0xc0, 0x93, 0xa0, 0xa6, 0x20, 0x41, 0x25, 0xae, 0x76, 0x0a, 0xb3, 0xce, 0xf4, 0x6c, 0xa7, + 0xa8, 0x67, 0x83, 0xfc, 0xfc, 0xa2, 0xc2, 0x14, 0x58, 0xda, 0x83, 0x83, 0x02, 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, + 0x40, 0x4f, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0x4a, 0x7b, 0x1d, 0x68, 0x5b, 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, + 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x7d, 0x15, 0x6f, 0x47, 0x48, 0xec, 0x7f, 0x54, 0x3a, 0xd0, 0x98, 0x25, 0xdd, 0xd5, + 0xc6, 0x7c, 0x55, 0xd3, 0x23, 0x56, 0x93, 0x10, 0x36, 0x48, 0x97, 0xe3, 0xd3, 0x9e, 0xc1, 0x15, 0xab, 0xd0, 0x72, + 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x16, 0x51, 0xc9, 0x86, 0x61, 0x06, 0x61, + 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0x33, 0x7f, 0x4a, 0x1f, 0x6c, 0xba, 0x76, 0xe6, 0x11, 0x40, + 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x37, 0x2a, 0x33, 0xbf, 0x96, 0xb6, 0x95, 0xdb, 0xf6, 0x18, 0x7b, 0x21, 0xb7, + 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x08, 0x55, 0x6d, 0xc8, 0x5a, 0x1b, 0x3a, 0xd0, 0x2f, + 0xd2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x59, 0x2e, 0xc1, 0x22, 0xbc, 0x74, 0x08, 0x7f, 0x97, 0x83, 0x33, 0x3c, 0x66, + 0x58, 0xac, 0x56, 0x50, 0xcf, 0xe1, 0x7d, 0xb2, 0x19, 0x9c, 0x54, 0x6c, 0x8c, 0x5d, 0x98, 0x89, 0x87, 0x65, 0x13, + 0x02, 0x27, 0xd0, 0xaf, 0xab, 0x88, 0xfa, 0xfb, 0xed, 0xf8, 0xa9, 0x0c, 0x6b, 0x3b, 0x10, 0x6b, 0xd6, 0x1b, 0xac, + 0x3e, 0x80, 0x96, 0xff, 0x93, 0xb8, 0x87, 0xca, 0xbc, 0x9b, 0x84, 0x7c, 0x73, 0x11, 0x7b, 0xac, 0x87, 0x18, 0xa9, + 0x2d, 0xee, 0x0e, 0x21, 0xfe, 0x9f, 0xad, 0x28, 0x06, 0x3c, 0xaa, 0xf8, 0xe7, 0x10, 0xf5, 0x20, 0x14, 0xb5, 0xf1, + 0xb0, 0x01, 0x4a, 0xbb, 0x5c, 0x57, 0x62, 0xa4, 0x4f, 0x20, 0xdf, 0xda, 0xf0, 0x82, 0xfa, 0x24, 0xca, 0x41, 0x4e, + 0xf6, 0xa2, 0x92, 0x26, 0x1b, 0xc2, 0x5c, 0x6f, 0x0b, 0xc7, 0xf4, 0xd5, 0x06, 0x2d, 0xc2, 0x17, 0xc0, 0xce, 0x70, + 0x2d, 0x59, 0x5a, 0xf0, 0xe5, 0x35, 0xf0, 0xb9, 0x35, 0xd7, 0x14, 0x25, 0x47, 0xfd, 0x17, 0x52, 0xdf, 0xfa, 0xc3, + 0xef, 0xd8, 0x13, 0x1f, 0xa9, 0xd5, 0x91, 0x6c, 0x84, 0x5a, 0xb3, 0x76, 0xbc, 0x6c, 0x33, 0xc2, 0xa0, 0x34, 0xd1, + 0xfb, 0x2a, 0x64, 0x95, 0x3b, 0x3b, 0x95, 0xde, 0x9c, 0xbe, 0xe6, 0x95, 0x73, 0x2a, 0x37, 0x8c, 0x6a, 0xa9, 0x69, + 0x80, 0x08, 0x57, 0x2e, 0x91, 0xbc, 0x4f, 0x74, 0xf8, 0x07, 0x8d, 0x71, 0xf5, 0x48, 0xe1, 0xef, 0x77, 0xc5, 0x0e, + 0xd9, 0x8e, 0x0e, 0xb7, 0x11, 0x34, 0xcf, 0x57, 0xf0, 0x80, 0xa3, 0x92, 0x21, 0x44, 0x39, 0xb9, 0xd8, 0xcf, 0x6b, + 0xa6, 0x6c, 0x37, 0x01, 0x42, 0x48, 0x39, 0x9c, 0x75, 0x0e, 0x91, 0xb5, 0xd0, 0x23, 0x55, 0x94, 0xc3, 0x2d, 0x9a, + 0x6b, 0x03, 0x54, 0x68, 0x81, 0x74, 0xf9, 0x85, 0xdd, 0xc7, 0x02, 0xa2, 0x97, 0xaf, 0x6d, 0x08, 0x63, 0x6b, 0x65, + 0x89, 0x0b, 0x3d, 0x6a, 0x13, 0x46, 0xd7, 0x6e, 0x0c, 0x6b, 0x03, 0xa3, 0xa7, 0x41, 0x49, 0x0b, 0x42, 0x5d, 0xf7, + 0xe8, 0x79, 0xa2, 0x03, 0x3d, 0x66, 0x84, 0x36, 0x18, 0x9e, 0x12, 0x05, 0x96, 0x4d, 0x05, 0x58, 0xf0, 0x2d, 0x8b, + 0x38, 0xd7, 0x36, 0x9b, 0x2c, 0xfc, 0xa8, 0x42, 0xfd, 0xb4, 0x5f, 0x56, 0x31, 0xcf, 0x85, 0xa5, 0x6e, 0xcf, 0x13, + 0x17, 0x8f, 0xee, 0xe9, 0x9b, 0xeb, 0x17, 0x2f, 0x5f, 0xbf, 0x5a, 0xad, 0xda, 0xac, 0xd9, 0x3e, 0xc1, 0x3f, 0xa9, + 0x32, 0x1e, 0x6c, 0x19, 0x05, 0xe8, 0xe0, 0x60, 0x9f, 0x6b, 0x17, 0x9e, 0x2f, 0x7c, 0x0e, 0x71, 0x83, 0xd4, 0x10, + 0x27, 0x45, 0x19, 0x13, 0xe4, 0x2e, 0xe8, 0x07, 0xf7, 0x01, 0x28, 0xa1, 0x2a, 0xf2, 0xf7, 0x61, 0x73, 0xf6, 0x7b, + 0x10, 0x98, 0x08, 0xea, 0x43, 0x04, 0x10, 0x88, 0x57, 0x8a, 0x0b, 0xc2, 0x5c, 0x02, 0x44, 0xf1, 0x5e, 0xc0, 0x9b, + 0x90, 0x3a, 0x6a, 0xd5, 0x22, 0x0f, 0x0b, 0x20, 0x89, 0x26, 0x1c, 0x25, 0x3d, 0xd2, 0x01, 0xbc, 0x21, 0x28, 0xa5, + 0xf9, 0xd5, 0xcb, 0xac, 0xbb, 0x54, 0x86, 0xfa, 0xad, 0x38, 0xc3, 0x53, 0xfb, 0x39, 0x85, 0xcf, 0x69, 0xcf, 0x9d, + 0x0e, 0xf2, 0x30, 0xc3, 0x0b, 0x22, 0x0f, 0xdd, 0xb3, 0x88, 0xcb, 0x79, 0xc1, 0xbe, 0x72, 0xb1, 0x90, 0xf1, 0xf2, + 0x2e, 0x16, 0xd1, 0x5d, 0x33, 0x3d, 0x0c, 0x8b, 0xe8, 0xae, 0x99, 0x47, 0x77, 0x08, 0xdf, 0xc7, 0x22, 0xba, 0x37, + 0x29, 0xf7, 0xcd, 0x1c, 0x6e, 0xbe, 0x70, 0x0e, 0x87, 0xa2, 0x29, 0xda, 0x58, 0x6c, 0x16, 0x35, 0x29, 0xb6, 0xa8, + 0x87, 0xc1, 0xbf, 0xef, 0xd8, 0xf8, 0x7e, 0xf8, 0x12, 0x5c, 0x9a, 0x34, 0x91, 0x9f, 0x40, 0xfa, 0x69, 0x55, 0x06, + 0xee, 0x53, 0xd2, 0xea, 0x4d, 0xcf, 0x65, 0xb3, 0xdd, 0x6b, 0x34, 0xa6, 0xb0, 0x77, 0x13, 0x92, 0xb9, 0x62, 0xd3, + 0x86, 0x8e, 0xaf, 0xb3, 0x9f, 0xac, 0x56, 0xfb, 0x19, 0xd2, 0x1b, 0x6e, 0xc2, 0x42, 0x35, 0x98, 0x0e, 0x71, 0x0b, + 0x3f, 0x4f, 0x10, 0x5a, 0xb2, 0xc1, 0x74, 0x48, 0xd8, 0x60, 0xda, 0x68, 0x0f, 0x8d, 0xa1, 0x9d, 0xde, 0x8a, 0x6b, + 0x08, 0xa1, 0x39, 0x1d, 0x1e, 0xe9, 0x92, 0xc2, 0xe6, 0x9b, 0x2f, 0x5a, 0x05, 0xf4, 0xcb, 0x6b, 0xc1, 0xcb, 0x04, + 0xee, 0x40, 0x5f, 0xf4, 0xdc, 0x3c, 0xdd, 0x5a, 0x90, 0xe3, 0xa3, 0xca, 0xd5, 0x9e, 0x22, 0xac, 0x7b, 0xca, 0x0f, + 0x8b, 0x43, 0xdd, 0x8c, 0xed, 0x52, 0xd8, 0x6f, 0x5f, 0x33, 0xf2, 0xd1, 0xc2, 0x02, 0x10, 0xa4, 0x82, 0x47, 0x52, + 0xd8, 0x70, 0x4a, 0x3e, 0x5c, 0x2c, 0x54, 0xb6, 0x60, 0x92, 0x91, 0x56, 0x2f, 0xd3, 0x96, 0xfe, 0x99, 0x8d, 0x68, + 0x4a, 0x31, 0x25, 0x89, 0x2b, 0x99, 0x69, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x10, 0xa7, 0x04, 0xe2, + 0x21, 0xf5, 0x0a, 0x6d, 0xe0, 0x15, 0x4e, 0x9b, 0xc5, 0x80, 0x0d, 0xd1, 0xd1, 0x31, 0xa6, 0x83, 0xcf, 0xc9, 0xbc, + 0x0d, 0x8f, 0x05, 0x7e, 0x1e, 0x92, 0x69, 0x53, 0x94, 0x09, 0x12, 0x12, 0xd2, 0xa6, 0x38, 0x84, 0xbd, 0x84, 0x70, + 0x62, 0x2a, 0x26, 0x03, 0x36, 0x6c, 0x4e, 0xcb, 0x8a, 0x1d, 0x57, 0xb1, 0x21, 0xca, 0x04, 0x53, 0xb1, 0x61, 0x2b, + 0xfa, 0xaf, 0x33, 0x68, 0x10, 0xf8, 0x00, 0x60, 0x00, 0x00, 0x85, 0xbc, 0x68, 0xbe, 0x38, 0x27, 0x6e, 0xb3, 0x9b, + 0x7b, 0xfc, 0x16, 0x58, 0xa0, 0xd5, 0xf6, 0xff, 0x2e, 0x94, 0x01, 0x7b, 0xca, 0x42, 0xc7, 0xcc, 0x2d, 0x8c, 0x8a, + 0x0e, 0xa0, 0x52, 0x22, 0x4c, 0xa1, 0x21, 0xb3, 0x9f, 0x68, 0xa8, 0x79, 0x5a, 0x83, 0x6c, 0xa0, 0x86, 0xcd, 0x04, + 0x8e, 0x18, 0x78, 0x87, 0x86, 0x4c, 0xb5, 0x31, 0x61, 0x98, 0xc1, 0x14, 0x13, 0x0d, 0x9e, 0x69, 0xdc, 0x5a, 0x0b, + 0x2d, 0xcb, 0xf5, 0xb3, 0xfe, 0xdf, 0x2a, 0xcc, 0x07, 0x45, 0xb3, 0x3d, 0x44, 0xfb, 0x84, 0x98, 0x8f, 0x21, 0x6c, + 0x32, 0x9b, 0xda, 0xd0, 0xdf, 0x47, 0x9d, 0xd8, 0x7c, 0xc2, 0x9f, 0xe1, 0x5a, 0xef, 0x00, 0x1d, 0x78, 0x50, 0xaf, + 0xbf, 0xa8, 0xa9, 0xbc, 0x3e, 0xee, 0x8c, 0x52, 0xb9, 0xeb, 0xdd, 0x69, 0x4f, 0x53, 0xec, 0x7b, 0xeb, 0xe1, 0xf2, + 0xa1, 0x1e, 0x02, 0x66, 0x0c, 0xfa, 0x96, 0x19, 0x7d, 0x2f, 0x44, 0x72, 0x41, 0x04, 0x16, 0x1a, 0x6b, 0x18, 0xec, + 0xad, 0x83, 0x03, 0x5d, 0x8d, 0x35, 0xe0, 0x79, 0x52, 0x04, 0x82, 0x81, 0x8b, 0xa0, 0x0c, 0x68, 0x92, 0xeb, 0xdb, + 0x70, 0xf2, 0x91, 0xd9, 0x5f, 0xb8, 0xbc, 0x7d, 0x2c, 0x8c, 0xb6, 0x55, 0x27, 0xdf, 0x97, 0x05, 0xee, 0xcb, 0x7b, + 0x49, 0xa3, 0xe0, 0x46, 0xe6, 0x26, 0x2f, 0xd7, 0x77, 0xeb, 0xae, 0x54, 0x67, 0x77, 0x33, 0x9d, 0xb2, 0x99, 0xce, + 0x76, 0x33, 0xbe, 0x66, 0xe6, 0x5b, 0x56, 0x91, 0xfa, 0x64, 0x8d, 0xe4, 0x9c, 0xe6, 0x3f, 0xd1, 0x39, 0x18, 0x05, + 0x73, 0x73, 0xaf, 0x0a, 0x27, 0x57, 0x46, 0x2e, 0xf6, 0x33, 0x4d, 0x5c, 0x91, 0xbe, 0x50, 0x87, 0x00, 0x2f, 0x2f, + 0xca, 0xc7, 0x07, 0xb8, 0xc8, 0x7f, 0x15, 0xa9, 0x8d, 0x72, 0x9a, 0x0b, 0x25, 0x72, 0x16, 0x20, 0x8d, 0xaa, 0x36, + 0x06, 0xf6, 0xd2, 0xec, 0x3d, 0xd9, 0xe7, 0x83, 0x2a, 0x62, 0xde, 0x50, 0x3f, 0xf7, 0xf1, 0x3d, 0x4d, 0xb1, 0x55, + 0x13, 0x27, 0xe4, 0x43, 0x12, 0x66, 0x20, 0x9b, 0x0d, 0xaa, 0xd7, 0x7e, 0x1b, 0x6d, 0x5c, 0x34, 0x43, 0xd9, 0xd7, + 0x4f, 0x9c, 0xfc, 0x50, 0x68, 0xe3, 0x00, 0xe3, 0xe8, 0x8f, 0x30, 0x35, 0x60, 0x4f, 0x22, 0x47, 0xa1, 0xa3, 0x3b, + 0x93, 0x76, 0xef, 0xa7, 0xdd, 0xeb, 0xb4, 0x0e, 0x94, 0x03, 0xd2, 0x6c, 0xcb, 0x74, 0xee, 0xdd, 0xf7, 0x3d, 0xbc, + 0x74, 0xbb, 0x86, 0x48, 0xdc, 0xf3, 0xc7, 0xda, 0x18, 0xe2, 0x0d, 0xd8, 0x88, 0xca, 0x83, 0x83, 0x3f, 0xac, 0xf7, + 0x6d, 0x25, 0xcb, 0xca, 0x6f, 0x84, 0x03, 0xdb, 0x60, 0x2a, 0x6d, 0x5e, 0x2a, 0x92, 0x05, 0xd8, 0x75, 0xee, 0xef, + 0x8e, 0x87, 0xff, 0x52, 0xfa, 0x4c, 0x8b, 0x71, 0x15, 0x7f, 0x25, 0xd2, 0xd2, 0x43, 0x54, 0x41, 0x04, 0xd2, 0xca, + 0xba, 0xd4, 0x37, 0x1d, 0xbd, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x0d, 0xcd, 0x8b, 0xdc, 0x2a, 0x82, 0x47, + 0x0b, 0x6b, 0x0c, 0xcd, 0x7d, 0xe9, 0x9d, 0x64, 0x02, 0xa2, 0xd6, 0xc7, 0xed, 0x4b, 0x22, 0xa1, 0xac, 0xee, 0x42, + 0x38, 0xdc, 0x85, 0x60, 0x5e, 0x06, 0x6d, 0x83, 0xd8, 0xed, 0x36, 0x68, 0x5b, 0x28, 0x89, 0x34, 0x81, 0xdb, 0xbd, + 0xc1, 0xc2, 0xde, 0x87, 0x97, 0x63, 0x39, 0x96, 0xee, 0x9a, 0xcc, 0x3c, 0x00, 0x04, 0x6a, 0x1f, 0x56, 0x3c, 0xb1, + 0x20, 0x88, 0xac, 0xe1, 0xe8, 0x7b, 0xce, 0x6e, 0x8d, 0xe5, 0xf0, 0x6c, 0xbe, 0x50, 0x2c, 0xd5, 0x77, 0xd4, 0x80, + 0x3f, 0x75, 0x3f, 0xaf, 0x9f, 0x92, 0x9a, 0x6e, 0xfc, 0x01, 0x84, 0x91, 0xb0, 0xca, 0x0e, 0xad, 0x90, 0x30, 0xc1, + 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0xa5, 0xc3, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x00, 0x9b, 0x78, 0x63, + 0x5e, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x07, 0xcd, 0xa0, 0xc1, 0x62, 0x1b, 0x94, + 0xd9, 0x45, 0x18, 0xcf, 0xcf, 0x4f, 0x74, 0x9c, 0xf6, 0x52, 0xaf, 0xfe, 0x5b, 0x02, 0x06, 0xf8, 0x12, 0xbc, 0xc4, + 0xfc, 0xe8, 0xae, 0x03, 0xd5, 0x80, 0xfa, 0xa2, 0xc1, 0x86, 0x68, 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xd9, 0x6b, 0x2e, + 0x69, 0xae, 0xb9, 0xa4, 0xbd, 0xe6, 0x92, 0xee, 0x9a, 0x4b, 0xea, 0x6b, 0x2e, 0xe9, 0xae, 0xb9, 0x1c, 0x08, 0x3f, + 0x79, 0x71, 0x1c, 0x43, 0x0e, 0x71, 0x15, 0x95, 0x89, 0x8c, 0x07, 0x17, 0x9e, 0xfb, 0x2c, 0x92, 0xe5, 0xf2, 0xfb, + 0x31, 0xe4, 0xb6, 0x6c, 0x25, 0xb4, 0xdb, 0x14, 0x93, 0x10, 0x39, 0xfd, 0xe0, 0xa0, 0x74, 0x77, 0x06, 0x1f, 0xf5, + 0x98, 0xe3, 0xa5, 0x71, 0xa2, 0xfd, 0x03, 0x74, 0xf2, 0xfa, 0xd7, 0xc7, 0x58, 0xac, 0x89, 0xb4, 0x26, 0xf7, 0xfb, + 0x6d, 0x47, 0x29, 0x3e, 0x25, 0x3a, 0x3c, 0x39, 0x8f, 0x94, 0x16, 0x41, 0x10, 0xa2, 0x24, 0xc7, 0x09, 0x11, 0x66, + 0xbf, 0x3b, 0x57, 0x78, 0xad, 0x8a, 0x72, 0x66, 0x25, 0x57, 0x19, 0x38, 0xb1, 0x6b, 0x2b, 0x0c, 0xd4, 0x03, 0x17, + 0x82, 0x44, 0x27, 0xfc, 0xd1, 0xcc, 0x0c, 0x39, 0x4b, 0xca, 0xa4, 0x8f, 0xcd, 0x4c, 0x13, 0xb0, 0x82, 0xec, 0x3b, + 0x98, 0x2d, 0xef, 0x62, 0x8a, 0xef, 0xe3, 0x04, 0xff, 0xbf, 0xec, 0xbd, 0xeb, 0x92, 0xdb, 0x46, 0x96, 0x2e, 0xfa, + 0x2a, 0x55, 0x0c, 0x99, 0x06, 0xc4, 0x24, 0x8b, 0xa5, 0xbd, 0x67, 0x22, 0x0e, 0x58, 0x29, 0x86, 0x2c, 0x59, 0xdd, + 0x72, 0x5b, 0x97, 0x56, 0xa9, 0xdd, 0x76, 0x33, 0x78, 0x68, 0x14, 0x90, 0x24, 0x20, 0x83, 0x00, 0x0d, 0x80, 0x55, + 0xa4, 0x48, 0xbc, 0xfb, 0x8e, 0xb5, 0x56, 0x5e, 0x41, 0xb0, 0xa4, 0x9e, 0xd9, 0xf3, 0xeb, 0x9c, 0x3f, 0x52, 0x31, + 0x91, 0x48, 0xe4, 0x3d, 0x57, 0xae, 0xcb, 0xf7, 0xdd, 0x15, 0xbb, 0xa0, 0xb4, 0x7d, 0x41, 0x94, 0xe1, 0x6f, 0xe9, + 0xf5, 0xf2, 0x10, 0xe2, 0x7d, 0x7a, 0x69, 0x7e, 0x91, 0xb6, 0xa2, 0x00, 0x0f, 0x11, 0x7a, 0x54, 0x07, 0x82, 0x9d, + 0xf1, 0x84, 0x07, 0x70, 0xb2, 0x9a, 0xe5, 0xfc, 0x49, 0x0a, 0xe2, 0x44, 0xc1, 0x21, 0xe0, 0x6a, 0x77, 0x9b, 0x7e, + 0x01, 0xc3, 0x97, 0x0e, 0xb6, 0x1c, 0xde, 0x15, 0xbb, 0x1e, 0x2b, 0xf9, 0x07, 0x60, 0xdf, 0xea, 0xc9, 0x58, 0xdd, + 0x1e, 0x38, 0xeb, 0x52, 0x8a, 0x8e, 0x37, 0xc5, 0xe1, 0xed, 0xf9, 0xec, 0xb0, 0x0b, 0x22, 0xb6, 0x0f, 0x32, 0xac, + 0x75, 0xd2, 0xf0, 0x9f, 0x68, 0xeb, 0x60, 0x31, 0xc2, 0xfe, 0x2f, 0xeb, 0x81, 0x97, 0x90, 0x1a, 0x0a, 0x5c, 0x0c, + 0xb6, 0x1c, 0xad, 0xed, 0x32, 0x0d, 0xdc, 0xd4, 0xa0, 0xd7, 0x0f, 0x14, 0xa2, 0xbc, 0x64, 0x34, 0x37, 0x82, 0x4d, + 0x63, 0xc8, 0xc5, 0xe1, 0xb8, 0x59, 0x0e, 0x79, 0x49, 0xd3, 0x69, 0x10, 0x4a, 0x77, 0x96, 0x0d, 0x24, 0x51, 0xf6, + 0x41, 0xa8, 0x5d, 0x5b, 0x0e, 0xbb, 0xc0, 0xf6, 0xe5, 0x8f, 0x86, 0xb1, 0x7f, 0xb5, 0x7c, 0x2a, 0xa4, 0x8b, 0x78, + 0x05, 0x82, 0xa8, 0xfd, 0x3c, 0x1b, 0x6e, 0xfd, 0xab, 0xcd, 0x53, 0xa1, 0xfc, 0xc6, 0x2b, 0x5b, 0x0e, 0xa9, 0xb3, + 0x16, 0xbe, 0x30, 0x1e, 0x1e, 0x5c, 0x19, 0xda, 0x8e, 0x47, 0xa1, 0xff, 0x36, 0x6b, 0x04, 0x37, 0x36, 0xb4, 0xcf, + 0x17, 0x3e, 0x6c, 0x6d, 0x34, 0xd6, 0x14, 0xd3, 0x2d, 0xf4, 0x6f, 0x32, 0x5b, 0xda, 0xd3, 0xa8, 0xe4, 0xc5, 0xb9, + 0x69, 0xc4, 0x42, 0x18, 0x30, 0xf4, 0x93, 0xf9, 0x00, 0xaa, 0xb9, 0xd3, 0x11, 0xc8, 0xe4, 0x03, 0x3d, 0x58, 0x93, + 0x5a, 0xf5, 0xd7, 0x30, 0x93, 0xff, 0x47, 0x2a, 0x2c, 0x46, 0x77, 0xdb, 0x30, 0x53, 0x7f, 0x44, 0xf2, 0x0f, 0x56, + 0xf1, 0x7d, 0xea, 0x85, 0xda, 0x8f, 0x85, 0x15, 0x18, 0x94, 0xa8, 0x1a, 0xd0, 0x03, 0x11, 0x54, 0x65, 0x90, 0x66, + 0x58, 0x9d, 0x83, 0x7e, 0xf7, 0xb4, 0xea, 0x48, 0x0e, 0x69, 0xad, 0x86, 0x54, 0x30, 0x55, 0x6a, 0x50, 0x1d, 0x8f, + 0xab, 0x94, 0xe9, 0x32, 0xe0, 0x92, 0xbe, 0x4a, 0x95, 0x52, 0xf8, 0x4f, 0x04, 0xa0, 0x73, 0x70, 0x8f, 0xaf, 0xc7, + 0x40, 0x9a, 0x61, 0xe1, 0xb7, 0x66, 0xa7, 0xd7, 0x24, 0xdc, 0x26, 0xc1, 0xc5, 0x00, 0xe7, 0xe8, 0x3a, 0x2c, 0x57, + 0x29, 0x44, 0x50, 0x95, 0x50, 0xdf, 0xdc, 0x34, 0x28, 0x6d, 0x35, 0x08, 0x6b, 0x12, 0xea, 0x4c, 0xb2, 0x51, 0x69, + 0xbb, 0x51, 0x98, 0x2d, 0xe2, 0x7a, 0x46, 0x58, 0x73, 0x36, 0x53, 0x0d, 0x4c, 0x1a, 0x8e, 0x9b, 0x46, 0x6b, 0x51, + 0xa1, 0xa6, 0x30, 0xaf, 0x71, 0x55, 0xa9, 0xea, 0x6e, 0xcf, 0x2d, 0xa5, 0x65, 0x7b, 0xd5, 0x4d, 0xb2, 0x21, 0x97, + 0xa1, 0x0c, 0x83, 0xad, 0x1c, 0xc1, 0x04, 0x92, 0xe4, 0xcc, 0xdf, 0xca, 0x3f, 0xd4, 0xa6, 0x6b, 0x01, 0x73, 0x8c, + 0x59, 0x36, 0x2c, 0xe8, 0x15, 0xb8, 0x07, 0x5a, 0xe9, 0xd5, 0x34, 0xbb, 0xaa, 0x82, 0x64, 0x58, 0xe8, 0x65, 0x93, + 0xf1, 0x3f, 0x85, 0x91, 0x26, 0x33, 0x56, 0xb2, 0xc8, 0x76, 0x75, 0x4a, 0x9c, 0xc7, 0x09, 0x6c, 0x8f, 0xa6, 0xb7, + 0x7c, 0x9f, 0x41, 0x54, 0x10, 0x28, 0x98, 0x31, 0x5f, 0x76, 0xf5, 0xcc, 0xf7, 0x99, 0x65, 0xea, 0x3e, 0x1e, 0x8d, + 0x19, 0xdb, 0xef, 0xf7, 0xab, 0x7e, 0x5f, 0xcd, 0xb7, 0x7e, 0x3f, 0x79, 0x6e, 0xfe, 0xf6, 0x80, 0x41, 0x41, 0x4e, + 0x44, 0x53, 0x21, 0x82, 0x7f, 0x48, 0x9e, 0x22, 0x19, 0xdd, 0x69, 0x9f, 0x5b, 0xce, 0x96, 0xf9, 0x09, 0x08, 0xe6, + 0xf1, 0x78, 0xad, 0xc0, 0xae, 0x25, 0x8a, 0x84, 0x2c, 0xff, 0x29, 0x18, 0xcf, 0xdc, 0x07, 0x58, 0x32, 0x00, 0x61, + 0xab, 0x3c, 0x5d, 0xef, 0xf9, 0x2a, 0x78, 0xa7, 0xe3, 0x5d, 0x63, 0x45, 0x06, 0xe2, 0x16, 0xd8, 0x88, 0xb5, 0xf6, + 0x80, 0x9c, 0x29, 0xc0, 0xf1, 0xe2, 0x78, 0xbc, 0x94, 0xbf, 0x74, 0xb3, 0x75, 0x02, 0x95, 0x02, 0xb7, 0x47, 0x27, + 0x07, 0xff, 0x1d, 0x68, 0x06, 0xe5, 0x30, 0x6f, 0x76, 0xbf, 0x33, 0x27, 0x3f, 0x3d, 0xc5, 0x3f, 0xe1, 0x21, 0x3a, + 0xfd, 0x76, 0x6f, 0xfe, 0xa0, 0xa8, 0x3c, 0x1e, 0xd5, 0xe2, 0x07, 0x9e, 0x1f, 0xf8, 0x85, 0x6f, 0x02, 0xb3, 0xc9, + 0xd4, 0x3b, 0xfb, 0x26, 0xaf, 0x98, 0x7a, 0x8d, 0xe7, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xdd, 0xc8, 0x89, + 0x76, 0xaa, 0x30, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, 0x96, 0x78, + 0x96, 0x2e, 0xaf, 0x27, 0x75, 0xb9, 0xd7, 0x8a, 0xa7, 0x03, 0xb0, 0xb8, 0x6d, 0xc0, 0x0b, 0xe0, 0xde, 0x62, 0xeb, + 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, 0x42, 0x30, + 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, 0x77, 0xf9, + 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0xe5, 0x60, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, 0x52, 0x3c, + 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfd, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xb3, 0x7b, 0x72, 0x65, + 0x20, 0x81, 0xa6, 0x03, 0xe0, 0x21, 0x54, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, 0x05, 0xf7, + 0xe9, 0xa7, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa7, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x2a, 0xfb, 0xa6, + 0x02, 0x2a, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, 0x53, 0x71, + 0x73, 0xad, 0xd3, 0xc5, 0xf3, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, 0x07, 0xf1, + 0xb6, 0xb6, 0xa7, 0x3f, 0xf6, 0x10, 0xe9, 0x78, 0x20, 0x17, 0xea, 0x6b, 0x48, 0x25, 0x17, 0xea, 0x06, 0x62, 0x17, + 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0xdb, 0x1a, 0x05, 0x2b, 0x01, 0x67, 0xda, 0x5b, 0x30, 0xd8, 0xc0, 0xba, 0x65, + 0x19, 0xfc, 0x0d, 0xd7, 0x34, 0x81, 0x1b, 0x16, 0x59, 0xef, 0x0d, 0xb6, 0xd2, 0x5b, 0x70, 0xb4, 0x4c, 0x9c, 0x4b, + 0x49, 0x56, 0xb6, 0xc8, 0xb8, 0x7a, 0x14, 0x52, 0x35, 0x3d, 0xdc, 0x89, 0xfa, 0x41, 0x88, 0x3c, 0x58, 0xa7, 0x2c, + 0x2a, 0xd6, 0x20, 0xb3, 0x07, 0x7f, 0x0f, 0x19, 0x39, 0xca, 0x81, 0xa3, 0xd0, 0x5f, 0x9a, 0x40, 0xe7, 0xf9, 0x29, + 0xd4, 0x79, 0x24, 0xd8, 0x4a, 0x3d, 0x14, 0x56, 0x5e, 0x40, 0x74, 0xb0, 0x85, 0xb1, 0xdc, 0x93, 0x50, 0xb1, 0x29, + 0x13, 0x79, 0x1c, 0xd4, 0x12, 0x30, 0x56, 0x10, 0xcc, 0x59, 0x25, 0x5d, 0x90, 0xf2, 0x46, 0x0f, 0x8b, 0xcc, 0xfd, + 0x9d, 0xa0, 0xfc, 0xdf, 0xa9, 0x9c, 0x70, 0x7d, 0x19, 0x02, 0x1c, 0xed, 0x77, 0x20, 0x4a, 0x8c, 0xf5, 0x8b, 0x16, + 0xef, 0x64, 0xe6, 0x6c, 0x6a, 0x07, 0x09, 0x32, 0xb6, 0xc7, 0xaf, 0x10, 0x5a, 0x2d, 0x14, 0x59, 0x34, 0x5c, 0x30, + 0xdd, 0x9e, 0xd2, 0xaa, 0x7b, 0xd8, 0xf0, 0xac, 0xf4, 0x50, 0xa9, 0x6f, 0x63, 0x02, 0xcb, 0x2a, 0x65, 0xf8, 0x76, + 0x42, 0xd5, 0x89, 0x41, 0xc5, 0xba, 0x65, 0x4b, 0x38, 0xc4, 0x62, 0xd2, 0x58, 0x67, 0x03, 0x1e, 0xb1, 0x04, 0xfe, + 0xd9, 0xf2, 0x31, 0x5b, 0xf2, 0x68, 0xb2, 0xbd, 0x59, 0xf6, 0xfb, 0xa5, 0x17, 0x7a, 0xf5, 0x2c, 0xfb, 0x2e, 0x9a, + 0xcf, 0xaa, 0xb9, 0x8f, 0x8a, 0x8b, 0xc9, 0x60, 0xb0, 0xf5, 0xb3, 0xe1, 0x90, 0x25, 0xc3, 0xe1, 0x24, 0xfb, 0x0e, + 0x5e, 0xfb, 0x8e, 0x47, 0x6a, 0x49, 0x25, 0x37, 0x19, 0xec, 0xef, 0x03, 0x1e, 0xf9, 0xac, 0xf3, 0xd3, 0xb2, 0xe9, + 0xd2, 0xfd, 0xcc, 0x8e, 0xbb, 0xd0, 0x1d, 0x60, 0xe3, 0x6d, 0x83, 0x8e, 0xfc, 0xeb, 0x1d, 0x52, 0xea, 0x26, 0x03, + 0xb0, 0x1b, 0x0d, 0x70, 0xc8, 0x54, 0x2f, 0x45, 0x56, 0x2f, 0x65, 0xaa, 0x97, 0x64, 0xe5, 0x12, 0x2c, 0x24, 0xa6, + 0xca, 0x6d, 0x65, 0xe5, 0x96, 0x0d, 0xd7, 0xc3, 0xc1, 0x36, 0x8a, 0xcb, 0x66, 0x05, 0xf7, 0x85, 0x35, 0x05, 0xfe, + 0xdf, 0xb1, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x5b, 0x74, 0x4c, 0x82, 0x0b, 0xc4, 0x3d, 0xbb, 0x03, 0x3b, 0x2c, 0xfc, + 0x05, 0xd7, 0xc9, 0x31, 0xdb, 0xe3, 0xa3, 0xd0, 0x2b, 0xd8, 0x9d, 0x4f, 0x40, 0xbb, 0x60, 0x6b, 0x80, 0x6c, 0x6c, + 0x87, 0x8f, 0x56, 0xc7, 0xe3, 0x5b, 0xcf, 0x67, 0x0f, 0xf8, 0xe3, 0x72, 0x75, 0x3c, 0xee, 0x3d, 0xa3, 0xde, 0xbb, + 0xe5, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xed, 0x0d, 0x8f, 0x27, 0x83, 0xc1, 0xad, 0xbf, 0xe0, 0xf5, 0xec, 0x16, 0xb4, + 0x03, 0x97, 0x0b, 0xa9, 0x6b, 0xf6, 0xee, 0x78, 0xe6, 0x2d, 0x70, 0x6c, 0xee, 0xe0, 0xe8, 0xed, 0xf7, 0xbd, 0x15, + 0x8f, 0xbc, 0x3b, 0x52, 0x31, 0xad, 0xb9, 0xe2, 0x78, 0xdb, 0xe1, 0x7e, 0xba, 0xe6, 0x21, 0x3c, 0xc2, 0xaa, 0x4c, + 0x6f, 0x83, 0xf7, 0x3e, 0x5b, 0x6b, 0x16, 0xb8, 0x07, 0xcc, 0xb1, 0x21, 0x3b, 0xa1, 0x99, 0xf8, 0x6b, 0xec, 0x9f, + 0x5b, 0xd5, 0x3f, 0x34, 0xff, 0x4b, 0xdd, 0x4f, 0xe0, 0xf6, 0x45, 0x16, 0x24, 0xf6, 0x9e, 0xdf, 0xb2, 0x7b, 0x6e, + 0xd8, 0x66, 0x2f, 0x4c, 0xd9, 0x67, 0x4a, 0x8d, 0x1f, 0x29, 0x75, 0x63, 0x19, 0x56, 0x32, 0x77, 0x5f, 0x46, 0xe0, + 0x70, 0x40, 0x7e, 0x5a, 0x21, 0x0e, 0x42, 0xeb, 0x26, 0xab, 0xb9, 0xa2, 0x9c, 0x0b, 0x6d, 0x99, 0x79, 0x15, 0xb0, + 0x98, 0xa5, 0x14, 0x1a, 0x0b, 0x00, 0x04, 0x93, 0x42, 0x6b, 0xef, 0x65, 0x00, 0x39, 0x41, 0xc3, 0x9f, 0x9a, 0xab, + 0xa2, 0xac, 0x65, 0x4b, 0x42, 0x94, 0xed, 0x7a, 0x78, 0x8d, 0x90, 0x69, 0xfd, 0xfe, 0x25, 0x91, 0xac, 0x4d, 0xf2, + 0x9b, 0x1a, 0x2d, 0x01, 0x39, 0x59, 0x02, 0x26, 0x7e, 0xae, 0xf9, 0x04, 0xe0, 0x49, 0xc7, 0x83, 0xfc, 0x3b, 0x5e, + 0x33, 0x41, 0x64, 0x1b, 0xb9, 0x3f, 0x29, 0x9e, 0x23, 0x19, 0x41, 0xf1, 0x5d, 0xad, 0x32, 0x16, 0x86, 0x79, 0xa0, + 0x80, 0xbc, 0x07, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, 0xe8, + 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x3d, 0x89, 0x6e, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, 0x67, + 0xd1, 0x77, 0xf9, 0x7c, 0x42, 0x4a, 0xb2, 0xe3, 0x31, 0x1b, 0x55, 0x75, 0xb1, 0x99, 0x86, 0xf2, 0xa7, 0x87, 0xe0, + 0xeb, 0x05, 0xf5, 0x9a, 0xac, 0x52, 0xfd, 0x1d, 0x55, 0xca, 0x8b, 0x86, 0xd7, 0xfe, 0x77, 0xb9, 0xdc, 0xf7, 0x80, + 0xb4, 0x96, 0x97, 0x5c, 0xbe, 0x1f, 0x21, 0xc6, 0x88, 0x1f, 0x78, 0x25, 0x8f, 0x58, 0xa8, 0xa6, 0x70, 0xcd, 0x23, + 0x04, 0x79, 0xcb, 0x74, 0xf0, 0xb7, 0x9e, 0x38, 0xdd, 0x9f, 0x28, 0xed, 0xe2, 0x0b, 0x8b, 0xba, 0x27, 0x6b, 0xeb, + 0x06, 0xe4, 0x60, 0xc3, 0x74, 0x51, 0x90, 0x6d, 0x4a, 0x23, 0x68, 0xa3, 0xe5, 0xc0, 0x86, 0x93, 0xab, 0x0d, 0x67, + 0xae, 0x21, 0xb8, 0x2f, 0x2f, 0xd3, 0xd1, 0x02, 0x3e, 0xa4, 0xba, 0xbd, 0xc4, 0xcf, 0x87, 0x0d, 0x8f, 0x80, 0xcc, + 0x8e, 0xf8, 0xcc, 0x26, 0x92, 0x4e, 0xea, 0x52, 0x01, 0xbb, 0x5d, 0xbc, 0x05, 0x39, 0x62, 0xe6, 0xbe, 0x42, 0xf5, + 0x2d, 0x1a, 0x70, 0x65, 0xac, 0x7d, 0x4d, 0x32, 0x16, 0xde, 0x94, 0xd3, 0x70, 0x90, 0xc3, 0x73, 0xfa, 0xda, 0x72, + 0x9b, 0x65, 0x3f, 0x17, 0x10, 0x04, 0x51, 0x12, 0x8f, 0x0f, 0x78, 0x5f, 0xe6, 0x43, 0x8d, 0x92, 0x8f, 0x65, 0x23, + 0x95, 0x5e, 0x89, 0xfe, 0x6e, 0xcc, 0x25, 0x06, 0x7c, 0x9b, 0xb7, 0x05, 0x85, 0xcb, 0xea, 0x78, 0xbc, 0xac, 0x46, + 0xc6, 0xb3, 0x0c, 0x54, 0x2b, 0xd3, 0x3a, 0x88, 0xcd, 0x7c, 0xb1, 0xf0, 0x17, 0x3b, 0x27, 0x11, 0x51, 0x10, 0xd8, + 0x91, 0xf0, 0x20, 0x52, 0xbf, 0xcc, 0x3d, 0xdd, 0xa9, 0x3e, 0x3b, 0x2c, 0x6c, 0x22, 0xbd, 0xa0, 0x64, 0xf2, 0x49, + 0x70, 0x50, 0xfd, 0x1d, 0x84, 0x0d, 0xe1, 0xcd, 0xab, 0x5e, 0x67, 0x99, 0x9a, 0x95, 0x20, 0x61, 0xc6, 0x1c, 0xc1, + 0xe3, 0xb0, 0xd3, 0xd8, 0x96, 0xc7, 0x16, 0x1c, 0x9d, 0xb7, 0x61, 0x2b, 0xb6, 0x66, 0x77, 0xaa, 0x4e, 0x0b, 0x1e, + 0x4e, 0x87, 0xd7, 0x01, 0xae, 0xbe, 0xcd, 0x25, 0xe7, 0x2b, 0x3a, 0xc1, 0x36, 0x03, 0x1e, 0x4d, 0xc4, 0x6c, 0xf3, + 0x5d, 0xa4, 0x16, 0xcf, 0x66, 0xc8, 0x17, 0xb4, 0xfe, 0xc4, 0x6c, 0x65, 0x92, 0x57, 0x03, 0xbe, 0x98, 0x6c, 0xbe, + 0x8b, 0xe0, 0xd5, 0xef, 0xc0, 0x8a, 0x91, 0x39, 0xb3, 0x6c, 0xf3, 0x5d, 0x84, 0x63, 0xb6, 0xfa, 0x2e, 0xa2, 0x51, + 0x5b, 0xcb, 0x7d, 0xe9, 0xae, 0x01, 0x61, 0xe5, 0x8e, 0xc5, 0xf0, 0x1a, 0x88, 0x67, 0xda, 0x48, 0xba, 0x91, 0x86, + 0xde, 0x98, 0x87, 0xd3, 0x38, 0xd8, 0x50, 0x2b, 0xe4, 0x99, 0x21, 0x66, 0xf1, 0x77, 0xd1, 0x9c, 0xad, 0xb1, 0x22, + 0x5b, 0x1e, 0x0f, 0xae, 0x27, 0xdb, 0x1b, 0xbe, 0x01, 0xf2, 0xb3, 0xc9, 0xd6, 0x6c, 0x51, 0x77, 0x5c, 0xcc, 0xb6, + 0xdf, 0x45, 0xf3, 0xc9, 0x1a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x35, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, 0x3d, + 0xb6, 0x19, 0x07, 0x2b, 0xb6, 0xb9, 0x0e, 0xee, 0xd8, 0x66, 0x0c, 0x44, 0x1c, 0xd4, 0xef, 0xde, 0x16, 0x16, 0x5f, + 0xc4, 0x36, 0xd7, 0x26, 0x6d, 0xfb, 0x5d, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xcd, 0xbc, 0x35, 0x83, 0x4b, + 0xc8, 0xd2, 0x8b, 0xd9, 0x76, 0x78, 0xcd, 0x36, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0x56, 0xfc, 0x8e, 0x25, 0x7c, 0xdd, + 0xc4, 0x37, 0x5b, 0xd0, 0x88, 0x9e, 0x64, 0xd0, 0x57, 0x50, 0x33, 0x73, 0x5e, 0x5a, 0x50, 0xb9, 0x87, 0x16, 0x1c, + 0x50, 0x90, 0xb6, 0x01, 0x82, 0x24, 0x9e, 0xdd, 0xcb, 0x70, 0x73, 0x2b, 0x85, 0x01, 0x37, 0x81, 0x19, 0x30, 0x30, + 0xfd, 0x0c, 0x7e, 0x58, 0xe9, 0x12, 0x21, 0xce, 0x7e, 0x4a, 0x49, 0x32, 0xcf, 0x4f, 0x45, 0x9a, 0xbb, 0x85, 0xeb, + 0x14, 0x66, 0x45, 0x81, 0xea, 0xa7, 0xa4, 0x34, 0xb0, 0x50, 0x89, 0x4c, 0xa5, 0xe0, 0x97, 0xcd, 0x79, 0x94, 0x9d, + 0xa2, 0x73, 0x5d, 0x5e, 0x4f, 0x9c, 0xd3, 0x49, 0xdf, 0x7f, 0xe0, 0x18, 0xb6, 0x90, 0x81, 0x0b, 0x7f, 0xea, 0x09, + 0xe3, 0xd4, 0x0a, 0xc4, 0x54, 0xf2, 0xec, 0x29, 0x7c, 0x26, 0xb4, 0x3a, 0xba, 0xf0, 0xfd, 0xa0, 0xd0, 0x26, 0xe9, + 0x16, 0x24, 0x29, 0x78, 0x8a, 0x5e, 0x72, 0xde, 0x06, 0x2a, 0xc5, 0x88, 0x16, 0x44, 0xda, 0x5a, 0x66, 0x0e, 0xd2, + 0x96, 0xe6, 0xbb, 0x26, 0x7e, 0x0e, 0x0b, 0xb8, 0x88, 0x16, 0x76, 0xa5, 0xe0, 0x51, 0x15, 0x2b, 0xf7, 0x36, 0xcf, + 0x11, 0xce, 0xe8, 0x5a, 0x26, 0x00, 0xae, 0xf7, 0xab, 0xb0, 0x56, 0x78, 0x45, 0xcd, 0x22, 0x2f, 0x6a, 0xfa, 0x64, + 0x0b, 0xdc, 0xc7, 0xa2, 0x44, 0x81, 0xb3, 0x16, 0x0c, 0xd8, 0x0a, 0x4b, 0x76, 0x52, 0xd8, 0x14, 0x2d, 0xa1, 0x77, + 0xc0, 0x4f, 0x07, 0x35, 0x93, 0x01, 0x34, 0x01, 0x34, 0x1e, 0xff, 0x02, 0x50, 0xd3, 0xdb, 0x5a, 0x6c, 0xaa, 0xa0, + 0x54, 0xca, 0x4d, 0xf8, 0x19, 0x18, 0x66, 0xf8, 0xa1, 0x90, 0xdb, 0x44, 0x89, 0x9c, 0x1f, 0x8b, 0x52, 0x2c, 0x4b, + 0x51, 0x25, 0xed, 0x86, 0x82, 0x47, 0x84, 0xdb, 0xa0, 0x31, 0x73, 0x7b, 0xa2, 0x8b, 0x56, 0x84, 0x72, 0x6c, 0x37, + 0x31, 0xd2, 0x28, 0xb3, 0xb3, 0x5d, 0x27, 0x0b, 0xed, 0xf7, 0x55, 0x0e, 0x59, 0x07, 0xac, 0x91, 0x7c, 0xbd, 0xe6, + 0xd0, 0x6d, 0xa3, 0xbc, 0x78, 0xf0, 0x7c, 0x05, 0xa7, 0x39, 0x9e, 0xd8, 0x5d, 0xaf, 0x3b, 0x45, 0x22, 0x5e, 0xe1, + 0xa4, 0xaa, 0x46, 0xb2, 0x70, 0xdc, 0xb9, 0xd3, 0x5a, 0xac, 0x95, 0x4c, 0xe3, 0x72, 0xd0, 0x00, 0xd0, 0x0c, 0x3e, + 0x95, 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, + 0x11, 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0xf3, 0x4a, + 0x0f, 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, + 0x3c, 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, + 0x5d, 0x28, 0xe7, 0x4c, 0xce, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, + 0x8c, 0x4e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x56, 0xa9, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, + 0xc6, 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, + 0x94, 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x07, 0x59, 0x14, 0x38, 0x80, + 0xab, 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0x0e, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, + 0xcc, 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, + 0xb4, 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x4f, 0x5f, + 0xa7, 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7d, 0x41, 0x11, 0x17, 0x35, 0xb8, + 0xf2, 0xce, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, + 0x0e, 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x46, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xac, 0x58, 0x3e, 0x5a, 0xa8, 0xcc, + 0x08, 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xd3, 0x3d, 0xba, 0xab, 0xce, + 0x32, 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, + 0x77, 0x9d, 0xe5, 0x5b, 0xa9, 0x66, 0x6b, 0x28, 0x2a, 0xb5, 0x92, 0x14, 0x07, 0x19, 0xae, 0xdb, 0xdc, 0x87, 0xcd, + 0x14, 0xf4, 0x8c, 0x91, 0xc8, 0x3c, 0x7f, 0x22, 0x5f, 0x82, 0x73, 0xc6, 0x59, 0x21, 0x30, 0x61, 0xac, 0xde, 0xb5, + 0x96, 0x4a, 0x43, 0x8a, 0xb1, 0x93, 0x51, 0x96, 0x55, 0x96, 0x2e, 0xb3, 0xb5, 0x84, 0x2d, 0xab, 0xc8, 0x2d, 0x6c, + 0x99, 0xc9, 0x6a, 0xbe, 0xcf, 0xb9, 0x83, 0xf2, 0xcd, 0x36, 0x19, 0x3f, 0x48, 0x64, 0xef, 0x36, 0x50, 0xc2, 0xf3, + 0xd1, 0x7f, 0x20, 0xfd, 0x36, 0xc3, 0x38, 0xe5, 0xb6, 0x92, 0x16, 0xe0, 0xf4, 0x8f, 0xc7, 0xf7, 0x39, 0x06, 0x0d, + 0x8e, 0x30, 0x8e, 0xac, 0xdf, 0xbf, 0xcb, 0xbd, 0x1a, 0x13, 0x75, 0xf4, 0x42, 0xbf, 0x9f, 0xd3, 0xc3, 0x69, 0x3e, + 0x5a, 0xa7, 0x3b, 0x64, 0x27, 0xb4, 0xb1, 0xf2, 0x83, 0x5a, 0x01, 0xb3, 0xb7, 0x3e, 0x9f, 0x0e, 0x40, 0xc7, 0x02, + 0x24, 0x9a, 0xcd, 0x44, 0x62, 0x4e, 0xba, 0x27, 0xe1, 0xe9, 0x81, 0x05, 0x0e, 0x30, 0x39, 0xff, 0x87, 0xf0, 0x66, + 0x60, 0x83, 0x46, 0x89, 0xbe, 0x46, 0x57, 0xb5, 0xb9, 0xd1, 0xf1, 0xd2, 0x53, 0x48, 0x64, 0x05, 0xcb, 0xe7, 0xbe, + 0xdc, 0xc0, 0x69, 0x0f, 0x35, 0x87, 0xca, 0x12, 0x3c, 0x3d, 0x97, 0xf9, 0xf1, 0xb8, 0xc9, 0xa0, 0xb0, 0xfd, 0x46, + 0x68, 0x6f, 0xcc, 0x52, 0x0d, 0x15, 0xe1, 0xa0, 0xf3, 0xb5, 0x98, 0xd5, 0x23, 0xfa, 0x7b, 0x7e, 0x3c, 0xae, 0x09, + 0x0c, 0x38, 0x2c, 0x65, 0x26, 0x5a, 0x28, 0x96, 0xd6, 0xd9, 0x8c, 0xea, 0xc0, 0x03, 0x13, 0x73, 0x16, 0xee, 0x01, + 0xb4, 0x49, 0xad, 0x02, 0xbd, 0x8a, 0xe8, 0x27, 0xee, 0xd7, 0xf6, 0xeb, 0xf5, 0xc8, 0x2c, 0x1d, 0xb9, 0x31, 0x16, + 0x00, 0x1c, 0x78, 0x59, 0x93, 0x3c, 0x27, 0x5f, 0x43, 0xbb, 0x27, 0x17, 0xf2, 0x27, 0x28, 0x5b, 0x78, 0xa5, 0x9a, + 0x56, 0x16, 0x6b, 0xae, 0xaa, 0x57, 0x17, 0x3c, 0x37, 0x99, 0xd6, 0x69, 0x25, 0x54, 0xac, 0x5f, 0x43, 0x5d, 0xe2, + 0xb5, 0xa6, 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x79, 0x6d, + 0x1c, 0x3e, 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0xab, 0x1a, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, + 0xc5, 0xc4, 0xee, 0xd0, 0xaa, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, + 0x01, 0x2f, 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x72, 0x26, + 0xc0, 0x0f, 0x4a, 0xad, 0xe9, 0x83, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, + 0xe7, 0xe3, 0xe5, 0xb5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x55, 0xab, 0x7f, 0x98, 0xea, 0x5b, + 0xe8, 0x4e, 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, + 0x1c, 0xec, 0x0d, 0x70, 0xe2, 0x97, 0xc7, 0xa3, 0xb8, 0xa9, 0x7c, 0x76, 0xd9, 0x35, 0xb2, 0x72, 0x00, 0x73, 0x88, + 0x82, 0x71, 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xcd, 0xf8, 0xf4, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0x55, + 0xdf, 0x3d, 0x03, 0xd2, 0xb2, 0x7e, 0x3f, 0x7a, 0x7e, 0x3d, 0x7d, 0x36, 0x8c, 0x02, 0x70, 0xec, 0xb2, 0x97, 0x97, + 0x31, 0x5f, 0x5d, 0x33, 0xcb, 0x14, 0x16, 0xf9, 0x66, 0x40, 0x75, 0xc9, 0x6a, 0xe9, 0x7a, 0x05, 0x58, 0xba, 0xfc, + 0xe6, 0x21, 0x4c, 0x0d, 0x68, 0x64, 0xcd, 0xdd, 0x69, 0xae, 0x05, 0x4a, 0x3d, 0xef, 0x67, 0x86, 0x7c, 0x5d, 0x06, + 0x5d, 0x41, 0xba, 0xe7, 0x11, 0xe9, 0xe5, 0x41, 0x3a, 0xdd, 0x1f, 0x4a, 0x01, 0x96, 0xfa, 0x52, 0x7c, 0x06, 0x85, + 0x45, 0xe3, 0x1b, 0x01, 0xda, 0x1a, 0xaa, 0x69, 0xaf, 0x14, 0x55, 0x2f, 0xe8, 0x95, 0xe2, 0x73, 0x4f, 0x0f, 0x95, + 0xf9, 0xb2, 0x74, 0xf4, 0x3f, 0xa3, 0xe6, 0x82, 0x13, 0x62, 0x26, 0xe6, 0x00, 0x2a, 0x41, 0x1b, 0xdf, 0xfa, 0x64, + 0xe3, 0x53, 0xbd, 0x8a, 0x9b, 0x3e, 0xaf, 0xad, 0x65, 0x4e, 0x08, 0x9b, 0xee, 0x25, 0x40, 0x45, 0x5e, 0x09, 0x8f, + 0x60, 0xf9, 0xe5, 0x0f, 0x79, 0xba, 0x42, 0xb4, 0x8e, 0x7b, 0x96, 0xb9, 0x34, 0xf6, 0xaf, 0x0d, 0xa6, 0xaf, 0x6f, + 0xb7, 0x45, 0x7e, 0x6a, 0x62, 0xc2, 0x7a, 0xac, 0xe8, 0x9b, 0x77, 0xe1, 0x5a, 0xa0, 0xc0, 0xa1, 0x44, 0x62, 0x9b, + 0x2a, 0x14, 0xf1, 0x20, 0xe9, 0xd3, 0x45, 0xeb, 0xd3, 0x00, 0x53, 0x6b, 0x39, 0x30, 0x87, 0x70, 0x15, 0x17, 0x3e, + 0x7a, 0xfa, 0x16, 0xb3, 0x70, 0x3e, 0xf1, 0x3e, 0x7a, 0xc5, 0xc8, 0x7c, 0xdc, 0x47, 0xa5, 0x92, 0xfe, 0x79, 0x3c, + 0xce, 0xf2, 0xb9, 0xef, 0xd0, 0x47, 0x7a, 0xa8, 0x72, 0x41, 0xd9, 0x1b, 0x63, 0x12, 0x81, 0xd2, 0x18, 0xef, 0xe3, + 0xe0, 0x38, 0xef, 0xd3, 0x00, 0x52, 0xfb, 0xc4, 0x7b, 0x52, 0x72, 0x78, 0xce, 0x31, 0x27, 0x94, 0x56, 0x84, 0xe5, + 0x7c, 0x91, 0xa1, 0x5c, 0x77, 0x4e, 0xc1, 0x24, 0x87, 0x04, 0xc3, 0x5f, 0x35, 0x6f, 0x62, 0x05, 0xc2, 0xae, 0x91, + 0x33, 0x47, 0x4f, 0xaa, 0x24, 0x2c, 0x05, 0x1c, 0x95, 0x99, 0x67, 0xd8, 0x1b, 0x9e, 0x18, 0x46, 0x0e, 0x56, 0xf9, + 0xa3, 0x3a, 0x11, 0xb9, 0x47, 0x17, 0x18, 0x95, 0x85, 0x57, 0x0d, 0x5d, 0x69, 0x50, 0x49, 0x76, 0xfa, 0x15, 0xd7, + 0x80, 0xda, 0x1a, 0x23, 0x96, 0x83, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, + 0x95, 0xdc, 0xf5, 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, + 0x2c, 0x85, 0x23, 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, + 0x42, 0x9a, 0x6c, 0x5f, 0xcf, 0x3f, 0xe4, 0x5a, 0x90, 0x95, 0x5b, 0xce, 0xe9, 0xb0, 0xf8, 0xc6, 0xd9, 0x57, 0x39, + 0x79, 0x8a, 0x59, 0x46, 0x7a, 0xa7, 0x98, 0x17, 0xf0, 0xa7, 0xb2, 0xd4, 0x93, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, + 0x97, 0xde, 0xb6, 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0x0f, 0xf1, 0x48, 0x9e, 0x61, 0x5b, 0x96, 0xb0, 0xd0, 0x2a, + 0x18, 0x03, 0x48, 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x8f, 0xc7, 0xcb, 0xad, 0x39, 0x4b, 0x0e, 0xe0, 0xfa, 0xca, + 0x13, 0xf3, 0x0e, 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x5b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, + 0x62, 0xad, 0x63, 0xc9, 0xad, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0x7f, 0x70, 0x83, 0xab, + 0x6b, 0x63, 0x50, 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0x8b, 0x8a, 0x7c, 0xf9, 0xad, + 0x9d, 0x03, 0x82, 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, + 0x33, 0xd8, 0xc4, 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, + 0xab, 0x85, 0x48, 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, + 0x41, 0x27, 0x68, 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, + 0x07, 0x99, 0x13, 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, + 0x74, 0x28, 0x59, 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, + 0x0a, 0x5c, 0x08, 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xd5, 0xb4, 0x90, 0xa6, 0x81, 0x6a, + 0x9a, 0x3b, 0xe6, 0x81, 0xbd, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0x55, 0xfc, 0x83, 0x74, 0x2f, 0xce, + 0xe1, 0x2f, 0x6b, 0xfa, 0x20, 0xc2, 0x46, 0x0e, 0x1a, 0x4b, 0x89, 0xb1, 0x51, 0xe1, 0xdf, 0x12, 0x65, 0x43, 0x86, + 0x80, 0x10, 0xd2, 0x46, 0x45, 0x3f, 0xac, 0x2f, 0xef, 0x32, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, + 0xa9, 0x47, 0x3c, 0x5e, 0x1b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, + 0x28, 0x17, 0xbc, 0xe2, 0x39, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xa8, 0xe8, 0xf3, 0x39, 0xf0, 0x4c, + 0x40, 0xa0, 0x63, 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0xb7, 0x48, + 0x94, 0xfa, 0x8a, 0x94, 0xa4, 0x6f, 0x45, 0x8d, 0x57, 0x62, 0x15, 0x91, 0x40, 0x86, 0x1a, 0x22, 0x56, 0xd5, 0x53, + 0xf7, 0xa6, 0x98, 0x0c, 0x06, 0xb9, 0x2f, 0xa7, 0x27, 0xde, 0xd0, 0x50, 0x79, 0xd7, 0x15, 0xed, 0xf4, 0x44, 0x2b, + 0xe5, 0x2d, 0xa4, 0x25, 0x68, 0x1a, 0x46, 0x9a, 0x43, 0xa9, 0x6b, 0xe9, 0x6e, 0x0c, 0xe2, 0x4b, 0x26, 0x7a, 0xb6, + 0x53, 0x3b, 0x4a, 0x5b, 0xd2, 0x1e, 0x42, 0x7a, 0xee, 0x92, 0x8f, 0x21, 0x42, 0x4c, 0x55, 0xa5, 0xbc, 0x09, 0xd1, + 0xc9, 0xfd, 0x80, 0x21, 0x11, 0xe8, 0x73, 0x8e, 0x61, 0x5d, 0x34, 0xd4, 0x18, 0x6c, 0x6d, 0xb6, 0x50, 0xc2, 0x7c, + 0xc9, 0x78, 0x2a, 0x19, 0x34, 0x00, 0x32, 0xe0, 0xb3, 0x97, 0x81, 0xe5, 0xaf, 0x20, 0x7e, 0xb4, 0xf1, 0xf1, 0xf8, + 0x67, 0x4d, 0x21, 0xb6, 0x7f, 0xc2, 0x66, 0x08, 0x8f, 0xea, 0x01, 0xcf, 0x7c, 0x13, 0x27, 0x68, 0x05, 0x24, 0x65, + 0x76, 0x34, 0x91, 0xbd, 0xea, 0x21, 0x9c, 0xca, 0x0a, 0xd4, 0x51, 0xd6, 0x59, 0x09, 0x3f, 0xc2, 0x54, 0xb7, 0x12, + 0x6b, 0x81, 0x36, 0x57, 0x2b, 0xd6, 0x02, 0x38, 0xf0, 0x2b, 0x08, 0x9e, 0xa8, 0xe6, 0xe0, 0x62, 0x50, 0x80, 0xcf, + 0x01, 0xf0, 0x22, 0x77, 0xe1, 0xc1, 0x3c, 0xb2, 0xac, 0x46, 0x18, 0x8e, 0x2a, 0x62, 0xfd, 0x9a, 0xed, 0xc8, 0x07, + 0x6e, 0xc7, 0xf8, 0x5c, 0x7b, 0x2c, 0x59, 0x0e, 0x46, 0x99, 0x7b, 0xb5, 0x44, 0xcf, 0x9b, 0x34, 0x6e, 0x46, 0x4f, + 0x0e, 0xb5, 0xfc, 0x5f, 0xd0, 0xcb, 0xa0, 0xbf, 0x85, 0x5b, 0x5e, 0xf3, 0xbb, 0x05, 0x91, 0x66, 0x7a, 0x05, 0x91, + 0x32, 0x6a, 0x44, 0xc6, 0x10, 0x36, 0xa9, 0x6e, 0x65, 0x93, 0xea, 0x42, 0xc0, 0xd3, 0x09, 0xa9, 0xae, 0x85, 0xb4, + 0x51, 0x4d, 0xeb, 0x40, 0xc6, 0x22, 0xbd, 0xfb, 0xf1, 0x2f, 0x2f, 0x3e, 0xbd, 0xf9, 0xe5, 0xc7, 0xc5, 0x9b, 0x77, + 0xaf, 0xdf, 0xbc, 0x7b, 0xf3, 0xe9, 0x37, 0x82, 0xf0, 0x98, 0x0a, 0x95, 0xe1, 0xc3, 0xfb, 0xdb, 0x37, 0x4e, 0x06, + 0xdb, 0x9b, 0x21, 0x6b, 0xdf, 0xc8, 0xc1, 0x10, 0x88, 0x6c, 0x10, 0x32, 0xc8, 0x4e, 0x6d, 0xfb, 0x33, 0x31, 0xc7, + 0xd8, 0x3b, 0x81, 0xc9, 0x16, 0x24, 0x87, 0x65, 0x5e, 0x32, 0x22, 0x57, 0x8e, 0xd6, 0x0f, 0x68, 0xc1, 0x5b, 0x70, + 0x91, 0x49, 0xf3, 0xd5, 0x2f, 0x04, 0xb1, 0x4f, 0x2b, 0xa9, 0xf2, 0xd5, 0xb6, 0xe6, 0xf9, 0xf6, 0x7e, 0x9f, 0xd3, + 0x8a, 0x99, 0x4b, 0x23, 0x6a, 0x01, 0x0e, 0xc0, 0x97, 0xf0, 0xc7, 0x8d, 0xb6, 0xa4, 0xc9, 0x2c, 0xfa, 0x2c, 0x84, + 0xa0, 0x4b, 0x03, 0x69, 0x62, 0x8f, 0xbc, 0xd4, 0x27, 0x0b, 0x09, 0xdc, 0x11, 0xc3, 0xa7, 0x15, 0x41, 0xaf, 0x18, + 0x51, 0x5c, 0x72, 0x85, 0x4a, 0x29, 0xf9, 0x37, 0xca, 0x2e, 0x2a, 0xe4, 0xac, 0x60, 0xf7, 0x8a, 0x1c, 0x19, 0x3f, + 0x08, 0x26, 0xbe, 0x0a, 0xdc, 0x7f, 0x89, 0x77, 0x38, 0x53, 0x1c, 0xc9, 0x09, 0x7f, 0xc8, 0x30, 0xb0, 0xbf, 0x02, + 0x9f, 0x57, 0x87, 0x79, 0x79, 0xab, 0x4f, 0xb9, 0x25, 0x1f, 0x4f, 0x96, 0x37, 0x60, 0xb0, 0x5f, 0xaa, 0xe6, 0x6e, + 0x78, 0x3d, 0x5b, 0xce, 0xd9, 0x61, 0x16, 0xcd, 0x83, 0x15, 0x9b, 0x65, 0xf3, 0x60, 0xdd, 0xf0, 0x0d, 0xbb, 0xe3, + 0x1b, 0xab, 0x6a, 0x1b, 0xbb, 0x6a, 0x93, 0x2d, 0xbf, 0x03, 0x09, 0xe1, 0x36, 0xf3, 0x72, 0x96, 0xb0, 0x95, 0xcf, + 0xb6, 0x20, 0xd1, 0xae, 0xd9, 0x16, 0x2e, 0x62, 0x1b, 0xfe, 0x63, 0xee, 0x6d, 0x59, 0xc9, 0x2e, 0xc7, 0xac, 0xc2, + 0xf9, 0xe7, 0xc3, 0x03, 0xda, 0x0b, 0xf5, 0xb3, 0x6b, 0xf5, 0x6c, 0xa2, 0xec, 0x66, 0xdb, 0xd1, 0xe2, 0x3e, 0xad, + 0xb6, 0x61, 0x86, 0x9e, 0xe5, 0xf0, 0xd1, 0x56, 0x0a, 0x7e, 0x7a, 0x81, 0x5f, 0xb2, 0xa3, 0xb6, 0xd2, 0xb6, 0x5d, + 0x95, 0xd8, 0x0a, 0x5a, 0x14, 0x59, 0xad, 0xf0, 0xc0, 0x8a, 0x3f, 0x87, 0x05, 0x8c, 0x3d, 0xc7, 0x39, 0xaf, 0xfd, + 0x11, 0x32, 0xde, 0x3b, 0x00, 0x68, 0x99, 0xe3, 0x00, 0x8f, 0x58, 0x31, 0x8a, 0x06, 0xef, 0xf2, 0x5a, 0x59, 0xad, + 0x34, 0x27, 0xa1, 0x6d, 0xc4, 0xaa, 0xe5, 0x48, 0xd5, 0x8c, 0x48, 0x1f, 0xa4, 0xe7, 0x7d, 0x8f, 0xa8, 0x06, 0x7b, + 0x32, 0xaf, 0x03, 0xfb, 0xf4, 0xb2, 0xb5, 0xaa, 0x3b, 0xbf, 0xa7, 0x4a, 0x97, 0x1c, 0xd9, 0xf2, 0xd3, 0x65, 0xf8, + 0xa0, 0xfe, 0x94, 0x5c, 0x1f, 0x0a, 0x1c, 0xe1, 0xb1, 0x0a, 0x38, 0x5f, 0xcf, 0x45, 0xbb, 0x13, 0x61, 0x57, 0x2e, + 0x01, 0x21, 0xbe, 0xa4, 0x69, 0x8e, 0xc7, 0x11, 0x4d, 0x44, 0xd8, 0xc4, 0xe8, 0x2f, 0xec, 0x3e, 0x94, 0x58, 0x2e, + 0x2b, 0x0d, 0x4a, 0x2e, 0x19, 0xbc, 0x27, 0xed, 0x35, 0x68, 0x96, 0x57, 0xae, 0x26, 0x13, 0x39, 0x28, 0x1f, 0x8f, + 0x05, 0xec, 0xa5, 0xc6, 0x4f, 0x13, 0x7e, 0xc2, 0xf2, 0xd6, 0xde, 0x9a, 0x52, 0x54, 0xd2, 0x00, 0x15, 0xf8, 0x98, + 0xc1, 0xff, 0xee, 0x0c, 0xb1, 0x60, 0x8a, 0x4e, 0x1f, 0xce, 0xc4, 0xdc, 0x7a, 0x6e, 0x95, 0x75, 0x92, 0xad, 0x51, + 0x4e, 0xc0, 0xbf, 0xa5, 0x3a, 0x4e, 0x12, 0xe1, 0xd4, 0x7b, 0xc4, 0x45, 0xdd, 0xcb, 0x21, 0xea, 0x86, 0xbd, 0xc9, + 0x75, 0xb0, 0xe5, 0x34, 0x0d, 0x4e, 0xc4, 0xaf, 0xd4, 0x67, 0xef, 0x33, 0x8b, 0x47, 0x1d, 0xd9, 0x88, 0x92, 0x34, + 0x8e, 0x45, 0x0e, 0xdb, 0xfb, 0x42, 0xee, 0xff, 0xfd, 0x3e, 0x84, 0x93, 0x56, 0x41, 0x52, 0x7a, 0x02, 0x11, 0xe1, + 0xe8, 0xf0, 0x23, 0xc2, 0x13, 0xa9, 0x2a, 0x7c, 0x52, 0x9f, 0xb9, 0x31, 0xbb, 0x17, 0xe6, 0xa8, 0xde, 0x01, 0x0c, + 0x63, 0xbd, 0xb3, 0x08, 0x49, 0xb4, 0xd2, 0x8c, 0xb6, 0x1e, 0x10, 0x23, 0xde, 0x6f, 0x2c, 0x32, 0x18, 0x6b, 0x4b, + 0x22, 0x01, 0x7c, 0x45, 0x42, 0x86, 0xb6, 0x8d, 0xc0, 0x8c, 0xe1, 0xed, 0xac, 0xb8, 0x74, 0x1d, 0xb6, 0x39, 0x87, + 0x2f, 0x64, 0xa1, 0x59, 0x47, 0x94, 0x26, 0x08, 0xf9, 0x07, 0x9c, 0x2c, 0x14, 0x46, 0xf3, 0xea, 0x24, 0x9d, 0x24, + 0xd6, 0xf7, 0x5d, 0xa5, 0x82, 0xcd, 0xe6, 0x16, 0xf5, 0x65, 0x27, 0xc9, 0x2f, 0xc1, 0x49, 0xc7, 0x49, 0x16, 0x39, + 0x88, 0x5a, 0x54, 0xce, 0x6d, 0x12, 0x96, 0x76, 0x75, 0xaa, 0xed, 0x66, 0x53, 0x94, 0x75, 0xf5, 0x4a, 0x44, 0x8a, + 0xde, 0x47, 0x3d, 0x7a, 0x22, 0x21, 0x15, 0x5a, 0x95, 0xda, 0xe7, 0x11, 0xb8, 0x6d, 0x6a, 0xc5, 0xb6, 0x5c, 0xc2, + 0x12, 0x35, 0xfe, 0x13, 0xf4, 0x51, 0x2e, 0x1e, 0x64, 0x80, 0x46, 0xc7, 0x53, 0xf3, 0xd6, 0x23, 0xaf, 0x9c, 0xe4, + 0x97, 0x56, 0x9b, 0xf4, 0x0b, 0x20, 0x33, 0xda, 0x3f, 0x5a, 0x4a, 0x20, 0x33, 0x30, 0x93, 0x96, 0x86, 0x44, 0x8e, + 0x62, 0x96, 0xe6, 0x7f, 0xe0, 0x8a, 0xad, 0x10, 0x69, 0x58, 0xcd, 0x3d, 0xfe, 0x22, 0xf7, 0x6a, 0xb9, 0x96, 0x99, + 0xe6, 0x66, 0x89, 0x63, 0xc5, 0xe2, 0xa2, 0x5e, 0x57, 0x22, 0x0b, 0x84, 0x38, 0xc2, 0x34, 0xd6, 0x53, 0x6f, 0x94, + 0x56, 0x1f, 0x90, 0x50, 0xe6, 0x47, 0xec, 0xed, 0xd8, 0xeb, 0x41, 0x16, 0xe2, 0xd8, 0x72, 0xb0, 0xd9, 0x7a, 0x9f, + 0xca, 0x54, 0xc4, 0x17, 0x75, 0x71, 0xb1, 0xad, 0xc4, 0x45, 0x9d, 0x88, 0x8b, 0xef, 0x21, 0xe7, 0xf7, 0x17, 0x54, + 0xf4, 0xc5, 0x43, 0x5a, 0x27, 0xc5, 0xb6, 0xa6, 0x27, 0xaf, 0xb1, 0x8c, 0xef, 0x2f, 0x88, 0xab, 0xe6, 0x82, 0x46, + 0x32, 0x1e, 0x5d, 0x7c, 0xc8, 0x80, 0xe4, 0xf5, 0x22, 0x5d, 0xc3, 0xe0, 0x5d, 0x84, 0x79, 0x7c, 0x51, 0x8a, 0x15, + 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x3a, 0xfc, 0x43, 0x5c, 0x00, 0xb4, 0xeb, 0x45, 0x5a, 0x5f, 0xa4, 0xd5, + 0x45, 0x5e, 0xd4, 0x17, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, 0x4f, 0x5f, 0xd9, 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, + 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x72, 0xe1, 0xb5, 0xfb, 0xdb, 0xe6, 0xfe, 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, + 0x46, 0x74, 0x41, 0x3d, 0x5d, 0x49, 0x4a, 0x05, 0x05, 0x04, 0x4e, 0x34, 0x6b, 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, + 0x5b, 0xb2, 0x8d, 0xcf, 0x9f, 0xc7, 0x32, 0x4c, 0x7b, 0x1b, 0xe0, 0x5f, 0x65, 0x6f, 0xba, 0x09, 0x96, 0x78, 0xdf, + 0x42, 0xb6, 0xa1, 0x37, 0xaf, 0xf8, 0x0b, 0xaf, 0x52, 0x7f, 0xb3, 0x7f, 0x00, 0x10, 0x06, 0xc4, 0xac, 0xfa, 0x68, + 0xe2, 0xde, 0x5b, 0x59, 0xf6, 0x4e, 0x96, 0x7d, 0x0f, 0xfd, 0x9a, 0xc4, 0xa8, 0xb4, 0xb2, 0x94, 0x4e, 0x96, 0x12, + 0xb2, 0x80, 0x4f, 0x8c, 0xa6, 0x36, 0x02, 0x08, 0xdb, 0x51, 0x2a, 0x5f, 0x00, 0xc2, 0x49, 0x02, 0x12, 0x62, 0x09, + 0x17, 0xa3, 0x7b, 0x2b, 0x19, 0x30, 0x1c, 0x42, 0x30, 0x07, 0xed, 0xb0, 0x37, 0x74, 0x13, 0xf1, 0xd7, 0xeb, 0xa2, + 0x7c, 0x13, 0x93, 0x4f, 0xc1, 0xfe, 0xec, 0xe3, 0x12, 0x1e, 0x97, 0x67, 0x1f, 0x87, 0xe8, 0x91, 0x70, 0xf6, 0x31, + 0xf8, 0x1e, 0xc9, 0x79, 0xdd, 0xf5, 0x38, 0x41, 0x6e, 0x21, 0xdd, 0xdf, 0x8e, 0x49, 0x80, 0xe6, 0x35, 0x2c, 0x47, + 0x4d, 0xc5, 0x35, 0x33, 0x63, 0x3c, 0x6f, 0xf4, 0xfe, 0xd8, 0xf1, 0x96, 0x29, 0x14, 0xb3, 0x98, 0xd7, 0xf0, 0x7b, + 0x56, 0x05, 0xea, 0xae, 0xb7, 0x49, 0x6e, 0x99, 0xd5, 0x73, 0xb4, 0xfb, 0xbe, 0xaf, 0x13, 0x41, 0xed, 0xef, 0xb0, + 0xe7, 0x99, 0xf5, 0xae, 0x8a, 0x81, 0x4b, 0x95, 0xec, 0x90, 0xa9, 0x6a, 0x7a, 0xa0, 0x52, 0x1a, 0x3c, 0xbd, 0xb4, + 0x2e, 0x5f, 0x2a, 0x6d, 0xe4, 0x99, 0xe6, 0x37, 0x80, 0x17, 0x53, 0x97, 0xc5, 0xfe, 0xab, 0xfb, 0x0a, 0x6e, 0xe3, + 0xfd, 0xfe, 0x32, 0xf7, 0xcc, 0x4f, 0x5c, 0x00, 0xf6, 0xa6, 0x42, 0xeb, 0x04, 0x4a, 0x0d, 0xeb, 0xf0, 0x65, 0x22, + 0xa2, 0x3f, 0xda, 0xe5, 0x3a, 0x73, 0x1d, 0x30, 0xa2, 0x88, 0xdf, 0xc6, 0xa3, 0x3f, 0x40, 0x71, 0x6d, 0xec, 0x01, + 0x61, 0x1d, 0x12, 0xfa, 0x8c, 0x00, 0xa4, 0x1e, 0x73, 0x94, 0x80, 0x66, 0x45, 0x73, 0xc7, 0xc0, 0xc1, 0x2f, 0xaf, + 0x94, 0xfe, 0x61, 0x99, 0x7b, 0x64, 0x4e, 0x69, 0x9b, 0x69, 0xac, 0xd6, 0xe4, 0x02, 0xe1, 0x15, 0x95, 0xac, 0xc2, + 0x67, 0xf3, 0x46, 0xf4, 0xfb, 0xf2, 0x08, 0x4f, 0xab, 0x1f, 0x77, 0x18, 0xdf, 0x0a, 0x88, 0x46, 0x02, 0xa0, 0x9f, + 0x00, 0xe6, 0x45, 0x36, 0xb3, 0xfb, 0x38, 0xa0, 0x4a, 0x89, 0xa6, 0x71, 0x36, 0xcf, 0x6f, 0xe9, 0x4d, 0xd9, 0x41, + 0xe7, 0x4e, 0x15, 0xb8, 0xe0, 0xaa, 0x64, 0xbc, 0xb2, 0x9e, 0xc9, 0xe7, 0x37, 0x77, 0xdb, 0x34, 0x8b, 0xdf, 0x97, + 0xff, 0xc0, 0xb1, 0xd5, 0x75, 0x78, 0x64, 0xea, 0x74, 0xed, 0x3c, 0xd2, 0xda, 0x0b, 0x01, 0x11, 0xed, 0x1a, 0x6a, + 0xbd, 0xb0, 0xd0, 0x23, 0x3d, 0x11, 0xce, 0x49, 0xa2, 0xa6, 0x1d, 0x68, 0x69, 0x84, 0xbe, 0xbe, 0xca, 0x8b, 0x2e, + 0x06, 0x6b, 0x5f, 0x8e, 0x59, 0x0e, 0x5d, 0xaa, 0x1e, 0xab, 0x87, 0xc6, 0x66, 0x0e, 0x3d, 0x6b, 0x55, 0x9e, 0x79, + 0xf9, 0xf1, 0x88, 0xf8, 0x30, 0xfa, 0x4b, 0x7e, 0xbf, 0xff, 0x8a, 0xe6, 0x1f, 0x13, 0x6a, 0xfc, 0x6c, 0x33, 0x40, + 0xd7, 0xbe, 0x2b, 0x0f, 0x44, 0x3d, 0xd7, 0x2a, 0x41, 0x88, 0x37, 0x88, 0x89, 0x66, 0xc4, 0x1c, 0x9c, 0x76, 0xa8, + 0xf9, 0x27, 0xa9, 0x01, 0x21, 0x4a, 0xbc, 0x8e, 0x29, 0x0b, 0x72, 0xda, 0xc4, 0x91, 0x7e, 0x14, 0x4e, 0xe4, 0x47, + 0x51, 0x15, 0xd9, 0x3d, 0x5c, 0x30, 0x98, 0x7a, 0x4f, 0xfb, 0x25, 0xfa, 0x2d, 0xe1, 0xc8, 0x39, 0x5a, 0x15, 0x82, + 0xc8, 0x19, 0x61, 0xad, 0x21, 0x4c, 0x10, 0x1b, 0xc4, 0xcb, 0xbe, 0x4b, 0x32, 0x1c, 0x29, 0xb8, 0xac, 0x63, 0xc7, + 0x98, 0xab, 0xa3, 0xea, 0x35, 0x80, 0xf1, 0xaa, 0x10, 0x34, 0x1b, 0x45, 0x76, 0x09, 0x51, 0x45, 0x8e, 0x27, 0xa0, + 0x76, 0x50, 0x1a, 0x9b, 0xe9, 0xe5, 0x38, 0x80, 0x09, 0x8e, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x2b, 0xd5, + 0xcf, 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x9c, 0xe9, + 0x72, 0x60, 0xdc, 0xb7, 0x3c, 0xa7, 0x38, 0xc3, 0x8f, 0x5e, 0x3e, 0xab, 0xe7, 0xfe, 0x74, 0x4b, 0xed, 0xc7, 0xdc, + 0xa8, 0x87, 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, + 0xfc, 0x43, 0x99, 0xae, 0x53, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, + 0xa2, 0xac, 0xdf, 0x87, 0xdf, 0x37, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, + 0x93, 0x41, 0x0d, 0xda, 0xf0, 0x2d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, + 0xec, 0x4f, 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xeb, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xa7, 0x97, 0xfc, + 0x06, 0xbd, 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, + 0x8f, 0x51, 0xc9, 0x62, 0x4b, 0x8f, 0x95, 0xd3, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x0e, 0xc1, + 0x12, 0x18, 0x17, 0xb1, 0xe1, 0xdb, 0x41, 0xc5, 0xe2, 0xd9, 0x76, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1e, 0x0b, 0x09, + 0x36, 0x93, 0xcd, 0x36, 0x73, 0xb6, 0xf1, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, + 0x35, 0x58, 0xad, 0xa6, 0xec, 0x54, 0x53, 0xf6, 0x4e, 0x53, 0x4e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, + 0x88, 0x4d, 0xa2, 0x9b, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, + 0x50, 0x85, 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, + 0xbe, 0xa5, 0x8e, 0x07, 0x94, 0x6d, 0xfe, 0x26, 0xf6, 0x41, 0x88, 0xdc, 0x8d, 0x7b, 0xf5, 0x33, 0xe2, 0xbd, 0xfd, + 0x09, 0xc6, 0x4f, 0x76, 0xda, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8c, 0xca, 0x24, 0x41, 0x2d, 0x4b, 0xe2, + 0x6f, 0x79, 0x32, 0xa8, 0xd8, 0x12, 0x3c, 0x68, 0xe7, 0x2c, 0x03, 0xfc, 0x15, 0xab, 0x45, 0xbf, 0xd5, 0xde, 0x12, + 0xe4, 0xa7, 0xad, 0xdd, 0x28, 0x4c, 0x8c, 0x20, 0x51, 0xb7, 0x2b, 0x03, 0xf9, 0xe1, 0x03, 0x4e, 0xc7, 0x53, 0x4f, + 0x19, 0x73, 0x2b, 0xd3, 0xcb, 0x74, 0xae, 0xe4, 0x1b, 0xb9, 0x97, 0x3e, 0xf6, 0x12, 0xec, 0x1c, 0xf0, 0x06, 0xd2, + 0x06, 0xde, 0xc2, 0x76, 0xe1, 0xb5, 0x41, 0xc2, 0x8c, 0x00, 0x5b, 0x9c, 0x1e, 0x23, 0x25, 0x30, 0x84, 0xe3, 0x2c, + 0x05, 0x60, 0x1a, 0x7d, 0x99, 0xcd, 0xed, 0xcb, 0xac, 0xd6, 0x6c, 0xa9, 0x9c, 0xee, 0x9d, 0x5b, 0xb7, 0xf3, 0x89, + 0x04, 0x00, 0x93, 0x3a, 0x07, 0xe2, 0xcc, 0x04, 0xbb, 0x34, 0x89, 0x2c, 0x1f, 0xc3, 0x7c, 0x25, 0x5e, 0x97, 0xc5, + 0x5a, 0x75, 0x45, 0xdb, 0x67, 0xa6, 0x9a, 0x91, 0x4e, 0x42, 0x05, 0x14, 0x14, 0x72, 0xad, 0x4f, 0xdf, 0x85, 0xef, + 0x82, 0x42, 0x03, 0xb3, 0xe5, 0xb8, 0xa7, 0xc9, 0x1a, 0xa9, 0x37, 0xf2, 0x7e, 0x9f, 0x5c, 0x03, 0xa9, 0xce, 0x1c, + 0x5a, 0xf6, 0x04, 0x9d, 0x64, 0x4f, 0x6e, 0xca, 0x52, 0xa8, 0x03, 0xa9, 0x07, 0x0c, 0x21, 0xda, 0xa6, 0x8f, 0x3f, + 0x19, 0x12, 0x5d, 0x80, 0x2d, 0x44, 0x1b, 0xf8, 0xf1, 0x27, 0xd8, 0x67, 0x41, 0x78, 0x4c, 0xf3, 0xb7, 0x90, 0x74, + 0x6a, 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0x95, + 0x94, 0xea, 0x00, 0x6d, 0x4a, 0xb9, 0xab, 0x2b, 0x3f, 0x88, 0xb6, 0xe0, 0xc8, 0x22, 0xfe, 0x3e, 0x43, 0x44, 0x30, + 0x33, 0x88, 0xb0, 0x6b, 0xa1, 0xee, 0xf6, 0x9c, 0x5a, 0x16, 0xf5, 0xb6, 0xe7, 0x94, 0xba, 0x0d, 0xc3, 0x77, 0x13, + 0xcc, 0x14, 0x37, 0xfc, 0x8f, 0xcc, 0x0b, 0xf5, 0xc6, 0x63, 0x51, 0xa0, 0x7b, 0xfe, 0x61, 0xc9, 0xf3, 0xd9, 0x56, + 0x99, 0x30, 0x57, 0x7c, 0x39, 0x0b, 0x65, 0x57, 0x4b, 0xe3, 0xce, 0x67, 0x6f, 0xa9, 0xe6, 0x83, 0x7f, 0x3c, 0x26, + 0x10, 0x6f, 0x14, 0xdf, 0xac, 0x1a, 0xb9, 0x75, 0x4d, 0xb6, 0x37, 0x25, 0xa0, 0x7e, 0x5f, 0x6e, 0x70, 0xbf, 0xc5, + 0xfa, 0x77, 0x4f, 0x83, 0x8c, 0xd5, 0x0c, 0x57, 0x4c, 0xe1, 0x53, 0x00, 0x18, 0x1c, 0x4e, 0x05, 0x69, 0x81, 0xb7, + 0xbc, 0x1c, 0x5e, 0x4f, 0xb6, 0x64, 0xd2, 0xdd, 0xfa, 0xc8, 0x9d, 0x05, 0xaa, 0xde, 0x6f, 0x28, 0x4e, 0x1a, 0x24, + 0x1a, 0x7b, 0x0d, 0xbe, 0xc8, 0x32, 0xca, 0x45, 0x13, 0xf7, 0x31, 0xf9, 0x4a, 0x0f, 0x60, 0xa5, 0x42, 0x09, 0x10, + 0xfd, 0xc6, 0xb2, 0xd8, 0x88, 0xb6, 0xc5, 0x06, 0x96, 0x52, 0x3e, 0xd7, 0xab, 0xe9, 0xb3, 0x57, 0xa2, 0x79, 0x1f, + 0xcd, 0x38, 0xa5, 0xd1, 0x80, 0xe3, 0x34, 0x0a, 0x77, 0xef, 0xef, 0x45, 0xb9, 0xcc, 0xc0, 0x92, 0xad, 0xc2, 0x29, + 0xae, 0x1b, 0x75, 0x46, 0xbc, 0xc8, 0x63, 0x05, 0xd0, 0xf1, 0x98, 0x00, 0xa8, 0x2e, 0x08, 0xa8, 0x88, 0x96, 0xd2, + 0x5b, 0xa1, 0xc5, 0x42, 0xbd, 0xe1, 0x28, 0x85, 0x3f, 0xd2, 0x9f, 0x07, 0xd5, 0x14, 0x80, 0xd8, 0xf5, 0x71, 0xf4, + 0xba, 0x28, 0xe9, 0x53, 0xc5, 0xac, 0x92, 0x83, 0x09, 0xec, 0xea, 0x44, 0x86, 0x9a, 0x43, 0xde, 0xbc, 0x2b, 0x6f, + 0x6e, 0xf2, 0x36, 0xc6, 0x29, 0xf9, 0x91, 0x9b, 0x8e, 0x35, 0x62, 0xe0, 0x95, 0xa7, 0x75, 0x9a, 0x20, 0x4d, 0x2e, + 0x80, 0x61, 0x88, 0xef, 0x32, 0xef, 0x85, 0xe7, 0x48, 0x55, 0x90, 0xcc, 0xf6, 0x99, 0xa7, 0x2e, 0xa2, 0xfa, 0xca, + 0xa9, 0xa5, 0x33, 0xa7, 0x1f, 0x01, 0xbc, 0xc7, 0xd4, 0xa4, 0x21, 0x1f, 0xe1, 0xb6, 0x14, 0x5f, 0xef, 0xd4, 0x35, + 0x5e, 0x1a, 0x9d, 0xbb, 0x97, 0x2f, 0xdd, 0x69, 0xd0, 0x4f, 0x41, 0x50, 0xce, 0x17, 0xa5, 0x80, 0x3d, 0x65, 0x36, + 0xd7, 0xab, 0x55, 0x2b, 0xb4, 0x8e, 0xc7, 0xb1, 0x76, 0x14, 0xd2, 0xea, 0x2c, 0x60, 0xab, 0x91, 0x4e, 0x09, 0x10, + 0x82, 0xe3, 0x34, 0xec, 0x0c, 0xe3, 0x2e, 0x9d, 0x46, 0x64, 0xbd, 0x52, 0x92, 0x2e, 0xcc, 0x20, 0xf9, 0x27, 0x79, + 0x3d, 0x03, 0x5a, 0x02, 0x38, 0x14, 0xb1, 0x84, 0x87, 0x93, 0xe4, 0x06, 0xa0, 0xd3, 0xe1, 0xa0, 0xd2, 0xd0, 0x9c, + 0xf9, 0x2c, 0x99, 0x4f, 0x62, 0xa9, 0xaa, 0x3c, 0x1e, 0x3d, 0xe5, 0x66, 0xd0, 0xef, 0x67, 0xd3, 0x52, 0xb9, 0x00, + 0x04, 0xb1, 0x2e, 0x0c, 0x10, 0x8f, 0xb4, 0xf0, 0x64, 0xd1, 0xa7, 0x24, 0x7e, 0x39, 0x4b, 0xe6, 0x26, 0x1b, 0xde, + 0x81, 0x11, 0x6c, 0xc6, 0x75, 0x49, 0x99, 0xf6, 0xa8, 0xfc, 0x9e, 0xd1, 0x53, 0xdb, 0xd7, 0x5a, 0x6d, 0x11, 0xeb, + 0x3a, 0xb8, 0x2a, 0x51, 0x4f, 0xf1, 0x41, 0x49, 0x82, 0xf7, 0x2b, 0xe7, 0x66, 0xa4, 0x7c, 0x2d, 0x2a, 0x3f, 0x68, + 0x67, 0x6a, 0xe5, 0xc0, 0x11, 0xa8, 0xb0, 0x8a, 0x4a, 0x5e, 0xef, 0x3a, 0x04, 0x4f, 0xee, 0x4a, 0x05, 0xca, 0xc1, + 0xcf, 0x41, 0x8c, 0xae, 0x6f, 0x3a, 0x6b, 0xa8, 0x99, 0x46, 0x95, 0x47, 0xd0, 0xb9, 0x03, 0x78, 0x52, 0xf0, 0x52, + 0xab, 0x1f, 0x8f, 0x47, 0xcf, 0xfc, 0xe0, 0x2f, 0x33, 0x7d, 0x0b, 0x31, 0x51, 0x4e, 0x35, 0x42, 0xe2, 0x4a, 0x49, + 0x22, 0x3e, 0x5d, 0xb4, 0xac, 0x18, 0x95, 0xe1, 0x03, 0xb0, 0x00, 0x51, 0xf9, 0xea, 0x54, 0xe5, 0xc5, 0x48, 0xdb, + 0x12, 0x78, 0x4d, 0xfe, 0x21, 0x72, 0xcd, 0x5b, 0x5f, 0x77, 0x95, 0xa1, 0x6f, 0x65, 0x05, 0x3a, 0x82, 0xad, 0x2c, + 0x25, 0x07, 0x7c, 0x52, 0xdf, 0x55, 0x5b, 0x9f, 0x53, 0xb6, 0x11, 0x6e, 0xf2, 0xeb, 0xd8, 0xc1, 0x91, 0xf2, 0x1b, + 0xbc, 0x14, 0xc0, 0x5e, 0x03, 0xf6, 0xe6, 0x8a, 0x15, 0xcd, 0xa3, 0x43, 0xda, 0x16, 0x68, 0x64, 0xe6, 0x76, 0xae, + 0xee, 0xdb, 0xf2, 0x28, 0x8d, 0x21, 0x32, 0xed, 0x91, 0xe9, 0x60, 0x33, 0xca, 0x7f, 0x4b, 0xf9, 0xad, 0xc2, 0x31, + 0xf0, 0xed, 0xdc, 0x3b, 0x80, 0xaa, 0xa7, 0x0d, 0x32, 0xd6, 0x0c, 0x43, 0x2b, 0xbb, 0x5c, 0x0a, 0x2d, 0x41, 0x4b, + 0xdd, 0x04, 0xc1, 0xf9, 0x11, 0x51, 0x8e, 0x00, 0x74, 0x91, 0x02, 0x26, 0xf8, 0x39, 0x6d, 0x77, 0xbf, 0xbf, 0x49, + 0x3d, 0x72, 0xef, 0x0a, 0x95, 0xcd, 0xf2, 0x4d, 0x8e, 0x30, 0xf6, 0x13, 0x8d, 0x19, 0x74, 0x72, 0x45, 0x4e, 0x78, + 0xd6, 0xea, 0xb0, 0xae, 0x9b, 0x32, 0x28, 0x8b, 0x63, 0x9e, 0x4f, 0x67, 0xbf, 0x3f, 0x39, 0xd4, 0x0d, 0xb2, 0x90, + 0xff, 0xce, 0x7a, 0x48, 0x06, 0xdd, 0x83, 0x50, 0x88, 0xde, 0x3c, 0x98, 0xe1, 0x7f, 0x6c, 0xcb, 0xb3, 0x6f, 0xb8, + 0x51, 0x27, 0x80, 0x39, 0xe2, 0x7a, 0xe9, 0x29, 0xda, 0x7a, 0xb8, 0x05, 0xb2, 0x0d, 0x5e, 0xde, 0xda, 0x6b, 0xa0, + 0xa2, 0x38, 0xfe, 0x15, 0xcf, 0xd4, 0xca, 0x06, 0x3f, 0x3d, 0x65, 0x3b, 0xf0, 0xf0, 0x22, 0x04, 0x14, 0xc3, 0xb2, + 0xf1, 0x2b, 0xcb, 0x71, 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, + 0x93, 0x7b, 0x2b, 0x72, 0xca, 0x5c, 0xe9, 0x61, 0x74, 0x5d, 0x92, 0xbe, 0x49, 0x3e, 0xb6, 0x86, 0xed, 0x77, 0xed, + 0x7e, 0x33, 0x44, 0x10, 0x42, 0x39, 0x7e, 0xce, 0xe8, 0x84, 0xc6, 0x87, 0x35, 0xd7, 0x3b, 0xbd, 0x7e, 0xef, 0x12, + 0x2f, 0xd8, 0x1a, 0x0d, 0xf0, 0x74, 0xe8, 0x62, 0x9e, 0xa8, 0xa1, 0xd3, 0x75, 0xed, 0x1c, 0x3c, 0x30, 0xc8, 0xf2, + 0xe4, 0x1b, 0x86, 0x25, 0xf6, 0x27, 0x11, 0x4f, 0xda, 0xaa, 0x8d, 0xed, 0x89, 0x6a, 0xa3, 0x66, 0xe0, 0x07, 0xaf, + 0xa0, 0xc0, 0xe8, 0x82, 0xb4, 0x06, 0xe3, 0x70, 0x04, 0x20, 0x2b, 0xc6, 0xf1, 0xc8, 0x60, 0x02, 0x43, 0xba, 0xa1, + 0x28, 0x00, 0x0f, 0x8f, 0xd3, 0x41, 0xc8, 0x00, 0xd2, 0x05, 0x0f, 0x0d, 0xdb, 0x24, 0xa4, 0xfc, 0x3c, 0x2f, 0x6b, + 0x35, 0x84, 0xbe, 0xb3, 0x50, 0x1d, 0xfb, 0x91, 0xf6, 0x8a, 0x75, 0xad, 0x4a, 0x27, 0xb6, 0x3a, 0x40, 0xdf, 0x90, + 0x81, 0x6f, 0x1d, 0x5b, 0x00, 0x44, 0x4b, 0xfc, 0x96, 0x7a, 0xb5, 0x2f, 0x63, 0x56, 0xa8, 0xd7, 0x17, 0xa6, 0x5d, + 0xaf, 0xa4, 0x45, 0x01, 0x15, 0xb7, 0xad, 0xda, 0x9e, 0xc8, 0xf9, 0x8f, 0xef, 0x3a, 0xda, 0xf1, 0xd9, 0xa9, 0xb1, + 0x25, 0x94, 0xb9, 0xc5, 0x13, 0x59, 0x1d, 0x6d, 0xa9, 0x4e, 0xf5, 0x01, 0x97, 0x9a, 0x54, 0x67, 0xda, 0xa7, 0xc9, + 0x12, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xc1, 0xf9, 0x64, 0x50, 0x30, 0xb7, 0x48, 0x40, 0x02, 0xdb, 0xda, 0xda, + 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xf2, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, 0xce, 0xde, 0x69, 0x2d, 0x20, 0x80, + 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, 0xe5, 0x6f, 0x29, 0x2a, 0x62, 0xcf, + 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, 0x3a, 0x6a, 0x72, 0xd7, 0xcd, 0x55, + 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xbe, 0xd6, 0x95, 0x53, 0xef, 0x83, 0x8a, 0x23, 0x06, 0x82, 0x9b, 0xee, 0xf1, 0xc1, + 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, 0x68, 0xc5, 0xf4, 0x11, 0x00, 0x11, + 0x60, 0x95, 0xa8, 0xff, 0xcd, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, 0xb6, 0xde, 0x3f, 0xaf, 0x91, 0x56, + 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, 0xff, 0x9f, 0xfb, 0x00, 0x35, 0xa2, + 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2a, 0x7c, 0xe3, 0x87, 0x8c, 0xf3, 0xc1, 0x0c, 0x1d, 0xd5, 0xe6, + 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, 0x4f, 0xdc, 0x67, 0x5c, 0x7b, 0x41, + 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, 0x65, 0x93, 0x48, 0x7d, 0x33, 0x06, + 0x05, 0x40, 0xf1, 0x3c, 0x27, 0xb9, 0x74, 0x91, 0xe6, 0x95, 0x28, 0x6b, 0xdd, 0x8c, 0x9c, 0x15, 0xc3, 0x9c, 0xd5, + 0x7e, 0x50, 0xdc, 0xe4, 0x66, 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x7c, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, + 0xd2, 0xbb, 0x1c, 0xb7, 0xce, 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, + 0x3f, 0xe3, 0xcf, 0x09, 0x4c, 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x9c, 0x97, 0x93, + 0x70, 0x38, 0xf4, 0x41, 0x1f, 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, + 0x10, 0xd1, 0x42, 0x43, 0x1f, 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, + 0xda, 0xd0, 0x22, 0xc5, 0x45, 0xa3, 0xcc, 0x66, 0x95, 0xec, 0x84, 0xad, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, + 0x54, 0xad, 0xa7, 0x7a, 0x3d, 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa2, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, + 0xa3, 0x6a, 0x93, 0xa5, 0x11, 0x55, 0x6e, 0x52, 0xb9, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0xcd, 0xb5, 0xb3, 0x35, 0x38, + 0x71, 0xe4, 0xb9, 0xe4, 0x96, 0xef, 0xce, 0x2b, 0xba, 0x3b, 0xd5, 0xbe, 0x05, 0xb8, 0x37, 0xc3, 0x86, 0xcc, 0x79, + 0x8d, 0x9d, 0x06, 0x61, 0x12, 0xf8, 0x11, 0xfb, 0x98, 0x21, 0x1b, 0x0c, 0xe8, 0x28, 0xa4, 0x26, 0xc0, 0x32, 0x47, + 0x02, 0x26, 0x7f, 0x3d, 0xf7, 0x9b, 0x45, 0x91, 0xc3, 0x62, 0xfc, 0xb0, 0xc5, 0x48, 0x63, 0xb5, 0x06, 0xc3, 0x72, + 0x85, 0xc8, 0x9f, 0xda, 0x33, 0xd4, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, 0xa7, 0x4f, 0x75, 0x7d, 0xfe, 0xdb, + 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xc1, 0x2d, 0xce, 0x1d, 0x89, 0xde, 0xa9, 0xd2, 0xcc, 0x2e, + 0xed, 0x9a, 0x5d, 0x9b, 0xd2, 0x6e, 0xc9, 0xf5, 0xea, 0x2b, 0xe5, 0x8d, 0x9d, 0x57, 0x4c, 0xf7, 0x1f, 0x84, 0xde, + 0x51, 0xce, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, 0x26, 0x55, 0xbb, 0x84, 0x93, 0xae, + 0x61, 0x95, 0xf9, 0xf6, 0x3f, 0xf2, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, 0xfd, 0x29, 0x88, 0xab, 0xfa, 0xc3, + 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe4, 0x9e, 0x42, 0xd8, 0x60, 0xf6, 0xf3, + 0xd3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x9a, 0x11, 0xde, 0xef, 0x18, 0xe7, 0xfe, 0xcd, + 0x0f, 0x6a, 0x72, 0x84, 0x88, 0x76, 0x11, 0x0e, 0x00, 0xe2, 0x4e, 0x53, 0x59, 0x87, 0x1a, 0xa0, 0x0f, 0x08, 0xac, + 0x43, 0xdf, 0x66, 0x00, 0x07, 0x7d, 0xb4, 0x79, 0x16, 0x81, 0xbc, 0xee, 0xdd, 0xb3, 0xb7, 0x6c, 0xef, 0xf3, 0xe7, + 0xeb, 0xd4, 0xbb, 0x47, 0x87, 0xe0, 0xcb, 0xb1, 0x3f, 0xbd, 0x0e, 0x0c, 0x2e, 0x34, 0x7b, 0xfb, 0x54, 0xb0, 0x3d, + 0xdb, 0x3f, 0x45, 0xa4, 0xa2, 0xee, 0xfc, 0xc3, 0x6b, 0x13, 0x3d, 0xef, 0xbc, 0xb0, 0xe2, 0x4b, 0x00, 0x0f, 0x64, + 0x31, 0xa0, 0xf8, 0x2c, 0xbd, 0x7f, 0xb2, 0x04, 0xd4, 0xe4, 0x77, 0x7c, 0xe3, 0xbd, 0xa3, 0xd4, 0x05, 0xfc, 0x39, + 0xa0, 0xf4, 0x49, 0xc5, 0xbd, 0xd5, 0xf0, 0xce, 0xbf, 0x7a, 0x06, 0xce, 0x13, 0xeb, 0xe1, 0x02, 0xfe, 0x2a, 0xf8, + 0xd0, 0x5b, 0x0d, 0x30, 0xb1, 0xe4, 0x43, 0x6f, 0x3d, 0x80, 0x54, 0x85, 0x0b, 0x89, 0xb1, 0x0f, 0xbf, 0x06, 0x15, + 0xc3, 0x3f, 0x7e, 0xd3, 0x18, 0xac, 0xbf, 0x06, 0x85, 0x46, 0x63, 0x2d, 0x55, 0xc8, 0x52, 0x2c, 0x2e, 0x04, 0xd8, + 0x84, 0xe3, 0x6e, 0x5f, 0xac, 0x6a, 0xbb, 0x11, 0xf4, 0xe7, 0x23, 0xbe, 0x47, 0x63, 0x75, 0x55, 0xce, 0x45, 0xf9, + 0x11, 0xe9, 0x53, 0x1d, 0x1f, 0xa3, 0x62, 0x5b, 0x77, 0xa7, 0x53, 0xad, 0x3a, 0xd2, 0x7e, 0x53, 0xae, 0xc1, 0x8e, + 0xd7, 0xc9, 0x89, 0xa5, 0xf0, 0xa2, 0xc3, 0xce, 0x4b, 0xa7, 0x44, 0x87, 0x61, 0xbc, 0xdb, 0xaa, 0x67, 0x0c, 0xe5, + 0x95, 0xc1, 0x98, 0x2e, 0x78, 0xc4, 0x9f, 0x0f, 0x2a, 0x19, 0x1a, 0xf3, 0x01, 0xd9, 0x30, 0x94, 0x0f, 0x2d, 0x32, + 0x24, 0x44, 0xbc, 0x87, 0x4a, 0xc0, 0xb6, 0x05, 0x65, 0x52, 0xc0, 0x59, 0x34, 0xf8, 0xad, 0xf6, 0x2a, 0xe0, 0x3d, + 0x88, 0xfc, 0x46, 0xba, 0x94, 0x4b, 0x6c, 0x74, 0xe2, 0x58, 0x16, 0xda, 0x79, 0x5c, 0x7f, 0x1d, 0x83, 0xfa, 0xbd, + 0xd2, 0x6f, 0x50, 0xce, 0xfe, 0x28, 0x59, 0xa7, 0x8d, 0x27, 0xc6, 0xdf, 0x5d, 0xe5, 0x9f, 0xa2, 0xa5, 0x1e, 0xfe, + 0x3f, 0x63, 0x0a, 0xa5, 0x7f, 0x99, 0x96, 0xd1, 0x76, 0xbd, 0x14, 0xa5, 0xc8, 0x23, 0x71, 0xf6, 0xb5, 0xc8, 0xce, + 0xe5, 0x3b, 0x9f, 0x42, 0xbf, 0x00, 0xb4, 0xec, 0x13, 0x64, 0xf4, 0x0f, 0x4c, 0xf0, 0xe1, 0x0f, 0xda, 0xb9, 0xb6, + 0xe2, 0xe3, 0x49, 0x75, 0x63, 0xed, 0xdd, 0x8e, 0x17, 0x89, 0x51, 0x8c, 0x55, 0xbe, 0xea, 0x66, 0xe5, 0x44, 0x25, + 0x07, 0x46, 0xba, 0x26, 0x7b, 0x95, 0x92, 0x75, 0x3b, 0xdd, 0x4a, 0x20, 0xa2, 0x0a, 0xbc, 0xc7, 0xb8, 0x8a, 0x7d, + 0x04, 0xd3, 0x75, 0xc7, 0x65, 0xb4, 0xe3, 0x3d, 0xe3, 0xd5, 0x89, 0xb2, 0x82, 0xdb, 0x8d, 0x68, 0x4f, 0xe8, 0xe8, + 0xa7, 0x49, 0x6d, 0x59, 0x38, 0x00, 0xb9, 0x4b, 0x18, 0xcb, 0x86, 0x60, 0xc5, 0xa0, 0xf4, 0xf5, 0x9a, 0x92, 0x65, + 0x01, 0x16, 0x9d, 0x5d, 0x46, 0x20, 0x86, 0x75, 0xd3, 0x9c, 0xd1, 0xf1, 0xd2, 0xc5, 0xf9, 0xa0, 0x55, 0xa4, 0xe0, + 0x19, 0x2d, 0x3a, 0xe6, 0xa6, 0x23, 0xdd, 0x18, 0xed, 0xed, 0x0f, 0x06, 0x21, 0xc5, 0xf3, 0x07, 0xb6, 0x5a, 0x17, + 0x17, 0x89, 0x57, 0xc8, 0x44, 0x0b, 0x62, 0x29, 0x02, 0x33, 0x5e, 0x68, 0x1a, 0x61, 0x82, 0x32, 0x25, 0x58, 0xb4, + 0x46, 0x87, 0xf6, 0x87, 0x25, 0xec, 0x1e, 0x63, 0x04, 0x08, 0x54, 0x99, 0x3e, 0x87, 0xad, 0x09, 0xb3, 0xad, 0x8b, + 0x2d, 0xd0, 0x56, 0x31, 0x34, 0x08, 0x6b, 0x43, 0xcc, 0xc7, 0x34, 0x5f, 0xfd, 0x13, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, + 0xc1, 0xed, 0x9a, 0x84, 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xaa, 0x1d, 0x6b, + 0xa9, 0x77, 0xac, 0x8d, 0xde, 0xb1, 0x56, 0x0d, 0xff, 0x90, 0x79, 0x31, 0x4b, 0x40, 0xbf, 0xbb, 0xe6, 0xaa, 0x41, + 0xd0, 0x8c, 0x2d, 0xbb, 0x83, 0xdf, 0x12, 0x6b, 0xb7, 0xf4, 0xaf, 0x96, 0x6c, 0x61, 0xfa, 0x40, 0xb7, 0x0e, 0xb0, + 0x8c, 0xa8, 0xc9, 0xf7, 0xc8, 0xbb, 0xe9, 0xac, 0x28, 0xdc, 0x9e, 0xd8, 0xc2, 0x67, 0x6f, 0xcd, 0x9b, 0xf7, 0x4f, + 0x23, 0xc8, 0xbd, 0xe7, 0xde, 0xfd, 0xf0, 0xad, 0x7f, 0xa5, 0x5b, 0x20, 0x27, 0xb3, 0x9c, 0x81, 0xd4, 0x11, 0x9f, + 0x20, 0x5a, 0xd9, 0x53, 0xbe, 0x13, 0x72, 0x67, 0xdb, 0x3c, 0xbd, 0x77, 0xb7, 0xb5, 0xd5, 0xd3, 0x7b, 0x96, 0x8f, + 0x28, 0x56, 0x9c, 0xa6, 0x48, 0x98, 0x45, 0x5b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xfd, 0xd3, 0x8e, + 0x8e, 0x97, 0x73, 0xc0, 0xee, 0xfe, 0x93, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0xf7, 0x4f, 0x33, 0x8d, 0xe7, + 0x70, 0x22, 0x9f, 0x8e, 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, + 0xd6, 0x35, 0x6f, 0xaf, 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, + 0x70, 0xba, 0xe4, 0xb1, 0xef, 0xd3, 0x2c, 0xad, 0xf7, 0xa8, 0xb5, 0xc8, 0x2d, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, + 0x61, 0xa9, 0xe9, 0x9f, 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2d, 0xae, 0x7e, 0x38, 0x2f, 0x94, + 0x6b, 0x37, 0x6f, 0xe3, 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x4e, 0x94, + 0x5d, 0x2c, 0xe1, 0x1e, 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf5, 0x8c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, + 0x62, 0x5b, 0xb8, 0x7a, 0xc6, 0xb6, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0xad, 0x6a, 0x8e, + 0x35, 0xd4, 0x6c, 0x63, 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0x56, 0x6d, 0xc5, 0xc7, 0xda, 0x5a, 0x97, 0xee, 0xf5, + 0x1e, 0xd5, 0x05, 0xb0, 0xf5, 0xdf, 0x9d, 0xae, 0x5c, 0xcf, 0x67, 0x04, 0xf0, 0xb5, 0xe0, 0xe3, 0xc9, 0x02, 0xbd, + 0x4a, 0x16, 0xfe, 0xdd, 0x40, 0x8d, 0xbf, 0xd3, 0xb9, 0x0b, 0x80, 0xae, 0xa4, 0xbc, 0x02, 0xf2, 0x0e, 0x2a, 0xcc, + 0x2d, 0xbb, 0xf2, 0xfe, 0xec, 0x3b, 0xec, 0x2d, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x83, 0x53, 0x41, 0x32, 0xb0, 0x97, + 0x15, 0xdb, 0x07, 0xb1, 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x80, 0x20, 0xae, 0xe0, 0x0e, 0xe2, 0xf0, 0xe4, 0x9f, + 0x83, 0xfb, 0xd6, 0x66, 0x7d, 0xcf, 0xac, 0xce, 0x09, 0x36, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0xd6, 0xfd, 0xbe, + 0xb7, 0xd7, 0x8e, 0x4f, 0x2b, 0xa9, 0x13, 0x3b, 0xaf, 0xd5, 0x5a, 0xb0, 0xb7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x80, + 0x5f, 0x70, 0x37, 0xe0, 0xf7, 0x1d, 0x6b, 0xcb, 0x7b, 0xcb, 0x16, 0x6c, 0x0f, 0x97, 0xa0, 0xa6, 0xbd, 0xec, 0xcf, + 0x2a, 0x17, 0xb4, 0x63, 0x97, 0xc4, 0xc3, 0x19, 0xb3, 0x5c, 0x99, 0x59, 0x27, 0xf9, 0x8d, 0xe8, 0x8c, 0xe9, 0xac, + 0xf5, 0x7c, 0xce, 0xe7, 0x93, 0x42, 0x83, 0xfa, 0x5d, 0x12, 0x1f, 0x51, 0xd1, 0x79, 0x02, 0x5b, 0xcb, 0x0a, 0xc8, + 0xbd, 0x2e, 0xc1, 0x5a, 0xab, 0x5d, 0xfa, 0xbd, 0x6a, 0xc0, 0x6d, 0xca, 0x61, 0x4d, 0x40, 0xd0, 0x9c, 0x59, 0x51, + 0x8f, 0xd9, 0x8e, 0x71, 0xf3, 0xd3, 0xcb, 0x1f, 0x9c, 0xb0, 0x64, 0xc5, 0x6a, 0x7f, 0xfa, 0xc3, 0x53, 0x4f, 0x7f, + 0xa7, 0xf6, 0xaf, 0x84, 0x1f, 0x8c, 0xff, 0x5d, 0xbb, 0xaf, 0xb5, 0x18, 0x95, 0xad, 0x72, 0x84, 0xc6, 0xdd, 0x4a, + 0x9a, 0x2c, 0x3f, 0x09, 0x4f, 0x58, 0x0b, 0x9e, 0x99, 0x33, 0x20, 0x2b, 0x60, 0x85, 0xb5, 0x4c, 0xc2, 0x39, 0xc6, + 0x6a, 0x69, 0xab, 0x6f, 0xd1, 0x34, 0xa7, 0x87, 0x73, 0x6d, 0x50, 0xa6, 0x9c, 0x9d, 0x11, 0xab, 0xe1, 0x32, 0x2c, + 0x4d, 0x28, 0x42, 0xf6, 0x60, 0x07, 0x37, 0x76, 0xca, 0x52, 0xca, 0x70, 0x8e, 0xc1, 0x84, 0x27, 0x62, 0x54, 0xee, + 0xfb, 0x87, 0x92, 0x57, 0x6d, 0x39, 0x28, 0x47, 0xd8, 0x47, 0x12, 0x25, 0x70, 0x2b, 0xd2, 0x42, 0x91, 0xb2, 0xf8, + 0xdb, 0x01, 0xba, 0xc0, 0x0b, 0xa8, 0xab, 0x51, 0xb7, 0x3f, 0x1c, 0xf1, 0xf0, 0x91, 0xa9, 0x0f, 0x8c, 0x58, 0x12, + 0xa8, 0xed, 0x45, 0x96, 0xae, 0x40, 0x85, 0xdf, 0xc3, 0xd5, 0x44, 0xec, 0xe7, 0x96, 0x14, 0x15, 0xd9, 0x48, 0x6f, + 0x68, 0x0d, 0x1e, 0xa1, 0x35, 0xe5, 0x07, 0x27, 0xd5, 0x26, 0x9d, 0x77, 0x84, 0x1c, 0xab, 0x6f, 0x2d, 0x61, 0xb4, + 0x2b, 0x7a, 0xf1, 0xe0, 0xe8, 0x3d, 0xcf, 0x57, 0xbd, 0xf2, 0x27, 0xae, 0x98, 0x27, 0xb7, 0x11, 0xa8, 0x5b, 0x41, + 0x75, 0x7b, 0xaf, 0x12, 0x2c, 0x58, 0xd2, 0xee, 0xe3, 0xb7, 0xb3, 0x76, 0x20, 0x2a, 0x63, 0x95, 0xbe, 0x26, 0x09, + 0x7b, 0x62, 0xd0, 0x29, 0x54, 0x55, 0x76, 0x77, 0xb4, 0x05, 0xae, 0x53, 0x96, 0xa2, 0x17, 0xb6, 0xc8, 0xdd, 0xf2, + 0xef, 0x9e, 0x2b, 0x72, 0xf6, 0x6b, 0x40, 0x70, 0x6a, 0xbe, 0x22, 0xbe, 0x9c, 0xe0, 0x51, 0x75, 0x0b, 0x1c, 0xe7, + 0xef, 0x00, 0xfe, 0xf1, 0x78, 0x0d, 0x9a, 0x80, 0x58, 0xb0, 0x5e, 0x1a, 0xf7, 0x58, 0x2f, 0x2e, 0xb6, 0xab, 0x24, + 0xdf, 0x82, 0x33, 0x03, 0xa5, 0x5a, 0xfa, 0x81, 0x53, 0xb5, 0x80, 0x0a, 0x07, 0xb3, 0x93, 0x7a, 0x61, 0x19, 0xf5, + 0x98, 0x3e, 0x3f, 0x83, 0x83, 0x23, 0x24, 0x00, 0xee, 0x97, 0x7d, 0x40, 0x02, 0x1e, 0x3a, 0xb3, 0x03, 0xc2, 0x09, + 0xb3, 0xa8, 0x0a, 0x24, 0x92, 0x23, 0xfd, 0xec, 0x31, 0x13, 0xc9, 0x1f, 0xcc, 0x7a, 0xce, 0x29, 0xd1, 0x63, 0x3d, + 0x75, 0x84, 0xf4, 0x58, 0xcf, 0x3a, 0x22, 0x7a, 0xac, 0x67, 0x1d, 0x1f, 0x3d, 0xd6, 0x33, 0xc7, 0x4e, 0x0f, 0x02, + 0x13, 0x20, 0xf2, 0x80, 0xf5, 0x68, 0x32, 0xf5, 0x14, 0xf7, 0x00, 0xd1, 0x20, 0xb0, 0x9e, 0x14, 0xce, 0x7b, 0x80, + 0x3c, 0x46, 0x62, 0x75, 0xd0, 0xfb, 0x8f, 0xf1, 0x77, 0x3d, 0x23, 0x23, 0x8f, 0x5b, 0x87, 0xd5, 0xff, 0xfa, 0x4f, + 0x08, 0x80, 0xc3, 0xb3, 0xa9, 0x77, 0x3d, 0x86, 0xac, 0xb2, 0x8c, 0x40, 0xf2, 0x13, 0x83, 0x2f, 0x5f, 0x00, 0x54, + 0x7d, 0xa6, 0x6b, 0x35, 0x39, 0x6a, 0x8f, 0x39, 0x74, 0xc5, 0x00, 0xb0, 0x0d, 0x4b, 0x54, 0xd5, 0xc2, 0x26, 0x2c, + 0x6e, 0x3f, 0xc3, 0x68, 0x2e, 0x9b, 0x5e, 0xd0, 0x40, 0x3d, 0x42, 0xf0, 0x4b, 0xeb, 0xa1, 0xb5, 0x96, 0x29, 0x87, + 0xae, 0x8d, 0xa2, 0xca, 0x86, 0xba, 0x84, 0xd5, 0x46, 0x44, 0x35, 0x51, 0xa4, 0x5c, 0x33, 0x8a, 0x62, 0xa9, 0x82, + 0x43, 0x26, 0x56, 0x10, 0x35, 0x4f, 0x5b, 0x6d, 0x15, 0x1c, 0x56, 0x80, 0xb0, 0x16, 0xd6, 0x42, 0x3a, 0x83, 0xda, + 0x3b, 0xfd, 0x48, 0xf9, 0xcb, 0x0b, 0xb9, 0x9d, 0x5b, 0x28, 0xc2, 0xed, 0x39, 0x28, 0x6f, 0xea, 0xaa, 0x54, 0x44, + 0xa3, 0x25, 0x50, 0xca, 0x8a, 0x20, 0xb2, 0x00, 0x01, 0x1c, 0x37, 0x10, 0xf8, 0xbc, 0xc6, 0x27, 0xd0, 0x28, 0x04, + 0xf2, 0x03, 0xeb, 0x70, 0xe3, 0x21, 0x2d, 0xb5, 0x46, 0x44, 0x89, 0xf8, 0xc9, 0xd5, 0x73, 0x6c, 0x5f, 0x3d, 0x8d, + 0xb5, 0xa5, 0x34, 0x41, 0xfc, 0xc4, 0x62, 0x0b, 0x31, 0x41, 0x54, 0x87, 0xe8, 0x04, 0x96, 0x13, 0x42, 0x14, 0xfe, + 0x10, 0xfa, 0xa9, 0x81, 0xbf, 0x64, 0xcb, 0x22, 0xaf, 0x09, 0x16, 0x33, 0x67, 0x80, 0x56, 0x45, 0xe0, 0x99, 0xce, + 0x96, 0xca, 0x9c, 0xe6, 0xd1, 0x91, 0x1d, 0x5c, 0x76, 0x1d, 0xec, 0xa5, 0x2f, 0x63, 0x27, 0xcb, 0xa6, 0x51, 0x1b, + 0x1b, 0x22, 0xe1, 0x15, 0xf9, 0xcb, 0x2c, 0x35, 0xce, 0x91, 0x6a, 0x7d, 0xd7, 0xc5, 0x6a, 0x45, 0xdb, 0x84, 0x55, + 0x88, 0x50, 0xb7, 0x0d, 0x95, 0x4b, 0x61, 0x36, 0x36, 0x4d, 0x03, 0x7c, 0xa1, 0xa8, 0x54, 0xca, 0x53, 0x5b, 0xa9, + 0xe4, 0x84, 0x77, 0x7d, 0x55, 0x8b, 0xd4, 0x15, 0xc1, 0x36, 0x66, 0xa8, 0x87, 0x72, 0xa3, 0xc6, 0xbe, 0xee, 0x58, + 0xa5, 0x77, 0x98, 0xa0, 0x62, 0xe4, 0x45, 0x0e, 0x2e, 0x4a, 0x0a, 0x32, 0x57, 0x43, 0x98, 0x3f, 0x6a, 0xf8, 0xb4, + 0xb0, 0xdc, 0x43, 0x09, 0x98, 0x1d, 0x35, 0xbc, 0x8c, 0x10, 0x88, 0xb8, 0x54, 0xf6, 0x15, 0x13, 0xbf, 0xa7, 0x60, + 0x96, 0x4c, 0xe8, 0x5e, 0xc4, 0xc2, 0x08, 0x6d, 0x7c, 0x92, 0x24, 0x53, 0xb9, 0x3e, 0x41, 0x17, 0x2a, 0x5c, 0x20, + 0x23, 0xb4, 0x48, 0xf3, 0x4f, 0x87, 0x53, 0x09, 0x3e, 0xa2, 0x4e, 0x01, 0xc7, 0xf3, 0xcb, 0xc2, 0xfa, 0xc9, 0x2a, + 0x89, 0xb9, 0xac, 0xcd, 0x7f, 0xd9, 0xc9, 0x31, 0xd8, 0xe5, 0x69, 0xe2, 0xb8, 0xfa, 0x8f, 0xaa, 0xa4, 0x78, 0xf8, + 0x39, 0xcd, 0x01, 0x45, 0x30, 0xb3, 0xa7, 0x18, 0x1f, 0xfb, 0x2c, 0x53, 0xc0, 0xdf, 0xae, 0xb7, 0x96, 0x4c, 0xec, + 0x92, 0x76, 0x2b, 0x65, 0xfc, 0x52, 0x1b, 0x76, 0x1c, 0x5c, 0x1a, 0x80, 0xe2, 0xac, 0xd1, 0x61, 0x79, 0xad, 0xdb, + 0x56, 0x8e, 0x0a, 0xd4, 0xfa, 0xdf, 0xbb, 0x85, 0x29, 0x6f, 0xf3, 0x52, 0x79, 0x9b, 0x87, 0x26, 0x40, 0x20, 0x32, + 0x43, 0x9e, 0x35, 0x1d, 0x93, 0xc4, 0xbd, 0x23, 0x25, 0xed, 0x3b, 0x52, 0xfc, 0xe8, 0x1d, 0x09, 0xf9, 0x96, 0xd0, + 0x91, 0x7d, 0xc9, 0xc9, 0x09, 0x94, 0x19, 0xec, 0xe5, 0x0d, 0x93, 0xfd, 0x03, 0xda, 0x0b, 0xe7, 0xb2, 0xbc, 0xe6, + 0x6f, 0x85, 0xb7, 0xf1, 0xa7, 0x9b, 0xf3, 0xae, 0xaa, 0x77, 0x5f, 0x99, 0x99, 0xc7, 0x63, 0x71, 0x3c, 0xe6, 0x26, + 0x68, 0x77, 0xc1, 0xc5, 0xa0, 0x62, 0xf7, 0x6e, 0x7c, 0xfc, 0x5b, 0x8e, 0x22, 0xb6, 0x52, 0x1e, 0x49, 0x17, 0x2a, + 0x31, 0xbc, 0x36, 0xf0, 0x30, 0x7b, 0x3e, 0x9e, 0xec, 0x6f, 0xee, 0x27, 0x83, 0xc1, 0x5e, 0xf5, 0xed, 0x8e, 0xd7, + 0xb3, 0xfd, 0x9c, 0x3d, 0xf0, 0xbb, 0xe9, 0x2e, 0x38, 0x34, 0xb0, 0xed, 0xee, 0x6f, 0xc4, 0xf1, 0xb8, 0x7f, 0xce, + 0x17, 0xfe, 0xe1, 0x01, 0x01, 0x9d, 0xf9, 0xe5, 0xb8, 0x8d, 0xf1, 0x73, 0xdb, 0x76, 0xd5, 0xda, 0x03, 0x3c, 0xfd, + 0x8f, 0xde, 0xed, 0x6c, 0x39, 0xf7, 0xd9, 0x13, 0xfe, 0x00, 0xfe, 0xf9, 0xb8, 0x49, 0x22, 0xf5, 0x89, 0x76, 0x99, + 0xbc, 0x05, 0x07, 0xf2, 0xbd, 0xcf, 0xde, 0xf0, 0x87, 0xd9, 0x72, 0xce, 0x8b, 0xe3, 0xf1, 0xfd, 0x34, 0x44, 0xb2, + 0xa6, 0xb0, 0x22, 0x96, 0x14, 0xcf, 0x0f, 0xc2, 0xd3, 0xf7, 0x22, 0x32, 0x44, 0x5a, 0xee, 0xdd, 0x21, 0xbb, 0x65, + 0x91, 0x1f, 0xc0, 0x07, 0xd9, 0xde, 0x9f, 0xc8, 0x9a, 0xd2, 0xfd, 0xe2, 0x89, 0x7f, 0x3c, 0xd2, 0x5f, 0x6f, 0xfc, + 0xe3, 0xf1, 0x3d, 0x7b, 0x40, 0x70, 0x74, 0xbe, 0x87, 0xfe, 0xd1, 0xb7, 0x0e, 0xa8, 0xca, 0xf0, 0xed, 0x6c, 0x3b, + 0xf7, 0x9f, 0xaf, 0xd9, 0x0a, 0xb8, 0x50, 0x94, 0x17, 0xda, 0x2d, 0x7b, 0x40, 0xaf, 0x33, 0x72, 0x22, 0x9a, 0xed, + 0xe7, 0x3e, 0x8b, 0xf1, 0xb9, 0xba, 0x2f, 0x26, 0x5f, 0xbd, 0x2f, 0xee, 0xd9, 0xae, 0xfb, 0xbe, 0x28, 0xdf, 0x74, + 0xd7, 0xcf, 0x8e, 0xed, 0xd9, 0x03, 0xcc, 0xb0, 0xb7, 0xfc, 0xb6, 0x39, 0x75, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, + 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0xb9, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x97, 0xde, + 0xa2, 0xd4, 0x45, 0x4f, 0xfb, 0x14, 0xe4, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x7c, + 0xa6, 0x1d, 0x3d, 0xaf, 0xbf, 0xed, 0x3d, 0x93, 0xdf, 0xc8, 0xc0, 0x16, 0x22, 0x29, 0x1c, 0xc7, 0x57, 0xcf, 0xce, + 0xf8, 0xaf, 0x5a, 0x1e, 0xb5, 0xda, 0x2f, 0x94, 0xfa, 0xf4, 0x25, 0x1d, 0xd1, 0xc4, 0xbd, 0x68, 0xcb, 0xb0, 0x46, + 0x59, 0x53, 0x4b, 0x87, 0x61, 0x5c, 0xc3, 0xbe, 0x3c, 0x70, 0xe8, 0x3b, 0x20, 0xd0, 0xe6, 0xa9, 0x14, 0x68, 0xe1, + 0x18, 0x46, 0x61, 0x16, 0x52, 0x1e, 0x17, 0x66, 0x29, 0xef, 0xa9, 0x40, 0x8b, 0x5b, 0x75, 0x8f, 0xa9, 0xed, 0x16, + 0x44, 0x58, 0xbd, 0x65, 0x5c, 0x5e, 0x37, 0xaa, 0x70, 0x5b, 0x80, 0xa2, 0x08, 0xca, 0xe0, 0x40, 0x72, 0xdb, 0x42, + 0x49, 0xb3, 0x51, 0x58, 0x8b, 0x55, 0x51, 0xee, 0x7b, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, + 0x75, 0x28, 0x17, 0xe9, 0xbf, 0x65, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xfb, 0x97, + 0xf4, 0xb3, 0xc1, 0x32, 0x72, 0x4a, 0xfd, 0x10, 0x8d, 0xee, 0xd2, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, + 0x0a, 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, + 0x26, 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, + 0x90, 0xdc, 0xa9, 0x73, 0x7f, 0x54, 0x4e, 0xfe, 0x1d, 0x0d, 0x91, 0x57, 0xdc, 0x20, 0x56, 0x16, 0x5c, 0x62, 0x31, + 0x54, 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xc7, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, + 0x13, 0x3e, 0x6e, 0xad, 0x45, 0x88, 0x3a, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, + 0x14, 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xc8, 0x49, 0xcf, 0x5f, 0x9a, 0x14, 0x65, + 0xcc, 0xf8, 0x20, 0xca, 0x48, 0xe4, 0x75, 0xb8, 0x12, 0xd3, 0x02, 0xf9, 0x46, 0x4f, 0x1f, 0x04, 0xd7, 0xf0, 0x6e, + 0xc8, 0xbd, 0x02, 0x6c, 0x09, 0xd8, 0x01, 0xee, 0x95, 0x19, 0xe5, 0x3a, 0xad, 0xeb, 0xb7, 0xd6, 0x43, 0x31, 0x0c, + 0x9f, 0x5a, 0x02, 0xdb, 0xc9, 0x3a, 0x3a, 0xd1, 0xc3, 0x87, 0xff, 0x75, 0x55, 0x73, 0xd4, 0xa9, 0x5c, 0xce, 0x4e, + 0x27, 0x2c, 0x45, 0xcc, 0xa0, 0xfb, 0xeb, 0xee, 0xa5, 0x00, 0xba, 0x5d, 0x16, 0xf3, 0x6c, 0xb4, 0x97, 0x7f, 0x4b, + 0x37, 0x56, 0x94, 0x36, 0xf1, 0x2e, 0xeb, 0x8d, 0xfd, 0xe1, 0xe8, 0x3f, 0x9e, 0xbe, 0x9b, 0x10, 0xaa, 0xce, 0x96, + 0x6d, 0x74, 0x9c, 0xcb, 0xff, 0xfa, 0xcf, 0x31, 0x59, 0x41, 0x50, 0x10, 0x96, 0x9d, 0x62, 0xa2, 0x82, 0x51, 0xa4, + 0xd8, 0xf0, 0xf1, 0x64, 0x83, 0x3a, 0xe1, 0x8d, 0xbf, 0xd4, 0x3a, 0x61, 0x62, 0x64, 0xa5, 0xf2, 0x37, 0x2c, 0x67, + 0x2b, 0x95, 0x59, 0x40, 0xe6, 0x41, 0x35, 0xd9, 0x18, 0x0d, 0xe6, 0x9a, 0xd7, 0xb3, 0xcd, 0x5c, 0x2a, 0x9f, 0xc1, + 0x94, 0xb3, 0x1c, 0x9c, 0x2d, 0x85, 0xdd, 0x93, 0x40, 0xd1, 0x9a, 0xa1, 0x1b, 0x7f, 0x8a, 0xad, 0x7a, 0x95, 0x56, + 0x35, 0xc0, 0x03, 0x42, 0x0c, 0x0c, 0xb5, 0x57, 0x0b, 0x0f, 0xad, 0x05, 0xb0, 0xf1, 0x47, 0xa5, 0x1f, 0x8c, 0x27, + 0x4b, 0xbe, 0x40, 0xfe, 0xe5, 0xc8, 0x51, 0xbb, 0xf7, 0xfb, 0xde, 0x3d, 0x48, 0xc1, 0x91, 0x6b, 0xa1, 0x40, 0x22, + 0xa0, 0x05, 0xdf, 0xfa, 0xca, 0x07, 0xe3, 0x2d, 0x6a, 0xab, 0x41, 0x41, 0xed, 0xe8, 0x96, 0xc7, 0x8e, 0xde, 0xf9, + 0xfe, 0x8c, 0xbe, 0x7a, 0xa1, 0x85, 0xe3, 0xaf, 0x9c, 0x91, 0x1b, 0xb6, 0xee, 0x90, 0x23, 0x9a, 0x49, 0x87, 0x10, + 0xb1, 0x66, 0x1b, 0xf6, 0x96, 0x54, 0xce, 0x9d, 0x43, 0x76, 0xfe, 0x08, 0x55, 0x7a, 0xad, 0xc7, 0xb7, 0x13, 0xa5, + 0xbb, 0x3d, 0xdd, 0x4d, 0xbe, 0x65, 0x13, 0x11, 0x83, 0x01, 0x6d, 0x10, 0xce, 0xc8, 0x3a, 0x44, 0x2a, 0x1d, 0x20, + 0x04, 0x8e, 0x09, 0x68, 0xfa, 0xf7, 0xaf, 0x49, 0x14, 0x70, 0xa4, 0x8d, 0x90, 0xb5, 0xec, 0x78, 0xac, 0x40, 0xa3, + 0xdc, 0xfc, 0xe1, 0x15, 0xea, 0x34, 0x07, 0xe6, 0xe9, 0x12, 0xf6, 0x1c, 0x3c, 0xd2, 0x8b, 0xd3, 0x23, 0xfd, 0xbf, + 0xa3, 0x89, 0x1a, 0xff, 0xfb, 0x9a, 0x28, 0xa5, 0x45, 0x72, 0x54, 0x4b, 0xdf, 0xa4, 0x8e, 0x82, 0x8b, 0xbc, 0xa3, + 0x16, 0xb2, 0x67, 0xd9, 0xb8, 0x51, 0xcd, 0xfb, 0xff, 0xb5, 0x32, 0xff, 0x5f, 0xd3, 0xca, 0x30, 0x25, 0x3b, 0x96, + 0x6a, 0xe6, 0x81, 0x56, 0x31, 0xcc, 0x7e, 0x26, 0x09, 0x91, 0xe1, 0xd2, 0x80, 0x1f, 0x55, 0x70, 0x88, 0xd3, 0x6a, + 0x93, 0x85, 0x7b, 0x54, 0xa2, 0xde, 0x89, 0x55, 0x9a, 0xbf, 0xa8, 0xff, 0x25, 0xca, 0x02, 0xa6, 0xf6, 0xaa, 0x4c, + 0xe3, 0x80, 0x2c, 0xfc, 0x59, 0x58, 0xe2, 0xe4, 0xc6, 0x36, 0xfe, 0x2c, 0xc7, 0xd3, 0x7e, 0xd5, 0x99, 0x79, 0x20, + 0x81, 0x1a, 0x88, 0x3f, 0x72, 0x2e, 0x2b, 0x8b, 0x07, 0x84, 0x6e, 0xfe, 0xb1, 0x2c, 0x8b, 0xd2, 0xeb, 0x7d, 0x4a, + 0xd2, 0xea, 0x62, 0x2d, 0xea, 0xa4, 0x88, 0x15, 0x94, 0x4d, 0x0a, 0x30, 0xfa, 0xb0, 0xf2, 0x44, 0x1c, 0x5c, 0x20, + 0x50, 0xc3, 0x45, 0x9d, 0x84, 0x00, 0x34, 0xac, 0x10, 0xf6, 0x2f, 0xa0, 0x85, 0x17, 0x61, 0x1c, 0x6e, 0x00, 0x26, + 0x27, 0xad, 0x2e, 0x36, 0x65, 0x71, 0x9f, 0xc6, 0x22, 0x1e, 0xf5, 0x14, 0x25, 0xcb, 0xc7, 0xca, 0x95, 0x73, 0xfd, + 0xc3, 0x1f, 0x14, 0xc0, 0x6e, 0xc0, 0x6c, 0x5b, 0x60, 0x07, 0x00, 0x09, 0x0a, 0x64, 0x0b, 0x75, 0x1a, 0x5d, 0xa8, + 0xa5, 0x02, 0xef, 0xb9, 0x1e, 0xe0, 0x1f, 0x2b, 0xc0, 0x32, 0xae, 0x0b, 0x19, 0x30, 0x82, 0x00, 0x46, 0xe0, 0xa0, + 0x04, 0x0c, 0x9d, 0x61, 0x6d, 0xf1, 0xb8, 0x43, 0x73, 0xa5, 0xdb, 0x92, 0x9b, 0x46, 0x39, 0x5b, 0x89, 0x00, 0xfa, + 0xea, 0xa6, 0xc4, 0xe9, 0x72, 0xd9, 0x4a, 0xc2, 0xbe, 0x7d, 0xdf, 0x4e, 0x15, 0x79, 0x7c, 0x92, 0x86, 0xbc, 0x02, + 0x4f, 0x32, 0x8e, 0x24, 0x51, 0x22, 0xf8, 0x58, 0x35, 0x66, 0x1c, 0x5e, 0xb4, 0x29, 0xa7, 0x0e, 0x66, 0xbd, 0x00, + 0x9c, 0x27, 0x68, 0xcb, 0x00, 0x63, 0x01, 0x83, 0x73, 0x21, 0x96, 0x3c, 0x45, 0xf0, 0x4b, 0x27, 0x52, 0x18, 0x77, + 0x39, 0x0c, 0xf3, 0xa0, 0xe8, 0x5d, 0x52, 0x7f, 0xf4, 0xfb, 0xa8, 0x4d, 0x06, 0x43, 0x50, 0x09, 0xa0, 0xb2, 0x6e, + 0x90, 0x18, 0x58, 0x95, 0x16, 0x12, 0x97, 0x10, 0x2f, 0xf3, 0xd5, 0xb4, 0x8e, 0x82, 0xf7, 0xf5, 0x84, 0x10, 0x4e, + 0x30, 0x3e, 0xc4, 0x0d, 0x10, 0x30, 0x58, 0xc5, 0x05, 0x06, 0xc9, 0x73, 0x89, 0xee, 0x8f, 0xe7, 0x3b, 0x06, 0xb8, + 0x72, 0xde, 0x53, 0xed, 0xea, 0x81, 0xbd, 0x5c, 0xa5, 0x4b, 0x46, 0x08, 0x2b, 0xfe, 0x2f, 0x22, 0xef, 0xdb, 0x61, + 0x02, 0x6a, 0x1b, 0xf9, 0x63, 0x90, 0x98, 0xcb, 0x44, 0x11, 0xc4, 0xa3, 0xac, 0x60, 0x49, 0x1a, 0x6c, 0x47, 0x49, + 0x0a, 0x1a, 0x4d, 0x8c, 0x21, 0x53, 0xa1, 0x1d, 0x92, 0x46, 0xb3, 0x31, 0xd9, 0xc7, 0x90, 0xd7, 0x70, 0xb1, 0x58, + 0xe0, 0x7d, 0x3f, 0x0b, 0xd5, 0xc1, 0xb6, 0x34, 0x87, 0x80, 0x93, 0x04, 0x7b, 0xea, 0x8a, 0x94, 0x84, 0xd9, 0xe8, + 0x53, 0xc8, 0xb9, 0x01, 0x1d, 0x27, 0x8d, 0xa1, 0xfa, 0xc0, 0x24, 0xbc, 0x89, 0xd0, 0x49, 0x59, 0x21, 0x2c, 0xe0, + 0xbe, 0x91, 0xd1, 0x68, 0x25, 0x0d, 0x02, 0x6f, 0x33, 0x6c, 0x05, 0x36, 0xa1, 0xe1, 0x2f, 0x32, 0x0f, 0xd3, 0x6a, + 0x56, 0x82, 0x39, 0xdf, 0x40, 0x25, 0xc6, 0x93, 0xe5, 0x0d, 0xdf, 0xba, 0x58, 0x89, 0xc9, 0x6c, 0x39, 0x9f, 0x6c, + 0x24, 0xd5, 0x1c, 0x08, 0x19, 0x19, 0x5b, 0xc2, 0xfe, 0x61, 0x60, 0x28, 0x1d, 0xd8, 0xd1, 0x54, 0xd3, 0x26, 0x01, + 0x26, 0xd3, 0x25, 0xe7, 0xc3, 0x6b, 0x44, 0x93, 0xd5, 0xa9, 0x7b, 0x99, 0xaa, 0x76, 0x70, 0x4d, 0xce, 0xe4, 0xf4, + 0x48, 0x3d, 0xd5, 0xba, 0x97, 0x6a, 0xb4, 0x1b, 0xe6, 0xa3, 0x9d, 0x1f, 0x80, 0x5b, 0xa7, 0xb0, 0xd3, 0xf7, 0xc3, + 0x7c, 0xb4, 0xf7, 0x35, 0xec, 0x2e, 0x29, 0x04, 0xaa, 0x3f, 0xcb, 0x9a, 0xcc, 0xc5, 0x9b, 0xe2, 0xc1, 0x2b, 0xd8, + 0x33, 0x7f, 0xa0, 0x7f, 0x95, 0xec, 0x99, 0x6f, 0x33, 0xb9, 0xfe, 0x99, 0x76, 0x8d, 0xc6, 0x4c, 0xc7, 0x6b, 0xe7, + 0x60, 0x85, 0x06, 0xc8, 0x2f, 0xd8, 0xd1, 0xde, 0xe4, 0x20, 0x10, 0xa0, 0x7b, 0x09, 0x8e, 0xa2, 0x80, 0xa8, 0x69, + 0x55, 0x79, 0x74, 0xba, 0xf7, 0x0f, 0xf8, 0x46, 0x09, 0xd8, 0xe4, 0xa9, 0x75, 0x6f, 0x19, 0xfb, 0xc7, 0x23, 0x84, + 0xd0, 0xcb, 0xe9, 0x37, 0xda, 0xb1, 0x7a, 0xb4, 0x67, 0x12, 0xfc, 0x1c, 0x31, 0xe9, 0x15, 0x8c, 0x61, 0xe8, 0xc2, + 0x2a, 0x46, 0xf2, 0x0c, 0xc8, 0x1a, 0xbf, 0x41, 0x74, 0x01, 0x8b, 0x5e, 0xef, 0xd5, 0x09, 0x0d, 0x22, 0xa0, 0xd2, + 0x6b, 0xfe, 0x52, 0xe4, 0x73, 0x55, 0x88, 0xde, 0x07, 0x6b, 0xe7, 0xcd, 0x8c, 0x64, 0x99, 0x34, 0x52, 0xed, 0x56, + 0x16, 0x9b, 0xca, 0x9b, 0x9d, 0x91, 0x2e, 0xe6, 0x18, 0x2a, 0x83, 0xc7, 0x01, 0x28, 0x3d, 0xff, 0x12, 0x7a, 0x25, + 0x43, 0xa6, 0x59, 0xa2, 0x99, 0xdd, 0x37, 0xfe, 0x64, 0x9d, 0x7a, 0x31, 0x22, 0x66, 0x03, 0x5b, 0x88, 0xdb, 0xa2, + 0xd2, 0x6d, 0x51, 0x28, 0x5b, 0x14, 0xe9, 0x43, 0xed, 0x42, 0x77, 0x66, 0xe1, 0xb3, 0xdc, 0xb4, 0xef, 0x4d, 0x66, + 0xc6, 0x06, 0x68, 0xbb, 0x08, 0xdf, 0x40, 0x07, 0x2a, 0x84, 0xfc, 0x47, 0x44, 0x44, 0x22, 0x60, 0x97, 0x73, 0x77, + 0x62, 0xd3, 0x21, 0x99, 0x87, 0x98, 0x15, 0x6a, 0x94, 0x97, 0x3c, 0x39, 0x19, 0x90, 0x9c, 0x50, 0xb7, 0xfb, 0xfd, + 0xcb, 0xa5, 0x0b, 0x6a, 0xbf, 0xa1, 0xd8, 0x31, 0xba, 0x29, 0xe0, 0x5c, 0xf0, 0x28, 0xef, 0xa5, 0x77, 0x09, 0x68, + 0x8e, 0xed, 0x29, 0xb2, 0x01, 0x9c, 0xde, 0x76, 0x21, 0xc0, 0xf6, 0x59, 0xb3, 0x8d, 0x3f, 0x59, 0xdf, 0x44, 0x53, + 0xaf, 0xe4, 0x33, 0xdd, 0x45, 0x89, 0xdb, 0x45, 0xb1, 0xec, 0xa2, 0x6d, 0x03, 0xc1, 0x8e, 0x6b, 0x3f, 0x00, 0xde, + 0xd0, 0xa8, 0xdf, 0x2f, 0x5b, 0x3d, 0x7b, 0xf6, 0xb5, 0xd3, 0x9e, 0xcd, 0x7c, 0x56, 0x9a, 0x9e, 0xfd, 0x35, 0x75, + 0x7b, 0x56, 0x4e, 0xf6, 0xa2, 0x73, 0xb2, 0x4f, 0x67, 0xf3, 0x40, 0x70, 0xb9, 0x73, 0x5f, 0x56, 0x53, 0x3d, 0xed, + 0x72, 0x3f, 0x68, 0x0d, 0x91, 0xf9, 0xc2, 0xa7, 0xbc, 0x7b, 0x5d, 0xc1, 0x02, 0x96, 0xe0, 0x6e, 0xbd, 0x34, 0xff, + 0x15, 0xbb, 0xbf, 0x17, 0xf4, 0xd2, 0xfc, 0x37, 0xfa, 0x93, 0x02, 0x38, 0x00, 0x8d, 0xa9, 0xdd, 0x02, 0x0f, 0x31, + 0x54, 0x50, 0xb8, 0x9b, 0x95, 0x73, 0xaf, 0x06, 0x38, 0x4c, 0xd2, 0x37, 0xb4, 0x7a, 0xa5, 0xc5, 0xae, 0x97, 0xc9, + 0x5e, 0x01, 0x1e, 0xaa, 0x90, 0x87, 0xc7, 0x63, 0xd4, 0x31, 0xec, 0xa0, 0x8e, 0x80, 0x61, 0x0f, 0xa1, 0xb1, 0x05, + 0x9e, 0x8f, 0x9f, 0x32, 0x7e, 0x10, 0xa0, 0x36, 0x42, 0x78, 0xbc, 0x5a, 0x94, 0x21, 0xb6, 0xec, 0x0d, 0x52, 0x49, + 0xfd, 0x2c, 0x10, 0x65, 0xb4, 0x0a, 0x68, 0xab, 0x3d, 0x65, 0x69, 0xbc, 0x85, 0x50, 0xb1, 0xd4, 0xc7, 0x10, 0x1a, + 0x38, 0xfc, 0x8e, 0x47, 0x90, 0xe0, 0x4b, 0xae, 0xc9, 0xe6, 0xde, 0xe4, 0xf7, 0xb4, 0xcf, 0x1f, 0x8f, 0x97, 0xd7, + 0x08, 0x4a, 0x97, 0xc2, 0x47, 0x2a, 0x11, 0xd5, 0x53, 0xdc, 0x94, 0x90, 0xcd, 0x92, 0x95, 0x7e, 0xf0, 0xab, 0xfa, + 0x05, 0x00, 0xb2, 0x10, 0x68, 0x13, 0x99, 0xfd, 0xe9, 0x42, 0x45, 0x17, 0x00, 0x87, 0xf8, 0xe3, 0x27, 0x88, 0xbe, + 0xa1, 0x65, 0x5a, 0x3e, 0x4e, 0x78, 0x08, 0x5a, 0x5b, 0xd2, 0x49, 0xc4, 0x4a, 0x81, 0x0d, 0x91, 0xf0, 0xfd, 0xfe, + 0x65, 0x2c, 0xe9, 0x40, 0xa3, 0x56, 0xf7, 0xc6, 0xad, 0xee, 0x95, 0xaf, 0xeb, 0x4e, 0x6e, 0x7c, 0x50, 0xb4, 0xcf, + 0xe6, 0x8d, 0xca, 0xf7, 0x6d, 0x9d, 0xb3, 0x3f, 0xdf, 0x3b, 0x72, 0x4e, 0x7c, 0x7b, 0x0f, 0xa1, 0xe8, 0xa1, 0x29, + 0xb2, 0x2c, 0x09, 0x03, 0x5a, 0x6b, 0xd7, 0x9e, 0x65, 0x74, 0xf0, 0xda, 0x37, 0x84, 0x88, 0x3c, 0xc5, 0x27, 0x21, + 0xb7, 0x38, 0x3e, 0x28, 0xd0, 0x3f, 0x33, 0xfe, 0xcc, 0x89, 0x1f, 0xb6, 0xfa, 0x05, 0x70, 0x6e, 0xba, 0xf7, 0xee, + 0xc4, 0xac, 0xc7, 0x50, 0xca, 0xc6, 0xff, 0xfd, 0x3e, 0x91, 0x05, 0x3a, 0x1d, 0xd1, 0x30, 0x10, 0xdc, 0x45, 0xf5, + 0x7f, 0xaf, 0x78, 0xdd, 0xb3, 0x56, 0xe7, 0xcb, 0x4f, 0x9d, 0x9f, 0xf4, 0xea, 0x65, 0xdc, 0x03, 0x72, 0x74, 0x80, + 0x70, 0x5e, 0xf7, 0x1b, 0xb6, 0xff, 0xe6, 0x97, 0xf7, 0x27, 0x2f, 0x03, 0x9b, 0x14, 0x89, 0x6d, 0x25, 0x9f, 0xf5, + 0x40, 0xe1, 0xd7, 0x63, 0xbd, 0xba, 0xd8, 0xf4, 0x58, 0x0f, 0xb5, 0x80, 0xe8, 0x61, 0x01, 0xea, 0xbf, 0x9e, 0x7d, + 0x1a, 0x0a, 0x07, 0xd9, 0x38, 0x55, 0xa0, 0xc8, 0x82, 0x3f, 0x17, 0xa3, 0x4d, 0x41, 0x80, 0xc8, 0x96, 0x90, 0x96, + 0x9f, 0xcd, 0x1e, 0x97, 0x5a, 0x92, 0xc1, 0x37, 0x01, 0x99, 0x1d, 0x58, 0x39, 0x41, 0xe9, 0xb8, 0x33, 0xe0, 0xca, + 0x16, 0x8f, 0x76, 0xfb, 0xd3, 0x20, 0x3b, 0x6b, 0x4e, 0x1a, 0xed, 0xc3, 0x3e, 0x05, 0x4e, 0x1a, 0x10, 0x7b, 0x44, + 0xa0, 0xef, 0xb6, 0xb9, 0xf4, 0xd1, 0xe1, 0x9c, 0x17, 0xf2, 0xcf, 0xa9, 0xc4, 0xe0, 0x1e, 0x4a, 0xac, 0x81, 0x40, + 0xe5, 0x19, 0xaa, 0x1c, 0x36, 0xc8, 0xf1, 0xcf, 0x8e, 0x64, 0x26, 0x31, 0x59, 0xe4, 0x6e, 0xcd, 0x54, 0xf8, 0x81, + 0x00, 0xfe, 0x73, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x01, 0x7f, 0x4c, 0xe1, 0xe7, 0x3c, 0x85, + 0x9d, 0xf6, 0xb0, 0x29, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, 0x3f, + 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x75, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x05, 0x39, + 0xdb, 0x14, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xf2, 0x51, 0x5a, 0xfd, 0x55, 0xff, + 0x04, 0xe6, 0x6d, 0x2a, 0x46, 0xb5, 0x8a, 0xc9, 0x6f, 0xf4, 0xfb, 0xc5, 0xa0, 0xf5, 0x21, 0x83, 0x8f, 0x5e, 0x9b, + 0x06, 0x7f, 0x74, 0x1a, 0xec, 0x30, 0xd1, 0x08, 0x80, 0x64, 0x4e, 0x2d, 0x79, 0x28, 0xfa, 0x23, 0xa8, 0xb0, 0x46, + 0xb9, 0x53, 0x30, 0x58, 0xff, 0xf1, 0x68, 0x07, 0xa6, 0x5e, 0x1c, 0x6d, 0xc9, 0x0e, 0x9a, 0xfb, 0x06, 0xb8, 0x5f, + 0x23, 0x5b, 0xcc, 0x2a, 0x80, 0x66, 0xaf, 0x11, 0x19, 0x9f, 0xbc, 0x00, 0xc6, 0x6c, 0x93, 0x85, 0x91, 0x88, 0x83, + 0xb1, 0x6a, 0xcc, 0x98, 0x81, 0x81, 0x0b, 0x74, 0x2d, 0x93, 0x92, 0x34, 0xa4, 0x83, 0x01, 0x2b, 0x65, 0x0b, 0x07, + 0xbc, 0x68, 0x4e, 0xdb, 0xf1, 0xba, 0x45, 0xe3, 0x81, 0xed, 0x62, 0x87, 0xfb, 0x1f, 0x8a, 0xdd, 0xdb, 0x70, 0x47, + 0x7a, 0x85, 0x8a, 0x25, 0xf4, 0xf3, 0xaf, 0xb2, 0xcf, 0x1a, 0x4e, 0x4e, 0x85, 0x66, 0x68, 0x29, 0x12, 0x4a, 0xf1, + 0x4e, 0x4f, 0x0a, 0x8c, 0x65, 0x2c, 0xfc, 0x03, 0x70, 0x4e, 0x17, 0x8a, 0xc8, 0x1d, 0x38, 0x8e, 0x6f, 0xa1, 0x82, + 0x51, 0xc3, 0xc1, 0xcb, 0x18, 0xb6, 0x45, 0x31, 0x0b, 0x09, 0xa7, 0x10, 0x2e, 0x56, 0x59, 0xbf, 0x2f, 0x7f, 0x51, + 0x17, 0x5d, 0x65, 0xb2, 0xee, 0x93, 0x70, 0x64, 0xc6, 0x72, 0xea, 0x85, 0xe4, 0x79, 0xcf, 0x93, 0x69, 0xf2, 0xb4, + 0x0a, 0x22, 0x80, 0x7c, 0x0e, 0xef, 0xc3, 0x34, 0x03, 0xab, 0x34, 0x29, 0x3f, 0x42, 0xe9, 0x8b, 0xcf, 0x73, 0x3f, + 0xd0, 0xd9, 0x2b, 0x93, 0x0c, 0x6f, 0xe6, 0xad, 0x37, 0xa9, 0x75, 0x5d, 0x3c, 0xe0, 0xef, 0x9c, 0xc1, 0xc6, 0xb9, + 0xce, 0x04, 0x07, 0x5e, 0x24, 0xb5, 0x5e, 0x33, 0xfe, 0x3c, 0xc3, 0x75, 0xa9, 0xda, 0xe8, 0xa3, 0x10, 0x5d, 0x41, + 0xa6, 0x02, 0x14, 0x8a, 0xb4, 0x7f, 0x50, 0x6a, 0x6e, 0x52, 0x69, 0x23, 0x01, 0x74, 0x0f, 0x93, 0x06, 0x5b, 0x0c, + 0x65, 0x2c, 0x4d, 0xa2, 0xdc, 0x69, 0x10, 0x57, 0xf6, 0xe7, 0x5c, 0xe2, 0xd0, 0xb2, 0x48, 0xfe, 0xbd, 0xef, 0xe9, + 0x2b, 0xa4, 0xee, 0x64, 0x81, 0xcc, 0x18, 0x2f, 0xf2, 0xf8, 0x13, 0x10, 0x66, 0x83, 0x36, 0x2a, 0x0a, 0x21, 0x64, + 0x83, 0x18, 0x34, 0x5e, 0xe4, 0xf1, 0x0f, 0x8a, 0xc6, 0x43, 0x3e, 0x8a, 0x7c, 0xf5, 0x57, 0xa9, 0xff, 0x0a, 0x7d, + 0x66, 0x82, 0x47, 0xa8, 0x26, 0xfa, 0x77, 0xcf, 0x67, 0xf7, 0xa0, 0x36, 0x8c, 0xc2, 0xcc, 0x94, 0x9f, 0xfb, 0xa6, + 0x38, 0x7b, 0xfd, 0x15, 0x5d, 0x65, 0x5b, 0xf7, 0xa3, 0x8f, 0x27, 0x04, 0xd6, 0xc6, 0xe8, 0x8a, 0x1b, 0x03, 0xc8, + 0x61, 0xf2, 0x7e, 0x45, 0x69, 0x15, 0xa4, 0x41, 0xe8, 0xa0, 0x21, 0xe8, 0x95, 0x44, 0x1f, 0x48, 0x2c, 0x62, 0x0c, + 0x2f, 0xc4, 0x33, 0x52, 0x93, 0x89, 0x86, 0x78, 0x45, 0xec, 0x87, 0x68, 0xc9, 0xa9, 0x89, 0x6e, 0x84, 0x29, 0x06, + 0x12, 0x3b, 0x83, 0xe4, 0x24, 0xa9, 0x95, 0x5f, 0x3c, 0x93, 0x84, 0x25, 0x76, 0x1e, 0x62, 0x30, 0xa9, 0xa5, 0x3b, + 0xbd, 0xa9, 0xd2, 0x97, 0x13, 0x2d, 0x07, 0xed, 0x03, 0xb0, 0x4b, 0x49, 0xef, 0x9f, 0x14, 0x8a, 0xf8, 0x10, 0xc6, + 0x31, 0x84, 0x6f, 0x11, 0xd5, 0x15, 0x38, 0xd7, 0x0a, 0x34, 0x56, 0x03, 0x0f, 0xcd, 0x2c, 0x9f, 0x0f, 0x39, 0xfd, + 0x54, 0x5a, 0xfe, 0x18, 0xd1, 0xd8, 0x68, 0xdd, 0x1c, 0x8f, 0x07, 0x5a, 0xf5, 0xd2, 0x39, 0xe8, 0xba, 0x99, 0xc4, + 0xc4, 0x0d, 0xa4, 0xeb, 0x47, 0xbf, 0x99, 0xb0, 0x17, 0x51, 0x21, 0x97, 0x42, 0x50, 0xd0, 0xea, 0x40, 0xe0, 0x50, + 0x78, 0x8b, 0x32, 0x5f, 0xc5, 0xb4, 0x81, 0x30, 0xf8, 0xfc, 0x40, 0x7e, 0xbe, 0x29, 0x48, 0xc5, 0x8e, 0x75, 0xed, + 0xf7, 0xb7, 0xa5, 0x07, 0x78, 0x72, 0x26, 0xc9, 0xd3, 0x66, 0x08, 0x2b, 0x02, 0x68, 0xcc, 0x6a, 0xb2, 0x38, 0xe1, + 0xca, 0x1c, 0x7e, 0xcc, 0xbd, 0x92, 0xa5, 0x4c, 0x9d, 0xa7, 0x7a, 0x01, 0x44, 0x1d, 0x6f, 0xd0, 0x8a, 0xd4, 0xaf, + 0xd0, 0xd9, 0x6b, 0x56, 0x42, 0xc6, 0xc3, 0x4b, 0xce, 0xd3, 0xd1, 0x03, 0x4b, 0x78, 0x84, 0x7f, 0x25, 0x13, 0x7d, + 0xf8, 0x3d, 0x70, 0xb8, 0x19, 0x27, 0x3c, 0x72, 0x9b, 0x7d, 0xa8, 0xc2, 0x35, 0xdc, 0x4c, 0x0b, 0x40, 0x72, 0x0b, + 0x92, 0x26, 0xa0, 0x84, 0x44, 0x26, 0x64, 0xd6, 0x94, 0xfc, 0xdc, 0xd2, 0x36, 0x58, 0xc3, 0xa4, 0xf3, 0x80, 0x17, + 0xad, 0x3e, 0x5a, 0x4d, 0xb4, 0xcb, 0xac, 0x9a, 0x0f, 0x71, 0x86, 0x6a, 0x8e, 0xbb, 0x0b, 0xf8, 0x39, 0xe0, 0x39, + 0xcb, 0x9b, 0x74, 0xb4, 0x1f, 0x70, 0xe1, 0xc9, 0x75, 0x9e, 0x8e, 0x76, 0xf8, 0x4b, 0xee, 0x0f, 0x00, 0x1d, 0x4c, + 0x5d, 0x02, 0x7f, 0xaa, 0xb6, 0x9a, 0x4a, 0xfd, 0xd2, 0xda, 0xaf, 0xeb, 0xce, 0x6a, 0xc1, 0x19, 0xa2, 0x2f, 0x43, + 0x07, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, + 0x82, 0x7b, 0xc9, 0x9f, 0x1f, 0x10, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, + 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xa9, 0x34, 0x26, 0x45, 0x05, 0xe9, 0x9c, 0x0e, 0x37, 0xaf, 0x8e, 0xf3, 0x84, 0x65, 0x7c, 0xdc, 0x3e, 0x53, 0x20, 0xc4, 0x16, 0xcf, 0x90, - 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x38, 0xd4, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, - 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1a, 0xfe, 0x2e, 0x43, 0x75, 0x77, 0x08, - 0x4c, 0x6c, 0xd9, 0x81, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x1b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, - 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x11, 0x5e, 0x25, 0x5b, 0x79, 0x38, 0x24, 0xd6, 0x5d, 0xd8, 0xd1, - 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0xe4, 0x66, 0x17, 0x12, 0x83, 0x8a, 0xa5, 0xfa, - 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xd5, 0x71, 0x9f, 0x8a, 0xd1, 0x5a, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, - 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x5c, 0x1f, 0xc7, 0x87, 0x83, 0x14, 0x33, - 0x2e, 0x8f, 0xc4, 0x8c, 0xcb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xc3, 0xe1, 0x92, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, - 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4b, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x75, 0xea, 0x65, 0xe4, - 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x2a, 0xda, 0xad, 0x4b, 0x26, - 0xec, 0x2d, 0xa5, 0x92, 0x56, 0x79, 0xf9, 0x74, 0xe3, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, + 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x3c, 0xd6, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, + 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1b, 0xfe, 0x25, 0x43, 0x75, 0x77, 0x08, + 0x4c, 0x6c, 0xd9, 0x91, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x5b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, + 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x15, 0x5e, 0x2e, 0x5b, 0x79, 0x3c, 0x26, 0xd6, 0x5d, 0xd8, 0xd1, + 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0x54, 0x66, 0x17, 0x12, 0x83, 0x9c, 0xa5, 0xfa, + 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xf9, 0x69, 0x9f, 0x8a, 0xd1, 0x46, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, + 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x4a, 0x1f, 0xc7, 0xc7, 0xa3, 0x14, 0x33, + 0xae, 0x4f, 0xc4, 0x8c, 0xeb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xe3, 0xf1, 0x9a, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, + 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4d, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x4d, 0xea, 0x65, 0xe4, + 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x72, 0xda, 0xad, 0x4b, 0x26, + 0xec, 0x2d, 0x25, 0x97, 0x56, 0x79, 0xf9, 0x74, 0xeb, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, 0x12, 0xb5, 0x32, 0x4c, 0x16, 0xce, 0x4b, 0xa6, 0x9e, 0x0c, 0x78, 0xcc, 0x4a, 0x1e, 0xc9, 0x4e, 0x6f, 0x0c, 0x82, - 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x74, 0x95, 0x0b, 0x0c, 0xb7, 0x5b, 0xb3, 0x8d, - 0xaa, 0xb3, 0xdc, 0xd4, 0x2a, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0x37, 0x10, 0x8c, - 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x05, 0x96, 0xd2, 0xd1, 0x8e, 0x97, - 0xa8, 0x52, 0xf8, 0xbb, 0xe0, 0xfb, 0x30, 0x8e, 0xbf, 0x2f, 0xb6, 0xea, 0x40, 0xbc, 0x2d, 0xb6, 0x48, 0xfb, 0x22, + 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x7c, 0x95, 0x0b, 0x0c, 0xb7, 0xdb, 0xb0, 0xad, + 0xaa, 0xb3, 0xdc, 0xd4, 0x72, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0xb7, 0x10, 0x8c, + 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x03, 0x96, 0xd2, 0xd1, 0x9e, 0x97, + 0xa8, 0x52, 0xf8, 0x9b, 0xe0, 0x87, 0x30, 0x8e, 0x7f, 0x28, 0x76, 0xea, 0x40, 0xbc, 0x2b, 0x76, 0x48, 0xfb, 0x22, 0xff, 0x42, 0x1c, 0xf0, 0x5a, 0xd7, 0x94, 0xd7, 0xd6, 0x9c, 0x06, 0xb6, 0x86, 0x91, 0x92, 0xc2, 0xb9, 0xf9, 0xf3, - 0x70, 0xa0, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x44, 0x09, 0x8e, 0x5c, - 0xf2, 0xaf, 0xc3, 0x41, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0xdb, 0x7f, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, + 0x78, 0xa4, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x45, 0x09, 0x7e, 0x13, + 0xf2, 0xaf, 0xe3, 0x51, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0x3b, 0x7c, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, 0x24, 0xff, 0x6a, 0x9a, 0x79, 0xc3, 0x64, 0xcd, 0x14, 0x8e, 0x43, 0xc3, 0x08, 0x69, 0x40, 0xb7, 0x41, 0x6d, 0x78, - 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0x97, 0x13, 0x71, 0x4e, 0x97, 0x24, 0xf5, 0x54, 0x42, - 0x49, 0x08, 0x76, 0xe9, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, - 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xab, - 0x78, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8a, 0x4d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, - 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xac, 0xe4, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, - 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0x1f, 0x55, 0x36, 0x76, 0x07, 0xe4, 0x90, 0x64, 0xb2, 0xb8, 0x1b, 0xdd, - 0x8a, 0x65, 0x51, 0x8a, 0x9f, 0xb1, 0x1e, 0xae, 0xd9, 0xc2, 0x7d, 0x06, 0x84, 0xf6, 0x13, 0xa5, 0xbd, 0x89, 0x34, - 0x41, 0xf7, 0x1d, 0x5b, 0x01, 0xc8, 0x00, 0x8a, 0xba, 0xda, 0xad, 0xcf, 0xf9, 0x39, 0x92, 0x66, 0x38, 0x8c, 0x6e, - 0x9f, 0xde, 0x05, 0x77, 0x83, 0x4b, 0xd4, 0x4a, 0x5f, 0xb2, 0xb8, 0x85, 0x41, 0xb5, 0x37, 0x4b, 0x38, 0xa8, 0x99, - 0xb5, 0x36, 0x02, 0xc1, 0x64, 0x0f, 0x05, 0x15, 0x73, 0x05, 0xfb, 0xa0, 0x60, 0x2d, 0x79, 0x1d, 0x1c, 0x6e, 0xed, - 0xcb, 0x4a, 0x71, 0xf1, 0xfc, 0x22, 0x69, 0x5d, 0x58, 0xca, 0x8b, 0xe7, 0x0d, 0x18, 0x5c, 0x8e, 0xb0, 0xa9, 0x2a, - 0x7f, 0xb2, 0x01, 0xd0, 0xad, 0x90, 0x22, 0x5e, 0x94, 0xc2, 0xb6, 0x95, 0xcf, 0x9c, 0xb0, 0xc1, 0x86, 0x3d, 0xc0, - 0xbd, 0x32, 0x28, 0x19, 0x5c, 0x88, 0x71, 0xbb, 0xd9, 0x05, 0xb8, 0x82, 0xa1, 0x30, 0xb6, 0xe6, 0x6f, 0x32, 0x2f, - 0x52, 0x02, 0x6e, 0x86, 0x28, 0x5f, 0x1b, 0x38, 0x99, 0xf4, 0xe4, 0x5a, 0xb2, 0x18, 0xb0, 0xa0, 0xc1, 0x77, 0xd4, - 0xfa, 0x3b, 0x93, 0x7f, 0xe3, 0xe9, 0xa1, 0x1f, 0x7c, 0xce, 0xbc, 0xa5, 0xcf, 0xde, 0x54, 0x32, 0x5a, 0x93, 0x44, - 0x79, 0xf5, 0x70, 0x09, 0x72, 0xc3, 0x72, 0xf4, 0xc0, 0x96, 0x20, 0x4e, 0x2c, 0x47, 0x09, 0x65, 0x74, 0x85, 0x7b, - 0x95, 0xd9, 0x32, 0x11, 0x48, 0x71, 0x60, 0x29, 0xe5, 0xde, 0x62, 0x1d, 0x2c, 0x71, 0x7f, 0x22, 0xb9, 0x80, 0x92, - 0x07, 0x50, 0xae, 0x14, 0x10, 0xf0, 0xe9, 0x00, 0xca, 0x97, 0xf2, 0x22, 0xfc, 0x89, 0x13, 0x35, 0x58, 0x8e, 0x1e, - 0x1a, 0xf6, 0xa3, 0x17, 0x5a, 0xf6, 0x87, 0x3b, 0xad, 0x69, 0x58, 0xf1, 0x3b, 0x98, 0x16, 0x13, 0xb7, 0x2f, 0x57, - 0x76, 0x55, 0x7c, 0xb6, 0x52, 0x67, 0x37, 0x35, 0x24, 0x61, 0x5f, 0x91, 0x55, 0x80, 0x83, 0x55, 0x11, 0xf7, 0x2c, - 0xcb, 0x7d, 0x18, 0xfd, 0xb9, 0x49, 0x4b, 0x61, 0xa1, 0x4a, 0xfa, 0xfb, 0xa6, 0x14, 0x48, 0x65, 0xa2, 0x13, 0x2d, - 0x04, 0x57, 0x60, 0x10, 0xb8, 0x17, 0x79, 0x0d, 0x80, 0x31, 0xe0, 0x52, 0xa0, 0x2c, 0xdb, 0x12, 0x42, 0xaa, 0xfb, - 0x19, 0xa8, 0xed, 0xc4, 0x7d, 0x1a, 0x91, 0xb5, 0x10, 0x7d, 0x15, 0x8c, 0x99, 0xf3, 0x52, 0xba, 0xc5, 0xa6, 0xab, - 0xcd, 0xea, 0x06, 0x9d, 0x4b, 0x5b, 0x6e, 0x7e, 0xc2, 0x16, 0x6b, 0x05, 0xca, 0x26, 0x24, 0x6d, 0xe7, 0x3c, 0x47, - 0xd9, 0x84, 0x96, 0xf6, 0x9e, 0x7a, 0x54, 0xa8, 0x4e, 0xb6, 0x5e, 0xaa, 0xa6, 0x16, 0x61, 0xb5, 0xb8, 0xa8, 0xfc, - 0x00, 0x74, 0x53, 0x69, 0xf5, 0xb2, 0xae, 0xd1, 0x14, 0x6a, 0xb5, 0x70, 0xdc, 0x68, 0x67, 0xd3, 0x65, 0x7a, 0x87, - 0x38, 0xab, 0xd2, 0x0e, 0xfd, 0x7d, 0xa6, 0x5d, 0x2f, 0x3b, 0xfa, 0xcd, 0xb8, 0xba, 0xc0, 0x85, 0xd8, 0x80, 0xcf, - 0xb9, 0xbf, 0xbc, 0xde, 0xf3, 0xb8, 0xe7, 0x1f, 0x0e, 0xc8, 0x9e, 0xd4, 0xfe, 0x50, 0x7d, 0xec, 0x0a, 0x86, 0x2c, - 0x8c, 0x52, 0x7f, 0x91, 0xf2, 0xde, 0x13, 0x1c, 0xf7, 0xcf, 0x55, 0x8f, 0xfd, 0x98, 0xf1, 0x7d, 0x5d, 0x6c, 0xa2, - 0x84, 0xa2, 0x1a, 0x7a, 0xab, 0x62, 0x53, 0x89, 0xb8, 0x78, 0xc8, 0x7b, 0x0c, 0x93, 0x61, 0x2c, 0x64, 0x2a, 0xfc, - 0x29, 0x53, 0xc1, 0x23, 0x84, 0x12, 0x37, 0xeb, 0x1e, 0x69, 0x37, 0x21, 0x4e, 0xa9, 0x16, 0xa5, 0x4c, 0xc6, 0xbf, - 0xf5, 0x13, 0x28, 0xcf, 0x29, 0x5a, 0xa6, 0x1f, 0x15, 0x2e, 0xd3, 0x37, 0xeb, 0xe3, 0xd2, 0x33, 0x11, 0xea, 0xcc, - 0xc5, 0xa6, 0xd6, 0xe9, 0x18, 0x3b, 0xa5, 0x53, 0x1b, 0xf6, 0xa5, 0x52, 0x5c, 0x56, 0x14, 0xfe, 0x8d, 0x44, 0x56, - 0x3d, 0x23, 0x8e, 0xff, 0x2b, 0x6b, 0x9f, 0x61, 0x15, 0xf8, 0x65, 0x20, 0xef, 0x17, 0x00, 0x1f, 0xd7, 0x75, 0x99, - 0xde, 0x6e, 0x80, 0x36, 0x84, 0x86, 0xbf, 0xe7, 0x23, 0x03, 0xa6, 0xfb, 0x08, 0x67, 0x48, 0x0f, 0x75, 0xce, 0xe9, - 0xac, 0x4c, 0xe7, 0x5c, 0x85, 0xb5, 0x04, 0x7b, 0x39, 0x69, 0x72, 0xb9, 0x2e, 0x41, 0xcd, 0x04, 0x6e, 0x1f, 0xda, - 0x23, 0x42, 0xa8, 0x4d, 0x59, 0x4d, 0x2f, 0xa1, 0xe6, 0x9d, 0x9c, 0x76, 0x34, 0x29, 0xc1, 0x55, 0x43, 0x67, 0xe5, - 0xfa, 0xaf, 0xc3, 0xa1, 0x77, 0x9b, 0x15, 0xd1, 0x1f, 0x3d, 0xf4, 0x77, 0xdc, 0xde, 0xa4, 0x5f, 0x20, 0x5a, 0xc6, - 0xfa, 0x1b, 0x32, 0xa0, 0xe3, 0xc9, 0xf0, 0xb6, 0xd8, 0xf6, 0xd8, 0x17, 0xd4, 0x60, 0xe9, 0xeb, 0xc7, 0x1f, 0x20, - 0xa1, 0xea, 0xda, 0x17, 0x16, 0x4f, 0x98, 0xa7, 0x44, 0xdb, 0xc2, 0x87, 0xb0, 0xd0, 0x2f, 0x10, 0x19, 0x09, 0xe1, - 0xa6, 0xb2, 0x7b, 0x94, 0xb4, 0x0b, 0x7d, 0xe9, 0x6b, 0xd9, 0x57, 0xbe, 0x73, 0x01, 0xb0, 0xb2, 0xcf, 0x6d, 0xb8, - 0x27, 0xfd, 0x29, 0xd5, 0x87, 0xed, 0x6f, 0xc9, 0x02, 0x0a, 0x2d, 0xac, 0xa7, 0x72, 0x76, 0xae, 0x4b, 0x9e, 0x66, - 0xd3, 0xfd, 0x1a, 0xf6, 0xa8, 0x7b, 0xf4, 0x9a, 0x0a, 0xce, 0x2f, 0xcd, 0xe8, 0xfd, 0xd3, 0x50, 0xa8, 0x8e, 0x3a, - 0x77, 0x90, 0x75, 0x69, 0x5d, 0x72, 0x7e, 0xb3, 0x72, 0x47, 0x61, 0x7e, 0x1f, 0x82, 0x67, 0x58, 0xf7, 0xee, 0xe2, - 0xbc, 0xf7, 0x67, 0x6b, 0x8e, 0xfc, 0x98, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0xf6, 0xdb, - 0x20, 0x87, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, - 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xdb, 0x20, 0xd7, 0x5d, 0x30, 0xcd, 0x91, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x92, 0x0a, - 0xcd, 0x22, 0x6d, 0x95, 0x8c, 0x7f, 0x47, 0xda, 0x4c, 0xc9, 0x1e, 0x5b, 0x03, 0xef, 0x25, 0x28, 0x27, 0xc3, 0x14, - 0xc3, 0x77, 0x7c, 0xbd, 0xf3, 0x98, 0x7b, 0xce, 0x31, 0xdb, 0xa4, 0xec, 0x08, 0x26, 0xc9, 0xc6, 0x37, 0x14, 0x6f, - 0xf8, 0xfe, 0xb6, 0x12, 0x25, 0x80, 0x5e, 0x16, 0xfc, 0x85, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, - 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, - 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, - 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, - 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, - 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, - 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, - 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, - 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, 0xf3, 0xfd, 0x95, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, - 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, - 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, - 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, - 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, - 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, - 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, - 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, - 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, - 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, - 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, - 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, - 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, - 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, - 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, - 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, - 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, - 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, - 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, - 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, - 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, - 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, - 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, - 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd1, - 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, - 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe1, 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, - 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, - 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, - 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, - 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, - 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, - 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, - 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, - 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, - 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, - 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, - 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, - 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0x7c, 0xa1, 0x56, 0xda, 0x59, 0x99, - 0x78, 0x35, 0xcb, 0xc0, 0x59, 0xe0, 0xa2, 0xf2, 0x59, 0xa6, 0x55, 0x4f, 0x55, 0x82, 0x3e, 0xaf, 0xe4, 0x04, 0x57, - 0x82, 0x93, 0x0d, 0xc8, 0x2f, 0x40, 0x92, 0xa6, 0x94, 0x35, 0xe5, 0x8b, 0x4b, 0xba, 0x21, 0xa3, 0xe7, 0xbc, 0xe7, - 0x45, 0xc3, 0xd0, 0xbf, 0xf0, 0x4a, 0x08, 0xdf, 0xc4, 0x6d, 0x1b, 0xa5, 0xb0, 0xbf, 0x09, 0x2c, 0x3e, 0x61, 0x3f, - 0x78, 0x4b, 0x7f, 0x3a, 0x0e, 0xc2, 0x21, 0x72, 0x43, 0xc5, 0x1c, 0xd8, 0xd3, 0x80, 0xc5, 0x26, 0xbe, 0xda, 0x4c, - 0xe2, 0xc1, 0xc0, 0xd7, 0x19, 0x8b, 0x59, 0x0c, 0x34, 0xc8, 0xf1, 0xe0, 0x72, 0xae, 0x4f, 0x08, 0xfd, 0x30, 0xa2, - 0x72, 0x54, 0xa0, 0x73, 0x10, 0x0d, 0x96, 0x80, 0xa7, 0xde, 0xca, 0x06, 0x49, 0xc6, 0x24, 0x93, 0xb8, 0xd6, 0x24, - 0xd5, 0xe1, 0x84, 0xd6, 0x81, 0x8e, 0xab, 0x0b, 0xe8, 0x7c, 0x5c, 0xf7, 0x3e, 0x5e, 0x0d, 0x17, 0x54, 0xfa, 0x85, - 0x18, 0x78, 0xf5, 0x74, 0x1c, 0x5c, 0xd2, 0xad, 0x70, 0xb1, 0x0a, 0xb7, 0x3f, 0xcb, 0x07, 0x8e, 0x3b, 0x2a, 0x69, - 0x08, 0x0c, 0xde, 0x1e, 0xba, 0x9b, 0x19, 0x1a, 0xea, 0xa4, 0x7d, 0x18, 0x87, 0x72, 0x88, 0x55, 0x2b, 0x2e, 0xa4, - 0x37, 0x82, 0x6f, 0x17, 0x8a, 0xb1, 0x6c, 0xec, 0xd2, 0x50, 0x14, 0xfe, 0x0a, 0x60, 0x87, 0xda, 0x5f, 0xa9, 0xe4, - 0x63, 0x64, 0x54, 0xd3, 0x40, 0xc7, 0x00, 0x2c, 0x59, 0x9a, 0x48, 0xaa, 0x48, 0x23, 0xf1, 0x47, 0x66, 0xac, 0xa3, - 0xa6, 0xeb, 0x0b, 0xa6, 0xaa, 0x45, 0xd2, 0xed, 0x4c, 0x62, 0x39, 0x91, 0xa4, 0xb6, 0xfb, 0x88, 0x18, 0x0c, 0x7c, - 0xb0, 0x11, 0xd3, 0x4c, 0x84, 0x23, 0x1e, 0x95, 0xc8, 0xa2, 0xcb, 0x6f, 0xa3, 0x4c, 0xda, 0xbe, 0xac, 0xc8, 0x16, - 0x04, 0xd3, 0x93, 0xe8, 0x83, 0x24, 0xe5, 0x54, 0x24, 0xd2, 0x8c, 0x10, 0xe0, 0xc7, 0x93, 0xf2, 0x4a, 0x7f, 0x0e, - 0x9a, 0x56, 0x82, 0x97, 0x0c, 0x92, 0x47, 0xe2, 0x67, 0x52, 0x30, 0x8b, 0xb1, 0x6a, 0x30, 0xc0, 0x72, 0xaa, 0x67, - 0x8e, 0x49, 0xfa, 0x6f, 0x9d, 0x4e, 0xd8, 0x2f, 0xbd, 0xdc, 0xd6, 0xf2, 0xa6, 0xb9, 0xf7, 0xd2, 0xab, 0x58, 0xaa, - 0x61, 0x19, 0xf4, 0x5f, 0x13, 0xed, 0x82, 0xad, 0x2d, 0x63, 0xc2, 0xaa, 0x1f, 0x40, 0xda, 0x23, 0x5d, 0x5e, 0x35, - 0xcc, 0x99, 0xe0, 0xd1, 0x85, 0x35, 0x0f, 0xa2, 0x0b, 0xe1, 0x23, 0x97, 0xdd, 0x24, 0xb9, 0x1a, 0x4f, 0xfc, 0x70, - 0x30, 0x50, 0x00, 0xb4, 0xb4, 0x4e, 0x8a, 0x41, 0xf8, 0x4c, 0xc8, 0x81, 0x34, 0x3a, 0xaa, 0x02, 0x2c, 0x96, 0xd9, - 0x55, 0x39, 0xc9, 0x06, 0x03, 0x1f, 0xc4, 0xc6, 0xc4, 0x6e, 0x68, 0x36, 0xf7, 0xd9, 0x89, 0x82, 0xac, 0x36, 0x87, - 0xad, 0x99, 0x6e, 0x81, 0x01, 0xc0, 0x20, 0x22, 0x58, 0xee, 0x73, 0x23, 0x1f, 0x51, 0xa7, 0xa7, 0x30, 0x02, 0x82, - 0x5f, 0x4e, 0x04, 0x22, 0x17, 0x09, 0xd4, 0x03, 0xcc, 0x04, 0x98, 0x51, 0xc5, 0xf0, 0x12, 0xd8, 0xc5, 0x73, 0xf3, - 0x8a, 0x41, 0xff, 0xa2, 0x49, 0x96, 0x68, 0x2a, 0x71, 0x34, 0x46, 0x4e, 0xa5, 0x31, 0x32, 0x20, 0x76, 0x71, 0xfc, - 0x7b, 0x4a, 0x8f, 0x82, 0x94, 0x7d, 0xae, 0x0c, 0x71, 0x38, 0x8a, 0xaf, 0x60, 0xd5, 0x38, 0x1c, 0x6a, 0xf3, 0x7a, - 0x3a, 0xab, 0xe7, 0x03, 0x11, 0xc0, 0x7f, 0x43, 0xc1, 0x7e, 0xd1, 0x54, 0xe4, 0x06, 0xa9, 0xf3, 0x70, 0x48, 0x41, - 0x3e, 0xd5, 0x4d, 0xfe, 0xbe, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, - 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, - 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, - 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, - 0x7f, 0x95, 0xee, 0xcd, 0xa9, 0x0d, 0x72, 0x00, 0xdb, 0xbd, 0x87, 0xdb, 0x31, 0x7a, 0x20, 0x83, 0x37, 0x42, 0xce, - 0x39, 0xbf, 0x9c, 0x5a, 0x33, 0x26, 0x1a, 0x16, 0xac, 0x1c, 0x46, 0x7e, 0x80, 0x8c, 0x97, 0x53, 0x60, 0x65, 0x3f, - 0x2a, 0xe2, 0xd2, 0x1f, 0x46, 0xfe, 0xc5, 0xf3, 0x20, 0xe3, 0x5e, 0x34, 0xec, 0xf8, 0x02, 0xec, 0xd5, 0x17, 0xcf, - 0x59, 0x34, 0xe0, 0xd5, 0x55, 0x3d, 0xcd, 0x82, 0x61, 0xc6, 0xa2, 0xab, 0x62, 0x08, 0x3e, 0xb4, 0x2f, 0xca, 0x41, - 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x47, 0x70, 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, - 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x85, 0xd4, 0x6c, 0x14, 0x68, 0x4e, 0xae, 0xd0, 0x9c, - 0xac, 0x84, 0x5a, 0xf2, 0x49, 0x85, 0x13, 0x76, 0x3e, 0xc9, 0x95, 0xdd, 0x68, 0x8c, 0x81, 0x8b, 0xf6, 0xdc, 0x16, - 0x46, 0x66, 0x3a, 0x4b, 0xd1, 0x80, 0x85, 0x67, 0xe2, 0x94, 0xc6, 0x80, 0xf6, 0xe5, 0xc0, 0xd2, 0x86, 0xfc, 0x28, - 0x67, 0x06, 0xda, 0x86, 0x94, 0x46, 0xcd, 0xc0, 0x9f, 0xa9, 0x09, 0xf3, 0x2b, 0x58, 0x89, 0x20, 0xaa, 0x0b, 0x30, - 0x49, 0x72, 0x32, 0x1a, 0x29, 0x2b, 0x91, 0x9c, 0x03, 0xde, 0x47, 0xf0, 0x64, 0x11, 0xdb, 0xda, 0x9f, 0xd2, 0xff, - 0xea, 0xf0, 0xb9, 0xf4, 0x9f, 0x09, 0x60, 0x21, 0x97, 0x06, 0x91, 0x81, 0xc2, 0x21, 0x35, 0x95, 0x88, 0x13, 0xc7, - 0x33, 0xf0, 0x0d, 0x5c, 0xa0, 0x29, 0xa0, 0x3f, 0xa8, 0x19, 0x45, 0x64, 0xe1, 0xaf, 0x9e, 0xdd, 0xd4, 0x8d, 0x9e, - 0x67, 0xce, 0x6b, 0xd0, 0xcc, 0x40, 0x48, 0x8f, 0x53, 0xf5, 0x36, 0x24, 0x3a, 0x2f, 0x2f, 0xf5, 0xcb, 0x84, 0x48, - 0x56, 0x44, 0x9e, 0xbe, 0xcf, 0xc1, 0x3c, 0xa2, 0x08, 0x1d, 0x5c, 0x99, 0x87, 0xc3, 0xb9, 0xa0, 0xf0, 0x1d, 0xe5, - 0xf9, 0x80, 0xd3, 0x2c, 0x4a, 0x40, 0x1b, 0xc8, 0x72, 0x53, 0xe6, 0x3a, 0x69, 0x99, 0xba, 0xf7, 0x60, 0x25, 0xa8, - 0xd0, 0xcd, 0x29, 0x28, 0x94, 0x91, 0xa0, 0x94, 0x56, 0x83, 0x50, 0xaa, 0xc3, 0x22, 0x88, 0x1c, 0xb2, 0x10, 0x70, - 0x33, 0x15, 0x8d, 0x96, 0x34, 0x3c, 0xc2, 0xb9, 0x81, 0x42, 0x00, 0x12, 0x7b, 0xaa, 0x28, 0xe3, 0x72, 0x08, 0xf8, - 0x28, 0xe1, 0x10, 0x67, 0x4d, 0xda, 0xf2, 0x1c, 0xc4, 0xb1, 0x5c, 0xf2, 0x75, 0x85, 0x60, 0x10, 0xa1, 0xcf, 0x90, - 0x3f, 0x59, 0xce, 0xbf, 0x5b, 0x87, 0x69, 0x47, 0xf8, 0xb0, 0xab, 0x2d, 0xb8, 0x98, 0xdd, 0xce, 0x27, 0x10, 0xdf, - 0x72, 0x3b, 0x3f, 0xc6, 0x10, 0x59, 0xf8, 0x83, 0xbb, 0xa1, 0xe4, 0x8a, 0x42, 0x97, 0xf5, 0x88, 0x14, 0xd9, 0xd3, - 0x35, 0x47, 0x10, 0x1c, 0x68, 0xd5, 0x20, 0x43, 0x23, 0xf1, 0xc5, 0x73, 0xc8, 0x1a, 0xac, 0xf9, 0xe7, 0x8a, 0x9c, - 0xd5, 0xfd, 0xc9, 0x06, 0xaa, 0x49, 0x26, 0x6b, 0x45, 0xe5, 0xfc, 0xf5, 0xaa, 0x2c, 0x4f, 0x56, 0x65, 0xb8, 0x1a, - 0x74, 0x55, 0x65, 0xc9, 0x91, 0xda, 0x00, 0xad, 0xe9, 0x0a, 0x31, 0x14, 0xb2, 0x06, 0x4b, 0xab, 0x2a, 0x6b, 0xea, - 0x13, 0x08, 0xf4, 0x01, 0x96, 0x51, 0xb3, 0x9f, 0x0e, 0xff, 0x15, 0xfc, 0x4b, 0x85, 0x2c, 0xd5, 0x69, 0x9d, 0x89, - 0x5f, 0x83, 0x25, 0xc3, 0x3f, 0x7e, 0x0b, 0xd6, 0x80, 0x25, 0x40, 0x96, 0xbb, 0x8d, 0x8d, 0xd6, 0x2b, 0xaf, 0x10, - 0x5f, 0x6a, 0x7d, 0xd1, 0x6f, 0xdd, 0x26, 0x6a, 0x05, 0x18, 0xa1, 0xd0, 0x22, 0xc0, 0x56, 0x0f, 0xdc, 0x53, 0xf0, - 0x03, 0x31, 0x9c, 0x6b, 0xd2, 0x9a, 0x3a, 0xe1, 0x75, 0x36, 0x8e, 0x44, 0x54, 0x6f, 0xe1, 0xe2, 0x5e, 0x6f, 0x2d, - 0xfe, 0x46, 0x05, 0x02, 0x20, 0x8b, 0x29, 0xd6, 0xce, 0x1b, 0xd2, 0x2b, 0xc3, 0x4e, 0x42, 0xef, 0x0d, 0x3b, 0x81, - 0xbc, 0x38, 0xec, 0x14, 0xba, 0x44, 0xdb, 0x29, 0x52, 0x13, 0x6d, 0x27, 0x2d, 0x56, 0x61, 0x09, 0xc1, 0xaf, 0xda, - 0x5b, 0x47, 0xd9, 0xbe, 0xc8, 0x12, 0xa6, 0x2d, 0x60, 0x94, 0x5b, 0xf5, 0x99, 0x53, 0xc4, 0x4a, 0xd9, 0x3b, 0x9d, - 0x54, 0xb9, 0x8b, 0x7c, 0x6a, 0x35, 0x45, 0x26, 0x7f, 0x7f, 0xdc, 0x22, 0xf9, 0xe4, 0xe7, 0x76, 0xc3, 0x64, 0xfa, - 0xc7, 0xa3, 0x2f, 0xa0, 0x2b, 0xb2, 0xd3, 0x27, 0x10, 0x90, 0xa9, 0xa0, 0x5a, 0xdd, 0x2a, 0xa6, 0x79, 0xbb, 0xca, - 0x6e, 0x2f, 0x94, 0x18, 0x4e, 0x67, 0x27, 0xe1, 0xd1, 0x66, 0xc8, 0xc0, 0x21, 0x08, 0x14, 0x42, 0x45, 0x31, 0x3c, - 0x02, 0xb5, 0x46, 0xf2, 0x01, 0x7e, 0xb4, 0x3b, 0x15, 0x44, 0x6a, 0x37, 0x15, 0x37, 0x4e, 0x6e, 0xba, 0x5e, 0x0a, - 0xd4, 0x3a, 0x25, 0x2b, 0x80, 0x12, 0xa2, 0xfe, 0x24, 0xb6, 0xf5, 0x2b, 0xb8, 0x62, 0xf3, 0x7d, 0xa3, 0xe8, 0xc9, - 0xf5, 0x29, 0xea, 0x56, 0x5c, 0x9d, 0xa6, 0xad, 0xe6, 0xd8, 0x71, 0x86, 0x1c, 0x3c, 0x2b, 0x08, 0xb6, 0xa3, 0x12, - 0xe5, 0x75, 0xbb, 0xe9, 0x98, 0xd8, 0xea, 0x9f, 0x45, 0xb5, 0xb9, 0x83, 0x8a, 0x88, 0xf8, 0x28, 0xbb, 0x79, 0xd2, - 0x7e, 0x07, 0x7b, 0xac, 0xd5, 0x20, 0xb2, 0xcf, 0xe0, 0x2a, 0xd7, 0x69, 0x91, 0xdb, 0x32, 0x38, 0xff, 0xf0, 0x6a, - 0x57, 0x61, 0x93, 0x63, 0x5d, 0x5d, 0xcd, 0x54, 0x27, 0x15, 0x1b, 0x18, 0x6b, 0x5a, 0x4b, 0x35, 0x8f, 0x21, 0xe9, - 0xae, 0x2c, 0xce, 0xaa, 0xa4, 0x9b, 0x9e, 0x1b, 0x67, 0x0a, 0x31, 0x70, 0xb6, 0x1a, 0x2d, 0x67, 0x18, 0xa2, 0xeb, - 0xc3, 0x2c, 0xf1, 0x5b, 0x3d, 0xe5, 0x3e, 0x0f, 0xb7, 0x7e, 0x57, 0x2f, 0x38, 0x99, 0xec, 0x27, 0xc7, 0xb9, 0xdb, - 0x45, 0xda, 0x4f, 0x7c, 0x1b, 0xe6, 0x5f, 0xdf, 0x20, 0xee, 0x44, 0xfd, 0xcf, 0x0a, 0x80, 0x06, 0x37, 0x79, 0x2c, - 0x51, 0xea, 0xf7, 0xaa, 0xfa, 0x41, 0xcd, 0x54, 0x4d, 0x03, 0xc1, 0x9c, 0x4a, 0x01, 0x7f, 0xb8, 0x5d, 0xb8, 0xe2, - 0x11, 0x37, 0x2c, 0x8c, 0x7f, 0x7a, 0x35, 0x3b, 0x15, 0x54, 0x06, 0x6e, 0xc6, 0x7f, 0x7a, 0x82, 0x9d, 0xc2, 0x5a, - 0x01, 0x59, 0xe1, 0x4f, 0x2f, 0x7f, 0xe4, 0xfd, 0x8a, 0xff, 0xe9, 0x55, 0x8f, 0xbc, 0x8f, 0x38, 0x2f, 0x7f, 0x22, - 0xa9, 0x13, 0xa2, 0xba, 0xfc, 0x49, 0x98, 0x62, 0xab, 0x34, 0x7f, 0x4d, 0x0a, 0x9f, 0xe0, 0x33, 0xf0, 0x1d, 0xae, - 0xc2, 0xad, 0xf9, 0x0d, 0x1e, 0x3b, 0x16, 0xdb, 0x2e, 0xf5, 0x05, 0x94, 0x23, 0xb0, 0x88, 0xdc, 0x7e, 0xbb, 0xb2, - 0x5f, 0x2d, 0x8c, 0x32, 0xc6, 0xee, 0x4b, 0x56, 0xa2, 0x74, 0xd6, 0xef, 0x17, 0x52, 0x30, 0xb2, 0x0b, 0x6b, 0xb4, - 0x47, 0xa9, 0x7a, 0xf5, 0x3a, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, - 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, - 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, - 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0x5e, 0xe4, 0x18, 0x5b, 0x91, 0x03, 0x07, 0x32, 0xfc, 0x80, 0xc0, - 0x7b, 0xd9, 0xbf, 0x82, 0xc1, 0x30, 0xc1, 0x8d, 0x8c, 0x3a, 0x39, 0x67, 0x7f, 0x62, 0x60, 0x06, 0xf5, 0xa4, 0x76, - 0x9f, 0xdd, 0xab, 0xc0, 0x5e, 0x38, 0x03, 0xda, 0xbb, 0x31, 0xfa, 0x59, 0x15, 0x6b, 0x27, 0xfd, 0x53, 0xb1, 0x86, - 0x64, 0x3a, 0x2c, 0x8e, 0xb6, 0x69, 0x78, 0x24, 0x4f, 0x8e, 0xe3, 0x4d, 0xff, 0x70, 0x18, 0xe3, 0xc7, 0x51, 0x7e, - 0x6d, 0x01, 0xaf, 0xe2, 0x16, 0xd2, 0x58, 0xa4, 0xe8, 0x1d, 0x88, 0x39, 0x14, 0xbd, 0x64, 0xbf, 0x65, 0xbc, 0x9c, - 0x08, 0x4a, 0x49, 0x62, 0xc3, 0x3b, 0xd2, 0xd3, 0xb4, 0x1e, 0x6d, 0x65, 0xc0, 0x7e, 0x3d, 0xda, 0xd1, 0x5f, 0xa0, - 0x78, 0xb4, 0xf0, 0x97, 0xf4, 0x77, 0x71, 0x37, 0xf7, 0x9c, 0x6f, 0x1a, 0xdf, 0x11, 0x17, 0x28, 0xd6, 0xec, 0xfe, - 0x9a, 0x96, 0xce, 0x3a, 0x10, 0x1c, 0xf0, 0x16, 0xbb, 0x68, 0xdf, 0x6f, 0x5c, 0xa7, 0xa7, 0xfd, 0xb7, 0x6e, 0x8d, - 0xf2, 0xbd, 0x7f, 0x4a, 0x94, 0x83, 0xfd, 0x6b, 0x17, 0xcd, 0xdf, 0x7e, 0xca, 0x90, 0x54, 0x68, 0x6e, 0xb0, 0x9d, - 0x6c, 0x11, 0xd6, 0xc6, 0x38, 0xa8, 0xd8, 0x5d, 0x19, 0x46, 0xc0, 0xa0, 0x8e, 0xfd, 0x8f, 0x3e, 0x9b, 0x36, 0x64, - 0x1f, 0x00, 0x2a, 0x57, 0x21, 0x60, 0x0f, 0xc0, 0x89, 0x46, 0xb8, 0x01, 0x6e, 0x35, 0x5a, 0xd2, 0x41, 0xdd, 0x16, - 0x0c, 0x44, 0x4b, 0xd8, 0xc8, 0xdb, 0xae, 0x4e, 0x5f, 0x11, 0x3e, 0xd4, 0x4e, 0x4a, 0x87, 0xf2, 0x57, 0xcf, 0xd9, - 0xff, 0xec, 0xb0, 0xa6, 0xa6, 0xdc, 0x00, 0x66, 0xce, 0x4a, 0xe4, 0x15, 0x42, 0xa7, 0xc8, 0xef, 0x55, 0x5d, 0x89, - 0xe1, 0xb2, 0x16, 0x65, 0x67, 0x76, 0xeb, 0x44, 0xef, 0x9c, 0x82, 0x5a, 0x2a, 0x1b, 0xe4, 0x24, 0xd5, 0xe6, 0x23, - 0x6b, 0x05, 0x25, 0xea, 0x1a, 0x05, 0x8e, 0x4f, 0xb9, 0x76, 0xff, 0xef, 0x9c, 0x09, 0x6a, 0xb6, 0x51, 0xdd, 0x5f, - 0xeb, 0xa7, 0xaa, 0x26, 0xb1, 0x00, 0x97, 0x93, 0x34, 0xef, 0x78, 0x84, 0xd5, 0x3f, 0x4e, 0x96, 0x22, 0xd0, 0xeb, - 0x88, 0x76, 0x25, 0x20, 0x41, 0x3b, 0x39, 0x0b, 0x15, 0x81, 0x02, 0x7d, 0xfd, 0xfb, 0x4d, 0x9a, 0xc5, 0x72, 0x35, - 0xdb, 0xc3, 0x44, 0x59, 0xac, 0x87, 0x08, 0x72, 0x66, 0xea, 0x60, 0xbf, 0xa7, 0x19, 0xcd, 0xc2, 0x2b, 0x53, 0x82, - 0x4b, 0x71, 0x15, 0x15, 0x39, 0xf8, 0x1c, 0xe2, 0x0b, 0x9f, 0x0a, 0xb9, 0x41, 0x44, 0xd3, 0xef, 0x25, 0xaa, 0x1d, - 0x29, 0x90, 0x43, 0xc9, 0x4f, 0x88, 0xbf, 0x64, 0x6d, 0x8c, 0xfb, 0xa5, 0x53, 0xed, 0x57, 0x0a, 0xc1, 0xfd, 0x67, - 0x5b, 0x6c, 0x54, 0x79, 0xa2, 0x47, 0x9f, 0x62, 0xfd, 0x4f, 0x16, 0x50, 0xaa, 0xfb, 0x36, 0x38, 0x15, 0x8f, 0xc2, - 0x4d, 0x5d, 0xdc, 0x20, 0xb4, 0x40, 0x39, 0xaa, 0x8a, 0x4d, 0x19, 0x11, 0x27, 0xec, 0xa6, 0x2e, 0x7a, 0x9a, 0x03, - 0x9d, 0x3a, 0x2c, 0x4d, 0xe4, 0x89, 0xd0, 0x6e, 0x41, 0xf7, 0x34, 0xc7, 0x4a, 0xbc, 0x94, 0xa5, 0x83, 0xac, 0x13, - 0x69, 0x42, 0xe5, 0xae, 0xae, 0x3a, 0x2a, 0x95, 0xba, 0xe1, 0x4d, 0xaa, 0x19, 0x7f, 0x97, 0xe6, 0x4f, 0x2c, 0xfb, - 0x4d, 0xeb, 0xb7, 0x5a, 0xed, 0x8d, 0xd5, 0xa3, 0x92, 0x35, 0xc7, 0xd9, 0x84, 0xa4, 0xf4, 0x09, 0xdb, 0xcd, 0xa4, - 0x6b, 0x1d, 0x78, 0x12, 0x5c, 0x0e, 0x3d, 0x01, 0x15, 0x83, 0x26, 0xde, 0xee, 0x02, 0xf5, 0x08, 0x3c, 0x03, 0xe5, - 0x13, 0xb5, 0x0e, 0xf8, 0x79, 0xad, 0xe5, 0x29, 0x23, 0x0c, 0xab, 0x9d, 0x45, 0xcb, 0xc1, 0x79, 0xa7, 0x08, 0x5c, - 0xbb, 0x12, 0x78, 0x3e, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, 0xa7, - 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, 0x36, - 0x9f, 0x7d, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, 0xcf, - 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, 0x76, - 0x7c, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, 0x88, - 0xc2, 0x2c, 0xfb, 0xb1, 0x28, 0xfe, 0xa8, 0xf4, 0x1d, 0x81, 0x8e, 0xee, 0xbc, 0xa8, 0xd3, 0xe5, 0xee, 0x03, 0x61, - 0x3c, 0x79, 0xf5, 0x11, 0xd1, 0xad, 0xef, 0x33, 0xf7, 0x2b, 0xc0, 0x8d, 0xe0, 0x0e, 0xa2, 0xbd, 0x5b, 0xea, 0x93, - 0x5a, 0x7d, 0xad, 0xd7, 0xce, 0xd3, 0xf3, 0x9b, 0xce, 0xed, 0x77, 0xdf, 0x1c, 0x6d, 0xbd, 0xc7, 0x85, 0xb5, 0xb2, - 0xf4, 0x54, 0x15, 0xec, 0xcd, 0xf2, 0x54, 0x15, 0x4c, 0x1e, 0x78, 0xcd, 0x7e, 0x41, 0x83, 0x2b, 0x1d, 0x6d, 0xbc, - 0x27, 0x6a, 0xe0, 0x16, 0x85, 0xa5, 0xc3, 0x2f, 0xb9, 0x99, 0xbc, 0xc2, 0xfd, 0xa5, 0x22, 0x17, 0xfb, 0xce, 0x19, - 0xdd, 0x99, 0x59, 0xf7, 0xaa, 0xc2, 0xd5, 0x82, 0x5c, 0x1d, 0xd8, 0x5a, 0x76, 0x71, 0xb8, 0x61, 0x11, 0x05, 0x08, - 0xc4, 0xf4, 0x4a, 0xad, 0xfd, 0x11, 0x0d, 0x42, 0x3e, 0x18, 0xf8, 0x05, 0x06, 0xab, 0x02, 0x85, 0x0f, 0x14, 0xc9, - 0x5f, 0x7b, 0x02, 0x76, 0xf1, 0x0c, 0xd0, 0xad, 0xd8, 0xac, 0x18, 0x21, 0x42, 0x26, 0xcb, 0x59, 0x4d, 0x67, 0x90, - 0x4f, 0x7d, 0xf1, 0x8d, 0xad, 0x3a, 0x9d, 0xb7, 0x35, 0x55, 0x4e, 0x1d, 0x0a, 0xdd, 0xdd, 0xd4, 0x9d, 0x5b, 0x17, - 0x79, 0xea, 0x10, 0x72, 0xa5, 0x62, 0x25, 0xa6, 0xa1, 0xe6, 0x49, 0x9a, 0x51, 0x7f, 0xb1, 0xf7, 0x7b, 0x8d, 0xc2, - 0x29, 0x7f, 0x3a, 0x06, 0x55, 0xb8, 0xaa, 0x21, 0x8e, 0xa5, 0x2a, 0x1e, 0xd9, 0x20, 0xd0, 0xbc, 0xba, 0x55, 0x49, - 0x13, 0x32, 0xb9, 0x11, 0x3e, 0x35, 0x29, 0xe5, 0x69, 0xda, 0xa4, 0x95, 0x22, 0x75, 0xf0, 0x41, 0x9d, 0x6a, 0x3c, - 0x37, 0xab, 0x17, 0x00, 0x66, 0x9c, 0x5f, 0xf1, 0x4b, 0xc5, 0x65, 0xd4, 0x56, 0x66, 0xd2, 0xfe, 0xe4, 0x68, 0x6c, - 0xd4, 0xe5, 0xb4, 0x51, 0x46, 0x58, 0x29, 0xcd, 0x49, 0xb1, 0x1c, 0xcf, 0x3f, 0x60, 0xb0, 0xe6, 0x09, 0xec, 0x60, - 0xa2, 0x52, 0xde, 0x47, 0x40, 0x7c, 0x9d, 0xa4, 0x77, 0x09, 0xa4, 0x48, 0xff, 0xd2, 0x25, 0x77, 0x19, 0x1b, 0x88, - 0x31, 0x2b, 0x66, 0x46, 0xff, 0x83, 0xbb, 0xa4, 0x3f, 0x09, 0x01, 0x70, 0x13, 0x4d, 0xa1, 0x53, 0xe7, 0xc9, 0x45, - 0x1e, 0x2c, 0x2f, 0x3c, 0xb4, 0x62, 0xc4, 0x83, 0xbf, 0xbe, 0x08, 0x11, 0xc4, 0x1c, 0x53, 0x3c, 0xfd, 0xc2, 0xe8, - 0x2f, 0xc1, 0x25, 0x46, 0x10, 0xba, 0x7b, 0xe7, 0x30, 0x84, 0x9b, 0x3d, 0xc8, 0xa0, 0xfe, 0x50, 0x87, 0x44, 0x0d, - 0x7f, 0xac, 0x3c, 0xe8, 0xff, 0x3a, 0x13, 0x96, 0xda, 0x4f, 0x4f, 0x07, 0x50, 0xc1, 0xfb, 0x8a, 0xb7, 0x11, 0xf1, - 0x7d, 0xe2, 0x67, 0xf1, 0x60, 0xf3, 0x6c, 0x03, 0xd6, 0xba, 0x27, 0xb9, 0xb1, 0xae, 0x12, 0x36, 0x10, 0xf0, 0x35, - 0x8a, 0xda, 0xf3, 0xda, 0xed, 0x1e, 0xfc, 0xd5, 0xbf, 0x08, 0x19, 0x30, 0x71, 0xfa, 0x3e, 0x73, 0xb2, 0x46, 0x17, - 0x99, 0x4c, 0x1f, 0x3a, 0xe9, 0x1b, 0x9d, 0xee, 0x3b, 0xe1, 0x1f, 0x15, 0xb3, 0xf8, 0x70, 0x4b, 0x5f, 0x69, 0x52, - 0xdc, 0x01, 0x2b, 0x9b, 0x47, 0x05, 0xa1, 0xce, 0x45, 0xf4, 0x95, 0x29, 0xdf, 0x12, 0x6a, 0xf6, 0x8d, 0x25, 0xa5, - 0x74, 0xaf, 0xa1, 0x37, 0x69, 0xad, 0xdf, 0x46, 0x09, 0xc6, 0x44, 0xc7, 0x93, 0x97, 0xf1, 0x58, 0x79, 0x1f, 0x8f, - 0x1b, 0xa9, 0x90, 0x07, 0x20, 0x02, 0x15, 0xe3, 0x4f, 0x57, 0x9e, 0x9c, 0xf4, 0xc2, 0x78, 0x15, 0x4a, 0x41, 0x61, - 0x40, 0x57, 0x20, 0x05, 0x3c, 0x6a, 0x4f, 0x74, 0x16, 0x76, 0x09, 0xf7, 0xe8, 0x26, 0x60, 0xac, 0xcf, 0x3f, 0x02, - 0x9a, 0xbb, 0x70, 0x87, 0x17, 0x03, 0xd4, 0xa6, 0x5e, 0xdd, 0x7d, 0x5c, 0xab, 0x73, 0x38, 0x04, 0x07, 0xab, 0x41, - 0x04, 0xa7, 0xf3, 0xa9, 0xa3, 0x59, 0x16, 0xa0, 0x72, 0xb2, 0xdc, 0xc8, 0x9b, 0x47, 0x8b, 0x5e, 0xdd, 0xf7, 0x96, - 0x69, 0x59, 0xd5, 0x41, 0xc6, 0xb2, 0xb0, 0x02, 0x5c, 0x1d, 0x5a, 0x3f, 0x08, 0x97, 0x85, 0xf3, 0x07, 0x42, 0x10, - 0xbb, 0x57, 0xdb, 0x92, 0xe7, 0x6a, 0x0e, 0x3f, 0x7b, 0xce, 0xd6, 0x5c, 0xa2, 0x4e, 0x3a, 0x13, 0x01, 0x88, 0x3d, - 0x35, 0xab, 0xe8, 0x1a, 0x48, 0xea, 0x34, 0xab, 0xe8, 0x9a, 0x9a, 0x6d, 0x8c, 0x03, 0xf9, 0x68, 0x95, 0x02, 0xf6, - 0xdd, 0x74, 0x1c, 0xac, 0x9e, 0xc5, 0xf2, 0x3a, 0x74, 0xf7, 0x6c, 0xa3, 0x7c, 0x06, 0x75, 0xab, 0x8d, 0x31, 0xb1, - 0xdd, 0x7c, 0x39, 0xd7, 0x6f, 0x07, 0x4b, 0xdf, 0x0e, 0x9a, 0x73, 0xca, 0xbe, 0xd3, 0x65, 0xaf, 0xec, 0xb2, 0xa9, - 0xe7, 0x8e, 0x8a, 0x56, 0x63, 0x40, 0x6f, 0x60, 0xc1, 0xfa, 0x5c, 0xa4, 0xd9, 0xaa, 0x54, 0x25, 0xe0, 0x85, 0xb1, - 0x62, 0x77, 0x7e, 0x23, 0x33, 0x24, 0x61, 0x1e, 0x67, 0xe2, 0x9a, 0xee, 0xb5, 0x30, 0x39, 0x8e, 0x45, 0x32, 0x25, - 0x74, 0x4a, 0x77, 0xb6, 0xa1, 0x73, 0x15, 0x46, 0x11, 0xad, 0x95, 0x54, 0x1a, 0x09, 0x4c, 0xcd, 0x00, 0x25, 0x73, - 0x05, 0x4e, 0xe9, 0x72, 0xff, 0x3b, 0x12, 0xe3, 0xcc, 0x17, 0x25, 0x33, 0xa0, 0x5b, 0x7e, 0x5d, 0xac, 0x5b, 0x29, - 0x32, 0xc2, 0xbc, 0x39, 0x6e, 0xaf, 0xeb, 0x43, 0x20, 0x57, 0xcb, 0x1e, 0x45, 0xe3, 0xa0, 0xd0, 0xe1, 0x52, 0x25, - 0xc0, 0xbe, 0x48, 0xfc, 0x8c, 0xb0, 0xa5, 0x3d, 0x90, 0xdb, 0xa3, 0x33, 0x61, 0xce, 0x39, 0x29, 0xcb, 0xce, 0xa5, - 0x19, 0x5c, 0x4e, 0x5c, 0x09, 0x2e, 0xd2, 0xdb, 0xf6, 0x34, 0x69, 0x69, 0xfb, 0xd8, 0x70, 0x8e, 0x86, 0xb6, 0x41, - 0x77, 0xec, 0x0f, 0xcd, 0xc5, 0x22, 0xb6, 0x2e, 0x16, 0xc3, 0xce, 0xec, 0x47, 0x8b, 0x05, 0xc8, 0x01, 0xe0, 0xa8, - 0xdb, 0xf0, 0x31, 0x5b, 0x02, 0xa7, 0xd5, 0x34, 0x9b, 0x7a, 0x1b, 0x5e, 0x3d, 0x53, 0x3d, 0xbd, 0xe4, 0xf9, 0x33, - 0x61, 0xc6, 0x62, 0xc3, 0xf3, 0x67, 0xd6, 0x91, 0x53, 0x3d, 0x13, 0x4a, 0xb4, 0x2e, 0xa0, 0x19, 0x78, 0x4d, 0x01, - 0x23, 0x96, 0x4c, 0xa6, 0x54, 0x91, 0xc7, 0xbd, 0xe9, 0x46, 0x0d, 0x5e, 0x50, 0x38, 0x04, 0x52, 0x3a, 0xfd, 0xe2, - 0x39, 0xd3, 0xef, 0x5d, 0x3c, 0xef, 0x90, 0xb5, 0x0d, 0xd3, 0xe5, 0x66, 0x98, 0x0c, 0x4a, 0xff, 0x99, 0x99, 0x18, - 0x17, 0xd6, 0x24, 0x01, 0xc4, 0xbf, 0xb1, 0xdf, 0x21, 0x85, 0x9b, 0xf7, 0x97, 0xc3, 0xf8, 0x91, 0xf7, 0x63, 0x64, - 0x4f, 0xd2, 0x0c, 0xb1, 0x66, 0x52, 0x21, 0x77, 0x5f, 0xad, 0x7f, 0x4c, 0xec, 0x26, 0x7b, 0x60, 0x01, 0x88, 0xad, - 0x69, 0xab, 0x5b, 0xde, 0xef, 0x7b, 0xa6, 0x08, 0xf0, 0x83, 0xf2, 0x8f, 0xee, 0x0c, 0xc9, 0xa0, 0xec, 0xba, 0x21, - 0xc4, 0x83, 0xb2, 0x69, 0xda, 0xeb, 0x6d, 0xef, 0xcc, 0x63, 0x75, 0x9d, 0x76, 0x16, 0x57, 0x8b, 0x0c, 0xd2, 0xea, - 0x43, 0x76, 0x9c, 0xd9, 0x67, 0x47, 0x4b, 0xa5, 0xfb, 0x7d, 0x88, 0x88, 0x3b, 0xca, 0xda, 0x7e, 0xbb, 0x05, 0xd7, - 0x70, 0x34, 0x08, 0x5d, 0xd9, 0xdb, 0x65, 0xb4, 0x71, 0x21, 0x8e, 0x7b, 0xa6, 0xf3, 0x05, 0x5f, 0x1e, 0xa5, 0x9d, - 0x07, 0xa7, 0x7a, 0xa2, 0xcf, 0x4d, 0x77, 0x95, 0xc9, 0xb5, 0x0e, 0xab, 0x31, 0xa8, 0xcd, 0xc2, 0x16, 0xee, 0xc2, - 0x36, 0x3a, 0x68, 0xed, 0xcb, 0x82, 0x7f, 0xca, 0x00, 0x7c, 0xe9, 0xd9, 0xb2, 0xed, 0x35, 0x69, 0xf5, 0x46, 0x46, - 0x21, 0xb6, 0xb4, 0xbd, 0xfa, 0x74, 0x94, 0x8f, 0x9b, 0x13, 0x8a, 0x0b, 0x39, 0xca, 0x8f, 0x5e, 0x43, 0xd4, 0xb5, - 0xae, 0xe3, 0x62, 0xd1, 0xe1, 0xc6, 0x55, 0xb7, 0xdd, 0xb8, 0x7e, 0x40, 0xbc, 0x35, 0xda, 0xa4, 0x50, 0x2b, 0x63, - 0x47, 0xf0, 0xb2, 0x7c, 0x38, 0x64, 0x62, 0x38, 0x94, 0x90, 0xa9, 0x8f, 0xdd, 0x1b, 0x9a, 0xf6, 0xf9, 0x69, 0xeb, - 0x47, 0x2c, 0x35, 0x8e, 0x62, 0xc3, 0x3b, 0x7d, 0xe7, 0xb1, 0x35, 0xae, 0xe4, 0xcb, 0x60, 0xb6, 0x2b, 0xa8, 0xb6, - 0xc6, 0x1b, 0xf6, 0x72, 0xfe, 0x7d, 0x25, 0x95, 0xfc, 0xed, 0xcf, 0x70, 0x0d, 0x6f, 0x6d, 0xe9, 0xa0, 0xa9, 0x66, - 0x39, 0xcb, 0xf5, 0xbd, 0xe0, 0xf8, 0xe3, 0xee, 0x15, 0xc1, 0xe0, 0xf7, 0x74, 0x14, 0xe4, 0x62, 0xa9, 0xd6, 0x80, - 0x82, 0x74, 0x64, 0xc7, 0x54, 0x16, 0x18, 0x06, 0xf0, 0x86, 0x0c, 0x90, 0xc7, 0x14, 0xee, 0x86, 0x0a, 0x2f, 0xfc, - 0xa5, 0x22, 0xbb, 0x04, 0xb6, 0x35, 0xe3, 0x63, 0x86, 0x3b, 0x08, 0xf9, 0x47, 0xb0, 0x3b, 0xb6, 0x62, 0xb7, 0x6c, - 0xc1, 0x90, 0x6c, 0x1c, 0x87, 0x31, 0xe6, 0xe3, 0x49, 0x7c, 0x25, 0x26, 0xf1, 0x80, 0x47, 0xe8, 0x18, 0xb1, 0xe6, - 0xf5, 0x2c, 0x96, 0x03, 0xc8, 0xee, 0xb8, 0xd2, 0x01, 0x21, 0x34, 0x36, 0xb4, 0xe4, 0x4d, 0x61, 0x70, 0xb1, 0x63, - 0x9f, 0x91, 0x48, 0xc6, 0x21, 0x58, 0xb4, 0xaa, 0x81, 0x85, 0x89, 0xdd, 0xf2, 0x62, 0xb6, 0x9a, 0xe3, 0x3f, 0x87, - 0x03, 0x02, 0x60, 0x07, 0xfb, 0x86, 0xdd, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x77, 0x96, 0xa7, 0x0b, 0xbb, 0xe7, 0xd7, - 0x7c, 0xcc, 0xce, 0x7f, 0xf0, 0x20, 0x72, 0xf6, 0xfc, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xdb, 0xd4, 0xab, 0xd8, 0x2d, - 0x51, 0x10, 0xde, 0x82, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0x5e, 0xf3, 0x05, 0xc6, 0x8a, 0x9d, 0xa5, 0x4b, 0x0f, 0x33, - 0x42, 0xed, 0xe9, 0x7c, 0x59, 0xab, 0x49, 0xb8, 0xb9, 0x5a, 0x4e, 0x06, 0x83, 0x8d, 0xbf, 0xe3, 0x6b, 0xe0, 0x83, - 0x39, 0xff, 0xc1, 0xdb, 0x51, 0xb9, 0xf0, 0x9f, 0xd7, 0x59, 0xf2, 0xce, 0x67, 0xd7, 0x03, 0xbe, 0x00, 0xbc, 0x25, - 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0xbb, 0xd6, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0xbe, - 0x86, 0x08, 0x8c, 0x04, 0x7c, 0x5b, 0xb5, 0x47, 0xfc, 0x96, 0x1b, 0xc0, 0xaf, 0xcc, 0x67, 0x0f, 0x3c, 0xd4, 0x3f, - 0x13, 0x9f, 0xdd, 0xf0, 0xf7, 0xfc, 0x85, 0x27, 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, - 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, - 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, - 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, - 0xde, 0x14, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, - 0x7c, 0x38, 0xd4, 0x2f, 0x84, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, - 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, - 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, 0xaa, 0xda, 0xbf, 0x25, 0x49, 0xb5, 0xab, 0xb4, - 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, - 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, - 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, - 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, - 0x89, 0x17, 0xe3, 0x69, 0x4d, 0x2c, 0xa9, 0x5d, 0x81, 0x31, 0x7a, 0x5c, 0x15, 0xb5, 0x4f, 0xfd, 0x02, 0x42, 0x91, - 0x6a, 0xcd, 0x1c, 0x6b, 0xdc, 0x18, 0x11, 0x77, 0x58, 0xb9, 0x76, 0x6a, 0xaf, 0x03, 0xb0, 0xbc, 0x1a, 0x17, 0x84, - 0x4d, 0x72, 0xec, 0x5c, 0xc0, 0x6a, 0x34, 0xa4, 0xda, 0x0d, 0xb7, 0x5e, 0x76, 0x7e, 0xf3, 0x38, 0xb1, 0xb5, 0x11, - 0x6e, 0x29, 0xa0, 0x8c, 0xf2, 0x1b, 0xcb, 0x09, 0xbb, 0x53, 0xbd, 0x23, 0x55, 0x3b, 0xe2, 0xc4, 0x05, 0x2c, 0x37, - 0x3c, 0xb5, 0xfa, 0x26, 0x06, 0x27, 0x42, 0xd5, 0x4a, 0xc7, 0x6b, 0x3f, 0xe2, 0x7e, 0x75, 0x5f, 0xf7, 0x4a, 0xf0, - 0x93, 0x90, 0xd7, 0x6f, 0x79, 0x07, 0x80, 0x15, 0x1f, 0xf2, 0x62, 0x5a, 0x38, 0x5a, 0x97, 0x41, 0x19, 0x20, 0x42, - 0x33, 0x00, 0x3a, 0xb9, 0x3a, 0x88, 0xd2, 0xc0, 0x15, 0x77, 0x88, 0xf0, 0xd3, 0xe8, 0x59, 0xfe, 0x22, 0x7c, 0x56, - 0x4d, 0xc3, 0x8b, 0x3c, 0x88, 0x2e, 0xaa, 0x20, 0x7a, 0x56, 0x5d, 0x85, 0xcf, 0xf2, 0x69, 0x74, 0x91, 0x07, 0xe1, - 0x45, 0xd5, 0xd8, 0x77, 0xed, 0xee, 0x9e, 0x90, 0xb7, 0x5d, 0xfd, 0x91, 0x73, 0x65, 0x4f, 0x99, 0x9e, 0x9f, 0xd7, - 0x7a, 0xa5, 0x76, 0x9b, 0xeb, 0x35, 0x6a, 0xa6, 0x3e, 0xca, 0xfe, 0x66, 0x1b, 0x0b, 0x8f, 0xe6, 0x10, 0xfa, 0x8c, - 0xb4, 0x98, 0x7b, 0x9c, 0xeb, 0xcd, 0x9e, 0x14, 0x06, 0x46, 0x4c, 0x2a, 0x19, 0x39, 0xbd, 0xc0, 0x45, 0xa8, 0x42, - 0x0c, 0x6b, 0xe9, 0x6a, 0x9f, 0x75, 0xe9, 0x0d, 0xd4, 0x35, 0xc5, 0xbe, 0x86, 0x0c, 0xbc, 0x68, 0x7a, 0x19, 0x8c, - 0x01, 0x39, 0x02, 0xef, 0xf8, 0x6c, 0x09, 0x07, 0xe6, 0x1a, 0xa0, 0x6f, 0x1e, 0xf5, 0x75, 0xb9, 0xe3, 0x6b, 0xd5, - 0x37, 0xd3, 0xf5, 0x48, 0x29, 0x3f, 0x56, 0xfc, 0xee, 0xe2, 0x39, 0xbb, 0xe5, 0x1a, 0x15, 0xe5, 0x17, 0xbd, 0x58, - 0xef, 0x81, 0xab, 0xee, 0x17, 0xb8, 0xcd, 0xe2, 0xb1, 0x2b, 0x0f, 0x58, 0xb6, 0x65, 0x0f, 0xec, 0x86, 0xbd, 0x67, - 0x4f, 0xd8, 0x5b, 0xf6, 0x8e, 0xfd, 0x84, 0xaa, 0x0d, 0x25, 0xe4, 0xf9, 0x0b, 0x7e, 0x2b, 0x4d, 0x8f, 0x12, 0x95, - 0xec, 0xc1, 0x36, 0xd3, 0x0c, 0x37, 0xec, 0x3d, 0x5f, 0x0c, 0x57, 0xec, 0x2d, 0x64, 0x43, 0x99, 0x78, 0xb0, 0x62, - 0x3f, 0x71, 0x05, 0x62, 0xa6, 0xcf, 0xc2, 0xd2, 0x12, 0x15, 0x4d, 0x99, 0x28, 0x43, 0xbf, 0xe5, 0xf8, 0x22, 0xfb, - 0x09, 0x8b, 0x90, 0x9f, 0x19, 0xae, 0xd8, 0x03, 0x5f, 0x0c, 0x56, 0xec, 0xbd, 0x36, 0x10, 0x0d, 0x36, 0x6e, 0x69, - 0x84, 0x64, 0xa5, 0xcb, 0x92, 0xd2, 0xf4, 0xd6, 0xbe, 0x06, 0x6e, 0xd8, 0x0d, 0xd6, 0xee, 0x09, 0x16, 0x8d, 0x02, - 0xff, 0x60, 0xc5, 0xde, 0x71, 0x09, 0xa0, 0xe6, 0x96, 0x27, 0xbd, 0x42, 0x75, 0x81, 0x74, 0x3f, 0x78, 0xc2, 0xe9, - 0x45, 0xf6, 0x0e, 0xcb, 0xa0, 0xaf, 0x0c, 0x57, 0x6c, 0x8b, 0xb5, 0xbb, 0x31, 0x96, 0x2d, 0xab, 0x7a, 0x12, 0x11, - 0x18, 0x05, 0x95, 0xd2, 0xf2, 0x6f, 0xc4, 0xb2, 0xa9, 0x9b, 0x06, 0xb5, 0xa1, 0x3f, 0x1f, 0x8c, 0xfe, 0xe2, 0xeb, - 0x77, 0x3f, 0x78, 0xa5, 0xbe, 0xf6, 0xfe, 0xe2, 0xb8, 0x56, 0x96, 0xe8, 0x5a, 0xf9, 0x2b, 0x2f, 0x67, 0xbf, 0xcc, - 0x27, 0xba, 0x96, 0xb4, 0xc3, 0x90, 0xaf, 0xe9, 0xec, 0x97, 0x0e, 0x67, 0xcb, 0x5f, 0x7d, 0xbf, 0x31, 0x5d, 0xac, - 0x3e, 0xab, 0x7b, 0xf7, 0x61, 0xb0, 0x69, 0x9c, 0x7a, 0xef, 0x4e, 0xd7, 0x1b, 0x9b, 0x59, 0x6b, 0xcf, 0xcc, 0xff, - 0xe1, 0x4a, 0x6f, 0x71, 0xe8, 0x6e, 0xf8, 0x76, 0xb8, 0xb1, 0x47, 0x41, 0x7e, 0x5f, 0x2a, 0x8d, 0xb3, 0x9a, 0xbf, - 0xf4, 0x3a, 0xa5, 0x58, 0x40, 0x34, 0xfa, 0x64, 0x24, 0xa1, 0x4b, 0x66, 0xe2, 0x19, 0xe2, 0x8b, 0x0c, 0x90, 0xb9, - 0x40, 0x34, 0xbb, 0xe7, 0xe3, 0xc9, 0xfd, 0x55, 0x3c, 0xb9, 0x1f, 0xf0, 0x4f, 0xa6, 0x05, 0xed, 0xc5, 0x76, 0xef, - 0xb3, 0x5f, 0x79, 0x61, 0x2f, 0xc7, 0x5f, 0x7c, 0xf6, 0x45, 0xb8, 0x2b, 0xf4, 0x17, 0x9f, 0xbd, 0x13, 0xfc, 0xd7, - 0x91, 0x26, 0xca, 0x60, 0xef, 0x6a, 0xfe, 0xeb, 0x08, 0x19, 0x3f, 0xd8, 0x67, 0xc1, 0xbf, 0x80, 0xef, 0x77, 0x95, - 0xa0, 0x55, 0xfc, 0x73, 0xad, 0x7e, 0xbe, 0x97, 0x71, 0x39, 0xf0, 0x26, 0xb4, 0x82, 0xde, 0xbc, 0xad, 0xe5, 0x4f, - 0xe2, 0xe1, 0x48, 0xd5, 0x53, 0xc3, 0x3f, 0x8b, 0xc5, 0x2c, 0xea, 0xa3, 0x74, 0x2a, 0x6f, 0x72, 0xcd, 0x33, 0x69, - 0x5d, 0xbe, 0x87, 0x50, 0xe0, 0x6b, 0x1b, 0xa2, 0x60, 0xc7, 0x71, 0x23, 0xb8, 0x66, 0xef, 0x84, 0xcf, 0xb2, 0xe9, - 0x96, 0xdf, 0xf0, 0x27, 0xfc, 0x1d, 0xdf, 0x05, 0x0f, 0xfc, 0x3d, 0x7f, 0xcb, 0x7f, 0xe2, 0x3b, 0xb6, 0x94, 0x68, - 0xa7, 0xf5, 0xf6, 0x32, 0xd8, 0xb2, 0x7a, 0x77, 0x19, 0x3c, 0xb0, 0x7a, 0xfb, 0x3c, 0xb8, 0x61, 0xf5, 0xee, 0x79, - 0xf0, 0x9e, 0x6d, 0x2f, 0x83, 0x27, 0x6c, 0x77, 0x19, 0xbc, 0x65, 0xdb, 0xe7, 0xc1, 0x3b, 0xb6, 0x7b, 0x1e, 0xfc, - 0x24, 0x31, 0x1e, 0xde, 0x09, 0xc9, 0x71, 0xf2, 0xae, 0x66, 0x86, 0x4f, 0x37, 0xf8, 0x2c, 0xac, 0x5f, 0x54, 0xc7, - 0xe0, 0x73, 0xcd, 0x74, 0x8b, 0x03, 0x21, 0x98, 0x6e, 0x6f, 0x70, 0x4b, 0x4f, 0x4c, 0xab, 0x82, 0x54, 0xb0, 0xae, - 0x76, 0x06, 0x8b, 0xba, 0x69, 0x9d, 0xc9, 0x8e, 0x5f, 0x62, 0xdc, 0xe1, 0x97, 0xb8, 0x60, 0xcb, 0xa6, 0xd3, 0x49, - 0xe7, 0xf4, 0x49, 0xa0, 0x37, 0x7f, 0xbd, 0xeb, 0x57, 0xd2, 0x77, 0xa6, 0x68, 0x78, 0xae, 0xb4, 0xc6, 0xad, 0x9d, - 0x3e, 0xb4, 0x76, 0x7a, 0x26, 0x55, 0x68, 0x11, 0x8b, 0xca, 0xa2, 0xaa, 0x90, 0x49, 0x3c, 0xc8, 0xb4, 0x3e, 0x2d, - 0x61, 0xa4, 0xc8, 0x04, 0x34, 0xfa, 0x82, 0x8e, 0x81, 0x9c, 0x2c, 0x0a, 0x6c, 0xc9, 0x37, 0x83, 0x84, 0xad, 0x79, - 0x3c, 0x1d, 0x26, 0xc1, 0x92, 0xdd, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x52, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, - 0x79, 0x6f, 0x95, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x56, 0xe9, 0x0d, 0x7e, 0xeb, 0xec, 0xe7, 0x6b, 0xb5, 0xbf, 0x83, - 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xaf, 0xec, 0x2d, 0x7d, 0x6b, - 0xb6, 0xe9, 0xff, 0xb4, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xc6, 0x9f, 0x3c, - 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xc7, 0x3f, 0x8d, 0xb6, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, - 0x68, 0xef, 0xe4, 0x95, 0xbd, 0x23, 0x6e, 0x79, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, - 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xab, 0xd9, 0xa7, 0xf9, 0x64, 0xcb, 0x8f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, - 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x3b, 0x7e, 0xbc, 0x89, 0x0f, 0xff, 0xe3, - 0x4a, 0xef, 0xbe, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, + 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0xd7, 0x13, 0x71, 0x49, 0x97, 0x24, 0xf5, 0x54, 0x42, + 0x49, 0x08, 0x76, 0xed, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, + 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xcb, + 0x79, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8b, 0x6d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, + 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xcc, 0xe5, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, + 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0xbf, 0xaa, 0x6c, 0x6c, 0x05, 0xe4, 0x90, 0x64, 0xb2, 0x58, 0x8d, 0xee, + 0xc4, 0xb2, 0x28, 0xc5, 0xcf, 0x58, 0x0f, 0xd7, 0x6c, 0xe1, 0x3e, 0x03, 0x42, 0xfb, 0x89, 0xd2, 0xde, 0x44, 0x9a, + 0xa0, 0x7b, 0xc5, 0xd6, 0x00, 0x32, 0x80, 0xa2, 0xae, 0x76, 0xeb, 0x73, 0x7e, 0x8e, 0xa4, 0x19, 0x0e, 0xa3, 0xdb, + 0xa7, 0xab, 0x60, 0x35, 0xb8, 0x46, 0xad, 0xf4, 0x35, 0x8b, 0x5b, 0x18, 0x54, 0x07, 0xb3, 0x84, 0x83, 0x9a, 0x59, + 0x6b, 0x23, 0x10, 0x4c, 0xf6, 0x50, 0x90, 0x33, 0x57, 0xb0, 0x0f, 0x0a, 0xd6, 0x92, 0xd7, 0xc1, 0xe1, 0xd6, 0xbe, + 0xac, 0x14, 0x57, 0xcf, 0xae, 0x92, 0xd6, 0x85, 0xa5, 0xbc, 0x7a, 0xd6, 0x80, 0xc1, 0xe5, 0x04, 0x9b, 0x2a, 0xf7, + 0x27, 0x5b, 0x00, 0xdd, 0x0a, 0x29, 0xe2, 0x45, 0x29, 0x6c, 0x5b, 0xf9, 0xcc, 0x09, 0x1b, 0x6c, 0xd9, 0x03, 0xdc, + 0x2b, 0x83, 0x92, 0xc1, 0x85, 0x18, 0xb7, 0x9b, 0x7d, 0x80, 0x2b, 0x18, 0x0a, 0x63, 0x1b, 0xfe, 0x3a, 0xf3, 0x22, + 0x25, 0xe0, 0x66, 0x88, 0xf2, 0xb5, 0x85, 0x93, 0x49, 0x4f, 0xae, 0x25, 0x8b, 0x01, 0x0b, 0x1a, 0x7c, 0x47, 0xad, + 0xbf, 0x33, 0xf9, 0x37, 0x9e, 0x1e, 0xfa, 0xc1, 0xe7, 0xcc, 0x5b, 0xfa, 0xec, 0x75, 0x2e, 0xa3, 0x35, 0x49, 0x94, + 0x57, 0x0f, 0x97, 0x20, 0x37, 0x2c, 0x47, 0x0f, 0x6c, 0x09, 0xe2, 0xc4, 0x72, 0x94, 0x50, 0x46, 0x57, 0xb8, 0x57, + 0x99, 0x2d, 0x13, 0x81, 0x14, 0x07, 0x96, 0x52, 0xee, 0x2d, 0x36, 0xc1, 0x12, 0xf7, 0x27, 0x92, 0x0b, 0x28, 0x79, + 0x00, 0xe5, 0x4a, 0x01, 0x01, 0x9f, 0x0e, 0xa0, 0x7c, 0x29, 0x2f, 0xc2, 0x9f, 0x38, 0x51, 0x83, 0xe5, 0xe8, 0xa1, + 0x61, 0x7f, 0xf5, 0x42, 0xcb, 0xfe, 0xb0, 0xd2, 0x9a, 0x86, 0x35, 0x5f, 0xc1, 0xb4, 0x98, 0xb8, 0x7d, 0xb9, 0xb6, + 0xab, 0xe2, 0xb3, 0xb5, 0x3a, 0xbb, 0xa9, 0x21, 0x09, 0xfb, 0x8a, 0xac, 0x02, 0x1c, 0xac, 0x8a, 0xb8, 0x67, 0x59, + 0x1e, 0xc2, 0xe8, 0xcf, 0x6d, 0x5a, 0x0a, 0x0b, 0x55, 0xd2, 0x3f, 0x34, 0xa5, 0x40, 0x2a, 0x13, 0x9d, 0x68, 0x21, + 0xb8, 0x02, 0x83, 0xc0, 0xbd, 0xc8, 0x6b, 0x00, 0x8c, 0x01, 0x97, 0x02, 0x65, 0xd9, 0x96, 0x10, 0x52, 0xdd, 0xcf, + 0x40, 0x6d, 0x27, 0xee, 0xd3, 0x88, 0xac, 0x85, 0xe8, 0xab, 0x60, 0xcc, 0x9c, 0xd7, 0xd2, 0x2d, 0x36, 0x5d, 0x6f, + 0xd7, 0xb7, 0xe8, 0x5c, 0xda, 0x72, 0xf3, 0x13, 0xb6, 0x58, 0x2b, 0x50, 0x36, 0x21, 0x69, 0xbb, 0xe2, 0x15, 0xca, + 0x26, 0xb4, 0xb4, 0x0f, 0xd4, 0xa3, 0x42, 0x75, 0xb2, 0xf5, 0x52, 0x3e, 0xb5, 0x08, 0xab, 0xc5, 0x55, 0xee, 0x07, + 0xa0, 0x9b, 0x4a, 0xab, 0x17, 0x75, 0x8d, 0xa6, 0x50, 0xab, 0x85, 0xe3, 0x46, 0x3b, 0x9b, 0x2e, 0xd3, 0x15, 0xe2, + 0xac, 0x4a, 0x3b, 0xf4, 0x0f, 0x99, 0x76, 0xbd, 0xec, 0xe8, 0x37, 0xe3, 0xea, 0x02, 0x17, 0x62, 0x03, 0x3e, 0xe7, + 0xfe, 0xf2, 0x7a, 0xcf, 0xe2, 0x1e, 0x44, 0x3c, 0x03, 0x7b, 0x52, 0xfb, 0x43, 0xf5, 0xa9, 0x2b, 0x18, 0xb2, 0x30, + 0x4a, 0xfd, 0x45, 0xca, 0x7b, 0x4f, 0x70, 0xdc, 0x3f, 0x57, 0x3d, 0xf6, 0xd7, 0x8c, 0x1f, 0xea, 0x62, 0x1b, 0x25, + 0x14, 0xd5, 0xd0, 0x5b, 0x17, 0xdb, 0x4a, 0xc4, 0xc5, 0x43, 0xde, 0x63, 0x98, 0x0c, 0x63, 0x21, 0x53, 0xe1, 0x4f, + 0x99, 0x0a, 0x1e, 0x21, 0x94, 0xb8, 0xdd, 0xf4, 0x48, 0xbb, 0x09, 0x71, 0x4a, 0xb5, 0x28, 0x65, 0x32, 0xfe, 0xad, + 0x9f, 0x40, 0x79, 0x4e, 0xd1, 0x32, 0xfd, 0xa4, 0x70, 0x99, 0xbe, 0xdd, 0x9c, 0x96, 0x9e, 0x89, 0x50, 0x67, 0x2e, + 0xb6, 0xb5, 0x4e, 0xc7, 0xd8, 0x29, 0x9d, 0xda, 0xb0, 0x77, 0xb9, 0xe2, 0xb2, 0xa2, 0xf0, 0x6f, 0x24, 0xb2, 0xea, + 0x19, 0x71, 0xfc, 0x9f, 0x59, 0xfb, 0x0c, 0xab, 0xc0, 0x2f, 0x03, 0x79, 0xbf, 0x00, 0xf8, 0xb8, 0xae, 0xcb, 0xf4, + 0x6e, 0x0b, 0xb4, 0x21, 0x34, 0xfc, 0x3d, 0x1f, 0x19, 0x30, 0xdd, 0x47, 0x38, 0x43, 0x7a, 0xa8, 0x73, 0x4e, 0x67, + 0x65, 0x3a, 0xe7, 0x2a, 0xac, 0x25, 0x38, 0xc8, 0x49, 0x53, 0xc9, 0x75, 0x09, 0x6a, 0x26, 0x70, 0xfb, 0xd0, 0x1e, + 0x11, 0x42, 0x6d, 0xca, 0x6a, 0x7a, 0x09, 0x35, 0xef, 0xe4, 0xb4, 0xa3, 0x49, 0x09, 0xae, 0x1a, 0x3a, 0x2b, 0xd7, + 0x7f, 0x1d, 0x8f, 0xbd, 0xbb, 0xac, 0x88, 0xfe, 0xe8, 0xa1, 0xbf, 0xe3, 0xee, 0x36, 0xfd, 0x02, 0xd1, 0x32, 0xd6, + 0xdf, 0x90, 0x01, 0x1d, 0x4f, 0x86, 0x77, 0xc5, 0xae, 0xc7, 0xde, 0xe5, 0x78, 0x81, 0x55, 0xd7, 0x8f, 0x3f, 0x40, + 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, 0x89, 0xb6, 0x85, 0x0f, 0x61, 0xa1, 0xef, 0x72, 0xd8, 0x84, 0xa1, + 0x79, 0xd4, 0x3d, 0x4a, 0xda, 0x85, 0xbe, 0xf4, 0xb5, 0xec, 0x2b, 0xdf, 0xb9, 0x02, 0x58, 0xd9, 0x67, 0x36, 0xdc, + 0x93, 0xfe, 0x94, 0xea, 0xc3, 0xf6, 0xb7, 0x64, 0x01, 0x85, 0x16, 0xd6, 0x53, 0x39, 0x3b, 0x37, 0x25, 0x4f, 0xb3, + 0xe9, 0x61, 0x03, 0x7b, 0xd4, 0x3d, 0x7a, 0x4d, 0x05, 0x97, 0xd7, 0x66, 0xf4, 0xfe, 0x61, 0x28, 0x54, 0x47, 0x9d, + 0x3b, 0xc8, 0xa6, 0xb4, 0x2e, 0x39, 0xbf, 0x59, 0xb9, 0xa3, 0x30, 0xbf, 0x0f, 0xc1, 0x33, 0xac, 0x7b, 0x77, 0x71, + 0xde, 0xfb, 0xb3, 0x35, 0x47, 0xfe, 0x9a, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0x0e, 0xbb, + 0xa0, 0x82, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, + 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xbb, 0xc0, 0xd0, 0xb6, 0x4d, 0x89, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x39, 0x51, 0xa1, + 0x59, 0xa4, 0xad, 0x92, 0xf1, 0xef, 0x44, 0x9b, 0x29, 0xd9, 0x63, 0x6b, 0xe0, 0xbd, 0x04, 0xe5, 0x64, 0x98, 0x62, + 0xf8, 0x8e, 0xaf, 0x77, 0x1e, 0x73, 0xcf, 0x39, 0x65, 0x9b, 0x94, 0x1d, 0xc1, 0x72, 0x22, 0x1b, 0xdf, 0x52, 0xbc, + 0xe1, 0xfb, 0xbb, 0x4a, 0x94, 0x00, 0x7a, 0x59, 0xf0, 0xe7, 0xd2, 0xe6, 0x0a, 0xdd, 0xee, 0xde, 0x51, 0x0a, 0xbf, + 0xe4, 0xe5, 0xf1, 0xb8, 0x4b, 0xbd, 0x10, 0x3a, 0x5f, 0xc4, 0xef, 0xc0, 0x1c, 0xc6, 0x10, 0x9b, 0x11, 0x20, 0xcc, + 0xf1, 0x01, 0x75, 0xb0, 0x7e, 0x04, 0xa0, 0x71, 0x02, 0x05, 0x18, 0x7d, 0xb5, 0x2d, 0xe8, 0x5b, 0x5e, 0x5c, 0x44, + 0x88, 0x1a, 0x05, 0x98, 0x28, 0x69, 0x16, 0xc3, 0x70, 0xa0, 0xf3, 0xfb, 0xf6, 0xae, 0x2e, 0x05, 0x0e, 0xbd, 0x63, + 0x19, 0xfe, 0xdb, 0xff, 0x58, 0x5b, 0x5a, 0x55, 0xb6, 0x5b, 0xe3, 0x34, 0xf3, 0xbf, 0xdd, 0x16, 0xfa, 0xfe, 0x4b, + 0xa1, 0x78, 0xde, 0xf1, 0xba, 0xfd, 0x05, 0xa2, 0xf7, 0x75, 0x2b, 0x57, 0xa5, 0x76, 0xc3, 0x4c, 0xf9, 0x43, 0x9a, + 0xc7, 0xc5, 0xc3, 0x28, 0x6e, 0x1d, 0x79, 0x93, 0xf4, 0x92, 0xf3, 0x2f, 0xe0, 0x6c, 0xfd, 0x05, 0xc8, 0x78, 0x5f, + 0x0a, 0xe3, 0x88, 0x49, 0x1c, 0x7c, 0x07, 0x31, 0x8a, 0xb6, 0x25, 0x6c, 0xc8, 0xed, 0xd3, 0x12, 0x34, 0x33, 0xfd, + 0x3e, 0x4a, 0x94, 0xd6, 0x7c, 0xff, 0x8b, 0x9c, 0xef, 0x2f, 0x85, 0xbc, 0x59, 0xc9, 0x0f, 0x9f, 0xac, 0x30, 0xf0, + 0x3d, 0x4e, 0xbf, 0x88, 0x1e, 0x5b, 0x95, 0x3e, 0x7c, 0x57, 0x5a, 0xfa, 0xac, 0xa2, 0xfe, 0x8e, 0x8a, 0x9a, 0x97, + 0x62, 0x44, 0xc4, 0x83, 0xa0, 0x9d, 0x6d, 0x97, 0xda, 0xb5, 0x04, 0xed, 0x82, 0x4d, 0x61, 0xff, 0x7a, 0x6c, 0xc8, + 0xab, 0x7e, 0xff, 0xe7, 0xca, 0x6b, 0xf1, 0xba, 0xeb, 0xd0, 0x94, 0x9f, 0x0a, 0x0f, 0x21, 0x80, 0xb5, 0x0c, 0x94, + 0xf1, 0x1c, 0x60, 0xd2, 0x45, 0x5e, 0xa3, 0x6c, 0x3a, 0x11, 0xf8, 0x98, 0x65, 0x37, 0x4e, 0x32, 0x0d, 0x30, 0xa3, + 0x9a, 0x62, 0xcc, 0x8a, 0x78, 0xb8, 0xf8, 0x88, 0x75, 0xd3, 0xd3, 0x2a, 0xb4, 0x7c, 0x0d, 0xc1, 0xba, 0xc8, 0x32, + 0x8e, 0x62, 0x26, 0x00, 0xd8, 0x7c, 0x04, 0xf9, 0x8a, 0xae, 0x0e, 0x49, 0x2b, 0x55, 0xde, 0xaf, 0x33, 0x22, 0xa3, + 0x49, 0x88, 0xe6, 0xb7, 0xf0, 0xc0, 0xbe, 0x6d, 0x66, 0x54, 0xa9, 0x67, 0x54, 0xee, 0x33, 0x1c, 0x96, 0xc2, 0x31, + 0xe2, 0xff, 0x2d, 0x55, 0x3d, 0x22, 0xd0, 0xab, 0x32, 0xad, 0xa2, 0x22, 0xcf, 0x45, 0x84, 0x08, 0xd5, 0xd2, 0x39, + 0x1c, 0xfa, 0xb1, 0xdf, 0xc7, 0x81, 0x30, 0x2f, 0xfe, 0xf4, 0x58, 0x57, 0xfe, 0x54, 0xe0, 0x5a, 0x49, 0x81, 0x53, + 0x51, 0x23, 0x44, 0x08, 0xef, 0x4f, 0xe0, 0x59, 0x4d, 0x7d, 0xbf, 0xb1, 0x4c, 0x74, 0xff, 0xc8, 0x80, 0xf2, 0x07, + 0xe4, 0xeb, 0x5c, 0x8a, 0x33, 0x75, 0xf2, 0x98, 0x38, 0xe3, 0x00, 0xc4, 0x7c, 0x5d, 0xa2, 0xd1, 0xd8, 0xff, 0x80, + 0x04, 0x43, 0xf5, 0x83, 0x9d, 0x6e, 0xea, 0xfd, 0x33, 0x93, 0x38, 0x8a, 0x3e, 0x6d, 0x93, 0xa7, 0x92, 0xa5, 0xd1, + 0xc2, 0xd1, 0x7b, 0xc4, 0x30, 0x0e, 0xa7, 0xf3, 0x29, 0xc9, 0x36, 0x26, 0xab, 0x00, 0xd2, 0xc9, 0x4c, 0x1d, 0x53, + 0xea, 0x68, 0x9c, 0xeb, 0x05, 0x55, 0xe8, 0xb1, 0x2e, 0x79, 0x05, 0xd6, 0x93, 0x1f, 0xbd, 0xd2, 0x9f, 0x0a, 0x39, + 0x87, 0x8d, 0x44, 0x50, 0xf8, 0x01, 0xae, 0x06, 0x2b, 0x05, 0x0c, 0xa6, 0xbe, 0x85, 0xaf, 0x89, 0xe7, 0x28, 0x78, + 0x14, 0x76, 0x31, 0xb6, 0xe6, 0xbe, 0xf3, 0x49, 0x41, 0xb9, 0x67, 0xc5, 0x9c, 0xe7, 0xc0, 0xb9, 0x0c, 0x0a, 0x61, + 0x3a, 0x9e, 0xe5, 0xff, 0x4c, 0xf2, 0x7a, 0x62, 0x43, 0x80, 0x0c, 0xfe, 0x9c, 0x38, 0x2d, 0xdd, 0xa1, 0x3b, 0x0f, + 0x3d, 0x8b, 0x38, 0x6c, 0xf4, 0x64, 0x53, 0x16, 0xbb, 0x14, 0xf5, 0x12, 0xe6, 0x07, 0xf2, 0xf3, 0x96, 0xfc, 0x10, + 0xa2, 0x78, 0x1b, 0xfc, 0x9a, 0xb1, 0x58, 0xe0, 0x5f, 0x7f, 0xcb, 0x18, 0x4d, 0xb4, 0xe0, 0x5f, 0x59, 0x83, 0x44, + 0xc5, 0x3f, 0x65, 0x93, 0x1c, 0xb8, 0x4c, 0xd5, 0x87, 0xcf, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x39, 0xe8, + 0xd4, 0xe7, 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x96, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4b, 0xa9, 0x1a, 0xbf, + 0x65, 0x14, 0xbf, 0x93, 0xfb, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xf9, 0x7b, 0xc3, 0x99, 0x5d, 0xf6, 0xab, 0xb7, + 0x89, 0xcc, 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x35, 0x13, 0x7f, 0xae, 0x0c, 0xa7, 0xc4, 0xe5, 0xa5, 0x87, 0x2b, 0x36, + 0xad, 0x5e, 0xd2, 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0xa9, 0xf2, 0x00, 0x82, + 0x99, 0xd4, 0x04, 0x80, 0xb4, 0x10, 0x95, 0x42, 0xe4, 0x2f, 0x71, 0x56, 0x5f, 0xf2, 0xde, 0x36, 0x8f, 0x89, 0xb4, + 0xba, 0xd7, 0xef, 0xa7, 0x17, 0x69, 0x4e, 0x41, 0x0d, 0xa7, 0x59, 0xa7, 0x3f, 0x64, 0x41, 0x9d, 0xc8, 0x55, 0xfa, + 0x77, 0x37, 0xc8, 0xcb, 0xf8, 0xbe, 0xee, 0x7a, 0xfe, 0x44, 0xfd, 0xbd, 0xb7, 0xfe, 0xb6, 0x40, 0x70, 0x27, 0xa7, + 0x7e, 0xb2, 0x2a, 0xe5, 0x89, 0x71, 0x69, 0xef, 0xf9, 0x4d, 0x5d, 0x14, 0x59, 0x9d, 0x6e, 0x3e, 0x48, 0x3d, 0x8d, + 0xee, 0x8b, 0x03, 0x18, 0x83, 0xf7, 0x00, 0x78, 0xa6, 0x43, 0x03, 0xa4, 0xef, 0x19, 0x79, 0xb8, 0xcf, 0x2d, 0xf9, + 0x49, 0x65, 0x6d, 0x92, 0xb0, 0xa2, 0xd8, 0x0c, 0x63, 0x84, 0x92, 0x71, 0x1a, 0x3b, 0xbf, 0xdf, 0x57, 0x7f, 0xef, + 0x31, 0x8a, 0x8a, 0x8a, 0x3b, 0x45, 0xa3, 0xb2, 0xaa, 0x47, 0xdb, 0xc1, 0xf1, 0x78, 0x59, 0xd9, 0x38, 0xda, 0x7a, + 0x05, 0x1c, 0xac, 0x50, 0x29, 0x7b, 0x25, 0xc2, 0xf2, 0xc3, 0x95, 0xdf, 0xef, 0xc3, 0xbf, 0x32, 0xd2, 0xc2, 0xf3, + 0xa7, 0xf8, 0x6b, 0x51, 0x17, 0x18, 0x9e, 0x41, 0x6b, 0x34, 0x87, 0x60, 0x82, 0xbf, 0x77, 0xa0, 0x5e, 0x5a, 0x69, + 0x1f, 0x41, 0xb7, 0x02, 0x3d, 0xa8, 0x87, 0x3e, 0x4d, 0xda, 0x17, 0x12, 0x75, 0x7b, 0xab, 0xd3, 0xe8, 0x8f, 0x0a, + 0x2e, 0xa7, 0x30, 0x39, 0xdc, 0xd0, 0xa7, 0x75, 0xb8, 0xfb, 0x04, 0x4f, 0x7f, 0x06, 0xca, 0xad, 0xe3, 0x11, 0xc5, + 0x16, 0x70, 0xf3, 0x58, 0x87, 0x9f, 0x8b, 0x52, 0x46, 0xd4, 0xc7, 0xd3, 0x02, 0xb4, 0x77, 0x01, 0x3a, 0x60, 0x69, + 0x10, 0xaf, 0x90, 0x3c, 0x67, 0x23, 0x80, 0x65, 0x07, 0x96, 0xb3, 0x8c, 0x53, 0x98, 0x67, 0xf9, 0x5c, 0xad, 0xb4, + 0x8b, 0x32, 0xf1, 0x6a, 0x96, 0x81, 0xb3, 0xc0, 0x55, 0xee, 0xb3, 0x4c, 0xab, 0x9e, 0xf2, 0x04, 0x7d, 0x5e, 0xc9, + 0x09, 0xae, 0x04, 0x27, 0x1b, 0x90, 0x5f, 0x80, 0x24, 0x4d, 0x29, 0x6b, 0xca, 0xe7, 0xd7, 0x74, 0x43, 0x46, 0xcf, + 0x79, 0xcf, 0x8b, 0x86, 0xa1, 0x7f, 0xe5, 0x95, 0x10, 0xbe, 0x89, 0xdb, 0x36, 0x4a, 0x61, 0x7f, 0x11, 0x58, 0x7c, + 0xc2, 0x7e, 0xf4, 0x96, 0xfe, 0x74, 0x1c, 0x84, 0x43, 0xe4, 0x86, 0x8a, 0x39, 0xb0, 0xa7, 0x01, 0x8b, 0x4d, 0x7c, + 0xb3, 0x9d, 0xc4, 0x83, 0x81, 0xaf, 0x33, 0x16, 0xb3, 0x18, 0x68, 0x90, 0xe3, 0xc1, 0xf5, 0x5c, 0x9f, 0x10, 0xfa, + 0x61, 0x44, 0xe5, 0xa8, 0x40, 0xe7, 0x20, 0x1a, 0x2c, 0x01, 0x4f, 0xbd, 0x95, 0x0d, 0x92, 0x8c, 0x49, 0x26, 0x71, + 0xad, 0x49, 0xaa, 0xc3, 0x09, 0xad, 0x03, 0x1d, 0x57, 0x17, 0xd0, 0xf9, 0xb8, 0xee, 0x7d, 0xbc, 0x1a, 0x2e, 0xa8, + 0xf4, 0x2b, 0x31, 0xf0, 0xea, 0xe9, 0x38, 0xb8, 0xa6, 0x5b, 0xe1, 0x62, 0x1d, 0xee, 0x7e, 0x96, 0x0f, 0x1c, 0x77, + 0x54, 0xd2, 0x10, 0x18, 0xbc, 0x3d, 0x74, 0x37, 0x33, 0x34, 0xd4, 0x49, 0xfb, 0x30, 0x0e, 0xe5, 0x10, 0xab, 0x56, + 0x5c, 0x49, 0x6f, 0x04, 0xdf, 0x2e, 0x14, 0x63, 0xd9, 0xd8, 0xb5, 0xa1, 0x28, 0xfc, 0x15, 0xc0, 0x0e, 0xb5, 0xbf, + 0x52, 0xc9, 0xc7, 0xc8, 0xa8, 0xa6, 0x81, 0x8e, 0x01, 0x58, 0xb2, 0x34, 0x91, 0x54, 0x91, 0x46, 0xe2, 0x8f, 0xcc, + 0x58, 0x47, 0x4d, 0xd7, 0x17, 0x4c, 0x55, 0x8b, 0xa4, 0xdb, 0x99, 0xc4, 0x72, 0x22, 0x49, 0x6d, 0xf7, 0x11, 0x31, + 0x18, 0xf8, 0x60, 0x23, 0xa6, 0x99, 0x08, 0x47, 0x3c, 0x2a, 0x91, 0x45, 0x97, 0xdf, 0x46, 0x99, 0xb4, 0x7d, 0x59, + 0x91, 0x2d, 0x08, 0xa6, 0x27, 0xd1, 0x07, 0x49, 0xd0, 0xba, 0x48, 0xa4, 0x19, 0x21, 0xc0, 0x8f, 0x27, 0xe5, 0x8d, + 0xfe, 0x1c, 0x34, 0xad, 0x04, 0x2f, 0x19, 0x24, 0x8f, 0xc4, 0xcf, 0xa4, 0x60, 0x16, 0x63, 0xf9, 0x60, 0x80, 0xe5, + 0xe4, 0x4f, 0x1d, 0x93, 0xf4, 0x5f, 0x3a, 0x9d, 0xb0, 0x5f, 0x78, 0x95, 0xad, 0xe5, 0x4d, 0x73, 0xef, 0x85, 0x97, + 0xb3, 0x54, 0xc3, 0x32, 0xe8, 0xbf, 0x26, 0xda, 0x05, 0x5b, 0x5b, 0xc6, 0x84, 0x55, 0x3f, 0x80, 0xb4, 0x47, 0xba, + 0xbc, 0x7c, 0x58, 0x31, 0xc1, 0xa3, 0x2b, 0x6b, 0x1e, 0x44, 0x57, 0xc2, 0x47, 0x2e, 0xbb, 0x49, 0x72, 0x33, 0x9e, + 0xf8, 0xe1, 0x60, 0xa0, 0x00, 0x68, 0x69, 0x9d, 0x14, 0x83, 0xf0, 0xa9, 0x90, 0x03, 0x69, 0x74, 0x54, 0x05, 0x58, + 0x2c, 0xb3, 0x9b, 0x72, 0x92, 0x0d, 0x06, 0x3e, 0x88, 0x8d, 0x89, 0xdd, 0xd0, 0x6c, 0xee, 0xb3, 0x33, 0x05, 0x59, + 0x6d, 0x0e, 0x5b, 0x33, 0xdd, 0x02, 0x03, 0x80, 0x41, 0x44, 0xb0, 0xdc, 0x67, 0x46, 0x3e, 0xa2, 0x4e, 0x4f, 0x61, + 0x04, 0x04, 0xbf, 0x9e, 0x08, 0x44, 0x2e, 0x12, 0xa8, 0x07, 0x98, 0x09, 0x30, 0xa3, 0x8a, 0xe1, 0x35, 0xb0, 0x8b, + 0x57, 0xe6, 0x15, 0x83, 0xfe, 0x45, 0x93, 0x2c, 0xd1, 0x54, 0xe2, 0x68, 0x8c, 0x9c, 0x4a, 0x63, 0x64, 0x40, 0xec, + 0xe2, 0xf8, 0xf7, 0x94, 0x1e, 0x05, 0x29, 0xfb, 0x9c, 0x1b, 0xe2, 0x70, 0x14, 0x5f, 0xc1, 0xaa, 0x71, 0x3c, 0xd6, + 0xe6, 0xf5, 0x74, 0x56, 0xcf, 0x07, 0x22, 0x80, 0xff, 0x86, 0x82, 0xfd, 0xa2, 0xa9, 0xc8, 0x0d, 0x52, 0xe7, 0xf1, + 0x98, 0x82, 0x7c, 0xaa, 0x9b, 0xfc, 0x43, 0xee, 0xee, 0xa7, 0xb3, 0xb9, 0x35, 0x47, 0xaf, 0x6a, 0x5c, 0xb7, 0x56, + 0x37, 0x14, 0x12, 0xad, 0x69, 0x52, 0xdc, 0xe4, 0x93, 0x62, 0xc0, 0x2b, 0x5f, 0xa8, 0x2e, 0xb6, 0x46, 0xb0, 0xf0, + 0xe7, 0x16, 0x08, 0x93, 0x71, 0x2f, 0x3e, 0x59, 0xc8, 0x29, 0xed, 0xda, 0x6a, 0xb7, 0xb5, 0x49, 0xd3, 0x58, 0x35, + 0xbc, 0x86, 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, + 0x2d, 0x86, 0xff, 0x29, 0xdd, 0x9b, 0x53, 0x1b, 0xe4, 0x00, 0xb6, 0x7b, 0x0f, 0xb7, 0x63, 0xf4, 0x40, 0x06, 0x6f, + 0x04, 0x10, 0x8d, 0xaf, 0xa7, 0xd6, 0x8c, 0x89, 0x86, 0x05, 0x2b, 0x87, 0x91, 0x1f, 0x20, 0xe3, 0xe5, 0x14, 0x58, + 0xd9, 0x4f, 0x8a, 0xb8, 0xf6, 0x87, 0x91, 0x7f, 0xf5, 0x2c, 0xc8, 0xb8, 0x17, 0x0d, 0x3b, 0xbe, 0x00, 0x7b, 0xf5, + 0xd5, 0x33, 0x16, 0x0d, 0x78, 0x7e, 0x53, 0x4f, 0xb3, 0x60, 0x98, 0xb1, 0xe8, 0xa6, 0x18, 0x82, 0x0f, 0xed, 0xf3, + 0x72, 0x10, 0xfa, 0xbe, 0xd9, 0x39, 0x74, 0x37, 0x24, 0xf2, 0x08, 0xfb, 0x2b, 0xb8, 0xed, 0x6a, 0x89, 0x19, 0xe0, + 0x06, 0x56, 0x11, 0x33, 0xd8, 0xf2, 0x57, 0xcf, 0x0c, 0x97, 0x50, 0xfe, 0x5c, 0x6a, 0x36, 0x0a, 0x34, 0x27, 0xe7, + 0x68, 0x4e, 0x56, 0x42, 0x2d, 0xf9, 0xa4, 0xc2, 0xa9, 0x3a, 0x9f, 0x68, 0xbb, 0xd1, 0x18, 0x03, 0x17, 0xed, 0xb9, + 0x2d, 0x8c, 0xcc, 0x74, 0x91, 0xa2, 0x01, 0x0b, 0xcf, 0xc4, 0x29, 0x8d, 0x01, 0xed, 0xcb, 0x81, 0xa5, 0x0d, 0xf9, + 0xab, 0x9c, 0x19, 0x68, 0x1b, 0x52, 0x1a, 0x35, 0x03, 0x7f, 0xa6, 0x26, 0xcc, 0xaf, 0x60, 0x25, 0x82, 0xa8, 0x2e, + 0xc0, 0x24, 0xa9, 0xc8, 0x68, 0xa4, 0xac, 0x44, 0x72, 0x0e, 0x78, 0x1f, 0xc1, 0x93, 0x45, 0xec, 0x6a, 0x7f, 0x4a, + 0xff, 0xab, 0xc3, 0xe7, 0xda, 0x7f, 0x2a, 0x80, 0x85, 0x5c, 0x1a, 0x44, 0x06, 0x0a, 0x87, 0xd4, 0x54, 0x22, 0x4e, + 0x1c, 0xcf, 0xc0, 0xd7, 0x70, 0x81, 0xa6, 0x80, 0xfe, 0xa0, 0x66, 0x14, 0x91, 0x85, 0xbf, 0x7a, 0x76, 0x53, 0xb7, + 0x7a, 0x9e, 0x39, 0xaf, 0x41, 0x33, 0x03, 0x21, 0x3d, 0x4e, 0xd5, 0xdb, 0x90, 0xe8, 0xbc, 0xbc, 0xd4, 0x2f, 0x13, + 0x22, 0x59, 0x11, 0x79, 0xfa, 0x3e, 0x07, 0xf3, 0x88, 0x22, 0x74, 0x70, 0x65, 0x1e, 0x8f, 0x97, 0x82, 0xc2, 0x77, + 0x94, 0xe7, 0x03, 0x4e, 0xb3, 0x28, 0x01, 0x6d, 0x20, 0xab, 0x4c, 0x99, 0x9b, 0xa4, 0x65, 0xea, 0x3e, 0x80, 0x95, + 0x20, 0x47, 0x37, 0xa7, 0xa0, 0x50, 0x46, 0x82, 0x52, 0x5a, 0x0d, 0x42, 0xa9, 0x0e, 0x8b, 0x20, 0x72, 0xc8, 0x42, + 0xc0, 0xcd, 0x54, 0x34, 0x5a, 0xd2, 0xf0, 0x08, 0xe7, 0x06, 0x0a, 0x01, 0x48, 0xec, 0xa9, 0xa2, 0x8c, 0xcb, 0x61, + 0xce, 0xd6, 0x3c, 0x1c, 0xe2, 0xac, 0x49, 0x5b, 0x9e, 0x83, 0x38, 0x96, 0x4b, 0xbe, 0xc9, 0x11, 0x0c, 0x22, 0xf4, + 0x19, 0xf2, 0x27, 0xcb, 0xf9, 0x77, 0xe7, 0x30, 0xed, 0x08, 0x1f, 0x76, 0xb5, 0x05, 0x17, 0xb3, 0xbb, 0xf9, 0x04, + 0xe2, 0x5b, 0xee, 0xe6, 0xa7, 0x18, 0x22, 0x0b, 0x7f, 0xb0, 0x1a, 0x4a, 0xae, 0x28, 0x74, 0x59, 0x8f, 0x48, 0x91, + 0x3d, 0xdd, 0x70, 0x04, 0xc1, 0x81, 0x56, 0x0d, 0x32, 0x34, 0x12, 0x5f, 0x3d, 0x83, 0xac, 0xc1, 0x86, 0x7f, 0xce, + 0xc9, 0x59, 0xdd, 0x9f, 0x6c, 0xa1, 0x9a, 0x64, 0xb2, 0x56, 0x54, 0xce, 0x5f, 0xaf, 0xca, 0xf2, 0x6c, 0x55, 0x86, + 0xeb, 0x41, 0x57, 0x55, 0x96, 0x1c, 0xa9, 0x0d, 0xd0, 0x9a, 0xae, 0x10, 0x43, 0x21, 0x6b, 0xb0, 0xb4, 0xaa, 0xb2, + 0xa1, 0x3e, 0x81, 0x40, 0x1f, 0x60, 0x19, 0x35, 0xfb, 0xe9, 0xf0, 0x9f, 0xc1, 0x3f, 0x55, 0xc8, 0x52, 0x9d, 0xd6, + 0x99, 0xf8, 0x35, 0x58, 0x32, 0xfc, 0xe3, 0xb7, 0x60, 0x03, 0x58, 0x02, 0x64, 0xb9, 0xdb, 0xda, 0x68, 0xbd, 0xf2, + 0x0a, 0xf1, 0xae, 0xd6, 0x17, 0xfd, 0xd6, 0x6d, 0xa2, 0x56, 0x80, 0x11, 0x0a, 0x2d, 0x02, 0x6c, 0xf5, 0xc0, 0x3d, + 0x05, 0x3f, 0x10, 0xc3, 0xb9, 0x26, 0xad, 0xa9, 0x13, 0x5e, 0x67, 0xe3, 0x48, 0x44, 0xf5, 0x0e, 0x2e, 0xee, 0xf5, + 0xce, 0xe2, 0x6f, 0x54, 0x20, 0x00, 0xb2, 0x98, 0x62, 0xe3, 0xbc, 0x21, 0xbd, 0x32, 0xec, 0x24, 0xf4, 0xde, 0xb0, + 0x13, 0xc8, 0x8b, 0xc3, 0x4e, 0xa1, 0x4b, 0xb4, 0x9d, 0x22, 0x35, 0xd1, 0x76, 0xd2, 0x62, 0x1d, 0x96, 0x10, 0xfc, + 0xaa, 0xbd, 0x75, 0x94, 0xed, 0x8b, 0x2c, 0x61, 0xda, 0x02, 0x46, 0xb9, 0x55, 0x9f, 0x39, 0x45, 0xac, 0x95, 0xbd, + 0xd3, 0x49, 0x95, 0xbb, 0xc8, 0xa7, 0x56, 0x53, 0x64, 0xf2, 0x0f, 0xa7, 0x2d, 0x92, 0x4f, 0x7e, 0x6e, 0x37, 0x4c, + 0xa6, 0x7f, 0x3c, 0xf9, 0x02, 0xba, 0x22, 0x3b, 0x7d, 0x02, 0x01, 0x99, 0x0a, 0xaa, 0xd5, 0xad, 0x62, 0x9a, 0xb7, + 0xab, 0xec, 0xf6, 0x42, 0x89, 0xe1, 0x74, 0x76, 0x12, 0x1e, 0x6d, 0x86, 0x0c, 0x1c, 0x82, 0x40, 0x21, 0x54, 0x14, + 0xc3, 0x23, 0x50, 0x6b, 0x24, 0x1f, 0xe0, 0x47, 0xbb, 0x53, 0x41, 0xa4, 0x76, 0x53, 0x71, 0xe3, 0xe4, 0xa6, 0xeb, + 0xa5, 0x40, 0xad, 0x53, 0xb2, 0x02, 0x28, 0x21, 0xea, 0x4f, 0x62, 0x57, 0xbf, 0x84, 0x2b, 0x36, 0x3f, 0x34, 0x8a, + 0x9e, 0x5c, 0x9f, 0xa2, 0x6e, 0xc5, 0xd5, 0x69, 0xda, 0x6a, 0x8e, 0x1d, 0x67, 0xc8, 0xc1, 0xb3, 0x82, 0x60, 0x3b, + 0x2a, 0x51, 0xbe, 0x6d, 0x37, 0x1d, 0x13, 0x5b, 0xfd, 0xb3, 0xa8, 0xb6, 0x2b, 0xa8, 0x88, 0x88, 0x4f, 0xb2, 0x9b, + 0x27, 0xed, 0x77, 0xb0, 0xc7, 0x5a, 0x0d, 0x22, 0xfb, 0x0c, 0xae, 0x72, 0x9d, 0x16, 0xb9, 0x2d, 0x83, 0xf3, 0x0f, + 0xaf, 0x76, 0x15, 0x36, 0x39, 0xd6, 0xd5, 0xd5, 0x4c, 0x75, 0x52, 0xb1, 0x81, 0xb1, 0xa6, 0xb5, 0x54, 0xf3, 0x18, + 0x92, 0xee, 0xca, 0xe2, 0xac, 0x4a, 0xba, 0xe9, 0xb9, 0x71, 0xa6, 0x10, 0x03, 0x67, 0xab, 0xd1, 0x72, 0x86, 0x21, + 0xba, 0x3e, 0xcc, 0x12, 0xbf, 0xd5, 0x53, 0xee, 0xf3, 0x70, 0xe7, 0x77, 0xf5, 0x82, 0x93, 0xc9, 0x7e, 0x72, 0x9a, + 0xbb, 0x5d, 0xa4, 0xfd, 0xc4, 0xb7, 0x61, 0xfe, 0xf5, 0x0d, 0x62, 0x25, 0xea, 0x7f, 0x54, 0x00, 0x34, 0xb8, 0xcd, + 0x63, 0x89, 0x52, 0x7f, 0x50, 0xd5, 0x0f, 0x6a, 0xa6, 0x6a, 0x1a, 0x08, 0xe6, 0x54, 0x0a, 0xf8, 0xc3, 0xed, 0xc2, + 0x15, 0x8f, 0xb8, 0x61, 0x61, 0xfc, 0xd3, 0xab, 0xd9, 0xb9, 0xa0, 0x32, 0x70, 0x33, 0xfe, 0xd3, 0x13, 0xec, 0x1c, + 0xd6, 0x0a, 0xc8, 0x0a, 0x7f, 0x7a, 0xd5, 0x23, 0xef, 0xe7, 0xfc, 0x4f, 0x2f, 0x7f, 0xe4, 0x7d, 0xc4, 0x79, 0xf9, + 0x13, 0x49, 0x9d, 0x10, 0xd5, 0xe5, 0x4f, 0xc2, 0x14, 0x5b, 0xa7, 0xf9, 0x2b, 0x52, 0xf8, 0x04, 0x9f, 0x81, 0xef, + 0x70, 0x1d, 0xee, 0xcc, 0x6f, 0xf0, 0xd8, 0xb1, 0xd8, 0x76, 0xa9, 0x2f, 0xa0, 0x1c, 0x81, 0x45, 0x54, 0xf6, 0xdb, + 0xb9, 0xfd, 0x6a, 0x61, 0x94, 0x31, 0x76, 0x5f, 0xb2, 0x12, 0xa5, 0xb3, 0x7e, 0xbf, 0x90, 0x82, 0x91, 0x5d, 0x58, + 0xa3, 0x3d, 0x4a, 0xd5, 0xab, 0x6f, 0xc3, 0x3a, 0x4a, 0xd2, 0x7c, 0x25, 0xa3, 0x8f, 0x64, 0xd8, 0x91, 0xbe, 0x92, + 0x12, 0xed, 0xb5, 0x0a, 0xcb, 0xd1, 0xec, 0xd7, 0x25, 0x07, 0xca, 0xeb, 0x56, 0x50, 0xbe, 0x6a, 0x02, 0xe8, 0x95, + 0x6a, 0x9f, 0x01, 0x23, 0xa7, 0xb0, 0x54, 0x1e, 0xac, 0xc4, 0xb9, 0xe8, 0xb3, 0xe2, 0x78, 0xf4, 0x2c, 0x34, 0xf3, + 0x0a, 0x1e, 0x84, 0x3b, 0x0b, 0x23, 0x15, 0x2e, 0x84, 0xe2, 0x79, 0x85, 0xb1, 0x15, 0x15, 0x70, 0x20, 0xc3, 0x0f, + 0x08, 0xbc, 0x97, 0xfd, 0x2b, 0x18, 0x0c, 0x13, 0xdc, 0xc8, 0xa8, 0x93, 0x2b, 0xf6, 0x27, 0x06, 0x66, 0x50, 0x4f, + 0x6a, 0xf7, 0xd9, 0x83, 0x0a, 0xec, 0x85, 0x33, 0xa0, 0xbd, 0x1b, 0xa3, 0x9f, 0x55, 0xb1, 0x71, 0xd2, 0x3f, 0x15, + 0x1b, 0x48, 0xa6, 0xc3, 0xe2, 0x64, 0x9b, 0x86, 0x47, 0xf2, 0xe4, 0x38, 0xdd, 0xf4, 0x8f, 0xc7, 0x31, 0x7e, 0x1c, + 0xe5, 0xd7, 0x16, 0xf0, 0x2a, 0x6e, 0x21, 0x8d, 0x45, 0x8a, 0xde, 0x81, 0x98, 0x43, 0xd1, 0x4b, 0xf6, 0x5b, 0xc6, + 0xcb, 0x89, 0xa0, 0x94, 0x24, 0x36, 0xbc, 0x23, 0x3d, 0x4d, 0xeb, 0xd1, 0x4e, 0x06, 0xec, 0xd7, 0xa3, 0x3d, 0xfd, + 0x05, 0x8a, 0x47, 0x0b, 0x7f, 0x49, 0x7f, 0x17, 0x77, 0x73, 0xcf, 0xf9, 0xa6, 0xf1, 0x1d, 0x71, 0x81, 0x62, 0xcd, + 0xee, 0xaf, 0x69, 0xe9, 0xac, 0x03, 0xc1, 0x01, 0x6f, 0xb1, 0x8b, 0xf6, 0xfd, 0xc6, 0x75, 0x7a, 0x3a, 0x7c, 0xeb, + 0xd6, 0x28, 0xdf, 0xfb, 0x87, 0x44, 0x39, 0x38, 0xbc, 0x72, 0xd1, 0xfc, 0xed, 0xa7, 0x0c, 0x49, 0x85, 0xe6, 0x06, + 0xdb, 0xc9, 0x16, 0x61, 0x6d, 0x8c, 0x83, 0x9c, 0xad, 0xca, 0x30, 0x02, 0x06, 0x75, 0xec, 0x7f, 0xf4, 0xd9, 0xb4, + 0x21, 0xfb, 0x00, 0x50, 0xb9, 0x0a, 0x01, 0x7b, 0x00, 0x4e, 0x34, 0xc2, 0x0d, 0x70, 0xab, 0xd1, 0x92, 0x0e, 0xea, + 0xb6, 0x60, 0x20, 0x5a, 0xc2, 0xc6, 0x09, 0x5d, 0xdf, 0x57, 0x84, 0x8f, 0xca, 0xb7, 0x0f, 0xe5, 0xaf, 0x9e, 0xb3, + 0xff, 0xde, 0x61, 0x4d, 0x4d, 0xb9, 0x05, 0xcc, 0x9c, 0xb5, 0xc8, 0x2b, 0x84, 0x4e, 0x91, 0xdf, 0xab, 0xba, 0x12, + 0xc3, 0x65, 0x2d, 0xca, 0xce, 0xec, 0xd6, 0x89, 0xde, 0x39, 0x05, 0xb5, 0x54, 0x36, 0x20, 0x01, 0x6e, 0x20, 0xc5, + 0xb6, 0xc0, 0x92, 0xce, 0x06, 0x28, 0xfe, 0x0d, 0x2a, 0xed, 0xfe, 0xdf, 0x39, 0x13, 0xd4, 0x6c, 0xa3, 0xba, 0xbf, + 0xd2, 0x4f, 0x55, 0x4d, 0x62, 0x01, 0x2e, 0x27, 0x69, 0xde, 0xf1, 0x08, 0xab, 0x7f, 0x9a, 0x2c, 0x45, 0xa0, 0x57, + 0x11, 0xed, 0x4a, 0x40, 0x82, 0x76, 0x76, 0x16, 0x2a, 0x02, 0x05, 0xfa, 0xfa, 0x0f, 0xdb, 0x34, 0x8b, 0xe5, 0x6a, + 0xb6, 0x87, 0x89, 0xb2, 0x58, 0x0f, 0x11, 0xe4, 0xcc, 0xd4, 0xc1, 0x7e, 0x4f, 0x33, 0x9a, 0x85, 0x37, 0xa6, 0x04, + 0x97, 0xe2, 0x2a, 0x2a, 0x72, 0xf0, 0x39, 0xc4, 0x17, 0x3e, 0x15, 0x72, 0x83, 0x88, 0xa6, 0x3f, 0xe4, 0x9e, 0x79, + 0x83, 0x85, 0x92, 0x9f, 0x10, 0x7f, 0xc9, 0xda, 0x18, 0xf7, 0x4b, 0xa7, 0xda, 0x2f, 0x15, 0x82, 0xfb, 0xcf, 0xb6, + 0xd8, 0xa8, 0xf2, 0x44, 0x8f, 0x3e, 0xc5, 0xfa, 0x9f, 0x2d, 0xa0, 0x54, 0xf7, 0x6d, 0x70, 0x2a, 0x1e, 0x85, 0xdb, + 0xba, 0xb8, 0x45, 0x68, 0x81, 0x72, 0x54, 0x15, 0xdb, 0x32, 0x22, 0x4e, 0xd8, 0x6d, 0x5d, 0xf4, 0x34, 0x07, 0x3a, + 0x75, 0x58, 0x9a, 0xc8, 0x13, 0xa1, 0xdd, 0x82, 0xee, 0x69, 0x8e, 0x95, 0x78, 0x21, 0x4b, 0x07, 0x59, 0x27, 0xd2, + 0x84, 0xca, 0x5d, 0x5d, 0x75, 0x52, 0x2a, 0x75, 0xc3, 0xeb, 0x54, 0x33, 0xfe, 0x2e, 0xcd, 0x9f, 0x58, 0xf6, 0xeb, + 0xd6, 0x6f, 0xb5, 0xda, 0x1b, 0xab, 0x47, 0x25, 0x6b, 0x8e, 0xb3, 0x09, 0x49, 0xe9, 0x13, 0xb6, 0x9b, 0x49, 0xd7, + 0x3a, 0xf0, 0x24, 0xb8, 0x1c, 0x7a, 0x02, 0x2a, 0x06, 0x4d, 0xbc, 0xdd, 0x05, 0xea, 0x11, 0x78, 0x06, 0xaa, 0x19, + 0x24, 0xd7, 0x01, 0xbf, 0xac, 0xb5, 0x3c, 0x65, 0x84, 0x61, 0xb5, 0xb3, 0x68, 0x39, 0x58, 0x49, 0x78, 0xae, 0x08, + 0x5c, 0xbb, 0x12, 0x78, 0x35, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, + 0xa7, 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, + 0x36, 0x9f, 0x43, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, + 0xcf, 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, + 0x76, 0x7a, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, + 0x88, 0xc2, 0x2c, 0xfb, 0x6b, 0x51, 0xfc, 0x51, 0xe9, 0x3b, 0x02, 0x1d, 0xdd, 0x79, 0x51, 0xa7, 0xcb, 0xfd, 0x07, + 0xc2, 0x78, 0xf2, 0xea, 0x13, 0xa2, 0x5b, 0xdf, 0x67, 0xee, 0x57, 0x80, 0x1b, 0xc1, 0x1d, 0x44, 0x7b, 0xb7, 0xd4, + 0x27, 0xb5, 0xfa, 0x5a, 0xaf, 0x9d, 0xa7, 0xe7, 0x37, 0x9d, 0xdb, 0xef, 0xa1, 0x39, 0xd9, 0x7a, 0x4f, 0x0b, 0x6b, + 0x65, 0xe9, 0xa9, 0x2a, 0xd8, 0x9b, 0xe5, 0xb9, 0x2a, 0x98, 0x3c, 0xf0, 0x9a, 0xfd, 0x82, 0x06, 0x57, 0x3a, 0xd9, + 0x78, 0xcf, 0xd4, 0xc0, 0x2d, 0x0a, 0x4b, 0x87, 0x5f, 0x72, 0x33, 0x79, 0x89, 0xfb, 0x4b, 0x45, 0x2e, 0xf6, 0x9d, + 0x33, 0xba, 0x33, 0xb3, 0xee, 0x55, 0x85, 0xab, 0x05, 0xb9, 0x3a, 0xb0, 0xb5, 0xec, 0xe2, 0x70, 0xc3, 0x22, 0x0a, + 0x10, 0x88, 0xe9, 0x95, 0x5a, 0xfb, 0x13, 0x1a, 0x84, 0x6a, 0x30, 0xf0, 0x0b, 0x0c, 0x56, 0x05, 0x0a, 0x1f, 0x28, + 0x92, 0xbf, 0xf2, 0x04, 0xec, 0xe2, 0x19, 0xa0, 0x5b, 0xb1, 0x59, 0x31, 0x42, 0x84, 0x4c, 0x56, 0xb1, 0x9a, 0xce, + 0x20, 0x9f, 0xfa, 0xe2, 0x1b, 0x5b, 0x75, 0x3e, 0x6f, 0x6b, 0xaa, 0x9c, 0x3b, 0x14, 0xba, 0xbb, 0xa9, 0x3b, 0xb7, + 0x2e, 0xf2, 0xdc, 0x21, 0xe4, 0x4a, 0xc5, 0x4a, 0x4c, 0x43, 0xcd, 0x93, 0x34, 0xa3, 0xfe, 0x62, 0x9f, 0x8a, 0x1a, + 0x85, 0x53, 0xfe, 0x74, 0x0c, 0xaa, 0x70, 0x55, 0x43, 0x1c, 0x4b, 0x55, 0x3c, 0xb2, 0x41, 0xa0, 0x79, 0x75, 0xa7, + 0x92, 0x26, 0x64, 0x72, 0x23, 0x7c, 0x6a, 0x52, 0xca, 0xd3, 0xb4, 0x49, 0x2b, 0x45, 0xea, 0xe0, 0x83, 0x3a, 0xd5, + 0x78, 0x6e, 0xe6, 0xcf, 0x01, 0xcc, 0xb8, 0xba, 0xe1, 0xd7, 0x8a, 0xcb, 0xa8, 0xad, 0xcc, 0xa4, 0xfd, 0xc9, 0xd1, + 0xd8, 0x28, 0x56, 0xe3, 0x46, 0x19, 0x61, 0xa5, 0x34, 0x27, 0xc5, 0x72, 0x3c, 0xff, 0x80, 0xc1, 0x9a, 0x27, 0xb0, + 0x83, 0x89, 0x4a, 0x79, 0x1f, 0x01, 0xf1, 0x75, 0x92, 0xae, 0x12, 0x48, 0x91, 0xfe, 0xa5, 0x4b, 0xee, 0x32, 0x36, + 0x10, 0x63, 0x56, 0xcc, 0x8c, 0xfe, 0x07, 0x77, 0x49, 0x7f, 0x12, 0x02, 0xe0, 0x26, 0x9a, 0x42, 0xa7, 0xce, 0x93, + 0xab, 0x2a, 0x58, 0x5e, 0x79, 0x68, 0xc5, 0x88, 0x07, 0xff, 0xf9, 0x3c, 0x44, 0x10, 0x73, 0x4c, 0xf1, 0xf4, 0x0b, + 0xa3, 0xff, 0x08, 0xae, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, 0x21, 0xdc, 0xec, 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, + 0x6a, 0xf8, 0xd7, 0xdc, 0x83, 0xfe, 0xaf, 0x33, 0x61, 0xa9, 0xfd, 0xf4, 0x74, 0x00, 0x15, 0xbc, 0xaf, 0x78, 0x1b, + 0x11, 0xdf, 0x27, 0x7e, 0x1a, 0x0f, 0xb6, 0x4f, 0xb7, 0x60, 0xad, 0xfb, 0x50, 0x19, 0xeb, 0x2a, 0x61, 0x03, 0x01, + 0x5f, 0xa3, 0xa8, 0x3d, 0xaf, 0xdd, 0xee, 0xc1, 0x7f, 0xfa, 0x57, 0x21, 0x03, 0x26, 0x4e, 0xdf, 0x67, 0x4e, 0xd6, + 0xe8, 0x2a, 0x93, 0xe9, 0x43, 0x27, 0x7d, 0xab, 0xd3, 0x7d, 0x27, 0xfc, 0x23, 0x67, 0x16, 0x1f, 0x6e, 0xe9, 0x2b, + 0x4d, 0x8a, 0x3b, 0x60, 0x65, 0xf3, 0xa8, 0x20, 0xd4, 0xb9, 0x88, 0xbe, 0x32, 0xe5, 0x5b, 0x42, 0xcd, 0xa1, 0xb1, + 0xa4, 0x94, 0xee, 0x35, 0xf4, 0x3a, 0xad, 0xf5, 0xdb, 0x28, 0xc1, 0x98, 0xe8, 0x78, 0xf2, 0x32, 0x1e, 0x2b, 0xef, + 0xe3, 0x71, 0x23, 0x15, 0xf2, 0x00, 0x44, 0xa0, 0x62, 0xfc, 0xe9, 0xca, 0x53, 0x91, 0x5e, 0x18, 0xaf, 0x42, 0x29, + 0x28, 0x0c, 0xe8, 0x0a, 0xa4, 0x80, 0x47, 0xed, 0x89, 0xce, 0xc2, 0x2e, 0xe1, 0x1e, 0xdd, 0x04, 0x8c, 0xf5, 0xf9, + 0xaf, 0xb9, 0x97, 0x33, 0xe1, 0x0e, 0x2f, 0x06, 0xa8, 0x4d, 0xbd, 0xba, 0xfb, 0xb8, 0x56, 0xe7, 0x70, 0x08, 0x0e, + 0x56, 0x83, 0x08, 0x4e, 0xe7, 0x73, 0x47, 0xb3, 0x2c, 0x40, 0xe5, 0x64, 0x95, 0x91, 0x37, 0x4f, 0x16, 0xbd, 0xba, + 0xef, 0x2d, 0xd3, 0xb2, 0xaa, 0x83, 0x8c, 0x65, 0x61, 0x05, 0xb8, 0x3a, 0xb4, 0x7e, 0x10, 0x2e, 0x0b, 0xe7, 0x0f, + 0x84, 0x20, 0x76, 0xaf, 0xb6, 0x25, 0xd7, 0x47, 0xf5, 0xd3, 0x67, 0x6c, 0xc3, 0x25, 0xea, 0xa4, 0x33, 0x11, 0x80, + 0xd8, 0x53, 0xb3, 0x8a, 0x6e, 0x80, 0xa4, 0x4e, 0xb3, 0x8a, 0x6e, 0xa8, 0xd9, 0xc6, 0x38, 0x00, 0xca, 0x58, 0xc0, + 0xbe, 0x9b, 0x8e, 0x83, 0xf5, 0xd3, 0x58, 0x5e, 0x87, 0x56, 0x4f, 0xb7, 0xca, 0x67, 0x50, 0xb7, 0xda, 0x18, 0x13, + 0xdb, 0xcd, 0x97, 0x73, 0xfd, 0x6e, 0xb0, 0xf4, 0xed, 0xa0, 0x39, 0xa7, 0xec, 0x95, 0x2e, 0x7b, 0x6d, 0x97, 0x4d, + 0x3d, 0x77, 0x52, 0xb4, 0x1a, 0x03, 0x7a, 0x03, 0x0b, 0xd6, 0xe7, 0x22, 0xcd, 0x56, 0xa5, 0x2a, 0x01, 0x2f, 0x8c, + 0x35, 0x5b, 0xf9, 0x8d, 0xcc, 0x90, 0x84, 0x79, 0x9c, 0x89, 0xb7, 0x74, 0xaf, 0x85, 0xc9, 0x71, 0x2a, 0x92, 0x29, + 0xa1, 0x53, 0xba, 0xb3, 0x0d, 0x9d, 0xab, 0x30, 0x8a, 0x68, 0xad, 0xa4, 0xd2, 0x48, 0x60, 0x6a, 0x06, 0x28, 0x99, + 0x2b, 0x70, 0x4a, 0x97, 0xfb, 0xdf, 0x89, 0x18, 0x67, 0xbe, 0x28, 0x99, 0x01, 0xdd, 0xf2, 0xeb, 0x62, 0xd3, 0x4a, + 0x91, 0x11, 0xe6, 0xcd, 0x69, 0x7b, 0x5d, 0x1f, 0x02, 0xb9, 0x5a, 0x0e, 0x28, 0x1a, 0x07, 0x85, 0x0e, 0x97, 0x2a, + 0x01, 0xf6, 0x45, 0xe2, 0x67, 0x84, 0x2d, 0xed, 0x81, 0xdc, 0x1e, 0x9d, 0x09, 0x73, 0xc9, 0x49, 0x59, 0x76, 0x29, + 0xcd, 0xe0, 0x72, 0xe2, 0x4a, 0x70, 0x91, 0xde, 0xae, 0xa7, 0x49, 0x4b, 0xdb, 0xc7, 0x86, 0x73, 0x34, 0xb4, 0x0d, + 0xba, 0x63, 0x7f, 0x68, 0x2e, 0x16, 0xb1, 0x75, 0xb1, 0x18, 0x76, 0x66, 0x3f, 0x59, 0x2c, 0x40, 0x0e, 0x00, 0x47, + 0xdd, 0x96, 0x8f, 0xd9, 0x12, 0x38, 0xad, 0xa6, 0xd9, 0xd4, 0xdb, 0xf2, 0xfc, 0xa9, 0xea, 0xe9, 0x25, 0xaf, 0x9e, + 0x0a, 0x33, 0x16, 0x5b, 0x5e, 0x3d, 0xb5, 0x8e, 0x9c, 0xfc, 0xa9, 0x50, 0xa2, 0x75, 0x01, 0xcd, 0xc0, 0x6b, 0x0a, + 0x18, 0xb1, 0x64, 0x32, 0xa5, 0x8a, 0x3c, 0xee, 0x4d, 0xb7, 0x6a, 0xf0, 0x82, 0xc2, 0x21, 0x90, 0xd2, 0xe9, 0x57, + 0xcf, 0x98, 0x7e, 0xef, 0xea, 0x59, 0x87, 0xac, 0x6d, 0x98, 0x2e, 0xb7, 0xc3, 0x64, 0x50, 0xfa, 0x4f, 0xcd, 0xc4, + 0xb8, 0xb2, 0x26, 0x09, 0x20, 0xfe, 0x8d, 0xfd, 0x0e, 0x29, 0xdc, 0xbc, 0xbf, 0x1c, 0xc6, 0x8f, 0xbc, 0x1f, 0x23, + 0x7b, 0x92, 0x66, 0x88, 0x35, 0x93, 0x0a, 0xb9, 0xfb, 0x6a, 0xfd, 0x63, 0x62, 0x37, 0xd9, 0x03, 0x0b, 0x40, 0x6c, + 0x4d, 0x5b, 0xdd, 0xf2, 0x7e, 0xdf, 0x33, 0x45, 0x80, 0x1f, 0x94, 0x7f, 0x72, 0x67, 0x48, 0x06, 0x65, 0xd7, 0x0d, + 0x21, 0x1e, 0x94, 0x4d, 0xd3, 0x5e, 0x6f, 0x07, 0x67, 0x1e, 0xab, 0xeb, 0xb4, 0xb3, 0xb8, 0x5a, 0x64, 0x90, 0x56, + 0x1f, 0xb2, 0xd3, 0xcc, 0x3e, 0x3b, 0x59, 0x2a, 0xdd, 0xef, 0x43, 0x44, 0xdc, 0x49, 0xd6, 0xf6, 0xdb, 0x2d, 0xb8, + 0x86, 0x93, 0x41, 0xe8, 0xca, 0xde, 0x2e, 0xa3, 0x8d, 0x0b, 0x71, 0xda, 0x33, 0x9d, 0x2f, 0xf8, 0xf2, 0x28, 0xed, + 0x3c, 0x38, 0xd5, 0x13, 0x7d, 0x6e, 0xba, 0xab, 0x4c, 0xae, 0x75, 0x58, 0x8d, 0x41, 0x6d, 0x16, 0xb6, 0x70, 0x17, + 0xb6, 0xd1, 0x41, 0x6b, 0x5f, 0x16, 0xfc, 0x53, 0x06, 0xe0, 0x4b, 0xcf, 0x96, 0x5d, 0xaf, 0x49, 0xab, 0xd7, 0x32, + 0x0a, 0xb1, 0xa5, 0xed, 0xd5, 0xa7, 0xa3, 0x7c, 0xdc, 0x9c, 0x51, 0x5c, 0xc8, 0x51, 0x7e, 0xf4, 0x1a, 0xa2, 0xae, + 0x75, 0x1d, 0x17, 0x8b, 0x0e, 0x37, 0xae, 0xba, 0xed, 0xc6, 0xf5, 0x23, 0xe2, 0xad, 0xd1, 0x26, 0x85, 0x5a, 0x19, + 0x3b, 0x82, 0x97, 0x55, 0xc3, 0x21, 0x13, 0xc3, 0xa1, 0x84, 0x4c, 0x7d, 0xec, 0xde, 0xd0, 0xb4, 0xcf, 0x4f, 0x5b, + 0x3f, 0x62, 0xa9, 0x71, 0x14, 0x1b, 0xde, 0xf9, 0x3b, 0x8f, 0xad, 0x71, 0x25, 0x5f, 0x06, 0xb3, 0x5d, 0x41, 0xb5, + 0x35, 0xde, 0xb0, 0x57, 0xf1, 0x1f, 0x72, 0xa9, 0xe4, 0x6f, 0x7f, 0x86, 0x6b, 0x78, 0x6b, 0x4b, 0x07, 0x4d, 0x35, + 0xab, 0x98, 0xb9, 0x17, 0x9c, 0x7e, 0xdc, 0xbd, 0x22, 0x18, 0xfc, 0x9e, 0x8e, 0x82, 0x5c, 0x2c, 0xd5, 0x1a, 0x50, + 0x90, 0x4e, 0xec, 0x98, 0xca, 0x02, 0xc3, 0x00, 0xde, 0x90, 0x01, 0xf2, 0x98, 0xc2, 0xdd, 0x50, 0xe1, 0x85, 0xbf, + 0xe4, 0x64, 0x97, 0xc0, 0xb6, 0x66, 0x7c, 0xcc, 0x70, 0x07, 0x21, 0xff, 0x08, 0xb6, 0x62, 0x6b, 0x76, 0xc7, 0x16, + 0x0c, 0xc9, 0xc6, 0x71, 0x18, 0x63, 0x3e, 0x9e, 0xc4, 0x37, 0x62, 0x12, 0x0f, 0x78, 0x84, 0x8e, 0x11, 0x1b, 0x5e, + 0xcf, 0x62, 0x39, 0x80, 0x6c, 0xc5, 0x95, 0x0e, 0x08, 0xa1, 0xb1, 0xa1, 0x25, 0xaf, 0x0b, 0x83, 0x8b, 0x1d, 0xfb, + 0x2c, 0x47, 0x91, 0x8c, 0x43, 0xb0, 0x68, 0x55, 0x03, 0x0b, 0x13, 0xbb, 0xe3, 0xc5, 0x6c, 0x3d, 0xc7, 0x7f, 0x8e, + 0x47, 0x04, 0xc0, 0x0e, 0x0e, 0x0d, 0x5b, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x2b, 0xcb, 0xd3, 0x85, 0xdd, 0xf3, 0xb7, + 0x7c, 0xcc, 0x2e, 0x7f, 0xf4, 0x20, 0x72, 0xf6, 0xf2, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xbb, 0xd4, 0xcb, 0xd9, 0x1d, + 0x51, 0x10, 0xde, 0x81, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0xbe, 0xe5, 0x0b, 0x8c, 0x15, 0xbb, 0x48, 0x97, 0x1e, 0x66, + 0x84, 0xda, 0xd3, 0xf9, 0xb2, 0x51, 0x93, 0x70, 0x7b, 0xb3, 0x9c, 0x0c, 0x06, 0x5b, 0x7f, 0xcf, 0x37, 0xc0, 0x07, + 0x73, 0xf9, 0xa3, 0xb7, 0xa7, 0x72, 0xe1, 0x3f, 0xaf, 0xb3, 0xe4, 0xbd, 0xcf, 0xde, 0x0e, 0xf8, 0x02, 0xf0, 0x96, + 0xd0, 0x81, 0xeb, 0xde, 0x67, 0x12, 0xaf, 0xed, 0xad, 0xbe, 0x46, 0x20, 0x91, 0x2f, 0x00, 0x23, 0x26, 0xe6, 0xf7, + 0x5b, 0x88, 0xc0, 0x48, 0xc0, 0xb7, 0x55, 0x7b, 0xc4, 0xef, 0xb8, 0x01, 0xfc, 0xca, 0x7c, 0xf6, 0xc0, 0x43, 0xfd, + 0x33, 0xf1, 0xd9, 0x2d, 0x7f, 0xcf, 0x9f, 0x7b, 0x52, 0x92, 0x2e, 0x67, 0xef, 0xe7, 0x70, 0x3d, 0x94, 0xf2, 0x74, + 0x48, 0x3f, 0x1b, 0x83, 0x01, 0x84, 0x42, 0xe6, 0xad, 0x07, 0xac, 0x49, 0x21, 0xfe, 0x05, 0x7c, 0x3b, 0x4a, 0xd8, + 0xbc, 0xf5, 0x76, 0xbe, 0x96, 0x37, 0x6f, 0xbd, 0x07, 0x9f, 0xa2, 0x00, 0xab, 0xa0, 0x94, 0x05, 0x56, 0x41, 0xd8, + 0x68, 0x23, 0x8c, 0x81, 0xab, 0x77, 0x8d, 0xa1, 0xae, 0xe7, 0x88, 0x6d, 0x2b, 0x7d, 0x17, 0xbe, 0x83, 0x0c, 0xf8, + 0xe0, 0x75, 0x51, 0x12, 0x7d, 0x4e, 0x4d, 0x91, 0xb4, 0xee, 0xb9, 0xdf, 0x5a, 0x77, 0xb4, 0xa6, 0xd4, 0x47, 0x6e, + 0xc6, 0xc7, 0x63, 0xfd, 0x5c, 0x68, 0x91, 0x60, 0x0a, 0x1a, 0xd7, 0xa0, 0x2d, 0x40, 0xd0, 0xe7, 0x01, 0xb2, 0x96, + 0x14, 0x0b, 0xbe, 0xfd, 0x15, 0x62, 0xf0, 0xca, 0xf4, 0xce, 0xe5, 0x2a, 0x23, 0x61, 0x7b, 0xe1, 0xd7, 0xc3, 0xda, + 0x9f, 0x38, 0xb5, 0xb0, 0xb4, 0x9a, 0x83, 0xfa, 0xa9, 0x2d, 0xc7, 0xa9, 0xaa, 0xfd, 0x4b, 0x92, 0x54, 0xbb, 0x4a, + 0xcb, 0xe9, 0xbd, 0x7d, 0xd3, 0x65, 0x82, 0x8d, 0xfd, 0x80, 0xaa, 0x23, 0xab, 0x61, 0xf7, 0x85, 0xfa, 0xa2, 0xa7, + 0x64, 0x42, 0xf3, 0x51, 0x45, 0xf3, 0xec, 0x7e, 0xb3, 0xa3, 0xfe, 0xd3, 0xeb, 0xa1, 0x08, 0x90, 0xac, 0xd2, 0x62, + 0x29, 0x72, 0x36, 0xf6, 0xd3, 0x61, 0x92, 0xa9, 0xf0, 0x82, 0x74, 0x74, 0xf7, 0x1b, 0xf7, 0xb7, 0xdc, 0x40, 0xd6, + 0x68, 0xd5, 0x06, 0x63, 0xa5, 0x68, 0x19, 0xac, 0x6f, 0xc6, 0xfd, 0xbe, 0xb8, 0x19, 0x4f, 0x45, 0x50, 0x03, 0x71, + 0x91, 0x78, 0x3e, 0x9e, 0xd6, 0xc4, 0x92, 0xda, 0x15, 0x18, 0xa3, 0xc7, 0x55, 0x51, 0xfb, 0xd4, 0xcf, 0x21, 0x14, + 0xa9, 0xd6, 0xcc, 0xb1, 0xc6, 0x8d, 0x11, 0x71, 0x87, 0x95, 0x6b, 0xa7, 0xf6, 0x3a, 0x00, 0xcb, 0xab, 0x71, 0x41, + 0xd8, 0x26, 0xa7, 0xce, 0x05, 0xac, 0x46, 0x43, 0xaa, 0xdd, 0x70, 0xeb, 0x65, 0xe7, 0x37, 0x8f, 0x13, 0x5b, 0x1b, + 0xe1, 0x96, 0x02, 0xca, 0x28, 0xbf, 0xb1, 0x9c, 0xb0, 0x3b, 0xd5, 0x3b, 0x52, 0xb5, 0x23, 0xce, 0x5c, 0xc0, 0x2a, + 0xc3, 0x53, 0xab, 0x6f, 0x62, 0x70, 0x22, 0xe4, 0xad, 0x74, 0xbc, 0xf6, 0x23, 0xee, 0x57, 0xf7, 0x75, 0xaf, 0x04, + 0x3f, 0x09, 0x79, 0xfd, 0x96, 0x77, 0x00, 0x58, 0xf1, 0x21, 0x2f, 0xa6, 0x85, 0xa3, 0x75, 0x19, 0x94, 0x01, 0x22, + 0x34, 0x03, 0xa0, 0x93, 0xab, 0x83, 0x28, 0x0d, 0x5c, 0x71, 0x87, 0x08, 0x3f, 0x8d, 0x9e, 0x56, 0xcf, 0xc3, 0xa7, + 0xf9, 0x34, 0xbc, 0xaa, 0x82, 0xe8, 0x2a, 0x0f, 0xa2, 0xa7, 0xf9, 0x4d, 0xf8, 0xb4, 0x9a, 0x46, 0x57, 0x55, 0x10, + 0x5e, 0xe5, 0x8d, 0x7d, 0xd7, 0xee, 0xee, 0x09, 0x79, 0xdb, 0xd5, 0x1f, 0xb9, 0x54, 0xf6, 0x94, 0xe9, 0xe5, 0x65, + 0xad, 0x57, 0x6a, 0xb7, 0xb9, 0x5e, 0xa3, 0x66, 0xea, 0xa3, 0xec, 0x2f, 0xb6, 0xb1, 0xf0, 0x64, 0x0e, 0xa1, 0xcf, + 0x48, 0x8b, 0xb9, 0xc7, 0xb9, 0xde, 0x1c, 0x48, 0x61, 0x60, 0xc4, 0xa4, 0x92, 0x91, 0xd3, 0x0b, 0x5c, 0x84, 0x72, + 0xc4, 0xb0, 0x96, 0xae, 0xf6, 0x59, 0x97, 0xde, 0x40, 0x5d, 0x53, 0xec, 0x6b, 0xc8, 0xc0, 0x8b, 0xa6, 0xd7, 0xc1, + 0x18, 0x90, 0x23, 0xf0, 0x8e, 0xcf, 0x96, 0x70, 0x60, 0x6e, 0x00, 0xfa, 0xe6, 0x51, 0x5f, 0x97, 0x15, 0xdf, 0xa8, + 0xbe, 0x99, 0x6e, 0x46, 0x4a, 0xf9, 0xb1, 0xe6, 0xab, 0xab, 0x67, 0xec, 0x8e, 0x6b, 0x54, 0x94, 0x5f, 0xf4, 0x62, + 0xbd, 0x07, 0xae, 0xba, 0x5f, 0xe0, 0x36, 0x8b, 0xc7, 0xae, 0x3c, 0x60, 0xd9, 0x8e, 0x3d, 0xb0, 0x5b, 0xf6, 0x9e, + 0x3d, 0x61, 0x6f, 0xd8, 0x17, 0xf6, 0x13, 0xaa, 0x36, 0x94, 0x90, 0xe7, 0x2f, 0xf8, 0x9d, 0x34, 0x3d, 0x4a, 0x54, + 0xb2, 0x07, 0xdb, 0x4c, 0x33, 0xdc, 0xb2, 0xf7, 0x7c, 0x31, 0x5c, 0xb3, 0x37, 0x90, 0x0d, 0x65, 0xe2, 0xc1, 0x9a, + 0xfd, 0xc4, 0x15, 0x88, 0x99, 0x3e, 0x0b, 0x4b, 0x4b, 0x54, 0x34, 0x65, 0xa2, 0x0c, 0xfd, 0x86, 0xe3, 0x8b, 0xec, + 0x27, 0x2c, 0x42, 0x7e, 0x66, 0xb8, 0x66, 0x0f, 0x7c, 0x31, 0x58, 0xb3, 0xf7, 0xda, 0x40, 0x34, 0xd8, 0xba, 0xa5, + 0x11, 0x92, 0x95, 0x2e, 0x4b, 0x4a, 0xd3, 0x3b, 0xfb, 0x1a, 0xb8, 0x65, 0xb7, 0x58, 0xbb, 0x27, 0x58, 0x34, 0x0a, + 0xfc, 0x83, 0x35, 0xfb, 0xc2, 0x25, 0x80, 0x9a, 0x5b, 0x9e, 0xf4, 0x0a, 0xd5, 0x05, 0xd2, 0xfd, 0xe0, 0x09, 0xa7, + 0x17, 0xd9, 0x17, 0x2c, 0x83, 0xbe, 0x32, 0x5c, 0xb3, 0x1d, 0xd6, 0xee, 0xd6, 0x58, 0xb6, 0xac, 0xea, 0x49, 0x44, + 0x60, 0x14, 0x54, 0x4a, 0xcb, 0xbf, 0x11, 0xcb, 0xa6, 0x6e, 0x1a, 0xd4, 0x86, 0xfe, 0x7c, 0x30, 0xfa, 0x0f, 0x5f, + 0xbf, 0xfb, 0xc1, 0x2b, 0xf5, 0xb5, 0xf7, 0x17, 0xc7, 0xb5, 0xb2, 0x44, 0xd7, 0xca, 0x5f, 0x79, 0x39, 0xfb, 0x65, + 0x3e, 0xd1, 0xb5, 0xa4, 0x1d, 0x86, 0x7c, 0x4d, 0x67, 0xbf, 0x74, 0x38, 0x5b, 0xfe, 0xea, 0xfb, 0x8d, 0xe9, 0x62, + 0xf5, 0x59, 0xdd, 0xbb, 0x0f, 0x83, 0x6d, 0xe3, 0xd4, 0x7b, 0x7f, 0xbe, 0xde, 0xd8, 0xcc, 0x5a, 0x7b, 0x66, 0xfe, + 0x0f, 0x57, 0x7a, 0x87, 0x43, 0x77, 0xcb, 0x77, 0xc3, 0xad, 0x3d, 0x0a, 0xf2, 0xfb, 0x52, 0x69, 0x9c, 0xd5, 0xfc, + 0x85, 0x97, 0x77, 0x49, 0xb1, 0x80, 0x68, 0xf4, 0xc9, 0x48, 0x42, 0xd7, 0xcc, 0xc4, 0x33, 0xc4, 0x57, 0x19, 0x20, + 0x73, 0x81, 0x68, 0x76, 0xcf, 0xc7, 0x93, 0xfb, 0x9b, 0x78, 0x72, 0x3f, 0xe0, 0x9f, 0x4c, 0x0b, 0xda, 0x8b, 0xed, + 0xde, 0x67, 0xbf, 0xf2, 0xc2, 0x5e, 0x8e, 0xbf, 0xf8, 0xec, 0x9d, 0x70, 0x57, 0xe8, 0x2f, 0x3e, 0xfb, 0x22, 0xf8, + 0xaf, 0x23, 0x4d, 0x94, 0xc1, 0xbe, 0xd4, 0xfc, 0xd7, 0x11, 0x32, 0x7e, 0xb0, 0xcf, 0x82, 0xbf, 0x03, 0xdf, 0xef, + 0x2a, 0x41, 0xab, 0xf8, 0xe7, 0x5a, 0xfd, 0x7c, 0x2f, 0xe3, 0x72, 0xe0, 0x4d, 0x68, 0x05, 0xbd, 0x79, 0x57, 0xcb, + 0x9f, 0xc4, 0xc3, 0x91, 0xaa, 0xa7, 0x86, 0x7f, 0x16, 0x8b, 0x59, 0xd4, 0x27, 0xe9, 0x54, 0xde, 0xe4, 0x2d, 0xcf, + 0xa4, 0x75, 0xf9, 0x1e, 0x42, 0x81, 0xdf, 0xda, 0x10, 0x05, 0x7b, 0x8e, 0x1b, 0xc1, 0x5b, 0x06, 0xf0, 0x91, 0xd9, + 0x74, 0xc7, 0x6f, 0xf9, 0x13, 0xfe, 0x85, 0xef, 0x83, 0x07, 0xfe, 0x9e, 0xbf, 0xe1, 0x3f, 0xf1, 0x3d, 0x5b, 0x4a, + 0xb4, 0xd3, 0x7a, 0x77, 0x1d, 0xec, 0x58, 0xbd, 0xbf, 0x0e, 0x1e, 0x58, 0xbd, 0x7b, 0x16, 0xdc, 0xb2, 0x7a, 0xff, + 0x2c, 0x78, 0xcf, 0x76, 0xd7, 0xc1, 0x13, 0xb6, 0xbf, 0x0e, 0xde, 0xb0, 0xdd, 0xb3, 0xe0, 0x0b, 0xdb, 0x3f, 0x0b, + 0x7e, 0x92, 0x18, 0x0f, 0x5f, 0x84, 0xe4, 0x38, 0xf9, 0x52, 0x33, 0xc3, 0xa7, 0x1b, 0x7c, 0x16, 0xd6, 0x2f, 0xaa, + 0x63, 0xf0, 0xb9, 0x66, 0xba, 0xc5, 0x81, 0x10, 0x4c, 0xb7, 0x37, 0xb8, 0xa3, 0x27, 0xa6, 0x55, 0x41, 0x2a, 0x58, + 0x57, 0x3b, 0x83, 0x45, 0xdd, 0xb4, 0xce, 0x64, 0xc7, 0x2f, 0x31, 0xee, 0xf0, 0x4b, 0x5c, 0xb0, 0x65, 0xd3, 0xe9, + 0xa4, 0x73, 0xfe, 0x24, 0xd0, 0x9b, 0xbf, 0xde, 0xf5, 0x73, 0xe9, 0x3b, 0x53, 0x34, 0x5c, 0x6b, 0x8d, 0x5b, 0x3b, + 0x7d, 0x68, 0xed, 0xf4, 0x4c, 0xaa, 0xd0, 0x22, 0x16, 0x95, 0x45, 0x55, 0x21, 0x93, 0x78, 0x90, 0x69, 0x7d, 0x5a, + 0xc2, 0x48, 0x91, 0x09, 0x68, 0xf4, 0x05, 0x1d, 0x03, 0x15, 0x59, 0x14, 0xd8, 0x92, 0x6f, 0x07, 0x09, 0xdb, 0xf0, + 0x78, 0x3a, 0x4c, 0x82, 0x25, 0x5b, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x56, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, + 0x79, 0x6f, 0x9d, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x96, 0xeb, 0x0d, 0x7e, 0xe7, 0xec, 0xe7, 0x1b, 0xb5, 0xbf, 0x83, + 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xcf, 0xed, 0x2d, 0x7d, 0x67, + 0xb6, 0xe9, 0x7f, 0xb7, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xd6, 0x9f, 0x3c, + 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xcf, 0x3f, 0x8d, 0x76, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, + 0x68, 0xef, 0xe4, 0xb9, 0xbd, 0x23, 0xee, 0x78, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, + 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xf3, 0xd9, 0xa7, 0xf9, 0x64, 0xc7, 0x4f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, + 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x7b, 0x7e, 0xba, 0x89, 0x0f, 0xff, 0xed, + 0x4a, 0xef, 0xbf, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, 0xf8, 0x13, 0xcd, 0xd2, 0x20, 0xb2, 0x14, 0x8a, 0x3f, 0x99, 0x69, 0xa7, 0xee, 0x54, 0x59, 0xdd, 0x2d, 0xdf, 0xe2, - 0x1e, 0x7f, 0xcb, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0x6f, 0xaf, 0x16, 0x93, 0xc1, 0xe0, 0xd6, 0xdf, 0xdf, 0xf3, 0x70, - 0x76, 0x3b, 0x67, 0xd7, 0xfc, 0x9e, 0x16, 0xd3, 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, - 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, - 0xde, 0xdb, 0x9a, 0x86, 0xb7, 0xfc, 0xa3, 0x77, 0xed, 0x4f, 0xaf, 0x75, 0xcc, 0xcd, 0x44, 0x1d, 0x49, 0x6f, 0x2f, - 0x9e, 0xb3, 0x5f, 0xf9, 0x27, 0x79, 0x9c, 0x7c, 0x11, 0x72, 0xd2, 0xde, 0x20, 0x77, 0x13, 0x9d, 0x12, 0xef, 0xdc, - 0x44, 0xc2, 0x82, 0x40, 0x18, 0x8e, 0x9a, 0x3f, 0x4c, 0xca, 0xa9, 0xb7, 0x03, 0x6e, 0x57, 0x6e, 0xeb, 0x9f, 0x6f, - 0x39, 0xe7, 0x8b, 0xe1, 0xe5, 0xf4, 0x5d, 0xb7, 0x4b, 0x8f, 0x8a, 0x66, 0x53, 0x81, 0x6e, 0xb7, 0x18, 0x7b, 0x75, - 0x32, 0xb3, 0xcc, 0x25, 0x5f, 0x7a, 0x57, 0x9b, 0x99, 0xc7, 0xf4, 0x7e, 0x33, 0xcd, 0x90, 0xc8, 0x17, 0x08, 0x99, - 0x0e, 0x87, 0xbb, 0x73, 0x2c, 0x8f, 0x0f, 0xdf, 0x3e, 0x7b, 0x32, 0x78, 0x82, 0x91, 0x5b, 0x56, 0x34, 0xc8, 0x3b, - 0x3e, 0xcc, 0xea, 0xd6, 0x6d, 0xe3, 0xe2, 0xf9, 0xf0, 0x17, 0xc8, 0x1b, 0x74, 0x3d, 0x34, 0x45, 0xb4, 0xca, 0xef, - 0x28, 0xfa, 0x44, 0xc9, 0x41, 0xc7, 0x13, 0xa8, 0x1d, 0x52, 0xe0, 0xbe, 0x7b, 0xc6, 0x41, 0xbf, 0x81, 0xa5, 0xf6, - 0xfb, 0xe7, 0x9f, 0x88, 0x47, 0x1a, 0xc6, 0xfb, 0xfb, 0x30, 0xfa, 0x23, 0x2e, 0x8b, 0x35, 0x9c, 0xae, 0x03, 0xf8, - 0xdc, 0x33, 0x7d, 0xfb, 0xba, 0xf3, 0x7d, 0x3f, 0xf0, 0xb6, 0xfc, 0x86, 0xbd, 0xe3, 0xde, 0xe5, 0xf0, 0xad, 0xff, - 0xec, 0x09, 0x88, 0x4e, 0x30, 0x2e, 0x9f, 0x31, 0x12, 0xb6, 0xa3, 0x18, 0xb5, 0x0a, 0x3f, 0xd7, 0x10, 0xa2, 0xf5, - 0x09, 0x19, 0xbb, 0x20, 0xfd, 0x83, 0x02, 0xf4, 0x13, 0x02, 0xab, 0x49, 0x6a, 0x14, 0x98, 0xc4, 0xb7, 0x35, 0x24, - 0x90, 0x82, 0x05, 0x42, 0x6f, 0xa0, 0xf8, 0x54, 0xf0, 0x77, 0xc3, 0xcf, 0x24, 0xf9, 0x2d, 0x6a, 0x3e, 0x86, 0xbf, - 0x61, 0x68, 0x26, 0xd5, 0x43, 0x5a, 0x47, 0x89, 0xf7, 0x93, 0xbf, 0x8f, 0xc2, 0x4a, 0xa8, 0x63, 0x21, 0x48, 0xc5, - 0x90, 0x0b, 0x71, 0xf1, 0x7c, 0x72, 0x5b, 0x8a, 0xf0, 0x8f, 0x09, 0x3e, 0x93, 0x0b, 0x4d, 0x3e, 0xa3, 0x27, 0x8d, - 0x7c, 0xff, 0x41, 0xbe, 0x2f, 0x3b, 0x35, 0x58, 0xd4, 0x43, 0x7e, 0x5b, 0xbb, 0xef, 0xcb, 0x29, 0x41, 0x8f, 0xec, - 0x07, 0x34, 0x05, 0x03, 0x35, 0x01, 0x29, 0x43, 0x70, 0x0b, 0x57, 0x7d, 0x4f, 0x15, 0xe4, 0xcb, 0xef, 0x7d, 0x16, - 0x32, 0x5c, 0x65, 0x41, 0x48, 0x72, 0xa9, 0x90, 0xc2, 0xc6, 0x6d, 0x3d, 0xf8, 0xac, 0x31, 0x49, 0x24, 0xe4, 0x94, - 0x80, 0x24, 0x69, 0x6f, 0x20, 0x49, 0xc4, 0xf4, 0x1f, 0xae, 0x93, 0xa6, 0x59, 0x49, 0xe9, 0x86, 0x38, 0x55, 0xaf, - 0x91, 0xe6, 0x2c, 0x78, 0xcf, 0x60, 0xe9, 0x48, 0xb1, 0xe2, 0x9d, 0x31, 0x18, 0xeb, 0x60, 0xa1, 0x3b, 0x59, 0xdc, - 0xaf, 0x92, 0x30, 0x8d, 0x44, 0x95, 0x2f, 0x42, 0xfe, 0xfc, 0x97, 0x12, 0x7f, 0xf4, 0x96, 0x06, 0x22, 0x10, 0xfc, - 0x00, 0xad, 0x07, 0xac, 0xf1, 0xe0, 0x27, 0x56, 0x97, 0x61, 0x5e, 0x65, 0x54, 0xde, 0x6c, 0xc7, 0xb6, 0x73, 0xa6, - 0xaa, 0x16, 0x7c, 0x16, 0x86, 0x16, 0xed, 0x6c, 0xd5, 0x9c, 0xdc, 0xe6, 0x0d, 0xbe, 0x33, 0x49, 0x22, 0xb5, 0x94, - 0x44, 0xda, 0xea, 0xfa, 0x74, 0xe9, 0x75, 0x8b, 0x0a, 0x1a, 0x23, 0x40, 0x2f, 0x49, 0x77, 0x95, 0x4f, 0x28, 0x5e, - 0x59, 0x0d, 0xab, 0xe1, 0xa5, 0x43, 0x11, 0xc6, 0xda, 0x9b, 0x2b, 0x79, 0x76, 0x07, 0xd6, 0x23, 0xb4, 0x76, 0x55, - 0xea, 0x10, 0xb6, 0x9f, 0xe8, 0x3d, 0xa7, 0x52, 0x7f, 0x03, 0xaa, 0xc0, 0xa9, 0xa3, 0xa1, 0x3e, 0x6a, 0xa7, 0x90, - 0xed, 0xdc, 0x5b, 0x12, 0x54, 0xae, 0xe4, 0xa6, 0x4a, 0x8b, 0x52, 0xca, 0x94, 0xaf, 0x65, 0xb6, 0xb2, 0xfb, 0x64, - 0x00, 0xf1, 0x6c, 0x50, 0x20, 0xb9, 0xa8, 0xad, 0xe6, 0x20, 0x7d, 0x34, 0x4b, 0x1c, 0x6b, 0x07, 0x85, 0x97, 0x55, - 0x60, 0xe6, 0x32, 0x97, 0xcb, 0x41, 0xc1, 0x72, 0xbd, 0xd5, 0x4c, 0x33, 0xd5, 0x17, 0xb9, 0xbd, 0xcd, 0x78, 0x99, - 0xfe, 0x9b, 0x25, 0x03, 0x1e, 0x5d, 0x3c, 0xf7, 0x03, 0x48, 0x93, 0xbc, 0x0e, 0x90, 0x04, 0x9b, 0x83, 0x5d, 0xec, - 0x30, 0x6c, 0x15, 0x2b, 0x7b, 0xf2, 0x74, 0xb9, 0x43, 0x53, 0x2e, 0x61, 0x24, 0x27, 0xe6, 0x52, 0xea, 0xfb, 0x92, - 0xea, 0x86, 0x82, 0x93, 0x4d, 0x13, 0x50, 0x0a, 0x68, 0xb7, 0xe0, 0xbf, 0xf0, 0xa9, 0xa1, 0xd3, 0x02, 0x2c, 0xb5, - 0xdd, 0x80, 0xff, 0x42, 0xbf, 0xd8, 0x3e, 0xa2, 0x7e, 0x60, 0x1e, 0xec, 0xcd, 0xda, 0xca, 0x18, 0x10, 0x91, 0xb8, - 0x82, 0x3c, 0x12, 0xfc, 0xa0, 0xd8, 0xd3, 0x65, 0xe2, 0xc0, 0x99, 0xe2, 0x62, 0x29, 0xb5, 0x99, 0x79, 0xed, 0xb7, - 0xd4, 0xc4, 0x9b, 0x28, 0x89, 0x0a, 0xdb, 0x21, 0x8d, 0x5e, 0x52, 0xc6, 0x54, 0xc1, 0x86, 0xe8, 0xbe, 0x6e, 0x82, - 0x29, 0xf0, 0xa6, 0xaa, 0x02, 0x22, 0xd4, 0x5e, 0x64, 0x79, 0x7e, 0xd3, 0x05, 0x56, 0x17, 0x7c, 0x6c, 0x4c, 0xb3, - 0x0b, 0x56, 0x72, 0x35, 0x93, 0x3e, 0xf3, 0x76, 0xa0, 0x85, 0xbc, 0xcb, 0xcb, 0xa2, 0x15, 0xba, 0x1e, 0x44, 0x0b, - 0x7f, 0xaf, 0x39, 0x1e, 0x3d, 0xdb, 0x56, 0x53, 0x9b, 0x7d, 0xad, 0xc5, 0x02, 0x19, 0x88, 0x86, 0xbe, 0x90, 0x33, - 0x0a, 0x77, 0x95, 0xe6, 0x6a, 0xb5, 0xaf, 0xca, 0x20, 0x81, 0x89, 0x20, 0x6b, 0x59, 0x78, 0x8f, 0xee, 0xd5, 0x23, - 0xcd, 0x2b, 0x09, 0x9e, 0xb9, 0xf8, 0x0b, 0x00, 0xa1, 0x3c, 0x49, 0xc8, 0x01, 0x39, 0x80, 0xbf, 0xa5, 0x28, 0x95, - 0x06, 0xf8, 0x67, 0x75, 0x39, 0xb6, 0xf5, 0xfd, 0x9d, 0x56, 0x31, 0xb8, 0xfe, 0x7c, 0xdd, 0xf5, 0xac, 0x1d, 0xe2, - 0x5c, 0xd9, 0xea, 0xb5, 0x65, 0x9a, 0xc7, 0x48, 0x5d, 0x03, 0x70, 0x27, 0xd2, 0x23, 0x10, 0xc9, 0x4c, 0x34, 0xc8, - 0xd9, 0x0b, 0x3e, 0x9e, 0x8a, 0xc7, 0xa4, 0xbd, 0xca, 0xf7, 0xcd, 0x85, 0x3e, 0x18, 0x63, 0xdf, 0x82, 0x06, 0xf1, - 0xd1, 0x6a, 0x6b, 0x05, 0x62, 0xbd, 0x55, 0xea, 0x43, 0x37, 0x46, 0x41, 0x07, 0x8f, 0xb8, 0x91, 0x0b, 0x8e, 0xed, - 0xae, 0xad, 0xa7, 0xf4, 0x15, 0x80, 0xb9, 0x0e, 0x54, 0x32, 0x0c, 0x52, 0xe7, 0x89, 0xc2, 0x24, 0x3f, 0x4f, 0x48, - 0x42, 0x44, 0x75, 0xb6, 0x1c, 0xa5, 0xdc, 0xb4, 0x80, 0xcb, 0x8c, 0x0c, 0x30, 0x9b, 0x34, 0xeb, 0x27, 0x97, 0x2f, - 0x41, 0x2a, 0x0d, 0x11, 0xdc, 0xb0, 0xbd, 0x64, 0x74, 0xeb, 0xa8, 0x1b, 0x54, 0x49, 0xe6, 0xfa, 0xcd, 0xed, 0x2c, - 0x52, 0xe6, 0xcd, 0x47, 0x18, 0x6b, 0xf2, 0x21, 0xac, 0x13, 0xfc, 0x36, 0x40, 0x25, 0x7d, 0x2a, 0xbc, 0x68, 0x04, - 0x10, 0xea, 0x3b, 0x55, 0xc6, 0xa7, 0xc2, 0xcb, 0x46, 0x5b, 0x96, 0x51, 0x0a, 0xd5, 0x05, 0xb3, 0x5b, 0xd3, 0x85, - 0xe8, 0x56, 0xd5, 0x40, 0x1b, 0xb8, 0x76, 0x1d, 0x28, 0xa0, 0xa1, 0xda, 0x95, 0x1b, 0x16, 0x80, 0xd5, 0x4c, 0x04, - 0x86, 0xcb, 0xbf, 0xcf, 0x5f, 0xa9, 0x18, 0x9e, 0x7e, 0x3f, 0xf4, 0xf6, 0xdb, 0x20, 0x1a, 0x6d, 0x2f, 0xd9, 0x2e, - 0x88, 0x46, 0xbb, 0xcb, 0x86, 0xd1, 0xef, 0xe7, 0xf4, 0xfb, 0x79, 0x03, 0x3a, 0x12, 0x61, 0xc2, 0xec, 0xf5, 0x1b, - 0xb5, 0x7c, 0xa5, 0xd6, 0xef, 0xd4, 0xf2, 0xa5, 0x1a, 0xde, 0xda, 0x93, 0x44, 0x10, 0x59, 0xaa, 0x9a, 0x07, 0x49, - 0x91, 0x6a, 0xe9, 0x72, 0x8c, 0x16, 0x23, 0x6a, 0x29, 0x6b, 0x8e, 0x75, 0x22, 0xed, 0x1c, 0x94, 0x0c, 0x70, 0xb4, - 0xb8, 0xaa, 0x31, 0xdd, 0xac, 0x68, 0x09, 0xc4, 0x08, 0x2b, 0xdb, 0x72, 0x71, 0x93, 0xfa, 0xe8, 0x9c, 0x7c, 0xdb, - 0x2a, 0xe5, 0xdb, 0x56, 0xf0, 0xfc, 0x2b, 0x0a, 0xe5, 0x92, 0x6b, 0xd7, 0xb2, 0x69, 0xa1, 0x14, 0xca, 0xb8, 0x06, - 0x5b, 0xfb, 0x26, 0x30, 0x64, 0x3e, 0x52, 0xd4, 0xd8, 0x5e, 0x34, 0xca, 0x21, 0xc8, 0xd6, 0xc1, 0xa8, 0x53, 0x16, - 0x2c, 0xbe, 0xdd, 0x21, 0x03, 0x19, 0xe8, 0xa8, 0x6a, 0xe3, 0xd5, 0xce, 0x4a, 0x7f, 0x58, 0x5e, 0x3c, 0x67, 0x89, - 0x95, 0x4e, 0x7e, 0x53, 0xa1, 0x3f, 0x08, 0xd1, 0x37, 0x65, 0xc3, 0xc1, 0x8b, 0x2e, 0xb6, 0x32, 0x20, 0xde, 0x30, - 0xbd, 0xb7, 0xb1, 0x92, 0xe5, 0xae, 0x29, 0x5f, 0xcc, 0x78, 0xc2, 0x71, 0xf4, 0xe5, 0x6a, 0x11, 0xd6, 0x6a, 0x91, - 0x9d, 0x00, 0x0f, 0xad, 0xd5, 0x52, 0xc8, 0xd5, 0x22, 0x9c, 0x99, 0x2e, 0xd4, 0x4c, 0xcf, 0x40, 0xf3, 0x28, 0xd4, - 0x2c, 0x4f, 0x00, 0x0b, 0x5e, 0x98, 0x19, 0x2e, 0xcc, 0x0c, 0xc7, 0x21, 0x35, 0x4e, 0x0f, 0x7a, 0xaf, 0x73, 0xcf, - 0x2d, 0x77, 0xa3, 0xd3, 0x30, 0x6f, 0x47, 0x1b, 0xcc, 0xf1, 0x41, 0x38, 0x81, 0xf8, 0xc0, 0x12, 0x01, 0x7a, 0x34, - 0xac, 0x8e, 0x1a, 0x2a, 0x47, 0xf1, 0x65, 0x01, 0x48, 0x96, 0x04, 0x20, 0xb9, 0x57, 0xe3, 0x5c, 0x5a, 0x7e, 0x5d, - 0x25, 0x21, 0x47, 0x64, 0xbc, 0x94, 0x76, 0xf7, 0x84, 0x97, 0x23, 0x23, 0x34, 0x4f, 0x16, 0xa9, 0x97, 0xb3, 0x8c, - 0x8d, 0x11, 0xb8, 0x28, 0xf4, 0x9b, 0xaa, 0xdf, 0x4f, 0x4b, 0x2f, 0xa7, 0x76, 0x7e, 0x02, 0x7f, 0xcb, 0x53, 0x67, - 0x91, 0x23, 0xe4, 0xd5, 0xc8, 0x24, 0x2c, 0x2f, 0x95, 0x7a, 0xfa, 0x12, 0x66, 0x50, 0x77, 0x6f, 0x14, 0x80, 0x6b, - 0x91, 0x4b, 0xa7, 0xda, 0x12, 0xae, 0x4c, 0xb9, 0xc1, 0x3e, 0x0f, 0x79, 0x4e, 0x42, 0xa8, 0x44, 0x1e, 0x29, 0xac, - 0xfb, 0xf6, 0xc5, 0xf3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x0e, 0x00, 0x73, 0x30, 0xf5, 0xa2, 0x01, 0x2f, - 0xd5, 0x9c, 0xf9, 0xe8, 0xe5, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x33, 0xf9, 0xc8, 0xf8, 0x96, 0xf9, - 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, 0x6c, 0x50, - 0x09, 0x36, 0x0d, 0x5f, 0x4b, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, 0x1b, 0xb3, - 0x31, 0x2b, 0xd4, 0xce, 0x93, 0xcb, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, 0x71, 0xce, - 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, 0xa6, 0x25, - 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, 0xe8, 0x95, - 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x73, 0xfe, 0x52, - 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd1, 0xb4, 0x04, 0x75, 0x80, - 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x39, 0xe7, 0x5f, 0x6a, 0x43, 0x84, 0x8c, - 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, 0xc0, 0xe3, - 0xbc, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x1c, 0xf7, 0x4e, 0xd3, 0xb0, 0xfd, 0x17, 0xa0, 0x29, 0x86, 0x72, 0x3c, 0xdf, - 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xca, 0x42, 0xda, 0x96, 0x63, 0xb4, - 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xdc, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x7d, 0xdd, 0x63, 0x36, 0xc9, 0x8a, - 0x45, 0xae, 0x22, 0x4e, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, 0x41, 0xc9, - 0x72, 0x5e, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xd5, 0x9c, 0x52, 0xa8, - 0x7d, 0xc5, 0xc3, 0xea, 0xf4, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, 0x7c, 0xe7, - 0xeb, 0xf4, 0x8e, 0x42, 0x77, 0x9c, 0x99, 0x78, 0xaa, 0x02, 0x63, 0xdf, 0xda, 0x11, 0x14, 0x0e, 0x4d, 0xd7, 0x01, - 0x87, 0x69, 0x74, 0xc2, 0xe2, 0x9f, 0xd2, 0x71, 0xf2, 0xa2, 0x56, 0x88, 0x24, 0xff, 0x10, 0x2e, 0x0c, 0x89, 0x05, - 0x79, 0x49, 0xa8, 0x23, 0x32, 0x62, 0x35, 0x2a, 0xd6, 0x42, 0x45, 0xc5, 0x29, 0x1e, 0x6f, 0x15, 0x14, 0x97, 0xa2, - 0x54, 0x29, 0x15, 0xb9, 0x51, 0x29, 0x20, 0x96, 0x0d, 0xbc, 0x5b, 0xc0, 0x01, 0x10, 0x74, 0x96, 0xbb, 0xb5, 0xed, - 0x6e, 0x23, 0xf3, 0x99, 0x69, 0x9e, 0x56, 0x1f, 0xd4, 0xdf, 0xef, 0x97, 0x18, 0x5b, 0xe3, 0xe9, 0xef, 0xdb, 0xb4, - 0xe0, 0xe6, 0x6f, 0x18, 0xa2, 0x3b, 0x40, 0xc4, 0x2c, 0xed, 0xa1, 0x90, 0x05, 0x13, 0x96, 0xa1, 0x2a, 0x4f, 0x39, - 0xea, 0xe5, 0x93, 0x5b, 0x80, 0x50, 0x43, 0xbf, 0x36, 0x3a, 0xd5, 0x55, 0x09, 0xc2, 0xf7, 0x5d, 0xa1, 0x1e, 0x9b, - 0x03, 0x9e, 0x0c, 0x80, 0xbf, 0x22, 0xaf, 0xf5, 0xd8, 0xfe, 0x41, 0x6f, 0xd4, 0x1b, 0x20, 0x88, 0xce, 0x79, 0xe1, - 0x1f, 0x71, 0xae, 0x53, 0x7f, 0xc6, 0x85, 0x20, 0xbe, 0xf5, 0x24, 0xbc, 0x17, 0x67, 0x69, 0x1c, 0x9c, 0xf5, 0x06, - 0xe6, 0x22, 0x50, 0x9c, 0xa5, 0xf9, 0x19, 0x88, 0xe5, 0x88, 0x89, 0x58, 0xb3, 0x3b, 0x80, 0x09, 0x2c, 0x75, 0x1c, - 0xb2, 0xea, 0xd8, 0x7e, 0xff, 0xcd, 0xc8, 0x90, 0xa5, 0x23, 0x0c, 0x8c, 0xfe, 0x5d, 0x81, 0x00, 0x05, 0xcb, 0xcc, - 0xf6, 0x60, 0xd2, 0xd5, 0x9e, 0xd5, 0xf3, 0x66, 0x93, 0x77, 0xf5, 0x8e, 0xd5, 0xb4, 0x9c, 0x9a, 0x56, 0x59, 0x4d, - 0x9b, 0xe4, 0x50, 0x33, 0xd1, 0xef, 0x6b, 0x50, 0xd4, 0x7c, 0x0e, 0x60, 0x6c, 0x98, 0xfc, 0x66, 0x56, 0xcd, 0xfb, - 0x7d, 0x4f, 0x3e, 0x82, 0x5f, 0xc8, 0x56, 0xe6, 0xd6, 0x58, 0x3e, 0x7d, 0x4d, 0x24, 0x66, 0x06, 0xe6, 0xe8, 0xee, - 0x08, 0xdf, 0xeb, 0x46, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x0d, 0x0c, 0x9e, 0x27, 0x7c, 0x70, 0x91, 0xa3, - 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x1b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, 0x78, 0x90, - 0xfd, 0xfe, 0x0a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0xd7, 0x75, 0x51, 0x56, 0xd0, 0xb1, 0xf4, 0xf3, - 0x56, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x92, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, 0x2e, 0x3e, - 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0xe7, 0x7c, 0xb4, 0x2e, 0xd6, 0x1e, 0xf8, 0xc1, 0xcc, 0xd2, 0xb9, - 0x22, 0xce, 0xc8, 0xfd, 0xd1, 0xe7, 0x22, 0xcd, 0x29, 0x0f, 0x70, 0x1f, 0x8a, 0xb9, 0xfd, 0x16, 0x48, 0x3f, 0xf4, - 0x16, 0xc8, 0x3e, 0x3a, 0xe7, 0xe4, 0x0d, 0x20, 0xd2, 0x21, 0x0c, 0x6e, 0x45, 0x82, 0x8e, 0x55, 0xc3, 0x5b, 0x0b, - 0xec, 0xb4, 0x97, 0xc6, 0xbd, 0x34, 0x3f, 0x4b, 0xfb, 0x7d, 0x83, 0x9a, 0x99, 0x22, 0x1c, 0x3c, 0xce, 0xc8, 0x45, - 0xd2, 0x82, 0x2d, 0xa5, 0xfd, 0x57, 0x03, 0x47, 0x10, 0xf2, 0xf7, 0x3f, 0x84, 0xf7, 0x04, 0x20, 0x36, 0x69, 0x03, - 0xae, 0x7a, 0x4c, 0x47, 0x63, 0x4b, 0xa2, 0x56, 0x9d, 0x0d, 0x90, 0x38, 0x55, 0x5a, 0x4f, 0xb9, 0x59, 0x53, 0x18, - 0xa4, 0xca, 0x42, 0xfd, 0xc6, 0x7a, 0x32, 0x59, 0xe5, 0x22, 0x23, 0x8e, 0xca, 0xf4, 0xa5, 0x66, 0x04, 0xd3, 0xa5, - 0x9f, 0x2f, 0x60, 0xc9, 0xc6, 0x1f, 0x71, 0xf2, 0x96, 0x80, 0x63, 0x3b, 0x6b, 0x57, 0xd5, 0x2e, 0xc7, 0xad, 0xdd, - 0x1c, 0xe0, 0x7b, 0xbd, 0xd1, 0x68, 0xa4, 0x9d, 0xe3, 0x04, 0x0c, 0x55, 0x4f, 0x2d, 0x85, 0x1e, 0xab, 0x15, 0xa0, - 0x6e, 0x47, 0x2e, 0xb3, 0x64, 0x30, 0x5f, 0x18, 0xc7, 0xaf, 0xcc, 0x47, 0x1f, 0x2f, 0x95, 0xb5, 0xeb, 0x88, 0xaf, - 0xff, 0x20, 0xab, 0xf5, 0x2d, 0xef, 0xaa, 0x26, 0xe0, 0x8b, 0x2a, 0xa0, 0xf4, 0x1b, 0xde, 0x93, 0xbd, 0x8b, 0xaf, - 0xdd, 0x60, 0x97, 0x7c, 0xcb, 0x5b, 0xd4, 0x79, 0xbe, 0x72, 0x70, 0xa3, 0x4a, 0xb7, 0xf7, 0x92, 0x05, 0xae, 0xbd, - 0xa3, 0xa6, 0xb1, 0x9e, 0xf9, 0xd1, 0xc3, 0x22, 0x64, 0x3b, 0x1f, 0x7b, 0x5f, 0x35, 0x4f, 0xcf, 0x1a, 0x7a, 0x93, - 0x1a, 0xfa, 0xd8, 0x8b, 0xb2, 0x7d, 0x6a, 0x1a, 0xd1, 0x6b, 0xd8, 0xd0, 0xc7, 0xde, 0x92, 0x93, 0x43, 0x22, 0xc0, - 0xa9, 0x31, 0x7f, 0x7c, 0x38, 0x9d, 0xe1, 0xef, 0x18, 0x50, 0x09, 0xc4, 0x7c, 0x7a, 0x4c, 0x3b, 0x0a, 0x30, 0xa3, - 0x4a, 0x6f, 0x9f, 0x1e, 0xd8, 0x8e, 0x97, 0xf5, 0xd0, 0xd2, 0xbb, 0x27, 0x47, 0xb7, 0xe3, 0x55, 0x35, 0xbe, 0x94, - 0x43, 0x9e, 0xe7, 0xb3, 0xd1, 0x68, 0x24, 0x0c, 0x24, 0x77, 0xa5, 0x37, 0xb0, 0x02, 0x69, 0x5b, 0x54, 0x1f, 0xca, - 0xa5, 0xb7, 0x53, 0x87, 0x76, 0xe5, 0x4f, 0xf2, 0xc3, 0xa1, 0x18, 0x99, 0x63, 0x1c, 0xc0, 0x4d, 0x0a, 0x25, 0x47, - 0xc9, 0x5a, 0x82, 0xe8, 0x94, 0xc6, 0x53, 0x59, 0xaf, 0xad, 0x88, 0xbc, 0x1a, 0x71, 0x1e, 0x82, 0x1f, 0x3d, 0x50, - 0x8b, 0xbf, 0xd0, 0x82, 0xd8, 0x63, 0x9f, 0x2a, 0xa5, 0x17, 0xbc, 0x2a, 0x20, 0x44, 0xec, 0xef, 0x06, 0xda, 0x41, - 0x09, 0x0e, 0x25, 0xdc, 0x07, 0x84, 0x85, 0x7e, 0xed, 0xe5, 0x33, 0x19, 0xa3, 0xdc, 0x1b, 0x54, 0x73, 0x06, 0x30, - 0x95, 0x3e, 0x03, 0xbf, 0x4b, 0x80, 0x3a, 0xc5, 0xa7, 0xe8, 0x54, 0x6f, 0x1e, 0x36, 0x5d, 0x9f, 0x96, 0x28, 0x8a, - 0xe8, 0xce, 0xcf, 0xc7, 0x80, 0xd8, 0xd9, 0xb5, 0x19, 0x69, 0xd7, 0x7e, 0x83, 0x06, 0x2b, 0x25, 0x89, 0x76, 0x4e, - 0x09, 0xbb, 0x9d, 0x8f, 0x6c, 0xe9, 0x47, 0x29, 0x10, 0x73, 0xc7, 0x89, 0x44, 0xf6, 0x60, 0x23, 0x27, 0x70, 0x8b, - 0xf6, 0x8e, 0x0e, 0x40, 0xe5, 0x46, 0x41, 0x7e, 0x35, 0x47, 0x72, 0xc7, 0x77, 0xbd, 0xef, 0x06, 0xf5, 0xe0, 0xbb, - 0xde, 0x59, 0x4a, 0x72, 0x47, 0x78, 0xa6, 0xa6, 0x84, 0x88, 0xcf, 0xbe, 0x1b, 0xe4, 0x03, 0x3c, 0x4b, 0xb4, 0x48, - 0x8b, 0x84, 0x6a, 0x75, 0x8d, 0x9b, 0xf0, 0x22, 0x91, 0xdc, 0x43, 0xbb, 0xce, 0x23, 0x62, 0x01, 0xc8, 0x58, 0x7c, - 0x36, 0x6f, 0x28, 0xd4, 0xdd, 0xc4, 0x6c, 0xd1, 0x5d, 0x16, 0xfb, 0xfd, 0x6d, 0x9e, 0xd6, 0x3d, 0x1d, 0x1f, 0x83, - 0x2f, 0x48, 0x35, 0x01, 0x1e, 0xed, 0xaf, 0xcd, 0xf1, 0xea, 0xd5, 0xe6, 0x48, 0x59, 0xa8, 0x12, 0xf5, 0x5b, 0xac, - 0x66, 0x3d, 0x84, 0xe1, 0xce, 0x32, 0x63, 0x6d, 0x2f, 0x78, 0x25, 0x67, 0x55, 0x6c, 0x97, 0xe3, 0x2b, 0x96, 0xda, - 0x4a, 0xa2, 0x72, 0xb4, 0x1e, 0x6b, 0x53, 0x8c, 0xfc, 0x4a, 0x21, 0x51, 0x16, 0x1d, 0x5b, 0x0b, 0x05, 0xc4, 0x0b, - 0xd0, 0x97, 0xec, 0x4c, 0x03, 0xac, 0x37, 0x7a, 0x15, 0x11, 0x5a, 0x3e, 0x52, 0xe1, 0x4d, 0x6e, 0xaa, 0xcc, 0xca, - 0x66, 0xd1, 0xee, 0xa7, 0x8a, 0x57, 0x08, 0x56, 0x6f, 0xd4, 0x1e, 0x05, 0xa8, 0x3d, 0xb4, 0x50, 0x06, 0x90, 0xd2, - 0x34, 0x03, 0x40, 0x06, 0x00, 0x99, 0x2a, 0xe2, 0x33, 0x01, 0x2a, 0x6d, 0x75, 0xa3, 0xc0, 0x89, 0xf4, 0x1a, 0x68, - 0x16, 0x58, 0xe9, 0x23, 0x05, 0x19, 0x2c, 0xb6, 0x08, 0xc0, 0xca, 0x91, 0x33, 0x4c, 0x63, 0xc8, 0x36, 0x9a, 0xb8, - 0x24, 0xcd, 0xef, 0xc3, 0x2c, 0x95, 0x78, 0x12, 0x3f, 0xc8, 0x1a, 0x23, 0x00, 0x90, 0xbe, 0x4f, 0x2f, 0x8a, 0x2c, - 0x26, 0x1c, 0x38, 0xeb, 0xa9, 0x83, 0xa2, 0x26, 0xe7, 0x5a, 0xd3, 0xea, 0x59, 0x6d, 0xf2, 0x90, 0x05, 0x3a, 0x7b, - 0x30, 0x26, 0xb5, 0x7c, 0xcf, 0x23, 0xfb, 0x2b, 0xc7, 0x33, 0xc2, 0x77, 0xdd, 0xc1, 0xa9, 0xff, 0x6e, 0x6a, 0x60, - 0x62, 0x4a, 0x00, 0x36, 0x06, 0x47, 0x13, 0xe2, 0x77, 0x3a, 0x26, 0x53, 0x9b, 0x14, 0x81, 0xc0, 0x43, 0xf0, 0x0a, - 0x9e, 0x1b, 0x2e, 0xb7, 0xdc, 0xd8, 0x59, 0xe4, 0x69, 0x02, 0x70, 0xe2, 0x05, 0xdf, 0x02, 0x1c, 0xa7, 0x5e, 0x15, - 0xb2, 0x67, 0xcf, 0xc5, 0x74, 0x36, 0x0f, 0x1e, 0x12, 0xda, 0xbf, 0x98, 0xf0, 0x9b, 0xee, 0x2a, 0xb9, 0x32, 0xb5, - 0xee, 0x4d, 0x74, 0x95, 0xcb, 0x9d, 0x3e, 0xad, 0x38, 0x86, 0x39, 0x83, 0x55, 0x40, 0xce, 0xd9, 0x90, 0xbf, 0x38, - 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0xfe, 0x22, 0x94, 0xd5, 0x02, 0xb8, 0x47, 0xce, 0x23, 0xf3, 0xcb, 0x57, 0xdb, - 0xa1, 0x9c, 0x53, 0x14, 0xc6, 0x72, 0x6a, 0x5a, 0x52, 0x9c, 0x0e, 0x3d, 0x05, 0x93, 0xa9, 0x2d, 0x7f, 0x6f, 0x13, - 0x97, 0xd9, 0x9b, 0x49, 0x38, 0x5f, 0x47, 0xb6, 0xad, 0x55, 0xf7, 0xd0, 0x0d, 0xc1, 0xa0, 0x8f, 0x11, 0xb4, 0x6c, - 0xae, 0xef, 0xd6, 0x83, 0x81, 0xc2, 0xf6, 0xad, 0xe9, 0xa6, 0x45, 0xa7, 0x38, 0xe0, 0xcc, 0x5a, 0xd7, 0xa8, 0x54, - 0x15, 0x87, 0x5e, 0xf2, 0x6e, 0x59, 0x95, 0x5d, 0x96, 0x5e, 0x08, 0x52, 0xa3, 0xae, 0x22, 0x44, 0x4a, 0xc5, 0x0e, - 0xef, 0xc9, 0xaf, 0x81, 0x89, 0x67, 0x56, 0x8e, 0xd2, 0x78, 0x0e, 0x30, 0x41, 0x0a, 0x7d, 0x53, 0x7e, 0x05, 0xb8, - 0xa1, 0x8b, 0x28, 0xcc, 0xde, 0xc6, 0x55, 0x50, 0x5b, 0x4d, 0xbf, 0x77, 0x70, 0x62, 0xcf, 0xeb, 0x7e, 0x3f, 0x25, - 0x1a, 0x3f, 0x0c, 0xbd, 0xc0, 0xbf, 0xc7, 0xd3, 0x7d, 0x13, 0xa4, 0xe6, 0x95, 0x07, 0x78, 0x45, 0x97, 0x5b, 0x9b, - 0x72, 0x45, 0xe3, 0x62, 0x5e, 0x23, 0x22, 0x7c, 0xea, 0x28, 0xb6, 0xdb, 0xfc, 0x38, 0xb5, 0x31, 0x18, 0x84, 0x70, - 0xdf, 0xca, 0xf8, 0x7d, 0xe2, 0xe5, 0xb3, 0x68, 0x0e, 0x8a, 0xd2, 0x4c, 0x93, 0x84, 0x14, 0xd2, 0x4b, 0x80, 0x3e, - 0x1a, 0x84, 0x5a, 0x5d, 0xf9, 0x47, 0xe2, 0xa5, 0x6a, 0x5a, 0x9b, 0xa7, 0x58, 0xa3, 0x40, 0xcc, 0xa2, 0x79, 0xc3, - 0x32, 0x3a, 0x24, 0xd5, 0xe5, 0xd2, 0x34, 0xe3, 0x0f, 0xab, 0x19, 0xaa, 0x15, 0x47, 0x4d, 0x50, 0xa3, 0x74, 0x03, - 0x17, 0xc0, 0xbf, 0xd3, 0x1d, 0x47, 0x35, 0x8a, 0x14, 0x0d, 0xf8, 0x04, 0x81, 0x61, 0xcd, 0xe6, 0x09, 0x6b, 0x4d, - 0x5d, 0x33, 0xfa, 0x7d, 0x19, 0x27, 0x64, 0x92, 0x90, 0x9c, 0x0f, 0x97, 0xeb, 0x47, 0x52, 0x5d, 0x00, 0xa9, 0x72, - 0xc5, 0x66, 0xbd, 0xde, 0x1c, 0x30, 0x7a, 0x61, 0xfd, 0xc2, 0xc6, 0x15, 0x9c, 0x5f, 0x12, 0xe6, 0xae, 0xfa, 0x11, - 0x66, 0x19, 0x54, 0x01, 0x69, 0x7e, 0x2c, 0x78, 0xf3, 0xdc, 0x05, 0xa2, 0x7e, 0x33, 0x52, 0x17, 0x94, 0x59, 0x3a, - 0xb7, 0x88, 0x40, 0xc0, 0x6b, 0x58, 0x3d, 0x81, 0x64, 0x5f, 0x3e, 0xf6, 0x69, 0x46, 0x81, 0xea, 0x08, 0x40, 0xd9, - 0xac, 0x1f, 0xc2, 0xfe, 0x01, 0xe1, 0x84, 0xfa, 0x9b, 0x37, 0x72, 0xd6, 0x90, 0x3c, 0x90, 0x6a, 0xc2, 0x63, 0x38, - 0x35, 0x16, 0xf8, 0xd2, 0xa2, 0x37, 0x15, 0xbc, 0x26, 0x38, 0xee, 0x05, 0x5a, 0xfb, 0x16, 0x70, 0x84, 0x08, 0x2e, - 0x43, 0x13, 0xa7, 0xbd, 0x5d, 0x2f, 0x40, 0x42, 0x73, 0x0b, 0xe7, 0xfa, 0xda, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, - 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, - 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, 0x2a, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, - 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, - 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xab, 0xc4, 0x33, 0xec, - 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, - 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x2a, 0xcc, 0x41, 0xde, - 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, - 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, - 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, - 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, - 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0x2f, 0xf2, 0xd1, - 0x96, 0xbe, 0x06, 0xdf, 0x3a, 0x1c, 0xf2, 0xd1, 0xce, 0xfc, 0xf4, 0xc9, 0x5a, 0x29, 0x83, 0x8d, 0x14, 0xa3, 0x10, - 0x12, 0xc5, 0x6d, 0x7b, 0x0c, 0x80, 0xff, 0xfd, 0xc3, 0x81, 0x7e, 0xef, 0xe4, 0x6f, 0xb5, 0x5b, 0x5a, 0xf5, 0xfc, - 0xd0, 0x22, 0xcc, 0x78, 0x5d, 0x1b, 0x76, 0xb6, 0xbd, 0x04, 0x94, 0xde, 0x37, 0x0d, 0x6a, 0x8a, 0xe8, 0x27, 0xac, - 0x26, 0x56, 0x71, 0x58, 0x90, 0x12, 0x87, 0x18, 0x8e, 0xd1, 0x0e, 0x3d, 0x4e, 0x17, 0x35, 0x4f, 0xee, 0x3b, 0x64, - 0xdc, 0xfa, 0x3e, 0x20, 0xb9, 0x14, 0xce, 0x3f, 0x78, 0xa1, 0xc1, 0x44, 0x2f, 0xf2, 0xaa, 0xc8, 0xc4, 0x48, 0xd0, - 0x28, 0xbf, 0x25, 0x71, 0xe6, 0x0c, 0x6b, 0x71, 0xa6, 0x10, 0xc2, 0x42, 0x42, 0xe5, 0x2e, 0x4a, 0x4a, 0x0f, 0xce, - 0x9e, 0xec, 0xcb, 0xe6, 0x77, 0xc2, 0x84, 0x18, 0x2d, 0x80, 0x06, 0x67, 0xd7, 0x2e, 0xef, 0x21, 0x2c, 0x73, 0xef, - 0xf7, 0xb7, 0x77, 0x79, 0x01, 0x71, 0x99, 0x67, 0x52, 0xb1, 0x5a, 0x9e, 0x01, 0x4d, 0x9e, 0x88, 0xcf, 0xc2, 0x4a, - 0x4e, 0x83, 0xaa, 0xa3, 0x58, 0xbd, 0x8d, 0xe7, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, 0xdd, 0x67, 0x6f, 0x94, - 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, 0xe7, 0x26, 0xc8, 0x3f, - 0xbe, 0x3e, 0xa1, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, 0x9b, 0x23, 0x35, 0x79, - 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, 0x67, 0x2b, 0x73, 0x2f, - 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xba, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, 0x62, 0x86, 0x29, 0xd6, - 0x5f, 0xd8, 0xf0, 0x9b, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x63, 0x16, 0xc2, 0xe1, 0xb0, 0x99, 0x14, - 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0x87, 0x43, 0x57, 0xcb, 0xd6, 0xc2, 0x83, 0x87, 0xaa, 0x85, 0x9b, 0x86, 0xe5, - 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, 0x1b, 0x6b, 0xe0, 0x1a, - 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, 0x09, 0xa3, 0x15, 0xc2, - 0xef, 0xbe, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, 0x4a, 0xb1, 0x34, 0x6f, - 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0x73, 0xdf, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, 0xcd, 0xe6, 0xc0, 0x7d, - 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x27, 0xcb, 0xe3, 0xf0, 0x2d, 0xfc, 0xcb, - 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xab, 0x14, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, 0x8d, 0xa8, 0x0d, 0x7f, - 0xc3, 0xbf, 0x85, 0x7d, 0x84, 0xfd, 0x86, 0x26, 0x08, 0x03, 0x58, 0x7f, 0x26, 0x10, 0x17, 0x16, 0x82, 0x04, 0x7f, - 0xab, 0x24, 0xff, 0x9c, 0xf0, 0xd9, 0xa2, 0x04, 0xb2, 0x3a, 0x8c, 0xe2, 0x13, 0x8a, 0x89, 0x42, 0x18, 0x6e, 0x09, - 0xbd, 0xa3, 0xff, 0x46, 0x94, 0x64, 0x93, 0xdc, 0x8a, 0xf5, 0x40, 0x26, 0x49, 0x30, 0xc1, 0xca, 0x0b, 0xe5, 0x4b, - 0xf7, 0x42, 0xa9, 0xb5, 0x16, 0xb4, 0x7e, 0xf9, 0x93, 0xc4, 0x33, 0xa0, 0x7b, 0x20, 0x63, 0xd0, 0x6d, 0x44, 0x35, - 0xc9, 0x31, 0x7d, 0x94, 0xce, 0x33, 0x50, 0x01, 0x9d, 0xad, 0xb3, 0xb0, 0x5e, 0x16, 0xe5, 0xaa, 0x15, 0x1e, 0x2a, - 0x4b, 0x1f, 0xa9, 0xc7, 0x98, 0x17, 0xe6, 0xc9, 0x89, 0x7c, 0xf0, 0x08, 0xd0, 0xf0, 0x28, 0x4f, 0xab, 0x8e, 0xd2, - 0xfa, 0x81, 0x65, 0xc0, 0x08, 0x9c, 0x28, 0x03, 0x1e, 0x61, 0x19, 0x98, 0xa7, 0x5d, 0x86, 0x1a, 0xc4, 0x1a, 0x55, - 0x57, 0x6a, 0x83, 0x39, 0x51, 0x94, 0x7c, 0x8a, 0xa5, 0x15, 0xc6, 0xd0, 0xd4, 0x95, 0x47, 0xd6, 0x4b, 0x4e, 0xd8, - 0x93, 0xdd, 0x40, 0xba, 0x85, 0x8d, 0x02, 0x17, 0x74, 0x2d, 0x4b, 0x94, 0x8b, 0x6e, 0x19, 0x51, 0x26, 0x42, 0xea, - 0x67, 0x0f, 0x67, 0x5a, 0xed, 0x37, 0x76, 0xd2, 0xbe, 0x3d, 0x52, 0xf4, 0x82, 0x81, 0xf8, 0xb4, 0x47, 0x4a, 0x3d, - 0x6b, 0xe4, 0x32, 0xb0, 0xa5, 0x4b, 0x55, 0xcf, 0x7f, 0x83, 0xf2, 0x1d, 0xcc, 0x8c, 0xb3, 0xd9, 0xef, 0x7a, 0x73, - 0x7b, 0xb2, 0xaf, 0x9b, 0xdf, 0x59, 0xaf, 0x07, 0x5b, 0x83, 0x4c, 0x7c, 0xa9, 0xa8, 0xa7, 0xac, 0x42, 0xac, 0xc8, - 0xec, 0x7f, 0x0b, 0xef, 0x77, 0x78, 0x6b, 0x84, 0x66, 0x65, 0x3c, 0xcc, 0x47, 0x4f, 0xf6, 0xa2, 0xf9, 0xbd, 0xb3, - 0x6c, 0x2b, 0x57, 0x25, 0xb3, 0xfd, 0x7e, 0x94, 0x34, 0x67, 0x8f, 0xd7, 0x48, 0xea, 0x00, 0x1f, 0xaf, 0xcf, 0xf0, - 0x91, 0x4a, 0x28, 0xb5, 0xa0, 0xaa, 0x41, 0xeb, 0x63, 0xbf, 0xb7, 0x9e, 0xd3, 0xc7, 0x8f, 0xe5, 0x74, 0x4b, 0x8a, - 0x30, 0x7e, 0x60, 0x30, 0x65, 0x27, 0x4e, 0x5d, 0xf2, 0x66, 0x48, 0xef, 0xba, 0x55, 0x52, 0x97, 0x3d, 0x4a, 0x04, - 0xa1, 0x0e, 0xd6, 0x2f, 0xf6, 0x43, 0x98, 0xd9, 0xa2, 0x3f, 0x6c, 0x56, 0x73, 0x42, 0x41, 0x04, 0x88, 0x56, 0x79, - 0x1f, 0x38, 0x26, 0x09, 0xb3, 0xe6, 0x86, 0x74, 0xeb, 0xcd, 0x95, 0xf6, 0x4a, 0x0a, 0xe8, 0xe7, 0x20, 0x73, 0xfb, - 0xe8, 0x96, 0xab, 0x96, 0x79, 0x2e, 0x6d, 0x39, 0x60, 0xd1, 0x42, 0x74, 0x66, 0xe7, 0xd2, 0xe1, 0xe0, 0x3f, 0xa8, - 0x2b, 0x51, 0x45, 0x04, 0x1d, 0x45, 0x0b, 0x46, 0xab, 0x55, 0xbb, 0x9c, 0x6c, 0x2a, 0x64, 0x4b, 0x22, 0x9c, 0x28, - 0xd9, 0x2b, 0xa1, 0x3e, 0xca, 0xd5, 0x9e, 0x69, 0x88, 0x3f, 0x13, 0xb0, 0x69, 0x83, 0xbf, 0x05, 0xee, 0x65, 0x70, - 0x66, 0xda, 0xa7, 0x61, 0x04, 0x44, 0xe6, 0x10, 0xec, 0xe7, 0x77, 0x3d, 0xa8, 0xe0, 0x41, 0x47, 0xfa, 0xeb, 0x7a, - 0x56, 0xe0, 0x99, 0x7b, 0xe2, 0xf9, 0x9b, 0x13, 0xe9, 0x45, 0x0e, 0x0f, 0x34, 0xf7, 0x61, 0xc6, 0x5f, 0x96, 0x65, - 0xb8, 0x1b, 0x2d, 0xcb, 0x62, 0xe5, 0x45, 0x7a, 0x1f, 0xcf, 0xa4, 0x18, 0x48, 0x74, 0x98, 0x19, 0x5d, 0xc5, 0x3a, - 0xce, 0x61, 0xdc, 0xdb, 0x93, 0xb0, 0x42, 0xfb, 0x67, 0x89, 0xbd, 0x2e, 0x00, 0xc0, 0x21, 0x6b, 0xd0, 0x0a, 0xef, - 0x74, 0x7b, 0xbb, 0xc7, 0x25, 0x25, 0x8a, 0x1b, 0x35, 0x3f, 0xab, 0xa1, 0x65, 0x82, 0x5a, 0x66, 0xdd, 0xc9, 0x64, - 0x8a, 0x24, 0xf0, 0x6d, 0xd8, 0x1b, 0x56, 0xe4, 0xf3, 0x46, 0x6e, 0x0f, 0xef, 0xc2, 0x95, 0x88, 0xb5, 0x05, 0x9d, - 0x74, 0x64, 0x1c, 0xee, 0x85, 0xe6, 0x46, 0xba, 0x7f, 0x52, 0x25, 0x61, 0x29, 0x62, 0xb8, 0x05, 0xb2, 0xbd, 0xda, - 0x56, 0x82, 0x12, 0x48, 0x60, 0x3f, 0x94, 0x62, 0x99, 0x6e, 0x05, 0x80, 0x39, 0xf0, 0x3f, 0x25, 0x0c, 0xa1, 0xbb, - 0xf3, 0x10, 0xaf, 0x1a, 0x79, 0xdf, 0x20, 0x04, 0xfb, 0x6b, 0x90, 0xd3, 0x80, 0x41, 0xa4, 0x18, 0xc9, 0x82, 0x81, - 0x04, 0x20, 0xe7, 0x6b, 0x30, 0xc9, 0x4d, 0x73, 0xcf, 0x0f, 0x72, 0xdd, 0xc1, 0xb4, 0x0f, 0xba, 0x17, 0xd7, 0x9a, - 0xe5, 0xe0, 0x15, 0x13, 0xf1, 0xbf, 0xd7, 0x5e, 0xc9, 0x72, 0x96, 0xf9, 0x8d, 0xb9, 0xe8, 0x64, 0x70, 0xd5, 0x10, - 0x7e, 0x31, 0xcb, 0xe6, 0x3c, 0x9a, 0x65, 0x3a, 0xd4, 0xbf, 0x68, 0x8e, 0x4a, 0x01, 0x0c, 0x75, 0xbc, 0x00, 0x6b, - 0xbc, 0x2b, 0xdd, 0xb4, 0xe2, 0x91, 0xc6, 0x18, 0x05, 0x15, 0x3a, 0x08, 0xfd, 0xbd, 0x06, 0x78, 0x0d, 0x26, 0xb9, - 0x11, 0x2a, 0x1f, 0x5c, 0xd0, 0x0d, 0xdd, 0x72, 0xe5, 0x12, 0xd4, 0xa4, 0x6a, 0xf9, 0xe5, 0x08, 0xf5, 0xae, 0x96, - 0x5c, 0xaa, 0xcd, 0xa7, 0x46, 0x59, 0x23, 0xc8, 0xe4, 0x28, 0xfd, 0x3e, 0xe5, 0xc2, 0xad, 0x8c, 0xc9, 0xfa, 0x70, - 0xf0, 0x0a, 0x6e, 0x6a, 0xfc, 0x3a, 0x27, 0x16, 0x51, 0x7b, 0x48, 0x84, 0xad, 0xdd, 0x0a, 0xdd, 0x7b, 0xdc, 0x28, - 0xcd, 0xa3, 0x6c, 0x13, 0x8b, 0xca, 0xeb, 0x25, 0x60, 0x2d, 0xee, 0x01, 0x19, 0x2a, 0x2d, 0xfd, 0x8a, 0x15, 0x00, - 0x19, 0x20, 0x85, 0x8d, 0x1f, 0x90, 0xf6, 0xea, 0x83, 0x97, 0xfa, 0xfd, 0xbe, 0x31, 0xe5, 0xbf, 0x7f, 0xc8, 0x81, - 0x99, 0x50, 0x94, 0xf5, 0x0e, 0x26, 0x10, 0x5c, 0x3b, 0x49, 0x7b, 0x56, 0xf3, 0x17, 0xeb, 0xda, 0x03, 0x52, 0x2b, - 0xdf, 0x62, 0xae, 0x7a, 0x6d, 0x5f, 0x6c, 0xf6, 0x69, 0x75, 0x63, 0x34, 0x0e, 0x82, 0xa5, 0xd5, 0x5b, 0xad, 0x72, - 0xc8, 0x1b, 0x5e, 0x81, 0x48, 0x65, 0x5d, 0x5d, 0x2b, 0xe7, 0xea, 0x5a, 0x70, 0x24, 0x90, 0x2d, 0x79, 0x0e, 0xff, - 0x85, 0xdc, 0x2b, 0x0f, 0x87, 0xc2, 0xef, 0xf7, 0xd3, 0x19, 0x69, 0x65, 0x81, 0x32, 0x6d, 0x5d, 0x7b, 0xa1, 0x7f, - 0x38, 0xfc, 0x00, 0x5e, 0x23, 0xfe, 0xe1, 0x50, 0xf6, 0xfb, 0x1f, 0xcd, 0x4d, 0xe6, 0x7c, 0xac, 0x94, 0xb2, 0x97, - 0xa8, 0x74, 0x7f, 0x9b, 0xf0, 0xde, 0xff, 0x1e, 0xfd, 0xef, 0xd1, 0x65, 0x4f, 0x05, 0x80, 0x25, 0x7c, 0x86, 0x37, - 0x74, 0xa6, 0x2e, 0xe7, 0x4c, 0xba, 0xbb, 0x2b, 0x3f, 0xf4, 0x9e, 0xc6, 0x87, 0xef, 0xcd, 0x4d, 0x1b, 0x7f, 0xad, - 0x8e, 0x34, 0x09, 0x1d, 0x17, 0xfd, 0xc3, 0xe1, 0x53, 0xa2, 0xf5, 0x69, 0xa9, 0xd2, 0xa7, 0x29, 0xf0, 0x24, 0xc3, - 0x86, 0xeb, 0x16, 0xa6, 0xa3, 0xf9, 0x71, 0xf3, 0x55, 0xf2, 0xe2, 0x2c, 0x85, 0x6b, 0x6f, 0x3e, 0x4b, 0xe7, 0x53, - 0xb0, 0xae, 0x0c, 0xf3, 0x59, 0x3d, 0x0f, 0x20, 0x75, 0x08, 0x69, 0xd6, 0x34, 0xfc, 0x5b, 0xe5, 0x0a, 0xde, 0xda, - 0xe3, 0xdd, 0x60, 0x44, 0xa9, 0x23, 0x7d, 0xd2, 0x86, 0xd0, 0x25, 0x95, 0xfc, 0x47, 0x91, 0xc7, 0x18, 0xb3, 0xf1, - 0x9a, 0xc8, 0x3e, 0x8b, 0xfc, 0x55, 0x01, 0x80, 0x45, 0x80, 0x80, 0x9c, 0xce, 0x1d, 0x49, 0xfc, 0xe7, 0xe4, 0xdb, - 0x3f, 0xa6, 0x4b, 0xfb, 0x50, 0x16, 0x77, 0xa5, 0xa8, 0xaa, 0xa3, 0xd2, 0x76, 0xb6, 0x5c, 0x0f, 0xf4, 0xa1, 0xfd, - 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, 0x58, 0x3f, 0xbf, - 0xdf, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, 0xc3, 0x54, 0xe2, - 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0x7f, 0x54, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, - 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0x17, 0xc2, 0x22, 0xf9, 0xf5, 0xc9, 0x91, - 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x91, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9e, 0xff, 0xb9, 0x99, 0xff, 0x03, 0x74, 0x86, - 0x2c, 0x5e, 0x70, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0x2f, 0x80, 0x83, 0xf9, 0x05, - 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0x37, 0x16, 0xcf, 0x95, 0x5c, 0x10, 0xfa, - 0xba, 0x0a, 0xb3, 0x71, 0x55, 0x6c, 0x2a, 0x51, 0x6c, 0xea, 0x1e, 0xa9, 0x65, 0xf3, 0x69, 0x6d, 0x2b, 0x64, 0x7f, - 0x12, 0x2d, 0xda, 0x2e, 0x43, 0x35, 0x19, 0x65, 0xe9, 0x7a, 0x0a, 0xa4, 0x7a, 0x01, 0x9c, 0x45, 0xe6, 0x95, 0x2f, - 0xce, 0x1e, 0xb0, 0x45, 0xe3, 0x29, 0x30, 0xa2, 0xd2, 0x1f, 0x79, 0x63, 0x74, 0x7a, 0xa2, 0xdf, 0xcf, 0xa7, 0x14, - 0xf2, 0xf5, 0x13, 0x60, 0x72, 0xd5, 0x72, 0x01, 0xfa, 0x32, 0xd4, 0x41, 0x25, 0x4a, 0xad, 0x18, 0x46, 0x2c, 0xfc, - 0x24, 0x90, 0xbd, 0x99, 0x82, 0x9a, 0x55, 0x94, 0x84, 0x4a, 0x54, 0x4a, 0xb6, 0x26, 0xa8, 0xa5, 0xf7, 0x45, 0x51, - 0xef, 0x2b, 0x70, 0x94, 0x8c, 0xb4, 0x59, 0x4e, 0x99, 0x71, 0x51, 0xe6, 0xa2, 0x1f, 0xec, 0xdf, 0x95, 0xe7, 0x37, - 0x32, 0x9f, 0xe5, 0xbe, 0xa3, 0x73, 0xda, 0x8e, 0x0b, 0x94, 0xb9, 0xe5, 0xb4, 0xd5, 0x92, 0xc7, 0xe4, 0x3d, 0x0b, - 0xb6, 0xfd, 0x97, 0x09, 0xf2, 0x2a, 0xc2, 0x7c, 0x42, 0x95, 0xcd, 0x3f, 0x20, 0xcc, 0x16, 0x07, 0xf6, 0xd8, 0x85, - 0x89, 0x48, 0x6f, 0xc1, 0x92, 0x18, 0x66, 0xa5, 0x08, 0xe3, 0x1d, 0x78, 0xff, 0x6c, 0x2a, 0x31, 0x3a, 0x43, 0x27, - 0xf7, 0xb3, 0x87, 0xb4, 0x4e, 0xce, 0xde, 0xbe, 0x3e, 0xfb, 0xae, 0x37, 0x28, 0x46, 0x69, 0x3c, 0xe8, 0x7d, 0x77, - 0xb6, 0xda, 0x00, 0x44, 0xa6, 0x38, 0x8b, 0xc9, 0x94, 0x26, 0xe2, 0x33, 0x32, 0x0c, 0x9e, 0xd5, 0x89, 0x38, 0xa3, - 0x89, 0xe9, 0xbe, 0x46, 0x69, 0xf2, 0xed, 0x28, 0xcc, 0xe1, 0xe5, 0x52, 0x6c, 0x2a, 0x11, 0x83, 0x9d, 0x52, 0xcd, - 0xb3, 0xbc, 0x7d, 0x16, 0xe7, 0xa3, 0x0e, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, 0x05, 0x84, 0x1e, - 0x00, 0x27, 0x5d, 0xf9, 0xf3, 0x70, 0x10, 0x09, 0x84, 0x5a, 0x30, 0x27, 0xd3, 0x88, 0x6e, 0x48, 0xaf, 0xb0, 0xcf, - 0xc0, 0x2c, 0xa4, 0x34, 0x0f, 0x6e, 0xae, 0x16, 0x2d, 0x77, 0xc5, 0xca, 0x51, 0x58, 0xad, 0x45, 0x54, 0x23, 0xd5, - 0x31, 0x38, 0xef, 0x40, 0x04, 0x80, 0x62, 0x04, 0xcf, 0x78, 0xd4, 0xef, 0x47, 0x2a, 0x28, 0x27, 0xa1, 0x5f, 0x14, - 0xfa, 0xa5, 0x31, 0x28, 0x63, 0xfe, 0x2e, 0xd4, 0xc4, 0x00, 0xf5, 0x96, 0x87, 0x8a, 0x23, 0x00, 0x97, 0x73, 0xc4, - 0x8c, 0xf3, 0x1e, 0x77, 0xd1, 0x38, 0x15, 0xef, 0x84, 0xba, 0x0e, 0x96, 0x0a, 0x75, 0xde, 0xd4, 0x47, 0x7a, 0x4e, - 0x9a, 0x04, 0x0d, 0xe2, 0x06, 0x1e, 0xaf, 0x86, 0x80, 0x6a, 0x25, 0xa4, 0xde, 0x42, 0xa7, 0x54, 0x75, 0x08, 0xac, - 0x01, 0x2e, 0x51, 0xd8, 0x56, 0x98, 0x1c, 0xd1, 0xa6, 0x2c, 0x45, 0x7e, 0xc4, 0x06, 0xed, 0x92, 0x91, 0xa9, 0x83, - 0xcb, 0xe5, 0x72, 0x22, 0xea, 0x5f, 0xf3, 0x2d, 0x80, 0xf3, 0x42, 0x7e, 0x6b, 0x37, 0x5b, 0x26, 0xd9, 0xae, 0x2b, - 0xc3, 0x59, 0x52, 0x8a, 0x6a, 0x5d, 0xe4, 0x55, 0x7a, 0x2f, 0x7e, 0xd6, 0x0f, 0x5d, 0x02, 0x29, 0xf4, 0x23, 0xbd, - 0x6e, 0x37, 0x47, 0xaa, 0x71, 0x74, 0x39, 0xb6, 0xa7, 0xd2, 0x4e, 0xf6, 0xaa, 0xc5, 0x9b, 0x2d, 0x73, 0x25, 0x69, - 0x1c, 0x8b, 0xfc, 0x6d, 0x1e, 0xa7, 0x91, 0x95, 0x1c, 0xfe, 0x1f, 0xde, 0xbe, 0x85, 0xbb, 0x6d, 0x1b, 0x5b, 0xf7, - 0xaf, 0x58, 0xbc, 0xa9, 0x4a, 0x44, 0x90, 0x2c, 0x39, 0x49, 0x67, 0x4a, 0x19, 0xd6, 0x71, 0xf3, 0x68, 0xd3, 0x36, - 0x71, 0x1a, 0xa7, 0x9d, 0xce, 0xe8, 0xea, 0xb8, 0x34, 0x09, 0x5b, 0x6c, 0x68, 0x40, 0x25, 0x29, 0x3f, 0x22, 0xf1, - 0xbf, 0xdf, 0xb5, 0x37, 0x9e, 0xa4, 0x68, 0x27, 0x33, 0xf7, 0xdc, 0xbb, 0xb2, 0x56, 0x2c, 0x82, 0x20, 0xde, 0xd8, - 0xd8, 0xd8, 0x8f, 0x6f, 0xeb, 0x00, 0xd5, 0x2e, 0xf2, 0x95, 0x8b, 0x8d, 0xfc, 0x22, 0x2b, 0x31, 0x60, 0x70, 0xa3, - 0x51, 0xad, 0x50, 0x53, 0x26, 0xf0, 0x85, 0x7c, 0x8f, 0x11, 0xb7, 0x59, 0x99, 0x00, 0xc3, 0x8f, 0x89, 0xfa, 0x92, - 0x9e, 0x42, 0x94, 0x07, 0x15, 0x8f, 0xfb, 0x05, 0x47, 0xc4, 0x6b, 0xab, 0x32, 0x07, 0x26, 0x5b, 0xab, 0x20, 0x11, - 0xec, 0x2e, 0x9b, 0xeb, 0x45, 0xb4, 0x50, 0x77, 0xa1, 0x5e, 0xbc, 0xdd, 0xf6, 0x12, 0x45, 0x07, 0x9c, 0xfc, 0x34, - 0x78, 0x15, 0x67, 0x39, 0x4f, 0xf7, 0x2a, 0xb9, 0xa7, 0x36, 0xd4, 0x9e, 0x72, 0xe6, 0x80, 0x9d, 0xf7, 0x75, 0xb5, - 0xa7, 0xd7, 0xf4, 0x9e, 0x6e, 0xe7, 0x1e, 0x5c, 0x30, 0x70, 0xe7, 0x5e, 0x66, 0xd7, 0x5c, 0xec, 0x81, 0x32, 0xd0, - 0x1a, 0x0f, 0xd4, 0xa2, 0x1a, 0xa9, 0x89, 0xd1, 0x81, 0xab, 0x13, 0x7d, 0x30, 0x07, 0xf4, 0x7b, 0x88, 0x15, 0xde, - 0x7a, 0xbb, 0xd2, 0x07, 0x6d, 0x40, 0x7f, 0x5e, 0x9a, 0x3e, 0xe8, 0x68, 0xf1, 0x2a, 0x24, 0x70, 0x63, 0x48, 0x35, - 0x52, 0xab, 0x91, 0x55, 0xa0, 0x78, 0xc3, 0x5b, 0xbc, 0x3b, 0xd7, 0x92, 0x8d, 0xf7, 0x12, 0x81, 0xbd, 0x32, 0x51, - 0xc5, 0x99, 0x38, 0xf6, 0x52, 0x79, 0xad, 0x9d, 0x64, 0x84, 0xf1, 0x2d, 0x2b, 0xa9, 0xbf, 0x43, 0xcc, 0x2d, 0xd2, - 0x1c, 0x06, 0x2f, 0xc3, 0x8a, 0xcc, 0x78, 0xbf, 0x2f, 0x67, 0x32, 0x2a, 0x67, 0x62, 0xbf, 0x8c, 0x14, 0x42, 0xdb, - 0x7d, 0x22, 0xa0, 0x07, 0x25, 0x40, 0xbe, 0x00, 0xa8, 0x7a, 0x48, 0xf8, 0xf3, 0x90, 0xd4, 0xa7, 0x53, 0xe8, 0x53, - 0x68, 0xeb, 0x15, 0xaf, 0xa0, 0xaa, 0x6e, 0x8c, 0x6c, 0xa3, 0x82, 0x16, 0x8f, 0xe5, 0x59, 0x6d, 0x18, 0x9b, 0x53, - 0xeb, 0x5d, 0x6f, 0x36, 0x98, 0xb2, 0xb9, 0x50, 0xab, 0x30, 0x24, 0xd1, 0x4d, 0xe9, 0x85, 0x0f, 0xb1, 0x58, 0x59, - 0xad, 0xcd, 0x6f, 0x62, 0x7f, 0x64, 0x22, 0xc5, 0xfd, 0x6c, 0x89, 0x73, 0x17, 0x8f, 0xe7, 0x55, 0x5f, 0x6b, 0x69, - 0x91, 0x69, 0xf3, 0x9d, 0xbe, 0x0c, 0x69, 0x2a, 0x6a, 0x48, 0xa3, 0xce, 0x0c, 0xba, 0x6f, 0x97, 0x57, 0x54, 0x23, - 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, 0x1e, 0x88, 0xa2, 0x1a, 0x15, 0x6b, 0x21, 0x10, 0x6d, 0x18, 0x72, 0xcc, - 0x2c, 0x21, 0xc9, 0x3e, 0xf1, 0xef, 0x54, 0x70, 0x85, 0x22, 0xbe, 0x31, 0x70, 0xde, 0x95, 0xf5, 0xec, 0xae, 0x23, - 0x3f, 0x27, 0x16, 0x56, 0xfb, 0x0f, 0xcd, 0xa3, 0xd6, 0x38, 0x0b, 0x68, 0x6b, 0x5a, 0xdd, 0x70, 0xb8, 0x47, 0x75, - 0x2c, 0x4a, 0x03, 0x48, 0xec, 0x91, 0xe5, 0xa2, 0x75, 0xcc, 0xa0, 0x01, 0xfd, 0x6d, 0x76, 0xb5, 0xbe, 0x42, 0xd4, - 0xb6, 0x12, 0x59, 0x27, 0xa9, 0xfc, 0x4b, 0xda, 0xa3, 0xae, 0xed, 0xa9, 0xfc, 0x6f, 0xdb, 0x54, 0x39, 0xb4, 0x40, - 0xf2, 0xd8, 0xcd, 0x59, 0xa0, 0x3a, 0x12, 0x44, 0x81, 0xda, 0x7a, 0xc1, 0xd4, 0x3b, 0x65, 0x8a, 0x0e, 0xe4, 0xe7, - 0xc2, 0x9c, 0x61, 0x5f, 0x70, 0xc4, 0x98, 0xa5, 0x12, 0x83, 0xa9, 0x8f, 0x31, 0xaa, 0x69, 0xad, 0x00, 0x5d, 0x3f, - 0xdd, 0xc0, 0x9f, 0xa8, 0xa8, 0xd1, 0x50, 0x6b, 0x24, 0x85, 0xa2, 0x89, 0x0a, 0x3a, 0x96, 0x16, 0x3a, 0x98, 0x42, - 0x27, 0x91, 0xb0, 0x04, 0x34, 0x4c, 0x88, 0x4e, 0x2a, 0xf0, 0xd6, 0x00, 0xce, 0x7c, 0x5c, 0x94, 0xeb, 0x42, 0x1b, - 0xcc, 0xfd, 0x10, 0x5f, 0xf3, 0xd7, 0x2f, 0x9c, 0x51, 0x7d, 0xcb, 0x5a, 0xdf, 0xd3, 0x82, 0xfc, 0x10, 0x72, 0x8a, - 0x0e, 0x4c, 0xec, 0x68, 0x83, 0xc6, 0x18, 0x65, 0xad, 0x43, 0x5d, 0x9c, 0xe8, 0xf8, 0x2b, 0xda, 0x04, 0xef, 0x01, - 0x4f, 0x11, 0x6d, 0x78, 0x28, 0x8c, 0x55, 0x35, 0x3e, 0x95, 0xac, 0xa5, 0x07, 0x2b, 0x78, 0xba, 0x4e, 0x78, 0x08, - 0x7a, 0x24, 0xc2, 0x8e, 0xc2, 0x62, 0x1e, 0x2f, 0xe0, 0x38, 0x29, 0x08, 0xa8, 0x1d, 0xf4, 0x15, 0x7c, 0xbe, 0x40, - 0xf7, 0x57, 0x89, 0x1e, 0x60, 0x68, 0x41, 0xdc, 0x0c, 0x7d, 0x3a, 0xba, 0x8a, 0x57, 0x0d, 0x15, 0x09, 0x9f, 0x17, - 0x60, 0x3b, 0xa4, 0xd4, 0x53, 0xa0, 0x85, 0x4a, 0x94, 0x7e, 0x18, 0xf8, 0x0e, 0x0d, 0x7c, 0xad, 0x75, 0x80, 0x86, - 0x7e, 0xc6, 0x34, 0xb5, 0xce, 0x50, 0xf9, 0xcc, 0xbb, 0x67, 0x46, 0xcb, 0x99, 0x05, 0x63, 0xd0, 0xb7, 0xd1, 0x14, - 0xc5, 0x39, 0xf9, 0x2c, 0x28, 0xe2, 0x34, 0x8b, 0x73, 0xf0, 0xdb, 0x8c, 0x0b, 0xcc, 0x98, 0xc4, 0x15, 0xbf, 0x94, - 0x05, 0x68, 0xbb, 0x73, 0x95, 0x5a, 0xd7, 0x20, 0x20, 0xfb, 0x01, 0xac, 0x5e, 0x1a, 0x3a, 0x2a, 0xe7, 0xdd, 0xa5, - 0x4d, 0x21, 0x62, 0x11, 0x82, 0x4d, 0x33, 0x5d, 0xb2, 0xe3, 0x50, 0x69, 0x73, 0x20, 0xbe, 0x11, 0x1a, 0xf7, 0x4f, - 0xc3, 0xd8, 0x6a, 0x8a, 0xad, 0xdd, 0xdb, 0x76, 0xfb, 0x7b, 0xe9, 0xa5, 0xd3, 0x9c, 0xf4, 0x18, 0xfb, 0xbd, 0x0c, - 0x8b, 0x91, 0xed, 0x08, 0x81, 0x25, 0xe7, 0x7d, 0xea, 0xbf, 0xa2, 0xe5, 0x3c, 0x01, 0xd3, 0x11, 0x1d, 0x21, 0x17, - 0x28, 0x3b, 0x46, 0x71, 0x07, 0x06, 0x57, 0xf4, 0xfb, 0x60, 0x95, 0x61, 0x2e, 0x24, 0x4b, 0x92, 0x32, 0x78, 0x9e, - 0x7a, 0x18, 0xf0, 0x6b, 0xa6, 0xcc, 0x5d, 0x94, 0xf5, 0xe9, 0x92, 0x4c, 0x53, 0x64, 0x20, 0xd6, 0xe1, 0x26, 0x4b, - 0xa3, 0x44, 0x89, 0xc8, 0x96, 0xe8, 0x1f, 0x69, 0x28, 0x96, 0x0e, 0xd7, 0x8b, 0x54, 0x89, 0x50, 0x31, 0x4f, 0xf1, - 0xa4, 0x4e, 0xeb, 0x74, 0x84, 0xf1, 0x26, 0x41, 0x29, 0x57, 0xc3, 0x40, 0x95, 0x54, 0x2f, 0x85, 0x4d, 0xb1, 0xdd, - 0xea, 0x8b, 0x95, 0x98, 0xc7, 0x0b, 0x7c, 0x29, 0x70, 0x14, 0x7f, 0xe2, 0x5e, 0xac, 0x29, 0xb5, 0x3d, 0xa8, 0x1d, - 0x51, 0x42, 0x7f, 0xe2, 0x70, 0x91, 0xf8, 0x4e, 0xea, 0xb8, 0x7f, 0x68, 0x11, 0x72, 0xa6, 0x0e, 0x52, 0xc3, 0x0d, - 0xed, 0x08, 0xff, 0x0d, 0xd7, 0x67, 0x9c, 0xd1, 0x9b, 0x6a, 0x46, 0x8d, 0xdf, 0xeb, 0xe1, 0x19, 0xa3, 0x3e, 0x1b, - 0x38, 0xac, 0x10, 0x85, 0x36, 0xec, 0xa8, 0x54, 0xa2, 0x85, 0xa1, 0x54, 0x7f, 0x09, 0x15, 0x47, 0xdc, 0x99, 0x51, - 0x96, 0x8c, 0x4f, 0xcb, 0x43, 0x31, 0x1d, 0x0c, 0x4a, 0x52, 0x19, 0x0b, 0x3d, 0xb8, 0x1e, 0x78, 0xfe, 0x3d, 0x70, - 0x0b, 0xf1, 0xe0, 0x90, 0xc5, 0x90, 0x1b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8d, 0x4a, 0x15, 0xbc, 0x9a, 0xa8, 0x16, - 0xfc, 0x54, 0x86, 0x01, 0xfa, 0x24, 0x05, 0x60, 0x32, 0x98, 0xf2, 0x5b, 0x90, 0x28, 0x9d, 0xa9, 0x1b, 0xd2, 0xaf, - 0xa2, 0xe0, 0x17, 0xbc, 0xe0, 0x22, 0x71, 0x05, 0x58, 0xde, 0xc1, 0xf6, 0x3a, 0xaa, 0xa8, 0x02, 0xe2, 0x35, 0x3d, - 0x8e, 0xb8, 0xf1, 0xfe, 0x33, 0x3d, 0xb6, 0x40, 0xad, 0xd6, 0xb1, 0xc1, 0x67, 0x8e, 0xc1, 0x05, 0x5d, 0x4b, 0x6c, - 0x0d, 0xd5, 0xb0, 0x22, 0x30, 0x70, 0x01, 0x07, 0x61, 0x89, 0xe2, 0xd8, 0x4a, 0x5e, 0x91, 0x86, 0x94, 0xf6, 0x81, - 0xe1, 0x68, 0x93, 0x1c, 0xdf, 0x66, 0xd9, 0x4d, 0xe0, 0x7c, 0xd1, 0x39, 0x69, 0x26, 0x96, 0x0d, 0xde, 0xe7, 0xcd, - 0xf9, 0x75, 0xff, 0x90, 0x50, 0x15, 0xec, 0x86, 0xb7, 0x83, 0xdd, 0x38, 0xe1, 0xd7, 0x5c, 0x2c, 0x74, 0x7c, 0x16, - 0x73, 0xc9, 0xf2, 0x5b, 0xeb, 0xdd, 0x92, 0xa4, 0x56, 0x40, 0xfb, 0x2c, 0x0b, 0x6a, 0x22, 0x00, 0xdd, 0x0f, 0x7f, - 0x81, 0xd0, 0x19, 0xfe, 0xf6, 0x18, 0x5c, 0x91, 0xc2, 0x7b, 0x87, 0x40, 0x58, 0xd3, 0xcd, 0x9d, 0xda, 0x80, 0x2f, - 0xc6, 0xfd, 0x19, 0x53, 0x4f, 0xbf, 0xcd, 0xe4, 0xae, 0xae, 0xdb, 0x23, 0xcb, 0xf0, 0x11, 0xae, 0x14, 0x00, 0xcb, - 0x84, 0xbf, 0x18, 0x5b, 0x52, 0x7d, 0x02, 0x70, 0x6a, 0x3a, 0xa2, 0x4f, 0x10, 0x18, 0x38, 0x25, 0x5a, 0x8c, 0xae, - 0x95, 0x23, 0x9a, 0x41, 0x5a, 0xd3, 0xad, 0x30, 0xde, 0x7a, 0xd0, 0x42, 0xcf, 0x34, 0x9c, 0xf8, 0x0f, 0x9a, 0x79, - 0x55, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0xd1, 0x1c, 0x21, 0x3e, 0x61, 0x49, 0x34, 0x61, 0xf1, 0x4c, 0xf1, - 0x63, 0x42, 0x37, 0x4d, 0x6d, 0xd3, 0x07, 0xa4, 0xbf, 0xb8, 0x66, 0xfd, 0x94, 0x65, 0xed, 0xdb, 0x43, 0xc5, 0x8b, - 0x69, 0x33, 0xf8, 0x61, 0xa2, 0x8a, 0xf1, 0xbf, 0xa8, 0x7c, 0xa9, 0x15, 0xc0, 0x30, 0x77, 0xd5, 0xd3, 0xef, 0x37, - 0xb3, 0xe5, 0x40, 0xa8, 0xfc, 0xce, 0x20, 0xe9, 0xd3, 0xf1, 0xfc, 0xc0, 0x26, 0x51, 0x5b, 0xe8, 0xf9, 0xe3, 0x52, - 0x37, 0xa1, 0xf2, 0xda, 0xd4, 0x88, 0x56, 0xc8, 0x50, 0xd9, 0x3a, 0x60, 0x7d, 0xff, 0x10, 0xee, 0x2e, 0x6a, 0x1a, - 0x6a, 0xdd, 0x73, 0xd7, 0xa2, 0xe0, 0xc4, 0x1f, 0x60, 0x2c, 0x2e, 0x24, 0xb5, 0x0e, 0xc2, 0xa4, 0x1f, 0x2d, 0x4e, - 0x72, 0xa3, 0xae, 0x4e, 0xce, 0x14, 0xf3, 0x04, 0x2e, 0xaa, 0x65, 0xdb, 0x5f, 0x51, 0xa9, 0x4b, 0xb9, 0xbd, 0xa2, - 0x34, 0x3d, 0xa4, 0xed, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x0b, 0x05, 0x17, 0xd6, 0xc1, 0xba, 0xe3, 0x4e, 0xd9, - 0x13, 0x9e, 0x28, 0xd3, 0xda, 0xe0, 0xae, 0x1b, 0x8c, 0x89, 0xb1, 0xdf, 0x5d, 0xf2, 0xe4, 0x23, 0xb2, 0xe0, 0xdf, - 0x65, 0x02, 0x3c, 0x93, 0xdd, 0x2b, 0x95, 0xff, 0x07, 0xff, 0x6a, 0x6b, 0xdf, 0x59, 0xf3, 0x4f, 0xcf, 0x7a, 0xb8, - 0x73, 0x98, 0xfc, 0x00, 0x9d, 0x01, 0xdd, 0x5c, 0xc9, 0x94, 0x03, 0x32, 0x80, 0xb5, 0x48, 0x46, 0x03, 0x3e, 0xb4, - 0xb2, 0x6c, 0xfb, 0x4e, 0xab, 0x0b, 0xc2, 0xbd, 0x04, 0x6e, 0x7a, 0x7f, 0x6d, 0x66, 0xe6, 0x74, 0xad, 0x44, 0xd3, - 0xa5, 0xb1, 0xb5, 0x2c, 0x55, 0xc0, 0xee, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x70, 0x39, 0xcd, 0x2d, 0x75, 0xdb, 0xb8, - 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0xb5, 0x22, 0xf4, 0x54, 0x89, 0xd0, - 0xa7, 0x69, 0xb3, 0x0f, 0x76, 0x55, 0xad, 0x1b, 0x71, 0x8e, 0x06, 0xa9, 0x66, 0xe4, 0x4f, 0xae, 0x79, 0x71, 0x91, - 0xcb, 0x1b, 0xc0, 0x40, 0x26, 0xb5, 0x51, 0x58, 0x5e, 0x81, 0x3b, 0x3f, 0x3a, 0x8e, 0x33, 0x31, 0xca, 0x31, 0x58, - 0x2b, 0xc2, 0x23, 0xeb, 0xc4, 0x19, 0x80, 0x20, 0xfb, 0x93, 0xa6, 0xe3, 0xb9, 0x16, 0x18, 0xd3, 0x17, 0xb8, 0xab, - 0x9c, 0x1d, 0x6d, 0x72, 0xbb, 0xe8, 0x9b, 0x33, 0xac, 0x3b, 0x52, 0x5a, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, 0x06, - 0x6d, 0x11, 0x4a, 0x3e, 0xe4, 0x4e, 0xda, 0x4f, 0x01, 0x0d, 0xce, 0xb2, 0xf4, 0xd6, 0x5a, 0xe5, 0x6f, 0xb4, 0x10, - 0x27, 0x8a, 0xa9, 0x13, 0xdf, 0x44, 0x89, 0x3e, 0x3f, 0x13, 0xe3, 0x06, 0x02, 0xa9, 0x3f, 0x60, 0x50, 0x8d, 0x22, - 0x4c, 0xe0, 0x3a, 0x10, 0xc5, 0xf6, 0x44, 0x6d, 0x2c, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x41, 0x19, 0xc6, 0xea, 0xe2, - 0x40, 0x1b, 0x2c, 0x7d, 0xdd, 0x5a, 0xe7, 0x86, 0x50, 0x18, 0x27, 0x30, 0xc5, 0x20, 0xa9, 0xb3, 0xce, 0x32, 0x41, - 0x95, 0x1d, 0x93, 0xce, 0xfb, 0x00, 0xdd, 0x5d, 0x8b, 0xa6, 0xf8, 0xba, 0x73, 0x07, 0xdd, 0xc7, 0xf5, 0x6b, 0x2d, - 0x72, 0x83, 0x3f, 0x6f, 0x89, 0xb0, 0x08, 0x9c, 0xb5, 0x26, 0x5f, 0x35, 0xc2, 0x81, 0x29, 0xc9, 0x34, 0xec, 0x25, - 0xca, 0xa6, 0x7b, 0xbb, 0xed, 0xf5, 0xee, 0x15, 0x71, 0xf5, 0x18, 0xab, 0xbc, 0x9b, 0xb9, 0xbd, 0x53, 0xad, 0xc5, - 0xee, 0x4d, 0xdb, 0x4f, 0xb1, 0xa3, 0xd6, 0xda, 0xed, 0x86, 0x13, 0x6a, 0xc8, 0xb7, 0xa2, 0x4a, 0xab, 0xd3, 0x8d, - 0x41, 0x3b, 0xc4, 0xb3, 0x16, 0x19, 0xdc, 0x28, 0x5f, 0x38, 0xa1, 0x93, 0x8a, 0xb3, 0xea, 0xd4, 0x05, 0x9b, 0x2b, - 0x5e, 0x2d, 0x65, 0x1a, 0x09, 0x8a, 0x36, 0xe7, 0x51, 0x49, 0x13, 0xb9, 0x16, 0x55, 0x24, 0x6b, 0xd4, 0x8b, 0x5a, - 0x8d, 0x01, 0x02, 0x32, 0x9d, 0x35, 0x3d, 0xa8, 0x82, 0xd9, 0x50, 0x46, 0x72, 0xfa, 0x1e, 0x2c, 0xed, 0x91, 0x63, - 0xad, 0xef, 0xab, 0xb3, 0xc5, 0xb7, 0x7a, 0x42, 0x30, 0x85, 0xd9, 0x03, 0x61, 0xe0, 0x9a, 0xc6, 0x90, 0xd3, 0x2e, - 0x71, 0x59, 0xd3, 0x2d, 0xe1, 0x1e, 0x6e, 0x57, 0xb2, 0x23, 0x37, 0x4f, 0x9a, 0x9b, 0x2b, 0xd8, 0x51, 0x31, 0x1f, - 0x83, 0xf6, 0x4b, 0xaa, 0x6b, 0x97, 0xe6, 0xd6, 0xe3, 0x41, 0x40, 0x83, 0x41, 0x61, 0xf8, 0xd7, 0x89, 0xf1, 0xf0, - 0xa4, 0x01, 0x41, 0x52, 0x2e, 0xc2, 0xb1, 0x6f, 0x44, 0x3f, 0x99, 0xca, 0x43, 0x8e, 0x16, 0xef, 0xd0, 0xea, 0x04, - 0xa2, 0x78, 0x89, 0x50, 0x12, 0xa3, 0x2a, 0x34, 0x22, 0x28, 0x4f, 0xcb, 0x5f, 0xaa, 0xea, 0x10, 0x50, 0x48, 0xfb, - 0x8a, 0x42, 0xd9, 0x26, 0x31, 0x34, 0xc3, 0x2f, 0xe7, 0x93, 0x85, 0x9e, 0x81, 0x81, 0x9c, 0x1f, 0x2c, 0xf4, 0x2c, - 0x0c, 0xe4, 0xfc, 0xc9, 0xa2, 0x76, 0xeb, 0x40, 0x13, 0x10, 0xcf, 0x85, 0xa3, 0x93, 0xd2, 0xaa, 0x6c, 0x01, 0xdd, - 0x3c, 0x44, 0xd0, 0x7f, 0xb2, 0x87, 0xa0, 0x93, 0x0b, 0xed, 0xc8, 0x0d, 0x68, 0x3b, 0x0e, 0x81, 0xbd, 0x62, 0x52, - 0x61, 0x02, 0x10, 0x1d, 0xb2, 0x31, 0x18, 0x62, 0xab, 0x0f, 0x0e, 0xd9, 0x78, 0xea, 0x93, 0x20, 0x60, 0x74, 0x7f, - 0x30, 0x90, 0xe0, 0xb7, 0x78, 0x95, 0x3e, 0xda, 0x08, 0x74, 0xd3, 0x77, 0x77, 0x43, 0xef, 0xe2, 0x0a, 0x4e, 0xd5, - 0xee, 0x9e, 0x84, 0x6e, 0x32, 0xed, 0x00, 0xbd, 0x86, 0xb8, 0x21, 0xbf, 0x32, 0x1a, 0x8d, 0x6c, 0x4a, 0x48, 0x88, - 0xe1, 0x1c, 0x9a, 0x39, 0x2d, 0x97, 0xaf, 0x6e, 0x3d, 0x1b, 0x90, 0x61, 0xa6, 0xb7, 0x4c, 0xd6, 0x0f, 0x50, 0x56, - 0x3d, 0x86, 0x76, 0xe8, 0x3d, 0x72, 0xfc, 0xf0, 0xe0, 0x9b, 0x8c, 0x9f, 0x39, 0x5c, 0x7b, 0x38, 0x17, 0xbe, 0xcb, - 0x9a, 0x91, 0x39, 0x74, 0x9e, 0x7d, 0x1c, 0xef, 0x61, 0x9c, 0x7c, 0x9e, 0x85, 0xf2, 0xc6, 0x6b, 0xfa, 0x1f, 0x95, - 0xde, 0xec, 0x70, 0xc8, 0xe9, 0x0a, 0x56, 0xdc, 0xac, 0x0a, 0x0d, 0x3f, 0x8b, 0xbc, 0x71, 0xc4, 0x6b, 0x12, 0x55, - 0xdd, 0xe7, 0xbd, 0x0d, 0x53, 0xda, 0x31, 0x0e, 0x00, 0x4e, 0xd4, 0xaa, 0x61, 0x57, 0x1a, 0xd7, 0xea, 0x20, 0x86, - 0xa1, 0x84, 0xad, 0x12, 0x47, 0x42, 0xf9, 0x1b, 0x80, 0xb0, 0x18, 0x8a, 0xe3, 0xad, 0x61, 0x7d, 0x80, 0xfd, 0xd0, - 0x05, 0x9a, 0xe6, 0x94, 0x6a, 0x06, 0x00, 0x49, 0xc0, 0x1f, 0x3d, 0xdd, 0x34, 0x54, 0xb6, 0x79, 0x1e, 0x5a, 0x56, - 0x57, 0xf0, 0x40, 0x4f, 0x5d, 0xc9, 0xc0, 0xb8, 0xaa, 0x63, 0x6f, 0x73, 0x7f, 0x7b, 0xb4, 0x8a, 0x7c, 0x67, 0x93, - 0xda, 0x66, 0x55, 0x68, 0xec, 0xe3, 0x09, 0x3d, 0x9d, 0x00, 0xad, 0xd7, 0x96, 0x8a, 0xf6, 0xfb, 0x28, 0x46, 0x8d, - 0x0b, 0x05, 0x56, 0x61, 0x22, 0xc1, 0x21, 0xc2, 0x08, 0xa1, 0xdf, 0x97, 0xe1, 0xc6, 0x17, 0x64, 0x10, 0x0d, 0xd7, - 0xa2, 0xe3, 0x0f, 0x39, 0x5e, 0xb4, 0x2d, 0x55, 0x35, 0x27, 0x4d, 0x5b, 0x02, 0x6f, 0xc2, 0x01, 0xb6, 0xf3, 0x4f, - 0x1b, 0x22, 0x57, 0xe1, 0xa2, 0x84, 0xef, 0x88, 0x6b, 0x41, 0x74, 0x53, 0x9b, 0x7a, 0x1b, 0x76, 0x88, 0x8e, 0xa6, - 0x78, 0x74, 0xc8, 0x3d, 0x77, 0xcf, 0x6d, 0x11, 0xdf, 0x7c, 0x86, 0xdc, 0x35, 0x9d, 0xbd, 0x14, 0x61, 0x50, 0xb7, - 0x6c, 0xa0, 0x58, 0x87, 0x4e, 0x50, 0x80, 0x51, 0x5b, 0x3e, 0x01, 0x1d, 0x1b, 0x0c, 0x2a, 0x82, 0x4f, 0x0a, 0xdb, - 0xa6, 0x41, 0xfe, 0x88, 0x77, 0x43, 0x87, 0xd7, 0x96, 0x3c, 0x10, 0xaf, 0xb0, 0xcf, 0x94, 0x70, 0xff, 0x82, 0x82, - 0xee, 0x28, 0x2f, 0x57, 0x85, 0xab, 0xd2, 0x00, 0x54, 0xd9, 0xf1, 0x5c, 0x6b, 0x4a, 0x5a, 0xc0, 0x4a, 0x49, 0xdd, - 0xf9, 0x4d, 0x44, 0xdc, 0x92, 0xa9, 0x98, 0xad, 0xba, 0x51, 0xe5, 0xa1, 0x44, 0x91, 0x8e, 0x3d, 0xdb, 0x39, 0x58, - 0x03, 0xe0, 0x29, 0x6c, 0x2f, 0xce, 0xb0, 0xa0, 0x8c, 0xcb, 0x96, 0xb9, 0x04, 0x8a, 0xfa, 0x61, 0x9c, 0x97, 0x1d, - 0x5f, 0xee, 0x8e, 0xb6, 0xf7, 0xd0, 0x1b, 0xb1, 0x31, 0x5e, 0x5f, 0x46, 0x4d, 0xbf, 0x78, 0x86, 0x2b, 0x4b, 0x41, - 0x1e, 0x68, 0xaa, 0x47, 0x18, 0x1d, 0x02, 0xd3, 0x94, 0x1f, 0xb1, 0xf1, 0x74, 0x38, 0x34, 0x64, 0xd0, 0x6b, 0x26, - 0xc6, 0xff, 0xfa, 0x02, 0x5a, 0x67, 0x26, 0xae, 0xf1, 0x69, 0xfb, 0x0a, 0x5a, 0xdd, 0xa2, 0x4c, 0xee, 0x0c, 0x0c, - 0x1f, 0x68, 0xc9, 0x14, 0x4c, 0x15, 0xde, 0x10, 0xa9, 0x64, 0x9f, 0x96, 0xd6, 0x61, 0xdf, 0x2e, 0x14, 0x5a, 0x68, - 0xe2, 0x57, 0x19, 0xe2, 0xa7, 0xae, 0x33, 0xff, 0x36, 0xed, 0x53, 0x83, 0x58, 0x58, 0x12, 0xa3, 0x10, 0xbf, 0x38, - 0x55, 0xb6, 0x13, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x55, 0xec, 0x49, 0xa1, 0xf1, 0xd4, 0x70, 0xdf, - 0x0b, 0x1d, 0xb3, 0x0e, 0xb3, 0xb8, 0xcd, 0x1a, 0x49, 0x8d, 0x71, 0x2a, 0x4c, 0x70, 0x4a, 0xb9, 0x8a, 0x04, 0x46, - 0xc7, 0xb3, 0x85, 0x41, 0x54, 0x49, 0x4c, 0x32, 0xb6, 0x16, 0xc2, 0xc4, 0xae, 0x73, 0x85, 0x69, 0xea, 0x22, 0xf5, - 0x9b, 0x81, 0xc9, 0x82, 0x86, 0xfc, 0x1e, 0x8d, 0xd6, 0x54, 0x4d, 0x01, 0x86, 0x71, 0x94, 0x6a, 0xfc, 0x5b, 0x84, - 0xda, 0x0c, 0x03, 0x00, 0xdb, 0xbc, 0x93, 0x99, 0xa8, 0x5e, 0x0b, 0x84, 0x40, 0x73, 0xf6, 0x53, 0x45, 0xb5, 0x33, - 0x0b, 0x46, 0xd1, 0x6e, 0xaf, 0x7c, 0x3e, 0x70, 0x42, 0x79, 0xac, 0x2e, 0x50, 0xaf, 0x64, 0xf1, 0x46, 0xa6, 0xbc, - 0x15, 0x17, 0x73, 0x4f, 0xb2, 0x0f, 0xf9, 0x08, 0xce, 0x2b, 0x74, 0x2a, 0x37, 0xdb, 0x44, 0x99, 0x25, 0x49, 0xc6, - 0x02, 0x63, 0xf3, 0x12, 0xcc, 0xa4, 0x66, 0xc6, 0xf0, 0x6b, 0x08, 0x2e, 0xb6, 0x73, 0x12, 0x6e, 0xee, 0xe7, 0x81, - 0x21, 0x34, 0xb9, 0x68, 0x89, 0x86, 0xad, 0x1d, 0xaf, 0x27, 0xd7, 0x84, 0xfb, 0xb0, 0x11, 0x6b, 0x32, 0xc6, 0xb8, - 0x36, 0x37, 0xb2, 0x7e, 0xb4, 0xc0, 0x83, 0x31, 0x65, 0xfd, 0x09, 0x64, 0x5a, 0x49, 0x59, 0xe7, 0x0b, 0x23, 0x66, - 0x52, 0x89, 0xde, 0xed, 0x1b, 0x9f, 0xd5, 0x5d, 0x44, 0xfd, 0xd6, 0x7e, 0x4f, 0xea, 0xe1, 0xce, 0x7f, 0x50, 0x58, - 0x83, 0xca, 0x88, 0xcb, 0x88, 0xf2, 0xcc, 0x81, 0x6e, 0x9a, 0x14, 0x71, 0x7a, 0xb6, 0x8a, 0x8b, 0x92, 0xa7, 0x50, - 0xa9, 0xa6, 0x6e, 0x51, 0x6f, 0x02, 0xf6, 0x86, 0x48, 0x92, 0xac, 0xa5, 0xb1, 0x15, 0xbb, 0x34, 0x48, 0xcf, 0xbd, - 0x61, 0x96, 0x5e, 0x55, 0x68, 0x48, 0x4b, 0xbd, 0xb3, 0x50, 0xc9, 0xfc, 0x15, 0xff, 0x19, 0xd4, 0x0a, 0x74, 0xb4, - 0x49, 0x31, 0x9e, 0x03, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x09, 0x4a, 0xbd, 0x23, 0x76, 0xfc, 0xdc, - 0xe4, 0xe1, 0x5d, 0xc8, 0x39, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0x48, 0x8c, 0xd4, 0x0c, 0xa0, 0xe9, 0xa0, - 0xcc, 0x79, 0x2c, 0x82, 0x59, 0xcf, 0x24, 0x46, 0x3d, 0xae, 0x7f, 0x81, 0x86, 0xda, 0x6f, 0x56, 0x96, 0x67, 0xd5, - 0xdd, 0x97, 0x70, 0x60, 0x53, 0x5b, 0x41, 0x8f, 0xd7, 0x95, 0xbc, 0xbc, 0x54, 0xdd, 0xf6, 0x0b, 0x31, 0x72, 0xba, - 0xc6, 0xb5, 0x74, 0x5e, 0x2d, 0x58, 0xaf, 0x3b, 0xdd, 0x2c, 0xee, 0x66, 0x19, 0x0d, 0x84, 0xb5, 0x9d, 0x4f, 0x34, - 0x7f, 0xd6, 0x6c, 0xbb, 0x8f, 0xb7, 0x20, 0x66, 0x01, 0x00, 0xa4, 0x07, 0x51, 0xb0, 0xcc, 0x52, 0x1e, 0x50, 0x79, - 0x1f, 0x47, 0x59, 0x28, 0xbd, 0x9c, 0x65, 0xfc, 0xb4, 0x69, 0xac, 0x75, 0x56, 0x28, 0x43, 0x6b, 0xa3, 0x3b, 0x5d, - 0x65, 0x88, 0xed, 0x27, 0x71, 0xb6, 0x00, 0xf7, 0xc7, 0x0c, 0x85, 0x86, 0xce, 0x32, 0xd2, 0x44, 0xc3, 0x77, 0xdd, - 0x33, 0xc8, 0x28, 0x4e, 0xd6, 0x79, 0x25, 0xdd, 0xe8, 0xb3, 0x36, 0x12, 0xe6, 0x1e, 0xa2, 0x5f, 0xc5, 0xe0, 0x51, - 0xee, 0xf3, 0xda, 0xe8, 0x64, 0x5a, 0x46, 0xda, 0x9d, 0x9f, 0xd4, 0xcb, 0x2c, 0xd5, 0x3a, 0x6c, 0x9f, 0x61, 0x6f, - 0x8d, 0x49, 0x6f, 0x42, 0x6a, 0x18, 0x89, 0xcf, 0x67, 0xd4, 0x08, 0x01, 0x6d, 0x39, 0xfe, 0x0e, 0x9f, 0x61, 0x68, - 0x0a, 0x2c, 0x55, 0xdc, 0xc2, 0x6e, 0xf8, 0x9a, 0x4f, 0x56, 0x2d, 0x00, 0x11, 0xac, 0x7c, 0xbd, 0x8b, 0x57, 0x42, - 0x7d, 0xa6, 0xcd, 0x00, 0x90, 0x05, 0xa5, 0xdc, 0xf1, 0x53, 0x2a, 0x1d, 0x2c, 0x51, 0xb4, 0xbd, 0x9c, 0xbe, 0xd1, - 0xb1, 0xf1, 0x43, 0x7a, 0x2e, 0x60, 0xbb, 0x90, 0xdf, 0xba, 0x57, 0x2f, 0x51, 0x91, 0xda, 0x36, 0xeb, 0x01, 0xbe, - 0xdc, 0xa0, 0x49, 0x18, 0x41, 0x99, 0x32, 0x05, 0x30, 0xb8, 0xa9, 0x46, 0xc1, 0xa4, 0xd5, 0x48, 0xd8, 0x52, 0x4f, - 0xb2, 0xdc, 0xf4, 0xc1, 0xa9, 0xee, 0x11, 0xf4, 0x68, 0x87, 0x93, 0x96, 0xfd, 0x5a, 0xc1, 0xd1, 0xc9, 0xd5, 0x10, - 0x35, 0xf3, 0x5e, 0xdb, 0x91, 0x21, 0xe5, 0x32, 0x0c, 0x04, 0x53, 0x8e, 0x79, 0x7a, 0x6c, 0x3d, 0x23, 0xa2, 0x07, - 0xce, 0x3e, 0xd3, 0xad, 0xba, 0x92, 0x80, 0xe8, 0xf8, 0xcd, 0xd3, 0xd7, 0x57, 0xf1, 0xa5, 0x41, 0x51, 0x6a, 0x58, - 0xc4, 0x28, 0xd3, 0xbe, 0x4a, 0xc2, 0xe0, 0xfd, 0xfa, 0xfe, 0x67, 0x95, 0xa5, 0xf6, 0x7b, 0xb0, 0xb1, 0xa2, 0xaa, - 0x5f, 0x4b, 0x5e, 0x34, 0x05, 0x58, 0xf7, 0x59, 0xa2, 0x40, 0xee, 0xf7, 0x36, 0xcd, 0x7c, 0x13, 0x35, 0x6e, 0x36, - 0xac, 0x37, 0xae, 0xdb, 0xa5, 0xb6, 0x64, 0x47, 0x56, 0x22, 0x67, 0x16, 0x83, 0x19, 0x3f, 0x2a, 0x0c, 0x4a, 0xc3, - 0x06, 0x55, 0xa9, 0xf8, 0xbd, 0x11, 0xc1, 0xa9, 0x63, 0x55, 0x61, 0x4c, 0x03, 0x66, 0x5b, 0x51, 0x6b, 0x50, 0x07, - 0xa5, 0xb4, 0x35, 0x51, 0xd8, 0x7e, 0x67, 0x05, 0x35, 0xbf, 0xff, 0x69, 0x0c, 0xf9, 0x9a, 0x52, 0x50, 0x49, 0xc0, - 0xce, 0xa0, 0xd1, 0x53, 0x25, 0x0c, 0xa4, 0x20, 0x78, 0x02, 0x94, 0x2f, 0xa2, 0xc6, 0x6a, 0xb7, 0xaf, 0x4e, 0x8d, - 0xd1, 0x16, 0x10, 0x5a, 0x48, 0x8f, 0x2e, 0xfb, 0xb8, 0x8d, 0x75, 0x20, 0xf1, 0xe0, 0x04, 0xdb, 0xb9, 0xba, 0x46, - 0x23, 0xa1, 0xf9, 0x43, 0xa3, 0x01, 0xaf, 0x69, 0x05, 0x0a, 0xf5, 0x1c, 0x47, 0x43, 0x67, 0x87, 0x14, 0x44, 0x6c, - 0xd0, 0xc2, 0xbe, 0x7b, 0x3e, 0x34, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x4d, 0xa5, 0xfb, 0xdc, 0x2d, 0x21, 0x6b, 0xd5, - 0xa1, 0xac, 0x3c, 0xc0, 0xf1, 0x42, 0xc9, 0xfc, 0x1d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x63, 0xc4, 0x02, 0x96, 0x04, - 0xed, 0xf5, 0x40, 0xfd, 0x32, 0x08, 0x15, 0xce, 0xf4, 0x44, 0xe2, 0x53, 0xca, 0xd5, 0xa7, 0x05, 0xa9, 0xa7, 0x05, - 0x73, 0xa0, 0x97, 0xbe, 0x95, 0x5f, 0xd9, 0xf8, 0x68, 0x77, 0xef, 0x9a, 0x0b, 0xeb, 0x18, 0x82, 0x61, 0x0b, 0xbf, - 0x39, 0x35, 0x05, 0x60, 0xc3, 0x63, 0x5d, 0x96, 0x6f, 0xd4, 0x44, 0x66, 0x71, 0x48, 0x22, 0x90, 0x6c, 0x37, 0x37, - 0xb7, 0x11, 0x6c, 0x7b, 0x0b, 0xb5, 0xa1, 0xfe, 0xf2, 0xb6, 0xfb, 0x3d, 0xc3, 0xcb, 0x3d, 0xb9, 0x77, 0xd3, 0x86, - 0xf2, 0x87, 0xfb, 0x57, 0xc9, 0xff, 0x55, 0x25, 0xf7, 0x5b, 0x65, 0xd6, 0x6d, 0xf1, 0x7e, 0xd7, 0x71, 0xcb, 0x31, - 0x1a, 0x04, 0xd6, 0x14, 0x18, 0x48, 0x4f, 0x1a, 0xd3, 0x44, 0x87, 0x54, 0x66, 0xcc, 0xe0, 0xd1, 0x05, 0x68, 0x0e, - 0xd3, 0x79, 0x1e, 0x03, 0x70, 0x80, 0x7f, 0xe4, 0x11, 0xea, 0x9f, 0xce, 0xf3, 0xe0, 0x2c, 0x18, 0x94, 0x83, 0x40, - 0x7f, 0xe2, 0x9a, 0x13, 0x2c, 0x40, 0xe7, 0x16, 0x33, 0x08, 0x36, 0x69, 0xcd, 0x1c, 0xe2, 0xc3, 0x64, 0x3a, 0x18, - 0xc4, 0x64, 0x03, 0x20, 0x7d, 0xf1, 0xc2, 0x3a, 0x07, 0x15, 0x7a, 0x41, 0xb6, 0xea, 0x2e, 0x9a, 0x15, 0x7b, 0xd5, - 0x4e, 0xf3, 0x7e, 0x3f, 0x9f, 0x97, 0x83, 0xa0, 0x51, 0x61, 0x61, 0xbc, 0xff, 0x68, 0xf3, 0x4b, 0xa3, 0x93, 0x26, - 0x18, 0xa6, 0xf6, 0x18, 0xd5, 0x2b, 0x9e, 0x66, 0xb4, 0x71, 0x3b, 0x56, 0xca, 0x17, 0x10, 0xc5, 0x03, 0x43, 0xd6, - 0xca, 0xbb, 0x73, 0xf0, 0xba, 0xdc, 0x78, 0x73, 0x44, 0x01, 0x76, 0x53, 0x18, 0x27, 0x35, 0x17, 0x5d, 0xd4, 0xc4, - 0x33, 0xd8, 0xe9, 0xea, 0xad, 0x44, 0xab, 0xf1, 0x5e, 0xbc, 0x6b, 0x36, 0xfe, 0x56, 0xee, 0xe9, 0x32, 0xf7, 0x2e, - 0x00, 0x71, 0x76, 0x2f, 0xae, 0xf6, 0xb0, 0xd4, 0xbd, 0x60, 0x60, 0x91, 0x43, 0xda, 0xd5, 0xea, 0xa1, 0x88, 0xd4, - 0x79, 0x0c, 0x06, 0x4c, 0xa6, 0x21, 0x35, 0x99, 0xf6, 0x0a, 0x05, 0x69, 0x63, 0xad, 0x05, 0xb4, 0xe1, 0xb0, 0xd8, - 0xb1, 0x1b, 0x76, 0xa7, 0x5b, 0x87, 0x42, 0x09, 0xa3, 0x57, 0xd7, 0xcd, 0x43, 0xad, 0xe1, 0x89, 0xa0, 0x07, 0xd5, - 0x68, 0x3f, 0x3d, 0x94, 0x27, 0xed, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0x52, 0xe0, 0x45, 0x7b, 0x07, 0x79, 0xce, - 0x7c, 0xaa, 0x7c, 0x10, 0x1b, 0x6e, 0x19, 0x3e, 0xb4, 0x8f, 0x6f, 0x05, 0x32, 0xa9, 0x3b, 0x9a, 0xda, 0xda, 0x1d, - 0x8d, 0x63, 0x02, 0xfd, 0xa6, 0x1c, 0xa5, 0x4c, 0x4c, 0x2d, 0x4b, 0x76, 0xd4, 0xcb, 0x95, 0x37, 0x54, 0xca, 0x8e, - 0x96, 0x6d, 0xce, 0x2f, 0x6d, 0x24, 0xf4, 0xfb, 0xda, 0x1d, 0x08, 0xdf, 0xa8, 0xf5, 0x86, 0xbc, 0x6c, 0x88, 0x58, - 0x0e, 0x31, 0x03, 0xc7, 0x0b, 0xa9, 0x5c, 0xbb, 0x8b, 0xa6, 0xaa, 0x6e, 0x67, 0x2b, 0x17, 0xb4, 0xc4, 0x5b, 0x29, - 0xb0, 0x8a, 0xd4, 0xe9, 0xf5, 0x54, 0xe2, 0x7d, 0x1f, 0xc5, 0xf6, 0x23, 0x60, 0x1b, 0x1b, 0x47, 0x63, 0xe3, 0x16, - 0xb1, 0xc1, 0x57, 0x51, 0x45, 0x0b, 0x0e, 0x10, 0xdc, 0x6d, 0x49, 0x2d, 0xcd, 0x1c, 0xe2, 0xbe, 0xe2, 0x01, 0xda, - 0x77, 0x71, 0xc4, 0xa9, 0x00, 0xdb, 0xba, 0xd6, 0x39, 0xab, 0xe5, 0x80, 0xcd, 0x44, 0xcf, 0x3f, 0xad, 0x1a, 0x89, - 0x18, 0x56, 0xd9, 0x48, 0x59, 0xa1, 0x3d, 0x28, 0x5d, 0xc2, 0xc5, 0x17, 0xe0, 0x65, 0xfb, 0x7e, 0x65, 0xf7, 0xd9, - 0x12, 0xfb, 0x87, 0x79, 0xd5, 0x04, 0x8f, 0xbc, 0xc6, 0xdb, 0x7b, 0x98, 0xf8, 0x52, 0x29, 0x84, 0x57, 0x29, 0x0d, - 0x25, 0x00, 0x83, 0x24, 0xa8, 0xe1, 0x4a, 0xdb, 0x66, 0x90, 0xca, 0x18, 0x76, 0xb7, 0x7a, 0xab, 0xff, 0xd3, 0x2a, - 0x5c, 0x54, 0xb2, 0x18, 0x93, 0x40, 0xe7, 0x54, 0xcb, 0x4d, 0x4c, 0xc1, 0xb3, 0x5d, 0x72, 0x04, 0x0a, 0x3b, 0x01, - 0xdc, 0x50, 0xc2, 0x7e, 0xc5, 0xdb, 0x50, 0xce, 0x5e, 0x59, 0xc9, 0x93, 0xdb, 0x97, 0x54, 0xd0, 0x84, 0x4c, 0x85, - 0xdd, 0xbf, 0xad, 0x0d, 0xfb, 0x22, 0x94, 0x23, 0x29, 0x70, 0x71, 0xd0, 0x39, 0x80, 0xfd, 0x41, 0x2e, 0x63, 0xf3, - 0x99, 0xf4, 0xfb, 0xea, 0xfd, 0xf3, 0x3c, 0x4b, 0x3e, 0xee, 0xbc, 0x37, 0x3c, 0xcd, 0x92, 0x01, 0x95, 0x88, 0xa9, - 0x75, 0x55, 0x0c, 0x97, 0xda, 0xc5, 0xb8, 0x41, 0x32, 0xe2, 0x7b, 0xa9, 0x43, 0x8c, 0x18, 0x5f, 0x64, 0x87, 0xa4, - 0xe4, 0x74, 0x59, 0x77, 0xf6, 0x5c, 0x8b, 0x66, 0xd0, 0x18, 0x6e, 0xc7, 0x7b, 0x49, 0xaf, 0x00, 0x15, 0x15, 0xba, - 0x67, 0x81, 0x6b, 0x78, 0x73, 0x49, 0x34, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xb8, 0x57, 0x26, 0x24, 0xd5, 0xc6, 0x01, - 0x16, 0xb1, 0xae, 0x3f, 0x86, 0x12, 0x80, 0x5a, 0x0d, 0xd2, 0x2b, 0x7d, 0x45, 0xa8, 0x4a, 0x42, 0x30, 0x3a, 0x91, - 0xf0, 0x32, 0xa0, 0x71, 0x66, 0x12, 0x2d, 0x6c, 0x70, 0x40, 0x5f, 0x54, 0x26, 0xd1, 0xd8, 0x90, 0x07, 0xb4, 0xb2, - 0x69, 0x00, 0x83, 0x0f, 0x92, 0x24, 0xfa, 0x7a, 0x69, 0x92, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x4b, 0xe9, 0xf9, - 0x58, 0xfe, 0xcb, 0x3b, 0x94, 0x7e, 0x08, 0x25, 0xc8, 0x14, 0x75, 0xc5, 0x34, 0x63, 0x47, 0x59, 0xb7, 0x31, 0x89, - 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x79, 0xbc, 0x62, 0xc7, 0x21, 0xd7, - 0x78, 0xe9, 0xcf, 0xe3, 0x15, 0xce, 0x10, 0xad, 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, - 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x4e, 0x92, 0xf9, 0xf2, - 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, - 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x5a, - 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1b, 0x50, 0x22, 0xa3, 0xb2, - 0xe2, 0xab, 0x15, 0x4f, 0x67, 0xb7, 0x49, 0x94, 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0x59, 0x9f, 0x67, - 0xc9, 0x6b, 0x88, 0x3d, 0xb0, 0x92, 0x0a, 0x8b, 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x76, - 0x9d, 0x44, 0x6f, 0x97, 0x1e, 0x92, 0x9a, 0x99, 0xb2, 0x4d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x1b, 0x6d, 0x01, - 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, - 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x0f, 0x8b, 0x7e, 0x5f, - 0x1e, 0x16, 0xdb, 0x6d, 0x79, 0x14, 0xf7, 0xfb, 0xf2, 0x28, 0x36, 0xfc, 0x83, 0x52, 0x6c, 0x1b, 0x73, 0x83, 0x84, - 0xe6, 0x12, 0xa2, 0x16, 0x8d, 0xe0, 0x0f, 0xcd, 0x72, 0x2e, 0xa2, 0xfc, 0x30, 0xe9, 0xf7, 0x7b, 0xcb, 0x99, 0x18, - 0xe4, 0xc3, 0x24, 0xca, 0x87, 0x89, 0xe7, 0x84, 0xf8, 0x9b, 0xe7, 0x84, 0xa8, 0x68, 0xe0, 0x0a, 0xce, 0x0c, 0x40, - 0x14, 0xf0, 0xe9, 0x1f, 0xd5, 0xb5, 0x14, 0xba, 0x96, 0x58, 0xd5, 0x92, 0xe8, 0x0a, 0x6a, 0x76, 0x5d, 0x84, 0x25, - 0x96, 0x42, 0x97, 0xec, 0xcf, 0x25, 0xf0, 0x44, 0x39, 0xaf, 0x36, 0xc0, 0xc0, 0x46, 0x78, 0xe7, 0x30, 0xe1, 0x24, - 0xd6, 0x35, 0xa0, 0x9d, 0x6e, 0x6a, 0x7a, 0x41, 0x57, 0xf4, 0x12, 0xf9, 0xd9, 0x0b, 0x30, 0x58, 0x3a, 0x64, 0xf9, - 0x74, 0x30, 0xb8, 0x20, 0x2b, 0x56, 0xce, 0xc3, 0x78, 0x10, 0xae, 0x67, 0xf9, 0xf0, 0x22, 0xba, 0x20, 0xe4, 0xab, - 0x62, 0x41, 0x7b, 0xab, 0x51, 0xf9, 0x31, 0x83, 0xe0, 0x7e, 0xe9, 0x2c, 0xcc, 0x4c, 0x9c, 0x8f, 0xd5, 0xe8, 0x96, - 0xae, 0x20, 0x7e, 0x0d, 0xdc, 0x48, 0x48, 0x04, 0x1d, 0xb9, 0xa4, 0x2b, 0xba, 0xa6, 0xd2, 0xcc, 0x30, 0x86, 0xe8, - 0xb6, 0xc7, 0x49, 0x02, 0x8e, 0xc9, 0xae, 0xf8, 0x68, 0xac, 0x0a, 0xef, 0xfa, 0x8e, 0xd0, 0x5e, 0x2f, 0x71, 0x83, - 0xf4, 0x5d, 0x7b, 0x90, 0x80, 0x11, 0x19, 0xa9, 0x81, 0x32, 0x23, 0x23, 0xa9, 0x99, 0x54, 0x1c, 0x92, 0xd8, 0x1f, - 0x12, 0x35, 0x0e, 0x89, 0x3f, 0x0e, 0xb9, 0x1e, 0x07, 0xe4, 0xee, 0x97, 0x6c, 0x4c, 0x53, 0x36, 0xa6, 0x6b, 0x35, - 0x2a, 0xf4, 0x8a, 0x9e, 0x6b, 0xea, 0x78, 0xc6, 0xde, 0xc0, 0x81, 0x3d, 0x08, 0xf3, 0x59, 0x3c, 0x7c, 0x13, 0xbd, - 0x21, 0xe4, 0x2b, 0x49, 0xaf, 0xd5, 0xa5, 0x0c, 0xc2, 0x20, 0x5e, 0x81, 0x73, 0xa9, 0x0b, 0x75, 0x72, 0x65, 0x76, - 0x1c, 0x3e, 0x5d, 0x36, 0x9e, 0xce, 0x21, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x05, 0x2b, 0xe7, 0x67, 0xe1, - 0x98, 0x00, 0x0e, 0x8f, 0x1e, 0xce, 0x8b, 0xd1, 0x2d, 0xbd, 0x18, 0xdd, 0x11, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0x87, - 0x2c, 0x9e, 0x0e, 0x06, 0x6b, 0xa4, 0xea, 0x2a, 0xf7, 0x9a, 0x2c, 0xe8, 0x05, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x13, - 0x6b, 0x43, 0xc3, 0xdf, 0x30, 0xf8, 0xf8, 0x8e, 0x5d, 0x8c, 0xee, 0xe8, 0x2d, 0x7b, 0xb3, 0x1d, 0x4f, 0x81, 0x99, - 0x5a, 0xcd, 0xc2, 0xbb, 0xc3, 0xcb, 0xd9, 0x25, 0xbb, 0x8b, 0xee, 0x8e, 0xa0, 0xa1, 0x57, 0xec, 0x0e, 0x01, 0x97, - 0xd2, 0xc7, 0xcb, 0xc1, 0x1b, 0xb2, 0x3f, 0x18, 0xa4, 0x24, 0x0a, 0xaf, 0x43, 0xaf, 0x95, 0x6f, 0xe8, 0x1d, 0xa1, - 0x2b, 0x76, 0x8b, 0xa3, 0x71, 0xc9, 0xf0, 0x83, 0x73, 0x76, 0x57, 0x5f, 0x87, 0xde, 0x6e, 0x4e, 0x44, 0x27, 0x88, - 0x11, 0xfa, 0x1a, 0x38, 0x9a, 0xe5, 0xc2, 0x4c, 0xc0, 0x93, 0xb9, 0xc8, 0x68, 0x51, 0x68, 0x06, 0xe2, 0xac, 0x04, - 0xc4, 0x92, 0xa8, 0xfb, 0xcd, 0x46, 0x67, 0xb0, 0x9c, 0xfb, 0xfd, 0x5e, 0x65, 0xe8, 0x01, 0x22, 0x67, 0x76, 0xd2, - 0x83, 0x9e, 0x4f, 0x0f, 0xf0, 0x13, 0xbd, 0x6a, 0x10, 0x27, 0xf3, 0xbb, 0x65, 0xf4, 0x9b, 0x47, 0x1f, 0x7e, 0xe8, - 0xa6, 0x3c, 0x22, 0xff, 0xf7, 0x29, 0x4f, 0x99, 0x47, 0x6f, 0x2a, 0x0f, 0x04, 0xcf, 0x5b, 0x93, 0x4a, 0x23, 0x51, - 0x8d, 0xce, 0x56, 0x31, 0x68, 0x23, 0x51, 0xdb, 0xa0, 0x9f, 0xd0, 0xc2, 0x0a, 0x22, 0xe4, 0x1c, 0xbc, 0x00, 0x83, - 0x54, 0x08, 0x95, 0xa3, 0x16, 0x25, 0x1a, 0x82, 0xe4, 0xb2, 0xe4, 0x2a, 0x7c, 0x0e, 0xa1, 0xea, 0xf4, 0x71, 0x26, - 0xc2, 0x86, 0x1e, 0x87, 0x3e, 0x00, 0xfc, 0xaf, 0x3b, 0xe4, 0xa2, 0xe4, 0x97, 0x78, 0x36, 0xb7, 0x09, 0x46, 0xc1, - 0x12, 0xd1, 0x0c, 0x6d, 0x83, 0xd8, 0x8f, 0x25, 0xc1, 0x7a, 0x24, 0x8d, 0x47, 0xa5, 0x39, 0x22, 0xfc, 0x28, 0x3e, - 0x8a, 0x9e, 0xc6, 0x86, 0x44, 0x72, 0x24, 0x91, 0x7c, 0x00, 0x84, 0x93, 0xa0, 0xbf, 0xb8, 0x6b, 0xb2, 0x6b, 0x21, - 0x31, 0xe8, 0x4f, 0x4b, 0xa6, 0x65, 0xf7, 0xaa, 0xc7, 0xbe, 0x22, 0xc8, 0x1d, 0xd3, 0x7f, 0x79, 0x7d, 0xf8, 0xe7, - 0x12, 0x67, 0xd0, 0x7a, 0xbe, 0xa8, 0xce, 0xcc, 0xbc, 0xc1, 0x8d, 0xbc, 0x2e, 0x6b, 0xd7, 0xe5, 0x0b, 0xbe, 0xc7, - 0x6f, 0x2b, 0x2e, 0xd2, 0x72, 0xef, 0x97, 0xaa, 0x8d, 0xe7, 0x54, 0xae, 0x57, 0x2e, 0xce, 0x8a, 0x32, 0x4e, 0xf5, - 0xa4, 0x2e, 0xc6, 0x1a, 0xb6, 0xe1, 0xf7, 0x88, 0xba, 0x92, 0x96, 0xa3, 0xa7, 0x94, 0xab, 0x66, 0xca, 0xc5, 0x3a, - 0xcf, 0x7f, 0xde, 0x49, 0xc5, 0x29, 0x6e, 0xa6, 0x20, 0x55, 0x6a, 0xb9, 0x80, 0xea, 0x39, 0x6a, 0xb9, 0x5b, 0x9a, - 0x1d, 0xe0, 0xdc, 0x36, 0xd5, 0xc7, 0xca, 0xec, 0xc2, 0x4b, 0x6e, 0xdc, 0x9f, 0x4c, 0x19, 0x16, 0x8c, 0x42, 0x9b, - 0x55, 0x57, 0xda, 0xbe, 0xd0, 0x3a, 0x0d, 0xc3, 0x95, 0x1f, 0x2f, 0x20, 0x5d, 0xc0, 0x38, 0x5e, 0x94, 0x4c, 0x8c, - 0xdb, 0xa3, 0xb7, 0x82, 0xf8, 0x92, 0xad, 0x40, 0xc0, 0x5c, 0xc3, 0xdb, 0x75, 0x1d, 0x6d, 0xf7, 0xc4, 0x29, 0xa3, - 0x72, 0x15, 0x8b, 0xef, 0xe3, 0x95, 0x81, 0x4c, 0x56, 0xc7, 0x63, 0x63, 0x4c, 0xa7, 0x3f, 0x25, 0xa1, 0x5f, 0x08, - 0x05, 0x9f, 0xf5, 0xd2, 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, - 0xe4, 0xab, 0xa6, 0x80, 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, - 0x9d, 0x1a, 0x53, 0x31, 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, - 0xa8, 0xdf, 0x02, 0x17, 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, - 0xbe, 0x85, 0x07, 0x88, 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, - 0xa9, 0xd2, 0xc4, 0x70, 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, - 0xe8, 0xa6, 0x74, 0xe9, 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, - 0xac, 0x95, 0xf0, 0xa6, 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, - 0x14, 0x0d, 0x1d, 0xd0, 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, - 0x35, 0x2b, 0xe6, 0xf9, 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, - 0x21, 0xc9, 0x26, 0x56, 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, - 0x32, 0x0c, 0xcb, 0xe1, 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x70, 0x3e, 0x09, 0x15, - 0xbb, 0x60, 0xf7, 0x02, 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, - 0x65, 0x16, 0xcf, 0xc7, 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, - 0xbe, 0xc1, 0x2a, 0xf2, 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, - 0xdc, 0x94, 0x33, 0xae, 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, - 0x49, 0xd3, 0x80, 0xee, 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, - 0xad, 0xd0, 0xab, 0x1a, 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, - 0x12, 0x06, 0x3f, 0xa4, 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, - 0x14, 0x62, 0x94, 0x50, 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, - 0x7c, 0x5d, 0x55, 0x81, 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, - 0x48, 0x08, 0x5e, 0xff, 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, - 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, - 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, - 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, - 0x4f, 0xae, 0xd8, 0x51, 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, - 0xf7, 0x1f, 0xcb, 0x5d, 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, - 0x84, 0x2d, 0xe6, 0x70, 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, - 0xb4, 0xcc, 0xaa, 0xf7, 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, - 0x02, 0xd0, 0x64, 0x23, 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, - 0x92, 0xa0, 0x84, 0x66, 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, - 0x07, 0xf6, 0x16, 0x04, 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, - 0x08, 0xf2, 0xd5, 0x18, 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, - 0xe4, 0xd0, 0x3e, 0x4b, 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb7, 0x2d, 0xb2, 0x24, 0xeb, - 0xc7, 0xd2, 0x28, 0x62, 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3e, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, - 0x0e, 0xe2, 0x36, 0x08, 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, - 0x6f, 0xb2, 0xd6, 0xa8, 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, - 0xdb, 0xed, 0x78, 0x2a, 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, - 0xa5, 0xb7, 0x7f, 0xe1, 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, - 0x4e, 0xff, 0x76, 0x6b, 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xb4, 0x81, 0x2b, 0xd5, 0x2a, 0x04, 0xec, 0x42, - 0x49, 0xf6, 0x0f, 0x20, 0x2a, 0x42, 0x33, 0xee, 0x66, 0xd9, 0x90, 0xc8, 0xf8, 0x71, 0x3a, 0xcb, 0x86, 0x60, 0x87, - 0x7b, 0x51, 0x89, 0xcb, 0x51, 0x6b, 0x83, 0xd3, 0xb3, 0x24, 0x84, 0x50, 0x0e, 0x58, 0xd9, 0xad, 0xfa, 0x73, 0xa7, - 0xcc, 0x84, 0xd4, 0x64, 0x75, 0x3b, 0xa5, 0x7b, 0x98, 0xe6, 0x7b, 0x66, 0x04, 0x07, 0xdc, 0xdb, 0x5f, 0xf5, 0xc7, - 0x30, 0xc9, 0x34, 0x39, 0x45, 0xf2, 0x8b, 0xf4, 0x14, 0x92, 0x76, 0xe8, 0xa9, 0x22, 0x80, 0x13, 0x6a, 0x3f, 0x86, - 0xdf, 0x30, 0xee, 0xdf, 0x35, 0x5f, 0xbb, 0xa9, 0x88, 0x9e, 0x52, 0x2c, 0x53, 0x93, 0xd3, 0x24, 0x2b, 0x12, 0x88, - 0xda, 0xa8, 0x9a, 0x11, 0x3d, 0x71, 0x31, 0x1f, 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, - 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xec, 0x29, 0xdd, 0x9b, 0x7c, 0x73, 0x40, 0xf7, 0x0e, 0x9e, 0x3c, 0x23, 0x00, - 0x8b, 0x76, 0x79, 0x1e, 0x1e, 0x3c, 0x7b, 0x46, 0xf7, 0xbe, 0xfd, 0x96, 0xee, 0x4d, 0x9e, 0x1c, 0x34, 0xd2, 0x26, - 0xcf, 0xbe, 0xa5, 0x7b, 0xdf, 0x3c, 0x6d, 0xa4, 0x1d, 0x8c, 0x9f, 0xd1, 0xbd, 0xbf, 0x7f, 0x63, 0xd2, 0xfe, 0x06, - 0xd9, 0xbe, 0x3d, 0xc0, 0xff, 0x4c, 0xda, 0xe4, 0xd9, 0x13, 0xba, 0x37, 0x19, 0x43, 0x25, 0xcf, 0x5c, 0x25, 0xe3, - 0x09, 0x7c, 0xfc, 0x04, 0xfe, 0xfb, 0x1b, 0x09, 0x16, 0xb4, 0x92, 0x2c, 0x17, 0xa8, 0x3f, 0x43, 0x11, 0x27, 0xaa, - 0x26, 0x12, 0x1e, 0x62, 0x66, 0xf5, 0x4d, 0x1c, 0x06, 0xc4, 0xa5, 0x43, 0x41, 0x74, 0x6f, 0x3c, 0x7a, 0x46, 0x02, - 0x1f, 0x9e, 0xee, 0xc6, 0x07, 0x19, 0xcb, 0xc5, 0x3c, 0xfb, 0x2a, 0x37, 0xb1, 0x15, 0x3c, 0x00, 0xab, 0x8f, 0x7e, - 0xae, 0x4a, 0xce, 0xb3, 0xaf, 0x2a, 0xb9, 0x9b, 0xeb, 0xf7, 0x16, 0xa0, 0xbc, 0xbf, 0x6a, 0xd9, 0x4d, 0xa1, 0x42, - 0xa7, 0xb5, 0x46, 0x9f, 0x7d, 0xc4, 0xf4, 0xc1, 0xc0, 0xbb, 0x61, 0xff, 0xb4, 0x53, 0x4e, 0xeb, 0x1b, 0x8d, 0x42, - 0x8d, 0xca, 0x43, 0xc2, 0x8e, 0xa0, 0xe8, 0xc1, 0x00, 0x78, 0x02, 0x0f, 0xf7, 0xed, 0xdf, 0x2c, 0xe3, 0x63, 0x47, - 0x19, 0xbf, 0xa0, 0x0c, 0x01, 0x8d, 0x7a, 0x98, 0xdd, 0xf4, 0xb0, 0xd1, 0xad, 0x5e, 0xb2, 0x54, 0x27, 0x53, 0xd3, - 0x33, 0xd8, 0xd7, 0xba, 0x96, 0x7b, 0x46, 0x14, 0x2d, 0x2f, 0xf6, 0x52, 0x3e, 0xab, 0xd8, 0x4f, 0x4b, 0x54, 0x6f, - 0x45, 0x8d, 0x37, 0x32, 0x9b, 0x55, 0xec, 0x7b, 0xf3, 0x06, 0xb8, 0x19, 0xf6, 0xbb, 0x7a, 0xf2, 0x03, 0x67, 0x70, - 0x69, 0xdb, 0xa3, 0x4c, 0x8c, 0x00, 0x2b, 0x20, 0x03, 0x07, 0x1e, 0x00, 0x1d, 0xf4, 0x47, 0x7b, 0xbb, 0x55, 0x29, - 0xcd, 0x3e, 0x5b, 0x18, 0x40, 0xc3, 0xbc, 0x4d, 0x5c, 0xd9, 0xff, 0x6a, 0xc8, 0x4b, 0x50, 0xb8, 0xd5, 0x2c, 0x6f, - 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x65, 0x40, 0xcd, 0x96, 0x8f, 0x36, - 0x5c, 0xa9, 0x27, 0x81, 0x33, 0xb8, 0x90, 0x45, 0xc2, 0x4f, 0xb4, 0xd8, 0x1f, 0xad, 0x1f, 0x7d, 0xdf, 0x1e, 0x0f, - 0xd6, 0xbe, 0xc7, 0x47, 0xfa, 0xb3, 0xc6, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0x17, 0xb5, 0x95, 0x78, 0x94, 0xc0, 0x1b, - 0x98, 0x88, 0x14, 0x06, 0xa9, 0x16, 0x38, 0x06, 0xe5, 0x8d, 0x85, 0x58, 0xaa, 0xae, 0x6e, 0xb0, 0x05, 0x91, 0x21, - 0x78, 0xb8, 0xfd, 0x6b, 0xa9, 0x02, 0x47, 0xf5, 0xfb, 0x5c, 0xfa, 0x6e, 0x4f, 0xc6, 0x8e, 0x1c, 0xa7, 0x7e, 0x2a, - 0x1c, 0xfc, 0x37, 0xa9, 0x6b, 0x63, 0xb9, 0x92, 0x32, 0xcb, 0xb2, 0xb0, 0xa3, 0x50, 0xcb, 0x3d, 0x2a, 0x0f, 0x92, - 0x2f, 0xe4, 0x10, 0xc9, 0x02, 0xa3, 0x50, 0x90, 0xe1, 0x84, 0x8a, 0xd1, 0x5a, 0x94, 0xcb, 0xec, 0xa2, 0x0a, 0x37, - 0x4a, 0xa1, 0xcc, 0x29, 0xfa, 0x76, 0x83, 0x03, 0x09, 0x89, 0xb2, 0xf2, 0x6d, 0xfc, 0x36, 0x44, 0xb0, 0x3a, 0xae, - 0x6d, 0xa1, 0xb8, 0xb7, 0x3f, 0x79, 0xda, 0xc5, 0x1f, 0x19, 0x17, 0x50, 0x17, 0x8b, 0x69, 0x38, 0xb1, 0xb1, 0x6f, - 0xdc, 0x17, 0x56, 0xd3, 0x03, 0x50, 0xdf, 0xa5, 0x12, 0x23, 0xa8, 0xaf, 0x8c, 0x7d, 0x6c, 0x8f, 0x31, 0x39, 0x83, - 0x58, 0xc3, 0x2a, 0x67, 0xa6, 0xfa, 0x46, 0xd8, 0x11, 0x00, 0x37, 0x42, 0x6b, 0x14, 0x04, 0x1e, 0xaf, 0x42, 0x3c, - 0x2f, 0x55, 0xf8, 0xd6, 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, - 0x61, 0xb5, 0x95, 0x65, 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, - 0x5c, 0x0a, 0xcb, 0xa0, 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, - 0x44, 0x23, 0xc4, 0xc3, 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, - 0xa3, 0x04, 0x97, 0xa9, 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, - 0x6a, 0x5f, 0x43, 0x31, 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, - 0x4d, 0xd8, 0xb9, 0x91, 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, - 0xdb, 0x22, 0x73, 0x44, 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, - 0xf1, 0x14, 0x11, 0x01, 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, - 0x81, 0x2c, 0x80, 0xbe, 0xfd, 0x9c, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, - 0x04, 0xbb, 0xba, 0x35, 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, - 0x44, 0x02, 0x32, 0xfb, 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, - 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, - 0x17, 0x7f, 0x5a, 0x75, 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, - 0x6d, 0x29, 0xc9, 0x55, 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, - 0xee, 0x0e, 0xbf, 0xc4, 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, - 0x2a, 0xca, 0x07, 0x13, 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, - 0xac, 0x77, 0xd3, 0x5a, 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, - 0x30, 0x20, 0xda, 0xa5, 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, - 0x9e, 0x01, 0x49, 0x26, 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, - 0xfb, 0x7a, 0xc6, 0x7f, 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, - 0x10, 0x43, 0x54, 0x7b, 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, - 0x43, 0xa3, 0xde, 0xc6, 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, - 0x88, 0x64, 0xbf, 0x3d, 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, - 0xb8, 0x2c, 0x22, 0xcb, 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, - 0xbf, 0x5e, 0xc9, 0x02, 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, - 0xe3, 0xce, 0x9e, 0x80, 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, - 0xb7, 0x80, 0x49, 0xc0, 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, - 0xd6, 0xfe, 0xd5, 0x5d, 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, - 0xa4, 0xb0, 0xe5, 0x31, 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, - 0x0d, 0xee, 0x47, 0x15, 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, - 0x72, 0xbc, 0xed, 0x76, 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, - 0x59, 0xef, 0x25, 0x60, 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, - 0x4b, 0xb2, 0x1f, 0xa6, 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, - 0x41, 0x6f, 0xe9, 0x0d, 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, - 0xfb, 0xfd, 0xde, 0x99, 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, - 0x9b, 0xf0, 0x2c, 0x0f, 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, - 0x93, 0x23, 0xd0, 0x9b, 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, - 0xde, 0xb5, 0x27, 0x63, 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, - 0x7f, 0xb3, 0xf0, 0x86, 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, - 0xd2, 0x53, 0x76, 0x45, 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0xa7, 0x38, 0x0c, 0xe3, 0x61, 0x41, - 0xf6, 0x25, 0xbd, 0xdb, 0x9f, 0xf0, 0x27, 0x64, 0x16, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, - 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0x4e, 0xe8, 0x0d, 0x2b, 0xe8, 0x29, 0x8b, 0x49, 0x74, 0x0d, 0xad, 0x38, 0x9f, - 0x15, 0xd1, 0x0d, 0x3d, 0x65, 0x67, 0xb3, 0x38, 0x3a, 0xa5, 0x27, 0x2c, 0x1f, 0x4e, 0x20, 0xef, 0xe9, 0xf0, 0x86, - 0xec, 0x9f, 0x90, 0x28, 0x3c, 0xd1, 0xbf, 0xef, 0xe8, 0x25, 0x0f, 0x4f, 0xa8, 0x57, 0xcd, 0x09, 0x31, 0xd5, 0x37, - 0x6a, 0x3f, 0x21, 0x91, 0x3f, 0x98, 0x27, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, - 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, 0x06, 0x74, 0xf6, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, - 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, 0xd7, 0xc1, 0x6b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0xeb, 0x7e, 0x1f, 0x22, - 0xdd, 0x17, 0x33, 0x13, 0xdb, 0xcd, 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0xd7, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, - 0xbc, 0x19, 0xbc, 0x7e, 0x7c, 0x47, 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x1b, 0x9a, 0x01, 0xe0, 0xd7, 0xeb, - 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, 0x7d, 0x7d, 0x78, 0x32, 0x1d, 0x0c, 0x5e, 0x9b, 0x6d, 0xf2, 0x96, 0xdd, 0x53, - 0x0a, 0xac, 0xbf, 0xb3, 0x7e, 0xff, 0xed, 0x51, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xd6, 0x45, - 0x55, 0x3b, 0xeb, 0xf7, 0xd7, 0xfd, 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9c, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x8e, 0x22, - 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, 0xac, 0xda, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, - 0xec, 0x9d, 0x6d, 0xb7, 0xa7, 0x8c, 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, - 0xcc, 0xe6, 0x66, 0x69, 0x0f, 0x81, 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0x2f, 0x00, - 0x42, 0x24, 0x59, 0xc8, 0x67, 0x38, 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xbb, - 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, 0xd1, 0xdf, 0x9e, 0x3d, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, - 0x61, 0x17, 0x6b, 0xb5, 0x0f, 0x46, 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0xbe, 0x98, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, - 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, 0x18, 0x4c, 0x2e, 0xd2, 0xcf, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, - 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, 0xdb, 0x6e, 0x2b, 0xff, 0x12, 0xf8, 0x16, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, - 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, - 0xba, 0xdc, 0xe3, 0xea, 0x5f, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, - 0x0c, 0xb7, 0x56, 0x22, 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, - 0x86, 0x07, 0xc9, 0xc4, 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, - 0x24, 0xd3, 0xe4, 0x10, 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, - 0x8e, 0x49, 0xad, 0xef, 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, - 0x78, 0x34, 0x7e, 0x46, 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, - 0x9b, 0x57, 0x3a, 0x36, 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, - 0xea, 0x23, 0x08, 0xb3, 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, - 0xa3, 0x52, 0xa6, 0xba, 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, - 0x10, 0xc0, 0xa3, 0x11, 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, - 0xde, 0x83, 0x30, 0x29, 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, - 0x57, 0x10, 0x27, 0x6c, 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, - 0x25, 0xf7, 0x26, 0xe3, 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, - 0x57, 0xdc, 0x1b, 0x17, 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, - 0x76, 0x3f, 0x31, 0x2b, 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xf6, 0xf2, 0xec, 0xf5, - 0xdb, 0x57, 0xaf, 0xdf, 0xbe, 0xfe, 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, - 0x6a, 0xf1, 0x85, 0xb3, 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, - 0x20, 0xa3, 0x51, 0x21, 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, - 0xdb, 0xd1, 0xd6, 0xac, 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, - 0xc8, 0x75, 0xf0, 0xbe, 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, - 0x13, 0x73, 0x6d, 0x74, 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, - 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, - 0xc2, 0xfc, 0x0c, 0x1b, 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, - 0xce, 0x17, 0xdf, 0x42, 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, - 0x31, 0x1e, 0x77, 0xf7, 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, - 0xbe, 0x5d, 0x24, 0xce, 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, - 0x35, 0xe7, 0x6d, 0x42, 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, - 0x17, 0x43, 0x9a, 0x72, 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, - 0xd7, 0xd9, 0xe6, 0x33, 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, - 0xc4, 0x40, 0x74, 0x01, 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, - 0x31, 0x8b, 0xad, 0x25, 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x84, 0x1d, 0x7d, - 0xf7, 0xb6, 0x01, 0x10, 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, - 0x2b, 0xb4, 0xec, 0x95, 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, - 0xa6, 0x12, 0xd5, 0x23, 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, - 0xee, 0xff, 0xe6, 0x42, 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, - 0x5d, 0xa6, 0x97, 0x5d, 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, - 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, - 0x7c, 0x89, 0x5f, 0x29, 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, - 0xfe, 0x17, 0x18, 0x0d, 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, - 0xeb, 0x67, 0x35, 0xcc, 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, - 0x29, 0x11, 0x83, 0x41, 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, - 0x1a, 0x5b, 0x92, 0x6c, 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, - 0x32, 0xd3, 0xc2, 0xa2, 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, - 0x4d, 0xac, 0xf1, 0x8b, 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, - 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, - 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, - 0xcc, 0xaf, 0x24, 0x19, 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, - 0xdc, 0x18, 0xd6, 0xf4, 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, - 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, - 0x60, 0x1c, 0xa5, 0x83, 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, - 0x0b, 0x68, 0xda, 0x97, 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, - 0x0b, 0xd7, 0xc2, 0x8b, 0xdd, 0x16, 0x0a, 0x4d, 0xb6, 0x0b, 0xf9, 0xff, 0xe3, 0x86, 0x71, 0xdf, 0x5d, 0xc2, 0x2c, - 0xae, 0xeb, 0x6c, 0xb4, 0x2a, 0x64, 0x25, 0xe1, 0x36, 0xa1, 0x44, 0x61, 0xa3, 0x78, 0xb5, 0xca, 0xb5, 0x8b, 0xd8, - 0xbc, 0xa2, 0x00, 0xee, 0x02, 0x71, 0x8a, 0x81, 0x85, 0x36, 0x06, 0x72, 0x9f, 0x78, 0x21, 0x99, 0x55, 0xfb, 0x98, - 0x7b, 0xe4, 0x9f, 0x21, 0x18, 0xa3, 0x8a, 0xa3, 0xf1, 0x4c, 0x61, 0x5d, 0x7c, 0x4e, 0xde, 0xfb, 0x6f, 0x1c, 0x45, - 0xf6, 0x68, 0x06, 0x3d, 0x41, 0xe4, 0x3c, 0xe2, 0xec, 0xc9, 0xe4, 0x65, 0xe0, 0x7e, 0x06, 0x2b, 0xfd, 0x75, 0xb7, - 0x19, 0x6b, 0xdb, 0xa3, 0x7b, 0x61, 0x84, 0xa2, 0x9f, 0xf0, 0x9d, 0xa9, 0x17, 0x70, 0x09, 0xd5, 0xc0, 0xae, 0x2f, - 0x2f, 0x79, 0x09, 0x20, 0x42, 0x99, 0xe8, 0xf7, 0x7b, 0x7f, 0x1a, 0x68, 0xd2, 0x92, 0x17, 0x6f, 0x32, 0x61, 0x9d, - 0x71, 0xa0, 0xa9, 0x40, 0xfd, 0x3f, 0x56, 0xf6, 0x99, 0x8e, 0xc9, 0xcc, 0x7f, 0x1c, 0x4e, 0x48, 0xd4, 0x7c, 0x4d, - 0x3e, 0x73, 0x9a, 0x7e, 0xe6, 0x8a, 0xf6, 0x1f, 0xc8, 0xcc, 0x0d, 0x87, 0x0c, 0xf5, 0x97, 0x8e, 0x79, 0x32, 0x7a, - 0x9d, 0x98, 0x1d, 0x09, 0x56, 0xcd, 0x20, 0x0a, 0x7b, 0x01, 0x0f, 0xea, 0x5a, 0x16, 0x4f, 0x61, 0xf6, 0x41, 0x8d, - 0x28, 0x0e, 0xd9, 0x78, 0x16, 0xca, 0x70, 0x02, 0xf6, 0xbd, 0x93, 0x31, 0xdc, 0x07, 0x64, 0xf8, 0xb1, 0x0a, 0xb1, - 0x73, 0x90, 0xf6, 0xb1, 0x42, 0xc5, 0x04, 0x40, 0x04, 0x42, 0xde, 0x7e, 0x5f, 0xaa, 0x24, 0x7c, 0x5d, 0x62, 0x4a, - 0xa1, 0x3e, 0xf8, 0x4f, 0xa4, 0xea, 0x8e, 0xe9, 0x57, 0xeb, 0xc7, 0x9f, 0x09, 0xc5, 0xa7, 0xbb, 0x94, 0xf8, 0x16, - 0x82, 0x3b, 0x4b, 0xd0, 0x41, 0x54, 0x68, 0xc6, 0xf6, 0x30, 0xbf, 0x2b, 0xee, 0xe7, 0x77, 0xc5, 0xff, 0x3b, 0x7e, - 0x57, 0x3c, 0xc4, 0x18, 0x56, 0x16, 0x1a, 0x7e, 0x16, 0x8c, 0x83, 0xe8, 0x3f, 0xe7, 0x13, 0xef, 0xe5, 0xa9, 0xaf, - 0x32, 0x31, 0xbd, 0x87, 0x69, 0xf6, 0x09, 0x0a, 0xc2, 0x2a, 0xee, 0xd2, 0x93, 0x75, 0x65, 0x6f, 0xad, 0x64, 0x88, - 0x79, 0x1e, 0x60, 0x8d, 0xc2, 0xca, 0x03, 0xba, 0x47, 0xd5, 0x06, 0x71, 0x22, 0x78, 0x18, 0x33, 0x2b, 0x7d, 0xdf, - 0x6e, 0x8d, 0x0a, 0xf3, 0x41, 0x2e, 0x0a, 0xb2, 0x9b, 0x8f, 0x67, 0xe3, 0x28, 0xc4, 0x06, 0xfc, 0xc7, 0x8c, 0x55, - 0x43, 0x36, 0xdf, 0xc9, 0x48, 0xed, 0x98, 0x3c, 0x4d, 0x76, 0x49, 0xef, 0x80, 0x77, 0xc8, 0xcf, 0xeb, 0x8f, 0x61, - 0x21, 0x0d, 0xbf, 0x25, 0x2f, 0xe3, 0x22, 0xab, 0x96, 0x57, 0x59, 0x82, 0x4c, 0x17, 0xbc, 0xf8, 0x62, 0xa6, 0xcb, - 0xfb, 0x58, 0x1f, 0x30, 0x9e, 0x52, 0xbc, 0x6e, 0x88, 0xd2, 0xd7, 0x2d, 0xcf, 0x0a, 0x75, 0x79, 0x52, 0x31, 0xdb, - 0xb3, 0x12, 0x9c, 0x4e, 0xc1, 0x04, 0x5f, 0xff, 0x74, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x0b, 0xb9, 0x32, - 0x58, 0x4e, 0x16, 0xba, 0x13, 0x30, 0x43, 0xa5, 0xc0, 0x0b, 0x14, 0xfc, 0x45, 0x03, 0x23, 0xfa, 0xca, 0xfd, 0x26, - 0x03, 0x83, 0x74, 0x69, 0x4e, 0x84, 0xb1, 0xe3, 0x76, 0x8a, 0xb4, 0x15, 0xe5, 0x8c, 0xb3, 0xf7, 0xea, 0x4a, 0x01, - 0x06, 0x78, 0x9b, 0x9b, 0xe8, 0x3c, 0x41, 0xaf, 0x05, 0xa5, 0xf3, 0x06, 0xee, 0x66, 0x19, 0x19, 0xe1, 0xe2, 0xe3, - 0xca, 0x63, 0xc1, 0x3d, 0xfb, 0x85, 0x58, 0x1a, 0xcd, 0x34, 0x18, 0xb3, 0x79, 0xc1, 0x02, 0x85, 0x0a, 0x14, 0x58, - 0xce, 0xb4, 0xa5, 0x69, 0x35, 0xe4, 0xfb, 0x07, 0x68, 0x6d, 0x5a, 0x0d, 0xf8, 0xfe, 0x41, 0x1d, 0x65, 0x87, 0x90, - 0xe5, 0xc8, 0xcf, 0xa0, 0x5e, 0xd7, 0x91, 0x49, 0x31, 0xd9, 0xfd, 0xfa, 0x52, 0x7f, 0x54, 0x37, 0xe0, 0xfa, 0x01, - 0x08, 0x60, 0x03, 0x70, 0x08, 0x54, 0x83, 0xa5, 0x11, 0xc1, 0xa2, 0x4c, 0xa1, 0x7d, 0x0d, 0xbd, 0x37, 0x1a, 0xfe, - 0x0b, 0xdc, 0x45, 0xe4, 0xca, 0xff, 0x04, 0x81, 0xbf, 0xa2, 0x4c, 0x2b, 0x53, 0xfc, 0x4f, 0xb4, 0x7a, 0x85, 0x72, - 0xd6, 0xb4, 0xe6, 0x83, 0x68, 0x4d, 0x84, 0x6a, 0xc6, 0x10, 0xfc, 0x5b, 0x59, 0xa6, 0x2d, 0x55, 0x95, 0xfa, 0xd0, - 0x78, 0xad, 0x15, 0xce, 0xf2, 0x71, 0xe4, 0xbd, 0xc6, 0xd0, 0xb1, 0x89, 0xb3, 0x94, 0x53, 0xa9, 0xb3, 0x4f, 0xfb, - 0x32, 0x72, 0x80, 0xd3, 0x09, 0x1b, 0x4f, 0x93, 0x43, 0x39, 0x4d, 0x1c, 0x64, 0x7e, 0xce, 0x30, 0xb2, 0xaa, 0x01, - 0x61, 0x51, 0x36, 0x94, 0xb6, 0x00, 0x93, 0x9c, 0x10, 0x32, 0xc5, 0x50, 0x14, 0xf9, 0x48, 0xf7, 0xc3, 0x7a, 0xb3, - 0xba, 0x2f, 0xde, 0x69, 0x80, 0xd3, 0x30, 0x81, 0x40, 0xe0, 0x45, 0x7c, 0x93, 0x89, 0x4b, 0xf0, 0x18, 0x1e, 0xc0, - 0x97, 0xe0, 0x26, 0x97, 0xb2, 0xdf, 0xab, 0x30, 0xc7, 0xb5, 0x05, 0x0c, 0x1a, 0xac, 0x1e, 0x44, 0x87, 0x4b, 0x69, - 0xb3, 0xab, 0x00, 0xb1, 0x31, 0x85, 0x58, 0x16, 0x6c, 0x6d, 0xd9, 0xb3, 0xef, 0x55, 0xd3, 0xd0, 0x3a, 0xe1, 0x58, - 0x5c, 0xe6, 0x10, 0x45, 0x65, 0x10, 0x83, 0x3b, 0x92, 0xc7, 0xe7, 0x3d, 0x12, 0xe1, 0x05, 0x01, 0xb7, 0xb2, 0x58, - 0x86, 0x2b, 0xba, 0x1c, 0xdd, 0xd2, 0xf5, 0xe8, 0x86, 0x8e, 0xe9, 0xe4, 0xef, 0x63, 0xb0, 0xc8, 0xd6, 0xa9, 0x77, - 0x74, 0x3d, 0x5a, 0xd2, 0x6f, 0xc7, 0xf4, 0xe0, 0x6f, 0x60, 0xc2, 0x87, 0x87, 0x09, 0xbd, 0x00, 0xc7, 0x2e, 0x52, - 0xa3, 0xa7, 0xa6, 0x6f, 0x70, 0x58, 0x8d, 0xf2, 0x21, 0x1f, 0xe5, 0x94, 0x8f, 0x8a, 0x61, 0x35, 0x02, 0x4f, 0xc7, - 0x6a, 0xc8, 0x47, 0x15, 0xe5, 0xa3, 0xf3, 0x61, 0x35, 0x3a, 0x27, 0xcd, 0xa6, 0xbf, 0xae, 0xf8, 0x55, 0xc9, 0x52, - 0xd8, 0x16, 0xb0, 0x7c, 0x3d, 0xaf, 0xa8, 0xd4, 0x5f, 0xd5, 0xe6, 0x64, 0xb6, 0x9c, 0xbd, 0xbd, 0xee, 0x72, 0x62, - 0xf1, 0xb8, 0x6d, 0x3a, 0x5c, 0x7d, 0x39, 0x51, 0x27, 0xbd, 0x42, 0x7e, 0x18, 0x4f, 0x85, 0x3a, 0x87, 0xc0, 0x4c, - 0x62, 0x16, 0xc6, 0x0c, 0x9b, 0xa9, 0xd3, 0x40, 0x81, 0x93, 0x8d, 0x3c, 0x17, 0xc5, 0x6c, 0x94, 0x53, 0x78, 0x1f, - 0x13, 0x12, 0x09, 0x38, 0xab, 0x8e, 0xaa, 0x51, 0x01, 0x31, 0x47, 0x58, 0x88, 0x8f, 0xd0, 0x2f, 0xf5, 0x91, 0x87, - 0x04, 0x9e, 0x61, 0x5f, 0x8b, 0x41, 0x0c, 0x47, 0xbc, 0xad, 0xac, 0x9a, 0x85, 0x09, 0x54, 0x56, 0x0d, 0x4b, 0x53, - 0x59, 0x41, 0xb3, 0x51, 0xe5, 0x57, 0x56, 0xe1, 0x18, 0x25, 0x84, 0x44, 0xa5, 0xae, 0x0c, 0xd4, 0x27, 0x09, 0x0b, - 0x4b, 0x5d, 0xd9, 0xb9, 0xfa, 0xe8, 0xdc, 0xaf, 0xec, 0x1c, 0x5c, 0x48, 0x07, 0x89, 0x7f, 0x95, 0xca, 0xd3, 0xf6, - 0x75, 0xb0, 0xb1, 0xaa, 0xe8, 0x86, 0xdf, 0x56, 0x45, 0x1c, 0x95, 0xd4, 0xc5, 0x80, 0xc6, 0x85, 0x11, 0x49, 0xaa, - 0xd7, 0x28, 0xf8, 0x43, 0x82, 0xa8, 0x34, 0x06, 0xaf, 0xce, 0xa4, 0x6b, 0xa5, 0x56, 0x54, 0x0c, 0xca, 0x41, 0x01, - 0xf7, 0xa7, 0xbc, 0xb5, 0x90, 0xbe, 0x87, 0x88, 0xca, 0x50, 0xde, 0xe0, 0x1f, 0x18, 0x3c, 0x99, 0xad, 0xd2, 0x30, - 0x19, 0xdd, 0xd1, 0x78, 0xb4, 0x44, 0x38, 0x18, 0xb6, 0x4e, 0x15, 0xde, 0xfa, 0x05, 0xa4, 0xdf, 0xd2, 0x78, 0x74, - 0x43, 0x53, 0x6b, 0x73, 0x6a, 0xa0, 0xae, 0x7a, 0x63, 0x7a, 0x1b, 0xc1, 0xeb, 0xbb, 0x68, 0x49, 0x61, 0x2b, 0x1d, - 0xe7, 0xd9, 0xa5, 0x88, 0x52, 0x8a, 0x08, 0x84, 0x6b, 0x44, 0x0e, 0x5c, 0x6a, 0xb4, 0xc1, 0xf5, 0x00, 0xca, 0xd0, - 0x70, 0x81, 0xcb, 0x41, 0x3c, 0x5a, 0x7a, 0x64, 0x6a, 0xa9, 0x2f, 0xb2, 0x08, 0x1f, 0xed, 0x6c, 0xb4, 0x14, 0xcf, - 0x88, 0x85, 0x71, 0x05, 0x43, 0xa8, 0x0b, 0x2b, 0x4d, 0x41, 0xd2, 0x05, 0x8e, 0xec, 0x85, 0x45, 0x15, 0x6e, 0xc0, - 0xb4, 0xe8, 0x0e, 0xcc, 0xa3, 0x40, 0xe1, 0xe0, 0x12, 0xa4, 0x9f, 0x50, 0xb6, 0x73, 0x94, 0x26, 0x87, 0x37, 0x41, - 0xe9, 0xce, 0x04, 0x21, 0xed, 0xea, 0x26, 0x5b, 0xd2, 0x37, 0xd8, 0xde, 0xa1, 0x53, 0x51, 0x41, 0xf5, 0xb9, 0x05, - 0x93, 0x25, 0x1b, 0x84, 0x2d, 0x61, 0x7a, 0xa6, 0xd7, 0x80, 0x3d, 0xbd, 0x7f, 0xb0, 0x33, 0xdf, 0xc5, 0xec, 0xd3, - 0x7e, 0x19, 0x8d, 0x95, 0x05, 0x6f, 0x6e, 0x89, 0xdd, 0x92, 0x8d, 0xa7, 0xcb, 0xc3, 0x72, 0xba, 0x44, 0x62, 0x67, - 0xe8, 0x16, 0xe3, 0xf3, 0xe5, 0x82, 0x26, 0x78, 0xb6, 0xb1, 0x6a, 0xbe, 0x34, 0x68, 0x29, 0x29, 0xc3, 0xf5, 0xb6, - 0x44, 0xff, 0x7f, 0x75, 0xf1, 0x4b, 0x01, 0x5e, 0x82, 0xb1, 0x00, 0x10, 0xee, 0xc1, 0xb4, 0x20, 0xb5, 0x51, 0x36, - 0x96, 0x69, 0x98, 0xe2, 0x22, 0x30, 0x29, 0xfd, 0x7e, 0x98, 0xb3, 0x94, 0x78, 0xd0, 0xa1, 0xee, 0xd4, 0x4e, 0x7d, - 0x21, 0x08, 0xf0, 0x48, 0xea, 0x1c, 0x9b, 0xfc, 0x7d, 0x3c, 0x0b, 0xd4, 0x40, 0x04, 0x51, 0x76, 0x88, 0x8f, 0x18, - 0xb8, 0x28, 0xd2, 0x71, 0x3b, 0x5d, 0x11, 0x17, 0xbb, 0xc7, 0x2c, 0xc4, 0x49, 0xc2, 0x5c, 0xb3, 0x6c, 0xc8, 0xaa, - 0x08, 0x13, 0x74, 0x61, 0x60, 0x96, 0x37, 0x64, 0xd5, 0xfe, 0x01, 0x44, 0x6a, 0xb5, 0x65, 0xac, 0xba, 0xca, 0xf8, - 0x16, 0x80, 0xac, 0x19, 0x63, 0x07, 0x7f, 0x1b, 0xcf, 0xd4, 0x37, 0x51, 0xc8, 0x8f, 0x0e, 0xfe, 0x06, 0xc9, 0x87, - 0xdf, 0x22, 0x33, 0x07, 0xc9, 0x8d, 0x82, 0x2e, 0x9b, 0xb3, 0xae, 0xa1, 0x34, 0x71, 0xed, 0x95, 0x7a, 0xed, 0x49, - 0xb3, 0xf6, 0x0a, 0x74, 0xa7, 0x36, 0xbc, 0x87, 0xb2, 0x9d, 0x05, 0x13, 0x74, 0x34, 0xbb, 0x03, 0x1d, 0xbc, 0x53, - 0x04, 0xbd, 0x4c, 0x42, 0xe3, 0x11, 0xaa, 0x8c, 0x7a, 0x61, 0x47, 0x76, 0xb3, 0x2e, 0x99, 0x67, 0xc0, 0x1c, 0xdb, - 0x73, 0x48, 0x0c, 0x73, 0x75, 0x50, 0xa7, 0xac, 0x1c, 0xe6, 0x78, 0x00, 0xaf, 0x99, 0x1c, 0x8a, 0x41, 0xae, 0x51, - 0xbe, 0x2f, 0x58, 0x31, 0x2c, 0x07, 0xb9, 0xe6, 0x66, 0xa6, 0xcd, 0xd8, 0xb4, 0x89, 0x0e, 0xcf, 0xbc, 0x62, 0x47, - 0xab, 0x1e, 0xf0, 0xb1, 0xe0, 0xc9, 0xec, 0x7b, 0x3e, 0xbe, 0x01, 0x4e, 0x66, 0x73, 0x1b, 0x2d, 0xe9, 0x5d, 0x94, - 0xd2, 0x9b, 0x68, 0x4d, 0x97, 0xd1, 0x85, 0x31, 0x31, 0x4e, 0x6a, 0x38, 0x07, 0xa0, 0x55, 0x00, 0x89, 0xa7, 0x7e, - 0xbd, 0xe7, 0x49, 0x15, 0x2e, 0x69, 0x0a, 0x6e, 0xc3, 0xbe, 0x7d, 0xe6, 0x95, 0x2f, 0x91, 0xda, 0x20, 0xc6, 0x9a, - 0x35, 0x54, 0xdc, 0x78, 0xeb, 0x3e, 0x12, 0x35, 0xec, 0x5c, 0x17, 0x9b, 0xa8, 0x1a, 0x4e, 0xa6, 0x25, 0x20, 0xb6, - 0x96, 0xc3, 0xa1, 0x3b, 0x42, 0x76, 0x8f, 0x1f, 0x1d, 0xe8, 0xb9, 0x27, 0x2d, 0xb6, 0x6d, 0xcb, 0x1f, 0x18, 0xc2, - 0x94, 0x7e, 0xfe, 0xc8, 0x07, 0xc4, 0x8a, 0x4b, 0x38, 0x1b, 0x81, 0x3a, 0x5a, 0xa1, 0xd3, 0xef, 0x55, 0x58, 0xe8, - 0x03, 0x7c, 0x73, 0x1b, 0x25, 0xf4, 0x2e, 0xca, 0x3d, 0xb2, 0xb6, 0xac, 0x99, 0x9c, 0x9e, 0x65, 0x21, 0x6f, 0x1f, - 0xe8, 0xe5, 0x02, 0x40, 0xb4, 0x06, 0xb1, 0x2f, 0x75, 0x3d, 0x00, 0xa7, 0x21, 0x34, 0x09, 0x8d, 0xe0, 0xaa, 0x82, - 0x30, 0x02, 0xae, 0x24, 0xfc, 0x0d, 0x26, 0x2a, 0xf0, 0x05, 0xb8, 0xc8, 0xa4, 0x69, 0xce, 0x83, 0xda, 0x1f, 0xc9, - 0xd3, 0xa2, 0xed, 0xed, 0x0a, 0xa3, 0x09, 0xc6, 0x9e, 0x68, 0x9f, 0x47, 0xca, 0x51, 0x5c, 0x24, 0x61, 0x36, 0xba, - 0x55, 0xe7, 0x39, 0xcd, 0x46, 0x77, 0xfa, 0x57, 0x45, 0xc7, 0xf4, 0x3b, 0x1d, 0xd0, 0x46, 0x49, 0xdf, 0x3a, 0xce, - 0x06, 0xb4, 0x5e, 0x2c, 0x8d, 0xff, 0xb5, 0x1c, 0xdd, 0x52, 0x39, 0xba, 0xf3, 0x2d, 0xa9, 0x26, 0xd3, 0xe2, 0x50, - 0xa0, 0x21, 0x55, 0xe7, 0xf7, 0x05, 0xf0, 0x73, 0xa5, 0xf1, 0x9d, 0x36, 0xdf, 0x7b, 0xed, 0x3f, 0xef, 0xe4, 0x09, - 0x14, 0x4b, 0x54, 0xb0, 0x6a, 0x04, 0x76, 0xec, 0xeb, 0x3c, 0x2e, 0xcc, 0x28, 0xc5, 0xd4, 0x9a, 0xf4, 0x63, 0xe0, - 0x8a, 0x69, 0xaf, 0x00, 0x57, 0xcb, 0xed, 0x56, 0xc5, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, - 0x36, 0xdc, 0x03, 0x62, 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, - 0x9d, 0xc7, 0x43, 0x9f, 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, - 0x3c, 0xd7, 0x5f, 0x69, 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, - 0x6e, 0x94, 0x79, 0x24, 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, - 0x3d, 0xf2, 0xa0, 0x9c, 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, - 0x12, 0x73, 0x27, 0x51, 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, - 0x13, 0x57, 0xe1, 0x5a, 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, - 0x1a, 0x56, 0x9a, 0x80, 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, - 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, - 0x02, 0x33, 0x57, 0x72, 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, - 0x5a, 0x62, 0x42, 0xb4, 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, - 0xda, 0x55, 0x20, 0xb4, 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, - 0xb2, 0x69, 0xc8, 0x5c, 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, - 0x2d, 0x3f, 0x82, 0x17, 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, - 0xb9, 0xdd, 0x96, 0x68, 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, - 0x2b, 0xd0, 0xf7, 0xf8, 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, - 0xfc, 0x4a, 0x76, 0xd6, 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, - 0x2d, 0x85, 0x05, 0xc7, 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, - 0xb2, 0x33, 0xd7, 0x07, 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, - 0xe1, 0xce, 0x3c, 0x6a, 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, - 0xf7, 0x7d, 0x58, 0x3d, 0xe6, 0x83, 0x5f, 0x70, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, - 0x53, 0xbe, 0xd0, 0xad, 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, - 0x18, 0xd7, 0xc0, 0x6d, 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, - 0x31, 0xf7, 0xa5, 0x6b, 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, - 0xe7, 0x91, 0xf9, 0x62, 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, - 0x43, 0x2f, 0x03, 0x17, 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, - 0xa8, 0x10, 0xac, 0xeb, 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x63, 0x20, - 0x9c, 0x5b, 0xa2, 0x67, 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, - 0x5f, 0xf0, 0x5a, 0x0a, 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, - 0x8a, 0xde, 0xbf, 0xe6, 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, - 0x4a, 0x50, 0xc9, 0x5a, 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, - 0x7c, 0x8e, 0x7e, 0x98, 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, - 0xc6, 0xf0, 0x60, 0x36, 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, - 0x7d, 0x89, 0x36, 0xaf, 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, - 0xab, 0x96, 0x8a, 0x06, 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, - 0x59, 0xda, 0xa6, 0xe8, 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, - 0x51, 0x6a, 0x37, 0x48, 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, - 0x1d, 0x47, 0x43, 0xbf, 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, - 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, - 0x4d, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, - 0xe9, 0xb9, 0x6e, 0xe7, 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, - 0xf5, 0x98, 0x15, 0xc3, 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, - 0xb4, 0x0b, 0xa4, 0x6d, 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, - 0xd8, 0x88, 0x7a, 0x7c, 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, - 0x5a, 0xb5, 0xb9, 0xfb, 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, - 0x5a, 0xb0, 0x9c, 0x75, 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, - 0x92, 0x67, 0x9a, 0xfe, 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, - 0x12, 0x57, 0xbe, 0xc2, 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, - 0x6e, 0x92, 0x1b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, - 0x28, 0x73, 0x13, 0x73, 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, - 0x3a, 0xd1, 0x5c, 0x86, 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, - 0xdc, 0xcc, 0x52, 0xb3, 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, - 0x2c, 0x0d, 0xd7, 0x28, 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, - 0x90, 0x8d, 0xd2, 0x38, 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, - 0x15, 0xdd, 0x96, 0x98, 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0xc5, 0xd0, 0xde, 0x1d, - 0x81, 0x51, 0xe5, 0x04, 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, - 0x24, 0x10, 0x18, 0x15, 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, - 0xb7, 0x88, 0x8e, 0xe9, 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, - 0x9e, 0xba, 0x14, 0xfd, 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, - 0xb2, 0x2a, 0x07, 0xed, 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, - 0x6f, 0xc4, 0xa8, 0xbd, 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, - 0x9f, 0x39, 0xb2, 0x33, 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, - 0xda, 0xcf, 0x9d, 0xe9, 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, - 0x35, 0xd5, 0xd1, 0x01, 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, - 0x53, 0x5b, 0x55, 0xc1, 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, - 0xa7, 0xa6, 0x3f, 0x68, 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, - 0x57, 0x95, 0x0f, 0xa0, 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, - 0x58, 0x4f, 0xe4, 0x79, 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, - 0x68, 0x2e, 0xa3, 0x09, 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, - 0x15, 0xdf, 0xc9, 0xf4, 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, - 0x73, 0xf0, 0xb4, 0xa6, 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, - 0xf9, 0x47, 0x97, 0x69, 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, - 0xa2, 0x0e, 0xbe, 0x39, 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, - 0x71, 0x7f, 0xfb, 0xfb, 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, - 0x7f, 0xab, 0x6b, 0xfa, 0x2b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, - 0x06, 0x90, 0x4b, 0xab, 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, - 0xe3, 0xac, 0x02, 0x38, 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x07, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, - 0x46, 0x45, 0x06, 0x3a, 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, - 0xc1, 0x44, 0x58, 0x10, 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, - 0x10, 0x44, 0x77, 0x91, 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, - 0x10, 0x14, 0xff, 0x86, 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, - 0x82, 0x06, 0xba, 0xed, 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, - 0xf5, 0x5f, 0x0d, 0xeb, 0xe8, 0xc2, 0x8f, 0xfe, 0x6a, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, - 0x0c, 0xa4, 0x8b, 0xe3, 0x76, 0x9c, 0xcd, 0x7f, 0x9d, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, - 0xd2, 0xce, 0x07, 0x6f, 0x8e, 0x7f, 0x3f, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, - 0x0a, 0xee, 0xae, 0xe6, 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, - 0x40, 0x0e, 0x99, 0x85, 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, - 0x6f, 0xb9, 0x0d, 0xb2, 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, - 0xce, 0xe6, 0xc5, 0xc2, 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, - 0xa6, 0x51, 0x85, 0x6b, 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, - 0x03, 0x3a, 0x98, 0x50, 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x75, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, - 0x54, 0x5e, 0xc9, 0x6b, 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, - 0x93, 0x4b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, - 0x7c, 0x2e, 0x16, 0x11, 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, - 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, - 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, - 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, - 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, - 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, - 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, - 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, - 0xb3, 0x5c, 0x1d, 0x7a, 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, - 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, 0x42, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, - 0x91, 0x9e, 0x67, 0x9f, 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, - 0x3f, 0x57, 0x1c, 0xaf, 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, - 0x97, 0x3c, 0xac, 0x46, 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, - 0xff, 0x0a, 0x99, 0x8c, 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, - 0x93, 0x66, 0xa1, 0x4c, 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, - 0xf7, 0xd0, 0xe1, 0xff, 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, - 0x7d, 0x33, 0xf1, 0x0b, 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, - 0xc3, 0x76, 0x8b, 0x0b, 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, - 0x67, 0x6a, 0x98, 0x93, 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, - 0xd0, 0x5e, 0xec, 0x67, 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, - 0x1e, 0x83, 0xf7, 0x06, 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, - 0xb7, 0x95, 0xf1, 0xb7, 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, - 0x5a, 0x60, 0xf8, 0xec, 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, - 0xac, 0x01, 0x88, 0xe4, 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, - 0xeb, 0x60, 0xe2, 0x4c, 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, - 0xa9, 0x42, 0xa9, 0x36, 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, - 0x67, 0xf7, 0xb9, 0xed, 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, - 0x15, 0x63, 0x8c, 0xde, 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, - 0xc5, 0xf5, 0xf2, 0x4b, 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, - 0x5d, 0x69, 0x64, 0x20, 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, - 0x6d, 0x09, 0x1d, 0xb2, 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, - 0x0b, 0x67, 0x59, 0x1c, 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, - 0x81, 0xdd, 0xc9, 0xe9, 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, - 0x42, 0x9b, 0xeb, 0xfa, 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, - 0xfa, 0x40, 0x39, 0x96, 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, - 0xb1, 0x00, 0x58, 0xe8, 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, - 0xee, 0x8a, 0x65, 0x58, 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, - 0x6a, 0x0c, 0x20, 0x72, 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, - 0x5e, 0x4f, 0x4a, 0x02, 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, - 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, - 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, - 0xfb, 0xbf, 0x99, 0x2c, 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, - 0x82, 0xc0, 0x70, 0xc3, 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, - 0x1a, 0x33, 0x3a, 0x78, 0x06, 0xa0, 0xb0, 0x10, 0x10, 0x7d, 0x0c, 0x32, 0x5a, 0x01, 0xbf, 0x85, 0xfa, 0xdd, 0x3a, - 0xf1, 0x7d, 0xe8, 0x57, 0x41, 0x2f, 0x62, 0x60, 0x38, 0xa2, 0xc9, 0x7e, 0xc8, 0x07, 0x93, 0x01, 0x68, 0x4b, 0xbc, - 0xdd, 0xd7, 0xd2, 0x8a, 0x9b, 0xd3, 0xa5, 0xd3, 0xfd, 0x93, 0x36, 0x41, 0x12, 0xa9, 0x64, 0xa5, 0x22, 0x06, 0x10, - 0xca, 0x52, 0x6d, 0x93, 0x25, 0x58, 0x56, 0x98, 0x25, 0xcd, 0x0d, 0x4a, 0xe2, 0xee, 0x66, 0xe0, 0x18, 0x35, 0xeb, - 0x38, 0x2c, 0x5b, 0x6e, 0xd4, 0x00, 0x9f, 0x93, 0xb0, 0xc2, 0xde, 0x70, 0x66, 0xd2, 0x3b, 0xd3, 0xe1, 0xea, 0x98, - 0xb3, 0x37, 0x1c, 0xc1, 0x38, 0x12, 0xbc, 0xf1, 0xd0, 0x25, 0xd3, 0x50, 0x91, 0x29, 0xe3, 0x60, 0xda, 0x03, 0xdc, - 0x7b, 0x0e, 0xc6, 0x61, 0x6c, 0x50, 0x59, 0x52, 0x9f, 0x7a, 0x77, 0x21, 0x10, 0xa4, 0xb5, 0x5e, 0xe6, 0x33, 0x3c, - 0x3d, 0x23, 0x94, 0xfd, 0x21, 0x87, 0x2f, 0xc0, 0x8e, 0x82, 0x1c, 0x4d, 0xf8, 0xb3, 0xc7, 0xbb, 0x81, 0xaa, 0xf8, - 0x20, 0xd8, 0x8b, 0x45, 0xba, 0x17, 0x0c, 0x04, 0xfc, 0x2a, 0xf8, 0x5e, 0x25, 0xe5, 0xde, 0x45, 0x5c, 0xec, 0xc5, - 0xab, 0xb8, 0xa8, 0xf6, 0x6e, 0xb2, 0x6a, 0xb9, 0x67, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x7b, 0xc1, - 0xa0, 0x30, 0x53, 0xbb, 0x62, 0x65, 0xe3, 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, - 0xea, 0x9a, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, 0x88, 0xe9, 0x1a, 0xfa, 0x00, 0x3c, 0xf2, 0x9a, 0xc6, 0xb0, 0x04, 0x2e, - 0x06, 0x03, 0xb2, 0x86, 0xc8, 0x05, 0x6b, 0x6a, 0x83, 0x38, 0x84, 0x6b, 0x65, 0xa7, 0xbd, 0x0b, 0xcc, 0xb4, 0xdd, - 0x02, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, 0x1b, 0xea, 0x5f, 0xb0, 0x97, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, - 0xe6, 0xfb, 0x92, 0x1d, 0x0d, 0x54, 0xc4, 0xe1, 0x1d, 0x47, 0x8a, 0x36, 0x2a, 0x97, 0x65, 0x4f, 0x96, 0x0d, 0x5f, - 0x89, 0x2b, 0xee, 0xfc, 0xb8, 0x2a, 0x29, 0xf3, 0x2a, 0x5b, 0x29, 0xf6, 0x6f, 0xc6, 0x35, 0xf7, 0x07, 0xd6, 0x9f, - 0xcd, 0x57, 0x70, 0x6d, 0xf5, 0xde, 0x35, 0xb9, 0x46, 0xe4, 0x2c, 0xa1, 0x5c, 0x52, 0xdb, 0x3c, 0xbc, 0xa5, 0xef, - 0xf3, 0xab, 0x6f, 0x33, 0x9d, 0xc6, 0x67, 0x15, 0x16, 0x2e, 0x44, 0x2b, 0x82, 0x43, 0x43, 0x2e, 0x9a, 0x47, 0x80, - 0xb9, 0xf6, 0xd9, 0x0a, 0x0a, 0x52, 0x9f, 0x55, 0xe8, 0xdd, 0x0a, 0x09, 0xaf, 0x34, 0xbb, 0xf4, 0x30, 0x90, 0x32, - 0x6e, 0x0f, 0x2d, 0x61, 0xd2, 0xf2, 0x22, 0xbc, 0xf7, 0x9a, 0x9b, 0xdc, 0x8b, 0x10, 0xa3, 0x17, 0x79, 0x76, 0x02, - 0xc6, 0xba, 0x4b, 0x76, 0x36, 0x3c, 0xf1, 0x1b, 0x9e, 0xb3, 0x16, 0x8d, 0xa6, 0x4b, 0x96, 0xf4, 0xfb, 0x31, 0x98, - 0x78, 0xa7, 0x2c, 0x87, 0x5f, 0xf9, 0x82, 0xae, 0x19, 0x60, 0x8a, 0xd1, 0x0b, 0x48, 0x48, 0x11, 0x89, 0x64, 0xad, - 0x4e, 0x92, 0xcf, 0x74, 0x17, 0x80, 0xd1, 0x2f, 0x66, 0x69, 0xb4, 0xbc, 0xd7, 0xcc, 0x02, 0xc9, 0x33, 0xf4, 0x5d, - 0x07, 0xdb, 0x1b, 0xfb, 0x20, 0xe5, 0xfc, 0x50, 0x4c, 0x07, 0x03, 0x4e, 0x34, 0xdc, 0x78, 0xa9, 0xc4, 0xb5, 0xba, - 0xc5, 0x1d, 0xc3, 0x58, 0xea, 0xdb, 0x22, 0x06, 0x07, 0xec, 0xa2, 0x95, 0xdd, 0x3e, 0xc0, 0xbe, 0x72, 0xbc, 0x4b, - 0x95, 0xdd, 0xe9, 0x31, 0xd3, 0x5c, 0xb6, 0x9a, 0x74, 0x52, 0x71, 0x3f, 0x91, 0x6f, 0x72, 0x07, 0x5d, 0x2e, 0xc7, - 0x9a, 0xb7, 0x1c, 0x80, 0x8a, 0x7e, 0xa4, 0xa8, 0xee, 0x17, 0x38, 0xc2, 0x3c, 0x58, 0xb7, 0xf9, 0x64, 0xdf, 0x14, - 0x38, 0x44, 0x9e, 0xb4, 0xd1, 0x14, 0xd0, 0xbd, 0x8b, 0xc7, 0x5d, 0xfd, 0xb6, 0x74, 0x17, 0x28, 0xd1, 0x4e, 0xc5, - 0x0d, 0x3f, 0x26, 0xea, 0x74, 0xa6, 0x0d, 0xa1, 0x7f, 0x65, 0xc4, 0xfd, 0xa5, 0x71, 0x15, 0x6f, 0x7a, 0x97, 0xcf, - 0x38, 0xd4, 0xd9, 0x0d, 0xa1, 0x00, 0x5c, 0xb5, 0xa7, 0x53, 0x37, 0x86, 0xf4, 0x4a, 0x89, 0x6e, 0x83, 0x83, 0xdd, - 0xeb, 0x33, 0x8e, 0xa2, 0x1f, 0xa3, 0x46, 0xbe, 0x89, 0xc4, 0x63, 0x39, 0x88, 0x1f, 0x17, 0x74, 0x19, 0x89, 0xc7, - 0xc5, 0x20, 0x7e, 0x2c, 0xeb, 0x7a, 0xf7, 0x5c, 0xb9, 0xbf, 0x8f, 0xc8, 0xb3, 0xee, 0xec, 0xa5, 0x12, 0x36, 0x06, - 0x9e, 0x5d, 0x0b, 0x08, 0xa7, 0xe0, 0x89, 0x6c, 0x2d, 0x7d, 0xe8, 0xdc, 0xee, 0x63, 0xcb, 0x24, 0x41, 0xd0, 0xf3, - 0x36, 0x9b, 0x44, 0xb1, 0xb3, 0xcd, 0xa3, 0x0f, 0xa7, 0x40, 0x42, 0xb7, 0xdb, 0x66, 0x5d, 0xad, 0x01, 0xc5, 0x34, - 0x1c, 0xf3, 0xfd, 0x62, 0x74, 0xe3, 0xbb, 0xeb, 0xef, 0x17, 0xa3, 0x25, 0x19, 0x4e, 0xcc, 0xe4, 0xc7, 0x47, 0xe3, - 0x59, 0x1c, 0x4d, 0xea, 0x8e, 0xd3, 0x42, 0xe3, 0x9f, 0x7a, 0xb7, 0x50, 0x04, 0x4e, 0xc5, 0x08, 0x8e, 0x9c, 0x0a, - 0xe5, 0xa4, 0xd4, 0xc0, 0xf0, 0xdf, 0xab, 0x76, 0xb4, 0x69, 0x6f, 0xe2, 0x2a, 0x59, 0x66, 0xe2, 0x52, 0x87, 0x0f, - 0xd7, 0xd1, 0xc5, 0x6d, 0x40, 0x3b, 0xef, 0x32, 0xed, 0xf8, 0x75, 0xd2, 0xa0, 0x27, 0xae, 0x66, 0x06, 0xdc, 0xba, - 0x1f, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, 0xc4, 0xdc, 0xfe, 0x4d, 0xd9, 0xfc, 0x2a, 0xda, 0xe7, 0xc8, 0x48, - 0xd9, 0x26, 0x23, 0x15, 0x18, 0x61, 0x4a, 0x91, 0xc4, 0x55, 0x08, 0x81, 0xec, 0xbf, 0xa4, 0xb8, 0x16, 0x4b, 0xef, - 0x35, 0x08, 0x13, 0x6c, 0x17, 0xb4, 0x5f, 0xdd, 0xce, 0x6d, 0xa5, 0xc5, 0x1e, 0xa9, 0xef, 0x73, 0x67, 0xbb, 0xa2, - 0xc9, 0xdf, 0x97, 0x0d, 0x68, 0x03, 0x88, 0xf2, 0xbe, 0x3e, 0x2a, 0x81, 0x93, 0x11, 0x37, 0x94, 0x18, 0xbd, 0xa0, - 0xab, 0x13, 0xb9, 0x67, 0xa7, 0xe6, 0x4d, 0xc5, 0x4c, 0xc5, 0x95, 0x6f, 0xf6, 0xcc, 0x7f, 0x30, 0x14, 0x54, 0x80, - 0x81, 0xb7, 0x39, 0xe3, 0xd1, 0x81, 0xee, 0xc6, 0xe8, 0xb4, 0x60, 0xb3, 0xa0, 0x2e, 0xeb, 0xa6, 0x8d, 0x07, 0x8d, - 0x38, 0x28, 0x8a, 0x55, 0xa1, 0x46, 0xc2, 0x13, 0x81, 0x80, 0x29, 0xbb, 0xe2, 0x91, 0x11, 0xd4, 0xf4, 0x26, 0x14, - 0x36, 0x14, 0xfc, 0x55, 0xa2, 0x9a, 0xde, 0x84, 0x36, 0x99, 0x38, 0xcd, 0x20, 0x82, 0x19, 0xb1, 0xdd, 0x6f, 0x01, - 0x6d, 0x6e, 0xcd, 0x68, 0x53, 0xd7, 0x56, 0x5b, 0x85, 0x5c, 0x52, 0xa4, 0x2c, 0xff, 0x9d, 0x9a, 0x0a, 0x4a, 0x6a, - 0xb9, 0xe8, 0x4d, 0x9a, 0x2e, 0x7a, 0x3c, 0x33, 0x92, 0x40, 0xe5, 0x96, 0x3b, 0x46, 0x7f, 0x08, 0x0b, 0x3c, 0x62, - 0xe2, 0xc4, 0x82, 0xb9, 0xd5, 0x11, 0xcb, 0xe6, 0x62, 0x31, 0x5a, 0x49, 0x08, 0x1b, 0x7c, 0xc8, 0xb2, 0x79, 0xa9, - 0x1f, 0x42, 0x5f, 0x58, 0x7a, 0x02, 0x76, 0xb1, 0xc1, 0x4a, 0x96, 0x01, 0xf8, 0x5e, 0xd0, 0xcd, 0x4a, 0x96, 0x91, - 0x54, 0xdd, 0x8f, 0x6b, 0x2c, 0x41, 0xa5, 0x15, 0x2a, 0x2d, 0xa9, 0xb1, 0x20, 0xf0, 0x55, 0xd5, 0xe5, 0x43, 0xb2, - 0xab, 0x40, 0x3d, 0x75, 0xd4, 0x80, 0x53, 0xa0, 0xaa, 0xc0, 0x82, 0x24, 0xa8, 0x0c, 0x5d, 0x15, 0x98, 0x56, 0x60, - 0x9a, 0xa9, 0xc2, 0x45, 0x99, 0x1d, 0x4a, 0xb3, 0x5e, 0xf2, 0x59, 0x3c, 0x08, 0x93, 0x61, 0x4c, 0x1e, 0x23, 0xd4, - 0xfe, 0x7e, 0x1e, 0xc5, 0x5a, 0x2e, 0xb9, 0x72, 0x7e, 0xf1, 0x37, 0x9f, 0xb1, 0xd7, 0x3d, 0xc3, 0x60, 0x01, 0xce, - 0xd2, 0xf6, 0x2a, 0x13, 0xef, 0x64, 0x2b, 0x38, 0x0e, 0x66, 0x51, 0x0e, 0xab, 0x9e, 0x1c, 0xd1, 0x5c, 0xe4, 0xda, - 0xbb, 0x08, 0x91, 0x83, 0xcc, 0x1e, 0x03, 0xec, 0x46, 0xf8, 0x3a, 0xb4, 0x36, 0xb7, 0xba, 0x42, 0xfc, 0x8d, 0x12, - 0x89, 0x9f, 0xa5, 0xfc, 0xb8, 0x5e, 0xa9, 0x5c, 0x95, 0xc1, 0x63, 0xd5, 0xcd, 0xe0, 0x99, 0xf6, 0x3d, 0xd6, 0xfe, - 0xad, 0xed, 0xe6, 0x78, 0xef, 0xc1, 0x83, 0xd6, 0xff, 0xd6, 0x93, 0x10, 0xda, 0x2b, 0x27, 0xa9, 0x3b, 0x6a, 0xf4, - 0xcc, 0x64, 0x8d, 0xa8, 0x84, 0xa9, 0xdd, 0xa9, 0x1c, 0x03, 0x35, 0x1d, 0xc0, 0xb5, 0x44, 0x4d, 0xd0, 0x93, 0x82, - 0x8d, 0xe1, 0x88, 0xb3, 0x38, 0x68, 0x87, 0x31, 0x8a, 0x97, 0x73, 0x25, 0x5e, 0xce, 0x8f, 0x18, 0x07, 0x68, 0x2d, - 0x40, 0xaa, 0xd7, 0xb0, 0x9f, 0xb9, 0x82, 0x05, 0x36, 0x77, 0xbe, 0x03, 0x0b, 0x64, 0x88, 0x93, 0xcd, 0x71, 0xb2, - 0xc7, 0xb5, 0x9e, 0x7b, 0x81, 0x8f, 0x93, 0x7a, 0xe1, 0xd5, 0x55, 0xb6, 0xeb, 0x5a, 0xb2, 0x72, 0x5e, 0x0c, 0x26, - 0x10, 0x94, 0xa5, 0x9c, 0x17, 0xc3, 0xc9, 0x82, 0xe6, 0xf0, 0x63, 0xd1, 0x40, 0x87, 0x58, 0x0e, 0x12, 0xb8, 0x74, - 0xf6, 0x18, 0xf0, 0x86, 0x52, 0x8b, 0xbb, 0xb1, 0x8e, 0x1c, 0xeb, 0x28, 0xf6, 0xc3, 0x18, 0x70, 0x65, 0x9d, 0xc0, - 0xfb, 0xfe, 0xeb, 0x63, 0x13, 0x90, 0x55, 0xbb, 0xc2, 0xab, 0x51, 0xee, 0xba, 0xd2, 0xe8, 0x4b, 0x4a, 0x4f, 0x78, - 0xc1, 0x53, 0xc9, 0x76, 0xdb, 0x33, 0x70, 0xb6, 0xc4, 0x43, 0xe2, 0x1d, 0x23, 0x7a, 0x31, 0x6d, 0x64, 0xe6, 0x04, - 0xce, 0x6c, 0x77, 0xd9, 0xc6, 0xfc, 0xd8, 0x01, 0x0e, 0x16, 0x41, 0x48, 0xdc, 0x10, 0x86, 0x89, 0x1d, 0x95, 0x43, - 0x2d, 0x84, 0xeb, 0x5a, 0x78, 0x1d, 0xa7, 0x65, 0x0c, 0x2e, 0xd2, 0xda, 0x36, 0xf1, 0x1e, 0xba, 0xee, 0xf9, 0x31, - 0xb7, 0x3a, 0x46, 0x5b, 0x48, 0xbf, 0x1d, 0x9d, 0xde, 0x73, 0x18, 0x80, 0xa6, 0x07, 0xb3, 0xaa, 0x7d, 0x26, 0x71, - 0x73, 0xda, 0x09, 0x42, 0x22, 0x10, 0x45, 0xe9, 0x8c, 0x30, 0xfd, 0x3b, 0xcd, 0x65, 0x15, 0xad, 0x1e, 0xe4, 0x99, - 0x43, 0x9e, 0x85, 0xde, 0xf6, 0xa0, 0x55, 0x73, 0x37, 0x18, 0x27, 0x6e, 0xb7, 0x77, 0xfe, 0xdf, 0xb2, 0xae, 0xad, - 0xd6, 0x88, 0xc7, 0xed, 0xea, 0x07, 0x8d, 0xbd, 0xda, 0x53, 0x31, 0x60, 0x56, 0xd2, 0x3b, 0xa3, 0x4a, 0x5e, 0x64, - 0xbc, 0xc4, 0x93, 0x6a, 0xd5, 0xf0, 0xf1, 0xbe, 0xc9, 0x46, 0xe6, 0x81, 0x4c, 0x01, 0xf1, 0xfc, 0x26, 0x35, 0xea, - 0xe3, 0x14, 0x25, 0xe0, 0xef, 0x74, 0x7c, 0x23, 0xfa, 0xd1, 0xbe, 0xb8, 0xe4, 0xd5, 0xc9, 0x8d, 0x30, 0x2f, 0x5e, - 0x58, 0x9d, 0x3f, 0x7d, 0x53, 0xf8, 0xd0, 0xe1, 0xa8, 0xbd, 0x83, 0x22, 0x4b, 0x26, 0x8e, 0x26, 0x46, 0xd6, 0x26, - 0x66, 0x1f, 0x15, 0x5c, 0x4c, 0x54, 0xa1, 0x67, 0x9d, 0x3d, 0x61, 0x0a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x16, - 0x0c, 0xd4, 0x69, 0x4a, 0x88, 0x1e, 0x8a, 0x19, 0xc6, 0x2b, 0x06, 0x50, 0x98, 0x42, 0x81, 0x28, 0x3a, 0xfb, 0x70, - 0xa0, 0x09, 0xfd, 0xfe, 0x4d, 0xaa, 0x33, 0xd0, 0xb2, 0x9e, 0x4a, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, - 0x2e, 0x69, 0x99, 0xd1, 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, - 0x21, 0xec, 0xff, 0x6a, 0xd0, 0xf5, 0x56, 0xac, 0x35, 0xb4, 0x3b, 0x41, 0x46, 0x68, 0xbe, 0xd0, 0x41, 0xc8, 0x50, - 0x39, 0x09, 0x5d, 0xab, 0x34, 0x5e, 0x81, 0x4b, 0xa6, 0xd9, 0x68, 0x19, 0x97, 0x61, 0x60, 0xbf, 0x0a, 0x2c, 0x26, - 0x07, 0x26, 0x9d, 0xae, 0xcf, 0x9f, 0xcb, 0xab, 0x95, 0x14, 0x5c, 0x54, 0x0a, 0xa2, 0xdf, 0xe0, 0xbe, 0x9b, 0xb8, - 0xea, 0xac, 0x59, 0x2b, 0x7d, 0xe8, 0x5b, 0x9f, 0xb5, 0x71, 0x5f, 0x18, 0x1c, 0x83, 0x9d, 0x8f, 0x88, 0x81, 0x34, - 0xa8, 0x74, 0x8b, 0x43, 0x13, 0xa0, 0x4b, 0x87, 0x14, 0xb2, 0x64, 0x2a, 0x53, 0x25, 0xa8, 0xf8, 0xc6, 0xef, 0xa5, - 0xac, 0x46, 0x7f, 0xad, 0x79, 0x71, 0x77, 0xca, 0x73, 0x8e, 0x63, 0x14, 0x24, 0xb1, 0xb8, 0x8e, 0xcb, 0x80, 0xf8, - 0x96, 0x57, 0xc1, 0x41, 0x6a, 0xc2, 0xc6, 0xec, 0x54, 0x8d, 0x5a, 0x2f, 0x89, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, - 0x13, 0x51, 0x05, 0x7d, 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, - 0x6e, 0x98, 0x08, 0x41, 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, - 0xf1, 0x39, 0x73, 0xa1, 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, - 0xd9, 0x91, 0x76, 0x69, 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, - 0x2a, 0xce, 0xc4, 0x71, 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, - 0x61, 0x30, 0x35, 0x15, 0xf7, 0xd8, 0x19, 0x5c, 0x54, 0x7f, 0x44, 0x4b, 0x89, 0xb1, 0x50, 0x75, 0xf1, 0xf1, 0x79, - 0x29, 0xf3, 0x75, 0x05, 0xda, 0xdd, 0x8b, 0x2a, 0x3a, 0x78, 0xba, 0xba, 0x9d, 0xaa, 0x1b, 0x4c, 0xf4, 0xf4, 0x60, - 0x75, 0xdb, 0xcb, 0xae, 0x56, 0xb2, 0xa8, 0x62, 0x51, 0x4d, 0x15, 0x22, 0x59, 0x12, 0xe7, 0x49, 0x38, 0x19, 0x8f, - 0xbf, 0xda, 0x1b, 0xee, 0x41, 0x06, 0x32, 0xfd, 0x34, 0x54, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x95, 0xea, 0x6e, - 0x17, 0x8d, 0x26, 0x35, 0xd6, 0x33, 0x4c, 0xf4, 0xcc, 0x8c, 0xf8, 0xed, 0x2a, 0x16, 0x29, 0xc4, 0xaf, 0xd3, 0xc5, - 0x1f, 0x3c, 0x1d, 0x37, 0xca, 0xb7, 0x9f, 0x3e, 0xab, 0xff, 0xa8, 0x4d, 0x58, 0x6b, 0xd3, 0xee, 0xe7, 0x7f, 0x1c, - 0xaa, 0xf9, 0x3e, 0x3a, 0xdc, 0xd7, 0x3f, 0xfe, 0xa8, 0xeb, 0xe9, 0x9b, 0x22, 0x9c, 0xff, 0x33, 0x54, 0xf3, 0x79, - 0x5c, 0x14, 0xf1, 0x5d, 0x0d, 0x91, 0x3c, 0x85, 0xf3, 0x26, 0xa1, 0xde, 0x36, 0xa0, 0x07, 0x64, 0x7a, 0x21, 0x18, - 0x7c, 0xf3, 0xbe, 0x0a, 0x03, 0x5e, 0xae, 0x86, 0x5c, 0x54, 0x59, 0x75, 0x37, 0xc4, 0x3c, 0x01, 0x7e, 0x6a, 0x78, - 0xb3, 0xe7, 0x85, 0x21, 0x36, 0x17, 0x05, 0xe7, 0x9f, 0x78, 0xa8, 0x8c, 0xa3, 0xc7, 0x68, 0x1c, 0x3d, 0xa6, 0x6a, - 0x30, 0x26, 0xdf, 0x50, 0xdd, 0x99, 0xc9, 0x37, 0x60, 0x82, 0x94, 0xb5, 0xbf, 0x51, 0xc6, 0x89, 0xd1, 0x98, 0x5e, - 0xbf, 0xca, 0xb3, 0x15, 0x30, 0xc1, 0x4b, 0xfd, 0xa3, 0x26, 0xf4, 0x3d, 0x6f, 0x67, 0x1f, 0x8d, 0x46, 0xcf, 0x0b, - 0x3a, 0x1a, 0x8d, 0x3e, 0x66, 0x35, 0xa1, 0x2b, 0xd1, 0xf1, 0xfe, 0x3d, 0xa7, 0xe7, 0x32, 0xbd, 0x8b, 0x82, 0x80, - 0x2e, 0xb3, 0x34, 0xe5, 0x42, 0x95, 0x75, 0x9a, 0xb6, 0xf3, 0xaa, 0x16, 0x22, 0xf0, 0x8f, 0x6e, 0x23, 0x42, 0x10, - 0x11, 0x7a, 0xb2, 0xd3, 0xb3, 0xd1, 0x68, 0x74, 0x9a, 0x9a, 0x6a, 0x1d, 0x43, 0xfe, 0x06, 0xcd, 0x07, 0x9c, 0x5d, - 0x3e, 0x58, 0xdf, 0x98, 0x68, 0x27, 0xfb, 0xff, 0x3d, 0x9c, 0xcd, 0xc7, 0xc3, 0x6f, 0x47, 0x8b, 0xc7, 0xfb, 0x34, - 0x08, 0x7c, 0xd0, 0xea, 0x50, 0x5b, 0x73, 0x4c, 0xcb, 0xc3, 0xf1, 0x94, 0x94, 0x03, 0xf6, 0xd4, 0xfa, 0xd2, 0x7c, - 0xf5, 0x14, 0x90, 0x48, 0x51, 0x84, 0x1a, 0x38, 0xe9, 0x1f, 0x5e, 0x45, 0x5e, 0x0b, 0xc0, 0x47, 0xb3, 0x91, 0x0c, - 0x8c, 0x16, 0x70, 0x1c, 0x41, 0x79, 0xb5, 0x35, 0x8d, 0xe8, 0x31, 0x96, 0x99, 0xa8, 0xa0, 0xe3, 0x69, 0x79, 0x93, - 0x55, 0xc9, 0x12, 0x03, 0x1b, 0xc5, 0x25, 0x0f, 0xbe, 0x0a, 0xa2, 0x92, 0x1d, 0x3c, 0x9b, 0x2a, 0x78, 0x5f, 0x4c, - 0x4a, 0xf9, 0x25, 0x24, 0x7e, 0x3b, 0x46, 0x08, 0x54, 0xa2, 0x3d, 0x16, 0xb1, 0xc6, 0x57, 0xb9, 0x8c, 0xc1, 0x83, - 0xb3, 0xd4, 0x3c, 0x8b, 0x3d, 0x09, 0xac, 0xfd, 0x45, 0xab, 0x39, 0x12, 0x9a, 0x13, 0x4a, 0x26, 0xf7, 0x4b, 0x2a, - 0xbf, 0x9a, 0xa0, 0x57, 0x10, 0xb8, 0x55, 0x47, 0x70, 0xdc, 0x59, 0xcb, 0x06, 0xbd, 0x7c, 0x52, 0xb6, 0x3f, 0xff, - 0xdf, 0x25, 0x5d, 0x0c, 0xf6, 0xdd, 0xd0, 0x9c, 0x68, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x9e, 0x12, 0x6b, - 0x7c, 0xca, 0xd9, 0xd1, 0xc6, 0x74, 0x67, 0x54, 0x15, 0xd9, 0x55, 0x48, 0x74, 0xaf, 0x1c, 0x28, 0x66, 0x10, 0x65, - 0x23, 0x5c, 0x3f, 0x60, 0x2d, 0xe2, 0x75, 0xf2, 0x9a, 0x17, 0x55, 0x96, 0xa8, 0xf7, 0xd7, 0x8d, 0xf7, 0x40, 0x0d, - 0x54, 0x83, 0xde, 0x15, 0x0c, 0xe6, 0xf9, 0xa4, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, - 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, - 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xae, 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, - 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x93, 0x86, 0x10, - 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, 0x9e, 0xe0, 0xa9, 0x1a, 0x06, 0x17, 0x79, 0xb6, 0xd2, 0x49, 0xd5, 0xa8, - 0xa3, 0xf9, 0x50, 0x6a, 0x47, 0x72, 0x40, 0xbd, 0xf4, 0x18, 0xd3, 0x0b, 0x95, 0xae, 0x8a, 0x72, 0x46, 0x28, 0xef, - 0xf4, 0xc4, 0xb8, 0x30, 0x7d, 0x1c, 0x22, 0xbf, 0xbc, 0x2b, 0x54, 0xe8, 0x17, 0xbe, 0x00, 0xf0, 0x2b, 0xb8, 0xdd, - 0xef, 0xc6, 0x77, 0x51, 0xd9, 0xcf, 0x38, 0xdb, 0xff, 0xef, 0x79, 0x3c, 0xfc, 0x34, 0x1e, 0x7e, 0xbb, 0x18, 0x84, - 0x43, 0xfb, 0x93, 0x3c, 0x7e, 0xb4, 0x4f, 0x5f, 0x71, 0xcb, 0x95, 0xc0, 0xc2, 0x6f, 0x04, 0xb7, 0x51, 0x2b, 0x21, - 0x88, 0x02, 0xbc, 0x51, 0xb8, 0xd5, 0x38, 0x01, 0x80, 0xbf, 0xe0, 0xbf, 0x02, 0x34, 0x12, 0x72, 0x17, 0x0d, 0xd0, - 0x0f, 0xa8, 0xdf, 0x47, 0x4f, 0x1a, 0x06, 0x72, 0x20, 0x9e, 0x50, 0x31, 0x50, 0x88, 0x2e, 0x63, 0xa2, 0x60, 0x7f, - 0x6d, 0xf6, 0xed, 0xb6, 0xd7, 0x96, 0xfc, 0xe0, 0x97, 0x7e, 0xa6, 0x89, 0x99, 0x77, 0xb8, 0xa1, 0xac, 0xe4, 0x2a, - 0x44, 0x6c, 0x3c, 0xfd, 0x2b, 0x67, 0x10, 0x6b, 0xf2, 0x3a, 0x03, 0x1f, 0x06, 0xfb, 0xc5, 0x78, 0x06, 0x6c, 0x03, - 0xdc, 0x71, 0x0a, 0x7e, 0x91, 0x81, 0x5b, 0xb3, 0x88, 0xf1, 0x82, 0x6d, 0x97, 0x44, 0xbf, 0xdf, 0xcb, 0xb3, 0x30, - 0xd7, 0x38, 0xcb, 0x79, 0x6d, 0xc4, 0xee, 0xa8, 0x13, 0x06, 0x71, 0xbb, 0x1e, 0x82, 0xa1, 0x1a, 0x82, 0xa2, 0xa3, - 0x2d, 0xae, 0x5e, 0x5b, 0x4f, 0x61, 0x7a, 0xab, 0xea, 0x2b, 0x46, 0x7f, 0xca, 0x4c, 0x60, 0x21, 0xed, 0x9a, 0x63, - 0x5d, 0x73, 0x8c, 0xb4, 0xa7, 0xdf, 0x17, 0x0d, 0xf2, 0xd3, 0x59, 0x78, 0x10, 0xa8, 0x52, 0xe5, 0x4e, 0x59, 0x94, - 0xdb, 0xd2, 0xbc, 0x31, 0xac, 0x69, 0x9e, 0xd9, 0xb8, 0x2e, 0xb3, 0x5e, 0x2f, 0x0c, 0xd1, 0xa1, 0x11, 0x4b, 0xc5, - 0xda, 0x20, 0xbc, 0x8f, 0x49, 0x18, 0x5d, 0x81, 0xac, 0x2e, 0x3c, 0xe3, 0x04, 0xf9, 0x32, 0x30, 0x59, 0x53, 0xd5, - 0x7a, 0x39, 0xe1, 0xb1, 0x91, 0x2f, 0x1b, 0x41, 0x83, 0xbc, 0xa4, 0xa8, 0x37, 0x71, 0x3b, 0xf6, 0x51, 0x0b, 0xa9, - 0x71, 0x53, 0x4f, 0x7b, 0x9a, 0x54, 0xf4, 0x58, 0xaf, 0x52, 0xbf, 0xc0, 0xb2, 0xc0, 0x92, 0x0f, 0x42, 0x7b, 0x9a, - 0x56, 0x60, 0x86, 0x6b, 0x9b, 0xc1, 0xd0, 0x0f, 0x87, 0xb6, 0x08, 0x9d, 0x51, 0xdb, 0x12, 0xc2, 0xb6, 0x0d, 0xc2, - 0xca, 0x7b, 0x22, 0x5f, 0x3d, 0xf5, 0x18, 0xe1, 0x90, 0x9b, 0xcd, 0x2c, 0x1a, 0x18, 0xe6, 0x57, 0xb2, 0xd9, 0x3c, - 0xdd, 0x5c, 0x2f, 0x2a, 0xa6, 0x80, 0xed, 0xb6, 0x12, 0x04, 0xff, 0x7e, 0xcc, 0x66, 0xf8, 0x37, 0xeb, 0xf7, 0x7b, - 0x21, 0xfe, 0xe2, 0x18, 0xbc, 0x67, 0x2e, 0x16, 0xec, 0x23, 0xc8, 0x54, 0x48, 0x84, 0xa9, 0xca, 0xf8, 0x8d, 0x55, - 0x60, 0x01, 0x67, 0x3e, 0x50, 0xb9, 0x30, 0x93, 0xbd, 0xbc, 0xb8, 0x86, 0x1c, 0xb7, 0xc6, 0x29, 0x1b, 0x65, 0x89, - 0x72, 0x5d, 0xc8, 0x46, 0x71, 0x9e, 0xc5, 0x25, 0x2f, 0xb7, 0x5b, 0x7d, 0x38, 0x26, 0x05, 0x07, 0xf6, 0x54, 0x51, - 0xa9, 0x92, 0x75, 0xa4, 0xba, 0xf1, 0x97, 0x61, 0x81, 0xfb, 0x94, 0xcf, 0x0b, 0x43, 0x23, 0xf6, 0xe0, 0xf2, 0xce, - 0xd4, 0xad, 0xb4, 0x17, 0x16, 0xd0, 0xbc, 0x92, 0x90, 0x0d, 0xa6, 0x7a, 0x16, 0xad, 0x31, 0x13, 0xf3, 0x62, 0x01, - 0x61, 0x64, 0x8a, 0x05, 0xd8, 0x4c, 0x71, 0x01, 0x5e, 0x24, 0x31, 0xc0, 0xc4, 0xc5, 0x64, 0x0a, 0xf1, 0xcc, 0x55, - 0x39, 0xf1, 0xc2, 0xdc, 0x2f, 0x13, 0x87, 0x94, 0x01, 0xaf, 0x6a, 0x83, 0x26, 0x66, 0x1b, 0x8e, 0x3a, 0x41, 0x4e, - 0x4c, 0x7e, 0x3f, 0x55, 0x10, 0xe2, 0x4e, 0x1c, 0x09, 0x97, 0x15, 0xdb, 0x85, 0x97, 0x1d, 0x88, 0x31, 0x6a, 0x70, - 0xca, 0xcf, 0x0c, 0x8e, 0xc6, 0xe0, 0xdc, 0x78, 0x27, 0x48, 0x11, 0xc6, 0x64, 0x23, 0xd9, 0x95, 0x0c, 0xc5, 0x3c, - 0x5e, 0x80, 0xb2, 0x2e, 0x5e, 0x80, 0x65, 0x8d, 0x31, 0xc0, 0x04, 0x79, 0x15, 0xf7, 0x42, 0x3f, 0x51, 0x5c, 0x21, - 0xd2, 0xb3, 0x72, 0x7d, 0x54, 0xb4, 0x43, 0x5f, 0xe0, 0xf5, 0x5e, 0x99, 0xe3, 0x66, 0x3d, 0x16, 0x48, 0x6c, 0x08, - 0x18, 0x1b, 0xe9, 0x34, 0xd5, 0x5a, 0xf7, 0xc6, 0xcc, 0x03, 0x9f, 0x66, 0x23, 0x21, 0xab, 0xb3, 0x0b, 0x10, 0xa1, - 0xf8, 0x68, 0xf0, 0xc8, 0x2f, 0xe2, 0xce, 0x32, 0x6f, 0x6d, 0x8b, 0x4a, 0x76, 0xb4, 0x01, 0x90, 0x3e, 0x1d, 0x2d, - 0x4a, 0xc9, 0x29, 0x4a, 0x52, 0xbb, 0x4d, 0x01, 0x2b, 0xc9, 0x5f, 0xc0, 0x10, 0x6c, 0x6c, 0x4f, 0x38, 0x9d, 0x22, - 0xc4, 0x27, 0x9a, 0x22, 0xb2, 0x62, 0x58, 0x52, 0x1c, 0xdb, 0x12, 0x51, 0x3f, 0x6d, 0x59, 0x76, 0x30, 0x4c, 0x54, - 0xdc, 0x17, 0xa9, 0x47, 0x89, 0x82, 0x80, 0xea, 0x21, 0x07, 0x89, 0xad, 0x6d, 0x20, 0x3c, 0x20, 0x8f, 0xe8, 0x8d, - 0xf5, 0xf7, 0x59, 0xe7, 0xd9, 0x85, 0xe6, 0xa8, 0x5c, 0xef, 0x0a, 0x33, 0x46, 0x78, 0x92, 0x19, 0x98, 0x7c, 0xef, - 0x3c, 0x33, 0x6a, 0x8a, 0x9e, 0x87, 0x4f, 0x76, 0x8c, 0x11, 0xe9, 0xee, 0x19, 0x74, 0x13, 0xbc, 0xaa, 0xc3, 0x46, - 0xbb, 0x52, 0x10, 0x12, 0xa6, 0x16, 0x4d, 0xcc, 0x7a, 0xd6, 0x80, 0x7a, 0xbb, 0xed, 0xe9, 0xb9, 0xba, 0x7f, 0xee, - 0xb6, 0xdb, 0x1e, 0x76, 0xeb, 0x45, 0xda, 0x6d, 0x05, 0x5e, 0xa9, 0x0f, 0xda, 0xe3, 0xcf, 0xdd, 0xf8, 0x73, 0x83, - 0xe4, 0x51, 0x3a, 0x9a, 0x69, 0xeb, 0x83, 0x70, 0xb8, 0xe9, 0x5d, 0xa3, 0x49, 0xdf, 0x67, 0xa1, 0xa4, 0x2b, 0xd1, - 0xa8, 0xae, 0x76, 0x26, 0x95, 0x0f, 0xae, 0xff, 0x87, 0x57, 0x01, 0x1e, 0x71, 0x6a, 0x67, 0xdf, 0xdb, 0xa0, 0xa2, - 0xd1, 0x16, 0x8e, 0x14, 0xa1, 0x07, 0x24, 0xe1, 0xbe, 0x96, 0xb5, 0xb8, 0xcd, 0xd3, 0xec, 0x61, 0xfa, 0xf4, 0x3a, - 0xf5, 0xad, 0xee, 0xdd, 0x32, 0xcb, 0xcc, 0x81, 0x57, 0x51, 0x1c, 0xd0, 0xa8, 0x8b, 0xf6, 0x5d, 0x65, 0x65, 0x09, - 0x5e, 0x1e, 0x70, 0x7d, 0x3e, 0xe5, 0x3e, 0xdc, 0xdc, 0x65, 0xd5, 0xdc, 0xa4, 0xa7, 0xd9, 0x3c, 0x5b, 0x6c, 0xb7, - 0x21, 0xfe, 0xed, 0x6a, 0x91, 0xa3, 0xc9, 0x73, 0xd0, 0xe1, 0x61, 0xe4, 0x1e, 0xa6, 0x1b, 0xe7, 0x6d, 0xfe, 0x4f, - 0xa2, 0xe1, 0x24, 0x70, 0x0c, 0xf4, 0x62, 0xf6, 0x08, 0x64, 0x30, 0xc6, 0xa9, 0x5f, 0xcc, 0xf4, 0x9a, 0x81, 0xe8, - 0x5b, 0x22, 0x02, 0x1c, 0x5d, 0x6c, 0x24, 0x1a, 0x59, 0x70, 0x52, 0x13, 0xb0, 0xd8, 0xb4, 0xe5, 0x7d, 0xb0, 0xb4, - 0xad, 0x2a, 0xee, 0xbc, 0x25, 0xcd, 0x71, 0x1d, 0x38, 0xdb, 0x7e, 0x33, 0xc4, 0xa6, 0xec, 0x6a, 0x81, 0xdc, 0x2f, - 0xaf, 0x69, 0x6f, 0x5c, 0x27, 0x30, 0x6b, 0x9b, 0xda, 0x32, 0x7e, 0xb6, 0xf4, 0x9f, 0xf5, 0xe0, 0x2a, 0xe3, 0xa7, - 0xb9, 0xb1, 0x4a, 0xb0, 0xfb, 0xc6, 0xf3, 0x1d, 0x80, 0x70, 0x6c, 0x3e, 0x3d, 0x3e, 0xcd, 0x3c, 0x7a, 0x0c, 0x44, - 0xc7, 0x7c, 0x54, 0xba, 0x8f, 0xec, 0xee, 0xf5, 0x03, 0xe0, 0xcd, 0xab, 0x76, 0x41, 0xf3, 0x72, 0x01, 0x81, 0x44, - 0xbd, 0xf2, 0x0a, 0xcb, 0x67, 0xc6, 0xec, 0x12, 0xc8, 0x50, 0x41, 0xc0, 0x26, 0xa9, 0xeb, 0x5c, 0x88, 0x55, 0x87, - 0x95, 0xf9, 0x48, 0xc2, 0x8e, 0x42, 0x34, 0xe7, 0x0c, 0x66, 0xc1, 0x7f, 0x05, 0x83, 0x72, 0x10, 0x44, 0x41, 0x14, - 0x04, 0x64, 0x50, 0xc0, 0x2f, 0xc4, 0x19, 0x23, 0x18, 0xa3, 0x04, 0x3a, 0xfc, 0x8e, 0x33, 0x9f, 0x11, 0x79, 0xd9, - 0x08, 0x63, 0xe9, 0x06, 0xe0, 0x5c, 0xca, 0x9c, 0xc7, 0xe8, 0x63, 0xf1, 0x8e, 0xb3, 0x8c, 0xd0, 0x77, 0xde, 0xa9, - 0xfc, 0x88, 0x37, 0x82, 0xdb, 0xed, 0x0e, 0xdb, 0x2b, 0x1e, 0x66, 0xb4, 0x37, 0xa6, 0xef, 0x38, 0x89, 0xb2, 0x86, - 0xf3, 0x30, 0x87, 0x9e, 0x55, 0x96, 0xb5, 0xa2, 0x86, 0xdc, 0xa0, 0x58, 0x17, 0x59, 0x26, 0x27, 0xc3, 0x55, 0x73, - 0x2a, 0x70, 0xdd, 0xd9, 0xf5, 0x02, 0x92, 0x32, 0xa1, 0x59, 0x3a, 0x1b, 0xbe, 0xda, 0xb6, 0xec, 0x45, 0xeb, 0x14, - 0xf2, 0x1a, 0xa2, 0xa2, 0x1f, 0x3a, 0x02, 0x6a, 0x68, 0xc5, 0x65, 0x05, 0x2e, 0xbb, 0xa6, 0x3d, 0xdc, 0xb4, 0xc7, - 0x34, 0xe3, 0x03, 0xc4, 0x88, 0xe3, 0xd8, 0x32, 0xb0, 0x9b, 0x70, 0x78, 0x36, 0xce, 0xf7, 0x65, 0x97, 0xde, 0xba, - 0x5a, 0x3c, 0xc2, 0xda, 0xf3, 0x56, 0x48, 0x08, 0x90, 0x96, 0xa6, 0xd2, 0xed, 0x36, 0x08, 0x60, 0x80, 0xfb, 0xfd, - 0x1e, 0x70, 0xad, 0x86, 0x9d, 0x34, 0xb7, 0x66, 0x4b, 0xec, 0x15, 0x85, 0xc7, 0x40, 0x94, 0x9a, 0xff, 0x0c, 0x02, - 0x8a, 0xe7, 0x6e, 0x08, 0xf6, 0x95, 0xec, 0x68, 0x53, 0xf4, 0xfb, 0x2f, 0x0a, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, - 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, - 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x9f, 0x00, 0x16, 0x3c, 0xf3, 0x86, 0xe5, - 0xbd, 0x07, 0x00, 0xd6, 0xeb, 0xe1, 0x42, 0x71, 0x2f, 0x5f, 0x35, 0xd0, 0x27, 0xf1, 0xa5, 0x65, 0xd7, 0x67, 0x5a, - 0x56, 0x32, 0x1a, 0x8d, 0xaa, 0x5a, 0x49, 0x3e, 0x1c, 0x79, 0x69, 0xa1, 0x56, 0xca, 0x38, 0xe5, 0x29, 0x58, 0x7a, - 0x1b, 0x4a, 0x37, 0x5f, 0xd0, 0x15, 0x17, 0xa9, 0xfa, 0xe9, 0xa1, 0x4d, 0x36, 0x88, 0x6b, 0xd6, 0xd4, 0x59, 0xd8, - 0xe1, 0x87, 0x80, 0x8f, 0xf6, 0x61, 0xe6, 0xd2, 0x35, 0x2c, 0x2d, 0x88, 0x23, 0xe3, 0x82, 0x87, 0x2e, 0x0f, 0x60, - 0xfd, 0x99, 0x43, 0x12, 0x3f, 0x85, 0x9f, 0x33, 0x93, 0xd6, 0xf1, 0x19, 0xce, 0x66, 0x54, 0xaa, 0x1b, 0x41, 0xfb, - 0x35, 0x24, 0x12, 0x83, 0x6c, 0xdc, 0x60, 0x28, 0x5a, 0x77, 0x1b, 0xb8, 0xf2, 0x5b, 0x7a, 0xe7, 0xd3, 0x20, 0xc0, - 0xb6, 0xc6, 0x62, 0x00, 0x30, 0x14, 0x7f, 0xa0, 0xaa, 0xc6, 0x5c, 0x51, 0x4c, 0xc3, 0x54, 0xa2, 0xbd, 0xe3, 0xb8, - 0x8e, 0x1a, 0x57, 0x59, 0xc1, 0x4a, 0x6b, 0xcb, 0xeb, 0xde, 0xd2, 0xc2, 0x96, 0x80, 0x6a, 0x30, 0xdc, 0x09, 0xe0, - 0x33, 0x22, 0xd5, 0x81, 0x20, 0xbb, 0x0f, 0x0e, 0x9a, 0xb3, 0x04, 0xcf, 0xc3, 0x10, 0xfe, 0xc0, 0xc2, 0x81, 0x65, - 0xa9, 0xfa, 0xb9, 0x9c, 0xc6, 0x70, 0xee, 0xe6, 0x6a, 0x87, 0xcf, 0x96, 0xa0, 0xc8, 0x53, 0x73, 0x6a, 0x2e, 0x5f, - 0x79, 0x63, 0xbf, 0xc7, 0x04, 0xf3, 0x98, 0xd9, 0x86, 0xdf, 0x7a, 0xba, 0xad, 0x2f, 0xac, 0x1b, 0x38, 0x69, 0x2f, - 0x9c, 0xf6, 0x62, 0xbb, 0x34, 0x10, 0x77, 0x75, 0x43, 0x88, 0xf0, 0x5a, 0x13, 0x8b, 0xac, 0x21, 0xd3, 0xb1, 0xd8, - 0x18, 0xaa, 0x4d, 0xc5, 0x73, 0xad, 0x10, 0x2f, 0xa7, 0xea, 0xc2, 0xd4, 0x4a, 0x65, 0xc2, 0x20, 0xcc, 0x94, 0xb0, - 0xa8, 0x32, 0xf0, 0xd9, 0xaf, 0x90, 0xe2, 0xda, 0x7a, 0xde, 0xe2, 0xf2, 0xcd, 0x4c, 0x9b, 0xed, 0xa7, 0xaf, 0xf2, - 0xf8, 0x72, 0xbb, 0x0d, 0xbb, 0x5f, 0x80, 0xf9, 0x65, 0xa9, 0x34, 0x6a, 0xe0, 0xf4, 0x10, 0xa2, 0x9f, 0xf3, 0x3d, - 0x39, 0x27, 0x8e, 0x93, 0x6b, 0x37, 0x6f, 0xb6, 0x93, 0x62, 0x04, 0x16, 0x70, 0xe2, 0x22, 0x1d, 0x68, 0xa9, 0xe0, - 0xb4, 0x65, 0xbc, 0xb7, 0xe9, 0x1d, 0xa5, 0xc2, 0xab, 0x85, 0x26, 0x21, 0x95, 0xbb, 0x97, 0xd8, 0x51, 0x03, 0xce, - 0x49, 0xdd, 0x41, 0xc0, 0x49, 0x4d, 0x37, 0xd6, 0x2a, 0x4e, 0x4d, 0x82, 0xf7, 0x4a, 0x0f, 0x5d, 0xa2, 0x9d, 0xb8, - 0xdd, 0xb6, 0x2a, 0x5b, 0xa8, 0x8f, 0x7b, 0x39, 0x4b, 0xd4, 0xf1, 0x80, 0x42, 0x17, 0x75, 0x34, 0xe4, 0x0b, 0x52, - 0xe8, 0x95, 0xa3, 0x55, 0xab, 0xbb, 0x92, 0x81, 0x52, 0xad, 0x82, 0xbc, 0x26, 0xd6, 0x5d, 0x2b, 0x6b, 0x2c, 0xae, - 0x9c, 0x90, 0xc2, 0x26, 0x7c, 0x69, 0x29, 0x16, 0x56, 0xb0, 0x37, 0xa6, 0xbe, 0x70, 0x89, 0xd0, 0x76, 0xb7, 0x21, - 0x26, 0x19, 0xac, 0x9b, 0xed, 0xf6, 0x75, 0x11, 0xce, 0xb3, 0x05, 0x95, 0xa3, 0x2c, 0x45, 0x08, 0x31, 0xe3, 0xa1, - 0x6b, 0xbb, 0x60, 0x26, 0x86, 0xba, 0xf6, 0x78, 0x49, 0xa6, 0x58, 0x9b, 0x24, 0x47, 0xf1, 0xb9, 0x2c, 0xd4, 0x5a, - 0x23, 0x04, 0x0f, 0xf7, 0x3f, 0x53, 0x88, 0xe1, 0x66, 0xd6, 0xdd, 0x6f, 0x3b, 0x37, 0xc4, 0x3f, 0x21, 0x90, 0x40, - 0xc9, 0x5e, 0x17, 0xa3, 0xf3, 0x4c, 0xa4, 0xb8, 0x53, 0x55, 0x54, 0x5c, 0xb5, 0x0e, 0x9a, 0x2d, 0xb7, 0xf7, 0x62, - 0x4b, 0x14, 0x20, 0xae, 0xb1, 0xd0, 0x8c, 0x67, 0xe5, 0x2c, 0x45, 0x32, 0x8a, 0x0d, 0x89, 0x4a, 0x2f, 0x2a, 0xba, - 0xcf, 0xd3, 0x98, 0x1e, 0xba, 0x35, 0x08, 0xae, 0x9a, 0x3b, 0x1b, 0x69, 0xbe, 0x20, 0x44, 0x4d, 0x80, 0x84, 0x8d, - 0x6a, 0x4e, 0xad, 0x4b, 0xf1, 0x30, 0xab, 0x7c, 0xa6, 0x0f, 0xe2, 0x4b, 0x01, 0x3c, 0xac, 0xb7, 0xbd, 0xaf, 0x84, - 0xc7, 0xda, 0xe0, 0xdb, 0xed, 0xf6, 0x52, 0xcc, 0x83, 0xc0, 0x63, 0x34, 0xbf, 0x53, 0x12, 0xf3, 0xde, 0x98, 0xc2, - 0x8a, 0xf7, 0x5d, 0xda, 0xba, 0x49, 0xad, 0xb5, 0x40, 0xdd, 0xe1, 0xfa, 0x80, 0xe7, 0x29, 0x71, 0xb4, 0xa3, 0x72, - 0x2a, 0xad, 0xae, 0x1c, 0xbb, 0x22, 0x30, 0x30, 0xf4, 0x0f, 0x29, 0xdb, 0x80, 0x39, 0x1e, 0x58, 0xdb, 0xa0, 0x9f, - 0x92, 0xd2, 0xc2, 0x8c, 0xd1, 0x98, 0x45, 0xae, 0xab, 0xe8, 0x80, 0xeb, 0xe8, 0xed, 0x3c, 0xfa, 0xdb, 0xb3, 0x31, - 0x2d, 0x62, 0x91, 0xca, 0x2b, 0x50, 0x41, 0x80, 0x32, 0x04, 0x0d, 0xff, 0x35, 0x35, 0x00, 0x0d, 0x82, 0x1b, 0x80, - 0x7f, 0x74, 0x3a, 0x0d, 0xda, 0x9a, 0x7c, 0x4c, 0x52, 0x55, 0xe4, 0xac, 0x0d, 0x65, 0xa6, 0x92, 0x43, 0xf2, 0xb8, - 0x04, 0x3c, 0x47, 0x6c, 0x96, 0xb2, 0xb9, 0x50, 0x9b, 0x4d, 0xbd, 0x56, 0xec, 0xc8, 0x6d, 0xa3, 0x68, 0xb3, 0x16, - 0xb5, 0x9d, 0xc4, 0x7c, 0x31, 0xbd, 0xb5, 0xc2, 0xc0, 0xa9, 0x69, 0xcd, 0xcd, 0x0e, 0x74, 0x9a, 0xad, 0xcf, 0xe4, - 0x26, 0x40, 0x1c, 0x60, 0xb8, 0x6e, 0xe7, 0x37, 0x0b, 0x42, 0x6f, 0xd9, 0xad, 0x15, 0xab, 0xde, 0x58, 0xb9, 0x88, - 0x49, 0xbb, 0x19, 0x4c, 0xe0, 0x32, 0xce, 0x0a, 0xfb, 0x42, 0xab, 0x1b, 0x8a, 0x8e, 0xb6, 0x49, 0xfb, 0x79, 0x47, - 0xbb, 0xe1, 0x82, 0x6f, 0xc5, 0x3a, 0xce, 0x0d, 0x69, 0xaa, 0xd0, 0xa3, 0x03, 0xbd, 0x1d, 0x02, 0x9a, 0xb3, 0x31, - 0x5d, 0xd2, 0x14, 0x2f, 0xd0, 0x74, 0x0d, 0x66, 0x29, 0x17, 0xd0, 0xd7, 0x6e, 0x9f, 0xe4, 0x0b, 0xd5, 0x13, 0xe1, - 0x2d, 0x51, 0xf0, 0xe5, 0x48, 0xc1, 0x2b, 0x2b, 0xe7, 0xb1, 0x99, 0x43, 0xc0, 0x63, 0x51, 0x25, 0x7a, 0x27, 0xc5, - 0x25, 0x28, 0x53, 0xe1, 0x08, 0x34, 0x55, 0x23, 0x96, 0x70, 0x80, 0xdb, 0x8b, 0xa7, 0x01, 0xa1, 0x20, 0xd5, 0x5d, - 0xdb, 0x15, 0x79, 0xcb, 0x8e, 0x36, 0xb7, 0x60, 0x16, 0x5b, 0xad, 0xcb, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, - 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, 0x43, 0x36, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, - 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x55, 0x7c, 0x07, 0x9b, - 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, - 0x5e, 0x6d, 0x6d, 0xd6, 0x66, 0xb9, 0x3e, 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, - 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x36, 0xce, - 0xdc, 0xeb, 0x90, 0x6c, 0xfe, 0xc7, 0x06, 0xea, 0x4d, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x3e, 0x61, 0x10, 0x1b, 0x33, - 0x28, 0xd7, 0x49, 0xc2, 0xcb, 0x32, 0x30, 0x4a, 0xad, 0x35, 0x5b, 0x9b, 0xf3, 0xec, 0x11, 0x3b, 0x7a, 0xd4, 0x63, - 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x04, 0x85, - 0x2c, 0xed, 0x7d, 0x6e, 0x4e, 0x64, 0xf5, 0x8d, 0x36, 0xba, 0x88, 0x54, 0x22, 0xc8, 0xc6, 0x6f, 0x10, 0xb0, 0x17, - 0x9a, 0x1d, 0x90, 0xcd, 0x92, 0x9d, 0xd2, 0x33, 0x6b, 0x02, 0x03, 0xaf, 0x4f, 0x54, 0xa2, 0x19, 0x65, 0x45, 0x74, - 0x95, 0x91, 0xcb, 0x5d, 0x48, 0xa2, 0xb3, 0x90, 0xf8, 0xb9, 0x61, 0x69, 0x5d, 0x87, 0x28, 0x66, 0x36, 0x1b, 0x5e, - 0x75, 0xf7, 0x51, 0x63, 0x5b, 0x19, 0x9f, 0xea, 0x5b, 0x9b, 0x46, 0xa6, 0xd0, 0xd7, 0xe1, 0xa4, 0xdf, 0x87, 0xbf, - 0x9a, 0x7e, 0xe0, 0x2d, 0x05, 0x7f, 0xb1, 0x47, 0xa4, 0x4e, 0x58, 0x00, 0x70, 0x84, 0x39, 0xaf, 0x9a, 0x13, 0xf8, - 0x88, 0x1d, 0x6d, 0x1e, 0x85, 0xa7, 0x8d, 0x99, 0xbb, 0x0b, 0xf1, 0x52, 0x95, 0xf4, 0xbc, 0x79, 0x32, 0x03, 0xb1, - 0x0a, 0xcd, 0x7e, 0xbd, 0x65, 0x56, 0x9f, 0x00, 0x44, 0xea, 0xd6, 0x3a, 0x94, 0xe2, 0xc7, 0xa6, 0xcb, 0x64, 0x93, - 0xb2, 0x36, 0x13, 0xa5, 0x54, 0x24, 0xcd, 0x45, 0x00, 0xfd, 0x86, 0xe1, 0xa8, 0x01, 0xde, 0x5b, 0x8f, 0xbd, 0x19, - 0x1a, 0x6f, 0x4c, 0x0d, 0x3d, 0xdb, 0xe8, 0xe5, 0xed, 0x28, 0x84, 0x19, 0x8b, 0xe8, 0xd6, 0x1d, 0x8b, 0xe1, 0x29, - 0x3d, 0x81, 0x0a, 0xdf, 0x84, 0x18, 0x4d, 0x97, 0xd4, 0xf5, 0x74, 0xad, 0xb6, 0xd2, 0x0d, 0xa1, 0x39, 0x46, 0xf1, - 0xf1, 0xda, 0x76, 0x47, 0x8d, 0xd0, 0x9e, 0x50, 0x1e, 0xde, 0xd2, 0x8a, 0xde, 0x58, 0x16, 0xc1, 0xc9, 0x8f, 0xbd, - 0xfc, 0x84, 0x9e, 0x7b, 0x02, 0x93, 0xa2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x3d, 0xb5, 0x52, 0x0e, 0x4f, - 0xe1, 0x4b, 0x36, 0x20, 0x57, 0xd0, 0x8b, 0x35, 0x66, 0x47, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x37, 0x29, 0x65, - 0x88, 0xd6, 0x77, 0x0e, 0xe2, 0xe9, 0x1f, 0xa0, 0xe9, 0x83, 0xb4, 0x30, 0xa5, 0x6b, 0x14, 0xf0, 0x80, 0xbe, 0xa9, - 0xdf, 0xcf, 0xf1, 0xb9, 0xf6, 0x2c, 0xb1, 0xb0, 0xc7, 0x4b, 0x42, 0x97, 0x5e, 0xdc, 0x28, 0x90, 0x36, 0x3b, 0x56, - 0x01, 0x58, 0x91, 0x04, 0x1a, 0x91, 0x80, 0xa5, 0x8e, 0x27, 0x2e, 0xdb, 0xa0, 0x01, 0x49, 0x54, 0x52, 0xc8, 0x12, - 0x49, 0xe0, 0x87, 0x11, 0x84, 0x28, 0x8a, 0x41, 0xdc, 0xab, 0x97, 0x57, 0x5c, 0x53, 0x03, 0x4e, 0x14, 0xc1, 0x04, - 0xeb, 0x74, 0x0a, 0xc4, 0x56, 0xac, 0x57, 0xe0, 0x79, 0xe9, 0x38, 0x71, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x97, 0x4e, - 0xbb, 0xe5, 0xed, 0x89, 0x96, 0x2a, 0x36, 0xf7, 0x5e, 0x2c, 0x2c, 0xf7, 0x58, 0xf9, 0xdb, 0x81, 0xf6, 0xc2, 0x6a, - 0x47, 0x44, 0x0d, 0x56, 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xea, 0x5e, 0x39, 0x26, 0xa0, 0xa2, 0xab, 0xb8, 0x5a, - 0x46, 0xd9, 0x08, 0xfe, 0x6c, 0xb7, 0xc1, 0x7e, 0x00, 0x16, 0x90, 0xbf, 0xbe, 0xff, 0x39, 0xc2, 0xf0, 0x4c, 0xbf, - 0xbe, 0xff, 0x79, 0xbb, 0x7d, 0x36, 0x1e, 0x1b, 0xae, 0xc0, 0xa9, 0x75, 0x80, 0x3f, 0x30, 0x6c, 0x83, 0x5d, 0xb2, - 0xdb, 0xed, 0x33, 0xe0, 0x20, 0x14, 0xdb, 0x60, 0x76, 0xb1, 0x72, 0xe4, 0x52, 0xac, 0x86, 0xde, 0x91, 0x80, 0x55, - 0xb7, 0xc3, 0x52, 0xec, 0x52, 0x1f, 0x15, 0x82, 0x51, 0x2f, 0xfa, 0x97, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, - 0xb2, 0xaa, 0x56, 0x65, 0xb4, 0xbf, 0x1f, 0xaf, 0xb2, 0x51, 0x99, 0xc1, 0x36, 0x2f, 0xaf, 0x2f, 0x01, 0x50, 0x21, - 0xa0, 0x8d, 0x77, 0x6b, 0x91, 0x99, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0xad, 0x6e, 0x72, - 0x4a, 0xec, 0x03, 0xd8, 0x1c, 0x6e, 0xb7, 0x0d, 0x7e, 0xe1, 0x68, 0xf4, 0x6c, 0xb6, 0xcc, 0xb4, 0x41, 0x27, 0x37, - 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, 0xc9, 0xf4, 0x65, 0x06, 0x7c, 0x1e, 0x7b, 0x2b, 0x42, 0x9f, 0xe5, 0x6a, - 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x32, 0x23, 0xbe, 0x4d, - 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x56, 0x78, 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x12, 0x85, 0xa8, - 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x9a, 0x3a, 0x73, 0x19, 0x5f, 0xb8, - 0xf7, 0xd2, 0x97, 0x99, 0xdc, 0x4a, 0x00, 0x45, 0x52, 0xb5, 0xff, 0xf2, 0x19, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, - 0xe8, 0xfd, 0x02, 0x35, 0x39, 0x82, 0x80, 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, - 0x6d, 0x54, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, 0x4f, 0xd7, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, - 0x1b, 0x21, 0xeb, 0x97, 0x66, 0x17, 0x7e, 0x2e, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, - 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, 0x1e, 0x73, 0x82, 0x3f, 0x3d, 0x78, 0x4a, 0xe8, 0xad, 0x9c, 0x96, 0x08, - 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, - 0x6c, 0xd9, 0x6f, 0x4d, 0xd9, 0x92, 0x6c, 0x04, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbc, 0xdf, 0xa0, - 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, - 0x9c, 0x85, 0xed, 0x76, 0x42, 0x7c, 0x09, 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, - 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x20, 0xa0, 0xc7, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x8e, 0xf9, 0x20, 0x18, - 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x57, 0x05, 0x43, 0x58, 0xa1, 0xbf, - 0x52, 0x36, 0xf9, 0xe6, 0xef, 0x6e, 0x7e, 0xcf, 0xb5, 0x98, 0x1d, 0x84, 0xe2, 0xf6, 0x7a, 0x02, 0xc4, 0xaf, 0xe2, - 0x57, 0x60, 0x5d, 0xad, 0x25, 0xde, 0x6e, 0x7a, 0xfe, 0x14, 0xbe, 0x1c, 0xdd, 0x7e, 0x52, 0x9a, 0x4f, 0x20, 0x48, - 0x8d, 0x93, 0x94, 0xbb, 0xef, 0x3e, 0x4a, 0x57, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xdd, 0x5b, 0xc9, 0x59, 0x53, 0xf8, - 0x8f, 0x75, 0xbe, 0xc7, 0xd8, 0x21, 0xf2, 0x14, 0xa7, 0xbf, 0x01, 0x86, 0x7d, 0xe7, 0xdf, 0xca, 0xac, 0x21, 0xd1, - 0xb9, 0xfa, 0x08, 0xe8, 0xff, 0x58, 0x8f, 0xdf, 0x31, 0x4a, 0xfa, 0x92, 0x38, 0x47, 0xb8, 0x22, 0x5e, 0xa2, 0xa9, - 0x5e, 0x6f, 0x5c, 0xd3, 0x4f, 0x85, 0x79, 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0x9b, 0x68, - 0x08, 0xba, 0x7f, 0xc7, 0xbd, 0xf1, 0x9b, 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, - 0x1b, 0xc6, 0x82, 0xb5, 0x50, 0xe6, 0xab, 0x69, 0x30, 0xdb, 0xd4, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x6d, 0x9c, 0xb0, - 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, - 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x71, 0x05, 0xbb, 0xcc, - 0x57, 0x52, 0xfc, 0xd9, 0x92, 0x64, 0x63, 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, - 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, - 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x63, 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0xa7, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, - 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, 0x53, 0xba, 0x9b, 0xd3, 0xfe, 0xab, 0x82, 0x0c, 0xff, 0x02, 0xef, 0xae, - 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, - 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, 0xe4, 0xad, 0xc6, 0x6c, 0xca, 0xfd, 0x0f, 0x60, 0x44, 0xb5, 0xb4, 0xdd, - 0x0e, 0xf8, 0x72, 0x84, 0x06, 0xdb, 0xa9, 0x1b, 0xec, 0x7e, 0xdf, 0xa4, 0x1d, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, - 0x51, 0xda, 0x2c, 0x95, 0x41, 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x92, 0xc6, 0x56, - 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, - 0xed, 0x36, 0x84, 0x08, 0x1c, 0xc5, 0x70, 0x32, 0x0b, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0xa9, 0x98, - 0x67, 0x0b, 0x85, 0xd8, 0xe3, 0xef, 0xa4, 0xdf, 0x0a, 0xc5, 0x29, 0xf7, 0x7e, 0x13, 0x64, 0xf3, 0x7b, 0x8a, 0x31, - 0x07, 0x9d, 0x66, 0x33, 0x03, 0x09, 0xeb, 0x71, 0x45, 0xd4, 0x3a, 0xb2, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, - 0x75, 0x8b, 0x27, 0xd6, 0x33, 0x7a, 0x0f, 0x2a, 0x41, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x3e, 0x89, 0x50, 0x52, - 0x4e, 0x9a, 0xcc, 0x8c, 0x15, 0x0d, 0x16, 0x20, 0x24, 0x8d, 0xcb, 0xea, 0x8d, 0x4c, 0xb3, 0x8b, 0x0c, 0x10, 0x13, - 0x9c, 0xff, 0x9c, 0x6c, 0xbc, 0x79, 0xae, 0xe6, 0xa5, 0x2b, 0x71, 0x66, 0x61, 0x3e, 0xba, 0xde, 0xd2, 0x82, 0x44, - 0x05, 0xd0, 0x28, 0x5f, 0xcb, 0xf3, 0xd3, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x65, 0x3b, 0xc4, 0x8f, 0x58, 0x45, - 0xbc, 0xd3, 0xba, 0x52, 0x22, 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xa8, 0xe1, 0x83, 0x30, 0x83, 0x4e, - 0xf2, 0x83, 0x9e, 0xd1, 0xb1, 0x35, 0x90, 0xf4, 0xb5, 0x08, 0xbe, 0x46, 0x47, 0x3a, 0x51, 0xa6, 0x91, 0x98, 0x42, - 0xa2, 0x5f, 0x2f, 0xb4, 0xc6, 0x32, 0xca, 0xbe, 0x22, 0xff, 0x7b, 0xdd, 0xbd, 0xdf, 0xc4, 0x76, 0x0b, 0x93, 0xec, - 0x79, 0x5c, 0xc1, 0xa6, 0x46, 0xad, 0x10, 0xce, 0xce, 0x71, 0x85, 0xda, 0xb1, 0x5e, 0x58, 0x02, 0x79, 0x00, 0x5b, - 0x91, 0x06, 0x65, 0x90, 0xec, 0x53, 0x31, 0x17, 0x0b, 0x27, 0xca, 0x91, 0x0a, 0xef, 0x4b, 0x8e, 0x52, 0x0e, 0x57, - 0xb1, 0xb0, 0x60, 0xc8, 0xaf, 0x8e, 0x2e, 0x0a, 0x79, 0x05, 0x92, 0x12, 0xc3, 0x50, 0x59, 0x5e, 0x17, 0x57, 0x6d, - 0x49, 0x68, 0xef, 0x0c, 0x40, 0x58, 0x0a, 0x10, 0xbc, 0x34, 0x6a, 0x88, 0xd9, 0x46, 0xed, 0xae, 0xe8, 0x5e, 0x72, - 0x40, 0x9d, 0xee, 0xda, 0xad, 0x37, 0x65, 0x9b, 0x6d, 0xc5, 0x85, 0x7f, 0x42, 0xe9, 0xc7, 0x7c, 0x50, 0xf8, 0x54, - 0x02, 0x37, 0xbe, 0xda, 0x64, 0xd9, 0xc5, 0x1d, 0x2e, 0xfd, 0xaa, 0x31, 0x7e, 0xfd, 0x7e, 0x4f, 0x2d, 0x84, 0x46, - 0x2a, 0x30, 0xdf, 0x3e, 0x33, 0x55, 0x19, 0x4d, 0xa9, 0xbd, 0x04, 0x57, 0xce, 0x7e, 0x04, 0x15, 0x71, 0x5d, 0x91, - 0xc9, 0xd4, 0x00, 0xed, 0x79, 0x59, 0xe1, 0x56, 0x16, 0xe0, 0xb1, 0x13, 0x90, 0xed, 0x96, 0x87, 0x81, 0x3e, 0x74, - 0x02, 0x7f, 0x4b, 0x9e, 0x22, 0xb3, 0x66, 0x1f, 0x7f, 0xd1, 0x82, 0x7f, 0x6c, 0xc1, 0xcf, 0x28, 0xee, 0xb4, 0x32, - 0xff, 0x56, 0x5a, 0xb7, 0xb8, 0x7f, 0x27, 0xd3, 0x84, 0xa2, 0x32, 0xa1, 0xf6, 0x2b, 0xfd, 0x97, 0x09, 0x96, 0xa4, - 0xb2, 0x7f, 0x90, 0xf0, 0xc1, 0xac, 0xf1, 0xc4, 0x1a, 0x4f, 0x86, 0xd3, 0xad, 0x34, 0x0c, 0x01, 0x0a, 0xfd, 0xbc, - 0xcc, 0x15, 0xd5, 0xcf, 0xbf, 0xac, 0xf9, 0x9a, 0x37, 0x5b, 0x6c, 0x93, 0x1e, 0x68, 0xb0, 0x97, 0x47, 0x53, 0x0a, - 0x27, 0x51, 0xe7, 0x46, 0xa2, 0x2e, 0x6a, 0x96, 0xa1, 0x3a, 0xc1, 0xab, 0x79, 0xaa, 0x87, 0xbd, 0x99, 0x88, 0xd6, - 0x4a, 0xca, 0x12, 0x03, 0xd6, 0x3a, 0xf2, 0x90, 0xdc, 0xad, 0x75, 0xdc, 0x69, 0xa8, 0x4b, 0x53, 0x28, 0x01, 0x56, - 0xb8, 0x00, 0x47, 0xd0, 0xcf, 0x45, 0xc8, 0xe1, 0x9a, 0xaa, 0xf4, 0x0b, 0x9a, 0x92, 0x27, 0x9e, 0xa2, 0x56, 0x2b, - 0xd2, 0xed, 0x47, 0x39, 0x76, 0xc3, 0x37, 0x4e, 0xc8, 0x89, 0x11, 0xfa, 0xbb, 0x63, 0x29, 0x67, 0x68, 0xf1, 0xa0, - 0x4e, 0xb0, 0x5e, 0xde, 0x52, 0xa0, 0x98, 0xa3, 0xcb, 0xaa, 0x6b, 0x5e, 0xa3, 0xed, 0xcb, 0xb2, 0xdf, 0xcf, 0x6d, - 0x3d, 0x29, 0x3b, 0xda, 0x2c, 0xcd, 0x3e, 0x44, 0xc5, 0x14, 0xee, 0xfa, 0x44, 0xf3, 0x57, 0xa1, 0xbe, 0x6a, 0xcb, - 0x9c, 0x8f, 0x38, 0xe2, 0x62, 0xe4, 0xa4, 0xfe, 0x45, 0x4d, 0xbd, 0x12, 0xf7, 0xab, 0x4a, 0xbe, 0x13, 0xc6, 0x8a, - 0xd1, 0x01, 0xf5, 0xa7, 0x4a, 0xe5, 0xfd, 0xb2, 0x00, 0xb8, 0x27, 0xc1, 0x3e, 0x81, 0x7d, 0x85, 0x46, 0xf8, 0x6d, - 0x09, 0xf8, 0x37, 0x8a, 0x1b, 0xb0, 0x0a, 0x0c, 0x30, 0x9a, 0x6c, 0xcf, 0x69, 0x02, 0x07, 0x9c, 0xd0, 0x2a, 0x0a, - 0x2a, 0xcc, 0xd0, 0x50, 0x5b, 0x18, 0x3d, 0x45, 0x19, 0xb7, 0xca, 0xec, 0xdd, 0x18, 0x3b, 0x2d, 0xf0, 0x1a, 0xfe, - 0x7c, 0x5e, 0xe8, 0x61, 0xa3, 0x0e, 0xd2, 0xa3, 0x93, 0x98, 0xfe, 0xb8, 0x85, 0x93, 0x9b, 0x85, 0xb3, 0xac, 0x59, - 0x02, 0xdd, 0x81, 0x0b, 0x62, 0xdc, 0xef, 0xe7, 0x70, 0x64, 0x9a, 0x91, 0x2f, 0x58, 0x4e, 0x63, 0xb6, 0xa4, 0xda, - 0xd3, 0xee, 0xb2, 0x0a, 0x73, 0xba, 0xb4, 0x32, 0xde, 0x94, 0x81, 0xca, 0x68, 0xbb, 0x0d, 0xe1, 0x4f, 0xb7, 0xb5, - 0x4b, 0x3a, 0x5f, 0x42, 0x06, 0xf8, 0x03, 0x12, 0x51, 0xc4, 0xbe, 0xfe, 0xb7, 0x1a, 0xa7, 0xf4, 0x44, 0x69, 0xcd, - 0x12, 0xba, 0x66, 0xba, 0x7e, 0x7a, 0xc1, 0xd6, 0x8d, 0xa5, 0xb0, 0xdd, 0x86, 0xcd, 0x04, 0xa6, 0x39, 0x57, 0x32, - 0xbd, 0x40, 0x9d, 0x14, 0x50, 0xb1, 0xf0, 0x02, 0x97, 0x5f, 0x4a, 0x28, 0x34, 0x77, 0xbe, 0x5c, 0x18, 0x25, 0x26, - 0xb4, 0x4a, 0x7e, 0xf9, 0x50, 0x99, 0xaf, 0x8d, 0x47, 0xdc, 0xbf, 0xd2, 0x30, 0x31, 0x45, 0xa2, 0x42, 0x74, 0xf6, - 0x1b, 0xc8, 0x72, 0x04, 0xe0, 0x58, 0x9e, 0xca, 0x9a, 0xfe, 0x98, 0x42, 0x1c, 0x74, 0x68, 0xd0, 0xbb, 0x42, 0x5e, - 0x65, 0x25, 0x0f, 0xf1, 0x9e, 0xe0, 0x69, 0x46, 0xef, 0x37, 0xf8, 0xd0, 0xd6, 0x1e, 0x3d, 0x41, 0x36, 0x9e, 0x72, - 0xbf, 0xfe, 0x4e, 0x84, 0x73, 0x88, 0x56, 0xb9, 0xa0, 0x5a, 0x5d, 0xed, 0x00, 0xa8, 0x3c, 0xdb, 0xab, 0x47, 0x70, - 0xba, 0xe9, 0xeb, 0x5b, 0x15, 0x3a, 0x73, 0x00, 0x69, 0x0f, 0xc9, 0xba, 0xe6, 0x7a, 0x07, 0xb8, 0x23, 0xb1, 0x5a, - 0x03, 0x8d, 0x75, 0x5b, 0xb3, 0xd3, 0x1e, 0xc5, 0x63, 0x22, 0x33, 0x63, 0x91, 0x62, 0xcc, 0xdd, 0x3a, 0x2d, 0x8a, - 0x36, 0x68, 0x86, 0xb0, 0x7b, 0xd7, 0xe1, 0xeb, 0x56, 0x84, 0xf5, 0xfb, 0x6d, 0x5f, 0x60, 0x34, 0x8c, 0xb9, 0x76, - 0xcf, 0x33, 0x74, 0xc3, 0x06, 0xdb, 0xc8, 0x79, 0x88, 0x7c, 0x98, 0xa9, 0x03, 0x51, 0xd6, 0xd6, 0x80, 0xed, 0x11, - 0xd7, 0x9b, 0x56, 0xf1, 0xf3, 0x2a, 0xe6, 0x6c, 0xcf, 0x1a, 0xa7, 0xb4, 0xbe, 0xc6, 0x35, 0xc7, 0x55, 0x21, 0xa2, - 0xb6, 0x9e, 0xf1, 0x30, 0xec, 0x7c, 0x81, 0x3b, 0xb3, 0xc2, 0xe0, 0x45, 0x58, 0x2a, 0xd9, 0xa9, 0x5c, 0x7f, 0x0e, - 0x5b, 0x1c, 0xa4, 0xf2, 0xa5, 0xd7, 0xdf, 0x7f, 0xf9, 0xe2, 0x0b, 0x74, 0x53, 0x73, 0x7e, 0x04, 0x41, 0x26, 0xd0, - 0x21, 0x4b, 0xa9, 0x1e, 0xbf, 0x2b, 0x80, 0xda, 0xc3, 0x3c, 0x7c, 0x57, 0x30, 0x11, 0x5f, 0x67, 0x97, 0x71, 0x25, - 0x8b, 0xd1, 0x35, 0x17, 0xa9, 0x2c, 0xac, 0xd4, 0x38, 0x38, 0x5e, 0xad, 0x72, 0x1e, 0x80, 0xa9, 0xbc, 0x65, 0x94, - 0x6d, 0x65, 0x99, 0x1e, 0x5c, 0x2d, 0x4f, 0xaf, 0xb4, 0xe8, 0xbc, 0xbc, 0xbe, 0x0c, 0x22, 0xfc, 0x75, 0x6e, 0x7e, - 0x5c, 0xc5, 0xe5, 0xc7, 0x20, 0xb2, 0x36, 0x75, 0xe6, 0x07, 0x4a, 0xe5, 0xc1, 0x7f, 0x0a, 0x64, 0xba, 0xdf, 0x15, - 0x60, 0x99, 0x6d, 0x2b, 0x3e, 0x8c, 0xb1, 0xd6, 0xe1, 0x84, 0xcc, 0x54, 0x89, 0xde, 0xbb, 0x64, 0x5d, 0x80, 0xb5, - 0x9f, 0xc2, 0x32, 0x56, 0xb9, 0x66, 0x58, 0x99, 0xaa, 0xc8, 0xcc, 0xca, 0x9a, 0xed, 0x87, 0xd6, 0x89, 0x66, 0x8e, - 0xde, 0x02, 0xfa, 0x81, 0xec, 0x5f, 0xd2, 0x72, 0xcd, 0x3c, 0x1f, 0x9b, 0xc6, 0xeb, 0x47, 0xfb, 0x97, 0x6e, 0xc1, - 0xde, 0xda, 0x3b, 0x39, 0x0a, 0x13, 0xc1, 0xb3, 0xd6, 0x8c, 0x2f, 0xf2, 0xac, 0x80, 0x95, 0x33, 0x19, 0x8f, 0xa9, - 0xb7, 0xb4, 0x5a, 0x37, 0x47, 0x87, 0xe4, 0x9a, 0x3d, 0xae, 0x1e, 0x73, 0xb2, 0xcf, 0x5b, 0xa6, 0xb6, 0x6d, 0xeb, - 0x38, 0x4f, 0x93, 0xaf, 0x4c, 0xf7, 0xc5, 0xda, 0x46, 0x44, 0x57, 0xce, 0x7d, 0xce, 0x2b, 0xb8, 0xf5, 0x4d, 0x69, - 0xe8, 0xb5, 0x04, 0x20, 0x3a, 0x6d, 0xc0, 0x5f, 0xb0, 0x72, 0x3d, 0xaa, 0x78, 0x59, 0x81, 0x84, 0x05, 0x45, 0x78, - 0x53, 0xec, 0x4d, 0xe1, 0x6e, 0x9c, 0x9e, 0xc3, 0x0e, 0x5c, 0x4c, 0xd1, 0x1d, 0x27, 0x26, 0xb3, 0xd2, 0x68, 0x45, - 0x23, 0xfd, 0xcb, 0xf5, 0x25, 0xd6, 0x7d, 0xd1, 0xca, 0x3c, 0x9b, 0x53, 0x61, 0xb1, 0xbb, 0xca, 0xa5, 0x13, 0xf5, - 0x5b, 0x26, 0x5c, 0xb9, 0x12, 0x04, 0x64, 0x5a, 0xb0, 0x5e, 0x61, 0x76, 0x91, 0x5c, 0x03, 0x21, 0x03, 0xc3, 0xd7, - 0x60, 0x2d, 0x4a, 0x6e, 0xac, 0x60, 0xbd, 0x7b, 0xbe, 0x4e, 0x10, 0x52, 0xf0, 0xc0, 0x4d, 0xd0, 0x0f, 0xad, 0x9b, - 0xb7, 0xa3, 0x44, 0x19, 0xc4, 0xe3, 0xd6, 0x4e, 0x39, 0x48, 0x20, 0x00, 0xf7, 0x54, 0x85, 0xe0, 0x50, 0x20, 0xeb, - 0xe0, 0x6a, 0xc6, 0x11, 0x5c, 0x5d, 0x39, 0x73, 0x71, 0x03, 0xb0, 0xae, 0xfc, 0xb9, 0x6c, 0x70, 0x61, 0x3d, 0xa2, - 0xca, 0x9c, 0x71, 0x8a, 0x41, 0x8c, 0x2c, 0x41, 0x5f, 0x59, 0x4a, 0x7b, 0x09, 0x9a, 0xc6, 0x2b, 0xb6, 0x52, 0x3e, - 0x00, 0xf4, 0x9c, 0xad, 0x94, 0xb1, 0x3f, 0x7e, 0x7d, 0xc6, 0x56, 0x5a, 0x1a, 0x3c, 0xbd, 0x9a, 0x9d, 0xcf, 0xce, - 0x06, 0xec, 0x20, 0x0a, 0xb5, 0x01, 0x43, 0xe0, 0x90, 0xf8, 0x83, 0x41, 0xa8, 0xf1, 0x4e, 0x06, 0x2a, 0x20, 0x16, - 0xf1, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, 0x43, 0x0c, 0x7e, 0xd5, 0x7c, 0x41, 0x02, 0x42, 0x4d, 0x69, 0xe8, 0xf2, - 0x18, 0x0e, 0x27, 0x7b, 0x13, 0x48, 0xc5, 0xcc, 0x4c, 0x15, 0xc6, 0xc6, 0x24, 0x82, 0x78, 0xa7, 0x9d, 0xf5, 0x42, - 0xb9, 0xdd, 0x35, 0x1a, 0xc8, 0x95, 0xc1, 0x17, 0x55, 0x3c, 0xd9, 0x1b, 0x76, 0x55, 0x8c, 0xa3, 0x70, 0x6d, 0x94, - 0x6f, 0x67, 0x87, 0x00, 0x5e, 0x7b, 0x36, 0xf4, 0xe5, 0x12, 0x67, 0xfb, 0x4f, 0xc9, 0xe3, 0xa7, 0x84, 0x9e, 0xb1, - 0xb3, 0xaf, 0x9e, 0xd2, 0x33, 0x45, 0x4e, 0xf6, 0x26, 0xd1, 0x35, 0xb3, 0x98, 0x2f, 0x07, 0xaa, 0x09, 0xf4, 0x72, - 0xb4, 0x16, 0x6a, 0x81, 0x69, 0x87, 0xa6, 0xf0, 0xdb, 0xf1, 0x5e, 0x30, 0xb8, 0x6e, 0x37, 0xfd, 0xba, 0xdd, 0x56, - 0xcf, 0xab, 0x6b, 0xef, 0x20, 0xda, 0x2d, 0x66, 0xf2, 0xf7, 0xf1, 0x9e, 0x9b, 0x03, 0xac, 0xef, 0xe1, 0x31, 0x31, - 0x4d, 0xda, 0x19, 0x15, 0xbf, 0xa6, 0x27, 0xd8, 0x87, 0x66, 0x91, 0x1d, 0x7d, 0x18, 0xfe, 0x5b, 0x9d, 0xa8, 0xcf, - 0xbe, 0x3a, 0x00, 0x72, 0x04, 0x32, 0x50, 0x2c, 0x11, 0xcc, 0x70, 0xa0, 0x29, 0xa0, 0x20, 0xd3, 0xe3, 0x4e, 0xf5, - 0xf0, 0xab, 0x51, 0x53, 0x33, 0x72, 0x0d, 0x53, 0x83, 0x6d, 0xc1, 0x0f, 0x54, 0x37, 0xf4, 0x37, 0x1a, 0xdd, 0x48, - 0x3b, 0x99, 0x99, 0x97, 0xd4, 0xc6, 0x75, 0xbb, 0x86, 0x00, 0xc6, 0x0e, 0x5e, 0x50, 0xb2, 0xaf, 0x0f, 0x2f, 0xf7, - 0x70, 0x15, 0x01, 0x4a, 0x16, 0x0b, 0xbe, 0x1e, 0x5c, 0xea, 0xcd, 0xbd, 0x17, 0x90, 0xc1, 0xd7, 0xc1, 0xd1, 0xd7, - 0x03, 0x39, 0x08, 0x0e, 0xf7, 0x2f, 0x8f, 0x02, 0x67, 0xdc, 0x0f, 0x21, 0x1e, 0x55, 0x45, 0x31, 0x13, 0xa6, 0x8a, - 0xc4, 0xd6, 0x9e, 0xdb, 0x7a, 0x95, 0xf1, 0x19, 0x4d, 0xa7, 0x16, 0xf9, 0x3b, 0x4c, 0x59, 0x6c, 0x7e, 0x07, 0x13, - 0x7e, 0x15, 0x44, 0x2e, 0x08, 0xea, 0x2c, 0x8f, 0x62, 0xba, 0x64, 0xb7, 0x22, 0x4c, 0x69, 0xb2, 0x9f, 0x13, 0x12, - 0x85, 0x4b, 0x05, 0x9e, 0xa7, 0x5e, 0x27, 0x10, 0xc7, 0xd5, 0x7d, 0x7e, 0x2b, 0xc2, 0x25, 0xcd, 0xf7, 0x13, 0xd2, - 0x2a, 0xc2, 0x45, 0x64, 0xd9, 0xd4, 0xf4, 0x82, 0x85, 0x2b, 0x7a, 0x09, 0xcc, 0x94, 0x5c, 0x87, 0x97, 0xc0, 0xe5, - 0xad, 0xe7, 0xab, 0x05, 0xbb, 0x6c, 0x48, 0xdf, 0x0c, 0x5f, 0x7c, 0x61, 0x7d, 0xf2, 0x80, 0x87, 0x74, 0x7e, 0x78, - 0x29, 0xd8, 0x00, 0x5c, 0x67, 0xfc, 0xe6, 0x3b, 0x79, 0xab, 0xe7, 0xa5, 0x3d, 0xc5, 0x38, 0x33, 0xed, 0xc4, 0xa4, - 0x9d, 0x90, 0xfb, 0xf7, 0xed, 0x4d, 0x6c, 0x4e, 0xf6, 0x32, 0x5a, 0x2b, 0x97, 0x55, 0xcb, 0x90, 0x14, 0x6b, 0x86, - 0xfc, 0x3d, 0x4a, 0x4e, 0xad, 0xc0, 0x93, 0x5d, 0xf0, 0x2a, 0x59, 0xfa, 0x07, 0x95, 0xb5, 0x1a, 0xb0, 0xc7, 0x88, - 0x65, 0xa1, 0x70, 0xec, 0xdf, 0x64, 0xac, 0x58, 0xfb, 0x02, 0x8d, 0x18, 0xb9, 0xb7, 0x37, 0x19, 0xf3, 0x62, 0xae, - 0x26, 0x6b, 0x2f, 0x54, 0x9d, 0x97, 0x9e, 0xb7, 0x78, 0x2f, 0xa7, 0xd4, 0x30, 0x12, 0xd1, 0xbd, 0xb1, 0x32, 0xa3, - 0x54, 0x89, 0x5a, 0x83, 0x46, 0x04, 0x1b, 0xbb, 0xe0, 0x97, 0xe0, 0x84, 0xca, 0x3d, 0x75, 0xb6, 0x6f, 0xa7, 0x54, - 0x7a, 0xc0, 0xb2, 0xd4, 0xa8, 0xca, 0xdd, 0x32, 0x93, 0xac, 0x1a, 0x04, 0xa3, 0x3f, 0x4b, 0x29, 0x66, 0x78, 0x67, - 0x64, 0xc1, 0x14, 0xac, 0x04, 0x55, 0x2d, 0xc3, 0x72, 0xc8, 0x51, 0x8b, 0x67, 0x7c, 0x52, 0xa5, 0xfe, 0xd1, 0x11, - 0x24, 0x77, 0xb9, 0x6e, 0x05, 0xc9, 0x7d, 0x3a, 0x7e, 0xaa, 0x07, 0x3a, 0x5d, 0x6b, 0xc7, 0x43, 0x9f, 0xdf, 0x46, - 0x7c, 0x6d, 0xdd, 0x7b, 0xaa, 0xb5, 0x0a, 0x65, 0xa0, 0xc5, 0x8a, 0xca, 0x95, 0x5a, 0xd2, 0xfb, 0x5d, 0x04, 0xc0, - 0x22, 0x36, 0x66, 0xe3, 0x5d, 0xdb, 0xac, 0x10, 0x34, 0xba, 0xec, 0x68, 0x13, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, - 0xd0, 0xf8, 0x88, 0x95, 0xfd, 0x7e, 0x7e, 0x04, 0xf4, 0x54, 0x1b, 0x31, 0x15, 0x70, 0xe4, 0x7f, 0x69, 0x45, 0xa6, - 0x28, 0xb0, 0x59, 0x53, 0x77, 0x6b, 0x2c, 0x23, 0xd1, 0x97, 0x29, 0x5d, 0x9e, 0xf0, 0x0c, 0x98, 0xd6, 0xeb, 0x96, - 0xe3, 0xca, 0xae, 0xe2, 0xc8, 0x53, 0x61, 0x59, 0x71, 0x5e, 0x85, 0xe3, 0xad, 0xc7, 0x37, 0xd8, 0x37, 0x6c, 0xda, - 0x85, 0x3f, 0x84, 0xb0, 0x10, 0xde, 0x64, 0x70, 0x1b, 0xd1, 0x76, 0x12, 0xa8, 0xbc, 0x31, 0xd7, 0x09, 0x65, 0x73, - 0xbb, 0x5e, 0x7b, 0x06, 0xe9, 0xc4, 0x1c, 0x28, 0xd5, 0x08, 0x5a, 0xa3, 0x59, 0x50, 0x35, 0xe2, 0x91, 0xe3, 0xe1, - 0x9d, 0x41, 0xac, 0x96, 0x2f, 0x69, 0x2a, 0x45, 0x03, 0x30, 0x2e, 0x80, 0xcb, 0xd3, 0xaf, 0xef, 0x7f, 0x3e, 0xe5, - 0x71, 0x91, 0x2c, 0xdf, 0xc5, 0x45, 0x7c, 0x55, 0x86, 0x1b, 0x35, 0x46, 0x71, 0x4d, 0xa6, 0x62, 0xc0, 0xa4, 0x59, - 0x49, 0xcd, 0x5d, 0xa9, 0x09, 0x31, 0xd6, 0x99, 0xac, 0xcb, 0x4a, 0x5e, 0x35, 0x2a, 0x5d, 0x17, 0x19, 0x7e, 0xdc, - 0xf2, 0x39, 0xdd, 0x07, 0x20, 0x4f, 0xe3, 0x42, 0x1a, 0x49, 0x5d, 0x88, 0x31, 0x17, 0xf1, 0xba, 0x3e, 0x1e, 0x37, - 0xba, 0x5e, 0xb2, 0x67, 0xe3, 0x27, 0xd3, 0x37, 0x59, 0x98, 0x0d, 0x04, 0x19, 0x55, 0x4b, 0x2e, 0x5a, 0xa6, 0x9c, - 0xca, 0x24, 0x00, 0x7d, 0x3c, 0x7b, 0x8c, 0x1d, 0x8c, 0xc7, 0x64, 0xd3, 0x16, 0x0f, 0xf0, 0x70, 0xb9, 0x0e, 0x0b, - 0x32, 0xd3, 0x75, 0x44, 0x81, 0xe0, 0xb7, 0x55, 0x00, 0x48, 0x8e, 0xb6, 0x2a, 0xc3, 0xa5, 0xb1, 0x67, 0xe3, 0x09, - 0x95, 0xd8, 0xed, 0x90, 0xd4, 0x5e, 0x85, 0x6e, 0xe6, 0xa5, 0xef, 0x51, 0x24, 0x8d, 0xcb, 0xd2, 0x4e, 0xa5, 0x52, - 0xed, 0x99, 0x99, 0xeb, 0x1a, 0xc4, 0x60, 0x08, 0x75, 0xdd, 0xa5, 0x57, 0xf7, 0x6e, 0x73, 0xad, 0xd9, 0x0e, 0x78, - 0xaf, 0x41, 0x33, 0x94, 0xbc, 0xc5, 0xbc, 0x75, 0x45, 0xd4, 0x74, 0xb5, 0x06, 0xb3, 0x62, 0x94, 0x2d, 0x45, 0xe9, - 0x9a, 0x82, 0x52, 0x30, 0xba, 0x58, 0x7b, 0x0b, 0xf7, 0x8d, 0x6c, 0x5c, 0x58, 0x32, 0xbd, 0x5a, 0x94, 0x94, 0x50, - 0xdd, 0x54, 0x8c, 0x94, 0x30, 0x52, 0x1a, 0x9e, 0xca, 0xf7, 0x02, 0x8f, 0xf3, 0x3c, 0x88, 0x5a, 0x5e, 0x60, 0xc7, - 0x15, 0x39, 0x06, 0x47, 0x2f, 0x93, 0xd3, 0x50, 0xe0, 0x1f, 0x33, 0x05, 0x62, 0x3a, 0x54, 0xf7, 0x1b, 0xdc, 0xfc, - 0xff, 0x28, 0x58, 0xe0, 0xf1, 0xad, 0x97, 0xb8, 0x8d, 0xfe, 0x51, 0xf8, 0xb4, 0xf4, 0xb9, 0xf4, 0x5d, 0x5d, 0x3c, - 0x69, 0x6f, 0x36, 0x4a, 0x96, 0x59, 0x9e, 0xbe, 0x95, 0x29, 0x07, 0x91, 0x19, 0x5a, 0x83, 0xb2, 0x23, 0xd1, 0xb8, - 0xe1, 0x81, 0x11, 0x63, 0xe3, 0xc6, 0xf7, 0x63, 0x06, 0xb2, 0x61, 0xb0, 0xfa, 0x66, 0xa9, 0x4c, 0xd6, 0x57, 0x80, - 0x29, 0xa2, 0xe4, 0x27, 0x2f, 0x73, 0x0e, 0x4f, 0xa1, 0xbe, 0x7e, 0x81, 0xdb, 0x5c, 0xe9, 0xfb, 0x9c, 0xff, 0x98, - 0xd1, 0x1f, 0x11, 0xe8, 0x24, 0x5e, 0x81, 0xdc, 0xe3, 0x39, 0xd4, 0x8d, 0x30, 0xb5, 0x1c, 0x83, 0x03, 0x21, 0x1a, - 0x88, 0xa8, 0x58, 0xa0, 0xa0, 0x2e, 0x0c, 0xb0, 0x86, 0xba, 0x60, 0x0e, 0xcf, 0x73, 0x99, 0x7c, 0x9c, 0x1a, 0x9f, - 0xf9, 0x61, 0x8c, 0x31, 0x93, 0x83, 0x41, 0x58, 0xcd, 0x82, 0xe1, 0x78, 0x34, 0x39, 0x78, 0x06, 0xe7, 0x76, 0x30, - 0x0e, 0xc8, 0x20, 0xa8, 0xcb, 0x55, 0x2c, 0x68, 0x79, 0x7d, 0x69, 0xcb, 0xc0, 0x8f, 0xeb, 0x60, 0xf0, 0x8f, 0xc2, - 0x53, 0xbc, 0x83, 0xe6, 0xe4, 0x4c, 0x86, 0x60, 0x63, 0xbf, 0x26, 0x20, 0x29, 0xeb, 0x69, 0x7e, 0x52, 0x1f, 0x6e, - 0x4c, 0x69, 0xff, 0xcc, 0xe1, 0x05, 0x87, 0x1d, 0x12, 0x28, 0x90, 0xc6, 0xd3, 0x6c, 0xf4, 0x5a, 0x29, 0x72, 0xdf, - 0x15, 0x1c, 0xee, 0xcc, 0x3d, 0x67, 0x7a, 0xe4, 0x14, 0x12, 0xcd, 0x2c, 0xe0, 0x46, 0xfe, 0x5a, 0x5c, 0xc7, 0x79, - 0x96, 0xee, 0x35, 0xdf, 0xec, 0x95, 0x77, 0xa2, 0x8a, 0x6f, 0x47, 0x81, 0xb1, 0x26, 0xe4, 0xbe, 0xea, 0x09, 0xd0, - 0x13, 0x60, 0x0b, 0x80, 0x01, 0xf1, 0x8e, 0x99, 0xc9, 0x8c, 0x47, 0xe0, 0x11, 0xd8, 0xf4, 0x81, 0x2c, 0xee, 0x9c, - 0x4b, 0x92, 0xbf, 0x99, 0x4a, 0x7b, 0xd5, 0x2b, 0x77, 0x0a, 0xb2, 0x5e, 0x6d, 0xe5, 0xae, 0x5b, 0x9f, 0x7d, 0xd3, - 0xe1, 0x15, 0x78, 0x2e, 0xc1, 0x2d, 0xb2, 0xdf, 0x6f, 0x0a, 0x2a, 0x85, 0x51, 0x11, 0xef, 0x24, 0xd7, 0xe8, 0xdf, - 0xee, 0x8d, 0x8d, 0x22, 0xb9, 0xe5, 0xc3, 0x03, 0xa8, 0x33, 0x79, 0x57, 0xdc, 0xce, 0x21, 0x6a, 0xeb, 0x6e, 0x3c, - 0xb0, 0xda, 0xa0, 0x5d, 0xd6, 0x1c, 0xc1, 0x85, 0x17, 0x7b, 0x19, 0x8c, 0x05, 0xce, 0xca, 0x48, 0xa9, 0x71, 0x0d, - 0xa9, 0x05, 0x9f, 0xe4, 0xe9, 0x3d, 0x64, 0xa9, 0x27, 0x41, 0x91, 0xe3, 0x59, 0x0c, 0x99, 0xc6, 0xdb, 0xc0, 0xe3, - 0x77, 0x32, 0x04, 0x69, 0xda, 0x76, 0xdb, 0x1c, 0x81, 0xb2, 0x7b, 0x60, 0x4a, 0x52, 0xd7, 0xc6, 0xd4, 0x40, 0x43, - 0xed, 0xa1, 0x46, 0x2a, 0xe2, 0xec, 0xe8, 0x0d, 0xe8, 0x10, 0xc1, 0xf7, 0x3b, 0xcd, 0xca, 0x8e, 0x17, 0x13, 0x82, - 0x27, 0xef, 0xcb, 0xdb, 0xac, 0xac, 0xca, 0xe8, 0x7d, 0x8a, 0x86, 0x50, 0x89, 0x14, 0xd1, 0x2b, 0x88, 0xa7, 0x57, - 0xe2, 0xef, 0x32, 0xfa, 0x39, 0xa5, 0x71, 0x9a, 0x62, 0xfa, 0x8b, 0x02, 0x7e, 0x3e, 0x07, 0x54, 0x47, 0xdc, 0x09, - 0xd1, 0xb9, 0x04, 0x7b, 0x35, 0x88, 0x66, 0x55, 0x71, 0xc0, 0xd0, 0x8c, 0x6e, 0x05, 0x45, 0x8c, 0x36, 0xcc, 0xfe, - 0x43, 0x81, 0x42, 0x21, 0x55, 0xcc, 0x77, 0xc2, 0x3e, 0x44, 0x3f, 0x62, 0x91, 0xc7, 0xef, 0x5e, 0x9b, 0x21, 0x8d, - 0xee, 0x24, 0xd5, 0x5b, 0x1b, 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xae, 0xe9, 0x59, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, - 0x4f, 0xbc, 0x7b, 0xfd, 0x5c, 0x59, 0x98, 0xbc, 0xc8, 0x40, 0x71, 0x70, 0xfc, 0xee, 0xf5, 0x1b, 0x99, 0xae, 0x73, - 0x1e, 0x9d, 0x49, 0x24, 0xad, 0xc7, 0xef, 0x5e, 0xff, 0x82, 0xe6, 0x5e, 0x3f, 0x17, 0xf0, 0xfe, 0x15, 0xf0, 0x96, - 0x51, 0xbc, 0x86, 0x3e, 0xa9, 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd5, 0x5a, 0x46, 0xbf, 0xa6, 0xb5, 0x27, 0xad, 0xfa, - 0x67, 0xe1, 0x53, 0x3b, 0x4f, 0xc0, 0x73, 0x9b, 0x67, 0xe2, 0x63, 0x64, 0x45, 0x3b, 0x41, 0xf4, 0xf5, 0xde, 0xed, - 0x55, 0x2e, 0xca, 0x08, 0x5f, 0x30, 0xb4, 0x0b, 0x8a, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0x46, 0x37, 0x4f, 0x46, 0xb2, - 0xb8, 0xdc, 0x9f, 0x7c, 0xfb, 0xed, 0xb7, 0xfb, 0xf8, 0x36, 0xf8, 0xba, 0xed, 0xf6, 0x5e, 0x11, 0x3e, 0x60, 0x01, - 0x22, 0x54, 0x7f, 0x0d, 0x57, 0x14, 0xd0, 0xc2, 0x0d, 0xbe, 0x0e, 0xbe, 0xd6, 0x87, 0xce, 0xd7, 0x87, 0xe5, 0xf5, - 0xa5, 0x2a, 0xbf, 0xab, 0xe4, 0x83, 0xf1, 0x78, 0xbc, 0x0f, 0x12, 0xa8, 0xaf, 0x07, 0x7c, 0x10, 0x1c, 0x05, 0x83, - 0x0c, 0x2e, 0x34, 0xe5, 0xf5, 0xe5, 0x51, 0xe0, 0x99, 0xe6, 0x36, 0x58, 0x44, 0x07, 0xe2, 0x12, 0xec, 0x5f, 0xd2, - 0xe0, 0xeb, 0x80, 0xb8, 0x94, 0xaf, 0x20, 0xe5, 0xab, 0x83, 0x67, 0x7e, 0xda, 0xff, 0x52, 0x69, 0x4f, 0xfc, 0xb4, - 0x43, 0x4c, 0x7b, 0xf2, 0xdc, 0x4f, 0x3b, 0x52, 0x69, 0x2f, 0xfd, 0xb4, 0xff, 0x5d, 0x0e, 0x20, 0x75, 0xcf, 0xb7, - 0xfe, 0x3b, 0xf7, 0x5a, 0x83, 0xa7, 0x50, 0x94, 0x5d, 0xc5, 0x97, 0x1c, 0x1a, 0x3d, 0xb8, 0xbd, 0xca, 0x69, 0x30, - 0xc0, 0xf6, 0x7a, 0x26, 0x21, 0xde, 0x07, 0x5f, 0xaf, 0x8b, 0x3c, 0x0c, 0xbe, 0x1e, 0x60, 0x21, 0x83, 0xaf, 0x03, - 0xf2, 0xb5, 0x31, 0x90, 0x11, 0x6c, 0x13, 0xb8, 0x50, 0xa4, 0x43, 0x1b, 0x20, 0xcc, 0x97, 0xc6, 0xd5, 0xf4, 0xaf, - 0xa2, 0x3b, 0x1b, 0xde, 0x12, 0x95, 0x9b, 0x6e, 0x50, 0xd3, 0x13, 0xf0, 0x4e, 0x80, 0x46, 0x45, 0xc1, 0x75, 0x5c, - 0x84, 0xc3, 0x61, 0x79, 0x7d, 0x49, 0xc0, 0x2e, 0x73, 0xc5, 0xe3, 0x2a, 0x0a, 0x84, 0x1c, 0xaa, 0x9f, 0x81, 0x8a, - 0x7c, 0x15, 0x20, 0x20, 0x12, 0xfc, 0x17, 0xd4, 0xf4, 0x9d, 0x64, 0x9b, 0x60, 0x78, 0xc3, 0xcf, 0x3f, 0x66, 0xd5, - 0x50, 0x89, 0x16, 0xaf, 0x05, 0x85, 0x1f, 0xf0, 0xd7, 0x55, 0x1d, 0xfd, 0x05, 0x6e, 0xdc, 0x4d, 0x0d, 0xfb, 0x3b, - 0xe9, 0x58, 0xd4, 0x77, 0x72, 0x9e, 0x2d, 0xa6, 0xad, 0x03, 0xfd, 0x44, 0x92, 0x6a, 0x9e, 0x0d, 0x82, 0x61, 0x30, - 0xe0, 0x0b, 0x76, 0x22, 0xe7, 0xdc, 0x33, 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x65, 0x03, 0xf0, 0x4d, 0x41, 0x7e, - 0x64, 0xff, 0xbf, 0xe7, 0x43, 0x14, 0x1e, 0x0e, 0x1e, 0xed, 0x93, 0x59, 0xb0, 0xba, 0x45, 0x8f, 0xce, 0x28, 0xc8, - 0xc4, 0x92, 0x17, 0x59, 0xe5, 0x2d, 0x95, 0xbb, 0x75, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x15, 0x8b, 0x40, 0x9d, - 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb0, 0x37, 0x1c, - 0xee, 0x05, 0x03, 0xa7, 0xce, 0x1d, 0x04, 0x7b, 0xc3, 0xe1, 0x51, 0xe0, 0xee, 0x43, 0xd9, 0xc8, 0xdd, 0x19, 0x69, - 0xc1, 0xfe, 0x59, 0x84, 0x25, 0x05, 0xf1, 0x98, 0xd4, 0xe2, 0x2f, 0x0d, 0x2e, 0x33, 0x00, 0xe8, 0x23, 0x25, 0x01, - 0x33, 0xb0, 0x32, 0x03, 0x08, 0xcd, 0x4d, 0x63, 0x76, 0x06, 0xcc, 0x23, 0x70, 0xcc, 0x23, 0x64, 0x1c, 0x00, 0xb1, - 0x24, 0xc0, 0xb9, 0x0b, 0xa2, 0x58, 0x17, 0xf2, 0x08, 0x40, 0xef, 0xf1, 0x27, 0x31, 0xa5, 0x60, 0x92, 0x8e, 0x55, - 0x08, 0x82, 0x38, 0x3e, 0xbb, 0x16, 0xad, 0xc9, 0x59, 0xa2, 0x83, 0x19, 0x49, 0x80, 0x0d, 0x31, 0xb0, 0x73, 0x70, - 0x3f, 0x07, 0xa5, 0x87, 0xd5, 0x3b, 0x21, 0x17, 0x7c, 0xc7, 0x3d, 0xd9, 0x2c, 0x5c, 0x3d, 0xe1, 0x20, 0xb8, 0xe3, - 0x9a, 0x05, 0x18, 0x55, 0xc5, 0xba, 0xac, 0x78, 0xfa, 0xe1, 0x6e, 0x05, 0xb1, 0xef, 0x70, 0x40, 0xdf, 0xc9, 0x3c, - 0x4b, 0xee, 0x42, 0x67, 0xcf, 0xb5, 0x51, 0xe9, 0x3f, 0x7c, 0x78, 0xf3, 0x73, 0x04, 0x22, 0xc7, 0xda, 0x50, 0xfa, - 0x3b, 0x8e, 0x67, 0x93, 0x1f, 0xe1, 0xc9, 0xdf, 0xd8, 0x77, 0xdc, 0x9e, 0x1e, 0xfd, 0x3e, 0xd4, 0x4d, 0xef, 0xf8, - 0xec, 0x8e, 0x8f, 0x5c, 0x71, 0xa8, 0xae, 0x70, 0x5f, 0xdf, 0xac, 0x7d, 0x23, 0xa4, 0x87, 0xe7, 0x99, 0xf2, 0xc6, - 0xfc, 0x68, 0x07, 0xc3, 0x20, 0x98, 0x6a, 0xa1, 0x24, 0x44, 0xdd, 0x60, 0x4a, 0xc0, 0x10, 0xed, 0xe9, 0x65, 0x35, - 0x45, 0xce, 0x4d, 0x8d, 0x2c, 0xbc, 0x1f, 0x30, 0x2d, 0x74, 0x68, 0xe4, 0x50, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc2, - 0x6f, 0x95, 0x30, 0xfd, 0x6a, 0x51, 0x39, 0x07, 0xd1, 0x3d, 0x30, 0xc6, 0x15, 0xbc, 0x80, 0xae, 0xb0, 0xeb, 0xb5, - 0x8a, 0x8a, 0x81, 0xe0, 0x71, 0xc8, 0x01, 0x7a, 0xd8, 0x05, 0x2d, 0x2b, 0x4b, 0x75, 0xab, 0x72, 0x96, 0x2a, 0xea, - 0x32, 0x94, 0x95, 0xb1, 0xc2, 0x7c, 0x2f, 0xd9, 0x0f, 0x05, 0x7a, 0x96, 0x4f, 0x45, 0x17, 0xbc, 0x10, 0x4a, 0xb0, - 0x5c, 0xd7, 0x3b, 0x11, 0x88, 0x3a, 0x3f, 0xf4, 0xae, 0xfa, 0x1a, 0xc7, 0x8e, 0xa7, 0x6f, 0x64, 0xca, 0xb5, 0x09, - 0x85, 0xe6, 0xf3, 0xa5, 0xaf, 0x98, 0x28, 0xd8, 0x0d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd6, 0x7a, 0x33, 0x28, - 0xd1, 0x31, 0xaf, 0x51, 0x70, 0xad, 0x14, 0x0a, 0x46, 0x7b, 0x1b, 0x7f, 0x86, 0x23, 0xb7, 0xba, 0x3d, 0xf4, 0x7e, - 0xab, 0xe2, 0xcb, 0xb7, 0xe8, 0xdb, 0x69, 0x7f, 0x8e, 0x2a, 0xf9, 0xeb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, - 0xe2, 0xd2, 0x42, 0x3d, 0xa7, 0xef, 0x8e, 0xdf, 0x82, 0x1f, 0x25, 0xfe, 0xfe, 0xed, 0xfb, 0xa0, 0x26, 0xd3, 0x78, - 0x56, 0x98, 0x0f, 0x6d, 0x0e, 0x08, 0x4d, 0xe2, 0xd2, 0xec, 0xfb, 0x59, 0xdc, 0x64, 0xdf, 0x35, 0x5b, 0x4f, 0x8b, - 0x26, 0x92, 0x94, 0xe1, 0xf6, 0xc1, 0x80, 0x40, 0x1f, 0x20, 0x8a, 0xb3, 0x2f, 0x68, 0x0c, 0x69, 0x3e, 0xb3, 0xef, - 0x47, 0xc4, 0x7b, 0xb9, 0x13, 0x42, 0x8c, 0x2b, 0x2c, 0x1a, 0x3d, 0xe4, 0x33, 0x1e, 0x29, 0xc3, 0xa2, 0xf7, 0x98, - 0x40, 0x9c, 0xe1, 0xb4, 0x7a, 0x8f, 0x98, 0xc7, 0x78, 0x37, 0xd0, 0xb2, 0x87, 0x28, 0xa3, 0x2e, 0x7b, 0xc3, 0xe2, - 0xfb, 0xe3, 0x3a, 0xcc, 0xac, 0xe5, 0xe5, 0x10, 0xfe, 0x06, 0xda, 0x00, 0x9c, 0x72, 0x64, 0xf9, 0x2a, 0xb3, 0xd1, - 0xd5, 0x12, 0xd3, 0x9b, 0x08, 0x62, 0xf1, 0xe8, 0x74, 0x58, 0xbb, 0x3a, 0x55, 0xef, 0x6a, 0xe7, 0x33, 0xd1, 0xab, - 0x40, 0x2b, 0xd7, 0xb6, 0xc7, 0x43, 0xb8, 0x4b, 0x2d, 0xad, 0xb0, 0x11, 0xe5, 0x5c, 0x3c, 0xdd, 0x39, 0x36, 0x27, - 0xa0, 0xc1, 0x95, 0x4c, 0x01, 0x38, 0x4b, 0xab, 0xd1, 0xa8, 0x11, 0xf6, 0x59, 0x39, 0x9f, 0xc3, 0xd6, 0x42, 0x3c, - 0x2d, 0x00, 0xc3, 0x6d, 0x62, 0x50, 0xf2, 0x6e, 0x0c, 0xca, 0xe9, 0x47, 0x05, 0x6f, 0x1d, 0x9c, 0x95, 0xcb, 0x38, - 0x95, 0x37, 0x80, 0xc5, 0x18, 0xf8, 0xa9, 0x58, 0xaa, 0x97, 0x90, 0x2c, 0x79, 0xf2, 0x11, 0xad, 0x36, 0xd2, 0x00, - 0xb8, 0xca, 0xa9, 0xb1, 0xdc, 0x53, 0x20, 0xa1, 0xae, 0x14, 0x95, 0x10, 0x57, 0x55, 0x9c, 0x2c, 0x4f, 0x31, 0x35, - 0xdc, 0x40, 0x2f, 0xa2, 0x40, 0xae, 0xb8, 0x00, 0x92, 0x9e, 0xb3, 0x7f, 0x65, 0x1a, 0x6b, 0xfc, 0xb9, 0x44, 0x01, - 0x93, 0x46, 0x0d, 0xc6, 0x4a, 0xd9, 0x4b, 0x69, 0xa2, 0xbd, 0x05, 0x41, 0xed, 0x5e, 0xfe, 0x05, 0x75, 0x3f, 0x87, - 0x56, 0x84, 0x0d, 0x30, 0x44, 0x79, 0x8e, 0x3b, 0x34, 0xb5, 0x4b, 0xce, 0x03, 0x46, 0x74, 0xde, 0x67, 0xb5, 0xdd, - 0xea, 0xcf, 0x97, 0x80, 0x6d, 0x9a, 0x1a, 0x9f, 0xc2, 0x30, 0x21, 0x26, 0x36, 0xb0, 0x55, 0x56, 0xda, 0x0d, 0x65, - 0xda, 0x49, 0x97, 0xcc, 0x6b, 0xe1, 0x34, 0xef, 0x31, 0xb6, 0x1c, 0xa9, 0xdc, 0xfd, 0x7e, 0x68, 0x7e, 0xb2, 0x9c, - 0x3e, 0xd7, 0x21, 0x9b, 0xbd, 0xf1, 0xa0, 0x39, 0xd1, 0xea, 0xaa, 0x8e, 0x7e, 0x40, 0x07, 0x60, 0xa6, 0x2d, 0x40, - 0xa6, 0x0b, 0x36, 0xed, 0x2b, 0x51, 0x71, 0x49, 0xc2, 0x52, 0x49, 0x60, 0x67, 0x37, 0x25, 0x3b, 0x9b, 0x80, 0x78, - 0x86, 0xbb, 0x9e, 0x16, 0x3b, 0x21, 0x4d, 0x78, 0x8b, 0xbd, 0x04, 0x44, 0x1d, 0xaa, 0xba, 0x84, 0x6c, 0x8c, 0xa1, - 0x8b, 0x7f, 0x51, 0x0a, 0x13, 0xd6, 0x32, 0xa9, 0x4a, 0x4c, 0x10, 0xa4, 0x72, 0xb7, 0x45, 0x60, 0x89, 0x82, 0x1d, - 0xc0, 0xde, 0xbb, 0x51, 0x37, 0xa3, 0xa6, 0xaa, 0x53, 0x2f, 0xc1, 0xc7, 0x69, 0xd6, 0x55, 0x90, 0x59, 0xd8, 0x55, - 0xb1, 0xe6, 0x81, 0x8e, 0x4d, 0xa5, 0x8c, 0x89, 0xbb, 0xb4, 0xc8, 0x10, 0x0f, 0x18, 0x63, 0xe9, 0x42, 0x20, 0xdf, - 0x6c, 0x77, 0xdc, 0xf4, 0x04, 0xa1, 0x9f, 0xb0, 0xa1, 0x04, 0x6e, 0x3a, 0xdb, 0x53, 0xd3, 0xcc, 0x07, 0x44, 0x1c, - 0x06, 0x14, 0x48, 0x36, 0x0e, 0x69, 0x8e, 0xf4, 0x05, 0x49, 0x13, 0x06, 0x86, 0x56, 0x3c, 0x27, 0xc8, 0x8a, 0x42, - 0xcf, 0xd6, 0x55, 0x1b, 0xe7, 0xca, 0x30, 0x47, 0x4b, 0x4e, 0x85, 0xcf, 0x09, 0x32, 0xb1, 0x7b, 0xda, 0x66, 0x26, - 0xc3, 0x51, 0xb2, 0xc0, 0xfc, 0x0a, 0xa2, 0xc4, 0x9d, 0x69, 0x56, 0xe5, 0x60, 0x5c, 0xc0, 0x02, 0xad, 0x7c, 0x0f, - 0xea, 0xc6, 0x1a, 0xda, 0x68, 0x18, 0x62, 0xb7, 0x3f, 0xc1, 0x7e, 0xad, 0x9d, 0xd6, 0x65, 0x8a, 0xe5, 0x65, 0x0a, - 0xd1, 0x5e, 0xc8, 0xfc, 0x46, 0x91, 0xe8, 0x4e, 0x11, 0x86, 0x84, 0x75, 0x94, 0x3d, 0x69, 0x53, 0x03, 0xe8, 0xa9, - 0x17, 0xf0, 0xbc, 0x73, 0x2d, 0xc3, 0x2e, 0xd2, 0xfd, 0x55, 0xc1, 0xa7, 0x74, 0x83, 0x20, 0x45, 0x6f, 0x52, 0x30, - 0xe7, 0xf5, 0x28, 0xa9, 0x37, 0xa7, 0x2d, 0x33, 0xaa, 0x8e, 0x8a, 0x90, 0x72, 0x82, 0xff, 0xe4, 0xa5, 0xd4, 0xc4, - 0x26, 0x4c, 0xf0, 0xc0, 0x87, 0x79, 0x86, 0x0d, 0xbc, 0xdd, 0xbe, 0x4b, 0xc3, 0xa4, 0xcd, 0x36, 0xa4, 0x20, 0xad, - 0x30, 0x71, 0x31, 0xa0, 0xb2, 0xd7, 0xb8, 0x5f, 0xb0, 0x9d, 0x34, 0x05, 0x0f, 0xc2, 0x46, 0x03, 0x13, 0xb7, 0xba, - 0xf8, 0x3a, 0x4c, 0x68, 0xb8, 0xa4, 0xda, 0xd9, 0x49, 0x4b, 0x9a, 0xdb, 0xeb, 0xf2, 0xc2, 0xf6, 0x41, 0xc7, 0x0e, - 0xeb, 0x1a, 0x1e, 0x68, 0x5e, 0xb3, 0x8b, 0x2b, 0xa6, 0x69, 0xa2, 0xb1, 0x1e, 0x52, 0x96, 0x1c, 0xeb, 0x7a, 0xba, - 0xc2, 0xd5, 0x32, 0xd3, 0xc0, 0xee, 0x12, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x81, 0xcd, 0x66, 0xab, - 0x9a, 0x4c, 0xf3, 0xfb, 0xb2, 0xe5, 0x26, 0x20, 0x9c, 0xa5, 0xbe, 0xb9, 0x4f, 0x8e, 0x35, 0x6d, 0xf3, 0x93, 0x00, - 0xc7, 0xdb, 0x2b, 0x20, 0xe9, 0x58, 0x82, 0x2e, 0xbe, 0xa5, 0x3f, 0x88, 0xd4, 0x4c, 0x05, 0xbd, 0x77, 0xbe, 0x48, - 0xdd, 0xfc, 0x02, 0x6c, 0xa3, 0x36, 0xc6, 0x34, 0x2b, 0x5b, 0x87, 0x89, 0xb2, 0xb0, 0x46, 0x16, 0x72, 0x09, 0x3e, - 0x98, 0xbb, 0x4d, 0x9d, 0x1e, 0x77, 0x10, 0x61, 0xbf, 0x8b, 0x1e, 0x8f, 0x30, 0x56, 0xac, 0x41, 0x62, 0x58, 0x85, - 0x35, 0x6d, 0x2e, 0x87, 0x28, 0xa7, 0x66, 0xc9, 0x44, 0x4b, 0xea, 0x53, 0x8a, 0x28, 0x05, 0x73, 0xe3, 0x69, 0xd9, - 0x30, 0x25, 0x44, 0xc8, 0x0a, 0xe9, 0x80, 0x6a, 0x2d, 0xb4, 0x54, 0x13, 0xf4, 0x3a, 0xf4, 0xb2, 0xd0, 0x98, 0x82, - 0xe8, 0x23, 0x32, 0xdc, 0x88, 0x23, 0xa3, 0xbb, 0x63, 0x14, 0x13, 0x08, 0x55, 0xed, 0xe5, 0x85, 0xd5, 0xa7, 0x65, - 0x5b, 0x1d, 0xc4, 0x15, 0x22, 0xdf, 0x77, 0x13, 0xd4, 0x18, 0x05, 0x6d, 0x4e, 0x37, 0xfa, 0x6b, 0x11, 0xfa, 0x76, - 0xe1, 0xd8, 0x8d, 0x82, 0x48, 0x88, 0xc0, 0xea, 0x35, 0x15, 0x03, 0xb2, 0xce, 0x63, 0x17, 0xa1, 0x49, 0x77, 0x0b, - 0x51, 0xde, 0xa8, 0xac, 0x3f, 0xae, 0x43, 0xb2, 0xdd, 0x62, 0x59, 0xe0, 0xcb, 0x7e, 0xba, 0xbe, 0x07, 0xf2, 0xfb, - 0xcd, 0xfa, 0xb3, 0x90, 0xdf, 0xaf, 0xb3, 0x2f, 0x81, 0xfc, 0x7e, 0xb3, 0xfe, 0x9f, 0x86, 0xfc, 0x3e, 0x5d, 0x7b, - 0x90, 0xdf, 0x6a, 0x30, 0x7e, 0x2f, 0x58, 0x70, 0xf2, 0x36, 0xa0, 0x2f, 0x24, 0x0b, 0x4e, 0x5e, 0xbd, 0xf2, 0x8d, - 0x40, 0x84, 0x46, 0xae, 0x37, 0xb2, 0x60, 0xc4, 0x6d, 0x81, 0x57, 0xa8, 0x75, 0xf2, 0x81, 0x8a, 0x32, 0x00, 0x5e, - 0x2f, 0xff, 0x91, 0x55, 0xcb, 0x30, 0xd8, 0x0f, 0xc8, 0xcc, 0x41, 0x82, 0x0e, 0x27, 0x70, 0x7b, 0x43, 0x23, 0xcb, - 0xea, 0x8b, 0xe0, 0xc3, 0x47, 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0xa5, 0xce, 0x6c, 0x24, 0x04, 0x3c, 0xce, 0x78, 0x69, - 0x43, 0x44, 0x2c, 0xe3, 0xf2, 0x4c, 0xc7, 0x66, 0x29, 0xed, 0x56, 0x84, 0x88, 0xf3, 0x67, 0x80, 0x53, 0x6f, 0xf7, - 0x66, 0x8c, 0xfd, 0x50, 0x1c, 0xb1, 0x0e, 0x20, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, - 0x06, 0xbd, 0x84, 0xbb, 0x88, 0xe0, 0x49, 0xe5, 0xb1, 0x4d, 0x0a, 0xa8, 0x3c, 0xd3, 0x40, 0xe5, 0x1d, 0xef, 0x69, - 0x68, 0x87, 0x45, 0xfb, 0x00, 0x1b, 0xe9, 0x72, 0x06, 0x46, 0x8b, 0x2f, 0xaf, 0xb9, 0xa8, 0x7e, 0x06, 0x3c, 0x75, - 0xc1, 0x0b, 0xb8, 0x25, 0x20, 0x17, 0xdb, 0x70, 0x42, 0xa0, 0xc2, 0xf7, 0xec, 0x50, 0x51, 0x63, 0x8c, 0x68, 0xa2, - 0xd1, 0x6f, 0xbc, 0x09, 0xa1, 0x77, 0x27, 0xe8, 0x8a, 0x30, 0x12, 0xde, 0x5f, 0x6b, 0x7e, 0x96, 0x81, 0xf9, 0xbc, - 0x00, 0x28, 0x0d, 0x84, 0x43, 0x65, 0x4a, 0x6e, 0x81, 0x09, 0x1b, 0x63, 0xae, 0x94, 0xa5, 0x1e, 0x52, 0x29, 0x55, - 0x70, 0xba, 0x82, 0xa6, 0x12, 0x70, 0xb8, 0x23, 0x09, 0x60, 0xa6, 0xb6, 0x30, 0x88, 0x6e, 0x9b, 0xd2, 0x2c, 0x8d, - 0x9c, 0x22, 0xcd, 0xe1, 0x93, 0x52, 0x05, 0x3a, 0x7d, 0x96, 0xc4, 0x15, 0xbf, 0x94, 0x05, 0x84, 0xc2, 0x6d, 0xa5, - 0x50, 0xa4, 0xdf, 0x67, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0x39, 0x5b, 0x66, 0x65, 0x05, 0xf9, 0xe6, 0xfa, 0xf4, 0x5b, - 0xd4, 0xd3, 0x02, 0xe7, 0x4d, 0x4d, 0x0a, 0x33, 0xf3, 0x78, 0xac, 0x76, 0x3a, 0xa8, 0x57, 0xbd, 0xd7, 0x06, 0xfb, - 0xbd, 0x39, 0xd1, 0xe3, 0xd6, 0x7a, 0xb0, 0x9a, 0xd4, 0x66, 0xaa, 0x82, 0x38, 0x02, 0xea, 0xc0, 0x8e, 0xe2, 0x76, - 0x33, 0x0f, 0x93, 0x76, 0xca, 0x76, 0xbb, 0x93, 0x09, 0x0e, 0xee, 0x56, 0x12, 0xdc, 0x12, 0x61, 0xc5, 0x1f, 0x2a, - 0x08, 0x96, 0xd9, 0x70, 0x12, 0x99, 0x70, 0xac, 0x05, 0xff, 0x6b, 0xcd, 0x0d, 0x16, 0x7c, 0xa8, 0x1d, 0xf2, 0x9c, - 0xe4, 0x5c, 0x0f, 0x80, 0x67, 0xc3, 0xa6, 0x67, 0x67, 0x0e, 0xf6, 0x53, 0x7e, 0xcb, 0x21, 0x60, 0x4b, 0xe7, 0x28, - 0x2e, 0xa6, 0xda, 0x9a, 0xd7, 0xb0, 0x12, 0xf4, 0xcb, 0xbe, 0xd3, 0x38, 0xb5, 0x09, 0x0f, 0x87, 0xcf, 0xc6, 0xa4, - 0xd6, 0xa6, 0xe5, 0x38, 0xcf, 0xf6, 0xb7, 0x5a, 0x0b, 0xee, 0xd9, 0xae, 0x07, 0xda, 0x74, 0x0a, 0x68, 0xd7, 0x48, - 0xc5, 0x3d, 0xdd, 0xaf, 0x49, 0xed, 0xe6, 0xd5, 0x0a, 0x7a, 0xfe, 0x50, 0x87, 0xcb, 0xd9, 0xa3, 0x4d, 0xa6, 0xab, - 0xac, 0xff, 0xc8, 0x6c, 0x58, 0xb8, 0xc6, 0x46, 0xad, 0xf5, 0x8c, 0xfb, 0xa8, 0x6c, 0x1d, 0xd9, 0xf4, 0x0c, 0xb1, - 0xac, 0x73, 0xb7, 0x8f, 0xd4, 0x23, 0x57, 0x51, 0xb2, 0xba, 0xb3, 0xf0, 0x5b, 0x9e, 0x84, 0x5d, 0x0d, 0x53, 0x8c, - 0xb8, 0xe9, 0x02, 0x02, 0x55, 0x82, 0xf8, 0x3d, 0xfc, 0xe3, 0xd1, 0xa6, 0x49, 0x3d, 0xea, 0x7d, 0xef, 0x33, 0xfc, - 0x9d, 0xa5, 0xf0, 0xb7, 0xaa, 0xff, 0xa0, 0x9b, 0x2b, 0x5e, 0x2d, 0x65, 0x1a, 0x05, 0xef, 0x4e, 0x4e, 0x3f, 0x04, - 0x1a, 0x00, 0x1d, 0xaf, 0x01, 0x46, 0xf1, 0x6b, 0xa0, 0x96, 0x40, 0x11, 0x92, 0xcb, 0x4b, 0xc4, 0x00, 0xd4, 0x20, - 0xf2, 0xa7, 0x4b, 0x79, 0x73, 0x9c, 0xe7, 0x3e, 0xaf, 0x6a, 0xe8, 0x9b, 0x66, 0xdf, 0x1a, 0xc4, 0x21, 0x04, 0x91, - 0xdb, 0x28, 0x2b, 0xcf, 0xb4, 0x92, 0x24, 0x3d, 0x3b, 0xbf, 0x3b, 0xd3, 0x82, 0x18, 0x0b, 0xc2, 0xf8, 0xfc, 0x8f, - 0xc3, 0x34, 0xbb, 0xde, 0x43, 0x22, 0xcc, 0x02, 0xb0, 0x60, 0xcf, 0xf9, 0xf9, 0xba, 0xaa, 0xa4, 0x18, 0x16, 0xf2, - 0x26, 0x38, 0x3a, 0x54, 0x0f, 0x26, 0x43, 0xac, 0x1e, 0x83, 0xbd, 0xff, 0x4a, 0xf2, 0x2c, 0xf9, 0xc8, 0x82, 0x47, - 0x9b, 0x8c, 0x1d, 0xb5, 0x48, 0xed, 0xb8, 0x0e, 0x8e, 0xa0, 0xad, 0x7b, 0xc7, 0x79, 0x7e, 0xb8, 0xaf, 0xbe, 0x38, - 0x3a, 0xdc, 0x4f, 0xb3, 0xeb, 0x23, 0x0f, 0x0f, 0xdf, 0x99, 0xb7, 0x22, 0xf2, 0x98, 0xbb, 0xbe, 0x82, 0x1f, 0x6b, - 0xc2, 0x43, 0x7b, 0xe0, 0x83, 0xd0, 0xc4, 0x44, 0x13, 0x41, 0x41, 0x4b, 0x18, 0xc3, 0xf1, 0xb6, 0xdd, 0x86, 0xd6, - 0xf6, 0x26, 0xf1, 0x80, 0x69, 0x0a, 0x60, 0x08, 0x30, 0x0b, 0x4d, 0x08, 0x4d, 0x6a, 0x12, 0x1a, 0xf8, 0x9c, 0x98, - 0xd0, 0xa2, 0xa6, 0x40, 0xf1, 0xdf, 0xc4, 0x2b, 0x23, 0x6b, 0xd2, 0x77, 0x77, 0xd3, 0xfa, 0x59, 0x63, 0x1c, 0xa3, - 0xf6, 0xa8, 0x1a, 0x40, 0xab, 0x5e, 0x79, 0xdf, 0xc0, 0x82, 0x78, 0x31, 0xac, 0x68, 0xd0, 0x22, 0x15, 0x20, 0x1e, - 0xf4, 0xa5, 0x5a, 0x9c, 0x86, 0xf3, 0x92, 0xca, 0x05, 0x61, 0x47, 0xe1, 0x06, 0xb9, 0xdb, 0x52, 0x11, 0xcb, 0x48, - 0xd6, 0x0e, 0x5d, 0x52, 0xcd, 0xce, 0xd1, 0xa3, 0x8d, 0x40, 0x40, 0xc3, 0x92, 0x1d, 0x35, 0xe7, 0xab, 0x8a, 0xcf, - 0x87, 0x4b, 0x0e, 0x6e, 0x30, 0xc1, 0xde, 0x7f, 0xa5, 0xe7, 0xb9, 0x9d, 0x14, 0xb5, 0x22, 0x97, 0xb1, 0x48, 0x73, - 0xfe, 0x21, 0x3e, 0xff, 0x01, 0xf3, 0xbc, 0x38, 0xcf, 0x9f, 0x43, 0x86, 0x3a, 0x38, 0x7a, 0xb4, 0x49, 0xaa, 0xd1, - 0xcb, 0xb7, 0x1f, 0x5e, 0x7f, 0xf8, 0xe7, 0xd9, 0xf3, 0xe3, 0x0f, 0x2f, 0xbf, 0x3f, 0x79, 0xff, 0xfa, 0xe5, 0xe9, - 0xdc, 0xfa, 0x9d, 0x2a, 0x38, 0x33, 0xb2, 0xd8, 0x6e, 0x5d, 0xbe, 0x5f, 0xdf, 0xbe, 0x78, 0xf9, 0xea, 0xf5, 0xdb, - 0x97, 0x2f, 0x6a, 0x35, 0x97, 0xed, 0x86, 0xc0, 0x0e, 0x8d, 0x33, 0xc1, 0x0b, 0x28, 0x5e, 0x07, 0x55, 0xc4, 0x66, - 0x6b, 0x14, 0xbe, 0x66, 0xd3, 0x75, 0xc0, 0x02, 0x58, 0x64, 0x7b, 0x7a, 0xb3, 0x40, 0xc3, 0xa5, 0xd9, 0x38, 0xfe, - 0x12, 0xf3, 0x7b, 0xf3, 0x12, 0xbf, 0x7b, 0x2f, 0x6f, 0x4c, 0x57, 0xf4, 0x08, 0x29, 0x80, 0xad, 0xd9, 0xf3, 0x3f, - 0x0e, 0x7d, 0xa1, 0x16, 0xde, 0xfc, 0x55, 0xb9, 0xf0, 0xab, 0x0e, 0xf6, 0xb4, 0x81, 0x5d, 0x00, 0xf1, 0x21, 0x82, - 0xa3, 0xc3, 0x7d, 0x3f, 0xf7, 0xd1, 0x1f, 0xd1, 0xcf, 0x5e, 0xe7, 0xb0, 0x54, 0x18, 0x87, 0x66, 0xda, 0xce, 0x21, - 0x04, 0x11, 0x8c, 0xdc, 0x31, 0xa5, 0x56, 0x90, 0x21, 0x57, 0x92, 0x44, 0x76, 0x12, 0x95, 0xe1, 0x88, 0x29, 0xed, - 0x0f, 0xfd, 0xd7, 0xf5, 0x19, 0x2f, 0xe2, 0x5c, 0x94, 0xb2, 0x08, 0xa0, 0x1f, 0xed, 0xb0, 0x0e, 0x7b, 0x5e, 0xf8, - 0x14, 0xec, 0x51, 0x27, 0x79, 0x87, 0x11, 0xd9, 0x6f, 0x7f, 0xea, 0x75, 0xec, 0x0f, 0xe2, 0x7e, 0xec, 0xe9, 0xce, - 0xb4, 0xc8, 0x8b, 0x6d, 0xe0, 0xfd, 0xe1, 0x37, 0xe6, 0x27, 0x19, 0xfd, 0x87, 0xa4, 0x97, 0x31, 0xbd, 0x8a, 0xe9, - 0xa9, 0x58, 0xd4, 0x9d, 0xb3, 0x63, 0x43, 0xbb, 0x50, 0x3e, 0x0d, 0x01, 0x20, 0x42, 0xb3, 0xed, 0x9a, 0x99, 0xcd, - 0x46, 0x5a, 0xa5, 0xf5, 0x21, 0x2e, 0x2e, 0xb9, 0x89, 0xa8, 0x62, 0xde, 0x56, 0x7a, 0x54, 0x88, 0x37, 0x2c, 0x80, - 0x9e, 0xd2, 0xd3, 0x9a, 0xff, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xe6, 0xaa, 0xac, 0xe4, 0x0a, 0x58, - 0xea, 0xf8, 0x52, 0x8b, 0x48, 0x68, 0xc8, 0xbf, 0xac, 0xba, 0xed, 0x96, 0x8f, 0x70, 0x49, 0x02, 0x5f, 0x36, 0xaa, - 0xe4, 0xe5, 0x65, 0xce, 0xc3, 0xc0, 0xc4, 0xf8, 0x08, 0xa8, 0xad, 0x66, 0xf6, 0x7f, 0x9a, 0x7b, 0xfa, 0xe5, 0xb6, - 0x6d, 0xe4, 0xff, 0xbf, 0xa7, 0x60, 0x98, 0x5c, 0x2a, 0x26, 0x24, 0x4d, 0x4a, 0x96, 0xed, 0x48, 0x96, 0xdd, 0x36, - 0x49, 0xe7, 0xdc, 0x71, 0x9b, 0x4e, 0xe2, 0xcb, 0xdc, 0xd5, 0xf5, 0x58, 0x14, 0x05, 0x49, 0xbc, 0x50, 0xa4, 0x86, - 0xa4, 0x6c, 0xb9, 0x2a, 0xef, 0x59, 0xfa, 0x2c, 0xf7, 0x64, 0xbf, 0xd9, 0x5d, 0x00, 0x04, 0x3f, 0xf4, 0xe1, 0x26, - 0xbd, 0xfb, 0x4d, 0xcf, 0x17, 0x11, 0x04, 0x40, 0x60, 0x01, 0x2c, 0xf6, 0x7b, 0x9f, 0x38, 0x22, 0xb0, 0xa6, 0x91, - 0x6f, 0x3a, 0x5a, 0x62, 0xc6, 0x4c, 0x46, 0x9e, 0x23, 0x02, 0x13, 0x45, 0xa8, 0x77, 0xa8, 0x85, 0xe0, 0xeb, 0x52, - 0x1c, 0x5d, 0x6b, 0x1c, 0x2f, 0x47, 0x21, 0xb3, 0x70, 0xbb, 0xc3, 0x27, 0xd7, 0xa3, 0xe5, 0x68, 0x04, 0xc9, 0x54, - 0x9e, 0x38, 0x26, 0x84, 0x87, 0x89, 0x53, 0x64, 0xdb, 0x72, 0xa3, 0x0f, 0x93, 0xb2, 0xb3, 0xea, 0xf0, 0xc1, 0xa4, - 0x03, 0x24, 0x32, 0xf4, 0x81, 0x0c, 0x58, 0xb4, 0x86, 0x53, 0x3b, 0xd0, 0x3f, 0xc0, 0xee, 0x4b, 0xf5, 0x7e, 0xd3, - 0xd1, 0x1f, 0x5c, 0xeb, 0x1f, 0x10, 0xc6, 0x98, 0x64, 0xf8, 0x35, 0xed, 0x5e, 0xdd, 0xd4, 0x49, 0x37, 0xbd, 0xc4, - 0x74, 0x03, 0x20, 0x9b, 0x7d, 0x13, 0x78, 0xd3, 0x28, 0x4e, 0xb3, 0xc0, 0xd7, 0x6f, 0xfa, 0x17, 0x41, 0xeb, 0x7a, - 0x9e, 0xb5, 0x8c, 0x1b, 0xd3, 0xcf, 0xd4, 0x4c, 0x25, 0x02, 0x61, 0x62, 0xa2, 0x92, 0x4d, 0x95, 0xd4, 0x13, 0xb4, - 0xb5, 0xa2, 0x40, 0xcd, 0x58, 0xc9, 0xcf, 0x06, 0x50, 0xaf, 0x92, 0xf6, 0x04, 0xf3, 0x37, 0xe9, 0xd8, 0xd2, 0xe8, - 0x13, 0x43, 0xf1, 0x7a, 0xb9, 0xc6, 0xab, 0x3c, 0x2b, 0x6e, 0x4b, 0x0c, 0xd5, 0x2b, 0xfc, 0x5b, 0xe8, 0xf9, 0x89, - 0x6a, 0x9b, 0x59, 0xba, 0x77, 0x87, 0xdf, 0x94, 0xe9, 0x02, 0xb8, 0xbf, 0xc1, 0x30, 0x22, 0x8a, 0x33, 0x0d, 0xe2, - 0xcf, 0xc0, 0x17, 0x87, 0x55, 0x5b, 0x2e, 0xde, 0x6b, 0xcb, 0xc8, 0x39, 0x32, 0xf8, 0x16, 0x2f, 0xbf, 0x16, 0x8f, - 0x42, 0x56, 0x0a, 0x34, 0x41, 0x34, 0x7d, 0x04, 0x0b, 0x98, 0xc5, 0x97, 0xf1, 0x7d, 0x55, 0x5d, 0xf1, 0x7a, 0xb8, - 0xfb, 0xee, 0xc5, 0x0b, 0x10, 0xf6, 0x9b, 0x48, 0xbe, 0xd7, 0xe2, 0xf9, 0x43, 0x05, 0xa1, 0x53, 0x39, 0x53, 0x68, - 0x9f, 0x21, 0x68, 0x98, 0x0c, 0xcc, 0xb9, 0xf0, 0x2e, 0x00, 0x94, 0xc4, 0xaf, 0xe9, 0x61, 0x7e, 0x2b, 0x32, 0x1c, - 0x8b, 0xfc, 0xc2, 0xca, 0xe5, 0x0c, 0xd8, 0x35, 0x5a, 0x2c, 0x33, 0x8c, 0x88, 0x0b, 0x03, 0x60, 0xb9, 0xae, 0x61, - 0x84, 0x4d, 0xc0, 0xd2, 0x05, 0x99, 0x98, 0xeb, 0x5a, 0x30, 0xae, 0x97, 0x71, 0xa2, 0x17, 0x90, 0x17, 0xe2, 0x77, - 0x94, 0x27, 0xc1, 0x63, 0xc2, 0xa7, 0xe1, 0x9b, 0x45, 0x38, 0xf9, 0x96, 0x8f, 0x7a, 0x97, 0x06, 0xcc, 0xe0, 0x53, - 0x3f, 0xfd, 0x56, 0xd8, 0x38, 0x59, 0x88, 0x92, 0x59, 0x9a, 0xe6, 0xf0, 0xd9, 0x3a, 0xca, 0xcf, 0x9f, 0xad, 0xd3, - 0x7c, 0xf0, 0x6c, 0xed, 0x01, 0x25, 0x97, 0xeb, 0x30, 0xd1, 0xc2, 0x9f, 0xa6, 0x98, 0x1e, 0x6c, 0x2a, 0x2a, 0xd7, - 0x50, 0xa1, 0x3e, 0xe0, 0x6a, 0xf3, 0x45, 0x12, 0xcc, 0xbd, 0xe4, 0x81, 0xb4, 0xec, 0xa6, 0xaa, 0x8a, 0x37, 0x74, - 0x8d, 0xf0, 0x3a, 0xcd, 0x97, 0x50, 0xbc, 0xae, 0x7d, 0x2d, 0xcb, 0x18, 0x9f, 0x9c, 0x54, 0x35, 0xc2, 0xb7, 0x6e, - 0xf5, 0x97, 0xcc, 0x1e, 0xb3, 0xcc, 0x0b, 0x42, 0x6a, 0xd2, 0x17, 0x39, 0xe4, 0x6b, 0xb3, 0x49, 0xcb, 0xb3, 0x89, - 0xca, 0xdb, 0x05, 0x27, 0x43, 0x18, 0x9f, 0xc6, 0x8d, 0x33, 0xc3, 0xdc, 0x52, 0xcd, 0x0b, 0x48, 0xef, 0xfe, 0xab, - 0xd0, 0x67, 0x00, 0xfd, 0x08, 0xa0, 0xcf, 0x22, 0x3f, 0x1e, 0xb3, 0xbf, 0xbf, 0xbf, 0x90, 0xc9, 0xac, 0x40, 0x2e, - 0x33, 0xe4, 0xfb, 0x30, 0x45, 0x72, 0x21, 0x41, 0x52, 0x81, 0xd2, 0x4e, 0x69, 0x72, 0xc7, 0x24, 0xb9, 0xae, 0x9d, - 0xd3, 0xd8, 0xd9, 0x98, 0x46, 0x3d, 0x88, 0xb1, 0x55, 0x92, 0x9f, 0x1e, 0x50, 0x6d, 0xba, 0xdc, 0xa8, 0x12, 0x80, - 0x21, 0x81, 0x19, 0x16, 0x50, 0x80, 0xbc, 0x9b, 0x03, 0xb7, 0xe0, 0x1f, 0xec, 0x39, 0x4a, 0xbf, 0xdd, 0xf3, 0x32, - 0x65, 0x82, 0xad, 0xf4, 0xb3, 0x53, 0xcc, 0xa4, 0x05, 0xd7, 0x33, 0xc4, 0xde, 0x38, 0x3d, 0xa0, 0x47, 0xad, 0x72, - 0x00, 0x8a, 0x4e, 0x04, 0x27, 0xd7, 0xe3, 0x1d, 0x3c, 0xea, 0x64, 0x40, 0xe2, 0x76, 0x28, 0xf5, 0x72, 0x5d, 0x9b, - 0x73, 0x4a, 0x88, 0x07, 0xf9, 0x81, 0x08, 0x00, 0x0e, 0x1c, 0x55, 0x5d, 0x9b, 0x7b, 0x2b, 0x9c, 0xb9, 0x78, 0xe3, - 0xad, 0x5a, 0x2e, 0x7f, 0x55, 0x1c, 0xad, 0xb4, 0x7c, 0xb4, 0x7c, 0xbe, 0xb8, 0x60, 0xde, 0x2f, 0xa4, 0xb6, 0xad, - 0x19, 0xaa, 0x4d, 0x1b, 0x16, 0x77, 0x26, 0x16, 0x77, 0xbc, 0x61, 0x71, 0xc7, 0x5b, 0x16, 0x37, 0xe4, 0x0b, 0xa9, - 0x49, 0xd0, 0x25, 0xe8, 0xb2, 0x25, 0x81, 0xc7, 0xe9, 0x8a, 0x1e, 0x3f, 0x67, 0x08, 0x27, 0x2b, 0x0d, 0xc1, 0x64, - 0x69, 0x03, 0xac, 0x9a, 0xe0, 0xa2, 0x00, 0xa2, 0x3e, 0x71, 0x79, 0xea, 0xc4, 0xbc, 0x21, 0x33, 0x66, 0x2b, 0xac, - 0xce, 0x17, 0x76, 0x29, 0x65, 0xfd, 0x6e, 0xcd, 0x36, 0xcc, 0x74, 0xb6, 0x65, 0xa6, 0x7e, 0xe9, 0xe8, 0xf2, 0x69, - 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0xcc, 0x38, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x94, 0xaa, 0xec, 0xa8, - 0x85, 0x97, 0xa6, 0xf7, 0x71, 0x02, 0x7a, 0x10, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x1e, 0x44, 0x3c, 0xc4, 0xca, 0xc6, - 0xcd, 0x54, 0xbc, 0x57, 0xb7, 0x54, 0xbb, 0xdb, 0xa5, 0x1a, 0x0b, 0x2f, 0xcb, 0x58, 0x82, 0x40, 0xf7, 0x20, 0x16, - 0x77, 0xae, 0x6b, 0xff, 0x0f, 0x76, 0x59, 0x03, 0x0a, 0x09, 0x8d, 0x02, 0xa9, 0x23, 0x82, 0x5e, 0x00, 0x25, 0x95, - 0x88, 0x6b, 0x57, 0x89, 0xd6, 0x96, 0x48, 0xb8, 0xff, 0x88, 0xa7, 0xb5, 0x95, 0x28, 0xfe, 0x44, 0xee, 0x91, 0x61, - 0x2f, 0xbc, 0xf1, 0x07, 0xd0, 0xb6, 0xb5, 0xda, 0x26, 0x58, 0xce, 0xaa, 0xb1, 0xd9, 0x12, 0x22, 0xed, 0xfc, 0x02, - 0x47, 0x22, 0x92, 0xe4, 0x76, 0x49, 0xe0, 0xd2, 0xe8, 0x59, 0x93, 0x9b, 0x75, 0x3b, 0x3f, 0x98, 0x06, 0x46, 0x0d, - 0x69, 0x02, 0x66, 0x0b, 0x07, 0x67, 0x92, 0xc3, 0x0a, 0x4d, 0xf7, 0xc8, 0x00, 0x71, 0xec, 0x35, 0x24, 0x19, 0x75, - 0x04, 0xfb, 0x3a, 0x4c, 0xe0, 0x8e, 0xba, 0x76, 0x6e, 0xf2, 0xe7, 0x53, 0xfc, 0xe5, 0xde, 0xe4, 0xcf, 0x47, 0xf8, - 0xab, 0x7d, 0x83, 0xe9, 0xe4, 0x1a, 0xd8, 0x76, 0x65, 0xce, 0xfa, 0x59, 0x69, 0x3b, 0x91, 0x51, 0xd8, 0x23, 0x76, - 0x0d, 0x5f, 0xe0, 0xa7, 0xcf, 0xd6, 0x29, 0xb8, 0x41, 0xaa, 0x73, 0x88, 0xec, 0xc4, 0xc8, 0x1b, 0xcb, 0xa7, 0x1b, - 0xca, 0x47, 0xc6, 0x7f, 0xf9, 0x9a, 0xc7, 0x5d, 0x12, 0x17, 0x57, 0x4a, 0x59, 0xe8, 0x70, 0x3b, 0x0a, 0x22, 0x2f, - 0x79, 0xb8, 0x25, 0x66, 0xa2, 0x25, 0x28, 0x75, 0x29, 0x4c, 0x21, 0x62, 0xb2, 0xac, 0x83, 0xca, 0x14, 0xa9, 0xeb, - 0x03, 0xbf, 0xe7, 0x07, 0xff, 0x48, 0x14, 0x22, 0xad, 0xc4, 0x6e, 0xf2, 0x05, 0x29, 0x7d, 0xe8, 0xf6, 0xd9, 0xba, - 0xc5, 0xea, 0xdd, 0x54, 0x66, 0x5b, 0xa1, 0x02, 0x61, 0x79, 0x90, 0x75, 0x9d, 0x8f, 0x83, 0x1e, 0x2a, 0x99, 0x46, - 0xf1, 0xca, 0x7a, 0xb6, 0xce, 0xce, 0xf5, 0xb9, 0x97, 0x7c, 0x62, 0x63, 0xcb, 0x0f, 0x12, 0x3f, 0x64, 0x7a, 0x4f, - 0x1f, 0x85, 0x5e, 0xf4, 0x89, 0x3f, 0x5a, 0xf1, 0x32, 0x43, 0xb5, 0xf1, 0x4e, 0x4e, 0x57, 0xc0, 0x84, 0x04, 0x74, - 0x48, 0x9a, 0x36, 0x40, 0x41, 0x7b, 0x2d, 0xc5, 0x5b, 0x05, 0x59, 0x58, 0xd4, 0x32, 0xc1, 0xea, 0x11, 0x34, 0xd9, - 0xe0, 0x46, 0x6a, 0xea, 0xb8, 0x5e, 0xba, 0xa9, 0x4e, 0x95, 0x44, 0x93, 0x32, 0x0f, 0xe2, 0x2d, 0xf6, 0xf0, 0xc7, - 0x3f, 0x47, 0x19, 0xaa, 0xf7, 0xff, 0x1c, 0x27, 0xf1, 0x36, 0x7f, 0x50, 0x6d, 0xec, 0xa5, 0xe9, 0x72, 0xce, 0xc6, - 0xa4, 0x31, 0x3b, 0x2f, 0x86, 0x52, 0x26, 0xe5, 0xd5, 0xe1, 0xfc, 0xb2, 0x6c, 0x1f, 0x1f, 0xbe, 0x06, 0x4d, 0x3e, - 0x90, 0x74, 0xf1, 0x64, 0xa2, 0x17, 0x4c, 0xf5, 0x8e, 0x66, 0xee, 0xe1, 0x2f, 0xcb, 0xef, 0xde, 0x3a, 0xdf, 0xc9, - 0xc6, 0x91, 0x6e, 0xe4, 0x43, 0xa1, 0x96, 0xe4, 0x94, 0xa9, 0x32, 0x5e, 0x31, 0xa3, 0x89, 0x17, 0x6d, 0x9e, 0xce, - 0x75, 0x69, 0x97, 0x2d, 0x18, 0x1b, 0x83, 0xc5, 0xaa, 0x59, 0x2b, 0xbd, 0x0d, 0xd9, 0x1d, 0x93, 0x2a, 0xcf, 0xfa, - 0xc7, 0x1a, 0x5a, 0x60, 0x4c, 0x36, 0xae, 0x4a, 0xe5, 0x74, 0x95, 0x32, 0xa5, 0x21, 0xce, 0x81, 0xcf, 0x5c, 0xdd, - 0xe5, 0x95, 0x5d, 0x3d, 0x34, 0x75, 0x65, 0x00, 0x1b, 0x47, 0x76, 0xbe, 0xa1, 0xbc, 0x87, 0x09, 0x99, 0x9b, 0xc7, - 0x66, 0xba, 0x46, 0x0f, 0x62, 0x58, 0x73, 0x38, 0x85, 0xb0, 0xf9, 0x5b, 0x85, 0xfc, 0x61, 0x13, 0xc4, 0x9a, 0xa4, - 0x52, 0x3a, 0x89, 0x3b, 0x84, 0x15, 0x20, 0x9a, 0xc3, 0x0a, 0xc1, 0x4f, 0xe3, 0xda, 0x68, 0xe5, 0x99, 0x8f, 0x30, - 0xd1, 0x69, 0xc4, 0xd2, 0x74, 0x23, 0xc0, 0xe4, 0xa2, 0x9b, 0x7a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0x74, 0x4c, - 0xb8, 0x94, 0x71, 0x82, 0xd5, 0x6f, 0x21, 0x86, 0xbf, 0x9d, 0x73, 0x3b, 0x8e, 0x64, 0x3a, 0xd2, 0xb9, 0x8e, 0x7d, - 0xd3, 0xfb, 0x7b, 0x9d, 0x0f, 0xaa, 0x74, 0x53, 0x36, 0x0e, 0xad, 0x55, 0xc2, 0x7e, 0x35, 0xf9, 0x0c, 0x76, 0x20, - 0xc6, 0x54, 0x41, 0x71, 0x6c, 0x32, 0x61, 0x7e, 0x96, 0x1a, 0x42, 0x5a, 0x23, 0xa3, 0xaa, 0x82, 0x37, 0xcd, 0x93, - 0x81, 0xfe, 0x23, 0xf8, 0x96, 0x8b, 0xe0, 0x43, 0x7c, 0x40, 0x82, 0x6b, 0x69, 0x06, 0x13, 0xf5, 0x58, 0x06, 0x11, - 0xff, 0x0a, 0x24, 0xcd, 0x6e, 0x28, 0xc7, 0xa1, 0xf1, 0x2b, 0xa0, 0xd8, 0x17, 0xb1, 0xb4, 0xf6, 0xd8, 0x8e, 0x80, - 0xb6, 0x1d, 0xdf, 0xb5, 0xfb, 0x5d, 0xd7, 0x75, 0x72, 0xdd, 0x04, 0x9f, 0xa6, 0x4f, 0xfb, 0x1e, 0x7a, 0x6c, 0xd5, - 0x81, 0x56, 0xcb, 0xe8, 0x31, 0xed, 0xda, 0xee, 0x2b, 0x57, 0x37, 0xc9, 0x94, 0x4c, 0xc1, 0x6d, 0x7e, 0x7c, 0xc7, - 0x92, 0xcf, 0x9e, 0x4a, 0xb9, 0xf3, 0xfd, 0xc6, 0x73, 0xe4, 0x3a, 0x80, 0x84, 0xb3, 0x78, 0xf1, 0x88, 0x29, 0x74, - 0x74, 0x53, 0xf7, 0xc3, 0x38, 0x65, 0xea, 0x1c, 0x48, 0xea, 0xf0, 0x99, 0x93, 0xf8, 0xe9, 0xfd, 0xdb, 0x0f, 0x1f, - 0x74, 0x13, 0x33, 0x64, 0xa6, 0x6a, 0xef, 0x7c, 0x43, 0xed, 0xc0, 0xfe, 0x8d, 0xfb, 0x8e, 0x6e, 0x18, 0x62, 0x2b, - 0xcb, 0x7b, 0x8e, 0xca, 0x6a, 0x5b, 0x8e, 0xdf, 0x3c, 0xfc, 0xcb, 0xc4, 0x0b, 0xee, 0x35, 0xaf, 0x06, 0xdc, 0xb0, - 0xfd, 0x7a, 0x2b, 0x95, 0xcc, 0x83, 0xe8, 0xb6, 0xa1, 0xd4, 0x5b, 0x35, 0x94, 0x02, 0x33, 0x55, 0xc3, 0x55, 0xcb, - 0x78, 0xae, 0xdc, 0xce, 0x90, 0xe0, 0x78, 0x17, 0xb8, 0x14, 0x8e, 0xe6, 0x33, 0x06, 0xcd, 0x23, 0x9c, 0x57, 0x47, - 0xdd, 0x50, 0xcc, 0xd9, 0x10, 0x09, 0x5b, 0x3f, 0x04, 0x43, 0x38, 0xa6, 0xaa, 0xc1, 0xca, 0x94, 0x9b, 0x34, 0x63, - 0x55, 0x3a, 0x21, 0x0a, 0xf3, 0x36, 0x63, 0xf3, 0x05, 0x4b, 0xbc, 0x6c, 0x99, 0xb0, 0xdb, 0x30, 0xbe, 0x7f, 0x52, - 0x98, 0x99, 0xef, 0xa8, 0x3c, 0x0b, 0xa6, 0x33, 0x59, 0xfb, 0xbc, 0xc5, 0x06, 0x72, 0x01, 0xb7, 0x7e, 0x20, 0xff, - 0xcf, 0xef, 0xb6, 0xfd, 0x9f, 0xdf, 0x77, 0x56, 0x85, 0xee, 0xf3, 0xa1, 0x99, 0x0d, 0xf6, 0xd8, 0x17, 0xcd, 0x5f, - 0x2a, 0xc3, 0xbc, 0xb9, 0x4e, 0x6d, 0x11, 0xe0, 0x7d, 0x6d, 0x09, 0x6a, 0x85, 0xe5, 0x7d, 0xf3, 0xa8, 0x81, 0xc1, - 0xbc, 0x76, 0x8e, 0x0c, 0x2a, 0x7d, 0xd6, 0xd0, 0x86, 0x46, 0x6f, 0xaf, 0x15, 0xf9, 0xe3, 0x10, 0xde, 0x35, 0x87, - 0xcf, 0x1c, 0x3e, 0x97, 0x0c, 0xbe, 0x1e, 0x0e, 0x65, 0xce, 0x35, 0xb5, 0x29, 0x98, 0xbe, 0x9f, 0xd7, 0x4a, 0xf8, - 0xe5, 0xd9, 0x73, 0x0c, 0xf2, 0x49, 0x1f, 0xbc, 0x1e, 0xa2, 0x91, 0xd6, 0xe9, 0x28, 0x29, 0x88, 0x95, 0x8d, 0xa8, - 0x8d, 0x8c, 0xac, 0x6b, 0x9d, 0xd6, 0xf0, 0x1a, 0x94, 0x62, 0x22, 0xae, 0x7c, 0x68, 0x98, 0xaf, 0x87, 0x5c, 0xb4, - 0xc3, 0xed, 0x42, 0x7b, 0xd5, 0xad, 0xcd, 0x05, 0xa3, 0x25, 0xa0, 0x9b, 0x1a, 0x29, 0x5c, 0xb0, 0x32, 0x2b, 0x24, - 0x69, 0x28, 0x51, 0x07, 0xa6, 0x7e, 0x98, 0x63, 0x1e, 0x90, 0x77, 0x9b, 0x6c, 0xa7, 0x7e, 0xda, 0x6d, 0x3b, 0x75, - 0xb5, 0x97, 0xed, 0xd4, 0x4f, 0x5f, 0xdc, 0x76, 0xea, 0x9d, 0x6a, 0x3b, 0x05, 0x8b, 0xf8, 0x96, 0xed, 0x65, 0xd0, - 0x24, 0xcc, 0x24, 0xe2, 0xfb, 0x74, 0xe0, 0x72, 0x92, 0x36, 0xf5, 0x67, 0x0c, 0xd8, 0x74, 0xbe, 0x2a, 0x61, 0x3c, - 0x05, 0xe3, 0xa6, 0x3f, 0xdf, 0x0c, 0x29, 0x8c, 0xa7, 0xaa, 0x11, 0x52, 0xc4, 0x23, 0xa1, 0x16, 0xd1, 0x8d, 0xc8, - 0xf0, 0xc7, 0x31, 0x45, 0x2c, 0x24, 0xeb, 0xd0, 0x50, 0xb2, 0x3d, 0x4b, 0xab, 0xae, 0xb6, 0x30, 0x0d, 0xea, 0xa1, - 0x55, 0x91, 0x6c, 0xd8, 0x7e, 0x29, 0x62, 0x3e, 0xa8, 0x3d, 0x48, 0xeb, 0x59, 0x8a, 0x9f, 0xb0, 0xd6, 0x7f, 0x59, - 0xb9, 0xdf, 0x5e, 0xbb, 0xfd, 0x8e, 0x0b, 0x4e, 0xcb, 0xc0, 0xe4, 0x61, 0x81, 0xd3, 0xef, 0x74, 0xa0, 0xe0, 0x5e, - 0x29, 0x68, 0x43, 0x41, 0xa0, 0x14, 0x74, 0xa1, 0xc0, 0x57, 0x0a, 0x8e, 0xa0, 0x60, 0xac, 0x14, 0x1c, 0x43, 0xc1, - 0x9d, 0x9e, 0x5f, 0x47, 0x72, 0xb8, 0xc7, 0xc6, 0x8d, 0x49, 0x4c, 0x85, 0x28, 0x3b, 0x36, 0x5d, 0xb0, 0x26, 0xf2, - 0xa6, 0xbd, 0xd8, 0x24, 0xf9, 0x5e, 0x2f, 0x31, 0xef, 0x67, 0x8c, 0x02, 0x28, 0xbf, 0xc1, 0x3b, 0xc7, 0xce, 0x62, - 0xb0, 0x27, 0x16, 0x81, 0x09, 0x04, 0x1c, 0x34, 0xdd, 0x00, 0x99, 0x4d, 0x5f, 0xae, 0x9c, 0x08, 0xee, 0xa0, 0xac, - 0x65, 0xf1, 0x8e, 0x3e, 0x67, 0xc9, 0x2d, 0x50, 0x98, 0x78, 0xb4, 0x54, 0xb9, 0xe0, 0x97, 0x50, 0xf4, 0xbf, 0x61, - 0xa3, 0xe5, 0x54, 0xbb, 0x8c, 0xa7, 0x3b, 0x75, 0xf6, 0xea, 0x2b, 0x18, 0xa5, 0x4e, 0x0a, 0x10, 0x4b, 0x6c, 0x4b, - 0xfe, 0x2d, 0x7a, 0xcc, 0xcb, 0xf5, 0x33, 0x18, 0x9b, 0x96, 0x91, 0xc5, 0x08, 0x7c, 0x07, 0x60, 0xa4, 0x28, 0xcd, - 0x2f, 0x01, 0xce, 0xca, 0xf3, 0x95, 0xa7, 0x8c, 0xe7, 0xec, 0x07, 0x96, 0xa6, 0xde, 0x54, 0xd4, 0xaf, 0x8f, 0x13, - 0xac, 0x64, 0x24, 0xff, 0x85, 0x00, 0x04, 0x61, 0x5a, 0x50, 0x33, 0x86, 0x48, 0xe2, 0x7b, 0x0d, 0xcc, 0x6d, 0x60, - 0x43, 0x15, 0x86, 0x01, 0x81, 0x0d, 0x4b, 0x58, 0x56, 0xe1, 0xc3, 0xe1, 0xbf, 0x63, 0x61, 0xb5, 0x30, 0xf3, 0xa6, - 0xd5, 0x22, 0xda, 0x07, 0xb9, 0x3a, 0x36, 0xa9, 0x41, 0x2f, 0x15, 0x7e, 0x8e, 0x4a, 0x38, 0x8c, 0xa7, 0x7f, 0xaa, - 0x3e, 0x78, 0x8b, 0x1e, 0xff, 0x43, 0x64, 0x06, 0xd9, 0xd0, 0x46, 0x18, 0x6b, 0x36, 0x80, 0xb0, 0x17, 0x65, 0x33, - 0x0b, 0x5d, 0xae, 0x5a, 0xed, 0xc8, 0x30, 0x6d, 0x5c, 0xdb, 0x75, 0xd5, 0xd1, 0xb4, 0x97, 0x4c, 0x47, 0x5e, 0xcb, - 0x6d, 0x1f, 0x9b, 0xe2, 0xcf, 0x76, 0xba, 0x46, 0x8e, 0x3d, 0x68, 0xe3, 0xe0, 0x6e, 0x3d, 0x89, 0xa3, 0xcc, 0x9a, - 0x78, 0xf3, 0x20, 0x7c, 0xe8, 0xcd, 0xe3, 0x28, 0x4e, 0x17, 0x9e, 0xcf, 0xfa, 0x05, 0x43, 0xdd, 0xc7, 0x10, 0x06, - 0xdc, 0x8b, 0xce, 0xb5, 0xdb, 0x09, 0x9b, 0x53, 0x6b, 0x19, 0xa1, 0x60, 0x12, 0xb2, 0x55, 0xce, 0x3f, 0x5f, 0xaa, - 0x4c, 0x55, 0x71, 0xcb, 0x51, 0x0b, 0xa0, 0x48, 0x79, 0xf8, 0x03, 0x08, 0xfa, 0xd3, 0x5f, 0x78, 0x63, 0x8c, 0xd8, - 0x67, 0xb7, 0xbb, 0x09, 0x9b, 0x6b, 0x76, 0x77, 0x63, 0xe7, 0x49, 0x7c, 0x7f, 0x06, 0xa3, 0xc5, 0xc6, 0x56, 0xca, - 0xc2, 0x09, 0xbe, 0xb1, 0xd0, 0xe3, 0x42, 0xf4, 0x63, 0x21, 0x23, 0x0e, 0xbd, 0xb1, 0x79, 0x1f, 0x5e, 0xf7, 0xda, - 0x9a, 0xd3, 0x9f, 0x07, 0x91, 0x45, 0xd3, 0x39, 0x76, 0x16, 0x4a, 0x5f, 0x2a, 0xfc, 0x8c, 0x35, 0x56, 0x77, 0x35, - 0xa7, 0x0f, 0xcc, 0xda, 0x24, 0x8c, 0xef, 0x7b, 0xb3, 0x60, 0x3c, 0x66, 0x51, 0x1f, 0xc7, 0x2c, 0x0b, 0x59, 0x18, - 0x06, 0x8b, 0x34, 0x48, 0xfb, 0x73, 0x6f, 0xc5, 0x7b, 0x3d, 0xdc, 0xd4, 0x6b, 0x87, 0xf7, 0xda, 0xd9, 0xbb, 0x57, - 0xa5, 0x1b, 0xf0, 0xee, 0xa0, 0x7e, 0xf8, 0xd0, 0xba, 0x9a, 0x53, 0x99, 0xe7, 0xde, 0xbd, 0x2e, 0x12, 0xb6, 0x9e, - 0x7b, 0xc9, 0x34, 0x88, 0x7a, 0x4e, 0x6e, 0xdf, 0xad, 0x69, 0x63, 0x3c, 0x3d, 0x39, 0x39, 0xc9, 0xed, 0xb1, 0x78, - 0x72, 0xc6, 0xe3, 0xdc, 0xf6, 0xc5, 0xd3, 0x64, 0xe2, 0x38, 0x93, 0x49, 0x6e, 0x07, 0xa2, 0xa0, 0xd3, 0xf6, 0xc7, - 0x9d, 0x76, 0x6e, 0xdf, 0x2b, 0x35, 0x72, 0x9b, 0xf1, 0xa7, 0x84, 0x8d, 0xfb, 0xb8, 0x91, 0xee, 0x69, 0xe9, 0x8f, - 0x1d, 0x27, 0x47, 0x0c, 0x70, 0x5d, 0xc2, 0x4d, 0x28, 0xeb, 0xb9, 0x59, 0xef, 0x5d, 0x53, 0x2b, 0x3e, 0xe7, 0xfb, - 0x8d, 0xf5, 0xc6, 0x5e, 0xf2, 0xe9, 0x46, 0x53, 0x66, 0xe1, 0x79, 0x54, 0x6d, 0x2d, 0xc0, 0x60, 0xad, 0x7a, 0x10, - 0xca, 0xaa, 0x3f, 0x8a, 0x13, 0x38, 0xb3, 0x89, 0x37, 0x0e, 0x96, 0x69, 0xcf, 0x6d, 0x2f, 0x56, 0xa2, 0x88, 0xef, - 0xf5, 0xa2, 0x00, 0xcf, 0x5e, 0x2f, 0x8d, 0xc3, 0x60, 0x2c, 0x8a, 0x36, 0x9d, 0x25, 0xb7, 0x6d, 0xf4, 0xd1, 0x91, - 0x3b, 0xc0, 0x70, 0x04, 0x5e, 0x18, 0x6a, 0x76, 0x27, 0xd5, 0x98, 0x97, 0xa2, 0x88, 0x57, 0x73, 0x52, 0x82, 0x0b, - 0x3a, 0x6d, 0xbb, 0x87, 0x8b, 0x95, 0xdc, 0xf3, 0xee, 0xd1, 0x62, 0x95, 0x7f, 0x3d, 0x67, 0xe3, 0xc0, 0xd3, 0x5a, - 0xc5, 0x6e, 0x72, 0x1d, 0x10, 0x03, 0x1b, 0xeb, 0x0d, 0xdb, 0x54, 0x1c, 0x0b, 0x08, 0xf9, 0xf7, 0x24, 0x98, 0x2f, - 0xe2, 0x24, 0xf3, 0xa2, 0x2c, 0xcf, 0x87, 0x37, 0x79, 0xde, 0xbf, 0x0a, 0x5a, 0xd7, 0xff, 0x6c, 0xd1, 0x3d, 0x4d, - 0x6a, 0x93, 0xdc, 0xb8, 0x31, 0xdf, 0x32, 0xd5, 0x48, 0x03, 0xae, 0x31, 0x34, 0xd0, 0x50, 0x2b, 0xd3, 0x2d, 0x59, - 0xaf, 0x4c, 0x40, 0x96, 0xd5, 0xc9, 0xe8, 0xa3, 0x5c, 0x05, 0x6f, 0x20, 0xa8, 0xf0, 0x96, 0x0d, 0xae, 0x14, 0x83, - 0x0f, 0x20, 0x56, 0xb0, 0x32, 0xd9, 0xdb, 0x3f, 0xdb, 0x44, 0x33, 0x7e, 0xb3, 0x9b, 0x66, 0xfc, 0x39, 0xdb, 0x87, - 0x66, 0xfc, 0xe6, 0x8b, 0xd3, 0x8c, 0xcf, 0xea, 0xf6, 0xf6, 0x17, 0xf1, 0x40, 0x97, 0x42, 0x7e, 0xb8, 0x9a, 0x12, - 0x8a, 0x64, 0x73, 0xf1, 0x87, 0xcd, 0xe3, 0x45, 0x6f, 0x94, 0x9b, 0x8d, 0x6e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0x06, - 0xff, 0x48, 0xd4, 0xe7, 0xc9, 0x64, 0xf0, 0x26, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0x7f, 0x28, 0x45, 0x1d, 0xa0, 0x37, - 0xc2, 0xec, 0x11, 0xf3, 0x32, 0x80, 0xd3, 0x32, 0x99, 0xf9, 0x8e, 0xa5, 0xb9, 0x57, 0xbf, 0x3c, 0x84, 0x96, 0xb4, - 0xb1, 0x14, 0xae, 0x29, 0x35, 0x51, 0xe2, 0x94, 0x65, 0xdc, 0x97, 0xf4, 0xdb, 0x87, 0x8b, 0x71, 0xeb, 0x22, 0x36, - 0xf2, 0x20, 0x7d, 0x57, 0x75, 0x0c, 0xe1, 0xea, 0x97, 0x81, 0x3a, 0x9d, 0x9c, 0x9b, 0x6c, 0xa9, 0x89, 0x97, 0xe1, - 0x35, 0x35, 0x3f, 0x2f, 0xcd, 0xb4, 0xa7, 0x36, 0xe4, 0x09, 0xa0, 0x6a, 0x97, 0x31, 0xb7, 0xca, 0x5f, 0x73, 0x0a, - 0x10, 0x73, 0x5a, 0xa1, 0x3f, 0xed, 0x98, 0x9a, 0x07, 0xe3, 0x3c, 0x37, 0xfa, 0x02, 0x10, 0xca, 0x45, 0xcb, 0x76, - 0x11, 0x71, 0xe9, 0xbd, 0xb4, 0x2a, 0xe0, 0x4a, 0x3a, 0xd2, 0xc0, 0x5d, 0x80, 0x4a, 0x9b, 0xeb, 0xeb, 0x38, 0xcc, - 0x74, 0x8d, 0xc0, 0x47, 0xa6, 0x0e, 0xca, 0x84, 0x40, 0xe3, 0x2d, 0xe1, 0x2f, 0x5e, 0x89, 0x82, 0xba, 0xd1, 0x24, - 0x01, 0x07, 0x75, 0xf2, 0xe0, 0xfd, 0x2e, 0xe4, 0xda, 0x84, 0x76, 0x78, 0x1d, 0x7c, 0xc8, 0x75, 0x49, 0xfb, 0xe1, - 0xf6, 0x3b, 0x3b, 0x3d, 0x80, 0x06, 0x67, 0x15, 0xd5, 0xfd, 0x0e, 0x93, 0x40, 0x20, 0x25, 0xd2, 0x7b, 0xd3, 0x4e, - 0xef, 0xb5, 0x17, 0x6b, 0x11, 0x39, 0x22, 0xf3, 0x16, 0x16, 0xb0, 0xf8, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x82, 0x54, - 0xf4, 0x97, 0x29, 0xe0, 0x46, 0x64, 0x54, 0x11, 0xff, 0xf4, 0xfd, 0x65, 0x92, 0xc6, 0x49, 0x6f, 0x11, 0x07, 0x51, - 0xc6, 0x92, 0x1c, 0x41, 0x75, 0x8d, 0xf0, 0x11, 0xe0, 0xb9, 0x59, 0xc7, 0x0b, 0xcf, 0x0f, 0xb2, 0x87, 0x9e, 0xc3, - 0x49, 0x0a, 0xa7, 0xcf, 0xa9, 0x03, 0xa7, 0xb1, 0x7e, 0x8f, 0x43, 0xf3, 0x25, 0x12, 0x7e, 0x49, 0x9d, 0x9c, 0x51, - 0xb7, 0x79, 0x5f, 0x79, 0x4b, 0xb1, 0x33, 0x80, 0xfc, 0xf0, 0x12, 0x6b, 0x0a, 0x58, 0x1e, 0x96, 0xda, 0x19, 0xb3, - 0xa9, 0x89, 0x58, 0x1b, 0xe4, 0xf2, 0xe2, 0xcf, 0xee, 0x1a, 0x9a, 0xd3, 0x5c, 0x0c, 0x14, 0x8f, 0xb1, 0xcf, 0xc8, - 0x7a, 0x1e, 0x64, 0x9a, 0x32, 0xf7, 0xa9, 0x39, 0x62, 0x93, 0x38, 0x61, 0x14, 0x67, 0xd5, 0x3d, 0x59, 0xac, 0xf6, - 0xef, 0x7e, 0xfb, 0xf4, 0x9b, 0xfb, 0x89, 0xe2, 0xac, 0x25, 0x3a, 0x33, 0x76, 0xf4, 0x56, 0xbf, 0xcf, 0x80, 0x34, - 0x24, 0xc8, 0xfb, 0x14, 0xd2, 0xaa, 0xa7, 0xeb, 0xfd, 0xc6, 0x70, 0x56, 0x8b, 0x98, 0xdf, 0x79, 0x09, 0x0b, 0xbd, - 0x2c, 0xb8, 0x13, 0x34, 0x63, 0xe7, 0x68, 0xb1, 0x12, 0x6b, 0x8c, 0x17, 0xde, 0x23, 0x16, 0xa9, 0x32, 0x14, 0xb1, - 0x48, 0xd5, 0x62, 0x5c, 0xa4, 0x7e, 0x6d, 0x36, 0x22, 0xc2, 0x43, 0xe5, 0xa6, 0xef, 0x2e, 0x56, 0xea, 0x15, 0x5d, - 0x34, 0x93, 0x37, 0x75, 0x35, 0x34, 0xd7, 0x3c, 0x18, 0x8f, 0x43, 0x96, 0x97, 0x16, 0xba, 0xbc, 0x96, 0x0a, 0x70, - 0x24, 0x1c, 0xbc, 0x51, 0x1a, 0x87, 0xcb, 0x8c, 0x35, 0x83, 0x8b, 0x80, 0xd3, 0x76, 0x0a, 0xe0, 0xe0, 0xef, 0xf2, - 0x58, 0xbb, 0x40, 0x6e, 0xc3, 0x36, 0x71, 0xfa, 0x10, 0x89, 0xd7, 0xea, 0x94, 0x87, 0x0e, 0xaf, 0xe4, 0xa0, 0xcd, - 0x86, 0x89, 0x98, 0x70, 0x2d, 0x11, 0xf6, 0xd6, 0x6c, 0x97, 0x97, 0xc9, 0x68, 0xa4, 0xb2, 0x28, 0x2f, 0x4f, 0xe6, - 0xcf, 0x39, 0x63, 0xaf, 0x9a, 0xcf, 0xd8, 0x2b, 0x71, 0xc6, 0xb6, 0xef, 0xcc, 0xa7, 0x13, 0x17, 0xfe, 0xeb, 0x17, - 0x13, 0xea, 0x39, 0x5a, 0x67, 0xb1, 0xd2, 0xdc, 0xc5, 0x4a, 0xb3, 0xda, 0x8b, 0x95, 0x86, 0x5d, 0xa3, 0x49, 0x86, - 0x69, 0xb7, 0x0d, 0xd3, 0xd1, 0xa0, 0x10, 0xfe, 0x9c, 0xd2, 0x2b, 0xf7, 0x10, 0xde, 0x41, 0xab, 0x6e, 0xfd, 0x5d, - 0x7b, 0xfb, 0x51, 0xa7, 0xb3, 0x24, 0x90, 0xb6, 0x61, 0x67, 0xde, 0x68, 0xc4, 0xc6, 0xbd, 0x49, 0xec, 0x2f, 0xd3, - 0x7f, 0xf3, 0xf1, 0x73, 0x20, 0x6e, 0x45, 0x04, 0x95, 0x7e, 0x44, 0x53, 0x50, 0x94, 0xdc, 0x31, 0xd1, 0xc3, 0x5a, - 0xae, 0x53, 0x8f, 0xc2, 0x06, 0xb7, 0xed, 0xc3, 0x86, 0x4d, 0xde, 0x0c, 0xe8, 0x3f, 0x6d, 0x95, 0x36, 0xa3, 0x98, - 0xcf, 0x00, 0xcb, 0x56, 0x70, 0x3c, 0x1e, 0x1a, 0x7c, 0x35, 0x9d, 0x93, 0xe6, 0xe1, 0x5e, 0x8b, 0x2f, 0xdd, 0x88, - 0x4b, 0x85, 0xdf, 0x5b, 0xdc, 0x13, 0x64, 0x7b, 0xaf, 0x9b, 0xf6, 0x48, 0xad, 0xd7, 0x2d, 0x17, 0x42, 0x51, 0x77, - 0x4f, 0x2c, 0xff, 0xf4, 0xd5, 0x21, 0xfc, 0x47, 0x54, 0xfd, 0xcf, 0x59, 0x13, 0xa1, 0x7e, 0x51, 0x36, 0xbd, 0x26, - 0x52, 0x09, 0x09, 0xf1, 0xfd, 0xeb, 0x4f, 0x26, 0x8f, 0x6b, 0xb0, 0x77, 0x6d, 0xb2, 0x66, 0xaa, 0xd6, 0xfe, 0x36, - 0x8e, 0x21, 0xa5, 0x65, 0xbd, 0xba, 0x00, 0x0f, 0x59, 0x97, 0x67, 0x03, 0x68, 0x24, 0xf8, 0x08, 0xd2, 0xe2, 0xeb, - 0xd8, 0x86, 0x58, 0x89, 0xb7, 0x9b, 0x58, 0x89, 0x37, 0xbb, 0x59, 0x89, 0xef, 0xf7, 0x62, 0x25, 0xde, 0x7c, 0x71, - 0x56, 0xe2, 0x6d, 0x9d, 0x95, 0xb8, 0x8a, 0x85, 0x05, 0xab, 0x79, 0xb1, 0xe4, 0x3f, 0x3f, 0x92, 0x52, 0xee, 0x32, - 0x1e, 0x74, 0x1d, 0x0a, 0x05, 0x7c, 0xf5, 0x87, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd1, 0xa2, 0xab, 0x60, 0x2d, 0x38, - 0x66, 0xc7, 0xef, 0x28, 0xc5, 0x61, 0x1c, 0x4d, 0x7f, 0x02, 0xa5, 0x2c, 0x88, 0x03, 0x13, 0xe5, 0x45, 0x90, 0xfe, - 0x14, 0x2f, 0x96, 0x8b, 0x0b, 0xe8, 0xeb, 0x63, 0x90, 0x06, 0xa3, 0x90, 0x49, 0x0f, 0x5d, 0xb2, 0x40, 0xe3, 0x32, - 0x71, 0xb0, 0xf9, 0x14, 0x3f, 0xbd, 0x95, 0xf8, 0x89, 0x56, 0xa1, 0xfc, 0x37, 0x99, 0xb6, 0xe9, 0xcd, 0x8c, 0x88, - 0x50, 0x02, 0x2a, 0x83, 0x7e, 0x3c, 0x33, 0x72, 0x15, 0x1b, 0x0d, 0xb3, 0x14, 0xf6, 0x0e, 0x1b, 0xfb, 0x61, 0x35, - 0xa6, 0x66, 0x69, 0x98, 0x32, 0x34, 0x55, 0x5d, 0x0c, 0x3f, 0x8f, 0x97, 0x29, 0x1b, 0xc7, 0xf7, 0x91, 0x6e, 0x46, - 0xd2, 0xaa, 0x1f, 0x34, 0x9c, 0xb2, 0x0d, 0x26, 0x55, 0xfc, 0x80, 0x84, 0x72, 0x9c, 0xb4, 0x74, 0xc8, 0xe9, 0xb9, - 0x5c, 0x58, 0xa4, 0x6a, 0xb6, 0x70, 0x8a, 0xba, 0xcc, 0xfe, 0xf3, 0xa4, 0xd5, 0x8a, 0x07, 0x8f, 0x6b, 0x29, 0x4c, - 0x35, 0x62, 0x9b, 0x4b, 0x85, 0xd3, 0x56, 0x24, 0x84, 0x8b, 0x22, 0x3e, 0x44, 0xc3, 0xc2, 0xf1, 0x37, 0xe4, 0x2b, - 0x5a, 0xbc, 0x85, 0xe8, 0x1a, 0xf9, 0x92, 0xaf, 0x07, 0x8f, 0x96, 0x40, 0x8f, 0xaf, 0x15, 0x30, 0xbe, 0xbb, 0x63, - 0x49, 0xe8, 0x3d, 0xb4, 0x8c, 0x3c, 0x8e, 0x7e, 0x00, 0x00, 0xbc, 0x89, 0xef, 0x23, 0xb5, 0x02, 0x26, 0x31, 0x69, - 0xd8, 0x4b, 0x8d, 0x71, 0x3d, 0xc0, 0x53, 0x44, 0x19, 0x01, 0xa4, 0x8f, 0x9d, 0xb2, 0x7f, 0x98, 0xf4, 0xef, 0x3f, - 0x8d, 0xdc, 0xbc, 0x8c, 0xe5, 0x87, 0xfe, 0xbe, 0xd8, 0xe3, 0x33, 0xcf, 0x9f, 0x3f, 0xd9, 0x3c, 0xed, 0x72, 0xda, - 0xf2, 0x86, 0xd6, 0xc6, 0xc6, 0x53, 0x00, 0xa3, 0xb8, 0x8a, 0x97, 0xfe, 0x0c, 0x6d, 0x4d, 0xbf, 0xdc, 0x7c, 0x33, - 0xe8, 0x13, 0xb3, 0x77, 0xca, 0xa9, 0x57, 0x8a, 0x0a, 0x28, 0xe0, 0xf7, 0xdf, 0x42, 0x60, 0xca, 0xff, 0x21, 0x18, - 0xea, 0xbb, 0x86, 0x73, 0xf1, 0xc1, 0xe3, 0x36, 0x6f, 0x1f, 0x92, 0x4c, 0xf2, 0x90, 0x0f, 0x42, 0xb9, 0xd6, 0x8c, - 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0xf0, 0x6a, 0x9b, 0x22, 0xc7, 0x89, 0xaf, 0x30, 0x9b, 0xd8, 0x74, 0x6e, 0xea, 0x6f, - 0x32, 0x8e, 0xad, 0x2a, 0x48, 0x86, 0x9b, 0x3c, 0x30, 0x44, 0x5f, 0xd5, 0x77, 0xf3, 0x20, 0x32, 0x31, 0x3a, 0x7a, - 0xfd, 0x8d, 0xb7, 0x82, 0xf8, 0xc0, 0x80, 0xdc, 0xaa, 0xaf, 0xa0, 0xd0, 0x54, 0x1d, 0xd5, 0x20, 0x05, 0x92, 0xde, - 0x08, 0x09, 0xa1, 0xc5, 0x1b, 0xfe, 0x45, 0xd3, 0x34, 0x4d, 0xb2, 0x11, 0x9a, 0xe4, 0x23, 0xb0, 0x1c, 0xd9, 0x01, - 0xd0, 0x96, 0xe4, 0x8b, 0x15, 0x95, 0x00, 0x67, 0x80, 0x3a, 0x59, 0x51, 0xc0, 0x43, 0xe0, 0x75, 0x1d, 0x51, 0x20, - 0x18, 0x7a, 0x08, 0x5f, 0xe6, 0x25, 0x10, 0x29, 0xb7, 0xa7, 0x21, 0xc3, 0x8e, 0x6f, 0xb9, 0x24, 0x58, 0x73, 0xe8, - 0x71, 0xd8, 0x67, 0xcd, 0xb1, 0xd2, 0x22, 0x05, 0x0b, 0x82, 0xd6, 0xa1, 0x12, 0xfa, 0xd8, 0x64, 0x0d, 0xb8, 0x11, - 0xf9, 0xa2, 0x55, 0x36, 0x67, 0xd1, 0x52, 0xc7, 0x5c, 0x49, 0x18, 0xbb, 0x0e, 0xea, 0xbc, 0x21, 0x62, 0x0b, 0xb0, - 0x4d, 0x73, 0xcb, 0x19, 0xdd, 0x85, 0x29, 0x47, 0xa9, 0x9e, 0xe9, 0x73, 0xc5, 0x66, 0xca, 0x71, 0x5b, 0xf5, 0x86, - 0xe0, 0x4b, 0x1a, 0x57, 0x3d, 0xa7, 0xc8, 0x18, 0x19, 0xfa, 0xa0, 0xa8, 0x11, 0x5c, 0x5c, 0x24, 0xc0, 0xde, 0xf2, - 0xaa, 0x8b, 0x26, 0x35, 0x32, 0x5e, 0x45, 0x50, 0x94, 0x18, 0xf5, 0x6e, 0xf8, 0x38, 0x21, 0x60, 0xcf, 0xc6, 0x7e, - 0xfc, 0x5a, 0x3f, 0x1b, 0x26, 0xfd, 0x89, 0x3d, 0xd0, 0x45, 0x42, 0xa0, 0xfa, 0xc4, 0x1e, 0xc0, 0xf6, 0xef, 0x2d, - 0x48, 0x53, 0xf4, 0x2d, 0xe8, 0xda, 0x84, 0x10, 0xf8, 0x3e, 0x04, 0x71, 0xda, 0x72, 0x80, 0x9c, 0x7c, 0x0b, 0x16, - 0x47, 0x10, 0x43, 0xb6, 0x63, 0x71, 0x88, 0xb9, 0x95, 0x7d, 0xab, 0x11, 0xc6, 0x56, 0xc3, 0xd1, 0x30, 0x5e, 0xb8, - 0x8e, 0x73, 0x50, 0xab, 0x0f, 0x82, 0xec, 0xa6, 0xda, 0x86, 0x99, 0x0d, 0x5c, 0xc7, 0x0a, 0x5e, 0xd8, 0xed, 0x7e, - 0xed, 0x8e, 0x56, 0x62, 0x2c, 0x0e, 0x51, 0xfc, 0x75, 0xf6, 0x6c, 0xdd, 0xaa, 0x1d, 0x48, 0xa3, 0x6a, 0xb5, 0x8e, - 0x63, 0xcb, 0xb9, 0xfc, 0x6b, 0x58, 0xbf, 0xfa, 0x29, 0xc2, 0x23, 0xe5, 0xfb, 0x18, 0x42, 0x94, 0xe0, 0x16, 0x1c, - 0xa3, 0xbf, 0x6a, 0x2f, 0xb5, 0x16, 0x1d, 0x1f, 0xc3, 0x18, 0xca, 0x34, 0xd2, 0xc2, 0xab, 0x4b, 0xed, 0xa0, 0xf2, - 0xc5, 0xb4, 0x8a, 0xe1, 0x78, 0x3c, 0x52, 0x56, 0x68, 0xf4, 0xb6, 0x52, 0x0b, 0xd8, 0xff, 0x86, 0xeb, 0xd3, 0x1e, - 0x41, 0x20, 0x00, 0xa8, 0x01, 0x31, 0xc5, 0x77, 0x76, 0xb8, 0x5c, 0x94, 0xbb, 0x2b, 0x5f, 0x92, 0xfb, 0x77, 0x86, - 0x97, 0x0e, 0xea, 0xd0, 0x64, 0x7f, 0xcd, 0xd7, 0xdd, 0x23, 0xbb, 0x64, 0xd1, 0xb8, 0xdc, 0x61, 0xe5, 0xfe, 0xda, - 0xbf, 0xbb, 0x12, 0x46, 0x81, 0x60, 0xfb, 0x71, 0x03, 0x46, 0xc9, 0xe3, 0x08, 0x37, 0x3f, 0x1d, 0xb7, 0x60, 0x2f, - 0x2a, 0x06, 0x1b, 0x50, 0xa4, 0x2c, 0xd9, 0x4c, 0x11, 0x8a, 0x43, 0x44, 0x67, 0xf4, 0xc3, 0x6d, 0x09, 0x42, 0x74, - 0xe3, 0x4e, 0xcc, 0x84, 0x4d, 0x61, 0xd1, 0x26, 0xe0, 0x31, 0x1a, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, 0xd9, - 0x2e, 0xa9, 0x35, 0x39, 0x34, 0xdd, 0x27, 0xde, 0x42, 0xf1, 0x89, 0x13, 0xc4, 0xb9, 0xea, 0x1a, 0x57, 0x12, 0x75, - 0xa3, 0xff, 0x93, 0x68, 0x55, 0xeb, 0x8d, 0xac, 0x04, 0x51, 0xfc, 0xad, 0x30, 0x28, 0x42, 0xa1, 0xae, 0xca, 0xc6, - 0xaf, 0x0a, 0xd9, 0x38, 0x71, 0x35, 0x85, 0x2f, 0x8b, 0xa0, 0xfe, 0x15, 0x37, 0x31, 0xc9, 0x1d, 0x14, 0xee, 0x62, - 0xc5, 0x48, 0x15, 0x07, 0xa8, 0x82, 0xd1, 0x50, 0xdc, 0xea, 0x04, 0x97, 0x51, 0xf6, 0xae, 0x2b, 0x57, 0x2d, 0xbc, - 0xcd, 0x8a, 0x72, 0x90, 0xba, 0xe3, 0x90, 0x65, 0xb1, 0xba, 0x6d, 0xca, 0x1e, 0x30, 0xea, 0x6b, 0x65, 0x93, 0x48, - 0x57, 0x15, 0x02, 0xb0, 0x10, 0xd3, 0x57, 0xf4, 0xda, 0xd2, 0x06, 0x02, 0x07, 0xd9, 0xe0, 0x58, 0xb7, 0x5b, 0x3a, - 0x4f, 0x79, 0x04, 0x0a, 0x2d, 0xbc, 0x2a, 0x83, 0x40, 0xf8, 0xde, 0xac, 0x1b, 0x6e, 0x79, 0xbc, 0xe4, 0xf9, 0xfd, - 0x0e, 0xe2, 0x45, 0xcd, 0x51, 0x15, 0xf9, 0x78, 0x32, 0x2d, 0x32, 0xcf, 0xc5, 0xaa, 0xf5, 0x4e, 0x49, 0x88, 0xb3, - 0xe6, 0xce, 0x29, 0x65, 0x19, 0x3d, 0xaf, 0xd1, 0x13, 0xdf, 0xe5, 0x5b, 0x27, 0x59, 0x46, 0x18, 0xf3, 0xdd, 0xca, - 0x12, 0xcf, 0xff, 0xa4, 0x0c, 0x59, 0xc8, 0x39, 0x41, 0x06, 0x5c, 0xd6, 0x14, 0xf4, 0x3d, 0x0c, 0x91, 0xc8, 0x7a, - 0x76, 0x3b, 0x55, 0xa4, 0x2f, 0xbd, 0xa7, 0x4e, 0xc7, 0x7b, 0x35, 0x39, 0xac, 0x08, 0x45, 0xdb, 0xdd, 0xb2, 0xc8, - 0x7c, 0xc3, 0x38, 0xb2, 0xd9, 0x72, 0x3e, 0x5a, 0xab, 0xb2, 0x55, 0x45, 0xe4, 0x5a, 0x17, 0xb3, 0xaa, 0x9f, 0x9d, - 0x4c, 0x26, 0x65, 0x41, 0xa3, 0xa3, 0x1d, 0xa2, 0xb0, 0xf0, 0xa9, 0xe3, 0x38, 0xd5, 0xb1, 0x6f, 0x07, 0xbb, 0x85, - 0x72, 0xdb, 0x93, 0xc6, 0x11, 0x23, 0x6c, 0x77, 0xc1, 0xaf, 0x0e, 0x8e, 0xdc, 0x2e, 0x4e, 0x76, 0xc9, 0x2c, 0xa2, - 0x4f, 0xc6, 0x10, 0x41, 0xc6, 0xe6, 0x69, 0xcf, 0x67, 0xa8, 0x83, 0xb1, 0x95, 0x03, 0x8d, 0x86, 0x03, 0xd6, 0x14, - 0x4c, 0x45, 0x5c, 0xb1, 0x2b, 0x1c, 0x0d, 0xe5, 0xe1, 0x35, 0xe1, 0xbd, 0xf8, 0x08, 0x1e, 0x94, 0x75, 0x5d, 0xa6, - 0x8d, 0xd3, 0xea, 0x3a, 0x7f, 0x2d, 0xd5, 0xd3, 0xe0, 0x02, 0x5c, 0x0b, 0x85, 0x36, 0xc9, 0x67, 0xf1, 0xff, 0xa5, - 0xfc, 0xff, 0xd5, 0x62, 0x55, 0xb6, 0x1f, 0x39, 0x01, 0x89, 0x76, 0x71, 0x5a, 0x68, 0xd4, 0x4d, 0x7b, 0x40, 0x5a, - 0x19, 0x4c, 0x54, 0x05, 0x3a, 0x28, 0xe9, 0x4b, 0x89, 0x31, 0x1a, 0xc4, 0xef, 0x48, 0x31, 0xc3, 0x12, 0x17, 0x22, - 0xc4, 0x22, 0xad, 0x1b, 0xcc, 0xc1, 0x7c, 0x79, 0x82, 0xfa, 0x83, 0xd2, 0x9e, 0x00, 0x6d, 0x7c, 0x6d, 0x6e, 0x7b, - 0x89, 0xfb, 0xab, 0x7a, 0x2d, 0xd1, 0x31, 0x80, 0xcc, 0x85, 0x43, 0x88, 0x86, 0x04, 0x5a, 0x65, 0x73, 0xd3, 0x28, - 0xe5, 0x5b, 0x55, 0xcf, 0x26, 0x06, 0x86, 0xdd, 0x35, 0x57, 0xa1, 0xbe, 0x85, 0xb6, 0x00, 0x26, 0xcb, 0xb7, 0x1f, - 0x3e, 0x5b, 0xb0, 0xc4, 0xea, 0x7e, 0x74, 0x71, 0xc9, 0x71, 0xff, 0x5a, 0x78, 0x77, 0xa6, 0x74, 0xfe, 0x51, 0xbe, - 0xf8, 0x7d, 0xa3, 0x40, 0xef, 0xaa, 0x24, 0xa1, 0xe3, 0xd6, 0xe2, 0x6d, 0x63, 0xaf, 0xda, 0xf3, 0x20, 0xda, 0xbf, - 0xae, 0xb7, 0xda, 0xbb, 0x2e, 0x5c, 0x18, 0x7b, 0x57, 0x86, 0x1b, 0x87, 0x2c, 0x17, 0xb2, 0xc1, 0xf7, 0x8a, 0x40, - 0x51, 0xf5, 0xfb, 0xd5, 0xb1, 0x15, 0x51, 0xf9, 0x57, 0x4b, 0x20, 0x3e, 0xf7, 0x4a, 0x7c, 0xa0, 0x89, 0xdc, 0x65, - 0xfa, 0xb1, 0x76, 0xa2, 0x1d, 0x77, 0xb4, 0x23, 0x47, 0x27, 0x2e, 0x6c, 0xa0, 0x77, 0xdb, 0x85, 0x43, 0xdf, 0xa1, - 0xa3, 0x9f, 0x9d, 0x4e, 0xc5, 0x25, 0x31, 0x09, 0xc2, 0x90, 0x50, 0x45, 0x9a, 0x25, 0xf1, 0x27, 0x56, 0x56, 0xb3, - 0x50, 0x19, 0x37, 0x02, 0x69, 0x8b, 0x47, 0x38, 0x3b, 0xbe, 0xb7, 0xe8, 0xe1, 0xd9, 0x50, 0x0b, 0xc1, 0x80, 0x93, - 0x4a, 0xf1, 0x13, 0x70, 0x07, 0x8f, 0xf4, 0xb3, 0x53, 0x08, 0xed, 0xa7, 0x8d, 0x07, 0xfa, 0x0f, 0xed, 0x63, 0xcd, - 0xed, 0xde, 0x59, 0x1d, 0xdf, 0xb1, 0x5c, 0xfb, 0x50, 0x73, 0xec, 0x23, 0xab, 0x6d, 0x1f, 0x6b, 0x6d, 0xbb, 0x0b, - 0xff, 0xfa, 0xae, 0xfd, 0x4a, 0x73, 0xe0, 0x49, 0x73, 0xed, 0x0e, 0xfe, 0xdb, 0xb6, 0x8f, 0xef, 0x3a, 0x74, 0xd3, - 0x7b, 0xd2, 0xad, 0xaa, 0x32, 0x0a, 0x70, 0x02, 0xd1, 0x0f, 0xce, 0x4e, 0x97, 0x29, 0xd3, 0x56, 0x03, 0xfd, 0x95, - 0xae, 0xcd, 0x12, 0x36, 0x19, 0xe8, 0x4f, 0x3d, 0xa5, 0xd4, 0x3d, 0x69, 0x2c, 0x6e, 0x1f, 0x37, 0x16, 0x77, 0x8e, - 0x1a, 0x8b, 0x0f, 0xbb, 0xe5, 0xe2, 0x83, 0x29, 0xbd, 0x52, 0x32, 0xeb, 0xcd, 0xbd, 0x2c, 0x09, 0x56, 0x2d, 0x57, - 0x03, 0x74, 0x6d, 0xc1, 0x3f, 0xc7, 0x6d, 0x43, 0xb6, 0x1a, 0x41, 0x2b, 0x09, 0x8d, 0xe3, 0x13, 0xcd, 0x3d, 0xfa, - 0x5b, 0xfb, 0xc8, 0x87, 0x7a, 0x90, 0x07, 0x12, 0xfe, 0xee, 0x3a, 0x27, 0xbe, 0xa3, 0x41, 0x43, 0x17, 0xfe, 0x9b, - 0x75, 0xdb, 0x3e, 0x3d, 0x38, 0xf0, 0xfe, 0xa3, 0x7b, 0x9c, 0x3a, 0x96, 0x0b, 0xff, 0xfd, 0x2a, 0x55, 0xee, 0xa0, - 0xf0, 0x57, 0xfb, 0x3d, 0x74, 0xb4, 0xce, 0xc9, 0xac, 0x6d, 0xbf, 0xba, 0x3b, 0xb6, 0x4f, 0x66, 0xee, 0xf1, 0x47, - 0x7a, 0x0a, 0xad, 0xb6, 0xfd, 0x0a, 0xfe, 0x3e, 0x76, 0x9c, 0x99, 0xe5, 0xda, 0x27, 0x77, 0x1d, 0xbb, 0x13, 0x5a, - 0x47, 0xf6, 0x09, 0xfc, 0xfd, 0x0a, 0xe0, 0x05, 0xb8, 0xf2, 0xc4, 0x9d, 0x1a, 0x6c, 0x8c, 0x8a, 0xfd, 0x86, 0xfa, - 0x91, 0xf6, 0xa1, 0xd6, 0x3d, 0xfc, 0xdb, 0xc9, 0x9d, 0x75, 0x38, 0x73, 0xdb, 0x77, 0xd6, 0xc6, 0x9f, 0x1f, 0x01, - 0xf2, 0xdb, 0x17, 0x0e, 0xc0, 0x88, 0x99, 0x3a, 0xfe, 0x32, 0x34, 0x2f, 0x37, 0x89, 0xd1, 0xdf, 0xef, 0x16, 0xa3, - 0x7f, 0xb7, 0xdc, 0x47, 0x8c, 0xfe, 0xfe, 0x8b, 0x8b, 0xd1, 0x2f, 0xab, 0x56, 0xdc, 0xef, 0xab, 0x11, 0xc5, 0x7f, - 0x5e, 0x57, 0x89, 0xe4, 0xc0, 0x6b, 0x5d, 0x5f, 0x2d, 0x6f, 0x20, 0xd8, 0xce, 0xfb, 0x78, 0xf0, 0xdd, 0xb2, 0x64, - 0xa2, 0x14, 0x03, 0x06, 0x78, 0x1f, 0x13, 0x06, 0xf8, 0x75, 0x39, 0x00, 0xbb, 0x08, 0x7e, 0x6b, 0x06, 0x63, 0x6b, - 0xe6, 0x85, 0x13, 0x79, 0xe3, 0x42, 0x49, 0x1f, 0x8b, 0xc1, 0x66, 0x1e, 0x2e, 0x13, 0x50, 0xd6, 0x2c, 0xe7, 0x51, - 0xda, 0x3b, 0x72, 0x00, 0xcd, 0xb7, 0x27, 0x49, 0x5e, 0x69, 0x6c, 0x8b, 0xf0, 0x44, 0xb7, 0xdc, 0xa6, 0x7f, 0xe3, - 0x7b, 0x34, 0x59, 0x6b, 0xee, 0xdd, 0xad, 0xf7, 0xab, 0x81, 0x2d, 0x88, 0x30, 0xe9, 0x03, 0x62, 0xa3, 0xe9, 0x7d, - 0xd9, 0x70, 0xac, 0x62, 0x2a, 0xb8, 0x79, 0xa4, 0x30, 0x92, 0x6a, 0x7b, 0xb7, 0x6c, 0x78, 0xb6, 0x6b, 0x9a, 0x0d, - 0x9f, 0x2f, 0x35, 0xdf, 0x62, 0xf5, 0x26, 0x3b, 0xae, 0x82, 0xaa, 0x92, 0x0f, 0xab, 0x11, 0x20, 0x05, 0xed, 0x59, - 0x98, 0xc6, 0x15, 0x84, 0x8f, 0xa3, 0xe1, 0x6d, 0xec, 0x28, 0xef, 0x4a, 0x7d, 0xaa, 0xe6, 0x74, 0x2f, 0xd6, 0x48, - 0x0f, 0x06, 0xbf, 0x02, 0x61, 0xc3, 0xef, 0xe3, 0x51, 0xac, 0xc2, 0x79, 0xad, 0xf4, 0x4b, 0xa4, 0x76, 0x3e, 0x73, - 0xd7, 0x75, 0xd2, 0x66, 0xa3, 0x21, 0xad, 0xcb, 0xe6, 0xe2, 0x8e, 0xc6, 0xcf, 0x93, 0xd9, 0x6a, 0x4e, 0xa6, 0xc5, - 0x68, 0x99, 0xbb, 0xad, 0x33, 0x51, 0xef, 0x29, 0x6c, 0x62, 0x93, 0x3f, 0xa8, 0x8e, 0xe3, 0xeb, 0x09, 0xe4, 0x2e, - 0xee, 0x21, 0x11, 0xa1, 0x50, 0x50, 0x6d, 0xb4, 0xb1, 0xed, 0x6f, 0x31, 0xff, 0x50, 0x3b, 0xe6, 0x9d, 0xa0, 0xad, - 0xee, 0x36, 0x8b, 0x11, 0xe9, 0xda, 0xb0, 0x2e, 0x29, 0x50, 0xdd, 0xee, 0xb1, 0xe9, 0x1e, 0x99, 0xf6, 0x71, 0xd7, - 0xc8, 0xc5, 0x81, 0x53, 0xbb, 0x2c, 0x01, 0x04, 0x4c, 0x76, 0xe5, 0x30, 0x83, 0x28, 0xc8, 0x02, 0x2f, 0xcc, 0x01, - 0xd5, 0x97, 0x69, 0xde, 0x7f, 0x2d, 0xd3, 0x0c, 0xe6, 0x28, 0x48, 0x32, 0x34, 0x57, 0xb6, 0x46, 0x2c, 0xbb, 0x67, - 0x2c, 0xda, 0xa0, 0xca, 0xad, 0x5a, 0x3f, 0xff, 0x79, 0xb6, 0xa0, 0x39, 0xd9, 0x59, 0x8c, 0xb2, 0x88, 0xef, 0x0f, - 0x61, 0xaa, 0x9b, 0x0f, 0xcd, 0x1f, 0x37, 0x21, 0xdc, 0x7f, 0xed, 0x46, 0xb8, 0x19, 0xdb, 0x07, 0xe1, 0xfe, 0xeb, - 0x8b, 0x23, 0xdc, 0x1f, 0x55, 0x84, 0x5b, 0xf2, 0x54, 0x29, 0x64, 0xa2, 0x1f, 0xf0, 0xb9, 0x05, 0xa1, 0x78, 0x5f, - 0xea, 0x07, 0x44, 0x5e, 0xea, 0x4a, 0x8a, 0xd4, 0x8f, 0xa5, 0x9c, 0x2f, 0xc8, 0xb2, 0x63, 0x4c, 0x52, 0xca, 0x2f, - 0x01, 0xe9, 0x43, 0x65, 0x22, 0x6c, 0xe8, 0xf3, 0x22, 0xca, 0x42, 0xfb, 0x3d, 0x67, 0x4b, 0x40, 0x05, 0xf1, 0x5d, - 0x9c, 0xcc, 0x3d, 0x8c, 0xc7, 0xa6, 0x63, 0xae, 0x38, 0x78, 0x70, 0xc0, 0x3b, 0xca, 0x8f, 0xa3, 0xb1, 0x94, 0xa3, - 0xb3, 0xc1, 0x35, 0xd1, 0x83, 0xfa, 0x03, 0xf3, 0x12, 0xdd, 0xa4, 0xd7, 0xb0, 0xb8, 0x2f, 0x3a, 0xce, 0x8b, 0xf6, - 0xe1, 0x8b, 0x23, 0x07, 0xfe, 0xe7, 0xb2, 0x4e, 0x6e, 0xf2, 0x8a, 0xf3, 0x38, 0x82, 0x74, 0x15, 0xa2, 0xe6, 0xa6, - 0x6a, 0xf7, 0x8c, 0x7d, 0x2a, 0x6a, 0x1d, 0x37, 0x57, 0x1a, 0x7b, 0x0f, 0x45, 0x9d, 0xc6, 0x1a, 0xb3, 0x78, 0xa9, - 0x0c, 0xab, 0x61, 0x34, 0x41, 0xb4, 0x04, 0xc9, 0x90, 0x52, 0x43, 0x7d, 0xcd, 0xa7, 0x5b, 0xcc, 0x8b, 0x75, 0xf2, - 0x9b, 0x22, 0x27, 0x8e, 0xc8, 0xcd, 0xb1, 0x13, 0x82, 0x5c, 0xa8, 0xee, 0x60, 0x44, 0x6d, 0xcc, 0x0a, 0xa3, 0x41, - 0x46, 0xba, 0x22, 0xf1, 0x39, 0x2e, 0x50, 0x96, 0x2c, 0x23, 0x9f, 0x72, 0x9b, 0x7b, 0xa3, 0xb4, 0x15, 0x1c, 0x40, - 0xb0, 0x4e, 0xfc, 0xb0, 0x81, 0xab, 0xe6, 0x9d, 0x39, 0x45, 0x02, 0x81, 0x54, 0xac, 0x8a, 0xf7, 0x22, 0x33, 0x13, - 0x4a, 0x3b, 0x8a, 0x4b, 0x6b, 0x0d, 0xbc, 0x17, 0xb2, 0xe1, 0x8b, 0xcc, 0x84, 0xd4, 0x9f, 0xb0, 0xdc, 0xcf, 0x9f, - 0x53, 0x2d, 0x48, 0xc6, 0x47, 0xd3, 0x3a, 0xf7, 0x65, 0x02, 0x2f, 0x5d, 0xf3, 0xa6, 0xb1, 0x8e, 0x09, 0xbc, 0x7a, - 0xbe, 0x19, 0xbf, 0x7c, 0x79, 0x36, 0x70, 0x0d, 0x9e, 0x4a, 0xb2, 0x94, 0xf7, 0xe8, 0x72, 0x3f, 0xd5, 0xb8, 0xd1, - 0xe8, 0xb4, 0xb5, 0x08, 0xa2, 0xa9, 0xd0, 0x4c, 0x4b, 0xec, 0x05, 0x79, 0x08, 0x48, 0x05, 0xe6, 0x09, 0x15, 0xb5, - 0xa8, 0x73, 0xc7, 0x12, 0x48, 0x83, 0x39, 0xd0, 0x3b, 0xb6, 0x63, 0x3b, 0xba, 0x6c, 0x38, 0x09, 0xa6, 0x83, 0x75, - 0x9c, 0x79, 0x90, 0xd1, 0x25, 0x8c, 0xa7, 0xe0, 0xf9, 0x91, 0x05, 0x59, 0x08, 0xe9, 0x41, 0xc0, 0x05, 0x64, 0x4e, - 0x5c, 0x63, 0xce, 0xed, 0x71, 0xbd, 0xe4, 0x13, 0xa6, 0x88, 0x13, 0x4e, 0x5f, 0x18, 0x92, 0xe6, 0x07, 0xb8, 0x0c, - 0x5b, 0x7a, 0x0b, 0x12, 0x14, 0xb2, 0x24, 0xb5, 0x54, 0xfb, 0xf6, 0x9e, 0x06, 0x6d, 0x20, 0x79, 0x38, 0x76, 0x30, - 0x49, 0xbc, 0x39, 0x44, 0xd2, 0x5e, 0xe7, 0x26, 0xc7, 0xb4, 0x3a, 0x47, 0xb5, 0x9a, 0xfb, 0xea, 0xc8, 0xd4, 0xda, - 0xae, 0xa9, 0x39, 0x80, 0x6e, 0xf5, 0xdc, 0x5c, 0xe7, 0x37, 0xfd, 0x5d, 0x2a, 0x3a, 0xc2, 0x2f, 0x4f, 0x69, 0x1e, - 0xa4, 0x9c, 0xe3, 0xc2, 0xcf, 0x8c, 0xe2, 0x09, 0xb6, 0x94, 0x18, 0xd7, 0x01, 0x89, 0xe9, 0xaf, 0xd8, 0x2a, 0x33, - 0x30, 0x7d, 0x06, 0xaf, 0x12, 0x18, 0x6b, 0x74, 0x4d, 0x0b, 0x22, 0x2d, 0xf8, 0xed, 0xb7, 0x56, 0x00, 0xe6, 0xf7, - 0x03, 0x05, 0x3e, 0xf0, 0x6c, 0x94, 0x00, 0x16, 0x14, 0x8a, 0x25, 0x04, 0x16, 0xf8, 0xc6, 0xc0, 0xbf, 0x45, 0xb1, - 0xf8, 0xc1, 0x15, 0x7b, 0x76, 0xe8, 0x45, 0x53, 0x40, 0x69, 0x5e, 0x34, 0xad, 0x19, 0x10, 0x90, 0x77, 0x5d, 0xa5, - 0xb4, 0xe8, 0xaa, 0x50, 0xee, 0xa7, 0xdf, 0x3e, 0x5c, 0x51, 0x7a, 0x20, 0x48, 0x45, 0xed, 0x8d, 0xd1, 0x15, 0xac, - 0xd0, 0x3d, 0xbc, 0x1c, 0x7c, 0x75, 0x3a, 0x67, 0x99, 0x47, 0x82, 0x4b, 0x60, 0xf1, 0x80, 0x1c, 0xd0, 0x7c, 0x91, - 0xda, 0x93, 0x18, 0xbc, 0x31, 0xbb, 0x0b, 0x7c, 0xce, 0xa7, 0x99, 0x1a, 0xbf, 0xa7, 0x2c, 0xb4, 0x51, 0x1a, 0xb8, - 0x26, 0x99, 0xc8, 0xfa, 0x1e, 0x46, 0x1d, 0x1c, 0x44, 0xb1, 0x7e, 0xf6, 0x95, 0xf4, 0x26, 0xda, 0xb4, 0x08, 0x90, - 0xa3, 0xef, 0x3a, 0x61, 0xe1, 0xbf, 0x07, 0x5f, 0xc1, 0xc5, 0xfd, 0xd5, 0x8d, 0x6e, 0xf4, 0x33, 0x1b, 0xf9, 0x98, - 0xaf, 0x1a, 0x72, 0xd5, 0x21, 0x8f, 0xca, 0x99, 0xcd, 0x8e, 0xc2, 0x6c, 0xc2, 0xef, 0xdd, 0xac, 0xeb, 0xd9, 0x29, - 0x5e, 0x68, 0x67, 0xc0, 0x5d, 0xac, 0x4b, 0x3c, 0xa7, 0xdb, 0x47, 0x06, 0x75, 0x14, 0x7a, 0xfe, 0x27, 0xc1, 0xa1, - 0xaa, 0x0f, 0xfb, 0xf0, 0xa2, 0x92, 0xb2, 0x6b, 0xdc, 0xcb, 0xb8, 0x95, 0xd7, 0xf8, 0x65, 0xfc, 0xd4, 0xfd, 0x2c, - 0xc8, 0x24, 0x33, 0x8c, 0x0f, 0x39, 0x68, 0x73, 0x70, 0x7c, 0x05, 0xfb, 0x03, 0x0c, 0xaa, 0x7b, 0xf2, 0xb7, 0xee, - 0x9d, 0xeb, 0xcc, 0xda, 0xae, 0x0d, 0x6c, 0xce, 0xac, 0x63, 0x1f, 0x87, 0x56, 0xc7, 0x3e, 0x86, 0xbf, 0x8f, 0xc0, - 0x7a, 0x59, 0x6d, 0xfb, 0xf0, 0xa3, 0xdb, 0x0e, 0xad, 0x13, 0xfb, 0x18, 0xfe, 0x2e, 0xa9, 0xd5, 0xcf, 0xc8, 0xf4, - 0x00, 0xc3, 0xf3, 0x55, 0x09, 0x0b, 0x28, 0xbf, 0xa5, 0x16, 0xc1, 0x2c, 0x5d, 0x6f, 0x0d, 0x9a, 0x08, 0x40, 0x19, - 0xba, 0x29, 0x82, 0x04, 0x46, 0xfd, 0x16, 0x24, 0xcf, 0xc6, 0xb0, 0xef, 0xc2, 0x20, 0x23, 0x2a, 0x12, 0xc1, 0x6f, - 0x3e, 0x46, 0xbc, 0x4d, 0x73, 0xfc, 0x6d, 0x91, 0x4f, 0x88, 0x54, 0x17, 0x7f, 0x5f, 0x60, 0x60, 0x1d, 0x11, 0x31, - 0x5c, 0xc1, 0x4a, 0x45, 0x4e, 0xbb, 0x7c, 0xf7, 0xc0, 0xd1, 0x6f, 0x94, 0xc9, 0x9c, 0x2a, 0x5f, 0xb4, 0x6f, 0xae, - 0xce, 0x90, 0xbd, 0xff, 0xd1, 0x7e, 0x30, 0x95, 0x28, 0xf5, 0x23, 0x82, 0x7b, 0x8e, 0x83, 0x44, 0x0e, 0x4f, 0x41, - 0xd1, 0x6e, 0x73, 0xe0, 0x72, 0x03, 0x92, 0x4f, 0x5c, 0x00, 0x95, 0x7c, 0xe7, 0x85, 0x8a, 0xe9, 0x85, 0xd2, 0xf2, - 0x89, 0xc4, 0xfc, 0xcf, 0x9f, 0x17, 0x83, 0xb3, 0x2a, 0xe3, 0x3e, 0x75, 0xbb, 0x70, 0xed, 0x76, 0x59, 0x67, 0xab, - 0x15, 0xd0, 0xee, 0xe8, 0xb0, 0x45, 0x38, 0x49, 0xa1, 0xe9, 0x17, 0x3a, 0xc6, 0x8d, 0xa6, 0x48, 0x35, 0x0d, 0x23, - 0xc4, 0xd5, 0xad, 0xb0, 0x3a, 0xba, 0xd1, 0x8f, 0x84, 0xc2, 0x2c, 0xda, 0x12, 0x11, 0x97, 0xf3, 0x62, 0x3a, 0x80, - 0x66, 0xcb, 0x3c, 0x76, 0xb8, 0x34, 0xfe, 0xaf, 0x27, 0x81, 0xee, 0x45, 0xa0, 0xe1, 0xab, 0x9c, 0xd6, 0x92, 0xbb, - 0x89, 0xbc, 0x57, 0xe9, 0x42, 0x65, 0xe9, 0xb9, 0x0e, 0x45, 0x90, 0x95, 0x08, 0x13, 0x91, 0x49, 0xf3, 0x26, 0x79, - 0x5b, 0x14, 0x05, 0x66, 0x00, 0x21, 0xa1, 0x5b, 0xc2, 0xd5, 0xc9, 0x78, 0xfe, 0x7c, 0xe3, 0x25, 0x44, 0xea, 0x64, - 0x35, 0x1f, 0xa3, 0xae, 0xe2, 0x37, 0x5d, 0x45, 0x31, 0xb2, 0x5f, 0xc4, 0x1a, 0xc2, 0x2a, 0x8b, 0xf6, 0x1e, 0xfe, - 0x1c, 0x31, 0x2f, 0xb3, 0xb9, 0x1e, 0xa4, 0xa5, 0x5c, 0xee, 0xa6, 0xcb, 0x3a, 0x60, 0x8f, 0xc5, 0xe3, 0x6f, 0xf1, - 0x60, 0x73, 0xcf, 0xd6, 0x1f, 0x97, 0xdc, 0x0f, 0x19, 0xfa, 0xf8, 0xcd, 0x29, 0x82, 0xa7, 0xbc, 0xcb, 0x3c, 0x8a, - 0xb0, 0xa1, 0x5e, 0xb9, 0x71, 0xe6, 0x89, 0xec, 0x1f, 0x40, 0x97, 0xf7, 0x1b, 0x15, 0x86, 0x8a, 0xaf, 0xf2, 0xd9, - 0xbb, 0xab, 0x6f, 0x34, 0xbe, 0xff, 0x49, 0xbf, 0x85, 0x8c, 0x0c, 0x05, 0xc1, 0x1f, 0x50, 0x10, 0x7c, 0x8d, 0x27, - 0x7f, 0x80, 0x50, 0xf2, 0xf9, 0x01, 0x41, 0x50, 0xd7, 0x58, 0xe4, 0x93, 0xd6, 0x6f, 0xbe, 0x0c, 0xb3, 0x60, 0xe1, - 0x25, 0xd9, 0x01, 0x34, 0xb5, 0x00, 0xc9, 0xe9, 0x9b, 0x3c, 0x98, 0x49, 0x71, 0x28, 0x84, 0x6a, 0x59, 0x24, 0x34, - 0x87, 0x93, 0x20, 0x94, 0x8a, 0x43, 0xf1, 0x01, 0xcf, 0xf7, 0xd9, 0x22, 0x1b, 0xe8, 0xde, 0x02, 0x92, 0x21, 0x60, - 0x78, 0xe3, 0x83, 0xd8, 0xcf, 0x58, 0x66, 0xa5, 0x59, 0xc2, 0xbc, 0xb9, 0x2e, 0x43, 0x7d, 0xd6, 0xfb, 0x4b, 0x97, - 0xa3, 0x79, 0x90, 0xc9, 0x60, 0x79, 0x34, 0x41, 0x50, 0xe1, 0xc1, 0x10, 0xcf, 0x86, 0x39, 0x07, 0xe1, 0x65, 0x3c, - 0xad, 0xec, 0xa8, 0x82, 0x72, 0x39, 0xc7, 0x48, 0xac, 0x3c, 0x00, 0xfe, 0x18, 0x3d, 0x72, 0x6e, 0xb9, 0xd7, 0xb5, - 0x8c, 0xe9, 0xa7, 0x9f, 0x9d, 0x72, 0xf6, 0x56, 0xc3, 0x40, 0x01, 0x7a, 0xd7, 0x81, 0x58, 0xb3, 0x9b, 0xfc, 0xb1, - 0x0f, 0x78, 0x65, 0xb8, 0x9a, 0xa8, 0x67, 0x0c, 0xfb, 0x4d, 0x63, 0xb9, 0x02, 0x42, 0xa8, 0xa4, 0xe2, 0x9d, 0xb9, - 0x67, 0xd2, 0x01, 0x08, 0x47, 0x85, 0xb4, 0xd2, 0x6f, 0xbf, 0xbd, 0x1e, 0xfe, 0xe7, 0x77, 0x88, 0x4d, 0x3e, 0x73, - 0x85, 0x17, 0xf4, 0xb5, 0x5a, 0x8b, 0x53, 0x9f, 0xe6, 0x10, 0xd5, 0xfb, 0x6c, 0x2c, 0xc2, 0x82, 0x88, 0xad, 0x95, - 0x0f, 0x6f, 0x44, 0xa8, 0x27, 0xc8, 0x3f, 0x60, 0x08, 0x5f, 0xed, 0x21, 0x2c, 0xef, 0x50, 0x84, 0x08, 0xd0, 0x7e, - 0x59, 0x7d, 0x7b, 0x0c, 0xb9, 0x74, 0x6b, 0x69, 0x01, 0x94, 0x01, 0xe2, 0x1e, 0x3a, 0x3b, 0xf5, 0xb8, 0xf0, 0x15, - 0xc8, 0x8f, 0xb4, 0x77, 0x00, 0xd3, 0x9c, 0xc5, 0x73, 0x66, 0x07, 0xf1, 0xc1, 0x3d, 0x1b, 0x59, 0xde, 0x22, 0x20, - 0xf9, 0x32, 0xca, 0xdd, 0x34, 0xa2, 0xfc, 0xa4, 0x82, 0x96, 0xe8, 0xeb, 0xbc, 0x00, 0x65, 0x5c, 0x00, 0x0a, 0x7e, - 0x7a, 0x67, 0xe5, 0x00, 0x7e, 0xb6, 0x08, 0x18, 0x5f, 0xc6, 0xf2, 0xe7, 0x14, 0x87, 0x4f, 0x84, 0xdc, 0x2b, 0x1e, - 0xac, 0x78, 0x32, 0x51, 0x83, 0xee, 0xd9, 0xe5, 0xef, 0x4b, 0xa8, 0x14, 0x7b, 0x36, 0x5e, 0xd0, 0x97, 0xea, 0x9f, - 0x90, 0x3f, 0x21, 0xa7, 0x2d, 0x8f, 0xcf, 0x08, 0xe7, 0xb9, 0x16, 0xbc, 0x4f, 0x82, 0xe4, 0x29, 0x55, 0xe2, 0x88, - 0xa2, 0x1a, 0x18, 0x7a, 0x03, 0x69, 0xf2, 0x64, 0x30, 0x20, 0x3c, 0x56, 0x45, 0x67, 0x00, 0xa5, 0x86, 0xe0, 0xf9, - 0x30, 0xd9, 0x0c, 0x1a, 0x5a, 0xe4, 0xc1, 0x85, 0x8d, 0xaa, 0xd3, 0xa9, 0x8f, 0xf1, 0xc0, 0x13, 0xfb, 0xab, 0xb4, - 0x03, 0x61, 0x67, 0xf1, 0x85, 0x05, 0x04, 0x2e, 0xfa, 0xa9, 0xe0, 0x71, 0xed, 0x6b, 0x42, 0xd9, 0x56, 0xe8, 0x3d, - 0xc4, 0x8a, 0x66, 0x9d, 0x3b, 0xd9, 0x5f, 0x62, 0xe9, 0x95, 0x70, 0x6e, 0xab, 0x9d, 0x24, 0x19, 0x80, 0xbc, 0x7e, - 0x9a, 0xd4, 0x88, 0xe1, 0xbb, 0x0e, 0x93, 0x5a, 0xb7, 0x3c, 0x19, 0xc4, 0x8e, 0x79, 0x71, 0xd0, 0x4a, 0x2f, 0xf1, - 0xdc, 0xe7, 0xa7, 0x07, 0x30, 0x3f, 0x08, 0x0c, 0x50, 0xa2, 0x8c, 0x02, 0x03, 0xa2, 0x0f, 0x78, 0x29, 0x59, 0x07, - 0x5c, 0x8c, 0x05, 0x51, 0x87, 0x9c, 0xa3, 0x8c, 0x0e, 0x5a, 0xaa, 0x52, 0x27, 0x56, 0x9c, 0x66, 0x2a, 0x6f, 0x77, - 0xc0, 0xfe, 0x5f, 0x97, 0x18, 0xad, 0x3f, 0xef, 0x67, 0x4c, 0xf8, 0xdd, 0x5e, 0x66, 0x1b, 0x5c, 0x73, 0x37, 0x55, - 0x21, 0x82, 0x75, 0x4b, 0x85, 0x62, 0x1f, 0x6f, 0xab, 0x55, 0x90, 0x46, 0xb2, 0xda, 0xc2, 0x6b, 0xe9, 0x4f, 0x71, - 0xc7, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0xbb, 0xcc, 0x06, 0x50, 0x55, 0x08, 0xdb, 0xbd, 0xc5, 0x82, 0x2a, 0x1b, 0xfd, - 0xd3, 0x03, 0xe2, 0x3b, 0xcf, 0x68, 0x87, 0x9d, 0x9d, 0x82, 0x75, 0x21, 0x2d, 0xba, 0xb7, 0x58, 0xf0, 0x25, 0xa5, - 0x5f, 0xf4, 0xe6, 0x60, 0x96, 0xcd, 0xc3, 0xb3, 0xff, 0x03, 0x30, 0x11, 0x13, 0xf1, 0xb7, 0x59, 0x03, 0x00}; + 0x1e, 0x7f, 0xc7, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0xef, 0x6e, 0x16, 0x93, 0xc1, 0xe0, 0xce, 0x3f, 0xdc, 0xf3, 0x70, + 0x76, 0x37, 0x67, 0x6f, 0xf9, 0x3d, 0x2d, 0xa6, 0x89, 0x6a, 0x7a, 0xf1, 0x98, 0xe0, 0x75, 0xe7, 0xfb, 0x13, 0x8b, + 0xff, 0xd5, 0xbe, 0x68, 0xde, 0xf9, 0x03, 0x69, 0x8d, 0x96, 0xbb, 0xfa, 0xfb, 0xc7, 0x15, 0x13, 0x77, 0x20, 0x5e, + 0xbc, 0xb7, 0x35, 0x0d, 0x6f, 0xf8, 0x47, 0xef, 0xad, 0x3f, 0x7d, 0xab, 0x63, 0x6e, 0x26, 0xea, 0x48, 0x7a, 0x73, + 0xf5, 0x8c, 0xfd, 0xca, 0x3f, 0xc9, 0xe3, 0xe4, 0x9d, 0x90, 0x93, 0xf6, 0x16, 0xb9, 0x9b, 0xe8, 0x94, 0xf8, 0xe2, + 0x26, 0x12, 0x16, 0x04, 0xc2, 0x70, 0xd4, 0xfc, 0x61, 0x52, 0x4e, 0xbd, 0x3d, 0x70, 0xbb, 0x72, 0x5b, 0xff, 0x7c, + 0xc7, 0x39, 0x5f, 0x0c, 0xaf, 0xa7, 0x5f, 0xba, 0x5d, 0x7a, 0x54, 0x34, 0x9b, 0x0a, 0x74, 0xbb, 0xc3, 0xd8, 0xab, + 0xb3, 0x99, 0x65, 0x2e, 0xf9, 0xd2, 0x97, 0xda, 0xcc, 0x3c, 0xa6, 0xf7, 0x9b, 0x69, 0x86, 0x44, 0xbe, 0x40, 0xc8, + 0x74, 0x3c, 0xae, 0x2e, 0xb1, 0x3c, 0x3e, 0x7c, 0xf3, 0xf4, 0xc9, 0xe0, 0x09, 0x46, 0x6e, 0x59, 0xd1, 0x20, 0x5f, + 0xf8, 0x30, 0xab, 0x5b, 0xb7, 0x8d, 0xab, 0x67, 0xc3, 0x5f, 0x20, 0x6f, 0xd0, 0xf5, 0xd0, 0x14, 0xd1, 0x2a, 0xbf, + 0xa3, 0xe8, 0x33, 0x25, 0x07, 0x1d, 0x4f, 0xa0, 0x76, 0x48, 0x81, 0xfb, 0xe5, 0x29, 0x07, 0xfd, 0x06, 0x96, 0xda, + 0xef, 0x5f, 0x7e, 0x22, 0x1e, 0x69, 0x18, 0xef, 0x1f, 0xc2, 0xe8, 0x8f, 0xb8, 0x2c, 0x36, 0x70, 0xba, 0x0e, 0xe0, + 0x73, 0x4f, 0xf5, 0xed, 0x6b, 0xe5, 0xfb, 0x7e, 0xe0, 0xed, 0xf8, 0x2d, 0xfb, 0xc2, 0xbd, 0xeb, 0xe1, 0x1b, 0xff, + 0xe9, 0x13, 0x10, 0x9d, 0x60, 0x5c, 0x3e, 0x63, 0x24, 0x6c, 0x47, 0x31, 0x6a, 0x15, 0x7e, 0xae, 0x21, 0x44, 0xeb, + 0x13, 0x32, 0x76, 0x41, 0xfa, 0x07, 0x05, 0xe8, 0x27, 0x04, 0x56, 0x93, 0xd4, 0x28, 0x30, 0x89, 0xef, 0x6a, 0x48, + 0x20, 0x05, 0x0b, 0x84, 0xde, 0x40, 0xf1, 0xa9, 0xe0, 0x5f, 0x86, 0x9f, 0x49, 0xf2, 0x5b, 0xd4, 0x7c, 0x0c, 0x7f, + 0xc3, 0xd0, 0x4c, 0xaa, 0x87, 0xb4, 0x8e, 0x12, 0xef, 0x27, 0xff, 0x10, 0x85, 0x95, 0x50, 0xc7, 0x42, 0x90, 0x8a, + 0x21, 0x17, 0xe2, 0xea, 0xd9, 0xe4, 0xae, 0x14, 0xe1, 0x1f, 0x13, 0x7c, 0x26, 0x17, 0x9a, 0x7c, 0x46, 0x4f, 0x1a, + 0xf9, 0xfe, 0x83, 0x7c, 0x5f, 0x76, 0x6a, 0xb0, 0xa8, 0x87, 0xfc, 0xae, 0x76, 0xdf, 0x97, 0x53, 0x82, 0x1e, 0xd9, + 0x0f, 0x68, 0x0a, 0x06, 0x6a, 0x02, 0x52, 0x86, 0xe0, 0x0e, 0xae, 0xfa, 0x9e, 0x2a, 0xc8, 0x97, 0xdf, 0xfb, 0x2c, + 0x64, 0xb8, 0xca, 0x82, 0x90, 0xe4, 0x52, 0x21, 0x85, 0x8d, 0xbb, 0x7a, 0xf0, 0x59, 0x63, 0x92, 0x48, 0xc8, 0x29, + 0x01, 0x49, 0xd2, 0xde, 0x40, 0x92, 0x88, 0xe9, 0x3f, 0x5c, 0x27, 0x4d, 0xb3, 0x96, 0xd2, 0x0d, 0x71, 0xaa, 0xbe, + 0x45, 0x9a, 0xb3, 0xe0, 0x3d, 0x83, 0xa5, 0x23, 0xc5, 0x8a, 0x2f, 0xc6, 0x60, 0xac, 0x83, 0x85, 0x56, 0xb2, 0xb8, + 0x5f, 0x25, 0x61, 0x1a, 0x89, 0x2a, 0xef, 0x84, 0xfc, 0xf9, 0x4f, 0x25, 0xfe, 0xe8, 0x2d, 0x0d, 0x44, 0x20, 0xf8, + 0x01, 0x5a, 0x0f, 0x58, 0xe3, 0xc1, 0x4f, 0xac, 0x2e, 0xc3, 0xbc, 0xca, 0xa8, 0xbc, 0xd9, 0x9e, 0xed, 0xe6, 0x4c, + 0x55, 0x2d, 0xf8, 0x2c, 0x0c, 0x2d, 0xda, 0xc5, 0xba, 0x39, 0xbb, 0xcd, 0x1b, 0x7c, 0x67, 0x92, 0x44, 0x6a, 0x29, + 0x89, 0xb4, 0xd5, 0xf5, 0xe9, 0xd2, 0xeb, 0x16, 0x15, 0x34, 0x46, 0x80, 0x5e, 0x92, 0xee, 0x2a, 0x9f, 0x50, 0xbc, + 0xb2, 0x1a, 0x56, 0xc3, 0x4b, 0x87, 0x22, 0x8c, 0xb5, 0x37, 0xe7, 0xf2, 0xec, 0x0e, 0xac, 0x47, 0x68, 0xed, 0xca, + 0xd5, 0x21, 0x6c, 0x3f, 0xd1, 0x7b, 0x4e, 0xae, 0xfe, 0x06, 0x54, 0x81, 0x73, 0x47, 0x43, 0x7d, 0xd2, 0x4e, 0x21, + 0xdb, 0x79, 0xb0, 0x24, 0xa8, 0x4a, 0xc9, 0x4d, 0xb9, 0x16, 0xa5, 0x94, 0x29, 0x5f, 0xcb, 0x6c, 0x65, 0xf7, 0xc9, + 0x00, 0xe2, 0xd9, 0xa0, 0x40, 0x72, 0x51, 0x5b, 0xcd, 0x41, 0xfa, 0x68, 0x96, 0x38, 0xd6, 0x0e, 0x0a, 0x2f, 0xcb, + 0xc1, 0xcc, 0x65, 0x2e, 0x97, 0x83, 0x82, 0x55, 0x7a, 0xab, 0x99, 0x66, 0xaa, 0x2f, 0x2a, 0x7b, 0x9b, 0xf1, 0x32, + 0xfd, 0x37, 0x4b, 0x06, 0x3c, 0xba, 0x7a, 0xe6, 0x07, 0x90, 0x26, 0x79, 0x1d, 0x20, 0x09, 0x36, 0x07, 0xbb, 0xd8, + 0x61, 0xd8, 0x2a, 0x56, 0xf6, 0xe4, 0xf9, 0x72, 0x87, 0xa6, 0x5c, 0xc2, 0x48, 0x4e, 0xcc, 0xa5, 0xd4, 0xf7, 0x25, + 0xd5, 0x0d, 0x05, 0x27, 0x9b, 0x26, 0xa0, 0x14, 0xd0, 0x6e, 0xc1, 0x7f, 0xe1, 0x53, 0x43, 0xa7, 0x05, 0x58, 0x6a, + 0xbb, 0x01, 0xff, 0x85, 0x7e, 0xb1, 0x7d, 0x44, 0xfd, 0xc0, 0x3c, 0x38, 0x98, 0xb5, 0x95, 0x31, 0x20, 0x22, 0x71, + 0x05, 0x79, 0x24, 0xf8, 0x41, 0xb1, 0xa7, 0xcb, 0xc4, 0x81, 0x33, 0xc5, 0xc5, 0x52, 0x6a, 0x33, 0xf3, 0xda, 0x6f, + 0xa9, 0x89, 0x37, 0x51, 0x12, 0x15, 0xb6, 0x43, 0x1a, 0xbd, 0xa4, 0x8c, 0xa9, 0x82, 0x0d, 0xd1, 0x7d, 0xdd, 0x04, + 0x53, 0xe0, 0x4d, 0x55, 0x05, 0x44, 0xa8, 0xbd, 0xc8, 0xf2, 0xfc, 0xa6, 0x0b, 0xac, 0x2e, 0xf8, 0xd4, 0x98, 0x66, + 0x17, 0xac, 0xe4, 0x6a, 0x26, 0x7d, 0xe6, 0xed, 0x40, 0x0b, 0x79, 0x97, 0x97, 0x45, 0x2b, 0x74, 0x3d, 0x88, 0x16, + 0xfe, 0x41, 0x73, 0x3c, 0x7a, 0xb6, 0xad, 0xa6, 0x36, 0xfb, 0x5a, 0x8b, 0x05, 0x32, 0x10, 0x0d, 0x7d, 0xa1, 0x62, + 0x14, 0xee, 0x2a, 0xcd, 0xd5, 0x6a, 0x5f, 0x95, 0x41, 0x02, 0x13, 0x41, 0xd6, 0xb2, 0xf0, 0x1e, 0xdd, 0xab, 0x47, + 0x9a, 0x57, 0x12, 0x3c, 0x73, 0xf1, 0x17, 0x00, 0x42, 0x79, 0x92, 0x90, 0x03, 0x72, 0x00, 0x7f, 0x4b, 0x51, 0x2a, + 0x0d, 0xf0, 0xcf, 0xea, 0x72, 0x6c, 0xeb, 0xfb, 0x3b, 0xad, 0x62, 0x70, 0xfd, 0xf9, 0xba, 0xeb, 0x59, 0x3b, 0xc4, + 0x39, 0xb7, 0xd5, 0x6b, 0xcb, 0x34, 0x8f, 0x91, 0xba, 0x06, 0xe0, 0x4e, 0xa4, 0x47, 0x20, 0x92, 0x99, 0x68, 0x90, + 0xb3, 0xe7, 0x7c, 0x3c, 0x15, 0x8f, 0x49, 0x7b, 0xb9, 0xef, 0x9b, 0x0b, 0x7d, 0x30, 0xc6, 0xbe, 0x05, 0x0d, 0xe2, + 0xa3, 0xd5, 0xd6, 0x0a, 0xc4, 0x7a, 0xa7, 0xd4, 0x87, 0x6e, 0x8c, 0x82, 0x0e, 0x1e, 0x71, 0x23, 0x17, 0x1c, 0xdb, + 0x5d, 0x5b, 0x4f, 0xe9, 0x2b, 0x00, 0x73, 0x1d, 0xa8, 0x64, 0x18, 0xa4, 0x2e, 0x13, 0x85, 0x49, 0x7e, 0x99, 0x90, + 0x84, 0x88, 0xea, 0x6c, 0x39, 0x4a, 0x95, 0x69, 0x01, 0x97, 0x19, 0x19, 0x60, 0x36, 0x69, 0xd6, 0x4f, 0x2e, 0x5f, + 0x62, 0x18, 0x01, 0xf1, 0x33, 0xfa, 0xb1, 0x56, 0x89, 0x97, 0x8c, 0xee, 0x1c, 0x75, 0x83, 0x2a, 0xc9, 0x5c, 0xbf, + 0xb9, 0x9d, 0x45, 0xca, 0xbc, 0x60, 0xb8, 0x5d, 0xa5, 0xf9, 0x87, 0xb0, 0x4e, 0xf0, 0xdb, 0x00, 0x95, 0xf4, 0xa9, + 0xf0, 0xa2, 0x11, 0x40, 0xa8, 0xef, 0x55, 0x19, 0x9f, 0x0a, 0x2f, 0x1b, 0xed, 0x58, 0x46, 0x29, 0x54, 0x17, 0xcc, + 0x6e, 0x4d, 0x17, 0xa2, 0x5b, 0x55, 0x03, 0x6d, 0xe0, 0xda, 0x15, 0x52, 0xba, 0x81, 0x6a, 0x57, 0x6e, 0x58, 0x80, + 0x68, 0x33, 0x11, 0x18, 0x2e, 0xff, 0x3e, 0x7f, 0xa9, 0x62, 0x78, 0xfa, 0xfd, 0xd0, 0x3b, 0xec, 0x82, 0x68, 0xb4, + 0xbb, 0x66, 0xfb, 0x20, 0x1a, 0xed, 0xaf, 0x1b, 0x46, 0xbf, 0x9f, 0xd1, 0xef, 0x67, 0x0d, 0xe8, 0x48, 0x84, 0x09, + 0xb3, 0xd7, 0x6f, 0xd4, 0xf2, 0x95, 0x5a, 0xbf, 0x53, 0xcb, 0x97, 0x6a, 0x78, 0xeb, 0x40, 0x12, 0x41, 0x64, 0xa9, + 0x6a, 0x1e, 0x24, 0x45, 0xaa, 0xa5, 0xcb, 0x31, 0x5a, 0x8c, 0xa8, 0xa5, 0xac, 0x39, 0xd5, 0x89, 0xb4, 0x73, 0x50, + 0x32, 0xc0, 0xd1, 0xe2, 0xaa, 0xc6, 0x74, 0xb3, 0xa2, 0x25, 0x10, 0x23, 0xac, 0x6c, 0xcb, 0xc5, 0x4d, 0xea, 0xa3, + 0x2b, 0xf2, 0x6d, 0xcb, 0x95, 0x6f, 0x5b, 0xc1, 0xab, 0xaf, 0x28, 0x94, 0x4b, 0xae, 0x95, 0xed, 0xd3, 0x42, 0x29, + 0x94, 0x71, 0x0d, 0xb6, 0xf6, 0x4d, 0x60, 0xc8, 0x7c, 0xa4, 0xa8, 0xb1, 0xbd, 0x68, 0x94, 0x43, 0x90, 0xad, 0x83, + 0x51, 0xa7, 0x2c, 0x58, 0x7c, 0xbb, 0x43, 0x06, 0x32, 0xd0, 0x51, 0xd5, 0xc6, 0xab, 0x9d, 0x95, 0xfe, 0xb0, 0xbc, + 0x7a, 0xc6, 0x12, 0x2b, 0x9d, 0xfc, 0xa6, 0x42, 0x7f, 0x10, 0xa2, 0x6f, 0xca, 0x96, 0x83, 0x17, 0x5d, 0x6c, 0x65, + 0x40, 0xbc, 0x61, 0x7a, 0x6f, 0x6b, 0x25, 0xcb, 0x5d, 0x53, 0xbe, 0x98, 0xf1, 0x84, 0xe3, 0xe8, 0xcb, 0xd5, 0x22, + 0xac, 0xd5, 0x22, 0x3b, 0x01, 0x1e, 0x5a, 0xab, 0xa5, 0x90, 0xab, 0x45, 0x38, 0x33, 0x5d, 0xa8, 0x99, 0x9e, 0x81, + 0xe6, 0x51, 0xa8, 0x59, 0x9e, 0x00, 0x16, 0xbc, 0x30, 0x33, 0x5c, 0x98, 0x19, 0x8e, 0x43, 0x6a, 0x9c, 0x1e, 0xf4, + 0x5e, 0xe7, 0x9e, 0x5b, 0xee, 0x46, 0xa7, 0x61, 0xde, 0x4e, 0x36, 0x98, 0xd3, 0x83, 0x70, 0x02, 0xf1, 0x81, 0x25, + 0x02, 0xf4, 0x68, 0x58, 0x1d, 0x35, 0x54, 0x8e, 0xe2, 0xcb, 0x02, 0x90, 0x2c, 0x09, 0x40, 0xf2, 0xa0, 0xc6, 0xb9, + 0xb4, 0xfc, 0xba, 0x4a, 0x42, 0x8e, 0xc8, 0x78, 0x29, 0xed, 0xee, 0x09, 0x2f, 0x47, 0x46, 0x68, 0x9e, 0x2c, 0x52, + 0xaf, 0x62, 0x19, 0x1b, 0x23, 0x70, 0x51, 0xe8, 0x37, 0x79, 0xbf, 0x9f, 0x96, 0x5e, 0x45, 0xed, 0xfc, 0x04, 0xfe, + 0x96, 0xe7, 0xce, 0x22, 0x47, 0xc8, 0xab, 0x91, 0x49, 0x58, 0x5e, 0x2a, 0xf5, 0xf4, 0x25, 0xcc, 0xa0, 0xee, 0xde, + 0x28, 0x00, 0xd7, 0x42, 0x39, 0xd5, 0x96, 0x70, 0x65, 0xaa, 0x0c, 0xf6, 0x79, 0xc8, 0x65, 0x68, 0x87, 0x44, 0x1e, + 0x29, 0xac, 0xfb, 0xf6, 0xd5, 0xb3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x8f, 0x00, 0x73, 0x30, 0xf5, 0xa2, + 0x01, 0x2f, 0xd5, 0x9c, 0xf9, 0xe8, 0x55, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x53, 0xf9, 0xc8, 0xf8, + 0x96, 0xf9, 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, + 0x6c, 0x50, 0x09, 0xb6, 0x0d, 0xdf, 0x48, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, + 0x1b, 0xb3, 0x31, 0x2b, 0xd4, 0xce, 0x53, 0xc9, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, + 0x71, 0xce, 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, + 0xa6, 0x25, 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, + 0xe8, 0x95, 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x2b, + 0xfe, 0x42, 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd0, 0xb4, 0x04, + 0x75, 0x80, 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x25, 0xe7, 0xef, 0x6a, 0x43, + 0x84, 0x8c, 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, + 0xc0, 0xe3, 0xaa, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x9c, 0xf6, 0x4e, 0xd3, 0xb0, 0xc3, 0x17, 0xa0, 0x29, 0x86, 0x72, + 0x3c, 0xdf, 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xce, 0x42, 0xda, 0x96, + 0x63, 0xb4, 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xca, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x79, 0xd5, 0x63, 0x36, + 0xc9, 0x8a, 0x45, 0xae, 0x22, 0xce, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, + 0x41, 0xc9, 0x72, 0x59, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xde, 0x9c, + 0x53, 0xa8, 0x7d, 0xc5, 0xc3, 0xea, 0xfc, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, + 0x7c, 0xe7, 0xab, 0x74, 0x45, 0xa1, 0x3b, 0xce, 0x4c, 0x3c, 0x57, 0x81, 0xb1, 0x6f, 0xed, 0x08, 0x0a, 0x87, 0xa6, + 0xeb, 0x80, 0xc3, 0x34, 0x3a, 0x61, 0xf1, 0x4f, 0xe9, 0x38, 0x79, 0x55, 0x2b, 0x44, 0x92, 0xbf, 0x0b, 0x17, 0x86, + 0xc4, 0x82, 0xbc, 0x24, 0xd4, 0x11, 0x19, 0xb1, 0x1a, 0x15, 0x1b, 0xa1, 0xa2, 0xe2, 0x14, 0x8f, 0xb7, 0x0a, 0x8a, + 0x4b, 0x51, 0xaa, 0x94, 0x8a, 0xdc, 0xa8, 0x14, 0x10, 0xcb, 0x06, 0xde, 0x2d, 0xe0, 0x00, 0x08, 0x3a, 0xcb, 0xfd, + 0xc6, 0x76, 0xb7, 0x91, 0xf9, 0xcc, 0x34, 0x4f, 0xab, 0x0f, 0xea, 0xef, 0xf7, 0x4b, 0x8c, 0xad, 0xf1, 0xf4, 0xf7, + 0x6d, 0x5a, 0x70, 0xf3, 0x37, 0x0c, 0xd1, 0x0a, 0x10, 0x31, 0x4b, 0x7b, 0x28, 0x64, 0xc1, 0x84, 0x65, 0xa8, 0xca, + 0x53, 0x8e, 0x7a, 0xd5, 0xe4, 0x0e, 0x20, 0xd4, 0xd0, 0xaf, 0x8d, 0x4e, 0x75, 0x55, 0x82, 0xf0, 0x7d, 0x57, 0xa8, + 0xc7, 0xe6, 0x80, 0x27, 0x03, 0xe0, 0xaf, 0xc8, 0x6b, 0x3d, 0xb6, 0x7f, 0xd0, 0x1b, 0xf5, 0x06, 0x08, 0xa2, 0x73, + 0x59, 0xf8, 0x27, 0x9c, 0xeb, 0xd4, 0x9f, 0x71, 0x21, 0x88, 0x6f, 0x3d, 0x09, 0xef, 0xc5, 0x45, 0x1a, 0x07, 0x17, + 0xbd, 0x81, 0xb9, 0x08, 0x14, 0x17, 0x69, 0x7e, 0x01, 0x61, 0xf9, 0x88, 0x89, 0x58, 0xb3, 0x15, 0xc0, 0x04, 0x96, + 0x3a, 0x0e, 0x59, 0x75, 0x6c, 0xbf, 0xff, 0x7a, 0x64, 0xc8, 0xd2, 0x11, 0x06, 0x46, 0xff, 0x06, 0x14, 0xa1, 0x12, + 0x96, 0x99, 0xed, 0xc1, 0xa4, 0xab, 0x3d, 0xab, 0xe7, 0xcd, 0x36, 0xef, 0xea, 0x1d, 0xab, 0x69, 0x15, 0x35, 0x2d, + 0xb7, 0x9a, 0x36, 0xa9, 0xa0, 0x66, 0xa2, 0xdf, 0xd7, 0xa0, 0xa8, 0xd5, 0x1c, 0xc0, 0xd8, 0x30, 0xf9, 0xf5, 0x2c, + 0x9f, 0xf7, 0xfb, 0x9e, 0x7c, 0x04, 0xbf, 0x90, 0xad, 0xcc, 0xad, 0xb1, 0x7c, 0xfa, 0x8a, 0x48, 0xcc, 0x0c, 0xcc, + 0xd1, 0xea, 0x04, 0xdf, 0xeb, 0x56, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x35, 0x0c, 0x9e, 0x27, 0x7c, 0x70, + 0x91, 0xa3, 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x6b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, + 0x78, 0x90, 0xfd, 0xfe, 0x1a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0x37, 0x75, 0x51, 0x56, 0xd0, 0xb1, + 0xf4, 0xf3, 0x4e, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x96, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, + 0x2e, 0x3e, 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0x67, 0xb8, 0xcf, 0x6f, 0x3c, 0xf0, 0x83, 0x99, 0xa5, + 0x73, 0x45, 0x9c, 0x51, 0xf9, 0xa3, 0xcf, 0x45, 0x9a, 0x53, 0x1e, 0xe0, 0x3e, 0x14, 0x73, 0xfb, 0x2d, 0x90, 0x7e, + 0xe8, 0x2d, 0x90, 0x7d, 0x74, 0xce, 0xc9, 0x6b, 0x40, 0xa4, 0x43, 0x18, 0xdc, 0x9c, 0x04, 0x1d, 0xab, 0x86, 0x77, + 0x16, 0xd8, 0x69, 0x2f, 0x8d, 0x7b, 0x69, 0x7e, 0x91, 0xf6, 0xfb, 0x06, 0x35, 0x33, 0x45, 0x38, 0x78, 0x9c, 0x91, + 0x8b, 0xa4, 0x05, 0x5b, 0x4a, 0xfb, 0xaf, 0x06, 0x8e, 0xa8, 0x10, 0xa0, 0xf9, 0xef, 0xc2, 0x7b, 0x02, 0x10, 0x9b, + 0xb4, 0x01, 0x57, 0x3d, 0xa6, 0xa3, 0xb1, 0x25, 0x51, 0xab, 0xce, 0x06, 0x48, 0x9c, 0x2a, 0xad, 0xa7, 0xdc, 0xac, + 0x29, 0x0c, 0x52, 0x65, 0xa1, 0x7e, 0x63, 0x3d, 0x99, 0xac, 0x72, 0x91, 0x11, 0x47, 0x65, 0x7a, 0x57, 0x33, 0x82, + 0xe9, 0xd2, 0xcf, 0x17, 0xb0, 0x64, 0xe3, 0x8f, 0x38, 0x79, 0x4b, 0xc0, 0xb1, 0x9d, 0xb5, 0xab, 0x6a, 0x97, 0xe3, + 0xd6, 0x6e, 0x0e, 0xf0, 0xbd, 0xde, 0x68, 0x34, 0xd2, 0xce, 0x71, 0x02, 0x86, 0xaa, 0xa7, 0x96, 0x42, 0x8f, 0xd5, + 0x0a, 0x50, 0xb7, 0x23, 0x97, 0x59, 0x32, 0x98, 0x2f, 0x8c, 0xe3, 0x97, 0xe6, 0xa3, 0x8f, 0x97, 0xca, 0xda, 0x75, + 0xc4, 0xd7, 0x7f, 0x94, 0xd5, 0xfa, 0x96, 0x77, 0x55, 0x13, 0xf0, 0x45, 0x15, 0x50, 0xfa, 0x0d, 0xef, 0xc9, 0xde, + 0xc5, 0xd7, 0x6e, 0xb1, 0x4b, 0xbe, 0xe5, 0x2d, 0xea, 0x3c, 0x5f, 0x39, 0xb8, 0x51, 0xa5, 0xdb, 0x7b, 0xc9, 0x02, + 0xd7, 0xde, 0x49, 0xd3, 0x58, 0xcf, 0xfc, 0xe8, 0x61, 0x11, 0xb2, 0x9d, 0x8f, 0xbd, 0xaf, 0x9a, 0xa7, 0x67, 0x0d, + 0xbd, 0x49, 0x0d, 0x7d, 0xec, 0x45, 0xd9, 0x3e, 0x35, 0x8d, 0xe8, 0x35, 0x6c, 0xe8, 0x63, 0x6f, 0xc9, 0xc9, 0x21, + 0x11, 0xe0, 0xd4, 0x98, 0x3f, 0x3e, 0x9c, 0xce, 0xf0, 0x77, 0x0c, 0xa8, 0x04, 0x62, 0x3e, 0x3f, 0xa6, 0x1d, 0x05, + 0x98, 0x51, 0xa5, 0xb7, 0xcf, 0x0f, 0x6c, 0xc7, 0xcb, 0x7a, 0x68, 0xe9, 0xdd, 0xb3, 0xa3, 0xdb, 0xf1, 0xaa, 0x1a, + 0x5f, 0xca, 0x21, 0xcf, 0xf3, 0xd9, 0x68, 0x34, 0x12, 0x06, 0x92, 0x3b, 0xd7, 0x1b, 0x58, 0x81, 0xb4, 0x2d, 0xaa, + 0x0f, 0xe5, 0xd2, 0xdb, 0xab, 0x43, 0x3b, 0xf7, 0x27, 0xd5, 0xf1, 0x58, 0x8c, 0xcc, 0x31, 0x9e, 0xfb, 0xc7, 0x63, + 0xa1, 0xe4, 0x28, 0x59, 0x4b, 0x10, 0x9d, 0xd2, 0x78, 0x2a, 0xeb, 0xb5, 0x13, 0x91, 0x57, 0x23, 0xce, 0x43, 0xf0, + 0x57, 0x2f, 0x67, 0xa5, 0xfe, 0x54, 0xf8, 0xe8, 0xa7, 0x4a, 0xe9, 0x05, 0xaf, 0x0a, 0x08, 0x11, 0xfb, 0xbb, 0x81, + 0x76, 0x50, 0x82, 0x43, 0x09, 0xf7, 0x1e, 0xaf, 0x93, 0xaf, 0xbc, 0x6a, 0x26, 0x63, 0x94, 0x7b, 0x83, 0x7c, 0xce, + 0x00, 0xa6, 0xd2, 0x67, 0xe0, 0x77, 0x09, 0x50, 0xa7, 0xf8, 0x14, 0x9d, 0xea, 0xcd, 0xc3, 0xa6, 0xeb, 0xd3, 0x12, + 0x45, 0x11, 0xdd, 0xf9, 0xf9, 0x18, 0x10, 0x3b, 0xbb, 0x36, 0x23, 0xed, 0xda, 0x6f, 0xd0, 0x60, 0x95, 0x26, 0xad, + 0x95, 0x53, 0xc2, 0x6e, 0x57, 0x23, 0x5b, 0xfa, 0x51, 0x0a, 0xc4, 0xca, 0x71, 0x22, 0x91, 0x3d, 0xd8, 0xc8, 0x09, + 0xdc, 0xa2, 0xbd, 0xa3, 0x03, 0x50, 0xb9, 0x51, 0x90, 0x5f, 0xcd, 0x89, 0xdc, 0xf1, 0x7d, 0xef, 0xfb, 0x41, 0x3d, + 0xf8, 0xbe, 0x77, 0x91, 0x92, 0xdc, 0x11, 0x5e, 0xa8, 0x29, 0x21, 0xe2, 0x8b, 0xef, 0x07, 0xd5, 0x00, 0xcf, 0x12, + 0x2d, 0xd2, 0x22, 0xa1, 0x5a, 0x5d, 0xe3, 0x26, 0xbc, 0x48, 0x24, 0xf7, 0xd0, 0xbe, 0xf3, 0x88, 0x58, 0x00, 0x32, + 0x16, 0x9f, 0xcd, 0x1b, 0x0a, 0x75, 0x37, 0x31, 0x5b, 0x74, 0x97, 0xc5, 0x7e, 0x7f, 0x93, 0xa7, 0x75, 0x4f, 0xc7, + 0xc7, 0xe0, 0x0b, 0x52, 0x4d, 0x80, 0x47, 0xfb, 0x2b, 0x73, 0xbc, 0x7a, 0xb5, 0x39, 0x52, 0x16, 0xaa, 0x44, 0xfd, + 0x16, 0xab, 0x59, 0x0f, 0x61, 0xb8, 0xb3, 0xcc, 0x58, 0xdb, 0x0b, 0x9e, 0xcb, 0x59, 0x15, 0xdb, 0xe5, 0xf8, 0x8a, + 0xa5, 0x36, 0x97, 0xa8, 0x1c, 0xad, 0xc7, 0xda, 0x14, 0x23, 0xbf, 0x52, 0x48, 0x94, 0x45, 0xc7, 0xd6, 0x42, 0x01, + 0xf1, 0x02, 0xf4, 0x25, 0x7b, 0xd3, 0x00, 0xeb, 0x8d, 0x5e, 0x45, 0x84, 0x96, 0x8f, 0x54, 0x78, 0x9b, 0x9b, 0x2a, + 0xb3, 0xb2, 0x59, 0xb4, 0xfb, 0x29, 0xe7, 0x39, 0x82, 0xd5, 0x1b, 0xb5, 0x47, 0x01, 0x6a, 0x0f, 0x2d, 0x94, 0x01, + 0xa4, 0x34, 0xcd, 0x00, 0x90, 0x01, 0x40, 0xa6, 0x8a, 0xf8, 0x4c, 0x80, 0x4a, 0x5b, 0xdd, 0x28, 0x70, 0x22, 0xbd, + 0x02, 0x9a, 0x05, 0x56, 0xfa, 0x48, 0x41, 0x06, 0x8b, 0x2d, 0x02, 0xb0, 0x72, 0xe4, 0x0c, 0xd3, 0x18, 0xb2, 0x8d, + 0x26, 0x2e, 0x49, 0xf3, 0xfb, 0x30, 0x4b, 0x25, 0x9e, 0xc4, 0x8f, 0xb2, 0xc6, 0x08, 0x00, 0xa4, 0xef, 0xd3, 0x8b, + 0x22, 0x8b, 0x09, 0x07, 0xce, 0x7a, 0xea, 0xa0, 0xa8, 0xc9, 0xb9, 0xd6, 0xb4, 0x7a, 0x56, 0x9b, 0x3c, 0x64, 0x81, + 0xce, 0x1e, 0x8c, 0x49, 0x2d, 0xdf, 0xf3, 0xc8, 0xfe, 0xca, 0xe9, 0x8c, 0xf0, 0x5d, 0x77, 0x70, 0xea, 0xbf, 0xdb, + 0x1a, 0x98, 0x98, 0x12, 0x80, 0x8d, 0xc1, 0xd1, 0x84, 0xf8, 0x9d, 0x8e, 0xc9, 0xd4, 0x26, 0x45, 0x20, 0xf0, 0x10, + 0xbc, 0x82, 0xeb, 0x0b, 0x19, 0x30, 0x20, 0x68, 0x3b, 0x8b, 0x3c, 0x4d, 0x00, 0x4e, 0xbc, 0xe0, 0x3b, 0x80, 0xe3, + 0xd4, 0xab, 0x42, 0xf6, 0xec, 0xa5, 0x98, 0xce, 0xe6, 0xc1, 0x43, 0x42, 0xfb, 0x17, 0x13, 0x7e, 0xd3, 0x5d, 0x25, + 0x57, 0xa6, 0xd6, 0xbd, 0x89, 0xae, 0x72, 0x95, 0xd3, 0xa7, 0x39, 0xc7, 0x30, 0x67, 0xb0, 0x0a, 0xc8, 0x39, 0x1b, + 0xf2, 0xe7, 0x97, 0x00, 0xd8, 0xb2, 0x16, 0x5e, 0xc4, 0x9f, 0x87, 0xb2, 0x5a, 0x00, 0xf7, 0xc8, 0x79, 0x64, 0x7e, + 0xf9, 0x6a, 0x3b, 0x94, 0x73, 0x8a, 0xc2, 0x58, 0xce, 0x4d, 0x4b, 0x8a, 0xd3, 0xa1, 0xa7, 0x60, 0x32, 0xb5, 0xe5, + 0xef, 0x5d, 0xe2, 0x32, 0x7b, 0x33, 0x09, 0xe7, 0xeb, 0xc8, 0xb6, 0xb5, 0xea, 0x1e, 0xba, 0x21, 0x18, 0xf4, 0x31, + 0x82, 0x96, 0xd5, 0x9b, 0x5f, 0x31, 0x18, 0x28, 0x6c, 0xdf, 0x9a, 0x6e, 0x5a, 0x74, 0x8a, 0x03, 0xce, 0xac, 0x75, + 0x8d, 0x4a, 0x55, 0x71, 0xe8, 0x25, 0xef, 0x96, 0x95, 0xdb, 0x65, 0xe9, 0x85, 0x20, 0x35, 0xea, 0x2a, 0x42, 0xa4, + 0x54, 0xec, 0xf0, 0x9e, 0xfc, 0x1a, 0x98, 0x78, 0x66, 0xe5, 0x28, 0x8d, 0xe7, 0x00, 0x13, 0xa4, 0xd0, 0x37, 0xe5, + 0x57, 0x80, 0x1b, 0xba, 0x88, 0xc2, 0xec, 0x4d, 0x5c, 0x05, 0xb5, 0xd5, 0xf4, 0x7b, 0x07, 0x27, 0xf6, 0xb2, 0xee, + 0xf7, 0x53, 0xa2, 0xf1, 0xc3, 0xd0, 0x0b, 0xfc, 0x7b, 0x3c, 0x3d, 0x34, 0x41, 0x6a, 0x5e, 0x79, 0x80, 0x57, 0x74, + 0xb9, 0xb5, 0x29, 0x57, 0x34, 0x2e, 0xe6, 0x35, 0x22, 0xc2, 0xa7, 0x8e, 0x62, 0xbb, 0xcd, 0x8f, 0x53, 0x1b, 0x83, + 0x41, 0x08, 0xf7, 0xad, 0x8c, 0xdf, 0x27, 0x5e, 0x35, 0x8b, 0xe6, 0xa0, 0x28, 0xcd, 0x34, 0x49, 0x48, 0x21, 0xbd, + 0x04, 0xe8, 0xa3, 0x41, 0xa8, 0xd5, 0x95, 0x7f, 0x24, 0x5e, 0xaa, 0xa6, 0xb5, 0x79, 0x8a, 0x35, 0x0a, 0xc4, 0x2c, + 0x9a, 0x37, 0x2c, 0xa3, 0x43, 0x52, 0x5d, 0x2e, 0x4d, 0x33, 0xfe, 0xb0, 0x9a, 0xa1, 0x5a, 0x71, 0xd2, 0x04, 0x35, + 0x4a, 0xb7, 0x70, 0x01, 0xfc, 0x1b, 0xdd, 0x71, 0x54, 0xa3, 0x48, 0xd1, 0x80, 0x4f, 0x20, 0xa6, 0xab, 0x30, 0x9b, + 0x27, 0xac, 0x35, 0x75, 0xcd, 0xe8, 0xf7, 0x65, 0x9c, 0x90, 0x49, 0x42, 0x72, 0x3e, 0x5c, 0xae, 0x1f, 0x49, 0x75, + 0x01, 0xa4, 0xca, 0x39, 0x9b, 0xf5, 0x7a, 0x73, 0xc0, 0xe8, 0x85, 0xf5, 0x0b, 0x1b, 0x57, 0x70, 0x79, 0x4d, 0x98, + 0xbb, 0xea, 0x47, 0x98, 0x65, 0x50, 0x05, 0xa4, 0xf9, 0xb1, 0xa0, 0xd3, 0x2b, 0x17, 0x88, 0xfa, 0xf5, 0x48, 0x5d, + 0x50, 0x66, 0xe9, 0xdc, 0x22, 0x02, 0x01, 0xaf, 0x61, 0xf5, 0x04, 0x92, 0x7d, 0xf9, 0xd8, 0xa7, 0x19, 0x05, 0xaa, + 0x23, 0x00, 0x65, 0xb3, 0x7e, 0x08, 0xfb, 0x07, 0x84, 0x13, 0xea, 0x6f, 0xde, 0xca, 0x59, 0x43, 0xf2, 0x40, 0xaa, + 0x09, 0x8f, 0xe1, 0xd4, 0x58, 0xe0, 0x4b, 0x8b, 0xde, 0x54, 0xf0, 0x9a, 0xe0, 0xb8, 0x17, 0x68, 0xed, 0x5b, 0xc0, + 0x11, 0x22, 0xb8, 0x0c, 0x4d, 0x9c, 0xf6, 0xf6, 0xbd, 0x00, 0x09, 0xcd, 0x2d, 0x9c, 0xeb, 0xb7, 0x2e, 0x68, 0x71, + 0x8a, 0x9c, 0x2c, 0xba, 0xc0, 0x40, 0x17, 0x64, 0xde, 0xf8, 0x67, 0x0e, 0x2b, 0x17, 0x20, 0x7b, 0xa9, 0x58, 0x49, + 0xc4, 0xb6, 0x57, 0x7f, 0x94, 0xca, 0x7e, 0x7b, 0x61, 0x4d, 0xe0, 0x97, 0x89, 0xfd, 0x12, 0x99, 0x7c, 0xd3, 0x53, + 0x93, 0xaf, 0x8c, 0x85, 0x4e, 0x2d, 0x83, 0x73, 0x7a, 0x62, 0x70, 0xee, 0xed, 0xad, 0xda, 0x94, 0x30, 0x14, 0x24, + 0x81, 0xa6, 0x4b, 0x0f, 0xeb, 0xa6, 0x3f, 0x3f, 0x69, 0xf1, 0x6b, 0xd5, 0xbe, 0x75, 0x3f, 0x0e, 0xb1, 0x8b, 0x5f, + 0x26, 0x9e, 0x61, 0x1f, 0xf5, 0x81, 0x03, 0x4c, 0x46, 0x4c, 0x5c, 0xf7, 0xfb, 0x50, 0xd8, 0x6c, 0x3c, 0x1f, 0xd5, + 0xc5, 0xcf, 0xc5, 0x03, 0x40, 0x39, 0x54, 0x60, 0x97, 0x43, 0x19, 0xca, 0x88, 0x4d, 0x6d, 0xb9, 0xe7, 0xf7, 0x97, + 0x61, 0x0e, 0xf2, 0x8e, 0xc6, 0xc4, 0xb9, 0x00, 0x31, 0x0c, 0xbe, 0xfe, 0xfd, 0x93, 0x43, 0xda, 0x7c, 0x7f, 0x01, + 0xdf, 0x1d, 0x5d, 0x7c, 0x40, 0x8e, 0x9b, 0x8b, 0x4d, 0x59, 0xdc, 0xa7, 0xb1, 0xb8, 0xf8, 0x1e, 0x52, 0xbf, 0xbf, + 0x28, 0xca, 0x8b, 0xef, 0x55, 0x65, 0xbe, 0xbf, 0xa0, 0x05, 0x37, 0xfa, 0xdd, 0x9a, 0x78, 0xff, 0xc8, 0x35, 0xed, + 0xd9, 0x12, 0xc2, 0xb1, 0xb4, 0xfa, 0x11, 0x94, 0x88, 0x8a, 0x14, 0x55, 0x86, 0xb2, 0x5a, 0x3b, 0xce, 0xfb, 0x44, + 0xc3, 0x63, 0xd3, 0x84, 0xc4, 0xd5, 0x12, 0xd6, 0xa1, 0x9e, 0x9d, 0x36, 0xc9, 0x8e, 0xf3, 0x40, 0x1d, 0x10, 0x15, + 0x7f, 0x5e, 0x8d, 0x76, 0xf4, 0x35, 0xf8, 0xd6, 0xf1, 0x58, 0x8d, 0xf6, 0xe6, 0xa7, 0x4f, 0xd6, 0x4a, 0x19, 0x6c, + 0xa4, 0x18, 0x85, 0x90, 0x28, 0x6e, 0xd7, 0x63, 0x00, 0xfc, 0xef, 0x1f, 0x8f, 0xf4, 0x7b, 0x2f, 0x7f, 0xab, 0xdd, + 0xd2, 0xaa, 0xe7, 0x87, 0x16, 0x61, 0xc6, 0xab, 0xda, 0xb0, 0xb3, 0x1d, 0x24, 0xa0, 0xf4, 0xa1, 0x69, 0x50, 0x53, + 0x44, 0x3f, 0x61, 0x35, 0xb1, 0x9c, 0xc3, 0x82, 0x94, 0x38, 0xc4, 0x70, 0x8c, 0x76, 0xe8, 0x71, 0xba, 0xa8, 0x79, + 0x2a, 0xdf, 0x21, 0xe3, 0xd6, 0xf7, 0x01, 0xc9, 0xa5, 0x70, 0xf9, 0xc1, 0x0b, 0x0d, 0x26, 0x7a, 0x91, 0x57, 0x45, + 0x26, 0x46, 0x82, 0x46, 0xf9, 0x0d, 0x89, 0x33, 0x17, 0x58, 0x8b, 0x0b, 0x85, 0x10, 0x16, 0x12, 0x2a, 0x77, 0x51, + 0x52, 0x7a, 0x70, 0xf1, 0xe4, 0x50, 0x36, 0xbf, 0x13, 0x26, 0xc4, 0x68, 0x01, 0x34, 0x38, 0xfb, 0x76, 0x79, 0x0f, + 0x61, 0x99, 0x7b, 0xbf, 0xbf, 0x59, 0xe5, 0x05, 0xc4, 0x65, 0x5e, 0x48, 0xc5, 0x6a, 0x79, 0x01, 0x34, 0x79, 0x22, + 0xbe, 0x08, 0x2b, 0x39, 0x0d, 0xaa, 0x8e, 0x62, 0xd5, 0x36, 0x5e, 0x56, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, + 0xdd, 0x67, 0xaf, 0x95, 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, + 0xe7, 0x26, 0xc8, 0x3f, 0xbe, 0x39, 0xa3, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, + 0x9b, 0x23, 0x35, 0x79, 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, + 0x67, 0x2b, 0x2a, 0x2f, 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xaa, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, + 0x62, 0x86, 0x29, 0xd6, 0x5f, 0xd8, 0xf2, 0xdb, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x6b, 0x16, 0xc2, + 0xf1, 0xb8, 0x9d, 0x14, 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0xc7, 0x63, 0x57, 0xcb, 0x36, 0xc2, 0x83, 0x87, 0xaa, + 0x85, 0xdb, 0x86, 0x55, 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, + 0x1b, 0x1b, 0xe0, 0x1a, 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, + 0x09, 0xa3, 0x15, 0xc2, 0xef, 0xa1, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, + 0x4a, 0xb1, 0x34, 0x6f, 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0xf3, 0xd0, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, + 0xcd, 0xe6, 0xc0, 0x7d, 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x67, 0xcb, 0xe3, + 0xf0, 0x2d, 0xfc, 0xcb, 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xcb, 0x15, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, + 0xad, 0xa8, 0x0d, 0x7f, 0xc3, 0xbf, 0x84, 0x7d, 0x84, 0xfd, 0x96, 0xe3, 0x4d, 0xd2, 0x10, 0x90, 0x09, 0xc4, 0x85, + 0x85, 0x20, 0xc1, 0xdf, 0x72, 0xc9, 0x3f, 0x27, 0x7c, 0xb6, 0x28, 0x81, 0xac, 0x0e, 0xa3, 0xf8, 0x84, 0x62, 0xa2, + 0x10, 0x86, 0x5b, 0x42, 0xef, 0xe8, 0xbf, 0x11, 0x25, 0xd9, 0xa4, 0xb2, 0x62, 0x3d, 0x90, 0x49, 0x12, 0x4c, 0xb0, + 0xf2, 0x42, 0xf9, 0xc2, 0xbd, 0x50, 0x6a, 0xad, 0x05, 0xad, 0x5f, 0xfe, 0x24, 0xf1, 0x0c, 0xe8, 0x1e, 0xc8, 0x18, + 0x74, 0x1b, 0x51, 0x4d, 0x72, 0x4c, 0x1f, 0xa5, 0xf3, 0x0c, 0x54, 0x40, 0x17, 0x9b, 0x2c, 0xac, 0x97, 0x45, 0xb9, + 0x6e, 0x85, 0x87, 0xca, 0xd2, 0x47, 0xea, 0x31, 0xe6, 0x85, 0x79, 0x72, 0x26, 0x1f, 0x3c, 0x02, 0x34, 0x3c, 0xca, + 0xd3, 0xaa, 0xa3, 0xb4, 0x7e, 0x60, 0x19, 0x30, 0x02, 0x67, 0xca, 0x80, 0x47, 0x58, 0x06, 0xe6, 0x69, 0x97, 0xa1, + 0x06, 0xb1, 0x46, 0xd5, 0x95, 0xda, 0x60, 0xce, 0x14, 0x25, 0x9f, 0x62, 0x69, 0x85, 0x31, 0x34, 0x75, 0xe5, 0x91, + 0xf5, 0x92, 0x13, 0xf6, 0x6c, 0x37, 0x90, 0x6e, 0x61, 0xab, 0xc0, 0x05, 0x5d, 0xcb, 0x12, 0xe5, 0xa2, 0x5b, 0x46, + 0x94, 0x89, 0x90, 0xfa, 0xd9, 0xc3, 0x99, 0x56, 0xfb, 0x8d, 0x9d, 0x74, 0x68, 0x8f, 0x14, 0xbd, 0x60, 0x20, 0x3e, + 0xed, 0x91, 0x52, 0xcf, 0x1a, 0xb9, 0x0c, 0x6c, 0xe9, 0x52, 0xd5, 0xf3, 0x5f, 0xa0, 0x7c, 0x07, 0x33, 0xe3, 0x6c, + 0xf6, 0xbb, 0xde, 0xdc, 0x9e, 0x1c, 0xea, 0xe6, 0x77, 0xd6, 0xeb, 0xc1, 0xd6, 0x20, 0x13, 0x5f, 0x28, 0xea, 0x29, + 0xab, 0x10, 0x2b, 0x32, 0xfb, 0x5f, 0xc2, 0xfb, 0x1d, 0xde, 0x1a, 0xa1, 0x59, 0x19, 0x0f, 0xf3, 0xd1, 0x93, 0x83, + 0x68, 0x7e, 0xef, 0x2c, 0xdb, 0xca, 0x55, 0xc9, 0x6c, 0xbf, 0x9f, 0x24, 0xcd, 0xd9, 0xe3, 0x35, 0x92, 0x3a, 0xc0, + 0xc7, 0xeb, 0x33, 0x7c, 0xa4, 0x12, 0x4a, 0x2d, 0xa8, 0x6a, 0xd0, 0xfa, 0xd8, 0xef, 0xad, 0xe7, 0xf4, 0xf1, 0x53, + 0x39, 0xdd, 0x92, 0x22, 0x8c, 0x1f, 0x18, 0x4c, 0xd9, 0x89, 0x53, 0x97, 0xaa, 0x19, 0xd2, 0xbb, 0x6e, 0x95, 0xd4, + 0x65, 0x8f, 0x12, 0x41, 0xa8, 0x83, 0xf5, 0x8b, 0xfd, 0x10, 0x66, 0xb6, 0xe8, 0x0f, 0x9b, 0xd5, 0x9c, 0x50, 0x10, + 0x01, 0xa2, 0x55, 0xde, 0x07, 0x4e, 0x49, 0xc2, 0xac, 0xb9, 0x21, 0xdd, 0x7a, 0x2b, 0xa5, 0xbd, 0x92, 0x02, 0xfa, + 0x65, 0x7e, 0x3c, 0xa2, 0xf9, 0xcd, 0xec, 0x5c, 0x95, 0xb4, 0xe5, 0x00, 0x22, 0x75, 0xde, 0xb4, 0x2f, 0x1d, 0x0e, + 0xfe, 0x83, 0xba, 0x12, 0xe5, 0x44, 0xd0, 0x51, 0xb4, 0x60, 0xb4, 0x5a, 0xb5, 0xab, 0xc8, 0xa6, 0x42, 0xb6, 0x24, + 0xc2, 0x89, 0x92, 0xbd, 0x12, 0xea, 0xa3, 0x5c, 0xed, 0x99, 0x86, 0xf8, 0x33, 0x01, 0x9b, 0x36, 0xf8, 0x5b, 0xe0, + 0x5e, 0x06, 0x67, 0xa6, 0x7d, 0x1a, 0x46, 0x40, 0x64, 0x0e, 0xc1, 0x7e, 0x7e, 0xd7, 0x83, 0x1c, 0x1e, 0x74, 0xa4, + 0xbf, 0xaa, 0x67, 0x05, 0x9e, 0xb9, 0x67, 0x9e, 0xbf, 0x3e, 0x93, 0x9e, 0x57, 0xf0, 0x40, 0x73, 0x1f, 0x66, 0xfc, + 0x45, 0x59, 0x86, 0xfb, 0xd1, 0xb2, 0x2c, 0xd6, 0x5e, 0xa4, 0xf7, 0xf1, 0x4c, 0x8a, 0x81, 0x44, 0x87, 0x99, 0xd1, + 0x55, 0xac, 0xe3, 0x1c, 0xc6, 0xbd, 0x3d, 0x09, 0x2b, 0xb4, 0x7f, 0x96, 0xd8, 0xeb, 0x02, 0x00, 0x1c, 0xb2, 0x06, + 0xad, 0xf0, 0x4e, 0xb7, 0xb7, 0x7b, 0x5c, 0x52, 0xa2, 0xb8, 0x51, 0xf3, 0xb3, 0x1a, 0x5a, 0x26, 0xa8, 0x65, 0xd6, + 0x9d, 0x4c, 0xa6, 0x48, 0x02, 0xdf, 0x86, 0xbd, 0x66, 0x79, 0x35, 0x6f, 0xe4, 0xf6, 0xf0, 0x2e, 0x5c, 0x8b, 0x58, + 0x5b, 0xd0, 0x49, 0x47, 0xc6, 0xe1, 0x5e, 0x68, 0x6e, 0xa4, 0x87, 0x27, 0x55, 0x12, 0x96, 0x22, 0x86, 0x5b, 0x20, + 0x3b, 0xa8, 0x6d, 0x25, 0x28, 0x81, 0x04, 0xf6, 0x43, 0x29, 0x96, 0xe9, 0x4e, 0x00, 0x98, 0x03, 0xff, 0x53, 0x1a, + 0xbb, 0xdd, 0x9d, 0x87, 0x78, 0xd5, 0xc8, 0xfb, 0x06, 0x21, 0xd8, 0x5f, 0x81, 0x9c, 0x06, 0x0c, 0x22, 0xc5, 0x48, + 0x16, 0x0c, 0x24, 0x00, 0x15, 0xdf, 0x80, 0x49, 0x6e, 0x5a, 0x79, 0x7e, 0x50, 0xe9, 0x0e, 0xa6, 0x7d, 0xd0, 0xbd, + 0xb8, 0xd6, 0x0c, 0x90, 0x7f, 0x27, 0x11, 0xff, 0x5b, 0xed, 0x95, 0xac, 0x62, 0x99, 0xdf, 0x98, 0x8b, 0x4e, 0x06, + 0x57, 0x0d, 0xe1, 0x17, 0xb3, 0x6c, 0xce, 0xa3, 0x59, 0xa6, 0x43, 0xfd, 0x8b, 0xe6, 0xa4, 0x14, 0xc0, 0x50, 0xc7, + 0x0b, 0xb0, 0xc6, 0xbb, 0xd2, 0x4d, 0x2b, 0x1e, 0x69, 0x8c, 0x51, 0x50, 0xa1, 0x83, 0xd0, 0xdf, 0x6a, 0x80, 0xd7, + 0x60, 0x92, 0x1b, 0x21, 0xf7, 0xc1, 0x05, 0xdd, 0xd0, 0x2d, 0xe7, 0x2e, 0x41, 0x4d, 0xaa, 0x96, 0x5f, 0x85, 0x50, + 0xef, 0x6a, 0xc9, 0xa5, 0xda, 0x7c, 0x6a, 0x94, 0x35, 0x82, 0x4c, 0x8e, 0xd2, 0xef, 0x53, 0x2e, 0xdc, 0xdc, 0x98, + 0xac, 0x8f, 0x47, 0xaf, 0xe0, 0xa6, 0xc6, 0x3f, 0x56, 0x92, 0x45, 0xd4, 0x1a, 0x12, 0x61, 0x6b, 0xb7, 0x42, 0xf7, + 0x1e, 0x37, 0x4a, 0xf3, 0x28, 0xdb, 0xc6, 0xa2, 0xf2, 0x7a, 0x09, 0x58, 0x8b, 0x7b, 0x40, 0x86, 0x4a, 0x4b, 0x3f, + 0x67, 0x05, 0x40, 0x06, 0x48, 0x61, 0xe3, 0x47, 0xa4, 0xbd, 0xfa, 0xe0, 0xa5, 0x7e, 0xbf, 0x6f, 0x4c, 0xf9, 0xef, + 0x1f, 0x72, 0x60, 0x26, 0x14, 0x65, 0xbd, 0x87, 0x09, 0x54, 0x79, 0xa9, 0x4f, 0xda, 0xb3, 0x9a, 0x3f, 0xdf, 0xd4, + 0x1e, 0x90, 0x5a, 0xf9, 0x16, 0x73, 0xd5, 0x2b, 0xfb, 0x62, 0x73, 0x48, 0xab, 0x5b, 0xa3, 0x71, 0x10, 0x2c, 0xad, + 0xde, 0x68, 0x95, 0x43, 0xd5, 0xf0, 0x1c, 0x44, 0x2a, 0xeb, 0xea, 0x9a, 0x3b, 0x57, 0xd7, 0x82, 0x23, 0x81, 0x6c, + 0xc9, 0x21, 0x2c, 0x8d, 0x85, 0xdc, 0x2b, 0x8f, 0xc7, 0xc2, 0xef, 0xf7, 0xd3, 0x59, 0x8e, 0x97, 0x16, 0xa0, 0x4c, + 0xdb, 0xd4, 0x5e, 0xe8, 0x1f, 0x8f, 0x3f, 0x82, 0xd7, 0x88, 0x7f, 0x3c, 0x96, 0xfd, 0xfe, 0x47, 0x73, 0x93, 0xb9, + 0x1c, 0x2b, 0xa5, 0xec, 0x35, 0x2a, 0xdd, 0xdf, 0x24, 0xbc, 0xf7, 0xbf, 0x47, 0xff, 0x7b, 0x74, 0xdd, 0x53, 0x01, + 0x60, 0x09, 0x9f, 0xe1, 0x0d, 0x9d, 0xa9, 0xcb, 0x39, 0x93, 0xee, 0xee, 0xca, 0x0f, 0xbd, 0xa7, 0xf1, 0xe1, 0x7b, + 0x73, 0xd3, 0xc6, 0x5f, 0xf3, 0x13, 0x4d, 0x42, 0xc7, 0x45, 0xff, 0x78, 0xfc, 0x94, 0x68, 0x7d, 0x5a, 0xaa, 0xf4, + 0x69, 0x0a, 0x3c, 0xc9, 0xb0, 0xe1, 0xba, 0x85, 0xe9, 0x68, 0x7e, 0xdc, 0x7c, 0x95, 0xbc, 0x38, 0x4b, 0xe1, 0xda, + 0x0b, 0x3a, 0x97, 0x29, 0x58, 0x57, 0x86, 0xe0, 0x66, 0x10, 0x40, 0xea, 0x10, 0xd2, 0xac, 0x69, 0xf8, 0x97, 0xdc, + 0x15, 0xbc, 0xb5, 0xc7, 0xbb, 0xc1, 0x88, 0x52, 0x47, 0xfa, 0xa4, 0x0d, 0xa1, 0x4b, 0x2a, 0xf9, 0x8f, 0x22, 0x8f, + 0x31, 0x66, 0xe3, 0x15, 0x91, 0x7d, 0x16, 0xf9, 0xcb, 0x02, 0x00, 0x8b, 0x00, 0x01, 0x39, 0x9d, 0x3b, 0x92, 0xf8, + 0xcf, 0xc9, 0xb7, 0x7f, 0x4c, 0x97, 0xf6, 0xa1, 0x2c, 0x56, 0xa5, 0xa8, 0xaa, 0x93, 0xd2, 0xf6, 0xb6, 0x5c, 0x0f, + 0xf4, 0xa1, 0xfd, 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, + 0x58, 0x3f, 0x7f, 0xd8, 0xbf, 0x89, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, + 0xc3, 0x54, 0xe2, 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0xbf, 0xe7, 0x30, 0xff, 0x75, + 0x7b, 0xb0, 0x3e, 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0xe7, 0xc2, 0x22, 0xf9, + 0xf5, 0xc9, 0x91, 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x89, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9d, 0xff, 0x95, 0x99, 0xff, + 0x03, 0x8c, 0x49, 0x28, 0x9e, 0x73, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0xcf, 0x81, + 0x83, 0xf9, 0x39, 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0xd7, 0x16, 0xcf, 0x95, + 0x5c, 0x10, 0xfa, 0xba, 0x0a, 0xb3, 0x71, 0x5d, 0x6c, 0x2b, 0x51, 0x6c, 0x21, 0x6c, 0x04, 0xd4, 0xb2, 0xd5, 0xb4, + 0xb6, 0x15, 0xb2, 0x3f, 0x89, 0x16, 0x6d, 0x97, 0xa1, 0x9a, 0x8c, 0xb2, 0x74, 0x33, 0x05, 0x52, 0xbd, 0x00, 0xce, + 0x22, 0xf3, 0xca, 0x3b, 0x67, 0x0f, 0xd8, 0xa1, 0xf1, 0x14, 0x18, 0x51, 0xe9, 0x8f, 0xaa, 0x31, 0x3a, 0x3d, 0xd1, + 0xef, 0x57, 0x53, 0x0a, 0xf9, 0xfa, 0x09, 0x30, 0xb9, 0x6a, 0xb9, 0x00, 0x7d, 0x19, 0xea, 0xa0, 0x12, 0xa5, 0x56, + 0x0c, 0x23, 0x16, 0x7e, 0x12, 0xc8, 0xde, 0x4c, 0x41, 0xcd, 0x2a, 0x4a, 0x42, 0x25, 0x2a, 0x25, 0x5b, 0x13, 0xd4, + 0xd2, 0xfb, 0xa2, 0xa8, 0x0f, 0x15, 0x38, 0x4a, 0x46, 0xda, 0x2c, 0xa7, 0xcc, 0xb8, 0x28, 0x73, 0xd1, 0x0f, 0xf6, + 0x2f, 0xc0, 0xf8, 0x92, 0xf9, 0x2c, 0xf7, 0x1d, 0x9d, 0xd3, 0x76, 0x5c, 0xa0, 0xcc, 0x2d, 0xa7, 0xad, 0x96, 0x3c, + 0x26, 0xef, 0x59, 0xb0, 0xed, 0xbf, 0x48, 0x90, 0x57, 0x11, 0xe6, 0x13, 0xaa, 0x6c, 0xfe, 0x9e, 0x7b, 0xc4, 0x3e, + 0xda, 0xe1, 0xc2, 0x44, 0xa4, 0xb7, 0x60, 0x49, 0x0c, 0xb3, 0x52, 0x84, 0xf1, 0x1e, 0xbc, 0x7f, 0xb6, 0x95, 0x18, + 0x5d, 0xa0, 0x93, 0xfb, 0xc5, 0x43, 0x5a, 0x27, 0x17, 0x6f, 0x5e, 0x5d, 0x7c, 0xdf, 0x1b, 0x14, 0xa3, 0x34, 0x1e, + 0xf4, 0xbe, 0xbf, 0x58, 0x6f, 0x01, 0x22, 0x53, 0x5c, 0xc4, 0x64, 0x4a, 0x13, 0xf1, 0x05, 0x19, 0x06, 0x2f, 0xea, + 0x44, 0x5c, 0xd0, 0xc4, 0x74, 0x5f, 0xa3, 0x34, 0xf9, 0x76, 0x14, 0xe6, 0xf0, 0x72, 0x29, 0xb6, 0x95, 0x88, 0xc1, + 0x4e, 0xa9, 0xe6, 0xd9, 0xc9, 0x59, 0x2c, 0x3d, 0x06, 0x5d, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, + 0x05, 0x84, 0x1e, 0xf0, 0xcc, 0xcf, 0xe3, 0x51, 0x24, 0x10, 0x6a, 0xc1, 0x9c, 0x4c, 0x23, 0xba, 0x21, 0xbd, 0xc4, + 0x3e, 0x03, 0xb3, 0x90, 0xd2, 0x3c, 0xb8, 0xb9, 0x5a, 0xb4, 0xdc, 0x39, 0x2b, 0x47, 0x61, 0xb5, 0x11, 0x51, 0x8d, + 0x54, 0xc7, 0xe0, 0xbc, 0x03, 0x11, 0x00, 0x8a, 0x11, 0x3c, 0xe3, 0x51, 0xbf, 0x1f, 0xa9, 0xa0, 0x9c, 0x84, 0x7e, + 0x51, 0xe8, 0x97, 0xc6, 0xa0, 0x8c, 0xf9, 0x97, 0x50, 0x13, 0x03, 0xd4, 0x3b, 0x1e, 0x2a, 0x8e, 0x00, 0x5c, 0xce, + 0x11, 0x33, 0xce, 0x7b, 0xdc, 0x45, 0xe3, 0x54, 0xbc, 0x13, 0xea, 0x3a, 0x58, 0x2a, 0xd4, 0x79, 0x53, 0x1f, 0xe9, + 0x39, 0x69, 0x12, 0x34, 0x88, 0x1b, 0x78, 0xbc, 0x1a, 0x02, 0xaa, 0xb5, 0x90, 0x7a, 0x0b, 0x9d, 0x52, 0xd5, 0x21, + 0xb0, 0x06, 0xb8, 0x44, 0x61, 0x3b, 0x61, 0x72, 0x44, 0xdb, 0xb2, 0x14, 0xf9, 0x09, 0x1b, 0xb4, 0x4b, 0x46, 0xa6, + 0x0e, 0x2e, 0x97, 0xcb, 0x89, 0xa8, 0x7f, 0xcd, 0xb7, 0x00, 0xce, 0x0b, 0xf9, 0xad, 0xdd, 0x6c, 0x99, 0x64, 0xbb, + 0xfe, 0x3f, 0xbc, 0x7d, 0x09, 0x77, 0xdb, 0x46, 0xb2, 0xee, 0x5f, 0x11, 0xf1, 0x1c, 0x06, 0x6d, 0x36, 0x29, 0x52, + 0xb1, 0x33, 0x09, 0xa8, 0x16, 0xaf, 0xe2, 0x25, 0x71, 0x26, 0x5e, 0x62, 0x39, 0x99, 0xcc, 0xf0, 0xf1, 0x2a, 0x10, + 0xd0, 0x12, 0x11, 0x43, 0x68, 0x06, 0x00, 0xb5, 0x84, 0xc4, 0x7f, 0x7f, 0xa7, 0xaa, 0x77, 0x10, 0x94, 0x3d, 0xf3, + 0xee, 0x7b, 0xc7, 0xe7, 0x58, 0x44, 0xa3, 0xd1, 0x7b, 0x57, 0x57, 0xd7, 0xf2, 0x55, 0x65, 0x63, 0x96, 0x94, 0xbc, + 0x5a, 0x89, 0xa2, 0xca, 0x6e, 0xf8, 0x4f, 0xe6, 0xa5, 0x1f, 0x40, 0x0a, 0xed, 0x48, 0x5f, 0xb7, 0xbb, 0xa3, 0xc4, + 0x38, 0xa6, 0x1c, 0xd7, 0x52, 0xe9, 0x5e, 0x8d, 0xaa, 0x13, 0x37, 0x5b, 0xe5, 0x5a, 0x66, 0x69, 0xca, 0x8b, 0x57, + 0x45, 0x9a, 0x25, 0x4e, 0x72, 0xac, 0x02, 0x54, 0xdb, 0xc8, 0x57, 0x36, 0x36, 0xf2, 0xf3, 0xac, 0xc2, 0x80, 0xc1, + 0x5e, 0xa3, 0x5a, 0xa1, 0xa6, 0x74, 0xe0, 0x0b, 0xf1, 0x1e, 0x23, 0x6e, 0xb3, 0x22, 0x01, 0x86, 0x1f, 0x13, 0xd5, + 0x25, 0x3d, 0x85, 0x28, 0x0f, 0x32, 0x1e, 0xf7, 0x73, 0x8e, 0x88, 0xd7, 0x46, 0x65, 0x0e, 0x4c, 0xb6, 0x52, 0x41, + 0x22, 0xd8, 0x5d, 0x36, 0x57, 0x8b, 0x68, 0x21, 0xef, 0x42, 0xbd, 0x78, 0xbb, 0xed, 0x25, 0x92, 0x0e, 0x58, 0xf9, + 0x69, 0xf0, 0x32, 0xce, 0x72, 0x9e, 0x1e, 0xd4, 0xe2, 0x40, 0x6e, 0xa8, 0x03, 0xe9, 0xcc, 0x01, 0x3b, 0xef, 0xcb, + 0xfa, 0x40, 0xad, 0xe9, 0x03, 0xd5, 0xce, 0x03, 0xb8, 0x60, 0xe0, 0xce, 0xbd, 0xca, 0x6e, 0x78, 0x71, 0x00, 0xca, + 0x40, 0x63, 0x3c, 0xd0, 0x54, 0xf5, 0x48, 0x4e, 0x8c, 0x0a, 0x5c, 0x9d, 0xa8, 0x83, 0x39, 0xa0, 0xdf, 0x03, 0x52, + 0x54, 0xeb, 0xed, 0x4a, 0x1d, 0xb4, 0x01, 0xfd, 0x69, 0xa9, 0xfb, 0xa0, 0xa2, 0xc5, 0xcb, 0x90, 0xc0, 0xde, 0x90, + 0x2a, 0xa4, 0x56, 0x2d, 0xab, 0x40, 0xf1, 0x86, 0xb3, 0x78, 0x77, 0xae, 0x25, 0x1b, 0xe7, 0x25, 0x02, 0x7b, 0x65, + 0x45, 0x1d, 0x67, 0xc5, 0xa9, 0x93, 0xca, 0x1b, 0xe5, 0x24, 0x53, 0x69, 0xdf, 0xb2, 0x82, 0xba, 0x3b, 0x44, 0xdf, + 0x22, 0xf5, 0x61, 0xf0, 0x22, 0xac, 0xc9, 0x8c, 0xf7, 0xfb, 0x62, 0x26, 0xa2, 0x62, 0x56, 0x1d, 0x16, 0x91, 0x44, + 0x68, 0xdb, 0x27, 0x02, 0x7a, 0x50, 0x02, 0xe4, 0x0a, 0x80, 0xea, 0x87, 0x84, 0x3f, 0x0f, 0x49, 0x7d, 0x3a, 0x85, + 0x3e, 0xa5, 0xb2, 0x5e, 0x71, 0x0a, 0xaa, 0x1b, 0x6f, 0x64, 0xbd, 0x0a, 0x5a, 0x3c, 0x96, 0x63, 0xb5, 0xa1, 0x6d, + 0x4e, 0x8d, 0x77, 0xbd, 0xde, 0x60, 0xd2, 0xe6, 0x42, 0xae, 0xc2, 0x90, 0x44, 0xb7, 0x85, 0x13, 0x3e, 0xc4, 0x60, + 0x65, 0xb5, 0x36, 0xbf, 0x8e, 0xfd, 0x91, 0x15, 0x29, 0xee, 0x67, 0x43, 0x9c, 0xbb, 0x78, 0x3c, 0xa7, 0xfa, 0x46, + 0x49, 0x8b, 0x74, 0x9b, 0xef, 0xd5, 0x65, 0x48, 0x51, 0x51, 0x4d, 0x1a, 0x55, 0x66, 0xd0, 0x7d, 0xdb, 0xbc, 0x55, + 0x3d, 0xc2, 0x04, 0x78, 0xa5, 0x32, 0xa8, 0x46, 0xe3, 0x81, 0x58, 0xd5, 0xa3, 0x72, 0x5d, 0x14, 0x88, 0x36, 0x0c, + 0x39, 0x66, 0x86, 0x90, 0x64, 0x7f, 0xf1, 0xef, 0x64, 0x70, 0x85, 0x32, 0xbe, 0xd5, 0x70, 0xde, 0xb5, 0xf1, 0xec, + 0x6e, 0x22, 0x37, 0x27, 0x16, 0xd6, 0xb8, 0x0f, 0xfe, 0x51, 0xab, 0x9d, 0x05, 0x94, 0x35, 0xad, 0x6a, 0x38, 0xdc, + 0xa3, 0x3a, 0x16, 0xa5, 0x06, 0x24, 0x76, 0xc8, 0x72, 0xd9, 0x3a, 0x66, 0xd0, 0x80, 0xfe, 0x2e, 0xbb, 0x5e, 0x5f, + 0x23, 0x6a, 0x5b, 0x81, 0xac, 0x93, 0x90, 0xfe, 0x25, 0xed, 0x51, 0x57, 0xf6, 0x54, 0xee, 0xb7, 0x6d, 0xaa, 0x1c, + 0x1a, 0x20, 0x79, 0xec, 0xe6, 0x2c, 0x90, 0x1d, 0x09, 0xa2, 0x40, 0x6e, 0xbd, 0x60, 0xea, 0x9c, 0x32, 0x65, 0x07, + 0xf2, 0x73, 0xa9, 0xcf, 0xb0, 0xcf, 0x38, 0x62, 0xf4, 0x52, 0x89, 0xc1, 0xd4, 0x47, 0x1b, 0xd5, 0xb4, 0x56, 0x80, + 0xaa, 0x9f, 0x6e, 0xe0, 0x4f, 0x54, 0x36, 0x68, 0xa8, 0x35, 0x12, 0x85, 0xa4, 0x89, 0x12, 0x3a, 0x96, 0x96, 0x2a, + 0x98, 0x42, 0x27, 0x91, 0x30, 0x04, 0x34, 0x4c, 0x88, 0x4a, 0x2a, 0xf1, 0xd6, 0x00, 0xce, 0x7c, 0xbc, 0xa8, 0xd6, + 0xa5, 0x32, 0x98, 0xfb, 0x21, 0xbe, 0xe1, 0xaf, 0x9e, 0x5b, 0xa3, 0xfa, 0x96, 0xb5, 0xbe, 0xa3, 0x05, 0xf9, 0x21, + 0xe4, 0x14, 0x1d, 0x98, 0xd8, 0xc9, 0x06, 0x0f, 0xe6, 0xa2, 0x51, 0xa1, 0x2e, 0xde, 0xaa, 0xf8, 0x2b, 0xca, 0x04, + 0xef, 0x01, 0x4f, 0x11, 0x65, 0x78, 0x58, 0x69, 0xab, 0x6a, 0x7c, 0x2a, 0x58, 0x4b, 0x0f, 0x56, 0xf2, 0x74, 0x9d, + 0xf0, 0x10, 0xf4, 0x48, 0x84, 0x9d, 0x84, 0xe5, 0x3c, 0x5e, 0xc0, 0x71, 0x52, 0x12, 0x50, 0x3b, 0xa8, 0x2b, 0xf8, + 0x7c, 0x81, 0xee, 0xaf, 0x02, 0x3d, 0xc0, 0xd0, 0x82, 0xd8, 0x0f, 0x7d, 0x3a, 0xba, 0x8e, 0x57, 0x9e, 0x8a, 0x84, + 0xcf, 0x4b, 0xb0, 0x1d, 0x92, 0xea, 0x29, 0xd0, 0x42, 0x25, 0x52, 0x3f, 0x0c, 0x7c, 0x87, 0x02, 0xbe, 0x56, 0x3a, + 0x40, 0x4d, 0x3f, 0x63, 0x9a, 0x1a, 0x67, 0xa8, 0x7c, 0xe6, 0xdc, 0x33, 0xa3, 0xe5, 0xcc, 0x80, 0x31, 0xa8, 0xdb, + 0x68, 0x8a, 0xe2, 0x9c, 0x7c, 0x16, 0x94, 0x71, 0x9a, 0xc5, 0x39, 0xf8, 0x6d, 0xc6, 0x25, 0x66, 0x4c, 0xe2, 0x9a, + 0x5f, 0x89, 0x12, 0xb4, 0xdd, 0xb9, 0x4c, 0x6d, 0x1a, 0x10, 0x90, 0xfd, 0x00, 0x56, 0x2f, 0x9e, 0x8e, 0xca, 0x7a, + 0x77, 0x29, 0x53, 0x88, 0xb2, 0x0a, 0xc1, 0xa6, 0x99, 0x2e, 0xd9, 0x69, 0x28, 0xb5, 0x39, 0x10, 0xdf, 0x08, 0x8d, + 0xfb, 0xa7, 0x61, 0x6c, 0x34, 0xc5, 0xc6, 0xee, 0x6d, 0xbb, 0xfd, 0xad, 0x70, 0xd2, 0x69, 0x4e, 0x7a, 0x8c, 0xfd, + 0x56, 0x84, 0xe5, 0xc8, 0x74, 0x84, 0xc0, 0x92, 0x73, 0x3e, 0x75, 0x5f, 0xd1, 0x62, 0x9e, 0x80, 0xe9, 0x88, 0x8a, + 0x90, 0x0b, 0x94, 0x1d, 0xa3, 0xb8, 0x03, 0x83, 0x0b, 0x66, 0x42, 0x10, 0x4b, 0x4f, 0x5d, 0x48, 0x96, 0x24, 0x65, + 0xf0, 0x3c, 0x75, 0x30, 0xe0, 0xd7, 0x4c, 0x9a, 0xbb, 0x48, 0xeb, 0xd3, 0x25, 0x99, 0xa6, 0xc8, 0x40, 0xac, 0xc3, + 0x4d, 0x96, 0x46, 0x89, 0x14, 0x91, 0x2d, 0xd1, 0x3f, 0x52, 0x53, 0x2c, 0x15, 0xae, 0x17, 0xa9, 0x12, 0xa1, 0xd5, + 0x3c, 0xc5, 0x93, 0x3a, 0x6d, 0xd2, 0x11, 0xc6, 0x9b, 0x04, 0xa5, 0x5c, 0x03, 0x03, 0x55, 0x50, 0xb5, 0x14, 0x36, + 0xe5, 0x76, 0xab, 0x2e, 0x56, 0xd5, 0x3c, 0x5e, 0xe0, 0xcb, 0x0a, 0x47, 0xf1, 0xef, 0xdc, 0x89, 0x35, 0x25, 0xb7, + 0x07, 0x35, 0x23, 0x4a, 0xe8, 0xdf, 0x39, 0x5c, 0x24, 0xbe, 0x13, 0x2a, 0xee, 0x1f, 0x5a, 0x84, 0x9c, 0xcb, 0x83, + 0x54, 0x73, 0x43, 0x3b, 0xc2, 0x7f, 0xcd, 0xf5, 0x69, 0x67, 0x74, 0x5f, 0xcd, 0xa8, 0xf0, 0x7b, 0x1d, 0x3c, 0x63, + 0xd4, 0x67, 0x03, 0x87, 0x15, 0xa2, 0xd0, 0x86, 0x9d, 0x14, 0x52, 0xb4, 0x30, 0x14, 0xf2, 0x2f, 0xa1, 0xd5, 0x09, + 0xb7, 0x66, 0x94, 0x05, 0xe3, 0xd3, 0xe2, 0xb8, 0x9a, 0x0e, 0x06, 0x05, 0xa9, 0xb5, 0x85, 0x1e, 0x5c, 0x0f, 0x1c, + 0xff, 0x1e, 0xb8, 0x85, 0x38, 0x70, 0xc8, 0xd5, 0x90, 0x6b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8f, 0x2a, 0x19, 0xbc, + 0x9a, 0xc8, 0x16, 0xfc, 0xbd, 0x08, 0x03, 0xf4, 0x49, 0x0a, 0xc0, 0x64, 0x30, 0xe5, 0x77, 0x20, 0x51, 0x3a, 0x97, + 0x37, 0xa4, 0x5f, 0x8a, 0x92, 0x5f, 0xf2, 0x92, 0x17, 0x89, 0x2d, 0xc0, 0xf0, 0x0e, 0xa6, 0xd7, 0x51, 0x4d, 0x25, + 0x10, 0xaf, 0xee, 0x71, 0xc4, 0xb5, 0xf7, 0x9f, 0xee, 0xb1, 0x01, 0x6a, 0x35, 0x8e, 0x0d, 0x2e, 0x73, 0x0c, 0x2e, + 0xe8, 0x4a, 0x62, 0xab, 0xa9, 0x86, 0x11, 0x81, 0x81, 0x0b, 0x38, 0x08, 0x4b, 0x24, 0xc7, 0x56, 0xf1, 0x9a, 0x78, + 0x52, 0xda, 0x07, 0x86, 0xa3, 0x4d, 0x72, 0x5c, 0x9b, 0x65, 0x3b, 0x81, 0xf3, 0x45, 0xe7, 0xa4, 0xe9, 0x58, 0x36, + 0x78, 0x9f, 0xd7, 0xe7, 0xd7, 0xfe, 0x21, 0xa1, 0x32, 0xd8, 0x0d, 0x6f, 0x07, 0xbb, 0xb1, 0xc2, 0xaf, 0x79, 0xb5, + 0x50, 0xf1, 0x59, 0xf4, 0x25, 0xcb, 0x6d, 0xad, 0x73, 0x4b, 0x12, 0x4a, 0x01, 0xed, 0xb2, 0x2c, 0xa8, 0x89, 0x00, + 0x74, 0x3f, 0xfc, 0x05, 0x42, 0x67, 0xf8, 0xdb, 0x63, 0x70, 0x45, 0x0a, 0xf7, 0x0e, 0x41, 0x65, 0x4c, 0x37, 0x77, + 0x6a, 0x03, 0xbe, 0x18, 0xf7, 0x67, 0x4c, 0x1d, 0xfd, 0x36, 0x13, 0xbb, 0xba, 0x6e, 0x87, 0x2c, 0xc3, 0x47, 0xb8, + 0x52, 0x00, 0x2c, 0x13, 0xfe, 0x62, 0x6c, 0x49, 0xf9, 0x09, 0xc0, 0xa9, 0xa9, 0x88, 0x3e, 0x41, 0xa0, 0xe1, 0x94, + 0x68, 0x39, 0xba, 0x91, 0x8e, 0x68, 0x1a, 0x69, 0x4d, 0xb5, 0x42, 0x7b, 0xeb, 0x61, 0x91, 0xd6, 0x34, 0x9c, 0xb8, + 0x0f, 0x8a, 0x79, 0x95, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0x51, 0x1f, 0x21, 0x2e, 0x61, 0x49, 0x14, 0x61, + 0x71, 0x4c, 0xf1, 0x63, 0x42, 0x37, 0xbe, 0xb6, 0xe9, 0x03, 0xd2, 0x5f, 0x5c, 0xb3, 0x6e, 0xca, 0xb2, 0x71, 0xed, + 0xa1, 0xe2, 0xc5, 0xd4, 0x0f, 0x7e, 0x98, 0xc8, 0x62, 0xdc, 0x2f, 0x6a, 0x57, 0x6a, 0x05, 0x30, 0xcc, 0x5d, 0xf5, + 0xf4, 0xfb, 0x7e, 0xb6, 0x1c, 0x08, 0x95, 0xdb, 0x19, 0x24, 0x7d, 0x2a, 0x9e, 0x1f, 0x1c, 0xd1, 0xca, 0x42, 0xcf, + 0x1d, 0x97, 0xc6, 0x87, 0xca, 0x6b, 0x53, 0x23, 0x5a, 0x23, 0x43, 0x65, 0xea, 0x80, 0xf5, 0xfd, 0x43, 0xb8, 0xbb, + 0xa8, 0x69, 0xa8, 0x74, 0xcf, 0x5d, 0x8b, 0x82, 0x13, 0x77, 0x80, 0xb1, 0xb8, 0x90, 0x34, 0x2a, 0x08, 0x93, 0x7a, + 0x34, 0x38, 0xc9, 0x5e, 0x5d, 0x9d, 0x9c, 0x29, 0xe6, 0x09, 0x6c, 0x54, 0xcb, 0xb6, 0xbf, 0xa2, 0x54, 0x97, 0x72, + 0x73, 0x45, 0xf1, 0x3d, 0xa4, 0xcd, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x33, 0x05, 0x17, 0xc6, 0xc1, 0xba, 0xe3, + 0x4e, 0xd9, 0x73, 0x45, 0x99, 0xc6, 0x06, 0x77, 0xed, 0x31, 0x26, 0xda, 0x7e, 0x77, 0xc9, 0x93, 0x8f, 0xc8, 0x82, + 0x7f, 0x97, 0x15, 0xe0, 0x99, 0x6c, 0x5f, 0xc9, 0xfc, 0x3f, 0xb8, 0x57, 0x5b, 0xf3, 0xce, 0x98, 0x7f, 0x3a, 0xd6, + 0xc3, 0x9d, 0xc3, 0xe4, 0x06, 0xe8, 0x0c, 0xe8, 0xe6, 0x5a, 0xa4, 0x1c, 0x90, 0x01, 0x8c, 0x45, 0x32, 0x1a, 0xf0, + 0xa1, 0x95, 0x65, 0xdb, 0x77, 0x5a, 0x5e, 0x10, 0xf6, 0x12, 0xb8, 0xe9, 0xfe, 0xda, 0xf4, 0xcc, 0xa9, 0x5a, 0x89, + 0xa2, 0x4b, 0x63, 0x63, 0x59, 0x2a, 0x81, 0xdd, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x78, 0x39, 0xcd, 0x0d, 0x75, 0xdb, + 0xd8, 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0x35, 0x22, 0xf4, 0x54, 0x8a, + 0xd0, 0xa7, 0xa9, 0xdf, 0x07, 0xb3, 0xaa, 0xd6, 0x5e, 0x9c, 0xa3, 0x41, 0xaa, 0x18, 0xf9, 0xb7, 0x37, 0xbc, 0xbc, + 0xcc, 0xc5, 0x2d, 0x60, 0x20, 0x93, 0x46, 0x2b, 0x2c, 0xaf, 0xc1, 0x9d, 0x1f, 0x1d, 0xc7, 0x19, 0xc0, 0x26, 0x41, + 0xb0, 0x56, 0x84, 0x47, 0x56, 0x89, 0x33, 0x00, 0x41, 0x76, 0x27, 0x4d, 0xc5, 0x73, 0x2d, 0x31, 0xa6, 0x2f, 0x70, + 0x57, 0x39, 0x3b, 0xd9, 0xe4, 0x66, 0xd1, 0xfb, 0x33, 0xac, 0x3a, 0x52, 0x19, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, + 0x06, 0x4d, 0x11, 0x52, 0x3e, 0x64, 0x4f, 0xda, 0xbf, 0x02, 0x1a, 0x9c, 0x67, 0xe9, 0x9d, 0xb1, 0xca, 0xdf, 0x28, + 0x21, 0x4e, 0x14, 0x53, 0x2b, 0xbe, 0x89, 0x12, 0x75, 0x7e, 0x26, 0xda, 0x0d, 0x04, 0x52, 0x7f, 0xc0, 0xa0, 0x1a, + 0x65, 0x98, 0xc0, 0x75, 0x20, 0x8a, 0xcd, 0x89, 0xea, 0x2d, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x01, 0x50, 0xef, 0xd8, + 0xfa, 0x08, 0x68, 0x96, 0xbe, 0x69, 0xad, 0x73, 0x4d, 0x28, 0xb4, 0x13, 0x98, 0x64, 0x90, 0xe4, 0x59, 0x67, 0x98, + 0xa0, 0xda, 0x8c, 0x49, 0xe7, 0x7d, 0x80, 0xee, 0xae, 0x45, 0x5d, 0x7c, 0xd3, 0xb9, 0x83, 0xf6, 0x71, 0xfd, 0x4a, + 0x8b, 0xec, 0xf1, 0xe7, 0x2d, 0x11, 0x16, 0x81, 0xb3, 0x56, 0xe7, 0xab, 0x47, 0x38, 0x30, 0x15, 0x99, 0x86, 0xbd, + 0x44, 0x2a, 0x59, 0xb6, 0xdb, 0x5e, 0x6f, 0xaf, 0x88, 0xab, 0xc7, 0x58, 0xed, 0xdc, 0xcc, 0xcd, 0x9d, 0x6a, 0x5d, + 0xec, 0xde, 0xb4, 0xdd, 0x14, 0x33, 0x6a, 0xad, 0xdd, 0xae, 0x39, 0x21, 0x4f, 0xbe, 0x15, 0xd5, 0x4a, 0x9d, 0xae, + 0x0d, 0xda, 0x21, 0x9e, 0x75, 0x91, 0xc1, 0x8d, 0xf2, 0xb9, 0x15, 0x3a, 0xc9, 0x38, 0xab, 0x56, 0x5d, 0xb0, 0xb9, + 0xe6, 0xf5, 0x52, 0xa4, 0x51, 0x45, 0xd1, 0xe6, 0x3c, 0x2a, 0x68, 0x22, 0xd6, 0x45, 0x1d, 0x89, 0x06, 0xf5, 0xa2, + 0x46, 0x63, 0x80, 0x80, 0x4c, 0xe7, 0xbe, 0x07, 0x55, 0x30, 0x1b, 0x8a, 0x48, 0x4c, 0xdf, 0x83, 0xa5, 0x7d, 0x01, + 0xfb, 0xa2, 0xd9, 0x57, 0x67, 0x8b, 0x6f, 0x75, 0x84, 0x60, 0x12, 0xb3, 0x07, 0xc2, 0xc0, 0xf9, 0xc6, 0x90, 0xd3, + 0x2e, 0x71, 0x99, 0xef, 0x96, 0xb0, 0x87, 0xdb, 0x15, 0xec, 0xc4, 0xce, 0x93, 0xe2, 0xe6, 0x4a, 0x76, 0x52, 0xce, + 0xc7, 0xa0, 0xfd, 0x12, 0xf2, 0xda, 0xa5, 0xb8, 0xf5, 0x78, 0x10, 0xd0, 0x60, 0x50, 0x6a, 0xfe, 0x75, 0xa2, 0x3d, + 0x3c, 0x69, 0x40, 0x90, 0x94, 0x83, 0x8b, 0xb6, 0x63, 0xf8, 0x3e, 0x99, 0x8a, 0x63, 0x8e, 0x16, 0xef, 0xd0, 0xea, + 0x04, 0xa2, 0x78, 0x81, 0xbd, 0x9b, 0x56, 0x15, 0x6a, 0x11, 0x94, 0xa3, 0xe5, 0x2f, 0x64, 0x75, 0x08, 0x28, 0xa4, + 0x7c, 0x45, 0xa1, 0x6c, 0x9d, 0x18, 0xea, 0xe1, 0x17, 0xf3, 0xc9, 0x42, 0xcd, 0xc0, 0x40, 0xcc, 0x8f, 0x16, 0x6a, + 0x16, 0x06, 0x62, 0xfe, 0xd5, 0xa2, 0xb1, 0xeb, 0x40, 0x11, 0x10, 0xc7, 0x85, 0xa3, 0x93, 0xd2, 0xca, 0x6c, 0x01, + 0xdd, 0x3c, 0x44, 0xd0, 0xff, 0x6e, 0x0e, 0x41, 0x2b, 0x17, 0xda, 0x91, 0x1b, 0xd0, 0x76, 0x1c, 0x02, 0x73, 0xc5, + 0xa4, 0x95, 0x0e, 0x40, 0x74, 0xcc, 0xc6, 0x60, 0x88, 0x2d, 0x3f, 0x38, 0x66, 0xe3, 0xa9, 0x4b, 0x82, 0x80, 0xd1, + 0xfd, 0x41, 0x43, 0x82, 0xdf, 0xe1, 0x55, 0xfa, 0x64, 0x83, 0xbe, 0x66, 0xce, 0xdd, 0xd0, 0xb9, 0xb8, 0x82, 0x53, + 0xb5, 0xbd, 0x27, 0xa1, 0x9b, 0x4c, 0x3b, 0x40, 0xaf, 0x26, 0x6e, 0xc8, 0xaf, 0x8c, 0x46, 0xa3, 0x62, 0x64, 0x00, + 0x20, 0x88, 0xe6, 0x1c, 0xfc, 0x9c, 0x86, 0xcb, 0x97, 0xb7, 0x9e, 0x4d, 0x31, 0x02, 0x5a, 0xc8, 0x44, 0xf3, 0x00, + 0x65, 0x55, 0x63, 0x68, 0x86, 0xde, 0x21, 0xc7, 0x0f, 0x0f, 0xbe, 0xce, 0xf8, 0x89, 0xc3, 0xb5, 0x87, 0x73, 0xe1, + 0xba, 0xac, 0x69, 0x99, 0x43, 0xe7, 0xd9, 0xc7, 0xf1, 0x1e, 0xc6, 0xc9, 0xa7, 0x59, 0x28, 0x67, 0xbc, 0xa6, 0xff, + 0x51, 0xe9, 0x7e, 0x87, 0x43, 0x4e, 0x57, 0xb0, 0xe2, 0x66, 0x75, 0xa8, 0xf9, 0x59, 0xe4, 0x8d, 0x23, 0xde, 0x90, + 0xa8, 0xee, 0x3e, 0xef, 0x4d, 0x98, 0xd2, 0x8e, 0x71, 0x00, 0x70, 0xa2, 0x56, 0x0d, 0xbb, 0xd2, 0xb8, 0x56, 0x07, + 0x31, 0x0c, 0x25, 0x6c, 0x95, 0x38, 0xaa, 0xa4, 0xbf, 0x01, 0x08, 0x8b, 0xa1, 0x38, 0xde, 0x1a, 0xd6, 0x07, 0xd8, + 0x0f, 0x55, 0xa0, 0x6e, 0x4e, 0x21, 0x67, 0x00, 0x90, 0x04, 0xdc, 0xd1, 0x53, 0x4d, 0x43, 0x65, 0x9b, 0xe3, 0xa1, + 0x65, 0x74, 0x05, 0x0f, 0xf4, 0xd4, 0x96, 0x0c, 0x8c, 0xab, 0x3c, 0xf6, 0x36, 0xfb, 0xdb, 0xa3, 0x54, 0xe4, 0x3b, + 0x9b, 0xd4, 0x34, 0xab, 0x46, 0x63, 0x1f, 0x47, 0xe8, 0x69, 0x05, 0x68, 0xbd, 0xb6, 0x54, 0xb4, 0xdf, 0x47, 0x31, + 0x6a, 0x5c, 0x4a, 0xb0, 0x0a, 0x1d, 0x09, 0x0e, 0x11, 0x46, 0x08, 0xfd, 0xbe, 0x08, 0x37, 0xae, 0x20, 0x83, 0x28, + 0xb8, 0x16, 0x15, 0x7f, 0xc8, 0xf2, 0xa2, 0x6d, 0xa9, 0xaa, 0x3e, 0x69, 0xda, 0x12, 0x78, 0x1d, 0x0e, 0xb0, 0x9d, + 0x7f, 0xea, 0x89, 0x5c, 0x2b, 0x1b, 0x25, 0x7c, 0x47, 0x5c, 0x0b, 0xa2, 0x9b, 0x46, 0xd7, 0xeb, 0xd9, 0x21, 0x5a, + 0x9a, 0xe2, 0xd0, 0x21, 0xfb, 0xdc, 0x3d, 0xb7, 0x65, 0x7c, 0xfb, 0x09, 0x72, 0xe7, 0x3b, 0x7b, 0x49, 0xc2, 0x20, + 0x6f, 0xd9, 0x40, 0xb1, 0x8e, 0xad, 0xa0, 0x00, 0xa3, 0xb6, 0xfc, 0x05, 0x74, 0x6c, 0x30, 0xa8, 0x09, 0x3e, 0x49, + 0x6c, 0x1b, 0x8f, 0xfc, 0x11, 0xe7, 0x86, 0x0e, 0xaf, 0x0d, 0x79, 0x20, 0x4e, 0x61, 0x9f, 0x28, 0x61, 0xff, 0x82, + 0x82, 0xee, 0x48, 0x2f, 0x57, 0x89, 0xab, 0xe2, 0x01, 0xaa, 0xec, 0x78, 0xae, 0xf9, 0x92, 0x16, 0x5a, 0x69, 0x64, + 0x15, 0x1d, 0x11, 0xb7, 0x60, 0x32, 0x66, 0xab, 0x6a, 0x54, 0x71, 0x2c, 0x50, 0xa4, 0x63, 0xce, 0x76, 0x0e, 0xd6, + 0x00, 0x78, 0x0a, 0x9b, 0x8b, 0x33, 0x2c, 0x28, 0xed, 0xb2, 0xa5, 0x2f, 0x81, 0x55, 0xf3, 0x30, 0xce, 0xcb, 0x8e, + 0x2f, 0x77, 0x47, 0xdb, 0x7b, 0xe8, 0x8d, 0xe8, 0x8d, 0xd7, 0xe7, 0x51, 0xd3, 0xcf, 0x9e, 0xe1, 0xda, 0x50, 0x90, + 0x07, 0x9a, 0xea, 0x10, 0x46, 0x8b, 0xc0, 0x34, 0xe5, 0x27, 0x6c, 0x3c, 0x1d, 0x0e, 0x35, 0x19, 0x74, 0x9a, 0x89, + 0xf1, 0xbf, 0x3e, 0x83, 0xd6, 0xe9, 0x89, 0xf3, 0x3e, 0x6d, 0x5f, 0x41, 0xeb, 0x3b, 0x94, 0xc9, 0x9d, 0x83, 0xe1, + 0x03, 0x2d, 0x98, 0x84, 0xa9, 0xc2, 0x1b, 0x22, 0x15, 0xec, 0xcd, 0xd2, 0x38, 0xec, 0x9b, 0x85, 0x42, 0x4b, 0x45, + 0xfc, 0x6a, 0x4d, 0xfc, 0xe4, 0x75, 0xe6, 0xdf, 0xa6, 0x7d, 0x72, 0x10, 0x4b, 0x43, 0x62, 0x24, 0xe2, 0x17, 0xa7, + 0xd2, 0x76, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x64, 0xec, 0x49, 0x8d, 0xa7, 0x86, 0xfb, 0x5e, 0xc7, + 0xac, 0xc3, 0x2c, 0x76, 0xb3, 0x46, 0x42, 0x61, 0x9c, 0x9a, 0xe0, 0x94, 0x62, 0x15, 0xc9, 0xe8, 0x78, 0xa6, 0x30, + 0x88, 0x2a, 0x29, 0x21, 0xd6, 0x94, 0xad, 0x85, 0x89, 0x5d, 0x67, 0x0b, 0x53, 0xd4, 0x45, 0xa8, 0x37, 0x03, 0x9d, + 0x05, 0x0d, 0xf9, 0x1d, 0x1a, 0xad, 0xa8, 0x9a, 0x04, 0x0c, 0xe3, 0x28, 0xd5, 0xf8, 0xb7, 0x08, 0xb5, 0x1e, 0x06, + 0x00, 0xb6, 0x79, 0x27, 0xb2, 0xa2, 0x7e, 0x55, 0x20, 0x04, 0x9a, 0xb5, 0x9f, 0x2a, 0xeb, 0x9d, 0x59, 0xd0, 0x8a, + 0x76, 0x73, 0xe5, 0x73, 0x81, 0x13, 0xaa, 0x53, 0x79, 0x81, 0x7a, 0x29, 0xca, 0xd7, 0x22, 0xe5, 0xad, 0xb8, 0x98, + 0x07, 0x82, 0x7d, 0xc8, 0x47, 0x70, 0x5e, 0xa1, 0x53, 0xb9, 0xde, 0x26, 0xd2, 0x2c, 0x49, 0x30, 0x16, 0x68, 0x9b, + 0x97, 0x60, 0x26, 0x14, 0x33, 0x86, 0x5f, 0x43, 0x70, 0xb1, 0x9d, 0x93, 0x70, 0xb3, 0x9f, 0x07, 0x86, 0xd0, 0xe4, + 0x55, 0x4b, 0x34, 0x6c, 0xec, 0x78, 0x1d, 0xb9, 0x26, 0xdc, 0x87, 0xb5, 0x58, 0x93, 0x31, 0xc6, 0x95, 0xb9, 0x91, + 0xf1, 0xa3, 0x05, 0x1e, 0x8c, 0x49, 0xeb, 0x4f, 0x20, 0xd3, 0x52, 0xca, 0x3a, 0x5f, 0x68, 0x31, 0x93, 0x4c, 0x74, + 0x6e, 0xdf, 0xf8, 0x2c, 0xef, 0x22, 0xf2, 0xb7, 0xf2, 0x7b, 0x92, 0x0f, 0xf7, 0xee, 0x83, 0xc4, 0x1a, 0x94, 0x46, + 0x5c, 0x5a, 0x94, 0xa7, 0x0f, 0x74, 0xdd, 0xa4, 0x88, 0xd3, 0xf3, 0x55, 0x5c, 0x56, 0x3c, 0x85, 0x4a, 0x15, 0x75, + 0x8b, 0x7a, 0x13, 0xb0, 0x37, 0x44, 0x92, 0x64, 0x2c, 0x8d, 0x8d, 0xd8, 0xc5, 0x23, 0x3d, 0x7b, 0xc3, 0x2c, 0xbd, + 0xac, 0xd1, 0x90, 0x96, 0x3a, 0x67, 0xa1, 0x94, 0xf9, 0x4b, 0xfe, 0x33, 0x68, 0x24, 0xe8, 0xa8, 0x4f, 0x31, 0x9e, + 0x01, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x08, 0x4a, 0xb3, 0x23, 0x76, 0xfc, 0xd4, 0xe4, 0xe1, 0x5d, + 0xc8, 0x3a, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0xa8, 0x1a, 0xc9, 0x19, 0x40, 0xd3, 0x41, 0x91, 0xf3, 0xb8, + 0x08, 0x66, 0x3d, 0x9d, 0x18, 0xf5, 0xb8, 0xfa, 0x05, 0x1a, 0x6a, 0xb7, 0x59, 0x59, 0x9e, 0xd5, 0xf7, 0x9f, 0xc3, + 0x81, 0x4d, 0x4d, 0x05, 0x3d, 0xde, 0xd4, 0xe2, 0xea, 0x4a, 0x76, 0xdb, 0x2d, 0x44, 0xcb, 0xe9, 0xbc, 0x6b, 0xe9, + 0xbc, 0x5e, 0xb0, 0x5e, 0x77, 0xba, 0x5e, 0xdc, 0x7e, 0x19, 0x1e, 0xc2, 0xda, 0xce, 0x27, 0x8a, 0x3f, 0xf3, 0xdb, + 0xee, 0xe2, 0x2d, 0x54, 0xb3, 0x00, 0x00, 0xd2, 0x83, 0x28, 0x58, 0x66, 0x29, 0x0f, 0xa8, 0xd8, 0xc7, 0x51, 0x96, + 0x52, 0x2f, 0x67, 0x18, 0x3f, 0x65, 0x1a, 0x6b, 0x9c, 0x15, 0xaa, 0xd0, 0xd8, 0xe8, 0x4e, 0x57, 0x19, 0x62, 0xfb, + 0x09, 0x9c, 0x2d, 0xc0, 0xfd, 0xd1, 0x43, 0xa1, 0xee, 0x4d, 0x5a, 0x9a, 0xa8, 0xf9, 0xae, 0x3d, 0x83, 0x8c, 0xe2, + 0x64, 0x95, 0x57, 0xd0, 0x8d, 0x3a, 0x6b, 0xa3, 0x4a, 0xdf, 0x43, 0xd4, 0xab, 0x18, 0x3c, 0xca, 0x5d, 0x5e, 0x1b, + 0x9d, 0x4c, 0x8b, 0x48, 0xb9, 0xf3, 0x93, 0x66, 0x99, 0xa5, 0x4a, 0x87, 0xed, 0x32, 0xec, 0xad, 0x31, 0xe9, 0x4d, + 0x48, 0x03, 0x23, 0xf1, 0xe9, 0x8c, 0x0a, 0x21, 0xa0, 0x2d, 0xc7, 0xdf, 0xe1, 0x33, 0x34, 0x4d, 0x81, 0xa5, 0x8a, + 0x5b, 0xd8, 0x0e, 0x9f, 0xff, 0x64, 0xd4, 0x02, 0x10, 0xc1, 0xca, 0xd5, 0xbb, 0x38, 0x25, 0x34, 0xe7, 0xca, 0x0c, + 0x00, 0x59, 0x50, 0xca, 0x2d, 0x3f, 0x25, 0xd3, 0xc1, 0x12, 0x45, 0xd9, 0xcb, 0xa9, 0x1b, 0x1d, 0x1b, 0x3f, 0xa4, + 0xe7, 0x02, 0xb6, 0x0b, 0xf9, 0xad, 0xbd, 0x7a, 0x89, 0x9a, 0x34, 0xa6, 0x59, 0x0f, 0xf0, 0xe5, 0x1a, 0x4d, 0x42, + 0x0b, 0xca, 0xa4, 0x29, 0x80, 0xc6, 0x4d, 0xd5, 0x0a, 0x26, 0xa5, 0x46, 0xc2, 0x96, 0x3a, 0x92, 0x65, 0xdf, 0x07, + 0xa7, 0xde, 0x23, 0xe8, 0x01, 0xf3, 0x08, 0xf4, 0xf4, 0x5f, 0xba, 0x6a, 0xff, 0x92, 0xa3, 0x93, 0xab, 0x26, 0x6a, + 0xfa, 0xbd, 0xb2, 0x23, 0x43, 0xca, 0xa5, 0x19, 0x08, 0x26, 0x1d, 0xf3, 0xd4, 0xd8, 0x3a, 0x46, 0x44, 0x0f, 0x9c, + 0x7d, 0xba, 0x5b, 0x4d, 0x2d, 0x00, 0xd1, 0xf1, 0xeb, 0x27, 0xaf, 0xae, 0xe3, 0x2b, 0x8d, 0xa2, 0xe4, 0x59, 0xc4, + 0x48, 0xd3, 0xbe, 0x5a, 0xc0, 0xe0, 0xfd, 0xf2, 0xfe, 0x27, 0x99, 0xa5, 0x71, 0x7b, 0xb0, 0x31, 0xa2, 0xaa, 0x5f, + 0x2a, 0x5e, 0xfa, 0x02, 0xac, 0x7d, 0x96, 0x28, 0x90, 0xfb, 0xbd, 0x49, 0xd3, 0xdf, 0x44, 0xde, 0xcd, 0x86, 0xf5, + 0xc6, 0x4d, 0xbb, 0xd4, 0x96, 0xec, 0xc8, 0x48, 0xe4, 0xf4, 0x62, 0xd0, 0xe3, 0x47, 0x2b, 0x8d, 0xd2, 0xb0, 0x41, + 0x55, 0x2a, 0x7e, 0xaf, 0x45, 0x70, 0xf2, 0x58, 0x95, 0x18, 0xd3, 0x80, 0xd9, 0x56, 0x36, 0x0a, 0xd4, 0x41, 0x2a, + 0x6d, 0x75, 0x14, 0xb6, 0xdf, 0x58, 0x49, 0xf5, 0xef, 0x7f, 0x6a, 0x43, 0x3e, 0x5f, 0x0a, 0x2a, 0x08, 0xd8, 0x19, + 0x78, 0x3d, 0x95, 0xc2, 0x40, 0x2a, 0xd8, 0x49, 0x05, 0x28, 0x5f, 0x44, 0x8e, 0xd5, 0x6e, 0x5f, 0xad, 0x1a, 0xa3, + 0x2d, 0x20, 0x34, 0x90, 0x1e, 0x5d, 0xf6, 0x71, 0x1b, 0xe3, 0x40, 0xe2, 0xc0, 0x09, 0xb6, 0x73, 0x75, 0x8d, 0x46, + 0x42, 0xf3, 0x87, 0x46, 0x03, 0x5e, 0xd3, 0x1a, 0x14, 0xea, 0x39, 0x8e, 0x86, 0xca, 0x0e, 0x29, 0x88, 0xd8, 0xa0, + 0x84, 0x7d, 0x7b, 0x3e, 0xd4, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x43, 0x85, 0xfd, 0xdc, 0x2e, 0x21, 0x63, 0xd5, 0x21, + 0xad, 0x3c, 0xc0, 0xf1, 0x42, 0xca, 0xfc, 0x2d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x6d, 0xc4, 0x02, 0x96, 0x04, 0xed, + 0xf5, 0x40, 0xdd, 0x32, 0x08, 0x75, 0x4c, 0x4f, 0x04, 0x3e, 0xa5, 0x5c, 0x7e, 0x5a, 0x92, 0x66, 0x5a, 0x32, 0x0b, + 0x7a, 0xe9, 0x5a, 0xf9, 0x15, 0xde, 0x47, 0xbb, 0x7b, 0x57, 0x5f, 0x58, 0xc7, 0x10, 0x0c, 0xbb, 0x72, 0x9b, 0xd3, + 0x50, 0x00, 0x36, 0x3c, 0x55, 0x65, 0xb9, 0x46, 0x4d, 0x64, 0x16, 0x87, 0x24, 0x02, 0xc9, 0xb6, 0xbf, 0xb9, 0xb5, + 0x60, 0xdb, 0x59, 0xa8, 0x9e, 0xfa, 0xcb, 0xd9, 0xee, 0x7b, 0x86, 0x97, 0x3b, 0x72, 0x6f, 0xdf, 0x86, 0xf2, 0x87, + 0xfd, 0xab, 0xe4, 0xff, 0xaa, 0x92, 0xfd, 0x56, 0x99, 0x4d, 0x5b, 0xbc, 0xdf, 0x75, 0xdc, 0x72, 0x8c, 0x06, 0x81, + 0x35, 0x05, 0x1a, 0xd2, 0x93, 0xc6, 0x34, 0x51, 0x21, 0x95, 0x19, 0xd3, 0x78, 0x74, 0x01, 0x9a, 0xc3, 0x74, 0x9e, + 0xc7, 0x00, 0x1c, 0xe0, 0x1e, 0x79, 0x84, 0xba, 0xa7, 0xf3, 0x3c, 0x38, 0x0f, 0x06, 0xc5, 0x20, 0x50, 0x9f, 0xd8, + 0xe6, 0x04, 0x0b, 0xd0, 0xb9, 0xc5, 0x0c, 0x82, 0x4d, 0x1a, 0x33, 0x87, 0xf8, 0x38, 0x99, 0x0e, 0x06, 0x31, 0xd9, + 0x00, 0x48, 0x5f, 0xbc, 0x30, 0xce, 0x41, 0xa5, 0x5a, 0x90, 0xad, 0xba, 0x4b, 0xbf, 0x62, 0xa7, 0xda, 0x69, 0xde, + 0xef, 0xe7, 0xf3, 0x62, 0x10, 0x78, 0x15, 0x96, 0xda, 0xfb, 0x8f, 0xfa, 0x5f, 0x6a, 0x9d, 0x34, 0xc1, 0x30, 0xb5, + 0xa7, 0xa8, 0x5e, 0x71, 0x34, 0xa3, 0xde, 0xed, 0x58, 0x2a, 0x5f, 0x40, 0x14, 0x0f, 0x0c, 0x59, 0x2b, 0xef, 0xce, + 0xc1, 0x6b, 0x73, 0xe3, 0xcd, 0x11, 0x05, 0xd8, 0xbe, 0x30, 0x4e, 0x28, 0x2e, 0xba, 0x6c, 0x88, 0x63, 0xb0, 0xd3, + 0xd5, 0x5b, 0x81, 0x56, 0xe3, 0xbd, 0x78, 0xd7, 0x6c, 0xfc, 0x8d, 0x38, 0x50, 0x65, 0x1e, 0x5c, 0x02, 0xe2, 0xec, + 0x41, 0x5c, 0x1f, 0x60, 0xa9, 0x07, 0xc1, 0xc0, 0x20, 0x87, 0xb4, 0xab, 0x55, 0x43, 0x11, 0xc9, 0xf3, 0x18, 0x0c, + 0x98, 0x74, 0x43, 0x1a, 0x32, 0xed, 0x95, 0x12, 0xd2, 0xc6, 0x58, 0x0b, 0x28, 0xc3, 0xe1, 0x6a, 0xc7, 0x6e, 0xd8, + 0x9e, 0x6e, 0x1d, 0x0a, 0x25, 0x8c, 0x5e, 0xdd, 0xf8, 0x87, 0x9a, 0xe7, 0x89, 0xa0, 0x06, 0x55, 0x6b, 0x3f, 0x1d, + 0x94, 0x27, 0xe5, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0xa2, 0xc0, 0x8b, 0xf6, 0x0e, 0xf2, 0x9c, 0xfe, 0x54, 0xfa, + 0x20, 0x7a, 0x6e, 0x19, 0x2e, 0xb4, 0x8f, 0x6b, 0x05, 0x32, 0x69, 0x3a, 0x9a, 0xda, 0xda, 0x1d, 0xde, 0x31, 0x81, + 0x7e, 0x53, 0x96, 0x52, 0x26, 0xba, 0x96, 0x25, 0x3b, 0xe9, 0xe5, 0xd2, 0x1b, 0x2a, 0x65, 0x27, 0xcb, 0x36, 0xe7, + 0x97, 0x7a, 0x09, 0xfd, 0xbe, 0x72, 0x07, 0xc2, 0x37, 0x72, 0xbd, 0x21, 0x2f, 0x1b, 0x22, 0x96, 0x43, 0xcc, 0xc0, + 0xf1, 0x42, 0x48, 0xd7, 0xee, 0xd2, 0x57, 0xd5, 0xed, 0x6c, 0xe5, 0x92, 0x16, 0x78, 0x2b, 0x05, 0x56, 0x91, 0x5a, + 0xbd, 0x9e, 0x4c, 0xdc, 0xf7, 0x51, 0x6c, 0x3e, 0x02, 0xb6, 0xd1, 0x3b, 0x1a, 0xbd, 0x5b, 0xc4, 0x06, 0x5f, 0x45, + 0x35, 0x2d, 0x39, 0x40, 0x70, 0xb7, 0x25, 0xb5, 0x34, 0xb3, 0x88, 0xfb, 0x92, 0x07, 0x68, 0xdf, 0xc5, 0xe1, 0x4c, + 0x2a, 0xc1, 0xb6, 0xae, 0x75, 0xce, 0x2a, 0x39, 0xa0, 0x9f, 0xe8, 0xf8, 0xa7, 0xd5, 0xa3, 0x22, 0x86, 0x55, 0x36, + 0x92, 0x56, 0x68, 0x0f, 0x4a, 0x97, 0x70, 0xf1, 0x05, 0x78, 0xd9, 0xde, 0xaf, 0xec, 0x3e, 0x5f, 0x62, 0xff, 0x30, + 0xaf, 0x9c, 0xe0, 0x91, 0xd3, 0x78, 0x73, 0x0f, 0xab, 0x3e, 0x57, 0x0a, 0xe1, 0x54, 0x4a, 0x43, 0x01, 0xc0, 0x20, + 0x09, 0x6a, 0xb8, 0xd2, 0xb6, 0x19, 0xa4, 0x34, 0x86, 0xdd, 0xad, 0xde, 0xe8, 0xff, 0x94, 0x0a, 0x17, 0xa0, 0x94, + 0x0d, 0xdc, 0x90, 0x75, 0xaa, 0xe5, 0x3a, 0xa6, 0xe0, 0xf9, 0x2e, 0x39, 0x02, 0x85, 0x1d, 0x18, 0x99, 0xd1, 0x84, + 0xfd, 0x82, 0xb7, 0xa1, 0x9c, 0xbd, 0x34, 0x92, 0x27, 0xbb, 0x2f, 0x69, 0x45, 0x13, 0x32, 0xad, 0xcc, 0xfe, 0x6d, + 0x6d, 0xd8, 0xe7, 0xa1, 0x18, 0x89, 0x02, 0x17, 0x07, 0x9d, 0x03, 0xd8, 0x1f, 0xe4, 0xd2, 0x36, 0x9f, 0x49, 0xbf, + 0x2f, 0xdf, 0x3f, 0xcb, 0xb3, 0xe4, 0xe3, 0xce, 0x7b, 0xcd, 0xd3, 0x2c, 0x19, 0x50, 0x89, 0x98, 0x1a, 0x57, 0xc5, + 0x70, 0xa9, 0x5c, 0x8c, 0x3d, 0x92, 0x11, 0xef, 0xa5, 0x0e, 0x31, 0x62, 0x7c, 0x91, 0x1d, 0x92, 0x92, 0xd3, 0x65, + 0xd3, 0xd9, 0x73, 0x25, 0x9a, 0x41, 0x63, 0xb8, 0x1d, 0xef, 0x25, 0xb5, 0x02, 0x64, 0x54, 0xe8, 0x9e, 0x01, 0xae, + 0xe1, 0xfe, 0x92, 0xf0, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xd8, 0x2b, 0x13, 0x12, 0x72, 0xe3, 0x00, 0x8b, 0xd8, 0x34, + 0x1f, 0x43, 0x01, 0x40, 0xad, 0x1a, 0xe9, 0x95, 0xbe, 0x24, 0x54, 0x26, 0x21, 0x18, 0x5d, 0x91, 0xf0, 0x2a, 0xa0, + 0x71, 0xa6, 0x13, 0x0d, 0x6c, 0x70, 0x40, 0x9f, 0xd7, 0x3a, 0x51, 0xdb, 0x90, 0x07, 0xb4, 0x36, 0x69, 0x00, 0x83, + 0x0f, 0x92, 0x24, 0xfa, 0x6a, 0xa9, 0x93, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x73, 0xe1, 0xf8, 0x58, 0x82, 0xff, + 0x91, 0x26, 0x82, 0x3f, 0x84, 0x02, 0x64, 0x8a, 0xaa, 0x62, 0x9a, 0xb1, 0x93, 0xac, 0xdb, 0x98, 0xc4, 0xf1, 0xb4, + 0xbb, 0x2b, 0xa5, 0x4b, 0x17, 0xf8, 0x95, 0x65, 0x88, 0x63, 0xfd, 0x2c, 0x5e, 0xb1, 0xd3, 0x90, 0x2b, 0xbc, 0xf4, + 0x67, 0xf1, 0x0a, 0x67, 0x88, 0xd6, 0xad, 0x04, 0x22, 0xfd, 0x57, 0x4d, 0xe0, 0x10, 0xfb, 0x09, 0x06, 0xb9, 0xa8, + 0x9d, 0x07, 0x02, 0x79, 0x5b, 0x41, 0x44, 0xfc, 0xec, 0x2a, 0x8c, 0x48, 0xbd, 0x93, 0xa4, 0xbf, 0xfc, 0x51, 0x64, + 0x85, 0xf3, 0x0d, 0x3c, 0xfa, 0xcd, 0x32, 0x29, 0xfa, 0x0b, 0x19, 0xcc, 0xc1, 0x7e, 0x22, 0xe3, 0x52, 0xd4, 0xee, + 0x13, 0x76, 0xc1, 0x89, 0xf1, 0xe0, 0xf4, 0x1a, 0x01, 0xf6, 0x6b, 0xf7, 0xc9, 0x19, 0xb3, 0xbf, 0x8c, 0x1b, 0x5f, + 0xa6, 0x23, 0x3e, 0xf0, 0xd1, 0x1d, 0xe5, 0xa3, 0x7b, 0x27, 0xd3, 0x1f, 0x1e, 0x94, 0xc8, 0xa8, 0xaa, 0xf9, 0x6a, + 0xc5, 0xd3, 0xd9, 0x5d, 0x12, 0x65, 0xa3, 0x9a, 0x17, 0x30, 0xbd, 0xe0, 0x78, 0x97, 0xac, 0x2f, 0xb2, 0xe4, 0x15, + 0xc4, 0x1e, 0x58, 0x09, 0x89, 0xc5, 0x0f, 0xcb, 0x4c, 0x2e, 0xe6, 0x42, 0xd4, 0xa2, 0xe0, 0xc1, 0xec, 0x26, 0x89, + 0xfe, 0x5a, 0x3a, 0x48, 0x6a, 0x7a, 0xca, 0x36, 0x8d, 0x25, 0xd4, 0xda, 0xd7, 0x91, 0x6e, 0x94, 0x05, 0x00, 0xdc, + 0xb3, 0x8b, 0x34, 0x12, 0xac, 0x1a, 0x4e, 0x1a, 0xc6, 0x75, 0x7a, 0x89, 0xa9, 0x71, 0xc3, 0x6a, 0x9a, 0x58, 0x0b, + 0x19, 0xd0, 0xfb, 0x03, 0x5e, 0x0e, 0x3e, 0x67, 0x45, 0x28, 0xa4, 0x35, 0x70, 0x71, 0x5c, 0xf6, 0xfb, 0xe2, 0xb8, + 0xdc, 0x6e, 0x8b, 0x93, 0xb8, 0xdf, 0x17, 0x27, 0xb1, 0xe6, 0x1f, 0xa4, 0x62, 0x5b, 0x9b, 0x1b, 0x24, 0x34, 0x17, + 0x10, 0xb5, 0x68, 0x04, 0x7f, 0x68, 0x96, 0xf3, 0x22, 0xca, 0x8f, 0x93, 0x7e, 0xbf, 0xb7, 0x9c, 0x55, 0x83, 0x7c, + 0x98, 0x44, 0xf9, 0x30, 0x71, 0x9c, 0x10, 0x7f, 0x75, 0x9c, 0x10, 0x25, 0x0d, 0x5c, 0xc1, 0x99, 0x01, 0x88, 0x02, + 0x2e, 0xfd, 0xa3, 0xaa, 0x96, 0x52, 0xd5, 0x12, 0xcb, 0x5a, 0x12, 0x55, 0x41, 0xc3, 0x6e, 0xca, 0xb0, 0xc0, 0x52, + 0xe8, 0x92, 0xfd, 0xb1, 0x04, 0x9e, 0x28, 0xe7, 0xf5, 0x06, 0x18, 0xd8, 0x08, 0xef, 0x1c, 0x3a, 0x9c, 0xc4, 0xba, + 0x61, 0x12, 0x32, 0xe9, 0x92, 0xae, 0xe8, 0x15, 0xf2, 0xb3, 0x97, 0x60, 0xb0, 0x74, 0xcc, 0xf2, 0xe9, 0x60, 0x70, + 0x49, 0x56, 0xac, 0x98, 0x87, 0xf1, 0x20, 0x5c, 0xcf, 0xf2, 0xe1, 0x65, 0x74, 0x49, 0xc8, 0x17, 0xe5, 0x82, 0xf6, + 0x56, 0xa3, 0xea, 0x63, 0x06, 0xc1, 0xfd, 0xd2, 0x59, 0x98, 0xe9, 0x38, 0x1f, 0xab, 0xd1, 0x1d, 0x5d, 0x41, 0xfc, + 0x1a, 0xb8, 0x91, 0x90, 0x08, 0x3a, 0x72, 0x45, 0x57, 0x74, 0x4d, 0x85, 0x9e, 0x61, 0x0c, 0xd1, 0x6d, 0x8e, 0x93, + 0x04, 0x1c, 0x93, 0x6d, 0xf1, 0xd1, 0x58, 0x16, 0xde, 0xf5, 0x1d, 0xa1, 0xbd, 0x5e, 0x62, 0x07, 0xe9, 0xbb, 0xf6, + 0x20, 0x01, 0x23, 0x32, 0x92, 0x03, 0xa5, 0x47, 0x46, 0x50, 0x3d, 0xa9, 0x38, 0x24, 0xb1, 0x3b, 0x24, 0x72, 0x1c, + 0x12, 0x77, 0x1c, 0x72, 0x35, 0x0e, 0xc8, 0xdd, 0x2f, 0xd9, 0x98, 0xa6, 0x6c, 0x4c, 0xd7, 0x72, 0x54, 0xe8, 0x35, + 0xbd, 0x50, 0xd4, 0xf1, 0x9c, 0xbd, 0x86, 0x03, 0x7b, 0x10, 0xe6, 0xb3, 0x78, 0xf8, 0x3a, 0x7a, 0x4d, 0xc8, 0x17, + 0x82, 0xde, 0xc8, 0x4b, 0x19, 0x84, 0x41, 0xbc, 0x06, 0xe7, 0x52, 0x1b, 0xea, 0xe4, 0x5a, 0xef, 0x38, 0x7c, 0xba, + 0xf2, 0x9e, 0x2e, 0x20, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x25, 0x2b, 0xe6, 0xe7, 0xe1, 0x98, 0x00, 0x0e, + 0x8f, 0x1a, 0xce, 0xcb, 0xd1, 0x1d, 0xbd, 0x1c, 0xdd, 0x13, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0xc7, 0x2c, 0x9e, 0x0e, + 0x06, 0x6b, 0xa4, 0xea, 0x32, 0xf7, 0x9a, 0x2c, 0xe8, 0x25, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x2b, 0xd6, 0x9a, 0x86, + 0xbf, 0x66, 0xf0, 0xf1, 0x3d, 0xbb, 0x1c, 0xdd, 0xd3, 0x3b, 0xf6, 0x7a, 0x3b, 0x9e, 0x02, 0x33, 0xb5, 0x9a, 0x85, + 0xf7, 0xc7, 0x57, 0xb3, 0x2b, 0x76, 0x1f, 0xdd, 0x9f, 0x40, 0x43, 0xaf, 0xd9, 0x3d, 0x02, 0x2e, 0xa5, 0x8f, 0x97, + 0x83, 0xd7, 0xe4, 0x70, 0x30, 0x48, 0x49, 0x14, 0xde, 0x84, 0x4e, 0x2b, 0x5f, 0xd3, 0x7b, 0x42, 0x57, 0xec, 0x0e, + 0x47, 0xe3, 0x8a, 0xe1, 0x07, 0x17, 0xec, 0xbe, 0xb9, 0x09, 0x9d, 0xdd, 0x1c, 0x57, 0x9d, 0x20, 0x46, 0xe8, 0x6b, + 0x60, 0x69, 0x96, 0x0d, 0x33, 0x01, 0x4f, 0xfa, 0x22, 0xa3, 0x44, 0xa1, 0x19, 0x88, 0xb3, 0x12, 0x10, 0x4b, 0xa2, + 0xee, 0x37, 0x1b, 0x9d, 0xc3, 0x72, 0xee, 0xf7, 0x7b, 0xb5, 0xa6, 0x07, 0x88, 0x9c, 0xd9, 0x49, 0x0f, 0x7a, 0x2e, + 0x3d, 0xc0, 0x4f, 0xd4, 0xaa, 0x41, 0x9c, 0xcc, 0xef, 0x96, 0xd1, 0xaf, 0x0e, 0x7d, 0xf8, 0xa1, 0x9b, 0xf2, 0x54, + 0xf9, 0xbf, 0x4f, 0x79, 0x8a, 0x3c, 0x7a, 0x5d, 0x3b, 0x20, 0x78, 0xce, 0x9a, 0x94, 0x1a, 0x89, 0x7a, 0x74, 0xbe, + 0x8a, 0x41, 0x1b, 0x89, 0xda, 0x06, 0xf5, 0x84, 0x16, 0x56, 0x10, 0x21, 0xe7, 0xe8, 0x39, 0x18, 0xa4, 0x42, 0xa8, + 0x1c, 0xb9, 0x28, 0xd1, 0x10, 0x24, 0x17, 0x15, 0x97, 0xe1, 0x73, 0x08, 0x95, 0xa7, 0x8f, 0x35, 0x11, 0xd6, 0xf4, + 0x18, 0x0c, 0xb0, 0x2d, 0xfc, 0xdb, 0x0e, 0xb9, 0xa8, 0xf8, 0x15, 0x9e, 0xcd, 0x6d, 0x82, 0x51, 0xb2, 0xb8, 0x15, + 0xda, 0x06, 0xb1, 0x1f, 0x0b, 0x82, 0xf5, 0x08, 0x1a, 0x8f, 0x2a, 0x7d, 0x44, 0xb8, 0x51, 0x7c, 0x24, 0x3d, 0x8d, + 0x35, 0x89, 0xe4, 0x48, 0x22, 0xf9, 0x00, 0x08, 0x27, 0x41, 0x7f, 0x71, 0xdb, 0x64, 0xdb, 0x42, 0xa2, 0xd1, 0x9f, + 0x96, 0x4c, 0xc9, 0xee, 0x65, 0x8f, 0x5d, 0x45, 0x90, 0x3d, 0xa6, 0xff, 0x74, 0xfa, 0xf0, 0xcf, 0x25, 0xce, 0xa0, + 0xf1, 0x7c, 0x91, 0x9d, 0x99, 0x39, 0x83, 0x1b, 0x39, 0x5d, 0x56, 0xae, 0xcb, 0x97, 0xfc, 0x80, 0xdf, 0xd5, 0xbc, + 0x48, 0xab, 0x83, 0x9f, 0xeb, 0x36, 0x9e, 0x53, 0xb5, 0x5e, 0xd9, 0x38, 0x2b, 0xd2, 0x38, 0xd5, 0x91, 0xba, 0x68, + 0x6b, 0x58, 0xcf, 0xef, 0x11, 0x75, 0x25, 0x2d, 0x47, 0x4f, 0x21, 0x56, 0x7e, 0xca, 0xe5, 0x3a, 0xcf, 0x7f, 0xda, + 0x49, 0xc5, 0x29, 0xf6, 0x53, 0x90, 0x2a, 0xb5, 0x5c, 0x40, 0xd5, 0x1c, 0xb5, 0xdc, 0x2d, 0xf5, 0x0e, 0xb0, 0x6e, + 0x9b, 0xf2, 0x63, 0x69, 0x76, 0xe1, 0x24, 0x7b, 0xf7, 0x27, 0x5d, 0x86, 0x01, 0xa3, 0x50, 0x66, 0xd5, 0xb5, 0xb2, + 0x2f, 0x34, 0x4e, 0xc3, 0x70, 0xe5, 0xc7, 0x0b, 0x48, 0x17, 0x30, 0x8e, 0x13, 0x25, 0x13, 0xe3, 0xf6, 0xa8, 0xad, + 0x50, 0x7d, 0xce, 0x56, 0x20, 0x60, 0xae, 0xe1, 0xec, 0xba, 0x8e, 0xb6, 0x3b, 0xe2, 0x94, 0x51, 0xb5, 0x8a, 0x8b, + 0xef, 0xe3, 0x55, 0x35, 0xb3, 0x43, 0x1b, 0xf9, 0x63, 0x3a, 0xfd, 0x7b, 0x12, 0xba, 0x85, 0x50, 0xb8, 0xe5, 0x16, + 0x46, 0x9e, 0xdc, 0x1e, 0x96, 0x71, 0x83, 0x5e, 0x89, 0x2b, 0xd5, 0x37, 0x2d, 0x85, 0x54, 0x23, 0x5f, 0xfb, 0x02, + 0x7a, 0x3d, 0xf6, 0x7e, 0x2a, 0xcc, 0xdb, 0x9e, 0x31, 0x97, 0x08, 0x56, 0xb2, 0xec, 0xf6, 0x9d, 0x1a, 0x53, 0x31, + 0x83, 0x2e, 0xb6, 0x9d, 0x45, 0xa7, 0x1b, 0xf9, 0xa7, 0x99, 0xfb, 0x65, 0xde, 0xe1, 0xae, 0xa8, 0xde, 0x02, 0x17, + 0x9a, 0x95, 0x55, 0xdd, 0x96, 0x0d, 0x9b, 0xc6, 0x6b, 0x59, 0x28, 0x36, 0xc0, 0xb0, 0xe7, 0xae, 0x85, 0x07, 0x88, + 0x9b, 0x70, 0xcf, 0x2e, 0x1a, 0xb8, 0x31, 0x7c, 0x5e, 0x49, 0xae, 0x2b, 0x8d, 0xbe, 0xf4, 0xc9, 0xd2, 0xaa, 0xe1, + 0x64, 0x31, 0xe2, 0x45, 0xba, 0x68, 0x32, 0xb3, 0x16, 0x3e, 0xe1, 0x65, 0x38, 0xe7, 0x0b, 0xad, 0x9b, 0x52, 0xa5, + 0x97, 0x2c, 0x56, 0x9d, 0xde, 0xac, 0x14, 0x56, 0x4a, 0xc4, 0x8d, 0x59, 0x26, 0x50, 0x96, 0xa2, 0x91, 0xc2, 0x9b, + 0xb2, 0x65, 0x2b, 0xa9, 0xe5, 0x3d, 0x73, 0x70, 0x1f, 0xfb, 0x01, 0x31, 0x91, 0x75, 0x60, 0x52, 0x34, 0x74, 0x40, + 0xbb, 0xea, 0xd2, 0x35, 0xa3, 0x1e, 0x0c, 0x72, 0x43, 0x12, 0xb1, 0x82, 0x14, 0x2b, 0x58, 0x37, 0xac, 0x9c, 0xe7, + 0x0b, 0x7a, 0xc9, 0xc4, 0x3c, 0x5d, 0xd0, 0x15, 0x13, 0xf3, 0x35, 0xde, 0x84, 0x2e, 0xe1, 0x84, 0x24, 0x9b, 0x58, + 0x2a, 0x60, 0x2f, 0xf1, 0xf2, 0x86, 0x67, 0xaa, 0xa2, 0x65, 0x57, 0x92, 0x03, 0x8c, 0x2f, 0xaa, 0x30, 0x2c, 0x86, + 0x97, 0x60, 0x2d, 0x71, 0x18, 0xae, 0xe6, 0x7c, 0x21, 0x7f, 0x43, 0xc0, 0xf9, 0x24, 0x94, 0xec, 0x82, 0xd9, 0x0b, + 0x64, 0x7a, 0x3d, 0xe7, 0x0b, 0x39, 0x12, 0xaa, 0xe0, 0x6b, 0x63, 0x6c, 0x12, 0x3b, 0x82, 0x96, 0x59, 0x3c, 0x1f, + 0x2f, 0xa2, 0xb8, 0x81, 0x65, 0x78, 0x26, 0x67, 0xa6, 0x25, 0xff, 0xd1, 0x76, 0x52, 0xea, 0x06, 0x2b, 0xc9, 0x1f, + 0x1e, 0x1f, 0x5d, 0x02, 0x19, 0x33, 0xbb, 0x82, 0xe9, 0x0f, 0x5d, 0x1f, 0x19, 0xdc, 0x73, 0x53, 0xce, 0xb8, 0x0c, + 0x12, 0xa5, 0x05, 0x0e, 0x72, 0x96, 0xb4, 0xb5, 0x08, 0xdf, 0x3d, 0x2a, 0xca, 0x3e, 0x13, 0xba, 0x01, 0xdd, 0x47, + 0x82, 0x3e, 0xd0, 0x7b, 0xa5, 0x0a, 0x97, 0xd5, 0x36, 0x13, 0x70, 0x17, 0x09, 0xf2, 0x5b, 0xa1, 0x53, 0x35, 0x06, + 0x55, 0x34, 0x8b, 0x58, 0xb8, 0xf7, 0x11, 0x37, 0xca, 0xe6, 0x9f, 0xfa, 0x1e, 0x2f, 0x25, 0x0c, 0x6e, 0x48, 0x4d, + 0x9f, 0xcc, 0x9b, 0x2b, 0xf6, 0x1e, 0x3a, 0xea, 0x50, 0x6b, 0xbc, 0xaf, 0x5e, 0x72, 0x0a, 0x31, 0x4a, 0x28, 0x3a, + 0x09, 0x06, 0x70, 0xbb, 0x84, 0x14, 0x7b, 0x83, 0xdd, 0xf8, 0xd7, 0xbc, 0x28, 0xb8, 0x58, 0xd7, 0x75, 0xe0, 0x06, + 0x34, 0x9c, 0x2f, 0x76, 0x43, 0x18, 0x8e, 0x69, 0xeb, 0x1a, 0x06, 0x61, 0xc6, 0x30, 0x12, 0x82, 0xd3, 0xbf, 0xe8, + 0x2b, 0x9a, 0xc4, 0xab, 0xef, 0xf8, 0x5f, 0x19, 0x2f, 0x25, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x74, 0x93, + 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0x58, 0xd3, 0x54, 0xfc, 0x2d, 0x17, 0x1f, 0xfc, 0x54, 0x74, 0x3c, 0x1a, 0x37, + 0xad, 0xce, 0xc8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0xa0, 0x1b, 0xa9, 0xdf, 0xda, 0x87, 0xc0, + 0x29, 0xd3, 0xe0, 0x9d, 0x07, 0x74, 0x73, 0xee, 0x82, 0x27, 0x8f, 0xe9, 0xb9, 0x45, 0x4f, 0xae, 0xd9, 0x49, 0xdd, + 0x43, 0xed, 0xbd, 0x1e, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0xd0, 0x38, 0x57, 0xf7, 0x1f, 0x8b, 0x5d, 0x0e, + 0xdf, 0x72, 0x96, 0x1b, 0xc0, 0x52, 0x11, 0x8d, 0x04, 0x8f, 0x02, 0xd4, 0xa5, 0x2a, 0x84, 0x2d, 0x66, 0x71, 0xa8, + 0xcc, 0x56, 0xad, 0x87, 0x82, 0x1c, 0x17, 0x23, 0x70, 0x08, 0x5d, 0x57, 0x83, 0x62, 0xb4, 0xcc, 0xea, 0xf7, 0xf8, + 0x5b, 0xb1, 0x0e, 0x49, 0xb6, 0x8f, 0x75, 0xe0, 0x86, 0x75, 0x98, 0x7e, 0xd4, 0x48, 0x01, 0x68, 0xb2, 0x11, 0xd8, + 0x04, 0xe0, 0xbd, 0xdd, 0x47, 0x84, 0x5a, 0x99, 0xee, 0x65, 0x2c, 0xe4, 0xf7, 0x5e, 0x12, 0x94, 0xe0, 0x27, 0xd4, + 0x96, 0xa5, 0xe0, 0x9d, 0x47, 0x3a, 0x27, 0x4d, 0x56, 0xbc, 0x07, 0x71, 0x5a, 0xf8, 0xc0, 0xde, 0x82, 0xe0, 0x9c, + 0x25, 0xbd, 0xc7, 0xdb, 0xac, 0x92, 0xda, 0xa8, 0x81, 0x02, 0xf8, 0xdd, 0xe0, 0x1e, 0x41, 0xbe, 0xbc, 0xe1, 0x5a, + 0x89, 0xdb, 0x90, 0x0f, 0x4b, 0x7a, 0x44, 0x06, 0xe6, 0xb9, 0x1a, 0xc6, 0xf4, 0x88, 0x1c, 0x9b, 0x67, 0x61, 0x07, + 0x70, 0x20, 0xd4, 0xa8, 0xd2, 0x23, 0x68, 0xd0, 0x6f, 0xa6, 0x45, 0x86, 0x64, 0xfd, 0xa8, 0x1b, 0x8c, 0x88, 0xbf, + 0x20, 0xa2, 0x2e, 0xfe, 0xf9, 0x60, 0xae, 0x7b, 0xcc, 0x05, 0xc2, 0x1c, 0x0c, 0x38, 0x88, 0xdb, 0x20, 0xd4, 0x07, + 0xcc, 0xe6, 0x2e, 0xaa, 0xe8, 0xbd, 0x31, 0xcc, 0xec, 0xe8, 0x0f, 0x37, 0x12, 0x7c, 0x9d, 0xb5, 0x41, 0x9d, 0x17, + 0x87, 0x40, 0x10, 0xdc, 0x17, 0xaa, 0x9a, 0xab, 0x1e, 0xd8, 0x78, 0xcb, 0x7e, 0x6c, 0xb7, 0xe3, 0x69, 0x65, 0xaf, + 0xfd, 0x15, 0x85, 0x93, 0x4f, 0xca, 0xbf, 0xde, 0xeb, 0x0c, 0x16, 0x8c, 0x0c, 0x5f, 0x3a, 0xfb, 0x17, 0xbe, 0x56, + 0xd2, 0xbd, 0x6a, 0x50, 0x90, 0xc7, 0x47, 0x92, 0xfe, 0xed, 0x95, 0x95, 0x4f, 0xcd, 0xf4, 0x6f, 0xb7, 0x7a, 0x7d, + 0x1e, 0x8f, 0x26, 0xdb, 0x6d, 0x4f, 0x19, 0xb8, 0x52, 0x1d, 0x43, 0x08, 0x9d, 0xeb, 0xc9, 0xe1, 0x11, 0x44, 0x45, + 0xf0, 0xe3, 0x6e, 0x16, 0x9e, 0x44, 0xc6, 0x8d, 0xd3, 0x59, 0x78, 0x82, 0x1d, 0xee, 0x44, 0x25, 0x2e, 0x46, 0xad, + 0x0d, 0x4e, 0xcf, 0x93, 0x10, 0x42, 0x39, 0x60, 0x65, 0x77, 0xf2, 0xcf, 0xbd, 0x34, 0x13, 0x92, 0x93, 0xd5, 0xed, + 0x94, 0xee, 0x60, 0x9a, 0x1f, 0xe8, 0x11, 0x1c, 0x70, 0x67, 0x7f, 0x35, 0x1f, 0xc3, 0x24, 0x53, 0xe4, 0x14, 0xc9, + 0x2f, 0xd2, 0x53, 0x48, 0xda, 0xa1, 0xa7, 0x92, 0x00, 0x4e, 0xa8, 0xf9, 0x18, 0x7e, 0xc3, 0xb8, 0x7f, 0xe7, 0xbf, + 0xb6, 0x53, 0x11, 0x3d, 0xa1, 0x58, 0xa6, 0x22, 0xa7, 0x49, 0x56, 0x26, 0x10, 0xb5, 0x51, 0x36, 0x23, 0xfa, 0xca, + 0xc6, 0x7c, 0x94, 0x84, 0xcf, 0xa9, 0xf5, 0x7f, 0x86, 0xf0, 0x69, 0x74, 0x46, 0x80, 0xcb, 0x2b, 0xaf, 0x2e, 0xc2, + 0xa7, 0x4f, 0xe8, 0xc1, 0xe4, 0xeb, 0x23, 0x7a, 0x70, 0xf4, 0xd5, 0x53, 0x02, 0xb0, 0x68, 0x57, 0x17, 0xe1, 0xd1, + 0xd3, 0xa7, 0xf4, 0xe0, 0xdb, 0x6f, 0xe9, 0xc1, 0xe4, 0xab, 0x23, 0x2f, 0x6d, 0xf2, 0xf4, 0x5b, 0x7a, 0xf0, 0xf5, + 0x13, 0x2f, 0xed, 0x68, 0xfc, 0x94, 0x1e, 0x7c, 0xf3, 0xb5, 0x4e, 0xfb, 0x1b, 0x64, 0xfb, 0xf6, 0x08, 0xff, 0xd3, + 0x69, 0x93, 0xa7, 0x5f, 0xd1, 0x83, 0xc9, 0x18, 0x2a, 0x79, 0x6a, 0x2b, 0x19, 0x4f, 0xe0, 0xe3, 0xaf, 0xe0, 0xbf, + 0xbf, 0x91, 0x60, 0x41, 0x6b, 0xc1, 0x92, 0x0a, 0xf5, 0x67, 0x28, 0xe2, 0x44, 0xd5, 0x44, 0xc2, 0x43, 0xcc, 0x2c, + 0xbf, 0x89, 0xc3, 0x80, 0xd8, 0x74, 0x28, 0x88, 0x1e, 0x8c, 0x47, 0x4f, 0x49, 0xe0, 0xc2, 0xd3, 0xdd, 0xba, 0x20, + 0x63, 0x49, 0x35, 0xcf, 0xbe, 0x48, 0x34, 0x63, 0xe0, 0x00, 0x58, 0x7d, 0x74, 0x73, 0xd5, 0x62, 0x9e, 0x7d, 0x51, + 0x8b, 0xdd, 0x5c, 0xbf, 0xb5, 0x00, 0xe5, 0xdd, 0x55, 0xcb, 0x6e, 0x4b, 0x19, 0x3a, 0xad, 0x35, 0xfa, 0xec, 0x23, + 0xa6, 0x0f, 0x06, 0xce, 0x0d, 0xfb, 0xef, 0x3b, 0xe5, 0xb4, 0xbe, 0x51, 0x28, 0xd4, 0xa8, 0x3c, 0x24, 0xec, 0x04, + 0x8a, 0x1e, 0x0c, 0x80, 0x27, 0x70, 0x70, 0xdf, 0xfe, 0xcd, 0x32, 0x3e, 0x76, 0x94, 0xf1, 0x33, 0xca, 0x10, 0xd0, + 0xa8, 0x87, 0x99, 0x4d, 0x0f, 0x1b, 0xdd, 0xe8, 0x25, 0x0b, 0x79, 0x32, 0xf9, 0x9e, 0xc1, 0xae, 0xd6, 0xb5, 0x38, + 0xd0, 0xa2, 0x68, 0x71, 0x79, 0x90, 0xf2, 0x59, 0xcd, 0xfe, 0xbe, 0x44, 0xf5, 0x56, 0xe4, 0xbd, 0x11, 0xd9, 0xac, + 0x66, 0xdf, 0xeb, 0x37, 0xc0, 0xcd, 0xb0, 0xdf, 0xe4, 0x93, 0x1b, 0x38, 0x83, 0x0b, 0xd3, 0x1e, 0x69, 0x62, 0x04, + 0x58, 0x01, 0x19, 0x38, 0xf0, 0x00, 0xe8, 0xa0, 0x3b, 0xda, 0xdb, 0xad, 0x4c, 0xf1, 0xfb, 0x6c, 0x60, 0x00, 0x35, + 0xf3, 0x36, 0xb1, 0x65, 0xff, 0xcb, 0x93, 0x97, 0xa0, 0x70, 0xcb, 0x2f, 0x6f, 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, + 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x55, 0x40, 0xf5, 0x96, 0x8f, 0x36, 0x5c, 0xaa, 0x27, 0x81, 0x33, 0xb8, + 0x14, 0x65, 0xc2, 0xdf, 0x2a, 0xb1, 0x3f, 0x5a, 0x3f, 0xba, 0xbe, 0x3d, 0x0e, 0xac, 0x7d, 0x8f, 0x8f, 0xd4, 0x67, + 0xde, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0xaf, 0x1a, 0x23, 0xf1, 0x28, 0x80, 0x37, 0xd0, 0x11, 0x29, 0x34, 0x52, 0x2d, + 0x70, 0x0c, 0x85, 0xb4, 0x40, 0x1c, 0x79, 0x75, 0x83, 0x2d, 0x88, 0x08, 0xc1, 0xc3, 0xed, 0x5f, 0x4b, 0x19, 0x38, + 0xaa, 0xdf, 0xe7, 0xc2, 0x75, 0x7b, 0xd2, 0x76, 0xe4, 0x38, 0xf5, 0x53, 0x07, 0xdf, 0x9c, 0x34, 0x8d, 0xb6, 0x5c, + 0x49, 0x99, 0x61, 0x59, 0xd8, 0x49, 0xa8, 0xe4, 0x1e, 0xb5, 0x03, 0xc9, 0x17, 0x72, 0x88, 0x64, 0x81, 0x51, 0x28, + 0xc8, 0x70, 0x42, 0xc1, 0x66, 0xaa, 0x5a, 0x66, 0x97, 0x75, 0xb8, 0x91, 0x0a, 0x65, 0x4e, 0xd1, 0xb7, 0x1b, 0x1c, + 0x48, 0x48, 0x94, 0x55, 0x6f, 0xe2, 0x37, 0x21, 0x82, 0xd5, 0x71, 0x65, 0x0b, 0xc5, 0x9d, 0xfd, 0xc9, 0xd3, 0x2e, + 0xfe, 0x48, 0xbb, 0x80, 0xda, 0x58, 0x4c, 0xc3, 0x89, 0x89, 0x7d, 0x63, 0xbf, 0x30, 0x9a, 0x1e, 0x80, 0xfa, 0xae, + 0xa4, 0x18, 0x41, 0x7e, 0xa5, 0xed, 0x63, 0x7b, 0x8c, 0x89, 0x19, 0xc4, 0x1a, 0x96, 0x39, 0x33, 0xd9, 0x37, 0xc2, + 0x4e, 0x00, 0xb8, 0x11, 0x5a, 0x23, 0x21, 0xf0, 0x78, 0x1d, 0xe2, 0x79, 0x29, 0xc3, 0xb7, 0x66, 0x84, 0x8e, 0xc1, + 0x9b, 0xca, 0x34, 0x32, 0x13, 0xae, 0x60, 0x50, 0x1f, 0xdb, 0x2a, 0x0a, 0xab, 0xa9, 0x2c, 0x3b, 0x01, 0xb8, 0x81, + 0xec, 0x58, 0x5f, 0x3c, 0x67, 0xf5, 0x3c, 0x5b, 0x44, 0x3a, 0x28, 0x60, 0x5e, 0x19, 0x06, 0xed, 0xcd, 0x1e, 0xd9, + 0x8e, 0x45, 0xe8, 0x86, 0xfb, 0x08, 0xc6, 0xd3, 0xf6, 0x05, 0x2b, 0x88, 0x46, 0x88, 0x87, 0x19, 0x33, 0xf8, 0x5e, + 0x69, 0xca, 0x53, 0xd9, 0x12, 0x08, 0x1c, 0x85, 0x50, 0x17, 0xbb, 0x46, 0x09, 0x36, 0x93, 0x17, 0xcc, 0x60, 0xc7, + 0x8e, 0xd4, 0x74, 0xc9, 0x3a, 0x1d, 0xca, 0x29, 0x2d, 0xd4, 0x94, 0x2a, 0x5f, 0xc3, 0x6a, 0x5e, 0xa0, 0x87, 0x1e, + 0xb8, 0x1e, 0x28, 0x87, 0xbc, 0x82, 0x4e, 0x74, 0x04, 0x9d, 0x56, 0x9b, 0xb0, 0x73, 0x23, 0xd5, 0xb2, 0x06, 0x79, + 0xc7, 0x50, 0xef, 0x88, 0x17, 0x4e, 0xa0, 0x2e, 0x84, 0x08, 0xd9, 0xdb, 0x22, 0x7d, 0x44, 0xb3, 0xac, 0x7a, 0x09, + 0x65, 0x71, 0xc4, 0xd6, 0x05, 0x2b, 0x6d, 0x34, 0xb9, 0xe4, 0x11, 0x4f, 0x11, 0x11, 0xf0, 0x54, 0x6a, 0xd7, 0x77, + 0x5a, 0x42, 0x68, 0x96, 0x02, 0x71, 0xb3, 0x51, 0x9c, 0x1b, 0x13, 0xc8, 0x02, 0xe8, 0xdb, 0x4f, 0xd9, 0xb5, 0x13, + 0x0e, 0x76, 0x73, 0x9d, 0x15, 0xcf, 0xf9, 0x65, 0x56, 0xf0, 0x14, 0xc1, 0xae, 0xee, 0xf4, 0x03, 0xb7, 0x6c, 0x1b, + 0x58, 0xbe, 0x7d, 0x07, 0x0b, 0xa6, 0x0a, 0x95, 0x52, 0x22, 0x2b, 0xa2, 0x0a, 0x32, 0xbb, 0xcc, 0xdd, 0xeb, 0xac, + 0x78, 0x1d, 0xdf, 0x81, 0x37, 0x85, 0xc7, 0x4f, 0x8f, 0x2e, 0xf0, 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, + 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x29, 0x68, 0x6d, 0x0d, 0x81, 0x13, 0x7f, 0x5a, 0x76, 0xef, 0x3a, 0x2b, 0xb4, + 0x7d, 0xc6, 0x75, 0x7c, 0xc7, 0x0a, 0x09, 0x66, 0x81, 0x71, 0xee, 0xdb, 0x52, 0x92, 0xeb, 0xac, 0xd0, 0x02, 0x92, + 0xeb, 0xf8, 0x8e, 0xfa, 0x32, 0x0e, 0x65, 0x45, 0xe7, 0xc4, 0xf9, 0xdd, 0x1d, 0x7e, 0x81, 0xa1, 0x56, 0xc6, 0xfd, + 0x3e, 0x48, 0xcc, 0x84, 0x69, 0xca, 0x4c, 0x44, 0x42, 0xa1, 0x85, 0xd4, 0x94, 0x0f, 0x26, 0x64, 0x77, 0xa5, 0x1a, + 0x46, 0xd4, 0x7c, 0x15, 0x56, 0xb3, 0x71, 0x34, 0x21, 0x74, 0xd2, 0xb1, 0xde, 0x75, 0x6b, 0x21, 0xd3, 0xe8, 0x69, + 0xe4, 0xf8, 0x74, 0x96, 0xac, 0x9e, 0x96, 0xc7, 0x8c, 0x4f, 0xcb, 0xc1, 0x80, 0xa8, 0xd0, 0xc1, 0x1b, 0xac, 0x07, + 0x4c, 0x69, 0x6c, 0xbc, 0x35, 0xdd, 0xea, 0x97, 0x42, 0x86, 0xa4, 0x77, 0x0c, 0x48, 0x32, 0x61, 0x83, 0xdd, 0x82, + 0x44, 0xd1, 0xf1, 0xbf, 0x93, 0x5b, 0x70, 0xd7, 0x83, 0xd1, 0x8f, 0xee, 0xeb, 0x18, 0xff, 0xa1, 0xb6, 0x05, 0x51, + 0x9f, 0x2a, 0xd6, 0xeb, 0x48, 0x94, 0x21, 0x17, 0xe1, 0x67, 0x47, 0x43, 0x34, 0x51, 0xed, 0xb1, 0xa0, 0x58, 0x5f, + 0x5f, 0xf0, 0x12, 0xa7, 0x9f, 0xd9, 0xcb, 0x15, 0x6c, 0x0b, 0x5a, 0x6b, 0x1a, 0xf5, 0x26, 0x7e, 0x13, 0x99, 0xcb, + 0x82, 0x2a, 0xf2, 0x39, 0x0a, 0x59, 0xf3, 0x30, 0xac, 0x87, 0xed, 0x41, 0x24, 0x87, 0xed, 0x49, 0xf0, 0x1a, 0x03, + 0x0b, 0x64, 0x87, 0x46, 0xe0, 0x22, 0x34, 0xf2, 0xb7, 0x63, 0x70, 0xe1, 0x32, 0x88, 0x2c, 0x43, 0x15, 0xbf, 0xa9, + 0xdd, 0x04, 0xd9, 0x2b, 0x74, 0x9a, 0xc2, 0xaa, 0xa4, 0x49, 0x3e, 0xfc, 0x7a, 0x29, 0x4a, 0xcc, 0xe4, 0x74, 0xd9, + 0xa1, 0xaf, 0xed, 0xf6, 0x0e, 0x74, 0xc1, 0xaa, 0x4f, 0xce, 0xd7, 0x8f, 0x3b, 0x7b, 0x02, 0x46, 0xb1, 0x32, 0x87, + 0x2f, 0xa4, 0x54, 0x3e, 0x28, 0xcd, 0xc7, 0x30, 0xaf, 0x14, 0xc7, 0x6e, 0x00, 0x93, 0x80, 0x7d, 0x86, 0x54, 0x87, + 0x69, 0xc7, 0x3e, 0x47, 0x1b, 0x58, 0x12, 0x70, 0xf8, 0x47, 0x99, 0x68, 0xdc, 0xab, 0x7b, 0x95, 0xfa, 0x21, 0x5b, + 0xe6, 0x0b, 0xe0, 0xf3, 0x61, 0xd7, 0x46, 0x05, 0xca, 0x26, 0x22, 0x41, 0x61, 0xcb, 0x63, 0x90, 0xf6, 0x28, 0xa6, + 0xab, 0x92, 0x27, 0x19, 0x4a, 0x29, 0x12, 0xe5, 0x13, 0x9c, 0xc3, 0x1b, 0xdc, 0x8f, 0x32, 0x20, 0xbc, 0x0c, 0x39, + 0x1d, 0xa5, 0x54, 0x59, 0xc0, 0x48, 0xea, 0x01, 0xa2, 0xbc, 0x0c, 0xe4, 0x78, 0xdb, 0xed, 0x84, 0xae, 0xd8, 0x72, + 0x38, 0xa1, 0x48, 0x4a, 0xae, 0xb0, 0xdc, 0x6b, 0xd0, 0x79, 0x5c, 0xb0, 0xde, 0x0b, 0xc0, 0x22, 0x38, 0x87, 0xbf, + 0x31, 0xa1, 0x37, 0xf0, 0x37, 0x27, 0xf4, 0x35, 0x0b, 0xaf, 0x87, 0x57, 0xe4, 0x30, 0x4c, 0x07, 0x13, 0x29, 0x18, + 0xbb, 0x67, 0xcb, 0x22, 0x94, 0x89, 0xab, 0xc3, 0x4b, 0xf2, 0xf8, 0x92, 0xde, 0xd1, 0x5b, 0x7a, 0x46, 0xdf, 0x02, + 0xe1, 0xbf, 0x3f, 0x9e, 0xf0, 0xe1, 0xe4, 0x49, 0xbf, 0xdf, 0xbb, 0xe8, 0xf7, 0x7b, 0xe7, 0xda, 0x80, 0x42, 0xed, + 0xa2, 0xab, 0x86, 0xaa, 0x5f, 0xd7, 0xcd, 0x62, 0xfa, 0x56, 0x6e, 0xdc, 0x84, 0x67, 0x79, 0x78, 0x7d, 0x78, 0x4f, + 0x86, 0xf8, 0x78, 0x99, 0x0b, 0x51, 0x86, 0x57, 0x87, 0xf7, 0x84, 0xbe, 0x3d, 0x01, 0xbd, 0x29, 0xd6, 0xf7, 0xf6, + 0xf1, 0xbd, 0xaa, 0x8d, 0xd0, 0x17, 0x61, 0x02, 0xdb, 0xe4, 0x8e, 0x99, 0xbb, 0xf6, 0x64, 0x0c, 0xb1, 0x4c, 0xee, + 0x9d, 0xf2, 0xee, 0x1f, 0xdf, 0x91, 0xc3, 0x3b, 0xf0, 0x14, 0x35, 0xe4, 0x6f, 0x16, 0xde, 0xb2, 0x56, 0x0d, 0x8f, + 0xef, 0xe9, 0x59, 0xab, 0x11, 0x8f, 0xef, 0x49, 0x14, 0xde, 0xb2, 0x2b, 0x7a, 0xc6, 0xae, 0x09, 0xbd, 0xe8, 0xf7, + 0xcf, 0xfb, 0x7d, 0xd1, 0xef, 0xff, 0x3d, 0x0e, 0xc3, 0x78, 0x58, 0x92, 0x43, 0x41, 0xef, 0x0f, 0x27, 0xfc, 0x2b, + 0x32, 0x0b, 0x55, 0xf3, 0xe5, 0x82, 0x33, 0x2a, 0x6f, 0x99, 0xeb, 0x9e, 0x82, 0xb5, 0xc2, 0x3d, 0x93, 0x4f, 0x6f, + 0xe9, 0x2d, 0x2b, 0xe9, 0x19, 0x8b, 0x49, 0x74, 0x03, 0xad, 0xb8, 0x98, 0x95, 0xd1, 0x2d, 0x3d, 0x63, 0xe7, 0xb3, + 0x38, 0x3a, 0xa3, 0x6f, 0x59, 0x3e, 0x9c, 0x40, 0xde, 0xb3, 0xe1, 0x2d, 0x39, 0x7c, 0x4b, 0xa2, 0xf0, 0xad, 0xfa, + 0x7d, 0x4f, 0xaf, 0x78, 0xf8, 0x96, 0x3a, 0xd5, 0xbc, 0x25, 0xba, 0x7a, 0xaf, 0xf6, 0xb7, 0x24, 0x72, 0x07, 0xf3, + 0xad, 0xb1, 0xa7, 0x79, 0x64, 0x69, 0x63, 0x5a, 0x84, 0xa0, 0x6f, 0x2e, 0xc2, 0x5b, 0x42, 0xa6, 0xfe, 0xd8, 0xc1, + 0x80, 0xce, 0x1e, 0x45, 0x09, 0xa1, 0xb7, 0x6e, 0xa9, 0xb7, 0x38, 0x86, 0x7a, 0x84, 0x64, 0xda, 0x19, 0xa6, 0xe1, + 0x3a, 0x78, 0xa5, 0xc0, 0x3a, 0x2e, 0xfa, 0xfd, 0x70, 0xdd, 0xef, 0x43, 0xa4, 0xfb, 0x72, 0xa6, 0x63, 0xbb, 0x59, + 0xb2, 0x49, 0x6f, 0x41, 0xfb, 0xff, 0x6a, 0x30, 0x80, 0xce, 0x38, 0x25, 0x85, 0xb7, 0x83, 0x57, 0x8f, 0xef, 0x89, + 0xac, 0xa3, 0xa4, 0x95, 0x08, 0x4b, 0xfa, 0x9a, 0x66, 0x00, 0xf8, 0xf5, 0x6a, 0x30, 0x20, 0x91, 0xfe, 0x8c, 0x4c, + 0x5f, 0x1d, 0xbf, 0x9d, 0x0e, 0x06, 0xaf, 0xf4, 0x36, 0xf9, 0x8b, 0xed, 0x29, 0x05, 0xd6, 0xdf, 0x79, 0xbf, 0xff, + 0xd7, 0x49, 0x4c, 0x2e, 0x4a, 0x1e, 0x7f, 0x9c, 0xfa, 0x6d, 0xf9, 0xcb, 0x46, 0x55, 0x3b, 0xef, 0xf7, 0xd7, 0xfd, + 0xfe, 0x19, 0x60, 0x17, 0xcd, 0xac, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x96, 0x22, 0x29, 0x92, 0x43, 0x63, 0x68, 0x5b, + 0x2c, 0xdb, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xc8, 0xaf, 0x28, 0x6e, 0x48, 0x14, 0xf6, 0xce, 0xb7, 0xdb, 0x33, 0xc6, + 0x58, 0x4c, 0x40, 0xfa, 0xe1, 0xbe, 0x3e, 0x6b, 0xbc, 0x18, 0x62, 0x95, 0x40, 0x66, 0x73, 0xb3, 0x34, 0x87, 0x40, + 0xc4, 0x61, 0xd3, 0xbf, 0xd7, 0xf7, 0xf2, 0xaa, 0xb1, 0x7c, 0xeb, 0xcf, 0x00, 0x42, 0x24, 0x58, 0xc8, 0x67, 0x38, + 0x06, 0x55, 0x06, 0xc0, 0xbf, 0x91, 0x9c, 0x79, 0x01, 0xa0, 0xe6, 0x64, 0xbb, 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb2, + 0xd1, 0xdf, 0x9e, 0x3e, 0xae, 0x1f, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, 0x61, 0x16, 0x6b, 0x7d, 0x08, 0x46, + 0xf0, 0x8a, 0x7d, 0xbc, 0xc9, 0x3e, 0x9b, 0x7d, 0x44, 0xc2, 0xea, 0x31, 0x8e, 0xbc, 0x48, 0x5b, 0x7a, 0xbb, 0x3d, + 0x0c, 0x26, 0x2f, 0xd2, 0x4f, 0xb0, 0x9d, 0x2e, 0xff, 0xe6, 0xc0, 0x78, 0xc2, 0xc1, 0x68, 0x2f, 0x0a, 0xea, 0x4c, + 0xdb, 0x6e, 0x6b, 0xf7, 0x12, 0xf8, 0x06, 0x53, 0x41, 0xc7, 0x66, 0x58, 0xb8, 0x41, 0x4d, 0xe4, 0xd1, 0x32, 0xa8, + 0x1b, 0x69, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0xd2, 0x71, 0x0b, 0x34, 0x43, 0x86, 0xba, 0xdc, 0xd3, 0xfa, 0x5f, 0xbc, + 0x14, 0x1a, 0x3e, 0xc3, 0x8a, 0x08, 0x1d, 0x6e, 0x8d, 0xbb, 0xdc, 0x5a, 0xf5, 0x09, 0x6e, 0xad, 0x40, 0x12, 0xab, + 0x61, 0x49, 0xf5, 0xe5, 0x28, 0x61, 0x27, 0x05, 0xe3, 0x33, 0xa0, 0xe3, 0x31, 0x3c, 0x08, 0x56, 0xcd, 0x44, 0x94, + 0xa0, 0x7d, 0xa2, 0x8d, 0x30, 0xf8, 0x27, 0x60, 0xf6, 0xd3, 0x1c, 0xfe, 0x0a, 0x32, 0x4d, 0x8e, 0x21, 0x20, 0xc4, + 0xf1, 0x78, 0x16, 0x87, 0x63, 0x12, 0x25, 0x27, 0xf0, 0x04, 0xff, 0x95, 0xe1, 0x98, 0x34, 0xea, 0x0e, 0x23, 0xe4, + 0xe5, 0x36, 0x61, 0x00, 0x57, 0x36, 0x9e, 0x4d, 0x22, 0x23, 0xdd, 0x15, 0x8f, 0x47, 0xe3, 0xa7, 0x64, 0x1a, 0x87, + 0x62, 0x90, 0x10, 0x0a, 0xde, 0xbd, 0x61, 0x31, 0x4c, 0x14, 0x3c, 0x1b, 0xb0, 0x79, 0x85, 0x65, 0xf3, 0x04, 0x9c, + 0x80, 0x30, 0x4c, 0xc8, 0xb1, 0xee, 0x41, 0x4a, 0x51, 0xe7, 0x39, 0xf6, 0x53, 0x1d, 0x41, 0x98, 0x1d, 0xb5, 0x54, + 0x7c, 0x05, 0x40, 0x97, 0x38, 0x38, 0xd4, 0x20, 0x61, 0x54, 0xb3, 0xb0, 0x70, 0xa8, 0x94, 0xae, 0xee, 0xb0, 0xf2, + 0x28, 0xbf, 0x6e, 0xd0, 0x61, 0x45, 0x06, 0x13, 0x5a, 0x9c, 0x4c, 0xf8, 0x57, 0x10, 0xc0, 0xc3, 0x8b, 0xf8, 0x25, + 0x71, 0x62, 0x20, 0xbc, 0x0a, 0x32, 0x50, 0x69, 0x23, 0x1b, 0x33, 0x32, 0x15, 0x1f, 0x40, 0x98, 0x94, 0x83, 0x5b, + 0xb1, 0xce, 0x53, 0x88, 0x0a, 0xb6, 0xce, 0xeb, 0x83, 0x2b, 0xb0, 0x64, 0x8f, 0x6b, 0x88, 0x13, 0xb6, 0x5e, 0x01, + 0x76, 0xee, 0xa3, 0x4d, 0xd1, 0x1c, 0xc8, 0xef, 0x0e, 0xb0, 0xe5, 0xf0, 0xaa, 0x16, 0x07, 0x93, 0xf1, 0x78, 0x3c, + 0xfa, 0x1d, 0x8e, 0x0e, 0x20, 0xb4, 0x24, 0xd2, 0x7c, 0x32, 0x40, 0xe3, 0xae, 0x6b, 0xee, 0x8c, 0x0b, 0x45, 0x59, + 0xe9, 0x64, 0x42, 0x40, 0xfc, 0xac, 0xfb, 0x06, 0xfb, 0x8a, 0xab, 0xf8, 0x27, 0xbb, 0x9f, 0xe8, 0x15, 0x2d, 0x57, + 0xea, 0xe8, 0xdd, 0xdb, 0xb3, 0x57, 0x1f, 0x5e, 0xfd, 0xfa, 0xe2, 0xfc, 0xd5, 0x9b, 0x97, 0xaf, 0xde, 0xbc, 0xfa, + 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xd7, 0x56, 0xc4, 0x8c, 0xbd, 0x73, 0x8f, 0x71, 0x6a, 0x71, 0x85, 0xb3, 0x47, 0xf6, + 0x16, 0x0b, 0xb0, 0x09, 0x9a, 0x5b, 0xa8, 0xa8, 0x62, 0x34, 0x6a, 0x75, 0x4f, 0x40, 0x46, 0xa3, 0x46, 0x36, 0x1e, + 0x56, 0x6c, 0x8d, 0x5c, 0xbc, 0x65, 0x38, 0xf8, 0xc8, 0xfc, 0x96, 0x9c, 0x09, 0x37, 0xa3, 0xad, 0x58, 0x11, 0xf0, + 0xf9, 0x5a, 0x17, 0xb5, 0xc3, 0x85, 0xc8, 0xbd, 0x6d, 0x9e, 0x43, 0x42, 0x1d, 0x22, 0xd7, 0xc1, 0xfb, 0x7a, 0x64, + 0x8f, 0x8f, 0x9c, 0x27, 0xe9, 0x19, 0xea, 0x72, 0x34, 0x7c, 0xe4, 0x3d, 0xa3, 0x13, 0x73, 0xa3, 0x75, 0xa8, 0xe7, + 0x25, 0xec, 0x6f, 0x29, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x58, 0xdd, 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, + 0x7e, 0xa4, 0x6a, 0x02, 0x69, 0x51, 0x20, 0x75, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, 0x52, 0xff, 0x0c, 0x3d, 0x02, 0x68, + 0x2e, 0x3b, 0x86, 0x04, 0xea, 0xc5, 0x6b, 0x5c, 0xff, 0x9c, 0x7c, 0x59, 0xd1, 0xce, 0x17, 0xdf, 0x41, 0x88, 0x61, + 0xf7, 0x8a, 0xe0, 0x4d, 0xb8, 0x9d, 0x64, 0x7b, 0x69, 0xd1, 0xf7, 0xaa, 0xeb, 0x18, 0x8f, 0xbb, 0x3d, 0x57, 0x0a, + 0xff, 0xd6, 0x05, 0xf6, 0x40, 0xfe, 0x75, 0xbc, 0x60, 0x21, 0x60, 0x33, 0x1e, 0x9a, 0x45, 0x62, 0xfd, 0xde, 0xe9, + 0x84, 0x1c, 0x1e, 0x4d, 0xf9, 0x90, 0x15, 0xb4, 0x1a, 0xb0, 0xa2, 0xd9, 0xa1, 0xe6, 0xbc, 0x4d, 0xc8, 0xab, 0x5d, + 0x1a, 0x5e, 0x0d, 0xf9, 0x43, 0x97, 0xa4, 0x0f, 0xdc, 0x73, 0xa8, 0x36, 0xcd, 0xc5, 0x90, 0xa6, 0x9c, 0xee, 0x52, + 0x19, 0x10, 0x22, 0x5d, 0xc7, 0x35, 0x69, 0xd4, 0x51, 0xb5, 0xb4, 0x92, 0x8e, 0x9b, 0x6c, 0xf3, 0x89, 0x4b, 0xb6, + 0xbc, 0x5d, 0xbb, 0xd7, 0xea, 0xf6, 0x85, 0x19, 0xc8, 0xdf, 0x1f, 0x88, 0x6a, 0xa2, 0x21, 0xba, 0x80, 0x0a, 0xfe, + 0x01, 0x5e, 0x9e, 0x3c, 0x52, 0x0a, 0xd0, 0x7d, 0x67, 0x47, 0xd7, 0x1e, 0xf7, 0x66, 0xb1, 0xb5, 0xc4, 0x39, 0xab, + 0x5d, 0x67, 0x79, 0x59, 0xb6, 0x44, 0xd7, 0xa9, 0xd8, 0xcf, 0x61, 0x47, 0xdf, 0x9d, 0x6d, 0x00, 0x44, 0x29, 0xac, + 0xed, 0xd9, 0x5f, 0x39, 0x67, 0x7f, 0x65, 0xce, 0x7e, 0xb3, 0x09, 0xa4, 0x0f, 0x2b, 0xb4, 0xec, 0xa5, 0x28, 0x6a, + 0xdd, 0xe4, 0xb1, 0xaf, 0xcb, 0x42, 0x5a, 0xcc, 0x0f, 0x0d, 0xed, 0x7a, 0x32, 0xa6, 0x02, 0xd5, 0x23, 0x3f, 0x60, + 0xab, 0x0e, 0x0b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0xb9, 0xef, 0x6e, 0xf7, 0x7f, 0x73, 0xa1, 0x83, 0xdb, + 0xda, 0xb2, 0x72, 0xd4, 0xd5, 0x71, 0x89, 0x77, 0xb5, 0xe5, 0xc3, 0x77, 0xb5, 0x77, 0x99, 0x5a, 0x76, 0x35, 0xa0, + 0x06, 0x15, 0xeb, 0x6b, 0x5e, 0x66, 0x49, 0x63, 0x14, 0x1a, 0x6f, 0x39, 0x84, 0xf6, 0x70, 0x0e, 0x2e, 0x90, 0xc3, + 0x12, 0x42, 0x3f, 0xd6, 0x5a, 0x00, 0xe8, 0xb2, 0xd8, 0x6f, 0x79, 0x98, 0x91, 0x81, 0x2b, 0xf1, 0x2b, 0x84, 0x2b, + 0x2e, 0x3e, 0xdc, 0xc9, 0x4c, 0xd0, 0xab, 0xc4, 0x46, 0xcd, 0x15, 0xed, 0x98, 0x1f, 0xee, 0x17, 0x18, 0x0d, 0xc2, + 0x69, 0x4b, 0x76, 0x58, 0x75, 0xcc, 0x72, 0x0d, 0x47, 0x6d, 0x61, 0xcb, 0x2c, 0x5a, 0xd7, 0xcf, 0x7a, 0x98, 0xa9, + 0x33, 0xe5, 0x2d, 0xc8, 0xbe, 0x90, 0xbb, 0x9f, 0xaa, 0x8a, 0x2b, 0x72, 0x32, 0x19, 0x4f, 0x49, 0x35, 0x18, 0xb4, + 0x92, 0x8f, 0x31, 0x79, 0x38, 0xdc, 0x61, 0x2e, 0x2b, 0xd5, 0x0f, 0xa7, 0x0f, 0x50, 0x9f, 0xb7, 0x25, 0xc9, 0xa6, + 0x66, 0x7f, 0x82, 0x59, 0x2c, 0x10, 0x47, 0x0b, 0xbf, 0x38, 0x5f, 0x00, 0xc8, 0x32, 0x2c, 0x33, 0x25, 0x2c, 0x82, + 0x2b, 0x3d, 0x74, 0xb2, 0x64, 0xe2, 0x78, 0x3c, 0x73, 0x7b, 0x6e, 0x19, 0x1c, 0x42, 0xa2, 0x89, 0x31, 0x7e, 0x71, + 0xb3, 0x60, 0x1c, 0x87, 0xe2, 0x44, 0x78, 0xdf, 0x15, 0x24, 0x1a, 0x6b, 0x53, 0x65, 0x75, 0x95, 0xa8, 0x87, 0x09, + 0x79, 0x5c, 0x92, 0xc3, 0x92, 0x2e, 0xdd, 0xb1, 0xc4, 0xf4, 0xc3, 0xf8, 0x70, 0x32, 0x26, 0x8f, 0xe3, 0xc7, 0x13, + 0x0d, 0x37, 0xec, 0xe6, 0xc8, 0x87, 0x4b, 0x72, 0xe8, 0x57, 0x09, 0xa6, 0xa8, 0xba, 0x67, 0x6e, 0x25, 0xc9, 0x60, + 0x39, 0x48, 0x1f, 0xb7, 0xf2, 0x62, 0xad, 0x6a, 0xbc, 0xd7, 0xc7, 0x7c, 0x4a, 0x2a, 0xef, 0xc6, 0xb0, 0xa6, 0xd7, + 0xf1, 0x1f, 0xa2, 0x8c, 0x0a, 0x01, 0x88, 0x84, 0xa0, 0xde, 0xce, 0x2e, 0xb3, 0x24, 0x2e, 0xd2, 0x28, 0x6d, 0x08, + 0x4d, 0x4f, 0xd8, 0x64, 0x3c, 0x4b, 0x59, 0x7a, 0x3c, 0x79, 0x3a, 0x9b, 0x3c, 0x8d, 0x8e, 0xc6, 0x51, 0x3a, 0x18, + 0x40, 0xf2, 0xd1, 0x18, 0x5c, 0xec, 0xe0, 0x37, 0x3b, 0x82, 0xa1, 0x3b, 0x41, 0x96, 0xb0, 0x84, 0xa6, 0x7d, 0x5e, + 0x93, 0xd4, 0x70, 0x5e, 0xca, 0x9e, 0xc4, 0x77, 0x74, 0xed, 0x38, 0xb8, 0xb8, 0x2d, 0xbc, 0xb4, 0x2d, 0xbc, 0xdc, + 0x6d, 0xa1, 0xb6, 0x20, 0x28, 0xc5, 0xff, 0x8f, 0x1b, 0xc6, 0xbe, 0xbb, 0x84, 0x5e, 0x5c, 0x37, 0xd9, 0x68, 0x55, + 0x8a, 0x5a, 0xc0, 0x6d, 0x42, 0x8a, 0xc2, 0x46, 0xf1, 0x6a, 0x95, 0x2b, 0x17, 0xb1, 0x79, 0x4d, 0x01, 0xdc, 0x05, + 0xce, 0x56, 0x60, 0xa1, 0xb5, 0x81, 0xdc, 0x5f, 0xbc, 0x14, 0xcc, 0xa8, 0x7d, 0xf4, 0x3d, 0xf2, 0x8f, 0x10, 0xc1, + 0x96, 0x4e, 0xc6, 0xb3, 0x0a, 0x11, 0x2d, 0x3e, 0x25, 0xef, 0xfd, 0x37, 0x8e, 0x22, 0x73, 0x34, 0x8f, 0x51, 0xa1, + 0x65, 0x3c, 0xe2, 0xcc, 0xc9, 0xe4, 0x64, 0xe0, 0x6e, 0x06, 0x23, 0xfd, 0xb5, 0xb7, 0x19, 0x63, 0xdb, 0xa3, 0x7a, + 0xa1, 0x85, 0xa2, 0x7f, 0xe1, 0x3b, 0x5d, 0x2f, 0xe0, 0x12, 0xca, 0x81, 0x5d, 0x5f, 0x5d, 0xf1, 0x0a, 0x40, 0x84, + 0xb2, 0xa2, 0xdf, 0xef, 0xfd, 0xa1, 0xa1, 0x49, 0x2b, 0x5e, 0xbe, 0xce, 0x0a, 0xe3, 0x8c, 0x03, 0x4d, 0x05, 0xea, + 0xff, 0xb1, 0x36, 0xcf, 0x74, 0x4c, 0x66, 0xee, 0xe3, 0x70, 0x42, 0x22, 0xff, 0x35, 0xf9, 0xc4, 0x69, 0xfa, 0x89, + 0x2b, 0xda, 0x7f, 0x20, 0x33, 0xd7, 0x1c, 0x32, 0xd4, 0x5f, 0x58, 0xe6, 0x49, 0xeb, 0x75, 0x62, 0x76, 0x52, 0xb1, + 0x7a, 0x06, 0xe8, 0xe9, 0x25, 0x3c, 0xc8, 0x6b, 0x59, 0x3c, 0x85, 0xd9, 0x07, 0x35, 0x62, 0x75, 0xcc, 0xc6, 0xb3, + 0x50, 0x84, 0x13, 0xb0, 0xef, 0x9d, 0x8c, 0xe1, 0x3e, 0x20, 0xc2, 0x8f, 0x75, 0x58, 0x51, 0x94, 0x92, 0x97, 0xf0, + 0x1b, 0x14, 0x13, 0x00, 0x11, 0x08, 0x79, 0xfb, 0x7d, 0x21, 0x93, 0xf0, 0x75, 0x81, 0x29, 0xa5, 0xfc, 0xe0, 0x3f, + 0x91, 0xaa, 0x5b, 0xa6, 0x5f, 0xae, 0x1f, 0x77, 0x26, 0x24, 0x9f, 0x6e, 0x53, 0xe2, 0x3b, 0x08, 0xee, 0x2c, 0x40, + 0x07, 0x51, 0xa3, 0x19, 0xdb, 0xc3, 0xfc, 0x6e, 0xb5, 0x9f, 0xdf, 0xad, 0xfe, 0xdf, 0xf1, 0xbb, 0xd5, 0x43, 0x8c, + 0x61, 0x6d, 0xa0, 0xe1, 0x67, 0xc1, 0x38, 0x88, 0xfe, 0x73, 0x3e, 0x71, 0x2f, 0x4f, 0x7d, 0x9d, 0x15, 0xd3, 0x3d, + 0x4c, 0xb3, 0x4b, 0x50, 0x10, 0x56, 0x71, 0x97, 0x9e, 0xac, 0x6b, 0x73, 0x6b, 0x25, 0x43, 0xcc, 0xf3, 0x00, 0x6b, + 0x14, 0xd6, 0x0e, 0xd0, 0x3d, 0xaa, 0x36, 0x88, 0x15, 0xc1, 0xc3, 0x98, 0x19, 0xe9, 0xfb, 0x76, 0xab, 0x55, 0x98, + 0x0f, 0x72, 0x51, 0x90, 0x5d, 0x7f, 0x3c, 0x1b, 0x47, 0x21, 0x36, 0xe0, 0x3f, 0x66, 0xac, 0x3c, 0xd9, 0x7c, 0x27, + 0x23, 0xb5, 0x63, 0xf2, 0x34, 0xd9, 0x25, 0xbd, 0x03, 0xde, 0x21, 0x3f, 0x6f, 0x3e, 0x86, 0xa5, 0xd0, 0xfc, 0x96, + 0xb8, 0x8a, 0xcb, 0xac, 0x5e, 0x5e, 0x67, 0x09, 0x32, 0x5d, 0xf0, 0xe2, 0xb3, 0x99, 0x2e, 0xe7, 0x63, 0x75, 0xc0, + 0x38, 0x4a, 0xf1, 0xc6, 0x13, 0xa5, 0xa7, 0x2d, 0xcf, 0x0a, 0x79, 0x79, 0x92, 0x31, 0xdb, 0xb3, 0x0a, 0x9c, 0x4e, + 0xc1, 0x04, 0x5f, 0xfd, 0xb4, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x4b, 0xb1, 0xd2, 0x58, 0x4e, 0x06, 0xba, + 0x13, 0x30, 0x43, 0x45, 0x81, 0x17, 0x28, 0xf8, 0x8b, 0x06, 0x46, 0xf4, 0xa5, 0xfd, 0x4d, 0x06, 0x1a, 0xe9, 0x52, + 0x9f, 0x08, 0x63, 0xcb, 0xed, 0x94, 0x69, 0x2b, 0xca, 0x19, 0x67, 0xef, 0xe5, 0x95, 0x02, 0x0c, 0xf0, 0x36, 0xb7, + 0xd1, 0x45, 0x82, 0x5e, 0x0b, 0x52, 0xe7, 0x0d, 0xdc, 0xcd, 0x32, 0xd2, 0xc2, 0xc5, 0xc7, 0xb5, 0xc3, 0x82, 0x3b, + 0xf6, 0x0b, 0xb1, 0xd0, 0x9a, 0x69, 0x30, 0x66, 0x73, 0x82, 0x05, 0x56, 0x32, 0x50, 0x60, 0x31, 0x53, 0x96, 0xa6, + 0xf5, 0x90, 0x1f, 0x1e, 0xa1, 0xb5, 0x69, 0x3d, 0xe0, 0x87, 0x47, 0x4d, 0x94, 0x1d, 0x43, 0x96, 0x13, 0x37, 0x83, + 0x7c, 0xdd, 0x44, 0x3a, 0x45, 0x67, 0x77, 0xeb, 0x4b, 0xdd, 0x51, 0xdd, 0x80, 0xeb, 0x07, 0x20, 0x80, 0x0d, 0xc0, + 0x21, 0x50, 0x0e, 0x96, 0x42, 0x04, 0x8b, 0x32, 0x89, 0xf6, 0x35, 0x74, 0xde, 0x28, 0xf8, 0x2f, 0x70, 0x17, 0x11, + 0x2b, 0xf7, 0x13, 0x04, 0xfe, 0x8a, 0x32, 0xa5, 0x4c, 0x71, 0x3f, 0x51, 0xea, 0x15, 0xca, 0x99, 0x6f, 0xcd, 0x07, + 0xd1, 0x9a, 0x08, 0x55, 0x8c, 0x21, 0xf8, 0xb7, 0xb2, 0x4c, 0x59, 0xaa, 0x4a, 0xf5, 0xa1, 0xf6, 0x5a, 0x2b, 0xad, + 0xe5, 0xe3, 0xc8, 0x79, 0x8d, 0xa1, 0x63, 0x13, 0x6b, 0x29, 0x27, 0x53, 0x67, 0x6f, 0x0e, 0x45, 0x64, 0x01, 0xa7, + 0x13, 0x36, 0x9e, 0x26, 0xc7, 0x62, 0x9a, 0x58, 0xc8, 0xfc, 0x9c, 0x61, 0x64, 0x55, 0x0d, 0xc2, 0x22, 0x6d, 0x28, + 0x4d, 0x01, 0x3a, 0x39, 0x21, 0x64, 0x8a, 0xa1, 0x28, 0xf2, 0x91, 0xea, 0x87, 0xf1, 0x66, 0xb5, 0x5f, 0xbc, 0x53, + 0x00, 0xa7, 0x61, 0x02, 0x81, 0xc0, 0xcb, 0xf8, 0x36, 0x2b, 0xae, 0xc0, 0x63, 0x78, 0x00, 0x5f, 0x82, 0x9b, 0x5c, + 0xca, 0x7e, 0xab, 0xc3, 0x1c, 0xd7, 0x16, 0x30, 0x68, 0xb0, 0x7a, 0x10, 0x1d, 0x2e, 0xa5, 0x7e, 0x57, 0x01, 0x62, + 0x63, 0x0a, 0xff, 0xb3, 0xb5, 0x61, 0xcf, 0xbe, 0x97, 0x4d, 0x43, 0xeb, 0x84, 0xd3, 0xe2, 0x2a, 0x87, 0x28, 0x2a, + 0x83, 0x18, 0xdc, 0x91, 0x1c, 0x3e, 0xef, 0x5d, 0x15, 0x5e, 0x12, 0x70, 0x2b, 0x8b, 0x45, 0xb8, 0xa2, 0xcb, 0xd1, + 0x1d, 0x5d, 0x8f, 0x6e, 0xe9, 0x98, 0x4e, 0xbe, 0x19, 0x83, 0x45, 0xb6, 0x4a, 0xbd, 0xa7, 0xeb, 0xd1, 0x92, 0x7e, + 0x3b, 0xa6, 0x47, 0x7f, 0x03, 0x13, 0x3e, 0x3c, 0x4c, 0xe8, 0x25, 0x38, 0x76, 0x91, 0x06, 0x3d, 0x35, 0x5d, 0x83, + 0xc3, 0x7a, 0x94, 0x0f, 0xf9, 0x28, 0xa7, 0x7c, 0x54, 0x0e, 0xeb, 0x11, 0x78, 0x3a, 0xd6, 0x43, 0x3e, 0xaa, 0x29, + 0x1f, 0x5d, 0x0c, 0xeb, 0xd1, 0x05, 0xf1, 0x9b, 0xfe, 0xaa, 0xe6, 0xd7, 0x15, 0x4b, 0x61, 0x5b, 0xc0, 0xf2, 0xb5, + 0xab, 0x2c, 0x49, 0xdd, 0x55, 0xad, 0x4f, 0x66, 0xc3, 0xd9, 0x9b, 0xeb, 0x2e, 0x27, 0x06, 0x8f, 0xdb, 0xa4, 0xc3, + 0xd5, 0x97, 0x13, 0x79, 0xd2, 0x4b, 0xe4, 0x87, 0xf1, 0x54, 0x9d, 0x43, 0x60, 0x26, 0x31, 0x0b, 0x63, 0x86, 0xcd, + 0x54, 0x69, 0xa0, 0xc0, 0xc9, 0x46, 0x8e, 0x8b, 0x62, 0x36, 0xca, 0x29, 0xbc, 0x8f, 0x09, 0x89, 0xf0, 0xac, 0x3a, + 0xa9, 0x47, 0x25, 0xc4, 0x1c, 0x61, 0x21, 0x3e, 0x42, 0xbf, 0xe4, 0x47, 0x0e, 0x12, 0x78, 0x86, 0x7d, 0x2d, 0x07, + 0x31, 0x1c, 0xf1, 0xa6, 0xb2, 0x7a, 0x16, 0x26, 0x50, 0x59, 0x3d, 0x2c, 0x74, 0x65, 0x25, 0xcd, 0x46, 0xb5, 0x5b, + 0x59, 0x8d, 0x63, 0x94, 0x10, 0x12, 0x15, 0xaa, 0x32, 0x50, 0x9f, 0x24, 0x2c, 0x2c, 0x54, 0x65, 0x17, 0xf2, 0xa3, + 0x0b, 0xb7, 0xb2, 0x0b, 0x70, 0x21, 0x1d, 0x24, 0xee, 0x55, 0x2a, 0x4f, 0xdb, 0xd7, 0x41, 0x6f, 0x55, 0xd1, 0x0d, + 0xbf, 0xab, 0xcb, 0x38, 0x2a, 0xa8, 0x8d, 0x01, 0x8d, 0x0b, 0x23, 0x12, 0x54, 0xad, 0x51, 0xf0, 0x87, 0x04, 0x51, + 0x69, 0x0c, 0x5e, 0x9d, 0x49, 0xd7, 0x4a, 0xad, 0x69, 0x35, 0x28, 0x06, 0x25, 0xdc, 0x9f, 0xf2, 0xd6, 0x42, 0xfa, + 0x1e, 0x22, 0x2a, 0x43, 0x79, 0x83, 0x7f, 0x60, 0xf0, 0x64, 0xb6, 0x4a, 0xc3, 0x64, 0x74, 0x4f, 0xe3, 0xd1, 0x12, + 0xe1, 0x60, 0xd8, 0x3a, 0x95, 0x78, 0xeb, 0x97, 0x90, 0x7e, 0x47, 0xe3, 0xd1, 0x2d, 0x4d, 0x8d, 0xcd, 0xa9, 0x86, + 0xba, 0xea, 0x8d, 0xe9, 0x5d, 0x04, 0xaf, 0xef, 0xa3, 0x25, 0x85, 0xad, 0x74, 0x9a, 0x67, 0x57, 0x45, 0x94, 0x52, + 0x44, 0x20, 0x5c, 0x23, 0x72, 0xe0, 0x52, 0xa1, 0x0d, 0xae, 0x07, 0x50, 0x86, 0x82, 0x0b, 0x5c, 0x0e, 0xe2, 0xd1, + 0xd2, 0x21, 0x53, 0x4b, 0x75, 0x91, 0x45, 0xf8, 0x68, 0x6b, 0xa3, 0x25, 0x79, 0x46, 0x2c, 0x8c, 0x4b, 0x18, 0x42, + 0x55, 0x58, 0xa1, 0x0b, 0x12, 0x36, 0x70, 0x64, 0x2f, 0x2c, 0xeb, 0x70, 0x03, 0xa6, 0x45, 0xf7, 0x60, 0x1e, 0x05, + 0x0a, 0x07, 0x9b, 0x20, 0xdc, 0x84, 0xa2, 0x9d, 0xa3, 0xd0, 0x39, 0x9c, 0x09, 0x4a, 0x77, 0x26, 0x08, 0x69, 0x57, + 0x37, 0xd9, 0x12, 0xae, 0xc1, 0xf6, 0x0e, 0x9d, 0x8a, 0x4a, 0xaa, 0xce, 0x2d, 0x98, 0x2c, 0xe1, 0x11, 0xb6, 0x84, + 0xa9, 0x99, 0x4e, 0xe1, 0x06, 0x7c, 0x78, 0xb4, 0x33, 0xdf, 0xe5, 0xec, 0xcd, 0x21, 0xd8, 0x76, 0x4a, 0x1f, 0x10, + 0x43, 0xec, 0x96, 0x6c, 0x3c, 0x5d, 0x1e, 0x17, 0xd3, 0x25, 0x12, 0x3b, 0x4d, 0xb7, 0x18, 0x9f, 0x2f, 0x17, 0x34, + 0xc1, 0xb3, 0x8d, 0xd5, 0xf3, 0xa5, 0x46, 0x4b, 0x49, 0x19, 0xae, 0xb7, 0x25, 0xfa, 0xff, 0xcb, 0x8b, 0x5f, 0x0a, + 0xf0, 0x12, 0x8c, 0x05, 0x80, 0x70, 0x0f, 0xa6, 0x05, 0xa9, 0x89, 0xb2, 0xb1, 0x4c, 0xc3, 0x14, 0x17, 0x81, 0x4e, + 0xe9, 0xf7, 0xc3, 0x9c, 0xa5, 0xc4, 0x81, 0x0e, 0x35, 0xa3, 0xb4, 0x4e, 0x5d, 0x21, 0x08, 0xf0, 0x48, 0xf2, 0x1c, + 0x9b, 0x7c, 0x33, 0x9e, 0x05, 0x72, 0x20, 0x82, 0x28, 0x3b, 0xc6, 0x47, 0x0c, 0x5c, 0x14, 0xa9, 0xb8, 0x9d, 0xb6, + 0x88, 0xcb, 0xdd, 0x63, 0x16, 0xe2, 0x24, 0x61, 0xae, 0x59, 0x36, 0x64, 0x75, 0x84, 0x09, 0xaa, 0x30, 0x30, 0xcb, + 0x1b, 0xb2, 0xfa, 0xf0, 0x08, 0x22, 0xb5, 0x9a, 0x32, 0x56, 0x5d, 0x65, 0x7c, 0x0b, 0x40, 0xd6, 0x8c, 0xb1, 0xa3, + 0xbf, 0x8d, 0x67, 0xf2, 0x9b, 0x28, 0xe4, 0x27, 0x47, 0x7f, 0x83, 0xe4, 0xe3, 0x6f, 0x91, 0x99, 0x83, 0x64, 0xaf, + 0xa0, 0x2b, 0x7f, 0xd6, 0x15, 0x94, 0x26, 0xae, 0xbd, 0x42, 0xad, 0x3d, 0xa1, 0xd7, 0x5e, 0x89, 0xee, 0xd4, 0x9a, + 0xf7, 0x90, 0xb6, 0xb3, 0x60, 0x82, 0x8e, 0x66, 0x77, 0xa0, 0x83, 0xb7, 0x8a, 0xa0, 0x17, 0x49, 0xa8, 0x3d, 0x42, + 0xa5, 0x51, 0x2f, 0xec, 0xc8, 0x6e, 0xd6, 0x25, 0x73, 0x0c, 0x98, 0x63, 0x73, 0x0e, 0x55, 0xc3, 0x5c, 0x1e, 0xd4, + 0x29, 0x2b, 0x86, 0x39, 0x1e, 0xc0, 0x6b, 0x26, 0x86, 0xd5, 0x20, 0x57, 0x28, 0xdf, 0x97, 0xac, 0x1c, 0x16, 0x83, + 0x5c, 0x71, 0x33, 0x53, 0x3f, 0x36, 0x6d, 0xa2, 0xc2, 0x33, 0xaf, 0xd8, 0xc9, 0xaa, 0x07, 0x7c, 0x2c, 0x78, 0x32, + 0xbb, 0x9e, 0x8f, 0xaf, 0x81, 0x93, 0xd9, 0xdc, 0x45, 0x4b, 0x7a, 0x1f, 0xa5, 0xf4, 0x36, 0x5a, 0xd3, 0x65, 0x74, + 0xa9, 0x4d, 0x8c, 0x93, 0x06, 0xce, 0x01, 0x68, 0x15, 0x40, 0xe2, 0xc9, 0x5f, 0xef, 0x79, 0x52, 0x87, 0x4b, 0x9a, + 0x82, 0xdb, 0xb0, 0x6b, 0x9f, 0x79, 0xed, 0x4a, 0xa4, 0x36, 0x88, 0xb1, 0x66, 0x0c, 0x15, 0x37, 0xce, 0xba, 0x8f, + 0xaa, 0x06, 0x76, 0xae, 0x8d, 0x4d, 0x54, 0x0f, 0x27, 0xd3, 0x02, 0x10, 0x5b, 0x8b, 0xe1, 0xd0, 0x1e, 0x21, 0xbb, + 0xc7, 0x8f, 0x0a, 0xf4, 0xdc, 0x13, 0x06, 0xdb, 0xb6, 0xe5, 0x0f, 0x0c, 0x61, 0x4a, 0x3f, 0x7d, 0xe4, 0x17, 0x84, + 0x4c, 0xaf, 0xe0, 0x6c, 0x04, 0xea, 0x68, 0x84, 0x4e, 0xbf, 0xd5, 0x61, 0xa9, 0x0e, 0xf0, 0xcd, 0x5d, 0x94, 0xd0, + 0xfb, 0x28, 0x77, 0xc8, 0xda, 0xb2, 0x61, 0x62, 0x7a, 0x9e, 0x85, 0xbc, 0x7d, 0xa0, 0x17, 0x0b, 0x00, 0xd1, 0x1a, + 0xc4, 0xae, 0xd4, 0xf5, 0x08, 0x9c, 0x86, 0xd0, 0x24, 0x34, 0x82, 0xab, 0x0a, 0xc2, 0x08, 0xd8, 0x92, 0xf0, 0x37, + 0x98, 0xa8, 0xc0, 0x17, 0xe0, 0x22, 0x93, 0xa6, 0x39, 0x0f, 0x1a, 0x77, 0x24, 0xcf, 0xca, 0xb6, 0xb7, 0x2b, 0x8c, + 0x26, 0x18, 0x7b, 0xa2, 0x7d, 0x1e, 0x29, 0x46, 0x71, 0x99, 0x84, 0xd9, 0xe8, 0x4e, 0x9e, 0xe7, 0x34, 0x1b, 0xdd, + 0xab, 0x5f, 0x35, 0x1d, 0xd3, 0xef, 0x54, 0x40, 0x1b, 0x29, 0x7d, 0xeb, 0x38, 0x1b, 0xd0, 0x7a, 0xb1, 0xd0, 0xfe, + 0xd7, 0x62, 0x74, 0x47, 0xc5, 0xe8, 0xde, 0xb5, 0xa4, 0x9a, 0x4c, 0xcb, 0xe3, 0x0a, 0x0d, 0xa9, 0x3a, 0xbf, 0x2f, + 0x81, 0x9f, 0x2b, 0xb4, 0xef, 0xb4, 0xfe, 0xde, 0x69, 0xff, 0x45, 0x27, 0x4f, 0x20, 0x59, 0xa2, 0x92, 0xd5, 0x23, + 0xb0, 0x63, 0x5f, 0xe7, 0x71, 0xa9, 0x47, 0x29, 0xa6, 0xc6, 0xa4, 0x1f, 0x03, 0x57, 0x4c, 0x7b, 0x25, 0xb8, 0x5a, + 0x6e, 0xb7, 0x32, 0x86, 0x26, 0xec, 0xd9, 0x31, 0x44, 0x3d, 0xd7, 0x8e, 0x51, 0xc2, 0x73, 0x0f, 0x88, 0x95, 0xcc, + 0x5b, 0xba, 0x04, 0x24, 0xf0, 0xd6, 0xc1, 0xa4, 0x28, 0x46, 0x29, 0xc0, 0x4f, 0xa8, 0x3c, 0x0e, 0xfa, 0x84, 0x7c, + 0xa1, 0x50, 0x27, 0x84, 0xb7, 0x25, 0x70, 0xfc, 0x61, 0x7d, 0x54, 0x08, 0x5e, 0xe5, 0xb8, 0xfe, 0x0a, 0xe3, 0xfa, + 0x4b, 0x85, 0xe3, 0x8e, 0x65, 0xbb, 0x7e, 0xde, 0xa6, 0x46, 0x2f, 0xc1, 0xc2, 0x77, 0x23, 0xcd, 0x23, 0xb9, 0x41, + 0x48, 0x95, 0x60, 0xa5, 0x76, 0x21, 0xc1, 0xfc, 0x4b, 0x39, 0x5b, 0x9d, 0xb9, 0xea, 0x91, 0x07, 0xe5, 0x6c, 0x6a, + 0xfa, 0x3d, 0x09, 0xda, 0x7d, 0x47, 0x9a, 0xc3, 0x5b, 0x74, 0xf8, 0xec, 0x1a, 0x4b, 0xcc, 0x9d, 0x44, 0xc9, 0xf3, + 0x49, 0x60, 0xab, 0xe7, 0xd9, 0xb5, 0xf4, 0xb1, 0xda, 0xc5, 0xf1, 0xd3, 0xe7, 0x4f, 0x5c, 0x87, 0x69, 0xe5, 0x29, + 0x41, 0xc0, 0x9b, 0x43, 0xdb, 0x15, 0xca, 0x80, 0x86, 0xfa, 0x06, 0x8e, 0x73, 0x35, 0xac, 0x15, 0x01, 0x53, 0x52, + 0x1e, 0x15, 0xe0, 0x50, 0xe7, 0x91, 0xbb, 0x69, 0x58, 0x6b, 0xba, 0xe6, 0xf5, 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, + 0x3f, 0x3c, 0x1a, 0xd4, 0xf8, 0x93, 0xf8, 0xa3, 0xd1, 0xce, 0x0d, 0x77, 0x9a, 0x0a, 0x33, 0xd7, 0x62, 0x45, 0x76, + 0x47, 0xc9, 0xc9, 0xef, 0xe8, 0x85, 0xb1, 0x3f, 0xff, 0xb9, 0x98, 0x70, 0xd2, 0x12, 0x13, 0xa2, 0xa5, 0x83, 0x12, + 0x1d, 0xec, 0x28, 0xaf, 0xcc, 0x4b, 0xbc, 0x74, 0x8e, 0xff, 0x7d, 0x3d, 0xd6, 0xae, 0x02, 0xa1, 0xd5, 0xc9, 0xc3, + 0xf6, 0x64, 0x81, 0xa8, 0x01, 0xd5, 0xec, 0xb2, 0x1c, 0x69, 0xda, 0x59, 0x93, 0x8d, 0x27, 0x73, 0xdd, 0xcd, 0xe2, + 0xd9, 0x4c, 0x76, 0x2c, 0x2c, 0x3d, 0x0c, 0xc6, 0x4e, 0x15, 0x7d, 0x0e, 0x5a, 0x7e, 0x04, 0xcf, 0x7d, 0xe5, 0x99, + 0xcb, 0x66, 0x69, 0xf1, 0x02, 0x9d, 0x73, 0xaa, 0x21, 0x87, 0x1c, 0x80, 0xe3, 0x02, 0x8d, 0x25, 0x8a, 0x28, 0x08, + 0x1a, 0x13, 0x84, 0x5d, 0x95, 0xee, 0x48, 0x9f, 0x76, 0xf1, 0x69, 0x2b, 0xf4, 0x3d, 0xde, 0x67, 0x20, 0x31, 0x75, + 0x24, 0x0f, 0xb5, 0xd7, 0x1c, 0x95, 0x3c, 0x8b, 0x53, 0x85, 0xcf, 0x2f, 0x65, 0x67, 0xfe, 0xdd, 0x6a, 0x4c, 0xf1, + 0x1f, 0x69, 0xda, 0x77, 0x2e, 0x4d, 0x13, 0xdd, 0xb5, 0x3c, 0x68, 0x29, 0x2c, 0x38, 0x6e, 0x1b, 0x77, 0xfd, 0xfa, + 0x39, 0xaa, 0x61, 0x61, 0x73, 0x38, 0x13, 0x3a, 0xb4, 0x77, 0x95, 0x9d, 0xb9, 0x3e, 0xa2, 0x56, 0x5d, 0xac, 0xda, + 0x80, 0x92, 0x25, 0xe7, 0xd6, 0xe9, 0x88, 0x95, 0xbe, 0x3b, 0x0c, 0x77, 0xe6, 0x51, 0xb1, 0xbb, 0xdb, 0xed, 0x84, + 0xb4, 0xed, 0x83, 0xf1, 0xbe, 0x84, 0x85, 0x58, 0xef, 0xb0, 0x83, 0xef, 0xc3, 0xfa, 0x31, 0x1f, 0xfc, 0x1c, 0xca, + 0x75, 0x55, 0x3f, 0xcf, 0xa4, 0xa1, 0xcf, 0xcb, 0x52, 0x5c, 0xcb, 0x4e, 0xb9, 0x42, 0xb7, 0x96, 0xa9, 0xf7, 0x9b, + 0xf8, 0x4d, 0x2b, 0x40, 0x8c, 0xd3, 0x15, 0x23, 0xc5, 0x1b, 0x1a, 0x61, 0x9c, 0x87, 0xdb, 0x64, 0x51, 0x4b, 0x95, + 0x40, 0xd4, 0xe6, 0x27, 0x8f, 0x79, 0xa4, 0xd5, 0x99, 0xf0, 0xdd, 0x63, 0xee, 0x4a, 0xd7, 0x76, 0x9b, 0xf8, 0xa9, + 0xa6, 0x1d, 0xee, 0x0e, 0x74, 0x47, 0xeb, 0x1e, 0x6e, 0x9e, 0xc9, 0xcf, 0x23, 0xfd, 0xc5, 0x00, 0x9b, 0xb5, 0xcb, + 0xb8, 0xec, 0x18, 0xee, 0x3b, 0xd3, 0x83, 0xb1, 0x80, 0x40, 0x62, 0x86, 0x5e, 0x06, 0x36, 0x70, 0x81, 0xbd, 0xc2, + 0x80, 0x21, 0xae, 0x6e, 0xc9, 0xb9, 0xb2, 0xb2, 0x75, 0x91, 0xb7, 0x51, 0x21, 0xd8, 0x34, 0x1d, 0x37, 0x49, 0x0e, + 0xc1, 0x09, 0x5b, 0xee, 0x7d, 0xed, 0xb5, 0x33, 0xfc, 0xc7, 0xa0, 0xb2, 0x6e, 0x89, 0x8e, 0x51, 0xdb, 0x63, 0xa5, + 0xee, 0xd5, 0xbc, 0xca, 0x7d, 0xe4, 0x58, 0xbf, 0xe9, 0x97, 0x9a, 0x7d, 0xc1, 0x6b, 0x29, 0x38, 0x34, 0xb6, 0x5b, + 0x61, 0x17, 0x8b, 0x73, 0xb4, 0x1a, 0x59, 0x6b, 0xab, 0xbd, 0x46, 0x2a, 0xba, 0x7f, 0xcd, 0x71, 0x62, 0x2d, 0x85, + 0xcd, 0x87, 0x0f, 0x17, 0x6c, 0x9b, 0x00, 0x06, 0x2d, 0x3a, 0x0b, 0x94, 0x20, 0x93, 0x95, 0xaa, 0xdd, 0x4c, 0x89, + 0x5b, 0xee, 0x67, 0x5d, 0x66, 0x3b, 0x8f, 0x5f, 0x3b, 0x69, 0x9f, 0xf8, 0x1c, 0xfd, 0x30, 0xbf, 0x33, 0x4e, 0x4a, + 0xd6, 0x30, 0xae, 0xe5, 0xff, 0x57, 0xd3, 0xab, 0x32, 0x4b, 0xa3, 0x8d, 0xe6, 0xc1, 0x4c, 0xa8, 0x4d, 0x17, 0x1a, + 0xa3, 0xb6, 0xcb, 0x46, 0x12, 0xd1, 0xfa, 0x0e, 0x04, 0x33, 0x92, 0xfb, 0xaa, 0xda, 0xbc, 0x52, 0x6d, 0xe0, 0x1d, + 0x3e, 0xb1, 0xd1, 0x3d, 0xdb, 0x13, 0x42, 0xf9, 0xee, 0x69, 0xa1, 0x57, 0x2d, 0xad, 0x3c, 0xb6, 0xab, 0x72, 0x2e, + 0x46, 0xb5, 0x7a, 0xc2, 0x64, 0xc3, 0x82, 0xc9, 0xfe, 0x7f, 0x5f, 0x66, 0x69, 0x9b, 0xa2, 0x03, 0xd3, 0xe9, 0xfb, + 0x74, 0xd2, 0x0d, 0xae, 0x33, 0x60, 0x11, 0xc1, 0x96, 0x0a, 0xc7, 0xa3, 0x50, 0x6e, 0x90, 0x30, 0x11, 0x5c, 0x47, + 0xbd, 0xec, 0x68, 0x99, 0x94, 0x55, 0x01, 0xcf, 0x2f, 0x5d, 0x65, 0x3a, 0x8e, 0x86, 0x7e, 0xff, 0x3a, 0xd5, 0xa1, + 0x5f, 0x69, 0xe1, 0x9c, 0x23, 0xcb, 0xcc, 0x51, 0x75, 0xc8, 0x30, 0x46, 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x86, + 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x8c, 0x81, 0x5c, 0x2a, 0x83, 0x7a, 0x45, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, + 0x42, 0x2f, 0x59, 0xe1, 0xde, 0x85, 0xd6, 0x20, 0x50, 0x14, 0x7e, 0xca, 0xf4, 0x42, 0xb5, 0xf3, 0x92, 0x26, 0xb4, + 0xa4, 0x2b, 0xd2, 0x80, 0xbe, 0xd7, 0xca, 0xd9, 0xd1, 0xc9, 0x4e, 0xcf, 0x7a, 0xcc, 0xca, 0xe1, 0x64, 0x1a, 0xc3, + 0x35, 0x2d, 0xb6, 0xd7, 0xb4, 0xa5, 0x7f, 0xe3, 0xf2, 0x36, 0x8e, 0x47, 0xbb, 0x40, 0xda, 0xa6, 0xb8, 0xfd, 0xd4, + 0xe1, 0xf6, 0xd7, 0x0d, 0x5b, 0x4e, 0x7b, 0xeb, 0xed, 0xb6, 0x97, 0x82, 0x8d, 0xa8, 0xc3, 0xc7, 0xaf, 0xa5, 0x74, + 0xdd, 0x70, 0xf9, 0x29, 0x3c, 0x3b, 0x7c, 0xfd, 0xd2, 0x05, 0x97, 0xa3, 0x75, 0x9b, 0xbb, 0x5f, 0xee, 0x22, 0xcb, + 0x7d, 0xd6, 0xd0, 0x72, 0x35, 0x43, 0x3e, 0x79, 0xd6, 0xda, 0x3b, 0xd4, 0x82, 0xe5, 0xac, 0x9b, 0xf0, 0xc4, 0x60, + 0xc7, 0x5e, 0x7b, 0x9b, 0xa3, 0xd6, 0x97, 0x2c, 0x8f, 0x04, 0xba, 0x24, 0x4f, 0x37, 0xfd, 0x83, 0x08, 0xf3, 0xd1, + 0x1d, 0xcd, 0x01, 0x57, 0xac, 0x36, 0x97, 0x0c, 0xd2, 0xd4, 0xed, 0x25, 0x2e, 0x7d, 0x85, 0x43, 0xb2, 0xc1, 0x27, + 0xcd, 0x54, 0x7d, 0x72, 0xc9, 0x83, 0xff, 0xb7, 0x51, 0xab, 0xf4, 0xec, 0x24, 0x7b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, + 0x4c, 0x34, 0x12, 0xf0, 0xd4, 0x2c, 0x86, 0x7a, 0x54, 0x97, 0x71, 0x51, 0xe5, 0x3a, 0xe6, 0xd8, 0xde, 0xae, 0xa1, + 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xfa, 0x0e, 0x6c, 0x04, 0x3a, 0x2a, 0x51, 0x5f, 0x86, 0x99, 0xbe, 0x0c, 0xd3, + 0xae, 0xad, 0x02, 0xc3, 0x2b, 0xb7, 0x4a, 0x22, 0x5d, 0x8d, 0x7a, 0x5c, 0xcf, 0x92, 0xdf, 0x8b, 0xbc, 0x7b, 0x4d, + 0x3a, 0x12, 0x7f, 0xba, 0x74, 0xe4, 0xf5, 0x30, 0x20, 0xe2, 0x73, 0x96, 0x86, 0x6d, 0x14, 0x04, 0xa7, 0x96, 0x3b, + 0x90, 0xe6, 0x23, 0x40, 0xe6, 0xc7, 0x69, 0xf8, 0x4e, 0x89, 0x73, 0xc8, 0x46, 0x6a, 0x9c, 0xd8, 0x52, 0xab, 0x87, + 0xe0, 0xce, 0x7b, 0xcd, 0x63, 0x08, 0x7c, 0xf8, 0x01, 0x37, 0x83, 0x8c, 0x6e, 0x4b, 0x74, 0x94, 0x36, 0x87, 0xba, + 0xe5, 0x23, 0x4f, 0xa8, 0x64, 0x64, 0x78, 0x31, 0xb4, 0x77, 0x47, 0x60, 0x54, 0x5b, 0x81, 0xcc, 0xb0, 0x3c, 0x3c, + 0x1a, 0xa6, 0x52, 0x50, 0x34, 0x14, 0xc3, 0x25, 0xca, 0x01, 0x31, 0x09, 0x04, 0x46, 0xe5, 0x20, 0x55, 0x95, 0xc9, + 0x17, 0x83, 0x54, 0xdd, 0xaa, 0x48, 0x73, 0x9e, 0x85, 0x35, 0x55, 0x2d, 0xa2, 0x63, 0x3a, 0x14, 0x74, 0xa9, 0x77, + 0x6a, 0xae, 0xa4, 0x17, 0x72, 0x39, 0x3e, 0x53, 0x69, 0x30, 0x8a, 0x67, 0x36, 0x45, 0xbd, 0x95, 0xfb, 0xd9, 0x7d, + 0x8b, 0x29, 0x0d, 0x62, 0x53, 0x3b, 0x8b, 0x18, 0x56, 0xed, 0x87, 0xac, 0xce, 0x41, 0xbb, 0x0b, 0xca, 0xc6, 0x5a, + 0x3b, 0xcf, 0x7b, 0xc1, 0xcc, 0x41, 0xdb, 0x58, 0xfb, 0x3e, 0xf4, 0x5a, 0x8c, 0xda, 0x1b, 0x53, 0x85, 0x7b, 0x02, + 0x3f, 0x4d, 0xd0, 0x74, 0x27, 0xf2, 0x1c, 0x75, 0xc8, 0xbb, 0xfb, 0x99, 0x25, 0x3b, 0x93, 0x4f, 0x62, 0x99, 0x34, + 0xed, 0x63, 0x12, 0xa3, 0x96, 0x18, 0x46, 0x17, 0x6e, 0x64, 0x52, 0xfb, 0xb9, 0x33, 0xfd, 0x88, 0x67, 0xf2, 0xb0, + 0x1d, 0x1a, 0x75, 0xa5, 0x61, 0x2d, 0x29, 0xa2, 0xba, 0xa0, 0xb7, 0xa6, 0x3a, 0x3a, 0xa2, 0x4e, 0x47, 0x60, 0x75, + 0x45, 0x1b, 0xd4, 0x00, 0x4c, 0xc6, 0x8d, 0xa9, 0xcd, 0xe5, 0x60, 0x1a, 0xa3, 0x2a, 0x78, 0x4a, 0x77, 0x85, 0xd2, + 0xbd, 0x49, 0xd3, 0xb4, 0x86, 0xd8, 0x00, 0x06, 0x04, 0x76, 0xf4, 0xe4, 0xf4, 0x07, 0x3e, 0x2a, 0x00, 0x0d, 0xbc, + 0xdb, 0x99, 0xca, 0x91, 0xa8, 0x77, 0x72, 0xd3, 0xfa, 0xa9, 0x4e, 0x55, 0x2e, 0x80, 0x8a, 0x3b, 0x4b, 0xe7, 0x97, + 0x7a, 0xc4, 0x02, 0x18, 0xf7, 0xc0, 0x9a, 0xea, 0x9d, 0x66, 0x60, 0x3d, 0x91, 0xe7, 0x59, 0xc5, 0x13, 0x51, 0xc0, + 0x8c, 0x88, 0xeb, 0x6b, 0x51, 0xc0, 0x30, 0xc8, 0x01, 0x40, 0x8b, 0xe6, 0x2a, 0x9a, 0xf0, 0xaf, 0x1a, 0xba, 0x2f, + 0x0f, 0xff, 0x4a, 0xe5, 0xfa, 0x7a, 0xdc, 0x80, 0xa1, 0xf2, 0xba, 0xe6, 0x3b, 0x99, 0xbe, 0xe6, 0x4f, 0x9c, 0x4c, + 0x4b, 0xb1, 0x2e, 0x77, 0xb2, 0x7c, 0xf5, 0x35, 0x7f, 0xaa, 0xf2, 0x1c, 0x3d, 0x69, 0x68, 0x1a, 0xdf, 0xef, 0x64, + 0xf9, 0xe6, 0xeb, 0x27, 0x26, 0xcf, 0x57, 0xe3, 0x86, 0xde, 0x72, 0xfe, 0xd1, 0x66, 0x9a, 0xa8, 0xaa, 0xc6, 0x4f, + 0xbe, 0x31, 0xb9, 0x9e, 0x34, 0xf4, 0x5a, 0x14, 0xf5, 0x72, 0xa7, 0xa8, 0xa3, 0xaf, 0x8f, 0xbe, 0xe1, 0x5f, 0xeb, + 0xee, 0x1d, 0x35, 0xf4, 0xcf, 0x75, 0x5c, 0xd6, 0xbc, 0xdc, 0x29, 0xee, 0x6f, 0xdf, 0x7c, 0xf3, 0xc4, 0x64, 0x7c, + 0xd2, 0xd0, 0x7b, 0x1e, 0x77, 0xb4, 0x7d, 0xf2, 0xf4, 0x09, 0xff, 0x5b, 0xd3, 0xd0, 0x5f, 0x98, 0x1b, 0x1c, 0xf5, + 0x34, 0x73, 0xf4, 0xf0, 0x89, 0xf0, 0x51, 0x03, 0x86, 0x0e, 0x1a, 0x40, 0x2e, 0x8c, 0x9a, 0x66, 0x8f, 0x57, 0x2e, + 0xb8, 0x7d, 0x9f, 0xc7, 0x69, 0xbc, 0x82, 0x83, 0x60, 0x83, 0xc6, 0x59, 0x25, 0x70, 0xaa, 0xc0, 0x7b, 0x46, 0x05, + 0xcd, 0x2a, 0xf1, 0x0f, 0xce, 0x3f, 0xc2, 0xa0, 0x21, 0xa4, 0x8d, 0x8c, 0x0c, 0xf4, 0x76, 0xa5, 0x22, 0x1b, 0xa1, + 0xff, 0xa6, 0x1f, 0x07, 0xc7, 0x85, 0xd1, 0xeb, 0xf7, 0xc3, 0x92, 0x55, 0x61, 0x49, 0x08, 0xfd, 0x23, 0x2c, 0xc1, + 0xa1, 0xa4, 0x64, 0x4e, 0x3e, 0xed, 0x7b, 0xae, 0x8c, 0xc2, 0x42, 0x10, 0xdd, 0x45, 0xe6, 0x01, 0x55, 0x8f, 0xae, + 0x43, 0x37, 0xc4, 0xcb, 0x0a, 0x4b, 0x86, 0x0e, 0x66, 0x30, 0x43, 0x50, 0xfc, 0x6b, 0x1e, 0x0a, 0xf0, 0x89, 0x07, + 0xf8, 0xe8, 0x31, 0x99, 0x71, 0x79, 0xad, 0x7d, 0x7b, 0x19, 0x96, 0x34, 0x50, 0x6d, 0x87, 0xa0, 0x03, 0x91, 0xfb, + 0x02, 0x3c, 0x05, 0x06, 0x2e, 0x2c, 0xec, 0x52, 0xec, 0xfa, 0xab, 0xff, 0xa2, 0x59, 0x47, 0x1b, 0x7e, 0xf4, 0x17, + 0xe3, 0xc2, 0x9e, 0x91, 0xa9, 0x38, 0x2e, 0x86, 0x93, 0xe9, 0x60, 0x20, 0x6c, 0x1c, 0xb7, 0xd3, 0x6c, 0xfe, 0xcb, + 0x5c, 0x2c, 0x16, 0xa8, 0xfb, 0xc6, 0x79, 0x9d, 0xa9, 0xbf, 0x91, 0x72, 0x3e, 0x78, 0x7d, 0xfa, 0xdb, 0xf9, 0xd9, + 0xe9, 0x4b, 0x70, 0x3e, 0xf8, 0xf0, 0xe2, 0xfb, 0x17, 0xef, 0x65, 0x70, 0x77, 0x39, 0xe7, 0xfd, 0xbe, 0x95, 0xfa, + 0x84, 0x7c, 0x58, 0x93, 0xc3, 0x30, 0x7e, 0x5c, 0x4a, 0xa3, 0x07, 0x72, 0xcc, 0x0c, 0x14, 0x32, 0x54, 0xd1, 0x98, + 0xdf, 0xc5, 0x70, 0xe2, 0x80, 0x59, 0xdc, 0x7b, 0x22, 0x5c, 0xb7, 0xe5, 0x26, 0xc8, 0x9a, 0x38, 0x71, 0xfa, 0xc1, + 0xc9, 0x54, 0x58, 0xb6, 0xb0, 0x64, 0x50, 0x36, 0xb4, 0xe9, 0x34, 0x9b, 0x97, 0x0b, 0xd3, 0x2e, 0xbb, 0x40, 0x46, + 0x69, 0x76, 0x79, 0x19, 0x4a, 0xe8, 0xea, 0x13, 0xd0, 0x00, 0xe8, 0x46, 0x95, 0xb6, 0x45, 0x7c, 0xe6, 0x96, 0x1f, + 0x8d, 0x9d, 0xe6, 0xdd, 0xa1, 0xee, 0x49, 0x37, 0xab, 0xf6, 0x06, 0x74, 0x30, 0xa1, 0xdc, 0x0e, 0xba, 0x0e, 0x26, + 0x23, 0xdb, 0xf2, 0xcb, 0xbc, 0x5e, 0xe8, 0xe6, 0xd8, 0x61, 0xa8, 0x9d, 0x92, 0xd7, 0xc2, 0x43, 0x64, 0x20, 0x19, + 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0xfd, 0x60, 0xd7, 0x3b, 0x7e, 0x93, 0x0b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x51, + 0x25, 0x9d, 0xcb, 0x05, 0xe3, 0xf3, 0x6a, 0x71, 0x02, 0x6e, 0xe7, 0xf3, 0x6a, 0x11, 0x61, 0x50, 0xbe, 0x0c, 0x62, + 0x95, 0x80, 0xdd, 0x8b, 0x85, 0xf0, 0xed, 0x84, 0x36, 0x30, 0x1b, 0x48, 0xb0, 0x41, 0x61, 0x56, 0x1a, 0xa2, 0xdc, + 0x49, 0x8f, 0x36, 0x88, 0x3c, 0xc4, 0xea, 0x79, 0xdd, 0xf6, 0x64, 0xd3, 0x17, 0x13, 0x5c, 0x65, 0x31, 0x13, 0xd3, + 0xf8, 0x98, 0x95, 0xd3, 0x18, 0x4a, 0x89, 0xd3, 0x34, 0x8c, 0xe9, 0x84, 0x56, 0x84, 0x24, 0x8c, 0xcf, 0xe3, 0x05, + 0x4d, 0x50, 0x4a, 0x10, 0x42, 0xc8, 0x8f, 0x11, 0xda, 0xe6, 0xc0, 0x92, 0x37, 0xdb, 0xcf, 0xd1, 0xcf, 0xed, 0x18, + 0x2e, 0xa3, 0x22, 0x74, 0x83, 0xce, 0x1a, 0xee, 0x8d, 0xa8, 0xa4, 0x31, 0x56, 0x0c, 0x41, 0xc0, 0x4b, 0x8c, 0x4a, + 0x58, 0x92, 0x98, 0xd5, 0x10, 0x45, 0xa0, 0x98, 0xc7, 0x0b, 0x56, 0x52, 0xdf, 0xe6, 0x34, 0x56, 0x26, 0x41, 0x3d, + 0x8b, 0xa5, 0x76, 0x20, 0xa4, 0x0a, 0xb1, 0xc7, 0x67, 0x55, 0x74, 0xa3, 0x0c, 0x0d, 0x00, 0x05, 0x4a, 0xca, 0xc5, + 0x6f, 0x3f, 0xdf, 0xc3, 0x4d, 0x42, 0xff, 0xb3, 0x8d, 0x8e, 0x76, 0x96, 0xcb, 0x43, 0x6f, 0xbe, 0xa0, 0x71, 0x9e, + 0x43, 0x28, 0x36, 0x8d, 0x40, 0x5e, 0x64, 0x35, 0x44, 0xb4, 0xb8, 0x0f, 0x74, 0x48, 0x38, 0x68, 0xd3, 0x2f, 0x90, + 0xea, 0x89, 0xc9, 0xa5, 0x27, 0x06, 0xc6, 0xed, 0x90, 0x09, 0x05, 0x1c, 0xe9, 0x79, 0xf6, 0x97, 0x8f, 0xb1, 0xa6, + 0xa8, 0x99, 0x8e, 0xb7, 0x21, 0x11, 0x0d, 0x5a, 0x10, 0xcd, 0xe0, 0xfd, 0x73, 0xcd, 0xf1, 0xaa, 0x03, 0x3f, 0xe0, + 0x9d, 0x8d, 0x33, 0x2f, 0x67, 0x1e, 0x91, 0x53, 0x1f, 0xe5, 0x88, 0x7e, 0xc9, 0xc3, 0x7a, 0xa4, 0x92, 0x31, 0x56, + 0x12, 0x07, 0xbd, 0x0d, 0x16, 0xcc, 0x09, 0x5d, 0xf1, 0xd0, 0xf0, 0xf1, 0x2f, 0x91, 0xc9, 0xa8, 0x68, 0xa1, 0xd8, + 0x8d, 0xca, 0x60, 0xc4, 0x39, 0x0d, 0x33, 0x34, 0x59, 0xd2, 0xc5, 0x52, 0x91, 0xe6, 0x4a, 0x9a, 0x06, 0xb8, 0x04, + 0x1a, 0x3c, 0x1f, 0xf4, 0x43, 0x43, 0x3d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, 0xfb, 0xd0, 0xe1, 0xff, 0xe7, 0xd8, + 0x05, 0x22, 0xed, 0xcd, 0x75, 0x64, 0x3c, 0xd2, 0x78, 0x38, 0x28, 0xda, 0xc7, 0xde, 0x4f, 0xfc, 0xcc, 0x19, 0x7d, + 0x48, 0x2a, 0xdf, 0xe1, 0x83, 0xe5, 0x8e, 0x37, 0xd5, 0xb3, 0x32, 0x82, 0xf5, 0xb0, 0xdd, 0xe2, 0x82, 0x68, 0xbb, + 0x00, 0x52, 0xc7, 0x78, 0xb5, 0x74, 0x8d, 0x57, 0xe3, 0x3d, 0xc6, 0xab, 0xf6, 0x4c, 0x0d, 0x73, 0xb2, 0x41, 0x7d, + 0x96, 0x94, 0xe7, 0xe7, 0x28, 0x13, 0xf4, 0x5d, 0xce, 0x0a, 0x2a, 0x53, 0x09, 0xed, 0xc5, 0x6e, 0xc6, 0xf8, 0x8e, + 0x60, 0x9c, 0x15, 0x8b, 0x91, 0x40, 0x65, 0x2a, 0x69, 0xc2, 0x5e, 0x09, 0xea, 0x31, 0x78, 0xaf, 0x31, 0x44, 0xb5, + 0x8c, 0x5d, 0xb7, 0x81, 0xd0, 0x50, 0x5b, 0x8f, 0xf6, 0x8c, 0xf5, 0xe8, 0x76, 0x5b, 0x6b, 0x7f, 0x3b, 0xb1, 0x2e, + 0x13, 0x44, 0x15, 0x96, 0xa3, 0x09, 0xf0, 0xa6, 0x89, 0xb9, 0x2d, 0x59, 0xa5, 0x05, 0x86, 0xcf, 0xfe, 0x23, 0x2c, + 0xac, 0x4a, 0xa2, 0x20, 0xb3, 0x22, 0x1a, 0xd8, 0x73, 0xf0, 0x79, 0x5c, 0xc3, 0x1a, 0x80, 0x48, 0x8e, 0xe8, 0xe1, + 0xfa, 0x47, 0x28, 0x6c, 0x66, 0x41, 0x66, 0x02, 0x32, 0xf3, 0x22, 0x6d, 0x67, 0x1d, 0x4c, 0xac, 0x49, 0xad, 0x33, + 0x16, 0x62, 0xa8, 0x91, 0x1f, 0x40, 0x19, 0x62, 0xf1, 0xc9, 0x07, 0x13, 0x2a, 0x64, 0x28, 0x55, 0xaf, 0x9b, 0xdd, + 0xc0, 0x2b, 0x1f, 0xb2, 0x6b, 0x5e, 0xd5, 0xf1, 0xf5, 0x4a, 0x5b, 0x12, 0x73, 0xb6, 0xcf, 0x6d, 0x8f, 0x56, 0xfa, + 0xd5, 0x9b, 0x17, 0xdf, 0x9f, 0x7a, 0xaf, 0x76, 0x11, 0x47, 0x43, 0xb0, 0xad, 0x18, 0x63, 0xf4, 0x16, 0x97, 0x06, + 0x13, 0xe9, 0x1a, 0x81, 0xde, 0xa5, 0xa0, 0xdf, 0xfe, 0x5c, 0x4f, 0xc0, 0x6b, 0xae, 0x96, 0x5f, 0xf2, 0x11, 0xb0, + 0x44, 0xf5, 0xac, 0x30, 0x3b, 0x2b, 0xb3, 0xbd, 0xdd, 0x8a, 0xf4, 0xb4, 0x4b, 0x8d, 0x0c, 0xc4, 0xab, 0xed, 0x30, + 0x16, 0x2e, 0x6c, 0xd3, 0xcd, 0x60, 0xd7, 0x4b, 0xc7, 0x12, 0x79, 0xbb, 0x2d, 0xa0, 0x43, 0x66, 0xc0, 0x9d, 0x97, + 0xf1, 0x1d, 0xbc, 0x2c, 0x9c, 0x6e, 0xfa, 0xc1, 0x13, 0xc0, 0x4c, 0xb8, 0xb4, 0x96, 0xc5, 0x31, 0xe3, 0x09, 0xcc, + 0x1f, 0x2d, 0x7d, 0x91, 0xb7, 0x24, 0xb4, 0x7a, 0x7f, 0x85, 0xd5, 0x08, 0xec, 0x4e, 0xce, 0x3e, 0x66, 0xab, 0xd9, + 0x12, 0x50, 0xf3, 0xaf, 0xb3, 0x02, 0x68, 0xae, 0x59, 0x0b, 0xa6, 0x29, 0xd4, 0x5f, 0xd7, 0xcf, 0xe2, 0x55, 0x9c, + 0x80, 0xea, 0x06, 0xbc, 0x45, 0xee, 0x95, 0xe8, 0x4a, 0xa3, 0x8b, 0xd2, 0x07, 0xca, 0x31, 0xa4, 0xd0, 0xd2, 0xf7, + 0x5e, 0x25, 0xcf, 0x3d, 0x0d, 0xb8, 0xa4, 0x50, 0xf3, 0x64, 0x4b, 0x19, 0x0b, 0x80, 0x85, 0x0e, 0x66, 0x92, 0x6c, + 0x45, 0x77, 0x1a, 0x93, 0x02, 0xde, 0x6a, 0xe0, 0x8f, 0x22, 0xab, 0xe5, 0x5d, 0xb1, 0x0a, 0x0b, 0xc7, 0xfe, 0xba, + 0xdf, 0x8f, 0x1d, 0xfb, 0xeb, 0x4b, 0x45, 0xeb, 0xe2, 0x76, 0x03, 0x48, 0x83, 0x01, 0x44, 0x4e, 0xd5, 0x40, 0xe8, + 0x88, 0x62, 0xbe, 0xef, 0xdf, 0xa9, 0xce, 0x22, 0x41, 0xe8, 0x77, 0xea, 0x75, 0xa4, 0x24, 0xa0, 0x53, 0xab, 0xd9, + 0xc9, 0x40, 0x99, 0x7d, 0x40, 0x40, 0x54, 0x37, 0x23, 0x9b, 0x2f, 0xa4, 0x73, 0xb1, 0x0c, 0x1f, 0x3e, 0xa6, 0x10, + 0x50, 0xb8, 0xa3, 0x46, 0xeb, 0x6d, 0x88, 0x04, 0xca, 0x08, 0x45, 0x8c, 0x79, 0xb1, 0x92, 0x84, 0xcc, 0xc7, 0x0b, + 0x14, 0x5c, 0x59, 0x60, 0x57, 0xce, 0x26, 0xc3, 0x22, 0xe2, 0x2c, 0xdc, 0xff, 0xcd, 0x64, 0x41, 0x50, 0x73, 0xe5, + 0x06, 0x72, 0xdc, 0xc9, 0xe4, 0xed, 0x29, 0xaf, 0x86, 0x8a, 0x89, 0x08, 0x02, 0xc3, 0x0d, 0x3f, 0xe3, 0xe3, 0xa3, + 0x05, 0x01, 0x15, 0x99, 0x31, 0x0b, 0xd1, 0x2f, 0x8e, 0xbf, 0x02, 0xd4, 0x98, 0xd1, 0xd1, 0x53, 0x00, 0x85, 0x85, + 0x80, 0xe8, 0x63, 0x90, 0xd1, 0x56, 0xf0, 0xbb, 0x92, 0xbf, 0x5b, 0x27, 0xbe, 0x0b, 0xfd, 0x5a, 0xd1, 0xcb, 0x18, + 0x18, 0x8e, 0x68, 0x72, 0x18, 0xf2, 0xc1, 0x64, 0x00, 0xda, 0x12, 0x67, 0xf7, 0xb5, 0xb4, 0xe2, 0xfa, 0x74, 0xe9, + 0x74, 0xff, 0xa4, 0x3e, 0x48, 0x22, 0x15, 0xac, 0x90, 0xc4, 0x00, 0x42, 0x59, 0xca, 0x6d, 0xb2, 0x04, 0xcb, 0x0a, + 0xbd, 0xa4, 0xb9, 0x46, 0x49, 0xdc, 0xdd, 0x0c, 0x1c, 0xa3, 0x66, 0x9d, 0x86, 0x45, 0xcb, 0x8d, 0x1a, 0xe0, 0x73, + 0x12, 0x56, 0x9a, 0x1b, 0xce, 0x4c, 0x38, 0x67, 0x3a, 0x5c, 0x1d, 0x73, 0xf6, 0x9a, 0x23, 0x18, 0x47, 0x82, 0x37, + 0x1e, 0xba, 0x64, 0x0a, 0x2a, 0x32, 0x65, 0x1c, 0x4c, 0x7b, 0x80, 0x7b, 0xcf, 0xc1, 0x38, 0x8c, 0x0d, 0x6a, 0x43, + 0xea, 0x53, 0xe7, 0x2e, 0x04, 0x82, 0xb4, 0xd6, 0xcb, 0x7c, 0x86, 0xa7, 0x67, 0x84, 0xb2, 0x3f, 0xe4, 0xf0, 0x01, + 0xf0, 0xb2, 0x24, 0x27, 0x13, 0xfe, 0xf4, 0xf1, 0x6e, 0xa0, 0x2a, 0x3e, 0x08, 0x0e, 0xe2, 0x22, 0x3d, 0x08, 0x06, + 0x15, 0xfc, 0x2a, 0xf9, 0x41, 0x2d, 0xc4, 0xc1, 0x65, 0x5c, 0x1e, 0xc4, 0xab, 0xb8, 0xac, 0x0f, 0x6e, 0xb3, 0x7a, + 0x79, 0xa0, 0x3b, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x07, 0xc1, 0xa0, 0xd4, 0x53, 0xbb, 0x62, 0x85, 0x77, + 0x9c, 0xe9, 0x10, 0x65, 0x81, 0x1f, 0x20, 0xcc, 0x3b, 0x0d, 0x80, 0x4f, 0x5d, 0xb3, 0x94, 0x5e, 0x62, 0xb8, 0x81, + 0x6a, 0xba, 0x86, 0x3e, 0x00, 0x8f, 0xbc, 0xa6, 0x31, 0x2c, 0x81, 0xcb, 0xc1, 0x80, 0xac, 0x21, 0x72, 0xc1, 0x9a, + 0x9a, 0x20, 0x0e, 0xe1, 0x5a, 0xda, 0x69, 0x17, 0x3b, 0x14, 0x76, 0xbb, 0x05, 0x44, 0xe5, 0x09, 0xe9, 0xf7, 0xcd, + 0x37, 0xd4, 0xbd, 0x60, 0x2f, 0xc1, 0xfe, 0xaa, 0xac, 0xc3, 0x44, 0x48, 0xcd, 0xf7, 0x15, 0x3b, 0x19, 0xc8, 0x88, + 0xc3, 0x3b, 0x8e, 0x14, 0x6d, 0x54, 0x2e, 0xc3, 0x9e, 0x2c, 0x3d, 0x5f, 0x89, 0x6b, 0x6e, 0xfd, 0xb8, 0x6a, 0x21, + 0xf2, 0x3a, 0x5b, 0x49, 0xf6, 0x6f, 0xc6, 0x15, 0xf7, 0x07, 0xd6, 0x9f, 0xfe, 0x2b, 0xb8, 0xb6, 0x3a, 0xef, 0x7c, + 0xae, 0x11, 0x39, 0x4b, 0x28, 0x97, 0x34, 0x26, 0x0f, 0x6f, 0xe9, 0xfb, 0xdc, 0xea, 0xdb, 0x4c, 0xa7, 0xf6, 0x59, + 0x85, 0x85, 0x0b, 0xd1, 0x8a, 0xe0, 0xd0, 0x10, 0x0b, 0xff, 0x08, 0xd0, 0xd7, 0x3e, 0x53, 0x41, 0x49, 0x9a, 0xf3, + 0x1a, 0xbd, 0x5b, 0x21, 0xe1, 0xa5, 0x62, 0x97, 0x1e, 0x06, 0x52, 0xc6, 0xed, 0xa1, 0x24, 0x4c, 0x4a, 0x5e, 0x84, + 0xf7, 0x5e, 0x7d, 0x93, 0x7b, 0x1e, 0x62, 0xf4, 0x22, 0xc7, 0x4e, 0x40, 0x5b, 0x77, 0x89, 0xce, 0x86, 0x27, 0x6e, + 0xc3, 0x73, 0xd6, 0xa2, 0xd1, 0x74, 0xc9, 0x92, 0x7e, 0x3f, 0x06, 0x13, 0xef, 0x94, 0xe5, 0xf0, 0x2b, 0x5f, 0xd0, + 0x35, 0x03, 0x4c, 0x31, 0x7a, 0x09, 0x09, 0x29, 0x22, 0x91, 0xac, 0xe5, 0x49, 0xf2, 0x89, 0xee, 0x42, 0x70, 0x84, + 0xcb, 0x59, 0x1a, 0x2d, 0xf7, 0x9a, 0x59, 0x20, 0x79, 0x86, 0xbe, 0xab, 0x60, 0x7b, 0x63, 0x17, 0xa4, 0x9c, 0x1f, + 0x57, 0xd3, 0xc1, 0x80, 0x13, 0x05, 0x37, 0x5e, 0x48, 0x71, 0xad, 0x6a, 0x71, 0xc7, 0x30, 0x16, 0xea, 0xb6, 0x88, + 0xc1, 0x01, 0xbb, 0x68, 0x65, 0xb7, 0x0f, 0xb0, 0xab, 0x1c, 0xef, 0x52, 0x65, 0x77, 0x7a, 0xcc, 0xf8, 0xcb, 0x56, + 0x91, 0x4e, 0x5a, 0xed, 0x27, 0xf2, 0x3e, 0x77, 0xd0, 0xe5, 0x72, 0xac, 0x78, 0xcb, 0x41, 0x45, 0x1e, 0xf3, 0x91, + 0xa4, 0xba, 0x9f, 0xe1, 0x08, 0xf3, 0x60, 0xdd, 0xfa, 0x93, 0x43, 0x5d, 0xe0, 0x10, 0x79, 0x52, 0xaf, 0x29, 0xa0, + 0x7b, 0xaf, 0x1e, 0x77, 0xf5, 0xdb, 0xd0, 0x5d, 0xa0, 0x44, 0x3b, 0x15, 0x7b, 0x7e, 0x4c, 0xd4, 0xea, 0x4c, 0x3d, + 0xa1, 0x7f, 0xad, 0xc5, 0xfd, 0x85, 0x76, 0x15, 0xf7, 0xbd, 0xcb, 0x67, 0x1c, 0xea, 0xec, 0x86, 0x50, 0x00, 0xae, + 0xda, 0xd1, 0xa9, 0x6b, 0x43, 0x7a, 0xa9, 0x44, 0x37, 0xc1, 0xc1, 0xf6, 0xfa, 0x8c, 0xa3, 0xe8, 0x47, 0xab, 0x91, + 0x6f, 0xa3, 0xea, 0xb1, 0x18, 0xc4, 0x8f, 0x4b, 0xba, 0x8c, 0xaa, 0xc7, 0xe5, 0x20, 0x7e, 0x2c, 0x9a, 0x66, 0xf7, + 0x5c, 0xd9, 0xdf, 0x47, 0xe4, 0x59, 0x77, 0xf6, 0x52, 0x01, 0x1b, 0x03, 0xcf, 0xae, 0x05, 0x84, 0x53, 0x70, 0x44, + 0xb6, 0x86, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x61, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, 0x59, 0xff, 0xe8, + 0xc3, 0x29, 0x10, 0xd0, 0xed, 0xb6, 0x59, 0x57, 0x6b, 0x40, 0x31, 0x0d, 0xc7, 0xfc, 0xb0, 0x1c, 0xdd, 0xba, 0xee, + 0xfa, 0x87, 0xe5, 0x68, 0x49, 0x86, 0x13, 0x3d, 0xf9, 0xf1, 0xc9, 0x78, 0x16, 0x47, 0x93, 0xa6, 0xe3, 0xb4, 0x50, + 0xf8, 0xa7, 0xce, 0x2d, 0x14, 0x81, 0x53, 0x31, 0x82, 0x23, 0xa7, 0xca, 0x49, 0xc9, 0xc3, 0xf0, 0x3f, 0xa8, 0x77, + 0xb4, 0x69, 0xaf, 0xe3, 0x3a, 0x59, 0x66, 0xc5, 0x95, 0x0a, 0x1f, 0xae, 0xa2, 0x8b, 0x9b, 0x80, 0x76, 0xce, 0x65, + 0xda, 0xf2, 0xeb, 0xc4, 0xa3, 0x27, 0xb6, 0x66, 0x06, 0xdc, 0xba, 0x1b, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, + 0xc4, 0xdc, 0xfe, 0x55, 0xda, 0xfc, 0x4a, 0xda, 0x67, 0xc9, 0x48, 0xd1, 0x26, 0x23, 0x35, 0x18, 0x61, 0x8a, 0x22, + 0x89, 0xeb, 0xb0, 0x80, 0x20, 0xd8, 0x9f, 0x51, 0x5c, 0x8b, 0xa5, 0x77, 0x1a, 0x84, 0x09, 0xa6, 0x0b, 0xca, 0xaf, + 0x6e, 0xe7, 0xb6, 0xd2, 0x62, 0x8f, 0xe4, 0xf7, 0xb9, 0xb5, 0x5d, 0x51, 0xe4, 0xef, 0xf3, 0x06, 0xd4, 0x03, 0xa2, + 0xdc, 0xd7, 0x47, 0x29, 0x70, 0xd2, 0xe2, 0x86, 0x02, 0xa3, 0x17, 0x74, 0x75, 0x22, 0x77, 0xec, 0xd4, 0x9c, 0xa9, + 0x98, 0xc9, 0xb8, 0xf2, 0x7e, 0xcf, 0xdc, 0x07, 0x4d, 0x41, 0x2b, 0x30, 0xf0, 0xd6, 0x67, 0x3c, 0x3a, 0xd0, 0xdd, + 0x6a, 0x9d, 0x16, 0x6c, 0x16, 0xd4, 0x65, 0xdd, 0xb6, 0xf1, 0xa0, 0x11, 0x07, 0x45, 0xb2, 0x2a, 0x54, 0x4b, 0x78, + 0x22, 0x10, 0x30, 0x65, 0xd7, 0x3c, 0xd2, 0x82, 0x9a, 0xde, 0x84, 0xc2, 0x86, 0x82, 0xbf, 0x52, 0x54, 0xd3, 0x9b, + 0x50, 0x9f, 0x89, 0x53, 0x0c, 0x22, 0x98, 0x11, 0x9b, 0xfd, 0x16, 0x50, 0x7f, 0x6b, 0x46, 0x9b, 0xa6, 0x31, 0xda, + 0x2a, 0xe4, 0x92, 0x22, 0x69, 0xf9, 0x6f, 0xd5, 0x54, 0x50, 0x52, 0xcb, 0x45, 0x6f, 0xe2, 0xbb, 0xe8, 0xf1, 0x4c, + 0x4b, 0x02, 0xa5, 0x5b, 0xee, 0x18, 0xfd, 0x21, 0x0c, 0xf0, 0x88, 0x8e, 0x13, 0x0b, 0xe6, 0x56, 0x27, 0x2c, 0x9b, + 0x57, 0x8b, 0xd1, 0x4a, 0x40, 0xd8, 0xe0, 0x63, 0x96, 0xcd, 0x0b, 0xf5, 0x10, 0xba, 0xc2, 0xd2, 0xb7, 0x60, 0x17, + 0x1b, 0xac, 0x44, 0x15, 0x80, 0xef, 0x05, 0xdd, 0xac, 0x44, 0x15, 0x09, 0xd9, 0xfd, 0xb8, 0xc1, 0x12, 0x64, 0x5a, + 0x29, 0xd3, 0x92, 0x06, 0x0b, 0x02, 0x5f, 0x55, 0x55, 0x3e, 0x24, 0xdb, 0x0a, 0xe4, 0x53, 0x47, 0x0d, 0x38, 0x05, + 0xb2, 0x0a, 0x2c, 0x48, 0x80, 0xca, 0xd0, 0x56, 0x81, 0x69, 0x25, 0xa6, 0xe9, 0x2a, 0x6c, 0x94, 0xd9, 0xa1, 0xd0, + 0xeb, 0x25, 0x9f, 0xc5, 0x83, 0x30, 0x19, 0xc6, 0xe4, 0x31, 0x42, 0xed, 0x1f, 0xe6, 0x51, 0xac, 0xe4, 0x92, 0x2b, + 0xeb, 0x17, 0x7f, 0xfb, 0x09, 0x7b, 0xdd, 0x73, 0x0c, 0x16, 0x60, 0x2d, 0x6d, 0xaf, 0xb3, 0xe2, 0x9d, 0x68, 0x05, + 0xc7, 0xc1, 0x2c, 0xd2, 0x61, 0xd5, 0x91, 0x23, 0xea, 0x8b, 0x5c, 0x7b, 0x17, 0x21, 0x72, 0x90, 0xde, 0x63, 0x80, + 0xdd, 0x08, 0x5f, 0x87, 0xc6, 0xe6, 0x56, 0x55, 0x88, 0xbf, 0x51, 0x22, 0xf1, 0x93, 0x10, 0x1f, 0xd7, 0x2b, 0x99, + 0xab, 0xd6, 0x78, 0xac, 0xaa, 0x19, 0x3c, 0x53, 0xbe, 0xc7, 0xca, 0xbf, 0xb5, 0xdd, 0x1c, 0xe7, 0x3d, 0x78, 0xd0, + 0xba, 0xdf, 0x3a, 0x12, 0x42, 0x73, 0xe5, 0x24, 0x4d, 0x47, 0x8d, 0x8e, 0x99, 0xac, 0x16, 0x95, 0x30, 0xb9, 0x3b, + 0xa5, 0x63, 0xa0, 0xa2, 0x03, 0xb8, 0x96, 0xa8, 0x0e, 0x7a, 0x52, 0xb2, 0x31, 0x1c, 0x71, 0x06, 0x07, 0xed, 0x38, + 0x46, 0xf1, 0x72, 0x2e, 0xc5, 0xcb, 0xf9, 0x09, 0xe3, 0x00, 0xad, 0x05, 0x48, 0xf5, 0x0a, 0xf6, 0x33, 0x97, 0xb0, + 0xc0, 0xfa, 0xce, 0x77, 0x64, 0x80, 0x0c, 0x71, 0xb2, 0x39, 0x4e, 0xf6, 0xb8, 0x51, 0x73, 0x5f, 0xe1, 0xe3, 0xa4, + 0x59, 0x38, 0x75, 0x15, 0xed, 0xba, 0x96, 0xac, 0x98, 0x97, 0x83, 0x09, 0x04, 0x65, 0x29, 0xe6, 0xe5, 0x70, 0xb2, + 0xa0, 0x39, 0xfc, 0x58, 0x78, 0xe8, 0x10, 0xcb, 0x41, 0x02, 0x97, 0xce, 0x1e, 0x03, 0xde, 0x50, 0x28, 0x71, 0x37, + 0xd6, 0x91, 0x63, 0x1d, 0xe5, 0x61, 0x18, 0x03, 0xae, 0xac, 0x15, 0x78, 0xef, 0xbf, 0x3e, 0xfa, 0x80, 0xac, 0xca, + 0x15, 0x5e, 0x8e, 0x72, 0xd7, 0x95, 0x46, 0x5d, 0x52, 0x7a, 0x95, 0x13, 0x3c, 0x95, 0x6c, 0xb7, 0x3d, 0x63, 0x4f, + 0xe5, 0x20, 0xf1, 0x8e, 0x11, 0xbd, 0x98, 0x7a, 0x99, 0x39, 0x81, 0x33, 0xdb, 0x5e, 0xb6, 0x31, 0x3f, 0x76, 0x80, + 0x83, 0x45, 0x10, 0x12, 0x37, 0x84, 0x61, 0x62, 0x27, 0xc5, 0x50, 0x09, 0xe1, 0xba, 0x16, 0x5e, 0xc7, 0x69, 0x19, + 0x83, 0x8b, 0xb4, 0xb2, 0x4d, 0xdc, 0x43, 0xd7, 0x1d, 0x3f, 0xe6, 0x56, 0xc7, 0x68, 0xcb, 0x7c, 0xb8, 0xa3, 0xd3, + 0x07, 0x16, 0x03, 0x50, 0xf7, 0x60, 0x56, 0xb7, 0xcf, 0x24, 0xae, 0x4f, 0xbb, 0x8a, 0x90, 0x08, 0x44, 0x51, 0x2a, + 0x23, 0x4c, 0xff, 0x4e, 0x73, 0x59, 0x4d, 0xeb, 0x07, 0x79, 0xe6, 0x90, 0x67, 0xa1, 0xb3, 0x3d, 0x68, 0xed, 0xef, + 0x06, 0xed, 0xc4, 0x6d, 0xf7, 0xce, 0xff, 0x5b, 0xd6, 0xb5, 0xd5, 0x9a, 0xea, 0x71, 0xbb, 0xfa, 0x81, 0xb7, 0x57, + 0x7b, 0x32, 0x06, 0xcc, 0x4a, 0x38, 0x67, 0x54, 0xc5, 0xcb, 0x8c, 0x57, 0x78, 0x52, 0xad, 0x3c, 0x1f, 0xef, 0xdb, + 0x6c, 0xa4, 0x1f, 0xc8, 0x14, 0x10, 0xcf, 0x6f, 0x53, 0xad, 0x3e, 0x4e, 0x51, 0x02, 0xfe, 0x4e, 0xc5, 0x37, 0xa2, + 0x1f, 0xcd, 0x8b, 0x2b, 0x5e, 0xbf, 0xbd, 0x2d, 0xf4, 0x8b, 0xe7, 0x46, 0xe7, 0x4f, 0x5f, 0x97, 0x2e, 0x74, 0x38, + 0x6a, 0xef, 0xa0, 0xc8, 0x82, 0x55, 0x27, 0x13, 0x2d, 0x6b, 0xab, 0x66, 0x1f, 0x25, 0x5c, 0x4c, 0x54, 0xa3, 0x67, + 0x9d, 0x39, 0x61, 0x4a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x96, 0x0c, 0xd4, 0x69, 0x52, 0x88, 0x1e, 0x56, 0x33, + 0x8c, 0x57, 0x0c, 0xa0, 0x30, 0xa5, 0x04, 0x51, 0xb4, 0x06, 0xc1, 0x40, 0x13, 0xfa, 0xfd, 0xdb, 0x54, 0x65, 0xa0, + 0x45, 0x33, 0x15, 0x20, 0xaa, 0x83, 0x68, 0xab, 0xbc, 0x0c, 0x7f, 0x5c, 0xd2, 0x22, 0xa3, 0x79, 0x45, 0x97, 0x15, + 0x4d, 0x32, 0x7a, 0xc9, 0xa5, 0xa8, 0x78, 0x5d, 0x31, 0x49, 0xdb, 0x35, 0x61, 0xff, 0x97, 0x47, 0xd7, 0x5b, 0xb1, + 0xd6, 0xd0, 0xee, 0x04, 0x19, 0xa1, 0xf9, 0x42, 0x05, 0x21, 0x43, 0xe5, 0x24, 0x74, 0xad, 0x56, 0x78, 0x05, 0x36, + 0x99, 0x66, 0xa3, 0x65, 0x5c, 0x85, 0x81, 0xf9, 0x2a, 0x30, 0x98, 0x1c, 0x98, 0x74, 0xb6, 0xbe, 0x78, 0x26, 0xae, + 0x57, 0xa2, 0xe0, 0x45, 0x2d, 0x21, 0xfa, 0x35, 0xee, 0xbb, 0x8e, 0xab, 0xce, 0xfc, 0x5a, 0xe9, 0x43, 0xdf, 0xba, + 0xac, 0x8d, 0xfd, 0x42, 0xe3, 0x18, 0xec, 0x7c, 0x44, 0x34, 0xa4, 0x41, 0xad, 0x5a, 0x1c, 0xea, 0x00, 0x5d, 0x2a, + 0xa4, 0x90, 0x21, 0x53, 0x99, 0x2c, 0x41, 0xc6, 0x37, 0x7e, 0x2f, 0x44, 0x3d, 0xfa, 0x73, 0xcd, 0xcb, 0xfb, 0x33, + 0x9e, 0x73, 0x1c, 0xa3, 0x20, 0x89, 0x8b, 0x9b, 0xb8, 0x0a, 0x88, 0x6b, 0x79, 0x15, 0x1c, 0xa5, 0x3a, 0x6c, 0xcc, + 0x4e, 0xd5, 0xa8, 0xf5, 0x12, 0xe8, 0x2b, 0x23, 0x7d, 0x63, 0x30, 0x34, 0x11, 0x95, 0xd0, 0xf7, 0x4a, 0xdd, 0xd3, + 0xea, 0x86, 0x01, 0xc4, 0x9f, 0x4b, 0xbd, 0x50, 0xeb, 0xb5, 0x1f, 0x73, 0x43, 0x47, 0x08, 0x1a, 0x7d, 0xd5, 0x2c, + 0x1a, 0xc7, 0x2d, 0x4d, 0x46, 0xc6, 0x8d, 0x36, 0x39, 0xbf, 0x02, 0x19, 0x9f, 0x35, 0x17, 0x9a, 0x34, 0x0d, 0x95, + 0x50, 0x85, 0xd1, 0xe6, 0xce, 0x4b, 0xa7, 0xf7, 0xe0, 0xce, 0xa6, 0xcd, 0x8e, 0x94, 0x4b, 0x63, 0x43, 0x4b, 0x5e, + 0xad, 0x44, 0x51, 0x41, 0x18, 0xe7, 0xde, 0x98, 0x5e, 0xc7, 0x59, 0x51, 0xc7, 0x59, 0x71, 0x5a, 0xad, 0x78, 0x52, + 0xbf, 0x87, 0x5b, 0x9c, 0xb4, 0xba, 0x69, 0x2a, 0xb8, 0xd2, 0x25, 0x07, 0x18, 0x4c, 0x4d, 0xc6, 0x3d, 0xb6, 0x06, + 0x17, 0xf5, 0xef, 0xd1, 0x52, 0x60, 0x2c, 0x54, 0x55, 0x7c, 0x7c, 0x51, 0x89, 0x7c, 0x5d, 0x83, 0x76, 0xf7, 0xb2, + 0x8e, 0x8e, 0x9e, 0xac, 0xee, 0xa6, 0xf2, 0x06, 0x13, 0x3d, 0x39, 0x5a, 0xdd, 0xf5, 0xb2, 0xeb, 0x95, 0x28, 0xeb, + 0xb8, 0xa8, 0xa7, 0x12, 0x91, 0x2c, 0x89, 0xf3, 0x24, 0x9c, 0x8c, 0xc7, 0x5f, 0x1c, 0x0c, 0x0f, 0x20, 0x03, 0x99, + 0xfe, 0x35, 0x94, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x15, 0xf2, 0x6e, 0x17, 0x8d, 0x26, 0x0d, 0xd6, 0x33, 0x4c, + 0xd4, 0xcc, 0x8c, 0xf8, 0xdd, 0x2a, 0x2e, 0x52, 0x88, 0x5f, 0xa7, 0x8a, 0x3f, 0x7a, 0x32, 0xf6, 0xca, 0x37, 0x9f, + 0x3e, 0x6d, 0x7e, 0x6f, 0x74, 0x58, 0x6b, 0xdd, 0xee, 0x67, 0xbf, 0x1f, 0xcb, 0xf9, 0x3e, 0x39, 0x3e, 0x54, 0x3f, + 0x7e, 0x6f, 0x9a, 0xe9, 0xeb, 0x32, 0x9c, 0xff, 0x33, 0x94, 0xf3, 0x79, 0x5a, 0x96, 0xf1, 0x7d, 0x43, 0x16, 0x74, + 0x5d, 0x59, 0x6f, 0x12, 0xea, 0x6c, 0x03, 0x7a, 0x44, 0xa6, 0xeb, 0x8a, 0xc1, 0x37, 0xef, 0xeb, 0x30, 0xe0, 0xd5, + 0x6a, 0xc8, 0x8b, 0x3a, 0xab, 0xef, 0x87, 0x98, 0x27, 0xc0, 0x4f, 0x35, 0x6f, 0xf6, 0xac, 0xd4, 0xc4, 0xe6, 0xb2, + 0xe4, 0xfc, 0x2f, 0x1e, 0x4a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1c, 0x8c, 0xc9, 0xd7, 0x54, 0x75, 0x66, + 0xf2, 0x35, 0x98, 0x20, 0x65, 0xed, 0x6f, 0xa4, 0x71, 0x62, 0x34, 0xa6, 0x37, 0x2f, 0xf3, 0x6c, 0x05, 0x4c, 0xf0, + 0x52, 0xfd, 0x68, 0x08, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xb3, 0x92, 0x8e, 0x46, 0xa3, 0x8f, 0x59, 0x43, + 0xe8, 0x65, 0xd5, 0xf1, 0xfe, 0x3d, 0xa7, 0x17, 0x22, 0xbd, 0x8f, 0x82, 0x80, 0x2e, 0xb3, 0x34, 0xe5, 0x85, 0x2c, + 0xeb, 0x2c, 0x6d, 0xe7, 0x95, 0x2d, 0x44, 0xe0, 0x1f, 0xd5, 0x46, 0x84, 0x20, 0x22, 0xf4, 0xed, 0x4e, 0xcf, 0x46, + 0xa3, 0xd1, 0x59, 0xaa, 0xab, 0xb5, 0x0c, 0xf9, 0x6b, 0x34, 0x1f, 0xb0, 0x76, 0xf9, 0x60, 0x7d, 0xa3, 0xa3, 0x9d, + 0x1c, 0xfe, 0xf7, 0x70, 0x36, 0x1f, 0x0f, 0xbf, 0x1d, 0x2d, 0x1e, 0x1f, 0xd2, 0x20, 0x70, 0x41, 0xab, 0x43, 0x65, + 0xcd, 0x31, 0x2d, 0x8e, 0xc7, 0x53, 0x52, 0x0c, 0xd8, 0x13, 0xe3, 0x4b, 0xf3, 0xc5, 0x13, 0x40, 0x22, 0x45, 0x11, + 0x6a, 0x60, 0xa5, 0x7f, 0x78, 0x15, 0x79, 0x55, 0x00, 0x3e, 0x9a, 0x89, 0x64, 0xa0, 0xb5, 0x80, 0xe3, 0x08, 0xca, + 0x6b, 0x8c, 0x69, 0x44, 0x8f, 0xb1, 0x4c, 0x47, 0x05, 0x1d, 0x4f, 0xab, 0xdb, 0xac, 0x4e, 0x96, 0x18, 0xd8, 0x28, + 0xae, 0x78, 0xf0, 0x45, 0x10, 0x15, 0xec, 0xe8, 0xe9, 0x54, 0xc2, 0xfb, 0x62, 0x52, 0xca, 0xaf, 0x20, 0xf1, 0xdb, + 0x31, 0x42, 0xa0, 0x12, 0xe5, 0xb1, 0x88, 0x35, 0xbe, 0xcc, 0x45, 0x0c, 0x1e, 0x9c, 0x95, 0xe2, 0x59, 0xcc, 0x49, + 0x60, 0xec, 0x2f, 0x5a, 0xcd, 0x11, 0xd0, 0x9c, 0x50, 0x30, 0x71, 0x58, 0x50, 0xf1, 0xc5, 0x04, 0xbd, 0x82, 0xc0, + 0xad, 0x3a, 0x82, 0xe3, 0xce, 0x58, 0x36, 0xa8, 0xe5, 0x93, 0xb2, 0xc3, 0xf9, 0xff, 0xae, 0xe8, 0x62, 0x70, 0x68, + 0x87, 0xe6, 0xad, 0x72, 0x5f, 0xad, 0x91, 0x51, 0xaa, 0xc3, 0x67, 0x29, 0x31, 0xc6, 0xa7, 0x9c, 0x9d, 0x6c, 0x74, + 0x77, 0x46, 0x75, 0x99, 0x5d, 0x87, 0x44, 0xf5, 0xca, 0x82, 0x62, 0x06, 0x51, 0x36, 0xc2, 0xf5, 0x03, 0xd6, 0x22, + 0x4e, 0x27, 0x6f, 0x78, 0x59, 0x67, 0x89, 0x7c, 0x7f, 0xe3, 0xbd, 0x07, 0x6a, 0x20, 0x1b, 0xf4, 0xae, 0x64, 0x30, + 0xcf, 0x6f, 0x4b, 0x00, 0xed, 0xac, 0x78, 0x79, 0xc3, 0x5d, 0xba, 0x11, 0x04, 0x8d, 0x6d, 0xe6, 0x95, 0x17, 0x6c, + 0x02, 0xbe, 0x7a, 0x57, 0x02, 0xe6, 0x46, 0x08, 0x52, 0x53, 0x08, 0x85, 0x03, 0x17, 0xf8, 0xba, 0x2e, 0xb3, 0x8b, + 0x75, 0xcd, 0x31, 0xd8, 0x47, 0x61, 0xb5, 0x98, 0xd2, 0x09, 0x8f, 0x87, 0x01, 0xfe, 0x08, 0xa8, 0x0c, 0xb8, 0xa1, + 0x3d, 0xec, 0xe0, 0x85, 0xfc, 0x65, 0xdf, 0xc8, 0x3d, 0xc2, 0x5e, 0xa7, 0x21, 0x04, 0xd7, 0xc1, 0x87, 0x00, 0x96, + 0x14, 0xa1, 0x6f, 0xf1, 0x54, 0x0d, 0x83, 0xcb, 0x3c, 0x5b, 0xa9, 0xa4, 0x7a, 0xd4, 0xd1, 0x7c, 0x28, 0xb5, 0x23, + 0x39, 0xa0, 0x4e, 0x7a, 0x8c, 0xe9, 0xa5, 0x4c, 0x97, 0x45, 0x59, 0x23, 0x94, 0x77, 0x6a, 0x62, 0x6c, 0x98, 0x3e, + 0x0e, 0x91, 0x5f, 0xde, 0x95, 0x32, 0xf4, 0x0b, 0x5f, 0x00, 0xf8, 0x15, 0xdc, 0xee, 0x77, 0xe3, 0xbb, 0xc8, 0xec, + 0xe7, 0x9c, 0x1d, 0xfe, 0xf7, 0x3c, 0x1e, 0xfe, 0x35, 0x1e, 0x7e, 0xbb, 0x18, 0x84, 0x43, 0xf3, 0x93, 0x3c, 0x7e, + 0x74, 0x48, 0x5f, 0x72, 0xc3, 0x95, 0xc0, 0xc2, 0xf7, 0x82, 0xdb, 0xc8, 0x95, 0x10, 0x44, 0x01, 0xde, 0x28, 0xec, + 0x6a, 0x9c, 0x00, 0xc0, 0x5f, 0xf0, 0x5f, 0x01, 0x1a, 0x09, 0xd9, 0x8b, 0x06, 0xe8, 0x07, 0xe4, 0xef, 0x93, 0xaf, + 0x3c, 0x03, 0x39, 0x10, 0x4f, 0xc8, 0x18, 0x28, 0x44, 0x95, 0x31, 0x91, 0xb0, 0xbf, 0x26, 0xfb, 0x76, 0xdb, 0x6b, + 0x4b, 0x7e, 0xf0, 0x4b, 0x37, 0xd3, 0x44, 0xcf, 0x3b, 0xdc, 0x50, 0x56, 0x62, 0x15, 0x22, 0x36, 0x9e, 0xfa, 0x95, + 0x33, 0x88, 0x35, 0x79, 0x93, 0x81, 0x0f, 0x83, 0xf9, 0x62, 0x3c, 0x03, 0x69, 0x11, 0xdc, 0x71, 0x4a, 0x7e, 0x99, + 0x81, 0x5b, 0x73, 0x11, 0xe3, 0x05, 0xdb, 0x2c, 0x89, 0x7e, 0xbf, 0x97, 0x67, 0x61, 0xae, 0x70, 0x96, 0xf3, 0x46, + 0x8b, 0xdd, 0x51, 0x27, 0x0c, 0xe2, 0x76, 0x35, 0x04, 0x43, 0x39, 0x04, 0x65, 0x47, 0x5b, 0x6c, 0xbd, 0xa6, 0x9e, + 0x52, 0xf7, 0x56, 0xd6, 0x57, 0x8e, 0xfe, 0x10, 0x59, 0x81, 0x85, 0xb4, 0x6b, 0x8e, 0x55, 0xcd, 0x31, 0xd2, 0x9e, + 0x7e, 0xbf, 0xf2, 0xc8, 0x4f, 0x67, 0xe1, 0x41, 0x20, 0x4b, 0x15, 0x3b, 0x65, 0x51, 0x6e, 0x4a, 0x73, 0xc6, 0xb0, + 0xa1, 0x79, 0x66, 0xe2, 0xba, 0xcc, 0x7a, 0xbd, 0x30, 0x44, 0x87, 0x46, 0x2c, 0x15, 0x6b, 0x83, 0xf0, 0x3e, 0x3a, + 0x61, 0x74, 0x0d, 0xb2, 0xba, 0xf0, 0x9c, 0x13, 0xe4, 0xcb, 0xc0, 0x64, 0x4d, 0x56, 0xeb, 0xe4, 0x84, 0x47, 0x2f, + 0x5f, 0x36, 0x82, 0x06, 0x39, 0x49, 0x51, 0x6f, 0x62, 0x77, 0xec, 0xa3, 0x16, 0x52, 0xe3, 0xa6, 0x99, 0xf6, 0x14, + 0xa9, 0xe8, 0xb1, 0x5e, 0x2d, 0x7f, 0x81, 0x65, 0x81, 0x21, 0x1f, 0x84, 0xf6, 0x14, 0xad, 0xc0, 0x0c, 0x37, 0x26, + 0x83, 0xa6, 0x1f, 0x16, 0x6d, 0x11, 0x3a, 0x23, 0xb7, 0x25, 0x84, 0x6d, 0x1b, 0x84, 0xb5, 0xf3, 0x44, 0xbe, 0x78, + 0xe2, 0x30, 0xc2, 0x21, 0xd7, 0x9b, 0xb9, 0xf2, 0x30, 0xcc, 0xaf, 0x85, 0xdf, 0x3c, 0xd5, 0x5c, 0x27, 0x2a, 0x66, + 0x05, 0xdb, 0xed, 0xb2, 0x22, 0xf8, 0xf7, 0x63, 0x36, 0xc3, 0xbf, 0x59, 0xbf, 0xdf, 0x0b, 0xf1, 0x17, 0xc7, 0xe0, + 0x3d, 0xf3, 0x6a, 0xc1, 0x3e, 0x82, 0x4c, 0x85, 0x44, 0x98, 0x2a, 0x8d, 0xdf, 0x58, 0x0d, 0x16, 0x70, 0xfa, 0x03, + 0x99, 0x0b, 0x33, 0x99, 0xcb, 0x8b, 0x6d, 0xc8, 0x69, 0x6b, 0x9c, 0xb2, 0x51, 0x96, 0x48, 0xd7, 0x85, 0x6c, 0x14, + 0xe7, 0x59, 0x5c, 0xf1, 0x6a, 0xbb, 0x55, 0x87, 0x63, 0x52, 0x72, 0xf4, 0x2b, 0x40, 0x2a, 0x55, 0xb0, 0x8e, 0x54, + 0x3b, 0xfe, 0x22, 0x2c, 0x71, 0x9f, 0xf2, 0x79, 0xb9, 0x30, 0x7b, 0x6b, 0x5e, 0x2e, 0x98, 0xbc, 0x95, 0xf6, 0xc2, + 0x12, 0x9a, 0x57, 0x10, 0xb2, 0xc1, 0x54, 0xc7, 0xa2, 0x35, 0x66, 0xd5, 0xbc, 0x5c, 0x40, 0x18, 0x99, 0x72, 0x01, + 0x36, 0x53, 0xbc, 0x00, 0x2f, 0x92, 0x18, 0x60, 0xe2, 0x62, 0x32, 0x85, 0x78, 0xe6, 0xb2, 0x9c, 0x78, 0xa1, 0xef, + 0x97, 0x89, 0x45, 0xca, 0x80, 0x57, 0x8d, 0x46, 0x13, 0x33, 0x0d, 0x47, 0x9d, 0x20, 0x27, 0x3a, 0xbf, 0x9b, 0x5a, + 0x11, 0x62, 0x4f, 0x1c, 0x01, 0x97, 0x15, 0xd3, 0x85, 0x17, 0x1d, 0x88, 0x31, 0x72, 0x70, 0x8a, 0x4f, 0x0c, 0x8e, + 0xc2, 0xe0, 0xdc, 0x38, 0x27, 0x48, 0x19, 0xc6, 0x64, 0x23, 0xd8, 0xb5, 0x08, 0xab, 0x79, 0xbc, 0x00, 0x65, 0x5d, + 0xbc, 0x00, 0xcb, 0x1a, 0x6d, 0x80, 0x09, 0xf2, 0x2a, 0xee, 0x84, 0x7e, 0xa2, 0xb8, 0x42, 0x84, 0x63, 0xe5, 0xfa, + 0xa8, 0x6c, 0x87, 0xbe, 0xc0, 0xeb, 0xbd, 0x34, 0xc7, 0xcd, 0x7a, 0x2c, 0x10, 0xd8, 0x10, 0x30, 0x36, 0x52, 0x69, + 0xb2, 0xb5, 0xf6, 0x8d, 0x9e, 0x07, 0x3e, 0xcd, 0x46, 0x85, 0xa8, 0xcf, 0x2f, 0x41, 0x84, 0xe2, 0xa2, 0xc1, 0x23, + 0xbf, 0x88, 0x3b, 0x4b, 0xbf, 0x35, 0x2d, 0x2a, 0xd8, 0xc9, 0x06, 0x40, 0xfa, 0x54, 0xb4, 0x28, 0x29, 0xa7, 0x28, + 0x48, 0x63, 0x37, 0x05, 0xac, 0x24, 0x77, 0x01, 0x43, 0xb0, 0xb1, 0x83, 0xca, 0xea, 0x14, 0x11, 0x49, 0x02, 0x91, + 0x15, 0xc3, 0x82, 0xe2, 0xd8, 0x16, 0x88, 0xfa, 0x69, 0xca, 0x32, 0x83, 0xa1, 0xa3, 0xe2, 0x3e, 0x4f, 0x1d, 0x4a, + 0x14, 0x04, 0x54, 0x0d, 0x39, 0x48, 0x6c, 0x4d, 0x03, 0xe1, 0x01, 0x79, 0x44, 0x67, 0xac, 0xbf, 0xcf, 0x3a, 0xcf, + 0x2e, 0x34, 0x47, 0xe5, 0x6a, 0x57, 0xe8, 0x31, 0xc2, 0x93, 0x4c, 0xc3, 0xe4, 0x3b, 0xe7, 0x99, 0x56, 0x53, 0xf4, + 0x1c, 0x7c, 0xb2, 0x53, 0x8c, 0x48, 0xb7, 0x67, 0xd0, 0x75, 0xf0, 0xaa, 0x0e, 0x1b, 0xed, 0x5a, 0x42, 0x48, 0xe8, + 0x5a, 0x14, 0x31, 0xeb, 0x19, 0x03, 0xea, 0xed, 0xb6, 0xa7, 0xe6, 0x6a, 0xff, 0xdc, 0x6d, 0xb7, 0x3d, 0xec, 0xd6, + 0xf3, 0xb4, 0xdb, 0x0a, 0xbc, 0x96, 0x1f, 0xb4, 0xc7, 0x9f, 0xdb, 0xf1, 0xe7, 0x1a, 0xc9, 0xa3, 0xb0, 0x34, 0xd3, + 0xd4, 0x07, 0xe1, 0x70, 0xd3, 0x7b, 0xaf, 0x49, 0xdf, 0x67, 0xa1, 0xa0, 0x97, 0x95, 0x57, 0x5d, 0x63, 0x4d, 0x2a, + 0x1f, 0x5c, 0xff, 0x0f, 0xaf, 0x02, 0x3c, 0xe2, 0xe4, 0xce, 0xde, 0xdb, 0xa0, 0xd2, 0x6b, 0x0b, 0x47, 0x8a, 0xd0, + 0x03, 0x92, 0xb0, 0xaf, 0x65, 0x2d, 0x6e, 0xf3, 0x2c, 0x7b, 0x98, 0x3e, 0xbd, 0x4a, 0x5d, 0xab, 0x7b, 0xbb, 0xcc, + 0x32, 0x7d, 0xe0, 0xd5, 0x14, 0x07, 0x34, 0xea, 0xa2, 0x7d, 0xd7, 0x59, 0x55, 0x81, 0x97, 0x07, 0x5c, 0x9f, 0xcf, + 0xb8, 0x0b, 0x37, 0x77, 0x55, 0xfb, 0x9b, 0xf4, 0x2c, 0x9b, 0x67, 0x8b, 0xed, 0x36, 0xc4, 0xbf, 0x5d, 0x2d, 0xb2, + 0x34, 0x79, 0x0e, 0x3a, 0x3c, 0x8c, 0xdc, 0xc3, 0x54, 0xe3, 0x9c, 0xcd, 0xff, 0xb2, 0xf2, 0x9c, 0x04, 0x4e, 0x81, + 0x5e, 0xcc, 0x1e, 0x81, 0x0c, 0x46, 0x3b, 0xf5, 0x57, 0x33, 0xb5, 0x66, 0x20, 0xfa, 0x56, 0x15, 0x01, 0x8e, 0x2e, + 0x36, 0x12, 0x8d, 0x2c, 0x38, 0x69, 0x08, 0x58, 0x6c, 0x9a, 0xf2, 0x3e, 0x18, 0xda, 0x56, 0x97, 0xf7, 0xce, 0x92, + 0xe6, 0xb8, 0x0e, 0xac, 0x6d, 0xbf, 0x1e, 0x62, 0x5d, 0x76, 0xbd, 0x40, 0xee, 0x97, 0x37, 0xb4, 0x37, 0x6e, 0x12, + 0x98, 0xb5, 0x4d, 0x63, 0x18, 0x3f, 0x53, 0xfa, 0x4f, 0x6a, 0x70, 0xa5, 0xf1, 0xd3, 0x5c, 0x5b, 0x25, 0x98, 0x7d, + 0xe3, 0xf8, 0x0e, 0x40, 0x38, 0x36, 0x97, 0x1e, 0x9f, 0x65, 0x0e, 0x3d, 0x06, 0xa2, 0xa3, 0x3f, 0x2a, 0xec, 0x47, + 0x66, 0xf7, 0xba, 0x01, 0xf0, 0xe6, 0x75, 0xbb, 0xa0, 0x79, 0xb1, 0x80, 0x40, 0xa2, 0x4e, 0x79, 0xa5, 0xe1, 0x33, + 0x63, 0x76, 0x05, 0x64, 0xa8, 0x24, 0x60, 0x93, 0xd4, 0x75, 0x2e, 0xc4, 0xb2, 0xc3, 0xd2, 0x7c, 0x24, 0x61, 0x27, + 0x21, 0xa0, 0xbd, 0x06, 0xc1, 0x2c, 0xf8, 0xaf, 0x60, 0x50, 0x0c, 0x82, 0x28, 0x88, 0x82, 0x80, 0x0c, 0x4a, 0xf8, + 0x85, 0x38, 0x63, 0x04, 0x63, 0x94, 0x40, 0x87, 0xdf, 0x71, 0xe6, 0x32, 0x22, 0x2f, 0xbc, 0x30, 0x96, 0x76, 0x00, + 0x2e, 0x84, 0xc8, 0x79, 0x8c, 0x3e, 0x16, 0xef, 0x38, 0xcb, 0x08, 0x7d, 0xe7, 0x9c, 0xca, 0x8f, 0xb8, 0x17, 0xdc, + 0x6e, 0x77, 0xd8, 0x5e, 0xf2, 0x30, 0xa3, 0xbd, 0x31, 0x7d, 0xc7, 0x49, 0x94, 0x79, 0xce, 0xc3, 0x1c, 0x7a, 0x56, + 0x1b, 0xd6, 0x8a, 0x6a, 0x72, 0x83, 0x62, 0x5d, 0x64, 0x99, 0xac, 0x0c, 0x57, 0xce, 0x69, 0x85, 0xeb, 0xce, 0xac, + 0x17, 0x90, 0x94, 0x55, 0x8a, 0xa5, 0x33, 0xe1, 0xab, 0x4d, 0xcb, 0x9e, 0xb7, 0x4e, 0x21, 0xa7, 0x21, 0x32, 0xfa, + 0xa1, 0x25, 0xa0, 0x9a, 0x56, 0x5c, 0xd5, 0xe0, 0xb2, 0xab, 0xdb, 0xc3, 0x75, 0x7b, 0x74, 0x33, 0x3e, 0x40, 0x8c, + 0x38, 0x8e, 0x2d, 0x03, 0xbb, 0x09, 0x8b, 0x67, 0x63, 0x7d, 0x5f, 0x76, 0xe9, 0xad, 0xad, 0xc5, 0x21, 0xac, 0x3d, + 0x67, 0x85, 0x84, 0x00, 0x69, 0xa9, 0x2b, 0xdd, 0x6e, 0x83, 0x00, 0x06, 0xb8, 0xdf, 0xef, 0x01, 0xd7, 0xaa, 0xd9, + 0x49, 0x7d, 0x6b, 0x36, 0xc4, 0x5e, 0x52, 0x78, 0x0c, 0x44, 0xa9, 0xf8, 0xcf, 0x20, 0xa0, 0x78, 0xee, 0x86, 0x60, + 0x5f, 0xc9, 0x4e, 0x36, 0x65, 0xbf, 0xff, 0xbc, 0xc4, 0x07, 0x94, 0x83, 0x82, 0x58, 0x57, 0xc5, 0xad, 0xd0, 0xec, + 0x93, 0xfc, 0x10, 0xc7, 0x22, 0xcf, 0x42, 0x4b, 0x58, 0x6a, 0x4d, 0x58, 0xb8, 0x64, 0xa4, 0x83, 0x38, 0x68, 0x48, + 0xe7, 0x60, 0xd5, 0x36, 0xd8, 0x70, 0xaf, 0xf7, 0xb2, 0x0a, 0x2b, 0x9a, 0x39, 0xc3, 0xf2, 0xde, 0x01, 0x00, 0xeb, + 0xf5, 0x70, 0xa1, 0x38, 0x64, 0xc2, 0x43, 0x9f, 0xc4, 0x97, 0x86, 0x5d, 0x9f, 0x29, 0x59, 0xc9, 0x68, 0x34, 0xaa, + 0x1b, 0x29, 0xf9, 0x30, 0xdf, 0xbd, 0x69, 0xa1, 0x56, 0x8a, 0x38, 0xe5, 0x29, 0x58, 0x7a, 0x6b, 0x4a, 0x37, 0x5f, + 0xd0, 0x15, 0x2f, 0x52, 0xf9, 0xd3, 0x41, 0x9b, 0xf4, 0x88, 0x6b, 0xe6, 0xeb, 0x2c, 0xcc, 0xf0, 0x43, 0xc0, 0x47, + 0xf3, 0x30, 0xb3, 0xe9, 0x0a, 0x96, 0x16, 0xc4, 0x91, 0x71, 0xc9, 0x43, 0x9b, 0x07, 0xb0, 0xfe, 0xf4, 0x21, 0x89, + 0x9f, 0xc2, 0xcf, 0x99, 0x4e, 0xeb, 0xf8, 0x0c, 0x67, 0x33, 0x2a, 0xe4, 0x8d, 0xa0, 0xfd, 0x1a, 0x12, 0x89, 0x46, + 0x36, 0xf6, 0x18, 0x8a, 0xd6, 0xdd, 0x06, 0xae, 0xfc, 0x86, 0xde, 0xb9, 0x34, 0x08, 0xb0, 0xad, 0xb1, 0x18, 0x38, + 0xe3, 0xf1, 0x07, 0xaa, 0x6a, 0xf4, 0x15, 0x45, 0x37, 0x4c, 0x26, 0x9a, 0x3b, 0x8e, 0xed, 0xa8, 0x76, 0x95, 0xad, + 0x58, 0x61, 0x6c, 0x79, 0xed, 0x5b, 0x5a, 0x9a, 0x12, 0x50, 0x0d, 0x86, 0x3b, 0x01, 0x7c, 0x46, 0x84, 0x3c, 0x10, + 0x44, 0xf7, 0xc1, 0x41, 0x73, 0x96, 0xe0, 0x79, 0x18, 0xc2, 0x1f, 0x58, 0x38, 0xb0, 0x2c, 0x65, 0x3f, 0x97, 0xd3, + 0x18, 0xce, 0xdd, 0x5c, 0xee, 0xf0, 0xd9, 0x12, 0x14, 0x79, 0x72, 0x4e, 0xf5, 0xe5, 0x2b, 0xf7, 0xf6, 0x7b, 0x4c, + 0x30, 0x8f, 0x9e, 0x6d, 0xf8, 0xad, 0xa6, 0xdb, 0xf8, 0xc2, 0xda, 0x81, 0x13, 0xe6, 0xc2, 0x69, 0x2e, 0xb6, 0x4b, + 0x0d, 0x71, 0xd7, 0x78, 0x42, 0x84, 0x57, 0x8a, 0x58, 0x64, 0x9e, 0x4c, 0xc7, 0x60, 0x63, 0xc8, 0x36, 0x95, 0xcf, + 0x94, 0x42, 0xbc, 0x9a, 0xca, 0x0b, 0x53, 0x2b, 0x95, 0x55, 0x1a, 0x61, 0xa6, 0x80, 0x45, 0x95, 0x81, 0xcf, 0x7e, + 0x8d, 0x14, 0xd7, 0xd4, 0xf3, 0x17, 0x2e, 0xdf, 0x4c, 0xb7, 0xd9, 0x7c, 0xfa, 0x32, 0x8f, 0xaf, 0xb6, 0xdb, 0xb0, + 0xfb, 0x05, 0x98, 0x5f, 0x56, 0x52, 0xa3, 0x06, 0x4e, 0x0f, 0x21, 0xfa, 0x39, 0xef, 0xc9, 0x39, 0xb1, 0x9c, 0x5c, + 0xbb, 0x79, 0xb3, 0x9d, 0x14, 0x2d, 0xb0, 0x80, 0x13, 0x17, 0xe9, 0x40, 0x4b, 0x05, 0xa7, 0x2c, 0xe3, 0x9d, 0x4d, + 0x6f, 0x29, 0x15, 0x5e, 0x2d, 0x14, 0x09, 0xa9, 0xed, 0xbd, 0xc4, 0x8c, 0x1a, 0x70, 0x4e, 0xf2, 0x0e, 0x02, 0x4e, + 0x6a, 0xaa, 0xb1, 0x46, 0x71, 0xaa, 0x13, 0x9c, 0x57, 0x6a, 0xe8, 0x12, 0xe5, 0xc4, 0x6d, 0xb7, 0x55, 0xd1, 0x42, + 0x7d, 0x3c, 0xc8, 0x59, 0x22, 0x8f, 0x07, 0x14, 0xba, 0xc8, 0xa3, 0x21, 0x5f, 0x90, 0x52, 0xad, 0x1c, 0xa5, 0x5a, + 0xdd, 0x95, 0x0c, 0x14, 0x72, 0x15, 0xe4, 0x0d, 0x31, 0xee, 0x5a, 0x99, 0xb7, 0xb8, 0x72, 0x42, 0x4a, 0x93, 0xf0, + 0xb9, 0xa5, 0x18, 0x58, 0xc1, 0xde, 0x98, 0xba, 0xc2, 0x25, 0x42, 0xdb, 0xdd, 0x86, 0x98, 0x64, 0xb0, 0x6e, 0xb6, + 0xdb, 0x57, 0x65, 0x38, 0xcf, 0x16, 0x54, 0x8c, 0xb2, 0x14, 0x21, 0xc4, 0xb4, 0x87, 0xae, 0xe9, 0x82, 0x9e, 0x18, + 0x6a, 0xdb, 0xe3, 0x24, 0xe9, 0x62, 0x4d, 0x92, 0x18, 0xc5, 0x17, 0xa2, 0x94, 0x6b, 0x8d, 0x10, 0x3c, 0xdc, 0xff, + 0x48, 0x21, 0x86, 0x9b, 0x5e, 0x77, 0xbf, 0xee, 0xdc, 0x10, 0xff, 0x80, 0x40, 0x02, 0x05, 0x7b, 0x55, 0x8e, 0x2e, + 0xb2, 0x22, 0xc5, 0x9d, 0x2a, 0xa3, 0xe2, 0xca, 0x75, 0xe0, 0xb7, 0xdc, 0xf0, 0xaf, 0x86, 0x28, 0x40, 0x5c, 0xe3, + 0x4a, 0x31, 0x9e, 0xb5, 0xb5, 0x14, 0xc9, 0x28, 0x36, 0x24, 0x2a, 0x9c, 0xa8, 0xe8, 0x2e, 0x4f, 0xa3, 0x7b, 0x68, + 0xd7, 0x20, 0xb8, 0x6a, 0xee, 0x6c, 0xa4, 0xf9, 0x82, 0x10, 0x39, 0x01, 0x02, 0x36, 0xaa, 0x3e, 0xb5, 0x56, 0xd5, + 0xc3, 0xac, 0xf2, 0xb9, 0x3a, 0x88, 0x57, 0x15, 0xf0, 0xb0, 0xce, 0xf6, 0xbe, 0xaa, 0x1c, 0xd6, 0x06, 0xdf, 0x6e, + 0xb7, 0xab, 0x6a, 0x1e, 0x04, 0x0e, 0xa3, 0xf9, 0x9d, 0x94, 0x98, 0xf7, 0xc6, 0x14, 0x56, 0xbc, 0xeb, 0xd2, 0xd6, + 0x4d, 0x6a, 0x8d, 0x05, 0xea, 0x0e, 0xd7, 0x07, 0x3c, 0x4f, 0x81, 0xa3, 0x1d, 0x15, 0x53, 0x61, 0x74, 0xe5, 0xd8, + 0x95, 0x0a, 0x03, 0x43, 0xff, 0x90, 0xb2, 0x0d, 0x98, 0xe3, 0x81, 0xb5, 0x0d, 0xfa, 0x29, 0x49, 0x2d, 0xcc, 0x18, + 0x8d, 0x59, 0xc4, 0xba, 0x8e, 0x8e, 0xb8, 0x8a, 0xde, 0xce, 0xa3, 0xbf, 0x3d, 0x1d, 0xd3, 0x32, 0x2e, 0x52, 0x71, + 0x0d, 0x2a, 0x08, 0x50, 0x86, 0xa0, 0xe1, 0xbf, 0xa2, 0x06, 0xa0, 0x41, 0xb0, 0x03, 0xf0, 0x8f, 0x4e, 0xa7, 0x41, + 0x53, 0x93, 0x8b, 0x49, 0x2a, 0x8b, 0x9c, 0xb5, 0xa1, 0xcc, 0x64, 0x72, 0x48, 0x1e, 0x17, 0x80, 0xe7, 0x88, 0xcd, + 0x92, 0x36, 0x17, 0x72, 0xb3, 0xc9, 0xd7, 0x92, 0x1d, 0xb9, 0xf3, 0x8a, 0xd6, 0x6b, 0x51, 0xd9, 0x49, 0xcc, 0x17, + 0xd3, 0x3b, 0x23, 0x0c, 0x9c, 0xea, 0xd6, 0xdc, 0xee, 0x40, 0xa7, 0x99, 0xfa, 0x74, 0x6e, 0x02, 0xc4, 0x01, 0x86, + 0xeb, 0x6e, 0x7e, 0xbb, 0x20, 0xf4, 0x8e, 0xdd, 0x19, 0xb1, 0xea, 0xad, 0x91, 0x8b, 0xe8, 0xb4, 0xdb, 0xc1, 0x04, + 0x2e, 0xe3, 0xac, 0x34, 0x2f, 0x94, 0xba, 0xa1, 0xec, 0x68, 0x9b, 0x30, 0x9f, 0x77, 0xb4, 0x1b, 0x2e, 0xf8, 0x46, + 0xac, 0x63, 0xdd, 0x90, 0xa6, 0x12, 0x3d, 0x3a, 0x50, 0xdb, 0x21, 0xa0, 0x39, 0x1b, 0xd3, 0x25, 0x40, 0x6d, 0xc2, + 0x7e, 0x59, 0x83, 0x59, 0xca, 0x25, 0xf4, 0xb5, 0xdb, 0x27, 0xf9, 0x52, 0xf6, 0xa4, 0x72, 0x96, 0x28, 0xf8, 0x72, + 0xa4, 0xe0, 0x95, 0x95, 0xf3, 0x58, 0xcf, 0x21, 0xe0, 0xb1, 0xc8, 0x12, 0x9d, 0x93, 0xe2, 0x0a, 0x94, 0xa9, 0x70, + 0x04, 0xea, 0xaa, 0x11, 0x4b, 0x38, 0xc0, 0xed, 0xc5, 0xd3, 0x80, 0x50, 0x90, 0xea, 0xae, 0xcd, 0x8a, 0xbc, 0x63, + 0x27, 0x9b, 0x3b, 0x30, 0x8b, 0xad, 0xd7, 0x55, 0xeb, 0x2b, 0x93, 0x6c, 0x3f, 0x6e, 0x08, 0xb6, 0xdd, 0x91, 0xf2, + 0x85, 0x77, 0xf4, 0x96, 0x6c, 0x6e, 0xfb, 0xfd, 0x10, 0xfa, 0x43, 0xa8, 0xea, 0xd0, 0x5d, 0x67, 0x87, 0xee, 0x5c, + 0xe6, 0xd7, 0xe8, 0xf9, 0xa4, 0x37, 0xc4, 0x07, 0x34, 0xd1, 0xa2, 0xab, 0xf8, 0x1e, 0x36, 0x75, 0x54, 0x53, 0x59, + 0x79, 0x94, 0x50, 0x50, 0x01, 0x67, 0xbc, 0x3a, 0xe3, 0x18, 0xdb, 0x54, 0x3d, 0xbd, 0x53, 0xbc, 0xda, 0x5a, 0xaf, + 0xcd, 0x6a, 0x7d, 0x01, 0x16, 0x01, 0x17, 0x3c, 0xba, 0x56, 0xb4, 0xe4, 0xca, 0x61, 0xea, 0xcf, 0x71, 0x54, 0x82, + 0xcb, 0x38, 0xcb, 0x79, 0x1a, 0xd0, 0x4b, 0xbf, 0xff, 0xa1, 0xb2, 0x95, 0x5a, 0x7a, 0x67, 0xee, 0x4d, 0x48, 0x36, + 0xff, 0x63, 0x03, 0xf5, 0x3a, 0xc4, 0x88, 0xa8, 0x7a, 0x41, 0xbf, 0x65, 0x10, 0x1b, 0x33, 0xa8, 0xd6, 0x49, 0xc2, + 0xab, 0x2a, 0xd0, 0x4a, 0xad, 0x35, 0x5b, 0xeb, 0xf3, 0xec, 0x11, 0x3b, 0x79, 0xd4, 0x63, 0xec, 0x8e, 0xd0, 0x44, + 0xe9, 0x84, 0x74, 0x8d, 0x91, 0xa3, 0x05, 0x52, 0x1d, 0x8a, 0xb2, 0xcb, 0xf0, 0x2d, 0x0a, 0x59, 0xda, 0xfb, 0x5c, + 0x9f, 0xc8, 0xf2, 0x1b, 0x65, 0x74, 0x11, 0xc9, 0x44, 0x90, 0x8d, 0xdf, 0x22, 0x60, 0x2f, 0x34, 0x3b, 0x20, 0x9b, + 0x25, 0x3b, 0xa3, 0xe7, 0xc6, 0x04, 0x06, 0x5e, 0xbf, 0x95, 0x89, 0x7a, 0x94, 0x25, 0xd1, 0x95, 0x46, 0x2e, 0xf7, + 0x21, 0x89, 0xce, 0x43, 0xe2, 0xe6, 0x86, 0xa5, 0x75, 0x13, 0xa2, 0x98, 0x59, 0x6f, 0x78, 0xd9, 0xdd, 0x47, 0xde, + 0xb6, 0xd2, 0x3e, 0xd5, 0x77, 0x26, 0x8d, 0x4c, 0xa1, 0xaf, 0xc3, 0x49, 0xbf, 0x0f, 0x7f, 0x15, 0xfd, 0xc0, 0x5b, + 0x0a, 0xfe, 0x62, 0x8f, 0x48, 0x93, 0xb0, 0x00, 0xe0, 0x08, 0x73, 0x5e, 0xfb, 0x13, 0xf8, 0x88, 0x9d, 0x6c, 0x1e, + 0x85, 0x67, 0xde, 0xcc, 0xdd, 0x87, 0x78, 0xa9, 0x4a, 0x7a, 0xce, 0x3c, 0xe9, 0x81, 0x58, 0x85, 0x7a, 0xbf, 0xde, + 0x31, 0xa3, 0x4f, 0x00, 0x22, 0x75, 0x67, 0x1c, 0x4a, 0xf1, 0x63, 0xdd, 0x65, 0xb2, 0x49, 0x59, 0x9b, 0x89, 0x92, + 0x2a, 0x12, 0x7f, 0x11, 0x40, 0xbf, 0x61, 0x38, 0x1a, 0x80, 0xf7, 0x56, 0x63, 0xaf, 0x87, 0xc6, 0x19, 0x53, 0x4d, + 0xcf, 0x36, 0x6a, 0x79, 0x5b, 0x0a, 0xa1, 0xc7, 0x22, 0xba, 0xb3, 0xc7, 0x62, 0x78, 0x46, 0xdf, 0x42, 0x85, 0xaf, + 0x43, 0x8c, 0xa6, 0x4b, 0x9a, 0x66, 0xba, 0x96, 0x5b, 0xe9, 0x96, 0xd0, 0x1c, 0xa3, 0xf8, 0x38, 0x6d, 0xbb, 0xa7, + 0x5a, 0x68, 0x4f, 0x28, 0x0f, 0xef, 0x68, 0x4d, 0x6f, 0x0d, 0x8b, 0x60, 0x91, 0x96, 0x9d, 0xfc, 0x84, 0x5e, 0x38, + 0x02, 0x93, 0xb2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x33, 0x35, 0x52, 0x0e, 0x47, 0xe1, 0x4b, 0x36, 0x20, + 0x57, 0x50, 0x8b, 0x35, 0x66, 0x27, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x33, 0x29, 0x88, 0x64, 0x44, 0x73, 0x0b, + 0xf1, 0xf4, 0x0f, 0xd0, 0xf4, 0x41, 0x5a, 0x98, 0xd2, 0x35, 0x0a, 0x78, 0x40, 0xdf, 0xd4, 0xef, 0xe7, 0xf8, 0xdc, + 0x38, 0x96, 0x58, 0xd8, 0xe3, 0x25, 0xa1, 0x4b, 0x27, 0x6e, 0x14, 0x48, 0x9b, 0x2d, 0xab, 0x00, 0xac, 0x48, 0x02, + 0x8d, 0x48, 0xd0, 0x52, 0xc7, 0x8a, 0xcb, 0x36, 0x68, 0x40, 0x12, 0x15, 0x14, 0xb2, 0x44, 0x02, 0xf8, 0x61, 0x04, + 0x21, 0x8a, 0x62, 0x10, 0xf7, 0xaa, 0xe5, 0x15, 0x37, 0x54, 0x83, 0x13, 0x45, 0x30, 0xc1, 0x2a, 0x9d, 0x02, 0xb1, + 0x2d, 0xd6, 0x2b, 0xf0, 0xbc, 0xb4, 0x17, 0x49, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x95, 0x4e, 0xdb, 0xe5, 0xed, 0x88, + 0x96, 0x6a, 0x36, 0x77, 0x5e, 0x2c, 0x0c, 0xf7, 0x58, 0xbb, 0xdb, 0x81, 0xf6, 0xc2, 0x7a, 0x47, 0x44, 0x0d, 0x56, + 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xaa, 0x5e, 0x59, 0x26, 0xa0, 0xa6, 0xab, 0xb8, 0x5e, 0x46, 0xd9, 0x08, 0xfe, + 0x6c, 0xb7, 0xc1, 0x61, 0x00, 0x16, 0x90, 0xbf, 0xbc, 0xff, 0x29, 0xc2, 0xf0, 0x4c, 0xbf, 0xbc, 0xff, 0x69, 0xbb, + 0x7d, 0x3a, 0x1e, 0x6b, 0xae, 0xc0, 0xaa, 0x75, 0x80, 0x3f, 0xd0, 0x6c, 0x83, 0x59, 0xb2, 0xdb, 0xed, 0x53, 0xe0, + 0x20, 0x24, 0xdb, 0xa0, 0x77, 0xb1, 0x74, 0xe4, 0x92, 0xac, 0x86, 0xda, 0x91, 0x80, 0x55, 0xb7, 0xc3, 0x52, 0xec, + 0x52, 0x1f, 0x19, 0x82, 0x51, 0x2d, 0xfa, 0x17, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, 0xb2, 0xae, 0x57, 0x55, + 0x74, 0x78, 0x18, 0xaf, 0xb2, 0x51, 0x95, 0xc1, 0x36, 0xaf, 0x6e, 0xae, 0x00, 0x50, 0x21, 0xa0, 0xde, 0xbb, 0x75, + 0x91, 0xe9, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0x8d, 0x6e, 0x72, 0x4a, 0xcc, 0x03, 0xd8, + 0x1c, 0x6e, 0xb7, 0x1e, 0xbf, 0x70, 0x32, 0x7a, 0x3a, 0x5b, 0x66, 0xca, 0xa0, 0x93, 0xeb, 0xfd, 0x4f, 0x22, 0x27, + 0x0d, 0x15, 0x9f, 0x64, 0xfa, 0x22, 0x03, 0x3e, 0x8f, 0xbd, 0xa9, 0x42, 0x97, 0xe5, 0xf2, 0x5a, 0x03, 0x6c, 0x6c, + 0x76, 0x79, 0x3f, 0x4a, 0x39, 0x44, 0xa4, 0x08, 0x8c, 0xba, 0x66, 0x99, 0x11, 0xd7, 0xa6, 0xe2, 0xbe, 0xa5, 0x0a, + 0x7b, 0x53, 0x39, 0xce, 0x2a, 0x5c, 0x3b, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x02, 0x85, 0xa8, 0x1c, 0x8d, 0xe9, 0xac, + 0x40, 0x2a, 0x73, 0x98, 0x50, 0xcc, 0x61, 0xdf, 0xfd, 0x92, 0x5a, 0x73, 0x19, 0x57, 0xb8, 0xf7, 0xc2, 0x95, 0x99, + 0xdc, 0x09, 0x00, 0x45, 0x92, 0xb5, 0xff, 0xfc, 0x09, 0xa9, 0xf1, 0x3f, 0x53, 0xa5, 0x01, 0xe8, 0xfd, 0x0c, 0x35, + 0x59, 0x82, 0x80, 0xad, 0x98, 0xba, 0x68, 0xfa, 0x46, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x15, 0xdb, 0xc8, 0xf8, 0x39, + 0x51, 0x4d, 0x4b, 0x9e, 0xae, 0x8b, 0x34, 0x2e, 0x92, 0xfb, 0x88, 0x37, 0x53, 0x2c, 0x89, 0x55, 0x9a, 0x02, 0xfd, + 0xec, 0x77, 0xe1, 0xa7, 0xd2, 0x33, 0x01, 0xa7, 0x85, 0xbb, 0xad, 0x9c, 0xcd, 0x64, 0x18, 0x67, 0x64, 0xca, 0x25, + 0x62, 0xb7, 0xd1, 0xf7, 0xe8, 0x13, 0xfc, 0xc9, 0xd1, 0x13, 0x42, 0xef, 0xc4, 0xb4, 0x40, 0x50, 0xba, 0x22, 0x35, + 0xae, 0x9a, 0xd8, 0xaf, 0x29, 0x44, 0x71, 0xa8, 0x18, 0x84, 0xee, 0xd4, 0xed, 0x93, 0x7c, 0x9f, 0x29, 0xfb, 0x8d, + 0x2e, 0x5b, 0x90, 0x4d, 0x05, 0x1d, 0x13, 0xd6, 0xdb, 0xd3, 0xd9, 0xb3, 0x33, 0xe7, 0x37, 0x68, 0xc2, 0x41, 0x75, + 0x03, 0xed, 0x2a, 0xc9, 0x34, 0x46, 0xb1, 0x59, 0x8c, 0xb5, 0x1b, 0x13, 0x11, 0x04, 0x9d, 0x2e, 0x66, 0x61, 0xbb, + 0x9d, 0x10, 0x5f, 0x02, 0x09, 0x14, 0xb8, 0x72, 0x51, 0x4e, 0x42, 0x22, 0x2f, 0x64, 0x6a, 0xb2, 0x6e, 0x04, 0x0b, + 0xd4, 0x1a, 0x3b, 0x0a, 0xe8, 0x29, 0x37, 0x4f, 0x01, 0x7d, 0x5f, 0xb2, 0x53, 0x3e, 0x08, 0x86, 0x18, 0x5f, 0x35, + 0xa0, 0xb7, 0x42, 0x3e, 0x82, 0x87, 0x30, 0xb0, 0x5c, 0xf4, 0x65, 0xc9, 0x10, 0x56, 0xe8, 0xcf, 0x94, 0x4d, 0xbe, + 0xfe, 0xc6, 0xce, 0xef, 0xb5, 0x12, 0xb3, 0x83, 0x50, 0xdc, 0x5c, 0x4f, 0x80, 0xf8, 0xd5, 0xfc, 0x1a, 0xac, 0xab, + 0x95, 0xc4, 0xdb, 0x91, 0x3c, 0x54, 0xae, 0x1c, 0xdd, 0x7c, 0x52, 0xe9, 0x4f, 0x20, 0x48, 0x8d, 0x95, 0x94, 0xdb, + 0xef, 0x3e, 0x0a, 0x5b, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xed, 0xad, 0xe4, 0xc2, 0x17, 0xfe, 0x63, 0x9d, 0xef, 0x31, + 0x76, 0x88, 0x38, 0xc3, 0xe9, 0xf7, 0xc1, 0xb0, 0xbd, 0x5b, 0x99, 0x36, 0x24, 0xba, 0x96, 0x1f, 0x01, 0xfd, 0x1f, + 0xab, 0xf1, 0x3b, 0x45, 0x49, 0x5f, 0x12, 0xe7, 0x08, 0x57, 0xc4, 0x2b, 0x34, 0xd5, 0xeb, 0x8d, 0x1b, 0xfa, 0xa6, + 0xd4, 0x2f, 0x94, 0x82, 0xc3, 0xbc, 0xd5, 0x0a, 0x0f, 0x3c, 0xf3, 0xfe, 0xa8, 0x3c, 0x41, 0xf7, 0x6f, 0xb8, 0x37, + 0xfe, 0xa8, 0x58, 0x86, 0x37, 0xe5, 0x2c, 0xd3, 0x77, 0xb8, 0xdb, 0xac, 0x48, 0xc5, 0x2d, 0x63, 0xc1, 0xba, 0x90, + 0xe6, 0xab, 0x69, 0x30, 0xdb, 0x34, 0x91, 0x4c, 0xb6, 0xdf, 0xff, 0xe5, 0x9d, 0xb0, 0xd9, 0x20, 0x38, 0xab, 0x45, + 0x19, 0x5f, 0xf1, 0x60, 0xaa, 0x54, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0x63, 0xb5, 0x77, 0xf0, 0x64, 0xa8, + 0x99, 0x0e, 0x71, 0x6d, 0x74, 0x16, 0xf0, 0x56, 0x8f, 0xe6, 0x69, 0x0d, 0xbb, 0xcc, 0x55, 0x52, 0xfc, 0xd1, 0x92, + 0x64, 0x63, 0xfd, 0x9e, 0x0c, 0xdb, 0xc8, 0x67, 0xae, 0x01, 0x63, 0xe6, 0x56, 0xc8, 0x20, 0x77, 0x3d, 0x60, 0x84, + 0x90, 0x08, 0x54, 0xd6, 0x62, 0xe2, 0xbc, 0xd2, 0xe1, 0x1f, 0x6d, 0x60, 0x9c, 0x18, 0x03, 0xe3, 0x7c, 0x14, 0x21, + 0xa7, 0xa7, 0x7c, 0x90, 0x78, 0xb3, 0xf5, 0x97, 0x2c, 0x91, 0xde, 0x08, 0x42, 0x2f, 0xe0, 0xf7, 0xb8, 0xc5, 0x03, + 0x79, 0xc1, 0x29, 0xed, 0xcd, 0xe9, 0xf0, 0x65, 0x49, 0x86, 0x7f, 0x82, 0x77, 0x57, 0x6c, 0x2e, 0xcb, 0x09, 0x2c, + 0xee, 0xd8, 0x29, 0x9e, 0xe6, 0xb2, 0xc5, 0x09, 0x71, 0x88, 0x45, 0xee, 0x12, 0x0b, 0x18, 0x51, 0xcd, 0x68, 0xfc, + 0x78, 0xf6, 0xf6, 0x8d, 0xc2, 0x6c, 0xca, 0xdd, 0x0f, 0x60, 0x44, 0x95, 0xb4, 0xdd, 0x0c, 0xf8, 0x72, 0x84, 0x06, + 0xdb, 0xa9, 0x1d, 0xec, 0x7e, 0x5f, 0xa7, 0x9d, 0x14, 0x4e, 0x36, 0x2b, 0x06, 0xdd, 0x51, 0xda, 0x2c, 0xa5, 0x41, + 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0xab, 0xc5, 0xaa, 0xce, 0x87, 0xe1, 0x92, 0xc6, 0x46, 0x56, 0x6e, 0x76, 0x13, 0x8e, + 0x6c, 0x02, 0x5c, 0x9f, 0x84, 0xb2, 0xf2, 0xe7, 0xa0, 0x05, 0x9d, 0x09, 0x1c, 0xd1, 0x76, 0x1b, 0x42, 0x04, 0x8e, + 0x72, 0x38, 0x99, 0x85, 0xe5, 0x70, 0x28, 0x07, 0xbe, 0x24, 0x24, 0x7a, 0x53, 0xce, 0xb3, 0x85, 0x44, 0xec, 0x71, + 0x77, 0xd2, 0xaf, 0xa5, 0xe4, 0x94, 0x7b, 0x7f, 0x54, 0x64, 0xf3, 0x5b, 0x8a, 0x31, 0x07, 0xad, 0x66, 0x33, 0x03, + 0x09, 0xeb, 0x69, 0x4d, 0xe4, 0x3a, 0x32, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, 0x75, 0x8b, 0x23, 0xd6, 0xd3, + 0x7a, 0x0f, 0x2a, 0x40, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x5e, 0x56, 0xa1, 0xa0, 0x9c, 0xf8, 0xcc, 0x8c, 0x11, + 0x0d, 0x96, 0x20, 0x24, 0x8d, 0xab, 0xfa, 0xb5, 0x48, 0xb3, 0xcb, 0x0c, 0x10, 0x13, 0xac, 0xff, 0x9c, 0xf0, 0xde, + 0x3c, 0x93, 0xf3, 0xd2, 0x95, 0x38, 0x33, 0x30, 0x1f, 0x5d, 0x6f, 0x69, 0x49, 0xa2, 0x12, 0x68, 0x94, 0xab, 0xe5, + 0xf9, 0xfb, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x69, 0x3b, 0xc4, 0x4f, 0x58, 0x4d, 0x9c, 0xd3, 0xba, 0x96, 0x22, + 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xc8, 0xe1, 0x03, 0x83, 0x0a, 0x2b, 0xf9, 0x29, 0x70, 0xf8, 0x8c, + 0x81, 0xa4, 0xab, 0x45, 0x70, 0x35, 0x3a, 0xc2, 0x8a, 0x32, 0xb5, 0xc4, 0x14, 0x12, 0xdd, 0x7a, 0xa1, 0x35, 0x86, + 0x51, 0x76, 0x15, 0xf9, 0xdf, 0xab, 0xee, 0xfd, 0x51, 0x6d, 0xb7, 0x30, 0xc9, 0x8e, 0xc7, 0x15, 0x6c, 0x6a, 0xd4, + 0x0a, 0xe1, 0xec, 0x9c, 0xd6, 0xa8, 0x1d, 0xeb, 0x85, 0x05, 0x90, 0x07, 0xb0, 0x15, 0xf1, 0x28, 0x83, 0x60, 0x6f, + 0xca, 0x79, 0xb5, 0xb0, 0xa2, 0x1c, 0x21, 0xf1, 0xbe, 0xc4, 0x28, 0xe5, 0x70, 0x15, 0x0b, 0x4b, 0x86, 0xfc, 0xea, + 0xe8, 0xb2, 0x14, 0xd7, 0x20, 0x29, 0xd1, 0x0c, 0x95, 0xe1, 0x75, 0x71, 0xd5, 0x16, 0x84, 0xf6, 0x2e, 0x2a, 0x50, + 0x47, 0x82, 0xe0, 0xc5, 0xab, 0x21, 0x66, 0x1b, 0xb9, 0xbb, 0xa2, 0xbd, 0xe4, 0x80, 0x5a, 0xdd, 0xb5, 0x5d, 0x6f, + 0xd2, 0x36, 0xdb, 0x88, 0x0b, 0xff, 0x82, 0xd2, 0x4f, 0xf9, 0xa0, 0x74, 0xa9, 0x04, 0x6e, 0x7c, 0xb9, 0xc9, 0xb2, + 0xcb, 0x7b, 0x5c, 0xfa, 0xb5, 0x37, 0x7e, 0xfd, 0x7e, 0x4f, 0x2e, 0x04, 0x2f, 0x15, 0x98, 0x6f, 0x97, 0x99, 0xaa, + 0xb5, 0xa6, 0xd4, 0x5c, 0x82, 0x6b, 0x6b, 0x3f, 0x82, 0x8a, 0xb8, 0xae, 0xc8, 0x64, 0x72, 0x80, 0x0e, 0x9c, 0xac, + 0x70, 0x2b, 0x0b, 0xf0, 0xd8, 0x09, 0xc8, 0x76, 0xcb, 0xc3, 0x40, 0x1d, 0x3a, 0x81, 0xbb, 0x25, 0xcf, 0x90, 0x59, + 0x33, 0x8f, 0x3f, 0x2b, 0xc1, 0x3f, 0xb6, 0xe0, 0x27, 0x14, 0x77, 0x1a, 0x99, 0x7f, 0x2b, 0xad, 0x5b, 0xdc, 0xbf, + 0x93, 0x69, 0x42, 0x51, 0x99, 0xd0, 0xb8, 0x95, 0xfe, 0x4b, 0x07, 0x4b, 0x92, 0xd9, 0x3f, 0x08, 0xf8, 0x60, 0xe6, + 0x3d, 0x31, 0xef, 0x49, 0x73, 0xba, 0xb5, 0x82, 0x21, 0x40, 0xa1, 0x9f, 0x93, 0xb9, 0xa6, 0xea, 0xf9, 0xe7, 0x35, + 0x5f, 0x73, 0xbf, 0xc5, 0x26, 0xe9, 0x81, 0x06, 0x3b, 0x79, 0x14, 0xa5, 0xb0, 0x12, 0x75, 0xae, 0x25, 0xea, 0x55, + 0xc3, 0x32, 0x54, 0x27, 0x38, 0x35, 0x4f, 0xd5, 0xb0, 0xfb, 0x89, 0x68, 0xad, 0x24, 0x2d, 0x31, 0x60, 0xad, 0x23, + 0x0f, 0xc9, 0xed, 0x5a, 0xc7, 0x9d, 0x86, 0xba, 0x34, 0x89, 0x12, 0x60, 0x84, 0x0b, 0x70, 0x04, 0xfd, 0x54, 0x86, + 0x1c, 0xae, 0xa9, 0x52, 0xbf, 0xa0, 0x28, 0x79, 0xe2, 0x28, 0x6a, 0x95, 0x22, 0xdd, 0x7c, 0x94, 0x63, 0x37, 0x5c, + 0xe3, 0x84, 0x9c, 0x68, 0xa1, 0xbf, 0x3d, 0x96, 0x72, 0x86, 0x16, 0x0f, 0xf2, 0x04, 0xeb, 0xe5, 0x2d, 0x05, 0x8a, + 0x3e, 0xba, 0x8c, 0xba, 0xe6, 0x15, 0xda, 0xbe, 0x2c, 0xfb, 0xfd, 0xdc, 0xd4, 0x93, 0xb2, 0x93, 0xcd, 0x52, 0xef, + 0x43, 0x54, 0x4c, 0xe1, 0xae, 0x4f, 0x14, 0x7f, 0x15, 0xaa, 0xab, 0xb6, 0xc8, 0xf9, 0x88, 0x23, 0x2e, 0x46, 0x4e, + 0x9a, 0x9f, 0xe5, 0xd4, 0x4b, 0x71, 0xbf, 0xac, 0xe4, 0xd7, 0x4a, 0x5b, 0x31, 0x5a, 0xa0, 0xfe, 0x54, 0xaa, 0xbc, + 0x5f, 0x94, 0x00, 0xf7, 0x54, 0xb1, 0x37, 0x60, 0x5f, 0xa1, 0x10, 0x7e, 0x5b, 0x02, 0xfe, 0x8d, 0xe4, 0x06, 0x8c, + 0x02, 0x03, 0x8c, 0x26, 0xdb, 0x73, 0x9a, 0xc0, 0x01, 0x57, 0x29, 0x15, 0x05, 0xad, 0xf4, 0xd0, 0x50, 0x53, 0x18, + 0x3d, 0x43, 0x19, 0xb7, 0xcc, 0xec, 0xdc, 0x18, 0x3b, 0x2d, 0xf0, 0x3c, 0x7f, 0x3e, 0x27, 0xf4, 0xb0, 0x56, 0x07, + 0xa9, 0xd1, 0x49, 0x74, 0x7f, 0xec, 0xc2, 0xc9, 0xf5, 0xc2, 0x59, 0x36, 0x2c, 0x81, 0xee, 0xc0, 0x05, 0x31, 0xee, + 0xf7, 0x73, 0x38, 0x32, 0xf5, 0xc8, 0x97, 0x2c, 0xa7, 0x31, 0x5b, 0x52, 0xe5, 0x69, 0x77, 0x55, 0x87, 0x39, 0x5d, + 0x1a, 0x19, 0x6f, 0xca, 0x8a, 0x79, 0x0e, 0x1a, 0x49, 0xf8, 0xd3, 0x6d, 0xed, 0x92, 0xce, 0x97, 0x90, 0x01, 0xfe, + 0x80, 0x44, 0x14, 0xb1, 0xaf, 0xff, 0xad, 0xc6, 0x49, 0x3d, 0x51, 0xda, 0xb0, 0x84, 0xae, 0x99, 0xaa, 0x9f, 0x5e, + 0xb2, 0xb5, 0xb7, 0x14, 0xb6, 0xdb, 0xd0, 0x4f, 0x60, 0x8a, 0x73, 0x25, 0xd3, 0x4b, 0xd4, 0x49, 0x01, 0x15, 0x0b, + 0x2f, 0x71, 0xf9, 0xa5, 0x84, 0x42, 0x73, 0xe7, 0xcb, 0x85, 0x56, 0x62, 0x42, 0xab, 0xc4, 0xe7, 0x0f, 0x95, 0xfe, + 0x5a, 0x7b, 0xc4, 0xfd, 0x2b, 0x0d, 0x13, 0x5d, 0x24, 0x2a, 0x44, 0x67, 0xbf, 0x82, 0x2c, 0xa7, 0x02, 0x1c, 0xcb, + 0x33, 0xd1, 0xd0, 0x1f, 0x53, 0x88, 0x83, 0x0e, 0x0d, 0x7a, 0x57, 0x8a, 0xeb, 0xac, 0xe2, 0x21, 0xde, 0x13, 0x1c, + 0xcd, 0xe8, 0x7e, 0x83, 0x0f, 0x65, 0xed, 0xd1, 0xab, 0xc8, 0xc6, 0x51, 0xee, 0x37, 0xbf, 0x56, 0xe1, 0x1c, 0xa2, + 0x55, 0x2e, 0xa8, 0x52, 0x57, 0x5b, 0x00, 0x2a, 0xc7, 0xf6, 0xea, 0x11, 0x9c, 0x6e, 0xea, 0xfa, 0x56, 0x87, 0xd6, + 0x1c, 0x40, 0x98, 0x43, 0xb2, 0x69, 0xb8, 0xda, 0x01, 0xf6, 0x48, 0xac, 0xd7, 0x40, 0x63, 0xed, 0xd6, 0xec, 0xb4, + 0x47, 0x71, 0x98, 0xc8, 0x4c, 0x5b, 0xa4, 0x68, 0x73, 0xb7, 0x4e, 0x8b, 0xa2, 0x0d, 0x9a, 0x21, 0xec, 0xde, 0x75, + 0xf8, 0xba, 0x15, 0x61, 0x7d, 0xbf, 0xed, 0x0b, 0x8c, 0x86, 0x36, 0xd7, 0xee, 0x39, 0x86, 0x6e, 0xd8, 0x60, 0x13, + 0x39, 0x0f, 0x91, 0x0f, 0x33, 0x79, 0x20, 0x8a, 0xc6, 0x18, 0xb0, 0x3d, 0xe2, 0x6a, 0xd3, 0x4a, 0x7e, 0x5e, 0xc6, + 0x9c, 0xed, 0x19, 0xe3, 0x94, 0xd6, 0xd7, 0xb8, 0xe6, 0xb8, 0x2c, 0xa4, 0x6a, 0x8c, 0x67, 0x3c, 0x0c, 0x3b, 0x5f, + 0xe0, 0xce, 0xac, 0x31, 0x78, 0x11, 0x96, 0x4a, 0x76, 0x2a, 0x57, 0x9f, 0xc3, 0x16, 0x47, 0xb3, 0x31, 0xa7, 0xbf, + 0xff, 0x72, 0xc5, 0x17, 0xe8, 0xa6, 0x66, 0xfd, 0x08, 0x82, 0xac, 0x40, 0x87, 0x2c, 0xa9, 0x7a, 0xfc, 0xae, 0x04, + 0x6a, 0x0f, 0xf3, 0xf0, 0x5d, 0xc9, 0x8a, 0xf8, 0x26, 0xbb, 0x8a, 0x6b, 0x51, 0x8e, 0x6e, 0x78, 0x91, 0x8a, 0xd2, + 0x48, 0x8d, 0x83, 0xd3, 0xd5, 0x2a, 0xe7, 0x01, 0x98, 0xca, 0x1b, 0x46, 0xd9, 0x54, 0x96, 0xa9, 0xc1, 0x55, 0xf2, + 0xf4, 0x5a, 0x89, 0xce, 0xab, 0x9b, 0xab, 0x20, 0xc2, 0x5f, 0x17, 0xfa, 0xc7, 0x75, 0x5c, 0x7d, 0x0c, 0x22, 0x63, + 0x53, 0xa7, 0x7f, 0xa0, 0x54, 0x1e, 0xfc, 0xa7, 0x40, 0xa6, 0xfb, 0x5d, 0x09, 0x96, 0xd9, 0xa6, 0xe2, 0xe3, 0x18, + 0x6b, 0x1d, 0x4e, 0xc8, 0x4c, 0x96, 0xe8, 0xbc, 0x4b, 0xd6, 0x25, 0x58, 0xfb, 0x49, 0x2c, 0x63, 0x99, 0x6b, 0x86, + 0x95, 0xc9, 0x8a, 0xf4, 0xac, 0xac, 0xd9, 0x61, 0x68, 0x9c, 0x68, 0xe6, 0xe8, 0x2d, 0xa0, 0x1e, 0xc8, 0xe1, 0x15, + 0x2d, 0xd6, 0xcc, 0xf1, 0xb1, 0xf1, 0x5e, 0x3f, 0x3a, 0xbc, 0x72, 0x04, 0x4a, 0xe6, 0x4e, 0x8e, 0xc2, 0x44, 0xf0, + 0xac, 0xd5, 0xe3, 0x8b, 0x3c, 0x2b, 0x60, 0xe5, 0x4c, 0xc6, 0x63, 0xea, 0x2c, 0xad, 0xd6, 0xcd, 0xd1, 0x22, 0xb9, + 0x66, 0x8f, 0xeb, 0xc7, 0x9c, 0x1c, 0xf2, 0x96, 0xa9, 0x6d, 0xdb, 0x3a, 0xce, 0xd1, 0xe4, 0x4b, 0xd3, 0xfd, 0x6a, + 0x6d, 0x22, 0xa2, 0x4b, 0xe7, 0x3e, 0xeb, 0x15, 0xdc, 0xfa, 0xa6, 0xd0, 0xf4, 0x5a, 0x00, 0x10, 0x9d, 0x32, 0xe0, + 0x2f, 0x59, 0xb1, 0x1e, 0xd5, 0xbc, 0xaa, 0x41, 0xc2, 0x82, 0x22, 0xbc, 0x29, 0xf6, 0xa6, 0xb4, 0x37, 0x4e, 0xc7, + 0x61, 0x07, 0x2e, 0xa6, 0xe8, 0x8e, 0x03, 0x76, 0xfd, 0x5a, 0x2b, 0x1a, 0xa9, 0x5f, 0xb6, 0x2f, 0xb1, 0xea, 0x8b, + 0x52, 0xe6, 0x99, 0x9c, 0x12, 0x8b, 0xdd, 0x56, 0x2e, 0xac, 0xa8, 0xdf, 0x30, 0xe1, 0xd2, 0x95, 0x20, 0x20, 0xd3, + 0x92, 0xf5, 0x4a, 0xbd, 0x8b, 0xc4, 0x1a, 0x08, 0x19, 0x18, 0xbe, 0x06, 0xeb, 0xa2, 0xe2, 0xda, 0x0a, 0xd6, 0xb9, + 0xe7, 0xab, 0x84, 0x42, 0x14, 0x3c, 0xb0, 0x13, 0xf4, 0x43, 0xeb, 0xe6, 0x6d, 0x29, 0x51, 0x06, 0xf1, 0xb8, 0x95, + 0x53, 0x0e, 0x12, 0x08, 0xc0, 0x3d, 0x95, 0x21, 0x38, 0x24, 0xc8, 0x3a, 0xb8, 0x9a, 0x71, 0x04, 0x57, 0x97, 0xce, + 0x5c, 0x5c, 0x03, 0xac, 0x4b, 0x7f, 0x2e, 0x13, 0x5c, 0x58, 0x8d, 0xa8, 0x34, 0x67, 0x9c, 0x62, 0x10, 0x23, 0x43, + 0xd0, 0x57, 0x86, 0xd2, 0x5e, 0x81, 0xa6, 0xf1, 0x9a, 0xad, 0xa4, 0x0f, 0x00, 0xbd, 0x60, 0x2b, 0x69, 0xec, 0x8f, + 0x5f, 0x9f, 0xb3, 0x95, 0x92, 0x06, 0x4f, 0xaf, 0x67, 0x17, 0xb3, 0xf3, 0x01, 0x3b, 0x8a, 0x42, 0x65, 0xc0, 0x10, + 0x58, 0x24, 0xfe, 0x60, 0x10, 0x16, 0xb2, 0x11, 0x83, 0x42, 0x46, 0xc1, 0x72, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, + 0xc3, 0x02, 0x43, 0x5e, 0x79, 0x2f, 0x48, 0x40, 0xa8, 0x2e, 0x0d, 0x5d, 0x1e, 0xc3, 0xe1, 0xe4, 0x60, 0x02, 0xa9, + 0x98, 0x99, 0xc9, 0xc2, 0xd8, 0x98, 0x44, 0x10, 0xef, 0xb4, 0xb3, 0x5e, 0x28, 0xb7, 0xbb, 0xc6, 0x42, 0x8d, 0xc3, + 0xe0, 0xb3, 0x2a, 0x9e, 0x1c, 0x0c, 0xbb, 0x2a, 0xc6, 0x51, 0xb8, 0xd1, 0xca, 0xb7, 0xf3, 0x63, 0x00, 0xaf, 0x3d, + 0x1f, 0xba, 0x72, 0x89, 0xf3, 0xc3, 0x27, 0xe4, 0xf1, 0x13, 0x42, 0xcf, 0xd9, 0xf9, 0x17, 0x4f, 0xe8, 0xb9, 0x24, + 0x27, 0x07, 0x93, 0xe8, 0x86, 0xe9, 0x06, 0x1c, 0x1e, 0xc9, 0x26, 0xd0, 0xab, 0xd1, 0xba, 0x90, 0x0b, 0x4c, 0x39, + 0x34, 0x85, 0xdf, 0x8e, 0x0f, 0x82, 0xc1, 0x4d, 0xbb, 0xe9, 0x37, 0xed, 0xb6, 0x3a, 0x5e, 0x5d, 0x07, 0x47, 0xd1, + 0x6e, 0x31, 0x93, 0x6f, 0xc6, 0x07, 0x76, 0x0e, 0xb0, 0xbe, 0x87, 0xc7, 0x44, 0x37, 0x69, 0x67, 0x54, 0xdc, 0x9a, + 0xbe, 0xc2, 0x3e, 0xf8, 0x45, 0x76, 0xf4, 0x61, 0xf8, 0x6f, 0x75, 0xa2, 0x39, 0xff, 0xe2, 0x08, 0xc8, 0x11, 0xc8, + 0x40, 0xb1, 0x44, 0x30, 0xc3, 0x81, 0xa6, 0x80, 0x82, 0x4c, 0x8d, 0x3b, 0x55, 0xc3, 0x2f, 0x47, 0x4d, 0xce, 0xc8, + 0x0d, 0x4c, 0x0d, 0xb6, 0x05, 0x3f, 0x90, 0xdd, 0x50, 0xdf, 0x28, 0x74, 0x23, 0xe5, 0x64, 0xa6, 0x5f, 0x52, 0xfd, + 0x83, 0xdd, 0x40, 0x00, 0x63, 0x0b, 0x2f, 0x28, 0xd8, 0x97, 0xc7, 0x57, 0x07, 0xb8, 0x8a, 0x00, 0x25, 0x8b, 0x05, + 0x5f, 0x0e, 0xae, 0xd4, 0xe6, 0x3e, 0x08, 0xc8, 0xe0, 0xcb, 0xe0, 0xe4, 0xcb, 0x81, 0x18, 0x04, 0xc7, 0x87, 0x57, + 0x27, 0x81, 0x35, 0xee, 0x87, 0x10, 0x8f, 0xb2, 0xa2, 0x98, 0x69, 0x34, 0x1f, 0xf4, 0x82, 0x92, 0x89, 0xb9, 0xa9, + 0x57, 0x1a, 0x9f, 0xd1, 0x74, 0x6a, 0x90, 0xbf, 0xc3, 0x94, 0xc5, 0xfa, 0x77, 0x30, 0xe1, 0xd7, 0x41, 0x64, 0x83, + 0xa0, 0xce, 0xf2, 0x28, 0xa6, 0x4b, 0x76, 0x5f, 0x85, 0x29, 0x4d, 0x0e, 0x73, 0x42, 0xa2, 0x70, 0x29, 0xc1, 0xf3, + 0xe4, 0xeb, 0x04, 0xe2, 0xb8, 0xda, 0xcf, 0x01, 0xd7, 0x8d, 0xe6, 0x87, 0x09, 0x69, 0x15, 0x61, 0x23, 0xb2, 0x6c, + 0x1a, 0x7a, 0xc9, 0xc2, 0x15, 0xbd, 0x02, 0x66, 0x4a, 0xac, 0xc3, 0x2b, 0xe0, 0xf2, 0xd6, 0xf3, 0xd5, 0x82, 0x5d, + 0x79, 0xd2, 0x37, 0xcd, 0x17, 0x5f, 0x1a, 0x9f, 0x3c, 0xe0, 0x21, 0xad, 0x1f, 0x5e, 0x0a, 0x36, 0x00, 0x37, 0x19, + 0xbf, 0xfd, 0x4e, 0xdc, 0xa9, 0x79, 0x69, 0x4f, 0x31, 0xce, 0x4c, 0x3b, 0x31, 0x69, 0x27, 0xe4, 0xee, 0x7d, 0x7b, + 0x13, 0xeb, 0x93, 0xbd, 0x8a, 0xd6, 0xd2, 0x65, 0xd5, 0x30, 0x24, 0xe5, 0x9a, 0x21, 0x7f, 0x8f, 0x92, 0x53, 0x23, + 0xf0, 0x64, 0x97, 0xbc, 0x4e, 0x96, 0xee, 0x41, 0x65, 0xac, 0x06, 0xcc, 0x31, 0x62, 0x58, 0x28, 0x1c, 0xfb, 0xd7, + 0x19, 0x2b, 0xd7, 0xae, 0x40, 0x23, 0x46, 0xee, 0xed, 0x75, 0xc6, 0x9c, 0x98, 0xab, 0xc9, 0xda, 0x09, 0x55, 0xe7, + 0xa4, 0xe7, 0x2d, 0xde, 0xcb, 0x2a, 0x35, 0xb4, 0x44, 0xf4, 0x60, 0x2c, 0xcd, 0x28, 0x65, 0xa2, 0xd2, 0xa0, 0x91, + 0x8a, 0x8d, 0x6d, 0xf0, 0x4b, 0x70, 0x42, 0xe5, 0x8e, 0x3a, 0xdb, 0xb5, 0x53, 0x2a, 0x1c, 0x60, 0x59, 0xaa, 0x55, + 0xe5, 0x76, 0x99, 0x09, 0x56, 0x0f, 0x82, 0xd1, 0x1f, 0x95, 0x28, 0x66, 0x78, 0x67, 0x64, 0xc1, 0x14, 0xac, 0x04, + 0x65, 0x2d, 0xc3, 0x62, 0xc8, 0x51, 0x8b, 0xa7, 0x7d, 0x52, 0x85, 0xfa, 0xd1, 0x11, 0x24, 0x77, 0xb9, 0x6e, 0x05, + 0xc9, 0x7d, 0x32, 0x7e, 0xa2, 0x06, 0x3a, 0x5d, 0x2b, 0xc7, 0x43, 0x97, 0xdf, 0x46, 0x7c, 0x6d, 0xd5, 0x7b, 0xaa, + 0xb4, 0x0a, 0x55, 0xa0, 0xc4, 0x8a, 0xd2, 0x95, 0x5a, 0xd0, 0xfd, 0x2e, 0x02, 0x60, 0x11, 0x1b, 0xb3, 0xf1, 0xae, + 0x6d, 0x56, 0x08, 0x1a, 0x5d, 0x76, 0xb2, 0x89, 0x07, 0x2c, 0x51, 0xad, 0x1d, 0x4c, 0x68, 0x7c, 0xc2, 0x8a, 0x7e, + 0x3f, 0x3f, 0x01, 0x7a, 0xaa, 0x8c, 0x98, 0x4a, 0x38, 0xf2, 0x3f, 0xb7, 0x22, 0x5d, 0x14, 0xd8, 0xac, 0xc9, 0xbb, + 0x35, 0x96, 0x91, 0xa8, 0xcb, 0x94, 0x2a, 0xaf, 0x72, 0x0c, 0x98, 0xd6, 0xeb, 0x96, 0xe3, 0xca, 0xae, 0xe2, 0xc8, + 0x51, 0x61, 0x19, 0x71, 0x5e, 0x8d, 0xe3, 0xad, 0xc6, 0x37, 0x38, 0xd4, 0x6c, 0xda, 0xa5, 0x3b, 0x84, 0xb0, 0x10, + 0x5e, 0x67, 0x70, 0x1b, 0x51, 0x76, 0x12, 0xa8, 0xbc, 0xd1, 0xd7, 0x09, 0x69, 0x73, 0xbb, 0x5e, 0x3b, 0x06, 0xe9, + 0x44, 0x1f, 0x28, 0xf5, 0x08, 0x5a, 0xa3, 0x58, 0x50, 0x39, 0xe2, 0x91, 0xe5, 0xe1, 0xad, 0x41, 0xac, 0x92, 0x2f, + 0x29, 0x2a, 0x45, 0x03, 0xf4, 0xbf, 0xe4, 0xb7, 0x07, 0xbf, 0xbc, 0xff, 0xe9, 0x8c, 0xc7, 0x65, 0xb2, 0x7c, 0x17, + 0x97, 0xf1, 0x75, 0x15, 0x6e, 0xe4, 0x18, 0xc5, 0x0d, 0x99, 0x56, 0x03, 0x26, 0xf4, 0x4a, 0xf2, 0x77, 0xa5, 0x22, + 0xc4, 0x58, 0x67, 0xb2, 0xae, 0x6a, 0x71, 0xed, 0x55, 0xba, 0x2e, 0x33, 0xfc, 0xb8, 0xe5, 0x73, 0x7a, 0x08, 0x40, + 0x9e, 0xda, 0x85, 0x34, 0x12, 0xaa, 0x10, 0x6d, 0x2e, 0xe2, 0x74, 0x7d, 0x3c, 0xf6, 0xba, 0x5e, 0xb0, 0xa7, 0xe3, + 0xaf, 0xa6, 0xaf, 0xb3, 0x30, 0x1b, 0x54, 0x64, 0x54, 0x2f, 0x79, 0xd1, 0x32, 0xe5, 0x94, 0x26, 0x01, 0xe8, 0xe3, + 0xd9, 0x63, 0xec, 0x68, 0x3c, 0x26, 0x9b, 0xb6, 0x78, 0x80, 0x87, 0xcb, 0x75, 0x58, 0x92, 0x99, 0xaa, 0x23, 0x0a, + 0x0a, 0x7e, 0x57, 0x07, 0x80, 0xe4, 0x68, 0xaa, 0xd2, 0x5c, 0x1a, 0x7b, 0x3a, 0x9e, 0x50, 0x81, 0xdd, 0x0e, 0x49, + 0xe3, 0x54, 0x68, 0x67, 0x5e, 0xb8, 0x1e, 0x45, 0x42, 0xbb, 0x2c, 0xed, 0x54, 0x2a, 0xe4, 0x9e, 0x99, 0xd9, 0xae, + 0x41, 0x0c, 0x86, 0x50, 0xd5, 0x5d, 0x38, 0x75, 0xef, 0x36, 0xd7, 0x98, 0xed, 0x80, 0xf7, 0x1a, 0x34, 0x43, 0xca, + 0x5b, 0xf4, 0x5b, 0x5b, 0x44, 0x43, 0x57, 0x6b, 0x30, 0x2b, 0x46, 0xd9, 0x52, 0x94, 0xae, 0x29, 0x28, 0x05, 0xa3, + 0xcb, 0xb5, 0xb3, 0x70, 0x5f, 0x0b, 0xef, 0xc2, 0x92, 0xa9, 0xd5, 0x22, 0xa5, 0x84, 0xf2, 0xa6, 0xa2, 0xa5, 0x84, + 0x91, 0xd4, 0xf0, 0xd4, 0xae, 0x17, 0x78, 0x9c, 0xe7, 0x41, 0xd4, 0xf2, 0x02, 0x3b, 0xad, 0xc9, 0x29, 0x38, 0x7a, + 0xe9, 0x9c, 0x9a, 0x02, 0xff, 0x98, 0x49, 0x10, 0xd3, 0xa1, 0xbc, 0xdf, 0xe0, 0xe6, 0xff, 0x47, 0xc9, 0x02, 0x87, + 0x6f, 0xbd, 0xc2, 0x6d, 0xf4, 0x8f, 0xd2, 0xa5, 0xa5, 0xcf, 0x84, 0xeb, 0xea, 0xe2, 0x48, 0x7b, 0xb3, 0x51, 0xb2, + 0xcc, 0xf2, 0xf4, 0x8d, 0x48, 0x79, 0x45, 0xa4, 0x09, 0x46, 0xc5, 0x4e, 0x2a, 0xef, 0x86, 0x07, 0x46, 0x8c, 0xde, + 0x8d, 0xef, 0xc7, 0x0c, 0x64, 0xc3, 0x60, 0xf5, 0xcd, 0x52, 0x91, 0xac, 0xaf, 0x01, 0x53, 0x44, 0xca, 0x4f, 0x5e, + 0xe4, 0x1c, 0x9e, 0x42, 0x75, 0xfd, 0x02, 0xb7, 0xb9, 0xca, 0xf5, 0x39, 0xff, 0x31, 0xa3, 0x3f, 0x22, 0xd0, 0x49, + 0xbc, 0x02, 0xb9, 0xc7, 0x33, 0xa8, 0x1b, 0x61, 0x6a, 0x39, 0x06, 0x07, 0x42, 0x34, 0x90, 0xa2, 0x66, 0x81, 0x84, + 0xba, 0xd0, 0xc0, 0x1a, 0xf2, 0x82, 0x39, 0xbc, 0xc8, 0x45, 0xf2, 0x71, 0xaa, 0x7d, 0xe6, 0x87, 0x31, 0xc6, 0x4c, + 0x0e, 0x06, 0x61, 0x3d, 0x0b, 0x86, 0xe3, 0xd1, 0xe4, 0xe8, 0x29, 0x9c, 0xdb, 0xc1, 0x38, 0x20, 0x83, 0xa0, 0xa9, + 0x56, 0x71, 0x41, 0xab, 0x9b, 0x2b, 0x53, 0x06, 0x7e, 0xdc, 0x04, 0x83, 0x7f, 0x94, 0x8e, 0xe2, 0x1d, 0x34, 0x27, + 0xe7, 0x22, 0x04, 0x1b, 0xfb, 0x35, 0x01, 0x49, 0x59, 0x4f, 0xf1, 0x93, 0xea, 0x70, 0x63, 0x52, 0xfb, 0xa7, 0x0f, + 0x2f, 0x38, 0xec, 0x90, 0x40, 0x81, 0x34, 0x9e, 0x66, 0xa3, 0x57, 0x52, 0x91, 0xfb, 0xae, 0xe4, 0x70, 0x67, 0xee, + 0x59, 0xd3, 0x23, 0xab, 0x90, 0xf0, 0xb3, 0x80, 0x1b, 0xf9, 0xab, 0xe2, 0x26, 0xce, 0xb3, 0xf4, 0xc0, 0x7f, 0x73, + 0x50, 0xdd, 0x17, 0x75, 0x7c, 0x37, 0x0a, 0xb4, 0x35, 0x21, 0x77, 0x55, 0x4f, 0x80, 0x9e, 0x00, 0x5b, 0x00, 0x0c, + 0x88, 0x77, 0xcc, 0x4c, 0x66, 0x3c, 0x02, 0x8f, 0x40, 0xdf, 0x07, 0xb2, 0xbc, 0xb7, 0x2e, 0x49, 0xee, 0x66, 0x2a, + 0xcc, 0x55, 0xaf, 0xd8, 0x29, 0xc8, 0x78, 0xb5, 0x15, 0xbb, 0x6e, 0x7d, 0xe6, 0x4d, 0x87, 0x57, 0xe0, 0x85, 0x00, + 0xb7, 0xc8, 0x7e, 0xdf, 0x17, 0x54, 0x56, 0x5a, 0x45, 0xbc, 0x93, 0xdc, 0xa0, 0x7f, 0xbb, 0x33, 0x36, 0x92, 0xe4, + 0x56, 0x0f, 0x0f, 0xa0, 0xca, 0xe4, 0x5c, 0x71, 0x3b, 0x87, 0xa8, 0xad, 0xbb, 0x71, 0xc0, 0x6a, 0x83, 0x76, 0x59, + 0x73, 0x04, 0x17, 0x5e, 0x1c, 0x64, 0x90, 0x13, 0x67, 0x65, 0x24, 0xd5, 0xb8, 0x9a, 0xd4, 0x82, 0x4f, 0xf2, 0x74, + 0x0f, 0x59, 0xea, 0x09, 0x50, 0xe4, 0x38, 0x16, 0x43, 0xba, 0xf1, 0x26, 0xf0, 0xf8, 0xbd, 0x08, 0x41, 0x9a, 0xb6, + 0xdd, 0xfa, 0x23, 0x50, 0x74, 0x0f, 0x4c, 0x41, 0x9a, 0x46, 0x9b, 0x1a, 0x28, 0xa8, 0x3d, 0xd4, 0x48, 0x45, 0x9c, + 0x9d, 0xbc, 0x06, 0x1d, 0x22, 0xf8, 0x7e, 0xa7, 0x59, 0xd5, 0xf1, 0x62, 0x42, 0xf0, 0xe4, 0x7d, 0x71, 0x97, 0x55, + 0x75, 0x15, 0xbd, 0x4f, 0xd1, 0x10, 0x2a, 0x11, 0x45, 0xf4, 0x12, 0xe2, 0xe9, 0x55, 0xf8, 0xbb, 0x8a, 0x7e, 0x4a, + 0x69, 0x9c, 0xa6, 0x98, 0xfe, 0xbc, 0x84, 0x9f, 0xcf, 0x00, 0xd5, 0x11, 0x77, 0x42, 0x74, 0x21, 0xc0, 0x5e, 0x0d, + 0xa2, 0x59, 0xd5, 0x1c, 0x30, 0x34, 0xa3, 0xfb, 0x8a, 0x22, 0x46, 0x1b, 0x66, 0xff, 0xa1, 0x44, 0xa1, 0x90, 0x2c, + 0xe6, 0xd7, 0xca, 0x3c, 0x44, 0x3f, 0x62, 0x91, 0xa7, 0xef, 0x5e, 0xe9, 0x21, 0x8d, 0xee, 0x05, 0x55, 0x5b, 0x1b, + 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xad, 0xe9, 0x79, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, 0x4f, 0xbc, 0x7b, 0xf5, 0x4c, + 0x5a, 0x98, 0x3c, 0xcf, 0x40, 0x71, 0x70, 0xfa, 0xee, 0xd5, 0x6b, 0x91, 0xae, 0x73, 0x1e, 0x9d, 0x0b, 0x24, 0xad, + 0xa7, 0xef, 0x5e, 0xfd, 0x8c, 0xe6, 0x5e, 0x3f, 0x95, 0xf0, 0xfe, 0x25, 0xf0, 0x96, 0x51, 0xbc, 0x86, 0x3e, 0xc9, + 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd4, 0x5a, 0x45, 0xbf, 0xa4, 0x8d, 0x23, 0xad, 0xfa, 0x67, 0xe9, 0x52, 0x3b, 0x47, + 0xc0, 0x73, 0x97, 0x67, 0xc5, 0xc7, 0xc8, 0x88, 0x76, 0x82, 0xe8, 0xcb, 0x83, 0xbb, 0xeb, 0xbc, 0xa8, 0x22, 0x7c, + 0xc1, 0xd0, 0x2e, 0x28, 0x3a, 0x3c, 0xbc, 0xbd, 0xbd, 0x1d, 0xdd, 0x7e, 0x35, 0x12, 0xe5, 0xd5, 0xe1, 0xe4, 0xdb, + 0x6f, 0xbf, 0x3d, 0xc4, 0xb7, 0xc1, 0x97, 0x6d, 0xb7, 0xf7, 0x9a, 0xf0, 0x01, 0x0b, 0x10, 0xa1, 0xfa, 0x4b, 0xb8, + 0xa2, 0x80, 0x16, 0x6e, 0xf0, 0x65, 0xf0, 0xa5, 0x3a, 0x74, 0xbe, 0x3c, 0xae, 0x6e, 0xae, 0x64, 0xf9, 0x5d, 0x25, + 0x1f, 0x8d, 0xc7, 0xe3, 0x43, 0x90, 0x40, 0x7d, 0x39, 0xe0, 0x83, 0xe0, 0x24, 0x18, 0x64, 0x70, 0xa1, 0xa9, 0x6e, + 0xae, 0x4e, 0x02, 0xc7, 0x34, 0xd7, 0x63, 0x11, 0x2d, 0x88, 0x4b, 0x70, 0x78, 0x45, 0x83, 0x2f, 0x03, 0x62, 0x53, + 0xbe, 0x80, 0x94, 0x2f, 0x8e, 0x9e, 0xba, 0x69, 0xff, 0x4b, 0xa6, 0x7d, 0xe5, 0xa6, 0x1d, 0x63, 0xda, 0x57, 0xcf, + 0xdc, 0xb4, 0x13, 0x99, 0xf6, 0xc2, 0x4d, 0xfb, 0xdf, 0xd5, 0x00, 0x52, 0x0f, 0x5c, 0xeb, 0xbf, 0x0b, 0xa7, 0x35, + 0x78, 0x0a, 0x45, 0xd9, 0x75, 0x7c, 0xc5, 0xa1, 0xd1, 0x83, 0xbb, 0xeb, 0x9c, 0x06, 0x03, 0x6c, 0xaf, 0x63, 0xe4, + 0xe1, 0x7c, 0xf0, 0xe5, 0xba, 0xcc, 0xc3, 0xe0, 0xcb, 0x01, 0x16, 0x32, 0xf8, 0x32, 0x20, 0x5f, 0xaa, 0x23, 0xed, + 0xae, 0x62, 0x9b, 0xc0, 0x86, 0x22, 0x1d, 0x9a, 0x00, 0x61, 0xae, 0x34, 0xae, 0xa1, 0x7f, 0x96, 0xdd, 0xd9, 0xf0, + 0x96, 0x28, 0xdd, 0x74, 0x83, 0x86, 0xbe, 0x05, 0xef, 0x04, 0x68, 0x54, 0x14, 0xdc, 0xc4, 0x65, 0x38, 0x1c, 0x56, + 0x37, 0x57, 0x04, 0xec, 0x32, 0x57, 0x3c, 0xae, 0xa3, 0xa0, 0x10, 0x43, 0xf9, 0x33, 0x90, 0x91, 0xaf, 0x02, 0x04, + 0x44, 0x82, 0xff, 0x82, 0x86, 0xbe, 0x13, 0x6c, 0x13, 0x0c, 0x6f, 0xf9, 0xc5, 0xc7, 0xac, 0x1e, 0x4a, 0xd1, 0xe2, + 0x5d, 0x45, 0xe1, 0x07, 0xfc, 0xb5, 0x55, 0x47, 0x7f, 0x82, 0x1b, 0xb7, 0xaf, 0x61, 0x7f, 0x27, 0x2c, 0x8b, 0xfa, + 0x4e, 0xcc, 0xb3, 0xc5, 0xb4, 0x75, 0xa0, 0xbf, 0x15, 0xa4, 0x9e, 0x67, 0x83, 0x60, 0x18, 0x0c, 0xf8, 0x82, 0xbd, + 0x15, 0x73, 0xee, 0x98, 0x4f, 0x3d, 0x12, 0xee, 0x34, 0xcf, 0xb2, 0x01, 0xf8, 0xa6, 0x20, 0x3f, 0x72, 0xf8, 0xdf, + 0xf3, 0x21, 0x0a, 0x0f, 0x07, 0x8f, 0x0e, 0xc9, 0x2c, 0x58, 0xdd, 0xa1, 0x47, 0x67, 0x14, 0x64, 0xc5, 0x92, 0x97, + 0x59, 0xed, 0x2c, 0x95, 0xfb, 0x75, 0xdb, 0xcb, 0x63, 0xef, 0xd9, 0xbc, 0x8a, 0x8b, 0x40, 0x9e, 0x73, 0xa0, 0x78, + 0x43, 0xd9, 0x53, 0xe1, 0x4b, 0x48, 0x95, 0x21, 0x6f, 0x58, 0x0c, 0x58, 0x70, 0xdc, 0x1b, 0x0e, 0x0f, 0x82, 0x81, + 0x55, 0xe7, 0x0e, 0x82, 0x83, 0xe1, 0xf0, 0x24, 0xb0, 0xf7, 0xa1, 0x6c, 0x64, 0xef, 0x8c, 0xb4, 0x64, 0xff, 0x2c, + 0xc3, 0x82, 0x82, 0x78, 0x4c, 0x28, 0xf1, 0x97, 0x02, 0x97, 0x19, 0x00, 0xf4, 0x91, 0x94, 0x80, 0x69, 0x58, 0x99, + 0x01, 0x84, 0xe6, 0xa6, 0x31, 0x3b, 0x07, 0xe6, 0x91, 0x26, 0x20, 0xde, 0x03, 0x8a, 0x01, 0x88, 0x25, 0x01, 0xce, + 0x5d, 0x10, 0xc5, 0xaa, 0x90, 0x47, 0x00, 0x7a, 0x8f, 0x3f, 0x89, 0x2e, 0x05, 0x93, 0x54, 0xac, 0x42, 0x10, 0xc4, + 0xf1, 0xd9, 0x5d, 0xd5, 0x9a, 0x9c, 0x25, 0x3a, 0x98, 0x91, 0x04, 0xd8, 0x10, 0x0d, 0x3b, 0x07, 0xf7, 0x73, 0x50, + 0x7a, 0x18, 0xbd, 0x13, 0x72, 0xc1, 0xf7, 0xdc, 0xb2, 0x50, 0x77, 0x70, 0xf5, 0x84, 0x83, 0xe0, 0x9e, 0x2b, 0x16, + 0x60, 0x54, 0x97, 0xeb, 0xaa, 0xe6, 0xe9, 0x87, 0xfb, 0x15, 0xc4, 0xbe, 0xc3, 0x01, 0x7d, 0x27, 0xf2, 0x2c, 0xb9, + 0x0f, 0xad, 0x3d, 0xd7, 0x46, 0xa6, 0xff, 0xf0, 0xe1, 0xf5, 0x4f, 0x11, 0x88, 0x1c, 0x1b, 0x4d, 0xe9, 0xef, 0x39, + 0x9e, 0x4d, 0x6e, 0x84, 0x27, 0x77, 0x63, 0xdf, 0x73, 0x73, 0x7a, 0xf4, 0xfb, 0x50, 0x37, 0xbd, 0xe7, 0xb3, 0x7b, + 0x3e, 0xb2, 0xc5, 0xa1, 0xba, 0xc2, 0x7e, 0x7d, 0xbb, 0x76, 0x8d, 0x90, 0x1e, 0x9e, 0x67, 0xca, 0xbd, 0xf9, 0x51, + 0x0e, 0x86, 0x41, 0x30, 0x55, 0x42, 0x49, 0x88, 0xba, 0xc1, 0xa4, 0x80, 0x21, 0x3a, 0x50, 0xcb, 0x6a, 0x8a, 0x9c, + 0x9b, 0x1c, 0x59, 0x78, 0x3f, 0x60, 0x4a, 0xe8, 0xe0, 0xe5, 0x90, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc0, 0x6f, 0x15, + 0x30, 0xfd, 0x72, 0x51, 0x59, 0x07, 0xd1, 0x03, 0x30, 0xc6, 0x2d, 0x78, 0x09, 0x5d, 0x61, 0x37, 0x6b, 0x19, 0x15, + 0x03, 0xc1, 0xe3, 0x90, 0x03, 0x74, 0xb0, 0x0b, 0x5a, 0x56, 0x96, 0xf2, 0x56, 0x65, 0x2d, 0x55, 0xe4, 0x65, 0x28, + 0xab, 0x62, 0x89, 0xf9, 0x5e, 0xb0, 0x1f, 0x4a, 0xf4, 0x2c, 0x9f, 0x56, 0x5d, 0xf0, 0x42, 0x28, 0xc1, 0xb2, 0x5d, + 0xef, 0x44, 0x20, 0xea, 0x4c, 0x75, 0xae, 0xfa, 0x0a, 0xc7, 0x8e, 0xa7, 0xaf, 0x45, 0xca, 0x95, 0x09, 0x85, 0xe2, + 0xf3, 0x85, 0xab, 0x98, 0x28, 0xd9, 0x2d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd7, 0x6a, 0x33, 0x48, 0xd1, 0x31, + 0x6f, 0x50, 0x70, 0x2d, 0x15, 0x0a, 0x5a, 0x7b, 0x1b, 0x7f, 0x82, 0x23, 0x37, 0xba, 0x3d, 0xf4, 0x7e, 0xab, 0xe3, + 0xab, 0x37, 0xe8, 0xdb, 0x69, 0x7e, 0x8e, 0x6a, 0xf1, 0xcb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, 0xe0, 0xd2, + 0x42, 0x3d, 0x67, 0xef, 0x4e, 0xdf, 0x80, 0x1f, 0x25, 0xfe, 0xfe, 0xf5, 0xfb, 0xa0, 0x21, 0xd3, 0x78, 0x56, 0xea, + 0x0f, 0x4d, 0x0e, 0x08, 0x4d, 0x62, 0xd3, 0xcc, 0xfb, 0x59, 0xec, 0xb3, 0xef, 0x8a, 0xad, 0xa7, 0xa5, 0x8f, 0x24, + 0xa5, 0xb9, 0x7d, 0x30, 0x20, 0x50, 0x07, 0x88, 0xe4, 0xec, 0x4b, 0x1a, 0x43, 0x9a, 0xcb, 0xec, 0xbb, 0x11, 0xf1, + 0x5e, 0xec, 0x84, 0x10, 0xe3, 0x12, 0x8b, 0x46, 0x0d, 0xf9, 0x8c, 0x47, 0xd2, 0xb0, 0xe8, 0x3d, 0x26, 0x10, 0x6b, + 0x38, 0x2d, 0xdf, 0x23, 0xe6, 0x31, 0xde, 0x0d, 0x94, 0xec, 0x21, 0xca, 0xa8, 0xcd, 0xee, 0x59, 0x7c, 0x7f, 0x5c, + 0x87, 0x99, 0xb1, 0xbc, 0x1c, 0xc2, 0xdf, 0x40, 0x19, 0x80, 0x53, 0x8e, 0x2c, 0x5f, 0xad, 0x37, 0xba, 0x5c, 0x62, + 0x6a, 0x13, 0x41, 0x2c, 0x1e, 0x95, 0x0e, 0x6b, 0x57, 0xa5, 0xaa, 0x5d, 0x6d, 0x7d, 0x26, 0x7a, 0x35, 0x68, 0xe5, + 0xda, 0xf6, 0x78, 0x08, 0x77, 0xa9, 0xa4, 0x15, 0x26, 0xb0, 0x5e, 0x65, 0x15, 0x2a, 0xd8, 0x9c, 0x80, 0x06, 0xd7, + 0x22, 0x05, 0xe0, 0x2c, 0xa5, 0x46, 0xa3, 0x5a, 0xd8, 0x67, 0xe4, 0x7c, 0x16, 0x5b, 0x0b, 0xf1, 0xb4, 0x00, 0x0c, + 0xd7, 0xc7, 0xa0, 0xe4, 0xdd, 0x18, 0x94, 0xd3, 0x8f, 0x12, 0xde, 0x3a, 0x38, 0xaf, 0x96, 0x71, 0x2a, 0x6e, 0x01, + 0x8b, 0x31, 0x70, 0x53, 0xb1, 0x54, 0x27, 0x21, 0x59, 0xf2, 0xe4, 0x23, 0x5a, 0x6d, 0xa4, 0x01, 0x70, 0x95, 0x53, + 0x6d, 0xb9, 0x27, 0x41, 0x42, 0x6d, 0x29, 0x32, 0x21, 0xae, 0xeb, 0x38, 0x59, 0x9e, 0x61, 0x6a, 0xb8, 0x81, 0x5e, + 0x44, 0x81, 0x58, 0xf1, 0x02, 0x48, 0x7a, 0xce, 0xfe, 0x95, 0x29, 0xac, 0xf1, 0x67, 0x02, 0x05, 0x4c, 0x0a, 0x35, + 0x18, 0x2b, 0x65, 0x2f, 0x84, 0x8e, 0xf6, 0x16, 0x04, 0x8d, 0x7d, 0xf9, 0x27, 0xd4, 0xfd, 0x0c, 0x5a, 0x11, 0x7a, + 0x60, 0x88, 0xe2, 0x02, 0x77, 0x68, 0x6a, 0x96, 0x9c, 0x03, 0x8c, 0x58, 0x18, 0xef, 0xb3, 0xc6, 0x6c, 0xf5, 0x67, + 0x4b, 0xc0, 0x36, 0x4d, 0xb5, 0x4f, 0x61, 0x98, 0x10, 0x1d, 0x1b, 0xd8, 0x28, 0x2b, 0xcd, 0x86, 0xd2, 0xed, 0xa4, + 0x4b, 0xe6, 0xb4, 0x70, 0x9a, 0xf7, 0x18, 0x5b, 0x8e, 0x64, 0xee, 0x7e, 0x3f, 0xd4, 0x3f, 0x59, 0x4e, 0x9f, 0xa9, + 0x90, 0xcd, 0xce, 0x78, 0xd0, 0x9c, 0x28, 0x75, 0x55, 0x47, 0x3f, 0xa0, 0x03, 0x30, 0xd3, 0x06, 0x20, 0xd3, 0x06, + 0x9b, 0x76, 0x95, 0xa8, 0xb8, 0x24, 0x61, 0xa9, 0x24, 0xb0, 0xb3, 0x7d, 0xc9, 0xce, 0x26, 0x20, 0x8e, 0xe1, 0xae, + 0xa3, 0xc5, 0x4e, 0x88, 0x0f, 0x6f, 0x71, 0x90, 0x80, 0xa8, 0x43, 0x56, 0x97, 0x90, 0x8d, 0x36, 0x74, 0x71, 0x2f, + 0x4a, 0x61, 0xc2, 0x5a, 0x26, 0x55, 0x89, 0x0e, 0x82, 0x54, 0xed, 0xb6, 0x08, 0x2c, 0x51, 0xb0, 0x03, 0xd8, 0x7b, + 0x3b, 0xea, 0x7a, 0xd4, 0x64, 0x75, 0xf2, 0x25, 0xf8, 0x38, 0xcd, 0xba, 0x0a, 0xd2, 0x0b, 0xbb, 0x2e, 0xd7, 0x3c, + 0x50, 0xb1, 0xa9, 0xa4, 0x31, 0x71, 0x97, 0x16, 0x19, 0xe2, 0x01, 0x63, 0x2c, 0x5d, 0x08, 0xe4, 0x9b, 0xed, 0x8e, + 0x9b, 0x9a, 0x20, 0xf4, 0x13, 0xd6, 0x94, 0xc0, 0x4e, 0x67, 0x7b, 0x6a, 0xfc, 0x7c, 0x40, 0xc4, 0x61, 0x40, 0x81, + 0x64, 0xe3, 0x90, 0xe6, 0x48, 0x5f, 0x90, 0x34, 0x61, 0x60, 0x68, 0xc9, 0x73, 0x82, 0xac, 0x28, 0x74, 0x6c, 0x5d, + 0x95, 0x71, 0xae, 0x08, 0x73, 0xb4, 0xe4, 0x94, 0xf8, 0x9c, 0x20, 0x13, 0xdb, 0xd3, 0x36, 0x3d, 0x19, 0x96, 0x92, + 0x05, 0xfa, 0x57, 0x10, 0x25, 0xf6, 0x4c, 0x33, 0x2a, 0x07, 0xed, 0x02, 0x16, 0x28, 0xe5, 0x7b, 0xd0, 0x78, 0x6b, + 0x68, 0xa3, 0x60, 0x88, 0xed, 0xfe, 0x04, 0xfb, 0xb5, 0x76, 0x5a, 0x97, 0x29, 0x96, 0x93, 0x29, 0x44, 0x7b, 0x21, + 0xfd, 0x1b, 0x45, 0xa2, 0x3b, 0x45, 0x68, 0x12, 0xd6, 0x51, 0xf6, 0xa4, 0x4d, 0x0d, 0xa0, 0xa7, 0x4e, 0xc0, 0xf3, + 0xce, 0xb5, 0x0c, 0xbb, 0x48, 0xf5, 0x57, 0x06, 0x9f, 0x52, 0x0d, 0x82, 0x14, 0xb5, 0x49, 0xc1, 0x9c, 0xd7, 0xa1, + 0xa4, 0xce, 0x9c, 0xb6, 0xcc, 0xa8, 0x3a, 0x2a, 0x42, 0xca, 0x09, 0xfe, 0x93, 0x57, 0x42, 0x11, 0x9b, 0x30, 0xc1, + 0x03, 0x1f, 0xe6, 0x19, 0x36, 0xf0, 0x76, 0xfb, 0x2e, 0x0d, 0x93, 0x36, 0xdb, 0x90, 0x82, 0xb4, 0x42, 0xc7, 0xc5, + 0x80, 0xca, 0x5e, 0xe1, 0x7e, 0xc1, 0x76, 0xd2, 0x14, 0x3c, 0x08, 0xbd, 0x06, 0x26, 0x76, 0x75, 0xf1, 0x75, 0x98, + 0xd0, 0x70, 0x49, 0x95, 0xb3, 0x93, 0x92, 0x34, 0xb7, 0xd7, 0xe5, 0xa5, 0xe9, 0x83, 0x8a, 0x1d, 0xd6, 0x35, 0x3c, + 0xd0, 0x3c, 0xbf, 0x8b, 0x2b, 0xa6, 0x68, 0xa2, 0xb6, 0x1e, 0x92, 0x96, 0x1c, 0xeb, 0x66, 0xba, 0xc2, 0xd5, 0x32, + 0x53, 0xc0, 0xee, 0x02, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x89, 0xcd, 0x66, 0xab, 0x86, 0x4c, 0xf3, + 0x7d, 0xd9, 0x72, 0x1d, 0x10, 0xce, 0x50, 0xdf, 0xdc, 0x25, 0xc7, 0x8a, 0xb6, 0xb9, 0x49, 0x80, 0xe3, 0xed, 0x14, + 0x90, 0x74, 0x2c, 0x41, 0x1b, 0xdf, 0xd2, 0x1d, 0x44, 0xaa, 0xa7, 0x82, 0xee, 0x9d, 0x2f, 0xd2, 0xf8, 0x5f, 0x80, + 0x6d, 0xd4, 0x46, 0x9b, 0x66, 0x65, 0xeb, 0x30, 0x91, 0x16, 0xd6, 0xc8, 0x42, 0x2e, 0xc1, 0x07, 0x73, 0xb7, 0xa9, + 0xd3, 0xd3, 0x0e, 0x22, 0xec, 0x76, 0xd1, 0xe1, 0x11, 0xc6, 0x92, 0x35, 0x48, 0x34, 0xab, 0xb0, 0xa6, 0xfe, 0x72, + 0x88, 0x72, 0xaa, 0x97, 0x4c, 0xb4, 0xa4, 0x2e, 0xa5, 0x88, 0x52, 0x30, 0x37, 0x9e, 0x16, 0x9e, 0x29, 0x21, 0x42, + 0x56, 0x08, 0x0b, 0x54, 0x6b, 0xa0, 0xa5, 0x7c, 0xd0, 0xeb, 0xd0, 0xc9, 0x42, 0x63, 0x0a, 0xa2, 0x8f, 0x48, 0x73, + 0x23, 0x96, 0x8c, 0xee, 0x8e, 0x51, 0x4c, 0x20, 0x54, 0xb5, 0x93, 0x17, 0x56, 0x9f, 0x92, 0x6d, 0x75, 0x10, 0xd7, + 0x98, 0x26, 0x7b, 0x08, 0x6a, 0x8c, 0x82, 0x36, 0xab, 0x1b, 0xfd, 0xa5, 0x0c, 0x5d, 0xbb, 0x70, 0xec, 0x46, 0x49, + 0x04, 0x44, 0x60, 0x75, 0x9a, 0x8a, 0x01, 0x59, 0xe7, 0xb1, 0x8d, 0xd0, 0xa4, 0xba, 0x85, 0x28, 0x6f, 0x54, 0x34, + 0x1f, 0xd7, 0x21, 0xd9, 0x6e, 0xb1, 0x2c, 0xf0, 0x65, 0x3f, 0x5b, 0xef, 0x81, 0xfc, 0x7e, 0xbd, 0xfe, 0x24, 0xe4, + 0xf7, 0xab, 0xec, 0x73, 0x20, 0xbf, 0x5f, 0xaf, 0xff, 0xa7, 0x21, 0xbf, 0xcf, 0xd6, 0x0e, 0xe4, 0xb7, 0x1c, 0x8c, + 0xdf, 0x4a, 0x16, 0xbc, 0x7d, 0x13, 0xd0, 0xe7, 0x82, 0x05, 0x6f, 0x5f, 0xbe, 0x74, 0x84, 0xe9, 0xdf, 0xe9, 0x38, + 0x2f, 0x5a, 0x16, 0x8c, 0xb8, 0x2d, 0xf0, 0x0a, 0xb5, 0x4e, 0x2e, 0x50, 0x51, 0x06, 0xc0, 0xeb, 0xd5, 0x3f, 0xb2, + 0x7a, 0x19, 0x06, 0x87, 0x01, 0x99, 0x59, 0x48, 0xd0, 0xe1, 0x04, 0x6e, 0x6f, 0x68, 0x64, 0x59, 0x7f, 0x16, 0x7c, + 0xf8, 0x68, 0x34, 0x8a, 0xcb, 0x2b, 0xbc, 0xd4, 0xe9, 0x8d, 0x84, 0x80, 0xc7, 0x19, 0xaf, 0x4c, 0x88, 0x88, 0x65, + 0x5c, 0x9d, 0xab, 0xd8, 0x2c, 0x95, 0xd9, 0x8a, 0x10, 0x71, 0xfe, 0x1c, 0x70, 0xea, 0xcd, 0xde, 0x8c, 0xb1, 0x1f, + 0x92, 0x23, 0x56, 0x01, 0x64, 0x9f, 0xad, 0xd5, 0xbb, 0x8b, 0xb8, 0xe2, 0xef, 0xe2, 0x7a, 0xc9, 0xa0, 0x97, 0x70, + 0x17, 0x29, 0x78, 0x52, 0x3b, 0x6c, 0x93, 0x04, 0x2a, 0xcf, 0x14, 0x50, 0x79, 0xc7, 0x7b, 0x1a, 0x9a, 0x61, 0x51, + 0x3e, 0xc0, 0x5a, 0xba, 0x9c, 0x81, 0xd1, 0xe2, 0x8b, 0x1b, 0x5e, 0xd4, 0x3f, 0x01, 0x9e, 0x7a, 0xc1, 0x4b, 0xb8, + 0x25, 0x20, 0x17, 0xeb, 0x39, 0x21, 0xd0, 0xca, 0xf5, 0xec, 0x90, 0x51, 0x63, 0xb4, 0x68, 0xc2, 0xeb, 0x37, 0xde, + 0x84, 0xd0, 0xbb, 0x13, 0x74, 0x45, 0x18, 0x09, 0xef, 0xcf, 0x35, 0x3f, 0xcf, 0xc0, 0x7c, 0xbe, 0x02, 0x28, 0x0d, + 0x84, 0x43, 0x65, 0x52, 0x6e, 0x81, 0x09, 0x1b, 0x6d, 0xae, 0x94, 0xa5, 0x0e, 0x52, 0x29, 0x95, 0x70, 0xba, 0x15, + 0x4d, 0x05, 0xe0, 0x70, 0x47, 0x02, 0xc0, 0x4c, 0x4d, 0x61, 0x10, 0xdd, 0x36, 0xa5, 0x59, 0x1a, 0x59, 0x45, 0x9a, + 0xc5, 0x27, 0xa5, 0x12, 0x74, 0xfa, 0x3c, 0x89, 0x6b, 0x7e, 0x25, 0x4a, 0x08, 0x85, 0xdb, 0x4a, 0x69, 0x0c, 0x16, + 0x80, 0x3c, 0xee, 0xac, 0xcd, 0xd6, 0xac, 0x94, 0x29, 0xe7, 0xc5, 0xfa, 0x9a, 0x97, 0x59, 0x72, 0xbe, 0xcc, 0xaa, + 0x5a, 0x94, 0xf7, 0x6c, 0xae, 0xb2, 0x2e, 0xa2, 0x6a, 0xa4, 0x24, 0x5e, 0xe7, 0x35, 0xbf, 0x5e, 0x41, 0xe8, 0x87, + 0x75, 0x09, 0xac, 0xe7, 0xde, 0x2f, 0x65, 0x64, 0xd2, 0xb0, 0xf3, 0x3b, 0xb2, 0x00, 0xbd, 0x2b, 0xac, 0x11, 0xb9, + 0x00, 0x98, 0x5e, 0x33, 0xa7, 0x92, 0xaa, 0x94, 0xfe, 0x6b, 0x8d, 0x33, 0xef, 0x2f, 0xaa, 0x71, 0x6b, 0xed, 0x19, + 0xad, 0xad, 0x9f, 0x2a, 0xe1, 0x94, 0x80, 0x12, 0xb1, 0x13, 0x5c, 0x31, 0x29, 0x5d, 0x1b, 0xb4, 0x16, 0xb0, 0xac, + 0xc0, 0x1c, 0x59, 0x71, 0x75, 0x7e, 0x2b, 0x65, 0x35, 0x3d, 0x49, 0xcd, 0xd2, 0x28, 0x96, 0x28, 0x42, 0x4b, 0x16, + 0xae, 0x59, 0xb2, 0x27, 0xd7, 0x3a, 0x4a, 0x3c, 0x3c, 0xb0, 0xb8, 0x3d, 0xe8, 0xc7, 0x49, 0x3b, 0x65, 0xbb, 0xdd, + 0xc9, 0x04, 0x6c, 0x48, 0x2b, 0x09, 0x22, 0x83, 0x2c, 0x67, 0xc3, 0x49, 0x04, 0x70, 0x2d, 0x8a, 0x84, 0xfe, 0xb9, + 0xe6, 0x1a, 0xd0, 0x3e, 0x54, 0x5e, 0x85, 0x72, 0x15, 0xcd, 0xc1, 0xce, 0xcb, 0xed, 0x35, 0x04, 0x96, 0xe9, 0x9c, + 0x97, 0xc5, 0xfe, 0x35, 0xa0, 0xcc, 0x91, 0xd5, 0x0b, 0xb2, 0x6f, 0xc6, 0x55, 0xb6, 0x07, 0xa7, 0xb7, 0x35, 0x07, + 0x7b, 0x5b, 0xa3, 0x50, 0x7a, 0x13, 0x1e, 0x0e, 0x9f, 0x8e, 0x8d, 0x3f, 0x03, 0xae, 0x72, 0xf3, 0x5b, 0xee, 0x04, + 0xfb, 0x6c, 0x76, 0x03, 0xf5, 0x5d, 0x22, 0xda, 0x35, 0xd2, 0x6a, 0xcf, 0xb8, 0x35, 0xa4, 0xb1, 0x2b, 0xcd, 0x88, + 0xb9, 0x7e, 0x97, 0x47, 0xeb, 0xf9, 0xa3, 0x4d, 0xa6, 0xaa, 0x6c, 0x7e, 0xcf, 0x4c, 0x50, 0x3c, 0x8f, 0x4c, 0x35, + 0x6a, 0x0d, 0xba, 0x98, 0x74, 0x1d, 0xd9, 0xd4, 0x8c, 0xb2, 0xac, 0x93, 0xd6, 0x8d, 0xe4, 0x23, 0x97, 0x31, 0xc2, + 0xba, 0xb3, 0xf0, 0x3b, 0x9e, 0x84, 0x5d, 0x0d, 0x93, 0xd7, 0x10, 0xdd, 0x05, 0x84, 0xe9, 0x04, 0xe5, 0x43, 0xf8, + 0xfb, 0xa3, 0x8d, 0x4f, 0x3b, 0x9b, 0x43, 0xe7, 0x33, 0xfc, 0x9d, 0xa5, 0xf0, 0xb7, 0x6e, 0x7e, 0xa7, 0x9b, 0x6b, + 0x5e, 0x2f, 0x45, 0x1a, 0x05, 0xef, 0xde, 0x9e, 0x7d, 0x08, 0x14, 0xfc, 0x3b, 0x5e, 0x82, 0xb4, 0xda, 0x5b, 0x03, + 0x4d, 0x81, 0x1a, 0x28, 0x17, 0x57, 0x88, 0x80, 0xa8, 0x20, 0xf4, 0xcf, 0x96, 0xe2, 0xf6, 0x34, 0xcf, 0x5d, 0x4e, + 0x5d, 0x53, 0x77, 0xc5, 0xbc, 0x7a, 0xa4, 0x31, 0x04, 0x81, 0xe3, 0x28, 0xab, 0xce, 0x95, 0x8a, 0x28, 0x3d, 0xbf, + 0xb8, 0x3f, 0x57, 0x62, 0x28, 0x03, 0x41, 0xf9, 0xec, 0xf7, 0xe3, 0x34, 0xbb, 0x39, 0xc0, 0x23, 0x88, 0x05, 0x60, + 0xbf, 0x9f, 0xf3, 0x8b, 0x75, 0x5d, 0x8b, 0x62, 0x58, 0x8a, 0xdb, 0xe0, 0xe4, 0x58, 0x3e, 0xe8, 0x0c, 0xb1, 0x7c, + 0x0c, 0x0e, 0xfe, 0x2b, 0xc9, 0xb3, 0xe4, 0x23, 0x0b, 0x1e, 0x6d, 0x32, 0x76, 0xd2, 0x3a, 0x68, 0xc6, 0x4d, 0x70, + 0x02, 0x6d, 0x3d, 0x38, 0xcd, 0xf3, 0xe3, 0x43, 0xf9, 0xc5, 0xc9, 0xf1, 0x61, 0x9a, 0xdd, 0x9c, 0x38, 0xd1, 0x00, + 0xac, 0x71, 0x2f, 0xe2, 0xae, 0xd9, 0xcb, 0x3b, 0x78, 0xf1, 0x26, 0x3c, 0x34, 0xec, 0x0e, 0x88, 0x8c, 0x74, 0x2c, + 0x15, 0x14, 0x33, 0x85, 0x31, 0x1c, 0xee, 0xdb, 0x6d, 0x68, 0x2c, 0x8f, 0x12, 0x07, 0x96, 0xa7, 0x04, 0x76, 0x08, + 0xb3, 0xd0, 0x84, 0xd0, 0xa4, 0x21, 0xa1, 0x06, 0x0f, 0x8a, 0x09, 0x2d, 0x1b, 0x0a, 0xe7, 0xdd, 0xeb, 0x78, 0xa5, + 0x25, 0x6d, 0x4a, 0x72, 0xa1, 0x5b, 0x3f, 0xf3, 0xc6, 0x31, 0x6a, 0x8f, 0xaa, 0x86, 0xf3, 0xea, 0x15, 0xfb, 0x06, + 0x16, 0x84, 0xab, 0x61, 0x4d, 0x83, 0x16, 0x69, 0x01, 0xe1, 0xa8, 0x2b, 0xd3, 0xe3, 0x34, 0x9c, 0x17, 0x54, 0x2c, + 0x08, 0x3b, 0x09, 0x37, 0xc8, 0xdb, 0x17, 0x54, 0xb2, 0xfa, 0xa2, 0xb1, 0xd8, 0x9a, 0x72, 0x76, 0x4e, 0x1e, 0x6d, + 0x64, 0xcc, 0xde, 0x82, 0x9d, 0xf8, 0xf3, 0x55, 0xc7, 0x17, 0xc3, 0x25, 0x07, 0x27, 0xa0, 0xe0, 0xe0, 0xbf, 0xd2, + 0x8b, 0xdc, 0x4c, 0x8a, 0x5c, 0x91, 0xcb, 0xb8, 0x48, 0x73, 0xfe, 0x21, 0xbe, 0xf8, 0x01, 0xf3, 0x3c, 0xbf, 0xc8, + 0x9f, 0x41, 0x86, 0x26, 0x38, 0x79, 0xb4, 0x49, 0xea, 0xd1, 0x8b, 0x37, 0x1f, 0x5e, 0x7d, 0xf8, 0xe7, 0xf9, 0xb3, + 0xd3, 0x0f, 0x2f, 0xbe, 0x7f, 0xfb, 0xfe, 0xd5, 0x8b, 0xb3, 0xb9, 0xf1, 0xba, 0x95, 0x60, 0x6e, 0x64, 0xb1, 0xdd, + 0xda, 0x7c, 0xbf, 0xbc, 0x79, 0xfe, 0xe2, 0xe5, 0xab, 0x37, 0x2f, 0x9e, 0x37, 0x72, 0x2e, 0xdb, 0x0d, 0x81, 0x1d, + 0x1a, 0x67, 0x05, 0x2f, 0xa1, 0x78, 0x75, 0xbb, 0xc3, 0x66, 0x2b, 0x0c, 0x42, 0xbf, 0xe9, 0x2a, 0x5c, 0x03, 0x2c, + 0xb2, 0x03, 0xb5, 0x59, 0xa0, 0xe1, 0x42, 0x6f, 0x1c, 0x77, 0x89, 0xb9, 0xbd, 0x79, 0x81, 0xdf, 0xbd, 0x17, 0xb7, + 0xba, 0x2b, 0x6a, 0x84, 0x24, 0xbc, 0xd8, 0xec, 0xd9, 0xef, 0xc7, 0xae, 0x48, 0x0f, 0xe5, 0x1e, 0xb2, 0x5c, 0xf8, + 0xd5, 0x04, 0x07, 0xca, 0xbc, 0x30, 0x80, 0xe8, 0x18, 0xc1, 0xc9, 0xf1, 0xa1, 0x9b, 0xfb, 0xe4, 0xf7, 0xe8, 0x27, + 0xa7, 0x73, 0x58, 0x2a, 0x8c, 0x83, 0x9f, 0xb6, 0x73, 0x2c, 0x02, 0x7d, 0xb6, 0x07, 0xa7, 0x5c, 0x41, 0x9a, 0x5c, + 0x09, 0x12, 0x99, 0x49, 0x94, 0x66, 0x33, 0xba, 0xb4, 0xdf, 0xd5, 0x5f, 0xdb, 0x67, 0x14, 0x43, 0xf0, 0xa2, 0x12, + 0x25, 0xd8, 0xb8, 0x38, 0x89, 0x49, 0x0e, 0x82, 0x0f, 0x1e, 0x40, 0xef, 0xda, 0xa1, 0x2e, 0x0e, 0x9c, 0x90, 0x32, + 0xd8, 0xcf, 0x4e, 0xa2, 0x0f, 0xe3, 0x74, 0xd8, 0xfe, 0xd4, 0xe9, 0xee, 0xef, 0xc4, 0xfe, 0x38, 0x50, 0x5d, 0x6c, + 0x11, 0x1d, 0xd3, 0xec, 0xfd, 0x21, 0x49, 0xe6, 0x6f, 0xff, 0x4f, 0x73, 0x4f, 0xbb, 0xdd, 0xb6, 0x71, 0xe5, 0xff, + 0x3e, 0x05, 0x0c, 0xbb, 0x0e, 0x60, 0x03, 0x10, 0x40, 0x8a, 0x92, 0x4c, 0x8a, 0x52, 0x13, 0xdb, 0x39, 0x51, 0xaa, + 0xd4, 0x39, 0x8e, 0xea, 0x6d, 0xa3, 0xe8, 0x98, 0x43, 0x70, 0x48, 0xa2, 0x02, 0x01, 0x1e, 0x00, 0x94, 0xa8, 0xd0, + 0xe8, 0x53, 0xec, 0xff, 0xed, 0x73, 0xec, 0xfe, 0xeb, 0x13, 0xed, 0x23, 0xec, 0xb9, 0x77, 0x3e, 0x30, 0xf8, 0x22, + 0xa9, 0xc4, 0x69, 0xf7, 0xa4, 0xaa, 0x89, 0xc1, 0xcc, 0x60, 0xe6, 0xce, 0xcc, 0x9d, 0xfb, 0x7d, 0x03, 0xeb, 0x3f, + 0x62, 0x6b, 0x46, 0xac, 0x05, 0xb1, 0x6e, 0xd3, 0x9b, 0xbc, 0x71, 0xcd, 0x64, 0xba, 0x1b, 0x4c, 0x89, 0x68, 0x18, + 0x10, 0x37, 0x83, 0x73, 0x33, 0x9c, 0xc6, 0x0f, 0xc4, 0x05, 0x77, 0x45, 0x92, 0x19, 0x15, 0x89, 0x66, 0xc4, 0xdb, + 0x8c, 0x43, 0xc6, 0x2c, 0xc1, 0xcb, 0x30, 0xe8, 0xe3, 0xba, 0xa1, 0x6a, 0x37, 0x02, 0xc2, 0x18, 0x43, 0xf3, 0x09, + 0xb7, 0xac, 0x08, 0x1c, 0x3f, 0x4b, 0xc2, 0x3f, 0xd2, 0x07, 0x20, 0x5e, 0xd3, 0x2c, 0x5e, 0x02, 0xcb, 0x42, 0x66, + 0x5c, 0x04, 0x65, 0x19, 0xe9, 0x7e, 0x1f, 0x84, 0x64, 0x59, 0xb8, 0xe9, 0x81, 0xee, 0x75, 0xb2, 0x78, 0x36, 0x0b, + 0xa9, 0xa1, 0x8b, 0x1c, 0x2a, 0xba, 0x25, 0x3f, 0x73, 0xfe, 0xc4, 0x15, 0x81, 0x4b, 0xcd, 0xbc, 0xed, 0xf0, 0x0a, + 0xe8, 0x51, 0x19, 0xd9, 0x8f, 0x11, 0xf0, 0x28, 0xa2, 0xbe, 0x43, 0x2d, 0x0f, 0x5f, 0xe3, 0x02, 0x39, 0xd8, 0x93, + 0x78, 0x35, 0x0e, 0xa9, 0x8d, 0x07, 0x0a, 0x3e, 0xb9, 0x19, 0xaf, 0xc6, 0x63, 0x48, 0x56, 0xf3, 0xc4, 0xb5, 0x20, + 0xfc, 0x4e, 0x9c, 0x22, 0x5b, 0x9c, 0x9b, 0x03, 0x80, 0xa2, 0x93, 0x95, 0x87, 0xcf, 0xb2, 0x77, 0x82, 0xc4, 0x8b, + 0x7d, 0x20, 0x03, 0x16, 0xb8, 0x01, 0x2f, 0x0c, 0xf5, 0x1f, 0x60, 0x7f, 0xa7, 0xfa, 0xa0, 0x09, 0xb9, 0x0c, 0xaf, + 0xf5, 0x1f, 0x70, 0xb1, 0x30, 0x89, 0xf3, 0x6b, 0x76, 0x3e, 0x74, 0x4b, 0x67, 0xba, 0xff, 0x15, 0xa6, 0x73, 0x00, + 0xd9, 0xf7, 0x9b, 0x80, 0xcc, 0xa2, 0x38, 0xcd, 0x02, 0x5f, 0xbf, 0x19, 0x5c, 0x04, 0xc6, 0xf5, 0x22, 0x33, 0xcc, + 0x1b, 0xcb, 0xcf, 0xd4, 0x4c, 0x30, 0x02, 0x25, 0x63, 0x22, 0x98, 0xb6, 0x4a, 0xea, 0x19, 0xdd, 0x5a, 0x51, 0x20, + 0x7f, 0xac, 0xe4, 0x67, 0x43, 0xa8, 0x57, 0x49, 0x2b, 0x83, 0xf9, 0xb1, 0x74, 0x6c, 0x69, 0x0e, 0x18, 0xc3, 0xf6, + 0x7a, 0xb5, 0x41, 0x62, 0x21, 0x2b, 0xee, 0x63, 0x0c, 0x85, 0x2c, 0xfc, 0x87, 0xd8, 0xf3, 0x13, 0xd5, 0xf6, 0xb5, + 0x74, 0xb3, 0x8f, 0xbe, 0x2c, 0x53, 0x1e, 0x40, 0x21, 0x80, 0xe1, 0x49, 0x14, 0x67, 0x1a, 0xc4, 0xf7, 0x81, 0x2f, + 0x8e, 0xaa, 0xb6, 0x72, 0xbc, 0x57, 0xc3, 0xcc, 0x39, 0xba, 0xf9, 0x0a, 0xaf, 0x57, 0x83, 0x47, 0x79, 0x2b, 0x05, + 0xf2, 0x60, 0x3c, 0x53, 0x0a, 0x0b, 0x98, 0xc5, 0x97, 0xf1, 0x7d, 0x55, 0x1d, 0xf4, 0x7a, 0xb4, 0xfb, 0x76, 0x37, + 0x04, 0x05, 0x2f, 0x92, 0x1b, 0x1a, 0x3c, 0x3f, 0xab, 0x20, 0xa5, 0x2a, 0xa7, 0x0a, 0xed, 0x5f, 0x04, 0x95, 0x94, + 0x81, 0xb9, 0x1c, 0xde, 0x36, 0x80, 0xf4, 0x38, 0x21, 0x30, 0xca, 0x91, 0x6c, 0x95, 0xc9, 0x9f, 0x84, 0xc3, 0x4b, + 0x79, 0xdc, 0xe9, 0x10, 0xa5, 0xb2, 0xf3, 0x60, 0x36, 0xd7, 0xcf, 0x33, 0xbe, 0x23, 0x55, 0x7a, 0xf7, 0x23, 0xbc, + 0xea, 0x37, 0xbd, 0x81, 0x84, 0x54, 0x0d, 0xf5, 0xc3, 0xf8, 0x1e, 0xbc, 0xd9, 0x8b, 0x5e, 0x39, 0x35, 0xdd, 0xda, + 0xb9, 0xf9, 0x52, 0xd6, 0x80, 0xac, 0xe2, 0x66, 0x7f, 0x4b, 0x83, 0xf6, 0x6f, 0x56, 0x7b, 0xb1, 0xe2, 0x47, 0x8d, + 0xc1, 0xfe, 0x2c, 0x63, 0xa8, 0xf4, 0x32, 0x88, 0x86, 0xd1, 0x99, 0x2c, 0x5a, 0x90, 0x35, 0x36, 0x30, 0xcf, 0xeb, + 0x45, 0xfd, 0xc8, 0x8a, 0x87, 0xf1, 0x9e, 0x75, 0x63, 0x6e, 0x78, 0x4c, 0xcf, 0x47, 0x29, 0xcd, 0xce, 0x1b, 0xc6, + 0x02, 0x1b, 0x61, 0xf8, 0x6c, 0x13, 0xe5, 0xa3, 0x7e, 0x4b, 0x15, 0xf6, 0xd6, 0x22, 0xbb, 0x3b, 0x89, 0xb7, 0x76, + 0x12, 0xe7, 0xa3, 0xc7, 0x6c, 0x73, 0x9f, 0xef, 0xf2, 0x70, 0xe0, 0x37, 0x61, 0xfa, 0xb0, 0x71, 0xcf, 0x43, 0x30, + 0xda, 0xd2, 0x6e, 0x4f, 0x70, 0xb7, 0xff, 0xef, 0x7f, 0xfd, 0xe7, 0x7f, 0x17, 0x64, 0xef, 0x38, 0x39, 0x3b, 0xc5, + 0x8c, 0x64, 0x40, 0xc5, 0xe5, 0xa7, 0x07, 0xec, 0x37, 0x16, 0xff, 0x8b, 0x46, 0x45, 0xc4, 0xa8, 0xfe, 0x47, 0x3d, + 0x83, 0x22, 0x8b, 0xbb, 0xc8, 0xa1, 0xae, 0x90, 0xe0, 0x40, 0x43, 0x45, 0xcb, 0x55, 0x86, 0x51, 0xbf, 0x61, 0x1c, + 0x34, 0xd7, 0x35, 0x8c, 0x22, 0x0c, 0xb4, 0x58, 0xc1, 0x0c, 0xe6, 0xba, 0x16, 0x4c, 0xea, 0x65, 0x9c, 0xc9, 0x05, + 0x62, 0x04, 0xa9, 0x38, 0x94, 0x99, 0xc3, 0x63, 0xc2, 0xa7, 0xe3, 0x5b, 0x45, 0xca, 0x0c, 0xc3, 0x47, 0xdd, 0x72, + 0xc3, 0xfd, 0xec, 0xb3, 0x7e, 0x06, 0xfb, 0x4e, 0x73, 0x04, 0xf0, 0x3d, 0x87, 0xed, 0x33, 0x7c, 0xb6, 0x21, 0xc0, + 0xaf, 0xe5, 0x3a, 0x4c, 0xb4, 0xf0, 0x19, 0x2c, 0xa6, 0x07, 0x88, 0x9d, 0x95, 0x6b, 0x68, 0x34, 0x34, 0xe4, 0xa6, + 0x41, 0xcb, 0x24, 0x58, 0x90, 0xe4, 0x81, 0x59, 0x12, 0x59, 0xaa, 0xb9, 0x91, 0xa9, 0x6b, 0x8c, 0x7a, 0x63, 0xf3, + 0x65, 0x84, 0x9c, 0xae, 0xfd, 0x41, 0x96, 0x51, 0x3e, 0x39, 0x81, 0xbe, 0x74, 0xf8, 0xd6, 0x47, 0xfd, 0x25, 0x75, + 0x26, 0x34, 0x23, 0x41, 0xc8, 0x9a, 0x0c, 0x8c, 0xa8, 0x65, 0x36, 0x51, 0x79, 0x36, 0x69, 0x19, 0x65, 0xe3, 0x64, + 0x18, 0x05, 0xc7, 0xc6, 0x8d, 0x33, 0x43, 0x14, 0xda, 0xbc, 0x80, 0xec, 0x9d, 0xb2, 0x97, 0x00, 0xf8, 0x49, 0x7d, + 0x17, 0xe5, 0xed, 0x4b, 0xd4, 0x50, 0xfb, 0xb7, 0x59, 0x36, 0x0a, 0xcb, 0x96, 0xc2, 0xb2, 0xd1, 0xc8, 0x8f, 0x27, + 0xf4, 0xcf, 0xef, 0x2f, 0x64, 0xa6, 0x3f, 0x10, 0x5a, 0x8f, 0xf8, 0x25, 0x12, 0x21, 0x37, 0x91, 0x20, 0x27, 0xc1, + 0x72, 0xf2, 0x69, 0x72, 0xab, 0x25, 0xb9, 0xae, 0x9d, 0xb3, 0x49, 0xd3, 0x09, 0x9b, 0xc9, 0x30, 0xc6, 0x56, 0x49, + 0x7e, 0x7a, 0xc0, 0x6a, 0x33, 0x2a, 0x97, 0x55, 0x02, 0xf8, 0x25, 0x30, 0xeb, 0x02, 0x7c, 0x90, 0x94, 0x78, 0xe8, + 0x15, 0xe2, 0x05, 0x67, 0x81, 0xaa, 0x41, 0xef, 0xbc, 0xcc, 0xb8, 0x60, 0x2b, 0xbd, 0x38, 0xd4, 0x31, 0x04, 0x26, + 0x12, 0xe7, 0x5a, 0xab, 0x9c, 0x9c, 0xa2, 0x13, 0x21, 0xf2, 0xe9, 0xf3, 0x0e, 0x1e, 0x75, 0xa4, 0x00, 0x6b, 0x43, + 0x29, 0xc9, 0x75, 0x6d, 0xc1, 0x19, 0x25, 0x1e, 0x01, 0x0d, 0xc2, 0xa3, 0xb8, 0x70, 0xcf, 0xea, 0xda, 0x82, 0xac, + 0x71, 0xe6, 0xe2, 0x0d, 0x59, 0x1b, 0x1e, 0x7f, 0x55, 0x9c, 0xc9, 0xa8, 0xbc, 0xe0, 0x02, 0xc5, 0x80, 0xef, 0x93, + 0x14, 0xd0, 0xcd, 0xd1, 0xa6, 0xa4, 0x61, 0x71, 0xe7, 0x62, 0x71, 0x27, 0x2d, 0x8b, 0x3b, 0xd9, 0xb2, 0xb8, 0x21, + 0x5f, 0x48, 0x4d, 0x82, 0x2e, 0x41, 0x7f, 0xd6, 0x02, 0x29, 0x32, 0x06, 0xa3, 0xcf, 0x0f, 0x28, 0xc2, 0xc9, 0x4e, + 0x43, 0xb0, 0xe7, 0x6c, 0x81, 0x55, 0x13, 0x5c, 0x14, 0x40, 0xd4, 0x27, 0x2e, 0x8f, 0xab, 0x44, 0xad, 0xd6, 0x1c, + 0xb6, 0xaa, 0x5f, 0xa5, 0x79, 0x43, 0xd6, 0xd0, 0x32, 0xe6, 0x2d, 0x33, 0x9d, 0x6f, 0x99, 0xa9, 0x5f, 0x3a, 0xf3, + 0x7c, 0xda, 0xec, 0xf4, 0xaa, 0x93, 0x62, 0xa4, 0xd0, 0x3a, 0xc3, 0x2d, 0x53, 0xde, 0x87, 0xed, 0xb8, 0x58, 0xd9, + 0x51, 0x4b, 0x92, 0xa6, 0xf7, 0x71, 0x02, 0x4a, 0x62, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x11, 0x44, 0x3c, 0xfe, 0x54, + 0xeb, 0x66, 0x2a, 0xde, 0xab, 0x5b, 0xaa, 0xd3, 0xeb, 0xb1, 0x1a, 0x4b, 0x92, 0x65, 0x34, 0x41, 0xa0, 0x13, 0x48, + 0x54, 0xf0, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0xd0, 0x2c, 0xae, 0x03, 0x44, 0xed, 0x4b, 0xe0, 0x83, 0x12, 0x41, + 0x34, 0x2b, 0xb1, 0x2c, 0x13, 0x09, 0x78, 0x4e, 0xdf, 0x24, 0x8a, 0xb7, 0xa5, 0x77, 0x64, 0x3a, 0x4b, 0x32, 0xf9, + 0x01, 0x6c, 0x11, 0x8c, 0x8e, 0x05, 0x7e, 0x05, 0x6a, 0xe4, 0xca, 0x84, 0x31, 0x66, 0x7e, 0x81, 0x24, 0x11, 0x4b, + 0x72, 0xab, 0x4d, 0x70, 0xf8, 0x26, 0xf6, 0xf4, 0x66, 0xd3, 0xc9, 0x0f, 0x66, 0x81, 0x59, 0xc3, 0x9a, 0x80, 0xda, + 0xc2, 0xe1, 0x99, 0x94, 0xc0, 0x84, 0x96, 0x77, 0x64, 0x82, 0xb2, 0xea, 0x1a, 0x52, 0x30, 0xbb, 0x42, 0xbc, 0x35, + 0x4a, 0xe0, 0x76, 0xbb, 0x76, 0x6f, 0xf2, 0xe7, 0x33, 0xfc, 0xe5, 0xdd, 0xe4, 0xcf, 0xc7, 0xf8, 0xab, 0x73, 0x83, + 0xc9, 0x36, 0x1b, 0xc4, 0x7a, 0xca, 0x9c, 0xf5, 0xb3, 0xd2, 0x7e, 0x62, 0x26, 0xb3, 0x8f, 0xd8, 0x36, 0x7c, 0x81, + 0x9f, 0x3e, 0xdb, 0x44, 0xe0, 0x24, 0xae, 0xce, 0x21, 0x75, 0x12, 0x33, 0x6f, 0x2c, 0x9f, 0xb5, 0x94, 0x8f, 0xcd, + 0x7f, 0x31, 0x81, 0x80, 0xbb, 0x24, 0x2e, 0xee, 0x94, 0xb2, 0x50, 0xf2, 0xe3, 0x38, 0x88, 0x48, 0xf2, 0xf0, 0x91, + 0xc9, 0x14, 0x0c, 0xc1, 0x67, 0x4b, 0x61, 0x2b, 0x63, 0x05, 0xcb, 0x1a, 0xfa, 0x4c, 0xd1, 0x49, 0x3d, 0x70, 0x0a, + 0x61, 0xf8, 0x97, 0x44, 0xa1, 0x3d, 0x4b, 0xe2, 0x28, 0xbe, 0x20, 0xa5, 0x0f, 0x7d, 0x7c, 0xb6, 0x31, 0x68, 0xbd, + 0x9b, 0x9a, 0xb8, 0xa2, 0x44, 0x10, 0xc0, 0xf2, 0xa0, 0x68, 0x6b, 0x31, 0x09, 0xfa, 0xa8, 0x82, 0x1f, 0xc7, 0x6b, + 0xfb, 0xd9, 0x26, 0x3b, 0xd7, 0x17, 0x24, 0xb9, 0xa5, 0x13, 0xdb, 0x0f, 0x12, 0x3f, 0xa4, 0x7a, 0x5f, 0x1f, 0x87, + 0x24, 0xba, 0xe5, 0x8f, 0x76, 0xbc, 0xca, 0xd0, 0xa8, 0x66, 0xa7, 0x24, 0x4c, 0xc0, 0x84, 0x09, 0xf0, 0x91, 0x41, + 0x6b, 0x80, 0x82, 0xf6, 0x5a, 0x8a, 0xbf, 0x0b, 0x82, 0xb2, 0xa8, 0x65, 0x81, 0x4d, 0x38, 0xd8, 0xf9, 0x80, 0x93, + 0xbd, 0xa5, 0xe3, 0x7a, 0xe9, 0x96, 0x3a, 0x55, 0xa6, 0xf7, 0x90, 0x59, 0x62, 0x3f, 0x62, 0x0f, 0xbf, 0xfc, 0x73, + 0x50, 0xf2, 0x98, 0xcf, 0x71, 0xe2, 0xb0, 0xfd, 0x83, 0x6a, 0x63, 0x92, 0xa6, 0xab, 0x05, 0x9d, 0x30, 0x7b, 0x82, + 0xf3, 0x62, 0x28, 0x65, 0x46, 0x5c, 0x1d, 0xce, 0x4f, 0xab, 0xce, 0xf1, 0xe1, 0x6b, 0xb0, 0x73, 0x02, 0x62, 0x30, + 0x9e, 0x4e, 0xf5, 0x42, 0xbc, 0xb6, 0xa3, 0x99, 0x77, 0xf8, 0xd3, 0xea, 0xeb, 0xb7, 0xee, 0xd7, 0xb2, 0x71, 0xa4, + 0x9b, 0xf9, 0x48, 0x18, 0x6d, 0x70, 0x9a, 0x56, 0x19, 0xaf, 0x98, 0xd1, 0x94, 0x44, 0xed, 0xd3, 0xb9, 0x2e, 0xed, + 0xb2, 0x25, 0xa5, 0x13, 0xb0, 0xe7, 0xb7, 0x6a, 0xa5, 0x1f, 0x43, 0x7a, 0x47, 0xa5, 0x41, 0x48, 0xfd, 0x63, 0x0d, + 0x2d, 0x30, 0x62, 0x25, 0x37, 0x34, 0xe1, 0x84, 0x95, 0x32, 0xa5, 0x11, 0xce, 0x81, 0xcf, 0x5c, 0xdd, 0xe5, 0x95, + 0x5d, 0x3d, 0xb2, 0x74, 0x65, 0x00, 0xad, 0x23, 0x3b, 0x6f, 0x29, 0xef, 0x63, 0xba, 0xfa, 0xe6, 0xb1, 0x59, 0x9e, + 0xd9, 0x87, 0x08, 0xff, 0x1c, 0x4e, 0x21, 0x6c, 0x7e, 0x43, 0x4a, 0x22, 0x07, 0x6d, 0x10, 0x6b, 0x92, 0x5a, 0xeb, + 0x4c, 0xf0, 0x29, 0x6c, 0xa4, 0xd1, 0x59, 0x40, 0x08, 0x86, 0x1b, 0xd7, 0x46, 0x2b, 0xcf, 0x7c, 0x8c, 0x69, 0xa0, + 0x23, 0x9a, 0xa6, 0xad, 0x00, 0x93, 0x8b, 0x6e, 0xe9, 0x45, 0xed, 0x32, 0x3c, 0x8a, 0x72, 0xcb, 0xb5, 0xe0, 0x56, + 0xc6, 0x09, 0x56, 0xbf, 0x85, 0x18, 0xfe, 0xe3, 0x82, 0x5b, 0xb9, 0x25, 0xb3, 0xb1, 0xce, 0x2d, 0x90, 0xda, 0xde, + 0xdf, 0xeb, 0x7c, 0x50, 0xa5, 0x9b, 0xb2, 0x71, 0x68, 0x46, 0x09, 0xfb, 0xd5, 0xc4, 0xb4, 0xd8, 0x81, 0x18, 0x53, + 0x05, 0xc5, 0xd1, 0xe9, 0x94, 0xfa, 0x59, 0x6a, 0x0a, 0x59, 0xab, 0x8c, 0x39, 0x0d, 0xbe, 0x86, 0x4f, 0x86, 0xfa, + 0x9f, 0x20, 0xf2, 0x86, 0x08, 0xcd, 0xc6, 0x07, 0x24, 0xf8, 0x9d, 0x66, 0x30, 0xb1, 0x1e, 0xcb, 0x20, 0xe2, 0x5f, + 0xf9, 0xf4, 0x49, 0x98, 0x48, 0x94, 0xca, 0x71, 0x68, 0xfc, 0x0a, 0x28, 0xf6, 0x45, 0x2c, 0x6d, 0xe1, 0xb6, 0x23, + 0xa0, 0x6d, 0xc7, 0x77, 0xe3, 0x7d, 0xdd, 0xf3, 0xdc, 0x5c, 0xb7, 0xc0, 0xe3, 0xf3, 0x76, 0xdf, 0x43, 0x8f, 0xad, + 0xba, 0xd0, 0x6a, 0x15, 0x3d, 0xa6, 0x5d, 0xc7, 0x7b, 0xe5, 0xe9, 0x16, 0x33, 0xb4, 0x55, 0x70, 0x9b, 0x1f, 0xdf, + 0xd1, 0xe4, 0x57, 0x4f, 0xa5, 0xdc, 0xf9, 0x7e, 0xe3, 0x39, 0xf2, 0x5c, 0x40, 0xc2, 0x59, 0xbc, 0x7c, 0xc4, 0x14, + 0xba, 0xba, 0xa5, 0xfb, 0x61, 0x9c, 0x52, 0x75, 0x0e, 0x4c, 0x5e, 0xf1, 0x2b, 0x27, 0xf1, 0xfd, 0xfb, 0xb7, 0x3f, + 0xfc, 0xa0, 0x5b, 0x98, 0x3f, 0x38, 0x55, 0x7b, 0xe7, 0x1b, 0x6a, 0x07, 0xf6, 0x6f, 0xdc, 0x77, 0xec, 0x86, 0x61, + 0x7c, 0x65, 0x79, 0xcf, 0xb1, 0xb2, 0xda, 0x96, 0xe3, 0x37, 0x0f, 0xff, 0x32, 0x63, 0x06, 0xf7, 0x9a, 0x57, 0x03, + 0x6e, 0xd8, 0x7e, 0xbd, 0x95, 0x4a, 0x16, 0x41, 0xf4, 0xb1, 0xa1, 0x94, 0xac, 0x1b, 0x4a, 0x51, 0x36, 0x58, 0xc5, + 0x1f, 0xab, 0x78, 0xa1, 0xdc, 0xce, 0x90, 0xfe, 0x7d, 0x17, 0xb8, 0x14, 0x96, 0xe6, 0x57, 0x0c, 0x9a, 0xe7, 0x7f, + 0xa8, 0x8e, 0xba, 0xa1, 0x98, 0xf3, 0x21, 0x12, 0xb6, 0x5c, 0x97, 0xa3, 0xaa, 0xc9, 0xcb, 0x94, 0x9b, 0xda, 0xb8, + 0x59, 0x60, 0xfa, 0xa4, 0x70, 0xbe, 0xd9, 0x51, 0x19, 0x84, 0xb4, 0xb2, 0x76, 0x41, 0x13, 0x6c, 0xed, 0x3d, 0xff, + 0xe7, 0x3f, 0x1c, 0xe7, 0x9f, 0xff, 0xd8, 0x59, 0x15, 0xfa, 0xce, 0x81, 0x1d, 0xde, 0x55, 0x33, 0x1f, 0xa1, 0xd0, + 0x29, 0x1b, 0xbe, 0x1e, 0x8d, 0x06, 0x46, 0x09, 0x64, 0xe0, 0x33, 0x72, 0x5e, 0x2b, 0xe1, 0x78, 0xb5, 0xef, 0x9a, + 0x18, 0xcc, 0x01, 0x1a, 0xca, 0xeb, 0xab, 0x75, 0xb3, 0x33, 0xa7, 0x84, 0x5a, 0x5f, 0xb5, 0x9d, 0x0e, 0xa5, 0x98, + 0xb8, 0x2e, 0x1f, 0x99, 0x3c, 0xc7, 0x00, 0x8c, 0x8b, 0xab, 0x0f, 0x4a, 0x2b, 0x07, 0x7e, 0x36, 0x59, 0x79, 0x7c, + 0xbc, 0xac, 0x32, 0x42, 0xba, 0xd7, 0x08, 0x59, 0xdb, 0xf2, 0x18, 0x79, 0x7f, 0xb5, 0x51, 0xb2, 0x72, 0x31, 0x4e, + 0x0b, 0x45, 0x66, 0x3c, 0xca, 0x08, 0x67, 0x9a, 0xb8, 0x4a, 0xb0, 0xa4, 0xf6, 0xad, 0xa8, 0x2e, 0x94, 0x21, 0xec, + 0x5e, 0xf6, 0x73, 0x3d, 0x8c, 0xef, 0xd1, 0x59, 0x4f, 0xd5, 0x27, 0x73, 0x61, 0xc8, 0x69, 0x9a, 0x25, 0x71, 0x34, + 0x3b, 0xab, 0x5c, 0xde, 0x75, 0x3b, 0x1f, 0x90, 0x60, 0xb1, 0xaa, 0x65, 0xb1, 0x89, 0x3a, 0xca, 0xed, 0x5b, 0xea, + 0x7c, 0xc7, 0x4c, 0x98, 0x6a, 0x42, 0xb9, 0x1c, 0x45, 0xd7, 0x0d, 0x6a, 0x70, 0x95, 0x94, 0x2b, 0xbf, 0x96, 0x8f, + 0x07, 0x1c, 0xae, 0x67, 0xa3, 0x1c, 0x93, 0x1d, 0xbd, 0x6b, 0x33, 0x10, 0xfd, 0x7e, 0xb7, 0x81, 0xe8, 0xd5, 0x5e, + 0x06, 0xa2, 0xdf, 0x7f, 0x76, 0x03, 0xd1, 0x77, 0xaa, 0x81, 0x28, 0x6c, 0xe9, 0xb7, 0x74, 0x2f, 0xab, 0x4d, 0x61, + 0x0d, 0x15, 0xdf, 0xa7, 0x43, 0x8f, 0x53, 0xa6, 0xa9, 0x3f, 0xa7, 0xc0, 0x6d, 0xf3, 0x6d, 0x1a, 0xc6, 0x33, 0xb0, + 0xe0, 0xfc, 0xed, 0x6d, 0x2d, 0xc3, 0x78, 0xa6, 0x5a, 0x5a, 0xa6, 0x3c, 0xdc, 0x73, 0x11, 0xc2, 0x8d, 0x59, 0x37, + 0xba, 0x96, 0x38, 0x7b, 0xf6, 0xa1, 0xa9, 0xa4, 0xb4, 0x97, 0xa6, 0xab, 0x1d, 0x61, 0xff, 0xd8, 0x47, 0xd3, 0x49, + 0xd9, 0xb0, 0xf3, 0x32, 0x96, 0x49, 0x7b, 0x8a, 0x1e, 0xa4, 0x8b, 0x00, 0x0b, 0x12, 0xb3, 0xd1, 0x7f, 0x5a, 0x7b, + 0x5f, 0x5d, 0x7b, 0x83, 0xae, 0x07, 0x91, 0x19, 0x80, 0x57, 0xc3, 0x02, 0x77, 0xd0, 0xed, 0x42, 0xc1, 0xbd, 0x52, + 0xd0, 0x81, 0x82, 0x40, 0x29, 0xe8, 0x41, 0x81, 0xaf, 0x14, 0x1c, 0x41, 0xc1, 0x44, 0x29, 0x38, 0x86, 0x82, 0x3b, + 0x3d, 0xbf, 0x2e, 0x12, 0x39, 0x1d, 0x9b, 0x37, 0x16, 0xe3, 0x0d, 0x44, 0xd9, 0xb1, 0xe5, 0x81, 0x19, 0x23, 0x99, + 0xf5, 0x63, 0x8b, 0xc9, 0xe9, 0xfa, 0x89, 0x75, 0x3f, 0xa7, 0x2c, 0x4a, 0xfc, 0x1b, 0xbc, 0x3a, 0x9c, 0x2c, 0x06, + 0xa7, 0x09, 0x11, 0x7d, 0x45, 0xc0, 0x41, 0xd3, 0x4d, 0x10, 0xbd, 0x0c, 0xe4, 0xca, 0x89, 0x08, 0x36, 0xca, 0x5a, + 0x16, 0xef, 0xd8, 0xe7, 0x6c, 0xb9, 0x05, 0x0a, 0x4b, 0x2e, 0x43, 0x95, 0xef, 0x7d, 0x0e, 0x7b, 0x9e, 0x37, 0x74, + 0xbc, 0x9a, 0x69, 0x97, 0xf1, 0x6c, 0xa7, 0x69, 0x8e, 0xfa, 0x0a, 0x46, 0xa9, 0x33, 0x0d, 0x88, 0x2d, 0xb6, 0x25, + 0xff, 0x16, 0x7b, 0xcc, 0xcb, 0xf5, 0x33, 0x18, 0x9b, 0x96, 0x31, 0xc3, 0x30, 0xf8, 0x0e, 0xc0, 0x48, 0x39, 0xf5, + 0x97, 0x00, 0x67, 0xe5, 0xf9, 0x8a, 0x28, 0xe3, 0x39, 0xfb, 0x8e, 0xa6, 0x29, 0x99, 0x89, 0xfa, 0xf5, 0x71, 0x82, + 0x31, 0x9c, 0x64, 0xa3, 0x10, 0x80, 0x20, 0x13, 0x0b, 0x6a, 0x36, 0x4f, 0x49, 0x7c, 0xaf, 0x81, 0x55, 0x1d, 0x6c, + 0xa8, 0xc2, 0xfe, 0x27, 0x70, 0x60, 0x09, 0xcb, 0x38, 0x08, 0x0e, 0xff, 0x1d, 0x0d, 0xab, 0x85, 0x19, 0x99, 0x55, + 0x8b, 0xd8, 0x3e, 0xc8, 0xd5, 0xb1, 0x49, 0x93, 0x98, 0x52, 0xe1, 0xaf, 0xb1, 0xcb, 0x08, 0xe3, 0xd9, 0x6f, 0x6a, + 0x94, 0xb1, 0xc5, 0x30, 0xe7, 0x36, 0xb5, 0x82, 0x6c, 0xe4, 0x20, 0x8c, 0x35, 0x07, 0x40, 0xd8, 0x8f, 0xb2, 0xb9, + 0x8d, 0x7e, 0xa5, 0x46, 0x27, 0x32, 0x2d, 0x07, 0xd7, 0x76, 0x53, 0xf5, 0xa6, 0xef, 0x27, 0xb3, 0x31, 0x31, 0xbc, + 0xce, 0xb1, 0x25, 0xfe, 0x1c, 0xb7, 0x67, 0xe6, 0xd8, 0x83, 0x36, 0x09, 0xee, 0x36, 0xd3, 0x38, 0xca, 0xec, 0x29, + 0x59, 0x04, 0xe1, 0x43, 0x7f, 0x11, 0x47, 0x71, 0xba, 0x24, 0x3e, 0x1d, 0x14, 0x7c, 0xf1, 0x00, 0xe3, 0xb4, 0x70, + 0x57, 0x61, 0xcf, 0xe9, 0x24, 0x74, 0xc1, 0x5a, 0xcb, 0x30, 0x2c, 0xd3, 0x90, 0xae, 0x73, 0xfe, 0xf9, 0x52, 0x65, + 0x56, 0x15, 0xb7, 0x1c, 0x6b, 0x01, 0x84, 0x25, 0x8f, 0xf1, 0x02, 0x91, 0xcd, 0x06, 0x4b, 0x32, 0xc1, 0xb0, 0xa4, + 0x4e, 0xa7, 0x97, 0xd0, 0x85, 0xe6, 0xf4, 0x5a, 0x3b, 0x4f, 0xe2, 0xfb, 0x33, 0x18, 0x2d, 0x36, 0xb6, 0x53, 0x1a, + 0x4e, 0xf1, 0x8d, 0x8d, 0x6e, 0x65, 0xa2, 0x1f, 0x1b, 0xf9, 0x69, 0xe8, 0x8d, 0x2e, 0x06, 0xf0, 0xba, 0xdf, 0xd1, + 0xdc, 0xc1, 0x22, 0x88, 0x6c, 0x36, 0x9d, 0x63, 0x77, 0xa9, 0xf4, 0xa5, 0xc2, 0xcf, 0xdc, 0x60, 0x75, 0x4f, 0x73, + 0x07, 0xc0, 0x73, 0x4d, 0xc3, 0xf8, 0xbe, 0x3f, 0x0f, 0x26, 0x13, 0x1a, 0x0d, 0x70, 0xcc, 0xb2, 0x90, 0x86, 0x61, + 0xb0, 0x4c, 0x83, 0x74, 0xb0, 0x20, 0x6b, 0xde, 0xeb, 0x61, 0x5b, 0xaf, 0x5d, 0xde, 0x6b, 0x77, 0xef, 0x5e, 0x95, + 0x6e, 0xc0, 0x85, 0x8d, 0xf5, 0xc3, 0x87, 0xd6, 0xd3, 0xdc, 0xca, 0x3c, 0xf7, 0xee, 0x75, 0x99, 0xd0, 0xcd, 0x82, + 0x24, 0xb3, 0x20, 0xea, 0xbb, 0xb9, 0x73, 0xb7, 0x61, 0x1b, 0xe3, 0xe9, 0xc9, 0xc9, 0x49, 0xee, 0x4c, 0xc4, 0x93, + 0x3b, 0x99, 0xe4, 0x8e, 0x2f, 0x9e, 0xa6, 0x53, 0xd7, 0x9d, 0x4e, 0x73, 0x27, 0x10, 0x05, 0xdd, 0x8e, 0x3f, 0xe9, + 0x76, 0x72, 0xe7, 0x5e, 0xa9, 0x91, 0x3b, 0x94, 0x3f, 0x25, 0x74, 0x32, 0xc0, 0x8d, 0xc4, 0xec, 0xbc, 0xfb, 0xc7, + 0xae, 0x9b, 0x23, 0x06, 0xb8, 0x2e, 0xe1, 0x26, 0x14, 0xd9, 0xdc, 0x6c, 0xf6, 0xae, 0xa9, 0x15, 0x9f, 0xf3, 0xfd, + 0xc6, 0x7a, 0x13, 0x92, 0xdc, 0xde, 0x68, 0xca, 0x2c, 0x08, 0x61, 0xd5, 0x36, 0x02, 0x0c, 0xf6, 0xba, 0x0f, 0xf1, + 0xfa, 0x06, 0xe3, 0x38, 0x81, 0x33, 0x9b, 0x90, 0x49, 0xb0, 0x4a, 0xfb, 0x5e, 0x67, 0xb9, 0x16, 0x45, 0x7c, 0xaf, + 0x17, 0x05, 0x78, 0xf6, 0xfa, 0x69, 0x1c, 0x06, 0x13, 0x51, 0xd4, 0x76, 0x96, 0xbc, 0x8e, 0x39, 0xc0, 0x68, 0x15, + 0x01, 0xc6, 0x5c, 0x21, 0x61, 0xa8, 0x39, 0xdd, 0x54, 0xa3, 0x24, 0x45, 0x49, 0xad, 0xe6, 0xa6, 0x0c, 0x2e, 0x18, + 0x99, 0xc2, 0x3b, 0x5c, 0xae, 0xe5, 0x9e, 0xf7, 0x8e, 0x96, 0xeb, 0xfc, 0x0f, 0x0b, 0x3a, 0x09, 0x88, 0x66, 0x14, + 0xbb, 0xc9, 0x73, 0x41, 0x9a, 0x6b, 0x6e, 0x5a, 0xb6, 0xa9, 0x38, 0x16, 0x10, 0xd7, 0xf4, 0x49, 0xb0, 0x58, 0xc6, + 0x49, 0x46, 0xa2, 0x2c, 0xcf, 0x47, 0x37, 0x79, 0x3e, 0xb8, 0x0a, 0x8c, 0xeb, 0xbf, 0x1a, 0xec, 0x9e, 0x66, 0xda, + 0x8f, 0xdc, 0xbc, 0xb1, 0xde, 0x52, 0xd5, 0x52, 0x0a, 0xae, 0x31, 0xb4, 0x92, 0x52, 0x2b, 0xb3, 0x5b, 0xb2, 0x5e, + 0x99, 0x01, 0x59, 0x56, 0x67, 0x96, 0x57, 0xe5, 0x2a, 0x78, 0x03, 0x41, 0x85, 0xb7, 0x74, 0x78, 0xa5, 0x58, 0x5d, + 0x01, 0xb1, 0x82, 0x95, 0x99, 0x53, 0xd1, 0xb3, 0x36, 0x9a, 0xf1, 0xcb, 0xdd, 0x34, 0xe3, 0x8f, 0xd9, 0x3e, 0x34, + 0xe3, 0x97, 0x9f, 0x9d, 0x66, 0x7c, 0x56, 0x77, 0x2a, 0xba, 0x88, 0x87, 0xba, 0x94, 0xd5, 0xc3, 0xd5, 0x94, 0xb0, + 0x70, 0x5d, 0x17, 0xbf, 0xd8, 0x07, 0x48, 0xf4, 0xc6, 0x12, 0x50, 0xb2, 0x9b, 0x1b, 0x68, 0xf1, 0x77, 0xd1, 0xf0, + 0x2f, 0x89, 0xfa, 0x3c, 0x9d, 0x0e, 0xdf, 0xc4, 0x4a, 0x81, 0x7c, 0xe2, 0xf6, 0x0f, 0xa5, 0xd0, 0x2a, 0xec, 0x8d, + 0xb0, 0x6e, 0xc6, 0xe4, 0x33, 0x10, 0x99, 0x81, 0x59, 0xf3, 0x4f, 0xa4, 0xfd, 0xe6, 0xa0, 0x3c, 0x04, 0x43, 0x9a, + 0x52, 0x0b, 0xff, 0xbb, 0x9a, 0x44, 0x70, 0x46, 0x33, 0xee, 0x30, 0xff, 0xd5, 0xc3, 0xc5, 0xc4, 0xb8, 0x88, 0xcd, + 0x3c, 0x48, 0xdf, 0x55, 0xbd, 0xdf, 0xb8, 0x16, 0x65, 0xa8, 0x4e, 0x27, 0xe7, 0x76, 0x93, 0x6a, 0x76, 0x79, 0x78, + 0xcd, 0x9a, 0x9f, 0x97, 0x66, 0xda, 0x57, 0x1b, 0x72, 0x0e, 0xb4, 0x76, 0x19, 0x73, 0xd7, 0xa3, 0x0d, 0xa7, 0x00, + 0x31, 0x71, 0x1f, 0x06, 0x0d, 0x98, 0xb0, 0xe6, 0xc1, 0x24, 0xcf, 0xcd, 0x81, 0x00, 0x84, 0x72, 0xd1, 0xd2, 0x5d, + 0x44, 0x5c, 0x7a, 0x2f, 0xad, 0x03, 0xb8, 0xae, 0x8d, 0x29, 0xd2, 0x2e, 0x40, 0x35, 0xcd, 0xd5, 0x6e, 0x1c, 0x66, + 0xba, 0xc6, 0xc0, 0xc7, 0x4c, 0x16, 0x94, 0x09, 0x81, 0x2e, 0x55, 0xc2, 0x5f, 0xbc, 0x12, 0x05, 0x75, 0xdb, 0x68, + 0x06, 0x1c, 0xd4, 0xad, 0x43, 0x88, 0x0f, 0x21, 0x9e, 0x66, 0x68, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xb4, 0x1f, + 0x6e, 0x3f, 0x60, 0xcf, 0x96, 0x24, 0xaa, 0xf0, 0x92, 0xbb, 0x6c, 0x7c, 0x81, 0x94, 0x48, 0xef, 0x2d, 0x27, 0xbd, + 0xd7, 0x5e, 0x6c, 0x44, 0x78, 0x9c, 0x8c, 0x2c, 0x6d, 0xe0, 0x1c, 0x11, 0xf7, 0x72, 0x8c, 0xa7, 0x44, 0xe2, 0x19, + 0xac, 0x52, 0xc0, 0x8d, 0xc8, 0x70, 0x22, 0xfe, 0x19, 0xf8, 0xab, 0x24, 0x8d, 0x93, 0xfe, 0x32, 0x0e, 0xa2, 0x8c, + 0x26, 0x39, 0x82, 0xea, 0x1a, 0xe1, 0x23, 0xc0, 0x73, 0xb3, 0x89, 0x97, 0xc4, 0x0f, 0xb2, 0x87, 0xbe, 0xcb, 0x49, + 0x0a, 0x77, 0xc0, 0xa9, 0x03, 0xb7, 0xb1, 0x7e, 0x9f, 0x43, 0xf3, 0x25, 0x12, 0x7e, 0x49, 0x9d, 0x9c, 0x51, 0xb7, + 0xf9, 0x40, 0x79, 0xcb, 0x02, 0x04, 0x01, 0xf9, 0x41, 0x12, 0x7b, 0x06, 0x58, 0x1e, 0x96, 0xda, 0x9d, 0xd0, 0x99, + 0x85, 0x58, 0x1b, 0xc4, 0xeb, 0xe2, 0xcf, 0xe9, 0x99, 0x9a, 0xdb, 0x5c, 0x0c, 0x14, 0x8f, 0xb9, 0xcf, 0xc8, 0xfa, + 0x04, 0xd2, 0xe9, 0x59, 0xfb, 0xd4, 0x1c, 0xd3, 0x69, 0x9c, 0x50, 0x16, 0x4c, 0xda, 0x3b, 0x59, 0xae, 0xf7, 0xef, + 0x7e, 0xfb, 0xf4, 0x9b, 0xfb, 0x89, 0xe2, 0xcc, 0x10, 0x9d, 0x99, 0x3b, 0x7a, 0xab, 0xdf, 0x67, 0x40, 0x1a, 0x32, + 0xc8, 0xfb, 0x2c, 0x6e, 0x5f, 0x5f, 0xd7, 0x07, 0x8d, 0x31, 0xfb, 0x96, 0x31, 0xbf, 0xf3, 0x12, 0x1a, 0x92, 0x2c, + 0xb8, 0x13, 0x34, 0x63, 0xf7, 0x68, 0xb9, 0x16, 0x6b, 0x8c, 0x17, 0xde, 0x23, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, + 0xd5, 0x62, 0x5c, 0xa4, 0x41, 0x6d, 0x36, 0x22, 0x8c, 0x4d, 0xe5, 0xa6, 0xef, 0x2d, 0xd7, 0xea, 0x15, 0x5d, 0x34, + 0x93, 0x37, 0x75, 0x35, 0xfe, 0xe0, 0x22, 0x98, 0x4c, 0x42, 0x9a, 0x97, 0x16, 0xba, 0xbc, 0x96, 0x0a, 0x70, 0x24, + 0x1c, 0xc8, 0x38, 0x8d, 0xc3, 0x55, 0x46, 0x9b, 0xc1, 0xc5, 0x80, 0xd3, 0x71, 0x0b, 0xe0, 0xe0, 0xef, 0xf2, 0x58, + 0x7b, 0x40, 0x6e, 0xc3, 0x36, 0x71, 0x07, 0x10, 0x6e, 0xdc, 0xee, 0x96, 0x87, 0x0e, 0xaf, 0xe4, 0xa0, 0xad, 0x86, + 0x89, 0x58, 0x70, 0x2d, 0x31, 0xec, 0xad, 0x39, 0x1e, 0x2f, 0x93, 0x21, 0x97, 0x65, 0x51, 0x5e, 0x9e, 0xcc, 0x6f, + 0x73, 0xc6, 0x5e, 0x35, 0x9f, 0xb1, 0x57, 0xe2, 0x8c, 0x6d, 0xdf, 0x99, 0x4f, 0xa7, 0x1e, 0xfc, 0x37, 0x28, 0x26, + 0xd4, 0x77, 0xb5, 0xee, 0x72, 0xad, 0x79, 0xcb, 0xb5, 0x66, 0x77, 0x96, 0x6b, 0x0d, 0xbb, 0x46, 0xcb, 0x0a, 0xcb, + 0xe9, 0x98, 0x96, 0xab, 0x41, 0x21, 0xfc, 0xb9, 0xa5, 0x57, 0xde, 0x21, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, + 0xf6, 0xa3, 0xce, 0xce, 0x92, 0x40, 0xda, 0xa6, 0x93, 0x91, 0xf1, 0x98, 0x4e, 0xfa, 0xd3, 0xd8, 0x5f, 0xa5, 0x7f, + 0xe7, 0xe3, 0xe7, 0x40, 0xdc, 0x8a, 0x08, 0x2a, 0xfd, 0x88, 0xa6, 0xa0, 0xef, 0xb8, 0xa3, 0xa2, 0x87, 0x8d, 0x5c, + 0xa7, 0x3e, 0x8b, 0x8d, 0xde, 0x71, 0x0e, 0x1b, 0x36, 0x79, 0x33, 0xa0, 0x7f, 0xb3, 0x55, 0x6a, 0x47, 0x31, 0xbf, + 0x02, 0x2c, 0x5b, 0xc1, 0xf1, 0x78, 0x68, 0xf0, 0xd5, 0x74, 0x4f, 0x9a, 0x87, 0x7b, 0x2d, 0xbe, 0x74, 0x23, 0x2e, + 0x15, 0x7e, 0x6f, 0x71, 0x87, 0xaf, 0xed, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x5b, 0x2e, 0x84, 0xa2, 0xee, 0x9e, + 0x58, 0xfe, 0xe9, 0xab, 0x43, 0xf8, 0x8f, 0x51, 0xf5, 0x3f, 0x66, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xff, 0x81, 0x91, + 0x4a, 0x48, 0x88, 0xef, 0x5f, 0x7f, 0x3a, 0x7d, 0x5c, 0x83, 0xbd, 0x6b, 0x33, 0xa3, 0xa4, 0x6a, 0xed, 0xaf, 0xe2, + 0x18, 0xf2, 0xf6, 0xd6, 0xab, 0x0b, 0xf0, 0x30, 0x17, 0x8f, 0x6c, 0x08, 0x8d, 0x04, 0x1f, 0xc1, 0x94, 0xf1, 0x3a, + 0xb6, 0x61, 0xac, 0xc4, 0xdb, 0x36, 0x56, 0xe2, 0xcd, 0x6e, 0x56, 0xe2, 0xdb, 0xbd, 0x58, 0x89, 0x37, 0x9f, 0x9d, + 0x95, 0x78, 0x5b, 0x67, 0x25, 0xae, 0x62, 0x61, 0x89, 0x6a, 0x5d, 0xac, 0xf8, 0xcf, 0x0f, 0x4c, 0xb7, 0x76, 0x19, + 0x0f, 0x7b, 0x2e, 0x8b, 0x77, 0x7e, 0xf5, 0x8b, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd1, 0x30, 0xab, 0x60, 0x2d, 0x38, + 0x66, 0xc7, 0xef, 0x28, 0xc5, 0x61, 0x1c, 0xcd, 0xbe, 0x07, 0xdd, 0x2a, 0x88, 0x03, 0x13, 0xe5, 0x45, 0x90, 0x7e, + 0x1f, 0x2f, 0x57, 0xcb, 0x0b, 0xe8, 0xeb, 0x43, 0x90, 0x06, 0xe3, 0x90, 0xca, 0x30, 0x04, 0xcc, 0x90, 0x8c, 0xcb, + 0xc4, 0xc1, 0x76, 0x53, 0xfc, 0x24, 0x6b, 0xf1, 0x13, 0xad, 0x3b, 0xf9, 0x6f, 0x66, 0xa1, 0xa6, 0x37, 0x33, 0x22, + 0x10, 0xb0, 0xab, 0x32, 0xe8, 0xc7, 0x33, 0x23, 0x57, 0xb1, 0xd9, 0x30, 0x4b, 0x61, 0xb6, 0xd0, 0xda, 0x0f, 0xad, + 0x31, 0x35, 0x2b, 0xd3, 0x92, 0xf1, 0xf7, 0xea, 0x62, 0xf8, 0x45, 0xbc, 0x4a, 0xe9, 0x24, 0xbe, 0x8f, 0x74, 0x2b, + 0x95, 0xae, 0x35, 0xa0, 0xa8, 0x94, 0x6d, 0x30, 0x73, 0xac, 0xd4, 0xcc, 0xe8, 0x90, 0xb8, 0x78, 0xb5, 0xb4, 0x99, + 0xc6, 0xd8, 0xc6, 0x29, 0xea, 0x32, 0xc5, 0xd9, 0x13, 0xc3, 0x88, 0x87, 0x8f, 0x6b, 0x29, 0x2c, 0x2e, 0x62, 0x87, + 0x4b, 0x85, 0x53, 0x23, 0x15, 0xc2, 0x45, 0x11, 0x04, 0xa7, 0x61, 0xe1, 0xf8, 0x1b, 0xe6, 0x12, 0x5e, 0xbc, 0x85, + 0x10, 0x42, 0xf9, 0x8a, 0xaf, 0x07, 0x0f, 0x09, 0xc3, 0x1e, 0x5f, 0x2b, 0x60, 0x7c, 0x77, 0x47, 0x93, 0x90, 0x3c, + 0x18, 0x66, 0x1e, 0x47, 0xdf, 0x01, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0x33, 0x35, 0x35, 0xec, 0xa5, 0xc6, + 0xe0, 0x45, 0xe0, 0xae, 0xa5, 0x8c, 0x00, 0x72, 0x64, 0xcf, 0xe8, 0x5f, 0x2c, 0xf6, 0xef, 0x5f, 0xcd, 0xdc, 0xba, + 0x8c, 0xe5, 0x87, 0xfe, 0xbc, 0xdc, 0xe3, 0x33, 0xcf, 0x9f, 0x3f, 0x69, 0x9f, 0xb6, 0x01, 0xe9, 0xc2, 0x45, 0xe6, + 0x6b, 0xa3, 0xa1, 0xb5, 0xd9, 0x7a, 0x0a, 0x60, 0x14, 0x57, 0xf1, 0xca, 0x9f, 0xa3, 0xc9, 0xe8, 0xe7, 0x9b, 0x6f, + 0x06, 0x7d, 0x62, 0x8a, 0x62, 0x39, 0xf5, 0x4a, 0x51, 0x01, 0x05, 0xfc, 0xfe, 0x5b, 0x88, 0xbe, 0xfb, 0x6f, 0x04, + 0x43, 0x7d, 0xd7, 0x70, 0x2e, 0x3e, 0x78, 0xdc, 0xe6, 0x1d, 0x40, 0x26, 0x5d, 0x1e, 0xd7, 0x46, 0x28, 0xd7, 0x9a, + 0x91, 0x4c, 0x5e, 0x05, 0x9a, 0x1a, 0x43, 0xb2, 0x2d, 0x3c, 0xa6, 0xf8, 0x0a, 0x75, 0x18, 0x9b, 0xce, 0x4d, 0xf6, + 0x2d, 0xca, 0xb1, 0x55, 0x05, 0xc9, 0x70, 0xcb, 0x05, 0x8a, 0xe8, 0xab, 0xfa, 0x6e, 0x11, 0x44, 0x16, 0xa6, 0x80, + 0xa8, 0xbf, 0x21, 0x6b, 0x08, 0x82, 0x0e, 0xc8, 0xad, 0xfa, 0x0a, 0x0a, 0x2d, 0xaa, 0x78, 0x8b, 0x42, 0x9e, 0x37, + 0xbd, 0x11, 0x12, 0x42, 0x8b, 0x37, 0xfa, 0x9d, 0xa6, 0x69, 0x9a, 0x64, 0x23, 0x34, 0xc9, 0x47, 0x60, 0x39, 0xb2, + 0x03, 0xa0, 0x2d, 0xc9, 0x97, 0x6b, 0x56, 0x02, 0x9c, 0x01, 0x98, 0x78, 0xc8, 0x02, 0x1e, 0xe7, 0xb3, 0xe7, 0x8a, + 0x02, 0xc1, 0xd0, 0x43, 0x8c, 0x46, 0x92, 0x40, 0x38, 0xf0, 0xbe, 0x86, 0x0c, 0x3b, 0xbe, 0xe5, 0x92, 0x60, 0xcd, + 0x65, 0x8f, 0xa3, 0x01, 0x6d, 0x0e, 0x08, 0x99, 0x2a, 0x58, 0x10, 0xb4, 0x0e, 0x95, 0xf8, 0xee, 0x16, 0x6d, 0xc0, + 0x8d, 0xc8, 0x17, 0xad, 0xb3, 0x05, 0x8d, 0x56, 0x3a, 0x26, 0x84, 0xc3, 0xe0, 0xe2, 0x50, 0xe7, 0x0d, 0x23, 0xb6, + 0x00, 0xdb, 0x34, 0xb7, 0x9c, 0xb3, 0xbb, 0x30, 0xe2, 0x28, 0x95, 0x58, 0x3e, 0x57, 0x6c, 0x46, 0x1c, 0xb7, 0x55, + 0x6f, 0x08, 0xbe, 0xa4, 0x71, 0xd5, 0x7d, 0x91, 0xd9, 0x14, 0x43, 0x1f, 0x2c, 0x34, 0x0e, 0x17, 0x17, 0x09, 0xb0, + 0x1b, 0xa4, 0xba, 0x68, 0x52, 0x23, 0x43, 0x2a, 0x82, 0xa2, 0xc4, 0xac, 0x77, 0xc3, 0xc7, 0x09, 0x51, 0xc9, 0x5a, + 0xfb, 0xf1, 0x6b, 0xfd, 0xb4, 0x4c, 0xfa, 0x96, 0x3e, 0xb0, 0x8b, 0x84, 0x81, 0xea, 0x96, 0x3e, 0x80, 0x09, 0xdf, + 0x5b, 0x90, 0xa6, 0xe8, 0x5b, 0xd0, 0xb5, 0x05, 0x79, 0x3e, 0x7c, 0x88, 0x54, 0xb7, 0xe5, 0x00, 0xb9, 0xf9, 0x16, + 0x2c, 0x8e, 0x20, 0x86, 0x94, 0xee, 0xe2, 0x10, 0x73, 0x63, 0x79, 0xa3, 0x11, 0xc6, 0x76, 0xc3, 0xd1, 0x30, 0x5f, + 0x78, 0xae, 0x7b, 0x50, 0xab, 0x0f, 0x82, 0xec, 0xa6, 0xda, 0xa6, 0x95, 0x0d, 0x3d, 0xd7, 0x0e, 0x5e, 0x38, 0x9d, + 0x41, 0xed, 0x8e, 0x56, 0x02, 0xc9, 0x8e, 0x50, 0xfc, 0x75, 0xf6, 0x6c, 0x63, 0xa4, 0x2d, 0xe0, 0x2d, 0x8c, 0xcf, + 0x71, 0x6c, 0x39, 0x97, 0x7f, 0x8d, 0xea, 0x57, 0x3f, 0x0b, 0x63, 0xcb, 0x92, 0x1a, 0x8d, 0x20, 0x14, 0xba, 0x01, + 0xc7, 0xe8, 0xf7, 0xda, 0x4b, 0xcd, 0x60, 0xc7, 0xc7, 0x34, 0x47, 0x03, 0x81, 0x51, 0x84, 0x5b, 0x97, 0xda, 0x41, + 0xe5, 0x8b, 0x51, 0x15, 0xc3, 0xf1, 0xa0, 0xcb, 0xb4, 0xd0, 0xe8, 0x6d, 0xa5, 0x16, 0xb0, 0xff, 0x96, 0xeb, 0xd3, + 0x19, 0x43, 0xbc, 0x0f, 0xa8, 0x01, 0x89, 0x13, 0x76, 0x76, 0xb8, 0x5a, 0x96, 0xbb, 0x2b, 0x5f, 0x92, 0xfb, 0x77, + 0x86, 0x97, 0x0e, 0xea, 0xd0, 0x64, 0x7f, 0xcd, 0xd7, 0xdd, 0x23, 0xbb, 0xa4, 0xd1, 0xa4, 0xdc, 0x61, 0xe5, 0xfe, + 0xda, 0xbf, 0xbb, 0x12, 0x46, 0x81, 0x8c, 0x22, 0x71, 0x03, 0x46, 0xc9, 0xe3, 0x08, 0x37, 0x3f, 0x3b, 0x6e, 0xc1, + 0x5e, 0x54, 0x0c, 0x36, 0x60, 0xe1, 0x00, 0x65, 0x33, 0x45, 0x28, 0x0e, 0x61, 0xeb, 0xd1, 0x19, 0xde, 0x10, 0x84, + 0x68, 0xeb, 0x4e, 0xcc, 0x84, 0x69, 0x60, 0xd1, 0x26, 0xe0, 0x81, 0x68, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, + 0xd9, 0x2e, 0xa9, 0x35, 0x73, 0x4c, 0xba, 0x4f, 0xc8, 0x52, 0xf1, 0x6d, 0x13, 0xc4, 0xb9, 0xea, 0xe2, 0x56, 0x12, + 0x75, 0xa3, 0x1f, 0x93, 0x68, 0x55, 0xeb, 0x8d, 0x19, 0xfb, 0xa1, 0xf8, 0x5b, 0x61, 0x50, 0x84, 0x42, 0x5d, 0x95, + 0x8d, 0x5f, 0x15, 0xb2, 0x71, 0xc6, 0xd5, 0x14, 0x2e, 0x29, 0x82, 0xfa, 0x57, 0xdc, 0xbd, 0x24, 0x77, 0x50, 0xb8, + 0x7d, 0x15, 0x23, 0x55, 0x1c, 0x99, 0x0a, 0x46, 0x43, 0x71, 0x8f, 0x13, 0x5c, 0x46, 0xd9, 0x4b, 0xae, 0x5c, 0xb5, + 0xf0, 0x63, 0x2a, 0xca, 0x41, 0xea, 0x8e, 0x43, 0x96, 0xc5, 0xea, 0xb6, 0x29, 0x3b, 0xb2, 0xa8, 0xaf, 0x95, 0x4d, + 0x22, 0x3d, 0x4e, 0x18, 0x80, 0x85, 0x98, 0xbe, 0xa2, 0xd7, 0x96, 0x36, 0x10, 0x38, 0xc8, 0x06, 0x07, 0xb9, 0xdd, + 0xd2, 0x79, 0x96, 0x2c, 0xa5, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0x84, 0xef, 0xcd, 0xa6, 0xe1, 0x96, 0xc7, 0x4b, 0x9e, + 0xdf, 0xef, 0x20, 0x5e, 0xd4, 0x5c, 0x55, 0x91, 0x8f, 0x27, 0xd3, 0x66, 0x56, 0xb6, 0x58, 0xb5, 0xde, 0x29, 0x13, + 0xe2, 0x6c, 0xb8, 0x8f, 0x49, 0x59, 0x46, 0xcf, 0x6b, 0xf4, 0xc5, 0x77, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0x26, 0xb6, + 0xb0, 0xb3, 0x84, 0xf8, 0xb7, 0xca, 0x90, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0xc1, 0x80, 0x60, 0x1c, 0x58, + 0xda, 0x77, 0x3a, 0xa9, 0x22, 0x7d, 0xe9, 0x3f, 0x75, 0xbb, 0xe4, 0xd5, 0xf4, 0xb0, 0x22, 0x14, 0xed, 0xf4, 0xca, + 0x22, 0xf3, 0x96, 0x71, 0x64, 0xf3, 0xd5, 0x62, 0xbc, 0x51, 0x65, 0xab, 0x8a, 0xc8, 0xb5, 0x2e, 0x66, 0x55, 0x3f, + 0x3b, 0x9d, 0x4e, 0xcb, 0x82, 0x46, 0x57, 0x3b, 0x44, 0x61, 0xe1, 0x53, 0xd7, 0x75, 0xab, 0x63, 0xdf, 0x0e, 0x76, + 0x1b, 0xe5, 0xb6, 0x27, 0x8d, 0x23, 0x46, 0xd8, 0xee, 0x82, 0x5f, 0x1d, 0x1c, 0xb9, 0x53, 0x9c, 0xec, 0x92, 0x59, + 0xc4, 0x80, 0x19, 0x43, 0x04, 0x19, 0x5d, 0xa4, 0x7d, 0x9f, 0xa2, 0x0e, 0xc6, 0x51, 0x0e, 0x34, 0x1a, 0x0e, 0xd8, + 0x33, 0x30, 0x15, 0xf1, 0xc4, 0xae, 0x70, 0x35, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0x78, 0x50, 0x36, 0x75, + 0x99, 0x36, 0x4e, 0xab, 0xe7, 0xfe, 0xbe, 0x54, 0x4f, 0x83, 0x0b, 0x70, 0x23, 0x14, 0xda, 0x4c, 0x3e, 0x8b, 0xff, + 0x2f, 0xe5, 0xff, 0xaf, 0x96, 0xeb, 0xb2, 0xfd, 0xc8, 0x09, 0x48, 0xb4, 0x8b, 0xd3, 0xc2, 0x46, 0xdd, 0xb4, 0x07, + 0xa4, 0x95, 0xc1, 0x54, 0x55, 0xa0, 0x83, 0x92, 0xbe, 0x94, 0xfd, 0xa7, 0x41, 0xfc, 0x8e, 0x14, 0x33, 0x2c, 0x71, + 0x21, 0x42, 0x2c, 0x72, 0x57, 0xc2, 0x1c, 0xac, 0x97, 0x27, 0xa8, 0x3f, 0x28, 0xed, 0x09, 0xd0, 0xc6, 0xd7, 0xe6, + 0xb6, 0x97, 0xb8, 0xbf, 0xaa, 0xd7, 0x12, 0x1d, 0x03, 0xc8, 0x3c, 0x38, 0x84, 0x68, 0x48, 0xa0, 0x55, 0x36, 0x37, + 0x1b, 0xa5, 0x7c, 0xab, 0xea, 0xd9, 0xc4, 0xc0, 0xb0, 0xbb, 0xe6, 0x2a, 0xac, 0x6f, 0xa1, 0x2d, 0x80, 0xc9, 0xf2, + 0xed, 0x87, 0xcf, 0x36, 0x2c, 0xb1, 0xba, 0x1f, 0x3d, 0x5c, 0x72, 0xdc, 0xbf, 0x36, 0xde, 0x9d, 0x29, 0x3b, 0xff, + 0x28, 0x5f, 0xfc, 0xb6, 0x51, 0xa0, 0x77, 0x55, 0x92, 0xd0, 0x71, 0xa3, 0xef, 0x8e, 0xb9, 0x57, 0xed, 0x45, 0x10, + 0xed, 0x5f, 0x97, 0xac, 0xf7, 0xae, 0x0b, 0x17, 0xc6, 0xde, 0x95, 0xe1, 0xc6, 0x61, 0x96, 0x0b, 0xd9, 0xf0, 0x5b, + 0x45, 0xa0, 0xa8, 0xfa, 0xef, 0xea, 0xd8, 0x8a, 0x51, 0xf9, 0x57, 0x2b, 0x20, 0x3e, 0xf7, 0xca, 0xee, 0xa2, 0x89, + 0x04, 0x8d, 0xfa, 0xb1, 0x76, 0xa2, 0x1d, 0x77, 0xb5, 0x23, 0x57, 0x67, 0x5c, 0xd8, 0x50, 0xef, 0x75, 0x0a, 0xbf, + 0xbc, 0x43, 0x57, 0x3f, 0x3b, 0x9d, 0x89, 0x4b, 0x62, 0x1a, 0x84, 0x21, 0x43, 0x15, 0x60, 0xfe, 0x7b, 0x4b, 0xcb, + 0x6a, 0x16, 0x56, 0xc6, 0x8d, 0x40, 0x3a, 0xe2, 0x11, 0xce, 0x8e, 0x4f, 0x96, 0x7d, 0x3c, 0x1b, 0x6a, 0x21, 0x18, + 0x70, 0xb2, 0x52, 0xfc, 0x04, 0xdc, 0xc1, 0x63, 0xfd, 0xec, 0x14, 0xe2, 0x97, 0x6a, 0x93, 0xa1, 0xfe, 0x5d, 0xe7, + 0x58, 0xf3, 0x7a, 0x77, 0x76, 0xd7, 0x77, 0x6d, 0xcf, 0x39, 0xd4, 0x5c, 0xe7, 0xc8, 0xee, 0x38, 0xc7, 0x5a, 0xc7, + 0xe9, 0xc1, 0xbf, 0xbe, 0xe7, 0xbc, 0xd2, 0x5c, 0x78, 0xd2, 0x3c, 0xa7, 0x8b, 0xff, 0x76, 0x9c, 0xe3, 0xbb, 0x2e, + 0xbb, 0xe9, 0x89, 0xf4, 0x8e, 0xaa, 0x8c, 0x02, 0x7c, 0x39, 0xf4, 0x83, 0xb3, 0xd3, 0x55, 0x4a, 0xb5, 0xf5, 0x50, + 0x7f, 0xa5, 0x6b, 0xf3, 0x84, 0x4e, 0x87, 0xfa, 0x53, 0xa2, 0x94, 0x7a, 0x27, 0x8d, 0xc5, 0x9d, 0xe3, 0xc6, 0xe2, + 0xee, 0x51, 0x63, 0xf1, 0x61, 0xaf, 0x5c, 0x7c, 0x30, 0x63, 0xaf, 0x94, 0xf4, 0xa1, 0x0b, 0x92, 0x25, 0xc1, 0xda, + 0xf0, 0x34, 0x40, 0xd7, 0x36, 0xfc, 0x73, 0xdc, 0x31, 0x65, 0xab, 0x31, 0xb4, 0x92, 0xd0, 0x38, 0x3e, 0xd1, 0xbc, + 0xa3, 0x6f, 0x3a, 0x47, 0x3e, 0xd4, 0x83, 0x64, 0xb7, 0xf0, 0x77, 0xd7, 0x3d, 0xf1, 0x5d, 0x0d, 0x1a, 0x7a, 0xf0, + 0xdf, 0xbc, 0xd7, 0xf1, 0xd9, 0x83, 0x0b, 0xef, 0x3f, 0x78, 0xc7, 0xa9, 0x6b, 0x7b, 0xf0, 0xdf, 0xcf, 0x52, 0xe5, + 0x0e, 0x0a, 0x7f, 0xb5, 0xdf, 0x43, 0x57, 0xeb, 0x9e, 0xcc, 0x3b, 0xce, 0xab, 0xbb, 0x63, 0xe7, 0x64, 0xee, 0x1d, + 0x7f, 0x60, 0x4f, 0xa1, 0xdd, 0x71, 0x5e, 0xc1, 0xdf, 0x87, 0xae, 0x3b, 0xb7, 0x3d, 0xe7, 0xe4, 0xae, 0xeb, 0x74, + 0x43, 0xfb, 0xc8, 0x39, 0x81, 0xbf, 0x9f, 0x01, 0xbc, 0x00, 0x57, 0x9e, 0x9d, 0x58, 0x83, 0x8d, 0x51, 0xb1, 0xdf, + 0x50, 0x3f, 0xd2, 0x39, 0xd4, 0x7a, 0x87, 0xdf, 0x9c, 0xdc, 0xd9, 0x87, 0x73, 0xaf, 0x73, 0x67, 0xb7, 0xfe, 0xfc, + 0x00, 0x90, 0xdf, 0xbe, 0x70, 0x00, 0x46, 0x4c, 0x47, 0xf4, 0xbb, 0x91, 0x75, 0xd9, 0x26, 0x46, 0x7f, 0xbf, 0x5b, + 0x8c, 0xfe, 0xf5, 0x6a, 0x1f, 0x31, 0xfa, 0xfb, 0xcf, 0x2e, 0x46, 0xbf, 0xac, 0x5a, 0x71, 0xbf, 0xaf, 0xa6, 0x4d, + 0xf8, 0x71, 0x53, 0x25, 0x92, 0x03, 0x62, 0x5c, 0x5f, 0xad, 0x6e, 0x20, 0xe2, 0xd5, 0xfb, 0x78, 0xf8, 0xf5, 0xaa, + 0x64, 0xa2, 0x14, 0x03, 0x06, 0x78, 0x1f, 0x33, 0x0c, 0xf0, 0xa7, 0xd5, 0x10, 0xec, 0x22, 0xf8, 0xad, 0x19, 0x4c, + 0xec, 0x39, 0x09, 0xa7, 0xf2, 0xc6, 0x85, 0x92, 0x01, 0x16, 0x83, 0xdd, 0x3d, 0x5c, 0x26, 0xa0, 0xac, 0x59, 0x2d, + 0xa2, 0xb4, 0x7f, 0xe4, 0x02, 0x9a, 0xef, 0x4c, 0x93, 0xbc, 0xd2, 0xd8, 0x11, 0x31, 0xc2, 0x3e, 0x72, 0xcb, 0xfc, + 0xd6, 0xf7, 0x68, 0xb2, 0xd6, 0xdc, 0xbb, 0x57, 0xef, 0x57, 0x03, 0x5b, 0x10, 0x61, 0xd2, 0x07, 0xc4, 0x46, 0xd3, + 0xfb, 0xb2, 0xe1, 0x58, 0xc5, 0x54, 0xb0, 0x7d, 0xa4, 0x30, 0x92, 0x6a, 0x7b, 0xaf, 0x6c, 0x78, 0xb6, 0x6b, 0x9a, + 0x0d, 0x9f, 0x2f, 0x35, 0xdf, 0x62, 0xf5, 0x26, 0x3b, 0xae, 0x82, 0xaa, 0x92, 0xf4, 0xaf, 0x11, 0x20, 0x05, 0xed, + 0x59, 0x98, 0xc6, 0x15, 0x84, 0x8f, 0xab, 0xe1, 0x6d, 0xec, 0x2a, 0xef, 0x4a, 0x7d, 0xaa, 0xe6, 0x74, 0x2f, 0x36, + 0x48, 0x0f, 0x06, 0x3f, 0x03, 0x61, 0xc3, 0xef, 0xe3, 0x71, 0xac, 0xc2, 0x79, 0xa3, 0xf4, 0xcb, 0x48, 0xed, 0x7c, + 0xee, 0x6d, 0xea, 0xa4, 0x4d, 0xab, 0x21, 0xad, 0x47, 0x17, 0xe2, 0x8e, 0xc6, 0xcf, 0x33, 0xb3, 0xd5, 0x9c, 0x99, + 0x16, 0xa3, 0x65, 0xee, 0xb6, 0xce, 0x44, 0xbd, 0xa7, 0xb0, 0x89, 0x2d, 0xfe, 0xa0, 0xfa, 0x7f, 0x6f, 0xa6, 0x90, + 0xa0, 0xbd, 0x8f, 0x44, 0x84, 0x42, 0x41, 0x75, 0xd0, 0xc6, 0x76, 0xb0, 0xc5, 0xfc, 0x43, 0xed, 0x98, 0x77, 0x82, + 0xb6, 0xba, 0xdb, 0x2c, 0x46, 0xa4, 0x6b, 0xc3, 0xa6, 0xa4, 0x40, 0xf5, 0x7a, 0xc7, 0x96, 0x77, 0x64, 0x39, 0xc7, + 0x3d, 0x33, 0x17, 0x07, 0x4e, 0xed, 0xb2, 0x04, 0x10, 0x30, 0xd9, 0x95, 0xc3, 0x0c, 0xa2, 0x20, 0x0b, 0x48, 0x98, + 0x03, 0xaa, 0x2f, 0xd3, 0xbc, 0x7f, 0x5b, 0xa5, 0x19, 0xcc, 0x51, 0x90, 0x64, 0x68, 0xae, 0x6c, 0x8f, 0x69, 0x76, + 0x4f, 0x69, 0xd4, 0xa2, 0xca, 0xad, 0x5a, 0x3f, 0xff, 0x76, 0xb6, 0xa0, 0x39, 0xb3, 0xb3, 0x18, 0x67, 0x11, 0xdf, + 0x1f, 0xc2, 0x54, 0x37, 0x1f, 0x59, 0x3f, 0xb7, 0x21, 0xdc, 0xbf, 0xed, 0x46, 0xb8, 0x19, 0xdd, 0x07, 0xe1, 0xfe, + 0xed, 0xb3, 0x23, 0xdc, 0x9f, 0x55, 0x84, 0x5b, 0xf2, 0x54, 0x29, 0x64, 0xa2, 0x3f, 0xe0, 0xb3, 0x01, 0xf1, 0xc6, + 0x5f, 0xea, 0x07, 0x8c, 0xbc, 0xd4, 0x95, 0x3c, 0xd0, 0x1f, 0x4a, 0x89, 0xad, 0x90, 0x65, 0xc7, 0xd0, 0xc3, 0x2c, + 0x89, 0x0e, 0xe4, 0x48, 0x76, 0x85, 0xfb, 0x21, 0xf4, 0x79, 0x11, 0x65, 0xa1, 0xf3, 0x9e, 0xb3, 0x25, 0xa0, 0x82, + 0xf8, 0x3a, 0x4e, 0x16, 0x04, 0x83, 0x22, 0xea, 0x98, 0x10, 0x13, 0x1e, 0x5c, 0x70, 0x18, 0xf3, 0xe3, 0x68, 0x22, + 0xe5, 0xe8, 0x74, 0x78, 0xcd, 0xe8, 0x41, 0xfd, 0x81, 0x92, 0x44, 0xb7, 0xd8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xf7, + 0x45, 0xe7, 0xf0, 0xc5, 0x91, 0x0b, 0xff, 0xf3, 0x68, 0x37, 0xb7, 0x78, 0xc5, 0x45, 0x1c, 0x41, 0x4e, 0x1e, 0x51, + 0xb3, 0xad, 0xda, 0x3d, 0xa5, 0xb7, 0x45, 0xad, 0xe3, 0xe6, 0x4a, 0x13, 0xf2, 0x50, 0xd4, 0x69, 0xac, 0x31, 0x8f, + 0x57, 0xca, 0xb0, 0x1a, 0x46, 0x13, 0x44, 0x2b, 0x90, 0x0c, 0x29, 0x35, 0xd4, 0xd7, 0x7c, 0xba, 0xc5, 0xbc, 0x68, + 0x37, 0xbf, 0x29, 0x12, 0x7f, 0x89, 0x04, 0x44, 0x3b, 0x21, 0xc8, 0x85, 0xea, 0x2e, 0xa6, 0x0d, 0xc0, 0x68, 0x6f, + 0x1a, 0xa4, 0xdd, 0x14, 0x0b, 0x44, 0xd8, 0x02, 0x65, 0xc9, 0x2a, 0xf2, 0x0d, 0xfc, 0x49, 0xc6, 0xa9, 0x11, 0x1c, + 0x40, 0x4c, 0x5e, 0xfc, 0xb0, 0x89, 0xab, 0x46, 0xce, 0xdc, 0x22, 0x4b, 0x4a, 0x24, 0x56, 0x85, 0xbc, 0xc8, 0xac, + 0x84, 0xe5, 0x56, 0xc6, 0xa5, 0xb5, 0x87, 0xe4, 0x85, 0x6c, 0xf8, 0x22, 0xb3, 0x20, 0xbf, 0x31, 0x2c, 0xf7, 0xf3, + 0xe7, 0xac, 0x16, 0x64, 0x1c, 0x65, 0xd3, 0x3a, 0xf7, 0x65, 0x96, 0x42, 0x5d, 0x23, 0xb3, 0x58, 0xc7, 0x2c, 0x85, + 0x7d, 0xdf, 0x8a, 0x5f, 0xbe, 0x3c, 0x1b, 0x7a, 0x26, 0xcf, 0x97, 0x5b, 0x4a, 0xee, 0x76, 0xb9, 0x9f, 0x6a, 0xdc, + 0x6c, 0x74, 0xda, 0x5a, 0x06, 0xd1, 0x4c, 0x68, 0xa6, 0x25, 0xf6, 0x82, 0x64, 0x2b, 0x4c, 0x05, 0x46, 0x84, 0x8a, + 0x5a, 0xd4, 0xb9, 0xa3, 0x09, 0xe4, 0xfa, 0x1d, 0xea, 0x5d, 0xc7, 0x75, 0x5c, 0x5d, 0x36, 0x9c, 0x06, 0xb3, 0xe1, + 0x26, 0xce, 0x08, 0xa4, 0xad, 0x0a, 0xe3, 0x19, 0x78, 0x7e, 0x64, 0x41, 0x16, 0x42, 0x0e, 0x24, 0x70, 0x01, 0x59, + 0x30, 0xae, 0x31, 0xe7, 0xf6, 0xb8, 0x24, 0xb9, 0xc5, 0x3c, 0x98, 0xc2, 0xe9, 0x0b, 0x23, 0xcb, 0x7c, 0x07, 0x97, + 0xa1, 0xa1, 0x1b, 0x90, 0x85, 0x95, 0x26, 0xa9, 0xad, 0xda, 0xb7, 0xf7, 0x35, 0x68, 0x63, 0xea, 0x7c, 0x12, 0xd3, + 0x84, 0x2c, 0x20, 0x5d, 0xc0, 0x26, 0xb7, 0x38, 0xa6, 0xd5, 0x39, 0xaa, 0xd5, 0xbc, 0x57, 0x47, 0x96, 0xd6, 0xf1, + 0x2c, 0xcd, 0x05, 0x74, 0xab, 0xe7, 0xd6, 0x26, 0xbf, 0x19, 0xec, 0x52, 0xd1, 0x31, 0xfc, 0xf2, 0x94, 0xcd, 0x83, + 0x29, 0xe7, 0xb8, 0xf0, 0x33, 0x63, 0x41, 0x3d, 0x0d, 0x25, 0x90, 0x7f, 0xc0, 0xc4, 0xf4, 0x57, 0x74, 0x9d, 0x99, + 0x98, 0x23, 0x88, 0x57, 0x09, 0xcc, 0x0d, 0xba, 0xa6, 0x05, 0x91, 0x16, 0x7c, 0xfa, 0x64, 0x04, 0x60, 0x7e, 0x3f, + 0x54, 0xe0, 0x03, 0xcf, 0x66, 0x09, 0x60, 0x41, 0xa1, 0x58, 0x42, 0x60, 0x81, 0x6f, 0x0c, 0xfc, 0x5b, 0x14, 0x8b, + 0x1f, 0x5c, 0xb1, 0xe7, 0x84, 0x24, 0x9a, 0x01, 0x4a, 0x23, 0xd1, 0xac, 0x66, 0x40, 0xc0, 0xbc, 0xeb, 0x2a, 0xa5, + 0x45, 0x57, 0x85, 0x72, 0x3f, 0xfd, 0xea, 0xe1, 0x8a, 0xe5, 0x40, 0x33, 0x74, 0xb8, 0xe5, 0xd0, 0x15, 0xac, 0xd0, + 0x3d, 0xbc, 0x1c, 0x7e, 0x71, 0xba, 0xa0, 0x19, 0x61, 0x82, 0x4b, 0x60, 0xf1, 0x80, 0x1c, 0xd0, 0x7c, 0x91, 0xbf, + 0x98, 0x31, 0x78, 0x13, 0x7a, 0x17, 0xf8, 0x9c, 0x4f, 0xb3, 0x34, 0x7e, 0x4f, 0xd9, 0x68, 0xa3, 0x34, 0xf4, 0x2c, + 0x66, 0x22, 0xeb, 0x13, 0x0c, 0xfd, 0x39, 0x8c, 0x62, 0xfd, 0xec, 0x0b, 0xe9, 0x4d, 0xd4, 0xb6, 0x08, 0x90, 0x88, + 0xf4, 0x3a, 0xa1, 0xe1, 0xdf, 0x87, 0x5f, 0xc0, 0xc5, 0xfd, 0xc5, 0x8d, 0x6e, 0x0e, 0x32, 0x07, 0xf9, 0x98, 0x2f, + 0x1a, 0x12, 0x72, 0x22, 0x8f, 0xca, 0x99, 0xcd, 0xae, 0xc2, 0x6c, 0xc2, 0xef, 0xdd, 0xac, 0x2b, 0xb8, 0xa9, 0x3e, + 0x84, 0xf4, 0x0c, 0xb8, 0x8b, 0x4d, 0x89, 0xe7, 0xf4, 0x06, 0xc8, 0xa0, 0x8e, 0x43, 0xe2, 0xdf, 0x0a, 0x0e, 0x55, + 0x7d, 0xd8, 0x87, 0x17, 0x95, 0x94, 0x5d, 0xe3, 0x5e, 0xc6, 0xad, 0xbc, 0xc1, 0x2f, 0xe3, 0xa7, 0xee, 0xe7, 0x41, + 0x26, 0x99, 0x61, 0x7c, 0xc8, 0xd1, 0x37, 0x16, 0xc6, 0x57, 0xb0, 0x3f, 0xc0, 0xa0, 0x7a, 0x27, 0xdf, 0xf4, 0xee, + 0x3c, 0x77, 0xde, 0xf1, 0x1c, 0x60, 0x73, 0xe6, 0x5d, 0xe7, 0x38, 0xb4, 0xbb, 0xce, 0x31, 0xfc, 0x7d, 0x00, 0xd6, + 0xcb, 0xee, 0x38, 0x87, 0x1f, 0xbc, 0x4e, 0x68, 0x9f, 0x38, 0xc7, 0xf0, 0x77, 0xc9, 0x5a, 0xfd, 0x88, 0x4c, 0x0f, + 0x30, 0x3c, 0x5f, 0x94, 0xb0, 0x80, 0xf2, 0x5b, 0x6a, 0x11, 0xac, 0xd2, 0xf5, 0xd6, 0xa0, 0x89, 0x00, 0x94, 0xa1, + 0x5b, 0x22, 0x4a, 0x60, 0x3a, 0x30, 0xd2, 0x21, 0xcf, 0x6d, 0x21, 0x0c, 0x32, 0x84, 0xd7, 0xa4, 0xc8, 0xbc, 0xd0, + 0x78, 0x8c, 0x78, 0x9b, 0xe6, 0x30, 0xfb, 0x22, 0x69, 0x1a, 0x53, 0x5d, 0xfc, 0x79, 0x89, 0xf1, 0x71, 0xa8, 0x59, + 0xc3, 0x4a, 0x45, 0xe2, 0xce, 0x7c, 0xf7, 0xc0, 0xd1, 0x6f, 0x94, 0xca, 0xc4, 0x51, 0x9f, 0xb5, 0x6f, 0xae, 0xce, + 0x90, 0xbd, 0xff, 0xd2, 0x7e, 0x30, 0x5f, 0x32, 0xeb, 0x47, 0x44, 0xd8, 0x9d, 0x04, 0x89, 0x1c, 0x9e, 0x82, 0xa2, + 0xbd, 0xe6, 0xfc, 0x04, 0x26, 0x64, 0xd8, 0xb9, 0x00, 0x2a, 0xf9, 0x8e, 0x84, 0x8a, 0xe9, 0x85, 0xd2, 0xf2, 0x89, + 0xc4, 0xfc, 0xcf, 0x9f, 0x17, 0x83, 0xb3, 0x2b, 0xe3, 0x3e, 0xf5, 0x7a, 0x70, 0xed, 0xf6, 0x68, 0x77, 0xab, 0x15, + 0xd0, 0xee, 0x10, 0xcd, 0x45, 0x3c, 0x49, 0xa1, 0xe9, 0x17, 0x3a, 0xc6, 0x56, 0x53, 0xa4, 0x9a, 0x86, 0x11, 0xc2, + 0x5b, 0x57, 0x58, 0x1d, 0xdd, 0x1c, 0xa4, 0xfb, 0x84, 0xa5, 0xe6, 0xbc, 0x98, 0x0e, 0xa0, 0xd9, 0x32, 0x8f, 0x1d, + 0x2e, 0x8d, 0xff, 0xee, 0x49, 0xa0, 0x7b, 0x11, 0x68, 0xf8, 0x2a, 0xa7, 0xb5, 0xe4, 0x6e, 0x22, 0xef, 0x55, 0x76, + 0xa1, 0xd2, 0xf4, 0x5c, 0x87, 0x22, 0x48, 0xbd, 0x86, 0xd9, 0x16, 0xa5, 0x79, 0x93, 0xbc, 0x2d, 0x8a, 0x02, 0x2b, + 0x80, 0xc8, 0xef, 0x86, 0x70, 0x75, 0x32, 0x9f, 0x3f, 0x6f, 0xbd, 0x84, 0x98, 0x3a, 0x59, 0x4d, 0x3a, 0xab, 0xab, + 0xf8, 0x4d, 0x57, 0x51, 0x8c, 0xec, 0x17, 0xb1, 0x86, 0xb0, 0xca, 0x62, 0x7b, 0x0f, 0x7f, 0x8e, 0x29, 0xc9, 0x1c, + 0xae, 0x07, 0x31, 0x94, 0xcb, 0xdd, 0xf2, 0x68, 0x17, 0xec, 0xb1, 0x78, 0x18, 0x2d, 0x1e, 0x33, 0xee, 0xd9, 0xe6, + 0xc3, 0x8a, 0xfb, 0x21, 0x43, 0x1f, 0x9f, 0xdc, 0x22, 0x06, 0xca, 0xbb, 0x8c, 0xb0, 0x40, 0x19, 0xea, 0x95, 0x1b, + 0x67, 0x44, 0xa4, 0x38, 0x02, 0xba, 0x7c, 0xd0, 0xa8, 0x30, 0x54, 0x7c, 0x95, 0xcf, 0xde, 0x5d, 0x7d, 0xa9, 0xf1, + 0xfd, 0xcf, 0xf4, 0x5b, 0xc8, 0xc8, 0xb0, 0x5c, 0x17, 0x43, 0x96, 0xeb, 0x42, 0xe3, 0x59, 0x67, 0x20, 0x63, 0x44, + 0x7e, 0xc0, 0x20, 0xa8, 0x6b, 0x34, 0xf2, 0x99, 0xd6, 0x6f, 0xb1, 0x0a, 0xb3, 0x60, 0x49, 0x92, 0xec, 0x00, 0x9a, + 0xda, 0x80, 0xe4, 0xf4, 0x36, 0x0f, 0x66, 0xa6, 0x38, 0x14, 0x42, 0xb5, 0x2c, 0x12, 0x9a, 0xc3, 0x69, 0x10, 0x4a, + 0xc5, 0xa1, 0xf8, 0x00, 0xf1, 0x7d, 0xba, 0xcc, 0x86, 0x3a, 0x59, 0x42, 0xce, 0x13, 0x0c, 0x63, 0x7a, 0x10, 0xfb, + 0x19, 0xcd, 0xec, 0x34, 0x4b, 0x28, 0x59, 0xe8, 0x32, 0x64, 0x67, 0xbd, 0xbf, 0x74, 0x35, 0x5e, 0x04, 0x99, 0x8c, + 0x79, 0xc7, 0x26, 0x08, 0x2a, 0x3c, 0x18, 0x22, 0x84, 0x33, 0x60, 0x20, 0xbc, 0x8c, 0x67, 0x95, 0x1d, 0x55, 0x50, + 0x2e, 0xe7, 0x4a, 0x5c, 0x09, 0x10, 0x8e, 0xfa, 0x71, 0xf8, 0x91, 0x7b, 0x5d, 0xcb, 0xd0, 0x7c, 0xfa, 0xd9, 0x29, + 0x67, 0x6f, 0x35, 0x0c, 0x14, 0xa0, 0xf7, 0x5c, 0x08, 0x36, 0xdb, 0xe6, 0x8f, 0x7d, 0xc0, 0x2b, 0xab, 0x91, 0x15, + 0xfa, 0x97, 0x7c, 0x2c, 0x57, 0x40, 0x08, 0x95, 0x54, 0xbc, 0x73, 0xef, 0x4c, 0x3a, 0x00, 0xe1, 0xa8, 0x90, 0x56, + 0xfa, 0xf4, 0xe9, 0xf5, 0xe8, 0x9f, 0xff, 0x80, 0x14, 0x04, 0x73, 0x4f, 0x78, 0x41, 0x5f, 0xab, 0xb5, 0x38, 0xf5, + 0x69, 0x8d, 0x50, 0xbd, 0x4f, 0x27, 0x22, 0x2a, 0x8c, 0xd8, 0x5a, 0xf9, 0xe8, 0x46, 0x44, 0x6c, 0x82, 0x34, 0x23, + 0xa6, 0xf0, 0xd5, 0x1e, 0xc1, 0xf2, 0x8e, 0x44, 0x88, 0x00, 0xed, 0xa7, 0xf5, 0x57, 0xc7, 0x9a, 0x5e, 0xe4, 0x0e, + 0x68, 0xd0, 0x41, 0xb3, 0x3d, 0x74, 0x76, 0x4a, 0xb8, 0xf0, 0x15, 0xc8, 0x8f, 0xb4, 0x7f, 0x00, 0xd3, 0x9c, 0xc7, + 0x0b, 0xea, 0x04, 0xf1, 0xc1, 0x3d, 0x1d, 0xdb, 0x64, 0x19, 0x30, 0xf9, 0x32, 0xca, 0xdd, 0x34, 0x46, 0xf9, 0x49, + 0x05, 0x2d, 0xa3, 0xaf, 0xf3, 0x02, 0x94, 0x71, 0x01, 0x28, 0xf8, 0x49, 0xce, 0xca, 0x71, 0xf8, 0x1c, 0x91, 0x17, + 0xa2, 0x8c, 0xe5, 0xcf, 0x59, 0x38, 0x3d, 0x11, 0x39, 0xaf, 0x78, 0xb0, 0xe3, 0xe9, 0x54, 0x8d, 0x9d, 0xe7, 0x94, + 0xbf, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0xc9, 0xbe, 0x54, 0xff, 0x84, 0xfc, 0x09, 0xb1, 0x40, 0x78, 0x98, 0x45, + 0x38, 0xcf, 0xb5, 0x18, 0x7c, 0x12, 0x24, 0x4f, 0x59, 0x25, 0x8e, 0x28, 0xaa, 0xd1, 0xd9, 0x5b, 0x48, 0x93, 0x27, + 0xc3, 0x21, 0xc3, 0x63, 0x55, 0x74, 0x06, 0x50, 0x6a, 0xc8, 0x91, 0x01, 0x93, 0xcd, 0xa0, 0xa1, 0xcd, 0x3c, 0xb8, + 0xb0, 0x51, 0x75, 0x3a, 0xf5, 0x31, 0x1e, 0x10, 0xb1, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5f, 0x58, 0x40, 0xe0, + 0xa2, 0x9f, 0x0a, 0x1e, 0xd7, 0xfe, 0xc0, 0x50, 0xb6, 0x1d, 0x92, 0x87, 0x58, 0xd1, 0xac, 0x73, 0x27, 0xfb, 0x4b, + 0x2c, 0xbd, 0x12, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0xb3, 0x00, 0xd4, 0x4f, 0x93, 0x1a, 0xb6, 0x7f, 0xd7, 0x61, 0x52, + 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xf4, 0x00, 0xe6, 0x07, 0x81, + 0x01, 0x4a, 0x94, 0x51, 0x60, 0x42, 0xf4, 0x01, 0x92, 0x32, 0xeb, 0x80, 0x8b, 0x89, 0x20, 0xea, 0x90, 0x73, 0x94, + 0x41, 0x3e, 0x4b, 0x55, 0xea, 0xc4, 0x8a, 0xdb, 0x4c, 0xe5, 0xed, 0xce, 0xc0, 0xf1, 0xa7, 0x15, 0xa6, 0xdf, 0xc8, + 0x07, 0x19, 0x15, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x46, 0xb0, 0x6e, 0xa9, 0x50, 0xec, 0xe3, + 0x6d, 0xb5, 0x0a, 0xd2, 0x48, 0x56, 0x5b, 0x12, 0x43, 0x7f, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, 0x65, + 0x36, 0x84, 0xaa, 0x42, 0xd8, 0x4e, 0x96, 0x4b, 0x56, 0xd9, 0x1c, 0x9c, 0x1e, 0x30, 0xbe, 0xf3, 0x8c, 0xed, 0xb0, + 0xb3, 0x53, 0xb0, 0x2e, 0x64, 0x8b, 0x4e, 0x96, 0x4b, 0xbe, 0xa4, 0xec, 0x17, 0x7b, 0x73, 0x30, 0xcf, 0x16, 0xe1, + 0xd9, 0xff, 0x01, 0xff, 0xd7, 0x9f, 0x05, 0x1b, 0x5f, 0x03, 0x00}; } // namespace web_server } // namespace esphome From bd8ccde8625752160f904fe4847cef6443aefebb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 8 May 2024 13:22:04 +1200 Subject: [PATCH 1686/2607] Bump version to 2024.5.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c0d27337d6..7996a7a24a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0-dev" +__version__ = "2024.5.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b7c6125a0bbd79c9bc5c07cde453cd95354ecd6b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 8 May 2024 13:22:05 +1200 Subject: [PATCH 1687/2607] Bump version to 2024.6.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index c0d27337d6..dba974610a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0-dev" +__version__ = "2024.6.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7764ab2411a4498dbb7171cf54f2565db0a9a617 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 8 May 2024 16:17:45 +1200 Subject: [PATCH 1688/2607] [github] Upgrade to actions/{upload,download}-artifact v4 (#6698) --- .github/actions/build-image/action.yaml | 16 ---------------- .github/workflows/release.yml | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 838bc362a1..87ea28fd20 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -57,14 +57,6 @@ runs: digest="${{ steps.build-ghcr.outputs.digest }}" touch "/tmp/digests/${{ inputs.target }}/ghcr/${digest#sha256:}" - - name: Upload ghcr digest - uses: actions/upload-artifact@v3.1.3 - with: - name: digests-${{ inputs.target }}-ghcr - path: /tmp/digests/${{ inputs.target }}/ghcr/* - if-no-files-found: error - retention-days: 1 - - name: Build and push to dockerhub by digest id: build-dockerhub uses: docker/build-push-action@v5.3.0 @@ -87,11 +79,3 @@ runs: mkdir -p /tmp/digests/${{ inputs.target }}/dockerhub digest="${{ steps.build-dockerhub.outputs.digest }}" touch "/tmp/digests/${{ inputs.target }}/dockerhub/${digest#sha256:}" - - - name: Upload dockerhub digest - uses: actions/upload-artifact@v3.1.3 - with: - name: digests-${{ inputs.target }}-dockerhub - path: /tmp/digests/${{ inputs.target }}/dockerhub/* - if-no-files-found: error - retention-days: 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d91d00b85..5002f041e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -132,6 +132,13 @@ jobs: suffix: lint version: ${{ needs.init.outputs.tag }} + - name: Upload digests + uses: actions/upload-artifact@v4.3.3 + with: + name: digests-${{ matrix.platform }} + path: /tmp/digests + retention-days: 1 + deploy-manifest: name: Publish ESPHome ${{ matrix.image.title }} to ${{ matrix.registry }} runs-on: ubuntu-latest @@ -160,11 +167,14 @@ jobs: - dockerhub steps: - uses: actions/checkout@v4.1.5 + - name: Download digests - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@v4.1.7 with: - name: digests-${{ matrix.image.target }}-${{ matrix.registry }} + pattern: digests-* path: /tmp/digests + merge-multiple: true + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.3.0 @@ -195,7 +205,7 @@ jobs: done - name: Create manifest list and push - working-directory: /tmp/digests + working-directory: /tmp/digests/${{ matrix.image.target }}/${{ matrix.registry }} run: | docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \ $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *) From e48d02495b65fcef806cbd07da24a928e7e646bc Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Wed, 8 May 2024 21:05:24 +0200 Subject: [PATCH 1689/2607] [nextion] Replace flags to `USE_ARDUINO` (#6700) --- esphome/components/nextion/nextion.h | 10 +++++----- esphome/components/nextion/nextion_upload_arduino.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 6435e2b4e2..dfa74f644d 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -12,7 +12,7 @@ #include "esphome/components/display/display_color_utils.h" #ifdef USE_NEXTION_TFT_UPLOAD -#ifdef ARDUINO +#ifdef USE_ARDUINO #ifdef USE_ESP32 #include #endif // USE_ESP32 @@ -22,7 +22,7 @@ #endif // USE_ESP8266 #elif defined(USE_ESP_IDF) #include -#endif // ARDUINO vs ESP-IDF +#endif // ARDUINO vs USE_ESP_IDF #endif // USE_NEXTION_TFT_UPLOAD namespace esphome { @@ -987,7 +987,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe #ifdef USE_NEXTION_TFT_UPLOAD /** - * Set the tft file URL. https seems problematic with arduino.. + * Set the tft file URL. https seems problematic with Arduino.. */ void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } @@ -1190,7 +1190,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe uint32_t original_baud_rate_ = 0; bool upload_first_chunk_sent_ = false; -#ifdef ARDUINO +#ifdef USE_ARDUINO /** * will request chunk_size chunks from the web server * and send each to the nextion @@ -1208,7 +1208,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return position of last byte transferred, -1 for failure. */ int upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start); -#endif // ARDUINO vs USE_ESP_IDF +#endif // USE_ARDUINO vs USE_ESP_IDF /** * Ends the upload process, restart Nextion and, if successful, diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index b199db91b7..1187c77c8e 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -1,7 +1,7 @@ #include "nextion.h" #ifdef USE_NEXTION_TFT_UPLOAD -#ifdef ARDUINO +#ifdef USE_ARDUINO #include "esphome/core/application.h" #include "esphome/core/defines.h" @@ -383,5 +383,5 @@ WiFiClient *Nextion::get_wifi_client_() { } // namespace nextion } // namespace esphome -#endif // ARDUINO +#endif // USE_ARDUINO #endif // USE_NEXTION_TFT_UPLOAD From 487e171443054d1613cdefb573a336c98012f427 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Wed, 8 May 2024 21:58:40 +0000 Subject: [PATCH 1690/2607] [remote_receiver, remote_transmitter] Improve error messages on the ESP32 (#6701) --- esphome/components/remote_receiver/remote_receiver.h | 1 + .../remote_receiver/remote_receiver_esp32.cpp | 11 ++++++++++- .../remote_transmitter/remote_transmitter.h | 1 + .../remote_transmitter/remote_transmitter_esp32.cpp | 9 ++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index a1db671e5c..773f8cf636 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -58,6 +58,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, void decode_rmt_(rmt_item32_t *item, size_t len); RingbufHandle_t ringbuf_; esp_err_t error_code_{ESP_OK}; + std::string error_string_{""}; #endif #if defined(USE_ESP8266) || defined(USE_LIBRETINY) diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index c0bfb0222f..91295871e2 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -29,6 +29,7 @@ void RemoteReceiverComponent::setup() { esp_err_t error = rmt_config(&rmt); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_config"; this->mark_failed(); return; } @@ -36,18 +37,25 @@ void RemoteReceiverComponent::setup() { error = rmt_driver_install(this->channel_, this->buffer_size_, 0); if (error != ESP_OK) { this->error_code_ = error; + if (error == ESP_ERR_INVALID_STATE) { + this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); + } else { + this->error_string_ = "in rmt_driver_install"; + } this->mark_failed(); return; } error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_get_ringbuf_handle"; this->mark_failed(); return; } error = rmt_rx_start(this->channel_, true); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_rx_start"; this->mark_failed(); return; } @@ -67,7 +75,8 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_); ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_); if (this->is_failed()) { - ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), + this->error_string_.c_str()); } } diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index e736172cda..b897fa8fab 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -53,6 +53,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, bool initialized_{false}; std::vector rmt_temp_; esp_err_t error_code_{ESP_OK}; + std::string error_string_{""}; bool inverted_{false}; #endif uint8_t carrier_duty_percent_; diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index c3d4d42e4f..eea35019ff 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -23,7 +23,8 @@ void RemoteTransmitterComponent::dump_config() { } if (this->is_failed()) { - ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), + this->error_string_.c_str()); } } @@ -56,6 +57,7 @@ void RemoteTransmitterComponent::configure_rmt_() { esp_err_t error = rmt_config(&c); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_config"; this->mark_failed(); return; } @@ -64,6 +66,11 @@ void RemoteTransmitterComponent::configure_rmt_() { error = rmt_driver_install(this->channel_, 0, 0); if (error != ESP_OK) { this->error_code_ = error; + if (error == ESP_ERR_INVALID_STATE) { + this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); + } else { + this->error_string_ = "in rmt_driver_install"; + } this->mark_failed(); return; } From 72481006e4b8634eb4309092327b082afc099d64 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 12:25:57 +1200 Subject: [PATCH 1691/2607] [ethernet] Use constexpr instead of inline define for KSZ80XX_PC2R_REG_ADDR (#6705) --- esphome/components/ethernet/ethernet_component.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 243135de89..17093ffb3d 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -1,12 +1,12 @@ #include "ethernet_component.h" +#include "esphome/core/application.h" #include "esphome/core/log.h" #include "esphome/core/util.h" -#include "esphome/core/application.h" #ifdef USE_ESP32 -#include #include +#include #include "esp_event.h" #ifdef USE_ETHERNET_SPI @@ -554,9 +554,10 @@ bool EthernetComponent::powerdown() { } #ifndef USE_ETHERNET_SPI -void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { -#define KSZ80XX_PC2R_REG_ADDR (0x1F) +constexpr uint8_t KSZ80XX_PC2R_REG_ADDR = 0x1F; + +void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { esp_err_t err; uint32_t phy_control_2; @@ -581,8 +582,6 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); } - -#undef KSZ80XX_PC2R_REG_ADDR } #endif From 819be760133e4c13a4ce141737705ae5fcae6292 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Wed, 8 May 2024 20:47:25 -0400 Subject: [PATCH 1692/2607] Add PHY register writes to enable external clock on Ethernet with RTL8201 (#6704) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../ethernet/ethernet_component.cpp | 44 +++++++++++++++++++ .../components/ethernet/ethernet_component.h | 2 + 2 files changed, 46 insertions(+) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 17093ffb3d..3af462d593 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -184,6 +184,10 @@ void EthernetComponent::setup() { // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide. this->ksz8081_set_clock_reference_(mac); } + if (this->type_ == ETHERNET_TYPE_RTL8201 && this->clk_mode_ == EMAC_CLK_EXT_IN) { + // Change in default behavior of RTL8201FI may require register setting to enable external clock + this->rtl8201_set_rmii_mode_(mac); + } #endif // use ESP internal eth mac @@ -583,6 +587,46 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); } } +constexpr uint8_t RTL8201_RMSR_REG_ADDR = 0x10; +void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) { + esp_err_t err; + uint32_t phy_rmii_mode; + err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07); + ESPHL_ERROR_CHECK(err, "Setting Page 7 failed"); + + /* + * RTL8201 RMII Mode Setting Register (RMSR) + * Page 7 Register 16 + * + * bit 0 Reserved 0 + * bit 1 Rg_rmii_rxdsel 1 (default) + * bit 2 Rg_rmii_rxdv_sel: 0 (default) + * bit 3 RMII Mode: 1 (RMII Mode) + * bit 4~7 Rg_rmii_rx_offset: 1111 (default) + * bit 8~11 Rg_rmii_tx_offset: 1111 (default) + * bit 12 Rg_rmii_clkdir: 1 (Input) + * bit 13~15 Reserved 000 + * + * Binary: 0001 1111 1111 1010 + * Hex: 0x1FFA + * + */ + + err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); + ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); + ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04X", phy_rmii_mode); + + err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA); + ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed"); + + err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); + ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); + ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04X", phy_rmii_mode); + + err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0); + ESPHL_ERROR_CHECK(err, "Setting Page 0 failed"); +} + #endif } // namespace ethernet diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index daeb5a2029..6276885fd1 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -86,6 +86,8 @@ class EthernetComponent : public Component { void dump_connect_params_(); /// @brief Set `RMII Reference Clock Select` bit for KSZ8081. void ksz8081_set_clock_reference_(esp_eth_mac_t *mac); + /// @brief Set `RMII Mode Setting Register` for RTL8201. + void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac); std::string use_address_; #ifdef USE_ETHERNET_SPI From 3ec4a66c9efb8258966f22e734fe23e06326d614 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 8 May 2024 20:45:10 -0500 Subject: [PATCH 1693/2607] Bump recommended ESP-IDF to 4.4.7 (#6703) --- esphome/components/esp32/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 5d74838daa..8f46567266 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -227,7 +227,7 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) # The default/recommended esp-idf framework version # - https://github.com/espressif/esp-idf/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf -RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 6) +RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 7) # The platformio/espressif32 version to use for esp-idf frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 diff --git a/platformio.ini b/platformio.ini index e699057fa3..d342b32b02 100644 --- a/platformio.ini +++ b/platformio.ini @@ -137,7 +137,7 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script extends = common:idf platform = platformio/espressif32@5.4.0 platform_packages = - platformio/framework-espidf@~3.40406.0 + platformio/framework-espidf@~3.40407.0 framework = espidf lib_deps = From 054587c0e48fa4874a99a48f94e89c17ef98ce12 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 8 May 2024 16:17:45 +1200 Subject: [PATCH 1694/2607] [github] Upgrade to actions/{upload,download}-artifact v4 (#6698) --- .github/actions/build-image/action.yaml | 16 ---------------- .github/workflows/release.yml | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 838bc362a1..87ea28fd20 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -57,14 +57,6 @@ runs: digest="${{ steps.build-ghcr.outputs.digest }}" touch "/tmp/digests/${{ inputs.target }}/ghcr/${digest#sha256:}" - - name: Upload ghcr digest - uses: actions/upload-artifact@v3.1.3 - with: - name: digests-${{ inputs.target }}-ghcr - path: /tmp/digests/${{ inputs.target }}/ghcr/* - if-no-files-found: error - retention-days: 1 - - name: Build and push to dockerhub by digest id: build-dockerhub uses: docker/build-push-action@v5.3.0 @@ -87,11 +79,3 @@ runs: mkdir -p /tmp/digests/${{ inputs.target }}/dockerhub digest="${{ steps.build-dockerhub.outputs.digest }}" touch "/tmp/digests/${{ inputs.target }}/dockerhub/${digest#sha256:}" - - - name: Upload dockerhub digest - uses: actions/upload-artifact@v3.1.3 - with: - name: digests-${{ inputs.target }}-dockerhub - path: /tmp/digests/${{ inputs.target }}/dockerhub/* - if-no-files-found: error - retention-days: 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d91d00b85..5002f041e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -132,6 +132,13 @@ jobs: suffix: lint version: ${{ needs.init.outputs.tag }} + - name: Upload digests + uses: actions/upload-artifact@v4.3.3 + with: + name: digests-${{ matrix.platform }} + path: /tmp/digests + retention-days: 1 + deploy-manifest: name: Publish ESPHome ${{ matrix.image.title }} to ${{ matrix.registry }} runs-on: ubuntu-latest @@ -160,11 +167,14 @@ jobs: - dockerhub steps: - uses: actions/checkout@v4.1.5 + - name: Download digests - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@v4.1.7 with: - name: digests-${{ matrix.image.target }}-${{ matrix.registry }} + pattern: digests-* path: /tmp/digests + merge-multiple: true + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.3.0 @@ -195,7 +205,7 @@ jobs: done - name: Create manifest list and push - working-directory: /tmp/digests + working-directory: /tmp/digests/${{ matrix.image.target }}/${{ matrix.registry }} run: | docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \ $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *) From 34585a6f15ba05805d3e54c14645b6ebcfaf83e1 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Wed, 8 May 2024 21:05:24 +0200 Subject: [PATCH 1695/2607] [nextion] Replace flags to `USE_ARDUINO` (#6700) --- esphome/components/nextion/nextion.h | 10 +++++----- esphome/components/nextion/nextion_upload_arduino.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 6435e2b4e2..dfa74f644d 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -12,7 +12,7 @@ #include "esphome/components/display/display_color_utils.h" #ifdef USE_NEXTION_TFT_UPLOAD -#ifdef ARDUINO +#ifdef USE_ARDUINO #ifdef USE_ESP32 #include #endif // USE_ESP32 @@ -22,7 +22,7 @@ #endif // USE_ESP8266 #elif defined(USE_ESP_IDF) #include -#endif // ARDUINO vs ESP-IDF +#endif // ARDUINO vs USE_ESP_IDF #endif // USE_NEXTION_TFT_UPLOAD namespace esphome { @@ -987,7 +987,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe #ifdef USE_NEXTION_TFT_UPLOAD /** - * Set the tft file URL. https seems problematic with arduino.. + * Set the tft file URL. https seems problematic with Arduino.. */ void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } @@ -1190,7 +1190,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe uint32_t original_baud_rate_ = 0; bool upload_first_chunk_sent_ = false; -#ifdef ARDUINO +#ifdef USE_ARDUINO /** * will request chunk_size chunks from the web server * and send each to the nextion @@ -1208,7 +1208,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * @return position of last byte transferred, -1 for failure. */ int upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start); -#endif // ARDUINO vs USE_ESP_IDF +#endif // USE_ARDUINO vs USE_ESP_IDF /** * Ends the upload process, restart Nextion and, if successful, diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index b199db91b7..1187c77c8e 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -1,7 +1,7 @@ #include "nextion.h" #ifdef USE_NEXTION_TFT_UPLOAD -#ifdef ARDUINO +#ifdef USE_ARDUINO #include "esphome/core/application.h" #include "esphome/core/defines.h" @@ -383,5 +383,5 @@ WiFiClient *Nextion::get_wifi_client_() { } // namespace nextion } // namespace esphome -#endif // ARDUINO +#endif // USE_ARDUINO #endif // USE_NEXTION_TFT_UPLOAD From 879f404b48e1de4535097e119698ae9861f7294f Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Wed, 8 May 2024 21:58:40 +0000 Subject: [PATCH 1696/2607] [remote_receiver, remote_transmitter] Improve error messages on the ESP32 (#6701) --- esphome/components/remote_receiver/remote_receiver.h | 1 + .../remote_receiver/remote_receiver_esp32.cpp | 11 ++++++++++- .../remote_transmitter/remote_transmitter.h | 1 + .../remote_transmitter/remote_transmitter_esp32.cpp | 9 ++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index a1db671e5c..773f8cf636 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -58,6 +58,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, void decode_rmt_(rmt_item32_t *item, size_t len); RingbufHandle_t ringbuf_; esp_err_t error_code_{ESP_OK}; + std::string error_string_{""}; #endif #if defined(USE_ESP8266) || defined(USE_LIBRETINY) diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index c0bfb0222f..91295871e2 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -29,6 +29,7 @@ void RemoteReceiverComponent::setup() { esp_err_t error = rmt_config(&rmt); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_config"; this->mark_failed(); return; } @@ -36,18 +37,25 @@ void RemoteReceiverComponent::setup() { error = rmt_driver_install(this->channel_, this->buffer_size_, 0); if (error != ESP_OK) { this->error_code_ = error; + if (error == ESP_ERR_INVALID_STATE) { + this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); + } else { + this->error_string_ = "in rmt_driver_install"; + } this->mark_failed(); return; } error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_get_ringbuf_handle"; this->mark_failed(); return; } error = rmt_rx_start(this->channel_, true); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_rx_start"; this->mark_failed(); return; } @@ -67,7 +75,8 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_); ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_); if (this->is_failed()) { - ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), + this->error_string_.c_str()); } } diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index e736172cda..b897fa8fab 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -53,6 +53,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, bool initialized_{false}; std::vector rmt_temp_; esp_err_t error_code_{ESP_OK}; + std::string error_string_{""}; bool inverted_{false}; #endif uint8_t carrier_duty_percent_; diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index c3d4d42e4f..eea35019ff 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -23,7 +23,8 @@ void RemoteTransmitterComponent::dump_config() { } if (this->is_failed()) { - ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), + this->error_string_.c_str()); } } @@ -56,6 +57,7 @@ void RemoteTransmitterComponent::configure_rmt_() { esp_err_t error = rmt_config(&c); if (error != ESP_OK) { this->error_code_ = error; + this->error_string_ = "in rmt_config"; this->mark_failed(); return; } @@ -64,6 +66,11 @@ void RemoteTransmitterComponent::configure_rmt_() { error = rmt_driver_install(this->channel_, 0, 0); if (error != ESP_OK) { this->error_code_ = error; + if (error == ESP_ERR_INVALID_STATE) { + this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); + } else { + this->error_string_ = "in rmt_driver_install"; + } this->mark_failed(); return; } From 2fbe80c1f78cc407d79a8d06e4c0c948f013f1ae Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 12:25:57 +1200 Subject: [PATCH 1697/2607] [ethernet] Use constexpr instead of inline define for KSZ80XX_PC2R_REG_ADDR (#6705) --- esphome/components/ethernet/ethernet_component.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 243135de89..17093ffb3d 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -1,12 +1,12 @@ #include "ethernet_component.h" +#include "esphome/core/application.h" #include "esphome/core/log.h" #include "esphome/core/util.h" -#include "esphome/core/application.h" #ifdef USE_ESP32 -#include #include +#include #include "esp_event.h" #ifdef USE_ETHERNET_SPI @@ -554,9 +554,10 @@ bool EthernetComponent::powerdown() { } #ifndef USE_ETHERNET_SPI -void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { -#define KSZ80XX_PC2R_REG_ADDR (0x1F) +constexpr uint8_t KSZ80XX_PC2R_REG_ADDR = 0x1F; + +void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { esp_err_t err; uint32_t phy_control_2; @@ -581,8 +582,6 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); } - -#undef KSZ80XX_PC2R_REG_ADDR } #endif From ed1344edd24c983196c1f50bc0571eaf0580a472 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Wed, 8 May 2024 20:47:25 -0400 Subject: [PATCH 1698/2607] Add PHY register writes to enable external clock on Ethernet with RTL8201 (#6704) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../ethernet/ethernet_component.cpp | 44 +++++++++++++++++++ .../components/ethernet/ethernet_component.h | 2 + 2 files changed, 46 insertions(+) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 17093ffb3d..3af462d593 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -184,6 +184,10 @@ void EthernetComponent::setup() { // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide. this->ksz8081_set_clock_reference_(mac); } + if (this->type_ == ETHERNET_TYPE_RTL8201 && this->clk_mode_ == EMAC_CLK_EXT_IN) { + // Change in default behavior of RTL8201FI may require register setting to enable external clock + this->rtl8201_set_rmii_mode_(mac); + } #endif // use ESP internal eth mac @@ -583,6 +587,46 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); } } +constexpr uint8_t RTL8201_RMSR_REG_ADDR = 0x10; +void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) { + esp_err_t err; + uint32_t phy_rmii_mode; + err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07); + ESPHL_ERROR_CHECK(err, "Setting Page 7 failed"); + + /* + * RTL8201 RMII Mode Setting Register (RMSR) + * Page 7 Register 16 + * + * bit 0 Reserved 0 + * bit 1 Rg_rmii_rxdsel 1 (default) + * bit 2 Rg_rmii_rxdv_sel: 0 (default) + * bit 3 RMII Mode: 1 (RMII Mode) + * bit 4~7 Rg_rmii_rx_offset: 1111 (default) + * bit 8~11 Rg_rmii_tx_offset: 1111 (default) + * bit 12 Rg_rmii_clkdir: 1 (Input) + * bit 13~15 Reserved 000 + * + * Binary: 0001 1111 1111 1010 + * Hex: 0x1FFA + * + */ + + err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); + ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); + ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04X", phy_rmii_mode); + + err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA); + ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed"); + + err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); + ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); + ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04X", phy_rmii_mode); + + err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0); + ESPHL_ERROR_CHECK(err, "Setting Page 0 failed"); +} + #endif } // namespace ethernet diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index daeb5a2029..6276885fd1 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -86,6 +86,8 @@ class EthernetComponent : public Component { void dump_connect_params_(); /// @brief Set `RMII Reference Clock Select` bit for KSZ8081. void ksz8081_set_clock_reference_(esp_eth_mac_t *mac); + /// @brief Set `RMII Mode Setting Register` for RTL8201. + void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac); std::string use_address_; #ifdef USE_ETHERNET_SPI From 98dc9fde6c6041a491f56d0a9ea67dc12ebab963 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 8 May 2024 20:45:10 -0500 Subject: [PATCH 1699/2607] Bump recommended ESP-IDF to 4.4.7 (#6703) --- esphome/components/esp32/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 5d74838daa..8f46567266 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -227,7 +227,7 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) # The default/recommended esp-idf framework version # - https://github.com/espressif/esp-idf/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf -RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 6) +RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 7) # The platformio/espressif32 version to use for esp-idf frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 diff --git a/platformio.ini b/platformio.ini index e699057fa3..d342b32b02 100644 --- a/platformio.ini +++ b/platformio.ini @@ -137,7 +137,7 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script extends = common:idf platform = platformio/espressif32@5.4.0 platform_packages = - platformio/framework-espidf@~3.40406.0 + platformio/framework-espidf@~3.40407.0 framework = espidf lib_deps = From 0ca395e8d0c7dc728da6f54c41c627117f74a006 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 14:45:40 +1200 Subject: [PATCH 1700/2607] Bump version to 2024.5.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 7996a7a24a..46fc5fc20b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b1" +__version__ = "2024.5.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From d0120cefd24dda9f512b3d8124c410179cdda87a Mon Sep 17 00:00:00 2001 From: chbmuc Date: Thu, 9 May 2024 05:02:43 +0200 Subject: [PATCH 1701/2607] Add IRK support to ble_rssi (#6422) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../ble_presence/ble_presence_device.h | 49 +------------------ esphome/components/ble_rssi/ble_rssi_sensor.h | 14 +++++- esphome/components/ble_rssi/sensor.py | 11 ++++- .../esp32_ble_tracker/esp32_ble_tracker.cpp | 36 ++++++++++++++ .../esp32_ble_tracker/esp32_ble_tracker.h | 2 + tests/components/ble_rssi/common.yaml | 3 ++ 6 files changed, 65 insertions(+), 50 deletions(-) diff --git a/esphome/components/ble_presence/ble_presence_device.h b/esphome/components/ble_presence/ble_presence_device.h index e74c2f4f45..3ed60d1b49 100644 --- a/esphome/components/ble_presence/ble_presence_device.h +++ b/esphome/components/ble_presence/ble_presence_device.h @@ -6,16 +6,6 @@ #ifdef USE_ESP32 -#ifdef USE_ARDUINO -#include "mbedtls/aes.h" -#include "mbedtls/base64.h" -#endif - -#ifdef USE_ESP_IDF -#define MBEDTLS_AES_ALT -#include -#endif - namespace esphome { namespace ble_presence { @@ -72,7 +62,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff, } break; case MATCH_BY_IRK: - if (resolve_irk_(device.address_uint64(), this->irk_)) { + if (device.resolve_irk(this->irk_)) { this->set_found_(true); return true; } @@ -142,43 +132,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff, bool check_ibeacon_minor_{false}; bool check_minimum_rssi_{false}; - bool resolve_irk_(uint64_t addr64, const uint8_t *irk) { - uint8_t ecb_key[16]; - uint8_t ecb_plaintext[16]; - uint8_t ecb_ciphertext[16]; - - memcpy(&ecb_key, irk, 16); - memset(&ecb_plaintext, 0, 16); - - ecb_plaintext[13] = (addr64 >> 40) & 0xff; - ecb_plaintext[14] = (addr64 >> 32) & 0xff; - ecb_plaintext[15] = (addr64 >> 24) & 0xff; - - mbedtls_aes_context ctx = {0, 0, {0}}; - mbedtls_aes_init(&ctx); - - if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) { - mbedtls_aes_free(&ctx); - return false; - } - - if (mbedtls_aes_crypt_ecb(&ctx, -#ifdef USE_ARDUINO - MBEDTLS_AES_ENCRYPT, -#elif defined(USE_ESP_IDF) - ESP_AES_ENCRYPT, -#endif - ecb_plaintext, ecb_ciphertext) != 0) { - mbedtls_aes_free(&ctx); - return false; - } - - mbedtls_aes_free(&ctx); - - return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) && - ecb_ciphertext[13] == ((addr64 >> 16) & 0xff); - } - bool found_{false}; uint32_t last_seen_{}; uint32_t timeout_{}; diff --git a/esphome/components/ble_rssi/ble_rssi_sensor.h b/esphome/components/ble_rssi/ble_rssi_sensor.h index 79aebce7d3..89e4f33aca 100644 --- a/esphome/components/ble_rssi/ble_rssi_sensor.h +++ b/esphome/components/ble_rssi/ble_rssi_sensor.h @@ -15,6 +15,10 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi this->match_by_ = MATCH_BY_MAC_ADDRESS; this->address_ = address; } + void set_irk(uint8_t *irk) { + this->match_by_ = MATCH_BY_IRK; + this->irk_ = irk; + } void set_service_uuid16(uint16_t uuid) { this->match_by_ = MATCH_BY_SERVICE_UUID; this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid); @@ -53,6 +57,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi return true; } break; + case MATCH_BY_IRK: + if (device.resolve_irk(this->irk_)) { + this->publish_state(device.get_rssi()); + this->found_ = true; + return true; + } + break; case MATCH_BY_SERVICE_UUID: for (auto uuid : device.get_service_uuids()) { if (this->uuid_ == uuid) { @@ -91,12 +102,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi float get_setup_priority() const override { return setup_priority::DATA; } protected: - enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; + enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; MatchType match_by_; bool found_{false}; uint64_t address_; + uint8_t *irk_; esp32_ble_tracker::ESPBTUUID uuid_; diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 4246d311ab..0543eb0578 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -12,6 +12,8 @@ from esphome.const import ( UNIT_DECIBEL_MILLIWATT, ) +CONF_IRK = "irk" + DEPENDENCIES = ["esp32_ble_tracker"] ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi") @@ -39,6 +41,7 @@ CONFIG_SCHEMA = cv.All( .extend( { cv.Optional(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_IRK): cv.uuid, cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, @@ -47,7 +50,9 @@ CONFIG_SCHEMA = cv.All( ) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) .extend(cv.COMPONENT_SCHEMA), - cv.has_exactly_one_key(CONF_MAC_ADDRESS, CONF_SERVICE_UUID, CONF_IBEACON_UUID), + cv.has_exactly_one_key( + CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID + ), _validate, ) @@ -60,6 +65,10 @@ async def to_code(config): if mac_address := config.get(CONF_MAC_ADDRESS): cg.add(var.set_address(mac_address.as_hex)) + if irk := config.get(CONF_IRK): + irk = esp32_ble_tracker.as_hex_array(str(irk)) + cg.add(var.set_irk(irk)) + if service_uuid := config.get(CONF_SERVICE_UUID): if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format): cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid))) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index a5209c764a..4ae7929ded 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -25,6 +25,9 @@ #include #endif +#define MBEDTLS_AES_ALT +#include + // bt_trace.h #undef TAG @@ -692,6 +695,39 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) { } } +bool ESPBTDevice::resolve_irk(const uint8_t *irk) const { + uint8_t ecb_key[16]; + uint8_t ecb_plaintext[16]; + uint8_t ecb_ciphertext[16]; + + uint64_t addr64 = esp32_ble::ble_addr_to_uint64(this->address_); + + memcpy(&ecb_key, irk, 16); + memset(&ecb_plaintext, 0, 16); + + ecb_plaintext[13] = (addr64 >> 40) & 0xff; + ecb_plaintext[14] = (addr64 >> 32) & 0xff; + ecb_plaintext[15] = (addr64 >> 24) & 0xff; + + mbedtls_aes_context ctx = {0, 0, {0}}; + mbedtls_aes_init(&ctx); + + if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) { + mbedtls_aes_free(&ctx); + return false; + } + + if (mbedtls_aes_crypt_ecb(&ctx, ESP_AES_ENCRYPT, ecb_plaintext, ecb_ciphertext) != 0) { + mbedtls_aes_free(&ctx); + return false; + } + + mbedtls_aes_free(&ctx); + + return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) && + ecb_ciphertext[13] == ((addr64 >> 16) & 0xff); +} + } // namespace esp32_ble_tracker } // namespace esphome diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 76dee875c5..3db7a54f6e 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -86,6 +86,8 @@ class ESPBTDevice { const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &get_scan_result() const { return scan_result_; } + bool resolve_irk(const uint8_t *irk) const; + optional get_ibeacon() const { for (auto &it : this->manufacturer_datas_) { auto res = ESPBLEiBeacon::from_manufacturer_data(it); diff --git a/tests/components/ble_rssi/common.yaml b/tests/components/ble_rssi/common.yaml index 52e5b865c6..43bed1d0e7 100644 --- a/tests/components/ble_rssi/common.yaml +++ b/tests/components/ble_rssi/common.yaml @@ -16,3 +16,6 @@ sensor: - platform: ble_rssi service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 name: BLE Test iBeacon UUID + - platform: ble_rssi + irk: 1234567890abcdef1234567890abcdef + name: "BLE Tracker with Identity Resolving Key" From afe81184a8ab3a742d52cd25e09c393313277ae7 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 9 May 2024 13:08:30 +1000 Subject: [PATCH 1702/2607] [core] Ensure that a generated ID name is distinct from its type. (#6706) --- esphome/core/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 58ae23e139..f25891965a 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -340,6 +340,8 @@ class ID: if self.id is None: base = str(self.type).replace("::", "_").lower() + if base == self.type: + base = base + "_id" name = "".join(c for c in base if c.isalnum() or c == "_") used = set(registered_ids) | set(RESERVED_IDS) | CORE.loaded_integrations self.id = ensure_unique_string(name, used) From 5956bebcb782a7c4adc45cc6f4049effb82137ac Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 9 May 2024 13:14:31 +1000 Subject: [PATCH 1703/2607] [color] Fix crash when hex color parses as int, improve error reporting. (#6707) --- esphome/components/color/__init__.py | 40 +++++++++++++++++++++------- tests/components/color/common.yaml | 9 +++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 4a55beef38..609d416a0b 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -14,15 +14,41 @@ CONF_HEX = "hex" def hex_color(value): + if isinstance(value, int): + value = str(value) + if not isinstance(value, str): + raise cv.Invalid("Invalid value for hex color") if len(value) != 6: - raise cv.Invalid("Color must have six digits") + raise cv.Invalid("Hex color must have six digits") try: - return (int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16)) + return int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16) except ValueError as exc: raise cv.Invalid("Color must be hexadecimal") from exc -CONFIG_SCHEMA = cv.Any( +components = { + CONF_RED, + CONF_RED_INT, + CONF_GREEN, + CONF_GREEN_INT, + CONF_BLUE, + CONF_BLUE_INT, + CONF_WHITE, + CONF_WHITE_INT, +} + + +def validate_color(config): + has_components = set(config) & components + has_hex = CONF_HEX in config + if has_hex and has_components: + raise cv.Invalid("Hex color value may not be combined with component values") + if not has_hex and not has_components: + raise cv.Invalid("Must provide at least one color option") + return config + + +CONFIG_SCHEMA = cv.All( cv.Schema( { cv.Required(CONF_ID): cv.declare_id(ColorStruct), @@ -34,14 +60,10 @@ CONFIG_SCHEMA = cv.Any( cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t, cv.Exclusive(CONF_WHITE, "white"): cv.percentage, cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t, + cv.Optional(CONF_HEX): hex_color, } ).extend(cv.COMPONENT_SCHEMA), - cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(ColorStruct), - cv.Required(CONF_HEX): hex_color, - } - ).extend(cv.COMPONENT_SCHEMA), + validate_color, ) diff --git a/tests/components/color/common.yaml b/tests/components/color/common.yaml index 7aa308bb63..88524e6a5f 100644 --- a/tests/components/color/common.yaml +++ b/tests/components/color/common.yaml @@ -9,3 +9,12 @@ color: blue: 100% - id: kbx_green hex: "3DEC55" + - id: kbx_green_1 + hex: 3DEC55 + - id: cps_red + hex: 800000 + - id: cps_green + hex: 008000 + - id: cps_blue + hex: 000080 + From 78d1a50853b6d0cc62927e604f883f9a8fb7574f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 21:25:48 +1200 Subject: [PATCH 1704/2607] [github] Fix digest artifact name (#6710) --- .github/workflows/release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5002f041e1..03ed523e1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -132,10 +132,16 @@ jobs: suffix: lint version: ${{ needs.init.outputs.tag }} + - name: Sanitize platform name + id: sanitize + run: | + echo "${{ matrix.platform }}" | sed 's|/|-|g' > /tmp/platform + echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT + - name: Upload digests uses: actions/upload-artifact@v4.3.3 with: - name: digests-${{ matrix.platform }} + name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests retention-days: 1 From 26048d18ef3a674847d9b14b6f396b57949b7279 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 9 May 2024 13:08:30 +1000 Subject: [PATCH 1705/2607] [core] Ensure that a generated ID name is distinct from its type. (#6706) --- esphome/core/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 58ae23e139..f25891965a 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -340,6 +340,8 @@ class ID: if self.id is None: base = str(self.type).replace("::", "_").lower() + if base == self.type: + base = base + "_id" name = "".join(c for c in base if c.isalnum() or c == "_") used = set(registered_ids) | set(RESERVED_IDS) | CORE.loaded_integrations self.id = ensure_unique_string(name, used) From 819bb9f8bc82603e370a3e94bfdb47fbb1bdb9f2 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 9 May 2024 13:14:31 +1000 Subject: [PATCH 1706/2607] [color] Fix crash when hex color parses as int, improve error reporting. (#6707) --- esphome/components/color/__init__.py | 40 +++++++++++++++++++++------- tests/components/color/common.yaml | 9 +++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 4a55beef38..609d416a0b 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -14,15 +14,41 @@ CONF_HEX = "hex" def hex_color(value): + if isinstance(value, int): + value = str(value) + if not isinstance(value, str): + raise cv.Invalid("Invalid value for hex color") if len(value) != 6: - raise cv.Invalid("Color must have six digits") + raise cv.Invalid("Hex color must have six digits") try: - return (int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16)) + return int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16) except ValueError as exc: raise cv.Invalid("Color must be hexadecimal") from exc -CONFIG_SCHEMA = cv.Any( +components = { + CONF_RED, + CONF_RED_INT, + CONF_GREEN, + CONF_GREEN_INT, + CONF_BLUE, + CONF_BLUE_INT, + CONF_WHITE, + CONF_WHITE_INT, +} + + +def validate_color(config): + has_components = set(config) & components + has_hex = CONF_HEX in config + if has_hex and has_components: + raise cv.Invalid("Hex color value may not be combined with component values") + if not has_hex and not has_components: + raise cv.Invalid("Must provide at least one color option") + return config + + +CONFIG_SCHEMA = cv.All( cv.Schema( { cv.Required(CONF_ID): cv.declare_id(ColorStruct), @@ -34,14 +60,10 @@ CONFIG_SCHEMA = cv.Any( cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t, cv.Exclusive(CONF_WHITE, "white"): cv.percentage, cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t, + cv.Optional(CONF_HEX): hex_color, } ).extend(cv.COMPONENT_SCHEMA), - cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(ColorStruct), - cv.Required(CONF_HEX): hex_color, - } - ).extend(cv.COMPONENT_SCHEMA), + validate_color, ) diff --git a/tests/components/color/common.yaml b/tests/components/color/common.yaml index 7aa308bb63..88524e6a5f 100644 --- a/tests/components/color/common.yaml +++ b/tests/components/color/common.yaml @@ -9,3 +9,12 @@ color: blue: 100% - id: kbx_green hex: "3DEC55" + - id: kbx_green_1 + hex: 3DEC55 + - id: cps_red + hex: 800000 + - id: cps_green + hex: 008000 + - id: cps_blue + hex: 000080 + From bd776baf8dfddac65590162f10375604a60e3a07 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 21:25:48 +1200 Subject: [PATCH 1707/2607] [github] Fix digest artifact name (#6710) --- .github/workflows/release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5002f041e1..03ed523e1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -132,10 +132,16 @@ jobs: suffix: lint version: ${{ needs.init.outputs.tag }} + - name: Sanitize platform name + id: sanitize + run: | + echo "${{ matrix.platform }}" | sed 's|/|-|g' > /tmp/platform + echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT + - name: Upload digests uses: actions/upload-artifact@v4.3.3 with: - name: digests-${{ matrix.platform }} + name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests retention-days: 1 From 8ae8cd1168bcdac80bb4de76255c6b2894179e07 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 May 2024 21:55:34 +1200 Subject: [PATCH 1708/2607] Bump version to 2024.5.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 46fc5fc20b..6e00c1bbe1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b2" +__version__ = "2024.5.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 8280772b9151e71ef544ee8e849285536ee2bcdb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 10 May 2024 10:57:47 +1200 Subject: [PATCH 1709/2607] Add new Error type to skip prepending path (#6716) --- esphome/config.py | 2 ++ esphome/config_validation.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/esphome/config.py b/esphome/config.py index 36a81f677b..4f340225fe 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -148,6 +148,8 @@ class Config(OrderedDict, fv.FinalValidateConfig): path = path or [] try: yield + except cv.FinalExternalInvalid as e: + self.add_error(e) except vol.Invalid as e: e.prepend(path) self.add_error(e) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 512f1d8f67..5fc72921e1 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -267,6 +267,10 @@ class Required(vol.Required): super().__init__(key, msg=msg) +class FinalExternalInvalid(Invalid): + """Represents an invalid value in the final validation phase where the path should not be prepended.""" + + def check_not_templatable(value): if isinstance(value, Lambda): raise Invalid("This option is not templatable!") From ca5050d4a51a6e8dc136a7051d08d4ae3494b038 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 10 May 2024 11:04:32 +1200 Subject: [PATCH 1710/2607] [github] Only save platformio cache for dev branch (#6711) --- .github/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fbebc55676..ba0a8a363c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -364,12 +364,20 @@ jobs: with: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} + - name: Cache platformio + if: github.ref == 'refs/heads/dev' uses: actions/cache@v4.0.2 with: path: ~/.platformio - # yamllint disable-line rule:line-length - key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} + key: platformio-${{ matrix.pio_cache_key }} + + - name: Cache platformio + if: github.ref != 'refs/heads/dev' + uses: actions/cache/restore@v4.0.2 + with: + path: ~/.platformio + key: platformio-${{ matrix.pio_cache_key }} - name: Install clang-tidy run: sudo apt-get install clang-tidy-14 From 47a1710b1ed9da2304d0f17454f0b578d8d1554c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 10 May 2024 11:55:35 +1200 Subject: [PATCH 1711/2607] Only cache docker images on dev branch (#6714) --- .github/actions/build-image/action.yaml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 87ea28fd20..d36bd65bb6 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -34,6 +34,16 @@ runs: echo $l >> $GITHUB_OUTPUT done + # set cache-to only if dev branch + - id: cache-to + shell: bash + run: |- + if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then + echo "value=type=gha,mode=max" >> $GITHUB_OUTPUT + else + echo "value=" >> $GITHUB_OUTPUT + fi + - name: Build and push to ghcr by digest id: build-ghcr uses: docker/build-push-action@v5.3.0 @@ -43,7 +53,7 @@ runs: platforms: ${{ inputs.platform }} target: ${{ inputs.target }} cache-from: type=gha - cache-to: type=gha,mode=max + cache-to: ${{ steps.cache-to.outputs.value }} build-args: | BASEIMGTYPE=${{ inputs.baseimg }} BUILD_VERSION=${{ inputs.version }} @@ -66,7 +76,7 @@ runs: platforms: ${{ inputs.platform }} target: ${{ inputs.target }} cache-from: type=gha - cache-to: type=gha,mode=max + cache-to: ${{ steps.cache-to.outputs.value }} build-args: | BASEIMGTYPE=${{ inputs.baseimg }} BUILD_VERSION=${{ inputs.version }} From 1a458589041e2df1ba1b8a8ed9e128627b4ea036 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 13 May 2024 07:56:55 +1000 Subject: [PATCH 1712/2607] Add pylint to git pre-commit hooks (#6726) --- .pre-commit-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f4bb52104..ce226846e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,3 +40,10 @@ repos: hooks: - id: clang-format types_or: [c, c++] + - repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] From 61b65e2726485ea4d12fc5f47de1e614236fa182 Mon Sep 17 00:00:00 2001 From: Marcin Krasowski Date: Mon, 13 May 2024 01:25:41 +0200 Subject: [PATCH 1713/2607] fix(ltr390): stuck ALS values when configured for ALS+UV readings (#6723) --- esphome/components/ltr390/ltr390.cpp | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 65c08ab614..4eb1ff2c46 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -8,6 +8,9 @@ namespace ltr390 { static const char *const TAG = "ltr390"; +static const uint8_t LTR390_WAKEUP_TIME = 10; +static const uint8_t LTR390_SETTLE_TIME = 5; + static const uint8_t LTR390_MAIN_CTRL = 0x00; static const uint8_t LTR390_MEAS_RATE = 0x04; static const uint8_t LTR390_GAIN = 0x05; @@ -101,21 +104,27 @@ void LTR390Component::read_mode_(int mode_index) { std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); ctrl[LTR390_CTRL_MODE] = mode; + ctrl[LTR390_CTRL_EN] = true; this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); // After the sensor integration time do the following - this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100, [this, mode_index]() { - // Read from the sensor - std::get<1>(this->mode_funcs_[mode_index])(); + this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, + [this, mode_index]() { + // Read from the sensor + std::get<1>(this->mode_funcs_[mode_index])(); - // If there are more modes to read then begin the next - // otherwise stop - if (mode_index + 1 < (int) this->mode_funcs_.size()) { - this->read_mode_(mode_index + 1); - } else { - this->reading_ = false; - } - }); + // If there are more modes to read then begin the next + // otherwise stop + if (mode_index + 1 < (int) this->mode_funcs_.size()) { + this->read_mode_(mode_index + 1); + } else { + // put sensor in standby + std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); + ctrl[LTR390_CTRL_EN] = false; + this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); + this->reading_ = false; + } + }); } void LTR390Component::setup() { From 67ca60e2afa118818a97c12246a1b751b16a2cf4 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 13 May 2024 01:54:43 +0200 Subject: [PATCH 1714/2607] separate debug component for each platform in different file (#6715) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/debug/debug_component.cpp | 374 +------------------ esphome/components/debug/debug_component.h | 5 + esphome/components/debug/debug_esp32.cpp | 287 ++++++++++++++ esphome/components/debug/debug_esp8266.cpp | 94 +++++ esphome/components/debug/debug_host.cpp | 18 + esphome/components/debug/debug_libretiny.cpp | 44 +++ esphome/components/debug/debug_rp2040.cpp | 23 ++ 7 files changed, 479 insertions(+), 366 deletions(-) create mode 100644 esphome/components/debug/debug_esp32.cpp create mode 100644 esphome/components/debug/debug_esp8266.cpp create mode 100644 esphome/components/debug/debug_host.cpp create mode 100644 esphome/components/debug/debug_libretiny.cpp create mode 100644 esphome/components/debug/debug_rp2040.cpp diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index f22a8a2e5d..cbd4249d92 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -8,62 +8,16 @@ #include #include -#ifdef USE_ESP32 - -#include -#include - -#include -#if defined(USE_ESP32_VARIANT_ESP32) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C3) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C6) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S2) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S3) -#include -#endif - -#endif // USE_ESP32 - -#ifdef USE_ARDUINO -#ifdef USE_RP2040 -#include -#elif defined(USE_ESP32) || defined(USE_ESP8266) -#include -#endif -#endif - namespace esphome { namespace debug { static const char *const TAG = "debug"; -static uint32_t get_free_heap() { -#if defined(USE_ESP8266) - return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) -#elif defined(USE_ESP32) - return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); -#elif defined(USE_RP2040) - return rp2040.getFreeHeap(); -#elif defined(USE_LIBRETINY) - return lt_heap_get_free(); -#elif defined(USE_HOST) - return INT_MAX; -#endif -} - void DebugComponent::dump_config() { #ifndef ESPHOME_LOG_HAS_DEBUG return; // Can't log below if debug logging is disabled #endif - std::string device_info; - std::string reset_reason; - device_info.reserve(256); - ESP_LOGCONFIG(TAG, "Debug component:"); #ifdef USE_TEXT_SENSOR LOG_TEXT_SENSOR(" ", "Device info", this->device_info_); @@ -76,305 +30,15 @@ void DebugComponent::dump_config() { #endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) #endif // USE_SENSOR + std::string device_info; + device_info.reserve(256); ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION); device_info += ESPHOME_VERSION; - this->free_heap_ = get_free_heap(); + this->free_heap_ = get_free_heap_(); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); -#if defined(USE_ARDUINO) && (defined(USE_ESP32) || defined(USE_ESP8266)) - const char *flash_mode; - switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) - case FM_QIO: - flash_mode = "QIO"; - break; - case FM_QOUT: - flash_mode = "QOUT"; - break; - case FM_DIO: - flash_mode = "DIO"; - break; - case FM_DOUT: - flash_mode = "DOUT"; - break; -#ifdef USE_ESP32 - case FM_FAST_READ: - flash_mode = "FAST_READ"; - break; - case FM_SLOW_READ: - flash_mode = "SLOW_READ"; - break; -#endif - default: - flash_mode = "UNKNOWN"; - } - ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", - ESP.getFlashChipSize() / 1024, // NOLINT - ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT - device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT - "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT - device_info += flash_mode; -#endif // USE_ARDUINO && (USE_ESP32 || USE_ESP8266) - -#ifdef USE_ESP32 - esp_chip_info_t info; - esp_chip_info(&info); - const char *model; -#if defined(USE_ESP32_VARIANT_ESP32) - model = "ESP32"; -#elif defined(USE_ESP32_VARIANT_ESP32C3) - model = "ESP32-C3"; -#elif defined(USE_ESP32_VARIANT_ESP32C6) - model = "ESP32-C6"; -#elif defined(USE_ESP32_VARIANT_ESP32S2) - model = "ESP32-S2"; -#elif defined(USE_ESP32_VARIANT_ESP32S3) - model = "ESP32-S3"; -#elif defined(USE_ESP32_VARIANT_ESP32H2) - model = "ESP32-H2"; -#else - model = "UNKNOWN"; -#endif - std::string features; - if (info.features & CHIP_FEATURE_EMB_FLASH) { - features += "EMB_FLASH,"; - info.features &= ~CHIP_FEATURE_EMB_FLASH; - } - if (info.features & CHIP_FEATURE_WIFI_BGN) { - features += "WIFI_BGN,"; - info.features &= ~CHIP_FEATURE_WIFI_BGN; - } - if (info.features & CHIP_FEATURE_BLE) { - features += "BLE,"; - info.features &= ~CHIP_FEATURE_BLE; - } - if (info.features & CHIP_FEATURE_BT) { - features += "BT,"; - info.features &= ~CHIP_FEATURE_BT; - } - if (info.features & CHIP_FEATURE_EMB_PSRAM) { - features += "EMB_PSRAM,"; - info.features &= ~CHIP_FEATURE_EMB_PSRAM; - } - if (info.features) - features += "Other:" + format_hex(info.features); - ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, - info.revision); - device_info += "|Chip: "; - device_info += model; - device_info += " Features:"; - device_info += features; - device_info += " Cores:" + to_string(info.cores); - device_info += " Revision:" + to_string(info.revision); - - ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); - device_info += "|ESP-IDF: "; - device_info += esp_get_idf_version(); - - std::string mac = get_mac_address_pretty(); - ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); - device_info += "|EFuse MAC: "; - device_info += mac; - - switch (rtc_get_reset_reason(0)) { - case POWERON_RESET: - reset_reason = "Power On Reset"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case RTC_SW_SYS_RESET: -#endif - reset_reason = "Software Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case OWDT_RESET: - reset_reason = "Watch Dog Reset Digital Core"; - break; -#endif - case DEEPSLEEP_RESET: - reset_reason = "Deep Sleep Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SDIO_RESET: - reset_reason = "SLC Module Reset Digital Core"; - break; -#endif - case TG0WDT_SYS_RESET: - reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; - break; - case TG1WDT_SYS_RESET: - reset_reason = "Timer Group 1 Watch Dog Reset Digital Core"; - break; - case RTCWDT_SYS_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core"; - break; -#if !defined(USE_ESP32_VARIANT_ESP32C6) - case INTRUSION_RESET: - reset_reason = "Intrusion Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case TGWDT_CPU_RESET: - reset_reason = "Timer Group Reset CPU"; - break; -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case TG0WDT_CPU_RESET: - reset_reason = "Timer Group 0 Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_CPU_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case RTC_SW_CPU_RESET: -#endif - reset_reason = "Software Reset CPU"; - break; - case RTCWDT_CPU_RESET: - reset_reason = "RTC Watch Dog Reset CPU"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case EXT_CPU_RESET: - reset_reason = "External CPU Reset"; - break; -#endif - case RTCWDT_BROWN_OUT_RESET: - reset_reason = "Voltage Unstable Reset"; - break; - case RTCWDT_RTC_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; - break; -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case TG1WDT_CPU_RESET: - reset_reason = "Timer Group 1 Reset CPU"; - break; - case SUPER_WDT_RESET: - reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; - break; - case GLITCH_RTC_RESET: - reset_reason = "Glitch Reset Digital Core And RTC Module"; - break; - case EFUSE_RESET: - reset_reason = "eFuse Reset Digital Core"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) - case USB_UART_CHIP_RESET: - reset_reason = "USB UART Reset Digital Core"; - break; - case USB_JTAG_CHIP_RESET: - reset_reason = "USB JTAG Reset Digital Core"; - break; - case POWER_GLITCH_RESET: - reset_reason = "Power Glitch Reset Digital Core And RTC Module"; - break; -#endif - default: - reset_reason = "Unknown Reset Reason"; - } - ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); - device_info += "|Reset: "; - device_info += reset_reason; - - const char *wakeup_reason; - switch (rtc_get_wakeup_cause()) { - case NO_SLEEP: - wakeup_reason = "No Sleep"; - break; - case EXT_EVENT0_TRIG: - wakeup_reason = "External Event 0"; - break; - case EXT_EVENT1_TRIG: - wakeup_reason = "External Event 1"; - break; - case GPIO_TRIG: - wakeup_reason = "GPIO"; - break; - case TIMER_EXPIRE: - wakeup_reason = "Wakeup Timer"; - break; - case SDIO_TRIG: - wakeup_reason = "SDIO"; - break; - case MAC_TRIG: - wakeup_reason = "MAC"; - break; - case UART0_TRIG: - wakeup_reason = "UART0"; - break; - case UART1_TRIG: - wakeup_reason = "UART1"; - break; - case TOUCH_TRIG: - wakeup_reason = "Touch"; - break; - case SAR_TRIG: - wakeup_reason = "SAR"; - break; - case BT_TRIG: - wakeup_reason = "BT"; - break; - default: - wakeup_reason = "Unknown"; - } - ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); - device_info += "|Wakeup: "; - device_info += wakeup_reason; -#endif - -#if defined(USE_ESP8266) && !defined(CLANG_TIDY) - ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId()); - ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion()); - ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str()); - ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode()); - ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz()); - ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId()); - ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str()); - ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str()); - - device_info += "|Chip: 0x" + format_hex(ESP.getChipId()); - device_info += "|SDK: "; - device_info += ESP.getSdkVersion(); - device_info += "|Core: "; - device_info += ESP.getCoreVersion().c_str(); - device_info += "|Boot: "; - device_info += to_string(ESP.getBootVersion()); - device_info += "|Mode: " + to_string(ESP.getBootMode()); - device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz()); - device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId()); - device_info += "|Reset: "; - device_info += ESP.getResetReason().c_str(); - device_info += "|"; - device_info += ESP.getResetInfo().c_str(); - - reset_reason = ESP.getResetReason().c_str(); -#endif - -#ifdef USE_RP2040 - ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu()); - device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); -#endif // USE_RP2040 - -#ifdef USE_LIBRETINY - ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); - ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); - ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); - ESP_LOGD(TAG, "Board: %s", lt_get_board_code()); - ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024); - ESP_LOGD(TAG, "Reset Reason: %s", lt_get_reboot_reason_name(lt_get_reboot_reason())); - - device_info += "|Version: "; - device_info += LT_BANNER_STR + 10; - device_info += "|Reset Reason: "; - device_info += lt_get_reboot_reason_name(lt_get_reboot_reason()); - device_info += "|Chip Name: "; - device_info += lt_cpu_get_model_name(); - device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id()); - device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB"; - device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB"; - - reset_reason = lt_get_reboot_reason_name(lt_get_reboot_reason()); -#endif // USE_LIBRETINY + get_device_info_(device_info); #ifdef USE_TEXT_SENSOR if (this->device_info_ != nullptr) { @@ -383,14 +47,14 @@ void DebugComponent::dump_config() { this->device_info_->publish_state(device_info); } if (this->reset_reason_ != nullptr) { - this->reset_reason_->publish_state(reset_reason); + this->reset_reason_->publish_state(get_reset_reason_()); } #endif // USE_TEXT_SENSOR } void DebugComponent::loop() { // log when free heap space has halved - uint32_t new_free_heap = get_free_heap(); + uint32_t new_free_heap = get_free_heap_(); if (new_free_heap < this->free_heap_ / 2) { this->free_heap_ = new_free_heap; ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); @@ -411,38 +75,16 @@ void DebugComponent::loop() { void DebugComponent::update() { #ifdef USE_SENSOR if (this->free_sensor_ != nullptr) { - this->free_sensor_->publish_state(get_free_heap()); + this->free_sensor_->publish_state(get_free_heap_()); } - if (this->block_sensor_ != nullptr) { -#if defined(USE_ESP8266) - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); -#elif defined(USE_ESP32) - this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); -#elif defined(USE_LIBRETINY) - this->block_sensor_->publish_state(lt_heap_get_max_alloc()); -#endif - } - -#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) - if (this->fragmentation_sensor_ != nullptr) { - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation()); - } -#endif - if (this->loop_time_sensor_ != nullptr) { this->loop_time_sensor_->publish_state(this->max_loop_time_); this->max_loop_time_ = 0; } -#ifdef USE_ESP32 - if (this->psram_sensor_ != nullptr) { - this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); - } -#endif // USE_ESP32 #endif // USE_SENSOR + update_platform_(); } float DebugComponent::get_setup_priority() const { return setup_priority::LATE; } diff --git a/esphome/components/debug/debug_component.h b/esphome/components/debug/debug_component.h index 93e3ba4857..2b54406603 100644 --- a/esphome/components/debug/debug_component.h +++ b/esphome/components/debug/debug_component.h @@ -59,6 +59,11 @@ class DebugComponent : public PollingComponent { text_sensor::TextSensor *device_info_{nullptr}; text_sensor::TextSensor *reset_reason_{nullptr}; #endif // USE_TEXT_SENSOR + + std::string get_reset_reason_(); + uint32_t get_free_heap_(); + void get_device_info_(std::string &device_info); + void update_platform_(); }; } // namespace debug diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp new file mode 100644 index 0000000000..cfdfdd2a61 --- /dev/null +++ b/esphome/components/debug/debug_esp32.cpp @@ -0,0 +1,287 @@ +#include "debug_component.h" +#ifdef USE_ESP32 +#include "esphome/core/log.h" + +#include +#include +#include + +#if defined(USE_ESP32_VARIANT_ESP32) +#include +#elif defined(USE_ESP32_VARIANT_ESP32C3) +#include +#elif defined(USE_ESP32_VARIANT_ESP32C6) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S2) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S3) +#include +#endif +#ifdef USE_ARDUINO +#include +#endif + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { + std::string reset_reason; + switch (rtc_get_reset_reason(0)) { + case POWERON_RESET: + reset_reason = "Power On Reset"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case SW_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_SYS_RESET: +#endif + reset_reason = "Software Reset Digital Core"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case OWDT_RESET: + reset_reason = "Watch Dog Reset Digital Core"; + break; +#endif + case DEEPSLEEP_RESET: + reset_reason = "Deep Sleep Reset Digital Core"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case SDIO_RESET: + reset_reason = "SLC Module Reset Digital Core"; + break; +#endif + case TG0WDT_SYS_RESET: + reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; + break; + case TG1WDT_SYS_RESET: + reset_reason = "Timer Group 1 Watch Dog Reset Digital Core"; + break; + case RTCWDT_SYS_RESET: + reset_reason = "RTC Watch Dog Reset Digital Core"; + break; +#if !defined(USE_ESP32_VARIANT_ESP32C6) + case INTRUSION_RESET: + reset_reason = "Intrusion Reset CPU"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32) + case TGWDT_CPU_RESET: + reset_reason = "Timer Group Reset CPU"; + break; +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG0WDT_CPU_RESET: + reset_reason = "Timer Group 0 Reset CPU"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32) + case SW_CPU_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_CPU_RESET: +#endif + reset_reason = "Software Reset CPU"; + break; + case RTCWDT_CPU_RESET: + reset_reason = "RTC Watch Dog Reset CPU"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case EXT_CPU_RESET: + reset_reason = "External CPU Reset"; + break; +#endif + case RTCWDT_BROWN_OUT_RESET: + reset_reason = "Voltage Unstable Reset"; + break; + case RTCWDT_RTC_RESET: + reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; + break; +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG1WDT_CPU_RESET: + reset_reason = "Timer Group 1 Reset CPU"; + break; + case SUPER_WDT_RESET: + reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; + break; + case GLITCH_RTC_RESET: + reset_reason = "Glitch Reset Digital Core And RTC Module"; + break; + case EFUSE_RESET: + reset_reason = "eFuse Reset Digital Core"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) + case USB_UART_CHIP_RESET: + reset_reason = "USB UART Reset Digital Core"; + break; + case USB_JTAG_CHIP_RESET: + reset_reason = "USB JTAG Reset Digital Core"; + break; + case POWER_GLITCH_RESET: + reset_reason = "Power Glitch Reset Digital Core And RTC Module"; + break; +#endif + default: + reset_reason = "Unknown Reset Reason"; + } + ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); + return reset_reason; +} + +uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); } + +void DebugComponent::get_device_info_(std::string &device_info) { +#if defined(USE_ARDUINO) + const char *flash_mode; + switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) + case FM_QIO: + flash_mode = "QIO"; + break; + case FM_QOUT: + flash_mode = "QOUT"; + break; + case FM_DIO: + flash_mode = "DIO"; + break; + case FM_DOUT: + flash_mode = "DOUT"; + break; + case FM_FAST_READ: + flash_mode = "FAST_READ"; + break; + case FM_SLOW_READ: + flash_mode = "SLOW_READ"; + break; + default: + flash_mode = "UNKNOWN"; + } + ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", + ESP.getFlashChipSize() / 1024, // NOLINT + ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT + device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT + "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT + device_info += flash_mode; +#endif + + esp_chip_info_t info; + esp_chip_info(&info); + const char *model; +#if defined(USE_ESP32_VARIANT_ESP32) + model = "ESP32"; +#elif defined(USE_ESP32_VARIANT_ESP32C3) + model = "ESP32-C3"; +#elif defined(USE_ESP32_VARIANT_ESP32C6) + model = "ESP32-C6"; +#elif defined(USE_ESP32_VARIANT_ESP32S2) + model = "ESP32-S2"; +#elif defined(USE_ESP32_VARIANT_ESP32S3) + model = "ESP32-S3"; +#elif defined(USE_ESP32_VARIANT_ESP32H2) + model = "ESP32-H2"; +#else + model = "UNKNOWN"; +#endif + std::string features; + if (info.features & CHIP_FEATURE_EMB_FLASH) { + features += "EMB_FLASH,"; + info.features &= ~CHIP_FEATURE_EMB_FLASH; + } + if (info.features & CHIP_FEATURE_WIFI_BGN) { + features += "WIFI_BGN,"; + info.features &= ~CHIP_FEATURE_WIFI_BGN; + } + if (info.features & CHIP_FEATURE_BLE) { + features += "BLE,"; + info.features &= ~CHIP_FEATURE_BLE; + } + if (info.features & CHIP_FEATURE_BT) { + features += "BT,"; + info.features &= ~CHIP_FEATURE_BT; + } + if (info.features & CHIP_FEATURE_EMB_PSRAM) { + features += "EMB_PSRAM,"; + info.features &= ~CHIP_FEATURE_EMB_PSRAM; + } + if (info.features) + features += "Other:" + format_hex(info.features); + ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, + info.revision); + device_info += "|Chip: "; + device_info += model; + device_info += " Features:"; + device_info += features; + device_info += " Cores:" + to_string(info.cores); + device_info += " Revision:" + to_string(info.revision); + + ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); + device_info += "|ESP-IDF: "; + device_info += esp_get_idf_version(); + + std::string mac = get_mac_address_pretty(); + ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); + device_info += "|EFuse MAC: "; + device_info += mac; + + device_info += "|Reset: "; + device_info += get_reset_reason_(); + + const char *wakeup_reason; + switch (rtc_get_wakeup_cause()) { + case NO_SLEEP: + wakeup_reason = "No Sleep"; + break; + case EXT_EVENT0_TRIG: + wakeup_reason = "External Event 0"; + break; + case EXT_EVENT1_TRIG: + wakeup_reason = "External Event 1"; + break; + case GPIO_TRIG: + wakeup_reason = "GPIO"; + break; + case TIMER_EXPIRE: + wakeup_reason = "Wakeup Timer"; + break; + case SDIO_TRIG: + wakeup_reason = "SDIO"; + break; + case MAC_TRIG: + wakeup_reason = "MAC"; + break; + case UART0_TRIG: + wakeup_reason = "UART0"; + break; + case UART1_TRIG: + wakeup_reason = "UART1"; + break; + case TOUCH_TRIG: + wakeup_reason = "Touch"; + break; + case SAR_TRIG: + wakeup_reason = "SAR"; + break; + case BT_TRIG: + wakeup_reason = "BT"; + break; + default: + wakeup_reason = "Unknown"; + } + ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); + device_info += "|Wakeup: "; + device_info += wakeup_reason; +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); + } + if (this->psram_sensor_ != nullptr) { + this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + } +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_esp8266.cpp b/esphome/components/debug/debug_esp8266.cpp new file mode 100644 index 0000000000..3395d9db12 --- /dev/null +++ b/esphome/components/debug/debug_esp8266.cpp @@ -0,0 +1,94 @@ +#include "debug_component.h" +#ifdef USE_ESP8266 +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { +#if !defined(CLANG_TIDY) + return ESP.getResetReason().c_str(); +#else + return ""; +#endif +} + +uint32_t DebugComponent::get_free_heap_() { + return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) +} + +void DebugComponent::get_device_info_(std::string &device_info) { + const char *flash_mode; + switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) + case FM_QIO: + flash_mode = "QIO"; + break; + case FM_QOUT: + flash_mode = "QOUT"; + break; + case FM_DIO: + flash_mode = "DIO"; + break; + case FM_DOUT: + flash_mode = "DOUT"; + break; + default: + flash_mode = "UNKNOWN"; + } + ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", + ESP.getFlashChipSize() / 1024, // NOLINT + ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT + device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT + "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT + device_info += flash_mode; + +#if !defined(CLANG_TIDY) + auto reset_reason = get_reset_reason_(); + ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId()); + ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion()); + ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str()); + ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode()); + ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz()); + ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId()); + ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); + ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str()); + + device_info += "|Chip: 0x" + format_hex(ESP.getChipId()); + device_info += "|SDK: "; + device_info += ESP.getSdkVersion(); + device_info += "|Core: "; + device_info += ESP.getCoreVersion().c_str(); + device_info += "|Boot: "; + device_info += to_string(ESP.getBootVersion()); + device_info += "|Mode: " + to_string(ESP.getBootMode()); + device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz()); + device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId()); + device_info += "|Reset: "; + device_info += reset_reason; + device_info += "|"; + device_info += ESP.getResetInfo().c_str(); +#endif +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); + } +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) + if (this->fragmentation_sensor_ != nullptr) { + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation()); + } +#endif + +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_host.cpp b/esphome/components/debug/debug_host.cpp new file mode 100644 index 0000000000..09ad34ef88 --- /dev/null +++ b/esphome/components/debug/debug_host.cpp @@ -0,0 +1,18 @@ +#include "debug_component.h" +#ifdef USE_HOST +#include + +namespace esphome { +namespace debug { + +std::string DebugComponent::get_reset_reason_() { return ""; } + +uint32_t DebugComponent::get_free_heap_() { return INT_MAX; } + +void DebugComponent::get_device_info_(std::string &device_info) {} + +void DebugComponent::update_platform_() {} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp new file mode 100644 index 0000000000..725cd870ca --- /dev/null +++ b/esphome/components/debug/debug_libretiny.cpp @@ -0,0 +1,44 @@ +#include "debug_component.h" +#ifdef USE_LIBRETINY +#include "esphome/core/log.h" + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_name(lt_get_reboot_reason()); } + +uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } + +void DebugComponent::get_device_info_(std::string &device_info) { + reset_reason = get_reset_reason_(); + ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); + ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); + ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); + ESP_LOGD(TAG, "Board: %s", lt_get_board_code()); + ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024); + ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); + + device_info += "|Version: "; + device_info += LT_BANNER_STR + 10; + device_info += "|Reset Reason: "; + device_info += reset_reason; + device_info += "|Chip Name: "; + device_info += lt_cpu_get_model_name(); + device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id()); + device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB"; + device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB"; +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + this->block_sensor_->publish_state(lt_heap_get_max_alloc()); + } +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_rp2040.cpp b/esphome/components/debug/debug_rp2040.cpp new file mode 100644 index 0000000000..497547e30d --- /dev/null +++ b/esphome/components/debug/debug_rp2040.cpp @@ -0,0 +1,23 @@ +#include "debug_component.h" +#ifdef USE_RP2040 +#include "esphome/core/log.h" +#include +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { return ""; } + +uint32_t DebugComponent::get_free_heap_() { return rp2040.getFreeHeap(); } + +void DebugComponent::get_device_info_(std::string &device_info) { + ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu()); + device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); +} + +void DebugComponent::update_platform_() {} + +} // namespace debug +} // namespace esphome +#endif From 13e3920c13ce8af481b0e89d61703e61051a0b0d Mon Sep 17 00:00:00 2001 From: Szewcson Date: Mon, 13 May 2024 03:36:10 +0200 Subject: [PATCH 1715/2607] GDK101 support (#4703) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/gdk101/__init__.py | 32 ++++ esphome/components/gdk101/binary_sensor.py | 29 +++ esphome/components/gdk101/gdk101.cpp | 189 ++++++++++++++++++++ esphome/components/gdk101/gdk101.h | 52 ++++++ esphome/components/gdk101/sensor.py | 83 +++++++++ esphome/const.py | 3 + tests/components/gdk101/common.yaml | 28 +++ tests/components/gdk101/test.esp32-idf.yaml | 5 + tests/components/gdk101/test.esp32.yaml | 5 + tests/components/gdk101/test.esp8266.yaml | 5 + tests/components/gdk101/test.rp2040.yaml | 5 + 12 files changed, 437 insertions(+) create mode 100644 esphome/components/gdk101/__init__.py create mode 100644 esphome/components/gdk101/binary_sensor.py create mode 100644 esphome/components/gdk101/gdk101.cpp create mode 100644 esphome/components/gdk101/gdk101.h create mode 100644 esphome/components/gdk101/sensor.py create mode 100644 tests/components/gdk101/common.yaml create mode 100644 tests/components/gdk101/test.esp32-idf.yaml create mode 100644 tests/components/gdk101/test.esp32.yaml create mode 100644 tests/components/gdk101/test.esp8266.yaml create mode 100644 tests/components/gdk101/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c630db7948..88f875f368 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -135,6 +135,7 @@ esphome/components/fs3000/* @kahrendt esphome/components/ft5x06/* @clydebarrow esphome/components/ft63x6/* @gpambrozio esphome/components/gcja5/* @gcormier +esphome/components/gdk101/* @Szewcson esphome/components/globals/* @esphome/core esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core diff --git a/esphome/components/gdk101/__init__.py b/esphome/components/gdk101/__init__.py new file mode 100644 index 0000000000..0d90257964 --- /dev/null +++ b/esphome/components/gdk101/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from esphome.const import CONF_ID + +CODEOWNERS = ["@Szewcson"] + +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + +CONF_GDK101_ID = "gdk101_id" + +gdk101_ns = cg.esphome_ns.namespace("gdk101") +GDK101Component = gdk101_ns.class_( + "GDK101Component", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(GDK101Component), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x18)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/gdk101/binary_sensor.py b/esphome/components/gdk101/binary_sensor.py new file mode 100644 index 0000000000..2a3d6f07eb --- /dev/null +++ b/esphome/components/gdk101/binary_sensor.py @@ -0,0 +1,29 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import ( + CONF_VIBRATIONS, + DEVICE_CLASS_VIBRATION, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_VIBRATE, +) +from . import CONF_GDK101_ID, GDK101Component + +DEPENDENCIES = ["gdk101"] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_GDK101_ID): cv.use_id(GDK101Component), + cv.Required(CONF_VIBRATIONS): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_VIBRATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_VIBRATE, + ), + } +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_GDK101_ID]) + var = await binary_sensor.new_binary_sensor(config[CONF_VIBRATIONS]) + cg.add(hub.set_vibration_binary_sensor(var)) diff --git a/esphome/components/gdk101/gdk101.cpp b/esphome/components/gdk101/gdk101.cpp new file mode 100644 index 0000000000..93f3c20fa8 --- /dev/null +++ b/esphome/components/gdk101/gdk101.cpp @@ -0,0 +1,189 @@ +#include "gdk101.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace gdk101 { + +static const char *const TAG = "gdk101"; +static const uint8_t NUMBER_OF_READ_RETRIES = 5; + +void GDK101Component::update() { + uint8_t data[2]; + if (!this->read_dose_1m_(data)) { + this->status_set_warning("Failed to read dose 1m"); + return; + } + + if (!this->read_dose_10m_(data)) { + this->status_set_warning("Failed to read dose 10m"); + return; + } + + if (!this->read_status_(data)) { + this->status_set_warning("Failed to read status"); + return; + } + + if (!this->read_measurement_duration_(data)) { + this->status_set_warning("Failed to read measurement duration"); + return; + } + this->status_clear_warning(); +} + +void GDK101Component::setup() { + uint8_t data[2]; + ESP_LOGCONFIG(TAG, "Setting up GDK101..."); + // first, reset the sensor + if (!this->reset_sensor_(data)) { + this->status_set_error("Reset failed!"); + this->mark_failed(); + return; + } + // sensor should acknowledge success of the reset procedure + if (data[0] != 1) { + this->status_set_error("Reset not acknowledged!"); + this->mark_failed(); + return; + } + delay(10); + // read firmware version + if (!this->read_fw_version_(data)) { + this->status_set_error("Failed to read firmware version"); + this->mark_failed(); + return; + } +} + +void GDK101Component::dump_config() { + ESP_LOGCONFIG(TAG, "GDK101:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with GDK101 failed!"); + } +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Firmware Version", this->fw_version_sensor_); + LOG_SENSOR(" ", "Average Radaition Dose per 1 minute", this->rad_1m_sensor_); + LOG_SENSOR(" ", "Average Radaition Dose per 10 minutes", this->rad_10m_sensor_); + LOG_SENSOR(" ", "Status", this->status_sensor_); + LOG_SENSOR(" ", "Measurement Duration", this->measurement_duration_sensor_); +#endif // USE_SENSOR + +#ifdef USE_BINARY_SENSOR + LOG_BINARY_SENSOR(" ", "Vibration Status", this->vibration_binary_sensor_); +#endif // USE_BINARY_SENSOR +} + +float GDK101Component::get_setup_priority() const { return setup_priority::DATA; } + +bool GDK101Component::read_bytes_with_retry_(uint8_t a_register, uint8_t *data, uint8_t len) { + uint8_t retry = NUMBER_OF_READ_RETRIES; + bool status = false; + while (!status && retry) { + status = this->read_bytes(a_register, data, len); + retry--; + } + return status; +} + +bool GDK101Component::reset_sensor_(uint8_t *data) { + // It looks like reset is not so well designed in that sensor + // After sending reset command it looks that sensor start performing reset and is unresponsible during read + // after a while we can send another reset command and read "0x01" as confirmation + // Documentation not going in to such details unfortunately + if (!this->read_bytes_with_retry_(GDK101_REG_RESET, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + return true; +} + +bool GDK101Component::read_dose_1m_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->rad_1m_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_1MIN_AVG, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float dose = data[0] + (data[1] / 100.0f); + + this->rad_1m_sensor_->publish_state(dose); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_dose_10m_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->rad_10m_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_10MIN_AVG, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float dose = data[0] + (data[1] / 100.0f); + + this->rad_10m_sensor_->publish_state(dose); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_status_(uint8_t *data) { + if (!this->read_bytes(GDK101_REG_READ_STATUS, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + +#ifdef USE_SENSOR + if (this->status_sensor_ != nullptr) { + this->status_sensor_->publish_state(data[0]); + } +#endif // USE_SENSOR + +#ifdef USE_BINARY_SENSOR + if (this->vibration_binary_sensor_ != nullptr) { + this->vibration_binary_sensor_->publish_state(data[1]); + } +#endif // USE_BINARY_SENSOR + + return true; +} + +bool GDK101Component::read_fw_version_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->fw_version_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_FIRMWARE, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float fw_version = data[0] + (data[1] / 10.0f); + + this->fw_version_sensor_->publish_state(fw_version); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_measurement_duration_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->measurement_duration_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_MEASURING_TIME, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float meas_time = (data[0] * 60) + data[1]; + + this->measurement_duration_sensor_->publish_state(meas_time); + } +#endif // USE_SENSOR + return true; +} + +} // namespace gdk101 +} // namespace esphome diff --git a/esphome/components/gdk101/gdk101.h b/esphome/components/gdk101/gdk101.h new file mode 100644 index 0000000000..460e72ac89 --- /dev/null +++ b/esphome/components/gdk101/gdk101.h @@ -0,0 +1,52 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif // USE_SENSOR +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif // USE_BINARY_SENSOR +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace gdk101 { + +static const uint8_t GDK101_REG_READ_FIRMWARE = 0xB4; // Firmware version +static const uint8_t GDK101_REG_RESET = 0xA0; // Reset register - reading its value triggers reset +static const uint8_t GDK101_REG_READ_STATUS = 0xB0; // Status register +static const uint8_t GDK101_REG_READ_MEASURING_TIME = 0xB1; // Mesuring time +static const uint8_t GDK101_REG_READ_10MIN_AVG = 0xB2; // Average radiation dose per 10 min +static const uint8_t GDK101_REG_READ_1MIN_AVG = 0xB3; // Average radiation dose per 1 min + +class GDK101Component : public PollingComponent, public i2c::I2CDevice { +#ifdef USE_SENSOR + SUB_SENSOR(rad_1m) + SUB_SENSOR(rad_10m) + SUB_SENSOR(status) + SUB_SENSOR(fw_version) + SUB_SENSOR(measurement_duration) +#endif // USE_SENSOR +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(vibration) +#endif // USE_BINARY_SENSOR + + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + + protected: + bool read_bytes_with_retry_(uint8_t a_register, uint8_t *data, uint8_t len); + bool reset_sensor_(uint8_t *data); + bool read_dose_1m_(uint8_t *data); + bool read_dose_10m_(uint8_t *data); + bool read_status_(uint8_t *data); + bool read_fw_version_(uint8_t *data); + bool read_measurement_duration_(uint8_t *data); +}; + +} // namespace gdk101 +} // namespace esphome diff --git a/esphome/components/gdk101/sensor.py b/esphome/components/gdk101/sensor.py new file mode 100644 index 0000000000..f782264615 --- /dev/null +++ b/esphome/components/gdk101/sensor.py @@ -0,0 +1,83 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + DEVICE_CLASS_DURATION, + DEVICE_CLASS_EMPTY, + ENTITY_CATEGORY_DIAGNOSTIC, + CONF_MEASUREMENT_DURATION, + CONF_STATUS, + CONF_VERSION, + ICON_RADIOACTIVE, + ICON_TIMER, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + UNIT_MICROSILVERTS_PER_HOUR, + UNIT_SECOND, +) +from . import CONF_GDK101_ID, GDK101Component + +CONF_RADIATION_DOSE_PER_1M = "radiation_dose_per_1m" +CONF_RADIATION_DOSE_PER_10M = "radiation_dose_per_10m" + +DEPENDENCIES = ["gdk101"] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_GDK101_ID): cv.use_id(GDK101Component), + cv.Optional(CONF_RADIATION_DOSE_PER_1M): sensor.sensor_schema( + icon=ICON_RADIOACTIVE, + unit_of_measurement=UNIT_MICROSILVERTS_PER_HOUR, + accuracy_decimals=2, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RADIATION_DOSE_PER_10M): sensor.sensor_schema( + icon=ICON_RADIOACTIVE, + unit_of_measurement=UNIT_MICROSILVERTS_PER_HOUR, + accuracy_decimals=2, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_VERSION): sensor.sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + accuracy_decimals=1, + ), + cv.Optional(CONF_STATUS): sensor.sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + accuracy_decimals=0, + ), + cv.Optional(CONF_MEASUREMENT_DURATION): sensor.sensor_schema( + unit_of_measurement=UNIT_SECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_TOTAL_INCREASING, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_GDK101_ID]) + + if radiation_dose_per_1m := config.get(CONF_RADIATION_DOSE_PER_1M): + sens = await sensor.new_sensor(radiation_dose_per_1m) + cg.add(hub.set_rad_1m_sensor(sens)) + + if radiation_dose_per_10m := config.get(CONF_RADIATION_DOSE_PER_10M): + sens = await sensor.new_sensor(radiation_dose_per_10m) + cg.add(hub.set_rad_10m_sensor(sens)) + + if version_config := config.get(CONF_VERSION): + sens = await sensor.new_sensor(version_config) + cg.add(hub.set_fw_version_sensor(sens)) + + if status_config := config.get(CONF_STATUS): + sens = await sensor.new_sensor(status_config) + cg.add(hub.set_status_sensor(sens)) + + if measurement_duration_config := config.get(CONF_MEASUREMENT_DURATION): + sens = await sensor.new_sensor(measurement_duration_config) + cg.add(hub.set_measurement_duration_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index dba974610a..542183d3b2 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -884,6 +884,7 @@ CONF_VALUE_FONT = "value_font" CONF_VARIABLES = "variables" CONF_VARIANT = "variant" CONF_VERSION = "version" +CONF_VIBRATIONS = "vibrations" CONF_VISIBLE = "visible" CONF_VISUAL = "visual" CONF_VOLTAGE = "voltage" @@ -983,6 +984,7 @@ ICON_SIGNAL_DISTANCE_VARIANT = "mdi:signal" ICON_THERMOMETER = "mdi:thermometer" ICON_TIMELAPSE = "mdi:timelapse" ICON_TIMER = "mdi:timer-outline" +ICON_VIBRATE = "mdi:vibrate" ICON_WATER = "mdi:water" ICON_WATER_PERCENT = "mdi:water-percent" ICON_WEATHER_SUNSET = "mdi:weather-sunset" @@ -1024,6 +1026,7 @@ UNIT_METER_PER_SECOND_SQUARED = "m/s²" UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³" UNIT_MICROMETER = "µm" UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" +UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" UNIT_MICROTESLA = "µT" UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" UNIT_MILLISECOND = "ms" diff --git a/tests/components/gdk101/common.yaml b/tests/components/gdk101/common.yaml new file mode 100644 index 0000000000..f886fc415b --- /dev/null +++ b/tests/components/gdk101/common.yaml @@ -0,0 +1,28 @@ +i2c: + id: i2c_bus + sda: ${i2c_sda} + scl: ${i2c_scl} + +gdk101: + id: my_gdk101 + i2c_id: i2c_bus + +sensor: + - platform: gdk101 + gdk101_id: my_gdk101 + radiation_dose_per_1m: + name: Radiation Dose @ 1 min + radiation_dose_per_10m: + name: Radiation Dose @ 10 min + status: + name: Status + version: + name: FW Version + measurement_duration: + name: Measuring Time + +binary_sensor: + - platform: gdk101 + gdk101_id: my_gdk101 + vibrations: + name: Vibrations diff --git a/tests/components/gdk101/test.esp32-idf.yaml b/tests/components/gdk101/test.esp32-idf.yaml new file mode 100644 index 0000000000..1037d5d35b --- /dev/null +++ b/tests/components/gdk101/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.esp32.yaml b/tests/components/gdk101/test.esp32.yaml new file mode 100644 index 0000000000..1037d5d35b --- /dev/null +++ b/tests/components/gdk101/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.esp8266.yaml b/tests/components/gdk101/test.esp8266.yaml new file mode 100644 index 0000000000..d7ae0d5161 --- /dev/null +++ b/tests/components/gdk101/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.rp2040.yaml b/tests/components/gdk101/test.rp2040.yaml new file mode 100644 index 0000000000..d7ae0d5161 --- /dev/null +++ b/tests/components/gdk101/test.rp2040.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + +<<: !include common.yaml From dd81c836862be87cdad41902f3847c097d8b0fa5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 13 May 2024 13:21:02 +1000 Subject: [PATCH 1716/2607] Typing hint and doc fixes (#6729) --- esphome/cpp_generator.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 04616d97c2..9a4cb2269a 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -2,7 +2,7 @@ import abc import inspect import math import re -from collections.abc import Generator, Sequence +from collections.abc import Sequence from typing import Any, Callable, Optional, Union from esphome.core import ( @@ -477,6 +477,7 @@ def variable( :param rhs: The expression to place on the right hand side of the assignment. :param type_: Manually define a type for the variable, only use this when it's not possible to do so during config validation phase (for example because of template arguments). + :param register: If true register the variable with the core :return: The new variable as a MockObj. """ @@ -492,9 +493,7 @@ def variable( return obj -def with_local_variable( - id_: ID, rhs: SafeExpType, callback: Callable[["MockObj"], None], *args -) -> None: +def with_local_variable(id_: ID, rhs: SafeExpType, callback: Callable, *args) -> None: """Declare a new variable, not pointer type, in the code generation, within a scoped block The variable is only usable within the callback The callback cannot be async. @@ -599,6 +598,7 @@ def add_library(name: str, version: Optional[str], repository: Optional[str] = N :param name: The name of the library (for example 'AsyncTCP') :param version: The version of the library, may be None. + :param repository: The repository for the library """ CORE.add_library(Library(name, version, repository)) @@ -654,7 +654,7 @@ async def process_lambda( parameters: list[tuple[SafeExpType, str]], capture: str = "=", return_type: SafeExpType = None, -) -> Generator[LambdaExpression, None, None]: +) -> Union[LambdaExpression, None]: """Process the given lambda value into a LambdaExpression. This is a coroutine because lambdas can depend on other IDs, @@ -673,7 +673,7 @@ async def process_lambda( ) if value is None: - return + return None parts = value.parts[:] for i, id in enumerate(value.requires_ids): full_id, var = await get_variable_with_full_id(id) @@ -712,7 +712,7 @@ async def templatable( value: Any, args: list[tuple[SafeExpType, str]], output_type: Optional[SafeExpType], - to_exp: Any = None, + to_exp: Union[Callable, dict] = None, ): """Generate code for a templatable config option. From a23d1631e199ac274a1f11d5fbe16ee12fe5b65c Mon Sep 17 00:00:00 2001 From: Jorge-Crespo-Celdran <86021690+Jorge-Crespo-Celdran@users.noreply.github.com> Date: Mon, 13 May 2024 06:04:06 +0200 Subject: [PATCH 1717/2607] time_based_cover.cpp with manual control fix (#6719) --- esphome/components/time_based/time_based_cover.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp index 50376224a9..e1936d5ee1 100644 --- a/esphome/components/time_based/time_based_cover.cpp +++ b/esphome/components/time_based/time_based_cover.cpp @@ -96,6 +96,9 @@ void TimeBasedCover::control(const CoverCall &call) { } } else { auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; + if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) { + this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED; + } this->target_position_ = pos; this->start_direction_(op); } From 5ee4bf380215d705c19ac4a07fb27a84cbc660db Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Mon, 13 May 2024 06:05:13 +0200 Subject: [PATCH 1718/2607] Set FEATURE_API_AUDIO flag also if the speaker component is not used (#6712) --- esphome/components/voice_assistant/voice_assistant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index d6b1502381..1c0ea12f4f 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -94,10 +94,10 @@ class VoiceAssistant : public Component { uint32_t get_feature_flags() const { uint32_t flags = 0; flags |= VoiceAssistantFeature::FEATURE_VOICE_ASSISTANT; + flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { flags |= VoiceAssistantFeature::FEATURE_SPEAKER; - flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; } #endif return flags; From 91007952e2276d09c4f52c1cc7ceabe3138c52eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Mon, 13 May 2024 11:21:06 +0100 Subject: [PATCH 1719/2607] [CST816] Add support for Hynitron Microelectronics CST826 capacitive touch (#6682) --- esphome/components/cst816/touchscreen/cst816_touchscreen.cpp | 4 ++++ esphome/components/cst816/touchscreen/cst816_touchscreen.h | 1 + 2 files changed, 5 insertions(+) diff --git a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp index d2b8cc81f1..9e59810c7e 100644 --- a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +++ b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp @@ -15,6 +15,7 @@ void CST816Touchscreen::continue_setup_() { } switch (this->chip_id_) { case CST820_CHIP_ID: + case CST826_CHIP_ID: case CST716_CHIP_ID: case CST816S_CHIP_ID: case CST816D_CHIP_ID: @@ -90,6 +91,9 @@ void CST816Touchscreen::dump_config() { case CST820_CHIP_ID: name = "CST820"; break; + case CST826_CHIP_ID: + name = "CST826"; + break; case CST816S_CHIP_ID: name = "CST816S"; break; diff --git a/esphome/components/cst816/touchscreen/cst816_touchscreen.h b/esphome/components/cst816/touchscreen/cst816_touchscreen.h index 0d987f2739..24e664e7ee 100644 --- a/esphome/components/cst816/touchscreen/cst816_touchscreen.h +++ b/esphome/components/cst816/touchscreen/cst816_touchscreen.h @@ -24,6 +24,7 @@ static const uint8_t REG_SLEEP = 0xE5; static const uint8_t REG_IRQ_CTL = 0xFA; static const uint8_t IRQ_EN_MOTION = 0x70; +static const uint8_t CST826_CHIP_ID = 0x11; static const uint8_t CST820_CHIP_ID = 0xB7; static const uint8_t CST816S_CHIP_ID = 0xB4; static const uint8_t CST816D_CHIP_ID = 0xB6; From eae97dbaa0d450872e35234ecb53f5119da4aa95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 07:11:59 +1200 Subject: [PATCH 1720/2607] Bump platformio from 6.1.13 to 6.1.15 (#6634) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index df94b8b77c..698ae56447 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ tornado==6.4 tzlocal==5.2 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.13 # When updating platformio, also update Dockerfile +platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240412.0 From 47b40505c2952b4ee1d066119eac3d212a6761b1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 09:42:53 +1200 Subject: [PATCH 1721/2607] Fix ESPHOME_PROJECT_VERSION_30 (#6731) --- esphome/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/config.py b/esphome/core/config.py index 2d87796987..80b731b905 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -394,7 +394,7 @@ async def to_code(config): if project_conf := config.get(CONF_PROJECT): cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME]) cg.add_define("ESPHOME_PROJECT_VERSION", project_conf[CONF_VERSION]) - cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:30]) + cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:29]) for conf in project_conf.get(CONF_ON_UPDATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await cg.register_component(trigger, conf) From 2ac0821cab11c4fbd23d17af1ada42577156d258 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 09:58:43 +1200 Subject: [PATCH 1722/2607] Bump pytest from 8.1.1 to 8.2.0 (#6732) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 78820765f4..ae833841ca 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.15.2 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==8.1.1 +pytest==8.2.0 pytest-cov==4.1.0 pytest-mock==3.14.0 pytest-asyncio==0.23.6 From 4ec2ef27a87cb8efa5f8a3899bd0fa7e2a80068c Mon Sep 17 00:00:00 2001 From: Marcin Krasowski Date: Mon, 13 May 2024 01:25:41 +0200 Subject: [PATCH 1723/2607] fix(ltr390): stuck ALS values when configured for ALS+UV readings (#6723) --- esphome/components/ltr390/ltr390.cpp | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 65c08ab614..4eb1ff2c46 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -8,6 +8,9 @@ namespace ltr390 { static const char *const TAG = "ltr390"; +static const uint8_t LTR390_WAKEUP_TIME = 10; +static const uint8_t LTR390_SETTLE_TIME = 5; + static const uint8_t LTR390_MAIN_CTRL = 0x00; static const uint8_t LTR390_MEAS_RATE = 0x04; static const uint8_t LTR390_GAIN = 0x05; @@ -101,21 +104,27 @@ void LTR390Component::read_mode_(int mode_index) { std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); ctrl[LTR390_CTRL_MODE] = mode; + ctrl[LTR390_CTRL_EN] = true; this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); // After the sensor integration time do the following - this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100, [this, mode_index]() { - // Read from the sensor - std::get<1>(this->mode_funcs_[mode_index])(); + this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, + [this, mode_index]() { + // Read from the sensor + std::get<1>(this->mode_funcs_[mode_index])(); - // If there are more modes to read then begin the next - // otherwise stop - if (mode_index + 1 < (int) this->mode_funcs_.size()) { - this->read_mode_(mode_index + 1); - } else { - this->reading_ = false; - } - }); + // If there are more modes to read then begin the next + // otherwise stop + if (mode_index + 1 < (int) this->mode_funcs_.size()) { + this->read_mode_(mode_index + 1); + } else { + // put sensor in standby + std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); + ctrl[LTR390_CTRL_EN] = false; + this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); + this->reading_ = false; + } + }); } void LTR390Component::setup() { From 694f75117e63e1261c873cb5fc080b2d4591b956 Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Mon, 13 May 2024 06:05:13 +0200 Subject: [PATCH 1724/2607] Set FEATURE_API_AUDIO flag also if the speaker component is not used (#6712) --- esphome/components/voice_assistant/voice_assistant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index d6b1502381..1c0ea12f4f 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -94,10 +94,10 @@ class VoiceAssistant : public Component { uint32_t get_feature_flags() const { uint32_t flags = 0; flags |= VoiceAssistantFeature::FEATURE_VOICE_ASSISTANT; + flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { flags |= VoiceAssistantFeature::FEATURE_SPEAKER; - flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; } #endif return flags; From ba3fc4c5d08dd643099590daf42c5638d496d128 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 07:11:59 +1200 Subject: [PATCH 1725/2607] Bump platformio from 6.1.13 to 6.1.15 (#6634) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index df94b8b77c..698ae56447 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ tornado==6.4 tzlocal==5.2 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.13 # When updating platformio, also update Dockerfile +platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240412.0 From 5afe0e5ec2a3619a341593884d7fe4ce6e35a791 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 09:42:53 +1200 Subject: [PATCH 1726/2607] Fix ESPHOME_PROJECT_VERSION_30 (#6731) --- esphome/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/config.py b/esphome/core/config.py index 2d87796987..80b731b905 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -394,7 +394,7 @@ async def to_code(config): if project_conf := config.get(CONF_PROJECT): cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME]) cg.add_define("ESPHOME_PROJECT_VERSION", project_conf[CONF_VERSION]) - cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:30]) + cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:29]) for conf in project_conf.get(CONF_ON_UPDATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await cg.register_component(trigger, conf) From 1e4d6ee34457f7afc3d7f26fddc72cec893702c1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 10:02:22 +1200 Subject: [PATCH 1727/2607] Bump version to 2024.5.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 6e00c1bbe1..e3d9bfeb64 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b3" +__version__ = "2024.5.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 921e56f2c693d8dd2facd642967c4f39db32e0d3 Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Tue, 14 May 2024 03:25:24 +0200 Subject: [PATCH 1728/2607] =?UTF-8?q?Voice-Assistant:=20Start-order=20chan?= =?UTF-8?q?ge=20for=20VAD=20disabled:=20start=20va-pipeline=20when=20micro?= =?UTF-8?q?phon=E2=80=A6=20(#6391)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/components/voice_assistant/voice_assistant.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index e68e00948e..3bd41e1fcf 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -152,7 +152,7 @@ void VoiceAssistant::loop() { } else #endif { - this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + this->set_state_(State::START_MICROPHONE, State::START_PIPELINE); } } else { this->high_freq_.stop(); @@ -514,7 +514,7 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) { } else #endif { - this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + this->set_state_(State::START_MICROPHONE, State::START_PIPELINE); } } } From 036a666e369009a7d85b4c1614cccdf296e3809f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 15:38:53 +1200 Subject: [PATCH 1729/2607] [web_server] Minor python formatting (#6735) --- esphome/components/web_server/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index bbd5bc662e..fa614fb5a6 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -35,19 +35,19 @@ WebServer = web_server_ns.class_("WebServer", cg.Component, cg.Controller) def default_url(config): config = config.copy() if config[CONF_VERSION] == 1: - if not (CONF_CSS_URL in config): + if CONF_CSS_URL not in config: config[CONF_CSS_URL] = "https://esphome.io/_static/webserver-v1.min.css" - if not (CONF_JS_URL in config): + if CONF_JS_URL not in config: config[CONF_JS_URL] = "https://esphome.io/_static/webserver-v1.min.js" if config[CONF_VERSION] == 2: - if not (CONF_CSS_URL in config): + if CONF_CSS_URL not in config: config[CONF_CSS_URL] = "" - if not (CONF_JS_URL in config): + if CONF_JS_URL not in config: config[CONF_JS_URL] = "https://oi.esphome.io/v2/www.js" if config[CONF_VERSION] == 3: - if not (CONF_CSS_URL in config): + if CONF_CSS_URL not in config: config[CONF_CSS_URL] = "" - if not (CONF_JS_URL in config): + if CONF_JS_URL not in config: config[CONF_JS_URL] = "https://oi.esphome.io/v3/www.js" return config From 7d791cbdfb028e24bc75e67af81919904ef78301 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 16:22:43 +1200 Subject: [PATCH 1730/2607] [esp32_ble] Fix compilation error on esp32c6 (#6734) --- esphome/components/esp32_ble/ble.cpp | 9 +++ esphome/components/esp32_ble/const_esp32c6.h | 67 ++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 esphome/components/esp32_ble/const_esp32c6.h diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 3797f3221e..ceb6516a02 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -1,6 +1,11 @@ #ifdef USE_ESP32 #include "ble.h" + +#ifdef USE_ESP32_VARIANT_ESP32C6 +#include "const_esp32c6.h" +#endif // USE_ESP32_VARIANT_ESP32C6 + #include "esphome/core/application.h" #include "esphome/core/log.h" @@ -114,7 +119,11 @@ bool ESP32BLE::ble_setup_() { if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { // start bt controller if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) { +#ifdef USE_ESP32_VARIANT_ESP32C6 + esp_bt_controller_config_t cfg = BT_CONTROLLER_CONFIG; +#else esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); +#endif err = esp_bt_controller_init(&cfg); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err)); diff --git a/esphome/components/esp32_ble/const_esp32c6.h b/esphome/components/esp32_ble/const_esp32c6.h new file mode 100644 index 0000000000..69f9adcf6b --- /dev/null +++ b/esphome/components/esp32_ble/const_esp32c6.h @@ -0,0 +1,67 @@ +#pragma once + +#ifdef USE_ESP32_VARIANT_ESP32C6 + +#include + +namespace esphome { +namespace esp32_ble { + +static const esp_bt_controller_config_t BT_CONTROLLER_CONFIG = { + .config_version = CONFIG_VERSION, + .ble_ll_resolv_list_size = CONFIG_BT_LE_LL_RESOLV_LIST_SIZE, + .ble_hci_evt_hi_buf_count = DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT, + .ble_hci_evt_lo_buf_count = DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT, + .ble_ll_sync_list_cnt = DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST, + .ble_ll_sync_cnt = DEFAULT_BT_LE_MAX_PERIODIC_SYNCS, + .ble_ll_rsp_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, + .ble_ll_adv_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, + .ble_ll_tx_pwr_dbm = BLE_LL_TX_PWR_DBM_N, + .rtc_freq = RTC_FREQ_N, + .ble_ll_sca = CONFIG_BT_LE_LL_SCA, + .ble_ll_scan_phy_number = BLE_LL_SCAN_PHY_NUMBER_N, + .ble_ll_conn_def_auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N, + .ble_ll_jitter_usecs = BLE_LL_JITTER_USECS_N, + .ble_ll_sched_max_adv_pdu_usecs = BLE_LL_SCHED_MAX_ADV_PDU_USECS_N, + .ble_ll_sched_direct_adv_max_usecs = BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N, + .ble_ll_sched_adv_max_usecs = BLE_LL_SCHED_ADV_MAX_USECS_N, + .ble_scan_rsp_data_max_len = DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N, + .ble_ll_cfg_num_hci_cmd_pkts = BLE_LL_CFG_NUM_HCI_CMD_PKTS_N, + .ble_ll_ctrl_proc_timeout_ms = BLE_LL_CTRL_PROC_TIMEOUT_MS_N, + .nimble_max_connections = DEFAULT_BT_LE_MAX_CONNECTIONS, + .ble_whitelist_size = DEFAULT_BT_NIMBLE_WHITELIST_SIZE, // NOLINT + .ble_acl_buf_size = DEFAULT_BT_LE_ACL_BUF_SIZE, + .ble_acl_buf_count = DEFAULT_BT_LE_ACL_BUF_COUNT, + .ble_hci_evt_buf_size = DEFAULT_BT_LE_HCI_EVT_BUF_SIZE, + .ble_multi_adv_instances = DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES, + .ble_ext_adv_max_size = DEFAULT_BT_LE_EXT_ADV_MAX_SIZE, + .controller_task_stack_size = NIMBLE_LL_STACK_SIZE, + .controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, + .controller_run_cpu = 0, + .enable_qa_test = RUN_QA_TEST, + .enable_bqb_test = RUN_BQB_TEST, + .enable_uart_hci = HCI_UART_EN, + .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, + .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, + .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, + .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, + .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, + .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, + .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, + .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, + .sleep_en = NIMBLE_SLEEP_ENABLE, + .coex_phy_coded_tx_rx_time_limit = DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF, + .dis_scan_backoff = NIMBLE_DISABLE_SCAN_BACKOFF, + .ble_scan_classify_filter_enable = 1, + .main_xtal_freq = CONFIG_XTAL_FREQ, + .version_num = (uint8_t) efuse_hal_chip_revision(), + .cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, + .ignore_wl_for_direct_adv = 0, + .enable_pcl = DEFAULT_BT_LE_POWER_CONTROL_ENABLED, + .config_magic = CONFIG_MAGIC, +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32C6 From 636037cec17bb0abae6def201fd1273bc752cea2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 14 May 2024 17:01:07 +1200 Subject: [PATCH 1731/2607] [core] Fix minor formatting issues (#6738) --- esphome/__main__.py | 2 +- esphome/components/animation/__init__.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 54c1aa112a..daf74eebb0 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -65,7 +65,7 @@ def choose_prompt(options, purpose: str = None): f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:' ) for i, (desc, _) in enumerate(options): - safe_print(f" [{i+1}] {desc}") + safe_print(f" [{i + 1}] {desc}") while True: opt = input("(number): ") diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 9151d6e56d..a7a955bead 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -157,7 +157,7 @@ async def to_code(config): pixels = list(frame.getdata()) if len(pixels) != height * width: raise core.EsphomeError( - f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" + f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})" ) for pix, a in pixels: if transparent: @@ -180,7 +180,7 @@ async def to_code(config): pixels = list(frame.getdata()) if len(pixels) != height * width: raise core.EsphomeError( - f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" + f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})" ) for pix in pixels: data[pos] = pix[0] @@ -203,7 +203,7 @@ async def to_code(config): pixels = list(frame.getdata()) if len(pixels) != height * width: raise core.EsphomeError( - f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" + f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})" ) for r, g, b, a in pixels: if transparent: @@ -232,7 +232,7 @@ async def to_code(config): pixels = list(frame.getdata()) if len(pixels) != height * width: raise core.EsphomeError( - f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" + f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})" ) for r, g, b, a in pixels: R = r >> 3 From d5eeab81d66f6d053a995f792a22424f7095527d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 14 May 2024 19:31:03 +1000 Subject: [PATCH 1732/2607] [config] Improve error reporting (#6736) --- esphome/config.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index 4f340225fe..2b231fc402 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -34,7 +34,7 @@ from esphome.voluptuous_schema import ExtraKeysInvalid from esphome.log import color, Fore import esphome.final_validate as fv import esphome.config_validation as cv -from esphome.types import ConfigType, ConfigPathType, ConfigFragmentType +from esphome.types import ConfigType, ConfigFragmentType _LOGGER = logging.getLogger(__name__) @@ -213,7 +213,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): return doc_range def get_nested_item( - self, path: ConfigPathType, raise_error: bool = False + self, path: ConfigPath, raise_error: bool = False ) -> ConfigFragmentType: data = self for item_index in path: @@ -244,7 +244,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): return path raise KeyError(f"ID {id} not found in configuration") - def get_config_for_path(self, path: ConfigPathType) -> ConfigFragmentType: + def get_config_for_path(self, path: ConfigPath) -> ConfigFragmentType: return self.get_nested_item(path, raise_error=True) @property @@ -885,6 +885,9 @@ def _get_parent_name(path, config): # Sub-item break return domain + # When processing a list, skip back over the index + while len(path) > 1 and isinstance(path[-1], int): + path = path[:-1] return path[-1] @@ -1106,7 +1109,14 @@ def read_config(command_line_substitutions): if errline: errstr += f" {errline}" safe_print(errstr) - safe_print(indent(dump_dict(res, path)[0])) + split_dump = dump_dict(res, path)[0].splitlines() + # find the last error message + i = len(split_dump) - 1 + while i > 10 and "\033[" not in split_dump[i]: + i = i - 1 + # discard lines more than 4 beyond the last error + i = min(i + 4, len(split_dump)) + safe_print(indent("\n".join(split_dump[:i]))) for err in res.errors: safe_print(color(Fore.BOLD_RED, err.msg)) From 6f53607e5ad20594268c2ed7ade53c8f95bcc070 Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Tue, 14 May 2024 11:40:08 +0200 Subject: [PATCH 1733/2607] Add ANNOUNCING state to media_player. (#6691) --- esphome/components/api/api.proto | 3 +++ esphome/components/api/api_connection.cpp | 9 ++++++++- esphome/components/api/api_pb2.cpp | 18 ++++++++++++++++++ esphome/components/api/api_pb2.h | 2 ++ .../media_player/i2s_audio_media_player.cpp | 17 ++++++++++++++--- .../media_player/i2s_audio_media_player.h | 1 + esphome/components/media_player/__init__.py | 12 ++++++++++++ esphome/components/media_player/automation.h | 1 + .../components/media_player/media_player.cpp | 10 ++++++++++ esphome/components/media_player/media_player.h | 6 +++++- .../voice_assistant/voice_assistant.cpp | 4 ++-- 11 files changed, 76 insertions(+), 7 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index b8073abc19..774ca7ed9b 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1147,6 +1147,9 @@ message MediaPlayerCommandRequest { bool has_media_url = 6; string media_url = 7; + + bool has_announcement = 8; + bool announcement = 9; } // ==================== BLUETOOTH ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index b31212bbdb..2804dba31f 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1002,7 +1002,11 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla MediaPlayerStateResponse resp{}; resp.key = media_player->get_object_id_hash(); - resp.state = static_cast(media_player->state); + + media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING + ? media_player::MEDIA_PLAYER_STATE_PLAYING + : media_player->state; + resp.state = static_cast(report_state); resp.volume = media_player->volume; resp.muted = media_player->is_muted(); return this->send_media_player_state_response(resp); @@ -1038,6 +1042,9 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { if (msg.has_media_url) { call.set_media_url(msg.media_url); } + if (msg.has_announcement) { + call.set_announcement(msg.announcement); + } call.perform(); } #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 6ec1870d72..a48087e348 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -5253,6 +5253,14 @@ bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt val this->has_media_url = value.as_bool(); return true; } + case 8: { + this->has_announcement = value.as_bool(); + return true; + } + case 9: { + this->announcement = value.as_bool(); + return true; + } default: return false; } @@ -5289,6 +5297,8 @@ void MediaPlayerCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_float(5, this->volume); buffer.encode_bool(6, this->has_media_url); buffer.encode_string(7, this->media_url); + buffer.encode_bool(8, this->has_announcement); + buffer.encode_bool(9, this->announcement); } #ifdef HAS_PROTO_MESSAGE_DUMP void MediaPlayerCommandRequest::dump_to(std::string &out) const { @@ -5323,6 +5333,14 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { out.append(" media_url: "); out.append("'").append(this->media_url).append("'"); out.append("\n"); + + out.append(" has_announcement: "); + out.append(YESNO(this->has_announcement)); + out.append("\n"); + + out.append(" announcement: "); + out.append(YESNO(this->announcement)); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 14fd95df37..807b150d82 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1298,6 +1298,8 @@ class MediaPlayerCommandRequest : public ProtoMessage { float volume{0.0f}; bool has_media_url{false}; std::string media_url{}; + bool has_announcement{false}; + bool announcement{false}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 6e07983920..1890e27bdf 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -10,6 +10,11 @@ namespace i2s_audio { static const char *const TAG = "audio"; void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { + media_player::MediaPlayerState play_state = media_player::MEDIA_PLAYER_STATE_PLAYING; + if (call.get_announcement().has_value()) { + play_state = call.get_announcement().value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING + : media_player::MEDIA_PLAYER_STATE_PLAYING; + } if (call.get_media_url().has_value()) { this->current_url_ = call.get_media_url(); if (this->i2s_state_ != I2S_STATE_STOPPED && this->audio_ != nullptr) { @@ -17,7 +22,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->audio_->stopSong(); } this->audio_->connecttohost(this->current_url_.value().c_str()); - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + this->state = play_state; } else { this->start(); } @@ -35,7 +40,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { case media_player::MEDIA_PLAYER_COMMAND_PLAY: if (!this->audio_->isRunning()) this->audio_->pauseResume(); - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + this->state = play_state; break; case media_player::MEDIA_PLAYER_COMMAND_PAUSE: if (this->audio_->isRunning()) @@ -126,7 +131,9 @@ void I2SAudioMediaPlayer::loop() { void I2SAudioMediaPlayer::play_() { this->audio_->loop(); - if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && !this->audio_->isRunning()) { + if ((this->state == media_player::MEDIA_PLAYER_STATE_PLAYING || + this->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING) && + !this->audio_->isRunning()) { this->stop(); } } @@ -164,6 +171,10 @@ void I2SAudioMediaPlayer::start_() { if (this->current_url_.has_value()) { this->audio_->connecttohost(this->current_url_.value().c_str()); this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + if (this->is_announcement_.has_value()) { + this->state = this->is_announcement_.value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING + : media_player::MEDIA_PLAYER_STATE_PLAYING; + } this->publish_state(); } } diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index 092e6de8e8..d7d9b1f74a 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -78,6 +78,7 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, HighFrequencyLoopRequester high_freq_; optional current_url_{}; + optional is_announcement_{}; }; } // namespace i2s_audio diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 5db78150bb..320014e355 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -51,12 +51,16 @@ VolumeSetAction = media_player_ns.class_( CONF_ON_PLAY = "on_play" CONF_ON_PAUSE = "on_pause" +CONF_ON_ANNOUNCEMENT = "on_announcement" CONF_MEDIA_URL = "media_url" StateTrigger = media_player_ns.class_("StateTrigger", automation.Trigger.template()) IdleTrigger = media_player_ns.class_("IdleTrigger", automation.Trigger.template()) PlayTrigger = media_player_ns.class_("PlayTrigger", automation.Trigger.template()) PauseTrigger = media_player_ns.class_("PauseTrigger", automation.Trigger.template()) +AnnoucementTrigger = media_player_ns.class_( + "AnnouncementTrigger", automation.Trigger.template() +) IsIdleCondition = media_player_ns.class_("IsIdleCondition", automation.Condition) IsPlayingCondition = media_player_ns.class_("IsPlayingCondition", automation.Condition) @@ -75,6 +79,9 @@ async def setup_media_player_core_(var, config): for conf in config.get(CONF_ON_PAUSE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ANNOUNCEMENT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) async def register_media_player(var, config): @@ -106,6 +113,11 @@ MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger), } ), + cv.Optional(CONF_ON_ANNOUNCEMENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(AnnoucementTrigger), + } + ), } ) diff --git a/esphome/components/media_player/automation.h b/esphome/components/media_player/automation.h index 261e93775c..fc3ce7a764 100644 --- a/esphome/components/media_player/automation.h +++ b/esphome/components/media_player/automation.h @@ -52,6 +52,7 @@ class StateTrigger : public Trigger<> { MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(IdleTrigger, IDLE) MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PlayTrigger, PLAYING) MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PauseTrigger, PAUSED) +MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(AnnouncementTrigger, ANNOUNCING) template class IsIdleCondition : public Condition, public Parented { public: diff --git a/esphome/components/media_player/media_player.cpp b/esphome/components/media_player/media_player.cpp index 81cb6ca751..586345ac9f 100644 --- a/esphome/components/media_player/media_player.cpp +++ b/esphome/components/media_player/media_player.cpp @@ -15,6 +15,8 @@ const char *media_player_state_to_string(MediaPlayerState state) { return "PLAYING"; case MEDIA_PLAYER_STATE_PAUSED: return "PAUSED"; + case MEDIA_PLAYER_STATE_ANNOUNCING: + return "ANNOUNCING"; case MEDIA_PLAYER_STATE_NONE: default: return "UNKNOWN"; @@ -68,6 +70,9 @@ void MediaPlayerCall::perform() { if (this->volume_.has_value()) { ESP_LOGD(TAG, " Volume: %.2f", this->volume_.value()); } + if (this->announcement_.has_value()) { + ESP_LOGD(TAG, " Announcement: %s", this->announcement_.value() ? "yes" : "no"); + } this->parent_->control(*this); } @@ -108,6 +113,11 @@ MediaPlayerCall &MediaPlayerCall::set_volume(float volume) { return *this; } +MediaPlayerCall &MediaPlayerCall::set_announcement(bool announce) { + this->announcement_ = announce; + return *this; +} + void MediaPlayer::add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } diff --git a/esphome/components/media_player/media_player.h b/esphome/components/media_player/media_player.h index 88114d5337..77746e1808 100644 --- a/esphome/components/media_player/media_player.h +++ b/esphome/components/media_player/media_player.h @@ -10,7 +10,8 @@ enum MediaPlayerState : uint8_t { MEDIA_PLAYER_STATE_NONE = 0, MEDIA_PLAYER_STATE_IDLE = 1, MEDIA_PLAYER_STATE_PLAYING = 2, - MEDIA_PLAYER_STATE_PAUSED = 3 + MEDIA_PLAYER_STATE_PAUSED = 3, + MEDIA_PLAYER_STATE_ANNOUNCING = 4 }; const char *media_player_state_to_string(MediaPlayerState state); @@ -51,12 +52,14 @@ class MediaPlayerCall { MediaPlayerCall &set_media_url(const std::string &url); MediaPlayerCall &set_volume(float volume); + MediaPlayerCall &set_announcement(bool announce); void perform(); const optional &get_command() const { return command_; } const optional &get_media_url() const { return media_url_; } const optional &get_volume() const { return volume_; } + const optional &get_announcement() const { return announcement_; } protected: void validate_(); @@ -64,6 +67,7 @@ class MediaPlayerCall { optional command_; optional media_url_; optional volume_; + optional announcement_; }; class MediaPlayer : public EntityBase { diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 3bd41e1fcf..109e52f8eb 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -318,7 +318,7 @@ void VoiceAssistant::loop() { #endif #ifdef USE_MEDIA_PLAYER if (this->media_player_ != nullptr) { - playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING); + playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING); } #endif if (playing) { @@ -640,7 +640,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->defer([this, url]() { #ifdef USE_MEDIA_PLAYER if (this->media_player_ != nullptr) { - this->media_player_->make_call().set_media_url(url).perform(); + this->media_player_->make_call().set_media_url(url).set_announcement(true).perform(); } #endif this->tts_end_trigger_->trigger(url); From 128fad57b3f91907ce8cacb3e91dbc96e8fc51a6 Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Tue, 14 May 2024 03:25:24 +0200 Subject: [PATCH 1734/2607] =?UTF-8?q?Voice-Assistant:=20Start-order=20chan?= =?UTF-8?q?ge=20for=20VAD=20disabled:=20start=20va-pipeline=20when=20micro?= =?UTF-8?q?phon=E2=80=A6=20(#6391)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/components/voice_assistant/voice_assistant.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index e68e00948e..3bd41e1fcf 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -152,7 +152,7 @@ void VoiceAssistant::loop() { } else #endif { - this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + this->set_state_(State::START_MICROPHONE, State::START_PIPELINE); } } else { this->high_freq_.stop(); @@ -514,7 +514,7 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) { } else #endif { - this->set_state_(State::START_PIPELINE, State::START_MICROPHONE); + this->set_state_(State::START_MICROPHONE, State::START_PIPELINE); } } } From 28a09cc0d03d4842961e04d8ade99c3cbc6a5269 Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Tue, 14 May 2024 11:40:08 +0200 Subject: [PATCH 1735/2607] Add ANNOUNCING state to media_player. (#6691) --- esphome/components/api/api.proto | 3 +++ esphome/components/api/api_connection.cpp | 9 ++++++++- esphome/components/api/api_pb2.cpp | 18 ++++++++++++++++++ esphome/components/api/api_pb2.h | 2 ++ .../media_player/i2s_audio_media_player.cpp | 17 ++++++++++++++--- .../media_player/i2s_audio_media_player.h | 1 + esphome/components/media_player/__init__.py | 12 ++++++++++++ esphome/components/media_player/automation.h | 1 + .../components/media_player/media_player.cpp | 10 ++++++++++ esphome/components/media_player/media_player.h | 6 +++++- .../voice_assistant/voice_assistant.cpp | 4 ++-- 11 files changed, 76 insertions(+), 7 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index b8073abc19..774ca7ed9b 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1147,6 +1147,9 @@ message MediaPlayerCommandRequest { bool has_media_url = 6; string media_url = 7; + + bool has_announcement = 8; + bool announcement = 9; } // ==================== BLUETOOTH ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index b31212bbdb..2804dba31f 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1002,7 +1002,11 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla MediaPlayerStateResponse resp{}; resp.key = media_player->get_object_id_hash(); - resp.state = static_cast(media_player->state); + + media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING + ? media_player::MEDIA_PLAYER_STATE_PLAYING + : media_player->state; + resp.state = static_cast(report_state); resp.volume = media_player->volume; resp.muted = media_player->is_muted(); return this->send_media_player_state_response(resp); @@ -1038,6 +1042,9 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { if (msg.has_media_url) { call.set_media_url(msg.media_url); } + if (msg.has_announcement) { + call.set_announcement(msg.announcement); + } call.perform(); } #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 6ec1870d72..a48087e348 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -5253,6 +5253,14 @@ bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt val this->has_media_url = value.as_bool(); return true; } + case 8: { + this->has_announcement = value.as_bool(); + return true; + } + case 9: { + this->announcement = value.as_bool(); + return true; + } default: return false; } @@ -5289,6 +5297,8 @@ void MediaPlayerCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_float(5, this->volume); buffer.encode_bool(6, this->has_media_url); buffer.encode_string(7, this->media_url); + buffer.encode_bool(8, this->has_announcement); + buffer.encode_bool(9, this->announcement); } #ifdef HAS_PROTO_MESSAGE_DUMP void MediaPlayerCommandRequest::dump_to(std::string &out) const { @@ -5323,6 +5333,14 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const { out.append(" media_url: "); out.append("'").append(this->media_url).append("'"); out.append("\n"); + + out.append(" has_announcement: "); + out.append(YESNO(this->has_announcement)); + out.append("\n"); + + out.append(" announcement: "); + out.append(YESNO(this->announcement)); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 14fd95df37..807b150d82 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1298,6 +1298,8 @@ class MediaPlayerCommandRequest : public ProtoMessage { float volume{0.0f}; bool has_media_url{false}; std::string media_url{}; + bool has_announcement{false}; + bool announcement{false}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 6e07983920..1890e27bdf 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -10,6 +10,11 @@ namespace i2s_audio { static const char *const TAG = "audio"; void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { + media_player::MediaPlayerState play_state = media_player::MEDIA_PLAYER_STATE_PLAYING; + if (call.get_announcement().has_value()) { + play_state = call.get_announcement().value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING + : media_player::MEDIA_PLAYER_STATE_PLAYING; + } if (call.get_media_url().has_value()) { this->current_url_ = call.get_media_url(); if (this->i2s_state_ != I2S_STATE_STOPPED && this->audio_ != nullptr) { @@ -17,7 +22,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->audio_->stopSong(); } this->audio_->connecttohost(this->current_url_.value().c_str()); - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + this->state = play_state; } else { this->start(); } @@ -35,7 +40,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { case media_player::MEDIA_PLAYER_COMMAND_PLAY: if (!this->audio_->isRunning()) this->audio_->pauseResume(); - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + this->state = play_state; break; case media_player::MEDIA_PLAYER_COMMAND_PAUSE: if (this->audio_->isRunning()) @@ -126,7 +131,9 @@ void I2SAudioMediaPlayer::loop() { void I2SAudioMediaPlayer::play_() { this->audio_->loop(); - if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && !this->audio_->isRunning()) { + if ((this->state == media_player::MEDIA_PLAYER_STATE_PLAYING || + this->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING) && + !this->audio_->isRunning()) { this->stop(); } } @@ -164,6 +171,10 @@ void I2SAudioMediaPlayer::start_() { if (this->current_url_.has_value()) { this->audio_->connecttohost(this->current_url_.value().c_str()); this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + if (this->is_announcement_.has_value()) { + this->state = this->is_announcement_.value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING + : media_player::MEDIA_PLAYER_STATE_PLAYING; + } this->publish_state(); } } diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index 092e6de8e8..d7d9b1f74a 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -78,6 +78,7 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, HighFrequencyLoopRequester high_freq_; optional current_url_{}; + optional is_announcement_{}; }; } // namespace i2s_audio diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 5db78150bb..320014e355 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -51,12 +51,16 @@ VolumeSetAction = media_player_ns.class_( CONF_ON_PLAY = "on_play" CONF_ON_PAUSE = "on_pause" +CONF_ON_ANNOUNCEMENT = "on_announcement" CONF_MEDIA_URL = "media_url" StateTrigger = media_player_ns.class_("StateTrigger", automation.Trigger.template()) IdleTrigger = media_player_ns.class_("IdleTrigger", automation.Trigger.template()) PlayTrigger = media_player_ns.class_("PlayTrigger", automation.Trigger.template()) PauseTrigger = media_player_ns.class_("PauseTrigger", automation.Trigger.template()) +AnnoucementTrigger = media_player_ns.class_( + "AnnouncementTrigger", automation.Trigger.template() +) IsIdleCondition = media_player_ns.class_("IsIdleCondition", automation.Condition) IsPlayingCondition = media_player_ns.class_("IsPlayingCondition", automation.Condition) @@ -75,6 +79,9 @@ async def setup_media_player_core_(var, config): for conf in config.get(CONF_ON_PAUSE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ANNOUNCEMENT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) async def register_media_player(var, config): @@ -106,6 +113,11 @@ MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger), } ), + cv.Optional(CONF_ON_ANNOUNCEMENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(AnnoucementTrigger), + } + ), } ) diff --git a/esphome/components/media_player/automation.h b/esphome/components/media_player/automation.h index 261e93775c..fc3ce7a764 100644 --- a/esphome/components/media_player/automation.h +++ b/esphome/components/media_player/automation.h @@ -52,6 +52,7 @@ class StateTrigger : public Trigger<> { MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(IdleTrigger, IDLE) MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PlayTrigger, PLAYING) MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PauseTrigger, PAUSED) +MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(AnnouncementTrigger, ANNOUNCING) template class IsIdleCondition : public Condition, public Parented { public: diff --git a/esphome/components/media_player/media_player.cpp b/esphome/components/media_player/media_player.cpp index 81cb6ca751..586345ac9f 100644 --- a/esphome/components/media_player/media_player.cpp +++ b/esphome/components/media_player/media_player.cpp @@ -15,6 +15,8 @@ const char *media_player_state_to_string(MediaPlayerState state) { return "PLAYING"; case MEDIA_PLAYER_STATE_PAUSED: return "PAUSED"; + case MEDIA_PLAYER_STATE_ANNOUNCING: + return "ANNOUNCING"; case MEDIA_PLAYER_STATE_NONE: default: return "UNKNOWN"; @@ -68,6 +70,9 @@ void MediaPlayerCall::perform() { if (this->volume_.has_value()) { ESP_LOGD(TAG, " Volume: %.2f", this->volume_.value()); } + if (this->announcement_.has_value()) { + ESP_LOGD(TAG, " Announcement: %s", this->announcement_.value() ? "yes" : "no"); + } this->parent_->control(*this); } @@ -108,6 +113,11 @@ MediaPlayerCall &MediaPlayerCall::set_volume(float volume) { return *this; } +MediaPlayerCall &MediaPlayerCall::set_announcement(bool announce) { + this->announcement_ = announce; + return *this; +} + void MediaPlayer::add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } diff --git a/esphome/components/media_player/media_player.h b/esphome/components/media_player/media_player.h index 88114d5337..77746e1808 100644 --- a/esphome/components/media_player/media_player.h +++ b/esphome/components/media_player/media_player.h @@ -10,7 +10,8 @@ enum MediaPlayerState : uint8_t { MEDIA_PLAYER_STATE_NONE = 0, MEDIA_PLAYER_STATE_IDLE = 1, MEDIA_PLAYER_STATE_PLAYING = 2, - MEDIA_PLAYER_STATE_PAUSED = 3 + MEDIA_PLAYER_STATE_PAUSED = 3, + MEDIA_PLAYER_STATE_ANNOUNCING = 4 }; const char *media_player_state_to_string(MediaPlayerState state); @@ -51,12 +52,14 @@ class MediaPlayerCall { MediaPlayerCall &set_media_url(const std::string &url); MediaPlayerCall &set_volume(float volume); + MediaPlayerCall &set_announcement(bool announce); void perform(); const optional &get_command() const { return command_; } const optional &get_media_url() const { return media_url_; } const optional &get_volume() const { return volume_; } + const optional &get_announcement() const { return announcement_; } protected: void validate_(); @@ -64,6 +67,7 @@ class MediaPlayerCall { optional command_; optional media_url_; optional volume_; + optional announcement_; }; class MediaPlayer : public EntityBase { diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 3bd41e1fcf..109e52f8eb 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -318,7 +318,7 @@ void VoiceAssistant::loop() { #endif #ifdef USE_MEDIA_PLAYER if (this->media_player_ != nullptr) { - playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING); + playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING); } #endif if (playing) { @@ -640,7 +640,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->defer([this, url]() { #ifdef USE_MEDIA_PLAYER if (this->media_player_ != nullptr) { - this->media_player_->make_call().set_media_url(url).perform(); + this->media_player_->make_call().set_media_url(url).set_announcement(true).perform(); } #endif this->tts_end_trigger_->trigger(url); From db4aa0b679b3b2324d715a1d2d16423661ed3057 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 May 2024 07:37:22 +1200 Subject: [PATCH 1736/2607] Bump version to 2024.5.0b5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e3d9bfeb64..2e5e9cc9de 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b4" +__version__ = "2024.5.0b5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 9a6e90af54f0704d8150905e01b1e2d105a28dc7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 May 2024 12:51:01 +1200 Subject: [PATCH 1737/2607] [adc] Fix 11db deprecation warning (#6749) --- esphome/components/adc/__init__.py | 14 ++++++++++++- esphome/components/adc/adc_sensor.cpp | 30 +++++++++++++-------------- esphome/components/adc/adc_sensor.h | 23 ++++++++++++++++---- esphome/components/adc/sensor.py | 18 ++++++++++++++-- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 87d769fec2..11b0ba2389 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -18,11 +18,23 @@ from esphome.components.esp32.const import ( CODEOWNERS = ["@esphome/core"] +adc_ns = cg.esphome_ns.namespace("adc") + + +""" +From the below patch versions (and 5.2+) ADC_ATTEN_DB_11 is deprecated and replaced with ADC_ATTEN_DB_12. +4.4.7 +5.0.5 +5.1.3 +5.2+ +""" + ATTENUATION_MODES = { "0db": cg.global_ns.ADC_ATTEN_DB_0, "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5, "6db": cg.global_ns.ADC_ATTEN_DB_6, - "11db": cg.global_ns.ADC_ATTEN_DB_11, + "11db": adc_ns.ADC_ATTEN_DB_12_COMPAT, + "12db": adc_ns.ADC_ATTEN_DB_12_COMPAT, "auto": "auto", } diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index a9ac5a5cfe..1a76bdb264 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -62,7 +62,7 @@ extern "C" } // load characteristics for each attenuation - for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) { + for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) { auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref @@ -118,8 +118,8 @@ void ADCSensor::dump_config() { case ADC_ATTEN_DB_6: ESP_LOGCONFIG(TAG, " Attenuation: 6db"); break; - case ADC_ATTEN_DB_11: - ESP_LOGCONFIG(TAG, " Attenuation: 11db"); + case ADC_ATTEN_DB_12_COMPAT: + ESP_LOGCONFIG(TAG, " Attenuation: 12db"); break; default: // This is to satisfy the unused ADC_ATTEN_MAX break; @@ -183,12 +183,12 @@ float ADCSensor::sample() { return mv / 1000.0f; } - int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; if (channel1_ != ADC1_CHANNEL_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); - raw11 = adc1_get_raw(channel1_); - if (raw11 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_12_COMPAT); + raw12 = adc1_get_raw(channel1_); + if (raw12 < ADC_MAX) { adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); raw6 = adc1_get_raw(channel1_); if (raw6 < ADC_MAX) { @@ -201,9 +201,9 @@ float ADCSensor::sample() { } } } else if (channel2_ != ADC2_CHANNEL_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11); - if (raw11 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_12_COMPAT); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12); + if (raw12 < ADC_MAX) { adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); if (raw6 < ADC_MAX) { @@ -217,25 +217,25 @@ float ADCSensor::sample() { } } - if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw11 == -1) { + if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) { return NAN; } - uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]); + uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]); uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) - uint32_t c11 = std::min(raw11, ADC_HALF); + uint32_t c12 = std::min(raw12, ADC_HALF); uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF); uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF); uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF); // max theoretical csum value is 4096*4 = 16384 - uint32_t csum = c11 + c6 + c2 + c0; + uint32_t csum = c12 + c6 + c2 + c0; // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32 - uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); + uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); return mv_scaled / (float) (csum * 1000U); } #endif // USE_ESP32 diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index b1fdcd5d29..d99c4bc75b 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -1,19 +1,34 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/hal.h" -#include "esphome/core/defines.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" #ifdef USE_ESP32 -#include "driver/adc.h" #include +#include "driver/adc.h" #endif namespace esphome { namespace adc { +#ifdef USE_ESP32 +// clang-format off +#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \ + (ESP_IDF_VERSION_MAJOR == 5 && \ + ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \ + (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \ + (ESP_IDF_VERSION_MINOR >= 2)) \ + ) +// clang-format on +static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_12; +#else +static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11; +#endif +#endif // USE_ESP32 + class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { public: #ifdef USE_ESP32 diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index c1ae22214d..4cf3d52802 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -1,3 +1,5 @@ +import logging + import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv @@ -19,16 +21,29 @@ from . import ( ATTENUATION_MODES, ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, ESP32_VARIANT_ADC2_PIN_TO_CHANNEL, + adc_ns, validate_adc_pin, ) +_LOGGER = logging.getLogger(__name__) + AUTO_LOAD = ["voltage_sampler"] +_attenuation = cv.enum(ATTENUATION_MODES, lower=True) + + def validate_config(config): if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") + if config.get(CONF_ATTENUATION) == "11db": + _LOGGER.warning( + "`attenuation: 11db` is deprecated, use `attenuation: 12db` instead" + ) + # Alter value here so `config` command prints the recommended change + config[CONF_ATTENUATION] = _attenuation("12db") + return config @@ -47,7 +62,6 @@ def final_validate_config(config): return config -adc_ns = cg.esphome_ns.namespace("adc") ADCSensor = adc_ns.class_( "ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler ) @@ -65,7 +79,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PIN): validate_adc_pin, cv.Optional(CONF_RAW, default=False): cv.boolean, cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All( - cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True) + cv.only_on_esp32, _attenuation ), } ) From ebc3f0fe1710ef3e11cc78cdd8f73bc5b319ae7c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 May 2024 12:51:01 +1200 Subject: [PATCH 1738/2607] [adc] Fix 11db deprecation warning (#6749) --- esphome/components/adc/__init__.py | 14 ++++++++++++- esphome/components/adc/adc_sensor.cpp | 30 +++++++++++++-------------- esphome/components/adc/adc_sensor.h | 23 ++++++++++++++++---- esphome/components/adc/sensor.py | 18 ++++++++++++++-- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 87d769fec2..11b0ba2389 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -18,11 +18,23 @@ from esphome.components.esp32.const import ( CODEOWNERS = ["@esphome/core"] +adc_ns = cg.esphome_ns.namespace("adc") + + +""" +From the below patch versions (and 5.2+) ADC_ATTEN_DB_11 is deprecated and replaced with ADC_ATTEN_DB_12. +4.4.7 +5.0.5 +5.1.3 +5.2+ +""" + ATTENUATION_MODES = { "0db": cg.global_ns.ADC_ATTEN_DB_0, "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5, "6db": cg.global_ns.ADC_ATTEN_DB_6, - "11db": cg.global_ns.ADC_ATTEN_DB_11, + "11db": adc_ns.ADC_ATTEN_DB_12_COMPAT, + "12db": adc_ns.ADC_ATTEN_DB_12_COMPAT, "auto": "auto", } diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index a9ac5a5cfe..1a76bdb264 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -62,7 +62,7 @@ extern "C" } // load characteristics for each attenuation - for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) { + for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) { auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref @@ -118,8 +118,8 @@ void ADCSensor::dump_config() { case ADC_ATTEN_DB_6: ESP_LOGCONFIG(TAG, " Attenuation: 6db"); break; - case ADC_ATTEN_DB_11: - ESP_LOGCONFIG(TAG, " Attenuation: 11db"); + case ADC_ATTEN_DB_12_COMPAT: + ESP_LOGCONFIG(TAG, " Attenuation: 12db"); break; default: // This is to satisfy the unused ADC_ATTEN_MAX break; @@ -183,12 +183,12 @@ float ADCSensor::sample() { return mv / 1000.0f; } - int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; + int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; if (channel1_ != ADC1_CHANNEL_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); - raw11 = adc1_get_raw(channel1_); - if (raw11 < ADC_MAX) { + adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_12_COMPAT); + raw12 = adc1_get_raw(channel1_); + if (raw12 < ADC_MAX) { adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); raw6 = adc1_get_raw(channel1_); if (raw6 < ADC_MAX) { @@ -201,9 +201,9 @@ float ADCSensor::sample() { } } } else if (channel2_ != ADC2_CHANNEL_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11); - if (raw11 < ADC_MAX) { + adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_12_COMPAT); + adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12); + if (raw12 < ADC_MAX) { adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); if (raw6 < ADC_MAX) { @@ -217,25 +217,25 @@ float ADCSensor::sample() { } } - if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw11 == -1) { + if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) { return NAN; } - uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]); + uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]); uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) - uint32_t c11 = std::min(raw11, ADC_HALF); + uint32_t c12 = std::min(raw12, ADC_HALF); uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF); uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF); uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF); // max theoretical csum value is 4096*4 = 16384 - uint32_t csum = c11 + c6 + c2 + c0; + uint32_t csum = c12 + c6 + c2 + c0; // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32 - uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); + uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); return mv_scaled / (float) (csum * 1000U); } #endif // USE_ESP32 diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index b1fdcd5d29..d99c4bc75b 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -1,19 +1,34 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/hal.h" -#include "esphome/core/defines.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" #ifdef USE_ESP32 -#include "driver/adc.h" #include +#include "driver/adc.h" #endif namespace esphome { namespace adc { +#ifdef USE_ESP32 +// clang-format off +#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \ + (ESP_IDF_VERSION_MAJOR == 5 && \ + ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \ + (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \ + (ESP_IDF_VERSION_MINOR >= 2)) \ + ) +// clang-format on +static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_12; +#else +static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11; +#endif +#endif // USE_ESP32 + class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { public: #ifdef USE_ESP32 diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index c1ae22214d..4cf3d52802 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -1,3 +1,5 @@ +import logging + import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv @@ -19,16 +21,29 @@ from . import ( ATTENUATION_MODES, ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, ESP32_VARIANT_ADC2_PIN_TO_CHANNEL, + adc_ns, validate_adc_pin, ) +_LOGGER = logging.getLogger(__name__) + AUTO_LOAD = ["voltage_sampler"] +_attenuation = cv.enum(ATTENUATION_MODES, lower=True) + + def validate_config(config): if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") + if config.get(CONF_ATTENUATION) == "11db": + _LOGGER.warning( + "`attenuation: 11db` is deprecated, use `attenuation: 12db` instead" + ) + # Alter value here so `config` command prints the recommended change + config[CONF_ATTENUATION] = _attenuation("12db") + return config @@ -47,7 +62,6 @@ def final_validate_config(config): return config -adc_ns = cg.esphome_ns.namespace("adc") ADCSensor = adc_ns.class_( "ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler ) @@ -65,7 +79,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PIN): validate_adc_pin, cv.Optional(CONF_RAW, default=False): cv.boolean, cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All( - cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True) + cv.only_on_esp32, _attenuation ), } ) From 5d2e3a7d8d803d03b3afda680e4fcb11b8e5ca2a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 May 2024 13:14:15 +1200 Subject: [PATCH 1739/2607] Bump version to 2024.5.0b6 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 2e5e9cc9de..786f988f91 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b5" +__version__ = "2024.5.0b6" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 0d3adc8f0c12d5900f63fc36df5dd72c85428229 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 May 2024 17:08:43 +1200 Subject: [PATCH 1740/2607] Bump version to 2024.5.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 786f988f91..9871ea704f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0b6" +__version__ = "2024.5.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 891f56b421456dbc9d523945f6ebf97b1975d0d6 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 15 May 2024 00:14:19 -0500 Subject: [PATCH 1741/2607] [tests] ``test2.yaml`` has become too large (#6750) --- tests/test2.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test2.yaml b/tests/test2.yaml index 2fdef72c08..970076e78b 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -1,10 +1,12 @@ --- esphome: name: $devicename - platform: ESP32 - board: nodemcu-32s build_path: build/test2 +esp32: + board: esp32dev + flash_size: 8MB + globals: - id: my_global_string type: std::string From 9f1ba00b7cc67c03667b6ac23707e9787238fde9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 17:16:04 +1200 Subject: [PATCH 1742/2607] Bump esphome-dashboard from 20240412.0 to 20240429.1 (#6743) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 698ae56447..05e46ca31e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240412.0 +esphome-dashboard==20240429.1 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 From 773951d85eba1031eaca56c1d340f20f8ad59009 Mon Sep 17 00:00:00 2001 From: Alex Boyd Date: Wed, 15 May 2024 17:31:08 -0600 Subject: [PATCH 1743/2607] BedJet: expose the outlet temperature on the climate and as a sensor (#6633) --- CODEOWNERS | 1 + esphome/components/bedjet/__init__.py | 2 +- esphome/components/bedjet/bedjet_codec.cpp | 6 ++ esphome/components/bedjet/bedjet_codec.h | 3 + esphome/components/bedjet/bedjet_const.h | 8 +++ esphome/components/bedjet/climate/__init__.py | 10 ++++ .../bedjet/climate/bedjet_climate.cpp | 15 +++-- .../bedjet/climate/bedjet_climate.h | 3 + esphome/components/bedjet/sensor/__init__.py | 55 +++++++++++++++++++ .../bedjet/sensor/bedjet_sensor.cpp | 34 ++++++++++++ .../components/bedjet/sensor/bedjet_sensor.h | 32 +++++++++++ tests/components/bedjet/common.yaml | 8 +++ 12 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 esphome/components/bedjet/sensor/__init__.py create mode 100644 esphome/components/bedjet/sensor/bedjet_sensor.cpp create mode 100644 esphome/components/bedjet/sensor/bedjet_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index 88f875f368..a661eba9b3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -51,6 +51,7 @@ esphome/components/bang_bang/* @OttoWinter esphome/components/bedjet/* @jhansche esphome/components/bedjet/climate/* @jhansche esphome/components/bedjet/fan/* @jhansche +esphome/components/bedjet/sensor/* @javawizard @jhansche esphome/components/bh1750/* @OttoWinter esphome/components/binary_sensor/* @esphome/core esphome/components/bk72xx/* @kuba2k2 diff --git a/esphome/components/bedjet/__init__.py b/esphome/components/bedjet/__init__.py index 395a5f25e4..a4b8a50eab 100644 --- a/esphome/components/bedjet/__init__.py +++ b/esphome/components/bedjet/__init__.py @@ -31,7 +31,7 @@ CONFIG_SCHEMA = ( BEDJET_CLIENT_SCHEMA = cv.Schema( { - cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub), + cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub), } ) diff --git a/esphome/components/bedjet/bedjet_codec.cpp b/esphome/components/bedjet/bedjet_codec.cpp index 735393ffcb..7e90621235 100644 --- a/esphome/components/bedjet/bedjet_codec.cpp +++ b/esphome/components/bedjet/bedjet_codec.cpp @@ -157,5 +157,11 @@ bool BedjetCodec::compare(const uint8_t *data, uint16_t length) { return explicit_fields_changed; } +/// Converts a BedJet temp step into degrees Celsius. +float bedjet_temp_to_c(uint8_t temp) { + // BedJet temp is "C*2"; to get C, divide by 2. + return temp / 2.0f; +} + } // namespace bedjet } // namespace esphome diff --git a/esphome/components/bedjet/bedjet_codec.h b/esphome/components/bedjet/bedjet_codec.h index 3a41313ada..527e757d7f 100644 --- a/esphome/components/bedjet/bedjet_codec.h +++ b/esphome/components/bedjet/bedjet_codec.h @@ -187,5 +187,8 @@ class BedjetCodec { BedjetStatusPacket buf_; }; +/// Converts a BedJet temp step into degrees Celsius. +float bedjet_temp_to_c(uint8_t temp); + } // namespace bedjet } // namespace esphome diff --git a/esphome/components/bedjet/bedjet_const.h b/esphome/components/bedjet/bedjet_const.h index 27a75b2671..7cac1b61ff 100644 --- a/esphome/components/bedjet/bedjet_const.h +++ b/esphome/components/bedjet/bedjet_const.h @@ -40,6 +40,14 @@ enum BedjetHeatMode { HEAT_MODE_EXTENDED, }; +// Which temperature to use as the climate entity's current temperature reading +enum BedjetTemperatureSource { + // Use the temperature of the air the BedJet is putting out + TEMPERATURE_SOURCE_OUTLET, + // Use the ambient temperature of the room the BedJet is in + TEMPERATURE_SOURCE_AMBIENT +}; + enum BedjetButton : uint8_t { /// Turn BedJet off BTN_OFF = 0x1, diff --git a/esphome/components/bedjet/climate/__init__.py b/esphome/components/bedjet/climate/__init__.py index b12622868f..e454b0922b 100644 --- a/esphome/components/bedjet/climate/__init__.py +++ b/esphome/components/bedjet/climate/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_HEAT_MODE, CONF_ID, CONF_RECEIVE_TIMEOUT, + CONF_TEMPERATURE_SOURCE, CONF_TIME_ID, ) from .. import ( @@ -21,10 +22,15 @@ DEPENDENCIES = ["bedjet"] BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent) BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode") +BedjetTemperatureSource = bedjet_ns.enum("BedjetTemperatureSource") BEDJET_HEAT_MODES = { "heat": BedjetHeatMode.HEAT_MODE_HEAT, "extended": BedjetHeatMode.HEAT_MODE_EXTENDED, } +BEDJET_TEMPERATURE_SOURCES = { + "outlet": BedjetTemperatureSource.TEMPERATURE_SOURCE_OUTLET, + "ambient": BedjetTemperatureSource.TEMPERATURE_SOURCE_AMBIENT, +} CONFIG_SCHEMA = ( climate.CLIMATE_SCHEMA.extend( @@ -33,6 +39,9 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum( BEDJET_HEAT_MODES, lower=True ), + cv.Optional(CONF_TEMPERATURE_SOURCE, default="ambient"): cv.enum( + BEDJET_TEMPERATURE_SOURCES, lower=True + ), } ) .extend(cv.polling_component_schema("60s")) @@ -63,3 +72,4 @@ async def to_code(config): await register_bedjet_child(var, config) cg.add(var.set_heating_mode(config[CONF_HEAT_MODE])) + cg.add(var.set_temperature_source(config[CONF_TEMPERATURE_SOURCE])) diff --git a/esphome/components/bedjet/climate/bedjet_climate.cpp b/esphome/components/bedjet/climate/bedjet_climate.cpp index 431cf614e9..854129f816 100644 --- a/esphome/components/bedjet/climate/bedjet_climate.cpp +++ b/esphome/components/bedjet/climate/bedjet_climate.cpp @@ -8,12 +8,6 @@ namespace bedjet { using namespace esphome::climate; -/// Converts a BedJet temp step into degrees Celsius. -float bedjet_temp_to_c(const uint8_t temp) { - // BedJet temp is "C*2"; to get C, divide by 2. - return temp / 2.0f; -} - static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) { if (fan_step < BEDJET_FAN_SPEED_COUNT) return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step]; @@ -236,9 +230,14 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) { if (converted_temp > 0) this->target_temperature = converted_temp; - converted_temp = bedjet_temp_to_c(data->ambient_temp_step); - if (converted_temp > 0) + if (this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET) { + converted_temp = bedjet_temp_to_c(data->actual_temp_step); + } else { + converted_temp = bedjet_temp_to_c(data->ambient_temp_step); + } + if (converted_temp > 0) { this->current_temperature = converted_temp; + } const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step); if (fan_mode_name != nullptr) { diff --git a/esphome/components/bedjet/climate/bedjet_climate.h b/esphome/components/bedjet/climate/bedjet_climate.h index 48c50d842f..7eaa735a3f 100644 --- a/esphome/components/bedjet/climate/bedjet_climate.h +++ b/esphome/components/bedjet/climate/bedjet_climate.h @@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */ void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; } + /** Sets the temperature source to use for the climate entity's current temperature */ + void set_temperature_source(BedjetTemperatureSource source) { this->temperature_source_ = source; } climate::ClimateTraits traits() override { auto traits = climate::ClimateTraits(); @@ -74,6 +76,7 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli void control(const climate::ClimateCall &call) override; BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT; + BedjetTemperatureSource temperature_source_ = TEMPERATURE_SOURCE_AMBIENT; void reset_state_(); bool update_status_(); diff --git a/esphome/components/bedjet/sensor/__init__.py b/esphome/components/bedjet/sensor/__init__.py new file mode 100644 index 0000000000..756b31de53 --- /dev/null +++ b/esphome/components/bedjet/sensor/__init__.py @@ -0,0 +1,55 @@ +import logging + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) +from .. import ( + BEDJET_CLIENT_SCHEMA, + bedjet_ns, + register_bedjet_child, +) + +_LOGGER = logging.getLogger(__name__) +CODEOWNERS = ["@jhansche", "@javawizard"] +DEPENDENCIES = ["bedjet"] + +CONF_OUTLET_TEMPERATURE = "outlet_temperature" +CONF_AMBIENT_TEMPERATURE = "ambient_temperature" + +BedjetSensor = bedjet_ns.class_("BedjetSensor", cg.Component) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(BedjetSensor), + cv.Optional(CONF_OUTLET_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_AMBIENT_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } +).extend(BEDJET_CLIENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await register_bedjet_child(var, config) + + if outlet_temperature_sensor := config.get(CONF_OUTLET_TEMPERATURE): + sensor_var = await sensor.new_sensor(outlet_temperature_sensor) + cg.add(var.set_outlet_temperature_sensor(sensor_var)) + + if ambient_temperature_sensor := config.get(CONF_AMBIENT_TEMPERATURE): + sensor_var = await sensor.new_sensor(ambient_temperature_sensor) + cg.add(var.set_ambient_temperature_sensor(sensor_var)) diff --git a/esphome/components/bedjet/sensor/bedjet_sensor.cpp b/esphome/components/bedjet/sensor/bedjet_sensor.cpp new file mode 100644 index 0000000000..2fda8c927f --- /dev/null +++ b/esphome/components/bedjet/sensor/bedjet_sensor.cpp @@ -0,0 +1,34 @@ +#include "bedjet_sensor.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace bedjet { + +std::string BedjetSensor::describe() { return "BedJet Sensor"; } + +void BedjetSensor::dump_config() { + ESP_LOGCONFIG(TAG, "BedJet Sensor:"); + LOG_SENSOR(" ", "Outlet Temperature", this->outlet_temperature_sensor_); + LOG_SENSOR(" ", "Ambient Temperature", this->ambient_temperature_sensor_); +} + +void BedjetSensor::on_bedjet_state(bool is_ready) {} + +void BedjetSensor::on_status(const BedjetStatusPacket *data) { + if (this->outlet_temperature_sensor_ != nullptr) { + float converted_temp = bedjet_temp_to_c(data->actual_temp_step); + if (converted_temp > 0) { + this->outlet_temperature_sensor_->publish_state(converted_temp); + } + } + + if (this->ambient_temperature_sensor_ != nullptr) { + float converted_temp = bedjet_temp_to_c(data->ambient_temp_step); + if (converted_temp > 0) { + this->ambient_temperature_sensor_->publish_state(converted_temp); + } + } +} + +} // namespace bedjet +} // namespace esphome diff --git a/esphome/components/bedjet/sensor/bedjet_sensor.h b/esphome/components/bedjet/sensor/bedjet_sensor.h new file mode 100644 index 0000000000..8cbaa863ee --- /dev/null +++ b/esphome/components/bedjet/sensor/bedjet_sensor.h @@ -0,0 +1,32 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/bedjet/bedjet_child.h" +#include "esphome/components/bedjet/bedjet_codec.h" + +namespace esphome { +namespace bedjet { + +class BedjetSensor : public BedJetClient, public Component { + public: + void dump_config() override; + + void on_status(const BedjetStatusPacket *data) override; + void on_bedjet_state(bool is_ready) override; + std::string describe() override; + + void set_outlet_temperature_sensor(sensor::Sensor *outlet_temperature_sensor) { + this->outlet_temperature_sensor_ = outlet_temperature_sensor; + } + void set_ambient_temperature_sensor(sensor::Sensor *ambient_temperature_sensor) { + this->ambient_temperature_sensor_ = ambient_temperature_sensor; + } + + protected: + sensor::Sensor *outlet_temperature_sensor_{nullptr}; + sensor::Sensor *ambient_temperature_sensor_{nullptr}; +}; + +} // namespace bedjet +} // namespace esphome diff --git a/tests/components/bedjet/common.yaml b/tests/components/bedjet/common.yaml index c2be04a49a..1563fc9dae 100644 --- a/tests/components/bedjet/common.yaml +++ b/tests/components/bedjet/common.yaml @@ -26,8 +26,16 @@ climate: name: My Bedjet bedjet_id: bedjet_hub heat_mode: extended + temperature_source: ambient fan: - platform: bedjet name: My Bedjet fan bedjet_id: bedjet_hub + +sensor: + - platform: bedjet + ambient_temperature: + name: My BedJet Ambient Temperature + outlet_temperature: + name: My BedJet Outlet Temperature From 46eee4a4f0c63c88294da9c3f27407af26d2ef98 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Wed, 15 May 2024 23:32:48 +0000 Subject: [PATCH 1744/2607] Add beken_spi_led_strip component (#6515) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../beken_spi_led_strip/__init__.py | 0 .../beken_spi_led_strip/led_strip.cpp | 384 ++++++++++++++++++ .../beken_spi_led_strip/led_strip.h | 85 ++++ .../components/beken_spi_led_strip/light.py | 134 ++++++ .../components/esp32_rmt_led_strip/light.py | 2 +- .../components/rp2040_pio_led_strip/light.py | 2 +- esphome/const.py | 1 + .../beken_spi_led_strip/test.bk72xx.yaml | 7 + .../build_components_base.bk72xx.yaml | 2 +- 10 files changed, 615 insertions(+), 3 deletions(-) create mode 100644 esphome/components/beken_spi_led_strip/__init__.py create mode 100644 esphome/components/beken_spi_led_strip/led_strip.cpp create mode 100644 esphome/components/beken_spi_led_strip/led_strip.h create mode 100644 esphome/components/beken_spi_led_strip/light.py create mode 100644 tests/components/beken_spi_led_strip/test.bk72xx.yaml diff --git a/CODEOWNERS b/CODEOWNERS index a661eba9b3..65ea3b1683 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -52,6 +52,7 @@ esphome/components/bedjet/* @jhansche esphome/components/bedjet/climate/* @jhansche esphome/components/bedjet/fan/* @jhansche esphome/components/bedjet/sensor/* @javawizard @jhansche +esphome/components/beken_spi_led_strip/* @Mat931 esphome/components/bh1750/* @OttoWinter esphome/components/binary_sensor/* @esphome/core esphome/components/bk72xx/* @kuba2k2 diff --git a/esphome/components/beken_spi_led_strip/__init__.py b/esphome/components/beken_spi_led_strip/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/beken_spi_led_strip/led_strip.cpp b/esphome/components/beken_spi_led_strip/led_strip.cpp new file mode 100644 index 0000000000..04c8649b90 --- /dev/null +++ b/esphome/components/beken_spi_led_strip/led_strip.cpp @@ -0,0 +1,384 @@ +#include "led_strip.h" + +#ifdef USE_BK72XX + +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +extern "C" { +#include "rtos_pub.h" +#include "spi.h" +#include "arm_arch.h" +#include "general_dma_pub.h" +#include "gpio_pub.h" +#include "icu_pub.h" +#undef SPI_DAT +#undef SPI_BASE +}; + +static const uint32_t SPI_TX_DMA_CHANNEL = GDMA_CHANNEL_3; + +// TODO: Check if SPI_PERI_CLK_DCO depends on the chip variant +static const uint32_t SPI_PERI_CLK_26M = 26000000; +static const uint32_t SPI_PERI_CLK_DCO = 120000000; + +static const uint32_t SPI_BASE = 0x00802700; +static const uint32_t SPI_DAT = SPI_BASE + 3 * 4; +static const uint32_t SPI_CONFIG = SPI_BASE + 1 * 4; + +static const uint32_t SPI_TX_EN = 1 << 0; +static const uint32_t CTRL_NSSMD_3 = 1 << 17; +static const uint32_t SPI_TX_FINISH_EN = 1 << 2; +static const uint32_t SPI_RX_FINISH_EN = 1 << 3; + +namespace esphome { +namespace beken_spi_led_strip { + +static const char *const TAG = "beken_spi_led_strip"; + +struct spi_data_t { + SemaphoreHandle_t dma_tx_semaphore; + volatile bool tx_in_progress; + bool first_run; +}; + +static spi_data_t *spi_data = nullptr; + +static void set_spi_ctrl_register(unsigned long bit, bool val) { + uint32_t value = REG_READ(SPI_CTRL); + if (val == 0) { + value &= ~bit; + } else if (val == 1) { + value |= bit; + } + REG_WRITE(SPI_CTRL, value); +} + +static void set_spi_config_register(unsigned long bit, bool val) { + uint32_t value = REG_READ(SPI_CONFIG); + if (val == 0) { + value &= ~bit; + } else if (val == 1) { + value |= bit; + } + REG_WRITE(SPI_CONFIG, value); +} + +void spi_dma_tx_enable(bool enable) { + GDMA_CFG_ST en_cfg; + set_spi_config_register(SPI_TX_EN, enable ? 1 : 0); + en_cfg.channel = SPI_TX_DMA_CHANNEL; + en_cfg.param = enable ? 1 : 0; + sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg); +} + +static void spi_set_clock(uint32_t max_hz) { + int source_clk = 0; + int spi_clk = 0; + int div = 0; + uint32_t param; + if (max_hz > 4333000) { + if (max_hz > 30000000) { + spi_clk = 30000000; + } else { + spi_clk = max_hz; + } + sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_DOWN, ¶m); + source_clk = SPI_PERI_CLK_DCO; + param = PCLK_POSI_SPI; + sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_DCO, ¶m); + param = PWD_SPI_CLK_BIT; + sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, ¶m); + } else { + spi_clk = max_hz; +#if CFG_XTAL_FREQUENCE + source_clk = CFG_XTAL_FREQUENCE; +#else + source_clk = SPI_PERI_CLK_26M; +#endif + param = PCLK_POSI_SPI; + sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, ¶m); + } + div = ((source_clk >> 1) / spi_clk); + if (div < 2) { + div = 2; + } else if (div >= 255) { + div = 255; + } + param = REG_READ(SPI_CTRL); + param &= ~(SPI_CKR_MASK << SPI_CKR_POSI); + param |= (div << SPI_CKR_POSI); + REG_WRITE(SPI_CTRL, param); + ESP_LOGD(TAG, "target frequency: %d, actual frequency: %d", max_hz, source_clk / 2 / div); +} + +void spi_dma_tx_finish_callback(unsigned int param) { + spi_data->tx_in_progress = false; + xSemaphoreGive(spi_data->dma_tx_semaphore); + spi_dma_tx_enable(0); +} + +void BekenSPILEDStripLightOutput::setup() { + ESP_LOGCONFIG(TAG, "Setting up Beken SPI LED Strip..."); + + size_t buffer_size = this->get_buffer_size_(); + size_t dma_buffer_size = (buffer_size * 8) + (2 * 64); + + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->buf_ = allocator.allocate(buffer_size); + if (this->buf_ == nullptr) { + ESP_LOGE(TAG, "Cannot allocate LED buffer!"); + this->mark_failed(); + return; + } + + this->effect_data_ = allocator.allocate(this->num_leds_); + if (this->effect_data_ == nullptr) { + ESP_LOGE(TAG, "Cannot allocate effect data!"); + this->mark_failed(); + return; + } + + this->dma_buf_ = allocator.allocate(dma_buffer_size); + if (this->dma_buf_ == nullptr) { + ESP_LOGE(TAG, "Cannot allocate DMA buffer!"); + this->mark_failed(); + return; + } + + memset(this->buf_, 0, buffer_size); + memset(this->effect_data_, 0, this->num_leds_); + memset(this->dma_buf_, 0, dma_buffer_size); + + uint32_t value = PCLK_POSI_SPI; + sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, &value); + + value = PWD_SPI_CLK_BIT; + sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, &value); + + if (spi_data != nullptr) { + ESP_LOGE(TAG, "SPI device already initialized!"); + this->mark_failed(); + return; + } + + spi_data = (spi_data_t *) calloc(1, sizeof(spi_data_t)); + if (spi_data == nullptr) { + ESP_LOGE(TAG, "Cannot allocate spi_data!"); + this->mark_failed(); + return; + } + + spi_data->dma_tx_semaphore = xSemaphoreCreateBinary(); + if (spi_data->dma_tx_semaphore == nullptr) { + ESP_LOGE(TAG, "TX Semaphore init faild!"); + this->mark_failed(); + return; + } + + spi_data->first_run = true; + + set_spi_ctrl_register(MSTEN, 0); + set_spi_ctrl_register(BIT_WDTH, 0); + spi_set_clock(this->spi_frequency_); + set_spi_ctrl_register(CKPOL, 0); + set_spi_ctrl_register(CKPHA, 0); + set_spi_ctrl_register(MSTEN, 1); + set_spi_ctrl_register(SPIEN, 1); + + set_spi_ctrl_register(TXINT_EN, 0); + set_spi_ctrl_register(RXINT_EN, 0); + set_spi_config_register(SPI_TX_FINISH_EN, 1); + set_spi_config_register(SPI_RX_FINISH_EN, 1); + set_spi_ctrl_register(RXOVR_EN, 0); + set_spi_ctrl_register(TXOVR_EN, 0); + + value = REG_READ(SPI_CTRL); + value &= ~CTRL_NSSMD_3; + value |= (1 << 17); + REG_WRITE(SPI_CTRL, value); + + value = GFUNC_MODE_SPI_DMA; + sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &value); + set_spi_ctrl_register(SPI_S_CS_UP_INT_EN, 0); + + GDMA_CFG_ST en_cfg; + GDMACFG_TPYES_ST init_cfg; + memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST)); + + init_cfg.dstdat_width = 8; + init_cfg.srcdat_width = 32; + init_cfg.dstptr_incr = 0; + init_cfg.srcptr_incr = 1; + init_cfg.src_start_addr = this->dma_buf_; + init_cfg.dst_start_addr = (void *) SPI_DAT; // SPI_DMA_REG4_TXFIFO + init_cfg.channel = SPI_TX_DMA_CHANNEL; + init_cfg.prio = 0; // 10 + init_cfg.u.type4.src_loop_start_addr = this->dma_buf_; + init_cfg.u.type4.src_loop_end_addr = this->dma_buf_ + dma_buffer_size; + init_cfg.half_fin_handler = nullptr; + init_cfg.fin_handler = spi_dma_tx_finish_callback; + init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ; + init_cfg.dst_module = GDMA_X_DST_GSPI_TX_REQ; // GDMA_X_DST_HSSPI_TX_REQ + sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (void *) &init_cfg); + en_cfg.channel = SPI_TX_DMA_CHANNEL; + en_cfg.param = dma_buffer_size; + sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *) &en_cfg); + en_cfg.channel = SPI_TX_DMA_CHANNEL; + en_cfg.param = 0; + sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_WORK_MODE, (void *) &en_cfg); + en_cfg.channel = SPI_TX_DMA_CHANNEL; + en_cfg.param = 0; + sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_SRCADDR_LOOP, &en_cfg); + + spi_dma_tx_enable(0); + + value = REG_READ(SPI_CONFIG); + value &= ~(0xFFF << 8); + value |= ((dma_buffer_size & 0xFFF) << 8); + REG_WRITE(SPI_CONFIG, value); +} + +void BekenSPILEDStripLightOutput::set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency) { + this->bit0_ = bit0; + this->bit1_ = bit1; + this->spi_frequency_ = spi_frequency; +} + +void BekenSPILEDStripLightOutput::write_state(light::LightState *state) { + // protect from refreshing too often + uint32_t now = micros(); + if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) { + // try again next loop iteration, so that this change won't get lost + this->schedule_show(); + return; + } + this->last_refresh_ = now; + this->mark_shown_(); + + ESP_LOGVV(TAG, "Writing RGB values to bus..."); + + if (spi_data == nullptr) { + ESP_LOGE(TAG, "SPI not initialized"); + this->status_set_warning(); + return; + } + + if (!spi_data->first_run && !xSemaphoreTake(spi_data->dma_tx_semaphore, 10 / portTICK_PERIOD_MS)) { + ESP_LOGE(TAG, "Timed out waiting for semaphore"); + return; + } + + if (spi_data->tx_in_progress) { + ESP_LOGE(TAG, "tx_in_progress is set"); + this->status_set_warning(); + return; + } + + spi_data->tx_in_progress = true; + + size_t buffer_size = this->get_buffer_size_(); + size_t size = 0; + uint8_t *psrc = this->buf_; + uint8_t *pdest = this->dma_buf_ + 64; + // The 64 byte padding is a workaround for a SPI DMA bug where the + // output doesn't exactly start at the beginning of dma_buf_ + + while (size < buffer_size) { + uint8_t b = *psrc; + for (int i = 0; i < 8; i++) { + *pdest++ = b & (1 << (7 - i)) ? this->bit1_ : this->bit0_; + } + size++; + psrc++; + } + + spi_data->first_run = false; + spi_dma_tx_enable(1); + + this->status_clear_warning(); +} + +light::ESPColorView BekenSPILEDStripLightOutput::get_view_internal(int32_t index) const { + int32_t r = 0, g = 0, b = 0; + switch (this->rgb_order_) { + case ORDER_RGB: + r = 0; + g = 1; + b = 2; + break; + case ORDER_RBG: + r = 0; + g = 2; + b = 1; + break; + case ORDER_GRB: + r = 1; + g = 0; + b = 2; + break; + case ORDER_GBR: + r = 2; + g = 0; + b = 1; + break; + case ORDER_BGR: + r = 2; + g = 1; + b = 0; + break; + case ORDER_BRG: + r = 1; + g = 2; + b = 0; + break; + } + uint8_t multiplier = this->is_rgbw_ || this->is_wrgb_ ? 4 : 3; + uint8_t white = this->is_wrgb_ ? 0 : 3; + + return {this->buf_ + (index * multiplier) + r + this->is_wrgb_, + this->buf_ + (index * multiplier) + g + this->is_wrgb_, + this->buf_ + (index * multiplier) + b + this->is_wrgb_, + this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white : nullptr, + &this->effect_data_[index], + &this->correction_}; +} + +void BekenSPILEDStripLightOutput::dump_config() { + ESP_LOGCONFIG(TAG, "Beken SPI LED Strip:"); + ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_); + const char *rgb_order; + switch (this->rgb_order_) { + case ORDER_RGB: + rgb_order = "RGB"; + break; + case ORDER_RBG: + rgb_order = "RBG"; + break; + case ORDER_GRB: + rgb_order = "GRB"; + break; + case ORDER_GBR: + rgb_order = "GBR"; + break; + case ORDER_BGR: + rgb_order = "BGR"; + break; + case ORDER_BRG: + rgb_order = "BRG"; + break; + default: + rgb_order = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order); + ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_); + ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_); +} + +float BekenSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; } + +} // namespace beken_spi_led_strip +} // namespace esphome + +#endif // USE_BK72XX diff --git a/esphome/components/beken_spi_led_strip/led_strip.h b/esphome/components/beken_spi_led_strip/led_strip.h new file mode 100644 index 0000000000..705f9102a9 --- /dev/null +++ b/esphome/components/beken_spi_led_strip/led_strip.h @@ -0,0 +1,85 @@ +#pragma once + +#ifdef USE_BK72XX + +#include "esphome/components/light/addressable_light.h" +#include "esphome/components/light/light_output.h" +#include "esphome/core/color.h" +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace beken_spi_led_strip { + +enum RGBOrder : uint8_t { + ORDER_RGB, + ORDER_RBG, + ORDER_GRB, + ORDER_GBR, + ORDER_BGR, + ORDER_BRG, +}; + +class BekenSPILEDStripLightOutput : public light::AddressableLight { + public: + void setup() override; + void write_state(light::LightState *state) override; + float get_setup_priority() const override; + + int32_t size() const override { return this->num_leds_; } + light::LightTraits get_traits() override { + auto traits = light::LightTraits(); + if (this->is_rgbw_ || this->is_wrgb_) { + traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE}); + } else { + traits.set_supported_color_modes({light::ColorMode::RGB}); + } + return traits; + } + + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; } + void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; } + void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; } + + /// Set a maximum refresh rate in µs as some lights do not like being updated too often. + void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; } + + void set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency); + + void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; } + + void clear_effect_data() override { + for (int i = 0; i < this->size(); i++) + this->effect_data_[i] = 0; + } + + void dump_config() override; + + protected: + light::ESPColorView get_view_internal(int32_t index) const override; + + size_t get_buffer_size_() const { return this->num_leds_ * (this->is_rgbw_ || this->is_wrgb_ ? 4 : 3); } + + uint8_t *buf_{nullptr}; + uint8_t *effect_data_{nullptr}; + uint8_t *dma_buf_{nullptr}; + + uint8_t pin_; + uint16_t num_leds_; + bool is_rgbw_; + bool is_wrgb_; + + uint32_t spi_frequency_{6666666}; + uint8_t bit0_{0xE0}; + uint8_t bit1_{0xFC}; + RGBOrder rgb_order_; + + uint32_t last_refresh_{0}; + optional max_refresh_rate_{}; +}; + +} // namespace beken_spi_led_strip +} // namespace esphome + +#endif // USE_BK72XX diff --git a/esphome/components/beken_spi_led_strip/light.py b/esphome/components/beken_spi_led_strip/light.py new file mode 100644 index 0000000000..2a1aa05c79 --- /dev/null +++ b/esphome/components/beken_spi_led_strip/light.py @@ -0,0 +1,134 @@ +from dataclasses import dataclass + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import libretiny, light +from esphome.const import ( + CONF_CHIPSET, + CONF_IS_RGBW, + CONF_MAX_REFRESH_RATE, + CONF_NUM_LEDS, + CONF_OUTPUT_ID, + CONF_PIN, + CONF_RGB_ORDER, +) + +CODEOWNERS = ["@Mat931"] +DEPENDENCIES = ["libretiny"] + +beken_spi_led_strip_ns = cg.esphome_ns.namespace("beken_spi_led_strip") +BekenSPILEDStripLightOutput = beken_spi_led_strip_ns.class_( + "BekenSPILEDStripLightOutput", light.AddressableLight +) + +RGBOrder = beken_spi_led_strip_ns.enum("RGBOrder") + +RGB_ORDERS = { + "RGB": RGBOrder.ORDER_RGB, + "RBG": RGBOrder.ORDER_RBG, + "GRB": RGBOrder.ORDER_GRB, + "GBR": RGBOrder.ORDER_GBR, + "BGR": RGBOrder.ORDER_BGR, + "BRG": RGBOrder.ORDER_BRG, +} + + +@dataclass +class LEDStripTimings: + bit0: int + bit1: int + spi_frequency: int + + +CHIPSETS = { + "WS2812": LEDStripTimings( + 0b11100000, 0b11111100, 6666666 + ), # Clock divider: 9, Bit time: 1350ns + "SK6812": LEDStripTimings( + 0b11000000, 0b11111000, 7500000 + ), # Clock divider: 8, Bit time: 1200ns + "APA106": LEDStripTimings( + 0b11000000, 0b11111110, 5454545 + ), # Clock divider: 11, Bit time: 1650ns + "SM16703": LEDStripTimings( + 0b11000000, 0b11111110, 7500000 + ), # Clock divider: 8, Bit time: 1200ns +} + + +CONF_IS_WRGB = "is_wrgb" + +SUPPORTED_PINS = { + libretiny.const.FAMILY_BK7231N: [16], + libretiny.const.FAMILY_BK7231T: [16], + libretiny.const.FAMILY_BK7251: [16], +} + + +def _validate_pin(value): + family = libretiny.get_libretiny_family() + if family not in SUPPORTED_PINS: + raise cv.Invalid(f"Chip family {family} is not supported.") + if value not in SUPPORTED_PINS[family]: + supported_pin_info = ", ".join(f"{x}" for x in SUPPORTED_PINS[family]) + raise cv.Invalid( + f"Pin {value} is not supported on the {family}. Supported pins: {supported_pin_info}" + ) + return value + + +def _validate_num_leds(value): + max_num_leds = 165 # 170 + if value[CONF_IS_RGBW] or value[CONF_IS_WRGB]: + max_num_leds = 123 # 127 + if value[CONF_NUM_LEDS] > max_num_leds: + raise cv.Invalid( + f"The maximum number of LEDs for this configuration is {max_num_leds}.", + path=CONF_NUM_LEDS, + ) + return value + + +CONFIG_SCHEMA = cv.All( + light.ADDRESSABLE_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(BekenSPILEDStripLightOutput), + cv.Required(CONF_PIN): cv.All( + pins.internal_gpio_output_pin_number, _validate_pin + ), + cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, + cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True), + cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, + cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), + cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, + cv.Optional(CONF_IS_WRGB, default=False): cv.boolean, + } + ), + _validate_num_leds, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) + await light.register_light(var, config) + await cg.register_component(var, config) + + cg.add(var.set_num_leds(config[CONF_NUM_LEDS])) + cg.add(var.set_pin(config[CONF_PIN])) + + if CONF_MAX_REFRESH_RATE in config: + cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) + + chipset = CHIPSETS[config[CONF_CHIPSET]] + cg.add( + var.set_led_params( + chipset.bit0, + chipset.bit1, + chipset.spi_frequency, + ) + ) + + cg.add(var.set_rgb_order(config[CONF_RGB_ORDER])) + cg.add(var.set_is_rgbw(config[CONF_IS_RGBW])) + cg.add(var.set_is_wrgb(config[CONF_IS_WRGB])) diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 1c15a468d9..4c8472b8d2 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -6,6 +6,7 @@ from esphome import pins from esphome.components import esp32_rmt, light from esphome.const import ( CONF_CHIPSET, + CONF_IS_RGBW, CONF_MAX_REFRESH_RATE, CONF_NUM_LEDS, CONF_OUTPUT_ID, @@ -52,7 +53,6 @@ CHIPSETS = { } -CONF_IS_RGBW = "is_rgbw" CONF_IS_WRGB = "is_wrgb" CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_LOW = "bit0_low" diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index 6c51b57e97..202263c914 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -5,6 +5,7 @@ from esphome.components import light, rp2040 from esphome.const import ( CONF_CHIPSET, CONF_ID, + CONF_IS_RGBW, CONF_NUM_LEDS, CONF_OUTPUT_ID, CONF_PIN, @@ -165,7 +166,6 @@ CHIPSETS = { "SM16703": LEDStripTimings(17, 52, 52, 17), } -CONF_IS_RGBW = "is_rgbw" CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_LOW = "bit0_low" CONF_BIT1_HIGH = "bit1_high" diff --git a/esphome/const.py b/esphome/const.py index 542183d3b2..eb48080040 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -399,6 +399,7 @@ CONF_INVERT_COLORS = "invert_colors" CONF_INVERTED = "inverted" CONF_IP_ADDRESS = "ip_address" CONF_IRQ_PIN = "irq_pin" +CONF_IS_RGBW = "is_rgbw" CONF_JS_INCLUDE = "js_include" CONF_JS_URL = "js_url" CONF_JVC = "jvc" diff --git a/tests/components/beken_spi_led_strip/test.bk72xx.yaml b/tests/components/beken_spi_led_strip/test.bk72xx.yaml new file mode 100644 index 0000000000..15409caeaf --- /dev/null +++ b/tests/components/beken_spi_led_strip/test.bk72xx.yaml @@ -0,0 +1,7 @@ +light: + - platform: beken_spi_led_strip + rgb_order: GRB + pin: P16 + num_leds: 30 + chipset: ws2812 + name: "My Light" diff --git a/tests/test_build_components/build_components_base.bk72xx.yaml b/tests/test_build_components/build_components_base.bk72xx.yaml index 9fd9431826..9a4e15d5cf 100644 --- a/tests/test_build_components/build_components_base.bk72xx.yaml +++ b/tests/test_build_components/build_components_base.bk72xx.yaml @@ -3,7 +3,7 @@ esphome: friendly_name: $component_name bk72xx: - board: cb3s + board: generic-bk7231n-qfn32-tuya logger: level: VERY_VERBOSE From 073fb4c124c6725c262d16b5a94bfac43f9cc344 Mon Sep 17 00:00:00 2001 From: ius Date: Thu, 16 May 2024 01:33:15 +0200 Subject: [PATCH 1745/2607] i2c: fix format string specifiers (#6746) --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index cbb748cca1..3a9c229778 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -56,7 +56,7 @@ void IDFI2CBus::setup() { this->mark_failed(); return; } else { - ESP_LOGV(TAG, "i2c_timeout set to %d ticks (%d us)", timeout_ * 80, timeout_); + ESP_LOGV(TAG, "i2c_timeout set to %" PRIu32 " ticks (%" PRIu32 " us)", timeout_ * 80, timeout_); } } err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, ESP_INTR_FLAG_IRAM); From 8952719045f2fb0ed53d9c014d682933d10960ae Mon Sep 17 00:00:00 2001 From: lbilger Date: Thu, 16 May 2024 01:33:27 +0200 Subject: [PATCH 1746/2607] Allow one timing to cancel others (#6744) Co-authored-by: Lars Bilger --- esphome/components/binary_sensor/automation.cpp | 5 +++++ esphome/components/binary_sensor/automation.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/esphome/components/binary_sensor/automation.cpp b/esphome/components/binary_sensor/automation.cpp index 7ac201b2db..c2e76246aa 100644 --- a/esphome/components/binary_sensor/automation.cpp +++ b/esphome/components/binary_sensor/automation.cpp @@ -98,6 +98,11 @@ void binary_sensor::MultiClickTrigger::schedule_is_not_valid_(uint32_t max_lengt this->schedule_cooldown_(); }); } +void binary_sensor::MultiClickTrigger::cancel() { + ESP_LOGV(TAG, "Multi Click: Sequence explicitly cancelled."); + this->is_valid_ = false; + this->schedule_cooldown_(); +} void binary_sensor::MultiClickTrigger::trigger_() { ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!"); this->at_index_.reset(); diff --git a/esphome/components/binary_sensor/automation.h b/esphome/components/binary_sensor/automation.h index a5e9d208a1..12b07a05e3 100644 --- a/esphome/components/binary_sensor/automation.h +++ b/esphome/components/binary_sensor/automation.h @@ -105,6 +105,8 @@ class MultiClickTrigger : public Trigger<>, public Component { void set_invalid_cooldown(uint32_t invalid_cooldown) { this->invalid_cooldown_ = invalid_cooldown; } + void cancel(); + protected: void on_state_(bool state); void schedule_cooldown_(); From ebfccc64c7f2b7274a79e4cfaf19e1d46cc87bb2 Mon Sep 17 00:00:00 2001 From: Daniel Mahaney Date: Wed, 15 May 2024 19:33:52 -0400 Subject: [PATCH 1747/2607] fix rp2040_pio_led flicker and proper multi-strip support (#6194) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../rp2040_pio_led_strip/led_strip.cpp | 75 +++++++++++++++---- .../rp2040_pio_led_strip/led_strip.h | 20 +++++ .../components/rp2040_pio_led_strip/light.py | 65 +++++++++------- 3 files changed, 122 insertions(+), 38 deletions(-) diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.cpp b/esphome/components/rp2040_pio_led_strip/led_strip.cpp index c04419a9bf..3e5e82898d 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.cpp +++ b/esphome/components/rp2040_pio_led_strip/led_strip.cpp @@ -6,6 +6,7 @@ #include "esphome/core/log.h" #include +#include #include #include @@ -14,6 +15,15 @@ namespace rp2040_pio_led_strip { static const char *TAG = "rp2040_pio_led_strip"; +static uint8_t num_instance_[2] = {0, 0}; +static std::map chipset_offsets_ = { + {CHIPSET_WS2812, 0}, {CHIPSET_WS2812B, 0}, {CHIPSET_SK6812, 0}, {CHIPSET_SM16703, 0}, {CHIPSET_CUSTOM, 0}, +}; +static std::map conf_count_ = { + {CHIPSET_WS2812, false}, {CHIPSET_WS2812B, false}, {CHIPSET_SK6812, false}, + {CHIPSET_SM16703, false}, {CHIPSET_CUSTOM, false}, +}; + void RP2040PIOLEDStripLightOutput::setup() { ESP_LOGCONFIG(TAG, "Setting up RP2040 LED Strip..."); @@ -34,24 +44,71 @@ void RP2040PIOLEDStripLightOutput::setup() { return; } + // Initialize the PIO program + // Select PIO instance to use (0 or 1) - this->pio_ = pio0; if (this->pio_ == nullptr) { ESP_LOGE(TAG, "Failed to claim PIO instance"); this->mark_failed(); return; } - // Load the assembled program into the PIO and get its location in the PIO's instruction memory - uint offset = pio_add_program(this->pio_, this->program_); + // if there are multiple strips, we can reuse the same PIO program and save space + // but there are only 4 state machines on each PIO so we can only have 4 strips per PIO + uint offset = 0; + + if (num_instance_[this->pio_ == pio0 ? 0 : 1] > 4) { + ESP_LOGE(TAG, "Too many instances of PIO program"); + this->mark_failed(); + return; + } + // keep track of how many instances of the PIO program are running on each PIO + num_instance_[this->pio_ == pio0 ? 0 : 1]++; + + // if there are multiple strips of the same chipset, we can reuse the same PIO program and save space + if (this->conf_count_[this->chipset_]) { + offset = chipset_offsets_[this->chipset_]; + } else { + // Load the assembled program into the PIO and get its location in the PIO's instruction memory and save it + offset = pio_add_program(this->pio_, this->program_); + chipset_offsets_[this->chipset_] = offset; + conf_count_[this->chipset_] = true; + } // Configure the state machine's PIO, and start it this->sm_ = pio_claim_unused_sm(this->pio_, true); if (this->sm_ < 0) { + // in theory this code should never be reached ESP_LOGE(TAG, "Failed to claim PIO state machine"); this->mark_failed(); return; } + + // Initalize the DMA channel (Note: There are 12 DMA channels and 8 state machines so we won't run out) + + this->dma_chan_ = dma_claim_unused_channel(true); + if (this->dma_chan_ < 0) { + ESP_LOGE(TAG, "Failed to claim DMA channel"); + this->mark_failed(); + return; + } + + this->dma_config_ = dma_channel_get_default_config(this->dma_chan_); + channel_config_set_transfer_data_size( + &this->dma_config_, + DMA_SIZE_8); // 8 bit transfers (could be 32 but the pio program would need to be changed to handle junk data) + channel_config_set_read_increment(&this->dma_config_, true); // increment the read address + channel_config_set_write_increment(&this->dma_config_, false); // don't increment the write address + channel_config_set_dreq(&this->dma_config_, + pio_get_dreq(this->pio_, this->sm_, true)); // set the DREQ to the state machine's TX FIFO + + dma_channel_configure(this->dma_chan_, &this->dma_config_, + &this->pio_->txf[this->sm_], // write to the state machine's TX FIFO + this->buf_, // read from memory + this->is_rgbw_ ? num_leds_ * 4 : num_leds_ * 3, // number of bytes to transfer + false // don't start yet + ); + this->init_(this->pio_, this->sm_, offset, this->pin_, this->max_refresh_rate_); } @@ -68,16 +125,8 @@ void RP2040PIOLEDStripLightOutput::write_state(light::LightState *state) { return; } - // assemble bits in buffer to 32 bit words with ex for GBR: 0bGGGGGGGGRRRRRRRRBBBBBBBB00000000 - for (int i = 0; i < this->num_leds_; i++) { - uint8_t multiplier = this->is_rgbw_ ? 4 : 3; - uint8_t c1 = this->buf_[(i * multiplier) + 0]; - uint8_t c2 = this->buf_[(i * multiplier) + 1]; - uint8_t c3 = this->buf_[(i * multiplier) + 2]; - uint8_t w = this->is_rgbw_ ? this->buf_[(i * 4) + 3] : 0; - uint32_t color = encode_uint32(c1, c2, c3, w); - pio_sm_put_blocking(this->pio_, this->sm_, color); - } + // the bits are already in the correct order for the pio program so we can just copy the buffer using DMA + dma_channel_transfer_from_buffer_now(this->dma_chan_, this->buf_, this->get_buffer_size_()); } light::ESPColorView RP2040PIOLEDStripLightOutput::get_view_internal(int32_t index) const { diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.h b/esphome/components/rp2040_pio_led_strip/led_strip.h index 25ef9ca55f..9976842f02 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.h +++ b/esphome/components/rp2040_pio_led_strip/led_strip.h @@ -9,9 +9,11 @@ #include "esphome/components/light/addressable_light.h" #include "esphome/components/light/light_output.h" +#include #include #include #include +#include namespace esphome { namespace rp2040_pio_led_strip { @@ -25,6 +27,15 @@ enum RGBOrder : uint8_t { ORDER_BRG, }; +enum Chipset : uint8_t { + CHIPSET_WS2812, + CHIPSET_WS2812B, + CHIPSET_SK6812, + CHIPSET_SM16703, + CHIPSET_APA102, + CHIPSET_CUSTOM = 0xFF, +}; + inline const char *rgb_order_to_string(RGBOrder order) { switch (order) { case ORDER_RGB: @@ -69,6 +80,7 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { void set_program(const pio_program_t *program) { this->program_ = program; } void set_init_function(init_fn init) { this->init_ = init; } + void set_chipset(Chipset chipset) { this->chipset_ = chipset; }; void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; } void clear_effect_data() override { for (int i = 0; i < this->size(); i++) { @@ -92,14 +104,22 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { pio_hw_t *pio_; uint sm_; + uint dma_chan_; + dma_channel_config dma_config_; RGBOrder rgb_order_{ORDER_RGB}; + Chipset chipset_{CHIPSET_CUSTOM}; uint32_t last_refresh_{0}; float max_refresh_rate_; const pio_program_t *program_; init_fn init_; + + private: + inline static int num_instance_[2]; + inline static std::map conf_count_; + inline static std::map chipset_offsets_; }; } // namespace rp2040_pio_led_strip diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index 202263c914..8dd2549ad4 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -68,12 +68,15 @@ static inline void rp2040_pio_led_strip_driver_{id}_init(PIO pio, uint sm, uint pio_sm_config c = rp2040_pio_led_strip_{id}_program_get_default_config(offset); sm_config_set_set_pins(&c, pin, 1); - sm_config_set_out_shift(&c, false, true, {32 if rgbw else 24}); + sm_config_set_out_shift(&c, false, true, 8); sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); - int cycles_per_bit = 69; - float div = 2.409; - sm_config_set_clkdiv(&c, div); + // target frequency is 57.5MHz + long clk = clock_get_hz(clk_sys); + long target_freq = 57500000; + int n = 2; + int f = round(((clk / target_freq) - n ) * 256); + sm_config_set_clkdiv_int_frac(&c, n, f); pio_sm_init(pio, sm, offset, &c); @@ -86,8 +89,9 @@ static inline void rp2040_pio_led_strip_driver_{id}_init(PIO pio, uint sm, uint .wrap_target awaiting_data: ; Wait for data in FIFO queue + ; out null, 24 ; discard the byte lane replication of the FIFO since we only need 8 bits (not needed????) pull block ; this will block until there is data in the FIFO queue and then it will pull it into the shift register - set y, {31 if rgbw else 23} ; set y to the number of bits to write counting 0, (23 if RGB, 31 if RGBW) + set y, 7 ; set y to the number of bits to write counting 0, (always 7 because we are doing one word at a time) mainloop: ; go through each bit in the shift register and jump to the appropriate label @@ -95,7 +99,15 @@ mainloop: out x, 1 jmp !x, writezero - jmp writeone + +writeone: + ; Write T1H and T1L bits to the output pin + set pins, 1 [{t1h}] +{nops_t1h} + set pins, 0 [{t1l}] +{nops_t1l} + jmp y--, mainloop + jmp awaiting_data writezero: ; Write T0H and T0L bits to the output pin @@ -106,14 +118,7 @@ writezero: jmp y--, mainloop jmp awaiting_data -writeone: - ; Write T1H and T1L bits to the output pin - set pins, 1 [{t1h}] -{nops_t1h} - set pins, 0 [{t1l}] -{nops_t1l} - jmp y--, mainloop - jmp awaiting_data + .wrap""" @@ -139,7 +144,15 @@ RP2040PIOLEDStripLightOutput = rp2040_pio_led_strip_ns.class_( RGBOrder = rp2040_pio_led_strip_ns.enum("RGBOrder") -Chipsets = rp2040_pio_led_strip_ns.enum("Chipset") +Chipset = rp2040_pio_led_strip_ns.enum("Chipset") + +CHIPSETS = { + "WS2812": Chipset.CHIPSET_WS2812, + "WS2812B": Chipset.CHIPSET_WS2812B, + "SK6812": Chipset.CHIPSET_SK6812, + "SM16703": Chipset.CHIPSET_SM16703, + "CUSTOM": Chipset.CHIPSET_CUSTOM, +} @dataclass @@ -159,10 +172,10 @@ RGB_ORDERS = { "BRG": RGBOrder.ORDER_BRG, } -CHIPSETS = { - "WS2812": LEDStripTimings(20, 43, 41, 31), - "WS2812B": LEDStripTimings(23, 46, 46, 23), - "SK6812": LEDStripTimings(17, 52, 31, 31), +CHIPSET_TIMINGS = { + "WS2812": LEDStripTimings(20, 40, 46, 34), + "WS2812B": LEDStripTimings(23, 49, 46, 26), + "SK6812": LEDStripTimings(17, 52, 34, 34), "SM16703": LEDStripTimings(17, 52, 52, 17), } @@ -192,7 +205,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True), cv.Required(CONF_PIO): cv.one_of(0, 1, int=True), - cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), + cv.Optional(CONF_CHIPSET): cv.enum(CHIPSETS, upper=True), cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, cv.Inclusive( CONF_BIT0_HIGH, @@ -238,7 +251,8 @@ async def to_code(config): key = f"led_strip_{id}" - if CONF_CHIPSET in config: + if chipset := config.get(CONF_CHIPSET): + cg.add(var.set_chipset(chipset)) _LOGGER.info("Generating PIO assembly code") rp2040.add_pio_file( __name__, @@ -246,13 +260,14 @@ async def to_code(config): generate_assembly_code( id, config[CONF_IS_RGBW], - CHIPSETS[config[CONF_CHIPSET]].T0H, - CHIPSETS[config[CONF_CHIPSET]].T0L, - CHIPSETS[config[CONF_CHIPSET]].T1H, - CHIPSETS[config[CONF_CHIPSET]].T1L, + CHIPSET_TIMINGS[chipset].T0H, + CHIPSET_TIMINGS[chipset].T0L, + CHIPSET_TIMINGS[chipset].T1H, + CHIPSET_TIMINGS[chipset].T1L, ), ) else: + cg.add(var.set_chipset(Chipset.CHIPSET_CUSTOM)) _LOGGER.info("Generating custom PIO assembly code") rp2040.add_pio_file( __name__, From 08509f775529a0ed07b3d0958208cc9f5cb51d86 Mon Sep 17 00:00:00 2001 From: heggi Date: Thu, 16 May 2024 03:35:17 +0400 Subject: [PATCH 1748/2607] Mirage remote receiver & transmitter (#6479) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/remote_base/__init__.py | 38 +++++++++ .../remote_base/mirage_protocol.cpp | 84 +++++++++++++++++++ .../components/remote_base/mirage_protocol.h | 39 +++++++++ .../remote_receiver/esp32-common.yaml | 4 + .../remote_receiver/test.esp8266.yaml | 4 + .../remote_transmitter/common-buttons.yaml | 5 ++ 6 files changed, 174 insertions(+) create mode 100644 esphome/components/remote_base/mirage_protocol.cpp create mode 100644 esphome/components/remote_base/mirage_protocol.h diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 8a1d50d1c6..9d49026aa3 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1913,3 +1913,41 @@ async def abbwelcome_action(var, config, args): cg.add(var.set_data_template(template_)) else: cg.add(var.set_data_static(data_)) + + +# Mirage +( + MirageData, + MirageBinarySensor, + MirageTrigger, + MirageAction, + MirageDumper, +) = declare_protocol("Mirage") + +MIRAGE_SCHEMA = cv.Schema( + { + cv.Required(CONF_CODE): cv.All([cv.hex_uint8_t], cv.Length(min=14, max=14)), + } +) + + +@register_binary_sensor("mirage", MirageBinarySensor, MIRAGE_SCHEMA) +def mirage_binary_sensor(var, config): + cg.add(var.set_code(config[CONF_CODE])) + + +@register_trigger("mirage", MirageTrigger, MirageData) +def mirage_trigger(var, config): + pass + + +@register_dumper("mirage", MirageDumper) +def mirage_dumper(var, config): + pass + + +@register_action("mirage", MirageAction, MIRAGE_SCHEMA) +async def mirage_action(var, config, args): + vec_ = cg.std_vector.template(cg.uint8) + template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_) + cg.add(var.set_code(template_)) diff --git a/esphome/components/remote_base/mirage_protocol.cpp b/esphome/components/remote_base/mirage_protocol.cpp new file mode 100644 index 0000000000..10d644a1cd --- /dev/null +++ b/esphome/components/remote_base/mirage_protocol.cpp @@ -0,0 +1,84 @@ +#include "mirage_protocol.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace remote_base { + +static const char *const TAG = "remote.mirage"; + +constexpr uint32_t HEADER_MARK_US = 8360; +constexpr uint32_t HEADER_SPACE_US = 4248; +constexpr uint32_t BIT_MARK_US = 554; +constexpr uint32_t BIT_ONE_SPACE_US = 1592; +constexpr uint32_t BIT_ZERO_SPACE_US = 545; + +constexpr unsigned int MIRAGE_IR_PACKET_BIT_SIZE = 120; + +void MirageProtocol::encode(RemoteTransmitData *dst, const MirageData &data) { + ESP_LOGI(TAG, "Transive Mirage: %s", format_hex_pretty(data.data).c_str()); + dst->set_carrier_frequency(38000); + dst->reserve(5 + ((data.data.size() + 1) * 2)); + dst->mark(HEADER_MARK_US); + dst->space(HEADER_SPACE_US); + dst->mark(BIT_MARK_US); + uint8_t checksum = 0; + for (uint8_t item : data.data) { + this->encode_byte_(dst, item); + checksum += (item >> 4) + (item & 0xF); + } + this->encode_byte_(dst, checksum); +} + +void MirageProtocol::encode_byte_(RemoteTransmitData *dst, uint8_t item) { + for (uint8_t b = 0; b < 8; b++) { + if (item & (1UL << b)) { + dst->space(BIT_ONE_SPACE_US); + } else { + dst->space(BIT_ZERO_SPACE_US); + } + dst->mark(BIT_MARK_US); + } +} + +optional MirageProtocol::decode(RemoteReceiveData src) { + if (!src.expect_item(HEADER_MARK_US, HEADER_SPACE_US)) { + return {}; + } + if (!src.expect_mark(BIT_MARK_US)) { + return {}; + } + size_t size = src.size() - src.get_index() - 1; + if (size < MIRAGE_IR_PACKET_BIT_SIZE * 2) + return {}; + size = MIRAGE_IR_PACKET_BIT_SIZE * 2; + uint8_t checksum = 0; + MirageData out; + while (size > 0) { + uint8_t data = 0; + for (uint8_t b = 0; b < 8; b++) { + if (src.expect_space(BIT_ONE_SPACE_US)) { + data |= (1UL << b); + } else if (!src.expect_space(BIT_ZERO_SPACE_US)) { + return {}; + } + if (!src.expect_mark(BIT_MARK_US)) { + return {}; + } + size -= 2; + } + if (size > 0) { + checksum += (data >> 4) + (data & 0xF); + out.data.push_back(data); + } else if (checksum != data) { + return {}; + } + } + return out; +} + +void MirageProtocol::dump(const MirageData &data) { + ESP_LOGI(TAG, "Received Mirage: %s", format_hex_pretty(data.data).c_str()); +} + +} // namespace remote_base +} // namespace esphome diff --git a/esphome/components/remote_base/mirage_protocol.h b/esphome/components/remote_base/mirage_protocol.h new file mode 100644 index 0000000000..4257f7fa00 --- /dev/null +++ b/esphome/components/remote_base/mirage_protocol.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/core/component.h" +#include "remote_base.h" + +namespace esphome { +namespace remote_base { + +struct MirageData { + std::vector data; + + bool operator==(const MirageData &rhs) const { return data == rhs.data; } +}; + +class MirageProtocol : public RemoteProtocol { + public: + void encode(RemoteTransmitData *dst, const MirageData &data) override; + optional decode(RemoteReceiveData src) override; + void dump(const MirageData &data) override; + + protected: + void encode_byte_(RemoteTransmitData *dst, uint8_t item); +}; + +DECLARE_REMOTE_PROTOCOL(Mirage) + +template class MirageAction : public RemoteTransmitterActionBase { + public: + TEMPLATABLE_VALUE(std::vector, code) + + void encode(RemoteTransmitData *dst, Ts... x) override { + MirageData data{}; + data.data = this->code_.value(x...); + MirageProtocol().encode(dst, data); + } +}; + +} // namespace remote_base +} // namespace esphome diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index 0e71143fc3..c2b5a2cf19 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -143,6 +143,10 @@ remote_receiver: - logger.log: format: "on_toshiba_ac: %llu %llu" args: ["x.rc_code_1", "x.rc_code_2"] + on_mirage: + then: + - lambda: |- + ESP_LOGD("mirage", "Mirage data: %s", format_hex(x.data).c_str()); binary_sensor: - platform: remote_receiver diff --git a/tests/components/remote_receiver/test.esp8266.yaml b/tests/components/remote_receiver/test.esp8266.yaml index e96f031e90..27d36d4a16 100644 --- a/tests/components/remote_receiver/test.esp8266.yaml +++ b/tests/components/remote_receiver/test.esp8266.yaml @@ -142,6 +142,10 @@ remote_receiver: - logger.log: format: "on_toshiba_ac: %llu %llu" args: ["x.rc_code_1", "x.rc_code_2"] + on_mirage: + then: + - lambda: |- + ESP_LOGD("mirage", "Mirage data: %s", format_hex(x.data).c_str()); binary_sensor: - platform: remote_receiver diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml index 27683b387f..e727017e85 100644 --- a/tests/components/remote_transmitter/common-buttons.yaml +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -176,6 +176,11 @@ button: 0x00, 0x05, ] + - platform: template + name: Mirage + on_press: + remote_transmitter.transmit_mirage: + code: [0x56, 0x77, 0x00, 0x00, 0x22, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - platform: template name: Dooya on_press: From 2921831b55b327d1670ee92b8b33163867fa7434 Mon Sep 17 00:00:00 2001 From: shxshxshxshx Date: Thu, 16 May 2024 01:37:53 +0200 Subject: [PATCH 1749/2607] WPA2 Enterprise - Explicitly set TTLS Phase 2 (#6436) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/wifi/__init__.py | 13 +++++++++++++ esphome/components/wifi/wifi_component.cpp | 15 +++++++++++++++ esphome/components/wifi/wifi_component.h | 8 ++++++++ .../components/wifi/wifi_component_esp_idf.cpp | 5 +++++ esphome/const.py | 1 + 5 files changed, 42 insertions(+) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index e0a17e9a2a..3b9e00956f 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -33,6 +33,7 @@ from esphome.const import ( CONF_KEY, CONF_USERNAME, CONF_EAP, + CONF_TTLS_PHASE_2, CONF_ON_CONNECT, CONF_ON_DISCONNECT, ) @@ -98,6 +99,14 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend( } ) +TTLS_PHASE_2 = { + "pap": cg.global_ns.ESP_EAP_TTLS_PHASE2_PAP, + "chap": cg.global_ns.ESP_EAP_TTLS_PHASE2_CHAP, + "mschap": cg.global_ns.ESP_EAP_TTLS_PHASE2_MSCHAP, + "mschapv2": cg.global_ns.ESP_EAP_TTLS_PHASE2_MSCHAPV2, + "eap": cg.global_ns.ESP_EAP_TTLS_PHASE2_EAP, +} + EAP_AUTH_SCHEMA = cv.All( cv.Schema( { @@ -105,6 +114,9 @@ EAP_AUTH_SCHEMA = cv.All( cv.Optional(CONF_USERNAME): cv.string_strict, cv.Optional(CONF_PASSWORD): cv.string_strict, cv.Optional(CONF_CERTIFICATE_AUTHORITY): wpa2_eap.validate_certificate, + cv.Optional(CONF_TTLS_PHASE_2): cv.All( + cv.enum(TTLS_PHASE_2), cv.only_with_esp_idf + ), cv.Inclusive( CONF_CERTIFICATE, "certificate_and_key" ): wpa2_eap.validate_certificate, @@ -338,6 +350,7 @@ def eap_auth(config): ("ca_cert", ca_cert), ("client_cert", client_cert), ("client_key", key), + ("ttls_phase_2", config.get(CONF_TTLS_PHASE_2, TTLS_PHASE_2["mschapv2"])), ) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 7e245d3e86..f4a44b03a4 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -1,5 +1,10 @@ #include "wifi_component.h" #include +#include + +#ifdef USE_ESP_IDF +#include +#endif #if defined(USE_ESP32) || defined(USE_ESP_IDF) #include @@ -318,6 +323,16 @@ void WiFiComponent::start_connecting(const WiFiAP &ap, bool two) { ESP_LOGV(TAG, " Identity: " LOG_SECRET("'%s'"), eap_config.identity.c_str()); ESP_LOGV(TAG, " Username: " LOG_SECRET("'%s'"), eap_config.username.c_str()); ESP_LOGV(TAG, " Password: " LOG_SECRET("'%s'"), eap_config.password.c_str()); +#ifdef USE_ESP_IDF +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + std::map phase2types = {{ESP_EAP_TTLS_PHASE2_PAP, "pap"}, + {ESP_EAP_TTLS_PHASE2_CHAP, "chap"}, + {ESP_EAP_TTLS_PHASE2_MSCHAP, "mschap"}, + {ESP_EAP_TTLS_PHASE2_MSCHAPV2, "mschapv2"}, + {ESP_EAP_TTLS_PHASE2_EAP, "eap"}}; + ESP_LOGV(TAG, " TTLS Phase 2: " LOG_SECRET("'%s'"), phase2types[eap_config.ttls_phase_2].c_str()); +#endif +#endif bool ca_cert_present = eap_config.ca_cert != nullptr && strlen(eap_config.ca_cert); bool client_cert_present = eap_config.client_cert != nullptr && strlen(eap_config.client_cert); bool client_key_present = eap_config.client_key != nullptr && strlen(eap_config.client_key); diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 133fa2970c..0b077819ae 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -19,6 +19,10 @@ #include #endif +#if defined(USE_ESP_IDF) && defined(USE_WIFI_WPA2_EAP) +#include +#endif + #ifdef USE_ESP8266 #include #include @@ -102,6 +106,10 @@ struct EAPAuth { // used for EAP-TLS const char *client_cert; const char *client_key; +// used for EAP-TTLS +#ifdef USE_ESP_IDF + esp_eap_ttls_phase2_types ttls_phase_2; +#endif }; #endif // USE_WIFI_WPA2_EAP diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index ebb2fb92ea..5489a5d249 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -396,6 +396,11 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { if (err != ESP_OK) { ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_password failed! %d", err); } + // set TTLS Phase 2, defaults to MSCHAPV2 + err = esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(eap.ttls_phase_2); + if (err != ESP_OK) { + ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_ttls_phase2_method failed! %d", err); + } } err = esp_wifi_sta_wpa2_ent_enable(); if (err != ESP_OK) { diff --git a/esphome/const.py b/esphome/const.py index eb48080040..7745cca321 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -856,6 +856,7 @@ CONF_TRANSFORM = "transform" CONF_TRANSITION_LENGTH = "transition_length" CONF_TRIGGER_ID = "trigger_id" CONF_TRIGGER_PIN = "trigger_pin" +CONF_TTLS_PHASE_2 = "ttls_phase_2" CONF_TUNE_ANTENNA = "tune_antenna" CONF_TURN_OFF_ACTION = "turn_off_action" CONF_TURN_ON_ACTION = "turn_on_action" From 7d804bf90f646b669f5d46df7e1d9edca2988109 Mon Sep 17 00:00:00 2001 From: Shawn Wilsher <656602+sdwilsh@users.noreply.github.com> Date: Wed, 15 May 2024 16:39:57 -0700 Subject: [PATCH 1750/2607] Fix Prometheus Output to Match Spec (#6032) --- .../prometheus/prometheus_handler.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index 68bca95a21..09913bd713 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -65,8 +65,8 @@ std::string PrometheusHandler::relabel_name_(EntityBase *obj) { // Type-specific implementation #ifdef USE_SENSOR void PrometheusHandler::sensor_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_sensor_value GAUGE\n")); - stream->print(F("#TYPE esphome_sensor_failed GAUGE\n")); + stream->print(F("#TYPE esphome_sensor_value gauge\n")); + stream->print(F("#TYPE esphome_sensor_failed gauge\n")); } void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj) { if (obj->is_internal() && !this->include_internal_) @@ -102,8 +102,8 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor // Type-specific implementation #ifdef USE_BINARY_SENSOR void PrometheusHandler::binary_sensor_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_binary_sensor_value GAUGE\n")); - stream->print(F("#TYPE esphome_binary_sensor_failed GAUGE\n")); + stream->print(F("#TYPE esphome_binary_sensor_value gauge\n")); + stream->print(F("#TYPE esphome_binary_sensor_failed gauge\n")); } void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj) { if (obj->is_internal() && !this->include_internal_) @@ -136,10 +136,10 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s #ifdef USE_FAN void PrometheusHandler::fan_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_fan_value GAUGE\n")); - stream->print(F("#TYPE esphome_fan_failed GAUGE\n")); - stream->print(F("#TYPE esphome_fan_speed GAUGE\n")); - stream->print(F("#TYPE esphome_fan_oscillation GAUGE\n")); + stream->print(F("#TYPE esphome_fan_value gauge\n")); + stream->print(F("#TYPE esphome_fan_failed gauge\n")); + stream->print(F("#TYPE esphome_fan_speed gauge\n")); + stream->print(F("#TYPE esphome_fan_oscillation gauge\n")); } void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { if (obj->is_internal() && !this->include_internal_) @@ -182,9 +182,9 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { #ifdef USE_LIGHT void PrometheusHandler::light_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_light_state GAUGE\n")); - stream->print(F("#TYPE esphome_light_color GAUGE\n")); - stream->print(F("#TYPE esphome_light_effect_active GAUGE\n")); + stream->print(F("#TYPE esphome_light_state gauge\n")); + stream->print(F("#TYPE esphome_light_color gauge\n")); + stream->print(F("#TYPE esphome_light_effect_active gauge\n")); } void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightState *obj) { if (obj->is_internal() && !this->include_internal_) @@ -259,8 +259,8 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat #ifdef USE_COVER void PrometheusHandler::cover_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_cover_value GAUGE\n")); - stream->print(F("#TYPE esphome_cover_failed GAUGE\n")); + stream->print(F("#TYPE esphome_cover_value gauge\n")); + stream->print(F("#TYPE esphome_cover_failed gauge\n")); } void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *obj) { if (obj->is_internal() && !this->include_internal_) @@ -302,8 +302,8 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob #ifdef USE_SWITCH void PrometheusHandler::switch_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_switch_value GAUGE\n")); - stream->print(F("#TYPE esphome_switch_failed GAUGE\n")); + stream->print(F("#TYPE esphome_switch_value gauge\n")); + stream->print(F("#TYPE esphome_switch_failed gauge\n")); } void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch *obj) { if (obj->is_internal() && !this->include_internal_) @@ -326,8 +326,8 @@ void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch #ifdef USE_LOCK void PrometheusHandler::lock_type_(AsyncResponseStream *stream) { - stream->print(F("#TYPE esphome_lock_value GAUGE\n")); - stream->print(F("#TYPE esphome_lock_failed GAUGE\n")); + stream->print(F("#TYPE esphome_lock_value gauge\n")); + stream->print(F("#TYPE esphome_lock_failed gauge\n")); } void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) { if (obj->is_internal() && !this->include_internal_) From f0ec900e4841a32023491f8482af3c4a07432adb Mon Sep 17 00:00:00 2001 From: Andrew McFague <144809+amcfague@users.noreply.github.com> Date: Wed, 15 May 2024 16:49:04 -0700 Subject: [PATCH 1751/2607] Skip gpio validation (#5615) --- esphome/components/esp32/gpio.py | 40 ++++++++++++++++++++-- esphome/components/esp32_touch/__init__.py | 2 +- esphome/const.py | 1 + esphome/pins.py | 2 ++ tests/test8.yaml | 13 +++++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/esphome/components/esp32/gpio.py b/esphome/components/esp32/gpio.py index 16f99f2b15..0d9cb5daf0 100644 --- a/esphome/components/esp32/gpio.py +++ b/esphome/components/esp32/gpio.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from typing import Any +import logging from esphome.const import ( CONF_ID, @@ -8,6 +9,7 @@ from esphome.const import ( CONF_NUMBER, CONF_OPEN_DRAIN, CONF_OUTPUT, + CONF_IGNORE_PIN_VALIDATION_ERROR, CONF_IGNORE_STRAPPING_WARNING, PLATFORM_ESP32, ) @@ -42,6 +44,9 @@ from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_support ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin) +_LOGGER = logging.getLogger(__name__) + + def _lookup_pin(value): board = CORE.data[KEY_ESP32][KEY_BOARD] board_pins = boards.ESP32_BOARD_PINS.get(board, {}) @@ -111,7 +116,7 @@ _esp32_validations = { } -def validate_gpio_pin(value): +def gpio_pin_number_validator(value): value = _translate_pin(value) board = CORE.data[KEY_ESP32][KEY_BOARD] board_pins = boards.ESP32_BOARD_PINS.get(board, {}) @@ -127,7 +132,33 @@ def validate_gpio_pin(value): if variant not in _esp32_validations: raise cv.Invalid(f"Unsupported ESP32 variant {variant}") - return _esp32_validations[variant].pin_validation(value) + return value + + +def validate_gpio_pin(pin): + variant = CORE.data[KEY_ESP32][KEY_VARIANT] + if variant not in _esp32_validations: + raise cv.Invalid(f"Unsupported ESP32 variant {variant}") + + ignore_pin_validation_warning = pin[CONF_IGNORE_PIN_VALIDATION_ERROR] + try: + pin[CONF_NUMBER] = _esp32_validations[variant].pin_validation(pin[CONF_NUMBER]) + except cv.Invalid as exc: + if not ignore_pin_validation_warning: + raise + + _LOGGER.warning( + "Ignoring validation error on pin %d; error: %s", + pin[CONF_NUMBER], + exc, + ) + else: + # Throw an exception if used for a pin that would not have resulted + # in a validation error anyway! + if ignore_pin_validation_warning: + raise cv.Invalid(f"GPIO{pin[CONF_NUMBER]} is not a reserved pin") + + return pin def validate_supports(value): @@ -158,9 +189,11 @@ DRIVE_STRENGTHS = { gpio_num_t = cg.global_ns.enum("gpio_num_t") CONF_DRIVE_STRENGTH = "drive_strength" + ESP32_PIN_SCHEMA = cv.All( - pins.gpio_base_schema(ESP32InternalGPIOPin, validate_gpio_pin).extend( + pins.gpio_base_schema(ESP32InternalGPIOPin, gpio_pin_number_validator).extend( { + cv.Optional(CONF_IGNORE_PIN_VALIDATION_ERROR, default=False): cv.boolean, cv.Optional(CONF_IGNORE_STRAPPING_WARNING, default=False): cv.boolean, cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All( cv.float_with_unit("current", "mA", optional_unit=True), @@ -168,6 +201,7 @@ ESP32_PIN_SCHEMA = cv.All( ), } ), + validate_gpio_pin, validate_supports, ) diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index 0180d18104..fc7bf200e4 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -150,7 +150,7 @@ TOUCH_PAD_WATERPROOF_SHIELD_DRIVER = { def validate_touch_pad(value): - value = gpio.validate_gpio_pin(value) + value = gpio.gpio_pin_number_validator(value) variant = get_esp32_variant() if variant not in TOUCH_PADS: raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") diff --git a/esphome/const.py b/esphome/const.py index 7745cca321..616b686052 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -367,6 +367,7 @@ CONF_IDLE_TIME = "idle_time" CONF_IF = "if" CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc" CONF_IGNORE_OUT_OF_RANGE = "ignore_out_of_range" +CONF_IGNORE_PIN_VALIDATION_ERROR = "ignore_pin_validation_error" CONF_IGNORE_STRAPPING_WARNING = "ignore_strapping_warning" CONF_IIR_FILTER = "iir_filter" CONF_ILLUMINANCE = "illuminance" diff --git a/esphome/pins.py b/esphome/pins.py index d02ad357a0..5ccb696738 100644 --- a/esphome/pins.py +++ b/esphome/pins.py @@ -327,6 +327,8 @@ def gpio_base_schema( cv.Optional(CONF_MODE, default={}): cv.All(mode_dict, mode_validator), } ) + if invertable: return schema.extend({cv.Optional(CONF_INVERTED, default=False): cv.boolean}) + return schema diff --git a/tests/test8.yaml b/tests/test8.yaml index 5a8ae77468..fcc93c6154 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -38,6 +38,11 @@ light: id: rgb_led name: "RGB LED" data_rate: 8MHz + - platform: binary + name: "Red Info Light" + output: board_info_ed + entity_category: diagnostic + restore_mode: ALWAYS_OFF spi: id: spi_id_1 @@ -73,6 +78,14 @@ i2c: scl: GPIO18 sda: GPIO8 +output: + - platform: gpio + id: board_info_ed + pin: + # This pin is reserved on the ESP32S3! + number: 26 + ignore_pin_validation_error: true + touchscreen: - platform: tt21100 display: displ8 From f2ef06d8b538deee919efbc396040eee502fd22c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 13:19:37 +1200 Subject: [PATCH 1752/2607] [core] Migrate to pyproject.toml (#6737) --- setup.cfg => .flake8 | 51 +++++++++------------------ docker/Dockerfile | 4 +-- pyproject.toml | 53 ++++++++++++++++++++++++++++ script/setup | 6 ++-- setup.py | 82 -------------------------------------------- 5 files changed, 74 insertions(+), 122 deletions(-) rename setup.cfg => .flake8 (56%) delete mode 100755 setup.py diff --git a/setup.cfg b/.flake8 similarity index 56% rename from setup.cfg rename to .flake8 index b3cfbba6a1..2724da06b6 100644 --- a/setup.cfg +++ b/.flake8 @@ -1,19 +1,3 @@ -[metadata] -license = MIT -license_file = LICENSE -platforms = any -description = Make creating custom firmwares for ESP32/ESP8266 super easy. -long_description = file: README.md -keywords = home, automation -classifier = - Environment :: Console - Intended Audience :: Developers - Intended Audience :: End Users/Desktop - License :: OSI Approved :: MIT License - Programming Language :: C++ - Programming Language :: Python :: 3 - Topic :: Home Automation - [flake8] max-line-length = 120 # Following 4 for black compatibility @@ -37,25 +21,22 @@ max-line-length = 120 # D401 First line should be in imperative mood ignore = - E501, - W503, - E203, - D202, + E501, + W503, + E203, + D202, - D100, - D101, - D102, - D103, - D104, - D105, - D107, - D200, - D205, - D209, - D400, - D401, + D100, + D101, + D102, + D103, + D104, + D105, + D107, + D200, + D205, + D209, + D400, + D401, exclude = api_pb2.py - -[bdist_wheel] -universal = 1 diff --git a/docker/Dockerfile b/docker/Dockerfile index 5d9ece16a1..3c661b7e1c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -110,7 +110,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ fi; \ pip3 install \ - --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome + --break-system-packages --no-cache-dir -e /esphome # Settings for dashboard ENV USERNAME="" PASSWORD="" @@ -160,7 +160,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ fi; \ pip3 install \ - --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome + --break-system-packages --no-cache-dir -e /esphome # Labels LABEL \ diff --git a/pyproject.toml b/pyproject.toml index a49abb7b3d..aa524e2d62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,56 @@ +[build-system] +requires = ["setuptools==69.2.0", "wheel~=0.43.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "esphome" +license = {text = "MIT"} +description = "Make creating custom firmwares for ESP32/ESP8266 super easy." +readme = "README.md" +authors = [ + {name = "The ESPHome Authors", email = "esphome@nabucasa.com"} +] +keywords = ["home", "automation"] +classifiers = [ + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: End Users/Desktop", + "License :: OSI Approved :: MIT License", + "Programming Language :: C++", + "Programming Language :: Python :: 3", + "Topic :: Home Automation", +] +requires-python = ">=3.9.0" + +dynamic = ["dependencies", "optional-dependencies", "version"] + +[project.urls] +"Documentation" = "https://esphome.io" +"Source Code" = "https://github.com/esphome/esphome" +"Bug Tracker" = "https://github.com/esphome/issues/issues" +"Feature Request Tracker" = "https://github.com/esphome/feature-requests/issues" +"Discord" = "https://discord.gg/KhAMKrd" +"Forum" = "https://community.home-assistant.io/c/esphome" +"Twitter" = "https://twitter.com/esphome_" + +[project.scripts] +esphome = "esphome.__main__:main" + +[tool.setuptools] +platforms = ["any"] +zip-safe = false +include-package-data = true + +[tool.setuptools.dynamic] +dependencies = {file = ["requirements.txt"]} +optional-dependencies.dev = { file = ["requirements_dev.txt"] } +optional-dependencies.test = { file = ["requirements_test.txt"] } +optional-dependencies.displays = { file = ["requirements_optional.txt"] } +version = {attr = "esphome.const.__version__"} + +[tool.setuptools.packages.find] +include = ["esphome*"] + [tool.black] target-version = ["py39", "py310"] exclude = 'generated' diff --git a/script/setup b/script/setup index f286b4672a..71573a9352 100755 --- a/script/setup +++ b/script/setup @@ -10,17 +10,17 @@ if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ] && [ ! "$ESPHOME_NO_VENV" if [ -f venv/Scripts/activate ]; then location="venv/Scripts/activate" fi - source $location; + source $location fi # Avoid unsafe git error when running inside devcontainer -if [ -n "$DEVCONTAINER" ];then +if [ -n "$DEVCONTAINER" ]; then git config --global --add safe.directory "$PWD" fi pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt -r requirements_dev.txt pip3 install setuptools wheel -pip3 install --no-use-pep517 -e . +pip3 install -e --config-settings editable_mode=compat ".[dev,test,displays]" pre-commit install diff --git a/setup.py b/setup.py deleted file mode 100755 index 95453960ff..0000000000 --- a/setup.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 -"""esphome setup script.""" -import os - -from setuptools import setup, find_packages - -from esphome import const - -PROJECT_NAME = "esphome" -PROJECT_PACKAGE_NAME = "esphome" -PROJECT_LICENSE = "MIT" -PROJECT_AUTHOR = "ESPHome" -PROJECT_COPYRIGHT = "2019, ESPHome" -PROJECT_URL = "https://esphome.io/" -PROJECT_EMAIL = "esphome@nabucasa.com" - -PROJECT_GITHUB_USERNAME = "esphome" -PROJECT_GITHUB_REPOSITORY = "esphome" - -PYPI_URL = f"https://pypi.python.org/pypi/{PROJECT_PACKAGE_NAME}" -GITHUB_PATH = f"{PROJECT_GITHUB_USERNAME}/{PROJECT_GITHUB_REPOSITORY}" -GITHUB_URL = f"https://github.com/{GITHUB_PATH}" - -DOWNLOAD_URL = f"{GITHUB_URL}/archive/{const.__version__}.zip" - -here = os.path.abspath(os.path.dirname(__file__)) - -with open(os.path.join(here, "requirements.txt")) as requirements_txt: - REQUIRES = requirements_txt.read().splitlines() - -with open(os.path.join(here, "README.md")) as readme: - LONG_DESCRIPTION = readme.read() - -# If you have problems importing platformio and esptool as modules you can set -# $ESPHOME_USE_SUBPROCESS to make ESPHome call their executables instead. -# This means they have to be in your $PATH. -if "ESPHOME_USE_SUBPROCESS" in os.environ: - # Remove platformio and esptool from requirements - REQUIRES = [ - req - for req in REQUIRES - if not any(req.startswith(prefix) for prefix in ["platformio", "esptool"]) - ] - -CLASSIFIERS = [ - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "License :: OSI Approved :: MIT License", - "Programming Language :: C++", - "Programming Language :: Python :: 3", - "Topic :: Home Automation", -] - -setup( - name=PROJECT_PACKAGE_NAME, - version=const.__version__, - license=PROJECT_LICENSE, - url=GITHUB_URL, - project_urls={ - "Bug Tracker": "https://github.com/esphome/issues/issues", - "Feature Request Tracker": "https://github.com/esphome/feature-requests/issues", - "Source Code": "https://github.com/esphome/esphome", - "Documentation": "https://esphome.io", - "Twitter": "https://twitter.com/esphome_", - }, - download_url=DOWNLOAD_URL, - author=PROJECT_AUTHOR, - author_email=PROJECT_EMAIL, - description="Make creating custom firmwares for ESP32/ESP8266 super easy.", - long_description=LONG_DESCRIPTION, - long_description_content_type="text/markdown", - include_package_data=True, - zip_safe=False, - platforms="any", - test_suite="tests", - python_requires=">=3.9.0", - install_requires=REQUIRES, - keywords=["home", "automation"], - entry_points={"console_scripts": ["esphome = esphome.__main__:main"]}, - packages=find_packages(include="esphome.*"), -) From bf48ccaf22a32e11e9974cf888bed1e424de8822 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 13:20:12 +1200 Subject: [PATCH 1753/2607] [core] Move pytest config into pyproject.toml (#6740) --- pyproject.toml | 9 +++++++++ pytest.ini | 4 ---- 2 files changed, 9 insertions(+), 4 deletions(-) delete mode 100644 pytest.ini diff --git a/pyproject.toml b/pyproject.toml index aa524e2d62..4406165433 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,3 +54,12 @@ include = ["esphome*"] [tool.black] target-version = ["py39", "py310"] exclude = 'generated' + +[tool.pytest.ini_options] +testpaths = [ + "tests", +] +addopts = [ + "--cov=esphome", + "--cov-branch", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index a91a2ea200..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -addopts = - --cov=esphome - --cov-branch From a27c05483cf3d20f98ea8db392dde5b277ff2337 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 13:47:36 +1200 Subject: [PATCH 1754/2607] [core] Move pylint config into pyproject.toml (#6739) --- pylintrc | 30 ------------------------------ pyproject.toml | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 30 deletions(-) delete mode 100644 pylintrc diff --git a/pylintrc b/pylintrc deleted file mode 100644 index b70e5c7da9..0000000000 --- a/pylintrc +++ /dev/null @@ -1,30 +0,0 @@ -[MASTER] -reports=no -ignore=api_pb2.py - -disable= - format, - missing-docstring, - fixme, - unused-argument, - global-statement, - too-few-public-methods, - too-many-lines, - too-many-locals, - too-many-ancestors, - too-many-branches, - too-many-statements, - too-many-arguments, - too-many-return-statements, - too-many-instance-attributes, - duplicate-code, - invalid-name, - cyclic-import, - redefined-builtin, - undefined-loop-variable, - useless-object-inheritance, - stop-iteration-return, - import-outside-toplevel, - # Broken - unsupported-membership-test, - unsubscriptable-object, diff --git a/pyproject.toml b/pyproject.toml index 4406165433..fe558f695f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,3 +63,45 @@ addopts = [ "--cov=esphome", "--cov-branch", ] + +[tool.pylint.MAIN] +py-version = "3.9" +ignore = [ + "api_pb2.py", +] +persistent = false + +[tool.pylint.REPORTS] +score = false + +[tool.pylint."MESSAGES CONTROL"] +disable = [ + "format", + "missing-docstring", + "fixme", + "unused-argument", + "global-statement", + "too-few-public-methods", + "too-many-lines", + "too-many-locals", + "too-many-ancestors", + "too-many-branches", + "too-many-statements", + "too-many-arguments", + "too-many-return-statements", + "too-many-instance-attributes", + "duplicate-code", + "invalid-name", + "cyclic-import", + "redefined-builtin", + "undefined-loop-variable", + "useless-object-inheritance", + "stop-iteration-return", + "import-outside-toplevel", + # Broken + "unsupported-membership-test", + "unsubscriptable-object", +] + +[tool.pylint.FORMAT] +expected-line-ending-format = "LF" From f91c31f093142d11225e1ca3d4fa79817a719490 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 13:47:56 +1200 Subject: [PATCH 1755/2607] [core] Fix running pylint via pre-commit from GUI apps (#6754) --- .pre-commit-config.yaml | 4 ++-- script/run-in-env.sh | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100755 script/run-in-env.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce226846e3..418716e4f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,6 +44,6 @@ repos: hooks: - id: pylint name: pylint - entry: pylint - language: system + entry: script/run-in-env.sh pylint + language: script types: [python] diff --git a/script/run-in-env.sh b/script/run-in-env.sh new file mode 100755 index 0000000000..2e05fe1d17 --- /dev/null +++ b/script/run-in-env.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env sh +set -eu + +my_path=$(git rev-parse --show-toplevel) + +for venv in venv .venv .; do + if [ -f "${my_path}/${venv}/bin/activate" ]; then + . "${my_path}/${venv}/bin/activate" + break + fi +done + +exec "$@" From f46c499c4e4598b95d24f546a2d2cbaa13206850 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 15 May 2024 21:01:09 -0500 Subject: [PATCH 1756/2607] Separate `OTABackend` from OTA component (#6459) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 25 +- .../esp32_ble_tracker/esp32_ble_tracker.cpp | 13 +- esphome/components/esphome/ota/__init__.py | 72 ++++++ .../ota/ota_esphome.cpp} | 215 ++++++++---------- .../ota/ota_esphome.h} | 62 +---- esphome/components/ota/__init__.py | 106 ++++----- esphome/components/ota/automation.h | 19 +- esphome/components/ota/ota_backend.cpp | 20 ++ esphome/components/ota/ota_backend.h | 79 ++++++- .../ota/ota_backend_arduino_esp32.cpp | 5 +- .../ota/ota_backend_arduino_esp32.h | 6 +- .../ota/ota_backend_arduino_esp8266.cpp | 9 +- .../ota/ota_backend_arduino_esp8266.h | 5 +- .../ota/ota_backend_arduino_libretiny.cpp | 9 +- .../ota/ota_backend_arduino_libretiny.h | 5 +- .../ota/ota_backend_arduino_rp2040.cpp | 9 +- .../ota/ota_backend_arduino_rp2040.h | 7 +- .../components/ota/ota_backend_esp_idf.cpp | 13 +- esphome/components/ota/ota_backend_esp_idf.h | 8 +- .../components/safe_mode/button/__init__.py | 16 +- .../safe_mode/button/safe_mode_button.cpp | 2 +- .../safe_mode/button/safe_mode_button.h | 8 +- .../components/safe_mode/switch/__init__.py | 14 +- .../safe_mode/switch/safe_mode_switch.cpp | 4 +- .../safe_mode/switch/safe_mode_switch.h | 8 +- esphome/cpp_helpers.py | 21 +- esphome/wizard.py | 5 +- tests/components/ota/common.yaml | 51 +++-- tests/components/safe_mode/common.yaml | 2 + tests/dummy_main.cpp | 4 +- tests/test1.yaml | 47 ++-- tests/test11.5.yaml | 1 + tests/test2.yaml | 7 +- tests/test3.1.yaml | 3 +- tests/test3.yaml | 7 +- tests/test4.yaml | 5 +- tests/test5.yaml | 1 + tests/test6.yaml | 1 + tests/test9.1.yaml | 1 + tests/test9.yaml | 1 + 40 files changed, 505 insertions(+), 391 deletions(-) create mode 100644 esphome/components/esphome/ota/__init__.py rename esphome/components/{ota/ota_component.cpp => esphome/ota/ota_esphome.cpp} (66%) rename esphome/components/{ota/ota_component.h => esphome/ota/ota_esphome.h} (50%) create mode 100644 esphome/components/ota/ota_backend.cpp diff --git a/esphome/__main__.py b/esphome/__main__.py index daf74eebb0..9930119c86 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -18,22 +18,23 @@ from esphome.const import ( CONF_BAUD_RATE, CONF_BROKER, CONF_DEASSERT_RTS_DTR, + CONF_DISABLED, + CONF_ESPHOME, CONF_LOGGER, + CONF_MDNS, + CONF_MQTT, CONF_NAME, CONF_OTA, - CONF_MQTT, - CONF_MDNS, - CONF_DISABLED, CONF_PASSWORD, - CONF_PORT, - CONF_ESPHOME, + CONF_PLATFORM, CONF_PLATFORMIO_OPTIONS, + CONF_PORT, CONF_SUBSTITUTIONS, PLATFORM_BK72XX, - PLATFORM_RTL87XX, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, + PLATFORM_RTL87XX, SECRETS_FILES, ) from esphome.core import CORE, EsphomeError, coroutine @@ -330,15 +331,19 @@ def upload_program(config, args, host): return 1 # Unknown target platform - if CONF_OTA not in config: + ota_conf = {} + for ota_item in config.get(CONF_OTA, []): + if ota_item[CONF_PLATFORM] == CONF_ESPHOME: + ota_conf = ota_item + break + + if not ota_conf: raise EsphomeError( - "Cannot upload Over the Air as the config does not include the ota: " - "component" + f"Cannot upload Over the Air as the {CONF_OTA} configuration is not present or does not include {CONF_PLATFORM}: {CONF_ESPHOME}" ) from esphome import espota2 - ota_conf = config[CONF_OTA] remote_port = ota_conf[CONF_PORT] password = ota_conf.get(CONF_PASSWORD, "") diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 4ae7929ded..d154d4e519 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -18,7 +18,7 @@ #include #ifdef USE_OTA -#include "esphome/components/ota/ota_component.h" +#include "esphome/components/ota/ota_backend.h" #endif #ifdef USE_ARDUINO @@ -61,11 +61,12 @@ void ESP32BLETracker::setup() { this->scanner_idle_ = true; #ifdef USE_OTA - ota::global_ota_component->add_on_state_callback([this](ota::OTAState state, float progress, uint8_t error) { - if (state == ota::OTA_STARTED) { - this->stop_scan(); - } - }); + ota::get_global_ota_callback()->add_on_state_callback( + [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) { + if (state == ota::OTA_STARTED) { + this->stop_scan(); + } + }); #endif } diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py new file mode 100644 index 0000000000..abe9323b53 --- /dev/null +++ b/esphome/components/esphome/ota/__init__.py @@ -0,0 +1,72 @@ +from esphome.cpp_generator import RawExpression +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent +from esphome.const import ( + CONF_ID, + CONF_NUM_ATTEMPTS, + CONF_OTA, + CONF_PASSWORD, + CONF_PORT, + CONF_REBOOT_TIMEOUT, + CONF_SAFE_MODE, + CONF_VERSION, + KEY_PAST_SAFE_MODE, +) +from esphome.core import CORE, coroutine_with_priority + + +CODEOWNERS = ["@esphome/core"] +AUTO_LOAD = ["md5", "socket"] +DEPENDENCIES = ["network"] + +esphome = cg.esphome_ns.namespace("esphome") +ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) + + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ESPHomeOTAComponent), + cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean, + cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), + cv.SplitDefault( + CONF_PORT, + esp8266=8266, + esp32=3232, + rp2040=2040, + bk72xx=8892, + rtl87xx=8892, + ): cv.port, + cv.Optional(CONF_PASSWORD): cv.string, + cv.Optional( + CONF_REBOOT_TIMEOUT, default="5min" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, + } + ) + .extend(BASE_OTA_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +@coroutine_with_priority(50.0) +async def to_code(config): + CORE.data[CONF_OTA] = {} + + var = cg.new_Pvariable(config[CONF_ID]) + await ota_to_code(var, config) + cg.add(var.set_port(config[CONF_PORT])) + if CONF_PASSWORD in config: + cg.add(var.set_auth_password(config[CONF_PASSWORD])) + cg.add_define("USE_OTA_PASSWORD") + cg.add_define("USE_OTA_VERSION", config[CONF_VERSION]) + + await cg.register_component(var, config) + + if config[CONF_SAFE_MODE]: + condition = var.should_enter_safe_mode( + config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] + ) + cg.add(RawExpression(f"if ({condition}) return")) + CORE.data[CONF_OTA][KEY_PAST_SAFE_MODE] = True diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/esphome/ota/ota_esphome.cpp similarity index 66% rename from esphome/components/ota/ota_component.cpp rename to esphome/components/esphome/ota/ota_esphome.cpp index 15af14ff1a..f2f1cfc6a8 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -1,55 +1,34 @@ -#include "ota_component.h" -#include "ota_backend.h" -#include "ota_backend_arduino_esp32.h" -#include "ota_backend_arduino_esp8266.h" -#include "ota_backend_arduino_rp2040.h" -#include "ota_backend_arduino_libretiny.h" -#include "ota_backend_esp_idf.h" +#include "ota_esphome.h" -#include "esphome/core/log.h" -#include "esphome/core/application.h" -#include "esphome/core/hal.h" -#include "esphome/core/util.h" #include "esphome/components/md5/md5.h" #include "esphome/components/network/util.h" +#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/ota/ota_backend_arduino_esp32.h" +#include "esphome/components/ota/ota_backend_arduino_esp8266.h" +#include "esphome/components/ota/ota_backend_arduino_libretiny.h" +#include "esphome/components/ota/ota_backend_arduino_rp2040.h" +#include "esphome/components/ota/ota_backend_esp_idf.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "esphome/core/util.h" #include #include namespace esphome { -namespace ota { -static const char *const TAG = "ota"; +static const char *const TAG = "esphome.ota"; static constexpr u_int16_t OTA_BLOCK_SIZE = 8192; -OTAComponent *global_ota_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -std::unique_ptr make_ota_backend() { -#ifdef USE_ARDUINO -#ifdef USE_ESP8266 - return make_unique(); -#endif // USE_ESP8266 -#ifdef USE_ESP32 - return make_unique(); -#endif // USE_ESP32 -#endif // USE_ARDUINO -#ifdef USE_ESP_IDF - return make_unique(); -#endif // USE_ESP_IDF -#ifdef USE_RP2040 - return make_unique(); -#endif // USE_RP2040 -#ifdef USE_LIBRETINY - return make_unique(); +void ESPHomeOTAComponent::setup() { +#ifdef USE_OTA_STATE_CALLBACK + ota::register_ota_platform(this); #endif -} -OTAComponent::OTAComponent() { global_ota_component = this; } - -void OTAComponent::setup() { server_ = socket::socket_ip(SOCK_STREAM, 0); if (server_ == nullptr) { - ESP_LOGW(TAG, "Could not create socket."); + ESP_LOGW(TAG, "Could not create socket"); this->mark_failed(); return; } @@ -88,41 +67,39 @@ void OTAComponent::setup() { this->mark_failed(); return; } - - this->dump_config(); } -void OTAComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Over-The-Air Updates:"); +void ESPHomeOTAComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Over-The-Air updates:"); ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->port_); + ESP_LOGCONFIG(TAG, " Version: %d", USE_OTA_VERSION); #ifdef USE_OTA_PASSWORD if (!this->password_.empty()) { - ESP_LOGCONFIG(TAG, " Using Password."); + ESP_LOGCONFIG(TAG, " Password configured"); } #endif - ESP_LOGCONFIG(TAG, " OTA version: %d.", USE_OTA_VERSION); if (this->has_safe_mode_ && this->safe_mode_rtc_value_ > 1 && - this->safe_mode_rtc_value_ != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %" PRIu32 " restarts", + this->safe_mode_rtc_value_ != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { + ESP_LOGW(TAG, "Last reset occurred too quickly; safe mode will be invoked in %" PRIu32 " restarts", this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_); } } -void OTAComponent::loop() { +void ESPHomeOTAComponent::loop() { this->handle_(); if (this->has_safe_mode_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) { this->has_safe_mode_ = false; // successful boot, reset counter - ESP_LOGI(TAG, "Boot seems successful, resetting boot loop counter."); + ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter"); this->clean_rtc(); } } static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; -void OTAComponent::handle_() { - OTAResponseTypes error_code = OTA_RESPONSE_ERROR_UNKNOWN; +void ESPHomeOTAComponent::handle_() { + ota::OTAResponseTypes error_code = ota::OTA_RESPONSE_ERROR_UNKNOWN; bool update_started = false; size_t total = 0; uint32_t last_progress = 0; @@ -130,7 +107,7 @@ void OTAComponent::handle_() { char *sbuf = reinterpret_cast(buf); size_t ota_size; uint8_t ota_features; - std::unique_ptr backend; + std::unique_ptr backend; (void) ota_features; #if USE_OTA_VERSION == 2 size_t size_acknowledged = 0; @@ -147,54 +124,54 @@ void OTAComponent::handle_() { int enable = 1; int err = client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int)); if (err != 0) { - ESP_LOGW(TAG, "Socket could not enable tcp nodelay, errno: %d", errno); + ESP_LOGW(TAG, "Socket could not enable TCP nodelay, errno %d", errno); return; } - ESP_LOGD(TAG, "Starting OTA Update from %s...", this->client_->getpeername().c_str()); + ESP_LOGD(TAG, "Starting update from %s...", this->client_->getpeername().c_str()); this->status_set_warning(); #ifdef USE_OTA_STATE_CALLBACK - this->state_callback_.call(OTA_STARTED, 0.0f, 0); + this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); #endif if (!this->readall_(buf, 5)) { - ESP_LOGW(TAG, "Reading magic bytes failed!"); + ESP_LOGW(TAG, "Reading magic bytes failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } // 0x6C, 0x26, 0xF7, 0x5C, 0x45 if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) { ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3], buf[4]); - error_code = OTA_RESPONSE_ERROR_MAGIC; + error_code = ota::OTA_RESPONSE_ERROR_MAGIC; goto error; // NOLINT(cppcoreguidelines-avoid-goto) } // Send OK and version - 2 bytes - buf[0] = OTA_RESPONSE_OK; + buf[0] = ota::OTA_RESPONSE_OK; buf[1] = USE_OTA_VERSION; this->writeall_(buf, 2); - backend = make_ota_backend(); + backend = ota::make_ota_backend(); // Read features - 1 byte if (!this->readall_(buf, 1)) { - ESP_LOGW(TAG, "Reading features failed!"); + ESP_LOGW(TAG, "Reading features failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } ota_features = buf[0]; // NOLINT - ESP_LOGV(TAG, "OTA features is 0x%02X", ota_features); + ESP_LOGV(TAG, "Features: 0x%02X", ota_features); // Acknowledge header - 1 byte - buf[0] = OTA_RESPONSE_HEADER_OK; + buf[0] = ota::OTA_RESPONSE_HEADER_OK; if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) { - buf[0] = OTA_RESPONSE_SUPPORTS_COMPRESSION; + buf[0] = ota::OTA_RESPONSE_SUPPORTS_COMPRESSION; } this->writeall_(buf, 1); #ifdef USE_OTA_PASSWORD if (!this->password_.empty()) { - buf[0] = OTA_RESPONSE_REQUEST_AUTH; + buf[0] = ota::OTA_RESPONSE_REQUEST_AUTH; this->writeall_(buf, 1); md5::MD5Digest md5{}; md5.init(); @@ -206,7 +183,7 @@ void OTAComponent::handle_() { // Send nonce, 32 bytes hex MD5 if (!this->writeall_(reinterpret_cast(sbuf), 32)) { - ESP_LOGW(TAG, "Auth: Writing nonce failed!"); + ESP_LOGW(TAG, "Auth: Writing nonce failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } @@ -218,7 +195,7 @@ void OTAComponent::handle_() { // Receive cnonce, 32 bytes hex MD5 if (!this->readall_(buf, 32)) { - ESP_LOGW(TAG, "Auth: Reading cnonce failed!"); + ESP_LOGW(TAG, "Auth: Reading cnonce failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } sbuf[32] = '\0'; @@ -233,7 +210,7 @@ void OTAComponent::handle_() { // Receive result, 32 bytes hex MD5 if (!this->readall_(buf + 64, 32)) { - ESP_LOGW(TAG, "Auth: Reading response failed!"); + ESP_LOGW(TAG, "Auth: Reading response failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } sbuf[64 + 32] = '\0'; @@ -244,20 +221,20 @@ void OTAComponent::handle_() { matches = matches && buf[i] == buf[64 + i]; if (!matches) { - ESP_LOGW(TAG, "Auth failed! Passwords do not match!"); - error_code = OTA_RESPONSE_ERROR_AUTH_INVALID; + ESP_LOGW(TAG, "Auth failed! Passwords do not match"); + error_code = ota::OTA_RESPONSE_ERROR_AUTH_INVALID; goto error; // NOLINT(cppcoreguidelines-avoid-goto) } } #endif // USE_OTA_PASSWORD // Acknowledge auth OK - 1 byte - buf[0] = OTA_RESPONSE_AUTH_OK; + buf[0] = ota::OTA_RESPONSE_AUTH_OK; this->writeall_(buf, 1); // Read size, 4 bytes MSB first if (!this->readall_(buf, 4)) { - ESP_LOGW(TAG, "Reading size failed!"); + ESP_LOGW(TAG, "Reading size failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } ota_size = 0; @@ -265,20 +242,20 @@ void OTAComponent::handle_() { ota_size <<= 8; ota_size |= buf[i]; } - ESP_LOGV(TAG, "OTA size is %u bytes", ota_size); + ESP_LOGV(TAG, "Size is %u bytes", ota_size); error_code = backend->begin(ota_size); - if (error_code != OTA_RESPONSE_OK) + if (error_code != ota::OTA_RESPONSE_OK) goto error; // NOLINT(cppcoreguidelines-avoid-goto) update_started = true; // Acknowledge prepare OK - 1 byte - buf[0] = OTA_RESPONSE_UPDATE_PREPARE_OK; + buf[0] = ota::OTA_RESPONSE_UPDATE_PREPARE_OK; this->writeall_(buf, 1); // Read binary MD5, 32 bytes if (!this->readall_(buf, 32)) { - ESP_LOGW(TAG, "Reading binary MD5 checksum failed!"); + ESP_LOGW(TAG, "Reading binary MD5 checksum failed"); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } sbuf[32] = '\0'; @@ -286,7 +263,7 @@ void OTAComponent::handle_() { backend->set_update_md5(sbuf); // Acknowledge MD5 OK - 1 byte - buf[0] = OTA_RESPONSE_BIN_MD5_OK; + buf[0] = ota::OTA_RESPONSE_BIN_MD5_OK; this->writeall_(buf, 1); while (total < ota_size) { @@ -299,7 +276,7 @@ void OTAComponent::handle_() { delay(1); continue; } - ESP_LOGW(TAG, "Error receiving data for update, errno: %d", errno); + ESP_LOGW(TAG, "Error receiving data for update, errno %d", errno); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } else if (read == 0) { // $ man recv @@ -310,14 +287,14 @@ void OTAComponent::handle_() { } error_code = backend->write(buf, read); - if (error_code != OTA_RESPONSE_OK) { + if (error_code != ota::OTA_RESPONSE_OK) { ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } total += read; #if USE_OTA_VERSION == 2 while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) { - buf[0] = OTA_RESPONSE_CHUNK_OK; + buf[0] = ota::OTA_RESPONSE_CHUNK_OK; this->writeall_(buf, 1); size_acknowledged += OTA_BLOCK_SIZE; } @@ -327,9 +304,9 @@ void OTAComponent::handle_() { if (now - last_progress > 1000) { last_progress = now; float percentage = (total * 100.0f) / ota_size; - ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage); + ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); #ifdef USE_OTA_STATE_CALLBACK - this->state_callback_.call(OTA_IN_PROGRESS, percentage, 0); + this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0); #endif // feed watchdog and give other tasks a chance to run App.feed_wdt(); @@ -338,32 +315,32 @@ void OTAComponent::handle_() { } // Acknowledge receive OK - 1 byte - buf[0] = OTA_RESPONSE_RECEIVE_OK; + buf[0] = ota::OTA_RESPONSE_RECEIVE_OK; this->writeall_(buf, 1); error_code = backend->end(); - if (error_code != OTA_RESPONSE_OK) { - ESP_LOGW(TAG, "Error ending OTA!, error_code: %d", error_code); + if (error_code != ota::OTA_RESPONSE_OK) { + ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); goto error; // NOLINT(cppcoreguidelines-avoid-goto) } // Acknowledge Update end OK - 1 byte - buf[0] = OTA_RESPONSE_UPDATE_END_OK; + buf[0] = ota::OTA_RESPONSE_UPDATE_END_OK; this->writeall_(buf, 1); // Read ACK - if (!this->readall_(buf, 1) || buf[0] != OTA_RESPONSE_OK) { - ESP_LOGW(TAG, "Reading back acknowledgement failed!"); + if (!this->readall_(buf, 1) || buf[0] != ota::OTA_RESPONSE_OK) { + ESP_LOGW(TAG, "Reading back acknowledgement failed"); // do not go to error, this is not fatal } this->client_->close(); this->client_ = nullptr; delay(10); - ESP_LOGI(TAG, "OTA update finished!"); + ESP_LOGI(TAG, "Update complete"); this->status_clear_warning(); #ifdef USE_OTA_STATE_CALLBACK - this->state_callback_.call(OTA_COMPLETED, 100.0f, 0); + this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, 0); #endif delay(100); // NOLINT App.safe_reboot(); @@ -380,11 +357,11 @@ error: this->status_momentary_error("onerror", 5000); #ifdef USE_OTA_STATE_CALLBACK - this->state_callback_.call(OTA_ERROR, 0.0f, static_cast(error_code)); + this->state_callback_.call(ota::OTA_ERROR, 0.0f, static_cast(error_code)); #endif } -bool OTAComponent::readall_(uint8_t *buf, size_t len) { +bool ESPHomeOTAComponent::readall_(uint8_t *buf, size_t len) { uint32_t start = millis(); uint32_t at = 0; while (len - at > 0) { @@ -401,7 +378,7 @@ bool OTAComponent::readall_(uint8_t *buf, size_t len) { delay(1); continue; } - ESP_LOGW(TAG, "Failed to read %d bytes of data, errno: %d", len, errno); + ESP_LOGW(TAG, "Failed to read %d bytes of data, errno %d", len, errno); return false; } else if (read == 0) { ESP_LOGW(TAG, "Remote closed connection"); @@ -415,7 +392,7 @@ bool OTAComponent::readall_(uint8_t *buf, size_t len) { return true; } -bool OTAComponent::writeall_(const uint8_t *buf, size_t len) { +bool ESPHomeOTAComponent::writeall_(const uint8_t *buf, size_t len) { uint32_t start = millis(); uint32_t at = 0; while (len - at > 0) { @@ -432,7 +409,7 @@ bool OTAComponent::writeall_(const uint8_t *buf, size_t len) { delay(1); continue; } - ESP_LOGW(TAG, "Failed to write %d bytes of data, errno: %d", len, errno); + ESP_LOGW(TAG, "Failed to write %d bytes of data, errno %d", len, errno); return false; } else { at += written; @@ -443,31 +420,31 @@ bool OTAComponent::writeall_(const uint8_t *buf, size_t len) { return true; } -float OTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } -uint16_t OTAComponent::get_port() const { return this->port_; } -void OTAComponent::set_port(uint16_t port) { this->port_ = port; } +float ESPHomeOTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } +uint16_t ESPHomeOTAComponent::get_port() const { return this->port_; } +void ESPHomeOTAComponent::set_port(uint16_t port) { this->port_ = port; } -void OTAComponent::set_safe_mode_pending(const bool &pending) { +void ESPHomeOTAComponent::set_safe_mode_pending(const bool &pending) { if (!this->has_safe_mode_) return; uint32_t current_rtc = this->read_rtc_(); - if (pending && current_rtc != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGI(TAG, "Device will enter safe mode on next boot."); - this->write_rtc_(esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC); + if (pending && current_rtc != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { + ESP_LOGI(TAG, "Device will enter safe mode on next boot"); + this->write_rtc_(ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC); } - if (!pending && current_rtc == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) { + if (!pending && current_rtc == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { ESP_LOGI(TAG, "Safe mode pending has been cleared"); this->clean_rtc(); } } -bool OTAComponent::get_safe_mode_pending() { - return this->has_safe_mode_ && this->read_rtc_() == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC; +bool ESPHomeOTAComponent::get_safe_mode_pending() { + return this->has_safe_mode_ && this->read_rtc_() == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC; } -bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { +bool ESPHomeOTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { this->has_safe_mode_ = true; this->safe_mode_start_time_ = millis(); this->safe_mode_enable_time_ = enable_time; @@ -475,24 +452,24 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_ this->rtc_ = global_preferences->make_preference(233825507UL, false); this->safe_mode_rtc_value_ = this->read_rtc_(); - bool is_manual_safe_mode = this->safe_mode_rtc_value_ == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC; + bool is_manual_safe_mode = this->safe_mode_rtc_value_ == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC; if (is_manual_safe_mode) { ESP_LOGI(TAG, "Safe mode has been entered manually"); } else { - ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_); + ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts", this->safe_mode_rtc_value_); } if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) { this->clean_rtc(); if (!is_manual_safe_mode) { - ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode."); + ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode"); } this->status_set_error(); this->set_timeout(enable_time, []() { - ESP_LOGE(TAG, "No OTA attempt made, restarting."); + ESP_LOGE(TAG, "No OTA attempt made, restarting"); App.reboot(); }); @@ -500,7 +477,7 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_ delay(300); // NOLINT App.setup(); - ESP_LOGI(TAG, "Waiting for OTA attempt."); + ESP_LOGI(TAG, "Waiting for OTA attempt"); return true; } else { @@ -509,27 +486,23 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_ return false; } } -void OTAComponent::write_rtc_(uint32_t val) { + +void ESPHomeOTAComponent::write_rtc_(uint32_t val) { this->rtc_.save(&val); global_preferences->sync(); } -uint32_t OTAComponent::read_rtc_() { + +uint32_t ESPHomeOTAComponent::read_rtc_() { uint32_t val; if (!this->rtc_.load(&val)) return 0; return val; } -void OTAComponent::clean_rtc() { this->write_rtc_(0); } -void OTAComponent::on_safe_shutdown() { - if (this->has_safe_mode_ && this->read_rtc_() != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) + +void ESPHomeOTAComponent::clean_rtc() { this->write_rtc_(0); } + +void ESPHomeOTAComponent::on_safe_shutdown() { + if (this->has_safe_mode_ && this->read_rtc_() != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) this->clean_rtc(); } - -#ifdef USE_OTA_STATE_CALLBACK -void OTAComponent::add_on_state_callback(std::function &&callback) { - this->state_callback_.add(std::move(callback)); -} -#endif - -} // namespace ota } // namespace esphome diff --git a/esphome/components/ota/ota_component.h b/esphome/components/esphome/ota/ota_esphome.h similarity index 50% rename from esphome/components/ota/ota_component.h rename to esphome/components/esphome/ota/ota_esphome.h index c20f4f0709..e8f36f05ca 100644 --- a/esphome/components/ota/ota_component.h +++ b/esphome/components/esphome/ota/ota_esphome.h @@ -1,49 +1,16 @@ #pragma once -#include "esphome/components/socket/socket.h" -#include "esphome/core/component.h" -#include "esphome/core/preferences.h" -#include "esphome/core/helpers.h" #include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" +#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/socket/socket.h" namespace esphome { -namespace ota { -enum OTAResponseTypes { - OTA_RESPONSE_OK = 0x00, - OTA_RESPONSE_REQUEST_AUTH = 0x01, - - OTA_RESPONSE_HEADER_OK = 0x40, - OTA_RESPONSE_AUTH_OK = 0x41, - OTA_RESPONSE_UPDATE_PREPARE_OK = 0x42, - OTA_RESPONSE_BIN_MD5_OK = 0x43, - OTA_RESPONSE_RECEIVE_OK = 0x44, - OTA_RESPONSE_UPDATE_END_OK = 0x45, - OTA_RESPONSE_SUPPORTS_COMPRESSION = 0x46, - OTA_RESPONSE_CHUNK_OK = 0x47, - - OTA_RESPONSE_ERROR_MAGIC = 0x80, - OTA_RESPONSE_ERROR_UPDATE_PREPARE = 0x81, - OTA_RESPONSE_ERROR_AUTH_INVALID = 0x82, - OTA_RESPONSE_ERROR_WRITING_FLASH = 0x83, - OTA_RESPONSE_ERROR_UPDATE_END = 0x84, - OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING = 0x85, - OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG = 0x86, - OTA_RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG = 0x87, - OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE = 0x88, - OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE = 0x89, - OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION = 0x8A, - OTA_RESPONSE_ERROR_MD5_MISMATCH = 0x8B, - OTA_RESPONSE_ERROR_RP2040_NOT_ENOUGH_SPACE = 0x8C, - OTA_RESPONSE_ERROR_UNKNOWN = 0xFF, -}; - -enum OTAState { OTA_COMPLETED = 0, OTA_STARTED, OTA_IN_PROGRESS, OTA_ERROR }; - -/// OTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA. -class OTAComponent : public Component { +/// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA. +class ESPHomeOTAComponent : public ota::OTAComponent { public: - OTAComponent(); #ifdef USE_OTA_PASSWORD void set_auth_password(const std::string &password) { password_ = password; } #endif // USE_OTA_PASSWORD @@ -57,10 +24,6 @@ class OTAComponent : public Component { void set_safe_mode_pending(const bool &pending); bool get_safe_mode_pending(); -#ifdef USE_OTA_STATE_CALLBACK - void add_on_state_callback(std::function &&callback); -#endif - // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; @@ -91,22 +54,15 @@ class OTAComponent : public Component { std::unique_ptr server_; std::unique_ptr client_; - bool has_safe_mode_{false}; ///< stores whether safe mode can be enabled. - uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled. - uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should be on for. + bool has_safe_mode_{false}; ///< stores whether safe mode can be enabled + uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled + uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should be on for uint32_t safe_mode_rtc_value_; uint8_t safe_mode_num_attempts_; ESPPreferenceObject rtc_; static const uint32_t ENTER_SAFE_MODE_MAGIC = 0x5afe5afe; ///< a magic number to indicate that safe mode should be entered on next boot - -#ifdef USE_OTA_STATE_CALLBACK - CallbackManager state_callback_{}; -#endif }; -extern OTAComponent *global_ota_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace ota } // namespace esphome diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 3c845490dc..728d36f3fa 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -1,71 +1,67 @@ -from esphome.cpp_generator import RawExpression import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.const import ( - CONF_ID, - CONF_NUM_ATTEMPTS, - CONF_PASSWORD, - CONF_PORT, - CONF_REBOOT_TIMEOUT, - CONF_SAFE_MODE, - CONF_TRIGGER_ID, - CONF_OTA, - KEY_PAST_SAFE_MODE, - CONF_VERSION, -) from esphome.core import CORE, coroutine_with_priority -CODEOWNERS = ["@esphome/core"] -DEPENDENCIES = ["network"] -AUTO_LOAD = ["socket", "md5"] +from esphome.const import CONF_ESPHOME, CONF_OTA, CONF_PLATFORM, CONF_TRIGGER_ID -CONF_ON_STATE_CHANGE = "on_state_change" +CODEOWNERS = ["@esphome/core"] +AUTO_LOAD = ["md5"] + +IS_PLATFORM_COMPONENT = True + +CONF_ON_ABORT = "on_abort" CONF_ON_BEGIN = "on_begin" -CONF_ON_PROGRESS = "on_progress" CONF_ON_END = "on_end" CONF_ON_ERROR = "on_error" +CONF_ON_PROGRESS = "on_progress" +CONF_ON_STATE_CHANGE = "on_state_change" + ota_ns = cg.esphome_ns.namespace("ota") -OTAState = ota_ns.enum("OTAState") OTAComponent = ota_ns.class_("OTAComponent", cg.Component) +OTAState = ota_ns.enum("OTAState") +OTAAbortTrigger = ota_ns.class_("OTAAbortTrigger", automation.Trigger.template()) +OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template()) +OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template()) +OTAProgressTrigger = ota_ns.class_("OTAProgressTrigger", automation.Trigger.template()) +OTAStartTrigger = ota_ns.class_("OTAStartTrigger", automation.Trigger.template()) OTAStateChangeTrigger = ota_ns.class_( "OTAStateChangeTrigger", automation.Trigger.template() ) -OTAStartTrigger = ota_ns.class_("OTAStartTrigger", automation.Trigger.template()) -OTAProgressTrigger = ota_ns.class_("OTAProgressTrigger", automation.Trigger.template()) -OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template()) -OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template()) -CONFIG_SCHEMA = cv.Schema( +def _ota_final_validate(config): + if len(config) < 1: + raise cv.Invalid( + f"At least one platform must be specified for '{CONF_OTA}'; add '{CONF_PLATFORM}: {CONF_ESPHOME}' for original OTA functionality" + ) + + +FINAL_VALIDATE_SCHEMA = _ota_final_validate + +BASE_OTA_SCHEMA = cv.Schema( { - cv.GenerateID(): cv.declare_id(OTAComponent), - cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean, - cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), - cv.SplitDefault( - CONF_PORT, - esp8266=8266, - esp32=3232, - rp2040=2040, - bk72xx=8892, - rtl87xx=8892, - ): cv.port, - cv.Optional(CONF_PASSWORD): cv.string, - cv.Optional( - CONF_REBOOT_TIMEOUT, default="5min" - ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, cv.Optional(CONF_ON_STATE_CHANGE): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAStateChangeTrigger), } ), + cv.Optional(CONF_ON_ABORT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAAbortTrigger), + } + ), cv.Optional(CONF_ON_BEGIN): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAStartTrigger), } ), + cv.Optional(CONF_ON_END): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAEndTrigger), + } + ), cv.Optional(CONF_ON_ERROR): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAErrorTrigger), @@ -76,35 +72,13 @@ CONFIG_SCHEMA = cv.Schema( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAProgressTrigger), } ), - cv.Optional(CONF_ON_END): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OTAEndTrigger), - } - ), } -).extend(cv.COMPONENT_SCHEMA) +) @coroutine_with_priority(50.0) async def to_code(config): - CORE.data[CONF_OTA] = {} - - var = cg.new_Pvariable(config[CONF_ID]) - cg.add(var.set_port(config[CONF_PORT])) cg.add_define("USE_OTA") - if CONF_PASSWORD in config: - cg.add(var.set_auth_password(config[CONF_PASSWORD])) - cg.add_define("USE_OTA_PASSWORD") - cg.add_define("USE_OTA_VERSION", config[CONF_VERSION]) - - await cg.register_component(var, config) - - if config[CONF_SAFE_MODE]: - condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] - ) - cg.add(RawExpression(f"if ({condition}) return")) - CORE.data[CONF_OTA][KEY_PAST_SAFE_MODE] = True if CORE.is_esp32 and CORE.using_arduino: cg.add_library("Update", None) @@ -112,11 +86,17 @@ async def to_code(config): if CORE.is_rp2040 and CORE.using_arduino: cg.add_library("Updater", None) + +async def ota_to_code(var, config): use_state_callback = False for conf in config.get(CONF_ON_STATE_CHANGE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(OTAState, "state")], conf) use_state_callback = True + for conf in config.get(CONF_ON_ABORT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + use_state_callback = True for conf in config.get(CONF_ON_BEGIN, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/ota/automation.h b/esphome/components/ota/automation.h index 0c77a18ce1..4605193480 100644 --- a/esphome/components/ota/automation.h +++ b/esphome/components/ota/automation.h @@ -1,11 +1,8 @@ #pragma once - -#include "esphome/core/defines.h" #ifdef USE_OTA_STATE_CALLBACK +#include "ota_backend.h" -#include "esphome/core/component.h" #include "esphome/core/automation.h" -#include "esphome/components/ota/ota_component.h" namespace esphome { namespace ota { @@ -54,6 +51,17 @@ class OTAEndTrigger : public Trigger<> { } }; +class OTAAbortTrigger : public Trigger<> { + public: + explicit OTAAbortTrigger(OTAComponent *parent) { + parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { + if (state == OTA_ABORT && !parent->is_failed()) { + trigger(); + } + }); + } +}; + class OTAErrorTrigger : public Trigger { public: explicit OTAErrorTrigger(OTAComponent *parent) { @@ -67,5 +75,4 @@ class OTAErrorTrigger : public Trigger { } // namespace ota } // namespace esphome - -#endif // USE_OTA_STATE_CALLBACK +#endif diff --git a/esphome/components/ota/ota_backend.cpp b/esphome/components/ota/ota_backend.cpp new file mode 100644 index 0000000000..30de4ec4b3 --- /dev/null +++ b/esphome/components/ota/ota_backend.cpp @@ -0,0 +1,20 @@ +#include "ota_backend.h" + +namespace esphome { +namespace ota { + +#ifdef USE_OTA_STATE_CALLBACK +OTAGlobalCallback *global_ota_callback{nullptr}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +OTAGlobalCallback *get_global_ota_callback() { + if (global_ota_callback == nullptr) { + global_ota_callback = new OTAGlobalCallback(); // NOLINT(cppcoreguidelines-owning-memory) + } + return global_ota_callback; +} + +void register_ota_platform(OTAComponent *ota_caller) { get_global_ota_callback()->register_ota(ota_caller); } +#endif + +} // namespace ota +} // namespace esphome diff --git a/esphome/components/ota/ota_backend.h b/esphome/components/ota/ota_backend.h index 5c5b61a278..bc8ab46643 100644 --- a/esphome/components/ota/ota_backend.h +++ b/esphome/components/ota/ota_backend.h @@ -1,9 +1,53 @@ #pragma once -#include "ota_component.h" + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" + +#ifdef USE_OTA_STATE_CALLBACK +#include "esphome/core/automation.h" +#endif namespace esphome { namespace ota { +enum OTAResponseTypes { + OTA_RESPONSE_OK = 0x00, + OTA_RESPONSE_REQUEST_AUTH = 0x01, + + OTA_RESPONSE_HEADER_OK = 0x40, + OTA_RESPONSE_AUTH_OK = 0x41, + OTA_RESPONSE_UPDATE_PREPARE_OK = 0x42, + OTA_RESPONSE_BIN_MD5_OK = 0x43, + OTA_RESPONSE_RECEIVE_OK = 0x44, + OTA_RESPONSE_UPDATE_END_OK = 0x45, + OTA_RESPONSE_SUPPORTS_COMPRESSION = 0x46, + OTA_RESPONSE_CHUNK_OK = 0x47, + + OTA_RESPONSE_ERROR_MAGIC = 0x80, + OTA_RESPONSE_ERROR_UPDATE_PREPARE = 0x81, + OTA_RESPONSE_ERROR_AUTH_INVALID = 0x82, + OTA_RESPONSE_ERROR_WRITING_FLASH = 0x83, + OTA_RESPONSE_ERROR_UPDATE_END = 0x84, + OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING = 0x85, + OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG = 0x86, + OTA_RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG = 0x87, + OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE = 0x88, + OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE = 0x89, + OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION = 0x8A, + OTA_RESPONSE_ERROR_MD5_MISMATCH = 0x8B, + OTA_RESPONSE_ERROR_RP2040_NOT_ENOUGH_SPACE = 0x8C, + OTA_RESPONSE_ERROR_UNKNOWN = 0xFF, +}; + +enum OTAState { + OTA_COMPLETED = 0, + OTA_STARTED, + OTA_IN_PROGRESS, + OTA_ABORT, + OTA_ERROR, +}; + class OTABackend { public: virtual ~OTABackend() = default; @@ -15,5 +59,38 @@ class OTABackend { virtual bool supports_compression() = 0; }; +class OTAComponent : public Component { +#ifdef USE_OTA_STATE_CALLBACK + public: + void add_on_state_callback(std::function &&callback) { + this->state_callback_.add(std::move(callback)); + } + + protected: + CallbackManager state_callback_{}; +#endif +}; + +#ifdef USE_OTA_STATE_CALLBACK +class OTAGlobalCallback { + public: + void register_ota(OTAComponent *ota_caller) { + ota_caller->add_on_state_callback([this, ota_caller](OTAState state, float progress, uint8_t error) { + this->state_callback_.call(state, progress, error, ota_caller); + }); + } + void add_on_state_callback(std::function &&callback) { + this->state_callback_.add(std::move(callback)); + } + + protected: + CallbackManager state_callback_{}; +}; + +OTAGlobalCallback *get_global_ota_callback(); +void register_ota_platform(OTAComponent *ota_caller); +#endif +std::unique_ptr make_ota_backend(); + } // namespace ota } // namespace esphome diff --git a/esphome/components/ota/ota_backend_arduino_esp32.cpp b/esphome/components/ota/ota_backend_arduino_esp32.cpp index 4759737dbd..62c6a72388 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp32.cpp @@ -1,8 +1,7 @@ -#include "esphome/core/defines.h" #ifdef USE_ESP32_FRAMEWORK_ARDUINO +#include "esphome/core/defines.h" #include "ota_backend_arduino_esp32.h" -#include "ota_component.h" #include "ota_backend.h" #include @@ -10,6 +9,8 @@ namespace esphome { namespace ota { +std::unique_ptr make_ota_backend() { return make_unique(); } + OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { bool ret = Update.begin(image_size, U_FLASH); if (ret) { diff --git a/esphome/components/ota/ota_backend_arduino_esp32.h b/esphome/components/ota/ota_backend_arduino_esp32.h index f86a70d678..ac7fe9f14f 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.h +++ b/esphome/components/ota/ota_backend_arduino_esp32.h @@ -1,10 +1,10 @@ #pragma once -#include "esphome/core/defines.h" #ifdef USE_ESP32_FRAMEWORK_ARDUINO - -#include "ota_component.h" #include "ota_backend.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" + namespace esphome { namespace ota { diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.cpp b/esphome/components/ota/ota_backend_arduino_esp8266.cpp index 23dc0d4e21..b317075bd0 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp8266.cpp @@ -1,10 +1,9 @@ -#include "esphome/core/defines.h" #ifdef USE_ARDUINO #ifdef USE_ESP8266 - -#include "ota_backend_arduino_esp8266.h" -#include "ota_component.h" #include "ota_backend.h" +#include "ota_backend_arduino_esp8266.h" + +#include "esphome/core/defines.h" #include "esphome/components/esp8266/preferences.h" #include @@ -12,6 +11,8 @@ namespace esphome { namespace ota { +std::unique_ptr make_ota_backend() { return make_unique(); } + OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { bool ret = Update.begin(image_size, U_FLASH); if (ret) { diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.h b/esphome/components/ota/ota_backend_arduino_esp8266.h index 7937c665b0..7f44d7c965 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.h +++ b/esphome/components/ota/ota_backend_arduino_esp8266.h @@ -1,10 +1,9 @@ #pragma once -#include "esphome/core/defines.h" #ifdef USE_ARDUINO #ifdef USE_ESP8266 - -#include "ota_component.h" #include "ota_backend.h" + +#include "esphome/core/defines.h" #include "esphome/core/macros.h" namespace esphome { diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp index dbf6c97988..df4e774ebc 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.cpp +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -1,15 +1,16 @@ -#include "esphome/core/defines.h" #ifdef USE_LIBRETINY - -#include "ota_backend_arduino_libretiny.h" -#include "ota_component.h" #include "ota_backend.h" +#include "ota_backend_arduino_libretiny.h" + +#include "esphome/core/defines.h" #include namespace esphome { namespace ota { +std::unique_ptr make_ota_backend() { return make_unique(); } + OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { bool ret = Update.begin(image_size, U_FLASH); if (ret) { diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.h b/esphome/components/ota/ota_backend_arduino_libretiny.h index 79656bb353..11deb6e2f2 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.h +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -1,10 +1,9 @@ #pragma once -#include "esphome/core/defines.h" #ifdef USE_LIBRETINY - -#include "ota_component.h" #include "ota_backend.h" +#include "esphome/core/defines.h" + namespace esphome { namespace ota { diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.cpp b/esphome/components/ota/ota_backend_arduino_rp2040.cpp index 260387cec1..4448b0c95e 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.cpp +++ b/esphome/components/ota/ota_backend_arduino_rp2040.cpp @@ -1,17 +1,18 @@ -#include "esphome/core/defines.h" #ifdef USE_ARDUINO #ifdef USE_RP2040 - -#include "esphome/components/rp2040/preferences.h" #include "ota_backend.h" #include "ota_backend_arduino_rp2040.h" -#include "ota_component.h" + +#include "esphome/components/rp2040/preferences.h" +#include "esphome/core/defines.h" #include namespace esphome { namespace ota { +std::unique_ptr make_ota_backend() { return make_unique(); } + OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { bool ret = Update.begin(image_size, U_FLASH); if (ret) { diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.h b/esphome/components/ota/ota_backend_arduino_rp2040.h index 5aa2ec9435..b189964ab3 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.h +++ b/esphome/components/ota/ota_backend_arduino_rp2040.h @@ -1,11 +1,10 @@ #pragma once -#include "esphome/core/defines.h" #ifdef USE_ARDUINO #ifdef USE_RP2040 - -#include "esphome/core/macros.h" #include "ota_backend.h" -#include "ota_component.h" + +#include "esphome/core/defines.h" +#include "esphome/core/macros.h" namespace esphome { namespace ota { diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp index 319a1482f1..6f45fb75e4 100644 --- a/esphome/components/ota/ota_backend_esp_idf.cpp +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -1,12 +1,11 @@ -#include "esphome/core/defines.h" #ifdef USE_ESP_IDF - -#include - #include "ota_backend_esp_idf.h" -#include "ota_component.h" -#include + #include "esphome/components/md5/md5.h" +#include "esphome/core/defines.h" + +#include +#include #if ESP_IDF_VERSION_MAJOR >= 5 #include @@ -15,6 +14,8 @@ namespace esphome { namespace ota { +std::unique_ptr make_ota_backend() { return make_unique(); } + OTAResponseTypes IDFOTABackend::begin(size_t image_size) { this->partition_ = esp_ota_get_next_update_partition(nullptr); if (this->partition_ == nullptr) { diff --git a/esphome/components/ota/ota_backend_esp_idf.h b/esphome/components/ota/ota_backend_esp_idf.h index af09d0d693..ed66d9b970 100644 --- a/esphome/components/ota/ota_backend_esp_idf.h +++ b/esphome/components/ota/ota_backend_esp_idf.h @@ -1,11 +1,11 @@ #pragma once -#include "esphome/core/defines.h" #ifdef USE_ESP_IDF - -#include "ota_component.h" #include "ota_backend.h" -#include + #include "esphome/components/md5/md5.h" +#include "esphome/core/defines.h" + +#include namespace esphome { namespace ota { diff --git a/esphome/components/safe_mode/button/__init__.py b/esphome/components/safe_mode/button/__init__.py index 307e4e372e..bd51d2e038 100644 --- a/esphome/components/safe_mode/button/__init__.py +++ b/esphome/components/safe_mode/button/__init__.py @@ -1,18 +1,17 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import button -from esphome.components.ota import OTAComponent +from esphome.components.esphome.ota import ESPHomeOTAComponent from esphome.const import ( - CONF_ID, - CONF_OTA, + CONF_ESPHOME, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_CONFIG, ICON_RESTART_ALERT, ) +from .. import safe_mode_ns -DEPENDENCIES = ["ota"] +DEPENDENCIES = ["ota.esphome"] -safe_mode_ns = cg.esphome_ns.namespace("safe_mode") SafeModeButton = safe_mode_ns.class_("SafeModeButton", button.Button, cg.Component) CONFIG_SCHEMA = ( @@ -22,15 +21,14 @@ CONFIG_SCHEMA = ( entity_category=ENTITY_CATEGORY_CONFIG, icon=ICON_RESTART_ALERT, ) - .extend({cv.GenerateID(CONF_OTA): cv.use_id(OTAComponent)}) + .extend({cv.GenerateID(CONF_ESPHOME): cv.use_id(ESPHomeOTAComponent)}) .extend(cv.COMPONENT_SCHEMA) ) async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) + var = await button.new_button(config) await cg.register_component(var, config) - await button.register_button(var, config) - ota = await cg.get_variable(config[CONF_OTA]) + ota = await cg.get_variable(config[CONF_ESPHOME]) cg.add(var.set_ota(ota)) diff --git a/esphome/components/safe_mode/button/safe_mode_button.cpp b/esphome/components/safe_mode/button/safe_mode_button.cpp index 2b8654de46..d513b79c12 100644 --- a/esphome/components/safe_mode/button/safe_mode_button.cpp +++ b/esphome/components/safe_mode/button/safe_mode_button.cpp @@ -8,7 +8,7 @@ namespace safe_mode { static const char *const TAG = "safe_mode.button"; -void SafeModeButton::set_ota(ota::OTAComponent *ota) { this->ota_ = ota; } +void SafeModeButton::set_ota(esphome::ESPHomeOTAComponent *ota) { this->ota_ = ota; } void SafeModeButton::press_action() { ESP_LOGI(TAG, "Restarting device in safe mode..."); diff --git a/esphome/components/safe_mode/button/safe_mode_button.h b/esphome/components/safe_mode/button/safe_mode_button.h index 63e0d1755e..a306735b7f 100644 --- a/esphome/components/safe_mode/button/safe_mode_button.h +++ b/esphome/components/safe_mode/button/safe_mode_button.h @@ -1,8 +1,8 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/components/ota/ota_component.h" #include "esphome/components/button/button.h" +#include "esphome/components/esphome/ota/ota_esphome.h" +#include "esphome/core/component.h" namespace esphome { namespace safe_mode { @@ -10,10 +10,10 @@ namespace safe_mode { class SafeModeButton : public button::Button, public Component { public: void dump_config() override; - void set_ota(ota::OTAComponent *ota); + void set_ota(esphome::ESPHomeOTAComponent *ota); protected: - ota::OTAComponent *ota_; + esphome::ESPHomeOTAComponent *ota_; void press_action() override; }; diff --git a/esphome/components/safe_mode/switch/__init__.py b/esphome/components/safe_mode/switch/__init__.py index a6fcdfbece..0f8e500482 100644 --- a/esphome/components/safe_mode/switch/__init__.py +++ b/esphome/components/safe_mode/switch/__init__.py @@ -1,26 +1,26 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import switch -from esphome.components.ota import OTAComponent +from esphome.components.esphome.ota import ESPHomeOTAComponent from esphome.const import ( - CONF_OTA, + CONF_ESPHOME, ENTITY_CATEGORY_CONFIG, ICON_RESTART_ALERT, ) from .. import safe_mode_ns -DEPENDENCIES = ["ota"] +DEPENDENCIES = ["ota.esphome"] SafeModeSwitch = safe_mode_ns.class_("SafeModeSwitch", switch.Switch, cg.Component) CONFIG_SCHEMA = ( switch.switch_schema( SafeModeSwitch, - icon=ICON_RESTART_ALERT, - entity_category=ENTITY_CATEGORY_CONFIG, block_inverted=True, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RESTART_ALERT, ) - .extend({cv.GenerateID(CONF_OTA): cv.use_id(OTAComponent)}) + .extend({cv.GenerateID(CONF_ESPHOME): cv.use_id(ESPHomeOTAComponent)}) .extend(cv.COMPONENT_SCHEMA) ) @@ -29,5 +29,5 @@ async def to_code(config): var = await switch.new_switch(config) await cg.register_component(var, config) - ota = await cg.get_variable(config[CONF_OTA]) + ota = await cg.get_variable(config[CONF_ESPHOME]) cg.add(var.set_ota(ota)) diff --git a/esphome/components/safe_mode/switch/safe_mode_switch.cpp b/esphome/components/safe_mode/switch/safe_mode_switch.cpp index a3979eec06..71408df140 100644 --- a/esphome/components/safe_mode/switch/safe_mode_switch.cpp +++ b/esphome/components/safe_mode/switch/safe_mode_switch.cpp @@ -1,14 +1,14 @@ #include "safe_mode_switch.h" +#include "esphome/core/application.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" -#include "esphome/core/application.h" namespace esphome { namespace safe_mode { static const char *const TAG = "safe_mode_switch"; -void SafeModeSwitch::set_ota(ota::OTAComponent *ota) { this->ota_ = ota; } +void SafeModeSwitch::set_ota(esphome::ESPHomeOTAComponent *ota) { this->ota_ = ota; } void SafeModeSwitch::write_state(bool state) { // Acknowledge diff --git a/esphome/components/safe_mode/switch/safe_mode_switch.h b/esphome/components/safe_mode/switch/safe_mode_switch.h index 2772db3d84..5bd15a44de 100644 --- a/esphome/components/safe_mode/switch/safe_mode_switch.h +++ b/esphome/components/safe_mode/switch/safe_mode_switch.h @@ -1,8 +1,8 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/components/ota/ota_component.h" +#include "esphome/components/esphome/ota/ota_esphome.h" #include "esphome/components/switch/switch.h" +#include "esphome/core/component.h" namespace esphome { namespace safe_mode { @@ -10,10 +10,10 @@ namespace safe_mode { class SafeModeSwitch : public switch_::Switch, public Component { public: void dump_config() override; - void set_ota(ota::OTAComponent *ota); + void set_ota(esphome::ESPHomeOTAComponent *ota); protected: - ota::OTAComponent *ota_; + esphome::ESPHomeOTAComponent *ota_; void write_state(bool state) override; }; diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index 4b3716e223..ce494e5d9d 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -3,14 +3,16 @@ import logging from esphome.const import ( CONF_DISABLED_BY_DEFAULT, CONF_ENTITY_CATEGORY, + CONF_ESPHOME, CONF_ICON, CONF_INTERNAL, CONF_NAME, - CONF_SETUP_PRIORITY, - CONF_UPDATE_INTERVAL, - CONF_TYPE_ID, CONF_OTA, + CONF_PLATFORM, CONF_SAFE_MODE, + CONF_SETUP_PRIORITY, + CONF_TYPE_ID, + CONF_UPDATE_INTERVAL, KEY_PAST_SAFE_MODE, ) @@ -139,9 +141,16 @@ async def build_registry_list(registry, config): async def past_safe_mode(): - safe_mode_enabled = ( - CONF_OTA in CORE.config and CORE.config[CONF_OTA][CONF_SAFE_MODE] - ) + ota_conf = {} + for ota_item in CORE.config.get(CONF_OTA, []): + if ota_item[CONF_PLATFORM] == CONF_ESPHOME: + ota_conf = ota_item + break + + if not ota_conf: + return + + safe_mode_enabled = ota_conf[CONF_SAFE_MODE] if not safe_mode_enabled: return diff --git a/esphome/wizard.py b/esphome/wizard.py index 4ec366bbb9..9680ade044 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -153,10 +153,11 @@ def wizard_file(**kwargs): # Configure OTA config += "\nota:\n" + config += " - platform: esphome\n" if "ota_password" in kwargs: - config += f" password: \"{kwargs['ota_password']}\"" + config += f" password: \"{kwargs['ota_password']}\"" elif "password" in kwargs: - config += f" password: \"{kwargs['password']}\"" + config += f" password: \"{kwargs['password']}\"" # Configuring wifi config += "\n\nwifi:\n" diff --git a/tests/components/ota/common.yaml b/tests/components/ota/common.yaml index 367454995f..4910e2d891 100644 --- a/tests/components/ota/common.yaml +++ b/tests/components/ota/common.yaml @@ -3,28 +3,29 @@ wifi: password: password1 ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); + - platform: esphome + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml index df0abd9aec..1dfc516254 100644 --- a/tests/components/safe_mode/common.yaml +++ b/tests/components/safe_mode/common.yaml @@ -3,6 +3,8 @@ wifi: password: password1 ota: + - platform: esphome + safe_mode: true button: - platform: safe_mode diff --git a/tests/dummy_main.cpp b/tests/dummy_main.cpp index da5c6d10d0..3ba4c8bd07 100644 --- a/tests/dummy_main.cpp +++ b/tests/dummy_main.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include @@ -25,7 +25,7 @@ void setup() { ap.set_password("password1"); wifi->add_sta(ap); - auto *ota = new ota::OTAComponent(); // NOLINT + auto *ota = new esphome::ESPHomeOTAComponent(); // NOLINT ota->set_port(8266); App.setup(); diff --git a/tests/test1.yaml b/tests/test1.yaml index 79b836da4a..dc46b55c44 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -265,29 +265,30 @@ uart: baud_rate: 9600 ota: - safe_mode: true - password: "superlongpasswordthatnoonewillknow" - port: 3286 - reboot_timeout: 2min - num_attempts: 5 - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); - on_begin: - then: - logger.log: OTA begin - on_progress: - then: - lambda: >- - ESP_LOGD("ota", "Got progress %f", x); - on_end: - then: - logger.log: OTA end - on_error: - then: - lambda: >- - ESP_LOGD("ota", "Got error code %d", x); + - platform: esphome + safe_mode: true + password: "superlongpasswordthatnoonewillknow" + port: 3286 + reboot_timeout: 2min + num_attempts: 5 + on_state_change: + then: + lambda: >- + ESP_LOGD("ota", "State %d", state); + on_begin: + then: + logger.log: OTA begin + on_progress: + then: + lambda: >- + ESP_LOGD("ota", "Got progress %f", x); + on_end: + then: + logger.log: OTA end + on_error: + then: + lambda: >- + ESP_LOGD("ota", "Got error code %d", x); logger: baud_rate: 0 diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml index 13de7f1929..758f295a6c 100644 --- a/tests/test11.5.yaml +++ b/tests/test11.5.yaml @@ -31,6 +31,7 @@ network: api: ota: + - platform: esphome logger: diff --git a/tests/test2.yaml b/tests/test2.yaml index 970076e78b..54ff4807a3 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -80,9 +80,10 @@ uart: - lambda: UARTDebug::log_hex(direction, bytes, ':'); ota: - safe_mode: true - port: 3286 - num_attempts: 15 + - platform: esphome + safe_mode: true + port: 3286 + num_attempts: 15 logger: level: DEBUG diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 2bddd6f4d7..18d92289cd 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -49,7 +49,8 @@ spi: number: GPIO14 ota: - version: 2 + - platform: esphome + version: 2 logger: diff --git a/tests/test3.yaml b/tests/test3.yaml index 61d814385b..7554d4bcb2 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -328,9 +328,10 @@ vbus: uart_id: uart_4 ota: - safe_mode: true - port: 3286 - reboot_timeout: 15min + - platform: esphome + safe_mode: true + port: 3286 + reboot_timeout: 15min logger: hardware_uart: UART1 diff --git a/tests/test4.yaml b/tests/test4.yaml index 993ce126a8..86beee81c6 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -103,8 +103,9 @@ uart: parity: EVEN ota: - safe_mode: true - port: 3286 + - platform: esphome + safe_mode: true + port: 3286 logger: level: DEBUG diff --git a/tests/test5.yaml b/tests/test5.yaml index afd3359098..f7a34d5a1b 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -28,6 +28,7 @@ network: api: ota: + - platform: esphome logger: diff --git a/tests/test6.yaml b/tests/test6.yaml index 2c5aa30aad..b1103eb126 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -22,6 +22,7 @@ network: api: ota: + - platform: esphome logger: diff --git a/tests/test9.1.yaml b/tests/test9.1.yaml index f7455b7668..2d205ef4e6 100644 --- a/tests/test9.1.yaml +++ b/tests/test9.1.yaml @@ -12,6 +12,7 @@ esphome: logger: ota: + - platform: esphome captive_portal: diff --git a/tests/test9.yaml b/tests/test9.yaml index d660b4f24a..5017ccc5ed 100644 --- a/tests/test9.yaml +++ b/tests/test9.yaml @@ -12,6 +12,7 @@ esphome: logger: ota: + - platform: esphome captive_portal: From 247b2eee302fd69096bdd01f79d63b8b629c91ba Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Thu, 16 May 2024 02:11:21 +0000 Subject: [PATCH 1757/2607] Add ADC multisampling (#6330) --- esphome/components/adc/adc_sensor.cpp | 158 +++++++++++++++----------- esphome/components/adc/adc_sensor.h | 18 +-- esphome/components/adc/sensor.py | 8 ++ 3 files changed, 112 insertions(+), 72 deletions(-) diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 1a76bdb264..7257793016 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -46,27 +46,27 @@ extern "C" ADCSensor::setup() { ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); #if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040) - pin_->setup(); + this->pin_->setup(); #endif #ifdef USE_ESP32 - if (channel1_ != ADC1_CHANNEL_MAX) { + if (this->channel1_ != ADC1_CHANNEL_MAX) { adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); - if (!autorange_) { - adc1_config_channel_atten(channel1_, attenuation_); + if (!this->autorange_) { + adc1_config_channel_atten(this->channel1_, this->attenuation_); } - } else if (channel2_ != ADC2_CHANNEL_MAX) { - if (!autorange_) { - adc2_config_channel_atten(channel2_, attenuation_); + } else if (this->channel2_ != ADC2_CHANNEL_MAX) { + if (!this->autorange_) { + adc2_config_channel_atten(this->channel2_, this->attenuation_); } } // load characteristics for each attenuation for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) { - auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; + auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, 1100, // default vref - &cal_characteristics_[i]); + &this->cal_characteristics_[i]); switch (cal_value) { case ESP_ADC_CAL_VAL_EFUSE_VREF: ESP_LOGV(TAG, "Using eFuse Vref for calibration"); @@ -99,27 +99,27 @@ void ADCSensor::dump_config() { #ifdef USE_ADC_SENSOR_VCC ESP_LOGCONFIG(TAG, " Pin: VCC"); #else - LOG_PIN(" Pin: ", pin_); + LOG_PIN(" Pin: ", this->pin_); #endif #endif // USE_ESP8266 || USE_LIBRETINY #ifdef USE_ESP32 - LOG_PIN(" Pin: ", pin_); - if (autorange_) { - ESP_LOGCONFIG(TAG, " Attenuation: auto"); + LOG_PIN(" Pin: ", this->pin_); + if (this->autorange_) { + ESP_LOGCONFIG(TAG, " Attenuation: auto"); } else { switch (this->attenuation_) { case ADC_ATTEN_DB_0: - ESP_LOGCONFIG(TAG, " Attenuation: 0db"); + ESP_LOGCONFIG(TAG, " Attenuation: 0db"); break; case ADC_ATTEN_DB_2_5: - ESP_LOGCONFIG(TAG, " Attenuation: 2.5db"); + ESP_LOGCONFIG(TAG, " Attenuation: 2.5db"); break; case ADC_ATTEN_DB_6: - ESP_LOGCONFIG(TAG, " Attenuation: 6db"); + ESP_LOGCONFIG(TAG, " Attenuation: 6db"); break; case ADC_ATTEN_DB_12_COMPAT: - ESP_LOGCONFIG(TAG, " Attenuation: 12db"); + ESP_LOGCONFIG(TAG, " Attenuation: 12db"); break; default: // This is to satisfy the unused ADC_ATTEN_MAX break; @@ -134,11 +134,11 @@ void ADCSensor::dump_config() { #ifdef USE_ADC_SENSOR_VCC ESP_LOGCONFIG(TAG, " Pin: VCC"); #else - LOG_PIN(" Pin: ", pin_); + LOG_PIN(" Pin: ", this->pin_); #endif // USE_ADC_SENSOR_VCC } #endif // USE_RP2040 - + ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); LOG_UPDATE_INTERVAL(this); } @@ -149,14 +149,24 @@ void ADCSensor::update() { this->publish_state(value_v); } +void ADCSensor::set_sample_count(uint8_t sample_count) { + if (sample_count != 0) { + this->sample_count_ = sample_count; + } +} + #ifdef USE_ESP8266 float ADCSensor::sample() { + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { #ifdef USE_ADC_SENSOR_VCC - int32_t raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) + raw += ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) #else - int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT + raw += analogRead(this->pin_->get_pin()); // NOLINT #endif - if (output_raw_) { + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + if (this->output_raw_) { return raw; } return raw / 1024.0f; @@ -165,53 +175,57 @@ float ADCSensor::sample() { #ifdef USE_ESP32 float ADCSensor::sample() { - if (!autorange_) { - int raw = -1; - if (channel1_ != ADC1_CHANNEL_MAX) { - raw = adc1_get_raw(channel1_); - } else if (channel2_ != ADC2_CHANNEL_MAX) { - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw); + if (!this->autorange_) { + uint32_t sum = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + int raw = -1; + if (this->channel1_ != ADC1_CHANNEL_MAX) { + raw = adc1_get_raw(this->channel1_); + } else if (this->channel2_ != ADC2_CHANNEL_MAX) { + adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw); + } + if (raw == -1) { + return NAN; + } + sum += raw; } - - if (raw == -1) { - return NAN; + sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + if (this->output_raw_) { + return sum; } - if (output_raw_) { - return raw; - } - uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]); + uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]); return mv / 1000.0f; } int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; - if (channel1_ != ADC1_CHANNEL_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_12_COMPAT); - raw12 = adc1_get_raw(channel1_); + if (this->channel1_ != ADC1_CHANNEL_MAX) { + adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT); + raw12 = adc1_get_raw(this->channel1_); if (raw12 < ADC_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); - raw6 = adc1_get_raw(channel1_); + adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6); + raw6 = adc1_get_raw(this->channel1_); if (raw6 < ADC_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5); - raw2 = adc1_get_raw(channel1_); + adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5); + raw2 = adc1_get_raw(this->channel1_); if (raw2 < ADC_MAX) { - adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0); - raw0 = adc1_get_raw(channel1_); + adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0); + raw0 = adc1_get_raw(this->channel1_); } } } - } else if (channel2_ != ADC2_CHANNEL_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_12_COMPAT); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12); + } else if (this->channel2_ != ADC2_CHANNEL_MAX) { + adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT); + adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12); if (raw12 < ADC_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); + adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6); + adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); if (raw6 < ADC_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2); + adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5); + adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2); if (raw2 < ADC_MAX) { - adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0); - adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0); + adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0); + adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0); } } } @@ -221,10 +235,10 @@ float ADCSensor::sample() { return NAN; } - uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]); - uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); - uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); - uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); + uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]); + uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); + uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); + uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) uint32_t c12 = std::min(raw12, ADC_HALF); @@ -246,8 +260,11 @@ float ADCSensor::sample() { adc_set_temp_sensor_enabled(true); delay(1); adc_select_input(4); - - int32_t raw = adc_read(); + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += adc_read(); + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) adc_set_temp_sensor_enabled(false); if (this->output_raw_) { return raw; @@ -268,7 +285,11 @@ float ADCSensor::sample() { adc_gpio_init(pin); adc_select_input(pin - 26); - int32_t raw = adc_read(); + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += adc_read(); + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) #ifdef CYW43_USES_VSYS_PIN if (pin == PICO_VSYS_PIN) { @@ -276,7 +297,7 @@ float ADCSensor::sample() { } #endif // CYW43_USES_VSYS_PIN - if (output_raw_) { + if (this->output_raw_) { return raw; } float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0; @@ -287,10 +308,19 @@ float ADCSensor::sample() { #ifdef USE_LIBRETINY float ADCSensor::sample() { - if (output_raw_) { - return analogRead(this->pin_->get_pin()); // NOLINT + uint32_t raw = 0; + if (this->output_raw_) { + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += analogRead(this->pin_->get_pin()); // NOLINT + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + return raw; } - return analogReadVoltage(this->pin_->get_pin()) / 1000.0f; // NOLINT + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += analogReadVoltage(this->pin_->get_pin()); // NOLINT + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + return raw / 1000.0f; } #endif // USE_LIBRETINY diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index d99c4bc75b..b697d6dd7e 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -33,16 +33,16 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage public: #ifdef USE_ESP32 /// Set the attenuation for this pin. Only available on the ESP32. - void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; } + void set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; } void set_channel1(adc1_channel_t channel) { - channel1_ = channel; - channel2_ = ADC2_CHANNEL_MAX; + this->channel1_ = channel; + this->channel2_ = ADC2_CHANNEL_MAX; } void set_channel2(adc2_channel_t channel) { - channel2_ = channel; - channel1_ = ADC1_CHANNEL_MAX; + this->channel2_ = channel; + this->channel1_ = ADC1_CHANNEL_MAX; } - void set_autorange(bool autorange) { autorange_ = autorange; } + void set_autorange(bool autorange) { this->autorange_ = autorange; } #endif /// Update ADC values @@ -53,7 +53,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage /// `HARDWARE_LATE` setup priority float get_setup_priority() const override; void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; } - void set_output_raw(bool output_raw) { output_raw_ = output_raw; } + void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; } + void set_sample_count(uint8_t sample_count); float sample() override; #ifdef USE_ESP8266 @@ -61,12 +62,13 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #endif #ifdef USE_RP2040 - void set_is_temperature() { is_temperature_ = true; } + void set_is_temperature() { this->is_temperature_ = true; } #endif protected: InternalGPIOPin *pin_; bool output_raw_{false}; + uint8_t sample_count_{1}; #ifdef USE_RP2040 bool is_temperature_{false}; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 4cf3d52802..59ea9e184c 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -29,6 +29,8 @@ _LOGGER = logging.getLogger(__name__) AUTO_LOAD = ["voltage_sampler"] +CONF_SAMPLES = "samples" + _attenuation = cv.enum(ATTENUATION_MODES, lower=True) @@ -37,6 +39,10 @@ def validate_config(config): if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") + if config.get(CONF_ATTENUATION, None) == "auto" and config.get(CONF_SAMPLES, 1) > 1: + raise cv.Invalid( + "Automatic attenuation cannot be used when multisampling is set" + ) if config.get(CONF_ATTENUATION) == "11db": _LOGGER.warning( "`attenuation: 11db` is deprecated, use `attenuation: 12db` instead" @@ -81,6 +87,7 @@ CONFIG_SCHEMA = cv.All( cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All( cv.only_on_esp32, _attenuation ), + cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255), } ) .extend(cv.polling_component_schema("60s")), @@ -104,6 +111,7 @@ async def to_code(config): cg.add(var.set_pin(pin)) cg.add(var.set_output_raw(config[CONF_RAW])) + cg.add(var.set_sample_count(config[CONF_SAMPLES])) if attenuation := config.get(CONF_ATTENUATION): if attenuation == "auto": From 7c243dafb35decec2869f6eed38b7f9ef64611c7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 14:11:54 +1200 Subject: [PATCH 1758/2607] [core] Fix some extends cases (#6748) --- esphome/components/substitutions/__init__.py | 4 +-- esphome/config_helpers.py | 27 +++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/esphome/components/substitutions/__init__.py b/esphome/components/substitutions/__init__.py index 2d3a79ccae..fa52200d46 100644 --- a/esphome/components/substitutions/__init__.py +++ b/esphome/components/substitutions/__init__.py @@ -4,7 +4,7 @@ import esphome.config_validation as cv from esphome import core from esphome.const import CONF_SUBSTITUTIONS, VALID_SUBSTITUTIONS_CHARACTERS from esphome.yaml_util import ESPHomeDataBase, make_data_base -from esphome.config_helpers import merge_config +from esphome.config_helpers import merge_config, Extend, Remove CODEOWNERS = ["@esphome/core"] _LOGGER = logging.getLogger(__name__) @@ -105,7 +105,7 @@ def _substitute_item(substitutions, item, path, ignore_missing): sub = _expand_substitutions(substitutions, item, path, ignore_missing) if sub != item: return sub - elif isinstance(item, core.Lambda): + elif isinstance(item, (core.Lambda, Extend, Remove)): sub = _expand_substitutions(substitutions, item.value, path, ignore_missing) if sub != item: item.value = sub diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index 7b47e097c8..b5e0b26143 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -8,6 +8,9 @@ class Extend: def __str__(self): return f"!extend {self.value}" + def __repr__(self): + return f"Extend({self.value})" + def __eq__(self, b): """ Check if two Extend objects contain the same ID. @@ -24,6 +27,9 @@ class Remove: def __str__(self): return f"!remove {self.value}" + def __repr__(self): + return f"Remove({self.value})" + def __eq__(self, b): """ Check if two Remove objects contain the same ID. @@ -50,14 +56,19 @@ def merge_config(full_old, full_new): return new res = old.copy() ids = { - v[CONF_ID]: i + v_id: i for i, v in enumerate(res) - if CONF_ID in v and isinstance(v[CONF_ID], str) + if (v_id := v.get(CONF_ID)) and isinstance(v_id, str) } + extend_ids = { + v_id.value: i + for i, v in enumerate(res) + if (v_id := v.get(CONF_ID)) and isinstance(v_id, Extend) + } + ids_to_delete = [] for v in new: - if CONF_ID in v: - new_id = v[CONF_ID] + if new_id := v.get(CONF_ID): if isinstance(new_id, Extend): new_id = new_id.value if new_id in ids: @@ -69,6 +80,14 @@ def merge_config(full_old, full_new): if new_id in ids: ids_to_delete.append(ids[new_id]) continue + elif ( + new_id in extend_ids + ): # When a package is extending a non-packaged item + extend_res = res[extend_ids[new_id]] + extend_res[CONF_ID] = new_id + new_v = merge(v, extend_res) + res[extend_ids[new_id]] = new_v + continue else: ids[new_id] = len(res) res.append(v) From 0bb2773c646fc3b0d1fe65a73e8e98dd57523e95 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Thu, 16 May 2024 05:49:40 +0300 Subject: [PATCH 1759/2607] Port wifi_component_esp32_arduino from tcpip_adapter to esp_netif (#6476) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../wifi/wifi_component_esp32_arduino.cpp | 329 ++++++++++-------- .../wifi/wifi_component_esp_idf.cpp | 60 ++-- 2 files changed, 219 insertions(+), 170 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 44d77b4eed..ef7a624cd5 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -2,6 +2,7 @@ #ifdef USE_ESP32_FRAMEWORK_ARDUINO +#include #include #include @@ -24,45 +25,73 @@ namespace wifi { static const char *const TAG = "wifi_esp32"; +static esp_netif_t *s_sta_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +#ifdef USE_WIFI_AP +static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +#endif // USE_WIFI_AP + static bool s_sta_connecting = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +void WiFiComponent::wifi_pre_setup_() { + auto f = std::bind(&WiFiComponent::wifi_event_callback_, this, std::placeholders::_1, std::placeholders::_2); + WiFi.onEvent(f); + WiFi.persistent(false); + // Make sure WiFi is in clean state before anything starts + this->wifi_mode_(false, false); +} + bool WiFiComponent::wifi_mode_(optional sta, optional ap) { - uint8_t current_mode = WiFiClass::getMode(); - bool current_sta = current_mode & 0b01; - bool current_ap = current_mode & 0b10; - bool enable_sta = sta.value_or(current_sta); - bool enable_ap = ap.value_or(current_ap); - if (current_sta == enable_sta && current_ap == enable_ap) + wifi_mode_t current_mode = WiFiClass::getMode(); + bool current_sta = current_mode == WIFI_MODE_STA || current_mode == WIFI_MODE_APSTA; + bool current_ap = current_mode == WIFI_MODE_AP || current_mode == WIFI_MODE_APSTA; + + bool set_sta = sta.value_or(current_sta); + bool set_ap = ap.value_or(current_ap); + + wifi_mode_t set_mode; + if (set_sta && set_ap) { + set_mode = WIFI_MODE_APSTA; + } else if (set_sta && !set_ap) { + set_mode = WIFI_MODE_STA; + } else if (!set_sta && set_ap) { + set_mode = WIFI_MODE_AP; + } else { + set_mode = WIFI_MODE_NULL; + } + + if (current_mode == set_mode) return true; - if (enable_sta && !current_sta) { + if (set_sta && !current_sta) { ESP_LOGV(TAG, "Enabling STA."); - } else if (!enable_sta && current_sta) { + } else if (!set_sta && current_sta) { ESP_LOGV(TAG, "Disabling STA."); } - if (enable_ap && !current_ap) { + if (set_ap && !current_ap) { ESP_LOGV(TAG, "Enabling AP."); - } else if (!enable_ap && current_ap) { + } else if (!set_ap && current_ap) { ESP_LOGV(TAG, "Disabling AP."); } - uint8_t mode = 0; - if (enable_sta) - mode |= 0b01; - if (enable_ap) - mode |= 0b10; - bool ret = WiFiClass::mode(static_cast(mode)); + bool ret = WiFiClass::mode(set_mode); if (!ret) { ESP_LOGW(TAG, "Setting WiFi mode failed!"); + return false; } + // WiFiClass::mode above calls esp_netif_create_default_wifi_sta() and + // esp_netif_create_default_wifi_ap(), which creates the interfaces. + if (set_sta) + s_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); +#ifdef USE_WIFI_AP + if (set_ap) + s_ap_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); +#endif + return ret; } -bool WiFiComponent::wifi_apply_output_power_(float output_power) { - int8_t val = static_cast(output_power * 4); - return esp_wifi_set_max_tx_power(val) == ESP_OK; -} + bool WiFiComponent::wifi_sta_pre_setup_() { if (!this->wifi_mode_(true, {})) return false; @@ -71,6 +100,12 @@ bool WiFiComponent::wifi_sta_pre_setup_() { delay(10); return true; } + +bool WiFiComponent::wifi_apply_output_power_(float output_power) { + int8_t val = static_cast(output_power * 4); + return esp_wifi_set_max_tx_power(val) == ESP_OK; +} + bool WiFiComponent::wifi_apply_power_save_() { wifi_ps_type_t power_save; switch (this->power_save_) { @@ -87,99 +122,7 @@ bool WiFiComponent::wifi_apply_power_save_() { } return esp_wifi_set_ps(power_save) == ESP_OK; } -bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { - // enable STA - if (!this->wifi_mode_(true, {})) - return false; - tcpip_adapter_dhcp_status_t dhcp_status; - tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &dhcp_status); - if (!manual_ip.has_value()) { - // lwIP starts the SNTP client if it gets an SNTP server from DHCP. We don't need the time, and more importantly, - // the built-in SNTP client has a memory leak in certain situations. Disable this feature. - // https://github.com/esphome/issues/issues/2299 - sntp_servermode_dhcp(false); - - // Use DHCP client - if (dhcp_status != TCPIP_ADAPTER_DHCP_STARTED) { - esp_err_t err = tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); - if (err != ESP_OK) { - ESP_LOGV(TAG, "Starting DHCP client failed! %d", err); - } - return err == ESP_OK; - } - return true; - } - - tcpip_adapter_ip_info_t info; - memset(&info, 0, sizeof(info)); - info.ip = manual_ip->static_ip; - info.gw = manual_ip->gateway; - info.netmask = manual_ip->subnet; - - esp_err_t dhcp_stop_ret = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); - if (dhcp_stop_ret != ESP_OK && dhcp_stop_ret != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "Stopping DHCP client failed! %s", esp_err_to_name(dhcp_stop_ret)); - } - - esp_err_t wifi_set_info_ret = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &info); - if (wifi_set_info_ret != ESP_OK) { - ESP_LOGV(TAG, "Setting manual IP info failed! %s", esp_err_to_name(wifi_set_info_ret)); - } - - ip_addr_t dns; -// TODO: is this needed? -#if LWIP_IPV6 - dns.type = IPADDR_TYPE_V4; -#endif /* LWIP_IPV6 */ - if (manual_ip->dns1.is_set()) { - dns = manual_ip->dns1; - dns_setserver(0, &dns); - } - if (manual_ip->dns2.is_set()) { - dns = manual_ip->dns2; - dns_setserver(1, &dns); - } - - return true; -} - -network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { - if (!this->has_sta()) - return {}; - network::IPAddresses addresses; - tcpip_adapter_ip_info_t ip; - esp_err_t err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip); - if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); - // TODO: do something smarter - // return false; - } else { - addresses[0] = network::IPAddress(&ip.ip); - } -#if USE_NETWORK_IPV6 - ip6_addr_t ipv6; - err = tcpip_adapter_get_ip6_global(TCPIP_ADAPTER_IF_STA, &ipv6); - if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_get_ip6_gobal failed: %s", esp_err_to_name(err)); - } else { - addresses[1] = network::IPAddress(&ipv6); - } - err = tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &ipv6); - if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_get_ip6_linklocal failed: %s", esp_err_to_name(err)); - } else { - addresses[2] = network::IPAddress(&ipv6); - } -#endif /* USE_NETWORK_IPV6 */ - - return addresses; -} - -bool WiFiComponent::wifi_apply_hostname_() { - // setting is done in SYSTEM_EVENT_STA_START callback - return true; -} bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // enable STA if (!this->wifi_mode_(true, {})) @@ -233,19 +176,24 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { wifi_config_t current_conf; esp_err_t err; - esp_wifi_get_config(WIFI_IF_STA, ¤t_conf); + err = esp_wifi_get_config(WIFI_IF_STA, ¤t_conf); + if (err != ERR_OK) { + ESP_LOGW(TAG, "esp_wifi_get_config failed: %s", esp_err_to_name(err)); + // can continue + } if (memcmp(¤t_conf, &conf, sizeof(wifi_config_t)) != 0) { // NOLINT err = esp_wifi_disconnect(); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_disconnect failed! %d", err); + ESP_LOGV(TAG, "esp_wifi_disconnect failed: %s", esp_err_to_name(err)); return false; } } err = esp_wifi_set_config(WIFI_IF_STA, &conf); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_set_config failed! %d", err); + ESP_LOGV(TAG, "esp_wifi_set_config failed: %s", esp_err_to_name(err)); + return false; } if (!this->wifi_sta_ip_config_(ap.get_manual_ip())) { @@ -304,12 +252,98 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { err = esp_wifi_connect(); if (err != ESP_OK) { - ESP_LOGW(TAG, "esp_wifi_connect failed! %d", err); + ESP_LOGW(TAG, "esp_wifi_connect failed: %s", esp_err_to_name(err)); return false; } return true; } + +bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { + // enable STA + if (!this->wifi_mode_(true, {})) + return false; + + esp_netif_dhcp_status_t dhcp_status; + esp_err_t err = esp_netif_dhcpc_get_status(s_sta_netif, &dhcp_status); + if (err != ESP_OK) { + ESP_LOGV(TAG, "esp_netif_dhcpc_get_status failed: %s", esp_err_to_name(err)); + return false; + } + + if (!manual_ip.has_value()) { + // lwIP starts the SNTP client if it gets an SNTP server from DHCP. We don't need the time, and more importantly, + // the built-in SNTP client has a memory leak in certain situations. Disable this feature. + // https://github.com/esphome/issues/issues/2299 + sntp_servermode_dhcp(false); + + // No manual IP is set; use DHCP client + if (dhcp_status != ESP_NETIF_DHCP_STARTED) { + err = esp_netif_dhcpc_start(s_sta_netif); + if (err != ESP_OK) { + ESP_LOGV(TAG, "Starting DHCP client failed! %d", err); + } + return err == ESP_OK; + } + return true; + } + + esp_netif_ip_info_t info; // struct of ip4_addr_t with ip, netmask, gw + info.ip = manual_ip->static_ip; + info.gw = manual_ip->gateway; + info.netmask = manual_ip->subnet; + err = esp_netif_dhcpc_stop(s_sta_netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { + ESP_LOGV(TAG, "Stopping DHCP client failed! %s", esp_err_to_name(err)); + } + + err = esp_netif_set_ip_info(s_sta_netif, &info); + if (err != ESP_OK) { + ESP_LOGV(TAG, "Setting manual IP info failed! %s", esp_err_to_name(err)); + } + + esp_netif_dns_info_t dns; + if (manual_ip->dns1.is_set()) { + dns.ip = manual_ip->dns1; + esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_MAIN, &dns); + } + if (manual_ip->dns2.is_set()) { + dns.ip = manual_ip->dns2; + esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_BACKUP, &dns); + } + + return true; +} + +network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { + if (!this->has_sta()) + return {}; + network::IPAddresses addresses; + esp_netif_ip_info_t ip; + esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip); + if (err != ESP_OK) { + ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); + // TODO: do something smarter + // return false; + } else { + addresses[0] = network::IPAddress(&ip.ip); + } +#if USE_NETWORK_IPV6 + struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; + uint8_t count = 0; + count = esp_netif_get_all_ip6(s_sta_netif, if_ip6s); + assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES); + for (int i = 0; i < count; i++) { + addresses[i + 1] = network::IPAddress(&if_ip6s[i]); + } +#endif /* USE_NETWORK_IPV6 */ + return addresses; +} + +bool WiFiComponent::wifi_apply_hostname_() { + // setting is done in SYSTEM_EVENT_STA_START callback + return true; +} const char *get_auth_mode_str(uint8_t mode) { switch (mode) { case WIFI_AUTH_OPEN: @@ -324,6 +358,12 @@ const char *get_auth_mode_str(uint8_t mode) { return "WPA/WPA2 PSK"; case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2 Enterprise"; + case WIFI_AUTH_WPA3_PSK: + return "WPA3 PSK"; + case WIFI_AUTH_WPA2_WPA3_PSK: + return "WPA2/WPA3 PSK"; + case WIFI_AUTH_WAPI_PSK: + return "WAPI PSK"; default: return "UNKNOWN"; } @@ -409,12 +449,16 @@ const char *get_disconnect_reason_str(uint8_t reason) { return "Handshake Failed"; case WIFI_REASON_CONNECTION_FAIL: return "Connection Failed"; + case WIFI_REASON_ROAMING: + return "Station Roaming"; case WIFI_REASON_UNSPECIFIED: default: return "Unspecified"; } } +void WiFiComponent::wifi_loop_() {} + #define ESPHOME_EVENT_ID_WIFI_READY ARDUINO_EVENT_WIFI_READY #define ESPHOME_EVENT_ID_WIFI_SCAN_DONE ARDUINO_EVENT_WIFI_SCAN_DONE #define ESPHOME_EVENT_ID_WIFI_STA_START ARDUINO_EVENT_WIFI_STA_START @@ -450,7 +494,11 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ } case ESPHOME_EVENT_ID_WIFI_STA_START: { ESP_LOGV(TAG, "Event: WiFi STA start"); - tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, App.get_name().c_str()); + // apply hostname + esp_err_t err = esp_netif_set_hostname(s_sta_netif, App.get_name().c_str()); + if (err != ERR_OK) { + ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err)); + } break; } case ESPHOME_EVENT_ID_WIFI_STA_STOP: { @@ -573,22 +621,19 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ break; } } -void WiFiComponent::wifi_pre_setup_() { - auto f = std::bind(&WiFiComponent::wifi_event_callback_, this, std::placeholders::_1, std::placeholders::_2); - WiFi.onEvent(f); - WiFi.persistent(false); - // Make sure WiFi is in clean state before anything starts - this->wifi_mode_(false, false); -} + WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { auto status = WiFiClass::status(); if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; - } else if (status == WL_NO_SSID_AVAIL) { + } + if (status == WL_NO_SSID_AVAIL) { return WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND; - } else if (s_sta_connecting) { + } + if (s_sta_connecting) { return WiFiSTAConnectStatus::CONNECTING; - } else if (status == WL_CONNECTED) { + } + if (status == WL_CONNECTED) { return WiFiSTAConnectStatus::CONNECTED; } return WiFiSTAConnectStatus::IDLE; @@ -638,8 +683,7 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { if (!this->wifi_mode_({}, true)) return false; - tcpip_adapter_ip_info_t info; - memset(&info, 0, sizeof(info)); + esp_netif_ip_info_t info; if (manual_ip.has_value()) { info.ip = manual_ip->static_ip; info.gw = manual_ip->gateway; @@ -649,17 +693,16 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.gw = network::IPAddress(192, 168, 4, 1); info.netmask = network::IPAddress(255, 255, 255, 0); } - tcpip_adapter_dhcp_status_t dhcp_status; - tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); - err = tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP); - if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_stop failed! %d", err); + + err = esp_netif_dhcpc_stop(s_ap_netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { + ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); return false; } - err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info); + err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_set_ip_info failed! %d", err); + ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -672,17 +715,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 100; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); - err = tcpip_adapter_dhcps_option(TCPIP_ADAPTER_OP_SET, TCPIP_ADAPTER_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); + err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_option failed! %d", err); + ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } - err = tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP); + err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_start failed! %d", err); + ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } @@ -710,6 +753,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password)); } + // pairwise cipher of SoftAP, group cipher will be derived using this. conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP; esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf); @@ -729,8 +773,8 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { } network::IPAddress WiFiComponent::wifi_soft_ap_ip() { - tcpip_adapter_ip_info_t ip; - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip); + esp_netif_ip_info_t ip; + esp_netif_get_ip_info(s_ap_netif, &ip); return network::IPAddress(&ip.ip); } #endif // USE_WIFI_AP @@ -752,7 +796,6 @@ int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } network::IPAddress WiFiComponent::wifi_subnet_mask_() { return network::IPAddress(WiFi.subnetMask()); } network::IPAddress WiFiComponent::wifi_gateway_ip_() { return network::IPAddress(WiFi.gatewayIP()); } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddress(WiFi.dnsIP(num)); } -void WiFiComponent::wifi_loop_() {} } // namespace wifi } // namespace esphome diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 5489a5d249..bc575e6a2d 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -2,18 +2,18 @@ #ifdef USE_ESP_IDF -#include -#include -#include +#include +#include #include #include #include -#include -#include +#include +#include +#include +#include #include #include -#include #ifdef USE_WIFI_WPA2_EAP #include #endif @@ -22,13 +22,14 @@ #include "dhcpserver/dhcpserver.h" #endif // USE_WIFI_AP -#include "lwip/err.h" +#include "lwip/apps/sntp.h" #include "lwip/dns.h" +#include "lwip/err.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" -#include "esphome/core/application.h" #include "esphome/core/util.h" namespace esphome { @@ -196,8 +197,8 @@ bool WiFiComponent::wifi_mode_(optional sta, optional ap) { bool current_sta = current_mode == WIFI_MODE_STA || current_mode == WIFI_MODE_APSTA; bool current_ap = current_mode == WIFI_MODE_AP || current_mode == WIFI_MODE_APSTA; - bool set_sta = sta.has_value() ? *sta : current_sta; - bool set_ap = ap.has_value() ? *ap : current_ap; + bool set_sta = sta.value_or(current_sta); + bool set_ap = ap.value_or(current_ap); wifi_mode_t set_mode; if (set_sta && set_ap) { @@ -438,6 +439,11 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } if (!manual_ip.has_value()) { + // lwIP starts the SNTP client if it gets an SNTP server from DHCP. We don't need the time, and more importantly, + // the built-in SNTP client has a memory leak in certain situations. Disable this feature. + // https://github.com/esphome/issues/issues/2299 + sntp_servermode_dhcp(false); + // No manual IP is set; use DHCP client if (dhcp_status != ESP_NETIF_DHCP_STARTED) { err = esp_netif_dhcpc_start(s_sta_netif); @@ -455,13 +461,12 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { info.netmask = manual_ip->subnet; err = esp_netif_dhcpc_stop(s_sta_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); - return false; + ESP_LOGV(TAG, "Stopping DHCP client failed! %s", esp_err_to_name(err)); } + err = esp_netif_set_ip_info(s_sta_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_set_ip_info failed: %s", esp_err_to_name(err)); - return false; + ESP_LOGV(TAG, "Setting manual IP info failed! %s", esp_err_to_name(err)); } esp_netif_dns_info_t dns; @@ -795,7 +800,7 @@ bool WiFiComponent::wifi_scan_start_(bool passive) { return false; } - scan_done_ = false; + this->scan_done_ = false; return true; } @@ -818,13 +823,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.netmask = network::IPAddress(255, 255, 255, 0); } - err = esp_netif_dhcpc_stop(s_sta_netif); + err = esp_netif_dhcpc_stop(s_ap_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); return false; } - err = esp_netif_set_ip_info(s_sta_netif, &info); + err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); return false; @@ -839,14 +844,14 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 100; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); - err = esp_netif_dhcps_option(s_sta_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); + err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } - err = esp_netif_dhcps_start(s_sta_netif); + err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); @@ -893,25 +898,26 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return true; } -#endif // USE_WIFI_AP network::IPAddress WiFiComponent::wifi_soft_ap_ip() { esp_netif_ip_info_t ip; - esp_netif_get_ip_info(s_sta_netif, &ip); + esp_netif_get_ip_info(s_ap_netif, &ip); return network::IPAddress(&ip.ip); } +#endif // USE_WIFI_AP + bool WiFiComponent::wifi_disconnect_() { return esp_wifi_disconnect(); } bssid_t WiFiComponent::wifi_bssid() { + bssid_t bssid{}; wifi_ap_record_t info; esp_err_t err = esp_wifi_sta_get_ap_info(&info); - bssid_t res{}; if (err != ESP_OK) { ESP_LOGW(TAG, "esp_wifi_sta_get_ap_info failed: %s", esp_err_to_name(err)); - return res; + return bssid; } - std::copy(info.bssid, info.bssid + 6, res.begin()); - return res; + std::copy(info.bssid, info.bssid + 6, bssid.begin()); + return bssid; } std::string WiFiComponent::wifi_ssid() { wifi_ap_record_t info{}; @@ -969,4 +975,4 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { } // namespace wifi } // namespace esphome -#endif +#endif // USE_ESP_IDF From 98cb6555df956bf73f456eaeb74e5fa0399554e4 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 16 May 2024 05:22:40 +0200 Subject: [PATCH 1760/2607] SPI and I2C for ENS160 (#6369) --- CODEOWNERS | 5 +- esphome/components/ens160/__init__.py | 1 - esphome/components/ens160/sensor.py | 90 ++----------------- esphome/components/ens160_base/__init__.py | 78 ++++++++++++++++ .../ens160_base.cpp} | 7 +- .../ens160.h => ens160_base/ens160_base.h} | 12 ++- esphome/components/ens160_i2c/__init__.py | 0 esphome/components/ens160_i2c/ens160_i2c.cpp | 32 +++++++ esphome/components/ens160_i2c/ens160_i2c.h | 19 ++++ esphome/components/ens160_i2c/sensor.py | 22 +++++ esphome/components/ens160_spi/__init__.py | 0 esphome/components/ens160_spi/ens160_spi.cpp | 59 ++++++++++++ esphome/components/ens160_spi/ens160_spi.h | 22 +++++ esphome/components/ens160_spi/sensor.py | 22 +++++ .../components/ens160/test.esp32-c3-idf.yaml | 13 --- tests/components/ens160/test.esp32-c3.yaml | 13 --- tests/components/ens160/test.esp32-idf.yaml | 13 --- tests/components/ens160/test.esp32.yaml | 13 --- tests/components/ens160/test.esp8266.yaml | 13 --- tests/components/ens160/test.rp2040.yaml | 13 --- tests/components/ens160_i2c/common.yaml | 15 ++++ .../ens160_i2c/test.esp32-c3-idf.yaml | 5 ++ .../components/ens160_i2c/test.esp32-c3.yaml | 5 ++ .../components/ens160_i2c/test.esp32-idf.yaml | 5 ++ tests/components/ens160_i2c/test.esp32.yaml | 5 ++ tests/components/ens160_i2c/test.esp8266.yaml | 5 ++ tests/components/ens160_i2c/test.rp2040.yaml | 5 ++ tests/components/ens160_spi/common.yaml | 17 ++++ .../ens160_spi/test.esp32-c3-idf.yaml | 7 ++ .../components/ens160_spi/test.esp32-c3.yaml | 7 ++ .../components/ens160_spi/test.esp32-idf.yaml | 7 ++ tests/components/ens160_spi/test.esp32.yaml | 7 ++ tests/components/ens160_spi/test.esp8266.yaml | 7 ++ tests/components/ens160_spi/test.rp2040.yaml | 7 ++ tests/test3.1.yaml | 7 -- 35 files changed, 378 insertions(+), 180 deletions(-) create mode 100644 esphome/components/ens160_base/__init__.py rename esphome/components/{ens160/ens160.cpp => ens160_base/ens160_base.cpp} (99%) rename esphome/components/{ens160/ens160.h => ens160_base/ens160_base.h} (76%) create mode 100644 esphome/components/ens160_i2c/__init__.py create mode 100644 esphome/components/ens160_i2c/ens160_i2c.cpp create mode 100644 esphome/components/ens160_i2c/ens160_i2c.h create mode 100644 esphome/components/ens160_i2c/sensor.py create mode 100644 esphome/components/ens160_spi/__init__.py create mode 100644 esphome/components/ens160_spi/ens160_spi.cpp create mode 100644 esphome/components/ens160_spi/ens160_spi.h create mode 100644 esphome/components/ens160_spi/sensor.py delete mode 100644 tests/components/ens160/test.esp32-c3-idf.yaml delete mode 100644 tests/components/ens160/test.esp32-c3.yaml delete mode 100644 tests/components/ens160/test.esp32-idf.yaml delete mode 100644 tests/components/ens160/test.esp32.yaml delete mode 100644 tests/components/ens160/test.esp8266.yaml delete mode 100644 tests/components/ens160/test.rp2040.yaml create mode 100644 tests/components/ens160_i2c/common.yaml create mode 100644 tests/components/ens160_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/ens160_i2c/test.esp32-c3.yaml create mode 100644 tests/components/ens160_i2c/test.esp32-idf.yaml create mode 100644 tests/components/ens160_i2c/test.esp32.yaml create mode 100644 tests/components/ens160_i2c/test.esp8266.yaml create mode 100644 tests/components/ens160_i2c/test.rp2040.yaml create mode 100644 tests/components/ens160_spi/common.yaml create mode 100644 tests/components/ens160_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ens160_spi/test.esp32-c3.yaml create mode 100644 tests/components/ens160_spi/test.esp32-idf.yaml create mode 100644 tests/components/ens160_spi/test.esp32.yaml create mode 100644 tests/components/ens160_spi/test.esp8266.yaml create mode 100644 tests/components/ens160_spi/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 65ea3b1683..4227cdb06d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -111,7 +111,10 @@ esphome/components/ee895/* @Stock-M esphome/components/ektf2232/touchscreen/* @jesserockz esphome/components/emc2101/* @ellull esphome/components/emmeti/* @E440QF -esphome/components/ens160/* @vincentscode +esphome/components/ens160/* @latonita +esphome/components/ens160_base/* @latonita @vincentscode +esphome/components/ens160_i2c/* @latonita +esphome/components/ens160_spi/* @latonita esphome/components/ens210/* @itn3rd77 esphome/components/esp32/* @esphome/core esphome/components/esp32_ble/* @Rapsssito @jesserockz diff --git a/esphome/components/ens160/__init__.py b/esphome/components/ens160/__init__.py index d26770a89d..e69de29bb2 100644 --- a/esphome/components/ens160/__init__.py +++ b/esphome/components/ens160/__init__.py @@ -1 +0,0 @@ -CODEOWNERS = ["@vincentscode"] diff --git a/esphome/components/ens160/sensor.py b/esphome/components/ens160/sensor.py index 6572c4e397..f666b530b3 100644 --- a/esphome/components/ens160/sensor.py +++ b/esphome/components/ens160/sensor.py @@ -1,87 +1,7 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import i2c, sensor -from esphome.const import ( - CONF_COMPENSATION, - CONF_ECO2, - CONF_HUMIDITY, - CONF_ID, - CONF_TEMPERATURE, - CONF_TVOC, - DEVICE_CLASS_AQI, - DEVICE_CLASS_CARBON_DIOXIDE, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, - ICON_CHEMICAL_WEAPON, - ICON_MOLECULE_CO2, - ICON_RADIATOR, - STATE_CLASS_MEASUREMENT, - UNIT_PARTS_PER_BILLION, - UNIT_PARTS_PER_MILLION, + +CODEOWNERS = ["@latonita"] + +CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( + "The ens160 sensor component has been renamed to ens160_i2c." ) - -CODEOWNERS = ["@vincentscode"] -DEPENDENCIES = ["i2c"] - -ens160_ns = cg.esphome_ns.namespace("ens160") -ENS160Component = ens160_ns.class_( - "ENS160Component", cg.PollingComponent, i2c.I2CDevice, sensor.Sensor -) - -CONF_AQI = "aqi" -UNIT_INDEX = "index" - -CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(ENS160Component), - cv.Required(CONF_ECO2): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_MILLION, - icon=ICON_MOLECULE_CO2, - accuracy_decimals=0, - device_class=DEVICE_CLASS_CARBON_DIOXIDE, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Required(CONF_TVOC): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_BILLION, - icon=ICON_RADIATOR, - accuracy_decimals=0, - device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Required(CONF_AQI): sensor.sensor_schema( - icon=ICON_CHEMICAL_WEAPON, - accuracy_decimals=0, - device_class=DEVICE_CLASS_AQI, - state_class=STATE_CLASS_MEASUREMENT, - ), - cv.Optional(CONF_COMPENSATION): cv.Schema( - { - cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), - cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor), - } - ), - } - ) - .extend(cv.polling_component_schema("60s")) - .extend(i2c.i2c_device_schema(0x53)) -) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await i2c.register_i2c_device(var, config) - - sens = await sensor.new_sensor(config[CONF_ECO2]) - cg.add(var.set_co2(sens)) - sens = await sensor.new_sensor(config[CONF_TVOC]) - cg.add(var.set_tvoc(sens)) - sens = await sensor.new_sensor(config[CONF_AQI]) - cg.add(var.set_aqi(sens)) - - if CONF_COMPENSATION in config: - compensation_config = config[CONF_COMPENSATION] - sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE]) - cg.add(var.set_temperature(sens)) - sens = await cg.get_variable(compensation_config[CONF_HUMIDITY]) - cg.add(var.set_humidity(sens)) diff --git a/esphome/components/ens160_base/__init__.py b/esphome/components/ens160_base/__init__.py new file mode 100644 index 0000000000..eb6d0880af --- /dev/null +++ b/esphome/components/ens160_base/__init__.py @@ -0,0 +1,78 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_COMPENSATION, + CONF_ECO2, + CONF_HUMIDITY, + CONF_ID, + CONF_TEMPERATURE, + CONF_TVOC, + DEVICE_CLASS_AQI, + DEVICE_CLASS_CARBON_DIOXIDE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + ICON_CHEMICAL_WEAPON, + ICON_MOLECULE_CO2, + ICON_RADIATOR, + STATE_CLASS_MEASUREMENT, + UNIT_PARTS_PER_BILLION, + UNIT_PARTS_PER_MILLION, +) + +CODEOWNERS = ["@vincentscode", "@latonita"] + +ens160_ns = cg.esphome_ns.namespace("ens160_base") + +CONF_AQI = "aqi" +UNIT_INDEX = "index" + +CONFIG_SCHEMA_BASE = cv.Schema( + { + cv.Required(CONF_ECO2): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + icon=ICON_MOLECULE_CO2, + accuracy_decimals=0, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Required(CONF_TVOC): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_BILLION, + icon=ICON_RADIATOR, + accuracy_decimals=0, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Required(CONF_AQI): sensor.sensor_schema( + icon=ICON_CHEMICAL_WEAPON, + accuracy_decimals=0, + device_class=DEVICE_CLASS_AQI, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_COMPENSATION): cv.Schema( + { + cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), + cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor), + } + ), + } +).extend(cv.polling_component_schema("60s")) + + +async def to_code_base(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + sens = await sensor.new_sensor(config[CONF_ECO2]) + cg.add(var.set_co2(sens)) + sens = await sensor.new_sensor(config[CONF_TVOC]) + cg.add(var.set_tvoc(sens)) + sens = await sensor.new_sensor(config[CONF_AQI]) + cg.add(var.set_aqi(sens)) + + if compensation_config := config.get(CONF_COMPENSATION): + sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE]) + cg.add(var.set_temperature(sens)) + sens = await cg.get_variable(compensation_config[CONF_HUMIDITY]) + cg.add(var.set_humidity(sens)) + + return var diff --git a/esphome/components/ens160/ens160.cpp b/esphome/components/ens160_base/ens160_base.cpp similarity index 99% rename from esphome/components/ens160/ens160.cpp rename to esphome/components/ens160_base/ens160_base.cpp index c7a6ccbb73..71082c58c2 100644 --- a/esphome/components/ens160/ens160.cpp +++ b/esphome/components/ens160_base/ens160_base.cpp @@ -5,12 +5,12 @@ // Implementation based on: // https://github.com/sciosense/ENS160_driver -#include "ens160.h" +#include "ens160_base.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" namespace esphome { -namespace ens160 { +namespace ens160_base { static const char *const TAG = "ens160"; @@ -303,7 +303,6 @@ void ENS160Component::dump_config() { ESP_LOGI(TAG, "Firmware Version: %d.%d.%d", this->firmware_ver_major_, this->firmware_ver_minor_, this->firmware_ver_build_); - LOG_I2C_DEVICE(this); LOG_UPDATE_INTERVAL(this); LOG_SENSOR(" ", "CO2 Sensor:", this->co2_); LOG_SENSOR(" ", "TVOC Sensor:", this->tvoc_); @@ -317,5 +316,5 @@ void ENS160Component::dump_config() { } } -} // namespace ens160 +} // namespace ens160_base } // namespace esphome diff --git a/esphome/components/ens160/ens160.h b/esphome/components/ens160_base/ens160_base.h similarity index 76% rename from esphome/components/ens160/ens160.h rename to esphome/components/ens160_base/ens160_base.h index 88bc8e3501..729225a5ae 100644 --- a/esphome/components/ens160/ens160.h +++ b/esphome/components/ens160_base/ens160_base.h @@ -2,12 +2,11 @@ #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" -#include "esphome/components/i2c/i2c.h" namespace esphome { -namespace ens160 { +namespace ens160_base { -class ENS160Component : public PollingComponent, public i2c::I2CDevice, public sensor::Sensor { +class ENS160Component : public PollingComponent, public sensor::Sensor { public: void set_co2(sensor::Sensor *co2) { co2_ = co2; } void set_tvoc(sensor::Sensor *tvoc) { tvoc_ = tvoc; } @@ -44,6 +43,11 @@ class ENS160Component : public PollingComponent, public i2c::I2CDevice, public s bool warming_up_{false}; bool initial_startup_{false}; + virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0; + virtual bool write_byte(uint8_t a_register, uint8_t data) = 0; + virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0; + virtual bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0; + uint8_t firmware_ver_major_{0}; uint8_t firmware_ver_minor_{0}; uint8_t firmware_ver_build_{0}; @@ -56,5 +60,5 @@ class ENS160Component : public PollingComponent, public i2c::I2CDevice, public s sensor::Sensor *temperature_{nullptr}; }; -} // namespace ens160 +} // namespace ens160_base } // namespace esphome diff --git a/esphome/components/ens160_i2c/__init__.py b/esphome/components/ens160_i2c/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ens160_i2c/ens160_i2c.cpp b/esphome/components/ens160_i2c/ens160_i2c.cpp new file mode 100644 index 0000000000..7163a5ad6e --- /dev/null +++ b/esphome/components/ens160_i2c/ens160_i2c.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include "ens160_i2c.h" +#include "esphome/components/i2c/i2c.h" +#include "../ens160_base/ens160_base.h" + +namespace esphome { +namespace ens160_i2c { + +static const char *const TAG = "ens160_i2c.sensor"; + +bool ENS160I2CComponent::read_byte(uint8_t a_register, uint8_t *data) { + return I2CDevice::read_byte(a_register, data); +}; +bool ENS160I2CComponent::write_byte(uint8_t a_register, uint8_t data) { + return I2CDevice::write_byte(a_register, data); +}; +bool ENS160I2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + return I2CDevice::read_bytes(a_register, data, len); +}; +bool ENS160I2CComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) { + return I2CDevice::write_bytes(a_register, data, len); +}; + +void ENS160I2CComponent::dump_config() { + ENS160Component::dump_config(); + LOG_I2C_DEVICE(this); +} + +} // namespace ens160_i2c +} // namespace esphome diff --git a/esphome/components/ens160_i2c/ens160_i2c.h b/esphome/components/ens160_i2c/ens160_i2c.h new file mode 100644 index 0000000000..2df32f27bf --- /dev/null +++ b/esphome/components/ens160_i2c/ens160_i2c.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/ens160_base/ens160_base.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace ens160_i2c { + +class ENS160I2CComponent : public esphome::ens160_base::ENS160Component, public i2c::I2CDevice { + void dump_config() override; + + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override; +}; + +} // namespace ens160_i2c +} // namespace esphome diff --git a/esphome/components/ens160_i2c/sensor.py b/esphome/components/ens160_i2c/sensor.py new file mode 100644 index 0000000000..96cbbaa7e9 --- /dev/null +++ b/esphome/components/ens160_i2c/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +from esphome.components import i2c +from ..ens160_base import to_code_base, cv, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["ens160_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +ens160_ns = cg.esphome_ns.namespace("ens160_i2c") + +ENS160I2CComponent = ens160_ns.class_( + "ENS160I2CComponent", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( + i2c.i2c_device_schema(default_address=0x52) +).extend({cv.GenerateID(): cv.declare_id(ENS160I2CComponent)}) + + +async def to_code(config): + var = await to_code_base(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ens160_spi/__init__.py b/esphome/components/ens160_spi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ens160_spi/ens160_spi.cpp b/esphome/components/ens160_spi/ens160_spi.cpp new file mode 100644 index 0000000000..fba2fdf0e4 --- /dev/null +++ b/esphome/components/ens160_spi/ens160_spi.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include "ens160_spi.h" +#include + +namespace esphome { +namespace ens160_spi { + +static const char *const TAG = "ens160_spi.sensor"; + +inline uint8_t reg_read(uint8_t reg) { return (reg << 1) | 0x01; } + +inline uint8_t reg_write(uint8_t reg) { return (reg << 1) & 0xFE; } + +void ENS160SPIComponent::setup() { + this->spi_setup(); + ENS160Component::setup(); +}; + +void ENS160SPIComponent::dump_config() { + ENS160Component::dump_config(); + LOG_PIN(" CS Pin: ", this->cs_); +} + +bool ENS160SPIComponent::read_byte(uint8_t a_register, uint8_t *data) { + this->enable(); + this->transfer_byte(reg_read(a_register)); + *data = this->transfer_byte(0); + this->disable(); + return true; +} + +bool ENS160SPIComponent::write_byte(uint8_t a_register, uint8_t data) { + this->enable(); + this->transfer_byte(reg_write(a_register)); + this->transfer_byte(data); + this->disable(); + return true; +} + +bool ENS160SPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + this->enable(); + this->transfer_byte(reg_read(a_register)); + this->read_array(data, len); + this->disable(); + return true; +} + +bool ENS160SPIComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) { + this->enable(); + this->transfer_byte(reg_write(a_register)); + this->transfer_array(data, len); + this->disable(); + return true; +} + +} // namespace ens160_spi +} // namespace esphome diff --git a/esphome/components/ens160_spi/ens160_spi.h b/esphome/components/ens160_spi/ens160_spi.h new file mode 100644 index 0000000000..3371f37ffd --- /dev/null +++ b/esphome/components/ens160_spi/ens160_spi.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/components/ens160_base/ens160_base.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace ens160_spi { + +class ENS160SPIComponent : public esphome::ens160_base::ENS160Component, + public spi::SPIDevice { + void setup() override; + void dump_config() override; + + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override; +}; + +} // namespace ens160_spi +} // namespace esphome diff --git a/esphome/components/ens160_spi/sensor.py b/esphome/components/ens160_spi/sensor.py new file mode 100644 index 0000000000..552697fe1b --- /dev/null +++ b/esphome/components/ens160_spi/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +from esphome.components import spi +from ..ens160_base import to_code_base, cv, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["ens160_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["spi"] + +ens160_spi_ns = cg.esphome_ns.namespace("ens160_spi") + +ENS160SPIComponent = ens160_spi_ns.class_( + "ENS160SPIComponent", cg.PollingComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( + {cv.GenerateID(): cv.declare_id(ENS160SPIComponent)} +) + + +async def to_code(config): + var = await to_code_base(config) + await spi.register_spi_device(var, config) diff --git a/tests/components/ens160/test.esp32-c3-idf.yaml b/tests/components/ens160/test.esp32-c3-idf.yaml deleted file mode 100644 index 29f48e812f..0000000000 --- a/tests/components/ens160/test.esp32-c3-idf.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 5 - sda: 4 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32-c3.yaml b/tests/components/ens160/test.esp32-c3.yaml deleted file mode 100644 index 29f48e812f..0000000000 --- a/tests/components/ens160/test.esp32-c3.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 5 - sda: 4 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32-idf.yaml b/tests/components/ens160/test.esp32-idf.yaml deleted file mode 100644 index 23f7674aef..0000000000 --- a/tests/components/ens160/test.esp32-idf.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 16 - sda: 17 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp32.yaml b/tests/components/ens160/test.esp32.yaml deleted file mode 100644 index 23f7674aef..0000000000 --- a/tests/components/ens160/test.esp32.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 16 - sda: 17 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.esp8266.yaml b/tests/components/ens160/test.esp8266.yaml deleted file mode 100644 index 29f48e812f..0000000000 --- a/tests/components/ens160/test.esp8266.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 5 - sda: 4 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160/test.rp2040.yaml b/tests/components/ens160/test.rp2040.yaml deleted file mode 100644 index 29f48e812f..0000000000 --- a/tests/components/ens160/test.rp2040.yaml +++ /dev/null @@ -1,13 +0,0 @@ -i2c: - - id: i2c_ens160 - scl: 5 - sda: 4 - -sensor: - - platform: ens160 - eco2: - name: ENS160 eCO2 - tvoc: - name: ENS160 Total Volatile Organic Compounds - aqi: - name: ENS160 Air Quality Index diff --git a/tests/components/ens160_i2c/common.yaml b/tests/components/ens160_i2c/common.yaml new file mode 100644 index 0000000000..39a5b35067 --- /dev/null +++ b/tests/components/ens160_i2c/common.yaml @@ -0,0 +1,15 @@ +i2c: + - id: i2c_ens160 + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: ens160_i2c + i2c_id: i2c_ens160 + address: 0x53 + eco2: + name: "ENS160 eCO2" + tvoc: + name: "ENS160 Total Volatile Organic Compounds" + aqi: + name: "ENS160 Air Quality Index" diff --git a/tests/components/ens160_i2c/test.esp32-c3-idf.yaml b/tests/components/ens160_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ens160_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ens160_i2c/test.esp32-c3.yaml b/tests/components/ens160_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ens160_i2c/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ens160_i2c/test.esp32-idf.yaml b/tests/components/ens160_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/ens160_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/ens160_i2c/test.esp32.yaml b/tests/components/ens160_i2c/test.esp32.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/ens160_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/ens160_i2c/test.esp8266.yaml b/tests/components/ens160_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ens160_i2c/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ens160_i2c/test.rp2040.yaml b/tests/components/ens160_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ens160_i2c/test.rp2040.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/common.yaml b/tests/components/ens160_spi/common.yaml new file mode 100644 index 0000000000..7250ead228 --- /dev/null +++ b/tests/components/ens160_spi/common.yaml @@ -0,0 +1,17 @@ +spi: + - id: spi_ens160 + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +sensor: + - platform: ens160_spi + spi_id: spi_ens160 + cs_pin: ${cs_pin} + eco2: + name: "ENS160 eCO2" + tvoc: + name: "ENS160 Total Volatile Organic Compounds" + aqi: + name: "ENS160 Air Quality Index" + diff --git a/tests/components/ens160_spi/test.esp32-c3-idf.yaml b/tests/components/ens160_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/ens160_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/test.esp32-c3.yaml b/tests/components/ens160_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/ens160_spi/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/test.esp32-idf.yaml b/tests/components/ens160_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/ens160_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/test.esp32.yaml b/tests/components/ens160_spi/test.esp32.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/ens160_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/test.esp8266.yaml b/tests/components/ens160_spi/test.esp8266.yaml new file mode 100644 index 0000000000..dbd158d030 --- /dev/null +++ b/tests/components/ens160_spi/test.esp8266.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + cs_pin: GPIO15 + +<<: !include common.yaml diff --git a/tests/components/ens160_spi/test.rp2040.yaml b/tests/components/ens160_spi/test.rp2040.yaml new file mode 100644 index 0000000000..f6c3f1eeca --- /dev/null +++ b/tests/components/ens160_spi/test.rp2040.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO2 + mosi_pin: GPIO3 + miso_pin: GPIO4 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 18d92289cd..a7d8dcb3f4 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -245,13 +245,6 @@ sensor: name: "ADE7953 Reactive Power B" update_interval: 1s - - platform: ens160 - eco2: - name: "ENS160 eCO2" - tvoc: - name: "ENS160 Total Volatile Organic Compounds" - aqi: - name: "ENS160 Air Quality Index" - platform: tmp102 name: TMP102 Temperature - platform: hm3301 From 996f71c03c2822c7fba5c761b1ab07ef3b119a0c Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 15 May 2024 23:40:21 -0500 Subject: [PATCH 1761/2607] Fix wifi compile error on IDF 5.1+ (#6756) --- esphome/components/wifi/wifi_component.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index f4a44b03a4..2f34f2b05b 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -3,8 +3,12 @@ #include #ifdef USE_ESP_IDF +#if (ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1) +#include +#else #include #endif +#endif #if defined(USE_ESP32) || defined(USE_ESP_IDF) #include From 034c196ad80a8ec4d1ba806bec3a2c87679a6477 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 16:46:16 +1200 Subject: [PATCH 1762/2607] [core] Update some coroutine priorities (#6755) --- esphome/components/datetime/__init__.py | 2 +- esphome/components/number/__init__.py | 2 +- esphome/components/ota/__init__.py | 2 +- esphome/components/select/__init__.py | 2 +- esphome/components/sensor/__init__.py | 2 +- esphome/components/template/datetime/__init__.py | 2 -- esphome/components/text/__init__.py | 2 +- 7 files changed, 6 insertions(+), 8 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 3d08e4a6d0..262f1e2315 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -156,7 +156,7 @@ async def new_datetime(config, *args): return var -@coroutine_with_priority(40.0) +@coroutine_with_priority(100.0) async def to_code(config): cg.add_define("USE_DATETIME") cg.add_global(datetime_ns.using) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 6d7ec97c90..8c3b15d22d 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -293,7 +293,7 @@ async def number_in_range_to_code(config, condition_id, template_arg, args): return var -@coroutine_with_priority(40.0) +@coroutine_with_priority(100.0) async def to_code(config): cg.add_define("USE_NUMBER") cg.add_global(number_ns.using) diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 728d36f3fa..3d2956931c 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -76,7 +76,7 @@ BASE_OTA_SCHEMA = cv.Schema( ) -@coroutine_with_priority(50.0) +@coroutine_with_priority(51.0) async def to_code(config): cg.add_define("USE_OTA") diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index 7ad14f2440..1d234d5617 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -113,7 +113,7 @@ async def new_select(config, *, options: list[str]): return var -@coroutine_with_priority(40.0) +@coroutine_with_priority(100.0) async def to_code(config): cg.add_define("USE_SELECT") cg.add_global(select_ns.using) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index ece232e1a6..ef5c4cc645 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -912,7 +912,7 @@ def _lstsq(a, b): return _mat_dot(_mat_dot(x, a_t), b) -@coroutine_with_priority(40.0) +@coroutine_with_priority(100.0) async def to_code(config): cg.add_define("USE_SENSOR") cg.add_global(sensor_ns.using) diff --git a/esphome/components/template/datetime/__init__.py b/esphome/components/template/datetime/__init__.py index 0c9447116f..746ab8a6f3 100644 --- a/esphome/components/template/datetime/__init__.py +++ b/esphome/components/template/datetime/__init__.py @@ -17,7 +17,6 @@ from esphome.const import ( CONF_YEAR, ) -from esphome.core import coroutine_with_priority from .. import template_ns CODEOWNERS = ["@rfdarter"] @@ -100,7 +99,6 @@ CONFIG_SCHEMA = cv.All( ) -@coroutine_with_priority(-100.0) async def to_code(config): var = await datetime.new_datetime(config) diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index c0140ff082..4ca055a730 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -108,7 +108,7 @@ async def new_text( return var -@coroutine_with_priority(40.0) +@coroutine_with_priority(100.0) async def to_code(config): cg.add_define("USE_TEXT") cg.add_global(text_ns.using) From b06e0746f55010434a7b4622a85ee8ef3aaf4cb2 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 16 May 2024 06:50:28 +0200 Subject: [PATCH 1763/2607] INA228/INA229, INA238/INA239, INA237 power/energy/charge monitor (I2C, SPI) (#6138) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 3 + esphome/components/ina2xx_base/__init__.py | 255 ++++++++ .../components/ina2xx_base/ina2xx_base.cpp | 604 ++++++++++++++++++ esphome/components/ina2xx_base/ina2xx_base.h | 253 ++++++++ esphome/components/ina2xx_i2c/__init__.py | 0 esphome/components/ina2xx_i2c/ina2xx_i2c.cpp | 39 ++ esphome/components/ina2xx_i2c/ina2xx_i2c.h | 21 + esphome/components/ina2xx_i2c/sensor.py | 34 + esphome/components/ina2xx_spi/__init__.py | 0 esphome/components/ina2xx_spi/ina2xx_spi.cpp | 38 ++ esphome/components/ina2xx_spi/ina2xx_spi.h | 22 + esphome/components/ina2xx_spi/sensor.py | 33 + tests/components/ina2xx_i2c/common.yaml | 20 + .../ina2xx_i2c/test.esp32-c3-idf.yaml | 5 + .../components/ina2xx_i2c/test.esp32-c3.yaml | 5 + .../components/ina2xx_i2c/test.esp32-idf.yaml | 5 + tests/components/ina2xx_i2c/test.esp32.yaml | 5 + tests/components/ina2xx_i2c/test.esp8266.yaml | 5 + tests/components/ina2xx_i2c/test.rp2040.yaml | 5 + tests/components/ina2xx_spi/common.yaml | 21 + .../ina2xx_spi/test.esp32-c3-idf.yaml | 7 + .../components/ina2xx_spi/test.esp32-c3.yaml | 7 + .../components/ina2xx_spi/test.esp32-idf.yaml | 7 + tests/components/ina2xx_spi/test.esp32.yaml | 7 + tests/components/ina2xx_spi/test.esp8266.yaml | 7 + tests/components/ina2xx_spi/test.rp2040.yaml | 7 + 26 files changed, 1415 insertions(+) create mode 100644 esphome/components/ina2xx_base/__init__.py create mode 100644 esphome/components/ina2xx_base/ina2xx_base.cpp create mode 100644 esphome/components/ina2xx_base/ina2xx_base.h create mode 100644 esphome/components/ina2xx_i2c/__init__.py create mode 100644 esphome/components/ina2xx_i2c/ina2xx_i2c.cpp create mode 100644 esphome/components/ina2xx_i2c/ina2xx_i2c.h create mode 100644 esphome/components/ina2xx_i2c/sensor.py create mode 100644 esphome/components/ina2xx_spi/__init__.py create mode 100644 esphome/components/ina2xx_spi/ina2xx_spi.cpp create mode 100644 esphome/components/ina2xx_spi/ina2xx_spi.h create mode 100644 esphome/components/ina2xx_spi/sensor.py create mode 100644 tests/components/ina2xx_i2c/common.yaml create mode 100644 tests/components/ina2xx_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina2xx_i2c/test.esp32-c3.yaml create mode 100644 tests/components/ina2xx_i2c/test.esp32-idf.yaml create mode 100644 tests/components/ina2xx_i2c/test.esp32.yaml create mode 100644 tests/components/ina2xx_i2c/test.esp8266.yaml create mode 100644 tests/components/ina2xx_i2c/test.rp2040.yaml create mode 100644 tests/components/ina2xx_spi/common.yaml create mode 100644 tests/components/ina2xx_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/ina2xx_spi/test.esp32-c3.yaml create mode 100644 tests/components/ina2xx_spi/test.esp32-idf.yaml create mode 100644 tests/components/ina2xx_spi/test.esp32.yaml create mode 100644 tests/components/ina2xx_spi/test.esp8266.yaml create mode 100644 tests/components/ina2xx_spi/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 4227cdb06d..d97207941f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -180,6 +180,9 @@ esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core esphome/components/ina226/* @Sergio303 @latonita esphome/components/ina260/* @mreditor97 +esphome/components/ina2xx_base/* @latonita +esphome/components/ina2xx_i2c/* @latonita +esphome/components/ina2xx_spi/* @latonita esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkplate6/* @jesserockz esphome/components/integration/* @OttoWinter diff --git a/esphome/components/ina2xx_base/__init__.py b/esphome/components/ina2xx_base/__init__.py new file mode 100644 index 0000000000..35b5baa83e --- /dev/null +++ b/esphome/components/ina2xx_base/__init__.py @@ -0,0 +1,255 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_BUS_VOLTAGE, + CONF_CURRENT, + CONF_ENERGY, + CONF_MAX_CURRENT, + CONF_MODEL, + CONF_NAME, + CONF_POWER, + CONF_SHUNT_RESISTANCE, + CONF_SHUNT_VOLTAGE, + CONF_TEMPERATURE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + UNIT_AMPERE, + UNIT_CELSIUS, + UNIT_VOLT, + UNIT_WATT_HOURS, + UNIT_WATT, +) + +CODEOWNERS = ["@latonita"] + +CONF_ADC_AVERAGING = "adc_averaging" +CONF_ADC_RANGE = "adc_range" +CONF_ADC_TIME = "adc_time" +CONF_CHARGE = "charge" +CONF_CHARGE_COULOMBS = "charge_coulombs" +CONF_ENERGY_JOULES = "energy_joules" +CONF_TEMPERATURE_COEFFICIENT = "temperature_coefficient" +UNIT_AMPERE_HOURS = "Ah" +UNIT_COULOMB = "C" +UNIT_JOULE = "J" +UNIT_MILLIVOLT = "mV" + +ina2xx_base_ns = cg.esphome_ns.namespace("ina2xx_base") +INA2XX = ina2xx_base_ns.class_("INA2XX", cg.PollingComponent) + +AdcTime = ina2xx_base_ns.enum("AdcTime") +ADC_TIMES = { + 50: AdcTime.ADC_TIME_50US, + 84: AdcTime.ADC_TIME_84US, + 150: AdcTime.ADC_TIME_150US, + 280: AdcTime.ADC_TIME_280US, + 540: AdcTime.ADC_TIME_540US, + 1052: AdcTime.ADC_TIME_1052US, + 2074: AdcTime.ADC_TIME_2074US, + 4120: AdcTime.ADC_TIME_4120US, +} + +AdcAvgSamples = ina2xx_base_ns.enum("AdcAvgSamples") +ADC_SAMPLES = { + 1: AdcAvgSamples.ADC_AVG_SAMPLES_1, + 4: AdcAvgSamples.ADC_AVG_SAMPLES_4, + 16: AdcAvgSamples.ADC_AVG_SAMPLES_16, + 64: AdcAvgSamples.ADC_AVG_SAMPLES_64, + 128: AdcAvgSamples.ADC_AVG_SAMPLES_128, + 256: AdcAvgSamples.ADC_AVG_SAMPLES_256, + 512: AdcAvgSamples.ADC_AVG_SAMPLES_512, + 1024: AdcAvgSamples.ADC_AVG_SAMPLES_1024, +} + +SENSOR_MODEL_OPTIONS = { + CONF_ENERGY: ["INA228", "INA229"], + CONF_ENERGY_JOULES: ["INA228", "INA229"], + CONF_CHARGE: ["INA228", "INA229"], + CONF_CHARGE_COULOMBS: ["INA228", "INA229"], +} + + +def validate_model_config(config): + model = config[CONF_MODEL] + + for key in config: + if key in SENSOR_MODEL_OPTIONS: + if model not in SENSOR_MODEL_OPTIONS[key]: + raise cv.Invalid( + f"Device model '{model}' does not support '{key}' sensor" + ) + + tempco = config[CONF_TEMPERATURE_COEFFICIENT] + if tempco > 0 and model not in ["INA228", "INA229"]: + raise cv.Invalid( + f"Device model '{model}' does not support temperature coefficient" + ) + + return config + + +def validate_adc_time(value): + value = cv.positive_time_period_microseconds(value).total_microseconds + return cv.enum(ADC_TIMES, int=True)(value) + + +INA2XX_SCHEMA = cv.Schema( + { + cv.Required(CONF_SHUNT_RESISTANCE): cv.All(cv.resistance, cv.Range(min=0.0)), + cv.Required(CONF_MAX_CURRENT): cv.All(cv.current, cv.Range(min=0.0)), + cv.Optional(CONF_ADC_RANGE, default=0): cv.int_range(min=0, max=1), + cv.Optional(CONF_ADC_TIME, default="4120 us"): cv.Any( + validate_adc_time, + { + cv.Optional(CONF_BUS_VOLTAGE, default="4120 us"): validate_adc_time, + cv.Optional(CONF_SHUNT_VOLTAGE, default="4120 us"): validate_adc_time, + cv.Optional(CONF_TEMPERATURE, default="4120 us"): validate_adc_time, + }, + ), + cv.Optional(CONF_ADC_AVERAGING, default=128): cv.enum(ADC_SAMPLES, int=True), + cv.Optional(CONF_TEMPERATURE_COEFFICIENT, default=0): cv.int_range( + min=0, max=16383 + ), + cv.Optional(CONF_SHUNT_VOLTAGE): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_MILLIVOLT, + accuracy_decimals=5, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_BUS_VOLTAGE): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=5, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_TEMPERATURE): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=5, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_CURRENT): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_AMPERE, + accuracy_decimals=8, + device_class=DEVICE_CLASS_CURRENT, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_POWER): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_WATT, + accuracy_decimals=6, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ENERGY): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_WATT_HOURS, + accuracy_decimals=8, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ENERGY_JOULES): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_JOULE, + accuracy_decimals=8, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_CHARGE): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_AMPERE_HOURS, + accuracy_decimals=8, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_CHARGE_COULOMBS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COULOMB, + accuracy_decimals=8, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + } +).extend(cv.polling_component_schema("60s")) + + +async def setup_ina2xx(var, config): + await cg.register_component(var, config) + + cg.add(var.set_model(config[CONF_MODEL])) + + cg.add(var.set_shunt_resistance_ohm(config[CONF_SHUNT_RESISTANCE])) + cg.add(var.set_max_current_a(config[CONF_MAX_CURRENT])) + cg.add(var.set_adc_range(config[CONF_ADC_RANGE])) + cg.add(var.set_adc_avg_samples(config[CONF_ADC_AVERAGING])) + cg.add(var.set_shunt_tempco(config[CONF_TEMPERATURE_COEFFICIENT])) + + adc_time_config = config[CONF_ADC_TIME] + if isinstance(adc_time_config, dict): + cg.add(var.set_adc_time_bus_voltage(adc_time_config[CONF_BUS_VOLTAGE])) + cg.add(var.set_adc_time_shunt_voltage(adc_time_config[CONF_SHUNT_VOLTAGE])) + cg.add(var.set_adc_time_die_temperature(adc_time_config[CONF_TEMPERATURE])) + else: + cg.add(var.set_adc_time_bus_voltage(adc_time_config)) + cg.add(var.set_adc_time_shunt_voltage(adc_time_config)) + cg.add(var.set_adc_time_die_temperature(adc_time_config)) + + if conf := config.get(CONF_SHUNT_VOLTAGE): + sens = await sensor.new_sensor(conf) + cg.add(var.set_shunt_voltage_sensor(sens)) + + if conf := config.get(CONF_BUS_VOLTAGE): + sens = await sensor.new_sensor(conf) + cg.add(var.set_bus_voltage_sensor(sens)) + + if conf := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(conf) + cg.add(var.set_die_temperature_sensor(sens)) + + if conf := config.get(CONF_CURRENT): + sens = await sensor.new_sensor(conf) + cg.add(var.set_current_sensor(sens)) + + if conf := config.get(CONF_POWER): + sens = await sensor.new_sensor(conf) + cg.add(var.set_power_sensor(sens)) + + if conf := config.get(CONF_ENERGY): + sens = await sensor.new_sensor(conf) + cg.add(var.set_energy_sensor_wh(sens)) + + if conf := config.get(CONF_ENERGY_JOULES): + sens = await sensor.new_sensor(conf) + cg.add(var.set_energy_sensor_j(sens)) + + if conf := config.get(CONF_CHARGE): + sens = await sensor.new_sensor(conf) + cg.add(var.set_charge_sensor_ah(sens)) + + if conf := config.get(CONF_CHARGE_COULOMBS): + sens = await sensor.new_sensor(conf) + cg.add(var.set_charge_sensor_c(sens)) diff --git a/esphome/components/ina2xx_base/ina2xx_base.cpp b/esphome/components/ina2xx_base/ina2xx_base.cpp new file mode 100644 index 0000000000..5d947d0537 --- /dev/null +++ b/esphome/components/ina2xx_base/ina2xx_base.cpp @@ -0,0 +1,604 @@ +#include "ina2xx_base.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include +#include + +namespace esphome { +namespace ina2xx_base { + +static const char *const TAG = "ina2xx"; + +#define OKFAILED(b) ((b) ? "OK" : "FAILED") + +static const uint16_t ADC_TIMES[8] = {50, 84, 150, 280, 540, 1052, 2074, 4120}; +static const uint16_t ADC_SAMPLES[8] = {1, 4, 16, 64, 128, 256, 512, 1024}; + +static const char *get_device_name(INAModel model) { + switch (model) { + case INAModel::INA_228: + return "INA228"; + case INAModel::INA_229: + return "INA229"; + case INAModel::INA_238: + return "INA238"; + case INAModel::INA_239: + return "INA239"; + case INAModel::INA_237: + return "INA237"; + default: + return "UNKNOWN"; + } +}; + +static bool check_model_and_device_match(INAModel model, uint16_t dev_id) { + switch (model) { + case INAModel::INA_228: + return dev_id == 0x228; + case INAModel::INA_229: + return dev_id == 0x229; + case INAModel::INA_238: + return dev_id == 0x238; + case INAModel::INA_239: + return dev_id == 0x239; + case INAModel::INA_237: + return dev_id == 0x237; + default: + return false; + } +} + +void INA2XX::setup() { + ESP_LOGCONFIG(TAG, "Setting up INA2xx..."); + + if (!this->reset_config_()) { + ESP_LOGE(TAG, "Reset failed, check connection"); + this->mark_failed(); + return; + } + delay(2); + + if (!this->check_device_model_()) { + ESP_LOGE(TAG, "Device not supported or model selected improperly in yaml file"); + this->mark_failed(); + return; + } + delay(1); + + this->configure_adc_range_(); + delay(1); + + this->configure_adc_(); + delay(1); + + this->configure_shunt_(); + delay(1); + + this->configure_shunt_tempco_(); + delay(1); + + this->state_ = State::IDLE; +} + +float INA2XX::get_setup_priority() const { return setup_priority::DATA; } + +void INA2XX::update() { + ESP_LOGD(TAG, "Updating"); + if (this->is_ready() && this->state_ == State::IDLE) { + ESP_LOGD(TAG, "Initiating new data collection"); + this->state_ = State::DATA_COLLECTION_1; + return; + } +} + +void INA2XX::loop() { + if (this->is_ready()) { + switch (this->state_) { + case State::NOT_INITIALIZED: + case State::IDLE: + break; + + case State::DATA_COLLECTION_1: + this->full_loop_is_okay_ = true; + + if (this->shunt_voltage_sensor_ != nullptr) { + float shunt_voltage{0}; + this->full_loop_is_okay_ &= this->read_shunt_voltage_mv_(shunt_voltage); + this->shunt_voltage_sensor_->publish_state(shunt_voltage); + } + this->state_ = State::DATA_COLLECTION_2; + break; + + case State::DATA_COLLECTION_2: + if (this->bus_voltage_sensor_ != nullptr) { + float bus_voltage{0}; + this->full_loop_is_okay_ &= this->read_bus_voltage_(bus_voltage); + this->bus_voltage_sensor_->publish_state(bus_voltage); + } + this->state_ = State::DATA_COLLECTION_3; + break; + + case State::DATA_COLLECTION_3: + if (this->die_temperature_sensor_ != nullptr) { + float die_temperature{0}; + this->full_loop_is_okay_ &= this->read_die_temp_c_(die_temperature); + this->die_temperature_sensor_->publish_state(die_temperature); + } + this->state_ = State::DATA_COLLECTION_4; + break; + + case State::DATA_COLLECTION_4: + if (this->current_sensor_ != nullptr) { + float current{0}; + this->full_loop_is_okay_ &= this->read_current_a_(current); + this->current_sensor_->publish_state(current); + } + this->state_ = State::DATA_COLLECTION_5; + break; + + case State::DATA_COLLECTION_5: + if (this->power_sensor_ != nullptr) { + float power{0}; + this->full_loop_is_okay_ &= this->read_power_w_(power); + this->power_sensor_->publish_state(power); + } + this->state_ = State::DATA_COLLECTION_6; + break; + + case State::DATA_COLLECTION_6: + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + if (this->energy_sensor_j_ != nullptr || this->energy_sensor_wh_ != nullptr || + this->charge_sensor_c_ != nullptr || this->charge_sensor_ah_ != nullptr) { + this->read_diagnostics_and_act_(); + } + if (this->energy_sensor_j_ != nullptr || this->energy_sensor_wh_ != nullptr) { + double energy_j{0}, energy_wh{0}; + this->full_loop_is_okay_ &= this->read_energy_(energy_j, energy_wh); + if (this->energy_sensor_j_ != nullptr) + this->energy_sensor_j_->publish_state(energy_j); + if (this->energy_sensor_wh_ != nullptr) + this->energy_sensor_wh_->publish_state(energy_wh); + } + } + this->state_ = State::DATA_COLLECTION_7; + break; + + case State::DATA_COLLECTION_7: + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + if (this->charge_sensor_c_ != nullptr || this->charge_sensor_ah_ != nullptr) { + double charge_c{0}, charge_ah{0}; + this->full_loop_is_okay_ &= this->read_charge_(charge_c, charge_ah); + if (this->charge_sensor_c_ != nullptr) + this->charge_sensor_c_->publish_state(charge_c); + if (this->charge_sensor_ah_ != nullptr) + this->charge_sensor_ah_->publish_state(charge_ah); + } + } + this->state_ = State::DATA_COLLECTION_8; + break; + + case State::DATA_COLLECTION_8: + if (this->full_loop_is_okay_) { + this->status_clear_warning(); + } else { + this->status_set_warning(); + } + this->state_ = State::IDLE; + break; + + default: + ESP_LOGW(TAG, "Unknown state of the component, might be due to memory corruption"); + break; + } + } +} + +void INA2XX::dump_config() { + ESP_LOGCONFIG(TAG, "INA2xx:"); + ESP_LOGCONFIG(TAG, " Device model = %s", get_device_name(this->ina_model_)); + + if (this->device_mismatch_) { + ESP_LOGE(TAG, " Device model mismatch. Found device with ID = %x. Please check your configuration.", + this->dev_id_); + } + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with INA2xx failed!"); + } + LOG_UPDATE_INTERVAL(this); + ESP_LOGCONFIG(TAG, " Shunt resistance = %f Ohm", this->shunt_resistance_ohm_); + ESP_LOGCONFIG(TAG, " Max current = %f A", this->max_current_a_); + ESP_LOGCONFIG(TAG, " Shunt temp coeff = %d ppm/°C", this->shunt_tempco_ppm_c_); + ESP_LOGCONFIG(TAG, " ADCRANGE = %d (%s)", (uint8_t) this->adc_range_, this->adc_range_ ? "±40.96 mV" : "±163.84 mV"); + ESP_LOGCONFIG(TAG, " CURRENT_LSB = %f", this->current_lsb_); + ESP_LOGCONFIG(TAG, " SHUNT_CAL = %d", this->shunt_cal_); + + ESP_LOGCONFIG(TAG, " ADC Samples = %d; ADC times: Bus = %d μs, Shunt = %d μs, Temp = %d μs", + ADC_SAMPLES[0b111 & (uint8_t) this->adc_avg_samples_], + ADC_TIMES[0b111 & (uint8_t) this->adc_time_bus_voltage_], + ADC_TIMES[0b111 & (uint8_t) this->adc_time_shunt_voltage_], + ADC_TIMES[0b111 & (uint8_t) this->adc_time_die_temperature_]); + + ESP_LOGCONFIG(TAG, " Device is %s", get_device_name(this->ina_model_)); + + LOG_SENSOR(" ", "Shunt Voltage", this->shunt_voltage_sensor_); + LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_); + LOG_SENSOR(" ", "Die Temperature", this->die_temperature_sensor_); + LOG_SENSOR(" ", "Current", this->current_sensor_); + LOG_SENSOR(" ", "Power", this->power_sensor_); + + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + LOG_SENSOR(" ", "Energy J", this->energy_sensor_j_); + LOG_SENSOR(" ", "Energy Wh", this->energy_sensor_wh_); + LOG_SENSOR(" ", "Charge C", this->charge_sensor_c_); + LOG_SENSOR(" ", "Charge Ah", this->charge_sensor_ah_); + } +} + +bool INA2XX::reset_energy_counters() { + if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) { + return false; + } + ESP_LOGV(TAG, "reset_energy_counters"); + + ConfigurationRegister cfg{0}; + auto ret = this->read_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16); + cfg.RSTACC = true; + cfg.ADCRANGE = this->adc_range_; + ret = ret && this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16); + + this->energy_overflows_count_ = 0; + this->charge_overflows_count_ = 0; + return ret; +} + +bool INA2XX::reset_config_() { + ESP_LOGV(TAG, "Reset"); + ConfigurationRegister cfg{0}; + cfg.RST = true; + return this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16); +} + +bool INA2XX::check_device_model_() { + constexpr uint16_t manufacturer_ti = 0x5449; // "TI" + + uint16_t manufacturer_id{0}, rev_id{0}; + this->read_unsigned_16_(RegisterMap::REG_MANUFACTURER_ID, manufacturer_id); + if (!this->read_unsigned_16_(RegisterMap::REG_DEVICE_ID, this->dev_id_)) { + this->dev_id_ = 0; + ESP_LOGV(TAG, "Can't read device ID"); + }; + rev_id = this->dev_id_ & 0x0F; + this->dev_id_ >>= 4; + ESP_LOGI(TAG, "Manufacturer: 0x%04X, Device ID: 0x%04X, Revision: %d", manufacturer_id, this->dev_id_, rev_id); + + if (manufacturer_id != manufacturer_ti) { + ESP_LOGE(TAG, "Manufacturer ID doesn't match original 0x5449"); + this->device_mismatch_ = true; + return false; + } + + if (this->dev_id_ == 0x228 || this->dev_id_ == 0x229) { + ESP_LOGI(TAG, "Supported device found: INA%x, 85-V, 20-Bit, Ultra-Precise Power/Energy/Charge Monitor", + this->dev_id_); + } else if (this->dev_id_ == 0x238 || this->dev_id_ == 0x239) { + ESP_LOGI(TAG, "Supported device found: INA%x, 85-V, 16-Bit, High-Precision Power Monitor", this->dev_id_); + } else if (this->dev_id_ == 0x0 || this->dev_id_ == 0xFF) { + ESP_LOGI(TAG, "We assume device is: INA237 85-V, 16-Bit, Precision Power Monitor"); + this->dev_id_ = 0x237; + } else { + ESP_LOGE(TAG, "Unknown device ID %x.", this->dev_id_); + this->device_mismatch_ = true; + return false; + } + + // Check user-selected model agains what we have found. Mark as failed if selected model != found model + if (!check_model_and_device_match(this->ina_model_, this->dev_id_)) { + ESP_LOGE(TAG, "Selected model %s doesn't match found device INA%x", get_device_name(this->ina_model_), + this->dev_id_); + this->device_mismatch_ = true; + return false; + } + + // setup device coefficients + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + this->cfg_.vbus_lsb = 0.0001953125f; + this->cfg_.v_shunt_lsb_range0 = 0.0003125f; + this->cfg_.v_shunt_lsb_range1 = 0.000078125f; + this->cfg_.shunt_cal_scale = 13107.2f * 1000000.0f; + this->cfg_.current_lsb_scale_factor = -19; + this->cfg_.die_temp_lsb = 0.0078125f; + this->cfg_.power_coeff = 3.2f; + this->cfg_.energy_coeff = 16.0f * 3.2f; + } else { + this->cfg_.vbus_lsb = 0.0031250000f; + this->cfg_.v_shunt_lsb_range0 = 0.0050000f; + this->cfg_.v_shunt_lsb_range1 = 0.001250000f; + this->cfg_.shunt_cal_scale = 819.2f * 1000000.0f; + this->cfg_.current_lsb_scale_factor = -15; + this->cfg_.die_temp_lsb = 0.1250000f; + this->cfg_.power_coeff = 0.2f; + this->cfg_.energy_coeff = 0.0f; // N/A + } + + return true; +} + +bool INA2XX::configure_adc_range_() { + ESP_LOGV(TAG, "Setting ADCRANGE = %d", (uint8_t) this->adc_range_); + ConfigurationRegister cfg{0}; + auto ret = this->read_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16); + cfg.ADCRANGE = this->adc_range_; + ret = ret && this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16); + + return ret; +} + +bool INA2XX::configure_adc_() { + bool ret{false}; + AdcConfigurationRegister adc_cfg{0}; + adc_cfg.MODE = 0x0F; // Fh = Continuous bus voltage, shunt voltage and temperature + adc_cfg.VBUSCT = this->adc_time_bus_voltage_; + adc_cfg.VSHCT = this->adc_time_shunt_voltage_; + adc_cfg.VTCT = this->adc_time_die_temperature_; + adc_cfg.AVG = this->adc_avg_samples_; + ret = this->write_unsigned_16_(RegisterMap::REG_ADC_CONFIG, adc_cfg.raw_u16); + return ret; +} + +bool INA2XX::configure_shunt_() { + this->current_lsb_ = ldexp(this->max_current_a_, this->cfg_.current_lsb_scale_factor); + this->shunt_cal_ = (uint16_t) (this->cfg_.shunt_cal_scale * this->current_lsb_ * this->shunt_resistance_ohm_); + if (this->adc_range_) + this->shunt_cal_ *= 4; + + if (this->shunt_cal_ & 0x8000) { + // cant be more than 15 bits + ESP_LOGW(TAG, "Shunt value too high"); + } + this->shunt_cal_ &= 0x7FFF; + ESP_LOGV(TAG, "Given Rshunt=%f Ohm and Max_current=%.3f", this->shunt_resistance_ohm_, this->max_current_a_); + ESP_LOGV(TAG, "New CURRENT_LSB=%f, SHUNT_CAL=%u", this->current_lsb_, this->shunt_cal_); + return this->write_unsigned_16_(RegisterMap::REG_SHUNT_CAL, this->shunt_cal_); +} + +bool INA2XX::configure_shunt_tempco_() { + // Only for 228/229 + // unsigned 14-bit value + // 0x0000 = 0 ppm/°C + // 0x3FFF = 16383 ppm/°C + if ((this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) && + this->shunt_tempco_ppm_c_ > 0) { + return this->write_unsigned_16_(RegisterMap::REG_SHUNT_TEMPCO, this->shunt_tempco_ppm_c_ & 0x3FFF); + } + return true; +} + +bool INA2XX::read_shunt_voltage_mv_(float &volt_out) { + // Two's complement value + // 228, 229 - 24bit: 20(23-4) + 4(3-0) res + // 237, 238, 239 - 16bit + + bool ret{false}; + float volt_reading{0}; + uint64_t raw{0}; + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + ret = this->read_unsigned_(RegisterMap::REG_VSHUNT, 3, raw); + raw >>= 4; + volt_reading = this->two_complement_(raw, 20); + } else { + ret = this->read_unsigned_(RegisterMap::REG_VSHUNT, 2, raw); + volt_reading = this->two_complement_(raw, 16); + } + + if (ret) { + volt_out = (this->adc_range_ ? this->cfg_.v_shunt_lsb_range1 : this->cfg_.v_shunt_lsb_range0) * volt_reading; + } + + ESP_LOGV(TAG, "read_shunt_voltage_mv_ ret=%s, shunt_cal=%d, reading_lsb=%f", OKFAILED(ret), this->shunt_cal_, + volt_reading); + + return ret; +} + +bool INA2XX::read_bus_voltage_(float &volt_out) { + // Two's complement value + // 228, 229 - 24bit: 20(23-4) + 4(3-0) res + // 237, 238, 239 - 16bit + + bool ret{false}; + float volt_reading{0}; + uint64_t raw{0}; + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + ret = this->read_unsigned_(RegisterMap::REG_VBUS, 3, raw); + raw >>= 4; + volt_reading = this->two_complement_(raw, 20); + } else { + ret = this->read_unsigned_(RegisterMap::REG_VBUS, 2, raw); + volt_reading = this->two_complement_(raw, 16); + } + if (ret) { + volt_out = this->cfg_.vbus_lsb * (float) volt_reading; + } + + ESP_LOGV(TAG, "read_bus_voltage_ ret=%s, reading_lsb=%f", OKFAILED(ret), volt_reading); + return ret; +} + +bool INA2XX::read_die_temp_c_(float &temp_out) { + // Two's complement value + // 228, 229 - 16bit + // 237, 238, 239 - 16bit: 12(15-4) + 4(3-0) res + + bool ret{false}; + float temp_reading{0}; + uint64_t raw{0}; + + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + ret = this->read_unsigned_(RegisterMap::REG_DIETEMP, 2, raw); + temp_reading = this->two_complement_(raw, 16); + } else { + ret = this->read_unsigned_(RegisterMap::REG_DIETEMP, 2, raw); + raw >>= 4; + temp_reading = this->two_complement_(raw, 12); + } + if (ret) { + temp_out = this->cfg_.die_temp_lsb * (float) temp_reading; + } + + ESP_LOGV(TAG, "read_die_temp_c_ ret=%s, reading_lsb=%f", OKFAILED(ret), temp_reading); + return ret; +} + +bool INA2XX::read_current_a_(float &s_out) { + // Two's complement value + // 228, 229 - 24bit: 20(23-4) + 4(3-0) res + // 237, 238, 239 - 16bit + bool ret{false}; + float amps_reading{0}; + uint64_t raw{0}; + + if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) { + ret = this->read_unsigned_(RegisterMap::REG_CURRENT, 3, raw); + raw >>= 4; + amps_reading = this->two_complement_(raw, 20); + } else { + ret = this->read_unsigned_(RegisterMap::REG_CURRENT, 2, raw); + amps_reading = this->two_complement_(raw, 16); + } + + ESP_LOGV(TAG, "read_current_a_ ret=%s. current_lsb=%f. reading_lsb=%f", OKFAILED(ret), this->current_lsb_, + amps_reading); + if (ret) { + amps_out = this->current_lsb_ * (float) amps_reading; + } + + return ret; +} + +bool INA2XX::read_power_w_(float &power_out) { + // Unsigned value + // 228, 229 - 24bit + // 237, 238, 239 - 24bit + uint64_t power_reading{0}; + auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_POWER, 3, power_reading); + + ESP_LOGV(TAG, "read_power_w_ ret=%s, reading_lsb=%d", OKFAILED(ret), (uint32_t) power_reading); + if (ret) { + power_out = this->cfg_.power_coeff * this->current_lsb_ * (float) power_reading; + } + + return ret; +} + +bool INA2XX::read_energy_(double &joules_out, double &watt_hours_out) { + // Unsigned value + // 228, 229 - 40bit + // 237, 238, 239 - not available + if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) { + joules_out = 0; + return false; + } + uint64_t joules_reading = 0; + uint64_t previous_energy = this->energy_overflows_count_ * (((uint64_t) 1) << 40); + auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_ENERGY, 5, joules_reading); + + ESP_LOGV(TAG, "read_energy_j_ ret=%s, reading_lsb=0x%" PRIX64 ", current_lsb=%f, overflow_cnt=%d", OKFAILED(ret), + joules_reading, this->current_lsb_, this->energy_overflows_count_); + if (ret) { + joules_out = this->cfg_.energy_coeff * this->current_lsb_ * (double) joules_reading + (double) previous_energy; + watt_hours_out = joules_out / 3600.0; + } + return ret; +} + +bool INA2XX::read_charge_(double &coulombs_out, double &_hours_out) { + // Two's complement value + // 228, 229 - 40bit + // 237, 238, 239 - not available + if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) { + coulombs_out = 0; + return false; + } + + // and what to do with this? datasheet doesnt tell us what if charge is negative + uint64_t previous_charge = this->charge_overflows_count_ * (((uint64_t) 1) << 39); + double coulombs_reading = 0; + uint64_t raw{0}; + auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_CHARGE, 5, raw); + coulombs_reading = this->two_complement_(raw, 40); + + ESP_LOGV(TAG, "read_charge_c_ ret=%d, curr_charge=%f + 39-bit overflow_cnt=%d", ret, coulombs_reading, + this->charge_overflows_count_); + if (ret) { + coulombs_out = this->current_lsb_ * (double) coulombs_reading + (double) previous_charge; + amp_hours_out = coulombs_out / 3600.0; + } + return ret; +} + +bool INA2XX::read_diagnostics_and_act_() { + if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) { + return false; + } + + DiagnosticRegister diag{0}; + auto ret = this->read_unsigned_16_(RegisterMap::REG_DIAG_ALRT, diag.raw_u16); + ESP_LOGV(TAG, "read_diagnostics_and_act_ ret=%s, 0x%04X", OKFAILED(ret), diag.raw_u16); + + if (diag.ENERGYOF) { + this->energy_overflows_count_++; // 40-bit overflow + } + + if (diag.CHARGEOF) { + this->charge_overflows_count_++; // 39-bit overflow + } + + return ret; +} + +bool INA2XX::write_unsigned_16_(uint8_t reg, uint16_t val) { + uint16_t data_out = byteswap(val); + auto ret = this->write_ina_register(reg, (uint8_t *) &data_out, 2); + if (!ret) { + ESP_LOGV(TAG, "write_unsigned_16_ FAILED reg=0x%02X, val=0x%04X", reg, val); + } + return ret; +} + +bool INA2XX::read_unsigned_(uint8_t reg, uint8_t reg_size, uint64_t &data_out) { + static uint8_t rx_buf[5] = {0}; // max buffer size + + if (reg_size > 5) { + return false; + } + + auto ret = this->read_ina_register(reg, rx_buf, reg_size); + + // Combine bytes + data_out = rx_buf[0]; + for (uint8_t i = 1; i < reg_size; i++) { + data_out = (data_out << 8) | rx_buf[i]; + } + ESP_LOGV(TAG, "read_unsigned_ reg=0x%02X, ret=%s, len=%d, val=0x%" PRIX64, reg, OKFAILED(ret), reg_size, data_out); + + return ret; +} + +bool INA2XX::read_unsigned_16_(uint8_t reg, uint16_t &out) { + uint16_t data_in{0}; + auto ret = this->read_ina_register(reg, (uint8_t *) &data_in, 2); + out = byteswap(data_in); + ESP_LOGV(TAG, "read_unsigned_16_ 0x%02X, ret= %s, val=0x%04X", reg, OKFAILED(ret), out); + return ret; +} + +int64_t INA2XX::two_complement_(uint64_t value, uint8_t bits) { + if (value > (1ULL << (bits - 1))) { + return (int64_t) (value - (1ULL << bits)); + } else { + return (int64_t) value; + } +} +} // namespace ina2xx_base +} // namespace esphome diff --git a/esphome/components/ina2xx_base/ina2xx_base.h b/esphome/components/ina2xx_base/ina2xx_base.h new file mode 100644 index 0000000000..261c5321bf --- /dev/null +++ b/esphome/components/ina2xx_base/ina2xx_base.h @@ -0,0 +1,253 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace ina2xx_base { + +enum RegisterMap : uint8_t { + REG_CONFIG = 0x00, + REG_ADC_CONFIG = 0x01, + REG_SHUNT_CAL = 0x02, + REG_SHUNT_TEMPCO = 0x03, + REG_VSHUNT = 0x04, + REG_VBUS = 0x05, + REG_DIETEMP = 0x06, + REG_CURRENT = 0x07, + REG_POWER = 0x08, + REG_ENERGY = 0x09, + REG_CHARGE = 0x0A, + REG_DIAG_ALRT = 0x0B, + REG_SOVL = 0x0C, + REG_SUVL = 0x0D, + REG_BOVL = 0x0E, + REG_BUVL = 0x0F, + REG_TEMP_LIMIT = 0x10, + REG_PWR_LIMIT = 0x11, + REG_MANUFACTURER_ID = 0x3E, + REG_DEVICE_ID = 0x3F +}; + +enum AdcRange : uint16_t { + ADC_RANGE_0 = 0, + ADC_RANGE_1 = 1, +}; + +enum AdcTime : uint16_t { + ADC_TIME_50US = 0, + ADC_TIME_84US = 1, + ADC_TIME_150US = 2, + ADC_TIME_280US = 3, + ADC_TIME_540US = 4, + ADC_TIME_1052US = 5, + ADC_TIME_2074US = 6, + ADC_TIME_4120US = 7, +}; + +enum AdcAvgSamples : uint16_t { + ADC_AVG_SAMPLES_1 = 0, + ADC_AVG_SAMPLES_4 = 1, + ADC_AVG_SAMPLES_16 = 2, + ADC_AVG_SAMPLES_64 = 3, + ADC_AVG_SAMPLES_128 = 4, + ADC_AVG_SAMPLES_256 = 5, + ADC_AVG_SAMPLES_512 = 6, + ADC_AVG_SAMPLES_1024 = 7, +}; + +union ConfigurationRegister { + uint16_t raw_u16; + struct { + uint16_t reserved_0_3 : 4; // Reserved + AdcRange ADCRANGE : 1; // Shunt measurement range 0: ±163.84 mV, 1: ±40.96 mV + bool TEMPCOMP : 1; // Temperature compensation enable + uint16_t CONVDLY : 8; // Sets the Delay for initial ADC conversion in steps of 2 ms. + bool RSTACC : 1; // Reset counters + bool RST : 1; // Full device reset + } __attribute__((packed)); +}; + +union AdcConfigurationRegister { + uint16_t raw_u16; + struct { + AdcAvgSamples AVG : 3; + AdcTime VTCT : 3; // Voltage conversion time + AdcTime VSHCT : 3; // Shunt voltage conversion time + AdcTime VBUSCT : 3; // Bus voltage conversion time + uint16_t MODE : 4; + } __attribute__((packed)); +}; + +union TempCompensationRegister { + uint16_t raw_u16; + struct { + uint16_t TEMPCO : 14; + uint16_t reserved : 2; + } __attribute__((packed)); +}; + +union DiagnosticRegister { + uint16_t raw_u16; + struct { + bool MEMSTAT : 1; + bool CNVRF : 1; + bool POL : 1; + bool BUSUL : 1; + bool BUSOL : 1; + bool SHNTUL : 1; + bool SHNTOL : 1; + bool TMPOL : 1; + bool RESERVED1 : 1; + bool MATHOF : 1; + bool CHARGEOF : 1; + bool ENERGYOF : 1; + bool APOL : 1; + bool SLOWALERT : 1; + bool CNVR : 1; + bool ALATCH : 1; + } __attribute__((packed)); +}; + +enum INAModel : uint8_t { INA_UNKNOWN = 0, INA_228, INA_229, INA_238, INA_239, INA_237 }; + +class INA2XX : public PollingComponent { + public: + void setup() override; + float get_setup_priority() const override; + void update() override; + void loop() override; + void dump_config() override; + + void set_shunt_resistance_ohm(float shunt_resistance_ohm) { this->shunt_resistance_ohm_ = shunt_resistance_ohm; } + void set_max_current_a(float max_current_a) { this->max_current_a_ = max_current_a; } + void set_adc_range(uint8_t range) { this->adc_range_ = (range == 0) ? AdcRange::ADC_RANGE_0 : AdcRange::ADC_RANGE_1; } + void set_adc_time_bus_voltage(AdcTime time) { this->adc_time_bus_voltage_ = time; } + void set_adc_time_shunt_voltage(AdcTime time) { this->adc_time_shunt_voltage_ = time; } + void set_adc_time_die_temperature(AdcTime time) { this->adc_time_die_temperature_ = time; } + void set_adc_avg_samples(AdcAvgSamples samples) { this->adc_avg_samples_ = samples; } + void set_shunt_tempco(uint16_t coeff) { this->shunt_tempco_ppm_c_ = coeff; } + + void set_shunt_voltage_sensor(sensor::Sensor *sensor) { this->shunt_voltage_sensor_ = sensor; } + void set_bus_voltage_sensor(sensor::Sensor *sensor) { this->bus_voltage_sensor_ = sensor; } + void set_die_temperature_sensor(sensor::Sensor *sensor) { this->die_temperature_sensor_ = sensor; } + void set_current_sensor(sensor::Sensor *sensor) { this->current_sensor_ = sensor; } + void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; } + void set_energy_sensor_j(sensor::Sensor *sensor) { this->energy_sensor_j_ = sensor; } + void set_energy_sensor_wh(sensor::Sensor *sensor) { this->energy_sensor_wh_ = sensor; } + void set_charge_sensor_c(sensor::Sensor *sensor) { this->charge_sensor_c_ = sensor; } + void set_charge_sensor_ah(sensor::Sensor *sensor) { this->charge_sensor_ah_ = sensor; } + + void set_model(INAModel model) { this->ina_model_ = model; } + + bool reset_energy_counters(); + + protected: + bool reset_config_(); + bool check_device_model_(); + bool configure_adc_(); + + bool configure_shunt_(); + bool configure_shunt_tempco_(); + bool configure_adc_range_(); + + bool read_shunt_voltage_mv_(float &volt_out); + bool read_bus_voltage_(float &volt_out); + bool read_die_temp_c_(float &temp); + bool read_current_a_(float &s_out); + bool read_power_w_(float &power_out); + bool read_energy_(double &joules_out, double &watt_hours_out); + bool read_charge_(double &coulombs_out, double &_hours_out); + + bool read_diagnostics_and_act_(); + + // + // User configuration + // + float shunt_resistance_ohm_; + float max_current_a_; + AdcRange adc_range_{AdcRange::ADC_RANGE_0}; + AdcTime adc_time_bus_voltage_{AdcTime::ADC_TIME_4120US}; + AdcTime adc_time_shunt_voltage_{AdcTime::ADC_TIME_4120US}; + AdcTime adc_time_die_temperature_{AdcTime::ADC_TIME_4120US}; + AdcAvgSamples adc_avg_samples_{AdcAvgSamples::ADC_AVG_SAMPLES_128}; + uint16_t shunt_tempco_ppm_c_{0}; + + // + // Calculated coefficients + // + uint16_t shunt_cal_{0}; + float current_lsb_{0}; + + uint32_t energy_overflows_count_{0}; + uint32_t charge_overflows_count_{0}; + + // + // Sensor objects + // + sensor::Sensor *shunt_voltage_sensor_{nullptr}; + sensor::Sensor *bus_voltage_sensor_{nullptr}; + sensor::Sensor *die_temperature_sensor_{nullptr}; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *power_sensor_{nullptr}; + sensor::Sensor *energy_sensor_j_{nullptr}; + sensor::Sensor *energy_sensor_wh_{nullptr}; + sensor::Sensor *charge_sensor_c_{nullptr}; + sensor::Sensor *charge_sensor_ah_{nullptr}; + + // + // FSM states + // + enum class State : uint8_t { + NOT_INITIALIZED = 0x0, + IDLE, + DATA_COLLECTION_1, + DATA_COLLECTION_2, + DATA_COLLECTION_3, + DATA_COLLECTION_4, + DATA_COLLECTION_5, + DATA_COLLECTION_6, + DATA_COLLECTION_7, + DATA_COLLECTION_8, + } state_{State::NOT_INITIALIZED}; + + bool full_loop_is_okay_{true}; + + // + // Device model + // + INAModel ina_model_{INAModel::INA_UNKNOWN}; + uint16_t dev_id_{0}; + bool device_mismatch_{false}; + + // + // Device specific parameters + // + struct { + float vbus_lsb; + float v_shunt_lsb_range0; + float v_shunt_lsb_range1; + float shunt_cal_scale; + int8_t current_lsb_scale_factor; + float die_temp_lsb; + float power_coeff; + float energy_coeff; + } cfg_; + + // + // Register read/write + // + bool read_unsigned_(uint8_t reg, uint8_t reg_size, uint64_t &data_out); + bool read_unsigned_16_(uint8_t reg, uint16_t &out); + bool write_unsigned_16_(uint8_t reg, uint16_t val); + + int64_t two_complement_(uint64_t value, uint8_t bits); + + // + // Interface-specific implementation + // + virtual bool read_ina_register(uint8_t a_register, uint8_t *data, size_t len) = 0; + virtual bool write_ina_register(uint8_t a_register, const uint8_t *data, size_t len) = 0; +}; +} // namespace ina2xx_base +} // namespace esphome diff --git a/esphome/components/ina2xx_i2c/__init__.py b/esphome/components/ina2xx_i2c/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp b/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp new file mode 100644 index 0000000000..d28525635d --- /dev/null +++ b/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp @@ -0,0 +1,39 @@ +#include "ina2xx_i2c.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace ina2xx_i2c { + +static const char *const TAG = "ina2xx_i2c"; + +void INA2XXI2C::setup() { + auto err = this->write(nullptr, 0); + if (err != i2c::ERROR_OK) { + this->mark_failed(); + return; + } + INA2XX::setup(); +} + +void INA2XXI2C::dump_config() { + INA2XX::dump_config(); + LOG_I2C_DEVICE(this); +} + +bool INA2XXI2C::read_ina_register(uint8_t reg, uint8_t *data, size_t len) { + auto ret = this->read_register(reg, data, len, false); + if (ret != i2c::ERROR_OK) { + ESP_LOGE(TAG, "read_ina_register_ failed. Reg=0x%02X Err=%d", reg, ret); + } + return ret == i2c::ERROR_OK; +} + +bool INA2XXI2C::write_ina_register(uint8_t reg, const uint8_t *data, size_t len) { + auto ret = this->write_register(reg, data, len); + if (ret != i2c::ERROR_OK) { + ESP_LOGE(TAG, "write_register failed. Reg=0x%02X Err=%d", reg, ret); + } + return ret == i2c::ERROR_OK; +} +} // namespace ina2xx_i2c +} // namespace esphome diff --git a/esphome/components/ina2xx_i2c/ina2xx_i2c.h b/esphome/components/ina2xx_i2c/ina2xx_i2c.h new file mode 100644 index 0000000000..c90b9bf190 --- /dev/null +++ b/esphome/components/ina2xx_i2c/ina2xx_i2c.h @@ -0,0 +1,21 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/ina2xx_base/ina2xx_base.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace ina2xx_i2c { + +class INA2XXI2C : public ina2xx_base::INA2XX, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + + protected: + bool read_ina_register(uint8_t reg, uint8_t *data, size_t len) override; + bool write_ina_register(uint8_t reg, const uint8_t *data, size_t len) override; +}; + +} // namespace ina2xx_i2c +} // namespace esphome diff --git a/esphome/components/ina2xx_i2c/sensor.py b/esphome/components/ina2xx_i2c/sensor.py new file mode 100644 index 0000000000..57ddcef17a --- /dev/null +++ b/esphome/components/ina2xx_i2c/sensor.py @@ -0,0 +1,34 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import ina2xx_base, i2c +from esphome.const import CONF_ID, CONF_MODEL + +AUTO_LOAD = ["ina2xx_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +ina2xx_i2c = cg.esphome_ns.namespace("ina2xx_i2c") +INA2XX_I2C = ina2xx_i2c.class_("INA2XXI2C", ina2xx_base.INA2XX, i2c.I2CDevice) + +INAModel = ina2xx_base.ina2xx_base_ns.enum("INAModel") +INA_MODELS = { + "INA228": INAModel.INA_228, + "INA238": INAModel.INA_238, + "INA237": INAModel.INA_237, +} + +CONFIG_SCHEMA = cv.All( + ina2xx_base.INA2XX_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(INA2XX_I2C), + cv.Required(CONF_MODEL): cv.enum(INA_MODELS, upper=True), + } + ).extend(i2c.i2c_device_schema(0x40)), + ina2xx_base.validate_model_config, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await ina2xx_base.setup_ina2xx(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ina2xx_spi/__init__.py b/esphome/components/ina2xx_spi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ina2xx_spi/ina2xx_spi.cpp b/esphome/components/ina2xx_spi/ina2xx_spi.cpp new file mode 100644 index 0000000000..3e04a87665 --- /dev/null +++ b/esphome/components/ina2xx_spi/ina2xx_spi.cpp @@ -0,0 +1,38 @@ +#include "ina2xx_spi.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace ina2xx_spi { + +static const char *const TAG = "ina2xx_spi"; + +void INA2XXSPI::setup() { + this->spi_setup(); + INA2XX::setup(); +} + +void INA2XXSPI::dump_config() { + INA2XX::dump_config(); + LOG_PIN(" CS Pin: ", this->cs_); +} + +bool INA2XXSPI::read_ina_register(uint8_t reg, uint8_t *data, size_t len) { + reg = (reg << 2); // top 6 bits + reg |= 0x01; // read + this->enable(); + this->write_byte(reg); + this->read_array(data, len); + this->disable(); + return true; +} + +bool INA2XXSPI::write_ina_register(uint8_t reg, const uint8_t *data, size_t len) { + reg = (reg << 2); // top 6 bits + this->enable(); + this->write_byte(reg); + this->write_array(data, len); + this->disable(); + return true; +} +} // namespace ina2xx_spi +} // namespace esphome diff --git a/esphome/components/ina2xx_spi/ina2xx_spi.h b/esphome/components/ina2xx_spi/ina2xx_spi.h new file mode 100644 index 0000000000..3b21518d34 --- /dev/null +++ b/esphome/components/ina2xx_spi/ina2xx_spi.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/ina2xx_base/ina2xx_base.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace ina2xx_spi { + +class INA2XXSPI : public ina2xx_base::INA2XX, + public spi::SPIDevice { + public: + void setup() override; + void dump_config() override; + + protected: + bool read_ina_register(uint8_t reg, uint8_t *data, size_t len) override; + bool write_ina_register(uint8_t reg, const uint8_t *data, size_t len) override; +}; +} // namespace ina2xx_spi +} // namespace esphome diff --git a/esphome/components/ina2xx_spi/sensor.py b/esphome/components/ina2xx_spi/sensor.py new file mode 100644 index 0000000000..e7ae51d516 --- /dev/null +++ b/esphome/components/ina2xx_spi/sensor.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import ina2xx_base, spi +from esphome.const import CONF_ID, CONF_MODEL + +AUTO_LOAD = ["ina2xx_base"] +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["spi"] + +ina2xx_spi = cg.esphome_ns.namespace("ina2xx_spi") +INA2XX_SPI = ina2xx_spi.class_("INA2XXSPI", ina2xx_base.INA2XX, spi.SPIDevice) + +INAModel = ina2xx_base.ina2xx_base_ns.enum("INAModel") +INA_MODELS = { + "INA229": INAModel.INA_229, + "INA239": INAModel.INA_239, +} + +CONFIG_SCHEMA = cv.All( + ina2xx_base.INA2XX_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(INA2XX_SPI), + cv.Required(CONF_MODEL): cv.enum(INA_MODELS, upper=True), + } + ).extend(spi.spi_device_schema(cs_pin_required=True)), + ina2xx_base.validate_model_config, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await ina2xx_base.setup_ina2xx(var, config) + await spi.register_spi_device(var, config) diff --git a/tests/components/ina2xx_i2c/common.yaml b/tests/components/ina2xx_i2c/common.yaml new file mode 100644 index 0000000000..320b680b6b --- /dev/null +++ b/tests/components/ina2xx_i2c/common.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_ina2xx + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: ina2xx_i2c + i2c_id: i2c_ina2xx + address: 0x40 + model: INA228 + shunt_resistance: 0.001130 ohm + max_current: 40 A + adc_range: 1 + temperature_coefficient: 50 + shunt_voltage: "INA2xx Shunt Voltage" + bus_voltage: "INA2xx Bus Voltage" + current: "INA2xx Current" + power: "INA2xx Power" + energy: "INA2xx Energy" + charge: "INA2xx Charge" diff --git a/tests/components/ina2xx_i2c/test.esp32-c3-idf.yaml b/tests/components/ina2xx_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ina2xx_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_i2c/test.esp32-c3.yaml b/tests/components/ina2xx_i2c/test.esp32-c3.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ina2xx_i2c/test.esp32-c3.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_i2c/test.esp32-idf.yaml b/tests/components/ina2xx_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/ina2xx_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_i2c/test.esp32.yaml b/tests/components/ina2xx_i2c/test.esp32.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/ina2xx_i2c/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_i2c/test.esp8266.yaml b/tests/components/ina2xx_i2c/test.esp8266.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ina2xx_i2c/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_i2c/test.rp2040.yaml b/tests/components/ina2xx_i2c/test.rp2040.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/ina2xx_i2c/test.rp2040.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/common.yaml b/tests/components/ina2xx_spi/common.yaml new file mode 100644 index 0000000000..3eab7e6f0a --- /dev/null +++ b/tests/components/ina2xx_spi/common.yaml @@ -0,0 +1,21 @@ +spi: + - id: spi_ina2xx + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +sensor: + - platform: ina2xx_spi + spi_id: spi_ina2xx + cs_pin: ${cs_pin} + model: INA229 + shunt_resistance: 0.001130 ohm + max_current: 40 A + adc_range: 1 + temperature_coefficient: 50 + shunt_voltage: "INA2xx Shunt Voltage" + bus_voltage: "INA2xx Bus Voltage" + current: "INA2xx Current" + power: "INA2xx Power" + energy: "INA2xx Energy" + charge: "INA2xx Charge" diff --git a/tests/components/ina2xx_spi/test.esp32-c3-idf.yaml b/tests/components/ina2xx_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/ina2xx_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/test.esp32-c3.yaml b/tests/components/ina2xx_spi/test.esp32-c3.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/ina2xx_spi/test.esp32-c3.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/test.esp32-idf.yaml b/tests/components/ina2xx_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/ina2xx_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/test.esp32.yaml b/tests/components/ina2xx_spi/test.esp32.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/ina2xx_spi/test.esp32.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/test.esp8266.yaml b/tests/components/ina2xx_spi/test.esp8266.yaml new file mode 100644 index 0000000000..dbd158d030 --- /dev/null +++ b/tests/components/ina2xx_spi/test.esp8266.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + cs_pin: GPIO15 + +<<: !include common.yaml diff --git a/tests/components/ina2xx_spi/test.rp2040.yaml b/tests/components/ina2xx_spi/test.rp2040.yaml new file mode 100644 index 0000000000..f6c3f1eeca --- /dev/null +++ b/tests/components/ina2xx_spi/test.rp2040.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO2 + mosi_pin: GPIO3 + miso_pin: GPIO4 + cs_pin: GPIO5 + +<<: !include common.yaml From d410cc4f7beac8b483b67adc6bba635dce5230ad Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 16 May 2024 12:22:18 +0200 Subject: [PATCH 1764/2607] [nextion] Fix type on sprintf for IDF v5 (#6758) --- esphome/components/nextion/nextion_upload_idf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index 448b6fc0ff..b5bb5478c1 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -260,7 +260,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { // Tells the Nextion the content length of the tft file and baud rate it will be sent at // Once the Nextion accepts the command it will wait until the file is successfully uploaded // If it fails for any reason a power cycle of the display will be needed - sprintf(command, "whmi-wris %d,%" PRIu32 ",1", this->content_length_, baud_rate); + sprintf(command, "whmi-wris %" PRIu32 ",%" PRIu32 ",1", this->content_length_, baud_rate); // Clear serial receive buffer ESP_LOGV(TAG, "Clear serial receive buffer"); From df838b5788e8d9b42718225d89c8f5f3854fa076 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 May 2024 22:33:33 +1200 Subject: [PATCH 1765/2607] [core] Remove references to deleted setup.py (#6757) --- .github/workflows/release.yml | 4 +++- CODEOWNERS | 2 +- script/build_codeowners.py | 2 +- script/ci-custom.py | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03ed523e1d..c1c502394a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,7 +61,9 @@ jobs: ESPHOME_NO_VENV: 1 run: script/setup - name: Build - run: python setup.py sdist bdist_wheel + run: |- + pip3 install build + python3 -m build - name: Publish uses: pypa/gh-action-pypi-publish@v1.8.14 diff --git a/CODEOWNERS b/CODEOWNERS index d97207941f..dc6c8caa87 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,7 +6,7 @@ # the integration's code owner is automatically notified. # Core Code -setup.py @esphome/core +pyproject.toml @esphome/core esphome/*.py @esphome/core esphome/core/* @esphome/core diff --git a/script/build_codeowners.py b/script/build_codeowners.py index 22f3c1b4bc..6bc558d351 100755 --- a/script/build_codeowners.py +++ b/script/build_codeowners.py @@ -28,7 +28,7 @@ BASE = """ # the integration's code owner is automatically notified. # Core Code -setup.py @esphome/core +pyproject.toml @esphome/core esphome/*.py @esphome/core esphome/core/* @esphome/core diff --git a/script/ci-custom.py b/script/ci-custom.py index 704962fa97..e2ee81f742 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -229,7 +229,6 @@ def lint_ext_check(fname): "docker/ha-addon-rootfs/**", "docker/*.py", "script/*", - "setup.py", ] ) def lint_executable_bit(fname): From 94b63d7bc2675b02b3f869018de7a842a69edb00 Mon Sep 17 00:00:00 2001 From: acshef Date: Fri, 17 May 2024 22:17:09 -0600 Subject: [PATCH 1766/2607] Add device_class to valve core config (#6765) --- esphome/components/valve/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index 22d617cc36..13c2947438 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, + DEVICE_CLASS_GAS, + DEVICE_CLASS_WATER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -22,6 +24,11 @@ IS_PLATFORM_COMPONENT = True CODEOWNERS = ["@esphome/core"] +DEVICE_CLASSES = [ + DEVICE_CLASS_GAS, + DEVICE_CLASS_WATER, +] + valve_ns = cg.esphome_ns.namespace("valve") Valve = valve_ns.class_("Valve", cg.EntityBase) @@ -65,6 +72,7 @@ VALVE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex { cv.GenerateID(): cv.declare_id(Valve), cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTValveComponent), + cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( cv.requires_component("mqtt"), cv.subscribe_topic ), From 1164cb86106bc44cf57ab280e379499fe03f440b Mon Sep 17 00:00:00 2001 From: esphomebot Date: Sat, 18 May 2024 19:15:52 +1200 Subject: [PATCH 1767/2607] Synchronise Device Classes from Home Assistant (#6768) --- esphome/components/valve/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index 13c2947438..ea6bfc6055 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, ) @@ -25,6 +26,7 @@ IS_PLATFORM_COMPONENT = True CODEOWNERS = ["@esphome/core"] DEVICE_CLASSES = [ + DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, ] From 70e0925f9abaab0aa0cc13646b1115cdce230a98 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Sun, 19 May 2024 01:31:36 +0200 Subject: [PATCH 1768/2607] Fix pip3 install (#6771) --- script/setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/setup b/script/setup index 71573a9352..1a18a6a9ea 100755 --- a/script/setup +++ b/script/setup @@ -20,7 +20,7 @@ fi pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt -r requirements_dev.txt pip3 install setuptools wheel -pip3 install -e --config-settings editable_mode=compat ".[dev,test,displays]" +pip3 install -e ".[dev,test,displays]" --config-settings editable_mode=compat pre-commit install From 4469ba402498e6b8e20b6fc89873f70f61a1a21e Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 19 May 2024 01:47:23 +0200 Subject: [PATCH 1769/2607] [tests] make test_build_components work with venv without installing esphome (#6761) --- script/test_build_components | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/script/test_build_components b/script/test_build_components index 4d91256572..f82dd5c3b6 100755 --- a/script/test_build_components +++ b/script/test_build_components @@ -37,9 +37,10 @@ start_esphome() { # Start esphome process echo "> [$target_component] [$test_name] [$target_platform]" - echo "esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file" + set -x # TODO: Validate escape of Command line substitution value - esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file + python -m esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file + { set +x; } 2>/dev/null } # Find all test yaml files. From ba73187c1bf20ac0c9d823a5ff8d8aa5f8a07e03 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 19 May 2024 22:11:27 +0200 Subject: [PATCH 1770/2607] separate deep_sleep component for each platform in different file (#6762) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../deep_sleep/deep_sleep_component.cpp | 115 ++---------------- .../deep_sleep/deep_sleep_component.h | 4 + .../deep_sleep/deep_sleep_esp32.cpp | 104 ++++++++++++++++ .../deep_sleep/deep_sleep_esp8266.cpp | 23 ++++ 4 files changed, 143 insertions(+), 103 deletions(-) create mode 100644 esphome/components/deep_sleep/deep_sleep_esp32.cpp create mode 100644 esphome/components/deep_sleep/deep_sleep_esp8266.cpp diff --git a/esphome/components/deep_sleep/deep_sleep_component.cpp b/esphome/components/deep_sleep/deep_sleep_component.cpp index 97fdf11366..1e7637f3e5 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.cpp +++ b/esphome/components/deep_sleep/deep_sleep_component.cpp @@ -1,12 +1,7 @@ #include "deep_sleep_component.h" -#include #include "esphome/core/application.h" #include "esphome/core/log.h" -#ifdef USE_ESP8266 -#include -#endif - namespace esphome { namespace deep_sleep { @@ -14,25 +9,6 @@ static const char *const TAG = "deep_sleep"; bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -optional DeepSleepComponent::get_run_duration_() const { -#ifdef USE_ESP32 - if (this->wakeup_cause_to_run_duration_.has_value()) { - esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause(); - switch (wakeup_cause) { - case ESP_SLEEP_WAKEUP_EXT0: - case ESP_SLEEP_WAKEUP_EXT1: - case ESP_SLEEP_WAKEUP_GPIO: - return this->wakeup_cause_to_run_duration_->gpio_cause; - case ESP_SLEEP_WAKEUP_TOUCHPAD: - return this->wakeup_cause_to_run_duration_->touch_cause; - default: - return this->wakeup_cause_to_run_duration_->default_cause; - } - } -#endif - return this->run_duration_; -} - void DeepSleepComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); global_has_deep_sleep = true; @@ -45,6 +21,7 @@ void DeepSleepComponent::setup() { ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured."); } } + void DeepSleepComponent::dump_config() { ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); if (this->sleep_duration_.has_value()) { @@ -54,65 +31,31 @@ void DeepSleepComponent::dump_config() { if (this->run_duration_.has_value()) { ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " ms", *this->run_duration_); } -#ifdef USE_ESP32 - if (wakeup_pin_ != nullptr) { - LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_); - } - if (this->wakeup_cause_to_run_duration_.has_value()) { - ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms", - this->wakeup_cause_to_run_duration_->default_cause); - ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause); - ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause); - } -#endif + this->dump_config_platform_(); } + void DeepSleepComponent::loop() { if (this->next_enter_deep_sleep_) this->begin_sleep(); } + float DeepSleepComponent::get_loop_priority() const { return -100.0f; // run after everything else is ready } + void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; } -#if defined(USE_ESP32) -void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) { - this->wakeup_pin_mode_ = wakeup_pin_mode; -} -#endif - -#if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) - -void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; } - -void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; } - -#endif - -void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) { - wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration; -} - -#endif void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; } + void DeepSleepComponent::begin_sleep(bool manual) { if (this->prevent_ && !manual) { this->next_enter_deep_sleep_ = true; return; } -#ifdef USE_ESP32 - if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr && - !this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) { - // Defer deep sleep until inactive - if (!this->next_enter_deep_sleep_) { - this->status_set_warning(); - ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep..."); - } - this->next_enter_deep_sleep_ = true; + + if (!this->prepare_to_sleep_()) { return; } -#endif ESP_LOGI(TAG, "Beginning Deep Sleep"); if (this->sleep_duration_.has_value()) { @@ -120,47 +63,13 @@ void DeepSleepComponent::begin_sleep(bool manual) { } App.run_safe_shutdown_hooks(); -#if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) - if (this->sleep_duration_.has_value()) - esp_sleep_enable_timer_wakeup(*this->sleep_duration_); - if (this->wakeup_pin_ != nullptr) { - bool level = !this->wakeup_pin_->is_inverted(); - if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) { - level = !level; - } - esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level); - } - if (this->ext1_wakeup_.has_value()) { - esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode); - } - - if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) { - esp_sleep_enable_touchpad_wakeup(); - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - } -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) - if (this->sleep_duration_.has_value()) - esp_sleep_enable_timer_wakeup(*this->sleep_duration_); - if (this->wakeup_pin_ != nullptr) { - bool level = !this->wakeup_pin_->is_inverted(); - if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) { - level = !level; - } - esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(), - static_cast(level)); - } -#endif - esp_deep_sleep_start(); -#endif - -#ifdef USE_ESP8266 - ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance) -#endif + this->deep_sleep_(); } + float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; } + void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; } + void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; } } // namespace deep_sleep diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h index e97d8300c4..be56b529ba 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.h +++ b/esphome/components/deep_sleep/deep_sleep_component.h @@ -106,6 +106,10 @@ class DeepSleepComponent : public Component { // duration before entering deep sleep. optional get_run_duration_() const; + void dump_config_platform_(); + bool prepare_to_sleep_(); + void deep_sleep_(); + optional sleep_duration_; #ifdef USE_ESP32 InternalGPIOPin *wakeup_pin_; diff --git a/esphome/components/deep_sleep/deep_sleep_esp32.cpp b/esphome/components/deep_sleep/deep_sleep_esp32.cpp new file mode 100644 index 0000000000..d54046bc11 --- /dev/null +++ b/esphome/components/deep_sleep/deep_sleep_esp32.cpp @@ -0,0 +1,104 @@ +#ifdef USE_ESP32 +#include "deep_sleep_component.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace deep_sleep { + +static const char *const TAG = "deep_sleep"; + +optional DeepSleepComponent::get_run_duration_() const { + if (this->wakeup_cause_to_run_duration_.has_value()) { + esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause(); + switch (wakeup_cause) { + case ESP_SLEEP_WAKEUP_EXT0: + case ESP_SLEEP_WAKEUP_EXT1: + case ESP_SLEEP_WAKEUP_GPIO: + return this->wakeup_cause_to_run_duration_->gpio_cause; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + return this->wakeup_cause_to_run_duration_->touch_cause; + default: + return this->wakeup_cause_to_run_duration_->default_cause; + } + } + return this->run_duration_; +} + +void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) { + this->wakeup_pin_mode_ = wakeup_pin_mode; +} + +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) +void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; } + +void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; } +#endif + +void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) { + wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration; +} + +void DeepSleepComponent::dump_config_platform_() { + if (wakeup_pin_ != nullptr) { + LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_); + } + if (this->wakeup_cause_to_run_duration_.has_value()) { + ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms", + this->wakeup_cause_to_run_duration_->default_cause); + ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause); + ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause); + } +} + +bool DeepSleepComponent::prepare_to_sleep_() { + if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr && + !this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) { + // Defer deep sleep until inactive + if (!this->next_enter_deep_sleep_) { + this->status_set_warning(); + ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep..."); + } + this->next_enter_deep_sleep_ = true; + return false; + } + return true; +} + +void DeepSleepComponent::deep_sleep_() { +#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) + if (this->sleep_duration_.has_value()) + esp_sleep_enable_timer_wakeup(*this->sleep_duration_); + if (this->wakeup_pin_ != nullptr) { + bool level = !this->wakeup_pin_->is_inverted(); + if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) { + level = !level; + } + esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level); + } + if (this->ext1_wakeup_.has_value()) { + esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode); + } + + if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) { + esp_sleep_enable_touchpad_wakeup(); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + } +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) + if (this->sleep_duration_.has_value()) + esp_sleep_enable_timer_wakeup(*this->sleep_duration_); + if (this->wakeup_pin_ != nullptr) { + bool level = !this->wakeup_pin_->is_inverted(); + if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) { + level = !level; + } + esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(), + static_cast(level)); + } +#endif + esp_deep_sleep_start(); +} + +} // namespace deep_sleep +} // namespace esphome +#endif diff --git a/esphome/components/deep_sleep/deep_sleep_esp8266.cpp b/esphome/components/deep_sleep/deep_sleep_esp8266.cpp new file mode 100644 index 0000000000..54d2aa993d --- /dev/null +++ b/esphome/components/deep_sleep/deep_sleep_esp8266.cpp @@ -0,0 +1,23 @@ +#ifdef USE_ESP8266 +#include "deep_sleep_component.h" + +#include + +namespace esphome { +namespace deep_sleep { + +static const char *const TAG = "deep_sleep"; + +optional DeepSleepComponent::get_run_duration_() const { return this->run_duration_; } + +void DeepSleepComponent::dump_config_platform_() {} + +bool DeepSleepComponent::prepare_to_sleep_() { return true; } + +void DeepSleepComponent::deep_sleep_() { + ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance) +} + +} // namespace deep_sleep +} // namespace esphome +#endif From a85d37a1cfae47d77c05e4deac830e5811af8066 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 08:12:32 +1200 Subject: [PATCH 1771/2607] Bump actions/checkout from 4.1.5 to 4.1.6 (#6764) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 32 +++++++++++------------ .github/workflows/release.yml | 8 +++--- .github/workflows/sync-device-classes.yml | 4 +-- .github/workflows/yaml-lint.yml | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 448d0fd10f..1628464061 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 72a16233fb..dd5c051cfb 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba0a8a363c..2b3c80cb35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -66,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -87,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -108,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -129,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -150,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -199,7 +199,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -229,7 +229,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -254,7 +254,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Find all YAML test files id: set-matrix run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT @@ -271,7 +271,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -303,7 +303,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -358,7 +358,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -410,7 +410,7 @@ jobs: count: ${{ steps.list-components.outputs.count }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 with: # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. fetch-depth: 500 @@ -458,7 +458,7 @@ jobs: run: sudo apt-get install libsodium-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -484,7 +484,7 @@ jobs: matrix: ${{ steps.split.outputs.components }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Split components into 20 groups id: split run: | @@ -512,7 +512,7 @@ jobs: run: sudo apt-get install libsodium-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c1c502394a..47dc217bf7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: tag: ${{ steps.tag.outputs.tag }} branch_build: ${{ steps.tag.outputs.branch_build }} steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - name: Get tag id: tag # yamllint disable rule:line-length @@ -51,7 +51,7 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -83,7 +83,7 @@ jobs: - linux/arm/v7 - linux/arm64 steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -174,7 +174,7 @@ jobs: - ghcr - dockerhub steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - name: Download digests uses: actions/download-artifact@v4.1.7 diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 7d67999b77..9a8c9d1753 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -13,10 +13,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Checkout Home Assistant - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 with: repository: home-assistant/core path: lib/home-assistant diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index 761247529b..f009643629 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Run yamllint uses: frenck/action-yamllint@v1.5.0 with: From 080f8bc86ed215dd12a1f6dc8d0b2bfa80302df2 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Sun, 19 May 2024 22:33:20 +0200 Subject: [PATCH 1772/2607] Fix Upload from Dashboard with MQTT discovery. (#6774) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 9930119c86..f3c4ff3e23 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -351,7 +351,7 @@ def upload_program(config, args, host): not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) and CONF_MQTT in config - and (not args.device or args.device == "MQTT") + and (not args.device or args.device in ("MQTT", "OTA")) ): from esphome import mqtt From 91e7a44c3172cddddc93804e04206a962384e2ab Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Mon, 20 May 2024 01:52:14 +0200 Subject: [PATCH 1773/2607] Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) --- esphome/dashboard/status/mqtt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/dashboard/status/mqtt.py b/esphome/dashboard/status/mqtt.py index 8c35dd2535..0e53c21679 100644 --- a/esphome/dashboard/status/mqtt.py +++ b/esphome/dashboard/status/mqtt.py @@ -18,7 +18,7 @@ class MqttStatusThread(threading.Thread): """Run the status thread.""" dashboard = DASHBOARD entries = dashboard.entries - current_entries = entries.all() + current_entries = entries.async_all() config = mqtt.config_from_env() topic = "esphome/discover/#" @@ -33,7 +33,7 @@ class MqttStatusThread(threading.Thread): return for entry in current_entries: if entry.name == data["name"]: - entries.set_state(entry, EntryState.ONLINE) + entries.async_set_state(entry, EntryState.ONLINE) return def on_connect(client, userdata, flags, return_code): @@ -53,11 +53,11 @@ class MqttStatusThread(threading.Thread): client.loop_start() while not dashboard.stop_event.wait(2): - current_entries = entries.all() + current_entries = entries.async_all() # will be set to true on on_message for entry in current_entries: if entry.no_mdns: - entries.set_state(entry, EntryState.OFFLINE) + entries.async_set_state(entry, EntryState.OFFLINE) client.publish("esphome/discover", None, retain=False) dashboard.mqtt_ping_request.wait() From b9bb3cd4bec794f155357e1688831456df77734d Mon Sep 17 00:00:00 2001 From: fodfodfod <94200657+fodfodfod@users.noreply.github.com> Date: Sun, 19 May 2024 20:42:30 -0400 Subject: [PATCH 1774/2607] add rp2040 support to the wizard (#6239) --- esphome/wizard.py | 115 ++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 51 deletions(-) diff --git a/esphome/wizard.py b/esphome/wizard.py index 9680ade044..f8911ae844 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -277,6 +277,7 @@ def wizard(path): from esphome.components.esp32 import boards as esp32_boards from esphome.components.esp8266 import boards as esp8266_boards from esphome.components.rtl87xx import boards as rtl87xx_boards + from esphome.components.rp2040 import boards as rp2040_boards if not path.endswith(".yaml") and not path.endswith(".yml"): safe_print( @@ -343,7 +344,7 @@ def wizard(path): "firmwares for it." ) - wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "RTL87XX"] + wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "RTL87XX", "RP2040"] safe_print( "Please choose one of the supported microcontrollers " "(Use ESP8266 for Sonoff devices)." @@ -373,6 +374,10 @@ def wizard(path): board_link = ( "http://docs.platformio.org/en/latest/platforms/espressif8266.html#boards" ) + elif platform == "RP2040": + board_link = ( + "https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html" + ) elif platform in ["BK72XX", "RTL87XX"]: board_link = "https://docs.libretiny.eu/docs/status/supported/" else: @@ -397,6 +402,10 @@ def wizard(path): elif platform == "RTL87XX": safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'wr3')}\".") boards_list = rtl87xx_boards.BOARDS.items() + elif platform == "RP2040": + safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'rpipicow')}\".") + boards_list = rp2040_boards.BOARDS.items() + else: raise NotImplementedError("Unknown platform!") @@ -423,60 +432,64 @@ def wizard(path): safe_print() sleep(1) - safe_print_step(3, WIFI_BIG) - safe_print("In this step, I'm going to create the configuration for WiFi.") - safe_print() - sleep(1) - safe_print( - f"First, what's the {color(Fore.GREEN, 'SSID')} (the name) of the WiFi network {name} should connect to?" - ) - sleep(1.5) - safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'Abraham Linksys')}\".") - while True: - ssid = safe_input(color(Fore.BOLD_WHITE, "(ssid): ")) - try: - ssid = cv.ssid(ssid) - break - except vol.Invalid: - safe_print( - color( - Fore.RED, - f'Unfortunately, "{ssid}" doesn\'t seem to be a valid SSID. Please try again.', + # Do not create wifi if the board does not support it + if board not in ["rpipico"]: + safe_print_step(3, WIFI_BIG) + safe_print("In this step, I'm going to create the configuration for WiFi.") + safe_print() + sleep(1) + safe_print( + f"First, what's the {color(Fore.GREEN, 'SSID')} (the name) of the WiFi network {name} should connect to?" + ) + sleep(1.5) + safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'Abraham Linksys')}\".") + while True: + ssid = safe_input(color(Fore.BOLD_WHITE, "(ssid): ")) + try: + ssid = cv.ssid(ssid) + break + except vol.Invalid: + safe_print( + color( + Fore.RED, + f'Unfortunately, "{ssid}" doesn\'t seem to be a valid SSID. Please try again.', + ) ) - ) - safe_print() - sleep(1) + safe_print() + sleep(1) - safe_print( - f'Thank you very much! You\'ve just chosen "{color(Fore.CYAN, ssid)}" as your SSID.' - ) - safe_print() - sleep(0.75) + safe_print( + f'Thank you very much! You\'ve just chosen "{color(Fore.CYAN, ssid)}" as your SSID.' + ) + safe_print() + sleep(0.75) - safe_print( - f"Now please state the {color(Fore.GREEN, 'password')} of the WiFi network so that I can connect to it (Leave empty for no password)" - ) - safe_print() - safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'PASSWORD42')}\"") - sleep(0.5) - psk = safe_input(color(Fore.BOLD_WHITE, "(PSK): ")) - safe_print( - "Perfect! WiFi is now set up (you can create static IPs and so on later)." - ) - sleep(1.5) + safe_print( + f"Now please state the {color(Fore.GREEN, 'password')} of the WiFi network so that I can connect to it (Leave empty for no password)" + ) + safe_print() + safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'PASSWORD42')}\"") + sleep(0.5) + psk = safe_input(color(Fore.BOLD_WHITE, "(PSK): ")) + safe_print( + "Perfect! WiFi is now set up (you can create static IPs and so on later)." + ) + sleep(1.5) - safe_print_step(4, OTA_BIG) - safe_print( - "Almost there! ESPHome can automatically upload custom firmwares over WiFi " - "(over the air) and integrates into Home Assistant with a native API." - ) - safe_print( - f"This can be insecure if you do not trust the WiFi network. Do you want to set a {color(Fore.GREEN, 'password')} for connecting to this ESP?" - ) - safe_print() - sleep(0.25) - safe_print("Press ENTER for no password") - password = safe_input(color(Fore.BOLD_WHITE, "(password): ")) + safe_print_step(4, OTA_BIG) + safe_print( + "Almost there! ESPHome can automatically upload custom firmwares over WiFi " + "(over the air) and integrates into Home Assistant with a native API." + ) + safe_print( + f"This can be insecure if you do not trust the WiFi network. Do you want to set a {color(Fore.GREEN, 'password')} for connecting to this ESP?" + ) + safe_print() + sleep(0.25) + safe_print("Press ENTER for no password") + password = safe_input(color(Fore.BOLD_WHITE, "(password): ")) + else: + ssid, password, psk = "", "", "" if not wizard_write( path=path, From 840f69ffe673401f5b1434dbf23213a51489d569 Mon Sep 17 00:00:00 2001 From: acshef Date: Fri, 17 May 2024 22:17:09 -0600 Subject: [PATCH 1775/2607] Add device_class to valve core config (#6765) --- esphome/components/valve/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index 22d617cc36..13c2947438 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, + DEVICE_CLASS_GAS, + DEVICE_CLASS_WATER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -22,6 +24,11 @@ IS_PLATFORM_COMPONENT = True CODEOWNERS = ["@esphome/core"] +DEVICE_CLASSES = [ + DEVICE_CLASS_GAS, + DEVICE_CLASS_WATER, +] + valve_ns = cg.esphome_ns.namespace("valve") Valve = valve_ns.class_("Valve", cg.EntityBase) @@ -65,6 +72,7 @@ VALVE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex { cv.GenerateID(): cv.declare_id(Valve), cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTValveComponent), + cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( cv.requires_component("mqtt"), cv.subscribe_topic ), From 4fc2f2284afd663d6e5649a959ed312dc96c5a38 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Sat, 18 May 2024 19:15:52 +1200 Subject: [PATCH 1776/2607] Synchronise Device Classes from Home Assistant (#6768) --- esphome/components/valve/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index 13c2947438..ea6bfc6055 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, ) @@ -25,6 +26,7 @@ IS_PLATFORM_COMPONENT = True CODEOWNERS = ["@esphome/core"] DEVICE_CLASSES = [ + DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, ] From 7452879fb1a85c4bd1795b44d08c4853595ae97e Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Sun, 19 May 2024 22:33:20 +0200 Subject: [PATCH 1777/2607] Fix Upload from Dashboard with MQTT discovery. (#6774) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 54c1aa112a..1d316a97ee 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -346,7 +346,7 @@ def upload_program(config, args, host): not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) and CONF_MQTT in config - and (not args.device or args.device == "MQTT") + and (not args.device or args.device in ("MQTT", "OTA")) ): from esphome import mqtt From ec6d86c8f5a57ca652449ed9b91b5e975d23f882 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Mon, 20 May 2024 01:52:14 +0200 Subject: [PATCH 1778/2607] Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) --- esphome/dashboard/status/mqtt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/dashboard/status/mqtt.py b/esphome/dashboard/status/mqtt.py index 8c35dd2535..0e53c21679 100644 --- a/esphome/dashboard/status/mqtt.py +++ b/esphome/dashboard/status/mqtt.py @@ -18,7 +18,7 @@ class MqttStatusThread(threading.Thread): """Run the status thread.""" dashboard = DASHBOARD entries = dashboard.entries - current_entries = entries.all() + current_entries = entries.async_all() config = mqtt.config_from_env() topic = "esphome/discover/#" @@ -33,7 +33,7 @@ class MqttStatusThread(threading.Thread): return for entry in current_entries: if entry.name == data["name"]: - entries.set_state(entry, EntryState.ONLINE) + entries.async_set_state(entry, EntryState.ONLINE) return def on_connect(client, userdata, flags, return_code): @@ -53,11 +53,11 @@ class MqttStatusThread(threading.Thread): client.loop_start() while not dashboard.stop_event.wait(2): - current_entries = entries.all() + current_entries = entries.async_all() # will be set to true on on_message for entry in current_entries: if entry.no_mdns: - entries.set_state(entry, EntryState.OFFLINE) + entries.async_set_state(entry, EntryState.OFFLINE) client.publish("esphome/discover", None, retain=False) dashboard.mqtt_ping_request.wait() From d2d3db4b8c2a29db046eb3478199c9917a28904d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 20 May 2024 17:14:17 +1200 Subject: [PATCH 1779/2607] Bump version to 2024.5.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 9871ea704f..9d2b8b78ea 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.0" +__version__ = "2024.5.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 25ee24299a220c231baf37d50156ee35d78e561c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 01:49:00 -1000 Subject: [PATCH 1780/2607] Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) --- esphome/dashboard/status/mqtt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/dashboard/status/mqtt.py b/esphome/dashboard/status/mqtt.py index 0e53c21679..8c35dd2535 100644 --- a/esphome/dashboard/status/mqtt.py +++ b/esphome/dashboard/status/mqtt.py @@ -18,7 +18,7 @@ class MqttStatusThread(threading.Thread): """Run the status thread.""" dashboard = DASHBOARD entries = dashboard.entries - current_entries = entries.async_all() + current_entries = entries.all() config = mqtt.config_from_env() topic = "esphome/discover/#" @@ -33,7 +33,7 @@ class MqttStatusThread(threading.Thread): return for entry in current_entries: if entry.name == data["name"]: - entries.async_set_state(entry, EntryState.ONLINE) + entries.set_state(entry, EntryState.ONLINE) return def on_connect(client, userdata, flags, return_code): @@ -53,11 +53,11 @@ class MqttStatusThread(threading.Thread): client.loop_start() while not dashboard.stop_event.wait(2): - current_entries = entries.async_all() + current_entries = entries.all() # will be set to true on on_message for entry in current_entries: if entry.no_mdns: - entries.async_set_state(entry, EntryState.OFFLINE) + entries.set_state(entry, EntryState.OFFLINE) client.publish("esphome/discover", None, retain=False) dashboard.mqtt_ping_request.wait() From 59b1e9c1b024191a666b98e97fe60da18de0d4e8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 01:52:24 -1000 Subject: [PATCH 1781/2607] Fix DashboardEntries.all() call (#6783) --- esphome/dashboard/entries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/dashboard/entries.py b/esphome/dashboard/entries.py index cd318ba8a7..7a9bff4ec1 100644 --- a/esphome/dashboard/entries.py +++ b/esphome/dashboard/entries.py @@ -103,7 +103,7 @@ class DashboardEntries: def all(self) -> list[DashboardEntry]: """Return all entries.""" - return asyncio.run_coroutine_threadsafe(self._async_all, self._loop).result() + return asyncio.run_coroutine_threadsafe(self._async_all(), self._loop).result() def async_all(self) -> list[DashboardEntry]: """Return all entries.""" From bad400e1cd2da09a2d3cf8072bc1d66bfe6d0801 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 21 May 2024 07:18:13 +1000 Subject: [PATCH 1782/2607] [ili9xxx] Add 18bit mode selection and custom init sequence (#6745) --- esphome/components/ili9xxx/display.py | 58 ++++++++++++-- .../components/ili9xxx/ili9xxx_display.cpp | 80 +++++++++++++++---- esphome/components/ili9xxx/ili9xxx_display.h | 14 +++- tests/components/ili9xxx/test.esp32-idf.yaml | 20 +---- 4 files changed, 132 insertions(+), 40 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 3aaf76d6f8..f0ac5ba9ef 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -47,6 +47,12 @@ ILI9XXXDisplay = ili9xxx_ns.class_( display.DisplayBuffer, ) +PixelMode = ili9xxx_ns.enum("PixelMode") +PIXEL_MODES = { + "16bit": PixelMode.PIXEL_MODE_16, + "18bit": PixelMode.PIXEL_MODE_18, +} + ILI9XXXColorMode = ili9xxx_ns.enum("ILI9XXXColorMode") ColorOrder = display.display_ns.enum("ColorMode") @@ -68,6 +74,7 @@ MODELS = { "S3BOX": ili9xxx_ns.class_("ILI9XXXS3Box", ILI9XXXDisplay), "S3BOX_LITE": ili9xxx_ns.class_("ILI9XXXS3BoxLite", ILI9XXXDisplay), "WAVESHARE_RES_3_5": ili9xxx_ns.class_("WAVESHARERES35", ILI9XXXDisplay), + "CUSTOM": ILI9XXXDisplay, } COLOR_ORDERS = { @@ -80,14 +87,37 @@ COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") CONF_LED_PIN = "led_pin" CONF_COLOR_PALETTE_IMAGES = "color_palette_images" CONF_INVERT_DISPLAY = "invert_display" +CONF_PIXEL_MODE = "pixel_mode" +CONF_INIT_SEQUENCE = "init_sequence" + + +def cmd(c, *args): + """ + Create a command sequence + :param c: The command (8 bit) + :param args: zero or more arguments (8 bit values) + :return: a list with the command, the argument count and the arguments + """ + return [c, len(args)] + list(args) + + +def map_sequence(value): + """ + An initialisation sequence is a literal array of data bytes. + The format is a repeated sequence of [CMD, ] + """ + if len(value) == 0: + raise cv.Invalid("Empty sequence") + return cmd(*value) def _validate(config): - if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get( - CONF_COLOR_PALETTE_IMAGES + if ( + config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" + and CONF_COLOR_PALETTE_IMAGES not in config ): raise cv.Invalid( - "Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette" + "IMAGE_ADAPTIVE palette requires at least one 'color_palette_images' entry" ) if ( config.get(CONF_COLOR_PALETTE_IMAGES) @@ -96,7 +126,8 @@ def _validate(config): raise cv.Invalid( "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'" ) - if CORE.is_esp8266 and config.get(CONF_MODEL) not in [ + model = config[CONF_MODEL] + if CORE.is_esp8266 and model not in [ "M5STACK", "TFT_2.4", "TFT_2.4R", @@ -104,9 +135,12 @@ def _validate(config): "ILI9342", "ST7789V", ]: - raise cv.Invalid( - "Provided model can't run on ESP8266. Use an ESP32 with PSRAM onboard" - ) + raise cv.Invalid("Selected model can't run on ESP8266.") + + if model == "CUSTOM": + if CONF_INIT_SEQUENCE not in config or CONF_DIMENSIONS not in config: + raise cv.Invalid("CUSTOM model requires init_sequence and dimensions") + return config @@ -116,6 +150,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(ILI9XXXDisplay), cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True, space="_"), + cv.Optional(CONF_PIXEL_MODE): cv.enum(PIXEL_MODES), cv.Optional(CONF_DIMENSIONS): cv.Any( cv.dimensions, cv.Schema( @@ -150,6 +185,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, } ), + cv.Optional(CONF_INIT_SEQUENCE): cv.ensure_list(map_sequence), } ) .extend(cv.polling_component_schema("1s")) @@ -167,6 +203,14 @@ async def to_code(config): await spi.register_spi_device(var, config) dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) + if init_sequences := config.get(CONF_INIT_SEQUENCE): + sequence = [] + for seq in init_sequences: + sequence.extend(seq) + cg.add(var.add_init_sequence(sequence)) + + if pixel_mode := config.get(CONF_PIXEL_MODE): + cg.add(var.set_pixel_mode(pixel_mode)) if CONF_COLOR_ORDER in config: cg.add(var.set_color_order(COLOR_ORDERS[config[CONF_COLOR_ORDER]])) if CONF_TRANSFORM in config: diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index e292906a93..463e3dd851 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -34,7 +34,26 @@ void ILI9XXXDisplay::setup() { ESP_LOGD(TAG, "Setting up ILI9xxx"); this->setup_pins_(); - this->init_lcd_(); + this->init_lcd_(this->init_sequence_); + this->init_lcd_(this->extra_init_sequence_.data()); + switch (this->pixel_mode_) { + case PIXEL_MODE_16: + if (this->is_18bitdisplay_) { + this->command(ILI9XXX_PIXFMT); + this->data(0x55); + this->is_18bitdisplay_ = false; + } + break; + case PIXEL_MODE_18: + if (!this->is_18bitdisplay_) { + this->command(ILI9XXX_PIXFMT); + this->data(0x66); + this->is_18bitdisplay_ = true; + } + break; + default: + break; + } this->set_madctl(); this->command(this->pre_invertcolors_ ? ILI9XXX_INVON : ILI9XXX_INVOFF); @@ -203,7 +222,6 @@ void ILI9XXXDisplay::update() { } void ILI9XXXDisplay::display_() { - uint8_t transfer_buffer[ILI9XXX_TRANSFER_BUFFER_SIZE]; // check if something was displayed if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) { return; @@ -231,6 +249,7 @@ void ILI9XXXDisplay::display_() { this->write_array(this->buffer_ + this->y_low_ * this->width_ * 2, h * this->width_ * 2); } else { ESP_LOGV(TAG, "Doing multiple write"); + uint8_t transfer_buffer[ILI9XXX_TRANSFER_BUFFER_SIZE]; size_t rem = h * w; // remaining number of pixels to write set_addr_window_(this->x_low_, this->y_low_, this->x_high_, this->y_high_); size_t idx = 0; // index into transfer_buffer @@ -247,7 +266,7 @@ void ILI9XXXDisplay::display_() { display::ColorUtil::index8_to_color_palette888(this->buffer_[pos++], this->palette_)); break; default: // case BITS_16: - color_val = (buffer_[pos * 2] << 8) + buffer_[pos * 2 + 1]; + color_val = (this->buffer_[pos * 2] << 8) + this->buffer_[pos * 2 + 1]; pos++; break; } @@ -259,7 +278,7 @@ void ILI9XXXDisplay::display_() { put16_be(transfer_buffer + idx, color_val); idx += 2; } - if (idx == ILI9XXX_TRANSFER_BUFFER_SIZE) { + if (idx == sizeof(transfer_buffer)) { this->write_array(transfer_buffer, idx); idx = 0; App.feed_wdt(); @@ -293,20 +312,50 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons // if color mapping or software rotation is required, hand this off to the parent implementation. This will // do color conversion pixel-by-pixel into the buffer and draw it later. If this is happening the user has not // configured the renderer well. - if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian || - this->is_18bitdisplay_) { + if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian) { return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad); } this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1); // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. - if (x_offset == 0 && x_pad == 0 && y_offset == 0) { - // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother - this->write_array(ptr, w * h * 2); + auto stride = x_offset + w + x_pad; + if (!this->is_18bitdisplay_) { + if (x_offset == 0 && x_pad == 0 && y_offset == 0) { + // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother + this->write_array(ptr, w * h * 2); + } else { + for (size_t y = 0; y != h; y++) { + this->write_array(ptr + (y + y_offset) * stride + x_offset, w * 2); + } + } } else { - auto stride = x_offset + w + x_pad; - for (size_t y = 0; y != h; y++) { - this->write_array(ptr + (y + y_offset) * stride + x_offset, w * 2); + // 18 bit mode + uint8_t transfer_buffer[ILI9XXX_TRANSFER_BUFFER_SIZE * 4]; + ESP_LOGV(TAG, "Doing multiple write"); + size_t rem = h * w; // remaining number of pixels to write + size_t idx = 0; // index into transfer_buffer + size_t pixel = 0; // pixel number offset + ptr += (y_offset * stride + x_offset) * 2; + while (rem-- != 0) { + uint8_t hi_byte = *ptr++; + uint8_t lo_byte = *ptr++; + transfer_buffer[idx++] = hi_byte & 0xF8; // Blue + transfer_buffer[idx++] = ((hi_byte << 5) | (lo_byte) >> 5); // Green + transfer_buffer[idx++] = lo_byte << 3; // Red + if (idx == sizeof(transfer_buffer)) { + this->write_array(transfer_buffer, idx); + idx = 0; + App.feed_wdt(); + } + // end of line? Skip to the next. + if (++pixel == w) { + pixel = 0; + ptr += (x_pad + x_offset) * 2; + } + } + // flush any balance. + if (idx != 0) { + this->write_array(transfer_buffer, idx); } } this->end_data_(); @@ -356,10 +405,11 @@ void ILI9XXXDisplay::reset_() { } } -void ILI9XXXDisplay::init_lcd_() { +void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { + if (addr == nullptr) + return; uint8_t cmd, x, num_args; - const uint8_t *addr = this->init_sequence_; - while ((cmd = *addr++) > 0) { + while ((cmd = *addr++) != 0) { x = *addr++; num_args = x & 0x7F; this->send_command(cmd, addr, num_args); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 11a90e142f..4446686e7b 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -17,6 +17,12 @@ enum ILI9XXXColorMode { BITS_16 = 0x10, }; +enum PixelMode { + PIXEL_MODE_UNSPECIFIED, + PIXEL_MODE_16, + PIXEL_MODE_18, +}; + class ILI9XXXDisplay : public display::DisplayBuffer, public spi::SPIDevice { @@ -52,6 +58,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, } } + void add_init_sequence(const std::vector &sequence) { this->extra_init_sequence_ = sequence; } void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } @@ -73,6 +80,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, void set_swap_xy(bool swap_xy) { this->swap_xy_ = swap_xy; } void set_mirror_x(bool mirror_x) { this->mirror_x_ = mirror_x; } void set_mirror_y(bool mirror_y) { this->mirror_y_ = mirror_y; } + void set_pixel_mode(PixelMode mode) { this->pixel_mode_ = mode; } void update() override; @@ -99,11 +107,12 @@ class ILI9XXXDisplay : public display::DisplayBuffer, virtual void set_madctl(); void display_(); - void init_lcd_(); + void init_lcd_(const uint8_t *addr); void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2); void reset_(); uint8_t const *init_sequence_{}; + std::vector extra_init_sequence_; int16_t width_{0}; ///< Display width as modified by current rotation int16_t height_{0}; ///< Display height as modified by current rotation int16_t offset_x_{0}; @@ -112,7 +121,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, uint16_t y_low_{0}; uint16_t x_high_{0}; uint16_t y_high_{0}; - const uint8_t *palette_; + const uint8_t *palette_{}; ILI9XXXColorMode buffer_color_mode_{BITS_16}; @@ -133,6 +142,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, bool prossing_update_ = false; bool need_update_ = false; bool is_18bitdisplay_ = false; + PixelMode pixel_mode_{}; bool pre_invertcolors_ = false; display::ColorOrder color_order_{display::COLOR_ORDER_BGR}; bool swap_xy_{}; diff --git a/tests/components/ili9xxx/test.esp32-idf.yaml b/tests/components/ili9xxx/test.esp32-idf.yaml index 0d7bda8ac6..6da62f69d2 100644 --- a/tests/components/ili9xxx/test.esp32-idf.yaml +++ b/tests/components/ili9xxx/test.esp32-idf.yaml @@ -12,24 +12,12 @@ display: swap_xy: true mirror_x: true mirror_y: false - model: TFT 2.4 - color_palette: GRAYSCALE + model: custom cs_pin: 12 dc_pin: 13 reset_pin: 14 + init_sequence: + - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10] + lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ili9xxx - dimensions: - width: 320 - height: 240 - offset_width: 20 - offset_height: 10 - model: TFT 2.4 - cs_pin: 25 - dc_pin: 26 - reset_pin: 27 - auto_clear_enabled: false - rotation: 90 - lambda: |- - it.fill(Color::WHITE); From 9de67feccd4b4c3ec9f5db40573c07ecca4bcf32 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 21 May 2024 10:53:16 +1200 Subject: [PATCH 1783/2607] [remote_receiver] Add better error message for tolerance breaking change (#6784) --- esphome/components/remote_receiver/__init__.py | 8 +++++++- tests/components/remote_receiver/esp32-common.yaml | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 6fe20153f4..e5085bb33c 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -63,7 +63,13 @@ def validate_tolerance(value): if "%" in str(value): type_ = TYPE_PERCENTAGE else: - type_ = TYPE_TIME + try: + cv.positive_time_period_microseconds(value) + type_ = TYPE_TIME + except cv.Invalid as exc: + raise cv.Invalid( + "Tolerance must be a percentage or time. Configurations made before 2024.5.0 treated the value as a percentage." + ) from exc return TOLERANCE_SCHEMA( { diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index c2b5a2cf19..c3987f8cd9 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -3,6 +3,7 @@ remote_receiver: pin: ${pin} rmt_channel: ${rmt_channel} dump: all + tolerance: 25% on_abbwelcome: then: - logger.log: From ce6dc040dab9bef5230c86840f8da3edacb7b8cd Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Mon, 20 May 2024 22:54:38 +0000 Subject: [PATCH 1784/2607] Tiny fix in automation.h - unused return value removed (#6760) --- esphome/core/automation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index 9b62640a0c..5a0a17ea1a 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -233,7 +233,7 @@ template class Automation { public: explicit Automation(Trigger *trigger) : trigger_(trigger) { this->trigger_->set_automation_parent(this); } - Action *add_action(Action *action) { this->actions_.add_action(action); } + void add_action(Action *action) { this->actions_.add_action(action); } void add_actions(const std::vector *> &actions) { this->actions_.add_actions(actions); } void stop() { this->actions_.stop(); } From 525c4891d52f5c0d6bd5a79ba8c3400aa3e5d588 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Tue, 21 May 2024 10:55:56 +1200 Subject: [PATCH 1785/2607] Update webserver local assets to 20240519-215627 (#6779) --- .../components/web_server/server_index_v3.h | 7970 ++++++++--------- 1 file changed, 3977 insertions(+), 3993 deletions(-) diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 66cd9de47a..f2f278b08f 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -10,4004 +10,3988 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0x6d, 0x7b, 0xdb, 0xb6, 0xb2, 0x28, 0xfa, - 0xf9, 0x9e, 0x5f, 0x61, 0x73, 0xa7, 0x2e, 0x61, 0x41, 0xb4, 0x24, 0x5b, 0x8e, 0x43, 0x19, 0xd6, 0x71, 0x9c, 0xa4, - 0x49, 0x9b, 0x26, 0x69, 0x9c, 0x26, 0x4d, 0x54, 0x6d, 0x07, 0x22, 0x21, 0x09, 0x0d, 0x45, 0xa8, 0x04, 0x14, 0xdb, - 0x95, 0xf4, 0xdf, 0xef, 0x33, 0x78, 0x21, 0x41, 0x49, 0xc9, 0x5a, 0xeb, 0xdc, 0x73, 0xee, 0x73, 0x76, 0xf7, 0x8a, - 0x45, 0xbc, 0x63, 0x30, 0x18, 0xcc, 0x0c, 0x66, 0x06, 0xe7, 0xfb, 0xa9, 0x48, 0xd4, 0xfd, 0x9c, 0xed, 0x4d, 0xd5, - 0x2c, 0xbb, 0x38, 0xb7, 0xff, 0x32, 0x9a, 0x5e, 0x9c, 0x67, 0x3c, 0xff, 0xb2, 0x57, 0xb0, 0x8c, 0xf0, 0x44, 0xe4, - 0x7b, 0xd3, 0x82, 0x8d, 0x49, 0x4a, 0x15, 0x8d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xc5, 0xf9, 0x8c, 0x29, 0xba, - 0x97, 0x4c, 0x69, 0x21, 0x99, 0x22, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbb, 0x38, 0x97, 0x49, 0xc1, 0xe7, 0x6a, 0x0f, - 0x9a, 0x24, 0x33, 0x91, 0x2e, 0x32, 0x76, 0x71, 0x74, 0x74, 0x7b, 0x7b, 0x1b, 0xfd, 0x25, 0xff, 0xc7, 0x57, 0x5a, - 0xec, 0xfd, 0x52, 0x90, 0xd7, 0xa3, 0xbf, 0x58, 0xa2, 0xa2, 0x94, 0x8d, 0x79, 0xce, 0xde, 0x14, 0x62, 0xce, 0x0a, - 0x75, 0xdf, 0x83, 0xcc, 0x9f, 0x0a, 0x12, 0x72, 0xac, 0x30, 0x43, 0xe4, 0x42, 0xed, 0xf1, 0x7c, 0x8f, 0xf7, 0x7f, - 0x29, 0x74, 0xca, 0x92, 0xe5, 0x8b, 0x19, 0x2b, 0xe8, 0x28, 0x63, 0xf1, 0x7e, 0x0b, 0x27, 0x22, 0x1f, 0xf3, 0xc9, - 0xa2, 0xfc, 0xbe, 0x2d, 0xb8, 0x72, 0xbf, 0xbf, 0xd2, 0x6c, 0xc1, 0x62, 0xb6, 0x46, 0x31, 0x1f, 0xa8, 0x21, 0x61, - 0xba, 0xe5, 0x2f, 0x55, 0xc3, 0xe1, 0x4f, 0xba, 0xc9, 0xfb, 0x39, 0x13, 0xe3, 0x3d, 0xb5, 0x4f, 0x02, 0x79, 0x3f, - 0x1b, 0x89, 0x2c, 0xe8, 0xab, 0x46, 0x10, 0xc4, 0x50, 0x06, 0x33, 0xd4, 0x4b, 0x44, 0x2e, 0xd5, 0x9e, 0xe4, 0xe4, - 0x96, 0xe7, 0xa9, 0xb8, 0xc5, 0x5f, 0x25, 0x91, 0x3c, 0xba, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x1d, 0x1c, - 0x84, 0xf6, 0xfb, 0xfe, 0xea, 0xfa, 0x9a, 0x10, 0xf2, 0x55, 0xf0, 0x74, 0xaf, 0xb5, 0x5a, 0x79, 0xa9, 0x51, 0x4e, - 0x15, 0xff, 0xca, 0x4c, 0x25, 0x74, 0x70, 0x10, 0xd0, 0x54, 0xcc, 0x15, 0x4b, 0xaf, 0xd5, 0x7d, 0xc6, 0xae, 0xa7, - 0x8c, 0x29, 0x19, 0xf0, 0x7c, 0xef, 0x89, 0x48, 0x16, 0x33, 0x96, 0xab, 0x68, 0x5e, 0x08, 0x25, 0x60, 0x60, 0x07, - 0x07, 0x41, 0xc1, 0xe6, 0x19, 0x4d, 0x18, 0xe4, 0x5f, 0x5d, 0x5f, 0x57, 0x35, 0xaa, 0x42, 0xf8, 0x56, 0x92, 0x6b, - 0x3d, 0xf4, 0x10, 0xe1, 0xe7, 0x92, 0xe4, 0xec, 0x76, 0xef, 0x03, 0xa3, 0x5f, 0x7e, 0xa5, 0xf3, 0x5e, 0x92, 0x51, - 0x29, 0xf7, 0x9e, 0x89, 0xa5, 0x9e, 0x46, 0xb1, 0x48, 0x94, 0x28, 0x42, 0x85, 0x19, 0x96, 0x68, 0xc9, 0xc7, 0xa1, - 0x9a, 0x72, 0x19, 0xdd, 0x3c, 0x48, 0xa4, 0x7c, 0xcb, 0xe4, 0x22, 0x53, 0x0f, 0xc8, 0x7e, 0x0b, 0xcb, 0x7d, 0x42, - 0x6e, 0x25, 0x52, 0xd3, 0x42, 0xdc, 0xee, 0x3d, 0x2d, 0x0a, 0x51, 0x84, 0xc1, 0xd5, 0xf5, 0xb5, 0x29, 0xb1, 0xc7, - 0xe5, 0x5e, 0x2e, 0xd4, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xda, 0xfb, 0x5d, 0xb2, 0xbd, 0xcf, 0x8b, 0x5c, 0xd2, 0x31, - 0xbb, 0xba, 0xbe, 0xfe, 0xbc, 0x27, 0x8a, 0xbd, 0xcf, 0x89, 0x94, 0x9f, 0xf7, 0x78, 0x2e, 0x15, 0xa3, 0x69, 0x14, - 0xa0, 0x9e, 0xee, 0x2c, 0x91, 0xf2, 0x1d, 0xbb, 0x53, 0x44, 0x61, 0xfd, 0xa9, 0x08, 0x5b, 0x4f, 0x98, 0xda, 0x93, - 0xe5, 0xbc, 0x42, 0xb4, 0xcc, 0x98, 0xda, 0x53, 0x44, 0xe7, 0x0b, 0x0b, 0x7f, 0x66, 0x3e, 0x55, 0x8f, 0x8f, 0xc3, - 0xaf, 0xf2, 0xe0, 0x40, 0x95, 0x80, 0x46, 0x4b, 0xbb, 0x42, 0x84, 0xed, 0xbb, 0xb4, 0x83, 0x03, 0x16, 0x65, 0x2c, - 0x9f, 0xa8, 0x29, 0x21, 0xa4, 0xdd, 0x93, 0x07, 0x07, 0xa1, 0x22, 0xcf, 0x65, 0x34, 0x61, 0x2a, 0x64, 0x08, 0xe1, - 0xaa, 0xf6, 0xc1, 0x41, 0x68, 0x80, 0x20, 0x88, 0xd2, 0x80, 0xab, 0xc1, 0x18, 0x45, 0x16, 0xfa, 0xd7, 0xf7, 0x79, - 0x12, 0xfa, 0xe3, 0x47, 0x58, 0x1e, 0x1c, 0x3c, 0x97, 0x91, 0x84, 0x16, 0xb1, 0x42, 0x68, 0x5d, 0x30, 0xb5, 0x28, - 0xf2, 0x3d, 0xb5, 0x56, 0xe2, 0x5a, 0x15, 0x3c, 0x9f, 0x84, 0x68, 0xe9, 0xd2, 0xbc, 0x8a, 0xeb, 0xb5, 0x19, 0xee, - 0x6f, 0x05, 0xe1, 0xe4, 0x02, 0x7a, 0x7c, 0x26, 0x42, 0x8b, 0x83, 0x9c, 0x90, 0x40, 0xea, 0xba, 0x41, 0x9f, 0xc7, - 0xbc, 0x11, 0x04, 0xd8, 0x8c, 0x12, 0xdf, 0x4a, 0x84, 0xb9, 0x02, 0xd4, 0x8d, 0xa2, 0x48, 0x21, 0x72, 0xb1, 0x74, - 0x60, 0xe1, 0xde, 0x44, 0xfb, 0x7c, 0xd0, 0x1a, 0xc6, 0x2a, 0x2a, 0x58, 0xba, 0x48, 0x58, 0x18, 0x4a, 0x9c, 0x63, - 0x81, 0xc8, 0x85, 0x6c, 0x84, 0x05, 0xb9, 0x80, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xd9, 0x41, 0x16, - 0x6e, 0x84, 0x00, 0x62, 0x3b, 0xa0, 0x82, 0x90, 0x20, 0x5f, 0xcc, 0x46, 0xac, 0x08, 0xca, 0x62, 0xbd, 0x1a, 0x5e, - 0x2c, 0x24, 0xdb, 0x4b, 0xa4, 0xdc, 0x1b, 0x2f, 0xf2, 0x44, 0x71, 0x91, 0xef, 0x05, 0x8d, 0xa2, 0x11, 0x18, 0x7c, - 0x28, 0xd1, 0x21, 0x40, 0x6b, 0x14, 0xe6, 0xa8, 0xc1, 0x07, 0xa2, 0xd1, 0x1e, 0x62, 0x18, 0x25, 0xea, 0xd9, 0xf6, - 0x2c, 0x04, 0x18, 0xe6, 0x30, 0xc9, 0x35, 0xfe, 0x64, 0x76, 0x3e, 0x4c, 0xf1, 0xab, 0xec, 0xf3, 0x68, 0x7b, 0xa7, - 0x10, 0x15, 0xcd, 0xe8, 0x3c, 0x64, 0xe4, 0x82, 0x69, 0xec, 0xa2, 0x79, 0x02, 0x63, 0xad, 0x2d, 0x5c, 0x9f, 0xc5, - 0x2c, 0xaa, 0x70, 0x0a, 0xc5, 0x2a, 0x1a, 0x8b, 0xe2, 0x29, 0x4d, 0xa6, 0x50, 0xaf, 0xc4, 0x98, 0xd4, 0x6d, 0xb8, - 0xa4, 0x60, 0x54, 0xb1, 0xa7, 0x19, 0x83, 0xaf, 0x30, 0xd0, 0x35, 0x03, 0x84, 0x73, 0xd8, 0xea, 0x19, 0x57, 0xaf, - 0x44, 0x9e, 0xb0, 0x5e, 0xee, 0xe1, 0x97, 0x5e, 0xf9, 0x4b, 0xa5, 0x0a, 0x3e, 0x5a, 0x28, 0x16, 0x06, 0x39, 0x94, - 0x08, 0x70, 0x8e, 0xb0, 0x8c, 0x14, 0xbb, 0x53, 0x57, 0x22, 0x57, 0x2c, 0x57, 0x84, 0x39, 0xa8, 0x62, 0x1e, 0xd1, - 0xf9, 0x9c, 0xe5, 0xe9, 0xd5, 0x94, 0x67, 0x69, 0x28, 0xd1, 0x1a, 0xad, 0xf1, 0x07, 0x49, 0x60, 0x92, 0xe4, 0x82, - 0xc7, 0xf0, 0xcf, 0xb7, 0xa7, 0x13, 0x2a, 0x72, 0xa1, 0xb7, 0x05, 0x23, 0x41, 0xd0, 0x1b, 0x8b, 0x22, 0xb4, 0x53, - 0xd8, 0x03, 0xd2, 0x05, 0x7d, 0xbc, 0x5d, 0x64, 0x4c, 0x22, 0xd6, 0x20, 0x25, 0xa6, 0x39, 0x08, 0xff, 0x56, 0x84, - 0x0c, 0x16, 0x80, 0xa3, 0x98, 0x6b, 0x12, 0xf8, 0x92, 0xdb, 0x4d, 0x95, 0x96, 0x44, 0xed, 0x77, 0x49, 0x52, 0x1e, - 0xa9, 0x62, 0x21, 0x15, 0x4b, 0xdf, 0xdd, 0xcf, 0x99, 0xc4, 0x3f, 0x17, 0xe4, 0x77, 0xd9, 0xff, 0x5d, 0x46, 0x6c, - 0x36, 0x57, 0xf7, 0xd7, 0x9a, 0x9a, 0xc7, 0x41, 0x80, 0x3f, 0xea, 0xa2, 0x05, 0xa3, 0x09, 0x90, 0x34, 0x0b, 0xb2, - 0x37, 0x22, 0xbb, 0x1f, 0xf3, 0x2c, 0xbb, 0x5e, 0xcc, 0xe7, 0xa2, 0x50, 0x58, 0x49, 0xb2, 0x54, 0xa2, 0x82, 0x0f, - 0xac, 0xe8, 0x52, 0xde, 0x72, 0x95, 0x4c, 0x43, 0x85, 0x96, 0x09, 0x95, 0x6c, 0xef, 0xb1, 0x10, 0x19, 0xa3, 0x79, - 0xcc, 0x09, 0xef, 0xff, 0x5c, 0xc4, 0xf9, 0x22, 0xcb, 0x7a, 0xa3, 0x82, 0xd1, 0x2f, 0x3d, 0x9d, 0x6d, 0x0e, 0x87, - 0x58, 0xff, 0xbe, 0x2c, 0x0a, 0x7a, 0x0f, 0x05, 0x09, 0x81, 0x62, 0x7d, 0x1e, 0xff, 0x7c, 0xfd, 0xfa, 0x55, 0x64, - 0xf6, 0x0a, 0x1f, 0xdf, 0x87, 0xbc, 0xdc, 0x7f, 0x7c, 0x8d, 0xc7, 0x85, 0x98, 0x6d, 0x74, 0x6d, 0x40, 0xc7, 0x7b, - 0xdf, 0x18, 0x02, 0x23, 0x7c, 0xdf, 0x34, 0xed, 0x8f, 0xe0, 0x95, 0xc6, 0x7c, 0xc8, 0x24, 0xb6, 0x5f, 0xf8, 0x27, - 0x36, 0xc9, 0x21, 0x47, 0xdf, 0x1f, 0xad, 0x2a, 0xee, 0x97, 0x8c, 0xe8, 0x71, 0xce, 0xe1, 0x60, 0x84, 0x31, 0x26, - 0x54, 0x25, 0xd3, 0x25, 0xd3, 0x8d, 0xad, 0xdd, 0x88, 0xd9, 0x7a, 0x8d, 0x5f, 0x09, 0x87, 0xf5, 0x6a, 0x9f, 0x10, - 0xae, 0xe9, 0x15, 0x51, 0xab, 0x15, 0x27, 0x84, 0x23, 0xfc, 0x96, 0x93, 0x25, 0x75, 0x13, 0x82, 0x93, 0x0d, 0xb6, - 0x67, 0x6c, 0xa8, 0x0c, 0x9c, 0x80, 0x5f, 0x59, 0xa1, 0x58, 0x11, 0x2b, 0x89, 0x0b, 0x36, 0xce, 0x60, 0x1c, 0xfb, - 0x6d, 0x3c, 0xa5, 0xf2, 0x6a, 0x4a, 0xf3, 0x09, 0x4b, 0xe3, 0x57, 0x62, 0x8d, 0x99, 0x24, 0xc1, 0x98, 0xe7, 0x34, - 0xe3, 0xff, 0xb0, 0x34, 0xb0, 0xe7, 0xc2, 0x63, 0xb5, 0xc7, 0xee, 0x14, 0xcb, 0x53, 0xb9, 0xf7, 0xfc, 0xdd, 0xaf, - 0x2f, 0xed, 0x62, 0xd6, 0xce, 0x0a, 0xb4, 0x94, 0x8b, 0x39, 0x2b, 0x42, 0x84, 0xed, 0x59, 0xf1, 0x94, 0x6b, 0x3a, - 0xf9, 0x2b, 0x9d, 0x9b, 0x14, 0x2e, 0x7f, 0x9f, 0xa7, 0x54, 0xb1, 0x37, 0x2c, 0x4f, 0x79, 0x3e, 0x21, 0xfb, 0x6d, - 0x93, 0x3e, 0xa5, 0x36, 0x23, 0x2d, 0x93, 0x6e, 0x1e, 0x3c, 0xcd, 0xf4, 0xdc, 0xcb, 0xcf, 0x45, 0x88, 0xd6, 0x52, - 0x51, 0xc5, 0x93, 0x3d, 0x9a, 0xa6, 0x2f, 0x72, 0xae, 0xb8, 0x1e, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xcc, 0xa9, - 0xe1, 0x46, 0x1e, 0x22, 0x1c, 0x86, 0xf6, 0x2c, 0x98, 0x22, 0xbb, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb3, 0xd8, - 0x64, 0x92, 0xc1, 0x10, 0x45, 0xf3, 0x85, 0x84, 0xc5, 0x76, 0x5d, 0xc0, 0x41, 0x23, 0x46, 0x92, 0x15, 0x5f, 0x59, - 0x5a, 0x22, 0x88, 0x0c, 0xd1, 0x72, 0xa3, 0x0f, 0xbb, 0x3d, 0x14, 0x19, 0x0c, 0x7b, 0x3e, 0x09, 0x67, 0x16, 0xd9, - 0x0d, 0xa7, 0xc2, 0x99, 0x2c, 0x89, 0x4a, 0x08, 0x07, 0x6a, 0x49, 0x58, 0x72, 0xe2, 0xe6, 0x37, 0x0f, 0x25, 0xf0, - 0x10, 0x3e, 0xe5, 0x70, 0x67, 0xee, 0xd3, 0xaf, 0xfa, 0xf0, 0xc8, 0xb1, 0x44, 0x58, 0x99, 0x91, 0xe6, 0x08, 0xad, - 0x11, 0x56, 0x6e, 0xb8, 0x86, 0x28, 0x39, 0xbe, 0x08, 0x4e, 0x6d, 0xf2, 0x96, 0xeb, 0x63, 0x1b, 0x68, 0x1b, 0x55, - 0xec, 0xe0, 0x20, 0x64, 0x51, 0x89, 0x18, 0x64, 0xbf, 0x6d, 0x17, 0xc9, 0x83, 0xd6, 0x37, 0xc6, 0x0d, 0x3d, 0x6b, - 0x06, 0x67, 0x9f, 0x45, 0xb9, 0xb8, 0x4c, 0x12, 0x26, 0xa5, 0x28, 0x0e, 0x0e, 0xf6, 0x75, 0xf9, 0x92, 0xb3, 0x80, - 0x45, 0x7c, 0x7d, 0x9b, 0x57, 0x43, 0x40, 0xd5, 0x69, 0xeb, 0xf8, 0x26, 0x52, 0xf1, 0x4d, 0x8e, 0x09, 0x89, 0x83, - 0x9b, 0x9b, 0xa0, 0xa1, 0xb0, 0x85, 0xc3, 0x84, 0xb9, 0xae, 0xef, 0x9f, 0x30, 0xc3, 0x16, 0x6a, 0x26, 0x64, 0x0b, - 0x34, 0x3b, 0xf9, 0xc1, 0xb0, 0x3e, 0x24, 0xac, 0x70, 0x8e, 0xd6, 0xde, 0x8a, 0xee, 0x6c, 0x5a, 0xf3, 0x37, 0x66, - 0xe9, 0x96, 0x13, 0xcd, 0x53, 0x78, 0xeb, 0x38, 0x60, 0xc3, 0x35, 0xd6, 0xb0, 0x77, 0xb3, 0x11, 0x7a, 0xa0, 0x03, - 0x35, 0xec, 0xd9, 0x7c, 0x92, 0x1b, 0xc8, 0x15, 0xec, 0xef, 0x05, 0x93, 0xca, 0x20, 0x72, 0xa8, 0xb0, 0xc0, 0x70, - 0x46, 0x6d, 0x32, 0x9d, 0x35, 0x96, 0x74, 0xd7, 0xd8, 0x5e, 0xcf, 0xe1, 0x6c, 0x94, 0x80, 0xd4, 0xdf, 0xc7, 0x27, - 0x18, 0xab, 0x42, 0xab, 0xd5, 0x5b, 0xee, 0x5a, 0xa9, 0xd6, 0xb2, 0xe4, 0xd7, 0x36, 0x16, 0x85, 0x49, 0x64, 0x0f, - 0xe7, 0xfd, 0xb6, 0x1d, 0xbf, 0x1c, 0x92, 0xfd, 0x56, 0x89, 0xc5, 0x16, 0xac, 0x66, 0x3c, 0x06, 0x8a, 0xaf, 0x4d, - 0x53, 0x48, 0x9f, 0xf5, 0x35, 0x7c, 0x89, 0xa6, 0x5b, 0xb8, 0x3a, 0x25, 0x03, 0xe0, 0x3a, 0xa2, 0xe9, 0xf0, 0x5b, - 0xf8, 0xe4, 0x28, 0x42, 0xa8, 0xb6, 0xf3, 0x2a, 0xc2, 0xf1, 0xb5, 0x4e, 0x38, 0x36, 0xa6, 0x11, 0xcc, 0xcb, 0x2a, - 0x41, 0x89, 0x66, 0x76, 0xab, 0x57, 0x59, 0x58, 0xea, 0xc1, 0x54, 0x53, 0xf2, 0x9a, 0x78, 0x45, 0x67, 0x4c, 0x86, - 0x0c, 0xe1, 0x6f, 0x15, 0x30, 0xf8, 0x09, 0x45, 0x86, 0xde, 0x19, 0x9a, 0xc3, 0x19, 0x0a, 0xec, 0x2e, 0x30, 0x69, - 0xf5, 0x2d, 0x97, 0x63, 0x36, 0xc8, 0x87, 0x15, 0x6f, 0xe7, 0x4d, 0x5e, 0x1f, 0xce, 0x92, 0xd4, 0xf6, 0x9b, 0x49, - 0x33, 0x40, 0xd3, 0x2c, 0x84, 0x44, 0x78, 0xbf, 0xb5, 0xb9, 0x92, 0xae, 0x54, 0x35, 0xc7, 0xc1, 0x10, 0xd6, 0x41, - 0x1f, 0x1b, 0x11, 0x97, 0xfa, 0x6f, 0x6d, 0xab, 0x01, 0xd8, 0xae, 0x01, 0x33, 0xa2, 0x71, 0x46, 0x55, 0xd8, 0x3e, - 0x6a, 0x01, 0x63, 0xfa, 0x95, 0xc1, 0xa9, 0x82, 0xd0, 0xf6, 0x54, 0x58, 0xb4, 0xc8, 0xe5, 0x94, 0x8f, 0x55, 0xf8, - 0x41, 0x6a, 0xa2, 0xc2, 0x32, 0xc9, 0x40, 0xc2, 0xf1, 0xd8, 0x63, 0x4d, 0x70, 0x3e, 0xc0, 0x30, 0x4a, 0x56, 0x8c, - 0xb9, 0x91, 0x6a, 0xc2, 0x05, 0xe4, 0xa1, 0x62, 0xad, 0x2b, 0x32, 0xe3, 0x4a, 0x4b, 0xe0, 0x1e, 0xdb, 0x7d, 0xd3, - 0x62, 0x6c, 0xa9, 0x81, 0xf4, 0x38, 0x58, 0x19, 0xfb, 0x24, 0xc2, 0x26, 0xaa, 0x48, 0x89, 0x97, 0xe2, 0x96, 0x15, - 0x57, 0x14, 0x06, 0x1f, 0x9b, 0xea, 0x6b, 0x73, 0x14, 0x68, 0x8a, 0xaf, 0x7a, 0x0e, 0x5f, 0x6e, 0xf4, 0xc4, 0xdf, - 0x14, 0x62, 0xc6, 0x25, 0x03, 0xbe, 0xcd, 0xc0, 0x3f, 0x87, 0x8d, 0xa6, 0x77, 0x24, 0x1c, 0x37, 0xac, 0xc4, 0xaf, - 0xcb, 0x97, 0x75, 0xfc, 0xba, 0x79, 0xf0, 0x74, 0xe2, 0x28, 0x60, 0x7d, 0x1f, 0x23, 0x1c, 0x5a, 0xf1, 0xc2, 0x3b, - 0xe9, 0xa2, 0x29, 0xb2, 0xc7, 0xfc, 0x6a, 0xa5, 0x3c, 0x31, 0xae, 0xc6, 0x39, 0x32, 0xb3, 0x6d, 0xd0, 0x9a, 0xa6, - 0x29, 0xb0, 0x78, 0x85, 0xc8, 0x32, 0xef, 0xb0, 0xc2, 0xb2, 0x57, 0x1e, 0x4f, 0x37, 0x0f, 0x9e, 0x5e, 0x7f, 0xef, - 0x84, 0x82, 0x7c, 0xff, 0x90, 0x72, 0x03, 0xcd, 0x53, 0x56, 0x80, 0x5c, 0xe9, 0xad, 0x96, 0x3d, 0x67, 0xaf, 0x44, - 0x9e, 0xb3, 0x44, 0xb1, 0x14, 0x84, 0x16, 0x60, 0x83, 0xa7, 0x42, 0xaa, 0x32, 0xb1, 0x1a, 0xbd, 0xf4, 0x85, 0xd0, - 0x28, 0xa1, 0x59, 0x16, 0x1a, 0x01, 0x65, 0x26, 0xbe, 0xb2, 0x1d, 0xa3, 0xee, 0xd5, 0x86, 0x5c, 0x36, 0xc3, 0xbc, - 0x66, 0x58, 0x24, 0xe7, 0x19, 0x4f, 0x58, 0x79, 0x78, 0x5d, 0x47, 0x3c, 0x4f, 0xd9, 0x1d, 0xd0, 0x11, 0x74, 0x71, - 0x71, 0xd1, 0xc2, 0x6d, 0xb4, 0x36, 0x00, 0x5f, 0x6e, 0x01, 0xf6, 0x3b, 0xc7, 0xa6, 0x11, 0xc4, 0x97, 0x3b, 0xc9, - 0x1a, 0xf2, 0xce, 0x4a, 0xee, 0x04, 0x2d, 0x43, 0x9e, 0x11, 0x4e, 0x59, 0xc6, 0x14, 0x73, 0xe4, 0x1c, 0x98, 0x69, - 0xb3, 0x75, 0xdf, 0x96, 0xf0, 0x2b, 0xd1, 0xc9, 0xed, 0x32, 0xb7, 0xe6, 0xb2, 0x14, 0xdd, 0xab, 0xe5, 0xa9, 0xa0, - 0xdd, 0x57, 0x66, 0x79, 0xa8, 0x52, 0x34, 0x99, 0x1a, 0x89, 0x3d, 0xdc, 0x9a, 0x52, 0xd5, 0x86, 0x25, 0xed, 0xe5, - 0x26, 0xfa, 0x54, 0xd8, 0x61, 0xee, 0x02, 0xc1, 0xb5, 0x25, 0x0a, 0x0c, 0x84, 0x40, 0xb3, 0x6c, 0x57, 0x34, 0xcb, - 0x46, 0x34, 0xf9, 0x52, 0xc7, 0xfe, 0x0a, 0x0d, 0xc8, 0x26, 0x35, 0xf6, 0xb2, 0x3c, 0x92, 0xe5, 0xcf, 0xdb, 0x51, - 0xe9, 0xda, 0x46, 0x09, 0xf7, 0x5b, 0x15, 0xda, 0xd7, 0x17, 0xfa, 0x9b, 0xd8, 0xae, 0x47, 0x24, 0xed, 0xcc, 0x42, - 0xa0, 0x02, 0xff, 0x12, 0xe3, 0x1c, 0x3d, 0xb0, 0x78, 0x07, 0x82, 0xc7, 0x7a, 0x63, 0x20, 0x0a, 0x2d, 0xd7, 0x29, - 0x97, 0xdf, 0x86, 0xc0, 0xff, 0x96, 0x51, 0x3e, 0xf1, 0x7a, 0xf8, 0x77, 0x07, 0x5a, 0xd2, 0x38, 0xcb, 0x38, 0x97, - 0x23, 0xb3, 0x0c, 0x85, 0x23, 0x34, 0xbf, 0x00, 0xf3, 0xa2, 0xf1, 0xfd, 0xb5, 0xc9, 0xd2, 0x7c, 0x19, 0x0c, 0x23, - 0xef, 0xf9, 0x0c, 0x45, 0x0d, 0x05, 0x2c, 0x51, 0x35, 0x67, 0xae, 0xa8, 0x89, 0x92, 0x96, 0x6b, 0x37, 0xe2, 0xb8, - 0xa5, 0xb9, 0x05, 0x09, 0xc3, 0x30, 0x27, 0xba, 0x0d, 0xc3, 0xdf, 0x57, 0xb3, 0xc8, 0xb7, 0x66, 0x91, 0x47, 0x9e, - 0xb4, 0x85, 0x2a, 0x64, 0xf6, 0xaa, 0xc7, 0x4a, 0x22, 0xbf, 0x14, 0xb0, 0xac, 0x11, 0x50, 0x68, 0x54, 0x12, 0xdc, - 0x8c, 0x28, 0x5c, 0x58, 0x51, 0xc7, 0xe2, 0x1a, 0x90, 0x8c, 0xaa, 0x8a, 0x40, 0x66, 0x73, 0xd4, 0x64, 0x5f, 0x81, - 0x0b, 0xb4, 0xc1, 0xdf, 0xaf, 0xd7, 0x16, 0x4a, 0x0c, 0xd9, 0xd5, 0xa9, 0x31, 0xc6, 0x1e, 0x58, 0xb0, 0x20, 0xb9, - 0x61, 0x86, 0x0d, 0xeb, 0xb3, 0x09, 0x9c, 0xb2, 0xdd, 0x7d, 0x42, 0x44, 0x05, 0x9b, 0x3c, 0xda, 0xc1, 0x5d, 0x09, - 0x84, 0xa9, 0x63, 0x4b, 0x8b, 0x6a, 0xe2, 0x84, 0x04, 0x4e, 0x3b, 0x11, 0xf4, 0x97, 0x35, 0xe1, 0x30, 0xf6, 0x8a, - 0xad, 0x63, 0x20, 0xaa, 0xc5, 0x2e, 0x78, 0xef, 0xc2, 0x9a, 0x5a, 0x3b, 0x1e, 0xc4, 0x8b, 0x1a, 0xc4, 0x3d, 0xd0, - 0x0a, 0x43, 0xbc, 0xc4, 0x90, 0xd0, 0x7a, 0xe5, 0x90, 0xe1, 0xc2, 0x2c, 0xc4, 0x16, 0x14, 0x37, 0xd9, 0x4f, 0x8d, - 0x85, 0x20, 0xcb, 0xe6, 0xc0, 0xdf, 0xf9, 0x47, 0x44, 0x08, 0x83, 0x97, 0xab, 0xd5, 0x16, 0xda, 0xed, 0xe4, 0x42, - 0x51, 0x54, 0x49, 0x87, 0xab, 0xd5, 0x2b, 0x81, 0x42, 0xcb, 0xff, 0x62, 0x86, 0xfa, 0x8e, 0xe8, 0x5e, 0xbe, 0x84, - 0x52, 0x9a, 0x1d, 0xad, 0x52, 0x4a, 0xc1, 0xa1, 0x8e, 0xb5, 0xf5, 0x85, 0x52, 0x1e, 0xe5, 0xbe, 0xda, 0x22, 0x60, - 0x3a, 0xd1, 0x9e, 0xd4, 0xd5, 0x94, 0xaf, 0x6c, 0xd3, 0x12, 0x21, 0x14, 0xe7, 0x5a, 0x96, 0xd9, 0xdf, 0x25, 0x5f, - 0x1e, 0x1c, 0xe4, 0x5e, 0x43, 0x37, 0x25, 0xa5, 0xf8, 0x2b, 0x84, 0x53, 0x59, 0xde, 0xe7, 0x9a, 0x7d, 0xf9, 0xcb, - 0x9d, 0x43, 0x5b, 0xd2, 0x69, 0xab, 0x07, 0x82, 0x39, 0xbd, 0xa5, 0x5c, 0xed, 0x95, 0xad, 0x18, 0xc1, 0x3c, 0x64, - 0x68, 0x69, 0xb9, 0x8d, 0xa8, 0x60, 0xc0, 0x3f, 0x02, 0x59, 0x70, 0x5c, 0xb4, 0x41, 0xfc, 0x64, 0xca, 0x40, 0x95, - 0xed, 0x18, 0x89, 0x52, 0x3c, 0xdc, 0xb7, 0x07, 0x89, 0x6d, 0x78, 0xf7, 0xd8, 0xd7, 0x9b, 0xd5, 0x6b, 0xd2, 0xc0, - 0x9c, 0x15, 0x63, 0x51, 0xcc, 0x5c, 0xde, 0x7a, 0xe3, 0xdb, 0x12, 0x47, 0x3e, 0x0e, 0x77, 0xb6, 0x6d, 0x45, 0x80, - 0xde, 0x86, 0xec, 0x5d, 0x49, 0xed, 0xb5, 0xd3, 0xb4, 0x3c, 0x80, 0x8d, 0x82, 0xd0, 0x61, 0x66, 0xee, 0x4b, 0xf9, - 0x56, 0xbd, 0xda, 0x33, 0xba, 0x93, 0xfd, 0x76, 0xaf, 0x94, 0xfc, 0x1c, 0x36, 0xf4, 0x8c, 0x8e, 0xc3, 0x9e, 0xaa, - 0x62, 0x91, 0xa5, 0x76, 0xb0, 0x70, 0xc4, 0x59, 0x3c, 0xba, 0xe5, 0x59, 0x56, 0xa5, 0xfe, 0x27, 0xa4, 0x3d, 0xb7, - 0xa4, 0x5d, 0x38, 0xd2, 0x0e, 0xa4, 0x02, 0x48, 0xbb, 0x69, 0xae, 0xaa, 0x2e, 0xb6, 0xb6, 0xa7, 0x30, 0x44, 0x3d, - 0xd7, 0xe2, 0x34, 0xf4, 0xb7, 0x70, 0x23, 0x40, 0x25, 0xf3, 0xf5, 0x25, 0xb4, 0xfa, 0x18, 0x10, 0x03, 0x8d, 0x4e, - 0x93, 0xf9, 0x9a, 0x8a, 0x2f, 0x21, 0xc2, 0xf9, 0x9a, 0x95, 0x98, 0x7d, 0xf9, 0x14, 0x94, 0x76, 0xde, 0x74, 0xe0, - 0x1c, 0xd3, 0xc9, 0xff, 0x11, 0x1f, 0xe5, 0x66, 0x27, 0xed, 0xec, 0x72, 0x37, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0xd2, - 0xef, 0x53, 0x7b, 0x3d, 0x3d, 0x59, 0x4e, 0xaf, 0x5a, 0xef, 0xd5, 0x2a, 0xdc, 0x48, 0x01, 0x8d, 0xbe, 0x95, 0x52, - 0x8a, 0xb2, 0x75, 0xa0, 0x01, 0x3e, 0x64, 0x20, 0x61, 0x6d, 0x26, 0x5d, 0x9e, 0x72, 0x2f, 0xff, 0x95, 0x9e, 0x47, - 0x2b, 0xee, 0x4d, 0xfd, 0x2b, 0x31, 0x9b, 0x03, 0x43, 0xb6, 0x81, 0xd2, 0x13, 0x66, 0x3b, 0xac, 0xf2, 0xd7, 0x3b, - 0xd2, 0x6a, 0x75, 0xf4, 0x7e, 0xac, 0x61, 0x53, 0x29, 0x35, 0xef, 0xb7, 0xd6, 0x8b, 0x32, 0xa9, 0x24, 0x1c, 0xbb, - 0x74, 0x2b, 0x57, 0x9b, 0x9a, 0x19, 0x97, 0xf1, 0x3a, 0x94, 0x86, 0x0e, 0x4b, 0xa0, 0x75, 0x1e, 0xf9, 0x71, 0xe8, - 0xee, 0xaf, 0xff, 0xba, 0x02, 0xce, 0x72, 0xbd, 0x01, 0xbe, 0xe5, 0x7a, 0xfd, 0x58, 0x59, 0x49, 0x1b, 0x3f, 0xde, - 0x21, 0xf7, 0x96, 0xd0, 0xab, 0x32, 0xad, 0xcc, 0x38, 0x18, 0x42, 0xda, 0x16, 0x0b, 0x49, 0x96, 0x33, 0x91, 0xb2, - 0x38, 0x10, 0x73, 0x96, 0x07, 0x6b, 0xd0, 0xb3, 0x5a, 0x04, 0xf8, 0x28, 0xc3, 0xe5, 0xdb, 0xba, 0xbe, 0x35, 0x7e, - 0xac, 0xd6, 0xa0, 0x0a, 0x7b, 0xc9, 0x77, 0x28, 0x63, 0xdf, 0xb3, 0x42, 0x6a, 0x9e, 0xb4, 0x64, 0x6f, 0x5f, 0xf2, - 0xea, 0x80, 0x7a, 0xc9, 0xe3, 0x6f, 0x57, 0xa9, 0x04, 0x92, 0xa0, 0x1d, 0x9d, 0x46, 0xc7, 0x01, 0xd2, 0x1a, 0xe3, - 0x67, 0x4e, 0x63, 0xbc, 0x28, 0x35, 0xc6, 0xcf, 0x15, 0x59, 0x6c, 0x68, 0x8c, 0xff, 0x96, 0xe4, 0xb9, 0xea, 0x3f, - 0x77, 0xda, 0xf4, 0x37, 0x22, 0xe3, 0xc9, 0x7d, 0x18, 0x64, 0x5c, 0x35, 0xe1, 0x36, 0x31, 0xc0, 0x4b, 0x93, 0x01, - 0xaa, 0x46, 0xad, 0xef, 0x5e, 0x3b, 0xf9, 0x0f, 0x73, 0x49, 0x82, 0x07, 0x19, 0x57, 0x0f, 0x02, 0x3c, 0x55, 0xe4, - 0x33, 0xfc, 0x7a, 0xb0, 0x0c, 0x7f, 0xa5, 0x6a, 0x1a, 0x15, 0x34, 0x4f, 0xc5, 0x2c, 0x44, 0x8d, 0x20, 0x40, 0x91, - 0xd4, 0x42, 0xc8, 0x23, 0xb4, 0x7e, 0xf0, 0x19, 0xff, 0x23, 0x48, 0xd0, 0x0f, 0x1a, 0x53, 0x85, 0x15, 0x25, 0x9f, - 0xcf, 0x1f, 0x2c, 0xff, 0x11, 0xeb, 0x8b, 0xcf, 0xf8, 0xa9, 0x2a, 0xd5, 0xfa, 0xf8, 0x8e, 0x91, 0x10, 0x91, 0x8b, - 0xa7, 0x6e, 0x48, 0x57, 0x62, 0x66, 0x14, 0xfc, 0x01, 0xc2, 0x5f, 0x41, 0xaf, 0x7b, 0xc1, 0x2b, 0x22, 0x64, 0xef, - 0x60, 0xf6, 0x49, 0x20, 0xb4, 0xf2, 0x20, 0x38, 0x38, 0xf0, 0xd2, 0x4a, 0x16, 0x02, 0xff, 0x25, 0x48, 0x4d, 0x54, - 0xc7, 0x8c, 0x42, 0x4b, 0x7f, 0x89, 0x90, 0x23, 0xd7, 0x4c, 0xe8, 0x34, 0xd5, 0x76, 0xc7, 0xf2, 0x81, 0xd1, 0x3d, - 0x44, 0x5c, 0xb1, 0x82, 0x2a, 0x51, 0x0c, 0x91, 0xcf, 0x96, 0xe0, 0x57, 0x9c, 0x7c, 0x1e, 0xec, 0xfd, 0x3f, 0xff, - 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xf0, 0x33, 0x96, 0x8c, 0x1c, 0x9d, 0x87, 0xfd, 0x38, 0xdc, 0x6f, 0x36, 0x57, 0x7f, - 0x1e, 0x0d, 0xfe, 0x9b, 0x36, 0xff, 0xb9, 0x6c, 0x7e, 0x1a, 0xa2, 0x55, 0xf8, 0xe7, 0x51, 0x7f, 0x60, 0xbf, 0x06, - 0xff, 0x7d, 0xf1, 0xa7, 0x1c, 0x1e, 0x9a, 0xc4, 0x07, 0x08, 0x1d, 0x4d, 0xf0, 0x1f, 0x92, 0x1c, 0x35, 0x9b, 0x17, - 0x47, 0x13, 0xfc, 0x8b, 0x24, 0x47, 0xf0, 0xf7, 0x5e, 0x91, 0xb7, 0x6c, 0xf2, 0xf4, 0x6e, 0x1e, 0x7e, 0xbe, 0x58, - 0x3d, 0x58, 0xbe, 0xe2, 0x6b, 0x68, 0x77, 0xf0, 0xdf, 0x7f, 0xfe, 0x29, 0x83, 0x1f, 0x2f, 0xc8, 0xd1, 0xb0, 0x81, - 0x42, 0x9d, 0x7c, 0x48, 0xcc, 0x9f, 0xb0, 0x1f, 0x0f, 0xfe, 0xdb, 0x0e, 0x25, 0xf8, 0xf1, 0xcf, 0xcf, 0xe7, 0x17, - 0x64, 0xb8, 0x0a, 0x83, 0xd5, 0x8f, 0x68, 0x85, 0xd0, 0xea, 0x01, 0xfa, 0x8c, 0x83, 0x49, 0x80, 0xf0, 0x4f, 0x92, - 0x1c, 0xfd, 0x78, 0x34, 0xc1, 0xbf, 0x49, 0x72, 0x14, 0x1c, 0x4d, 0xf0, 0x7b, 0x41, 0x8e, 0xfe, 0x3b, 0xec, 0xc7, - 0x46, 0x09, 0xb7, 0xd2, 0xea, 0x8f, 0x15, 0xdc, 0x84, 0xd0, 0x82, 0xd1, 0x95, 0xe2, 0x2a, 0x63, 0xe8, 0xc1, 0x11, - 0xc7, 0x8f, 0x05, 0x00, 0x2b, 0x54, 0xa0, 0xa4, 0xd1, 0x97, 0xb0, 0xcb, 0x1b, 0x58, 0x78, 0xc0, 0xa0, 0x07, 0x31, - 0xc7, 0x46, 0x4f, 0x20, 0x63, 0x65, 0x6e, 0x6f, 0x25, 0x5c, 0xdf, 0xe2, 0x2b, 0xf2, 0x58, 0x84, 0x6d, 0x84, 0x39, - 0x85, 0x1f, 0x1d, 0x84, 0x3f, 0x28, 0x7b, 0xe1, 0x09, 0xdb, 0xdc, 0x60, 0x58, 0x2e, 0x0c, 0x3f, 0x13, 0x20, 0xfc, - 0x72, 0x47, 0xa6, 0x9a, 0x82, 0xfa, 0x01, 0xe1, 0x4f, 0xb5, 0xeb, 0x51, 0x7c, 0xa5, 0x48, 0x89, 0x1c, 0xef, 0x0a, - 0xc6, 0x3e, 0xd0, 0xec, 0x0b, 0x2b, 0xc2, 0xa7, 0x0a, 0xb7, 0x3b, 0x8f, 0xb0, 0x56, 0x55, 0xef, 0xb7, 0x51, 0xaf, - 0xbc, 0xdd, 0x7a, 0x2e, 0xcc, 0x7d, 0x02, 0x9c, 0xc2, 0x75, 0x7d, 0x0d, 0xac, 0xfd, 0x3e, 0xdf, 0x52, 0x6a, 0x15, - 0xf4, 0x36, 0x40, 0xf5, 0xab, 0x54, 0x9e, 0x7f, 0xa5, 0x19, 0x4f, 0xf7, 0x14, 0x9b, 0xcd, 0x33, 0xaa, 0xd8, 0x9e, - 0x9d, 0xf3, 0x1e, 0x85, 0x86, 0x82, 0x92, 0xa7, 0xf8, 0x5b, 0x56, 0x9b, 0xf6, 0x6f, 0x27, 0xe7, 0xc1, 0xde, 0x09, - 0xe1, 0x3e, 0xcb, 0xf2, 0x25, 0x92, 0x96, 0xd7, 0x65, 0x9b, 0x37, 0x82, 0xcd, 0x36, 0x28, 0xcb, 0x86, 0xfa, 0xfc, - 0xce, 0x31, 0xdc, 0x6f, 0x12, 0xd2, 0xe9, 0x07, 0xe7, 0xf2, 0xeb, 0xe4, 0x22, 0x80, 0x9b, 0x9c, 0x82, 0x48, 0xa6, - 0x95, 0x47, 0x50, 0x82, 0x92, 0x56, 0x8f, 0x9e, 0xb3, 0x1e, 0x6d, 0x34, 0x1c, 0x9b, 0x9d, 0x10, 0x3e, 0xa0, 0xa6, - 0x7e, 0x86, 0xa7, 0x38, 0x25, 0xcd, 0x36, 0x5e, 0x90, 0x96, 0xae, 0xd2, 0x5b, 0x9c, 0x27, 0xb6, 0x9f, 0x83, 0x83, - 0xb0, 0x88, 0x32, 0x2a, 0xd5, 0x0b, 0xd0, 0x08, 0x90, 0x05, 0x9e, 0x92, 0x22, 0x62, 0x77, 0x2c, 0x09, 0x13, 0x84, - 0xa7, 0x96, 0x06, 0xa1, 0x1e, 0x5a, 0x10, 0xaf, 0x18, 0xc8, 0x19, 0x44, 0xb2, 0xfe, 0x74, 0xd0, 0x1e, 0x12, 0x42, - 0x82, 0xfd, 0x66, 0x33, 0xe8, 0x17, 0xe4, 0x0f, 0x19, 0x43, 0x8a, 0xc7, 0x4e, 0x93, 0x5f, 0x20, 0xa9, 0xe3, 0x25, - 0x85, 0xef, 0x45, 0xa4, 0x98, 0x54, 0x21, 0x24, 0x83, 0x92, 0x20, 0x77, 0x18, 0x1e, 0x9c, 0x1f, 0x05, 0x0d, 0x48, - 0xd5, 0x28, 0x8a, 0x70, 0x41, 0xee, 0x15, 0x8a, 0xa7, 0x83, 0xe3, 0xa1, 0x7f, 0x46, 0x98, 0x54, 0xe8, 0xff, 0x5e, - 0xf5, 0xa7, 0x83, 0x96, 0xee, 0xff, 0x22, 0xe8, 0x87, 0x05, 0xc9, 0xf7, 0xed, 0x3d, 0x4f, 0x2c, 0x99, 0x9e, 0x2f, - 0x8a, 0xed, 0x00, 0x6d, 0xdf, 0x29, 0x69, 0x76, 0xe2, 0x30, 0xf5, 0x67, 0xd2, 0x84, 0x0e, 0x2d, 0x28, 0x70, 0x46, - 0xa0, 0x3c, 0x2e, 0x08, 0x74, 0x5a, 0x55, 0xbb, 0x57, 0xb1, 0x4d, 0xf8, 0x31, 0xf8, 0xb1, 0xff, 0x9b, 0x8c, 0x7f, - 0x92, 0x66, 0x04, 0xbf, 0xc9, 0xd5, 0x0a, 0xfe, 0xfe, 0x24, 0xfb, 0x30, 0x2c, 0x9d, 0xf6, 0x87, 0x4d, 0xfb, 0x05, - 0xd2, 0x24, 0x8b, 0xf5, 0x80, 0x71, 0x5e, 0xf2, 0x63, 0x66, 0x71, 0xc6, 0xc4, 0xcc, 0xe0, 0xe0, 0x80, 0x0f, 0x68, - 0xa3, 0x3d, 0x84, 0x1b, 0x81, 0x42, 0xc9, 0x0f, 0x5c, 0x4d, 0xc3, 0xe0, 0xe8, 0x22, 0x40, 0xfd, 0x60, 0x0f, 0x56, - 0xb9, 0x27, 0x1a, 0xc4, 0xc2, 0x3a, 0x69, 0x28, 0x1a, 0xa7, 0x17, 0xa4, 0xd5, 0x0f, 0xa5, 0x21, 0xf2, 0x19, 0xc2, - 0x89, 0xa5, 0xa9, 0x2d, 0x9c, 0xa2, 0x06, 0x97, 0x0d, 0xf7, 0x9d, 0xa2, 0xc6, 0x54, 0x35, 0xc6, 0x28, 0x4e, 0xe0, - 0x6f, 0x98, 0x12, 0x42, 0x9a, 0x9d, 0xb2, 0xa2, 0x3b, 0x2c, 0x29, 0x8a, 0xc7, 0x4e, 0x3d, 0x3a, 0xd0, 0x9b, 0x43, - 0x34, 0x42, 0x3e, 0x60, 0xc3, 0xd5, 0x2a, 0x38, 0xef, 0x5f, 0x04, 0xa8, 0x11, 0x3a, 0xb4, 0x3b, 0x72, 0x78, 0x87, - 0x10, 0x96, 0xc3, 0xb5, 0xbd, 0x81, 0xba, 0x65, 0xb5, 0xdb, 0xa6, 0x65, 0xb5, 0xff, 0x3d, 0xb2, 0xc0, 0xd6, 0xa5, - 0xdc, 0x63, 0xf8, 0xdb, 0x39, 0x4c, 0xd5, 0xe1, 0xb6, 0x20, 0x2d, 0x5c, 0x10, 0xa7, 0xee, 0xa6, 0x44, 0x55, 0xf8, - 0x9f, 0x90, 0xaa, 0x38, 0x1e, 0x64, 0x78, 0x3a, 0x24, 0x92, 0x6a, 0xf9, 0xa5, 0xe7, 0x94, 0xe9, 0x2c, 0x23, 0xb7, - 0x6c, 0xe3, 0xfe, 0x37, 0x83, 0x3b, 0x99, 0x2b, 0x15, 0x25, 0x8b, 0xa2, 0x60, 0xb9, 0x7a, 0x25, 0x52, 0xcb, 0xd8, - 0xb1, 0x0c, 0x64, 0x2b, 0xb8, 0xd8, 0xc5, 0xc0, 0xd5, 0x75, 0xdc, 0x4e, 0x49, 0xb7, 0xb2, 0x17, 0x24, 0x35, 0x0c, - 0x97, 0xbe, 0xee, 0xed, 0x2d, 0xac, 0x28, 0x1d, 0x22, 0x9c, 0xda, 0x7b, 0xe0, 0x30, 0x8a, 0xa2, 0x45, 0x94, 0x40, - 0x36, 0x74, 0x20, 0xd1, 0x5a, 0xef, 0xab, 0x30, 0x27, 0x57, 0x2a, 0xca, 0xd9, 0x9d, 0xee, 0x36, 0x44, 0xd5, 0x21, - 0xee, 0xf6, 0xdb, 0x39, 0xed, 0x69, 0x02, 0x94, 0x47, 0xb9, 0x48, 0x19, 0x40, 0x08, 0xee, 0xfe, 0x6d, 0xd2, 0x94, - 0x4a, 0xff, 0x66, 0xab, 0x1a, 0xe0, 0xc0, 0x57, 0x79, 0x2f, 0x40, 0x4f, 0xac, 0x65, 0xe8, 0xb2, 0xb0, 0x51, 0x9e, - 0x23, 0xc4, 0xc7, 0xe1, 0x22, 0x82, 0x1b, 0x41, 0x8d, 0x49, 0x5c, 0xa2, 0xd5, 0x6a, 0xe1, 0xe3, 0xd6, 0xb4, 0x52, - 0x4c, 0x8f, 0xc9, 0x74, 0x50, 0x34, 0x1a, 0x5a, 0x79, 0x9d, 0x1a, 0xbc, 0x58, 0x20, 0x3c, 0x2e, 0xf7, 0x9a, 0x2b, - 0x37, 0x27, 0xf5, 0xae, 0xc2, 0x71, 0x5d, 0x09, 0xdc, 0xe0, 0x12, 0x69, 0xfd, 0xa2, 0x82, 0xd6, 0xf1, 0x84, 0x1c, - 0x85, 0x83, 0xa8, 0xff, 0x3f, 0x87, 0xa8, 0x1f, 0x46, 0x87, 0xe8, 0xc8, 0xd0, 0x92, 0x31, 0xea, 0x25, 0xa6, 0x8f, - 0xa5, 0xbe, 0xfd, 0x6c, 0x63, 0xad, 0x80, 0x8c, 0x05, 0xce, 0xe9, 0x8c, 0xc5, 0x13, 0xd8, 0xf5, 0x0e, 0x79, 0xe6, - 0x18, 0x90, 0x29, 0x9e, 0x58, 0xda, 0x12, 0x05, 0x7d, 0x41, 0xcb, 0xaf, 0x7e, 0xd0, 0xa7, 0xd5, 0xd7, 0xff, 0x0c, - 0xfa, 0x09, 0x8d, 0xaf, 0xf8, 0xda, 0x2a, 0xc9, 0x6b, 0x7d, 0x9c, 0xba, 0x3e, 0xd6, 0x66, 0x71, 0x3c, 0xe0, 0xa5, - 0x28, 0xdf, 0xd2, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0x94, 0x47, 0x8a, 0x4e, 0x00, 0xaa, 0xde, 0x22, 0xe4, - 0xbe, 0x6d, 0x80, 0x37, 0x65, 0xc0, 0x16, 0x87, 0xb4, 0x00, 0xcd, 0xc5, 0x45, 0x0b, 0x2d, 0x6b, 0x85, 0x2d, 0x67, - 0x55, 0xbf, 0x8b, 0x2f, 0x89, 0xf7, 0x18, 0xa8, 0xf2, 0xf9, 0xa2, 0x37, 0x6e, 0x34, 0x50, 0xee, 0xf0, 0x2b, 0x1d, - 0x8c, 0x87, 0xf8, 0x0e, 0x50, 0x08, 0xd7, 0x30, 0x0a, 0xd7, 0xe6, 0xd8, 0xb1, 0x73, 0x6c, 0x34, 0xc4, 0x1a, 0xf5, - 0xbc, 0xca, 0x0b, 0x5b, 0x79, 0xbd, 0x36, 0x90, 0xd9, 0xc4, 0xb8, 0x33, 0xa4, 0x53, 0xc0, 0x10, 0x8c, 0x10, 0xf2, - 0x8f, 0x40, 0x3b, 0x9b, 0x85, 0x46, 0xa1, 0xba, 0xde, 0xbd, 0x40, 0x51, 0xcd, 0xe9, 0x11, 0x02, 0x2c, 0xa0, 0x6a, - 0xa9, 0x46, 0x9e, 0x2a, 0x9c, 0x36, 0xda, 0x1a, 0xdd, 0x9b, 0xed, 0x5e, 0xbd, 0xb1, 0x87, 0x55, 0x63, 0x38, 0x6d, - 0x90, 0x69, 0xb5, 0xc3, 0xd7, 0xa2, 0xd1, 0x58, 0xd7, 0xef, 0x4b, 0xdd, 0x26, 0xae, 0xdd, 0x5f, 0x3c, 0xdd, 0x32, - 0xf1, 0x70, 0xa7, 0x6f, 0x75, 0xde, 0xca, 0x88, 0xe7, 0x39, 0x2b, 0xe0, 0x84, 0x25, 0x0a, 0xcb, 0xf5, 0xba, 0x3c, - 0xf5, 0x7f, 0x57, 0xc6, 0x66, 0x8c, 0x70, 0xa0, 0x43, 0x5a, 0x6a, 0xc3, 0x02, 0x17, 0x98, 0x6a, 0x2a, 0x42, 0x08, - 0xf9, 0xa0, 0x9c, 0x79, 0x8c, 0xd2, 0x24, 0x29, 0x21, 0xde, 0xd9, 0x1d, 0xe6, 0x84, 0x45, 0x37, 0x0f, 0xae, 0xc4, - 0x77, 0x45, 0xba, 0x81, 0x1c, 0xc6, 0xba, 0x58, 0x66, 0x09, 0x59, 0x46, 0xbe, 0x82, 0x9c, 0x53, 0x5e, 0xb0, 0x44, - 0x9a, 0x20, 0x3e, 0xe1, 0x05, 0xd3, 0x8c, 0xfb, 0x03, 0x27, 0x37, 0x26, 0x75, 0x4e, 0x33, 0xf1, 0xb5, 0x3f, 0x00, - 0xcd, 0x0c, 0x94, 0x43, 0x82, 0x6c, 0x15, 0xbb, 0x79, 0x70, 0xf9, 0x7a, 0x97, 0x0c, 0xbd, 0x5a, 0x59, 0xe9, 0x39, - 0x01, 0xd6, 0x07, 0x67, 0xd5, 0x50, 0x13, 0xfb, 0x23, 0x0e, 0x13, 0xcd, 0x44, 0x65, 0x21, 0x07, 0x64, 0xba, 0x79, - 0x70, 0xf9, 0x2e, 0xe4, 0x5a, 0x37, 0x85, 0xb0, 0x3f, 0xef, 0xb0, 0x20, 0x21, 0x25, 0x0c, 0x99, 0xc9, 0x97, 0x74, - 0xac, 0xf0, 0x4e, 0xf7, 0x98, 0xea, 0x4c, 0x10, 0x3b, 0x06, 0x72, 0x48, 0x12, 0x0b, 0x02, 0x92, 0x20, 0x9c, 0xd4, - 0xe4, 0x3a, 0xa2, 0xd7, 0x40, 0x77, 0x76, 0x0d, 0x8b, 0x11, 0x19, 0xf6, 0x10, 0xe1, 0x44, 0x77, 0xab, 0xd6, 0xe6, - 0x38, 0xc9, 0xe9, 0xa6, 0xa1, 0x5b, 0x25, 0xcf, 0xbe, 0x07, 0xc1, 0xcb, 0x7d, 0xbc, 0xb2, 0x6d, 0x97, 0x09, 0x4f, - 0x9c, 0x45, 0xda, 0xcd, 0x83, 0xcb, 0x5f, 0xad, 0x51, 0xda, 0x9c, 0x3a, 0xf2, 0xbf, 0x25, 0xa3, 0x5e, 0xfe, 0x1a, - 0x55, 0xb9, 0xba, 0xf0, 0xcd, 0x83, 0xcb, 0xdf, 0x77, 0x15, 0x83, 0xf4, 0xf5, 0xa2, 0x52, 0x12, 0xe8, 0xf1, 0x2d, - 0x59, 0x16, 0x2f, 0xed, 0x59, 0x11, 0xcb, 0x35, 0xd6, 0x27, 0x54, 0x9c, 0xaf, 0x4b, 0xdd, 0xca, 0x13, 0x2c, 0x88, - 0xbe, 0x4a, 0xaa, 0x2f, 0x9b, 0x45, 0x63, 0x2e, 0xf2, 0xeb, 0x44, 0xcc, 0xd9, 0x37, 0xee, 0x97, 0x9e, 0x2a, 0x14, - 0xf1, 0x19, 0x18, 0xe2, 0xe8, 0xb1, 0x4b, 0xbc, 0xdf, 0x42, 0xbd, 0x8d, 0xf3, 0x4c, 0x68, 0x44, 0x2d, 0xea, 0x87, - 0x0d, 0xa6, 0xa4, 0x85, 0x13, 0xd2, 0xc2, 0x19, 0xc9, 0x07, 0x2d, 0x73, 0x62, 0xf4, 0xb2, 0xb2, 0x69, 0x73, 0xee, - 0xc0, 0x76, 0xcf, 0xcc, 0xbe, 0x35, 0x87, 0xf2, 0xb4, 0x97, 0x69, 0xfd, 0xa5, 0x3e, 0xe8, 0xa7, 0x1a, 0x35, 0x9e, - 0xb0, 0xb0, 0xc0, 0x85, 0x6e, 0xf9, 0x9a, 0x8f, 0x32, 0xb0, 0x53, 0x81, 0x99, 0x61, 0x85, 0xe2, 0xb2, 0x6c, 0xdb, - 0x96, 0xcd, 0x22, 0xbd, 0x56, 0x05, 0xce, 0x22, 0x20, 0xe5, 0x38, 0xb3, 0x76, 0x3d, 0x72, 0xbb, 0xca, 0xe9, 0xc1, - 0x41, 0x68, 0x2b, 0xd1, 0xb0, 0x70, 0xf9, 0xd5, 0x0d, 0xe0, 0x7b, 0x43, 0x35, 0xa6, 0x48, 0x4f, 0xa0, 0xd1, 0x48, - 0x86, 0x6b, 0xba, 0x4f, 0x48, 0x98, 0xd5, 0xa1, 0xe8, 0x46, 0xaf, 0x99, 0xc1, 0x0d, 0x00, 0x34, 0x1a, 0xe5, 0x75, - 0xef, 0x06, 0xc4, 0x9e, 0x2a, 0x2c, 0xd6, 0x5f, 0xc3, 0xd2, 0x9a, 0xa8, 0xb5, 0x65, 0x87, 0xe5, 0x46, 0x81, 0xa4, - 0x8f, 0xbb, 0xd2, 0xcd, 0xc7, 0xdb, 0x1a, 0xba, 0xdc, 0x0b, 0x6b, 0x03, 0x81, 0xb5, 0xd5, 0x96, 0x2d, 0xe4, 0x48, - 0x5b, 0x07, 0xc5, 0xae, 0x10, 0x5c, 0x70, 0x41, 0xa1, 0xc6, 0xda, 0x62, 0xf9, 0x13, 0xb6, 0x6d, 0xce, 0x89, 0x73, - 0x64, 0xb5, 0x65, 0x7a, 0x18, 0x1a, 0x60, 0x9d, 0x12, 0x30, 0xcf, 0xc9, 0xcb, 0x6f, 0xa3, 0xfe, 0xa5, 0x87, 0xfa, - 0x8f, 0x09, 0xf3, 0xb6, 0x81, 0x59, 0x82, 0x48, 0x58, 0x05, 0x45, 0xee, 0xb2, 0xae, 0xe6, 0x04, 0xb4, 0x71, 0x75, - 0xa8, 0xe6, 0xfe, 0x15, 0xe5, 0x37, 0x28, 0x8b, 0xbf, 0x53, 0xb4, 0x3e, 0x13, 0xbb, 0xfb, 0xe4, 0xb0, 0xba, 0xa0, - 0x83, 0xae, 0x77, 0x29, 0x07, 0x7d, 0x52, 0x78, 0xf9, 0xfb, 0xf7, 0xef, 0x56, 0xaf, 0xe6, 0xdb, 0x3b, 0xd8, 0x33, - 0x2b, 0x85, 0x59, 0x7b, 0x1b, 0xb8, 0x6e, 0x64, 0x0a, 0xfd, 0x97, 0x77, 0xe2, 0x75, 0x2a, 0xb4, 0xb1, 0x19, 0xdd, - 0x71, 0x08, 0xa3, 0x6d, 0xb7, 0x75, 0x09, 0xe6, 0x35, 0x0b, 0x74, 0xc9, 0x18, 0xb7, 0xd2, 0xe2, 0x1b, 0x64, 0xe4, - 0x52, 0x17, 0x60, 0x79, 0xba, 0x3b, 0xfb, 0xf1, 0xda, 0xe2, 0x89, 0x19, 0x1a, 0x5a, 0x6a, 0x42, 0x68, 0xf0, 0x1e, - 0x30, 0xc7, 0x1c, 0x11, 0x00, 0xa2, 0x97, 0x1a, 0x52, 0x15, 0xc8, 0x82, 0xa0, 0x52, 0xe4, 0x3f, 0xdf, 0x27, 0xe4, - 0x65, 0xa5, 0xc8, 0x7c, 0x5b, 0x19, 0x73, 0x01, 0x62, 0xa0, 0x18, 0x2e, 0x12, 0xca, 0x04, 0x73, 0x19, 0xfa, 0x41, - 0xb9, 0xf2, 0x5a, 0xda, 0x8c, 0x2a, 0x6e, 0xdc, 0xbb, 0x29, 0xd5, 0x2a, 0x3e, 0x93, 0xef, 0x20, 0xb1, 0x91, 0xfb, - 0x00, 0x72, 0x19, 0xd5, 0x83, 0x84, 0xef, 0x77, 0xba, 0xb4, 0x6b, 0x77, 0xfd, 0x65, 0xd3, 0x22, 0x66, 0x63, 0x5d, - 0x22, 0x9e, 0x4b, 0x56, 0xa8, 0xc7, 0x6c, 0x2c, 0x0a, 0xb8, 0xff, 0x28, 0xc1, 0x82, 0xd6, 0x0f, 0x3c, 0x1d, 0xa0, - 0x9e, 0xa0, 0x77, 0xe9, 0xb0, 0x31, 0x43, 0xfd, 0xeb, 0x8b, 0xbe, 0x03, 0xbf, 0xd9, 0xac, 0xf5, 0xf2, 0xe0, 0xe0, - 0x2b, 0xab, 0x00, 0x65, 0x87, 0xa9, 0x87, 0xe1, 0x11, 0x2f, 0xc3, 0xe5, 0xd8, 0x9b, 0xe1, 0x07, 0x61, 0xa5, 0x32, - 0x70, 0x84, 0xc3, 0x27, 0x42, 0xcf, 0x89, 0x5a, 0x4f, 0x36, 0xe9, 0xbd, 0xd5, 0x66, 0x48, 0x5f, 0xac, 0x01, 0x72, - 0x0f, 0x72, 0xb9, 0x51, 0x32, 0xe5, 0x95, 0xad, 0x6d, 0x39, 0x88, 0x2b, 0x00, 0x57, 0x98, 0x83, 0x90, 0xe2, 0xa1, - 0x61, 0xbe, 0x53, 0x68, 0x79, 0x2e, 0x80, 0xfd, 0xc7, 0x79, 0x04, 0x22, 0x2d, 0xaa, 0x6d, 0x5c, 0x84, 0x70, 0xae, - 0x25, 0x1e, 0xcf, 0x38, 0xe1, 0xf2, 0xf9, 0x2e, 0x0d, 0xb5, 0x43, 0x6d, 0xa6, 0xcf, 0x20, 0x28, 0x21, 0x50, 0x59, - 0x21, 0xfa, 0x1a, 0x4a, 0xcb, 0xcd, 0x95, 0xf7, 0x70, 0xec, 0x76, 0x2f, 0xa7, 0xa1, 0xb9, 0xdb, 0x82, 0xe3, 0xa3, - 0x88, 0x16, 0x61, 0xad, 0xeb, 0x5e, 0xa1, 0xab, 0x61, 0x0b, 0x3a, 0xea, 0xc3, 0xa9, 0xd0, 0xf7, 0x84, 0x57, 0x15, - 0x49, 0xfd, 0x64, 0x2d, 0xa0, 0x1c, 0x31, 0xac, 0x4c, 0x53, 0xbc, 0xf9, 0x7f, 0xb2, 0xe6, 0x6b, 0xe5, 0x31, 0xc1, - 0xf4, 0x30, 0x6e, 0xcd, 0x2a, 0xb0, 0x35, 0xe0, 0xd8, 0xf2, 0x2f, 0xe1, 0x2d, 0xaa, 0x53, 0x8a, 0xeb, 0x4e, 0x3d, - 0x26, 0xe0, 0x2d, 0x58, 0xcf, 0x6c, 0x6e, 0xfd, 0xe7, 0xfa, 0x60, 0x94, 0x38, 0xaf, 0x11, 0x78, 0xa1, 0x09, 0x3c, - 0x02, 0xc6, 0xcd, 0x99, 0x96, 0xf7, 0xad, 0x11, 0x8d, 0x74, 0x27, 0x9e, 0xc5, 0x33, 0xc3, 0x72, 0x6f, 0x7d, 0x6c, - 0xac, 0x48, 0x2c, 0x09, 0xd8, 0x16, 0x61, 0x4b, 0xe4, 0x05, 0xc2, 0x79, 0xa3, 0xd1, 0xcb, 0xcf, 0x59, 0xa5, 0x55, - 0xa9, 0x86, 0x29, 0xe1, 0x96, 0x18, 0xf0, 0xbe, 0x76, 0xa2, 0xe6, 0x08, 0x97, 0x66, 0xee, 0x39, 0xa8, 0xef, 0x2f, - 0xdf, 0x86, 0x3e, 0x7d, 0xf3, 0xcb, 0x96, 0x17, 0xb1, 0x30, 0xa5, 0xb0, 0xba, 0xc3, 0x79, 0xf3, 0x7d, 0xb3, 0x11, - 0x18, 0xf7, 0x7e, 0x1b, 0x83, 0x8d, 0x1b, 0xea, 0x29, 0x43, 0x1a, 0xca, 0x4d, 0xd8, 0x43, 0x95, 0xbd, 0xa3, 0xdf, - 0x59, 0x4f, 0x55, 0xd2, 0xae, 0x22, 0xf9, 0x7a, 0x2d, 0x59, 0x65, 0x34, 0xb0, 0x61, 0xd8, 0xa9, 0x8f, 0x99, 0x6d, - 0x05, 0xfe, 0xd5, 0x9c, 0x28, 0xec, 0x21, 0xeb, 0x9b, 0x6f, 0x5d, 0xa7, 0x54, 0xc3, 0x84, 0xed, 0x6d, 0xcf, 0xc7, - 0x2b, 0xbe, 0xeb, 0x7c, 0xc4, 0xc2, 0x6e, 0x7d, 0x7d, 0x36, 0xb6, 0xff, 0x8d, 0xb3, 0xd1, 0xaa, 0xed, 0xdd, 0xf1, - 0x08, 0xdc, 0x49, 0xed, 0x78, 0xcc, 0xeb, 0xc7, 0xa3, 0xc0, 0xee, 0xf4, 0xbe, 0xe8, 0xac, 0x56, 0x72, 0xd0, 0x02, - 0xb5, 0x53, 0x10, 0xc0, 0xcf, 0xb6, 0xf9, 0xe9, 0x91, 0x64, 0xa3, 0x43, 0x0e, 0xcb, 0xf3, 0xbe, 0x8d, 0x22, 0x30, - 0xa0, 0x0e, 0xb5, 0xad, 0x97, 0x46, 0x6c, 0x8b, 0x43, 0x16, 0xcb, 0x89, 0x2c, 0xaf, 0xae, 0x60, 0xc4, 0xfa, 0xd8, - 0xb0, 0x02, 0x66, 0xb8, 0xd3, 0xaa, 0xd0, 0x89, 0x9f, 0xff, 0x9a, 0x39, 0xad, 0x1d, 0x31, 0x86, 0x93, 0xa8, 0x59, - 0x31, 0xd8, 0x11, 0x58, 0x86, 0x71, 0x5f, 0x4b, 0xa8, 0xd5, 0xa9, 0x8e, 0x6a, 0x47, 0x12, 0x6e, 0x81, 0xda, 0x6d, - 0x5f, 0x9f, 0x4b, 0xab, 0xd5, 0xce, 0x83, 0x05, 0x17, 0x1e, 0x6e, 0x3f, 0x27, 0xaa, 0x46, 0x52, 0x28, 0xb1, 0x12, - 0x14, 0xce, 0x34, 0xaa, 0x2a, 0x22, 0x06, 0xad, 0x21, 0xf0, 0xa4, 0xbd, 0xe4, 0x5c, 0x54, 0x42, 0x72, 0xd2, 0x68, - 0xa0, 0xac, 0xec, 0x98, 0x0e, 0x64, 0x23, 0x19, 0x62, 0x86, 0x13, 0x23, 0xb0, 0xc0, 0xe9, 0x15, 0x66, 0x55, 0xd7, - 0x83, 0x64, 0x88, 0x70, 0xb1, 0x5a, 0x85, 0x66, 0x68, 0x19, 0x5a, 0xad, 0x32, 0x7f, 0x68, 0x3a, 0x1f, 0x2a, 0xbe, - 0xec, 0x2b, 0xf2, 0x52, 0x9f, 0x87, 0x2f, 0x61, 0x90, 0x0d, 0x12, 0x66, 0x56, 0x25, 0x98, 0x81, 0xe6, 0xaa, 0x21, - 0x06, 0x49, 0xa3, 0x3d, 0xf4, 0x68, 0xd8, 0x20, 0x19, 0x92, 0x6c, 0x0d, 0x96, 0xb3, 0xb9, 0x3d, 0x30, 0xff, 0x82, - 0x83, 0xed, 0x2f, 0x7d, 0xce, 0x98, 0x06, 0xfd, 0x35, 0xd9, 0x54, 0x19, 0x94, 0x78, 0x65, 0x17, 0xd7, 0x95, 0xab, - 0x19, 0x58, 0x94, 0x85, 0xb0, 0xbd, 0x66, 0xee, 0x83, 0xf0, 0x5f, 0x62, 0xbb, 0xa0, 0xa5, 0x11, 0xf7, 0x06, 0xe2, - 0x3b, 0xdb, 0xed, 0x28, 0x8a, 0x68, 0x31, 0xd1, 0x57, 0x22, 0x8e, 0x12, 0xeb, 0x3d, 0x70, 0x6c, 0xc7, 0xe9, 0xf5, - 0x3c, 0x28, 0x3b, 0x1b, 0x12, 0x33, 0x7e, 0xc7, 0xec, 0x38, 0xc7, 0x95, 0x82, 0xee, 0xd6, 0x45, 0x98, 0xc1, 0xd0, - 0xff, 0xe5, 0xc1, 0x9c, 0xd8, 0xc1, 0x18, 0x34, 0xd9, 0x80, 0xdb, 0x37, 0xe0, 0x51, 0xd0, 0x0d, 0xb8, 0x7d, 0x1b, - 0xbe, 0x0e, 0x5a, 0xc9, 0x37, 0x07, 0xe8, 0x91, 0x09, 0x33, 0xd2, 0x2a, 0xc1, 0x1b, 0x66, 0x77, 0x93, 0x23, 0x33, - 0x64, 0x15, 0x0e, 0x57, 0x45, 0x42, 0xb9, 0xb1, 0x17, 0x2a, 0x26, 0xd5, 0xe3, 0xfe, 0x65, 0xfc, 0x12, 0xf9, 0x4a, - 0x83, 0xba, 0x71, 0x0c, 0x60, 0x95, 0xd5, 0xd6, 0xbf, 0x3c, 0x38, 0x00, 0xf3, 0x68, 0x60, 0xed, 0xa2, 0x84, 0xce, - 0xd5, 0xa2, 0x00, 0xfe, 0x2a, 0x77, 0xbf, 0x21, 0x19, 0xdc, 0x4e, 0x74, 0x1a, 0xfc, 0x80, 0x84, 0x39, 0x95, 0x92, - 0x7f, 0x35, 0x69, 0xf6, 0x37, 0x2e, 0x88, 0xc3, 0xe8, 0xdc, 0x70, 0x8a, 0x02, 0xf5, 0x84, 0x45, 0xd7, 0x3a, 0xe4, - 0x9e, 0x7e, 0x65, 0xb9, 0x7a, 0xc9, 0xa5, 0x62, 0x39, 0x00, 0xa0, 0x42, 0x3c, 0x98, 0x52, 0x8e, 0x60, 0xeb, 0xd6, - 0x6a, 0xd1, 0x34, 0xfd, 0x6e, 0x15, 0x55, 0x67, 0x8b, 0xa6, 0x34, 0x4f, 0x33, 0xd3, 0x89, 0x6f, 0x33, 0xe9, 0xec, - 0x44, 0xcb, 0x92, 0xbe, 0xc5, 0x4e, 0xc5, 0x7e, 0x68, 0x5a, 0x1f, 0x4a, 0xe2, 0xce, 0x05, 0x77, 0x96, 0x7e, 0x97, - 0x8f, 0x81, 0x2b, 0xf5, 0x6f, 0xac, 0x82, 0x3f, 0x13, 0xac, 0x3c, 0xf2, 0x1a, 0xd5, 0xc7, 0xe9, 0x50, 0x27, 0xdb, - 0x52, 0x2e, 0x94, 0x46, 0x61, 0x1b, 0x27, 0x85, 0xc6, 0x94, 0xd3, 0x6f, 0x4b, 0x5c, 0xbf, 0xba, 0x63, 0xc4, 0x1d, - 0x1d, 0xf2, 0xdf, 0xa5, 0xd2, 0x68, 0x59, 0x22, 0x18, 0x72, 0x3b, 0xf2, 0x67, 0x09, 0x57, 0xb1, 0x19, 0x57, 0xcf, - 0xd5, 0x2c, 0xdb, 0xf0, 0xc4, 0xe9, 0xfd, 0x5c, 0x5e, 0x23, 0xff, 0x2c, 0xc3, 0x5b, 0x86, 0x9f, 0x30, 0xb8, 0x37, - 0x7e, 0xc6, 0xbd, 0x2a, 0xdb, 0xf7, 0xc5, 0xcf, 0xbc, 0xfb, 0xe2, 0x67, 0x3c, 0xde, 0x2e, 0xea, 0xdd, 0x13, 0x77, - 0xa2, 0xb3, 0xa8, 0x15, 0x38, 0x3e, 0x6a, 0x4a, 0x2b, 0xff, 0x4a, 0xb3, 0x35, 0x70, 0x65, 0x13, 0x07, 0xc6, 0x79, - 0x75, 0x11, 0x8a, 0x59, 0x73, 0x46, 0xc3, 0xe1, 0x7f, 0x6b, 0x9d, 0xec, 0xc9, 0x23, 0x8c, 0x14, 0xf2, 0x86, 0x16, - 0xea, 0x01, 0x6c, 0xb8, 0x62, 0xcb, 0x07, 0x90, 0x12, 0x50, 0xb6, 0xfd, 0x7b, 0x5d, 0x54, 0x8e, 0x07, 0xfd, 0xdc, - 0x38, 0x1f, 0xf9, 0xed, 0x93, 0xa2, 0xe4, 0xea, 0xea, 0x42, 0xc8, 0x9d, 0xd6, 0x12, 0x20, 0x4c, 0x9d, 0x6b, 0x1e, - 0xb3, 0x34, 0x99, 0xc5, 0xcb, 0x75, 0xa9, 0x3a, 0x28, 0x0c, 0x57, 0xc7, 0x11, 0x2e, 0xd6, 0xfa, 0x06, 0xfd, 0x1f, - 0x8e, 0xff, 0xe2, 0x96, 0x46, 0x7e, 0x2a, 0x29, 0xd0, 0xe3, 0xdd, 0xbe, 0x36, 0x3b, 0x48, 0xa4, 0x99, 0x43, 0x69, - 0x29, 0x00, 0x58, 0xad, 0xf1, 0x75, 0xed, 0x70, 0xea, 0x89, 0xb0, 0xb3, 0xf9, 0xa6, 0x21, 0x2c, 0x66, 0xa5, 0x05, - 0x8f, 0xee, 0x66, 0x87, 0xe5, 0xa8, 0x93, 0xc5, 0x55, 0xb9, 0xc7, 0x6a, 0xfd, 0xa2, 0x6f, 0x80, 0xb2, 0x32, 0x44, - 0x5b, 0xad, 0xc2, 0x3a, 0xbc, 0x89, 0xf4, 0xae, 0x41, 0x10, 0x96, 0x9e, 0x01, 0x47, 0x8d, 0xf1, 0x36, 0x75, 0x42, - 0xb4, 0x69, 0xbf, 0xe4, 0x58, 0xf7, 0xda, 0x38, 0x7c, 0x45, 0x83, 0xa9, 0xee, 0x6b, 0x1e, 0xb0, 0x99, 0x5d, 0xd9, - 0x91, 0x07, 0xa1, 0x29, 0x75, 0xc6, 0xb9, 0x95, 0x15, 0xed, 0x0e, 0xf8, 0xa2, 0xef, 0x98, 0xe7, 0x5a, 0xd0, 0x6d, - 0xe7, 0x7b, 0xb6, 0x4d, 0x4f, 0xc4, 0xb7, 0x6c, 0x9b, 0x6a, 0x9c, 0xf0, 0x7e, 0x0b, 0x7d, 0xdf, 0x10, 0xd6, 0xf4, - 0xb5, 0xbb, 0xc8, 0xff, 0x42, 0x77, 0x6d, 0x40, 0x4f, 0x03, 0x66, 0x47, 0x63, 0x3e, 0xa8, 0xf5, 0xfa, 0x53, 0xe9, - 0xbf, 0xa0, 0x6d, 0x85, 0x3e, 0x99, 0x5d, 0x60, 0xc5, 0x4a, 0xed, 0x10, 0x1c, 0xfe, 0xc3, 0xc9, 0x24, 0x13, 0x23, - 0x9a, 0xbd, 0x83, 0x1e, 0xab, 0xdc, 0xe7, 0xf7, 0x69, 0x41, 0x15, 0xb3, 0xb4, 0xa6, 0x1a, 0xc5, 0x3f, 0xdc, 0x1b, - 0xc6, 0x3f, 0xdc, 0x50, 0xee, 0xaa, 0x05, 0xbc, 0x7c, 0x59, 0x36, 0x11, 0x7f, 0x5a, 0x97, 0xfe, 0x56, 0xf9, 0xee, - 0x5e, 0x36, 0x49, 0x9a, 0xca, 0xcb, 0xd9, 0xe6, 0xe1, 0x66, 0x53, 0x61, 0xf8, 0xd7, 0x37, 0x06, 0xbb, 0x4d, 0xe6, - 0xfe, 0xf2, 0xc8, 0xdc, 0x5f, 0x3c, 0xfe, 0x6e, 0x2d, 0x8f, 0xe2, 0x1d, 0x47, 0xc7, 0xda, 0x32, 0xc6, 0x8c, 0xfa, - 0xad, 0x02, 0x83, 0x06, 0x45, 0x2e, 0x3c, 0x6f, 0x87, 0xea, 0xf4, 0x72, 0xf6, 0x47, 0x61, 0xb2, 0x90, 0x4a, 0xcc, - 0x6c, 0xa3, 0xd2, 0xfa, 0x38, 0xe9, 0x4c, 0x50, 0x60, 0xeb, 0x3b, 0xfc, 0xb8, 0xee, 0x46, 0xb6, 0xfc, 0xc2, 0xf3, - 0x34, 0xce, 0xb1, 0x3d, 0x5b, 0x64, 0x2c, 0xd6, 0xc4, 0x99, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0xcf, 0xb9, 0x9c, 0xb2, - 0x22, 0x2c, 0xd0, 0xf2, 0x5b, 0x9d, 0x15, 0x70, 0x9b, 0x63, 0x3a, 0xc3, 0x69, 0x69, 0x39, 0xa0, 0x22, 0x68, 0x0d, - 0x74, 0x46, 0x33, 0xa6, 0xa6, 0x22, 0x05, 0xc3, 0x97, 0x28, 0x2d, 0xdd, 0xa9, 0x0e, 0x0e, 0xf6, 0xc3, 0x40, 0xeb, - 0x2f, 0xc0, 0x07, 0xdd, 0xcf, 0x41, 0xfd, 0x25, 0x38, 0x06, 0x55, 0x5d, 0x33, 0xb4, 0x64, 0x9b, 0x3e, 0x34, 0x2a, - 0xfa, 0xc2, 0xee, 0x31, 0x47, 0xeb, 0x75, 0x6c, 0x46, 0x1d, 0x8c, 0x39, 0xcb, 0xd2, 0x00, 0x7f, 0x61, 0xf7, 0x71, - 0xe9, 0xb6, 0xae, 0xbd, 0xac, 0xf5, 0x22, 0x06, 0xe2, 0x36, 0x0f, 0x70, 0xd5, 0x49, 0xbc, 0x5c, 0x63, 0x51, 0xf0, - 0x09, 0xe0, 0xe8, 0x2f, 0xec, 0x3e, 0xb6, 0xed, 0x79, 0xae, 0x82, 0x68, 0xe9, 0x40, 0x1f, 0x79, 0xc9, 0xfe, 0x32, - 0x58, 0x81, 0x63, 0xa0, 0xeb, 0x0e, 0x49, 0xad, 0x5c, 0x25, 0x42, 0x22, 0xb4, 0xfe, 0x77, 0xa7, 0x82, 0x17, 0xfe, - 0x39, 0xa7, 0x6a, 0x16, 0xb7, 0x1b, 0x95, 0x18, 0x54, 0xa8, 0x2c, 0x48, 0x3e, 0x86, 0xdc, 0xed, 0x3e, 0xeb, 0xfd, - 0xe0, 0xe9, 0xcc, 0x16, 0xd4, 0x36, 0x1a, 0xa7, 0xfa, 0x17, 0xaa, 0xee, 0xa0, 0x66, 0xaa, 0xaa, 0xb8, 0xf7, 0x31, - 0x04, 0xc0, 0x83, 0xb5, 0x0c, 0xd5, 0x0e, 0xa1, 0x6b, 0x67, 0xa6, 0x3a, 0xa6, 0x24, 0x5c, 0xba, 0x39, 0xc4, 0xdc, - 0x07, 0xa3, 0x5a, 0x03, 0x1a, 0x5a, 0x04, 0x33, 0x96, 0x87, 0x7c, 0x1c, 0xca, 0xad, 0x33, 0x54, 0xe8, 0x33, 0x34, - 0xf2, 0x40, 0xfe, 0x8d, 0x33, 0x93, 0x69, 0x68, 0x68, 0xde, 0x52, 0x1f, 0x80, 0x76, 0x75, 0x2d, 0x0e, 0xf9, 0x2b, - 0x5a, 0x3a, 0xef, 0x99, 0x45, 0x17, 0xb5, 0x61, 0x85, 0xba, 0x1d, 0xb4, 0x8e, 0x61, 0x4a, 0xcc, 0x14, 0x58, 0x3b, - 0xbd, 0x0f, 0x77, 0x76, 0xb5, 0x61, 0x11, 0xb9, 0x69, 0x11, 0x07, 0x93, 0x90, 0xa2, 0x25, 0x0f, 0x29, 0x16, 0x60, - 0x07, 0x59, 0xac, 0xcb, 0xf1, 0x33, 0x7f, 0x39, 0x6a, 0x56, 0xd2, 0xbb, 0x1d, 0x0c, 0x81, 0xcb, 0x57, 0x60, 0x1b, - 0x8a, 0xb9, 0x23, 0x2c, 0x3c, 0xd4, 0x9e, 0x7e, 0xde, 0xba, 0xcd, 0xcd, 0x82, 0xb8, 0x15, 0x18, 0xd3, 0x70, 0xe9, - 0xcd, 0xc2, 0x77, 0x2a, 0xb7, 0x0e, 0x87, 0xf6, 0x9a, 0xb0, 0x32, 0x5e, 0x0d, 0x73, 0xb2, 0x71, 0xf4, 0x7c, 0xdf, - 0xc6, 0xf3, 0xef, 0x05, 0x2b, 0xee, 0xaf, 0x19, 0xd8, 0x58, 0x0b, 0x70, 0x37, 0xae, 0x96, 0xa1, 0x32, 0x90, 0xef, - 0x0b, 0xcd, 0xba, 0xac, 0xf1, 0x77, 0xa3, 0x62, 0xac, 0xf5, 0x3d, 0xa5, 0xa7, 0xad, 0x31, 0xdb, 0x85, 0x7d, 0xd3, - 0x75, 0x93, 0xf5, 0xb4, 0x22, 0xae, 0x82, 0xb4, 0xbd, 0x5b, 0xc0, 0x85, 0xef, 0x0f, 0x3b, 0xc8, 0x87, 0x9b, 0xaa, - 0x1b, 0x48, 0x82, 0x6b, 0x3f, 0xf1, 0xed, 0xa9, 0xee, 0xb2, 0xd6, 0xfd, 0xf6, 0x54, 0x6b, 0x97, 0x85, 0xda, 0x90, - 0x08, 0xdb, 0x7e, 0x4a, 0xff, 0x69, 0xb9, 0x5e, 0xa3, 0x35, 0x0c, 0xef, 0x3d, 0xef, 0x85, 0xe1, 0x7b, 0x67, 0xa1, - 0x18, 0xc1, 0x45, 0xee, 0x75, 0x26, 0x1c, 0x21, 0xaf, 0x46, 0xf0, 0x9e, 0x6f, 0x0d, 0xe1, 0x3d, 0xf7, 0x9c, 0x5e, - 0x41, 0x6a, 0x9a, 0xe4, 0x2c, 0x75, 0xf4, 0x13, 0x19, 0x24, 0xd4, 0x7c, 0xdc, 0x6b, 0x4e, 0xb8, 0xfa, 0x1c, 0x03, - 0xff, 0x85, 0x47, 0x0b, 0xa5, 0x44, 0x8e, 0x79, 0x3e, 0x5f, 0x28, 0x2c, 0xf5, 0xe8, 0x97, 0x63, 0x91, 0xab, 0xe6, - 0x98, 0xce, 0x78, 0x76, 0x1f, 0x2f, 0x78, 0x73, 0x26, 0x72, 0x21, 0xe7, 0x34, 0x61, 0x58, 0xde, 0x4b, 0xc5, 0x66, - 0xcd, 0x05, 0xc7, 0xcf, 0x59, 0xf6, 0x95, 0x29, 0x9e, 0x50, 0xfc, 0x56, 0x8c, 0x84, 0x12, 0xf8, 0xf5, 0xdd, 0xfd, - 0x84, 0xe5, 0xf8, 0xf7, 0xd1, 0x22, 0x57, 0x0b, 0x2c, 0x69, 0x2e, 0x9b, 0x92, 0x15, 0x7c, 0xdc, 0x6b, 0x36, 0xe7, - 0x05, 0x9f, 0xd1, 0xe2, 0xbe, 0x99, 0x88, 0x4c, 0x14, 0xf1, 0x7f, 0xb5, 0x8e, 0xe9, 0xa3, 0xf1, 0x49, 0x4f, 0x15, - 0x34, 0x97, 0x1c, 0x16, 0x26, 0xa6, 0x59, 0xb6, 0x77, 0xdc, 0x6d, 0xcd, 0xe4, 0xbe, 0xb9, 0xf0, 0xa3, 0xb9, 0x5a, - 0x7f, 0xc6, 0x1f, 0x04, 0x8c, 0x32, 0x1a, 0xa9, 0xdc, 0x0e, 0x72, 0x99, 0x2c, 0x0a, 0x29, 0x8a, 0x78, 0x2e, 0x78, - 0xae, 0x58, 0xd1, 0x1b, 0x89, 0x22, 0x65, 0x45, 0xb3, 0xa0, 0x29, 0x5f, 0xc8, 0xf8, 0x64, 0x7e, 0xd7, 0xab, 0xf7, - 0x60, 0xf2, 0xe3, 0x5c, 0xe4, 0xac, 0x07, 0xfc, 0xc6, 0xa4, 0x10, 0x8b, 0x3c, 0xb5, 0xc3, 0x58, 0xe4, 0x92, 0xa9, - 0xde, 0x9c, 0xa6, 0x60, 0x07, 0x1c, 0x9f, 0xcd, 0xef, 0x7a, 0x7a, 0xd6, 0xb7, 0x8c, 0x4f, 0xa6, 0x2a, 0xee, 0xb6, - 0x5a, 0xe6, 0x5b, 0xf2, 0x7f, 0x58, 0xdc, 0xee, 0x44, 0x9d, 0xee, 0xfc, 0x0e, 0x38, 0x78, 0xc5, 0x8a, 0x26, 0xc0, - 0x02, 0x2a, 0xb5, 0xa3, 0xd6, 0xa3, 0xe3, 0x87, 0x90, 0x01, 0x36, 0x0e, 0x4d, 0x3d, 0x21, 0x30, 0x76, 0x8f, 0x17, - 0xf3, 0x39, 0x2b, 0xc0, 0x8b, 0xbe, 0x37, 0xa3, 0xc5, 0x84, 0xe7, 0xcd, 0x42, 0x37, 0xda, 0x3c, 0x9b, 0xdf, 0xad, - 0x61, 0x3e, 0xb1, 0x31, 0x5b, 0xb5, 0xd3, 0xb2, 0x5f, 0x4b, 0x6f, 0x88, 0x3a, 0x26, 0x4d, 0x5c, 0x4c, 0x46, 0x34, - 0x6c, 0x77, 0x1e, 0x62, 0xf7, 0xbf, 0xa8, 0x83, 0x3c, 0xb0, 0x35, 0xd3, 0x45, 0xa1, 0x6f, 0x51, 0xe3, 0xb6, 0x34, - 0xcd, 0x4e, 0xc5, 0x57, 0x56, 0xb8, 0x56, 0xf5, 0xc7, 0x72, 0x6b, 0xde, 0xff, 0x49, 0xa3, 0x9f, 0xf1, 0x84, 0xc2, - 0x1a, 0x68, 0xe4, 0x18, 0x68, 0x79, 0x10, 0x66, 0x3a, 0x5c, 0xde, 0xf2, 0x54, 0x4d, 0xe3, 0x76, 0xab, 0xf5, 0x43, - 0xb5, 0x62, 0xbd, 0xa9, 0x01, 0x5d, 0xbb, 0x60, 0xb3, 0xda, 0x3a, 0xce, 0x68, 0x89, 0x6d, 0xcb, 0xb9, 0xb0, 0x4b, - 0x5e, 0xb0, 0x4c, 0x47, 0x93, 0x59, 0x5b, 0x94, 0xdb, 0x1a, 0x27, 0xcf, 0xa7, 0xac, 0xe0, 0xaa, 0x57, 0xff, 0xaa, - 0x3a, 0xde, 0x5e, 0xfd, 0xb5, 0x91, 0x43, 0x97, 0xa6, 0x86, 0xbd, 0xf4, 0xbc, 0x82, 0x8f, 0xed, 0xd5, 0xff, 0x4a, - 0x8b, 0x70, 0x03, 0x31, 0xb1, 0x5f, 0x03, 0xad, 0xbd, 0x39, 0x17, 0x60, 0x92, 0x39, 0xc4, 0xdf, 0x80, 0x42, 0x42, - 0xb3, 0x24, 0x84, 0x11, 0xed, 0x35, 0xf7, 0x8e, 0x0b, 0x36, 0x43, 0x0e, 0x10, 0xd1, 0xc3, 0x6e, 0xc1, 0x66, 0xeb, - 0x48, 0x57, 0x5f, 0x6a, 0x14, 0xa1, 0x19, 0x9f, 0xe4, 0x71, 0xc2, 0x00, 0x7d, 0xd7, 0x11, 0xcb, 0x15, 0x57, 0xf7, - 0xcd, 0x42, 0xdc, 0x2e, 0x53, 0x2e, 0xe7, 0x19, 0xbd, 0x8f, 0xc7, 0x19, 0xbb, 0xeb, 0xe9, 0x52, 0x4d, 0xae, 0xd8, - 0x4c, 0xda, 0xb2, 0x3d, 0x48, 0x6f, 0xa6, 0xc6, 0x6c, 0x02, 0xa0, 0x27, 0x6e, 0x37, 0xf7, 0x4f, 0x74, 0x2c, 0xf7, - 0x18, 0x95, 0xac, 0x29, 0x16, 0x6a, 0xaf, 0x25, 0x7b, 0x33, 0x9e, 0x37, 0xed, 0x40, 0x4e, 0x5a, 0xf3, 0xbb, 0xde, - 0x36, 0xe4, 0xbd, 0xfe, 0x23, 0x76, 0x37, 0xa7, 0x79, 0xca, 0xd2, 0xa5, 0x57, 0xad, 0x03, 0xf5, 0xfc, 0x52, 0x71, - 0xae, 0xa6, 0x4d, 0x6d, 0xeb, 0x15, 0x76, 0x72, 0xf4, 0x0d, 0xd4, 0x7a, 0xd4, 0xc2, 0xe6, 0xff, 0xa3, 0x36, 0xf2, - 0x2b, 0xef, 0x41, 0xd8, 0x25, 0x3e, 0xbe, 0x6f, 0xc2, 0xdf, 0x25, 0xf8, 0x16, 0xf1, 0x84, 0x66, 0x16, 0x22, 0x33, - 0x9e, 0xa6, 0x59, 0x6d, 0x44, 0x17, 0x5e, 0x67, 0x6d, 0xb4, 0x84, 0xf9, 0xc7, 0xad, 0xbd, 0xd6, 0x9e, 0x9e, 0x8b, - 0xdd, 0xe6, 0x27, 0x27, 0x0f, 0x8f, 0x1f, 0xb1, 0x5e, 0xc6, 0x73, 0x56, 0x9b, 0xea, 0x77, 0x41, 0xed, 0x37, 0xdc, - 0xb1, 0x0d, 0xb7, 0xf7, 0xda, 0x7b, 0x27, 0xad, 0x1f, 0xdc, 0x6e, 0xcd, 0xd8, 0x58, 0xc5, 0xed, 0xd3, 0xf9, 0x5d, - 0x7d, 0xfb, 0x9e, 0xb9, 0xa6, 0x6f, 0x0b, 0x3a, 0x8f, 0x73, 0x01, 0x7f, 0x7a, 0xb0, 0xc9, 0xc6, 0x99, 0xb8, 0x8d, - 0xa7, 0x3c, 0x4d, 0x59, 0x6e, 0x0a, 0x94, 0x89, 0x2c, 0xcb, 0xf8, 0x5c, 0x72, 0xb3, 0x1a, 0x16, 0x77, 0xbb, 0x1b, - 0x50, 0xf5, 0x07, 0x74, 0xec, 0x0d, 0xa8, 0x5b, 0x0d, 0xa8, 0xea, 0xdf, 0x1f, 0x61, 0x67, 0x63, 0xae, 0xba, 0x54, - 0xaf, 0x86, 0x49, 0x7f, 0x2d, 0xa4, 0x02, 0x98, 0x97, 0x46, 0x1a, 0x40, 0xc5, 0x9b, 0x23, 0xa6, 0x6e, 0x19, 0xcb, - 0xbf, 0x3d, 0x88, 0x8b, 0x58, 0xe4, 0xd9, 0xbd, 0xf9, 0x5c, 0xfa, 0x5d, 0xd2, 0x85, 0x12, 0xeb, 0x68, 0xc4, 0x73, - 0x5a, 0xdc, 0xdf, 0x48, 0x96, 0x4b, 0x51, 0xdc, 0x88, 0xf1, 0x78, 0xf9, 0x2d, 0xd2, 0xf2, 0x10, 0xad, 0x23, 0xc9, - 0xf3, 0x49, 0xc6, 0x0c, 0x51, 0xd2, 0x88, 0x60, 0x89, 0xb9, 0x69, 0x57, 0x37, 0x59, 0x1b, 0xb4, 0xbf, 0xf3, 0x74, - 0xbb, 0xc3, 0x38, 0x6e, 0xde, 0xb2, 0xd1, 0x17, 0xae, 0x0c, 0x9e, 0x35, 0xe5, 0x2d, 0x78, 0xbc, 0xe8, 0x65, 0x98, - 0xb3, 0x62, 0xe9, 0x68, 0x78, 0xcb, 0xa3, 0x3a, 0x51, 0x92, 0xf1, 0x19, 0x55, 0xcc, 0xa3, 0x54, 0x65, 0x27, 0x93, - 0x82, 0xa7, 0xdb, 0x38, 0xd2, 0x83, 0xe4, 0xa6, 0x33, 0xa8, 0x82, 0x9e, 0x16, 0xb3, 0x5c, 0xc6, 0x05, 0x9b, 0x33, - 0xaa, 0xc2, 0x63, 0xdc, 0x1e, 0x17, 0xa8, 0x37, 0xa1, 0xf3, 0x18, 0xf0, 0xc2, 0x75, 0xd9, 0x86, 0x25, 0xd8, 0xde, - 0xae, 0xeb, 0xcf, 0xf8, 0x8b, 0xd4, 0x87, 0x97, 0xa2, 0xa3, 0x26, 0x84, 0x1f, 0x63, 0x45, 0xb9, 0xc5, 0x79, 0xae, - 0x11, 0x56, 0xaf, 0xcf, 0xe6, 0x26, 0xf5, 0x8f, 0xa0, 0x93, 0x56, 0xcb, 0xf5, 0xd3, 0x34, 0x75, 0xe2, 0x76, 0xd4, - 0x65, 0xb3, 0x5d, 0xe4, 0xa1, 0x4e, 0x0b, 0xdb, 0x9d, 0xf9, 0xdd, 0x9e, 0xfe, 0xa7, 0xb5, 0xd7, 0xda, 0xa6, 0x7d, - 0xdb, 0xcb, 0x74, 0x8c, 0x1c, 0x62, 0x29, 0x31, 0x8f, 0xdb, 0x6c, 0xd6, 0x5b, 0x48, 0x38, 0xe7, 0x34, 0x69, 0xd6, - 0xe7, 0xe7, 0x5a, 0xcf, 0x04, 0xd0, 0x88, 0xf2, 0x1c, 0x8e, 0x15, 0x73, 0xb4, 0x42, 0x1f, 0x52, 0x80, 0x1d, 0xf8, - 0xce, 0x46, 0xeb, 0xc3, 0x6a, 0xed, 0x55, 0x03, 0x83, 0x7f, 0xd6, 0x9f, 0x2b, 0xc6, 0xf4, 0x05, 0xf3, 0x04, 0x03, - 0xde, 0x88, 0xba, 0xab, 0x96, 0x15, 0x06, 0x52, 0x55, 0xc9, 0x28, 0xda, 0x95, 0x62, 0x46, 0xef, 0x8c, 0x4f, 0xc5, - 0x8c, 0xe7, 0x60, 0xb1, 0x85, 0xb0, 0xf2, 0x6c, 0xdb, 0xa7, 0x7e, 0x43, 0xa9, 0x0a, 0xa1, 0xe1, 0xc3, 0x4e, 0xd4, - 0xed, 0x22, 0xdc, 0xc2, 0x9d, 0x6e, 0xd7, 0x13, 0x46, 0xc6, 0x6a, 0x57, 0xd1, 0x5d, 0x25, 0xf3, 0x1d, 0x25, 0x8f, - 0x74, 0xa3, 0x47, 0xed, 0x56, 0x0b, 0x6b, 0xbf, 0xf1, 0xb2, 0x30, 0xcb, 0x77, 0x34, 0xdb, 0x6e, 0xb5, 0xa0, 0x59, - 0xf8, 0x63, 0xe7, 0xf5, 0x0b, 0x59, 0xb6, 0xe2, 0x16, 0x6e, 0xc7, 0x6d, 0xdc, 0x89, 0x3b, 0xf8, 0x38, 0x3e, 0xc6, - 0x27, 0xf1, 0x09, 0xee, 0xc6, 0x5d, 0x7c, 0x1a, 0x9f, 0xe2, 0x87, 0xf1, 0x43, 0x7c, 0x16, 0x9f, 0xe1, 0x47, 0xf1, - 0x23, 0x7c, 0x19, 0xb7, 0x5b, 0xf8, 0x71, 0xdc, 0x6e, 0xe3, 0xab, 0xb8, 0xdd, 0xc1, 0x4f, 0xe2, 0xf6, 0x31, 0x7e, - 0x1a, 0xb7, 0x4f, 0xf0, 0xb3, 0xb8, 0xdd, 0xc5, 0x14, 0x72, 0x47, 0x90, 0x9b, 0x40, 0x6e, 0x0a, 0xb9, 0x0c, 0x72, - 0xc7, 0x71, 0xbb, 0xbb, 0xc6, 0xd2, 0xc4, 0x9a, 0x08, 0x5a, 0xed, 0xce, 0xf1, 0x49, 0xf7, 0xf4, 0xe1, 0xd9, 0xa3, - 0xcb, 0xc7, 0x57, 0x4f, 0x9e, 0x3e, 0x0b, 0x86, 0x78, 0xa4, 0x5d, 0x3e, 0xa4, 0x1c, 0xf0, 0x83, 0x76, 0x77, 0x88, - 0x6f, 0xdc, 0x67, 0xc8, 0x0f, 0x3a, 0x27, 0x2d, 0x74, 0x71, 0x71, 0x32, 0x6c, 0x94, 0xb9, 0xef, 0xb5, 0xa7, 0x49, - 0x95, 0x45, 0x08, 0x09, 0x21, 0x07, 0xe1, 0x7b, 0x5d, 0xef, 0x3d, 0x0b, 0x79, 0x54, 0xa0, 0x83, 0x03, 0xfd, 0x63, - 0xe2, 0x7e, 0x8c, 0xdc, 0x0f, 0xea, 0x2d, 0xd2, 0x1d, 0x0d, 0xad, 0xab, 0xb1, 0x2a, 0x0d, 0xfd, 0x4b, 0x1b, 0x9a, - 0x3d, 0x6e, 0xad, 0xd9, 0xff, 0x2b, 0x30, 0xd6, 0x2a, 0xe4, 0xc4, 0x68, 0x84, 0xba, 0x7d, 0x46, 0x96, 0x45, 0xdc, - 0xe9, 0x76, 0x0f, 0x7e, 0x19, 0xf0, 0x41, 0x7b, 0x38, 0x3c, 0x6c, 0x3f, 0xc4, 0x93, 0x32, 0xa1, 0x63, 0x12, 0x46, - 0x65, 0xc2, 0xb1, 0x49, 0xa0, 0xb1, 0xa9, 0x0d, 0x49, 0x27, 0x3a, 0x09, 0x4a, 0xac, 0x63, 0xdd, 0xf6, 0x43, 0xd3, - 0xf6, 0x23, 0x30, 0xa3, 0xd2, 0xcd, 0xdb, 0xa6, 0xcf, 0xcf, 0x4f, 0x56, 0xb6, 0x51, 0x3c, 0x89, 0x6d, 0x6b, 0x2e, - 0xf1, 0x64, 0x38, 0xc4, 0x23, 0x9d, 0xd8, 0xad, 0x12, 0x4f, 0x87, 0x43, 0xdb, 0xd5, 0x23, 0xdd, 0xd5, 0xc3, 0x2a, - 0xeb, 0x6c, 0x38, 0xd4, 0x5d, 0x22, 0xeb, 0x34, 0x2f, 0xd5, 0xde, 0xd7, 0x52, 0x71, 0xc1, 0xcf, 0x3b, 0xdd, 0x6e, - 0x1f, 0x30, 0x4c, 0x1b, 0xc3, 0x3a, 0x18, 0xdd, 0x7a, 0x30, 0xba, 0x87, 0xdf, 0xfd, 0x11, 0x8d, 0x6f, 0x68, 0x09, - 0xa4, 0x7e, 0xf0, 0x5f, 0x41, 0x43, 0x69, 0x98, 0xeb, 0x3f, 0x13, 0xf3, 0x67, 0x84, 0x1a, 0x5f, 0x29, 0x80, 0x1b, - 0x54, 0x31, 0x4e, 0x97, 0xaa, 0x7b, 0xfc, 0x42, 0xc1, 0xb7, 0x65, 0x2a, 0x33, 0xda, 0x5f, 0x4d, 0x6f, 0x47, 0xab, - 0xa9, 0xfc, 0x8a, 0xfe, 0x0c, 0xff, 0x94, 0x87, 0xe1, 0xa0, 0xd9, 0x88, 0xd8, 0x9f, 0x29, 0x38, 0xd1, 0xf4, 0xe3, - 0x94, 0x4d, 0x50, 0x7f, 0xf0, 0xa7, 0xc4, 0xc3, 0x86, 0x97, 0xf1, 0xc3, 0x76, 0x0a, 0xb8, 0xd8, 0x6c, 0x26, 0x86, - 0x3f, 0xa0, 0x3e, 0xea, 0xff, 0x29, 0x0f, 0xff, 0x44, 0x0f, 0x8e, 0xaa, 0xb9, 0xfc, 0x2e, 0xec, 0x16, 0xae, 0xe2, - 0xee, 0x1c, 0x96, 0x5b, 0x98, 0xe1, 0x76, 0x93, 0x41, 0x94, 0x32, 0xf0, 0xc1, 0x26, 0xa1, 0x68, 0xf0, 0xa3, 0xe3, - 0x16, 0xfa, 0xa1, 0xdd, 0x01, 0xad, 0x42, 0x53, 0x1e, 0x6e, 0x6f, 0xfa, 0xa2, 0x79, 0x8c, 0x1f, 0x35, 0x0b, 0xdc, - 0x46, 0xb8, 0xd9, 0x76, 0xea, 0xde, 0x41, 0x1e, 0xb6, 0x10, 0xce, 0xc3, 0x33, 0xf8, 0xe7, 0x04, 0x0d, 0xab, 0x0d, - 0x79, 0x4d, 0x37, 0x7b, 0x07, 0x87, 0x51, 0x12, 0xe6, 0x0d, 0x7e, 0x74, 0xda, 0x42, 0x3f, 0x9c, 0xea, 0x8e, 0xd8, - 0xa1, 0xda, 0xd1, 0x95, 0xc0, 0x27, 0x4d, 0x01, 0x1d, 0xb5, 0xca, 0x7e, 0x64, 0xd8, 0x45, 0x58, 0x86, 0xc7, 0xf0, - 0x4f, 0xdb, 0xef, 0xe7, 0xd7, 0xad, 0x7e, 0xf4, 0xbc, 0xdb, 0x38, 0xea, 0x1a, 0xff, 0xd3, 0xdc, 0x5c, 0x06, 0x37, - 0xd8, 0x45, 0x5b, 0xdf, 0x62, 0xb5, 0x8f, 0xe0, 0x03, 0x61, 0x75, 0x48, 0x72, 0xcc, 0x0e, 0xc1, 0x71, 0x15, 0xec, - 0x35, 0xf2, 0xf3, 0xe3, 0x5e, 0xde, 0x68, 0x20, 0x90, 0x0f, 0x0f, 0x49, 0xbb, 0xa9, 0x9a, 0x0c, 0xc3, 0xef, 0x06, - 0x29, 0xa3, 0xa1, 0xc9, 0xaa, 0xd7, 0x2b, 0xdb, 0xab, 0xb9, 0xf2, 0x76, 0xd8, 0x01, 0x62, 0x62, 0x3f, 0x54, 0x4d, - 0x86, 0x8e, 0x64, 0x23, 0x54, 0xe7, 0xac, 0x7f, 0x1a, 0xb7, 0x90, 0xc6, 0xce, 0xbc, 0x1f, 0xb2, 0x26, 0x87, 0xf4, - 0x4e, 0x1c, 0xf2, 0xa6, 0x82, 0x5f, 0x27, 0x1e, 0xb4, 0x24, 0xe0, 0x5d, 0xe5, 0x86, 0x53, 0x1c, 0x75, 0xba, 0x5d, - 0x2c, 0x09, 0x8f, 0x26, 0xfa, 0x57, 0x4e, 0x78, 0x34, 0xd2, 0xbf, 0x04, 0x29, 0xe1, 0x65, 0x7a, 0xc7, 0x05, 0xf1, - 0x56, 0x55, 0xa7, 0x50, 0x58, 0xd0, 0x02, 0x1d, 0x75, 0xdc, 0x7d, 0x38, 0x9e, 0xba, 0x39, 0x80, 0xfc, 0x5f, 0x68, - 0x53, 0x48, 0xd1, 0x2c, 0x70, 0x46, 0xe8, 0x45, 0xd4, 0xed, 0x4f, 0x8f, 0xc2, 0x4e, 0x53, 0x34, 0x0b, 0x14, 0x4f, - 0x8f, 0x74, 0x4d, 0x9c, 0x90, 0x2b, 0x6a, 0x5a, 0xc3, 0x53, 0xb8, 0xc4, 0x4c, 0x48, 0x72, 0x78, 0xda, 0x6a, 0x44, - 0x5d, 0x84, 0x07, 0xc9, 0xaa, 0x85, 0xb3, 0xd5, 0xaa, 0x85, 0xa9, 0xbf, 0x0c, 0xd2, 0x01, 0xa4, 0x54, 0x51, 0x6d, - 0x06, 0xa5, 0xe9, 0xf3, 0x50, 0xc1, 0x85, 0xbc, 0x02, 0x37, 0x17, 0x05, 0x0e, 0x38, 0x31, 0xb7, 0x37, 0x61, 0x48, - 0x87, 0xe5, 0x1b, 0xfb, 0x4a, 0xab, 0x2b, 0xe9, 0xd6, 0xd5, 0x8e, 0xfc, 0x57, 0x19, 0xfe, 0x2e, 0xb0, 0x49, 0xab, - 0x8a, 0xbd, 0xa6, 0xdb, 0xc5, 0x7e, 0xa5, 0x5b, 0xc5, 0xde, 0xec, 0x28, 0x76, 0xbd, 0x5d, 0xec, 0xa3, 0xf0, 0x54, - 0x6c, 0xfc, 0x87, 0xe3, 0xd3, 0x56, 0xe3, 0x18, 0x90, 0xf5, 0xf8, 0xb4, 0x55, 0x15, 0x7a, 0x40, 0xab, 0xb5, 0x52, - 0xe4, 0x0b, 0x35, 0x4e, 0x06, 0xdc, 0x79, 0x3b, 0xeb, 0x85, 0x33, 0xbe, 0xd6, 0xa5, 0x63, 0xf5, 0xa0, 0x0b, 0x46, - 0x1c, 0x52, 0x53, 0x3b, 0x35, 0x38, 0x1d, 0xf6, 0xa7, 0x2c, 0x6c, 0x40, 0x2a, 0x8a, 0xc7, 0xca, 0xfe, 0x42, 0xe5, - 0x5d, 0xee, 0x47, 0x01, 0x49, 0x9d, 0x21, 0xc2, 0x82, 0x34, 0xd4, 0xe0, 0x78, 0xa8, 0xcf, 0xbb, 0x02, 0x7e, 0x9f, - 0xe8, 0xdf, 0xa5, 0x26, 0xc5, 0x7a, 0x22, 0x4c, 0x6f, 0x47, 0x41, 0x5f, 0x92, 0xd7, 0x34, 0xd4, 0xc6, 0xe5, 0x28, - 0x2e, 0x33, 0xe4, 0x57, 0xc8, 0x78, 0x53, 0x66, 0x48, 0x72, 0x25, 0xed, 0x6f, 0xbc, 0x2c, 0x62, 0x30, 0x34, 0xc1, - 0x93, 0x18, 0x8c, 0x4c, 0xf0, 0x28, 0x96, 0xe0, 0x08, 0x41, 0x63, 0xe6, 0x99, 0xaf, 0x5f, 0x5a, 0xd5, 0x95, 0xbe, - 0x6e, 0x25, 0x1a, 0x4b, 0x7b, 0x0c, 0x4e, 0x8a, 0x8f, 0x22, 0x84, 0xbf, 0x0d, 0x85, 0x30, 0x83, 0x36, 0x19, 0xc2, - 0x3c, 0x2a, 0x08, 0xa4, 0x61, 0x1e, 0x4d, 0x08, 0x83, 0x26, 0x79, 0x34, 0x22, 0x6c, 0xd0, 0xf1, 0xd0, 0xe4, 0xa9, - 0x86, 0x1d, 0x00, 0x87, 0xd7, 0x6f, 0xb0, 0x95, 0x69, 0x1c, 0xae, 0xc6, 0xa1, 0x09, 0x49, 0x58, 0x1e, 0xc2, 0x2c, - 0x60, 0x73, 0xea, 0x9f, 0x9d, 0x2a, 0xee, 0x23, 0x8f, 0xa8, 0xa6, 0xde, 0x9f, 0x81, 0xac, 0x86, 0x0f, 0x96, 0x6c, - 0x8d, 0xf7, 0x1e, 0x2c, 0xe5, 0xfa, 0x07, 0xf8, 0x93, 0xdb, 0x3f, 0x4a, 0x9f, 0x7e, 0x6b, 0xf4, 0x39, 0x86, 0x62, - 0x3b, 0x4a, 0xa1, 0xcf, 0xce, 0x0f, 0x2e, 0x27, 0xcb, 0xbb, 0x38, 0x48, 0x69, 0xf1, 0x25, 0xc0, 0x9f, 0xe2, 0x20, - 0x03, 0x46, 0x30, 0xc0, 0x1f, 0xe3, 0xa0, 0x60, 0x01, 0xfe, 0x23, 0x0e, 0x46, 0xd9, 0x22, 0xc0, 0x1f, 0xe2, 0x60, - 0x52, 0x04, 0xf8, 0x3d, 0x68, 0x29, 0x53, 0xbe, 0x98, 0x05, 0xf8, 0xf7, 0x38, 0x90, 0xda, 0x0d, 0x00, 0x5f, 0xc6, - 0x01, 0x63, 0x01, 0x7e, 0x17, 0x07, 0x22, 0x0b, 0xf0, 0x75, 0x1c, 0x88, 0x22, 0xc0, 0x8f, 0xe3, 0xa0, 0xa0, 0x01, - 0xbe, 0x8a, 0x03, 0x28, 0x34, 0x09, 0xf0, 0x93, 0x38, 0x80, 0x96, 0x65, 0x80, 0xdf, 0xc6, 0x01, 0xcf, 0x03, 0xfc, - 0x5b, 0x1c, 0xa8, 0x45, 0xf1, 0xf7, 0x42, 0x70, 0x19, 0xe0, 0xa7, 0x71, 0x30, 0xe5, 0x01, 0x7e, 0x13, 0x07, 0x85, - 0x08, 0xf0, 0xeb, 0x38, 0xa0, 0x59, 0x80, 0x5f, 0xc5, 0x41, 0xc6, 0x02, 0xfc, 0x6b, 0x1c, 0xa4, 0x2c, 0xc0, 0x2f, - 0xe3, 0xe0, 0x9e, 0x65, 0x99, 0x08, 0xf0, 0xb3, 0x38, 0x60, 0x79, 0x80, 0x7f, 0x89, 0x83, 0x64, 0x1a, 0xe0, 0x9f, - 0xe2, 0x80, 0x16, 0x5f, 0x64, 0x80, 0x9f, 0xc7, 0x01, 0xa3, 0x01, 0x7e, 0x61, 0x3a, 0x9a, 0x04, 0xf8, 0xe7, 0x38, - 0xb8, 0x9d, 0x06, 0x6b, 0x9c, 0xe7, 0x64, 0xf9, 0x9a, 0x27, 0xec, 0x0f, 0x16, 0x07, 0xe3, 0xd6, 0xf8, 0x6c, 0x3c, - 0x0e, 0x30, 0xcd, 0x15, 0xff, 0x7b, 0xc1, 0x6e, 0x9f, 0x2a, 0x48, 0xa4, 0x6c, 0x94, 0x3e, 0x0c, 0x30, 0xfd, 0x7b, - 0x41, 0xe3, 0x60, 0x3c, 0xd6, 0x05, 0xfe, 0x5e, 0xd0, 0x19, 0x2d, 0xde, 0xb2, 0x38, 0x78, 0x38, 0x1e, 0x8f, 0xd3, - 0x93, 0x00, 0xd3, 0x7f, 0x16, 0x1f, 0x75, 0x0b, 0xba, 0xc0, 0x88, 0xf1, 0x09, 0xd4, 0xed, 0x8e, 0xbb, 0x69, 0x12, - 0xe0, 0x11, 0x97, 0x7f, 0x2f, 0xe0, 0x7b, 0xcc, 0x4e, 0x92, 0x93, 0x00, 0x8f, 0x32, 0x9a, 0x7c, 0x89, 0x83, 0x96, - 0xfe, 0x95, 0xff, 0xc2, 0xd2, 0xd7, 0x33, 0xa1, 0x75, 0xf8, 0x63, 0x36, 0x4a, 0xd2, 0x00, 0xeb, 0xc1, 0x8c, 0xe1, - 0xef, 0x57, 0xfe, 0x8e, 0xa9, 0x38, 0x38, 0xa3, 0x9d, 0x11, 0xeb, 0x04, 0x78, 0xf4, 0xe6, 0x36, 0x8f, 0x03, 0xda, - 0xed, 0xd0, 0x0e, 0x0d, 0xf0, 0x68, 0x51, 0x64, 0xf7, 0xb7, 0x42, 0xa4, 0x00, 0x84, 0xd1, 0xd9, 0xd9, 0xc3, 0x00, - 0x27, 0xf4, 0x57, 0x05, 0xb5, 0xbb, 0xe3, 0x47, 0x8c, 0xb6, 0x02, 0xfc, 0x0b, 0x2d, 0xd4, 0xc7, 0x85, 0xb4, 0x03, - 0x6d, 0x41, 0x8a, 0x48, 0xde, 0x81, 0x7e, 0x3b, 0x48, 0x3b, 0xa7, 0x8f, 0xda, 0x2c, 0xc0, 0xc9, 0xf5, 0x6b, 0xe8, - 0xed, 0xe1, 0xb8, 0xdb, 0x82, 0x8f, 0x1c, 0x04, 0x45, 0x56, 0x40, 0x23, 0xa7, 0x27, 0x8f, 0xba, 0x2c, 0xd5, 0x89, - 0x92, 0x67, 0x5f, 0xf4, 0xec, 0xcf, 0x60, 0x3e, 0x49, 0xc1, 0x67, 0x52, 0xe4, 0x71, 0x90, 0x26, 0xed, 0x93, 0x63, - 0x48, 0xb8, 0xa7, 0xb9, 0x03, 0xce, 0x1d, 0x54, 0x3d, 0x1b, 0x05, 0xf8, 0xce, 0xa4, 0x9e, 0x8d, 0xf4, 0xc7, 0xe4, - 0xdd, 0xaf, 0xf9, 0x9b, 0x34, 0x0e, 0x46, 0x67, 0x67, 0xa7, 0x2d, 0x48, 0xf8, 0x40, 0xef, 0xe3, 0x80, 0x3e, 0x82, - 0xff, 0x20, 0xfb, 0xe3, 0x33, 0xe8, 0x10, 0x46, 0x78, 0x37, 0xf9, 0xe8, 0xe7, 0x7c, 0x99, 0xd2, 0x2f, 0x3c, 0x0e, - 0x46, 0xe9, 0xe8, 0xe1, 0x29, 0xd4, 0x9b, 0xd1, 0xc9, 0x33, 0x45, 0xa1, 0xdd, 0x56, 0x4b, 0xb7, 0xfc, 0x8e, 0x7f, - 0x65, 0xba, 0x7a, 0xb7, 0x7b, 0x3a, 0xea, 0xc0, 0x08, 0xae, 0x41, 0xc3, 0x01, 0xe3, 0x39, 0x4b, 0x74, 0x83, 0xd7, - 0xc9, 0xd3, 0x34, 0x0e, 0x1e, 0x3d, 0x3a, 0xee, 0x24, 0x49, 0x80, 0xef, 0x3e, 0xa6, 0xa6, 0xb6, 0xce, 0x93, 0x00, - 0xfb, 0x38, 0x60, 0x8f, 0x1e, 0x9d, 0x3e, 0xa4, 0xf0, 0xfd, 0x5c, 0xb7, 0x75, 0x36, 0x1e, 0x25, 0x67, 0xd0, 0xd6, - 0xef, 0x30, 0x9d, 0x93, 0xb3, 0xe3, 0x54, 0xf7, 0xf5, 0xbb, 0x1e, 0x75, 0x67, 0x7c, 0x32, 0x3e, 0xd1, 0x99, 0x7a, - 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x0e, 0x12, 0x96, 0xb6, 0x03, 0x7c, 0x67, 0x17, 0xee, 0xd1, 0x49, 0xab, 0x95, 0x1e, - 0x07, 0x38, 0xbd, 0x9c, 0xcf, 0xdf, 0x6a, 0x08, 0xb6, 0x4f, 0x1e, 0x99, 0x6f, 0xf9, 0xe5, 0x1e, 0x9a, 0x1e, 0x69, - 0xa0, 0xa5, 0x7c, 0xa6, 0x5b, 0x3e, 0x7d, 0x04, 0xff, 0xe9, 0x6f, 0xdd, 0x74, 0xf9, 0x2d, 0xd2, 0x89, 0x59, 0x94, - 0x36, 0x7b, 0xd4, 0x82, 0x1a, 0x63, 0xfe, 0x71, 0x54, 0x70, 0x40, 0xa3, 0x51, 0x07, 0xfe, 0x2f, 0xc0, 0xe3, 0xec, - 0xfa, 0xb5, 0xc5, 0xd9, 0xf1, 0x98, 0x8e, 0x5b, 0x01, 0x1e, 0x8b, 0x8f, 0x52, 0x7d, 0xb8, 0xcc, 0xe3, 0xa0, 0xd3, - 0x39, 0x1b, 0xe9, 0x32, 0x8b, 0x5f, 0x24, 0xd7, 0x78, 0xdc, 0xd2, 0xad, 0x4c, 0xe8, 0x5b, 0x39, 0xba, 0x16, 0xb0, - 0x92, 0xf0, 0x5f, 0x80, 0x27, 0xa0, 0x16, 0xb3, 0xad, 0x9c, 0x99, 0xed, 0x30, 0x79, 0xa7, 0x51, 0x33, 0x7d, 0x08, - 0xf0, 0x72, 0xcb, 0x98, 0x52, 0xda, 0xed, 0xb4, 0x02, 0xac, 0x47, 0x7d, 0xd6, 0x82, 0xff, 0x02, 0x6c, 0x20, 0xa7, - 0xe1, 0x3a, 0xf9, 0xf8, 0xec, 0xe5, 0x6d, 0x1c, 0xd0, 0x74, 0x3c, 0x86, 0x25, 0xd1, 0x93, 0x71, 0xc5, 0xa6, 0x22, - 0x67, 0xf7, 0xbf, 0xde, 0xda, 0xed, 0xa2, 0x13, 0x94, 0x85, 0xce, 0xe9, 0xa3, 0xd1, 0x49, 0x80, 0xdf, 0xa6, 0x9c, - 0xe6, 0xb0, 0x4a, 0x49, 0xda, 0x4d, 0xba, 0x89, 0x4e, 0x98, 0x88, 0x38, 0x38, 0x81, 0x25, 0xef, 0x04, 0x98, 0x7f, - 0xbd, 0xbe, 0x37, 0xe8, 0x06, 0xb5, 0x2d, 0x82, 0x8c, 0x5b, 0xec, 0xf4, 0x2c, 0x09, 0x70, 0x46, 0xbf, 0x3e, 0xfb, - 0xb5, 0x88, 0x03, 0x76, 0xca, 0x4e, 0xc7, 0xd4, 0x7d, 0xff, 0x21, 0xa7, 0xba, 0x46, 0x6b, 0xdc, 0x85, 0xa4, 0xdb, - 0x5c, 0x8f, 0xf5, 0x61, 0x32, 0xd6, 0x18, 0xf2, 0x6a, 0x26, 0xf2, 0xe4, 0xe9, 0x78, 0x2c, 0x0c, 0x16, 0x53, 0xd8, - 0x84, 0x9f, 0x00, 0xda, 0x34, 0x4d, 0xcf, 0xd8, 0x69, 0x80, 0x3f, 0x99, 0x5d, 0x62, 0x27, 0xf0, 0xc9, 0x60, 0x36, - 0xb3, 0xbb, 0xfd, 0x93, 0x01, 0x0a, 0xcc, 0x77, 0x4c, 0xc7, 0x34, 0xed, 0x04, 0xf8, 0x93, 0x86, 0x4b, 0x7a, 0x0c, - 0xff, 0x41, 0x01, 0xe8, 0xec, 0x51, 0x8b, 0xb1, 0x47, 0x2d, 0xfd, 0xe5, 0xe7, 0xd9, 0x99, 0x8f, 0x4e, 0x93, 0x76, - 0x80, 0x3f, 0x59, 0x74, 0x1c, 0x8f, 0x69, 0x0b, 0xd0, 0xf1, 0x93, 0x45, 0xc7, 0x4e, 0x6b, 0xd4, 0xa1, 0xfa, 0xdb, - 0x60, 0xcd, 0xd9, 0xc3, 0x84, 0xc1, 0xe4, 0x3e, 0x19, 0x84, 0x7c, 0xf8, 0xf0, 0xec, 0xec, 0xd1, 0x23, 0xf8, 0xd4, - 0x6d, 0x97, 0x9f, 0x52, 0x5d, 0x66, 0x1a, 0xc9, 0x5a, 0xc9, 0x09, 0xd0, 0xc9, 0x4f, 0x7a, 0x8c, 0xe3, 0xf1, 0x98, - 0xb5, 0x02, 0x9c, 0xf1, 0x19, 0x33, 0x98, 0x60, 0x7e, 0xeb, 0x8e, 0x8e, 0x3b, 0x49, 0x7a, 0xdc, 0x09, 0x70, 0xf6, - 0xf6, 0x99, 0x9e, 0x4d, 0x0b, 0x66, 0xef, 0xb6, 0x9c, 0xc3, 0x9a, 0x19, 0x7d, 0x03, 0x83, 0x84, 0x95, 0x86, 0xca, - 0xef, 0x3d, 0x7a, 0x78, 0x7a, 0x9a, 0xa4, 0x30, 0xd0, 0xf7, 0xd0, 0x2d, 0x80, 0xf1, 0xbd, 0xd9, 0x7c, 0x23, 0xda, - 0xed, 0xc2, 0x74, 0xdf, 0xcf, 0x17, 0xc5, 0xfc, 0x55, 0x1c, 0x3c, 0x3a, 0x7e, 0xd8, 0x4a, 0x47, 0x01, 0x7e, 0x6f, - 0x27, 0x78, 0x9c, 0x8c, 0x8e, 0x1f, 0xb6, 0x03, 0xfc, 0x5e, 0xef, 0xb7, 0x87, 0xa3, 0xd3, 0x33, 0x38, 0x37, 0xde, - 0xcb, 0x79, 0xf1, 0x76, 0xa2, 0x0b, 0x8c, 0xe9, 0x23, 0x68, 0xf6, 0x37, 0xbd, 0x1b, 0xd3, 0x36, 0x6c, 0xe4, 0xf7, - 0x7a, 0x93, 0x69, 0x3c, 0x79, 0xd8, 0xee, 0x9e, 0x75, 0x03, 0x3c, 0xe3, 0x69, 0x0e, 0x04, 0x5e, 0x6f, 0x94, 0x47, - 0xed, 0x47, 0x0f, 0x5b, 0x01, 0x9e, 0xbd, 0x55, 0xc9, 0x47, 0x3a, 0xd3, 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa9, - 0xee, 0xdf, 0x48, 0x4b, 0x8f, 0x59, 0x3b, 0xc0, 0x33, 0x91, 0x24, 0x54, 0xbe, 0x35, 0x09, 0xa3, 0x6e, 0x80, 0x73, - 0xfa, 0x95, 0xfe, 0x25, 0xdc, 0x66, 0x4a, 0x19, 0x4d, 0x75, 0x9a, 0xc6, 0xe1, 0x00, 0xbf, 0x4b, 0xe1, 0x16, 0x2e, - 0x0e, 0xc6, 0xe9, 0xb8, 0x0b, 0xe0, 0x01, 0x02, 0x64, 0xb0, 0x1b, 0xa0, 0x01, 0x5f, 0xe9, 0xe3, 0x51, 0x1c, 0x9c, - 0x8e, 0xce, 0x58, 0xe7, 0x38, 0xc0, 0x25, 0x35, 0xa2, 0x5d, 0xc8, 0xd7, 0x9f, 0x1f, 0xf5, 0x96, 0x3a, 0x31, 0x09, - 0x1a, 0x40, 0x29, 0x7d, 0xd8, 0x4a, 0x4f, 0x03, 0x3c, 0x7f, 0xcd, 0xdc, 0x1e, 0x63, 0x8c, 0x9d, 0x01, 0x2c, 0x21, - 0x49, 0x23, 0xd0, 0xd9, 0x78, 0xf4, 0xe8, 0x4c, 0x7f, 0x03, 0x18, 0xe8, 0x98, 0x31, 0x00, 0xd2, 0xfc, 0x35, 0x2b, - 0x01, 0x91, 0x8e, 0x1e, 0xb6, 0x80, 0xbe, 0xcc, 0xe9, 0x9c, 0xde, 0xd3, 0xdb, 0xa7, 0x73, 0x3d, 0xa7, 0x71, 0xda, - 0x0d, 0xf0, 0xfc, 0xf9, 0x2f, 0xf3, 0xc5, 0x78, 0xac, 0x27, 0x44, 0x47, 0x8f, 0x02, 0x3c, 0x67, 0xc5, 0x02, 0xd6, - 0xe8, 0xac, 0x7b, 0x3c, 0x0e, 0xb0, 0x45, 0xc3, 0xa4, 0x95, 0x8c, 0xe0, 0x9a, 0x71, 0x31, 0x8b, 0x83, 0x34, 0xa5, - 0xad, 0x14, 0x2e, 0x1d, 0xc5, 0xed, 0xaf, 0x85, 0x41, 0x23, 0xa6, 0xf1, 0xc1, 0xae, 0x21, 0xcc, 0x17, 0xe0, 0xf1, - 0x71, 0xc4, 0x92, 0x84, 0xda, 0xc4, 0xd3, 0xd3, 0xe3, 0x63, 0xc0, 0x3d, 0x33, 0x43, 0x83, 0x20, 0x6f, 0xe4, 0xfd, - 0xa8, 0x10, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, 0xfe, 0xb5, 0xa6, 0xab, 0xed, 0xd3, 0x47, 0xb0, 0x00, - 0x92, 0xa6, 0xe9, 0x2b, 0x73, 0xb8, 0x9d, 0x8d, 0x4e, 0xba, 0xed, 0xe3, 0x00, 0xbb, 0x8d, 0x40, 0xcf, 0x5a, 0x0f, - 0x3b, 0x50, 0x22, 0x4f, 0xef, 0x4d, 0x89, 0xf1, 0x09, 0x3d, 0x39, 0x6d, 0x05, 0xd8, 0x6d, 0x0d, 0x76, 0x36, 0xea, - 0x3e, 0x84, 0x4f, 0x39, 0x65, 0x59, 0xa6, 0xf1, 0xbb, 0x0b, 0x70, 0x91, 0xfc, 0x59, 0x4e, 0xe3, 0x80, 0xb6, 0xba, - 0x9d, 0x4e, 0x0a, 0x9f, 0xd9, 0x57, 0x56, 0xc4, 0x41, 0xd2, 0x82, 0xff, 0x02, 0xec, 0xed, 0x24, 0x36, 0x0a, 0xb0, - 0xc6, 0xbb, 0x53, 0xda, 0xd5, 0x7b, 0xdf, 0xee, 0xaa, 0xd6, 0x59, 0x0b, 0x36, 0xac, 0xdd, 0x54, 0xf6, 0x4b, 0xe6, - 0xe2, 0xd6, 0x92, 0x58, 0x1a, 0x60, 0x0f, 0x41, 0xc7, 0x0f, 0xc7, 0x01, 0x76, 0x3b, 0xee, 0xe4, 0xf4, 0xac, 0x03, - 0xa4, 0x4c, 0x01, 0xa1, 0x48, 0x3b, 0xa3, 0x13, 0x20, 0x4d, 0x8a, 0xbd, 0x36, 0x78, 0x12, 0x60, 0xf5, 0x54, 0xaa, - 0x57, 0x71, 0x90, 0x9e, 0x8d, 0xc6, 0xe9, 0x59, 0x80, 0x95, 0x98, 0x51, 0x25, 0x34, 0x05, 0x3c, 0x3e, 0x79, 0x18, - 0x60, 0x8d, 0xe6, 0x2d, 0xd6, 0x4a, 0x5b, 0x01, 0xb6, 0x47, 0x09, 0x63, 0x67, 0x1d, 0x98, 0xd6, 0xcf, 0xcf, 0x15, - 0xe0, 0x72, 0xca, 0x46, 0xc7, 0x01, 0x2e, 0xe9, 0xbd, 0x26, 0x44, 0xf0, 0x25, 0x67, 0xe2, 0x8b, 0x65, 0x3d, 0x80, - 0xd4, 0xb9, 0x0d, 0x0f, 0xcb, 0xf0, 0xf2, 0xd6, 0xa0, 0x11, 0xd5, 0x5b, 0xdc, 0xbb, 0x86, 0x7d, 0x42, 0x43, 0xc7, - 0xb6, 0x73, 0xb2, 0x5c, 0xe3, 0x32, 0xba, 0xe9, 0x17, 0x76, 0x2f, 0xc3, 0x1c, 0x4c, 0xe2, 0x6b, 0x29, 0x32, 0x47, - 0xce, 0x9e, 0xdf, 0xba, 0x6c, 0x82, 0x20, 0x29, 0x49, 0xab, 0x27, 0xcf, 0x9d, 0x1b, 0x69, 0x4f, 0x42, 0xcc, 0x03, - 0x48, 0x2f, 0x08, 0x25, 0x0a, 0x42, 0xc3, 0x18, 0x61, 0xd2, 0x59, 0xd7, 0x6b, 0x99, 0x52, 0x18, 0x7b, 0x7d, 0x4a, - 0xa8, 0x0b, 0x0a, 0x0f, 0x77, 0xc4, 0xf9, 0x40, 0x0c, 0x51, 0x4f, 0x10, 0x1d, 0xe2, 0xf9, 0x45, 0xae, 0xc2, 0x3c, - 0x1f, 0x14, 0x43, 0xdc, 0x3e, 0x45, 0x18, 0x82, 0x27, 0x90, 0x81, 0xb8, 0xb8, 0x68, 0x9f, 0x1e, 0x68, 0xa1, 0xef, - 0xe2, 0xe2, 0xcc, 0xfc, 0x80, 0x7f, 0x87, 0x55, 0xc0, 0x6a, 0x18, 0xdf, 0x63, 0xe6, 0x69, 0xf4, 0x34, 0x7f, 0xfd, - 0x98, 0xad, 0x56, 0xe1, 0x63, 0x46, 0x60, 0xc6, 0xf8, 0x31, 0x8b, 0xf4, 0xa5, 0x85, 0x71, 0x8d, 0x21, 0x03, 0xd0, - 0x9c, 0xb5, 0x30, 0x84, 0x51, 0x77, 0x9c, 0xf7, 0x63, 0x36, 0xe0, 0x75, 0xb7, 0xea, 0x2a, 0x76, 0xf1, 0xc1, 0xc1, - 0xb2, 0x88, 0x95, 0x11, 0x13, 0x94, 0x11, 0x13, 0x94, 0x11, 0x13, 0x54, 0x15, 0x3d, 0xfe, 0xa4, 0x0f, 0x52, 0x8a, - 0x56, 0xb6, 0x58, 0x9e, 0xfa, 0x1d, 0xa8, 0x3d, 0x40, 0x3b, 0xd9, 0xaf, 0x94, 0x1d, 0xa5, 0xae, 0x62, 0xa7, 0x02, - 0x63, 0x67, 0xa2, 0xd5, 0x76, 0x1c, 0xfd, 0x3b, 0xea, 0x8e, 0x97, 0x35, 0xb1, 0xec, 0xdd, 0x4e, 0xb1, 0x0c, 0x56, - 0x52, 0x8b, 0x66, 0xfb, 0x26, 0x10, 0x87, 0x1a, 0x3c, 0xd4, 0x82, 0x59, 0x15, 0x1d, 0xae, 0x01, 0x49, 0x3d, 0x90, - 0x42, 0xce, 0xb4, 0x94, 0x56, 0xa0, 0x38, 0x55, 0x61, 0x01, 0x1a, 0x4a, 0xa7, 0xa0, 0x2c, 0x83, 0x98, 0x36, 0x34, - 0x40, 0x72, 0x23, 0xa3, 0x19, 0x59, 0xad, 0x0b, 0xa2, 0x0b, 0x68, 0xc2, 0xb4, 0xc4, 0x02, 0x0d, 0x48, 0xdd, 0x80, - 0xb4, 0x95, 0x41, 0x9c, 0xb1, 0xd9, 0x27, 0x3a, 0x3b, 0xd7, 0xd9, 0x79, 0x99, 0x2d, 0x5c, 0xb6, 0x11, 0x12, 0x85, - 0xce, 0x16, 0x65, 0x36, 0xc8, 0x6c, 0x78, 0x12, 0xe7, 0x78, 0x14, 0x0b, 0x23, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0xea, - 0x6b, 0x73, 0x0f, 0x0e, 0xc2, 0x52, 0x4e, 0xd2, 0x6a, 0xe2, 0x07, 0x4b, 0x1e, 0x15, 0x5a, 0x06, 0xe2, 0xd1, 0xc4, - 0xfe, 0x1d, 0xad, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfa, 0x46, 0x49, 0xf4, 0xd9, 0x29, 0x51, 0x1f, 0x73, 0x1d, 0xfe, - 0xe6, 0x9c, 0x44, 0xad, 0xd6, 0x71, 0xfb, 0xb8, 0x75, 0xd6, 0xe7, 0x87, 0xed, 0x4e, 0xf4, 0xa8, 0x13, 0x6b, 0x45, - 0xc4, 0x5c, 0xdc, 0x82, 0x02, 0xe6, 0xa8, 0x13, 0x9d, 0xa0, 0xc3, 0x76, 0xd4, 0xea, 0x76, 0x9b, 0xf0, 0x0f, 0x7e, - 0xaf, 0xca, 0x6a, 0x27, 0xad, 0x93, 0x6e, 0x9f, 0x1f, 0x6d, 0x54, 0x0a, 0x79, 0x03, 0x0a, 0xa2, 0x23, 0x5d, 0x09, - 0x43, 0xfd, 0x6a, 0x79, 0x9f, 0x6d, 0xe9, 0x79, 0xde, 0xab, 0x30, 0x37, 0xaa, 0x38, 0x80, 0xaa, 0xfb, 0x9a, 0x68, - 0x20, 0xba, 0xaf, 0x51, 0x19, 0xa2, 0x76, 0x59, 0x80, 0xa8, 0xfd, 0x98, 0x87, 0xb2, 0xc1, 0x0e, 0x43, 0x93, 0xaf, - 0xa0, 0x6e, 0x13, 0xc2, 0xc6, 0xe1, 0x89, 0xcd, 0xcd, 0xfd, 0xdc, 0x09, 0x42, 0xcd, 0x1c, 0x72, 0x47, 0x36, 0x57, - 0xf8, 0xb9, 0x23, 0x84, 0x9a, 0x02, 0x72, 0x69, 0xcc, 0x23, 0x0a, 0x39, 0x2a, 0xa2, 0x4d, 0x0d, 0xc9, 0x6a, 0x51, - 0x9e, 0x33, 0x37, 0x6c, 0x3e, 0x86, 0xe5, 0xd1, 0x04, 0xc5, 0x0a, 0xd2, 0x10, 0x35, 0xaf, 0xd2, 0xe6, 0xb4, 0x70, - 0xa9, 0xc6, 0x81, 0x8c, 0x06, 0xfc, 0x73, 0xc8, 0xf4, 0x7b, 0x13, 0xad, 0xfe, 0xf1, 0x69, 0x2b, 0x6e, 0x83, 0x8f, - 0x34, 0xc8, 0xda, 0xd2, 0xc8, 0xda, 0xd2, 0xc9, 0xda, 0xd2, 0xc9, 0xda, 0x20, 0xc0, 0x7b, 0x7d, 0xff, 0x2d, 0x6a, - 0x76, 0x27, 0xbc, 0x34, 0x62, 0x31, 0x56, 0x0a, 0xa1, 0x5a, 0xad, 0x96, 0x6b, 0x30, 0x31, 0x2a, 0x6b, 0x88, 0xbc, - 0x52, 0x7f, 0x2e, 0x8b, 0xb8, 0x85, 0x27, 0x31, 0x68, 0xb9, 0x5b, 0x98, 0xea, 0xcd, 0xed, 0xa8, 0xc2, 0x66, 0xf8, - 0x9a, 0xbe, 0x53, 0x27, 0x5f, 0x90, 0x63, 0xad, 0x3d, 0x5e, 0x16, 0x31, 0x37, 0x34, 0x83, 0x1b, 0x9a, 0xc1, 0x0d, - 0xcd, 0x80, 0x46, 0x70, 0x59, 0x58, 0x97, 0x8d, 0x28, 0x81, 0x2b, 0x81, 0xc1, 0xf1, 0x10, 0xa2, 0xf7, 0x85, 0x8a, - 0xe8, 0x51, 0x6f, 0x74, 0xde, 0x86, 0x68, 0x65, 0xa6, 0xa4, 0x8a, 0xa8, 0x76, 0xda, 0x2e, 0xc7, 0xfc, 0xaa, 0x86, - 0xf6, 0x11, 0x3c, 0x25, 0x73, 0xa9, 0xc2, 0x16, 0xd8, 0x6c, 0x04, 0x45, 0xd0, 0xd7, 0x64, 0x21, 0xd6, 0x3a, 0x1b, - 0x6b, 0x8b, 0xfd, 0x65, 0xc3, 0x05, 0xd6, 0x50, 0x02, 0xff, 0x01, 0x85, 0x2f, 0xac, 0xf2, 0xc9, 0x2f, 0x4d, 0x4d, - 0xad, 0x9d, 0x98, 0x39, 0x12, 0x7a, 0x60, 0x2f, 0xee, 0x82, 0x3d, 0xf5, 0x25, 0x11, 0xb9, 0xf6, 0x56, 0x24, 0x55, - 0xb8, 0x62, 0xf0, 0xde, 0x25, 0x77, 0x54, 0xfb, 0xb2, 0xbc, 0x30, 0x7f, 0x5e, 0x51, 0xcf, 0xd9, 0xaf, 0x98, 0x8c, - 0x9c, 0x8f, 0xec, 0x8d, 0x0e, 0xea, 0x43, 0xf6, 0xf7, 0x8d, 0x29, 0xb7, 0xfe, 0xda, 0xb4, 0xe5, 0xd6, 0x89, 0x3a, - 0x1b, 0x76, 0xa8, 0x5b, 0xa3, 0xbf, 0x9d, 0xab, 0x5a, 0x31, 0x19, 0x21, 0x8f, 0x66, 0x6b, 0xb0, 0xe6, 0x15, 0xb0, - 0xa4, 0xad, 0x57, 0x7a, 0x30, 0x42, 0xef, 0x7a, 0xcc, 0xeb, 0x62, 0x32, 0xda, 0xf9, 0xe6, 0x88, 0xe9, 0xb1, 0xff, - 0x96, 0x7a, 0x3d, 0x38, 0xd5, 0xf6, 0x94, 0xdd, 0x7d, 0xaf, 0xce, 0xed, 0xce, 0x3a, 0x32, 0xfb, 0x5e, 0x9d, 0xa7, - 0xbb, 0xea, 0xcc, 0xf8, 0x5d, 0xe8, 0xf6, 0x8e, 0xf2, 0xd4, 0xd8, 0xda, 0x3e, 0x68, 0x32, 0x82, 0x20, 0xf1, 0xf0, - 0xd7, 0x84, 0x72, 0xe9, 0x39, 0x12, 0x0e, 0xab, 0x20, 0xfa, 0x51, 0x37, 0x66, 0x98, 0x92, 0xce, 0x61, 0xa1, 0x83, - 0xb9, 0xc8, 0x88, 0x36, 0xf3, 0x88, 0xe2, 0x8c, 0x84, 0x21, 0x3d, 0x4c, 0x20, 0x24, 0x4d, 0xbb, 0x4f, 0xe3, 0x90, - 0x36, 0x12, 0x74, 0x14, 0xb6, 0x1b, 0xf4, 0x30, 0x41, 0xa8, 0xd1, 0x06, 0x9d, 0xa9, 0x20, 0xed, 0x66, 0x06, 0x41, - 0x2a, 0x35, 0x29, 0xce, 0x0e, 0x65, 0x54, 0x34, 0xc4, 0x61, 0x1e, 0x15, 0x8d, 0xa8, 0x8b, 0x65, 0x34, 0x29, 0x93, - 0x27, 0x3a, 0x79, 0x62, 0x92, 0x47, 0x65, 0xf2, 0x48, 0x27, 0x8f, 0x4c, 0x32, 0x25, 0xc5, 0xa1, 0x8c, 0x68, 0x23, - 0x6c, 0x37, 0x0b, 0x74, 0x08, 0x23, 0x70, 0xa3, 0x27, 0xd2, 0x8f, 0x0d, 0xbe, 0xd6, 0xc6, 0x35, 0x73, 0x91, 0xd9, - 0x68, 0x9d, 0x15, 0x90, 0x4a, 0x8f, 0x27, 0xa8, 0xf3, 0xcc, 0x03, 0x13, 0x56, 0xe6, 0x8f, 0x8b, 0x45, 0xb7, 0x4e, - 0x32, 0x91, 0x7b, 0x1e, 0x5d, 0x60, 0x84, 0xfe, 0xc5, 0xfa, 0xb1, 0x00, 0x54, 0xd7, 0x34, 0x9b, 0x4f, 0xe9, 0x96, - 0xdb, 0x6c, 0x31, 0x19, 0xd9, 0x9d, 0x55, 0x36, 0xc3, 0x68, 0x61, 0x62, 0x3c, 0xd7, 0x1d, 0x1c, 0x01, 0xd4, 0xce, - 0xa9, 0x32, 0xa2, 0x5a, 0x49, 0x6e, 0x6a, 0x4c, 0x0a, 0x76, 0x2f, 0x13, 0x9a, 0xb1, 0xb0, 0x3a, 0x80, 0xab, 0x61, - 0x32, 0xf2, 0x02, 0x4c, 0xe1, 0x8b, 0xc3, 0xe8, 0xb8, 0xa1, 0xa2, 0xc9, 0x61, 0xd4, 0x7d, 0xd4, 0x50, 0xd1, 0xe8, - 0x30, 0x6a, 0xb7, 0x2b, 0x9c, 0x8d, 0x0a, 0xa2, 0xa2, 0x09, 0x51, 0xa0, 0x31, 0x34, 0x8d, 0x8a, 0x39, 0x05, 0xdb, - 0xae, 0x7f, 0x63, 0x18, 0x0d, 0x3b, 0x8c, 0x9c, 0x4d, 0x4c, 0xb8, 0xcb, 0xad, 0x31, 0xf8, 0xdd, 0x74, 0xba, 0xdd, - 0xa6, 0x8a, 0x0a, 0xac, 0xcc, 0x4a, 0x36, 0x55, 0x34, 0xc1, 0xca, 0x2c, 0x5f, 0x53, 0x45, 0x23, 0xd3, 0x94, 0xd6, - 0x01, 0x82, 0xde, 0xb1, 0x04, 0xd6, 0x73, 0xe6, 0x41, 0xbe, 0xe3, 0xbc, 0x53, 0xd6, 0xa0, 0x35, 0xfc, 0x5e, 0xb9, - 0xa6, 0x2b, 0x28, 0xa9, 0x02, 0x1b, 0x1f, 0xf6, 0xad, 0xa2, 0xed, 0xaa, 0x49, 0xf6, 0xaf, 0xcb, 0x96, 0xcd, 0x16, - 0x42, 0xd5, 0x0b, 0x5e, 0xd6, 0x30, 0xc4, 0x96, 0xb2, 0x07, 0xf7, 0x3f, 0x94, 0x84, 0x10, 0xd4, 0x4e, 0x9f, 0x42, - 0x9c, 0x38, 0x3d, 0x32, 0x24, 0xf1, 0x46, 0x63, 0x8d, 0x42, 0xef, 0xbc, 0x7d, 0xea, 0x53, 0xd5, 0xad, 0x48, 0x77, - 0x84, 0x04, 0x8b, 0xdc, 0xd8, 0x42, 0xa6, 0x81, 0xc7, 0x82, 0x58, 0xed, 0x6e, 0xed, 0x80, 0x38, 0x38, 0xd8, 0x3c, - 0x2f, 0xdc, 0x9b, 0x03, 0x5b, 0xef, 0x0c, 0x54, 0x86, 0x74, 0xee, 0x25, 0x24, 0x63, 0x62, 0xcb, 0x3d, 0x44, 0x71, - 0x31, 0xa7, 0x1e, 0x6a, 0x0a, 0x3f, 0xa8, 0x02, 0xee, 0xd9, 0x9c, 0xe6, 0xa9, 0xce, 0xd0, 0x7d, 0x0d, 0xbd, 0xb1, - 0xbd, 0xf1, 0x27, 0x54, 0x1a, 0x09, 0xfe, 0xcb, 0x8e, 0xbd, 0x4e, 0xec, 0x4b, 0x2d, 0x7e, 0xa3, 0x7f, 0xf9, 0x26, - 0xb9, 0x15, 0x6c, 0xac, 0x33, 0xf6, 0x6a, 0x55, 0x7b, 0x97, 0xc7, 0xbc, 0xfe, 0x82, 0x0e, 0x0e, 0xb8, 0x7c, 0x06, - 0x56, 0xc4, 0x2c, 0x6c, 0xf8, 0x87, 0xef, 0xdf, 0xb5, 0xd3, 0xfa, 0x2f, 0x7d, 0xae, 0xc6, 0xde, 0x41, 0x77, 0x59, - 0xcb, 0xdf, 0xb9, 0x12, 0x7d, 0x15, 0x73, 0xbb, 0xd6, 0x7f, 0x55, 0x36, 0xda, 0x5b, 0x2f, 0x44, 0x1d, 0x1c, 0xf0, - 0x2a, 0x4e, 0x53, 0xf0, 0x43, 0x80, 0xfa, 0x5a, 0x06, 0x79, 0x96, 0x09, 0x0a, 0x37, 0xa2, 0x70, 0xc5, 0x10, 0x37, - 0xf8, 0x91, 0xc2, 0x7f, 0x88, 0xff, 0x4f, 0x8d, 0x1c, 0xaa, 0xb8, 0xc1, 0x3d, 0x01, 0xcc, 0x67, 0x85, 0xaa, 0x08, - 0x89, 0x1a, 0xd2, 0xbe, 0xc9, 0x35, 0x2a, 0x0f, 0x73, 0x3a, 0x9f, 0x67, 0xf7, 0xfa, 0x91, 0x2c, 0x8f, 0xa3, 0xaa, - 0x2e, 0x9a, 0x6c, 0x78, 0x3a, 0x5c, 0x00, 0x4f, 0x0f, 0xb8, 0x87, 0xb4, 0x7b, 0x69, 0x79, 0xb9, 0x2d, 0x11, 0x48, - 0x66, 0x39, 0x11, 0xcd, 0x76, 0x2f, 0xbf, 0x00, 0xb9, 0xac, 0xd9, 0x44, 0xca, 0x46, 0xed, 0xc6, 0x1c, 0x64, 0xb2, - 0xdc, 0xb8, 0x90, 0xee, 0x99, 0x82, 0x20, 0xb9, 0x09, 0x2d, 0xb2, 0xed, 0x2e, 0xc5, 0xc7, 0x21, 0xa0, 0x11, 0x32, - 0x02, 0x9f, 0x2f, 0x2c, 0x72, 0xe0, 0x3a, 0x0b, 0xd7, 0xf1, 0x37, 0x5a, 0x2a, 0x06, 0xf9, 0x70, 0x88, 0x0b, 0xfd, - 0x2e, 0x44, 0x39, 0x1f, 0xb8, 0x69, 0x2a, 0xdf, 0x19, 0xf2, 0x44, 0x14, 0xbe, 0x5a, 0xed, 0xc3, 0x33, 0x3e, 0xb6, - 0x4d, 0xf0, 0x39, 0xb5, 0x3f, 0xab, 0x27, 0x3b, 0x60, 0x1c, 0x8c, 0xb4, 0xf4, 0x45, 0xa1, 0x95, 0x37, 0xd9, 0xb9, - 0xec, 0x35, 0x1a, 0x4c, 0x47, 0x58, 0x22, 0x10, 0x4e, 0x0d, 0x1c, 0x02, 0xe1, 0x8f, 0x09, 0x9a, 0x24, 0x99, 0x09, - 0x3d, 0x07, 0x31, 0xb1, 0x6b, 0x09, 0xab, 0x55, 0x6e, 0x42, 0x9b, 0xe8, 0x1c, 0x13, 0xe4, 0xa4, 0xec, 0xa7, 0x8c, - 0xa1, 0x5a, 0x99, 0x71, 0x70, 0xbb, 0xd5, 0xdf, 0x56, 0xfb, 0x79, 0x8f, 0x9b, 0x6b, 0x3c, 0xae, 0x03, 0x06, 0x68, - 0x40, 0x2d, 0x37, 0x36, 0xb8, 0x31, 0x70, 0x0f, 0x8d, 0x35, 0x2e, 0xdb, 0x84, 0xa0, 0x2c, 0x1d, 0xe4, 0xcd, 0xcd, - 0xad, 0x0b, 0x18, 0x98, 0xeb, 0x39, 0xe5, 0x48, 0x0d, 0x40, 0x8e, 0x1e, 0x12, 0xe8, 0xdc, 0xfc, 0xac, 0xe8, 0x42, - 0x25, 0x13, 0x97, 0x63, 0xfc, 0xc5, 0xbb, 0xcd, 0x1b, 0x04, 0x37, 0x37, 0x7a, 0x93, 0xdf, 0xdc, 0x04, 0xd8, 0xb7, - 0x2a, 0x0f, 0x3c, 0x5e, 0x30, 0x18, 0x96, 0x31, 0xa5, 0xf4, 0xc6, 0x6f, 0xb6, 0xab, 0xc6, 0xde, 0xd3, 0x0a, 0xef, - 0x60, 0x79, 0x74, 0xe3, 0x5b, 0x5e, 0x98, 0x03, 0x0e, 0xf0, 0x66, 0x03, 0x3e, 0xec, 0xbd, 0x09, 0x73, 0x74, 0x70, - 0xf0, 0x26, 0x14, 0xa8, 0x7f, 0xcd, 0xf4, 0x9d, 0x1b, 0xb8, 0x61, 0x0f, 0xb8, 0x1e, 0xbe, 0xf0, 0x10, 0xe0, 0x9a, - 0x6d, 0x4a, 0x36, 0x6f, 0x75, 0xd0, 0x8b, 0x18, 0x82, 0x6a, 0x43, 0x68, 0x5f, 0x0b, 0x12, 0xe8, 0xf5, 0x8d, 0x0f, - 0xed, 0x1e, 0x23, 0x0c, 0x58, 0xf8, 0xd2, 0x49, 0x8e, 0x45, 0x33, 0x56, 0x4c, 0x58, 0xb1, 0x5a, 0xbd, 0xa7, 0xc6, - 0xf1, 0x6d, 0x23, 0x46, 0x63, 0xde, 0x6b, 0x34, 0xa8, 0x1e, 0x3f, 0x88, 0x0f, 0x74, 0x88, 0xf7, 0xdf, 0x84, 0x05, - 0x42, 0x60, 0x61, 0xc4, 0xf3, 0x85, 0x73, 0xf2, 0x4a, 0x6a, 0xeb, 0x52, 0xa0, 0xb2, 0x91, 0x8c, 0xb4, 0xf0, 0x94, - 0x24, 0xe5, 0x1a, 0x9d, 0x4f, 0x7b, 0x8d, 0x46, 0x86, 0x44, 0x98, 0x0c, 0xb2, 0x21, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, - 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0xb2, 0xf3, 0x5d, 0x9a, 0xb1, 0xc6, 0x8f, 0xe9, 0xda, 0x03, 0xc6, 0x63, 0xea, - 0x11, 0x89, 0x5d, 0x40, 0x96, 0x06, 0xc8, 0xb9, 0x03, 0xb2, 0xd4, 0x40, 0xce, 0x51, 0x7f, 0x0e, 0xd1, 0x8a, 0x72, - 0x14, 0x6f, 0x51, 0xf4, 0x7a, 0x5c, 0x4d, 0xeb, 0xb3, 0x81, 0xb9, 0x0e, 0xed, 0x60, 0x97, 0x03, 0x1e, 0x3a, 0xb1, - 0x6e, 0x80, 0x39, 0x59, 0x06, 0x81, 0x0e, 0x31, 0x8b, 0xef, 0xf4, 0x9f, 0xe8, 0x0e, 0xdf, 0x9b, 0x1f, 0xf7, 0x9e, - 0x32, 0xe9, 0x79, 0x4d, 0xdb, 0xc0, 0x6d, 0x40, 0xb6, 0x20, 0x0a, 0x00, 0xad, 0x6d, 0x74, 0x41, 0x59, 0x7f, 0x70, - 0x2d, 0x37, 0x71, 0x20, 0x64, 0x83, 0xe4, 0x58, 0x7a, 0xa4, 0xf3, 0xcf, 0x3f, 0x03, 0xd4, 0x97, 0x10, 0xc6, 0xc7, - 0x9e, 0x6c, 0xcd, 0x36, 0x6a, 0x04, 0x51, 0x10, 0x87, 0x2e, 0x4a, 0x04, 0xec, 0x8c, 0x20, 0xf0, 0x1e, 0x5b, 0x29, - 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x3d, 0xa8, 0x2a, 0xee, 0xc5, 0xc5, 0x72, 0x33, 0xca, 0x90, 0x86, 0xaa, 0xd4, 0x21, - 0x5e, 0x90, 0x79, 0x81, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0x06, 0x72, 0xe8, 0x3d, 0x29, 0x56, 0x5d, 0x87, 0x2b, 0x7f, - 0xe1, 0x42, 0x9a, 0x0f, 0xd4, 0x70, 0xb5, 0x32, 0x7f, 0xc9, 0x07, 0x2d, 0xcd, 0xc0, 0xdb, 0x70, 0xde, 0x6d, 0xbc, - 0xdc, 0x2d, 0x8b, 0x45, 0x4a, 0xfc, 0x0e, 0x56, 0x83, 0x2e, 0x68, 0x9f, 0x9d, 0x6a, 0xdb, 0x41, 0x7d, 0xae, 0x35, - 0x0a, 0x5e, 0xc8, 0xdc, 0xea, 0x48, 0xc3, 0x73, 0xe5, 0xe7, 0xd5, 0x42, 0xdf, 0x26, 0x79, 0x19, 0xc1, 0x14, 0x8e, - 0x94, 0x08, 0xcc, 0xc6, 0x35, 0x9d, 0x84, 0x1f, 0x75, 0x2a, 0x69, 0x59, 0x48, 0x80, 0x02, 0x47, 0xfa, 0x72, 0x5e, - 0x47, 0xa8, 0x67, 0x68, 0x07, 0x91, 0xf3, 0x4c, 0x68, 0xea, 0xb2, 0xa5, 0x0d, 0x25, 0x15, 0xcc, 0xc4, 0x42, 0xb2, - 0xc5, 0x1c, 0xce, 0xf7, 0x32, 0x2d, 0xc9, 0x78, 0xf2, 0xa5, 0x9e, 0x02, 0xe6, 0x9f, 0x77, 0x6a, 0xc6, 0xf2, 0x45, - 0x60, 0xe7, 0xf9, 0xca, 0x88, 0xfb, 0x6f, 0x5e, 0xe0, 0xc7, 0xa4, 0x73, 0xf8, 0x0a, 0x7f, 0xa4, 0xe4, 0x71, 0xe3, - 0x15, 0x9e, 0x70, 0x62, 0x78, 0x83, 0xe8, 0xcd, 0xeb, 0xeb, 0x17, 0xef, 0x5e, 0xbc, 0x7f, 0x7a, 0xf3, 0xe2, 0xd5, - 0xb3, 0x17, 0xaf, 0x5e, 0xbc, 0xfb, 0x88, 0xff, 0xa6, 0xe4, 0xd5, 0x51, 0xfb, 0xac, 0x85, 0x3f, 0x90, 0x57, 0x47, - 0x1d, 0x7c, 0xa7, 0xc8, 0xab, 0xa3, 0x13, 0x9c, 0xe5, 0xe4, 0xd5, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0x94, 0x69, 0x32, - 0x13, 0x93, 0x76, 0x0b, 0xff, 0x6d, 0xbf, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x9b, 0xc6, 0x0f, 0x50, 0x86, 0x8e, - 0xa4, 0x36, 0x44, 0x39, 0xf7, 0xd0, 0x69, 0x9a, 0xfb, 0xe8, 0x64, 0x62, 0x28, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, - 0xb6, 0x1d, 0x7e, 0xd4, 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd5, 0x62, 0x8c, 0x33, - 0x21, 0x8a, 0x70, 0x01, 0x8c, 0x80, 0xd6, 0x5a, 0xf0, 0xa3, 0x32, 0x58, 0x93, 0x3c, 0x27, 0xed, 0x7e, 0x3b, 0x96, - 0xe7, 0xa4, 0xd3, 0xef, 0xc0, 0x9f, 0x6e, 0xbf, 0x1b, 0xb7, 0x5b, 0xe8, 0xd0, 0x1b, 0xc7, 0x1f, 0x35, 0xb4, 0x1e, - 0x0c, 0xb1, 0xed, 0x42, 0xfe, 0x5d, 0x28, 0xa7, 0xd2, 0x93, 0x56, 0x1d, 0xdb, 0xee, 0xc9, 0x73, 0xa6, 0xf5, 0xb0, - 0xfc, 0x07, 0x40, 0x6d, 0xed, 0x4f, 0x52, 0x6e, 0x1c, 0xfb, 0x8b, 0x1f, 0x49, 0x54, 0x8b, 0x08, 0x13, 0xb2, 0x55, - 0x0b, 0x01, 0xd3, 0xa8, 0xb3, 0xc1, 0x1c, 0x28, 0x92, 0xa2, 0x50, 0x2e, 0xaa, 0x7d, 0xde, 0x14, 0x28, 0x9a, 0x8b, - 0x79, 0x58, 0x53, 0x35, 0xfc, 0xea, 0x99, 0x39, 0xee, 0x73, 0xf9, 0x8a, 0xbe, 0x0a, 0x6b, 0x3c, 0x8f, 0xcf, 0xda, - 0xf9, 0xdb, 0xe2, 0x17, 0x6b, 0x45, 0x51, 0x03, 0x57, 0x09, 0x58, 0x37, 0xaa, 0xa6, 0x3a, 0x87, 0xe7, 0xfb, 0x58, - 0x43, 0x5d, 0x10, 0x8f, 0x7a, 0xfe, 0x54, 0x9a, 0x71, 0x95, 0xca, 0x68, 0xa7, 0x88, 0xd6, 0x66, 0x41, 0x4e, 0x11, - 0x7d, 0x9e, 0x6b, 0x20, 0x08, 0xc2, 0x07, 0x72, 0x08, 0x07, 0xbe, 0x19, 0xa0, 0xd0, 0x74, 0x0e, 0xd4, 0x4a, 0x95, - 0x99, 0x90, 0xfe, 0xd4, 0xb1, 0x09, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xf4, 0x27, 0x16, 0xc8, 0x1b, 0xfa, 0x6f, 0xfe, - 0x06, 0x38, 0x0c, 0x35, 0x2a, 0xfa, 0x76, 0x35, 0xb2, 0x9e, 0xdf, 0x3e, 0x6b, 0x1d, 0xbd, 0xf2, 0xf2, 0xd3, 0xdc, - 0xd9, 0x7b, 0xfc, 0xe5, 0x51, 0x72, 0x13, 0x4d, 0xab, 0x8d, 0x5d, 0x20, 0xb4, 0x9e, 0x0f, 0x90, 0x43, 0x85, 0x8e, - 0xf4, 0x4b, 0x86, 0x3d, 0xa4, 0x0e, 0x49, 0xbb, 0x05, 0xd1, 0xcb, 0x76, 0x50, 0xbe, 0x9f, 0x36, 0x60, 0xaa, 0xa2, - 0xbb, 0x26, 0xd0, 0x6a, 0x78, 0xdc, 0xe8, 0xbe, 0xc9, 0xa3, 0x7b, 0x9c, 0x7b, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1e, - 0x4a, 0x64, 0xa3, 0xbe, 0x9a, 0x0d, 0xa0, 0x68, 0xde, 0x31, 0x8f, 0xec, 0x39, 0xe3, 0xa8, 0xf3, 0x66, 0xd4, 0x3d, - 0x7c, 0x75, 0x70, 0x10, 0x8a, 0x06, 0x79, 0x8c, 0xf0, 0x92, 0x82, 0x11, 0x35, 0x38, 0x9d, 0x71, 0xc3, 0xc4, 0xc7, - 0xb9, 0x47, 0x1d, 0x17, 0x79, 0xed, 0x58, 0xab, 0x3a, 0x2b, 0x77, 0x83, 0x1b, 0x53, 0x07, 0x35, 0xbc, 0x34, 0x33, - 0xba, 0x4e, 0x0d, 0xca, 0x35, 0x0f, 0x31, 0xd8, 0x96, 0x8d, 0x8f, 0x14, 0xfd, 0xf0, 0xb8, 0xf9, 0xca, 0x9b, 0x70, - 0xcd, 0x34, 0xe9, 0x71, 0xe3, 0x31, 0xfa, 0xe1, 0xb1, 0xe7, 0xe3, 0xc7, 0x2b, 0xf6, 0xc4, 0x71, 0x23, 0x3f, 0x19, - 0xae, 0xf4, 0x27, 0x90, 0xec, 0x0b, 0xf2, 0x13, 0x60, 0x39, 0x25, 0x3f, 0x85, 0xa2, 0x99, 0x83, 0x41, 0xd7, 0x4f, - 0x61, 0x01, 0x3f, 0x32, 0xf2, 0x53, 0x08, 0xd8, 0x8e, 0xa7, 0xfa, 0x47, 0x51, 0xbd, 0xae, 0x0a, 0x6a, 0x14, 0xe3, - 0x5e, 0x56, 0xac, 0x56, 0xf2, 0xe0, 0x40, 0x98, 0x5f, 0xf4, 0x22, 0x39, 0x38, 0xc8, 0xce, 0xa7, 0x9e, 0xed, 0xad, - 0xda, 0x45, 0x5f, 0x34, 0x42, 0x61, 0xcf, 0x34, 0x8d, 0xfb, 0x33, 0xfe, 0xe4, 0x53, 0x56, 0xdd, 0x40, 0xf3, 0xb8, - 0xf3, 0xf0, 0xf4, 0x0c, 0xc3, 0xbf, 0x0f, 0xbd, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, 0xb3, 0xe6, 0x69, 0x85, 0x6c, - 0x17, 0x1e, 0x3e, 0x63, 0x86, 0x9a, 0xf2, 0xe0, 0x80, 0x9f, 0x7b, 0xb8, 0x8c, 0x19, 0x6a, 0x78, 0x16, 0x7b, 0x0f, - 0x4a, 0x7b, 0x32, 0xcd, 0x35, 0xc1, 0xab, 0xb6, 0x7c, 0x50, 0x0c, 0xcf, 0x95, 0xa5, 0x26, 0x7e, 0xec, 0xeb, 0x9c, - 0xb4, 0xec, 0x26, 0xeb, 0xc9, 0x66, 0x7e, 0xd1, 0xee, 0x21, 0x41, 0xf2, 0x86, 0xbc, 0xb8, 0x68, 0x63, 0x50, 0xc9, - 0xf7, 0x73, 0x22, 0x62, 0x49, 0x9c, 0x7f, 0xde, 0x32, 0x13, 0x71, 0x8e, 0xa7, 0x3c, 0x2e, 0xe5, 0xec, 0xd7, 0xce, - 0x7a, 0x5a, 0x7b, 0x4c, 0xea, 0x9e, 0x19, 0x96, 0xfd, 0xbc, 0xf4, 0xf4, 0x83, 0x4d, 0x9a, 0x0f, 0xe1, 0xd1, 0xc0, - 0x12, 0xf3, 0x98, 0x71, 0x6f, 0x63, 0x10, 0x94, 0x39, 0x6f, 0xb4, 0x21, 0x13, 0x3e, 0xd7, 0x71, 0x0e, 0x03, 0xd5, - 0x85, 0xcf, 0x81, 0x4c, 0x25, 0x95, 0x61, 0xb6, 0x6b, 0x18, 0x0a, 0x48, 0x28, 0x70, 0x41, 0x98, 0x27, 0xc1, 0xc3, - 0xed, 0x87, 0x47, 0x38, 0xea, 0xe4, 0xc2, 0x4c, 0xee, 0x3c, 0x87, 0xee, 0xe4, 0xf0, 0x5c, 0xf5, 0x90, 0x6c, 0x34, - 0x2c, 0xb7, 0x7d, 0x21, 0xf5, 0x20, 0x9a, 0xed, 0xe1, 0x05, 0xeb, 0xa1, 0xbc, 0xd9, 0x2c, 0x0d, 0x20, 0x2f, 0x5a, - 0xab, 0x55, 0x7e, 0xee, 0x1a, 0xe9, 0xbb, 0x73, 0x5c, 0xf3, 0x5d, 0x4e, 0xf0, 0xfc, 0x4d, 0x90, 0x41, 0x00, 0x54, - 0x15, 0xf8, 0x6c, 0x31, 0x0f, 0x70, 0xa0, 0xdf, 0x93, 0x83, 0xbf, 0xfa, 0x1d, 0xb0, 0x00, 0x07, 0xf6, 0x89, 0xb9, - 0x60, 0x58, 0x0d, 0x96, 0x27, 0x65, 0x74, 0x74, 0x1e, 0xdd, 0x00, 0xe3, 0xa0, 0xfe, 0x02, 0x4e, 0xbb, 0xfc, 0x1d, - 0x65, 0x36, 0x4e, 0x88, 0x74, 0xaf, 0x9e, 0xd9, 0x51, 0xad, 0x77, 0x7b, 0x66, 0x72, 0x1c, 0xb8, 0xaa, 0xf0, 0x7a, - 0xc0, 0x77, 0x9e, 0x5d, 0x6c, 0xdb, 0xd7, 0xbe, 0x97, 0x65, 0x0f, 0xc0, 0x79, 0xaf, 0xd7, 0x08, 0xff, 0x26, 0x76, - 0x3e, 0xfd, 0x1b, 0xdc, 0x88, 0xfc, 0x09, 0x55, 0x34, 0x68, 0xbc, 0xd6, 0x86, 0x6f, 0x46, 0xce, 0xea, 0x7d, 0x6b, - 0x1c, 0xec, 0xdf, 0xea, 0x1e, 0x22, 0x37, 0xd4, 0x5e, 0x29, 0x32, 0xb2, 0xaf, 0x8e, 0xd7, 0x21, 0x3c, 0xd3, 0xb7, - 0x1d, 0xf0, 0x70, 0x63, 0xa4, 0xe0, 0x4f, 0x6c, 0xf8, 0x24, 0x0a, 0x21, 0x51, 0x6b, 0x5e, 0xcc, 0x90, 0x62, 0xfa, - 0xd0, 0x1e, 0xaf, 0x6b, 0xe4, 0x73, 0xdd, 0xe3, 0xbc, 0x4e, 0x4c, 0xab, 0x6e, 0xb4, 0xd4, 0xc1, 0x36, 0x59, 0x70, - 0x56, 0xf5, 0xae, 0x25, 0x94, 0xea, 0x41, 0x37, 0xfd, 0x28, 0x67, 0xb3, 0xad, 0x5f, 0x39, 0x36, 0xcf, 0xbe, 0xe5, - 0x60, 0xc8, 0xbb, 0x5f, 0x46, 0xab, 0xba, 0x80, 0x63, 0x37, 0xf4, 0x20, 0x2b, 0xc8, 0xc5, 0xd2, 0x3e, 0xc9, 0xc6, - 0x07, 0x62, 0xb8, 0x2e, 0x1f, 0x68, 0xf3, 0xf0, 0xa0, 0x1a, 0xa9, 0x4c, 0x7c, 0xce, 0xc0, 0xbd, 0x6e, 0x58, 0xd3, - 0x0f, 0xf1, 0x7f, 0xe0, 0x80, 0xaf, 0x90, 0x34, 0x36, 0xea, 0x27, 0x78, 0x38, 0x09, 0x14, 0xde, 0xa6, 0xee, 0x27, - 0xe1, 0x7b, 0xa8, 0xd6, 0x75, 0x2a, 0xc6, 0x09, 0xb4, 0xae, 0x58, 0x29, 0x0b, 0x7b, 0xc7, 0x5d, 0x88, 0xd6, 0xb1, - 0x75, 0x18, 0xb5, 0xaf, 0x2d, 0x5d, 0xe6, 0xe0, 0xff, 0xc2, 0x45, 0xfe, 0xac, 0x80, 0xf0, 0x59, 0xbe, 0x3e, 0xed, - 0x67, 0xe1, 0x3f, 0x27, 0x3c, 0x80, 0x7b, 0xc2, 0x92, 0xe7, 0x2c, 0x9f, 0xc0, 0x86, 0x05, 0xca, 0x81, 0x42, 0xe5, - 0x58, 0xae, 0x56, 0xa1, 0xd4, 0x41, 0x15, 0x6c, 0x4c, 0x5d, 0xfb, 0x78, 0x86, 0xd6, 0xdf, 0x41, 0x5d, 0xec, 0xd4, - 0x23, 0xda, 0x84, 0x15, 0xf9, 0x97, 0x4e, 0x79, 0xe2, 0xf5, 0xb5, 0xab, 0x0f, 0x59, 0x4d, 0xb9, 0x1f, 0x6a, 0x7d, - 0xef, 0x3b, 0x3e, 0x63, 0x62, 0x01, 0xaf, 0x16, 0x61, 0x46, 0x24, 0x53, 0xee, 0x1b, 0x28, 0x08, 0x84, 0x9c, 0xe3, - 0x3e, 0x3e, 0x02, 0x5f, 0xe5, 0x68, 0x9d, 0x48, 0xdc, 0x5b, 0x18, 0x81, 0x8e, 0x55, 0x19, 0xf4, 0x03, 0x70, 0x5a, - 0x02, 0x11, 0x8a, 0x90, 0x80, 0xe5, 0x69, 0xd0, 0x0f, 0xb4, 0x8f, 0x54, 0x00, 0x56, 0x63, 0xa0, 0xe4, 0x0e, 0xf0, - 0x3c, 0xaf, 0x88, 0x98, 0x5f, 0x53, 0x79, 0x95, 0x58, 0xac, 0xcd, 0xb4, 0x8f, 0x3a, 0x15, 0x08, 0x8b, 0x64, 0x53, - 0x50, 0x56, 0x1b, 0xea, 0x02, 0x2c, 0x88, 0xc6, 0x58, 0x1e, 0xdd, 0x00, 0x37, 0xc7, 0x52, 0x5b, 0x74, 0xc9, 0xaf, - 0x41, 0x3d, 0x1d, 0x17, 0xf8, 0x46, 0x33, 0x6c, 0x69, 0x4c, 0xd7, 0x84, 0xe3, 0x84, 0x14, 0x11, 0xbd, 0x83, 0xa0, - 0x12, 0x33, 0x9e, 0xc7, 0x19, 0x9e, 0xd1, 0xbb, 0x78, 0x8a, 0x67, 0x3c, 0x7f, 0x62, 0x96, 0x3d, 0x4e, 0x21, 0xc9, - 0x7d, 0x2c, 0xd6, 0x44, 0xbf, 0x89, 0xf5, 0xbb, 0x64, 0xc5, 0x63, 0xe0, 0x55, 0x64, 0x88, 0x7a, 0xa9, 0xb6, 0x29, - 0x67, 0xaa, 0x32, 0x5e, 0x7f, 0xad, 0x42, 0x8a, 0x13, 0x9c, 0xa1, 0x28, 0x13, 0x98, 0xf5, 0x65, 0xfc, 0x1a, 0x02, - 0x4a, 0x27, 0xd8, 0xbc, 0xa7, 0xc5, 0xef, 0x58, 0xf6, 0x4c, 0x14, 0xef, 0xf5, 0x96, 0xcf, 0x10, 0x14, 0x02, 0x17, - 0x15, 0xd9, 0x84, 0xdb, 0xbd, 0x45, 0x5f, 0x54, 0x4d, 0xd1, 0x3b, 0xd3, 0x94, 0x1d, 0xe2, 0x14, 0x22, 0xf1, 0x46, - 0x53, 0xde, 0x68, 0x63, 0xd6, 0x6f, 0x7d, 0xa7, 0xd1, 0x29, 0x2a, 0x4b, 0x22, 0x0c, 0x4f, 0x04, 0x37, 0xf3, 0x58, - 0x10, 0xd9, 0xcc, 0xad, 0x84, 0xb7, 0xd4, 0xc0, 0x8e, 0x73, 0x9c, 0x88, 0x45, 0xae, 0x62, 0xe1, 0xe1, 0x0d, 0xad, - 0x36, 0xd7, 0xf2, 0xce, 0x40, 0x4c, 0xe1, 0x7b, 0xf3, 0x83, 0xe1, 0x1b, 0xad, 0xe2, 0x7f, 0x0b, 0x86, 0x3d, 0x32, - 0x96, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x19, 0x7e, 0xf2, 0x0e, 0xc0, 0x67, 0x58, 0xc8, 0x7b, 0x48, 0x65, 0x3a, - 0xf5, 0x1e, 0x52, 0x19, 0xa4, 0x6a, 0x57, 0xf2, 0x7d, 0x59, 0x29, 0x8b, 0xfc, 0x06, 0x49, 0x8e, 0x4b, 0x75, 0xb0, - 0x20, 0x32, 0x82, 0x76, 0xb5, 0x28, 0x37, 0xe3, 0x39, 0xc4, 0x14, 0x84, 0xc6, 0xcd, 0x37, 0xbd, 0x83, 0xef, 0x7b, - 0x93, 0xcf, 0x5c, 0xfe, 0xbd, 0xc9, 0xd7, 0x1d, 0x39, 0x8c, 0xaf, 0xdf, 0x76, 0x6a, 0xcb, 0x78, 0x61, 0xb1, 0xf6, - 0x43, 0xf9, 0x82, 0x4b, 0x4b, 0xbf, 0x94, 0x4d, 0xda, 0x78, 0xe2, 0x21, 0x65, 0xb3, 0xe2, 0xe1, 0x3a, 0xb8, 0xdd, - 0x3a, 0x0c, 0x79, 0x93, 0xb4, 0x11, 0x3a, 0xb4, 0xc2, 0x55, 0x1e, 0x6a, 0xc9, 0xe9, 0xf0, 0xf1, 0x11, 0xdc, 0xbd, - 0xcc, 0xf2, 0x0d, 0x5f, 0x29, 0x53, 0xad, 0xd9, 0x6e, 0x1d, 0xf2, 0x9d, 0x55, 0x1a, 0x6d, 0x3c, 0x63, 0x64, 0x09, - 0xce, 0x65, 0xb4, 0x30, 0xaa, 0x06, 0xf0, 0x21, 0x7d, 0x91, 0xff, 0xb6, 0xa0, 0xa9, 0xfe, 0x3e, 0x34, 0x29, 0xaf, - 0x17, 0xca, 0x25, 0x35, 0x39, 0x0c, 0xa2, 0x83, 0x6c, 0x49, 0x2f, 0x27, 0xe4, 0x47, 0x24, 0xea, 0xa2, 0xf3, 0x76, - 0x3f, 0xea, 0x1e, 0xf2, 0x43, 0x1e, 0x03, 0x0f, 0x1b, 0x36, 0x5d, 0x85, 0x66, 0xdb, 0xd5, 0xb9, 0x5a, 0x8c, 0x78, - 0x62, 0x9b, 0xaf, 0x3a, 0x28, 0x53, 0xcd, 0x1c, 0x21, 0x0b, 0x50, 0xcc, 0xf5, 0xe2, 0x65, 0xd7, 0xbb, 0x39, 0xe4, - 0x31, 0xf4, 0x03, 0xb5, 0x3a, 0xa6, 0x56, 0x39, 0xb8, 0xdf, 0x16, 0x80, 0x60, 0xae, 0xa3, 0xda, 0x5c, 0x4c, 0x7a, - 0x33, 0xac, 0x3a, 0x3b, 0xe4, 0xd5, 0x08, 0xfd, 0x32, 0xdb, 0xfd, 0xb9, 0xa9, 0x55, 0x5d, 0x1e, 0x7a, 0x10, 0xf9, - 0x6d, 0xc1, 0x73, 0xbf, 0x53, 0xbf, 0x5b, 0x9b, 0xe3, 0x77, 0x5a, 0x9f, 0xa5, 0x57, 0x64, 0xbb, 0xd7, 0xad, 0x99, - 0xd6, 0x67, 0x7b, 0x0d, 0x3e, 0x82, 0x30, 0x29, 0xbd, 0xd2, 0x89, 0x90, 0x21, 0x3f, 0xfc, 0x80, 0x6c, 0xeb, 0xaf, - 0x17, 0xca, 0xe5, 0x97, 0x88, 0x00, 0xd9, 0x55, 0xd7, 0x65, 0x75, 0xe8, 0xa3, 0x6c, 0xe2, 0xd5, 0x21, 0xf7, 0x56, - 0xee, 0xe9, 0xdd, 0x5c, 0xc4, 0x0e, 0x5f, 0xfb, 0xad, 0x78, 0x0b, 0x39, 0x81, 0x78, 0xd8, 0xee, 0xfc, 0xb2, 0x20, - 0x67, 0x37, 0xb7, 0x50, 0xd2, 0x9f, 0xb8, 0x2b, 0xfd, 0x81, 0x99, 0xeb, 0x06, 0x7e, 0x1e, 0x75, 0x61, 0xea, 0x9b, - 0x3d, 0x1c, 0x76, 0xa0, 0x0f, 0x0d, 0x87, 0xcd, 0x06, 0x5d, 0x66, 0x05, 0x91, 0x2b, 0x5e, 0x18, 0x3c, 0xbb, 0x20, - 0xed, 0x3e, 0x8f, 0xed, 0x66, 0xd2, 0xa2, 0x51, 0xbb, 0xc9, 0xbd, 0x99, 0x01, 0x7e, 0xd9, 0xb2, 0x7e, 0x11, 0xb7, - 0x4e, 0x1e, 0x94, 0x5c, 0xb1, 0x6a, 0x7d, 0x2a, 0x78, 0xd5, 0x1b, 0x8e, 0x37, 0xd3, 0xdd, 0xba, 0xc1, 0xed, 0xae, - 0x83, 0x27, 0xbc, 0xc0, 0x62, 0xd0, 0xda, 0x4d, 0x7c, 0x02, 0x1c, 0x50, 0xd4, 0x7a, 0xd8, 0x05, 0x17, 0xca, 0x12, - 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x0c, 0x1c, 0x4d, 0x49, 0x8f, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, 0xd8, 0xc1, - 0x51, 0xbb, 0xdd, 0xe9, 0xe2, 0xe8, 0xa4, 0x0b, 0x03, 0x6d, 0x44, 0xdd, 0xc3, 0x59, 0x6e, 0x00, 0xe8, 0xe5, 0xac, - 0x6d, 0xbb, 0x8f, 0x21, 0x5a, 0x93, 0x2f, 0x5e, 0xf3, 0xc3, 0x30, 0x6c, 0x47, 0x0f, 0x5b, 0xed, 0xee, 0x59, 0x03, - 0x00, 0xd4, 0xb4, 0x1f, 0xb6, 0xc6, 0xeb, 0x85, 0xaa, 0x57, 0x29, 0x11, 0xbe, 0x5e, 0xad, 0xe1, 0xaa, 0x35, 0xda, - 0xeb, 0x6a, 0x0a, 0xae, 0xaa, 0x15, 0xce, 0x4d, 0x11, 0xa7, 0xb4, 0xf1, 0xb7, 0x45, 0x68, 0x06, 0x12, 0x82, 0x74, - 0x1e, 0x75, 0x3b, 0x5d, 0x64, 0xc6, 0xa2, 0x2c, 0x7e, 0x94, 0xfb, 0x64, 0xab, 0x48, 0x43, 0x01, 0x92, 0x94, 0xb3, - 0x13, 0x0b, 0x90, 0xa8, 0x39, 0xb9, 0x68, 0x37, 0x67, 0x2c, 0x72, 0x13, 0xd0, 0xa9, 0xb0, 0x9c, 0xe5, 0x2a, 0xd8, - 0x24, 0x0f, 0x10, 0xe7, 0x60, 0x5c, 0xf4, 0xb0, 0xdb, 0x7f, 0x18, 0x75, 0x4f, 0x3b, 0x86, 0xe8, 0xf1, 0xf3, 0x4e, - 0x2d, 0x4d, 0x4f, 0x3d, 0xea, 0xea, 0x34, 0xe8, 0x3a, 0x7a, 0xd8, 0x85, 0x32, 0x36, 0xc5, 0x2f, 0x05, 0x51, 0x26, - 0xaa, 0x62, 0x10, 0x5a, 0x22, 0xae, 0xe5, 0x9e, 0xd6, 0xb2, 0xcf, 0x4e, 0x8e, 0x1f, 0x76, 0x7d, 0xa8, 0x95, 0xb3, - 0xd0, 0x0b, 0x6d, 0x27, 0xe2, 0x66, 0x07, 0x4b, 0x8b, 0x0e, 0xa3, 0x6e, 0xbc, 0x35, 0x41, 0xb3, 0x69, 0x0e, 0x35, - 0x0e, 0x78, 0x0a, 0xc7, 0x4b, 0x69, 0xf5, 0x25, 0xde, 0xfd, 0x58, 0x65, 0x68, 0xe2, 0x2b, 0x9c, 0xdd, 0x3d, 0xa5, - 0xf7, 0x90, 0xa4, 0x7f, 0x55, 0x79, 0x45, 0xf3, 0xaf, 0x54, 0xbe, 0xa1, 0x10, 0x3a, 0x23, 0x1f, 0x06, 0x36, 0xb0, - 0x77, 0x3d, 0xf7, 0x27, 0x70, 0x11, 0x66, 0x39, 0x5c, 0x68, 0x3a, 0x25, 0x68, 0xc5, 0x0b, 0x8c, 0x7c, 0x56, 0x57, - 0x0f, 0xab, 0xcf, 0x63, 0x6b, 0x52, 0xe0, 0xeb, 0xb6, 0x9e, 0xf3, 0xef, 0x95, 0x8b, 0xca, 0xab, 0xec, 0xa8, 0x8b, - 0x22, 0x7b, 0x59, 0x1e, 0xb5, 0x51, 0xe4, 0x99, 0x90, 0xd8, 0x23, 0x39, 0x49, 0xc8, 0x20, 0xb8, 0x0b, 0x70, 0x70, - 0x1f, 0xe0, 0xc0, 0xf8, 0x30, 0x7f, 0x00, 0x37, 0xf2, 0x00, 0x07, 0xc6, 0x95, 0x39, 0xc0, 0x81, 0x62, 0x39, 0x44, - 0xd4, 0x0a, 0x86, 0x38, 0x83, 0xd2, 0xda, 0xb3, 0xba, 0x2c, 0x7d, 0xe5, 0xbe, 0x4a, 0xd7, 0x6b, 0x93, 0xe2, 0x49, - 0x99, 0x53, 0xbd, 0x43, 0xcd, 0x8b, 0xd0, 0x01, 0x75, 0xcc, 0x7a, 0x80, 0x41, 0x00, 0xa1, 0xf7, 0xee, 0x45, 0xb9, - 0x2a, 0x18, 0x07, 0x3b, 0x86, 0x95, 0x06, 0x9f, 0xf3, 0xc0, 0x3f, 0xc3, 0x02, 0x3c, 0xce, 0x5d, 0x61, 0x10, 0x2b, - 0xdc, 0xef, 0x4c, 0x88, 0xb9, 0xfb, 0xad, 0x44, 0xf9, 0x0b, 0xde, 0x21, 0xb1, 0x16, 0x2d, 0x60, 0xb9, 0x65, 0x62, - 0xff, 0x8c, 0x58, 0x7d, 0x04, 0x37, 0x63, 0x1b, 0x9f, 0x0d, 0x24, 0xc2, 0x1b, 0x2d, 0x50, 0x39, 0xf9, 0xf0, 0xc6, - 0xc4, 0x0a, 0xd2, 0x9f, 0x10, 0x2c, 0x0c, 0xe2, 0x01, 0x0b, 0xb8, 0xd0, 0x98, 0x14, 0x4c, 0xca, 0xc0, 0x04, 0xd1, - 0x0b, 0x44, 0xee, 0x5e, 0x45, 0x74, 0x29, 0xe3, 0x3c, 0xd0, 0x1d, 0xd6, 0x67, 0x6b, 0xc4, 0xe1, 0x4c, 0x14, 0x32, - 0x36, 0x4f, 0xa4, 0x38, 0x30, 0xce, 0xcb, 0xf7, 0x07, 0xe3, 0x2c, 0x59, 0x63, 0x73, 0x87, 0x5d, 0x16, 0xb2, 0x57, - 0xda, 0x7e, 0xa9, 0x24, 0x59, 0x7f, 0x6b, 0x42, 0xb2, 0x36, 0x23, 0x6f, 0xa2, 0xd5, 0x80, 0xaa, 0x48, 0x1a, 0x50, - 0xd8, 0x44, 0x63, 0x89, 0x97, 0x65, 0xc9, 0x78, 0x59, 0x2e, 0xc3, 0x49, 0xab, 0xb5, 0x5e, 0xe3, 0x82, 0xe9, 0xa8, - 0x30, 0x3b, 0x4b, 0x40, 0xbe, 0x9c, 0x8a, 0x5b, 0x2f, 0x57, 0xc6, 0xe5, 0x2c, 0xf5, 0x12, 0x05, 0x9e, 0x11, 0x6c, - 0xb0, 0xc6, 0x5f, 0xb9, 0xe4, 0x00, 0x4f, 0x3b, 0xbb, 0x91, 0x10, 0x19, 0xa3, 0x10, 0x3c, 0xcc, 0x6b, 0x72, 0x8d, - 0xa7, 0x3c, 0x65, 0xbb, 0xdb, 0x04, 0x33, 0xe6, 0x7f, 0xaf, 0x45, 0x87, 0x40, 0x86, 0xdd, 0xd3, 0xa8, 0x03, 0x8b, - 0xb8, 0x82, 0x0e, 0x7c, 0x19, 0x3c, 0xf5, 0x71, 0x33, 0xa3, 0xf7, 0x62, 0xa1, 0x00, 0x2e, 0x0b, 0x25, 0xde, 0xd8, - 0xb8, 0x07, 0xfb, 0x2d, 0xec, 0x42, 0x20, 0x2c, 0x21, 0x64, 0x40, 0x0b, 0x9b, 0x10, 0x15, 0x2d, 0x3c, 0x12, 0x4a, - 0x89, 0x59, 0xdc, 0xc2, 0x3a, 0x5e, 0x44, 0x6b, 0x5d, 0x06, 0xf5, 0xba, 0xc9, 0xdd, 0x5b, 0x92, 0xd5, 0x26, 0x58, - 0x58, 0xe9, 0x50, 0x11, 0xe5, 0xdd, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbf, 0x7e, 0x65, 0x43, 0x36, 0xf3, 0x31, - 0xb8, 0x6c, 0x5a, 0xd5, 0xd8, 0x8d, 0x7e, 0x84, 0x29, 0xac, 0x14, 0xa5, 0x46, 0x38, 0x85, 0x96, 0x5f, 0xe4, 0x2a, - 0x8b, 0xcc, 0xe5, 0xc5, 0x33, 0x51, 0xcc, 0xa8, 0xb9, 0x31, 0xc2, 0x37, 0xb9, 0x7d, 0x75, 0x5d, 0x3f, 0xec, 0x52, - 0x4d, 0xf2, 0xdd, 0xe6, 0x55, 0xc4, 0x22, 0xd1, 0xf2, 0x2b, 0x68, 0x03, 0x74, 0xe5, 0xf2, 0xd1, 0xdc, 0x82, 0xd8, - 0xc0, 0xf7, 0x1e, 0x79, 0x79, 0x6b, 0xa8, 0x4b, 0x10, 0x34, 0xb8, 0xc6, 0x4f, 0x56, 0xf0, 0xc4, 0xbb, 0x2e, 0xd4, - 0xec, 0x91, 0x15, 0x2f, 0x82, 0x56, 0x50, 0x7f, 0x74, 0x56, 0xab, 0x12, 0x5c, 0xd0, 0xd4, 0x28, 0x13, 0x20, 0x7a, - 0x94, 0xef, 0xdb, 0x71, 0x10, 0x4d, 0xdc, 0xdd, 0xf3, 0x45, 0xdb, 0xd1, 0xd9, 0xac, 0x52, 0x27, 0x96, 0x57, 0x26, - 0xe0, 0xe1, 0x68, 0x5e, 0x90, 0x41, 0xd8, 0x4b, 0x64, 0xa5, 0xf6, 0xd0, 0xe5, 0xa2, 0x5e, 0x98, 0x9d, 0xb7, 0x59, - 0xf3, 0x64, 0xb5, 0xca, 0x2e, 0xda, 0xac, 0xdd, 0x35, 0xef, 0xcd, 0x05, 0x32, 0x01, 0x9a, 0xcb, 0xc7, 0x3c, 0x09, - 0x40, 0x3b, 0x3b, 0x4e, 0x74, 0x38, 0x05, 0x17, 0x21, 0x99, 0x2c, 0x54, 0xd5, 0x97, 0x00, 0xe3, 0x52, 0x62, 0xf4, - 0xf8, 0x05, 0xea, 0xb7, 0xe3, 0x6d, 0x57, 0xe9, 0x66, 0xfb, 0xd0, 0xbb, 0x70, 0x29, 0x10, 0xee, 0x40, 0xc8, 0x03, - 0xd0, 0xef, 0x2e, 0x73, 0x30, 0x0d, 0x02, 0x54, 0xce, 0x41, 0xa4, 0xe5, 0xb3, 0xc5, 0xec, 0x59, 0x41, 0xf5, 0x32, - 0x3c, 0xe1, 0x13, 0xae, 0x64, 0x4c, 0x41, 0xba, 0xdd, 0x95, 0xbe, 0xde, 0x2d, 0x41, 0x25, 0xb5, 0xc0, 0xb3, 0x91, - 0xe2, 0xc9, 0x17, 0x69, 0x17, 0x0e, 0x61, 0xbd, 0xb2, 0x12, 0x27, 0x68, 0x8d, 0x33, 0x31, 0xa1, 0x05, 0x57, 0xd3, - 0xd9, 0xbf, 0xb5, 0x3a, 0x6c, 0xa0, 0x86, 0xfa, 0xc2, 0x0a, 0x40, 0x42, 0xf3, 0x74, 0xb5, 0xe2, 0x47, 0xdf, 0xbf, - 0x4f, 0x72, 0x3e, 0xe1, 0x6d, 0xdc, 0xc1, 0xc7, 0xb8, 0x8b, 0xdb, 0x2d, 0xdc, 0xee, 0xc2, 0xd5, 0x7d, 0x92, 0x2d, - 0x52, 0x06, 0xf6, 0xb1, 0xab, 0x95, 0xba, 0x88, 0xce, 0x0e, 0xcb, 0x70, 0xfb, 0xaa, 0x88, 0x2c, 0xba, 0x78, 0x51, - 0xdf, 0x6d, 0xb8, 0xbc, 0x20, 0xf0, 0x63, 0xb5, 0x8d, 0x7d, 0xd5, 0x49, 0xa9, 0x5f, 0xb8, 0x38, 0xee, 0x83, 0x3d, - 0xb7, 0x59, 0xd9, 0x26, 0x98, 0x7d, 0x9b, 0x9f, 0x71, 0xf5, 0xb3, 0xa9, 0x4a, 0xc4, 0x70, 0xd0, 0xab, 0xd0, 0x03, - 0x5d, 0x90, 0xf6, 0xc1, 0x01, 0x58, 0x1d, 0x79, 0xb3, 0xe1, 0x26, 0xfa, 0x01, 0x6f, 0xd6, 0xd2, 0x20, 0x58, 0x01, - 0x18, 0x77, 0xbe, 0xe1, 0x64, 0x69, 0x60, 0xab, 0x80, 0x0a, 0xab, 0xc2, 0x0f, 0x28, 0xe7, 0x93, 0x0a, 0x2d, 0x44, - 0xc3, 0x11, 0x66, 0x23, 0x9d, 0xec, 0xb7, 0xb0, 0x18, 0x8f, 0x25, 0x53, 0x70, 0x74, 0x14, 0xec, 0x2b, 0x2b, 0xa4, - 0x3e, 0x45, 0x46, 0x6c, 0xc2, 0xf3, 0x4b, 0xf5, 0x89, 0x15, 0x42, 0x7f, 0x6a, 0x0d, 0x46, 0x1c, 0xe8, 0x55, 0x0c, - 0x70, 0x92, 0xf1, 0x39, 0x54, 0x9d, 0x14, 0xe0, 0xf4, 0x03, 0x7f, 0x79, 0x1a, 0xfb, 0x6d, 0x02, 0xf9, 0xfa, 0x60, - 0xc2, 0xba, 0xe0, 0xb4, 0xa0, 0xb7, 0xaf, 0xf3, 0x2b, 0xd8, 0x51, 0x97, 0x05, 0xa3, 0x90, 0x0d, 0x49, 0xef, 0xa0, - 0x29, 0xf8, 0x80, 0x36, 0x5f, 0x6a, 0xc0, 0xc5, 0x67, 0xfa, 0xc3, 0x54, 0x74, 0x41, 0x0b, 0xa3, 0xb2, 0x2d, 0x9d, - 0xa9, 0x4f, 0xe9, 0x2a, 0xd3, 0x84, 0x85, 0x2a, 0xa7, 0xb0, 0xc6, 0x36, 0xea, 0x89, 0x3f, 0x98, 0x94, 0xca, 0x69, - 0x3c, 0x18, 0xea, 0xbf, 0xaf, 0x4d, 0xc9, 0x16, 0xb6, 0x41, 0x67, 0xd6, 0x58, 0xbf, 0x18, 0xea, 0x95, 0x6f, 0x63, - 0xb8, 0x87, 0x85, 0x67, 0x2b, 0x6b, 0xe4, 0xf3, 0xc4, 0x91, 0xcd, 0x93, 0xf5, 0x5a, 0x0f, 0x44, 0xc6, 0xa0, 0x07, - 0x7a, 0xeb, 0xb6, 0x4d, 0x0b, 0xb6, 0x47, 0xf9, 0xd5, 0x6d, 0xe1, 0x19, 0x87, 0x57, 0x38, 0x5d, 0x7b, 0xd7, 0xaa, - 0x10, 0x5f, 0x2c, 0x48, 0x5a, 0x5e, 0x8a, 0x99, 0x8e, 0xd7, 0xd9, 0x31, 0xf6, 0x46, 0x0e, 0xf4, 0xfc, 0xfa, 0x8b, - 0x81, 0xb5, 0xfb, 0xfd, 0xa6, 0x2c, 0x98, 0xd1, 0x11, 0xcb, 0xca, 0x09, 0x25, 0xee, 0xfc, 0x7c, 0xc3, 0xa3, 0x0a, - 0x15, 0xec, 0xf3, 0x55, 0xb0, 0xa7, 0x4d, 0x84, 0xcb, 0x19, 0xfd, 0xcb, 0xfc, 0x30, 0x81, 0x75, 0x4a, 0x2d, 0x5b, - 0x52, 0x08, 0x29, 0x2f, 0x4d, 0x9a, 0x39, 0x7a, 0xe0, 0x88, 0x7c, 0x09, 0x5d, 0x00, 0xaf, 0x9f, 0x16, 0x62, 0xae, - 0x11, 0xc1, 0xfe, 0xb6, 0xe3, 0xd6, 0xbe, 0x02, 0xe0, 0xed, 0xb0, 0x57, 0xfd, 0xd3, 0x02, 0xf6, 0x37, 0x28, 0x4b, - 0xba, 0xf1, 0x76, 0xcc, 0xf1, 0x5f, 0x08, 0x08, 0x97, 0x6e, 0xf0, 0x30, 0xb2, 0xe8, 0x54, 0xb2, 0x66, 0xe5, 0xcf, - 0xad, 0x92, 0x80, 0x61, 0xf5, 0x82, 0x3e, 0x1b, 0xb7, 0x55, 0xdc, 0x64, 0xfe, 0x07, 0x15, 0x34, 0x16, 0x7c, 0x6b, - 0x24, 0x15, 0xcb, 0xe2, 0xb6, 0x4f, 0x9d, 0xff, 0xaa, 0x73, 0x5c, 0xfb, 0xaa, 0xf6, 0x44, 0xe6, 0x48, 0x87, 0x27, - 0x0e, 0xd0, 0xc1, 0xc1, 0x46, 0x06, 0x1d, 0x03, 0xe0, 0x91, 0x65, 0xbf, 0xdc, 0xf2, 0x39, 0x76, 0x4c, 0x6b, 0x1e, - 0x8b, 0xc0, 0x67, 0xee, 0x1c, 0x37, 0x67, 0x26, 0xf2, 0x84, 0xca, 0xa9, 0x2b, 0x0c, 0x70, 0x7c, 0xbc, 0x95, 0x0a, - 0xf8, 0x1e, 0xac, 0x77, 0x4c, 0x60, 0x83, 0xdf, 0x32, 0x93, 0xda, 0x55, 0xd0, 0x2d, 0xd0, 0x72, 0x17, 0x53, 0xb9, - 0xb1, 0xc0, 0xc1, 0xe6, 0x44, 0x76, 0x0e, 0x7d, 0xa3, 0x4e, 0xc9, 0x7a, 0x3c, 0xd9, 0x6d, 0xf4, 0x95, 0xcb, 0x5d, - 0xc9, 0x15, 0x6d, 0x1b, 0xb1, 0xea, 0x99, 0x5c, 0x55, 0x99, 0x3a, 0x55, 0xd7, 0xbc, 0x95, 0xa5, 0x4d, 0x69, 0x97, - 0x64, 0xee, 0xb6, 0x98, 0x7f, 0x15, 0xde, 0x68, 0x94, 0x17, 0xa1, 0x60, 0x8f, 0x25, 0x87, 0x3d, 0x4e, 0xe0, 0x7a, - 0x61, 0xb5, 0x0a, 0xe1, 0xcf, 0xae, 0x31, 0xec, 0x32, 0x5d, 0xfa, 0xc0, 0x37, 0xf8, 0x15, 0x2f, 0x52, 0xaf, 0xb5, - 0x83, 0x04, 0xeb, 0x2e, 0x3b, 0x68, 0x38, 0x4e, 0xdc, 0x17, 0xbc, 0x13, 0xad, 0x9c, 0xcb, 0xc1, 0x24, 0xf9, 0xc6, - 0xdb, 0x72, 0x25, 0x6b, 0x59, 0x0b, 0xf3, 0xbe, 0x21, 0xc1, 0x10, 0xb3, 0x29, 0xad, 0xe3, 0x56, 0xd4, 0x46, 0x81, - 0x2d, 0x56, 0xa1, 0xff, 0xb7, 0x8a, 0x24, 0x26, 0xf3, 0xbf, 0x4e, 0x4f, 0x4f, 0x6d, 0x8a, 0xb5, 0xf9, 0x93, 0xda, - 0x03, 0x4e, 0x27, 0xb0, 0xaf, 0x3c, 0x61, 0x5a, 0x87, 0xfc, 0x16, 0x86, 0x42, 0x24, 0xb9, 0x70, 0xec, 0x12, 0x44, - 0xe5, 0x02, 0xca, 0x03, 0xec, 0xdf, 0x93, 0x8d, 0x72, 0xee, 0x9d, 0x24, 0x17, 0x47, 0xb8, 0x6c, 0x90, 0x7d, 0xd5, - 0x9f, 0x03, 0x63, 0x26, 0x03, 0x4f, 0x03, 0x04, 0xd8, 0xfc, 0xd6, 0x2c, 0xad, 0xb5, 0x94, 0xc1, 0x81, 0x12, 0x8b, - 0x64, 0x6a, 0x34, 0xff, 0xf6, 0x43, 0x97, 0xb5, 0x6f, 0xec, 0x40, 0x50, 0x2e, 0xb2, 0xb4, 0xe1, 0x30, 0x83, 0x1f, - 0xcb, 0xc8, 0x97, 0x7b, 0xaf, 0xd8, 0x82, 0xfd, 0x88, 0xf7, 0xaa, 0x14, 0xf8, 0xb8, 0x2c, 0x38, 0xcd, 0x7e, 0xc4, - 0x7b, 0x55, 0x04, 0x4c, 0x70, 0x85, 0xd4, 0x41, 0x24, 0xb1, 0x7e, 0x4f, 0x3a, 0x0e, 0x72, 0xa0, 0xa0, 0x59, 0xa0, - 0x0f, 0xb2, 0xe7, 0x36, 0x68, 0x62, 0xd4, 0xc1, 0x36, 0xee, 0x97, 0x09, 0x85, 0x6a, 0x22, 0x88, 0x43, 0x20, 0xb9, - 0x72, 0x36, 0xfa, 0xeb, 0xf1, 0xc6, 0x82, 0x68, 0x65, 0x32, 0xb9, 0x78, 0xce, 0xc3, 0x7c, 0x73, 0xb1, 0x90, 0x5f, - 0xcd, 0x5b, 0xa0, 0x5a, 0x95, 0x2a, 0xdd, 0x2f, 0xbe, 0x5d, 0x30, 0xf1, 0x8a, 0xe8, 0xad, 0x77, 0x79, 0x07, 0xcf, - 0x9d, 0xdf, 0x05, 0x2e, 0x09, 0x9e, 0x04, 0xd7, 0x98, 0xea, 0x5e, 0x80, 0x07, 0x42, 0xcf, 0xa4, 0x0a, 0xb0, 0xce, - 0x93, 0x10, 0x49, 0x6c, 0xbf, 0x85, 0x2d, 0x6b, 0xf4, 0x22, 0x77, 0x42, 0x0a, 0x9c, 0xab, 0xba, 0x89, 0x19, 0xe5, - 0x3a, 0xba, 0xd8, 0xa5, 0x9c, 0xb3, 0x44, 0x19, 0x04, 0xd8, 0xb7, 0x68, 0x28, 0xf2, 0xe7, 0x1a, 0x14, 0xfa, 0x2d, - 0x6b, 0x9b, 0x72, 0x05, 0x8b, 0xe7, 0xa5, 0x00, 0x51, 0xe3, 0xf9, 0xa4, 0xac, 0x33, 0xcf, 0x16, 0x13, 0x9e, 0x57, - 0xc8, 0x50, 0x30, 0x39, 0x17, 0x39, 0x3c, 0x25, 0x51, 0x16, 0xd1, 0x74, 0xa8, 0x86, 0xef, 0x86, 0x84, 0x95, 0x75, - 0xf4, 0x31, 0xc5, 0xf3, 0xaa, 0x06, 0x30, 0x17, 0x97, 0xfe, 0x9b, 0xf3, 0xf2, 0x75, 0xfe, 0x4e, 0xcc, 0xab, 0x7c, - 0x47, 0xe3, 0x5c, 0xc4, 0x76, 0x6b, 0x37, 0x8c, 0xd6, 0xfa, 0xb5, 0x27, 0x6f, 0xfb, 0x7e, 0xe0, 0xd5, 0x0b, 0x68, - 0x6b, 0xfd, 0x5e, 0x54, 0x99, 0x35, 0x62, 0xe5, 0xe3, 0x08, 0x55, 0x7b, 0xf5, 0xaa, 0xb9, 0xad, 0x08, 0x50, 0x29, - 0x78, 0xba, 0x95, 0xff, 0x44, 0x99, 0x7c, 0x73, 0x0e, 0x95, 0xe1, 0x81, 0x1c, 0x19, 0xaa, 0x7a, 0xc0, 0x45, 0xf9, - 0xa1, 0x9f, 0xbe, 0x0a, 0x74, 0xe0, 0xdc, 0x5d, 0x17, 0xc8, 0x9c, 0xc9, 0x50, 0xe0, 0xe5, 0x80, 0x0e, 0x63, 0x23, - 0x0f, 0xc5, 0x02, 0x6c, 0x7b, 0x6e, 0x0b, 0xae, 0x5c, 0x84, 0x5e, 0x3c, 0x60, 0xc3, 0x78, 0x59, 0x8f, 0xe2, 0x6b, - 0xe2, 0x08, 0x3b, 0x73, 0x4e, 0x1d, 0xf6, 0x96, 0x0e, 0x71, 0x46, 0xc0, 0xf6, 0xd8, 0xb1, 0xa7, 0x6f, 0xc2, 0x04, - 0xf5, 0xeb, 0x1c, 0xfe, 0x72, 0x8d, 0x33, 0x9c, 0xa0, 0xf8, 0x32, 0x84, 0x0b, 0xac, 0x35, 0x06, 0xf0, 0x25, 0x86, - 0x54, 0x81, 0x47, 0x6a, 0xa2, 0x25, 0x56, 0x7b, 0x11, 0x88, 0x96, 0xca, 0xbf, 0x1d, 0x67, 0x2e, 0x0e, 0xb6, 0xe6, - 0x5e, 0x9f, 0x69, 0xe1, 0x70, 0x92, 0x84, 0xb5, 0x73, 0x86, 0x93, 0x8b, 0x7d, 0x5e, 0x3b, 0x31, 0xc1, 0xda, 0xdb, - 0x3f, 0x55, 0x40, 0x8f, 0x06, 0xa7, 0x8a, 0xa1, 0x21, 0x10, 0x33, 0x01, 0xbc, 0x99, 0xfd, 0xa3, 0xcd, 0xc3, 0xf9, - 0x60, 0x8d, 0xbd, 0xaf, 0xb8, 0xd6, 0xd5, 0xa6, 0x12, 0x65, 0xbd, 0xc6, 0x83, 0x69, 0x82, 0xd3, 0x04, 0xcf, 0x93, - 0xa1, 0x77, 0xdc, 0xcc, 0x12, 0xdf, 0xa4, 0x6b, 0xb5, 0x7a, 0x6a, 0xcd, 0x08, 0x91, 0xf9, 0x69, 0xe8, 0x0f, 0xea, - 0x03, 0xc2, 0xc7, 0x90, 0x05, 0xb4, 0xa4, 0x6f, 0xff, 0x36, 0xcc, 0x33, 0xd9, 0xa8, 0x11, 0xf2, 0xc8, 0x90, 0x91, - 0xbe, 0xfb, 0x51, 0x66, 0x99, 0xd6, 0x1a, 0xc1, 0xfc, 0x6e, 0x2f, 0x68, 0xb8, 0xf6, 0x3c, 0x2d, 0x5b, 0x69, 0xb6, - 0x03, 0x88, 0x62, 0x8c, 0x93, 0x94, 0xb7, 0x46, 0x62, 0xb5, 0x0a, 0x4d, 0x0a, 0xe1, 0xd1, 0x8c, 0x51, 0xb9, 0x28, - 0xf4, 0xcb, 0x71, 0x61, 0x8e, 0x22, 0xcd, 0xef, 0x62, 0x6b, 0x23, 0x9a, 0x83, 0xdb, 0x23, 0x18, 0x6e, 0x84, 0x92, - 0x88, 0x9a, 0xc8, 0x3d, 0x4a, 0x2a, 0xcb, 0x20, 0x49, 0xa4, 0x16, 0xf9, 0xcd, 0x75, 0xa9, 0x39, 0x0c, 0xec, 0x1f, - 0xed, 0x0b, 0x08, 0x37, 0x6f, 0x13, 0x5a, 0x8c, 0xe8, 0x04, 0xd8, 0x58, 0x88, 0x43, 0xb8, 0x95, 0xb0, 0x5a, 0x0d, - 0x86, 0x3d, 0x43, 0x9e, 0xed, 0xcb, 0x79, 0x65, 0x43, 0xbb, 0x1b, 0x80, 0xab, 0x6e, 0x43, 0xcd, 0x95, 0xd6, 0xfd, - 0x50, 0xfd, 0xb8, 0x17, 0xb7, 0x49, 0xf6, 0x7d, 0x8e, 0xea, 0x09, 0xee, 0x9a, 0x05, 0xb8, 0x0e, 0x5d, 0x85, 0x53, - 0xbc, 0x30, 0x36, 0x9c, 0xfa, 0x25, 0x27, 0xaa, 0x1f, 0x70, 0x82, 0x77, 0xa3, 0x09, 0x1b, 0x24, 0x43, 0x9c, 0xba, - 0x38, 0xdf, 0xfb, 0x6f, 0xc3, 0x14, 0xa1, 0x82, 0x68, 0x98, 0x1a, 0x97, 0xed, 0xb4, 0xb2, 0xdb, 0xd7, 0x99, 0x9a, - 0x61, 0xd0, 0x46, 0xcc, 0xa9, 0x6f, 0xc4, 0x9c, 0x35, 0x1a, 0x68, 0x41, 0x52, 0x30, 0x62, 0x5e, 0x78, 0xad, 0x2d, - 0xcc, 0x2b, 0x9f, 0x5e, 0x7b, 0x0b, 0x84, 0x7a, 0x1c, 0x68, 0x9a, 0x82, 0xf7, 0x3c, 0xaa, 0xf7, 0xd4, 0xdd, 0xeb, - 0x52, 0x47, 0x1d, 0x50, 0x24, 0x8c, 0x2f, 0xdc, 0x24, 0x8c, 0x6b, 0xb8, 0x19, 0xf7, 0x58, 0x8f, 0xdb, 0xda, 0x36, - 0xe4, 0x03, 0x31, 0x48, 0x86, 0xc3, 0x9e, 0x70, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x5e, 0x00, 0xa9, 0x16, 0xef, 0xab, - 0xda, 0xbc, 0xf2, 0xe6, 0xee, 0x61, 0xd1, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, 0x1f, 0xaa, 0xe2, 0x83, 0x1d, - 0x75, 0x20, 0x0a, 0x5a, 0xdc, 0xaa, 0x09, 0xa4, 0xc6, 0xcc, 0x2e, 0x54, 0xcd, 0x1c, 0x1d, 0x4a, 0x08, 0x43, 0x96, - 0x57, 0xdd, 0xdd, 0xe7, 0x9e, 0x6a, 0x88, 0xc3, 0xa9, 0x7f, 0x65, 0x8c, 0x58, 0xc3, 0xa0, 0x93, 0x06, 0xda, 0x48, - 0xd2, 0x2c, 0x1f, 0x3c, 0xfa, 0x03, 0x56, 0x02, 0x2e, 0xf8, 0xb2, 0x4e, 0xd2, 0x86, 0x04, 0x6f, 0x59, 0xa2, 0x34, - 0x1f, 0xc2, 0x2d, 0x82, 0xf2, 0xc8, 0xc4, 0xda, 0xb4, 0x95, 0x0c, 0xe4, 0xaa, 0x2e, 0x6f, 0x3c, 0xf4, 0xbc, 0x4f, - 0xaa, 0xdd, 0x00, 0x1c, 0x99, 0x37, 0xb0, 0x64, 0x6b, 0x9f, 0x80, 0x47, 0x3e, 0xae, 0x10, 0xc4, 0x2d, 0x85, 0x8a, - 0x74, 0xa0, 0xea, 0x6b, 0xd8, 0xa0, 0x78, 0x0e, 0x0e, 0x82, 0x56, 0x82, 0xc3, 0xe0, 0x5d, 0x66, 0x34, 0xc9, 0x1a, - 0xb7, 0x66, 0x24, 0x9c, 0xaf, 0x56, 0x2d, 0x74, 0xf8, 0xb7, 0x7e, 0x8b, 0x79, 0x5c, 0x2a, 0xdc, 0xc7, 0x95, 0xc2, - 0x1d, 0x2c, 0x01, 0xc9, 0xd8, 0xd3, 0xb5, 0x63, 0xe1, 0xab, 0xd1, 0x21, 0x4c, 0xf8, 0x0b, 0x08, 0x1a, 0x6d, 0x8f, - 0x25, 0xd0, 0xb3, 0x6f, 0x15, 0x30, 0xba, 0xf6, 0xb2, 0x04, 0xd2, 0x82, 0xbb, 0xdb, 0x04, 0x5a, 0x85, 0xa8, 0x7d, - 0xfe, 0xf4, 0x73, 0x0e, 0x3c, 0xb2, 0xfe, 0x5c, 0x33, 0xcd, 0xba, 0x17, 0xf4, 0x56, 0x37, 0x1f, 0x8e, 0x71, 0x73, - 0x6c, 0xc0, 0x79, 0xd4, 0x81, 0x9f, 0x06, 0xa2, 0x47, 0x1d, 0x6c, 0x53, 0xf1, 0xb8, 0x04, 0xb2, 0x8f, 0x9e, 0xd6, - 0x40, 0x0a, 0x58, 0xe9, 0xd0, 0x68, 0x91, 0x26, 0x68, 0xb5, 0x9a, 0x9c, 0x93, 0x16, 0x42, 0x4b, 0x79, 0xcb, 0x55, - 0x32, 0x05, 0x1f, 0x69, 0x50, 0x0c, 0xbc, 0xa1, 0x6a, 0x1a, 0x22, 0x3c, 0x46, 0xcb, 0x94, 0x8d, 0xe9, 0x22, 0x53, - 0x71, 0xde, 0xe7, 0x91, 0x89, 0xa4, 0xcb, 0x4c, 0x24, 0xb8, 0xa3, 0x0e, 0x9e, 0x68, 0xfe, 0xf2, 0xb1, 0x36, 0x07, - 0x29, 0x12, 0x9d, 0x3c, 0xd1, 0x09, 0x98, 0x47, 0x49, 0x26, 0x24, 0x33, 0xcd, 0xf4, 0x8c, 0x6d, 0x39, 0xc4, 0xe2, - 0x0e, 0x54, 0xc1, 0xb5, 0x15, 0x65, 0x10, 0x4f, 0x49, 0xde, 0xcf, 0x8f, 0x3a, 0xf1, 0x04, 0xf3, 0x08, 0x38, 0xbd, - 0x77, 0x22, 0x64, 0x8d, 0xf2, 0x56, 0x74, 0x86, 0x0e, 0xa7, 0x58, 0x56, 0x97, 0xa8, 0x33, 0x74, 0x38, 0x41, 0x78, - 0xd6, 0x20, 0x59, 0x0e, 0x1e, 0xc3, 0x3c, 0xff, 0x3f, 0x52, 0xfe, 0x9b, 0xc3, 0x86, 0x98, 0xcf, 0x6f, 0x61, 0xa7, - 0xb0, 0x34, 0x88, 0x33, 0x02, 0x5e, 0x8b, 0xed, 0x53, 0x9c, 0x90, 0x49, 0x33, 0x73, 0x01, 0xf7, 0x74, 0x2b, 0x8d, - 0x3b, 0x85, 0x0e, 0x13, 0x9c, 0x6e, 0x26, 0x85, 0x7a, 0xae, 0xcd, 0x2c, 0x4e, 0xe0, 0x7c, 0xaf, 0x46, 0x61, 0xcb, - 0x2f, 0x36, 0x93, 0xfc, 0xf2, 0x16, 0xb8, 0xcd, 0x14, 0xcb, 0x26, 0xc5, 0x19, 0x9e, 0x35, 0x5f, 0xe1, 0x59, 0xf3, - 0x43, 0x99, 0xd1, 0x58, 0x60, 0x09, 0xc1, 0xfb, 0x20, 0x11, 0xcf, 0xaa, 0xe4, 0x14, 0xcb, 0x86, 0x2e, 0x8f, 0x67, - 0x8d, 0xaa, 0x74, 0x73, 0x81, 0x65, 0x43, 0x97, 0x6e, 0x7c, 0xc0, 0xb3, 0xc6, 0xab, 0x7f, 0x31, 0xe9, 0x20, 0x06, - 0x74, 0x99, 0xa3, 0x65, 0x62, 0x86, 0x78, 0xfd, 0xdb, 0xdb, 0x77, 0xed, 0x9b, 0xce, 0xe1, 0x04, 0xbb, 0xf5, 0x4b, - 0x34, 0x8e, 0x25, 0x2a, 0x64, 0x4d, 0x80, 0x68, 0x82, 0x3b, 0x87, 0x53, 0xdc, 0x39, 0x4c, 0x6c, 0x53, 0xeb, 0x59, - 0x83, 0xdc, 0x29, 0x1f, 0x8a, 0x2a, 0x88, 0x7d, 0xf8, 0xb8, 0xc9, 0xc6, 0x13, 0x54, 0x03, 0x25, 0x3a, 0x9c, 0xd4, - 0x40, 0x05, 0xdf, 0x8b, 0xda, 0x77, 0x55, 0xaf, 0xc2, 0x20, 0x03, 0x25, 0xe4, 0xaf, 0xb9, 0x06, 0x4f, 0x2d, 0x45, - 0x43, 0xc6, 0x4f, 0x31, 0x40, 0xf9, 0x0e, 0x28, 0xb4, 0xf2, 0x44, 0x0f, 0xdd, 0x9b, 0x8e, 0x4e, 0xfc, 0xff, 0x79, - 0x32, 0xe5, 0xd0, 0xcb, 0x2d, 0xb3, 0x35, 0x3d, 0x3b, 0x19, 0x7f, 0xf8, 0xc0, 0x63, 0xfd, 0x5f, 0x3b, 0x50, 0xac, - 0x41, 0x8a, 0xff, 0x2f, 0x1d, 0x9d, 0x0f, 0x46, 0xc8, 0x0a, 0xe2, 0xc2, 0x22, 0xfe, 0xf7, 0x87, 0xe5, 0x75, 0x5f, - 0x6c, 0x75, 0x5f, 0xe8, 0xee, 0xfd, 0xa6, 0xb5, 0x2a, 0x27, 0xae, 0x2a, 0x19, 0xf2, 0x5f, 0xa7, 0x5b, 0x5b, 0xa0, - 0x91, 0x35, 0x7a, 0x36, 0xf1, 0x1b, 0xdc, 0x6f, 0xc7, 0x3b, 0x90, 0x79, 0xcd, 0xcd, 0xd3, 0xa0, 0x70, 0xf8, 0x7a, - 0x77, 0xaa, 0x17, 0x2d, 0xf0, 0xde, 0x94, 0x5a, 0x5f, 0x19, 0xfa, 0x96, 0x83, 0xc5, 0xa6, 0x29, 0xb7, 0x36, 0x96, - 0x8e, 0xba, 0x58, 0xbb, 0x22, 0x42, 0xa5, 0xbb, 0x0b, 0x50, 0x8a, 0x8f, 0x55, 0x93, 0xe9, 0xaf, 0x73, 0x15, 0xe9, - 0x4b, 0xa8, 0x86, 0xfe, 0xbc, 0xbf, 0x50, 0x91, 0x12, 0x73, 0x93, 0x77, 0x7f, 0x0e, 0x7d, 0x82, 0x86, 0xb5, 0xe1, - 0xd9, 0xed, 0xb3, 0xc2, 0xea, 0x77, 0xaa, 0x43, 0xd0, 0x3f, 0x80, 0x2c, 0x69, 0x31, 0x7d, 0x60, 0xdd, 0x1a, 0xb6, - 0x5d, 0x34, 0xcb, 0x44, 0xd3, 0x6a, 0x53, 0xe7, 0x9a, 0x3d, 0xcc, 0xe7, 0x3e, 0x4f, 0xc1, 0x0b, 0xa3, 0x1f, 0xdf, - 0xc1, 0x6e, 0xdc, 0xd5, 0x18, 0x89, 0xba, 0x92, 0xa9, 0x84, 0x7e, 0x74, 0x87, 0x59, 0x74, 0xaf, 0xbd, 0x18, 0x73, - 0xed, 0xef, 0xa3, 0x03, 0xe5, 0x07, 0x95, 0x24, 0x07, 0x96, 0xfd, 0x0d, 0x16, 0xdd, 0x81, 0x79, 0x62, 0x59, 0x4d, - 0x60, 0x15, 0xdd, 0x7b, 0x8b, 0x28, 0x74, 0x23, 0x6b, 0xcd, 0x80, 0xea, 0x66, 0x8c, 0x7a, 0x70, 0x1f, 0x02, 0x3d, - 0xf4, 0xcb, 0x52, 0xca, 0x76, 0x16, 0xd7, 0xba, 0x57, 0xba, 0xfb, 0xcd, 0x01, 0x79, 0x7c, 0xa1, 0xc7, 0x35, 0xfd, - 0xab, 0x49, 0x44, 0x23, 0xf6, 0x0f, 0x67, 0xc5, 0xd5, 0xa2, 0xd0, 0x98, 0x26, 0xfb, 0x2a, 0x4a, 0xe6, 0x6d, 0x30, - 0xd5, 0x4b, 0xe6, 0x9d, 0x3b, 0x6c, 0xbf, 0xef, 0xcd, 0xf7, 0x3d, 0x96, 0x7d, 0xa6, 0x33, 0x62, 0xa6, 0x8b, 0xb9, - 0xef, 0x7b, 0xf3, 0x7d, 0x8f, 0xb7, 0x07, 0x73, 0xeb, 0x2e, 0x14, 0x4b, 0x76, 0x86, 0x0b, 0x30, 0x2c, 0xf7, 0xb8, - 0x9b, 0x5a, 0x96, 0x0e, 0x02, 0x5b, 0x4b, 0x80, 0x38, 0x9f, 0x4f, 0xc3, 0x8a, 0x57, 0x43, 0xc0, 0x7d, 0x3a, 0xd7, - 0xf6, 0x2a, 0x15, 0x78, 0x4c, 0xd0, 0x88, 0xe8, 0xd8, 0x36, 0xfa, 0x59, 0x2f, 0xe0, 0xf2, 0x88, 0x2a, 0xf5, 0x24, - 0x11, 0xf0, 0xaa, 0x5a, 0xe5, 0xad, 0x8b, 0x94, 0x5f, 0xc4, 0xcb, 0x71, 0xc5, 0x1e, 0x53, 0xc9, 0x00, 0x56, 0x65, - 0x49, 0x97, 0x40, 0xea, 0xf9, 0xde, 0x44, 0xbf, 0x6c, 0x22, 0x4f, 0xae, 0x6f, 0x4b, 0xbf, 0x30, 0x35, 0x2d, 0xc4, - 0x62, 0x32, 0x05, 0x1f, 0x5a, 0x60, 0x19, 0x0a, 0x5d, 0xaf, 0xb2, 0xf5, 0xaf, 0x49, 0x6e, 0x12, 0x28, 0x9c, 0x6a, - 0x8a, 0x88, 0x26, 0x6a, 0x41, 0x33, 0x6d, 0x49, 0xca, 0xf3, 0xc9, 0x63, 0x71, 0xf7, 0x12, 0xb0, 0x9b, 0x12, 0xd5, - 0xd8, 0x91, 0xf7, 0x16, 0x76, 0x00, 0x4e, 0x08, 0xdb, 0x55, 0xf1, 0x52, 0x82, 0xce, 0x1f, 0x67, 0x84, 0xed, 0xaa, - 0xfa, 0x84, 0x99, 0xec, 0x29, 0xd9, 0x18, 0x6e, 0x3f, 0x4c, 0x1a, 0x19, 0x3a, 0xea, 0xc4, 0x59, 0xcf, 0x11, 0x03, - 0x03, 0x50, 0x0f, 0xb8, 0x5b, 0xdb, 0xb3, 0xbc, 0xbb, 0x21, 0x79, 0x94, 0xb2, 0x44, 0x98, 0xeb, 0x72, 0x9d, 0xb2, - 0x5a, 0x75, 0x2a, 0x2a, 0x58, 0xe0, 0xa9, 0xb7, 0x17, 0xa8, 0xf9, 0xda, 0x41, 0x71, 0xae, 0x93, 0x4d, 0xd3, 0xf3, - 0xb2, 0xef, 0xde, 0x8e, 0x45, 0xc6, 0x26, 0xed, 0xed, 0x0e, 0x22, 0x61, 0x38, 0x61, 0xe5, 0x71, 0xc2, 0x55, 0x6d, - 0x8f, 0x00, 0xdd, 0x78, 0x22, 0x37, 0x16, 0x64, 0xb9, 0xae, 0x8c, 0xee, 0x3d, 0xbf, 0x5b, 0x4a, 0x84, 0x1d, 0x6d, - 0x49, 0x30, 0x5d, 0x82, 0x56, 0xd3, 0xe9, 0x37, 0x99, 0x6b, 0xcf, 0x0d, 0x6f, 0x8a, 0xb6, 0xb9, 0xbd, 0x49, 0xc7, - 0x7a, 0x7b, 0xe8, 0x18, 0xca, 0x20, 0x06, 0x3a, 0x1f, 0xf1, 0x5e, 0xa3, 0x91, 0x20, 0x50, 0xc8, 0x24, 0x43, 0x2c, - 0x22, 0xa7, 0x45, 0x3f, 0x38, 0xd0, 0xf0, 0xa8, 0x12, 0x10, 0xa6, 0x20, 0x84, 0xf8, 0x5d, 0x6b, 0x84, 0xf5, 0x97, - 0xab, 0x96, 0x0b, 0x1b, 0xa9, 0x36, 0x74, 0xf0, 0xff, 0xf2, 0x97, 0xad, 0x9e, 0x59, 0x2e, 0x8a, 0xc6, 0xcd, 0x4c, - 0x83, 0x45, 0x80, 0xf4, 0x68, 0xb2, 0x1d, 0x14, 0x77, 0xe7, 0x62, 0xbd, 0x21, 0x20, 0x31, 0x83, 0x09, 0xca, 0x86, - 0x75, 0x63, 0x0c, 0xf3, 0xa8, 0xd2, 0xb2, 0xd6, 0x24, 0x66, 0xcf, 0x97, 0xce, 0x5f, 0xf7, 0xe5, 0x5d, 0xcc, 0xf0, - 0x7d, 0x2c, 0xf1, 0x2d, 0x78, 0xd2, 0xc4, 0x02, 0xdb, 0xc7, 0x0b, 0x8a, 0x35, 0x51, 0x3d, 0xc7, 0xde, 0x16, 0xb0, - 0xce, 0x7a, 0x8f, 0x48, 0xef, 0x77, 0xf5, 0xab, 0x0d, 0xbe, 0x5b, 0xf8, 0x15, 0x58, 0x3f, 0x7b, 0x27, 0x29, 0x96, - 0x0d, 0xd1, 0x2c, 0xec, 0x91, 0x01, 0xe5, 0x2a, 0x7e, 0xd9, 0x4f, 0xdd, 0x2a, 0x86, 0x6b, 0x1f, 0xaf, 0xf0, 0x87, - 0x8d, 0x76, 0x1b, 0x79, 0x59, 0xdc, 0xec, 0x4d, 0xd9, 0x10, 0x55, 0xd3, 0x3b, 0x32, 0x37, 0x52, 0xea, 0x5f, 0x1f, - 0x70, 0x6b, 0xab, 0x7d, 0x37, 0xcd, 0xb7, 0x0e, 0x9d, 0xab, 0xa6, 0x5d, 0x6a, 0xad, 0x08, 0xf6, 0x7e, 0xb6, 0x70, - 0x73, 0x6b, 0xc0, 0x1e, 0xfc, 0xdc, 0x1d, 0xcd, 0x55, 0x02, 0xd1, 0xe9, 0x8d, 0x66, 0x7c, 0x15, 0xfe, 0x99, 0x36, - 0xc2, 0x7e, 0xfc, 0x67, 0xf4, 0x67, 0xda, 0x40, 0x7d, 0x14, 0xce, 0xef, 0x56, 0x6c, 0xb6, 0x82, 0x60, 0x6b, 0x0f, - 0x8e, 0xf0, 0x6b, 0xbf, 0x24, 0x57, 0x34, 0xe3, 0xc9, 0xca, 0xbe, 0x84, 0xb7, 0xb2, 0xcf, 0x04, 0xad, 0xf4, 0xe3, - 0x4e, 0xab, 0x50, 0x8c, 0x32, 0x08, 0x2c, 0x1c, 0xee, 0x35, 0xfb, 0x83, 0x56, 0xf3, 0xd1, 0xd0, 0xfc, 0xab, 0x23, - 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x04, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, 0xe9, 0x55, 0x82, - 0x8c, 0xef, 0xc9, 0x6a, 0xc5, 0x6c, 0x34, 0x6b, 0xab, 0xc1, 0x2f, 0x63, 0x33, 0x1d, 0xb6, 0xa3, 0x4e, 0xcf, 0x89, - 0xb1, 0xa4, 0x01, 0x91, 0xa6, 0x31, 0x83, 0x40, 0x52, 0x4b, 0xcd, 0x61, 0xcd, 0xef, 0x82, 0xb8, 0xba, 0x3f, 0x82, - 0x94, 0x1f, 0x82, 0x98, 0x1f, 0x11, 0x08, 0xa0, 0x6d, 0x98, 0xa3, 0xb2, 0x21, 0xe7, 0xbb, 0xf4, 0x40, 0x3b, 0x33, - 0x34, 0xf8, 0x6a, 0xd5, 0xaa, 0x86, 0x29, 0x8b, 0xfa, 0x30, 0x97, 0x6b, 0x2c, 0xc9, 0x1b, 0xd0, 0x35, 0xe7, 0x44, - 0xf6, 0x7d, 0x57, 0x79, 0x78, 0x08, 0x18, 0x0b, 0x02, 0x4e, 0xfa, 0x7d, 0xd9, 0x2f, 0xc8, 0xc5, 0x65, 0x08, 0x3e, - 0x66, 0x98, 0x0f, 0xd4, 0xa0, 0x18, 0x0e, 0x51, 0x6c, 0x9d, 0xce, 0x62, 0x1d, 0x71, 0xc5, 0xf3, 0x4b, 0x2e, 0xc0, - 0x2f, 0x39, 0x47, 0x6c, 0x50, 0x0c, 0xc9, 0x83, 0x24, 0x14, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, 0xd2, 0x37, 0x30, - 0xd5, 0xc3, 0xd2, 0x17, 0xd9, 0x60, 0x31, 0x67, 0x2c, 0x81, 0xe0, 0x66, 0xc0, 0x5e, 0x6a, 0x43, 0xa2, 0xb6, 0x06, - 0x0a, 0xee, 0x02, 0xdf, 0xcc, 0xe8, 0xe9, 0x56, 0x1b, 0x83, 0xc0, 0xe2, 0x85, 0xbe, 0x86, 0x31, 0x08, 0xa4, 0x2f, - 0x57, 0x1d, 0xf6, 0x97, 0x1f, 0x26, 0xcb, 0x0f, 0x5e, 0xa1, 0x4d, 0x76, 0x4a, 0xab, 0x44, 0x3d, 0xbe, 0xca, 0x13, - 0x47, 0x13, 0x64, 0x62, 0xa8, 0x74, 0xc3, 0x32, 0x71, 0x25, 0x7d, 0x26, 0x9a, 0x6c, 0x37, 0x1c, 0x33, 0xe7, 0xbb, - 0xd9, 0xfe, 0x61, 0xdd, 0xce, 0x39, 0xe1, 0x5a, 0x2b, 0xa9, 0xb5, 0x51, 0xcf, 0x34, 0x55, 0xb5, 0xc1, 0xfc, 0x2e, - 0xad, 0x96, 0x16, 0x5b, 0x57, 0xef, 0x9e, 0xff, 0x2c, 0x5d, 0x19, 0x7f, 0x8b, 0x55, 0xa1, 0x15, 0x19, 0x6e, 0xb7, - 0x90, 0x33, 0x67, 0xba, 0x74, 0x8a, 0x5c, 0xa8, 0x0e, 0x7f, 0x51, 0x4f, 0xea, 0x97, 0x2a, 0x83, 0x86, 0x74, 0xe8, - 0xf7, 0x3a, 0x01, 0xe5, 0x1f, 0x4c, 0x4c, 0x64, 0x2c, 0xba, 0xa5, 0x45, 0x1e, 0xfe, 0xf8, 0x22, 0xd7, 0xb1, 0xaa, - 0xf6, 0x60, 0x20, 0x7b, 0xba, 0xe2, 0x1e, 0xdc, 0x9a, 0xf0, 0x31, 0x67, 0x69, 0xbc, 0x17, 0xfc, 0xd8, 0x90, 0x8d, - 0x1f, 0x83, 0x1f, 0xc1, 0xdd, 0xd9, 0x3e, 0x8b, 0x58, 0xc6, 0x85, 0x70, 0xf7, 0x58, 0x97, 0xa5, 0x4a, 0x19, 0x2b, - 0xa7, 0x5b, 0xf6, 0x2f, 0xa4, 0xde, 0x24, 0xe1, 0xa5, 0x25, 0xd6, 0x26, 0x05, 0x2b, 0x9f, 0x92, 0xc2, 0xb3, 0x2b, - 0xfa, 0x56, 0x8b, 0xd9, 0x4b, 0x2d, 0xe9, 0xae, 0xaf, 0x2e, 0x4b, 0x15, 0x34, 0x1c, 0x84, 0xb6, 0xb4, 0x81, 0x04, - 0x18, 0xb8, 0x94, 0x3e, 0x9d, 0xf6, 0x4c, 0x22, 0xb3, 0x24, 0x84, 0x77, 0x0f, 0x2a, 0x98, 0xff, 0xce, 0x36, 0xc2, - 0xaa, 0xc0, 0xe5, 0x4a, 0x15, 0xf5, 0x52, 0x10, 0x08, 0x40, 0x5f, 0x7a, 0x0f, 0x8a, 0xf3, 0xa2, 0xd7, 0x68, 0x08, - 0xd0, 0xc2, 0x52, 0x7d, 0xad, 0x8a, 0xe9, 0xbe, 0xff, 0x9c, 0x9f, 0xf7, 0xe1, 0x1c, 0xd2, 0x36, 0xde, 0xd4, 0xa4, - 0x84, 0x9a, 0x1d, 0xb4, 0x0f, 0x56, 0xd9, 0x5e, 0xf9, 0xb7, 0x21, 0x45, 0x26, 0x7f, 0xc0, 0x7e, 0xa0, 0xb6, 0xc3, - 0xa1, 0x2d, 0x58, 0xf5, 0x52, 0x46, 0xc1, 0x80, 0x95, 0x03, 0x6e, 0x4f, 0x46, 0x09, 0x4d, 0xa6, 0x0c, 0xd4, 0xfd, - 0xa6, 0x68, 0x35, 0xb7, 0x27, 0x75, 0xbf, 0x21, 0xed, 0xec, 0x23, 0xb5, 0xb3, 0x4f, 0x0e, 0x5e, 0x2c, 0x82, 0xfc, - 0x21, 0x42, 0x85, 0xc3, 0xbc, 0x29, 0xd1, 0x51, 0x07, 0xb8, 0x33, 0x70, 0xe0, 0x01, 0x5b, 0x94, 0x83, 0x03, 0x6a, - 0x2d, 0xee, 0x69, 0x23, 0x71, 0xde, 0x9e, 0x50, 0xbb, 0x08, 0x25, 0x6e, 0xd6, 0xcc, 0xb4, 0xa0, 0xb5, 0x42, 0x3b, - 0x8f, 0x7b, 0xbc, 0xcd, 0xb3, 0x5a, 0xfc, 0x84, 0x0d, 0x6b, 0xaa, 0xfa, 0x0d, 0x34, 0x47, 0xb5, 0x20, 0x37, 0x4f, - 0xb5, 0xb7, 0x2a, 0x19, 0x04, 0xc1, 0xd0, 0x70, 0x2a, 0x44, 0x93, 0x8c, 0x41, 0x6b, 0xe8, 0xdd, 0x6a, 0xaf, 0x56, - 0xdc, 0x21, 0xbe, 0xac, 0x79, 0xab, 0xe9, 0x5b, 0x00, 0x5a, 0x84, 0x41, 0x79, 0x6f, 0x12, 0x80, 0xf7, 0x6d, 0x19, - 0x21, 0x6d, 0x39, 0x30, 0x6f, 0x36, 0x96, 0x8a, 0xcd, 0x77, 0x74, 0x32, 0x8c, 0x03, 0x33, 0xa2, 0x00, 0xdf, 0x94, - 0x90, 0x84, 0xab, 0xa4, 0x1b, 0x99, 0x88, 0x39, 0x93, 0x31, 0xc7, 0x37, 0x85, 0x10, 0xea, 0xda, 0x7c, 0x09, 0x5c, - 0xdd, 0xc9, 0x48, 0x7c, 0x33, 0x61, 0xea, 0x1d, 0x2d, 0x26, 0x0c, 0xfc, 0x8a, 0xdc, 0xed, 0x58, 0x4c, 0xc9, 0xc5, - 0x53, 0x19, 0x0e, 0x28, 0x86, 0x07, 0x47, 0x87, 0x58, 0xe9, 0x10, 0x28, 0x15, 0x2e, 0xb2, 0xdb, 0xbd, 0x37, 0x85, - 0xb8, 0xbb, 0x0f, 0x0b, 0x6c, 0x1d, 0x00, 0x4b, 0xa7, 0x49, 0x80, 0x7f, 0xf9, 0x98, 0x8f, 0xd1, 0x98, 0x53, 0xad, - 0xeb, 0xb7, 0xbf, 0xa3, 0x1b, 0xa0, 0xb7, 0xa5, 0xa3, 0xe0, 0xa0, 0x35, 0x84, 0x5c, 0xb8, 0x0b, 0x83, 0x8b, 0x2f, - 0xbf, 0xb6, 0x28, 0xb4, 0x37, 0x16, 0x40, 0xef, 0xaf, 0x04, 0x2c, 0xd8, 0x30, 0xc7, 0x14, 0x5e, 0x6b, 0x9d, 0x30, - 0xe5, 0x45, 0x05, 0x79, 0x52, 0xbe, 0xc7, 0x59, 0xab, 0xfd, 0x96, 0x8d, 0xe1, 0x0e, 0x23, 0xfa, 0x76, 0xe1, 0xc8, - 0x82, 0x07, 0x64, 0x9a, 0xc4, 0x34, 0xfb, 0xc6, 0x45, 0x1e, 0x79, 0x3d, 0x0e, 0x77, 0xb5, 0xe4, 0xe7, 0xeb, 0x15, - 0x5d, 0x63, 0x08, 0x45, 0xe1, 0xf7, 0xfb, 0x15, 0x1e, 0x28, 0xad, 0x0c, 0xda, 0xa0, 0x61, 0x71, 0x9b, 0xff, 0x02, - 0x67, 0x0c, 0xad, 0x17, 0x32, 0x77, 0x74, 0xc6, 0xe1, 0xcc, 0x62, 0xc6, 0x94, 0xc0, 0xa8, 0x94, 0x28, 0xe8, 0x04, - 0x1c, 0x9d, 0xab, 0x0f, 0x92, 0x87, 0xd5, 0xb1, 0x02, 0xf0, 0x24, 0x53, 0xf8, 0x27, 0xdb, 0x04, 0xeb, 0x7e, 0xab, - 0x66, 0x98, 0xfa, 0x8b, 0xda, 0x76, 0x2d, 0x5f, 0xfa, 0x38, 0xd2, 0xc6, 0x10, 0x5a, 0xe7, 0xee, 0x1e, 0x50, 0xc4, - 0x06, 0xbd, 0x88, 0x15, 0xbe, 0x91, 0x8b, 0x91, 0x5e, 0x5f, 0xed, 0x3a, 0xa6, 0x00, 0x51, 0xac, 0xbb, 0x26, 0xbe, - 0xa9, 0x9e, 0x3f, 0x95, 0x71, 0x0e, 0x67, 0x10, 0x84, 0x38, 0x29, 0x2f, 0x1b, 0x62, 0x41, 0x2e, 0x74, 0xa7, 0x42, - 0x77, 0x5a, 0x21, 0x94, 0x4d, 0x8f, 0xca, 0xfb, 0x57, 0x08, 0x61, 0xa0, 0xcb, 0xec, 0xc0, 0xaa, 0x7c, 0x0b, 0xab, - 0xe0, 0xd5, 0x8b, 0x0d, 0xac, 0x12, 0x70, 0x3c, 0x97, 0x68, 0x54, 0x54, 0x38, 0xa4, 0x49, 0x9f, 0x8f, 0x45, 0x90, - 0x00, 0x58, 0xf4, 0x2e, 0xb1, 0x79, 0xdf, 0xc3, 0x21, 0xbf, 0x27, 0x11, 0xf9, 0xd3, 0x8d, 0x68, 0x06, 0xef, 0xe2, - 0xca, 0xbe, 0x43, 0x08, 0x58, 0x7a, 0x8e, 0xe1, 0x3d, 0xe4, 0xef, 0xbf, 0xc3, 0x6a, 0x2d, 0xc8, 0xe3, 0x7f, 0x89, - 0x92, 0xd0, 0xd8, 0x7f, 0x8e, 0x87, 0x16, 0x09, 0xfd, 0x81, 0x6f, 0x8e, 0xb0, 0xc2, 0xc1, 0xad, 0x22, 0x2e, 0x83, - 0x5b, 0x7c, 0xac, 0x43, 0x0f, 0x00, 0x4b, 0x28, 0xf6, 0x41, 0xbe, 0x81, 0x62, 0x1a, 0x07, 0x14, 0x59, 0xfa, 0x17, - 0xb8, 0x60, 0xb5, 0x50, 0xde, 0xdf, 0xb6, 0x9c, 0x94, 0x56, 0xbb, 0xe4, 0xd5, 0xe6, 0x40, 0xe5, 0xa7, 0x7f, 0xe1, - 0x2b, 0xf5, 0x43, 0xcd, 0xf6, 0x0b, 0xdf, 0x58, 0xa0, 0xc7, 0xa0, 0x08, 0xb0, 0xbf, 0xd7, 0x84, 0x3b, 0x8a, 0x5e, - 0xe6, 0x62, 0xbf, 0x6d, 0xaf, 0x7b, 0x89, 0xb9, 0xbc, 0xae, 0xb2, 0xe6, 0x60, 0x0a, 0x0d, 0x0e, 0xaa, 0x70, 0x46, - 0x60, 0x2e, 0x5f, 0x94, 0x05, 0xe7, 0x20, 0xde, 0xf7, 0xa5, 0xce, 0x29, 0xa3, 0x01, 0xbc, 0x48, 0xca, 0x47, 0xa7, - 0xfa, 0x1c, 0x5c, 0xc6, 0x35, 0x9b, 0xf8, 0x44, 0xba, 0x54, 0x60, 0x25, 0x8d, 0x71, 0x68, 0x40, 0x53, 0x3a, 0x07, - 0xb3, 0x0d, 0xa0, 0xe0, 0xf6, 0x7c, 0xd8, 0x58, 0x28, 0xef, 0x2d, 0xda, 0xda, 0xd3, 0xd1, 0x84, 0x58, 0x93, 0x26, - 0xef, 0x6e, 0x5b, 0x23, 0x83, 0x33, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, 0x84, 0x27, 0x28, - 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xb2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x5a, 0x6a, 0x20, 0x2b, 0x6a, 0x90, - 0x7b, 0xd4, 0x40, 0xd4, 0xb7, 0x7f, 0x01, 0x0b, 0x61, 0x22, 0x54, 0x49, 0x2f, 0x20, 0xc2, 0x5c, 0x69, 0x3e, 0xa0, - 0x88, 0x7c, 0xc8, 0x6b, 0x40, 0x85, 0x94, 0xbc, 0x04, 0xa3, 0x71, 0x78, 0xbd, 0x07, 0xdc, 0x2f, 0x0d, 0xc3, 0xe0, - 0x38, 0x05, 0x9d, 0xff, 0xd6, 0xe5, 0x43, 0xf5, 0x72, 0x75, 0x10, 0xc2, 0x4f, 0x24, 0x64, 0x98, 0x46, 0x7e, 0x01, - 0xb2, 0x99, 0x63, 0x71, 0x70, 0x20, 0x40, 0xe0, 0x87, 0x28, 0xc2, 0x1e, 0xcf, 0xf0, 0x32, 0xd9, 0x20, 0x7a, 0x6e, - 0x56, 0x79, 0x35, 0x2b, 0xe1, 0xcd, 0xaa, 0x70, 0x34, 0x8e, 0xae, 0x09, 0x03, 0xc1, 0x85, 0x9a, 0x7d, 0x83, 0x10, - 0x28, 0x5b, 0x6e, 0x35, 0x5d, 0x7a, 0x0a, 0xe6, 0xa3, 0x61, 0xf0, 0x96, 0xc1, 0x8b, 0xba, 0xda, 0xe4, 0x9f, 0x29, - 0x96, 0x28, 0xcd, 0x3c, 0x36, 0x3c, 0x27, 0x75, 0x8a, 0xa2, 0xbf, 0x04, 0xcf, 0xc3, 0xa0, 0x79, 0x11, 0xa0, 0x06, - 0xfc, 0xdb, 0xe0, 0xa8, 0x47, 0x23, 0x9a, 0xa6, 0x2e, 0xf8, 0x4d, 0x42, 0xf4, 0x26, 0x5b, 0xad, 0x64, 0x45, 0xd0, - 0x23, 0xb3, 0xc1, 0x80, 0x95, 0x78, 0x02, 0x3b, 0xd6, 0x70, 0xb0, 0xe4, 0x85, 0x0c, 0x73, 0x77, 0x4a, 0xe1, 0x1c, - 0x43, 0x3a, 0xc2, 0x89, 0x17, 0xb3, 0xf1, 0x3f, 0x9f, 0xa9, 0xbf, 0x7e, 0x6e, 0xbe, 0x96, 0x11, 0x11, 0x2e, 0x88, - 0x5c, 0x8d, 0x1d, 0x91, 0x5e, 0xd8, 0x32, 0x35, 0xb0, 0x65, 0x7e, 0x70, 0xd6, 0xd5, 0x43, 0x13, 0x2e, 0x0e, 0x0c, - 0xa8, 0x91, 0x67, 0xb4, 0x82, 0x33, 0x52, 0x0e, 0x1c, 0x94, 0x10, 0x8a, 0x15, 0xe1, 0x94, 0x5c, 0x40, 0x24, 0xbc, - 0x04, 0xf5, 0xc0, 0xb0, 0xc0, 0x93, 0xa0, 0xa6, 0x20, 0x41, 0x25, 0xae, 0x76, 0x0a, 0xb3, 0xce, 0xf4, 0x6c, 0xa7, - 0xa8, 0x67, 0x83, 0xfc, 0xfc, 0xa2, 0xc2, 0x14, 0x58, 0xda, 0x83, 0x83, 0x02, 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, - 0x40, 0x4f, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0x4a, 0x7b, 0x1d, 0x68, 0x5b, 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, - 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x7d, 0x15, 0x6f, 0x47, 0x48, 0xec, 0x7f, 0x54, 0x3a, 0xd0, 0x98, 0x25, 0xdd, 0xd5, - 0xc6, 0x7c, 0x55, 0xd3, 0x23, 0x56, 0x93, 0x10, 0x36, 0x48, 0x97, 0xe3, 0xd3, 0x9e, 0xc1, 0x15, 0xab, 0xd0, 0x72, - 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x16, 0x51, 0xc9, 0x86, 0x61, 0x06, 0x61, - 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0x33, 0x7f, 0x4a, 0x1f, 0x6c, 0xba, 0x76, 0xe6, 0x11, 0x40, - 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x37, 0x2a, 0x33, 0xbf, 0x96, 0xb6, 0x95, 0xdb, 0xf6, 0x18, 0x7b, 0x21, 0xb7, - 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x08, 0x55, 0x6d, 0xc8, 0x5a, 0x1b, 0x3a, 0xd0, 0x2f, - 0xd2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x59, 0x2e, 0xc1, 0x22, 0xbc, 0x74, 0x08, 0x7f, 0x97, 0x83, 0x33, 0x3c, 0x66, - 0x58, 0xac, 0x56, 0x50, 0xcf, 0xe1, 0x7d, 0xb2, 0x19, 0x9c, 0x54, 0x6c, 0x8c, 0x5d, 0x98, 0x89, 0x87, 0x65, 0x13, - 0x02, 0x27, 0xd0, 0xaf, 0xab, 0x88, 0xfa, 0xfb, 0xed, 0xf8, 0xa9, 0x0c, 0x6b, 0x3b, 0x10, 0x6b, 0xd6, 0x1b, 0xac, - 0x3e, 0x80, 0x96, 0xff, 0x93, 0xb8, 0x87, 0xca, 0xbc, 0x9b, 0x84, 0x7c, 0x73, 0x11, 0x7b, 0xac, 0x87, 0x18, 0xa9, - 0x2d, 0xee, 0x0e, 0x21, 0xfe, 0x9f, 0xad, 0x28, 0x06, 0x3c, 0xaa, 0xf8, 0xe7, 0x10, 0xf5, 0x20, 0x14, 0xb5, 0xf1, - 0xb0, 0x01, 0x4a, 0xbb, 0x5c, 0x57, 0x62, 0xa4, 0x4f, 0x20, 0xdf, 0xda, 0xf0, 0x82, 0xfa, 0x24, 0xca, 0x41, 0x4e, - 0xf6, 0xa2, 0x92, 0x26, 0x1b, 0xc2, 0x5c, 0x6f, 0x0b, 0xc7, 0xf4, 0xd5, 0x06, 0x2d, 0xc2, 0x17, 0xc0, 0xce, 0x70, - 0x2d, 0x59, 0x5a, 0xf0, 0xe5, 0x35, 0xf0, 0xb9, 0x35, 0xd7, 0x14, 0x25, 0x47, 0xfd, 0x17, 0x52, 0xdf, 0xfa, 0xc3, - 0xef, 0xd8, 0x13, 0x1f, 0xa9, 0xd5, 0x91, 0x6c, 0x84, 0x5a, 0xb3, 0x76, 0xbc, 0x6c, 0x33, 0xc2, 0xa0, 0x34, 0xd1, - 0xfb, 0x2a, 0x64, 0x95, 0x3b, 0x3b, 0x95, 0xde, 0x9c, 0xbe, 0xe6, 0x95, 0x73, 0x2a, 0x37, 0x8c, 0x6a, 0xa9, 0x69, - 0x80, 0x08, 0x57, 0x2e, 0x91, 0xbc, 0x4f, 0x74, 0xf8, 0x07, 0x8d, 0x71, 0xf5, 0x48, 0xe1, 0xef, 0x77, 0xc5, 0x0e, - 0xd9, 0x8e, 0x0e, 0xb7, 0x11, 0x34, 0xcf, 0x57, 0xf0, 0x80, 0xa3, 0x92, 0x21, 0x44, 0x39, 0xb9, 0xd8, 0xcf, 0x6b, - 0xa6, 0x6c, 0x37, 0x01, 0x42, 0x48, 0x39, 0x9c, 0x75, 0x0e, 0x91, 0xb5, 0xd0, 0x23, 0x55, 0x94, 0xc3, 0x2d, 0x9a, - 0x6b, 0x03, 0x54, 0x68, 0x81, 0x74, 0xf9, 0x85, 0xdd, 0xc7, 0x02, 0xa2, 0x97, 0xaf, 0x6d, 0x08, 0x63, 0x6b, 0x65, - 0x89, 0x0b, 0x3d, 0x6a, 0x13, 0x46, 0xd7, 0x6e, 0x0c, 0x6b, 0x03, 0xa3, 0xa7, 0x41, 0x49, 0x0b, 0x42, 0x5d, 0xf7, - 0xe8, 0x79, 0xa2, 0x03, 0x3d, 0x66, 0x84, 0x36, 0x18, 0x9e, 0x12, 0x05, 0x96, 0x4d, 0x05, 0x58, 0xf0, 0x2d, 0x8b, - 0x38, 0xd7, 0x36, 0x9b, 0x2c, 0xfc, 0xa8, 0x42, 0xfd, 0xb4, 0x5f, 0x56, 0x31, 0xcf, 0x85, 0xa5, 0x6e, 0xcf, 0x13, - 0x17, 0x8f, 0xee, 0xe9, 0x9b, 0xeb, 0x17, 0x2f, 0x5f, 0xbf, 0x5a, 0xad, 0xda, 0xac, 0xd9, 0x3e, 0xc1, 0x3f, 0xa9, - 0x32, 0x1e, 0x6c, 0x19, 0x05, 0xe8, 0xe0, 0x60, 0x9f, 0x6b, 0x17, 0x9e, 0x2f, 0x7c, 0x0e, 0x71, 0x83, 0xd4, 0x10, - 0x27, 0x45, 0x19, 0x13, 0xe4, 0x2e, 0xe8, 0x07, 0xf7, 0x01, 0x28, 0xa1, 0x2a, 0xf2, 0xf7, 0x61, 0x73, 0xf6, 0x7b, - 0x10, 0x98, 0x08, 0xea, 0x43, 0x04, 0x10, 0x88, 0x57, 0x8a, 0x0b, 0xc2, 0x5c, 0x02, 0x44, 0xf1, 0x5e, 0xc0, 0x9b, - 0x90, 0x3a, 0x6a, 0xd5, 0x22, 0x0f, 0x0b, 0x20, 0x89, 0x26, 0x1c, 0x25, 0x3d, 0xd2, 0x01, 0xbc, 0x21, 0x28, 0xa5, - 0xf9, 0xd5, 0xcb, 0xac, 0xbb, 0x54, 0x86, 0xfa, 0xad, 0x38, 0xc3, 0x53, 0xfb, 0x39, 0x85, 0xcf, 0x69, 0xcf, 0x9d, - 0x0e, 0xf2, 0x30, 0xc3, 0x0b, 0x22, 0x0f, 0xdd, 0xb3, 0x88, 0xcb, 0x79, 0xc1, 0xbe, 0x72, 0xb1, 0x90, 0xf1, 0xf2, - 0x2e, 0x16, 0xd1, 0x5d, 0x33, 0x3d, 0x0c, 0x8b, 0xe8, 0xae, 0x99, 0x47, 0x77, 0x08, 0xdf, 0xc7, 0x22, 0xba, 0x37, - 0x29, 0xf7, 0xcd, 0x1c, 0x6e, 0xbe, 0x70, 0x0e, 0x87, 0xa2, 0x29, 0xda, 0x58, 0x6c, 0x16, 0x35, 0x29, 0xb6, 0xa8, - 0x87, 0xc1, 0xbf, 0xef, 0xd8, 0xf8, 0x7e, 0xf8, 0x12, 0x5c, 0x9a, 0x34, 0x91, 0x9f, 0x40, 0xfa, 0x69, 0x55, 0x06, - 0xee, 0x53, 0xd2, 0xea, 0x4d, 0xcf, 0x65, 0xb3, 0xdd, 0x6b, 0x34, 0xa6, 0xb0, 0x77, 0x13, 0x92, 0xb9, 0x62, 0xd3, - 0x86, 0x8e, 0xaf, 0xb3, 0x9f, 0xac, 0x56, 0xfb, 0x19, 0xd2, 0x1b, 0x6e, 0xc2, 0x42, 0x35, 0x98, 0x0e, 0x71, 0x0b, - 0x3f, 0x4f, 0x10, 0x5a, 0xb2, 0xc1, 0x74, 0x48, 0xd8, 0x60, 0xda, 0x68, 0x0f, 0x8d, 0xa1, 0x9d, 0xde, 0x8a, 0x6b, - 0x08, 0xa1, 0x39, 0x1d, 0x1e, 0xe9, 0x92, 0xc2, 0xe6, 0x9b, 0x2f, 0x5a, 0x05, 0xf4, 0xcb, 0x6b, 0xc1, 0xcb, 0x04, - 0xee, 0x40, 0x5f, 0xf4, 0xdc, 0x3c, 0xdd, 0x5a, 0x90, 0xe3, 0xa3, 0xca, 0xd5, 0x9e, 0x22, 0xac, 0x7b, 0xca, 0x0f, - 0x8b, 0x43, 0xdd, 0x8c, 0xed, 0x52, 0xd8, 0x6f, 0x5f, 0x33, 0xf2, 0xd1, 0xc2, 0x02, 0x10, 0xa4, 0x82, 0x47, 0x52, - 0xd8, 0x70, 0x4a, 0x3e, 0x5c, 0x2c, 0x54, 0xb6, 0x60, 0x92, 0x91, 0x56, 0x2f, 0xd3, 0x96, 0xfe, 0x99, 0x8d, 0x68, - 0x4a, 0x31, 0x25, 0x89, 0x2b, 0x99, 0x69, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x10, 0xa7, 0x04, 0xe2, - 0x21, 0xf5, 0x0a, 0x6d, 0xe0, 0x15, 0x4e, 0x9b, 0xc5, 0x80, 0x0d, 0xd1, 0xd1, 0x31, 0xa6, 0x83, 0xcf, 0xc9, 0xbc, - 0x0d, 0x8f, 0x05, 0x7e, 0x1e, 0x92, 0x69, 0x53, 0x94, 0x09, 0x12, 0x12, 0xd2, 0xa6, 0x38, 0x84, 0xbd, 0x84, 0x70, - 0x62, 0x2a, 0x26, 0x03, 0x36, 0x6c, 0x4e, 0xcb, 0x8a, 0x1d, 0x57, 0xb1, 0x21, 0xca, 0x04, 0x53, 0xb1, 0x61, 0x2b, - 0xfa, 0xaf, 0x33, 0x68, 0x10, 0xf8, 0x00, 0x60, 0x00, 0x00, 0x85, 0xbc, 0x68, 0xbe, 0x38, 0x27, 0x6e, 0xb3, 0x9b, - 0x7b, 0xfc, 0x16, 0x58, 0xa0, 0xd5, 0xf6, 0xff, 0x2e, 0x94, 0x01, 0x7b, 0xca, 0x42, 0xc7, 0xcc, 0x2d, 0x8c, 0x8a, - 0x0e, 0xa0, 0x52, 0x22, 0x4c, 0xa1, 0x21, 0xb3, 0x9f, 0x68, 0xa8, 0x79, 0x5a, 0x83, 0x6c, 0xa0, 0x86, 0xcd, 0x04, - 0x8e, 0x18, 0x78, 0x87, 0x86, 0x4c, 0xb5, 0x31, 0x61, 0x98, 0xc1, 0x14, 0x13, 0x0d, 0x9e, 0x69, 0xdc, 0x5a, 0x0b, - 0x2d, 0xcb, 0xf5, 0xb3, 0xfe, 0xdf, 0x2a, 0xcc, 0x07, 0x45, 0xb3, 0x3d, 0x44, 0xfb, 0x84, 0x98, 0x8f, 0x21, 0x6c, - 0x32, 0x9b, 0xda, 0xd0, 0xdf, 0x47, 0x9d, 0xd8, 0x7c, 0xc2, 0x9f, 0xe1, 0x5a, 0xef, 0x00, 0x1d, 0x78, 0x50, 0xaf, - 0xbf, 0xa8, 0xa9, 0xbc, 0x3e, 0xee, 0x8c, 0x52, 0xb9, 0xeb, 0xdd, 0x69, 0x4f, 0x53, 0xec, 0x7b, 0xeb, 0xe1, 0xf2, - 0xa1, 0x1e, 0x02, 0x66, 0x0c, 0xfa, 0x96, 0x19, 0x7d, 0x2f, 0x44, 0x72, 0x41, 0x04, 0x16, 0x1a, 0x6b, 0x18, 0xec, - 0xad, 0x83, 0x03, 0x5d, 0x8d, 0x35, 0xe0, 0x79, 0x52, 0x04, 0x82, 0x81, 0x8b, 0xa0, 0x0c, 0x68, 0x92, 0xeb, 0xdb, - 0x70, 0xf2, 0x91, 0xd9, 0x5f, 0xb8, 0xbc, 0x7d, 0x2c, 0x8c, 0xb6, 0x55, 0x27, 0xdf, 0x97, 0x05, 0xee, 0xcb, 0x7b, - 0x49, 0xa3, 0xe0, 0x46, 0xe6, 0x26, 0x2f, 0xd7, 0x77, 0xeb, 0xae, 0x54, 0x67, 0x77, 0x33, 0x9d, 0xb2, 0x99, 0xce, - 0x76, 0x33, 0xbe, 0x66, 0xe6, 0x5b, 0x56, 0x91, 0xfa, 0x64, 0x8d, 0xe4, 0x9c, 0xe6, 0x3f, 0xd1, 0x39, 0x18, 0x05, - 0x73, 0x73, 0xaf, 0x0a, 0x27, 0x57, 0x46, 0x2e, 0xf6, 0x33, 0x4d, 0x5c, 0x91, 0xbe, 0x50, 0x87, 0x00, 0x2f, 0x2f, - 0xca, 0xc7, 0x07, 0xb8, 0xc8, 0x7f, 0x15, 0xa9, 0x8d, 0x72, 0x9a, 0x0b, 0x25, 0x72, 0x16, 0x20, 0x8d, 0xaa, 0x36, - 0x06, 0xf6, 0xd2, 0xec, 0x3d, 0xd9, 0xe7, 0x83, 0x2a, 0x62, 0xde, 0x50, 0x3f, 0xf7, 0xf1, 0x3d, 0x4d, 0xb1, 0x55, - 0x13, 0x27, 0xe4, 0x43, 0x12, 0x66, 0x20, 0x9b, 0x0d, 0xaa, 0xd7, 0x7e, 0x1b, 0x6d, 0x5c, 0x34, 0x43, 0xd9, 0xd7, - 0x4f, 0x9c, 0xfc, 0x50, 0x68, 0xe3, 0x00, 0xe3, 0xe8, 0x8f, 0x30, 0x35, 0x60, 0x4f, 0x22, 0x47, 0xa1, 0xa3, 0x3b, - 0x93, 0x76, 0xef, 0xa7, 0xdd, 0xeb, 0xb4, 0x0e, 0x94, 0x03, 0xd2, 0x6c, 0xcb, 0x74, 0xee, 0xdd, 0xf7, 0x3d, 0xbc, - 0x74, 0xbb, 0x86, 0x48, 0xdc, 0xf3, 0xc7, 0xda, 0x18, 0xe2, 0x0d, 0xd8, 0x88, 0xca, 0x83, 0x83, 0x3f, 0xac, 0xf7, - 0x6d, 0x25, 0xcb, 0xca, 0x6f, 0x84, 0x03, 0xdb, 0x60, 0x2a, 0x6d, 0x5e, 0x2a, 0x92, 0x05, 0xd8, 0x75, 0xee, 0xef, - 0x8e, 0x87, 0xff, 0x52, 0xfa, 0x4c, 0x8b, 0x71, 0x15, 0x7f, 0x25, 0xd2, 0xd2, 0x43, 0x54, 0x41, 0x04, 0xd2, 0xca, - 0xba, 0xd4, 0x37, 0x1d, 0xbd, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x0d, 0xcd, 0x8b, 0xdc, 0x2a, 0x82, 0x47, - 0x0b, 0x6b, 0x0c, 0xcd, 0x7d, 0xe9, 0x9d, 0x64, 0x02, 0xa2, 0xd6, 0xc7, 0xed, 0x4b, 0x22, 0xa1, 0xac, 0xee, 0x42, - 0x38, 0xdc, 0x85, 0x60, 0x5e, 0x06, 0x6d, 0x83, 0xd8, 0xed, 0x36, 0x68, 0x5b, 0x28, 0x89, 0x34, 0x81, 0xdb, 0xbd, - 0xc1, 0xc2, 0xde, 0x87, 0x97, 0x63, 0x39, 0x96, 0xee, 0x9a, 0xcc, 0x3c, 0x00, 0x04, 0x6a, 0x1f, 0x56, 0x3c, 0xb1, - 0x20, 0x88, 0xac, 0xe1, 0xe8, 0x7b, 0xce, 0x6e, 0x8d, 0xe5, 0xf0, 0x6c, 0xbe, 0x50, 0x2c, 0xd5, 0x77, 0xd4, 0x80, - 0x3f, 0x75, 0x3f, 0xaf, 0x9f, 0x92, 0x9a, 0x6e, 0xfc, 0x01, 0x84, 0x91, 0xb0, 0xca, 0x0e, 0xad, 0x90, 0x30, 0xc1, - 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0xa5, 0xc3, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x00, 0x9b, 0x78, 0x63, - 0x5e, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x07, 0xcd, 0xa0, 0xc1, 0x62, 0x1b, 0x94, - 0xd9, 0x45, 0x18, 0xcf, 0xcf, 0x4f, 0x74, 0x9c, 0xf6, 0x52, 0xaf, 0xfe, 0x5b, 0x02, 0x06, 0xf8, 0x12, 0xbc, 0xc4, - 0xfc, 0xe8, 0xae, 0x03, 0xd5, 0x80, 0xfa, 0xa2, 0xc1, 0x86, 0x68, 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xd9, 0x6b, 0x2e, - 0x69, 0xae, 0xb9, 0xa4, 0xbd, 0xe6, 0x92, 0xee, 0x9a, 0x4b, 0xea, 0x6b, 0x2e, 0xe9, 0xae, 0xb9, 0x1c, 0x08, 0x3f, - 0x79, 0x71, 0x1c, 0x43, 0x0e, 0x71, 0x15, 0x95, 0x89, 0x8c, 0x07, 0x17, 0x9e, 0xfb, 0x2c, 0x92, 0xe5, 0xf2, 0xfb, - 0x31, 0xe4, 0xb6, 0x6c, 0x25, 0xb4, 0xdb, 0x14, 0x93, 0x10, 0x39, 0xfd, 0xe0, 0xa0, 0x74, 0x77, 0x06, 0x1f, 0xf5, - 0x98, 0xe3, 0xa5, 0x71, 0xa2, 0xfd, 0x03, 0x74, 0xf2, 0xfa, 0xd7, 0xc7, 0x58, 0xac, 0x89, 0xb4, 0x26, 0xf7, 0xfb, - 0x6d, 0x47, 0x29, 0x3e, 0x25, 0x3a, 0x3c, 0x39, 0x8f, 0x94, 0x16, 0x41, 0x10, 0xa2, 0x24, 0xc7, 0x09, 0x11, 0x66, - 0xbf, 0x3b, 0x57, 0x78, 0xad, 0x8a, 0x72, 0x66, 0x25, 0x57, 0x19, 0x38, 0xb1, 0x6b, 0x2b, 0x0c, 0xd4, 0x03, 0x17, - 0x82, 0x44, 0x27, 0xfc, 0xd1, 0xcc, 0x0c, 0x39, 0x4b, 0xca, 0xa4, 0x8f, 0xcd, 0x4c, 0x13, 0xb0, 0x82, 0xec, 0x3b, - 0x98, 0x2d, 0xef, 0x62, 0x8a, 0xef, 0xe3, 0x04, 0xff, 0xbf, 0xec, 0xbd, 0xeb, 0x92, 0xdb, 0x46, 0x96, 0x2e, 0xfa, - 0x2a, 0x55, 0x0c, 0x99, 0x06, 0xc4, 0x24, 0x8b, 0xa5, 0xbd, 0x67, 0x22, 0x0e, 0x58, 0x29, 0x86, 0x2c, 0x59, 0xdd, - 0x72, 0x5b, 0x97, 0x56, 0xa9, 0xdd, 0x76, 0x33, 0x78, 0x68, 0x14, 0x90, 0x24, 0x20, 0x83, 0x00, 0x0d, 0x80, 0x55, - 0xa4, 0x48, 0xbc, 0xfb, 0x8e, 0xb5, 0x56, 0x5e, 0x41, 0xb0, 0xa4, 0x9e, 0xd9, 0xf3, 0xeb, 0x9c, 0x3f, 0x52, 0x31, - 0x91, 0x48, 0xe4, 0x3d, 0x57, 0xae, 0xcb, 0xf7, 0xdd, 0x15, 0xbb, 0xa0, 0xb4, 0x7d, 0x41, 0x94, 0xe1, 0x6f, 0xe9, - 0xf5, 0xf2, 0x10, 0xe2, 0x7d, 0x7a, 0x69, 0x7e, 0x91, 0xb6, 0xa2, 0x00, 0x0f, 0x11, 0x7a, 0x54, 0x07, 0x82, 0x9d, - 0xf1, 0x84, 0x07, 0x70, 0xb2, 0x9a, 0xe5, 0xfc, 0x49, 0x0a, 0xe2, 0x44, 0xc1, 0x21, 0xe0, 0x6a, 0x77, 0x9b, 0x7e, - 0x01, 0xc3, 0x97, 0x0e, 0xb6, 0x1c, 0xde, 0x15, 0xbb, 0x1e, 0x2b, 0xf9, 0x07, 0x60, 0xdf, 0xea, 0xc9, 0x58, 0xdd, - 0x1e, 0x38, 0xeb, 0x52, 0x8a, 0x8e, 0x37, 0xc5, 0xe1, 0xed, 0xf9, 0xec, 0xb0, 0x0b, 0x22, 0xb6, 0x0f, 0x32, 0xac, - 0x75, 0xd2, 0xf0, 0x9f, 0x68, 0xeb, 0x60, 0x31, 0xc2, 0xfe, 0x2f, 0xeb, 0x81, 0x97, 0x90, 0x1a, 0x0a, 0x5c, 0x0c, - 0xb6, 0x1c, 0xad, 0xed, 0x32, 0x0d, 0xdc, 0xd4, 0xa0, 0xd7, 0x0f, 0x14, 0xa2, 0xbc, 0x64, 0x34, 0x37, 0x82, 0x4d, - 0x63, 0xc8, 0xc5, 0xe1, 0xb8, 0x59, 0x0e, 0x79, 0x49, 0xd3, 0x69, 0x10, 0x4a, 0x77, 0x96, 0x0d, 0x24, 0x51, 0xf6, - 0x41, 0xa8, 0x5d, 0x5b, 0x0e, 0xbb, 0xc0, 0xf6, 0xe5, 0x8f, 0x86, 0xb1, 0x7f, 0xb5, 0x7c, 0x2a, 0xa4, 0x8b, 0x78, - 0x05, 0x82, 0xa8, 0xfd, 0x3c, 0x1b, 0x6e, 0xfd, 0xab, 0xcd, 0x53, 0xa1, 0xfc, 0xc6, 0x2b, 0x5b, 0x0e, 0xa9, 0xb3, - 0x16, 0xbe, 0x30, 0x1e, 0x1e, 0x5c, 0x19, 0xda, 0x8e, 0x47, 0xa1, 0xff, 0x36, 0x6b, 0x04, 0x37, 0x36, 0xb4, 0xcf, - 0x17, 0x3e, 0x6c, 0x6d, 0x34, 0xd6, 0x14, 0xd3, 0x2d, 0xf4, 0x6f, 0x32, 0x5b, 0xda, 0xd3, 0xa8, 0xe4, 0xc5, 0xb9, - 0x69, 0xc4, 0x42, 0x18, 0x30, 0xf4, 0x93, 0xf9, 0x00, 0xaa, 0xb9, 0xd3, 0x11, 0xc8, 0xe4, 0x03, 0x3d, 0x58, 0x93, - 0x5a, 0xf5, 0xd7, 0x30, 0x93, 0xff, 0x47, 0x2a, 0x2c, 0x46, 0x77, 0xdb, 0x30, 0x53, 0x7f, 0x44, 0xf2, 0x0f, 0x56, - 0xf1, 0x7d, 0xea, 0x85, 0xda, 0x8f, 0x85, 0x15, 0x18, 0x94, 0xa8, 0x1a, 0xd0, 0x03, 0x11, 0x54, 0x65, 0x90, 0x66, - 0x58, 0x9d, 0x83, 0x7e, 0xf7, 0xb4, 0xea, 0x48, 0x0e, 0x69, 0xad, 0x86, 0x54, 0x30, 0x55, 0x6a, 0x50, 0x1d, 0x8f, - 0xab, 0x94, 0xe9, 0x32, 0xe0, 0x92, 0xbe, 0x4a, 0x95, 0x52, 0xf8, 0x4f, 0x04, 0xa0, 0x73, 0x70, 0x8f, 0xaf, 0xc7, - 0x40, 0x9a, 0x61, 0xe1, 0xb7, 0x66, 0xa7, 0xd7, 0x24, 0xdc, 0x26, 0xc1, 0xc5, 0x00, 0xe7, 0xe8, 0x3a, 0x2c, 0x57, - 0x29, 0x44, 0x50, 0x95, 0x50, 0xdf, 0xdc, 0x34, 0x28, 0x6d, 0x35, 0x08, 0x6b, 0x12, 0xea, 0x4c, 0xb2, 0x51, 0x69, - 0xbb, 0x51, 0x98, 0x2d, 0xe2, 0x7a, 0x46, 0x58, 0x73, 0x36, 0x53, 0x0d, 0x4c, 0x1a, 0x8e, 0x9b, 0x46, 0x6b, 0x51, - 0xa1, 0xa6, 0x30, 0xaf, 0x71, 0x55, 0xa9, 0xea, 0x6e, 0xcf, 0x2d, 0xa5, 0x65, 0x7b, 0xd5, 0x4d, 0xb2, 0x21, 0x97, - 0xa1, 0x0c, 0x83, 0xad, 0x1c, 0xc1, 0x04, 0x92, 0xe4, 0xcc, 0xdf, 0xca, 0x3f, 0xd4, 0xa6, 0x6b, 0x01, 0x73, 0x8c, - 0x59, 0x36, 0x2c, 0xe8, 0x15, 0xb8, 0x07, 0x5a, 0xe9, 0xd5, 0x34, 0xbb, 0xaa, 0x82, 0x64, 0x58, 0xe8, 0x65, 0x93, - 0xf1, 0x3f, 0x85, 0x91, 0x26, 0x33, 0x56, 0xb2, 0xc8, 0x76, 0x75, 0x4a, 0x9c, 0xc7, 0x09, 0x6c, 0x8f, 0xa6, 0xb7, - 0x7c, 0x9f, 0x41, 0x54, 0x10, 0x28, 0x98, 0x31, 0x5f, 0x76, 0xf5, 0xcc, 0xf7, 0x99, 0x65, 0xea, 0x3e, 0x1e, 0x8d, - 0x19, 0xdb, 0xef, 0xf7, 0xab, 0x7e, 0x5f, 0xcd, 0xb7, 0x7e, 0x3f, 0x79, 0x6e, 0xfe, 0xf6, 0x80, 0x41, 0x41, 0x4e, - 0x44, 0x53, 0x21, 0x82, 0x7f, 0x48, 0x9e, 0x22, 0x19, 0xdd, 0x69, 0x9f, 0x5b, 0xce, 0x96, 0xf9, 0x09, 0x08, 0xe6, - 0xf1, 0x78, 0xad, 0xc0, 0xae, 0x25, 0x8a, 0x84, 0x2c, 0xff, 0x29, 0x18, 0xcf, 0xdc, 0x07, 0x58, 0x32, 0x00, 0x61, - 0xab, 0x3c, 0x5d, 0xef, 0xf9, 0x2a, 0x78, 0xa7, 0xe3, 0x5d, 0x63, 0x45, 0x06, 0xe2, 0x16, 0xd8, 0x88, 0xb5, 0xf6, - 0x80, 0x9c, 0x29, 0xc0, 0xf1, 0xe2, 0x78, 0xbc, 0x94, 0xbf, 0x74, 0xb3, 0x75, 0x02, 0x95, 0x02, 0xb7, 0x47, 0x27, - 0x07, 0xff, 0x1d, 0x68, 0x06, 0xe5, 0x30, 0x6f, 0x76, 0xbf, 0x33, 0x27, 0x3f, 0x3d, 0xc5, 0x3f, 0xe1, 0x21, 0x3a, - 0xfd, 0x76, 0x6f, 0xfe, 0xa0, 0xa8, 0x3c, 0x1e, 0xd5, 0xe2, 0x07, 0x9e, 0x1f, 0xf8, 0x85, 0x6f, 0x02, 0xb3, 0xc9, - 0xd4, 0x3b, 0xfb, 0x26, 0xaf, 0x98, 0x7a, 0x8d, 0xe7, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xdd, 0xc8, 0x89, - 0x76, 0xaa, 0x30, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, 0x96, 0x78, - 0x96, 0x2e, 0xaf, 0x27, 0x75, 0xb9, 0xd7, 0x8a, 0xa7, 0x03, 0xb0, 0xb8, 0x6d, 0xc0, 0x0b, 0xe0, 0xde, 0x62, 0xeb, - 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, 0x42, 0x30, - 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, 0x77, 0xf9, - 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0xe5, 0x60, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, 0x52, 0x3c, - 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfd, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xb3, 0x7b, 0x72, 0x65, - 0x20, 0x81, 0xa6, 0x03, 0xe0, 0x21, 0x54, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, 0x05, 0xf7, - 0xe9, 0xa7, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa7, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x2a, 0xfb, 0xa6, - 0x02, 0x2a, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, 0x53, 0x71, - 0x73, 0xad, 0xd3, 0xc5, 0xf3, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, 0x07, 0xf1, - 0xb6, 0xb6, 0xa7, 0x3f, 0xf6, 0x10, 0xe9, 0x78, 0x20, 0x17, 0xea, 0x6b, 0x48, 0x25, 0x17, 0xea, 0x06, 0x62, 0x17, - 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0xdb, 0x1a, 0x05, 0x2b, 0x01, 0x67, 0xda, 0x5b, 0x30, 0xd8, 0xc0, 0xba, 0x65, - 0x19, 0xfc, 0x0d, 0xd7, 0x34, 0x81, 0x1b, 0x16, 0x59, 0xef, 0x0d, 0xb6, 0xd2, 0x5b, 0x70, 0xb4, 0x4c, 0x9c, 0x4b, - 0x49, 0x56, 0xb6, 0xc8, 0xb8, 0x7a, 0x14, 0x52, 0x35, 0x3d, 0xdc, 0x89, 0xfa, 0x41, 0x88, 0x3c, 0x58, 0xa7, 0x2c, - 0x2a, 0xd6, 0x20, 0xb3, 0x07, 0x7f, 0x0f, 0x19, 0x39, 0xca, 0x81, 0xa3, 0xd0, 0x5f, 0x9a, 0x40, 0xe7, 0xf9, 0x29, - 0xd4, 0x79, 0x24, 0xd8, 0x4a, 0x3d, 0x14, 0x56, 0x5e, 0x40, 0x74, 0xb0, 0x85, 0xb1, 0xdc, 0x93, 0x50, 0xb1, 0x29, - 0x13, 0x79, 0x1c, 0xd4, 0x12, 0x30, 0x56, 0x10, 0xcc, 0x59, 0x25, 0x5d, 0x90, 0xf2, 0x46, 0x0f, 0x8b, 0xcc, 0xfd, - 0x9d, 0xa0, 0xfc, 0xdf, 0xa9, 0x9c, 0x70, 0x7d, 0x19, 0x02, 0x1c, 0xed, 0x77, 0x20, 0x4a, 0x8c, 0xf5, 0x8b, 0x16, - 0xef, 0x64, 0xe6, 0x6c, 0x6a, 0x07, 0x09, 0x32, 0xb6, 0xc7, 0xaf, 0x10, 0x5a, 0x2d, 0x14, 0x59, 0x34, 0x5c, 0x30, - 0xdd, 0x9e, 0xd2, 0xaa, 0x7b, 0xd8, 0xf0, 0xac, 0xf4, 0x50, 0xa9, 0x6f, 0x63, 0x02, 0xcb, 0x2a, 0x65, 0xf8, 0x76, - 0x42, 0xd5, 0x89, 0x41, 0xc5, 0xba, 0x65, 0x4b, 0x38, 0xc4, 0x62, 0xd2, 0x58, 0x67, 0x03, 0x1e, 0xb1, 0x04, 0xfe, - 0xd9, 0xf2, 0x31, 0x5b, 0xf2, 0x68, 0xb2, 0xbd, 0x59, 0xf6, 0xfb, 0xa5, 0x17, 0x7a, 0xf5, 0x2c, 0xfb, 0x2e, 0x9a, - 0xcf, 0xaa, 0xb9, 0x8f, 0x8a, 0x8b, 0xc9, 0x60, 0xb0, 0xf5, 0xb3, 0xe1, 0x90, 0x25, 0xc3, 0xe1, 0x24, 0xfb, 0x0e, - 0x5e, 0xfb, 0x8e, 0x47, 0x6a, 0x49, 0x25, 0x37, 0x19, 0xec, 0xef, 0x03, 0x1e, 0xf9, 0xac, 0xf3, 0xd3, 0xb2, 0xe9, - 0xd2, 0xfd, 0xcc, 0x8e, 0xbb, 0xd0, 0x1d, 0x60, 0xe3, 0x6d, 0x83, 0x8e, 0xfc, 0xeb, 0x1d, 0x52, 0xea, 0x26, 0x03, - 0xb0, 0x1b, 0x0d, 0x70, 0xc8, 0x54, 0x2f, 0x45, 0x56, 0x2f, 0x65, 0xaa, 0x97, 0x64, 0xe5, 0x12, 0x2c, 0x24, 0xa6, - 0xca, 0x6d, 0x65, 0xe5, 0x96, 0x0d, 0xd7, 0xc3, 0xc1, 0x36, 0x8a, 0xcb, 0x66, 0x05, 0xf7, 0x85, 0x35, 0x05, 0xfe, - 0xdf, 0xb1, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x5b, 0x74, 0x4c, 0x82, 0x0b, 0xc4, 0x3d, 0xbb, 0x03, 0x3b, 0x2c, 0xfc, - 0x05, 0xd7, 0xc9, 0x31, 0xdb, 0xe3, 0xa3, 0xd0, 0x2b, 0xd8, 0x9d, 0x4f, 0x40, 0xbb, 0x60, 0x6b, 0x80, 0x6c, 0x6c, - 0x87, 0x8f, 0x56, 0xc7, 0xe3, 0x5b, 0xcf, 0x67, 0x0f, 0xf8, 0xe3, 0x72, 0x75, 0x3c, 0xee, 0x3d, 0xa3, 0xde, 0xbb, - 0xe5, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xed, 0x0d, 0x8f, 0x27, 0x83, 0xc1, 0xad, 0xbf, 0xe0, 0xf5, 0xec, 0x16, 0xb4, - 0x03, 0x97, 0x0b, 0xa9, 0x6b, 0xf6, 0xee, 0x78, 0xe6, 0x2d, 0x70, 0x6c, 0xee, 0xe0, 0xe8, 0xed, 0xf7, 0xbd, 0x15, - 0x8f, 0xbc, 0x3b, 0x52, 0x31, 0xad, 0xb9, 0xe2, 0x78, 0xdb, 0xe1, 0x7e, 0xba, 0xe6, 0x21, 0x3c, 0xc2, 0xaa, 0x4c, - 0x6f, 0x83, 0xf7, 0x3e, 0x5b, 0x6b, 0x16, 0xb8, 0x07, 0xcc, 0xb1, 0x21, 0x3b, 0xa1, 0x99, 0xf8, 0x6b, 0xec, 0x9f, - 0x5b, 0xd5, 0x3f, 0x34, 0xff, 0x4b, 0xdd, 0x4f, 0xe0, 0xf6, 0x45, 0x16, 0x24, 0xf6, 0x9e, 0xdf, 0xb2, 0x7b, 0x6e, - 0xd8, 0x66, 0x2f, 0x4c, 0xd9, 0x67, 0x4a, 0x8d, 0x1f, 0x29, 0x75, 0x63, 0x19, 0x56, 0x32, 0x77, 0x5f, 0x46, 0xe0, - 0x70, 0x40, 0x7e, 0x5a, 0x21, 0x0e, 0x42, 0xeb, 0x26, 0xab, 0xb9, 0xa2, 0x9c, 0x0b, 0x6d, 0x99, 0x79, 0x15, 0xb0, - 0x98, 0xa5, 0x14, 0x1a, 0x0b, 0x00, 0x04, 0x93, 0x42, 0x6b, 0xef, 0x65, 0x00, 0x39, 0x41, 0xc3, 0x9f, 0x9a, 0xab, - 0xa2, 0xac, 0x65, 0x4b, 0x42, 0x94, 0xed, 0x7a, 0x78, 0x8d, 0x90, 0x69, 0xfd, 0xfe, 0x25, 0x91, 0xac, 0x4d, 0xf2, - 0x9b, 0x1a, 0x2d, 0x01, 0x39, 0x59, 0x02, 0x26, 0x7e, 0xae, 0xf9, 0x04, 0xe0, 0x49, 0xc7, 0x83, 0xfc, 0x3b, 0x5e, - 0x33, 0x41, 0x64, 0x1b, 0xb9, 0x3f, 0x29, 0x9e, 0x23, 0x19, 0x41, 0xf1, 0x5d, 0xad, 0x32, 0x16, 0x86, 0x79, 0xa0, - 0x80, 0xbc, 0x07, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, 0xe8, - 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x3d, 0x89, 0x6e, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, 0x67, - 0xd1, 0x77, 0xf9, 0x7c, 0x42, 0x4a, 0xb2, 0xe3, 0x31, 0x1b, 0x55, 0x75, 0xb1, 0x99, 0x86, 0xf2, 0xa7, 0x87, 0xe0, - 0xeb, 0x05, 0xf5, 0x9a, 0xac, 0x52, 0xfd, 0x1d, 0x55, 0xca, 0x8b, 0x86, 0xd7, 0xfe, 0x77, 0xb9, 0xdc, 0xf7, 0x80, - 0xb4, 0x96, 0x97, 0x5c, 0xbe, 0x1f, 0x21, 0xc6, 0x88, 0x1f, 0x78, 0x25, 0x8f, 0x58, 0xa8, 0xa6, 0x70, 0xcd, 0x23, - 0x04, 0x79, 0xcb, 0x74, 0xf0, 0xb7, 0x9e, 0x38, 0xdd, 0x9f, 0x28, 0xed, 0xe2, 0x0b, 0x8b, 0xba, 0x27, 0x6b, 0xeb, - 0x06, 0xe4, 0x60, 0xc3, 0x74, 0x51, 0x90, 0x6d, 0x4a, 0x23, 0x68, 0xa3, 0xe5, 0xc0, 0x86, 0x93, 0xab, 0x0d, 0x67, - 0xae, 0x21, 0xb8, 0x2f, 0x2f, 0xd3, 0xd1, 0x02, 0x3e, 0xa4, 0xba, 0xbd, 0xc4, 0xcf, 0x87, 0x0d, 0x8f, 0x80, 0xcc, - 0x8e, 0xf8, 0xcc, 0x26, 0x92, 0x4e, 0xea, 0x52, 0x01, 0xbb, 0x5d, 0xbc, 0x05, 0x39, 0x62, 0xe6, 0xbe, 0x42, 0xf5, - 0x2d, 0x1a, 0x70, 0x65, 0xac, 0x7d, 0x4d, 0x32, 0x16, 0xde, 0x94, 0xd3, 0x70, 0x90, 0xc3, 0x73, 0xfa, 0xda, 0x72, - 0x9b, 0x65, 0x3f, 0x17, 0x10, 0x04, 0x51, 0x12, 0x8f, 0x0f, 0x78, 0x5f, 0xe6, 0x43, 0x8d, 0x92, 0x8f, 0x65, 0x23, - 0x95, 0x5e, 0x89, 0xfe, 0x6e, 0xcc, 0x25, 0x06, 0x7c, 0x9b, 0xb7, 0x05, 0x85, 0xcb, 0xea, 0x78, 0xbc, 0xac, 0x46, - 0xc6, 0xb3, 0x0c, 0x54, 0x2b, 0xd3, 0x3a, 0x88, 0xcd, 0x7c, 0xb1, 0xf0, 0x17, 0x3b, 0x27, 0x11, 0x51, 0x10, 0xd8, - 0x91, 0xf0, 0x20, 0x52, 0xbf, 0xcc, 0x3d, 0xdd, 0xa9, 0x3e, 0x3b, 0x2c, 0x6c, 0x22, 0xbd, 0xa0, 0x64, 0xf2, 0x49, - 0x70, 0x50, 0xfd, 0x1d, 0x84, 0x0d, 0xe1, 0xcd, 0xab, 0x5e, 0x67, 0x99, 0x9a, 0x95, 0x20, 0x61, 0xc6, 0x1c, 0xc1, - 0xe3, 0xb0, 0xd3, 0xd8, 0x96, 0xc7, 0x16, 0x1c, 0x9d, 0xb7, 0x61, 0x2b, 0xb6, 0x66, 0x77, 0xaa, 0x4e, 0x0b, 0x1e, - 0x4e, 0x87, 0xd7, 0x01, 0xae, 0xbe, 0xcd, 0x25, 0xe7, 0x2b, 0x3a, 0xc1, 0x36, 0x03, 0x1e, 0x4d, 0xc4, 0x6c, 0xf3, - 0x5d, 0xa4, 0x16, 0xcf, 0x66, 0xc8, 0x17, 0xb4, 0xfe, 0xc4, 0x6c, 0x65, 0x92, 0x57, 0x03, 0xbe, 0x98, 0x6c, 0xbe, - 0x8b, 0xe0, 0xd5, 0xef, 0xc0, 0x8a, 0x91, 0x39, 0xb3, 0x6c, 0xf3, 0x5d, 0x84, 0x63, 0xb6, 0xfa, 0x2e, 0xa2, 0x51, - 0x5b, 0xcb, 0x7d, 0xe9, 0xae, 0x01, 0x61, 0xe5, 0x8e, 0xc5, 0xf0, 0x1a, 0x88, 0x67, 0xda, 0x48, 0xba, 0x91, 0x86, - 0xde, 0x98, 0x87, 0xd3, 0x38, 0xd8, 0x50, 0x2b, 0xe4, 0x99, 0x21, 0x66, 0xf1, 0x77, 0xd1, 0x9c, 0xad, 0xb1, 0x22, - 0x5b, 0x1e, 0x0f, 0xae, 0x27, 0xdb, 0x1b, 0xbe, 0x01, 0xf2, 0xb3, 0xc9, 0xd6, 0x6c, 0x51, 0x77, 0x5c, 0xcc, 0xb6, - 0xdf, 0x45, 0xf3, 0xc9, 0x1a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x35, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, 0x3d, - 0xb6, 0x19, 0x07, 0x2b, 0xb6, 0xb9, 0x0e, 0xee, 0xd8, 0x66, 0x0c, 0x44, 0x1c, 0xd4, 0xef, 0xde, 0x16, 0x16, 0x5f, - 0xc4, 0x36, 0xd7, 0x26, 0x6d, 0xfb, 0x5d, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xcd, 0xbc, 0x35, 0x83, 0x4b, - 0xc8, 0xd2, 0x8b, 0xd9, 0x76, 0x78, 0xcd, 0x36, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0x56, 0xfc, 0x8e, 0x25, 0x7c, 0xdd, - 0xc4, 0x37, 0x5b, 0xd0, 0x88, 0x9e, 0x64, 0xd0, 0x57, 0x50, 0x33, 0x73, 0x5e, 0x5a, 0x50, 0xb9, 0x87, 0x16, 0x1c, - 0x50, 0x90, 0xb6, 0x01, 0x82, 0x24, 0x9e, 0xdd, 0xcb, 0x70, 0x73, 0x2b, 0x85, 0x01, 0x37, 0x81, 0x19, 0x30, 0x30, - 0xfd, 0x0c, 0x7e, 0x58, 0xe9, 0x12, 0x21, 0xce, 0x7e, 0x4a, 0x49, 0x32, 0xcf, 0x4f, 0x45, 0x9a, 0xbb, 0x85, 0xeb, - 0x14, 0x66, 0x45, 0x81, 0xea, 0xa7, 0xa4, 0x34, 0xb0, 0x50, 0x89, 0x4c, 0xa5, 0xe0, 0x97, 0xcd, 0x79, 0x94, 0x9d, - 0xa2, 0x73, 0x5d, 0x5e, 0x4f, 0x9c, 0xd3, 0x49, 0xdf, 0x7f, 0xe0, 0x18, 0xb6, 0x90, 0x81, 0x0b, 0x7f, 0xea, 0x09, - 0xe3, 0xd4, 0x0a, 0xc4, 0x54, 0xf2, 0xec, 0x29, 0x7c, 0x26, 0xb4, 0x3a, 0xba, 0xf0, 0xfd, 0xa0, 0xd0, 0x26, 0xe9, - 0x16, 0x24, 0x29, 0x78, 0x8a, 0x5e, 0x72, 0xde, 0x06, 0x2a, 0xc5, 0x88, 0x16, 0x44, 0xda, 0x5a, 0x66, 0x0e, 0xd2, - 0x96, 0xe6, 0xbb, 0x26, 0x7e, 0x0e, 0x0b, 0xb8, 0x88, 0x16, 0x76, 0xa5, 0xe0, 0x51, 0x15, 0x2b, 0xf7, 0x36, 0xcf, - 0x11, 0xce, 0xe8, 0x5a, 0x26, 0x00, 0xae, 0xf7, 0xab, 0xb0, 0x56, 0x78, 0x45, 0xcd, 0x22, 0x2f, 0x6a, 0xfa, 0x64, - 0x0b, 0xdc, 0xc7, 0xa2, 0x44, 0x81, 0xb3, 0x16, 0x0c, 0xd8, 0x0a, 0x4b, 0x76, 0x52, 0xd8, 0x14, 0x2d, 0xa1, 0x77, - 0xc0, 0x4f, 0x07, 0x35, 0x93, 0x01, 0x34, 0x01, 0x34, 0x1e, 0xff, 0x02, 0x50, 0xd3, 0xdb, 0x5a, 0x6c, 0xaa, 0xa0, - 0x54, 0xca, 0x4d, 0xf8, 0x19, 0x18, 0x66, 0xf8, 0xa1, 0x90, 0xdb, 0x44, 0x89, 0x9c, 0x1f, 0x8b, 0x52, 0x2c, 0x4b, - 0x51, 0x25, 0xed, 0x86, 0x82, 0x47, 0x84, 0xdb, 0xa0, 0x31, 0x73, 0x7b, 0xa2, 0x8b, 0x56, 0x84, 0x72, 0x6c, 0x37, - 0x31, 0xd2, 0x28, 0xb3, 0xb3, 0x5d, 0x27, 0x0b, 0xed, 0xf7, 0x55, 0x0e, 0x59, 0x07, 0xac, 0x91, 0x7c, 0xbd, 0xe6, - 0xd0, 0x6d, 0xa3, 0xbc, 0x78, 0xf0, 0x7c, 0x05, 0xa7, 0x39, 0x9e, 0xd8, 0x5d, 0xaf, 0x3b, 0x45, 0x22, 0x5e, 0xe1, - 0xa4, 0xaa, 0x46, 0xb2, 0x70, 0xdc, 0xb9, 0xd3, 0x5a, 0xac, 0x95, 0x4c, 0xe3, 0x72, 0xd0, 0x00, 0xd0, 0x0c, 0x3e, - 0x95, 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, - 0x11, 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0xf3, 0x4a, - 0x0f, 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, - 0x3c, 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, - 0x5d, 0x28, 0xe7, 0x4c, 0xce, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, - 0x8c, 0x4e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x56, 0xa9, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, - 0xc6, 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, - 0x94, 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x07, 0x59, 0x14, 0x38, 0x80, - 0xab, 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0x0e, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, - 0xcc, 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, - 0xb4, 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x4f, 0x5f, - 0xa7, 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7d, 0x41, 0x11, 0x17, 0x35, 0xb8, - 0xf2, 0xce, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, - 0x0e, 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x46, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xac, 0x58, 0x3e, 0x5a, 0xa8, 0xcc, - 0x08, 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xd3, 0x3d, 0xba, 0xab, 0xce, - 0x32, 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, - 0x77, 0x9d, 0xe5, 0x5b, 0xa9, 0x66, 0x6b, 0x28, 0x2a, 0xb5, 0x92, 0x14, 0x07, 0x19, 0xae, 0xdb, 0xdc, 0x87, 0xcd, - 0x14, 0xf4, 0x8c, 0x91, 0xc8, 0x3c, 0x7f, 0x22, 0x5f, 0x82, 0x73, 0xc6, 0x59, 0x21, 0x30, 0x61, 0xac, 0xde, 0xb5, - 0x96, 0x4a, 0x43, 0x8a, 0xb1, 0x93, 0x51, 0x96, 0x55, 0x96, 0x2e, 0xb3, 0xb5, 0x84, 0x2d, 0xab, 0xc8, 0x2d, 0x6c, - 0x99, 0xc9, 0x6a, 0xbe, 0xcf, 0xb9, 0x83, 0xf2, 0xcd, 0x36, 0x19, 0x3f, 0x48, 0x64, 0xef, 0x36, 0x50, 0xc2, 0xf3, - 0xd1, 0x7f, 0x20, 0xfd, 0x36, 0xc3, 0x38, 0xe5, 0xb6, 0x92, 0x16, 0xe0, 0xf4, 0x8f, 0xc7, 0xf7, 0x39, 0x06, 0x0d, - 0x8e, 0x30, 0x8e, 0xac, 0xdf, 0xbf, 0xcb, 0xbd, 0x1a, 0x13, 0x75, 0xf4, 0x42, 0xbf, 0x9f, 0xd3, 0xc3, 0x69, 0x3e, - 0x5a, 0xa7, 0x3b, 0x64, 0x27, 0xb4, 0xb1, 0xf2, 0x83, 0x5a, 0x01, 0xb3, 0xb7, 0x3e, 0x9f, 0x0e, 0x40, 0xc7, 0x02, - 0x24, 0x9a, 0xcd, 0x44, 0x62, 0x4e, 0xba, 0x27, 0xe1, 0xe9, 0x81, 0x05, 0x0e, 0x30, 0x39, 0xff, 0x87, 0xf0, 0x66, - 0x60, 0x83, 0x46, 0x89, 0xbe, 0x46, 0x57, 0xb5, 0xb9, 0xd1, 0xf1, 0xd2, 0x53, 0x48, 0x64, 0x05, 0xcb, 0xe7, 0xbe, - 0xdc, 0xc0, 0x69, 0x0f, 0x35, 0x87, 0xca, 0x12, 0x3c, 0x3d, 0x97, 0xf9, 0xf1, 0xb8, 0xc9, 0xa0, 0xb0, 0xfd, 0x46, - 0x68, 0x6f, 0xcc, 0x52, 0x0d, 0x15, 0xe1, 0xa0, 0xf3, 0xb5, 0x98, 0xd5, 0x23, 0xfa, 0x7b, 0x7e, 0x3c, 0xae, 0x09, - 0x0c, 0x38, 0x2c, 0x65, 0x26, 0x5a, 0x28, 0x96, 0xd6, 0xd9, 0x8c, 0xea, 0xc0, 0x03, 0x13, 0x73, 0x16, 0xee, 0x01, - 0xb4, 0x49, 0xad, 0x02, 0xbd, 0x8a, 0xe8, 0x27, 0xee, 0xd7, 0xf6, 0xeb, 0xf5, 0xc8, 0x2c, 0x1d, 0xb9, 0x31, 0x16, - 0x00, 0x1c, 0x78, 0x59, 0x93, 0x3c, 0x27, 0x5f, 0x43, 0xbb, 0x27, 0x17, 0xf2, 0x27, 0x28, 0x5b, 0x78, 0xa5, 0x9a, - 0x56, 0x16, 0x6b, 0xae, 0xaa, 0x57, 0x17, 0x3c, 0x37, 0x99, 0xd6, 0x69, 0x25, 0x54, 0xac, 0x5f, 0x43, 0x5d, 0xe2, - 0xb5, 0xa6, 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x79, 0x6d, - 0x1c, 0x3e, 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0xab, 0x1a, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, - 0xc5, 0xc4, 0xee, 0xd0, 0xaa, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, - 0x01, 0x2f, 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x72, 0x26, - 0xc0, 0x0f, 0x4a, 0xad, 0xe9, 0x83, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, - 0xe7, 0xe3, 0xe5, 0xb5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x55, 0xab, 0x7f, 0x98, 0xea, 0x5b, - 0xe8, 0x4e, 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, - 0x1c, 0xec, 0x0d, 0x70, 0xe2, 0x97, 0xc7, 0xa3, 0xb8, 0xa9, 0x7c, 0x76, 0xd9, 0x35, 0xb2, 0x72, 0x00, 0x73, 0x88, - 0x82, 0x71, 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xcd, 0xf8, 0xf4, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0x55, - 0xdf, 0x3d, 0x03, 0xd2, 0xb2, 0x7e, 0x3f, 0x7a, 0x7e, 0x3d, 0x7d, 0x36, 0x8c, 0x02, 0x70, 0xec, 0xb2, 0x97, 0x97, - 0x31, 0x5f, 0x5d, 0x33, 0xcb, 0x14, 0x16, 0xf9, 0x66, 0x40, 0x75, 0xc9, 0x6a, 0xe9, 0x7a, 0x05, 0x58, 0xba, 0xfc, - 0xe6, 0x21, 0x4c, 0x0d, 0x68, 0x64, 0xcd, 0xdd, 0x69, 0xae, 0x05, 0x4a, 0x3d, 0xef, 0x67, 0x86, 0x7c, 0x5d, 0x06, - 0x5d, 0x41, 0xba, 0xe7, 0x11, 0xe9, 0xe5, 0x41, 0x3a, 0xdd, 0x1f, 0x4a, 0x01, 0x96, 0xfa, 0x52, 0x7c, 0x06, 0x85, - 0x45, 0xe3, 0x1b, 0x01, 0xda, 0x1a, 0xaa, 0x69, 0xaf, 0x14, 0x55, 0x2f, 0xe8, 0x95, 0xe2, 0x73, 0x4f, 0x0f, 0x95, - 0xf9, 0xb2, 0x74, 0xf4, 0x3f, 0xa3, 0xe6, 0x82, 0x13, 0x62, 0x26, 0xe6, 0x00, 0x2a, 0x41, 0x1b, 0xdf, 0xfa, 0x64, - 0xe3, 0x53, 0xbd, 0x8a, 0x9b, 0x3e, 0xaf, 0xad, 0x65, 0x4e, 0x08, 0x9b, 0xee, 0x25, 0x40, 0x45, 0x5e, 0x09, 0x8f, - 0x60, 0xf9, 0xe5, 0x0f, 0x79, 0xba, 0x42, 0xb4, 0x8e, 0x7b, 0x96, 0xb9, 0x34, 0xf6, 0xaf, 0x0d, 0xa6, 0xaf, 0x6f, - 0xb7, 0x45, 0x7e, 0x6a, 0x62, 0xc2, 0x7a, 0xac, 0xe8, 0x9b, 0x77, 0xe1, 0x5a, 0xa0, 0xc0, 0xa1, 0x44, 0x62, 0x9b, - 0x2a, 0x14, 0xf1, 0x20, 0xe9, 0xd3, 0x45, 0xeb, 0xd3, 0x00, 0x53, 0x6b, 0x39, 0x30, 0x87, 0x70, 0x15, 0x17, 0x3e, - 0x7a, 0xfa, 0x16, 0xb3, 0x70, 0x3e, 0xf1, 0x3e, 0x7a, 0xc5, 0xc8, 0x7c, 0xdc, 0x47, 0xa5, 0x92, 0xfe, 0x79, 0x3c, - 0xce, 0xf2, 0xb9, 0xef, 0xd0, 0x47, 0x7a, 0xa8, 0x72, 0x41, 0xd9, 0x1b, 0x63, 0x12, 0x81, 0xd2, 0x18, 0xef, 0xe3, - 0xe0, 0x38, 0xef, 0xd3, 0x00, 0x52, 0xfb, 0xc4, 0x7b, 0x52, 0x72, 0x78, 0xce, 0x31, 0x27, 0x94, 0x56, 0x84, 0xe5, - 0x7c, 0x91, 0xa1, 0x5c, 0x77, 0x4e, 0xc1, 0x24, 0x87, 0x04, 0xc3, 0x5f, 0x35, 0x6f, 0x62, 0x05, 0xc2, 0xae, 0x91, - 0x33, 0x47, 0x4f, 0xaa, 0x24, 0x2c, 0x05, 0x1c, 0x95, 0x99, 0x67, 0xd8, 0x1b, 0x9e, 0x18, 0x46, 0x0e, 0x56, 0xf9, - 0xa3, 0x3a, 0x11, 0xb9, 0x47, 0x17, 0x18, 0x95, 0x85, 0x57, 0x0d, 0x5d, 0x69, 0x50, 0x49, 0x76, 0xfa, 0x15, 0xd7, - 0x80, 0xda, 0x1a, 0x23, 0x96, 0x83, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, - 0x95, 0xdc, 0xf5, 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, - 0x2c, 0x85, 0x23, 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, - 0x42, 0x9a, 0x6c, 0x5f, 0xcf, 0x3f, 0xe4, 0x5a, 0x90, 0x95, 0x5b, 0xce, 0xe9, 0xb0, 0xf8, 0xc6, 0xd9, 0x57, 0x39, - 0x79, 0x8a, 0x59, 0x46, 0x7a, 0xa7, 0x98, 0x17, 0xf0, 0xa7, 0xb2, 0xd4, 0x93, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, - 0x97, 0xde, 0xb6, 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0x0f, 0xf1, 0x48, 0x9e, 0x61, 0x5b, 0x96, 0xb0, 0xd0, 0x2a, - 0x18, 0x03, 0x48, 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x8f, 0xc7, 0xcb, 0xad, 0x39, 0x4b, 0x0e, 0xe0, 0xfa, 0xca, - 0x13, 0xf3, 0x0e, 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x5b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, - 0x62, 0xad, 0x63, 0xc9, 0xad, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0x7f, 0x70, 0x83, 0xab, - 0x6b, 0x63, 0x50, 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0x8b, 0x8a, 0x7c, 0xf9, 0xad, - 0x9d, 0x03, 0x82, 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, - 0x33, 0xd8, 0xc4, 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, - 0xab, 0x85, 0x48, 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, - 0x41, 0x27, 0x68, 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, - 0x07, 0x99, 0x13, 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, - 0x74, 0x28, 0x59, 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, - 0x0a, 0x5c, 0x08, 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xd5, 0xb4, 0x90, 0xa6, 0x81, 0x6a, - 0x9a, 0x3b, 0xe6, 0x81, 0xbd, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0x55, 0xfc, 0x83, 0x74, 0x2f, 0xce, - 0xe1, 0x2f, 0x6b, 0xfa, 0x20, 0xc2, 0x46, 0x0e, 0x1a, 0x4b, 0x89, 0xb1, 0x51, 0xe1, 0xdf, 0x12, 0x65, 0x43, 0x86, - 0x80, 0x10, 0xd2, 0x46, 0x45, 0x3f, 0xac, 0x2f, 0xef, 0x32, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, - 0xa9, 0x47, 0x3c, 0x5e, 0x1b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, - 0x28, 0x17, 0xbc, 0xe2, 0x39, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xa8, 0xe8, 0xf3, 0x39, 0xf0, 0x4c, - 0x40, 0xa0, 0x63, 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0xb7, 0x48, - 0x94, 0xfa, 0x8a, 0x94, 0xa4, 0x6f, 0x45, 0x8d, 0x57, 0x62, 0x15, 0x91, 0x40, 0x86, 0x1a, 0x22, 0x56, 0xd5, 0x53, - 0xf7, 0xa6, 0x98, 0x0c, 0x06, 0xb9, 0x2f, 0xa7, 0x27, 0xde, 0xd0, 0x50, 0x79, 0xd7, 0x15, 0xed, 0xf4, 0x44, 0x2b, - 0xe5, 0x2d, 0xa4, 0x25, 0x68, 0x1a, 0x46, 0x9a, 0x43, 0xa9, 0x6b, 0xe9, 0x6e, 0x0c, 0xe2, 0x4b, 0x26, 0x7a, 0xb6, - 0x53, 0x3b, 0x4a, 0x5b, 0xd2, 0x1e, 0x42, 0x7a, 0xee, 0x92, 0x8f, 0x21, 0x42, 0x4c, 0x55, 0xa5, 0xbc, 0x09, 0xd1, - 0xc9, 0xfd, 0x80, 0x21, 0x11, 0xe8, 0x73, 0x8e, 0x61, 0x5d, 0x34, 0xd4, 0x18, 0x6c, 0x6d, 0xb6, 0x50, 0xc2, 0x7c, - 0xc9, 0x78, 0x2a, 0x19, 0x34, 0x00, 0x32, 0xe0, 0xb3, 0x97, 0x81, 0xe5, 0xaf, 0x20, 0x7e, 0xb4, 0xf1, 0xf1, 0xf8, - 0x67, 0x4d, 0x21, 0xb6, 0x7f, 0xc2, 0x66, 0x08, 0x8f, 0xea, 0x01, 0xcf, 0x7c, 0x13, 0x27, 0x68, 0x05, 0x24, 0x65, - 0x76, 0x34, 0x91, 0xbd, 0xea, 0x21, 0x9c, 0xca, 0x0a, 0xd4, 0x51, 0xd6, 0x59, 0x09, 0x3f, 0xc2, 0x54, 0xb7, 0x12, - 0x6b, 0x81, 0x36, 0x57, 0x2b, 0xd6, 0x02, 0x38, 0xf0, 0x2b, 0x08, 0x9e, 0xa8, 0xe6, 0xe0, 0x62, 0x50, 0x80, 0xcf, - 0x01, 0xf0, 0x22, 0x77, 0xe1, 0xc1, 0x3c, 0xb2, 0xac, 0x46, 0x18, 0x8e, 0x2a, 0x62, 0xfd, 0x9a, 0xed, 0xc8, 0x07, - 0x6e, 0xc7, 0xf8, 0x5c, 0x7b, 0x2c, 0x59, 0x0e, 0x46, 0x99, 0x7b, 0xb5, 0x44, 0xcf, 0x9b, 0x34, 0x6e, 0x46, 0x4f, - 0x0e, 0xb5, 0xfc, 0x5f, 0xd0, 0xcb, 0xa0, 0xbf, 0x85, 0x5b, 0x5e, 0xf3, 0xbb, 0x05, 0x91, 0x66, 0x7a, 0x05, 0x91, - 0x32, 0x6a, 0x44, 0xc6, 0x10, 0x36, 0xa9, 0x6e, 0x65, 0x93, 0xea, 0x42, 0xc0, 0xd3, 0x09, 0xa9, 0xae, 0x85, 0xb4, - 0x51, 0x4d, 0xeb, 0x40, 0xc6, 0x22, 0xbd, 0xfb, 0xf1, 0x2f, 0x2f, 0x3e, 0xbd, 0xf9, 0xe5, 0xc7, 0xc5, 0x9b, 0x77, - 0xaf, 0xdf, 0xbc, 0x7b, 0xf3, 0xe9, 0x37, 0x82, 0xf0, 0x98, 0x0a, 0x95, 0xe1, 0xc3, 0xfb, 0xdb, 0x37, 0x4e, 0x06, - 0xdb, 0x9b, 0x21, 0x6b, 0xdf, 0xc8, 0xc1, 0x10, 0x88, 0x6c, 0x10, 0x32, 0xc8, 0x4e, 0x6d, 0xfb, 0x33, 0x31, 0xc7, - 0xd8, 0x3b, 0x81, 0xc9, 0x16, 0x24, 0x87, 0x65, 0x5e, 0x32, 0x22, 0x57, 0x8e, 0xd6, 0x0f, 0x68, 0xc1, 0x5b, 0x70, - 0x91, 0x49, 0xf3, 0xd5, 0x2f, 0x04, 0xb1, 0x4f, 0x2b, 0xa9, 0xf2, 0xd5, 0xb6, 0xe6, 0xf9, 0xf6, 0x7e, 0x9f, 0xd3, - 0x8a, 0x99, 0x4b, 0x23, 0x6a, 0x01, 0x0e, 0xc0, 0x97, 0xf0, 0xc7, 0x8d, 0xb6, 0xa4, 0xc9, 0x2c, 0xfa, 0x2c, 0x84, - 0xa0, 0x4b, 0x03, 0x69, 0x62, 0x8f, 0xbc, 0xd4, 0x27, 0x0b, 0x09, 0xdc, 0x11, 0xc3, 0xa7, 0x15, 0x41, 0xaf, 0x18, - 0x51, 0x5c, 0x72, 0x85, 0x4a, 0x29, 0xf9, 0x37, 0xca, 0x2e, 0x2a, 0xe4, 0xac, 0x60, 0xf7, 0x8a, 0x1c, 0x19, 0x3f, - 0x08, 0x26, 0xbe, 0x0a, 0xdc, 0x7f, 0x89, 0x77, 0x38, 0x53, 0x1c, 0xc9, 0x09, 0x7f, 0xc8, 0x30, 0xb0, 0xbf, 0x02, - 0x9f, 0x57, 0x87, 0x79, 0x79, 0xab, 0x4f, 0xb9, 0x25, 0x1f, 0x4f, 0x96, 0x37, 0x60, 0xb0, 0x5f, 0xaa, 0xe6, 0x6e, - 0x78, 0x3d, 0x5b, 0xce, 0xd9, 0x61, 0x16, 0xcd, 0x83, 0x15, 0x9b, 0x65, 0xf3, 0x60, 0xdd, 0xf0, 0x0d, 0xbb, 0xe3, - 0x1b, 0xab, 0x6a, 0x1b, 0xbb, 0x6a, 0x93, 0x2d, 0xbf, 0x03, 0x09, 0xe1, 0x36, 0xf3, 0x72, 0x96, 0xb0, 0x95, 0xcf, - 0xb6, 0x20, 0xd1, 0xae, 0xd9, 0x16, 0x2e, 0x62, 0x1b, 0xfe, 0x63, 0xee, 0x6d, 0x59, 0xc9, 0x2e, 0xc7, 0xac, 0xc2, - 0xf9, 0xe7, 0xc3, 0x03, 0xda, 0x0b, 0xf5, 0xb3, 0x6b, 0xf5, 0x6c, 0xa2, 0xec, 0x66, 0xdb, 0xd1, 0xe2, 0x3e, 0xad, - 0xb6, 0x61, 0x86, 0x9e, 0xe5, 0xf0, 0xd1, 0x56, 0x0a, 0x7e, 0x7a, 0x81, 0x5f, 0xb2, 0xa3, 0xb6, 0xd2, 0xb6, 0x5d, - 0x95, 0xd8, 0x0a, 0x5a, 0x14, 0x59, 0xad, 0xf0, 0xc0, 0x8a, 0x3f, 0x87, 0x05, 0x8c, 0x3d, 0xc7, 0x39, 0xaf, 0xfd, - 0x11, 0x32, 0xde, 0x3b, 0x00, 0x68, 0x99, 0xe3, 0x00, 0x8f, 0x58, 0x31, 0x8a, 0x06, 0xef, 0xf2, 0x5a, 0x59, 0xad, - 0x34, 0x27, 0xa1, 0x6d, 0xc4, 0xaa, 0xe5, 0x48, 0xd5, 0x8c, 0x48, 0x1f, 0xa4, 0xe7, 0x7d, 0x8f, 0xa8, 0x06, 0x7b, - 0x32, 0xaf, 0x03, 0xfb, 0xf4, 0xb2, 0xb5, 0xaa, 0x3b, 0xbf, 0xa7, 0x4a, 0x97, 0x1c, 0xd9, 0xf2, 0xd3, 0x65, 0xf8, - 0xa0, 0xfe, 0x94, 0x5c, 0x1f, 0x0a, 0x1c, 0xe1, 0xb1, 0x0a, 0x38, 0x5f, 0xcf, 0x45, 0xbb, 0x13, 0x61, 0x57, 0x2e, - 0x01, 0x21, 0xbe, 0xa4, 0x69, 0x8e, 0xc7, 0x11, 0x4d, 0x44, 0xd8, 0xc4, 0xe8, 0x2f, 0xec, 0x3e, 0x94, 0x58, 0x2e, - 0x2b, 0x0d, 0x4a, 0x2e, 0x19, 0xbc, 0x27, 0xed, 0x35, 0x68, 0x96, 0x57, 0xae, 0x26, 0x13, 0x39, 0x28, 0x1f, 0x8f, - 0x05, 0xec, 0xa5, 0xc6, 0x4f, 0x13, 0x7e, 0xc2, 0xf2, 0xd6, 0xde, 0x9a, 0x52, 0x54, 0xd2, 0x00, 0x15, 0xf8, 0x98, - 0xc1, 0xff, 0xee, 0x0c, 0xb1, 0x60, 0x8a, 0x4e, 0x1f, 0xce, 0xc4, 0xdc, 0x7a, 0x6e, 0x95, 0x75, 0x92, 0xad, 0x51, - 0x4e, 0xc0, 0xbf, 0xa5, 0x3a, 0x4e, 0x12, 0xe1, 0xd4, 0x7b, 0xc4, 0x45, 0xdd, 0xcb, 0x21, 0xea, 0x86, 0xbd, 0xc9, - 0x75, 0xb0, 0xe5, 0x34, 0x0d, 0x4e, 0xc4, 0xaf, 0xd4, 0x67, 0xef, 0x33, 0x8b, 0x47, 0x1d, 0xd9, 0x88, 0x92, 0x34, - 0x8e, 0x45, 0x0e, 0xdb, 0xfb, 0x42, 0xee, 0xff, 0xfd, 0x3e, 0x84, 0x93, 0x56, 0x41, 0x52, 0x7a, 0x02, 0x11, 0xe1, - 0xe8, 0xf0, 0x23, 0xc2, 0x13, 0xa9, 0x2a, 0x7c, 0x52, 0x9f, 0xb9, 0x31, 0xbb, 0x17, 0xe6, 0xa8, 0xde, 0x01, 0x0c, - 0x63, 0xbd, 0xb3, 0x08, 0x49, 0xb4, 0xd2, 0x8c, 0xb6, 0x1e, 0x10, 0x23, 0xde, 0x6f, 0x2c, 0x32, 0x18, 0x6b, 0x4b, - 0x22, 0x01, 0x7c, 0x45, 0x42, 0x86, 0xb6, 0x8d, 0xc0, 0x8c, 0xe1, 0xed, 0xac, 0xb8, 0x74, 0x1d, 0xb6, 0x39, 0x87, - 0x2f, 0x64, 0xa1, 0x59, 0x47, 0x94, 0x26, 0x08, 0xf9, 0x07, 0x9c, 0x2c, 0x14, 0x46, 0xf3, 0xea, 0x24, 0x9d, 0x24, - 0xd6, 0xf7, 0x5d, 0xa5, 0x82, 0xcd, 0xe6, 0x16, 0xf5, 0x65, 0x27, 0xc9, 0x2f, 0xc1, 0x49, 0xc7, 0x49, 0x16, 0x39, - 0x88, 0x5a, 0x54, 0xce, 0x6d, 0x12, 0x96, 0x76, 0x75, 0xaa, 0xed, 0x66, 0x53, 0x94, 0x75, 0xf5, 0x4a, 0x44, 0x8a, - 0xde, 0x47, 0x3d, 0x7a, 0x22, 0x21, 0x15, 0x5a, 0x95, 0xda, 0xe7, 0x11, 0xb8, 0x6d, 0x6a, 0xc5, 0xb6, 0x5c, 0xc2, - 0x12, 0x35, 0xfe, 0x13, 0xf4, 0x51, 0x2e, 0x1e, 0x64, 0x80, 0x46, 0xc7, 0x53, 0xf3, 0xd6, 0x23, 0xaf, 0x9c, 0xe4, - 0x97, 0x56, 0x9b, 0xf4, 0x0b, 0x20, 0x33, 0xda, 0x3f, 0x5a, 0x4a, 0x20, 0x33, 0x30, 0x93, 0x96, 0x86, 0x44, 0x8e, - 0x62, 0x96, 0xe6, 0x7f, 0xe0, 0x8a, 0xad, 0x10, 0x69, 0x58, 0xcd, 0x3d, 0xfe, 0x22, 0xf7, 0x6a, 0xb9, 0x96, 0x99, - 0xe6, 0x66, 0x89, 0x63, 0xc5, 0xe2, 0xa2, 0x5e, 0x57, 0x22, 0x0b, 0x84, 0x38, 0xc2, 0x34, 0xd6, 0x53, 0x6f, 0x94, - 0x56, 0x1f, 0x90, 0x50, 0xe6, 0x47, 0xec, 0xed, 0xd8, 0xeb, 0x41, 0x16, 0xe2, 0xd8, 0x72, 0xb0, 0xd9, 0x7a, 0x9f, - 0xca, 0x54, 0xc4, 0x17, 0x75, 0x71, 0xb1, 0xad, 0xc4, 0x45, 0x9d, 0x88, 0x8b, 0xef, 0x21, 0xe7, 0xf7, 0x17, 0x54, - 0xf4, 0xc5, 0x43, 0x5a, 0x27, 0xc5, 0xb6, 0xa6, 0x27, 0xaf, 0xb1, 0x8c, 0xef, 0x2f, 0x88, 0xab, 0xe6, 0x82, 0x46, - 0x32, 0x1e, 0x5d, 0x7c, 0xc8, 0x80, 0xe4, 0xf5, 0x22, 0x5d, 0xc3, 0xe0, 0x5d, 0x84, 0x79, 0x7c, 0x51, 0x8a, 0x15, - 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x3a, 0xfc, 0x43, 0x5c, 0x00, 0xb4, 0xeb, 0x45, 0x5a, 0x5f, 0xa4, 0xd5, - 0x45, 0x5e, 0xd4, 0x17, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, 0x4f, 0x5f, 0xd9, 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, - 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x72, 0xe1, 0xb5, 0xfb, 0xdb, 0xe6, 0xfe, 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, - 0x46, 0x74, 0x41, 0x3d, 0x5d, 0x49, 0x4a, 0x05, 0x05, 0x04, 0x4e, 0x34, 0x6b, 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, - 0x5b, 0xb2, 0x8d, 0xcf, 0x9f, 0xc7, 0x32, 0x4c, 0x7b, 0x1b, 0xe0, 0x5f, 0x65, 0x6f, 0xba, 0x09, 0x96, 0x78, 0xdf, - 0x42, 0xb6, 0xa1, 0x37, 0xaf, 0xf8, 0x0b, 0xaf, 0x52, 0x7f, 0xb3, 0x7f, 0x00, 0x10, 0x06, 0xc4, 0xac, 0xfa, 0x68, - 0xe2, 0xde, 0x5b, 0x59, 0xf6, 0x4e, 0x96, 0x7d, 0x0f, 0xfd, 0x9a, 0xc4, 0xa8, 0xb4, 0xb2, 0x94, 0x4e, 0x96, 0x12, - 0xb2, 0x80, 0x4f, 0x8c, 0xa6, 0x36, 0x02, 0x08, 0xdb, 0x51, 0x2a, 0x5f, 0x00, 0xc2, 0x49, 0x02, 0x12, 0x62, 0x09, - 0x17, 0xa3, 0x7b, 0x2b, 0x19, 0x30, 0x1c, 0x42, 0x30, 0x07, 0xed, 0xb0, 0x37, 0x74, 0x13, 0xf1, 0xd7, 0xeb, 0xa2, - 0x7c, 0x13, 0x93, 0x4f, 0xc1, 0xfe, 0xec, 0xe3, 0x12, 0x1e, 0x97, 0x67, 0x1f, 0x87, 0xe8, 0x91, 0x70, 0xf6, 0x31, - 0xf8, 0x1e, 0xc9, 0x79, 0xdd, 0xf5, 0x38, 0x41, 0x6e, 0x21, 0xdd, 0xdf, 0x8e, 0x49, 0x80, 0xe6, 0x35, 0x2c, 0x47, - 0x4d, 0xc5, 0x35, 0x33, 0x63, 0x3c, 0x6f, 0xf4, 0xfe, 0xd8, 0xf1, 0x96, 0x29, 0x14, 0xb3, 0x98, 0xd7, 0xf0, 0x7b, - 0x56, 0x05, 0xea, 0xae, 0xb7, 0x49, 0x6e, 0x99, 0xd5, 0x73, 0xb4, 0xfb, 0xbe, 0xaf, 0x13, 0x41, 0xed, 0xef, 0xb0, - 0xe7, 0x99, 0xf5, 0xae, 0x8a, 0x81, 0x4b, 0x95, 0xec, 0x90, 0xa9, 0x6a, 0x7a, 0xa0, 0x52, 0x1a, 0x3c, 0xbd, 0xb4, - 0x2e, 0x5f, 0x2a, 0x6d, 0xe4, 0x99, 0xe6, 0x37, 0x80, 0x17, 0x53, 0x97, 0xc5, 0xfe, 0xab, 0xfb, 0x0a, 0x6e, 0xe3, - 0xfd, 0xfe, 0x32, 0xf7, 0xcc, 0x4f, 0x5c, 0x00, 0xf6, 0xa6, 0x42, 0xeb, 0x04, 0x4a, 0x0d, 0xeb, 0xf0, 0x65, 0x22, - 0xa2, 0x3f, 0xda, 0xe5, 0x3a, 0x73, 0x1d, 0x30, 0xa2, 0x88, 0xdf, 0xc6, 0xa3, 0x3f, 0x40, 0x71, 0x6d, 0xec, 0x01, - 0x61, 0x1d, 0x12, 0xfa, 0x8c, 0x00, 0xa4, 0x1e, 0x73, 0x94, 0x80, 0x66, 0x45, 0x73, 0xc7, 0xc0, 0xc1, 0x2f, 0xaf, - 0x94, 0xfe, 0x61, 0x99, 0x7b, 0x64, 0x4e, 0x69, 0x9b, 0x69, 0xac, 0xd6, 0xe4, 0x02, 0xe1, 0x15, 0x95, 0xac, 0xc2, - 0x67, 0xf3, 0x46, 0xf4, 0xfb, 0xf2, 0x08, 0x4f, 0xab, 0x1f, 0x77, 0x18, 0xdf, 0x0a, 0x88, 0x46, 0x02, 0xa0, 0x9f, - 0x00, 0xe6, 0x45, 0x36, 0xb3, 0xfb, 0x38, 0xa0, 0x4a, 0x89, 0xa6, 0x71, 0x36, 0xcf, 0x6f, 0xe9, 0x4d, 0xd9, 0x41, - 0xe7, 0x4e, 0x15, 0xb8, 0xe0, 0xaa, 0x64, 0xbc, 0xb2, 0x9e, 0xc9, 0xe7, 0x37, 0x77, 0xdb, 0x34, 0x8b, 0xdf, 0x97, - 0xff, 0xc0, 0xb1, 0xd5, 0x75, 0x78, 0x64, 0xea, 0x74, 0xed, 0x3c, 0xd2, 0xda, 0x0b, 0x01, 0x11, 0xed, 0x1a, 0x6a, - 0xbd, 0xb0, 0xd0, 0x23, 0x3d, 0x11, 0xce, 0x49, 0xa2, 0xa6, 0x1d, 0x68, 0x69, 0x84, 0xbe, 0xbe, 0xca, 0x8b, 0x2e, - 0x06, 0x6b, 0x5f, 0x8e, 0x59, 0x0e, 0x5d, 0xaa, 0x1e, 0xab, 0x87, 0xc6, 0x66, 0x0e, 0x3d, 0x6b, 0x55, 0x9e, 0x79, - 0xf9, 0xf1, 0x88, 0xf8, 0x30, 0xfa, 0x4b, 0x7e, 0xbf, 0xff, 0x8a, 0xe6, 0x1f, 0x13, 0x6a, 0xfc, 0x6c, 0x33, 0x40, - 0xd7, 0xbe, 0x2b, 0x0f, 0x44, 0x3d, 0xd7, 0x2a, 0x41, 0x88, 0x37, 0x88, 0x89, 0x66, 0xc4, 0x1c, 0x9c, 0x76, 0xa8, - 0xf9, 0x27, 0xa9, 0x01, 0x21, 0x4a, 0xbc, 0x8e, 0x29, 0x0b, 0x72, 0xda, 0xc4, 0x91, 0x7e, 0x14, 0x4e, 0xe4, 0x47, - 0x51, 0x15, 0xd9, 0x3d, 0x5c, 0x30, 0x98, 0x7a, 0x4f, 0xfb, 0x25, 0xfa, 0x2d, 0xe1, 0xc8, 0x39, 0x5a, 0x15, 0x82, - 0xc8, 0x19, 0x61, 0xad, 0x21, 0x4c, 0x10, 0x1b, 0xc4, 0xcb, 0xbe, 0x4b, 0x32, 0x1c, 0x29, 0xb8, 0xac, 0x63, 0xc7, - 0x98, 0xab, 0xa3, 0xea, 0x35, 0x80, 0xf1, 0xaa, 0x10, 0x34, 0x1b, 0x45, 0x76, 0x09, 0x51, 0x45, 0x8e, 0x27, 0xa0, - 0x76, 0x50, 0x1a, 0x9b, 0xe9, 0xe5, 0x38, 0x80, 0x09, 0x8e, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x2b, 0xd5, - 0xcf, 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x9c, 0xe9, - 0x72, 0x60, 0xdc, 0xb7, 0x3c, 0xa7, 0x38, 0xc3, 0x8f, 0x5e, 0x3e, 0xab, 0xe7, 0xfe, 0x74, 0x4b, 0xed, 0xc7, 0xdc, - 0xa8, 0x87, 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, - 0xfc, 0x43, 0x99, 0xae, 0x53, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, - 0xa2, 0xac, 0xdf, 0x87, 0xdf, 0x37, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, - 0x93, 0x41, 0x0d, 0xda, 0xf0, 0x2d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, - 0xec, 0x4f, 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xeb, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xa7, 0x97, 0xfc, - 0x06, 0xbd, 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, - 0x8f, 0x51, 0xc9, 0x62, 0x4b, 0x8f, 0x95, 0xd3, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x0e, 0xc1, - 0x12, 0x18, 0x17, 0xb1, 0xe1, 0xdb, 0x41, 0xc5, 0xe2, 0xd9, 0x76, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1e, 0x0b, 0x09, - 0x36, 0x93, 0xcd, 0x36, 0x73, 0xb6, 0xf1, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, - 0x35, 0x58, 0xad, 0xa6, 0xec, 0x54, 0x53, 0xf6, 0x4e, 0x53, 0x4e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, - 0x88, 0x4d, 0xa2, 0x9b, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, - 0x50, 0x85, 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, - 0xbe, 0xa5, 0x8e, 0x07, 0x94, 0x6d, 0xfe, 0x26, 0xf6, 0x41, 0x88, 0xdc, 0x8d, 0x7b, 0xf5, 0x33, 0xe2, 0xbd, 0xfd, - 0x09, 0xc6, 0x4f, 0x76, 0xda, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8c, 0xca, 0x24, 0x41, 0x2d, 0x4b, 0xe2, - 0x6f, 0x79, 0x32, 0xa8, 0xd8, 0x12, 0x3c, 0x68, 0xe7, 0x2c, 0x03, 0xfc, 0x15, 0xab, 0x45, 0xbf, 0xd5, 0xde, 0x12, - 0xe4, 0xa7, 0xad, 0xdd, 0x28, 0x4c, 0x8c, 0x20, 0x51, 0xb7, 0x2b, 0x03, 0xf9, 0xe1, 0x03, 0x4e, 0xc7, 0x53, 0x4f, - 0x19, 0x73, 0x2b, 0xd3, 0xcb, 0x74, 0xae, 0xe4, 0x1b, 0xb9, 0x97, 0x3e, 0xf6, 0x12, 0xec, 0x1c, 0xf0, 0x06, 0xd2, - 0x06, 0xde, 0xc2, 0x76, 0xe1, 0xb5, 0x41, 0xc2, 0x8c, 0x00, 0x5b, 0x9c, 0x1e, 0x23, 0x25, 0x30, 0x84, 0xe3, 0x2c, - 0x05, 0x60, 0x1a, 0x7d, 0x99, 0xcd, 0xed, 0xcb, 0xac, 0xd6, 0x6c, 0xa9, 0x9c, 0xee, 0x9d, 0x5b, 0xb7, 0xf3, 0x89, - 0x04, 0x00, 0x93, 0x3a, 0x07, 0xe2, 0xcc, 0x04, 0xbb, 0x34, 0x89, 0x2c, 0x1f, 0xc3, 0x7c, 0x25, 0x5e, 0x97, 0xc5, - 0x5a, 0x75, 0x45, 0xdb, 0x67, 0xa6, 0x9a, 0x91, 0x4e, 0x42, 0x05, 0x14, 0x14, 0x72, 0xad, 0x4f, 0xdf, 0x85, 0xef, - 0x82, 0x42, 0x03, 0xb3, 0xe5, 0xb8, 0xa7, 0xc9, 0x1a, 0xa9, 0x37, 0xf2, 0x7e, 0x9f, 0x5c, 0x03, 0xa9, 0xce, 0x1c, - 0x5a, 0xf6, 0x04, 0x9d, 0x64, 0x4f, 0x6e, 0xca, 0x52, 0xa8, 0x03, 0xa9, 0x07, 0x0c, 0x21, 0xda, 0xa6, 0x8f, 0x3f, - 0x19, 0x12, 0x5d, 0x80, 0x2d, 0x44, 0x1b, 0xf8, 0xf1, 0x27, 0xd8, 0x67, 0x41, 0x78, 0x4c, 0xf3, 0xb7, 0x90, 0x74, - 0x6a, 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0x95, - 0x94, 0xea, 0x00, 0x6d, 0x4a, 0xb9, 0xab, 0x2b, 0x3f, 0x88, 0xb6, 0xe0, 0xc8, 0x22, 0xfe, 0x3e, 0x43, 0x44, 0x30, - 0x33, 0x88, 0xb0, 0x6b, 0xa1, 0xee, 0xf6, 0x9c, 0x5a, 0x16, 0xf5, 0xb6, 0xe7, 0x94, 0xba, 0x0d, 0xc3, 0x77, 0x13, - 0xcc, 0x14, 0x37, 0xfc, 0x8f, 0xcc, 0x0b, 0xf5, 0xc6, 0x63, 0x51, 0xa0, 0x7b, 0xfe, 0x61, 0xc9, 0xf3, 0xd9, 0x56, - 0x99, 0x30, 0x57, 0x7c, 0x39, 0x0b, 0x65, 0x57, 0x4b, 0xe3, 0xce, 0x67, 0x6f, 0xa9, 0xe6, 0x83, 0x7f, 0x3c, 0x26, - 0x10, 0x6f, 0x14, 0xdf, 0xac, 0x1a, 0xb9, 0x75, 0x4d, 0xb6, 0x37, 0x25, 0xa0, 0x7e, 0x5f, 0x6e, 0x70, 0xbf, 0xc5, - 0xfa, 0x77, 0x4f, 0x83, 0x8c, 0xd5, 0x0c, 0x57, 0x4c, 0xe1, 0x53, 0x00, 0x18, 0x1c, 0x4e, 0x05, 0x69, 0x81, 0xb7, - 0xbc, 0x1c, 0x5e, 0x4f, 0xb6, 0x64, 0xd2, 0xdd, 0xfa, 0xc8, 0x9d, 0x05, 0xaa, 0xde, 0x6f, 0x28, 0x4e, 0x1a, 0x24, - 0x1a, 0x7b, 0x0d, 0xbe, 0xc8, 0x32, 0xca, 0x45, 0x13, 0xf7, 0x31, 0xf9, 0x4a, 0x0f, 0x60, 0xa5, 0x42, 0x09, 0x10, - 0xfd, 0xc6, 0xb2, 0xd8, 0x88, 0xb6, 0xc5, 0x06, 0x96, 0x52, 0x3e, 0xd7, 0xab, 0xe9, 0xb3, 0x57, 0xa2, 0x79, 0x1f, - 0xcd, 0x38, 0xa5, 0xd1, 0x80, 0xe3, 0x34, 0x0a, 0x77, 0xef, 0xef, 0x45, 0xb9, 0xcc, 0xc0, 0x92, 0xad, 0xc2, 0x29, - 0xae, 0x1b, 0x75, 0x46, 0xbc, 0xc8, 0x63, 0x05, 0xd0, 0xf1, 0x98, 0x00, 0xa8, 0x2e, 0x08, 0xa8, 0x88, 0x96, 0xd2, - 0x5b, 0xa1, 0xc5, 0x42, 0xbd, 0xe1, 0x28, 0x85, 0x3f, 0xd2, 0x9f, 0x07, 0xd5, 0x14, 0x80, 0xd8, 0xf5, 0x71, 0xf4, - 0xba, 0x28, 0xe9, 0x53, 0xc5, 0xac, 0x92, 0x83, 0x09, 0xec, 0xea, 0x44, 0x86, 0x9a, 0x43, 0xde, 0xbc, 0x2b, 0x6f, - 0x6e, 0xf2, 0x36, 0xc6, 0x29, 0xf9, 0x91, 0x9b, 0x8e, 0x35, 0x62, 0xe0, 0x95, 0xa7, 0x75, 0x9a, 0x20, 0x4d, 0x2e, - 0x80, 0x61, 0x88, 0xef, 0x32, 0xef, 0x85, 0xe7, 0x48, 0x55, 0x90, 0xcc, 0xf6, 0x99, 0xa7, 0x2e, 0xa2, 0xfa, 0xca, - 0xa9, 0xa5, 0x33, 0xa7, 0x1f, 0x01, 0xbc, 0xc7, 0xd4, 0xa4, 0x21, 0x1f, 0xe1, 0xb6, 0x14, 0x5f, 0xef, 0xd4, 0x35, - 0x5e, 0x1a, 0x9d, 0xbb, 0x97, 0x2f, 0xdd, 0x69, 0xd0, 0x4f, 0x41, 0x50, 0xce, 0x17, 0xa5, 0x80, 0x3d, 0x65, 0x36, - 0xd7, 0xab, 0x55, 0x2b, 0xb4, 0x8e, 0xc7, 0xb1, 0x76, 0x14, 0xd2, 0xea, 0x2c, 0x60, 0xab, 0x91, 0x4e, 0x09, 0x10, - 0x82, 0xe3, 0x34, 0xec, 0x0c, 0xe3, 0x2e, 0x9d, 0x46, 0x64, 0xbd, 0x52, 0x92, 0x2e, 0xcc, 0x20, 0xf9, 0x27, 0x79, - 0x3d, 0x03, 0x5a, 0x02, 0x38, 0x14, 0xb1, 0x84, 0x87, 0x93, 0xe4, 0x06, 0xa0, 0xd3, 0xe1, 0xa0, 0xd2, 0xd0, 0x9c, - 0xf9, 0x2c, 0x99, 0x4f, 0x62, 0xa9, 0xaa, 0x3c, 0x1e, 0x3d, 0xe5, 0x66, 0xd0, 0xef, 0x67, 0xd3, 0x52, 0xb9, 0x00, - 0x04, 0xb1, 0x2e, 0x0c, 0x10, 0x8f, 0xb4, 0xf0, 0x64, 0xd1, 0xa7, 0x24, 0x7e, 0x39, 0x4b, 0xe6, 0x26, 0x1b, 0xde, - 0x81, 0x11, 0x6c, 0xc6, 0x75, 0x49, 0x99, 0xf6, 0xa8, 0xfc, 0x9e, 0xd1, 0x53, 0xdb, 0xd7, 0x5a, 0x6d, 0x11, 0xeb, - 0x3a, 0xb8, 0x2a, 0x51, 0x4f, 0xf1, 0x41, 0x49, 0x82, 0xf7, 0x2b, 0xe7, 0x66, 0xa4, 0x7c, 0x2d, 0x2a, 0x3f, 0x68, - 0x67, 0x6a, 0xe5, 0xc0, 0x11, 0xa8, 0xb0, 0x8a, 0x4a, 0x5e, 0xef, 0x3a, 0x04, 0x4f, 0xee, 0x4a, 0x05, 0xca, 0xc1, - 0xcf, 0x41, 0x8c, 0xae, 0x6f, 0x3a, 0x6b, 0xa8, 0x99, 0x46, 0x95, 0x47, 0xd0, 0xb9, 0x03, 0x78, 0x52, 0xf0, 0x52, - 0xab, 0x1f, 0x8f, 0x47, 0xcf, 0xfc, 0xe0, 0x2f, 0x33, 0x7d, 0x0b, 0x31, 0x51, 0x4e, 0x35, 0x42, 0xe2, 0x4a, 0x49, - 0x22, 0x3e, 0x5d, 0xb4, 0xac, 0x18, 0x95, 0xe1, 0x03, 0xb0, 0x00, 0x51, 0xf9, 0xea, 0x54, 0xe5, 0xc5, 0x48, 0xdb, - 0x12, 0x78, 0x4d, 0xfe, 0x21, 0x72, 0xcd, 0x5b, 0x5f, 0x77, 0x95, 0xa1, 0x6f, 0x65, 0x05, 0x3a, 0x82, 0xad, 0x2c, - 0x25, 0x07, 0x7c, 0x52, 0xdf, 0x55, 0x5b, 0x9f, 0x53, 0xb6, 0x11, 0x6e, 0xf2, 0xeb, 0xd8, 0xc1, 0x91, 0xf2, 0x1b, - 0xbc, 0x14, 0xc0, 0x5e, 0x03, 0xf6, 0xe6, 0x8a, 0x15, 0xcd, 0xa3, 0x43, 0xda, 0x16, 0x68, 0x64, 0xe6, 0x76, 0xae, - 0xee, 0xdb, 0xf2, 0x28, 0x8d, 0x21, 0x32, 0xed, 0x91, 0xe9, 0x60, 0x33, 0xca, 0x7f, 0x4b, 0xf9, 0xad, 0xc2, 0x31, - 0xf0, 0xed, 0xdc, 0x3b, 0x80, 0xaa, 0xa7, 0x0d, 0x32, 0xd6, 0x0c, 0x43, 0x2b, 0xbb, 0x5c, 0x0a, 0x2d, 0x41, 0x4b, - 0xdd, 0x04, 0xc1, 0xf9, 0x11, 0x51, 0x8e, 0x00, 0x74, 0x91, 0x02, 0x26, 0xf8, 0x39, 0x6d, 0x77, 0xbf, 0xbf, 0x49, - 0x3d, 0x72, 0xef, 0x0a, 0x95, 0xcd, 0xf2, 0x4d, 0x8e, 0x30, 0xf6, 0x13, 0x8d, 0x19, 0x74, 0x72, 0x45, 0x4e, 0x78, - 0xd6, 0xea, 0xb0, 0xae, 0x9b, 0x32, 0x28, 0x8b, 0x63, 0x9e, 0x4f, 0x67, 0xbf, 0x3f, 0x39, 0xd4, 0x0d, 0xb2, 0x90, - 0xff, 0xce, 0x7a, 0x48, 0x06, 0xdd, 0x83, 0x50, 0x88, 0xde, 0x3c, 0x98, 0xe1, 0x7f, 0x6c, 0xcb, 0xb3, 0x6f, 0xb8, - 0x51, 0x27, 0x80, 0x39, 0xe2, 0x7a, 0xe9, 0x29, 0xda, 0x7a, 0xb8, 0x05, 0xb2, 0x0d, 0x5e, 0xde, 0xda, 0x6b, 0xa0, - 0xa2, 0x38, 0xfe, 0x15, 0xcf, 0xd4, 0xca, 0x06, 0x3f, 0x3d, 0x65, 0x3b, 0xf0, 0xf0, 0x22, 0x04, 0x14, 0xc3, 0xb2, - 0xf1, 0x2b, 0xcb, 0x71, 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, - 0x93, 0x7b, 0x2b, 0x72, 0xca, 0x5c, 0xe9, 0x61, 0x74, 0x5d, 0x92, 0xbe, 0x49, 0x3e, 0xb6, 0x86, 0xed, 0x77, 0xed, - 0x7e, 0x33, 0x44, 0x10, 0x42, 0x39, 0x7e, 0xce, 0xe8, 0x84, 0xc6, 0x87, 0x35, 0xd7, 0x3b, 0xbd, 0x7e, 0xef, 0x12, - 0x2f, 0xd8, 0x1a, 0x0d, 0xf0, 0x74, 0xe8, 0x62, 0x9e, 0xa8, 0xa1, 0xd3, 0x75, 0xed, 0x1c, 0x3c, 0x30, 0xc8, 0xf2, - 0xe4, 0x1b, 0x86, 0x25, 0xf6, 0x27, 0x11, 0x4f, 0xda, 0xaa, 0x8d, 0xed, 0x89, 0x6a, 0xa3, 0x66, 0xe0, 0x07, 0xaf, - 0xa0, 0xc0, 0xe8, 0x82, 0xb4, 0x06, 0xe3, 0x70, 0x04, 0x20, 0x2b, 0xc6, 0xf1, 0xc8, 0x60, 0x02, 0x43, 0xba, 0xa1, - 0x28, 0x00, 0x0f, 0x8f, 0xd3, 0x41, 0xc8, 0x00, 0xd2, 0x05, 0x0f, 0x0d, 0xdb, 0x24, 0xa4, 0xfc, 0x3c, 0x2f, 0x6b, - 0x35, 0x84, 0xbe, 0xb3, 0x50, 0x1d, 0xfb, 0x91, 0xf6, 0x8a, 0x75, 0xad, 0x4a, 0x27, 0xb6, 0x3a, 0x40, 0xdf, 0x90, - 0x81, 0x6f, 0x1d, 0x5b, 0x00, 0x44, 0x4b, 0xfc, 0x96, 0x7a, 0xb5, 0x2f, 0x63, 0x56, 0xa8, 0xd7, 0x17, 0xa6, 0x5d, - 0xaf, 0xa4, 0x45, 0x01, 0x15, 0xb7, 0xad, 0xda, 0x9e, 0xc8, 0xf9, 0x8f, 0xef, 0x3a, 0xda, 0xf1, 0xd9, 0xa9, 0xb1, - 0x25, 0x94, 0xb9, 0xc5, 0x13, 0x59, 0x1d, 0x6d, 0xa9, 0x4e, 0xf5, 0x01, 0x97, 0x9a, 0x54, 0x67, 0xda, 0xa7, 0xc9, - 0x12, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xc1, 0xf9, 0x64, 0x50, 0x30, 0xb7, 0x48, 0x40, 0x02, 0xdb, 0xda, 0xda, - 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xf2, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, 0xce, 0xde, 0x69, 0x2d, 0x20, 0x80, - 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, 0xe5, 0x6f, 0x29, 0x2a, 0x62, 0xcf, - 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, 0x3a, 0x6a, 0x72, 0xd7, 0xcd, 0x55, - 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xbe, 0xd6, 0x95, 0x53, 0xef, 0x83, 0x8a, 0x23, 0x06, 0x82, 0x9b, 0xee, 0xf1, 0xc1, - 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, 0x68, 0xc5, 0xf4, 0x11, 0x00, 0x11, - 0x60, 0x95, 0xa8, 0xff, 0xcd, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, 0xb6, 0xde, 0x3f, 0xaf, 0x91, 0x56, - 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, 0xff, 0x9f, 0xfb, 0x00, 0x35, 0xa2, - 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2a, 0x7c, 0xe3, 0x87, 0x8c, 0xf3, 0xc1, 0x0c, 0x1d, 0xd5, 0xe6, - 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, 0x4f, 0xdc, 0x67, 0x5c, 0x7b, 0x41, - 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, 0x65, 0x93, 0x48, 0x7d, 0x33, 0x06, - 0x05, 0x40, 0xf1, 0x3c, 0x27, 0xb9, 0x74, 0x91, 0xe6, 0x95, 0x28, 0x6b, 0xdd, 0x8c, 0x9c, 0x15, 0xc3, 0x9c, 0xd5, - 0x7e, 0x50, 0xdc, 0xe4, 0x66, 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x7c, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, - 0xd2, 0xbb, 0x1c, 0xb7, 0xce, 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, - 0x3f, 0xe3, 0xcf, 0x09, 0x4c, 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x9c, 0x97, 0x93, - 0x70, 0x38, 0xf4, 0x41, 0x1f, 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, - 0x10, 0xd1, 0x42, 0x43, 0x1f, 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, - 0xda, 0xd0, 0x22, 0xc5, 0x45, 0xa3, 0xcc, 0x66, 0x95, 0xec, 0x84, 0xad, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, - 0x54, 0xad, 0xa7, 0x7a, 0x3d, 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa2, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, - 0xa3, 0x6a, 0x93, 0xa5, 0x11, 0x55, 0x6e, 0x52, 0xb9, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0xcd, 0xb5, 0xb3, 0x35, 0x38, - 0x71, 0xe4, 0xb9, 0xe4, 0x96, 0xef, 0xce, 0x2b, 0xba, 0x3b, 0xd5, 0xbe, 0x05, 0xb8, 0x37, 0xc3, 0x86, 0xcc, 0x79, - 0x8d, 0x9d, 0x06, 0x61, 0x12, 0xf8, 0x11, 0xfb, 0x98, 0x21, 0x1b, 0x0c, 0xe8, 0x28, 0xa4, 0x26, 0xc0, 0x32, 0x47, - 0x02, 0x26, 0x7f, 0x3d, 0xf7, 0x9b, 0x45, 0x91, 0xc3, 0x62, 0xfc, 0xb0, 0xc5, 0x48, 0x63, 0xb5, 0x06, 0xc3, 0x72, - 0x85, 0xc8, 0x9f, 0xda, 0x33, 0xd4, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, 0xa7, 0x4f, 0x75, 0x7d, 0xfe, 0xdb, - 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xc1, 0x2d, 0xce, 0x1d, 0x89, 0xde, 0xa9, 0xd2, 0xcc, 0x2e, - 0xed, 0x9a, 0x5d, 0x9b, 0xd2, 0x6e, 0xc9, 0xf5, 0xea, 0x2b, 0xe5, 0x8d, 0x9d, 0x57, 0x4c, 0xf7, 0x1f, 0x84, 0xde, - 0x51, 0xce, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, 0x26, 0x55, 0xbb, 0x84, 0x93, 0xae, - 0x61, 0x95, 0xf9, 0xf6, 0x3f, 0xf2, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, 0xfd, 0x29, 0x88, 0xab, 0xfa, 0xc3, - 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe4, 0x9e, 0x42, 0xd8, 0x60, 0xf6, 0xf3, - 0xd3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x9a, 0x11, 0xde, 0xef, 0x18, 0xe7, 0xfe, 0xcd, - 0x0f, 0x6a, 0x72, 0x84, 0x88, 0x76, 0x11, 0x0e, 0x00, 0xe2, 0x4e, 0x53, 0x59, 0x87, 0x1a, 0xa0, 0x0f, 0x08, 0xac, - 0x43, 0xdf, 0x66, 0x00, 0x07, 0x7d, 0xb4, 0x79, 0x16, 0x81, 0xbc, 0xee, 0xdd, 0xb3, 0xb7, 0x6c, 0xef, 0xf3, 0xe7, - 0xeb, 0xd4, 0xbb, 0x47, 0x87, 0xe0, 0xcb, 0xb1, 0x3f, 0xbd, 0x0e, 0x0c, 0x2e, 0x34, 0x7b, 0xfb, 0x54, 0xb0, 0x3d, - 0xdb, 0x3f, 0x45, 0xa4, 0xa2, 0xee, 0xfc, 0xc3, 0x6b, 0x13, 0x3d, 0xef, 0xbc, 0xb0, 0xe2, 0x4b, 0x00, 0x0f, 0x64, - 0x31, 0xa0, 0xf8, 0x2c, 0xbd, 0x7f, 0xb2, 0x04, 0xd4, 0xe4, 0x77, 0x7c, 0xe3, 0xbd, 0xa3, 0xd4, 0x05, 0xfc, 0x39, - 0xa0, 0xf4, 0x49, 0xc5, 0xbd, 0xd5, 0xf0, 0xce, 0xbf, 0x7a, 0x06, 0xce, 0x13, 0xeb, 0xe1, 0x02, 0xfe, 0x2a, 0xf8, - 0xd0, 0x5b, 0x0d, 0x30, 0xb1, 0xe4, 0x43, 0x6f, 0x3d, 0x80, 0x54, 0x85, 0x0b, 0x89, 0xb1, 0x0f, 0xbf, 0x06, 0x15, - 0xc3, 0x3f, 0x7e, 0xd3, 0x18, 0xac, 0xbf, 0x06, 0x85, 0x46, 0x63, 0x2d, 0x55, 0xc8, 0x52, 0x2c, 0x2e, 0x04, 0xd8, - 0x84, 0xe3, 0x6e, 0x5f, 0xac, 0x6a, 0xbb, 0x11, 0xf4, 0xe7, 0x23, 0xbe, 0x47, 0x63, 0x75, 0x55, 0xce, 0x45, 0xf9, - 0x11, 0xe9, 0x53, 0x1d, 0x1f, 0xa3, 0x62, 0x5b, 0x77, 0xa7, 0x53, 0xad, 0x3a, 0xd2, 0x7e, 0x53, 0xae, 0xc1, 0x8e, - 0xd7, 0xc9, 0x89, 0xa5, 0xf0, 0xa2, 0xc3, 0xce, 0x4b, 0xa7, 0x44, 0x87, 0x61, 0xbc, 0xdb, 0xaa, 0x67, 0x0c, 0xe5, - 0x95, 0xc1, 0x98, 0x2e, 0x78, 0xc4, 0x9f, 0x0f, 0x2a, 0x19, 0x1a, 0xf3, 0x01, 0xd9, 0x30, 0x94, 0x0f, 0x2d, 0x32, - 0x24, 0x44, 0xbc, 0x87, 0x4a, 0xc0, 0xb6, 0x05, 0x65, 0x52, 0xc0, 0x59, 0x34, 0xf8, 0xad, 0xf6, 0x2a, 0xe0, 0x3d, - 0x88, 0xfc, 0x46, 0xba, 0x94, 0x4b, 0x6c, 0x74, 0xe2, 0x58, 0x16, 0xda, 0x79, 0x5c, 0x7f, 0x1d, 0x83, 0xfa, 0xbd, - 0xd2, 0x6f, 0x50, 0xce, 0xfe, 0x28, 0x59, 0xa7, 0x8d, 0x27, 0xc6, 0xdf, 0x5d, 0xe5, 0x9f, 0xa2, 0xa5, 0x1e, 0xfe, - 0x3f, 0x63, 0x0a, 0xa5, 0x7f, 0x99, 0x96, 0xd1, 0x76, 0xbd, 0x14, 0xa5, 0xc8, 0x23, 0x71, 0xf6, 0xb5, 0xc8, 0xce, - 0xe5, 0x3b, 0x9f, 0x42, 0xbf, 0x00, 0xb4, 0xec, 0x13, 0x64, 0xf4, 0x0f, 0x4c, 0xf0, 0xe1, 0x0f, 0xda, 0xb9, 0xb6, - 0xe2, 0xe3, 0x49, 0x75, 0x63, 0xed, 0xdd, 0x8e, 0x17, 0x89, 0x51, 0x8c, 0x55, 0xbe, 0xea, 0x66, 0xe5, 0x44, 0x25, - 0x07, 0x46, 0xba, 0x26, 0x7b, 0x95, 0x92, 0x75, 0x3b, 0xdd, 0x4a, 0x20, 0xa2, 0x0a, 0xbc, 0xc7, 0xb8, 0x8a, 0x7d, - 0x04, 0xd3, 0x75, 0xc7, 0x65, 0xb4, 0xe3, 0x3d, 0xe3, 0xd5, 0x89, 0xb2, 0x82, 0xdb, 0x8d, 0x68, 0x4f, 0xe8, 0xe8, - 0xa7, 0x49, 0x6d, 0x59, 0x38, 0x00, 0xb9, 0x4b, 0x18, 0xcb, 0x86, 0x60, 0xc5, 0xa0, 0xf4, 0xf5, 0x9a, 0x92, 0x65, - 0x01, 0x16, 0x9d, 0x5d, 0x46, 0x20, 0x86, 0x75, 0xd3, 0x9c, 0xd1, 0xf1, 0xd2, 0xc5, 0xf9, 0xa0, 0x55, 0xa4, 0xe0, - 0x19, 0x2d, 0x3a, 0xe6, 0xa6, 0x23, 0xdd, 0x18, 0xed, 0xed, 0x0f, 0x06, 0x21, 0xc5, 0xf3, 0x07, 0xb6, 0x5a, 0x17, - 0x17, 0x89, 0x57, 0xc8, 0x44, 0x0b, 0x62, 0x29, 0x02, 0x33, 0x5e, 0x68, 0x1a, 0x61, 0x82, 0x32, 0x25, 0x58, 0xb4, - 0x46, 0x87, 0xf6, 0x87, 0x25, 0xec, 0x1e, 0x63, 0x04, 0x08, 0x54, 0x99, 0x3e, 0x87, 0xad, 0x09, 0xb3, 0xad, 0x8b, - 0x2d, 0xd0, 0x56, 0x31, 0x34, 0x08, 0x6b, 0x43, 0xcc, 0xc7, 0x34, 0x5f, 0xfd, 0x13, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, - 0xc1, 0xed, 0x9a, 0x84, 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xaa, 0x1d, 0x6b, - 0xa9, 0x77, 0xac, 0x8d, 0xde, 0xb1, 0x56, 0x0d, 0xff, 0x90, 0x79, 0x31, 0x4b, 0x40, 0xbf, 0xbb, 0xe6, 0xaa, 0x41, - 0xd0, 0x8c, 0x2d, 0xbb, 0x83, 0xdf, 0x12, 0x6b, 0xb7, 0xf4, 0xaf, 0x96, 0x6c, 0x61, 0xfa, 0x40, 0xb7, 0x0e, 0xb0, - 0x8c, 0xa8, 0xc9, 0xf7, 0xc8, 0xbb, 0xe9, 0xac, 0x28, 0xdc, 0x9e, 0xd8, 0xc2, 0x67, 0x6f, 0xcd, 0x9b, 0xf7, 0x4f, - 0x23, 0xc8, 0xbd, 0xe7, 0xde, 0xfd, 0xf0, 0xad, 0x7f, 0xa5, 0x5b, 0x20, 0x27, 0xb3, 0x9c, 0x81, 0xd4, 0x11, 0x9f, - 0x20, 0x5a, 0xd9, 0x53, 0xbe, 0x13, 0x72, 0x67, 0xdb, 0x3c, 0xbd, 0x77, 0xb7, 0xb5, 0xd5, 0xd3, 0x7b, 0x96, 0x8f, - 0x28, 0x56, 0x9c, 0xa6, 0x48, 0x98, 0x45, 0x5b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xfd, 0xd3, 0x8e, - 0x8e, 0x97, 0x73, 0xc0, 0xee, 0xfe, 0x93, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0xf7, 0x4f, 0x33, 0x8d, 0xe7, - 0x70, 0x22, 0x9f, 0x8e, 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, - 0xd6, 0x35, 0x6f, 0xaf, 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, - 0x70, 0xba, 0xe4, 0xb1, 0xef, 0xd3, 0x2c, 0xad, 0xf7, 0xa8, 0xb5, 0xc8, 0x2d, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, - 0x61, 0xa9, 0xe9, 0x9f, 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2d, 0xae, 0x7e, 0x38, 0x2f, 0x94, - 0x6b, 0x37, 0x6f, 0xe3, 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x4e, 0x94, - 0x5d, 0x2c, 0xe1, 0x1e, 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf5, 0x8c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, - 0x62, 0x5b, 0xb8, 0x7a, 0xc6, 0xb6, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0xad, 0x6a, 0x8e, - 0x35, 0xd4, 0x6c, 0x63, 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0x56, 0x6d, 0xc5, 0xc7, 0xda, 0x5a, 0x97, 0xee, 0xf5, - 0x1e, 0xd5, 0x05, 0xb0, 0xf5, 0xdf, 0x9d, 0xae, 0x5c, 0xcf, 0x67, 0x04, 0xf0, 0xb5, 0xe0, 0xe3, 0xc9, 0x02, 0xbd, - 0x4a, 0x16, 0xfe, 0xdd, 0x40, 0x8d, 0xbf, 0xd3, 0xb9, 0x0b, 0x80, 0xae, 0xa4, 0xbc, 0x02, 0xf2, 0x0e, 0x2a, 0xcc, - 0x2d, 0xbb, 0xf2, 0xfe, 0xec, 0x3b, 0xec, 0x2d, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x83, 0x53, 0x41, 0x32, 0xb0, 0x97, - 0x15, 0xdb, 0x07, 0xb1, 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x80, 0x20, 0xae, 0xe0, 0x0e, 0xe2, 0xf0, 0xe4, 0x9f, - 0x83, 0xfb, 0xd6, 0x66, 0x7d, 0xcf, 0xac, 0xce, 0x09, 0x36, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0xd6, 0xfd, 0xbe, - 0xb7, 0xd7, 0x8e, 0x4f, 0x2b, 0xa9, 0x13, 0x3b, 0xaf, 0xd5, 0x5a, 0xb0, 0xb7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x80, - 0x5f, 0x70, 0x37, 0xe0, 0xf7, 0x1d, 0x6b, 0xcb, 0x7b, 0xcb, 0x16, 0x6c, 0x0f, 0x97, 0xa0, 0xa6, 0xbd, 0xec, 0xcf, - 0x2a, 0x17, 0xb4, 0x63, 0x97, 0xc4, 0xc3, 0x19, 0xb3, 0x5c, 0x99, 0x59, 0x27, 0xf9, 0x8d, 0xe8, 0x8c, 0xe9, 0xac, - 0xf5, 0x7c, 0xce, 0xe7, 0x93, 0x42, 0x83, 0xfa, 0x5d, 0x12, 0x1f, 0x51, 0xd1, 0x79, 0x02, 0x5b, 0xcb, 0x0a, 0xc8, - 0xbd, 0x2e, 0xc1, 0x5a, 0xab, 0x5d, 0xfa, 0xbd, 0x6a, 0xc0, 0x6d, 0xca, 0x61, 0x4d, 0x40, 0xd0, 0x9c, 0x59, 0x51, - 0x8f, 0xd9, 0x8e, 0x71, 0xf3, 0xd3, 0xcb, 0x1f, 0x9c, 0xb0, 0x64, 0xc5, 0x6a, 0x7f, 0xfa, 0xc3, 0x53, 0x4f, 0x7f, - 0xa7, 0xf6, 0xaf, 0x84, 0x1f, 0x8c, 0xff, 0x5d, 0xbb, 0xaf, 0xb5, 0x18, 0x95, 0xad, 0x72, 0x84, 0xc6, 0xdd, 0x4a, - 0x9a, 0x2c, 0x3f, 0x09, 0x4f, 0x58, 0x0b, 0x9e, 0x99, 0x33, 0x20, 0x2b, 0x60, 0x85, 0xb5, 0x4c, 0xc2, 0x39, 0xc6, - 0x6a, 0x69, 0xab, 0x6f, 0xd1, 0x34, 0xa7, 0x87, 0x73, 0x6d, 0x50, 0xa6, 0x9c, 0x9d, 0x11, 0xab, 0xe1, 0x32, 0x2c, - 0x4d, 0x28, 0x42, 0xf6, 0x60, 0x07, 0x37, 0x76, 0xca, 0x52, 0xca, 0x70, 0x8e, 0xc1, 0x84, 0x27, 0x62, 0x54, 0xee, - 0xfb, 0x87, 0x92, 0x57, 0x6d, 0x39, 0x28, 0x47, 0xd8, 0x47, 0x12, 0x25, 0x70, 0x2b, 0xd2, 0x42, 0x91, 0xb2, 0xf8, - 0xdb, 0x01, 0xba, 0xc0, 0x0b, 0xa8, 0xab, 0x51, 0xb7, 0x3f, 0x1c, 0xf1, 0xf0, 0x91, 0xa9, 0x0f, 0x8c, 0x58, 0x12, - 0xa8, 0xed, 0x45, 0x96, 0xae, 0x40, 0x85, 0xdf, 0xc3, 0xd5, 0x44, 0xec, 0xe7, 0x96, 0x14, 0x15, 0xd9, 0x48, 0x6f, - 0x68, 0x0d, 0x1e, 0xa1, 0x35, 0xe5, 0x07, 0x27, 0xd5, 0x26, 0x9d, 0x77, 0x84, 0x1c, 0xab, 0x6f, 0x2d, 0x61, 0xb4, - 0x2b, 0x7a, 0xf1, 0xe0, 0xe8, 0x3d, 0xcf, 0x57, 0xbd, 0xf2, 0x27, 0xae, 0x98, 0x27, 0xb7, 0x11, 0xa8, 0x5b, 0x41, - 0x75, 0x7b, 0xaf, 0x12, 0x2c, 0x58, 0xd2, 0xee, 0xe3, 0xb7, 0xb3, 0x76, 0x20, 0x2a, 0x63, 0x95, 0xbe, 0x26, 0x09, - 0x7b, 0x62, 0xd0, 0x29, 0x54, 0x55, 0x76, 0x77, 0xb4, 0x05, 0xae, 0x53, 0x96, 0xa2, 0x17, 0xb6, 0xc8, 0xdd, 0xf2, - 0xef, 0x9e, 0x2b, 0x72, 0xf6, 0x6b, 0x40, 0x70, 0x6a, 0xbe, 0x22, 0xbe, 0x9c, 0xe0, 0x51, 0x75, 0x0b, 0x1c, 0xe7, - 0xef, 0x00, 0xfe, 0xf1, 0x78, 0x0d, 0x9a, 0x80, 0x58, 0xb0, 0x5e, 0x1a, 0xf7, 0x58, 0x2f, 0x2e, 0xb6, 0xab, 0x24, - 0xdf, 0x82, 0x33, 0x03, 0xa5, 0x5a, 0xfa, 0x81, 0x53, 0xb5, 0x80, 0x0a, 0x07, 0xb3, 0x93, 0x7a, 0x61, 0x19, 0xf5, - 0x98, 0x3e, 0x3f, 0x83, 0x83, 0x23, 0x24, 0x00, 0xee, 0x97, 0x7d, 0x40, 0x02, 0x1e, 0x3a, 0xb3, 0x03, 0xc2, 0x09, - 0xb3, 0xa8, 0x0a, 0x24, 0x92, 0x23, 0xfd, 0xec, 0x31, 0x13, 0xc9, 0x1f, 0xcc, 0x7a, 0xce, 0x29, 0xd1, 0x63, 0x3d, - 0x75, 0x84, 0xf4, 0x58, 0xcf, 0x3a, 0x22, 0x7a, 0xac, 0x67, 0x1d, 0x1f, 0x3d, 0xd6, 0x33, 0xc7, 0x4e, 0x0f, 0x02, - 0x13, 0x20, 0xf2, 0x80, 0xf5, 0x68, 0x32, 0xf5, 0x14, 0xf7, 0x00, 0xd1, 0x20, 0xb0, 0x9e, 0x14, 0xce, 0x7b, 0x80, - 0x3c, 0x46, 0x62, 0x75, 0xd0, 0xfb, 0x8f, 0xf1, 0x77, 0x3d, 0x23, 0x23, 0x8f, 0x5b, 0x87, 0xd5, 0xff, 0xfa, 0x4f, - 0x08, 0x80, 0xc3, 0xb3, 0xa9, 0x77, 0x3d, 0x86, 0xac, 0xb2, 0x8c, 0x40, 0xf2, 0x13, 0x83, 0x2f, 0x5f, 0x00, 0x54, - 0x7d, 0xa6, 0x6b, 0x35, 0x39, 0x6a, 0x8f, 0x39, 0x74, 0xc5, 0x00, 0xb0, 0x0d, 0x4b, 0x54, 0xd5, 0xc2, 0x26, 0x2c, - 0x6e, 0x3f, 0xc3, 0x68, 0x2e, 0x9b, 0x5e, 0xd0, 0x40, 0x3d, 0x42, 0xf0, 0x4b, 0xeb, 0xa1, 0xb5, 0x96, 0x29, 0x87, - 0xae, 0x8d, 0xa2, 0xca, 0x86, 0xba, 0x84, 0xd5, 0x46, 0x44, 0x35, 0x51, 0xa4, 0x5c, 0x33, 0x8a, 0x62, 0xa9, 0x82, - 0x43, 0x26, 0x56, 0x10, 0x35, 0x4f, 0x5b, 0x6d, 0x15, 0x1c, 0x56, 0x80, 0xb0, 0x16, 0xd6, 0x42, 0x3a, 0x83, 0xda, - 0x3b, 0xfd, 0x48, 0xf9, 0xcb, 0x0b, 0xb9, 0x9d, 0x5b, 0x28, 0xc2, 0xed, 0x39, 0x28, 0x6f, 0xea, 0xaa, 0x54, 0x44, - 0xa3, 0x25, 0x50, 0xca, 0x8a, 0x20, 0xb2, 0x00, 0x01, 0x1c, 0x37, 0x10, 0xf8, 0xbc, 0xc6, 0x27, 0xd0, 0x28, 0x04, - 0xf2, 0x03, 0xeb, 0x70, 0xe3, 0x21, 0x2d, 0xb5, 0x46, 0x44, 0x89, 0xf8, 0xc9, 0xd5, 0x73, 0x6c, 0x5f, 0x3d, 0x8d, - 0xb5, 0xa5, 0x34, 0x41, 0xfc, 0xc4, 0x62, 0x0b, 0x31, 0x41, 0x54, 0x87, 0xe8, 0x04, 0x96, 0x13, 0x42, 0x14, 0xfe, - 0x10, 0xfa, 0xa9, 0x81, 0xbf, 0x64, 0xcb, 0x22, 0xaf, 0x09, 0x16, 0x33, 0x67, 0x80, 0x56, 0x45, 0xe0, 0x99, 0xce, - 0x96, 0xca, 0x9c, 0xe6, 0xd1, 0x91, 0x1d, 0x5c, 0x76, 0x1d, 0xec, 0xa5, 0x2f, 0x63, 0x27, 0xcb, 0xa6, 0x51, 0x1b, - 0x1b, 0x22, 0xe1, 0x15, 0xf9, 0xcb, 0x2c, 0x35, 0xce, 0x91, 0x6a, 0x7d, 0xd7, 0xc5, 0x6a, 0x45, 0xdb, 0x84, 0x55, - 0x88, 0x50, 0xb7, 0x0d, 0x95, 0x4b, 0x61, 0x36, 0x36, 0x4d, 0x03, 0x7c, 0xa1, 0xa8, 0x54, 0xca, 0x53, 0x5b, 0xa9, - 0xe4, 0x84, 0x77, 0x7d, 0x55, 0x8b, 0xd4, 0x15, 0xc1, 0x36, 0x66, 0xa8, 0x87, 0x72, 0xa3, 0xc6, 0xbe, 0xee, 0x58, - 0xa5, 0x77, 0x98, 0xa0, 0x62, 0xe4, 0x45, 0x0e, 0x2e, 0x4a, 0x0a, 0x32, 0x57, 0x43, 0x98, 0x3f, 0x6a, 0xf8, 0xb4, - 0xb0, 0xdc, 0x43, 0x09, 0x98, 0x1d, 0x35, 0xbc, 0x8c, 0x10, 0x88, 0xb8, 0x54, 0xf6, 0x15, 0x13, 0xbf, 0xa7, 0x60, - 0x96, 0x4c, 0xe8, 0x5e, 0xc4, 0xc2, 0x08, 0x6d, 0x7c, 0x92, 0x24, 0x53, 0xb9, 0x3e, 0x41, 0x17, 0x2a, 0x5c, 0x20, - 0x23, 0xb4, 0x48, 0xf3, 0x4f, 0x87, 0x53, 0x09, 0x3e, 0xa2, 0x4e, 0x01, 0xc7, 0xf3, 0xcb, 0xc2, 0xfa, 0xc9, 0x2a, - 0x89, 0xb9, 0xac, 0xcd, 0x7f, 0xd9, 0xc9, 0x31, 0xd8, 0xe5, 0x69, 0xe2, 0xb8, 0xfa, 0x8f, 0xaa, 0xa4, 0x78, 0xf8, - 0x39, 0xcd, 0x01, 0x45, 0x30, 0xb3, 0xa7, 0x18, 0x1f, 0xfb, 0x2c, 0x53, 0xc0, 0xdf, 0xae, 0xb7, 0x96, 0x4c, 0xec, - 0x92, 0x76, 0x2b, 0x65, 0xfc, 0x52, 0x1b, 0x76, 0x1c, 0x5c, 0x1a, 0x80, 0xe2, 0xac, 0xd1, 0x61, 0x79, 0xad, 0xdb, - 0x56, 0x8e, 0x0a, 0xd4, 0xfa, 0xdf, 0xbb, 0x85, 0x29, 0x6f, 0xf3, 0x52, 0x79, 0x9b, 0x87, 0x26, 0x40, 0x20, 0x32, - 0x43, 0x9e, 0x35, 0x1d, 0x93, 0xc4, 0xbd, 0x23, 0x25, 0xed, 0x3b, 0x52, 0xfc, 0xe8, 0x1d, 0x09, 0xf9, 0x96, 0xd0, - 0x91, 0x7d, 0xc9, 0xc9, 0x09, 0x94, 0x19, 0xec, 0xe5, 0x0d, 0x93, 0xfd, 0x03, 0xda, 0x0b, 0xe7, 0xb2, 0xbc, 0xe6, - 0x6f, 0x85, 0xb7, 0xf1, 0xa7, 0x9b, 0xf3, 0xae, 0xaa, 0x77, 0x5f, 0x99, 0x99, 0xc7, 0x63, 0x71, 0x3c, 0xe6, 0x26, - 0x68, 0x77, 0xc1, 0xc5, 0xa0, 0x62, 0xf7, 0x6e, 0x7c, 0xfc, 0x5b, 0x8e, 0x22, 0xb6, 0x52, 0x1e, 0x49, 0x17, 0x2a, - 0x31, 0xbc, 0x36, 0xf0, 0x30, 0x7b, 0x3e, 0x9e, 0xec, 0x6f, 0xee, 0x27, 0x83, 0xc1, 0x5e, 0xf5, 0xed, 0x8e, 0xd7, - 0xb3, 0xfd, 0x9c, 0x3d, 0xf0, 0xbb, 0xe9, 0x2e, 0x38, 0x34, 0xb0, 0xed, 0xee, 0x6f, 0xc4, 0xf1, 0xb8, 0x7f, 0xce, - 0x17, 0xfe, 0xe1, 0x01, 0x01, 0x9d, 0xf9, 0xe5, 0xb8, 0x8d, 0xf1, 0x73, 0xdb, 0x76, 0xd5, 0xda, 0x03, 0x3c, 0xfd, - 0x8f, 0xde, 0xed, 0x6c, 0x39, 0xf7, 0xd9, 0x13, 0xfe, 0x00, 0xfe, 0xf9, 0xb8, 0x49, 0x22, 0xf5, 0x89, 0x76, 0x99, - 0xbc, 0x05, 0x07, 0xf2, 0xbd, 0xcf, 0xde, 0xf0, 0x87, 0xd9, 0x72, 0xce, 0x8b, 0xe3, 0xf1, 0xfd, 0x34, 0x44, 0xb2, - 0xa6, 0xb0, 0x22, 0x96, 0x14, 0xcf, 0x0f, 0xc2, 0xd3, 0xf7, 0x22, 0x32, 0x44, 0x5a, 0xee, 0xdd, 0x21, 0xbb, 0x65, - 0x91, 0x1f, 0xc0, 0x07, 0xd9, 0xde, 0x9f, 0xc8, 0x9a, 0xd2, 0xfd, 0xe2, 0x89, 0x7f, 0x3c, 0xd2, 0x5f, 0x6f, 0xfc, - 0xe3, 0xf1, 0x3d, 0x7b, 0x40, 0x70, 0x74, 0xbe, 0x87, 0xfe, 0xd1, 0xb7, 0x0e, 0xa8, 0xca, 0xf0, 0xed, 0x6c, 0x3b, - 0xf7, 0x9f, 0xaf, 0xd9, 0x0a, 0xb8, 0x50, 0x94, 0x17, 0xda, 0x2d, 0x7b, 0x40, 0xaf, 0x33, 0x72, 0x22, 0x9a, 0xed, - 0xe7, 0x3e, 0x8b, 0xf1, 0xb9, 0xba, 0x2f, 0x26, 0x5f, 0xbd, 0x2f, 0xee, 0xd9, 0xae, 0xfb, 0xbe, 0x28, 0xdf, 0x74, - 0xd7, 0xcf, 0x8e, 0xed, 0xd9, 0x03, 0xcc, 0xb0, 0xb7, 0xfc, 0xb6, 0x39, 0x75, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, - 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0xb9, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x97, 0xde, - 0xa2, 0xd4, 0x45, 0x4f, 0xfb, 0x14, 0xe4, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x7c, - 0xa6, 0x1d, 0x3d, 0xaf, 0xbf, 0xed, 0x3d, 0x93, 0xdf, 0xc8, 0xc0, 0x16, 0x22, 0x29, 0x1c, 0xc7, 0x57, 0xcf, 0xce, - 0xf8, 0xaf, 0x5a, 0x1e, 0xb5, 0xda, 0x2f, 0x94, 0xfa, 0xf4, 0x25, 0x1d, 0xd1, 0xc4, 0xbd, 0x68, 0xcb, 0xb0, 0x46, - 0x59, 0x53, 0x4b, 0x87, 0x61, 0x5c, 0xc3, 0xbe, 0x3c, 0x70, 0xe8, 0x3b, 0x20, 0xd0, 0xe6, 0xa9, 0x14, 0x68, 0xe1, - 0x18, 0x46, 0x61, 0x16, 0x52, 0x1e, 0x17, 0x66, 0x29, 0xef, 0xa9, 0x40, 0x8b, 0x5b, 0x75, 0x8f, 0xa9, 0xed, 0x16, - 0x44, 0x58, 0xbd, 0x65, 0x5c, 0x5e, 0x37, 0xaa, 0x70, 0x5b, 0x80, 0xa2, 0x08, 0xca, 0xe0, 0x40, 0x72, 0xdb, 0x42, - 0x49, 0xb3, 0x51, 0x58, 0x8b, 0x55, 0x51, 0xee, 0x7b, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, - 0x75, 0x28, 0x17, 0xe9, 0xbf, 0x65, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xfb, 0x97, - 0xf4, 0xb3, 0xc1, 0x32, 0x72, 0x4a, 0xfd, 0x10, 0x8d, 0xee, 0xd2, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, - 0x0a, 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, - 0x26, 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, - 0x90, 0xdc, 0xa9, 0x73, 0x7f, 0x54, 0x4e, 0xfe, 0x1d, 0x0d, 0x91, 0x57, 0xdc, 0x20, 0x56, 0x16, 0x5c, 0x62, 0x31, - 0x54, 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xc7, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, - 0x13, 0x3e, 0x6e, 0xad, 0x45, 0x88, 0x3a, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, - 0x14, 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xc8, 0x49, 0xcf, 0x5f, 0x9a, 0x14, 0x65, - 0xcc, 0xf8, 0x20, 0xca, 0x48, 0xe4, 0x75, 0xb8, 0x12, 0xd3, 0x02, 0xf9, 0x46, 0x4f, 0x1f, 0x04, 0xd7, 0xf0, 0x6e, - 0xc8, 0xbd, 0x02, 0x6c, 0x09, 0xd8, 0x01, 0xee, 0x95, 0x19, 0xe5, 0x3a, 0xad, 0xeb, 0xb7, 0xd6, 0x43, 0x31, 0x0c, - 0x9f, 0x5a, 0x02, 0xdb, 0xc9, 0x3a, 0x3a, 0xd1, 0xc3, 0x87, 0xff, 0x75, 0x55, 0x73, 0xd4, 0xa9, 0x5c, 0xce, 0x4e, - 0x27, 0x2c, 0x45, 0xcc, 0xa0, 0xfb, 0xeb, 0xee, 0xa5, 0x00, 0xba, 0x5d, 0x16, 0xf3, 0x6c, 0xb4, 0x97, 0x7f, 0x4b, - 0x37, 0x56, 0x94, 0x36, 0xf1, 0x2e, 0xeb, 0x8d, 0xfd, 0xe1, 0xe8, 0x3f, 0x9e, 0xbe, 0x9b, 0x10, 0xaa, 0xce, 0x96, - 0x6d, 0x74, 0x9c, 0xcb, 0xff, 0xfa, 0xcf, 0x31, 0x59, 0x41, 0x50, 0x10, 0x96, 0x9d, 0x62, 0xa2, 0x82, 0x51, 0xa4, - 0xd8, 0xf0, 0xf1, 0x64, 0x83, 0x3a, 0xe1, 0x8d, 0xbf, 0xd4, 0x3a, 0x61, 0x62, 0x64, 0xa5, 0xf2, 0x37, 0x2c, 0x67, - 0x2b, 0x95, 0x59, 0x40, 0xe6, 0x41, 0x35, 0xd9, 0x18, 0x0d, 0xe6, 0x9a, 0xd7, 0xb3, 0xcd, 0x5c, 0x2a, 0x9f, 0xc1, - 0x94, 0xb3, 0x1c, 0x9c, 0x2d, 0x85, 0xdd, 0x93, 0x40, 0xd1, 0x9a, 0xa1, 0x1b, 0x7f, 0x8a, 0xad, 0x7a, 0x95, 0x56, - 0x35, 0xc0, 0x03, 0x42, 0x0c, 0x0c, 0xb5, 0x57, 0x0b, 0x0f, 0xad, 0x05, 0xb0, 0xf1, 0x47, 0xa5, 0x1f, 0x8c, 0x27, - 0x4b, 0xbe, 0x40, 0xfe, 0xe5, 0xc8, 0x51, 0xbb, 0xf7, 0xfb, 0xde, 0x3d, 0x48, 0xc1, 0x91, 0x6b, 0xa1, 0x40, 0x22, - 0xa0, 0x05, 0xdf, 0xfa, 0xca, 0x07, 0xe3, 0x2d, 0x6a, 0xab, 0x41, 0x41, 0xed, 0xe8, 0x96, 0xc7, 0x8e, 0xde, 0xf9, - 0xfe, 0x8c, 0xbe, 0x7a, 0xa1, 0x85, 0xe3, 0xaf, 0x9c, 0x91, 0x1b, 0xb6, 0xee, 0x90, 0x23, 0x9a, 0x49, 0x87, 0x10, - 0xb1, 0x66, 0x1b, 0xf6, 0x96, 0x54, 0xce, 0x9d, 0x43, 0x76, 0xfe, 0x08, 0x55, 0x7a, 0xad, 0xc7, 0xb7, 0x13, 0xa5, - 0xbb, 0x3d, 0xdd, 0x4d, 0xbe, 0x65, 0x13, 0x11, 0x83, 0x01, 0x6d, 0x10, 0xce, 0xc8, 0x3a, 0x44, 0x2a, 0x1d, 0x20, - 0x04, 0x8e, 0x09, 0x68, 0xfa, 0xf7, 0xaf, 0x49, 0x14, 0x70, 0xa4, 0x8d, 0x90, 0xb5, 0xec, 0x78, 0xac, 0x40, 0xa3, - 0xdc, 0xfc, 0xe1, 0x15, 0xea, 0x34, 0x07, 0xe6, 0xe9, 0x12, 0xf6, 0x1c, 0x3c, 0xd2, 0x8b, 0xd3, 0x23, 0xfd, 0xbf, - 0xa3, 0x89, 0x1a, 0xff, 0xfb, 0x9a, 0x28, 0xa5, 0x45, 0x72, 0x54, 0x4b, 0xdf, 0xa4, 0x8e, 0x82, 0x8b, 0xbc, 0xa3, - 0x16, 0xb2, 0x67, 0xd9, 0xb8, 0x51, 0xcd, 0xfb, 0xff, 0xb5, 0x32, 0xff, 0x5f, 0xd3, 0xca, 0x30, 0x25, 0x3b, 0x96, - 0x6a, 0xe6, 0x81, 0x56, 0x31, 0xcc, 0x7e, 0x26, 0x09, 0x91, 0xe1, 0xd2, 0x80, 0x1f, 0x55, 0x70, 0x88, 0xd3, 0x6a, - 0x93, 0x85, 0x7b, 0x54, 0xa2, 0xde, 0x89, 0x55, 0x9a, 0xbf, 0xa8, 0xff, 0x25, 0xca, 0x02, 0xa6, 0xf6, 0xaa, 0x4c, - 0xe3, 0x80, 0x2c, 0xfc, 0x59, 0x58, 0xe2, 0xe4, 0xc6, 0x36, 0xfe, 0x2c, 0xc7, 0xd3, 0x7e, 0xd5, 0x99, 0x79, 0x20, - 0x81, 0x1a, 0x88, 0x3f, 0x72, 0x2e, 0x2b, 0x8b, 0x07, 0x84, 0x6e, 0xfe, 0xb1, 0x2c, 0x8b, 0xd2, 0xeb, 0x7d, 0x4a, - 0xd2, 0xea, 0x62, 0x2d, 0xea, 0xa4, 0x88, 0x15, 0x94, 0x4d, 0x0a, 0x30, 0xfa, 0xb0, 0xf2, 0x44, 0x1c, 0x5c, 0x20, - 0x50, 0xc3, 0x45, 0x9d, 0x84, 0x00, 0x34, 0xac, 0x10, 0xf6, 0x2f, 0xa0, 0x85, 0x17, 0x61, 0x1c, 0x6e, 0x00, 0x26, - 0x27, 0xad, 0x2e, 0x36, 0x65, 0x71, 0x9f, 0xc6, 0x22, 0x1e, 0xf5, 0x14, 0x25, 0xcb, 0xc7, 0xca, 0x95, 0x73, 0xfd, - 0xc3, 0x1f, 0x14, 0xc0, 0x6e, 0xc0, 0x6c, 0x5b, 0x60, 0x07, 0x00, 0x09, 0x0a, 0x64, 0x0b, 0x75, 0x1a, 0x5d, 0xa8, - 0xa5, 0x02, 0xef, 0xb9, 0x1e, 0xe0, 0x1f, 0x2b, 0xc0, 0x32, 0xae, 0x0b, 0x19, 0x30, 0x82, 0x00, 0x46, 0xe0, 0xa0, - 0x04, 0x0c, 0x9d, 0x61, 0x6d, 0xf1, 0xb8, 0x43, 0x73, 0xa5, 0xdb, 0x92, 0x9b, 0x46, 0x39, 0x5b, 0x89, 0x00, 0xfa, - 0xea, 0xa6, 0xc4, 0xe9, 0x72, 0xd9, 0x4a, 0xc2, 0xbe, 0x7d, 0xdf, 0x4e, 0x15, 0x79, 0x7c, 0x92, 0x86, 0xbc, 0x02, - 0x4f, 0x32, 0x8e, 0x24, 0x51, 0x22, 0xf8, 0x58, 0x35, 0x66, 0x1c, 0x5e, 0xb4, 0x29, 0xa7, 0x0e, 0x66, 0xbd, 0x00, - 0x9c, 0x27, 0x68, 0xcb, 0x00, 0x63, 0x01, 0x83, 0x73, 0x21, 0x96, 0x3c, 0x45, 0xf0, 0x4b, 0x27, 0x52, 0x18, 0x77, - 0x39, 0x0c, 0xf3, 0xa0, 0xe8, 0x5d, 0x52, 0x7f, 0xf4, 0xfb, 0xa8, 0x4d, 0x06, 0x43, 0x50, 0x09, 0xa0, 0xb2, 0x6e, - 0x90, 0x18, 0x58, 0x95, 0x16, 0x12, 0x97, 0x10, 0x2f, 0xf3, 0xd5, 0xb4, 0x8e, 0x82, 0xf7, 0xf5, 0x84, 0x10, 0x4e, - 0x30, 0x3e, 0xc4, 0x0d, 0x10, 0x30, 0x58, 0xc5, 0x05, 0x06, 0xc9, 0x73, 0x89, 0xee, 0x8f, 0xe7, 0x3b, 0x06, 0xb8, - 0x72, 0xde, 0x53, 0xed, 0xea, 0x81, 0xbd, 0x5c, 0xa5, 0x4b, 0x46, 0x08, 0x2b, 0xfe, 0x2f, 0x22, 0xef, 0xdb, 0x61, - 0x02, 0x6a, 0x1b, 0xf9, 0x63, 0x90, 0x98, 0xcb, 0x44, 0x11, 0xc4, 0xa3, 0xac, 0x60, 0x49, 0x1a, 0x6c, 0x47, 0x49, - 0x0a, 0x1a, 0x4d, 0x8c, 0x21, 0x53, 0xa1, 0x1d, 0x92, 0x46, 0xb3, 0x31, 0xd9, 0xc7, 0x90, 0xd7, 0x70, 0xb1, 0x58, - 0xe0, 0x7d, 0x3f, 0x0b, 0xd5, 0xc1, 0xb6, 0x34, 0x87, 0x80, 0x93, 0x04, 0x7b, 0xea, 0x8a, 0x94, 0x84, 0xd9, 0xe8, - 0x53, 0xc8, 0xb9, 0x01, 0x1d, 0x27, 0x8d, 0xa1, 0xfa, 0xc0, 0x24, 0xbc, 0x89, 0xd0, 0x49, 0x59, 0x21, 0x2c, 0xe0, - 0xbe, 0x91, 0xd1, 0x68, 0x25, 0x0d, 0x02, 0x6f, 0x33, 0x6c, 0x05, 0x36, 0xa1, 0xe1, 0x2f, 0x32, 0x0f, 0xd3, 0x6a, - 0x56, 0x82, 0x39, 0xdf, 0x40, 0x25, 0xc6, 0x93, 0xe5, 0x0d, 0xdf, 0xba, 0x58, 0x89, 0xc9, 0x6c, 0x39, 0x9f, 0x6c, - 0x24, 0xd5, 0x1c, 0x08, 0x19, 0x19, 0x5b, 0xc2, 0xfe, 0x61, 0x60, 0x28, 0x1d, 0xd8, 0xd1, 0x54, 0xd3, 0x26, 0x01, - 0x26, 0xd3, 0x25, 0xe7, 0xc3, 0x6b, 0x44, 0x93, 0xd5, 0xa9, 0x7b, 0x99, 0xaa, 0x76, 0x70, 0x4d, 0xce, 0xe4, 0xf4, - 0x48, 0x3d, 0xd5, 0xba, 0x97, 0x6a, 0xb4, 0x1b, 0xe6, 0xa3, 0x9d, 0x1f, 0x80, 0x5b, 0xa7, 0xb0, 0xd3, 0xf7, 0xc3, - 0x7c, 0xb4, 0xf7, 0x35, 0xec, 0x2e, 0x29, 0x04, 0xaa, 0x3f, 0xcb, 0x9a, 0xcc, 0xc5, 0x9b, 0xe2, 0xc1, 0x2b, 0xd8, - 0x33, 0x7f, 0xa0, 0x7f, 0x95, 0xec, 0x99, 0x6f, 0x33, 0xb9, 0xfe, 0x99, 0x76, 0x8d, 0xc6, 0x4c, 0xc7, 0x6b, 0xe7, - 0x60, 0x85, 0x06, 0xc8, 0x2f, 0xd8, 0xd1, 0xde, 0xe4, 0x20, 0x10, 0xa0, 0x7b, 0x09, 0x8e, 0xa2, 0x80, 0xa8, 0x69, - 0x55, 0x79, 0x74, 0xba, 0xf7, 0x0f, 0xf8, 0x46, 0x09, 0xd8, 0xe4, 0xa9, 0x75, 0x6f, 0x19, 0xfb, 0xc7, 0x23, 0x84, - 0xd0, 0xcb, 0xe9, 0x37, 0xda, 0xb1, 0x7a, 0xb4, 0x67, 0x12, 0xfc, 0x1c, 0x31, 0xe9, 0x15, 0x8c, 0x61, 0xe8, 0xc2, - 0x2a, 0x46, 0xf2, 0x0c, 0xc8, 0x1a, 0xbf, 0x41, 0x74, 0x01, 0x8b, 0x5e, 0xef, 0xd5, 0x09, 0x0d, 0x22, 0xa0, 0xd2, - 0x6b, 0xfe, 0x52, 0xe4, 0x73, 0x55, 0x88, 0xde, 0x07, 0x6b, 0xe7, 0xcd, 0x8c, 0x64, 0x99, 0x34, 0x52, 0xed, 0x56, - 0x16, 0x9b, 0xca, 0x9b, 0x9d, 0x91, 0x2e, 0xe6, 0x18, 0x2a, 0x83, 0xc7, 0x01, 0x28, 0x3d, 0xff, 0x12, 0x7a, 0x25, - 0x43, 0xa6, 0x59, 0xa2, 0x99, 0xdd, 0x37, 0xfe, 0x64, 0x9d, 0x7a, 0x31, 0x22, 0x66, 0x03, 0x5b, 0x88, 0xdb, 0xa2, - 0xd2, 0x6d, 0x51, 0x28, 0x5b, 0x14, 0xe9, 0x43, 0xed, 0x42, 0x77, 0x66, 0xe1, 0xb3, 0xdc, 0xb4, 0xef, 0x4d, 0x66, - 0xc6, 0x06, 0x68, 0xbb, 0x08, 0xdf, 0x40, 0x07, 0x2a, 0x84, 0xfc, 0x47, 0x44, 0x44, 0x22, 0x60, 0x97, 0x73, 0x77, - 0x62, 0xd3, 0x21, 0x99, 0x87, 0x98, 0x15, 0x6a, 0x94, 0x97, 0x3c, 0x39, 0x19, 0x90, 0x9c, 0x50, 0xb7, 0xfb, 0xfd, - 0xcb, 0xa5, 0x0b, 0x6a, 0xbf, 0xa1, 0xd8, 0x31, 0xba, 0x29, 0xe0, 0x5c, 0xf0, 0x28, 0xef, 0xa5, 0x77, 0x09, 0x68, - 0x8e, 0xed, 0x29, 0xb2, 0x01, 0x9c, 0xde, 0x76, 0x21, 0xc0, 0xf6, 0x59, 0xb3, 0x8d, 0x3f, 0x59, 0xdf, 0x44, 0x53, - 0xaf, 0xe4, 0x33, 0xdd, 0x45, 0x89, 0xdb, 0x45, 0xb1, 0xec, 0xa2, 0x6d, 0x03, 0xc1, 0x8e, 0x6b, 0x3f, 0x00, 0xde, - 0xd0, 0xa8, 0xdf, 0x2f, 0x5b, 0x3d, 0x7b, 0xf6, 0xb5, 0xd3, 0x9e, 0xcd, 0x7c, 0x56, 0x9a, 0x9e, 0xfd, 0x35, 0x75, - 0x7b, 0x56, 0x4e, 0xf6, 0xa2, 0x73, 0xb2, 0x4f, 0x67, 0xf3, 0x40, 0x70, 0xb9, 0x73, 0x5f, 0x56, 0x53, 0x3d, 0xed, - 0x72, 0x3f, 0x68, 0x0d, 0x91, 0xf9, 0xc2, 0xa7, 0xbc, 0x7b, 0x5d, 0xc1, 0x02, 0x96, 0xe0, 0x6e, 0xbd, 0x34, 0xff, - 0x15, 0xbb, 0xbf, 0x17, 0xf4, 0xd2, 0xfc, 0x37, 0xfa, 0x93, 0x02, 0x38, 0x00, 0x8d, 0xa9, 0xdd, 0x02, 0x0f, 0x31, - 0x54, 0x50, 0xb8, 0x9b, 0x95, 0x73, 0xaf, 0x06, 0x38, 0x4c, 0xd2, 0x37, 0xb4, 0x7a, 0xa5, 0xc5, 0xae, 0x97, 0xc9, - 0x5e, 0x01, 0x1e, 0xaa, 0x90, 0x87, 0xc7, 0x63, 0xd4, 0x31, 0xec, 0xa0, 0x8e, 0x80, 0x61, 0x0f, 0xa1, 0xb1, 0x05, - 0x9e, 0x8f, 0x9f, 0x32, 0x7e, 0x10, 0xa0, 0x36, 0x42, 0x78, 0xbc, 0x5a, 0x94, 0x21, 0xb6, 0xec, 0x0d, 0x52, 0x49, - 0xfd, 0x2c, 0x10, 0x65, 0xb4, 0x0a, 0x68, 0xab, 0x3d, 0x65, 0x69, 0xbc, 0x85, 0x50, 0xb1, 0xd4, 0xc7, 0x10, 0x1a, - 0x38, 0xfc, 0x8e, 0x47, 0x90, 0xe0, 0x4b, 0xae, 0xc9, 0xe6, 0xde, 0xe4, 0xf7, 0xb4, 0xcf, 0x1f, 0x8f, 0x97, 0xd7, - 0x08, 0x4a, 0x97, 0xc2, 0x47, 0x2a, 0x11, 0xd5, 0x53, 0xdc, 0x94, 0x90, 0xcd, 0x92, 0x95, 0x7e, 0xf0, 0xab, 0xfa, - 0x05, 0x00, 0xb2, 0x10, 0x68, 0x13, 0x99, 0xfd, 0xe9, 0x42, 0x45, 0x17, 0x00, 0x87, 0xf8, 0xe3, 0x27, 0x88, 0xbe, - 0xa1, 0x65, 0x5a, 0x3e, 0x4e, 0x78, 0x08, 0x5a, 0x5b, 0xd2, 0x49, 0xc4, 0x4a, 0x81, 0x0d, 0x91, 0xf0, 0xfd, 0xfe, - 0x65, 0x2c, 0xe9, 0x40, 0xa3, 0x56, 0xf7, 0xc6, 0xad, 0xee, 0x95, 0xaf, 0xeb, 0x4e, 0x6e, 0x7c, 0x50, 0xb4, 0xcf, - 0xe6, 0x8d, 0xca, 0xf7, 0x6d, 0x9d, 0xb3, 0x3f, 0xdf, 0x3b, 0x72, 0x4e, 0x7c, 0x7b, 0x0f, 0xa1, 0xe8, 0xa1, 0x29, - 0xb2, 0x2c, 0x09, 0x03, 0x5a, 0x6b, 0xd7, 0x9e, 0x65, 0x74, 0xf0, 0xda, 0x37, 0x84, 0x88, 0x3c, 0xc5, 0x27, 0x21, - 0xb7, 0x38, 0x3e, 0x28, 0xd0, 0x3f, 0x33, 0xfe, 0xcc, 0x89, 0x1f, 0xb6, 0xfa, 0x05, 0x70, 0x6e, 0xba, 0xf7, 0xee, - 0xc4, 0xac, 0xc7, 0x50, 0xca, 0xc6, 0xff, 0xfd, 0x3e, 0x91, 0x05, 0x3a, 0x1d, 0xd1, 0x30, 0x10, 0xdc, 0x45, 0xf5, - 0x7f, 0xaf, 0x78, 0xdd, 0xb3, 0x56, 0xe7, 0xcb, 0x4f, 0x9d, 0x9f, 0xf4, 0xea, 0x65, 0xdc, 0x03, 0x72, 0x74, 0x80, - 0x70, 0x5e, 0xf7, 0x1b, 0xb6, 0xff, 0xe6, 0x97, 0xf7, 0x27, 0x2f, 0x03, 0x9b, 0x14, 0x89, 0x6d, 0x25, 0x9f, 0xf5, - 0x40, 0xe1, 0xd7, 0x63, 0xbd, 0xba, 0xd8, 0xf4, 0x58, 0x0f, 0xb5, 0x80, 0xe8, 0x61, 0x01, 0xea, 0xbf, 0x9e, 0x7d, - 0x1a, 0x0a, 0x07, 0xd9, 0x38, 0x55, 0xa0, 0xc8, 0x82, 0x3f, 0x17, 0xa3, 0x4d, 0x41, 0x80, 0xc8, 0x96, 0x90, 0x96, - 0x9f, 0xcd, 0x1e, 0x97, 0x5a, 0x92, 0xc1, 0x37, 0x01, 0x99, 0x1d, 0x58, 0x39, 0x41, 0xe9, 0xb8, 0x33, 0xe0, 0xca, - 0x16, 0x8f, 0x76, 0xfb, 0xd3, 0x20, 0x3b, 0x6b, 0x4e, 0x1a, 0xed, 0xc3, 0x3e, 0x05, 0x4e, 0x1a, 0x10, 0x7b, 0x44, - 0xa0, 0xef, 0xb6, 0xb9, 0xf4, 0xd1, 0xe1, 0x9c, 0x17, 0xf2, 0xcf, 0xa9, 0xc4, 0xe0, 0x1e, 0x4a, 0xac, 0x81, 0x40, - 0xe5, 0x19, 0xaa, 0x1c, 0x36, 0xc8, 0xf1, 0xcf, 0x8e, 0x64, 0x26, 0x31, 0x59, 0xe4, 0x6e, 0xcd, 0x54, 0xf8, 0x81, - 0x00, 0xfe, 0x73, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x01, 0x7f, 0x4c, 0xe1, 0xe7, 0x3c, 0x85, - 0x9d, 0xf6, 0xb0, 0x29, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, 0x3f, - 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x75, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x05, 0x39, - 0xdb, 0x14, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xf2, 0x51, 0x5a, 0xfd, 0x55, 0xff, - 0x04, 0xe6, 0x6d, 0x2a, 0x46, 0xb5, 0x8a, 0xc9, 0x6f, 0xf4, 0xfb, 0xc5, 0xa0, 0xf5, 0x21, 0x83, 0x8f, 0x5e, 0x9b, - 0x06, 0x7f, 0x74, 0x1a, 0xec, 0x30, 0xd1, 0x08, 0x80, 0x64, 0x4e, 0x2d, 0x79, 0x28, 0xfa, 0x23, 0xa8, 0xb0, 0x46, - 0xb9, 0x53, 0x30, 0x58, 0xff, 0xf1, 0x68, 0x07, 0xa6, 0x5e, 0x1c, 0x6d, 0xc9, 0x0e, 0x9a, 0xfb, 0x06, 0xb8, 0x5f, - 0x23, 0x5b, 0xcc, 0x2a, 0x80, 0x66, 0xaf, 0x11, 0x19, 0x9f, 0xbc, 0x00, 0xc6, 0x6c, 0x93, 0x85, 0x91, 0x88, 0x83, - 0xb1, 0x6a, 0xcc, 0x98, 0x81, 0x81, 0x0b, 0x74, 0x2d, 0x93, 0x92, 0x34, 0xa4, 0x83, 0x01, 0x2b, 0x65, 0x0b, 0x07, - 0xbc, 0x68, 0x4e, 0xdb, 0xf1, 0xba, 0x45, 0xe3, 0x81, 0xed, 0x62, 0x87, 0xfb, 0x1f, 0x8a, 0xdd, 0xdb, 0x70, 0x47, - 0x7a, 0x85, 0x8a, 0x25, 0xf4, 0xf3, 0xaf, 0xb2, 0xcf, 0x1a, 0x4e, 0x4e, 0x85, 0x66, 0x68, 0x29, 0x12, 0x4a, 0xf1, - 0x4e, 0x4f, 0x0a, 0x8c, 0x65, 0x2c, 0xfc, 0x03, 0x70, 0x4e, 0x17, 0x8a, 0xc8, 0x1d, 0x38, 0x8e, 0x6f, 0xa1, 0x82, - 0x51, 0xc3, 0xc1, 0xcb, 0x18, 0xb6, 0x45, 0x31, 0x0b, 0x09, 0xa7, 0x10, 0x2e, 0x56, 0x59, 0xbf, 0x2f, 0x7f, 0x51, - 0x17, 0x5d, 0x65, 0xb2, 0xee, 0x93, 0x70, 0x64, 0xc6, 0x72, 0xea, 0x85, 0xe4, 0x79, 0xcf, 0x93, 0x69, 0xf2, 0xb4, - 0x0a, 0x22, 0x80, 0x7c, 0x0e, 0xef, 0xc3, 0x34, 0x03, 0xab, 0x34, 0x29, 0x3f, 0x42, 0xe9, 0x8b, 0xcf, 0x73, 0x3f, - 0xd0, 0xd9, 0x2b, 0x93, 0x0c, 0x6f, 0xe6, 0xad, 0x37, 0xa9, 0x75, 0x5d, 0x3c, 0xe0, 0xef, 0x9c, 0xc1, 0xc6, 0xb9, - 0xce, 0x04, 0x07, 0x5e, 0x24, 0xb5, 0x5e, 0x33, 0xfe, 0x3c, 0xc3, 0x75, 0xa9, 0xda, 0xe8, 0xa3, 0x10, 0x5d, 0x41, - 0xa6, 0x02, 0x14, 0x8a, 0xb4, 0x7f, 0x50, 0x6a, 0x6e, 0x52, 0x69, 0x23, 0x01, 0x74, 0x0f, 0x93, 0x06, 0x5b, 0x0c, - 0x65, 0x2c, 0x4d, 0xa2, 0xdc, 0x69, 0x10, 0x57, 0xf6, 0xe7, 0x5c, 0xe2, 0xd0, 0xb2, 0x48, 0xfe, 0xbd, 0xef, 0xe9, - 0x2b, 0xa4, 0xee, 0x64, 0x81, 0xcc, 0x18, 0x2f, 0xf2, 0xf8, 0x13, 0x10, 0x66, 0x83, 0x36, 0x2a, 0x0a, 0x21, 0x64, - 0x83, 0x18, 0x34, 0x5e, 0xe4, 0xf1, 0x0f, 0x8a, 0xc6, 0x43, 0x3e, 0x8a, 0x7c, 0xf5, 0x57, 0xa9, 0xff, 0x0a, 0x7d, - 0x66, 0x82, 0x47, 0xa8, 0x26, 0xfa, 0x77, 0xcf, 0x67, 0xf7, 0xa0, 0x36, 0x8c, 0xc2, 0xcc, 0x94, 0x9f, 0xfb, 0xa6, - 0x38, 0x7b, 0xfd, 0x15, 0x5d, 0x65, 0x5b, 0xf7, 0xa3, 0x8f, 0x27, 0x04, 0xd6, 0xc6, 0xe8, 0x8a, 0x1b, 0x03, 0xc8, - 0x61, 0xf2, 0x7e, 0x45, 0x69, 0x15, 0xa4, 0x41, 0xe8, 0xa0, 0x21, 0xe8, 0x95, 0x44, 0x1f, 0x48, 0x2c, 0x62, 0x0c, - 0x2f, 0xc4, 0x33, 0x52, 0x93, 0x89, 0x86, 0x78, 0x45, 0xec, 0x87, 0x68, 0xc9, 0xa9, 0x89, 0x6e, 0x84, 0x29, 0x06, - 0x12, 0x3b, 0x83, 0xe4, 0x24, 0xa9, 0x95, 0x5f, 0x3c, 0x93, 0x84, 0x25, 0x76, 0x1e, 0x62, 0x30, 0xa9, 0xa5, 0x3b, - 0xbd, 0xa9, 0xd2, 0x97, 0x13, 0x2d, 0x07, 0xed, 0x03, 0xb0, 0x4b, 0x49, 0xef, 0x9f, 0x14, 0x8a, 0xf8, 0x10, 0xc6, - 0x31, 0x84, 0x6f, 0x11, 0xd5, 0x15, 0x38, 0xd7, 0x0a, 0x34, 0x56, 0x03, 0x0f, 0xcd, 0x2c, 0x9f, 0x0f, 0x39, 0xfd, - 0x54, 0x5a, 0xfe, 0x18, 0xd1, 0xd8, 0x68, 0xdd, 0x1c, 0x8f, 0x07, 0x5a, 0xf5, 0xd2, 0x39, 0xe8, 0xba, 0x99, 0xc4, - 0xc4, 0x0d, 0xa4, 0xeb, 0x47, 0xbf, 0x99, 0xb0, 0x17, 0x51, 0x21, 0x97, 0x42, 0x50, 0xd0, 0xea, 0x40, 0xe0, 0x50, - 0x78, 0x8b, 0x32, 0x5f, 0xc5, 0xb4, 0x81, 0x30, 0xf8, 0xfc, 0x40, 0x7e, 0xbe, 0x29, 0x48, 0xc5, 0x8e, 0x75, 0xed, - 0xf7, 0xb7, 0xa5, 0x07, 0x78, 0x72, 0x26, 0xc9, 0xd3, 0x66, 0x08, 0x2b, 0x02, 0x68, 0xcc, 0x6a, 0xb2, 0x38, 0xe1, - 0xca, 0x1c, 0x7e, 0xcc, 0xbd, 0x92, 0xa5, 0x4c, 0x9d, 0xa7, 0x7a, 0x01, 0x44, 0x1d, 0x6f, 0xd0, 0x8a, 0xd4, 0xaf, - 0xd0, 0xd9, 0x6b, 0x56, 0x42, 0xc6, 0xc3, 0x4b, 0xce, 0xd3, 0xd1, 0x03, 0x4b, 0x78, 0x84, 0x7f, 0x25, 0x13, 0x7d, - 0xf8, 0x3d, 0x70, 0xb8, 0x19, 0x27, 0x3c, 0x72, 0x9b, 0x7d, 0xa8, 0xc2, 0x35, 0xdc, 0x4c, 0x0b, 0x40, 0x72, 0x0b, - 0x92, 0x26, 0xa0, 0x84, 0x44, 0x26, 0x64, 0xd6, 0x94, 0xfc, 0xdc, 0xd2, 0x36, 0x58, 0xc3, 0xa4, 0xf3, 0x80, 0x17, - 0xad, 0x3e, 0x5a, 0x4d, 0xb4, 0xcb, 0xac, 0x9a, 0x0f, 0x71, 0x86, 0x6a, 0x8e, 0xbb, 0x0b, 0xf8, 0x39, 0xe0, 0x39, - 0xcb, 0x9b, 0x74, 0xb4, 0x1f, 0x70, 0xe1, 0xc9, 0x75, 0x9e, 0x8e, 0x76, 0xf8, 0x4b, 0xee, 0x0f, 0x00, 0x1d, 0x4c, - 0x5d, 0x02, 0x7f, 0xaa, 0xb6, 0x9a, 0x4a, 0xfd, 0xd2, 0xda, 0xaf, 0xeb, 0xce, 0x6a, 0xc1, 0x19, 0xa2, 0x2f, 0x43, - 0x07, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, - 0x82, 0x7b, 0xc9, 0x9f, 0x1f, 0x10, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, - 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xa9, 0x34, 0x26, 0x45, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0xeb, 0x7a, 0x1b, 0xb7, 0xb2, 0x20, 0xfa, + 0xfb, 0xcc, 0x53, 0x48, 0xbd, 0x1d, 0xa5, 0x21, 0x82, 0x2d, 0x92, 0xba, 0x58, 0x6e, 0x0a, 0xe2, 0xf8, 0x1a, 0x3b, + 0x71, 0x6c, 0xc7, 0x72, 0xec, 0xd8, 0x0c, 0xb7, 0x02, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, + 0xe4, 0xbb, 0x9f, 0xaf, 0x70, 0xe9, 0x46, 0x93, 0xb4, 0xd7, 0x5a, 0x73, 0x66, 0xce, 0x37, 0x3b, 0x7b, 0x59, 0x6c, + 0xdc, 0x51, 0x28, 0x14, 0xaa, 0x0a, 0x55, 0x85, 0x8b, 0xfd, 0x91, 0xcc, 0xf4, 0xdd, 0x9c, 0xed, 0x4d, 0xf5, 0x2c, + 0xbf, 0xbc, 0x70, 0xff, 0x32, 0x3a, 0xba, 0xbc, 0xc8, 0xb9, 0xf8, 0xbc, 0x57, 0xb0, 0x9c, 0xf0, 0x4c, 0x8a, 0xbd, + 0x69, 0xc1, 0xc6, 0x64, 0x44, 0x35, 0x4d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xe5, 0xc5, 0x8c, 0x69, 0xba, 0x97, + 0x4d, 0x69, 0xa1, 0x98, 0x26, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbf, 0xbc, 0x50, 0x59, 0xc1, 0xe7, 0x7a, 0x0f, 0x9a, + 0x24, 0x33, 0x39, 0x5a, 0xe4, 0xec, 0xf2, 0xe8, 0xe8, 0xe6, 0xe6, 0x26, 0xf9, 0x5b, 0xfd, 0x8f, 0x2f, 0xb4, 0xd8, + 0xfb, 0xa5, 0x20, 0xaf, 0x87, 0x7f, 0xb3, 0x4c, 0x27, 0x23, 0x36, 0xe6, 0x82, 0xbd, 0x29, 0xe4, 0x9c, 0x15, 0xfa, + 0xae, 0x0b, 0x99, 0x3f, 0x15, 0x24, 0xe6, 0x58, 0x63, 0x86, 0xc8, 0xa5, 0xde, 0xe3, 0x62, 0x8f, 0xf7, 0x7e, 0x29, + 0x4c, 0xca, 0x92, 0x89, 0xc5, 0x8c, 0x15, 0x74, 0x98, 0xb3, 0x74, 0xbf, 0x85, 0x33, 0x29, 0xc6, 0x7c, 0xb2, 0x28, + 0xbf, 0x6f, 0x0a, 0xae, 0xfd, 0xef, 0x2f, 0x34, 0x5f, 0xb0, 0x94, 0xad, 0x51, 0xca, 0xfb, 0x7a, 0x40, 0x98, 0x69, + 0xf9, 0x73, 0xd5, 0x70, 0xfc, 0x93, 0x69, 0xf2, 0x6e, 0xce, 0xe4, 0x78, 0x4f, 0xef, 0x93, 0x48, 0xdd, 0xcd, 0x86, + 0x32, 0x8f, 0x7a, 0xba, 0x11, 0x45, 0x29, 0x94, 0xc1, 0x0c, 0x75, 0x33, 0x29, 0x94, 0xde, 0x13, 0x9c, 0xdc, 0x70, + 0x31, 0x92, 0x37, 0xf8, 0x46, 0x10, 0xc1, 0x93, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x83, 0x83, 0xd8, + 0x7d, 0xdf, 0x3d, 0xbe, 0xba, 0x22, 0x84, 0x7c, 0x91, 0x7c, 0xb4, 0xd7, 0x5a, 0xad, 0x82, 0xd4, 0x44, 0x50, 0xcd, + 0xbf, 0x30, 0x5b, 0x09, 0x1d, 0x1c, 0x44, 0x74, 0x24, 0xe7, 0x9a, 0x8d, 0xae, 0xf4, 0x5d, 0xce, 0xae, 0xa6, 0x8c, + 0x69, 0x15, 0x71, 0xb1, 0xf7, 0x44, 0x66, 0x8b, 0x19, 0x13, 0x3a, 0x99, 0x17, 0x52, 0x4b, 0x18, 0xd8, 0xc1, 0x41, + 0x54, 0xb0, 0x79, 0x4e, 0x33, 0x06, 0xf9, 0x8f, 0xaf, 0xae, 0xaa, 0x1a, 0x55, 0x21, 0xfc, 0x59, 0x90, 0x2b, 0x33, + 0xf4, 0x18, 0xe1, 0x0f, 0x82, 0x08, 0x76, 0xb3, 0xf7, 0x81, 0xd1, 0xcf, 0xbf, 0xd2, 0x79, 0x37, 0xcb, 0xa9, 0x52, + 0x7b, 0xcf, 0xe4, 0xd2, 0x4c, 0xa3, 0x58, 0x64, 0x5a, 0x16, 0xb1, 0xc6, 0x0c, 0x0b, 0xb4, 0xe4, 0xe3, 0x58, 0x4f, + 0xb9, 0x4a, 0xae, 0xef, 0x65, 0x4a, 0xbd, 0x65, 0x6a, 0x91, 0xeb, 0x7b, 0x64, 0xbf, 0x85, 0xc5, 0x3e, 0x21, 0x9f, + 0x05, 0xd2, 0xd3, 0x42, 0xde, 0xec, 0x3d, 0x2d, 0x0a, 0x59, 0xc4, 0xd1, 0xe3, 0xab, 0x2b, 0x5b, 0x62, 0x8f, 0xab, + 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0xbf, 0x16, 0x42, 0xd1, 0x31, 0x7b, + 0x7c, 0x75, 0xf5, 0xd7, 0x9e, 0x2c, 0xf6, 0xfe, 0xca, 0x94, 0xfa, 0x6b, 0x8f, 0x0b, 0xa5, 0x19, 0x1d, 0x25, 0x11, + 0xea, 0x9a, 0xce, 0x32, 0xa5, 0xde, 0xb1, 0x5b, 0x4d, 0x34, 0x36, 0x9f, 0x9a, 0xb0, 0xf5, 0x84, 0xe9, 0x3d, 0x55, + 0xce, 0x2b, 0x46, 0xcb, 0x9c, 0xe9, 0x3d, 0x4d, 0x4c, 0xbe, 0x74, 0xf0, 0x67, 0xf6, 0x53, 0x77, 0xf9, 0x38, 0xbe, + 0x11, 0x07, 0x07, 0xba, 0x04, 0x34, 0x5a, 0xba, 0x15, 0x22, 0x6c, 0xdf, 0xa7, 0x1d, 0x1c, 0xb0, 0x24, 0x67, 0x62, + 0xa2, 0xa7, 0x84, 0x90, 0x76, 0x57, 0x1c, 0x1c, 0xc4, 0x9a, 0x7c, 0x10, 0xc9, 0x84, 0xe9, 0x98, 0x21, 0x84, 0xab, + 0xda, 0x07, 0x07, 0xb1, 0x05, 0x82, 0x24, 0xda, 0x00, 0xae, 0x06, 0x63, 0x94, 0x38, 0xe8, 0x5f, 0xdd, 0x89, 0x2c, + 0x0e, 0xc7, 0x8f, 0xb0, 0x38, 0x38, 0xf8, 0x20, 0x12, 0x05, 0x2d, 0x62, 0x8d, 0xd0, 0xba, 0x60, 0x7a, 0x51, 0x88, + 0x3d, 0xbd, 0xd6, 0xf2, 0x4a, 0x17, 0x5c, 0x4c, 0x62, 0xb4, 0xf4, 0x69, 0x41, 0xc5, 0xf5, 0xda, 0x0e, 0xf7, 0xb7, + 0x82, 0x70, 0x72, 0x09, 0x3d, 0x3e, 0x93, 0xb1, 0xc3, 0x41, 0x4e, 0x48, 0xa4, 0x4c, 0xdd, 0xa8, 0xc7, 0x53, 0xde, + 0x88, 0x22, 0x6c, 0x47, 0x89, 0x3f, 0x0b, 0x84, 0xb9, 0x06, 0xd4, 0x4d, 0x92, 0x44, 0x23, 0x72, 0xb9, 0xf4, 0x60, + 0xe1, 0xc1, 0x44, 0x7b, 0xbc, 0xdf, 0x1a, 0xa4, 0x3a, 0x29, 0xd8, 0x68, 0x91, 0xb1, 0x38, 0x16, 0x58, 0x61, 0x89, + 0xc8, 0xa5, 0x68, 0xc4, 0x05, 0xb9, 0x84, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xb9, 0x41, 0x16, 0x7e, + 0x84, 0x00, 0x62, 0x37, 0xa0, 0x82, 0x90, 0x48, 0x2c, 0x66, 0x43, 0x56, 0x44, 0x65, 0xb1, 0x6e, 0x0d, 0x2f, 0x16, + 0x8a, 0xed, 0x65, 0x4a, 0xed, 0x8d, 0x17, 0x22, 0xd3, 0x5c, 0x8a, 0xbd, 0xa8, 0x51, 0x34, 0x22, 0x8b, 0x0f, 0x25, + 0x3a, 0x44, 0x68, 0x8d, 0x62, 0x85, 0x1a, 0xbc, 0x2f, 0x1b, 0xed, 0x01, 0x86, 0x51, 0xa2, 0xae, 0x6b, 0xcf, 0x41, + 0x80, 0x61, 0x0e, 0x93, 0x5c, 0xe3, 0x4f, 0x76, 0xe7, 0xc3, 0x14, 0x6f, 0x44, 0x8f, 0x27, 0xdb, 0x3b, 0x85, 0xe8, + 0x64, 0x46, 0xe7, 0x31, 0x23, 0x97, 0xcc, 0x60, 0x17, 0x15, 0x19, 0x8c, 0xb5, 0xb6, 0x70, 0x3d, 0x96, 0xb2, 0xa4, + 0xc2, 0x29, 0x94, 0xea, 0x64, 0x2c, 0x8b, 0xa7, 0x34, 0x9b, 0x42, 0xbd, 0x12, 0x63, 0x46, 0x7e, 0xc3, 0x65, 0x05, + 0xa3, 0x9a, 0x3d, 0xcd, 0x19, 0x7c, 0xc5, 0x91, 0xa9, 0x19, 0x21, 0xac, 0x60, 0xab, 0xe7, 0x5c, 0xbf, 0x92, 0x22, + 0x63, 0x5d, 0x15, 0xe0, 0x97, 0x59, 0xf9, 0x87, 0x5a, 0x17, 0x7c, 0xb8, 0xd0, 0x2c, 0x8e, 0x04, 0x94, 0x88, 0xb0, + 0x42, 0x58, 0x24, 0x9a, 0xdd, 0xea, 0xc7, 0x52, 0x68, 0x26, 0x34, 0x61, 0x1e, 0xaa, 0x98, 0x27, 0x74, 0x3e, 0x67, + 0x62, 0xf4, 0x78, 0xca, 0xf3, 0x51, 0x2c, 0xd0, 0x1a, 0xad, 0xf1, 0xef, 0x82, 0xc0, 0x24, 0xc9, 0x25, 0x4f, 0xe1, + 0x9f, 0x6f, 0x4f, 0x27, 0xd6, 0xe4, 0xd2, 0x6c, 0x0b, 0x46, 0xa2, 0xa8, 0x3b, 0x96, 0x45, 0xec, 0xa6, 0xb0, 0x07, + 0xa4, 0x0b, 0xfa, 0x78, 0xbb, 0xc8, 0x99, 0x42, 0xac, 0x41, 0x44, 0xb9, 0x8e, 0x0e, 0xc2, 0xbf, 0x15, 0x31, 0x83, + 0x05, 0xe0, 0x28, 0xe5, 0x86, 0x04, 0xbe, 0xe4, 0x6e, 0x53, 0x8d, 0x4a, 0xa2, 0xf6, 0x51, 0x90, 0x11, 0x4f, 0x74, + 0xb1, 0x50, 0x9a, 0x8d, 0xde, 0xdd, 0xcd, 0x99, 0xc2, 0x3f, 0x17, 0xe4, 0xa3, 0xe8, 0x7d, 0x14, 0x09, 0x9b, 0xcd, + 0xf5, 0xdd, 0x95, 0xa1, 0xe6, 0x69, 0x14, 0xe1, 0x7f, 0x4c, 0xd1, 0x82, 0xd1, 0x0c, 0x48, 0x9a, 0x03, 0xd9, 0x1b, + 0x99, 0xdf, 0x8d, 0x79, 0x9e, 0x5f, 0x2d, 0xe6, 0x73, 0x59, 0x68, 0xac, 0x05, 0x59, 0x6a, 0x59, 0xc1, 0x07, 0x56, + 0x74, 0xa9, 0x6e, 0xb8, 0xce, 0xa6, 0xb1, 0x46, 0xcb, 0x8c, 0x2a, 0xb6, 0xf7, 0x48, 0xca, 0x9c, 0x51, 0x91, 0x72, + 0xc2, 0x7b, 0x3f, 0x17, 0xa9, 0x58, 0xe4, 0x79, 0x77, 0x58, 0x30, 0xfa, 0xb9, 0x6b, 0xb2, 0xed, 0xe1, 0x90, 0x9a, + 0xdf, 0x0f, 0x8b, 0x82, 0xde, 0x41, 0x41, 0x42, 0xa0, 0x58, 0x8f, 0xa7, 0x3f, 0x5f, 0xbd, 0x7e, 0x95, 0xd8, 0xbd, + 0xc2, 0xc7, 0x77, 0x31, 0x2f, 0xf7, 0x1f, 0x5f, 0xe3, 0x71, 0x21, 0x67, 0x1b, 0x5d, 0x5b, 0xd0, 0xf1, 0xee, 0x37, + 0x86, 0xc0, 0x08, 0xdf, 0xb7, 0x4d, 0x87, 0x23, 0x78, 0x65, 0x30, 0x1f, 0x32, 0x89, 0xeb, 0x17, 0xfe, 0x49, 0x6d, + 0x72, 0xcc, 0xd1, 0xf7, 0x47, 0xab, 0x8b, 0xbb, 0x25, 0x23, 0x66, 0x9c, 0x73, 0x38, 0x18, 0x61, 0x8c, 0x19, 0xd5, + 0xd9, 0x74, 0xc9, 0x4c, 0x63, 0x6b, 0x3f, 0x62, 0xb6, 0x5e, 0xe3, 0xaf, 0xd2, 0x63, 0xbd, 0xde, 0x27, 0x84, 0x1b, + 0x7a, 0x45, 0xf4, 0x6a, 0xc5, 0x09, 0xe1, 0x08, 0xbf, 0xe5, 0x64, 0x49, 0xfd, 0x84, 0xe0, 0x64, 0x83, 0xed, 0x99, + 0x5a, 0x2a, 0x03, 0x27, 0xe0, 0x17, 0x56, 0x68, 0x56, 0xa4, 0x5a, 0xe0, 0x82, 0x8d, 0x73, 0x18, 0xc7, 0x7e, 0x1b, + 0x4f, 0xa9, 0x7a, 0x3c, 0xa5, 0x62, 0xc2, 0x46, 0xe9, 0x57, 0xb9, 0xc6, 0x4c, 0x90, 0x68, 0xcc, 0x05, 0xcd, 0xf9, + 0x57, 0x36, 0x8a, 0xdc, 0xb9, 0xf0, 0x48, 0xef, 0xb1, 0x5b, 0xcd, 0xc4, 0x48, 0xed, 0x3d, 0x7f, 0xf7, 0xeb, 0x4b, + 0xb7, 0x98, 0xb5, 0xb3, 0x02, 0x2d, 0xd5, 0x62, 0xce, 0x8a, 0x18, 0x61, 0x77, 0x56, 0x3c, 0xe5, 0x86, 0x4e, 0xfe, + 0x4a, 0xe7, 0x36, 0x85, 0xab, 0xdf, 0xe7, 0x23, 0xaa, 0xd9, 0x1b, 0x26, 0x46, 0x5c, 0x4c, 0xc8, 0x7e, 0xdb, 0xa6, + 0x4f, 0xa9, 0xcb, 0x18, 0x95, 0x49, 0xd7, 0xf7, 0x9e, 0xe6, 0x66, 0xee, 0xe5, 0xe7, 0x22, 0x46, 0x6b, 0xa5, 0xa9, + 0xe6, 0xd9, 0x1e, 0x1d, 0x8d, 0x5e, 0x08, 0xae, 0xb9, 0x19, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xec, 0xa9, 0xe1, + 0x47, 0x1e, 0x23, 0x1c, 0xc7, 0xee, 0x2c, 0x98, 0x22, 0xb7, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb1, 0xd4, 0x66, + 0x92, 0xfe, 0x00, 0x25, 0xf3, 0x85, 0x82, 0xc5, 0xf6, 0x5d, 0xc0, 0x41, 0x23, 0x87, 0x8a, 0x15, 0x5f, 0xd8, 0xa8, + 0x44, 0x10, 0x15, 0xa3, 0xe5, 0x46, 0x1f, 0x6e, 0x7b, 0x68, 0xd2, 0x1f, 0x74, 0x43, 0x12, 0xce, 0x1c, 0xb2, 0x5b, + 0x4e, 0x85, 0x33, 0x55, 0x12, 0x95, 0x18, 0x0e, 0xd4, 0x92, 0xb0, 0x28, 0xe2, 0xe7, 0x37, 0x8f, 0x05, 0xf0, 0x10, + 0x21, 0xe5, 0xf0, 0x67, 0xee, 0xd3, 0x2f, 0xe6, 0xf0, 0x50, 0x58, 0x20, 0xac, 0xed, 0x48, 0x15, 0x42, 0x6b, 0x84, + 0xb5, 0x1f, 0xae, 0x25, 0x4a, 0x9e, 0x2f, 0x82, 0x53, 0x9b, 0xbc, 0xe5, 0xe6, 0xd8, 0x06, 0xda, 0x46, 0x35, 0x3b, + 0x38, 0x88, 0x59, 0x52, 0x22, 0x06, 0xd9, 0x6f, 0xbb, 0x45, 0x0a, 0xa0, 0xf5, 0x8d, 0x71, 0x43, 0xcf, 0x86, 0xc1, + 0xd9, 0x67, 0x89, 0x90, 0x0f, 0xb3, 0x8c, 0x29, 0x25, 0x8b, 0x83, 0x83, 0x7d, 0x53, 0xbe, 0xe4, 0x2c, 0x60, 0x11, + 0x5f, 0xdf, 0x88, 0x6a, 0x08, 0xa8, 0x3a, 0x6d, 0x3d, 0xdf, 0x44, 0x2a, 0xbe, 0xc9, 0x33, 0x21, 0x69, 0x74, 0x7d, + 0x1d, 0x35, 0x34, 0x76, 0x70, 0x98, 0x30, 0xdf, 0xf5, 0xdd, 0x13, 0x66, 0xd9, 0x42, 0xc3, 0x84, 0x6c, 0x81, 0x66, + 0x27, 0x3f, 0x18, 0xd7, 0x87, 0x84, 0x35, 0x56, 0x68, 0x1d, 0xac, 0xe8, 0xce, 0xa6, 0x0d, 0x7f, 0x63, 0x97, 0x6e, + 0x39, 0x31, 0x3c, 0x45, 0xb0, 0x8e, 0x7d, 0x36, 0x58, 0x63, 0x03, 0x7b, 0x3f, 0x1b, 0x69, 0x06, 0xda, 0xd7, 0x83, + 0xae, 0xcb, 0x27, 0xca, 0x42, 0xae, 0x60, 0xff, 0x2c, 0x98, 0xd2, 0x16, 0x91, 0x63, 0x8d, 0x25, 0x86, 0x33, 0x6a, + 0x93, 0xe9, 0xac, 0xb1, 0xa4, 0xbb, 0xc6, 0xf6, 0x7a, 0x0e, 0x67, 0xa3, 0x02, 0xa4, 0xfe, 0x3e, 0x3e, 0xc1, 0x58, + 0x35, 0x5a, 0xad, 0xde, 0x72, 0xdf, 0x4a, 0xb5, 0x96, 0x25, 0xbf, 0xb6, 0xb1, 0x28, 0x4c, 0x20, 0x77, 0x38, 0xef, + 0xb7, 0xdd, 0xf8, 0xc5, 0x80, 0xec, 0xb7, 0x4a, 0x2c, 0x76, 0x60, 0xb5, 0xe3, 0xb1, 0x50, 0x7c, 0x6d, 0x9b, 0x42, + 0xe6, 0xac, 0xaf, 0xe1, 0x4b, 0x32, 0xdd, 0xc2, 0xd5, 0x29, 0xe9, 0x03, 0xd7, 0x91, 0x4c, 0x07, 0xdf, 0xc2, 0x27, + 0x4f, 0x11, 0x62, 0xbd, 0x9d, 0x57, 0x11, 0x8e, 0x2f, 0x75, 0xc2, 0xb1, 0x31, 0x8d, 0x68, 0x5e, 0x56, 0x89, 0x4a, + 0x34, 0x73, 0x5b, 0xbd, 0xca, 0xc2, 0xc2, 0x0c, 0xa6, 0x9a, 0x52, 0xd0, 0xc4, 0x2b, 0x3a, 0x63, 0x2a, 0x66, 0x08, + 0x7f, 0xab, 0x80, 0xc5, 0x4f, 0x28, 0x32, 0x08, 0xce, 0x50, 0x05, 0x67, 0x28, 0xb0, 0xbb, 0xc0, 0xa4, 0xd5, 0xb7, + 0x9c, 0xc2, 0xac, 0xaf, 0x06, 0x15, 0x6f, 0x17, 0x4c, 0xde, 0x1c, 0xce, 0x0e, 0xc1, 0x3d, 0xfc, 0x6c, 0x9a, 0x05, + 0x9a, 0x61, 0x21, 0x14, 0xc2, 0xfb, 0xad, 0xcd, 0x95, 0xf4, 0xa5, 0xaa, 0x39, 0xf6, 0x07, 0xb0, 0x0e, 0xe6, 0xd8, + 0x48, 0xb8, 0x32, 0x7f, 0x6b, 0x5b, 0x0d, 0xc0, 0x76, 0x05, 0x98, 0x91, 0x8c, 0x73, 0xaa, 0xe3, 0xf6, 0x51, 0x0b, + 0x18, 0xd3, 0x2f, 0x0c, 0x4e, 0x15, 0x84, 0xb6, 0xa7, 0xc2, 0x92, 0x85, 0x50, 0x53, 0x3e, 0xd6, 0xf1, 0xef, 0xc2, + 0x10, 0x15, 0x96, 0x2b, 0x06, 0x12, 0x4e, 0xc0, 0x1e, 0x1b, 0x82, 0xf3, 0xbb, 0x80, 0x7e, 0xba, 0xe5, 0x41, 0xe4, + 0x46, 0x6a, 0x08, 0x17, 0x90, 0x87, 0x8a, 0xb5, 0xae, 0xc8, 0x4c, 0xc9, 0xb8, 0x01, 0xf7, 0xd8, 0xee, 0xd9, 0x16, + 0x53, 0x47, 0x0d, 0x44, 0xc0, 0xc1, 0x8a, 0x34, 0x24, 0x11, 0x2e, 0x51, 0x27, 0x5a, 0xbe, 0x94, 0x37, 0xac, 0x78, + 0x4c, 0x61, 0xf0, 0xa9, 0xad, 0xbe, 0xb6, 0x47, 0x81, 0xa1, 0xf8, 0xba, 0xeb, 0xf1, 0xe5, 0xda, 0x4c, 0xfc, 0x4d, + 0x21, 0x67, 0x5c, 0x31, 0xe0, 0xdb, 0x2c, 0xfc, 0x05, 0x6c, 0x34, 0xb3, 0x23, 0xe1, 0xb8, 0x61, 0x25, 0x7e, 0x3d, + 0x7c, 0x59, 0xc7, 0xaf, 0xeb, 0x7b, 0x4f, 0x27, 0x9e, 0x02, 0xd6, 0xf7, 0x31, 0xc2, 0xb1, 0x13, 0x2f, 0x82, 0x93, + 0x2e, 0x99, 0x22, 0x77, 0xcc, 0xaf, 0x56, 0x3a, 0x10, 0xe3, 0x6a, 0x9c, 0x23, 0xb3, 0xdb, 0x06, 0xad, 0xe9, 0x68, + 0x04, 0x2c, 0x5e, 0x21, 0xf3, 0x3c, 0x38, 0xac, 0xb0, 0xe8, 0x96, 0xc7, 0xd3, 0xf5, 0xbd, 0xa7, 0x57, 0xdf, 0x3b, + 0xa1, 0x20, 0x3f, 0x3c, 0xa4, 0xfc, 0x40, 0xc5, 0x88, 0x15, 0x20, 0x57, 0x06, 0xab, 0xe5, 0xce, 0xd9, 0xc7, 0x52, + 0x08, 0x96, 0x69, 0x36, 0x02, 0xa1, 0x45, 0x10, 0x9d, 0x4c, 0xa5, 0xd2, 0x65, 0x62, 0x35, 0x7a, 0x11, 0x0a, 0xa1, + 0x49, 0x46, 0xf3, 0x3c, 0xb6, 0x02, 0xca, 0x4c, 0x7e, 0x61, 0x3b, 0x46, 0xdd, 0xad, 0x0d, 0xb9, 0x6c, 0x86, 0x05, + 0xcd, 0xb0, 0x44, 0xcd, 0x73, 0x9e, 0xb1, 0xf2, 0xf0, 0xba, 0x4a, 0xb8, 0x18, 0xb1, 0x5b, 0xa0, 0x23, 0xe8, 0xf2, + 0xf2, 0xb2, 0x85, 0xdb, 0x68, 0x6d, 0x01, 0xbe, 0xdc, 0x02, 0xec, 0x77, 0x8e, 0x4d, 0x2b, 0x88, 0x2f, 0x77, 0x92, + 0x35, 0x14, 0x9c, 0x95, 0xdc, 0x0b, 0x5a, 0x96, 0x3c, 0x23, 0x3c, 0x62, 0x39, 0xd3, 0xcc, 0x93, 0x73, 0x60, 0xa6, + 0xed, 0xd6, 0x7d, 0x5b, 0xc2, 0xaf, 0x44, 0x27, 0xbf, 0xcb, 0xfc, 0x9a, 0xab, 0x52, 0x74, 0xaf, 0x96, 0xa7, 0x82, + 0x76, 0x4f, 0xdb, 0xe5, 0xa1, 0x5a, 0xd3, 0x6c, 0x6a, 0x25, 0xf6, 0x78, 0x6b, 0x4a, 0x55, 0x1b, 0x8e, 0xb4, 0x97, + 0x9b, 0xe8, 0x53, 0xe1, 0x86, 0xb9, 0x0b, 0x04, 0x57, 0x8e, 0x28, 0x30, 0x10, 0x02, 0xed, 0xb2, 0x3d, 0xa6, 0x79, + 0x3e, 0xa4, 0xd9, 0xe7, 0x3a, 0xf6, 0x57, 0x68, 0x40, 0x36, 0xa9, 0x71, 0x90, 0x15, 0x90, 0xac, 0x70, 0xde, 0x9e, + 0x4a, 0xd7, 0x36, 0x4a, 0xbc, 0xdf, 0xaa, 0xd0, 0xbe, 0xbe, 0xd0, 0xdf, 0xc4, 0x76, 0x33, 0x22, 0xe1, 0x66, 0x16, + 0x03, 0x15, 0xf8, 0x97, 0x18, 0xe7, 0xe9, 0x81, 0xc3, 0x3b, 0x10, 0x3c, 0xd6, 0x1b, 0x03, 0xd1, 0x68, 0xb9, 0x1e, + 0x71, 0xf5, 0x6d, 0x08, 0xfc, 0x6f, 0x19, 0xe5, 0x93, 0xa0, 0x87, 0x7f, 0x77, 0xa0, 0x25, 0x8d, 0x73, 0x8c, 0x73, + 0x39, 0x32, 0xc7, 0x50, 0x78, 0x42, 0xf3, 0x0b, 0x30, 0x2f, 0x06, 0xdf, 0x5f, 0xdb, 0x2c, 0xc3, 0x97, 0xc1, 0x30, + 0x54, 0x37, 0x64, 0x28, 0x6a, 0x28, 0xe0, 0x88, 0xaa, 0x30, 0x67, 0xae, 0xac, 0x89, 0x92, 0x8e, 0x6b, 0xb7, 0xe2, + 0xb8, 0xa3, 0xb9, 0x05, 0x89, 0xe3, 0x58, 0x81, 0x34, 0xe7, 0xf9, 0xfb, 0x6a, 0x16, 0x6a, 0x6b, 0x16, 0x2a, 0x09, + 0xa4, 0x2d, 0x54, 0x21, 0x73, 0x50, 0x3d, 0xd5, 0x02, 0x85, 0xa5, 0x80, 0x65, 0x4d, 0x80, 0x42, 0xa3, 0x92, 0xe0, + 0xe6, 0x44, 0xe3, 0xc2, 0x89, 0x3a, 0x0e, 0xd7, 0x80, 0x64, 0x54, 0x55, 0x24, 0xb2, 0x9b, 0xa3, 0x26, 0xfb, 0x4a, + 0x5c, 0xa0, 0x0d, 0xfe, 0x7e, 0xbd, 0x76, 0x50, 0x62, 0xc8, 0xad, 0x4e, 0x8d, 0x31, 0x0e, 0xc0, 0x82, 0x25, 0x71, + 0xcc, 0xb0, 0x65, 0x7d, 0x36, 0x81, 0x53, 0xb6, 0xbb, 0x4f, 0x88, 0xac, 0x60, 0x53, 0x63, 0x2a, 0x3d, 0x77, 0x25, + 0x11, 0xa6, 0x9e, 0x2d, 0x2d, 0xaa, 0x89, 0x13, 0x12, 0x79, 0xed, 0x44, 0xd4, 0x5b, 0xd6, 0x84, 0xc3, 0x34, 0x28, + 0xb6, 0x4e, 0x81, 0xa8, 0x16, 0xbb, 0xe0, 0xbd, 0x0b, 0x6b, 0x6a, 0xed, 0x04, 0x10, 0x2f, 0x6a, 0x10, 0x0f, 0x40, + 0x2b, 0x2d, 0xf1, 0x92, 0x03, 0x42, 0xeb, 0x95, 0x63, 0x86, 0x0b, 0xbb, 0x10, 0x5b, 0x50, 0xdc, 0x64, 0x3f, 0x0d, + 0x16, 0x82, 0x2c, 0xab, 0x80, 0xbf, 0x0b, 0x8f, 0x88, 0x18, 0x06, 0x2f, 0x56, 0xab, 0x2d, 0xb4, 0xdb, 0xc9, 0x85, + 0xa2, 0xa4, 0x92, 0x0e, 0x57, 0xab, 0xaf, 0x12, 0xc5, 0x8e, 0xff, 0xc5, 0x0c, 0xf5, 0x3c, 0xd1, 0x7d, 0xf8, 0x12, + 0x4a, 0x19, 0x76, 0xb4, 0x4a, 0x29, 0x05, 0x87, 0x3a, 0xd6, 0xd6, 0x17, 0x4a, 0x07, 0x94, 0xfb, 0xf1, 0x16, 0x01, + 0x33, 0x89, 0xee, 0xa4, 0xae, 0xa6, 0xfc, 0xd8, 0x35, 0x2d, 0x10, 0x42, 0xa9, 0x32, 0xb2, 0xcc, 0xfe, 0x2e, 0xf9, + 0xf2, 0xe0, 0x40, 0x05, 0x0d, 0x5d, 0x97, 0x94, 0xe2, 0xef, 0x18, 0x4e, 0x65, 0x75, 0x27, 0x0c, 0xfb, 0xf2, 0xb7, + 0x3f, 0x87, 0xb6, 0xa4, 0xd3, 0x56, 0x17, 0x04, 0x73, 0x7a, 0x43, 0xb9, 0xde, 0x2b, 0x5b, 0xb1, 0x82, 0x79, 0xcc, + 0xd0, 0xd2, 0x71, 0x1b, 0x49, 0xc1, 0x80, 0x7f, 0x04, 0xb2, 0xe0, 0xb9, 0x68, 0x8b, 0xf8, 0xd9, 0x94, 0x81, 0x2a, + 0xdb, 0x33, 0x12, 0xa5, 0x78, 0xb8, 0xef, 0x0e, 0x12, 0xd7, 0xf0, 0xee, 0xb1, 0xaf, 0x37, 0xab, 0xd7, 0xa4, 0x81, + 0x39, 0x2b, 0xc6, 0xb2, 0x98, 0xf9, 0xbc, 0xf5, 0xc6, 0xb7, 0x23, 0x8e, 0x7c, 0x1c, 0xef, 0x6c, 0xdb, 0x89, 0x00, + 0xdd, 0x0d, 0xd9, 0xbb, 0x92, 0xda, 0x6b, 0xa7, 0x69, 0x79, 0x00, 0x5b, 0x05, 0xa1, 0xc7, 0x4c, 0x15, 0x4a, 0xf9, + 0x4e, 0xbd, 0xda, 0xb5, 0xba, 0x93, 0xfd, 0x76, 0xb7, 0x94, 0xfc, 0x3c, 0x36, 0x74, 0xad, 0x8e, 0xc3, 0x9d, 0xaa, + 0x72, 0x91, 0x8f, 0xdc, 0x60, 0x05, 0xc2, 0xcc, 0xe1, 0xd1, 0x0d, 0xcf, 0xf3, 0x2a, 0xf5, 0x3f, 0x21, 0xed, 0xca, + 0x91, 0x76, 0xe9, 0x49, 0x3b, 0x90, 0x0a, 0x20, 0xed, 0xb6, 0xb9, 0xaa, 0xba, 0xdc, 0xda, 0x9e, 0xd2, 0x12, 0x75, + 0x65, 0xc4, 0x69, 0xe8, 0x6f, 0xe1, 0x47, 0x80, 0x4a, 0xe6, 0xeb, 0x73, 0xec, 0xf4, 0x31, 0x20, 0x06, 0x5a, 0x9d, + 0x26, 0x0b, 0x35, 0x15, 0x9f, 0x63, 0x84, 0xd5, 0x9a, 0x95, 0x98, 0xfd, 0xf0, 0x29, 0x28, 0xed, 0x82, 0xe9, 0xc0, + 0x39, 0x66, 0x92, 0xff, 0x23, 0x3e, 0xca, 0xcf, 0x4e, 0xb8, 0xd9, 0x29, 0x3f, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0x46, + 0xdf, 0xa7, 0xf6, 0x66, 0x7a, 0xa2, 0x9c, 0x5e, 0xb5, 0xde, 0xab, 0x55, 0xbc, 0x91, 0x02, 0x1a, 0x7d, 0x27, 0xa5, + 0x14, 0x65, 0xeb, 0x40, 0x03, 0x42, 0xc8, 0x40, 0xc2, 0xda, 0x4e, 0xba, 0x3c, 0xe5, 0x5e, 0xfe, 0x2b, 0x3d, 0x8f, + 0x51, 0xdc, 0xdb, 0xfa, 0x8f, 0xe5, 0x6c, 0x0e, 0x0c, 0xd9, 0x06, 0x4a, 0x4f, 0x98, 0xeb, 0xb0, 0xca, 0x5f, 0xef, + 0x48, 0xab, 0xd5, 0x31, 0xfb, 0xb1, 0x86, 0x4d, 0xa5, 0xd4, 0xbc, 0xdf, 0x5a, 0x2f, 0xca, 0xa4, 0x92, 0x70, 0xec, + 0xd2, 0xad, 0x3c, 0xde, 0xd4, 0xcc, 0xf8, 0x8c, 0xd7, 0xb1, 0xb0, 0x74, 0x58, 0x00, 0xad, 0x0b, 0xc8, 0x8f, 0x47, + 0xf7, 0x70, 0xfd, 0xd7, 0x15, 0x70, 0x96, 0xeb, 0x0d, 0xf0, 0x2d, 0xd7, 0xeb, 0x47, 0xda, 0x49, 0xda, 0xf8, 0xd1, + 0x0e, 0xb9, 0xb7, 0x84, 0x5e, 0x95, 0xe9, 0x64, 0xc6, 0xfe, 0x00, 0xd2, 0xb6, 0x58, 0x48, 0xb2, 0x9c, 0xc9, 0x11, + 0x4b, 0x23, 0x39, 0x67, 0x22, 0x5a, 0x83, 0x9e, 0xd5, 0x21, 0xc0, 0x3f, 0x22, 0x5e, 0xbe, 0xad, 0xeb, 0x5b, 0xd3, + 0x47, 0x7a, 0x0d, 0xaa, 0xb0, 0x97, 0x7c, 0x87, 0x32, 0xf6, 0x3d, 0x2b, 0x94, 0xe1, 0x49, 0x4b, 0xf6, 0xf6, 0x25, + 0xaf, 0x0e, 0xa8, 0x97, 0x3c, 0xfd, 0x76, 0x95, 0x4a, 0x20, 0x89, 0xda, 0xc9, 0x59, 0x72, 0x1c, 0x21, 0xa3, 0x31, + 0x7e, 0xe6, 0x35, 0xc6, 0x8b, 0x52, 0x63, 0xfc, 0x5c, 0x93, 0xc5, 0x86, 0xc6, 0xf8, 0x0f, 0x41, 0x9e, 0xeb, 0xde, + 0x73, 0xaf, 0x4d, 0x7f, 0x23, 0x73, 0x9e, 0xdd, 0xc5, 0x51, 0xce, 0x75, 0x13, 0x6e, 0x13, 0x23, 0xbc, 0xb4, 0x19, + 0xa0, 0x6a, 0x34, 0xfa, 0xee, 0xb5, 0x97, 0xff, 0xb0, 0x10, 0x24, 0xba, 0x97, 0x73, 0x7d, 0x2f, 0xc2, 0x53, 0x4d, + 0xfe, 0x82, 0x5f, 0xf7, 0x96, 0xf1, 0xaf, 0x54, 0x4f, 0x93, 0x82, 0x8a, 0x91, 0x9c, 0xc5, 0xa8, 0x11, 0x45, 0x28, + 0x51, 0x46, 0x08, 0x79, 0x80, 0xd6, 0xf7, 0xfe, 0xc2, 0xaf, 0x24, 0x89, 0x7a, 0x51, 0x63, 0xaa, 0xb1, 0xa6, 0xe4, + 0xaf, 0x8b, 0x7b, 0xcb, 0x57, 0x72, 0x7d, 0xf9, 0x17, 0x7e, 0xaa, 0x4b, 0xb5, 0x3e, 0xbe, 0x65, 0x24, 0x46, 0xe4, + 0xf2, 0xa9, 0x1f, 0xd2, 0x63, 0x39, 0xb3, 0x0a, 0xfe, 0x08, 0xe1, 0x2f, 0xa0, 0xd7, 0xbd, 0xe4, 0x15, 0x11, 0x72, + 0x77, 0x30, 0xfb, 0x24, 0x92, 0x46, 0x79, 0x10, 0x1d, 0x1c, 0x04, 0x69, 0x25, 0x0b, 0x81, 0xff, 0x96, 0xa4, 0x26, + 0xaa, 0x63, 0x46, 0xa1, 0xa5, 0xbf, 0x65, 0xcc, 0x91, 0x6f, 0x26, 0xf6, 0x9a, 0x6a, 0xb7, 0x63, 0x79, 0xdf, 0xea, + 0x1e, 0x12, 0xae, 0x59, 0x41, 0xb5, 0x2c, 0x06, 0x28, 0x64, 0x4b, 0xf0, 0x57, 0x4e, 0xfe, 0xea, 0xef, 0xfd, 0x3f, + 0xff, 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xe0, 0x2f, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, + 0xfe, 0x3c, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x34, 0x40, 0xab, 0xf8, 0xcf, 0xa3, 0x5e, 0xdf, 0x7d, + 0xf5, 0xff, 0xfb, 0xf2, 0x4f, 0x35, 0x38, 0xb4, 0x89, 0xf7, 0x10, 0x3a, 0x9a, 0xe0, 0x5f, 0x04, 0x39, 0x6a, 0x36, + 0x2f, 0x8f, 0x26, 0xf8, 0x27, 0x41, 0x8e, 0xe0, 0xef, 0x9d, 0x26, 0x6f, 0xd9, 0xe4, 0xe9, 0xed, 0x3c, 0xfe, 0xeb, + 0x72, 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf9, 0xa7, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, + 0x06, 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0x3f, 0xff, 0xba, + 0xb8, 0x24, 0x83, 0x55, 0x1c, 0xad, 0x7e, 0x44, 0x2b, 0x84, 0x56, 0xf7, 0xd0, 0x5f, 0x38, 0x9a, 0x44, 0x08, 0xff, + 0x26, 0xc8, 0xd1, 0x8f, 0x47, 0x13, 0xfc, 0x49, 0x90, 0xa3, 0xe8, 0x68, 0x82, 0xdf, 0x4b, 0x72, 0xf4, 0xdf, 0x71, + 0x2f, 0xb5, 0x4a, 0xb8, 0x95, 0x51, 0x7f, 0xac, 0xe0, 0x26, 0x84, 0x16, 0x8c, 0xae, 0x34, 0xd7, 0x39, 0x43, 0xf7, + 0x8e, 0x38, 0x7e, 0x24, 0x01, 0x58, 0xb1, 0x06, 0x25, 0x8d, 0xb9, 0x84, 0x5d, 0x5e, 0xc3, 0xc2, 0x03, 0x06, 0xdd, + 0x4b, 0x39, 0xb6, 0x7a, 0x02, 0x95, 0x6a, 0x7b, 0x7b, 0xab, 0xe0, 0xfa, 0x16, 0x3f, 0x26, 0x8f, 0x64, 0xdc, 0x46, + 0x98, 0x53, 0xf8, 0xd1, 0x41, 0xf8, 0x83, 0x76, 0x17, 0x9e, 0xb0, 0xcd, 0x2d, 0x86, 0x09, 0x69, 0xf9, 0x99, 0x08, + 0xe1, 0x97, 0x3b, 0x32, 0xf5, 0x14, 0xd4, 0x0f, 0x08, 0xff, 0x5c, 0xbb, 0x1e, 0xc5, 0x8f, 0x35, 0x29, 0x91, 0xe3, + 0x5d, 0xc1, 0xd8, 0x07, 0x9a, 0x7f, 0x66, 0x45, 0xfc, 0x54, 0xe3, 0x76, 0xe7, 0x01, 0x36, 0xaa, 0xea, 0xfd, 0x36, + 0xea, 0x96, 0xb7, 0x5b, 0xcf, 0xa5, 0xbd, 0x4f, 0x80, 0x53, 0xb8, 0xae, 0xaf, 0x81, 0xb5, 0xdf, 0xe7, 0x5b, 0x4a, + 0xad, 0x82, 0xde, 0x44, 0xa8, 0x7e, 0x95, 0xca, 0xc5, 0x17, 0x9a, 0xf3, 0xd1, 0x9e, 0x66, 0xb3, 0x79, 0x4e, 0x35, + 0xdb, 0x73, 0x73, 0xde, 0xa3, 0xd0, 0x50, 0x54, 0xf2, 0x14, 0x7f, 0x88, 0x6a, 0xd3, 0xfe, 0x21, 0x92, 0x6a, 0xef, + 0xc4, 0x70, 0x9f, 0xe5, 0xf8, 0x12, 0x41, 0xcb, 0xeb, 0xb2, 0xcd, 0x1b, 0xc1, 0x66, 0x1b, 0x94, 0x65, 0x03, 0x73, + 0x7e, 0x2b, 0x0c, 0xf7, 0x9b, 0x84, 0x74, 0x7a, 0xd1, 0x85, 0xfa, 0x32, 0xb9, 0x8c, 0xe0, 0x26, 0xa7, 0x20, 0x82, + 0x19, 0xe5, 0x11, 0x94, 0xa0, 0xa4, 0xd5, 0xa5, 0x17, 0xac, 0x4b, 0x1b, 0x0d, 0xcf, 0x66, 0x67, 0x84, 0xf7, 0xa9, + 0xad, 0x9f, 0xe3, 0x29, 0x1e, 0x91, 0x66, 0x1b, 0x2f, 0x48, 0xcb, 0x54, 0xe9, 0x2e, 0x2e, 0x32, 0xd7, 0xcf, 0xc1, + 0x41, 0x5c, 0x24, 0x39, 0x55, 0xfa, 0x05, 0x68, 0x04, 0xc8, 0x02, 0x4f, 0x49, 0x91, 0xb0, 0x5b, 0x96, 0xc5, 0x19, + 0xc2, 0x53, 0x47, 0x83, 0x50, 0x17, 0x2d, 0x48, 0x50, 0x0c, 0xe4, 0x0c, 0x22, 0x58, 0x6f, 0xda, 0x6f, 0x0f, 0x08, + 0x21, 0xd1, 0x7e, 0xb3, 0x19, 0xf5, 0x0a, 0xf2, 0x8b, 0x48, 0x21, 0x25, 0x60, 0xa7, 0xc9, 0x4f, 0x90, 0xd4, 0x09, + 0x92, 0xe2, 0xf7, 0x32, 0xd1, 0x4c, 0xe9, 0x18, 0x92, 0x41, 0x49, 0xa0, 0x3c, 0x86, 0x47, 0x17, 0x47, 0x51, 0x03, + 0x52, 0x0d, 0x8a, 0x22, 0x5c, 0x90, 0x3b, 0x8d, 0xd2, 0x69, 0xff, 0x78, 0x10, 0x9e, 0x11, 0x36, 0x15, 0xfa, 0xbf, + 0xd3, 0xbd, 0x69, 0xbf, 0x65, 0xfa, 0xbf, 0x8c, 0x7a, 0x71, 0x41, 0x94, 0x65, 0xe3, 0x7a, 0x2a, 0x15, 0xcc, 0xcc, + 0x17, 0xa5, 0x6e, 0x80, 0xae, 0xef, 0x11, 0x69, 0x76, 0xd2, 0x78, 0x14, 0xce, 0xa4, 0x09, 0x1d, 0x3a, 0x50, 0xe0, + 0x9c, 0x40, 0x79, 0x5c, 0x10, 0xe8, 0xb4, 0xaa, 0x76, 0xa7, 0x53, 0x97, 0xf0, 0x63, 0xf4, 0x63, 0xef, 0x93, 0x48, + 0x7f, 0x13, 0x76, 0x04, 0x9f, 0xc4, 0x6a, 0x05, 0x7f, 0x7f, 0x13, 0x3d, 0x18, 0x96, 0x49, 0xfb, 0xc5, 0xa5, 0xfd, + 0x04, 0x69, 0x82, 0xa5, 0x66, 0xc0, 0x58, 0x95, 0xfc, 0x98, 0x5d, 0x9c, 0x31, 0xb1, 0x33, 0x38, 0x38, 0xe0, 0x7d, + 0xda, 0x68, 0x0f, 0xe0, 0x46, 0xa0, 0xd0, 0xea, 0x03, 0xd7, 0xd3, 0x38, 0x3a, 0xba, 0x8c, 0x50, 0x2f, 0xda, 0x83, + 0x55, 0xee, 0xca, 0x06, 0x71, 0xb0, 0xce, 0x1a, 0x9a, 0xa6, 0xa3, 0x4b, 0xd2, 0xea, 0xc5, 0xc2, 0x12, 0xf9, 0x1c, + 0xe1, 0xcc, 0xd1, 0xd4, 0x16, 0x1e, 0xa1, 0x86, 0x10, 0x0d, 0xff, 0x3d, 0x42, 0x8d, 0xa9, 0x6e, 0x8c, 0x51, 0x9a, + 0xc1, 0xdf, 0x78, 0x44, 0x08, 0x69, 0x76, 0xca, 0x8a, 0xfe, 0xb0, 0xa4, 0x28, 0x1d, 0x7b, 0xf5, 0x68, 0xdf, 0x6c, + 0x0e, 0xd9, 0x88, 0x79, 0x9f, 0x0d, 0x56, 0xab, 0xe8, 0xa2, 0x77, 0x19, 0xa1, 0x46, 0xec, 0xd1, 0xee, 0xc8, 0xe3, + 0x1d, 0x42, 0x58, 0x0c, 0xd6, 0xee, 0x06, 0xea, 0x86, 0xd5, 0x6e, 0x9b, 0x96, 0xd5, 0xfe, 0x0f, 0xc8, 0x02, 0x5b, + 0x97, 0x72, 0x8f, 0xe5, 0x6f, 0xe7, 0x30, 0x55, 0x8f, 0xdb, 0x92, 0xb4, 0x70, 0x41, 0xbc, 0xba, 0x9b, 0x12, 0x5d, + 0xe1, 0x7f, 0x46, 0xaa, 0xe2, 0xb8, 0x9f, 0xe3, 0xe9, 0x80, 0x08, 0x6a, 0xe4, 0x97, 0xae, 0x57, 0xa6, 0xb3, 0x9c, + 0xdc, 0xb0, 0x8d, 0xfb, 0xdf, 0x1c, 0xee, 0x64, 0x1e, 0xeb, 0x24, 0x5b, 0x14, 0x05, 0x13, 0xfa, 0x95, 0x1c, 0x39, + 0xc6, 0x8e, 0xe5, 0x20, 0x5b, 0xc1, 0xc5, 0x2e, 0x06, 0xae, 0xae, 0xe3, 0x77, 0xca, 0x68, 0x2b, 0x7b, 0x41, 0x46, + 0x96, 0xe1, 0x32, 0xd7, 0xbd, 0xdd, 0x85, 0x13, 0xa5, 0x63, 0x84, 0x47, 0xee, 0x1e, 0x38, 0x4e, 0x92, 0x64, 0x91, + 0x64, 0x90, 0x0d, 0x1d, 0x28, 0xb4, 0x36, 0xfb, 0x2a, 0x56, 0xe4, 0xb1, 0x4e, 0x04, 0xbb, 0x35, 0xdd, 0xc6, 0xa8, + 0x3a, 0xc4, 0xfd, 0x7e, 0xbb, 0xa0, 0x5d, 0x43, 0x80, 0x54, 0x22, 0xe4, 0x88, 0x01, 0x84, 0xe0, 0xee, 0xdf, 0x25, + 0x4d, 0xa9, 0x0a, 0x6f, 0xb6, 0xaa, 0x01, 0xf6, 0x43, 0x95, 0xf7, 0x02, 0xf4, 0xc4, 0x86, 0x3d, 0x2b, 0x0b, 0x5b, + 0xe5, 0x39, 0x42, 0x7c, 0x1c, 0x2f, 0x12, 0xb8, 0x11, 0x34, 0x98, 0x24, 0x04, 0x5a, 0xad, 0x16, 0x21, 0x6e, 0x4d, + 0x2b, 0xc5, 0xf4, 0x98, 0x4c, 0xfb, 0x45, 0xa3, 0x61, 0x94, 0xd7, 0x23, 0x8b, 0x17, 0x0b, 0x84, 0xc7, 0xe5, 0x5e, + 0xf3, 0xe5, 0xe6, 0xa4, 0xde, 0x55, 0x3c, 0xae, 0x2b, 0x81, 0x1b, 0x42, 0x20, 0xa3, 0x5f, 0xd4, 0xd0, 0x3a, 0x9e, + 0x90, 0xa3, 0xb8, 0x9f, 0xf4, 0xfe, 0xe7, 0x00, 0xf5, 0xe2, 0xe4, 0x10, 0x1d, 0x59, 0x5a, 0x32, 0x46, 0xdd, 0xcc, + 0xf6, 0xb1, 0x34, 0xb7, 0x9f, 0x6d, 0x6c, 0x14, 0x90, 0xa9, 0xc4, 0x82, 0xce, 0x58, 0x3a, 0x81, 0x5d, 0xef, 0x91, + 0x67, 0x8e, 0x01, 0x99, 0xd2, 0x89, 0xa3, 0x2d, 0x49, 0xd4, 0x93, 0xb4, 0xfc, 0xea, 0x45, 0x3d, 0x5a, 0x7d, 0xfd, + 0xcf, 0xa8, 0x97, 0xd1, 0xf4, 0x31, 0x5f, 0x3b, 0x25, 0x79, 0xad, 0x8f, 0x33, 0xdf, 0xc7, 0xda, 0x2e, 0x4e, 0x00, + 0xbc, 0x11, 0xda, 0xd6, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0xa4, 0x12, 0x4d, 0x27, 0x00, 0xd5, 0x60, 0x11, + 0x54, 0x68, 0x1b, 0x10, 0x4c, 0x19, 0xb0, 0xc5, 0x23, 0x2d, 0x40, 0x73, 0x71, 0xd9, 0x42, 0xcb, 0x5a, 0x61, 0xc7, + 0x59, 0xd5, 0xef, 0xe2, 0x4b, 0xe2, 0x3d, 0x06, 0xaa, 0x7c, 0xb1, 0xe8, 0x8e, 0x1b, 0x0d, 0xa4, 0x3c, 0x7e, 0x8d, + 0xfa, 0xe3, 0x01, 0xbe, 0x05, 0x14, 0xc2, 0x35, 0x8c, 0xc2, 0xb5, 0x39, 0x76, 0xdc, 0x1c, 0x1b, 0x0d, 0xb9, 0x46, + 0xdd, 0xa0, 0xf2, 0xc2, 0x55, 0x5e, 0xaf, 0x2d, 0x64, 0x36, 0x31, 0xee, 0x1c, 0x99, 0x14, 0x30, 0x04, 0x23, 0x84, + 0xbc, 0x92, 0x68, 0x67, 0xb3, 0xd0, 0x28, 0x54, 0x37, 0xbb, 0x17, 0x28, 0xaa, 0x3d, 0x3d, 0x62, 0x80, 0x05, 0x54, + 0x2d, 0xd5, 0xc8, 0x53, 0x8d, 0x47, 0x8d, 0xb6, 0x41, 0xf7, 0x66, 0xbb, 0x5b, 0x6f, 0xec, 0x7e, 0xd5, 0x18, 0x1e, + 0x35, 0xc8, 0xb4, 0xda, 0xe1, 0x6b, 0xd9, 0x68, 0xac, 0xeb, 0xf7, 0xa5, 0x7e, 0x13, 0xd7, 0xee, 0x2f, 0x9e, 0x6e, + 0x99, 0x78, 0xf8, 0xd3, 0xb7, 0x3a, 0x6f, 0x45, 0xc2, 0x85, 0x60, 0x05, 0x9c, 0xb0, 0x44, 0x63, 0xb1, 0x5e, 0x97, + 0xa7, 0xfe, 0xef, 0xda, 0xda, 0x8c, 0x11, 0x0e, 0x74, 0xc8, 0x48, 0x6d, 0x58, 0xe2, 0x02, 0x53, 0x43, 0x45, 0x08, + 0x21, 0x1f, 0xb4, 0x37, 0x8f, 0xd1, 0x86, 0x24, 0x65, 0x24, 0x38, 0xbb, 0x63, 0x45, 0x58, 0x72, 0x7d, 0xef, 0xb1, + 0xfc, 0xae, 0x48, 0xd7, 0x17, 0x83, 0xd4, 0x14, 0xcb, 0x1d, 0x21, 0xcb, 0xc9, 0x17, 0x90, 0x73, 0xca, 0x0b, 0x96, + 0xc4, 0x10, 0xc4, 0x27, 0xbc, 0x60, 0x86, 0x71, 0xbf, 0xe7, 0xe5, 0xc6, 0xac, 0xce, 0x69, 0x66, 0xa1, 0xf6, 0x07, + 0xa0, 0x99, 0x83, 0x72, 0x48, 0x92, 0xad, 0x62, 0xd7, 0xf7, 0x1e, 0xbe, 0xde, 0x25, 0x43, 0xaf, 0x56, 0x4e, 0x7a, + 0xce, 0x80, 0xf5, 0xc1, 0x79, 0x35, 0xd4, 0xcc, 0xfd, 0x48, 0xe3, 0xcc, 0x30, 0x51, 0x79, 0xcc, 0x01, 0x99, 0xae, + 0xef, 0x3d, 0x7c, 0x17, 0x73, 0xa3, 0x9b, 0x42, 0x38, 0x9c, 0x77, 0x5c, 0x90, 0x98, 0x12, 0x86, 0xec, 0xe4, 0x4b, + 0x3a, 0x56, 0x04, 0xa7, 0x7b, 0x4a, 0x4d, 0x26, 0x88, 0x1d, 0x7d, 0x31, 0x20, 0x99, 0x03, 0x01, 0xc9, 0x10, 0xce, + 0x6a, 0x72, 0x1d, 0x31, 0x6b, 0x60, 0x3a, 0xbb, 0x82, 0xc5, 0x48, 0x2c, 0x7b, 0x88, 0x70, 0x66, 0xba, 0xd5, 0x6b, + 0x7b, 0x9c, 0x28, 0xba, 0x69, 0xe8, 0x56, 0xc9, 0xb3, 0xef, 0x41, 0xf0, 0xf2, 0x1f, 0xaf, 0x5c, 0xdb, 0x65, 0xc2, + 0x13, 0x6f, 0x91, 0x76, 0x7d, 0xef, 0xe1, 0xaf, 0xce, 0x28, 0x6d, 0x4e, 0x3d, 0xf9, 0xdf, 0x92, 0x51, 0x1f, 0xfe, + 0x9a, 0x54, 0xb9, 0xa6, 0xf0, 0xf5, 0xbd, 0x87, 0xbf, 0xef, 0x2a, 0x06, 0xe9, 0xeb, 0x45, 0xa5, 0x24, 0x30, 0xe3, + 0x5b, 0xb2, 0x3c, 0x5d, 0xba, 0xb3, 0x22, 0x15, 0x6b, 0x6c, 0x4e, 0xa8, 0x54, 0xad, 0x4b, 0xdd, 0xca, 0x13, 0x2c, + 0x89, 0xb9, 0x4a, 0xaa, 0x2f, 0x9b, 0x43, 0x63, 0x2e, 0xc5, 0x55, 0x26, 0xe7, 0xec, 0x1b, 0xf7, 0x4b, 0x4f, 0x35, + 0x4a, 0xf8, 0x0c, 0x0c, 0x71, 0xcc, 0xd8, 0x05, 0xde, 0x6f, 0xa1, 0xee, 0xc6, 0x79, 0x26, 0x0d, 0xa2, 0x16, 0xf5, + 0xc3, 0x06, 0x53, 0xd2, 0xc2, 0x19, 0x69, 0xe1, 0x9c, 0xa8, 0x7e, 0xcb, 0x9e, 0x18, 0xdd, 0xbc, 0x6c, 0xda, 0x9e, + 0x3b, 0xb0, 0xdd, 0x73, 0xbb, 0x6f, 0xed, 0xa1, 0x3c, 0xed, 0xe6, 0x46, 0x7f, 0x69, 0x0e, 0xfa, 0xa9, 0x41, 0x8d, + 0x27, 0x2c, 0x2e, 0x70, 0x61, 0x5a, 0xbe, 0xe2, 0xc3, 0x1c, 0xec, 0x54, 0x60, 0x66, 0x58, 0xa3, 0xb4, 0x2c, 0xdb, + 0x76, 0x65, 0xf3, 0xc4, 0xac, 0x55, 0x81, 0xf3, 0x04, 0x48, 0x39, 0xce, 0x9d, 0x5d, 0x8f, 0xda, 0xae, 0x72, 0x76, + 0x70, 0x10, 0xbb, 0x4a, 0x34, 0x2e, 0x7c, 0x7e, 0x75, 0x03, 0xf8, 0xde, 0x52, 0x8d, 0x29, 0x32, 0x13, 0x68, 0x34, + 0xb2, 0xc1, 0x9a, 0xee, 0x13, 0x12, 0xe7, 0x75, 0x28, 0xfa, 0xd1, 0x1b, 0x66, 0x70, 0x03, 0x00, 0x8d, 0x46, 0x79, + 0xdd, 0xbb, 0x01, 0xb1, 0xa7, 0x1a, 0xcb, 0xf5, 0x97, 0xb8, 0xb4, 0x26, 0x6a, 0x6d, 0xd9, 0x61, 0xf9, 0x51, 0x20, + 0x11, 0xe2, 0xae, 0xf0, 0xf3, 0x09, 0xb6, 0x86, 0x80, 0x72, 0x2f, 0x9c, 0x0d, 0x04, 0x36, 0x56, 0x5b, 0xae, 0x90, + 0x27, 0x6d, 0x1d, 0x94, 0xfa, 0x42, 0x70, 0xc1, 0x05, 0x85, 0x1a, 0x6b, 0x87, 0xe5, 0x4f, 0xd8, 0xb6, 0x39, 0x27, + 0x56, 0xc8, 0x69, 0xcb, 0xcc, 0x30, 0x0c, 0xc0, 0x3a, 0x25, 0x60, 0x9e, 0x93, 0x97, 0xdf, 0x46, 0xfd, 0x87, 0x01, + 0xea, 0x3f, 0x22, 0x2c, 0xd8, 0x06, 0x56, 0x57, 0x92, 0x48, 0xa7, 0xa0, 0x50, 0x3e, 0xeb, 0xf1, 0x9c, 0x80, 0x36, + 0xae, 0x0e, 0xd5, 0xda, 0x15, 0xe5, 0x37, 0x28, 0x4b, 0xb8, 0x53, 0x8c, 0x3e, 0x13, 0xfb, 0xfb, 0xe4, 0xb8, 0xba, + 0xa0, 0x83, 0xae, 0x77, 0x29, 0x07, 0x43, 0x52, 0xf8, 0xf0, 0xf7, 0xef, 0xdf, 0xad, 0x3e, 0x9e, 0x6f, 0xef, 0xe0, + 0xc0, 0xac, 0x14, 0x66, 0x1d, 0x6c, 0xe0, 0xba, 0x91, 0x29, 0xf4, 0x5f, 0xde, 0x89, 0xd7, 0xa9, 0xd0, 0xc6, 0x66, + 0xf4, 0xc7, 0x21, 0x8c, 0xb6, 0xdd, 0x36, 0x25, 0x58, 0xd0, 0x2c, 0xd0, 0x25, 0x6b, 0xdc, 0x4a, 0x8b, 0x6f, 0x90, + 0x91, 0x87, 0xa6, 0x00, 0x13, 0xa3, 0xdd, 0xd9, 0x8f, 0xd6, 0x0e, 0x4f, 0xec, 0xd0, 0xd0, 0xd2, 0x10, 0x42, 0x8b, + 0xf7, 0x80, 0x39, 0xf6, 0x88, 0x00, 0x10, 0xbd, 0x34, 0x90, 0xaa, 0x40, 0x16, 0x45, 0x95, 0x22, 0xff, 0xf9, 0x3e, + 0x21, 0x2f, 0x2b, 0x45, 0xe6, 0xdb, 0xca, 0x98, 0x0b, 0x10, 0x03, 0xa5, 0x70, 0x91, 0x50, 0x26, 0xd8, 0xcb, 0xd0, + 0x0f, 0xda, 0x97, 0x37, 0xd2, 0x66, 0x52, 0x71, 0xe3, 0xc1, 0x4d, 0xa9, 0x51, 0xf1, 0xd9, 0x7c, 0x0f, 0x89, 0x8d, + 0xdc, 0x7b, 0x90, 0xcb, 0xa8, 0x19, 0x24, 0x7c, 0xbf, 0x33, 0xa5, 0x7d, 0xbb, 0xeb, 0xcf, 0x9b, 0x16, 0x31, 0x1b, + 0xeb, 0x92, 0x70, 0xa1, 0x58, 0xa1, 0x1f, 0xb1, 0xb1, 0x2c, 0xe0, 0xfe, 0xa3, 0x04, 0x0b, 0x5a, 0xdf, 0x0b, 0x74, + 0x80, 0x66, 0x82, 0xc1, 0xa5, 0xc3, 0xc6, 0x0c, 0xcd, 0xaf, 0xcf, 0xe6, 0x0e, 0xfc, 0x7a, 0xb3, 0xd6, 0xcb, 0x83, + 0x83, 0x2f, 0xac, 0x02, 0x94, 0x1b, 0xa6, 0x19, 0x46, 0x40, 0xbc, 0x2c, 0x97, 0xe3, 0x6e, 0x86, 0xef, 0xc5, 0x95, + 0xca, 0xc0, 0x13, 0x8e, 0x90, 0x08, 0x3d, 0x27, 0x7a, 0x3d, 0xd9, 0xa4, 0xf7, 0x4e, 0x9b, 0x21, 0x42, 0xb1, 0x06, + 0xc8, 0x3d, 0xc8, 0xe5, 0x56, 0xc9, 0xa4, 0x2a, 0x5b, 0xdb, 0x72, 0x10, 0x8f, 0x01, 0x5c, 0xb1, 0x11, 0x52, 0x02, + 0x34, 0xdc, 0x2d, 0xb4, 0x3c, 0x97, 0xc0, 0xfe, 0x63, 0x95, 0x80, 0x48, 0x8b, 0x6a, 0x1b, 0x17, 0x21, 0x6c, 0x4d, + 0x7d, 0x02, 0xe3, 0x84, 0x87, 0xcf, 0x77, 0x69, 0xa8, 0x3d, 0x6a, 0x33, 0x73, 0x06, 0x41, 0x09, 0x89, 0xca, 0x0a, + 0xc9, 0x97, 0x58, 0x38, 0x6e, 0xce, 0xdf, 0xc3, 0x01, 0x29, 0x56, 0x34, 0xb6, 0x77, 0x5b, 0x70, 0x7c, 0x14, 0xc9, + 0x22, 0xae, 0x75, 0xdd, 0x2d, 0x4c, 0x35, 0xec, 0x40, 0x47, 0x43, 0x38, 0x15, 0xe6, 0x9e, 0xf0, 0x71, 0x45, 0x52, + 0x7f, 0xb6, 0x26, 0xda, 0xda, 0x13, 0xc3, 0xca, 0x34, 0x25, 0x98, 0xff, 0xcf, 0xd6, 0xea, 0xba, 0x2c, 0x84, 0x99, + 0x19, 0xc6, 0x8d, 0x5d, 0x05, 0xb6, 0x06, 0x1c, 0x5b, 0xfe, 0x2d, 0x83, 0x45, 0xf5, 0x4a, 0x71, 0xd3, 0x69, 0xc0, + 0x04, 0xbc, 0x05, 0xeb, 0x99, 0xcd, 0xad, 0xff, 0xdc, 0x1c, 0x8c, 0x02, 0xab, 0x1a, 0x81, 0x97, 0x86, 0xc0, 0x23, + 0x60, 0xdc, 0xbc, 0x69, 0x79, 0xcf, 0x19, 0xd1, 0x08, 0x7f, 0xe2, 0x39, 0x3c, 0xb3, 0x2c, 0xf7, 0xd6, 0xc7, 0xc6, + 0x8a, 0xa4, 0x82, 0x80, 0x6d, 0x11, 0x76, 0x44, 0x5e, 0x22, 0xac, 0x1a, 0x8d, 0xae, 0xba, 0x60, 0x95, 0x56, 0xa5, + 0x1a, 0xa6, 0x80, 0x5b, 0x62, 0xc0, 0xfb, 0xda, 0x89, 0x0a, 0x86, 0x04, 0xde, 0xfa, 0x5b, 0x81, 0xfa, 0xfe, 0xe1, + 0xdb, 0x38, 0xa4, 0x6f, 0x61, 0xd9, 0xf2, 0x22, 0x16, 0xa6, 0x14, 0x57, 0x77, 0x38, 0x6f, 0xbe, 0x6f, 0x36, 0x02, + 0xe3, 0xde, 0x6f, 0x63, 0xb0, 0x71, 0x43, 0x5d, 0x6d, 0x49, 0x43, 0xb9, 0x09, 0xbb, 0xa8, 0xb2, 0x77, 0x0c, 0x3b, + 0xeb, 0xea, 0x4a, 0xda, 0xd5, 0x44, 0xad, 0xd7, 0x8a, 0x55, 0x46, 0x03, 0x1b, 0x86, 0x9d, 0xe6, 0x98, 0xd9, 0x56, + 0xe0, 0x3f, 0x9e, 0x13, 0x8d, 0x03, 0x64, 0x7d, 0xf3, 0xad, 0xeb, 0x94, 0x6a, 0x98, 0xb0, 0xbd, 0xdd, 0xf9, 0xf8, + 0x98, 0xef, 0x3a, 0x1f, 0xb1, 0x74, 0x5b, 0xdf, 0x9c, 0x8d, 0xed, 0x7f, 0xe3, 0x6c, 0x74, 0x6a, 0x7b, 0x7f, 0x3c, + 0x02, 0x77, 0x52, 0x3b, 0x1e, 0xeb, 0x6b, 0x4a, 0x24, 0x16, 0x6e, 0x39, 0x2e, 0x3b, 0xab, 0x95, 0xe8, 0xb7, 0x40, + 0xed, 0x14, 0x45, 0xf0, 0xb3, 0x6d, 0x7f, 0x06, 0x24, 0xd9, 0xea, 0x90, 0x63, 0x51, 0x8a, 0x32, 0x28, 0x01, 0x03, + 0xea, 0xd8, 0xd8, 0x7a, 0x19, 0xc4, 0x76, 0x38, 0xe4, 0xb0, 0x9c, 0x88, 0xf2, 0xea, 0x0a, 0x46, 0x6c, 0x8e, 0x0d, + 0x27, 0x60, 0xc6, 0x3b, 0xad, 0x0a, 0xbd, 0xf8, 0xf9, 0xaf, 0x99, 0xd3, 0xda, 0x11, 0x63, 0x39, 0x89, 0x9a, 0x15, + 0x83, 0x1b, 0x81, 0x63, 0x18, 0xf7, 0x8d, 0x84, 0x5a, 0x9d, 0xea, 0xa8, 0x76, 0x24, 0xe1, 0x16, 0xa8, 0xdd, 0xf6, + 0xcd, 0xb9, 0xb4, 0x5a, 0xed, 0x3c, 0x58, 0x70, 0x11, 0xe0, 0xf6, 0x73, 0xa2, 0x6b, 0x24, 0x85, 0x12, 0x27, 0x41, + 0xe1, 0xdc, 0xa0, 0xaa, 0x26, 0xb2, 0xdf, 0x1a, 0x00, 0x4f, 0xda, 0xcd, 0x2e, 0x64, 0x25, 0x24, 0x67, 0x8d, 0x06, + 0xca, 0xcb, 0x8e, 0x69, 0x5f, 0x34, 0xb2, 0x01, 0x66, 0x38, 0xb3, 0x02, 0x0b, 0x9c, 0x5e, 0x71, 0x5e, 0x75, 0xdd, + 0xcf, 0x06, 0x08, 0x17, 0xab, 0x55, 0x6c, 0x87, 0x96, 0xa3, 0xd5, 0x2a, 0x0f, 0x87, 0x66, 0xf2, 0xa1, 0xe2, 0xcb, + 0x9e, 0x26, 0x2f, 0xcd, 0x79, 0xf8, 0x12, 0x06, 0xd9, 0x20, 0x71, 0xee, 0x54, 0x82, 0x39, 0x68, 0xae, 0x1a, 0xb2, + 0x9f, 0x35, 0xda, 0x83, 0x80, 0x86, 0xf5, 0xb3, 0x01, 0xc9, 0xd7, 0x60, 0x39, 0xab, 0xdc, 0x81, 0xf9, 0x37, 0x1c, + 0x6c, 0x7f, 0x9b, 0x73, 0xc6, 0x36, 0x18, 0xae, 0xc9, 0xa6, 0xca, 0xa0, 0xc4, 0x2b, 0xb7, 0xb8, 0xbe, 0x5c, 0xcd, + 0xc0, 0xa2, 0x2c, 0x84, 0xdd, 0x35, 0x73, 0x0f, 0x84, 0xff, 0x12, 0xdb, 0x25, 0x2d, 0x8d, 0xb8, 0x37, 0x10, 0xdf, + 0xdb, 0x6e, 0x27, 0x49, 0x42, 0x8b, 0x89, 0xb9, 0x12, 0xf1, 0x37, 0xbc, 0x66, 0x0f, 0x1c, 0xbb, 0x71, 0x06, 0x3d, + 0xf7, 0xcb, 0xce, 0x06, 0xc4, 0x8e, 0xdf, 0x33, 0x3b, 0xde, 0x71, 0xa5, 0xa0, 0xbb, 0x75, 0x11, 0x76, 0x30, 0xf4, + 0x7f, 0x79, 0x30, 0x27, 0x6e, 0x30, 0x16, 0x4d, 0x36, 0xe0, 0xf6, 0x0d, 0x78, 0x14, 0x74, 0x03, 0x6e, 0xdf, 0x86, + 0xaf, 0x87, 0x56, 0xf6, 0xcd, 0x01, 0x06, 0x64, 0xc2, 0x8e, 0xb4, 0x4a, 0x08, 0x86, 0x79, 0xba, 0xc9, 0x91, 0x59, + 0xb2, 0x0a, 0x87, 0xab, 0x26, 0xb1, 0xd8, 0xd8, 0x0b, 0x15, 0x93, 0x1a, 0x08, 0xc6, 0x22, 0x7d, 0x89, 0x42, 0xa5, + 0x41, 0xdd, 0x38, 0x06, 0xb0, 0xca, 0x69, 0xeb, 0x5f, 0x1e, 0x1c, 0x80, 0xd0, 0x00, 0xac, 0x5d, 0x92, 0xd1, 0xb9, + 0x5e, 0x14, 0xc0, 0x5f, 0x29, 0xff, 0x1b, 0x92, 0xc1, 0xed, 0xc4, 0xa4, 0xc1, 0x0f, 0x48, 0x98, 0x53, 0xa5, 0xf8, + 0x17, 0x9b, 0xe6, 0x7e, 0xe3, 0x82, 0x78, 0x8c, 0x56, 0x96, 0x53, 0x94, 0xa8, 0x2b, 0x1d, 0xba, 0xd6, 0x21, 0xf7, + 0xf4, 0x0b, 0x13, 0xfa, 0x25, 0x57, 0x9a, 0x09, 0x00, 0x40, 0x85, 0x78, 0x30, 0x25, 0x85, 0x60, 0xeb, 0xd6, 0x6a, + 0xd1, 0xd1, 0xe8, 0xbb, 0x55, 0x74, 0x9d, 0x2d, 0x9a, 0x52, 0x31, 0xca, 0x6d, 0x27, 0xa1, 0xcd, 0xa4, 0xb7, 0x13, + 0x2d, 0x4b, 0x86, 0x16, 0x3b, 0x15, 0xfb, 0x61, 0x68, 0x7d, 0x2c, 0x88, 0x3f, 0x17, 0xfc, 0x59, 0xfa, 0x5d, 0x3e, + 0x06, 0xae, 0xd4, 0xbf, 0xb1, 0x0a, 0xe1, 0x4c, 0xb0, 0x0e, 0xc8, 0x6b, 0x52, 0x1f, 0xa7, 0x47, 0x9d, 0x7c, 0x4b, + 0xb9, 0x50, 0x1a, 0x85, 0x6d, 0x9c, 0x14, 0x06, 0x53, 0xce, 0xbe, 0x2d, 0x71, 0xfd, 0xea, 0x8f, 0x11, 0x7f, 0x74, + 0x88, 0x7f, 0x97, 0x4a, 0xa3, 0x65, 0x89, 0x60, 0xc8, 0xef, 0x48, 0xad, 0xe0, 0x2a, 0x36, 0xe7, 0xfa, 0xb9, 0x9e, + 0xe5, 0x1b, 0x9e, 0x38, 0x5d, 0xad, 0x4a, 0xa9, 0x40, 0xc5, 0x37, 0x0c, 0x3f, 0x61, 0x70, 0x6f, 0xfc, 0x8c, 0x07, + 0x55, 0xb6, 0xef, 0x8b, 0x9f, 0x05, 0xf7, 0xc5, 0xcf, 0x78, 0xba, 0x5d, 0x34, 0xb8, 0x27, 0xee, 0x24, 0xe7, 0x49, + 0x2b, 0xf2, 0x7c, 0xd4, 0x94, 0x56, 0xfe, 0x95, 0x76, 0x6b, 0xe0, 0xca, 0x26, 0x0e, 0x8c, 0xf3, 0xea, 0x22, 0x14, + 0x73, 0xe6, 0x8c, 0x96, 0xc3, 0xff, 0xd6, 0x3a, 0xb9, 0x93, 0x47, 0x5a, 0x29, 0xe4, 0x0d, 0x2d, 0xf4, 0x3d, 0xd8, + 0x70, 0xc5, 0x96, 0x0f, 0x20, 0x25, 0xa0, 0x6c, 0xfb, 0xf7, 0xba, 0x08, 0xc4, 0x71, 0x65, 0x9d, 0x8f, 0xc2, 0xf6, + 0x49, 0x51, 0x72, 0x75, 0x75, 0x21, 0xe4, 0xd6, 0x68, 0x09, 0x10, 0xa6, 0xde, 0x35, 0x8f, 0x39, 0x9a, 0xcc, 0xd2, + 0xe5, 0xba, 0x54, 0x1d, 0x14, 0x96, 0xab, 0xe3, 0x08, 0x17, 0x6b, 0x73, 0x83, 0xfe, 0x8a, 0xe3, 0xbf, 0xb9, 0xa3, + 0x91, 0x9f, 0x4a, 0x0a, 0xf4, 0x68, 0xb7, 0xaf, 0xcd, 0x0e, 0x12, 0x69, 0xe7, 0x50, 0x5a, 0x0a, 0x00, 0x56, 0x1b, + 0x7c, 0x5d, 0x7b, 0x9c, 0x7a, 0x22, 0xdd, 0x6c, 0xbe, 0x69, 0x08, 0x8b, 0x59, 0x69, 0xc1, 0x63, 0xba, 0xd9, 0x61, + 0x39, 0xea, 0x65, 0x71, 0x5d, 0xee, 0xb1, 0x5a, 0xbf, 0xe8, 0x1b, 0xa0, 0xac, 0x0c, 0xd1, 0x56, 0xab, 0xb8, 0x0e, + 0x6f, 0x22, 0x82, 0x6b, 0x10, 0x84, 0x45, 0x60, 0xc0, 0x51, 0x63, 0xbc, 0x6d, 0x9d, 0x18, 0x6d, 0xda, 0x2f, 0x79, + 0xd6, 0xbd, 0x36, 0x8e, 0x50, 0xd1, 0x60, 0xab, 0x87, 0x9a, 0x07, 0x6c, 0x67, 0x57, 0x76, 0x14, 0x40, 0x68, 0x4a, + 0xbd, 0x71, 0x6e, 0x65, 0x45, 0xbb, 0x03, 0xbe, 0xe8, 0x3b, 0xe6, 0xb9, 0x0e, 0x74, 0xdb, 0xf9, 0x81, 0x6d, 0xd3, + 0x13, 0xf9, 0x2d, 0xdb, 0xa6, 0x1a, 0x27, 0xbc, 0xdf, 0x42, 0xdf, 0x37, 0x84, 0xb5, 0x7d, 0xed, 0x2e, 0xf2, 0xbf, + 0xd0, 0x5d, 0x1b, 0xd0, 0xd3, 0x82, 0xd9, 0xd3, 0x98, 0x0f, 0x7a, 0xbd, 0xfe, 0x54, 0xfa, 0x2f, 0x18, 0x5b, 0xa1, + 0x4f, 0x76, 0x17, 0x38, 0xb1, 0xd2, 0x38, 0x04, 0xc7, 0xaf, 0x38, 0x99, 0xe4, 0x72, 0x48, 0xf3, 0x77, 0xd0, 0x63, + 0x95, 0xfb, 0xfc, 0x6e, 0x54, 0x50, 0xcd, 0x1c, 0xad, 0xa9, 0x46, 0xf1, 0x8a, 0x07, 0xc3, 0x78, 0xc5, 0x2d, 0xe5, + 0xae, 0x5a, 0xc0, 0xcb, 0x97, 0x65, 0x13, 0xe9, 0xa7, 0x75, 0x29, 0x83, 0xa9, 0xdd, 0xbd, 0x6c, 0x92, 0x34, 0x56, + 0x92, 0x34, 0xa6, 0xe2, 0xcd, 0xa6, 0xe2, 0xf8, 0xef, 0x6f, 0x0c, 0x76, 0x9b, 0xcc, 0xfd, 0x1d, 0x90, 0xb9, 0xbf, + 0x79, 0xfa, 0xdd, 0x5a, 0x01, 0xc5, 0x3b, 0x4e, 0x8e, 0x8d, 0x65, 0x8c, 0x1d, 0xf5, 0x5b, 0x0d, 0x06, 0x0d, 0x9a, + 0x5c, 0x06, 0xde, 0x0e, 0xd5, 0xe9, 0xe5, 0xed, 0x8f, 0xe2, 0x6c, 0xa1, 0xb4, 0x9c, 0xb9, 0x46, 0x95, 0xf3, 0x71, + 0x32, 0x99, 0xa0, 0xc0, 0x36, 0x77, 0xf8, 0x69, 0xdd, 0x8d, 0x6c, 0xf9, 0x99, 0x8b, 0x51, 0xaa, 0xb0, 0x3b, 0x5b, + 0x54, 0x2a, 0xd7, 0xc4, 0x9b, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0x17, 0x5c, 0x4d, 0x59, 0x11, 0x17, 0x68, 0xf9, 0xad, + 0xce, 0x0a, 0xb8, 0xcd, 0xb1, 0x9d, 0xe1, 0x51, 0x69, 0x39, 0xa0, 0x13, 0x68, 0x0d, 0x74, 0x46, 0x33, 0xa6, 0xa7, + 0x72, 0x04, 0x86, 0x2f, 0xc9, 0xa8, 0x74, 0xa7, 0x3a, 0x38, 0xd8, 0x8f, 0x23, 0xa3, 0xbf, 0x00, 0x1f, 0xf4, 0x30, + 0x07, 0xf5, 0x96, 0xe0, 0x18, 0x54, 0x75, 0xcd, 0xd0, 0x92, 0x6d, 0xfa, 0xd0, 0xe8, 0xe4, 0x33, 0xbb, 0xc3, 0x1c, + 0xad, 0xd7, 0xa9, 0x1d, 0x75, 0x34, 0xe6, 0x2c, 0x1f, 0x45, 0xf8, 0x33, 0xbb, 0x4b, 0x4b, 0xb7, 0x75, 0xe3, 0x65, + 0x6d, 0x16, 0x31, 0x92, 0x37, 0x22, 0xc2, 0x55, 0x27, 0xe9, 0x72, 0x8d, 0x65, 0xc1, 0x27, 0x80, 0xa3, 0xbf, 0xb0, + 0xbb, 0xd4, 0xb5, 0x17, 0xb8, 0x0a, 0xa2, 0xa5, 0x07, 0x7d, 0x12, 0x24, 0x87, 0xcb, 0xe0, 0x04, 0x8e, 0xbe, 0xa9, + 0x3b, 0x20, 0xb5, 0x72, 0x95, 0x08, 0x89, 0xd0, 0xfa, 0xdf, 0x9d, 0x0a, 0x5e, 0x84, 0xe7, 0x9c, 0xae, 0x59, 0xdc, + 0x6e, 0x54, 0x62, 0x50, 0xa1, 0xb2, 0x20, 0xf9, 0x18, 0x73, 0xbf, 0xfb, 0x9c, 0xf7, 0x43, 0xa0, 0x33, 0x5b, 0x50, + 0xd7, 0x68, 0x3a, 0x32, 0xbf, 0x50, 0x75, 0x07, 0x35, 0xd3, 0x55, 0xc5, 0xbd, 0x8f, 0x31, 0x00, 0x1e, 0xac, 0x65, + 0xa8, 0x71, 0x08, 0x5d, 0x7b, 0x33, 0xd5, 0x31, 0x25, 0xf1, 0xd2, 0xcf, 0x21, 0xe5, 0x21, 0x18, 0xf5, 0x1a, 0xd0, + 0xd0, 0x21, 0x98, 0xb5, 0x3c, 0xe4, 0xe3, 0x58, 0x6c, 0x9d, 0xa1, 0xd2, 0x9c, 0xa1, 0x49, 0x00, 0xf2, 0x6f, 0x9c, + 0x99, 0xcc, 0x40, 0xc3, 0xf0, 0x96, 0xe6, 0x00, 0x74, 0xab, 0xeb, 0x70, 0x28, 0x5c, 0xd1, 0xd2, 0x79, 0xcf, 0x2e, + 0xba, 0xac, 0x0d, 0x2b, 0x36, 0xed, 0xa0, 0x75, 0x0a, 0x53, 0x62, 0xb6, 0xc0, 0xda, 0xeb, 0x7d, 0xb8, 0xb7, 0xab, + 0x8d, 0x8b, 0xc4, 0x4f, 0x8b, 0x78, 0x98, 0xc4, 0x14, 0x2d, 0x79, 0x4c, 0xb1, 0x04, 0x3b, 0xc8, 0x62, 0x5d, 0x8e, + 0x9f, 0x85, 0xcb, 0x51, 0xb3, 0x92, 0xde, 0xed, 0x60, 0x08, 0x5c, 0xbe, 0x06, 0xdb, 0x50, 0xcc, 0x3d, 0x61, 0xe1, + 0xb1, 0xf1, 0xf4, 0x0b, 0xd6, 0x6d, 0x6e, 0x17, 0xc4, 0xaf, 0xc0, 0x98, 0xc6, 0xcb, 0x60, 0x16, 0xa1, 0x53, 0xb9, + 0x73, 0x38, 0x74, 0xd7, 0x84, 0x95, 0xf1, 0x6a, 0xac, 0xc8, 0xc6, 0xd1, 0xf3, 0x7d, 0x1b, 0xcf, 0x7f, 0x16, 0xac, + 0xb8, 0xbb, 0x62, 0x60, 0x63, 0x2d, 0xc1, 0xdd, 0xb8, 0x5a, 0x86, 0xca, 0x40, 0xbe, 0x27, 0x0d, 0xeb, 0xb2, 0xc6, + 0xdf, 0x8d, 0x8a, 0xb1, 0x36, 0xf7, 0x94, 0x81, 0xb6, 0xc6, 0x6e, 0x17, 0xf6, 0x4d, 0xd7, 0x4d, 0xd6, 0x35, 0x8a, + 0xb8, 0x0a, 0xd2, 0xee, 0x6e, 0x01, 0x17, 0xa1, 0x3f, 0x6c, 0x5f, 0x0d, 0x36, 0x55, 0x37, 0x90, 0x04, 0xd7, 0x7e, + 0xf2, 0xdb, 0x53, 0xdd, 0x65, 0xad, 0xfb, 0xed, 0xa9, 0xd6, 0x2e, 0x0b, 0x8d, 0x21, 0x11, 0x76, 0xfd, 0x94, 0xfe, + 0xd3, 0x62, 0xbd, 0x46, 0x6b, 0x18, 0xde, 0x7b, 0xde, 0x8d, 0xe3, 0xf7, 0xde, 0x42, 0x31, 0x81, 0x8b, 0xdc, 0xab, + 0x5c, 0x7a, 0x42, 0x5e, 0x8d, 0xe0, 0x3d, 0xdf, 0x1a, 0xc2, 0x7b, 0x1e, 0x38, 0xbd, 0x82, 0xd4, 0x34, 0x11, 0x6c, + 0xe4, 0xe9, 0x27, 0xb2, 0x48, 0x68, 0xf8, 0xb8, 0xd7, 0x9c, 0x70, 0xfd, 0x57, 0x0a, 0xfc, 0x17, 0x1e, 0x2e, 0xb4, + 0x96, 0x02, 0x73, 0x31, 0x5f, 0x68, 0xac, 0xcc, 0xe8, 0x97, 0x63, 0x29, 0x74, 0x73, 0x4c, 0x67, 0x3c, 0xbf, 0x4b, + 0x17, 0xbc, 0x39, 0x93, 0x42, 0xaa, 0x39, 0xcd, 0x18, 0x56, 0x77, 0x4a, 0xb3, 0x59, 0x73, 0xc1, 0xf1, 0x73, 0x96, + 0x7f, 0x61, 0x9a, 0x67, 0x14, 0xbf, 0x95, 0x43, 0xa9, 0x25, 0x7e, 0x7d, 0x7b, 0x37, 0x61, 0x02, 0xff, 0x3e, 0x5c, + 0x08, 0xbd, 0xc0, 0x8a, 0x0a, 0xd5, 0x54, 0xac, 0xe0, 0xe3, 0x6e, 0xb3, 0x39, 0x2f, 0xf8, 0x8c, 0x16, 0x77, 0xcd, + 0x4c, 0xe6, 0xb2, 0x48, 0xff, 0xab, 0x75, 0x4c, 0x1f, 0x8c, 0x4f, 0xba, 0xba, 0xa0, 0x42, 0x71, 0x58, 0x98, 0x94, + 0xe6, 0xf9, 0xde, 0xf1, 0x69, 0x6b, 0xa6, 0xf6, 0xed, 0x85, 0x1f, 0x15, 0x7a, 0xfd, 0x17, 0xfe, 0x20, 0x61, 0x94, + 0xc9, 0x50, 0x0b, 0x37, 0xc8, 0x65, 0xb6, 0x28, 0x94, 0x2c, 0xd2, 0xb9, 0xe4, 0x42, 0xb3, 0xa2, 0x3b, 0x94, 0xc5, + 0x88, 0x15, 0xcd, 0x82, 0x8e, 0xf8, 0x42, 0xa5, 0x27, 0xf3, 0xdb, 0x6e, 0xbd, 0x07, 0x9b, 0x9f, 0x0a, 0x29, 0x58, + 0x17, 0xf8, 0x8d, 0x49, 0x21, 0x17, 0x62, 0xe4, 0x86, 0xb1, 0x10, 0x8a, 0xe9, 0xee, 0x9c, 0x8e, 0xc0, 0x0e, 0x38, + 0x3d, 0x9f, 0xdf, 0x76, 0xcd, 0xac, 0x6f, 0x18, 0x9f, 0x4c, 0x75, 0x7a, 0xda, 0x6a, 0xd9, 0x6f, 0xc5, 0xbf, 0xb2, + 0xb4, 0xdd, 0x49, 0x3a, 0xa7, 0xf3, 0x5b, 0xe0, 0xe0, 0x35, 0x2b, 0x9a, 0x00, 0x0b, 0xa8, 0xd4, 0x4e, 0x5a, 0x0f, + 0x8e, 0xef, 0x43, 0x06, 0xd8, 0x38, 0x34, 0xcd, 0x84, 0xc0, 0xd8, 0x3d, 0x5d, 0xcc, 0xe7, 0xac, 0x00, 0x2f, 0xfa, + 0xee, 0x8c, 0x16, 0x13, 0x2e, 0x9a, 0x85, 0x69, 0xb4, 0x79, 0x3e, 0xbf, 0x5d, 0xc3, 0x7c, 0x52, 0x6b, 0xb6, 0xea, + 0xa6, 0xe5, 0xbe, 0x96, 0xc1, 0x10, 0x4d, 0x4c, 0x9a, 0xb4, 0x98, 0x0c, 0x69, 0xdc, 0xee, 0xdc, 0xc7, 0xfe, 0x7f, + 0x49, 0x07, 0x05, 0x60, 0x6b, 0x8e, 0x16, 0x85, 0xb9, 0x45, 0x4d, 0xdb, 0xca, 0x36, 0x3b, 0x95, 0x5f, 0x58, 0xe1, + 0x5b, 0x35, 0x1f, 0xcb, 0xad, 0x79, 0xff, 0x27, 0x8d, 0xfe, 0x85, 0x27, 0x14, 0xd6, 0xc0, 0x20, 0x47, 0xdf, 0xc8, + 0x83, 0x30, 0xd3, 0xc1, 0xf2, 0x86, 0x8f, 0xf4, 0x34, 0x6d, 0xb7, 0x5a, 0x3f, 0x54, 0x2b, 0xd6, 0x9d, 0x5a, 0xd0, + 0xb5, 0x0b, 0x36, 0xab, 0xad, 0xe3, 0x8c, 0x96, 0xd8, 0xb6, 0x9c, 0x4b, 0xb7, 0xe4, 0x05, 0xcb, 0x4d, 0x34, 0x99, + 0xb5, 0x43, 0xb9, 0xad, 0x71, 0x72, 0x31, 0x65, 0x05, 0xd7, 0xdd, 0xfa, 0x57, 0xd5, 0xf1, 0xf6, 0xea, 0xaf, 0xad, + 0x1c, 0xba, 0xb4, 0x35, 0xdc, 0xa5, 0xe7, 0x63, 0xf8, 0xd8, 0x5e, 0xfd, 0x2f, 0xb4, 0x88, 0x37, 0x10, 0x13, 0x87, + 0x35, 0xd0, 0x3a, 0x98, 0x73, 0x01, 0x26, 0x99, 0x03, 0xfc, 0x0d, 0x28, 0x64, 0x34, 0xcf, 0x62, 0x18, 0xd1, 0x5e, + 0x73, 0xef, 0xb8, 0x60, 0x33, 0xe4, 0x01, 0x91, 0xdc, 0x3f, 0x2d, 0xd8, 0x6c, 0x9d, 0x98, 0xea, 0x4b, 0x83, 0x22, + 0x34, 0xe7, 0x13, 0x91, 0x66, 0x0c, 0xd0, 0x77, 0x9d, 0x30, 0xa1, 0xb9, 0xbe, 0x6b, 0x16, 0xf2, 0x66, 0x39, 0xe2, + 0x6a, 0x9e, 0xd3, 0xbb, 0x74, 0x9c, 0xb3, 0xdb, 0xae, 0x29, 0xd5, 0xe4, 0x9a, 0xcd, 0x94, 0x2b, 0xdb, 0x85, 0xf4, + 0xe6, 0xc8, 0x9a, 0x4d, 0x00, 0xf4, 0xe4, 0xcd, 0xe6, 0xfe, 0x49, 0x8e, 0xd5, 0x1e, 0xa3, 0x8a, 0x35, 0xe5, 0x42, + 0xef, 0xb5, 0x54, 0x77, 0xc6, 0x45, 0xd3, 0x0d, 0xe4, 0xa4, 0x35, 0xbf, 0xed, 0x6e, 0x43, 0x3e, 0xe8, 0x3f, 0x61, + 0xb7, 0x73, 0x2a, 0x46, 0x6c, 0xb4, 0x0c, 0xaa, 0x75, 0xa0, 0x5e, 0x58, 0x2a, 0x15, 0x7a, 0xda, 0x34, 0xb6, 0x5e, + 0x71, 0x47, 0xa0, 0x6f, 0xa0, 0xd6, 0x83, 0x16, 0xb6, 0xff, 0x9f, 0xb4, 0x51, 0x58, 0x79, 0x0f, 0xc2, 0x2e, 0xf1, + 0xf1, 0x5d, 0x13, 0xfe, 0x2e, 0xc1, 0xb7, 0x88, 0x67, 0x34, 0x77, 0x10, 0x99, 0xf1, 0xd1, 0x28, 0xaf, 0x8d, 0xe8, + 0x32, 0xe8, 0xac, 0x8d, 0x96, 0x30, 0xff, 0xb4, 0xb5, 0xd7, 0xda, 0x33, 0x73, 0x71, 0xdb, 0xfc, 0xe4, 0xe4, 0xfe, + 0xf1, 0x03, 0xd6, 0xcd, 0xb9, 0x60, 0xb5, 0xa9, 0x7e, 0x17, 0xd4, 0x61, 0xc3, 0x1d, 0xd7, 0x70, 0x7b, 0xaf, 0xbd, + 0x77, 0xd2, 0xfa, 0xc1, 0xef, 0xd6, 0x9c, 0x8d, 0x75, 0xda, 0x3e, 0x9b, 0xdf, 0xd6, 0xb7, 0xef, 0xb9, 0x6f, 0xfa, + 0xa6, 0xa0, 0xf3, 0x54, 0x48, 0xf8, 0xd3, 0x85, 0x4d, 0x36, 0xce, 0xe5, 0x4d, 0x3a, 0xe5, 0xa3, 0x11, 0x13, 0xb6, + 0x40, 0x99, 0xc8, 0xf2, 0x9c, 0xcf, 0x15, 0xb7, 0xab, 0xe1, 0x70, 0xf7, 0x74, 0x03, 0xaa, 0xe1, 0x80, 0x8e, 0x83, + 0x01, 0x9d, 0x56, 0x03, 0xaa, 0xfa, 0x0f, 0x47, 0xd8, 0xd9, 0x98, 0xab, 0x29, 0xd5, 0xad, 0x61, 0xd2, 0xdf, 0x0b, + 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, + 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, + 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, + 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x70, 0xe7, 0x99, 0x76, 0x07, 0x69, 0xda, 0xbc, 0x61, + 0xc3, 0xcf, 0x5c, 0x5b, 0x3c, 0x6b, 0xaa, 0x1b, 0xf0, 0x78, 0x31, 0xcb, 0x30, 0x67, 0xc5, 0xd2, 0xd3, 0xf0, 0x56, + 0x8d, 0xea, 0x5c, 0x09, 0x73, 0x7a, 0x68, 0x3a, 0x6c, 0x42, 0xfc, 0x2f, 0x56, 0x94, 0x7b, 0x8c, 0x0b, 0x83, 0x31, + 0x06, 0x40, 0x9b, 0xbb, 0x24, 0x3c, 0x03, 0x4e, 0x5a, 0x2d, 0x7f, 0x3e, 0x34, 0x6d, 0x9d, 0xb4, 0x9d, 0x9c, 0xb2, + 0xd9, 0xae, 0xfd, 0x59, 0x27, 0x46, 0xed, 0xce, 0xfc, 0x76, 0xcf, 0xfc, 0xd3, 0xda, 0x6b, 0x6d, 0x13, 0x9f, 0x6d, + 0x38, 0x1d, 0x23, 0xbf, 0xb2, 0x5a, 0xce, 0xd3, 0x36, 0x9b, 0x75, 0x17, 0x0a, 0x0e, 0x1a, 0x43, 0x1b, 0xcd, 0x01, + 0xb6, 0x36, 0x33, 0x81, 0x75, 0xa4, 0x5c, 0x00, 0x5d, 0xb7, 0x67, 0x1b, 0xf4, 0xa1, 0x24, 0x18, 0x62, 0xef, 0x6c, + 0xb4, 0x3e, 0xac, 0xd6, 0x5e, 0x35, 0x30, 0xf8, 0x67, 0xfd, 0x57, 0xc5, 0x19, 0xbe, 0x60, 0x01, 0x67, 0xce, 0x1b, + 0xc9, 0xe9, 0xaa, 0xe5, 0xb8, 0xf1, 0x91, 0xae, 0x84, 0x04, 0xe3, 0xcb, 0x30, 0xa3, 0xb7, 0xd6, 0xa9, 0x61, 0xc6, + 0x05, 0x98, 0x4c, 0x21, 0xac, 0x03, 0xe3, 0xf2, 0x69, 0xd8, 0xd0, 0x48, 0xc7, 0xd0, 0xf0, 0x61, 0x27, 0x39, 0x3d, + 0x45, 0xb8, 0x85, 0x3b, 0xa7, 0xa7, 0x81, 0x34, 0x30, 0xd6, 0xbb, 0x8a, 0xee, 0x2a, 0xa9, 0x76, 0x94, 0x3c, 0x32, + 0x8d, 0x1e, 0xb5, 0x5b, 0x2d, 0x6c, 0x1c, 0xb7, 0xcb, 0xc2, 0x5c, 0xed, 0x68, 0xb6, 0xdd, 0x6a, 0x41, 0xb3, 0xf0, + 0xc7, 0xcd, 0xeb, 0x17, 0xb2, 0x6c, 0xa5, 0x2d, 0xdc, 0x4e, 0xdb, 0xb8, 0x93, 0x76, 0xf0, 0x71, 0x7a, 0x8c, 0x4f, + 0xd2, 0x13, 0x7c, 0x9a, 0x9e, 0xe2, 0xb3, 0xf4, 0x0c, 0xdf, 0x4f, 0xef, 0xe3, 0xf3, 0xf4, 0x1c, 0x3f, 0x48, 0x1f, + 0xe0, 0x87, 0x69, 0xbb, 0x85, 0x1f, 0xa5, 0xed, 0x36, 0x7e, 0x9c, 0xb6, 0x3b, 0xf8, 0x49, 0xda, 0x3e, 0xc6, 0x4f, + 0xd3, 0xf6, 0x09, 0x7e, 0x96, 0xb6, 0x4f, 0x31, 0x85, 0xdc, 0x21, 0xe4, 0x66, 0x90, 0x3b, 0x82, 0x5c, 0x06, 0xb9, + 0xe3, 0xb4, 0x7d, 0xba, 0xc6, 0xca, 0x06, 0x7b, 0x88, 0x5a, 0xed, 0xce, 0xf1, 0xc9, 0xe9, 0xd9, 0xfd, 0xf3, 0x07, + 0x0f, 0x1f, 0x3d, 0x7e, 0xf2, 0xf4, 0x59, 0x34, 0xc0, 0x43, 0xe3, 0x73, 0xa1, 0x44, 0x9f, 0x1f, 0xb4, 0x4f, 0x07, + 0xf8, 0xda, 0x7f, 0xc6, 0xfc, 0xa0, 0x73, 0xd2, 0x42, 0x97, 0x97, 0x27, 0x83, 0x46, 0x99, 0xfb, 0xde, 0xb8, 0x7a, + 0x54, 0x59, 0x84, 0x90, 0x18, 0x72, 0x10, 0xbe, 0x33, 0xf5, 0xde, 0xb3, 0x98, 0x27, 0x05, 0x3a, 0x38, 0x30, 0x3f, + 0x26, 0xfe, 0xc7, 0xd0, 0xff, 0xa0, 0xc1, 0x22, 0xdd, 0xd2, 0xd8, 0xf9, 0xfa, 0xea, 0xd2, 0xd2, 0xbe, 0x34, 0x62, + 0xd9, 0xe3, 0xce, 0x9c, 0xfc, 0xbf, 0x22, 0x6b, 0x2e, 0x42, 0x4e, 0xac, 0x4a, 0xe6, 0xb4, 0xc7, 0xc8, 0xb2, 0x48, + 0x3b, 0xa7, 0xa7, 0x07, 0xbf, 0xf4, 0x79, 0xbf, 0x3d, 0x18, 0x1c, 0xb6, 0xef, 0xe3, 0x49, 0x99, 0xd0, 0xb1, 0x09, + 0xc3, 0x32, 0xe1, 0xd8, 0x26, 0xd0, 0xd4, 0xd6, 0x86, 0xa4, 0x13, 0x93, 0x04, 0x25, 0xd6, 0xa9, 0x69, 0xfb, 0xbe, + 0x6d, 0xfb, 0x01, 0xd8, 0x31, 0x99, 0xe6, 0x5d, 0xd3, 0x17, 0x17, 0x27, 0x2b, 0xd7, 0x28, 0x9e, 0xa4, 0xae, 0x35, + 0x9f, 0x78, 0x32, 0x18, 0xe0, 0xa1, 0x49, 0x3c, 0xad, 0x12, 0xcf, 0x06, 0x03, 0xd7, 0xd5, 0x03, 0xd3, 0xd5, 0xfd, + 0x2a, 0xeb, 0x7c, 0x30, 0x30, 0x5d, 0x22, 0xe7, 0xb5, 0xae, 0xf4, 0xde, 0x97, 0x52, 0x73, 0xc0, 0x2f, 0x3a, 0xa7, + 0xa7, 0x3d, 0xc0, 0x30, 0x63, 0x8d, 0xea, 0x61, 0x74, 0x13, 0xc0, 0xe8, 0x0e, 0x7e, 0xf7, 0x86, 0x34, 0xbd, 0xa6, + 0x25, 0x90, 0x7a, 0xd1, 0x7f, 0x45, 0x0d, 0x6d, 0x60, 0x6e, 0xfe, 0x4c, 0xec, 0x9f, 0x21, 0x6a, 0x7c, 0xa1, 0x00, + 0x6e, 0xd0, 0x85, 0x78, 0x65, 0xa6, 0xe9, 0xf1, 0x33, 0x05, 0xe7, 0x92, 0xa9, 0xca, 0x69, 0x6f, 0x35, 0xbd, 0x19, + 0xae, 0xa6, 0xea, 0x0b, 0xfa, 0x33, 0xfe, 0x53, 0x1d, 0xc6, 0xfd, 0x66, 0x23, 0x61, 0x7f, 0x8e, 0xc0, 0x8b, 0xa5, + 0x97, 0x8e, 0xd8, 0x04, 0xf5, 0xfa, 0x7f, 0x2a, 0x3c, 0x68, 0x04, 0x19, 0x3f, 0x6c, 0xa7, 0x80, 0x8f, 0xcb, 0x66, + 0x62, 0xfc, 0x03, 0xea, 0xa1, 0xde, 0x9f, 0xea, 0xf0, 0x4f, 0x74, 0xef, 0xa8, 0x9a, 0xcb, 0xef, 0xd2, 0x6d, 0xe1, + 0x2a, 0xf0, 0xcd, 0x61, 0xb9, 0x85, 0x19, 0x6e, 0x37, 0x19, 0x84, 0x09, 0x03, 0x27, 0x68, 0x12, 0xcb, 0x06, 0x3f, + 0x3a, 0x6e, 0xa1, 0x1f, 0xda, 0x1d, 0x10, 0xeb, 0x9b, 0xe2, 0x70, 0x7b, 0xd3, 0x17, 0xcd, 0x63, 0xfc, 0xa0, 0x59, + 0xe0, 0x36, 0xc2, 0xcd, 0xb6, 0xd7, 0xb7, 0xf6, 0x55, 0xdc, 0x42, 0x58, 0xc5, 0xe7, 0xf0, 0xcf, 0x09, 0x1a, 0x54, + 0x1b, 0xf2, 0x8a, 0x6e, 0xf6, 0x0e, 0x1e, 0x9b, 0x24, 0x56, 0x0d, 0x7e, 0x74, 0xd6, 0x42, 0x3f, 0x9c, 0x99, 0x8e, + 0xd8, 0xa1, 0xde, 0xd1, 0x95, 0xc4, 0x27, 0x4d, 0x09, 0x1d, 0xb5, 0xca, 0x7e, 0x44, 0x7c, 0x8a, 0xb0, 0x88, 0x8f, + 0xe1, 0x9f, 0x76, 0xd8, 0xcf, 0xaf, 0x5b, 0xfd, 0x98, 0x79, 0xb7, 0x71, 0x72, 0x6a, 0x1d, 0x40, 0x95, 0xbd, 0x8d, + 0x6d, 0xb0, 0xcb, 0xb6, 0xb9, 0x46, 0x6a, 0x1f, 0xc1, 0x07, 0xc2, 0xfa, 0x90, 0x28, 0xcc, 0x0e, 0xc1, 0x73, 0x14, + 0x0c, 0x26, 0xd4, 0xc5, 0x71, 0x57, 0x35, 0x1a, 0x48, 0xf4, 0xd5, 0xe0, 0x90, 0xb4, 0x9b, 0xba, 0xc9, 0x30, 0xfc, + 0x6e, 0x90, 0x32, 0x1c, 0x99, 0xa8, 0x7a, 0x7d, 0xec, 0x7a, 0xb5, 0x77, 0xce, 0x1e, 0x3b, 0x08, 0x21, 0xaa, 0x17, + 0xeb, 0x26, 0x43, 0x47, 0xa2, 0x11, 0xeb, 0x0b, 0xd6, 0x3b, 0x4b, 0x5b, 0xc8, 0x60, 0xa7, 0xea, 0xc5, 0xac, 0xc9, + 0x21, 0xbd, 0x93, 0xc6, 0xbc, 0xa9, 0xe1, 0xd7, 0x49, 0x30, 0x0b, 0x01, 0x78, 0x57, 0xf9, 0xc1, 0x14, 0x47, 0x9d, + 0xd3, 0x53, 0x2c, 0x08, 0x4f, 0x26, 0xe6, 0x97, 0x22, 0x3c, 0x19, 0x9a, 0x5f, 0x92, 0x94, 0xf0, 0xb2, 0xbd, 0xe3, + 0x82, 0x04, 0xab, 0x6a, 0x52, 0x28, 0x2c, 0x68, 0x81, 0x8e, 0x3a, 0xfe, 0x42, 0x1a, 0x4f, 0xfd, 0x1c, 0x40, 0x00, + 0x2f, 0x8c, 0x2d, 0xa2, 0x6c, 0x16, 0x38, 0x27, 0xf4, 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, + 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, 0xb6, 0x86, 0xa7, 0x70, 0x8b, 0x98, 0x91, 0xec, 0xf0, 0xac, + 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, + 0xa5, 0x8e, 0x68, 0x33, 0x2a, 0x4c, 0x8f, 0xc7, 0x1a, 0x6e, 0xc4, 0x35, 0xf8, 0x99, 0x68, 0xf0, 0x80, 0x49, 0xb9, + 0xbb, 0x8a, 0x42, 0x26, 0x2e, 0xde, 0x38, 0xd4, 0x1a, 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x4d, 0xa3, 0x88, 0x7f, 0x97, + 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, + 0x03, 0x1d, 0x17, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, + 0xad, 0x34, 0xf9, 0x4c, 0xad, 0x95, 0x3f, 0xf7, 0xee, 0xc6, 0x66, 0xe1, 0xac, 0xb3, 0x73, 0xe9, 0xd9, 0xdc, 0x3f, + 0x05, 0x2b, 0x0a, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, + 0xa1, 0xf2, 0x32, 0xf5, 0xa3, 0x84, 0xa4, 0xce, 0x00, 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, + 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x95, 0xe1, 0x5c, 0x01, 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0xeb, + 0x6e, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0xb0, + 0xf4, 0xc0, 0x93, 0x14, 0xac, 0x3c, 0xf0, 0x30, 0x15, 0xe0, 0x89, 0x40, 0x53, 0x16, 0xd8, 0x8f, 0x3f, 0x74, 0xba, + 0x23, 0x73, 0xdf, 0x49, 0x0c, 0x96, 0x76, 0x19, 0x9c, 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, + 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, + 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0x5f, 0x21, 0x6b, 0xdb, 0x38, 0xdc, 0x4d, 0x43, 0x13, 0x82, 0x70, 0x15, + 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0xf0, 0x22, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, + 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, + 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x47, 0x34, 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, + 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, + 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0x26, 0x1c, 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x76, 0xf8, + 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, + 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, + 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, + 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, + 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, + 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, + 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, + 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, + 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, + 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, + 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, + 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, 0x26, 0x8d, 0x12, 0x7d, 0xcc, 0x86, 0xd9, 0x28, 0xc2, 0x66, + 0x30, 0x63, 0xf8, 0xfb, 0x85, 0xbf, 0x63, 0x3a, 0x8d, 0xce, 0x69, 0x67, 0xc8, 0x3a, 0x11, 0x1e, 0xbe, 0xb9, 0x11, + 0x69, 0x44, 0x4f, 0x3b, 0xb4, 0x43, 0x23, 0x3c, 0x5c, 0x14, 0xf9, 0xdd, 0x8d, 0x94, 0x23, 0x00, 0xc2, 0xf0, 0xfc, + 0xfc, 0x7e, 0x84, 0x33, 0xfa, 0xab, 0x86, 0xda, 0xa7, 0xe3, 0x07, 0x8c, 0xb6, 0x22, 0xfc, 0x0b, 0x2d, 0xf4, 0xc7, + 0x85, 0x72, 0x03, 0x6d, 0x41, 0x8a, 0xcc, 0xde, 0x81, 0x82, 0x39, 0x1a, 0x75, 0xce, 0x1e, 0xb4, 0x59, 0x84, 0xb3, + 0xab, 0xd7, 0xd0, 0xdb, 0xfd, 0xf1, 0x69, 0x0b, 0x3e, 0x04, 0x48, 0x6a, 0xac, 0x80, 0x46, 0xce, 0x4e, 0x1e, 0x9c, + 0xb2, 0x91, 0x49, 0x54, 0x3c, 0xff, 0x6c, 0x66, 0x7f, 0x0e, 0xf3, 0xc9, 0x0a, 0x3e, 0x53, 0x52, 0xa4, 0xd1, 0x28, + 0x6b, 0x9f, 0x1c, 0x43, 0xc2, 0x1d, 0x15, 0x1e, 0x38, 0xb7, 0x50, 0xf5, 0x7c, 0x18, 0xe1, 0x5b, 0x9b, 0x7a, 0x3e, + 0x34, 0x1f, 0x93, 0x77, 0xbf, 0x8a, 0x37, 0xa3, 0x34, 0x1a, 0x9e, 0x9f, 0x9f, 0xb5, 0x20, 0xe1, 0x03, 0xbd, 0x4b, + 0x23, 0xfa, 0x00, 0xfe, 0x83, 0xec, 0x8f, 0xcf, 0xa0, 0x43, 0x18, 0xe1, 0xed, 0xe4, 0x63, 0x98, 0xf3, 0x79, 0x4a, + 0x3f, 0xf3, 0x34, 0x1a, 0x8e, 0x86, 0xf7, 0xcf, 0xa0, 0xde, 0x8c, 0x4e, 0x9e, 0x69, 0x0a, 0xed, 0xb6, 0x5a, 0xa6, + 0xe5, 0x77, 0xfc, 0x0b, 0x33, 0xd5, 0x4f, 0x4f, 0xcf, 0x86, 0x1d, 0x18, 0xc1, 0x15, 0xa8, 0x18, 0x60, 0x3c, 0xe7, + 0x99, 0x69, 0xf0, 0x2a, 0x7b, 0x3a, 0x4a, 0xa3, 0x07, 0x0f, 0x8e, 0x3b, 0x59, 0x16, 0xe1, 0xdb, 0x8f, 0x23, 0x5b, + 0xdb, 0xe4, 0x29, 0x80, 0x7d, 0x1a, 0xb1, 0x07, 0x0f, 0xce, 0xee, 0x53, 0xf8, 0x7e, 0x6e, 0xda, 0x3a, 0x1f, 0x0f, + 0xb3, 0x73, 0x68, 0xeb, 0x77, 0x98, 0xce, 0xc9, 0xf9, 0xf1, 0xc8, 0xf4, 0xf5, 0xbb, 0x19, 0x75, 0x67, 0x7c, 0x32, + 0x3e, 0x31, 0x99, 0x66, 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x8d, 0x32, 0x36, 0x6a, 0x47, 0xf8, 0xd6, 0x2d, 0xdc, 0x83, + 0x93, 0x56, 0x6b, 0x74, 0x1c, 0xe1, 0xd1, 0xc3, 0xf9, 0xfc, 0xad, 0x81, 0x60, 0xfb, 0xe4, 0x81, 0xfd, 0x56, 0x9f, + 0xef, 0xa0, 0xe9, 0xa1, 0x01, 0xda, 0x88, 0xcf, 0x4c, 0xcb, 0x67, 0x0f, 0xe0, 0x3f, 0xf3, 0x6d, 0x9a, 0x2e, 0xbf, + 0xe5, 0x68, 0x62, 0x17, 0xa5, 0xcd, 0x1e, 0xb4, 0xa0, 0xc6, 0x98, 0x7f, 0x1c, 0x16, 0x1c, 0xd0, 0x68, 0xd8, 0x81, + 0xff, 0x8b, 0xf0, 0x38, 0xbf, 0x7a, 0xed, 0x70, 0x76, 0x3c, 0xa6, 0xe3, 0x56, 0x84, 0xc7, 0xf2, 0xa3, 0xd2, 0x1f, + 0x1e, 0x8a, 0x34, 0xea, 0x74, 0xce, 0x87, 0xa6, 0xcc, 0xe2, 0x17, 0xc5, 0x0d, 0x1e, 0xb7, 0x4c, 0x2b, 0x13, 0xfa, + 0x56, 0x0d, 0xaf, 0x24, 0xac, 0x24, 0xfc, 0x17, 0xe1, 0x09, 0xe8, 0xa5, 0x5c, 0x2b, 0xe7, 0x76, 0x3b, 0x4c, 0xde, + 0x19, 0xd4, 0x1c, 0xdd, 0x07, 0x78, 0xf9, 0x65, 0x1c, 0x51, 0x7a, 0xda, 0x69, 0x45, 0xd8, 0x8c, 0xfa, 0xbc, 0x05, + 0xff, 0x45, 0xd8, 0x42, 0xce, 0xc0, 0x75, 0xf2, 0xf1, 0xd9, 0xcb, 0x9b, 0x34, 0xa2, 0xa3, 0xf1, 0x18, 0x96, 0xc4, + 0x4c, 0xc6, 0x17, 0x9b, 0x4a, 0xc1, 0xee, 0x7e, 0xbd, 0x71, 0xdb, 0xc5, 0x24, 0x68, 0x07, 0x9d, 0xb3, 0x07, 0xc3, + 0x93, 0x08, 0xbf, 0x1d, 0x71, 0x2a, 0x60, 0x95, 0xb2, 0xd1, 0x69, 0x76, 0x9a, 0x99, 0x84, 0x89, 0x4c, 0xa3, 0x13, + 0x58, 0xf2, 0x4e, 0x84, 0xf9, 0x97, 0xab, 0x3b, 0x8b, 0x6e, 0x50, 0xdb, 0x21, 0xc8, 0xb8, 0xc5, 0xce, 0xce, 0xb3, + 0x08, 0xe7, 0xf4, 0xcb, 0xb3, 0x5f, 0x8b, 0x34, 0x62, 0x67, 0xec, 0x6c, 0x4c, 0xfd, 0xf7, 0x1f, 0x6a, 0x6a, 0x6a, + 0xb4, 0xc6, 0xa7, 0x90, 0x74, 0x23, 0xcc, 0x58, 0xef, 0x67, 0x63, 0x83, 0x21, 0xaf, 0x66, 0x52, 0x64, 0x4f, 0xc7, + 0x63, 0x69, 0xb1, 0x98, 0xc2, 0x26, 0xfc, 0x04, 0xd0, 0xa6, 0xa3, 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x27, 0xbb, 0x4b, + 0xdc, 0x04, 0x3e, 0x59, 0xcc, 0x66, 0x6e, 0xb7, 0x7f, 0xb2, 0x40, 0x81, 0xf9, 0x8e, 0xe9, 0x98, 0x8e, 0x3a, 0x11, + 0xfe, 0x64, 0xe0, 0x32, 0x3a, 0x86, 0xff, 0xa0, 0x00, 0x74, 0xf6, 0xa0, 0xc5, 0xd8, 0x83, 0x96, 0xf9, 0x0a, 0xf3, + 0xdc, 0xcc, 0x87, 0x67, 0x59, 0x3b, 0xc2, 0x9f, 0x1c, 0x3a, 0x8e, 0xc7, 0xb4, 0x05, 0xe8, 0xf8, 0xc9, 0xa1, 0x63, + 0xa7, 0x35, 0xec, 0x50, 0xf3, 0x6d, 0xb1, 0xe6, 0xfc, 0x7e, 0xc6, 0x60, 0x72, 0x9f, 0x2c, 0x42, 0xde, 0xbf, 0x7f, + 0x7e, 0xfe, 0xe0, 0x01, 0x7c, 0x9a, 0xb6, 0xcb, 0x4f, 0xa5, 0x1f, 0xe6, 0x06, 0xc9, 0x5a, 0xd9, 0x09, 0xd0, 0xc9, + 0x4f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, + 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, + 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, + 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, + 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, + 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, + 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, + 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, + 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, + 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, + 0x87, 0x23, 0xfc, 0x6e, 0x04, 0xd7, 0x60, 0x69, 0x34, 0x1e, 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, + 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, + 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, + 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, + 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, + 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, + 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, + 0x21, 0xdc, 0xf3, 0x2d, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, 0x08, 0x6e, 0xfd, 0xe4, 0xcd, 0xaf, 0x85, 0x45, 0x23, + 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, + 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, + 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, + 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, + 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, + 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, + 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, + 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, + 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, + 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, + 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, + 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, + 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, + 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0x3d, 0xe8, 0x13, 0x1a, 0x7b, 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xe1, 0x45, 0x3f, + 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x5c, 0x00, 0x9c, 0x41, 0xbd, 0xf3, 0x99, 0x04, 0x41, 0x52, + 0x90, 0x56, 0x57, 0x5c, 0x78, 0x3f, 0xce, 0xae, 0x80, 0xa0, 0x03, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0xc4, 0x66, 0xb1, + 0xc2, 0xa4, 0x37, 0x6f, 0x37, 0x32, 0xa5, 0xb4, 0x06, 0xf3, 0x94, 0x50, 0x1f, 0x95, 0x1d, 0x2e, 0x69, 0x21, 0x6e, + 0x11, 0xea, 0x4a, 0x62, 0x62, 0x2c, 0xbf, 0x10, 0x3a, 0x56, 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0x5e, + 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0x11, + 0xa3, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, + 0x47, 0x2c, 0x31, 0xb7, 0x06, 0xd6, 0x37, 0x85, 0xf4, 0x41, 0x73, 0xd6, 0xc2, 0x10, 0xc7, 0xdc, 0x73, 0xde, 0x8f, + 0x58, 0x9f, 0xd7, 0xfd, 0x9a, 0xab, 0xe0, 0xc1, 0x07, 0x07, 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, + 0x56, 0x4c, 0xd0, 0x55, 0xf8, 0xf6, 0x93, 0x1e, 0x48, 0x29, 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, + 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, + 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, 0x49, 0x23, 0x9a, 0xed, 0xdb, 0x48, 0x18, 0xba, 0x7f, + 0xdf, 0x08, 0x66, 0x55, 0x78, 0xb6, 0x06, 0x24, 0x75, 0x41, 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, + 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x45, 0xb4, 0x61, 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, + 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, + 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, + 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, + 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, + 0x46, 0x49, 0xf4, 0x97, 0x57, 0xa2, 0x3e, 0xe2, 0x26, 0xfe, 0xcc, 0x05, 0x49, 0x5a, 0xad, 0xe3, 0xf6, 0x71, 0xeb, + 0xbc, 0xc7, 0x0f, 0xdb, 0x9d, 0xe4, 0x41, 0x27, 0x35, 0x8a, 0x88, 0xb9, 0xbc, 0x01, 0x05, 0xcc, 0x51, 0x27, 0x39, + 0x41, 0x87, 0xed, 0xa4, 0x75, 0x7a, 0xda, 0x84, 0x7f, 0xf0, 0x7b, 0x5d, 0x56, 0x3b, 0x69, 0x9d, 0x9c, 0xf6, 0xf8, + 0xd1, 0x46, 0xa5, 0x98, 0x37, 0xa0, 0x20, 0x3a, 0x32, 0x95, 0x30, 0xd4, 0xaf, 0x96, 0xf7, 0xd9, 0x96, 0x9e, 0xe7, + 0xbd, 0x8e, 0x95, 0x55, 0xc5, 0x01, 0x54, 0xfd, 0xd7, 0xc4, 0x00, 0xd1, 0x7f, 0x0d, 0xcb, 0x18, 0xb1, 0xcb, 0x02, + 0x44, 0xed, 0x47, 0x3c, 0x16, 0x0d, 0x76, 0x18, 0xdb, 0x7c, 0x0d, 0x75, 0x9b, 0x10, 0xb7, 0x0d, 0x4f, 0x5c, 0xae, + 0x0a, 0x73, 0x27, 0x08, 0x35, 0x15, 0xe4, 0x0e, 0x5d, 0xae, 0x0c, 0x73, 0x87, 0x08, 0x35, 0x25, 0xe4, 0xd2, 0x94, + 0x27, 0x14, 0x72, 0x74, 0x42, 0x9b, 0x06, 0x92, 0xd5, 0xa2, 0x3c, 0x67, 0x7e, 0xd8, 0x7c, 0x0c, 0xcb, 0x63, 0x08, + 0x8a, 0x13, 0xa4, 0x05, 0xbc, 0xed, 0x51, 0x6a, 0x73, 0x5a, 0xb8, 0x54, 0xe3, 0x40, 0x46, 0x03, 0xfe, 0x39, 0x64, + 0xe6, 0xc1, 0x87, 0x56, 0xef, 0xf8, 0xac, 0x95, 0xb6, 0xc1, 0x49, 0x19, 0x64, 0x6d, 0x61, 0x65, 0x6d, 0xe1, 0x65, + 0x6d, 0xe1, 0x65, 0x6d, 0x10, 0xe0, 0x83, 0xbe, 0xff, 0x91, 0x35, 0xc3, 0x0f, 0x5e, 0x5a, 0x91, 0x58, 0x33, 0x81, + 0x58, 0xaf, 0x56, 0xcb, 0x35, 0xd8, 0xf8, 0x94, 0x35, 0xa4, 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, + 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, 0x3f, 0xa6, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, + 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, + 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0xf0, 0x79, 0xb1, 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x5c, 0x98, + 0x2d, 0xa9, 0x13, 0x6a, 0xbc, 0xa6, 0xcb, 0x31, 0x7f, 0xad, 0xa1, 0x7d, 0x02, 0x6f, 0xb9, 0x3c, 0xd4, 0x71, 0x0b, + 0x8c, 0x26, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, 0x8d, 0x33, 0x86, 0xfe, 0xbc, 0xe1, 0x83, 0x6a, 0x29, + 0x41, 0xf8, 0x82, 0xc1, 0x67, 0x56, 0x39, 0xc5, 0x97, 0xb6, 0x9e, 0xce, 0x50, 0xcb, 0x1e, 0x09, 0x5d, 0x30, 0xd8, + 0xf6, 0xd1, 0x96, 0x7a, 0x82, 0x48, 0x65, 0xdc, 0x05, 0x49, 0x15, 0x2f, 0x18, 0xdc, 0x67, 0xc9, 0x2d, 0x35, 0xce, + 0x24, 0x2f, 0xec, 0x9f, 0xaf, 0x34, 0xf0, 0xb6, 0x2b, 0x26, 0x43, 0xef, 0xa4, 0x7a, 0x6d, 0xa2, 0xea, 0x90, 0xfd, + 0x7d, 0x6b, 0x4b, 0x6d, 0xbe, 0x36, 0x8d, 0xa9, 0x4d, 0xa2, 0xc9, 0x86, 0x1d, 0xea, 0xd7, 0xe8, 0x1f, 0xef, 0x2b, + 0x56, 0x4c, 0x86, 0x28, 0xa0, 0xd9, 0x06, 0xac, 0xaa, 0x02, 0x96, 0x72, 0xf5, 0x4a, 0x17, 0x42, 0xe8, 0xdd, 0x8c, + 0x79, 0x5d, 0x4c, 0x86, 0x3b, 0x1f, 0xfd, 0xb0, 0x3d, 0xf6, 0xde, 0xd2, 0xa0, 0x07, 0xaf, 0xda, 0x9e, 0xb2, 0xdb, + 0xef, 0xd5, 0xb9, 0xd9, 0x59, 0x47, 0xe5, 0xdf, 0xab, 0xf3, 0x74, 0x57, 0x9d, 0x19, 0xbf, 0x8d, 0xfd, 0xde, 0xd1, + 0x81, 0x1a, 0xdb, 0x18, 0xe8, 0x4c, 0x86, 0x10, 0xa5, 0x1d, 0xfe, 0xda, 0x58, 0x2a, 0x5d, 0x4f, 0xc2, 0x61, 0x15, + 0x64, 0x2f, 0x39, 0x4d, 0x19, 0xa6, 0xa4, 0x73, 0x58, 0x98, 0x68, 0x2a, 0x22, 0xa1, 0x4d, 0x95, 0x50, 0x9c, 0x93, + 0x38, 0xa6, 0x87, 0x19, 0xc4, 0x84, 0x69, 0xf7, 0x68, 0x1a, 0xd3, 0x46, 0x86, 0x8e, 0xe2, 0x76, 0x83, 0x1e, 0x66, + 0x08, 0x35, 0xda, 0xa0, 0x33, 0x95, 0xa4, 0xdd, 0xcc, 0x21, 0x4a, 0xa4, 0x21, 0xc5, 0xf9, 0xa1, 0x48, 0x8a, 0x86, + 0x3c, 0x54, 0x49, 0xd1, 0x48, 0x4e, 0xb1, 0x48, 0x26, 0x65, 0xf2, 0xc4, 0x24, 0x4f, 0x6c, 0xf2, 0xb0, 0x4c, 0x1e, + 0x9a, 0xe4, 0xa1, 0x4d, 0xa6, 0xa4, 0x38, 0x14, 0x09, 0x6d, 0xc4, 0xed, 0x66, 0x81, 0x0e, 0x61, 0x04, 0x7e, 0xf4, + 0x44, 0x84, 0xc1, 0xb9, 0xd7, 0xc6, 0xba, 0x65, 0x2e, 0x73, 0x17, 0x2e, 0xb3, 0x02, 0x52, 0xe9, 0x72, 0x04, 0x75, + 0x9e, 0x05, 0x60, 0xc2, 0xda, 0xfe, 0xf1, 0xc1, 0xe0, 0xd6, 0x59, 0x2e, 0x45, 0xe0, 0x52, 0x05, 0x56, 0xe0, 0x9f, + 0x9d, 0x23, 0x09, 0x40, 0x75, 0x4d, 0xf3, 0xf9, 0x94, 0x6e, 0xf9, 0xad, 0x16, 0x93, 0xa1, 0xdb, 0x59, 0x65, 0x33, + 0x8c, 0x16, 0x36, 0xc8, 0x72, 0xdd, 0xc3, 0x10, 0x40, 0xed, 0xbd, 0x1a, 0x13, 0x6a, 0x94, 0xe4, 0xb6, 0xc6, 0xa4, + 0x60, 0x77, 0x2a, 0xa3, 0x39, 0x8b, 0xab, 0x03, 0xb8, 0x1a, 0x26, 0x23, 0x2f, 0xc0, 0x16, 0xbd, 0x38, 0x4c, 0x8e, + 0x1b, 0x3a, 0x99, 0x1c, 0x26, 0xa7, 0x0f, 0x1a, 0x3a, 0x19, 0x1e, 0x26, 0xed, 0x76, 0x85, 0xb3, 0x49, 0x41, 0x74, + 0x32, 0x21, 0x1a, 0x34, 0x86, 0xb6, 0x51, 0x39, 0xa7, 0x60, 0x5c, 0xf5, 0x6f, 0x0c, 0xa3, 0xe1, 0x86, 0x21, 0xd8, + 0xc4, 0xc6, 0x9b, 0xdc, 0x1a, 0x43, 0xd8, 0x4d, 0xe7, 0xf4, 0xb4, 0xa9, 0x93, 0x02, 0x6b, 0xbb, 0x92, 0x4d, 0x9d, + 0x4c, 0xb0, 0xb6, 0xcb, 0xd7, 0xd4, 0xc9, 0xd0, 0x36, 0x65, 0x74, 0x80, 0x4c, 0x04, 0xc0, 0x7a, 0xce, 0x02, 0xc8, + 0x77, 0xbc, 0x7b, 0xc8, 0x1a, 0xb4, 0x86, 0xdf, 0x2b, 0xd7, 0xf4, 0x05, 0x15, 0xd5, 0x60, 0x64, 0xc3, 0xbe, 0x55, + 0xb4, 0x5d, 0x35, 0xc9, 0xfe, 0x75, 0xd9, 0xb2, 0xd9, 0x42, 0xea, 0x7a, 0xc1, 0x87, 0x35, 0x0c, 0x71, 0xa5, 0xdc, + 0xc1, 0xfd, 0x8a, 0x92, 0x18, 0xa2, 0xca, 0x99, 0x53, 0x88, 0x13, 0xaf, 0x47, 0x86, 0x24, 0xde, 0x68, 0xac, 0x51, + 0x1c, 0x9c, 0xb7, 0x4f, 0x43, 0xaa, 0xba, 0x15, 0x6a, 0x8e, 0x90, 0x68, 0x21, 0xac, 0x31, 0xe2, 0x28, 0x0a, 0x58, + 0x10, 0xa7, 0xdd, 0xad, 0x1d, 0x10, 0x07, 0x07, 0x9b, 0xe7, 0x85, 0x0f, 0xfa, 0xbf, 0x15, 0xe8, 0xbf, 0xb2, 0x64, + 0xf3, 0x4f, 0x11, 0x59, 0x1b, 0x57, 0x1e, 0x20, 0x8a, 0x0f, 0xfa, 0x74, 0xdf, 0x50, 0xf8, 0x7e, 0x15, 0xf1, 0xce, + 0xe5, 0x34, 0xcf, 0x4c, 0x86, 0xe9, 0x6b, 0x10, 0x8c, 0xed, 0x4d, 0x38, 0xa1, 0xd2, 0x4a, 0xef, 0x5f, 0x76, 0x1c, + 0x74, 0xe2, 0x9e, 0x4a, 0x09, 0x1b, 0xfd, 0x3b, 0xb4, 0x89, 0xad, 0x60, 0xe3, 0xbc, 0xa1, 0x57, 0xab, 0xda, 0xc3, + 0x38, 0xf6, 0xf9, 0x15, 0x74, 0x70, 0xc0, 0xd5, 0x33, 0x30, 0xe3, 0x65, 0x71, 0x23, 0x3c, 0x7c, 0xff, 0xa9, 0x9d, + 0xd6, 0x7f, 0x9b, 0x73, 0x35, 0x0d, 0x0e, 0xba, 0x87, 0xb5, 0xfc, 0x9d, 0x2b, 0xd1, 0xd3, 0x29, 0x77, 0x6b, 0xfd, + 0x77, 0x65, 0x24, 0xbd, 0xf5, 0x44, 0xd3, 0xc1, 0x01, 0xaf, 0x02, 0x25, 0x45, 0x3f, 0x44, 0xa8, 0x67, 0x64, 0x90, + 0x67, 0xb9, 0xa4, 0x70, 0x23, 0x0a, 0x57, 0x0c, 0x69, 0x83, 0x1f, 0x69, 0xfc, 0x87, 0xfc, 0xff, 0xd4, 0xc8, 0xa1, + 0x4e, 0x1b, 0x3c, 0x10, 0xc0, 0x42, 0x56, 0xa8, 0x0a, 0x51, 0x68, 0x20, 0x1d, 0xda, 0x3c, 0xa3, 0xf2, 0x30, 0xa7, + 0xf3, 0x79, 0x7e, 0x67, 0x5e, 0xa9, 0x0a, 0x38, 0xaa, 0xea, 0xa2, 0xc9, 0xc5, 0x87, 0xc3, 0x05, 0xf0, 0xf4, 0x80, + 0x7b, 0xc8, 0xf8, 0x77, 0x96, 0x97, 0xdb, 0x02, 0x81, 0x64, 0xa6, 0x88, 0x6c, 0xb6, 0xbb, 0xea, 0x12, 0xe4, 0xb2, + 0x66, 0x13, 0x69, 0x17, 0x36, 0x1b, 0x73, 0x90, 0xc9, 0x94, 0xf5, 0xe1, 0xdc, 0xb3, 0x05, 0x41, 0x72, 0x93, 0x46, + 0x64, 0xdb, 0x5d, 0x8a, 0x8f, 0x63, 0x40, 0x23, 0x64, 0x05, 0xbe, 0x50, 0x58, 0xe4, 0xc0, 0x75, 0x16, 0xbe, 0xe3, + 0x6f, 0xb4, 0x54, 0xf4, 0xd5, 0x60, 0x80, 0x0b, 0xf3, 0x30, 0x43, 0x39, 0x9f, 0x42, 0x05, 0x0f, 0xfd, 0x04, 0x22, + 0x0a, 0x5f, 0xad, 0xf6, 0xe1, 0x1d, 0x1d, 0xd7, 0x26, 0x38, 0x7d, 0xba, 0x9f, 0xd5, 0x9b, 0x19, 0x30, 0x0e, 0x46, + 0x5a, 0xe6, 0xa2, 0xd0, 0xc9, 0x9b, 0xec, 0x42, 0x74, 0x1b, 0x0d, 0x66, 0x42, 0x1c, 0x11, 0x88, 0x67, 0x06, 0x1e, + 0x79, 0xf0, 0xc7, 0x46, 0x2d, 0x52, 0xcc, 0xc6, 0x7e, 0x83, 0xa0, 0xd4, 0xb5, 0x84, 0xd5, 0x4a, 0xd9, 0xd8, 0x22, + 0x26, 0xc7, 0x46, 0x19, 0x29, 0xfb, 0x29, 0x83, 0x98, 0x56, 0x66, 0x1c, 0xdc, 0x6d, 0xf5, 0xb7, 0xd5, 0x7e, 0xde, + 0xe3, 0xf6, 0x1a, 0x8f, 0x1b, 0x8f, 0x7d, 0x03, 0xa8, 0xe5, 0xc6, 0x06, 0xb7, 0x16, 0xe6, 0xb1, 0x35, 0x87, 0x65, + 0x9b, 0x10, 0x14, 0xa5, 0x87, 0xba, 0xbd, 0xb9, 0xf5, 0x11, 0xfb, 0x94, 0x99, 0x93, 0x42, 0xba, 0x0f, 0x72, 0xf4, + 0x80, 0x40, 0xe7, 0xf6, 0x67, 0x45, 0x17, 0x2a, 0x99, 0xb8, 0x1c, 0xe3, 0x2f, 0xc1, 0x6d, 0x5e, 0x3f, 0xba, 0xbe, + 0x36, 0x9b, 0xfc, 0xfa, 0x3a, 0xc2, 0xa1, 0x59, 0x77, 0x14, 0xf0, 0x82, 0xd1, 0xa0, 0x0c, 0xea, 0x64, 0x36, 0x7e, + 0xb3, 0x5d, 0x35, 0xf6, 0x9e, 0x56, 0x78, 0x07, 0xcb, 0x63, 0x1a, 0xdf, 0x72, 0x83, 0xec, 0x73, 0x80, 0x37, 0xeb, + 0xf3, 0x41, 0xf7, 0x4d, 0xac, 0xd0, 0xc1, 0xc1, 0x9b, 0x58, 0xa2, 0xde, 0x15, 0x33, 0x77, 0x6e, 0xe0, 0x07, 0xdd, + 0xe7, 0x66, 0xf8, 0x32, 0x40, 0x80, 0x2b, 0xb6, 0x29, 0xd9, 0xbc, 0x35, 0x51, 0x27, 0x52, 0x88, 0x6a, 0x0d, 0xb1, + 0x75, 0x1d, 0x48, 0xa0, 0xd7, 0x37, 0x21, 0xb4, 0xbb, 0x8c, 0x30, 0x60, 0xe1, 0x4b, 0x2f, 0x35, 0x96, 0xcc, 0x58, + 0x31, 0x61, 0xc5, 0x6a, 0xf5, 0x9e, 0x5a, 0xcf, 0xb3, 0x8d, 0x20, 0x89, 0xaa, 0xdb, 0x68, 0x50, 0x33, 0x7e, 0x10, + 0x1f, 0xe8, 0x00, 0xef, 0xbf, 0x89, 0x0b, 0x84, 0xc0, 0xc2, 0x88, 0x8b, 0x85, 0xf7, 0xb2, 0xca, 0x6a, 0xeb, 0x52, + 0xa0, 0xb2, 0x91, 0x9c, 0xb4, 0xf0, 0x94, 0x64, 0xe5, 0x1a, 0x5d, 0x4c, 0xbb, 0x8d, 0x46, 0x8e, 0x64, 0x9c, 0xf5, + 0xf3, 0x01, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0x72, 0xf3, 0x5d, 0xda, 0xb1, 0xa6, + 0x8f, 0xe8, 0x3a, 0x00, 0xc6, 0x23, 0x1a, 0x10, 0x89, 0x5d, 0x40, 0x16, 0x16, 0xc8, 0xca, 0x03, 0x59, 0x18, 0x20, + 0x2b, 0xd4, 0x9b, 0x43, 0xb8, 0x20, 0x85, 0xd2, 0x2d, 0x8a, 0x5e, 0x0f, 0x6c, 0xe9, 0x9c, 0x26, 0x30, 0x37, 0xb1, + 0x15, 0xdc, 0x72, 0x80, 0x03, 0x85, 0xf3, 0xc3, 0x53, 0x64, 0x19, 0x45, 0x26, 0xc6, 0x2b, 0xbe, 0x35, 0x7f, 0x92, + 0x5b, 0x7c, 0x67, 0x7f, 0xdc, 0x05, 0xca, 0xa4, 0xe7, 0x35, 0x6d, 0x03, 0x77, 0x11, 0xd1, 0xa2, 0x24, 0x02, 0xb4, + 0x76, 0xe1, 0xfd, 0x44, 0xfd, 0xc5, 0x33, 0x65, 0x03, 0x31, 0x88, 0x06, 0x51, 0x58, 0x04, 0xa4, 0xf3, 0xcf, 0x3f, + 0x23, 0xd4, 0x13, 0x10, 0x47, 0xc7, 0x9d, 0x6c, 0xcd, 0x36, 0x6a, 0x44, 0x49, 0x94, 0xc6, 0x3e, 0x4c, 0x03, 0xec, + 0x8c, 0x28, 0x0a, 0x5e, 0x3b, 0x29, 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x33, 0xa8, 0x2a, 0xf0, 0xc4, 0xe5, 0x72, 0x33, + 0xcc, 0x8f, 0x81, 0xaa, 0x30, 0x31, 0x56, 0x90, 0x7d, 0x02, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0xfa, 0x62, 0x10, 0xbc, + 0xe9, 0x55, 0x5d, 0x87, 0xeb, 0x70, 0xe1, 0x62, 0x0a, 0x71, 0xd6, 0x57, 0x2b, 0xfb, 0x97, 0x7c, 0x30, 0xd2, 0x0c, + 0x3c, 0xce, 0x16, 0x9c, 0xb1, 0x62, 0xb7, 0x2c, 0x96, 0x68, 0xf9, 0x3b, 0x98, 0xed, 0xb9, 0xa8, 0x79, 0xdc, 0x4d, + 0xb5, 0xed, 0xa1, 0x3e, 0x37, 0x1a, 0x85, 0x20, 0x66, 0x6d, 0x75, 0xa4, 0xe1, 0xb9, 0x0e, 0xf3, 0x6a, 0xb1, 0x67, + 0x33, 0x55, 0x86, 0x10, 0x85, 0x23, 0x25, 0x01, 0xbb, 0x6d, 0x43, 0x27, 0xe1, 0x47, 0x9d, 0x4a, 0x3a, 0x16, 0x12, + 0xa0, 0xc0, 0x91, 0xb9, 0x9c, 0x37, 0x21, 0xe2, 0x19, 0xda, 0x41, 0xe4, 0x02, 0x13, 0x9a, 0xba, 0x6c, 0xe9, 0x62, + 0x39, 0x45, 0x33, 0xb9, 0x50, 0x6c, 0x31, 0x87, 0xf3, 0xbd, 0x4c, 0xcb, 0x72, 0x9e, 0x7d, 0xae, 0xa7, 0x80, 0xfd, + 0xe5, 0xad, 0x9e, 0x31, 0xb1, 0x88, 0xdc, 0x3c, 0xbf, 0x5a, 0x71, 0xff, 0xcd, 0x0b, 0xfc, 0x88, 0x74, 0x0e, 0xbf, + 0xe2, 0x8f, 0x94, 0x3c, 0x6a, 0x7c, 0xc5, 0x13, 0x4e, 0x2c, 0x6f, 0x90, 0xbc, 0x79, 0x7d, 0xf5, 0xe2, 0xdd, 0x8b, + 0xf7, 0x4f, 0xaf, 0x5f, 0xbc, 0x7a, 0xf6, 0xe2, 0xd5, 0x8b, 0x77, 0x1f, 0xf1, 0x3f, 0x94, 0x7c, 0x3d, 0x6a, 0x9f, + 0xb7, 0xf0, 0x07, 0xf2, 0xf5, 0xa8, 0x83, 0x6f, 0x35, 0xf9, 0x7a, 0x74, 0x82, 0x73, 0x45, 0xbe, 0x1e, 0x76, 0x8e, + 0x8e, 0xf1, 0x42, 0xdb, 0x26, 0x73, 0x39, 0x69, 0xb7, 0xf0, 0x3f, 0xee, 0x0b, 0xc4, 0xfb, 0x6a, 0x16, 0x13, 0xb6, + 0x61, 0xfc, 0x60, 0xca, 0xd0, 0xa1, 0x32, 0x86, 0x28, 0x17, 0x01, 0x3a, 0x4d, 0x55, 0x88, 0x4e, 0x36, 0x88, 0x31, + 0xd8, 0x30, 0x02, 0x5a, 0x71, 0xe2, 0xda, 0xe1, 0x47, 0x6d, 0x76, 0x0c, 0xf4, 0x89, 0x97, 0xc2, 0x71, 0xa9, 0xc2, + 0x69, 0x3b, 0x2d, 0xc6, 0x38, 0x97, 0xb2, 0x88, 0x17, 0xc0, 0x08, 0x18, 0xad, 0x05, 0x3f, 0x2a, 0xa3, 0x25, 0x89, + 0x0b, 0xd2, 0xee, 0xb5, 0x53, 0x71, 0x41, 0x3a, 0xbd, 0x0e, 0xfc, 0x39, 0xed, 0x9d, 0xa6, 0xed, 0x16, 0x3a, 0x0c, + 0xc6, 0xf1, 0x47, 0x0d, 0xad, 0xfb, 0x03, 0xec, 0xba, 0x50, 0xff, 0x14, 0xda, 0xab, 0xf4, 0x84, 0x53, 0xc7, 0xb6, + 0xbb, 0xe2, 0x82, 0x19, 0x3d, 0x2c, 0xff, 0x01, 0x50, 0xdb, 0x38, 0x74, 0x94, 0x1b, 0xc7, 0xfd, 0xe2, 0x47, 0x02, + 0xd5, 0x42, 0xb2, 0xc4, 0x6c, 0xd5, 0x42, 0xc0, 0x34, 0x9a, 0x6c, 0x30, 0x07, 0x4a, 0x94, 0x2c, 0xb4, 0x0f, 0x2b, + 0xaf, 0x9a, 0x12, 0x25, 0x73, 0x39, 0x8f, 0x6b, 0xaa, 0x86, 0x5f, 0x03, 0x33, 0xc7, 0x7d, 0xae, 0x5e, 0xd1, 0x57, + 0x71, 0x8d, 0xe7, 0x09, 0x59, 0xbb, 0x70, 0x5b, 0xfc, 0xe2, 0xac, 0x28, 0x6a, 0xe0, 0x2a, 0x01, 0xeb, 0x47, 0xd5, + 0xd4, 0x17, 0xf0, 0x7e, 0x1e, 0x6b, 0xe8, 0x4b, 0x12, 0x50, 0xcf, 0x9f, 0x4a, 0x33, 0xae, 0x52, 0x19, 0xed, 0x15, + 0xd1, 0xc6, 0x2c, 0xc8, 0x2b, 0xa2, 0x2f, 0x94, 0x01, 0x82, 0x24, 0xbc, 0x2f, 0x06, 0x70, 0xe0, 0xdb, 0x01, 0x4a, + 0x43, 0xe7, 0x40, 0xad, 0x54, 0x99, 0x09, 0x99, 0x4f, 0x13, 0x1c, 0x00, 0x34, 0x4f, 0x95, 0x0a, 0xca, 0x7c, 0x62, + 0x89, 0x82, 0xa1, 0xff, 0x16, 0x6e, 0x80, 0xc3, 0xd8, 0xa0, 0x62, 0x90, 0x7d, 0x4f, 0xd4, 0xf3, 0xdb, 0xe7, 0xad, + 0xa3, 0xaf, 0x41, 0xfe, 0x48, 0x79, 0x7b, 0x8f, 0xbf, 0x03, 0x4a, 0x6e, 0xc3, 0x59, 0xb5, 0xb1, 0x8f, 0x44, 0xd6, + 0x0d, 0x01, 0x72, 0xa8, 0xd1, 0x91, 0x79, 0x4a, 0xb0, 0x8b, 0xf4, 0x21, 0x69, 0xb7, 0x20, 0x7c, 0xd8, 0x0e, 0xca, + 0xf7, 0xd3, 0x06, 0x4c, 0x75, 0x72, 0xdb, 0x04, 0x5a, 0x0d, 0xaf, 0x0b, 0xdd, 0x35, 0x79, 0x72, 0x87, 0x55, 0x80, + 0x33, 0xec, 0x90, 0x35, 0xc4, 0xa1, 0x40, 0x2e, 0xec, 0xaa, 0xdd, 0x00, 0x9a, 0x8a, 0x8e, 0x7d, 0xe5, 0xce, 0x1b, + 0x47, 0x5d, 0x34, 0x93, 0xd3, 0xc3, 0xaf, 0x07, 0x07, 0xb1, 0x6c, 0x90, 0x47, 0x08, 0x2f, 0x29, 0x58, 0x31, 0x83, + 0xd7, 0x17, 0xb7, 0x4c, 0x7c, 0xaa, 0x02, 0xea, 0xb8, 0x50, 0xb5, 0x63, 0xad, 0xea, 0xac, 0xdc, 0x0d, 0x7e, 0x4c, + 0x1d, 0xd4, 0x08, 0xd2, 0xec, 0xe8, 0x3a, 0x35, 0x28, 0xd7, 0x5c, 0xb4, 0x60, 0x5b, 0x36, 0x3e, 0x52, 0xf4, 0xc3, + 0xa3, 0xe6, 0xd7, 0x60, 0xc2, 0x35, 0xd3, 0xa4, 0x47, 0x8d, 0x47, 0xe8, 0x87, 0x47, 0x81, 0x93, 0x1d, 0xaf, 0xd8, + 0x13, 0xcf, 0x8d, 0xfc, 0x64, 0xb9, 0xd2, 0x9f, 0x40, 0xb2, 0x2f, 0xc8, 0x4f, 0x80, 0xe5, 0x94, 0xfc, 0x14, 0xcb, + 0x26, 0x04, 0x1f, 0x24, 0x3f, 0xc5, 0x05, 0xfc, 0xc8, 0xc9, 0x4f, 0x31, 0x60, 0x3b, 0x9e, 0x9a, 0x1f, 0x45, 0x09, + 0x0c, 0x70, 0xec, 0x92, 0xd6, 0xbf, 0xab, 0x58, 0xad, 0xc4, 0xc1, 0x81, 0xb4, 0xbf, 0xe8, 0x65, 0x76, 0x70, 0x90, + 0x5f, 0x4c, 0xab, 0xbe, 0x99, 0xde, 0x45, 0x5f, 0x0c, 0x42, 0xe1, 0xc0, 0x34, 0x8d, 0x87, 0x33, 0xfe, 0x14, 0x52, + 0x56, 0xd3, 0x40, 0xf3, 0xb8, 0x73, 0xff, 0xec, 0x1c, 0xc3, 0xbf, 0xf7, 0x83, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, + 0xb3, 0xe6, 0x59, 0x85, 0x6c, 0x97, 0x01, 0x3e, 0x63, 0x86, 0x9a, 0xe2, 0xe0, 0x80, 0x5f, 0x04, 0xb8, 0x8c, 0x19, + 0x6a, 0x04, 0x16, 0x7b, 0x0f, 0x4b, 0x7b, 0x32, 0xc3, 0x35, 0xc1, 0xb3, 0xb2, 0xbc, 0x5f, 0x0c, 0x2e, 0xb4, 0xa3, + 0x26, 0x61, 0xf0, 0x69, 0x45, 0x5a, 0x6e, 0x93, 0x75, 0x45, 0x53, 0x5d, 0xb6, 0xbb, 0x48, 0x12, 0xd5, 0x10, 0x97, + 0x97, 0x6d, 0x0c, 0x2a, 0xf9, 0x9e, 0x22, 0x32, 0x15, 0xc4, 0x3b, 0xc8, 0x2d, 0x73, 0x99, 0x2a, 0x3c, 0xe5, 0xa9, + 0xf0, 0x72, 0xf6, 0x6b, 0x6f, 0x3d, 0x6d, 0x5c, 0x16, 0x4d, 0xcf, 0x0c, 0x8b, 0x9e, 0x2a, 0x5d, 0xed, 0x60, 0x93, + 0xaa, 0x01, 0xbc, 0xda, 0x57, 0x62, 0x1e, 0xb3, 0xfe, 0x65, 0x0c, 0xa2, 0x22, 0xab, 0x46, 0x1b, 0x32, 0xe1, 0x73, + 0x9d, 0x2a, 0x18, 0xa8, 0x29, 0x7c, 0x01, 0x64, 0x2a, 0xab, 0x0c, 0xb3, 0x7d, 0xc3, 0x50, 0x40, 0x40, 0x81, 0x4b, + 0xc2, 0x02, 0x09, 0x1e, 0x6e, 0x3f, 0x02, 0xc2, 0x51, 0x27, 0x17, 0x76, 0x72, 0x17, 0x0a, 0xba, 0x13, 0x83, 0x0b, + 0xdd, 0x45, 0xa2, 0xd1, 0x70, 0xdc, 0xf6, 0xa5, 0x30, 0x83, 0x68, 0xb6, 0x07, 0x97, 0xac, 0x8b, 0x54, 0xb3, 0x59, + 0x1a, 0x40, 0x5e, 0xb6, 0x56, 0x2b, 0x75, 0xe1, 0x1b, 0xe9, 0xf9, 0x73, 0xdc, 0xf0, 0x5d, 0x5e, 0xf0, 0xfc, 0x4d, + 0x92, 0x7e, 0x04, 0x54, 0x15, 0xf8, 0x6c, 0x39, 0x8f, 0x70, 0x64, 0x1e, 0x74, 0x83, 0xbf, 0xe6, 0x21, 0xae, 0x08, + 0x47, 0xee, 0x8d, 0xb7, 0x68, 0x50, 0x0d, 0x96, 0x67, 0x65, 0x78, 0x72, 0x9e, 0x5c, 0x03, 0xe3, 0xa0, 0xff, 0x56, + 0x68, 0x59, 0xfd, 0x4e, 0x72, 0x17, 0xa8, 0x43, 0xf9, 0x67, 0xc7, 0xdc, 0xa8, 0xd6, 0xbb, 0x5d, 0x23, 0x39, 0x8e, + 0x7c, 0x55, 0x08, 0xdf, 0xff, 0x9d, 0x77, 0x0f, 0xdb, 0xee, 0xb9, 0xed, 0x65, 0xd9, 0x03, 0x70, 0xde, 0xeb, 0x35, + 0xc2, 0xbf, 0xc9, 0x9d, 0x6f, 0xef, 0x46, 0xd7, 0x52, 0x3c, 0xa1, 0x9a, 0x46, 0x8d, 0x37, 0xc6, 0xf0, 0xcd, 0xca, + 0x59, 0xdd, 0x6f, 0x8d, 0x83, 0xfd, 0x5b, 0xdd, 0x43, 0xe8, 0x84, 0xda, 0x33, 0x41, 0x56, 0xf6, 0x35, 0x01, 0x33, + 0x64, 0x60, 0xfa, 0xb6, 0x03, 0x1e, 0x7e, 0x8c, 0x14, 0x1c, 0x7a, 0x2d, 0x9f, 0x44, 0x21, 0x26, 0x69, 0xcd, 0x8d, + 0x18, 0x52, 0x6c, 0x1f, 0xc6, 0xe5, 0x74, 0x8d, 0x42, 0xae, 0x7b, 0xac, 0xea, 0xc4, 0xb4, 0xea, 0xc6, 0x48, 0x1d, + 0x6c, 0x93, 0x05, 0x67, 0x55, 0xef, 0x46, 0x42, 0xa9, 0x5e, 0x54, 0x33, 0xaf, 0x62, 0x36, 0xdb, 0xe6, 0x99, 0x61, + 0xfb, 0xee, 0x9a, 0x02, 0x43, 0xde, 0xfd, 0x32, 0x5c, 0xd4, 0x25, 0x1c, 0xbb, 0x71, 0x00, 0x59, 0x49, 0x2e, 0x97, + 0xee, 0x4d, 0x34, 0xde, 0x97, 0x83, 0x75, 0xf9, 0x42, 0x5a, 0x80, 0x07, 0xd5, 0x48, 0x45, 0x16, 0x72, 0x06, 0xfe, + 0x79, 0xc1, 0x9a, 0x7e, 0x88, 0x7f, 0x85, 0x03, 0xbe, 0x42, 0xd2, 0xd4, 0xaa, 0x9f, 0xe0, 0xe5, 0x22, 0x50, 0x78, + 0xdb, 0xba, 0x9f, 0x64, 0xe8, 0x22, 0x5a, 0xd7, 0xa9, 0x58, 0x2f, 0xcc, 0xba, 0x62, 0xa5, 0x2c, 0x1c, 0x1c, 0x77, + 0x31, 0x5a, 0xa7, 0xce, 0x63, 0xd3, 0x3d, 0x77, 0xf4, 0x50, 0xf0, 0x99, 0x71, 0xa4, 0x7b, 0x56, 0x40, 0xfc, 0xaa, + 0x50, 0x9f, 0xf6, 0xb3, 0x0c, 0xdf, 0xf3, 0xed, 0xc3, 0x3d, 0x61, 0xc9, 0x73, 0x96, 0x6f, 0x50, 0xc3, 0x02, 0x29, + 0xa0, 0x50, 0x0a, 0x8b, 0xd5, 0x2a, 0x16, 0x26, 0xaa, 0x81, 0x0b, 0x6a, 0xeb, 0x5e, 0xaf, 0x30, 0xfa, 0x3b, 0xa8, + 0x8b, 0xbd, 0x7a, 0xc4, 0x98, 0xb0, 0xa2, 0xf0, 0xd2, 0x49, 0x65, 0x41, 0x5f, 0xbb, 0xfa, 0x10, 0xd5, 0x94, 0x7b, + 0xb1, 0xd1, 0xf7, 0xbe, 0xe3, 0x33, 0x26, 0x17, 0xf0, 0x6c, 0x10, 0x66, 0x44, 0x31, 0xed, 0xbf, 0x81, 0x82, 0xc0, + 0xdb, 0x33, 0x3c, 0xc4, 0x47, 0xe0, 0xab, 0x3c, 0xad, 0x93, 0x99, 0x7f, 0x8c, 0x22, 0x32, 0xc1, 0x22, 0xa3, 0x5e, + 0x04, 0x5e, 0x43, 0x20, 0x42, 0x11, 0x12, 0x31, 0x31, 0x8a, 0x7a, 0x91, 0x71, 0x52, 0x8a, 0xc0, 0x6a, 0x0c, 0x94, + 0xdc, 0x11, 0x9e, 0xab, 0x8a, 0x88, 0x85, 0x35, 0x75, 0x50, 0x89, 0xa5, 0xc6, 0x4c, 0xfb, 0xa8, 0x53, 0x81, 0xb0, + 0xc8, 0x36, 0x05, 0x65, 0xbd, 0xa1, 0x2e, 0xc0, 0x92, 0x18, 0xd3, 0x5b, 0x9e, 0x5c, 0x03, 0x37, 0xc7, 0x46, 0xae, + 0xe8, 0x92, 0x5f, 0x81, 0x7a, 0x3a, 0x2d, 0xf0, 0xb5, 0x61, 0xd8, 0x46, 0x29, 0x5d, 0x13, 0x8e, 0x33, 0x52, 0x24, + 0xf4, 0x16, 0xa2, 0x3a, 0xcc, 0xb8, 0x48, 0x73, 0x3c, 0xa3, 0xb7, 0xe9, 0x14, 0xcf, 0xb8, 0x78, 0x62, 0x97, 0x3d, + 0x1d, 0x41, 0x92, 0xff, 0x58, 0xac, 0x89, 0x79, 0x94, 0xea, 0x77, 0xc5, 0x8a, 0x47, 0xc0, 0xab, 0xa8, 0x18, 0x75, + 0x47, 0xc6, 0xa6, 0x9c, 0xe9, 0xca, 0x78, 0xfd, 0xb5, 0x8e, 0x29, 0xce, 0x70, 0x8e, 0x92, 0x5c, 0x62, 0xd6, 0x13, + 0xe9, 0x6b, 0x88, 0xe8, 0x9c, 0x61, 0xfb, 0xa0, 0x15, 0xbf, 0x65, 0xf9, 0x33, 0x59, 0xbc, 0x37, 0x5b, 0x3e, 0x47, + 0x50, 0x08, 0x5c, 0x54, 0x44, 0x13, 0x6e, 0xf7, 0x16, 0x3d, 0x59, 0x35, 0x45, 0x6f, 0x6d, 0x53, 0x6e, 0x88, 0x53, + 0x08, 0x85, 0x9b, 0x4c, 0x79, 0xa3, 0x8d, 0x59, 0xaf, 0xf5, 0x9d, 0x46, 0xa7, 0xa8, 0x2c, 0x89, 0x30, 0xac, 0x55, + 0x53, 0xa5, 0x92, 0x88, 0xa6, 0x72, 0x12, 0xde, 0xd2, 0x00, 0x3b, 0x55, 0x38, 0x93, 0x0b, 0xa1, 0x53, 0x19, 0xe0, + 0x0d, 0xad, 0x36, 0xd7, 0xf2, 0xd6, 0x42, 0x4c, 0xe3, 0x3b, 0xfb, 0x83, 0xe1, 0x6b, 0xa3, 0xe2, 0x7f, 0x0b, 0x86, + 0x3d, 0x2a, 0x15, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x59, 0x7e, 0xf2, 0x16, 0xc0, 0x67, 0x59, 0xc8, 0x3b, 0x48, + 0x65, 0x26, 0xf5, 0x0e, 0x52, 0x19, 0xa4, 0x1a, 0x5f, 0xee, 0x7d, 0x51, 0x29, 0x8b, 0xc2, 0x06, 0x89, 0xc2, 0xa5, + 0x3a, 0x58, 0x12, 0x91, 0x40, 0xbb, 0x46, 0x94, 0x9b, 0x71, 0x01, 0x41, 0xfd, 0xa0, 0x71, 0xfb, 0x4d, 0x6f, 0xe1, + 0xfb, 0xce, 0xe6, 0x33, 0x9f, 0x7f, 0x67, 0xf3, 0x4d, 0x47, 0x1e, 0xe3, 0xeb, 0xb7, 0x9d, 0xc6, 0x32, 0x5e, 0x3a, + 0xac, 0xfd, 0x50, 0x3e, 0xa1, 0xd2, 0x32, 0x4f, 0x55, 0x93, 0x36, 0x9e, 0x04, 0x48, 0xd9, 0xac, 0x78, 0xb8, 0x0e, + 0x6e, 0xb7, 0x0e, 0x63, 0xde, 0x24, 0x6d, 0x84, 0x0e, 0x9d, 0x70, 0x25, 0x62, 0x23, 0x39, 0x1d, 0x3e, 0x3a, 0x82, + 0xbb, 0x97, 0x99, 0xda, 0xf0, 0x95, 0xb2, 0xd5, 0x9a, 0xed, 0xd6, 0x21, 0xdf, 0x59, 0xa5, 0xd1, 0xc6, 0x33, 0x46, + 0x96, 0xe0, 0x5c, 0x46, 0x0b, 0xab, 0x6a, 0x00, 0x27, 0xce, 0x17, 0xe2, 0xb7, 0x05, 0x1d, 0x99, 0xef, 0x43, 0x9b, + 0xf2, 0x7a, 0xa1, 0x7d, 0x52, 0x93, 0xc3, 0x20, 0x3a, 0xc8, 0x95, 0x0c, 0x72, 0x62, 0x7e, 0x44, 0x92, 0x53, 0x74, + 0xd1, 0xee, 0x25, 0xa7, 0x87, 0xfc, 0x90, 0xa7, 0xc0, 0xc3, 0xc6, 0x4d, 0x5f, 0xa1, 0xd9, 0xf6, 0x75, 0x1e, 0x2f, + 0x86, 0x3c, 0x73, 0xcd, 0x57, 0x1d, 0x94, 0xa9, 0x76, 0x8e, 0x90, 0x05, 0x28, 0xe6, 0x7b, 0x09, 0xb2, 0xeb, 0xdd, + 0x1c, 0xf2, 0x14, 0xfa, 0x81, 0x5a, 0x1d, 0x5b, 0xab, 0x1c, 0xdc, 0x6f, 0x0b, 0x40, 0x30, 0xdf, 0x51, 0x6d, 0x2e, + 0x36, 0xbd, 0x19, 0x57, 0x9d, 0x1d, 0xf2, 0x6a, 0x84, 0x61, 0x99, 0xed, 0xfe, 0xfc, 0xd4, 0xaa, 0x2e, 0x0f, 0x03, + 0x88, 0xfc, 0xb6, 0xe0, 0x22, 0xec, 0x34, 0xec, 0xd6, 0xe5, 0x84, 0x9d, 0xd6, 0x67, 0x19, 0x14, 0xd9, 0xee, 0x75, + 0x6b, 0xa6, 0xf5, 0xd9, 0x5e, 0x81, 0x8f, 0x20, 0x4c, 0xca, 0xac, 0x74, 0x06, 0x57, 0xe8, 0x87, 0x1f, 0x90, 0x6b, + 0xfd, 0xf5, 0x42, 0xfb, 0xfc, 0x12, 0x11, 0x20, 0xbb, 0xea, 0xba, 0xac, 0x0e, 0x7d, 0x94, 0x4d, 0x7c, 0x3d, 0xe4, + 0xc1, 0xca, 0x3d, 0xbd, 0x9d, 0xcb, 0xd4, 0xe3, 0x6b, 0xaf, 0x95, 0x6e, 0x21, 0x27, 0x10, 0x0f, 0xd7, 0x5d, 0x58, + 0x16, 0xe4, 0xec, 0xe6, 0x16, 0x4a, 0x86, 0x13, 0xf7, 0xa5, 0x3f, 0x30, 0x7b, 0xdd, 0xc0, 0x2f, 0x92, 0x53, 0x98, + 0xfa, 0x66, 0x0f, 0x87, 0x1d, 0xe8, 0xc3, 0xc0, 0x61, 0xb3, 0x41, 0x9f, 0x59, 0x41, 0xe4, 0x31, 0x2f, 0x2c, 0x9e, + 0x5d, 0x92, 0x76, 0x8f, 0xa7, 0x6e, 0x33, 0x19, 0xd1, 0xa8, 0xdd, 0xe4, 0xc1, 0xcc, 0x00, 0xbf, 0x5c, 0xd9, 0xb0, + 0x88, 0x5f, 0xa7, 0x00, 0x4a, 0xbe, 0x58, 0xb5, 0x3e, 0x15, 0xbc, 0xea, 0x0d, 0xa7, 0x9b, 0xe9, 0x7e, 0xdd, 0xe0, + 0x76, 0xd7, 0xc3, 0x13, 0x9e, 0x40, 0xb1, 0x68, 0xed, 0x27, 0x3e, 0x01, 0x0e, 0x28, 0x69, 0xdd, 0x3f, 0x05, 0x17, + 0xca, 0x12, 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x2c, 0x1c, 0x6d, 0xc9, 0x80, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, + 0xd8, 0xc1, 0x49, 0xbb, 0xdd, 0x39, 0xc5, 0xc9, 0xc9, 0x29, 0x0c, 0xb4, 0x91, 0x9c, 0x1e, 0xce, 0x94, 0x05, 0x60, + 0x90, 0xb3, 0x76, 0xed, 0x3e, 0x82, 0x70, 0x49, 0xa1, 0x78, 0xcd, 0x0f, 0xe3, 0xb8, 0x9d, 0xdc, 0x6f, 0xb5, 0x4f, + 0xcf, 0x1b, 0x00, 0xa0, 0xa6, 0xfb, 0x70, 0x35, 0x5e, 0x2f, 0x74, 0xbd, 0x4a, 0x89, 0xf0, 0xf5, 0x6a, 0x0d, 0x5f, + 0xad, 0xd1, 0x5e, 0x57, 0x53, 0xf0, 0x55, 0x9d, 0x70, 0x6e, 0x8b, 0x78, 0xa5, 0x4d, 0xb8, 0x2d, 0x62, 0x3b, 0x90, + 0x18, 0xa4, 0xf3, 0xe4, 0xb4, 0x73, 0x8a, 0xec, 0x58, 0xb4, 0xc3, 0x8f, 0x72, 0x9f, 0x6c, 0x15, 0x69, 0x68, 0x40, + 0x92, 0x72, 0x76, 0x72, 0x01, 0x12, 0x35, 0x27, 0x97, 0xed, 0xe6, 0x8c, 0x25, 0x7e, 0x02, 0x26, 0x15, 0x96, 0xb3, + 0x5c, 0x05, 0x97, 0x14, 0x00, 0xe2, 0x02, 0x8c, 0x8b, 0xee, 0x9f, 0xf6, 0xee, 0x27, 0xa7, 0x67, 0x1d, 0x4b, 0xf4, + 0xf8, 0x45, 0xa7, 0x96, 0x66, 0xa6, 0x9e, 0x9c, 0x9a, 0x34, 0xe8, 0x3a, 0xb9, 0x7f, 0x0a, 0x65, 0x5c, 0x4a, 0x58, + 0x0a, 0xc2, 0x3c, 0x54, 0xc5, 0x20, 0xb6, 0x43, 0x5a, 0xcb, 0x3d, 0xab, 0x65, 0x9f, 0x9f, 0x1c, 0xdf, 0x3f, 0x0d, + 0xa1, 0x56, 0xce, 0xc2, 0x2c, 0xb4, 0x9b, 0x88, 0x9f, 0x1d, 0x2c, 0x2d, 0x3a, 0x4c, 0x4e, 0xd3, 0xad, 0x09, 0xda, + 0x4d, 0x73, 0x68, 0x70, 0x20, 0x50, 0x38, 0x3e, 0x15, 0x4e, 0x5f, 0x12, 0xdc, 0x8f, 0x55, 0x86, 0x26, 0xa1, 0xc2, + 0xd9, 0xdf, 0x53, 0x06, 0x2f, 0x39, 0x86, 0x57, 0x95, 0x8f, 0xa9, 0xf8, 0x42, 0xd5, 0x1b, 0x0a, 0xb1, 0x2b, 0xc4, + 0x20, 0x72, 0x91, 0xb5, 0xeb, 0xb9, 0x3f, 0x81, 0x8b, 0x30, 0x13, 0x70, 0xa1, 0xe9, 0x95, 0xa0, 0x15, 0x2f, 0x30, + 0x0c, 0x1d, 0x6a, 0xcd, 0xb0, 0x7a, 0x3c, 0x75, 0x26, 0x05, 0xa1, 0x6e, 0xeb, 0x39, 0xff, 0x5e, 0xb9, 0xa4, 0xbc, + 0xca, 0x4e, 0x4e, 0x51, 0xe2, 0x2e, 0xcb, 0x93, 0x36, 0x4a, 0x02, 0x13, 0x12, 0x77, 0x24, 0x67, 0x19, 0xe9, 0x47, + 0xb7, 0x11, 0x8e, 0xee, 0x22, 0x1c, 0x59, 0x1f, 0xe6, 0x0f, 0xe0, 0x3c, 0x1f, 0xe1, 0xc8, 0xba, 0x32, 0x47, 0x38, + 0xd2, 0x4c, 0x40, 0x48, 0xab, 0x68, 0x80, 0x73, 0x28, 0x6d, 0x3c, 0xab, 0xcb, 0xd2, 0x8f, 0xfd, 0x57, 0xe9, 0x7a, + 0x6d, 0x53, 0x02, 0x29, 0x73, 0x6a, 0x76, 0xa8, 0x7d, 0x92, 0x39, 0xa2, 0x9e, 0x59, 0x8f, 0x30, 0x08, 0x20, 0xf4, + 0xce, 0x3f, 0xe9, 0x56, 0x45, 0xc3, 0x60, 0xc7, 0xb0, 0xd2, 0xe0, 0x67, 0x1e, 0x85, 0x67, 0x58, 0x84, 0xc7, 0xc2, + 0x17, 0x06, 0xb1, 0xc2, 0xff, 0xce, 0xa5, 0x9c, 0xfb, 0xdf, 0x5a, 0x96, 0xbf, 0xe0, 0x21, 0x10, 0x67, 0xd1, 0x02, + 0x96, 0x5b, 0x36, 0xf8, 0xce, 0x90, 0xd5, 0x47, 0x70, 0x3d, 0x76, 0x01, 0xd2, 0x40, 0x22, 0xbc, 0x36, 0x02, 0x95, + 0x97, 0x0f, 0xaf, 0x6d, 0xb0, 0x1e, 0xf3, 0x09, 0xd1, 0xba, 0x20, 0x20, 0xaf, 0x84, 0x0b, 0x8d, 0x49, 0xc1, 0x94, + 0x8a, 0x6c, 0x14, 0xbb, 0x48, 0x0a, 0xff, 0x2c, 0xa1, 0x4f, 0x19, 0x8b, 0xc8, 0x74, 0x58, 0x9f, 0xad, 0x15, 0x87, + 0x73, 0x59, 0xa8, 0xd4, 0xbe, 0x51, 0xe2, 0xc1, 0x58, 0x3d, 0x55, 0x9f, 0xe6, 0xd9, 0x1a, 0xdb, 0x3b, 0xec, 0xb2, + 0x90, 0xbb, 0xd2, 0x0e, 0x4b, 0x65, 0xd9, 0xfa, 0x5b, 0x13, 0x52, 0xb5, 0x19, 0x05, 0x13, 0xad, 0x06, 0x54, 0x85, + 0xb2, 0x80, 0xc2, 0x36, 0x1c, 0x4a, 0xba, 0x2c, 0x4b, 0xa6, 0xcb, 0x72, 0x19, 0x4e, 0x5a, 0xad, 0xf5, 0x1a, 0x17, + 0xcc, 0x84, 0x65, 0xd9, 0x59, 0x02, 0xf2, 0xd5, 0x54, 0xde, 0x04, 0xb9, 0x2a, 0x2d, 0x67, 0x69, 0x96, 0x28, 0x0a, + 0x8c, 0x60, 0xa3, 0x35, 0xfe, 0xc2, 0x15, 0x07, 0x78, 0xba, 0xd9, 0x0d, 0xa5, 0xcc, 0x19, 0x85, 0xe8, 0x5d, 0x41, + 0x93, 0x6b, 0x3c, 0xe5, 0x23, 0xb6, 0xbb, 0x4d, 0x30, 0x63, 0xfe, 0xf7, 0x5a, 0xf4, 0x08, 0x64, 0xd9, 0x3d, 0x83, + 0x3a, 0xb0, 0x88, 0x2b, 0xe8, 0x20, 0x94, 0xc1, 0x47, 0x21, 0x6e, 0xe6, 0xf4, 0x4e, 0x2e, 0x34, 0xc0, 0x65, 0xa1, + 0xe5, 0x1b, 0x17, 0xeb, 0x60, 0xbf, 0x85, 0x7d, 0xd8, 0x83, 0x25, 0x84, 0x0c, 0x68, 0x61, 0x1b, 0x23, 0xa2, 0x85, + 0x87, 0x52, 0x6b, 0x39, 0x4b, 0x5b, 0xd8, 0x04, 0x6c, 0x68, 0xad, 0xcb, 0xa8, 0x5a, 0xd7, 0xe5, 0x63, 0x8e, 0xd5, + 0x26, 0x58, 0x38, 0xe9, 0x50, 0x13, 0x1d, 0xdc, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbd, 0x7e, 0xe5, 0x62, 0x26, + 0xf3, 0x31, 0xb8, 0x6c, 0x3a, 0xd5, 0xd8, 0xb5, 0x79, 0x05, 0x29, 0xae, 0x14, 0xa5, 0x56, 0x38, 0x85, 0x96, 0x5f, + 0x08, 0x9d, 0x27, 0xf6, 0xf2, 0xe2, 0x99, 0x2c, 0x66, 0xd4, 0xde, 0x18, 0xe1, 0x6b, 0xe5, 0x9e, 0x3d, 0x37, 0x2f, + 0xab, 0x54, 0x93, 0x7c, 0xb7, 0x79, 0x15, 0xb1, 0xc8, 0x8c, 0xfc, 0x0a, 0xda, 0x00, 0x53, 0xb9, 0x7c, 0xb5, 0xb6, + 0x20, 0x2e, 0xf2, 0x7c, 0x40, 0x5e, 0xde, 0x5a, 0xea, 0x12, 0x45, 0x0d, 0x6e, 0xf0, 0x93, 0x15, 0x3c, 0x0b, 0xae, + 0x0b, 0x0d, 0x7b, 0xe4, 0xc4, 0x8b, 0xa8, 0x15, 0xd5, 0x5f, 0x7d, 0x35, 0xaa, 0x04, 0x1f, 0xb5, 0x34, 0xc9, 0x25, + 0x88, 0x1e, 0xe5, 0x03, 0x73, 0x1c, 0x44, 0x13, 0x7f, 0xf7, 0x7c, 0xd9, 0xf6, 0x74, 0x36, 0xaf, 0xd4, 0x89, 0xe5, + 0x95, 0x09, 0x78, 0x38, 0xda, 0x27, 0x5c, 0x10, 0x0e, 0x12, 0x59, 0xa9, 0x3d, 0xf4, 0xb9, 0xa8, 0x1b, 0xe7, 0x17, + 0x6d, 0xd6, 0x3c, 0x59, 0xad, 0xf2, 0xcb, 0x36, 0x6b, 0x9f, 0xda, 0x07, 0xdf, 0x22, 0x95, 0x01, 0xcd, 0xe5, 0x63, + 0x9e, 0x45, 0xa0, 0x9d, 0x1d, 0x67, 0x26, 0x9c, 0x82, 0x0f, 0x51, 0x4c, 0x16, 0xba, 0xea, 0x4b, 0x82, 0x71, 0x29, + 0xb1, 0x7a, 0xfc, 0x02, 0xf5, 0xda, 0xe9, 0xb6, 0xab, 0x74, 0xb3, 0x7d, 0x18, 0x5c, 0xb8, 0x14, 0x08, 0x77, 0x20, + 0xe4, 0x01, 0xe8, 0x77, 0x97, 0x02, 0x4c, 0x83, 0x00, 0x95, 0x15, 0x88, 0xb4, 0x7c, 0xb6, 0x98, 0x3d, 0x2b, 0xa8, + 0x59, 0x86, 0x27, 0x7c, 0xc2, 0xb5, 0x4a, 0x29, 0x48, 0xb7, 0xbb, 0xd2, 0xd7, 0xbb, 0x25, 0xa8, 0xac, 0x16, 0xf9, + 0x35, 0xd1, 0x3c, 0xfb, 0xac, 0xdc, 0xc2, 0x21, 0x6c, 0x56, 0x56, 0xe0, 0x0c, 0xad, 0x71, 0x2e, 0x27, 0xb4, 0xe0, + 0x7a, 0x3a, 0xfb, 0xb7, 0x56, 0x87, 0xf5, 0xf5, 0xc0, 0x5c, 0x58, 0x01, 0x48, 0xa8, 0x18, 0xad, 0x56, 0xfc, 0xe8, + 0xfb, 0xf7, 0x49, 0xde, 0x27, 0xbc, 0x8d, 0x3b, 0xf8, 0x18, 0x9f, 0xe2, 0x76, 0x0b, 0xb7, 0x4f, 0xe1, 0xea, 0x3e, + 0xcb, 0x17, 0x23, 0xa6, 0x62, 0x78, 0xf9, 0x4b, 0x5f, 0x26, 0xe7, 0x87, 0x65, 0xbc, 0x7b, 0x5d, 0x24, 0x0e, 0x5d, + 0x82, 0xb0, 0xeb, 0x2e, 0x5e, 0x5d, 0x14, 0x85, 0xc1, 0xd2, 0xc6, 0xa1, 0xea, 0xa4, 0xd4, 0x2f, 0x5c, 0x1e, 0xf7, + 0xc0, 0x9e, 0xdb, 0xae, 0x6c, 0x13, 0xcc, 0xbe, 0xed, 0xcf, 0xb4, 0xfa, 0xd9, 0xd4, 0x25, 0x62, 0x78, 0xe8, 0x55, + 0xe8, 0x81, 0x2e, 0x49, 0xfb, 0xe0, 0x00, 0xac, 0x8e, 0x82, 0xd9, 0x70, 0x1b, 0xfd, 0x80, 0x37, 0x6b, 0x69, 0x10, + 0xac, 0x00, 0x8c, 0x3b, 0xdf, 0x70, 0xb2, 0xb4, 0xb0, 0xd5, 0x40, 0x85, 0x75, 0x11, 0x46, 0x74, 0x0b, 0x49, 0x85, + 0x11, 0xa2, 0xe1, 0x08, 0x73, 0x91, 0x4e, 0xf6, 0x5b, 0x58, 0x8e, 0xc7, 0x8a, 0x69, 0x38, 0x3a, 0x0a, 0xf6, 0x85, + 0x15, 0xca, 0x9c, 0x22, 0x43, 0x36, 0xe1, 0xe2, 0xa1, 0xfe, 0xc4, 0x0a, 0x69, 0x3e, 0x8d, 0x06, 0x23, 0x8d, 0xcc, + 0x2a, 0x46, 0x38, 0xcb, 0xf9, 0x1c, 0xaa, 0x4e, 0x0a, 0x70, 0xfa, 0x81, 0xbf, 0x7c, 0x94, 0x86, 0x6d, 0x02, 0xf9, + 0xfa, 0x60, 0x83, 0xd9, 0xe0, 0x51, 0x41, 0x6f, 0x5e, 0x8b, 0xc7, 0xb0, 0xa3, 0x1e, 0x16, 0x8c, 0x42, 0x36, 0x24, + 0xbd, 0x83, 0xa6, 0xe0, 0x03, 0xda, 0x7c, 0x69, 0x00, 0x97, 0x9e, 0x9b, 0x0f, 0x5b, 0xd1, 0x47, 0x0d, 0x4c, 0xca, + 0xb6, 0x4c, 0xa6, 0x39, 0xa5, 0xab, 0x4c, 0x1b, 0x97, 0xa9, 0x9c, 0xc2, 0x1a, 0xbb, 0xa8, 0x27, 0xe1, 0x60, 0x46, + 0x54, 0x4d, 0xd3, 0xfe, 0xc0, 0xfc, 0x7d, 0x6d, 0x4b, 0xb6, 0xb0, 0x0b, 0xb5, 0xb3, 0xc6, 0xe6, 0xc9, 0xce, 0xa0, + 0x7c, 0x1b, 0xc3, 0x3d, 0x2c, 0xbc, 0x1b, 0x59, 0x23, 0x9f, 0x27, 0x9e, 0x6c, 0x9e, 0xac, 0xd7, 0x66, 0x20, 0x2a, + 0x05, 0x3d, 0xd0, 0x5b, 0xbf, 0x6d, 0x5a, 0xb0, 0x3d, 0xca, 0xaf, 0xd3, 0x16, 0x9e, 0x71, 0x78, 0x06, 0xd3, 0xb7, + 0x77, 0xa5, 0x0b, 0xf9, 0xd9, 0x81, 0xa4, 0x15, 0xa4, 0xd8, 0xe9, 0x04, 0x9d, 0x1d, 0xe3, 0x60, 0xe4, 0x40, 0xcf, + 0xaf, 0x3e, 0x5b, 0x58, 0xfb, 0xdf, 0x6f, 0xca, 0x82, 0x39, 0x1d, 0xb2, 0xbc, 0x9c, 0x50, 0xe6, 0xcf, 0xcf, 0x37, + 0x3c, 0xa9, 0x50, 0xc1, 0xbd, 0x1f, 0x05, 0x7b, 0xda, 0x86, 0x98, 0x9c, 0xd1, 0xbf, 0xed, 0x0f, 0x1b, 0x11, 0xa8, + 0xd4, 0xb2, 0x65, 0x85, 0x54, 0xea, 0xa1, 0x4d, 0xb3, 0x47, 0x0f, 0x1c, 0x91, 0x2f, 0xa1, 0x0b, 0xe0, 0xf5, 0x47, + 0x85, 0x9c, 0x1b, 0x44, 0x70, 0xbf, 0xdd, 0xb8, 0x8d, 0xaf, 0x00, 0x78, 0x3b, 0xec, 0x55, 0xff, 0xb4, 0x80, 0xfd, + 0x8d, 0xca, 0x92, 0x7e, 0xbc, 0x1d, 0x7b, 0xfc, 0x17, 0x12, 0xe2, 0x95, 0x5b, 0x3c, 0x4c, 0x1c, 0x3a, 0x95, 0xac, + 0x59, 0xf9, 0x73, 0xab, 0x24, 0x60, 0x58, 0xbd, 0x60, 0xc8, 0xc6, 0x6d, 0x15, 0xb7, 0x99, 0xff, 0x41, 0x05, 0x83, + 0x05, 0xdf, 0x1a, 0x49, 0xc5, 0xb2, 0xf8, 0xed, 0x53, 0xe7, 0xbf, 0xea, 0x1c, 0xd7, 0xbe, 0xae, 0xbd, 0x51, 0x39, + 0x34, 0xf1, 0x81, 0x23, 0x74, 0x70, 0xb0, 0x91, 0x41, 0xc7, 0x00, 0x78, 0xe4, 0xd8, 0x2f, 0xbf, 0x7c, 0x9e, 0x1d, + 0x33, 0x9a, 0xc7, 0x22, 0x0a, 0x99, 0x3b, 0xcf, 0xcd, 0xd9, 0x89, 0x3c, 0xa1, 0x6a, 0xea, 0x0b, 0x03, 0x1c, 0x1f, + 0x6d, 0xa5, 0x02, 0xbe, 0x47, 0xeb, 0x1d, 0x13, 0xd8, 0xe0, 0xb7, 0xec, 0xa4, 0x76, 0x15, 0xf4, 0x0b, 0xb4, 0xdc, + 0xc5, 0x54, 0x6e, 0x2c, 0x70, 0xb4, 0x39, 0x91, 0x9d, 0x43, 0xdf, 0xa8, 0x53, 0xb2, 0x1e, 0x4f, 0x76, 0x1b, 0x7d, + 0x49, 0xb1, 0x2b, 0xb9, 0xa2, 0x6d, 0x43, 0x56, 0xbd, 0x53, 0xab, 0x2b, 0x53, 0xa7, 0xea, 0x9a, 0xb7, 0xb2, 0xb4, + 0x29, 0xed, 0x92, 0xec, 0xdd, 0x16, 0x0b, 0xaf, 0xc2, 0x1b, 0x8d, 0xf2, 0x22, 0x14, 0xec, 0xb1, 0xc4, 0xa0, 0xcb, + 0x09, 0x5c, 0x2f, 0xac, 0x56, 0x31, 0xfc, 0xd9, 0x35, 0x86, 0x5d, 0xa6, 0x4b, 0x1f, 0xf8, 0x06, 0xbf, 0x12, 0x84, + 0xca, 0x75, 0x76, 0x90, 0x60, 0xdd, 0xe5, 0x06, 0x0d, 0xc7, 0x89, 0xff, 0x82, 0x87, 0x9a, 0xb5, 0x77, 0x39, 0x98, + 0x64, 0xdf, 0x78, 0xdc, 0xad, 0x64, 0x2d, 0x6b, 0x71, 0xd6, 0x37, 0x24, 0x18, 0x62, 0x37, 0xa5, 0x73, 0xdc, 0x4a, + 0xda, 0x28, 0x72, 0xc5, 0x2a, 0xf4, 0xff, 0x56, 0x91, 0xcc, 0x66, 0xfe, 0xd7, 0xd9, 0xd9, 0x99, 0x4b, 0x71, 0x36, + 0x7f, 0xca, 0x78, 0xc0, 0x99, 0x04, 0xf6, 0x85, 0x67, 0xcc, 0xe8, 0x90, 0xdf, 0xc2, 0x50, 0x88, 0x20, 0x97, 0xc2, + 0xb1, 0x4b, 0xf0, 0xce, 0x20, 0x50, 0x1e, 0x60, 0xff, 0x9e, 0x6c, 0x94, 0xf3, 0x0f, 0x15, 0xf9, 0x40, 0xbe, 0x65, + 0x83, 0xec, 0x8b, 0xf9, 0xec, 0x5b, 0x33, 0x19, 0x88, 0xcd, 0x1f, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, + 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, 0x0f, 0x53, 0xd6, 0x3d, 0x72, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0xc5, + 0xa3, 0x8c, 0x7e, 0x2c, 0x43, 0x4f, 0xee, 0xbd, 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, + 0x69, 0xfe, 0x23, 0xde, 0xab, 0x42, 0x50, 0x82, 0x2b, 0xa4, 0x89, 0xe2, 0x88, 0xcd, 0x83, 0xce, 0x69, 0x24, 0x80, + 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0xa8, 0x85, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0x16, 0xa9, 0x0d, 0xe1, + 0x0d, 0x91, 0xdc, 0xca, 0xd9, 0x98, 0xaf, 0x47, 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, + 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, + 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, 0x93, 0xdb, 0x60, 0xaa, 0x7f, 0x82, 0x1d, 0x08, 0x3d, 0x53, 0x3a, + 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, + 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, + 0xcc, 0x63, 0xd2, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, + 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, 0xde, 0x72, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, + 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, 0xcc, 0xc5, 0xc3, 0xf0, 0xd1, 0x77, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, + 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0x32, 0xdd, 0xd9, 0x0d, 0xa3, 0xb5, 0x79, 0x6e, 0x29, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, + 0x04, 0xd9, 0xda, 0x3c, 0xd8, 0x54, 0x66, 0x0d, 0x59, 0xf9, 0x3a, 0x41, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, + 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, + 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x22, 0xd7, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, + 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, 0x53, 0x70, 0xed, 0x43, 0xe4, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, + 0x18, 0x5d, 0x1b, 0xc8, 0xd7, 0x9b, 0x73, 0x9a, 0xb8, 0xb3, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, + 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, + 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x03, + 0x51, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, + 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, + 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, + 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, + 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0xa7, 0x1a, 0x35, 0x62, 0x9e, + 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, + 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, + 0xaa, 0x16, 0x85, 0x79, 0xba, 0x2d, 0x56, 0x28, 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0x52, 0x9a, 0x04, 0xc3, + 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, + 0x71, 0x38, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, + 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, 0xec, 0x9e, 0xae, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, + 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0xd7, 0xb5, 0xb8, 0x4b, 0x72, 0x0f, 0x64, 0x54, 0x6f, 0x60, 0xd7, 0x2c, 0xc0, + 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, 0x69, 0x9e, 0x52, 0xa2, 0xe6, 0x05, 0x25, 0x78, 0xb8, 0x99, 0xb0, + 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x68, 0x7b, 0xff, 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, + 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, + 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x67, 0x36, 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x0f, 0x6a, + 0x54, 0x0f, 0x9a, 0xfb, 0xe7, 0x9d, 0x8e, 0x3a, 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, + 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x9e, + 0xe0, 0xa8, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, 0xe6, 0xfe, 0x65, 0xcf, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, + 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, + 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, + 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, 0x5e, 0xdd, 0x01, 0x2b, 0x01, 0x1f, 0xfd, 0xd8, 0x24, 0x19, 0x43, + 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, + 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, + 0x20, 0x7e, 0x29, 0x74, 0x62, 0x22, 0x45, 0x5f, 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, + 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0x63, 0xc8, 0xe3, 0x52, + 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x71, 0xba, 0x5f, + 0x40, 0xd4, 0x66, 0x77, 0x2c, 0x81, 0x9e, 0x7d, 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, + 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0xde, 0x53, 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, + 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, + 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, + 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, + 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, 0x6c, 0x28, 0x5b, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, + 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, + 0x6d, 0xcb, 0x21, 0x18, 0x76, 0xa4, 0x0b, 0x6e, 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, + 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, + 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xd0, + 0xe5, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, + 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, + 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, + 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, + 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, + 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, + 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, + 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, + 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, + 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, + 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, + 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, + 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, + 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0xdf, + 0xe6, 0x84, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, + 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, + 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, + 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, + 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, + 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, + 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, 0xa9, 0x3e, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, + 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, + 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, + 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, + 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, + 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, + 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, + 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0xef, 0x6a, 0x01, 0x97, + 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, + 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x0b, 0xb3, 0x9f, + 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, + 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, + 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, + 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, + 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, + 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, + 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, + 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, + 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, 0x9a, 0xce, 0x3c, 0x8a, 0x5c, 0x7b, 0xef, 0x77, 0x53, 0xb4, 0xf5, + 0xaf, 0x0f, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, + 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, + 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, + 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, + 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, + 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, + 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, + 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, + 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, + 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, + 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, + 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, + 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0x3d, 0x45, 0xb7, 0x72, 0xef, 0xf4, + 0xac, 0xcc, 0xeb, 0x4a, 0xab, 0x58, 0x0e, 0x73, 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, + 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, + 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, + 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, + 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, + 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, + 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, 0x89, 0x17, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, + 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, + 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, + 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, + 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, + 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, + 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, + 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, + 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, 0xbd, 0xbb, 0xe1, 0xbb, 0x70, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, + 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0x3c, 0x15, 0x19, + 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, + 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, + 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, 0x67, 0xf7, 0x2e, 0x61, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, + 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, + 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, + 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, + 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, + 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, 0x55, 0x31, 0xdd, 0x0f, 0xdf, 0xd3, 0x0b, 0x3e, 0xbc, 0x43, 0xda, + 0xc6, 0xa3, 0x96, 0x94, 0x50, 0xbb, 0x83, 0xf6, 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, + 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, 0xca, 0x28, 0x18, 0xc2, 0x3e, 0x60, 0x1f, 0x8b, 0x24, 0xa3, 0xd9, + 0x94, 0x81, 0xba, 0xdf, 0x16, 0xad, 0xe6, 0xf6, 0xa4, 0xee, 0x37, 0x64, 0x9c, 0x7d, 0x84, 0x71, 0xf6, 0x51, 0xe0, + 0xc5, 0x22, 0xc9, 0x1f, 0x32, 0xd6, 0x38, 0x56, 0x4d, 0x81, 0x8e, 0x3a, 0xc0, 0x9d, 0x81, 0x03, 0x0f, 0xd8, 0xa2, + 0x1c, 0x1c, 0x50, 0x67, 0x71, 0x4f, 0x1b, 0x99, 0xf7, 0xf6, 0x84, 0xda, 0x45, 0x2c, 0x70, 0xb3, 0x66, 0xa6, 0x05, + 0xad, 0x15, 0xc6, 0x79, 0x3c, 0xe0, 0x6d, 0x9e, 0xd5, 0xe2, 0x27, 0x6c, 0x58, 0x53, 0xd5, 0x6f, 0xa0, 0x39, 0xaa, + 0x05, 0xb9, 0x79, 0x62, 0xbc, 0x55, 0x49, 0x3f, 0x8a, 0x06, 0x96, 0x53, 0x21, 0x86, 0x64, 0xf4, 0x5b, 0x83, 0xe0, + 0x56, 0x7b, 0xb5, 0xe2, 0x1e, 0xf1, 0x45, 0xcd, 0x5b, 0xcd, 0xdc, 0x02, 0xd0, 0x22, 0x8e, 0xca, 0x7b, 0x93, 0x08, + 0xbc, 0x6f, 0xcb, 0x08, 0x69, 0xcb, 0xbe, 0x7d, 0x34, 0xb1, 0x54, 0x6c, 0xbe, 0xa3, 0x93, 0x41, 0x1a, 0xd9, 0x11, + 0x45, 0xf8, 0xba, 0x84, 0x24, 0x5c, 0x25, 0x5d, 0xab, 0x4c, 0xce, 0x99, 0x4a, 0x39, 0xbe, 0x2e, 0xa4, 0xd4, 0x57, + 0xf6, 0x4b, 0xe2, 0xea, 0x4e, 0x46, 0xe0, 0xeb, 0x09, 0xd3, 0xef, 0x68, 0x31, 0x61, 0xe0, 0x57, 0xe4, 0x6f, 0xc7, + 0x52, 0x4a, 0x2e, 0x9f, 0x88, 0xb8, 0x4f, 0x31, 0xbc, 0xf8, 0x39, 0xc0, 0xda, 0x84, 0x40, 0x29, 0x71, 0x11, 0x2e, + 0x88, 0xde, 0x14, 0xf2, 0xf6, 0x2e, 0x2e, 0xb0, 0x73, 0x00, 0x2c, 0x9d, 0x26, 0x01, 0xfe, 0xe5, 0x63, 0x3e, 0x56, + 0x63, 0x4e, 0x8d, 0xae, 0xdf, 0xfd, 0x4e, 0xae, 0x81, 0xde, 0x96, 0x8e, 0x82, 0xfd, 0xd6, 0x00, 0x72, 0xe1, 0x2e, + 0x0c, 0x2e, 0xbe, 0xc2, 0xda, 0xb2, 0x30, 0xde, 0x58, 0x00, 0xbd, 0xbf, 0x33, 0xb0, 0x60, 0xc3, 0x1c, 0x53, 0x78, + 0x2e, 0x75, 0xc2, 0x74, 0x10, 0x15, 0xe4, 0x49, 0xf9, 0x20, 0x66, 0xad, 0xf6, 0x5b, 0x36, 0x86, 0x3b, 0x8c, 0xe4, + 0xdb, 0x85, 0x13, 0x07, 0x1e, 0x90, 0x69, 0x32, 0xdb, 0xec, 0x1b, 0x1f, 0x79, 0xe4, 0xf5, 0x38, 0xde, 0xd5, 0x52, + 0x98, 0x6f, 0x56, 0x74, 0x8d, 0x21, 0x14, 0x45, 0xd8, 0xef, 0x17, 0x15, 0x53, 0x54, 0x19, 0xb4, 0x41, 0xc3, 0xf2, + 0x46, 0xfc, 0x02, 0x67, 0x0c, 0xad, 0x17, 0xb2, 0x77, 0x74, 0xd6, 0xe1, 0xcc, 0x61, 0xc6, 0x94, 0xc0, 0xa8, 0xb4, + 0x2c, 0xe8, 0x04, 0x1c, 0x9d, 0xab, 0x0f, 0xa2, 0xe2, 0xea, 0x58, 0x01, 0x78, 0x92, 0x29, 0xfc, 0x93, 0x6f, 0x82, + 0x75, 0xbf, 0x55, 0x33, 0x4c, 0xfd, 0x45, 0x6f, 0xbb, 0x96, 0x2f, 0x43, 0x1c, 0x69, 0x63, 0x08, 0xad, 0x73, 0x7b, + 0x07, 0x28, 0xe2, 0x82, 0x5e, 0xa4, 0x1a, 0x5f, 0xab, 0xc5, 0xd0, 0xac, 0xaf, 0x71, 0x1d, 0xd3, 0x06, 0x51, 0xac, + 0xbb, 0x26, 0xbe, 0xae, 0xde, 0x1f, 0x55, 0xa9, 0x82, 0x33, 0x48, 0x20, 0xac, 0xca, 0xcb, 0x86, 0x54, 0x92, 0x4b, + 0xd3, 0xa9, 0x34, 0x9d, 0x56, 0x08, 0xe5, 0xd2, 0x93, 0xf2, 0xfe, 0x15, 0x42, 0x18, 0x98, 0x32, 0x3b, 0xb0, 0x4a, + 0x6d, 0x61, 0x15, 0xbc, 0x7a, 0xb1, 0x81, 0x55, 0x12, 0x8e, 0xe7, 0x12, 0x8d, 0x8a, 0x0a, 0x87, 0x0c, 0xe9, 0x0b, + 0xb1, 0x08, 0x12, 0x00, 0x8b, 0xde, 0x65, 0x2e, 0xef, 0x7b, 0x38, 0x14, 0xf6, 0x24, 0x93, 0x70, 0xba, 0x09, 0xcd, + 0xe1, 0x61, 0x5a, 0xd5, 0xf3, 0x08, 0x01, 0x4b, 0xcf, 0x31, 0x3c, 0x48, 0xfc, 0xfd, 0x87, 0x50, 0x9d, 0x05, 0x79, + 0xfa, 0x2f, 0x51, 0x12, 0x1a, 0xfb, 0xcf, 0xf1, 0xd0, 0x21, 0x61, 0x38, 0xf0, 0xcd, 0x11, 0x56, 0x38, 0xb8, 0x55, + 0xc4, 0x67, 0x70, 0x87, 0x8f, 0x75, 0xe8, 0x01, 0x60, 0x09, 0xc5, 0x21, 0xc8, 0x37, 0x50, 0xcc, 0xe0, 0x80, 0x26, + 0xcb, 0xf0, 0x02, 0x17, 0xac, 0x16, 0xca, 0xfb, 0xdb, 0x96, 0x97, 0xd2, 0x6a, 0x97, 0xbc, 0xc6, 0x1c, 0xa8, 0xfc, + 0x0c, 0x2f, 0x7c, 0x85, 0x79, 0x29, 0xd9, 0x7d, 0xe1, 0x6b, 0x07, 0xf4, 0x14, 0x02, 0x46, 0xba, 0xdf, 0x6b, 0xc2, + 0x3d, 0x45, 0x2f, 0x73, 0x71, 0xd8, 0x76, 0xd0, 0xbd, 0xc0, 0x5c, 0x5d, 0x55, 0x59, 0x73, 0x30, 0x85, 0x06, 0x07, + 0x55, 0x38, 0x23, 0x30, 0x57, 0x2f, 0xca, 0x82, 0x73, 0x10, 0xef, 0x7b, 0xc2, 0xe4, 0x94, 0xd1, 0x00, 0x5e, 0x64, + 0xe5, 0xa3, 0x53, 0x3d, 0x0e, 0x2e, 0xe3, 0x86, 0x4d, 0x7c, 0x21, 0x7c, 0x2a, 0xb0, 0x92, 0xd6, 0x38, 0x34, 0xa2, + 0x23, 0x3a, 0x07, 0xb3, 0x0d, 0xa0, 0xe0, 0xee, 0x7c, 0xd8, 0x58, 0xa8, 0xe0, 0x31, 0xd8, 0xda, 0xdb, 0xcd, 0x84, + 0x38, 0x93, 0xa6, 0xe0, 0x6e, 0xdb, 0x20, 0x83, 0x37, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, + 0x84, 0x27, 0x28, 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xa2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x3a, 0x6a, 0x20, + 0x2a, 0x6a, 0xa0, 0x02, 0x6a, 0x20, 0xeb, 0xdb, 0xbf, 0x80, 0x85, 0xb0, 0x11, 0xaa, 0x44, 0x10, 0x10, 0x61, 0xae, + 0x0d, 0x1f, 0x50, 0x24, 0x21, 0xe4, 0x0d, 0xa0, 0x62, 0x4a, 0x5e, 0x82, 0xd1, 0x38, 0xbc, 0xde, 0x03, 0xee, 0x97, + 0x96, 0x61, 0xf0, 0x9c, 0x82, 0xc9, 0x7f, 0xeb, 0xf3, 0xa1, 0x7a, 0xb9, 0x3a, 0x08, 0xe1, 0x17, 0x10, 0x2b, 0xc2, + 0xf1, 0x17, 0xbf, 0x00, 0xd9, 0x54, 0x58, 0x1e, 0x1c, 0x48, 0x10, 0xf8, 0x21, 0x8a, 0x70, 0xc0, 0x33, 0xbc, 0xcc, + 0x36, 0x88, 0x9e, 0x9f, 0x95, 0xaa, 0x66, 0x25, 0x83, 0x59, 0x15, 0x9e, 0xc6, 0xd1, 0x35, 0x61, 0x20, 0xb8, 0x50, + 0xbb, 0x6f, 0x10, 0x02, 0x65, 0xcb, 0x8d, 0xa1, 0x4b, 0x4f, 0xc1, 0x7c, 0x34, 0x8e, 0xde, 0x32, 0x78, 0xd2, 0xd6, + 0x98, 0xfc, 0x33, 0x6d, 0x1e, 0xb8, 0x4f, 0xf7, 0xa2, 0x46, 0xe0, 0xa4, 0x4e, 0x51, 0xf2, 0xb7, 0xe4, 0x22, 0x8e, + 0x9a, 0x97, 0x11, 0x6a, 0xc0, 0xbf, 0x0d, 0x8e, 0xba, 0x34, 0xa1, 0xa3, 0x91, 0x0f, 0x7e, 0x93, 0x11, 0xb3, 0xc9, + 0x56, 0x2b, 0x51, 0x11, 0xf4, 0xc4, 0x6e, 0x30, 0x60, 0x25, 0x5e, 0x00, 0xfb, 0x60, 0x39, 0x58, 0xf2, 0x4e, 0xc4, + 0xca, 0x9f, 0x52, 0x18, 0xac, 0x9e, 0x33, 0x84, 0x70, 0x16, 0xc4, 0x6c, 0xfc, 0xcf, 0x67, 0x1a, 0xae, 0x9f, 0x9f, + 0xaf, 0x63, 0x44, 0xa4, 0x0f, 0x22, 0x57, 0x63, 0x47, 0x44, 0x10, 0xb6, 0x4c, 0xf7, 0x5d, 0x99, 0x1f, 0xbc, 0x75, + 0xf5, 0xc0, 0x86, 0x8b, 0x03, 0x03, 0x6a, 0x14, 0x18, 0xad, 0xe0, 0x9c, 0x94, 0x03, 0x07, 0x25, 0x84, 0x66, 0x45, + 0x3c, 0x25, 0x97, 0x10, 0x09, 0x2f, 0x43, 0x5d, 0x30, 0x2c, 0x08, 0x24, 0xa8, 0x29, 0x48, 0x50, 0x99, 0xaf, 0x3d, + 0x82, 0x59, 0xe7, 0x66, 0xb6, 0x53, 0xd4, 0x75, 0x41, 0x7e, 0x7e, 0xd1, 0xf1, 0x08, 0x58, 0xda, 0x83, 0x83, 0x02, + 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, 0xc0, 0x40, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0xda, 0x78, 0x1d, 0x18, 0x5b, + 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x3d, 0x9d, 0x6e, 0x47, 0x48, 0xec, 0x7d, 0xd4, + 0x26, 0xd0, 0x98, 0x23, 0xdd, 0xd5, 0xc6, 0xfc, 0x5a, 0xd3, 0x23, 0x56, 0x93, 0x90, 0x2e, 0x48, 0x97, 0xe7, 0xd3, + 0x9e, 0xc1, 0x15, 0xab, 0x34, 0x72, 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x17, + 0x49, 0xc9, 0x86, 0x61, 0x06, 0x61, 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0xb3, 0x7f, 0x4a, 0x1f, + 0x6c, 0xba, 0xf6, 0xe6, 0x11, 0x40, 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x36, 0x2a, 0xb3, 0xb0, 0x96, 0xb1, 0x95, + 0xdb, 0xf6, 0x18, 0x7b, 0x27, 0xb6, 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x88, 0x75, 0x6d, + 0xc8, 0x46, 0x1b, 0xda, 0x37, 0x4f, 0xc2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x39, 0x2e, 0xc1, 0x21, 0xbc, 0xf0, 0x08, + 0x7f, 0x0b, 0x2c, 0x52, 0x81, 0x19, 0x96, 0xab, 0x15, 0xd4, 0xf3, 0x78, 0x9f, 0x6d, 0x06, 0x27, 0x95, 0x1b, 0x63, + 0x97, 0x76, 0xe2, 0x71, 0xd9, 0x84, 0xc4, 0x19, 0xf4, 0xeb, 0x2b, 0xa2, 0xde, 0x7e, 0x3b, 0x7d, 0xe2, 0xdf, 0x2b, + 0x73, 0x3b, 0x10, 0x1b, 0xd6, 0x1b, 0xac, 0x3e, 0x80, 0x96, 0xbf, 0xca, 0xfc, 0x43, 0x65, 0xc1, 0x4d, 0x82, 0xda, + 0x5c, 0xc4, 0x2e, 0xeb, 0x22, 0x46, 0x6a, 0x8b, 0xbb, 0x43, 0x88, 0x7f, 0xb5, 0x15, 0xc5, 0x80, 0x27, 0x15, 0xff, + 0x1c, 0xa3, 0x2e, 0x84, 0xa2, 0xb6, 0x1e, 0x36, 0x40, 0x69, 0x97, 0xeb, 0x4a, 0x8c, 0x0c, 0x09, 0xe4, 0x5b, 0x17, + 0x5e, 0xd0, 0x9c, 0x44, 0x0a, 0xe4, 0xe4, 0x20, 0x2a, 0x69, 0xb6, 0x21, 0xcc, 0x75, 0xb7, 0x70, 0xcc, 0x5c, 0x6d, + 0xd0, 0x22, 0x7e, 0x01, 0xec, 0x0c, 0x37, 0x92, 0xa5, 0x03, 0x9f, 0xaa, 0x81, 0xcf, 0xaf, 0xb9, 0xa1, 0x28, 0x0a, + 0xf5, 0xde, 0xd9, 0x47, 0xe6, 0xe0, 0x77, 0x1a, 0x88, 0x8f, 0xd4, 0xe9, 0x48, 0x36, 0x42, 0xad, 0x39, 0x3b, 0x5e, + 0xb6, 0x19, 0x61, 0x50, 0xd8, 0xe8, 0x7d, 0x15, 0xb2, 0x8a, 0x9d, 0x9d, 0x8a, 0x60, 0x4e, 0x5f, 0x54, 0xe5, 0x9c, + 0xca, 0x2d, 0xa3, 0x5a, 0x6a, 0x1a, 0x20, 0xc2, 0x95, 0x4f, 0x24, 0xef, 0x33, 0x13, 0xfe, 0xc1, 0x60, 0x5c, 0x3d, + 0x52, 0xf8, 0xfb, 0x5d, 0xb1, 0x43, 0xb6, 0xa3, 0xc3, 0x6d, 0x04, 0xcd, 0x0b, 0x15, 0x3c, 0xe0, 0xa8, 0x64, 0x09, + 0x91, 0x22, 0x97, 0xfb, 0xaa, 0x66, 0xca, 0x76, 0x1d, 0x21, 0x84, 0xb4, 0xc7, 0x59, 0x37, 0xb4, 0x7a, 0xe8, 0x91, + 0x2a, 0xca, 0xe1, 0x16, 0xcd, 0x75, 0x01, 0x2a, 0x8c, 0x40, 0xba, 0xfc, 0xcc, 0xee, 0x52, 0x09, 0xd1, 0xcb, 0xd7, + 0x2e, 0x84, 0xb1, 0xb3, 0xb2, 0xc4, 0x85, 0x19, 0xb5, 0x0d, 0xa3, 0xeb, 0x36, 0x86, 0xb3, 0x81, 0x31, 0xd3, 0xa0, + 0xa4, 0x05, 0xa1, 0xae, 0xbb, 0xf4, 0x22, 0x33, 0x81, 0x1e, 0x73, 0x42, 0x1b, 0x0c, 0x4f, 0x89, 0x06, 0xcb, 0xa6, + 0x02, 0x2c, 0xf8, 0x96, 0x45, 0x6a, 0x6d, 0x36, 0x59, 0xfc, 0x51, 0xc7, 0xe6, 0x69, 0xbf, 0xbc, 0x62, 0x9e, 0x0b, + 0x47, 0xdd, 0x9e, 0x67, 0x3e, 0x1e, 0xdd, 0xd3, 0x37, 0x57, 0x2f, 0x5e, 0xbe, 0x7e, 0xb5, 0x5a, 0xb5, 0x59, 0xb3, + 0x7d, 0x82, 0x7f, 0xd2, 0x65, 0x3c, 0xd8, 0x32, 0x0a, 0xd0, 0xc1, 0xc1, 0x3e, 0x37, 0x2e, 0x3c, 0x9f, 0xf9, 0x1c, + 0xe2, 0x06, 0xe9, 0x01, 0xce, 0x8a, 0x32, 0x26, 0xc8, 0x6d, 0xd4, 0x8b, 0xee, 0x22, 0x50, 0x42, 0x55, 0xe4, 0xef, + 0xc3, 0xe6, 0xec, 0xf7, 0x20, 0x30, 0x11, 0xd4, 0x87, 0x08, 0x20, 0x10, 0xaf, 0x14, 0x17, 0x84, 0xf9, 0x04, 0x88, + 0xe2, 0xbd, 0x00, 0xce, 0xd4, 0x44, 0xad, 0x5a, 0xa8, 0xb8, 0x00, 0x92, 0x68, 0xc3, 0x51, 0xd2, 0x23, 0x13, 0xc0, + 0x1b, 0x82, 0x52, 0xda, 0x5f, 0xdd, 0xdc, 0xb9, 0x4b, 0xe5, 0xa8, 0xd7, 0x4a, 0x73, 0x3c, 0x75, 0x9f, 0x53, 0xf8, + 0x9c, 0x76, 0xfd, 0xe9, 0x20, 0x0e, 0x73, 0xbc, 0x20, 0xe2, 0xd0, 0x3f, 0x8b, 0xb8, 0x9c, 0x17, 0xec, 0x0b, 0x97, + 0x0b, 0x95, 0x2e, 0x6f, 0x53, 0x99, 0xdc, 0x36, 0x47, 0x87, 0x71, 0x91, 0xdc, 0x36, 0x55, 0x72, 0x8b, 0xf0, 0x5d, + 0x2a, 0x93, 0x3b, 0x9b, 0x72, 0xd7, 0x54, 0x70, 0xf3, 0x85, 0x05, 0x1c, 0x8a, 0xb6, 0x68, 0x63, 0xb1, 0x59, 0xd4, + 0xa6, 0xb8, 0xa2, 0x01, 0x06, 0xff, 0xbe, 0x63, 0xe3, 0x87, 0xe1, 0x4b, 0x70, 0x69, 0xd2, 0x44, 0x7e, 0x02, 0xe9, + 0xa7, 0x55, 0x19, 0xb8, 0x4f, 0x49, 0xab, 0x3b, 0xbd, 0x10, 0xcd, 0x76, 0xb7, 0xd1, 0x98, 0xc2, 0xde, 0xcd, 0x48, + 0xee, 0x8b, 0x4d, 0x1b, 0x26, 0xbe, 0xce, 0x7e, 0xb6, 0x5a, 0xed, 0xe7, 0xc8, 0x6c, 0xb8, 0x09, 0x8b, 0x75, 0x7f, + 0x3a, 0xc0, 0x2d, 0xfc, 0x3c, 0x43, 0x68, 0xc9, 0xfa, 0xd3, 0x01, 0x61, 0xfd, 0x69, 0xa3, 0x3d, 0xb0, 0x86, 0x76, + 0x66, 0x2b, 0xae, 0x21, 0x84, 0xe6, 0x74, 0x70, 0x64, 0x4a, 0x4a, 0x97, 0x6f, 0xbf, 0x68, 0x15, 0xd0, 0x4f, 0xd5, + 0x82, 0x97, 0x49, 0xdc, 0x81, 0xbe, 0xe8, 0x85, 0x7d, 0xba, 0xb5, 0x20, 0xc7, 0x47, 0x95, 0xab, 0x3d, 0x45, 0xd8, + 0xf4, 0xa4, 0x0e, 0x8b, 0x43, 0xd3, 0x8c, 0xeb, 0x52, 0xba, 0xef, 0x50, 0x33, 0xf2, 0xd1, 0xc1, 0x02, 0x10, 0xa4, + 0x82, 0x47, 0x56, 0xb8, 0x70, 0x4a, 0x21, 0x5c, 0x1c, 0x54, 0xb6, 0x60, 0x92, 0x93, 0x56, 0x37, 0x37, 0x96, 0xfe, + 0xb9, 0x8b, 0x68, 0x4a, 0x31, 0x25, 0x99, 0x2f, 0x99, 0x1b, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x00, + 0x8f, 0x08, 0xc4, 0x43, 0xea, 0x16, 0xc6, 0xc0, 0x2b, 0x9e, 0x36, 0x8b, 0x3e, 0x1b, 0xa0, 0xa3, 0x63, 0x4c, 0xfb, + 0x7f, 0x65, 0xf3, 0x36, 0x3c, 0x16, 0xf8, 0xd7, 0x80, 0x4c, 0x9b, 0xb2, 0x4c, 0x10, 0x90, 0x30, 0x6a, 0xca, 0x43, + 0xd8, 0x4b, 0x08, 0x67, 0xb6, 0x62, 0xd6, 0x67, 0x83, 0xe6, 0xb4, 0xac, 0xd8, 0xf1, 0x15, 0x1b, 0xb2, 0x4c, 0xb0, + 0x15, 0x1b, 0xae, 0x62, 0xf8, 0x3a, 0x83, 0x01, 0x41, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x28, 0x88, 0xe6, 0x8b, 0x15, + 0xf1, 0x9b, 0xdd, 0xde, 0xe3, 0xb7, 0xc0, 0x02, 0xad, 0xb6, 0xff, 0x77, 0xa1, 0x0c, 0xd8, 0x53, 0x16, 0x26, 0x66, + 0x6e, 0x61, 0x55, 0x74, 0x00, 0x95, 0x12, 0x61, 0x0a, 0x03, 0x99, 0xfd, 0xcc, 0x40, 0x2d, 0xd0, 0x1a, 0xe4, 0x7d, + 0x3d, 0x68, 0x66, 0x70, 0xc4, 0xc0, 0x3b, 0x34, 0x64, 0x6a, 0x8c, 0x09, 0xe3, 0x1c, 0xa6, 0x98, 0x19, 0xf0, 0x4c, + 0xd3, 0xd6, 0x5a, 0x1a, 0x59, 0xae, 0x97, 0xf7, 0xfe, 0xd1, 0xb1, 0xea, 0x17, 0xcd, 0xf6, 0x00, 0xed, 0x13, 0x62, + 0x3f, 0x06, 0xb0, 0xc9, 0x5c, 0x6a, 0xc3, 0x7c, 0x1f, 0x75, 0x52, 0xfb, 0x09, 0x7f, 0x06, 0x6b, 0xb3, 0x03, 0x40, + 0x47, 0x86, 0xcd, 0xfa, 0xcb, 0x9a, 0xca, 0xeb, 0xe3, 0xce, 0x28, 0x95, 0xbb, 0xde, 0x9d, 0x0e, 0x34, 0xc5, 0xa1, + 0xb7, 0x1e, 0x2e, 0x1f, 0xea, 0x21, 0x60, 0xc6, 0x60, 0x6e, 0x99, 0xd1, 0xf7, 0x42, 0x24, 0x17, 0x44, 0x62, 0x69, + 0xb0, 0x86, 0xc1, 0xde, 0x3a, 0x38, 0x30, 0xd5, 0x58, 0x03, 0x9e, 0x27, 0x45, 0x20, 0x18, 0xf8, 0x08, 0xca, 0x80, + 0x26, 0xca, 0xdc, 0x86, 0x93, 0x8f, 0xcc, 0xfd, 0xc2, 0xe5, 0xed, 0x63, 0xe1, 0xb4, 0xad, 0xe6, 0x7a, 0xbc, 0x2c, + 0x70, 0x57, 0xde, 0x4b, 0x5a, 0x05, 0x37, 0xb2, 0x37, 0x79, 0xca, 0xdc, 0xad, 0xfb, 0x52, 0x9d, 0xdd, 0xcd, 0x74, + 0xca, 0x66, 0x3a, 0xdb, 0xcd, 0x84, 0x9a, 0x99, 0x6f, 0x59, 0x45, 0x9a, 0x93, 0x35, 0x51, 0x73, 0x2a, 0x7e, 0xa2, + 0x73, 0xd0, 0x8e, 0x72, 0x7b, 0xaf, 0x0a, 0x27, 0x57, 0x4e, 0x2e, 0xf7, 0x73, 0x43, 0x5c, 0x91, 0xb9, 0x50, 0x87, + 0x00, 0x2f, 0x2f, 0xca, 0xc7, 0x07, 0xb8, 0x14, 0xbf, 0xca, 0x91, 0x8b, 0x72, 0x2a, 0xa4, 0x96, 0x82, 0x45, 0xc8, + 0xa0, 0xaa, 0x8b, 0x81, 0xbd, 0xb4, 0x7b, 0x4f, 0xf4, 0x78, 0xbf, 0x8a, 0x98, 0x37, 0x30, 0xcf, 0x7d, 0x7c, 0x4f, + 0x53, 0xec, 0xd4, 0xc4, 0x19, 0xf9, 0x90, 0xc5, 0x39, 0xc8, 0x66, 0xfd, 0xea, 0xb5, 0xdf, 0x46, 0x1b, 0x17, 0xcd, + 0x58, 0xf4, 0xcc, 0x13, 0x27, 0x3f, 0x14, 0xc6, 0x38, 0xc0, 0x3a, 0xfa, 0x23, 0x4c, 0x2d, 0xd8, 0xb3, 0xc4, 0x53, + 0xe8, 0xe4, 0xd6, 0xa6, 0xdd, 0x85, 0x69, 0x77, 0x26, 0xad, 0x03, 0xe5, 0x80, 0x34, 0xbb, 0x32, 0x9d, 0x3b, 0xff, + 0x7d, 0x07, 0x2f, 0xdd, 0xae, 0x21, 0x12, 0xf7, 0xfc, 0x91, 0x31, 0x86, 0x78, 0x03, 0x36, 0xa2, 0xea, 0xe0, 0xe0, + 0x0f, 0xe7, 0x7d, 0x5b, 0xc9, 0x7d, 0xdf, 0x0a, 0x07, 0xb6, 0xc1, 0x54, 0xba, 0xbc, 0x91, 0xcc, 0x16, 0x60, 0xd7, + 0xb9, 0xff, 0x8d, 0x78, 0xf8, 0x22, 0x64, 0x5a, 0xac, 0xab, 0xf8, 0x2b, 0x39, 0x2a, 0x3d, 0x44, 0x35, 0x44, 0x20, + 0xad, 0xac, 0x4b, 0x43, 0xd3, 0xd1, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x81, 0x7d, 0x91, 0x5b, 0x27, + 0xf0, 0x68, 0x61, 0x8d, 0xa1, 0xb9, 0x2b, 0xbd, 0x93, 0x6c, 0x40, 0xd4, 0xfa, 0xb8, 0x43, 0x49, 0x24, 0x16, 0xd5, + 0x5d, 0x08, 0x87, 0xbb, 0x10, 0xcc, 0xcb, 0xa0, 0x6d, 0x10, 0xbb, 0xdd, 0x05, 0x6d, 0x03, 0xa7, 0x6e, 0x1b, 0xb8, + 0x3d, 0x18, 0x2c, 0xec, 0x7d, 0x78, 0x39, 0x96, 0x63, 0xe1, 0xaf, 0xc9, 0xec, 0x03, 0x40, 0xa0, 0xf6, 0x61, 0xc5, + 0x13, 0x07, 0x82, 0xc4, 0x19, 0x8e, 0xbe, 0xe7, 0xec, 0xc6, 0x5a, 0x0e, 0xcf, 0xe6, 0x0b, 0xcd, 0x46, 0xe6, 0x8e, + 0x1a, 0x54, 0x7c, 0x75, 0x3f, 0xaf, 0x9f, 0xb2, 0x9a, 0x6e, 0xfc, 0x1e, 0x84, 0x91, 0x70, 0xca, 0x0e, 0xa3, 0x90, + 0xb0, 0xc1, 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0x6d, 0xc2, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x08, 0xdb, + 0x78, 0x63, 0x41, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x45, 0xcd, 0xa8, 0xc1, 0x52, + 0x17, 0x94, 0xd9, 0x47, 0x18, 0x57, 0x17, 0x27, 0x26, 0x4e, 0x7b, 0xa9, 0x57, 0xff, 0x2d, 0x03, 0x03, 0x7c, 0x01, + 0x5e, 0x62, 0x61, 0x74, 0xd7, 0xbe, 0x6e, 0x40, 0x7d, 0xd9, 0x60, 0x03, 0xb4, 0x5a, 0xb5, 0xca, 0x67, 0xa0, 0xdc, + 0x35, 0x97, 0xb0, 0xd7, 0x5c, 0xc2, 0x5d, 0x73, 0x09, 0x7f, 0xcd, 0x25, 0xcc, 0x35, 0x97, 0xf0, 0xd7, 0x5c, 0x1e, + 0x84, 0x9f, 0x82, 0x38, 0x8e, 0x31, 0x87, 0xb8, 0x8a, 0xda, 0x46, 0xc6, 0x83, 0x0b, 0xcf, 0x7d, 0x96, 0xa8, 0x72, + 0xf9, 0xc3, 0x18, 0x72, 0x5b, 0xb6, 0x12, 0xc6, 0x6d, 0x8a, 0x29, 0x88, 0x9c, 0x7e, 0x70, 0x50, 0xba, 0x3b, 0x83, + 0x8f, 0x7a, 0xca, 0xf1, 0xd2, 0x3a, 0xd1, 0xfe, 0x01, 0x3a, 0x79, 0xf3, 0xeb, 0x63, 0x2a, 0xd7, 0x44, 0x38, 0x93, + 0xfb, 0xfd, 0xb6, 0xa7, 0x14, 0x9f, 0x32, 0x13, 0x9e, 0x9c, 0x27, 0xda, 0x88, 0x20, 0x08, 0x51, 0xa2, 0x70, 0x46, + 0xa4, 0xdd, 0xef, 0xde, 0x15, 0xde, 0xa8, 0xa2, 0xbc, 0x59, 0xc9, 0xe3, 0x1c, 0x9c, 0xd8, 0x8d, 0x15, 0x06, 0xea, + 0x82, 0x0b, 0x41, 0x66, 0x12, 0xfe, 0x68, 0xe6, 0x96, 0x9c, 0x65, 0x65, 0xd2, 0xc7, 0x66, 0x6e, 0x08, 0x58, 0x41, + 0xf6, 0x3d, 0xcc, 0x96, 0xb7, 0x29, 0xc5, 0x77, 0x69, 0x86, 0x87, 0xf2, 0x36, 0x2d, 0x42, 0x5b, 0x10, 0x7f, 0xf1, + 0x37, 0x8e, 0x23, 0x41, 0xc1, 0xdf, 0x27, 0xe2, 0x62, 0x8f, 0x6f, 0x78, 0x01, 0x2e, 0x33, 0x63, 0x51, 0x9d, 0x32, + 0xfc, 0x0d, 0x4b, 0x78, 0x08, 0x4e, 0xa6, 0xb1, 0x22, 0xf7, 0x38, 0xb0, 0x13, 0x92, 0x80, 0xc3, 0xd5, 0xed, 0x15, + 0xff, 0x0a, 0x17, 0x5f, 0xa5, 0xb3, 0x65, 0x73, 0x28, 0x6f, 0x23, 0x5c, 0x90, 0x37, 0xf0, 0xfa, 0xd6, 0xff, 0xcb, + 0xde, 0xdb, 0x36, 0xb7, 0x6d, 0x64, 0xeb, 0xa2, 0x7f, 0x45, 0x62, 0xd9, 0x0c, 0x60, 0x36, 0x29, 0xca, 0xe7, 0xcc, + 0x54, 0x5d, 0x50, 0x6d, 0x96, 0x63, 0xc7, 0x13, 0x67, 0x22, 0xdb, 0x63, 0x79, 0x32, 0xc9, 0xb0, 0x78, 0x19, 0x08, + 0x68, 0x0a, 0x70, 0x40, 0x80, 0x01, 0x40, 0x89, 0x34, 0x89, 0xff, 0x7e, 0x6a, 0xad, 0xd5, 0xaf, 0x20, 0x28, 0x7b, + 0xf6, 0x3e, 0xfb, 0xd3, 0xbd, 0x5f, 0x6c, 0xb1, 0xd1, 0x68, 0xf4, 0x7b, 0xaf, 0x5e, 0x2f, 0xcf, 0xd3, 0x93, 0xb1, + 0xba, 0x3d, 0x70, 0xd6, 0xa5, 0x14, 0x1d, 0x6f, 0x8a, 0xc3, 0xdb, 0xf3, 0xd9, 0x7e, 0x1b, 0x44, 0x6c, 0x17, 0x64, + 0x58, 0xeb, 0xa4, 0xe1, 0x3f, 0xd1, 0xd6, 0xc1, 0x62, 0x84, 0xfd, 0x5f, 0xd6, 0x03, 0x2f, 0x21, 0x35, 0x14, 0xb8, + 0x18, 0x6c, 0x38, 0x5a, 0xdb, 0x65, 0x1a, 0xb8, 0xa9, 0x41, 0xaf, 0xef, 0x29, 0x44, 0x79, 0xc9, 0x68, 0x6e, 0x04, + 0xeb, 0xc6, 0x90, 0x8b, 0xc3, 0x71, 0xb3, 0x1c, 0xf2, 0x92, 0xa6, 0xd3, 0x20, 0x94, 0xee, 0x2c, 0x6b, 0x48, 0xa2, + 0xec, 0x83, 0x50, 0xbb, 0xb6, 0xec, 0xb7, 0x81, 0xed, 0xcb, 0x1f, 0x0d, 0x63, 0xff, 0x62, 0xf9, 0x4c, 0x48, 0x17, + 0xf1, 0x1c, 0x04, 0x51, 0xfb, 0x79, 0x36, 0xdc, 0xf8, 0x17, 0xeb, 0x67, 0x42, 0xf9, 0x8d, 0xe7, 0xb6, 0x1c, 0x52, + 0x67, 0x2d, 0x7c, 0x61, 0x3c, 0x3c, 0xb8, 0x32, 0xb4, 0x1d, 0x0e, 0x42, 0xff, 0x6d, 0xd6, 0x08, 0x6e, 0x6c, 0x68, + 0x9f, 0x2f, 0x7c, 0xd8, 0xda, 0x68, 0xac, 0x29, 0xa6, 0x5b, 0xe8, 0xdf, 0x64, 0xb6, 0xb4, 0xa7, 0x51, 0xc9, 0x8b, + 0x53, 0xd3, 0x88, 0x85, 0x30, 0x60, 0xe8, 0x27, 0xf3, 0x01, 0x54, 0x73, 0xc7, 0x23, 0x90, 0xc9, 0x07, 0x7a, 0xb0, + 0x26, 0xb5, 0xea, 0xaf, 0x61, 0x26, 0xff, 0x8f, 0x54, 0x58, 0x8c, 0xee, 0xb6, 0x61, 0xa6, 0xfe, 0x88, 0xe4, 0x1f, + 0x2c, 0xe7, 0xbb, 0xd4, 0x0b, 0xb5, 0x1f, 0x0b, 0x2b, 0x30, 0x28, 0x51, 0x35, 0xa0, 0x07, 0x22, 0xa8, 0xca, 0x20, + 0xcd, 0xb0, 0x3a, 0x07, 0xfd, 0xee, 0x69, 0xd5, 0x91, 0x1c, 0xd2, 0x5a, 0x0d, 0xa9, 0x60, 0xaa, 0xd4, 0x20, 0x3f, + 0x1c, 0xee, 0x52, 0xa6, 0xcb, 0x80, 0x4b, 0xfa, 0x5d, 0xaa, 0x94, 0xc2, 0x7f, 0x22, 0x00, 0x9d, 0x83, 0x7b, 0x7c, + 0x39, 0x06, 0xd2, 0x0c, 0x0b, 0xbf, 0x35, 0x3b, 0xbe, 0x26, 0xe1, 0x36, 0x09, 0x2e, 0x06, 0x38, 0x47, 0x57, 0x61, + 0x79, 0x97, 0x42, 0x04, 0x55, 0x09, 0xf5, 0xad, 0x4c, 0x83, 0xd2, 0x56, 0x83, 0xb0, 0x26, 0xa1, 0xce, 0x24, 0x1b, + 0x95, 0xb6, 0x1b, 0x85, 0xd9, 0x22, 0xae, 0x67, 0x84, 0x35, 0x67, 0x33, 0xd5, 0xc0, 0xa4, 0xe1, 0xb8, 0x69, 0xb4, + 0x16, 0x15, 0x6a, 0x0a, 0xf3, 0x1a, 0x57, 0x95, 0xaa, 0xee, 0xe6, 0xd4, 0x52, 0x5a, 0xb6, 0x57, 0xdd, 0x24, 0x1b, + 0x72, 0x19, 0xca, 0x30, 0xd8, 0xc8, 0x11, 0x4c, 0x20, 0x49, 0xce, 0xfc, 0x8d, 0xfc, 0x43, 0x6d, 0xba, 0x16, 0x30, + 0xc7, 0x98, 0x65, 0xc3, 0x82, 0x5e, 0x81, 0x7b, 0xa0, 0x95, 0x9e, 0x4f, 0xb3, 0x8b, 0x3c, 0x48, 0x86, 0x85, 0x5e, + 0x36, 0x19, 0xff, 0x53, 0x18, 0x69, 0x32, 0x63, 0x25, 0x8b, 0x6c, 0x57, 0xa7, 0xc4, 0x79, 0x9c, 0xc0, 0xf6, 0x68, + 0x7a, 0xcb, 0xf7, 0x19, 0x44, 0x05, 0x81, 0x82, 0x19, 0xf3, 0x65, 0x17, 0xcf, 0x7d, 0x9f, 0x59, 0xa6, 0xee, 0xc3, + 0xc1, 0x98, 0xb1, 0xfd, 0x7e, 0x3f, 0xef, 0xf7, 0xd5, 0x7c, 0xeb, 0xf7, 0x93, 0x17, 0xe6, 0x6f, 0x0f, 0x18, 0x14, + 0xe4, 0x44, 0x34, 0x15, 0x22, 0xf8, 0x87, 0xe4, 0x19, 0x92, 0xd1, 0x1d, 0xf7, 0xb9, 0xe5, 0x6c, 0x59, 0x1d, 0x81, + 0x60, 0x1e, 0x0e, 0x97, 0x0a, 0xec, 0x5a, 0xa2, 0x48, 0xc8, 0xf2, 0x9f, 0x81, 0xf1, 0xcc, 0x7d, 0x80, 0x25, 0x03, + 0x10, 0xb6, 0xca, 0xd3, 0xf5, 0x9e, 0xaf, 0x82, 0x77, 0x3a, 0xde, 0x35, 0x56, 0x64, 0x20, 0x6e, 0x81, 0x8d, 0x58, + 0x6b, 0x0f, 0xc8, 0x99, 0x02, 0x1c, 0x2f, 0x0e, 0x87, 0x73, 0xf9, 0x4b, 0x37, 0x5b, 0x27, 0x50, 0x29, 0x70, 0x7b, + 0x74, 0x72, 0xf0, 0xdf, 0x81, 0x66, 0x50, 0x0e, 0xf3, 0x7a, 0xfb, 0x3b, 0x73, 0xf2, 0xd3, 0x53, 0xfc, 0x13, 0x1e, + 0xa2, 0xd3, 0x6f, 0xf7, 0xe6, 0x0f, 0x8a, 0xca, 0xc3, 0x41, 0x2d, 0xfe, 0x73, 0xce, 0x2b, 0xf8, 0x85, 0x6f, 0x02, + 0xb3, 0xc9, 0xd4, 0x3b, 0xf9, 0x26, 0xcf, 0x99, 0x7a, 0x8d, 0x57, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xed, + 0xc8, 0x89, 0x76, 0xca, 0x31, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, + 0x96, 0x78, 0x96, 0xce, 0x2f, 0x27, 0x75, 0xb9, 0xd3, 0x8a, 0xa7, 0x3d, 0xb0, 0xb8, 0xad, 0xc1, 0x0b, 0xe0, 0xde, + 0x62, 0xeb, 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, + 0x40, 0x30, 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, + 0x77, 0xf9, 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0x65, 0x6f, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, + 0x52, 0x3c, 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfc, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xbd, 0x7d, + 0x72, 0x61, 0x20, 0x81, 0xa6, 0x03, 0xf0, 0xe3, 0x55, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, + 0x05, 0xf7, 0xe9, 0x67, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa3, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x3c, + 0xfb, 0xa6, 0x02, 0x72, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, + 0x53, 0x71, 0x75, 0xa9, 0xd3, 0xc5, 0x8b, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, + 0x07, 0xf1, 0xb6, 0xb6, 0xa3, 0x3f, 0x76, 0x10, 0xe9, 0xb8, 0x27, 0x17, 0xea, 0x4b, 0x48, 0x25, 0x17, 0xea, 0x06, + 0x62, 0x17, 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0x75, 0x8d, 0x82, 0x95, 0x80, 0x33, 0xed, 0x1a, 0x0c, 0x36, 0xb0, + 0x6e, 0x59, 0x06, 0x7f, 0xc3, 0x35, 0x4d, 0xe0, 0x86, 0x45, 0xd6, 0x7b, 0x83, 0xad, 0x74, 0x0d, 0x8e, 0x96, 0x89, + 0x73, 0x29, 0xc9, 0xca, 0x16, 0x19, 0x57, 0x8f, 0x42, 0xaa, 0xa6, 0xfb, 0x5b, 0x51, 0x3f, 0x08, 0x91, 0x07, 0xab, + 0x94, 0x45, 0xc5, 0x0a, 0x64, 0xf6, 0xe0, 0x1f, 0x21, 0x23, 0x47, 0x39, 0x70, 0x14, 0xfa, 0x5b, 0x13, 0xe8, 0x3c, + 0x3f, 0x85, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, + 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, + 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, + 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, + 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, + 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, + 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, + 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, + 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, + 0x74, 0xe9, 0x7e, 0x66, 0xc7, 0x5d, 0xe8, 0x0e, 0xb0, 0xf1, 0xb6, 0x41, 0x47, 0xfe, 0xf5, 0x0e, 0x29, 0x75, 0x93, + 0x01, 0xd8, 0x8d, 0x06, 0x38, 0x64, 0xaa, 0x97, 0x22, 0xab, 0x97, 0x32, 0xd5, 0x4b, 0xb2, 0x72, 0x09, 0x16, 0x12, + 0x53, 0xe5, 0x36, 0xb2, 0x72, 0xcb, 0x86, 0xeb, 0xe1, 0x60, 0x6b, 0xc5, 0x65, 0x73, 0x07, 0xf7, 0x85, 0x15, 0x05, + 0xfe, 0xdf, 0xb2, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x35, 0x3a, 0x26, 0xc1, 0x05, 0xe2, 0x9e, 0xdd, 0x82, 0x1d, 0x16, + 0xfe, 0x82, 0xeb, 0xe4, 0x98, 0xed, 0xf0, 0x51, 0xe8, 0x15, 0xec, 0xd6, 0x27, 0xa0, 0x5d, 0xb0, 0x35, 0x40, 0x36, + 0xb6, 0xc5, 0x47, 0x77, 0x87, 0xc3, 0xb5, 0xe7, 0xb3, 0x07, 0xfc, 0x71, 0x7e, 0x77, 0x38, 0xec, 0x3c, 0xa3, 0xde, + 0xbb, 0xe1, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xcd, 0x15, 0x8f, 0x27, 0x83, 0xc1, 0x8d, 0xbf, 0xe0, 0xf5, 0xec, 0x06, + 0xb4, 0x03, 0xe7, 0x0b, 0xa9, 0x6b, 0xf6, 0x6e, 0x79, 0xe6, 0x2d, 0x70, 0x6c, 0x6e, 0xe1, 0xe8, 0xed, 0xf7, 0xbd, + 0x3b, 0x1e, 0x79, 0xb7, 0xa4, 0x62, 0x5a, 0x71, 0xc5, 0xf1, 0xb6, 0xc5, 0xfd, 0x74, 0xc5, 0x43, 0x78, 0x84, 0x55, + 0x99, 0xde, 0x04, 0xef, 0x7d, 0xb6, 0xd2, 0x2c, 0x70, 0x0f, 0x98, 0x63, 0x4d, 0x76, 0x42, 0x33, 0xf1, 0x57, 0xd8, + 0x3f, 0x37, 0xaa, 0x7f, 0x68, 0xfe, 0x97, 0xba, 0x9f, 0xc0, 0xed, 0x8b, 0x2c, 0x48, 0xec, 0x3d, 0xbf, 0x61, 0xf7, + 0xdc, 0xb0, 0xcd, 0x9e, 0x99, 0xb2, 0x4f, 0x94, 0x1a, 0x3f, 0x52, 0xea, 0xda, 0x32, 0xac, 0x64, 0xee, 0xbe, 0x8c, + 0xc0, 0xe1, 0x80, 0xfc, 0x74, 0x87, 0x38, 0x08, 0xad, 0x9b, 0xac, 0xe6, 0x8a, 0x72, 0x2e, 0xb4, 0x65, 0xe6, 0xe5, + 0xc0, 0x62, 0x96, 0x52, 0x68, 0x2c, 0x00, 0x10, 0x4c, 0x0a, 0xad, 0xbd, 0x97, 0x01, 0xe4, 0x04, 0x0d, 0x7f, 0x6c, + 0xae, 0x8a, 0xb2, 0x96, 0x2d, 0x09, 0x51, 0xb6, 0xeb, 0xe1, 0x25, 0x42, 0xa6, 0xf5, 0xfb, 0xe7, 0x44, 0xb2, 0x36, + 0xa9, 0xae, 0x6a, 0xb4, 0x04, 0x54, 0x64, 0x09, 0x98, 0xf8, 0x95, 0xe6, 0x13, 0x80, 0x27, 0x1d, 0x0f, 0xaa, 0xa7, + 0xbc, 0x66, 0x82, 0xc8, 0x36, 0x2a, 0x7f, 0x52, 0xbc, 0x40, 0x32, 0x82, 0xe2, 0x69, 0xad, 0x32, 0x16, 0x86, 0x79, + 0xa0, 0x80, 0xbc, 0x7b, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, + 0xe8, 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x39, 0x89, 0xae, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, + 0x67, 0xd1, 0xd3, 0x6a, 0x3e, 0x21, 0x25, 0xd9, 0xe1, 0x90, 0x8d, 0xaa, 0xba, 0x58, 0x4f, 0x43, 0xf9, 0xd3, 0x43, + 0xf0, 0xf5, 0x82, 0x7a, 0x4d, 0x56, 0xa9, 0x7e, 0x4a, 0x95, 0xf2, 0xa2, 0xe1, 0xa5, 0xff, 0xb4, 0x92, 0xfb, 0x1e, + 0x90, 0xd6, 0xf2, 0x92, 0xcb, 0xf7, 0x23, 0xc4, 0x18, 0xf1, 0x03, 0xaf, 0xe4, 0x11, 0x0b, 0xd5, 0x14, 0xae, 0x79, + 0x84, 0x20, 0x6f, 0x99, 0x0e, 0xfe, 0xd6, 0x13, 0xa7, 0xfb, 0x13, 0xa5, 0x5d, 0x7c, 0x61, 0x51, 0xf7, 0x64, 0x6d, + 0xdd, 0x80, 0x1c, 0x6c, 0x98, 0x2e, 0x0a, 0xb2, 0x4d, 0x69, 0x04, 0x6d, 0xb4, 0x1c, 0xd8, 0x70, 0x2a, 0xb5, 0xe1, + 0xcc, 0x35, 0x04, 0xf7, 0xf9, 0x79, 0x3a, 0x5a, 0xc0, 0x87, 0x54, 0xb7, 0x97, 0xf8, 0xf9, 0xb0, 0xe1, 0x11, 0x90, + 0xd9, 0x11, 0x9f, 0xd9, 0x44, 0xd2, 0x49, 0x9d, 0x2b, 0x60, 0xb7, 0xb3, 0x6b, 0x90, 0x23, 0x66, 0xee, 0x2b, 0x54, + 0xdf, 0xa2, 0x01, 0x57, 0xc6, 0xda, 0xd7, 0x24, 0x63, 0xe1, 0x55, 0x39, 0x0d, 0x07, 0x00, 0x43, 0x97, 0xd1, 0xd7, + 0x96, 0x9b, 0x2c, 0xfb, 0xb9, 0x80, 0x20, 0x88, 0x92, 0x78, 0x7c, 0xc0, 0xfb, 0xb2, 0x1a, 0x6a, 0x94, 0x7c, 0x2c, + 0x1b, 0xa9, 0xf4, 0x4a, 0xf4, 0x77, 0x63, 0x2e, 0x31, 0xe0, 0x75, 0xd5, 0x16, 0x14, 0xce, 0xf3, 0xc3, 0xe1, 0x3c, + 0x1f, 0x19, 0xcf, 0x32, 0x50, 0xad, 0x4c, 0xeb, 0x20, 0x36, 0xf3, 0xc5, 0xc2, 0x5f, 0xec, 0x9c, 0x44, 0x44, 0x41, + 0x60, 0x47, 0xc2, 0x83, 0x48, 0xfd, 0xaa, 0xf2, 0x74, 0xa7, 0xfa, 0x6c, 0xbf, 0xb0, 0x89, 0xf4, 0x82, 0x92, 0xc9, + 0x27, 0xc1, 0x5e, 0xf5, 0x77, 0x10, 0x36, 0x84, 0x37, 0xaf, 0x7a, 0x9d, 0x65, 0x6a, 0x56, 0x82, 0x84, 0x19, 0x73, + 0x04, 0x8f, 0xc3, 0x4e, 0x63, 0x1b, 0x1e, 0x5b, 0x70, 0x74, 0xde, 0x9a, 0xdd, 0xb1, 0x15, 0xbb, 0x55, 0x75, 0x5a, + 0xf0, 0x70, 0x3a, 0xbc, 0x0c, 0x70, 0xf5, 0xad, 0xcf, 0x39, 0xbf, 0xa3, 0x13, 0x6c, 0x3d, 0xe0, 0xd1, 0x44, 0xcc, + 0xd6, 0x4f, 0x23, 0xb5, 0x78, 0xd6, 0x43, 0xbe, 0xa0, 0xf5, 0x27, 0x66, 0x77, 0x26, 0xf9, 0x6e, 0xc0, 0x17, 0x93, + 0xf5, 0xd3, 0x08, 0x5e, 0x7d, 0x0a, 0x56, 0x8c, 0xcc, 0x99, 0x65, 0xeb, 0xa7, 0x11, 0x8e, 0xd9, 0xdd, 0xd3, 0x88, + 0x46, 0x6d, 0x25, 0xf7, 0xa5, 0xdb, 0x06, 0x84, 0x95, 0x5b, 0x16, 0xc3, 0x6b, 0x20, 0x9e, 0x69, 0x23, 0xe9, 0x5a, + 0x1a, 0x7a, 0x63, 0x1e, 0x4e, 0xe3, 0x60, 0x4d, 0xad, 0x90, 0x67, 0x86, 0x98, 0xc5, 0x4f, 0xa3, 0x39, 0x5b, 0x61, + 0x45, 0x36, 0x3c, 0x1e, 0x5c, 0x4e, 0x36, 0x57, 0x7c, 0x0d, 0xe4, 0x67, 0x93, 0x8d, 0xd9, 0xa2, 0x6e, 0xb9, 0x98, + 0x6d, 0x9e, 0x46, 0xf3, 0xc9, 0x0a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x0d, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, + 0x3d, 0xb6, 0x1e, 0x07, 0x77, 0x6c, 0x7d, 0x19, 0xdc, 0xb2, 0xf5, 0x18, 0x88, 0x38, 0xa8, 0xdf, 0xbd, 0x0d, 0x2c, + 0xbe, 0x88, 0xad, 0x2f, 0x4d, 0xda, 0xe6, 0x69, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xc9, 0xbc, 0x15, 0x83, + 0x4b, 0xc8, 0xd2, 0x8b, 0xd9, 0x66, 0x78, 0xc9, 0xd6, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0xee, 0xf8, 0x2d, 0x4b, 0xf8, + 0xaa, 0x89, 0xaf, 0x36, 0xa0, 0x11, 0x3d, 0xca, 0xa0, 0xaf, 0xa0, 0x66, 0xe6, 0xbc, 0xb2, 0x30, 0x2a, 0xf7, 0x2d, + 0x38, 0xa0, 0x20, 0x6d, 0x03, 0x04, 0x49, 0x3c, 0xbb, 0x57, 0xe1, 0xfa, 0x46, 0x0a, 0x03, 0x6e, 0x02, 0x33, 0x60, + 0x60, 0xfa, 0x19, 0xfc, 0xb0, 0xd2, 0x25, 0x42, 0x9c, 0xfd, 0x94, 0x92, 0x64, 0x9e, 0x9f, 0x8a, 0x34, 0x77, 0x0b, + 0xd7, 0x29, 0xcc, 0x8a, 0x02, 0xd5, 0x4f, 0x49, 0x69, 0x60, 0xa1, 0x12, 0x99, 0x4a, 0xc1, 0x2f, 0x9b, 0xf3, 0x28, + 0x3b, 0x46, 0xe7, 0x3a, 0xbf, 0x9c, 0x38, 0xa7, 0x93, 0xbe, 0xff, 0xc0, 0x31, 0x6c, 0x21, 0x03, 0x17, 0xfe, 0xd4, + 0x13, 0xc6, 0xa9, 0x15, 0x88, 0xa9, 0xe4, 0xd9, 0x53, 0xf8, 0x4c, 0x68, 0x75, 0x74, 0xe1, 0xfb, 0x41, 0xa1, 0x4d, + 0xd2, 0x2d, 0x48, 0x52, 0xf0, 0x14, 0x3d, 0xe7, 0xbc, 0x0d, 0x54, 0x8a, 0x11, 0x2d, 0x88, 0xb4, 0xb5, 0xcc, 0x1c, + 0xa4, 0x2d, 0xcd, 0x77, 0x4d, 0xfc, 0x1c, 0x16, 0x70, 0x11, 0x2d, 0x6c, 0x0d, 0x8f, 0xaa, 0x58, 0xb9, 0x37, 0x79, + 0x8e, 0x70, 0x46, 0x97, 0x32, 0x01, 0x70, 0xbd, 0x5f, 0x87, 0xb5, 0xc2, 0x2b, 0x6a, 0x16, 0x79, 0x51, 0xd3, 0x27, + 0x5b, 0xe0, 0x3e, 0x16, 0x25, 0x0a, 0x9c, 0xb5, 0x60, 0xc0, 0x56, 0x58, 0xb2, 0x93, 0xc2, 0xa6, 0x68, 0x09, 0xbd, + 0x3d, 0x7e, 0x3a, 0xa8, 0x99, 0x0c, 0xa0, 0x09, 0xa0, 0xf1, 0xf8, 0x17, 0x80, 0x9a, 0xde, 0xd4, 0x62, 0x5d, 0x05, + 0xa5, 0x52, 0x6e, 0xc2, 0xcf, 0xc0, 0x30, 0xc3, 0x0f, 0x85, 0xdc, 0x26, 0x4a, 0xe4, 0xfc, 0x58, 0x94, 0x62, 0x59, + 0x8a, 0x2a, 0x69, 0x37, 0x14, 0x3c, 0x22, 0xdc, 0x06, 0x8d, 0x99, 0xdb, 0x13, 0x5d, 0xb4, 0x22, 0x94, 0x63, 0xb3, + 0x8e, 0x91, 0x46, 0x99, 0x9d, 0xec, 0x3a, 0x59, 0x68, 0xbf, 0xaf, 0x72, 0xc8, 0x3a, 0x60, 0x8d, 0xe4, 0xeb, 0x35, + 0x87, 0x6e, 0x1b, 0xe5, 0xc5, 0x83, 0xe7, 0x2b, 0x38, 0xcd, 0xf1, 0xc4, 0xee, 0x7a, 0xdd, 0x29, 0x12, 0xf1, 0x0a, + 0x27, 0x55, 0x3e, 0x92, 0x85, 0xe3, 0xce, 0x9d, 0xd6, 0x62, 0x55, 0xb9, 0xac, 0xa7, 0x16, 0x47, 0x04, 0x3e, 0x95, + 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, 0x11, + 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0x8b, 0x5c, 0x0f, + 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, 0x3c, + 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, 0x5d, + 0x28, 0xe7, 0x4c, 0xc5, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, 0x8c, + 0x8e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x96, 0xab, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, 0xc6, + 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, 0x98, + 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x7b, 0x59, 0x14, 0x38, 0x80, 0xab, + 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0xf6, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, 0xcc, + 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, 0xb4, + 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x8f, 0x5f, 0xa7, + 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7e, 0x41, 0x11, 0x17, 0x35, 0xb8, 0xf2, + 0x4e, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, 0x0e, + 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x44, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xcc, 0x59, 0x35, 0x5a, 0xa8, 0xcc, 0x08, + 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xe3, 0x3d, 0xba, 0xab, 0xce, 0x32, + 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, 0x77, + 0x9d, 0xe5, 0xab, 0x9b, 0xad, 0xa1, 0xa8, 0xd4, 0x4a, 0x52, 0x1c, 0x64, 0xb8, 0x6e, 0x2b, 0x1f, 0x2e, 0x2e, 0xa0, + 0x67, 0x8c, 0x44, 0xe6, 0xf9, 0x13, 0xf9, 0x12, 0x9c, 0x33, 0xce, 0x0a, 0x81, 0x09, 0x63, 0xf5, 0xae, 0xb5, 0x54, + 0x1a, 0x52, 0x8c, 0x1d, 0x8d, 0xb2, 0xac, 0xb2, 0x74, 0x99, 0xad, 0x25, 0x6c, 0x59, 0x4e, 0x6e, 0x61, 0xcb, 0x4c, + 0x56, 0xf3, 0x7d, 0xc5, 0x1d, 0x94, 0x6f, 0xb6, 0xce, 0xf8, 0x5e, 0x22, 0x7b, 0xb7, 0x81, 0x12, 0x5e, 0x8c, 0xfe, + 0x82, 0xf4, 0xdb, 0x0c, 0xe3, 0x94, 0xdb, 0x4a, 0x5a, 0x80, 0xd3, 0x3f, 0x1c, 0xde, 0x57, 0x18, 0x34, 0x38, 0xc2, + 0x38, 0xb2, 0x7e, 0xff, 0xb6, 0xf2, 0x6a, 0x4c, 0xd4, 0xf1, 0x59, 0xfd, 0x7e, 0x45, 0x0f, 0xa7, 0xd5, 0x68, 0x95, + 0x6e, 0x91, 0x9d, 0xd0, 0xc6, 0xca, 0x0f, 0x6a, 0x05, 0xcc, 0xde, 0xfa, 0x7c, 0x3a, 0x00, 0x1d, 0x0b, 0x90, 0x68, + 0x36, 0x13, 0x89, 0x39, 0xe9, 0x9e, 0x84, 0xc7, 0x07, 0x16, 0x38, 0xc0, 0x54, 0xfc, 0x9f, 0xc2, 0x9b, 0x81, 0x0d, + 0x1a, 0x25, 0xfa, 0x1a, 0x5d, 0xd5, 0xe6, 0x46, 0xc7, 0x4b, 0x4f, 0x21, 0x91, 0x15, 0xac, 0x9a, 0xfb, 0x72, 0x03, + 0xa7, 0x3d, 0xd4, 0x1c, 0x2a, 0x4b, 0xf0, 0xb7, 0x5f, 0xe6, 0x87, 0xc3, 0x3a, 0x83, 0xc2, 0x76, 0x6b, 0xa1, 0xbd, + 0x31, 0x4b, 0x35, 0x54, 0x84, 0x83, 0xce, 0x57, 0x62, 0x56, 0x8f, 0xe8, 0xef, 0xf9, 0xe1, 0xb0, 0x22, 0x30, 0xe0, + 0xb0, 0x94, 0x99, 0x68, 0xa1, 0x58, 0x5a, 0x67, 0x33, 0xaa, 0x03, 0x0f, 0x4c, 0xcc, 0x59, 0xb8, 0x03, 0xd0, 0x26, + 0xb5, 0x0a, 0xf4, 0x2a, 0xa2, 0x9f, 0xb8, 0x5f, 0xdb, 0xaf, 0xd7, 0x23, 0xb3, 0x74, 0xe4, 0xc6, 0x58, 0x00, 0x70, + 0xe0, 0x79, 0x4d, 0xf2, 0x9c, 0x7c, 0x0d, 0xed, 0x9e, 0x5c, 0xc8, 0x9f, 0xa0, 0x6c, 0xe1, 0xb9, 0x6a, 0x5a, 0x59, + 0xac, 0xb8, 0xaa, 0x5e, 0x5d, 0xf0, 0xca, 0x64, 0x5a, 0xa5, 0x95, 0xa8, 0x94, 0x60, 0x40, 0x5d, 0xe2, 0xb5, 0xa6, + 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x7e, 0x69, 0x1c, 0x3e, + 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0x2b, 0x1f, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, 0xc5, 0xc4, + 0xee, 0xd0, 0xbc, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, 0x01, 0x2f, + 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x2a, 0x26, 0xc0, 0x0f, + 0x4a, 0xad, 0xe9, 0xbd, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, 0xe7, 0xe3, + 0xf9, 0xa5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x79, 0xab, 0x7f, 0x98, 0xea, 0x5b, 0xe8, 0x4e, + 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, 0x1c, 0xec, + 0x0d, 0x70, 0xe2, 0x97, 0x87, 0x83, 0xb8, 0xca, 0x7d, 0x76, 0xde, 0x35, 0xb2, 0x72, 0x00, 0x2b, 0x88, 0x82, 0x71, + 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xd5, 0xf8, 0xf8, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0xe4, 0x4f, 0x9f, + 0x03, 0x69, 0x59, 0xbf, 0x1f, 0xbd, 0xb8, 0x9c, 0x3e, 0x1f, 0x46, 0x01, 0x38, 0x76, 0xd9, 0xcb, 0xcb, 0x98, 0xaf, + 0x2e, 0x99, 0x65, 0x0a, 0x8b, 0x7c, 0x33, 0xa0, 0xba, 0x64, 0xb5, 0x74, 0xbd, 0x02, 0x2c, 0x5d, 0x7e, 0xf3, 0x10, + 0xa6, 0x06, 0x34, 0xb2, 0xe6, 0xee, 0x34, 0xd7, 0x02, 0xa5, 0x9e, 0xf7, 0x33, 0x43, 0xbe, 0x2e, 0x83, 0xae, 0x20, + 0xdd, 0xf3, 0x88, 0xf4, 0x72, 0x2f, 0x9d, 0xee, 0xf7, 0xa5, 0x00, 0x4b, 0x7d, 0x29, 0x3e, 0x83, 0xc2, 0xa2, 0xf1, + 0x8d, 0x00, 0x6d, 0x0d, 0xd5, 0xb4, 0x57, 0x8a, 0xaa, 0x17, 0xf4, 0x4a, 0xf1, 0xb9, 0xa7, 0x87, 0xca, 0x7c, 0x59, + 0x3a, 0xfa, 0x9f, 0x50, 0x73, 0xc1, 0x09, 0x31, 0x13, 0x73, 0x00, 0x95, 0xa0, 0x8d, 0x6f, 0x75, 0xb4, 0xf1, 0xa9, + 0x5e, 0xc5, 0x4d, 0x9f, 0xd7, 0xd6, 0x32, 0x27, 0x84, 0x4d, 0xf7, 0x12, 0xa0, 0x22, 0xaf, 0x84, 0x47, 0xb0, 0xfc, + 0xf2, 0x87, 0x3c, 0x5d, 0x21, 0x5a, 0xc7, 0x3d, 0xcb, 0x5c, 0x1a, 0xfb, 0x37, 0x06, 0xd3, 0xd7, 0xb7, 0xdb, 0x22, + 0x3f, 0x35, 0x31, 0x61, 0x3d, 0x56, 0xf4, 0xcd, 0xbb, 0x70, 0x25, 0x50, 0xe0, 0x50, 0x22, 0xb1, 0x4d, 0x15, 0x8a, + 0x78, 0x90, 0xf4, 0xe9, 0xa2, 0xf5, 0x69, 0x80, 0xa9, 0xb5, 0x1c, 0x98, 0x43, 0xb8, 0x8a, 0x0b, 0x1f, 0x3d, 0x7d, + 0x8b, 0x59, 0x38, 0x9f, 0x78, 0x1f, 0xbd, 0x62, 0x64, 0x3e, 0xee, 0xa3, 0x52, 0x49, 0xff, 0x3c, 0x1c, 0x66, 0xd5, + 0xdc, 0x77, 0xe8, 0x23, 0x3d, 0x54, 0xb9, 0xa0, 0xec, 0x8d, 0x31, 0x89, 0x40, 0x69, 0x8c, 0xf7, 0x71, 0x70, 0x9c, + 0xf7, 0x69, 0x00, 0xa9, 0x7d, 0xe2, 0x3d, 0x29, 0x39, 0x3c, 0xe7, 0x98, 0x13, 0x4a, 0x2b, 0xc2, 0x2a, 0xbe, 0xc8, + 0x50, 0xae, 0x3b, 0xa5, 0x60, 0x92, 0x43, 0x82, 0xe1, 0xaf, 0x9a, 0x37, 0xb1, 0x02, 0x61, 0xd7, 0xcc, 0xab, 0xd1, + 0x93, 0x2a, 0x09, 0x4b, 0x01, 0x47, 0x65, 0xe6, 0x19, 0xf6, 0x86, 0x27, 0x86, 0x91, 0x83, 0xe5, 0xfe, 0xa8, 0x4e, + 0x44, 0xee, 0xd1, 0x05, 0x46, 0x65, 0xe1, 0x79, 0x43, 0x57, 0x1a, 0x54, 0x92, 0x1d, 0x7f, 0xc5, 0x35, 0xa0, 0xb6, + 0xc6, 0x88, 0xa1, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, 0x95, 0xdc, 0xf5, + 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, 0x2c, 0x85, 0x23, + 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, 0x42, 0x9a, 0x6c, + 0x5f, 0xcf, 0xdf, 0x1b, 0x41, 0x56, 0x6e, 0x39, 0xc7, 0xc3, 0xe2, 0x1b, 0x67, 0x5f, 0xe5, 0xe4, 0x29, 0x66, 0x19, + 0xe9, 0x9d, 0x62, 0x5e, 0xc0, 0x9f, 0xca, 0x52, 0x9f, 0xa3, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, 0x97, 0xde, 0xa6, + 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0xf7, 0xf1, 0x48, 0x9e, 0x61, 0x1b, 0x96, 0xb0, 0xd0, 0x2a, 0x18, 0x03, 0x48, + 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x0e, 0x87, 0xf3, 0x8d, 0x39, 0x4b, 0xf6, 0xe0, 0xfa, 0xca, 0x13, 0xf3, 0x0e, + 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x1b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, 0x62, 0xad, 0x63, + 0xa9, 0xac, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0xbf, 0x77, 0x83, 0xab, 0x6b, 0x63, 0x50, + 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0xb3, 0x9c, 0x7c, 0xf9, 0xad, 0x9d, 0x03, 0x82, + 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, 0x33, 0xd8, 0xc4, + 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, 0xab, 0x85, 0x48, + 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, 0x5e, 0x27, 0x68, + 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, 0x7b, 0x99, 0x13, + 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, 0x74, 0x28, 0x59, + 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, 0x0a, 0x5c, 0x08, + 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xf9, 0xb4, 0x90, 0xa6, 0x81, 0x7c, 0x5a, 0x39, 0xe6, + 0x81, 0x9d, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0xe5, 0x1c, 0xab, 0x88, 0xde, 0xe7, 0x1f, 0x2a, 0x7b, + 0xfa, 0x20, 0xc2, 0x46, 0x05, 0x1a, 0x4b, 0x89, 0xb1, 0x91, 0xe3, 0xdf, 0x12, 0x65, 0x43, 0x86, 0x80, 0x10, 0xd2, + 0x46, 0x4e, 0x3f, 0xac, 0x2f, 0x6f, 0x33, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, 0xa9, 0x47, 0x3c, + 0x5e, 0x6b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, 0x28, 0x17, 0x3c, + 0xe7, 0x15, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xc8, 0xe9, 0xf3, 0x15, 0xf0, 0x4c, 0x40, 0xa0, 0x63, + 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0x37, 0x48, 0x94, 0xfa, 0x9a, + 0x94, 0xa4, 0xd7, 0xa2, 0xc6, 0x2b, 0xb1, 0x8a, 0x48, 0x20, 0x43, 0x0d, 0x11, 0xab, 0xea, 0xa9, 0x7b, 0x55, 0x4c, + 0x06, 0x83, 0xca, 0x97, 0xd3, 0x13, 0x6f, 0x68, 0xa8, 0xbc, 0xeb, 0x8a, 0x76, 0x7a, 0xa2, 0x95, 0xf2, 0x16, 0xd2, + 0x12, 0x34, 0x0d, 0x23, 0xcd, 0xa1, 0xd4, 0x95, 0x74, 0x37, 0x06, 0xf1, 0x25, 0x13, 0x3d, 0xdb, 0xa9, 0x1d, 0xa5, + 0x2d, 0x69, 0x0f, 0x21, 0x3d, 0x77, 0xc9, 0xc7, 0x2c, 0xe4, 0xea, 0x4e, 0x39, 0x29, 0xaf, 0x42, 0x74, 0x72, 0xdf, + 0x63, 0x48, 0x04, 0xfa, 0x9c, 0x63, 0x58, 0x17, 0x0d, 0x75, 0x0e, 0x2b, 0xc4, 0x6c, 0xa1, 0x84, 0xf9, 0x92, 0xf1, + 0x54, 0x32, 0x68, 0x00, 0x64, 0xc0, 0x67, 0x2f, 0x03, 0xcb, 0x5f, 0x41, 0xfc, 0x68, 0xe3, 0xc3, 0xe1, 0xcf, 0x9a, + 0x42, 0x6c, 0xff, 0x84, 0xcd, 0x10, 0x1e, 0xd5, 0x03, 0x9e, 0xf9, 0x26, 0x4e, 0xd0, 0x0a, 0x48, 0xca, 0xec, 0x68, + 0x22, 0x7b, 0xd5, 0x43, 0x38, 0x95, 0x15, 0xa8, 0xa3, 0xac, 0xb3, 0x12, 0x7e, 0x84, 0xa9, 0x6e, 0x25, 0xd6, 0x02, + 0x6d, 0xae, 0x56, 0xac, 0x05, 0x70, 0xe0, 0xe7, 0x10, 0x3c, 0x91, 0xcf, 0xc1, 0xc5, 0xa0, 0x00, 0x9f, 0x03, 0xe0, + 0x45, 0xee, 0xc2, 0x83, 0x79, 0x64, 0x59, 0x8d, 0x30, 0x1c, 0x55, 0xc4, 0xfa, 0x35, 0xdb, 0x91, 0x0f, 0xdc, 0x8e, + 0xf1, 0xb9, 0xf6, 0x58, 0xb2, 0x1c, 0x8c, 0x32, 0xf7, 0x6a, 0x89, 0x9e, 0x37, 0x69, 0xdc, 0x8c, 0x9e, 0xec, 0x6b, + 0xf9, 0xbf, 0xa0, 0x97, 0x41, 0x7f, 0x0b, 0xb7, 0xbc, 0xe6, 0x77, 0x0b, 0x22, 0xcd, 0xf4, 0x0a, 0x22, 0x65, 0xd4, + 0x88, 0x8c, 0x21, 0x6c, 0x52, 0xdd, 0xdc, 0x26, 0xd5, 0x85, 0x80, 0xa7, 0x23, 0x52, 0x5d, 0x0b, 0x69, 0x23, 0x9f, + 0xd6, 0x81, 0x8c, 0x45, 0x7a, 0xf7, 0xc3, 0xdf, 0x5e, 0x7e, 0x7a, 0xfb, 0xcb, 0x0f, 0x8b, 0xb7, 0xef, 0xde, 0xbc, + 0x7d, 0xf7, 0xf6, 0xd3, 0x6f, 0x04, 0xe1, 0x31, 0x15, 0x2a, 0xc3, 0x87, 0xf7, 0x37, 0x6f, 0x9d, 0x0c, 0xb6, 0x37, + 0x43, 0xd6, 0xbe, 0x91, 0x83, 0x21, 0x10, 0xd9, 0x20, 0x64, 0x90, 0x9d, 0xda, 0xf6, 0x67, 0x62, 0x8e, 0xb1, 0x77, + 0x02, 0x93, 0x2d, 0xe0, 0x1c, 0xcb, 0xbc, 0x64, 0x44, 0xae, 0x0a, 0xad, 0x1f, 0xd0, 0x82, 0x6b, 0x70, 0x91, 0x49, + 0xf3, 0xbb, 0x5f, 0x08, 0x62, 0x9f, 0x56, 0x52, 0xee, 0xab, 0x6d, 0xcd, 0xf3, 0xed, 0xfd, 0x5e, 0xc2, 0xf9, 0xcf, + 0xa5, 0x11, 0xb5, 0x00, 0x07, 0xe0, 0x73, 0xf8, 0xe3, 0x4a, 0x5b, 0xd2, 0x64, 0x16, 0xed, 0x67, 0x0c, 0x41, 0x97, + 0x06, 0x1f, 0xc4, 0x1e, 0x79, 0xa9, 0x4f, 0x16, 0x12, 0xb8, 0x23, 0x86, 0x4f, 0x2b, 0x82, 0x5e, 0x31, 0xa2, 0xb8, + 0xe4, 0x0a, 0x95, 0x52, 0xf2, 0x6f, 0x94, 0x5d, 0x54, 0xc8, 0x59, 0xc1, 0xee, 0x15, 0x39, 0x32, 0x7e, 0x10, 0x4c, + 0x7c, 0x39, 0xb8, 0xff, 0x12, 0xef, 0x70, 0xa6, 0x38, 0x92, 0x13, 0xfe, 0x90, 0x61, 0x60, 0x7f, 0x0e, 0x3e, 0xaf, + 0x0e, 0xf3, 0xf2, 0x46, 0x9f, 0x72, 0x4b, 0x3e, 0x9e, 0x2c, 0xaf, 0xc0, 0x60, 0xbf, 0x54, 0xcd, 0x5d, 0xf3, 0x7a, + 0xb6, 0x9c, 0xb3, 0xfd, 0x2c, 0x9a, 0x07, 0x77, 0x6c, 0x96, 0xcd, 0x83, 0x55, 0xc3, 0xd7, 0xec, 0x96, 0xaf, 0xad, + 0xaa, 0xad, 0xed, 0xaa, 0x4d, 0x36, 0xfc, 0x16, 0x24, 0x84, 0x9b, 0xcc, 0x03, 0xde, 0xe3, 0x3b, 0x9f, 0x6d, 0x40, + 0xa2, 0x5d, 0xb1, 0x0d, 0x5c, 0xc4, 0xd6, 0xfc, 0x87, 0xca, 0xdb, 0xb0, 0x92, 0x9d, 0x8f, 0x59, 0x8e, 0xf3, 0xcf, + 0x87, 0x07, 0xb4, 0x17, 0xea, 0x67, 0x97, 0xea, 0xd9, 0x44, 0xd9, 0xcd, 0x36, 0xa3, 0xc5, 0x7d, 0x5a, 0x6d, 0xc2, + 0x0c, 0x3d, 0xcb, 0xe1, 0xa3, 0xad, 0x14, 0xfc, 0xf4, 0x02, 0xbf, 0x64, 0x47, 0x6d, 0xa5, 0x6d, 0xbb, 0x2a, 0xb1, + 0x15, 0xb4, 0x28, 0xb2, 0x5a, 0xe1, 0x81, 0x39, 0x7f, 0x01, 0x0b, 0x18, 0x7b, 0x8e, 0x73, 0x5e, 0xfb, 0x23, 0x64, + 0xbc, 0x77, 0x00, 0xd0, 0x32, 0xc7, 0x01, 0x1e, 0xb1, 0x62, 0x14, 0x0d, 0xde, 0xf9, 0xa5, 0xb2, 0x5a, 0x69, 0x4e, + 0x42, 0xdb, 0x88, 0x55, 0xcb, 0x91, 0xaa, 0x19, 0x91, 0x3e, 0x48, 0xcf, 0xfb, 0x1e, 0x51, 0x0d, 0xf6, 0x64, 0x5e, + 0x07, 0xf6, 0xe9, 0x55, 0x6b, 0x55, 0x77, 0x7e, 0x4f, 0x95, 0x2e, 0x39, 0xb2, 0xe5, 0xa7, 0xcb, 0xf0, 0x41, 0xfd, + 0x29, 0xb9, 0x3e, 0x14, 0x38, 0xc2, 0x63, 0x15, 0x70, 0xbe, 0x5e, 0x89, 0x76, 0x27, 0xc2, 0xae, 0x5c, 0x02, 0x42, + 0x7c, 0x49, 0xd3, 0x1c, 0x8f, 0x23, 0x9a, 0x88, 0xb0, 0x89, 0xd1, 0x5f, 0xd8, 0x7d, 0x28, 0xb1, 0x9c, 0xe7, 0x1a, + 0x94, 0x5c, 0x32, 0x78, 0x4f, 0xda, 0x6b, 0xd0, 0x2c, 0xaf, 0x4a, 0x4d, 0x26, 0x72, 0x50, 0x3e, 0x1c, 0x0a, 0xd8, + 0x4b, 0x8d, 0x9f, 0x26, 0xfc, 0x84, 0xe5, 0xad, 0xbd, 0x35, 0xa5, 0xa8, 0xa4, 0x01, 0x2a, 0xf0, 0x31, 0x83, 0xff, + 0xdd, 0x19, 0x62, 0xc1, 0x14, 0x1d, 0x3f, 0x9c, 0x89, 0xb9, 0xf5, 0xdc, 0x2a, 0xeb, 0x28, 0x5b, 0xa3, 0x9c, 0x80, + 0x7f, 0x4b, 0x75, 0x9c, 0x24, 0xc2, 0xa9, 0xf7, 0x88, 0x8b, 0xba, 0x97, 0x43, 0xd4, 0x0d, 0x7b, 0x5b, 0xe9, 0x60, + 0xcb, 0x69, 0x1a, 0x1c, 0x89, 0x5f, 0xa9, 0xcf, 0xde, 0x67, 0x16, 0x8f, 0x3a, 0xb2, 0x11, 0x25, 0x69, 0x1c, 0x8b, + 0x1c, 0xb6, 0xf7, 0x85, 0xdc, 0xff, 0xfb, 0x7d, 0x08, 0x27, 0xad, 0x82, 0xa4, 0xf4, 0x04, 0x22, 0xc2, 0xd1, 0xe1, + 0x47, 0x84, 0x27, 0x52, 0x55, 0xf8, 0xa4, 0x3e, 0x71, 0x63, 0x76, 0x2f, 0xcc, 0x51, 0xbd, 0x05, 0x18, 0xc6, 0x7a, + 0x6b, 0x11, 0x92, 0x68, 0xa5, 0x19, 0x6d, 0x3d, 0x20, 0x46, 0xbc, 0x5f, 0x5b, 0x64, 0x30, 0xd6, 0x96, 0x44, 0x02, + 0xf8, 0x1d, 0x09, 0x19, 0xda, 0x36, 0x02, 0x33, 0x86, 0xb7, 0xb3, 0xe2, 0xd2, 0x75, 0xd8, 0xe6, 0x1c, 0xbe, 0x90, + 0x85, 0x66, 0x1d, 0x51, 0x9a, 0x20, 0xe4, 0x1f, 0x70, 0xb2, 0x50, 0x18, 0xcd, 0xeb, 0xa3, 0x74, 0x92, 0x58, 0xdf, + 0x77, 0x95, 0x0a, 0x36, 0x9b, 0x1b, 0xd4, 0x97, 0x1d, 0x25, 0xbf, 0x02, 0x27, 0x1d, 0x27, 0x59, 0xe4, 0x20, 0x6a, + 0x51, 0x39, 0x37, 0x49, 0x58, 0xda, 0xd5, 0xa9, 0x36, 0xeb, 0x75, 0x51, 0xd6, 0xd5, 0x6b, 0x11, 0x29, 0x7a, 0x1f, + 0xf5, 0xe8, 0x89, 0x84, 0x54, 0x68, 0x55, 0x6a, 0x97, 0x47, 0xe0, 0xb6, 0xa9, 0x15, 0xdb, 0x72, 0x09, 0x4b, 0xd4, + 0xf8, 0x4f, 0xd0, 0x47, 0xb9, 0x78, 0x90, 0x01, 0x1a, 0x1d, 0x4f, 0xcd, 0x5b, 0x8f, 0xbc, 0x72, 0x94, 0x5f, 0x5a, + 0x6d, 0xd2, 0x2f, 0x80, 0xcc, 0x68, 0xff, 0x68, 0x29, 0x81, 0xcc, 0xc0, 0x4c, 0x5a, 0x1a, 0x12, 0x39, 0x8a, 0x59, + 0x9a, 0xff, 0x81, 0x2b, 0xb6, 0x42, 0xa4, 0x61, 0x35, 0xf7, 0xf8, 0xcb, 0xca, 0xab, 0xe5, 0x5a, 0x66, 0x9a, 0x9b, + 0x25, 0x8e, 0x15, 0x8b, 0x8b, 0x7a, 0x5d, 0x89, 0x2c, 0x10, 0xe2, 0x08, 0xd3, 0x58, 0x4f, 0xbd, 0x51, 0x5a, 0x7d, + 0x40, 0x42, 0x99, 0x1f, 0xb0, 0xb7, 0x63, 0xaf, 0x07, 0x59, 0x88, 0x63, 0xcb, 0xc1, 0x66, 0xeb, 0x7d, 0x2a, 0x53, + 0x11, 0x9f, 0xd5, 0xc5, 0xd9, 0xa6, 0x12, 0x67, 0x75, 0x22, 0xce, 0xbe, 0x83, 0x9c, 0xdf, 0x9d, 0x51, 0xd1, 0x67, + 0x0f, 0x69, 0x9d, 0x14, 0x9b, 0x9a, 0x9e, 0xbc, 0xc1, 0x32, 0xbe, 0x3b, 0x23, 0xae, 0x9a, 0x33, 0x1a, 0xc9, 0x78, + 0x74, 0xf6, 0x21, 0x03, 0x92, 0xd7, 0xb3, 0x74, 0x05, 0x83, 0x77, 0x16, 0xe6, 0xf1, 0x59, 0x29, 0xee, 0xc0, 0xe2, + 0x54, 0x76, 0xbe, 0x07, 0x19, 0x56, 0xe1, 0x1f, 0xe2, 0x0c, 0xa0, 0x5d, 0xcf, 0xd2, 0xfa, 0x2c, 0xad, 0xce, 0xf2, + 0xa2, 0x3e, 0x53, 0x52, 0x38, 0x84, 0xf1, 0xc3, 0x7b, 0xfa, 0xca, 0x2e, 0x6f, 0xb3, 0xb8, 0xcb, 0x22, 0x7f, 0x8a, + 0x5e, 0x45, 0xc4, 0xa4, 0x51, 0x09, 0xaf, 0xdd, 0xdf, 0x36, 0xf7, 0x0f, 0xaf, 0x1b, 0xbb, 0x9f, 0xdd, 0x31, 0xa2, + 0x0b, 0xea, 0xf1, 0x4a, 0x52, 0x2a, 0x28, 0x20, 0x70, 0xa2, 0x59, 0xe3, 0xc1, 0x1d, 0x07, 0xbc, 0x1a, 0xd8, 0x92, + 0xad, 0x7d, 0xfe, 0x22, 0x96, 0x61, 0xda, 0x9b, 0x00, 0xff, 0x2a, 0x7b, 0xd3, 0x75, 0xb0, 0xc4, 0xfb, 0x16, 0xb2, + 0x0d, 0xbd, 0x7d, 0xcd, 0x5f, 0x7a, 0xb9, 0xfa, 0x9b, 0xfd, 0x13, 0x80, 0x30, 0x20, 0x66, 0xd5, 0x47, 0x13, 0xf7, + 0xce, 0xca, 0xb2, 0x73, 0xb2, 0xec, 0x7a, 0xe8, 0xd7, 0x24, 0x46, 0xa5, 0x95, 0xa5, 0x74, 0xb2, 0x94, 0x90, 0x05, + 0x7c, 0x62, 0x34, 0xb5, 0x11, 0x40, 0xd8, 0x8e, 0x52, 0xf9, 0x42, 0xe5, 0x45, 0x14, 0xce, 0x09, 0x9e, 0x27, 0x62, + 0x74, 0x6f, 0x25, 0x03, 0x86, 0x43, 0x08, 0xe6, 0xa0, 0x2d, 0xf6, 0x86, 0x6e, 0x22, 0xfe, 0x7a, 0x53, 0x94, 0x6f, + 0x63, 0xf2, 0x29, 0xd8, 0x9d, 0x7c, 0x5c, 0xc2, 0xe3, 0xf2, 0xe4, 0xe3, 0x10, 0x3d, 0x12, 0x4e, 0x3e, 0x06, 0xdf, + 0x23, 0x39, 0xaf, 0xbb, 0x1e, 0x27, 0xc8, 0x2d, 0xa4, 0xfb, 0xdb, 0x31, 0x09, 0xd0, 0xbc, 0x86, 0xe5, 0xa8, 0xa9, + 0xb8, 0x66, 0x66, 0x8c, 0xe7, 0x8d, 0xde, 0x1f, 0x3b, 0xde, 0x32, 0x85, 0x62, 0x16, 0xf3, 0x1a, 0x7e, 0xcf, 0xaa, + 0x40, 0xdd, 0xf5, 0x36, 0xc9, 0x2d, 0xb3, 0x7a, 0x8e, 0x76, 0xdf, 0xf7, 0x75, 0x22, 0xa8, 0xfd, 0x1d, 0xf6, 0x3c, + 0xb3, 0xde, 0x55, 0x31, 0x70, 0xa9, 0x92, 0x1d, 0x32, 0x55, 0x4d, 0x0f, 0x54, 0x4a, 0x83, 0xa7, 0x97, 0xd6, 0xe5, + 0x4b, 0xa5, 0x8d, 0x3c, 0xd3, 0xfc, 0x06, 0xf0, 0x62, 0xea, 0xb2, 0xd8, 0x7d, 0x75, 0x5f, 0xc1, 0x6d, 0xbc, 0xdf, + 0x5f, 0x56, 0x9e, 0xf9, 0x89, 0x0b, 0xc0, 0xde, 0x54, 0x68, 0x9d, 0x40, 0xa9, 0x61, 0x1d, 0xbe, 0x4a, 0x44, 0xf4, + 0x47, 0xbb, 0x5c, 0x67, 0xae, 0x03, 0x46, 0x14, 0xf1, 0xdb, 0x78, 0xf4, 0x07, 0x28, 0xae, 0x8d, 0x3d, 0x20, 0xac, + 0x43, 0x42, 0x9f, 0x11, 0x80, 0xd4, 0x63, 0x8e, 0x12, 0xd0, 0xac, 0x68, 0xee, 0x98, 0xfc, 0x5c, 0x5f, 0x29, 0xfd, + 0xfd, 0xb2, 0xf2, 0xc8, 0x9c, 0xd2, 0x36, 0xd3, 0x58, 0xad, 0xa9, 0x04, 0xc2, 0x2b, 0x2a, 0x59, 0x85, 0xcf, 0xe6, + 0x8d, 0xe8, 0xf7, 0xe5, 0x11, 0x9e, 0x56, 0x3f, 0x6c, 0x31, 0xbe, 0x15, 0x10, 0x8d, 0x04, 0x40, 0x3f, 0x01, 0xcc, + 0x8b, 0x6c, 0x66, 0xf7, 0x71, 0x40, 0x95, 0x12, 0x4d, 0xe3, 0x6c, 0x9e, 0xdf, 0xd2, 0x9b, 0xb2, 0x83, 0x4e, 0x9d, + 0x2a, 0x70, 0xc1, 0x55, 0xc9, 0x78, 0x65, 0x3d, 0x91, 0xcf, 0x6f, 0x6e, 0x37, 0x69, 0x16, 0xbf, 0x2f, 0xff, 0x89, + 0x63, 0xab, 0xeb, 0xf0, 0xc8, 0xd4, 0xe9, 0xda, 0x79, 0xa4, 0xb5, 0x17, 0x02, 0x22, 0xda, 0x35, 0xd4, 0x7a, 0x61, + 0xa1, 0x47, 0x7a, 0x22, 0x9c, 0x93, 0x44, 0x4d, 0x3b, 0xd0, 0xd2, 0x08, 0x7d, 0x7d, 0xcd, 0xe9, 0x2f, 0x0c, 0xd6, + 0x3e, 0x1f, 0x33, 0x20, 0x2b, 0xd1, 0x8f, 0xd5, 0x43, 0x63, 0x33, 0x87, 0x9e, 0xb5, 0x2a, 0xcf, 0xbc, 0xea, 0x70, + 0x40, 0x7c, 0x18, 0xfd, 0x25, 0xbf, 0xdf, 0x7f, 0x4d, 0xf3, 0x8f, 0x09, 0x35, 0x7e, 0xb6, 0x19, 0xa0, 0x6b, 0xdf, + 0x95, 0x07, 0xa2, 0x9e, 0x6b, 0x95, 0x20, 0xc4, 0x1b, 0xc4, 0x44, 0x33, 0x62, 0x0e, 0x4e, 0x3b, 0xd4, 0xfc, 0x93, + 0xd4, 0x80, 0x10, 0x25, 0x5e, 0xc7, 0x94, 0x05, 0x39, 0x6d, 0xe2, 0x48, 0x3f, 0x0a, 0x27, 0xf2, 0xa3, 0xa8, 0x8a, + 0xec, 0x1e, 0x2e, 0x18, 0x4c, 0xbd, 0xa7, 0xfd, 0x12, 0xfd, 0x96, 0x70, 0xe4, 0x1c, 0xad, 0x0a, 0x41, 0xe4, 0x84, + 0xb0, 0xd6, 0x10, 0x26, 0x88, 0x0d, 0xe2, 0x65, 0xdf, 0x25, 0x19, 0x8e, 0x14, 0x5c, 0xd6, 0xb1, 0x63, 0xcc, 0xd5, + 0x51, 0xf5, 0x1a, 0xc0, 0x78, 0xe5, 0x08, 0x9a, 0x8d, 0x22, 0xbb, 0x84, 0xa8, 0x22, 0xc7, 0x13, 0x50, 0x3b, 0x28, + 0x8d, 0xcd, 0xf4, 0x7c, 0x1c, 0xe4, 0xa3, 0x45, 0x85, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x73, 0xd5, 0xcf, + 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x8a, 0xe9, 0x72, + 0x60, 0xdc, 0x37, 0xbc, 0xa2, 0x38, 0xc3, 0x8f, 0x1e, 0x6c, 0x71, 0xfe, 0x74, 0x43, 0xed, 0xc7, 0xdc, 0xa8, 0x87, + 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, 0xfc, 0x43, + 0x99, 0xae, 0x52, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, 0xa2, 0xac, + 0xdf, 0x87, 0xdf, 0x57, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, 0x93, 0x41, + 0x0d, 0xda, 0xf0, 0x0d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, 0xec, 0x4f, + 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xe3, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xc7, 0x97, 0xfc, 0x06, 0xbd, + 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, 0x8f, 0x51, + 0xc9, 0x62, 0x4b, 0x8f, 0x55, 0xd1, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x05, 0xc1, 0x12, 0x18, + 0x17, 0xb1, 0xe6, 0x9b, 0x41, 0xce, 0xe2, 0xd9, 0x66, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1c, 0x0a, 0x09, 0x36, 0x93, + 0xcd, 0xd6, 0x73, 0xb6, 0xf6, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, 0x35, 0x58, + 0xad, 0xa6, 0x6c, 0x55, 0x53, 0x76, 0x4e, 0x53, 0x8e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, 0x88, 0x4d, + 0xa2, 0xab, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, 0x50, 0x85, + 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, 0xbe, 0xa5, + 0x8e, 0x7b, 0x94, 0x6d, 0xfe, 0x2e, 0x76, 0x41, 0x88, 0xdc, 0x8d, 0x3b, 0xf5, 0x33, 0xe2, 0xbd, 0xdd, 0x11, 0xc6, + 0x4f, 0x76, 0xdc, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8b, 0x79, 0x35, 0x49, 0x50, 0xcb, 0x92, 0xf8, 0x1b, + 0x9e, 0x0c, 0x72, 0xb6, 0x04, 0x0f, 0xda, 0x39, 0xcb, 0x00, 0x7f, 0xc5, 0x6a, 0xd1, 0x6f, 0xb5, 0xb7, 0x04, 0xf9, + 0x69, 0x63, 0x37, 0x0a, 0x13, 0x23, 0x48, 0xd4, 0xed, 0xca, 0x40, 0x7e, 0xf8, 0x80, 0xd3, 0xf1, 0xd8, 0x53, 0xc6, + 0xdc, 0xca, 0xf4, 0x32, 0x9d, 0x2b, 0xf9, 0x46, 0xee, 0xa5, 0x8f, 0xbd, 0x04, 0x3b, 0x07, 0xbc, 0x81, 0xb4, 0x81, + 0x37, 0xb0, 0x5d, 0x78, 0x6d, 0x90, 0x30, 0x23, 0xc0, 0x16, 0xc7, 0xc7, 0x48, 0x09, 0x0c, 0xe1, 0x38, 0x4b, 0x01, + 0x98, 0x46, 0x5f, 0x66, 0x2b, 0xfb, 0x32, 0xab, 0x35, 0x5b, 0x2a, 0xa7, 0x7b, 0xe7, 0xd6, 0xed, 0x7c, 0x22, 0x01, + 0xc0, 0xa4, 0xce, 0x81, 0x38, 0x33, 0xc1, 0x2e, 0x4d, 0x22, 0xcb, 0xc7, 0x30, 0xbf, 0x13, 0x6f, 0xca, 0x62, 0xa5, + 0xba, 0xa2, 0xed, 0x33, 0x93, 0xcf, 0x48, 0x27, 0xa1, 0x02, 0x0a, 0x0a, 0xb9, 0xd6, 0xa7, 0xef, 0xc2, 0x77, 0x41, + 0xa1, 0x81, 0xd9, 0x2a, 0xdc, 0xd3, 0x64, 0x8d, 0xd4, 0x1b, 0x55, 0xbf, 0x4f, 0xae, 0x81, 0x54, 0x67, 0x0e, 0x2d, + 0x7b, 0x52, 0x61, 0x80, 0xd8, 0x51, 0x9f, 0x91, 0x50, 0x07, 0x52, 0x0f, 0x18, 0x42, 0xb4, 0x4d, 0x1f, 0x7f, 0x32, + 0x24, 0xba, 0x00, 0x5b, 0x88, 0x36, 0xf0, 0xe3, 0x4f, 0xb0, 0xcf, 0x82, 0xf0, 0x98, 0xe6, 0xd7, 0x90, 0x74, 0x6c, + 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0xb9, 0x94, + 0xea, 0x58, 0xa9, 0xb7, 0x6d, 0xed, 0x07, 0xd1, 0x16, 0x1c, 0x59, 0xc4, 0xdf, 0x67, 0x88, 0x08, 0x66, 0x06, 0x11, + 0x76, 0x2d, 0xd4, 0xdd, 0x9e, 0x52, 0xcb, 0xa2, 0xde, 0xf6, 0x94, 0x52, 0xb7, 0x61, 0xf8, 0x6e, 0x82, 0x99, 0xe2, + 0x86, 0xff, 0x91, 0x79, 0xa1, 0xde, 0x78, 0x2c, 0x0a, 0x74, 0xcf, 0xdf, 0x2f, 0x79, 0x35, 0xdb, 0x28, 0x13, 0xe6, + 0x1d, 0x5f, 0xce, 0x42, 0xd9, 0xd5, 0xd2, 0xb8, 0xf3, 0xd9, 0x5b, 0xaa, 0xf9, 0xe0, 0x1f, 0x0e, 0x09, 0xc4, 0x1b, + 0xc5, 0x57, 0x77, 0x8d, 0xdc, 0xba, 0x26, 0x9b, 0xab, 0x12, 0x50, 0xbf, 0xcf, 0xd7, 0xb8, 0xdf, 0x62, 0xfd, 0xbb, + 0xa7, 0x41, 0xc6, 0x6a, 0x86, 0x2b, 0xa6, 0xf0, 0x29, 0x00, 0x0c, 0x0e, 0xa7, 0x82, 0xb4, 0xc0, 0x1b, 0x5e, 0x0e, + 0x2f, 0x27, 0x1b, 0x32, 0xe9, 0x6e, 0x7c, 0xe4, 0xce, 0x02, 0x55, 0xef, 0x37, 0x14, 0x27, 0x0d, 0x12, 0x8d, 0xbd, + 0x06, 0x5f, 0x66, 0x19, 0xe5, 0xa2, 0x89, 0xfb, 0x98, 0x7c, 0xa5, 0x07, 0x30, 0x57, 0xa1, 0x04, 0x88, 0x7e, 0x63, + 0x59, 0x6c, 0x44, 0xdb, 0x62, 0x03, 0x4b, 0xa9, 0x9a, 0xeb, 0xd5, 0xf4, 0xd9, 0x2b, 0xd1, 0xbc, 0x8f, 0x66, 0x9c, + 0xd2, 0x68, 0xc0, 0x71, 0x1a, 0x85, 0xdb, 0xf7, 0xf7, 0xa2, 0x5c, 0x66, 0x60, 0xc9, 0x56, 0xe1, 0x14, 0x97, 0x8d, + 0x3a, 0x23, 0x5e, 0xe6, 0xb1, 0x02, 0xe8, 0x78, 0x4c, 0x00, 0x54, 0x17, 0x04, 0x54, 0x44, 0x4b, 0xe9, 0xad, 0xd0, + 0x62, 0xa1, 0xde, 0x70, 0x94, 0xc2, 0x1f, 0xe9, 0xcf, 0x83, 0x7c, 0x0a, 0x40, 0xec, 0xfa, 0x38, 0x7a, 0x53, 0x94, + 0xf4, 0xa9, 0x62, 0x96, 0xcb, 0xc1, 0x04, 0x76, 0x75, 0x22, 0x43, 0xad, 0x20, 0x6f, 0xd5, 0x95, 0xb7, 0x32, 0x79, + 0x1b, 0xe3, 0x94, 0xfc, 0xc8, 0x4d, 0xc7, 0x1a, 0x31, 0xf0, 0xca, 0xd3, 0x3a, 0x4d, 0x90, 0x26, 0x17, 0xc0, 0x30, + 0xc4, 0xb7, 0x99, 0xf7, 0xd2, 0x73, 0xa4, 0x2a, 0x48, 0x66, 0xbb, 0xcc, 0x53, 0x17, 0x51, 0x7d, 0xe5, 0xd4, 0xd2, + 0x99, 0xd3, 0x8f, 0x00, 0xde, 0x63, 0x6a, 0xd2, 0x90, 0x8f, 0x70, 0x5b, 0x8a, 0xaf, 0xb7, 0xea, 0x1a, 0x2f, 0x8d, + 0xce, 0xdd, 0xcb, 0x97, 0xee, 0x34, 0xe8, 0xa7, 0x20, 0x28, 0xe7, 0xcb, 0x52, 0xc0, 0x9e, 0x32, 0x9b, 0xeb, 0xd5, + 0xaa, 0x15, 0x5a, 0x87, 0xc3, 0x58, 0x3b, 0x0a, 0x69, 0x75, 0x16, 0xb0, 0xd5, 0x48, 0xa7, 0x04, 0x08, 0xc1, 0x71, + 0x1a, 0x76, 0x82, 0x71, 0x97, 0x4e, 0x23, 0xb2, 0x5e, 0x29, 0x49, 0x17, 0x66, 0x90, 0xfc, 0x93, 0xbc, 0x9e, 0x01, + 0x2d, 0x01, 0x1c, 0x8a, 0x58, 0xc2, 0xc3, 0x49, 0x72, 0x05, 0xd0, 0xe9, 0x70, 0x50, 0x69, 0x68, 0xce, 0x6a, 0x96, + 0xcc, 0x27, 0xb1, 0x54, 0x55, 0x1e, 0x0e, 0x9e, 0x72, 0x33, 0xe8, 0xf7, 0xb3, 0x69, 0xa9, 0x5c, 0x00, 0x82, 0x58, + 0x17, 0x06, 0x88, 0x47, 0x5a, 0x78, 0xb2, 0xe8, 0x53, 0x12, 0xbf, 0x9c, 0x25, 0x73, 0x93, 0x0d, 0xef, 0xc0, 0x08, + 0x36, 0xe3, 0xba, 0xa4, 0x4c, 0x7b, 0x54, 0x7e, 0xcf, 0xe8, 0xa9, 0xed, 0x6b, 0xad, 0xb6, 0x88, 0x75, 0x1d, 0x5c, + 0x95, 0xa8, 0xa7, 0xf8, 0xa0, 0x24, 0xc1, 0xfb, 0xb5, 0x73, 0x33, 0x52, 0xbe, 0x16, 0xb9, 0x1f, 0xb4, 0x33, 0xb5, + 0x72, 0xe0, 0x08, 0xe4, 0x58, 0x45, 0x25, 0xaf, 0x77, 0x1d, 0x82, 0x47, 0x77, 0xa5, 0x02, 0xe5, 0xe0, 0x17, 0x20, + 0x46, 0xd7, 0x57, 0x9d, 0x35, 0xd4, 0x4c, 0xa3, 0xca, 0x23, 0xe8, 0xd4, 0x01, 0x3c, 0x29, 0x78, 0xa9, 0xd5, 0x8f, + 0x87, 0x83, 0x67, 0x7e, 0xf0, 0x57, 0x99, 0xbe, 0x85, 0x98, 0x28, 0xa7, 0x1a, 0x21, 0x71, 0xa5, 0x24, 0x11, 0x1f, + 0x2f, 0x5a, 0x56, 0x8c, 0xca, 0xf0, 0x81, 0x57, 0xaa, 0x7c, 0x75, 0xaa, 0xf2, 0x62, 0xa4, 0x6d, 0x09, 0xbc, 0x26, + 0xff, 0x10, 0xb9, 0xe6, 0xad, 0xaf, 0xbb, 0xca, 0xd0, 0x6b, 0x59, 0x81, 0x8e, 0x60, 0x2b, 0x4b, 0xc9, 0x01, 0x9f, + 0x54, 0x77, 0xd5, 0xaa, 0xf5, 0x39, 0x65, 0x1b, 0xe1, 0x26, 0xbf, 0x8e, 0x1d, 0x1c, 0x29, 0xbf, 0xc1, 0x73, 0x01, + 0xec, 0x35, 0x60, 0x6f, 0xce, 0x59, 0xd1, 0x3c, 0x3a, 0xa4, 0x6d, 0x81, 0x46, 0x66, 0x6e, 0xe7, 0xea, 0xbe, 0x2d, + 0x8f, 0xd2, 0x18, 0x22, 0xd3, 0x1e, 0x99, 0x0e, 0x36, 0xa3, 0xfc, 0xb7, 0x94, 0xdf, 0x2a, 0x1c, 0x03, 0xdf, 0x4e, + 0xbd, 0x03, 0xa8, 0x7a, 0xda, 0x20, 0x63, 0xcd, 0x30, 0xb4, 0xb2, 0xcb, 0xa5, 0xd0, 0x12, 0xb4, 0xd4, 0x4d, 0x10, + 0x9c, 0x1f, 0x11, 0xe5, 0x08, 0x40, 0x17, 0x29, 0x60, 0x82, 0x9f, 0xd2, 0x76, 0xf7, 0xfb, 0xeb, 0xd4, 0x23, 0xf7, + 0xae, 0x50, 0xa3, 0x84, 0x12, 0x8c, 0xfd, 0x44, 0x63, 0x06, 0x1d, 0x5d, 0x91, 0x13, 0x9e, 0xb5, 0x3a, 0xac, 0xeb, + 0xa6, 0x0c, 0xca, 0xe2, 0x98, 0x57, 0xd3, 0xd9, 0xef, 0x4f, 0xf6, 0x75, 0x83, 0x2c, 0xe4, 0xbf, 0xb3, 0x1e, 0x92, + 0x41, 0xf7, 0x20, 0x14, 0xa2, 0x37, 0x0f, 0x66, 0xf8, 0x1f, 0xdb, 0xf0, 0xec, 0x1b, 0x6e, 0xd4, 0x09, 0x60, 0x8e, + 0xb8, 0x5e, 0x7a, 0x8a, 0xb6, 0x1e, 0x6e, 0x81, 0x6c, 0x8d, 0x97, 0xb7, 0xf6, 0x1a, 0xc8, 0x29, 0x8e, 0xff, 0x8e, + 0x67, 0x6a, 0x65, 0x83, 0x9f, 0x9e, 0xb2, 0x1d, 0x78, 0x78, 0x11, 0x02, 0x8a, 0x61, 0xd9, 0xf8, 0x3b, 0xcb, 0x71, + 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, 0x5b, 0x79, 0x77, 0xe4, + 0x94, 0x79, 0xa7, 0x87, 0xd1, 0x75, 0x49, 0xfa, 0x26, 0xf9, 0xd8, 0x1a, 0xb6, 0xdf, 0xb5, 0xfb, 0xcd, 0x10, 0x41, + 0x08, 0xe5, 0xf8, 0x39, 0xa3, 0x13, 0x1a, 0x1f, 0x56, 0xb3, 0xd3, 0xeb, 0xf7, 0xce, 0xf1, 0x82, 0xad, 0xd1, 0x00, + 0x8f, 0x87, 0x2e, 0xe6, 0x89, 0x1a, 0x3a, 0x5d, 0xd7, 0xce, 0xc1, 0x03, 0x83, 0x2c, 0x4f, 0xbe, 0x61, 0x58, 0x62, + 0x7f, 0x12, 0xf1, 0xa4, 0xad, 0xda, 0xd8, 0x1c, 0xa9, 0x36, 0x6a, 0x06, 0x7e, 0xf0, 0x0a, 0x0a, 0x8c, 0x2e, 0x48, + 0x2b, 0x30, 0x0e, 0x47, 0x00, 0xb2, 0x62, 0x1c, 0x8f, 0x0c, 0x26, 0x30, 0xa4, 0x1b, 0x8a, 0x02, 0xf0, 0xf0, 0x38, + 0x1e, 0x84, 0x0c, 0x20, 0x5d, 0xf0, 0xd0, 0xb0, 0x4d, 0x42, 0xca, 0xcf, 0xf3, 0xbc, 0x56, 0x43, 0xe8, 0x3b, 0x0b, + 0xd5, 0xb1, 0x1f, 0x69, 0xaf, 0x58, 0xd7, 0xaa, 0x74, 0x64, 0xab, 0x03, 0xf4, 0x0d, 0x19, 0xf8, 0xd6, 0xb1, 0x05, + 0x40, 0xb4, 0xc4, 0x6f, 0xa9, 0x57, 0xfb, 0x32, 0x66, 0x85, 0x7a, 0x7d, 0x61, 0xda, 0xf5, 0x5a, 0x5a, 0x14, 0x50, + 0x71, 0xdb, 0xaa, 0xed, 0x91, 0x9c, 0xff, 0xf8, 0xae, 0xa3, 0x1d, 0x9f, 0x9d, 0x1a, 0x5b, 0x42, 0x99, 0x5b, 0x3c, + 0x91, 0xd5, 0xd1, 0x96, 0xea, 0x54, 0x1f, 0x70, 0xa9, 0x49, 0x75, 0x66, 0x60, 0x78, 0x8d, 0x00, 0xe5, 0x16, 0x22, + 0x69, 0x1c, 0xf6, 0xce, 0x27, 0x83, 0x82, 0xb9, 0x45, 0x02, 0x12, 0xd8, 0xc6, 0xd6, 0x2e, 0x9a, 0xeb, 0xd7, 0x6f, + 0xa9, 0x57, 0xb5, 0xa9, 0xea, 0xc1, 0x1b, 0x2f, 0x70, 0xf6, 0x4e, 0x6b, 0x01, 0x01, 0x14, 0xb6, 0x96, 0xe5, 0xe0, + 0xdc, 0xed, 0xaa, 0x96, 0x8a, 0x32, 0xea, 0xf7, 0xcf, 0x7f, 0x4b, 0x51, 0x11, 0x7b, 0xaa, 0x38, 0x65, 0xfd, 0x76, + 0xcb, 0x5c, 0x54, 0x96, 0xbc, 0x41, 0x15, 0xad, 0xd5, 0x51, 0x53, 0xb9, 0x6e, 0xae, 0x5a, 0x32, 0x41, 0x8c, 0xee, + 0xd3, 0xb5, 0xce, 0x9d, 0x7a, 0xef, 0x55, 0x1c, 0x31, 0x10, 0xdc, 0x74, 0x8f, 0x0f, 0x0e, 0x42, 0xa3, 0xa2, 0x5c, + 0x70, 0xa3, 0xb4, 0xaa, 0xa4, 0x14, 0xf2, 0x56, 0x45, 0x73, 0xa6, 0x8f, 0x00, 0x88, 0x00, 0xab, 0x44, 0xfd, 0x1f, + 0xbe, 0x34, 0xc6, 0x83, 0x07, 0xbe, 0x26, 0xd7, 0xb1, 0xf5, 0xfe, 0x69, 0x8d, 0xb4, 0xda, 0x38, 0x26, 0xb5, 0xea, + 0x65, 0xab, 0x78, 0xd9, 0xbd, 0x4e, 0xc5, 0xe0, 0xf9, 0xff, 0xdc, 0x07, 0xa8, 0x11, 0x2d, 0x65, 0x70, 0xeb, 0x6a, + 0x80, 0xc6, 0x87, 0x63, 0xe1, 0x1b, 0x3f, 0x64, 0x9c, 0x0f, 0x66, 0xe8, 0xa8, 0x36, 0x07, 0x07, 0x04, 0x47, 0x75, + 0x8f, 0xc6, 0x84, 0x59, 0x38, 0xf7, 0x20, 0x50, 0x7d, 0xe2, 0x3e, 0xe3, 0xda, 0x0b, 0xda, 0x04, 0x3e, 0x59, 0xd7, + 0x35, 0x45, 0x80, 0x8b, 0xd8, 0x98, 0x88, 0x21, 0x2e, 0x9b, 0x44, 0xea, 0x9b, 0x31, 0x28, 0x00, 0x8a, 0x17, 0x15, + 0xc9, 0xa5, 0x8b, 0x34, 0xaf, 0x44, 0x59, 0xeb, 0x66, 0x54, 0xac, 0x18, 0x02, 0xc0, 0x43, 0x50, 0x5c, 0x55, 0x66, + 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x6a, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, 0xd2, 0x3b, 0x1f, 0xb7, 0xce, + 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, 0x3f, 0xe3, 0x2f, 0x08, 0x4c, + 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x82, 0x97, 0x93, 0x70, 0x38, 0xf4, 0x41, 0x1f, + 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, 0x10, 0xd1, 0x42, 0x43, 0x1f, + 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, 0xda, 0xd0, 0x22, 0xc5, 0x45, + 0xa3, 0xcc, 0x66, 0xb9, 0xec, 0x84, 0x8d, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, 0x54, 0xad, 0xa7, 0x7a, 0x3d, + 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa4, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, 0xa3, 0x6a, 0x9d, 0xa5, 0x11, + 0x55, 0x6e, 0x92, 0xbb, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0x97, 0x29, 0x3b, 0x5b, 0x83, 0x13, 0x47, 0x9e, 0x4b, 0x6e, + 0xf9, 0xee, 0xbc, 0xa2, 0xbb, 0x53, 0xed, 0x5b, 0x80, 0x7b, 0x33, 0x6c, 0xc8, 0x9c, 0xd7, 0xd8, 0x69, 0x10, 0x26, + 0x81, 0x1f, 0xb1, 0x8f, 0x19, 0xb2, 0xc1, 0x80, 0x8e, 0x42, 0xfa, 0x5f, 0x5b, 0xe6, 0x48, 0xc0, 0xe4, 0xaf, 0xe7, + 0x7e, 0xb3, 0x28, 0x72, 0x58, 0x8c, 0x1f, 0x36, 0x18, 0x69, 0xac, 0xd6, 0x60, 0x58, 0xde, 0x21, 0xf2, 0xa7, 0x76, + 0xc7, 0x34, 0xd5, 0xf1, 0x66, 0xbd, 0xd6, 0xfc, 0xea, 0xe9, 0x53, 0x5d, 0x9f, 0xff, 0xf6, 0xfd, 0x65, 0x58, 0x33, + 0xfb, 0x43, 0x10, 0x4a, 0xbb, 0x77, 0x8b, 0x73, 0x47, 0xa2, 0x77, 0xac, 0x34, 0xb3, 0x4b, 0xbb, 0x64, 0x97, 0xa6, + 0xb4, 0x1b, 0x72, 0xbd, 0xfa, 0x4a, 0x79, 0x63, 0xe7, 0x15, 0xd3, 0xfd, 0x7b, 0xa1, 0x77, 0x94, 0x53, 0x35, 0x81, + 0x88, 0x26, 0xed, 0x48, 0xdc, 0xee, 0x95, 0xe1, 0xf3, 0x49, 0xde, 0x2e, 0xe1, 0xa8, 0x6b, 0x58, 0x6e, 0xbe, 0xfd, + 0xcf, 0xbc, 0xea, 0xac, 0x70, 0xfb, 0xa5, 0x31, 0x6b, 0x7f, 0x0a, 0xe2, 0xaa, 0xfe, 0xf0, 0x9e, 0xd4, 0x4c, 0xc9, + 0xff, 0x55, 0x8f, 0x81, 0xab, 0x9f, 0x4c, 0x3b, 0xba, 0xa7, 0x10, 0x36, 0x98, 0xfd, 0xfc, 0xf8, 0xa1, 0x05, 0xab, + 0xea, 0x02, 0x45, 0x72, 0x00, 0x9d, 0xbb, 0x64, 0x84, 0xf7, 0x3b, 0xc6, 0xb9, 0x7f, 0xf5, 0xbd, 0x9a, 0x1c, 0x21, + 0xa2, 0x5d, 0x84, 0x03, 0x80, 0xb8, 0xd3, 0x54, 0xd6, 0xa1, 0x06, 0xe8, 0x03, 0x02, 0xeb, 0xd0, 0xb7, 0x19, 0xc0, + 0x41, 0x1f, 0x6d, 0x9e, 0x45, 0x20, 0xaf, 0x7b, 0xf7, 0xec, 0x9a, 0xed, 0x7c, 0xfe, 0x62, 0x95, 0x7a, 0xf7, 0xe8, + 0x10, 0x7c, 0x3e, 0xf6, 0xa7, 0x97, 0x81, 0xc1, 0x85, 0x66, 0xd7, 0xcf, 0x04, 0xdb, 0xb1, 0xdd, 0x33, 0x44, 0x2a, + 0xea, 0xce, 0x3f, 0xbc, 0x34, 0xd1, 0xf3, 0xce, 0x0b, 0x77, 0x7c, 0x09, 0xe0, 0x81, 0x2c, 0x06, 0x14, 0x9f, 0xa5, + 0xf7, 0x2f, 0x96, 0x80, 0x9a, 0xfc, 0x96, 0xaf, 0xbd, 0x2f, 0x94, 0xba, 0x80, 0x3f, 0x07, 0x94, 0x3e, 0xc9, 0xb9, + 0x77, 0x37, 0xbc, 0xf5, 0x2f, 0x9e, 0x83, 0xf3, 0xc4, 0x6a, 0xb8, 0x80, 0xbf, 0x0a, 0x3e, 0xf4, 0xee, 0x06, 0x98, + 0x58, 0xf2, 0xa1, 0xb7, 0x1a, 0x40, 0xaa, 0xc2, 0x85, 0xc4, 0xd8, 0x87, 0x5f, 0x83, 0x9c, 0xe1, 0x1f, 0xbf, 0x69, + 0x0c, 0xd6, 0x5f, 0x83, 0x42, 0xa3, 0xb1, 0x96, 0x2a, 0x64, 0x29, 0x16, 0x67, 0x02, 0x6c, 0xc2, 0x71, 0xb7, 0x2f, + 0x56, 0xb5, 0x59, 0x0b, 0xfa, 0xf3, 0x11, 0xdf, 0xa3, 0xb1, 0xba, 0x2a, 0xe7, 0xa2, 0xfc, 0x88, 0xf4, 0xa9, 0x8e, + 0x8f, 0x51, 0xb1, 0xa9, 0xbb, 0xd3, 0xa9, 0x56, 0x1d, 0x69, 0xbf, 0x29, 0xd7, 0x60, 0xc7, 0xeb, 0xe4, 0xc8, 0x52, + 0x78, 0xd6, 0x61, 0xe7, 0xa5, 0x53, 0xa2, 0xc3, 0x30, 0xde, 0x6d, 0xd5, 0x33, 0x86, 0xf2, 0xdc, 0x60, 0x4c, 0x17, + 0x3c, 0xe2, 0x2f, 0x06, 0xb9, 0x0c, 0x8d, 0xf9, 0x80, 0x6c, 0x18, 0xca, 0x87, 0x16, 0x19, 0x12, 0x22, 0xde, 0x43, + 0x25, 0x60, 0xdb, 0x82, 0x32, 0x29, 0xe0, 0x2c, 0x1a, 0xfc, 0x56, 0x7b, 0x39, 0xf0, 0x1e, 0x44, 0x7e, 0x23, 0x5d, + 0xca, 0x25, 0x36, 0x3a, 0x71, 0x2c, 0x0b, 0xed, 0x3c, 0xae, 0xbf, 0x8e, 0x41, 0xfd, 0x5e, 0xe9, 0x37, 0x28, 0x67, + 0x7f, 0x94, 0xac, 0xd3, 0xc6, 0x13, 0xe3, 0x1f, 0xae, 0xf2, 0x4f, 0xd1, 0x52, 0x0f, 0xff, 0x9f, 0x31, 0x85, 0xd2, + 0xbf, 0x4a, 0xcb, 0x68, 0xb3, 0x5a, 0x8a, 0x52, 0xe4, 0x91, 0x38, 0xf9, 0x5a, 0x64, 0xe7, 0xf2, 0x9d, 0x4f, 0xa1, + 0x5f, 0x00, 0x5a, 0xf6, 0x09, 0x32, 0xfa, 0x7b, 0x26, 0xf8, 0xf0, 0x7b, 0xed, 0x5c, 0x9b, 0xf3, 0xf1, 0x24, 0xbf, + 0xb2, 0xf6, 0x6e, 0xc7, 0x8b, 0xc4, 0x28, 0xc6, 0x72, 0x5f, 0x75, 0xb3, 0x72, 0xa2, 0x92, 0x03, 0x23, 0x5d, 0x93, + 0xbd, 0x5c, 0xc9, 0xba, 0x9d, 0x6e, 0x25, 0x10, 0x51, 0x05, 0xde, 0x63, 0x5c, 0xc5, 0x3e, 0x82, 0xe9, 0xba, 0xe3, + 0x32, 0xda, 0xf1, 0x9e, 0xf1, 0xea, 0x44, 0x59, 0xc1, 0xed, 0x46, 0xb4, 0x27, 0x74, 0xf4, 0xd3, 0xa4, 0xb6, 0x2c, + 0x1c, 0x80, 0xdc, 0x25, 0x8c, 0x65, 0x43, 0xb0, 0x62, 0x50, 0xfa, 0x7a, 0x4d, 0xc9, 0xb2, 0x00, 0x8b, 0xce, 0x2e, + 0x23, 0x10, 0xc3, 0xba, 0x69, 0x4e, 0xe8, 0x78, 0xe9, 0xe2, 0xbc, 0xd7, 0x2a, 0x52, 0xf0, 0x8c, 0x16, 0x1d, 0x73, + 0xd3, 0x91, 0x6e, 0x8c, 0xf6, 0xf6, 0x7b, 0x83, 0x90, 0xe2, 0xf9, 0x03, 0x5b, 0xad, 0x8b, 0x8b, 0xc4, 0x2b, 0x64, + 0xa2, 0x05, 0xb1, 0x14, 0x81, 0x19, 0x2f, 0x34, 0x8d, 0x30, 0x41, 0x99, 0x12, 0x2c, 0x5a, 0xa3, 0x43, 0xfb, 0xc3, + 0x12, 0x76, 0x8f, 0x31, 0x02, 0x04, 0xaa, 0x4c, 0x9f, 0xc3, 0xd6, 0x84, 0xd9, 0xd4, 0xc5, 0x06, 0x68, 0xab, 0x18, + 0x1a, 0x84, 0xb5, 0x21, 0xe6, 0x63, 0x9a, 0xdf, 0xfd, 0x0b, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, 0xde, 0xed, 0x9a, 0x84, + 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xa8, 0x1d, 0x6b, 0xa9, 0x77, 0xac, 0xb5, + 0xde, 0xb1, 0xee, 0x1a, 0xfe, 0x21, 0xf3, 0x62, 0x96, 0x80, 0x7e, 0x77, 0xc5, 0x55, 0x83, 0xa0, 0x19, 0x1b, 0x76, + 0x0b, 0xbf, 0x25, 0xd6, 0x6e, 0xe9, 0x5f, 0x2c, 0xd9, 0xc2, 0xf4, 0x81, 0x6e, 0x1d, 0x60, 0x19, 0x51, 0x93, 0xef, + 0x91, 0x77, 0xd3, 0x59, 0x51, 0xb8, 0x3d, 0xb1, 0x85, 0xcf, 0xae, 0xcd, 0x9b, 0xf7, 0xcf, 0x22, 0xc8, 0xbd, 0xe3, + 0xde, 0xfd, 0xf0, 0xda, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, 0xea, 0x88, 0x4f, 0x10, 0xad, 0xec, 0x29, + 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, + 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, + 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, + 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, + 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, + 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, + 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0xbe, 0x3f, 0x2d, 0x94, 0x6b, 0x37, 0x6f, 0xe3, + 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x8e, 0x94, 0x5d, 0x2c, 0xe1, 0x1e, + 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf1, 0x9c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, 0x62, 0x5b, 0xb8, 0x78, + 0xce, 0x36, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0x8d, 0x6a, 0x8e, 0x35, 0xd4, 0x6c, 0x6d, + 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0xee, 0xda, 0x8a, 0x8f, 0x95, 0xb5, 0x2e, 0xdd, 0xeb, 0x3d, 0xaa, 0x0b, 0x60, + 0xeb, 0xbf, 0x3d, 0x5e, 0xb9, 0x9e, 0xcf, 0x08, 0xe0, 0x6b, 0xc1, 0xc7, 0x93, 0x05, 0x7a, 0x95, 0x2c, 0xfc, 0xdb, + 0x81, 0x1a, 0x7f, 0xa7, 0x73, 0x17, 0x00, 0x5d, 0x49, 0x79, 0x05, 0xe4, 0x1d, 0xe4, 0x98, 0x5b, 0x76, 0xe5, 0xfd, + 0xc9, 0x77, 0xd8, 0x35, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, + 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x84, 0x20, 0xae, 0xe0, 0x16, 0xe2, 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, + 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, + 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xd7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x40, 0xfc, 0x74, 0x3b, 0xe0, + 0xf7, 0x1d, 0x6b, 0xcb, 0xbb, 0x66, 0x0b, 0xb6, 0x83, 0x4b, 0x50, 0xd3, 0x5e, 0xf6, 0x27, 0x95, 0x0b, 0xda, 0xb1, + 0x4b, 0xe2, 0xe1, 0x8c, 0x59, 0xa5, 0xcc, 0xac, 0x93, 0xea, 0x4a, 0x74, 0xc6, 0x74, 0xd6, 0x7a, 0x3e, 0x57, 0xf3, + 0x49, 0xa1, 0x41, 0xfd, 0xce, 0x89, 0x8f, 0xa8, 0xe8, 0x3c, 0x81, 0xad, 0x65, 0x05, 0xb1, 0xda, 0xe7, 0x60, 0xad, + 0xd5, 0x2e, 0xfd, 0x5e, 0x3e, 0xe0, 0x36, 0xe5, 0xb0, 0x0e, 0x0c, 0x6a, 0x4e, 0xac, 0xa8, 0xc7, 0x6c, 0xc7, 0xb8, + 0xf9, 0xe9, 0xe5, 0x0f, 0x4e, 0x58, 0xb2, 0x62, 0xb5, 0x3f, 0xfd, 0xfe, 0x99, 0xa7, 0xbf, 0x53, 0xfb, 0x17, 0xc2, + 0x0f, 0xc6, 0xff, 0xa9, 0xdd, 0xd7, 0x5a, 0x8c, 0xca, 0x56, 0x39, 0x42, 0xe3, 0x6e, 0x25, 0x4d, 0x96, 0x9f, 0x84, + 0x27, 0xac, 0x05, 0xcf, 0x72, 0xbd, 0x44, 0xb3, 0x02, 0x56, 0x58, 0xcb, 0x24, 0x5c, 0x61, 0xac, 0x96, 0xb6, 0xfa, + 0x16, 0x4d, 0x73, 0x7c, 0x38, 0xd7, 0x06, 0x65, 0xca, 0xd9, 0x19, 0xb1, 0x1a, 0x2e, 0xc3, 0xd2, 0x84, 0x22, 0x64, + 0xf7, 0x76, 0x70, 0x63, 0xa7, 0x2c, 0xa5, 0x0c, 0xe7, 0x18, 0x4c, 0x78, 0x24, 0x46, 0x55, 0xbe, 0xbf, 0x2f, 0x29, + 0x72, 0xda, 0x96, 0x83, 0x2a, 0x84, 0x7d, 0x24, 0x51, 0x02, 0xb7, 0x22, 0x2d, 0x14, 0x29, 0x8b, 0xbf, 0x1d, 0xa0, + 0x0b, 0xbc, 0x80, 0xba, 0x1a, 0x75, 0xfb, 0xc3, 0x11, 0x0f, 0x1f, 0x99, 0xfa, 0xc0, 0x88, 0x25, 0x81, 0xda, 0x5e, + 0x66, 0xe9, 0x1d, 0xa8, 0xf0, 0x7b, 0xb8, 0x9a, 0x88, 0xfd, 0xdc, 0x92, 0xa2, 0x22, 0x1b, 0xe9, 0x0d, 0xad, 0xc1, + 0x23, 0xb4, 0xa6, 0x7c, 0xef, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, + 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0xef, + 0x55, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, 0xac, 0xd2, 0xd7, 0x24, 0x61, 0x4f, 0x0c, + 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, 0xd2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, + 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x57, 0xc4, 0x97, 0x23, 0x3c, 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, + 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, + 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, + 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, + 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, + 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, + 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, + 0x58, 0x1d, 0xf4, 0xfe, 0x32, 0x7e, 0xda, 0x33, 0x32, 0xf2, 0xb8, 0x75, 0x58, 0xfd, 0xaf, 0xbf, 0x42, 0x00, 0x1c, + 0x9e, 0x4d, 0xbd, 0xcb, 0x31, 0x64, 0x95, 0x65, 0x04, 0x92, 0x9f, 0x18, 0x7c, 0xf9, 0x02, 0xa0, 0xea, 0x33, 0x5d, + 0xab, 0xc9, 0x51, 0x7b, 0xcc, 0xa1, 0x2b, 0x06, 0x80, 0x6d, 0x58, 0xa2, 0xaa, 0x16, 0x36, 0x61, 0x71, 0xfb, 0x19, + 0x46, 0x73, 0xd9, 0xf4, 0x82, 0x06, 0xea, 0x11, 0x82, 0x5f, 0x5a, 0x0f, 0xad, 0xb5, 0x4c, 0x39, 0x74, 0x6d, 0x14, + 0x55, 0x36, 0xd4, 0x25, 0xac, 0xd6, 0x22, 0xaa, 0x89, 0x22, 0xe5, 0x92, 0x51, 0x14, 0x4b, 0x15, 0xec, 0x33, 0x71, + 0x07, 0x51, 0xf3, 0xb4, 0xd5, 0x56, 0xc1, 0xfe, 0x0e, 0x10, 0xd6, 0xc2, 0x5a, 0x48, 0x67, 0x50, 0x7b, 0xa7, 0x1f, + 0x29, 0x7f, 0x79, 0x21, 0xb7, 0x73, 0x0b, 0x45, 0xb8, 0x3d, 0x07, 0xe5, 0x4d, 0x5d, 0x95, 0x8a, 0x68, 0xb4, 0x04, + 0x4a, 0x99, 0x13, 0x44, 0x16, 0x20, 0x80, 0xe3, 0x06, 0x02, 0x9f, 0xd7, 0xf8, 0x04, 0x1a, 0x85, 0x40, 0x7e, 0x60, + 0x15, 0xae, 0x3d, 0xa4, 0xa5, 0xd6, 0x88, 0x28, 0x11, 0x3f, 0xba, 0x7a, 0x8e, 0xed, 0xab, 0xa7, 0xb1, 0xb6, 0x94, + 0x26, 0x88, 0x9f, 0x58, 0x6c, 0x21, 0x26, 0x88, 0xea, 0x10, 0x1d, 0xc1, 0x72, 0x42, 0x88, 0xc2, 0x1f, 0x42, 0x3f, + 0x35, 0xf0, 0x97, 0x6c, 0x59, 0xe4, 0x35, 0xc1, 0x62, 0x56, 0x0c, 0xd0, 0xaa, 0x08, 0x3c, 0xd3, 0xd9, 0x52, 0x99, + 0xd3, 0x3c, 0x3a, 0xb2, 0x83, 0xf3, 0xae, 0x83, 0xbd, 0xf4, 0x65, 0xec, 0x64, 0xd9, 0x34, 0x6a, 0x63, 0x43, 0x24, + 0xbc, 0x22, 0x7f, 0x95, 0xa5, 0xc6, 0x39, 0x32, 0x97, 0xeb, 0xbb, 0x2e, 0xee, 0xee, 0x68, 0x9b, 0xb0, 0x0a, 0x11, + 0xea, 0xb6, 0xa1, 0x72, 0x29, 0xcc, 0xc6, 0xa6, 0x69, 0x80, 0x2f, 0x14, 0x95, 0x4a, 0x55, 0x6a, 0x2b, 0x95, 0x9c, + 0xf0, 0xae, 0xaf, 0x6a, 0x91, 0xba, 0x22, 0xd8, 0xc6, 0x0c, 0xf5, 0x50, 0x6e, 0xd4, 0xd8, 0xd7, 0x1d, 0xab, 0xf4, + 0x0e, 0x13, 0xe4, 0x8c, 0xbc, 0xc8, 0xc1, 0x45, 0x49, 0x41, 0xe6, 0x6a, 0x08, 0xf3, 0x47, 0x0d, 0x9f, 0x16, 0x96, + 0x7b, 0x28, 0x01, 0xb3, 0xa3, 0x86, 0x97, 0x11, 0x02, 0x11, 0x97, 0xca, 0xbe, 0x62, 0xe2, 0xf7, 0x14, 0xcc, 0x92, + 0x09, 0xdd, 0x8b, 0x58, 0x18, 0xa1, 0x8d, 0x4f, 0x92, 0x64, 0xea, 0x69, 0x0a, 0x6e, 0xe4, 0x32, 0xcc, 0xd1, 0x08, + 0x2d, 0xf9, 0xc8, 0x81, 0xf4, 0xb5, 0x9c, 0x4a, 0xf0, 0x11, 0x75, 0x0a, 0x38, 0x9e, 0x9f, 0x17, 0xd6, 0x4f, 0x96, + 0x4b, 0xcc, 0x65, 0x6d, 0xfe, 0xcb, 0x8e, 0x8e, 0xc1, 0x2e, 0x4f, 0x13, 0xc7, 0xd5, 0x7f, 0x54, 0x25, 0xc5, 0xc3, + 0xcf, 0x69, 0x0e, 0x28, 0x82, 0x99, 0x3d, 0xc5, 0xf8, 0xd8, 0x67, 0x99, 0x02, 0xfe, 0x76, 0xbd, 0xb5, 0x64, 0x62, + 0x97, 0xb4, 0x9b, 0x2b, 0xe3, 0x97, 0xda, 0xb0, 0xe3, 0xe0, 0xdc, 0x00, 0x14, 0x67, 0x8d, 0x0e, 0xcb, 0x6b, 0xdd, + 0xb6, 0x2a, 0x54, 0xa0, 0xd6, 0xff, 0xd9, 0x2d, 0x4c, 0x79, 0x9b, 0x97, 0xca, 0xdb, 0x3c, 0x34, 0x01, 0x02, 0x91, + 0x19, 0xf2, 0xac, 0xe9, 0x98, 0x24, 0xee, 0x1d, 0x29, 0x69, 0xdf, 0x91, 0xe2, 0x47, 0xef, 0x48, 0xc8, 0xb7, 0x84, + 0x8e, 0xec, 0x4b, 0x4e, 0x4e, 0xa0, 0xcc, 0x60, 0x2f, 0xaf, 0x99, 0xec, 0x1f, 0xd0, 0x5e, 0x38, 0x97, 0xe5, 0x15, + 0xbf, 0x16, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, + 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, 0xf1, 0xf1, 0xd7, 0x1c, 0x45, 0x6c, 0xa5, 0x3c, 0x92, 0x2e, 0x54, + 0x62, 0x78, 0x69, 0xe0, 0x61, 0x76, 0x7c, 0x3c, 0xd9, 0x5d, 0xdd, 0x4f, 0x06, 0x83, 0x9d, 0xea, 0xdb, 0x2d, 0xaf, + 0x67, 0xbb, 0x39, 0x7b, 0xe0, 0xb7, 0xd3, 0x6d, 0xb0, 0x6f, 0x60, 0xdb, 0xdd, 0x5d, 0x89, 0xc3, 0x61, 0xf7, 0x82, + 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, + 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, + 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe5, 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, + 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, + 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xfa, + 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xf5, 0x6c, 0x33, + 0xf7, 0x5f, 0xac, 0xd8, 0x1d, 0x70, 0xa1, 0x28, 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, + 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, + 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, 0xd7, 0xfc, 0xa6, 0x39, 0x76, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, + 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0x95, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x57, 0x0b, + 0x39, 0xf3, 0xcc, 0x40, 0xdf, 0x56, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x6a, 0xa6, + 0x6d, 0x51, 0x97, 0xdf, 0xf6, 0x9e, 0xc9, 0x6f, 0x64, 0x60, 0x0b, 0x91, 0x14, 0x8e, 0xe3, 0x8b, 0xe7, 0x27, 0xfc, + 0x57, 0x2d, 0x8f, 0x5a, 0xed, 0x17, 0x4a, 0x7d, 0xfa, 0x8a, 0x8e, 0x68, 0xe2, 0x5e, 0xb4, 0x65, 0x58, 0xa3, 0xac, + 0xa9, 0xa5, 0xc3, 0x30, 0xae, 0x61, 0x5f, 0x1e, 0x38, 0xf4, 0x1d, 0x10, 0x68, 0xab, 0x54, 0x0a, 0xb4, 0x70, 0x0c, + 0xa3, 0x30, 0x0b, 0x29, 0x8f, 0x0b, 0xb3, 0x94, 0xf7, 0x58, 0xa0, 0xc5, 0xad, 0xba, 0xc7, 0xd4, 0x76, 0x0b, 0x22, + 0xac, 0xde, 0x32, 0xce, 0x2f, 0x1b, 0x55, 0xb8, 0x2d, 0x40, 0x51, 0x04, 0x65, 0xb0, 0x27, 0xb9, 0x6d, 0xa1, 0xa4, + 0xd9, 0x28, 0xac, 0xc5, 0x5d, 0x51, 0xee, 0x7a, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, 0x75, + 0x28, 0x17, 0xe9, 0x7f, 0x64, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xe7, 0x97, 0xf4, + 0x93, 0xc1, 0x32, 0x72, 0x4a, 0x7d, 0x1f, 0x8d, 0x6e, 0xd3, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, 0x0a, + 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, 0x26, + 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, 0x90, + 0xdc, 0xa9, 0x2b, 0x7f, 0x54, 0x4e, 0xfe, 0x13, 0x0d, 0x91, 0x57, 0x5c, 0x21, 0x56, 0x16, 0x5c, 0x62, 0x31, 0x54, + 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xcb, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, 0x11, + 0x3e, 0x6e, 0xad, 0x45, 0x08, 0x56, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, 0x14, + 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xa8, 0x48, 0xcf, 0x5f, 0x9a, 0x94, 0x5c, 0x1a, + 0x33, 0x3e, 0x88, 0x32, 0x12, 0x79, 0x1d, 0xde, 0x89, 0x69, 0x81, 0x7c, 0xa3, 0xc7, 0x0f, 0x82, 0x4b, 0x78, 0x37, + 0xe4, 0x5e, 0x01, 0xb6, 0x04, 0xec, 0x00, 0xf7, 0xca, 0x8c, 0x72, 0x9d, 0xd6, 0xf5, 0x5b, 0xeb, 0xa1, 0x18, 0x86, + 0xcf, 0x2c, 0x81, 0xed, 0x68, 0x1d, 0x1d, 0xe9, 0xe1, 0xc3, 0xff, 0xba, 0xaa, 0x39, 0xea, 0x54, 0x2e, 0x67, 0xc7, + 0x13, 0x96, 0x22, 0x66, 0xd0, 0xfd, 0x75, 0xfb, 0x4a, 0x00, 0xdd, 0x2e, 0x8b, 0x79, 0x36, 0xda, 0xc9, 0xbf, 0xa5, + 0x1b, 0x2b, 0x4a, 0x9b, 0x78, 0x97, 0xf5, 0xc6, 0xfe, 0x70, 0xf4, 0x97, 0x67, 0x5f, 0x26, 0x84, 0xaa, 0xb3, 0x61, + 0x6b, 0x1d, 0xe7, 0xf2, 0xbf, 0xfe, 0x3a, 0x26, 0x2b, 0x08, 0x0a, 0xc2, 0xb2, 0x53, 0x4c, 0x54, 0x30, 0x8a, 0x14, + 0x6b, 0x3e, 0x9e, 0xac, 0x51, 0x27, 0xbc, 0xf6, 0x97, 0x5a, 0x27, 0x4c, 0x8c, 0xac, 0x54, 0xfe, 0x9a, 0x55, 0xec, + 0x4e, 0x65, 0x16, 0x90, 0x79, 0x90, 0x4f, 0xd6, 0x46, 0x83, 0xb9, 0xe2, 0xf5, 0x6c, 0x3d, 0x97, 0xca, 0x67, 0x30, + 0xe5, 0x2c, 0x07, 0x27, 0x4b, 0x61, 0xf7, 0x24, 0x50, 0xb4, 0x66, 0xe8, 0xda, 0x9f, 0x62, 0xab, 0x5e, 0xa7, 0x55, + 0x0d, 0xf0, 0x80, 0x10, 0x03, 0x43, 0xed, 0xd5, 0xc2, 0x43, 0x6b, 0x01, 0xac, 0xfd, 0x51, 0xe9, 0x07, 0xe3, 0xc9, + 0x92, 0x2f, 0x90, 0x7f, 0x39, 0x72, 0xd4, 0xee, 0xfd, 0xbe, 0x77, 0x0f, 0x52, 0x70, 0xe4, 0x5a, 0x28, 0x90, 0x08, + 0x68, 0xc1, 0x37, 0xbe, 0xf2, 0xc1, 0xb8, 0x46, 0x6d, 0x35, 0x28, 0xa8, 0x1d, 0xdd, 0xf2, 0xd8, 0xd1, 0x3b, 0xdf, + 0x9f, 0xd0, 0x57, 0x2f, 0xb4, 0x70, 0xfc, 0x95, 0x33, 0x72, 0xcd, 0x56, 0x1d, 0x72, 0x44, 0x33, 0xe9, 0x10, 0x22, + 0x56, 0x6c, 0xcd, 0xae, 0x49, 0xe5, 0xdc, 0x39, 0x64, 0xa7, 0x8f, 0x50, 0xa5, 0xd7, 0x7a, 0x7c, 0x3b, 0x51, 0xba, + 0xdb, 0xe3, 0xdd, 0xe4, 0x5b, 0x36, 0x11, 0x31, 0x18, 0xd0, 0x06, 0xe1, 0x8c, 0xac, 0x43, 0xa4, 0xd2, 0x01, 0x42, + 0xe0, 0x98, 0x80, 0xa6, 0xff, 0xf8, 0x9a, 0x44, 0x01, 0x47, 0xda, 0x08, 0x59, 0xcb, 0x0e, 0x87, 0x1c, 0x34, 0xca, + 0xcd, 0x1f, 0x5e, 0xa1, 0x4e, 0x73, 0x60, 0x9e, 0x2e, 0x61, 0xcf, 0xc1, 0x23, 0xbd, 0x38, 0x3e, 0xd2, 0xff, 0x3b, + 0x9a, 0xa8, 0xf1, 0x7f, 0xae, 0x89, 0x52, 0x5a, 0x24, 0x47, 0xb5, 0xf4, 0x4d, 0xea, 0x28, 0xb8, 0xc8, 0x3b, 0x6a, + 0x21, 0x7b, 0x96, 0x8d, 0x1b, 0xd5, 0xbc, 0xff, 0x5f, 0x2b, 0xf3, 0xff, 0x35, 0xad, 0x0c, 0x53, 0xb2, 0x63, 0xa9, + 0x66, 0x1e, 0x68, 0x15, 0xc3, 0xec, 0x67, 0x92, 0x10, 0x19, 0x2e, 0x0d, 0xf8, 0x51, 0x05, 0xfb, 0x38, 0xad, 0xd6, + 0x59, 0xb8, 0x43, 0x25, 0xea, 0xad, 0xb8, 0x4b, 0xf3, 0x97, 0xf5, 0xbf, 0x45, 0x59, 0xc0, 0xd4, 0xbe, 0x2b, 0xd3, + 0x38, 0x20, 0x0b, 0x7f, 0x16, 0x96, 0x38, 0xb9, 0xb1, 0x8d, 0x3f, 0xcb, 0xf1, 0xb4, 0x5f, 0x75, 0x66, 0x1e, 0x48, + 0xa0, 0x06, 0xe2, 0x8f, 0x9c, 0xcb, 0xca, 0xe2, 0x01, 0xa1, 0x9b, 0x7f, 0x28, 0xcb, 0xa2, 0xf4, 0x7a, 0x9f, 0x92, + 0xb4, 0x3a, 0x5b, 0x89, 0x3a, 0x29, 0x62, 0x05, 0x65, 0x93, 0x02, 0x8c, 0x3e, 0xac, 0x3c, 0x11, 0x07, 0x67, 0x08, + 0xd4, 0x70, 0x56, 0x27, 0x21, 0x00, 0x0d, 0x2b, 0x84, 0xfd, 0x33, 0x68, 0xe1, 0x59, 0x18, 0x87, 0x6b, 0x80, 0xc9, + 0x49, 0xab, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, 0x88, 0x47, 0x3d, 0x45, 0xc9, 0xf2, 0x26, 0x77, 0xe5, 0x5c, 0x7f, + 0xff, 0x07, 0x05, 0xb0, 0x1b, 0x30, 0xdb, 0x16, 0xd8, 0x01, 0x40, 0x82, 0x02, 0xd9, 0x42, 0x9d, 0x46, 0x67, 0x6a, + 0xa9, 0xc0, 0x7b, 0xae, 0x07, 0xf8, 0x9b, 0x1c, 0xb0, 0x8c, 0xeb, 0x42, 0x06, 0x8c, 0x20, 0x80, 0x11, 0x38, 0x28, + 0x01, 0x43, 0x67, 0x88, 0xdb, 0xaa, 0x9c, 0xb5, 0xd0, 0x5c, 0xe9, 0xb6, 0xe4, 0xa6, 0x51, 0xce, 0x56, 0x22, 0x80, + 0xbe, 0xba, 0x29, 0x71, 0xba, 0x5c, 0xb6, 0x92, 0xb0, 0x6f, 0xdf, 0xb7, 0x53, 0x45, 0x1e, 0x1f, 0xa5, 0x21, 0xaf, + 0xc0, 0x93, 0x8c, 0x23, 0x49, 0x94, 0x08, 0xde, 0xe4, 0x8d, 0x19, 0x87, 0x97, 0x6d, 0xca, 0xa9, 0xbd, 0x59, 0x2f, + 0x00, 0xe7, 0x09, 0xda, 0x32, 0xc0, 0x58, 0xc0, 0xe0, 0x5c, 0x88, 0x25, 0x4f, 0x11, 0xfc, 0xd2, 0x89, 0x14, 0xc6, + 0x5d, 0x0e, 0xc3, 0x3c, 0x28, 0x7a, 0x97, 0xd4, 0x1f, 0xfd, 0x3e, 0x6a, 0x93, 0xc1, 0x10, 0x54, 0x02, 0xa8, 0xac, + 0x1b, 0x24, 0x06, 0x56, 0xa5, 0x85, 0xc4, 0x25, 0xc4, 0xcb, 0x7c, 0x35, 0xad, 0xa3, 0xe0, 0x7d, 0x3d, 0x21, 0x84, + 0x13, 0x8c, 0x0f, 0x71, 0x03, 0x04, 0x0c, 0x56, 0x71, 0x81, 0x41, 0xf2, 0x5c, 0xa2, 0xfb, 0xe3, 0xf9, 0x8e, 0x01, + 0xae, 0x9c, 0xf7, 0x54, 0xbb, 0x7a, 0x60, 0x2f, 0x57, 0xe9, 0x92, 0x11, 0xc2, 0x8a, 0xff, 0x8b, 0xc8, 0xfb, 0x76, + 0x98, 0x80, 0xda, 0x46, 0xfe, 0x18, 0x24, 0xe6, 0x32, 0x51, 0x04, 0xf1, 0x28, 0x2b, 0x58, 0x92, 0x06, 0x9b, 0x51, + 0x92, 0x82, 0x46, 0x13, 0x63, 0xc8, 0x54, 0x68, 0x87, 0xa4, 0xd1, 0x6c, 0x4c, 0xf6, 0x31, 0xe4, 0x35, 0x5c, 0x2c, + 0x16, 0x78, 0xdf, 0xcf, 0x42, 0x75, 0xb0, 0x2d, 0xcd, 0x21, 0xe0, 0x24, 0xc1, 0x9e, 0xba, 0x22, 0x25, 0x61, 0x36, + 0xfa, 0x14, 0x72, 0x6e, 0x40, 0xc7, 0x49, 0x63, 0xa8, 0x3e, 0x30, 0x09, 0xaf, 0x22, 0x74, 0x52, 0x56, 0x08, 0x0b, + 0xb8, 0x6f, 0x64, 0x34, 0x5a, 0x49, 0x83, 0xc0, 0xdb, 0x0c, 0x5b, 0x81, 0x4d, 0x68, 0xf8, 0xcb, 0xcc, 0xc3, 0xb4, + 0x9a, 0x95, 0x60, 0xce, 0x37, 0x50, 0x89, 0xf1, 0x64, 0x79, 0xc5, 0x37, 0x2e, 0x56, 0x62, 0x32, 0x5b, 0xce, 0x27, + 0x6b, 0x49, 0x35, 0x97, 0x7b, 0x6b, 0x96, 0xb1, 0x25, 0xec, 0x1f, 0x06, 0x86, 0xd2, 0x81, 0x1d, 0x4d, 0x35, 0x6d, + 0x12, 0x60, 0x32, 0x9d, 0x73, 0x3e, 0xbc, 0x44, 0x34, 0x59, 0x9d, 0xba, 0x93, 0xa9, 0x6a, 0x07, 0xd7, 0xe4, 0x4c, + 0x4e, 0x8f, 0xd4, 0x53, 0xad, 0x7b, 0xc9, 0x47, 0xdb, 0x61, 0x35, 0xda, 0xfa, 0x01, 0xb8, 0x75, 0x0a, 0x3b, 0x7d, + 0x37, 0xac, 0x46, 0x3b, 0x5f, 0xc3, 0xee, 0x92, 0x42, 0xa0, 0xfa, 0xb3, 0xac, 0xc9, 0x5c, 0xbc, 0x2e, 0x1e, 0xbc, + 0x82, 0x3d, 0xf7, 0x07, 0xfa, 0x57, 0xc9, 0x9e, 0xfb, 0x36, 0x93, 0xeb, 0x9f, 0x69, 0xd7, 0x68, 0xcc, 0x74, 0xbc, + 0x76, 0x05, 0x56, 0x68, 0x80, 0xfc, 0x82, 0x1d, 0xed, 0x6d, 0x0e, 0x02, 0x01, 0xba, 0x97, 0xe0, 0x28, 0x0a, 0x88, + 0x9a, 0x56, 0x95, 0x47, 0xa7, 0x7b, 0x7f, 0x8f, 0x6f, 0x94, 0x80, 0x4d, 0x9e, 0x5a, 0xf7, 0x96, 0xb1, 0x7f, 0x38, + 0x40, 0x08, 0xbd, 0x9c, 0x7e, 0xa3, 0x2d, 0xab, 0x47, 0x3b, 0x96, 0xfb, 0x86, 0x51, 0x4f, 0xc1, 0x18, 0x86, 0x2e, + 0xac, 0x62, 0x24, 0xcf, 0x80, 0xac, 0xf1, 0x1b, 0x44, 0x17, 0xb0, 0xe8, 0xf5, 0x5e, 0x1f, 0xd1, 0x20, 0x02, 0x2a, + 0xbd, 0xe6, 0x2f, 0x45, 0x3e, 0x57, 0x85, 0xe8, 0xbd, 0xb7, 0x76, 0xde, 0xcc, 0x48, 0x96, 0x49, 0x23, 0xd5, 0x6e, + 0x65, 0xb1, 0xae, 0xbc, 0xd9, 0x09, 0xe9, 0x62, 0x8e, 0xa1, 0x32, 0x78, 0x1c, 0x80, 0xd2, 0xf3, 0x6f, 0xa1, 0x57, + 0x32, 0x64, 0x9a, 0x25, 0x9a, 0xd9, 0x5d, 0xe3, 0x4f, 0x56, 0xa9, 0x17, 0x23, 0x62, 0x36, 0xb0, 0x85, 0xb8, 0x2d, + 0x2a, 0xdd, 0x16, 0x85, 0xb2, 0x45, 0x91, 0x3e, 0xd4, 0xce, 0x74, 0x67, 0x16, 0x3e, 0xab, 0x4c, 0xfb, 0xde, 0x66, + 0x66, 0x6c, 0x80, 0xb6, 0x8b, 0xf0, 0x0d, 0x74, 0xa0, 0x42, 0xc8, 0x7f, 0x40, 0x44, 0x24, 0x02, 0x76, 0x39, 0x75, + 0x27, 0x36, 0x1d, 0x92, 0x79, 0x88, 0x59, 0xa1, 0x46, 0x79, 0xc9, 0x93, 0xa3, 0x01, 0xa9, 0x08, 0x75, 0xbb, 0xdf, + 0x3f, 0x5f, 0xba, 0xa0, 0xf6, 0x6b, 0x8a, 0x1d, 0xa3, 0x9b, 0x02, 0xce, 0x05, 0x8f, 0xf2, 0x9e, 0x7b, 0xe7, 0x80, + 0xe6, 0xd8, 0x9e, 0x22, 0x6b, 0xc0, 0xe9, 0x6d, 0x17, 0x02, 0x6c, 0x9f, 0x35, 0x5b, 0xfb, 0x93, 0xd5, 0x55, 0x34, + 0xf5, 0x4a, 0x3e, 0xd3, 0x5d, 0x94, 0xb8, 0x5d, 0x14, 0xcb, 0x2e, 0xda, 0x34, 0x10, 0xec, 0xb8, 0xf2, 0x03, 0xe0, + 0x0d, 0x8d, 0xfa, 0xfd, 0xb2, 0xd5, 0xb3, 0x27, 0x5f, 0x3b, 0xee, 0xd9, 0xcc, 0x67, 0xa5, 0xe9, 0xd9, 0x5f, 0x53, + 0xb7, 0x67, 0xe5, 0x64, 0x2f, 0x3a, 0x27, 0xfb, 0x74, 0x36, 0x0f, 0x04, 0x97, 0x3b, 0xf7, 0x79, 0x3e, 0xd5, 0xd3, + 0xae, 0xf2, 0x83, 0xd6, 0x10, 0x99, 0x2f, 0x7c, 0xaa, 0xba, 0xd7, 0x15, 0x2c, 0x60, 0x09, 0xee, 0xd6, 0x4b, 0xf3, + 0x5f, 0xb1, 0xfb, 0x7b, 0x41, 0x2f, 0xcd, 0x7f, 0xa3, 0x3f, 0x29, 0x80, 0x03, 0xd0, 0x98, 0xda, 0x2d, 0xf0, 0x10, + 0x43, 0x05, 0x85, 0xbb, 0x59, 0x39, 0xf7, 0x6a, 0x80, 0xc3, 0x24, 0x7d, 0x43, 0xab, 0x57, 0x5a, 0xec, 0x7a, 0x99, + 0xec, 0x15, 0xe0, 0xa1, 0x0a, 0x79, 0x78, 0x38, 0x44, 0x1d, 0xc3, 0x0e, 0xea, 0x08, 0x18, 0xf6, 0x10, 0x1a, 0x5b, + 0xe0, 0xf9, 0xf8, 0x29, 0xe3, 0x7b, 0x01, 0x6a, 0x23, 0x84, 0xc7, 0xab, 0x45, 0x19, 0x62, 0xcb, 0xde, 0x22, 0x95, + 0xd4, 0xcf, 0x02, 0x51, 0x46, 0xab, 0x80, 0xb6, 0xda, 0x63, 0x96, 0xc6, 0x1b, 0x08, 0x15, 0x4b, 0x7d, 0x0c, 0xa1, + 0x81, 0xc3, 0xef, 0x70, 0x00, 0x09, 0xbe, 0xe4, 0x9a, 0x6c, 0xee, 0x6d, 0x7e, 0x4f, 0xfb, 0xfc, 0xe1, 0x70, 0x7e, + 0x89, 0xa0, 0x74, 0x29, 0x7c, 0xa4, 0x12, 0x51, 0x3d, 0xc5, 0x4d, 0x09, 0xd9, 0x2c, 0x59, 0xe9, 0x07, 0xbf, 0xaa, + 0x5f, 0x00, 0x20, 0x0b, 0x81, 0x36, 0x91, 0xd9, 0x9f, 0xce, 0x54, 0x74, 0x01, 0x70, 0x88, 0x3f, 0x7e, 0x82, 0xe8, + 0x1b, 0x5a, 0xa6, 0xe5, 0xe3, 0x84, 0x87, 0xa0, 0xb5, 0x25, 0x9d, 0x44, 0xac, 0x14, 0xd8, 0x10, 0x09, 0xdf, 0xef, + 0x9f, 0xc7, 0x92, 0x0e, 0x34, 0x6a, 0x75, 0x6f, 0xdc, 0xea, 0x5e, 0xf9, 0xba, 0xee, 0xe4, 0xc6, 0x07, 0x45, 0xfb, + 0x6c, 0xde, 0xa8, 0x7c, 0xdf, 0xd6, 0x39, 0xbb, 0xd3, 0xbd, 0x23, 0xe7, 0xc4, 0xb7, 0xf7, 0x10, 0x8a, 0x1e, 0x9a, + 0x22, 0xcb, 0x92, 0x30, 0xa0, 0xb5, 0x76, 0xed, 0x59, 0x46, 0x07, 0xaf, 0x7d, 0x43, 0x88, 0xc8, 0x53, 0x7c, 0x12, + 0x72, 0x8b, 0xe3, 0x83, 0x02, 0xfd, 0x33, 0xe3, 0xcf, 0x9c, 0xf8, 0x61, 0xab, 0x5f, 0x00, 0xe7, 0xa6, 0x7b, 0xef, + 0x4e, 0xcc, 0x7a, 0x0c, 0xa5, 0x6c, 0xfc, 0xdf, 0xef, 0x13, 0x59, 0xa0, 0xd3, 0x11, 0x0d, 0x03, 0xc1, 0x5d, 0x54, + 0xff, 0xf7, 0x8a, 0xd7, 0x3d, 0x6b, 0x75, 0xbe, 0xfc, 0xd4, 0xe9, 0x49, 0xaf, 0x5e, 0xc6, 0x3d, 0xa0, 0x42, 0x07, + 0x08, 0xe7, 0x75, 0xbf, 0x61, 0xbb, 0x6f, 0x7e, 0x79, 0x77, 0xf4, 0x32, 0xb0, 0x49, 0x91, 0xd8, 0x56, 0xf2, 0x59, + 0x0f, 0x14, 0x7e, 0x3d, 0xd6, 0xab, 0x8b, 0x75, 0x8f, 0xf5, 0x50, 0x0b, 0x88, 0x1e, 0x16, 0xa0, 0xfe, 0xeb, 0xd9, + 0xa7, 0xa1, 0x70, 0x90, 0x8d, 0x53, 0x05, 0x8a, 0x2c, 0xf8, 0x0b, 0x31, 0x5a, 0x17, 0x04, 0x88, 0x6c, 0x09, 0x69, + 0xd5, 0xc9, 0xec, 0x71, 0xa9, 0x25, 0x19, 0x7c, 0x13, 0x90, 0xd9, 0x81, 0x95, 0x13, 0x94, 0x8e, 0x5b, 0x03, 0xae, + 0x6c, 0xf1, 0x68, 0xb7, 0x3f, 0x0d, 0xb2, 0xb3, 0xe6, 0xa4, 0xd1, 0x3e, 0xec, 0xd3, 0x3c, 0x40, 0x20, 0x92, 0xa9, + 0x08, 0x72, 0xcd, 0xbd, 0x25, 0x7d, 0x74, 0x38, 0xe7, 0x85, 0xfc, 0x73, 0x2a, 0x75, 0x88, 0x43, 0x89, 0x35, 0x10, + 0xa8, 0x3c, 0x43, 0x95, 0xc3, 0x06, 0x39, 0xfe, 0xd9, 0x91, 0xcc, 0x24, 0x26, 0x8b, 0xdc, 0xad, 0x99, 0x0a, 0x3f, + 0x10, 0x7c, 0xcc, 0x72, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x02, 0x7f, 0x4c, 0xe1, 0x57, 0x3c, + 0x85, 0x9d, 0x76, 0xbf, 0x2e, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, + 0x3f, 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x65, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x06, + 0x15, 0x5b, 0x17, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xaa, 0x51, 0x5a, 0xfd, 0xa8, + 0x7f, 0x02, 0xf3, 0x36, 0x15, 0xa3, 0x5a, 0xc5, 0xe4, 0x37, 0xfa, 0xfd, 0x62, 0xd0, 0xfa, 0x90, 0xc1, 0x47, 0xaf, + 0x4d, 0x83, 0x3f, 0x3a, 0x0d, 0x76, 0x98, 0x68, 0x04, 0x40, 0x32, 0xa7, 0x96, 0x3c, 0x14, 0xfd, 0x11, 0xe4, 0x58, + 0xa3, 0xca, 0x29, 0x18, 0xac, 0xff, 0x78, 0xb4, 0x03, 0x53, 0x2f, 0x8e, 0xb6, 0x64, 0x07, 0xad, 0x7c, 0x03, 0xdc, + 0xaf, 0x91, 0x2d, 0x66, 0x39, 0x40, 0xb3, 0xd7, 0x88, 0x8c, 0x4f, 0x5e, 0x00, 0x63, 0xb6, 0xce, 0xc2, 0x48, 0xc4, + 0xc1, 0x58, 0x35, 0x66, 0xcc, 0xc0, 0xc0, 0x05, 0xba, 0x96, 0x49, 0x49, 0x1a, 0xd2, 0xc1, 0x80, 0x95, 0xb2, 0x85, + 0x03, 0x5e, 0x34, 0xc7, 0xed, 0x78, 0xd3, 0xa2, 0xf1, 0xc0, 0x76, 0xb1, 0xfd, 0xfd, 0xf7, 0xc5, 0xf6, 0x3a, 0xdc, + 0x92, 0x5e, 0x21, 0x67, 0x09, 0xfd, 0xfc, 0x51, 0xf6, 0x59, 0xc3, 0xc9, 0xa9, 0xd0, 0x0c, 0x2d, 0x45, 0x42, 0x29, + 0xde, 0xe9, 0x49, 0x81, 0xb1, 0x8c, 0x85, 0xbf, 0x07, 0xce, 0xe9, 0x42, 0x11, 0xb9, 0x03, 0xc7, 0xf1, 0x0d, 0x54, + 0x30, 0x6a, 0x38, 0x78, 0x19, 0xc3, 0xb6, 0x28, 0x66, 0x21, 0xe1, 0x14, 0xc2, 0xc5, 0x2a, 0xeb, 0xf7, 0xe5, 0x2f, + 0xea, 0xa2, 0x8b, 0x4c, 0xd6, 0x7d, 0x12, 0x8e, 0xcc, 0x58, 0x4e, 0xbd, 0x90, 0x3c, 0xef, 0x79, 0x32, 0x4d, 0x9e, + 0xe5, 0x41, 0x04, 0x90, 0xcf, 0xe1, 0x7d, 0x98, 0x66, 0x60, 0x95, 0x26, 0xe5, 0x47, 0x28, 0x7d, 0xf1, 0x79, 0xe5, + 0x07, 0x3a, 0x7b, 0x6e, 0x92, 0xe1, 0xcd, 0xaa, 0xf5, 0x26, 0xb5, 0xae, 0x8b, 0x07, 0xfc, 0x8b, 0x33, 0xd8, 0x38, + 0xd7, 0x99, 0xe0, 0xc0, 0x8b, 0xa4, 0xd6, 0x6b, 0xc6, 0x5f, 0x64, 0xb8, 0x2e, 0x55, 0x1b, 0x7d, 0x14, 0xa2, 0x73, + 0xc8, 0x54, 0x80, 0x42, 0x91, 0xf6, 0x0f, 0x4a, 0xad, 0x4c, 0x2a, 0x6d, 0x24, 0x80, 0xee, 0x61, 0xd2, 0x60, 0x8b, + 0xa1, 0x8c, 0xa5, 0x49, 0x94, 0x3b, 0x0d, 0xe2, 0xca, 0xfe, 0x5c, 0x49, 0x1c, 0x5a, 0x16, 0xc9, 0xbf, 0x77, 0x3d, + 0x7d, 0x85, 0xd4, 0x9d, 0x2c, 0x90, 0x19, 0xe3, 0x65, 0x1e, 0x7f, 0x02, 0xc2, 0x6c, 0xd0, 0x46, 0x45, 0x21, 0x84, + 0x6c, 0x10, 0x83, 0xc6, 0xcb, 0x3c, 0xfe, 0x5e, 0xd1, 0x78, 0xc8, 0x47, 0x91, 0xaf, 0xfe, 0x2a, 0xf5, 0x5f, 0xa1, + 0xcf, 0x4c, 0xf0, 0x08, 0xd5, 0x44, 0xff, 0xee, 0xf9, 0xec, 0x1e, 0xd4, 0x86, 0x51, 0x98, 0x99, 0xf2, 0x2b, 0xdf, + 0x14, 0x67, 0xaf, 0xbf, 0xa2, 0xab, 0x6c, 0xeb, 0x7e, 0xf4, 0xf1, 0x88, 0xc0, 0xda, 0x18, 0x5d, 0x71, 0x63, 0x00, + 0x39, 0x4c, 0xde, 0xaf, 0x28, 0x2d, 0x87, 0x34, 0x08, 0x1d, 0x34, 0x04, 0xbd, 0x92, 0xe8, 0x03, 0x89, 0x45, 0x8c, + 0xe1, 0x85, 0x78, 0x46, 0x6a, 0x32, 0xd1, 0x10, 0xaf, 0x88, 0xfd, 0x10, 0x2d, 0x39, 0x35, 0xd1, 0x8d, 0x30, 0xc5, + 0x40, 0x62, 0x67, 0x90, 0x9c, 0x24, 0xb5, 0xf2, 0x8b, 0x67, 0x92, 0xb0, 0xc4, 0xce, 0x43, 0x0c, 0x26, 0xb5, 0x74, + 0xa7, 0x37, 0x55, 0x7a, 0x77, 0xa4, 0xe5, 0xa0, 0x7d, 0x00, 0x76, 0x29, 0xe9, 0xfd, 0x93, 0x42, 0x11, 0x1f, 0xc2, + 0x38, 0x86, 0xf0, 0x2d, 0xa2, 0xba, 0x02, 0xe7, 0x5a, 0x81, 0xc6, 0x6a, 0xe0, 0xa1, 0x99, 0x55, 0xf3, 0x21, 0xa7, + 0x9f, 0x4a, 0xcb, 0x1f, 0x23, 0x1a, 0x1b, 0xad, 0x9b, 0xc3, 0x61, 0x4f, 0xab, 0x5e, 0x3a, 0x07, 0x5d, 0x36, 0x93, + 0x98, 0xb8, 0x81, 0x74, 0xfd, 0xe8, 0x37, 0x13, 0xf6, 0x22, 0x2a, 0xe4, 0x52, 0x08, 0x0a, 0x5a, 0x1d, 0x08, 0x1c, + 0x0a, 0x6f, 0x51, 0xe6, 0x8b, 0x98, 0x36, 0x10, 0x06, 0x9f, 0x1f, 0xc8, 0xcf, 0x37, 0x05, 0xa9, 0xd8, 0xb1, 0xae, + 0xfd, 0xfe, 0xa6, 0xf4, 0x00, 0x4f, 0xce, 0x24, 0x79, 0xda, 0x0c, 0x61, 0x45, 0x00, 0x8d, 0x59, 0x4d, 0x16, 0x27, + 0x5c, 0x99, 0xc3, 0x8f, 0x95, 0x57, 0xb2, 0x94, 0xa9, 0xf3, 0x54, 0x2f, 0x80, 0xa8, 0xe3, 0x0d, 0x5a, 0x91, 0xfa, + 0x15, 0x3a, 0x7b, 0xcd, 0x4a, 0xc8, 0x78, 0x78, 0xce, 0x79, 0x3a, 0x7a, 0x60, 0x09, 0x8f, 0xf0, 0xaf, 0x64, 0xa2, + 0x0f, 0xbf, 0x07, 0x0e, 0x37, 0xe3, 0x84, 0x47, 0x6e, 0xb3, 0xf7, 0x55, 0xb8, 0x82, 0x9b, 0x69, 0x01, 0x48, 0x6e, + 0x41, 0xd2, 0x04, 0x94, 0x90, 0xc8, 0x84, 0xcc, 0x9a, 0x92, 0x9f, 0x5b, 0xda, 0x06, 0x6b, 0x98, 0x74, 0x1e, 0xf0, + 0xa2, 0xd5, 0x47, 0xab, 0x89, 0x76, 0x99, 0xe5, 0xf3, 0x21, 0xce, 0x50, 0xcd, 0x71, 0x77, 0x06, 0x3f, 0x07, 0xbc, + 0x62, 0x55, 0x93, 0x8e, 0x76, 0x03, 0x2e, 0x3c, 0xb9, 0xce, 0xd3, 0xd1, 0x16, 0x7f, 0xc9, 0xfd, 0x01, 0xa0, 0x83, + 0xa9, 0x4b, 0xe0, 0x4f, 0xd5, 0x56, 0x53, 0xa9, 0x5f, 0x5a, 0xfb, 0x75, 0xdd, 0x59, 0xad, 0xdc, 0xb3, 0x2e, 0x43, + 0x7b, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, + 0x82, 0x7b, 0xc9, 0x5f, 0xec, 0x11, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, + 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xb1, 0x34, 0x26, 0x45, 0x05, 0xe9, 0x9c, 0x0e, 0x37, 0xaf, 0x8e, 0xf3, 0x84, 0x65, 0x7c, 0xdc, 0x3e, 0x53, 0x20, 0xc4, 0x16, 0xcf, 0x90, - 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x3c, 0xd6, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, - 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1b, 0xfe, 0x25, 0x43, 0x75, 0x77, 0x08, - 0x4c, 0x6c, 0xd9, 0x91, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x5b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, - 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x15, 0x5e, 0x2e, 0x5b, 0x79, 0x3c, 0x26, 0xd6, 0x5d, 0xd8, 0xd1, - 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0x54, 0x66, 0x17, 0x12, 0x83, 0x9c, 0xa5, 0xfa, - 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xf9, 0x69, 0x9f, 0x8a, 0xd1, 0x46, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, - 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x4a, 0x1f, 0xc7, 0xc7, 0xa3, 0x14, 0x33, - 0xae, 0x4f, 0xc4, 0x8c, 0xeb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xe3, 0xf1, 0x9a, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, - 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4d, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x4d, 0xea, 0x65, 0xe4, - 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x72, 0xda, 0xad, 0x4b, 0x26, - 0xec, 0x2d, 0x25, 0x97, 0x56, 0x79, 0xf9, 0x74, 0xeb, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, + 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x38, 0xd4, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, + 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1a, 0xfe, 0x2e, 0x43, 0x75, 0x77, 0x08, + 0x4c, 0x6c, 0xd9, 0x81, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x1b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, + 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x11, 0x5e, 0x25, 0x5b, 0x79, 0x38, 0x24, 0xd6, 0x5d, 0xd8, 0xd1, + 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0xe4, 0x66, 0x17, 0x12, 0x83, 0x8a, 0xa5, 0xfa, + 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xd5, 0x71, 0x9f, 0x8a, 0xd1, 0x5a, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, + 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x5c, 0x1f, 0xc7, 0x87, 0x83, 0x14, 0x33, + 0x2e, 0x8f, 0xc4, 0x8c, 0xcb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xc3, 0xe1, 0x92, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, + 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4b, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x75, 0xea, 0x65, 0xe4, + 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x2a, 0xda, 0xad, 0x4b, 0x26, + 0xec, 0x2d, 0xa5, 0x92, 0x56, 0x79, 0xf9, 0x74, 0xe3, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, 0x12, 0xb5, 0x32, 0x4c, 0x16, 0xce, 0x4b, 0xa6, 0x9e, 0x0c, 0x78, 0xcc, 0x4a, 0x1e, 0xc9, 0x4e, 0x6f, 0x0c, 0x82, - 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x7c, 0x95, 0x0b, 0x0c, 0xb7, 0xdb, 0xb0, 0xad, - 0xaa, 0xb3, 0xdc, 0xd4, 0x72, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0xb7, 0x10, 0x8c, - 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x03, 0x96, 0xd2, 0xd1, 0x9e, 0x97, - 0xa8, 0x52, 0xf8, 0x9b, 0xe0, 0x87, 0x30, 0x8e, 0x7f, 0x28, 0x76, 0xea, 0x40, 0xbc, 0x2b, 0x76, 0x48, 0xfb, 0x22, + 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x74, 0x95, 0x0b, 0x0c, 0xb7, 0x5b, 0xb3, 0x8d, + 0xaa, 0xb3, 0xdc, 0xd4, 0x2a, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0x37, 0x10, 0x8c, + 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x05, 0x96, 0xd2, 0xd1, 0x8e, 0x97, + 0xa8, 0x52, 0xf8, 0xbb, 0xe0, 0xfb, 0x30, 0x8e, 0xbf, 0x2f, 0xb6, 0xea, 0x40, 0xbc, 0x2d, 0xb6, 0x48, 0xfb, 0x22, 0xff, 0x42, 0x1c, 0xf0, 0x5a, 0xd7, 0x94, 0xd7, 0xd6, 0x9c, 0x06, 0xb6, 0x86, 0x91, 0x92, 0xc2, 0xb9, 0xf9, 0xf3, - 0x78, 0xa4, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x45, 0x09, 0x7e, 0x13, - 0xf2, 0xaf, 0xe3, 0x51, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0x3b, 0x7c, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, + 0x70, 0xa0, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x44, 0x09, 0x8e, 0x5c, + 0xf2, 0xaf, 0xc3, 0x41, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0xdb, 0x7f, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, 0x24, 0xff, 0x6a, 0x9a, 0x79, 0xc3, 0x64, 0xcd, 0x14, 0x8e, 0x43, 0xc3, 0x08, 0x69, 0x40, 0xb7, 0x41, 0x6d, 0x78, - 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0xd7, 0x13, 0x71, 0x49, 0x97, 0x24, 0xf5, 0x54, 0x42, - 0x49, 0x08, 0x76, 0xed, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, - 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xcb, - 0x79, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8b, 0x6d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, - 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xcc, 0xe5, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, - 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0xbf, 0xaa, 0x6c, 0x6c, 0x05, 0xe4, 0x90, 0x64, 0xb2, 0x58, 0x8d, 0xee, - 0xc4, 0xb2, 0x28, 0xc5, 0xcf, 0x58, 0x0f, 0xd7, 0x6c, 0xe1, 0x3e, 0x03, 0x42, 0xfb, 0x89, 0xd2, 0xde, 0x44, 0x9a, - 0xa0, 0x7b, 0xc5, 0xd6, 0x00, 0x32, 0x80, 0xa2, 0xae, 0x76, 0xeb, 0x73, 0x7e, 0x8e, 0xa4, 0x19, 0x0e, 0xa3, 0xdb, - 0xa7, 0xab, 0x60, 0x35, 0xb8, 0x46, 0xad, 0xf4, 0x35, 0x8b, 0x5b, 0x18, 0x54, 0x07, 0xb3, 0x84, 0x83, 0x9a, 0x59, - 0x6b, 0x23, 0x10, 0x4c, 0xf6, 0x50, 0x90, 0x33, 0x57, 0xb0, 0x0f, 0x0a, 0xd6, 0x92, 0xd7, 0xc1, 0xe1, 0xd6, 0xbe, - 0xac, 0x14, 0x57, 0xcf, 0xae, 0x92, 0xd6, 0x85, 0xa5, 0xbc, 0x7a, 0xd6, 0x80, 0xc1, 0xe5, 0x04, 0x9b, 0x2a, 0xf7, - 0x27, 0x5b, 0x00, 0xdd, 0x0a, 0x29, 0xe2, 0x45, 0x29, 0x6c, 0x5b, 0xf9, 0xcc, 0x09, 0x1b, 0x6c, 0xd9, 0x03, 0xdc, - 0x2b, 0x83, 0x92, 0xc1, 0x85, 0x18, 0xb7, 0x9b, 0x7d, 0x80, 0x2b, 0x18, 0x0a, 0x63, 0x1b, 0xfe, 0x3a, 0xf3, 0x22, - 0x25, 0xe0, 0x66, 0x88, 0xf2, 0xb5, 0x85, 0x93, 0x49, 0x4f, 0xae, 0x25, 0x8b, 0x01, 0x0b, 0x1a, 0x7c, 0x47, 0xad, - 0xbf, 0x33, 0xf9, 0x37, 0x9e, 0x1e, 0xfa, 0xc1, 0xe7, 0xcc, 0x5b, 0xfa, 0xec, 0x75, 0x2e, 0xa3, 0x35, 0x49, 0x94, - 0x57, 0x0f, 0x97, 0x20, 0x37, 0x2c, 0x47, 0x0f, 0x6c, 0x09, 0xe2, 0xc4, 0x72, 0x94, 0x50, 0x46, 0x57, 0xb8, 0x57, - 0x99, 0x2d, 0x13, 0x81, 0x14, 0x07, 0x96, 0x52, 0xee, 0x2d, 0x36, 0xc1, 0x12, 0xf7, 0x27, 0x92, 0x0b, 0x28, 0x79, - 0x00, 0xe5, 0x4a, 0x01, 0x01, 0x9f, 0x0e, 0xa0, 0x7c, 0x29, 0x2f, 0xc2, 0x9f, 0x38, 0x51, 0x83, 0xe5, 0xe8, 0xa1, - 0x61, 0x7f, 0xf5, 0x42, 0xcb, 0xfe, 0xb0, 0xd2, 0x9a, 0x86, 0x35, 0x5f, 0xc1, 0xb4, 0x98, 0xb8, 0x7d, 0xb9, 0xb6, - 0xab, 0xe2, 0xb3, 0xb5, 0x3a, 0xbb, 0xa9, 0x21, 0x09, 0xfb, 0x8a, 0xac, 0x02, 0x1c, 0xac, 0x8a, 0xb8, 0x67, 0x59, - 0x1e, 0xc2, 0xe8, 0xcf, 0x6d, 0x5a, 0x0a, 0x0b, 0x55, 0xd2, 0x3f, 0x34, 0xa5, 0x40, 0x2a, 0x13, 0x9d, 0x68, 0x21, - 0xb8, 0x02, 0x83, 0xc0, 0xbd, 0xc8, 0x6b, 0x00, 0x8c, 0x01, 0x97, 0x02, 0x65, 0xd9, 0x96, 0x10, 0x52, 0xdd, 0xcf, - 0x40, 0x6d, 0x27, 0xee, 0xd3, 0x88, 0xac, 0x85, 0xe8, 0xab, 0x60, 0xcc, 0x9c, 0xd7, 0xd2, 0x2d, 0x36, 0x5d, 0x6f, - 0xd7, 0xb7, 0xe8, 0x5c, 0xda, 0x72, 0xf3, 0x13, 0xb6, 0x58, 0x2b, 0x50, 0x36, 0x21, 0x69, 0xbb, 0xe2, 0x15, 0xca, - 0x26, 0xb4, 0xb4, 0x0f, 0xd4, 0xa3, 0x42, 0x75, 0xb2, 0xf5, 0x52, 0x3e, 0xb5, 0x08, 0xab, 0xc5, 0x55, 0xee, 0x07, - 0xa0, 0x9b, 0x4a, 0xab, 0x17, 0x75, 0x8d, 0xa6, 0x50, 0xab, 0x85, 0xe3, 0x46, 0x3b, 0x9b, 0x2e, 0xd3, 0x15, 0xe2, - 0xac, 0x4a, 0x3b, 0xf4, 0x0f, 0x99, 0x76, 0xbd, 0xec, 0xe8, 0x37, 0xe3, 0xea, 0x02, 0x17, 0x62, 0x03, 0x3e, 0xe7, - 0xfe, 0xf2, 0x7a, 0xcf, 0xe2, 0x1e, 0x44, 0x3c, 0x03, 0x7b, 0x52, 0xfb, 0x43, 0xf5, 0xa9, 0x2b, 0x18, 0xb2, 0x30, - 0x4a, 0xfd, 0x45, 0xca, 0x7b, 0x4f, 0x70, 0xdc, 0x3f, 0x57, 0x3d, 0xf6, 0xd7, 0x8c, 0x1f, 0xea, 0x62, 0x1b, 0x25, - 0x14, 0xd5, 0xd0, 0x5b, 0x17, 0xdb, 0x4a, 0xc4, 0xc5, 0x43, 0xde, 0x63, 0x98, 0x0c, 0x63, 0x21, 0x53, 0xe1, 0x4f, - 0x99, 0x0a, 0x1e, 0x21, 0x94, 0xb8, 0xdd, 0xf4, 0x48, 0xbb, 0x09, 0x71, 0x4a, 0xb5, 0x28, 0x65, 0x32, 0xfe, 0xad, - 0x9f, 0x40, 0x79, 0x4e, 0xd1, 0x32, 0xfd, 0xa4, 0x70, 0x99, 0xbe, 0xdd, 0x9c, 0x96, 0x9e, 0x89, 0x50, 0x67, 0x2e, - 0xb6, 0xb5, 0x4e, 0xc7, 0xd8, 0x29, 0x9d, 0xda, 0xb0, 0x77, 0xb9, 0xe2, 0xb2, 0xa2, 0xf0, 0x6f, 0x24, 0xb2, 0xea, - 0x19, 0x71, 0xfc, 0x9f, 0x59, 0xfb, 0x0c, 0xab, 0xc0, 0x2f, 0x03, 0x79, 0xbf, 0x00, 0xf8, 0xb8, 0xae, 0xcb, 0xf4, - 0x6e, 0x0b, 0xb4, 0x21, 0x34, 0xfc, 0x3d, 0x1f, 0x19, 0x30, 0xdd, 0x47, 0x38, 0x43, 0x7a, 0xa8, 0x73, 0x4e, 0x67, - 0x65, 0x3a, 0xe7, 0x2a, 0xac, 0x25, 0x38, 0xc8, 0x49, 0x53, 0xc9, 0x75, 0x09, 0x6a, 0x26, 0x70, 0xfb, 0xd0, 0x1e, - 0x11, 0x42, 0x6d, 0xca, 0x6a, 0x7a, 0x09, 0x35, 0xef, 0xe4, 0xb4, 0xa3, 0x49, 0x09, 0xae, 0x1a, 0x3a, 0x2b, 0xd7, - 0x7f, 0x1d, 0x8f, 0xbd, 0xbb, 0xac, 0x88, 0xfe, 0xe8, 0xa1, 0xbf, 0xe3, 0xee, 0x36, 0xfd, 0x02, 0xd1, 0x32, 0xd6, - 0xdf, 0x90, 0x01, 0x1d, 0x4f, 0x86, 0x77, 0xc5, 0xae, 0xc7, 0xde, 0xe5, 0x78, 0x81, 0x55, 0xd7, 0x8f, 0x3f, 0x40, - 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, 0x89, 0xb6, 0x85, 0x0f, 0x61, 0xa1, 0xef, 0x72, 0xd8, 0x84, 0xa1, - 0x79, 0xd4, 0x3d, 0x4a, 0xda, 0x85, 0xbe, 0xf4, 0xb5, 0xec, 0x2b, 0xdf, 0xb9, 0x02, 0x58, 0xd9, 0x67, 0x36, 0xdc, - 0x93, 0xfe, 0x94, 0xea, 0xc3, 0xf6, 0xb7, 0x64, 0x01, 0x85, 0x16, 0xd6, 0x53, 0x39, 0x3b, 0x37, 0x25, 0x4f, 0xb3, - 0xe9, 0x61, 0x03, 0x7b, 0xd4, 0x3d, 0x7a, 0x4d, 0x05, 0x97, 0xd7, 0x66, 0xf4, 0xfe, 0x61, 0x28, 0x54, 0x47, 0x9d, - 0x3b, 0xc8, 0xa6, 0xb4, 0x2e, 0x39, 0xbf, 0x59, 0xb9, 0xa3, 0x30, 0xbf, 0x0f, 0xc1, 0x33, 0xac, 0x7b, 0x77, 0x71, - 0xde, 0xfb, 0xb3, 0x35, 0x47, 0xfe, 0x9a, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0x0e, 0xbb, - 0xa0, 0x82, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, - 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xbb, 0xc0, 0xd0, 0xb6, 0x4d, 0x89, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x39, 0x51, 0xa1, - 0x59, 0xa4, 0xad, 0x92, 0xf1, 0xef, 0x44, 0x9b, 0x29, 0xd9, 0x63, 0x6b, 0xe0, 0xbd, 0x04, 0xe5, 0x64, 0x98, 0x62, - 0xf8, 0x8e, 0xaf, 0x77, 0x1e, 0x73, 0xcf, 0x39, 0x65, 0x9b, 0x94, 0x1d, 0xc1, 0x72, 0x22, 0x1b, 0xdf, 0x52, 0xbc, - 0xe1, 0xfb, 0xbb, 0x4a, 0x94, 0x00, 0x7a, 0x59, 0xf0, 0xe7, 0xd2, 0xe6, 0x0a, 0xdd, 0xee, 0xde, 0x51, 0x0a, 0xbf, - 0xe4, 0xe5, 0xf1, 0xb8, 0x4b, 0xbd, 0x10, 0x3a, 0x5f, 0xc4, 0xef, 0xc0, 0x1c, 0xc6, 0x10, 0x9b, 0x11, 0x20, 0xcc, - 0xf1, 0x01, 0x75, 0xb0, 0x7e, 0x04, 0xa0, 0x71, 0x02, 0x05, 0x18, 0x7d, 0xb5, 0x2d, 0xe8, 0x5b, 0x5e, 0x5c, 0x44, - 0x88, 0x1a, 0x05, 0x98, 0x28, 0x69, 0x16, 0xc3, 0x70, 0xa0, 0xf3, 0xfb, 0xf6, 0xae, 0x2e, 0x05, 0x0e, 0xbd, 0x63, - 0x19, 0xfe, 0xdb, 0xff, 0x58, 0x5b, 0x5a, 0x55, 0xb6, 0x5b, 0xe3, 0x34, 0xf3, 0xbf, 0xdd, 0x16, 0xfa, 0xfe, 0x4b, - 0xa1, 0x78, 0xde, 0xf1, 0xba, 0xfd, 0x05, 0xa2, 0xf7, 0x75, 0x2b, 0x57, 0xa5, 0x76, 0xc3, 0x4c, 0xf9, 0x43, 0x9a, - 0xc7, 0xc5, 0xc3, 0x28, 0x6e, 0x1d, 0x79, 0x93, 0xf4, 0x92, 0xf3, 0x2f, 0xe0, 0x6c, 0xfd, 0x05, 0xc8, 0x78, 0x5f, - 0x0a, 0xe3, 0x88, 0x49, 0x1c, 0x7c, 0x07, 0x31, 0x8a, 0xb6, 0x25, 0x6c, 0xc8, 0xed, 0xd3, 0x12, 0x34, 0x33, 0xfd, - 0x3e, 0x4a, 0x94, 0xd6, 0x7c, 0xff, 0x8b, 0x9c, 0xef, 0x2f, 0x85, 0xbc, 0x59, 0xc9, 0x0f, 0x9f, 0xac, 0x30, 0xf0, - 0x3d, 0x4e, 0xbf, 0x88, 0x1e, 0x5b, 0x95, 0x3e, 0x7c, 0x57, 0x5a, 0xfa, 0xac, 0xa2, 0xfe, 0x8e, 0x8a, 0x9a, 0x97, - 0x62, 0x44, 0xc4, 0x83, 0xa0, 0x9d, 0x6d, 0x97, 0xda, 0xb5, 0x04, 0xed, 0x82, 0x4d, 0x61, 0xff, 0x7a, 0x6c, 0xc8, - 0xab, 0x7e, 0xff, 0xe7, 0xca, 0x6b, 0xf1, 0xba, 0xeb, 0xd0, 0x94, 0x9f, 0x0a, 0x0f, 0x21, 0x80, 0xb5, 0x0c, 0x94, - 0xf1, 0x1c, 0x60, 0xd2, 0x45, 0x5e, 0xa3, 0x6c, 0x3a, 0x11, 0xf8, 0x98, 0x65, 0x37, 0x4e, 0x32, 0x0d, 0x30, 0xa3, - 0x9a, 0x62, 0xcc, 0x8a, 0x78, 0xb8, 0xf8, 0x88, 0x75, 0xd3, 0xd3, 0x2a, 0xb4, 0x7c, 0x0d, 0xc1, 0xba, 0xc8, 0x32, - 0x8e, 0x62, 0x26, 0x00, 0xd8, 0x7c, 0x04, 0xf9, 0x8a, 0xae, 0x0e, 0x49, 0x2b, 0x55, 0xde, 0xaf, 0x33, 0x22, 0xa3, - 0x49, 0x88, 0xe6, 0xb7, 0xf0, 0xc0, 0xbe, 0x6d, 0x66, 0x54, 0xa9, 0x67, 0x54, 0xee, 0x33, 0x1c, 0x96, 0xc2, 0x31, - 0xe2, 0xff, 0x2d, 0x55, 0x3d, 0x22, 0xd0, 0xab, 0x32, 0xad, 0xa2, 0x22, 0xcf, 0x45, 0x84, 0x08, 0xd5, 0xd2, 0x39, - 0x1c, 0xfa, 0xb1, 0xdf, 0xc7, 0x81, 0x30, 0x2f, 0xfe, 0xf4, 0x58, 0x57, 0xfe, 0x54, 0xe0, 0x5a, 0x49, 0x81, 0x53, - 0x51, 0x23, 0x44, 0x08, 0xef, 0x4f, 0xe0, 0x59, 0x4d, 0x7d, 0xbf, 0xb1, 0x4c, 0x74, 0xff, 0xc8, 0x80, 0xf2, 0x07, - 0xe4, 0xeb, 0x5c, 0x8a, 0x33, 0x75, 0xf2, 0x98, 0x38, 0xe3, 0x00, 0xc4, 0x7c, 0x5d, 0xa2, 0xd1, 0xd8, 0xff, 0x80, - 0x04, 0x43, 0xf5, 0x83, 0x9d, 0x6e, 0xea, 0xfd, 0x33, 0x93, 0x38, 0x8a, 0x3e, 0x6d, 0x93, 0xa7, 0x92, 0xa5, 0xd1, - 0xc2, 0xd1, 0x7b, 0xc4, 0x30, 0x0e, 0xa7, 0xf3, 0x29, 0xc9, 0x36, 0x26, 0xab, 0x00, 0xd2, 0xc9, 0x4c, 0x1d, 0x53, - 0xea, 0x68, 0x9c, 0xeb, 0x05, 0x55, 0xe8, 0xb1, 0x2e, 0x79, 0x05, 0xd6, 0x93, 0x1f, 0xbd, 0xd2, 0x9f, 0x0a, 0x39, - 0x87, 0x8d, 0x44, 0x50, 0xf8, 0x01, 0xae, 0x06, 0x2b, 0x05, 0x0c, 0xa6, 0xbe, 0x85, 0xaf, 0x89, 0xe7, 0x28, 0x78, - 0x14, 0x76, 0x31, 0xb6, 0xe6, 0xbe, 0xf3, 0x49, 0x41, 0xb9, 0x67, 0xc5, 0x9c, 0xe7, 0xc0, 0xb9, 0x0c, 0x0a, 0x61, - 0x3a, 0x9e, 0xe5, 0xff, 0x4c, 0xf2, 0x7a, 0x62, 0x43, 0x80, 0x0c, 0xfe, 0x9c, 0x38, 0x2d, 0xdd, 0xa1, 0x3b, 0x0f, - 0x3d, 0x8b, 0x38, 0x6c, 0xf4, 0x64, 0x53, 0x16, 0xbb, 0x14, 0xf5, 0x12, 0xe6, 0x07, 0xf2, 0xf3, 0x96, 0xfc, 0x10, - 0xa2, 0x78, 0x1b, 0xfc, 0x9a, 0xb1, 0x58, 0xe0, 0x5f, 0x7f, 0xcb, 0x18, 0x4d, 0xb4, 0xe0, 0x5f, 0x59, 0x83, 0x44, - 0xc5, 0x3f, 0x65, 0x93, 0x1c, 0xb8, 0x4c, 0xd5, 0x87, 0xcf, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x39, 0xe8, - 0xd4, 0xe7, 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x96, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4b, 0xa9, 0x1a, 0xbf, - 0x65, 0x14, 0xbf, 0x93, 0xfb, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xf9, 0x7b, 0xc3, 0x99, 0x5d, 0xf6, 0xab, 0xb7, - 0x89, 0xcc, 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x35, 0x13, 0x7f, 0xae, 0x0c, 0xa7, 0xc4, 0xe5, 0xa5, 0x87, 0x2b, 0x36, - 0xad, 0x5e, 0xd2, 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0xa9, 0xf2, 0x00, 0x82, - 0x99, 0xd4, 0x04, 0x80, 0xb4, 0x10, 0x95, 0x42, 0xe4, 0x2f, 0x71, 0x56, 0x5f, 0xf2, 0xde, 0x36, 0x8f, 0x89, 0xb4, - 0xba, 0xd7, 0xef, 0xa7, 0x17, 0x69, 0x4e, 0x41, 0x0d, 0xa7, 0x59, 0xa7, 0x3f, 0x64, 0x41, 0x9d, 0xc8, 0x55, 0xfa, - 0x77, 0x37, 0xc8, 0xcb, 0xf8, 0xbe, 0xee, 0x7a, 0xfe, 0x44, 0xfd, 0xbd, 0xb7, 0xfe, 0xb6, 0x40, 0x70, 0x27, 0xa7, - 0x7e, 0xb2, 0x2a, 0xe5, 0x89, 0x71, 0x69, 0xef, 0xf9, 0x4d, 0x5d, 0x14, 0x59, 0x9d, 0x6e, 0x3e, 0x48, 0x3d, 0x8d, - 0xee, 0x8b, 0x03, 0x18, 0x83, 0xf7, 0x00, 0x78, 0xa6, 0x43, 0x03, 0xa4, 0xef, 0x19, 0x79, 0xb8, 0xcf, 0x2d, 0xf9, - 0x49, 0x65, 0x6d, 0x92, 0xb0, 0xa2, 0xd8, 0x0c, 0x63, 0x84, 0x92, 0x71, 0x1a, 0x3b, 0xbf, 0xdf, 0x57, 0x7f, 0xef, - 0x31, 0x8a, 0x8a, 0x8a, 0x3b, 0x45, 0xa3, 0xb2, 0xaa, 0x47, 0xdb, 0xc1, 0xf1, 0x78, 0x59, 0xd9, 0x38, 0xda, 0x7a, - 0x05, 0x1c, 0xac, 0x50, 0x29, 0x7b, 0x25, 0xc2, 0xf2, 0xc3, 0x95, 0xdf, 0xef, 0xc3, 0xbf, 0x32, 0xd2, 0xc2, 0xf3, - 0xa7, 0xf8, 0x6b, 0x51, 0x17, 0x18, 0x9e, 0x41, 0x6b, 0x34, 0x87, 0x60, 0x82, 0xbf, 0x77, 0xa0, 0x5e, 0x5a, 0x69, - 0x1f, 0x41, 0xb7, 0x02, 0x3d, 0xa8, 0x87, 0x3e, 0x4d, 0xda, 0x17, 0x12, 0x75, 0x7b, 0xab, 0xd3, 0xe8, 0x8f, 0x0a, - 0x2e, 0xa7, 0x30, 0x39, 0xdc, 0xd0, 0xa7, 0x75, 0xb8, 0xfb, 0x04, 0x4f, 0x7f, 0x06, 0xca, 0xad, 0xe3, 0x11, 0xc5, - 0x16, 0x70, 0xf3, 0x58, 0x87, 0x9f, 0x8b, 0x52, 0x46, 0xd4, 0xc7, 0xd3, 0x02, 0xb4, 0x77, 0x01, 0x3a, 0x60, 0x69, - 0x10, 0xaf, 0x90, 0x3c, 0x67, 0x23, 0x80, 0x65, 0x07, 0x96, 0xb3, 0x8c, 0x53, 0x98, 0x67, 0xf9, 0x5c, 0xad, 0xb4, - 0x8b, 0x32, 0xf1, 0x6a, 0x96, 0x81, 0xb3, 0xc0, 0x55, 0xee, 0xb3, 0x4c, 0xab, 0x9e, 0xf2, 0x04, 0x7d, 0x5e, 0xc9, - 0x09, 0xae, 0x04, 0x27, 0x1b, 0x90, 0x5f, 0x80, 0x24, 0x4d, 0x29, 0x6b, 0xca, 0xe7, 0xd7, 0x74, 0x43, 0x46, 0xcf, - 0x79, 0xcf, 0x8b, 0x86, 0xa1, 0x7f, 0xe5, 0x95, 0x10, 0xbe, 0x89, 0xdb, 0x36, 0x4a, 0x61, 0x7f, 0x11, 0x58, 0x7c, - 0xc2, 0x7e, 0xf4, 0x96, 0xfe, 0x74, 0x1c, 0x84, 0x43, 0xe4, 0x86, 0x8a, 0x39, 0xb0, 0xa7, 0x01, 0x8b, 0x4d, 0x7c, - 0xb3, 0x9d, 0xc4, 0x83, 0x81, 0xaf, 0x33, 0x16, 0xb3, 0x18, 0x68, 0x90, 0xe3, 0xc1, 0xf5, 0x5c, 0x9f, 0x10, 0xfa, - 0x61, 0x44, 0xe5, 0xa8, 0x40, 0xe7, 0x20, 0x1a, 0x2c, 0x01, 0x4f, 0xbd, 0x95, 0x0d, 0x92, 0x8c, 0x49, 0x26, 0x71, - 0xad, 0x49, 0xaa, 0xc3, 0x09, 0xad, 0x03, 0x1d, 0x57, 0x17, 0xd0, 0xf9, 0xb8, 0xee, 0x7d, 0xbc, 0x1a, 0x2e, 0xa8, - 0xf4, 0x2b, 0x31, 0xf0, 0xea, 0xe9, 0x38, 0xb8, 0xa6, 0x5b, 0xe1, 0x62, 0x1d, 0xee, 0x7e, 0x96, 0x0f, 0x1c, 0x77, - 0x54, 0xd2, 0x10, 0x18, 0xbc, 0x3d, 0x74, 0x37, 0x33, 0x34, 0xd4, 0x49, 0xfb, 0x30, 0x0e, 0xe5, 0x10, 0xab, 0x56, - 0x5c, 0x49, 0x6f, 0x04, 0xdf, 0x2e, 0x14, 0x63, 0xd9, 0xd8, 0xb5, 0xa1, 0x28, 0xfc, 0x15, 0xc0, 0x0e, 0xb5, 0xbf, - 0x52, 0xc9, 0xc7, 0xc8, 0xa8, 0xa6, 0x81, 0x8e, 0x01, 0x58, 0xb2, 0x34, 0x91, 0x54, 0x91, 0x46, 0xe2, 0x8f, 0xcc, - 0x58, 0x47, 0x4d, 0xd7, 0x17, 0x4c, 0x55, 0x8b, 0xa4, 0xdb, 0x99, 0xc4, 0x72, 0x22, 0x49, 0x6d, 0xf7, 0x11, 0x31, - 0x18, 0xf8, 0x60, 0x23, 0xa6, 0x99, 0x08, 0x47, 0x3c, 0x2a, 0x91, 0x45, 0x97, 0xdf, 0x46, 0x99, 0xb4, 0x7d, 0x59, - 0x91, 0x2d, 0x08, 0xa6, 0x27, 0xd1, 0x07, 0x49, 0xd0, 0xba, 0x48, 0xa4, 0x19, 0x21, 0xc0, 0x8f, 0x27, 0xe5, 0x8d, - 0xfe, 0x1c, 0x34, 0xad, 0x04, 0x2f, 0x19, 0x24, 0x8f, 0xc4, 0xcf, 0xa4, 0x60, 0x16, 0x63, 0xf9, 0x60, 0x80, 0xe5, - 0xe4, 0x4f, 0x1d, 0x93, 0xf4, 0x5f, 0x3a, 0x9d, 0xb0, 0x5f, 0x78, 0x95, 0xad, 0xe5, 0x4d, 0x73, 0xef, 0x85, 0x97, - 0xb3, 0x54, 0xc3, 0x32, 0xe8, 0xbf, 0x26, 0xda, 0x05, 0x5b, 0x5b, 0xc6, 0x84, 0x55, 0x3f, 0x80, 0xb4, 0x47, 0xba, - 0xbc, 0x7c, 0x58, 0x31, 0xc1, 0xa3, 0x2b, 0x6b, 0x1e, 0x44, 0x57, 0xc2, 0x47, 0x2e, 0xbb, 0x49, 0x72, 0x33, 0x9e, - 0xf8, 0xe1, 0x60, 0xa0, 0x00, 0x68, 0x69, 0x9d, 0x14, 0x83, 0xf0, 0xa9, 0x90, 0x03, 0x69, 0x74, 0x54, 0x05, 0x58, - 0x2c, 0xb3, 0x9b, 0x72, 0x92, 0x0d, 0x06, 0x3e, 0x88, 0x8d, 0x89, 0xdd, 0xd0, 0x6c, 0xee, 0xb3, 0x33, 0x05, 0x59, - 0x6d, 0x0e, 0x5b, 0x33, 0xdd, 0x02, 0x03, 0x80, 0x41, 0x44, 0xb0, 0xdc, 0x67, 0x46, 0x3e, 0xa2, 0x4e, 0x4f, 0x61, - 0x04, 0x04, 0xbf, 0x9e, 0x08, 0x44, 0x2e, 0x12, 0xa8, 0x07, 0x98, 0x09, 0x30, 0xa3, 0x8a, 0xe1, 0x35, 0xb0, 0x8b, - 0x57, 0xe6, 0x15, 0x83, 0xfe, 0x45, 0x93, 0x2c, 0xd1, 0x54, 0xe2, 0x68, 0x8c, 0x9c, 0x4a, 0x63, 0x64, 0x40, 0xec, - 0xe2, 0xf8, 0xf7, 0x94, 0x1e, 0x05, 0x29, 0xfb, 0x9c, 0x1b, 0xe2, 0x70, 0x14, 0x5f, 0xc1, 0xaa, 0x71, 0x3c, 0xd6, - 0xe6, 0xf5, 0x74, 0x56, 0xcf, 0x07, 0x22, 0x80, 0xff, 0x86, 0x82, 0xfd, 0xa2, 0xa9, 0xc8, 0x0d, 0x52, 0xe7, 0xf1, - 0x98, 0x82, 0x7c, 0xaa, 0x9b, 0xfc, 0x43, 0xee, 0xee, 0xa7, 0xb3, 0xb9, 0x35, 0x47, 0xaf, 0x6a, 0x5c, 0xb7, 0x56, - 0x37, 0x14, 0x12, 0xad, 0x69, 0x52, 0xdc, 0xe4, 0x93, 0x62, 0xc0, 0x2b, 0x5f, 0xa8, 0x2e, 0xb6, 0x46, 0xb0, 0xf0, - 0xe7, 0x16, 0x08, 0x93, 0x71, 0x2f, 0x3e, 0x59, 0xc8, 0x29, 0xed, 0xda, 0x6a, 0xb7, 0xb5, 0x49, 0xd3, 0x58, 0x35, - 0xbc, 0x86, 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, - 0x2d, 0x86, 0xff, 0x29, 0xdd, 0x9b, 0x53, 0x1b, 0xe4, 0x00, 0xb6, 0x7b, 0x0f, 0xb7, 0x63, 0xf4, 0x40, 0x06, 0x6f, - 0x04, 0x10, 0x8d, 0xaf, 0xa7, 0xd6, 0x8c, 0x89, 0x86, 0x05, 0x2b, 0x87, 0x91, 0x1f, 0x20, 0xe3, 0xe5, 0x14, 0x58, - 0xd9, 0x4f, 0x8a, 0xb8, 0xf6, 0x87, 0x91, 0x7f, 0xf5, 0x2c, 0xc8, 0xb8, 0x17, 0x0d, 0x3b, 0xbe, 0x00, 0x7b, 0xf5, - 0xd5, 0x33, 0x16, 0x0d, 0x78, 0x7e, 0x53, 0x4f, 0xb3, 0x60, 0x98, 0xb1, 0xe8, 0xa6, 0x18, 0x82, 0x0f, 0xed, 0xf3, - 0x72, 0x10, 0xfa, 0xbe, 0xd9, 0x39, 0x74, 0x37, 0x24, 0xf2, 0x08, 0xfb, 0x2b, 0xb8, 0xed, 0x6a, 0x89, 0x19, 0xe0, - 0x06, 0x56, 0x11, 0x33, 0xd8, 0xf2, 0x57, 0xcf, 0x0c, 0x97, 0x50, 0xfe, 0x5c, 0x6a, 0x36, 0x0a, 0x34, 0x27, 0xe7, - 0x68, 0x4e, 0x56, 0x42, 0x2d, 0xf9, 0xa4, 0xc2, 0xa9, 0x3a, 0x9f, 0x68, 0xbb, 0xd1, 0x18, 0x03, 0x17, 0xed, 0xb9, - 0x2d, 0x8c, 0xcc, 0x74, 0x91, 0xa2, 0x01, 0x0b, 0xcf, 0xc4, 0x29, 0x8d, 0x01, 0xed, 0xcb, 0x81, 0xa5, 0x0d, 0xf9, - 0xab, 0x9c, 0x19, 0x68, 0x1b, 0x52, 0x1a, 0x35, 0x03, 0x7f, 0xa6, 0x26, 0xcc, 0xaf, 0x60, 0x25, 0x82, 0xa8, 0x2e, - 0xc0, 0x24, 0xa9, 0xc8, 0x68, 0xa4, 0xac, 0x44, 0x72, 0x0e, 0x78, 0x1f, 0xc1, 0x93, 0x45, 0xec, 0x6a, 0x7f, 0x4a, - 0xff, 0xab, 0xc3, 0xe7, 0xda, 0x7f, 0x2a, 0x80, 0x85, 0x5c, 0x1a, 0x44, 0x06, 0x0a, 0x87, 0xd4, 0x54, 0x22, 0x4e, - 0x1c, 0xcf, 0xc0, 0xd7, 0x70, 0x81, 0xa6, 0x80, 0xfe, 0xa0, 0x66, 0x14, 0x91, 0x85, 0xbf, 0x7a, 0x76, 0x53, 0xb7, - 0x7a, 0x9e, 0x39, 0xaf, 0x41, 0x33, 0x03, 0x21, 0x3d, 0x4e, 0xd5, 0xdb, 0x90, 0xe8, 0xbc, 0xbc, 0xd4, 0x2f, 0x13, - 0x22, 0x59, 0x11, 0x79, 0xfa, 0x3e, 0x07, 0xf3, 0x88, 0x22, 0x74, 0x70, 0x65, 0x1e, 0x8f, 0x97, 0x82, 0xc2, 0x77, - 0x94, 0xe7, 0x03, 0x4e, 0xb3, 0x28, 0x01, 0x6d, 0x20, 0xab, 0x4c, 0x99, 0x9b, 0xa4, 0x65, 0xea, 0x3e, 0x80, 0x95, - 0x20, 0x47, 0x37, 0xa7, 0xa0, 0x50, 0x46, 0x82, 0x52, 0x5a, 0x0d, 0x42, 0xa9, 0x0e, 0x8b, 0x20, 0x72, 0xc8, 0x42, - 0xc0, 0xcd, 0x54, 0x34, 0x5a, 0xd2, 0xf0, 0x08, 0xe7, 0x06, 0x0a, 0x01, 0x48, 0xec, 0xa9, 0xa2, 0x8c, 0xcb, 0x61, - 0xce, 0xd6, 0x3c, 0x1c, 0xe2, 0xac, 0x49, 0x5b, 0x9e, 0x83, 0x38, 0x96, 0x4b, 0xbe, 0xc9, 0x11, 0x0c, 0x22, 0xf4, - 0x19, 0xf2, 0x27, 0xcb, 0xf9, 0x77, 0xe7, 0x30, 0xed, 0x08, 0x1f, 0x76, 0xb5, 0x05, 0x17, 0xb3, 0xbb, 0xf9, 0x04, - 0xe2, 0x5b, 0xee, 0xe6, 0xa7, 0x18, 0x22, 0x0b, 0x7f, 0xb0, 0x1a, 0x4a, 0xae, 0x28, 0x74, 0x59, 0x8f, 0x48, 0x91, - 0x3d, 0xdd, 0x70, 0x04, 0xc1, 0x81, 0x56, 0x0d, 0x32, 0x34, 0x12, 0x5f, 0x3d, 0x83, 0xac, 0xc1, 0x86, 0x7f, 0xce, - 0xc9, 0x59, 0xdd, 0x9f, 0x6c, 0xa1, 0x9a, 0x64, 0xb2, 0x56, 0x54, 0xce, 0x5f, 0xaf, 0xca, 0xf2, 0x6c, 0x55, 0x86, - 0xeb, 0x41, 0x57, 0x55, 0x96, 0x1c, 0xa9, 0x0d, 0xd0, 0x9a, 0xae, 0x10, 0x43, 0x21, 0x6b, 0xb0, 0xb4, 0xaa, 0xb2, - 0xa1, 0x3e, 0x81, 0x40, 0x1f, 0x60, 0x19, 0x35, 0xfb, 0xe9, 0xf0, 0x9f, 0xc1, 0x3f, 0x55, 0xc8, 0x52, 0x9d, 0xd6, - 0x99, 0xf8, 0x35, 0x58, 0x32, 0xfc, 0xe3, 0xb7, 0x60, 0x03, 0x58, 0x02, 0x64, 0xb9, 0xdb, 0xda, 0x68, 0xbd, 0xf2, - 0x0a, 0xf1, 0xae, 0xd6, 0x17, 0xfd, 0xd6, 0x6d, 0xa2, 0x56, 0x80, 0x11, 0x0a, 0x2d, 0x02, 0x6c, 0xf5, 0xc0, 0x3d, - 0x05, 0x3f, 0x10, 0xc3, 0xb9, 0x26, 0xad, 0xa9, 0x13, 0x5e, 0x67, 0xe3, 0x48, 0x44, 0xf5, 0x0e, 0x2e, 0xee, 0xf5, - 0xce, 0xe2, 0x6f, 0x54, 0x20, 0x00, 0xb2, 0x98, 0x62, 0xe3, 0xbc, 0x21, 0xbd, 0x32, 0xec, 0x24, 0xf4, 0xde, 0xb0, - 0x13, 0xc8, 0x8b, 0xc3, 0x4e, 0xa1, 0x4b, 0xb4, 0x9d, 0x22, 0x35, 0xd1, 0x76, 0xd2, 0x62, 0x1d, 0x96, 0x10, 0xfc, - 0xaa, 0xbd, 0x75, 0x94, 0xed, 0x8b, 0x2c, 0x61, 0xda, 0x02, 0x46, 0xb9, 0x55, 0x9f, 0x39, 0x45, 0xac, 0x95, 0xbd, - 0xd3, 0x49, 0x95, 0xbb, 0xc8, 0xa7, 0x56, 0x53, 0x64, 0xf2, 0x0f, 0xa7, 0x2d, 0x92, 0x4f, 0x7e, 0x6e, 0x37, 0x4c, - 0xa6, 0x7f, 0x3c, 0xf9, 0x02, 0xba, 0x22, 0x3b, 0x7d, 0x02, 0x01, 0x99, 0x0a, 0xaa, 0xd5, 0xad, 0x62, 0x9a, 0xb7, - 0xab, 0xec, 0xf6, 0x42, 0x89, 0xe1, 0x74, 0x76, 0x12, 0x1e, 0x6d, 0x86, 0x0c, 0x1c, 0x82, 0x40, 0x21, 0x54, 0x14, - 0xc3, 0x23, 0x50, 0x6b, 0x24, 0x1f, 0xe0, 0x47, 0xbb, 0x53, 0x41, 0xa4, 0x76, 0x53, 0x71, 0xe3, 0xe4, 0xa6, 0xeb, - 0xa5, 0x40, 0xad, 0x53, 0xb2, 0x02, 0x28, 0x21, 0xea, 0x4f, 0x62, 0x57, 0xbf, 0x84, 0x2b, 0x36, 0x3f, 0x34, 0x8a, - 0x9e, 0x5c, 0x9f, 0xa2, 0x6e, 0xc5, 0xd5, 0x69, 0xda, 0x6a, 0x8e, 0x1d, 0x67, 0xc8, 0xc1, 0xb3, 0x82, 0x60, 0x3b, - 0x2a, 0x51, 0xbe, 0x6d, 0x37, 0x1d, 0x13, 0x5b, 0xfd, 0xb3, 0xa8, 0xb6, 0x2b, 0xa8, 0x88, 0x88, 0x4f, 0xb2, 0x9b, - 0x27, 0xed, 0x77, 0xb0, 0xc7, 0x5a, 0x0d, 0x22, 0xfb, 0x0c, 0xae, 0x72, 0x9d, 0x16, 0xb9, 0x2d, 0x83, 0xf3, 0x0f, - 0xaf, 0x76, 0x15, 0x36, 0x39, 0xd6, 0xd5, 0xd5, 0x4c, 0x75, 0x52, 0xb1, 0x81, 0xb1, 0xa6, 0xb5, 0x54, 0xf3, 0x18, - 0x92, 0xee, 0xca, 0xe2, 0xac, 0x4a, 0xba, 0xe9, 0xb9, 0x71, 0xa6, 0x10, 0x03, 0x67, 0xab, 0xd1, 0x72, 0x86, 0x21, - 0xba, 0x3e, 0xcc, 0x12, 0xbf, 0xd5, 0x53, 0xee, 0xf3, 0x70, 0xe7, 0x77, 0xf5, 0x82, 0x93, 0xc9, 0x7e, 0x72, 0x9a, - 0xbb, 0x5d, 0xa4, 0xfd, 0xc4, 0xb7, 0x61, 0xfe, 0xf5, 0x0d, 0x62, 0x25, 0xea, 0x7f, 0x54, 0x00, 0x34, 0xb8, 0xcd, - 0x63, 0x89, 0x52, 0x7f, 0x50, 0xd5, 0x0f, 0x6a, 0xa6, 0x6a, 0x1a, 0x08, 0xe6, 0x54, 0x0a, 0xf8, 0xc3, 0xed, 0xc2, - 0x15, 0x8f, 0xb8, 0x61, 0x61, 0xfc, 0xd3, 0xab, 0xd9, 0xb9, 0xa0, 0x32, 0x70, 0x33, 0xfe, 0xd3, 0x13, 0xec, 0x1c, - 0xd6, 0x0a, 0xc8, 0x0a, 0x7f, 0x7a, 0xd5, 0x23, 0xef, 0xe7, 0xfc, 0x4f, 0x2f, 0x7f, 0xe4, 0x7d, 0xc4, 0x79, 0xf9, - 0x13, 0x49, 0x9d, 0x10, 0xd5, 0xe5, 0x4f, 0xc2, 0x14, 0x5b, 0xa7, 0xf9, 0x2b, 0x52, 0xf8, 0x04, 0x9f, 0x81, 0xef, - 0x70, 0x1d, 0xee, 0xcc, 0x6f, 0xf0, 0xd8, 0xb1, 0xd8, 0x76, 0xa9, 0x2f, 0xa0, 0x1c, 0x81, 0x45, 0x54, 0xf6, 0xdb, - 0xb9, 0xfd, 0x6a, 0x61, 0x94, 0x31, 0x76, 0x5f, 0xb2, 0x12, 0xa5, 0xb3, 0x7e, 0xbf, 0x90, 0x82, 0x91, 0x5d, 0x58, - 0xa3, 0x3d, 0x4a, 0xd5, 0xab, 0x6f, 0xc3, 0x3a, 0x4a, 0xd2, 0x7c, 0x25, 0xa3, 0x8f, 0x64, 0xd8, 0x91, 0xbe, 0x92, - 0x12, 0xed, 0xb5, 0x0a, 0xcb, 0xd1, 0xec, 0xd7, 0x25, 0x07, 0xca, 0xeb, 0x56, 0x50, 0xbe, 0x6a, 0x02, 0xe8, 0x95, - 0x6a, 0x9f, 0x01, 0x23, 0xa7, 0xb0, 0x54, 0x1e, 0xac, 0xc4, 0xb9, 0xe8, 0xb3, 0xe2, 0x78, 0xf4, 0x2c, 0x34, 0xf3, - 0x0a, 0x1e, 0x84, 0x3b, 0x0b, 0x23, 0x15, 0x2e, 0x84, 0xe2, 0x79, 0x85, 0xb1, 0x15, 0x15, 0x70, 0x20, 0xc3, 0x0f, - 0x08, 0xbc, 0x97, 0xfd, 0x2b, 0x18, 0x0c, 0x13, 0xdc, 0xc8, 0xa8, 0x93, 0x2b, 0xf6, 0x27, 0x06, 0x66, 0x50, 0x4f, - 0x6a, 0xf7, 0xd9, 0x83, 0x0a, 0xec, 0x85, 0x33, 0xa0, 0xbd, 0x1b, 0xa3, 0x9f, 0x55, 0xb1, 0x71, 0xd2, 0x3f, 0x15, - 0x1b, 0x48, 0xa6, 0xc3, 0xe2, 0x64, 0x9b, 0x86, 0x47, 0xf2, 0xe4, 0x38, 0xdd, 0xf4, 0x8f, 0xc7, 0x31, 0x7e, 0x1c, - 0xe5, 0xd7, 0x16, 0xf0, 0x2a, 0x6e, 0x21, 0x8d, 0x45, 0x8a, 0xde, 0x81, 0x98, 0x43, 0xd1, 0x4b, 0xf6, 0x5b, 0xc6, - 0xcb, 0x89, 0xa0, 0x94, 0x24, 0x36, 0xbc, 0x23, 0x3d, 0x4d, 0xeb, 0xd1, 0x4e, 0x06, 0xec, 0xd7, 0xa3, 0x3d, 0xfd, - 0x05, 0x8a, 0x47, 0x0b, 0x7f, 0x49, 0x7f, 0x17, 0x77, 0x73, 0xcf, 0xf9, 0xa6, 0xf1, 0x1d, 0x71, 0x81, 0x62, 0xcd, - 0xee, 0xaf, 0x69, 0xe9, 0xac, 0x03, 0xc1, 0x01, 0x6f, 0xb1, 0x8b, 0xf6, 0xfd, 0xc6, 0x75, 0x7a, 0x3a, 0x7c, 0xeb, - 0xd6, 0x28, 0xdf, 0xfb, 0x87, 0x44, 0x39, 0x38, 0xbc, 0x72, 0xd1, 0xfc, 0xed, 0xa7, 0x0c, 0x49, 0x85, 0xe6, 0x06, - 0xdb, 0xc9, 0x16, 0x61, 0x6d, 0x8c, 0x83, 0x9c, 0xad, 0xca, 0x30, 0x02, 0x06, 0x75, 0xec, 0x7f, 0xf4, 0xd9, 0xb4, - 0x21, 0xfb, 0x00, 0x50, 0xb9, 0x0a, 0x01, 0x7b, 0x00, 0x4e, 0x34, 0xc2, 0x0d, 0x70, 0xab, 0xd1, 0x92, 0x0e, 0xea, - 0xb6, 0x60, 0x20, 0x5a, 0xc2, 0xc6, 0x09, 0x5d, 0xdf, 0x57, 0x84, 0x8f, 0xca, 0xb7, 0x0f, 0xe5, 0xaf, 0x9e, 0xb3, - 0xff, 0xde, 0x61, 0x4d, 0x4d, 0xb9, 0x05, 0xcc, 0x9c, 0xb5, 0xc8, 0x2b, 0x84, 0x4e, 0x91, 0xdf, 0xab, 0xba, 0x12, - 0xc3, 0x65, 0x2d, 0xca, 0xce, 0xec, 0xd6, 0x89, 0xde, 0x39, 0x05, 0xb5, 0x54, 0x36, 0x20, 0x01, 0x6e, 0x20, 0xc5, - 0xb6, 0xc0, 0x92, 0xce, 0x06, 0x28, 0xfe, 0x0d, 0x2a, 0xed, 0xfe, 0xdf, 0x39, 0x13, 0xd4, 0x6c, 0xa3, 0xba, 0xbf, - 0xd2, 0x4f, 0x55, 0x4d, 0x62, 0x01, 0x2e, 0x27, 0x69, 0xde, 0xf1, 0x08, 0xab, 0x7f, 0x9a, 0x2c, 0x45, 0xa0, 0x57, - 0x11, 0xed, 0x4a, 0x40, 0x82, 0x76, 0x76, 0x16, 0x2a, 0x02, 0x05, 0xfa, 0xfa, 0x0f, 0xdb, 0x34, 0x8b, 0xe5, 0x6a, - 0xb6, 0x87, 0x89, 0xb2, 0x58, 0x0f, 0x11, 0xe4, 0xcc, 0xd4, 0xc1, 0x7e, 0x4f, 0x33, 0x9a, 0x85, 0x37, 0xa6, 0x04, - 0x97, 0xe2, 0x2a, 0x2a, 0x72, 0xf0, 0x39, 0xc4, 0x17, 0x3e, 0x15, 0x72, 0x83, 0x88, 0xa6, 0x3f, 0xe4, 0x9e, 0x79, - 0x83, 0x85, 0x92, 0x9f, 0x10, 0x7f, 0xc9, 0xda, 0x18, 0xf7, 0x4b, 0xa7, 0xda, 0x2f, 0x15, 0x82, 0xfb, 0xcf, 0xb6, - 0xd8, 0xa8, 0xf2, 0x44, 0x8f, 0x3e, 0xc5, 0xfa, 0x9f, 0x2d, 0xa0, 0x54, 0xf7, 0x6d, 0x70, 0x2a, 0x1e, 0x85, 0xdb, - 0xba, 0xb8, 0x45, 0x68, 0x81, 0x72, 0x54, 0x15, 0xdb, 0x32, 0x22, 0x4e, 0xd8, 0x6d, 0x5d, 0xf4, 0x34, 0x07, 0x3a, - 0x75, 0x58, 0x9a, 0xc8, 0x13, 0xa1, 0xdd, 0x82, 0xee, 0x69, 0x8e, 0x95, 0x78, 0x21, 0x4b, 0x07, 0x59, 0x27, 0xd2, - 0x84, 0xca, 0x5d, 0x5d, 0x75, 0x52, 0x2a, 0x75, 0xc3, 0xeb, 0x54, 0x33, 0xfe, 0x2e, 0xcd, 0x9f, 0x58, 0xf6, 0xeb, - 0xd6, 0x6f, 0xb5, 0xda, 0x1b, 0xab, 0x47, 0x25, 0x6b, 0x8e, 0xb3, 0x09, 0x49, 0xe9, 0x13, 0xb6, 0x9b, 0x49, 0xd7, - 0x3a, 0xf0, 0x24, 0xb8, 0x1c, 0x7a, 0x02, 0x2a, 0x06, 0x4d, 0xbc, 0xdd, 0x05, 0xea, 0x11, 0x78, 0x06, 0xaa, 0x19, - 0x24, 0xd7, 0x01, 0xbf, 0xac, 0xb5, 0x3c, 0x65, 0x84, 0x61, 0xb5, 0xb3, 0x68, 0x39, 0x58, 0x49, 0x78, 0xae, 0x08, - 0x5c, 0xbb, 0x12, 0x78, 0x35, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, - 0xa7, 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, - 0x36, 0x9f, 0x43, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, - 0xcf, 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, - 0x76, 0x7a, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, - 0x88, 0xc2, 0x2c, 0xfb, 0x6b, 0x51, 0xfc, 0x51, 0xe9, 0x3b, 0x02, 0x1d, 0xdd, 0x79, 0x51, 0xa7, 0xcb, 0xfd, 0x07, - 0xc2, 0x78, 0xf2, 0xea, 0x13, 0xa2, 0x5b, 0xdf, 0x67, 0xee, 0x57, 0x80, 0x1b, 0xc1, 0x1d, 0x44, 0x7b, 0xb7, 0xd4, - 0x27, 0xb5, 0xfa, 0x5a, 0xaf, 0x9d, 0xa7, 0xe7, 0x37, 0x9d, 0xdb, 0xef, 0xa1, 0x39, 0xd9, 0x7a, 0x4f, 0x0b, 0x6b, - 0x65, 0xe9, 0xa9, 0x2a, 0xd8, 0x9b, 0xe5, 0xb9, 0x2a, 0x98, 0x3c, 0xf0, 0x9a, 0xfd, 0x82, 0x06, 0x57, 0x3a, 0xd9, - 0x78, 0xcf, 0xd4, 0xc0, 0x2d, 0x0a, 0x4b, 0x87, 0x5f, 0x72, 0x33, 0x79, 0x89, 0xfb, 0x4b, 0x45, 0x2e, 0xf6, 0x9d, - 0x33, 0xba, 0x33, 0xb3, 0xee, 0x55, 0x85, 0xab, 0x05, 0xb9, 0x3a, 0xb0, 0xb5, 0xec, 0xe2, 0x70, 0xc3, 0x22, 0x0a, - 0x10, 0x88, 0xe9, 0x95, 0x5a, 0xfb, 0x13, 0x1a, 0x84, 0x6a, 0x30, 0xf0, 0x0b, 0x0c, 0x56, 0x05, 0x0a, 0x1f, 0x28, - 0x92, 0xbf, 0xf2, 0x04, 0xec, 0xe2, 0x19, 0xa0, 0x5b, 0xb1, 0x59, 0x31, 0x42, 0x84, 0x4c, 0x56, 0xb1, 0x9a, 0xce, - 0x20, 0x9f, 0xfa, 0xe2, 0x1b, 0x5b, 0x75, 0x3e, 0x6f, 0x6b, 0xaa, 0x9c, 0x3b, 0x14, 0xba, 0xbb, 0xa9, 0x3b, 0xb7, - 0x2e, 0xf2, 0xdc, 0x21, 0xe4, 0x4a, 0xc5, 0x4a, 0x4c, 0x43, 0xcd, 0x93, 0x34, 0xa3, 0xfe, 0x62, 0x9f, 0x8a, 0x1a, - 0x85, 0x53, 0xfe, 0x74, 0x0c, 0xaa, 0x70, 0x55, 0x43, 0x1c, 0x4b, 0x55, 0x3c, 0xb2, 0x41, 0xa0, 0x79, 0x75, 0xa7, - 0x92, 0x26, 0x64, 0x72, 0x23, 0x7c, 0x6a, 0x52, 0xca, 0xd3, 0xb4, 0x49, 0x2b, 0x45, 0xea, 0xe0, 0x83, 0x3a, 0xd5, - 0x78, 0x6e, 0xe6, 0xcf, 0x01, 0xcc, 0xb8, 0xba, 0xe1, 0xd7, 0x8a, 0xcb, 0xa8, 0xad, 0xcc, 0xa4, 0xfd, 0xc9, 0xd1, - 0xd8, 0x28, 0x56, 0xe3, 0x46, 0x19, 0x61, 0xa5, 0x34, 0x27, 0xc5, 0x72, 0x3c, 0xff, 0x80, 0xc1, 0x9a, 0x27, 0xb0, - 0x83, 0x89, 0x4a, 0x79, 0x1f, 0x01, 0xf1, 0x75, 0x92, 0xae, 0x12, 0x48, 0x91, 0xfe, 0xa5, 0x4b, 0xee, 0x32, 0x36, - 0x10, 0x63, 0x56, 0xcc, 0x8c, 0xfe, 0x07, 0x77, 0x49, 0x7f, 0x12, 0x02, 0xe0, 0x26, 0x9a, 0x42, 0xa7, 0xce, 0x93, - 0xab, 0x2a, 0x58, 0x5e, 0x79, 0x68, 0xc5, 0x88, 0x07, 0xff, 0xf9, 0x3c, 0x44, 0x10, 0x73, 0x4c, 0xf1, 0xf4, 0x0b, - 0xa3, 0xff, 0x08, 0xae, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, 0x21, 0xdc, 0xec, 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, - 0x6a, 0xf8, 0xd7, 0xdc, 0x83, 0xfe, 0xaf, 0x33, 0x61, 0xa9, 0xfd, 0xf4, 0x74, 0x00, 0x15, 0xbc, 0xaf, 0x78, 0x1b, - 0x11, 0xdf, 0x27, 0x7e, 0x1a, 0x0f, 0xb6, 0x4f, 0xb7, 0x60, 0xad, 0xfb, 0x50, 0x19, 0xeb, 0x2a, 0x61, 0x03, 0x01, - 0x5f, 0xa3, 0xa8, 0x3d, 0xaf, 0xdd, 0xee, 0xc1, 0x7f, 0xfa, 0x57, 0x21, 0x03, 0x26, 0x4e, 0xdf, 0x67, 0x4e, 0xd6, - 0xe8, 0x2a, 0x93, 0xe9, 0x43, 0x27, 0x7d, 0xab, 0xd3, 0x7d, 0x27, 0xfc, 0x23, 0x67, 0x16, 0x1f, 0x6e, 0xe9, 0x2b, - 0x4d, 0x8a, 0x3b, 0x60, 0x65, 0xf3, 0xa8, 0x20, 0xd4, 0xb9, 0x88, 0xbe, 0x32, 0xe5, 0x5b, 0x42, 0xcd, 0xa1, 0xb1, - 0xa4, 0x94, 0xee, 0x35, 0xf4, 0x3a, 0xad, 0xf5, 0xdb, 0x28, 0xc1, 0x98, 0xe8, 0x78, 0xf2, 0x32, 0x1e, 0x2b, 0xef, - 0xe3, 0x71, 0x23, 0x15, 0xf2, 0x00, 0x44, 0xa0, 0x62, 0xfc, 0xe9, 0xca, 0x53, 0x91, 0x5e, 0x18, 0xaf, 0x42, 0x29, - 0x28, 0x0c, 0xe8, 0x0a, 0xa4, 0x80, 0x47, 0xed, 0x89, 0xce, 0xc2, 0x2e, 0xe1, 0x1e, 0xdd, 0x04, 0x8c, 0xf5, 0xf9, - 0xaf, 0xb9, 0x97, 0x33, 0xe1, 0x0e, 0x2f, 0x06, 0xa8, 0x4d, 0xbd, 0xba, 0xfb, 0xb8, 0x56, 0xe7, 0x70, 0x08, 0x0e, - 0x56, 0x83, 0x08, 0x4e, 0xe7, 0x73, 0x47, 0xb3, 0x2c, 0x40, 0xe5, 0x64, 0x95, 0x91, 0x37, 0x4f, 0x16, 0xbd, 0xba, - 0xef, 0x2d, 0xd3, 0xb2, 0xaa, 0x83, 0x8c, 0x65, 0x61, 0x05, 0xb8, 0x3a, 0xb4, 0x7e, 0x10, 0x2e, 0x0b, 0xe7, 0x0f, - 0x84, 0x20, 0x76, 0xaf, 0xb6, 0x25, 0xd7, 0x47, 0xf5, 0xd3, 0x67, 0x6c, 0xc3, 0x25, 0xea, 0xa4, 0x33, 0x11, 0x80, - 0xd8, 0x53, 0xb3, 0x8a, 0x6e, 0x80, 0xa4, 0x4e, 0xb3, 0x8a, 0x6e, 0xa8, 0xd9, 0xc6, 0x38, 0x00, 0xca, 0x58, 0xc0, - 0xbe, 0x9b, 0x8e, 0x83, 0xf5, 0xd3, 0x58, 0x5e, 0x87, 0x56, 0x4f, 0xb7, 0xca, 0x67, 0x50, 0xb7, 0xda, 0x18, 0x13, - 0xdb, 0xcd, 0x97, 0x73, 0xfd, 0x6e, 0xb0, 0xf4, 0xed, 0xa0, 0x39, 0xa7, 0xec, 0x95, 0x2e, 0x7b, 0x6d, 0x97, 0x4d, - 0x3d, 0x77, 0x52, 0xb4, 0x1a, 0x03, 0x7a, 0x03, 0x0b, 0xd6, 0xe7, 0x22, 0xcd, 0x56, 0xa5, 0x2a, 0x01, 0x2f, 0x8c, - 0x35, 0x5b, 0xf9, 0x8d, 0xcc, 0x90, 0x84, 0x79, 0x9c, 0x89, 0xb7, 0x74, 0xaf, 0x85, 0xc9, 0x71, 0x2a, 0x92, 0x29, - 0xa1, 0x53, 0xba, 0xb3, 0x0d, 0x9d, 0xab, 0x30, 0x8a, 0x68, 0xad, 0xa4, 0xd2, 0x48, 0x60, 0x6a, 0x06, 0x28, 0x99, - 0x2b, 0x70, 0x4a, 0x97, 0xfb, 0xdf, 0x89, 0x18, 0x67, 0xbe, 0x28, 0x99, 0x01, 0xdd, 0xf2, 0xeb, 0x62, 0xd3, 0x4a, - 0x91, 0x11, 0xe6, 0xcd, 0x69, 0x7b, 0x5d, 0x1f, 0x02, 0xb9, 0x5a, 0x0e, 0x28, 0x1a, 0x07, 0x85, 0x0e, 0x97, 0x2a, - 0x01, 0xf6, 0x45, 0xe2, 0x67, 0x84, 0x2d, 0xed, 0x81, 0xdc, 0x1e, 0x9d, 0x09, 0x73, 0xc9, 0x49, 0x59, 0x76, 0x29, - 0xcd, 0xe0, 0x72, 0xe2, 0x4a, 0x70, 0x91, 0xde, 0xae, 0xa7, 0x49, 0x4b, 0xdb, 0xc7, 0x86, 0x73, 0x34, 0xb4, 0x0d, - 0xba, 0x63, 0x7f, 0x68, 0x2e, 0x16, 0xb1, 0x75, 0xb1, 0x18, 0x76, 0x66, 0x3f, 0x59, 0x2c, 0x40, 0x0e, 0x00, 0x47, - 0xdd, 0x96, 0x8f, 0xd9, 0x12, 0x38, 0xad, 0xa6, 0xd9, 0xd4, 0xdb, 0xf2, 0xfc, 0xa9, 0xea, 0xe9, 0x25, 0xaf, 0x9e, - 0x0a, 0x33, 0x16, 0x5b, 0x5e, 0x3d, 0xb5, 0x8e, 0x9c, 0xfc, 0xa9, 0x50, 0xa2, 0x75, 0x01, 0xcd, 0xc0, 0x6b, 0x0a, - 0x18, 0xb1, 0x64, 0x32, 0xa5, 0x8a, 0x3c, 0xee, 0x4d, 0xb7, 0x6a, 0xf0, 0x82, 0xc2, 0x21, 0x90, 0xd2, 0xe9, 0x57, - 0xcf, 0x98, 0x7e, 0xef, 0xea, 0x59, 0x87, 0xac, 0x6d, 0x98, 0x2e, 0xb7, 0xc3, 0x64, 0x50, 0xfa, 0x4f, 0xcd, 0xc4, - 0xb8, 0xb2, 0x26, 0x09, 0x20, 0xfe, 0x8d, 0xfd, 0x0e, 0x29, 0xdc, 0xbc, 0xbf, 0x1c, 0xc6, 0x8f, 0xbc, 0x1f, 0x23, - 0x7b, 0x92, 0x66, 0x88, 0x35, 0x93, 0x0a, 0xb9, 0xfb, 0x6a, 0xfd, 0x63, 0x62, 0x37, 0xd9, 0x03, 0x0b, 0x40, 0x6c, - 0x4d, 0x5b, 0xdd, 0xf2, 0x7e, 0xdf, 0x33, 0x45, 0x80, 0x1f, 0x94, 0x7f, 0x72, 0x67, 0x48, 0x06, 0x65, 0xd7, 0x0d, - 0x21, 0x1e, 0x94, 0x4d, 0xd3, 0x5e, 0x6f, 0x07, 0x67, 0x1e, 0xab, 0xeb, 0xb4, 0xb3, 0xb8, 0x5a, 0x64, 0x90, 0x56, - 0x1f, 0xb2, 0xd3, 0xcc, 0x3e, 0x3b, 0x59, 0x2a, 0xdd, 0xef, 0x43, 0x44, 0xdc, 0x49, 0xd6, 0xf6, 0xdb, 0x2d, 0xb8, - 0x86, 0x93, 0x41, 0xe8, 0xca, 0xde, 0x2e, 0xa3, 0x8d, 0x0b, 0x71, 0xda, 0x33, 0x9d, 0x2f, 0xf8, 0xf2, 0x28, 0xed, - 0x3c, 0x38, 0xd5, 0x13, 0x7d, 0x6e, 0xba, 0xab, 0x4c, 0xae, 0x75, 0x58, 0x8d, 0x41, 0x6d, 0x16, 0xb6, 0x70, 0x17, - 0xb6, 0xd1, 0x41, 0x6b, 0x5f, 0x16, 0xfc, 0x53, 0x06, 0xe0, 0x4b, 0xcf, 0x96, 0x5d, 0xaf, 0x49, 0xab, 0xd7, 0x32, - 0x0a, 0xb1, 0xa5, 0xed, 0xd5, 0xa7, 0xa3, 0x7c, 0xdc, 0x9c, 0x51, 0x5c, 0xc8, 0x51, 0x7e, 0xf4, 0x1a, 0xa2, 0xae, - 0x75, 0x1d, 0x17, 0x8b, 0x0e, 0x37, 0xae, 0xba, 0xed, 0xc6, 0xf5, 0x23, 0xe2, 0xad, 0xd1, 0x26, 0x85, 0x5a, 0x19, - 0x3b, 0x82, 0x97, 0x55, 0xc3, 0x21, 0x13, 0xc3, 0xa1, 0x84, 0x4c, 0x7d, 0xec, 0xde, 0xd0, 0xb4, 0xcf, 0x4f, 0x5b, - 0x3f, 0x62, 0xa9, 0x71, 0x14, 0x1b, 0xde, 0xf9, 0x3b, 0x8f, 0xad, 0x71, 0x25, 0x5f, 0x06, 0xb3, 0x5d, 0x41, 0xb5, - 0x35, 0xde, 0xb0, 0x57, 0xf1, 0x1f, 0x72, 0xa9, 0xe4, 0x6f, 0x7f, 0x86, 0x6b, 0x78, 0x6b, 0x4b, 0x07, 0x4d, 0x35, - 0xab, 0x98, 0xb9, 0x17, 0x9c, 0x7e, 0xdc, 0xbd, 0x22, 0x18, 0xfc, 0x9e, 0x8e, 0x82, 0x5c, 0x2c, 0xd5, 0x1a, 0x50, - 0x90, 0x4e, 0xec, 0x98, 0xca, 0x02, 0xc3, 0x00, 0xde, 0x90, 0x01, 0xf2, 0x98, 0xc2, 0xdd, 0x50, 0xe1, 0x85, 0xbf, - 0xe4, 0x64, 0x97, 0xc0, 0xb6, 0x66, 0x7c, 0xcc, 0x70, 0x07, 0x21, 0xff, 0x08, 0xb6, 0x62, 0x6b, 0x76, 0xc7, 0x16, - 0x0c, 0xc9, 0xc6, 0x71, 0x18, 0x63, 0x3e, 0x9e, 0xc4, 0x37, 0x62, 0x12, 0x0f, 0x78, 0x84, 0x8e, 0x11, 0x1b, 0x5e, - 0xcf, 0x62, 0x39, 0x80, 0x6c, 0xc5, 0x95, 0x0e, 0x08, 0xa1, 0xb1, 0xa1, 0x25, 0xaf, 0x0b, 0x83, 0x8b, 0x1d, 0xfb, - 0x2c, 0x47, 0x91, 0x8c, 0x43, 0xb0, 0x68, 0x55, 0x03, 0x0b, 0x13, 0xbb, 0xe3, 0xc5, 0x6c, 0x3d, 0xc7, 0x7f, 0x8e, - 0x47, 0x04, 0xc0, 0x0e, 0x0e, 0x0d, 0x5b, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x2b, 0xcb, 0xd3, 0x85, 0xdd, 0xf3, 0xb7, - 0x7c, 0xcc, 0x2e, 0x7f, 0xf4, 0x20, 0x72, 0xf6, 0xf2, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xbb, 0xd4, 0xcb, 0xd9, 0x1d, - 0x51, 0x10, 0xde, 0x81, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0xbe, 0xe5, 0x0b, 0x8c, 0x15, 0xbb, 0x48, 0x97, 0x1e, 0x66, - 0x84, 0xda, 0xd3, 0xf9, 0xb2, 0x51, 0x93, 0x70, 0x7b, 0xb3, 0x9c, 0x0c, 0x06, 0x5b, 0x7f, 0xcf, 0x37, 0xc0, 0x07, - 0x73, 0xf9, 0xa3, 0xb7, 0xa7, 0x72, 0xe1, 0x3f, 0xaf, 0xb3, 0xe4, 0xbd, 0xcf, 0xde, 0x0e, 0xf8, 0x02, 0xf0, 0x96, - 0xd0, 0x81, 0xeb, 0xde, 0x67, 0x12, 0xaf, 0xed, 0xad, 0xbe, 0x46, 0x20, 0x91, 0x2f, 0x00, 0x23, 0x26, 0xe6, 0xf7, - 0x5b, 0x88, 0xc0, 0x48, 0xc0, 0xb7, 0x55, 0x7b, 0xc4, 0xef, 0xb8, 0x01, 0xfc, 0xca, 0x7c, 0xf6, 0xc0, 0x43, 0xfd, - 0x33, 0xf1, 0xd9, 0x2d, 0x7f, 0xcf, 0x9f, 0x7b, 0x52, 0x92, 0x2e, 0x67, 0xef, 0xe7, 0x70, 0x3d, 0x94, 0xf2, 0x74, - 0x48, 0x3f, 0x1b, 0x83, 0x01, 0x84, 0x42, 0xe6, 0xad, 0x07, 0xac, 0x49, 0x21, 0xfe, 0x05, 0x7c, 0x3b, 0x4a, 0xd8, - 0xbc, 0xf5, 0x76, 0xbe, 0x96, 0x37, 0x6f, 0xbd, 0x07, 0x9f, 0xa2, 0x00, 0xab, 0xa0, 0x94, 0x05, 0x56, 0x41, 0xd8, - 0x68, 0x23, 0x8c, 0x81, 0xab, 0x77, 0x8d, 0xa1, 0xae, 0xe7, 0x88, 0x6d, 0x2b, 0x7d, 0x17, 0xbe, 0x83, 0x0c, 0xf8, - 0xe0, 0x75, 0x51, 0x12, 0x7d, 0x4e, 0x4d, 0x91, 0xb4, 0xee, 0xb9, 0xdf, 0x5a, 0x77, 0xb4, 0xa6, 0xd4, 0x47, 0x6e, - 0xc6, 0xc7, 0x63, 0xfd, 0x5c, 0x68, 0x91, 0x60, 0x0a, 0x1a, 0xd7, 0xa0, 0x2d, 0x40, 0xd0, 0xe7, 0x01, 0xb2, 0x96, - 0x14, 0x0b, 0xbe, 0xfd, 0x15, 0x62, 0xf0, 0xca, 0xf4, 0xce, 0xe5, 0x2a, 0x23, 0x61, 0x7b, 0xe1, 0xd7, 0xc3, 0xda, - 0x9f, 0x38, 0xb5, 0xb0, 0xb4, 0x9a, 0x83, 0xfa, 0xa9, 0x2d, 0xc7, 0xa9, 0xaa, 0xfd, 0x4b, 0x92, 0x54, 0xbb, 0x4a, - 0xcb, 0xe9, 0xbd, 0x7d, 0xd3, 0x65, 0x82, 0x8d, 0xfd, 0x80, 0xaa, 0x23, 0xab, 0x61, 0xf7, 0x85, 0xfa, 0xa2, 0xa7, - 0x64, 0x42, 0xf3, 0x51, 0x45, 0xf3, 0xec, 0x7e, 0xb3, 0xa3, 0xfe, 0xd3, 0xeb, 0xa1, 0x08, 0x90, 0xac, 0xd2, 0x62, - 0x29, 0x72, 0x36, 0xf6, 0xd3, 0x61, 0x92, 0xa9, 0xf0, 0x82, 0x74, 0x74, 0xf7, 0x1b, 0xf7, 0xb7, 0xdc, 0x40, 0xd6, - 0x68, 0xd5, 0x06, 0x63, 0xa5, 0x68, 0x19, 0xac, 0x6f, 0xc6, 0xfd, 0xbe, 0xb8, 0x19, 0x4f, 0x45, 0x50, 0x03, 0x71, - 0x91, 0x78, 0x3e, 0x9e, 0xd6, 0xc4, 0x92, 0xda, 0x15, 0x18, 0xa3, 0xc7, 0x55, 0x51, 0xfb, 0xd4, 0xcf, 0x21, 0x14, - 0xa9, 0xd6, 0xcc, 0xb1, 0xc6, 0x8d, 0x11, 0x71, 0x87, 0x95, 0x6b, 0xa7, 0xf6, 0x3a, 0x00, 0xcb, 0xab, 0x71, 0x41, - 0xd8, 0x26, 0xa7, 0xce, 0x05, 0xac, 0x46, 0x43, 0xaa, 0xdd, 0x70, 0xeb, 0x65, 0xe7, 0x37, 0x8f, 0x13, 0x5b, 0x1b, - 0xe1, 0x96, 0x02, 0xca, 0x28, 0xbf, 0xb1, 0x9c, 0xb0, 0x3b, 0xd5, 0x3b, 0x52, 0xb5, 0x23, 0xce, 0x5c, 0xc0, 0x2a, - 0xc3, 0x53, 0xab, 0x6f, 0x62, 0x70, 0x22, 0xe4, 0xad, 0x74, 0xbc, 0xf6, 0x23, 0xee, 0x57, 0xf7, 0x75, 0xaf, 0x04, - 0x3f, 0x09, 0x79, 0xfd, 0x96, 0x77, 0x00, 0x58, 0xf1, 0x21, 0x2f, 0xa6, 0x85, 0xa3, 0x75, 0x19, 0x94, 0x01, 0x22, - 0x34, 0x03, 0xa0, 0x93, 0xab, 0x83, 0x28, 0x0d, 0x5c, 0x71, 0x87, 0x08, 0x3f, 0x8d, 0x9e, 0x56, 0xcf, 0xc3, 0xa7, - 0xf9, 0x34, 0xbc, 0xaa, 0x82, 0xe8, 0x2a, 0x0f, 0xa2, 0xa7, 0xf9, 0x4d, 0xf8, 0xb4, 0x9a, 0x46, 0x57, 0x55, 0x10, - 0x5e, 0xe5, 0x8d, 0x7d, 0xd7, 0xee, 0xee, 0x09, 0x79, 0xdb, 0xd5, 0x1f, 0xb9, 0x54, 0xf6, 0x94, 0xe9, 0xe5, 0x65, - 0xad, 0x57, 0x6a, 0xb7, 0xb9, 0x5e, 0xa3, 0x66, 0xea, 0xa3, 0xec, 0x2f, 0xb6, 0xb1, 0xf0, 0x64, 0x0e, 0xa1, 0xcf, - 0x48, 0x8b, 0xb9, 0xc7, 0xb9, 0xde, 0x1c, 0x48, 0x61, 0x60, 0xc4, 0xa4, 0x92, 0x91, 0xd3, 0x0b, 0x5c, 0x84, 0x72, - 0xc4, 0xb0, 0x96, 0xae, 0xf6, 0x59, 0x97, 0xde, 0x40, 0x5d, 0x53, 0xec, 0x6b, 0xc8, 0xc0, 0x8b, 0xa6, 0xd7, 0xc1, - 0x18, 0x90, 0x23, 0xf0, 0x8e, 0xcf, 0x96, 0x70, 0x60, 0x6e, 0x00, 0xfa, 0xe6, 0x51, 0x5f, 0x97, 0x15, 0xdf, 0xa8, - 0xbe, 0x99, 0x6e, 0x46, 0x4a, 0xf9, 0xb1, 0xe6, 0xab, 0xab, 0x67, 0xec, 0x8e, 0x6b, 0x54, 0x94, 0x5f, 0xf4, 0x62, - 0xbd, 0x07, 0xae, 0xba, 0x5f, 0xe0, 0x36, 0x8b, 0xc7, 0xae, 0x3c, 0x60, 0xd9, 0x8e, 0x3d, 0xb0, 0x5b, 0xf6, 0x9e, - 0x3d, 0x61, 0x6f, 0xd8, 0x17, 0xf6, 0x13, 0xaa, 0x36, 0x94, 0x90, 0xe7, 0x2f, 0xf8, 0x9d, 0x34, 0x3d, 0x4a, 0x54, - 0xb2, 0x07, 0xdb, 0x4c, 0x33, 0xdc, 0xb2, 0xf7, 0x7c, 0x31, 0x5c, 0xb3, 0x37, 0x90, 0x0d, 0x65, 0xe2, 0xc1, 0x9a, - 0xfd, 0xc4, 0x15, 0x88, 0x99, 0x3e, 0x0b, 0x4b, 0x4b, 0x54, 0x34, 0x65, 0xa2, 0x0c, 0xfd, 0x86, 0xe3, 0x8b, 0xec, - 0x27, 0x2c, 0x42, 0x7e, 0x66, 0xb8, 0x66, 0x0f, 0x7c, 0x31, 0x58, 0xb3, 0xf7, 0xda, 0x40, 0x34, 0xd8, 0xba, 0xa5, - 0x11, 0x92, 0x95, 0x2e, 0x4b, 0x4a, 0xd3, 0x3b, 0xfb, 0x1a, 0xb8, 0x65, 0xb7, 0x58, 0xbb, 0x27, 0x58, 0x34, 0x0a, - 0xfc, 0x83, 0x35, 0xfb, 0xc2, 0x25, 0x80, 0x9a, 0x5b, 0x9e, 0xf4, 0x0a, 0xd5, 0x05, 0xd2, 0xfd, 0xe0, 0x09, 0xa7, - 0x17, 0xd9, 0x17, 0x2c, 0x83, 0xbe, 0x32, 0x5c, 0xb3, 0x1d, 0xd6, 0xee, 0xd6, 0x58, 0xb6, 0xac, 0xea, 0x49, 0x44, - 0x60, 0x14, 0x54, 0x4a, 0xcb, 0xbf, 0x11, 0xcb, 0xa6, 0x6e, 0x1a, 0xd4, 0x86, 0xfe, 0x7c, 0x30, 0xfa, 0x0f, 0x5f, - 0xbf, 0xfb, 0xc1, 0x2b, 0xf5, 0xb5, 0xf7, 0x17, 0xc7, 0xb5, 0xb2, 0x44, 0xd7, 0xca, 0x5f, 0x79, 0x39, 0xfb, 0x65, - 0x3e, 0xd1, 0xb5, 0xa4, 0x1d, 0x86, 0x7c, 0x4d, 0x67, 0xbf, 0x74, 0x38, 0x5b, 0xfe, 0xea, 0xfb, 0x8d, 0xe9, 0x62, - 0xf5, 0x59, 0xdd, 0xbb, 0x0f, 0x83, 0x6d, 0xe3, 0xd4, 0x7b, 0x7f, 0xbe, 0xde, 0xd8, 0xcc, 0x5a, 0x7b, 0x66, 0xfe, - 0x0f, 0x57, 0x7a, 0x87, 0x43, 0x77, 0xcb, 0x77, 0xc3, 0xad, 0x3d, 0x0a, 0xf2, 0xfb, 0x52, 0x69, 0x9c, 0xd5, 0xfc, - 0x85, 0x97, 0x77, 0x49, 0xb1, 0x80, 0x68, 0xf4, 0xc9, 0x48, 0x42, 0xd7, 0xcc, 0xc4, 0x33, 0xc4, 0x57, 0x19, 0x20, - 0x73, 0x81, 0x68, 0x76, 0xcf, 0xc7, 0x93, 0xfb, 0x9b, 0x78, 0x72, 0x3f, 0xe0, 0x9f, 0x4c, 0x0b, 0xda, 0x8b, 0xed, - 0xde, 0x67, 0xbf, 0xf2, 0xc2, 0x5e, 0x8e, 0xbf, 0xf8, 0xec, 0x9d, 0x70, 0x57, 0xe8, 0x2f, 0x3e, 0xfb, 0x22, 0xf8, - 0xaf, 0x23, 0x4d, 0x94, 0xc1, 0xbe, 0xd4, 0xfc, 0xd7, 0x11, 0x32, 0x7e, 0xb0, 0xcf, 0x82, 0xbf, 0x03, 0xdf, 0xef, - 0x2a, 0x41, 0xab, 0xf8, 0xe7, 0x5a, 0xfd, 0x7c, 0x2f, 0xe3, 0x72, 0xe0, 0x4d, 0x68, 0x05, 0xbd, 0x79, 0x57, 0xcb, - 0x9f, 0xc4, 0xc3, 0x91, 0xaa, 0xa7, 0x86, 0x7f, 0x16, 0x8b, 0x59, 0xd4, 0x27, 0xe9, 0x54, 0xde, 0xe4, 0x2d, 0xcf, - 0xa4, 0x75, 0xf9, 0x1e, 0x42, 0x81, 0xdf, 0xda, 0x10, 0x05, 0x7b, 0x8e, 0x1b, 0xc1, 0x5b, 0x06, 0xf0, 0x91, 0xd9, - 0x74, 0xc7, 0x6f, 0xf9, 0x13, 0xfe, 0x85, 0xef, 0x83, 0x07, 0xfe, 0x9e, 0xbf, 0xe1, 0x3f, 0xf1, 0x3d, 0x5b, 0x4a, - 0xb4, 0xd3, 0x7a, 0x77, 0x1d, 0xec, 0x58, 0xbd, 0xbf, 0x0e, 0x1e, 0x58, 0xbd, 0x7b, 0x16, 0xdc, 0xb2, 0x7a, 0xff, - 0x2c, 0x78, 0xcf, 0x76, 0xd7, 0xc1, 0x13, 0xb6, 0xbf, 0x0e, 0xde, 0xb0, 0xdd, 0xb3, 0xe0, 0x0b, 0xdb, 0x3f, 0x0b, - 0x7e, 0x92, 0x18, 0x0f, 0x5f, 0x84, 0xe4, 0x38, 0xf9, 0x52, 0x33, 0xc3, 0xa7, 0x1b, 0x7c, 0x16, 0xd6, 0x2f, 0xaa, - 0x63, 0xf0, 0xb9, 0x66, 0xba, 0xc5, 0x81, 0x10, 0x4c, 0xb7, 0x37, 0xb8, 0xa3, 0x27, 0xa6, 0x55, 0x41, 0x2a, 0x58, - 0x57, 0x3b, 0x83, 0x45, 0xdd, 0xb4, 0xce, 0x64, 0xc7, 0x2f, 0x31, 0xee, 0xf0, 0x4b, 0x5c, 0xb0, 0x65, 0xd3, 0xe9, - 0xa4, 0x73, 0xfe, 0x24, 0xd0, 0x9b, 0xbf, 0xde, 0xf5, 0x73, 0xe9, 0x3b, 0x53, 0x34, 0x5c, 0x6b, 0x8d, 0x5b, 0x3b, - 0x7d, 0x68, 0xed, 0xf4, 0x4c, 0xaa, 0xd0, 0x22, 0x16, 0x95, 0x45, 0x55, 0x21, 0x93, 0x78, 0x90, 0x69, 0x7d, 0x5a, - 0xc2, 0x48, 0x91, 0x09, 0x68, 0xf4, 0x05, 0x1d, 0x03, 0x15, 0x59, 0x14, 0xd8, 0x92, 0x6f, 0x07, 0x09, 0xdb, 0xf0, - 0x78, 0x3a, 0x4c, 0x82, 0x25, 0x5b, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x56, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, - 0x79, 0x6f, 0x9d, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x96, 0xeb, 0x0d, 0x7e, 0xe7, 0xec, 0xe7, 0x1b, 0xb5, 0xbf, 0x83, - 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xcf, 0xed, 0x2d, 0x7d, 0x67, - 0xb6, 0xe9, 0x7f, 0xb7, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xd6, 0x9f, 0x3c, - 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xcf, 0x3f, 0x8d, 0x76, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, - 0x68, 0xef, 0xe4, 0xb9, 0xbd, 0x23, 0xee, 0x78, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, - 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xf3, 0xd9, 0xa7, 0xf9, 0x64, 0xc7, 0x4f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, - 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x7b, 0x7e, 0xba, 0x89, 0x0f, 0xff, 0xed, - 0x4a, 0xef, 0xbf, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, + 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0x97, 0x13, 0x71, 0x4e, 0x97, 0x24, 0xf5, 0x54, 0x42, + 0x49, 0x08, 0x76, 0xe9, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, + 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xab, + 0x78, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8a, 0x4d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, + 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xac, 0xe4, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, + 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0x1f, 0x55, 0x36, 0x76, 0x07, 0xe4, 0x90, 0x64, 0xb2, 0xb8, 0x1b, 0xdd, + 0x8a, 0x65, 0x51, 0x8a, 0x9f, 0xb1, 0x1e, 0xae, 0xd9, 0xc2, 0x7d, 0x06, 0x84, 0xf6, 0x13, 0xa5, 0xbd, 0x89, 0x34, + 0x41, 0xf7, 0x1d, 0x5b, 0x01, 0xc8, 0x00, 0x8a, 0xba, 0xda, 0xad, 0xcf, 0xf9, 0x39, 0x92, 0x66, 0x38, 0x8c, 0x6e, + 0x9f, 0xde, 0x05, 0x77, 0x83, 0x4b, 0xd4, 0x4a, 0x5f, 0xb2, 0xb8, 0x85, 0x41, 0xb5, 0x37, 0x4b, 0x38, 0xa8, 0x99, + 0xb5, 0x36, 0x02, 0xc1, 0x64, 0x0f, 0x05, 0x15, 0x73, 0x05, 0xfb, 0xa0, 0x60, 0x2d, 0x79, 0x1d, 0x1c, 0x6e, 0xed, + 0xcb, 0x4a, 0x71, 0xf1, 0xfc, 0x22, 0x69, 0x5d, 0x58, 0xca, 0x8b, 0xe7, 0x0d, 0x18, 0x5c, 0x8e, 0xb0, 0xa9, 0x2a, + 0x7f, 0xb2, 0x01, 0xd0, 0xad, 0x90, 0x22, 0x5e, 0x94, 0xc2, 0xb6, 0x95, 0xcf, 0x9c, 0xb0, 0xc1, 0x86, 0x3d, 0xc0, + 0xbd, 0x32, 0x28, 0x19, 0x5c, 0x88, 0x71, 0xbb, 0xd9, 0x05, 0xb8, 0x82, 0xa1, 0x30, 0xb6, 0xe6, 0x6f, 0x32, 0x2f, + 0x52, 0x02, 0x6e, 0x86, 0x28, 0x5f, 0x1b, 0x38, 0x99, 0xf4, 0xe4, 0x5a, 0xb2, 0x18, 0xb0, 0xa0, 0xc1, 0x77, 0xd4, + 0xfa, 0x3b, 0x93, 0x7f, 0xe3, 0xe9, 0xa1, 0x1f, 0x7c, 0xce, 0xbc, 0xa5, 0xcf, 0xde, 0x54, 0x32, 0x5a, 0x93, 0x44, + 0x79, 0xf5, 0x70, 0x09, 0x72, 0xc3, 0x72, 0xf4, 0xc0, 0x96, 0x20, 0x4e, 0x2c, 0x47, 0x09, 0x65, 0x74, 0x85, 0x7b, + 0x95, 0xd9, 0x32, 0x11, 0x48, 0x71, 0x60, 0x29, 0xe5, 0xde, 0x62, 0x1d, 0x2c, 0x71, 0x7f, 0x22, 0xb9, 0x80, 0x92, + 0x07, 0x50, 0xae, 0x14, 0x10, 0xf0, 0xe9, 0x00, 0xca, 0x97, 0xf2, 0x22, 0xfc, 0x89, 0x13, 0x35, 0x58, 0x8e, 0x1e, + 0x1a, 0xf6, 0xa3, 0x17, 0x5a, 0xf6, 0x87, 0x3b, 0xad, 0x69, 0x58, 0xf1, 0x3b, 0x98, 0x16, 0x13, 0xb7, 0x2f, 0x57, + 0x76, 0x55, 0x7c, 0xb6, 0x52, 0x67, 0x37, 0x35, 0x24, 0x61, 0x5f, 0x91, 0x55, 0x80, 0x83, 0x55, 0x11, 0xf7, 0x2c, + 0xcb, 0x7d, 0x18, 0xfd, 0xb9, 0x49, 0x4b, 0x61, 0xa1, 0x4a, 0xfa, 0xfb, 0xa6, 0x14, 0x48, 0x65, 0xa2, 0x13, 0x2d, + 0x04, 0x57, 0x60, 0x10, 0xb8, 0x17, 0x79, 0x0d, 0x80, 0x31, 0xe0, 0x52, 0xa0, 0x2c, 0xdb, 0x12, 0x42, 0xaa, 0xfb, + 0x19, 0xa8, 0xed, 0xc4, 0x7d, 0x1a, 0x91, 0xb5, 0x10, 0x7d, 0x15, 0x8c, 0x99, 0xf3, 0x52, 0xba, 0xc5, 0xa6, 0xab, + 0xcd, 0xea, 0x06, 0x9d, 0x4b, 0x5b, 0x6e, 0x7e, 0xc2, 0x16, 0x6b, 0x05, 0xca, 0x26, 0x24, 0x6d, 0xe7, 0x3c, 0x47, + 0xd9, 0x84, 0x96, 0xf6, 0x9e, 0x7a, 0x54, 0xa8, 0x4e, 0xb6, 0x5e, 0xaa, 0xa6, 0x16, 0x61, 0xb5, 0xb8, 0xa8, 0xfc, + 0x00, 0x74, 0x53, 0x69, 0xf5, 0xb2, 0xae, 0xd1, 0x14, 0x6a, 0xb5, 0x70, 0xdc, 0x68, 0x67, 0xd3, 0x65, 0x7a, 0x87, + 0x38, 0xab, 0xd2, 0x0e, 0xfd, 0x7d, 0xa6, 0x5d, 0x2f, 0x3b, 0xfa, 0xcd, 0xb8, 0xba, 0xc0, 0x85, 0xd8, 0x80, 0xcf, + 0xb9, 0xbf, 0xbc, 0xde, 0xf3, 0xb8, 0xe7, 0x1f, 0x0e, 0xc8, 0x9e, 0xd4, 0xfe, 0x50, 0x7d, 0xec, 0x0a, 0x86, 0x2c, + 0x8c, 0x52, 0x7f, 0x91, 0xf2, 0xde, 0x13, 0x1c, 0xf7, 0xcf, 0x55, 0x8f, 0xfd, 0x98, 0xf1, 0x7d, 0x5d, 0x6c, 0xa2, + 0x84, 0xa2, 0x1a, 0x7a, 0xab, 0x62, 0x53, 0x89, 0xb8, 0x78, 0xc8, 0x7b, 0x0c, 0x93, 0x61, 0x2c, 0x64, 0x2a, 0xfc, + 0x29, 0x53, 0xc1, 0x23, 0x84, 0x12, 0x37, 0xeb, 0x1e, 0x69, 0x37, 0x21, 0x4e, 0xa9, 0x16, 0xa5, 0x4c, 0xc6, 0xbf, + 0xf5, 0x13, 0x28, 0xcf, 0x29, 0x5a, 0xa6, 0x1f, 0x15, 0x2e, 0xd3, 0x37, 0xeb, 0xe3, 0xd2, 0x33, 0x11, 0xea, 0xcc, + 0xc5, 0xa6, 0xd6, 0xe9, 0x18, 0x3b, 0xa5, 0x53, 0x1b, 0xf6, 0xa5, 0x52, 0x5c, 0x56, 0x14, 0xfe, 0x8d, 0x44, 0x56, + 0x3d, 0x23, 0x8e, 0xff, 0x2b, 0x6b, 0x9f, 0x61, 0x15, 0xf8, 0x65, 0x20, 0xef, 0x17, 0x00, 0x1f, 0xd7, 0x75, 0x99, + 0xde, 0x6e, 0x80, 0x36, 0x84, 0x86, 0xbf, 0xe7, 0x23, 0x03, 0xa6, 0xfb, 0x08, 0x67, 0x48, 0x0f, 0x75, 0xce, 0xe9, + 0xac, 0x4c, 0xe7, 0x5c, 0x85, 0xb5, 0x04, 0x7b, 0x39, 0x69, 0x72, 0xb9, 0x2e, 0x41, 0xcd, 0x04, 0x6e, 0x1f, 0xda, + 0x23, 0x42, 0xa8, 0x4d, 0x59, 0x4d, 0x2f, 0xa1, 0xe6, 0x9d, 0x9c, 0x76, 0x34, 0x29, 0xc1, 0x55, 0x43, 0x67, 0xe5, + 0xfa, 0xaf, 0xc3, 0xa1, 0x77, 0x9b, 0x15, 0xd1, 0x1f, 0x3d, 0xf4, 0x77, 0xdc, 0xde, 0xa4, 0x5f, 0x20, 0x5a, 0xc6, + 0xfa, 0x1b, 0x32, 0xa0, 0xe3, 0xc9, 0xf0, 0xb6, 0xd8, 0xf6, 0xd8, 0x17, 0xd4, 0x60, 0xe9, 0xeb, 0xc7, 0x1f, 0x20, + 0xa1, 0xea, 0xda, 0x17, 0x16, 0x4f, 0x98, 0xa7, 0x44, 0xdb, 0xc2, 0x87, 0xb0, 0xd0, 0x2f, 0x10, 0x19, 0x09, 0xe1, + 0xa6, 0xb2, 0x7b, 0x94, 0xb4, 0x0b, 0x7d, 0xe9, 0x6b, 0xd9, 0x57, 0xbe, 0x73, 0x01, 0xb0, 0xb2, 0xcf, 0x6d, 0xb8, + 0x27, 0xfd, 0x29, 0xd5, 0x87, 0xed, 0x6f, 0xc9, 0x02, 0x0a, 0x2d, 0xac, 0xa7, 0x72, 0x76, 0xae, 0x4b, 0x9e, 0x66, + 0xd3, 0xfd, 0x1a, 0xf6, 0xa8, 0x7b, 0xf4, 0x9a, 0x0a, 0xce, 0x2f, 0xcd, 0xe8, 0xfd, 0xd3, 0x50, 0xa8, 0x8e, 0x3a, + 0x77, 0x90, 0x75, 0x69, 0x5d, 0x72, 0x7e, 0xb3, 0x72, 0x47, 0x61, 0x7e, 0x1f, 0x82, 0x67, 0x58, 0xf7, 0xee, 0xe2, + 0xbc, 0xf7, 0x67, 0x6b, 0x8e, 0xfc, 0x98, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0xf6, 0xdb, + 0x20, 0x87, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, + 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xdb, 0x20, 0xd7, 0x5d, 0x30, 0xcd, 0x91, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x92, 0x0a, + 0xcd, 0x22, 0x6d, 0x95, 0x8c, 0x7f, 0x47, 0xda, 0x4c, 0xc9, 0x1e, 0x5b, 0x03, 0xef, 0x25, 0x28, 0x27, 0xc3, 0x14, + 0xc3, 0x77, 0x7c, 0xbd, 0xf3, 0x98, 0x7b, 0xce, 0x31, 0xdb, 0xa4, 0xec, 0x08, 0x26, 0xc9, 0xc6, 0x37, 0x14, 0x6f, + 0xf8, 0xfe, 0xb6, 0x12, 0x25, 0x80, 0x5e, 0x16, 0xfc, 0x85, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, + 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, + 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, + 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, + 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, + 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, + 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, + 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, + 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, 0xf3, 0xfd, 0x95, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, + 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, + 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, + 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, + 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, + 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, + 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, + 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, + 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, + 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, + 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, + 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, + 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, + 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, + 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, + 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, + 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, + 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, + 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, + 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, + 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, + 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, + 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, + 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd1, + 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, + 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe1, 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, + 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, + 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, + 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, + 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, + 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, + 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, + 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, + 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, + 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, + 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, + 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, + 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0x7c, 0xa1, 0x56, 0xda, 0x59, 0x99, + 0x78, 0x35, 0xcb, 0xc0, 0x59, 0xe0, 0xa2, 0xf2, 0x59, 0xa6, 0x55, 0x4f, 0x55, 0x82, 0x3e, 0xaf, 0xe4, 0x04, 0x57, + 0x82, 0x93, 0x0d, 0xc8, 0x2f, 0x40, 0x92, 0xa6, 0x94, 0x35, 0xe5, 0x8b, 0x4b, 0xba, 0x21, 0xa3, 0xe7, 0xbc, 0xe7, + 0x45, 0xc3, 0xd0, 0xbf, 0xf0, 0x4a, 0x08, 0xdf, 0xc4, 0x6d, 0x1b, 0xa5, 0xb0, 0xbf, 0x09, 0x2c, 0x3e, 0x61, 0x3f, + 0x78, 0x4b, 0x7f, 0x3a, 0x0e, 0xc2, 0x21, 0x72, 0x43, 0xc5, 0x1c, 0xd8, 0xd3, 0x80, 0xc5, 0x26, 0xbe, 0xda, 0x4c, + 0xe2, 0xc1, 0xc0, 0xd7, 0x19, 0x8b, 0x59, 0x0c, 0x34, 0xc8, 0xf1, 0xe0, 0x72, 0xae, 0x4f, 0x08, 0xfd, 0x30, 0xa2, + 0x72, 0x54, 0xa0, 0x73, 0x10, 0x0d, 0x96, 0x80, 0xa7, 0xde, 0xca, 0x06, 0x49, 0xc6, 0x24, 0x93, 0xb8, 0xd6, 0x24, + 0xd5, 0xe1, 0x84, 0xd6, 0x81, 0x8e, 0xab, 0x0b, 0xe8, 0x7c, 0x5c, 0xf7, 0x3e, 0x5e, 0x0d, 0x17, 0x54, 0xfa, 0x85, + 0x18, 0x78, 0xf5, 0x74, 0x1c, 0x5c, 0xd2, 0xad, 0x70, 0xb1, 0x0a, 0xb7, 0x3f, 0xcb, 0x07, 0x8e, 0x3b, 0x2a, 0x69, + 0x08, 0x0c, 0xde, 0x1e, 0xba, 0x9b, 0x19, 0x1a, 0xea, 0xa4, 0x7d, 0x18, 0x87, 0x72, 0x88, 0x55, 0x2b, 0x2e, 0xa4, + 0x37, 0x82, 0x6f, 0x17, 0x8a, 0xb1, 0x6c, 0xec, 0xd2, 0x50, 0x14, 0xfe, 0x0a, 0x60, 0x87, 0xda, 0x5f, 0xa9, 0xe4, + 0x63, 0x64, 0x54, 0xd3, 0x40, 0xc7, 0x00, 0x2c, 0x59, 0x9a, 0x48, 0xaa, 0x48, 0x23, 0xf1, 0x47, 0x66, 0xac, 0xa3, + 0xa6, 0xeb, 0x0b, 0xa6, 0xaa, 0x45, 0xd2, 0xed, 0x4c, 0x62, 0x39, 0x91, 0xa4, 0xb6, 0xfb, 0x88, 0x18, 0x0c, 0x7c, + 0xb0, 0x11, 0xd3, 0x4c, 0x84, 0x23, 0x1e, 0x95, 0xc8, 0xa2, 0xcb, 0x6f, 0xa3, 0x4c, 0xda, 0xbe, 0xac, 0xc8, 0x16, + 0x04, 0xd3, 0x93, 0xe8, 0x83, 0x24, 0xe5, 0x54, 0x24, 0xd2, 0x8c, 0x10, 0xe0, 0xc7, 0x93, 0xf2, 0x4a, 0x7f, 0x0e, + 0x9a, 0x56, 0x82, 0x97, 0x0c, 0x92, 0x47, 0xe2, 0x67, 0x52, 0x30, 0x8b, 0xb1, 0x6a, 0x30, 0xc0, 0x72, 0xaa, 0x67, + 0x8e, 0x49, 0xfa, 0x6f, 0x9d, 0x4e, 0xd8, 0x2f, 0xbd, 0xdc, 0xd6, 0xf2, 0xa6, 0xb9, 0xf7, 0xd2, 0xab, 0x58, 0xaa, + 0x61, 0x19, 0xf4, 0x5f, 0x13, 0xed, 0x82, 0xad, 0x2d, 0x63, 0xc2, 0xaa, 0x1f, 0x40, 0xda, 0x23, 0x5d, 0x5e, 0x35, + 0xcc, 0x99, 0xe0, 0xd1, 0x85, 0x35, 0x0f, 0xa2, 0x0b, 0xe1, 0x23, 0x97, 0xdd, 0x24, 0xb9, 0x1a, 0x4f, 0xfc, 0x70, + 0x30, 0x50, 0x00, 0xb4, 0xb4, 0x4e, 0x8a, 0x41, 0xf8, 0x4c, 0xc8, 0x81, 0x34, 0x3a, 0xaa, 0x02, 0x2c, 0x96, 0xd9, + 0x55, 0x39, 0xc9, 0x06, 0x03, 0x1f, 0xc4, 0xc6, 0xc4, 0x6e, 0x68, 0x36, 0xf7, 0xd9, 0x89, 0x82, 0xac, 0x36, 0x87, + 0xad, 0x99, 0x6e, 0x81, 0x01, 0xc0, 0x20, 0x22, 0x58, 0xee, 0x73, 0x23, 0x1f, 0x51, 0xa7, 0xa7, 0x30, 0x02, 0x82, + 0x5f, 0x4e, 0x04, 0x22, 0x17, 0x09, 0xd4, 0x03, 0xcc, 0x04, 0x98, 0x51, 0xc5, 0xf0, 0x12, 0xd8, 0xc5, 0x73, 0xf3, + 0x8a, 0x41, 0xff, 0xa2, 0x49, 0x96, 0x68, 0x2a, 0x71, 0x34, 0x46, 0x4e, 0xa5, 0x31, 0x32, 0x20, 0x76, 0x71, 0xfc, + 0x7b, 0x4a, 0x8f, 0x82, 0x94, 0x7d, 0xae, 0x0c, 0x71, 0x38, 0x8a, 0xaf, 0x60, 0xd5, 0x38, 0x1c, 0x6a, 0xf3, 0x7a, + 0x3a, 0xab, 0xe7, 0x03, 0x11, 0xc0, 0x7f, 0x43, 0xc1, 0x7e, 0xd1, 0x54, 0xe4, 0x06, 0xa9, 0xf3, 0x70, 0x48, 0x41, + 0x3e, 0xd5, 0x4d, 0xfe, 0xbe, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, + 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, + 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, + 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, + 0x7f, 0x95, 0xee, 0xcd, 0xa9, 0x0d, 0x72, 0x00, 0xdb, 0xbd, 0x87, 0xdb, 0x31, 0x7a, 0x20, 0x83, 0x37, 0x42, 0xce, + 0x39, 0xbf, 0x9c, 0x5a, 0x33, 0x26, 0x1a, 0x16, 0xac, 0x1c, 0x46, 0x7e, 0x80, 0x8c, 0x97, 0x53, 0x60, 0x65, 0x3f, + 0x2a, 0xe2, 0xd2, 0x1f, 0x46, 0xfe, 0xc5, 0xf3, 0x20, 0xe3, 0x5e, 0x34, 0xec, 0xf8, 0x02, 0xec, 0xd5, 0x17, 0xcf, + 0x59, 0x34, 0xe0, 0xd5, 0x55, 0x3d, 0xcd, 0x82, 0x61, 0xc6, 0xa2, 0xab, 0x62, 0x08, 0x3e, 0xb4, 0x2f, 0xca, 0x41, + 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x47, 0x70, 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, + 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x85, 0xd4, 0x6c, 0x14, 0x68, 0x4e, 0xae, 0xd0, 0x9c, + 0xac, 0x84, 0x5a, 0xf2, 0x49, 0x85, 0x13, 0x76, 0x3e, 0xc9, 0x95, 0xdd, 0x68, 0x8c, 0x81, 0x8b, 0xf6, 0xdc, 0x16, + 0x46, 0x66, 0x3a, 0x4b, 0xd1, 0x80, 0x85, 0x67, 0xe2, 0x94, 0xc6, 0x80, 0xf6, 0xe5, 0xc0, 0xd2, 0x86, 0xfc, 0x28, + 0x67, 0x06, 0xda, 0x86, 0x94, 0x46, 0xcd, 0xc0, 0x9f, 0xa9, 0x09, 0xf3, 0x2b, 0x58, 0x89, 0x20, 0xaa, 0x0b, 0x30, + 0x49, 0x72, 0x32, 0x1a, 0x29, 0x2b, 0x91, 0x9c, 0x03, 0xde, 0x47, 0xf0, 0x64, 0x11, 0xdb, 0xda, 0x9f, 0xd2, 0xff, + 0xea, 0xf0, 0xb9, 0xf4, 0x9f, 0x09, 0x60, 0x21, 0x97, 0x06, 0x91, 0x81, 0xc2, 0x21, 0x35, 0x95, 0x88, 0x13, 0xc7, + 0x33, 0xf0, 0x0d, 0x5c, 0xa0, 0x29, 0xa0, 0x3f, 0xa8, 0x19, 0x45, 0x64, 0xe1, 0xaf, 0x9e, 0xdd, 0xd4, 0x8d, 0x9e, + 0x67, 0xce, 0x6b, 0xd0, 0xcc, 0x40, 0x48, 0x8f, 0x53, 0xf5, 0x36, 0x24, 0x3a, 0x2f, 0x2f, 0xf5, 0xcb, 0x84, 0x48, + 0x56, 0x44, 0x9e, 0xbe, 0xcf, 0xc1, 0x3c, 0xa2, 0x08, 0x1d, 0x5c, 0x99, 0x87, 0xc3, 0xb9, 0xa0, 0xf0, 0x1d, 0xe5, + 0xf9, 0x80, 0xd3, 0x2c, 0x4a, 0x40, 0x1b, 0xc8, 0x72, 0x53, 0xe6, 0x3a, 0x69, 0x99, 0xba, 0xf7, 0x60, 0x25, 0xa8, + 0xd0, 0xcd, 0x29, 0x28, 0x94, 0x91, 0xa0, 0x94, 0x56, 0x83, 0x50, 0xaa, 0xc3, 0x22, 0x88, 0x1c, 0xb2, 0x10, 0x70, + 0x33, 0x15, 0x8d, 0x96, 0x34, 0x3c, 0xc2, 0xb9, 0x81, 0x42, 0x00, 0x12, 0x7b, 0xaa, 0x28, 0xe3, 0x72, 0x08, 0xf8, + 0x28, 0xe1, 0x10, 0x67, 0x4d, 0xda, 0xf2, 0x1c, 0xc4, 0xb1, 0x5c, 0xf2, 0x75, 0x85, 0x60, 0x10, 0xa1, 0xcf, 0x90, + 0x3f, 0x59, 0xce, 0xbf, 0x5b, 0x87, 0x69, 0x47, 0xf8, 0xb0, 0xab, 0x2d, 0xb8, 0x98, 0xdd, 0xce, 0x27, 0x10, 0xdf, + 0x72, 0x3b, 0x3f, 0xc6, 0x10, 0x59, 0xf8, 0x83, 0xbb, 0xa1, 0xe4, 0x8a, 0x42, 0x97, 0xf5, 0x88, 0x14, 0xd9, 0xd3, + 0x35, 0x47, 0x10, 0x1c, 0x68, 0xd5, 0x20, 0x43, 0x23, 0xf1, 0xc5, 0x73, 0xc8, 0x1a, 0xac, 0xf9, 0xe7, 0x8a, 0x9c, + 0xd5, 0xfd, 0xc9, 0x06, 0xaa, 0x49, 0x26, 0x6b, 0x45, 0xe5, 0xfc, 0xf5, 0xaa, 0x2c, 0x4f, 0x56, 0x65, 0xb8, 0x1a, + 0x74, 0x55, 0x65, 0xc9, 0x91, 0xda, 0x00, 0xad, 0xe9, 0x0a, 0x31, 0x14, 0xb2, 0x06, 0x4b, 0xab, 0x2a, 0x6b, 0xea, + 0x13, 0x08, 0xf4, 0x01, 0x96, 0x51, 0xb3, 0x9f, 0x0e, 0xff, 0x15, 0xfc, 0x4b, 0x85, 0x2c, 0xd5, 0x69, 0x9d, 0x89, + 0x5f, 0x83, 0x25, 0xc3, 0x3f, 0x7e, 0x0b, 0xd6, 0x80, 0x25, 0x40, 0x96, 0xbb, 0x8d, 0x8d, 0xd6, 0x2b, 0xaf, 0x10, + 0x5f, 0x6a, 0x7d, 0xd1, 0x6f, 0xdd, 0x26, 0x6a, 0x05, 0x18, 0xa1, 0xd0, 0x22, 0xc0, 0x56, 0x0f, 0xdc, 0x53, 0xf0, + 0x03, 0x31, 0x9c, 0x6b, 0xd2, 0x9a, 0x3a, 0xe1, 0x75, 0x36, 0x8e, 0x44, 0x54, 0x6f, 0xe1, 0xe2, 0x5e, 0x6f, 0x2d, + 0xfe, 0x46, 0x05, 0x02, 0x20, 0x8b, 0x29, 0xd6, 0xce, 0x1b, 0xd2, 0x2b, 0xc3, 0x4e, 0x42, 0xef, 0x0d, 0x3b, 0x81, + 0xbc, 0x38, 0xec, 0x14, 0xba, 0x44, 0xdb, 0x29, 0x52, 0x13, 0x6d, 0x27, 0x2d, 0x56, 0x61, 0x09, 0xc1, 0xaf, 0xda, + 0x5b, 0x47, 0xd9, 0xbe, 0xc8, 0x12, 0xa6, 0x2d, 0x60, 0x94, 0x5b, 0xf5, 0x99, 0x53, 0xc4, 0x4a, 0xd9, 0x3b, 0x9d, + 0x54, 0xb9, 0x8b, 0x7c, 0x6a, 0x35, 0x45, 0x26, 0x7f, 0x7f, 0xdc, 0x22, 0xf9, 0xe4, 0xe7, 0x76, 0xc3, 0x64, 0xfa, + 0xc7, 0xa3, 0x2f, 0xa0, 0x2b, 0xb2, 0xd3, 0x27, 0x10, 0x90, 0xa9, 0xa0, 0x5a, 0xdd, 0x2a, 0xa6, 0x79, 0xbb, 0xca, + 0x6e, 0x2f, 0x94, 0x18, 0x4e, 0x67, 0x27, 0xe1, 0xd1, 0x66, 0xc8, 0xc0, 0x21, 0x08, 0x14, 0x42, 0x45, 0x31, 0x3c, + 0x02, 0xb5, 0x46, 0xf2, 0x01, 0x7e, 0xb4, 0x3b, 0x15, 0x44, 0x6a, 0x37, 0x15, 0x37, 0x4e, 0x6e, 0xba, 0x5e, 0x0a, + 0xd4, 0x3a, 0x25, 0x2b, 0x80, 0x12, 0xa2, 0xfe, 0x24, 0xb6, 0xf5, 0x2b, 0xb8, 0x62, 0xf3, 0x7d, 0xa3, 0xe8, 0xc9, + 0xf5, 0x29, 0xea, 0x56, 0x5c, 0x9d, 0xa6, 0xad, 0xe6, 0xd8, 0x71, 0x86, 0x1c, 0x3c, 0x2b, 0x08, 0xb6, 0xa3, 0x12, + 0xe5, 0x75, 0xbb, 0xe9, 0x98, 0xd8, 0xea, 0x9f, 0x45, 0xb5, 0xb9, 0x83, 0x8a, 0x88, 0xf8, 0x28, 0xbb, 0x79, 0xd2, + 0x7e, 0x07, 0x7b, 0xac, 0xd5, 0x20, 0xb2, 0xcf, 0xe0, 0x2a, 0xd7, 0x69, 0x91, 0xdb, 0x32, 0x38, 0xff, 0xf0, 0x6a, + 0x57, 0x61, 0x93, 0x63, 0x5d, 0x5d, 0xcd, 0x54, 0x27, 0x15, 0x1b, 0x18, 0x6b, 0x5a, 0x4b, 0x35, 0x8f, 0x21, 0xe9, + 0xae, 0x2c, 0xce, 0xaa, 0xa4, 0x9b, 0x9e, 0x1b, 0x67, 0x0a, 0x31, 0x70, 0xb6, 0x1a, 0x2d, 0x67, 0x18, 0xa2, 0xeb, + 0xc3, 0x2c, 0xf1, 0x5b, 0x3d, 0xe5, 0x3e, 0x0f, 0xb7, 0x7e, 0x57, 0x2f, 0x38, 0x99, 0xec, 0x27, 0xc7, 0xb9, 0xdb, + 0x45, 0xda, 0x4f, 0x7c, 0x1b, 0xe6, 0x5f, 0xdf, 0x20, 0xee, 0x44, 0xfd, 0xcf, 0x0a, 0x80, 0x06, 0x37, 0x79, 0x2c, + 0x51, 0xea, 0xf7, 0xaa, 0xfa, 0x41, 0xcd, 0x54, 0x4d, 0x03, 0xc1, 0x9c, 0x4a, 0x01, 0x7f, 0xb8, 0x5d, 0xb8, 0xe2, + 0x11, 0x37, 0x2c, 0x8c, 0x7f, 0x7a, 0x35, 0x3b, 0x15, 0x54, 0x06, 0x6e, 0xc6, 0x7f, 0x7a, 0x82, 0x9d, 0xc2, 0x5a, + 0x01, 0x59, 0xe1, 0x4f, 0x2f, 0x7f, 0xe4, 0xfd, 0x8a, 0xff, 0xe9, 0x55, 0x8f, 0xbc, 0x8f, 0x38, 0x2f, 0x7f, 0x22, + 0xa9, 0x13, 0xa2, 0xba, 0xfc, 0x49, 0x98, 0x62, 0xab, 0x34, 0x7f, 0x4d, 0x0a, 0x9f, 0xe0, 0x33, 0xf0, 0x1d, 0xae, + 0xc2, 0xad, 0xf9, 0x0d, 0x1e, 0x3b, 0x16, 0xdb, 0x2e, 0xf5, 0x05, 0x94, 0x23, 0xb0, 0x88, 0xdc, 0x7e, 0xbb, 0xb2, + 0x5f, 0x2d, 0x8c, 0x32, 0xc6, 0xee, 0x4b, 0x56, 0xa2, 0x74, 0xd6, 0xef, 0x17, 0x52, 0x30, 0xb2, 0x0b, 0x6b, 0xb4, + 0x47, 0xa9, 0x7a, 0xf5, 0x3a, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, + 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, + 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, + 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0x5e, 0xe4, 0x18, 0x5b, 0x91, 0x03, 0x07, 0x32, 0xfc, 0x80, 0xc0, + 0x7b, 0xd9, 0xbf, 0x82, 0xc1, 0x30, 0xc1, 0x8d, 0x8c, 0x3a, 0x39, 0x67, 0x7f, 0x62, 0x60, 0x06, 0xf5, 0xa4, 0x76, + 0x9f, 0xdd, 0xab, 0xc0, 0x5e, 0x38, 0x03, 0xda, 0xbb, 0x31, 0xfa, 0x59, 0x15, 0x6b, 0x27, 0xfd, 0x53, 0xb1, 0x86, + 0x64, 0x3a, 0x2c, 0x8e, 0xb6, 0x69, 0x78, 0x24, 0x4f, 0x8e, 0xe3, 0x4d, 0xff, 0x70, 0x18, 0xe3, 0xc7, 0x51, 0x7e, + 0x6d, 0x01, 0xaf, 0xe2, 0x16, 0xd2, 0x58, 0xa4, 0xe8, 0x1d, 0x88, 0x39, 0x14, 0xbd, 0x64, 0xbf, 0x65, 0xbc, 0x9c, + 0x08, 0x4a, 0x49, 0x62, 0xc3, 0x3b, 0xd2, 0xd3, 0xb4, 0x1e, 0x6d, 0x65, 0xc0, 0x7e, 0x3d, 0xda, 0xd1, 0x5f, 0xa0, + 0x78, 0xb4, 0xf0, 0x97, 0xf4, 0x77, 0x71, 0x37, 0xf7, 0x9c, 0x6f, 0x1a, 0xdf, 0x11, 0x17, 0x28, 0xd6, 0xec, 0xfe, + 0x9a, 0x96, 0xce, 0x3a, 0x10, 0x1c, 0xf0, 0x16, 0xbb, 0x68, 0xdf, 0x6f, 0x5c, 0xa7, 0xa7, 0xfd, 0xb7, 0x6e, 0x8d, + 0xf2, 0xbd, 0x7f, 0x4a, 0x94, 0x83, 0xfd, 0x6b, 0x17, 0xcd, 0xdf, 0x7e, 0xca, 0x90, 0x54, 0x68, 0x6e, 0xb0, 0x9d, + 0x6c, 0x11, 0xd6, 0xc6, 0x38, 0xa8, 0xd8, 0x5d, 0x19, 0x46, 0xc0, 0xa0, 0x8e, 0xfd, 0x8f, 0x3e, 0x9b, 0x36, 0x64, + 0x1f, 0x00, 0x2a, 0x57, 0x21, 0x60, 0x0f, 0xc0, 0x89, 0x46, 0xb8, 0x01, 0x6e, 0x35, 0x5a, 0xd2, 0x41, 0xdd, 0x16, + 0x0c, 0x44, 0x4b, 0xd8, 0xc8, 0xdb, 0xae, 0x4e, 0x5f, 0x11, 0x3e, 0xd4, 0x4e, 0x4a, 0x87, 0xf2, 0x57, 0xcf, 0xd9, + 0xff, 0xec, 0xb0, 0xa6, 0xa6, 0xdc, 0x00, 0x66, 0xce, 0x4a, 0xe4, 0x15, 0x42, 0xa7, 0xc8, 0xef, 0x55, 0x5d, 0x89, + 0xe1, 0xb2, 0x16, 0x65, 0x67, 0x76, 0xeb, 0x44, 0xef, 0x9c, 0x82, 0x5a, 0x2a, 0x1b, 0xe4, 0x24, 0xd5, 0xe6, 0x23, + 0x6b, 0x05, 0x25, 0xea, 0x1a, 0x05, 0x8e, 0x4f, 0xb9, 0x76, 0xff, 0xef, 0x9c, 0x09, 0x6a, 0xb6, 0x51, 0xdd, 0x5f, + 0xeb, 0xa7, 0xaa, 0x26, 0xb1, 0x00, 0x97, 0x93, 0x34, 0xef, 0x78, 0x84, 0xd5, 0x3f, 0x4e, 0x96, 0x22, 0xd0, 0xeb, + 0x88, 0x76, 0x25, 0x20, 0x41, 0x3b, 0x39, 0x0b, 0x15, 0x81, 0x02, 0x7d, 0xfd, 0xfb, 0x4d, 0x9a, 0xc5, 0x72, 0x35, + 0xdb, 0xc3, 0x44, 0x59, 0xac, 0x87, 0x08, 0x72, 0x66, 0xea, 0x60, 0xbf, 0xa7, 0x19, 0xcd, 0xc2, 0x2b, 0x53, 0x82, + 0x4b, 0x71, 0x15, 0x15, 0x39, 0xf8, 0x1c, 0xe2, 0x0b, 0x9f, 0x0a, 0xb9, 0x41, 0x44, 0xd3, 0xef, 0x25, 0xaa, 0x1d, + 0x29, 0x90, 0x43, 0xc9, 0x4f, 0x88, 0xbf, 0x64, 0x6d, 0x8c, 0xfb, 0xa5, 0x53, 0xed, 0x57, 0x0a, 0xc1, 0xfd, 0x67, + 0x5b, 0x6c, 0x54, 0x79, 0xa2, 0x47, 0x9f, 0x62, 0xfd, 0x4f, 0x16, 0x50, 0xaa, 0xfb, 0x36, 0x38, 0x15, 0x8f, 0xc2, + 0x4d, 0x5d, 0xdc, 0x20, 0xb4, 0x40, 0x39, 0xaa, 0x8a, 0x4d, 0x19, 0x11, 0x27, 0xec, 0xa6, 0x2e, 0x7a, 0x9a, 0x03, + 0x9d, 0x3a, 0x2c, 0x4d, 0xe4, 0x89, 0xd0, 0x6e, 0x41, 0xf7, 0x34, 0xc7, 0x4a, 0xbc, 0x94, 0xa5, 0x83, 0xac, 0x13, + 0x69, 0x42, 0xe5, 0xae, 0xae, 0x3a, 0x2a, 0x95, 0xba, 0xe1, 0x4d, 0xaa, 0x19, 0x7f, 0x97, 0xe6, 0x4f, 0x2c, 0xfb, + 0x4d, 0xeb, 0xb7, 0x5a, 0xed, 0x8d, 0xd5, 0xa3, 0x92, 0x35, 0xc7, 0xd9, 0x84, 0xa4, 0xf4, 0x09, 0xdb, 0xcd, 0xa4, + 0x6b, 0x1d, 0x78, 0x12, 0x5c, 0x0e, 0x3d, 0x01, 0x15, 0x83, 0x26, 0xde, 0xee, 0x02, 0xf5, 0x08, 0x3c, 0x03, 0xe5, + 0x13, 0xb5, 0x0e, 0xf8, 0x79, 0xad, 0xe5, 0x29, 0x23, 0x0c, 0xab, 0x9d, 0x45, 0xcb, 0xc1, 0x79, 0xa7, 0x08, 0x5c, + 0xbb, 0x12, 0x78, 0x3e, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, 0xa7, + 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, 0x36, + 0x9f, 0x7d, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, 0xcf, + 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, 0x76, + 0x7c, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, 0x88, + 0xc2, 0x2c, 0xfb, 0xb1, 0x28, 0xfe, 0xa8, 0xf4, 0x1d, 0x81, 0x8e, 0xee, 0xbc, 0xa8, 0xd3, 0xe5, 0xee, 0x03, 0x61, + 0x3c, 0x79, 0xf5, 0x11, 0xd1, 0xad, 0xef, 0x33, 0xf7, 0x2b, 0xc0, 0x8d, 0xe0, 0x0e, 0xa2, 0xbd, 0x5b, 0xea, 0x93, + 0x5a, 0x7d, 0xad, 0xd7, 0xce, 0xd3, 0xf3, 0x9b, 0xce, 0xed, 0x77, 0xdf, 0x1c, 0x6d, 0xbd, 0xc7, 0x85, 0xb5, 0xb2, + 0xf4, 0x54, 0x15, 0xec, 0xcd, 0xf2, 0x54, 0x15, 0x4c, 0x1e, 0x78, 0xcd, 0x7e, 0x41, 0x83, 0x2b, 0x1d, 0x6d, 0xbc, + 0x27, 0x6a, 0xe0, 0x16, 0x85, 0xa5, 0xc3, 0x2f, 0xb9, 0x99, 0xbc, 0xc2, 0xfd, 0xa5, 0x22, 0x17, 0xfb, 0xce, 0x19, + 0xdd, 0x99, 0x59, 0xf7, 0xaa, 0xc2, 0xd5, 0x82, 0x5c, 0x1d, 0xd8, 0x5a, 0x76, 0x71, 0xb8, 0x61, 0x11, 0x05, 0x08, + 0xc4, 0xf4, 0x4a, 0xad, 0xfd, 0x11, 0x0d, 0x42, 0x3e, 0x18, 0xf8, 0x05, 0x06, 0xab, 0x02, 0x85, 0x0f, 0x14, 0xc9, + 0x5f, 0x7b, 0x02, 0x76, 0xf1, 0x0c, 0xd0, 0xad, 0xd8, 0xac, 0x18, 0x21, 0x42, 0x26, 0xcb, 0x59, 0x4d, 0x67, 0x90, + 0x4f, 0x7d, 0xf1, 0x8d, 0xad, 0x3a, 0x9d, 0xb7, 0x35, 0x55, 0x4e, 0x1d, 0x0a, 0xdd, 0xdd, 0xd4, 0x9d, 0x5b, 0x17, + 0x79, 0xea, 0x10, 0x72, 0xa5, 0x62, 0x25, 0xa6, 0xa1, 0xe6, 0x49, 0x9a, 0x51, 0x7f, 0xb1, 0xf7, 0x7b, 0x8d, 0xc2, + 0x29, 0x7f, 0x3a, 0x06, 0x55, 0xb8, 0xaa, 0x21, 0x8e, 0xa5, 0x2a, 0x1e, 0xd9, 0x20, 0xd0, 0xbc, 0xba, 0x55, 0x49, + 0x13, 0x32, 0xb9, 0x11, 0x3e, 0x35, 0x29, 0xe5, 0x69, 0xda, 0xa4, 0x95, 0x22, 0x75, 0xf0, 0x41, 0x9d, 0x6a, 0x3c, + 0x37, 0xab, 0x17, 0x00, 0x66, 0x9c, 0x5f, 0xf1, 0x4b, 0xc5, 0x65, 0xd4, 0x56, 0x66, 0xd2, 0xfe, 0xe4, 0x68, 0x6c, + 0xd4, 0xe5, 0xb4, 0x51, 0x46, 0x58, 0x29, 0xcd, 0x49, 0xb1, 0x1c, 0xcf, 0x3f, 0x60, 0xb0, 0xe6, 0x09, 0xec, 0x60, + 0xa2, 0x52, 0xde, 0x47, 0x40, 0x7c, 0x9d, 0xa4, 0x77, 0x09, 0xa4, 0x48, 0xff, 0xd2, 0x25, 0x77, 0x19, 0x1b, 0x88, + 0x31, 0x2b, 0x66, 0x46, 0xff, 0x83, 0xbb, 0xa4, 0x3f, 0x09, 0x01, 0x70, 0x13, 0x4d, 0xa1, 0x53, 0xe7, 0xc9, 0x45, + 0x1e, 0x2c, 0x2f, 0x3c, 0xb4, 0x62, 0xc4, 0x83, 0xbf, 0xbe, 0x08, 0x11, 0xc4, 0x1c, 0x53, 0x3c, 0xfd, 0xc2, 0xe8, + 0x2f, 0xc1, 0x25, 0x46, 0x10, 0xba, 0x7b, 0xe7, 0x30, 0x84, 0x9b, 0x3d, 0xc8, 0xa0, 0xfe, 0x50, 0x87, 0x44, 0x0d, + 0x7f, 0xac, 0x3c, 0xe8, 0xff, 0x3a, 0x13, 0x96, 0xda, 0x4f, 0x4f, 0x07, 0x50, 0xc1, 0xfb, 0x8a, 0xb7, 0x11, 0xf1, + 0x7d, 0xe2, 0x67, 0xf1, 0x60, 0xf3, 0x6c, 0x03, 0xd6, 0xba, 0x27, 0xb9, 0xb1, 0xae, 0x12, 0x36, 0x10, 0xf0, 0x35, + 0x8a, 0xda, 0xf3, 0xda, 0xed, 0x1e, 0xfc, 0xd5, 0xbf, 0x08, 0x19, 0x30, 0x71, 0xfa, 0x3e, 0x73, 0xb2, 0x46, 0x17, + 0x99, 0x4c, 0x1f, 0x3a, 0xe9, 0x1b, 0x9d, 0xee, 0x3b, 0xe1, 0x1f, 0x15, 0xb3, 0xf8, 0x70, 0x4b, 0x5f, 0x69, 0x52, + 0xdc, 0x01, 0x2b, 0x9b, 0x47, 0x05, 0xa1, 0xce, 0x45, 0xf4, 0x95, 0x29, 0xdf, 0x12, 0x6a, 0xf6, 0x8d, 0x25, 0xa5, + 0x74, 0xaf, 0xa1, 0x37, 0x69, 0xad, 0xdf, 0x46, 0x09, 0xc6, 0x44, 0xc7, 0x93, 0x97, 0xf1, 0x58, 0x79, 0x1f, 0x8f, + 0x1b, 0xa9, 0x90, 0x07, 0x20, 0x02, 0x15, 0xe3, 0x4f, 0x57, 0x9e, 0x9c, 0xf4, 0xc2, 0x78, 0x15, 0x4a, 0x41, 0x61, + 0x40, 0x57, 0x20, 0x05, 0x3c, 0x6a, 0x4f, 0x74, 0x16, 0x76, 0x09, 0xf7, 0xe8, 0x26, 0x60, 0xac, 0xcf, 0x3f, 0x02, + 0x9a, 0xbb, 0x70, 0x87, 0x17, 0x03, 0xd4, 0xa6, 0x5e, 0xdd, 0x7d, 0x5c, 0xab, 0x73, 0x38, 0x04, 0x07, 0xab, 0x41, + 0x04, 0xa7, 0xf3, 0xa9, 0xa3, 0x59, 0x16, 0xa0, 0x72, 0xb2, 0xdc, 0xc8, 0x9b, 0x47, 0x8b, 0x5e, 0xdd, 0xf7, 0x96, + 0x69, 0x59, 0xd5, 0x41, 0xc6, 0xb2, 0xb0, 0x02, 0x5c, 0x1d, 0x5a, 0x3f, 0x08, 0x97, 0x85, 0xf3, 0x07, 0x42, 0x10, + 0xbb, 0x57, 0xdb, 0x92, 0xe7, 0x6a, 0x0e, 0x3f, 0x7b, 0xce, 0xd6, 0x5c, 0xa2, 0x4e, 0x3a, 0x13, 0x01, 0x88, 0x3d, + 0x35, 0xab, 0xe8, 0x1a, 0x48, 0xea, 0x34, 0xab, 0xe8, 0x9a, 0x9a, 0x6d, 0x8c, 0x03, 0xf9, 0x68, 0x95, 0x02, 0xf6, + 0xdd, 0x74, 0x1c, 0xac, 0x9e, 0xc5, 0xf2, 0x3a, 0x74, 0xf7, 0x6c, 0xa3, 0x7c, 0x06, 0x75, 0xab, 0x8d, 0x31, 0xb1, + 0xdd, 0x7c, 0x39, 0xd7, 0x6f, 0x07, 0x4b, 0xdf, 0x0e, 0x9a, 0x73, 0xca, 0xbe, 0xd3, 0x65, 0xaf, 0xec, 0xb2, 0xa9, + 0xe7, 0x8e, 0x8a, 0x56, 0x63, 0x40, 0x6f, 0x60, 0xc1, 0xfa, 0x5c, 0xa4, 0xd9, 0xaa, 0x54, 0x25, 0xe0, 0x85, 0xb1, + 0x62, 0x77, 0x7e, 0x23, 0x33, 0x24, 0x61, 0x1e, 0x67, 0xe2, 0x9a, 0xee, 0xb5, 0x30, 0x39, 0x8e, 0x45, 0x32, 0x25, + 0x74, 0x4a, 0x77, 0xb6, 0xa1, 0x73, 0x15, 0x46, 0x11, 0xad, 0x95, 0x54, 0x1a, 0x09, 0x4c, 0xcd, 0x00, 0x25, 0x73, + 0x05, 0x4e, 0xe9, 0x72, 0xff, 0x3b, 0x12, 0xe3, 0xcc, 0x17, 0x25, 0x33, 0xa0, 0x5b, 0x7e, 0x5d, 0xac, 0x5b, 0x29, + 0x32, 0xc2, 0xbc, 0x39, 0x6e, 0xaf, 0xeb, 0x43, 0x20, 0x57, 0xcb, 0x1e, 0x45, 0xe3, 0xa0, 0xd0, 0xe1, 0x52, 0x25, + 0xc0, 0xbe, 0x48, 0xfc, 0x8c, 0xb0, 0xa5, 0x3d, 0x90, 0xdb, 0xa3, 0x33, 0x61, 0xce, 0x39, 0x29, 0xcb, 0xce, 0xa5, + 0x19, 0x5c, 0x4e, 0x5c, 0x09, 0x2e, 0xd2, 0xdb, 0xf6, 0x34, 0x69, 0x69, 0xfb, 0xd8, 0x70, 0x8e, 0x86, 0xb6, 0x41, + 0x77, 0xec, 0x0f, 0xcd, 0xc5, 0x22, 0xb6, 0x2e, 0x16, 0xc3, 0xce, 0xec, 0x47, 0x8b, 0x05, 0xc8, 0x01, 0xe0, 0xa8, + 0xdb, 0xf0, 0x31, 0x5b, 0x02, 0xa7, 0xd5, 0x34, 0x9b, 0x7a, 0x1b, 0x5e, 0x3d, 0x53, 0x3d, 0xbd, 0xe4, 0xf9, 0x33, + 0x61, 0xc6, 0x62, 0xc3, 0xf3, 0x67, 0xd6, 0x91, 0x53, 0x3d, 0x13, 0x4a, 0xb4, 0x2e, 0xa0, 0x19, 0x78, 0x4d, 0x01, + 0x23, 0x96, 0x4c, 0xa6, 0x54, 0x91, 0xc7, 0xbd, 0xe9, 0x46, 0x0d, 0x5e, 0x50, 0x38, 0x04, 0x52, 0x3a, 0xfd, 0xe2, + 0x39, 0xd3, 0xef, 0x5d, 0x3c, 0xef, 0x90, 0xb5, 0x0d, 0xd3, 0xe5, 0x66, 0x98, 0x0c, 0x4a, 0xff, 0x99, 0x99, 0x18, + 0x17, 0xd6, 0x24, 0x01, 0xc4, 0xbf, 0xb1, 0xdf, 0x21, 0x85, 0x9b, 0xf7, 0x97, 0xc3, 0xf8, 0x91, 0xf7, 0x63, 0x64, + 0x4f, 0xd2, 0x0c, 0xb1, 0x66, 0x52, 0x21, 0x77, 0x5f, 0xad, 0x7f, 0x4c, 0xec, 0x26, 0x7b, 0x60, 0x01, 0x88, 0xad, + 0x69, 0xab, 0x5b, 0xde, 0xef, 0x7b, 0xa6, 0x08, 0xf0, 0x83, 0xf2, 0x8f, 0xee, 0x0c, 0xc9, 0xa0, 0xec, 0xba, 0x21, + 0xc4, 0x83, 0xb2, 0x69, 0xda, 0xeb, 0x6d, 0xef, 0xcc, 0x63, 0x75, 0x9d, 0x76, 0x16, 0x57, 0x8b, 0x0c, 0xd2, 0xea, + 0x43, 0x76, 0x9c, 0xd9, 0x67, 0x47, 0x4b, 0xa5, 0xfb, 0x7d, 0x88, 0x88, 0x3b, 0xca, 0xda, 0x7e, 0xbb, 0x05, 0xd7, + 0x70, 0x34, 0x08, 0x5d, 0xd9, 0xdb, 0x65, 0xb4, 0x71, 0x21, 0x8e, 0x7b, 0xa6, 0xf3, 0x05, 0x5f, 0x1e, 0xa5, 0x9d, + 0x07, 0xa7, 0x7a, 0xa2, 0xcf, 0x4d, 0x77, 0x95, 0xc9, 0xb5, 0x0e, 0xab, 0x31, 0xa8, 0xcd, 0xc2, 0x16, 0xee, 0xc2, + 0x36, 0x3a, 0x68, 0xed, 0xcb, 0x82, 0x7f, 0xca, 0x00, 0x7c, 0xe9, 0xd9, 0xb2, 0xed, 0x35, 0x69, 0xf5, 0x46, 0x46, + 0x21, 0xb6, 0xb4, 0xbd, 0xfa, 0x74, 0x94, 0x8f, 0x9b, 0x13, 0x8a, 0x0b, 0x39, 0xca, 0x8f, 0x5e, 0x43, 0xd4, 0xb5, + 0xae, 0xe3, 0x62, 0xd1, 0xe1, 0xc6, 0x55, 0xb7, 0xdd, 0xb8, 0x7e, 0x40, 0xbc, 0x35, 0xda, 0xa4, 0x50, 0x2b, 0x63, + 0x47, 0xf0, 0xb2, 0x7c, 0x38, 0x64, 0x62, 0x38, 0x94, 0x90, 0xa9, 0x8f, 0xdd, 0x1b, 0x9a, 0xf6, 0xf9, 0x69, 0xeb, + 0x47, 0x2c, 0x35, 0x8e, 0x62, 0xc3, 0x3b, 0x7d, 0xe7, 0xb1, 0x35, 0xae, 0xe4, 0xcb, 0x60, 0xb6, 0x2b, 0xa8, 0xb6, + 0xc6, 0x1b, 0xf6, 0x72, 0xfe, 0x7d, 0x25, 0x95, 0xfc, 0xed, 0xcf, 0x70, 0x0d, 0x6f, 0x6d, 0xe9, 0xa0, 0xa9, 0x66, + 0x39, 0xcb, 0xf5, 0xbd, 0xe0, 0xf8, 0xe3, 0xee, 0x15, 0xc1, 0xe0, 0xf7, 0x74, 0x14, 0xe4, 0x62, 0xa9, 0xd6, 0x80, + 0x82, 0x74, 0x64, 0xc7, 0x54, 0x16, 0x18, 0x06, 0xf0, 0x86, 0x0c, 0x90, 0xc7, 0x14, 0xee, 0x86, 0x0a, 0x2f, 0xfc, + 0xa5, 0x22, 0xbb, 0x04, 0xb6, 0x35, 0xe3, 0x63, 0x86, 0x3b, 0x08, 0xf9, 0x47, 0xb0, 0x3b, 0xb6, 0x62, 0xb7, 0x6c, + 0xc1, 0x90, 0x6c, 0x1c, 0x87, 0x31, 0xe6, 0xe3, 0x49, 0x7c, 0x25, 0x26, 0xf1, 0x80, 0x47, 0xe8, 0x18, 0xb1, 0xe6, + 0xf5, 0x2c, 0x96, 0x03, 0xc8, 0xee, 0xb8, 0xd2, 0x01, 0x21, 0x34, 0x36, 0xb4, 0xe4, 0x4d, 0x61, 0x70, 0xb1, 0x63, + 0x9f, 0x91, 0x48, 0xc6, 0x21, 0x58, 0xb4, 0xaa, 0x81, 0x85, 0x89, 0xdd, 0xf2, 0x62, 0xb6, 0x9a, 0xe3, 0x3f, 0x87, + 0x03, 0x02, 0x60, 0x07, 0xfb, 0x86, 0xdd, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x77, 0x96, 0xa7, 0x0b, 0xbb, 0xe7, 0xd7, + 0x7c, 0xcc, 0xce, 0x7f, 0xf0, 0x20, 0x72, 0xf6, 0xfc, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xdb, 0xd4, 0xab, 0xd8, 0x2d, + 0x51, 0x10, 0xde, 0x82, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0x5e, 0xf3, 0x05, 0xc6, 0x8a, 0x9d, 0xa5, 0x4b, 0x0f, 0x33, + 0x42, 0xed, 0xe9, 0x7c, 0x59, 0xab, 0x49, 0xb8, 0xb9, 0x5a, 0x4e, 0x06, 0x83, 0x8d, 0xbf, 0xe3, 0x6b, 0xe0, 0x83, + 0x39, 0xff, 0xc1, 0xdb, 0x51, 0xb9, 0xf0, 0x9f, 0xd7, 0x59, 0xf2, 0xce, 0x67, 0xd7, 0x03, 0xbe, 0x00, 0xbc, 0x25, + 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0xbb, 0xd6, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0xbe, + 0x86, 0x08, 0x8c, 0x04, 0x7c, 0x5b, 0xb5, 0x47, 0xfc, 0x96, 0x1b, 0xc0, 0xaf, 0xcc, 0x67, 0x0f, 0x3c, 0xd4, 0x3f, + 0x13, 0x9f, 0xdd, 0xf0, 0xf7, 0xfc, 0x85, 0x27, 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, + 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, + 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, + 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, + 0xde, 0x14, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, + 0x7c, 0x38, 0xd4, 0x2f, 0x84, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, + 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, + 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, 0xaa, 0xda, 0xbf, 0x25, 0x49, 0xb5, 0xab, 0xb4, + 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, + 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, + 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, + 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, + 0x89, 0x17, 0xe3, 0x69, 0x4d, 0x2c, 0xa9, 0x5d, 0x81, 0x31, 0x7a, 0x5c, 0x15, 0xb5, 0x4f, 0xfd, 0x02, 0x42, 0x91, + 0x6a, 0xcd, 0x1c, 0x6b, 0xdc, 0x18, 0x11, 0x77, 0x58, 0xb9, 0x76, 0x6a, 0xaf, 0x03, 0xb0, 0xbc, 0x1a, 0x17, 0x84, + 0x4d, 0x72, 0xec, 0x5c, 0xc0, 0x6a, 0x34, 0xa4, 0xda, 0x0d, 0xb7, 0x5e, 0x76, 0x7e, 0xf3, 0x38, 0xb1, 0xb5, 0x11, + 0x6e, 0x29, 0xa0, 0x8c, 0xf2, 0x1b, 0xcb, 0x09, 0xbb, 0x53, 0xbd, 0x23, 0x55, 0x3b, 0xe2, 0xc4, 0x05, 0x2c, 0x37, + 0x3c, 0xb5, 0xfa, 0x26, 0x06, 0x27, 0x42, 0xd5, 0x4a, 0xc7, 0x6b, 0x3f, 0xe2, 0x7e, 0x75, 0x5f, 0xf7, 0x4a, 0xf0, + 0x93, 0x90, 0xd7, 0x6f, 0x79, 0x07, 0x80, 0x15, 0x1f, 0xf2, 0x62, 0x5a, 0x38, 0x5a, 0x97, 0x41, 0x19, 0x20, 0x42, + 0x33, 0x00, 0x3a, 0xb9, 0x3a, 0x88, 0xd2, 0xc0, 0x15, 0x77, 0x88, 0xf0, 0xd3, 0xe8, 0x59, 0xfe, 0x22, 0x7c, 0x56, + 0x4d, 0xc3, 0x8b, 0x3c, 0x88, 0x2e, 0xaa, 0x20, 0x7a, 0x56, 0x5d, 0x85, 0xcf, 0xf2, 0x69, 0x74, 0x91, 0x07, 0xe1, + 0x45, 0xd5, 0xd8, 0x77, 0xed, 0xee, 0x9e, 0x90, 0xb7, 0x5d, 0xfd, 0x91, 0x73, 0x65, 0x4f, 0x99, 0x9e, 0x9f, 0xd7, + 0x7a, 0xa5, 0x76, 0x9b, 0xeb, 0x35, 0x6a, 0xa6, 0x3e, 0xca, 0xfe, 0x66, 0x1b, 0x0b, 0x8f, 0xe6, 0x10, 0xfa, 0x8c, + 0xb4, 0x98, 0x7b, 0x9c, 0xeb, 0xcd, 0x9e, 0x14, 0x06, 0x46, 0x4c, 0x2a, 0x19, 0x39, 0xbd, 0xc0, 0x45, 0xa8, 0x42, + 0x0c, 0x6b, 0xe9, 0x6a, 0x9f, 0x75, 0xe9, 0x0d, 0xd4, 0x35, 0xc5, 0xbe, 0x86, 0x0c, 0xbc, 0x68, 0x7a, 0x19, 0x8c, + 0x01, 0x39, 0x02, 0xef, 0xf8, 0x6c, 0x09, 0x07, 0xe6, 0x1a, 0xa0, 0x6f, 0x1e, 0xf5, 0x75, 0xb9, 0xe3, 0x6b, 0xd5, + 0x37, 0xd3, 0xf5, 0x48, 0x29, 0x3f, 0x56, 0xfc, 0xee, 0xe2, 0x39, 0xbb, 0xe5, 0x1a, 0x15, 0xe5, 0x17, 0xbd, 0x58, + 0xef, 0x81, 0xab, 0xee, 0x17, 0xb8, 0xcd, 0xe2, 0xb1, 0x2b, 0x0f, 0x58, 0xb6, 0x65, 0x0f, 0xec, 0x86, 0xbd, 0x67, + 0x4f, 0xd8, 0x5b, 0xf6, 0x8e, 0xfd, 0x84, 0xaa, 0x0d, 0x25, 0xe4, 0xf9, 0x0b, 0x7e, 0x2b, 0x4d, 0x8f, 0x12, 0x95, + 0xec, 0xc1, 0x36, 0xd3, 0x0c, 0x37, 0xec, 0x3d, 0x5f, 0x0c, 0x57, 0xec, 0x2d, 0x64, 0x43, 0x99, 0x78, 0xb0, 0x62, + 0x3f, 0x71, 0x05, 0x62, 0xa6, 0xcf, 0xc2, 0xd2, 0x12, 0x15, 0x4d, 0x99, 0x28, 0x43, 0xbf, 0xe5, 0xf8, 0x22, 0xfb, + 0x09, 0x8b, 0x90, 0x9f, 0x19, 0xae, 0xd8, 0x03, 0x5f, 0x0c, 0x56, 0xec, 0xbd, 0x36, 0x10, 0x0d, 0x36, 0x6e, 0x69, + 0x84, 0x64, 0xa5, 0xcb, 0x92, 0xd2, 0xf4, 0xd6, 0xbe, 0x06, 0x6e, 0xd8, 0x0d, 0xd6, 0xee, 0x09, 0x16, 0x8d, 0x02, + 0xff, 0x60, 0xc5, 0xde, 0x71, 0x09, 0xa0, 0xe6, 0x96, 0x27, 0xbd, 0x42, 0x75, 0x81, 0x74, 0x3f, 0x78, 0xc2, 0xe9, + 0x45, 0xf6, 0x0e, 0xcb, 0xa0, 0xaf, 0x0c, 0x57, 0x6c, 0x8b, 0xb5, 0xbb, 0x31, 0x96, 0x2d, 0xab, 0x7a, 0x12, 0x11, + 0x18, 0x05, 0x95, 0xd2, 0xf2, 0x6f, 0xc4, 0xb2, 0xa9, 0x9b, 0x06, 0xb5, 0xa1, 0x3f, 0x1f, 0x8c, 0xfe, 0xe2, 0xeb, + 0x77, 0x3f, 0x78, 0xa5, 0xbe, 0xf6, 0xfe, 0xe2, 0xb8, 0x56, 0x96, 0xe8, 0x5a, 0xf9, 0x2b, 0x2f, 0x67, 0xbf, 0xcc, + 0x27, 0xba, 0x96, 0xb4, 0xc3, 0x90, 0xaf, 0xe9, 0xec, 0x97, 0x0e, 0x67, 0xcb, 0x5f, 0x7d, 0xbf, 0x31, 0x5d, 0xac, + 0x3e, 0xab, 0x7b, 0xf7, 0x61, 0xb0, 0x69, 0x9c, 0x7a, 0xef, 0x4e, 0xd7, 0x1b, 0x9b, 0x59, 0x6b, 0xcf, 0xcc, 0xff, + 0xe1, 0x4a, 0x6f, 0x71, 0xe8, 0x6e, 0xf8, 0x76, 0xb8, 0xb1, 0x47, 0x41, 0x7e, 0x5f, 0x2a, 0x8d, 0xb3, 0x9a, 0xbf, + 0xf4, 0x3a, 0xa5, 0x58, 0x40, 0x34, 0xfa, 0x64, 0x24, 0xa1, 0x4b, 0x66, 0xe2, 0x19, 0xe2, 0x8b, 0x0c, 0x90, 0xb9, + 0x40, 0x34, 0xbb, 0xe7, 0xe3, 0xc9, 0xfd, 0x55, 0x3c, 0xb9, 0x1f, 0xf0, 0x4f, 0xa6, 0x05, 0xed, 0xc5, 0x76, 0xef, + 0xb3, 0x5f, 0x79, 0x61, 0x2f, 0xc7, 0x5f, 0x7c, 0xf6, 0x45, 0xb8, 0x2b, 0xf4, 0x17, 0x9f, 0xbd, 0x13, 0xfc, 0xd7, + 0x91, 0x26, 0xca, 0x60, 0xef, 0x6a, 0xfe, 0xeb, 0x08, 0x19, 0x3f, 0xd8, 0x67, 0xc1, 0xbf, 0x80, 0xef, 0x77, 0x95, + 0xa0, 0x55, 0xfc, 0x73, 0xad, 0x7e, 0xbe, 0x97, 0x71, 0x39, 0xf0, 0x26, 0xb4, 0x82, 0xde, 0xbc, 0xad, 0xe5, 0x4f, + 0xe2, 0xe1, 0x48, 0xd5, 0x53, 0xc3, 0x3f, 0x8b, 0xc5, 0x2c, 0xea, 0xa3, 0x74, 0x2a, 0x6f, 0x72, 0xcd, 0x33, 0x69, + 0x5d, 0xbe, 0x87, 0x50, 0xe0, 0x6b, 0x1b, 0xa2, 0x60, 0xc7, 0x71, 0x23, 0xb8, 0x66, 0xef, 0x84, 0xcf, 0xb2, 0xe9, + 0x96, 0xdf, 0xf0, 0x27, 0xfc, 0x1d, 0xdf, 0x05, 0x0f, 0xfc, 0x3d, 0x7f, 0xcb, 0x7f, 0xe2, 0x3b, 0xb6, 0x94, 0x68, + 0xa7, 0xf5, 0xf6, 0x32, 0xd8, 0xb2, 0x7a, 0x77, 0x19, 0x3c, 0xb0, 0x7a, 0xfb, 0x3c, 0xb8, 0x61, 0xf5, 0xee, 0x79, + 0xf0, 0x9e, 0x6d, 0x2f, 0x83, 0x27, 0x6c, 0x77, 0x19, 0xbc, 0x65, 0xdb, 0xe7, 0xc1, 0x3b, 0xb6, 0x7b, 0x1e, 0xfc, + 0x24, 0x31, 0x1e, 0xde, 0x09, 0xc9, 0x71, 0xf2, 0xae, 0x66, 0x86, 0x4f, 0x37, 0xf8, 0x2c, 0xac, 0x5f, 0x54, 0xc7, + 0xe0, 0x73, 0xcd, 0x74, 0x8b, 0x03, 0x21, 0x98, 0x6e, 0x6f, 0x70, 0x4b, 0x4f, 0x4c, 0xab, 0x82, 0x54, 0xb0, 0xae, + 0x76, 0x06, 0x8b, 0xba, 0x69, 0x9d, 0xc9, 0x8e, 0x5f, 0x62, 0xdc, 0xe1, 0x97, 0xb8, 0x60, 0xcb, 0xa6, 0xd3, 0x49, + 0xe7, 0xf4, 0x49, 0xa0, 0x37, 0x7f, 0xbd, 0xeb, 0x57, 0xd2, 0x77, 0xa6, 0x68, 0x78, 0xae, 0xb4, 0xc6, 0xad, 0x9d, + 0x3e, 0xb4, 0x76, 0x7a, 0x26, 0x55, 0x68, 0x11, 0x8b, 0xca, 0xa2, 0xaa, 0x90, 0x49, 0x3c, 0xc8, 0xb4, 0x3e, 0x2d, + 0x61, 0xa4, 0xc8, 0x04, 0x34, 0xfa, 0x82, 0x8e, 0x81, 0x9c, 0x2c, 0x0a, 0x6c, 0xc9, 0x37, 0x83, 0x84, 0xad, 0x79, + 0x3c, 0x1d, 0x26, 0xc1, 0x92, 0xdd, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x52, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, + 0x79, 0x6f, 0x95, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x56, 0xe9, 0x0d, 0x7e, 0xeb, 0xec, 0xe7, 0x6b, 0xb5, 0xbf, 0x83, + 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xaf, 0xec, 0x2d, 0x7d, 0x6b, + 0xb6, 0xe9, 0xff, 0xb4, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xc6, 0x9f, 0x3c, + 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xc7, 0x3f, 0x8d, 0xb6, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, + 0x68, 0xef, 0xe4, 0x95, 0xbd, 0x23, 0x6e, 0x79, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, + 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xab, 0xd9, 0xa7, 0xf9, 0x64, 0xcb, 0x8f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, + 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x3b, 0x7e, 0xbc, 0x89, 0x0f, 0xff, 0xe3, + 0x4a, 0xef, 0xbe, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, 0xf8, 0x13, 0xcd, 0xd2, 0x20, 0xb2, 0x14, 0x8a, 0x3f, 0x99, 0x69, 0xa7, 0xee, 0x54, 0x59, 0xdd, 0x2d, 0xdf, 0xe2, - 0x1e, 0x7f, 0xc7, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0xef, 0x6e, 0x16, 0x93, 0xc1, 0xe0, 0xce, 0x3f, 0xdc, 0xf3, 0x70, - 0x76, 0x37, 0x67, 0x6f, 0xf9, 0x3d, 0x2d, 0xa6, 0x89, 0x6a, 0x7a, 0xf1, 0x98, 0xe0, 0x75, 0xe7, 0xfb, 0x13, 0x8b, - 0xff, 0xd5, 0xbe, 0x68, 0xde, 0xf9, 0x03, 0x69, 0x8d, 0x96, 0xbb, 0xfa, 0xfb, 0xc7, 0x15, 0x13, 0x77, 0x20, 0x5e, - 0xbc, 0xb7, 0x35, 0x0d, 0x6f, 0xf8, 0x47, 0xef, 0xad, 0x3f, 0x7d, 0xab, 0x63, 0x6e, 0x26, 0xea, 0x48, 0x7a, 0x73, - 0xf5, 0x8c, 0xfd, 0xca, 0x3f, 0xc9, 0xe3, 0xe4, 0x9d, 0x90, 0x93, 0xf6, 0x16, 0xb9, 0x9b, 0xe8, 0x94, 0xf8, 0xe2, - 0x26, 0x12, 0x16, 0x04, 0xc2, 0x70, 0xd4, 0xfc, 0x61, 0x52, 0x4e, 0xbd, 0x3d, 0x70, 0xbb, 0x72, 0x5b, 0xff, 0x7c, - 0xc7, 0x39, 0x5f, 0x0c, 0xaf, 0xa7, 0x5f, 0xba, 0x5d, 0x7a, 0x54, 0x34, 0x9b, 0x0a, 0x74, 0xbb, 0xc3, 0xd8, 0xab, - 0xb3, 0x99, 0x65, 0x2e, 0xf9, 0xd2, 0x97, 0xda, 0xcc, 0x3c, 0xa6, 0xf7, 0x9b, 0x69, 0x86, 0x44, 0xbe, 0x40, 0xc8, - 0x74, 0x3c, 0xae, 0x2e, 0xb1, 0x3c, 0x3e, 0x7c, 0xf3, 0xf4, 0xc9, 0xe0, 0x09, 0x46, 0x6e, 0x59, 0xd1, 0x20, 0x5f, - 0xf8, 0x30, 0xab, 0x5b, 0xb7, 0x8d, 0xab, 0x67, 0xc3, 0x5f, 0x20, 0x6f, 0xd0, 0xf5, 0xd0, 0x14, 0xd1, 0x2a, 0xbf, - 0xa3, 0xe8, 0x33, 0x25, 0x07, 0x1d, 0x4f, 0xa0, 0x76, 0x48, 0x81, 0xfb, 0xe5, 0x29, 0x07, 0xfd, 0x06, 0x96, 0xda, - 0xef, 0x5f, 0x7e, 0x22, 0x1e, 0x69, 0x18, 0xef, 0x1f, 0xc2, 0xe8, 0x8f, 0xb8, 0x2c, 0x36, 0x70, 0xba, 0x0e, 0xe0, - 0x73, 0x4f, 0xf5, 0xed, 0x6b, 0xe5, 0xfb, 0x7e, 0xe0, 0xed, 0xf8, 0x2d, 0xfb, 0xc2, 0xbd, 0xeb, 0xe1, 0x1b, 0xff, - 0xe9, 0x13, 0x10, 0x9d, 0x60, 0x5c, 0x3e, 0x63, 0x24, 0x6c, 0x47, 0x31, 0x6a, 0x15, 0x7e, 0xae, 0x21, 0x44, 0xeb, - 0x13, 0x32, 0x76, 0x41, 0xfa, 0x07, 0x05, 0xe8, 0x27, 0x04, 0x56, 0x93, 0xd4, 0x28, 0x30, 0x89, 0xef, 0x6a, 0x48, - 0x20, 0x05, 0x0b, 0x84, 0xde, 0x40, 0xf1, 0xa9, 0xe0, 0x5f, 0x86, 0x9f, 0x49, 0xf2, 0x5b, 0xd4, 0x7c, 0x0c, 0x7f, - 0xc3, 0xd0, 0x4c, 0xaa, 0x87, 0xb4, 0x8e, 0x12, 0xef, 0x27, 0xff, 0x10, 0x85, 0x95, 0x50, 0xc7, 0x42, 0x90, 0x8a, - 0x21, 0x17, 0xe2, 0xea, 0xd9, 0xe4, 0xae, 0x14, 0xe1, 0x1f, 0x13, 0x7c, 0x26, 0x17, 0x9a, 0x7c, 0x46, 0x4f, 0x1a, - 0xf9, 0xfe, 0x83, 0x7c, 0x5f, 0x76, 0x6a, 0xb0, 0xa8, 0x87, 0xfc, 0xae, 0x76, 0xdf, 0x97, 0x53, 0x82, 0x1e, 0xd9, - 0x0f, 0x68, 0x0a, 0x06, 0x6a, 0x02, 0x52, 0x86, 0xe0, 0x0e, 0xae, 0xfa, 0x9e, 0x2a, 0xc8, 0x97, 0xdf, 0xfb, 0x2c, - 0x64, 0xb8, 0xca, 0x82, 0x90, 0xe4, 0x52, 0x21, 0x85, 0x8d, 0xbb, 0x7a, 0xf0, 0x59, 0x63, 0x92, 0x48, 0xc8, 0x29, - 0x01, 0x49, 0xd2, 0xde, 0x40, 0x92, 0x88, 0xe9, 0x3f, 0x5c, 0x27, 0x4d, 0xb3, 0x96, 0xd2, 0x0d, 0x71, 0xaa, 0xbe, - 0x45, 0x9a, 0xb3, 0xe0, 0x3d, 0x83, 0xa5, 0x23, 0xc5, 0x8a, 0x2f, 0xc6, 0x60, 0xac, 0x83, 0x85, 0x56, 0xb2, 0xb8, - 0x5f, 0x25, 0x61, 0x1a, 0x89, 0x2a, 0xef, 0x84, 0xfc, 0xf9, 0x4f, 0x25, 0xfe, 0xe8, 0x2d, 0x0d, 0x44, 0x20, 0xf8, - 0x01, 0x5a, 0x0f, 0x58, 0xe3, 0xc1, 0x4f, 0xac, 0x2e, 0xc3, 0xbc, 0xca, 0xa8, 0xbc, 0xd9, 0x9e, 0xed, 0xe6, 0x4c, - 0x55, 0x2d, 0xf8, 0x2c, 0x0c, 0x2d, 0xda, 0xc5, 0xba, 0x39, 0xbb, 0xcd, 0x1b, 0x7c, 0x67, 0x92, 0x44, 0x6a, 0x29, - 0x89, 0xb4, 0xd5, 0xf5, 0xe9, 0xd2, 0xeb, 0x16, 0x15, 0x34, 0x46, 0x80, 0x5e, 0x92, 0xee, 0x2a, 0x9f, 0x50, 0xbc, - 0xb2, 0x1a, 0x56, 0xc3, 0x4b, 0x87, 0x22, 0x8c, 0xb5, 0x37, 0xe7, 0xf2, 0xec, 0x0e, 0xac, 0x47, 0x68, 0xed, 0xca, - 0xd5, 0x21, 0x6c, 0x3f, 0xd1, 0x7b, 0x4e, 0xae, 0xfe, 0x06, 0x54, 0x81, 0x73, 0x47, 0x43, 0x7d, 0xd2, 0x4e, 0x21, - 0xdb, 0x79, 0xb0, 0x24, 0xa8, 0x4a, 0xc9, 0x4d, 0xb9, 0x16, 0xa5, 0x94, 0x29, 0x5f, 0xcb, 0x6c, 0x65, 0xf7, 0xc9, - 0x00, 0xe2, 0xd9, 0xa0, 0x40, 0x72, 0x51, 0x5b, 0xcd, 0x41, 0xfa, 0x68, 0x96, 0x38, 0xd6, 0x0e, 0x0a, 0x2f, 0xcb, - 0xc1, 0xcc, 0x65, 0x2e, 0x97, 0x83, 0x82, 0x55, 0x7a, 0xab, 0x99, 0x66, 0xaa, 0x2f, 0x2a, 0x7b, 0x9b, 0xf1, 0x32, - 0xfd, 0x37, 0x4b, 0x06, 0x3c, 0xba, 0x7a, 0xe6, 0x07, 0x90, 0x26, 0x79, 0x1d, 0x20, 0x09, 0x36, 0x07, 0xbb, 0xd8, - 0x61, 0xd8, 0x2a, 0x56, 0xf6, 0xe4, 0xf9, 0x72, 0x87, 0xa6, 0x5c, 0xc2, 0x48, 0x4e, 0xcc, 0xa5, 0xd4, 0xf7, 0x25, - 0xd5, 0x0d, 0x05, 0x27, 0x9b, 0x26, 0xa0, 0x14, 0xd0, 0x6e, 0xc1, 0x7f, 0xe1, 0x53, 0x43, 0xa7, 0x05, 0x58, 0x6a, - 0xbb, 0x01, 0xff, 0x85, 0x7e, 0xb1, 0x7d, 0x44, 0xfd, 0xc0, 0x3c, 0x38, 0x98, 0xb5, 0x95, 0x31, 0x20, 0x22, 0x71, - 0x05, 0x79, 0x24, 0xf8, 0x41, 0xb1, 0xa7, 0xcb, 0xc4, 0x81, 0x33, 0xc5, 0xc5, 0x52, 0x6a, 0x33, 0xf3, 0xda, 0x6f, - 0xa9, 0x89, 0x37, 0x51, 0x12, 0x15, 0xb6, 0x43, 0x1a, 0xbd, 0xa4, 0x8c, 0xa9, 0x82, 0x0d, 0xd1, 0x7d, 0xdd, 0x04, - 0x53, 0xe0, 0x4d, 0x55, 0x05, 0x44, 0xa8, 0xbd, 0xc8, 0xf2, 0xfc, 0xa6, 0x0b, 0xac, 0x2e, 0xf8, 0xd4, 0x98, 0x66, - 0x17, 0xac, 0xe4, 0x6a, 0x26, 0x7d, 0xe6, 0xed, 0x40, 0x0b, 0x79, 0x97, 0x97, 0x45, 0x2b, 0x74, 0x3d, 0x88, 0x16, - 0xfe, 0x41, 0x73, 0x3c, 0x7a, 0xb6, 0xad, 0xa6, 0x36, 0xfb, 0x5a, 0x8b, 0x05, 0x32, 0x10, 0x0d, 0x7d, 0xa1, 0x62, - 0x14, 0xee, 0x2a, 0xcd, 0xd5, 0x6a, 0x5f, 0x95, 0x41, 0x02, 0x13, 0x41, 0xd6, 0xb2, 0xf0, 0x1e, 0xdd, 0xab, 0x47, - 0x9a, 0x57, 0x12, 0x3c, 0x73, 0xf1, 0x17, 0x00, 0x42, 0x79, 0x92, 0x90, 0x03, 0x72, 0x00, 0x7f, 0x4b, 0x51, 0x2a, - 0x0d, 0xf0, 0xcf, 0xea, 0x72, 0x6c, 0xeb, 0xfb, 0x3b, 0xad, 0x62, 0x70, 0xfd, 0xf9, 0xba, 0xeb, 0x59, 0x3b, 0xc4, - 0x39, 0xb7, 0xd5, 0x6b, 0xcb, 0x34, 0x8f, 0x91, 0xba, 0x06, 0xe0, 0x4e, 0xa4, 0x47, 0x20, 0x92, 0x99, 0x68, 0x90, - 0xb3, 0xe7, 0x7c, 0x3c, 0x15, 0x8f, 0x49, 0x7b, 0xb9, 0xef, 0x9b, 0x0b, 0x7d, 0x30, 0xc6, 0xbe, 0x05, 0x0d, 0xe2, - 0xa3, 0xd5, 0xd6, 0x0a, 0xc4, 0x7a, 0xa7, 0xd4, 0x87, 0x6e, 0x8c, 0x82, 0x0e, 0x1e, 0x71, 0x23, 0x17, 0x1c, 0xdb, - 0x5d, 0x5b, 0x4f, 0xe9, 0x2b, 0x00, 0x73, 0x1d, 0xa8, 0x64, 0x18, 0xa4, 0x2e, 0x13, 0x85, 0x49, 0x7e, 0x99, 0x90, - 0x84, 0x88, 0xea, 0x6c, 0x39, 0x4a, 0x95, 0x69, 0x01, 0x97, 0x19, 0x19, 0x60, 0x36, 0x69, 0xd6, 0x4f, 0x2e, 0x5f, - 0x62, 0x18, 0x01, 0xf1, 0x33, 0xfa, 0xb1, 0x56, 0x89, 0x97, 0x8c, 0xee, 0x1c, 0x75, 0x83, 0x2a, 0xc9, 0x5c, 0xbf, - 0xb9, 0x9d, 0x45, 0xca, 0xbc, 0x60, 0xb8, 0x5d, 0xa5, 0xf9, 0x87, 0xb0, 0x4e, 0xf0, 0xdb, 0x00, 0x95, 0xf4, 0xa9, - 0xf0, 0xa2, 0x11, 0x40, 0xa8, 0xef, 0x55, 0x19, 0x9f, 0x0a, 0x2f, 0x1b, 0xed, 0x58, 0x46, 0x29, 0x54, 0x17, 0xcc, - 0x6e, 0x4d, 0x17, 0xa2, 0x5b, 0x55, 0x03, 0x6d, 0xe0, 0xda, 0x15, 0x52, 0xba, 0x81, 0x6a, 0x57, 0x6e, 0x58, 0x80, - 0x68, 0x33, 0x11, 0x18, 0x2e, 0xff, 0x3e, 0x7f, 0xa9, 0x62, 0x78, 0xfa, 0xfd, 0xd0, 0x3b, 0xec, 0x82, 0x68, 0xb4, - 0xbb, 0x66, 0xfb, 0x20, 0x1a, 0xed, 0xaf, 0x1b, 0x46, 0xbf, 0x9f, 0xd1, 0xef, 0x67, 0x0d, 0xe8, 0x48, 0x84, 0x09, - 0xb3, 0xd7, 0x6f, 0xd4, 0xf2, 0x95, 0x5a, 0xbf, 0x53, 0xcb, 0x97, 0x6a, 0x78, 0xeb, 0x40, 0x12, 0x41, 0x64, 0xa9, - 0x6a, 0x1e, 0x24, 0x45, 0xaa, 0xa5, 0xcb, 0x31, 0x5a, 0x8c, 0xa8, 0xa5, 0xac, 0x39, 0xd5, 0x89, 0xb4, 0x73, 0x50, - 0x32, 0xc0, 0xd1, 0xe2, 0xaa, 0xc6, 0x74, 0xb3, 0xa2, 0x25, 0x10, 0x23, 0xac, 0x6c, 0xcb, 0xc5, 0x4d, 0xea, 0xa3, - 0x2b, 0xf2, 0x6d, 0xcb, 0x95, 0x6f, 0x5b, 0xc1, 0xab, 0xaf, 0x28, 0x94, 0x4b, 0xae, 0x95, 0xed, 0xd3, 0x42, 0x29, - 0x94, 0x71, 0x0d, 0xb6, 0xf6, 0x4d, 0x60, 0xc8, 0x7c, 0xa4, 0xa8, 0xb1, 0xbd, 0x68, 0x94, 0x43, 0x90, 0xad, 0x83, - 0x51, 0xa7, 0x2c, 0x58, 0x7c, 0xbb, 0x43, 0x06, 0x32, 0xd0, 0x51, 0xd5, 0xc6, 0xab, 0x9d, 0x95, 0xfe, 0xb0, 0xbc, - 0x7a, 0xc6, 0x12, 0x2b, 0x9d, 0xfc, 0xa6, 0x42, 0x7f, 0x10, 0xa2, 0x6f, 0xca, 0x96, 0x83, 0x17, 0x5d, 0x6c, 0x65, - 0x40, 0xbc, 0x61, 0x7a, 0x6f, 0x6b, 0x25, 0xcb, 0x5d, 0x53, 0xbe, 0x98, 0xf1, 0x84, 0xe3, 0xe8, 0xcb, 0xd5, 0x22, - 0xac, 0xd5, 0x22, 0x3b, 0x01, 0x1e, 0x5a, 0xab, 0xa5, 0x90, 0xab, 0x45, 0x38, 0x33, 0x5d, 0xa8, 0x99, 0x9e, 0x81, - 0xe6, 0x51, 0xa8, 0x59, 0x9e, 0x00, 0x16, 0xbc, 0x30, 0x33, 0x5c, 0x98, 0x19, 0x8e, 0x43, 0x6a, 0x9c, 0x1e, 0xf4, - 0x5e, 0xe7, 0x9e, 0x5b, 0xee, 0x46, 0xa7, 0x61, 0xde, 0x4e, 0x36, 0x98, 0xd3, 0x83, 0x70, 0x02, 0xf1, 0x81, 0x25, - 0x02, 0xf4, 0x68, 0x58, 0x1d, 0x35, 0x54, 0x8e, 0xe2, 0xcb, 0x02, 0x90, 0x2c, 0x09, 0x40, 0xf2, 0xa0, 0xc6, 0xb9, - 0xb4, 0xfc, 0xba, 0x4a, 0x42, 0x8e, 0xc8, 0x78, 0x29, 0xed, 0xee, 0x09, 0x2f, 0x47, 0x46, 0x68, 0x9e, 0x2c, 0x52, - 0xaf, 0x62, 0x19, 0x1b, 0x23, 0x70, 0x51, 0xe8, 0x37, 0x79, 0xbf, 0x9f, 0x96, 0x5e, 0x45, 0xed, 0xfc, 0x04, 0xfe, - 0x96, 0xe7, 0xce, 0x22, 0x47, 0xc8, 0xab, 0x91, 0x49, 0x58, 0x5e, 0x2a, 0xf5, 0xf4, 0x25, 0xcc, 0xa0, 0xee, 0xde, - 0x28, 0x00, 0xd7, 0x42, 0x39, 0xd5, 0x96, 0x70, 0x65, 0xaa, 0x0c, 0xf6, 0x79, 0xc8, 0x65, 0x68, 0x87, 0x44, 0x1e, - 0x29, 0xac, 0xfb, 0xf6, 0xd5, 0xb3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x8f, 0x00, 0x73, 0x30, 0xf5, 0xa2, - 0x01, 0x2f, 0xd5, 0x9c, 0xf9, 0xe8, 0x55, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x53, 0xf9, 0xc8, 0xf8, - 0x96, 0xf9, 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, - 0x6c, 0x50, 0x09, 0xb6, 0x0d, 0xdf, 0x48, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, - 0x1b, 0xb3, 0x31, 0x2b, 0xd4, 0xce, 0x53, 0xc9, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, - 0x71, 0xce, 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, - 0xa6, 0x25, 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, - 0xe8, 0x95, 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x2b, - 0xfe, 0x42, 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd0, 0xb4, 0x04, - 0x75, 0x80, 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x25, 0xe7, 0xef, 0x6a, 0x43, - 0x84, 0x8c, 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, - 0xc0, 0xe3, 0xaa, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x9c, 0xf6, 0x4e, 0xd3, 0xb0, 0xc3, 0x17, 0xa0, 0x29, 0x86, 0x72, - 0x3c, 0xdf, 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xce, 0x42, 0xda, 0x96, - 0x63, 0xb4, 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xca, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x79, 0xd5, 0x63, 0x36, - 0xc9, 0x8a, 0x45, 0xae, 0x22, 0xce, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, - 0x41, 0xc9, 0x72, 0x59, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xde, 0x9c, - 0x53, 0xa8, 0x7d, 0xc5, 0xc3, 0xea, 0xfc, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, - 0x7c, 0xe7, 0xab, 0x74, 0x45, 0xa1, 0x3b, 0xce, 0x4c, 0x3c, 0x57, 0x81, 0xb1, 0x6f, 0xed, 0x08, 0x0a, 0x87, 0xa6, - 0xeb, 0x80, 0xc3, 0x34, 0x3a, 0x61, 0xf1, 0x4f, 0xe9, 0x38, 0x79, 0x55, 0x2b, 0x44, 0x92, 0xbf, 0x0b, 0x17, 0x86, - 0xc4, 0x82, 0xbc, 0x24, 0xd4, 0x11, 0x19, 0xb1, 0x1a, 0x15, 0x1b, 0xa1, 0xa2, 0xe2, 0x14, 0x8f, 0xb7, 0x0a, 0x8a, - 0x4b, 0x51, 0xaa, 0x94, 0x8a, 0xdc, 0xa8, 0x14, 0x10, 0xcb, 0x06, 0xde, 0x2d, 0xe0, 0x00, 0x08, 0x3a, 0xcb, 0xfd, - 0xc6, 0x76, 0xb7, 0x91, 0xf9, 0xcc, 0x34, 0x4f, 0xab, 0x0f, 0xea, 0xef, 0xf7, 0x4b, 0x8c, 0xad, 0xf1, 0xf4, 0xf7, - 0x6d, 0x5a, 0x70, 0xf3, 0x37, 0x0c, 0xd1, 0x0a, 0x10, 0x31, 0x4b, 0x7b, 0x28, 0x64, 0xc1, 0x84, 0x65, 0xa8, 0xca, - 0x53, 0x8e, 0x7a, 0xd5, 0xe4, 0x0e, 0x20, 0xd4, 0xd0, 0xaf, 0x8d, 0x4e, 0x75, 0x55, 0x82, 0xf0, 0x7d, 0x57, 0xa8, - 0xc7, 0xe6, 0x80, 0x27, 0x03, 0xe0, 0xaf, 0xc8, 0x6b, 0x3d, 0xb6, 0x7f, 0xd0, 0x1b, 0xf5, 0x06, 0x08, 0xa2, 0x73, - 0x59, 0xf8, 0x27, 0x9c, 0xeb, 0xd4, 0x9f, 0x71, 0x21, 0x88, 0x6f, 0x3d, 0x09, 0xef, 0xc5, 0x45, 0x1a, 0x07, 0x17, - 0xbd, 0x81, 0xb9, 0x08, 0x14, 0x17, 0x69, 0x7e, 0x01, 0x61, 0xf9, 0x88, 0x89, 0x58, 0xb3, 0x15, 0xc0, 0x04, 0x96, - 0x3a, 0x0e, 0x59, 0x75, 0x6c, 0xbf, 0xff, 0x7a, 0x64, 0xc8, 0xd2, 0x11, 0x06, 0x46, 0xff, 0x06, 0x14, 0xa1, 0x12, - 0x96, 0x99, 0xed, 0xc1, 0xa4, 0xab, 0x3d, 0xab, 0xe7, 0xcd, 0x36, 0xef, 0xea, 0x1d, 0xab, 0x69, 0x15, 0x35, 0x2d, - 0xb7, 0x9a, 0x36, 0xa9, 0xa0, 0x66, 0xa2, 0xdf, 0xd7, 0xa0, 0xa8, 0xd5, 0x1c, 0xc0, 0xd8, 0x30, 0xf9, 0xf5, 0x2c, - 0x9f, 0xf7, 0xfb, 0x9e, 0x7c, 0x04, 0xbf, 0x90, 0xad, 0xcc, 0xad, 0xb1, 0x7c, 0xfa, 0x8a, 0x48, 0xcc, 0x0c, 0xcc, - 0xd1, 0xea, 0x04, 0xdf, 0xeb, 0x56, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x35, 0x0c, 0x9e, 0x27, 0x7c, 0x70, - 0x91, 0xa3, 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x6b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, - 0x78, 0x90, 0xfd, 0xfe, 0x1a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0x37, 0x75, 0x51, 0x56, 0xd0, 0xb1, - 0xf4, 0xf3, 0x4e, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x96, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, - 0x2e, 0x3e, 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0x67, 0xb8, 0xcf, 0x6f, 0x3c, 0xf0, 0x83, 0x99, 0xa5, - 0x73, 0x45, 0x9c, 0x51, 0xf9, 0xa3, 0xcf, 0x45, 0x9a, 0x53, 0x1e, 0xe0, 0x3e, 0x14, 0x73, 0xfb, 0x2d, 0x90, 0x7e, - 0xe8, 0x2d, 0x90, 0x7d, 0x74, 0xce, 0xc9, 0x6b, 0x40, 0xa4, 0x43, 0x18, 0xdc, 0x9c, 0x04, 0x1d, 0xab, 0x86, 0x77, - 0x16, 0xd8, 0x69, 0x2f, 0x8d, 0x7b, 0x69, 0x7e, 0x91, 0xf6, 0xfb, 0x06, 0x35, 0x33, 0x45, 0x38, 0x78, 0x9c, 0x91, - 0x8b, 0xa4, 0x05, 0x5b, 0x4a, 0xfb, 0xaf, 0x06, 0x8e, 0xa8, 0x10, 0xa0, 0xf9, 0xef, 0xc2, 0x7b, 0x02, 0x10, 0x9b, - 0xb4, 0x01, 0x57, 0x3d, 0xa6, 0xa3, 0xb1, 0x25, 0x51, 0xab, 0xce, 0x06, 0x48, 0x9c, 0x2a, 0xad, 0xa7, 0xdc, 0xac, - 0x29, 0x0c, 0x52, 0x65, 0xa1, 0x7e, 0x63, 0x3d, 0x99, 0xac, 0x72, 0x91, 0x11, 0x47, 0x65, 0x7a, 0x57, 0x33, 0x82, - 0xe9, 0xd2, 0xcf, 0x17, 0xb0, 0x64, 0xe3, 0x8f, 0x38, 0x79, 0x4b, 0xc0, 0xb1, 0x9d, 0xb5, 0xab, 0x6a, 0x97, 0xe3, - 0xd6, 0x6e, 0x0e, 0xf0, 0xbd, 0xde, 0x68, 0x34, 0xd2, 0xce, 0x71, 0x02, 0x86, 0xaa, 0xa7, 0x96, 0x42, 0x8f, 0xd5, - 0x0a, 0x50, 0xb7, 0x23, 0x97, 0x59, 0x32, 0x98, 0x2f, 0x8c, 0xe3, 0x97, 0xe6, 0xa3, 0x8f, 0x97, 0xca, 0xda, 0x75, - 0xc4, 0xd7, 0x7f, 0x94, 0xd5, 0xfa, 0x96, 0x77, 0x55, 0x13, 0xf0, 0x45, 0x15, 0x50, 0xfa, 0x0d, 0xef, 0xc9, 0xde, - 0xc5, 0xd7, 0x6e, 0xb1, 0x4b, 0xbe, 0xe5, 0x2d, 0xea, 0x3c, 0x5f, 0x39, 0xb8, 0x51, 0xa5, 0xdb, 0x7b, 0xc9, 0x02, - 0xd7, 0xde, 0x49, 0xd3, 0x58, 0xcf, 0xfc, 0xe8, 0x61, 0x11, 0xb2, 0x9d, 0x8f, 0xbd, 0xaf, 0x9a, 0xa7, 0x67, 0x0d, - 0xbd, 0x49, 0x0d, 0x7d, 0xec, 0x45, 0xd9, 0x3e, 0x35, 0x8d, 0xe8, 0x35, 0x6c, 0xe8, 0x63, 0x6f, 0xc9, 0xc9, 0x21, - 0x11, 0xe0, 0xd4, 0x98, 0x3f, 0x3e, 0x9c, 0xce, 0xf0, 0x77, 0x0c, 0xa8, 0x04, 0x62, 0x3e, 0x3f, 0xa6, 0x1d, 0x05, - 0x98, 0x51, 0xa5, 0xb7, 0xcf, 0x0f, 0x6c, 0xc7, 0xcb, 0x7a, 0x68, 0xe9, 0xdd, 0xb3, 0xa3, 0xdb, 0xf1, 0xaa, 0x1a, - 0x5f, 0xca, 0x21, 0xcf, 0xf3, 0xd9, 0x68, 0x34, 0x12, 0x06, 0x92, 0x3b, 0xd7, 0x1b, 0x58, 0x81, 0xb4, 0x2d, 0xaa, - 0x0f, 0xe5, 0xd2, 0xdb, 0xab, 0x43, 0x3b, 0xf7, 0x27, 0xd5, 0xf1, 0x58, 0x8c, 0xcc, 0x31, 0x9e, 0xfb, 0xc7, 0x63, - 0xa1, 0xe4, 0x28, 0x59, 0x4b, 0x10, 0x9d, 0xd2, 0x78, 0x2a, 0xeb, 0xb5, 0x13, 0x91, 0x57, 0x23, 0xce, 0x43, 0xf0, - 0x57, 0x2f, 0x67, 0xa5, 0xfe, 0x54, 0xf8, 0xe8, 0xa7, 0x4a, 0xe9, 0x05, 0xaf, 0x0a, 0x08, 0x11, 0xfb, 0xbb, 0x81, - 0x76, 0x50, 0x82, 0x43, 0x09, 0xf7, 0x1e, 0xaf, 0x93, 0xaf, 0xbc, 0x6a, 0x26, 0x63, 0x94, 0x7b, 0x83, 0x7c, 0xce, - 0x00, 0xa6, 0xd2, 0x67, 0xe0, 0x77, 0x09, 0x50, 0xa7, 0xf8, 0x14, 0x9d, 0xea, 0xcd, 0xc3, 0xa6, 0xeb, 0xd3, 0x12, - 0x45, 0x11, 0xdd, 0xf9, 0xf9, 0x18, 0x10, 0x3b, 0xbb, 0x36, 0x23, 0xed, 0xda, 0x6f, 0xd0, 0x60, 0x95, 0x26, 0xad, - 0x95, 0x53, 0xc2, 0x6e, 0x57, 0x23, 0x5b, 0xfa, 0x51, 0x0a, 0xc4, 0xca, 0x71, 0x22, 0x91, 0x3d, 0xd8, 0xc8, 0x09, - 0xdc, 0xa2, 0xbd, 0xa3, 0x03, 0x50, 0xb9, 0x51, 0x90, 0x5f, 0xcd, 0x89, 0xdc, 0xf1, 0x7d, 0xef, 0xfb, 0x41, 0x3d, - 0xf8, 0xbe, 0x77, 0x91, 0x92, 0xdc, 0x11, 0x5e, 0xa8, 0x29, 0x21, 0xe2, 0x8b, 0xef, 0x07, 0xd5, 0x00, 0xcf, 0x12, - 0x2d, 0xd2, 0x22, 0xa1, 0x5a, 0x5d, 0xe3, 0x26, 0xbc, 0x48, 0x24, 0xf7, 0xd0, 0xbe, 0xf3, 0x88, 0x58, 0x00, 0x32, - 0x16, 0x9f, 0xcd, 0x1b, 0x0a, 0x75, 0x37, 0x31, 0x5b, 0x74, 0x97, 0xc5, 0x7e, 0x7f, 0x93, 0xa7, 0x75, 0x4f, 0xc7, - 0xc7, 0xe0, 0x0b, 0x52, 0x4d, 0x80, 0x47, 0xfb, 0x2b, 0x73, 0xbc, 0x7a, 0xb5, 0x39, 0x52, 0x16, 0xaa, 0x44, 0xfd, - 0x16, 0xab, 0x59, 0x0f, 0x61, 0xb8, 0xb3, 0xcc, 0x58, 0xdb, 0x0b, 0x9e, 0xcb, 0x59, 0x15, 0xdb, 0xe5, 0xf8, 0x8a, - 0xa5, 0x36, 0x97, 0xa8, 0x1c, 0xad, 0xc7, 0xda, 0x14, 0x23, 0xbf, 0x52, 0x48, 0x94, 0x45, 0xc7, 0xd6, 0x42, 0x01, - 0xf1, 0x02, 0xf4, 0x25, 0x7b, 0xd3, 0x00, 0xeb, 0x8d, 0x5e, 0x45, 0x84, 0x96, 0x8f, 0x54, 0x78, 0x9b, 0x9b, 0x2a, - 0xb3, 0xb2, 0x59, 0xb4, 0xfb, 0x29, 0xe7, 0x39, 0x82, 0xd5, 0x1b, 0xb5, 0x47, 0x01, 0x6a, 0x0f, 0x2d, 0x94, 0x01, - 0xa4, 0x34, 0xcd, 0x00, 0x90, 0x01, 0x40, 0xa6, 0x8a, 0xf8, 0x4c, 0x80, 0x4a, 0x5b, 0xdd, 0x28, 0x70, 0x22, 0xbd, - 0x02, 0x9a, 0x05, 0x56, 0xfa, 0x48, 0x41, 0x06, 0x8b, 0x2d, 0x02, 0xb0, 0x72, 0xe4, 0x0c, 0xd3, 0x18, 0xb2, 0x8d, - 0x26, 0x2e, 0x49, 0xf3, 0xfb, 0x30, 0x4b, 0x25, 0x9e, 0xc4, 0x8f, 0xb2, 0xc6, 0x08, 0x00, 0xa4, 0xef, 0xd3, 0x8b, - 0x22, 0x8b, 0x09, 0x07, 0xce, 0x7a, 0xea, 0xa0, 0xa8, 0xc9, 0xb9, 0xd6, 0xb4, 0x7a, 0x56, 0x9b, 0x3c, 0x64, 0x81, - 0xce, 0x1e, 0x8c, 0x49, 0x2d, 0xdf, 0xf3, 0xc8, 0xfe, 0xca, 0xe9, 0x8c, 0xf0, 0x5d, 0x77, 0x70, 0xea, 0xbf, 0xdb, - 0x1a, 0x98, 0x98, 0x12, 0x80, 0x8d, 0xc1, 0xd1, 0x84, 0xf8, 0x9d, 0x8e, 0xc9, 0xd4, 0x26, 0x45, 0x20, 0xf0, 0x10, - 0xbc, 0x82, 0xeb, 0x0b, 0x19, 0x30, 0x20, 0x68, 0x3b, 0x8b, 0x3c, 0x4d, 0x00, 0x4e, 0xbc, 0xe0, 0x3b, 0x80, 0xe3, - 0xd4, 0xab, 0x42, 0xf6, 0xec, 0xa5, 0x98, 0xce, 0xe6, 0xc1, 0x43, 0x42, 0xfb, 0x17, 0x13, 0x7e, 0xd3, 0x5d, 0x25, - 0x57, 0xa6, 0xd6, 0xbd, 0x89, 0xae, 0x72, 0x95, 0xd3, 0xa7, 0x39, 0xc7, 0x30, 0x67, 0xb0, 0x0a, 0xc8, 0x39, 0x1b, - 0xf2, 0xe7, 0x97, 0x00, 0xd8, 0xb2, 0x16, 0x5e, 0xc4, 0x9f, 0x87, 0xb2, 0x5a, 0x00, 0xf7, 0xc8, 0x79, 0x64, 0x7e, - 0xf9, 0x6a, 0x3b, 0x94, 0x73, 0x8a, 0xc2, 0x58, 0xce, 0x4d, 0x4b, 0x8a, 0xd3, 0xa1, 0xa7, 0x60, 0x32, 0xb5, 0xe5, - 0xef, 0x5d, 0xe2, 0x32, 0x7b, 0x33, 0x09, 0xe7, 0xeb, 0xc8, 0xb6, 0xb5, 0xea, 0x1e, 0xba, 0x21, 0x18, 0xf4, 0x31, - 0x82, 0x96, 0xd5, 0x9b, 0x5f, 0x31, 0x18, 0x28, 0x6c, 0xdf, 0x9a, 0x6e, 0x5a, 0x74, 0x8a, 0x03, 0xce, 0xac, 0x75, - 0x8d, 0x4a, 0x55, 0x71, 0xe8, 0x25, 0xef, 0x96, 0x95, 0xdb, 0x65, 0xe9, 0x85, 0x20, 0x35, 0xea, 0x2a, 0x42, 0xa4, - 0x54, 0xec, 0xf0, 0x9e, 0xfc, 0x1a, 0x98, 0x78, 0x66, 0xe5, 0x28, 0x8d, 0xe7, 0x00, 0x13, 0xa4, 0xd0, 0x37, 0xe5, - 0x57, 0x80, 0x1b, 0xba, 0x88, 0xc2, 0xec, 0x4d, 0x5c, 0x05, 0xb5, 0xd5, 0xf4, 0x7b, 0x07, 0x27, 0xf6, 0xb2, 0xee, - 0xf7, 0x53, 0xa2, 0xf1, 0xc3, 0xd0, 0x0b, 0xfc, 0x7b, 0x3c, 0x3d, 0x34, 0x41, 0x6a, 0x5e, 0x79, 0x80, 0x57, 0x74, - 0xb9, 0xb5, 0x29, 0x57, 0x34, 0x2e, 0xe6, 0x35, 0x22, 0xc2, 0xa7, 0x8e, 0x62, 0xbb, 0xcd, 0x8f, 0x53, 0x1b, 0x83, - 0x41, 0x08, 0xf7, 0xad, 0x8c, 0xdf, 0x27, 0x5e, 0x35, 0x8b, 0xe6, 0xa0, 0x28, 0xcd, 0x34, 0x49, 0x48, 0x21, 0xbd, - 0x04, 0xe8, 0xa3, 0x41, 0xa8, 0xd5, 0x95, 0x7f, 0x24, 0x5e, 0xaa, 0xa6, 0xb5, 0x79, 0x8a, 0x35, 0x0a, 0xc4, 0x2c, - 0x9a, 0x37, 0x2c, 0xa3, 0x43, 0x52, 0x5d, 0x2e, 0x4d, 0x33, 0xfe, 0xb0, 0x9a, 0xa1, 0x5a, 0x71, 0xd2, 0x04, 0x35, - 0x4a, 0xb7, 0x70, 0x01, 0xfc, 0x1b, 0xdd, 0x71, 0x54, 0xa3, 0x48, 0xd1, 0x80, 0x4f, 0x20, 0xa6, 0xab, 0x30, 0x9b, - 0x27, 0xac, 0x35, 0x75, 0xcd, 0xe8, 0xf7, 0x65, 0x9c, 0x90, 0x49, 0x42, 0x72, 0x3e, 0x5c, 0xae, 0x1f, 0x49, 0x75, - 0x01, 0xa4, 0xca, 0x39, 0x9b, 0xf5, 0x7a, 0x73, 0xc0, 0xe8, 0x85, 0xf5, 0x0b, 0x1b, 0x57, 0x70, 0x79, 0x4d, 0x98, - 0xbb, 0xea, 0x47, 0x98, 0x65, 0x50, 0x05, 0xa4, 0xf9, 0xb1, 0xa0, 0xd3, 0x2b, 0x17, 0x88, 0xfa, 0xf5, 0x48, 0x5d, - 0x50, 0x66, 0xe9, 0xdc, 0x22, 0x02, 0x01, 0xaf, 0x61, 0xf5, 0x04, 0x92, 0x7d, 0xf9, 0xd8, 0xa7, 0x19, 0x05, 0xaa, - 0x23, 0x00, 0x65, 0xb3, 0x7e, 0x08, 0xfb, 0x07, 0x84, 0x13, 0xea, 0x6f, 0xde, 0xca, 0x59, 0x43, 0xf2, 0x40, 0xaa, - 0x09, 0x8f, 0xe1, 0xd4, 0x58, 0xe0, 0x4b, 0x8b, 0xde, 0x54, 0xf0, 0x9a, 0xe0, 0xb8, 0x17, 0x68, 0xed, 0x5b, 0xc0, - 0x11, 0x22, 0xb8, 0x0c, 0x4d, 0x9c, 0xf6, 0xf6, 0xbd, 0x00, 0x09, 0xcd, 0x2d, 0x9c, 0xeb, 0xb7, 0x2e, 0x68, 0x71, - 0x8a, 0x9c, 0x2c, 0xba, 0xc0, 0x40, 0x17, 0x64, 0xde, 0xf8, 0x67, 0x0e, 0x2b, 0x17, 0x20, 0x7b, 0xa9, 0x58, 0x49, - 0xc4, 0xb6, 0x57, 0x7f, 0x94, 0xca, 0x7e, 0x7b, 0x61, 0x4d, 0xe0, 0x97, 0x89, 0xfd, 0x12, 0x99, 0x7c, 0xd3, 0x53, - 0x93, 0xaf, 0x8c, 0x85, 0x4e, 0x2d, 0x83, 0x73, 0x7a, 0x62, 0x70, 0xee, 0xed, 0xad, 0xda, 0x94, 0x30, 0x14, 0x24, - 0x81, 0xa6, 0x4b, 0x0f, 0xeb, 0xa6, 0x3f, 0x3f, 0x69, 0xf1, 0x6b, 0xd5, 0xbe, 0x75, 0x3f, 0x0e, 0xb1, 0x8b, 0x5f, - 0x26, 0x9e, 0x61, 0x1f, 0xf5, 0x81, 0x03, 0x4c, 0x46, 0x4c, 0x5c, 0xf7, 0xfb, 0x50, 0xd8, 0x6c, 0x3c, 0x1f, 0xd5, - 0xc5, 0xcf, 0xc5, 0x03, 0x40, 0x39, 0x54, 0x60, 0x97, 0x43, 0x19, 0xca, 0x88, 0x4d, 0x6d, 0xb9, 0xe7, 0xf7, 0x97, - 0x61, 0x0e, 0xf2, 0x8e, 0xc6, 0xc4, 0xb9, 0x00, 0x31, 0x0c, 0xbe, 0xfe, 0xfd, 0x93, 0x43, 0xda, 0x7c, 0x7f, 0x01, - 0xdf, 0x1d, 0x5d, 0x7c, 0x40, 0x8e, 0x9b, 0x8b, 0x4d, 0x59, 0xdc, 0xa7, 0xb1, 0xb8, 0xf8, 0x1e, 0x52, 0xbf, 0xbf, - 0x28, 0xca, 0x8b, 0xef, 0x55, 0x65, 0xbe, 0xbf, 0xa0, 0x05, 0x37, 0xfa, 0xdd, 0x9a, 0x78, 0xff, 0xc8, 0x35, 0xed, - 0xd9, 0x12, 0xc2, 0xb1, 0xb4, 0xfa, 0x11, 0x94, 0x88, 0x8a, 0x14, 0x55, 0x86, 0xb2, 0x5a, 0x3b, 0xce, 0xfb, 0x44, - 0xc3, 0x63, 0xd3, 0x84, 0xc4, 0xd5, 0x12, 0xd6, 0xa1, 0x9e, 0x9d, 0x36, 0xc9, 0x8e, 0xf3, 0x40, 0x1d, 0x10, 0x15, - 0x7f, 0x5e, 0x8d, 0x76, 0xf4, 0x35, 0xf8, 0xd6, 0xf1, 0x58, 0x8d, 0xf6, 0xe6, 0xa7, 0x4f, 0xd6, 0x4a, 0x19, 0x6c, - 0xa4, 0x18, 0x85, 0x90, 0x28, 0x6e, 0xd7, 0x63, 0x00, 0xfc, 0xef, 0x1f, 0x8f, 0xf4, 0x7b, 0x2f, 0x7f, 0xab, 0xdd, - 0xd2, 0xaa, 0xe7, 0x87, 0x16, 0x61, 0xc6, 0xab, 0xda, 0xb0, 0xb3, 0x1d, 0x24, 0xa0, 0xf4, 0xa1, 0x69, 0x50, 0x53, - 0x44, 0x3f, 0x61, 0x35, 0xb1, 0x9c, 0xc3, 0x82, 0x94, 0x38, 0xc4, 0x70, 0x8c, 0x76, 0xe8, 0x71, 0xba, 0xa8, 0x79, - 0x2a, 0xdf, 0x21, 0xe3, 0xd6, 0xf7, 0x01, 0xc9, 0xa5, 0x70, 0xf9, 0xc1, 0x0b, 0x0d, 0x26, 0x7a, 0x91, 0x57, 0x45, - 0x26, 0x46, 0x82, 0x46, 0xf9, 0x0d, 0x89, 0x33, 0x17, 0x58, 0x8b, 0x0b, 0x85, 0x10, 0x16, 0x12, 0x2a, 0x77, 0x51, - 0x52, 0x7a, 0x70, 0xf1, 0xe4, 0x50, 0x36, 0xbf, 0x13, 0x26, 0xc4, 0x68, 0x01, 0x34, 0x38, 0xfb, 0x76, 0x79, 0x0f, - 0x61, 0x99, 0x7b, 0xbf, 0xbf, 0x59, 0xe5, 0x05, 0xc4, 0x65, 0x5e, 0x48, 0xc5, 0x6a, 0x79, 0x01, 0x34, 0x79, 0x22, - 0xbe, 0x08, 0x2b, 0x39, 0x0d, 0xaa, 0x8e, 0x62, 0xd5, 0x36, 0x5e, 0x56, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, - 0xdd, 0x67, 0xaf, 0x95, 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, - 0xe7, 0x26, 0xc8, 0x3f, 0xbe, 0x39, 0xa3, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, - 0x9b, 0x23, 0x35, 0x79, 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, - 0x67, 0x2b, 0x2a, 0x2f, 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xaa, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, - 0x62, 0x86, 0x29, 0xd6, 0x5f, 0xd8, 0xf2, 0xdb, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x6b, 0x16, 0xc2, - 0xf1, 0xb8, 0x9d, 0x14, 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0xc7, 0x63, 0x57, 0xcb, 0x36, 0xc2, 0x83, 0x87, 0xaa, - 0x85, 0xdb, 0x86, 0x55, 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, - 0x1b, 0x1b, 0xe0, 0x1a, 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, - 0x09, 0xa3, 0x15, 0xc2, 0xef, 0xa1, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, - 0x4a, 0xb1, 0x34, 0x6f, 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0xf3, 0xd0, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, - 0xcd, 0xe6, 0xc0, 0x7d, 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x67, 0xcb, 0xe3, - 0xf0, 0x2d, 0xfc, 0xcb, 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xcb, 0x15, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, - 0xad, 0xa8, 0x0d, 0x7f, 0xc3, 0xbf, 0x84, 0x7d, 0x84, 0xfd, 0x96, 0xe3, 0x4d, 0xd2, 0x10, 0x90, 0x09, 0xc4, 0x85, - 0x85, 0x20, 0xc1, 0xdf, 0x72, 0xc9, 0x3f, 0x27, 0x7c, 0xb6, 0x28, 0x81, 0xac, 0x0e, 0xa3, 0xf8, 0x84, 0x62, 0xa2, - 0x10, 0x86, 0x5b, 0x42, 0xef, 0xe8, 0xbf, 0x11, 0x25, 0xd9, 0xa4, 0xb2, 0x62, 0x3d, 0x90, 0x49, 0x12, 0x4c, 0xb0, - 0xf2, 0x42, 0xf9, 0xc2, 0xbd, 0x50, 0x6a, 0xad, 0x05, 0xad, 0x5f, 0xfe, 0x24, 0xf1, 0x0c, 0xe8, 0x1e, 0xc8, 0x18, - 0x74, 0x1b, 0x51, 0x4d, 0x72, 0x4c, 0x1f, 0xa5, 0xf3, 0x0c, 0x54, 0x40, 0x17, 0x9b, 0x2c, 0xac, 0x97, 0x45, 0xb9, - 0x6e, 0x85, 0x87, 0xca, 0xd2, 0x47, 0xea, 0x31, 0xe6, 0x85, 0x79, 0x72, 0x26, 0x1f, 0x3c, 0x02, 0x34, 0x3c, 0xca, - 0xd3, 0xaa, 0xa3, 0xb4, 0x7e, 0x60, 0x19, 0x30, 0x02, 0x67, 0xca, 0x80, 0x47, 0x58, 0x06, 0xe6, 0x69, 0x97, 0xa1, - 0x06, 0xb1, 0x46, 0xd5, 0x95, 0xda, 0x60, 0xce, 0x14, 0x25, 0x9f, 0x62, 0x69, 0x85, 0x31, 0x34, 0x75, 0xe5, 0x91, - 0xf5, 0x92, 0x13, 0xf6, 0x6c, 0x37, 0x90, 0x6e, 0x61, 0xab, 0xc0, 0x05, 0x5d, 0xcb, 0x12, 0xe5, 0xa2, 0x5b, 0x46, - 0x94, 0x89, 0x90, 0xfa, 0xd9, 0xc3, 0x99, 0x56, 0xfb, 0x8d, 0x9d, 0x74, 0x68, 0x8f, 0x14, 0xbd, 0x60, 0x20, 0x3e, - 0xed, 0x91, 0x52, 0xcf, 0x1a, 0xb9, 0x0c, 0x6c, 0xe9, 0x52, 0xd5, 0xf3, 0x5f, 0xa0, 0x7c, 0x07, 0x33, 0xe3, 0x6c, - 0xf6, 0xbb, 0xde, 0xdc, 0x9e, 0x1c, 0xea, 0xe6, 0x77, 0xd6, 0xeb, 0xc1, 0xd6, 0x20, 0x13, 0x5f, 0x28, 0xea, 0x29, - 0xab, 0x10, 0x2b, 0x32, 0xfb, 0x5f, 0xc2, 0xfb, 0x1d, 0xde, 0x1a, 0xa1, 0x59, 0x19, 0x0f, 0xf3, 0xd1, 0x93, 0x83, - 0x68, 0x7e, 0xef, 0x2c, 0xdb, 0xca, 0x55, 0xc9, 0x6c, 0xbf, 0x9f, 0x24, 0xcd, 0xd9, 0xe3, 0x35, 0x92, 0x3a, 0xc0, - 0xc7, 0xeb, 0x33, 0x7c, 0xa4, 0x12, 0x4a, 0x2d, 0xa8, 0x6a, 0xd0, 0xfa, 0xd8, 0xef, 0xad, 0xe7, 0xf4, 0xf1, 0x53, - 0x39, 0xdd, 0x92, 0x22, 0x8c, 0x1f, 0x18, 0x4c, 0xd9, 0x89, 0x53, 0x97, 0xaa, 0x19, 0xd2, 0xbb, 0x6e, 0x95, 0xd4, - 0x65, 0x8f, 0x12, 0x41, 0xa8, 0x83, 0xf5, 0x8b, 0xfd, 0x10, 0x66, 0xb6, 0xe8, 0x0f, 0x9b, 0xd5, 0x9c, 0x50, 0x10, - 0x01, 0xa2, 0x55, 0xde, 0x07, 0x4e, 0x49, 0xc2, 0xac, 0xb9, 0x21, 0xdd, 0x7a, 0x2b, 0xa5, 0xbd, 0x92, 0x02, 0xfa, - 0x65, 0x7e, 0x3c, 0xa2, 0xf9, 0xcd, 0xec, 0x5c, 0x95, 0xb4, 0xe5, 0x00, 0x22, 0x75, 0xde, 0xb4, 0x2f, 0x1d, 0x0e, - 0xfe, 0x83, 0xba, 0x12, 0xe5, 0x44, 0xd0, 0x51, 0xb4, 0x60, 0xb4, 0x5a, 0xb5, 0xab, 0xc8, 0xa6, 0x42, 0xb6, 0x24, - 0xc2, 0x89, 0x92, 0xbd, 0x12, 0xea, 0xa3, 0x5c, 0xed, 0x99, 0x86, 0xf8, 0x33, 0x01, 0x9b, 0x36, 0xf8, 0x5b, 0xe0, - 0x5e, 0x06, 0x67, 0xa6, 0x7d, 0x1a, 0x46, 0x40, 0x64, 0x0e, 0xc1, 0x7e, 0x7e, 0xd7, 0x83, 0x1c, 0x1e, 0x74, 0xa4, - 0xbf, 0xaa, 0x67, 0x05, 0x9e, 0xb9, 0x67, 0x9e, 0xbf, 0x3e, 0x93, 0x9e, 0x57, 0xf0, 0x40, 0x73, 0x1f, 0x66, 0xfc, - 0x45, 0x59, 0x86, 0xfb, 0xd1, 0xb2, 0x2c, 0xd6, 0x5e, 0xa4, 0xf7, 0xf1, 0x4c, 0x8a, 0x81, 0x44, 0x87, 0x99, 0xd1, - 0x55, 0xac, 0xe3, 0x1c, 0xc6, 0xbd, 0x3d, 0x09, 0x2b, 0xb4, 0x7f, 0x96, 0xd8, 0xeb, 0x02, 0x00, 0x1c, 0xb2, 0x06, - 0xad, 0xf0, 0x4e, 0xb7, 0xb7, 0x7b, 0x5c, 0x52, 0xa2, 0xb8, 0x51, 0xf3, 0xb3, 0x1a, 0x5a, 0x26, 0xa8, 0x65, 0xd6, - 0x9d, 0x4c, 0xa6, 0x48, 0x02, 0xdf, 0x86, 0xbd, 0x66, 0x79, 0x35, 0x6f, 0xe4, 0xf6, 0xf0, 0x2e, 0x5c, 0x8b, 0x58, - 0x5b, 0xd0, 0x49, 0x47, 0xc6, 0xe1, 0x5e, 0x68, 0x6e, 0xa4, 0x87, 0x27, 0x55, 0x12, 0x96, 0x22, 0x86, 0x5b, 0x20, - 0x3b, 0xa8, 0x6d, 0x25, 0x28, 0x81, 0x04, 0xf6, 0x43, 0x29, 0x96, 0xe9, 0x4e, 0x00, 0x98, 0x03, 0xff, 0x53, 0x1a, - 0xbb, 0xdd, 0x9d, 0x87, 0x78, 0xd5, 0xc8, 0xfb, 0x06, 0x21, 0xd8, 0x5f, 0x81, 0x9c, 0x06, 0x0c, 0x22, 0xc5, 0x48, - 0x16, 0x0c, 0x24, 0x00, 0x15, 0xdf, 0x80, 0x49, 0x6e, 0x5a, 0x79, 0x7e, 0x50, 0xe9, 0x0e, 0xa6, 0x7d, 0xd0, 0xbd, - 0xb8, 0xd6, 0x0c, 0x90, 0x7f, 0x27, 0x11, 0xff, 0x5b, 0xed, 0x95, 0xac, 0x62, 0x99, 0xdf, 0x98, 0x8b, 0x4e, 0x06, - 0x57, 0x0d, 0xe1, 0x17, 0xb3, 0x6c, 0xce, 0xa3, 0x59, 0xa6, 0x43, 0xfd, 0x8b, 0xe6, 0xa4, 0x14, 0xc0, 0x50, 0xc7, - 0x0b, 0xb0, 0xc6, 0xbb, 0xd2, 0x4d, 0x2b, 0x1e, 0x69, 0x8c, 0x51, 0x50, 0xa1, 0x83, 0xd0, 0xdf, 0x6a, 0x80, 0xd7, - 0x60, 0x92, 0x1b, 0x21, 0xf7, 0xc1, 0x05, 0xdd, 0xd0, 0x2d, 0xe7, 0x2e, 0x41, 0x4d, 0xaa, 0x96, 0x5f, 0x85, 0x50, - 0xef, 0x6a, 0xc9, 0xa5, 0xda, 0x7c, 0x6a, 0x94, 0x35, 0x82, 0x4c, 0x8e, 0xd2, 0xef, 0x53, 0x2e, 0xdc, 0xdc, 0x98, - 0xac, 0x8f, 0x47, 0xaf, 0xe0, 0xa6, 0xc6, 0x3f, 0x56, 0x92, 0x45, 0xd4, 0x1a, 0x12, 0x61, 0x6b, 0xb7, 0x42, 0xf7, - 0x1e, 0x37, 0x4a, 0xf3, 0x28, 0xdb, 0xc6, 0xa2, 0xf2, 0x7a, 0x09, 0x58, 0x8b, 0x7b, 0x40, 0x86, 0x4a, 0x4b, 0x3f, - 0x67, 0x05, 0x40, 0x06, 0x48, 0x61, 0xe3, 0x47, 0xa4, 0xbd, 0xfa, 0xe0, 0xa5, 0x7e, 0xbf, 0x6f, 0x4c, 0xf9, 0xef, - 0x1f, 0x72, 0x60, 0x26, 0x14, 0x65, 0xbd, 0x87, 0x09, 0x54, 0x79, 0xa9, 0x4f, 0xda, 0xb3, 0x9a, 0x3f, 0xdf, 0xd4, - 0x1e, 0x90, 0x5a, 0xf9, 0x16, 0x73, 0xd5, 0x2b, 0xfb, 0x62, 0x73, 0x48, 0xab, 0x5b, 0xa3, 0x71, 0x10, 0x2c, 0xad, - 0xde, 0x68, 0x95, 0x43, 0xd5, 0xf0, 0x1c, 0x44, 0x2a, 0xeb, 0xea, 0x9a, 0x3b, 0x57, 0xd7, 0x82, 0x23, 0x81, 0x6c, - 0xc9, 0x21, 0x2c, 0x8d, 0x85, 0xdc, 0x2b, 0x8f, 0xc7, 0xc2, 0xef, 0xf7, 0xd3, 0x59, 0x8e, 0x97, 0x16, 0xa0, 0x4c, - 0xdb, 0xd4, 0x5e, 0xe8, 0x1f, 0x8f, 0x3f, 0x82, 0xd7, 0x88, 0x7f, 0x3c, 0x96, 0xfd, 0xfe, 0x47, 0x73, 0x93, 0xb9, - 0x1c, 0x2b, 0xa5, 0xec, 0x35, 0x2a, 0xdd, 0xdf, 0x24, 0xbc, 0xf7, 0xbf, 0x47, 0xff, 0x7b, 0x74, 0xdd, 0x53, 0x01, - 0x60, 0x09, 0x9f, 0xe1, 0x0d, 0x9d, 0xa9, 0xcb, 0x39, 0x93, 0xee, 0xee, 0xca, 0x0f, 0xbd, 0xa7, 0xf1, 0xe1, 0x7b, - 0x73, 0xd3, 0xc6, 0x5f, 0xf3, 0x13, 0x4d, 0x42, 0xc7, 0x45, 0xff, 0x78, 0xfc, 0x94, 0x68, 0x7d, 0x5a, 0xaa, 0xf4, - 0x69, 0x0a, 0x3c, 0xc9, 0xb0, 0xe1, 0xba, 0x85, 0xe9, 0x68, 0x7e, 0xdc, 0x7c, 0x95, 0xbc, 0x38, 0x4b, 0xe1, 0xda, - 0x0b, 0x3a, 0x97, 0x29, 0x58, 0x57, 0x86, 0xe0, 0x66, 0x10, 0x40, 0xea, 0x10, 0xd2, 0xac, 0x69, 0xf8, 0x97, 0xdc, - 0x15, 0xbc, 0xb5, 0xc7, 0xbb, 0xc1, 0x88, 0x52, 0x47, 0xfa, 0xa4, 0x0d, 0xa1, 0x4b, 0x2a, 0xf9, 0x8f, 0x22, 0x8f, - 0x31, 0x66, 0xe3, 0x15, 0x91, 0x7d, 0x16, 0xf9, 0xcb, 0x02, 0x00, 0x8b, 0x00, 0x01, 0x39, 0x9d, 0x3b, 0x92, 0xf8, - 0xcf, 0xc9, 0xb7, 0x7f, 0x4c, 0x97, 0xf6, 0xa1, 0x2c, 0x56, 0xa5, 0xa8, 0xaa, 0x93, 0xd2, 0xf6, 0xb6, 0x5c, 0x0f, - 0xf4, 0xa1, 0xfd, 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, - 0x58, 0x3f, 0x7f, 0xd8, 0xbf, 0x89, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, - 0xc3, 0x54, 0xe2, 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0xbf, 0xe7, 0x30, 0xff, 0x75, - 0x7b, 0xb0, 0x3e, 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0xe7, 0xc2, 0x22, 0xf9, - 0xf5, 0xc9, 0x91, 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x89, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9d, 0xff, 0x95, 0x99, 0xff, - 0x03, 0x8c, 0x49, 0x28, 0x9e, 0x73, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0xcf, 0x81, - 0x83, 0xf9, 0x39, 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0xd7, 0x16, 0xcf, 0x95, - 0x5c, 0x10, 0xfa, 0xba, 0x0a, 0xb3, 0x71, 0x5d, 0x6c, 0x2b, 0x51, 0x6c, 0x21, 0x6c, 0x04, 0xd4, 0xb2, 0xd5, 0xb4, - 0xb6, 0x15, 0xb2, 0x3f, 0x89, 0x16, 0x6d, 0x97, 0xa1, 0x9a, 0x8c, 0xb2, 0x74, 0x33, 0x05, 0x52, 0xbd, 0x00, 0xce, - 0x22, 0xf3, 0xca, 0x3b, 0x67, 0x0f, 0xd8, 0xa1, 0xf1, 0x14, 0x18, 0x51, 0xe9, 0x8f, 0xaa, 0x31, 0x3a, 0x3d, 0xd1, - 0xef, 0x57, 0x53, 0x0a, 0xf9, 0xfa, 0x09, 0x30, 0xb9, 0x6a, 0xb9, 0x00, 0x7d, 0x19, 0xea, 0xa0, 0x12, 0xa5, 0x56, - 0x0c, 0x23, 0x16, 0x7e, 0x12, 0xc8, 0xde, 0x4c, 0x41, 0xcd, 0x2a, 0x4a, 0x42, 0x25, 0x2a, 0x25, 0x5b, 0x13, 0xd4, - 0xd2, 0xfb, 0xa2, 0xa8, 0x0f, 0x15, 0x38, 0x4a, 0x46, 0xda, 0x2c, 0xa7, 0xcc, 0xb8, 0x28, 0x73, 0xd1, 0x0f, 0xf6, - 0x2f, 0xc0, 0xf8, 0x92, 0xf9, 0x2c, 0xf7, 0x1d, 0x9d, 0xd3, 0x76, 0x5c, 0xa0, 0xcc, 0x2d, 0xa7, 0xad, 0x96, 0x3c, - 0x26, 0xef, 0x59, 0xb0, 0xed, 0xbf, 0x48, 0x90, 0x57, 0x11, 0xe6, 0x13, 0xaa, 0x6c, 0xfe, 0x9e, 0x7b, 0xc4, 0x3e, - 0xda, 0xe1, 0xc2, 0x44, 0xa4, 0xb7, 0x60, 0x49, 0x0c, 0xb3, 0x52, 0x84, 0xf1, 0x1e, 0xbc, 0x7f, 0xb6, 0x95, 0x18, - 0x5d, 0xa0, 0x93, 0xfb, 0xc5, 0x43, 0x5a, 0x27, 0x17, 0x6f, 0x5e, 0x5d, 0x7c, 0xdf, 0x1b, 0x14, 0xa3, 0x34, 0x1e, - 0xf4, 0xbe, 0xbf, 0x58, 0x6f, 0x01, 0x22, 0x53, 0x5c, 0xc4, 0x64, 0x4a, 0x13, 0xf1, 0x05, 0x19, 0x06, 0x2f, 0xea, - 0x44, 0x5c, 0xd0, 0xc4, 0x74, 0x5f, 0xa3, 0x34, 0xf9, 0x76, 0x14, 0xe6, 0xf0, 0x72, 0x29, 0xb6, 0x95, 0x88, 0xc1, - 0x4e, 0xa9, 0xe6, 0xd9, 0xc9, 0x59, 0x2c, 0x3d, 0x06, 0x5d, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, - 0x05, 0x84, 0x1e, 0xf0, 0xcc, 0xcf, 0xe3, 0x51, 0x24, 0x10, 0x6a, 0xc1, 0x9c, 0x4c, 0x23, 0xba, 0x21, 0xbd, 0xc4, - 0x3e, 0x03, 0xb3, 0x90, 0xd2, 0x3c, 0xb8, 0xb9, 0x5a, 0xb4, 0xdc, 0x39, 0x2b, 0x47, 0x61, 0xb5, 0x11, 0x51, 0x8d, - 0x54, 0xc7, 0xe0, 0xbc, 0x03, 0x11, 0x00, 0x8a, 0x11, 0x3c, 0xe3, 0x51, 0xbf, 0x1f, 0xa9, 0xa0, 0x9c, 0x84, 0x7e, - 0x51, 0xe8, 0x97, 0xc6, 0xa0, 0x8c, 0xf9, 0x97, 0x50, 0x13, 0x03, 0xd4, 0x3b, 0x1e, 0x2a, 0x8e, 0x00, 0x5c, 0xce, - 0x11, 0x33, 0xce, 0x7b, 0xdc, 0x45, 0xe3, 0x54, 0xbc, 0x13, 0xea, 0x3a, 0x58, 0x2a, 0xd4, 0x79, 0x53, 0x1f, 0xe9, - 0x39, 0x69, 0x12, 0x34, 0x88, 0x1b, 0x78, 0xbc, 0x1a, 0x02, 0xaa, 0xb5, 0x90, 0x7a, 0x0b, 0x9d, 0x52, 0xd5, 0x21, - 0xb0, 0x06, 0xb8, 0x44, 0x61, 0x3b, 0x61, 0x72, 0x44, 0xdb, 0xb2, 0x14, 0xf9, 0x09, 0x1b, 0xb4, 0x4b, 0x46, 0xa6, - 0x0e, 0x2e, 0x97, 0xcb, 0x89, 0xa8, 0x7f, 0xcd, 0xb7, 0x00, 0xce, 0x0b, 0xf9, 0xad, 0xdd, 0x6c, 0x99, 0x64, 0xbb, - 0xfe, 0x3f, 0xbc, 0x7d, 0x09, 0x77, 0xdb, 0x46, 0xb2, 0xee, 0x5f, 0x11, 0xf1, 0x1c, 0x06, 0x6d, 0x36, 0x29, 0x52, - 0xb1, 0x33, 0x09, 0xa8, 0x16, 0xaf, 0xe2, 0x25, 0x71, 0x26, 0x5e, 0x62, 0x39, 0x99, 0xcc, 0xf0, 0xf1, 0x2a, 0x10, - 0xd0, 0x12, 0x11, 0x43, 0x68, 0x06, 0x00, 0xb5, 0x84, 0xc4, 0x7f, 0x7f, 0xa7, 0xaa, 0x77, 0x10, 0x94, 0x3d, 0xf3, - 0xee, 0x7b, 0xc7, 0xe7, 0x58, 0x44, 0xa3, 0xd1, 0x7b, 0x57, 0x57, 0xd7, 0xf2, 0x55, 0x65, 0x63, 0x96, 0x94, 0xbc, - 0x5a, 0x89, 0xa2, 0xca, 0x6e, 0xf8, 0x4f, 0xe6, 0xa5, 0x1f, 0x40, 0x0a, 0xed, 0x48, 0x5f, 0xb7, 0xbb, 0xa3, 0xc4, - 0x38, 0xa6, 0x1c, 0xd7, 0x52, 0xe9, 0x5e, 0x8d, 0xaa, 0x13, 0x37, 0x5b, 0xe5, 0x5a, 0x66, 0x69, 0xca, 0x8b, 0x57, - 0x45, 0x9a, 0x25, 0x4e, 0x72, 0xac, 0x02, 0x54, 0xdb, 0xc8, 0x57, 0x36, 0x36, 0xf2, 0xf3, 0xac, 0xc2, 0x80, 0xc1, - 0x5e, 0xa3, 0x5a, 0xa1, 0xa6, 0x74, 0xe0, 0x0b, 0xf1, 0x1e, 0x23, 0x6e, 0xb3, 0x22, 0x01, 0x86, 0x1f, 0x13, 0xd5, - 0x25, 0x3d, 0x85, 0x28, 0x0f, 0x32, 0x1e, 0xf7, 0x73, 0x8e, 0x88, 0xd7, 0x46, 0x65, 0x0e, 0x4c, 0xb6, 0x52, 0x41, - 0x22, 0xd8, 0x5d, 0x36, 0x57, 0x8b, 0x68, 0x21, 0xef, 0x42, 0xbd, 0x78, 0xbb, 0xed, 0x25, 0x92, 0x0e, 0x58, 0xf9, - 0x69, 0xf0, 0x32, 0xce, 0x72, 0x9e, 0x1e, 0xd4, 0xe2, 0x40, 0x6e, 0xa8, 0x03, 0xe9, 0xcc, 0x01, 0x3b, 0xef, 0xcb, - 0xfa, 0x40, 0xad, 0xe9, 0x03, 0xd5, 0xce, 0x03, 0xb8, 0x60, 0xe0, 0xce, 0xbd, 0xca, 0x6e, 0x78, 0x71, 0x00, 0xca, - 0x40, 0x63, 0x3c, 0xd0, 0x54, 0xf5, 0x48, 0x4e, 0x8c, 0x0a, 0x5c, 0x9d, 0xa8, 0x83, 0x39, 0xa0, 0xdf, 0x03, 0x52, - 0x54, 0xeb, 0xed, 0x4a, 0x1d, 0xb4, 0x01, 0xfd, 0x69, 0xa9, 0xfb, 0xa0, 0xa2, 0xc5, 0xcb, 0x90, 0xc0, 0xde, 0x90, - 0x2a, 0xa4, 0x56, 0x2d, 0xab, 0x40, 0xf1, 0x86, 0xb3, 0x78, 0x77, 0xae, 0x25, 0x1b, 0xe7, 0x25, 0x02, 0x7b, 0x65, - 0x45, 0x1d, 0x67, 0xc5, 0xa9, 0x93, 0xca, 0x1b, 0xe5, 0x24, 0x53, 0x69, 0xdf, 0xb2, 0x82, 0xba, 0x3b, 0x44, 0xdf, - 0x22, 0xf5, 0x61, 0xf0, 0x22, 0xac, 0xc9, 0x8c, 0xf7, 0xfb, 0x62, 0x26, 0xa2, 0x62, 0x56, 0x1d, 0x16, 0x91, 0x44, - 0x68, 0xdb, 0x27, 0x02, 0x7a, 0x50, 0x02, 0xe4, 0x0a, 0x80, 0xea, 0x87, 0x84, 0x3f, 0x0f, 0x49, 0x7d, 0x3a, 0x85, - 0x3e, 0xa5, 0xb2, 0x5e, 0x71, 0x0a, 0xaa, 0x1b, 0x6f, 0x64, 0xbd, 0x0a, 0x5a, 0x3c, 0x96, 0x63, 0xb5, 0xa1, 0x6d, - 0x4e, 0x8d, 0x77, 0xbd, 0xde, 0x60, 0xd2, 0xe6, 0x42, 0xae, 0xc2, 0x90, 0x44, 0xb7, 0x85, 0x13, 0x3e, 0xc4, 0x60, - 0x65, 0xb5, 0x36, 0xbf, 0x8e, 0xfd, 0x91, 0x15, 0x29, 0xee, 0x67, 0x43, 0x9c, 0xbb, 0x78, 0x3c, 0xa7, 0xfa, 0x46, - 0x49, 0x8b, 0x74, 0x9b, 0xef, 0xd5, 0x65, 0x48, 0x51, 0x51, 0x4d, 0x1a, 0x55, 0x66, 0xd0, 0x7d, 0xdb, 0xbc, 0x55, - 0x3d, 0xc2, 0x04, 0x78, 0xa5, 0x32, 0xa8, 0x46, 0xe3, 0x81, 0x58, 0xd5, 0xa3, 0x72, 0x5d, 0x14, 0x88, 0x36, 0x0c, - 0x39, 0x66, 0x86, 0x90, 0x64, 0x7f, 0xf1, 0xef, 0x64, 0x70, 0x85, 0x32, 0xbe, 0xd5, 0x70, 0xde, 0xb5, 0xf1, 0xec, - 0x6e, 0x22, 0x37, 0x27, 0x16, 0xd6, 0xb8, 0x0f, 0xfe, 0x51, 0xab, 0x9d, 0x05, 0x94, 0x35, 0xad, 0x6a, 0x38, 0xdc, - 0xa3, 0x3a, 0x16, 0xa5, 0x06, 0x24, 0x76, 0xc8, 0x72, 0xd9, 0x3a, 0x66, 0xd0, 0x80, 0xfe, 0x2e, 0xbb, 0x5e, 0x5f, - 0x23, 0x6a, 0x5b, 0x81, 0xac, 0x93, 0x90, 0xfe, 0x25, 0xed, 0x51, 0x57, 0xf6, 0x54, 0xee, 0xb7, 0x6d, 0xaa, 0x1c, - 0x1a, 0x20, 0x79, 0xec, 0xe6, 0x2c, 0x90, 0x1d, 0x09, 0xa2, 0x40, 0x6e, 0xbd, 0x60, 0xea, 0x9c, 0x32, 0x65, 0x07, - 0xf2, 0x73, 0xa9, 0xcf, 0xb0, 0xcf, 0x38, 0x62, 0xf4, 0x52, 0x89, 0xc1, 0xd4, 0x47, 0x1b, 0xd5, 0xb4, 0x56, 0x80, - 0xaa, 0x9f, 0x6e, 0xe0, 0x4f, 0x54, 0x36, 0x68, 0xa8, 0x35, 0x12, 0x85, 0xa4, 0x89, 0x12, 0x3a, 0x96, 0x96, 0x2a, - 0x98, 0x42, 0x27, 0x91, 0x30, 0x04, 0x34, 0x4c, 0x88, 0x4a, 0x2a, 0xf1, 0xd6, 0x00, 0xce, 0x7c, 0xbc, 0xa8, 0xd6, - 0xa5, 0x32, 0x98, 0xfb, 0x21, 0xbe, 0xe1, 0xaf, 0x9e, 0x5b, 0xa3, 0xfa, 0x96, 0xb5, 0xbe, 0xa3, 0x05, 0xf9, 0x21, - 0xe4, 0x14, 0x1d, 0x98, 0xd8, 0xc9, 0x06, 0x0f, 0xe6, 0xa2, 0x51, 0xa1, 0x2e, 0xde, 0xaa, 0xf8, 0x2b, 0xca, 0x04, - 0xef, 0x01, 0x4f, 0x11, 0x65, 0x78, 0x58, 0x69, 0xab, 0x6a, 0x7c, 0x2a, 0x58, 0x4b, 0x0f, 0x56, 0xf2, 0x74, 0x9d, - 0xf0, 0x10, 0xf4, 0x48, 0x84, 0x9d, 0x84, 0xe5, 0x3c, 0x5e, 0xc0, 0x71, 0x52, 0x12, 0x50, 0x3b, 0xa8, 0x2b, 0xf8, - 0x7c, 0x81, 0xee, 0xaf, 0x02, 0x3d, 0xc0, 0xd0, 0x82, 0xd8, 0x0f, 0x7d, 0x3a, 0xba, 0x8e, 0x57, 0x9e, 0x8a, 0x84, - 0xcf, 0x4b, 0xb0, 0x1d, 0x92, 0xea, 0x29, 0xd0, 0x42, 0x25, 0x52, 0x3f, 0x0c, 0x7c, 0x87, 0x02, 0xbe, 0x56, 0x3a, - 0x40, 0x4d, 0x3f, 0x63, 0x9a, 0x1a, 0x67, 0xa8, 0x7c, 0xe6, 0xdc, 0x33, 0xa3, 0xe5, 0xcc, 0x80, 0x31, 0xa8, 0xdb, - 0x68, 0x8a, 0xe2, 0x9c, 0x7c, 0x16, 0x94, 0x71, 0x9a, 0xc5, 0x39, 0xf8, 0x6d, 0xc6, 0x25, 0x66, 0x4c, 0xe2, 0x9a, - 0x5f, 0x89, 0x12, 0xb4, 0xdd, 0xb9, 0x4c, 0x6d, 0x1a, 0x10, 0x90, 0xfd, 0x00, 0x56, 0x2f, 0x9e, 0x8e, 0xca, 0x7a, - 0x77, 0x29, 0x53, 0x88, 0xb2, 0x0a, 0xc1, 0xa6, 0x99, 0x2e, 0xd9, 0x69, 0x28, 0xb5, 0x39, 0x10, 0xdf, 0x08, 0x8d, - 0xfb, 0xa7, 0x61, 0x6c, 0x34, 0xc5, 0xc6, 0xee, 0x6d, 0xbb, 0xfd, 0xad, 0x70, 0xd2, 0x69, 0x4e, 0x7a, 0x8c, 0xfd, - 0x56, 0x84, 0xe5, 0xc8, 0x74, 0x84, 0xc0, 0x92, 0x73, 0x3e, 0x75, 0x5f, 0xd1, 0x62, 0x9e, 0x80, 0xe9, 0x88, 0x8a, - 0x90, 0x0b, 0x94, 0x1d, 0xa3, 0xb8, 0x03, 0x83, 0x0b, 0x66, 0x42, 0x10, 0x4b, 0x4f, 0x5d, 0x48, 0x96, 0x24, 0x65, - 0xf0, 0x3c, 0x75, 0x30, 0xe0, 0xd7, 0x4c, 0x9a, 0xbb, 0x48, 0xeb, 0xd3, 0x25, 0x99, 0xa6, 0xc8, 0x40, 0xac, 0xc3, - 0x4d, 0x96, 0x46, 0x89, 0x14, 0x91, 0x2d, 0xd1, 0x3f, 0x52, 0x53, 0x2c, 0x15, 0xae, 0x17, 0xa9, 0x12, 0xa1, 0xd5, - 0x3c, 0xc5, 0x93, 0x3a, 0x6d, 0xd2, 0x11, 0xc6, 0x9b, 0x04, 0xa5, 0x5c, 0x03, 0x03, 0x55, 0x50, 0xb5, 0x14, 0x36, - 0xe5, 0x76, 0xab, 0x2e, 0x56, 0xd5, 0x3c, 0x5e, 0xe0, 0xcb, 0x0a, 0x47, 0xf1, 0xef, 0xdc, 0x89, 0x35, 0x25, 0xb7, - 0x07, 0x35, 0x23, 0x4a, 0xe8, 0xdf, 0x39, 0x5c, 0x24, 0xbe, 0x13, 0x2a, 0xee, 0x1f, 0x5a, 0x84, 0x9c, 0xcb, 0x83, - 0x54, 0x73, 0x43, 0x3b, 0xc2, 0x7f, 0xcd, 0xf5, 0x69, 0x67, 0x74, 0x5f, 0xcd, 0xa8, 0xf0, 0x7b, 0x1d, 0x3c, 0x63, - 0xd4, 0x67, 0x03, 0x87, 0x15, 0xa2, 0xd0, 0x86, 0x9d, 0x14, 0x52, 0xb4, 0x30, 0x14, 0xf2, 0x2f, 0xa1, 0xd5, 0x09, - 0xb7, 0x66, 0x94, 0x05, 0xe3, 0xd3, 0xe2, 0xb8, 0x9a, 0x0e, 0x06, 0x05, 0xa9, 0xb5, 0x85, 0x1e, 0x5c, 0x0f, 0x1c, - 0xff, 0x1e, 0xb8, 0x85, 0x38, 0x70, 0xc8, 0xd5, 0x90, 0x6b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8f, 0x2a, 0x19, 0xbc, - 0x9a, 0xc8, 0x16, 0xfc, 0xbd, 0x08, 0x03, 0xf4, 0x49, 0x0a, 0xc0, 0x64, 0x30, 0xe5, 0x77, 0x20, 0x51, 0x3a, 0x97, - 0x37, 0xa4, 0x5f, 0x8a, 0x92, 0x5f, 0xf2, 0x92, 0x17, 0x89, 0x2d, 0xc0, 0xf0, 0x0e, 0xa6, 0xd7, 0x51, 0x4d, 0x25, - 0x10, 0xaf, 0xee, 0x71, 0xc4, 0xb5, 0xf7, 0x9f, 0xee, 0xb1, 0x01, 0x6a, 0x35, 0x8e, 0x0d, 0x2e, 0x73, 0x0c, 0x2e, - 0xe8, 0x4a, 0x62, 0xab, 0xa9, 0x86, 0x11, 0x81, 0x81, 0x0b, 0x38, 0x08, 0x4b, 0x24, 0xc7, 0x56, 0xf1, 0x9a, 0x78, - 0x52, 0xda, 0x07, 0x86, 0xa3, 0x4d, 0x72, 0x5c, 0x9b, 0x65, 0x3b, 0x81, 0xf3, 0x45, 0xe7, 0xa4, 0xe9, 0x58, 0x36, - 0x78, 0x9f, 0xd7, 0xe7, 0xd7, 0xfe, 0x21, 0xa1, 0x32, 0xd8, 0x0d, 0x6f, 0x07, 0xbb, 0xb1, 0xc2, 0xaf, 0x79, 0xb5, - 0x50, 0xf1, 0x59, 0xf4, 0x25, 0xcb, 0x6d, 0xad, 0x73, 0x4b, 0x12, 0x4a, 0x01, 0xed, 0xb2, 0x2c, 0xa8, 0x89, 0x00, - 0x74, 0x3f, 0xfc, 0x05, 0x42, 0x67, 0xf8, 0xdb, 0x63, 0x70, 0x45, 0x0a, 0xf7, 0x0e, 0x41, 0x65, 0x4c, 0x37, 0x77, - 0x6a, 0x03, 0xbe, 0x18, 0xf7, 0x67, 0x4c, 0x1d, 0xfd, 0x36, 0x13, 0xbb, 0xba, 0x6e, 0x87, 0x2c, 0xc3, 0x47, 0xb8, - 0x52, 0x00, 0x2c, 0x13, 0xfe, 0x62, 0x6c, 0x49, 0xf9, 0x09, 0xc0, 0xa9, 0xa9, 0x88, 0x3e, 0x41, 0xa0, 0xe1, 0x94, - 0x68, 0x39, 0xba, 0x91, 0x8e, 0x68, 0x1a, 0x69, 0x4d, 0xb5, 0x42, 0x7b, 0xeb, 0x61, 0x91, 0xd6, 0x34, 0x9c, 0xb8, - 0x0f, 0x8a, 0x79, 0x95, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0x51, 0x1f, 0x21, 0x2e, 0x61, 0x49, 0x14, 0x61, - 0x71, 0x4c, 0xf1, 0x63, 0x42, 0x37, 0xbe, 0xb6, 0xe9, 0x03, 0xd2, 0x5f, 0x5c, 0xb3, 0x6e, 0xca, 0xb2, 0x71, 0xed, - 0xa1, 0xe2, 0xc5, 0xd4, 0x0f, 0x7e, 0x98, 0xc8, 0x62, 0xdc, 0x2f, 0x6a, 0x57, 0x6a, 0x05, 0x30, 0xcc, 0x5d, 0xf5, - 0xf4, 0xfb, 0x7e, 0xb6, 0x1c, 0x08, 0x95, 0xdb, 0x19, 0x24, 0x7d, 0x2a, 0x9e, 0x1f, 0x1c, 0xd1, 0xca, 0x42, 0xcf, - 0x1d, 0x97, 0xc6, 0x87, 0xca, 0x6b, 0x53, 0x23, 0x5a, 0x23, 0x43, 0x65, 0xea, 0x80, 0xf5, 0xfd, 0x43, 0xb8, 0xbb, - 0xa8, 0x69, 0xa8, 0x74, 0xcf, 0x5d, 0x8b, 0x82, 0x13, 0x77, 0x80, 0xb1, 0xb8, 0x90, 0x34, 0x2a, 0x08, 0x93, 0x7a, - 0x34, 0x38, 0xc9, 0x5e, 0x5d, 0x9d, 0x9c, 0x29, 0xe6, 0x09, 0x6c, 0x54, 0xcb, 0xb6, 0xbf, 0xa2, 0x54, 0x97, 0x72, - 0x73, 0x45, 0xf1, 0x3d, 0xa4, 0xcd, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x33, 0x05, 0x17, 0xc6, 0xc1, 0xba, 0xe3, - 0x4e, 0xd9, 0x73, 0x45, 0x99, 0xc6, 0x06, 0x77, 0xed, 0x31, 0x26, 0xda, 0x7e, 0x77, 0xc9, 0x93, 0x8f, 0xc8, 0x82, - 0x7f, 0x97, 0x15, 0xe0, 0x99, 0x6c, 0x5f, 0xc9, 0xfc, 0x3f, 0xb8, 0x57, 0x5b, 0xf3, 0xce, 0x98, 0x7f, 0x3a, 0xd6, - 0xc3, 0x9d, 0xc3, 0xe4, 0x06, 0xe8, 0x0c, 0xe8, 0xe6, 0x5a, 0xa4, 0x1c, 0x90, 0x01, 0x8c, 0x45, 0x32, 0x1a, 0xf0, - 0xa1, 0x95, 0x65, 0xdb, 0x77, 0x5a, 0x5e, 0x10, 0xf6, 0x12, 0xb8, 0xe9, 0xfe, 0xda, 0xf4, 0xcc, 0xa9, 0x5a, 0x89, - 0xa2, 0x4b, 0x63, 0x63, 0x59, 0x2a, 0x81, 0xdd, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x78, 0x39, 0xcd, 0x0d, 0x75, 0xdb, - 0xd8, 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0x35, 0x22, 0xf4, 0x54, 0x8a, - 0xd0, 0xa7, 0xa9, 0xdf, 0x07, 0xb3, 0xaa, 0xd6, 0x5e, 0x9c, 0xa3, 0x41, 0xaa, 0x18, 0xf9, 0xb7, 0x37, 0xbc, 0xbc, - 0xcc, 0xc5, 0x2d, 0x60, 0x20, 0x93, 0x46, 0x2b, 0x2c, 0xaf, 0xc1, 0x9d, 0x1f, 0x1d, 0xc7, 0x19, 0xc0, 0x26, 0x41, - 0xb0, 0x56, 0x84, 0x47, 0x56, 0x89, 0x33, 0x00, 0x41, 0x76, 0x27, 0x4d, 0xc5, 0x73, 0x2d, 0x31, 0xa6, 0x2f, 0x70, - 0x57, 0x39, 0x3b, 0xd9, 0xe4, 0x66, 0xd1, 0xfb, 0x33, 0xac, 0x3a, 0x52, 0x19, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, - 0x06, 0x4d, 0x11, 0x52, 0x3e, 0x64, 0x4f, 0xda, 0xbf, 0x02, 0x1a, 0x9c, 0x67, 0xe9, 0x9d, 0xb1, 0xca, 0xdf, 0x28, - 0x21, 0x4e, 0x14, 0x53, 0x2b, 0xbe, 0x89, 0x12, 0x75, 0x7e, 0x26, 0xda, 0x0d, 0x04, 0x52, 0x7f, 0xc0, 0xa0, 0x1a, - 0x65, 0x98, 0xc0, 0x75, 0x20, 0x8a, 0xcd, 0x89, 0xea, 0x2d, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x01, 0x50, 0xef, 0xd8, - 0xfa, 0x08, 0x68, 0x96, 0xbe, 0x69, 0xad, 0x73, 0x4d, 0x28, 0xb4, 0x13, 0x98, 0x64, 0x90, 0xe4, 0x59, 0x67, 0x98, - 0xa0, 0xda, 0x8c, 0x49, 0xe7, 0x7d, 0x80, 0xee, 0xae, 0x45, 0x5d, 0x7c, 0xd3, 0xb9, 0x83, 0xf6, 0x71, 0xfd, 0x4a, - 0x8b, 0xec, 0xf1, 0xe7, 0x2d, 0x11, 0x16, 0x81, 0xb3, 0x56, 0xe7, 0xab, 0x47, 0x38, 0x30, 0x15, 0x99, 0x86, 0xbd, - 0x44, 0x2a, 0x59, 0xb6, 0xdb, 0x5e, 0x6f, 0xaf, 0x88, 0xab, 0xc7, 0x58, 0xed, 0xdc, 0xcc, 0xcd, 0x9d, 0x6a, 0x5d, - 0xec, 0xde, 0xb4, 0xdd, 0x14, 0x33, 0x6a, 0xad, 0xdd, 0xae, 0x39, 0x21, 0x4f, 0xbe, 0x15, 0xd5, 0x4a, 0x9d, 0xae, - 0x0d, 0xda, 0x21, 0x9e, 0x75, 0x91, 0xc1, 0x8d, 0xf2, 0xb9, 0x15, 0x3a, 0xc9, 0x38, 0xab, 0x56, 0x5d, 0xb0, 0xb9, - 0xe6, 0xf5, 0x52, 0xa4, 0x51, 0x45, 0xd1, 0xe6, 0x3c, 0x2a, 0x68, 0x22, 0xd6, 0x45, 0x1d, 0x89, 0x06, 0xf5, 0xa2, - 0x46, 0x63, 0x80, 0x80, 0x4c, 0xe7, 0xbe, 0x07, 0x55, 0x30, 0x1b, 0x8a, 0x48, 0x4c, 0xdf, 0x83, 0xa5, 0x7d, 0x01, - 0xfb, 0xa2, 0xd9, 0x57, 0x67, 0x8b, 0x6f, 0x75, 0x84, 0x60, 0x12, 0xb3, 0x07, 0xc2, 0xc0, 0xf9, 0xc6, 0x90, 0xd3, - 0x2e, 0x71, 0x99, 0xef, 0x96, 0xb0, 0x87, 0xdb, 0x15, 0xec, 0xc4, 0xce, 0x93, 0xe2, 0xe6, 0x4a, 0x76, 0x52, 0xce, - 0xc7, 0xa0, 0xfd, 0x12, 0xf2, 0xda, 0xa5, 0xb8, 0xf5, 0x78, 0x10, 0xd0, 0x60, 0x50, 0x6a, 0xfe, 0x75, 0xa2, 0x3d, - 0x3c, 0x69, 0x40, 0x90, 0x94, 0x83, 0x8b, 0xb6, 0x63, 0xf8, 0x3e, 0x99, 0x8a, 0x63, 0x8e, 0x16, 0xef, 0xd0, 0xea, - 0x04, 0xa2, 0x78, 0x81, 0xbd, 0x9b, 0x56, 0x15, 0x6a, 0x11, 0x94, 0xa3, 0xe5, 0x2f, 0x64, 0x75, 0x08, 0x28, 0xa4, - 0x7c, 0x45, 0xa1, 0x6c, 0x9d, 0x18, 0xea, 0xe1, 0x17, 0xf3, 0xc9, 0x42, 0xcd, 0xc0, 0x40, 0xcc, 0x8f, 0x16, 0x6a, - 0x16, 0x06, 0x62, 0xfe, 0xd5, 0xa2, 0xb1, 0xeb, 0x40, 0x11, 0x10, 0xc7, 0x85, 0xa3, 0x93, 0xd2, 0xca, 0x6c, 0x01, - 0xdd, 0x3c, 0x44, 0xd0, 0xff, 0x6e, 0x0e, 0x41, 0x2b, 0x17, 0xda, 0x91, 0x1b, 0xd0, 0x76, 0x1c, 0x02, 0x73, 0xc5, - 0xa4, 0x95, 0x0e, 0x40, 0x74, 0xcc, 0xc6, 0x60, 0x88, 0x2d, 0x3f, 0x38, 0x66, 0xe3, 0xa9, 0x4b, 0x82, 0x80, 0xd1, - 0xfd, 0x41, 0x43, 0x82, 0xdf, 0xe1, 0x55, 0xfa, 0x64, 0x83, 0xbe, 0x66, 0xce, 0xdd, 0xd0, 0xb9, 0xb8, 0x82, 0x53, - 0xb5, 0xbd, 0x27, 0xa1, 0x9b, 0x4c, 0x3b, 0x40, 0xaf, 0x26, 0x6e, 0xc8, 0xaf, 0x8c, 0x46, 0xa3, 0x62, 0x64, 0x00, - 0x20, 0x88, 0xe6, 0x1c, 0xfc, 0x9c, 0x86, 0xcb, 0x97, 0xb7, 0x9e, 0x4d, 0x31, 0x02, 0x5a, 0xc8, 0x44, 0xf3, 0x00, - 0x65, 0x55, 0x63, 0x68, 0x86, 0xde, 0x21, 0xc7, 0x0f, 0x0f, 0xbe, 0xce, 0xf8, 0x89, 0xc3, 0xb5, 0x87, 0x73, 0xe1, - 0xba, 0xac, 0x69, 0x99, 0x43, 0xe7, 0xd9, 0xc7, 0xf1, 0x1e, 0xc6, 0xc9, 0xa7, 0x59, 0x28, 0x67, 0xbc, 0xa6, 0xff, - 0x51, 0xe9, 0x7e, 0x87, 0x43, 0x4e, 0x57, 0xb0, 0xe2, 0x66, 0x75, 0xa8, 0xf9, 0x59, 0xe4, 0x8d, 0x23, 0xde, 0x90, - 0xa8, 0xee, 0x3e, 0xef, 0x4d, 0x98, 0xd2, 0x8e, 0x71, 0x00, 0x70, 0xa2, 0x56, 0x0d, 0xbb, 0xd2, 0xb8, 0x56, 0x07, - 0x31, 0x0c, 0x25, 0x6c, 0x95, 0x38, 0xaa, 0xa4, 0xbf, 0x01, 0x08, 0x8b, 0xa1, 0x38, 0xde, 0x1a, 0xd6, 0x07, 0xd8, - 0x0f, 0x55, 0xa0, 0x6e, 0x4e, 0x21, 0x67, 0x00, 0x90, 0x04, 0xdc, 0xd1, 0x53, 0x4d, 0x43, 0x65, 0x9b, 0xe3, 0xa1, - 0x65, 0x74, 0x05, 0x0f, 0xf4, 0xd4, 0x96, 0x0c, 0x8c, 0xab, 0x3c, 0xf6, 0x36, 0xfb, 0xdb, 0xa3, 0x54, 0xe4, 0x3b, - 0x9b, 0xd4, 0x34, 0xab, 0x46, 0x63, 0x1f, 0x47, 0xe8, 0x69, 0x05, 0x68, 0xbd, 0xb6, 0x54, 0xb4, 0xdf, 0x47, 0x31, - 0x6a, 0x5c, 0x4a, 0xb0, 0x0a, 0x1d, 0x09, 0x0e, 0x11, 0x46, 0x08, 0xfd, 0xbe, 0x08, 0x37, 0xae, 0x20, 0x83, 0x28, - 0xb8, 0x16, 0x15, 0x7f, 0xc8, 0xf2, 0xa2, 0x6d, 0xa9, 0xaa, 0x3e, 0x69, 0xda, 0x12, 0x78, 0x1d, 0x0e, 0xb0, 0x9d, - 0x7f, 0xea, 0x89, 0x5c, 0x2b, 0x1b, 0x25, 0x7c, 0x47, 0x5c, 0x0b, 0xa2, 0x9b, 0x46, 0xd7, 0xeb, 0xd9, 0x21, 0x5a, - 0x9a, 0xe2, 0xd0, 0x21, 0xfb, 0xdc, 0x3d, 0xb7, 0x65, 0x7c, 0xfb, 0x09, 0x72, 0xe7, 0x3b, 0x7b, 0x49, 0xc2, 0x20, - 0x6f, 0xd9, 0x40, 0xb1, 0x8e, 0xad, 0xa0, 0x00, 0xa3, 0xb6, 0xfc, 0x05, 0x74, 0x6c, 0x30, 0xa8, 0x09, 0x3e, 0x49, - 0x6c, 0x1b, 0x8f, 0xfc, 0x11, 0xe7, 0x86, 0x0e, 0xaf, 0x0d, 0x79, 0x20, 0x4e, 0x61, 0x9f, 0x28, 0x61, 0xff, 0x82, - 0x82, 0xee, 0x48, 0x2f, 0x57, 0x89, 0xab, 0xe2, 0x01, 0xaa, 0xec, 0x78, 0xae, 0xf9, 0x92, 0x16, 0x5a, 0x69, 0x64, - 0x15, 0x1d, 0x11, 0xb7, 0x60, 0x32, 0x66, 0xab, 0x6a, 0x54, 0x71, 0x2c, 0x50, 0xa4, 0x63, 0xce, 0x76, 0x0e, 0xd6, - 0x00, 0x78, 0x0a, 0x9b, 0x8b, 0x33, 0x2c, 0x28, 0xed, 0xb2, 0xa5, 0x2f, 0x81, 0x55, 0xf3, 0x30, 0xce, 0xcb, 0x8e, - 0x2f, 0x77, 0x47, 0xdb, 0x7b, 0xe8, 0x8d, 0xe8, 0x8d, 0xd7, 0xe7, 0x51, 0xd3, 0xcf, 0x9e, 0xe1, 0xda, 0x50, 0x90, - 0x07, 0x9a, 0xea, 0x10, 0x46, 0x8b, 0xc0, 0x34, 0xe5, 0x27, 0x6c, 0x3c, 0x1d, 0x0e, 0x35, 0x19, 0x74, 0x9a, 0x89, - 0xf1, 0xbf, 0x3e, 0x83, 0xd6, 0xe9, 0x89, 0xf3, 0x3e, 0x6d, 0x5f, 0x41, 0xeb, 0x3b, 0x94, 0xc9, 0x9d, 0x83, 0xe1, - 0x03, 0x2d, 0x98, 0x84, 0xa9, 0xc2, 0x1b, 0x22, 0x15, 0xec, 0xcd, 0xd2, 0x38, 0xec, 0x9b, 0x85, 0x42, 0x4b, 0x45, - 0xfc, 0x6a, 0x4d, 0xfc, 0xe4, 0x75, 0xe6, 0xdf, 0xa6, 0x7d, 0x72, 0x10, 0x4b, 0x43, 0x62, 0x24, 0xe2, 0x17, 0xa7, - 0xd2, 0x76, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x64, 0xec, 0x49, 0x8d, 0xa7, 0x86, 0xfb, 0x5e, 0xc7, - 0xac, 0xc3, 0x2c, 0x76, 0xb3, 0x46, 0x42, 0x61, 0x9c, 0x9a, 0xe0, 0x94, 0x62, 0x15, 0xc9, 0xe8, 0x78, 0xa6, 0x30, - 0x88, 0x2a, 0x29, 0x21, 0xd6, 0x94, 0xad, 0x85, 0x89, 0x5d, 0x67, 0x0b, 0x53, 0xd4, 0x45, 0xa8, 0x37, 0x03, 0x9d, - 0x05, 0x0d, 0xf9, 0x1d, 0x1a, 0xad, 0xa8, 0x9a, 0x04, 0x0c, 0xe3, 0x28, 0xd5, 0xf8, 0xb7, 0x08, 0xb5, 0x1e, 0x06, - 0x00, 0xb6, 0x79, 0x27, 0xb2, 0xa2, 0x7e, 0x55, 0x20, 0x04, 0x9a, 0xb5, 0x9f, 0x2a, 0xeb, 0x9d, 0x59, 0xd0, 0x8a, - 0x76, 0x73, 0xe5, 0x73, 0x81, 0x13, 0xaa, 0x53, 0x79, 0x81, 0x7a, 0x29, 0xca, 0xd7, 0x22, 0xe5, 0xad, 0xb8, 0x98, - 0x07, 0x82, 0x7d, 0xc8, 0x47, 0x70, 0x5e, 0xa1, 0x53, 0xb9, 0xde, 0x26, 0xd2, 0x2c, 0x49, 0x30, 0x16, 0x68, 0x9b, - 0x97, 0x60, 0x26, 0x14, 0x33, 0x86, 0x5f, 0x43, 0x70, 0xb1, 0x9d, 0x93, 0x70, 0xb3, 0x9f, 0x07, 0x86, 0xd0, 0xe4, - 0x55, 0x4b, 0x34, 0x6c, 0xec, 0x78, 0x1d, 0xb9, 0x26, 0xdc, 0x87, 0xb5, 0x58, 0x93, 0x31, 0xc6, 0x95, 0xb9, 0x91, - 0xf1, 0xa3, 0x05, 0x1e, 0x8c, 0x49, 0xeb, 0x4f, 0x20, 0xd3, 0x52, 0xca, 0x3a, 0x5f, 0x68, 0x31, 0x93, 0x4c, 0x74, - 0x6e, 0xdf, 0xf8, 0x2c, 0xef, 0x22, 0xf2, 0xb7, 0xf2, 0x7b, 0x92, 0x0f, 0xf7, 0xee, 0x83, 0xc4, 0x1a, 0x94, 0x46, - 0x5c, 0x5a, 0x94, 0xa7, 0x0f, 0x74, 0xdd, 0xa4, 0x88, 0xd3, 0xf3, 0x55, 0x5c, 0x56, 0x3c, 0x85, 0x4a, 0x15, 0x75, - 0x8b, 0x7a, 0x13, 0xb0, 0x37, 0x44, 0x92, 0x64, 0x2c, 0x8d, 0x8d, 0xd8, 0xc5, 0x23, 0x3d, 0x7b, 0xc3, 0x2c, 0xbd, - 0xac, 0xd1, 0x90, 0x96, 0x3a, 0x67, 0xa1, 0x94, 0xf9, 0x4b, 0xfe, 0x33, 0x68, 0x24, 0xe8, 0xa8, 0x4f, 0x31, 0x9e, - 0x01, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x08, 0x4a, 0xb3, 0x23, 0x76, 0xfc, 0xd4, 0xe4, 0xe1, 0x5d, - 0xc8, 0x3a, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0xa8, 0x1a, 0xc9, 0x19, 0x40, 0xd3, 0x41, 0x91, 0xf3, 0xb8, - 0x08, 0x66, 0x3d, 0x9d, 0x18, 0xf5, 0xb8, 0xfa, 0x05, 0x1a, 0x6a, 0xb7, 0x59, 0x59, 0x9e, 0xd5, 0xf7, 0x9f, 0xc3, - 0x81, 0x4d, 0x4d, 0x05, 0x3d, 0xde, 0xd4, 0xe2, 0xea, 0x4a, 0x76, 0xdb, 0x2d, 0x44, 0xcb, 0xe9, 0xbc, 0x6b, 0xe9, - 0xbc, 0x5e, 0xb0, 0x5e, 0x77, 0xba, 0x5e, 0xdc, 0x7e, 0x19, 0x1e, 0xc2, 0xda, 0xce, 0x27, 0x8a, 0x3f, 0xf3, 0xdb, - 0xee, 0xe2, 0x2d, 0x54, 0xb3, 0x00, 0x00, 0xd2, 0x83, 0x28, 0x58, 0x66, 0x29, 0x0f, 0xa8, 0xd8, 0xc7, 0x51, 0x96, - 0x52, 0x2f, 0x67, 0x18, 0x3f, 0x65, 0x1a, 0x6b, 0x9c, 0x15, 0xaa, 0xd0, 0xd8, 0xe8, 0x4e, 0x57, 0x19, 0x62, 0xfb, - 0x09, 0x9c, 0x2d, 0xc0, 0xfd, 0xd1, 0x43, 0xa1, 0xee, 0x4d, 0x5a, 0x9a, 0xa8, 0xf9, 0xae, 0x3d, 0x83, 0x8c, 0xe2, - 0x64, 0x95, 0x57, 0xd0, 0x8d, 0x3a, 0x6b, 0xa3, 0x4a, 0xdf, 0x43, 0xd4, 0xab, 0x18, 0x3c, 0xca, 0x5d, 0x5e, 0x1b, - 0x9d, 0x4c, 0x8b, 0x48, 0xb9, 0xf3, 0x93, 0x66, 0x99, 0xa5, 0x4a, 0x87, 0xed, 0x32, 0xec, 0xad, 0x31, 0xe9, 0x4d, - 0x48, 0x03, 0x23, 0xf1, 0xe9, 0x8c, 0x0a, 0x21, 0xa0, 0x2d, 0xc7, 0xdf, 0xe1, 0x33, 0x34, 0x4d, 0x81, 0xa5, 0x8a, - 0x5b, 0xd8, 0x0e, 0x9f, 0xff, 0x64, 0xd4, 0x02, 0x10, 0xc1, 0xca, 0xd5, 0xbb, 0x38, 0x25, 0x34, 0xe7, 0xca, 0x0c, - 0x00, 0x59, 0x50, 0xca, 0x2d, 0x3f, 0x25, 0xd3, 0xc1, 0x12, 0x45, 0xd9, 0xcb, 0xa9, 0x1b, 0x1d, 0x1b, 0x3f, 0xa4, - 0xe7, 0x02, 0xb6, 0x0b, 0xf9, 0xad, 0xbd, 0x7a, 0x89, 0x9a, 0x34, 0xa6, 0x59, 0x0f, 0xf0, 0xe5, 0x1a, 0x4d, 0x42, - 0x0b, 0xca, 0xa4, 0x29, 0x80, 0xc6, 0x4d, 0xd5, 0x0a, 0x26, 0xa5, 0x46, 0xc2, 0x96, 0x3a, 0x92, 0x65, 0xdf, 0x07, - 0xa7, 0xde, 0x23, 0xe8, 0x01, 0xf3, 0x08, 0xf4, 0xf4, 0x5f, 0xba, 0x6a, 0xff, 0x92, 0xa3, 0x93, 0xab, 0x26, 0x6a, - 0xfa, 0xbd, 0xb2, 0x23, 0x43, 0xca, 0xa5, 0x19, 0x08, 0x26, 0x1d, 0xf3, 0xd4, 0xd8, 0x3a, 0x46, 0x44, 0x0f, 0x9c, - 0x7d, 0xba, 0x5b, 0x4d, 0x2d, 0x00, 0xd1, 0xf1, 0xeb, 0x27, 0xaf, 0xae, 0xe3, 0x2b, 0x8d, 0xa2, 0xe4, 0x59, 0xc4, - 0x48, 0xd3, 0xbe, 0x5a, 0xc0, 0xe0, 0xfd, 0xf2, 0xfe, 0x27, 0x99, 0xa5, 0x71, 0x7b, 0xb0, 0x31, 0xa2, 0xaa, 0x5f, - 0x2a, 0x5e, 0xfa, 0x02, 0xac, 0x7d, 0x96, 0x28, 0x90, 0xfb, 0xbd, 0x49, 0xd3, 0xdf, 0x44, 0xde, 0xcd, 0x86, 0xf5, - 0xc6, 0x4d, 0xbb, 0xd4, 0x96, 0xec, 0xc8, 0x48, 0xe4, 0xf4, 0x62, 0xd0, 0xe3, 0x47, 0x2b, 0x8d, 0xd2, 0xb0, 0x41, - 0x55, 0x2a, 0x7e, 0xaf, 0x45, 0x70, 0xf2, 0x58, 0x95, 0x18, 0xd3, 0x80, 0xd9, 0x56, 0x36, 0x0a, 0xd4, 0x41, 0x2a, - 0x6d, 0x75, 0x14, 0xb6, 0xdf, 0x58, 0x49, 0xf5, 0xef, 0x7f, 0x6a, 0x43, 0x3e, 0x5f, 0x0a, 0x2a, 0x08, 0xd8, 0x19, - 0x78, 0x3d, 0x95, 0xc2, 0x40, 0x2a, 0xd8, 0x49, 0x05, 0x28, 0x5f, 0x44, 0x8e, 0xd5, 0x6e, 0x5f, 0xad, 0x1a, 0xa3, - 0x2d, 0x20, 0x34, 0x90, 0x1e, 0x5d, 0xf6, 0x71, 0x1b, 0xe3, 0x40, 0xe2, 0xc0, 0x09, 0xb6, 0x73, 0x75, 0x8d, 0x46, - 0x42, 0xf3, 0x87, 0x46, 0x03, 0x5e, 0xd3, 0x1a, 0x14, 0xea, 0x39, 0x8e, 0x86, 0xca, 0x0e, 0x29, 0x88, 0xd8, 0xa0, - 0x84, 0x7d, 0x7b, 0x3e, 0xd4, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x43, 0x85, 0xfd, 0xdc, 0x2e, 0x21, 0x63, 0xd5, 0x21, - 0xad, 0x3c, 0xc0, 0xf1, 0x42, 0xca, 0xfc, 0x2d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x6d, 0xc4, 0x02, 0x96, 0x04, 0xed, - 0xf5, 0x40, 0xdd, 0x32, 0x08, 0x75, 0x4c, 0x4f, 0x04, 0x3e, 0xa5, 0x5c, 0x7e, 0x5a, 0x92, 0x66, 0x5a, 0x32, 0x0b, - 0x7a, 0xe9, 0x5a, 0xf9, 0x15, 0xde, 0x47, 0xbb, 0x7b, 0x57, 0x5f, 0x58, 0xc7, 0x10, 0x0c, 0xbb, 0x72, 0x9b, 0xd3, - 0x50, 0x00, 0x36, 0x3c, 0x55, 0x65, 0xb9, 0x46, 0x4d, 0x64, 0x16, 0x87, 0x24, 0x02, 0xc9, 0xb6, 0xbf, 0xb9, 0xb5, - 0x60, 0xdb, 0x59, 0xa8, 0x9e, 0xfa, 0xcb, 0xd9, 0xee, 0x7b, 0x86, 0x97, 0x3b, 0x72, 0x6f, 0xdf, 0x86, 0xf2, 0x87, - 0xfd, 0xab, 0xe4, 0xff, 0xaa, 0x92, 0xfd, 0x56, 0x99, 0x4d, 0x5b, 0xbc, 0xdf, 0x75, 0xdc, 0x72, 0x8c, 0x06, 0x81, - 0x35, 0x05, 0x1a, 0xd2, 0x93, 0xc6, 0x34, 0x51, 0x21, 0x95, 0x19, 0xd3, 0x78, 0x74, 0x01, 0x9a, 0xc3, 0x74, 0x9e, - 0xc7, 0x00, 0x1c, 0xe0, 0x1e, 0x79, 0x84, 0xba, 0xa7, 0xf3, 0x3c, 0x38, 0x0f, 0x06, 0xc5, 0x20, 0x50, 0x9f, 0xd8, - 0xe6, 0x04, 0x0b, 0xd0, 0xb9, 0xc5, 0x0c, 0x82, 0x4d, 0x1a, 0x33, 0x87, 0xf8, 0x38, 0x99, 0x0e, 0x06, 0x31, 0xd9, - 0x00, 0x48, 0x5f, 0xbc, 0x30, 0xce, 0x41, 0xa5, 0x5a, 0x90, 0xad, 0xba, 0x4b, 0xbf, 0x62, 0xa7, 0xda, 0x69, 0xde, - 0xef, 0xe7, 0xf3, 0x62, 0x10, 0x78, 0x15, 0x96, 0xda, 0xfb, 0x8f, 0xfa, 0x5f, 0x6a, 0x9d, 0x34, 0xc1, 0x30, 0xb5, - 0xa7, 0xa8, 0x5e, 0x71, 0x34, 0xa3, 0xde, 0xed, 0x58, 0x2a, 0x5f, 0x40, 0x14, 0x0f, 0x0c, 0x59, 0x2b, 0xef, 0xce, - 0xc1, 0x6b, 0x73, 0xe3, 0xcd, 0x11, 0x05, 0xd8, 0xbe, 0x30, 0x4e, 0x28, 0x2e, 0xba, 0x6c, 0x88, 0x63, 0xb0, 0xd3, - 0xd5, 0x5b, 0x81, 0x56, 0xe3, 0xbd, 0x78, 0xd7, 0x6c, 0xfc, 0x8d, 0x38, 0x50, 0x65, 0x1e, 0x5c, 0x02, 0xe2, 0xec, - 0x41, 0x5c, 0x1f, 0x60, 0xa9, 0x07, 0xc1, 0xc0, 0x20, 0x87, 0xb4, 0xab, 0x55, 0x43, 0x11, 0xc9, 0xf3, 0x18, 0x0c, - 0x98, 0x74, 0x43, 0x1a, 0x32, 0xed, 0x95, 0x12, 0xd2, 0xc6, 0x58, 0x0b, 0x28, 0xc3, 0xe1, 0x6a, 0xc7, 0x6e, 0xd8, - 0x9e, 0x6e, 0x1d, 0x0a, 0x25, 0x8c, 0x5e, 0xdd, 0xf8, 0x87, 0x9a, 0xe7, 0x89, 0xa0, 0x06, 0x55, 0x6b, 0x3f, 0x1d, - 0x94, 0x27, 0xe5, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0xa2, 0xc0, 0x8b, 0xf6, 0x0e, 0xf2, 0x9c, 0xfe, 0x54, 0xfa, - 0x20, 0x7a, 0x6e, 0x19, 0x2e, 0xb4, 0x8f, 0x6b, 0x05, 0x32, 0x69, 0x3a, 0x9a, 0xda, 0xda, 0x1d, 0xde, 0x31, 0x81, - 0x7e, 0x53, 0x96, 0x52, 0x26, 0xba, 0x96, 0x25, 0x3b, 0xe9, 0xe5, 0xd2, 0x1b, 0x2a, 0x65, 0x27, 0xcb, 0x36, 0xe7, - 0x97, 0x7a, 0x09, 0xfd, 0xbe, 0x72, 0x07, 0xc2, 0x37, 0x72, 0xbd, 0x21, 0x2f, 0x1b, 0x22, 0x96, 0x43, 0xcc, 0xc0, - 0xf1, 0x42, 0x48, 0xd7, 0xee, 0xd2, 0x57, 0xd5, 0xed, 0x6c, 0xe5, 0x92, 0x16, 0x78, 0x2b, 0x05, 0x56, 0x91, 0x5a, - 0xbd, 0x9e, 0x4c, 0xdc, 0xf7, 0x51, 0x6c, 0x3e, 0x02, 0xb6, 0xd1, 0x3b, 0x1a, 0xbd, 0x5b, 0xc4, 0x06, 0x5f, 0x45, - 0x35, 0x2d, 0x39, 0x40, 0x70, 0xb7, 0x25, 0xb5, 0x34, 0xb3, 0x88, 0xfb, 0x92, 0x07, 0x68, 0xdf, 0xc5, 0xe1, 0x4c, - 0x2a, 0xc1, 0xb6, 0xae, 0x75, 0xce, 0x2a, 0x39, 0xa0, 0x9f, 0xe8, 0xf8, 0xa7, 0xd5, 0xa3, 0x22, 0x86, 0x55, 0x36, - 0x92, 0x56, 0x68, 0x0f, 0x4a, 0x97, 0x70, 0xf1, 0x05, 0x78, 0xd9, 0xde, 0xaf, 0xec, 0x3e, 0x5f, 0x62, 0xff, 0x30, - 0xaf, 0x9c, 0xe0, 0x91, 0xd3, 0x78, 0x73, 0x0f, 0xab, 0x3e, 0x57, 0x0a, 0xe1, 0x54, 0x4a, 0x43, 0x01, 0xc0, 0x20, - 0x09, 0x6a, 0xb8, 0xd2, 0xb6, 0x19, 0xa4, 0x34, 0x86, 0xdd, 0xad, 0xde, 0xe8, 0xff, 0x94, 0x0a, 0x17, 0xa0, 0x94, - 0x0d, 0xdc, 0x90, 0x75, 0xaa, 0xe5, 0x3a, 0xa6, 0xe0, 0xf9, 0x2e, 0x39, 0x02, 0x85, 0x1d, 0x18, 0x99, 0xd1, 0x84, - 0xfd, 0x82, 0xb7, 0xa1, 0x9c, 0xbd, 0x34, 0x92, 0x27, 0xbb, 0x2f, 0x69, 0x45, 0x13, 0x32, 0xad, 0xcc, 0xfe, 0x6d, - 0x6d, 0xd8, 0xe7, 0xa1, 0x18, 0x89, 0x02, 0x17, 0x07, 0x9d, 0x03, 0xd8, 0x1f, 0xe4, 0xd2, 0x36, 0x9f, 0x49, 0xbf, - 0x2f, 0xdf, 0x3f, 0xcb, 0xb3, 0xe4, 0xe3, 0xce, 0x7b, 0xcd, 0xd3, 0x2c, 0x19, 0x50, 0x89, 0x98, 0x1a, 0x57, 0xc5, - 0x70, 0xa9, 0x5c, 0x8c, 0x3d, 0x92, 0x11, 0xef, 0xa5, 0x0e, 0x31, 0x62, 0x7c, 0x91, 0x1d, 0x92, 0x92, 0xd3, 0x65, - 0xd3, 0xd9, 0x73, 0x25, 0x9a, 0x41, 0x63, 0xb8, 0x1d, 0xef, 0x25, 0xb5, 0x02, 0x64, 0x54, 0xe8, 0x9e, 0x01, 0xae, - 0xe1, 0xfe, 0x92, 0xf0, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xd8, 0x2b, 0x13, 0x12, 0x72, 0xe3, 0x00, 0x8b, 0xd8, 0x34, - 0x1f, 0x43, 0x01, 0x40, 0xad, 0x1a, 0xe9, 0x95, 0xbe, 0x24, 0x54, 0x26, 0x21, 0x18, 0x5d, 0x91, 0xf0, 0x2a, 0xa0, - 0x71, 0xa6, 0x13, 0x0d, 0x6c, 0x70, 0x40, 0x9f, 0xd7, 0x3a, 0x51, 0xdb, 0x90, 0x07, 0xb4, 0x36, 0x69, 0x00, 0x83, - 0x0f, 0x92, 0x24, 0xfa, 0x6a, 0xa9, 0x93, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x73, 0xe1, 0xf8, 0x58, 0x82, 0xff, - 0x91, 0x26, 0x82, 0x3f, 0x84, 0x02, 0x64, 0x8a, 0xaa, 0x62, 0x9a, 0xb1, 0x93, 0xac, 0xdb, 0x98, 0xc4, 0xf1, 0xb4, - 0xbb, 0x2b, 0xa5, 0x4b, 0x17, 0xf8, 0x95, 0x65, 0x88, 0x63, 0xfd, 0x2c, 0x5e, 0xb1, 0xd3, 0x90, 0x2b, 0xbc, 0xf4, - 0x67, 0xf1, 0x0a, 0x67, 0x88, 0xd6, 0xad, 0x04, 0x22, 0xfd, 0x57, 0x4d, 0xe0, 0x10, 0xfb, 0x09, 0x06, 0xb9, 0xa8, - 0x9d, 0x07, 0x02, 0x79, 0x5b, 0x41, 0x44, 0xfc, 0xec, 0x2a, 0x8c, 0x48, 0xbd, 0x93, 0xa4, 0xbf, 0xfc, 0x51, 0x64, - 0x85, 0xf3, 0x0d, 0x3c, 0xfa, 0xcd, 0x32, 0x29, 0xfa, 0x0b, 0x19, 0xcc, 0xc1, 0x7e, 0x22, 0xe3, 0x52, 0xd4, 0xee, - 0x13, 0x76, 0xc1, 0x89, 0xf1, 0xe0, 0xf4, 0x1a, 0x01, 0xf6, 0x6b, 0xf7, 0xc9, 0x19, 0xb3, 0xbf, 0x8c, 0x1b, 0x5f, - 0xa6, 0x23, 0x3e, 0xf0, 0xd1, 0x1d, 0xe5, 0xa3, 0x7b, 0x27, 0xd3, 0x1f, 0x1e, 0x94, 0xc8, 0xa8, 0xaa, 0xf9, 0x6a, - 0xc5, 0xd3, 0xd9, 0x5d, 0x12, 0x65, 0xa3, 0x9a, 0x17, 0x30, 0xbd, 0xe0, 0x78, 0x97, 0xac, 0x2f, 0xb2, 0xe4, 0x15, - 0xc4, 0x1e, 0x58, 0x09, 0x89, 0xc5, 0x0f, 0xcb, 0x4c, 0x2e, 0xe6, 0x42, 0xd4, 0xa2, 0xe0, 0xc1, 0xec, 0x26, 0x89, - 0xfe, 0x5a, 0x3a, 0x48, 0x6a, 0x7a, 0xca, 0x36, 0x8d, 0x25, 0xd4, 0xda, 0xd7, 0x91, 0x6e, 0x94, 0x05, 0x00, 0xdc, - 0xb3, 0x8b, 0x34, 0x12, 0xac, 0x1a, 0x4e, 0x1a, 0xc6, 0x75, 0x7a, 0x89, 0xa9, 0x71, 0xc3, 0x6a, 0x9a, 0x58, 0x0b, - 0x19, 0xd0, 0xfb, 0x03, 0x5e, 0x0e, 0x3e, 0x67, 0x45, 0x28, 0xa4, 0x35, 0x70, 0x71, 0x5c, 0xf6, 0xfb, 0xe2, 0xb8, - 0xdc, 0x6e, 0x8b, 0x93, 0xb8, 0xdf, 0x17, 0x27, 0xb1, 0xe6, 0x1f, 0xa4, 0x62, 0x5b, 0x9b, 0x1b, 0x24, 0x34, 0x17, - 0x10, 0xb5, 0x68, 0x04, 0x7f, 0x68, 0x96, 0xf3, 0x22, 0xca, 0x8f, 0x93, 0x7e, 0xbf, 0xb7, 0x9c, 0x55, 0x83, 0x7c, - 0x98, 0x44, 0xf9, 0x30, 0x71, 0x9c, 0x10, 0x7f, 0x75, 0x9c, 0x10, 0x25, 0x0d, 0x5c, 0xc1, 0x99, 0x01, 0x88, 0x02, - 0x2e, 0xfd, 0xa3, 0xaa, 0x96, 0x52, 0xd5, 0x12, 0xcb, 0x5a, 0x12, 0x55, 0x41, 0xc3, 0x6e, 0xca, 0xb0, 0xc0, 0x52, - 0xe8, 0x92, 0xfd, 0xb1, 0x04, 0x9e, 0x28, 0xe7, 0xf5, 0x06, 0x18, 0xd8, 0x08, 0xef, 0x1c, 0x3a, 0x9c, 0xc4, 0xba, - 0x61, 0x12, 0x32, 0xe9, 0x92, 0xae, 0xe8, 0x15, 0xf2, 0xb3, 0x97, 0x60, 0xb0, 0x74, 0xcc, 0xf2, 0xe9, 0x60, 0x70, - 0x49, 0x56, 0xac, 0x98, 0x87, 0xf1, 0x20, 0x5c, 0xcf, 0xf2, 0xe1, 0x65, 0x74, 0x49, 0xc8, 0x17, 0xe5, 0x82, 0xf6, - 0x56, 0xa3, 0xea, 0x63, 0x06, 0xc1, 0xfd, 0xd2, 0x59, 0x98, 0xe9, 0x38, 0x1f, 0xab, 0xd1, 0x1d, 0x5d, 0x41, 0xfc, - 0x1a, 0xb8, 0x91, 0x90, 0x08, 0x3a, 0x72, 0x45, 0x57, 0x74, 0x4d, 0x85, 0x9e, 0x61, 0x0c, 0xd1, 0x6d, 0x8e, 0x93, - 0x04, 0x1c, 0x93, 0x6d, 0xf1, 0xd1, 0x58, 0x16, 0xde, 0xf5, 0x1d, 0xa1, 0xbd, 0x5e, 0x62, 0x07, 0xe9, 0xbb, 0xf6, - 0x20, 0x01, 0x23, 0x32, 0x92, 0x03, 0xa5, 0x47, 0x46, 0x50, 0x3d, 0xa9, 0x38, 0x24, 0xb1, 0x3b, 0x24, 0x72, 0x1c, - 0x12, 0x77, 0x1c, 0x72, 0x35, 0x0e, 0xc8, 0xdd, 0x2f, 0xd9, 0x98, 0xa6, 0x6c, 0x4c, 0xd7, 0x72, 0x54, 0xe8, 0x35, - 0xbd, 0x50, 0xd4, 0xf1, 0x9c, 0xbd, 0x86, 0x03, 0x7b, 0x10, 0xe6, 0xb3, 0x78, 0xf8, 0x3a, 0x7a, 0x4d, 0xc8, 0x17, - 0x82, 0xde, 0xc8, 0x4b, 0x19, 0x84, 0x41, 0xbc, 0x06, 0xe7, 0x52, 0x1b, 0xea, 0xe4, 0x5a, 0xef, 0x38, 0x7c, 0xba, - 0xf2, 0x9e, 0x2e, 0x20, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x25, 0x2b, 0xe6, 0xe7, 0xe1, 0x98, 0x00, 0x0e, - 0x8f, 0x1a, 0xce, 0xcb, 0xd1, 0x1d, 0xbd, 0x1c, 0xdd, 0x13, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0xc7, 0x2c, 0x9e, 0x0e, - 0x06, 0x6b, 0xa4, 0xea, 0x32, 0xf7, 0x9a, 0x2c, 0xe8, 0x25, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x2b, 0xd6, 0x9a, 0x86, - 0xbf, 0x66, 0xf0, 0xf1, 0x3d, 0xbb, 0x1c, 0xdd, 0xd3, 0x3b, 0xf6, 0x7a, 0x3b, 0x9e, 0x02, 0x33, 0xb5, 0x9a, 0x85, - 0xf7, 0xc7, 0x57, 0xb3, 0x2b, 0x76, 0x1f, 0xdd, 0x9f, 0x40, 0x43, 0xaf, 0xd9, 0x3d, 0x02, 0x2e, 0xa5, 0x8f, 0x97, - 0x83, 0xd7, 0xe4, 0x70, 0x30, 0x48, 0x49, 0x14, 0xde, 0x84, 0x4e, 0x2b, 0x5f, 0xd3, 0x7b, 0x42, 0x57, 0xec, 0x0e, - 0x47, 0xe3, 0x8a, 0xe1, 0x07, 0x17, 0xec, 0xbe, 0xb9, 0x09, 0x9d, 0xdd, 0x1c, 0x57, 0x9d, 0x20, 0x46, 0xe8, 0x6b, - 0x60, 0x69, 0x96, 0x0d, 0x33, 0x01, 0x4f, 0xfa, 0x22, 0xa3, 0x44, 0xa1, 0x19, 0x88, 0xb3, 0x12, 0x10, 0x4b, 0xa2, - 0xee, 0x37, 0x1b, 0x9d, 0xc3, 0x72, 0xee, 0xf7, 0x7b, 0xb5, 0xa6, 0x07, 0x88, 0x9c, 0xd9, 0x49, 0x0f, 0x7a, 0x2e, - 0x3d, 0xc0, 0x4f, 0xd4, 0xaa, 0x41, 0x9c, 0xcc, 0xef, 0x96, 0xd1, 0xaf, 0x0e, 0x7d, 0xf8, 0xa1, 0x9b, 0xf2, 0x54, - 0xf9, 0xbf, 0x4f, 0x79, 0x8a, 0x3c, 0x7a, 0x5d, 0x3b, 0x20, 0x78, 0xce, 0x9a, 0x94, 0x1a, 0x89, 0x7a, 0x74, 0xbe, - 0x8a, 0x41, 0x1b, 0x89, 0xda, 0x06, 0xf5, 0x84, 0x16, 0x56, 0x10, 0x21, 0xe7, 0xe8, 0x39, 0x18, 0xa4, 0x42, 0xa8, - 0x1c, 0xb9, 0x28, 0xd1, 0x10, 0x24, 0x17, 0x15, 0x97, 0xe1, 0x73, 0x08, 0x95, 0xa7, 0x8f, 0x35, 0x11, 0xd6, 0xf4, - 0x18, 0x0c, 0xb0, 0x2d, 0xfc, 0xdb, 0x0e, 0xb9, 0xa8, 0xf8, 0x15, 0x9e, 0xcd, 0x6d, 0x82, 0x51, 0xb2, 0xb8, 0x15, - 0xda, 0x06, 0xb1, 0x1f, 0x0b, 0x82, 0xf5, 0x08, 0x1a, 0x8f, 0x2a, 0x7d, 0x44, 0xb8, 0x51, 0x7c, 0x24, 0x3d, 0x8d, - 0x35, 0x89, 0xe4, 0x48, 0x22, 0xf9, 0x00, 0x08, 0x27, 0x41, 0x7f, 0x71, 0xdb, 0x64, 0xdb, 0x42, 0xa2, 0xd1, 0x9f, - 0x96, 0x4c, 0xc9, 0xee, 0x65, 0x8f, 0x5d, 0x45, 0x90, 0x3d, 0xa6, 0xff, 0x74, 0xfa, 0xf0, 0xcf, 0x25, 0xce, 0xa0, - 0xf1, 0x7c, 0x91, 0x9d, 0x99, 0x39, 0x83, 0x1b, 0x39, 0x5d, 0x56, 0xae, 0xcb, 0x97, 0xfc, 0x80, 0xdf, 0xd5, 0xbc, - 0x48, 0xab, 0x83, 0x9f, 0xeb, 0x36, 0x9e, 0x53, 0xb5, 0x5e, 0xd9, 0x38, 0x2b, 0xd2, 0x38, 0xd5, 0x91, 0xba, 0x68, - 0x6b, 0x58, 0xcf, 0xef, 0x11, 0x75, 0x25, 0x2d, 0x47, 0x4f, 0x21, 0x56, 0x7e, 0xca, 0xe5, 0x3a, 0xcf, 0x7f, 0xda, - 0x49, 0xc5, 0x29, 0xf6, 0x53, 0x90, 0x2a, 0xb5, 0x5c, 0x40, 0xd5, 0x1c, 0xb5, 0xdc, 0x2d, 0xf5, 0x0e, 0xb0, 0x6e, - 0x9b, 0xf2, 0x63, 0x69, 0x76, 0xe1, 0x24, 0x7b, 0xf7, 0x27, 0x5d, 0x86, 0x01, 0xa3, 0x50, 0x66, 0xd5, 0xb5, 0xb2, - 0x2f, 0x34, 0x4e, 0xc3, 0x70, 0xe5, 0xc7, 0x0b, 0x48, 0x17, 0x30, 0x8e, 0x13, 0x25, 0x13, 0xe3, 0xf6, 0xa8, 0xad, - 0x50, 0x7d, 0xce, 0x56, 0x20, 0x60, 0xae, 0xe1, 0xec, 0xba, 0x8e, 0xb6, 0x3b, 0xe2, 0x94, 0x51, 0xb5, 0x8a, 0x8b, - 0xef, 0xe3, 0x55, 0x35, 0xb3, 0x43, 0x1b, 0xf9, 0x63, 0x3a, 0xfd, 0x7b, 0x12, 0xba, 0x85, 0x50, 0xb8, 0xe5, 0x16, - 0x46, 0x9e, 0xdc, 0x1e, 0x96, 0x71, 0x83, 0x5e, 0x89, 0x2b, 0xd5, 0x37, 0x2d, 0x85, 0x54, 0x23, 0x5f, 0xfb, 0x02, - 0x7a, 0x3d, 0xf6, 0x7e, 0x2a, 0xcc, 0xdb, 0x9e, 0x31, 0x97, 0x08, 0x56, 0xb2, 0xec, 0xf6, 0x9d, 0x1a, 0x53, 0x31, - 0x83, 0x2e, 0xb6, 0x9d, 0x45, 0xa7, 0x1b, 0xf9, 0xa7, 0x99, 0xfb, 0x65, 0xde, 0xe1, 0xae, 0xa8, 0xde, 0x02, 0x17, - 0x9a, 0x95, 0x55, 0xdd, 0x96, 0x0d, 0x9b, 0xc6, 0x6b, 0x59, 0x28, 0x36, 0xc0, 0xb0, 0xe7, 0xae, 0x85, 0x07, 0x88, - 0x9b, 0x70, 0xcf, 0x2e, 0x1a, 0xb8, 0x31, 0x7c, 0x5e, 0x49, 0xae, 0x2b, 0x8d, 0xbe, 0xf4, 0xc9, 0xd2, 0xaa, 0xe1, - 0x64, 0x31, 0xe2, 0x45, 0xba, 0x68, 0x32, 0xb3, 0x16, 0x3e, 0xe1, 0x65, 0x38, 0xe7, 0x0b, 0xad, 0x9b, 0x52, 0xa5, - 0x97, 0x2c, 0x56, 0x9d, 0xde, 0xac, 0x14, 0x56, 0x4a, 0xc4, 0x8d, 0x59, 0x26, 0x50, 0x96, 0xa2, 0x91, 0xc2, 0x9b, - 0xb2, 0x65, 0x2b, 0xa9, 0xe5, 0x3d, 0x73, 0x70, 0x1f, 0xfb, 0x01, 0x31, 0x91, 0x75, 0x60, 0x52, 0x34, 0x74, 0x40, - 0xbb, 0xea, 0xd2, 0x35, 0xa3, 0x1e, 0x0c, 0x72, 0x43, 0x12, 0xb1, 0x82, 0x14, 0x2b, 0x58, 0x37, 0xac, 0x9c, 0xe7, - 0x0b, 0x7a, 0xc9, 0xc4, 0x3c, 0x5d, 0xd0, 0x15, 0x13, 0xf3, 0x35, 0xde, 0x84, 0x2e, 0xe1, 0x84, 0x24, 0x9b, 0x58, - 0x2a, 0x60, 0x2f, 0xf1, 0xf2, 0x86, 0x67, 0xaa, 0xa2, 0x65, 0x57, 0x92, 0x03, 0x8c, 0x2f, 0xaa, 0x30, 0x2c, 0x86, - 0x97, 0x60, 0x2d, 0x71, 0x18, 0xae, 0xe6, 0x7c, 0x21, 0x7f, 0x43, 0xc0, 0xf9, 0x24, 0x94, 0xec, 0x82, 0xd9, 0x0b, - 0x64, 0x7a, 0x3d, 0xe7, 0x0b, 0x39, 0x12, 0xaa, 0xe0, 0x6b, 0x63, 0x6c, 0x12, 0x3b, 0x82, 0x96, 0x59, 0x3c, 0x1f, - 0x2f, 0xa2, 0xb8, 0x81, 0x65, 0x78, 0x26, 0x67, 0xa6, 0x25, 0xff, 0xd1, 0x76, 0x52, 0xea, 0x06, 0x2b, 0xc9, 0x1f, - 0x1e, 0x1f, 0x5d, 0x02, 0x19, 0x33, 0xbb, 0x82, 0xe9, 0x0f, 0x5d, 0x1f, 0x19, 0xdc, 0x73, 0x53, 0xce, 0xb8, 0x0c, - 0x12, 0xa5, 0x05, 0x0e, 0x72, 0x96, 0xb4, 0xb5, 0x08, 0xdf, 0x3d, 0x2a, 0xca, 0x3e, 0x13, 0xba, 0x01, 0xdd, 0x47, - 0x82, 0x3e, 0xd0, 0x7b, 0xa5, 0x0a, 0x97, 0xd5, 0x36, 0x13, 0x70, 0x17, 0x09, 0xf2, 0x5b, 0xa1, 0x53, 0x35, 0x06, - 0x55, 0x34, 0x8b, 0x58, 0xb8, 0xf7, 0x11, 0x37, 0xca, 0xe6, 0x9f, 0xfa, 0x1e, 0x2f, 0x25, 0x0c, 0x6e, 0x48, 0x4d, - 0x9f, 0xcc, 0x9b, 0x2b, 0xf6, 0x1e, 0x3a, 0xea, 0x50, 0x6b, 0xbc, 0xaf, 0x5e, 0x72, 0x0a, 0x31, 0x4a, 0x28, 0x3a, - 0x09, 0x06, 0x70, 0xbb, 0x84, 0x14, 0x7b, 0x83, 0xdd, 0xf8, 0xd7, 0xbc, 0x28, 0xb8, 0x58, 0xd7, 0x75, 0xe0, 0x06, - 0x34, 0x9c, 0x2f, 0x76, 0x43, 0x18, 0x8e, 0x69, 0xeb, 0x1a, 0x06, 0x61, 0xc6, 0x30, 0x12, 0x82, 0xd3, 0xbf, 0xe8, - 0x2b, 0x9a, 0xc4, 0xab, 0xef, 0xf8, 0x5f, 0x19, 0x2f, 0x25, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x74, 0x93, - 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0x58, 0xd3, 0x54, 0xfc, 0x2d, 0x17, 0x1f, 0xfc, 0x54, 0x74, 0x3c, 0x1a, 0x37, - 0xad, 0xce, 0xc8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0xa0, 0x1b, 0xa9, 0xdf, 0xda, 0x87, 0xc0, - 0x29, 0xd3, 0xe0, 0x9d, 0x07, 0x74, 0x73, 0xee, 0x82, 0x27, 0x8f, 0xe9, 0xb9, 0x45, 0x4f, 0xae, 0xd9, 0x49, 0xdd, - 0x43, 0xed, 0xbd, 0x1e, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0xd0, 0x38, 0x57, 0xf7, 0x1f, 0x8b, 0x5d, 0x0e, - 0xdf, 0x72, 0x96, 0x1b, 0xc0, 0x52, 0x11, 0x8d, 0x04, 0x8f, 0x02, 0xd4, 0xa5, 0x2a, 0x84, 0x2d, 0x66, 0x71, 0xa8, - 0xcc, 0x56, 0xad, 0x87, 0x82, 0x1c, 0x17, 0x23, 0x70, 0x08, 0x5d, 0x57, 0x83, 0x62, 0xb4, 0xcc, 0xea, 0xf7, 0xf8, - 0x5b, 0xb1, 0x0e, 0x49, 0xb6, 0x8f, 0x75, 0xe0, 0x86, 0x75, 0x98, 0x7e, 0xd4, 0x48, 0x01, 0x68, 0xb2, 0x11, 0xd8, - 0x04, 0xe0, 0xbd, 0xdd, 0x47, 0x84, 0x5a, 0x99, 0xee, 0x65, 0x2c, 0xe4, 0xf7, 0x5e, 0x12, 0x94, 0xe0, 0x27, 0xd4, - 0x96, 0xa5, 0xe0, 0x9d, 0x47, 0x3a, 0x27, 0x4d, 0x56, 0xbc, 0x07, 0x71, 0x5a, 0xf8, 0xc0, 0xde, 0x82, 0xe0, 0x9c, - 0x25, 0xbd, 0xc7, 0xdb, 0xac, 0x92, 0xda, 0xa8, 0x81, 0x02, 0xf8, 0xdd, 0xe0, 0x1e, 0x41, 0xbe, 0xbc, 0xe1, 0x5a, - 0x89, 0xdb, 0x90, 0x0f, 0x4b, 0x7a, 0x44, 0x06, 0xe6, 0xb9, 0x1a, 0xc6, 0xf4, 0x88, 0x1c, 0x9b, 0x67, 0x61, 0x07, - 0x70, 0x20, 0xd4, 0xa8, 0xd2, 0x23, 0x68, 0xd0, 0x6f, 0xa6, 0x45, 0x86, 0x64, 0xfd, 0xa8, 0x1b, 0x8c, 0x88, 0xbf, - 0x20, 0xa2, 0x2e, 0xfe, 0xf9, 0x60, 0xae, 0x7b, 0xcc, 0x05, 0xc2, 0x1c, 0x0c, 0x38, 0x88, 0xdb, 0x20, 0xd4, 0x07, - 0xcc, 0xe6, 0x2e, 0xaa, 0xe8, 0xbd, 0x31, 0xcc, 0xec, 0xe8, 0x0f, 0x37, 0x12, 0x7c, 0x9d, 0xb5, 0x41, 0x9d, 0x17, - 0x87, 0x40, 0x10, 0xdc, 0x17, 0xaa, 0x9a, 0xab, 0x1e, 0xd8, 0x78, 0xcb, 0x7e, 0x6c, 0xb7, 0xe3, 0x69, 0x65, 0xaf, - 0xfd, 0x15, 0x85, 0x93, 0x4f, 0xca, 0xbf, 0xde, 0xeb, 0x0c, 0x16, 0x8c, 0x0c, 0x5f, 0x3a, 0xfb, 0x17, 0xbe, 0x56, - 0xd2, 0xbd, 0x6a, 0x50, 0x90, 0xc7, 0x47, 0x92, 0xfe, 0xed, 0x95, 0x95, 0x4f, 0xcd, 0xf4, 0x6f, 0xb7, 0x7a, 0x7d, - 0x1e, 0x8f, 0x26, 0xdb, 0x6d, 0x4f, 0x19, 0xb8, 0x52, 0x1d, 0x43, 0x08, 0x9d, 0xeb, 0xc9, 0xe1, 0x11, 0x44, 0x45, - 0xf0, 0xe3, 0x6e, 0x16, 0x9e, 0x44, 0xc6, 0x8d, 0xd3, 0x59, 0x78, 0x82, 0x1d, 0xee, 0x44, 0x25, 0x2e, 0x46, 0xad, - 0x0d, 0x4e, 0xcf, 0x93, 0x10, 0x42, 0x39, 0x60, 0x65, 0x77, 0xf2, 0xcf, 0xbd, 0x34, 0x13, 0x92, 0x93, 0xd5, 0xed, - 0x94, 0xee, 0x60, 0x9a, 0x1f, 0xe8, 0x11, 0x1c, 0x70, 0x67, 0x7f, 0x35, 0x1f, 0xc3, 0x24, 0x53, 0xe4, 0x14, 0xc9, - 0x2f, 0xd2, 0x53, 0x48, 0xda, 0xa1, 0xa7, 0x92, 0x00, 0x4e, 0xa8, 0xf9, 0x18, 0x7e, 0xc3, 0xb8, 0x7f, 0xe7, 0xbf, - 0xb6, 0x53, 0x11, 0x3d, 0xa1, 0x58, 0xa6, 0x22, 0xa7, 0x49, 0x56, 0x26, 0x10, 0xb5, 0x51, 0x36, 0x23, 0xfa, 0xca, - 0xc6, 0x7c, 0x94, 0x84, 0xcf, 0xa9, 0xf5, 0x7f, 0x86, 0xf0, 0x69, 0x74, 0x46, 0x80, 0xcb, 0x2b, 0xaf, 0x2e, 0xc2, - 0xa7, 0x4f, 0xe8, 0xc1, 0xe4, 0xeb, 0x23, 0x7a, 0x70, 0xf4, 0xd5, 0x53, 0x02, 0xb0, 0x68, 0x57, 0x17, 0xe1, 0xd1, - 0xd3, 0xa7, 0xf4, 0xe0, 0xdb, 0x6f, 0xe9, 0xc1, 0xe4, 0xab, 0x23, 0x2f, 0x6d, 0xf2, 0xf4, 0x5b, 0x7a, 0xf0, 0xf5, - 0x13, 0x2f, 0xed, 0x68, 0xfc, 0x94, 0x1e, 0x7c, 0xf3, 0xb5, 0x4e, 0xfb, 0x1b, 0x64, 0xfb, 0xf6, 0x08, 0xff, 0xd3, - 0x69, 0x93, 0xa7, 0x5f, 0xd1, 0x83, 0xc9, 0x18, 0x2a, 0x79, 0x6a, 0x2b, 0x19, 0x4f, 0xe0, 0xe3, 0xaf, 0xe0, 0xbf, - 0xbf, 0x91, 0x60, 0x41, 0x6b, 0xc1, 0x92, 0x0a, 0xf5, 0x67, 0x28, 0xe2, 0x44, 0xd5, 0x44, 0xc2, 0x43, 0xcc, 0x2c, - 0xbf, 0x89, 0xc3, 0x80, 0xd8, 0x74, 0x28, 0x88, 0x1e, 0x8c, 0x47, 0x4f, 0x49, 0xe0, 0xc2, 0xd3, 0xdd, 0xba, 0x20, - 0x63, 0x49, 0x35, 0xcf, 0xbe, 0x48, 0x34, 0x63, 0xe0, 0x00, 0x58, 0x7d, 0x74, 0x73, 0xd5, 0x62, 0x9e, 0x7d, 0x51, - 0x8b, 0xdd, 0x5c, 0xbf, 0xb5, 0x00, 0xe5, 0xdd, 0x55, 0xcb, 0x6e, 0x4b, 0x19, 0x3a, 0xad, 0x35, 0xfa, 0xec, 0x23, - 0xa6, 0x0f, 0x06, 0xce, 0x0d, 0xfb, 0xef, 0x3b, 0xe5, 0xb4, 0xbe, 0x51, 0x28, 0xd4, 0xa8, 0x3c, 0x24, 0xec, 0x04, - 0x8a, 0x1e, 0x0c, 0x80, 0x27, 0x70, 0x70, 0xdf, 0xfe, 0xcd, 0x32, 0x3e, 0x76, 0x94, 0xf1, 0x33, 0xca, 0x10, 0xd0, - 0xa8, 0x87, 0x99, 0x4d, 0x0f, 0x1b, 0xdd, 0xe8, 0x25, 0x0b, 0x79, 0x32, 0xf9, 0x9e, 0xc1, 0xae, 0xd6, 0xb5, 0x38, - 0xd0, 0xa2, 0x68, 0x71, 0x79, 0x90, 0xf2, 0x59, 0xcd, 0xfe, 0xbe, 0x44, 0xf5, 0x56, 0xe4, 0xbd, 0x11, 0xd9, 0xac, - 0x66, 0xdf, 0xeb, 0x37, 0xc0, 0xcd, 0xb0, 0xdf, 0xe4, 0x93, 0x1b, 0x38, 0x83, 0x0b, 0xd3, 0x1e, 0x69, 0x62, 0x04, - 0x58, 0x01, 0x19, 0x38, 0xf0, 0x00, 0xe8, 0xa0, 0x3b, 0xda, 0xdb, 0xad, 0x4c, 0xf1, 0xfb, 0x6c, 0x60, 0x00, 0x35, - 0xf3, 0x36, 0xb1, 0x65, 0xff, 0xcb, 0x93, 0x97, 0xa0, 0x70, 0xcb, 0x2f, 0x6f, 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, - 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x55, 0x40, 0xf5, 0x96, 0x8f, 0x36, 0x5c, 0xaa, 0x27, 0x81, 0x33, 0xb8, - 0x14, 0x65, 0xc2, 0xdf, 0x2a, 0xb1, 0x3f, 0x5a, 0x3f, 0xba, 0xbe, 0x3d, 0x0e, 0xac, 0x7d, 0x8f, 0x8f, 0xd4, 0x67, - 0xde, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0xaf, 0x1a, 0x23, 0xf1, 0x28, 0x80, 0x37, 0xd0, 0x11, 0x29, 0x34, 0x52, 0x2d, - 0x70, 0x0c, 0x85, 0xb4, 0x40, 0x1c, 0x79, 0x75, 0x83, 0x2d, 0x88, 0x08, 0xc1, 0xc3, 0xed, 0x5f, 0x4b, 0x19, 0x38, - 0xaa, 0xdf, 0xe7, 0xc2, 0x75, 0x7b, 0xd2, 0x76, 0xe4, 0x38, 0xf5, 0x53, 0x07, 0xdf, 0x9c, 0x34, 0x8d, 0xb6, 0x5c, - 0x49, 0x99, 0x61, 0x59, 0xd8, 0x49, 0xa8, 0xe4, 0x1e, 0xb5, 0x03, 0xc9, 0x17, 0x72, 0x88, 0x64, 0x81, 0x51, 0x28, - 0xc8, 0x70, 0x42, 0xc1, 0x66, 0xaa, 0x5a, 0x66, 0x97, 0x75, 0xb8, 0x91, 0x0a, 0x65, 0x4e, 0xd1, 0xb7, 0x1b, 0x1c, - 0x48, 0x48, 0x94, 0x55, 0x6f, 0xe2, 0x37, 0x21, 0x82, 0xd5, 0x71, 0x65, 0x0b, 0xc5, 0x9d, 0xfd, 0xc9, 0xd3, 0x2e, - 0xfe, 0x48, 0xbb, 0x80, 0xda, 0x58, 0x4c, 0xc3, 0x89, 0x89, 0x7d, 0x63, 0xbf, 0x30, 0x9a, 0x1e, 0x80, 0xfa, 0xae, - 0xa4, 0x18, 0x41, 0x7e, 0xa5, 0xed, 0x63, 0x7b, 0x8c, 0x89, 0x19, 0xc4, 0x1a, 0x96, 0x39, 0x33, 0xd9, 0x37, 0xc2, - 0x4e, 0x00, 0xb8, 0x11, 0x5a, 0x23, 0x21, 0xf0, 0x78, 0x1d, 0xe2, 0x79, 0x29, 0xc3, 0xb7, 0x66, 0x84, 0x8e, 0xc1, - 0x9b, 0xca, 0x34, 0x32, 0x13, 0xae, 0x60, 0x50, 0x1f, 0xdb, 0x2a, 0x0a, 0xab, 0xa9, 0x2c, 0x3b, 0x01, 0xb8, 0x81, - 0xec, 0x58, 0x5f, 0x3c, 0x67, 0xf5, 0x3c, 0x5b, 0x44, 0x3a, 0x28, 0x60, 0x5e, 0x19, 0x06, 0xed, 0xcd, 0x1e, 0xd9, - 0x8e, 0x45, 0xe8, 0x86, 0xfb, 0x08, 0xc6, 0xd3, 0xf6, 0x05, 0x2b, 0x88, 0x46, 0x88, 0x87, 0x19, 0x33, 0xf8, 0x5e, - 0x69, 0xca, 0x53, 0xd9, 0x12, 0x08, 0x1c, 0x85, 0x50, 0x17, 0xbb, 0x46, 0x09, 0x36, 0x93, 0x17, 0xcc, 0x60, 0xc7, - 0x8e, 0xd4, 0x74, 0xc9, 0x3a, 0x1d, 0xca, 0x29, 0x2d, 0xd4, 0x94, 0x2a, 0x5f, 0xc3, 0x6a, 0x5e, 0xa0, 0x87, 0x1e, - 0xb8, 0x1e, 0x28, 0x87, 0xbc, 0x82, 0x4e, 0x74, 0x04, 0x9d, 0x56, 0x9b, 0xb0, 0x73, 0x23, 0xd5, 0xb2, 0x06, 0x79, - 0xc7, 0x50, 0xef, 0x88, 0x17, 0x4e, 0xa0, 0x2e, 0x84, 0x08, 0xd9, 0xdb, 0x22, 0x7d, 0x44, 0xb3, 0xac, 0x7a, 0x09, - 0x65, 0x71, 0xc4, 0xd6, 0x05, 0x2b, 0x6d, 0x34, 0xb9, 0xe4, 0x11, 0x4f, 0x11, 0x11, 0xf0, 0x54, 0x6a, 0xd7, 0x77, - 0x5a, 0x42, 0x68, 0x96, 0x02, 0x71, 0xb3, 0x51, 0x9c, 0x1b, 0x13, 0xc8, 0x02, 0xe8, 0xdb, 0x4f, 0xd9, 0xb5, 0x13, - 0x0e, 0x76, 0x73, 0x9d, 0x15, 0xcf, 0xf9, 0x65, 0x56, 0xf0, 0x14, 0xc1, 0xae, 0xee, 0xf4, 0x03, 0xb7, 0x6c, 0x1b, - 0x58, 0xbe, 0x7d, 0x07, 0x0b, 0xa6, 0x0a, 0x95, 0x52, 0x22, 0x2b, 0xa2, 0x0a, 0x32, 0xbb, 0xcc, 0xdd, 0xeb, 0xac, - 0x78, 0x1d, 0xdf, 0x81, 0x37, 0x85, 0xc7, 0x4f, 0x8f, 0x2e, 0xf0, 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, - 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x29, 0x68, 0x6d, 0x0d, 0x81, 0x13, 0x7f, 0x5a, 0x76, 0xef, 0x3a, 0x2b, 0xb4, - 0x7d, 0xc6, 0x75, 0x7c, 0xc7, 0x0a, 0x09, 0x66, 0x81, 0x71, 0xee, 0xdb, 0x52, 0x92, 0xeb, 0xac, 0xd0, 0x02, 0x92, - 0xeb, 0xf8, 0x8e, 0xfa, 0x32, 0x0e, 0x65, 0x45, 0xe7, 0xc4, 0xf9, 0xdd, 0x1d, 0x7e, 0x81, 0xa1, 0x56, 0xc6, 0xfd, - 0x3e, 0x48, 0xcc, 0x84, 0x69, 0xca, 0x4c, 0x44, 0x42, 0xa1, 0x85, 0xd4, 0x94, 0x0f, 0x26, 0x64, 0x77, 0xa5, 0x1a, - 0x46, 0xd4, 0x7c, 0x15, 0x56, 0xb3, 0x71, 0x34, 0x21, 0x74, 0xd2, 0xb1, 0xde, 0x75, 0x6b, 0x21, 0xd3, 0xe8, 0x69, - 0xe4, 0xf8, 0x74, 0x96, 0xac, 0x9e, 0x96, 0xc7, 0x8c, 0x4f, 0xcb, 0xc1, 0x80, 0xa8, 0xd0, 0xc1, 0x1b, 0xac, 0x07, - 0x4c, 0x69, 0x6c, 0xbc, 0x35, 0xdd, 0xea, 0x97, 0x42, 0x86, 0xa4, 0x77, 0x0c, 0x48, 0x32, 0x61, 0x83, 0xdd, 0x82, - 0x44, 0xd1, 0xf1, 0xbf, 0x93, 0x5b, 0x70, 0xd7, 0x83, 0xd1, 0x8f, 0xee, 0xeb, 0x18, 0xff, 0xa1, 0xb6, 0x05, 0x51, - 0x9f, 0x2a, 0xd6, 0xeb, 0x48, 0x94, 0x21, 0x17, 0xe1, 0x67, 0x47, 0x43, 0x34, 0x51, 0xed, 0xb1, 0xa0, 0x58, 0x5f, - 0x5f, 0xf0, 0x12, 0xa7, 0x9f, 0xd9, 0xcb, 0x15, 0x6c, 0x0b, 0x5a, 0x6b, 0x1a, 0xf5, 0x26, 0x7e, 0x13, 0x99, 0xcb, - 0x82, 0x2a, 0xf2, 0x39, 0x0a, 0x59, 0xf3, 0x30, 0xac, 0x87, 0xed, 0x41, 0x24, 0x87, 0xed, 0x49, 0xf0, 0x1a, 0x03, - 0x0b, 0x64, 0x87, 0x46, 0xe0, 0x22, 0x34, 0xf2, 0xb7, 0x63, 0x70, 0xe1, 0x32, 0x88, 0x2c, 0x43, 0x15, 0xbf, 0xa9, - 0xdd, 0x04, 0xd9, 0x2b, 0x74, 0x9a, 0xc2, 0xaa, 0xa4, 0x49, 0x3e, 0xfc, 0x7a, 0x29, 0x4a, 0xcc, 0xe4, 0x74, 0xd9, - 0xa1, 0xaf, 0xed, 0xf6, 0x0e, 0x74, 0xc1, 0xaa, 0x4f, 0xce, 0xd7, 0x8f, 0x3b, 0x7b, 0x02, 0x46, 0xb1, 0x32, 0x87, - 0x2f, 0xa4, 0x54, 0x3e, 0x28, 0xcd, 0xc7, 0x30, 0xaf, 0x14, 0xc7, 0x6e, 0x00, 0x93, 0x80, 0x7d, 0x86, 0x54, 0x87, - 0x69, 0xc7, 0x3e, 0x47, 0x1b, 0x58, 0x12, 0x70, 0xf8, 0x47, 0x99, 0x68, 0xdc, 0xab, 0x7b, 0x95, 0xfa, 0x21, 0x5b, - 0xe6, 0x0b, 0xe0, 0xf3, 0x61, 0xd7, 0x46, 0x05, 0xca, 0x26, 0x22, 0x41, 0x61, 0xcb, 0x63, 0x90, 0xf6, 0x28, 0xa6, - 0xab, 0x92, 0x27, 0x19, 0x4a, 0x29, 0x12, 0xe5, 0x13, 0x9c, 0xc3, 0x1b, 0xdc, 0x8f, 0x32, 0x20, 0xbc, 0x0c, 0x39, - 0x1d, 0xa5, 0x54, 0x59, 0xc0, 0x48, 0xea, 0x01, 0xa2, 0xbc, 0x0c, 0xe4, 0x78, 0xdb, 0xed, 0x84, 0xae, 0xd8, 0x72, - 0x38, 0xa1, 0x48, 0x4a, 0xae, 0xb0, 0xdc, 0x6b, 0xd0, 0x79, 0x5c, 0xb0, 0xde, 0x0b, 0xc0, 0x22, 0x38, 0x87, 0xbf, - 0x31, 0xa1, 0x37, 0xf0, 0x37, 0x27, 0xf4, 0x35, 0x0b, 0xaf, 0x87, 0x57, 0xe4, 0x30, 0x4c, 0x07, 0x13, 0x29, 0x18, - 0xbb, 0x67, 0xcb, 0x22, 0x94, 0x89, 0xab, 0xc3, 0x4b, 0xf2, 0xf8, 0x92, 0xde, 0xd1, 0x5b, 0x7a, 0x46, 0xdf, 0x02, - 0xe1, 0xbf, 0x3f, 0x9e, 0xf0, 0xe1, 0xe4, 0x49, 0xbf, 0xdf, 0xbb, 0xe8, 0xf7, 0x7b, 0xe7, 0xda, 0x80, 0x42, 0xed, - 0xa2, 0xab, 0x86, 0xaa, 0x5f, 0xd7, 0xcd, 0x62, 0xfa, 0x56, 0x6e, 0xdc, 0x84, 0x67, 0x79, 0x78, 0x7d, 0x78, 0x4f, - 0x86, 0xf8, 0x78, 0x99, 0x0b, 0x51, 0x86, 0x57, 0x87, 0xf7, 0x84, 0xbe, 0x3d, 0x01, 0xbd, 0x29, 0xd6, 0xf7, 0xf6, - 0xf1, 0xbd, 0xaa, 0x8d, 0xd0, 0x17, 0x61, 0x02, 0xdb, 0xe4, 0x8e, 0x99, 0xbb, 0xf6, 0x64, 0x0c, 0xb1, 0x4c, 0xee, - 0x9d, 0xf2, 0xee, 0x1f, 0xdf, 0x91, 0xc3, 0x3b, 0xf0, 0x14, 0x35, 0xe4, 0x6f, 0x16, 0xde, 0xb2, 0x56, 0x0d, 0x8f, - 0xef, 0xe9, 0x59, 0xab, 0x11, 0x8f, 0xef, 0x49, 0x14, 0xde, 0xb2, 0x2b, 0x7a, 0xc6, 0xae, 0x09, 0xbd, 0xe8, 0xf7, - 0xcf, 0xfb, 0x7d, 0xd1, 0xef, 0xff, 0x3d, 0x0e, 0xc3, 0x78, 0x58, 0x92, 0x43, 0x41, 0xef, 0x0f, 0x27, 0xfc, 0x2b, - 0x32, 0x0b, 0x55, 0xf3, 0xe5, 0x82, 0x33, 0x2a, 0x6f, 0x99, 0xeb, 0x9e, 0x82, 0xb5, 0xc2, 0x3d, 0x93, 0x4f, 0x6f, - 0xe9, 0x2d, 0x2b, 0xe9, 0x19, 0x8b, 0x49, 0x74, 0x03, 0xad, 0xb8, 0x98, 0x95, 0xd1, 0x2d, 0x3d, 0x63, 0xe7, 0xb3, - 0x38, 0x3a, 0xa3, 0x6f, 0x59, 0x3e, 0x9c, 0x40, 0xde, 0xb3, 0xe1, 0x2d, 0x39, 0x7c, 0x4b, 0xa2, 0xf0, 0xad, 0xfa, - 0x7d, 0x4f, 0xaf, 0x78, 0xf8, 0x96, 0x3a, 0xd5, 0xbc, 0x25, 0xba, 0x7a, 0xaf, 0xf6, 0xb7, 0x24, 0x72, 0x07, 0xf3, - 0xad, 0xb1, 0xa7, 0x79, 0x64, 0x69, 0x63, 0x5a, 0x84, 0xa0, 0x6f, 0x2e, 0xc2, 0x5b, 0x42, 0xa6, 0xfe, 0xd8, 0xc1, - 0x80, 0xce, 0x1e, 0x45, 0x09, 0xa1, 0xb7, 0x6e, 0xa9, 0xb7, 0x38, 0x86, 0x7a, 0x84, 0x64, 0xda, 0x19, 0xa6, 0xe1, - 0x3a, 0x78, 0xa5, 0xc0, 0x3a, 0x2e, 0xfa, 0xfd, 0x70, 0xdd, 0xef, 0x43, 0xa4, 0xfb, 0x72, 0xa6, 0x63, 0xbb, 0x59, - 0xb2, 0x49, 0x6f, 0x41, 0xfb, 0xff, 0x6a, 0x30, 0x80, 0xce, 0x38, 0x25, 0x85, 0xb7, 0x83, 0x57, 0x8f, 0xef, 0x89, - 0xac, 0xa3, 0xa4, 0x95, 0x08, 0x4b, 0xfa, 0x9a, 0x66, 0x00, 0xf8, 0xf5, 0x6a, 0x30, 0x20, 0x91, 0xfe, 0x8c, 0x4c, - 0x5f, 0x1d, 0xbf, 0x9d, 0x0e, 0x06, 0xaf, 0xf4, 0x36, 0xf9, 0x8b, 0xed, 0x29, 0x05, 0xd6, 0xdf, 0x79, 0xbf, 0xff, - 0xd7, 0x49, 0x4c, 0x2e, 0x4a, 0x1e, 0x7f, 0x9c, 0xfa, 0x6d, 0xf9, 0xcb, 0x46, 0x55, 0x3b, 0xef, 0xf7, 0xd7, 0xfd, - 0xfe, 0x19, 0x60, 0x17, 0xcd, 0xac, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x96, 0x22, 0x29, 0x92, 0x43, 0x63, 0x68, 0x5b, - 0x2c, 0xdb, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xc8, 0xaf, 0x28, 0x6e, 0x48, 0x14, 0xf6, 0xce, 0xb7, 0xdb, 0x33, 0xc6, - 0x58, 0x4c, 0x40, 0xfa, 0xe1, 0xbe, 0x3e, 0x6b, 0xbc, 0x18, 0x62, 0x95, 0x40, 0x66, 0x73, 0xb3, 0x34, 0x87, 0x40, - 0xc4, 0x61, 0xd3, 0xbf, 0xd7, 0xf7, 0xf2, 0xaa, 0xb1, 0x7c, 0xeb, 0xcf, 0x00, 0x42, 0x24, 0x58, 0xc8, 0x67, 0x38, - 0x06, 0x55, 0x06, 0xc0, 0xbf, 0x91, 0x9c, 0x79, 0x01, 0xa0, 0xe6, 0x64, 0xbb, 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb2, - 0xd1, 0xdf, 0x9e, 0x3e, 0xae, 0x1f, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, 0x61, 0x16, 0x6b, 0x7d, 0x08, 0x46, - 0xf0, 0x8a, 0x7d, 0xbc, 0xc9, 0x3e, 0x9b, 0x7d, 0x44, 0xc2, 0xea, 0x31, 0x8e, 0xbc, 0x48, 0x5b, 0x7a, 0xbb, 0x3d, - 0x0c, 0x26, 0x2f, 0xd2, 0x4f, 0xb0, 0x9d, 0x2e, 0xff, 0xe6, 0xc0, 0x78, 0xc2, 0xc1, 0x68, 0x2f, 0x0a, 0xea, 0x4c, - 0xdb, 0x6e, 0x6b, 0xf7, 0x12, 0xf8, 0x06, 0x53, 0x41, 0xc7, 0x66, 0x58, 0xb8, 0x41, 0x4d, 0xe4, 0xd1, 0x32, 0xa8, - 0x1b, 0x69, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0xd2, 0x71, 0x0b, 0x34, 0x43, 0x86, 0xba, 0xdc, 0xd3, 0xfa, 0x5f, 0xbc, - 0x14, 0x1a, 0x3e, 0xc3, 0x8a, 0x08, 0x1d, 0x6e, 0x8d, 0xbb, 0xdc, 0x5a, 0xf5, 0x09, 0x6e, 0xad, 0x40, 0x12, 0xab, - 0x61, 0x49, 0xf5, 0xe5, 0x28, 0x61, 0x27, 0x05, 0xe3, 0x33, 0xa0, 0xe3, 0x31, 0x3c, 0x08, 0x56, 0xcd, 0x44, 0x94, - 0xa0, 0x7d, 0xa2, 0x8d, 0x30, 0xf8, 0x27, 0x60, 0xf6, 0xd3, 0x1c, 0xfe, 0x0a, 0x32, 0x4d, 0x8e, 0x21, 0x20, 0xc4, - 0xf1, 0x78, 0x16, 0x87, 0x63, 0x12, 0x25, 0x27, 0xf0, 0x04, 0xff, 0x95, 0xe1, 0x98, 0x34, 0xea, 0x0e, 0x23, 0xe4, - 0xe5, 0x36, 0x61, 0x00, 0x57, 0x36, 0x9e, 0x4d, 0x22, 0x23, 0xdd, 0x15, 0x8f, 0x47, 0xe3, 0xa7, 0x64, 0x1a, 0x87, - 0x62, 0x90, 0x10, 0x0a, 0xde, 0xbd, 0x61, 0x31, 0x4c, 0x14, 0x3c, 0x1b, 0xb0, 0x79, 0x85, 0x65, 0xf3, 0x04, 0x9c, - 0x80, 0x30, 0x4c, 0xc8, 0xb1, 0xee, 0x41, 0x4a, 0x51, 0xe7, 0x39, 0xf6, 0x53, 0x1d, 0x41, 0x98, 0x1d, 0xb5, 0x54, - 0x7c, 0x05, 0x40, 0x97, 0x38, 0x38, 0xd4, 0x20, 0x61, 0x54, 0xb3, 0xb0, 0x70, 0xa8, 0x94, 0xae, 0xee, 0xb0, 0xf2, - 0x28, 0xbf, 0x6e, 0xd0, 0x61, 0x45, 0x06, 0x13, 0x5a, 0x9c, 0x4c, 0xf8, 0x57, 0x10, 0xc0, 0xc3, 0x8b, 0xf8, 0x25, - 0x71, 0x62, 0x20, 0xbc, 0x0a, 0x32, 0x50, 0x69, 0x23, 0x1b, 0x33, 0x32, 0x15, 0x1f, 0x40, 0x98, 0x94, 0x83, 0x5b, - 0xb1, 0xce, 0x53, 0x88, 0x0a, 0xb6, 0xce, 0xeb, 0x83, 0x2b, 0xb0, 0x64, 0x8f, 0x6b, 0x88, 0x13, 0xb6, 0x5e, 0x01, - 0x76, 0xee, 0xa3, 0x4d, 0xd1, 0x1c, 0xc8, 0xef, 0x0e, 0xb0, 0xe5, 0xf0, 0xaa, 0x16, 0x07, 0x93, 0xf1, 0x78, 0x3c, - 0xfa, 0x1d, 0x8e, 0x0e, 0x20, 0xb4, 0x24, 0xd2, 0x7c, 0x32, 0x40, 0xe3, 0xae, 0x6b, 0xee, 0x8c, 0x0b, 0x45, 0x59, - 0xe9, 0x64, 0x42, 0x40, 0xfc, 0xac, 0xfb, 0x06, 0xfb, 0x8a, 0xab, 0xf8, 0x27, 0xbb, 0x9f, 0xe8, 0x15, 0x2d, 0x57, - 0xea, 0xe8, 0xdd, 0xdb, 0xb3, 0x57, 0x1f, 0x5e, 0xfd, 0xfa, 0xe2, 0xfc, 0xd5, 0x9b, 0x97, 0xaf, 0xde, 0xbc, 0xfa, - 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xd7, 0x56, 0xc4, 0x8c, 0xbd, 0x73, 0x8f, 0x71, 0x6a, 0x71, 0x85, 0xb3, 0x47, 0xf6, - 0x16, 0x0b, 0xb0, 0x09, 0x9a, 0x5b, 0xa8, 0xa8, 0x62, 0x34, 0x6a, 0x75, 0x4f, 0x40, 0x46, 0xa3, 0x46, 0x36, 0x1e, - 0x56, 0x6c, 0x8d, 0x5c, 0xbc, 0x65, 0x38, 0xf8, 0xc8, 0xfc, 0x96, 0x9c, 0x09, 0x37, 0xa3, 0xad, 0x58, 0x11, 0xf0, - 0xf9, 0x5a, 0x17, 0xb5, 0xc3, 0x85, 0xc8, 0xbd, 0x6d, 0x9e, 0x43, 0x42, 0x1d, 0x22, 0xd7, 0xc1, 0xfb, 0x7a, 0x64, - 0x8f, 0x8f, 0x9c, 0x27, 0xe9, 0x19, 0xea, 0x72, 0x34, 0x7c, 0xe4, 0x3d, 0xa3, 0x13, 0x73, 0xa3, 0x75, 0xa8, 0xe7, - 0x25, 0xec, 0x6f, 0x29, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x58, 0xdd, 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, - 0x7e, 0xa4, 0x6a, 0x02, 0x69, 0x51, 0x20, 0x75, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, 0x52, 0xff, 0x0c, 0x3d, 0x02, 0x68, - 0x2e, 0x3b, 0x86, 0x04, 0xea, 0xc5, 0x6b, 0x5c, 0xff, 0x9c, 0x7c, 0x59, 0xd1, 0xce, 0x17, 0xdf, 0x41, 0x88, 0x61, - 0xf7, 0x8a, 0xe0, 0x4d, 0xb8, 0x9d, 0x64, 0x7b, 0x69, 0xd1, 0xf7, 0xaa, 0xeb, 0x18, 0x8f, 0xbb, 0x3d, 0x57, 0x0a, - 0xff, 0xd6, 0x05, 0xf6, 0x40, 0xfe, 0x75, 0xbc, 0x60, 0x21, 0x60, 0x33, 0x1e, 0x9a, 0x45, 0x62, 0xfd, 0xde, 0xe9, - 0x84, 0x1c, 0x1e, 0x4d, 0xf9, 0x90, 0x15, 0xb4, 0x1a, 0xb0, 0xa2, 0xd9, 0xa1, 0xe6, 0xbc, 0x4d, 0xc8, 0xab, 0x5d, - 0x1a, 0x5e, 0x0d, 0xf9, 0x43, 0x97, 0xa4, 0x0f, 0xdc, 0x73, 0xa8, 0x36, 0xcd, 0xc5, 0x90, 0xa6, 0x9c, 0xee, 0x52, - 0x19, 0x10, 0x22, 0x5d, 0xc7, 0x35, 0x69, 0xd4, 0x51, 0xb5, 0xb4, 0x92, 0x8e, 0x9b, 0x6c, 0xf3, 0x89, 0x4b, 0xb6, - 0xbc, 0x5d, 0xbb, 0xd7, 0xea, 0xf6, 0x85, 0x19, 0xc8, 0xdf, 0x1f, 0x88, 0x6a, 0xa2, 0x21, 0xba, 0x80, 0x0a, 0xfe, - 0x01, 0x5e, 0x9e, 0x3c, 0x52, 0x0a, 0xd0, 0x7d, 0x67, 0x47, 0xd7, 0x1e, 0xf7, 0x66, 0xb1, 0xb5, 0xc4, 0x39, 0xab, - 0x5d, 0x67, 0x79, 0x59, 0xb6, 0x44, 0xd7, 0xa9, 0xd8, 0xcf, 0x61, 0x47, 0xdf, 0x9d, 0x6d, 0x00, 0x44, 0x29, 0xac, - 0xed, 0xd9, 0x5f, 0x39, 0x67, 0x7f, 0x65, 0xce, 0x7e, 0xb3, 0x09, 0xa4, 0x0f, 0x2b, 0xb4, 0xec, 0xa5, 0x28, 0x6a, - 0xdd, 0xe4, 0xb1, 0xaf, 0xcb, 0x42, 0x5a, 0xcc, 0x0f, 0x0d, 0xed, 0x7a, 0x32, 0xa6, 0x02, 0xd5, 0x23, 0x3f, 0x60, - 0xab, 0x0e, 0x0b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0xb9, 0xef, 0x6e, 0xf7, 0x7f, 0x73, 0xa1, 0x83, 0xdb, - 0xda, 0xb2, 0x72, 0xd4, 0xd5, 0x71, 0x89, 0x77, 0xb5, 0xe5, 0xc3, 0x77, 0xb5, 0x77, 0x99, 0x5a, 0x76, 0x35, 0xa0, - 0x06, 0x15, 0xeb, 0x6b, 0x5e, 0x66, 0x49, 0x63, 0x14, 0x1a, 0x6f, 0x39, 0x84, 0xf6, 0x70, 0x0e, 0x2e, 0x90, 0xc3, - 0x12, 0x42, 0x3f, 0xd6, 0x5a, 0x00, 0xe8, 0xb2, 0xd8, 0x6f, 0x79, 0x98, 0x91, 0x81, 0x2b, 0xf1, 0x2b, 0x84, 0x2b, - 0x2e, 0x3e, 0xdc, 0xc9, 0x4c, 0xd0, 0xab, 0xc4, 0x46, 0xcd, 0x15, 0xed, 0x98, 0x1f, 0xee, 0x17, 0x18, 0x0d, 0xc2, - 0x69, 0x4b, 0x76, 0x58, 0x75, 0xcc, 0x72, 0x0d, 0x47, 0x6d, 0x61, 0xcb, 0x2c, 0x5a, 0xd7, 0xcf, 0x7a, 0x98, 0xa9, - 0x33, 0xe5, 0x2d, 0xc8, 0xbe, 0x90, 0xbb, 0x9f, 0xaa, 0x8a, 0x2b, 0x72, 0x32, 0x19, 0x4f, 0x49, 0x35, 0x18, 0xb4, - 0x92, 0x8f, 0x31, 0x79, 0x38, 0xdc, 0x61, 0x2e, 0x2b, 0xd5, 0x0f, 0xa7, 0x0f, 0x50, 0x9f, 0xb7, 0x25, 0xc9, 0xa6, - 0x66, 0x7f, 0x82, 0x59, 0x2c, 0x10, 0x47, 0x0b, 0xbf, 0x38, 0x5f, 0x00, 0xc8, 0x32, 0x2c, 0x33, 0x25, 0x2c, 0x82, - 0x2b, 0x3d, 0x74, 0xb2, 0x64, 0xe2, 0x78, 0x3c, 0x73, 0x7b, 0x6e, 0x19, 0x1c, 0x42, 0xa2, 0x89, 0x31, 0x7e, 0x71, - 0xb3, 0x60, 0x1c, 0x87, 0xe2, 0x44, 0x78, 0xdf, 0x15, 0x24, 0x1a, 0x6b, 0x53, 0x65, 0x75, 0x95, 0xa8, 0x87, 0x09, - 0x79, 0x5c, 0x92, 0xc3, 0x92, 0x2e, 0xdd, 0xb1, 0xc4, 0xf4, 0xc3, 0xf8, 0x70, 0x32, 0x26, 0x8f, 0xe3, 0xc7, 0x13, - 0x0d, 0x37, 0xec, 0xe6, 0xc8, 0x87, 0x4b, 0x72, 0xe8, 0x57, 0x09, 0xa6, 0xa8, 0xba, 0x67, 0x6e, 0x25, 0xc9, 0x60, - 0x39, 0x48, 0x1f, 0xb7, 0xf2, 0x62, 0xad, 0x6a, 0xbc, 0xd7, 0xc7, 0x7c, 0x4a, 0x2a, 0xef, 0xc6, 0xb0, 0xa6, 0xd7, - 0xf1, 0x1f, 0xa2, 0x8c, 0x0a, 0x01, 0x88, 0x84, 0xa0, 0xde, 0xce, 0x2e, 0xb3, 0x24, 0x2e, 0xd2, 0x28, 0x6d, 0x08, - 0x4d, 0x4f, 0xd8, 0x64, 0x3c, 0x4b, 0x59, 0x7a, 0x3c, 0x79, 0x3a, 0x9b, 0x3c, 0x8d, 0x8e, 0xc6, 0x51, 0x3a, 0x18, - 0x40, 0xf2, 0xd1, 0x18, 0x5c, 0xec, 0xe0, 0x37, 0x3b, 0x82, 0xa1, 0x3b, 0x41, 0x96, 0xb0, 0x84, 0xa6, 0x7d, 0x5e, - 0x93, 0xd4, 0x70, 0x5e, 0xca, 0x9e, 0xc4, 0x77, 0x74, 0xed, 0x38, 0xb8, 0xb8, 0x2d, 0xbc, 0xb4, 0x2d, 0xbc, 0xdc, - 0x6d, 0xa1, 0xb6, 0x20, 0x28, 0xc5, 0xff, 0x8f, 0x1b, 0xc6, 0xbe, 0xbb, 0x84, 0x5e, 0x5c, 0x37, 0xd9, 0x68, 0x55, - 0x8a, 0x5a, 0xc0, 0x6d, 0x42, 0x8a, 0xc2, 0x46, 0xf1, 0x6a, 0x95, 0x2b, 0x17, 0xb1, 0x79, 0x4d, 0x01, 0xdc, 0x05, - 0xce, 0x56, 0x60, 0xa1, 0xb5, 0x81, 0xdc, 0x5f, 0xbc, 0x14, 0xcc, 0xa8, 0x7d, 0xf4, 0x3d, 0xf2, 0x8f, 0x10, 0xc1, - 0x96, 0x4e, 0xc6, 0xb3, 0x0a, 0x11, 0x2d, 0x3e, 0x25, 0xef, 0xfd, 0x37, 0x8e, 0x22, 0x73, 0x34, 0x8f, 0x51, 0xa1, - 0x65, 0x3c, 0xe2, 0xcc, 0xc9, 0xe4, 0x64, 0xe0, 0x6e, 0x06, 0x23, 0xfd, 0xb5, 0xb7, 0x19, 0x63, 0xdb, 0xa3, 0x7a, - 0xa1, 0x85, 0xa2, 0x7f, 0xe1, 0x3b, 0x5d, 0x2f, 0xe0, 0x12, 0xca, 0x81, 0x5d, 0x5f, 0x5d, 0xf1, 0x0a, 0x40, 0x84, - 0xb2, 0xa2, 0xdf, 0xef, 0xfd, 0xa1, 0xa1, 0x49, 0x2b, 0x5e, 0xbe, 0xce, 0x0a, 0xe3, 0x8c, 0x03, 0x4d, 0x05, 0xea, - 0xff, 0xb1, 0x36, 0xcf, 0x74, 0x4c, 0x66, 0xee, 0xe3, 0x70, 0x42, 0x22, 0xff, 0x35, 0xf9, 0xc4, 0x69, 0xfa, 0x89, - 0x2b, 0xda, 0x7f, 0x20, 0x33, 0xd7, 0x1c, 0x32, 0xd4, 0x5f, 0x58, 0xe6, 0x49, 0xeb, 0x75, 0x62, 0x76, 0x52, 0xb1, - 0x7a, 0x06, 0xe8, 0xe9, 0x25, 0x3c, 0xc8, 0x6b, 0x59, 0x3c, 0x85, 0xd9, 0x07, 0x35, 0x62, 0x75, 0xcc, 0xc6, 0xb3, - 0x50, 0x84, 0x13, 0xb0, 0xef, 0x9d, 0x8c, 0xe1, 0x3e, 0x20, 0xc2, 0x8f, 0x75, 0x58, 0x51, 0x94, 0x92, 0x97, 0xf0, - 0x1b, 0x14, 0x13, 0x00, 0x11, 0x08, 0x79, 0xfb, 0x7d, 0x21, 0x93, 0xf0, 0x75, 0x81, 0x29, 0xa5, 0xfc, 0xe0, 0x3f, - 0x91, 0xaa, 0x5b, 0xa6, 0x5f, 0xae, 0x1f, 0x77, 0x26, 0x24, 0x9f, 0x6e, 0x53, 0xe2, 0x3b, 0x08, 0xee, 0x2c, 0x40, - 0x07, 0x51, 0xa3, 0x19, 0xdb, 0xc3, 0xfc, 0x6e, 0xb5, 0x9f, 0xdf, 0xad, 0xfe, 0xdf, 0xf1, 0xbb, 0xd5, 0x43, 0x8c, - 0x61, 0x6d, 0xa0, 0xe1, 0x67, 0xc1, 0x38, 0x88, 0xfe, 0x73, 0x3e, 0x71, 0x2f, 0x4f, 0x7d, 0x9d, 0x15, 0xd3, 0x3d, - 0x4c, 0xb3, 0x4b, 0x50, 0x10, 0x56, 0x71, 0x97, 0x9e, 0xac, 0x6b, 0x73, 0x6b, 0x25, 0x43, 0xcc, 0xf3, 0x00, 0x6b, - 0x14, 0xd6, 0x0e, 0xd0, 0x3d, 0xaa, 0x36, 0x88, 0x15, 0xc1, 0xc3, 0x98, 0x19, 0xe9, 0xfb, 0x76, 0xab, 0x55, 0x98, - 0x0f, 0x72, 0x51, 0x90, 0x5d, 0x7f, 0x3c, 0x1b, 0x47, 0x21, 0x36, 0xe0, 0x3f, 0x66, 0xac, 0x3c, 0xd9, 0x7c, 0x27, - 0x23, 0xb5, 0x63, 0xf2, 0x34, 0xd9, 0x25, 0xbd, 0x03, 0xde, 0x21, 0x3f, 0x6f, 0x3e, 0x86, 0xa5, 0xd0, 0xfc, 0x96, - 0xb8, 0x8a, 0xcb, 0xac, 0x5e, 0x5e, 0x67, 0x09, 0x32, 0x5d, 0xf0, 0xe2, 0xb3, 0x99, 0x2e, 0xe7, 0x63, 0x75, 0xc0, - 0x38, 0x4a, 0xf1, 0xc6, 0x13, 0xa5, 0xa7, 0x2d, 0xcf, 0x0a, 0x79, 0x79, 0x92, 0x31, 0xdb, 0xb3, 0x0a, 0x9c, 0x4e, - 0xc1, 0x04, 0x5f, 0xfd, 0xb4, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x4b, 0xb1, 0xd2, 0x58, 0x4e, 0x06, 0xba, - 0x13, 0x30, 0x43, 0x45, 0x81, 0x17, 0x28, 0xf8, 0x8b, 0x06, 0x46, 0xf4, 0xa5, 0xfd, 0x4d, 0x06, 0x1a, 0xe9, 0x52, - 0x9f, 0x08, 0x63, 0xcb, 0xed, 0x94, 0x69, 0x2b, 0xca, 0x19, 0x67, 0xef, 0xe5, 0x95, 0x02, 0x0c, 0xf0, 0x36, 0xb7, - 0xd1, 0x45, 0x82, 0x5e, 0x0b, 0x52, 0xe7, 0x0d, 0xdc, 0xcd, 0x32, 0xd2, 0xc2, 0xc5, 0xc7, 0xb5, 0xc3, 0x82, 0x3b, - 0xf6, 0x0b, 0xb1, 0xd0, 0x9a, 0x69, 0x30, 0x66, 0x73, 0x82, 0x05, 0x56, 0x32, 0x50, 0x60, 0x31, 0x53, 0x96, 0xa6, - 0xf5, 0x90, 0x1f, 0x1e, 0xa1, 0xb5, 0x69, 0x3d, 0xe0, 0x87, 0x47, 0x4d, 0x94, 0x1d, 0x43, 0x96, 0x13, 0x37, 0x83, - 0x7c, 0xdd, 0x44, 0x3a, 0x45, 0x67, 0x77, 0xeb, 0x4b, 0xdd, 0x51, 0xdd, 0x80, 0xeb, 0x07, 0x20, 0x80, 0x0d, 0xc0, - 0x21, 0x50, 0x0e, 0x96, 0x42, 0x04, 0x8b, 0x32, 0x89, 0xf6, 0x35, 0x74, 0xde, 0x28, 0xf8, 0x2f, 0x70, 0x17, 0x11, - 0x2b, 0xf7, 0x13, 0x04, 0xfe, 0x8a, 0x32, 0xa5, 0x4c, 0x71, 0x3f, 0x51, 0xea, 0x15, 0xca, 0x99, 0x6f, 0xcd, 0x07, - 0xd1, 0x9a, 0x08, 0x55, 0x8c, 0x21, 0xf8, 0xb7, 0xb2, 0x4c, 0x59, 0xaa, 0x4a, 0xf5, 0xa1, 0xf6, 0x5a, 0x2b, 0xad, - 0xe5, 0xe3, 0xc8, 0x79, 0x8d, 0xa1, 0x63, 0x13, 0x6b, 0x29, 0x27, 0x53, 0x67, 0x6f, 0x0e, 0x45, 0x64, 0x01, 0xa7, - 0x13, 0x36, 0x9e, 0x26, 0xc7, 0x62, 0x9a, 0x58, 0xc8, 0xfc, 0x9c, 0x61, 0x64, 0x55, 0x0d, 0xc2, 0x22, 0x6d, 0x28, - 0x4d, 0x01, 0x3a, 0x39, 0x21, 0x64, 0x8a, 0xa1, 0x28, 0xf2, 0x91, 0xea, 0x87, 0xf1, 0x66, 0xb5, 0x5f, 0xbc, 0x53, - 0x00, 0xa7, 0x61, 0x02, 0x81, 0xc0, 0xcb, 0xf8, 0x36, 0x2b, 0xae, 0xc0, 0x63, 0x78, 0x00, 0x5f, 0x82, 0x9b, 0x5c, - 0xca, 0x7e, 0xab, 0xc3, 0x1c, 0xd7, 0x16, 0x30, 0x68, 0xb0, 0x7a, 0x10, 0x1d, 0x2e, 0xa5, 0x7e, 0x57, 0x01, 0x62, - 0x63, 0x0a, 0xff, 0xb3, 0xb5, 0x61, 0xcf, 0xbe, 0x97, 0x4d, 0x43, 0xeb, 0x84, 0xd3, 0xe2, 0x2a, 0x87, 0x28, 0x2a, - 0x83, 0x18, 0xdc, 0x91, 0x1c, 0x3e, 0xef, 0x5d, 0x15, 0x5e, 0x12, 0x70, 0x2b, 0x8b, 0x45, 0xb8, 0xa2, 0xcb, 0xd1, - 0x1d, 0x5d, 0x8f, 0x6e, 0xe9, 0x98, 0x4e, 0xbe, 0x19, 0x83, 0x45, 0xb6, 0x4a, 0xbd, 0xa7, 0xeb, 0xd1, 0x92, 0x7e, - 0x3b, 0xa6, 0x47, 0x7f, 0x03, 0x13, 0x3e, 0x3c, 0x4c, 0xe8, 0x25, 0x38, 0x76, 0x91, 0x06, 0x3d, 0x35, 0x5d, 0x83, - 0xc3, 0x7a, 0x94, 0x0f, 0xf9, 0x28, 0xa7, 0x7c, 0x54, 0x0e, 0xeb, 0x11, 0x78, 0x3a, 0xd6, 0x43, 0x3e, 0xaa, 0x29, - 0x1f, 0x5d, 0x0c, 0xeb, 0xd1, 0x05, 0xf1, 0x9b, 0xfe, 0xaa, 0xe6, 0xd7, 0x15, 0x4b, 0x61, 0x5b, 0xc0, 0xf2, 0xb5, - 0xab, 0x2c, 0x49, 0xdd, 0x55, 0xad, 0x4f, 0x66, 0xc3, 0xd9, 0x9b, 0xeb, 0x2e, 0x27, 0x06, 0x8f, 0xdb, 0xa4, 0xc3, - 0xd5, 0x97, 0x13, 0x79, 0xd2, 0x4b, 0xe4, 0x87, 0xf1, 0x54, 0x9d, 0x43, 0x60, 0x26, 0x31, 0x0b, 0x63, 0x86, 0xcd, - 0x54, 0x69, 0xa0, 0xc0, 0xc9, 0x46, 0x8e, 0x8b, 0x62, 0x36, 0xca, 0x29, 0xbc, 0x8f, 0x09, 0x89, 0xf0, 0xac, 0x3a, - 0xa9, 0x47, 0x25, 0xc4, 0x1c, 0x61, 0x21, 0x3e, 0x42, 0xbf, 0xe4, 0x47, 0x0e, 0x12, 0x78, 0x86, 0x7d, 0x2d, 0x07, - 0x31, 0x1c, 0xf1, 0xa6, 0xb2, 0x7a, 0x16, 0x26, 0x50, 0x59, 0x3d, 0x2c, 0x74, 0x65, 0x25, 0xcd, 0x46, 0xb5, 0x5b, - 0x59, 0x8d, 0x63, 0x94, 0x10, 0x12, 0x15, 0xaa, 0x32, 0x50, 0x9f, 0x24, 0x2c, 0x2c, 0x54, 0x65, 0x17, 0xf2, 0xa3, - 0x0b, 0xb7, 0xb2, 0x0b, 0x70, 0x21, 0x1d, 0x24, 0xee, 0x55, 0x2a, 0x4f, 0xdb, 0xd7, 0x41, 0x6f, 0x55, 0xd1, 0x0d, - 0xbf, 0xab, 0xcb, 0x38, 0x2a, 0xa8, 0x8d, 0x01, 0x8d, 0x0b, 0x23, 0x12, 0x54, 0xad, 0x51, 0xf0, 0x87, 0x04, 0x51, - 0x69, 0x0c, 0x5e, 0x9d, 0x49, 0xd7, 0x4a, 0xad, 0x69, 0x35, 0x28, 0x06, 0x25, 0xdc, 0x9f, 0xf2, 0xd6, 0x42, 0xfa, - 0x1e, 0x22, 0x2a, 0x43, 0x79, 0x83, 0x7f, 0x60, 0xf0, 0x64, 0xb6, 0x4a, 0xc3, 0x64, 0x74, 0x4f, 0xe3, 0xd1, 0x12, - 0xe1, 0x60, 0xd8, 0x3a, 0x95, 0x78, 0xeb, 0x97, 0x90, 0x7e, 0x47, 0xe3, 0xd1, 0x2d, 0x4d, 0x8d, 0xcd, 0xa9, 0x86, - 0xba, 0xea, 0x8d, 0xe9, 0x5d, 0x04, 0xaf, 0xef, 0xa3, 0x25, 0x85, 0xad, 0x74, 0x9a, 0x67, 0x57, 0x45, 0x94, 0x52, - 0x44, 0x20, 0x5c, 0x23, 0x72, 0xe0, 0x52, 0xa1, 0x0d, 0xae, 0x07, 0x50, 0x86, 0x82, 0x0b, 0x5c, 0x0e, 0xe2, 0xd1, - 0xd2, 0x21, 0x53, 0x4b, 0x75, 0x91, 0x45, 0xf8, 0x68, 0x6b, 0xa3, 0x25, 0x79, 0x46, 0x2c, 0x8c, 0x4b, 0x18, 0x42, - 0x55, 0x58, 0xa1, 0x0b, 0x12, 0x36, 0x70, 0x64, 0x2f, 0x2c, 0xeb, 0x70, 0x03, 0xa6, 0x45, 0xf7, 0x60, 0x1e, 0x05, - 0x0a, 0x07, 0x9b, 0x20, 0xdc, 0x84, 0xa2, 0x9d, 0xa3, 0xd0, 0x39, 0x9c, 0x09, 0x4a, 0x77, 0x26, 0x08, 0x69, 0x57, - 0x37, 0xd9, 0x12, 0xae, 0xc1, 0xf6, 0x0e, 0x9d, 0x8a, 0x4a, 0xaa, 0xce, 0x2d, 0x98, 0x2c, 0xe1, 0x11, 0xb6, 0x84, - 0xa9, 0x99, 0x4e, 0xe1, 0x06, 0x7c, 0x78, 0xb4, 0x33, 0xdf, 0xe5, 0xec, 0xcd, 0x21, 0xd8, 0x76, 0x4a, 0x1f, 0x10, - 0x43, 0xec, 0x96, 0x6c, 0x3c, 0x5d, 0x1e, 0x17, 0xd3, 0x25, 0x12, 0x3b, 0x4d, 0xb7, 0x18, 0x9f, 0x2f, 0x17, 0x34, - 0xc1, 0xb3, 0x8d, 0xd5, 0xf3, 0xa5, 0x46, 0x4b, 0x49, 0x19, 0xae, 0xb7, 0x25, 0xfa, 0xff, 0xcb, 0x8b, 0x5f, 0x0a, - 0xf0, 0x12, 0x8c, 0x05, 0x80, 0x70, 0x0f, 0xa6, 0x05, 0xa9, 0x89, 0xb2, 0xb1, 0x4c, 0xc3, 0x14, 0x17, 0x81, 0x4e, - 0xe9, 0xf7, 0xc3, 0x9c, 0xa5, 0xc4, 0x81, 0x0e, 0x35, 0xa3, 0xb4, 0x4e, 0x5d, 0x21, 0x08, 0xf0, 0x48, 0xf2, 0x1c, - 0x9b, 0x7c, 0x33, 0x9e, 0x05, 0x72, 0x20, 0x82, 0x28, 0x3b, 0xc6, 0x47, 0x0c, 0x5c, 0x14, 0xa9, 0xb8, 0x9d, 0xb6, - 0x88, 0xcb, 0xdd, 0x63, 0x16, 0xe2, 0x24, 0x61, 0xae, 0x59, 0x36, 0x64, 0x75, 0x84, 0x09, 0xaa, 0x30, 0x30, 0xcb, - 0x1b, 0xb2, 0xfa, 0xf0, 0x08, 0x22, 0xb5, 0x9a, 0x32, 0x56, 0x5d, 0x65, 0x7c, 0x0b, 0x40, 0xd6, 0x8c, 0xb1, 0xa3, - 0xbf, 0x8d, 0x67, 0xf2, 0x9b, 0x28, 0xe4, 0x27, 0x47, 0x7f, 0x83, 0xe4, 0xe3, 0x6f, 0x91, 0x99, 0x83, 0x64, 0xaf, - 0xa0, 0x2b, 0x7f, 0xd6, 0x15, 0x94, 0x26, 0xae, 0xbd, 0x42, 0xad, 0x3d, 0xa1, 0xd7, 0x5e, 0x89, 0xee, 0xd4, 0x9a, - 0xf7, 0x90, 0xb6, 0xb3, 0x60, 0x82, 0x8e, 0x66, 0x77, 0xa0, 0x83, 0xb7, 0x8a, 0xa0, 0x17, 0x49, 0xa8, 0x3d, 0x42, - 0xa5, 0x51, 0x2f, 0xec, 0xc8, 0x6e, 0xd6, 0x25, 0x73, 0x0c, 0x98, 0x63, 0x73, 0x0e, 0x55, 0xc3, 0x5c, 0x1e, 0xd4, - 0x29, 0x2b, 0x86, 0x39, 0x1e, 0xc0, 0x6b, 0x26, 0x86, 0xd5, 0x20, 0x57, 0x28, 0xdf, 0x97, 0xac, 0x1c, 0x16, 0x83, - 0x5c, 0x71, 0x33, 0x53, 0x3f, 0x36, 0x6d, 0xa2, 0xc2, 0x33, 0xaf, 0xd8, 0xc9, 0xaa, 0x07, 0x7c, 0x2c, 0x78, 0x32, - 0xbb, 0x9e, 0x8f, 0xaf, 0x81, 0x93, 0xd9, 0xdc, 0x45, 0x4b, 0x7a, 0x1f, 0xa5, 0xf4, 0x36, 0x5a, 0xd3, 0x65, 0x74, - 0xa9, 0x4d, 0x8c, 0x93, 0x06, 0xce, 0x01, 0x68, 0x15, 0x40, 0xe2, 0xc9, 0x5f, 0xef, 0x79, 0x52, 0x87, 0x4b, 0x9a, - 0x82, 0xdb, 0xb0, 0x6b, 0x9f, 0x79, 0xed, 0x4a, 0xa4, 0x36, 0x88, 0xb1, 0x66, 0x0c, 0x15, 0x37, 0xce, 0xba, 0x8f, - 0xaa, 0x06, 0x76, 0xae, 0x8d, 0x4d, 0x54, 0x0f, 0x27, 0xd3, 0x02, 0x10, 0x5b, 0x8b, 0xe1, 0xd0, 0x1e, 0x21, 0xbb, - 0xc7, 0x8f, 0x0a, 0xf4, 0xdc, 0x13, 0x06, 0xdb, 0xb6, 0xe5, 0x0f, 0x0c, 0x61, 0x4a, 0x3f, 0x7d, 0xe4, 0x17, 0x84, - 0x4c, 0xaf, 0xe0, 0x6c, 0x04, 0xea, 0x68, 0x84, 0x4e, 0xbf, 0xd5, 0x61, 0xa9, 0x0e, 0xf0, 0xcd, 0x5d, 0x94, 0xd0, - 0xfb, 0x28, 0x77, 0xc8, 0xda, 0xb2, 0x61, 0x62, 0x7a, 0x9e, 0x85, 0xbc, 0x7d, 0xa0, 0x17, 0x0b, 0x00, 0xd1, 0x1a, - 0xc4, 0xae, 0xd4, 0xf5, 0x08, 0x9c, 0x86, 0xd0, 0x24, 0x34, 0x82, 0xab, 0x0a, 0xc2, 0x08, 0xd8, 0x92, 0xf0, 0x37, - 0x98, 0xa8, 0xc0, 0x17, 0xe0, 0x22, 0x93, 0xa6, 0x39, 0x0f, 0x1a, 0x77, 0x24, 0xcf, 0xca, 0xb6, 0xb7, 0x2b, 0x8c, - 0x26, 0x18, 0x7b, 0xa2, 0x7d, 0x1e, 0x29, 0x46, 0x71, 0x99, 0x84, 0xd9, 0xe8, 0x4e, 0x9e, 0xe7, 0x34, 0x1b, 0xdd, - 0xab, 0x5f, 0x35, 0x1d, 0xd3, 0xef, 0x54, 0x40, 0x1b, 0x29, 0x7d, 0xeb, 0x38, 0x1b, 0xd0, 0x7a, 0xb1, 0xd0, 0xfe, - 0xd7, 0x62, 0x74, 0x47, 0xc5, 0xe8, 0xde, 0xb5, 0xa4, 0x9a, 0x4c, 0xcb, 0xe3, 0x0a, 0x0d, 0xa9, 0x3a, 0xbf, 0x2f, - 0x81, 0x9f, 0x2b, 0xb4, 0xef, 0xb4, 0xfe, 0xde, 0x69, 0xff, 0x45, 0x27, 0x4f, 0x20, 0x59, 0xa2, 0x92, 0xd5, 0x23, - 0xb0, 0x63, 0x5f, 0xe7, 0x71, 0xa9, 0x47, 0x29, 0xa6, 0xc6, 0xa4, 0x1f, 0x03, 0x57, 0x4c, 0x7b, 0x25, 0xb8, 0x5a, - 0x6e, 0xb7, 0x32, 0x86, 0x26, 0xec, 0xd9, 0x31, 0x44, 0x3d, 0xd7, 0x8e, 0x51, 0xc2, 0x73, 0x0f, 0x88, 0x95, 0xcc, - 0x5b, 0xba, 0x04, 0x24, 0xf0, 0xd6, 0xc1, 0xa4, 0x28, 0x46, 0x29, 0xc0, 0x4f, 0xa8, 0x3c, 0x0e, 0xfa, 0x84, 0x7c, - 0xa1, 0x50, 0x27, 0x84, 0xb7, 0x25, 0x70, 0xfc, 0x61, 0x7d, 0x54, 0x08, 0x5e, 0xe5, 0xb8, 0xfe, 0x0a, 0xe3, 0xfa, - 0x4b, 0x85, 0xe3, 0x8e, 0x65, 0xbb, 0x7e, 0xde, 0xa6, 0x46, 0x2f, 0xc1, 0xc2, 0x77, 0x23, 0xcd, 0x23, 0xb9, 0x41, - 0x48, 0x95, 0x60, 0xa5, 0x76, 0x21, 0xc1, 0xfc, 0x4b, 0x39, 0x5b, 0x9d, 0xb9, 0xea, 0x91, 0x07, 0xe5, 0x6c, 0x6a, - 0xfa, 0x3d, 0x09, 0xda, 0x7d, 0x47, 0x9a, 0xc3, 0x5b, 0x74, 0xf8, 0xec, 0x1a, 0x4b, 0xcc, 0x9d, 0x44, 0xc9, 0xf3, - 0x49, 0x60, 0xab, 0xe7, 0xd9, 0xb5, 0xf4, 0xb1, 0xda, 0xc5, 0xf1, 0xd3, 0xe7, 0x4f, 0x5c, 0x87, 0x69, 0xe5, 0x29, - 0x41, 0xc0, 0x9b, 0x43, 0xdb, 0x15, 0xca, 0x80, 0x86, 0xfa, 0x06, 0x8e, 0x73, 0x35, 0xac, 0x15, 0x01, 0x53, 0x52, - 0x1e, 0x15, 0xe0, 0x50, 0xe7, 0x91, 0xbb, 0x69, 0x58, 0x6b, 0xba, 0xe6, 0xf5, 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, - 0x3f, 0x3c, 0x1a, 0xd4, 0xf8, 0x93, 0xf8, 0xa3, 0xd1, 0xce, 0x0d, 0x77, 0x9a, 0x0a, 0x33, 0xd7, 0x62, 0x45, 0x76, - 0x47, 0xc9, 0xc9, 0xef, 0xe8, 0x85, 0xb1, 0x3f, 0xff, 0xb9, 0x98, 0x70, 0xd2, 0x12, 0x13, 0xa2, 0xa5, 0x83, 0x12, - 0x1d, 0xec, 0x28, 0xaf, 0xcc, 0x4b, 0xbc, 0x74, 0x8e, 0xff, 0x7d, 0x3d, 0xd6, 0xae, 0x02, 0xa1, 0xd5, 0xc9, 0xc3, - 0xf6, 0x64, 0x81, 0xa8, 0x01, 0xd5, 0xec, 0xb2, 0x1c, 0x69, 0xda, 0x59, 0x93, 0x8d, 0x27, 0x73, 0xdd, 0xcd, 0xe2, - 0xd9, 0x4c, 0x76, 0x2c, 0x2c, 0x3d, 0x0c, 0xc6, 0x4e, 0x15, 0x7d, 0x0e, 0x5a, 0x7e, 0x04, 0xcf, 0x7d, 0xe5, 0x99, - 0xcb, 0x66, 0x69, 0xf1, 0x02, 0x9d, 0x73, 0xaa, 0x21, 0x87, 0x1c, 0x80, 0xe3, 0x02, 0x8d, 0x25, 0x8a, 0x28, 0x08, - 0x1a, 0x13, 0x84, 0x5d, 0x95, 0xee, 0x48, 0x9f, 0x76, 0xf1, 0x69, 0x2b, 0xf4, 0x3d, 0xde, 0x67, 0x20, 0x31, 0x75, - 0x24, 0x0f, 0xb5, 0xd7, 0x1c, 0x95, 0x3c, 0x8b, 0x53, 0x85, 0xcf, 0x2f, 0x65, 0x67, 0xfe, 0xdd, 0x6a, 0x4c, 0xf1, - 0x1f, 0x69, 0xda, 0x77, 0x2e, 0x4d, 0x13, 0xdd, 0xb5, 0x3c, 0x68, 0x29, 0x2c, 0x38, 0x6e, 0x1b, 0x77, 0xfd, 0xfa, - 0x39, 0xaa, 0x61, 0x61, 0x73, 0x38, 0x13, 0x3a, 0xb4, 0x77, 0x95, 0x9d, 0xb9, 0x3e, 0xa2, 0x56, 0x5d, 0xac, 0xda, - 0x80, 0x92, 0x25, 0xe7, 0xd6, 0xe9, 0x88, 0x95, 0xbe, 0x3b, 0x0c, 0x77, 0xe6, 0x51, 0xb1, 0xbb, 0xdb, 0xed, 0x84, - 0xb4, 0xed, 0x83, 0xf1, 0xbe, 0x84, 0x85, 0x58, 0xef, 0xb0, 0x83, 0xef, 0xc3, 0xfa, 0x31, 0x1f, 0xfc, 0x1c, 0xca, - 0x75, 0x55, 0x3f, 0xcf, 0xa4, 0xa1, 0xcf, 0xcb, 0x52, 0x5c, 0xcb, 0x4e, 0xb9, 0x42, 0xb7, 0x96, 0xa9, 0xf7, 0x9b, - 0xf8, 0x4d, 0x2b, 0x40, 0x8c, 0xd3, 0x15, 0x23, 0xc5, 0x1b, 0x1a, 0x61, 0x9c, 0x87, 0xdb, 0x64, 0x51, 0x4b, 0x95, - 0x40, 0xd4, 0xe6, 0x27, 0x8f, 0x79, 0xa4, 0xd5, 0x99, 0xf0, 0xdd, 0x63, 0xee, 0x4a, 0xd7, 0x76, 0x9b, 0xf8, 0xa9, - 0xa6, 0x1d, 0xee, 0x0e, 0x74, 0x47, 0xeb, 0x1e, 0x6e, 0x9e, 0xc9, 0xcf, 0x23, 0xfd, 0xc5, 0x00, 0x9b, 0xb5, 0xcb, - 0xb8, 0xec, 0x18, 0xee, 0x3b, 0xd3, 0x83, 0xb1, 0x80, 0x40, 0x62, 0x86, 0x5e, 0x06, 0x36, 0x70, 0x81, 0xbd, 0xc2, - 0x80, 0x21, 0xae, 0x6e, 0xc9, 0xb9, 0xb2, 0xb2, 0x75, 0x91, 0xb7, 0x51, 0x21, 0xd8, 0x34, 0x1d, 0x37, 0x49, 0x0e, - 0xc1, 0x09, 0x5b, 0xee, 0x7d, 0xed, 0xb5, 0x33, 0xfc, 0xc7, 0xa0, 0xb2, 0x6e, 0x89, 0x8e, 0x51, 0xdb, 0x63, 0xa5, - 0xee, 0xd5, 0xbc, 0xca, 0x7d, 0xe4, 0x58, 0xbf, 0xe9, 0x97, 0x9a, 0x7d, 0xc1, 0x6b, 0x29, 0x38, 0x34, 0xb6, 0x5b, - 0x61, 0x17, 0x8b, 0x73, 0xb4, 0x1a, 0x59, 0x6b, 0xab, 0xbd, 0x46, 0x2a, 0xba, 0x7f, 0xcd, 0x71, 0x62, 0x2d, 0x85, - 0xcd, 0x87, 0x0f, 0x17, 0x6c, 0x9b, 0x00, 0x06, 0x2d, 0x3a, 0x0b, 0x94, 0x20, 0x93, 0x95, 0xaa, 0xdd, 0x4c, 0x89, - 0x5b, 0xee, 0x67, 0x5d, 0x66, 0x3b, 0x8f, 0x5f, 0x3b, 0x69, 0x9f, 0xf8, 0x1c, 0xfd, 0x30, 0xbf, 0x33, 0x4e, 0x4a, - 0xd6, 0x30, 0xae, 0xe5, 0xff, 0x57, 0xd3, 0xab, 0x32, 0x4b, 0xa3, 0x8d, 0xe6, 0xc1, 0x4c, 0xa8, 0x4d, 0x17, 0x1a, - 0xa3, 0xb6, 0xcb, 0x46, 0x12, 0xd1, 0xfa, 0x0e, 0x04, 0x33, 0x92, 0xfb, 0xaa, 0xda, 0xbc, 0x52, 0x6d, 0xe0, 0x1d, - 0x3e, 0xb1, 0xd1, 0x3d, 0xdb, 0x13, 0x42, 0xf9, 0xee, 0x69, 0xa1, 0x57, 0x2d, 0xad, 0x3c, 0xb6, 0xab, 0x72, 0x2e, - 0x46, 0xb5, 0x7a, 0xc2, 0x64, 0xc3, 0x82, 0xc9, 0xfe, 0x7f, 0x5f, 0x66, 0x69, 0x9b, 0xa2, 0x03, 0xd3, 0xe9, 0xfb, - 0x74, 0xd2, 0x0d, 0xae, 0x33, 0x60, 0x11, 0xc1, 0x96, 0x0a, 0xc7, 0xa3, 0x50, 0x6e, 0x90, 0x30, 0x11, 0x5c, 0x47, - 0xbd, 0xec, 0x68, 0x99, 0x94, 0x55, 0x01, 0xcf, 0x2f, 0x5d, 0x65, 0x3a, 0x8e, 0x86, 0x7e, 0xff, 0x3a, 0xd5, 0xa1, - 0x5f, 0x69, 0xe1, 0x9c, 0x23, 0xcb, 0xcc, 0x51, 0x75, 0xc8, 0x30, 0x46, 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x86, - 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x8c, 0x81, 0x5c, 0x2a, 0x83, 0x7a, 0x45, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, - 0x42, 0x2f, 0x59, 0xe1, 0xde, 0x85, 0xd6, 0x20, 0x50, 0x14, 0x7e, 0xca, 0xf4, 0x42, 0xb5, 0xf3, 0x92, 0x26, 0xb4, - 0xa4, 0x2b, 0xd2, 0x80, 0xbe, 0xd7, 0xca, 0xd9, 0xd1, 0xc9, 0x4e, 0xcf, 0x7a, 0xcc, 0xca, 0xe1, 0x64, 0x1a, 0xc3, - 0x35, 0x2d, 0xb6, 0xd7, 0xb4, 0xa5, 0x7f, 0xe3, 0xf2, 0x36, 0x8e, 0x47, 0xbb, 0x40, 0xda, 0xa6, 0xb8, 0xfd, 0xd4, - 0xe1, 0xf6, 0xd7, 0x0d, 0x5b, 0x4e, 0x7b, 0xeb, 0xed, 0xb6, 0x97, 0x82, 0x8d, 0xa8, 0xc3, 0xc7, 0xaf, 0xa5, 0x74, - 0xdd, 0x70, 0xf9, 0x29, 0x3c, 0x3b, 0x7c, 0xfd, 0xd2, 0x05, 0x97, 0xa3, 0x75, 0x9b, 0xbb, 0x5f, 0xee, 0x22, 0xcb, - 0x7d, 0xd6, 0xd0, 0x72, 0x35, 0x43, 0x3e, 0x79, 0xd6, 0xda, 0x3b, 0xd4, 0x82, 0xe5, 0xac, 0x9b, 0xf0, 0xc4, 0x60, - 0xc7, 0x5e, 0x7b, 0x9b, 0xa3, 0xd6, 0x97, 0x2c, 0x8f, 0x04, 0xba, 0x24, 0x4f, 0x37, 0xfd, 0x83, 0x08, 0xf3, 0xd1, - 0x1d, 0xcd, 0x01, 0x57, 0xac, 0x36, 0x97, 0x0c, 0xd2, 0xd4, 0xed, 0x25, 0x2e, 0x7d, 0x85, 0x43, 0xb2, 0xc1, 0x27, - 0xcd, 0x54, 0x7d, 0x72, 0xc9, 0x83, 0xff, 0xb7, 0x51, 0xab, 0xf4, 0xec, 0x24, 0x7b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, - 0x4c, 0x34, 0x12, 0xf0, 0xd4, 0x2c, 0x86, 0x7a, 0x54, 0x97, 0x71, 0x51, 0xe5, 0x3a, 0xe6, 0xd8, 0xde, 0xae, 0xa1, - 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xfa, 0x0e, 0x6c, 0x04, 0x3a, 0x2a, 0x51, 0x5f, 0x86, 0x99, 0xbe, 0x0c, 0xd3, - 0xae, 0xad, 0x02, 0xc3, 0x2b, 0xb7, 0x4a, 0x22, 0x5d, 0x8d, 0x7a, 0x5c, 0xcf, 0x92, 0xdf, 0x8b, 0xbc, 0x7b, 0x4d, - 0x3a, 0x12, 0x7f, 0xba, 0x74, 0xe4, 0xf5, 0x30, 0x20, 0xe2, 0x73, 0x96, 0x86, 0x6d, 0x14, 0x04, 0xa7, 0x96, 0x3b, - 0x90, 0xe6, 0x23, 0x40, 0xe6, 0xc7, 0x69, 0xf8, 0x4e, 0x89, 0x73, 0xc8, 0x46, 0x6a, 0x9c, 0xd8, 0x52, 0xab, 0x87, - 0xe0, 0xce, 0x7b, 0xcd, 0x63, 0x08, 0x7c, 0xf8, 0x01, 0x37, 0x83, 0x8c, 0x6e, 0x4b, 0x74, 0x94, 0x36, 0x87, 0xba, - 0xe5, 0x23, 0x4f, 0xa8, 0x64, 0x64, 0x78, 0x31, 0xb4, 0x77, 0x47, 0x60, 0x54, 0x5b, 0x81, 0xcc, 0xb0, 0x3c, 0x3c, - 0x1a, 0xa6, 0x52, 0x50, 0x34, 0x14, 0xc3, 0x25, 0xca, 0x01, 0x31, 0x09, 0x04, 0x46, 0xe5, 0x20, 0x55, 0x95, 0xc9, - 0x17, 0x83, 0x54, 0xdd, 0xaa, 0x48, 0x73, 0x9e, 0x85, 0x35, 0x55, 0x2d, 0xa2, 0x63, 0x3a, 0x14, 0x74, 0xa9, 0x77, - 0x6a, 0xae, 0xa4, 0x17, 0x72, 0x39, 0x3e, 0x53, 0x69, 0x30, 0x8a, 0x67, 0x36, 0x45, 0xbd, 0x95, 0xfb, 0xd9, 0x7d, - 0x8b, 0x29, 0x0d, 0x62, 0x53, 0x3b, 0x8b, 0x18, 0x56, 0xed, 0x87, 0xac, 0xce, 0x41, 0xbb, 0x0b, 0xca, 0xc6, 0x5a, - 0x3b, 0xcf, 0x7b, 0xc1, 0xcc, 0x41, 0xdb, 0x58, 0xfb, 0x3e, 0xf4, 0x5a, 0x8c, 0xda, 0x1b, 0x53, 0x85, 0x7b, 0x02, - 0x3f, 0x4d, 0xd0, 0x74, 0x27, 0xf2, 0x1c, 0x75, 0xc8, 0xbb, 0xfb, 0x99, 0x25, 0x3b, 0x93, 0x4f, 0x62, 0x99, 0x34, - 0xed, 0x63, 0x12, 0xa3, 0x96, 0x18, 0x46, 0x17, 0x6e, 0x64, 0x52, 0xfb, 0xb9, 0x33, 0xfd, 0x88, 0x67, 0xf2, 0xb0, - 0x1d, 0x1a, 0x75, 0xa5, 0x61, 0x2d, 0x29, 0xa2, 0xba, 0xa0, 0xb7, 0xa6, 0x3a, 0x3a, 0xa2, 0x4e, 0x47, 0x60, 0x75, - 0x45, 0x1b, 0xd4, 0x00, 0x4c, 0xc6, 0x8d, 0xa9, 0xcd, 0xe5, 0x60, 0x1a, 0xa3, 0x2a, 0x78, 0x4a, 0x77, 0x85, 0xd2, - 0xbd, 0x49, 0xd3, 0xb4, 0x86, 0xd8, 0x00, 0x06, 0x04, 0x76, 0xf4, 0xe4, 0xf4, 0x07, 0x3e, 0x2a, 0x00, 0x0d, 0xbc, - 0xdb, 0x99, 0xca, 0x91, 0xa8, 0x77, 0x72, 0xd3, 0xfa, 0xa9, 0x4e, 0x55, 0x2e, 0x80, 0x8a, 0x3b, 0x4b, 0xe7, 0x97, - 0x7a, 0xc4, 0x02, 0x18, 0xf7, 0xc0, 0x9a, 0xea, 0x9d, 0x66, 0x60, 0x3d, 0x91, 0xe7, 0x59, 0xc5, 0x13, 0x51, 0xc0, - 0x8c, 0x88, 0xeb, 0x6b, 0x51, 0xc0, 0x30, 0xc8, 0x01, 0x40, 0x8b, 0xe6, 0x2a, 0x9a, 0xf0, 0xaf, 0x1a, 0xba, 0x2f, - 0x0f, 0xff, 0x4a, 0xe5, 0xfa, 0x7a, 0xdc, 0x80, 0xa1, 0xf2, 0xba, 0xe6, 0x3b, 0x99, 0xbe, 0xe6, 0x4f, 0x9c, 0x4c, - 0x4b, 0xb1, 0x2e, 0x77, 0xb2, 0x7c, 0xf5, 0x35, 0x7f, 0xaa, 0xf2, 0x1c, 0x3d, 0x69, 0x68, 0x1a, 0xdf, 0xef, 0x64, - 0xf9, 0xe6, 0xeb, 0x27, 0x26, 0xcf, 0x57, 0xe3, 0x86, 0xde, 0x72, 0xfe, 0xd1, 0x66, 0x9a, 0xa8, 0xaa, 0xc6, 0x4f, - 0xbe, 0x31, 0xb9, 0x9e, 0x34, 0xf4, 0x5a, 0x14, 0xf5, 0x72, 0xa7, 0xa8, 0xa3, 0xaf, 0x8f, 0xbe, 0xe1, 0x5f, 0xeb, - 0xee, 0x1d, 0x35, 0xf4, 0xcf, 0x75, 0x5c, 0xd6, 0xbc, 0xdc, 0x29, 0xee, 0x6f, 0xdf, 0x7c, 0xf3, 0xc4, 0x64, 0x7c, - 0xd2, 0xd0, 0x7b, 0x1e, 0x77, 0xb4, 0x7d, 0xf2, 0xf4, 0x09, 0xff, 0x5b, 0xd3, 0xd0, 0x5f, 0x98, 0x1b, 0x1c, 0xf5, - 0x34, 0x73, 0xf4, 0xf0, 0x89, 0xf0, 0x51, 0x03, 0x86, 0x0e, 0x1a, 0x40, 0x2e, 0x8c, 0x9a, 0x66, 0x8f, 0x57, 0x2e, - 0xb8, 0x7d, 0x9f, 0xc7, 0x69, 0xbc, 0x82, 0x83, 0x60, 0x83, 0xc6, 0x59, 0x25, 0x70, 0xaa, 0xc0, 0x7b, 0x46, 0x05, - 0xcd, 0x2a, 0xf1, 0x0f, 0xce, 0x3f, 0xc2, 0xa0, 0x21, 0xa4, 0x8d, 0x8c, 0x0c, 0xf4, 0x76, 0xa5, 0x22, 0x1b, 0xa1, - 0xff, 0xa6, 0x1f, 0x07, 0xc7, 0x85, 0xd1, 0xeb, 0xf7, 0xc3, 0x92, 0x55, 0x61, 0x49, 0x08, 0xfd, 0x23, 0x2c, 0xc1, - 0xa1, 0xa4, 0x64, 0x4e, 0x3e, 0xed, 0x7b, 0xae, 0x8c, 0xc2, 0x42, 0x10, 0xdd, 0x45, 0xe6, 0x01, 0x55, 0x8f, 0xae, - 0x43, 0x37, 0xc4, 0xcb, 0x0a, 0x4b, 0x86, 0x0e, 0x66, 0x30, 0x43, 0x50, 0xfc, 0x6b, 0x1e, 0x0a, 0xf0, 0x89, 0x07, - 0xf8, 0xe8, 0x31, 0x99, 0x71, 0x79, 0xad, 0x7d, 0x7b, 0x19, 0x96, 0x34, 0x50, 0x6d, 0x87, 0xa0, 0x03, 0x91, 0xfb, - 0x02, 0x3c, 0x05, 0x06, 0x2e, 0x2c, 0xec, 0x52, 0xec, 0xfa, 0xab, 0xff, 0xa2, 0x59, 0x47, 0x1b, 0x7e, 0xf4, 0x17, - 0xe3, 0xc2, 0x9e, 0x91, 0xa9, 0x38, 0x2e, 0x86, 0x93, 0xe9, 0x60, 0x20, 0x6c, 0x1c, 0xb7, 0xd3, 0x6c, 0xfe, 0xcb, - 0x5c, 0x2c, 0x16, 0xa8, 0xfb, 0xc6, 0x79, 0x9d, 0xa9, 0xbf, 0x91, 0x72, 0x3e, 0x78, 0x7d, 0xfa, 0xdb, 0xf9, 0xd9, - 0xe9, 0x4b, 0x70, 0x3e, 0xf8, 0xf0, 0xe2, 0xfb, 0x17, 0xef, 0x65, 0x70, 0x77, 0x39, 0xe7, 0xfd, 0xbe, 0x95, 0xfa, - 0x84, 0x7c, 0x58, 0x93, 0xc3, 0x30, 0x7e, 0x5c, 0x4a, 0xa3, 0x07, 0x72, 0xcc, 0x0c, 0x14, 0x32, 0x54, 0xd1, 0x98, - 0xdf, 0xc5, 0x70, 0xe2, 0x80, 0x59, 0xdc, 0x7b, 0x22, 0x5c, 0xb7, 0xe5, 0x26, 0xc8, 0x9a, 0x38, 0x71, 0xfa, 0xc1, - 0xc9, 0x54, 0x58, 0xb6, 0xb0, 0x64, 0x50, 0x36, 0xb4, 0xe9, 0x34, 0x9b, 0x97, 0x0b, 0xd3, 0x2e, 0xbb, 0x40, 0x46, - 0x69, 0x76, 0x79, 0x19, 0x4a, 0xe8, 0xea, 0x13, 0xd0, 0x00, 0xe8, 0x46, 0x95, 0xb6, 0x45, 0x7c, 0xe6, 0x96, 0x1f, - 0x8d, 0x9d, 0xe6, 0xdd, 0xa1, 0xee, 0x49, 0x37, 0xab, 0xf6, 0x06, 0x74, 0x30, 0xa1, 0xdc, 0x0e, 0xba, 0x0e, 0x26, - 0x23, 0xdb, 0xf2, 0xcb, 0xbc, 0x5e, 0xe8, 0xe6, 0xd8, 0x61, 0xa8, 0x9d, 0x92, 0xd7, 0xc2, 0x43, 0x64, 0x20, 0x19, - 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0xfd, 0x60, 0xd7, 0x3b, 0x7e, 0x93, 0x0b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x51, - 0x25, 0x9d, 0xcb, 0x05, 0xe3, 0xf3, 0x6a, 0x71, 0x02, 0x6e, 0xe7, 0xf3, 0x6a, 0x11, 0x61, 0x50, 0xbe, 0x0c, 0x62, - 0x95, 0x80, 0xdd, 0x8b, 0x85, 0xf0, 0xed, 0x84, 0x36, 0x30, 0x1b, 0x48, 0xb0, 0x41, 0x61, 0x56, 0x1a, 0xa2, 0xdc, - 0x49, 0x8f, 0x36, 0x88, 0x3c, 0xc4, 0xea, 0x79, 0xdd, 0xf6, 0x64, 0xd3, 0x17, 0x13, 0x5c, 0x65, 0x31, 0x13, 0xd3, - 0xf8, 0x98, 0x95, 0xd3, 0x18, 0x4a, 0x89, 0xd3, 0x34, 0x8c, 0xe9, 0x84, 0x56, 0x84, 0x24, 0x8c, 0xcf, 0xe3, 0x05, - 0x4d, 0x50, 0x4a, 0x10, 0x42, 0xc8, 0x8f, 0x11, 0xda, 0xe6, 0xc0, 0x92, 0x37, 0xdb, 0xcf, 0xd1, 0xcf, 0xed, 0x18, - 0x2e, 0xa3, 0x22, 0x74, 0x83, 0xce, 0x1a, 0xee, 0x8d, 0xa8, 0xa4, 0x31, 0x56, 0x0c, 0x41, 0xc0, 0x4b, 0x8c, 0x4a, - 0x58, 0x92, 0x98, 0xd5, 0x10, 0x45, 0xa0, 0x98, 0xc7, 0x0b, 0x56, 0x52, 0xdf, 0xe6, 0x34, 0x56, 0x26, 0x41, 0x3d, - 0x8b, 0xa5, 0x76, 0x20, 0xa4, 0x0a, 0xb1, 0xc7, 0x67, 0x55, 0x74, 0xa3, 0x0c, 0x0d, 0x00, 0x05, 0x4a, 0xca, 0xc5, - 0x6f, 0x3f, 0xdf, 0xc3, 0x4d, 0x42, 0xff, 0xb3, 0x8d, 0x8e, 0x76, 0x96, 0xcb, 0x43, 0x6f, 0xbe, 0xa0, 0x71, 0x9e, - 0x43, 0x28, 0x36, 0x8d, 0x40, 0x5e, 0x64, 0x35, 0x44, 0xb4, 0xb8, 0x0f, 0x74, 0x48, 0x38, 0x68, 0xd3, 0x2f, 0x90, - 0xea, 0x89, 0xc9, 0xa5, 0x27, 0x06, 0xc6, 0xed, 0x90, 0x09, 0x05, 0x1c, 0xe9, 0x79, 0xf6, 0x97, 0x8f, 0xb1, 0xa6, - 0xa8, 0x99, 0x8e, 0xb7, 0x21, 0x11, 0x0d, 0x5a, 0x10, 0xcd, 0xe0, 0xfd, 0x73, 0xcd, 0xf1, 0xaa, 0x03, 0x3f, 0xe0, - 0x9d, 0x8d, 0x33, 0x2f, 0x67, 0x1e, 0x91, 0x53, 0x1f, 0xe5, 0x88, 0x7e, 0xc9, 0xc3, 0x7a, 0xa4, 0x92, 0x31, 0x56, - 0x12, 0x07, 0xbd, 0x0d, 0x16, 0xcc, 0x09, 0x5d, 0xf1, 0xd0, 0xf0, 0xf1, 0x2f, 0x91, 0xc9, 0xa8, 0x68, 0xa1, 0xd8, - 0x8d, 0xca, 0x60, 0xc4, 0x39, 0x0d, 0x33, 0x34, 0x59, 0xd2, 0xc5, 0x52, 0x91, 0xe6, 0x4a, 0x9a, 0x06, 0xb8, 0x04, - 0x1a, 0x3c, 0x1f, 0xf4, 0x43, 0x43, 0x3d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, 0xfb, 0xd0, 0xe1, 0xff, 0xe7, 0xd8, - 0x05, 0x22, 0xed, 0xcd, 0x75, 0x64, 0x3c, 0xd2, 0x78, 0x38, 0x28, 0xda, 0xc7, 0xde, 0x4f, 0xfc, 0xcc, 0x19, 0x7d, - 0x48, 0x2a, 0xdf, 0xe1, 0x83, 0xe5, 0x8e, 0x37, 0xd5, 0xb3, 0x32, 0x82, 0xf5, 0xb0, 0xdd, 0xe2, 0x82, 0x68, 0xbb, - 0x00, 0x52, 0xc7, 0x78, 0xb5, 0x74, 0x8d, 0x57, 0xe3, 0x3d, 0xc6, 0xab, 0xf6, 0x4c, 0x0d, 0x73, 0xb2, 0x41, 0x7d, - 0x96, 0x94, 0xe7, 0xe7, 0x28, 0x13, 0xf4, 0x5d, 0xce, 0x0a, 0x2a, 0x53, 0x09, 0xed, 0xc5, 0x6e, 0xc6, 0xf8, 0x8e, - 0x60, 0x9c, 0x15, 0x8b, 0x91, 0x40, 0x65, 0x2a, 0x69, 0xc2, 0x5e, 0x09, 0xea, 0x31, 0x78, 0xaf, 0x31, 0x44, 0xb5, - 0x8c, 0x5d, 0xb7, 0x81, 0xd0, 0x50, 0x5b, 0x8f, 0xf6, 0x8c, 0xf5, 0xe8, 0x76, 0x5b, 0x6b, 0x7f, 0x3b, 0xb1, 0x2e, - 0x13, 0x44, 0x15, 0x96, 0xa3, 0x09, 0xf0, 0xa6, 0x89, 0xb9, 0x2d, 0x59, 0xa5, 0x05, 0x86, 0xcf, 0xfe, 0x23, 0x2c, - 0xac, 0x4a, 0xa2, 0x20, 0xb3, 0x22, 0x1a, 0xd8, 0x73, 0xf0, 0x79, 0x5c, 0xc3, 0x1a, 0x80, 0x48, 0x8e, 0xe8, 0xe1, - 0xfa, 0x47, 0x28, 0x6c, 0x66, 0x41, 0x66, 0x02, 0x32, 0xf3, 0x22, 0x6d, 0x67, 0x1d, 0x4c, 0xac, 0x49, 0xad, 0x33, - 0x16, 0x62, 0xa8, 0x91, 0x1f, 0x40, 0x19, 0x62, 0xf1, 0xc9, 0x07, 0x13, 0x2a, 0x64, 0x28, 0x55, 0xaf, 0x9b, 0xdd, - 0xc0, 0x2b, 0x1f, 0xb2, 0x6b, 0x5e, 0xd5, 0xf1, 0xf5, 0x4a, 0x5b, 0x12, 0x73, 0xb6, 0xcf, 0x6d, 0x8f, 0x56, 0xfa, - 0xd5, 0x9b, 0x17, 0xdf, 0x9f, 0x7a, 0xaf, 0x76, 0x11, 0x47, 0x43, 0xb0, 0xad, 0x18, 0x63, 0xf4, 0x16, 0x97, 0x06, - 0x13, 0xe9, 0x1a, 0x81, 0xde, 0xa5, 0xa0, 0xdf, 0xfe, 0x5c, 0x4f, 0xc0, 0x6b, 0xae, 0x96, 0x5f, 0xf2, 0x11, 0xb0, - 0x44, 0xf5, 0xac, 0x30, 0x3b, 0x2b, 0xb3, 0xbd, 0xdd, 0x8a, 0xf4, 0xb4, 0x4b, 0x8d, 0x0c, 0xc4, 0xab, 0xed, 0x30, - 0x16, 0x2e, 0x6c, 0xd3, 0xcd, 0x60, 0xd7, 0x4b, 0xc7, 0x12, 0x79, 0xbb, 0x2d, 0xa0, 0x43, 0x66, 0xc0, 0x9d, 0x97, - 0xf1, 0x1d, 0xbc, 0x2c, 0x9c, 0x6e, 0xfa, 0xc1, 0x13, 0xc0, 0x4c, 0xb8, 0xb4, 0x96, 0xc5, 0x31, 0xe3, 0x09, 0xcc, - 0x1f, 0x2d, 0x7d, 0x91, 0xb7, 0x24, 0xb4, 0x7a, 0x7f, 0x85, 0xd5, 0x08, 0xec, 0x4e, 0xce, 0x3e, 0x66, 0xab, 0xd9, - 0x12, 0x50, 0xf3, 0xaf, 0xb3, 0x02, 0x68, 0xae, 0x59, 0x0b, 0xa6, 0x29, 0xd4, 0x5f, 0xd7, 0xcf, 0xe2, 0x55, 0x9c, - 0x80, 0xea, 0x06, 0xbc, 0x45, 0xee, 0x95, 0xe8, 0x4a, 0xa3, 0x8b, 0xd2, 0x07, 0xca, 0x31, 0xa4, 0xd0, 0xd2, 0xf7, - 0x5e, 0x25, 0xcf, 0x3d, 0x0d, 0xb8, 0xa4, 0x50, 0xf3, 0x64, 0x4b, 0x19, 0x0b, 0x80, 0x85, 0x0e, 0x66, 0x92, 0x6c, - 0x45, 0x77, 0x1a, 0x93, 0x02, 0xde, 0x6a, 0xe0, 0x8f, 0x22, 0xab, 0xe5, 0x5d, 0xb1, 0x0a, 0x0b, 0xc7, 0xfe, 0xba, - 0xdf, 0x8f, 0x1d, 0xfb, 0xeb, 0x4b, 0x45, 0xeb, 0xe2, 0x76, 0x03, 0x48, 0x83, 0x01, 0x44, 0x4e, 0xd5, 0x40, 0xe8, - 0x88, 0x62, 0xbe, 0xef, 0xdf, 0xa9, 0xce, 0x22, 0x41, 0xe8, 0x77, 0xea, 0x75, 0xa4, 0x24, 0xa0, 0x53, 0xab, 0xd9, - 0xc9, 0x40, 0x99, 0x7d, 0x40, 0x40, 0x54, 0x37, 0x23, 0x9b, 0x2f, 0xa4, 0x73, 0xb1, 0x0c, 0x1f, 0x3e, 0xa6, 0x10, - 0x50, 0xb8, 0xa3, 0x46, 0xeb, 0x6d, 0x88, 0x04, 0xca, 0x08, 0x45, 0x8c, 0x79, 0xb1, 0x92, 0x84, 0xcc, 0xc7, 0x0b, - 0x14, 0x5c, 0x59, 0x60, 0x57, 0xce, 0x26, 0xc3, 0x22, 0xe2, 0x2c, 0xdc, 0xff, 0xcd, 0x64, 0x41, 0x50, 0x73, 0xe5, - 0x06, 0x72, 0xdc, 0xc9, 0xe4, 0xed, 0x29, 0xaf, 0x86, 0x8a, 0x89, 0x08, 0x02, 0xc3, 0x0d, 0x3f, 0xe3, 0xe3, 0xa3, - 0x05, 0x01, 0x15, 0x99, 0x31, 0x0b, 0xd1, 0x2f, 0x8e, 0xbf, 0x02, 0xd4, 0x98, 0xd1, 0xd1, 0x53, 0x00, 0x85, 0x85, - 0x80, 0xe8, 0x63, 0x90, 0xd1, 0x56, 0xf0, 0xbb, 0x92, 0xbf, 0x5b, 0x27, 0xbe, 0x0b, 0xfd, 0x5a, 0xd1, 0xcb, 0x18, - 0x18, 0x8e, 0x68, 0x72, 0x18, 0xf2, 0xc1, 0x64, 0x00, 0xda, 0x12, 0x67, 0xf7, 0xb5, 0xb4, 0xe2, 0xfa, 0x74, 0xe9, - 0x74, 0xff, 0xa4, 0x3e, 0x48, 0x22, 0x15, 0xac, 0x90, 0xc4, 0x00, 0x42, 0x59, 0xca, 0x6d, 0xb2, 0x04, 0xcb, 0x0a, - 0xbd, 0xa4, 0xb9, 0x46, 0x49, 0xdc, 0xdd, 0x0c, 0x1c, 0xa3, 0x66, 0x9d, 0x86, 0x45, 0xcb, 0x8d, 0x1a, 0xe0, 0x73, - 0x12, 0x56, 0x9a, 0x1b, 0xce, 0x4c, 0x38, 0x67, 0x3a, 0x5c, 0x1d, 0x73, 0xf6, 0x9a, 0x23, 0x18, 0x47, 0x82, 0x37, - 0x1e, 0xba, 0x64, 0x0a, 0x2a, 0x32, 0x65, 0x1c, 0x4c, 0x7b, 0x80, 0x7b, 0xcf, 0xc1, 0x38, 0x8c, 0x0d, 0x6a, 0x43, - 0xea, 0x53, 0xe7, 0x2e, 0x04, 0x82, 0xb4, 0xd6, 0xcb, 0x7c, 0x86, 0xa7, 0x67, 0x84, 0xb2, 0x3f, 0xe4, 0xf0, 0x01, - 0xf0, 0xb2, 0x24, 0x27, 0x13, 0xfe, 0xf4, 0xf1, 0x6e, 0xa0, 0x2a, 0x3e, 0x08, 0x0e, 0xe2, 0x22, 0x3d, 0x08, 0x06, - 0x15, 0xfc, 0x2a, 0xf9, 0x41, 0x2d, 0xc4, 0xc1, 0x65, 0x5c, 0x1e, 0xc4, 0xab, 0xb8, 0xac, 0x0f, 0x6e, 0xb3, 0x7a, - 0x79, 0xa0, 0x3b, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x07, 0xc1, 0xa0, 0xd4, 0x53, 0xbb, 0x62, 0x85, 0x77, - 0x9c, 0xe9, 0x10, 0x65, 0x81, 0x1f, 0x20, 0xcc, 0x3b, 0x0d, 0x80, 0x4f, 0x5d, 0xb3, 0x94, 0x5e, 0x62, 0xb8, 0x81, - 0x6a, 0xba, 0x86, 0x3e, 0x00, 0x8f, 0xbc, 0xa6, 0x31, 0x2c, 0x81, 0xcb, 0xc1, 0x80, 0xac, 0x21, 0x72, 0xc1, 0x9a, - 0x9a, 0x20, 0x0e, 0xe1, 0x5a, 0xda, 0x69, 0x17, 0x3b, 0x14, 0x76, 0xbb, 0x05, 0x44, 0xe5, 0x09, 0xe9, 0xf7, 0xcd, - 0x37, 0xd4, 0xbd, 0x60, 0x2f, 0xc1, 0xfe, 0xaa, 0xac, 0xc3, 0x44, 0x48, 0xcd, 0xf7, 0x15, 0x3b, 0x19, 0xc8, 0x88, - 0xc3, 0x3b, 0x8e, 0x14, 0x6d, 0x54, 0x2e, 0xc3, 0x9e, 0x2c, 0x3d, 0x5f, 0x89, 0x6b, 0x6e, 0xfd, 0xb8, 0x6a, 0x21, - 0xf2, 0x3a, 0x5b, 0x49, 0xf6, 0x6f, 0xc6, 0x15, 0xf7, 0x07, 0xd6, 0x9f, 0xfe, 0x2b, 0xb8, 0xb6, 0x3a, 0xef, 0x7c, - 0xae, 0x11, 0x39, 0x4b, 0x28, 0x97, 0x34, 0x26, 0x0f, 0x6f, 0xe9, 0xfb, 0xdc, 0xea, 0xdb, 0x4c, 0xa7, 0xf6, 0x59, - 0x85, 0x85, 0x0b, 0xd1, 0x8a, 0xe0, 0xd0, 0x10, 0x0b, 0xff, 0x08, 0xd0, 0xd7, 0x3e, 0x53, 0x41, 0x49, 0x9a, 0xf3, - 0x1a, 0xbd, 0x5b, 0x21, 0xe1, 0xa5, 0x62, 0x97, 0x1e, 0x06, 0x52, 0xc6, 0xed, 0xa1, 0x24, 0x4c, 0x4a, 0x5e, 0x84, - 0xf7, 0x5e, 0x7d, 0x93, 0x7b, 0x1e, 0x62, 0xf4, 0x22, 0xc7, 0x4e, 0x40, 0x5b, 0x77, 0x89, 0xce, 0x86, 0x27, 0x6e, - 0xc3, 0x73, 0xd6, 0xa2, 0xd1, 0x74, 0xc9, 0x92, 0x7e, 0x3f, 0x06, 0x13, 0xef, 0x94, 0xe5, 0xf0, 0x2b, 0x5f, 0xd0, - 0x35, 0x03, 0x4c, 0x31, 0x7a, 0x09, 0x09, 0x29, 0x22, 0x91, 0xac, 0xe5, 0x49, 0xf2, 0x89, 0xee, 0x42, 0x70, 0x84, - 0xcb, 0x59, 0x1a, 0x2d, 0xf7, 0x9a, 0x59, 0x20, 0x79, 0x86, 0xbe, 0xab, 0x60, 0x7b, 0x63, 0x17, 0xa4, 0x9c, 0x1f, - 0x57, 0xd3, 0xc1, 0x80, 0x13, 0x05, 0x37, 0x5e, 0x48, 0x71, 0xad, 0x6a, 0x71, 0xc7, 0x30, 0x16, 0xea, 0xb6, 0x88, - 0xc1, 0x01, 0xbb, 0x68, 0x65, 0xb7, 0x0f, 0xb0, 0xab, 0x1c, 0xef, 0x52, 0x65, 0x77, 0x7a, 0xcc, 0xf8, 0xcb, 0x56, - 0x91, 0x4e, 0x5a, 0xed, 0x27, 0xf2, 0x3e, 0x77, 0xd0, 0xe5, 0x72, 0xac, 0x78, 0xcb, 0x41, 0x45, 0x1e, 0xf3, 0x91, - 0xa4, 0xba, 0x9f, 0xe1, 0x08, 0xf3, 0x60, 0xdd, 0xfa, 0x93, 0x43, 0x5d, 0xe0, 0x10, 0x79, 0x52, 0xaf, 0x29, 0xa0, - 0x7b, 0xaf, 0x1e, 0x77, 0xf5, 0xdb, 0xd0, 0x5d, 0xa0, 0x44, 0x3b, 0x15, 0x7b, 0x7e, 0x4c, 0xd4, 0xea, 0x4c, 0x3d, - 0xa1, 0x7f, 0xad, 0xc5, 0xfd, 0x85, 0x76, 0x15, 0xf7, 0xbd, 0xcb, 0x67, 0x1c, 0xea, 0xec, 0x86, 0x50, 0x00, 0xae, - 0xda, 0xd1, 0xa9, 0x6b, 0x43, 0x7a, 0xa9, 0x44, 0x37, 0xc1, 0xc1, 0xf6, 0xfa, 0x8c, 0xa3, 0xe8, 0x47, 0xab, 0x91, - 0x6f, 0xa3, 0xea, 0xb1, 0x18, 0xc4, 0x8f, 0x4b, 0xba, 0x8c, 0xaa, 0xc7, 0xe5, 0x20, 0x7e, 0x2c, 0x9a, 0x66, 0xf7, - 0x5c, 0xd9, 0xdf, 0x47, 0xe4, 0x59, 0x77, 0xf6, 0x52, 0x01, 0x1b, 0x03, 0xcf, 0xae, 0x05, 0x84, 0x53, 0x70, 0x44, - 0xb6, 0x86, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x61, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, 0x59, 0xff, 0xe8, - 0xc3, 0x29, 0x10, 0xd0, 0xed, 0xb6, 0x59, 0x57, 0x6b, 0x40, 0x31, 0x0d, 0xc7, 0xfc, 0xb0, 0x1c, 0xdd, 0xba, 0xee, - 0xfa, 0x87, 0xe5, 0x68, 0x49, 0x86, 0x13, 0x3d, 0xf9, 0xf1, 0xc9, 0x78, 0x16, 0x47, 0x93, 0xa6, 0xe3, 0xb4, 0x50, - 0xf8, 0xa7, 0xce, 0x2d, 0x14, 0x81, 0x53, 0x31, 0x82, 0x23, 0xa7, 0xca, 0x49, 0xc9, 0xc3, 0xf0, 0x3f, 0xa8, 0x77, - 0xb4, 0x69, 0xaf, 0xe3, 0x3a, 0x59, 0x66, 0xc5, 0x95, 0x0a, 0x1f, 0xae, 0xa2, 0x8b, 0x9b, 0x80, 0x76, 0xce, 0x65, - 0xda, 0xf2, 0xeb, 0xc4, 0xa3, 0x27, 0xb6, 0x66, 0x06, 0xdc, 0xba, 0x1b, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, - 0xc4, 0xdc, 0xfe, 0x55, 0xda, 0xfc, 0x4a, 0xda, 0x67, 0xc9, 0x48, 0xd1, 0x26, 0x23, 0x35, 0x18, 0x61, 0x8a, 0x22, - 0x89, 0xeb, 0xb0, 0x80, 0x20, 0xd8, 0x9f, 0x51, 0x5c, 0x8b, 0xa5, 0x77, 0x1a, 0x84, 0x09, 0xa6, 0x0b, 0xca, 0xaf, - 0x6e, 0xe7, 0xb6, 0xd2, 0x62, 0x8f, 0xe4, 0xf7, 0xb9, 0xb5, 0x5d, 0x51, 0xe4, 0xef, 0xf3, 0x06, 0xd4, 0x03, 0xa2, - 0xdc, 0xd7, 0x47, 0x29, 0x70, 0xd2, 0xe2, 0x86, 0x02, 0xa3, 0x17, 0x74, 0x75, 0x22, 0x77, 0xec, 0xd4, 0x9c, 0xa9, - 0x98, 0xc9, 0xb8, 0xf2, 0x7e, 0xcf, 0xdc, 0x07, 0x4d, 0x41, 0x2b, 0x30, 0xf0, 0xd6, 0x67, 0x3c, 0x3a, 0xd0, 0xdd, - 0x6a, 0x9d, 0x16, 0x6c, 0x16, 0xd4, 0x65, 0xdd, 0xb6, 0xf1, 0xa0, 0x11, 0x07, 0x45, 0xb2, 0x2a, 0x54, 0x4b, 0x78, - 0x22, 0x10, 0x30, 0x65, 0xd7, 0x3c, 0xd2, 0x82, 0x9a, 0xde, 0x84, 0xc2, 0x86, 0x82, 0xbf, 0x52, 0x54, 0xd3, 0x9b, - 0x50, 0x9f, 0x89, 0x53, 0x0c, 0x22, 0x98, 0x11, 0x9b, 0xfd, 0x16, 0x50, 0x7f, 0x6b, 0x46, 0x9b, 0xa6, 0x31, 0xda, - 0x2a, 0xe4, 0x92, 0x22, 0x69, 0xf9, 0x6f, 0xd5, 0x54, 0x50, 0x52, 0xcb, 0x45, 0x6f, 0xe2, 0xbb, 0xe8, 0xf1, 0x4c, - 0x4b, 0x02, 0xa5, 0x5b, 0xee, 0x18, 0xfd, 0x21, 0x0c, 0xf0, 0x88, 0x8e, 0x13, 0x0b, 0xe6, 0x56, 0x27, 0x2c, 0x9b, - 0x57, 0x8b, 0xd1, 0x4a, 0x40, 0xd8, 0xe0, 0x63, 0x96, 0xcd, 0x0b, 0xf5, 0x10, 0xba, 0xc2, 0xd2, 0xb7, 0x60, 0x17, - 0x1b, 0xac, 0x44, 0x15, 0x80, 0xef, 0x05, 0xdd, 0xac, 0x44, 0x15, 0x09, 0xd9, 0xfd, 0xb8, 0xc1, 0x12, 0x64, 0x5a, - 0x29, 0xd3, 0x92, 0x06, 0x0b, 0x02, 0x5f, 0x55, 0x55, 0x3e, 0x24, 0xdb, 0x0a, 0xe4, 0x53, 0x47, 0x0d, 0x38, 0x05, - 0xb2, 0x0a, 0x2c, 0x48, 0x80, 0xca, 0xd0, 0x56, 0x81, 0x69, 0x25, 0xa6, 0xe9, 0x2a, 0x6c, 0x94, 0xd9, 0xa1, 0xd0, - 0xeb, 0x25, 0x9f, 0xc5, 0x83, 0x30, 0x19, 0xc6, 0xe4, 0x31, 0x42, 0xed, 0x1f, 0xe6, 0x51, 0xac, 0xe4, 0x92, 0x2b, - 0xeb, 0x17, 0x7f, 0xfb, 0x09, 0x7b, 0xdd, 0x73, 0x0c, 0x16, 0x60, 0x2d, 0x6d, 0xaf, 0xb3, 0xe2, 0x9d, 0x68, 0x05, - 0xc7, 0xc1, 0x2c, 0xd2, 0x61, 0xd5, 0x91, 0x23, 0xea, 0x8b, 0x5c, 0x7b, 0x17, 0x21, 0x72, 0x90, 0xde, 0x63, 0x80, - 0xdd, 0x08, 0x5f, 0x87, 0xc6, 0xe6, 0x56, 0x55, 0x88, 0xbf, 0x51, 0x22, 0xf1, 0x93, 0x10, 0x1f, 0xd7, 0x2b, 0x99, - 0xab, 0xd6, 0x78, 0xac, 0xaa, 0x19, 0x3c, 0x53, 0xbe, 0xc7, 0xca, 0xbf, 0xb5, 0xdd, 0x1c, 0xe7, 0x3d, 0x78, 0xd0, - 0xba, 0xdf, 0x3a, 0x12, 0x42, 0x73, 0xe5, 0x24, 0x4d, 0x47, 0x8d, 0x8e, 0x99, 0xac, 0x16, 0x95, 0x30, 0xb9, 0x3b, - 0xa5, 0x63, 0xa0, 0xa2, 0x03, 0xb8, 0x96, 0xa8, 0x0e, 0x7a, 0x52, 0xb2, 0x31, 0x1c, 0x71, 0x06, 0x07, 0xed, 0x38, - 0x46, 0xf1, 0x72, 0x2e, 0xc5, 0xcb, 0xf9, 0x09, 0xe3, 0x00, 0xad, 0x05, 0x48, 0xf5, 0x0a, 0xf6, 0x33, 0x97, 0xb0, - 0xc0, 0xfa, 0xce, 0x77, 0x64, 0x80, 0x0c, 0x71, 0xb2, 0x39, 0x4e, 0xf6, 0xb8, 0x51, 0x73, 0x5f, 0xe1, 0xe3, 0xa4, - 0x59, 0x38, 0x75, 0x15, 0xed, 0xba, 0x96, 0xac, 0x98, 0x97, 0x83, 0x09, 0x04, 0x65, 0x29, 0xe6, 0xe5, 0x70, 0xb2, - 0xa0, 0x39, 0xfc, 0x58, 0x78, 0xe8, 0x10, 0xcb, 0x41, 0x02, 0x97, 0xce, 0x1e, 0x03, 0xde, 0x50, 0x28, 0x71, 0x37, - 0xd6, 0x91, 0x63, 0x1d, 0xe5, 0x61, 0x18, 0x03, 0xae, 0xac, 0x15, 0x78, 0xef, 0xbf, 0x3e, 0xfa, 0x80, 0xac, 0xca, - 0x15, 0x5e, 0x8e, 0x72, 0xd7, 0x95, 0x46, 0x5d, 0x52, 0x7a, 0x95, 0x13, 0x3c, 0x95, 0x6c, 0xb7, 0x3d, 0x63, 0x4f, - 0xe5, 0x20, 0xf1, 0x8e, 0x11, 0xbd, 0x98, 0x7a, 0x99, 0x39, 0x81, 0x33, 0xdb, 0x5e, 0xb6, 0x31, 0x3f, 0x76, 0x80, - 0x83, 0x45, 0x10, 0x12, 0x37, 0x84, 0x61, 0x62, 0x27, 0xc5, 0x50, 0x09, 0xe1, 0xba, 0x16, 0x5e, 0xc7, 0x69, 0x19, - 0x83, 0x8b, 0xb4, 0xb2, 0x4d, 0xdc, 0x43, 0xd7, 0x1d, 0x3f, 0xe6, 0x56, 0xc7, 0x68, 0xcb, 0x7c, 0xb8, 0xa3, 0xd3, - 0x07, 0x16, 0x03, 0x50, 0xf7, 0x60, 0x56, 0xb7, 0xcf, 0x24, 0xae, 0x4f, 0xbb, 0x8a, 0x90, 0x08, 0x44, 0x51, 0x2a, - 0x23, 0x4c, 0xff, 0x4e, 0x73, 0x59, 0x4d, 0xeb, 0x07, 0x79, 0xe6, 0x90, 0x67, 0xa1, 0xb3, 0x3d, 0x68, 0xed, 0xef, - 0x06, 0xed, 0xc4, 0x6d, 0xf7, 0xce, 0xff, 0x5b, 0xd6, 0xb5, 0xd5, 0x9a, 0xea, 0x71, 0xbb, 0xfa, 0x81, 0xb7, 0x57, - 0x7b, 0x32, 0x06, 0xcc, 0x4a, 0x38, 0x67, 0x54, 0xc5, 0xcb, 0x8c, 0x57, 0x78, 0x52, 0xad, 0x3c, 0x1f, 0xef, 0xdb, - 0x6c, 0xa4, 0x1f, 0xc8, 0x14, 0x10, 0xcf, 0x6f, 0x53, 0xad, 0x3e, 0x4e, 0x51, 0x02, 0xfe, 0x4e, 0xc5, 0x37, 0xa2, - 0x1f, 0xcd, 0x8b, 0x2b, 0x5e, 0xbf, 0xbd, 0x2d, 0xf4, 0x8b, 0xe7, 0x46, 0xe7, 0x4f, 0x5f, 0x97, 0x2e, 0x74, 0x38, - 0x6a, 0xef, 0xa0, 0xc8, 0x82, 0x55, 0x27, 0x13, 0x2d, 0x6b, 0xab, 0x66, 0x1f, 0x25, 0x5c, 0x4c, 0x54, 0xa3, 0x67, - 0x9d, 0x39, 0x61, 0x4a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x96, 0x0c, 0xd4, 0x69, 0x52, 0x88, 0x1e, 0x56, 0x33, - 0x8c, 0x57, 0x0c, 0xa0, 0x30, 0xa5, 0x04, 0x51, 0xb4, 0x06, 0xc1, 0x40, 0x13, 0xfa, 0xfd, 0xdb, 0x54, 0x65, 0xa0, - 0x45, 0x33, 0x15, 0x20, 0xaa, 0x83, 0x68, 0xab, 0xbc, 0x0c, 0x7f, 0x5c, 0xd2, 0x22, 0xa3, 0x79, 0x45, 0x97, 0x15, - 0x4d, 0x32, 0x7a, 0xc9, 0xa5, 0xa8, 0x78, 0x5d, 0x31, 0x49, 0xdb, 0x35, 0x61, 0xff, 0x97, 0x47, 0xd7, 0x5b, 0xb1, - 0xd6, 0xd0, 0xee, 0x04, 0x19, 0xa1, 0xf9, 0x42, 0x05, 0x21, 0x43, 0xe5, 0x24, 0x74, 0xad, 0x56, 0x78, 0x05, 0x36, - 0x99, 0x66, 0xa3, 0x65, 0x5c, 0x85, 0x81, 0xf9, 0x2a, 0x30, 0x98, 0x1c, 0x98, 0x74, 0xb6, 0xbe, 0x78, 0x26, 0xae, - 0x57, 0xa2, 0xe0, 0x45, 0x2d, 0x21, 0xfa, 0x35, 0xee, 0xbb, 0x8e, 0xab, 0xce, 0xfc, 0x5a, 0xe9, 0x43, 0xdf, 0xba, - 0xac, 0x8d, 0xfd, 0x42, 0xe3, 0x18, 0xec, 0x7c, 0x44, 0x34, 0xa4, 0x41, 0xad, 0x5a, 0x1c, 0xea, 0x00, 0x5d, 0x2a, - 0xa4, 0x90, 0x21, 0x53, 0x99, 0x2c, 0x41, 0xc6, 0x37, 0x7e, 0x2f, 0x44, 0x3d, 0xfa, 0x73, 0xcd, 0xcb, 0xfb, 0x33, - 0x9e, 0x73, 0x1c, 0xa3, 0x20, 0x89, 0x8b, 0x9b, 0xb8, 0x0a, 0x88, 0x6b, 0x79, 0x15, 0x1c, 0xa5, 0x3a, 0x6c, 0xcc, - 0x4e, 0xd5, 0xa8, 0xf5, 0x12, 0xe8, 0x2b, 0x23, 0x7d, 0x63, 0x30, 0x34, 0x11, 0x95, 0xd0, 0xf7, 0x4a, 0xdd, 0xd3, - 0xea, 0x86, 0x01, 0xc4, 0x9f, 0x4b, 0xbd, 0x50, 0xeb, 0xb5, 0x1f, 0x73, 0x43, 0x47, 0x08, 0x1a, 0x7d, 0xd5, 0x2c, - 0x1a, 0xc7, 0x2d, 0x4d, 0x46, 0xc6, 0x8d, 0x36, 0x39, 0xbf, 0x02, 0x19, 0x9f, 0x35, 0x17, 0x9a, 0x34, 0x0d, 0x95, - 0x50, 0x85, 0xd1, 0xe6, 0xce, 0x4b, 0xa7, 0xf7, 0xe0, 0xce, 0xa6, 0xcd, 0x8e, 0x94, 0x4b, 0x63, 0x43, 0x4b, 0x5e, - 0xad, 0x44, 0x51, 0x41, 0x18, 0xe7, 0xde, 0x98, 0x5e, 0xc7, 0x59, 0x51, 0xc7, 0x59, 0x71, 0x5a, 0xad, 0x78, 0x52, - 0xbf, 0x87, 0x5b, 0x9c, 0xb4, 0xba, 0x69, 0x2a, 0xb8, 0xd2, 0x25, 0x07, 0x18, 0x4c, 0x4d, 0xc6, 0x3d, 0xb6, 0x06, - 0x17, 0xf5, 0xef, 0xd1, 0x52, 0x60, 0x2c, 0x54, 0x55, 0x7c, 0x7c, 0x51, 0x89, 0x7c, 0x5d, 0x83, 0x76, 0xf7, 0xb2, - 0x8e, 0x8e, 0x9e, 0xac, 0xee, 0xa6, 0xf2, 0x06, 0x13, 0x3d, 0x39, 0x5a, 0xdd, 0xf5, 0xb2, 0xeb, 0x95, 0x28, 0xeb, - 0xb8, 0xa8, 0xa7, 0x12, 0x91, 0x2c, 0x89, 0xf3, 0x24, 0x9c, 0x8c, 0xc7, 0x5f, 0x1c, 0x0c, 0x0f, 0x20, 0x03, 0x99, - 0xfe, 0x35, 0x94, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x15, 0xf2, 0x6e, 0x17, 0x8d, 0x26, 0x0d, 0xd6, 0x33, 0x4c, - 0xd4, 0xcc, 0x8c, 0xf8, 0xdd, 0x2a, 0x2e, 0x52, 0x88, 0x5f, 0xa7, 0x8a, 0x3f, 0x7a, 0x32, 0xf6, 0xca, 0x37, 0x9f, - 0x3e, 0x6d, 0x7e, 0x6f, 0x74, 0x58, 0x6b, 0xdd, 0xee, 0x67, 0xbf, 0x1f, 0xcb, 0xf9, 0x3e, 0x39, 0x3e, 0x54, 0x3f, - 0x7e, 0x6f, 0x9a, 0xe9, 0xeb, 0x32, 0x9c, 0xff, 0x33, 0x94, 0xf3, 0x79, 0x5a, 0x96, 0xf1, 0x7d, 0x43, 0x16, 0x74, - 0x5d, 0x59, 0x6f, 0x12, 0xea, 0x6c, 0x03, 0x7a, 0x44, 0xa6, 0xeb, 0x8a, 0xc1, 0x37, 0xef, 0xeb, 0x30, 0xe0, 0xd5, - 0x6a, 0xc8, 0x8b, 0x3a, 0xab, 0xef, 0x87, 0x98, 0x27, 0xc0, 0x4f, 0x35, 0x6f, 0xf6, 0xac, 0xd4, 0xc4, 0xe6, 0xb2, - 0xe4, 0xfc, 0x2f, 0x1e, 0x4a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1c, 0x8c, 0xc9, 0xd7, 0x54, 0x75, 0x66, - 0xf2, 0x35, 0x98, 0x20, 0x65, 0xed, 0x6f, 0xa4, 0x71, 0x62, 0x34, 0xa6, 0x37, 0x2f, 0xf3, 0x6c, 0x05, 0x4c, 0xf0, - 0x52, 0xfd, 0x68, 0x08, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xb3, 0x92, 0x8e, 0x46, 0xa3, 0x8f, 0x59, 0x43, - 0xe8, 0x65, 0xd5, 0xf1, 0xfe, 0x3d, 0xa7, 0x17, 0x22, 0xbd, 0x8f, 0x82, 0x80, 0x2e, 0xb3, 0x34, 0xe5, 0x85, 0x2c, - 0xeb, 0x2c, 0x6d, 0xe7, 0x95, 0x2d, 0x44, 0xe0, 0x1f, 0xd5, 0x46, 0x84, 0x20, 0x22, 0xf4, 0xed, 0x4e, 0xcf, 0x46, - 0xa3, 0xd1, 0x59, 0xaa, 0xab, 0xb5, 0x0c, 0xf9, 0x6b, 0x34, 0x1f, 0xb0, 0x76, 0xf9, 0x60, 0x7d, 0xa3, 0xa3, 0x9d, - 0x1c, 0xfe, 0xf7, 0x70, 0x36, 0x1f, 0x0f, 0xbf, 0x1d, 0x2d, 0x1e, 0x1f, 0xd2, 0x20, 0x70, 0x41, 0xab, 0x43, 0x65, - 0xcd, 0x31, 0x2d, 0x8e, 0xc7, 0x53, 0x52, 0x0c, 0xd8, 0x13, 0xe3, 0x4b, 0xf3, 0xc5, 0x13, 0x40, 0x22, 0x45, 0x11, - 0x6a, 0x60, 0xa5, 0x7f, 0x78, 0x15, 0x79, 0x55, 0x00, 0x3e, 0x9a, 0x89, 0x64, 0xa0, 0xb5, 0x80, 0xe3, 0x08, 0xca, - 0x6b, 0x8c, 0x69, 0x44, 0x8f, 0xb1, 0x4c, 0x47, 0x05, 0x1d, 0x4f, 0xab, 0xdb, 0xac, 0x4e, 0x96, 0x18, 0xd8, 0x28, - 0xae, 0x78, 0xf0, 0x45, 0x10, 0x15, 0xec, 0xe8, 0xe9, 0x54, 0xc2, 0xfb, 0x62, 0x52, 0xca, 0xaf, 0x20, 0xf1, 0xdb, - 0x31, 0x42, 0xa0, 0x12, 0xe5, 0xb1, 0x88, 0x35, 0xbe, 0xcc, 0x45, 0x0c, 0x1e, 0x9c, 0x95, 0xe2, 0x59, 0xcc, 0x49, - 0x60, 0xec, 0x2f, 0x5a, 0xcd, 0x11, 0xd0, 0x9c, 0x50, 0x30, 0x71, 0x58, 0x50, 0xf1, 0xc5, 0x04, 0xbd, 0x82, 0xc0, - 0xad, 0x3a, 0x82, 0xe3, 0xce, 0x58, 0x36, 0xa8, 0xe5, 0x93, 0xb2, 0xc3, 0xf9, 0xff, 0xae, 0xe8, 0x62, 0x70, 0x68, - 0x87, 0xe6, 0xad, 0x72, 0x5f, 0xad, 0x91, 0x51, 0xaa, 0xc3, 0x67, 0x29, 0x31, 0xc6, 0xa7, 0x9c, 0x9d, 0x6c, 0x74, - 0x77, 0x46, 0x75, 0x99, 0x5d, 0x87, 0x44, 0xf5, 0xca, 0x82, 0x62, 0x06, 0x51, 0x36, 0xc2, 0xf5, 0x03, 0xd6, 0x22, - 0x4e, 0x27, 0x6f, 0x78, 0x59, 0x67, 0x89, 0x7c, 0x7f, 0xe3, 0xbd, 0x07, 0x6a, 0x20, 0x1b, 0xf4, 0xae, 0x64, 0x30, - 0xcf, 0x6f, 0x4b, 0x00, 0xed, 0xac, 0x78, 0x79, 0xc3, 0x5d, 0xba, 0x11, 0x04, 0x8d, 0x6d, 0xe6, 0x95, 0x17, 0x6c, - 0x02, 0xbe, 0x7a, 0x57, 0x02, 0xe6, 0x46, 0x08, 0x52, 0x53, 0x08, 0x85, 0x03, 0x17, 0xf8, 0xba, 0x2e, 0xb3, 0x8b, - 0x75, 0xcd, 0x31, 0xd8, 0x47, 0x61, 0xb5, 0x98, 0xd2, 0x09, 0x8f, 0x87, 0x01, 0xfe, 0x08, 0xa8, 0x0c, 0xb8, 0xa1, - 0x3d, 0xec, 0xe0, 0x85, 0xfc, 0x65, 0xdf, 0xc8, 0x3d, 0xc2, 0x5e, 0xa7, 0x21, 0x04, 0xd7, 0xc1, 0x87, 0x00, 0x96, - 0x14, 0xa1, 0x6f, 0xf1, 0x54, 0x0d, 0x83, 0xcb, 0x3c, 0x5b, 0xa9, 0xa4, 0x7a, 0xd4, 0xd1, 0x7c, 0x28, 0xb5, 0x23, - 0x39, 0xa0, 0x4e, 0x7a, 0x8c, 0xe9, 0xa5, 0x4c, 0x97, 0x45, 0x59, 0x23, 0x94, 0x77, 0x6a, 0x62, 0x6c, 0x98, 0x3e, - 0x0e, 0x91, 0x5f, 0xde, 0x95, 0x32, 0xf4, 0x0b, 0x5f, 0x00, 0xf8, 0x15, 0xdc, 0xee, 0x77, 0xe3, 0xbb, 0xc8, 0xec, - 0xe7, 0x9c, 0x1d, 0xfe, 0xf7, 0x3c, 0x1e, 0xfe, 0x35, 0x1e, 0x7e, 0xbb, 0x18, 0x84, 0x43, 0xf3, 0x93, 0x3c, 0x7e, - 0x74, 0x48, 0x5f, 0x72, 0xc3, 0x95, 0xc0, 0xc2, 0xf7, 0x82, 0xdb, 0xc8, 0x95, 0x10, 0x44, 0x01, 0xde, 0x28, 0xec, - 0x6a, 0x9c, 0x00, 0xc0, 0x5f, 0xf0, 0x5f, 0x01, 0x1a, 0x09, 0xd9, 0x8b, 0x06, 0xe8, 0x07, 0xe4, 0xef, 0x93, 0xaf, - 0x3c, 0x03, 0x39, 0x10, 0x4f, 0xc8, 0x18, 0x28, 0x44, 0x95, 0x31, 0x91, 0xb0, 0xbf, 0x26, 0xfb, 0x76, 0xdb, 0x6b, - 0x4b, 0x7e, 0xf0, 0x4b, 0x37, 0xd3, 0x44, 0xcf, 0x3b, 0xdc, 0x50, 0x56, 0x62, 0x15, 0x22, 0x36, 0x9e, 0xfa, 0x95, - 0x33, 0x88, 0x35, 0x79, 0x93, 0x81, 0x0f, 0x83, 0xf9, 0x62, 0x3c, 0x03, 0x69, 0x11, 0xdc, 0x71, 0x4a, 0x7e, 0x99, - 0x81, 0x5b, 0x73, 0x11, 0xe3, 0x05, 0xdb, 0x2c, 0x89, 0x7e, 0xbf, 0x97, 0x67, 0x61, 0xae, 0x70, 0x96, 0xf3, 0x46, - 0x8b, 0xdd, 0x51, 0x27, 0x0c, 0xe2, 0x76, 0x35, 0x04, 0x43, 0x39, 0x04, 0x65, 0x47, 0x5b, 0x6c, 0xbd, 0xa6, 0x9e, - 0x52, 0xf7, 0x56, 0xd6, 0x57, 0x8e, 0xfe, 0x10, 0x59, 0x81, 0x85, 0xb4, 0x6b, 0x8e, 0x55, 0xcd, 0x31, 0xd2, 0x9e, - 0x7e, 0xbf, 0xf2, 0xc8, 0x4f, 0x67, 0xe1, 0x41, 0x20, 0x4b, 0x15, 0x3b, 0x65, 0x51, 0x6e, 0x4a, 0x73, 0xc6, 0xb0, - 0xa1, 0x79, 0x66, 0xe2, 0xba, 0xcc, 0x7a, 0xbd, 0x30, 0x44, 0x87, 0x46, 0x2c, 0x15, 0x6b, 0x83, 0xf0, 0x3e, 0x3a, - 0x61, 0x74, 0x0d, 0xb2, 0xba, 0xf0, 0x9c, 0x13, 0xe4, 0xcb, 0xc0, 0x64, 0x4d, 0x56, 0xeb, 0xe4, 0x84, 0x47, 0x2f, - 0x5f, 0x36, 0x82, 0x06, 0x39, 0x49, 0x51, 0x6f, 0x62, 0x77, 0xec, 0xa3, 0x16, 0x52, 0xe3, 0xa6, 0x99, 0xf6, 0x14, - 0xa9, 0xe8, 0xb1, 0x5e, 0x2d, 0x7f, 0x81, 0x65, 0x81, 0x21, 0x1f, 0x84, 0xf6, 0x14, 0xad, 0xc0, 0x0c, 0x37, 0x26, - 0x83, 0xa6, 0x1f, 0x16, 0x6d, 0x11, 0x3a, 0x23, 0xb7, 0x25, 0x84, 0x6d, 0x1b, 0x84, 0xb5, 0xf3, 0x44, 0xbe, 0x78, - 0xe2, 0x30, 0xc2, 0x21, 0xd7, 0x9b, 0xb9, 0xf2, 0x30, 0xcc, 0xaf, 0x85, 0xdf, 0x3c, 0xd5, 0x5c, 0x27, 0x2a, 0x66, - 0x05, 0xdb, 0xed, 0xb2, 0x22, 0xf8, 0xf7, 0x63, 0x36, 0xc3, 0xbf, 0x59, 0xbf, 0xdf, 0x0b, 0xf1, 0x17, 0xc7, 0xe0, - 0x3d, 0xf3, 0x6a, 0xc1, 0x3e, 0x82, 0x4c, 0x85, 0x44, 0x98, 0x2a, 0x8d, 0xdf, 0x58, 0x0d, 0x16, 0x70, 0xfa, 0x03, - 0x99, 0x0b, 0x33, 0x99, 0xcb, 0x8b, 0x6d, 0xc8, 0x69, 0x6b, 0x9c, 0xb2, 0x51, 0x96, 0x48, 0xd7, 0x85, 0x6c, 0x14, - 0xe7, 0x59, 0x5c, 0xf1, 0x6a, 0xbb, 0x55, 0x87, 0x63, 0x52, 0x72, 0xf4, 0x2b, 0x40, 0x2a, 0x55, 0xb0, 0x8e, 0x54, - 0x3b, 0xfe, 0x22, 0x2c, 0x71, 0x9f, 0xf2, 0x79, 0xb9, 0x30, 0x7b, 0x6b, 0x5e, 0x2e, 0x98, 0xbc, 0x95, 0xf6, 0xc2, - 0x12, 0x9a, 0x57, 0x10, 0xb2, 0xc1, 0x54, 0xc7, 0xa2, 0x35, 0x66, 0xd5, 0xbc, 0x5c, 0x40, 0x18, 0x99, 0x72, 0x01, - 0x36, 0x53, 0xbc, 0x00, 0x2f, 0x92, 0x18, 0x60, 0xe2, 0x62, 0x32, 0x85, 0x78, 0xe6, 0xb2, 0x9c, 0x78, 0xa1, 0xef, - 0x97, 0x89, 0x45, 0xca, 0x80, 0x57, 0x8d, 0x46, 0x13, 0x33, 0x0d, 0x47, 0x9d, 0x20, 0x27, 0x3a, 0xbf, 0x9b, 0x5a, - 0x11, 0x62, 0x4f, 0x1c, 0x01, 0x97, 0x15, 0xd3, 0x85, 0x17, 0x1d, 0x88, 0x31, 0x72, 0x70, 0x8a, 0x4f, 0x0c, 0x8e, - 0xc2, 0xe0, 0xdc, 0x38, 0x27, 0x48, 0x19, 0xc6, 0x64, 0x23, 0xd8, 0xb5, 0x08, 0xab, 0x79, 0xbc, 0x00, 0x65, 0x5d, - 0xbc, 0x00, 0xcb, 0x1a, 0x6d, 0x80, 0x09, 0xf2, 0x2a, 0xee, 0x84, 0x7e, 0xa2, 0xb8, 0x42, 0x84, 0x63, 0xe5, 0xfa, - 0xa8, 0x6c, 0x87, 0xbe, 0xc0, 0xeb, 0xbd, 0x34, 0xc7, 0xcd, 0x7a, 0x2c, 0x10, 0xd8, 0x10, 0x30, 0x36, 0x52, 0x69, - 0xb2, 0xb5, 0xf6, 0x8d, 0x9e, 0x07, 0x3e, 0xcd, 0x46, 0x85, 0xa8, 0xcf, 0x2f, 0x41, 0x84, 0xe2, 0xa2, 0xc1, 0x23, - 0xbf, 0x88, 0x3b, 0x4b, 0xbf, 0x35, 0x2d, 0x2a, 0xd8, 0xc9, 0x06, 0x40, 0xfa, 0x54, 0xb4, 0x28, 0x29, 0xa7, 0x28, - 0x48, 0x63, 0x37, 0x05, 0xac, 0x24, 0x77, 0x01, 0x43, 0xb0, 0xb1, 0x83, 0xca, 0xea, 0x14, 0x11, 0x49, 0x02, 0x91, - 0x15, 0xc3, 0x82, 0xe2, 0xd8, 0x16, 0x88, 0xfa, 0x69, 0xca, 0x32, 0x83, 0xa1, 0xa3, 0xe2, 0x3e, 0x4f, 0x1d, 0x4a, - 0x14, 0x04, 0x54, 0x0d, 0x39, 0x48, 0x6c, 0x4d, 0x03, 0xe1, 0x01, 0x79, 0x44, 0x67, 0xac, 0xbf, 0xcf, 0x3a, 0xcf, - 0x2e, 0x34, 0x47, 0xe5, 0x6a, 0x57, 0xe8, 0x31, 0xc2, 0x93, 0x4c, 0xc3, 0xe4, 0x3b, 0xe7, 0x99, 0x56, 0x53, 0xf4, - 0x1c, 0x7c, 0xb2, 0x53, 0x8c, 0x48, 0xb7, 0x67, 0xd0, 0x75, 0xf0, 0xaa, 0x0e, 0x1b, 0xed, 0x5a, 0x42, 0x48, 0xe8, - 0x5a, 0x14, 0x31, 0xeb, 0x19, 0x03, 0xea, 0xed, 0xb6, 0xa7, 0xe6, 0x6a, 0xff, 0xdc, 0x6d, 0xb7, 0x3d, 0xec, 0xd6, - 0xf3, 0xb4, 0xdb, 0x0a, 0xbc, 0x96, 0x1f, 0xb4, 0xc7, 0x9f, 0xdb, 0xf1, 0xe7, 0x1a, 0xc9, 0xa3, 0xb0, 0x34, 0xd3, - 0xd4, 0x07, 0xe1, 0x70, 0xd3, 0x7b, 0xaf, 0x49, 0xdf, 0x67, 0xa1, 0xa0, 0x97, 0x95, 0x57, 0x5d, 0x63, 0x4d, 0x2a, - 0x1f, 0x5c, 0xff, 0x0f, 0xaf, 0x02, 0x3c, 0xe2, 0xe4, 0xce, 0xde, 0xdb, 0xa0, 0xd2, 0x6b, 0x0b, 0x47, 0x8a, 0xd0, - 0x03, 0x92, 0xb0, 0xaf, 0x65, 0x2d, 0x6e, 0xf3, 0x2c, 0x7b, 0x98, 0x3e, 0xbd, 0x4a, 0x5d, 0xab, 0x7b, 0xbb, 0xcc, - 0x32, 0x7d, 0xe0, 0xd5, 0x14, 0x07, 0x34, 0xea, 0xa2, 0x7d, 0xd7, 0x59, 0x55, 0x81, 0x97, 0x07, 0x5c, 0x9f, 0xcf, - 0xb8, 0x0b, 0x37, 0x77, 0x55, 0xfb, 0x9b, 0xf4, 0x2c, 0x9b, 0x67, 0x8b, 0xed, 0x36, 0xc4, 0xbf, 0x5d, 0x2d, 0xb2, - 0x34, 0x79, 0x0e, 0x3a, 0x3c, 0x8c, 0xdc, 0xc3, 0x54, 0xe3, 0x9c, 0xcd, 0xff, 0xb2, 0xf2, 0x9c, 0x04, 0x4e, 0x81, - 0x5e, 0xcc, 0x1e, 0x81, 0x0c, 0x46, 0x3b, 0xf5, 0x57, 0x33, 0xb5, 0x66, 0x20, 0xfa, 0x56, 0x15, 0x01, 0x8e, 0x2e, - 0x36, 0x12, 0x8d, 0x2c, 0x38, 0x69, 0x08, 0x58, 0x6c, 0x9a, 0xf2, 0x3e, 0x18, 0xda, 0x56, 0x97, 0xf7, 0xce, 0x92, - 0xe6, 0xb8, 0x0e, 0xac, 0x6d, 0xbf, 0x1e, 0x62, 0x5d, 0x76, 0xbd, 0x40, 0xee, 0x97, 0x37, 0xb4, 0x37, 0x6e, 0x12, - 0x98, 0xb5, 0x4d, 0x63, 0x18, 0x3f, 0x53, 0xfa, 0x4f, 0x6a, 0x70, 0xa5, 0xf1, 0xd3, 0x5c, 0x5b, 0x25, 0x98, 0x7d, - 0xe3, 0xf8, 0x0e, 0x40, 0x38, 0x36, 0x97, 0x1e, 0x9f, 0x65, 0x0e, 0x3d, 0x06, 0xa2, 0xa3, 0x3f, 0x2a, 0xec, 0x47, - 0x66, 0xf7, 0xba, 0x01, 0xf0, 0xe6, 0x75, 0xbb, 0xa0, 0x79, 0xb1, 0x80, 0x40, 0xa2, 0x4e, 0x79, 0xa5, 0xe1, 0x33, - 0x63, 0x76, 0x05, 0x64, 0xa8, 0x24, 0x60, 0x93, 0xd4, 0x75, 0x2e, 0xc4, 0xb2, 0xc3, 0xd2, 0x7c, 0x24, 0x61, 0x27, - 0x21, 0xa0, 0xbd, 0x06, 0xc1, 0x2c, 0xf8, 0xaf, 0x60, 0x50, 0x0c, 0x82, 0x28, 0x88, 0x82, 0x80, 0x0c, 0x4a, 0xf8, - 0x85, 0x38, 0x63, 0x04, 0x63, 0x94, 0x40, 0x87, 0xdf, 0x71, 0xe6, 0x32, 0x22, 0x2f, 0xbc, 0x30, 0x96, 0x76, 0x00, - 0x2e, 0x84, 0xc8, 0x79, 0x8c, 0x3e, 0x16, 0xef, 0x38, 0xcb, 0x08, 0x7d, 0xe7, 0x9c, 0xca, 0x8f, 0xb8, 0x17, 0xdc, - 0x6e, 0x77, 0xd8, 0x5e, 0xf2, 0x30, 0xa3, 0xbd, 0x31, 0x7d, 0xc7, 0x49, 0x94, 0x79, 0xce, 0xc3, 0x1c, 0x7a, 0x56, - 0x1b, 0xd6, 0x8a, 0x6a, 0x72, 0x83, 0x62, 0x5d, 0x64, 0x99, 0xac, 0x0c, 0x57, 0xce, 0x69, 0x85, 0xeb, 0xce, 0xac, - 0x17, 0x90, 0x94, 0x55, 0x8a, 0xa5, 0x33, 0xe1, 0xab, 0x4d, 0xcb, 0x9e, 0xb7, 0x4e, 0x21, 0xa7, 0x21, 0x32, 0xfa, - 0xa1, 0x25, 0xa0, 0x9a, 0x56, 0x5c, 0xd5, 0xe0, 0xb2, 0xab, 0xdb, 0xc3, 0x75, 0x7b, 0x74, 0x33, 0x3e, 0x40, 0x8c, - 0x38, 0x8e, 0x2d, 0x03, 0xbb, 0x09, 0x8b, 0x67, 0x63, 0x7d, 0x5f, 0x76, 0xe9, 0xad, 0xad, 0xc5, 0x21, 0xac, 0x3d, - 0x67, 0x85, 0x84, 0x00, 0x69, 0xa9, 0x2b, 0xdd, 0x6e, 0x83, 0x00, 0x06, 0xb8, 0xdf, 0xef, 0x01, 0xd7, 0xaa, 0xd9, - 0x49, 0x7d, 0x6b, 0x36, 0xc4, 0x5e, 0x52, 0x78, 0x0c, 0x44, 0xa9, 0xf8, 0xcf, 0x20, 0xa0, 0x78, 0xee, 0x86, 0x60, - 0x5f, 0xc9, 0x4e, 0x36, 0x65, 0xbf, 0xff, 0xbc, 0xc4, 0x07, 0x94, 0x83, 0x82, 0x58, 0x57, 0xc5, 0xad, 0xd0, 0xec, - 0x93, 0xfc, 0x10, 0xc7, 0x22, 0xcf, 0x42, 0x4b, 0x58, 0x6a, 0x4d, 0x58, 0xb8, 0x64, 0xa4, 0x83, 0x38, 0x68, 0x48, - 0xe7, 0x60, 0xd5, 0x36, 0xd8, 0x70, 0xaf, 0xf7, 0xb2, 0x0a, 0x2b, 0x9a, 0x39, 0xc3, 0xf2, 0xde, 0x01, 0x00, 0xeb, - 0xf5, 0x70, 0xa1, 0x38, 0x64, 0xc2, 0x43, 0x9f, 0xc4, 0x97, 0x86, 0x5d, 0x9f, 0x29, 0x59, 0xc9, 0x68, 0x34, 0xaa, - 0x1b, 0x29, 0xf9, 0x30, 0xdf, 0xbd, 0x69, 0xa1, 0x56, 0x8a, 0x38, 0xe5, 0x29, 0x58, 0x7a, 0x6b, 0x4a, 0x37, 0x5f, - 0xd0, 0x15, 0x2f, 0x52, 0xf9, 0xd3, 0x41, 0x9b, 0xf4, 0x88, 0x6b, 0xe6, 0xeb, 0x2c, 0xcc, 0xf0, 0x43, 0xc0, 0x47, - 0xf3, 0x30, 0xb3, 0xe9, 0x0a, 0x96, 0x16, 0xc4, 0x91, 0x71, 0xc9, 0x43, 0x9b, 0x07, 0xb0, 0xfe, 0xf4, 0x21, 0x89, - 0x9f, 0xc2, 0xcf, 0x99, 0x4e, 0xeb, 0xf8, 0x0c, 0x67, 0x33, 0x2a, 0xe4, 0x8d, 0xa0, 0xfd, 0x1a, 0x12, 0x89, 0x46, - 0x36, 0xf6, 0x18, 0x8a, 0xd6, 0xdd, 0x06, 0xae, 0xfc, 0x86, 0xde, 0xb9, 0x34, 0x08, 0xb0, 0xad, 0xb1, 0x18, 0x38, - 0xe3, 0xf1, 0x07, 0xaa, 0x6a, 0xf4, 0x15, 0x45, 0x37, 0x4c, 0x26, 0x9a, 0x3b, 0x8e, 0xed, 0xa8, 0x76, 0x95, 0xad, - 0x58, 0x61, 0x6c, 0x79, 0xed, 0x5b, 0x5a, 0x9a, 0x12, 0x50, 0x0d, 0x86, 0x3b, 0x01, 0x7c, 0x46, 0x84, 0x3c, 0x10, - 0x44, 0xf7, 0xc1, 0x41, 0x73, 0x96, 0xe0, 0x79, 0x18, 0xc2, 0x1f, 0x58, 0x38, 0xb0, 0x2c, 0x65, 0x3f, 0x97, 0xd3, - 0x18, 0xce, 0xdd, 0x5c, 0xee, 0xf0, 0xd9, 0x12, 0x14, 0x79, 0x72, 0x4e, 0xf5, 0xe5, 0x2b, 0xf7, 0xf6, 0x7b, 0x4c, - 0x30, 0x8f, 0x9e, 0x6d, 0xf8, 0xad, 0xa6, 0xdb, 0xf8, 0xc2, 0xda, 0x81, 0x13, 0xe6, 0xc2, 0x69, 0x2e, 0xb6, 0x4b, - 0x0d, 0x71, 0xd7, 0x78, 0x42, 0x84, 0x57, 0x8a, 0x58, 0x64, 0x9e, 0x4c, 0xc7, 0x60, 0x63, 0xc8, 0x36, 0x95, 0xcf, - 0x94, 0x42, 0xbc, 0x9a, 0xca, 0x0b, 0x53, 0x2b, 0x95, 0x55, 0x1a, 0x61, 0xa6, 0x80, 0x45, 0x95, 0x81, 0xcf, 0x7e, - 0x8d, 0x14, 0xd7, 0xd4, 0xf3, 0x17, 0x2e, 0xdf, 0x4c, 0xb7, 0xd9, 0x7c, 0xfa, 0x32, 0x8f, 0xaf, 0xb6, 0xdb, 0xb0, - 0xfb, 0x05, 0x98, 0x5f, 0x56, 0x52, 0xa3, 0x06, 0x4e, 0x0f, 0x21, 0xfa, 0x39, 0xef, 0xc9, 0x39, 0xb1, 0x9c, 0x5c, - 0xbb, 0x79, 0xb3, 0x9d, 0x14, 0x2d, 0xb0, 0x80, 0x13, 0x17, 0xe9, 0x40, 0x4b, 0x05, 0xa7, 0x2c, 0xe3, 0x9d, 0x4d, - 0x6f, 0x29, 0x15, 0x5e, 0x2d, 0x14, 0x09, 0xa9, 0xed, 0xbd, 0xc4, 0x8c, 0x1a, 0x70, 0x4e, 0xf2, 0x0e, 0x02, 0x4e, - 0x6a, 0xaa, 0xb1, 0x46, 0x71, 0xaa, 0x13, 0x9c, 0x57, 0x6a, 0xe8, 0x12, 0xe5, 0xc4, 0x6d, 0xb7, 0x55, 0xd1, 0x42, - 0x7d, 0x3c, 0xc8, 0x59, 0x22, 0x8f, 0x07, 0x14, 0xba, 0xc8, 0xa3, 0x21, 0x5f, 0x90, 0x52, 0xad, 0x1c, 0xa5, 0x5a, - 0xdd, 0x95, 0x0c, 0x14, 0x72, 0x15, 0xe4, 0x0d, 0x31, 0xee, 0x5a, 0x99, 0xb7, 0xb8, 0x72, 0x42, 0x4a, 0x93, 0xf0, - 0xb9, 0xa5, 0x18, 0x58, 0xc1, 0xde, 0x98, 0xba, 0xc2, 0x25, 0x42, 0xdb, 0xdd, 0x86, 0x98, 0x64, 0xb0, 0x6e, 0xb6, - 0xdb, 0x57, 0x65, 0x38, 0xcf, 0x16, 0x54, 0x8c, 0xb2, 0x14, 0x21, 0xc4, 0xb4, 0x87, 0xae, 0xe9, 0x82, 0x9e, 0x18, - 0x6a, 0xdb, 0xe3, 0x24, 0xe9, 0x62, 0x4d, 0x92, 0x18, 0xc5, 0x17, 0xa2, 0x94, 0x6b, 0x8d, 0x10, 0x3c, 0xdc, 0xff, - 0x48, 0x21, 0x86, 0x9b, 0x5e, 0x77, 0xbf, 0xee, 0xdc, 0x10, 0xff, 0x80, 0x40, 0x02, 0x05, 0x7b, 0x55, 0x8e, 0x2e, - 0xb2, 0x22, 0xc5, 0x9d, 0x2a, 0xa3, 0xe2, 0xca, 0x75, 0xe0, 0xb7, 0xdc, 0xf0, 0xaf, 0x86, 0x28, 0x40, 0x5c, 0xe3, - 0x4a, 0x31, 0x9e, 0xb5, 0xb5, 0x14, 0xc9, 0x28, 0x36, 0x24, 0x2a, 0x9c, 0xa8, 0xe8, 0x2e, 0x4f, 0xa3, 0x7b, 0x68, - 0xd7, 0x20, 0xb8, 0x6a, 0xee, 0x6c, 0xa4, 0xf9, 0x82, 0x10, 0x39, 0x01, 0x02, 0x36, 0xaa, 0x3e, 0xb5, 0x56, 0xd5, - 0xc3, 0xac, 0xf2, 0xb9, 0x3a, 0x88, 0x57, 0x15, 0xf0, 0xb0, 0xce, 0xf6, 0xbe, 0xaa, 0x1c, 0xd6, 0x06, 0xdf, 0x6e, - 0xb7, 0xab, 0x6a, 0x1e, 0x04, 0x0e, 0xa3, 0xf9, 0x9d, 0x94, 0x98, 0xf7, 0xc6, 0x14, 0x56, 0xbc, 0xeb, 0xd2, 0xd6, - 0x4d, 0x6a, 0x8d, 0x05, 0xea, 0x0e, 0xd7, 0x07, 0x3c, 0x4f, 0x81, 0xa3, 0x1d, 0x15, 0x53, 0x61, 0x74, 0xe5, 0xd8, - 0x95, 0x0a, 0x03, 0x43, 0xff, 0x90, 0xb2, 0x0d, 0x98, 0xe3, 0x81, 0xb5, 0x0d, 0xfa, 0x29, 0x49, 0x2d, 0xcc, 0x18, - 0x8d, 0x59, 0xc4, 0xba, 0x8e, 0x8e, 0xb8, 0x8a, 0xde, 0xce, 0xa3, 0xbf, 0x3d, 0x1d, 0xd3, 0x32, 0x2e, 0x52, 0x71, - 0x0d, 0x2a, 0x08, 0x50, 0x86, 0xa0, 0xe1, 0xbf, 0xa2, 0x06, 0xa0, 0x41, 0xb0, 0x03, 0xf0, 0x8f, 0x4e, 0xa7, 0x41, - 0x53, 0x93, 0x8b, 0x49, 0x2a, 0x8b, 0x9c, 0xb5, 0xa1, 0xcc, 0x64, 0x72, 0x48, 0x1e, 0x17, 0x80, 0xe7, 0x88, 0xcd, - 0x92, 0x36, 0x17, 0x72, 0xb3, 0xc9, 0xd7, 0x92, 0x1d, 0xb9, 0xf3, 0x8a, 0xd6, 0x6b, 0x51, 0xd9, 0x49, 0xcc, 0x17, - 0xd3, 0x3b, 0x23, 0x0c, 0x9c, 0xea, 0xd6, 0xdc, 0xee, 0x40, 0xa7, 0x99, 0xfa, 0x74, 0x6e, 0x02, 0xc4, 0x01, 0x86, - 0xeb, 0x6e, 0x7e, 0xbb, 0x20, 0xf4, 0x8e, 0xdd, 0x19, 0xb1, 0xea, 0xad, 0x91, 0x8b, 0xe8, 0xb4, 0xdb, 0xc1, 0x04, - 0x2e, 0xe3, 0xac, 0x34, 0x2f, 0x94, 0xba, 0xa1, 0xec, 0x68, 0x9b, 0x30, 0x9f, 0x77, 0xb4, 0x1b, 0x2e, 0xf8, 0x46, - 0xac, 0x63, 0xdd, 0x90, 0xa6, 0x12, 0x3d, 0x3a, 0x50, 0xdb, 0x21, 0xa0, 0x39, 0x1b, 0xd3, 0x25, 0x40, 0x6d, 0xc2, - 0x7e, 0x59, 0x83, 0x59, 0xca, 0x25, 0xf4, 0xb5, 0xdb, 0x27, 0xf9, 0x52, 0xf6, 0xa4, 0x72, 0x96, 0x28, 0xf8, 0x72, - 0xa4, 0xe0, 0x95, 0x95, 0xf3, 0x58, 0xcf, 0x21, 0xe0, 0xb1, 0xc8, 0x12, 0x9d, 0x93, 0xe2, 0x0a, 0x94, 0xa9, 0x70, - 0x04, 0xea, 0xaa, 0x11, 0x4b, 0x38, 0xc0, 0xed, 0xc5, 0xd3, 0x80, 0x50, 0x90, 0xea, 0xae, 0xcd, 0x8a, 0xbc, 0x63, - 0x27, 0x9b, 0x3b, 0x30, 0x8b, 0xad, 0xd7, 0x55, 0xeb, 0x2b, 0x93, 0x6c, 0x3f, 0x6e, 0x08, 0xb6, 0xdd, 0x91, 0xf2, - 0x85, 0x77, 0xf4, 0x96, 0x6c, 0x6e, 0xfb, 0xfd, 0x10, 0xfa, 0x43, 0xa8, 0xea, 0xd0, 0x5d, 0x67, 0x87, 0xee, 0x5c, - 0xe6, 0xd7, 0xe8, 0xf9, 0xa4, 0x37, 0xc4, 0x07, 0x34, 0xd1, 0xa2, 0xab, 0xf8, 0x1e, 0x36, 0x75, 0x54, 0x53, 0x59, - 0x79, 0x94, 0x50, 0x50, 0x01, 0x67, 0xbc, 0x3a, 0xe3, 0x18, 0xdb, 0x54, 0x3d, 0xbd, 0x53, 0xbc, 0xda, 0x5a, 0xaf, - 0xcd, 0x6a, 0x7d, 0x01, 0x16, 0x01, 0x17, 0x3c, 0xba, 0x56, 0xb4, 0xe4, 0xca, 0x61, 0xea, 0xcf, 0x71, 0x54, 0x82, - 0xcb, 0x38, 0xcb, 0x79, 0x1a, 0xd0, 0x4b, 0xbf, 0xff, 0xa1, 0xb2, 0x95, 0x5a, 0x7a, 0x67, 0xee, 0x4d, 0x48, 0x36, - 0xff, 0x63, 0x03, 0xf5, 0x3a, 0xc4, 0x88, 0xa8, 0x7a, 0x41, 0xbf, 0x65, 0x10, 0x1b, 0x33, 0xa8, 0xd6, 0x49, 0xc2, - 0xab, 0x2a, 0xd0, 0x4a, 0xad, 0x35, 0x5b, 0xeb, 0xf3, 0xec, 0x11, 0x3b, 0x79, 0xd4, 0x63, 0xec, 0x8e, 0xd0, 0x44, - 0xe9, 0x84, 0x74, 0x8d, 0x91, 0xa3, 0x05, 0x52, 0x1d, 0x8a, 0xb2, 0xcb, 0xf0, 0x2d, 0x0a, 0x59, 0xda, 0xfb, 0x5c, - 0x9f, 0xc8, 0xf2, 0x1b, 0x65, 0x74, 0x11, 0xc9, 0x44, 0x90, 0x8d, 0xdf, 0x22, 0x60, 0x2f, 0x34, 0x3b, 0x20, 0x9b, - 0x25, 0x3b, 0xa3, 0xe7, 0xc6, 0x04, 0x06, 0x5e, 0xbf, 0x95, 0x89, 0x7a, 0x94, 0x25, 0xd1, 0x95, 0x46, 0x2e, 0xf7, - 0x21, 0x89, 0xce, 0x43, 0xe2, 0xe6, 0x86, 0xa5, 0x75, 0x13, 0xa2, 0x98, 0x59, 0x6f, 0x78, 0xd9, 0xdd, 0x47, 0xde, - 0xb6, 0xd2, 0x3e, 0xd5, 0x77, 0x26, 0x8d, 0x4c, 0xa1, 0xaf, 0xc3, 0x49, 0xbf, 0x0f, 0x7f, 0x15, 0xfd, 0xc0, 0x5b, - 0x0a, 0xfe, 0x62, 0x8f, 0x48, 0x93, 0xb0, 0x00, 0xe0, 0x08, 0x73, 0x5e, 0xfb, 0x13, 0xf8, 0x88, 0x9d, 0x6c, 0x1e, - 0x85, 0x67, 0xde, 0xcc, 0xdd, 0x87, 0x78, 0xa9, 0x4a, 0x7a, 0xce, 0x3c, 0xe9, 0x81, 0x58, 0x85, 0x7a, 0xbf, 0xde, - 0x31, 0xa3, 0x4f, 0x00, 0x22, 0x75, 0x67, 0x1c, 0x4a, 0xf1, 0x63, 0xdd, 0x65, 0xb2, 0x49, 0x59, 0x9b, 0x89, 0x92, - 0x2a, 0x12, 0x7f, 0x11, 0x40, 0xbf, 0x61, 0x38, 0x1a, 0x80, 0xf7, 0x56, 0x63, 0xaf, 0x87, 0xc6, 0x19, 0x53, 0x4d, - 0xcf, 0x36, 0x6a, 0x79, 0x5b, 0x0a, 0xa1, 0xc7, 0x22, 0xba, 0xb3, 0xc7, 0x62, 0x78, 0x46, 0xdf, 0x42, 0x85, 0xaf, - 0x43, 0x8c, 0xa6, 0x4b, 0x9a, 0x66, 0xba, 0x96, 0x5b, 0xe9, 0x96, 0xd0, 0x1c, 0xa3, 0xf8, 0x38, 0x6d, 0xbb, 0xa7, - 0x5a, 0x68, 0x4f, 0x28, 0x0f, 0xef, 0x68, 0x4d, 0x6f, 0x0d, 0x8b, 0x60, 0x91, 0x96, 0x9d, 0xfc, 0x84, 0x5e, 0x38, - 0x02, 0x93, 0xb2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x33, 0x35, 0x52, 0x0e, 0x47, 0xe1, 0x4b, 0x36, 0x20, - 0x57, 0x50, 0x8b, 0x35, 0x66, 0x27, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x33, 0x29, 0x88, 0x64, 0x44, 0x73, 0x0b, - 0xf1, 0xf4, 0x0f, 0xd0, 0xf4, 0x41, 0x5a, 0x98, 0xd2, 0x35, 0x0a, 0x78, 0x40, 0xdf, 0xd4, 0xef, 0xe7, 0xf8, 0xdc, - 0x38, 0x96, 0x58, 0xd8, 0xe3, 0x25, 0xa1, 0x4b, 0x27, 0x6e, 0x14, 0x48, 0x9b, 0x2d, 0xab, 0x00, 0xac, 0x48, 0x02, - 0x8d, 0x48, 0xd0, 0x52, 0xc7, 0x8a, 0xcb, 0x36, 0x68, 0x40, 0x12, 0x15, 0x14, 0xb2, 0x44, 0x02, 0xf8, 0x61, 0x04, - 0x21, 0x8a, 0x62, 0x10, 0xf7, 0xaa, 0xe5, 0x15, 0x37, 0x54, 0x83, 0x13, 0x45, 0x30, 0xc1, 0x2a, 0x9d, 0x02, 0xb1, - 0x2d, 0xd6, 0x2b, 0xf0, 0xbc, 0xb4, 0x17, 0x49, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x95, 0x4e, 0xdb, 0xe5, 0xed, 0x88, - 0x96, 0x6a, 0x36, 0x77, 0x5e, 0x2c, 0x0c, 0xf7, 0x58, 0xbb, 0xdb, 0x81, 0xf6, 0xc2, 0x7a, 0x47, 0x44, 0x0d, 0x56, - 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xaa, 0x5e, 0x59, 0x26, 0xa0, 0xa6, 0xab, 0xb8, 0x5e, 0x46, 0xd9, 0x08, 0xfe, - 0x6c, 0xb7, 0xc1, 0x61, 0x00, 0x16, 0x90, 0xbf, 0xbc, 0xff, 0x29, 0xc2, 0xf0, 0x4c, 0xbf, 0xbc, 0xff, 0x69, 0xbb, - 0x7d, 0x3a, 0x1e, 0x6b, 0xae, 0xc0, 0xaa, 0x75, 0x80, 0x3f, 0xd0, 0x6c, 0x83, 0x59, 0xb2, 0xdb, 0xed, 0x53, 0xe0, - 0x20, 0x24, 0xdb, 0xa0, 0x77, 0xb1, 0x74, 0xe4, 0x92, 0xac, 0x86, 0xda, 0x91, 0x80, 0x55, 0xb7, 0xc3, 0x52, 0xec, - 0x52, 0x1f, 0x19, 0x82, 0x51, 0x2d, 0xfa, 0x17, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, 0xb2, 0xae, 0x57, 0x55, - 0x74, 0x78, 0x18, 0xaf, 0xb2, 0x51, 0x95, 0xc1, 0x36, 0xaf, 0x6e, 0xae, 0x00, 0x50, 0x21, 0xa0, 0xde, 0xbb, 0x75, - 0x91, 0xe9, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0x8d, 0x6e, 0x72, 0x4a, 0xcc, 0x03, 0xd8, - 0x1c, 0x6e, 0xb7, 0x1e, 0xbf, 0x70, 0x32, 0x7a, 0x3a, 0x5b, 0x66, 0xca, 0xa0, 0x93, 0xeb, 0xfd, 0x4f, 0x22, 0x27, - 0x0d, 0x15, 0x9f, 0x64, 0xfa, 0x22, 0x03, 0x3e, 0x8f, 0xbd, 0xa9, 0x42, 0x97, 0xe5, 0xf2, 0x5a, 0x03, 0x6c, 0x6c, - 0x76, 0x79, 0x3f, 0x4a, 0x39, 0x44, 0xa4, 0x08, 0x8c, 0xba, 0x66, 0x99, 0x11, 0xd7, 0xa6, 0xe2, 0xbe, 0xa5, 0x0a, - 0x7b, 0x53, 0x39, 0xce, 0x2a, 0x5c, 0x3b, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x02, 0x85, 0xa8, 0x1c, 0x8d, 0xe9, 0xac, - 0x40, 0x2a, 0x73, 0x98, 0x50, 0xcc, 0x61, 0xdf, 0xfd, 0x92, 0x5a, 0x73, 0x19, 0x57, 0xb8, 0xf7, 0xc2, 0x95, 0x99, - 0xdc, 0x09, 0x00, 0x45, 0x92, 0xb5, 0xff, 0xfc, 0x09, 0xa9, 0xf1, 0x3f, 0x53, 0xa5, 0x01, 0xe8, 0xfd, 0x0c, 0x35, - 0x59, 0x82, 0x80, 0xad, 0x98, 0xba, 0x68, 0xfa, 0x46, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x15, 0xdb, 0xc8, 0xf8, 0x39, - 0x51, 0x4d, 0x4b, 0x9e, 0xae, 0x8b, 0x34, 0x2e, 0x92, 0xfb, 0x88, 0x37, 0x53, 0x2c, 0x89, 0x55, 0x9a, 0x02, 0xfd, - 0xec, 0x77, 0xe1, 0xa7, 0xd2, 0x33, 0x01, 0xa7, 0x85, 0xbb, 0xad, 0x9c, 0xcd, 0x64, 0x18, 0x67, 0x64, 0xca, 0x25, - 0x62, 0xb7, 0xd1, 0xf7, 0xe8, 0x13, 0xfc, 0xc9, 0xd1, 0x13, 0x42, 0xef, 0xc4, 0xb4, 0x40, 0x50, 0xba, 0x22, 0x35, - 0xae, 0x9a, 0xd8, 0xaf, 0x29, 0x44, 0x71, 0xa8, 0x18, 0x84, 0xee, 0xd4, 0xed, 0x93, 0x7c, 0x9f, 0x29, 0xfb, 0x8d, - 0x2e, 0x5b, 0x90, 0x4d, 0x05, 0x1d, 0x13, 0xd6, 0xdb, 0xd3, 0xd9, 0xb3, 0x33, 0xe7, 0x37, 0x68, 0xc2, 0x41, 0x75, - 0x03, 0xed, 0x2a, 0xc9, 0x34, 0x46, 0xb1, 0x59, 0x8c, 0xb5, 0x1b, 0x13, 0x11, 0x04, 0x9d, 0x2e, 0x66, 0x61, 0xbb, - 0x9d, 0x10, 0x5f, 0x02, 0x09, 0x14, 0xb8, 0x72, 0x51, 0x4e, 0x42, 0x22, 0x2f, 0x64, 0x6a, 0xb2, 0x6e, 0x04, 0x0b, - 0xd4, 0x1a, 0x3b, 0x0a, 0xe8, 0x29, 0x37, 0x4f, 0x01, 0x7d, 0x5f, 0xb2, 0x53, 0x3e, 0x08, 0x86, 0x18, 0x5f, 0x35, - 0xa0, 0xb7, 0x42, 0x3e, 0x82, 0x87, 0x30, 0xb0, 0x5c, 0xf4, 0x65, 0xc9, 0x10, 0x56, 0xe8, 0xcf, 0x94, 0x4d, 0xbe, - 0xfe, 0xc6, 0xce, 0xef, 0xb5, 0x12, 0xb3, 0x83, 0x50, 0xdc, 0x5c, 0x4f, 0x80, 0xf8, 0xd5, 0xfc, 0x1a, 0xac, 0xab, - 0x95, 0xc4, 0xdb, 0x91, 0x3c, 0x54, 0xae, 0x1c, 0xdd, 0x7c, 0x52, 0xe9, 0x4f, 0x20, 0x48, 0x8d, 0x95, 0x94, 0xdb, - 0xef, 0x3e, 0x0a, 0x5b, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xed, 0xad, 0xe4, 0xc2, 0x17, 0xfe, 0x63, 0x9d, 0xef, 0x31, - 0x76, 0x88, 0x38, 0xc3, 0xe9, 0xf7, 0xc1, 0xb0, 0xbd, 0x5b, 0x99, 0x36, 0x24, 0xba, 0x96, 0x1f, 0x01, 0xfd, 0x1f, - 0xab, 0xf1, 0x3b, 0x45, 0x49, 0x5f, 0x12, 0xe7, 0x08, 0x57, 0xc4, 0x2b, 0x34, 0xd5, 0xeb, 0x8d, 0x1b, 0xfa, 0xa6, - 0xd4, 0x2f, 0x94, 0x82, 0xc3, 0xbc, 0xd5, 0x0a, 0x0f, 0x3c, 0xf3, 0xfe, 0xa8, 0x3c, 0x41, 0xf7, 0x6f, 0xb8, 0x37, - 0xfe, 0xa8, 0x58, 0x86, 0x37, 0xe5, 0x2c, 0xd3, 0x77, 0xb8, 0xdb, 0xac, 0x48, 0xc5, 0x2d, 0x63, 0xc1, 0xba, 0x90, - 0xe6, 0xab, 0x69, 0x30, 0xdb, 0x34, 0x91, 0x4c, 0xb6, 0xdf, 0xff, 0xe5, 0x9d, 0xb0, 0xd9, 0x20, 0x38, 0xab, 0x45, - 0x19, 0x5f, 0xf1, 0x60, 0xaa, 0x54, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0x63, 0xb5, 0x77, 0xf0, 0x64, 0xa8, - 0x99, 0x0e, 0x71, 0x6d, 0x74, 0x16, 0xf0, 0x56, 0x8f, 0xe6, 0x69, 0x0d, 0xbb, 0xcc, 0x55, 0x52, 0xfc, 0xd1, 0x92, - 0x64, 0x63, 0xfd, 0x9e, 0x0c, 0xdb, 0xc8, 0x67, 0xae, 0x01, 0x63, 0xe6, 0x56, 0xc8, 0x20, 0x77, 0x3d, 0x60, 0x84, - 0x90, 0x08, 0x54, 0xd6, 0x62, 0xe2, 0xbc, 0xd2, 0xe1, 0x1f, 0x6d, 0x60, 0x9c, 0x18, 0x03, 0xe3, 0x7c, 0x14, 0x21, - 0xa7, 0xa7, 0x7c, 0x90, 0x78, 0xb3, 0xf5, 0x97, 0x2c, 0x91, 0xde, 0x08, 0x42, 0x2f, 0xe0, 0xf7, 0xb8, 0xc5, 0x03, - 0x79, 0xc1, 0x29, 0xed, 0xcd, 0xe9, 0xf0, 0x65, 0x49, 0x86, 0x7f, 0x82, 0x77, 0x57, 0x6c, 0x2e, 0xcb, 0x09, 0x2c, - 0xee, 0xd8, 0x29, 0x9e, 0xe6, 0xb2, 0xc5, 0x09, 0x71, 0x88, 0x45, 0xee, 0x12, 0x0b, 0x18, 0x51, 0xcd, 0x68, 0xfc, - 0x78, 0xf6, 0xf6, 0x8d, 0xc2, 0x6c, 0xca, 0xdd, 0x0f, 0x60, 0x44, 0x95, 0xb4, 0xdd, 0x0c, 0xf8, 0x72, 0x84, 0x06, - 0xdb, 0xa9, 0x1d, 0xec, 0x7e, 0x5f, 0xa7, 0x9d, 0x14, 0x4e, 0x36, 0x2b, 0x06, 0xdd, 0x51, 0xda, 0x2c, 0xa5, 0x41, - 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0xab, 0xc5, 0xaa, 0xce, 0x87, 0xe1, 0x92, 0xc6, 0x46, 0x56, 0x6e, 0x76, 0x13, 0x8e, - 0x6c, 0x02, 0x5c, 0x9f, 0x84, 0xb2, 0xf2, 0xe7, 0xa0, 0x05, 0x9d, 0x09, 0x1c, 0xd1, 0x76, 0x1b, 0x42, 0x04, 0x8e, - 0x72, 0x38, 0x99, 0x85, 0xe5, 0x70, 0x28, 0x07, 0xbe, 0x24, 0x24, 0x7a, 0x53, 0xce, 0xb3, 0x85, 0x44, 0xec, 0x71, - 0x77, 0xd2, 0xaf, 0xa5, 0xe4, 0x94, 0x7b, 0x7f, 0x54, 0x64, 0xf3, 0x5b, 0x8a, 0x31, 0x07, 0xad, 0x66, 0x33, 0x03, - 0x09, 0xeb, 0x69, 0x4d, 0xe4, 0x3a, 0x32, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, 0x75, 0x8b, 0x23, 0xd6, 0xd3, - 0x7a, 0x0f, 0x2a, 0x40, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x5e, 0x56, 0xa1, 0xa0, 0x9c, 0xf8, 0xcc, 0x8c, 0x11, - 0x0d, 0x96, 0x20, 0x24, 0x8d, 0xab, 0xfa, 0xb5, 0x48, 0xb3, 0xcb, 0x0c, 0x10, 0x13, 0xac, 0xff, 0x9c, 0xf0, 0xde, - 0x3c, 0x93, 0xf3, 0xd2, 0x95, 0x38, 0x33, 0x30, 0x1f, 0x5d, 0x6f, 0x69, 0x49, 0xa2, 0x12, 0x68, 0x94, 0xab, 0xe5, - 0xf9, 0xfb, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x69, 0x3b, 0xc4, 0x4f, 0x58, 0x4d, 0x9c, 0xd3, 0xba, 0x96, 0x22, - 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xc8, 0xe1, 0x03, 0x83, 0x0a, 0x2b, 0xf9, 0x29, 0x70, 0xf8, 0x8c, - 0x81, 0xa4, 0xab, 0x45, 0x70, 0x35, 0x3a, 0xc2, 0x8a, 0x32, 0xb5, 0xc4, 0x14, 0x12, 0xdd, 0x7a, 0xa1, 0x35, 0x86, - 0x51, 0x76, 0x15, 0xf9, 0xdf, 0xab, 0xee, 0xfd, 0x51, 0x6d, 0xb7, 0x30, 0xc9, 0x8e, 0xc7, 0x15, 0x6c, 0x6a, 0xd4, - 0x0a, 0xe1, 0xec, 0x9c, 0xd6, 0xa8, 0x1d, 0xeb, 0x85, 0x05, 0x90, 0x07, 0xb0, 0x15, 0xf1, 0x28, 0x83, 0x60, 0x6f, - 0xca, 0x79, 0xb5, 0xb0, 0xa2, 0x1c, 0x21, 0xf1, 0xbe, 0xc4, 0x28, 0xe5, 0x70, 0x15, 0x0b, 0x4b, 0x86, 0xfc, 0xea, - 0xe8, 0xb2, 0x14, 0xd7, 0x20, 0x29, 0xd1, 0x0c, 0x95, 0xe1, 0x75, 0x71, 0xd5, 0x16, 0x84, 0xf6, 0x2e, 0x2a, 0x50, - 0x47, 0x82, 0xe0, 0xc5, 0xab, 0x21, 0x66, 0x1b, 0xb9, 0xbb, 0xa2, 0xbd, 0xe4, 0x80, 0x5a, 0xdd, 0xb5, 0x5d, 0x6f, - 0xd2, 0x36, 0xdb, 0x88, 0x0b, 0xff, 0x82, 0xd2, 0x4f, 0xf9, 0xa0, 0x74, 0xa9, 0x04, 0x6e, 0x7c, 0xb9, 0xc9, 0xb2, - 0xcb, 0x7b, 0x5c, 0xfa, 0xb5, 0x37, 0x7e, 0xfd, 0x7e, 0x4f, 0x2e, 0x04, 0x2f, 0x15, 0x98, 0x6f, 0x97, 0x99, 0xaa, - 0xb5, 0xa6, 0xd4, 0x5c, 0x82, 0x6b, 0x6b, 0x3f, 0x82, 0x8a, 0xb8, 0xae, 0xc8, 0x64, 0x72, 0x80, 0x0e, 0x9c, 0xac, - 0x70, 0x2b, 0x0b, 0xf0, 0xd8, 0x09, 0xc8, 0x76, 0xcb, 0xc3, 0x40, 0x1d, 0x3a, 0x81, 0xbb, 0x25, 0xcf, 0x90, 0x59, - 0x33, 0x8f, 0x3f, 0x2b, 0xc1, 0x3f, 0xb6, 0xe0, 0x27, 0x14, 0x77, 0x1a, 0x99, 0x7f, 0x2b, 0xad, 0x5b, 0xdc, 0xbf, - 0x93, 0x69, 0x42, 0x51, 0x99, 0xd0, 0xb8, 0x95, 0xfe, 0x4b, 0x07, 0x4b, 0x92, 0xd9, 0x3f, 0x08, 0xf8, 0x60, 0xe6, - 0x3d, 0x31, 0xef, 0x49, 0x73, 0xba, 0xb5, 0x82, 0x21, 0x40, 0xa1, 0x9f, 0x93, 0xb9, 0xa6, 0xea, 0xf9, 0xe7, 0x35, - 0x5f, 0x73, 0xbf, 0xc5, 0x26, 0xe9, 0x81, 0x06, 0x3b, 0x79, 0x14, 0xa5, 0xb0, 0x12, 0x75, 0xae, 0x25, 0xea, 0x55, - 0xc3, 0x32, 0x54, 0x27, 0x38, 0x35, 0x4f, 0xd5, 0xb0, 0xfb, 0x89, 0x68, 0xad, 0x24, 0x2d, 0x31, 0x60, 0xad, 0x23, - 0x0f, 0xc9, 0xed, 0x5a, 0xc7, 0x9d, 0x86, 0xba, 0x34, 0x89, 0x12, 0x60, 0x84, 0x0b, 0x70, 0x04, 0xfd, 0x54, 0x86, - 0x1c, 0xae, 0xa9, 0x52, 0xbf, 0xa0, 0x28, 0x79, 0xe2, 0x28, 0x6a, 0x95, 0x22, 0xdd, 0x7c, 0x94, 0x63, 0x37, 0x5c, - 0xe3, 0x84, 0x9c, 0x68, 0xa1, 0xbf, 0x3d, 0x96, 0x72, 0x86, 0x16, 0x0f, 0xf2, 0x04, 0xeb, 0xe5, 0x2d, 0x05, 0x8a, - 0x3e, 0xba, 0x8c, 0xba, 0xe6, 0x15, 0xda, 0xbe, 0x2c, 0xfb, 0xfd, 0xdc, 0xd4, 0x93, 0xb2, 0x93, 0xcd, 0x52, 0xef, - 0x43, 0x54, 0x4c, 0xe1, 0xae, 0x4f, 0x14, 0x7f, 0x15, 0xaa, 0xab, 0xb6, 0xc8, 0xf9, 0x88, 0x23, 0x2e, 0x46, 0x4e, - 0x9a, 0x9f, 0xe5, 0xd4, 0x4b, 0x71, 0xbf, 0xac, 0xe4, 0xd7, 0x4a, 0x5b, 0x31, 0x5a, 0xa0, 0xfe, 0x54, 0xaa, 0xbc, - 0x5f, 0x94, 0x00, 0xf7, 0x54, 0xb1, 0x37, 0x60, 0x5f, 0xa1, 0x10, 0x7e, 0x5b, 0x02, 0xfe, 0x8d, 0xe4, 0x06, 0x8c, - 0x02, 0x03, 0x8c, 0x26, 0xdb, 0x73, 0x9a, 0xc0, 0x01, 0x57, 0x29, 0x15, 0x05, 0xad, 0xf4, 0xd0, 0x50, 0x53, 0x18, - 0x3d, 0x43, 0x19, 0xb7, 0xcc, 0xec, 0xdc, 0x18, 0x3b, 0x2d, 0xf0, 0x3c, 0x7f, 0x3e, 0x27, 0xf4, 0xb0, 0x56, 0x07, - 0xa9, 0xd1, 0x49, 0x74, 0x7f, 0xec, 0xc2, 0xc9, 0xf5, 0xc2, 0x59, 0x36, 0x2c, 0x81, 0xee, 0xc0, 0x05, 0x31, 0xee, - 0xf7, 0x73, 0x38, 0x32, 0xf5, 0xc8, 0x97, 0x2c, 0xa7, 0x31, 0x5b, 0x52, 0xe5, 0x69, 0x77, 0x55, 0x87, 0x39, 0x5d, - 0x1a, 0x19, 0x6f, 0xca, 0x8a, 0x79, 0x0e, 0x1a, 0x49, 0xf8, 0xd3, 0x6d, 0xed, 0x92, 0xce, 0x97, 0x90, 0x01, 0xfe, - 0x80, 0x44, 0x14, 0xb1, 0xaf, 0xff, 0xad, 0xc6, 0x49, 0x3d, 0x51, 0xda, 0xb0, 0x84, 0xae, 0x99, 0xaa, 0x9f, 0x5e, - 0xb2, 0xb5, 0xb7, 0x14, 0xb6, 0xdb, 0xd0, 0x4f, 0x60, 0x8a, 0x73, 0x25, 0xd3, 0x4b, 0xd4, 0x49, 0x01, 0x15, 0x0b, - 0x2f, 0x71, 0xf9, 0xa5, 0x84, 0x42, 0x73, 0xe7, 0xcb, 0x85, 0x56, 0x62, 0x42, 0xab, 0xc4, 0xe7, 0x0f, 0x95, 0xfe, - 0x5a, 0x7b, 0xc4, 0xfd, 0x2b, 0x0d, 0x13, 0x5d, 0x24, 0x2a, 0x44, 0x67, 0xbf, 0x82, 0x2c, 0xa7, 0x02, 0x1c, 0xcb, - 0x33, 0xd1, 0xd0, 0x1f, 0x53, 0x88, 0x83, 0x0e, 0x0d, 0x7a, 0x57, 0x8a, 0xeb, 0xac, 0xe2, 0x21, 0xde, 0x13, 0x1c, - 0xcd, 0xe8, 0x7e, 0x83, 0x0f, 0x65, 0xed, 0xd1, 0xab, 0xc8, 0xc6, 0x51, 0xee, 0x37, 0xbf, 0x56, 0xe1, 0x1c, 0xa2, - 0x55, 0x2e, 0xa8, 0x52, 0x57, 0x5b, 0x00, 0x2a, 0xc7, 0xf6, 0xea, 0x11, 0x9c, 0x6e, 0xea, 0xfa, 0x56, 0x87, 0xd6, - 0x1c, 0x40, 0x98, 0x43, 0xb2, 0x69, 0xb8, 0xda, 0x01, 0xf6, 0x48, 0xac, 0xd7, 0x40, 0x63, 0xed, 0xd6, 0xec, 0xb4, - 0x47, 0x71, 0x98, 0xc8, 0x4c, 0x5b, 0xa4, 0x68, 0x73, 0xb7, 0x4e, 0x8b, 0xa2, 0x0d, 0x9a, 0x21, 0xec, 0xde, 0x75, - 0xf8, 0xba, 0x15, 0x61, 0x7d, 0xbf, 0xed, 0x0b, 0x8c, 0x86, 0x36, 0xd7, 0xee, 0x39, 0x86, 0x6e, 0xd8, 0x60, 0x13, - 0x39, 0x0f, 0x91, 0x0f, 0x33, 0x79, 0x20, 0x8a, 0xc6, 0x18, 0xb0, 0x3d, 0xe2, 0x6a, 0xd3, 0x4a, 0x7e, 0x5e, 0xc6, - 0x9c, 0xed, 0x19, 0xe3, 0x94, 0xd6, 0xd7, 0xb8, 0xe6, 0xb8, 0x2c, 0xa4, 0x6a, 0x8c, 0x67, 0x3c, 0x0c, 0x3b, 0x5f, - 0xe0, 0xce, 0xac, 0x31, 0x78, 0x11, 0x96, 0x4a, 0x76, 0x2a, 0x57, 0x9f, 0xc3, 0x16, 0x47, 0xb3, 0x31, 0xa7, 0xbf, - 0xff, 0x72, 0xc5, 0x17, 0xe8, 0xa6, 0x66, 0xfd, 0x08, 0x82, 0xac, 0x40, 0x87, 0x2c, 0xa9, 0x7a, 0xfc, 0xae, 0x04, - 0x6a, 0x0f, 0xf3, 0xf0, 0x5d, 0xc9, 0x8a, 0xf8, 0x26, 0xbb, 0x8a, 0x6b, 0x51, 0x8e, 0x6e, 0x78, 0x91, 0x8a, 0xd2, - 0x48, 0x8d, 0x83, 0xd3, 0xd5, 0x2a, 0xe7, 0x01, 0x98, 0xca, 0x1b, 0x46, 0xd9, 0x54, 0x96, 0xa9, 0xc1, 0x55, 0xf2, - 0xf4, 0x5a, 0x89, 0xce, 0xab, 0x9b, 0xab, 0x20, 0xc2, 0x5f, 0x17, 0xfa, 0xc7, 0x75, 0x5c, 0x7d, 0x0c, 0x22, 0x63, - 0x53, 0xa7, 0x7f, 0xa0, 0x54, 0x1e, 0xfc, 0xa7, 0x40, 0xa6, 0xfb, 0x5d, 0x09, 0x96, 0xd9, 0xa6, 0xe2, 0xe3, 0x18, - 0x6b, 0x1d, 0x4e, 0xc8, 0x4c, 0x96, 0xe8, 0xbc, 0x4b, 0xd6, 0x25, 0x58, 0xfb, 0x49, 0x2c, 0x63, 0x99, 0x6b, 0x86, - 0x95, 0xc9, 0x8a, 0xf4, 0xac, 0xac, 0xd9, 0x61, 0x68, 0x9c, 0x68, 0xe6, 0xe8, 0x2d, 0xa0, 0x1e, 0xc8, 0xe1, 0x15, - 0x2d, 0xd6, 0xcc, 0xf1, 0xb1, 0xf1, 0x5e, 0x3f, 0x3a, 0xbc, 0x72, 0x04, 0x4a, 0xe6, 0x4e, 0x8e, 0xc2, 0x44, 0xf0, - 0xac, 0xd5, 0xe3, 0x8b, 0x3c, 0x2b, 0x60, 0xe5, 0x4c, 0xc6, 0x63, 0xea, 0x2c, 0xad, 0xd6, 0xcd, 0xd1, 0x22, 0xb9, - 0x66, 0x8f, 0xeb, 0xc7, 0x9c, 0x1c, 0xf2, 0x96, 0xa9, 0x6d, 0xdb, 0x3a, 0xce, 0xd1, 0xe4, 0x4b, 0xd3, 0xfd, 0x6a, - 0x6d, 0x22, 0xa2, 0x4b, 0xe7, 0x3e, 0xeb, 0x15, 0xdc, 0xfa, 0xa6, 0xd0, 0xf4, 0x5a, 0x00, 0x10, 0x9d, 0x32, 0xe0, - 0x2f, 0x59, 0xb1, 0x1e, 0xd5, 0xbc, 0xaa, 0x41, 0xc2, 0x82, 0x22, 0xbc, 0x29, 0xf6, 0xa6, 0xb4, 0x37, 0x4e, 0xc7, - 0x61, 0x07, 0x2e, 0xa6, 0xe8, 0x8e, 0x03, 0x76, 0xfd, 0x5a, 0x2b, 0x1a, 0xa9, 0x5f, 0xb6, 0x2f, 0xb1, 0xea, 0x8b, - 0x52, 0xe6, 0x99, 0x9c, 0x12, 0x8b, 0xdd, 0x56, 0x2e, 0xac, 0xa8, 0xdf, 0x30, 0xe1, 0xd2, 0x95, 0x20, 0x20, 0xd3, - 0x92, 0xf5, 0x4a, 0xbd, 0x8b, 0xc4, 0x1a, 0x08, 0x19, 0x18, 0xbe, 0x06, 0xeb, 0xa2, 0xe2, 0xda, 0x0a, 0xd6, 0xb9, - 0xe7, 0xab, 0x84, 0x42, 0x14, 0x3c, 0xb0, 0x13, 0xf4, 0x43, 0xeb, 0xe6, 0x6d, 0x29, 0x51, 0x06, 0xf1, 0xb8, 0x95, - 0x53, 0x0e, 0x12, 0x08, 0xc0, 0x3d, 0x95, 0x21, 0x38, 0x24, 0xc8, 0x3a, 0xb8, 0x9a, 0x71, 0x04, 0x57, 0x97, 0xce, - 0x5c, 0x5c, 0x03, 0xac, 0x4b, 0x7f, 0x2e, 0x13, 0x5c, 0x58, 0x8d, 0xa8, 0x34, 0x67, 0x9c, 0x62, 0x10, 0x23, 0x43, - 0xd0, 0x57, 0x86, 0xd2, 0x5e, 0x81, 0xa6, 0xf1, 0x9a, 0xad, 0xa4, 0x0f, 0x00, 0xbd, 0x60, 0x2b, 0x69, 0xec, 0x8f, - 0x5f, 0x9f, 0xb3, 0x95, 0x92, 0x06, 0x4f, 0xaf, 0x67, 0x17, 0xb3, 0xf3, 0x01, 0x3b, 0x8a, 0x42, 0x65, 0xc0, 0x10, - 0x58, 0x24, 0xfe, 0x60, 0x10, 0x16, 0xb2, 0x11, 0x83, 0x42, 0x46, 0xc1, 0x72, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, - 0xc3, 0x02, 0x43, 0x5e, 0x79, 0x2f, 0x48, 0x40, 0xa8, 0x2e, 0x0d, 0x5d, 0x1e, 0xc3, 0xe1, 0xe4, 0x60, 0x02, 0xa9, - 0x98, 0x99, 0xc9, 0xc2, 0xd8, 0x98, 0x44, 0x10, 0xef, 0xb4, 0xb3, 0x5e, 0x28, 0xb7, 0xbb, 0xc6, 0x42, 0x8d, 0xc3, - 0xe0, 0xb3, 0x2a, 0x9e, 0x1c, 0x0c, 0xbb, 0x2a, 0xc6, 0x51, 0xb8, 0xd1, 0xca, 0xb7, 0xf3, 0x63, 0x00, 0xaf, 0x3d, - 0x1f, 0xba, 0x72, 0x89, 0xf3, 0xc3, 0x27, 0xe4, 0xf1, 0x13, 0x42, 0xcf, 0xd9, 0xf9, 0x17, 0x4f, 0xe8, 0xb9, 0x24, - 0x27, 0x07, 0x93, 0xe8, 0x86, 0xe9, 0x06, 0x1c, 0x1e, 0xc9, 0x26, 0xd0, 0xab, 0xd1, 0xba, 0x90, 0x0b, 0x4c, 0x39, - 0x34, 0x85, 0xdf, 0x8e, 0x0f, 0x82, 0xc1, 0x4d, 0xbb, 0xe9, 0x37, 0xed, 0xb6, 0x3a, 0x5e, 0x5d, 0x07, 0x47, 0xd1, - 0x6e, 0x31, 0x93, 0x6f, 0xc6, 0x07, 0x76, 0x0e, 0xb0, 0xbe, 0x87, 0xc7, 0x44, 0x37, 0x69, 0x67, 0x54, 0xdc, 0x9a, - 0xbe, 0xc2, 0x3e, 0xf8, 0x45, 0x76, 0xf4, 0x61, 0xf8, 0x6f, 0x75, 0xa2, 0x39, 0xff, 0xe2, 0x08, 0xc8, 0x11, 0xc8, - 0x40, 0xb1, 0x44, 0x30, 0xc3, 0x81, 0xa6, 0x80, 0x82, 0x4c, 0x8d, 0x3b, 0x55, 0xc3, 0x2f, 0x47, 0x4d, 0xce, 0xc8, - 0x0d, 0x4c, 0x0d, 0xb6, 0x05, 0x3f, 0x90, 0xdd, 0x50, 0xdf, 0x28, 0x74, 0x23, 0xe5, 0x64, 0xa6, 0x5f, 0x52, 0xfd, - 0x83, 0xdd, 0x40, 0x00, 0x63, 0x0b, 0x2f, 0x28, 0xd8, 0x97, 0xc7, 0x57, 0x07, 0xb8, 0x8a, 0x00, 0x25, 0x8b, 0x05, - 0x5f, 0x0e, 0xae, 0xd4, 0xe6, 0x3e, 0x08, 0xc8, 0xe0, 0xcb, 0xe0, 0xe4, 0xcb, 0x81, 0x18, 0x04, 0xc7, 0x87, 0x57, - 0x27, 0x81, 0x35, 0xee, 0x87, 0x10, 0x8f, 0xb2, 0xa2, 0x98, 0x69, 0x34, 0x1f, 0xf4, 0x82, 0x92, 0x89, 0xb9, 0xa9, - 0x57, 0x1a, 0x9f, 0xd1, 0x74, 0x6a, 0x90, 0xbf, 0xc3, 0x94, 0xc5, 0xfa, 0x77, 0x30, 0xe1, 0xd7, 0x41, 0x64, 0x83, - 0xa0, 0xce, 0xf2, 0x28, 0xa6, 0x4b, 0x76, 0x5f, 0x85, 0x29, 0x4d, 0x0e, 0x73, 0x42, 0xa2, 0x70, 0x29, 0xc1, 0xf3, - 0xe4, 0xeb, 0x04, 0xe2, 0xb8, 0xda, 0xcf, 0x01, 0xd7, 0x8d, 0xe6, 0x87, 0x09, 0x69, 0x15, 0x61, 0x23, 0xb2, 0x6c, - 0x1a, 0x7a, 0xc9, 0xc2, 0x15, 0xbd, 0x02, 0x66, 0x4a, 0xac, 0xc3, 0x2b, 0xe0, 0xf2, 0xd6, 0xf3, 0xd5, 0x82, 0x5d, - 0x79, 0xd2, 0x37, 0xcd, 0x17, 0x5f, 0x1a, 0x9f, 0x3c, 0xe0, 0x21, 0xad, 0x1f, 0x5e, 0x0a, 0x36, 0x00, 0x37, 0x19, - 0xbf, 0xfd, 0x4e, 0xdc, 0xa9, 0x79, 0x69, 0x4f, 0x31, 0xce, 0x4c, 0x3b, 0x31, 0x69, 0x27, 0xe4, 0xee, 0x7d, 0x7b, - 0x13, 0xeb, 0x93, 0xbd, 0x8a, 0xd6, 0xd2, 0x65, 0xd5, 0x30, 0x24, 0xe5, 0x9a, 0x21, 0x7f, 0x8f, 0x92, 0x53, 0x23, - 0xf0, 0x64, 0x97, 0xbc, 0x4e, 0x96, 0xee, 0x41, 0x65, 0xac, 0x06, 0xcc, 0x31, 0x62, 0x58, 0x28, 0x1c, 0xfb, 0xd7, - 0x19, 0x2b, 0xd7, 0xae, 0x40, 0x23, 0x46, 0xee, 0xed, 0x75, 0xc6, 0x9c, 0x98, 0xab, 0xc9, 0xda, 0x09, 0x55, 0xe7, - 0xa4, 0xe7, 0x2d, 0xde, 0xcb, 0x2a, 0x35, 0xb4, 0x44, 0xf4, 0x60, 0x2c, 0xcd, 0x28, 0x65, 0xa2, 0xd2, 0xa0, 0x91, - 0x8a, 0x8d, 0x6d, 0xf0, 0x4b, 0x70, 0x42, 0xe5, 0x8e, 0x3a, 0xdb, 0xb5, 0x53, 0x2a, 0x1c, 0x60, 0x59, 0xaa, 0x55, - 0xe5, 0x76, 0x99, 0x09, 0x56, 0x0f, 0x82, 0xd1, 0x1f, 0x95, 0x28, 0x66, 0x78, 0x67, 0x64, 0xc1, 0x14, 0xac, 0x04, - 0x65, 0x2d, 0xc3, 0x62, 0xc8, 0x51, 0x8b, 0xa7, 0x7d, 0x52, 0x85, 0xfa, 0xd1, 0x11, 0x24, 0x77, 0xb9, 0x6e, 0x05, - 0xc9, 0x7d, 0x32, 0x7e, 0xa2, 0x06, 0x3a, 0x5d, 0x2b, 0xc7, 0x43, 0x97, 0xdf, 0x46, 0x7c, 0x6d, 0xd5, 0x7b, 0xaa, - 0xb4, 0x0a, 0x55, 0xa0, 0xc4, 0x8a, 0xd2, 0x95, 0x5a, 0xd0, 0xfd, 0x2e, 0x02, 0x60, 0x11, 0x1b, 0xb3, 0xf1, 0xae, - 0x6d, 0x56, 0x08, 0x1a, 0x5d, 0x76, 0xb2, 0x89, 0x07, 0x2c, 0x51, 0xad, 0x1d, 0x4c, 0x68, 0x7c, 0xc2, 0x8a, 0x7e, - 0x3f, 0x3f, 0x01, 0x7a, 0xaa, 0x8c, 0x98, 0x4a, 0x38, 0xf2, 0x3f, 0xb7, 0x22, 0x5d, 0x14, 0xd8, 0xac, 0xc9, 0xbb, - 0x35, 0x96, 0x91, 0xa8, 0xcb, 0x94, 0x2a, 0xaf, 0x72, 0x0c, 0x98, 0xd6, 0xeb, 0x96, 0xe3, 0xca, 0xae, 0xe2, 0xc8, - 0x51, 0x61, 0x19, 0x71, 0x5e, 0x8d, 0xe3, 0xad, 0xc6, 0x37, 0x38, 0xd4, 0x6c, 0xda, 0xa5, 0x3b, 0x84, 0xb0, 0x10, - 0x5e, 0x67, 0x70, 0x1b, 0x51, 0x76, 0x12, 0xa8, 0xbc, 0xd1, 0xd7, 0x09, 0x69, 0x73, 0xbb, 0x5e, 0x3b, 0x06, 0xe9, - 0x44, 0x1f, 0x28, 0xf5, 0x08, 0x5a, 0xa3, 0x58, 0x50, 0x39, 0xe2, 0x91, 0xe5, 0xe1, 0xad, 0x41, 0xac, 0x92, 0x2f, - 0x29, 0x2a, 0x45, 0x03, 0xf4, 0xbf, 0xe4, 0xb7, 0x07, 0xbf, 0xbc, 0xff, 0xe9, 0x8c, 0xc7, 0x65, 0xb2, 0x7c, 0x17, - 0x97, 0xf1, 0x75, 0x15, 0x6e, 0xe4, 0x18, 0xc5, 0x0d, 0x99, 0x56, 0x03, 0x26, 0xf4, 0x4a, 0xf2, 0x77, 0xa5, 0x22, - 0xc4, 0x58, 0x67, 0xb2, 0xae, 0x6a, 0x71, 0xed, 0x55, 0xba, 0x2e, 0x33, 0xfc, 0xb8, 0xe5, 0x73, 0x7a, 0x08, 0x40, - 0x9e, 0xda, 0x85, 0x34, 0x12, 0xaa, 0x10, 0x6d, 0x2e, 0xe2, 0x74, 0x7d, 0x3c, 0xf6, 0xba, 0x5e, 0xb0, 0xa7, 0xe3, - 0xaf, 0xa6, 0xaf, 0xb3, 0x30, 0x1b, 0x54, 0x64, 0x54, 0x2f, 0x79, 0xd1, 0x32, 0xe5, 0x94, 0x26, 0x01, 0xe8, 0xe3, - 0xd9, 0x63, 0xec, 0x68, 0x3c, 0x26, 0x9b, 0xb6, 0x78, 0x80, 0x87, 0xcb, 0x75, 0x58, 0x92, 0x99, 0xaa, 0x23, 0x0a, - 0x0a, 0x7e, 0x57, 0x07, 0x80, 0xe4, 0x68, 0xaa, 0xd2, 0x5c, 0x1a, 0x7b, 0x3a, 0x9e, 0x50, 0x81, 0xdd, 0x0e, 0x49, - 0xe3, 0x54, 0x68, 0x67, 0x5e, 0xb8, 0x1e, 0x45, 0x42, 0xbb, 0x2c, 0xed, 0x54, 0x2a, 0xe4, 0x9e, 0x99, 0xd9, 0xae, - 0x41, 0x0c, 0x86, 0x50, 0xd5, 0x5d, 0x38, 0x75, 0xef, 0x36, 0xd7, 0x98, 0xed, 0x80, 0xf7, 0x1a, 0x34, 0x43, 0xca, - 0x5b, 0xf4, 0x5b, 0x5b, 0x44, 0x43, 0x57, 0x6b, 0x30, 0x2b, 0x46, 0xd9, 0x52, 0x94, 0xae, 0x29, 0x28, 0x05, 0xa3, - 0xcb, 0xb5, 0xb3, 0x70, 0x5f, 0x0b, 0xef, 0xc2, 0x92, 0xa9, 0xd5, 0x22, 0xa5, 0x84, 0xf2, 0xa6, 0xa2, 0xa5, 0x84, - 0x91, 0xd4, 0xf0, 0xd4, 0xae, 0x17, 0x78, 0x9c, 0xe7, 0x41, 0xd4, 0xf2, 0x02, 0x3b, 0xad, 0xc9, 0x29, 0x38, 0x7a, - 0xe9, 0x9c, 0x9a, 0x02, 0xff, 0x98, 0x49, 0x10, 0xd3, 0xa1, 0xbc, 0xdf, 0xe0, 0xe6, 0xff, 0x47, 0xc9, 0x02, 0x87, - 0x6f, 0xbd, 0xc2, 0x6d, 0xf4, 0x8f, 0xd2, 0xa5, 0xa5, 0xcf, 0x84, 0xeb, 0xea, 0xe2, 0x48, 0x7b, 0xb3, 0x51, 0xb2, - 0xcc, 0xf2, 0xf4, 0x8d, 0x48, 0x79, 0x45, 0xa4, 0x09, 0x46, 0xc5, 0x4e, 0x2a, 0xef, 0x86, 0x07, 0x46, 0x8c, 0xde, - 0x8d, 0xef, 0xc7, 0x0c, 0x64, 0xc3, 0x60, 0xf5, 0xcd, 0x52, 0x91, 0xac, 0xaf, 0x01, 0x53, 0x44, 0xca, 0x4f, 0x5e, - 0xe4, 0x1c, 0x9e, 0x42, 0x75, 0xfd, 0x02, 0xb7, 0xb9, 0xca, 0xf5, 0x39, 0xff, 0x31, 0xa3, 0x3f, 0x22, 0xd0, 0x49, - 0xbc, 0x02, 0xb9, 0xc7, 0x33, 0xa8, 0x1b, 0x61, 0x6a, 0x39, 0x06, 0x07, 0x42, 0x34, 0x90, 0xa2, 0x66, 0x81, 0x84, - 0xba, 0xd0, 0xc0, 0x1a, 0xf2, 0x82, 0x39, 0xbc, 0xc8, 0x45, 0xf2, 0x71, 0xaa, 0x7d, 0xe6, 0x87, 0x31, 0xc6, 0x4c, - 0x0e, 0x06, 0x61, 0x3d, 0x0b, 0x86, 0xe3, 0xd1, 0xe4, 0xe8, 0x29, 0x9c, 0xdb, 0xc1, 0x38, 0x20, 0x83, 0xa0, 0xa9, - 0x56, 0x71, 0x41, 0xab, 0x9b, 0x2b, 0x53, 0x06, 0x7e, 0xdc, 0x04, 0x83, 0x7f, 0x94, 0x8e, 0xe2, 0x1d, 0x34, 0x27, - 0xe7, 0x22, 0x04, 0x1b, 0xfb, 0x35, 0x01, 0x49, 0x59, 0x4f, 0xf1, 0x93, 0xea, 0x70, 0x63, 0x52, 0xfb, 0xa7, 0x0f, - 0x2f, 0x38, 0xec, 0x90, 0x40, 0x81, 0x34, 0x9e, 0x66, 0xa3, 0x57, 0x52, 0x91, 0xfb, 0xae, 0xe4, 0x70, 0x67, 0xee, - 0x59, 0xd3, 0x23, 0xab, 0x90, 0xf0, 0xb3, 0x80, 0x1b, 0xf9, 0xab, 0xe2, 0x26, 0xce, 0xb3, 0xf4, 0xc0, 0x7f, 0x73, - 0x50, 0xdd, 0x17, 0x75, 0x7c, 0x37, 0x0a, 0xb4, 0x35, 0x21, 0x77, 0x55, 0x4f, 0x80, 0x9e, 0x00, 0x5b, 0x00, 0x0c, - 0x88, 0x77, 0xcc, 0x4c, 0x66, 0x3c, 0x02, 0x8f, 0x40, 0xdf, 0x07, 0xb2, 0xbc, 0xb7, 0x2e, 0x49, 0xee, 0x66, 0x2a, - 0xcc, 0x55, 0xaf, 0xd8, 0x29, 0xc8, 0x78, 0xb5, 0x15, 0xbb, 0x6e, 0x7d, 0xe6, 0x4d, 0x87, 0x57, 0xe0, 0x85, 0x00, - 0xb7, 0xc8, 0x7e, 0xdf, 0x17, 0x54, 0x56, 0x5a, 0x45, 0xbc, 0x93, 0xdc, 0xa0, 0x7f, 0xbb, 0x33, 0x36, 0x92, 0xe4, - 0x56, 0x0f, 0x0f, 0xa0, 0xca, 0xe4, 0x5c, 0x71, 0x3b, 0x87, 0xa8, 0xad, 0xbb, 0x71, 0xc0, 0x6a, 0x83, 0x76, 0x59, - 0x73, 0x04, 0x17, 0x5e, 0x1c, 0x64, 0x90, 0x13, 0x67, 0x65, 0x24, 0xd5, 0xb8, 0x9a, 0xd4, 0x82, 0x4f, 0xf2, 0x74, - 0x0f, 0x59, 0xea, 0x09, 0x50, 0xe4, 0x38, 0x16, 0x43, 0xba, 0xf1, 0x26, 0xf0, 0xf8, 0xbd, 0x08, 0x41, 0x9a, 0xb6, - 0xdd, 0xfa, 0x23, 0x50, 0x74, 0x0f, 0x4c, 0x41, 0x9a, 0x46, 0x9b, 0x1a, 0x28, 0xa8, 0x3d, 0xd4, 0x48, 0x45, 0x9c, - 0x9d, 0xbc, 0x06, 0x1d, 0x22, 0xf8, 0x7e, 0xa7, 0x59, 0xd5, 0xf1, 0x62, 0x42, 0xf0, 0xe4, 0x7d, 0x71, 0x97, 0x55, - 0x75, 0x15, 0xbd, 0x4f, 0xd1, 0x10, 0x2a, 0x11, 0x45, 0xf4, 0x12, 0xe2, 0xe9, 0x55, 0xf8, 0xbb, 0x8a, 0x7e, 0x4a, - 0x69, 0x9c, 0xa6, 0x98, 0xfe, 0xbc, 0x84, 0x9f, 0xcf, 0x00, 0xd5, 0x11, 0x77, 0x42, 0x74, 0x21, 0xc0, 0x5e, 0x0d, - 0xa2, 0x59, 0xd5, 0x1c, 0x30, 0x34, 0xa3, 0xfb, 0x8a, 0x22, 0x46, 0x1b, 0x66, 0xff, 0xa1, 0x44, 0xa1, 0x90, 0x2c, - 0xe6, 0xd7, 0xca, 0x3c, 0x44, 0x3f, 0x62, 0x91, 0xa7, 0xef, 0x5e, 0xe9, 0x21, 0x8d, 0xee, 0x05, 0x55, 0x5b, 0x1b, - 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xad, 0xe9, 0x79, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, 0x4f, 0xbc, 0x7b, 0xf5, 0x4c, - 0x5a, 0x98, 0x3c, 0xcf, 0x40, 0x71, 0x70, 0xfa, 0xee, 0xd5, 0x6b, 0x91, 0xae, 0x73, 0x1e, 0x9d, 0x0b, 0x24, 0xad, - 0xa7, 0xef, 0x5e, 0xfd, 0x8c, 0xe6, 0x5e, 0x3f, 0x95, 0xf0, 0xfe, 0x25, 0xf0, 0x96, 0x51, 0xbc, 0x86, 0x3e, 0xc9, - 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd4, 0x5a, 0x45, 0xbf, 0xa4, 0x8d, 0x23, 0xad, 0xfa, 0x67, 0xe9, 0x52, 0x3b, 0x47, - 0xc0, 0x73, 0x97, 0x67, 0xc5, 0xc7, 0xc8, 0x88, 0x76, 0x82, 0xe8, 0xcb, 0x83, 0xbb, 0xeb, 0xbc, 0xa8, 0x22, 0x7c, - 0xc1, 0xd0, 0x2e, 0x28, 0x3a, 0x3c, 0xbc, 0xbd, 0xbd, 0x1d, 0xdd, 0x7e, 0x35, 0x12, 0xe5, 0xd5, 0xe1, 0xe4, 0xdb, - 0x6f, 0xbf, 0x3d, 0xc4, 0xb7, 0xc1, 0x97, 0x6d, 0xb7, 0xf7, 0x9a, 0xf0, 0x01, 0x0b, 0x10, 0xa1, 0xfa, 0x4b, 0xb8, - 0xa2, 0x80, 0x16, 0x6e, 0xf0, 0x65, 0xf0, 0xa5, 0x3a, 0x74, 0xbe, 0x3c, 0xae, 0x6e, 0xae, 0x64, 0xf9, 0x5d, 0x25, - 0x1f, 0x8d, 0xc7, 0xe3, 0x43, 0x90, 0x40, 0x7d, 0x39, 0xe0, 0x83, 0xe0, 0x24, 0x18, 0x64, 0x70, 0xa1, 0xa9, 0x6e, - 0xae, 0x4e, 0x02, 0xc7, 0x34, 0xd7, 0x63, 0x11, 0x2d, 0x88, 0x4b, 0x70, 0x78, 0x45, 0x83, 0x2f, 0x03, 0x62, 0x53, - 0xbe, 0x80, 0x94, 0x2f, 0x8e, 0x9e, 0xba, 0x69, 0xff, 0x4b, 0xa6, 0x7d, 0xe5, 0xa6, 0x1d, 0x63, 0xda, 0x57, 0xcf, - 0xdc, 0xb4, 0x13, 0x99, 0xf6, 0xc2, 0x4d, 0xfb, 0xdf, 0xd5, 0x00, 0x52, 0x0f, 0x5c, 0xeb, 0xbf, 0x0b, 0xa7, 0x35, - 0x78, 0x0a, 0x45, 0xd9, 0x75, 0x7c, 0xc5, 0xa1, 0xd1, 0x83, 0xbb, 0xeb, 0x9c, 0x06, 0x03, 0x6c, 0xaf, 0x63, 0xe4, - 0xe1, 0x7c, 0xf0, 0xe5, 0xba, 0xcc, 0xc3, 0xe0, 0xcb, 0x01, 0x16, 0x32, 0xf8, 0x32, 0x20, 0x5f, 0xaa, 0x23, 0xed, - 0xae, 0x62, 0x9b, 0xc0, 0x86, 0x22, 0x1d, 0x9a, 0x00, 0x61, 0xae, 0x34, 0xae, 0xa1, 0x7f, 0x96, 0xdd, 0xd9, 0xf0, - 0x96, 0x28, 0xdd, 0x74, 0x83, 0x86, 0xbe, 0x05, 0xef, 0x04, 0x68, 0x54, 0x14, 0xdc, 0xc4, 0x65, 0x38, 0x1c, 0x56, - 0x37, 0x57, 0x04, 0xec, 0x32, 0x57, 0x3c, 0xae, 0xa3, 0xa0, 0x10, 0x43, 0xf9, 0x33, 0x90, 0x91, 0xaf, 0x02, 0x04, - 0x44, 0x82, 0xff, 0x82, 0x86, 0xbe, 0x13, 0x6c, 0x13, 0x0c, 0x6f, 0xf9, 0xc5, 0xc7, 0xac, 0x1e, 0x4a, 0xd1, 0xe2, - 0x5d, 0x45, 0xe1, 0x07, 0xfc, 0xb5, 0x55, 0x47, 0x7f, 0x82, 0x1b, 0xb7, 0xaf, 0x61, 0x7f, 0x27, 0x2c, 0x8b, 0xfa, - 0x4e, 0xcc, 0xb3, 0xc5, 0xb4, 0x75, 0xa0, 0xbf, 0x15, 0xa4, 0x9e, 0x67, 0x83, 0x60, 0x18, 0x0c, 0xf8, 0x82, 0xbd, - 0x15, 0x73, 0xee, 0x98, 0x4f, 0x3d, 0x12, 0xee, 0x34, 0xcf, 0xb2, 0x01, 0xf8, 0xa6, 0x20, 0x3f, 0x72, 0xf8, 0xdf, - 0xf3, 0x21, 0x0a, 0x0f, 0x07, 0x8f, 0x0e, 0xc9, 0x2c, 0x58, 0xdd, 0xa1, 0x47, 0x67, 0x14, 0x64, 0xc5, 0x92, 0x97, - 0x59, 0xed, 0x2c, 0x95, 0xfb, 0x75, 0xdb, 0xcb, 0x63, 0xef, 0xd9, 0xbc, 0x8a, 0x8b, 0x40, 0x9e, 0x73, 0xa0, 0x78, - 0x43, 0xd9, 0x53, 0xe1, 0x4b, 0x48, 0x95, 0x21, 0x6f, 0x58, 0x0c, 0x58, 0x70, 0xdc, 0x1b, 0x0e, 0x0f, 0x82, 0x81, - 0x55, 0xe7, 0x0e, 0x82, 0x83, 0xe1, 0xf0, 0x24, 0xb0, 0xf7, 0xa1, 0x6c, 0x64, 0xef, 0x8c, 0xb4, 0x64, 0xff, 0x2c, - 0xc3, 0x82, 0x82, 0x78, 0x4c, 0x28, 0xf1, 0x97, 0x02, 0x97, 0x19, 0x00, 0xf4, 0x91, 0x94, 0x80, 0x69, 0x58, 0x99, - 0x01, 0x84, 0xe6, 0xa6, 0x31, 0x3b, 0x07, 0xe6, 0x91, 0x26, 0x20, 0xde, 0x03, 0x8a, 0x01, 0x88, 0x25, 0x01, 0xce, - 0x5d, 0x10, 0xc5, 0xaa, 0x90, 0x47, 0x00, 0x7a, 0x8f, 0x3f, 0x89, 0x2e, 0x05, 0x93, 0x54, 0xac, 0x42, 0x10, 0xc4, - 0xf1, 0xd9, 0x5d, 0xd5, 0x9a, 0x9c, 0x25, 0x3a, 0x98, 0x91, 0x04, 0xd8, 0x10, 0x0d, 0x3b, 0x07, 0xf7, 0x73, 0x50, - 0x7a, 0x18, 0xbd, 0x13, 0x72, 0xc1, 0xf7, 0xdc, 0xb2, 0x50, 0x77, 0x70, 0xf5, 0x84, 0x83, 0xe0, 0x9e, 0x2b, 0x16, - 0x60, 0x54, 0x97, 0xeb, 0xaa, 0xe6, 0xe9, 0x87, 0xfb, 0x15, 0xc4, 0xbe, 0xc3, 0x01, 0x7d, 0x27, 0xf2, 0x2c, 0xb9, - 0x0f, 0xad, 0x3d, 0xd7, 0x46, 0xa6, 0xff, 0xf0, 0xe1, 0xf5, 0x4f, 0x11, 0x88, 0x1c, 0x1b, 0x4d, 0xe9, 0xef, 0x39, - 0x9e, 0x4d, 0x6e, 0x84, 0x27, 0x77, 0x63, 0xdf, 0x73, 0x73, 0x7a, 0xf4, 0xfb, 0x50, 0x37, 0xbd, 0xe7, 0xb3, 0x7b, - 0x3e, 0xb2, 0xc5, 0xa1, 0xba, 0xc2, 0x7e, 0x7d, 0xbb, 0x76, 0x8d, 0x90, 0x1e, 0x9e, 0x67, 0xca, 0xbd, 0xf9, 0x51, - 0x0e, 0x86, 0x41, 0x30, 0x55, 0x42, 0x49, 0x88, 0xba, 0xc1, 0xa4, 0x80, 0x21, 0x3a, 0x50, 0xcb, 0x6a, 0x8a, 0x9c, - 0x9b, 0x1c, 0x59, 0x78, 0x3f, 0x60, 0x4a, 0xe8, 0xe0, 0xe5, 0x90, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc0, 0x6f, 0x15, - 0x30, 0xfd, 0x72, 0x51, 0x59, 0x07, 0xd1, 0x03, 0x30, 0xc6, 0x2d, 0x78, 0x09, 0x5d, 0x61, 0x37, 0x6b, 0x19, 0x15, - 0x03, 0xc1, 0xe3, 0x90, 0x03, 0x74, 0xb0, 0x0b, 0x5a, 0x56, 0x96, 0xf2, 0x56, 0x65, 0x2d, 0x55, 0xe4, 0x65, 0x28, - 0xab, 0x62, 0x89, 0xf9, 0x5e, 0xb0, 0x1f, 0x4a, 0xf4, 0x2c, 0x9f, 0x56, 0x5d, 0xf0, 0x42, 0x28, 0xc1, 0xb2, 0x5d, - 0xef, 0x44, 0x20, 0xea, 0x4c, 0x75, 0xae, 0xfa, 0x0a, 0xc7, 0x8e, 0xa7, 0xaf, 0x45, 0xca, 0x95, 0x09, 0x85, 0xe2, - 0xf3, 0x85, 0xab, 0x98, 0x28, 0xd9, 0x2d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd7, 0x6a, 0x33, 0x48, 0xd1, 0x31, - 0x6f, 0x50, 0x70, 0x2d, 0x15, 0x0a, 0x5a, 0x7b, 0x1b, 0x7f, 0x82, 0x23, 0x37, 0xba, 0x3d, 0xf4, 0x7e, 0xab, 0xe3, - 0xab, 0x37, 0xe8, 0xdb, 0x69, 0x7e, 0x8e, 0x6a, 0xf1, 0xcb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, 0xe0, 0xd2, - 0x42, 0x3d, 0x67, 0xef, 0x4e, 0xdf, 0x80, 0x1f, 0x25, 0xfe, 0xfe, 0xf5, 0xfb, 0xa0, 0x21, 0xd3, 0x78, 0x56, 0xea, - 0x0f, 0x4d, 0x0e, 0x08, 0x4d, 0x62, 0xd3, 0xcc, 0xfb, 0x59, 0xec, 0xb3, 0xef, 0x8a, 0xad, 0xa7, 0xa5, 0x8f, 0x24, - 0xa5, 0xb9, 0x7d, 0x30, 0x20, 0x50, 0x07, 0x88, 0xe4, 0xec, 0x4b, 0x1a, 0x43, 0x9a, 0xcb, 0xec, 0xbb, 0x11, 0xf1, - 0x5e, 0xec, 0x84, 0x10, 0xe3, 0x12, 0x8b, 0x46, 0x0d, 0xf9, 0x8c, 0x47, 0xd2, 0xb0, 0xe8, 0x3d, 0x26, 0x10, 0x6b, - 0x38, 0x2d, 0xdf, 0x23, 0xe6, 0x31, 0xde, 0x0d, 0x94, 0xec, 0x21, 0xca, 0xa8, 0xcd, 0xee, 0x59, 0x7c, 0x7f, 0x5c, - 0x87, 0x99, 0xb1, 0xbc, 0x1c, 0xc2, 0xdf, 0x40, 0x19, 0x80, 0x53, 0x8e, 0x2c, 0x5f, 0xad, 0x37, 0xba, 0x5c, 0x62, - 0x6a, 0x13, 0x41, 0x2c, 0x1e, 0x95, 0x0e, 0x6b, 0x57, 0xa5, 0xaa, 0x5d, 0x6d, 0x7d, 0x26, 0x7a, 0x35, 0x68, 0xe5, - 0xda, 0xf6, 0x78, 0x08, 0x77, 0xa9, 0xa4, 0x15, 0x26, 0xb0, 0x5e, 0x65, 0x15, 0x2a, 0xd8, 0x9c, 0x80, 0x06, 0xd7, - 0x22, 0x05, 0xe0, 0x2c, 0xa5, 0x46, 0xa3, 0x5a, 0xd8, 0x67, 0xe4, 0x7c, 0x16, 0x5b, 0x0b, 0xf1, 0xb4, 0x00, 0x0c, - 0xd7, 0xc7, 0xa0, 0xe4, 0xdd, 0x18, 0x94, 0xd3, 0x8f, 0x12, 0xde, 0x3a, 0x38, 0xaf, 0x96, 0x71, 0x2a, 0x6e, 0x01, - 0x8b, 0x31, 0x70, 0x53, 0xb1, 0x54, 0x27, 0x21, 0x59, 0xf2, 0xe4, 0x23, 0x5a, 0x6d, 0xa4, 0x01, 0x70, 0x95, 0x53, - 0x6d, 0xb9, 0x27, 0x41, 0x42, 0x6d, 0x29, 0x32, 0x21, 0xae, 0xeb, 0x38, 0x59, 0x9e, 0x61, 0x6a, 0xb8, 0x81, 0x5e, - 0x44, 0x81, 0x58, 0xf1, 0x02, 0x48, 0x7a, 0xce, 0xfe, 0x95, 0x29, 0xac, 0xf1, 0x67, 0x02, 0x05, 0x4c, 0x0a, 0x35, - 0x18, 0x2b, 0x65, 0x2f, 0x84, 0x8e, 0xf6, 0x16, 0x04, 0x8d, 0x7d, 0xf9, 0x27, 0xd4, 0xfd, 0x0c, 0x5a, 0x11, 0x7a, - 0x60, 0x88, 0xe2, 0x02, 0x77, 0x68, 0x6a, 0x96, 0x9c, 0x03, 0x8c, 0x58, 0x18, 0xef, 0xb3, 0xc6, 0x6c, 0xf5, 0x67, - 0x4b, 0xc0, 0x36, 0x4d, 0xb5, 0x4f, 0x61, 0x98, 0x10, 0x1d, 0x1b, 0xd8, 0x28, 0x2b, 0xcd, 0x86, 0xd2, 0xed, 0xa4, - 0x4b, 0xe6, 0xb4, 0x70, 0x9a, 0xf7, 0x18, 0x5b, 0x8e, 0x64, 0xee, 0x7e, 0x3f, 0xd4, 0x3f, 0x59, 0x4e, 0x9f, 0xa9, - 0x90, 0xcd, 0xce, 0x78, 0xd0, 0x9c, 0x28, 0x75, 0x55, 0x47, 0x3f, 0xa0, 0x03, 0x30, 0xd3, 0x06, 0x20, 0xd3, 0x06, - 0x9b, 0x76, 0x95, 0xa8, 0xb8, 0x24, 0x61, 0xa9, 0x24, 0xb0, 0xb3, 0x7d, 0xc9, 0xce, 0x26, 0x20, 0x8e, 0xe1, 0xae, - 0xa3, 0xc5, 0x4e, 0x88, 0x0f, 0x6f, 0x71, 0x90, 0x80, 0xa8, 0x43, 0x56, 0x97, 0x90, 0x8d, 0x36, 0x74, 0x71, 0x2f, - 0x4a, 0x61, 0xc2, 0x5a, 0x26, 0x55, 0x89, 0x0e, 0x82, 0x54, 0xed, 0xb6, 0x08, 0x2c, 0x51, 0xb0, 0x03, 0xd8, 0x7b, - 0x3b, 0xea, 0x7a, 0xd4, 0x64, 0x75, 0xf2, 0x25, 0xf8, 0x38, 0xcd, 0xba, 0x0a, 0xd2, 0x0b, 0xbb, 0x2e, 0xd7, 0x3c, - 0x50, 0xb1, 0xa9, 0xa4, 0x31, 0x71, 0x97, 0x16, 0x19, 0xe2, 0x01, 0x63, 0x2c, 0x5d, 0x08, 0xe4, 0x9b, 0xed, 0x8e, - 0x9b, 0x9a, 0x20, 0xf4, 0x13, 0xd6, 0x94, 0xc0, 0x4e, 0x67, 0x7b, 0x6a, 0xfc, 0x7c, 0x40, 0xc4, 0x61, 0x40, 0x81, - 0x64, 0xe3, 0x90, 0xe6, 0x48, 0x5f, 0x90, 0x34, 0x61, 0x60, 0x68, 0xc9, 0x73, 0x82, 0xac, 0x28, 0x74, 0x6c, 0x5d, - 0x95, 0x71, 0xae, 0x08, 0x73, 0xb4, 0xe4, 0x94, 0xf8, 0x9c, 0x20, 0x13, 0xdb, 0xd3, 0x36, 0x3d, 0x19, 0x96, 0x92, - 0x05, 0xfa, 0x57, 0x10, 0x25, 0xf6, 0x4c, 0x33, 0x2a, 0x07, 0xed, 0x02, 0x16, 0x28, 0xe5, 0x7b, 0xd0, 0x78, 0x6b, - 0x68, 0xa3, 0x60, 0x88, 0xed, 0xfe, 0x04, 0xfb, 0xb5, 0x76, 0x5a, 0x97, 0x29, 0x96, 0x93, 0x29, 0x44, 0x7b, 0x21, - 0xfd, 0x1b, 0x45, 0xa2, 0x3b, 0x45, 0x68, 0x12, 0xd6, 0x51, 0xf6, 0xa4, 0x4d, 0x0d, 0xa0, 0xa7, 0x4e, 0xc0, 0xf3, - 0xce, 0xb5, 0x0c, 0xbb, 0x48, 0xf5, 0x57, 0x06, 0x9f, 0x52, 0x0d, 0x82, 0x14, 0xb5, 0x49, 0xc1, 0x9c, 0xd7, 0xa1, - 0xa4, 0xce, 0x9c, 0xb6, 0xcc, 0xa8, 0x3a, 0x2a, 0x42, 0xca, 0x09, 0xfe, 0x93, 0x57, 0x42, 0x11, 0x9b, 0x30, 0xc1, - 0x03, 0x1f, 0xe6, 0x19, 0x36, 0xf0, 0x76, 0xfb, 0x2e, 0x0d, 0x93, 0x36, 0xdb, 0x90, 0x82, 0xb4, 0x42, 0xc7, 0xc5, - 0x80, 0xca, 0x5e, 0xe1, 0x7e, 0xc1, 0x76, 0xd2, 0x14, 0x3c, 0x08, 0xbd, 0x06, 0x26, 0x76, 0x75, 0xf1, 0x75, 0x98, - 0xd0, 0x70, 0x49, 0x95, 0xb3, 0x93, 0x92, 0x34, 0xb7, 0xd7, 0xe5, 0xa5, 0xe9, 0x83, 0x8a, 0x1d, 0xd6, 0x35, 0x3c, - 0xd0, 0x3c, 0xbf, 0x8b, 0x2b, 0xa6, 0x68, 0xa2, 0xb6, 0x1e, 0x92, 0x96, 0x1c, 0xeb, 0x66, 0xba, 0xc2, 0xd5, 0x32, - 0x53, 0xc0, 0xee, 0x02, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x89, 0xcd, 0x66, 0xab, 0x86, 0x4c, 0xf3, - 0x7d, 0xd9, 0x72, 0x1d, 0x10, 0xce, 0x50, 0xdf, 0xdc, 0x25, 0xc7, 0x8a, 0xb6, 0xb9, 0x49, 0x80, 0xe3, 0xed, 0x14, - 0x90, 0x74, 0x2c, 0x41, 0x1b, 0xdf, 0xd2, 0x1d, 0x44, 0xaa, 0xa7, 0x82, 0xee, 0x9d, 0x2f, 0xd2, 0xf8, 0x5f, 0x80, - 0x6d, 0xd4, 0x46, 0x9b, 0x66, 0x65, 0xeb, 0x30, 0x91, 0x16, 0xd6, 0xc8, 0x42, 0x2e, 0xc1, 0x07, 0x73, 0xb7, 0xa9, - 0xd3, 0xd3, 0x0e, 0x22, 0xec, 0x76, 0xd1, 0xe1, 0x11, 0xc6, 0x92, 0x35, 0x48, 0x34, 0xab, 0xb0, 0xa6, 0xfe, 0x72, - 0x88, 0x72, 0xaa, 0x97, 0x4c, 0xb4, 0xa4, 0x2e, 0xa5, 0x88, 0x52, 0x30, 0x37, 0x9e, 0x16, 0x9e, 0x29, 0x21, 0x42, - 0x56, 0x08, 0x0b, 0x54, 0x6b, 0xa0, 0xa5, 0x7c, 0xd0, 0xeb, 0xd0, 0xc9, 0x42, 0x63, 0x0a, 0xa2, 0x8f, 0x48, 0x73, - 0x23, 0x96, 0x8c, 0xee, 0x8e, 0x51, 0x4c, 0x20, 0x54, 0xb5, 0x93, 0x17, 0x56, 0x9f, 0x92, 0x6d, 0x75, 0x10, 0xd7, - 0x98, 0x26, 0x7b, 0x08, 0x6a, 0x8c, 0x82, 0x36, 0xab, 0x1b, 0xfd, 0xa5, 0x0c, 0x5d, 0xbb, 0x70, 0xec, 0x46, 0x49, - 0x04, 0x44, 0x60, 0x75, 0x9a, 0x8a, 0x01, 0x59, 0xe7, 0xb1, 0x8d, 0xd0, 0xa4, 0xba, 0x85, 0x28, 0x6f, 0x54, 0x34, - 0x1f, 0xd7, 0x21, 0xd9, 0x6e, 0xb1, 0x2c, 0xf0, 0x65, 0x3f, 0x5b, 0xef, 0x81, 0xfc, 0x7e, 0xbd, 0xfe, 0x24, 0xe4, - 0xf7, 0xab, 0xec, 0x73, 0x20, 0xbf, 0x5f, 0xaf, 0xff, 0xa7, 0x21, 0xbf, 0xcf, 0xd6, 0x0e, 0xe4, 0xb7, 0x1c, 0x8c, - 0xdf, 0x4a, 0x16, 0xbc, 0x7d, 0x13, 0xd0, 0xe7, 0x82, 0x05, 0x6f, 0x5f, 0xbe, 0x74, 0x84, 0xe9, 0xdf, 0xe9, 0x38, - 0x2f, 0x5a, 0x16, 0x8c, 0xb8, 0x2d, 0xf0, 0x0a, 0xb5, 0x4e, 0x2e, 0x50, 0x51, 0x06, 0xc0, 0xeb, 0xd5, 0x3f, 0xb2, - 0x7a, 0x19, 0x06, 0x87, 0x01, 0x99, 0x59, 0x48, 0xd0, 0xe1, 0x04, 0x6e, 0x6f, 0x68, 0x64, 0x59, 0x7f, 0x16, 0x7c, - 0xf8, 0x68, 0x34, 0x8a, 0xcb, 0x2b, 0xbc, 0xd4, 0xe9, 0x8d, 0x84, 0x80, 0xc7, 0x19, 0xaf, 0x4c, 0x88, 0x88, 0x65, - 0x5c, 0x9d, 0xab, 0xd8, 0x2c, 0x95, 0xd9, 0x8a, 0x10, 0x71, 0xfe, 0x1c, 0x70, 0xea, 0xcd, 0xde, 0x8c, 0xb1, 0x1f, - 0x92, 0x23, 0x56, 0x01, 0x64, 0x9f, 0xad, 0xd5, 0xbb, 0x8b, 0xb8, 0xe2, 0xef, 0xe2, 0x7a, 0xc9, 0xa0, 0x97, 0x70, - 0x17, 0x29, 0x78, 0x52, 0x3b, 0x6c, 0x93, 0x04, 0x2a, 0xcf, 0x14, 0x50, 0x79, 0xc7, 0x7b, 0x1a, 0x9a, 0x61, 0x51, - 0x3e, 0xc0, 0x5a, 0xba, 0x9c, 0x81, 0xd1, 0xe2, 0x8b, 0x1b, 0x5e, 0xd4, 0x3f, 0x01, 0x9e, 0x7a, 0xc1, 0x4b, 0xb8, - 0x25, 0x20, 0x17, 0xeb, 0x39, 0x21, 0xd0, 0xca, 0xf5, 0xec, 0x90, 0x51, 0x63, 0xb4, 0x68, 0xc2, 0xeb, 0x37, 0xde, - 0x84, 0xd0, 0xbb, 0x13, 0x74, 0x45, 0x18, 0x09, 0xef, 0xcf, 0x35, 0x3f, 0xcf, 0xc0, 0x7c, 0xbe, 0x02, 0x28, 0x0d, - 0x84, 0x43, 0x65, 0x52, 0x6e, 0x81, 0x09, 0x1b, 0x6d, 0xae, 0x94, 0xa5, 0x0e, 0x52, 0x29, 0x95, 0x70, 0xba, 0x15, - 0x4d, 0x05, 0xe0, 0x70, 0x47, 0x02, 0xc0, 0x4c, 0x4d, 0x61, 0x10, 0xdd, 0x36, 0xa5, 0x59, 0x1a, 0x59, 0x45, 0x9a, - 0xc5, 0x27, 0xa5, 0x12, 0x74, 0xfa, 0x3c, 0x89, 0x6b, 0x7e, 0x25, 0x4a, 0x08, 0x85, 0xdb, 0x4a, 0x69, 0x0c, 0x16, - 0x80, 0x3c, 0xee, 0xac, 0xcd, 0xd6, 0xac, 0x94, 0x29, 0xe7, 0xc5, 0xfa, 0x9a, 0x97, 0x59, 0x72, 0xbe, 0xcc, 0xaa, - 0x5a, 0x94, 0xf7, 0x6c, 0xae, 0xb2, 0x2e, 0xa2, 0x6a, 0xa4, 0x24, 0x5e, 0xe7, 0x35, 0xbf, 0x5e, 0x41, 0xe8, 0x87, - 0x75, 0x09, 0xac, 0xe7, 0xde, 0x2f, 0x65, 0x64, 0xd2, 0xb0, 0xf3, 0x3b, 0xb2, 0x00, 0xbd, 0x2b, 0xac, 0x11, 0xb9, - 0x00, 0x98, 0x5e, 0x33, 0xa7, 0x92, 0xaa, 0x94, 0xfe, 0x6b, 0x8d, 0x33, 0xef, 0x2f, 0xaa, 0x71, 0x6b, 0xed, 0x19, - 0xad, 0xad, 0x9f, 0x2a, 0xe1, 0x94, 0x80, 0x12, 0xb1, 0x13, 0x5c, 0x31, 0x29, 0x5d, 0x1b, 0xb4, 0x16, 0xb0, 0xac, - 0xc0, 0x1c, 0x59, 0x71, 0x75, 0x7e, 0x2b, 0x65, 0x35, 0x3d, 0x49, 0xcd, 0xd2, 0x28, 0x96, 0x28, 0x42, 0x4b, 0x16, - 0xae, 0x59, 0xb2, 0x27, 0xd7, 0x3a, 0x4a, 0x3c, 0x3c, 0xb0, 0xb8, 0x3d, 0xe8, 0xc7, 0x49, 0x3b, 0x65, 0xbb, 0xdd, - 0xc9, 0x04, 0x6c, 0x48, 0x2b, 0x09, 0x22, 0x83, 0x2c, 0x67, 0xc3, 0x49, 0x04, 0x70, 0x2d, 0x8a, 0x84, 0xfe, 0xb9, - 0xe6, 0x1a, 0xd0, 0x3e, 0x54, 0x5e, 0x85, 0x72, 0x15, 0xcd, 0xc1, 0xce, 0xcb, 0xed, 0x35, 0x04, 0x96, 0xe9, 0x9c, - 0x97, 0xc5, 0xfe, 0x35, 0xa0, 0xcc, 0x91, 0xd5, 0x0b, 0xb2, 0x6f, 0xc6, 0x55, 0xb6, 0x07, 0xa7, 0xb7, 0x35, 0x07, - 0x7b, 0x5b, 0xa3, 0x50, 0x7a, 0x13, 0x1e, 0x0e, 0x9f, 0x8e, 0x8d, 0x3f, 0x03, 0xae, 0x72, 0xf3, 0x5b, 0xee, 0x04, - 0xfb, 0x6c, 0x76, 0x03, 0xf5, 0x5d, 0x22, 0xda, 0x35, 0xd2, 0x6a, 0xcf, 0xb8, 0x35, 0xa4, 0xb1, 0x2b, 0xcd, 0x88, - 0xb9, 0x7e, 0x97, 0x47, 0xeb, 0xf9, 0xa3, 0x4d, 0xa6, 0xaa, 0x6c, 0x7e, 0xcf, 0x4c, 0x50, 0x3c, 0x8f, 0x4c, 0x35, - 0x6a, 0x0d, 0xba, 0x98, 0x74, 0x1d, 0xd9, 0xd4, 0x8c, 0xb2, 0xac, 0x93, 0xd6, 0x8d, 0xe4, 0x23, 0x97, 0x31, 0xc2, - 0xba, 0xb3, 0xf0, 0x3b, 0x9e, 0x84, 0x5d, 0x0d, 0x93, 0xd7, 0x10, 0xdd, 0x05, 0x84, 0xe9, 0x04, 0xe5, 0x43, 0xf8, - 0xfb, 0xa3, 0x8d, 0x4f, 0x3b, 0x9b, 0x43, 0xe7, 0x33, 0xfc, 0x9d, 0xa5, 0xf0, 0xb7, 0x6e, 0x7e, 0xa7, 0x9b, 0x6b, - 0x5e, 0x2f, 0x45, 0x1a, 0x05, 0xef, 0xde, 0x9e, 0x7d, 0x08, 0x14, 0xfc, 0x3b, 0x5e, 0x82, 0xb4, 0xda, 0x5b, 0x03, - 0x4d, 0x81, 0x1a, 0x28, 0x17, 0x57, 0x88, 0x80, 0xa8, 0x20, 0xf4, 0xcf, 0x96, 0xe2, 0xf6, 0x34, 0xcf, 0x5d, 0x4e, - 0x5d, 0x53, 0x77, 0xc5, 0xbc, 0x7a, 0xa4, 0x31, 0x04, 0x81, 0xe3, 0x28, 0xab, 0xce, 0x95, 0x8a, 0x28, 0x3d, 0xbf, - 0xb8, 0x3f, 0x57, 0x62, 0x28, 0x03, 0x41, 0xf9, 0xec, 0xf7, 0xe3, 0x34, 0xbb, 0x39, 0xc0, 0x23, 0x88, 0x05, 0x60, - 0xbf, 0x9f, 0xf3, 0x8b, 0x75, 0x5d, 0x8b, 0x62, 0x58, 0x8a, 0xdb, 0xe0, 0xe4, 0x58, 0x3e, 0xe8, 0x0c, 0xb1, 0x7c, - 0x0c, 0x0e, 0xfe, 0x2b, 0xc9, 0xb3, 0xe4, 0x23, 0x0b, 0x1e, 0x6d, 0x32, 0x76, 0xd2, 0x3a, 0x68, 0xc6, 0x4d, 0x70, - 0x02, 0x6d, 0x3d, 0x38, 0xcd, 0xf3, 0xe3, 0x43, 0xf9, 0xc5, 0xc9, 0xf1, 0x61, 0x9a, 0xdd, 0x9c, 0x38, 0xd1, 0x00, - 0xac, 0x71, 0x2f, 0xe2, 0xae, 0xd9, 0xcb, 0x3b, 0x78, 0xf1, 0x26, 0x3c, 0x34, 0xec, 0x0e, 0x88, 0x8c, 0x74, 0x2c, - 0x15, 0x14, 0x33, 0x85, 0x31, 0x1c, 0xee, 0xdb, 0x6d, 0x68, 0x2c, 0x8f, 0x12, 0x07, 0x96, 0xa7, 0x04, 0x76, 0x08, - 0xb3, 0xd0, 0x84, 0xd0, 0xa4, 0x21, 0xa1, 0x06, 0x0f, 0x8a, 0x09, 0x2d, 0x1b, 0x0a, 0xe7, 0xdd, 0xeb, 0x78, 0xa5, - 0x25, 0x6d, 0x4a, 0x72, 0xa1, 0x5b, 0x3f, 0xf3, 0xc6, 0x31, 0x6a, 0x8f, 0xaa, 0x86, 0xf3, 0xea, 0x15, 0xfb, 0x06, - 0x16, 0x84, 0xab, 0x61, 0x4d, 0x83, 0x16, 0x69, 0x01, 0xe1, 0xa8, 0x2b, 0xd3, 0xe3, 0x34, 0x9c, 0x17, 0x54, 0x2c, - 0x08, 0x3b, 0x09, 0x37, 0xc8, 0xdb, 0x17, 0x54, 0xb2, 0xfa, 0xa2, 0xb1, 0xd8, 0x9a, 0x72, 0x76, 0x4e, 0x1e, 0x6d, - 0x64, 0xcc, 0xde, 0x82, 0x9d, 0xf8, 0xf3, 0x55, 0xc7, 0x17, 0xc3, 0x25, 0x07, 0x27, 0xa0, 0xe0, 0xe0, 0xbf, 0xd2, - 0x8b, 0xdc, 0x4c, 0x8a, 0x5c, 0x91, 0xcb, 0xb8, 0x48, 0x73, 0xfe, 0x21, 0xbe, 0xf8, 0x01, 0xf3, 0x3c, 0xbf, 0xc8, - 0x9f, 0x41, 0x86, 0x26, 0x38, 0x79, 0xb4, 0x49, 0xea, 0xd1, 0x8b, 0x37, 0x1f, 0x5e, 0x7d, 0xf8, 0xe7, 0xf9, 0xb3, - 0xd3, 0x0f, 0x2f, 0xbe, 0x7f, 0xfb, 0xfe, 0xd5, 0x8b, 0xb3, 0xb9, 0xf1, 0xba, 0x95, 0x60, 0x6e, 0x64, 0xb1, 0xdd, - 0xda, 0x7c, 0xbf, 0xbc, 0x79, 0xfe, 0xe2, 0xe5, 0xab, 0x37, 0x2f, 0x9e, 0x37, 0x72, 0x2e, 0xdb, 0x0d, 0x81, 0x1d, - 0x1a, 0x67, 0x05, 0x2f, 0xa1, 0x78, 0x75, 0xbb, 0xc3, 0x66, 0x2b, 0x0c, 0x42, 0xbf, 0xe9, 0x2a, 0x5c, 0x03, 0x2c, - 0xb2, 0x03, 0xb5, 0x59, 0xa0, 0xe1, 0x42, 0x6f, 0x1c, 0x77, 0x89, 0xb9, 0xbd, 0x79, 0x81, 0xdf, 0xbd, 0x17, 0xb7, - 0xba, 0x2b, 0x6a, 0x84, 0x24, 0xbc, 0xd8, 0xec, 0xd9, 0xef, 0xc7, 0xae, 0x48, 0x0f, 0xe5, 0x1e, 0xb2, 0x5c, 0xf8, - 0xd5, 0x04, 0x07, 0xca, 0xbc, 0x30, 0x80, 0xe8, 0x18, 0xc1, 0xc9, 0xf1, 0xa1, 0x9b, 0xfb, 0xe4, 0xf7, 0xe8, 0x27, - 0xa7, 0x73, 0x58, 0x2a, 0x8c, 0x83, 0x9f, 0xb6, 0x73, 0x2c, 0x02, 0x7d, 0xb6, 0x07, 0xa7, 0x5c, 0x41, 0x9a, 0x5c, - 0x09, 0x12, 0x99, 0x49, 0x94, 0x66, 0x33, 0xba, 0xb4, 0xdf, 0xd5, 0x5f, 0xdb, 0x67, 0x14, 0x43, 0xf0, 0xa2, 0x12, - 0x25, 0xd8, 0xb8, 0x38, 0x89, 0x49, 0x0e, 0x82, 0x0f, 0x1e, 0x40, 0xef, 0xda, 0xa1, 0x2e, 0x0e, 0x9c, 0x90, 0x32, - 0xd8, 0xcf, 0x4e, 0xa2, 0x0f, 0xe3, 0x74, 0xd8, 0xfe, 0xd4, 0xe9, 0xee, 0xef, 0xc4, 0xfe, 0x38, 0x50, 0x5d, 0x6c, - 0x11, 0x1d, 0xd3, 0xec, 0xfd, 0x21, 0x49, 0xe6, 0x6f, 0xff, 0x4f, 0x73, 0x4f, 0xbb, 0xdd, 0xb6, 0x71, 0xe5, 0xff, - 0x3e, 0x05, 0x0c, 0xbb, 0x0e, 0x60, 0x03, 0x10, 0x40, 0x8a, 0x92, 0x4c, 0x8a, 0x52, 0x13, 0xdb, 0x39, 0x51, 0xaa, - 0xd4, 0x39, 0x8e, 0xea, 0x6d, 0xa3, 0xe8, 0x98, 0x43, 0x70, 0x48, 0xa2, 0x02, 0x01, 0x1e, 0x00, 0x94, 0xa8, 0xd0, - 0xe8, 0x53, 0xec, 0xff, 0xed, 0x73, 0xec, 0xfe, 0xeb, 0x13, 0xed, 0x23, 0xec, 0xb9, 0x77, 0x3e, 0x30, 0xf8, 0x22, - 0xa9, 0xc4, 0x69, 0xf7, 0xa4, 0xaa, 0x89, 0xc1, 0xcc, 0x60, 0xe6, 0xce, 0xcc, 0x9d, 0xfb, 0x7d, 0x03, 0xeb, 0x3f, - 0x62, 0x6b, 0x46, 0xac, 0x05, 0xb1, 0x6e, 0xd3, 0x9b, 0xbc, 0x71, 0xcd, 0x64, 0xba, 0x1b, 0x4c, 0x89, 0x68, 0x18, - 0x10, 0x37, 0x83, 0x73, 0x33, 0x9c, 0xc6, 0x0f, 0xc4, 0x05, 0x77, 0x45, 0x92, 0x19, 0x15, 0x89, 0x66, 0xc4, 0xdb, - 0x8c, 0x43, 0xc6, 0x2c, 0xc1, 0xcb, 0x30, 0xe8, 0xe3, 0xba, 0xa1, 0x6a, 0x37, 0x02, 0xc2, 0x18, 0x43, 0xf3, 0x09, - 0xb7, 0xac, 0x08, 0x1c, 0x3f, 0x4b, 0xc2, 0x3f, 0xd2, 0x07, 0x20, 0x5e, 0xd3, 0x2c, 0x5e, 0x02, 0xcb, 0x42, 0x66, - 0x5c, 0x04, 0x65, 0x19, 0xe9, 0x7e, 0x1f, 0x84, 0x64, 0x59, 0xb8, 0xe9, 0x81, 0xee, 0x75, 0xb2, 0x78, 0x36, 0x0b, - 0xa9, 0xa1, 0x8b, 0x1c, 0x2a, 0xba, 0x25, 0x3f, 0x73, 0xfe, 0xc4, 0x15, 0x81, 0x4b, 0xcd, 0xbc, 0xed, 0xf0, 0x0a, - 0xe8, 0x51, 0x19, 0xd9, 0x8f, 0x11, 0xf0, 0x28, 0xa2, 0xbe, 0x43, 0x2d, 0x0f, 0x5f, 0xe3, 0x02, 0x39, 0xd8, 0x93, - 0x78, 0x35, 0x0e, 0xa9, 0x8d, 0x07, 0x0a, 0x3e, 0xb9, 0x19, 0xaf, 0xc6, 0x63, 0x48, 0x56, 0xf3, 0xc4, 0xb5, 0x20, - 0xfc, 0x4e, 0x9c, 0x22, 0x5b, 0x9c, 0x9b, 0x03, 0x80, 0xa2, 0x93, 0x95, 0x87, 0xcf, 0xb2, 0x77, 0x82, 0xc4, 0x8b, - 0x7d, 0x20, 0x03, 0x16, 0xb8, 0x01, 0x2f, 0x0c, 0xf5, 0x1f, 0x60, 0x7f, 0xa7, 0xfa, 0xa0, 0x09, 0xb9, 0x0c, 0xaf, - 0xf5, 0x1f, 0x70, 0xb1, 0x30, 0x89, 0xf3, 0x6b, 0x76, 0x3e, 0x74, 0x4b, 0x67, 0xba, 0xff, 0x15, 0xa6, 0x73, 0x00, - 0xd9, 0xf7, 0x9b, 0x80, 0xcc, 0xa2, 0x38, 0xcd, 0x02, 0x5f, 0xbf, 0x19, 0x5c, 0x04, 0xc6, 0xf5, 0x22, 0x33, 0xcc, - 0x1b, 0xcb, 0xcf, 0xd4, 0x4c, 0x30, 0x02, 0x25, 0x63, 0x22, 0x98, 0xb6, 0x4a, 0xea, 0x19, 0xdd, 0x5a, 0x51, 0x20, - 0x7f, 0xac, 0xe4, 0x67, 0x43, 0xa8, 0x57, 0x49, 0x2b, 0x83, 0xf9, 0xb1, 0x74, 0x6c, 0x69, 0x0e, 0x18, 0xc3, 0xf6, - 0x7a, 0xb5, 0x41, 0x62, 0x21, 0x2b, 0xee, 0x63, 0x0c, 0x85, 0x2c, 0xfc, 0x87, 0xd8, 0xf3, 0x13, 0xd5, 0xf6, 0xb5, - 0x74, 0xb3, 0x8f, 0xbe, 0x2c, 0x53, 0x1e, 0x40, 0x21, 0x80, 0xe1, 0x49, 0x14, 0x67, 0x1a, 0xc4, 0xf7, 0x81, 0x2f, - 0x8e, 0xaa, 0xb6, 0x72, 0xbc, 0x57, 0xc3, 0xcc, 0x39, 0xba, 0xf9, 0x0a, 0xaf, 0x57, 0x83, 0x47, 0x79, 0x2b, 0x05, - 0xf2, 0x60, 0x3c, 0x53, 0x0a, 0x0b, 0x98, 0xc5, 0x97, 0xf1, 0x7d, 0x55, 0x1d, 0xf4, 0x7a, 0xb4, 0xfb, 0x76, 0x37, - 0x04, 0x05, 0x2f, 0x92, 0x1b, 0x1a, 0x3c, 0x3f, 0xab, 0x20, 0xa5, 0x2a, 0xa7, 0x0a, 0xed, 0x5f, 0x04, 0x95, 0x94, - 0x81, 0xb9, 0x1c, 0xde, 0x36, 0x80, 0xf4, 0x38, 0x21, 0x30, 0xca, 0x91, 0x6c, 0x95, 0xc9, 0x9f, 0x84, 0xc3, 0x4b, - 0x79, 0xdc, 0xe9, 0x10, 0xa5, 0xb2, 0xf3, 0x60, 0x36, 0xd7, 0xcf, 0x33, 0xbe, 0x23, 0x55, 0x7a, 0xf7, 0x23, 0xbc, - 0xea, 0x37, 0xbd, 0x81, 0x84, 0x54, 0x0d, 0xf5, 0xc3, 0xf8, 0x1e, 0xbc, 0xd9, 0x8b, 0x5e, 0x39, 0x35, 0xdd, 0xda, - 0xb9, 0xf9, 0x52, 0xd6, 0x80, 0xac, 0xe2, 0x66, 0x7f, 0x4b, 0x83, 0xf6, 0x6f, 0x56, 0x7b, 0xb1, 0xe2, 0x47, 0x8d, - 0xc1, 0xfe, 0x2c, 0x63, 0xa8, 0xf4, 0x32, 0x88, 0x86, 0xd1, 0x99, 0x2c, 0x5a, 0x90, 0x35, 0x36, 0x30, 0xcf, 0xeb, - 0x45, 0xfd, 0xc8, 0x8a, 0x87, 0xf1, 0x9e, 0x75, 0x63, 0x6e, 0x78, 0x4c, 0xcf, 0x47, 0x29, 0xcd, 0xce, 0x1b, 0xc6, - 0x02, 0x1b, 0x61, 0xf8, 0x6c, 0x13, 0xe5, 0xa3, 0x7e, 0x4b, 0x15, 0xf6, 0xd6, 0x22, 0xbb, 0x3b, 0x89, 0xb7, 0x76, - 0x12, 0xe7, 0xa3, 0xc7, 0x6c, 0x73, 0x9f, 0xef, 0xf2, 0x70, 0xe0, 0x37, 0x61, 0xfa, 0xb0, 0x71, 0xcf, 0x43, 0x30, - 0xda, 0xd2, 0x6e, 0x4f, 0x70, 0xb7, 0xff, 0xef, 0x7f, 0xfd, 0xe7, 0x7f, 0x17, 0x64, 0xef, 0x38, 0x39, 0x3b, 0xc5, - 0x8c, 0x64, 0x40, 0xc5, 0xe5, 0xa7, 0x07, 0xec, 0x37, 0x16, 0xff, 0x8b, 0x46, 0x45, 0xc4, 0xa8, 0xfe, 0x47, 0x3d, - 0x83, 0x22, 0x8b, 0xbb, 0xc8, 0xa1, 0xae, 0x90, 0xe0, 0x40, 0x43, 0x45, 0xcb, 0x55, 0x86, 0x51, 0xbf, 0x61, 0x1c, - 0x34, 0xd7, 0x35, 0x8c, 0x22, 0x0c, 0xb4, 0x58, 0xc1, 0x0c, 0xe6, 0xba, 0x16, 0x4c, 0xea, 0x65, 0x9c, 0xc9, 0x05, - 0x62, 0x04, 0xa9, 0x38, 0x94, 0x99, 0xc3, 0x63, 0xc2, 0xa7, 0xe3, 0x5b, 0x45, 0xca, 0x0c, 0xc3, 0x47, 0xdd, 0x72, - 0xc3, 0xfd, 0xec, 0xb3, 0x7e, 0x06, 0xfb, 0x4e, 0x73, 0x04, 0xf0, 0x3d, 0x87, 0xed, 0x33, 0x7c, 0xb6, 0x21, 0xc0, - 0xaf, 0xe5, 0x3a, 0x4c, 0xb4, 0xf0, 0x19, 0x2c, 0xa6, 0x07, 0x88, 0x9d, 0x95, 0x6b, 0x68, 0x34, 0x34, 0xe4, 0xa6, - 0x41, 0xcb, 0x24, 0x58, 0x90, 0xe4, 0x81, 0x59, 0x12, 0x59, 0xaa, 0xb9, 0x91, 0xa9, 0x6b, 0x8c, 0x7a, 0x63, 0xf3, - 0x65, 0x84, 0x9c, 0xae, 0xfd, 0x41, 0x96, 0x51, 0x3e, 0x39, 0x81, 0xbe, 0x74, 0xf8, 0xd6, 0x47, 0xfd, 0x25, 0x75, - 0x26, 0x34, 0x23, 0x41, 0xc8, 0x9a, 0x0c, 0x8c, 0xa8, 0x65, 0x36, 0x51, 0x79, 0x36, 0x69, 0x19, 0x65, 0xe3, 0x64, - 0x18, 0x05, 0xc7, 0xc6, 0x8d, 0x33, 0x43, 0x14, 0xda, 0xbc, 0x80, 0xec, 0x9d, 0xb2, 0x97, 0x00, 0xf8, 0x49, 0x7d, - 0x17, 0xe5, 0xed, 0x4b, 0xd4, 0x50, 0xfb, 0xb7, 0x59, 0x36, 0x0a, 0xcb, 0x96, 0xc2, 0xb2, 0xd1, 0xc8, 0x8f, 0x27, - 0xf4, 0xcf, 0xef, 0x2f, 0x64, 0xa6, 0x3f, 0x10, 0x5a, 0x8f, 0xf8, 0x25, 0x12, 0x21, 0x37, 0x91, 0x20, 0x27, 0xc1, - 0x72, 0xf2, 0x69, 0x72, 0xab, 0x25, 0xb9, 0xae, 0x9d, 0xb3, 0x49, 0xd3, 0x09, 0x9b, 0xc9, 0x30, 0xc6, 0x56, 0x49, - 0x7e, 0x7a, 0xc0, 0x6a, 0x33, 0x2a, 0x97, 0x55, 0x02, 0xf8, 0x25, 0x30, 0xeb, 0x02, 0x7c, 0x90, 0x94, 0x78, 0xe8, - 0x15, 0xe2, 0x05, 0x67, 0x81, 0xaa, 0x41, 0xef, 0xbc, 0xcc, 0xb8, 0x60, 0x2b, 0xbd, 0x38, 0xd4, 0x31, 0x04, 0x26, - 0x12, 0xe7, 0x5a, 0xab, 0x9c, 0x9c, 0xa2, 0x13, 0x21, 0xf2, 0xe9, 0xf3, 0x0e, 0x1e, 0x75, 0xa4, 0x00, 0x6b, 0x43, - 0x29, 0xc9, 0x75, 0x6d, 0xc1, 0x19, 0x25, 0x1e, 0x01, 0x0d, 0xc2, 0xa3, 0xb8, 0x70, 0xcf, 0xea, 0xda, 0x82, 0xac, - 0x71, 0xe6, 0xe2, 0x0d, 0x59, 0x1b, 0x1e, 0x7f, 0x55, 0x9c, 0xc9, 0xa8, 0xbc, 0xe0, 0x02, 0xc5, 0x80, 0xef, 0x93, - 0x14, 0xd0, 0xcd, 0xd1, 0xa6, 0xa4, 0x61, 0x71, 0xe7, 0x62, 0x71, 0x27, 0x2d, 0x8b, 0x3b, 0xd9, 0xb2, 0xb8, 0x21, - 0x5f, 0x48, 0x4d, 0x82, 0x2e, 0x41, 0x7f, 0xd6, 0x02, 0x29, 0x32, 0x06, 0xa3, 0xcf, 0x0f, 0x28, 0xc2, 0xc9, 0x4e, - 0x43, 0xb0, 0xe7, 0x6c, 0x81, 0x55, 0x13, 0x5c, 0x14, 0x40, 0xd4, 0x27, 0x2e, 0x8f, 0xab, 0x44, 0xad, 0xd6, 0x1c, - 0xb6, 0xaa, 0x5f, 0xa5, 0x79, 0x43, 0xd6, 0xd0, 0x32, 0xe6, 0x2d, 0x33, 0x9d, 0x6f, 0x99, 0xa9, 0x5f, 0x3a, 0xf3, - 0x7c, 0xda, 0xec, 0xf4, 0xaa, 0x93, 0x62, 0xa4, 0xd0, 0x3a, 0xc3, 0x2d, 0x53, 0xde, 0x87, 0xed, 0xb8, 0x58, 0xd9, - 0x51, 0x4b, 0x92, 0xa6, 0xf7, 0x71, 0x02, 0x4a, 0x62, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x11, 0x44, 0x3c, 0xfe, 0x54, - 0xeb, 0x66, 0x2a, 0xde, 0xab, 0x5b, 0xaa, 0xd3, 0xeb, 0xb1, 0x1a, 0x4b, 0x92, 0x65, 0x34, 0x41, 0xa0, 0x13, 0x48, - 0x54, 0xf0, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0xd0, 0x2c, 0xae, 0x03, 0x44, 0xed, 0x4b, 0xe0, 0x83, 0x12, 0x41, - 0x34, 0x2b, 0xb1, 0x2c, 0x13, 0x09, 0x78, 0x4e, 0xdf, 0x24, 0x8a, 0xb7, 0xa5, 0x77, 0x64, 0x3a, 0x4b, 0x32, 0xf9, - 0x01, 0x6c, 0x11, 0x8c, 0x8e, 0x05, 0x7e, 0x05, 0x6a, 0xe4, 0xca, 0x84, 0x31, 0x66, 0x7e, 0x81, 0x24, 0x11, 0x4b, - 0x72, 0xab, 0x4d, 0x70, 0xf8, 0x26, 0xf6, 0xf4, 0x66, 0xd3, 0xc9, 0x0f, 0x66, 0x81, 0x59, 0xc3, 0x9a, 0x80, 0xda, - 0xc2, 0xe1, 0x99, 0x94, 0xc0, 0x84, 0x96, 0x77, 0x64, 0x82, 0xb2, 0xea, 0x1a, 0x52, 0x30, 0xbb, 0x42, 0xbc, 0x35, - 0x4a, 0xe0, 0x76, 0xbb, 0x76, 0x6f, 0xf2, 0xe7, 0x33, 0xfc, 0xe5, 0xdd, 0xe4, 0xcf, 0xc7, 0xf8, 0xab, 0x73, 0x83, - 0xc9, 0x36, 0x1b, 0xc4, 0x7a, 0xca, 0x9c, 0xf5, 0xb3, 0xd2, 0x7e, 0x62, 0x26, 0xb3, 0x8f, 0xd8, 0x36, 0x7c, 0x81, - 0x9f, 0x3e, 0xdb, 0x44, 0xe0, 0x24, 0xae, 0xce, 0x21, 0x75, 0x12, 0x33, 0x6f, 0x2c, 0x9f, 0xb5, 0x94, 0x8f, 0xcd, - 0x7f, 0x31, 0x81, 0x80, 0xbb, 0x24, 0x2e, 0xee, 0x94, 0xb2, 0x50, 0xf2, 0xe3, 0x38, 0x88, 0x48, 0xf2, 0xf0, 0x91, - 0xc9, 0x14, 0x0c, 0xc1, 0x67, 0x4b, 0x61, 0x2b, 0x63, 0x05, 0xcb, 0x1a, 0xfa, 0x4c, 0xd1, 0x49, 0x3d, 0x70, 0x0a, - 0x61, 0xf8, 0x97, 0x44, 0xa1, 0x3d, 0x4b, 0xe2, 0x28, 0xbe, 0x20, 0xa5, 0x0f, 0x7d, 0x7c, 0xb6, 0x31, 0x68, 0xbd, - 0x9b, 0x9a, 0xb8, 0xa2, 0x44, 0x10, 0xc0, 0xf2, 0xa0, 0x68, 0x6b, 0x31, 0x09, 0xfa, 0xa8, 0x82, 0x1f, 0xc7, 0x6b, - 0xfb, 0xd9, 0x26, 0x3b, 0xd7, 0x17, 0x24, 0xb9, 0xa5, 0x13, 0xdb, 0x0f, 0x12, 0x3f, 0xa4, 0x7a, 0x5f, 0x1f, 0x87, - 0x24, 0xba, 0xe5, 0x8f, 0x76, 0xbc, 0xca, 0xd0, 0xa8, 0x66, 0xa7, 0x24, 0x4c, 0xc0, 0x84, 0x09, 0xf0, 0x91, 0x41, - 0x6b, 0x80, 0x82, 0xf6, 0x5a, 0x8a, 0xbf, 0x0b, 0x82, 0xb2, 0xa8, 0x65, 0x81, 0x4d, 0x38, 0xd8, 0xf9, 0x80, 0x93, - 0xbd, 0xa5, 0xe3, 0x7a, 0xe9, 0x96, 0x3a, 0x55, 0xa6, 0xf7, 0x90, 0x59, 0x62, 0x3f, 0x62, 0x0f, 0xbf, 0xfc, 0x73, - 0x50, 0xf2, 0x98, 0xcf, 0x71, 0xe2, 0xb0, 0xfd, 0x83, 0x6a, 0x63, 0x92, 0xa6, 0xab, 0x05, 0x9d, 0x30, 0x7b, 0x82, - 0xf3, 0x62, 0x28, 0x65, 0x46, 0x5c, 0x1d, 0xce, 0x4f, 0xab, 0xce, 0xf1, 0xe1, 0x6b, 0xb0, 0x73, 0x02, 0x62, 0x30, - 0x9e, 0x4e, 0xf5, 0x42, 0xbc, 0xb6, 0xa3, 0x99, 0x77, 0xf8, 0xd3, 0xea, 0xeb, 0xb7, 0xee, 0xd7, 0xb2, 0x71, 0xa4, - 0x9b, 0xf9, 0x48, 0x18, 0x6d, 0x70, 0x9a, 0x56, 0x19, 0xaf, 0x98, 0xd1, 0x94, 0x44, 0xed, 0xd3, 0xb9, 0x2e, 0xed, - 0xb2, 0x25, 0xa5, 0x13, 0xb0, 0xe7, 0xb7, 0x6a, 0xa5, 0x1f, 0x43, 0x7a, 0x47, 0xa5, 0x41, 0x48, 0xfd, 0x63, 0x0d, - 0x2d, 0x30, 0x62, 0x25, 0x37, 0x34, 0xe1, 0x84, 0x95, 0x32, 0xa5, 0x11, 0xce, 0x81, 0xcf, 0x5c, 0xdd, 0xe5, 0x95, - 0x5d, 0x3d, 0xb2, 0x74, 0x65, 0x00, 0xad, 0x23, 0x3b, 0x6f, 0x29, 0xef, 0x63, 0xba, 0xfa, 0xe6, 0xb1, 0x59, 0x9e, - 0xd9, 0x87, 0x08, 0xff, 0x1c, 0x4e, 0x21, 0x6c, 0x7e, 0x43, 0x4a, 0x22, 0x07, 0x6d, 0x10, 0x6b, 0x92, 0x5a, 0xeb, - 0x4c, 0xf0, 0x29, 0x6c, 0xa4, 0xd1, 0x59, 0x40, 0x08, 0x86, 0x1b, 0xd7, 0x46, 0x2b, 0xcf, 0x7c, 0x8c, 0x69, 0xa0, - 0x23, 0x9a, 0xa6, 0xad, 0x00, 0x93, 0x8b, 0x6e, 0xe9, 0x45, 0xed, 0x32, 0x3c, 0x8a, 0x72, 0xcb, 0xb5, 0xe0, 0x56, - 0xc6, 0x09, 0x56, 0xbf, 0x85, 0x18, 0xfe, 0xe3, 0x82, 0x5b, 0xb9, 0x25, 0xb3, 0xb1, 0xce, 0x2d, 0x90, 0xda, 0xde, - 0xdf, 0xeb, 0x7c, 0x50, 0xa5, 0x9b, 0xb2, 0x71, 0x68, 0x46, 0x09, 0xfb, 0xd5, 0xc4, 0xb4, 0xd8, 0x81, 0x18, 0x53, - 0x05, 0xc5, 0xd1, 0xe9, 0x94, 0xfa, 0x59, 0x6a, 0x0a, 0x59, 0xab, 0x8c, 0x39, 0x0d, 0xbe, 0x86, 0x4f, 0x86, 0xfa, - 0x9f, 0x20, 0xf2, 0x86, 0x08, 0xcd, 0xc6, 0x07, 0x24, 0xf8, 0x9d, 0x66, 0x30, 0xb1, 0x1e, 0xcb, 0x20, 0xe2, 0x5f, - 0xf9, 0xf4, 0x49, 0x98, 0x48, 0x94, 0xca, 0x71, 0x68, 0xfc, 0x0a, 0x28, 0xf6, 0x45, 0x2c, 0x6d, 0xe1, 0xb6, 0x23, - 0xa0, 0x6d, 0xc7, 0x77, 0xe3, 0x7d, 0xdd, 0xf3, 0xdc, 0x5c, 0xb7, 0xc0, 0xe3, 0xf3, 0x76, 0xdf, 0x43, 0x8f, 0xad, - 0xba, 0xd0, 0x6a, 0x15, 0x3d, 0xa6, 0x5d, 0xc7, 0x7b, 0xe5, 0xe9, 0x16, 0x33, 0xb4, 0x55, 0x70, 0x9b, 0x1f, 0xdf, - 0xd1, 0xe4, 0x57, 0x4f, 0xa5, 0xdc, 0xf9, 0x7e, 0xe3, 0x39, 0xf2, 0x5c, 0x40, 0xc2, 0x59, 0xbc, 0x7c, 0xc4, 0x14, - 0xba, 0xba, 0xa5, 0xfb, 0x61, 0x9c, 0x52, 0x75, 0x0e, 0x4c, 0x5e, 0xf1, 0x2b, 0x27, 0xf1, 0xfd, 0xfb, 0xb7, 0x3f, - 0xfc, 0xa0, 0x5b, 0x98, 0x3f, 0x38, 0x55, 0x7b, 0xe7, 0x1b, 0x6a, 0x07, 0xf6, 0x6f, 0xdc, 0x77, 0xec, 0x86, 0x61, - 0x7c, 0x65, 0x79, 0xcf, 0xb1, 0xb2, 0xda, 0x96, 0xe3, 0x37, 0x0f, 0xff, 0x32, 0x63, 0x06, 0xf7, 0x9a, 0x57, 0x03, - 0x6e, 0xd8, 0x7e, 0xbd, 0x95, 0x4a, 0x16, 0x41, 0xf4, 0xb1, 0xa1, 0x94, 0xac, 0x1b, 0x4a, 0x51, 0x36, 0x58, 0xc5, - 0x1f, 0xab, 0x78, 0xa1, 0xdc, 0xce, 0x90, 0xfe, 0x7d, 0x17, 0xb8, 0x14, 0x96, 0xe6, 0x57, 0x0c, 0x9a, 0xe7, 0x7f, - 0xa8, 0x8e, 0xba, 0xa1, 0x98, 0xf3, 0x21, 0x12, 0xb6, 0x5c, 0x97, 0xa3, 0xaa, 0xc9, 0xcb, 0x94, 0x9b, 0xda, 0xb8, - 0x59, 0x60, 0xfa, 0xa4, 0x70, 0xbe, 0xd9, 0x51, 0x19, 0x84, 0xb4, 0xb2, 0x76, 0x41, 0x13, 0x6c, 0xed, 0x3d, 0xff, - 0xe7, 0x3f, 0x1c, 0xe7, 0x9f, 0xff, 0xd8, 0x59, 0x15, 0xfa, 0xce, 0x81, 0x1d, 0xde, 0x55, 0x33, 0x1f, 0xa1, 0xd0, - 0x29, 0x1b, 0xbe, 0x1e, 0x8d, 0x06, 0x46, 0x09, 0x64, 0xe0, 0x33, 0x72, 0x5e, 0x2b, 0xe1, 0x78, 0xb5, 0xef, 0x9a, - 0x18, 0xcc, 0x01, 0x1a, 0xca, 0xeb, 0xab, 0x75, 0xb3, 0x33, 0xa7, 0x84, 0x5a, 0x5f, 0xb5, 0x9d, 0x0e, 0xa5, 0x98, - 0xb8, 0x2e, 0x1f, 0x99, 0x3c, 0xc7, 0x00, 0x8c, 0x8b, 0xab, 0x0f, 0x4a, 0x2b, 0x07, 0x7e, 0x36, 0x59, 0x79, 0x7c, - 0xbc, 0xac, 0x32, 0x42, 0xba, 0xd7, 0x08, 0x59, 0xdb, 0xf2, 0x18, 0x79, 0x7f, 0xb5, 0x51, 0xb2, 0x72, 0x31, 0x4e, - 0x0b, 0x45, 0x66, 0x3c, 0xca, 0x08, 0x67, 0x9a, 0xb8, 0x4a, 0xb0, 0xa4, 0xf6, 0xad, 0xa8, 0x2e, 0x94, 0x21, 0xec, - 0x5e, 0xf6, 0x73, 0x3d, 0x8c, 0xef, 0xd1, 0x59, 0x4f, 0xd5, 0x27, 0x73, 0x61, 0xc8, 0x69, 0x9a, 0x25, 0x71, 0x34, - 0x3b, 0xab, 0x5c, 0xde, 0x75, 0x3b, 0x1f, 0x90, 0x60, 0xb1, 0xaa, 0x65, 0xb1, 0x89, 0x3a, 0xca, 0xed, 0x5b, 0xea, - 0x7c, 0xc7, 0x4c, 0x98, 0x6a, 0x42, 0xb9, 0x1c, 0x45, 0xd7, 0x0d, 0x6a, 0x70, 0x95, 0x94, 0x2b, 0xbf, 0x96, 0x8f, - 0x07, 0x1c, 0xae, 0x67, 0xa3, 0x1c, 0x93, 0x1d, 0xbd, 0x6b, 0x33, 0x10, 0xfd, 0x7e, 0xb7, 0x81, 0xe8, 0xd5, 0x5e, - 0x06, 0xa2, 0xdf, 0x7f, 0x76, 0x03, 0xd1, 0x77, 0xaa, 0x81, 0x28, 0x6c, 0xe9, 0xb7, 0x74, 0x2f, 0xab, 0x4d, 0x61, - 0x0d, 0x15, 0xdf, 0xa7, 0x43, 0x8f, 0x53, 0xa6, 0xa9, 0x3f, 0xa7, 0xc0, 0x6d, 0xf3, 0x6d, 0x1a, 0xc6, 0x33, 0xb0, - 0xe0, 0xfc, 0xed, 0x6d, 0x2d, 0xc3, 0x78, 0xa6, 0x5a, 0x5a, 0xa6, 0x3c, 0xdc, 0x73, 0x11, 0xc2, 0x8d, 0x59, 0x37, - 0xba, 0x96, 0x38, 0x7b, 0xf6, 0xa1, 0xa9, 0xa4, 0xb4, 0x97, 0xa6, 0xab, 0x1d, 0x61, 0xff, 0xd8, 0x47, 0xd3, 0x49, - 0xd9, 0xb0, 0xf3, 0x32, 0x96, 0x49, 0x7b, 0x8a, 0x1e, 0xa4, 0x8b, 0x00, 0x0b, 0x12, 0xb3, 0xd1, 0x7f, 0x5a, 0x7b, - 0x5f, 0x5d, 0x7b, 0x83, 0xae, 0x07, 0x91, 0x19, 0x80, 0x57, 0xc3, 0x02, 0x77, 0xd0, 0xed, 0x42, 0xc1, 0xbd, 0x52, - 0xd0, 0x81, 0x82, 0x40, 0x29, 0xe8, 0x41, 0x81, 0xaf, 0x14, 0x1c, 0x41, 0xc1, 0x44, 0x29, 0x38, 0x86, 0x82, 0x3b, - 0x3d, 0xbf, 0x2e, 0x12, 0x39, 0x1d, 0x9b, 0x37, 0x16, 0xe3, 0x0d, 0x44, 0xd9, 0xb1, 0xe5, 0x81, 0x19, 0x23, 0x99, - 0xf5, 0x63, 0x8b, 0xc9, 0xe9, 0xfa, 0x89, 0x75, 0x3f, 0xa7, 0x2c, 0x4a, 0xfc, 0x1b, 0xbc, 0x3a, 0x9c, 0x2c, 0x06, - 0xa7, 0x09, 0x11, 0x7d, 0x45, 0xc0, 0x41, 0xd3, 0x4d, 0x10, 0xbd, 0x0c, 0xe4, 0xca, 0x89, 0x08, 0x36, 0xca, 0x5a, - 0x16, 0xef, 0xd8, 0xe7, 0x6c, 0xb9, 0x05, 0x0a, 0x4b, 0x2e, 0x43, 0x95, 0xef, 0x7d, 0x0e, 0x7b, 0x9e, 0x37, 0x74, - 0xbc, 0x9a, 0x69, 0x97, 0xf1, 0x6c, 0xa7, 0x69, 0x8e, 0xfa, 0x0a, 0x46, 0xa9, 0x33, 0x0d, 0x88, 0x2d, 0xb6, 0x25, - 0xff, 0x16, 0x7b, 0xcc, 0xcb, 0xf5, 0x33, 0x18, 0x9b, 0x96, 0x31, 0xc3, 0x30, 0xf8, 0x0e, 0xc0, 0x48, 0x39, 0xf5, - 0x97, 0x00, 0x67, 0xe5, 0xf9, 0x8a, 0x28, 0xe3, 0x39, 0xfb, 0x8e, 0xa6, 0x29, 0x99, 0x89, 0xfa, 0xf5, 0x71, 0x82, - 0x31, 0x9c, 0x64, 0xa3, 0x10, 0x80, 0x20, 0x13, 0x0b, 0x6a, 0x36, 0x4f, 0x49, 0x7c, 0xaf, 0x81, 0x55, 0x1d, 0x6c, - 0xa8, 0xc2, 0xfe, 0x27, 0x70, 0x60, 0x09, 0xcb, 0x38, 0x08, 0x0e, 0xff, 0x1d, 0x0d, 0xab, 0x85, 0x19, 0x99, 0x55, - 0x8b, 0xd8, 0x3e, 0xc8, 0xd5, 0xb1, 0x49, 0x93, 0x98, 0x52, 0xe1, 0xaf, 0xb1, 0xcb, 0x08, 0xe3, 0xd9, 0x6f, 0x6a, - 0x94, 0xb1, 0xc5, 0x30, 0xe7, 0x36, 0xb5, 0x82, 0x6c, 0xe4, 0x20, 0x8c, 0x35, 0x07, 0x40, 0xd8, 0x8f, 0xb2, 0xb9, - 0x8d, 0x7e, 0xa5, 0x46, 0x27, 0x32, 0x2d, 0x07, 0xd7, 0x76, 0x53, 0xf5, 0xa6, 0xef, 0x27, 0xb3, 0x31, 0x31, 0xbc, - 0xce, 0xb1, 0x25, 0xfe, 0x1c, 0xb7, 0x67, 0xe6, 0xd8, 0x83, 0x36, 0x09, 0xee, 0x36, 0xd3, 0x38, 0xca, 0xec, 0x29, - 0x59, 0x04, 0xe1, 0x43, 0x7f, 0x11, 0x47, 0x71, 0xba, 0x24, 0x3e, 0x1d, 0x14, 0x7c, 0xf1, 0x00, 0xe3, 0xb4, 0x70, - 0x57, 0x61, 0xcf, 0xe9, 0x24, 0x74, 0xc1, 0x5a, 0xcb, 0x30, 0x2c, 0xd3, 0x90, 0xae, 0x73, 0xfe, 0xf9, 0x52, 0x65, - 0x56, 0x15, 0xb7, 0x1c, 0x6b, 0x01, 0x84, 0x25, 0x8f, 0xf1, 0x02, 0x91, 0xcd, 0x06, 0x4b, 0x32, 0xc1, 0xb0, 0xa4, - 0x4e, 0xa7, 0x97, 0xd0, 0x85, 0xe6, 0xf4, 0x5a, 0x3b, 0x4f, 0xe2, 0xfb, 0x33, 0x18, 0x2d, 0x36, 0xb6, 0x53, 0x1a, - 0x4e, 0xf1, 0x8d, 0x8d, 0x6e, 0x65, 0xa2, 0x1f, 0x1b, 0xf9, 0x69, 0xe8, 0x8d, 0x2e, 0x06, 0xf0, 0xba, 0xdf, 0xd1, - 0xdc, 0xc1, 0x22, 0x88, 0x6c, 0x36, 0x9d, 0x63, 0x77, 0xa9, 0xf4, 0xa5, 0xc2, 0xcf, 0xdc, 0x60, 0x75, 0x4f, 0x73, - 0x07, 0xc0, 0x73, 0x4d, 0xc3, 0xf8, 0xbe, 0x3f, 0x0f, 0x26, 0x13, 0x1a, 0x0d, 0x70, 0xcc, 0xb2, 0x90, 0x86, 0x61, - 0xb0, 0x4c, 0x83, 0x74, 0xb0, 0x20, 0x6b, 0xde, 0xeb, 0x61, 0x5b, 0xaf, 0x5d, 0xde, 0x6b, 0x77, 0xef, 0x5e, 0x95, - 0x6e, 0xc0, 0x85, 0x8d, 0xf5, 0xc3, 0x87, 0xd6, 0xd3, 0xdc, 0xca, 0x3c, 0xf7, 0xee, 0x75, 0x99, 0xd0, 0xcd, 0x82, - 0x24, 0xb3, 0x20, 0xea, 0xbb, 0xb9, 0x73, 0xb7, 0x61, 0x1b, 0xe3, 0xe9, 0xc9, 0xc9, 0x49, 0xee, 0x4c, 0xc4, 0x93, - 0x3b, 0x99, 0xe4, 0x8e, 0x2f, 0x9e, 0xa6, 0x53, 0xd7, 0x9d, 0x4e, 0x73, 0x27, 0x10, 0x05, 0xdd, 0x8e, 0x3f, 0xe9, - 0x76, 0x72, 0xe7, 0x5e, 0xa9, 0x91, 0x3b, 0x94, 0x3f, 0x25, 0x74, 0x32, 0xc0, 0x8d, 0xc4, 0xec, 0xbc, 0xfb, 0xc7, - 0xae, 0x9b, 0x23, 0x06, 0xb8, 0x2e, 0xe1, 0x26, 0x14, 0xd9, 0xdc, 0x6c, 0xf6, 0xae, 0xa9, 0x15, 0x9f, 0xf3, 0xfd, - 0xc6, 0x7a, 0x13, 0x92, 0xdc, 0xde, 0x68, 0xca, 0x2c, 0x08, 0x61, 0xd5, 0x36, 0x02, 0x0c, 0xf6, 0xba, 0x0f, 0xf1, - 0xfa, 0x06, 0xe3, 0x38, 0x81, 0x33, 0x9b, 0x90, 0x49, 0xb0, 0x4a, 0xfb, 0x5e, 0x67, 0xb9, 0x16, 0x45, 0x7c, 0xaf, - 0x17, 0x05, 0x78, 0xf6, 0xfa, 0x69, 0x1c, 0x06, 0x13, 0x51, 0xd4, 0x76, 0x96, 0xbc, 0x8e, 0x39, 0xc0, 0x68, 0x15, - 0x01, 0xc6, 0x5c, 0x21, 0x61, 0xa8, 0x39, 0xdd, 0x54, 0xa3, 0x24, 0x45, 0x49, 0xad, 0xe6, 0xa6, 0x0c, 0x2e, 0x18, - 0x99, 0xc2, 0x3b, 0x5c, 0xae, 0xe5, 0x9e, 0xf7, 0x8e, 0x96, 0xeb, 0xfc, 0x0f, 0x0b, 0x3a, 0x09, 0x88, 0x66, 0x14, - 0xbb, 0xc9, 0x73, 0x41, 0x9a, 0x6b, 0x6e, 0x5a, 0xb6, 0xa9, 0x38, 0x16, 0x10, 0xd7, 0xf4, 0x49, 0xb0, 0x58, 0xc6, - 0x49, 0x46, 0xa2, 0x2c, 0xcf, 0x47, 0x37, 0x79, 0x3e, 0xb8, 0x0a, 0x8c, 0xeb, 0xbf, 0x1a, 0xec, 0x9e, 0x66, 0xda, - 0x8f, 0xdc, 0xbc, 0xb1, 0xde, 0x52, 0xd5, 0x52, 0x0a, 0xae, 0x31, 0xb4, 0x92, 0x52, 0x2b, 0xb3, 0x5b, 0xb2, 0x5e, - 0x99, 0x01, 0x59, 0x56, 0x67, 0x96, 0x57, 0xe5, 0x2a, 0x78, 0x03, 0x41, 0x85, 0xb7, 0x74, 0x78, 0xa5, 0x58, 0x5d, - 0x01, 0xb1, 0x82, 0x95, 0x99, 0x53, 0xd1, 0xb3, 0x36, 0x9a, 0xf1, 0xcb, 0xdd, 0x34, 0xe3, 0x8f, 0xd9, 0x3e, 0x34, - 0xe3, 0x97, 0x9f, 0x9d, 0x66, 0x7c, 0x56, 0x77, 0x2a, 0xba, 0x88, 0x87, 0xba, 0x94, 0xd5, 0xc3, 0xd5, 0x94, 0xb0, - 0x70, 0x5d, 0x17, 0xbf, 0xd8, 0x07, 0x48, 0xf4, 0xc6, 0x12, 0x50, 0xb2, 0x9b, 0x1b, 0x68, 0xf1, 0x77, 0xd1, 0xf0, - 0x2f, 0x89, 0xfa, 0x3c, 0x9d, 0x0e, 0xdf, 0xc4, 0x4a, 0x81, 0x7c, 0xe2, 0xf6, 0x0f, 0xa5, 0xd0, 0x2a, 0xec, 0x8d, - 0xb0, 0x6e, 0xc6, 0xe4, 0x33, 0x10, 0x99, 0x81, 0x59, 0xf3, 0x4f, 0xa4, 0xfd, 0xe6, 0xa0, 0x3c, 0x04, 0x43, 0x9a, - 0x52, 0x0b, 0xff, 0xbb, 0x9a, 0x44, 0x70, 0x46, 0x33, 0xee, 0x30, 0xff, 0xd5, 0xc3, 0xc5, 0xc4, 0xb8, 0x88, 0xcd, - 0x3c, 0x48, 0xdf, 0x55, 0xbd, 0xdf, 0xb8, 0x16, 0x65, 0xa8, 0x4e, 0x27, 0xe7, 0x76, 0x93, 0x6a, 0x76, 0x79, 0x78, - 0xcd, 0x9a, 0x9f, 0x97, 0x66, 0xda, 0x57, 0x1b, 0x72, 0x0e, 0xb4, 0x76, 0x19, 0x73, 0xd7, 0xa3, 0x0d, 0xa7, 0x00, - 0x31, 0x71, 0x1f, 0x06, 0x0d, 0x98, 0xb0, 0xe6, 0xc1, 0x24, 0xcf, 0xcd, 0x81, 0x00, 0x84, 0x72, 0xd1, 0xd2, 0x5d, - 0x44, 0x5c, 0x7a, 0x2f, 0xad, 0x03, 0xb8, 0xae, 0x8d, 0x29, 0xd2, 0x2e, 0x40, 0x35, 0xcd, 0xd5, 0x6e, 0x1c, 0x66, - 0xba, 0xc6, 0xc0, 0xc7, 0x4c, 0x16, 0x94, 0x09, 0x81, 0x2e, 0x55, 0xc2, 0x5f, 0xbc, 0x12, 0x05, 0x75, 0xdb, 0x68, - 0x06, 0x1c, 0xd4, 0xad, 0x43, 0x88, 0x0f, 0x21, 0x9e, 0x66, 0x68, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xb4, 0x1f, - 0x6e, 0x3f, 0x60, 0xcf, 0x96, 0x24, 0xaa, 0xf0, 0x92, 0xbb, 0x6c, 0x7c, 0x81, 0x94, 0x48, 0xef, 0x2d, 0x27, 0xbd, - 0xd7, 0x5e, 0x6c, 0x44, 0x78, 0x9c, 0x8c, 0x2c, 0x6d, 0xe0, 0x1c, 0x11, 0xf7, 0x72, 0x8c, 0xa7, 0x44, 0xe2, 0x19, - 0xac, 0x52, 0xc0, 0x8d, 0xc8, 0x70, 0x22, 0xfe, 0x19, 0xf8, 0xab, 0x24, 0x8d, 0x93, 0xfe, 0x32, 0x0e, 0xa2, 0x8c, - 0x26, 0x39, 0x82, 0xea, 0x1a, 0xe1, 0x23, 0xc0, 0x73, 0xb3, 0x89, 0x97, 0xc4, 0x0f, 0xb2, 0x87, 0xbe, 0xcb, 0x49, - 0x0a, 0x77, 0xc0, 0xa9, 0x03, 0xb7, 0xb1, 0x7e, 0x9f, 0x43, 0xf3, 0x25, 0x12, 0x7e, 0x49, 0x9d, 0x9c, 0x51, 0xb7, - 0xf9, 0x40, 0x79, 0xcb, 0x02, 0x04, 0x01, 0xf9, 0x41, 0x12, 0x7b, 0x06, 0x58, 0x1e, 0x96, 0xda, 0x9d, 0xd0, 0x99, - 0x85, 0x58, 0x1b, 0xc4, 0xeb, 0xe2, 0xcf, 0xe9, 0x99, 0x9a, 0xdb, 0x5c, 0x0c, 0x14, 0x8f, 0xb9, 0xcf, 0xc8, 0xfa, - 0x04, 0xd2, 0xe9, 0x59, 0xfb, 0xd4, 0x1c, 0xd3, 0x69, 0x9c, 0x50, 0x16, 0x4c, 0xda, 0x3b, 0x59, 0xae, 0xf7, 0xef, - 0x7e, 0xfb, 0xf4, 0x9b, 0xfb, 0x89, 0xe2, 0xcc, 0x10, 0x9d, 0x99, 0x3b, 0x7a, 0xab, 0xdf, 0x67, 0x40, 0x1a, 0x32, - 0xc8, 0xfb, 0x2c, 0x6e, 0x5f, 0x5f, 0xd7, 0x07, 0x8d, 0x31, 0xfb, 0x96, 0x31, 0xbf, 0xf3, 0x12, 0x1a, 0x92, 0x2c, - 0xb8, 0x13, 0x34, 0x63, 0xf7, 0x68, 0xb9, 0x16, 0x6b, 0x8c, 0x17, 0xde, 0x23, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, - 0xd5, 0x62, 0x5c, 0xa4, 0x41, 0x6d, 0x36, 0x22, 0x8c, 0x4d, 0xe5, 0xa6, 0xef, 0x2d, 0xd7, 0xea, 0x15, 0x5d, 0x34, - 0x93, 0x37, 0x75, 0x35, 0xfe, 0xe0, 0x22, 0x98, 0x4c, 0x42, 0x9a, 0x97, 0x16, 0xba, 0xbc, 0x96, 0x0a, 0x70, 0x24, - 0x1c, 0xc8, 0x38, 0x8d, 0xc3, 0x55, 0x46, 0x9b, 0xc1, 0xc5, 0x80, 0xd3, 0x71, 0x0b, 0xe0, 0xe0, 0xef, 0xf2, 0x58, - 0x7b, 0x40, 0x6e, 0xc3, 0x36, 0x71, 0x07, 0x10, 0x6e, 0xdc, 0xee, 0x96, 0x87, 0x0e, 0xaf, 0xe4, 0xa0, 0xad, 0x86, - 0x89, 0x58, 0x70, 0x2d, 0x31, 0xec, 0xad, 0x39, 0x1e, 0x2f, 0x93, 0x21, 0x97, 0x65, 0x51, 0x5e, 0x9e, 0xcc, 0x6f, - 0x73, 0xc6, 0x5e, 0x35, 0x9f, 0xb1, 0x57, 0xe2, 0x8c, 0x6d, 0xdf, 0x99, 0x4f, 0xa7, 0x1e, 0xfc, 0x37, 0x28, 0x26, - 0xd4, 0x77, 0xb5, 0xee, 0x72, 0xad, 0x79, 0xcb, 0xb5, 0x66, 0x77, 0x96, 0x6b, 0x0d, 0xbb, 0x46, 0xcb, 0x0a, 0xcb, - 0xe9, 0x98, 0x96, 0xab, 0x41, 0x21, 0xfc, 0xb9, 0xa5, 0x57, 0xde, 0x21, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, - 0xf6, 0xa3, 0xce, 0xce, 0x92, 0x40, 0xda, 0xa6, 0x93, 0x91, 0xf1, 0x98, 0x4e, 0xfa, 0xd3, 0xd8, 0x5f, 0xa5, 0x7f, - 0xe7, 0xe3, 0xe7, 0x40, 0xdc, 0x8a, 0x08, 0x2a, 0xfd, 0x88, 0xa6, 0xa0, 0xef, 0xb8, 0xa3, 0xa2, 0x87, 0x8d, 0x5c, - 0xa7, 0x3e, 0x8b, 0x8d, 0xde, 0x71, 0x0e, 0x1b, 0x36, 0x79, 0x33, 0xa0, 0x7f, 0xb3, 0x55, 0x6a, 0x47, 0x31, 0xbf, - 0x02, 0x2c, 0x5b, 0xc1, 0xf1, 0x78, 0x68, 0xf0, 0xd5, 0x74, 0x4f, 0x9a, 0x87, 0x7b, 0x2d, 0xbe, 0x74, 0x23, 0x2e, - 0x15, 0x7e, 0x6f, 0x71, 0x87, 0xaf, 0xed, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x5b, 0x2e, 0x84, 0xa2, 0xee, 0x9e, - 0x58, 0xfe, 0xe9, 0xab, 0x43, 0xf8, 0x8f, 0x51, 0xf5, 0x3f, 0x66, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xff, 0x81, 0x91, - 0x4a, 0x48, 0x88, 0xef, 0x5f, 0x7f, 0x3a, 0x7d, 0x5c, 0x83, 0xbd, 0x6b, 0x33, 0xa3, 0xa4, 0x6a, 0xed, 0xaf, 0xe2, - 0x18, 0xf2, 0xf6, 0xd6, 0xab, 0x0b, 0xf0, 0x30, 0x17, 0x8f, 0x6c, 0x08, 0x8d, 0x04, 0x1f, 0xc1, 0x94, 0xf1, 0x3a, - 0xb6, 0x61, 0xac, 0xc4, 0xdb, 0x36, 0x56, 0xe2, 0xcd, 0x6e, 0x56, 0xe2, 0xdb, 0xbd, 0x58, 0x89, 0x37, 0x9f, 0x9d, - 0x95, 0x78, 0x5b, 0x67, 0x25, 0xae, 0x62, 0x61, 0x89, 0x6a, 0x5d, 0xac, 0xf8, 0xcf, 0x0f, 0x4c, 0xb7, 0x76, 0x19, - 0x0f, 0x7b, 0x2e, 0x8b, 0x77, 0x7e, 0xf5, 0x8b, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd1, 0x30, 0xab, 0x60, 0x2d, 0x38, - 0x66, 0xc7, 0xef, 0x28, 0xc5, 0x61, 0x1c, 0xcd, 0xbe, 0x07, 0xdd, 0x2a, 0x88, 0x03, 0x13, 0xe5, 0x45, 0x90, 0x7e, - 0x1f, 0x2f, 0x57, 0xcb, 0x0b, 0xe8, 0xeb, 0x43, 0x90, 0x06, 0xe3, 0x90, 0xca, 0x30, 0x04, 0xcc, 0x90, 0x8c, 0xcb, - 0xc4, 0xc1, 0x76, 0x53, 0xfc, 0x24, 0x6b, 0xf1, 0x13, 0xad, 0x3b, 0xf9, 0x6f, 0x66, 0xa1, 0xa6, 0x37, 0x33, 0x22, - 0x10, 0xb0, 0xab, 0x32, 0xe8, 0xc7, 0x33, 0x23, 0x57, 0xb1, 0xd9, 0x30, 0x4b, 0x61, 0xb6, 0xd0, 0xda, 0x0f, 0xad, - 0x31, 0x35, 0x2b, 0xd3, 0x92, 0xf1, 0xf7, 0xea, 0x62, 0xf8, 0x45, 0xbc, 0x4a, 0xe9, 0x24, 0xbe, 0x8f, 0x74, 0x2b, - 0x95, 0xae, 0x35, 0xa0, 0xa8, 0x94, 0x6d, 0x30, 0x73, 0xac, 0xd4, 0xcc, 0xe8, 0x90, 0xb8, 0x78, 0xb5, 0xb4, 0x99, - 0xc6, 0xd8, 0xc6, 0x29, 0xea, 0x32, 0xc5, 0xd9, 0x13, 0xc3, 0x88, 0x87, 0x8f, 0x6b, 0x29, 0x2c, 0x2e, 0x62, 0x87, - 0x4b, 0x85, 0x53, 0x23, 0x15, 0xc2, 0x45, 0x11, 0x04, 0xa7, 0x61, 0xe1, 0xf8, 0x1b, 0xe6, 0x12, 0x5e, 0xbc, 0x85, - 0x10, 0x42, 0xf9, 0x8a, 0xaf, 0x07, 0x0f, 0x09, 0xc3, 0x1e, 0x5f, 0x2b, 0x60, 0x7c, 0x77, 0x47, 0x93, 0x90, 0x3c, - 0x18, 0x66, 0x1e, 0x47, 0xdf, 0x01, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0x33, 0x35, 0x35, 0xec, 0xa5, 0xc6, - 0xe0, 0x45, 0xe0, 0xae, 0xa5, 0x8c, 0x00, 0x72, 0x64, 0xcf, 0xe8, 0x5f, 0x2c, 0xf6, 0xef, 0x5f, 0xcd, 0xdc, 0xba, - 0x8c, 0xe5, 0x87, 0xfe, 0xbc, 0xdc, 0xe3, 0x33, 0xcf, 0x9f, 0x3f, 0x69, 0x9f, 0xb6, 0x01, 0xe9, 0xc2, 0x45, 0xe6, - 0x6b, 0xa3, 0xa1, 0xb5, 0xd9, 0x7a, 0x0a, 0x60, 0x14, 0x57, 0xf1, 0xca, 0x9f, 0xa3, 0xc9, 0xe8, 0xe7, 0x9b, 0x6f, - 0x06, 0x7d, 0x62, 0x8a, 0x62, 0x39, 0xf5, 0x4a, 0x51, 0x01, 0x05, 0xfc, 0xfe, 0x5b, 0x88, 0xbe, 0xfb, 0x6f, 0x04, - 0x43, 0x7d, 0xd7, 0x70, 0x2e, 0x3e, 0x78, 0xdc, 0xe6, 0x1d, 0x40, 0x26, 0x5d, 0x1e, 0xd7, 0x46, 0x28, 0xd7, 0x9a, - 0x91, 0x4c, 0x5e, 0x05, 0x9a, 0x1a, 0x43, 0xb2, 0x2d, 0x3c, 0xa6, 0xf8, 0x0a, 0x75, 0x18, 0x9b, 0xce, 0x4d, 0xf6, - 0x2d, 0xca, 0xb1, 0x55, 0x05, 0xc9, 0x70, 0xcb, 0x05, 0x8a, 0xe8, 0xab, 0xfa, 0x6e, 0x11, 0x44, 0x16, 0xa6, 0x80, - 0xa8, 0xbf, 0x21, 0x6b, 0x08, 0x82, 0x0e, 0xc8, 0xad, 0xfa, 0x0a, 0x0a, 0x2d, 0xaa, 0x78, 0x8b, 0x42, 0x9e, 0x37, - 0xbd, 0x11, 0x12, 0x42, 0x8b, 0x37, 0xfa, 0x9d, 0xa6, 0x69, 0x9a, 0x64, 0x23, 0x34, 0xc9, 0x47, 0x60, 0x39, 0xb2, - 0x03, 0xa0, 0x2d, 0xc9, 0x97, 0x6b, 0x56, 0x02, 0x9c, 0x01, 0x98, 0x78, 0xc8, 0x02, 0x1e, 0xe7, 0xb3, 0xe7, 0x8a, - 0x02, 0xc1, 0xd0, 0x43, 0x8c, 0x46, 0x92, 0x40, 0x38, 0xf0, 0xbe, 0x86, 0x0c, 0x3b, 0xbe, 0xe5, 0x92, 0x60, 0xcd, - 0x65, 0x8f, 0xa3, 0x01, 0x6d, 0x0e, 0x08, 0x99, 0x2a, 0x58, 0x10, 0xb4, 0x0e, 0x95, 0xf8, 0xee, 0x16, 0x6d, 0xc0, - 0x8d, 0xc8, 0x17, 0xad, 0xb3, 0x05, 0x8d, 0x56, 0x3a, 0x26, 0x84, 0xc3, 0xe0, 0xe2, 0x50, 0xe7, 0x0d, 0x23, 0xb6, - 0x00, 0xdb, 0x34, 0xb7, 0x9c, 0xb3, 0xbb, 0x30, 0xe2, 0x28, 0x95, 0x58, 0x3e, 0x57, 0x6c, 0x46, 0x1c, 0xb7, 0x55, - 0x6f, 0x08, 0xbe, 0xa4, 0x71, 0xd5, 0x7d, 0x91, 0xd9, 0x14, 0x43, 0x1f, 0x2c, 0x34, 0x0e, 0x17, 0x17, 0x09, 0xb0, - 0x1b, 0xa4, 0xba, 0x68, 0x52, 0x23, 0x43, 0x2a, 0x82, 0xa2, 0xc4, 0xac, 0x77, 0xc3, 0xc7, 0x09, 0x51, 0xc9, 0x5a, - 0xfb, 0xf1, 0x6b, 0xfd, 0xb4, 0x4c, 0xfa, 0x96, 0x3e, 0xb0, 0x8b, 0x84, 0x81, 0xea, 0x96, 0x3e, 0x80, 0x09, 0xdf, - 0x5b, 0x90, 0xa6, 0xe8, 0x5b, 0xd0, 0xb5, 0x05, 0x79, 0x3e, 0x7c, 0x88, 0x54, 0xb7, 0xe5, 0x00, 0xb9, 0xf9, 0x16, - 0x2c, 0x8e, 0x20, 0x86, 0x94, 0xee, 0xe2, 0x10, 0x73, 0x63, 0x79, 0xa3, 0x11, 0xc6, 0x76, 0xc3, 0xd1, 0x30, 0x5f, - 0x78, 0xae, 0x7b, 0x50, 0xab, 0x0f, 0x82, 0xec, 0xa6, 0xda, 0xa6, 0x95, 0x0d, 0x3d, 0xd7, 0x0e, 0x5e, 0x38, 0x9d, - 0x41, 0xed, 0x8e, 0x56, 0x02, 0xc9, 0x8e, 0x50, 0xfc, 0x75, 0xf6, 0x6c, 0x63, 0xa4, 0x2d, 0xe0, 0x2d, 0x8c, 0xcf, - 0x71, 0x6c, 0x39, 0x97, 0x7f, 0x8d, 0xea, 0x57, 0x3f, 0x0b, 0x63, 0xcb, 0x92, 0x1a, 0x8d, 0x20, 0x14, 0xba, 0x01, - 0xc7, 0xe8, 0xf7, 0xda, 0x4b, 0xcd, 0x60, 0xc7, 0xc7, 0x34, 0x47, 0x03, 0x81, 0x51, 0x84, 0x5b, 0x97, 0xda, 0x41, - 0xe5, 0x8b, 0x51, 0x15, 0xc3, 0xf1, 0xa0, 0xcb, 0xb4, 0xd0, 0xe8, 0x6d, 0xa5, 0x16, 0xb0, 0xff, 0x96, 0xeb, 0xd3, - 0x19, 0x43, 0xbc, 0x0f, 0xa8, 0x01, 0x89, 0x13, 0x76, 0x76, 0xb8, 0x5a, 0x96, 0xbb, 0x2b, 0x5f, 0x92, 0xfb, 0x77, - 0x86, 0x97, 0x0e, 0xea, 0xd0, 0x64, 0x7f, 0xcd, 0xd7, 0xdd, 0x23, 0xbb, 0xa4, 0xd1, 0xa4, 0xdc, 0x61, 0xe5, 0xfe, - 0xda, 0xbf, 0xbb, 0x12, 0x46, 0x81, 0x8c, 0x22, 0x71, 0x03, 0x46, 0xc9, 0xe3, 0x08, 0x37, 0x3f, 0x3b, 0x6e, 0xc1, - 0x5e, 0x54, 0x0c, 0x36, 0x60, 0xe1, 0x00, 0x65, 0x33, 0x45, 0x28, 0x0e, 0x61, 0xeb, 0xd1, 0x19, 0xde, 0x10, 0x84, - 0x68, 0xeb, 0x4e, 0xcc, 0x84, 0x69, 0x60, 0xd1, 0x26, 0xe0, 0x81, 0x68, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, - 0xd9, 0x2e, 0xa9, 0x35, 0x73, 0x4c, 0xba, 0x4f, 0xc8, 0x52, 0xf1, 0x6d, 0x13, 0xc4, 0xb9, 0xea, 0xe2, 0x56, 0x12, - 0x75, 0xa3, 0x1f, 0x93, 0x68, 0x55, 0xeb, 0x8d, 0x19, 0xfb, 0xa1, 0xf8, 0x5b, 0x61, 0x50, 0x84, 0x42, 0x5d, 0x95, - 0x8d, 0x5f, 0x15, 0xb2, 0x71, 0xc6, 0xd5, 0x14, 0x2e, 0x29, 0x82, 0xfa, 0x57, 0xdc, 0xbd, 0x24, 0x77, 0x50, 0xb8, - 0x7d, 0x15, 0x23, 0x55, 0x1c, 0x99, 0x0a, 0x46, 0x43, 0x71, 0x8f, 0x13, 0x5c, 0x46, 0xd9, 0x4b, 0xae, 0x5c, 0xb5, - 0xf0, 0x63, 0x2a, 0xca, 0x41, 0xea, 0x8e, 0x43, 0x96, 0xc5, 0xea, 0xb6, 0x29, 0x3b, 0xb2, 0xa8, 0xaf, 0x95, 0x4d, - 0x22, 0x3d, 0x4e, 0x18, 0x80, 0x85, 0x98, 0xbe, 0xa2, 0xd7, 0x96, 0x36, 0x10, 0x38, 0xc8, 0x06, 0x07, 0xb9, 0xdd, - 0xd2, 0x79, 0x96, 0x2c, 0xa5, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0x84, 0xef, 0xcd, 0xa6, 0xe1, 0x96, 0xc7, 0x4b, 0x9e, - 0xdf, 0xef, 0x20, 0x5e, 0xd4, 0x5c, 0x55, 0x91, 0x8f, 0x27, 0xd3, 0x66, 0x56, 0xb6, 0x58, 0xb5, 0xde, 0x29, 0x13, - 0xe2, 0x6c, 0xb8, 0x8f, 0x49, 0x59, 0x46, 0xcf, 0x6b, 0xf4, 0xc5, 0x77, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0x26, 0xb6, - 0xb0, 0xb3, 0x84, 0xf8, 0xb7, 0xca, 0x90, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0xc1, 0x80, 0x60, 0x1c, 0x58, - 0xda, 0x77, 0x3a, 0xa9, 0x22, 0x7d, 0xe9, 0x3f, 0x75, 0xbb, 0xe4, 0xd5, 0xf4, 0xb0, 0x22, 0x14, 0xed, 0xf4, 0xca, - 0x22, 0xf3, 0x96, 0x71, 0x64, 0xf3, 0xd5, 0x62, 0xbc, 0x51, 0x65, 0xab, 0x8a, 0xc8, 0xb5, 0x2e, 0x66, 0x55, 0x3f, - 0x3b, 0x9d, 0x4e, 0xcb, 0x82, 0x46, 0x57, 0x3b, 0x44, 0x61, 0xe1, 0x53, 0xd7, 0x75, 0xab, 0x63, 0xdf, 0x0e, 0x76, - 0x1b, 0xe5, 0xb6, 0x27, 0x8d, 0x23, 0x46, 0xd8, 0xee, 0x82, 0x5f, 0x1d, 0x1c, 0xb9, 0x53, 0x9c, 0xec, 0x92, 0x59, - 0xc4, 0x80, 0x19, 0x43, 0x04, 0x19, 0x5d, 0xa4, 0x7d, 0x9f, 0xa2, 0x0e, 0xc6, 0x51, 0x0e, 0x34, 0x1a, 0x0e, 0xd8, - 0x33, 0x30, 0x15, 0xf1, 0xc4, 0xae, 0x70, 0x35, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0x78, 0x50, 0x36, 0x75, - 0x99, 0x36, 0x4e, 0xab, 0xe7, 0xfe, 0xbe, 0x54, 0x4f, 0x83, 0x0b, 0x70, 0x23, 0x14, 0xda, 0x4c, 0x3e, 0x8b, 0xff, - 0x2f, 0xe5, 0xff, 0xaf, 0x96, 0xeb, 0xb2, 0xfd, 0xc8, 0x09, 0x48, 0xb4, 0x8b, 0xd3, 0xc2, 0x46, 0xdd, 0xb4, 0x07, - 0xa4, 0x95, 0xc1, 0x54, 0x55, 0xa0, 0x83, 0x92, 0xbe, 0x94, 0xfd, 0xa7, 0x41, 0xfc, 0x8e, 0x14, 0x33, 0x2c, 0x71, - 0x21, 0x42, 0x2c, 0x72, 0x57, 0xc2, 0x1c, 0xac, 0x97, 0x27, 0xa8, 0x3f, 0x28, 0xed, 0x09, 0xd0, 0xc6, 0xd7, 0xe6, - 0xb6, 0x97, 0xb8, 0xbf, 0xaa, 0xd7, 0x12, 0x1d, 0x03, 0xc8, 0x3c, 0x38, 0x84, 0x68, 0x48, 0xa0, 0x55, 0x36, 0x37, - 0x1b, 0xa5, 0x7c, 0xab, 0xea, 0xd9, 0xc4, 0xc0, 0xb0, 0xbb, 0xe6, 0x2a, 0xac, 0x6f, 0xa1, 0x2d, 0x80, 0xc9, 0xf2, - 0xed, 0x87, 0xcf, 0x36, 0x2c, 0xb1, 0xba, 0x1f, 0x3d, 0x5c, 0x72, 0xdc, 0xbf, 0x36, 0xde, 0x9d, 0x29, 0x3b, 0xff, - 0x28, 0x5f, 0xfc, 0xb6, 0x51, 0xa0, 0x77, 0x55, 0x92, 0xd0, 0x71, 0xa3, 0xef, 0x8e, 0xb9, 0x57, 0xed, 0x45, 0x10, - 0xed, 0x5f, 0x97, 0xac, 0xf7, 0xae, 0x0b, 0x17, 0xc6, 0xde, 0x95, 0xe1, 0xc6, 0x61, 0x96, 0x0b, 0xd9, 0xf0, 0x5b, - 0x45, 0xa0, 0xa8, 0xfa, 0xef, 0xea, 0xd8, 0x8a, 0x51, 0xf9, 0x57, 0x2b, 0x20, 0x3e, 0xf7, 0xca, 0xee, 0xa2, 0x89, - 0x04, 0x8d, 0xfa, 0xb1, 0x76, 0xa2, 0x1d, 0x77, 0xb5, 0x23, 0x57, 0x67, 0x5c, 0xd8, 0x50, 0xef, 0x75, 0x0a, 0xbf, - 0xbc, 0x43, 0x57, 0x3f, 0x3b, 0x9d, 0x89, 0x4b, 0x62, 0x1a, 0x84, 0x21, 0x43, 0x15, 0x60, 0xfe, 0x7b, 0x4b, 0xcb, - 0x6a, 0x16, 0x56, 0xc6, 0x8d, 0x40, 0x3a, 0xe2, 0x11, 0xce, 0x8e, 0x4f, 0x96, 0x7d, 0x3c, 0x1b, 0x6a, 0x21, 0x18, - 0x70, 0xb2, 0x52, 0xfc, 0x04, 0xdc, 0xc1, 0x63, 0xfd, 0xec, 0x14, 0xe2, 0x97, 0x6a, 0x93, 0xa1, 0xfe, 0x5d, 0xe7, - 0x58, 0xf3, 0x7a, 0x77, 0x76, 0xd7, 0x77, 0x6d, 0xcf, 0x39, 0xd4, 0x5c, 0xe7, 0xc8, 0xee, 0x38, 0xc7, 0x5a, 0xc7, - 0xe9, 0xc1, 0xbf, 0xbe, 0xe7, 0xbc, 0xd2, 0x5c, 0x78, 0xd2, 0x3c, 0xa7, 0x8b, 0xff, 0x76, 0x9c, 0xe3, 0xbb, 0x2e, - 0xbb, 0xe9, 0x89, 0xf4, 0x8e, 0xaa, 0x8c, 0x02, 0x7c, 0x39, 0xf4, 0x83, 0xb3, 0xd3, 0x55, 0x4a, 0xb5, 0xf5, 0x50, - 0x7f, 0xa5, 0x6b, 0xf3, 0x84, 0x4e, 0x87, 0xfa, 0x53, 0xa2, 0x94, 0x7a, 0x27, 0x8d, 0xc5, 0x9d, 0xe3, 0xc6, 0xe2, - 0xee, 0x51, 0x63, 0xf1, 0x61, 0xaf, 0x5c, 0x7c, 0x30, 0x63, 0xaf, 0x94, 0xf4, 0xa1, 0x0b, 0x92, 0x25, 0xc1, 0xda, - 0xf0, 0x34, 0x40, 0xd7, 0x36, 0xfc, 0x73, 0xdc, 0x31, 0x65, 0xab, 0x31, 0xb4, 0x92, 0xd0, 0x38, 0x3e, 0xd1, 0xbc, - 0xa3, 0x6f, 0x3a, 0x47, 0x3e, 0xd4, 0x83, 0x64, 0xb7, 0xf0, 0x77, 0xd7, 0x3d, 0xf1, 0x5d, 0x0d, 0x1a, 0x7a, 0xf0, - 0xdf, 0xbc, 0xd7, 0xf1, 0xd9, 0x83, 0x0b, 0xef, 0x3f, 0x78, 0xc7, 0xa9, 0x6b, 0x7b, 0xf0, 0xdf, 0xcf, 0x52, 0xe5, - 0x0e, 0x0a, 0x7f, 0xb5, 0xdf, 0x43, 0x57, 0xeb, 0x9e, 0xcc, 0x3b, 0xce, 0xab, 0xbb, 0x63, 0xe7, 0x64, 0xee, 0x1d, - 0x7f, 0x60, 0x4f, 0xa1, 0xdd, 0x71, 0x5e, 0xc1, 0xdf, 0x87, 0xae, 0x3b, 0xb7, 0x3d, 0xe7, 0xe4, 0xae, 0xeb, 0x74, - 0x43, 0xfb, 0xc8, 0x39, 0x81, 0xbf, 0x9f, 0x01, 0xbc, 0x00, 0x57, 0x9e, 0x9d, 0x58, 0x83, 0x8d, 0x51, 0xb1, 0xdf, - 0x50, 0x3f, 0xd2, 0x39, 0xd4, 0x7a, 0x87, 0xdf, 0x9c, 0xdc, 0xd9, 0x87, 0x73, 0xaf, 0x73, 0x67, 0xb7, 0xfe, 0xfc, - 0x00, 0x90, 0xdf, 0xbe, 0x70, 0x00, 0x46, 0x4c, 0x47, 0xf4, 0xbb, 0x91, 0x75, 0xd9, 0x26, 0x46, 0x7f, 0xbf, 0x5b, - 0x8c, 0xfe, 0xf5, 0x6a, 0x1f, 0x31, 0xfa, 0xfb, 0xcf, 0x2e, 0x46, 0xbf, 0xac, 0x5a, 0x71, 0xbf, 0xaf, 0xa6, 0x4d, - 0xf8, 0x71, 0x53, 0x25, 0x92, 0x03, 0x62, 0x5c, 0x5f, 0xad, 0x6e, 0x20, 0xe2, 0xd5, 0xfb, 0x78, 0xf8, 0xf5, 0xaa, - 0x64, 0xa2, 0x14, 0x03, 0x06, 0x78, 0x1f, 0x33, 0x0c, 0xf0, 0xa7, 0xd5, 0x10, 0xec, 0x22, 0xf8, 0xad, 0x19, 0x4c, - 0xec, 0x39, 0x09, 0xa7, 0xf2, 0xc6, 0x85, 0x92, 0x01, 0x16, 0x83, 0xdd, 0x3d, 0x5c, 0x26, 0xa0, 0xac, 0x59, 0x2d, - 0xa2, 0xb4, 0x7f, 0xe4, 0x02, 0x9a, 0xef, 0x4c, 0x93, 0xbc, 0xd2, 0xd8, 0x11, 0x31, 0xc2, 0x3e, 0x72, 0xcb, 0xfc, - 0xd6, 0xf7, 0x68, 0xb2, 0xd6, 0xdc, 0xbb, 0x57, 0xef, 0x57, 0x03, 0x5b, 0x10, 0x61, 0xd2, 0x07, 0xc4, 0x46, 0xd3, - 0xfb, 0xb2, 0xe1, 0x58, 0xc5, 0x54, 0xb0, 0x7d, 0xa4, 0x30, 0x92, 0x6a, 0x7b, 0xaf, 0x6c, 0x78, 0xb6, 0x6b, 0x9a, - 0x0d, 0x9f, 0x2f, 0x35, 0xdf, 0x62, 0xf5, 0x26, 0x3b, 0xae, 0x82, 0xaa, 0x92, 0xf4, 0xaf, 0x11, 0x20, 0x05, 0xed, - 0x59, 0x98, 0xc6, 0x15, 0x84, 0x8f, 0xab, 0xe1, 0x6d, 0xec, 0x2a, 0xef, 0x4a, 0x7d, 0xaa, 0xe6, 0x74, 0x2f, 0x36, - 0x48, 0x0f, 0x06, 0x3f, 0x03, 0x61, 0xc3, 0xef, 0xe3, 0x71, 0xac, 0xc2, 0x79, 0xa3, 0xf4, 0xcb, 0x48, 0xed, 0x7c, - 0xee, 0x6d, 0xea, 0xa4, 0x4d, 0xab, 0x21, 0xad, 0x47, 0x17, 0xe2, 0x8e, 0xc6, 0xcf, 0x33, 0xb3, 0xd5, 0x9c, 0x99, - 0x16, 0xa3, 0x65, 0xee, 0xb6, 0xce, 0x44, 0xbd, 0xa7, 0xb0, 0x89, 0x2d, 0xfe, 0xa0, 0xfa, 0x7f, 0x6f, 0xa6, 0x90, - 0xa0, 0xbd, 0x8f, 0x44, 0x84, 0x42, 0x41, 0x75, 0xd0, 0xc6, 0x76, 0xb0, 0xc5, 0xfc, 0x43, 0xed, 0x98, 0x77, 0x82, - 0xb6, 0xba, 0xdb, 0x2c, 0x46, 0xa4, 0x6b, 0xc3, 0xa6, 0xa4, 0x40, 0xf5, 0x7a, 0xc7, 0x96, 0x77, 0x64, 0x39, 0xc7, - 0x3d, 0x33, 0x17, 0x07, 0x4e, 0xed, 0xb2, 0x04, 0x10, 0x30, 0xd9, 0x95, 0xc3, 0x0c, 0xa2, 0x20, 0x0b, 0x48, 0x98, - 0x03, 0xaa, 0x2f, 0xd3, 0xbc, 0x7f, 0x5b, 0xa5, 0x19, 0xcc, 0x51, 0x90, 0x64, 0x68, 0xae, 0x6c, 0x8f, 0x69, 0x76, - 0x4f, 0x69, 0xd4, 0xa2, 0xca, 0xad, 0x5a, 0x3f, 0xff, 0x76, 0xb6, 0xa0, 0x39, 0xb3, 0xb3, 0x18, 0x67, 0x11, 0xdf, - 0x1f, 0xc2, 0x54, 0x37, 0x1f, 0x59, 0x3f, 0xb7, 0x21, 0xdc, 0xbf, 0xed, 0x46, 0xb8, 0x19, 0xdd, 0x07, 0xe1, 0xfe, - 0xed, 0xb3, 0x23, 0xdc, 0x9f, 0x55, 0x84, 0x5b, 0xf2, 0x54, 0x29, 0x64, 0xa2, 0x3f, 0xe0, 0xb3, 0x01, 0xf1, 0xc6, - 0x5f, 0xea, 0x07, 0x8c, 0xbc, 0xd4, 0x95, 0x3c, 0xd0, 0x1f, 0x4a, 0x89, 0xad, 0x90, 0x65, 0xc7, 0xd0, 0xc3, 0x2c, - 0x89, 0x0e, 0xe4, 0x48, 0x76, 0x85, 0xfb, 0x21, 0xf4, 0x79, 0x11, 0x65, 0xa1, 0xf3, 0x9e, 0xb3, 0x25, 0xa0, 0x82, - 0xf8, 0x3a, 0x4e, 0x16, 0x04, 0x83, 0x22, 0xea, 0x98, 0x10, 0x13, 0x1e, 0x5c, 0x70, 0x18, 0xf3, 0xe3, 0x68, 0x22, - 0xe5, 0xe8, 0x74, 0x78, 0xcd, 0xe8, 0x41, 0xfd, 0x81, 0x92, 0x44, 0xb7, 0xd8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xf7, - 0x45, 0xe7, 0xf0, 0xc5, 0x91, 0x0b, 0xff, 0xf3, 0x68, 0x37, 0xb7, 0x78, 0xc5, 0x45, 0x1c, 0x41, 0x4e, 0x1e, 0x51, - 0xb3, 0xad, 0xda, 0x3d, 0xa5, 0xb7, 0x45, 0xad, 0xe3, 0xe6, 0x4a, 0x13, 0xf2, 0x50, 0xd4, 0x69, 0xac, 0x31, 0x8f, - 0x57, 0xca, 0xb0, 0x1a, 0x46, 0x13, 0x44, 0x2b, 0x90, 0x0c, 0x29, 0x35, 0xd4, 0xd7, 0x7c, 0xba, 0xc5, 0xbc, 0x68, - 0x37, 0xbf, 0x29, 0x12, 0x7f, 0x89, 0x04, 0x44, 0x3b, 0x21, 0xc8, 0x85, 0xea, 0x2e, 0xa6, 0x0d, 0xc0, 0x68, 0x6f, - 0x1a, 0xa4, 0xdd, 0x14, 0x0b, 0x44, 0xd8, 0x02, 0x65, 0xc9, 0x2a, 0xf2, 0x0d, 0xfc, 0x49, 0xc6, 0xa9, 0x11, 0x1c, - 0x40, 0x4c, 0x5e, 0xfc, 0xb0, 0x89, 0xab, 0x46, 0xce, 0xdc, 0x22, 0x4b, 0x4a, 0x24, 0x56, 0x85, 0xbc, 0xc8, 0xac, - 0x84, 0xe5, 0x56, 0xc6, 0xa5, 0xb5, 0x87, 0xe4, 0x85, 0x6c, 0xf8, 0x22, 0xb3, 0x20, 0xbf, 0x31, 0x2c, 0xf7, 0xf3, - 0xe7, 0xac, 0x16, 0x64, 0x1c, 0x65, 0xd3, 0x3a, 0xf7, 0x65, 0x96, 0x42, 0x5d, 0x23, 0xb3, 0x58, 0xc7, 0x2c, 0x85, - 0x7d, 0xdf, 0x8a, 0x5f, 0xbe, 0x3c, 0x1b, 0x7a, 0x26, 0xcf, 0x97, 0x5b, 0x4a, 0xee, 0x76, 0xb9, 0x9f, 0x6a, 0xdc, - 0x6c, 0x74, 0xda, 0x5a, 0x06, 0xd1, 0x4c, 0x68, 0xa6, 0x25, 0xf6, 0x82, 0x64, 0x2b, 0x4c, 0x05, 0x46, 0x84, 0x8a, - 0x5a, 0xd4, 0xb9, 0xa3, 0x09, 0xe4, 0xfa, 0x1d, 0xea, 0x5d, 0xc7, 0x75, 0x5c, 0x5d, 0x36, 0x9c, 0x06, 0xb3, 0xe1, - 0x26, 0xce, 0x08, 0xa4, 0xad, 0x0a, 0xe3, 0x19, 0x78, 0x7e, 0x64, 0x41, 0x16, 0x42, 0x0e, 0x24, 0x70, 0x01, 0x59, - 0x30, 0xae, 0x31, 0xe7, 0xf6, 0xb8, 0x24, 0xb9, 0xc5, 0x3c, 0x98, 0xc2, 0xe9, 0x0b, 0x23, 0xcb, 0x7c, 0x07, 0x97, - 0xa1, 0xa1, 0x1b, 0x90, 0x85, 0x95, 0x26, 0xa9, 0xad, 0xda, 0xb7, 0xf7, 0x35, 0x68, 0x63, 0xea, 0x7c, 0x12, 0xd3, - 0x84, 0x2c, 0x20, 0x5d, 0xc0, 0x26, 0xb7, 0x38, 0xa6, 0xd5, 0x39, 0xaa, 0xd5, 0xbc, 0x57, 0x47, 0x96, 0xd6, 0xf1, - 0x2c, 0xcd, 0x05, 0x74, 0xab, 0xe7, 0xd6, 0x26, 0xbf, 0x19, 0xec, 0x52, 0xd1, 0x31, 0xfc, 0xf2, 0x94, 0xcd, 0x83, - 0x29, 0xe7, 0xb8, 0xf0, 0x33, 0x63, 0x41, 0x3d, 0x0d, 0x25, 0x90, 0x7f, 0xc0, 0xc4, 0xf4, 0x57, 0x74, 0x9d, 0x99, - 0x98, 0x23, 0x88, 0x57, 0x09, 0xcc, 0x0d, 0xba, 0xa6, 0x05, 0x91, 0x16, 0x7c, 0xfa, 0x64, 0x04, 0x60, 0x7e, 0x3f, - 0x54, 0xe0, 0x03, 0xcf, 0x66, 0x09, 0x60, 0x41, 0xa1, 0x58, 0x42, 0x60, 0x81, 0x6f, 0x0c, 0xfc, 0x5b, 0x14, 0x8b, - 0x1f, 0x5c, 0xb1, 0xe7, 0x84, 0x24, 0x9a, 0x01, 0x4a, 0x23, 0xd1, 0xac, 0x66, 0x40, 0xc0, 0xbc, 0xeb, 0x2a, 0xa5, - 0x45, 0x57, 0x85, 0x72, 0x3f, 0xfd, 0xea, 0xe1, 0x8a, 0xe5, 0x40, 0x33, 0x74, 0xb8, 0xe5, 0xd0, 0x15, 0xac, 0xd0, - 0x3d, 0xbc, 0x1c, 0x7e, 0x71, 0xba, 0xa0, 0x19, 0x61, 0x82, 0x4b, 0x60, 0xf1, 0x80, 0x1c, 0xd0, 0x7c, 0x91, 0xbf, - 0x98, 0x31, 0x78, 0x13, 0x7a, 0x17, 0xf8, 0x9c, 0x4f, 0xb3, 0x34, 0x7e, 0x4f, 0xd9, 0x68, 0xa3, 0x34, 0xf4, 0x2c, - 0x66, 0x22, 0xeb, 0x13, 0x0c, 0xfd, 0x39, 0x8c, 0x62, 0xfd, 0xec, 0x0b, 0xe9, 0x4d, 0xd4, 0xb6, 0x08, 0x90, 0x88, - 0xf4, 0x3a, 0xa1, 0xe1, 0xdf, 0x87, 0x5f, 0xc0, 0xc5, 0xfd, 0xc5, 0x8d, 0x6e, 0x0e, 0x32, 0x07, 0xf9, 0x98, 0x2f, - 0x1a, 0x12, 0x72, 0x22, 0x8f, 0xca, 0x99, 0xcd, 0xae, 0xc2, 0x6c, 0xc2, 0xef, 0xdd, 0xac, 0x2b, 0xb8, 0xa9, 0x3e, - 0x84, 0xf4, 0x0c, 0xb8, 0x8b, 0x4d, 0x89, 0xe7, 0xf4, 0x06, 0xc8, 0xa0, 0x8e, 0x43, 0xe2, 0xdf, 0x0a, 0x0e, 0x55, - 0x7d, 0xd8, 0x87, 0x17, 0x95, 0x94, 0x5d, 0xe3, 0x5e, 0xc6, 0xad, 0xbc, 0xc1, 0x2f, 0xe3, 0xa7, 0xee, 0xe7, 0x41, - 0x26, 0x99, 0x61, 0x7c, 0xc8, 0xd1, 0x37, 0x16, 0xc6, 0x57, 0xb0, 0x3f, 0xc0, 0xa0, 0x7a, 0x27, 0xdf, 0xf4, 0xee, - 0x3c, 0x77, 0xde, 0xf1, 0x1c, 0x60, 0x73, 0xe6, 0x5d, 0xe7, 0x38, 0xb4, 0xbb, 0xce, 0x31, 0xfc, 0x7d, 0x00, 0xd6, - 0xcb, 0xee, 0x38, 0x87, 0x1f, 0xbc, 0x4e, 0x68, 0x9f, 0x38, 0xc7, 0xf0, 0x77, 0xc9, 0x5a, 0xfd, 0x88, 0x4c, 0x0f, - 0x30, 0x3c, 0x5f, 0x94, 0xb0, 0x80, 0xf2, 0x5b, 0x6a, 0x11, 0xac, 0xd2, 0xf5, 0xd6, 0xa0, 0x89, 0x00, 0x94, 0xa1, - 0x5b, 0x22, 0x4a, 0x60, 0x3a, 0x30, 0xd2, 0x21, 0xcf, 0x6d, 0x21, 0x0c, 0x32, 0x84, 0xd7, 0xa4, 0xc8, 0xbc, 0xd0, - 0x78, 0x8c, 0x78, 0x9b, 0xe6, 0x30, 0xfb, 0x22, 0x69, 0x1a, 0x53, 0x5d, 0xfc, 0x79, 0x89, 0xf1, 0x71, 0xa8, 0x59, - 0xc3, 0x4a, 0x45, 0xe2, 0xce, 0x7c, 0xf7, 0xc0, 0xd1, 0x6f, 0x94, 0xca, 0xc4, 0x51, 0x9f, 0xb5, 0x6f, 0xae, 0xce, - 0x90, 0xbd, 0xff, 0xd2, 0x7e, 0x30, 0x5f, 0x32, 0xeb, 0x47, 0x44, 0xd8, 0x9d, 0x04, 0x89, 0x1c, 0x9e, 0x82, 0xa2, - 0xbd, 0xe6, 0xfc, 0x04, 0x26, 0x64, 0xd8, 0xb9, 0x00, 0x2a, 0xf9, 0x8e, 0x84, 0x8a, 0xe9, 0x85, 0xd2, 0xf2, 0x89, - 0xc4, 0xfc, 0xcf, 0x9f, 0x17, 0x83, 0xb3, 0x2b, 0xe3, 0x3e, 0xf5, 0x7a, 0x70, 0xed, 0xf6, 0x68, 0x77, 0xab, 0x15, - 0xd0, 0xee, 0x10, 0xcd, 0x45, 0x3c, 0x49, 0xa1, 0xe9, 0x17, 0x3a, 0xc6, 0x56, 0x53, 0xa4, 0x9a, 0x86, 0x11, 0xc2, - 0x5b, 0x57, 0x58, 0x1d, 0xdd, 0x1c, 0xa4, 0xfb, 0x84, 0xa5, 0xe6, 0xbc, 0x98, 0x0e, 0xa0, 0xd9, 0x32, 0x8f, 0x1d, - 0x2e, 0x8d, 0xff, 0xee, 0x49, 0xa0, 0x7b, 0x11, 0x68, 0xf8, 0x2a, 0xa7, 0xb5, 0xe4, 0x6e, 0x22, 0xef, 0x55, 0x76, - 0xa1, 0xd2, 0xf4, 0x5c, 0x87, 0x22, 0x48, 0xbd, 0x86, 0xd9, 0x16, 0xa5, 0x79, 0x93, 0xbc, 0x2d, 0x8a, 0x02, 0x2b, - 0x80, 0xc8, 0xef, 0x86, 0x70, 0x75, 0x32, 0x9f, 0x3f, 0x6f, 0xbd, 0x84, 0x98, 0x3a, 0x59, 0x4d, 0x3a, 0xab, 0xab, - 0xf8, 0x4d, 0x57, 0x51, 0x8c, 0xec, 0x17, 0xb1, 0x86, 0xb0, 0xca, 0x62, 0x7b, 0x0f, 0x7f, 0x8e, 0x29, 0xc9, 0x1c, - 0xae, 0x07, 0x31, 0x94, 0xcb, 0xdd, 0xf2, 0x68, 0x17, 0xec, 0xb1, 0x78, 0x18, 0x2d, 0x1e, 0x33, 0xee, 0xd9, 0xe6, - 0xc3, 0x8a, 0xfb, 0x21, 0x43, 0x1f, 0x9f, 0xdc, 0x22, 0x06, 0xca, 0xbb, 0x8c, 0xb0, 0x40, 0x19, 0xea, 0x95, 0x1b, - 0x67, 0x44, 0xa4, 0x38, 0x02, 0xba, 0x7c, 0xd0, 0xa8, 0x30, 0x54, 0x7c, 0x95, 0xcf, 0xde, 0x5d, 0x7d, 0xa9, 0xf1, - 0xfd, 0xcf, 0xf4, 0x5b, 0xc8, 0xc8, 0xb0, 0x5c, 0x17, 0x43, 0x96, 0xeb, 0x42, 0xe3, 0x59, 0x67, 0x20, 0x63, 0x44, - 0x7e, 0xc0, 0x20, 0xa8, 0x6b, 0x34, 0xf2, 0x99, 0xd6, 0x6f, 0xb1, 0x0a, 0xb3, 0x60, 0x49, 0x92, 0xec, 0x00, 0x9a, - 0xda, 0x80, 0xe4, 0xf4, 0x36, 0x0f, 0x66, 0xa6, 0x38, 0x14, 0x42, 0xb5, 0x2c, 0x12, 0x9a, 0xc3, 0x69, 0x10, 0x4a, - 0xc5, 0xa1, 0xf8, 0x00, 0xf1, 0x7d, 0xba, 0xcc, 0x86, 0x3a, 0x59, 0x42, 0xce, 0x13, 0x0c, 0x63, 0x7a, 0x10, 0xfb, - 0x19, 0xcd, 0xec, 0x34, 0x4b, 0x28, 0x59, 0xe8, 0x32, 0x64, 0x67, 0xbd, 0xbf, 0x74, 0x35, 0x5e, 0x04, 0x99, 0x8c, - 0x79, 0xc7, 0x26, 0x08, 0x2a, 0x3c, 0x18, 0x22, 0x84, 0x33, 0x60, 0x20, 0xbc, 0x8c, 0x67, 0x95, 0x1d, 0x55, 0x50, - 0x2e, 0xe7, 0x4a, 0x5c, 0x09, 0x10, 0x8e, 0xfa, 0x71, 0xf8, 0x91, 0x7b, 0x5d, 0xcb, 0xd0, 0x7c, 0xfa, 0xd9, 0x29, - 0x67, 0x6f, 0x35, 0x0c, 0x14, 0xa0, 0xf7, 0x5c, 0x08, 0x36, 0xdb, 0xe6, 0x8f, 0x7d, 0xc0, 0x2b, 0xab, 0x91, 0x15, - 0xfa, 0x97, 0x7c, 0x2c, 0x57, 0x40, 0x08, 0x95, 0x54, 0xbc, 0x73, 0xef, 0x4c, 0x3a, 0x00, 0xe1, 0xa8, 0x90, 0x56, - 0xfa, 0xf4, 0xe9, 0xf5, 0xe8, 0x9f, 0xff, 0x80, 0x14, 0x04, 0x73, 0x4f, 0x78, 0x41, 0x5f, 0xab, 0xb5, 0x38, 0xf5, - 0x69, 0x8d, 0x50, 0xbd, 0x4f, 0x27, 0x22, 0x2a, 0x8c, 0xd8, 0x5a, 0xf9, 0xe8, 0x46, 0x44, 0x6c, 0x82, 0x34, 0x23, - 0xa6, 0xf0, 0xd5, 0x1e, 0xc1, 0xf2, 0x8e, 0x44, 0x88, 0x00, 0xed, 0xa7, 0xf5, 0x57, 0xc7, 0x9a, 0x5e, 0xe4, 0x0e, - 0x68, 0xd0, 0x41, 0xb3, 0x3d, 0x74, 0x76, 0x4a, 0xb8, 0xf0, 0x15, 0xc8, 0x8f, 0xb4, 0x7f, 0x00, 0xd3, 0x9c, 0xc7, - 0x0b, 0xea, 0x04, 0xf1, 0xc1, 0x3d, 0x1d, 0xdb, 0x64, 0x19, 0x30, 0xf9, 0x32, 0xca, 0xdd, 0x34, 0x46, 0xf9, 0x49, - 0x05, 0x2d, 0xa3, 0xaf, 0xf3, 0x02, 0x94, 0x71, 0x01, 0x28, 0xf8, 0x49, 0xce, 0xca, 0x71, 0xf8, 0x1c, 0x91, 0x17, - 0xa2, 0x8c, 0xe5, 0xcf, 0x59, 0x38, 0x3d, 0x11, 0x39, 0xaf, 0x78, 0xb0, 0xe3, 0xe9, 0x54, 0x8d, 0x9d, 0xe7, 0x94, - 0xbf, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0xc9, 0xbe, 0x54, 0xff, 0x84, 0xfc, 0x09, 0xb1, 0x40, 0x78, 0x98, 0x45, - 0x38, 0xcf, 0xb5, 0x18, 0x7c, 0x12, 0x24, 0x4f, 0x59, 0x25, 0x8e, 0x28, 0xaa, 0xd1, 0xd9, 0x5b, 0x48, 0x93, 0x27, - 0xc3, 0x21, 0xc3, 0x63, 0x55, 0x74, 0x06, 0x50, 0x6a, 0xc8, 0x91, 0x01, 0x93, 0xcd, 0xa0, 0xa1, 0xcd, 0x3c, 0xb8, - 0xb0, 0x51, 0x75, 0x3a, 0xf5, 0x31, 0x1e, 0x10, 0xb1, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5f, 0x58, 0x40, 0xe0, - 0xa2, 0x9f, 0x0a, 0x1e, 0xd7, 0xfe, 0xc0, 0x50, 0xb6, 0x1d, 0x92, 0x87, 0x58, 0xd1, 0xac, 0x73, 0x27, 0xfb, 0x4b, - 0x2c, 0xbd, 0x12, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0xb3, 0x00, 0xd4, 0x4f, 0x93, 0x1a, 0xb6, 0x7f, 0xd7, 0x61, 0x52, - 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xf4, 0x00, 0xe6, 0x07, 0x81, - 0x01, 0x4a, 0x94, 0x51, 0x60, 0x42, 0xf4, 0x01, 0x92, 0x32, 0xeb, 0x80, 0x8b, 0x89, 0x20, 0xea, 0x90, 0x73, 0x94, - 0x41, 0x3e, 0x4b, 0x55, 0xea, 0xc4, 0x8a, 0xdb, 0x4c, 0xe5, 0xed, 0xce, 0xc0, 0xf1, 0xa7, 0x15, 0xa6, 0xdf, 0xc8, - 0x07, 0x19, 0x15, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x46, 0xb0, 0x6e, 0xa9, 0x50, 0xec, 0xe3, - 0x6d, 0xb5, 0x0a, 0xd2, 0x48, 0x56, 0x5b, 0x12, 0x43, 0x7f, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, 0x65, - 0x36, 0x84, 0xaa, 0x42, 0xd8, 0x4e, 0x96, 0x4b, 0x56, 0xd9, 0x1c, 0x9c, 0x1e, 0x30, 0xbe, 0xf3, 0x8c, 0xed, 0xb0, - 0xb3, 0x53, 0xb0, 0x2e, 0x64, 0x8b, 0x4e, 0x96, 0x4b, 0xbe, 0xa4, 0xec, 0x17, 0x7b, 0x73, 0x30, 0xcf, 0x16, 0xe1, - 0xd9, 0xff, 0x01, 0xff, 0xd7, 0x9f, 0x05, 0x1b, 0x5f, 0x03, 0x00}; + 0x1e, 0x7f, 0xcb, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0x6f, 0xaf, 0x16, 0x93, 0xc1, 0xe0, 0xd6, 0xdf, 0xdf, 0xf3, 0x70, + 0x76, 0x3b, 0x67, 0xd7, 0xfc, 0x9e, 0x16, 0xd3, 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, + 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, + 0xde, 0xdb, 0x9a, 0x86, 0xb7, 0xfc, 0xa3, 0x77, 0xed, 0x4f, 0xaf, 0x75, 0xcc, 0xcd, 0x44, 0x1d, 0x49, 0x6f, 0x2f, + 0x9e, 0xb3, 0x5f, 0xf9, 0x27, 0x79, 0x9c, 0x7c, 0x11, 0x72, 0xd2, 0xde, 0x20, 0x77, 0x13, 0x9d, 0x12, 0xef, 0xdc, + 0x44, 0xc2, 0x82, 0x40, 0x18, 0x8e, 0x9a, 0x3f, 0x4c, 0xca, 0xa9, 0xb7, 0x03, 0x6e, 0x57, 0x6e, 0xeb, 0x9f, 0x6f, + 0x39, 0xe7, 0x8b, 0xe1, 0xe5, 0xf4, 0x5d, 0xb7, 0x4b, 0x8f, 0x8a, 0x66, 0x53, 0x81, 0x6e, 0xb7, 0x18, 0x7b, 0x75, + 0x32, 0xb3, 0xcc, 0x25, 0x5f, 0x7a, 0x57, 0x9b, 0x99, 0xc7, 0xf4, 0x7e, 0x33, 0xcd, 0x90, 0xc8, 0x17, 0x08, 0x99, + 0x0e, 0x87, 0xbb, 0x73, 0x2c, 0x8f, 0x0f, 0xdf, 0x3e, 0x7b, 0x32, 0x78, 0x82, 0x91, 0x5b, 0x56, 0x34, 0xc8, 0x3b, + 0x3e, 0xcc, 0xea, 0xd6, 0x6d, 0xe3, 0xe2, 0xf9, 0xf0, 0x17, 0xc8, 0x1b, 0x74, 0x3d, 0x34, 0x45, 0xb4, 0xca, 0xef, + 0x28, 0xfa, 0x44, 0xc9, 0x41, 0xc7, 0x13, 0xa8, 0x1d, 0x52, 0xe0, 0xbe, 0x7b, 0xc6, 0x41, 0xbf, 0x81, 0xa5, 0xf6, + 0xfb, 0xe7, 0x9f, 0x88, 0x47, 0x1a, 0xc6, 0xfb, 0xfb, 0x30, 0xfa, 0x23, 0x2e, 0x8b, 0x35, 0x9c, 0xae, 0x03, 0xf8, + 0xdc, 0x33, 0x7d, 0xfb, 0xba, 0xf3, 0x7d, 0x3f, 0xf0, 0xb6, 0xfc, 0x86, 0xbd, 0xe3, 0xde, 0xe5, 0xf0, 0xad, 0xff, + 0xec, 0x09, 0x88, 0x4e, 0x30, 0x2e, 0x9f, 0x31, 0x12, 0xb6, 0xa3, 0x18, 0xb5, 0x0a, 0x3f, 0xd7, 0x10, 0xa2, 0xf5, + 0x09, 0x19, 0xbb, 0x20, 0xfd, 0x83, 0x02, 0xf4, 0x13, 0x02, 0xab, 0x49, 0x6a, 0x14, 0x98, 0xc4, 0xb7, 0x35, 0x24, + 0x90, 0x82, 0x05, 0x42, 0x6f, 0xa0, 0xf8, 0x54, 0xf0, 0x77, 0xc3, 0xcf, 0x24, 0xf9, 0x2d, 0x6a, 0x3e, 0x86, 0xbf, + 0x61, 0x68, 0x26, 0xd5, 0x43, 0x5a, 0x47, 0x89, 0xf7, 0x93, 0xbf, 0x8f, 0xc2, 0x4a, 0xa8, 0x63, 0x21, 0x48, 0xc5, + 0x90, 0x0b, 0x71, 0xf1, 0x7c, 0x72, 0x5b, 0x8a, 0xf0, 0x8f, 0x09, 0x3e, 0x93, 0x0b, 0x4d, 0x3e, 0xa3, 0x27, 0x8d, + 0x7c, 0xff, 0x41, 0xbe, 0x2f, 0x3b, 0x35, 0x58, 0xd4, 0x43, 0x7e, 0x5b, 0xbb, 0xef, 0xcb, 0x29, 0x41, 0x8f, 0xec, + 0x07, 0x34, 0x05, 0x03, 0x35, 0x01, 0x29, 0x43, 0x70, 0x0b, 0x57, 0x7d, 0x4f, 0x15, 0xe4, 0xcb, 0xef, 0x7d, 0x16, + 0x32, 0x5c, 0x65, 0x41, 0x48, 0x72, 0xa9, 0x90, 0xc2, 0xc6, 0x6d, 0x3d, 0xf8, 0xac, 0x31, 0x49, 0x24, 0xe4, 0x94, + 0x80, 0x24, 0x69, 0x6f, 0x20, 0x49, 0xc4, 0xf4, 0x1f, 0xae, 0x93, 0xa6, 0x59, 0x49, 0xe9, 0x86, 0x38, 0x55, 0xaf, + 0x91, 0xe6, 0x2c, 0x78, 0xcf, 0x60, 0xe9, 0x48, 0xb1, 0xe2, 0x9d, 0x31, 0x18, 0xeb, 0x60, 0xa1, 0x3b, 0x59, 0xdc, + 0xaf, 0x92, 0x30, 0x8d, 0x44, 0x95, 0x2f, 0x42, 0xfe, 0xfc, 0x97, 0x12, 0x7f, 0xf4, 0x96, 0x06, 0x22, 0x10, 0xfc, + 0x00, 0xad, 0x07, 0xac, 0xf1, 0xe0, 0x27, 0x56, 0x97, 0x61, 0x5e, 0x65, 0x54, 0xde, 0x6c, 0xc7, 0xb6, 0x73, 0xa6, + 0xaa, 0x16, 0x7c, 0x16, 0x86, 0x16, 0xed, 0x6c, 0xd5, 0x9c, 0xdc, 0xe6, 0x0d, 0xbe, 0x33, 0x49, 0x22, 0xb5, 0x94, + 0x44, 0xda, 0xea, 0xfa, 0x74, 0xe9, 0x75, 0x8b, 0x0a, 0x1a, 0x23, 0x40, 0x2f, 0x49, 0x77, 0x95, 0x4f, 0x28, 0x5e, + 0x59, 0x0d, 0xab, 0xe1, 0xa5, 0x43, 0x11, 0xc6, 0xda, 0x9b, 0x2b, 0x79, 0x76, 0x07, 0xd6, 0x23, 0xb4, 0x76, 0x55, + 0xea, 0x10, 0xb6, 0x9f, 0xe8, 0x3d, 0xa7, 0x52, 0x7f, 0x03, 0xaa, 0xc0, 0xa9, 0xa3, 0xa1, 0x3e, 0x6a, 0xa7, 0x90, + 0xed, 0xdc, 0x5b, 0x12, 0x54, 0xae, 0xe4, 0xa6, 0x4a, 0x8b, 0x52, 0xca, 0x94, 0xaf, 0x65, 0xb6, 0xb2, 0xfb, 0x64, + 0x00, 0xf1, 0x6c, 0x50, 0x20, 0xb9, 0xa8, 0xad, 0xe6, 0x20, 0x7d, 0x34, 0x4b, 0x1c, 0x6b, 0x07, 0x85, 0x97, 0x55, + 0x60, 0xe6, 0x32, 0x97, 0xcb, 0x41, 0xc1, 0x72, 0xbd, 0xd5, 0x4c, 0x33, 0xd5, 0x17, 0xb9, 0xbd, 0xcd, 0x78, 0x99, + 0xfe, 0x9b, 0x25, 0x03, 0x1e, 0x5d, 0x3c, 0xf7, 0x03, 0x48, 0x93, 0xbc, 0x0e, 0x90, 0x04, 0x9b, 0x83, 0x5d, 0xec, + 0x30, 0x6c, 0x15, 0x2b, 0x7b, 0xf2, 0x74, 0xb9, 0x43, 0x53, 0x2e, 0x61, 0x24, 0x27, 0xe6, 0x52, 0xea, 0xfb, 0x92, + 0xea, 0x86, 0x82, 0x93, 0x4d, 0x13, 0x50, 0x0a, 0x68, 0xb7, 0xe0, 0xbf, 0xf0, 0xa9, 0xa1, 0xd3, 0x02, 0x2c, 0xb5, + 0xdd, 0x80, 0xff, 0x42, 0xbf, 0xd8, 0x3e, 0xa2, 0x7e, 0x60, 0x1e, 0xec, 0xcd, 0xda, 0xca, 0x18, 0x10, 0x91, 0xb8, + 0x82, 0x3c, 0x12, 0xfc, 0xa0, 0xd8, 0xd3, 0x65, 0xe2, 0xc0, 0x99, 0xe2, 0x62, 0x29, 0xb5, 0x99, 0x79, 0xed, 0xb7, + 0xd4, 0xc4, 0x9b, 0x28, 0x89, 0x0a, 0xdb, 0x21, 0x8d, 0x5e, 0x52, 0xc6, 0x54, 0xc1, 0x86, 0xe8, 0xbe, 0x6e, 0x82, + 0x29, 0xf0, 0xa6, 0xaa, 0x02, 0x22, 0xd4, 0x5e, 0x64, 0x79, 0x7e, 0xd3, 0x05, 0x56, 0x17, 0x7c, 0x6c, 0x4c, 0xb3, + 0x0b, 0x56, 0x72, 0x35, 0x93, 0x3e, 0xf3, 0x76, 0xa0, 0x85, 0xbc, 0xcb, 0xcb, 0xa2, 0x15, 0xba, 0x1e, 0x44, 0x0b, + 0x7f, 0xaf, 0x39, 0x1e, 0x3d, 0xdb, 0x56, 0x53, 0x9b, 0x7d, 0xad, 0xc5, 0x02, 0x19, 0x88, 0x86, 0xbe, 0x90, 0x33, + 0x0a, 0x77, 0x95, 0xe6, 0x6a, 0xb5, 0xaf, 0xca, 0x20, 0x81, 0x89, 0x20, 0x6b, 0x59, 0x78, 0x8f, 0xee, 0xd5, 0x23, + 0xcd, 0x2b, 0x09, 0x9e, 0xb9, 0xf8, 0x0b, 0x00, 0xa1, 0x3c, 0x49, 0xc8, 0x01, 0x39, 0x80, 0xbf, 0xa5, 0x28, 0x95, + 0x06, 0xf8, 0x67, 0x75, 0x39, 0xb6, 0xf5, 0xfd, 0x9d, 0x56, 0x31, 0xb8, 0xfe, 0x7c, 0xdd, 0xf5, 0xac, 0x1d, 0xe2, + 0x5c, 0xd9, 0xea, 0xb5, 0x65, 0x9a, 0xc7, 0x48, 0x5d, 0x03, 0x70, 0x27, 0xd2, 0x23, 0x10, 0xc9, 0x4c, 0x34, 0xc8, + 0xd9, 0x0b, 0x3e, 0x9e, 0x8a, 0xc7, 0xa4, 0xbd, 0xca, 0xf7, 0xcd, 0x85, 0x3e, 0x18, 0x63, 0xdf, 0x82, 0x06, 0xf1, + 0xd1, 0x6a, 0x6b, 0x05, 0x62, 0xbd, 0x55, 0xea, 0x43, 0x37, 0x46, 0x41, 0x07, 0x8f, 0xb8, 0x91, 0x0b, 0x8e, 0xed, + 0xae, 0xad, 0xa7, 0xf4, 0x15, 0x80, 0xb9, 0x0e, 0x54, 0x32, 0x0c, 0x52, 0xe7, 0x89, 0xc2, 0x24, 0x3f, 0x4f, 0x48, + 0x42, 0x44, 0x75, 0xb6, 0x1c, 0xa5, 0xdc, 0xb4, 0x80, 0xcb, 0x8c, 0x0c, 0x30, 0x9b, 0x34, 0xeb, 0x27, 0x97, 0x2f, + 0x41, 0x2a, 0x0d, 0x11, 0xdc, 0xb0, 0xbd, 0x64, 0x74, 0xeb, 0xa8, 0x1b, 0x54, 0x49, 0xe6, 0xfa, 0xcd, 0xed, 0x2c, + 0x52, 0xe6, 0xcd, 0x47, 0x18, 0x6b, 0xf2, 0x21, 0xac, 0x13, 0xfc, 0x36, 0x40, 0x25, 0x7d, 0x2a, 0xbc, 0x68, 0x04, + 0x10, 0xea, 0x3b, 0x55, 0xc6, 0xa7, 0xc2, 0xcb, 0x46, 0x5b, 0x96, 0x51, 0x0a, 0xd5, 0x05, 0xb3, 0x5b, 0xd3, 0x85, + 0xe8, 0x56, 0xd5, 0x40, 0x1b, 0xb8, 0x76, 0x1d, 0x28, 0xa0, 0xa1, 0xda, 0x95, 0x1b, 0x16, 0x80, 0xd5, 0x4c, 0x04, + 0x86, 0xcb, 0xbf, 0xcf, 0x5f, 0xa9, 0x18, 0x9e, 0x7e, 0x3f, 0xf4, 0xf6, 0xdb, 0x20, 0x1a, 0x6d, 0x2f, 0xd9, 0x2e, + 0x88, 0x46, 0xbb, 0xcb, 0x86, 0xd1, 0xef, 0xe7, 0xf4, 0xfb, 0x79, 0x03, 0x3a, 0x12, 0x61, 0xc2, 0xec, 0xf5, 0x1b, + 0xb5, 0x7c, 0xa5, 0xd6, 0xef, 0xd4, 0xf2, 0xa5, 0x1a, 0xde, 0xda, 0x93, 0x44, 0x10, 0x59, 0xaa, 0x9a, 0x07, 0x49, + 0x91, 0x6a, 0xe9, 0x72, 0x8c, 0x16, 0x23, 0x6a, 0x29, 0x6b, 0x8e, 0x75, 0x22, 0xed, 0x1c, 0x94, 0x0c, 0x70, 0xb4, + 0xb8, 0xaa, 0x31, 0xdd, 0xac, 0x68, 0x09, 0xc4, 0x08, 0x2b, 0xdb, 0x72, 0x71, 0x93, 0xfa, 0xe8, 0x9c, 0x7c, 0xdb, + 0x2a, 0xe5, 0xdb, 0x56, 0xf0, 0xfc, 0x2b, 0x0a, 0xe5, 0x92, 0x6b, 0xd7, 0xb2, 0x69, 0xa1, 0x14, 0xca, 0xb8, 0x06, + 0x5b, 0xfb, 0x26, 0x30, 0x64, 0x3e, 0x52, 0xd4, 0xd8, 0x5e, 0x34, 0xca, 0x21, 0xc8, 0xd6, 0xc1, 0xa8, 0x53, 0x16, + 0x2c, 0xbe, 0xdd, 0x21, 0x03, 0x19, 0xe8, 0xa8, 0x6a, 0xe3, 0xd5, 0xce, 0x4a, 0x7f, 0x58, 0x5e, 0x3c, 0x67, 0x89, + 0x95, 0x4e, 0x7e, 0x53, 0xa1, 0x3f, 0x08, 0xd1, 0x37, 0x65, 0xc3, 0xc1, 0x8b, 0x2e, 0xb6, 0x32, 0x20, 0xde, 0x30, + 0xbd, 0xb7, 0xb1, 0x92, 0xe5, 0xae, 0x29, 0x5f, 0xcc, 0x78, 0xc2, 0x71, 0xf4, 0xe5, 0x6a, 0x11, 0xd6, 0x6a, 0x91, + 0x9d, 0x00, 0x0f, 0xad, 0xd5, 0x52, 0xc8, 0xd5, 0x22, 0x9c, 0x99, 0x2e, 0xd4, 0x4c, 0xcf, 0x40, 0xf3, 0x28, 0xd4, + 0x2c, 0x4f, 0x00, 0x0b, 0x5e, 0x98, 0x19, 0x2e, 0xcc, 0x0c, 0xc7, 0x21, 0x35, 0x4e, 0x0f, 0x7a, 0xaf, 0x73, 0xcf, + 0x2d, 0x77, 0xa3, 0xd3, 0x30, 0x6f, 0x47, 0x1b, 0xcc, 0xf1, 0x41, 0x38, 0x81, 0xf8, 0xc0, 0x12, 0x01, 0x7a, 0x34, + 0xac, 0x8e, 0x1a, 0x2a, 0x47, 0xf1, 0x65, 0x01, 0x48, 0x96, 0x04, 0x20, 0xb9, 0x57, 0xe3, 0x5c, 0x5a, 0x7e, 0x5d, + 0x25, 0x21, 0x47, 0x64, 0xbc, 0x94, 0x76, 0xf7, 0x84, 0x97, 0x23, 0x23, 0x34, 0x4f, 0x16, 0xa9, 0x97, 0xb3, 0x8c, + 0x8d, 0x11, 0xb8, 0x28, 0xf4, 0x9b, 0xaa, 0xdf, 0x4f, 0x4b, 0x2f, 0xa7, 0x76, 0x7e, 0x02, 0x7f, 0xcb, 0x53, 0x67, + 0x91, 0x23, 0xe4, 0xd5, 0xc8, 0x24, 0x2c, 0x2f, 0x95, 0x7a, 0xfa, 0x12, 0x66, 0x50, 0x77, 0x6f, 0x14, 0x80, 0x6b, + 0x91, 0x4b, 0xa7, 0xda, 0x12, 0xae, 0x4c, 0xb9, 0xc1, 0x3e, 0x0f, 0x79, 0x4e, 0x42, 0xa8, 0x44, 0x1e, 0x29, 0xac, + 0xfb, 0xf6, 0xc5, 0xf3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x0e, 0x00, 0x73, 0x30, 0xf5, 0xa2, 0x01, 0x2f, + 0xd5, 0x9c, 0xf9, 0xe8, 0xe5, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x33, 0xf9, 0xc8, 0xf8, 0x96, 0xf9, + 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, 0x6c, 0x50, + 0x09, 0x36, 0x0d, 0x5f, 0x4b, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, 0x1b, 0xb3, + 0x31, 0x2b, 0xd4, 0xce, 0x93, 0xcb, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, 0x71, 0xce, + 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, 0xa6, 0x25, + 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, 0xe8, 0x95, + 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x73, 0xfe, 0x52, + 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd1, 0xb4, 0x04, 0x75, 0x80, + 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x39, 0xe7, 0x5f, 0x6a, 0x43, 0x84, 0x8c, + 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, 0xc0, 0xe3, + 0xbc, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x1c, 0xf7, 0x4e, 0xd3, 0xb0, 0xfd, 0x17, 0xa0, 0x29, 0x86, 0x72, 0x3c, 0xdf, + 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xca, 0x42, 0xda, 0x96, 0x63, 0xb4, + 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xdc, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x7d, 0xdd, 0x63, 0x36, 0xc9, 0x8a, + 0x45, 0xae, 0x22, 0x4e, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, 0x41, 0xc9, + 0x72, 0x5e, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xd5, 0x9c, 0x52, 0xa8, + 0x7d, 0xc5, 0xc3, 0xea, 0xf4, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, 0x7c, 0xe7, + 0xeb, 0xf4, 0x8e, 0x42, 0x77, 0x9c, 0x99, 0x78, 0xaa, 0x02, 0x63, 0xdf, 0xda, 0x11, 0x14, 0x0e, 0x4d, 0xd7, 0x01, + 0x87, 0x69, 0x74, 0xc2, 0xe2, 0x9f, 0xd2, 0x71, 0xf2, 0xa2, 0x56, 0x88, 0x24, 0xff, 0x10, 0x2e, 0x0c, 0x89, 0x05, + 0x79, 0x49, 0xa8, 0x23, 0x32, 0x62, 0x35, 0x2a, 0xd6, 0x42, 0x45, 0xc5, 0x29, 0x1e, 0x6f, 0x15, 0x14, 0x97, 0xa2, + 0x54, 0x29, 0x15, 0xb9, 0x51, 0x29, 0x20, 0x96, 0x0d, 0xbc, 0x5b, 0xc0, 0x01, 0x10, 0x74, 0x96, 0xbb, 0xb5, 0xed, + 0x6e, 0x23, 0xf3, 0x99, 0x69, 0x9e, 0x56, 0x1f, 0xd4, 0xdf, 0xef, 0x97, 0x18, 0x5b, 0xe3, 0xe9, 0xef, 0xdb, 0xb4, + 0xe0, 0xe6, 0x6f, 0x18, 0xa2, 0x3b, 0x40, 0xc4, 0x2c, 0xed, 0xa1, 0x90, 0x05, 0x13, 0x96, 0xa1, 0x2a, 0x4f, 0x39, + 0xea, 0xe5, 0x93, 0x5b, 0x80, 0x50, 0x43, 0xbf, 0x36, 0x3a, 0xd5, 0x55, 0x09, 0xc2, 0xf7, 0x5d, 0xa1, 0x1e, 0x9b, + 0x03, 0x9e, 0x0c, 0x80, 0xbf, 0x22, 0xaf, 0xf5, 0xd8, 0xfe, 0x41, 0x6f, 0xd4, 0x1b, 0x20, 0x88, 0xce, 0x79, 0xe1, + 0x1f, 0x71, 0xae, 0x53, 0x7f, 0xc6, 0x85, 0x20, 0xbe, 0xf5, 0x24, 0xbc, 0x17, 0x67, 0x69, 0x1c, 0x9c, 0xf5, 0x06, + 0xe6, 0x22, 0x50, 0x9c, 0xa5, 0xf9, 0x19, 0x88, 0xe5, 0x88, 0x89, 0x58, 0xb3, 0x3b, 0x80, 0x09, 0x2c, 0x75, 0x1c, + 0xb2, 0xea, 0xd8, 0x7e, 0xff, 0xcd, 0xc8, 0x90, 0xa5, 0x23, 0x0c, 0x8c, 0xfe, 0x5d, 0x81, 0x00, 0x05, 0xcb, 0xcc, + 0xf6, 0x60, 0xd2, 0xd5, 0x9e, 0xd5, 0xf3, 0x66, 0x93, 0x77, 0xf5, 0x8e, 0xd5, 0xb4, 0x9c, 0x9a, 0x56, 0x59, 0x4d, + 0x9b, 0xe4, 0x50, 0x33, 0xd1, 0xef, 0x6b, 0x50, 0xd4, 0x7c, 0x0e, 0x60, 0x6c, 0x98, 0xfc, 0x66, 0x56, 0xcd, 0xfb, + 0x7d, 0x4f, 0x3e, 0x82, 0x5f, 0xc8, 0x56, 0xe6, 0xd6, 0x58, 0x3e, 0x7d, 0x4d, 0x24, 0x66, 0x06, 0xe6, 0xe8, 0xee, + 0x08, 0xdf, 0xeb, 0x46, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x0d, 0x0c, 0x9e, 0x27, 0x7c, 0x70, 0x91, 0xa3, + 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x1b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, 0x78, 0x90, + 0xfd, 0xfe, 0x0a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0xd7, 0x75, 0x51, 0x56, 0xd0, 0xb1, 0xf4, 0xf3, + 0x56, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x92, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, 0x2e, 0x3e, + 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0xe7, 0x7c, 0xb4, 0x2e, 0xd6, 0x1e, 0xf8, 0xc1, 0xcc, 0xd2, 0xb9, + 0x22, 0xce, 0xc8, 0xfd, 0xd1, 0xe7, 0x22, 0xcd, 0x29, 0x0f, 0x70, 0x1f, 0x8a, 0xb9, 0xfd, 0x16, 0x48, 0x3f, 0xf4, + 0x16, 0xc8, 0x3e, 0x3a, 0xe7, 0xe4, 0x0d, 0x20, 0xd2, 0x21, 0x0c, 0x6e, 0x45, 0x82, 0x8e, 0x55, 0xc3, 0x5b, 0x0b, + 0xec, 0xb4, 0x97, 0xc6, 0xbd, 0x34, 0x3f, 0x4b, 0xfb, 0x7d, 0x83, 0x9a, 0x99, 0x22, 0x1c, 0x3c, 0xce, 0xc8, 0x45, + 0xd2, 0x82, 0x2d, 0xa5, 0xfd, 0x57, 0x03, 0x47, 0x10, 0xf2, 0xf7, 0x3f, 0x84, 0xf7, 0x04, 0x20, 0x36, 0x69, 0x03, + 0xae, 0x7a, 0x4c, 0x47, 0x63, 0x4b, 0xa2, 0x56, 0x9d, 0x0d, 0x90, 0x38, 0x55, 0x5a, 0x4f, 0xb9, 0x59, 0x53, 0x18, + 0xa4, 0xca, 0x42, 0xfd, 0xc6, 0x7a, 0x32, 0x59, 0xe5, 0x22, 0x23, 0x8e, 0xca, 0xf4, 0xa5, 0x66, 0x04, 0xd3, 0xa5, + 0x9f, 0x2f, 0x60, 0xc9, 0xc6, 0x1f, 0x71, 0xf2, 0x96, 0x80, 0x63, 0x3b, 0x6b, 0x57, 0xd5, 0x2e, 0xc7, 0xad, 0xdd, + 0x1c, 0xe0, 0x7b, 0xbd, 0xd1, 0x68, 0xa4, 0x9d, 0xe3, 0x04, 0x0c, 0x55, 0x4f, 0x2d, 0x85, 0x1e, 0xab, 0x15, 0xa0, + 0x6e, 0x47, 0x2e, 0xb3, 0x64, 0x30, 0x5f, 0x18, 0xc7, 0xaf, 0xcc, 0x47, 0x1f, 0x2f, 0x95, 0xb5, 0xeb, 0x88, 0xaf, + 0xff, 0x20, 0xab, 0xf5, 0x2d, 0xef, 0xaa, 0x26, 0xe0, 0x8b, 0x2a, 0xa0, 0xf4, 0x1b, 0xde, 0x93, 0xbd, 0x8b, 0xaf, + 0xdd, 0x60, 0x97, 0x7c, 0xcb, 0x5b, 0xd4, 0x79, 0xbe, 0x72, 0x70, 0xa3, 0x4a, 0xb7, 0xf7, 0x92, 0x05, 0xae, 0xbd, + 0xa3, 0xa6, 0xb1, 0x9e, 0xf9, 0xd1, 0xc3, 0x22, 0x64, 0x3b, 0x1f, 0x7b, 0x5f, 0x35, 0x4f, 0xcf, 0x1a, 0x7a, 0x93, + 0x1a, 0xfa, 0xd8, 0x8b, 0xb2, 0x7d, 0x6a, 0x1a, 0xd1, 0x6b, 0xd8, 0xd0, 0xc7, 0xde, 0x92, 0x93, 0x43, 0x22, 0xc0, + 0xa9, 0x31, 0x7f, 0x7c, 0x38, 0x9d, 0xe1, 0xef, 0x18, 0x50, 0x09, 0xc4, 0x7c, 0x7a, 0x4c, 0x3b, 0x0a, 0x30, 0xa3, + 0x4a, 0x6f, 0x9f, 0x1e, 0xd8, 0x8e, 0x97, 0xf5, 0xd0, 0xd2, 0xbb, 0x27, 0x47, 0xb7, 0xe3, 0x55, 0x35, 0xbe, 0x94, + 0x43, 0x9e, 0xe7, 0xb3, 0xd1, 0x68, 0x24, 0x0c, 0x24, 0x77, 0xa5, 0x37, 0xb0, 0x02, 0x69, 0x5b, 0x54, 0x1f, 0xca, + 0xa5, 0xb7, 0x53, 0x87, 0x76, 0xe5, 0x4f, 0xf2, 0xc3, 0xa1, 0x18, 0x99, 0x63, 0x1c, 0xc0, 0x4d, 0x0a, 0x25, 0x47, + 0xc9, 0x5a, 0x82, 0xe8, 0x94, 0xc6, 0x53, 0x59, 0xaf, 0xad, 0x88, 0xbc, 0x1a, 0x71, 0x1e, 0x82, 0x1f, 0x3d, 0x50, + 0x8b, 0xbf, 0xd0, 0x82, 0xd8, 0x63, 0x9f, 0x2a, 0xa5, 0x17, 0xbc, 0x2a, 0x20, 0x44, 0xec, 0xef, 0x06, 0xda, 0x41, + 0x09, 0x0e, 0x25, 0xdc, 0x07, 0x84, 0x85, 0x7e, 0xed, 0xe5, 0x33, 0x19, 0xa3, 0xdc, 0x1b, 0x54, 0x73, 0x06, 0x30, + 0x95, 0x3e, 0x03, 0xbf, 0x4b, 0x80, 0x3a, 0xc5, 0xa7, 0xe8, 0x54, 0x6f, 0x1e, 0x36, 0x5d, 0x9f, 0x96, 0x28, 0x8a, + 0xe8, 0xce, 0xcf, 0xc7, 0x80, 0xd8, 0xd9, 0xb5, 0x19, 0x69, 0xd7, 0x7e, 0x83, 0x06, 0x2b, 0x25, 0x89, 0x76, 0x4e, + 0x09, 0xbb, 0x9d, 0x8f, 0x6c, 0xe9, 0x47, 0x29, 0x10, 0x73, 0xc7, 0x89, 0x44, 0xf6, 0x60, 0x23, 0x27, 0x70, 0x8b, + 0xf6, 0x8e, 0x0e, 0x40, 0xe5, 0x46, 0x41, 0x7e, 0x35, 0x47, 0x72, 0xc7, 0x77, 0xbd, 0xef, 0x06, 0xf5, 0xe0, 0xbb, + 0xde, 0x59, 0x4a, 0x72, 0x47, 0x78, 0xa6, 0xa6, 0x84, 0x88, 0xcf, 0xbe, 0x1b, 0xe4, 0x03, 0x3c, 0x4b, 0xb4, 0x48, + 0x8b, 0x84, 0x6a, 0x75, 0x8d, 0x9b, 0xf0, 0x22, 0x91, 0xdc, 0x43, 0xbb, 0xce, 0x23, 0x62, 0x01, 0xc8, 0x58, 0x7c, + 0x36, 0x6f, 0x28, 0xd4, 0xdd, 0xc4, 0x6c, 0xd1, 0x5d, 0x16, 0xfb, 0xfd, 0x6d, 0x9e, 0xd6, 0x3d, 0x1d, 0x1f, 0x83, + 0x2f, 0x48, 0x35, 0x01, 0x1e, 0xed, 0xaf, 0xcd, 0xf1, 0xea, 0xd5, 0xe6, 0x48, 0x59, 0xa8, 0x12, 0xf5, 0x5b, 0xac, + 0x66, 0x3d, 0x84, 0xe1, 0xce, 0x32, 0x63, 0x6d, 0x2f, 0x78, 0x25, 0x67, 0x55, 0x6c, 0x97, 0xe3, 0x2b, 0x96, 0xda, + 0x4a, 0xa2, 0x72, 0xb4, 0x1e, 0x6b, 0x53, 0x8c, 0xfc, 0x4a, 0x21, 0x51, 0x16, 0x1d, 0x5b, 0x0b, 0x05, 0xc4, 0x0b, + 0xd0, 0x97, 0xec, 0x4c, 0x03, 0xac, 0x37, 0x7a, 0x15, 0x11, 0x5a, 0x3e, 0x52, 0xe1, 0x4d, 0x6e, 0xaa, 0xcc, 0xca, + 0x66, 0xd1, 0xee, 0xa7, 0x8a, 0x57, 0x08, 0x56, 0x6f, 0xd4, 0x1e, 0x05, 0xa8, 0x3d, 0xb4, 0x50, 0x06, 0x90, 0xd2, + 0x34, 0x03, 0x40, 0x06, 0x00, 0x99, 0x2a, 0xe2, 0x33, 0x01, 0x2a, 0x6d, 0x75, 0xa3, 0xc0, 0x89, 0xf4, 0x1a, 0x68, + 0x16, 0x58, 0xe9, 0x23, 0x05, 0x19, 0x2c, 0xb6, 0x08, 0xc0, 0xca, 0x91, 0x33, 0x4c, 0x63, 0xc8, 0x36, 0x9a, 0xb8, + 0x24, 0xcd, 0xef, 0xc3, 0x2c, 0x95, 0x78, 0x12, 0x3f, 0xc8, 0x1a, 0x23, 0x00, 0x90, 0xbe, 0x4f, 0x2f, 0x8a, 0x2c, + 0x26, 0x1c, 0x38, 0xeb, 0xa9, 0x83, 0xa2, 0x26, 0xe7, 0x5a, 0xd3, 0xea, 0x59, 0x6d, 0xf2, 0x90, 0x05, 0x3a, 0x7b, + 0x30, 0x26, 0xb5, 0x7c, 0xcf, 0x23, 0xfb, 0x2b, 0xc7, 0x33, 0xc2, 0x77, 0xdd, 0xc1, 0xa9, 0xff, 0x6e, 0x6a, 0x60, + 0x62, 0x4a, 0x00, 0x36, 0x06, 0x47, 0x13, 0xe2, 0x77, 0x3a, 0x26, 0x53, 0x9b, 0x14, 0x81, 0xc0, 0x43, 0xf0, 0x0a, + 0x9e, 0x1b, 0x2e, 0xb7, 0xdc, 0xd8, 0x59, 0xe4, 0x69, 0x02, 0x70, 0xe2, 0x05, 0xdf, 0x02, 0x1c, 0xa7, 0x5e, 0x15, + 0xb2, 0x67, 0xcf, 0xc5, 0x74, 0x36, 0x0f, 0x1e, 0x12, 0xda, 0xbf, 0x98, 0xf0, 0x9b, 0xee, 0x2a, 0xb9, 0x32, 0xb5, + 0xee, 0x4d, 0x74, 0x95, 0xcb, 0x9d, 0x3e, 0xad, 0x38, 0x86, 0x39, 0x83, 0x55, 0x40, 0xce, 0xd9, 0x90, 0xbf, 0x38, + 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0xfe, 0x22, 0x94, 0xd5, 0x02, 0xb8, 0x47, 0xce, 0x23, 0xf3, 0xcb, 0x57, 0xdb, + 0xa1, 0x9c, 0x53, 0x14, 0xc6, 0x72, 0x6a, 0x5a, 0x52, 0x9c, 0x0e, 0x3d, 0x05, 0x93, 0xa9, 0x2d, 0x7f, 0x6f, 0x13, + 0x97, 0xd9, 0x9b, 0x49, 0x38, 0x5f, 0x47, 0xb6, 0xad, 0x55, 0xf7, 0xd0, 0x0d, 0xc1, 0xa0, 0x8f, 0x11, 0xb4, 0x6c, + 0xae, 0xef, 0xd6, 0x83, 0x81, 0xc2, 0xf6, 0xad, 0xe9, 0xa6, 0x45, 0xa7, 0x38, 0xe0, 0xcc, 0x5a, 0xd7, 0xa8, 0x54, + 0x15, 0x87, 0x5e, 0xf2, 0x6e, 0x59, 0x95, 0x5d, 0x96, 0x5e, 0x08, 0x52, 0xa3, 0xae, 0x22, 0x44, 0x4a, 0xc5, 0x0e, + 0xef, 0xc9, 0xaf, 0x81, 0x89, 0x67, 0x56, 0x8e, 0xd2, 0x78, 0x0e, 0x30, 0x41, 0x0a, 0x7d, 0x53, 0x7e, 0x05, 0xb8, + 0xa1, 0x8b, 0x28, 0xcc, 0xde, 0xc6, 0x55, 0x50, 0x5b, 0x4d, 0xbf, 0x77, 0x70, 0x62, 0xcf, 0xeb, 0x7e, 0x3f, 0x25, + 0x1a, 0x3f, 0x0c, 0xbd, 0xc0, 0xbf, 0xc7, 0xd3, 0x7d, 0x13, 0xa4, 0xe6, 0x95, 0x07, 0x78, 0x45, 0x97, 0x5b, 0x9b, + 0x72, 0x45, 0xe3, 0x62, 0x5e, 0x23, 0x22, 0x7c, 0xea, 0x28, 0xb6, 0xdb, 0xfc, 0x38, 0xb5, 0x31, 0x18, 0x84, 0x70, + 0xdf, 0xca, 0xf8, 0x7d, 0xe2, 0xe5, 0xb3, 0x68, 0x0e, 0x8a, 0xd2, 0x4c, 0x93, 0x84, 0x14, 0xd2, 0x4b, 0x80, 0x3e, + 0x1a, 0x84, 0x5a, 0x5d, 0xf9, 0x47, 0xe2, 0xa5, 0x6a, 0x5a, 0x9b, 0xa7, 0x58, 0xa3, 0x40, 0xcc, 0xa2, 0x79, 0xc3, + 0x32, 0x3a, 0x24, 0xd5, 0xe5, 0xd2, 0x34, 0xe3, 0x0f, 0xab, 0x19, 0xaa, 0x15, 0x47, 0x4d, 0x50, 0xa3, 0x74, 0x03, + 0x17, 0xc0, 0xbf, 0xd3, 0x1d, 0x47, 0x35, 0x8a, 0x14, 0x0d, 0xf8, 0x04, 0x81, 0x61, 0xcd, 0xe6, 0x09, 0x6b, 0x4d, + 0x5d, 0x33, 0xfa, 0x7d, 0x19, 0x27, 0x64, 0x92, 0x90, 0x9c, 0x0f, 0x97, 0xeb, 0x47, 0x52, 0x5d, 0x00, 0xa9, 0x72, + 0xc5, 0x66, 0xbd, 0xde, 0x1c, 0x30, 0x7a, 0x61, 0xfd, 0xc2, 0xc6, 0x15, 0x9c, 0x5f, 0x12, 0xe6, 0xae, 0xfa, 0x11, + 0x66, 0x19, 0x54, 0x01, 0x69, 0x7e, 0x2c, 0x78, 0xf3, 0xdc, 0x05, 0xa2, 0x7e, 0x33, 0x52, 0x17, 0x94, 0x59, 0x3a, + 0xb7, 0x88, 0x40, 0xc0, 0x6b, 0x58, 0x3d, 0x81, 0x64, 0x5f, 0x3e, 0xf6, 0x69, 0x46, 0x81, 0xea, 0x08, 0x40, 0xd9, + 0xac, 0x1f, 0xc2, 0xfe, 0x01, 0xe1, 0x84, 0xfa, 0x9b, 0x37, 0x72, 0xd6, 0x90, 0x3c, 0x90, 0x6a, 0xc2, 0x63, 0x38, + 0x35, 0x16, 0xf8, 0xd2, 0xa2, 0x37, 0x15, 0xbc, 0x26, 0x38, 0xee, 0x05, 0x5a, 0xfb, 0x16, 0x70, 0x84, 0x08, 0x2e, + 0x43, 0x13, 0xa7, 0xbd, 0x5d, 0x2f, 0x40, 0x42, 0x73, 0x0b, 0xe7, 0xfa, 0xda, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, + 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, + 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, 0x2a, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, + 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, + 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xab, 0xc4, 0x33, 0xec, + 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, + 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x2a, 0xcc, 0x41, 0xde, + 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, + 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, + 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, + 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, + 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0x2f, 0xf2, 0xd1, + 0x96, 0xbe, 0x06, 0xdf, 0x3a, 0x1c, 0xf2, 0xd1, 0xce, 0xfc, 0xf4, 0xc9, 0x5a, 0x29, 0x83, 0x8d, 0x14, 0xa3, 0x10, + 0x12, 0xc5, 0x6d, 0x7b, 0x0c, 0x80, 0xff, 0xfd, 0xc3, 0x81, 0x7e, 0xef, 0xe4, 0x6f, 0xb5, 0x5b, 0x5a, 0xf5, 0xfc, + 0xd0, 0x22, 0xcc, 0x78, 0x5d, 0x1b, 0x76, 0xb6, 0xbd, 0x04, 0x94, 0xde, 0x37, 0x0d, 0x6a, 0x8a, 0xe8, 0x27, 0xac, + 0x26, 0x56, 0x71, 0x58, 0x90, 0x12, 0x87, 0x18, 0x8e, 0xd1, 0x0e, 0x3d, 0x4e, 0x17, 0x35, 0x4f, 0xee, 0x3b, 0x64, + 0xdc, 0xfa, 0x3e, 0x20, 0xb9, 0x14, 0xce, 0x3f, 0x78, 0xa1, 0xc1, 0x44, 0x2f, 0xf2, 0xaa, 0xc8, 0xc4, 0x48, 0xd0, + 0x28, 0xbf, 0x25, 0x71, 0xe6, 0x0c, 0x6b, 0x71, 0xa6, 0x10, 0xc2, 0x42, 0x42, 0xe5, 0x2e, 0x4a, 0x4a, 0x0f, 0xce, + 0x9e, 0xec, 0xcb, 0xe6, 0x77, 0xc2, 0x84, 0x18, 0x2d, 0x80, 0x06, 0x67, 0xd7, 0x2e, 0xef, 0x21, 0x2c, 0x73, 0xef, + 0xf7, 0xb7, 0x77, 0x79, 0x01, 0x71, 0x99, 0x67, 0x52, 0xb1, 0x5a, 0x9e, 0x01, 0x4d, 0x9e, 0x88, 0xcf, 0xc2, 0x4a, + 0x4e, 0x83, 0xaa, 0xa3, 0x58, 0xbd, 0x8d, 0xe7, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, 0xdd, 0x67, 0x6f, 0x94, + 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, 0xe7, 0x26, 0xc8, 0x3f, + 0xbe, 0x3e, 0xa1, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, 0x9b, 0x23, 0x35, 0x79, + 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, 0x67, 0x2b, 0x73, 0x2f, + 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xba, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, 0x62, 0x86, 0x29, 0xd6, + 0x5f, 0xd8, 0xf0, 0x9b, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x63, 0x16, 0xc2, 0xe1, 0xb0, 0x99, 0x14, + 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0x87, 0x43, 0x57, 0xcb, 0xd6, 0xc2, 0x83, 0x87, 0xaa, 0x85, 0x9b, 0x86, 0xe5, + 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, 0x1b, 0x6b, 0xe0, 0x1a, + 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, 0x09, 0xa3, 0x15, 0xc2, + 0xef, 0xbe, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, 0x4a, 0xb1, 0x34, 0x6f, + 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0x73, 0xdf, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, 0xcd, 0xe6, 0xc0, 0x7d, + 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x27, 0xcb, 0xe3, 0xf0, 0x2d, 0xfc, 0xcb, + 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xab, 0x14, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, 0x8d, 0xa8, 0x0d, 0x7f, + 0xc3, 0xbf, 0x85, 0x7d, 0x84, 0xfd, 0x86, 0x26, 0x08, 0x03, 0x58, 0x7f, 0x26, 0x10, 0x17, 0x16, 0x82, 0x04, 0x7f, + 0xab, 0x24, 0xff, 0x9c, 0xf0, 0xd9, 0xa2, 0x04, 0xb2, 0x3a, 0x8c, 0xe2, 0x13, 0x8a, 0x89, 0x42, 0x18, 0x6e, 0x09, + 0xbd, 0xa3, 0xff, 0x46, 0x94, 0x64, 0x93, 0xdc, 0x8a, 0xf5, 0x40, 0x26, 0x49, 0x30, 0xc1, 0xca, 0x0b, 0xe5, 0x4b, + 0xf7, 0x42, 0xa9, 0xb5, 0x16, 0xb4, 0x7e, 0xf9, 0x93, 0xc4, 0x33, 0xa0, 0x7b, 0x20, 0x63, 0xd0, 0x6d, 0x44, 0x35, + 0xc9, 0x31, 0x7d, 0x94, 0xce, 0x33, 0x50, 0x01, 0x9d, 0xad, 0xb3, 0xb0, 0x5e, 0x16, 0xe5, 0xaa, 0x15, 0x1e, 0x2a, + 0x4b, 0x1f, 0xa9, 0xc7, 0x98, 0x17, 0xe6, 0xc9, 0x89, 0x7c, 0xf0, 0x08, 0xd0, 0xf0, 0x28, 0x4f, 0xab, 0x8e, 0xd2, + 0xfa, 0x81, 0x65, 0xc0, 0x08, 0x9c, 0x28, 0x03, 0x1e, 0x61, 0x19, 0x98, 0xa7, 0x5d, 0x86, 0x1a, 0xc4, 0x1a, 0x55, + 0x57, 0x6a, 0x83, 0x39, 0x51, 0x94, 0x7c, 0x8a, 0xa5, 0x15, 0xc6, 0xd0, 0xd4, 0x95, 0x47, 0xd6, 0x4b, 0x4e, 0xd8, + 0x93, 0xdd, 0x40, 0xba, 0x85, 0x8d, 0x02, 0x17, 0x74, 0x2d, 0x4b, 0x94, 0x8b, 0x6e, 0x19, 0x51, 0x26, 0x42, 0xea, + 0x67, 0x0f, 0x67, 0x5a, 0xed, 0x37, 0x76, 0xd2, 0xbe, 0x3d, 0x52, 0xf4, 0x82, 0x81, 0xf8, 0xb4, 0x47, 0x4a, 0x3d, + 0x6b, 0xe4, 0x32, 0xb0, 0xa5, 0x4b, 0x55, 0xcf, 0x7f, 0x83, 0xf2, 0x1d, 0xcc, 0x8c, 0xb3, 0xd9, 0xef, 0x7a, 0x73, + 0x7b, 0xb2, 0xaf, 0x9b, 0xdf, 0x59, 0xaf, 0x07, 0x5b, 0x83, 0x4c, 0x7c, 0xa9, 0xa8, 0xa7, 0xac, 0x42, 0xac, 0xc8, + 0xec, 0x7f, 0x0b, 0xef, 0x77, 0x78, 0x6b, 0x84, 0x66, 0x65, 0x3c, 0xcc, 0x47, 0x4f, 0xf6, 0xa2, 0xf9, 0xbd, 0xb3, + 0x6c, 0x2b, 0x57, 0x25, 0xb3, 0xfd, 0x7e, 0x94, 0x34, 0x67, 0x8f, 0xd7, 0x48, 0xea, 0x00, 0x1f, 0xaf, 0xcf, 0xf0, + 0x91, 0x4a, 0x28, 0xb5, 0xa0, 0xaa, 0x41, 0xeb, 0x63, 0xbf, 0xb7, 0x9e, 0xd3, 0xc7, 0x8f, 0xe5, 0x74, 0x4b, 0x8a, + 0x30, 0x7e, 0x60, 0x30, 0x65, 0x27, 0x4e, 0x5d, 0xf2, 0x66, 0x48, 0xef, 0xba, 0x55, 0x52, 0x97, 0x3d, 0x4a, 0x04, + 0xa1, 0x0e, 0xd6, 0x2f, 0xf6, 0x43, 0x98, 0xd9, 0xa2, 0x3f, 0x6c, 0x56, 0x73, 0x42, 0x41, 0x04, 0x88, 0x56, 0x79, + 0x1f, 0x38, 0x26, 0x09, 0xb3, 0xe6, 0x86, 0x74, 0xeb, 0xcd, 0x95, 0xf6, 0x4a, 0x0a, 0xe8, 0xe7, 0x20, 0x73, 0xfb, + 0xe8, 0x96, 0xab, 0x96, 0x79, 0x2e, 0x6d, 0x39, 0x60, 0xd1, 0x42, 0x74, 0x66, 0xe7, 0xd2, 0xe1, 0xe0, 0x3f, 0xa8, + 0x2b, 0x51, 0x45, 0x04, 0x1d, 0x45, 0x0b, 0x46, 0xab, 0x55, 0xbb, 0x9c, 0x6c, 0x2a, 0x64, 0x4b, 0x22, 0x9c, 0x28, + 0xd9, 0x2b, 0xa1, 0x3e, 0xca, 0xd5, 0x9e, 0x69, 0x88, 0x3f, 0x13, 0xb0, 0x69, 0x83, 0xbf, 0x05, 0xee, 0x65, 0x70, + 0x66, 0xda, 0xa7, 0x61, 0x04, 0x44, 0xe6, 0x10, 0xec, 0xe7, 0x77, 0x3d, 0xa8, 0xe0, 0x41, 0x47, 0xfa, 0xeb, 0x7a, + 0x56, 0xe0, 0x99, 0x7b, 0xe2, 0xf9, 0x9b, 0x13, 0xe9, 0x45, 0x0e, 0x0f, 0x34, 0xf7, 0x61, 0xc6, 0x5f, 0x96, 0x65, + 0xb8, 0x1b, 0x2d, 0xcb, 0x62, 0xe5, 0x45, 0x7a, 0x1f, 0xcf, 0xa4, 0x18, 0x48, 0x74, 0x98, 0x19, 0x5d, 0xc5, 0x3a, + 0xce, 0x61, 0xdc, 0xdb, 0x93, 0xb0, 0x42, 0xfb, 0x67, 0x89, 0xbd, 0x2e, 0x00, 0xc0, 0x21, 0x6b, 0xd0, 0x0a, 0xef, + 0x74, 0x7b, 0xbb, 0xc7, 0x25, 0x25, 0x8a, 0x1b, 0x35, 0x3f, 0xab, 0xa1, 0x65, 0x82, 0x5a, 0x66, 0xdd, 0xc9, 0x64, + 0x8a, 0x24, 0xf0, 0x6d, 0xd8, 0x1b, 0x56, 0xe4, 0xf3, 0x46, 0x6e, 0x0f, 0xef, 0xc2, 0x95, 0x88, 0xb5, 0x05, 0x9d, + 0x74, 0x64, 0x1c, 0xee, 0x85, 0xe6, 0x46, 0xba, 0x7f, 0x52, 0x25, 0x61, 0x29, 0x62, 0xb8, 0x05, 0xb2, 0xbd, 0xda, + 0x56, 0x82, 0x12, 0x48, 0x60, 0x3f, 0x94, 0x62, 0x99, 0x6e, 0x05, 0x80, 0x39, 0xf0, 0x3f, 0x25, 0x0c, 0xa1, 0xbb, + 0xf3, 0x10, 0xaf, 0x1a, 0x79, 0xdf, 0x20, 0x04, 0xfb, 0x6b, 0x90, 0xd3, 0x80, 0x41, 0xa4, 0x18, 0xc9, 0x82, 0x81, + 0x04, 0x20, 0xe7, 0x6b, 0x30, 0xc9, 0x4d, 0x73, 0xcf, 0x0f, 0x72, 0xdd, 0xc1, 0xb4, 0x0f, 0xba, 0x17, 0xd7, 0x9a, + 0xe5, 0xe0, 0x15, 0x13, 0xf1, 0xbf, 0xd7, 0x5e, 0xc9, 0x72, 0x96, 0xf9, 0x8d, 0xb9, 0xe8, 0x64, 0x70, 0xd5, 0x10, + 0x7e, 0x31, 0xcb, 0xe6, 0x3c, 0x9a, 0x65, 0x3a, 0xd4, 0xbf, 0x68, 0x8e, 0x4a, 0x01, 0x0c, 0x75, 0xbc, 0x00, 0x6b, + 0xbc, 0x2b, 0xdd, 0xb4, 0xe2, 0x91, 0xc6, 0x18, 0x05, 0x15, 0x3a, 0x08, 0xfd, 0xbd, 0x06, 0x78, 0x0d, 0x26, 0xb9, + 0x11, 0x2a, 0x1f, 0x5c, 0xd0, 0x0d, 0xdd, 0x72, 0xe5, 0x12, 0xd4, 0xa4, 0x6a, 0xf9, 0xe5, 0x08, 0xf5, 0xae, 0x96, + 0x5c, 0xaa, 0xcd, 0xa7, 0x46, 0x59, 0x23, 0xc8, 0xe4, 0x28, 0xfd, 0x3e, 0xe5, 0xc2, 0xad, 0x8c, 0xc9, 0xfa, 0x70, + 0xf0, 0x0a, 0x6e, 0x6a, 0xfc, 0x3a, 0x27, 0x16, 0x51, 0x7b, 0x48, 0x84, 0xad, 0xdd, 0x0a, 0xdd, 0x7b, 0xdc, 0x28, + 0xcd, 0xa3, 0x6c, 0x13, 0x8b, 0xca, 0xeb, 0x25, 0x60, 0x2d, 0xee, 0x01, 0x19, 0x2a, 0x2d, 0xfd, 0x8a, 0x15, 0x00, + 0x19, 0x20, 0x85, 0x8d, 0x1f, 0x90, 0xf6, 0xea, 0x83, 0x97, 0xfa, 0xfd, 0xbe, 0x31, 0xe5, 0xbf, 0x7f, 0xc8, 0x81, + 0x99, 0x50, 0x94, 0xf5, 0x0e, 0x26, 0x10, 0x5c, 0x3b, 0x49, 0x7b, 0x56, 0xf3, 0x17, 0xeb, 0xda, 0x03, 0x52, 0x2b, + 0xdf, 0x62, 0xae, 0x7a, 0x6d, 0x5f, 0x6c, 0xf6, 0x69, 0x75, 0x63, 0x34, 0x0e, 0x82, 0xa5, 0xd5, 0x5b, 0xad, 0x72, + 0xc8, 0x1b, 0x5e, 0x81, 0x48, 0x65, 0x5d, 0x5d, 0x2b, 0xe7, 0xea, 0x5a, 0x70, 0x24, 0x90, 0x2d, 0x79, 0x0e, 0xff, + 0x85, 0xdc, 0x2b, 0x0f, 0x87, 0xc2, 0xef, 0xf7, 0xd3, 0x19, 0x69, 0x65, 0x81, 0x32, 0x6d, 0x5d, 0x7b, 0xa1, 0x7f, + 0x38, 0xfc, 0x00, 0x5e, 0x23, 0xfe, 0xe1, 0x50, 0xf6, 0xfb, 0x1f, 0xcd, 0x4d, 0xe6, 0x7c, 0xac, 0x94, 0xb2, 0x97, + 0xa8, 0x74, 0x7f, 0x9b, 0xf0, 0xde, 0xff, 0x1e, 0xfd, 0xef, 0xd1, 0x65, 0x4f, 0x05, 0x80, 0x25, 0x7c, 0x86, 0x37, + 0x74, 0xa6, 0x2e, 0xe7, 0x4c, 0xba, 0xbb, 0x2b, 0x3f, 0xf4, 0x9e, 0xc6, 0x87, 0xef, 0xcd, 0x4d, 0x1b, 0x7f, 0xad, + 0x8e, 0x34, 0x09, 0x1d, 0x17, 0xfd, 0xc3, 0xe1, 0x53, 0xa2, 0xf5, 0x69, 0xa9, 0xd2, 0xa7, 0x29, 0xf0, 0x24, 0xc3, + 0x86, 0xeb, 0x16, 0xa6, 0xa3, 0xf9, 0x71, 0xf3, 0x55, 0xf2, 0xe2, 0x2c, 0x85, 0x6b, 0x6f, 0x3e, 0x4b, 0xe7, 0x53, + 0xb0, 0xae, 0x0c, 0xf3, 0x59, 0x3d, 0x0f, 0x20, 0x75, 0x08, 0x69, 0xd6, 0x34, 0xfc, 0x5b, 0xe5, 0x0a, 0xde, 0xda, + 0xe3, 0xdd, 0x60, 0x44, 0xa9, 0x23, 0x7d, 0xd2, 0x86, 0xd0, 0x25, 0x95, 0xfc, 0x47, 0x91, 0xc7, 0x18, 0xb3, 0xf1, + 0x9a, 0xc8, 0x3e, 0x8b, 0xfc, 0x55, 0x01, 0x80, 0x45, 0x80, 0x80, 0x9c, 0xce, 0x1d, 0x49, 0xfc, 0xe7, 0xe4, 0xdb, + 0x3f, 0xa6, 0x4b, 0xfb, 0x50, 0x16, 0x77, 0xa5, 0xa8, 0xaa, 0xa3, 0xd2, 0x76, 0xb6, 0x5c, 0x0f, 0xf4, 0xa1, 0xfd, + 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, 0x58, 0x3f, 0xbf, + 0xdf, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, 0xc3, 0x54, 0xe2, + 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0x7f, 0x54, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, + 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0x17, 0xc2, 0x22, 0xf9, 0xf5, 0xc9, 0x91, + 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x91, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9e, 0xff, 0xb9, 0x99, 0xff, 0x03, 0x74, 0x86, + 0x2c, 0x5e, 0x70, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0x2f, 0x80, 0x83, 0xf9, 0x05, + 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0x37, 0x16, 0xcf, 0x95, 0x5c, 0x10, 0xfa, + 0xba, 0x0a, 0xb3, 0x71, 0x55, 0x6c, 0x2a, 0x51, 0x6c, 0xea, 0x1e, 0xa9, 0x65, 0xf3, 0x69, 0x6d, 0x2b, 0x64, 0x7f, + 0x12, 0x2d, 0xda, 0x2e, 0x43, 0x35, 0x19, 0x65, 0xe9, 0x7a, 0x0a, 0xa4, 0x7a, 0x01, 0x9c, 0x45, 0xe6, 0x95, 0x2f, + 0xce, 0x1e, 0xb0, 0x45, 0xe3, 0x29, 0x30, 0xa2, 0xd2, 0x1f, 0x79, 0x63, 0x74, 0x7a, 0xa2, 0xdf, 0xcf, 0xa7, 0x14, + 0xf2, 0xf5, 0x13, 0x60, 0x72, 0xd5, 0x72, 0x01, 0xfa, 0x32, 0xd4, 0x41, 0x25, 0x4a, 0xad, 0x18, 0x46, 0x2c, 0xfc, + 0x24, 0x90, 0xbd, 0x99, 0x82, 0x9a, 0x55, 0x94, 0x84, 0x4a, 0x54, 0x4a, 0xb6, 0x26, 0xa8, 0xa5, 0xf7, 0x45, 0x51, + 0xef, 0x2b, 0x70, 0x94, 0x8c, 0xb4, 0x59, 0x4e, 0x99, 0x71, 0x51, 0xe6, 0xa2, 0x1f, 0xec, 0xdf, 0x95, 0xe7, 0x37, + 0x32, 0x9f, 0xe5, 0xbe, 0xa3, 0x73, 0xda, 0x8e, 0x0b, 0x94, 0xb9, 0xe5, 0xb4, 0xd5, 0x92, 0xc7, 0xe4, 0x3d, 0x0b, + 0xb6, 0xfd, 0x97, 0x09, 0xf2, 0x2a, 0xc2, 0x7c, 0x42, 0x95, 0xcd, 0x3f, 0x20, 0xcc, 0x16, 0x07, 0xf6, 0xd8, 0x85, + 0x89, 0x48, 0x6f, 0xc1, 0x92, 0x18, 0x66, 0xa5, 0x08, 0xe3, 0x1d, 0x78, 0xff, 0x6c, 0x2a, 0x31, 0x3a, 0x43, 0x27, + 0xf7, 0xb3, 0x87, 0xb4, 0x4e, 0xce, 0xde, 0xbe, 0x3e, 0xfb, 0xae, 0x37, 0x28, 0x46, 0x69, 0x3c, 0xe8, 0x7d, 0x77, + 0xb6, 0xda, 0x00, 0x44, 0xa6, 0x38, 0x8b, 0xc9, 0x94, 0x26, 0xe2, 0x33, 0x32, 0x0c, 0x9e, 0xd5, 0x89, 0x38, 0xa3, + 0x89, 0xe9, 0xbe, 0x46, 0x69, 0xf2, 0xed, 0x28, 0xcc, 0xe1, 0xe5, 0x52, 0x6c, 0x2a, 0x11, 0x83, 0x9d, 0x52, 0xcd, + 0xb3, 0xbc, 0x7d, 0x16, 0xe7, 0xa3, 0x0e, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, 0x05, 0x84, 0x1e, + 0x00, 0x27, 0x5d, 0xf9, 0xf3, 0x70, 0x10, 0x09, 0x84, 0x5a, 0x30, 0x27, 0xd3, 0x88, 0x6e, 0x48, 0xaf, 0xb0, 0xcf, + 0xc0, 0x2c, 0xa4, 0x34, 0x0f, 0x6e, 0xae, 0x16, 0x2d, 0x77, 0xc5, 0xca, 0x51, 0x58, 0xad, 0x45, 0x54, 0x23, 0xd5, + 0x31, 0x38, 0xef, 0x40, 0x04, 0x80, 0x62, 0x04, 0xcf, 0x78, 0xd4, 0xef, 0x47, 0x2a, 0x28, 0x27, 0xa1, 0x5f, 0x14, + 0xfa, 0xa5, 0x31, 0x28, 0x63, 0xfe, 0x2e, 0xd4, 0xc4, 0x00, 0xf5, 0x96, 0x87, 0x8a, 0x23, 0x00, 0x97, 0x73, 0xc4, + 0x8c, 0xf3, 0x1e, 0x77, 0xd1, 0x38, 0x15, 0xef, 0x84, 0xba, 0x0e, 0x96, 0x0a, 0x75, 0xde, 0xd4, 0x47, 0x7a, 0x4e, + 0x9a, 0x04, 0x0d, 0xe2, 0x06, 0x1e, 0xaf, 0x86, 0x80, 0x6a, 0x25, 0xa4, 0xde, 0x42, 0xa7, 0x54, 0x75, 0x08, 0xac, + 0x01, 0x2e, 0x51, 0xd8, 0x56, 0x98, 0x1c, 0xd1, 0xa6, 0x2c, 0x45, 0x7e, 0xc4, 0x06, 0xed, 0x92, 0x91, 0xa9, 0x83, + 0xcb, 0xe5, 0x72, 0x22, 0xea, 0x5f, 0xf3, 0x2d, 0x80, 0xf3, 0x42, 0x7e, 0x6b, 0x37, 0x5b, 0x26, 0xd9, 0xae, 0x2b, + 0xc3, 0x59, 0x52, 0x8a, 0x6a, 0x5d, 0xe4, 0x55, 0x7a, 0x2f, 0x7e, 0xd6, 0x0f, 0x5d, 0x02, 0x29, 0xf4, 0x23, 0xbd, + 0x6e, 0x37, 0x47, 0xaa, 0x71, 0x74, 0x39, 0xb6, 0xa7, 0xd2, 0x4e, 0xf6, 0xaa, 0xc5, 0x9b, 0x2d, 0x73, 0x25, 0x69, + 0x1c, 0x8b, 0xfc, 0x6d, 0x1e, 0xa7, 0x91, 0x95, 0x1c, 0xfe, 0x1f, 0xde, 0xbe, 0x85, 0xbb, 0x6d, 0x1b, 0x5b, 0xf7, + 0xaf, 0x58, 0xbc, 0xa9, 0x4a, 0x44, 0x90, 0x2c, 0x39, 0x49, 0x67, 0x4a, 0x19, 0xd6, 0x71, 0xf3, 0x68, 0xd3, 0x36, + 0x71, 0x1a, 0xa7, 0x9d, 0xce, 0xe8, 0xea, 0xb8, 0x34, 0x09, 0x5b, 0x6c, 0x68, 0x40, 0x25, 0x29, 0x3f, 0x22, 0xf1, + 0xbf, 0xdf, 0xb5, 0x37, 0x9e, 0xa4, 0x68, 0x27, 0x33, 0xf7, 0xdc, 0xbb, 0xb2, 0x56, 0x2c, 0x82, 0x20, 0xde, 0xd8, + 0xd8, 0xd8, 0x8f, 0x6f, 0xeb, 0x00, 0xd5, 0x2e, 0xf2, 0x95, 0x8b, 0x8d, 0xfc, 0x22, 0x2b, 0x31, 0x60, 0x70, 0xa3, + 0x51, 0xad, 0x50, 0x53, 0x26, 0xf0, 0x85, 0x7c, 0x8f, 0x11, 0xb7, 0x59, 0x99, 0x00, 0xc3, 0x8f, 0x89, 0xfa, 0x92, + 0x9e, 0x42, 0x94, 0x07, 0x15, 0x8f, 0xfb, 0x05, 0x47, 0xc4, 0x6b, 0xab, 0x32, 0x07, 0x26, 0x5b, 0xab, 0x20, 0x11, + 0xec, 0x2e, 0x9b, 0xeb, 0x45, 0xb4, 0x50, 0x77, 0xa1, 0x5e, 0xbc, 0xdd, 0xf6, 0x12, 0x45, 0x07, 0x9c, 0xfc, 0x34, + 0x78, 0x15, 0x67, 0x39, 0x4f, 0xf7, 0x2a, 0xb9, 0xa7, 0x36, 0xd4, 0x9e, 0x72, 0xe6, 0x80, 0x9d, 0xf7, 0x75, 0xb5, + 0xa7, 0xd7, 0xf4, 0x9e, 0x6e, 0xe7, 0x1e, 0x5c, 0x30, 0x70, 0xe7, 0x5e, 0x66, 0xd7, 0x5c, 0xec, 0x81, 0x32, 0xd0, + 0x1a, 0x0f, 0xd4, 0xa2, 0x1a, 0xa9, 0x89, 0xd1, 0x81, 0xab, 0x13, 0x7d, 0x30, 0x07, 0xf4, 0x7b, 0x88, 0x15, 0xde, + 0x7a, 0xbb, 0xd2, 0x07, 0x6d, 0x40, 0x7f, 0x5e, 0x9a, 0x3e, 0xe8, 0x68, 0xf1, 0x2a, 0x24, 0x70, 0x63, 0x48, 0x35, + 0x52, 0xab, 0x91, 0x55, 0xa0, 0x78, 0xc3, 0x5b, 0xbc, 0x3b, 0xd7, 0x92, 0x8d, 0xf7, 0x12, 0x81, 0xbd, 0x32, 0x51, + 0xc5, 0x99, 0x38, 0xf6, 0x52, 0x79, 0xad, 0x9d, 0x64, 0x84, 0xf1, 0x2d, 0x2b, 0xa9, 0xbf, 0x43, 0xcc, 0x2d, 0xd2, + 0x1c, 0x06, 0x2f, 0xc3, 0x8a, 0xcc, 0x78, 0xbf, 0x2f, 0x67, 0x32, 0x2a, 0x67, 0x62, 0xbf, 0x8c, 0x14, 0x42, 0xdb, + 0x7d, 0x22, 0xa0, 0x07, 0x25, 0x40, 0xbe, 0x00, 0xa8, 0x7a, 0x48, 0xf8, 0xf3, 0x90, 0xd4, 0xa7, 0x53, 0xe8, 0x53, + 0x68, 0xeb, 0x15, 0xaf, 0xa0, 0xaa, 0x6e, 0x8c, 0x6c, 0xa3, 0x82, 0x16, 0x8f, 0xe5, 0x59, 0x6d, 0x18, 0x9b, 0x53, + 0xeb, 0x5d, 0x6f, 0x36, 0x98, 0xb2, 0xb9, 0x50, 0xab, 0x30, 0x24, 0xd1, 0x4d, 0xe9, 0x85, 0x0f, 0xb1, 0x58, 0x59, + 0xad, 0xcd, 0x6f, 0x62, 0x7f, 0x64, 0x22, 0xc5, 0xfd, 0x6c, 0x89, 0x73, 0x17, 0x8f, 0xe7, 0x55, 0x5f, 0x6b, 0x69, + 0x91, 0x69, 0xf3, 0x9d, 0xbe, 0x0c, 0x69, 0x2a, 0x6a, 0x48, 0xa3, 0xce, 0x0c, 0xba, 0x6f, 0x97, 0x57, 0x54, 0x23, + 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, 0x1e, 0x88, 0xa2, 0x1a, 0x15, 0x6b, 0x21, 0x10, 0x6d, 0x18, 0x72, 0xcc, + 0x2c, 0x21, 0xc9, 0x3e, 0xf1, 0xef, 0x54, 0x70, 0x85, 0x22, 0xbe, 0x31, 0x70, 0xde, 0x95, 0xf5, 0xec, 0xae, 0x23, + 0x3f, 0x27, 0x16, 0x56, 0xfb, 0x0f, 0xcd, 0xa3, 0xd6, 0x38, 0x0b, 0x68, 0x6b, 0x5a, 0xdd, 0x70, 0xb8, 0x47, 0x75, + 0x2c, 0x4a, 0x03, 0x48, 0xec, 0x91, 0xe5, 0xa2, 0x75, 0xcc, 0xa0, 0x01, 0xfd, 0x6d, 0x76, 0xb5, 0xbe, 0x42, 0xd4, + 0xb6, 0x12, 0x59, 0x27, 0xa9, 0xfc, 0x4b, 0xda, 0xa3, 0xae, 0xed, 0xa9, 0xfc, 0x6f, 0xdb, 0x54, 0x39, 0xb4, 0x40, + 0xf2, 0xd8, 0xcd, 0x59, 0xa0, 0x3a, 0x12, 0x44, 0x81, 0xda, 0x7a, 0xc1, 0xd4, 0x3b, 0x65, 0x8a, 0x0e, 0xe4, 0xe7, + 0xc2, 0x9c, 0x61, 0x5f, 0x70, 0xc4, 0x98, 0xa5, 0x12, 0x83, 0xa9, 0x8f, 0x31, 0xaa, 0x69, 0xad, 0x00, 0x5d, 0x3f, + 0xdd, 0xc0, 0x9f, 0xa8, 0xa8, 0xd1, 0x50, 0x6b, 0x24, 0x85, 0xa2, 0x89, 0x0a, 0x3a, 0x96, 0x16, 0x3a, 0x98, 0x42, + 0x27, 0x91, 0xb0, 0x04, 0x34, 0x4c, 0x88, 0x4e, 0x2a, 0xf0, 0xd6, 0x00, 0xce, 0x7c, 0x5c, 0x94, 0xeb, 0x42, 0x1b, + 0xcc, 0xfd, 0x10, 0x5f, 0xf3, 0xd7, 0x2f, 0x9c, 0x51, 0x7d, 0xcb, 0x5a, 0xdf, 0xd3, 0x82, 0xfc, 0x10, 0x72, 0x8a, + 0x0e, 0x4c, 0xec, 0x68, 0x83, 0xc6, 0x18, 0x65, 0xad, 0x43, 0x5d, 0x9c, 0xe8, 0xf8, 0x2b, 0xda, 0x04, 0xef, 0x01, + 0x4f, 0x11, 0x6d, 0x78, 0x28, 0x8c, 0x55, 0x35, 0x3e, 0x95, 0xac, 0xa5, 0x07, 0x2b, 0x78, 0xba, 0x4e, 0x78, 0x08, + 0x7a, 0x24, 0xc2, 0x8e, 0xc2, 0x62, 0x1e, 0x2f, 0xe0, 0x38, 0x29, 0x08, 0xa8, 0x1d, 0xf4, 0x15, 0x7c, 0xbe, 0x40, + 0xf7, 0x57, 0x89, 0x1e, 0x60, 0x68, 0x41, 0xdc, 0x0c, 0x7d, 0x3a, 0xba, 0x8a, 0x57, 0x0d, 0x15, 0x09, 0x9f, 0x17, + 0x60, 0x3b, 0xa4, 0xd4, 0x53, 0xa0, 0x85, 0x4a, 0x94, 0x7e, 0x18, 0xf8, 0x0e, 0x0d, 0x7c, 0xad, 0x75, 0x80, 0x86, + 0x7e, 0xc6, 0x34, 0xb5, 0xce, 0x50, 0xf9, 0xcc, 0xbb, 0x67, 0x46, 0xcb, 0x99, 0x05, 0x63, 0xd0, 0xb7, 0xd1, 0x14, + 0xc5, 0x39, 0xf9, 0x2c, 0x28, 0xe2, 0x34, 0x8b, 0x73, 0xf0, 0xdb, 0x8c, 0x0b, 0xcc, 0x98, 0xc4, 0x15, 0xbf, 0x94, + 0x05, 0x68, 0xbb, 0x73, 0x95, 0x5a, 0xd7, 0x20, 0x20, 0xfb, 0x01, 0xac, 0x5e, 0x1a, 0x3a, 0x2a, 0xe7, 0xdd, 0xa5, + 0x4d, 0x21, 0x62, 0x11, 0x82, 0x4d, 0x33, 0x5d, 0xb2, 0xe3, 0x50, 0x69, 0x73, 0x20, 0xbe, 0x11, 0x1a, 0xf7, 0x4f, + 0xc3, 0xd8, 0x6a, 0x8a, 0xad, 0xdd, 0xdb, 0x76, 0xfb, 0x7b, 0xe9, 0xa5, 0xd3, 0x9c, 0xf4, 0x18, 0xfb, 0xbd, 0x0c, + 0x8b, 0x91, 0xed, 0x08, 0x81, 0x25, 0xe7, 0x7d, 0xea, 0xbf, 0xa2, 0xe5, 0x3c, 0x01, 0xd3, 0x11, 0x1d, 0x21, 0x17, + 0x28, 0x3b, 0x46, 0x71, 0x07, 0x06, 0x57, 0xf4, 0xfb, 0x60, 0x95, 0x61, 0x2e, 0x24, 0x4b, 0x92, 0x32, 0x78, 0x9e, + 0x7a, 0x18, 0xf0, 0x6b, 0xa6, 0xcc, 0x5d, 0x94, 0xf5, 0xe9, 0x92, 0x4c, 0x53, 0x64, 0x20, 0xd6, 0xe1, 0x26, 0x4b, + 0xa3, 0x44, 0x89, 0xc8, 0x96, 0xe8, 0x1f, 0x69, 0x28, 0x96, 0x0e, 0xd7, 0x8b, 0x54, 0x89, 0x50, 0x31, 0x4f, 0xf1, + 0xa4, 0x4e, 0xeb, 0x74, 0x84, 0xf1, 0x26, 0x41, 0x29, 0x57, 0xc3, 0x40, 0x95, 0x54, 0x2f, 0x85, 0x4d, 0xb1, 0xdd, + 0xea, 0x8b, 0x95, 0x98, 0xc7, 0x0b, 0x7c, 0x29, 0x70, 0x14, 0x7f, 0xe2, 0x5e, 0xac, 0x29, 0xb5, 0x3d, 0xa8, 0x1d, + 0x51, 0x42, 0x7f, 0xe2, 0x70, 0x91, 0xf8, 0x4e, 0xea, 0xb8, 0x7f, 0x68, 0x11, 0x72, 0xa6, 0x0e, 0x52, 0xc3, 0x0d, + 0xed, 0x08, 0xff, 0x0d, 0xd7, 0x67, 0x9c, 0xd1, 0x9b, 0x6a, 0x46, 0x8d, 0xdf, 0xeb, 0xe1, 0x19, 0xa3, 0x3e, 0x1b, + 0x38, 0xac, 0x10, 0x85, 0x36, 0xec, 0xa8, 0x54, 0xa2, 0x85, 0xa1, 0x54, 0x7f, 0x09, 0x15, 0x47, 0xdc, 0x99, 0x51, + 0x96, 0x8c, 0x4f, 0xcb, 0x43, 0x31, 0x1d, 0x0c, 0x4a, 0x52, 0x19, 0x0b, 0x3d, 0xb8, 0x1e, 0x78, 0xfe, 0x3d, 0x70, + 0x0b, 0xf1, 0xe0, 0x90, 0xc5, 0x90, 0x1b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8d, 0x4a, 0x15, 0xbc, 0x9a, 0xa8, 0x16, + 0xfc, 0x54, 0x86, 0x01, 0xfa, 0x24, 0x05, 0x60, 0x32, 0x98, 0xf2, 0x5b, 0x90, 0x28, 0x9d, 0xa9, 0x1b, 0xd2, 0xaf, + 0xa2, 0xe0, 0x17, 0xbc, 0xe0, 0x22, 0x71, 0x05, 0x58, 0xde, 0xc1, 0xf6, 0x3a, 0xaa, 0xa8, 0x02, 0xe2, 0x35, 0x3d, + 0x8e, 0xb8, 0xf1, 0xfe, 0x33, 0x3d, 0xb6, 0x40, 0xad, 0xd6, 0xb1, 0xc1, 0x67, 0x8e, 0xc1, 0x05, 0x5d, 0x4b, 0x6c, + 0x0d, 0xd5, 0xb0, 0x22, 0x30, 0x70, 0x01, 0x07, 0x61, 0x89, 0xe2, 0xd8, 0x4a, 0x5e, 0x91, 0x86, 0x94, 0xf6, 0x81, + 0xe1, 0x68, 0x93, 0x1c, 0xdf, 0x66, 0xd9, 0x4d, 0xe0, 0x7c, 0xd1, 0x39, 0x69, 0x26, 0x96, 0x0d, 0xde, 0xe7, 0xcd, + 0xf9, 0x75, 0xff, 0x90, 0x50, 0x15, 0xec, 0x86, 0xb7, 0x83, 0xdd, 0x38, 0xe1, 0xd7, 0x5c, 0x2c, 0x74, 0x7c, 0x16, + 0x73, 0xc9, 0xf2, 0x5b, 0xeb, 0xdd, 0x92, 0xa4, 0x56, 0x40, 0xfb, 0x2c, 0x0b, 0x6a, 0x22, 0x00, 0xdd, 0x0f, 0x7f, + 0x81, 0xd0, 0x19, 0xfe, 0xf6, 0x18, 0x5c, 0x91, 0xc2, 0x7b, 0x87, 0x40, 0x58, 0xd3, 0xcd, 0x9d, 0xda, 0x80, 0x2f, + 0xc6, 0xfd, 0x19, 0x53, 0x4f, 0xbf, 0xcd, 0xe4, 0xae, 0xae, 0xdb, 0x23, 0xcb, 0xf0, 0x11, 0xae, 0x14, 0x00, 0xcb, + 0x84, 0xbf, 0x18, 0x5b, 0x52, 0x7d, 0x02, 0x70, 0x6a, 0x3a, 0xa2, 0x4f, 0x10, 0x18, 0x38, 0x25, 0x5a, 0x8c, 0xae, + 0x95, 0x23, 0x9a, 0x41, 0x5a, 0xd3, 0xad, 0x30, 0xde, 0x7a, 0xd0, 0x42, 0xcf, 0x34, 0x9c, 0xf8, 0x0f, 0x9a, 0x79, + 0x55, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0xd1, 0x1c, 0x21, 0x3e, 0x61, 0x49, 0x34, 0x61, 0xf1, 0x4c, 0xf1, + 0x63, 0x42, 0x37, 0x4d, 0x6d, 0xd3, 0x07, 0xa4, 0xbf, 0xb8, 0x66, 0xfd, 0x94, 0x65, 0xed, 0xdb, 0x43, 0xc5, 0x8b, + 0x69, 0x33, 0xf8, 0x61, 0xa2, 0x8a, 0xf1, 0xbf, 0xa8, 0x7c, 0xa9, 0x15, 0xc0, 0x30, 0x77, 0xd5, 0xd3, 0xef, 0x37, + 0xb3, 0xe5, 0x40, 0xa8, 0xfc, 0xce, 0x20, 0xe9, 0xd3, 0xf1, 0xfc, 0xc0, 0x26, 0x51, 0x5b, 0xe8, 0xf9, 0xe3, 0x52, + 0x37, 0xa1, 0xf2, 0xda, 0xd4, 0x88, 0x56, 0xc8, 0x50, 0xd9, 0x3a, 0x60, 0x7d, 0xff, 0x10, 0xee, 0x2e, 0x6a, 0x1a, + 0x6a, 0xdd, 0x73, 0xd7, 0xa2, 0xe0, 0xc4, 0x1f, 0x60, 0x2c, 0x2e, 0x24, 0xb5, 0x0e, 0xc2, 0xa4, 0x1f, 0x2d, 0x4e, + 0x72, 0xa3, 0xae, 0x4e, 0xce, 0x14, 0xf3, 0x04, 0x2e, 0xaa, 0x65, 0xdb, 0x5f, 0x51, 0xa9, 0x4b, 0xb9, 0xbd, 0xa2, + 0x34, 0x3d, 0xa4, 0xed, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x0b, 0x05, 0x17, 0xd6, 0xc1, 0xba, 0xe3, 0x4e, 0xd9, + 0x13, 0x9e, 0x28, 0xd3, 0xda, 0xe0, 0xae, 0x1b, 0x8c, 0x89, 0xb1, 0xdf, 0x5d, 0xf2, 0xe4, 0x23, 0xb2, 0xe0, 0xdf, + 0x65, 0x02, 0x3c, 0x93, 0xdd, 0x2b, 0x95, 0xff, 0x07, 0xff, 0x6a, 0x6b, 0xdf, 0x59, 0xf3, 0x4f, 0xcf, 0x7a, 0xb8, + 0x73, 0x98, 0xfc, 0x00, 0x9d, 0x01, 0xdd, 0x5c, 0xc9, 0x94, 0x03, 0x32, 0x80, 0xb5, 0x48, 0x46, 0x03, 0x3e, 0xb4, + 0xb2, 0x6c, 0xfb, 0x4e, 0xab, 0x0b, 0xc2, 0xbd, 0x04, 0x6e, 0x7a, 0x7f, 0x6d, 0x66, 0xe6, 0x74, 0xad, 0x44, 0xd3, + 0xa5, 0xb1, 0xb5, 0x2c, 0x55, 0xc0, 0xee, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x70, 0x39, 0xcd, 0x2d, 0x75, 0xdb, 0xb8, + 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0xb5, 0x22, 0xf4, 0x54, 0x89, 0xd0, + 0xa7, 0x69, 0xb3, 0x0f, 0x76, 0x55, 0xad, 0x1b, 0x71, 0x8e, 0x06, 0xa9, 0x66, 0xe4, 0x4f, 0xae, 0x79, 0x71, 0x91, + 0xcb, 0x1b, 0xc0, 0x40, 0x26, 0xb5, 0x51, 0x58, 0x5e, 0x81, 0x3b, 0x3f, 0x3a, 0x8e, 0x33, 0x31, 0xca, 0x31, 0x58, + 0x2b, 0xc2, 0x23, 0xeb, 0xc4, 0x19, 0x80, 0x20, 0xfb, 0x93, 0xa6, 0xe3, 0xb9, 0x16, 0x18, 0xd3, 0x17, 0xb8, 0xab, + 0x9c, 0x1d, 0x6d, 0x72, 0xbb, 0xe8, 0x9b, 0x33, 0xac, 0x3b, 0x52, 0x5a, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, 0x06, + 0x6d, 0x11, 0x4a, 0x3e, 0xe4, 0x4e, 0xda, 0x4f, 0x01, 0x0d, 0xce, 0xb2, 0xf4, 0xd6, 0x5a, 0xe5, 0x6f, 0xb4, 0x10, + 0x27, 0x8a, 0xa9, 0x13, 0xdf, 0x44, 0x89, 0x3e, 0x3f, 0x13, 0xe3, 0x06, 0x02, 0xa9, 0x3f, 0x60, 0x50, 0x8d, 0x22, + 0x4c, 0xe0, 0x3a, 0x10, 0xc5, 0xf6, 0x44, 0x6d, 0x2c, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x41, 0x19, 0xc6, 0xea, 0xe2, + 0x40, 0x1b, 0x2c, 0x7d, 0xdd, 0x5a, 0xe7, 0x86, 0x50, 0x18, 0x27, 0x30, 0xc5, 0x20, 0xa9, 0xb3, 0xce, 0x32, 0x41, + 0x95, 0x1d, 0x93, 0xce, 0xfb, 0x00, 0xdd, 0x5d, 0x8b, 0xa6, 0xf8, 0xba, 0x73, 0x07, 0xdd, 0xc7, 0xf5, 0x6b, 0x2d, + 0x72, 0x83, 0x3f, 0x6f, 0x89, 0xb0, 0x08, 0x9c, 0xb5, 0x26, 0x5f, 0x35, 0xc2, 0x81, 0x29, 0xc9, 0x34, 0xec, 0x25, + 0xca, 0xa6, 0x7b, 0xbb, 0xed, 0xf5, 0xee, 0x15, 0x71, 0xf5, 0x18, 0xab, 0xbc, 0x9b, 0xb9, 0xbd, 0x53, 0xad, 0xc5, + 0xee, 0x4d, 0xdb, 0x4f, 0xb1, 0xa3, 0xd6, 0xda, 0xed, 0x86, 0x13, 0x6a, 0xc8, 0xb7, 0xa2, 0x4a, 0xab, 0xd3, 0x8d, + 0x41, 0x3b, 0xc4, 0xb3, 0x16, 0x19, 0xdc, 0x28, 0x5f, 0x38, 0xa1, 0x93, 0x8a, 0xb3, 0xea, 0xd4, 0x05, 0x9b, 0x2b, + 0x5e, 0x2d, 0x65, 0x1a, 0x09, 0x8a, 0x36, 0xe7, 0x51, 0x49, 0x13, 0xb9, 0x16, 0x55, 0x24, 0x6b, 0xd4, 0x8b, 0x5a, + 0x8d, 0x01, 0x02, 0x32, 0x9d, 0x35, 0x3d, 0xa8, 0x82, 0xd9, 0x50, 0x46, 0x72, 0xfa, 0x1e, 0x2c, 0xed, 0x91, 0x63, + 0xad, 0xef, 0xab, 0xb3, 0xc5, 0xb7, 0x7a, 0x42, 0x30, 0x85, 0xd9, 0x03, 0x61, 0xe0, 0x9a, 0xc6, 0x90, 0xd3, 0x2e, + 0x71, 0x59, 0xd3, 0x2d, 0xe1, 0x1e, 0x6e, 0x57, 0xb2, 0x23, 0x37, 0x4f, 0x9a, 0x9b, 0x2b, 0xd8, 0x51, 0x31, 0x1f, + 0x83, 0xf6, 0x4b, 0xaa, 0x6b, 0x97, 0xe6, 0xd6, 0xe3, 0x41, 0x40, 0x83, 0x41, 0x61, 0xf8, 0xd7, 0x89, 0xf1, 0xf0, + 0xa4, 0x01, 0x41, 0x52, 0x2e, 0xc2, 0xb1, 0x6f, 0x44, 0x3f, 0x99, 0xca, 0x43, 0x8e, 0x16, 0xef, 0xd0, 0xea, 0x04, + 0xa2, 0x78, 0x89, 0x50, 0x12, 0xa3, 0x2a, 0x34, 0x22, 0x28, 0x4f, 0xcb, 0x5f, 0xaa, 0xea, 0x10, 0x50, 0x48, 0xfb, + 0x8a, 0x42, 0xd9, 0x26, 0x31, 0x34, 0xc3, 0x2f, 0xe7, 0x93, 0x85, 0x9e, 0x81, 0x81, 0x9c, 0x1f, 0x2c, 0xf4, 0x2c, + 0x0c, 0xe4, 0xfc, 0xc9, 0xa2, 0x76, 0xeb, 0x40, 0x13, 0x10, 0xcf, 0x85, 0xa3, 0x93, 0xd2, 0xaa, 0x6c, 0x01, 0xdd, + 0x3c, 0x44, 0xd0, 0x7f, 0xb2, 0x87, 0xa0, 0x93, 0x0b, 0xed, 0xc8, 0x0d, 0x68, 0x3b, 0x0e, 0x81, 0xbd, 0x62, 0x52, + 0x61, 0x02, 0x10, 0x1d, 0xb2, 0x31, 0x18, 0x62, 0xab, 0x0f, 0x0e, 0xd9, 0x78, 0xea, 0x93, 0x20, 0x60, 0x74, 0x7f, + 0x30, 0x90, 0xe0, 0xb7, 0x78, 0x95, 0x3e, 0xda, 0x08, 0x74, 0xd3, 0x77, 0x77, 0x43, 0xef, 0xe2, 0x0a, 0x4e, 0xd5, + 0xee, 0x9e, 0x84, 0x6e, 0x32, 0xed, 0x00, 0xbd, 0x86, 0xb8, 0x21, 0xbf, 0x32, 0x1a, 0x8d, 0x6c, 0x4a, 0x48, 0x88, + 0xe1, 0x1c, 0x9a, 0x39, 0x2d, 0x97, 0xaf, 0x6e, 0x3d, 0x1b, 0x90, 0x61, 0xa6, 0xb7, 0x4c, 0xd6, 0x0f, 0x50, 0x56, + 0x3d, 0x86, 0x76, 0xe8, 0x3d, 0x72, 0xfc, 0xf0, 0xe0, 0x9b, 0x8c, 0x9f, 0x39, 0x5c, 0x7b, 0x38, 0x17, 0xbe, 0xcb, + 0x9a, 0x91, 0x39, 0x74, 0x9e, 0x7d, 0x1c, 0xef, 0x61, 0x9c, 0x7c, 0x9e, 0x85, 0xf2, 0xc6, 0x6b, 0xfa, 0x1f, 0x95, + 0xde, 0xec, 0x70, 0xc8, 0xe9, 0x0a, 0x56, 0xdc, 0xac, 0x0a, 0x0d, 0x3f, 0x8b, 0xbc, 0x71, 0xc4, 0x6b, 0x12, 0x55, + 0xdd, 0xe7, 0xbd, 0x0d, 0x53, 0xda, 0x31, 0x0e, 0x00, 0x4e, 0xd4, 0xaa, 0x61, 0x57, 0x1a, 0xd7, 0xea, 0x20, 0x86, + 0xa1, 0x84, 0xad, 0x12, 0x47, 0x42, 0xf9, 0x1b, 0x80, 0xb0, 0x18, 0x8a, 0xe3, 0xad, 0x61, 0x7d, 0x80, 0xfd, 0xd0, + 0x05, 0x9a, 0xe6, 0x94, 0x6a, 0x06, 0x00, 0x49, 0xc0, 0x1f, 0x3d, 0xdd, 0x34, 0x54, 0xb6, 0x79, 0x1e, 0x5a, 0x56, + 0x57, 0xf0, 0x40, 0x4f, 0x5d, 0xc9, 0xc0, 0xb8, 0xaa, 0x63, 0x6f, 0x73, 0x7f, 0x7b, 0xb4, 0x8a, 0x7c, 0x67, 0x93, + 0xda, 0x66, 0x55, 0x68, 0xec, 0xe3, 0x09, 0x3d, 0x9d, 0x00, 0xad, 0xd7, 0x96, 0x8a, 0xf6, 0xfb, 0x28, 0x46, 0x8d, + 0x0b, 0x05, 0x56, 0x61, 0x22, 0xc1, 0x21, 0xc2, 0x08, 0xa1, 0xdf, 0x97, 0xe1, 0xc6, 0x17, 0x64, 0x10, 0x0d, 0xd7, + 0xa2, 0xe3, 0x0f, 0x39, 0x5e, 0xb4, 0x2d, 0x55, 0x35, 0x27, 0x4d, 0x5b, 0x02, 0x6f, 0xc2, 0x01, 0xb6, 0xf3, 0x4f, + 0x1b, 0x22, 0x57, 0xe1, 0xa2, 0x84, 0xef, 0x88, 0x6b, 0x41, 0x74, 0x53, 0x9b, 0x7a, 0x1b, 0x76, 0x88, 0x8e, 0xa6, + 0x78, 0x74, 0xc8, 0x3d, 0x77, 0xcf, 0x6d, 0x11, 0xdf, 0x7c, 0x86, 0xdc, 0x35, 0x9d, 0xbd, 0x14, 0x61, 0x50, 0xb7, + 0x6c, 0xa0, 0x58, 0x87, 0x4e, 0x50, 0x80, 0x51, 0x5b, 0x3e, 0x01, 0x1d, 0x1b, 0x0c, 0x2a, 0x82, 0x4f, 0x0a, 0xdb, + 0xa6, 0x41, 0xfe, 0x88, 0x77, 0x43, 0x87, 0xd7, 0x96, 0x3c, 0x10, 0xaf, 0xb0, 0xcf, 0x94, 0x70, 0xff, 0x82, 0x82, + 0xee, 0x28, 0x2f, 0x57, 0x85, 0xab, 0xd2, 0x00, 0x54, 0xd9, 0xf1, 0x5c, 0x6b, 0x4a, 0x5a, 0xc0, 0x4a, 0x49, 0xdd, + 0xf9, 0x4d, 0x44, 0xdc, 0x92, 0xa9, 0x98, 0xad, 0xba, 0x51, 0xe5, 0xa1, 0x44, 0x91, 0x8e, 0x3d, 0xdb, 0x39, 0x58, + 0x03, 0xe0, 0x29, 0x6c, 0x2f, 0xce, 0xb0, 0xa0, 0x8c, 0xcb, 0x96, 0xb9, 0x04, 0x8a, 0xfa, 0x61, 0x9c, 0x97, 0x1d, + 0x5f, 0xee, 0x8e, 0xb6, 0xf7, 0xd0, 0x1b, 0xb1, 0x31, 0x5e, 0x5f, 0x46, 0x4d, 0xbf, 0x78, 0x86, 0x2b, 0x4b, 0x41, + 0x1e, 0x68, 0xaa, 0x47, 0x18, 0x1d, 0x02, 0xd3, 0x94, 0x1f, 0xb1, 0xf1, 0x74, 0x38, 0x34, 0x64, 0xd0, 0x6b, 0x26, + 0xc6, 0xff, 0xfa, 0x02, 0x5a, 0x67, 0x26, 0xae, 0xf1, 0x69, 0xfb, 0x0a, 0x5a, 0xdd, 0xa2, 0x4c, 0xee, 0x0c, 0x0c, + 0x1f, 0x68, 0xc9, 0x14, 0x4c, 0x15, 0xde, 0x10, 0xa9, 0x64, 0x9f, 0x96, 0xd6, 0x61, 0xdf, 0x2e, 0x14, 0x5a, 0x68, + 0xe2, 0x57, 0x19, 0xe2, 0xa7, 0xae, 0x33, 0xff, 0x36, 0xed, 0x53, 0x83, 0x58, 0x58, 0x12, 0xa3, 0x10, 0xbf, 0x38, + 0x55, 0xb6, 0x13, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x55, 0xec, 0x49, 0xa1, 0xf1, 0xd4, 0x70, 0xdf, + 0x0b, 0x1d, 0xb3, 0x0e, 0xb3, 0xb8, 0xcd, 0x1a, 0x49, 0x8d, 0x71, 0x2a, 0x4c, 0x70, 0x4a, 0xb9, 0x8a, 0x04, 0x46, + 0xc7, 0xb3, 0x85, 0x41, 0x54, 0x49, 0x4c, 0x32, 0xb6, 0x16, 0xc2, 0xc4, 0xae, 0x73, 0x85, 0x69, 0xea, 0x22, 0xf5, + 0x9b, 0x81, 0xc9, 0x82, 0x86, 0xfc, 0x1e, 0x8d, 0xd6, 0x54, 0x4d, 0x01, 0x86, 0x71, 0x94, 0x6a, 0xfc, 0x5b, 0x84, + 0xda, 0x0c, 0x03, 0x00, 0xdb, 0xbc, 0x93, 0x99, 0xa8, 0x5e, 0x0b, 0x84, 0x40, 0x73, 0xf6, 0x53, 0x45, 0xb5, 0x33, + 0x0b, 0x46, 0xd1, 0x6e, 0xaf, 0x7c, 0x3e, 0x70, 0x42, 0x79, 0xac, 0x2e, 0x50, 0xaf, 0x64, 0xf1, 0x46, 0xa6, 0xbc, + 0x15, 0x17, 0x73, 0x4f, 0xb2, 0x0f, 0xf9, 0x08, 0xce, 0x2b, 0x74, 0x2a, 0x37, 0xdb, 0x44, 0x99, 0x25, 0x49, 0xc6, + 0x02, 0x63, 0xf3, 0x12, 0xcc, 0xa4, 0x66, 0xc6, 0xf0, 0x6b, 0x08, 0x2e, 0xb6, 0x73, 0x12, 0x6e, 0xee, 0xe7, 0x81, + 0x21, 0x34, 0xb9, 0x68, 0x89, 0x86, 0xad, 0x1d, 0xaf, 0x27, 0xd7, 0x84, 0xfb, 0xb0, 0x11, 0x6b, 0x32, 0xc6, 0xb8, + 0x36, 0x37, 0xb2, 0x7e, 0xb4, 0xc0, 0x83, 0x31, 0x65, 0xfd, 0x09, 0x64, 0x5a, 0x49, 0x59, 0xe7, 0x0b, 0x23, 0x66, + 0x52, 0x89, 0xde, 0xed, 0x1b, 0x9f, 0xd5, 0x5d, 0x44, 0xfd, 0xd6, 0x7e, 0x4f, 0xea, 0xe1, 0xce, 0x7f, 0x50, 0x58, + 0x83, 0xca, 0x88, 0xcb, 0x88, 0xf2, 0xcc, 0x81, 0x6e, 0x9a, 0x14, 0x71, 0x7a, 0xb6, 0x8a, 0x8b, 0x92, 0xa7, 0x50, + 0xa9, 0xa6, 0x6e, 0x51, 0x6f, 0x02, 0xf6, 0x86, 0x48, 0x92, 0xac, 0xa5, 0xb1, 0x15, 0xbb, 0x34, 0x48, 0xcf, 0xbd, + 0x61, 0x96, 0x5e, 0x55, 0x68, 0x48, 0x4b, 0xbd, 0xb3, 0x50, 0xc9, 0xfc, 0x15, 0xff, 0x19, 0xd4, 0x0a, 0x74, 0xb4, + 0x49, 0x31, 0x9e, 0x03, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x09, 0x4a, 0xbd, 0x23, 0x76, 0xfc, 0xdc, + 0xe4, 0xe1, 0x5d, 0xc8, 0x39, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0x48, 0x8c, 0xd4, 0x0c, 0xa0, 0xe9, 0xa0, + 0xcc, 0x79, 0x2c, 0x82, 0x59, 0xcf, 0x24, 0x46, 0x3d, 0xae, 0x7f, 0x81, 0x86, 0xda, 0x6f, 0x56, 0x96, 0x67, 0xd5, + 0xdd, 0x97, 0x70, 0x60, 0x53, 0x5b, 0x41, 0x8f, 0xd7, 0x95, 0xbc, 0xbc, 0x54, 0xdd, 0xf6, 0x0b, 0x31, 0x72, 0xba, + 0xc6, 0xb5, 0x74, 0x5e, 0x2d, 0x58, 0xaf, 0x3b, 0xdd, 0x2c, 0xee, 0x66, 0x19, 0x0d, 0x84, 0xb5, 0x9d, 0x4f, 0x34, + 0x7f, 0xd6, 0x6c, 0xbb, 0x8f, 0xb7, 0x20, 0x66, 0x01, 0x00, 0xa4, 0x07, 0x51, 0xb0, 0xcc, 0x52, 0x1e, 0x50, 0x79, + 0x1f, 0x47, 0x59, 0x28, 0xbd, 0x9c, 0x65, 0xfc, 0xb4, 0x69, 0xac, 0x75, 0x56, 0x28, 0x43, 0x6b, 0xa3, 0x3b, 0x5d, + 0x65, 0x88, 0xed, 0x27, 0x71, 0xb6, 0x00, 0xf7, 0xc7, 0x0c, 0x85, 0x86, 0xce, 0x32, 0xd2, 0x44, 0xc3, 0x77, 0xdd, + 0x33, 0xc8, 0x28, 0x4e, 0xd6, 0x79, 0x25, 0xdd, 0xe8, 0xb3, 0x36, 0x12, 0xe6, 0x1e, 0xa2, 0x5f, 0xc5, 0xe0, 0x51, + 0xee, 0xf3, 0xda, 0xe8, 0x64, 0x5a, 0x46, 0xda, 0x9d, 0x9f, 0xd4, 0xcb, 0x2c, 0xd5, 0x3a, 0x6c, 0x9f, 0x61, 0x6f, + 0x8d, 0x49, 0x6f, 0x42, 0x6a, 0x18, 0x89, 0xcf, 0x67, 0xd4, 0x08, 0x01, 0x6d, 0x39, 0xfe, 0x0e, 0x9f, 0x61, 0x68, + 0x0a, 0x2c, 0x55, 0xdc, 0xc2, 0x6e, 0xf8, 0x9a, 0x4f, 0x56, 0x2d, 0x00, 0x11, 0xac, 0x7c, 0xbd, 0x8b, 0x57, 0x42, + 0x7d, 0xa6, 0xcd, 0x00, 0x90, 0x05, 0xa5, 0xdc, 0xf1, 0x53, 0x2a, 0x1d, 0x2c, 0x51, 0xb4, 0xbd, 0x9c, 0xbe, 0xd1, + 0xb1, 0xf1, 0x43, 0x7a, 0x2e, 0x60, 0xbb, 0x90, 0xdf, 0xba, 0x57, 0x2f, 0x51, 0x91, 0xda, 0x36, 0xeb, 0x01, 0xbe, + 0xdc, 0xa0, 0x49, 0x18, 0x41, 0x99, 0x32, 0x05, 0x30, 0xb8, 0xa9, 0x46, 0xc1, 0xa4, 0xd5, 0x48, 0xd8, 0x52, 0x4f, + 0xb2, 0xdc, 0xf4, 0xc1, 0xa9, 0xee, 0x11, 0xf4, 0x68, 0x87, 0x93, 0x96, 0xfd, 0x5a, 0xc1, 0xd1, 0xc9, 0xd5, 0x10, + 0x35, 0xf3, 0x5e, 0xdb, 0x91, 0x21, 0xe5, 0x32, 0x0c, 0x04, 0x53, 0x8e, 0x79, 0x7a, 0x6c, 0x3d, 0x23, 0xa2, 0x07, + 0xce, 0x3e, 0xd3, 0xad, 0xba, 0x92, 0x80, 0xe8, 0xf8, 0xcd, 0xd3, 0xd7, 0x57, 0xf1, 0xa5, 0x41, 0x51, 0x6a, 0x58, + 0xc4, 0x28, 0xd3, 0xbe, 0x4a, 0xc2, 0xe0, 0xfd, 0xfa, 0xfe, 0x67, 0x95, 0xa5, 0xf6, 0x7b, 0xb0, 0xb1, 0xa2, 0xaa, + 0x5f, 0x4b, 0x5e, 0x34, 0x05, 0x58, 0xf7, 0x59, 0xa2, 0x40, 0xee, 0xf7, 0x36, 0xcd, 0x7c, 0x13, 0x35, 0x6e, 0x36, + 0xac, 0x37, 0xae, 0xdb, 0xa5, 0xb6, 0x64, 0x47, 0x56, 0x22, 0x67, 0x16, 0x83, 0x19, 0x3f, 0x2a, 0x0c, 0x4a, 0xc3, + 0x06, 0x55, 0xa9, 0xf8, 0xbd, 0x11, 0xc1, 0xa9, 0x63, 0x55, 0x61, 0x4c, 0x03, 0x66, 0x5b, 0x51, 0x6b, 0x50, 0x07, + 0xa5, 0xb4, 0x35, 0x51, 0xd8, 0x7e, 0x67, 0x05, 0x35, 0xbf, 0xff, 0x69, 0x0c, 0xf9, 0x9a, 0x52, 0x50, 0x49, 0xc0, + 0xce, 0xa0, 0xd1, 0x53, 0x25, 0x0c, 0xa4, 0x20, 0x78, 0x02, 0x94, 0x2f, 0xa2, 0xc6, 0x6a, 0xb7, 0xaf, 0x4e, 0x8d, + 0xd1, 0x16, 0x10, 0x5a, 0x48, 0x8f, 0x2e, 0xfb, 0xb8, 0x8d, 0x75, 0x20, 0xf1, 0xe0, 0x04, 0xdb, 0xb9, 0xba, 0x46, + 0x23, 0xa1, 0xf9, 0x43, 0xa3, 0x01, 0xaf, 0x69, 0x05, 0x0a, 0xf5, 0x1c, 0x47, 0x43, 0x67, 0x87, 0x14, 0x44, 0x6c, + 0xd0, 0xc2, 0xbe, 0x7b, 0x3e, 0x34, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x4d, 0xa5, 0xfb, 0xdc, 0x2d, 0x21, 0x6b, 0xd5, + 0xa1, 0xac, 0x3c, 0xc0, 0xf1, 0x42, 0xc9, 0xfc, 0x1d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x63, 0xc4, 0x02, 0x96, 0x04, + 0xed, 0xf5, 0x40, 0xfd, 0x32, 0x08, 0x15, 0xce, 0xf4, 0x44, 0xe2, 0x53, 0xca, 0xd5, 0xa7, 0x05, 0xa9, 0xa7, 0x05, + 0x73, 0xa0, 0x97, 0xbe, 0x95, 0x5f, 0xd9, 0xf8, 0x68, 0x77, 0xef, 0x9a, 0x0b, 0xeb, 0x18, 0x82, 0x61, 0x0b, 0xbf, + 0x39, 0x35, 0x05, 0x60, 0xc3, 0x63, 0x5d, 0x96, 0x6f, 0xd4, 0x44, 0x66, 0x71, 0x48, 0x22, 0x90, 0x6c, 0x37, 0x37, + 0xb7, 0x11, 0x6c, 0x7b, 0x0b, 0xb5, 0xa1, 0xfe, 0xf2, 0xb6, 0xfb, 0x3d, 0xc3, 0xcb, 0x3d, 0xb9, 0x77, 0xd3, 0x86, + 0xf2, 0x87, 0xfb, 0x57, 0xc9, 0xff, 0x55, 0x25, 0xf7, 0x5b, 0x65, 0xd6, 0x6d, 0xf1, 0x7e, 0xd7, 0x71, 0xcb, 0x31, + 0x1a, 0x04, 0xd6, 0x14, 0x18, 0x48, 0x4f, 0x1a, 0xd3, 0x44, 0x87, 0x54, 0x66, 0xcc, 0xe0, 0xd1, 0x05, 0x68, 0x0e, + 0xd3, 0x79, 0x1e, 0x03, 0x70, 0x80, 0x7f, 0xe4, 0x11, 0xea, 0x9f, 0xce, 0xf3, 0xe0, 0x2c, 0x18, 0x94, 0x83, 0x40, + 0x7f, 0xe2, 0x9a, 0x13, 0x2c, 0x40, 0xe7, 0x16, 0x33, 0x08, 0x36, 0x69, 0xcd, 0x1c, 0xe2, 0xc3, 0x64, 0x3a, 0x18, + 0xc4, 0x64, 0x03, 0x20, 0x7d, 0xf1, 0xc2, 0x3a, 0x07, 0x15, 0x7a, 0x41, 0xb6, 0xea, 0x2e, 0x9a, 0x15, 0x7b, 0xd5, + 0x4e, 0xf3, 0x7e, 0x3f, 0x9f, 0x97, 0x83, 0xa0, 0x51, 0x61, 0x61, 0xbc, 0xff, 0x68, 0xf3, 0x4b, 0xa3, 0x93, 0x26, + 0x18, 0xa6, 0xf6, 0x18, 0xd5, 0x2b, 0x9e, 0x66, 0xb4, 0x71, 0x3b, 0x56, 0xca, 0x17, 0x10, 0xc5, 0x03, 0x43, 0xd6, + 0xca, 0xbb, 0x73, 0xf0, 0xba, 0xdc, 0x78, 0x73, 0x44, 0x01, 0x76, 0x53, 0x18, 0x27, 0x35, 0x17, 0x5d, 0xd4, 0xc4, + 0x33, 0xd8, 0xe9, 0xea, 0xad, 0x44, 0xab, 0xf1, 0x5e, 0xbc, 0x6b, 0x36, 0xfe, 0x56, 0xee, 0xe9, 0x32, 0xf7, 0x2e, + 0x00, 0x71, 0x76, 0x2f, 0xae, 0xf6, 0xb0, 0xd4, 0xbd, 0x60, 0x60, 0x91, 0x43, 0xda, 0xd5, 0xea, 0xa1, 0x88, 0xd4, + 0x79, 0x0c, 0x06, 0x4c, 0xa6, 0x21, 0x35, 0x99, 0xf6, 0x0a, 0x05, 0x69, 0x63, 0xad, 0x05, 0xb4, 0xe1, 0xb0, 0xd8, + 0xb1, 0x1b, 0x76, 0xa7, 0x5b, 0x87, 0x42, 0x09, 0xa3, 0x57, 0xd7, 0xcd, 0x43, 0xad, 0xe1, 0x89, 0xa0, 0x07, 0xd5, + 0x68, 0x3f, 0x3d, 0x94, 0x27, 0xed, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0x52, 0xe0, 0x45, 0x7b, 0x07, 0x79, 0xce, + 0x7c, 0xaa, 0x7c, 0x10, 0x1b, 0x6e, 0x19, 0x3e, 0xb4, 0x8f, 0x6f, 0x05, 0x32, 0xa9, 0x3b, 0x9a, 0xda, 0xda, 0x1d, + 0x8d, 0x63, 0x02, 0xfd, 0xa6, 0x1c, 0xa5, 0x4c, 0x4c, 0x2d, 0x4b, 0x76, 0xd4, 0xcb, 0x95, 0x37, 0x54, 0xca, 0x8e, + 0x96, 0x6d, 0xce, 0x2f, 0x6d, 0x24, 0xf4, 0xfb, 0xda, 0x1d, 0x08, 0xdf, 0xa8, 0xf5, 0x86, 0xbc, 0x6c, 0x88, 0x58, + 0x0e, 0x31, 0x03, 0xc7, 0x0b, 0xa9, 0x5c, 0xbb, 0x8b, 0xa6, 0xaa, 0x6e, 0x67, 0x2b, 0x17, 0xb4, 0xc4, 0x5b, 0x29, + 0xb0, 0x8a, 0xd4, 0xe9, 0xf5, 0x54, 0xe2, 0x7d, 0x1f, 0xc5, 0xf6, 0x23, 0x60, 0x1b, 0x1b, 0x47, 0x63, 0xe3, 0x16, + 0xb1, 0xc1, 0x57, 0x51, 0x45, 0x0b, 0x0e, 0x10, 0xdc, 0x6d, 0x49, 0x2d, 0xcd, 0x1c, 0xe2, 0xbe, 0xe2, 0x01, 0xda, + 0x77, 0x71, 0xc4, 0xa9, 0x00, 0xdb, 0xba, 0xd6, 0x39, 0xab, 0xe5, 0x80, 0xcd, 0x44, 0xcf, 0x3f, 0xad, 0x1a, 0x89, + 0x18, 0x56, 0xd9, 0x48, 0x59, 0xa1, 0x3d, 0x28, 0x5d, 0xc2, 0xc5, 0x17, 0xe0, 0x65, 0xfb, 0x7e, 0x65, 0xf7, 0xd9, + 0x12, 0xfb, 0x87, 0x79, 0xd5, 0x04, 0x8f, 0xbc, 0xc6, 0xdb, 0x7b, 0x98, 0xf8, 0x52, 0x29, 0x84, 0x57, 0x29, 0x0d, + 0x25, 0x00, 0x83, 0x24, 0xa8, 0xe1, 0x4a, 0xdb, 0x66, 0x90, 0xca, 0x18, 0x76, 0xb7, 0x7a, 0xab, 0xff, 0xd3, 0x2a, + 0x5c, 0x54, 0xb2, 0x18, 0x93, 0x40, 0xe7, 0x54, 0xcb, 0x4d, 0x4c, 0xc1, 0xb3, 0x5d, 0x72, 0x04, 0x0a, 0x3b, 0x01, + 0xdc, 0x50, 0xc2, 0x7e, 0xc5, 0xdb, 0x50, 0xce, 0x5e, 0x59, 0xc9, 0x93, 0xdb, 0x97, 0x54, 0xd0, 0x84, 0x4c, 0x85, + 0xdd, 0xbf, 0xad, 0x0d, 0xfb, 0x22, 0x94, 0x23, 0x29, 0x70, 0x71, 0xd0, 0x39, 0x80, 0xfd, 0x41, 0x2e, 0x63, 0xf3, + 0x99, 0xf4, 0xfb, 0xea, 0xfd, 0xf3, 0x3c, 0x4b, 0x3e, 0xee, 0xbc, 0x37, 0x3c, 0xcd, 0x92, 0x01, 0x95, 0x88, 0xa9, + 0x75, 0x55, 0x0c, 0x97, 0xda, 0xc5, 0xb8, 0x41, 0x32, 0xe2, 0x7b, 0xa9, 0x43, 0x8c, 0x18, 0x5f, 0x64, 0x87, 0xa4, + 0xe4, 0x74, 0x59, 0x77, 0xf6, 0x5c, 0x8b, 0x66, 0xd0, 0x18, 0x6e, 0xc7, 0x7b, 0x49, 0xaf, 0x00, 0x15, 0x15, 0xba, + 0x67, 0x81, 0x6b, 0x78, 0x73, 0x49, 0x34, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xb8, 0x57, 0x26, 0x24, 0xd5, 0xc6, 0x01, + 0x16, 0xb1, 0xae, 0x3f, 0x86, 0x12, 0x80, 0x5a, 0x0d, 0xd2, 0x2b, 0x7d, 0x45, 0xa8, 0x4a, 0x42, 0x30, 0x3a, 0x91, + 0xf0, 0x32, 0xa0, 0x71, 0x66, 0x12, 0x2d, 0x6c, 0x70, 0x40, 0x5f, 0x54, 0x26, 0xd1, 0xd8, 0x90, 0x07, 0xb4, 0xb2, + 0x69, 0x00, 0x83, 0x0f, 0x92, 0x24, 0xfa, 0x7a, 0x69, 0x92, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x4b, 0xe9, 0xf9, + 0x58, 0xfe, 0xcb, 0x3b, 0x94, 0x7e, 0x08, 0x25, 0xc8, 0x14, 0x75, 0xc5, 0x34, 0x63, 0x47, 0x59, 0xb7, 0x31, 0x89, + 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x79, 0xbc, 0x62, 0xc7, 0x21, 0xd7, + 0x78, 0xe9, 0xcf, 0xe3, 0x15, 0xce, 0x10, 0xad, 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, + 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x4e, 0x92, 0xf9, 0xf2, + 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, + 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x5a, + 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1b, 0x50, 0x22, 0xa3, 0xb2, + 0xe2, 0xab, 0x15, 0x4f, 0x67, 0xb7, 0x49, 0x94, 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0x59, 0x9f, 0x67, + 0xc9, 0x6b, 0x88, 0x3d, 0xb0, 0x92, 0x0a, 0x8b, 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x76, + 0x9d, 0x44, 0x6f, 0x97, 0x1e, 0x92, 0x9a, 0x99, 0xb2, 0x4d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x1b, 0x6d, 0x01, + 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, + 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x0f, 0x8b, 0x7e, 0x5f, + 0x1e, 0x16, 0xdb, 0x6d, 0x79, 0x14, 0xf7, 0xfb, 0xf2, 0x28, 0x36, 0xfc, 0x83, 0x52, 0x6c, 0x1b, 0x73, 0x83, 0x84, + 0xe6, 0x12, 0xa2, 0x16, 0x8d, 0xe0, 0x0f, 0xcd, 0x72, 0x2e, 0xa2, 0xfc, 0x30, 0xe9, 0xf7, 0x7b, 0xcb, 0x99, 0x18, + 0xe4, 0xc3, 0x24, 0xca, 0x87, 0x89, 0xe7, 0x84, 0xf8, 0x9b, 0xe7, 0x84, 0xa8, 0x68, 0xe0, 0x0a, 0xce, 0x0c, 0x40, + 0x14, 0xf0, 0xe9, 0x1f, 0xd5, 0xb5, 0x14, 0xba, 0x96, 0x58, 0xd5, 0x92, 0xe8, 0x0a, 0x6a, 0x76, 0x5d, 0x84, 0x25, + 0x96, 0x42, 0x97, 0xec, 0xcf, 0x25, 0xf0, 0x44, 0x39, 0xaf, 0x36, 0xc0, 0xc0, 0x46, 0x78, 0xe7, 0x30, 0xe1, 0x24, + 0xd6, 0x35, 0xa0, 0x9d, 0x6e, 0x6a, 0x7a, 0x41, 0x57, 0xf4, 0x12, 0xf9, 0xd9, 0x0b, 0x30, 0x58, 0x3a, 0x64, 0xf9, + 0x74, 0x30, 0xb8, 0x20, 0x2b, 0x56, 0xce, 0xc3, 0x78, 0x10, 0xae, 0x67, 0xf9, 0xf0, 0x22, 0xba, 0x20, 0xe4, 0xab, + 0x62, 0x41, 0x7b, 0xab, 0x51, 0xf9, 0x31, 0x83, 0xe0, 0x7e, 0xe9, 0x2c, 0xcc, 0x4c, 0x9c, 0x8f, 0xd5, 0xe8, 0x96, + 0xae, 0x20, 0x7e, 0x0d, 0xdc, 0x48, 0x48, 0x04, 0x1d, 0xb9, 0xa4, 0x2b, 0xba, 0xa6, 0xd2, 0xcc, 0x30, 0x86, 0xe8, + 0xb6, 0xc7, 0x49, 0x02, 0x8e, 0xc9, 0xae, 0xf8, 0x68, 0xac, 0x0a, 0xef, 0xfa, 0x8e, 0xd0, 0x5e, 0x2f, 0x71, 0x83, + 0xf4, 0x5d, 0x7b, 0x90, 0x80, 0x11, 0x19, 0xa9, 0x81, 0x32, 0x23, 0x23, 0xa9, 0x99, 0x54, 0x1c, 0x92, 0xd8, 0x1f, + 0x12, 0x35, 0x0e, 0x89, 0x3f, 0x0e, 0xb9, 0x1e, 0x07, 0xe4, 0xee, 0x97, 0x6c, 0x4c, 0x53, 0x36, 0xa6, 0x6b, 0x35, + 0x2a, 0xf4, 0x8a, 0x9e, 0x6b, 0xea, 0x78, 0xc6, 0xde, 0xc0, 0x81, 0x3d, 0x08, 0xf3, 0x59, 0x3c, 0x7c, 0x13, 0xbd, + 0x21, 0xe4, 0x2b, 0x49, 0xaf, 0xd5, 0xa5, 0x0c, 0xc2, 0x20, 0x5e, 0x81, 0x73, 0xa9, 0x0b, 0x75, 0x72, 0x65, 0x76, + 0x1c, 0x3e, 0x5d, 0x36, 0x9e, 0xce, 0x21, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x05, 0x2b, 0xe7, 0x67, 0xe1, + 0x98, 0x00, 0x0e, 0x8f, 0x1e, 0xce, 0x8b, 0xd1, 0x2d, 0xbd, 0x18, 0xdd, 0x11, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0x87, + 0x2c, 0x9e, 0x0e, 0x06, 0x6b, 0xa4, 0xea, 0x2a, 0xf7, 0x9a, 0x2c, 0xe8, 0x05, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x13, + 0x6b, 0x43, 0xc3, 0xdf, 0x30, 0xf8, 0xf8, 0x8e, 0x5d, 0x8c, 0xee, 0xe8, 0x2d, 0x7b, 0xb3, 0x1d, 0x4f, 0x81, 0x99, + 0x5a, 0xcd, 0xc2, 0xbb, 0xc3, 0xcb, 0xd9, 0x25, 0xbb, 0x8b, 0xee, 0x8e, 0xa0, 0xa1, 0x57, 0xec, 0x0e, 0x01, 0x97, + 0xd2, 0xc7, 0xcb, 0xc1, 0x1b, 0xb2, 0x3f, 0x18, 0xa4, 0x24, 0x0a, 0xaf, 0x43, 0xaf, 0x95, 0x6f, 0xe8, 0x1d, 0xa1, + 0x2b, 0x76, 0x8b, 0xa3, 0x71, 0xc9, 0xf0, 0x83, 0x73, 0x76, 0x57, 0x5f, 0x87, 0xde, 0x6e, 0x4e, 0x44, 0x27, 0x88, + 0x11, 0xfa, 0x1a, 0x38, 0x9a, 0xe5, 0xc2, 0x4c, 0xc0, 0x93, 0xb9, 0xc8, 0x68, 0x51, 0x68, 0x06, 0xe2, 0xac, 0x04, + 0xc4, 0x92, 0xa8, 0xfb, 0xcd, 0x46, 0x67, 0xb0, 0x9c, 0xfb, 0xfd, 0x5e, 0x65, 0xe8, 0x01, 0x22, 0x67, 0x76, 0xd2, + 0x83, 0x9e, 0x4f, 0x0f, 0xf0, 0x13, 0xbd, 0x6a, 0x10, 0x27, 0xf3, 0xbb, 0x65, 0xf4, 0x9b, 0x47, 0x1f, 0x7e, 0xe8, + 0xa6, 0x3c, 0x22, 0xff, 0xf7, 0x29, 0x4f, 0x99, 0x47, 0x6f, 0x2a, 0x0f, 0x04, 0xcf, 0x5b, 0x93, 0x4a, 0x23, 0x51, + 0x8d, 0xce, 0x56, 0x31, 0x68, 0x23, 0x51, 0xdb, 0xa0, 0x9f, 0xd0, 0xc2, 0x0a, 0x22, 0xe4, 0x1c, 0xbc, 0x00, 0x83, + 0x54, 0x08, 0x95, 0xa3, 0x16, 0x25, 0x1a, 0x82, 0xe4, 0xb2, 0xe4, 0x2a, 0x7c, 0x0e, 0xa1, 0xea, 0xf4, 0x71, 0x26, + 0xc2, 0x86, 0x1e, 0x87, 0x3e, 0x00, 0xfc, 0xaf, 0x3b, 0xe4, 0xa2, 0xe4, 0x97, 0x78, 0x36, 0xb7, 0x09, 0x46, 0xc1, + 0x12, 0xd1, 0x0c, 0x6d, 0x83, 0xd8, 0x8f, 0x25, 0xc1, 0x7a, 0x24, 0x8d, 0x47, 0xa5, 0x39, 0x22, 0xfc, 0x28, 0x3e, + 0x8a, 0x9e, 0xc6, 0x86, 0x44, 0x72, 0x24, 0x91, 0x7c, 0x00, 0x84, 0x93, 0xa0, 0xbf, 0xb8, 0x6b, 0xb2, 0x6b, 0x21, + 0x31, 0xe8, 0x4f, 0x4b, 0xa6, 0x65, 0xf7, 0xaa, 0xc7, 0xbe, 0x22, 0xc8, 0x1d, 0xd3, 0x7f, 0x79, 0x7d, 0xf8, 0xe7, + 0x12, 0x67, 0xd0, 0x7a, 0xbe, 0xa8, 0xce, 0xcc, 0xbc, 0xc1, 0x8d, 0xbc, 0x2e, 0x6b, 0xd7, 0xe5, 0x0b, 0xbe, 0xc7, + 0x6f, 0x2b, 0x2e, 0xd2, 0x72, 0xef, 0x97, 0xaa, 0x8d, 0xe7, 0x54, 0xae, 0x57, 0x2e, 0xce, 0x8a, 0x32, 0x4e, 0xf5, + 0xa4, 0x2e, 0xc6, 0x1a, 0xb6, 0xe1, 0xf7, 0x88, 0xba, 0x92, 0x96, 0xa3, 0xa7, 0x94, 0xab, 0x66, 0xca, 0xc5, 0x3a, + 0xcf, 0x7f, 0xde, 0x49, 0xc5, 0x29, 0x6e, 0xa6, 0x20, 0x55, 0x6a, 0xb9, 0x80, 0xea, 0x39, 0x6a, 0xb9, 0x5b, 0x9a, + 0x1d, 0xe0, 0xdc, 0x36, 0xd5, 0xc7, 0xca, 0xec, 0xc2, 0x4b, 0x6e, 0xdc, 0x9f, 0x4c, 0x19, 0x16, 0x8c, 0x42, 0x9b, + 0x55, 0x57, 0xda, 0xbe, 0xd0, 0x3a, 0x0d, 0xc3, 0x95, 0x1f, 0x2f, 0x20, 0x5d, 0xc0, 0x38, 0x5e, 0x94, 0x4c, 0x8c, + 0xdb, 0xa3, 0xb7, 0x82, 0xf8, 0x92, 0xad, 0x40, 0xc0, 0x5c, 0xc3, 0xdb, 0x75, 0x1d, 0x6d, 0xf7, 0xc4, 0x29, 0xa3, + 0x72, 0x15, 0x8b, 0xef, 0xe3, 0x95, 0x81, 0x4c, 0x56, 0xc7, 0x63, 0x63, 0x4c, 0xa7, 0x3f, 0x25, 0xa1, 0x5f, 0x08, + 0x05, 0x9f, 0xf5, 0xd2, 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, + 0xe4, 0xab, 0xa6, 0x80, 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, + 0x9d, 0x1a, 0x53, 0x31, 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, + 0xa8, 0xdf, 0x02, 0x17, 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, + 0xbe, 0x85, 0x07, 0x88, 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, + 0xa9, 0xd2, 0xc4, 0x70, 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, + 0xe8, 0xa6, 0x74, 0xe9, 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, + 0xac, 0x95, 0xf0, 0xa6, 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, + 0x14, 0x0d, 0x1d, 0xd0, 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, + 0x35, 0x2b, 0xe6, 0xf9, 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, + 0x21, 0xc9, 0x26, 0x56, 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, + 0x32, 0x0c, 0xcb, 0xe1, 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x70, 0x3e, 0x09, 0x15, + 0xbb, 0x60, 0xf7, 0x02, 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, + 0x65, 0x16, 0xcf, 0xc7, 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, + 0xbe, 0xc1, 0x2a, 0xf2, 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, + 0xdc, 0x94, 0x33, 0xae, 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, + 0x49, 0xd3, 0x80, 0xee, 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, + 0xad, 0xd0, 0xab, 0x1a, 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, + 0x12, 0x06, 0x3f, 0xa4, 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, + 0x14, 0x62, 0x94, 0x50, 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, + 0x7c, 0x5d, 0x55, 0x81, 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, + 0x48, 0x08, 0x5e, 0xff, 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, + 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, + 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, + 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, + 0x4f, 0xae, 0xd8, 0x51, 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, + 0xf7, 0x1f, 0xcb, 0x5d, 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, + 0x84, 0x2d, 0xe6, 0x70, 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, + 0xb4, 0xcc, 0xaa, 0xf7, 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, + 0x02, 0xd0, 0x64, 0x23, 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, + 0x92, 0xa0, 0x84, 0x66, 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, + 0x07, 0xf6, 0x16, 0x04, 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, + 0x08, 0xf2, 0xd5, 0x18, 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, + 0xe4, 0xd0, 0x3e, 0x4b, 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb7, 0x2d, 0xb2, 0x24, 0xeb, + 0xc7, 0xd2, 0x28, 0x62, 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3e, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, + 0x0e, 0xe2, 0x36, 0x08, 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, + 0x6f, 0xb2, 0xd6, 0xa8, 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, + 0xdb, 0xed, 0x78, 0x2a, 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, + 0xa5, 0xb7, 0x7f, 0xe1, 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, + 0x4e, 0xff, 0x76, 0x6b, 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xb4, 0x81, 0x2b, 0xd5, 0x2a, 0x04, 0xec, 0x42, + 0x49, 0xf6, 0x0f, 0x20, 0x2a, 0x42, 0x33, 0xee, 0x66, 0xd9, 0x90, 0xc8, 0xf8, 0x71, 0x3a, 0xcb, 0x86, 0x60, 0x87, + 0x7b, 0x51, 0x89, 0xcb, 0x51, 0x6b, 0x83, 0xd3, 0xb3, 0x24, 0x84, 0x50, 0x0e, 0x58, 0xd9, 0xad, 0xfa, 0x73, 0xa7, + 0xcc, 0x84, 0xd4, 0x64, 0x75, 0x3b, 0xa5, 0x7b, 0x98, 0xe6, 0x7b, 0x66, 0x04, 0x07, 0xdc, 0xdb, 0x5f, 0xf5, 0xc7, + 0x30, 0xc9, 0x34, 0x39, 0x45, 0xf2, 0x8b, 0xf4, 0x14, 0x92, 0x76, 0xe8, 0xa9, 0x22, 0x80, 0x13, 0x6a, 0x3f, 0x86, + 0xdf, 0x30, 0xee, 0xdf, 0x35, 0x5f, 0xbb, 0xa9, 0x88, 0x9e, 0x52, 0x2c, 0x53, 0x93, 0xd3, 0x24, 0x2b, 0x12, 0x88, + 0xda, 0xa8, 0x9a, 0x11, 0x3d, 0x71, 0x31, 0x1f, 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, + 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xec, 0x29, 0xdd, 0x9b, 0x7c, 0x73, 0x40, 0xf7, 0x0e, 0x9e, 0x3c, 0x23, 0x00, + 0x8b, 0x76, 0x79, 0x1e, 0x1e, 0x3c, 0x7b, 0x46, 0xf7, 0xbe, 0xfd, 0x96, 0xee, 0x4d, 0x9e, 0x1c, 0x34, 0xd2, 0x26, + 0xcf, 0xbe, 0xa5, 0x7b, 0xdf, 0x3c, 0x6d, 0xa4, 0x1d, 0x8c, 0x9f, 0xd1, 0xbd, 0xbf, 0x7f, 0x63, 0xd2, 0xfe, 0x06, + 0xd9, 0xbe, 0x3d, 0xc0, 0xff, 0x4c, 0xda, 0xe4, 0xd9, 0x13, 0xba, 0x37, 0x19, 0x43, 0x25, 0xcf, 0x5c, 0x25, 0xe3, + 0x09, 0x7c, 0xfc, 0x04, 0xfe, 0xfb, 0x1b, 0x09, 0x16, 0xb4, 0x92, 0x2c, 0x17, 0xa8, 0x3f, 0x43, 0x11, 0x27, 0xaa, + 0x26, 0x12, 0x1e, 0x62, 0x66, 0xf5, 0x4d, 0x1c, 0x06, 0xc4, 0xa5, 0x43, 0x41, 0x74, 0x6f, 0x3c, 0x7a, 0x46, 0x02, + 0x1f, 0x9e, 0xee, 0xc6, 0x07, 0x19, 0xcb, 0xc5, 0x3c, 0xfb, 0x2a, 0x37, 0xb1, 0x15, 0x3c, 0x00, 0xab, 0x8f, 0x7e, + 0xae, 0x4a, 0xce, 0xb3, 0xaf, 0x2a, 0xb9, 0x9b, 0xeb, 0xf7, 0x16, 0xa0, 0xbc, 0xbf, 0x6a, 0xd9, 0x4d, 0xa1, 0x42, + 0xa7, 0xb5, 0x46, 0x9f, 0x7d, 0xc4, 0xf4, 0xc1, 0xc0, 0xbb, 0x61, 0xff, 0xb4, 0x53, 0x4e, 0xeb, 0x1b, 0x8d, 0x42, + 0x8d, 0xca, 0x43, 0xc2, 0x8e, 0xa0, 0xe8, 0xc1, 0x00, 0x78, 0x02, 0x0f, 0xf7, 0xed, 0xdf, 0x2c, 0xe3, 0x63, 0x47, + 0x19, 0xbf, 0xa0, 0x0c, 0x01, 0x8d, 0x7a, 0x98, 0xdd, 0xf4, 0xb0, 0xd1, 0xad, 0x5e, 0xb2, 0x54, 0x27, 0x53, 0xd3, + 0x33, 0xd8, 0xd7, 0xba, 0x96, 0x7b, 0x46, 0x14, 0x2d, 0x2f, 0xf6, 0x52, 0x3e, 0xab, 0xd8, 0x4f, 0x4b, 0x54, 0x6f, + 0x45, 0x8d, 0x37, 0x32, 0x9b, 0x55, 0xec, 0x7b, 0xf3, 0x06, 0xb8, 0x19, 0xf6, 0xbb, 0x7a, 0xf2, 0x03, 0x67, 0x70, + 0x69, 0xdb, 0xa3, 0x4c, 0x8c, 0x00, 0x2b, 0x20, 0x03, 0x07, 0x1e, 0x00, 0x1d, 0xf4, 0x47, 0x7b, 0xbb, 0x55, 0x29, + 0xcd, 0x3e, 0x5b, 0x18, 0x40, 0xc3, 0xbc, 0x4d, 0x5c, 0xd9, 0xff, 0x6a, 0xc8, 0x4b, 0x50, 0xb8, 0xd5, 0x2c, 0x6f, + 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x65, 0x40, 0xcd, 0x96, 0x8f, 0x36, + 0x5c, 0xa9, 0x27, 0x81, 0x33, 0xb8, 0x90, 0x45, 0xc2, 0x4f, 0xb4, 0xd8, 0x1f, 0xad, 0x1f, 0x7d, 0xdf, 0x1e, 0x0f, + 0xd6, 0xbe, 0xc7, 0x47, 0xfa, 0xb3, 0xc6, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0x17, 0xb5, 0x95, 0x78, 0x94, 0xc0, 0x1b, + 0x98, 0x88, 0x14, 0x06, 0xa9, 0x16, 0x38, 0x06, 0xe5, 0x8d, 0x85, 0x58, 0xaa, 0xae, 0x6e, 0xb0, 0x05, 0x91, 0x21, + 0x78, 0xb8, 0xfd, 0x6b, 0xa9, 0x02, 0x47, 0xf5, 0xfb, 0x5c, 0xfa, 0x6e, 0x4f, 0xc6, 0x8e, 0x1c, 0xa7, 0x7e, 0x2a, + 0x1c, 0xfc, 0x37, 0xa9, 0x6b, 0x63, 0xb9, 0x92, 0x32, 0xcb, 0xb2, 0xb0, 0xa3, 0x50, 0xcb, 0x3d, 0x2a, 0x0f, 0x92, + 0x2f, 0xe4, 0x10, 0xc9, 0x02, 0xa3, 0x50, 0x90, 0xe1, 0x84, 0x8a, 0xd1, 0x5a, 0x94, 0xcb, 0xec, 0xa2, 0x0a, 0x37, + 0x4a, 0xa1, 0xcc, 0x29, 0xfa, 0x76, 0x83, 0x03, 0x09, 0x89, 0xb2, 0xf2, 0x6d, 0xfc, 0x36, 0x44, 0xb0, 0x3a, 0xae, + 0x6d, 0xa1, 0xb8, 0xb7, 0x3f, 0x79, 0xda, 0xc5, 0x1f, 0x19, 0x17, 0x50, 0x17, 0x8b, 0x69, 0x38, 0xb1, 0xb1, 0x6f, + 0xdc, 0x17, 0x56, 0xd3, 0x03, 0x50, 0xdf, 0xa5, 0x12, 0x23, 0xa8, 0xaf, 0x8c, 0x7d, 0x6c, 0x8f, 0x31, 0x39, 0x83, + 0x58, 0xc3, 0x2a, 0x67, 0xa6, 0xfa, 0x46, 0xd8, 0x11, 0x00, 0x37, 0x42, 0x6b, 0x14, 0x04, 0x1e, 0xaf, 0x42, 0x3c, + 0x2f, 0x55, 0xf8, 0xd6, 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, + 0x61, 0xb5, 0x95, 0x65, 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, + 0x5c, 0x0a, 0xcb, 0xa0, 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, + 0x44, 0x23, 0xc4, 0xc3, 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, + 0xa3, 0x04, 0x97, 0xa9, 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, + 0x6a, 0x5f, 0x43, 0x31, 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, + 0x4d, 0xd8, 0xb9, 0x91, 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, + 0xdb, 0x22, 0x73, 0x44, 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, + 0xf1, 0x14, 0x11, 0x01, 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, + 0x81, 0x2c, 0x80, 0xbe, 0xfd, 0x9c, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, + 0x04, 0xbb, 0xba, 0x35, 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, + 0x44, 0x02, 0x32, 0xfb, 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, + 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, + 0x17, 0x7f, 0x5a, 0x75, 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, + 0x6d, 0x29, 0xc9, 0x55, 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, + 0xee, 0x0e, 0xbf, 0xc4, 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, + 0x2a, 0xca, 0x07, 0x13, 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, + 0xac, 0x77, 0xd3, 0x5a, 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, + 0x30, 0x20, 0xda, 0xa5, 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, + 0x9e, 0x01, 0x49, 0x26, 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, + 0xfb, 0x7a, 0xc6, 0x7f, 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, + 0x10, 0x43, 0x54, 0x7b, 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, + 0x43, 0xa3, 0xde, 0xc6, 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, + 0x88, 0x64, 0xbf, 0x3d, 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, + 0xb8, 0x2c, 0x22, 0xcb, 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, + 0xbf, 0x5e, 0xc9, 0x02, 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, + 0xe3, 0xce, 0x9e, 0x80, 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, + 0xb7, 0x80, 0x49, 0xc0, 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, + 0xd6, 0xfe, 0xd5, 0x5d, 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, + 0xa4, 0xb0, 0xe5, 0x31, 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, + 0x0d, 0xee, 0x47, 0x15, 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, + 0x72, 0xbc, 0xed, 0x76, 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, + 0x59, 0xef, 0x25, 0x60, 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, + 0x4b, 0xb2, 0x1f, 0xa6, 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, + 0x41, 0x6f, 0xe9, 0x0d, 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, + 0xfb, 0xfd, 0xde, 0x99, 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, + 0x9b, 0xf0, 0x2c, 0x0f, 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, + 0x93, 0x23, 0xd0, 0x9b, 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, + 0xde, 0xb5, 0x27, 0x63, 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, + 0x7f, 0xb3, 0xf0, 0x86, 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, + 0xd2, 0x53, 0x76, 0x45, 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0xa7, 0x38, 0x0c, 0xe3, 0x61, 0x41, + 0xf6, 0x25, 0xbd, 0xdb, 0x9f, 0xf0, 0x27, 0x64, 0x16, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, + 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0x4e, 0xe8, 0x0d, 0x2b, 0xe8, 0x29, 0x8b, 0x49, 0x74, 0x0d, 0xad, 0x38, 0x9f, + 0x15, 0xd1, 0x0d, 0x3d, 0x65, 0x67, 0xb3, 0x38, 0x3a, 0xa5, 0x27, 0x2c, 0x1f, 0x4e, 0x20, 0xef, 0xe9, 0xf0, 0x86, + 0xec, 0x9f, 0x90, 0x28, 0x3c, 0xd1, 0xbf, 0xef, 0xe8, 0x25, 0x0f, 0x4f, 0xa8, 0x57, 0xcd, 0x09, 0x31, 0xd5, 0x37, + 0x6a, 0x3f, 0x21, 0x91, 0x3f, 0x98, 0x27, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, + 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, 0x06, 0x74, 0xf6, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, + 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, 0xd7, 0xc1, 0x6b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0xeb, 0x7e, 0x1f, 0x22, + 0xdd, 0x17, 0x33, 0x13, 0xdb, 0xcd, 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0xd7, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, + 0xbc, 0x19, 0xbc, 0x7e, 0x7c, 0x47, 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x1b, 0x9a, 0x01, 0xe0, 0xd7, 0xeb, + 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, 0x7d, 0x7d, 0x78, 0x32, 0x1d, 0x0c, 0x5e, 0x9b, 0x6d, 0xf2, 0x96, 0xdd, 0x53, + 0x0a, 0xac, 0xbf, 0xb3, 0x7e, 0xff, 0xed, 0x51, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xd6, 0x45, + 0x55, 0x3b, 0xeb, 0xf7, 0xd7, 0xfd, 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9c, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x8e, 0x22, + 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, 0xac, 0xda, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, + 0xec, 0x9d, 0x6d, 0xb7, 0xa7, 0x8c, 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, + 0xcc, 0xe6, 0x66, 0x69, 0x0f, 0x81, 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0x2f, 0x00, + 0x42, 0x24, 0x59, 0xc8, 0x67, 0x38, 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xbb, + 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, 0xd1, 0xdf, 0x9e, 0x3d, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, + 0x61, 0x17, 0x6b, 0xb5, 0x0f, 0x46, 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0xbe, 0x98, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, + 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, 0x18, 0x4c, 0x2e, 0xd2, 0xcf, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, + 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, 0xdb, 0x6e, 0x2b, 0xff, 0x12, 0xf8, 0x16, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, + 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, + 0xba, 0xdc, 0xe3, 0xea, 0x5f, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, + 0x0c, 0xb7, 0x56, 0x22, 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, + 0x86, 0x07, 0xc9, 0xc4, 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, + 0x24, 0xd3, 0xe4, 0x10, 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, + 0x8e, 0x49, 0xad, 0xef, 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, + 0x78, 0x34, 0x7e, 0x46, 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, + 0x9b, 0x57, 0x3a, 0x36, 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, + 0xea, 0x23, 0x08, 0xb3, 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, + 0xa3, 0x52, 0xa6, 0xba, 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, + 0x10, 0xc0, 0xa3, 0x11, 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, + 0xde, 0x83, 0x30, 0x29, 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, + 0x57, 0x10, 0x27, 0x6c, 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, + 0x25, 0xf7, 0x26, 0xe3, 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, + 0x57, 0xdc, 0x1b, 0x17, 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, + 0x76, 0x3f, 0x31, 0x2b, 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xf6, 0xf2, 0xec, 0xf5, + 0xdb, 0x57, 0xaf, 0xdf, 0xbe, 0xfe, 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, + 0x6a, 0xf1, 0x85, 0xb3, 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, + 0x20, 0xa3, 0x51, 0x21, 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, + 0xdb, 0xd1, 0xd6, 0xac, 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, + 0xc8, 0x75, 0xf0, 0xbe, 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, + 0x13, 0x73, 0x6d, 0x74, 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, + 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, + 0xc2, 0xfc, 0x0c, 0x1b, 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, + 0xce, 0x17, 0xdf, 0x42, 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, + 0x31, 0x1e, 0x77, 0xf7, 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, + 0xbe, 0x5d, 0x24, 0xce, 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, + 0x35, 0xe7, 0x6d, 0x42, 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, + 0x17, 0x43, 0x9a, 0x72, 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, + 0xd7, 0xd9, 0xe6, 0x33, 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, + 0xc4, 0x40, 0x74, 0x01, 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, + 0x31, 0x8b, 0xad, 0x25, 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x84, 0x1d, 0x7d, + 0xf7, 0xb6, 0x01, 0x10, 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, + 0x2b, 0xb4, 0xec, 0x95, 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, + 0xa6, 0x12, 0xd5, 0x23, 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, + 0xee, 0xff, 0xe6, 0x42, 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, + 0x5d, 0xa6, 0x97, 0x5d, 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, + 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, + 0x7c, 0x89, 0x5f, 0x29, 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, + 0xfe, 0x17, 0x18, 0x0d, 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, + 0xeb, 0x67, 0x35, 0xcc, 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, + 0x29, 0x11, 0x83, 0x41, 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, + 0x1a, 0x5b, 0x92, 0x6c, 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, + 0x32, 0xd3, 0xc2, 0xa2, 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, + 0x4d, 0xac, 0xf1, 0x8b, 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, + 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, + 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, + 0xcc, 0xaf, 0x24, 0x19, 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, + 0xdc, 0x18, 0xd6, 0xf4, 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, + 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, + 0x60, 0x1c, 0xa5, 0x83, 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, + 0x0b, 0x68, 0xda, 0x97, 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, + 0x0b, 0xd7, 0xc2, 0x8b, 0xdd, 0x16, 0x0a, 0x4d, 0xb6, 0x0b, 0xf9, 0xff, 0xe3, 0x86, 0x71, 0xdf, 0x5d, 0xc2, 0x2c, + 0xae, 0xeb, 0x6c, 0xb4, 0x2a, 0x64, 0x25, 0xe1, 0x36, 0xa1, 0x44, 0x61, 0xa3, 0x78, 0xb5, 0xca, 0xb5, 0x8b, 0xd8, + 0xbc, 0xa2, 0x00, 0xee, 0x02, 0x71, 0x8a, 0x81, 0x85, 0x36, 0x06, 0x72, 0x9f, 0x78, 0x21, 0x99, 0x55, 0xfb, 0x98, + 0x7b, 0xe4, 0x9f, 0x21, 0x18, 0xa3, 0x8a, 0xa3, 0xf1, 0x4c, 0x61, 0x5d, 0x7c, 0x4e, 0xde, 0xfb, 0x6f, 0x1c, 0x45, + 0xf6, 0x68, 0x06, 0x3d, 0x41, 0xe4, 0x3c, 0xe2, 0xec, 0xc9, 0xe4, 0x65, 0xe0, 0x7e, 0x06, 0x2b, 0xfd, 0x75, 0xb7, + 0x19, 0x6b, 0xdb, 0xa3, 0x7b, 0x61, 0x84, 0xa2, 0x9f, 0xf0, 0x9d, 0xa9, 0x17, 0x70, 0x09, 0xd5, 0xc0, 0xae, 0x2f, + 0x2f, 0x79, 0x09, 0x20, 0x42, 0x99, 0xe8, 0xf7, 0x7b, 0x7f, 0x1a, 0x68, 0xd2, 0x92, 0x17, 0x6f, 0x32, 0x61, 0x9d, + 0x71, 0xa0, 0xa9, 0x40, 0xfd, 0x3f, 0x56, 0xf6, 0x99, 0x8e, 0xc9, 0xcc, 0x7f, 0x1c, 0x4e, 0x48, 0xd4, 0x7c, 0x4d, + 0x3e, 0x73, 0x9a, 0x7e, 0xe6, 0x8a, 0xf6, 0x1f, 0xc8, 0xcc, 0x0d, 0x87, 0x0c, 0xf5, 0x97, 0x8e, 0x79, 0x32, 0x7a, + 0x9d, 0x98, 0x1d, 0x09, 0x56, 0xcd, 0x20, 0x0a, 0x7b, 0x01, 0x0f, 0xea, 0x5a, 0x16, 0x4f, 0x61, 0xf6, 0x41, 0x8d, + 0x28, 0x0e, 0xd9, 0x78, 0x16, 0xca, 0x70, 0x02, 0xf6, 0xbd, 0x93, 0x31, 0xdc, 0x07, 0x64, 0xf8, 0xb1, 0x0a, 0xb1, + 0x73, 0x90, 0xf6, 0xb1, 0x42, 0xc5, 0x04, 0x40, 0x04, 0x42, 0xde, 0x7e, 0x5f, 0xaa, 0x24, 0x7c, 0x5d, 0x62, 0x4a, + 0xa1, 0x3e, 0xf8, 0x4f, 0xa4, 0xea, 0x8e, 0xe9, 0x57, 0xeb, 0xc7, 0x9f, 0x09, 0xc5, 0xa7, 0xbb, 0x94, 0xf8, 0x16, + 0x82, 0x3b, 0x4b, 0xd0, 0x41, 0x54, 0x68, 0xc6, 0xf6, 0x30, 0xbf, 0x2b, 0xee, 0xe7, 0x77, 0xc5, 0xff, 0x3b, 0x7e, + 0x57, 0x3c, 0xc4, 0x18, 0x56, 0x16, 0x1a, 0x7e, 0x16, 0x8c, 0x83, 0xe8, 0x3f, 0xe7, 0x13, 0xef, 0xe5, 0xa9, 0xaf, + 0x32, 0x31, 0xbd, 0x87, 0x69, 0xf6, 0x09, 0x0a, 0xc2, 0x2a, 0xee, 0xd2, 0x93, 0x75, 0x65, 0x6f, 0xad, 0x64, 0x88, + 0x79, 0x1e, 0x60, 0x8d, 0xc2, 0xca, 0x03, 0xba, 0x47, 0xd5, 0x06, 0x71, 0x22, 0x78, 0x18, 0x33, 0x2b, 0x7d, 0xdf, + 0x6e, 0x8d, 0x0a, 0xf3, 0x41, 0x2e, 0x0a, 0xb2, 0x9b, 0x8f, 0x67, 0xe3, 0x28, 0xc4, 0x06, 0xfc, 0xc7, 0x8c, 0x55, + 0x43, 0x36, 0xdf, 0xc9, 0x48, 0xed, 0x98, 0x3c, 0x4d, 0x76, 0x49, 0xef, 0x80, 0x77, 0xc8, 0xcf, 0xeb, 0x8f, 0x61, + 0x21, 0x0d, 0xbf, 0x25, 0x2f, 0xe3, 0x22, 0xab, 0x96, 0x57, 0x59, 0x82, 0x4c, 0x17, 0xbc, 0xf8, 0x62, 0xa6, 0xcb, + 0xfb, 0x58, 0x1f, 0x30, 0x9e, 0x52, 0xbc, 0x6e, 0x88, 0xd2, 0xd7, 0x2d, 0xcf, 0x0a, 0x75, 0x79, 0x52, 0x31, 0xdb, + 0xb3, 0x12, 0x9c, 0x4e, 0xc1, 0x04, 0x5f, 0xff, 0x74, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x0b, 0xb9, 0x32, + 0x58, 0x4e, 0x16, 0xba, 0x13, 0x30, 0x43, 0xa5, 0xc0, 0x0b, 0x14, 0xfc, 0x45, 0x03, 0x23, 0xfa, 0xca, 0xfd, 0x26, + 0x03, 0x83, 0x74, 0x69, 0x4e, 0x84, 0xb1, 0xe3, 0x76, 0x8a, 0xb4, 0x15, 0xe5, 0x8c, 0xb3, 0xf7, 0xea, 0x4a, 0x01, + 0x06, 0x78, 0x9b, 0x9b, 0xe8, 0x3c, 0x41, 0xaf, 0x05, 0xa5, 0xf3, 0x06, 0xee, 0x66, 0x19, 0x19, 0xe1, 0xe2, 0xe3, + 0xca, 0x63, 0xc1, 0x3d, 0xfb, 0x85, 0x58, 0x1a, 0xcd, 0x34, 0x18, 0xb3, 0x79, 0xc1, 0x02, 0x85, 0x0a, 0x14, 0x58, + 0xce, 0xb4, 0xa5, 0x69, 0x35, 0xe4, 0xfb, 0x07, 0x68, 0x6d, 0x5a, 0x0d, 0xf8, 0xfe, 0x41, 0x1d, 0x65, 0x87, 0x90, + 0xe5, 0xc8, 0xcf, 0xa0, 0x5e, 0xd7, 0x91, 0x49, 0x31, 0xd9, 0xfd, 0xfa, 0x52, 0x7f, 0x54, 0x37, 0xe0, 0xfa, 0x01, + 0x08, 0x60, 0x03, 0x70, 0x08, 0x54, 0x83, 0xa5, 0x11, 0xc1, 0xa2, 0x4c, 0xa1, 0x7d, 0x0d, 0xbd, 0x37, 0x1a, 0xfe, + 0x0b, 0xdc, 0x45, 0xe4, 0xca, 0xff, 0x04, 0x81, 0xbf, 0xa2, 0x4c, 0x2b, 0x53, 0xfc, 0x4f, 0xb4, 0x7a, 0x85, 0x72, + 0xd6, 0xb4, 0xe6, 0x83, 0x68, 0x4d, 0x84, 0x6a, 0xc6, 0x10, 0xfc, 0x5b, 0x59, 0xa6, 0x2d, 0x55, 0x95, 0xfa, 0xd0, + 0x78, 0xad, 0x15, 0xce, 0xf2, 0x71, 0xe4, 0xbd, 0xc6, 0xd0, 0xb1, 0x89, 0xb3, 0x94, 0x53, 0xa9, 0xb3, 0x4f, 0xfb, + 0x32, 0x72, 0x80, 0xd3, 0x09, 0x1b, 0x4f, 0x93, 0x43, 0x39, 0x4d, 0x1c, 0x64, 0x7e, 0xce, 0x30, 0xb2, 0xaa, 0x01, + 0x61, 0x51, 0x36, 0x94, 0xb6, 0x00, 0x93, 0x9c, 0x10, 0x32, 0xc5, 0x50, 0x14, 0xf9, 0x48, 0xf7, 0xc3, 0x7a, 0xb3, + 0xba, 0x2f, 0xde, 0x69, 0x80, 0xd3, 0x30, 0x81, 0x40, 0xe0, 0x45, 0x7c, 0x93, 0x89, 0x4b, 0xf0, 0x18, 0x1e, 0xc0, + 0x97, 0xe0, 0x26, 0x97, 0xb2, 0xdf, 0xab, 0x30, 0xc7, 0xb5, 0x05, 0x0c, 0x1a, 0xac, 0x1e, 0x44, 0x87, 0x4b, 0x69, + 0xb3, 0xab, 0x00, 0xb1, 0x31, 0x85, 0x58, 0x16, 0x6c, 0x6d, 0xd9, 0xb3, 0xef, 0x55, 0xd3, 0xd0, 0x3a, 0xe1, 0x58, + 0x5c, 0xe6, 0x10, 0x45, 0x65, 0x10, 0x83, 0x3b, 0x92, 0xc7, 0xe7, 0x3d, 0x12, 0xe1, 0x05, 0x01, 0xb7, 0xb2, 0x58, + 0x86, 0x2b, 0xba, 0x1c, 0xdd, 0xd2, 0xf5, 0xe8, 0x86, 0x8e, 0xe9, 0xe4, 0xef, 0x63, 0xb0, 0xc8, 0xd6, 0xa9, 0x77, + 0x74, 0x3d, 0x5a, 0xd2, 0x6f, 0xc7, 0xf4, 0xe0, 0x6f, 0x60, 0xc2, 0x87, 0x87, 0x09, 0xbd, 0x00, 0xc7, 0x2e, 0x52, + 0xa3, 0xa7, 0xa6, 0x6f, 0x70, 0x58, 0x8d, 0xf2, 0x21, 0x1f, 0xe5, 0x94, 0x8f, 0x8a, 0x61, 0x35, 0x02, 0x4f, 0xc7, + 0x6a, 0xc8, 0x47, 0x15, 0xe5, 0xa3, 0xf3, 0x61, 0x35, 0x3a, 0x27, 0xcd, 0xa6, 0xbf, 0xae, 0xf8, 0x55, 0xc9, 0x52, + 0xd8, 0x16, 0xb0, 0x7c, 0x3d, 0xaf, 0xa8, 0xd4, 0x5f, 0xd5, 0xe6, 0x64, 0xb6, 0x9c, 0xbd, 0xbd, 0xee, 0x72, 0x62, + 0xf1, 0xb8, 0x6d, 0x3a, 0x5c, 0x7d, 0x39, 0x51, 0x27, 0xbd, 0x42, 0x7e, 0x18, 0x4f, 0x85, 0x3a, 0x87, 0xc0, 0x4c, + 0x62, 0x16, 0xc6, 0x0c, 0x9b, 0xa9, 0xd3, 0x40, 0x81, 0x93, 0x8d, 0x3c, 0x17, 0xc5, 0x6c, 0x94, 0x53, 0x78, 0x1f, + 0x13, 0x12, 0x09, 0x38, 0xab, 0x8e, 0xaa, 0x51, 0x01, 0x31, 0x47, 0x58, 0x88, 0x8f, 0xd0, 0x2f, 0xf5, 0x91, 0x87, + 0x04, 0x9e, 0x61, 0x5f, 0x8b, 0x41, 0x0c, 0x47, 0xbc, 0xad, 0xac, 0x9a, 0x85, 0x09, 0x54, 0x56, 0x0d, 0x4b, 0x53, + 0x59, 0x41, 0xb3, 0x51, 0xe5, 0x57, 0x56, 0xe1, 0x18, 0x25, 0x84, 0x44, 0xa5, 0xae, 0x0c, 0xd4, 0x27, 0x09, 0x0b, + 0x4b, 0x5d, 0xd9, 0xb9, 0xfa, 0xe8, 0xdc, 0xaf, 0xec, 0x1c, 0x5c, 0x48, 0x07, 0x89, 0x7f, 0x95, 0xca, 0xd3, 0xf6, + 0x75, 0xb0, 0xb1, 0xaa, 0xe8, 0x86, 0xdf, 0x56, 0x45, 0x1c, 0x95, 0xd4, 0xc5, 0x80, 0xc6, 0x85, 0x11, 0x49, 0xaa, + 0xd7, 0x28, 0xf8, 0x43, 0x82, 0xa8, 0x34, 0x06, 0xaf, 0xce, 0xa4, 0x6b, 0xa5, 0x56, 0x54, 0x0c, 0xca, 0x41, 0x01, + 0xf7, 0xa7, 0xbc, 0xb5, 0x90, 0xbe, 0x87, 0x88, 0xca, 0x50, 0xde, 0xe0, 0x1f, 0x18, 0x3c, 0x99, 0xad, 0xd2, 0x30, + 0x19, 0xdd, 0xd1, 0x78, 0xb4, 0x44, 0x38, 0x18, 0xb6, 0x4e, 0x15, 0xde, 0xfa, 0x05, 0xa4, 0xdf, 0xd2, 0x78, 0x74, + 0x43, 0x53, 0x6b, 0x73, 0x6a, 0xa0, 0xae, 0x7a, 0x63, 0x7a, 0x1b, 0xc1, 0xeb, 0xbb, 0x68, 0x49, 0x61, 0x2b, 0x1d, + 0xe7, 0xd9, 0xa5, 0x88, 0x52, 0x8a, 0x08, 0x84, 0x6b, 0x44, 0x0e, 0x5c, 0x6a, 0xb4, 0xc1, 0xf5, 0x00, 0xca, 0xd0, + 0x70, 0x81, 0xcb, 0x41, 0x3c, 0x5a, 0x7a, 0x64, 0x6a, 0xa9, 0x2f, 0xb2, 0x08, 0x1f, 0xed, 0x6c, 0xb4, 0x14, 0xcf, + 0x88, 0x85, 0x71, 0x05, 0x43, 0xa8, 0x0b, 0x2b, 0x4d, 0x41, 0xd2, 0x05, 0x8e, 0xec, 0x85, 0x45, 0x15, 0x6e, 0xc0, + 0xb4, 0xe8, 0x0e, 0xcc, 0xa3, 0x40, 0xe1, 0xe0, 0x12, 0xa4, 0x9f, 0x50, 0xb6, 0x73, 0x94, 0x26, 0x87, 0x37, 0x41, + 0xe9, 0xce, 0x04, 0x21, 0xed, 0xea, 0x26, 0x5b, 0xd2, 0x37, 0xd8, 0xde, 0xa1, 0x53, 0x51, 0x41, 0xf5, 0xb9, 0x05, + 0x93, 0x25, 0x1b, 0x84, 0x2d, 0x61, 0x7a, 0xa6, 0xd7, 0x80, 0x3d, 0xbd, 0x7f, 0xb0, 0x33, 0xdf, 0xc5, 0xec, 0xd3, + 0x7e, 0x19, 0x8d, 0x95, 0x05, 0x6f, 0x6e, 0x89, 0xdd, 0x92, 0x8d, 0xa7, 0xcb, 0xc3, 0x72, 0xba, 0x44, 0x62, 0x67, + 0xe8, 0x16, 0xe3, 0xf3, 0xe5, 0x82, 0x26, 0x78, 0xb6, 0xb1, 0x6a, 0xbe, 0x34, 0x68, 0x29, 0x29, 0xc3, 0xf5, 0xb6, + 0x44, 0xff, 0x7f, 0x75, 0xf1, 0x4b, 0x01, 0x5e, 0x82, 0xb1, 0x00, 0x10, 0xee, 0xc1, 0xb4, 0x20, 0xb5, 0x51, 0x36, + 0x96, 0x69, 0x98, 0xe2, 0x22, 0x30, 0x29, 0xfd, 0x7e, 0x98, 0xb3, 0x94, 0x78, 0xd0, 0xa1, 0xee, 0xd4, 0x4e, 0x7d, + 0x21, 0x08, 0xf0, 0x48, 0xea, 0x1c, 0x9b, 0xfc, 0x7d, 0x3c, 0x0b, 0xd4, 0x40, 0x04, 0x51, 0x76, 0x88, 0x8f, 0x18, + 0xb8, 0x28, 0xd2, 0x71, 0x3b, 0x5d, 0x11, 0x17, 0xbb, 0xc7, 0x2c, 0xc4, 0x49, 0xc2, 0x5c, 0xb3, 0x6c, 0xc8, 0xaa, + 0x08, 0x13, 0x74, 0x61, 0x60, 0x96, 0x37, 0x64, 0xd5, 0xfe, 0x01, 0x44, 0x6a, 0xb5, 0x65, 0xac, 0xba, 0xca, 0xf8, + 0x16, 0x80, 0xac, 0x19, 0x63, 0x07, 0x7f, 0x1b, 0xcf, 0xd4, 0x37, 0x51, 0xc8, 0x8f, 0x0e, 0xfe, 0x06, 0xc9, 0x87, + 0xdf, 0x22, 0x33, 0x07, 0xc9, 0x8d, 0x82, 0x2e, 0x9b, 0xb3, 0xae, 0xa1, 0x34, 0x71, 0xed, 0x95, 0x7a, 0xed, 0x49, + 0xb3, 0xf6, 0x0a, 0x74, 0xa7, 0x36, 0xbc, 0x87, 0xb2, 0x9d, 0x05, 0x13, 0x74, 0x34, 0xbb, 0x03, 0x1d, 0xbc, 0x53, + 0x04, 0xbd, 0x4c, 0x42, 0xe3, 0x11, 0xaa, 0x8c, 0x7a, 0x61, 0x47, 0x76, 0xb3, 0x2e, 0x99, 0x67, 0xc0, 0x1c, 0xdb, + 0x73, 0x48, 0x0c, 0x73, 0x75, 0x50, 0xa7, 0xac, 0x1c, 0xe6, 0x78, 0x00, 0xaf, 0x99, 0x1c, 0x8a, 0x41, 0xae, 0x51, + 0xbe, 0x2f, 0x58, 0x31, 0x2c, 0x07, 0xb9, 0xe6, 0x66, 0xa6, 0xcd, 0xd8, 0xb4, 0x89, 0x0e, 0xcf, 0xbc, 0x62, 0x47, + 0xab, 0x1e, 0xf0, 0xb1, 0xe0, 0xc9, 0xec, 0x7b, 0x3e, 0xbe, 0x01, 0x4e, 0x66, 0x73, 0x1b, 0x2d, 0xe9, 0x5d, 0x94, + 0xd2, 0x9b, 0x68, 0x4d, 0x97, 0xd1, 0x85, 0x31, 0x31, 0x4e, 0x6a, 0x38, 0x07, 0xa0, 0x55, 0x00, 0x89, 0xa7, 0x7e, + 0xbd, 0xe7, 0x49, 0x15, 0x2e, 0x69, 0x0a, 0x6e, 0xc3, 0xbe, 0x7d, 0xe6, 0x95, 0x2f, 0x91, 0xda, 0x20, 0xc6, 0x9a, + 0x35, 0x54, 0xdc, 0x78, 0xeb, 0x3e, 0x12, 0x35, 0xec, 0x5c, 0x17, 0x9b, 0xa8, 0x1a, 0x4e, 0xa6, 0x25, 0x20, 0xb6, + 0x96, 0xc3, 0xa1, 0x3b, 0x42, 0x76, 0x8f, 0x1f, 0x1d, 0xe8, 0xb9, 0x27, 0x2d, 0xb6, 0x6d, 0xcb, 0x1f, 0x18, 0xc2, + 0x94, 0x7e, 0xfe, 0xc8, 0x07, 0xc4, 0x8a, 0x4b, 0x38, 0x1b, 0x81, 0x3a, 0x5a, 0xa1, 0xd3, 0xef, 0x55, 0x58, 0xe8, + 0x03, 0x7c, 0x73, 0x1b, 0x25, 0xf4, 0x2e, 0xca, 0x3d, 0xb2, 0xb6, 0xac, 0x99, 0x9c, 0x9e, 0x65, 0x21, 0x6f, 0x1f, + 0xe8, 0xe5, 0x02, 0x40, 0xb4, 0x06, 0xb1, 0x2f, 0x75, 0x3d, 0x00, 0xa7, 0x21, 0x34, 0x09, 0x8d, 0xe0, 0xaa, 0x82, + 0x30, 0x02, 0xae, 0x24, 0xfc, 0x0d, 0x26, 0x2a, 0xf0, 0x05, 0xb8, 0xc8, 0xa4, 0x69, 0xce, 0x83, 0xda, 0x1f, 0xc9, + 0xd3, 0xa2, 0xed, 0xed, 0x0a, 0xa3, 0x09, 0xc6, 0x9e, 0x68, 0x9f, 0x47, 0xca, 0x51, 0x5c, 0x24, 0x61, 0x36, 0xba, + 0x55, 0xe7, 0x39, 0xcd, 0x46, 0x77, 0xfa, 0x57, 0x45, 0xc7, 0xf4, 0x3b, 0x1d, 0xd0, 0x46, 0x49, 0xdf, 0x3a, 0xce, + 0x06, 0xb4, 0x5e, 0x2c, 0x8d, 0xff, 0xb5, 0x1c, 0xdd, 0x52, 0x39, 0xba, 0xf3, 0x2d, 0xa9, 0x26, 0xd3, 0xe2, 0x50, + 0xa0, 0x21, 0x55, 0xe7, 0xf7, 0x05, 0xf0, 0x73, 0xa5, 0xf1, 0x9d, 0x36, 0xdf, 0x7b, 0xed, 0x3f, 0xef, 0xe4, 0x09, + 0x14, 0x4b, 0x54, 0xb0, 0x6a, 0x04, 0x76, 0xec, 0xeb, 0x3c, 0x2e, 0xcc, 0x28, 0xc5, 0xd4, 0x9a, 0xf4, 0x63, 0xe0, + 0x8a, 0x69, 0xaf, 0x00, 0x57, 0xcb, 0xed, 0x56, 0xc5, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, + 0x36, 0xdc, 0x03, 0x62, 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, + 0x9d, 0xc7, 0x43, 0x9f, 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, + 0x3c, 0xd7, 0x5f, 0x69, 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, + 0x6e, 0x94, 0x79, 0x24, 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, + 0x3d, 0xf2, 0xa0, 0x9c, 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, + 0x12, 0x73, 0x27, 0x51, 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, + 0x13, 0x57, 0xe1, 0x5a, 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, + 0x1a, 0x56, 0x9a, 0x80, 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, + 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, + 0x02, 0x33, 0x57, 0x72, 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, + 0x5a, 0x62, 0x42, 0xb4, 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, + 0xda, 0x55, 0x20, 0xb4, 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, + 0xb2, 0x69, 0xc8, 0x5c, 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, + 0x2d, 0x3f, 0x82, 0x17, 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, + 0xb9, 0xdd, 0x96, 0x68, 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, + 0x2b, 0xd0, 0xf7, 0xf8, 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, + 0xfc, 0x4a, 0x76, 0xd6, 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, + 0x2d, 0x85, 0x05, 0xc7, 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, + 0xb2, 0x33, 0xd7, 0x07, 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, + 0xe1, 0xce, 0x3c, 0x6a, 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, + 0xf7, 0x7d, 0x58, 0x3d, 0xe6, 0x83, 0x5f, 0x70, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, + 0x53, 0xbe, 0xd0, 0xad, 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, + 0x18, 0xd7, 0xc0, 0x6d, 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, + 0x31, 0xf7, 0xa5, 0x6b, 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, + 0xe7, 0x91, 0xf9, 0x62, 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, + 0x43, 0x2f, 0x03, 0x17, 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, + 0xa8, 0x10, 0xac, 0xeb, 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x63, 0x20, + 0x9c, 0x5b, 0xa2, 0x67, 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, + 0x5f, 0xf0, 0x5a, 0x0a, 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, + 0x8a, 0xde, 0xbf, 0xe6, 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, + 0x4a, 0x50, 0xc9, 0x5a, 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, + 0x7c, 0x8e, 0x7e, 0x98, 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, + 0xc6, 0xf0, 0x60, 0x36, 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, + 0x7d, 0x89, 0x36, 0xaf, 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, + 0xab, 0x96, 0x8a, 0x06, 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, + 0x59, 0xda, 0xa6, 0xe8, 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, + 0x51, 0x6a, 0x37, 0x48, 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, + 0x1d, 0x47, 0x43, 0xbf, 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, + 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, + 0x4d, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, + 0xe9, 0xb9, 0x6e, 0xe7, 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, + 0xf5, 0x98, 0x15, 0xc3, 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, + 0xb4, 0x0b, 0xa4, 0x6d, 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, + 0xd8, 0x88, 0x7a, 0x7c, 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, + 0x5a, 0xb5, 0xb9, 0xfb, 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, + 0x5a, 0xb0, 0x9c, 0x75, 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, + 0x92, 0x67, 0x9a, 0xfe, 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, + 0x12, 0x57, 0xbe, 0xc2, 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, + 0x6e, 0x92, 0x1b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, + 0x28, 0x73, 0x13, 0x73, 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, + 0x3a, 0xd1, 0x5c, 0x86, 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, + 0xdc, 0xcc, 0x52, 0xb3, 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, + 0x2c, 0x0d, 0xd7, 0x28, 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, + 0x90, 0x8d, 0xd2, 0x38, 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, + 0x15, 0xdd, 0x96, 0x98, 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0xc5, 0xd0, 0xde, 0x1d, + 0x81, 0x51, 0xe5, 0x04, 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, + 0x24, 0x10, 0x18, 0x15, 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, + 0xb7, 0x88, 0x8e, 0xe9, 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, + 0x9e, 0xba, 0x14, 0xfd, 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, + 0xb2, 0x2a, 0x07, 0xed, 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, + 0x6f, 0xc4, 0xa8, 0xbd, 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, + 0x9f, 0x39, 0xb2, 0x33, 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, + 0xda, 0xcf, 0x9d, 0xe9, 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, + 0x35, 0xd5, 0xd1, 0x01, 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, + 0x53, 0x5b, 0x55, 0xc1, 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, + 0xa7, 0xa6, 0x3f, 0x68, 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, + 0x57, 0x95, 0x0f, 0xa0, 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, + 0x58, 0x4f, 0xe4, 0x79, 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, + 0x68, 0x2e, 0xa3, 0x09, 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, + 0x15, 0xdf, 0xc9, 0xf4, 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, + 0x73, 0xf0, 0xb4, 0xa6, 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, + 0xf9, 0x47, 0x97, 0x69, 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, + 0xa2, 0x0e, 0xbe, 0x39, 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, + 0x71, 0x7f, 0xfb, 0xfb, 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, + 0x7f, 0xab, 0x6b, 0xfa, 0x2b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, + 0x06, 0x90, 0x4b, 0xab, 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, + 0xe3, 0xac, 0x02, 0x38, 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x07, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, + 0x46, 0x45, 0x06, 0x3a, 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, + 0xc1, 0x44, 0x58, 0x10, 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, + 0x10, 0x44, 0x77, 0x91, 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, + 0x10, 0x14, 0xff, 0x86, 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, + 0x82, 0x06, 0xba, 0xed, 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, + 0xf5, 0x5f, 0x0d, 0xeb, 0xe8, 0xc2, 0x8f, 0xfe, 0x6a, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, + 0x0c, 0xa4, 0x8b, 0xe3, 0x76, 0x9c, 0xcd, 0x7f, 0x9d, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, + 0xd2, 0xce, 0x07, 0x6f, 0x8e, 0x7f, 0x3f, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, + 0x0a, 0xee, 0xae, 0xe6, 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, + 0x40, 0x0e, 0x99, 0x85, 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, + 0x6f, 0xb9, 0x0d, 0xb2, 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, + 0xce, 0xe6, 0xc5, 0xc2, 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, + 0xa6, 0x51, 0x85, 0x6b, 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, + 0x03, 0x3a, 0x98, 0x50, 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x75, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, + 0x54, 0x5e, 0xc9, 0x6b, 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, + 0x93, 0x4b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, + 0x7c, 0x2e, 0x16, 0x11, 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, + 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, + 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, + 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, + 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, + 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, + 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, + 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, + 0xb3, 0x5c, 0x1d, 0x7a, 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, + 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, 0x42, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, + 0x91, 0x9e, 0x67, 0x9f, 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, + 0x3f, 0x57, 0x1c, 0xaf, 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, + 0x97, 0x3c, 0xac, 0x46, 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, + 0xff, 0x0a, 0x99, 0x8c, 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, + 0x93, 0x66, 0xa1, 0x4c, 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, + 0xf7, 0xd0, 0xe1, 0xff, 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, + 0x7d, 0x33, 0xf1, 0x0b, 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, + 0xc3, 0x76, 0x8b, 0x0b, 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, + 0x67, 0x6a, 0x98, 0x93, 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, + 0xd0, 0x5e, 0xec, 0x67, 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, + 0x1e, 0x83, 0xf7, 0x06, 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, + 0xb7, 0x95, 0xf1, 0xb7, 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, + 0x5a, 0x60, 0xf8, 0xec, 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, + 0xac, 0x01, 0x88, 0xe4, 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, + 0xeb, 0x60, 0xe2, 0x4c, 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, + 0xa9, 0x42, 0xa9, 0x36, 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, + 0x67, 0xf7, 0xb9, 0xed, 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, + 0x15, 0x63, 0x8c, 0xde, 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, + 0xc5, 0xf5, 0xf2, 0x4b, 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, + 0x5d, 0x69, 0x64, 0x20, 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, + 0x6d, 0x09, 0x1d, 0xb2, 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, + 0x0b, 0x67, 0x59, 0x1c, 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, + 0x81, 0xdd, 0xc9, 0xe9, 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, + 0x42, 0x9b, 0xeb, 0xfa, 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, + 0xfa, 0x40, 0x39, 0x96, 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, + 0xb1, 0x00, 0x58, 0xe8, 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, + 0xee, 0x8a, 0x65, 0x58, 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, + 0x6a, 0x0c, 0x20, 0x72, 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, + 0x5e, 0x4f, 0x4a, 0x02, 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, + 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, + 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, + 0xfb, 0xbf, 0x99, 0x2c, 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, + 0x82, 0xc0, 0x70, 0xc3, 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, + 0x1a, 0x33, 0x3a, 0x78, 0x06, 0xa0, 0xb0, 0x10, 0x10, 0x7d, 0x0c, 0x32, 0x5a, 0x01, 0xbf, 0x85, 0xfa, 0xdd, 0x3a, + 0xf1, 0x7d, 0xe8, 0x57, 0x41, 0x2f, 0x62, 0x60, 0x38, 0xa2, 0xc9, 0x7e, 0xc8, 0x07, 0x93, 0x01, 0x68, 0x4b, 0xbc, + 0xdd, 0xd7, 0xd2, 0x8a, 0x9b, 0xd3, 0xa5, 0xd3, 0xfd, 0x93, 0x36, 0x41, 0x12, 0xa9, 0x64, 0xa5, 0x22, 0x06, 0x10, + 0xca, 0x52, 0x6d, 0x93, 0x25, 0x58, 0x56, 0x98, 0x25, 0xcd, 0x0d, 0x4a, 0xe2, 0xee, 0x66, 0xe0, 0x18, 0x35, 0xeb, + 0x38, 0x2c, 0x5b, 0x6e, 0xd4, 0x00, 0x9f, 0x93, 0xb0, 0xc2, 0xde, 0x70, 0x66, 0xd2, 0x3b, 0xd3, 0xe1, 0xea, 0x98, + 0xb3, 0x37, 0x1c, 0xc1, 0x38, 0x12, 0xbc, 0xf1, 0xd0, 0x25, 0xd3, 0x50, 0x91, 0x29, 0xe3, 0x60, 0xda, 0x03, 0xdc, + 0x7b, 0x0e, 0xc6, 0x61, 0x6c, 0x50, 0x59, 0x52, 0x9f, 0x7a, 0x77, 0x21, 0x10, 0xa4, 0xb5, 0x5e, 0xe6, 0x33, 0x3c, + 0x3d, 0x23, 0x94, 0xfd, 0x21, 0x87, 0x2f, 0xc0, 0x8e, 0x82, 0x1c, 0x4d, 0xf8, 0xb3, 0xc7, 0xbb, 0x81, 0xaa, 0xf8, + 0x20, 0xd8, 0x8b, 0x45, 0xba, 0x17, 0x0c, 0x04, 0xfc, 0x2a, 0xf8, 0x5e, 0x25, 0xe5, 0xde, 0x45, 0x5c, 0xec, 0xc5, + 0xab, 0xb8, 0xa8, 0xf6, 0x6e, 0xb2, 0x6a, 0xb9, 0x67, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x7b, 0xc1, + 0xa0, 0x30, 0x53, 0xbb, 0x62, 0x65, 0xe3, 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, + 0xea, 0x9a, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, 0x88, 0xe9, 0x1a, 0xfa, 0x00, 0x3c, 0xf2, 0x9a, 0xc6, 0xb0, 0x04, 0x2e, + 0x06, 0x03, 0xb2, 0x86, 0xc8, 0x05, 0x6b, 0x6a, 0x83, 0x38, 0x84, 0x6b, 0x65, 0xa7, 0xbd, 0x0b, 0xcc, 0xb4, 0xdd, + 0x02, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, 0x1b, 0xea, 0x5f, 0xb0, 0x97, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, + 0xe6, 0xfb, 0x92, 0x1d, 0x0d, 0x54, 0xc4, 0xe1, 0x1d, 0x47, 0x8a, 0x36, 0x2a, 0x97, 0x65, 0x4f, 0x96, 0x0d, 0x5f, + 0x89, 0x2b, 0xee, 0xfc, 0xb8, 0x2a, 0x29, 0xf3, 0x2a, 0x5b, 0x29, 0xf6, 0x6f, 0xc6, 0x35, 0xf7, 0x07, 0xd6, 0x9f, + 0xcd, 0x57, 0x70, 0x6d, 0xf5, 0xde, 0x35, 0xb9, 0x46, 0xe4, 0x2c, 0xa1, 0x5c, 0x52, 0xdb, 0x3c, 0xbc, 0xa5, 0xef, + 0xf3, 0xab, 0x6f, 0x33, 0x9d, 0xc6, 0x67, 0x15, 0x16, 0x2e, 0x44, 0x2b, 0x82, 0x43, 0x43, 0x2e, 0x9a, 0x47, 0x80, + 0xb9, 0xf6, 0xd9, 0x0a, 0x0a, 0x52, 0x9f, 0x55, 0xe8, 0xdd, 0x0a, 0x09, 0xaf, 0x34, 0xbb, 0xf4, 0x30, 0x90, 0x32, + 0x6e, 0x0f, 0x2d, 0x61, 0xd2, 0xf2, 0x22, 0xbc, 0xf7, 0x9a, 0x9b, 0xdc, 0x8b, 0x10, 0xa3, 0x17, 0x79, 0x76, 0x02, + 0xc6, 0xba, 0x4b, 0x76, 0x36, 0x3c, 0xf1, 0x1b, 0x9e, 0xb3, 0x16, 0x8d, 0xa6, 0x4b, 0x96, 0xf4, 0xfb, 0x31, 0x98, + 0x78, 0xa7, 0x2c, 0x87, 0x5f, 0xf9, 0x82, 0xae, 0x19, 0x60, 0x8a, 0xd1, 0x0b, 0x48, 0x48, 0x11, 0x89, 0x64, 0xad, + 0x4e, 0x92, 0xcf, 0x74, 0x17, 0x80, 0xd1, 0x2f, 0x66, 0x69, 0xb4, 0xbc, 0xd7, 0xcc, 0x02, 0xc9, 0x33, 0xf4, 0x5d, + 0x07, 0xdb, 0x1b, 0xfb, 0x20, 0xe5, 0xfc, 0x50, 0x4c, 0x07, 0x03, 0x4e, 0x34, 0xdc, 0x78, 0xa9, 0xc4, 0xb5, 0xba, + 0xc5, 0x1d, 0xc3, 0x58, 0xea, 0xdb, 0x22, 0x06, 0x07, 0xec, 0xa2, 0x95, 0xdd, 0x3e, 0xc0, 0xbe, 0x72, 0xbc, 0x4b, + 0x95, 0xdd, 0xe9, 0x31, 0xd3, 0x5c, 0xb6, 0x9a, 0x74, 0x52, 0x71, 0x3f, 0x91, 0x6f, 0x72, 0x07, 0x5d, 0x2e, 0xc7, + 0x9a, 0xb7, 0x1c, 0x80, 0x8a, 0x7e, 0xa4, 0xa8, 0xee, 0x17, 0x38, 0xc2, 0x3c, 0x58, 0xb7, 0xf9, 0x64, 0xdf, 0x14, + 0x38, 0x44, 0x9e, 0xb4, 0xd1, 0x14, 0xd0, 0xbd, 0x8b, 0xc7, 0x5d, 0xfd, 0xb6, 0x74, 0x17, 0x28, 0xd1, 0x4e, 0xc5, + 0x0d, 0x3f, 0x26, 0xea, 0x74, 0xa6, 0x0d, 0xa1, 0x7f, 0x65, 0xc4, 0xfd, 0xa5, 0x71, 0x15, 0x6f, 0x7a, 0x97, 0xcf, + 0x38, 0xd4, 0xd9, 0x0d, 0xa1, 0x00, 0x5c, 0xb5, 0xa7, 0x53, 0x37, 0x86, 0xf4, 0x4a, 0x89, 0x6e, 0x83, 0x83, 0xdd, + 0xeb, 0x33, 0x8e, 0xa2, 0x1f, 0xa3, 0x46, 0xbe, 0x89, 0xc4, 0x63, 0x39, 0x88, 0x1f, 0x17, 0x74, 0x19, 0x89, 0xc7, + 0xc5, 0x20, 0x7e, 0x2c, 0xeb, 0x7a, 0xf7, 0x5c, 0xb9, 0xbf, 0x8f, 0xc8, 0xb3, 0xee, 0xec, 0xa5, 0x12, 0x36, 0x06, + 0x9e, 0x5d, 0x0b, 0x08, 0xa7, 0xe0, 0x89, 0x6c, 0x2d, 0x7d, 0xe8, 0xdc, 0xee, 0x63, 0xcb, 0x24, 0x41, 0xd0, 0xf3, + 0x36, 0x9b, 0x44, 0xb1, 0xb3, 0xcd, 0xa3, 0x0f, 0xa7, 0x40, 0x42, 0xb7, 0xdb, 0x66, 0x5d, 0xad, 0x01, 0xc5, 0x34, + 0x1c, 0xf3, 0xfd, 0x62, 0x74, 0xe3, 0xbb, 0xeb, 0xef, 0x17, 0xa3, 0x25, 0x19, 0x4e, 0xcc, 0xe4, 0xc7, 0x47, 0xe3, + 0x59, 0x1c, 0x4d, 0xea, 0x8e, 0xd3, 0x42, 0xe3, 0x9f, 0x7a, 0xb7, 0x50, 0x04, 0x4e, 0xc5, 0x08, 0x8e, 0x9c, 0x0a, + 0xe5, 0xa4, 0xd4, 0xc0, 0xf0, 0xdf, 0xab, 0x76, 0xb4, 0x69, 0x6f, 0xe2, 0x2a, 0x59, 0x66, 0xe2, 0x52, 0x87, 0x0f, + 0xd7, 0xd1, 0xc5, 0x6d, 0x40, 0x3b, 0xef, 0x32, 0xed, 0xf8, 0x75, 0xd2, 0xa0, 0x27, 0xae, 0x66, 0x06, 0xdc, 0xba, + 0x1f, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, 0xc4, 0xdc, 0xfe, 0x4d, 0xd9, 0xfc, 0x2a, 0xda, 0xe7, 0xc8, 0x48, + 0xd9, 0x26, 0x23, 0x15, 0x18, 0x61, 0x4a, 0x91, 0xc4, 0x55, 0x08, 0x81, 0xec, 0xbf, 0xa4, 0xb8, 0x16, 0x4b, 0xef, + 0x35, 0x08, 0x13, 0x6c, 0x17, 0xb4, 0x5f, 0xdd, 0xce, 0x6d, 0xa5, 0xc5, 0x1e, 0xa9, 0xef, 0x73, 0x67, 0xbb, 0xa2, + 0xc9, 0xdf, 0x97, 0x0d, 0x68, 0x03, 0x88, 0xf2, 0xbe, 0x3e, 0x2a, 0x81, 0x93, 0x11, 0x37, 0x94, 0x18, 0xbd, 0xa0, + 0xab, 0x13, 0xb9, 0x67, 0xa7, 0xe6, 0x4d, 0xc5, 0x4c, 0xc5, 0x95, 0x6f, 0xf6, 0xcc, 0x7f, 0x30, 0x14, 0x54, 0x80, + 0x81, 0xb7, 0x39, 0xe3, 0xd1, 0x81, 0xee, 0xc6, 0xe8, 0xb4, 0x60, 0xb3, 0xa0, 0x2e, 0xeb, 0xa6, 0x8d, 0x07, 0x8d, + 0x38, 0x28, 0x8a, 0x55, 0xa1, 0x46, 0xc2, 0x13, 0x81, 0x80, 0x29, 0xbb, 0xe2, 0x91, 0x11, 0xd4, 0xf4, 0x26, 0x14, + 0x36, 0x14, 0xfc, 0x55, 0xa2, 0x9a, 0xde, 0x84, 0x36, 0x99, 0x38, 0xcd, 0x20, 0x82, 0x19, 0xb1, 0xdd, 0x6f, 0x01, + 0x6d, 0x6e, 0xcd, 0x68, 0x53, 0xd7, 0x56, 0x5b, 0x85, 0x5c, 0x52, 0xa4, 0x2c, 0xff, 0x9d, 0x9a, 0x0a, 0x4a, 0x6a, + 0xb9, 0xe8, 0x4d, 0x9a, 0x2e, 0x7a, 0x3c, 0x33, 0x92, 0x40, 0xe5, 0x96, 0x3b, 0x46, 0x7f, 0x08, 0x0b, 0x3c, 0x62, + 0xe2, 0xc4, 0x82, 0xb9, 0xd5, 0x11, 0xcb, 0xe6, 0x62, 0x31, 0x5a, 0x49, 0x08, 0x1b, 0x7c, 0xc8, 0xb2, 0x79, 0xa9, + 0x1f, 0x42, 0x5f, 0x58, 0x7a, 0x02, 0x76, 0xb1, 0xc1, 0x4a, 0x96, 0x01, 0xf8, 0x5e, 0xd0, 0xcd, 0x4a, 0x96, 0x91, + 0x54, 0xdd, 0x8f, 0x6b, 0x2c, 0x41, 0xa5, 0x15, 0x2a, 0x2d, 0xa9, 0xb1, 0x20, 0xf0, 0x55, 0xd5, 0xe5, 0x43, 0xb2, + 0xab, 0x40, 0x3d, 0x75, 0xd4, 0x80, 0x53, 0xa0, 0xaa, 0xc0, 0x82, 0x24, 0xa8, 0x0c, 0x5d, 0x15, 0x98, 0x56, 0x60, + 0x9a, 0xa9, 0xc2, 0x45, 0x99, 0x1d, 0x4a, 0xb3, 0x5e, 0xf2, 0x59, 0x3c, 0x08, 0x93, 0x61, 0x4c, 0x1e, 0x23, 0xd4, + 0xfe, 0x7e, 0x1e, 0xc5, 0x5a, 0x2e, 0xb9, 0x72, 0x7e, 0xf1, 0x37, 0x9f, 0xb1, 0xd7, 0x3d, 0xc3, 0x60, 0x01, 0xce, + 0xd2, 0xf6, 0x2a, 0x13, 0xef, 0x64, 0x2b, 0x38, 0x0e, 0x66, 0x51, 0x0e, 0xab, 0x9e, 0x1c, 0xd1, 0x5c, 0xe4, 0xda, + 0xbb, 0x08, 0x91, 0x83, 0xcc, 0x1e, 0x03, 0xec, 0x46, 0xf8, 0x3a, 0xb4, 0x36, 0xb7, 0xba, 0x42, 0xfc, 0x8d, 0x12, + 0x89, 0x9f, 0xa5, 0xfc, 0xb8, 0x5e, 0xa9, 0x5c, 0x95, 0xc1, 0x63, 0xd5, 0xcd, 0xe0, 0x99, 0xf6, 0x3d, 0xd6, 0xfe, + 0xad, 0xed, 0xe6, 0x78, 0xef, 0xc1, 0x83, 0xd6, 0xff, 0xd6, 0x93, 0x10, 0xda, 0x2b, 0x27, 0xa9, 0x3b, 0x6a, 0xf4, + 0xcc, 0x64, 0x8d, 0xa8, 0x84, 0xa9, 0xdd, 0xa9, 0x1c, 0x03, 0x35, 0x1d, 0xc0, 0xb5, 0x44, 0x4d, 0xd0, 0x93, 0x82, + 0x8d, 0xe1, 0x88, 0xb3, 0x38, 0x68, 0x87, 0x31, 0x8a, 0x97, 0x73, 0x25, 0x5e, 0xce, 0x8f, 0x18, 0x07, 0x68, 0x2d, + 0x40, 0xaa, 0xd7, 0xb0, 0x9f, 0xb9, 0x82, 0x05, 0x36, 0x77, 0xbe, 0x03, 0x0b, 0x64, 0x88, 0x93, 0xcd, 0x71, 0xb2, + 0xc7, 0xb5, 0x9e, 0x7b, 0x81, 0x8f, 0x93, 0x7a, 0xe1, 0xd5, 0x55, 0xb6, 0xeb, 0x5a, 0xb2, 0x72, 0x5e, 0x0c, 0x26, + 0x10, 0x94, 0xa5, 0x9c, 0x17, 0xc3, 0xc9, 0x82, 0xe6, 0xf0, 0x63, 0xd1, 0x40, 0x87, 0x58, 0x0e, 0x12, 0xb8, 0x74, + 0xf6, 0x18, 0xf0, 0x86, 0x52, 0x8b, 0xbb, 0xb1, 0x8e, 0x1c, 0xeb, 0x28, 0xf6, 0xc3, 0x18, 0x70, 0x65, 0x9d, 0xc0, + 0xfb, 0xfe, 0xeb, 0x63, 0x13, 0x90, 0x55, 0xbb, 0xc2, 0xab, 0x51, 0xee, 0xba, 0xd2, 0xe8, 0x4b, 0x4a, 0x4f, 0x78, + 0xc1, 0x53, 0xc9, 0x76, 0xdb, 0x33, 0x70, 0xb6, 0xc4, 0x43, 0xe2, 0x1d, 0x23, 0x7a, 0x31, 0x6d, 0x64, 0xe6, 0x04, + 0xce, 0x6c, 0x77, 0xd9, 0xc6, 0xfc, 0xd8, 0x01, 0x0e, 0x16, 0x41, 0x48, 0xdc, 0x10, 0x86, 0x89, 0x1d, 0x95, 0x43, + 0x2d, 0x84, 0xeb, 0x5a, 0x78, 0x1d, 0xa7, 0x65, 0x0c, 0x2e, 0xd2, 0xda, 0x36, 0xf1, 0x1e, 0xba, 0xee, 0xf9, 0x31, + 0xb7, 0x3a, 0x46, 0x5b, 0x48, 0xbf, 0x1d, 0x9d, 0xde, 0x73, 0x18, 0x80, 0xa6, 0x07, 0xb3, 0xaa, 0x7d, 0x26, 0x71, + 0x73, 0xda, 0x09, 0x42, 0x22, 0x10, 0x45, 0xe9, 0x8c, 0x30, 0xfd, 0x3b, 0xcd, 0x65, 0x15, 0xad, 0x1e, 0xe4, 0x99, + 0x43, 0x9e, 0x85, 0xde, 0xf6, 0xa0, 0x55, 0x73, 0x37, 0x18, 0x27, 0x6e, 0xb7, 0x77, 0xfe, 0xdf, 0xb2, 0xae, 0xad, + 0xd6, 0x88, 0xc7, 0xed, 0xea, 0x07, 0x8d, 0xbd, 0xda, 0x53, 0x31, 0x60, 0x56, 0xd2, 0x3b, 0xa3, 0x4a, 0x5e, 0x64, + 0xbc, 0xc4, 0x93, 0x6a, 0xd5, 0xf0, 0xf1, 0xbe, 0xc9, 0x46, 0xe6, 0x81, 0x4c, 0x01, 0xf1, 0xfc, 0x26, 0x35, 0xea, + 0xe3, 0x14, 0x25, 0xe0, 0xef, 0x74, 0x7c, 0x23, 0xfa, 0xd1, 0xbe, 0xb8, 0xe4, 0xd5, 0xc9, 0x8d, 0x30, 0x2f, 0x5e, + 0x58, 0x9d, 0x3f, 0x7d, 0x53, 0xf8, 0xd0, 0xe1, 0xa8, 0xbd, 0x83, 0x22, 0x4b, 0x26, 0x8e, 0x26, 0x46, 0xd6, 0x26, + 0x66, 0x1f, 0x15, 0x5c, 0x4c, 0x54, 0xa1, 0x67, 0x9d, 0x3d, 0x61, 0x0a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x16, + 0x0c, 0xd4, 0x69, 0x4a, 0x88, 0x1e, 0x8a, 0x19, 0xc6, 0x2b, 0x06, 0x50, 0x98, 0x42, 0x81, 0x28, 0x3a, 0xfb, 0x70, + 0xa0, 0x09, 0xfd, 0xfe, 0x4d, 0xaa, 0x33, 0xd0, 0xb2, 0x9e, 0x4a, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, + 0x2e, 0x69, 0x99, 0xd1, 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, + 0x21, 0xec, 0xff, 0x6a, 0xd0, 0xf5, 0x56, 0xac, 0x35, 0xb4, 0x3b, 0x41, 0x46, 0x68, 0xbe, 0xd0, 0x41, 0xc8, 0x50, + 0x39, 0x09, 0x5d, 0xab, 0x34, 0x5e, 0x81, 0x4b, 0xa6, 0xd9, 0x68, 0x19, 0x97, 0x61, 0x60, 0xbf, 0x0a, 0x2c, 0x26, + 0x07, 0x26, 0x9d, 0xae, 0xcf, 0x9f, 0xcb, 0xab, 0x95, 0x14, 0x5c, 0x54, 0x0a, 0xa2, 0xdf, 0xe0, 0xbe, 0x9b, 0xb8, + 0xea, 0xac, 0x59, 0x2b, 0x7d, 0xe8, 0x5b, 0x9f, 0xb5, 0x71, 0x5f, 0x18, 0x1c, 0x83, 0x9d, 0x8f, 0x88, 0x81, 0x34, + 0xa8, 0x74, 0x8b, 0x43, 0x13, 0xa0, 0x4b, 0x87, 0x14, 0xb2, 0x64, 0x2a, 0x53, 0x25, 0xa8, 0xf8, 0xc6, 0xef, 0xa5, + 0xac, 0x46, 0x7f, 0xad, 0x79, 0x71, 0x77, 0xca, 0x73, 0x8e, 0x63, 0x14, 0x24, 0xb1, 0xb8, 0x8e, 0xcb, 0x80, 0xf8, + 0x96, 0x57, 0xc1, 0x41, 0x6a, 0xc2, 0xc6, 0xec, 0x54, 0x8d, 0x5a, 0x2f, 0x89, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, + 0x13, 0x51, 0x05, 0x7d, 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, + 0x6e, 0x98, 0x08, 0x41, 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, + 0xf1, 0x39, 0x73, 0xa1, 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, + 0xd9, 0x91, 0x76, 0x69, 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, + 0x2a, 0xce, 0xc4, 0x71, 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, + 0x61, 0x30, 0x35, 0x15, 0xf7, 0xd8, 0x19, 0x5c, 0x54, 0x7f, 0x44, 0x4b, 0x89, 0xb1, 0x50, 0x75, 0xf1, 0xf1, 0x79, + 0x29, 0xf3, 0x75, 0x05, 0xda, 0xdd, 0x8b, 0x2a, 0x3a, 0x78, 0xba, 0xba, 0x9d, 0xaa, 0x1b, 0x4c, 0xf4, 0xf4, 0x60, + 0x75, 0xdb, 0xcb, 0xae, 0x56, 0xb2, 0xa8, 0x62, 0x51, 0x4d, 0x15, 0x22, 0x59, 0x12, 0xe7, 0x49, 0x38, 0x19, 0x8f, + 0xbf, 0xda, 0x1b, 0xee, 0x41, 0x06, 0x32, 0xfd, 0x34, 0x54, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x95, 0xea, 0x6e, + 0x17, 0x8d, 0x26, 0x35, 0xd6, 0x33, 0x4c, 0xf4, 0xcc, 0x8c, 0xf8, 0xed, 0x2a, 0x16, 0x29, 0xc4, 0xaf, 0xd3, 0xc5, + 0x1f, 0x3c, 0x1d, 0x37, 0xca, 0xb7, 0x9f, 0x3e, 0xab, 0xff, 0xa8, 0x4d, 0x58, 0x6b, 0xd3, 0xee, 0xe7, 0x7f, 0x1c, + 0xaa, 0xf9, 0x3e, 0x3a, 0xdc, 0xd7, 0x3f, 0xfe, 0xa8, 0xeb, 0xe9, 0x9b, 0x22, 0x9c, 0xff, 0x33, 0x54, 0xf3, 0x79, + 0x5c, 0x14, 0xf1, 0x5d, 0x0d, 0x91, 0x3c, 0x85, 0xf3, 0x26, 0xa1, 0xde, 0x36, 0xa0, 0x07, 0x64, 0x7a, 0x21, 0x18, + 0x7c, 0xf3, 0xbe, 0x0a, 0x03, 0x5e, 0xae, 0x86, 0x5c, 0x54, 0x59, 0x75, 0x37, 0xc4, 0x3c, 0x01, 0x7e, 0x6a, 0x78, + 0xb3, 0xe7, 0x85, 0x21, 0x36, 0x17, 0x05, 0xe7, 0x9f, 0x78, 0xa8, 0x8c, 0xa3, 0xc7, 0x68, 0x1c, 0x3d, 0xa6, 0x6a, + 0x30, 0x26, 0xdf, 0x50, 0xdd, 0x99, 0xc9, 0x37, 0x60, 0x82, 0x94, 0xb5, 0xbf, 0x51, 0xc6, 0x89, 0xd1, 0x98, 0x5e, + 0xbf, 0xca, 0xb3, 0x15, 0x30, 0xc1, 0x4b, 0xfd, 0xa3, 0x26, 0xf4, 0x3d, 0x6f, 0x67, 0x1f, 0x8d, 0x46, 0xcf, 0x0b, + 0x3a, 0x1a, 0x8d, 0x3e, 0x66, 0x35, 0xa1, 0x2b, 0xd1, 0xf1, 0xfe, 0x3d, 0xa7, 0xe7, 0x32, 0xbd, 0x8b, 0x82, 0x80, + 0x2e, 0xb3, 0x34, 0xe5, 0x42, 0x95, 0x75, 0x9a, 0xb6, 0xf3, 0xaa, 0x16, 0x22, 0xf0, 0x8f, 0x6e, 0x23, 0x42, 0x10, + 0x11, 0x7a, 0xb2, 0xd3, 0xb3, 0xd1, 0x68, 0x74, 0x9a, 0x9a, 0x6a, 0x1d, 0x43, 0xfe, 0x06, 0xcd, 0x07, 0x9c, 0x5d, + 0x3e, 0x58, 0xdf, 0x98, 0x68, 0x27, 0xfb, 0xff, 0x3d, 0x9c, 0xcd, 0xc7, 0xc3, 0x6f, 0x47, 0x8b, 0xc7, 0xfb, 0x34, + 0x08, 0x7c, 0xd0, 0xea, 0x50, 0x5b, 0x73, 0x4c, 0xcb, 0xc3, 0xf1, 0x94, 0x94, 0x03, 0xf6, 0xd4, 0xfa, 0xd2, 0x7c, + 0xf5, 0x14, 0x90, 0x48, 0x51, 0x84, 0x1a, 0x38, 0xe9, 0x1f, 0x5e, 0x45, 0x5e, 0x0b, 0xc0, 0x47, 0xb3, 0x91, 0x0c, + 0x8c, 0x16, 0x70, 0x1c, 0x41, 0x79, 0xb5, 0x35, 0x8d, 0xe8, 0x31, 0x96, 0x99, 0xa8, 0xa0, 0xe3, 0x69, 0x79, 0x93, + 0x55, 0xc9, 0x12, 0x03, 0x1b, 0xc5, 0x25, 0x0f, 0xbe, 0x0a, 0xa2, 0x92, 0x1d, 0x3c, 0x9b, 0x2a, 0x78, 0x5f, 0x4c, + 0x4a, 0xf9, 0x25, 0x24, 0x7e, 0x3b, 0x46, 0x08, 0x54, 0xa2, 0x3d, 0x16, 0xb1, 0xc6, 0x57, 0xb9, 0x8c, 0xc1, 0x83, + 0xb3, 0xd4, 0x3c, 0x8b, 0x3d, 0x09, 0xac, 0xfd, 0x45, 0xab, 0x39, 0x12, 0x9a, 0x13, 0x4a, 0x26, 0xf7, 0x4b, 0x2a, + 0xbf, 0x9a, 0xa0, 0x57, 0x10, 0xb8, 0x55, 0x47, 0x70, 0xdc, 0x59, 0xcb, 0x06, 0xbd, 0x7c, 0x52, 0xb6, 0x3f, 0xff, + 0xdf, 0x25, 0x5d, 0x0c, 0xf6, 0xdd, 0xd0, 0x9c, 0x68, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x9e, 0x12, 0x6b, + 0x7c, 0xca, 0xd9, 0xd1, 0xc6, 0x74, 0x67, 0x54, 0x15, 0xd9, 0x55, 0x48, 0x74, 0xaf, 0x1c, 0x28, 0x66, 0x10, 0x65, + 0x23, 0x5c, 0x3f, 0x60, 0x2d, 0xe2, 0x75, 0xf2, 0x9a, 0x17, 0x55, 0x96, 0xa8, 0xf7, 0xd7, 0x8d, 0xf7, 0x40, 0x0d, + 0x54, 0x83, 0xde, 0x15, 0x0c, 0xe6, 0xf9, 0xa4, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, + 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, + 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xae, 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, + 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x93, 0x86, 0x10, + 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, 0x9e, 0xe0, 0xa9, 0x1a, 0x06, 0x17, 0x79, 0xb6, 0xd2, 0x49, 0xd5, 0xa8, + 0xa3, 0xf9, 0x50, 0x6a, 0x47, 0x72, 0x40, 0xbd, 0xf4, 0x18, 0xd3, 0x0b, 0x95, 0xae, 0x8a, 0x72, 0x46, 0x28, 0xef, + 0xf4, 0xc4, 0xb8, 0x30, 0x7d, 0x1c, 0x22, 0xbf, 0xbc, 0x2b, 0x54, 0xe8, 0x17, 0xbe, 0x00, 0xf0, 0x2b, 0xb8, 0xdd, + 0xef, 0xc6, 0x77, 0x51, 0xd9, 0xcf, 0x38, 0xdb, 0xff, 0xef, 0x79, 0x3c, 0xfc, 0x34, 0x1e, 0x7e, 0xbb, 0x18, 0x84, + 0x43, 0xfb, 0x93, 0x3c, 0x7e, 0xb4, 0x4f, 0x5f, 0x71, 0xcb, 0x95, 0xc0, 0xc2, 0x6f, 0x04, 0xb7, 0x51, 0x2b, 0x21, + 0x88, 0x02, 0xbc, 0x51, 0xb8, 0xd5, 0x38, 0x01, 0x80, 0xbf, 0xe0, 0xbf, 0x02, 0x34, 0x12, 0x72, 0x17, 0x0d, 0xd0, + 0x0f, 0xa8, 0xdf, 0x47, 0x4f, 0x1a, 0x06, 0x72, 0x20, 0x9e, 0x50, 0x31, 0x50, 0x88, 0x2e, 0x63, 0xa2, 0x60, 0x7f, + 0x6d, 0xf6, 0xed, 0xb6, 0xd7, 0x96, 0xfc, 0xe0, 0x97, 0x7e, 0xa6, 0x89, 0x99, 0x77, 0xb8, 0xa1, 0xac, 0xe4, 0x2a, + 0x44, 0x6c, 0x3c, 0xfd, 0x2b, 0x67, 0x10, 0x6b, 0xf2, 0x3a, 0x03, 0x1f, 0x06, 0xfb, 0xc5, 0x78, 0x06, 0x6c, 0x03, + 0xdc, 0x71, 0x0a, 0x7e, 0x91, 0x81, 0x5b, 0xb3, 0x88, 0xf1, 0x82, 0x6d, 0x97, 0x44, 0xbf, 0xdf, 0xcb, 0xb3, 0x30, + 0xd7, 0x38, 0xcb, 0x79, 0x6d, 0xc4, 0xee, 0xa8, 0x13, 0x06, 0x71, 0xbb, 0x1e, 0x82, 0xa1, 0x1a, 0x82, 0xa2, 0xa3, + 0x2d, 0xae, 0x5e, 0x5b, 0x4f, 0x61, 0x7a, 0xab, 0xea, 0x2b, 0x46, 0x7f, 0xca, 0x4c, 0x60, 0x21, 0xed, 0x9a, 0x63, + 0x5d, 0x73, 0x8c, 0xb4, 0xa7, 0xdf, 0x17, 0x0d, 0xf2, 0xd3, 0x59, 0x78, 0x10, 0xa8, 0x52, 0xe5, 0x4e, 0x59, 0x94, + 0xdb, 0xd2, 0xbc, 0x31, 0xac, 0x69, 0x9e, 0xd9, 0xb8, 0x2e, 0xb3, 0x5e, 0x2f, 0x0c, 0xd1, 0xa1, 0x11, 0x4b, 0xc5, + 0xda, 0x20, 0xbc, 0x8f, 0x49, 0x18, 0x5d, 0x81, 0xac, 0x2e, 0x3c, 0xe3, 0x04, 0xf9, 0x32, 0x30, 0x59, 0x53, 0xd5, + 0x7a, 0x39, 0xe1, 0xb1, 0x91, 0x2f, 0x1b, 0x41, 0x83, 0xbc, 0xa4, 0xa8, 0x37, 0x71, 0x3b, 0xf6, 0x51, 0x0b, 0xa9, + 0x71, 0x53, 0x4f, 0x7b, 0x9a, 0x54, 0xf4, 0x58, 0xaf, 0x52, 0xbf, 0xc0, 0xb2, 0xc0, 0x92, 0x0f, 0x42, 0x7b, 0x9a, + 0x56, 0x60, 0x86, 0x6b, 0x9b, 0xc1, 0xd0, 0x0f, 0x87, 0xb6, 0x08, 0x9d, 0x51, 0xdb, 0x12, 0xc2, 0xb6, 0x0d, 0xc2, + 0xca, 0x7b, 0x22, 0x5f, 0x3d, 0xf5, 0x18, 0xe1, 0x90, 0x9b, 0xcd, 0x2c, 0x1a, 0x18, 0xe6, 0x57, 0xb2, 0xd9, 0x3c, + 0xdd, 0x5c, 0x2f, 0x2a, 0xa6, 0x80, 0xed, 0xb6, 0x12, 0x04, 0xff, 0x7e, 0xcc, 0x66, 0xf8, 0x37, 0xeb, 0xf7, 0x7b, + 0x21, 0xfe, 0xe2, 0x18, 0xbc, 0x67, 0x2e, 0x16, 0xec, 0x23, 0xc8, 0x54, 0x48, 0x84, 0xa9, 0xca, 0xf8, 0x8d, 0x55, + 0x60, 0x01, 0x67, 0x3e, 0x50, 0xb9, 0x30, 0x93, 0xbd, 0xbc, 0xb8, 0x86, 0x1c, 0xb7, 0xc6, 0x29, 0x1b, 0x65, 0x89, + 0x72, 0x5d, 0xc8, 0x46, 0x71, 0x9e, 0xc5, 0x25, 0x2f, 0xb7, 0x5b, 0x7d, 0x38, 0x26, 0x05, 0x07, 0xf6, 0x54, 0x51, + 0xa9, 0x92, 0x75, 0xa4, 0xba, 0xf1, 0x97, 0x61, 0x81, 0xfb, 0x94, 0xcf, 0x0b, 0x43, 0x23, 0xf6, 0xe0, 0xf2, 0xce, + 0xd4, 0xad, 0xb4, 0x17, 0x16, 0xd0, 0xbc, 0x92, 0x90, 0x0d, 0xa6, 0x7a, 0x16, 0xad, 0x31, 0x13, 0xf3, 0x62, 0x01, + 0x61, 0x64, 0x8a, 0x05, 0xd8, 0x4c, 0x71, 0x01, 0x5e, 0x24, 0x31, 0xc0, 0xc4, 0xc5, 0x64, 0x0a, 0xf1, 0xcc, 0x55, + 0x39, 0xf1, 0xc2, 0xdc, 0x2f, 0x13, 0x87, 0x94, 0x01, 0xaf, 0x6a, 0x83, 0x26, 0x66, 0x1b, 0x8e, 0x3a, 0x41, 0x4e, + 0x4c, 0x7e, 0x3f, 0x55, 0x10, 0xe2, 0x4e, 0x1c, 0x09, 0x97, 0x15, 0xdb, 0x85, 0x97, 0x1d, 0x88, 0x31, 0x6a, 0x70, + 0xca, 0xcf, 0x0c, 0x8e, 0xc6, 0xe0, 0xdc, 0x78, 0x27, 0x48, 0x11, 0xc6, 0x64, 0x23, 0xd9, 0x95, 0x0c, 0xc5, 0x3c, + 0x5e, 0x80, 0xb2, 0x2e, 0x5e, 0x80, 0x65, 0x8d, 0x31, 0xc0, 0x04, 0x79, 0x15, 0xf7, 0x42, 0x3f, 0x51, 0x5c, 0x21, + 0xd2, 0xb3, 0x72, 0x7d, 0x54, 0xb4, 0x43, 0x5f, 0xe0, 0xf5, 0x5e, 0x99, 0xe3, 0x66, 0x3d, 0x16, 0x48, 0x6c, 0x08, + 0x18, 0x1b, 0xe9, 0x34, 0xd5, 0x5a, 0xf7, 0xc6, 0xcc, 0x03, 0x9f, 0x66, 0x23, 0x21, 0xab, 0xb3, 0x0b, 0x10, 0xa1, + 0xf8, 0x68, 0xf0, 0xc8, 0x2f, 0xe2, 0xce, 0x32, 0x6f, 0x6d, 0x8b, 0x4a, 0x76, 0xb4, 0x01, 0x90, 0x3e, 0x1d, 0x2d, + 0x4a, 0xc9, 0x29, 0x4a, 0x52, 0xbb, 0x4d, 0x01, 0x2b, 0xc9, 0x5f, 0xc0, 0x10, 0x6c, 0x6c, 0x4f, 0x38, 0x9d, 0x22, + 0xc4, 0x27, 0x9a, 0x22, 0xb2, 0x62, 0x58, 0x52, 0x1c, 0xdb, 0x12, 0x51, 0x3f, 0x6d, 0x59, 0x76, 0x30, 0x4c, 0x54, + 0xdc, 0x17, 0xa9, 0x47, 0x89, 0x82, 0x80, 0xea, 0x21, 0x07, 0x89, 0xad, 0x6d, 0x20, 0x3c, 0x20, 0x8f, 0xe8, 0x8d, + 0xf5, 0xf7, 0x59, 0xe7, 0xd9, 0x85, 0xe6, 0xa8, 0x5c, 0xef, 0x0a, 0x33, 0x46, 0x78, 0x92, 0x19, 0x98, 0x7c, 0xef, + 0x3c, 0x33, 0x6a, 0x8a, 0x9e, 0x87, 0x4f, 0x76, 0x8c, 0x11, 0xe9, 0xee, 0x19, 0x74, 0x13, 0xbc, 0xaa, 0xc3, 0x46, + 0xbb, 0x52, 0x10, 0x12, 0xa6, 0x16, 0x4d, 0xcc, 0x7a, 0xd6, 0x80, 0x7a, 0xbb, 0xed, 0xe9, 0xb9, 0xba, 0x7f, 0xee, + 0xb6, 0xdb, 0x1e, 0x76, 0xeb, 0x45, 0xda, 0x6d, 0x05, 0x5e, 0xa9, 0x0f, 0xda, 0xe3, 0xcf, 0xdd, 0xf8, 0x73, 0x83, + 0xe4, 0x51, 0x3a, 0x9a, 0x69, 0xeb, 0x83, 0x70, 0xb8, 0xe9, 0x5d, 0xa3, 0x49, 0xdf, 0x67, 0xa1, 0xa4, 0x2b, 0xd1, + 0xa8, 0xae, 0x76, 0x26, 0x95, 0x0f, 0xae, 0xff, 0x87, 0x57, 0x01, 0x1e, 0x71, 0x6a, 0x67, 0xdf, 0xdb, 0xa0, 0xa2, + 0xd1, 0x16, 0x8e, 0x14, 0xa1, 0x07, 0x24, 0xe1, 0xbe, 0x96, 0xb5, 0xb8, 0xcd, 0xd3, 0xec, 0x61, 0xfa, 0xf4, 0x3a, + 0xf5, 0xad, 0xee, 0xdd, 0x32, 0xcb, 0xcc, 0x81, 0x57, 0x51, 0x1c, 0xd0, 0xa8, 0x8b, 0xf6, 0x5d, 0x65, 0x65, 0x09, + 0x5e, 0x1e, 0x70, 0x7d, 0x3e, 0xe5, 0x3e, 0xdc, 0xdc, 0x65, 0xd5, 0xdc, 0xa4, 0xa7, 0xd9, 0x3c, 0x5b, 0x6c, 0xb7, + 0x21, 0xfe, 0xed, 0x6a, 0x91, 0xa3, 0xc9, 0x73, 0xd0, 0xe1, 0x61, 0xe4, 0x1e, 0xa6, 0x1b, 0xe7, 0x6d, 0xfe, 0x4f, + 0xa2, 0xe1, 0x24, 0x70, 0x0c, 0xf4, 0x62, 0xf6, 0x08, 0x64, 0x30, 0xc6, 0xa9, 0x5f, 0xcc, 0xf4, 0x9a, 0x81, 0xe8, + 0x5b, 0x22, 0x02, 0x1c, 0x5d, 0x6c, 0x24, 0x1a, 0x59, 0x70, 0x52, 0x13, 0xb0, 0xd8, 0xb4, 0xe5, 0x7d, 0xb0, 0xb4, + 0xad, 0x2a, 0xee, 0xbc, 0x25, 0xcd, 0x71, 0x1d, 0x38, 0xdb, 0x7e, 0x33, 0xc4, 0xa6, 0xec, 0x6a, 0x81, 0xdc, 0x2f, + 0xaf, 0x69, 0x6f, 0x5c, 0x27, 0x30, 0x6b, 0x9b, 0xda, 0x32, 0x7e, 0xb6, 0xf4, 0x9f, 0xf5, 0xe0, 0x2a, 0xe3, 0xa7, + 0xb9, 0xb1, 0x4a, 0xb0, 0xfb, 0xc6, 0xf3, 0x1d, 0x80, 0x70, 0x6c, 0x3e, 0x3d, 0x3e, 0xcd, 0x3c, 0x7a, 0x0c, 0x44, + 0xc7, 0x7c, 0x54, 0xba, 0x8f, 0xec, 0xee, 0xf5, 0x03, 0xe0, 0xcd, 0xab, 0x76, 0x41, 0xf3, 0x72, 0x01, 0x81, 0x44, + 0xbd, 0xf2, 0x0a, 0xcb, 0x67, 0xc6, 0xec, 0x12, 0xc8, 0x50, 0x41, 0xc0, 0x26, 0xa9, 0xeb, 0x5c, 0x88, 0x55, 0x87, + 0x95, 0xf9, 0x48, 0xc2, 0x8e, 0x42, 0x34, 0xe7, 0x0c, 0x66, 0xc1, 0x7f, 0x05, 0x83, 0x72, 0x10, 0x44, 0x41, 0x14, + 0x04, 0x64, 0x50, 0xc0, 0x2f, 0xc4, 0x19, 0x23, 0x18, 0xa3, 0x04, 0x3a, 0xfc, 0x8e, 0x33, 0x9f, 0x11, 0x79, 0xd9, + 0x08, 0x63, 0xe9, 0x06, 0xe0, 0x5c, 0xca, 0x9c, 0xc7, 0xe8, 0x63, 0xf1, 0x8e, 0xb3, 0x8c, 0xd0, 0x77, 0xde, 0xa9, + 0xfc, 0x88, 0x37, 0x82, 0xdb, 0xed, 0x0e, 0xdb, 0x2b, 0x1e, 0x66, 0xb4, 0x37, 0xa6, 0xef, 0x38, 0x89, 0xb2, 0x86, + 0xf3, 0x30, 0x87, 0x9e, 0x55, 0x96, 0xb5, 0xa2, 0x86, 0xdc, 0xa0, 0x58, 0x17, 0x59, 0x26, 0x27, 0xc3, 0x55, 0x73, + 0x2a, 0x70, 0xdd, 0xd9, 0xf5, 0x02, 0x92, 0x32, 0xa1, 0x59, 0x3a, 0x1b, 0xbe, 0xda, 0xb6, 0xec, 0x45, 0xeb, 0x14, + 0xf2, 0x1a, 0xa2, 0xa2, 0x1f, 0x3a, 0x02, 0x6a, 0x68, 0xc5, 0x65, 0x05, 0x2e, 0xbb, 0xa6, 0x3d, 0xdc, 0xb4, 0xc7, + 0x34, 0xe3, 0x03, 0xc4, 0x88, 0xe3, 0xd8, 0x32, 0xb0, 0x9b, 0x70, 0x78, 0x36, 0xce, 0xf7, 0x65, 0x97, 0xde, 0xba, + 0x5a, 0x3c, 0xc2, 0xda, 0xf3, 0x56, 0x48, 0x08, 0x90, 0x96, 0xa6, 0xd2, 0xed, 0x36, 0x08, 0x60, 0x80, 0xfb, 0xfd, + 0x1e, 0x70, 0xad, 0x86, 0x9d, 0x34, 0xb7, 0x66, 0x4b, 0xec, 0x15, 0x85, 0xc7, 0x40, 0x94, 0x9a, 0xff, 0x0c, 0x02, + 0x8a, 0xe7, 0x6e, 0x08, 0xf6, 0x95, 0xec, 0x68, 0x53, 0xf4, 0xfb, 0x2f, 0x0a, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, + 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, + 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x9f, 0x00, 0x16, 0x3c, 0xf3, 0x86, 0xe5, + 0xbd, 0x07, 0x00, 0xd6, 0xeb, 0xe1, 0x42, 0x71, 0x2f, 0x5f, 0x35, 0xd0, 0x27, 0xf1, 0xa5, 0x65, 0xd7, 0x67, 0x5a, + 0x56, 0x32, 0x1a, 0x8d, 0xaa, 0x5a, 0x49, 0x3e, 0x1c, 0x79, 0x69, 0xa1, 0x56, 0xca, 0x38, 0xe5, 0x29, 0x58, 0x7a, + 0x1b, 0x4a, 0x37, 0x5f, 0xd0, 0x15, 0x17, 0xa9, 0xfa, 0xe9, 0xa1, 0x4d, 0x36, 0x88, 0x6b, 0xd6, 0xd4, 0x59, 0xd8, + 0xe1, 0x87, 0x80, 0x8f, 0xf6, 0x61, 0xe6, 0xd2, 0x35, 0x2c, 0x2d, 0x88, 0x23, 0xe3, 0x82, 0x87, 0x2e, 0x0f, 0x60, + 0xfd, 0x99, 0x43, 0x12, 0x3f, 0x85, 0x9f, 0x33, 0x93, 0xd6, 0xf1, 0x19, 0xce, 0x66, 0x54, 0xaa, 0x1b, 0x41, 0xfb, + 0x35, 0x24, 0x12, 0x83, 0x6c, 0xdc, 0x60, 0x28, 0x5a, 0x77, 0x1b, 0xb8, 0xf2, 0x5b, 0x7a, 0xe7, 0xd3, 0x20, 0xc0, + 0xb6, 0xc6, 0x62, 0x00, 0x30, 0x14, 0x7f, 0xa0, 0xaa, 0xc6, 0x5c, 0x51, 0x4c, 0xc3, 0x54, 0xa2, 0xbd, 0xe3, 0xb8, + 0x8e, 0x1a, 0x57, 0x59, 0xc1, 0x4a, 0x6b, 0xcb, 0xeb, 0xde, 0xd2, 0xc2, 0x96, 0x80, 0x6a, 0x30, 0xdc, 0x09, 0xe0, + 0x33, 0x22, 0xd5, 0x81, 0x20, 0xbb, 0x0f, 0x0e, 0x9a, 0xb3, 0x04, 0xcf, 0xc3, 0x10, 0xfe, 0xc0, 0xc2, 0x81, 0x65, + 0xa9, 0xfa, 0xb9, 0x9c, 0xc6, 0x70, 0xee, 0xe6, 0x6a, 0x87, 0xcf, 0x96, 0xa0, 0xc8, 0x53, 0x73, 0x6a, 0x2e, 0x5f, + 0x79, 0x63, 0xbf, 0xc7, 0x04, 0xf3, 0x98, 0xd9, 0x86, 0xdf, 0x7a, 0xba, 0xad, 0x2f, 0xac, 0x1b, 0x38, 0x69, 0x2f, + 0x9c, 0xf6, 0x62, 0xbb, 0x34, 0x10, 0x77, 0x75, 0x43, 0x88, 0xf0, 0x5a, 0x13, 0x8b, 0xac, 0x21, 0xd3, 0xb1, 0xd8, + 0x18, 0xaa, 0x4d, 0xc5, 0x73, 0xad, 0x10, 0x2f, 0xa7, 0xea, 0xc2, 0xd4, 0x4a, 0x65, 0xc2, 0x20, 0xcc, 0x94, 0xb0, + 0xa8, 0x32, 0xf0, 0xd9, 0xaf, 0x90, 0xe2, 0xda, 0x7a, 0xde, 0xe2, 0xf2, 0xcd, 0x4c, 0x9b, 0xed, 0xa7, 0xaf, 0xf2, + 0xf8, 0x72, 0xbb, 0x0d, 0xbb, 0x5f, 0x80, 0xf9, 0x65, 0xa9, 0x34, 0x6a, 0xe0, 0xf4, 0x10, 0xa2, 0x9f, 0xf3, 0x3d, + 0x39, 0x27, 0x8e, 0x93, 0x6b, 0x37, 0x6f, 0xb6, 0x93, 0x62, 0x04, 0x16, 0x70, 0xe2, 0x22, 0x1d, 0x68, 0xa9, 0xe0, + 0xb4, 0x65, 0xbc, 0xb7, 0xe9, 0x1d, 0xa5, 0xc2, 0xab, 0x85, 0x26, 0x21, 0x95, 0xbb, 0x97, 0xd8, 0x51, 0x03, 0xce, + 0x49, 0xdd, 0x41, 0xc0, 0x49, 0x4d, 0x37, 0xd6, 0x2a, 0x4e, 0x4d, 0x82, 0xf7, 0x4a, 0x0f, 0x5d, 0xa2, 0x9d, 0xb8, + 0xdd, 0xb6, 0x2a, 0x5b, 0xa8, 0x8f, 0x7b, 0x39, 0x4b, 0xd4, 0xf1, 0x80, 0x42, 0x17, 0x75, 0x34, 0xe4, 0x0b, 0x52, + 0xe8, 0x95, 0xa3, 0x55, 0xab, 0xbb, 0x92, 0x81, 0x52, 0xad, 0x82, 0xbc, 0x26, 0xd6, 0x5d, 0x2b, 0x6b, 0x2c, 0xae, + 0x9c, 0x90, 0xc2, 0x26, 0x7c, 0x69, 0x29, 0x16, 0x56, 0xb0, 0x37, 0xa6, 0xbe, 0x70, 0x89, 0xd0, 0x76, 0xb7, 0x21, + 0x26, 0x19, 0xac, 0x9b, 0xed, 0xf6, 0x75, 0x11, 0xce, 0xb3, 0x05, 0x95, 0xa3, 0x2c, 0x45, 0x08, 0x31, 0xe3, 0xa1, + 0x6b, 0xbb, 0x60, 0x26, 0x86, 0xba, 0xf6, 0x78, 0x49, 0xa6, 0x58, 0x9b, 0x24, 0x47, 0xf1, 0xb9, 0x2c, 0xd4, 0x5a, + 0x23, 0x04, 0x0f, 0xf7, 0x3f, 0x53, 0x88, 0xe1, 0x66, 0xd6, 0xdd, 0x6f, 0x3b, 0x37, 0xc4, 0x3f, 0x21, 0x90, 0x40, + 0xc9, 0x5e, 0x17, 0xa3, 0xf3, 0x4c, 0xa4, 0xb8, 0x53, 0x55, 0x54, 0x5c, 0xb5, 0x0e, 0x9a, 0x2d, 0xb7, 0xf7, 0x62, + 0x4b, 0x14, 0x20, 0xae, 0xb1, 0xd0, 0x8c, 0x67, 0xe5, 0x2c, 0x45, 0x32, 0x8a, 0x0d, 0x89, 0x4a, 0x2f, 0x2a, 0xba, + 0xcf, 0xd3, 0x98, 0x1e, 0xba, 0x35, 0x08, 0xae, 0x9a, 0x3b, 0x1b, 0x69, 0xbe, 0x20, 0x44, 0x4d, 0x80, 0x84, 0x8d, + 0x6a, 0x4e, 0xad, 0x4b, 0xf1, 0x30, 0xab, 0x7c, 0xa6, 0x0f, 0xe2, 0x4b, 0x01, 0x3c, 0xac, 0xb7, 0xbd, 0xaf, 0x84, + 0xc7, 0xda, 0xe0, 0xdb, 0xed, 0xf6, 0x52, 0xcc, 0x83, 0xc0, 0x63, 0x34, 0xbf, 0x53, 0x12, 0xf3, 0xde, 0x98, 0xc2, + 0x8a, 0xf7, 0x5d, 0xda, 0xba, 0x49, 0xad, 0xb5, 0x40, 0xdd, 0xe1, 0xfa, 0x80, 0xe7, 0x29, 0x71, 0xb4, 0xa3, 0x72, + 0x2a, 0xad, 0xae, 0x1c, 0xbb, 0x22, 0x30, 0x30, 0xf4, 0x0f, 0x29, 0xdb, 0x80, 0x39, 0x1e, 0x58, 0xdb, 0xa0, 0x9f, + 0x92, 0xd2, 0xc2, 0x8c, 0xd1, 0x98, 0x45, 0xae, 0xab, 0xe8, 0x80, 0xeb, 0xe8, 0xed, 0x3c, 0xfa, 0xdb, 0xb3, 0x31, + 0x2d, 0x62, 0x91, 0xca, 0x2b, 0x50, 0x41, 0x80, 0x32, 0x04, 0x0d, 0xff, 0x35, 0x35, 0x00, 0x0d, 0x82, 0x1b, 0x80, + 0x7f, 0x74, 0x3a, 0x0d, 0xda, 0x9a, 0x7c, 0x4c, 0x52, 0x55, 0xe4, 0xac, 0x0d, 0x65, 0xa6, 0x92, 0x43, 0xf2, 0xb8, + 0x04, 0x3c, 0x47, 0x6c, 0x96, 0xb2, 0xb9, 0x50, 0x9b, 0x4d, 0xbd, 0x56, 0xec, 0xc8, 0x6d, 0xa3, 0x68, 0xb3, 0x16, + 0xb5, 0x9d, 0xc4, 0x7c, 0x31, 0xbd, 0xb5, 0xc2, 0xc0, 0xa9, 0x69, 0xcd, 0xcd, 0x0e, 0x74, 0x9a, 0xad, 0xcf, 0xe4, + 0x26, 0x40, 0x1c, 0x60, 0xb8, 0x6e, 0xe7, 0x37, 0x0b, 0x42, 0x6f, 0xd9, 0xad, 0x15, 0xab, 0xde, 0x58, 0xb9, 0x88, + 0x49, 0xbb, 0x19, 0x4c, 0xe0, 0x32, 0xce, 0x0a, 0xfb, 0x42, 0xab, 0x1b, 0x8a, 0x8e, 0xb6, 0x49, 0xfb, 0x79, 0x47, + 0xbb, 0xe1, 0x82, 0x6f, 0xc5, 0x3a, 0xce, 0x0d, 0x69, 0xaa, 0xd0, 0xa3, 0x03, 0xbd, 0x1d, 0x02, 0x9a, 0xb3, 0x31, + 0x5d, 0xd2, 0x14, 0x2f, 0xd0, 0x74, 0x0d, 0x66, 0x29, 0x17, 0xd0, 0xd7, 0x6e, 0x9f, 0xe4, 0x0b, 0xd5, 0x13, 0xe1, + 0x2d, 0x51, 0xf0, 0xe5, 0x48, 0xc1, 0x2b, 0x2b, 0xe7, 0xb1, 0x99, 0x43, 0xc0, 0x63, 0x51, 0x25, 0x7a, 0x27, 0xc5, + 0x25, 0x28, 0x53, 0xe1, 0x08, 0x34, 0x55, 0x23, 0x96, 0x70, 0x80, 0xdb, 0x8b, 0xa7, 0x01, 0xa1, 0x20, 0xd5, 0x5d, + 0xdb, 0x15, 0x79, 0xcb, 0x8e, 0x36, 0xb7, 0x60, 0x16, 0x5b, 0xad, 0xcb, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, + 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, 0x43, 0x36, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, + 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x55, 0x7c, 0x07, 0x9b, + 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, + 0x5e, 0x6d, 0x6d, 0xd6, 0x66, 0xb9, 0x3e, 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, + 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x36, 0xce, + 0xdc, 0xeb, 0x90, 0x6c, 0xfe, 0xc7, 0x06, 0xea, 0x4d, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x3e, 0x61, 0x10, 0x1b, 0x33, + 0x28, 0xd7, 0x49, 0xc2, 0xcb, 0x32, 0x30, 0x4a, 0xad, 0x35, 0x5b, 0x9b, 0xf3, 0xec, 0x11, 0x3b, 0x7a, 0xd4, 0x63, + 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x04, 0x85, + 0x2c, 0xed, 0x7d, 0x6e, 0x4e, 0x64, 0xf5, 0x8d, 0x36, 0xba, 0x88, 0x54, 0x22, 0xc8, 0xc6, 0x6f, 0x10, 0xb0, 0x17, + 0x9a, 0x1d, 0x90, 0xcd, 0x92, 0x9d, 0xd2, 0x33, 0x6b, 0x02, 0x03, 0xaf, 0x4f, 0x54, 0xa2, 0x19, 0x65, 0x45, 0x74, + 0x95, 0x91, 0xcb, 0x5d, 0x48, 0xa2, 0xb3, 0x90, 0xf8, 0xb9, 0x61, 0x69, 0x5d, 0x87, 0x28, 0x66, 0x36, 0x1b, 0x5e, + 0x75, 0xf7, 0x51, 0x63, 0x5b, 0x19, 0x9f, 0xea, 0x5b, 0x9b, 0x46, 0xa6, 0xd0, 0xd7, 0xe1, 0xa4, 0xdf, 0x87, 0xbf, + 0x9a, 0x7e, 0xe0, 0x2d, 0x05, 0x7f, 0xb1, 0x47, 0xa4, 0x4e, 0x58, 0x00, 0x70, 0x84, 0x39, 0xaf, 0x9a, 0x13, 0xf8, + 0x88, 0x1d, 0x6d, 0x1e, 0x85, 0xa7, 0x8d, 0x99, 0xbb, 0x0b, 0xf1, 0x52, 0x95, 0xf4, 0xbc, 0x79, 0x32, 0x03, 0xb1, + 0x0a, 0xcd, 0x7e, 0xbd, 0x65, 0x56, 0x9f, 0x00, 0x44, 0xea, 0xd6, 0x3a, 0x94, 0xe2, 0xc7, 0xa6, 0xcb, 0x64, 0x93, + 0xb2, 0x36, 0x13, 0xa5, 0x54, 0x24, 0xcd, 0x45, 0x00, 0xfd, 0x86, 0xe1, 0xa8, 0x01, 0xde, 0x5b, 0x8f, 0xbd, 0x19, + 0x1a, 0x6f, 0x4c, 0x0d, 0x3d, 0xdb, 0xe8, 0xe5, 0xed, 0x28, 0x84, 0x19, 0x8b, 0xe8, 0xd6, 0x1d, 0x8b, 0xe1, 0x29, + 0x3d, 0x81, 0x0a, 0xdf, 0x84, 0x18, 0x4d, 0x97, 0xd4, 0xf5, 0x74, 0xad, 0xb6, 0xd2, 0x0d, 0xa1, 0x39, 0x46, 0xf1, + 0xf1, 0xda, 0x76, 0x47, 0x8d, 0xd0, 0x9e, 0x50, 0x1e, 0xde, 0xd2, 0x8a, 0xde, 0x58, 0x16, 0xc1, 0xc9, 0x8f, 0xbd, + 0xfc, 0x84, 0x9e, 0x7b, 0x02, 0x93, 0xa2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x3d, 0xb5, 0x52, 0x0e, 0x4f, + 0xe1, 0x4b, 0x36, 0x20, 0x57, 0xd0, 0x8b, 0x35, 0x66, 0x47, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x37, 0x29, 0x65, + 0x88, 0xd6, 0x77, 0x0e, 0xe2, 0xe9, 0x1f, 0xa0, 0xe9, 0x83, 0xb4, 0x30, 0xa5, 0x6b, 0x14, 0xf0, 0x80, 0xbe, 0xa9, + 0xdf, 0xcf, 0xf1, 0xb9, 0xf6, 0x2c, 0xb1, 0xb0, 0xc7, 0x4b, 0x42, 0x97, 0x5e, 0xdc, 0x28, 0x90, 0x36, 0x3b, 0x56, + 0x01, 0x58, 0x91, 0x04, 0x1a, 0x91, 0x80, 0xa5, 0x8e, 0x27, 0x2e, 0xdb, 0xa0, 0x01, 0x49, 0x54, 0x52, 0xc8, 0x12, + 0x49, 0xe0, 0x87, 0x11, 0x84, 0x28, 0x8a, 0x41, 0xdc, 0xab, 0x97, 0x57, 0x5c, 0x53, 0x03, 0x4e, 0x14, 0xc1, 0x04, + 0xeb, 0x74, 0x0a, 0xc4, 0x56, 0xac, 0x57, 0xe0, 0x79, 0xe9, 0x38, 0x71, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x97, 0x4e, + 0xbb, 0xe5, 0xed, 0x89, 0x96, 0x2a, 0x36, 0xf7, 0x5e, 0x2c, 0x2c, 0xf7, 0x58, 0xf9, 0xdb, 0x81, 0xf6, 0xc2, 0x6a, + 0x47, 0x44, 0x0d, 0x56, 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xea, 0x5e, 0x39, 0x26, 0xa0, 0xa2, 0xab, 0xb8, 0x5a, + 0x46, 0xd9, 0x08, 0xfe, 0x6c, 0xb7, 0xc1, 0x7e, 0x00, 0x16, 0x90, 0xbf, 0xbe, 0xff, 0x39, 0xc2, 0xf0, 0x4c, 0xbf, + 0xbe, 0xff, 0x79, 0xbb, 0x7d, 0x36, 0x1e, 0x1b, 0xae, 0xc0, 0xa9, 0x75, 0x80, 0x3f, 0x30, 0x6c, 0x83, 0x5d, 0xb2, + 0xdb, 0xed, 0x33, 0xe0, 0x20, 0x14, 0xdb, 0x60, 0x76, 0xb1, 0x72, 0xe4, 0x52, 0xac, 0x86, 0xde, 0x91, 0x80, 0x55, + 0xb7, 0xc3, 0x52, 0xec, 0x52, 0x1f, 0x15, 0x82, 0x51, 0x2f, 0xfa, 0x97, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, + 0xb2, 0xaa, 0x56, 0x65, 0xb4, 0xbf, 0x1f, 0xaf, 0xb2, 0x51, 0x99, 0xc1, 0x36, 0x2f, 0xaf, 0x2f, 0x01, 0x50, 0x21, + 0xa0, 0x8d, 0x77, 0x6b, 0x91, 0x99, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0xad, 0x6e, 0x72, + 0x4a, 0xec, 0x03, 0xd8, 0x1c, 0x6e, 0xb7, 0x0d, 0x7e, 0xe1, 0x68, 0xf4, 0x6c, 0xb6, 0xcc, 0xb4, 0x41, 0x27, 0x37, + 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, 0xc9, 0xf4, 0x65, 0x06, 0x7c, 0x1e, 0x7b, 0x2b, 0x42, 0x9f, 0xe5, 0x6a, + 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x32, 0x23, 0xbe, 0x4d, + 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x56, 0x78, 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x12, 0x85, 0xa8, + 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x9a, 0x3a, 0x73, 0x19, 0x5f, 0xb8, + 0xf7, 0xd2, 0x97, 0x99, 0xdc, 0x4a, 0x00, 0x45, 0x52, 0xb5, 0xff, 0xf2, 0x19, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, + 0xe8, 0xfd, 0x02, 0x35, 0x39, 0x82, 0x80, 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, + 0x6d, 0x54, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, 0x4f, 0xd7, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, + 0x1b, 0x21, 0xeb, 0x97, 0x66, 0x17, 0x7e, 0x2e, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, + 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, 0x1e, 0x73, 0x82, 0x3f, 0x3d, 0x78, 0x4a, 0xe8, 0xad, 0x9c, 0x96, 0x08, + 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, + 0x6c, 0xd9, 0x6f, 0x4d, 0xd9, 0x92, 0x6c, 0x04, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbc, 0xdf, 0xa0, + 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, + 0x9c, 0x85, 0xed, 0x76, 0x42, 0x7c, 0x09, 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, + 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x20, 0xa0, 0xc7, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x8e, 0xf9, 0x20, 0x18, + 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x57, 0x05, 0x43, 0x58, 0xa1, 0xbf, + 0x52, 0x36, 0xf9, 0xe6, 0xef, 0x6e, 0x7e, 0xcf, 0xb5, 0x98, 0x1d, 0x84, 0xe2, 0xf6, 0x7a, 0x02, 0xc4, 0xaf, 0xe2, + 0x57, 0x60, 0x5d, 0xad, 0x25, 0xde, 0x6e, 0x7a, 0xfe, 0x14, 0xbe, 0x1c, 0xdd, 0x7e, 0x52, 0x9a, 0x4f, 0x20, 0x48, + 0x8d, 0x93, 0x94, 0xbb, 0xef, 0x3e, 0x4a, 0x57, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xdd, 0x5b, 0xc9, 0x59, 0x53, 0xf8, + 0x8f, 0x75, 0xbe, 0xc7, 0xd8, 0x21, 0xf2, 0x14, 0xa7, 0xbf, 0x01, 0x86, 0x7d, 0xe7, 0xdf, 0xca, 0xac, 0x21, 0xd1, + 0xb9, 0xfa, 0x08, 0xe8, 0xff, 0x58, 0x8f, 0xdf, 0x31, 0x4a, 0xfa, 0x92, 0x38, 0x47, 0xb8, 0x22, 0x5e, 0xa2, 0xa9, + 0x5e, 0x6f, 0x5c, 0xd3, 0x4f, 0x85, 0x79, 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0x9b, 0x68, + 0x08, 0xba, 0x7f, 0xc7, 0xbd, 0xf1, 0x9b, 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, + 0x1b, 0xc6, 0x82, 0xb5, 0x50, 0xe6, 0xab, 0x69, 0x30, 0xdb, 0xd4, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x6d, 0x9c, 0xb0, + 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, + 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x71, 0x05, 0xbb, 0xcc, + 0x57, 0x52, 0xfc, 0xd9, 0x92, 0x64, 0x63, 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, + 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, + 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x63, 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0xa7, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, + 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, 0x53, 0xba, 0x9b, 0xd3, 0xfe, 0xab, 0x82, 0x0c, 0xff, 0x02, 0xef, 0xae, + 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, + 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, 0xe4, 0xad, 0xc6, 0x6c, 0xca, 0xfd, 0x0f, 0x60, 0x44, 0xb5, 0xb4, 0xdd, + 0x0e, 0xf8, 0x72, 0x84, 0x06, 0xdb, 0xa9, 0x1b, 0xec, 0x7e, 0xdf, 0xa4, 0x1d, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, + 0x51, 0xda, 0x2c, 0x95, 0x41, 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x92, 0xc6, 0x56, + 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, + 0xed, 0x36, 0x84, 0x08, 0x1c, 0xc5, 0x70, 0x32, 0x0b, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0xa9, 0x98, + 0x67, 0x0b, 0x85, 0xd8, 0xe3, 0xef, 0xa4, 0xdf, 0x0a, 0xc5, 0x29, 0xf7, 0x7e, 0x13, 0x64, 0xf3, 0x7b, 0x8a, 0x31, + 0x07, 0x9d, 0x66, 0x33, 0x03, 0x09, 0xeb, 0x71, 0x45, 0xd4, 0x3a, 0xb2, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, + 0x75, 0x8b, 0x27, 0xd6, 0x33, 0x7a, 0x0f, 0x2a, 0x41, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x3e, 0x89, 0x50, 0x52, + 0x4e, 0x9a, 0xcc, 0x8c, 0x15, 0x0d, 0x16, 0x20, 0x24, 0x8d, 0xcb, 0xea, 0x8d, 0x4c, 0xb3, 0x8b, 0x0c, 0x10, 0x13, + 0x9c, 0xff, 0x9c, 0x6c, 0xbc, 0x79, 0xae, 0xe6, 0xa5, 0x2b, 0x71, 0x66, 0x61, 0x3e, 0xba, 0xde, 0xd2, 0x82, 0x44, + 0x05, 0xd0, 0x28, 0x5f, 0xcb, 0xf3, 0xd3, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x65, 0x3b, 0xc4, 0x8f, 0x58, 0x45, + 0xbc, 0xd3, 0xba, 0x52, 0x22, 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xa8, 0xe1, 0x83, 0x30, 0x83, 0x4e, + 0xf2, 0x83, 0x9e, 0xd1, 0xb1, 0x35, 0x90, 0xf4, 0xb5, 0x08, 0xbe, 0x46, 0x47, 0x3a, 0x51, 0xa6, 0x91, 0x98, 0x42, + 0xa2, 0x5f, 0x2f, 0xb4, 0xc6, 0x32, 0xca, 0xbe, 0x22, 0xff, 0x7b, 0xdd, 0xbd, 0xdf, 0xc4, 0x76, 0x0b, 0x93, 0xec, + 0x79, 0x5c, 0xc1, 0xa6, 0x46, 0xad, 0x10, 0xce, 0xce, 0x71, 0x85, 0xda, 0xb1, 0x5e, 0x58, 0x02, 0x79, 0x00, 0x5b, + 0x91, 0x06, 0x65, 0x90, 0xec, 0x53, 0x31, 0x17, 0x0b, 0x27, 0xca, 0x91, 0x0a, 0xef, 0x4b, 0x8e, 0x52, 0x0e, 0x57, + 0xb1, 0xb0, 0x60, 0xc8, 0xaf, 0x8e, 0x2e, 0x0a, 0x79, 0x05, 0x92, 0x12, 0xc3, 0x50, 0x59, 0x5e, 0x17, 0x57, 0x6d, + 0x49, 0x68, 0xef, 0x0c, 0x40, 0x58, 0x0a, 0x10, 0xbc, 0x34, 0x6a, 0x88, 0xd9, 0x46, 0xed, 0xae, 0xe8, 0x5e, 0x72, + 0x40, 0x9d, 0xee, 0xda, 0xad, 0x37, 0x65, 0x9b, 0x6d, 0xc5, 0x85, 0x7f, 0x42, 0xe9, 0xc7, 0x7c, 0x50, 0xf8, 0x54, + 0x02, 0x37, 0xbe, 0xda, 0x64, 0xd9, 0xc5, 0x1d, 0x2e, 0xfd, 0xaa, 0x31, 0x7e, 0xfd, 0x7e, 0x4f, 0x2d, 0x84, 0x46, + 0x2a, 0x30, 0xdf, 0x3e, 0x33, 0x55, 0x19, 0x4d, 0xa9, 0xbd, 0x04, 0x57, 0xce, 0x7e, 0x04, 0x15, 0x71, 0x5d, 0x91, + 0xc9, 0xd4, 0x00, 0xed, 0x79, 0x59, 0xe1, 0x56, 0x16, 0xe0, 0xb1, 0x13, 0x90, 0xed, 0x96, 0x87, 0x81, 0x3e, 0x74, + 0x02, 0x7f, 0x4b, 0x9e, 0x22, 0xb3, 0x66, 0x1f, 0x7f, 0xd1, 0x82, 0x7f, 0x6c, 0xc1, 0xcf, 0x28, 0xee, 0xb4, 0x32, + 0xff, 0x56, 0x5a, 0xb7, 0xb8, 0x7f, 0x27, 0xd3, 0x84, 0xa2, 0x32, 0xa1, 0xf6, 0x2b, 0xfd, 0x97, 0x09, 0x96, 0xa4, + 0xb2, 0x7f, 0x90, 0xf0, 0xc1, 0xac, 0xf1, 0xc4, 0x1a, 0x4f, 0x86, 0xd3, 0xad, 0x34, 0x0c, 0x01, 0x0a, 0xfd, 0xbc, + 0xcc, 0x15, 0xd5, 0xcf, 0xbf, 0xac, 0xf9, 0x9a, 0x37, 0x5b, 0x6c, 0x93, 0x1e, 0x68, 0xb0, 0x97, 0x47, 0x53, 0x0a, + 0x27, 0x51, 0xe7, 0x46, 0xa2, 0x2e, 0x6a, 0x96, 0xa1, 0x3a, 0xc1, 0xab, 0x79, 0xaa, 0x87, 0xbd, 0x99, 0x88, 0xd6, + 0x4a, 0xca, 0x12, 0x03, 0xd6, 0x3a, 0xf2, 0x90, 0xdc, 0xad, 0x75, 0xdc, 0x69, 0xa8, 0x4b, 0x53, 0x28, 0x01, 0x56, + 0xb8, 0x00, 0x47, 0xd0, 0xcf, 0x45, 0xc8, 0xe1, 0x9a, 0xaa, 0xf4, 0x0b, 0x9a, 0x92, 0x27, 0x9e, 0xa2, 0x56, 0x2b, + 0xd2, 0xed, 0x47, 0x39, 0x76, 0xc3, 0x37, 0x4e, 0xc8, 0x89, 0x11, 0xfa, 0xbb, 0x63, 0x29, 0x67, 0x68, 0xf1, 0xa0, + 0x4e, 0xb0, 0x5e, 0xde, 0x52, 0xa0, 0x98, 0xa3, 0xcb, 0xaa, 0x6b, 0x5e, 0xa3, 0xed, 0xcb, 0xb2, 0xdf, 0xcf, 0x6d, + 0x3d, 0x29, 0x3b, 0xda, 0x2c, 0xcd, 0x3e, 0x44, 0xc5, 0x14, 0xee, 0xfa, 0x44, 0xf3, 0x57, 0xa1, 0xbe, 0x6a, 0xcb, + 0x9c, 0x8f, 0x38, 0xe2, 0x62, 0xe4, 0xa4, 0xfe, 0x45, 0x4d, 0xbd, 0x12, 0xf7, 0xab, 0x4a, 0xbe, 0x13, 0xc6, 0x8a, + 0xd1, 0x01, 0xf5, 0xa7, 0x4a, 0xe5, 0xfd, 0xb2, 0x00, 0xb8, 0x27, 0xc1, 0x3e, 0x81, 0x7d, 0x85, 0x46, 0xf8, 0x6d, + 0x09, 0xf8, 0x37, 0x8a, 0x1b, 0xb0, 0x0a, 0x0c, 0x30, 0x9a, 0x6c, 0xcf, 0x69, 0x02, 0x07, 0x9c, 0xd0, 0x2a, 0x0a, + 0x2a, 0xcc, 0xd0, 0x50, 0x5b, 0x18, 0x3d, 0x45, 0x19, 0xb7, 0xca, 0xec, 0xdd, 0x18, 0x3b, 0x2d, 0xf0, 0x1a, 0xfe, + 0x7c, 0x5e, 0xe8, 0x61, 0xa3, 0x0e, 0xd2, 0xa3, 0x93, 0x98, 0xfe, 0xb8, 0x85, 0x93, 0x9b, 0x85, 0xb3, 0xac, 0x59, + 0x02, 0xdd, 0x81, 0x0b, 0x62, 0xdc, 0xef, 0xe7, 0x70, 0x64, 0x9a, 0x91, 0x2f, 0x58, 0x4e, 0x63, 0xb6, 0xa4, 0xda, + 0xd3, 0xee, 0xb2, 0x0a, 0x73, 0xba, 0xb4, 0x32, 0xde, 0x94, 0x81, 0xca, 0x68, 0xbb, 0x0d, 0xe1, 0x4f, 0xb7, 0xb5, + 0x4b, 0x3a, 0x5f, 0x42, 0x06, 0xf8, 0x03, 0x12, 0x51, 0xc4, 0xbe, 0xfe, 0xb7, 0x1a, 0xa7, 0xf4, 0x44, 0x69, 0xcd, + 0x12, 0xba, 0x66, 0xba, 0x7e, 0x7a, 0xc1, 0xd6, 0x8d, 0xa5, 0xb0, 0xdd, 0x86, 0xcd, 0x04, 0xa6, 0x39, 0x57, 0x32, + 0xbd, 0x40, 0x9d, 0x14, 0x50, 0xb1, 0xf0, 0x02, 0x97, 0x5f, 0x4a, 0x28, 0x34, 0x77, 0xbe, 0x5c, 0x18, 0x25, 0x26, + 0xb4, 0x4a, 0x7e, 0xf9, 0x50, 0x99, 0xaf, 0x8d, 0x47, 0xdc, 0xbf, 0xd2, 0x30, 0x31, 0x45, 0xa2, 0x42, 0x74, 0xf6, + 0x1b, 0xc8, 0x72, 0x04, 0xe0, 0x58, 0x9e, 0xca, 0x9a, 0xfe, 0x98, 0x42, 0x1c, 0x74, 0x68, 0xd0, 0xbb, 0x42, 0x5e, + 0x65, 0x25, 0x0f, 0xf1, 0x9e, 0xe0, 0x69, 0x46, 0xef, 0x37, 0xf8, 0xd0, 0xd6, 0x1e, 0x3d, 0x41, 0x36, 0x9e, 0x72, + 0xbf, 0xfe, 0x4e, 0x84, 0x73, 0x88, 0x56, 0xb9, 0xa0, 0x5a, 0x5d, 0xed, 0x00, 0xa8, 0x3c, 0xdb, 0xab, 0x47, 0x70, + 0xba, 0xe9, 0xeb, 0x5b, 0x15, 0x3a, 0x73, 0x00, 0x69, 0x0f, 0xc9, 0xba, 0xe6, 0x7a, 0x07, 0xb8, 0x23, 0xb1, 0x5a, + 0x03, 0x8d, 0x75, 0x5b, 0xb3, 0xd3, 0x1e, 0xc5, 0x63, 0x22, 0x33, 0x63, 0x91, 0x62, 0xcc, 0xdd, 0x3a, 0x2d, 0x8a, + 0x36, 0x68, 0x86, 0xb0, 0x7b, 0xd7, 0xe1, 0xeb, 0x56, 0x84, 0xf5, 0xfb, 0x6d, 0x5f, 0x60, 0x34, 0x8c, 0xb9, 0x76, + 0xcf, 0x33, 0x74, 0xc3, 0x06, 0xdb, 0xc8, 0x79, 0x88, 0x7c, 0x98, 0xa9, 0x03, 0x51, 0xd6, 0xd6, 0x80, 0xed, 0x11, + 0xd7, 0x9b, 0x56, 0xf1, 0xf3, 0x2a, 0xe6, 0x6c, 0xcf, 0x1a, 0xa7, 0xb4, 0xbe, 0xc6, 0x35, 0xc7, 0x55, 0x21, 0xa2, + 0xb6, 0x9e, 0xf1, 0x30, 0xec, 0x7c, 0x81, 0x3b, 0xb3, 0xc2, 0xe0, 0x45, 0x58, 0x2a, 0xd9, 0xa9, 0x5c, 0x7f, 0x0e, + 0x5b, 0x1c, 0xa4, 0xf2, 0xa5, 0xd7, 0xdf, 0x7f, 0xf9, 0xe2, 0x0b, 0x74, 0x53, 0x73, 0x7e, 0x04, 0x41, 0x26, 0xd0, + 0x21, 0x4b, 0xa9, 0x1e, 0xbf, 0x2b, 0x80, 0xda, 0xc3, 0x3c, 0x7c, 0x57, 0x30, 0x11, 0x5f, 0x67, 0x97, 0x71, 0x25, + 0x8b, 0xd1, 0x35, 0x17, 0xa9, 0x2c, 0xac, 0xd4, 0x38, 0x38, 0x5e, 0xad, 0x72, 0x1e, 0x80, 0xa9, 0xbc, 0x65, 0x94, + 0x6d, 0x65, 0x99, 0x1e, 0x5c, 0x2d, 0x4f, 0xaf, 0xb4, 0xe8, 0xbc, 0xbc, 0xbe, 0x0c, 0x22, 0xfc, 0x75, 0x6e, 0x7e, + 0x5c, 0xc5, 0xe5, 0xc7, 0x20, 0xb2, 0x36, 0x75, 0xe6, 0x07, 0x4a, 0xe5, 0xc1, 0x7f, 0x0a, 0x64, 0xba, 0xdf, 0x15, + 0x60, 0x99, 0x6d, 0x2b, 0x3e, 0x8c, 0xb1, 0xd6, 0xe1, 0x84, 0xcc, 0x54, 0x89, 0xde, 0xbb, 0x64, 0x5d, 0x80, 0xb5, + 0x9f, 0xc2, 0x32, 0x56, 0xb9, 0x66, 0x58, 0x99, 0xaa, 0xc8, 0xcc, 0xca, 0x9a, 0xed, 0x87, 0xd6, 0x89, 0x66, 0x8e, + 0xde, 0x02, 0xfa, 0x81, 0xec, 0x5f, 0xd2, 0x72, 0xcd, 0x3c, 0x1f, 0x9b, 0xc6, 0xeb, 0x47, 0xfb, 0x97, 0x6e, 0xc1, + 0xde, 0xda, 0x3b, 0x39, 0x0a, 0x13, 0xc1, 0xb3, 0xd6, 0x8c, 0x2f, 0xf2, 0xac, 0x80, 0x95, 0x33, 0x19, 0x8f, 0xa9, + 0xb7, 0xb4, 0x5a, 0x37, 0x47, 0x87, 0xe4, 0x9a, 0x3d, 0xae, 0x1e, 0x73, 0xb2, 0xcf, 0x5b, 0xa6, 0xb6, 0x6d, 0xeb, + 0x38, 0x4f, 0x93, 0xaf, 0x4c, 0xf7, 0xc5, 0xda, 0x46, 0x44, 0x57, 0xce, 0x7d, 0xce, 0x2b, 0xb8, 0xf5, 0x4d, 0x69, + 0xe8, 0xb5, 0x04, 0x20, 0x3a, 0x6d, 0xc0, 0x5f, 0xb0, 0x72, 0x3d, 0xaa, 0x78, 0x59, 0x81, 0x84, 0x05, 0x45, 0x78, + 0x53, 0xec, 0x4d, 0xe1, 0x6e, 0x9c, 0x9e, 0xc3, 0x0e, 0x5c, 0x4c, 0xd1, 0x1d, 0x27, 0x26, 0xb3, 0xd2, 0x68, 0x45, + 0x23, 0xfd, 0xcb, 0xf5, 0x25, 0xd6, 0x7d, 0xd1, 0xca, 0x3c, 0x9b, 0x53, 0x61, 0xb1, 0xbb, 0xca, 0xa5, 0x13, 0xf5, + 0x5b, 0x26, 0x5c, 0xb9, 0x12, 0x04, 0x64, 0x5a, 0xb0, 0x5e, 0x61, 0x76, 0x91, 0x5c, 0x03, 0x21, 0x03, 0xc3, 0xd7, + 0x60, 0x2d, 0x4a, 0x6e, 0xac, 0x60, 0xbd, 0x7b, 0xbe, 0x4e, 0x10, 0x52, 0xf0, 0xc0, 0x4d, 0xd0, 0x0f, 0xad, 0x9b, + 0xb7, 0xa3, 0x44, 0x19, 0xc4, 0xe3, 0xd6, 0x4e, 0x39, 0x48, 0x20, 0x00, 0xf7, 0x54, 0x85, 0xe0, 0x50, 0x20, 0xeb, + 0xe0, 0x6a, 0xc6, 0x11, 0x5c, 0x5d, 0x39, 0x73, 0x71, 0x03, 0xb0, 0xae, 0xfc, 0xb9, 0x6c, 0x70, 0x61, 0x3d, 0xa2, + 0xca, 0x9c, 0x71, 0x8a, 0x41, 0x8c, 0x2c, 0x41, 0x5f, 0x59, 0x4a, 0x7b, 0x09, 0x9a, 0xc6, 0x2b, 0xb6, 0x52, 0x3e, + 0x00, 0xf4, 0x9c, 0xad, 0x94, 0xb1, 0x3f, 0x7e, 0x7d, 0xc6, 0x56, 0x5a, 0x1a, 0x3c, 0xbd, 0x9a, 0x9d, 0xcf, 0xce, + 0x06, 0xec, 0x20, 0x0a, 0xb5, 0x01, 0x43, 0xe0, 0x90, 0xf8, 0x83, 0x41, 0xa8, 0xf1, 0x4e, 0x06, 0x2a, 0x20, 0x16, + 0xf1, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, 0x43, 0x0c, 0x7e, 0xd5, 0x7c, 0x41, 0x02, 0x42, 0x4d, 0x69, 0xe8, 0xf2, + 0x18, 0x0e, 0x27, 0x7b, 0x13, 0x48, 0xc5, 0xcc, 0x4c, 0x15, 0xc6, 0xc6, 0x24, 0x82, 0x78, 0xa7, 0x9d, 0xf5, 0x42, + 0xb9, 0xdd, 0x35, 0x1a, 0xc8, 0x95, 0xc1, 0x17, 0x55, 0x3c, 0xd9, 0x1b, 0x76, 0x55, 0x8c, 0xa3, 0x70, 0x6d, 0x94, + 0x6f, 0x67, 0x87, 0x00, 0x5e, 0x7b, 0x36, 0xf4, 0xe5, 0x12, 0x67, 0xfb, 0x4f, 0xc9, 0xe3, 0xa7, 0x84, 0x9e, 0xb1, + 0xb3, 0xaf, 0x9e, 0xd2, 0x33, 0x45, 0x4e, 0xf6, 0x26, 0xd1, 0x35, 0xb3, 0x98, 0x2f, 0x07, 0xaa, 0x09, 0xf4, 0x72, + 0xb4, 0x16, 0x6a, 0x81, 0x69, 0x87, 0xa6, 0xf0, 0xdb, 0xf1, 0x5e, 0x30, 0xb8, 0x6e, 0x37, 0xfd, 0xba, 0xdd, 0x56, + 0xcf, 0xab, 0x6b, 0xef, 0x20, 0xda, 0x2d, 0x66, 0xf2, 0xf7, 0xf1, 0x9e, 0x9b, 0x03, 0xac, 0xef, 0xe1, 0x31, 0x31, + 0x4d, 0xda, 0x19, 0x15, 0xbf, 0xa6, 0x27, 0xd8, 0x87, 0x66, 0x91, 0x1d, 0x7d, 0x18, 0xfe, 0x5b, 0x9d, 0xa8, 0xcf, + 0xbe, 0x3a, 0x00, 0x72, 0x04, 0x32, 0x50, 0x2c, 0x11, 0xcc, 0x70, 0xa0, 0x29, 0xa0, 0x20, 0xd3, 0xe3, 0x4e, 0xf5, + 0xf0, 0xab, 0x51, 0x53, 0x33, 0x72, 0x0d, 0x53, 0x83, 0x6d, 0xc1, 0x0f, 0x54, 0x37, 0xf4, 0x37, 0x1a, 0xdd, 0x48, + 0x3b, 0x99, 0x99, 0x97, 0xd4, 0xc6, 0x75, 0xbb, 0x86, 0x00, 0xc6, 0x0e, 0x5e, 0x50, 0xb2, 0xaf, 0x0f, 0x2f, 0xf7, + 0x70, 0x15, 0x01, 0x4a, 0x16, 0x0b, 0xbe, 0x1e, 0x5c, 0xea, 0xcd, 0xbd, 0x17, 0x90, 0xc1, 0xd7, 0xc1, 0xd1, 0xd7, + 0x03, 0x39, 0x08, 0x0e, 0xf7, 0x2f, 0x8f, 0x02, 0x67, 0xdc, 0x0f, 0x21, 0x1e, 0x55, 0x45, 0x31, 0x13, 0xa6, 0x8a, + 0xc4, 0xd6, 0x9e, 0xdb, 0x7a, 0x95, 0xf1, 0x19, 0x4d, 0xa7, 0x16, 0xf9, 0x3b, 0x4c, 0x59, 0x6c, 0x7e, 0x07, 0x13, + 0x7e, 0x15, 0x44, 0x2e, 0x08, 0xea, 0x2c, 0x8f, 0x62, 0xba, 0x64, 0xb7, 0x22, 0x4c, 0x69, 0xb2, 0x9f, 0x13, 0x12, + 0x85, 0x4b, 0x05, 0x9e, 0xa7, 0x5e, 0x27, 0x10, 0xc7, 0xd5, 0x7d, 0x7e, 0x2b, 0xc2, 0x25, 0xcd, 0xf7, 0x13, 0xd2, + 0x2a, 0xc2, 0x45, 0x64, 0xd9, 0xd4, 0xf4, 0x82, 0x85, 0x2b, 0x7a, 0x09, 0xcc, 0x94, 0x5c, 0x87, 0x97, 0xc0, 0xe5, + 0xad, 0xe7, 0xab, 0x05, 0xbb, 0x6c, 0x48, 0xdf, 0x0c, 0x5f, 0x7c, 0x61, 0x7d, 0xf2, 0x80, 0x87, 0x74, 0x7e, 0x78, + 0x29, 0xd8, 0x00, 0x5c, 0x67, 0xfc, 0xe6, 0x3b, 0x79, 0xab, 0xe7, 0xa5, 0x3d, 0xc5, 0x38, 0x33, 0xed, 0xc4, 0xa4, + 0x9d, 0x90, 0xfb, 0xf7, 0xed, 0x4d, 0x6c, 0x4e, 0xf6, 0x32, 0x5a, 0x2b, 0x97, 0x55, 0xcb, 0x90, 0x14, 0x6b, 0x86, + 0xfc, 0x3d, 0x4a, 0x4e, 0xad, 0xc0, 0x93, 0x5d, 0xf0, 0x2a, 0x59, 0xfa, 0x07, 0x95, 0xb5, 0x1a, 0xb0, 0xc7, 0x88, + 0x65, 0xa1, 0x70, 0xec, 0xdf, 0x64, 0xac, 0x58, 0xfb, 0x02, 0x8d, 0x18, 0xb9, 0xb7, 0x37, 0x19, 0xf3, 0x62, 0xae, + 0x26, 0x6b, 0x2f, 0x54, 0x9d, 0x97, 0x9e, 0xb7, 0x78, 0x2f, 0xa7, 0xd4, 0x30, 0x12, 0xd1, 0xbd, 0xb1, 0x32, 0xa3, + 0x54, 0x89, 0x5a, 0x83, 0x46, 0x04, 0x1b, 0xbb, 0xe0, 0x97, 0xe0, 0x84, 0xca, 0x3d, 0x75, 0xb6, 0x6f, 0xa7, 0x54, + 0x7a, 0xc0, 0xb2, 0xd4, 0xa8, 0xca, 0xdd, 0x32, 0x93, 0xac, 0x1a, 0x04, 0xa3, 0x3f, 0x4b, 0x29, 0x66, 0x78, 0x67, + 0x64, 0xc1, 0x14, 0xac, 0x04, 0x55, 0x2d, 0xc3, 0x72, 0xc8, 0x51, 0x8b, 0x67, 0x7c, 0x52, 0xa5, 0xfe, 0xd1, 0x11, + 0x24, 0x77, 0xb9, 0x6e, 0x05, 0xc9, 0x7d, 0x3a, 0x7e, 0xaa, 0x07, 0x3a, 0x5d, 0x6b, 0xc7, 0x43, 0x9f, 0xdf, 0x46, + 0x7c, 0x6d, 0xdd, 0x7b, 0xaa, 0xb5, 0x0a, 0x65, 0xa0, 0xc5, 0x8a, 0xca, 0x95, 0x5a, 0xd2, 0xfb, 0x5d, 0x04, 0xc0, + 0x22, 0x36, 0x66, 0xe3, 0x5d, 0xdb, 0xac, 0x10, 0x34, 0xba, 0xec, 0x68, 0x13, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, + 0xd0, 0xf8, 0x88, 0x95, 0xfd, 0x7e, 0x7e, 0x04, 0xf4, 0x54, 0x1b, 0x31, 0x15, 0x70, 0xe4, 0x7f, 0x69, 0x45, 0xa6, + 0x28, 0xb0, 0x59, 0x53, 0x77, 0x6b, 0x2c, 0x23, 0xd1, 0x97, 0x29, 0x5d, 0x9e, 0xf0, 0x0c, 0x98, 0xd6, 0xeb, 0x96, + 0xe3, 0xca, 0xae, 0xe2, 0xc8, 0x53, 0x61, 0x59, 0x71, 0x5e, 0x85, 0xe3, 0xad, 0xc7, 0x37, 0xd8, 0x37, 0x6c, 0xda, + 0x85, 0x3f, 0x84, 0xb0, 0x10, 0xde, 0x64, 0x70, 0x1b, 0xd1, 0x76, 0x12, 0xa8, 0xbc, 0x31, 0xd7, 0x09, 0x65, 0x73, + 0xbb, 0x5e, 0x7b, 0x06, 0xe9, 0xc4, 0x1c, 0x28, 0xd5, 0x08, 0x5a, 0xa3, 0x59, 0x50, 0x35, 0xe2, 0x91, 0xe3, 0xe1, + 0x9d, 0x41, 0xac, 0x96, 0x2f, 0x69, 0x2a, 0x45, 0x03, 0x30, 0x2e, 0x80, 0xcb, 0xd3, 0xaf, 0xef, 0x7f, 0x3e, 0xe5, + 0x71, 0x91, 0x2c, 0xdf, 0xc5, 0x45, 0x7c, 0x55, 0x86, 0x1b, 0x35, 0x46, 0x71, 0x4d, 0xa6, 0x62, 0xc0, 0xa4, 0x59, + 0x49, 0xcd, 0x5d, 0xa9, 0x09, 0x31, 0xd6, 0x99, 0xac, 0xcb, 0x4a, 0x5e, 0x35, 0x2a, 0x5d, 0x17, 0x19, 0x7e, 0xdc, + 0xf2, 0x39, 0xdd, 0x07, 0x20, 0x4f, 0xe3, 0x42, 0x1a, 0x49, 0x5d, 0x88, 0x31, 0x17, 0xf1, 0xba, 0x3e, 0x1e, 0x37, + 0xba, 0x5e, 0xb2, 0x67, 0xe3, 0x27, 0xd3, 0x37, 0x59, 0x98, 0x0d, 0x04, 0x19, 0x55, 0x4b, 0x2e, 0x5a, 0xa6, 0x9c, + 0xca, 0x24, 0x00, 0x7d, 0x3c, 0x7b, 0x8c, 0x1d, 0x8c, 0xc7, 0x64, 0xd3, 0x16, 0x0f, 0xf0, 0x70, 0xb9, 0x0e, 0x0b, + 0x32, 0xd3, 0x75, 0x44, 0x81, 0xe0, 0xb7, 0x55, 0x00, 0x48, 0x8e, 0xb6, 0x2a, 0xc3, 0xa5, 0xb1, 0x67, 0xe3, 0x09, + 0x95, 0xd8, 0xed, 0x90, 0xd4, 0x5e, 0x85, 0x6e, 0xe6, 0xa5, 0xef, 0x51, 0x24, 0x8d, 0xcb, 0xd2, 0x4e, 0xa5, 0x52, + 0xed, 0x99, 0x99, 0xeb, 0x1a, 0xc4, 0x60, 0x08, 0x75, 0xdd, 0xa5, 0x57, 0xf7, 0x6e, 0x73, 0xad, 0xd9, 0x0e, 0x78, + 0xaf, 0x41, 0x33, 0x94, 0xbc, 0xc5, 0xbc, 0x75, 0x45, 0xd4, 0x74, 0xb5, 0x06, 0xb3, 0x62, 0x94, 0x2d, 0x45, 0xe9, + 0x9a, 0x82, 0x52, 0x30, 0xba, 0x58, 0x7b, 0x0b, 0xf7, 0x8d, 0x6c, 0x5c, 0x58, 0x32, 0xbd, 0x5a, 0x94, 0x94, 0x50, + 0xdd, 0x54, 0x8c, 0x94, 0x30, 0x52, 0x1a, 0x9e, 0xca, 0xf7, 0x02, 0x8f, 0xf3, 0x3c, 0x88, 0x5a, 0x5e, 0x60, 0xc7, + 0x15, 0x39, 0x06, 0x47, 0x2f, 0x93, 0xd3, 0x50, 0xe0, 0x1f, 0x33, 0x05, 0x62, 0x3a, 0x54, 0xf7, 0x1b, 0xdc, 0xfc, + 0xff, 0x28, 0x58, 0xe0, 0xf1, 0xad, 0x97, 0xb8, 0x8d, 0xfe, 0x51, 0xf8, 0xb4, 0xf4, 0xb9, 0xf4, 0x5d, 0x5d, 0x3c, + 0x69, 0x6f, 0x36, 0x4a, 0x96, 0x59, 0x9e, 0xbe, 0x95, 0x29, 0x07, 0x91, 0x19, 0x5a, 0x83, 0xb2, 0x23, 0xd1, 0xb8, + 0xe1, 0x81, 0x11, 0x63, 0xe3, 0xc6, 0xf7, 0x63, 0x06, 0xb2, 0x61, 0xb0, 0xfa, 0x66, 0xa9, 0x4c, 0xd6, 0x57, 0x80, + 0x29, 0xa2, 0xe4, 0x27, 0x2f, 0x73, 0x0e, 0x4f, 0xa1, 0xbe, 0x7e, 0x81, 0xdb, 0x5c, 0xe9, 0xfb, 0x9c, 0xff, 0x98, + 0xd1, 0x1f, 0x11, 0xe8, 0x24, 0x5e, 0x81, 0xdc, 0xe3, 0x39, 0xd4, 0x8d, 0x30, 0xb5, 0x1c, 0x83, 0x03, 0x21, 0x1a, + 0x88, 0xa8, 0x58, 0xa0, 0xa0, 0x2e, 0x0c, 0xb0, 0x86, 0xba, 0x60, 0x0e, 0xcf, 0x73, 0x99, 0x7c, 0x9c, 0x1a, 0x9f, + 0xf9, 0x61, 0x8c, 0x31, 0x93, 0x83, 0x41, 0x58, 0xcd, 0x82, 0xe1, 0x78, 0x34, 0x39, 0x78, 0x06, 0xe7, 0x76, 0x30, + 0x0e, 0xc8, 0x20, 0xa8, 0xcb, 0x55, 0x2c, 0x68, 0x79, 0x7d, 0x69, 0xcb, 0xc0, 0x8f, 0xeb, 0x60, 0xf0, 0x8f, 0xc2, + 0x53, 0xbc, 0x83, 0xe6, 0xe4, 0x4c, 0x86, 0x60, 0x63, 0xbf, 0x26, 0x20, 0x29, 0xeb, 0x69, 0x7e, 0x52, 0x1f, 0x6e, + 0x4c, 0x69, 0xff, 0xcc, 0xe1, 0x05, 0x87, 0x1d, 0x12, 0x28, 0x90, 0xc6, 0xd3, 0x6c, 0xf4, 0x5a, 0x29, 0x72, 0xdf, + 0x15, 0x1c, 0xee, 0xcc, 0x3d, 0x67, 0x7a, 0xe4, 0x14, 0x12, 0xcd, 0x2c, 0xe0, 0x46, 0xfe, 0x5a, 0x5c, 0xc7, 0x79, + 0x96, 0xee, 0x35, 0xdf, 0xec, 0x95, 0x77, 0xa2, 0x8a, 0x6f, 0x47, 0x81, 0xb1, 0x26, 0xe4, 0xbe, 0xea, 0x09, 0xd0, + 0x13, 0x60, 0x0b, 0x80, 0x01, 0xf1, 0x8e, 0x99, 0xc9, 0x8c, 0x47, 0xe0, 0x11, 0xd8, 0xf4, 0x81, 0x2c, 0xee, 0x9c, + 0x4b, 0x92, 0xbf, 0x99, 0x4a, 0x7b, 0xd5, 0x2b, 0x77, 0x0a, 0xb2, 0x5e, 0x6d, 0xe5, 0xae, 0x5b, 0x9f, 0x7d, 0xd3, + 0xe1, 0x15, 0x78, 0x2e, 0xc1, 0x2d, 0xb2, 0xdf, 0x6f, 0x0a, 0x2a, 0x85, 0x51, 0x11, 0xef, 0x24, 0xd7, 0xe8, 0xdf, + 0xee, 0x8d, 0x8d, 0x22, 0xb9, 0xe5, 0xc3, 0x03, 0xa8, 0x33, 0x79, 0x57, 0xdc, 0xce, 0x21, 0x6a, 0xeb, 0x6e, 0x3c, + 0xb0, 0xda, 0xa0, 0x5d, 0xd6, 0x1c, 0xc1, 0x85, 0x17, 0x7b, 0x19, 0x8c, 0x05, 0xce, 0xca, 0x48, 0xa9, 0x71, 0x0d, + 0xa9, 0x05, 0x9f, 0xe4, 0xe9, 0x3d, 0x64, 0xa9, 0x27, 0x41, 0x91, 0xe3, 0x59, 0x0c, 0x99, 0xc6, 0xdb, 0xc0, 0xe3, + 0x77, 0x32, 0x04, 0x69, 0xda, 0x76, 0xdb, 0x1c, 0x81, 0xb2, 0x7b, 0x60, 0x4a, 0x52, 0xd7, 0xc6, 0xd4, 0x40, 0x43, + 0xed, 0xa1, 0x46, 0x2a, 0xe2, 0xec, 0xe8, 0x0d, 0xe8, 0x10, 0xc1, 0xf7, 0x3b, 0xcd, 0xca, 0x8e, 0x17, 0x13, 0x82, + 0x27, 0xef, 0xcb, 0xdb, 0xac, 0xac, 0xca, 0xe8, 0x7d, 0x8a, 0x86, 0x50, 0x89, 0x14, 0xd1, 0x2b, 0x88, 0xa7, 0x57, + 0xe2, 0xef, 0x32, 0xfa, 0x39, 0xa5, 0x71, 0x9a, 0x62, 0xfa, 0x8b, 0x02, 0x7e, 0x3e, 0x07, 0x54, 0x47, 0xdc, 0x09, + 0xd1, 0xb9, 0x04, 0x7b, 0x35, 0x88, 0x66, 0x55, 0x71, 0xc0, 0xd0, 0x8c, 0x6e, 0x05, 0x45, 0x8c, 0x36, 0xcc, 0xfe, + 0x43, 0x81, 0x42, 0x21, 0x55, 0xcc, 0x77, 0xc2, 0x3e, 0x44, 0x3f, 0x62, 0x91, 0xc7, 0xef, 0x5e, 0x9b, 0x21, 0x8d, + 0xee, 0x24, 0xd5, 0x5b, 0x1b, 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xae, 0xe9, 0x59, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, + 0x4f, 0xbc, 0x7b, 0xfd, 0x5c, 0x59, 0x98, 0xbc, 0xc8, 0x40, 0x71, 0x70, 0xfc, 0xee, 0xf5, 0x1b, 0x99, 0xae, 0x73, + 0x1e, 0x9d, 0x49, 0x24, 0xad, 0xc7, 0xef, 0x5e, 0xff, 0x82, 0xe6, 0x5e, 0x3f, 0x17, 0xf0, 0xfe, 0x15, 0xf0, 0x96, + 0x51, 0xbc, 0x86, 0x3e, 0xa9, 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd5, 0x5a, 0x46, 0xbf, 0xa6, 0xb5, 0x27, 0xad, 0xfa, + 0x67, 0xe1, 0x53, 0x3b, 0x4f, 0xc0, 0x73, 0x9b, 0x67, 0xe2, 0x63, 0x64, 0x45, 0x3b, 0x41, 0xf4, 0xf5, 0xde, 0xed, + 0x55, 0x2e, 0xca, 0x08, 0x5f, 0x30, 0xb4, 0x0b, 0x8a, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0x46, 0x37, 0x4f, 0x46, 0xb2, + 0xb8, 0xdc, 0x9f, 0x7c, 0xfb, 0xed, 0xb7, 0xfb, 0xf8, 0x36, 0xf8, 0xba, 0xed, 0xf6, 0x5e, 0x11, 0x3e, 0x60, 0x01, + 0x22, 0x54, 0x7f, 0x0d, 0x57, 0x14, 0xd0, 0xc2, 0x0d, 0xbe, 0x0e, 0xbe, 0xd6, 0x87, 0xce, 0xd7, 0x87, 0xe5, 0xf5, + 0xa5, 0x2a, 0xbf, 0xab, 0xe4, 0x83, 0xf1, 0x78, 0xbc, 0x0f, 0x12, 0xa8, 0xaf, 0x07, 0x7c, 0x10, 0x1c, 0x05, 0x83, + 0x0c, 0x2e, 0x34, 0xe5, 0xf5, 0xe5, 0x51, 0xe0, 0x99, 0xe6, 0x36, 0x58, 0x44, 0x07, 0xe2, 0x12, 0xec, 0x5f, 0xd2, + 0xe0, 0xeb, 0x80, 0xb8, 0x94, 0xaf, 0x20, 0xe5, 0xab, 0x83, 0x67, 0x7e, 0xda, 0xff, 0x52, 0x69, 0x4f, 0xfc, 0xb4, + 0x43, 0x4c, 0x7b, 0xf2, 0xdc, 0x4f, 0x3b, 0x52, 0x69, 0x2f, 0xfd, 0xb4, 0xff, 0x5d, 0x0e, 0x20, 0x75, 0xcf, 0xb7, + 0xfe, 0x3b, 0xf7, 0x5a, 0x83, 0xa7, 0x50, 0x94, 0x5d, 0xc5, 0x97, 0x1c, 0x1a, 0x3d, 0xb8, 0xbd, 0xca, 0x69, 0x30, + 0xc0, 0xf6, 0x7a, 0x26, 0x21, 0xde, 0x07, 0x5f, 0xaf, 0x8b, 0x3c, 0x0c, 0xbe, 0x1e, 0x60, 0x21, 0x83, 0xaf, 0x03, + 0xf2, 0xb5, 0x31, 0x90, 0x11, 0x6c, 0x13, 0xb8, 0x50, 0xa4, 0x43, 0x1b, 0x20, 0xcc, 0x97, 0xc6, 0xd5, 0xf4, 0xaf, + 0xa2, 0x3b, 0x1b, 0xde, 0x12, 0x95, 0x9b, 0x6e, 0x50, 0xd3, 0x13, 0xf0, 0x4e, 0x80, 0x46, 0x45, 0xc1, 0x75, 0x5c, + 0x84, 0xc3, 0x61, 0x79, 0x7d, 0x49, 0xc0, 0x2e, 0x73, 0xc5, 0xe3, 0x2a, 0x0a, 0x84, 0x1c, 0xaa, 0x9f, 0x81, 0x8a, + 0x7c, 0x15, 0x20, 0x20, 0x12, 0xfc, 0x17, 0xd4, 0xf4, 0x9d, 0x64, 0x9b, 0x60, 0x78, 0xc3, 0xcf, 0x3f, 0x66, 0xd5, + 0x50, 0x89, 0x16, 0xaf, 0x05, 0x85, 0x1f, 0xf0, 0xd7, 0x55, 0x1d, 0xfd, 0x05, 0x6e, 0xdc, 0x4d, 0x0d, 0xfb, 0x3b, + 0xe9, 0x58, 0xd4, 0x77, 0x72, 0x9e, 0x2d, 0xa6, 0xad, 0x03, 0xfd, 0x44, 0x92, 0x6a, 0x9e, 0x0d, 0x82, 0x61, 0x30, + 0xe0, 0x0b, 0x76, 0x22, 0xe7, 0xdc, 0x33, 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x65, 0x03, 0xf0, 0x4d, 0x41, 0x7e, + 0x64, 0xff, 0xbf, 0xe7, 0x43, 0x14, 0x1e, 0x0e, 0x1e, 0xed, 0x93, 0x59, 0xb0, 0xba, 0x45, 0x8f, 0xce, 0x28, 0xc8, + 0xc4, 0x92, 0x17, 0x59, 0xe5, 0x2d, 0x95, 0xbb, 0x75, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x15, 0x8b, 0x40, 0x9d, + 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb0, 0x37, 0x1c, + 0xee, 0x05, 0x03, 0xa7, 0xce, 0x1d, 0x04, 0x7b, 0xc3, 0xe1, 0x51, 0xe0, 0xee, 0x43, 0xd9, 0xc8, 0xdd, 0x19, 0x69, + 0xc1, 0xfe, 0x59, 0x84, 0x25, 0x05, 0xf1, 0x98, 0xd4, 0xe2, 0x2f, 0x0d, 0x2e, 0x33, 0x00, 0xe8, 0x23, 0x25, 0x01, + 0x33, 0xb0, 0x32, 0x03, 0x08, 0xcd, 0x4d, 0x63, 0x76, 0x06, 0xcc, 0x23, 0x70, 0xcc, 0x23, 0x64, 0x1c, 0x00, 0xb1, + 0x24, 0xc0, 0xb9, 0x0b, 0xa2, 0x58, 0x17, 0xf2, 0x08, 0x40, 0xef, 0xf1, 0x27, 0x31, 0xa5, 0x60, 0x92, 0x8e, 0x55, + 0x08, 0x82, 0x38, 0x3e, 0xbb, 0x16, 0xad, 0xc9, 0x59, 0xa2, 0x83, 0x19, 0x49, 0x80, 0x0d, 0x31, 0xb0, 0x73, 0x70, + 0x3f, 0x07, 0xa5, 0x87, 0xd5, 0x3b, 0x21, 0x17, 0x7c, 0xc7, 0x3d, 0xd9, 0x2c, 0x5c, 0x3d, 0xe1, 0x20, 0xb8, 0xe3, + 0x9a, 0x05, 0x18, 0x55, 0xc5, 0xba, 0xac, 0x78, 0xfa, 0xe1, 0x6e, 0x05, 0xb1, 0xef, 0x70, 0x40, 0xdf, 0xc9, 0x3c, + 0x4b, 0xee, 0x42, 0x67, 0xcf, 0xb5, 0x51, 0xe9, 0x3f, 0x7c, 0x78, 0xf3, 0x73, 0x04, 0x22, 0xc7, 0xda, 0x50, 0xfa, + 0x3b, 0x8e, 0x67, 0x93, 0x1f, 0xe1, 0xc9, 0xdf, 0xd8, 0x77, 0xdc, 0x9e, 0x1e, 0xfd, 0x3e, 0xd4, 0x4d, 0xef, 0xf8, + 0xec, 0x8e, 0x8f, 0x5c, 0x71, 0xa8, 0xae, 0x70, 0x5f, 0xdf, 0xac, 0x7d, 0x23, 0xa4, 0x87, 0xe7, 0x99, 0xf2, 0xc6, + 0xfc, 0x68, 0x07, 0xc3, 0x20, 0x98, 0x6a, 0xa1, 0x24, 0x44, 0xdd, 0x60, 0x4a, 0xc0, 0x10, 0xed, 0xe9, 0x65, 0x35, + 0x45, 0xce, 0x4d, 0x8d, 0x2c, 0xbc, 0x1f, 0x30, 0x2d, 0x74, 0x68, 0xe4, 0x50, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc2, + 0x6f, 0x95, 0x30, 0xfd, 0x6a, 0x51, 0x39, 0x07, 0xd1, 0x3d, 0x30, 0xc6, 0x15, 0xbc, 0x80, 0xae, 0xb0, 0xeb, 0xb5, + 0x8a, 0x8a, 0x81, 0xe0, 0x71, 0xc8, 0x01, 0x7a, 0xd8, 0x05, 0x2d, 0x2b, 0x4b, 0x75, 0xab, 0x72, 0x96, 0x2a, 0xea, + 0x32, 0x94, 0x95, 0xb1, 0xc2, 0x7c, 0x2f, 0xd9, 0x0f, 0x05, 0x7a, 0x96, 0x4f, 0x45, 0x17, 0xbc, 0x10, 0x4a, 0xb0, + 0x5c, 0xd7, 0x3b, 0x11, 0x88, 0x3a, 0x3f, 0xf4, 0xae, 0xfa, 0x1a, 0xc7, 0x8e, 0xa7, 0x6f, 0x64, 0xca, 0xb5, 0x09, + 0x85, 0xe6, 0xf3, 0xa5, 0xaf, 0x98, 0x28, 0xd8, 0x0d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd6, 0x7a, 0x33, 0x28, + 0xd1, 0x31, 0xaf, 0x51, 0x70, 0xad, 0x14, 0x0a, 0x46, 0x7b, 0x1b, 0x7f, 0x86, 0x23, 0xb7, 0xba, 0x3d, 0xf4, 0x7e, + 0xab, 0xe2, 0xcb, 0xb7, 0xe8, 0xdb, 0x69, 0x7f, 0x8e, 0x2a, 0xf9, 0xeb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, + 0xe2, 0xd2, 0x42, 0x3d, 0xa7, 0xef, 0x8e, 0xdf, 0x82, 0x1f, 0x25, 0xfe, 0xfe, 0xed, 0xfb, 0xa0, 0x26, 0xd3, 0x78, + 0x56, 0x98, 0x0f, 0x6d, 0x0e, 0x08, 0x4d, 0xe2, 0xd2, 0xec, 0xfb, 0x59, 0xdc, 0x64, 0xdf, 0x35, 0x5b, 0x4f, 0x8b, + 0x26, 0x92, 0x94, 0xe1, 0xf6, 0xc1, 0x80, 0x40, 0x1f, 0x20, 0x8a, 0xb3, 0x2f, 0x68, 0x0c, 0x69, 0x3e, 0xb3, 0xef, + 0x47, 0xc4, 0x7b, 0xb9, 0x13, 0x42, 0x8c, 0x2b, 0x2c, 0x1a, 0x3d, 0xe4, 0x33, 0x1e, 0x29, 0xc3, 0xa2, 0xf7, 0x98, + 0x40, 0x9c, 0xe1, 0xb4, 0x7a, 0x8f, 0x98, 0xc7, 0x78, 0x37, 0xd0, 0xb2, 0x87, 0x28, 0xa3, 0x2e, 0x7b, 0xc3, 0xe2, + 0xfb, 0xe3, 0x3a, 0xcc, 0xac, 0xe5, 0xe5, 0x10, 0xfe, 0x06, 0xda, 0x00, 0x9c, 0x72, 0x64, 0xf9, 0x2a, 0xb3, 0xd1, + 0xd5, 0x12, 0xd3, 0x9b, 0x08, 0x62, 0xf1, 0xe8, 0x74, 0x58, 0xbb, 0x3a, 0x55, 0xef, 0x6a, 0xe7, 0x33, 0xd1, 0xab, + 0x40, 0x2b, 0xd7, 0xb6, 0xc7, 0x43, 0xb8, 0x4b, 0x2d, 0xad, 0xb0, 0x11, 0xe5, 0x5c, 0x3c, 0xdd, 0x39, 0x36, 0x27, + 0xa0, 0xc1, 0x95, 0x4c, 0x01, 0x38, 0x4b, 0xab, 0xd1, 0xa8, 0x11, 0xf6, 0x59, 0x39, 0x9f, 0xc3, 0xd6, 0x42, 0x3c, + 0x2d, 0x00, 0xc3, 0x6d, 0x62, 0x50, 0xf2, 0x6e, 0x0c, 0xca, 0xe9, 0x47, 0x05, 0x6f, 0x1d, 0x9c, 0x95, 0xcb, 0x38, + 0x95, 0x37, 0x80, 0xc5, 0x18, 0xf8, 0xa9, 0x58, 0xaa, 0x97, 0x90, 0x2c, 0x79, 0xf2, 0x11, 0xad, 0x36, 0xd2, 0x00, + 0xb8, 0xca, 0xa9, 0xb1, 0xdc, 0x53, 0x20, 0xa1, 0xae, 0x14, 0x95, 0x10, 0x57, 0x55, 0x9c, 0x2c, 0x4f, 0x31, 0x35, + 0xdc, 0x40, 0x2f, 0xa2, 0x40, 0xae, 0xb8, 0x00, 0x92, 0x9e, 0xb3, 0x7f, 0x65, 0x1a, 0x6b, 0xfc, 0xb9, 0x44, 0x01, + 0x93, 0x46, 0x0d, 0xc6, 0x4a, 0xd9, 0x4b, 0x69, 0xa2, 0xbd, 0x05, 0x41, 0xed, 0x5e, 0xfe, 0x05, 0x75, 0x3f, 0x87, + 0x56, 0x84, 0x0d, 0x30, 0x44, 0x79, 0x8e, 0x3b, 0x34, 0xb5, 0x4b, 0xce, 0x03, 0x46, 0x74, 0xde, 0x67, 0xb5, 0xdd, + 0xea, 0xcf, 0x97, 0x80, 0x6d, 0x9a, 0x1a, 0x9f, 0xc2, 0x30, 0x21, 0x26, 0x36, 0xb0, 0x55, 0x56, 0xda, 0x0d, 0x65, + 0xda, 0x49, 0x97, 0xcc, 0x6b, 0xe1, 0x34, 0xef, 0x31, 0xb6, 0x1c, 0xa9, 0xdc, 0xfd, 0x7e, 0x68, 0x7e, 0xb2, 0x9c, + 0x3e, 0xd7, 0x21, 0x9b, 0xbd, 0xf1, 0xa0, 0x39, 0xd1, 0xea, 0xaa, 0x8e, 0x7e, 0x40, 0x07, 0x60, 0xa6, 0x2d, 0x40, + 0xa6, 0x0b, 0x36, 0xed, 0x2b, 0x51, 0x71, 0x49, 0xc2, 0x52, 0x49, 0x60, 0x67, 0x37, 0x25, 0x3b, 0x9b, 0x80, 0x78, + 0x86, 0xbb, 0x9e, 0x16, 0x3b, 0x21, 0x4d, 0x78, 0x8b, 0xbd, 0x04, 0x44, 0x1d, 0xaa, 0xba, 0x84, 0x6c, 0x8c, 0xa1, + 0x8b, 0x7f, 0x51, 0x0a, 0x13, 0xd6, 0x32, 0xa9, 0x4a, 0x4c, 0x10, 0xa4, 0x72, 0xb7, 0x45, 0x60, 0x89, 0x82, 0x1d, + 0xc0, 0xde, 0xbb, 0x51, 0x37, 0xa3, 0xa6, 0xaa, 0x53, 0x2f, 0xc1, 0xc7, 0x69, 0xd6, 0x55, 0x90, 0x59, 0xd8, 0x55, + 0xb1, 0xe6, 0x81, 0x8e, 0x4d, 0xa5, 0x8c, 0x89, 0xbb, 0xb4, 0xc8, 0x10, 0x0f, 0x18, 0x63, 0xe9, 0x42, 0x20, 0xdf, + 0x6c, 0x77, 0xdc, 0xf4, 0x04, 0xa1, 0x9f, 0xb0, 0xa1, 0x04, 0x6e, 0x3a, 0xdb, 0x53, 0xd3, 0xcc, 0x07, 0x44, 0x1c, + 0x06, 0x14, 0x48, 0x36, 0x0e, 0x69, 0x8e, 0xf4, 0x05, 0x49, 0x13, 0x06, 0x86, 0x56, 0x3c, 0x27, 0xc8, 0x8a, 0x42, + 0xcf, 0xd6, 0x55, 0x1b, 0xe7, 0xca, 0x30, 0x47, 0x4b, 0x4e, 0x85, 0xcf, 0x09, 0x32, 0xb1, 0x7b, 0xda, 0x66, 0x26, + 0xc3, 0x51, 0xb2, 0xc0, 0xfc, 0x0a, 0xa2, 0xc4, 0x9d, 0x69, 0x56, 0xe5, 0x60, 0x5c, 0xc0, 0x02, 0xad, 0x7c, 0x0f, + 0xea, 0xc6, 0x1a, 0xda, 0x68, 0x18, 0x62, 0xb7, 0x3f, 0xc1, 0x7e, 0xad, 0x9d, 0xd6, 0x65, 0x8a, 0xe5, 0x65, 0x0a, + 0xd1, 0x5e, 0xc8, 0xfc, 0x46, 0x91, 0xe8, 0x4e, 0x11, 0x86, 0x84, 0x75, 0x94, 0x3d, 0x69, 0x53, 0x03, 0xe8, 0xa9, + 0x17, 0xf0, 0xbc, 0x73, 0x2d, 0xc3, 0x2e, 0xd2, 0xfd, 0x55, 0xc1, 0xa7, 0x74, 0x83, 0x20, 0x45, 0x6f, 0x52, 0x30, + 0xe7, 0xf5, 0x28, 0xa9, 0x37, 0xa7, 0x2d, 0x33, 0xaa, 0x8e, 0x8a, 0x90, 0x72, 0x82, 0xff, 0xe4, 0xa5, 0xd4, 0xc4, + 0x26, 0x4c, 0xf0, 0xc0, 0x87, 0x79, 0x86, 0x0d, 0xbc, 0xdd, 0xbe, 0x4b, 0xc3, 0xa4, 0xcd, 0x36, 0xa4, 0x20, 0xad, + 0x30, 0x71, 0x31, 0xa0, 0xb2, 0xd7, 0xb8, 0x5f, 0xb0, 0x9d, 0x34, 0x05, 0x0f, 0xc2, 0x46, 0x03, 0x13, 0xb7, 0xba, + 0xf8, 0x3a, 0x4c, 0x68, 0xb8, 0xa4, 0xda, 0xd9, 0x49, 0x4b, 0x9a, 0xdb, 0xeb, 0xf2, 0xc2, 0xf6, 0x41, 0xc7, 0x0e, + 0xeb, 0x1a, 0x1e, 0x68, 0x5e, 0xb3, 0x8b, 0x2b, 0xa6, 0x69, 0xa2, 0xb1, 0x1e, 0x52, 0x96, 0x1c, 0xeb, 0x7a, 0xba, + 0xc2, 0xd5, 0x32, 0xd3, 0xc0, 0xee, 0x12, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x81, 0xcd, 0x66, 0xab, + 0x9a, 0x4c, 0xf3, 0xfb, 0xb2, 0xe5, 0x26, 0x20, 0x9c, 0xa5, 0xbe, 0xb9, 0x4f, 0x8e, 0x35, 0x6d, 0xf3, 0x93, 0x00, + 0xc7, 0xdb, 0x2b, 0x20, 0xe9, 0x58, 0x82, 0x2e, 0xbe, 0xa5, 0x3f, 0x88, 0xd4, 0x4c, 0x05, 0xbd, 0x77, 0xbe, 0x48, + 0xdd, 0xfc, 0x02, 0x6c, 0xa3, 0x36, 0xc6, 0x34, 0x2b, 0x5b, 0x87, 0x89, 0xb2, 0xb0, 0x46, 0x16, 0x72, 0x09, 0x3e, + 0x98, 0xbb, 0x4d, 0x9d, 0x1e, 0x77, 0x10, 0x61, 0xbf, 0x8b, 0x1e, 0x8f, 0x30, 0x56, 0xac, 0x41, 0x62, 0x58, 0x85, + 0x35, 0x6d, 0x2e, 0x87, 0x28, 0xa7, 0x66, 0xc9, 0x44, 0x4b, 0xea, 0x53, 0x8a, 0x28, 0x05, 0x73, 0xe3, 0x69, 0xd9, + 0x30, 0x25, 0x44, 0xc8, 0x0a, 0xe9, 0x80, 0x6a, 0x2d, 0xb4, 0x54, 0x13, 0xf4, 0x3a, 0xf4, 0xb2, 0xd0, 0x98, 0x82, + 0xe8, 0x23, 0x32, 0xdc, 0x88, 0x23, 0xa3, 0xbb, 0x63, 0x14, 0x13, 0x08, 0x55, 0xed, 0xe5, 0x85, 0xd5, 0xa7, 0x65, + 0x5b, 0x1d, 0xc4, 0x15, 0x22, 0xdf, 0x77, 0x13, 0xd4, 0x18, 0x05, 0x6d, 0x4e, 0x37, 0xfa, 0x6b, 0x11, 0xfa, 0x76, + 0xe1, 0xd8, 0x8d, 0x82, 0x48, 0x88, 0xc0, 0xea, 0x35, 0x15, 0x03, 0xb2, 0xce, 0x63, 0x17, 0xa1, 0x49, 0x77, 0x0b, + 0x51, 0xde, 0xa8, 0xac, 0x3f, 0xae, 0x43, 0xb2, 0xdd, 0x62, 0x59, 0xe0, 0xcb, 0x7e, 0xba, 0xbe, 0x07, 0xf2, 0xfb, + 0xcd, 0xfa, 0xb3, 0x90, 0xdf, 0xaf, 0xb3, 0x2f, 0x81, 0xfc, 0x7e, 0xb3, 0xfe, 0x9f, 0x86, 0xfc, 0x3e, 0x5d, 0x7b, + 0x90, 0xdf, 0x6a, 0x30, 0x7e, 0x2f, 0x58, 0x70, 0xf2, 0x36, 0xa0, 0x2f, 0x24, 0x0b, 0x4e, 0x5e, 0xbd, 0xf2, 0x8d, + 0x40, 0x84, 0x46, 0xae, 0x37, 0xb2, 0x60, 0xc4, 0x6d, 0x81, 0x57, 0xa8, 0x75, 0xf2, 0x81, 0x8a, 0x32, 0x00, 0x5e, + 0x2f, 0xff, 0x91, 0x55, 0xcb, 0x30, 0xd8, 0x0f, 0xc8, 0xcc, 0x41, 0x82, 0x0e, 0x27, 0x70, 0x7b, 0x43, 0x23, 0xcb, + 0xea, 0x8b, 0xe0, 0xc3, 0x47, 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0xa5, 0xce, 0x6c, 0x24, 0x04, 0x3c, 0xce, 0x78, 0x69, + 0x43, 0x44, 0x2c, 0xe3, 0xf2, 0x4c, 0xc7, 0x66, 0x29, 0xed, 0x56, 0x84, 0x88, 0xf3, 0x67, 0x80, 0x53, 0x6f, 0xf7, + 0x66, 0x8c, 0xfd, 0x50, 0x1c, 0xb1, 0x0e, 0x20, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, + 0x06, 0xbd, 0x84, 0xbb, 0x88, 0xe0, 0x49, 0xe5, 0xb1, 0x4d, 0x0a, 0xa8, 0x3c, 0xd3, 0x40, 0xe5, 0x1d, 0xef, 0x69, + 0x68, 0x87, 0x45, 0xfb, 0x00, 0x1b, 0xe9, 0x72, 0x06, 0x46, 0x8b, 0x2f, 0xaf, 0xb9, 0xa8, 0x7e, 0x06, 0x3c, 0x75, + 0xc1, 0x0b, 0xb8, 0x25, 0x20, 0x17, 0xdb, 0x70, 0x42, 0xa0, 0xc2, 0xf7, 0xec, 0x50, 0x51, 0x63, 0x8c, 0x68, 0xa2, + 0xd1, 0x6f, 0xbc, 0x09, 0xa1, 0x77, 0x27, 0xe8, 0x8a, 0x30, 0x12, 0xde, 0x5f, 0x6b, 0x7e, 0x96, 0x81, 0xf9, 0xbc, + 0x00, 0x28, 0x0d, 0x84, 0x43, 0x65, 0x4a, 0x6e, 0x81, 0x09, 0x1b, 0x63, 0xae, 0x94, 0xa5, 0x1e, 0x52, 0x29, 0x55, + 0x70, 0xba, 0x82, 0xa6, 0x12, 0x70, 0xb8, 0x23, 0x09, 0x60, 0xa6, 0xb6, 0x30, 0x88, 0x6e, 0x9b, 0xd2, 0x2c, 0x8d, + 0x9c, 0x22, 0xcd, 0xe1, 0x93, 0x52, 0x05, 0x3a, 0x7d, 0x96, 0xc4, 0x15, 0xbf, 0x94, 0x05, 0x84, 0xc2, 0x6d, 0xa5, + 0x50, 0xa4, 0xdf, 0x67, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0x39, 0x5b, 0x66, 0x65, 0x05, 0xf9, 0xe6, 0xfa, 0xf4, 0x5b, + 0xd4, 0xd3, 0x02, 0xe7, 0x4d, 0x4d, 0x0a, 0x33, 0xf3, 0x78, 0xac, 0x76, 0x3a, 0xa8, 0x57, 0xbd, 0xd7, 0x06, 0xfb, + 0xbd, 0x39, 0xd1, 0xe3, 0xd6, 0x7a, 0xb0, 0x9a, 0xd4, 0x66, 0xaa, 0x82, 0x38, 0x02, 0xea, 0xc0, 0x8e, 0x70, 0x16, + 0x53, 0xba, 0xb6, 0x08, 0x2a, 0x60, 0xed, 0x80, 0x39, 0x32, 0x71, 0x79, 0x76, 0xa3, 0xe4, 0x27, 0x3d, 0x45, 0x61, + 0xd2, 0x28, 0x56, 0xc8, 0x3e, 0x4b, 0x16, 0xae, 0x59, 0x72, 0x4f, 0xae, 0x75, 0x94, 0x34, 0x30, 0xba, 0xe2, 0xf6, + 0x40, 0x1c, 0x26, 0xed, 0x94, 0xed, 0x76, 0x27, 0x13, 0xb0, 0x06, 0xad, 0x24, 0x88, 0xd6, 0xb1, 0x9c, 0x0d, 0x27, + 0x11, 0x40, 0xa8, 0x68, 0xb2, 0xf6, 0xd7, 0x9a, 0x1b, 0x90, 0xf9, 0x50, 0x7b, 0xfa, 0x39, 0x91, 0xbc, 0x1e, 0x59, + 0xcf, 0x38, 0x4e, 0x4f, 0xfb, 0x1c, 0x0c, 0xb3, 0xfc, 0x21, 0x81, 0x48, 0x30, 0x9d, 0xd3, 0xb3, 0x98, 0x6a, 0x33, + 0x61, 0xc3, 0xa3, 0xd0, 0x2f, 0xfb, 0x4e, 0x03, 0xe0, 0x26, 0x3c, 0x1c, 0x3e, 0x1b, 0x93, 0x5a, 0xdb, 0xac, 0xe3, + 0x02, 0xb2, 0xbf, 0xd5, 0x22, 0x73, 0xcf, 0x76, 0xa1, 0xd1, 0xa6, 0xb7, 0x41, 0xbb, 0x46, 0x2a, 0xee, 0xe9, 0x7e, + 0x4d, 0x6a, 0xb7, 0x60, 0xac, 0x04, 0xe9, 0x0f, 0x75, 0x6a, 0x9d, 0x3d, 0xda, 0x64, 0xba, 0xca, 0xfa, 0x8f, 0xcc, + 0xc6, 0x9b, 0x6b, 0x50, 0x80, 0x5a, 0x2f, 0x25, 0x1f, 0xee, 0xad, 0x23, 0x9b, 0x9e, 0x18, 0x96, 0x75, 0x92, 0x91, + 0x91, 0x7a, 0xe4, 0x2a, 0xfc, 0x56, 0x77, 0x16, 0x7e, 0xcb, 0x93, 0xb0, 0xab, 0x61, 0x8a, 0xc3, 0x37, 0x5d, 0x40, + 0x04, 0x4c, 0x90, 0xeb, 0x87, 0x7f, 0x3c, 0xda, 0x34, 0xc9, 0x52, 0xbd, 0xef, 0x7d, 0x86, 0xbf, 0xb3, 0x14, 0xfe, + 0x56, 0xf5, 0x1f, 0x74, 0x73, 0xc5, 0xab, 0xa5, 0x4c, 0xa3, 0xe0, 0xdd, 0xc9, 0xe9, 0x87, 0x40, 0x23, 0xab, 0xe3, + 0xfd, 0xc2, 0x68, 0x94, 0x0d, 0x86, 0x13, 0x68, 0x58, 0x72, 0x79, 0x89, 0xe0, 0x82, 0x1a, 0x9d, 0xfe, 0x74, 0x29, + 0x6f, 0x8e, 0xf3, 0xdc, 0x67, 0x82, 0x0d, 0xe1, 0xd4, 0x7c, 0x61, 0x83, 0xea, 0x84, 0x20, 0xcb, 0x1b, 0x65, 0xe5, + 0x99, 0xd6, 0xbe, 0xa4, 0x67, 0xe7, 0x77, 0x67, 0x5a, 0xc2, 0x63, 0xd1, 0x1d, 0x9f, 0xff, 0x71, 0x98, 0x66, 0xd7, + 0x7b, 0x48, 0xdd, 0x59, 0x00, 0xa6, 0xf1, 0x39, 0x3f, 0x5f, 0x57, 0x95, 0x14, 0xc3, 0x42, 0xde, 0x04, 0x47, 0x87, + 0xea, 0xc1, 0x64, 0x88, 0xd5, 0x63, 0xb0, 0xf7, 0x5f, 0x49, 0x9e, 0x25, 0x1f, 0x59, 0xf0, 0x68, 0x93, 0xb1, 0xa3, + 0x16, 0x0d, 0x1f, 0xd7, 0xc1, 0x11, 0xb4, 0x75, 0xef, 0x38, 0xcf, 0x0f, 0xf7, 0xd5, 0x17, 0x47, 0x87, 0xfb, 0x69, + 0x76, 0x7d, 0xe4, 0x01, 0xed, 0x3b, 0xbb, 0x59, 0x84, 0x34, 0x73, 0xf7, 0x62, 0x70, 0x90, 0x4d, 0x78, 0x68, 0x39, + 0x09, 0x90, 0xc6, 0x98, 0x30, 0x25, 0x28, 0xc1, 0x09, 0x63, 0x38, 0x37, 0xb7, 0xdb, 0xd0, 0x1a, 0xf5, 0x24, 0x1e, + 0xe2, 0x4d, 0x01, 0x9c, 0x06, 0x66, 0xa1, 0x09, 0xa1, 0x49, 0x4d, 0x42, 0x83, 0xcb, 0x13, 0x13, 0x5a, 0xd4, 0x14, + 0x8e, 0x92, 0x37, 0xf1, 0xca, 0x08, 0xb1, 0xb4, 0x50, 0xc0, 0xb4, 0x7e, 0xd6, 0x18, 0xc7, 0xa8, 0x3d, 0xaa, 0x06, + 0x29, 0xab, 0x57, 0xde, 0x37, 0xb0, 0x20, 0xb7, 0x0c, 0x2b, 0x1a, 0xb4, 0x28, 0x04, 0xc8, 0x1d, 0x7d, 0x71, 0x19, + 0xa7, 0xe1, 0xbc, 0xa4, 0x72, 0x41, 0xd8, 0x51, 0xb8, 0x41, 0xb6, 0xb9, 0x54, 0x54, 0x38, 0x92, 0xb5, 0x83, 0xad, + 0x54, 0xb3, 0x73, 0xf4, 0x68, 0x23, 0x10, 0x29, 0xb1, 0x64, 0x47, 0xcd, 0xf9, 0xaa, 0xe2, 0xf3, 0xe1, 0x92, 0x83, + 0x7f, 0x4d, 0xb0, 0xf7, 0x5f, 0xe9, 0x79, 0x6e, 0x27, 0x45, 0xad, 0xc8, 0x65, 0x2c, 0xd2, 0x9c, 0x7f, 0x88, 0xcf, + 0x7f, 0xc0, 0x3c, 0x2f, 0xce, 0xf3, 0xe7, 0x90, 0xa1, 0x0e, 0x8e, 0x1e, 0x6d, 0x92, 0x6a, 0xf4, 0xf2, 0xed, 0x87, + 0xd7, 0x1f, 0xfe, 0x79, 0xf6, 0xfc, 0xf8, 0xc3, 0xcb, 0xef, 0x4f, 0xde, 0xbf, 0x7e, 0x79, 0x3a, 0xb7, 0x0e, 0xad, + 0x0a, 0x27, 0x8d, 0x2c, 0xb6, 0x5b, 0x97, 0xef, 0xd7, 0xb7, 0x2f, 0x5e, 0xbe, 0x7a, 0xfd, 0xf6, 0xe5, 0x8b, 0x5a, + 0xcd, 0x65, 0xbb, 0x21, 0xb0, 0x43, 0xe3, 0x4c, 0xf0, 0x02, 0x8a, 0xd7, 0xd1, 0x1a, 0xb1, 0xd9, 0x1a, 0xde, 0xaf, + 0xd9, 0x74, 0x1d, 0x09, 0x01, 0x16, 0xd9, 0x9e, 0xde, 0x2c, 0xd0, 0x70, 0x69, 0x36, 0x8e, 0xbf, 0xc4, 0xfc, 0xde, + 0xbc, 0xc4, 0xef, 0xde, 0xcb, 0x1b, 0xd3, 0x15, 0x3d, 0x42, 0x0a, 0xb9, 0x6b, 0xf6, 0xfc, 0x8f, 0x43, 0x5f, 0x5a, + 0x86, 0x22, 0x05, 0x55, 0x2e, 0xfc, 0xaa, 0x83, 0x3d, 0x6d, 0xb9, 0x17, 0x40, 0xe0, 0x89, 0xe0, 0xe8, 0x70, 0xdf, + 0xcf, 0x7d, 0xf4, 0x47, 0xf4, 0xb3, 0xd7, 0x39, 0x2c, 0x15, 0xc6, 0xa1, 0x99, 0xb6, 0x73, 0xba, 0x41, 0x68, 0x24, + 0x77, 0xfe, 0xa9, 0x15, 0x64, 0xc8, 0x95, 0x24, 0x91, 0x9d, 0x44, 0x65, 0x91, 0x62, 0x4a, 0xfb, 0x43, 0xff, 0x75, + 0x7d, 0xc6, 0x1b, 0x3e, 0x17, 0xa5, 0x2c, 0x02, 0xe8, 0x47, 0x3b, 0x5e, 0xc4, 0x9e, 0x17, 0x97, 0x05, 0x7b, 0xd4, + 0x49, 0xde, 0x61, 0x44, 0xf6, 0xdb, 0x9f, 0x7a, 0x1d, 0xfb, 0x83, 0xb8, 0x1f, 0x7b, 0xba, 0x33, 0x2d, 0xf2, 0x62, + 0x1b, 0x78, 0x7f, 0x5c, 0x8f, 0xf9, 0x49, 0x46, 0xff, 0x21, 0xe9, 0x65, 0x4c, 0xaf, 0x62, 0x7a, 0x2a, 0x16, 0x75, + 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, + 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, + 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, + 0xdc, 0xb3, 0x2e, 0xb7, 0x6d, 0x5c, 0xfd, 0xbf, 0x4f, 0x01, 0xc3, 0xae, 0x03, 0xd8, 0x00, 0x04, 0x90, 0xa2, 0x28, + 0x93, 0x22, 0x95, 0xc4, 0x76, 0xa6, 0xea, 0x28, 0x71, 0xc6, 0x56, 0x3d, 0x6d, 0x14, 0x8d, 0x08, 0x82, 0x4b, 0x12, + 0x35, 0x08, 0x60, 0x00, 0x50, 0xa2, 0x42, 0xa3, 0xcf, 0xd2, 0x67, 0xe9, 0x93, 0x7d, 0x73, 0xce, 0x5e, 0xb0, 0xb8, + 0x91, 0x54, 0xec, 0xb4, 0xdf, 0xa4, 0xaa, 0x89, 0xc5, 0xee, 0x62, 0xf7, 0xec, 0xee, 0xd9, 0x73, 0x3f, 0xee, 0x82, + 0xc9, 0x5e, 0x0c, 0x8d, 0x1c, 0xf6, 0xb9, 0xcf, 0x9f, 0x89, 0x85, 0x5b, 0x12, 0x08, 0x3e, 0x2b, 0x8b, 0x16, 0x8b, + 0x80, 0x68, 0x2a, 0x4f, 0x1e, 0xa2, 0x1a, 0xe2, 0x33, 0xe7, 0x4f, 0x6c, 0x1e, 0xb1, 0x53, 0xcf, 0xdb, 0x8e, 0x16, + 0x9f, 0x31, 0x11, 0x21, 0xed, 0x28, 0xe5, 0x8a, 0xb2, 0xd9, 0x3b, 0x54, 0x6f, 0xb0, 0x75, 0x29, 0x8e, 0xae, 0x39, + 0x8b, 0xd6, 0xd3, 0x80, 0x98, 0xb8, 0xdd, 0xe1, 0x93, 0xdb, 0xe9, 0x7a, 0x3a, 0x85, 0x2c, 0x2d, 0x4f, 0x6c, 0x03, + 0xe2, 0xce, 0x44, 0x29, 0xf2, 0x83, 0xb9, 0x3e, 0x84, 0x49, 0x59, 0x59, 0x75, 0xf8, 0x60, 0x2b, 0x02, 0xa2, 0x1e, + 0xfa, 0x81, 0x0c, 0x78, 0xbf, 0x86, 0x53, 0x3b, 0x52, 0x3f, 0xc0, 0xee, 0x4b, 0xd5, 0x61, 0xd3, 0xd1, 0x1f, 0x5d, + 0xab, 0x1f, 0x10, 0xc6, 0x98, 0xbd, 0xf8, 0x35, 0xdd, 0xbd, 0xaa, 0xa1, 0x52, 0xa5, 0xf7, 0x1a, 0xf3, 0x18, 0x80, + 0xd0, 0xf7, 0x8d, 0xef, 0x2e, 0xc2, 0x28, 0xcd, 0x7c, 0x4f, 0xbd, 0x19, 0x5e, 0xf8, 0xda, 0xf5, 0x2a, 0xd3, 0xf4, + 0x1b, 0xc3, 0xcb, 0xe4, 0x14, 0x28, 0x1c, 0x61, 0x62, 0x06, 0x94, 0xb6, 0x4a, 0xf2, 0x09, 0xda, 0x59, 0x91, 0xa3, + 0x66, 0xac, 0xe4, 0x65, 0x23, 0xa8, 0x57, 0xc9, 0xa7, 0x82, 0x89, 0xa1, 0x54, 0x6c, 0xa9, 0x0f, 0x29, 0xa7, 0xf2, + 0x7a, 0xbd, 0xc5, 0xab, 0x3c, 0x2b, 0x6e, 0x4b, 0x8c, 0x01, 0xcc, 0x1d, 0x67, 0xe8, 0xf3, 0x13, 0xd9, 0xe8, 0xb3, + 0x74, 0xef, 0x4e, 0xbe, 0x2b, 0xd3, 0x05, 0x70, 0x7f, 0x83, 0xc5, 0x45, 0x18, 0x65, 0x0a, 0x04, 0xb6, 0x81, 0x2f, + 0x4e, 0xaa, 0x46, 0x62, 0xac, 0x57, 0x4d, 0xcf, 0x19, 0x32, 0xf8, 0x1e, 0x2f, 0x3f, 0x8d, 0x85, 0x37, 0x2b, 0x45, + 0xb0, 0xa0, 0xcc, 0x42, 0x08, 0x0b, 0x98, 0x45, 0x97, 0xd1, 0x7d, 0x55, 0x0f, 0xf2, 0x7a, 0xb2, 0xff, 0xee, 0xd5, + 0x38, 0x99, 0xcc, 0xb3, 0xfa, 0x69, 0x2c, 0x31, 0x29, 0x27, 0x74, 0x2a, 0x67, 0x0a, 0x0d, 0x3f, 0x38, 0x0d, 0x93, + 0x81, 0x9d, 0x18, 0xde, 0x05, 0x80, 0x92, 0xd8, 0x35, 0x3d, 0xc9, 0x6f, 0x79, 0xea, 0x64, 0x9e, 0xb8, 0x58, 0xba, + 0x9c, 0x01, 0xbb, 0x86, 0xf1, 0x3a, 0xc3, 0x50, 0xbb, 0x30, 0x00, 0x92, 0xab, 0x0a, 0x86, 0xee, 0x04, 0x2c, 0x5d, + 0x90, 0x89, 0xb9, 0xaa, 0xf8, 0xb3, 0x7a, 0x19, 0x23, 0x7a, 0x01, 0x79, 0x21, 0x7e, 0x47, 0x41, 0x15, 0x3c, 0x26, + 0x6c, 0x1a, 0x9e, 0x51, 0xc4, 0xa9, 0xd7, 0x3c, 0x54, 0xe8, 0x34, 0x60, 0x06, 0x8f, 0xf6, 0x33, 0xd4, 0x82, 0xc6, + 0xc9, 0x42, 0xf8, 0xcd, 0xd2, 0x34, 0x27, 0xcf, 0xb6, 0x61, 0x7e, 0xfe, 0x6c, 0x9b, 0xe6, 0xa3, 0x67, 0x5b, 0x17, + 0x28, 0xb9, 0x5c, 0x85, 0x89, 0x16, 0x8e, 0x3a, 0xc5, 0xf4, 0x60, 0x53, 0xd1, 0x72, 0x05, 0x35, 0xf5, 0x23, 0xa6, + 0x8f, 0x8f, 0x13, 0x7f, 0xe5, 0x26, 0x0f, 0x54, 0x7d, 0x6f, 0xc8, 0x3a, 0x7e, 0x5d, 0x55, 0x28, 0x5e, 0xa7, 0xf3, + 0xa5, 0x28, 0x5e, 0x55, 0xbe, 0x15, 0x65, 0x84, 0x4d, 0x4e, 0xe8, 0x30, 0xe1, 0x5b, 0xb7, 0xea, 0x4b, 0x62, 0xcd, + 0x48, 0xe6, 0xfa, 0x01, 0x6d, 0x32, 0xe4, 0xc9, 0xe9, 0x6b, 0xb3, 0x49, 0xcb, 0xb3, 0x09, 0xcb, 0xdb, 0x05, 0x27, + 0x43, 0x31, 0x3e, 0x1d, 0x37, 0xce, 0x0c, 0x93, 0x56, 0x35, 0x2f, 0x20, 0x7d, 0xf7, 0x5f, 0x85, 0x3e, 0x01, 0xe8, + 0x87, 0x00, 0x7d, 0x12, 0x7a, 0xd1, 0x8c, 0xfc, 0xed, 0xfd, 0x85, 0xc8, 0x92, 0x05, 0x02, 0x9f, 0x09, 0xdb, 0x87, + 0x29, 0x92, 0x0b, 0x09, 0x92, 0x0a, 0x34, 0x9f, 0x95, 0x22, 0x76, 0x4c, 0x92, 0xab, 0xca, 0x39, 0x1d, 0x3b, 0x99, + 0xd1, 0x51, 0x8f, 0x22, 0x6c, 0x95, 0xe4, 0x67, 0x47, 0xb4, 0x36, 0xbd, 0xdc, 0x68, 0x25, 0x00, 0x43, 0x02, 0x33, + 0x2c, 0xa0, 0x00, 0x09, 0x3d, 0x47, 0x4e, 0xc1, 0x3f, 0x58, 0x2b, 0x14, 0xab, 0x3b, 0xe7, 0x65, 0xca, 0x04, 0x5b, + 0xa9, 0xe3, 0x33, 0x4c, 0xd1, 0x05, 0xd7, 0x33, 0x04, 0xf5, 0x38, 0x3b, 0xa2, 0x8f, 0x4a, 0xe5, 0x00, 0x14, 0x9d, + 0x70, 0x4e, 0x6e, 0xc0, 0x3a, 0x78, 0xd4, 0xc9, 0x80, 0x8c, 0xf0, 0x50, 0xea, 0xe6, 0xaa, 0xb2, 0x62, 0x94, 0x10, + 0x8b, 0x1e, 0x04, 0xa1, 0x05, 0x6c, 0x38, 0xaa, 0xaa, 0xb2, 0x72, 0x37, 0x38, 0x73, 0xfe, 0xc6, 0xdd, 0x68, 0x0e, + 0x7b, 0x55, 0x1c, 0xad, 0xb4, 0x7c, 0xb4, 0x3c, 0xb6, 0xb8, 0xe0, 0x37, 0x20, 0x18, 0xe9, 0x25, 0xea, 0x63, 0x1b, + 0x16, 0x77, 0xc9, 0x17, 0x77, 0xd6, 0xb2, 0xb8, 0xb3, 0x1d, 0x8b, 0x1b, 0xb0, 0x85, 0x54, 0x04, 0xe8, 0x12, 0xf4, + 0x05, 0x13, 0xc0, 0x63, 0x74, 0xc5, 0x80, 0x9d, 0x33, 0x84, 0x93, 0x99, 0x06, 0x60, 0x0b, 0xd5, 0x02, 0xab, 0x26, + 0xb8, 0x48, 0x80, 0xa8, 0x4f, 0x5c, 0x9c, 0x3a, 0x3e, 0x6f, 0x48, 0xb9, 0xa9, 0x05, 0xd5, 0xf9, 0xc2, 0x2e, 0xa5, + 0xe9, 0xc4, 0xb5, 0x65, 0xcb, 0x4c, 0x97, 0x3b, 0x66, 0xea, 0x95, 0x8e, 0x2e, 0x9b, 0x36, 0x3d, 0x84, 0xf2, 0xa4, + 0x60, 0x0f, 0x82, 0x7d, 0x28, 0x6e, 0x99, 0xf2, 0x3e, 0x6c, 0x47, 0xa9, 0xd2, 0x8e, 0x8a, 0xdd, 0x34, 0xbd, 0x8f, + 0x12, 0x50, 0xb0, 0x40, 0x37, 0x8f, 0xdb, 0x52, 0x2b, 0x3f, 0x64, 0xb1, 0x5b, 0x5a, 0x37, 0x53, 0xf1, 0x5e, 0xde, + 0x52, 0x9d, 0x5e, 0x8f, 0xd6, 0x88, 0xdd, 0x2c, 0x23, 0x09, 0x02, 0xdd, 0x85, 0x20, 0xdf, 0xff, 0x4f, 0xb6, 0x59, + 0x03, 0x0e, 0x09, 0xf4, 0x02, 0xab, 0x23, 0x86, 0x8e, 0x81, 0x94, 0x4a, 0xf8, 0xbd, 0x2b, 0xc5, 0x81, 0x4b, 0x04, + 0xe0, 0x7f, 0xc2, 0xe3, 0xaa, 0x25, 0x92, 0xa7, 0x92, 0x73, 0xa2, 0x5b, 0xb1, 0x3b, 0xfb, 0x00, 0x7a, 0x3c, 0xad, + 0x63, 0x80, 0x4d, 0xae, 0x1c, 0xf5, 0x2d, 0xa1, 0xb4, 0x9d, 0x57, 0x20, 0x49, 0xc4, 0x92, 0xcc, 0xe2, 0x09, 0x9c, + 0x25, 0x5d, 0x73, 0x7e, 0xb3, 0xed, 0xe4, 0x47, 0x0b, 0x5f, 0xaf, 0x61, 0x4d, 0x40, 0x6d, 0xc1, 0x68, 0x2c, 0x58, + 0xac, 0xc0, 0x70, 0x4e, 0x74, 0x10, 0xf4, 0x5e, 0x43, 0xfa, 0x52, 0x9b, 0xf3, 0xaf, 0x93, 0x04, 0x2e, 0xa9, 0x6b, + 0xfb, 0x26, 0x7f, 0xbe, 0xc0, 0x5f, 0xce, 0x4d, 0xfe, 0x7c, 0x8a, 0xbf, 0x3a, 0x37, 0x98, 0xa8, 0xae, 0x81, 0x6f, + 0x97, 0xe6, 0xac, 0x8e, 0x4b, 0xfb, 0x89, 0x9a, 0x9b, 0x3d, 0x62, 0xdb, 0xb0, 0x05, 0x7e, 0xfa, 0x6c, 0x9b, 0x82, + 0x83, 0xa5, 0x3c, 0x87, 0xd0, 0x4a, 0xf4, 0xbc, 0xb1, 0x7c, 0xd1, 0x52, 0x3e, 0xd5, 0xff, 0xcb, 0xf7, 0x3c, 0xee, + 0x92, 0xa8, 0xb8, 0x53, 0xca, 0x52, 0x87, 0xdb, 0xa9, 0x1f, 0xba, 0xc9, 0xc3, 0x2d, 0xe5, 0x26, 0x34, 0x4e, 0xaa, + 0x0b, 0x69, 0x0a, 0xa5, 0x26, 0xcb, 0xda, 0xad, 0x4c, 0x92, 0xe7, 0x3e, 0xb0, 0x8b, 0x7e, 0xf4, 0xf7, 0x44, 0xa2, + 0xd2, 0x4a, 0xfc, 0x26, 0x5b, 0x90, 0xd2, 0x87, 0x6e, 0x9f, 0x6d, 0x35, 0x52, 0xef, 0xa6, 0x32, 0xdb, 0x0a, 0x19, + 0x08, 0xcb, 0x83, 0xbc, 0xeb, 0x6a, 0xe6, 0x0f, 0x50, 0x7d, 0x35, 0x8d, 0x36, 0xe6, 0xb3, 0x6d, 0x76, 0xae, 0xae, + 0xdc, 0xe4, 0x13, 0x99, 0x99, 0x9e, 0x9f, 0x78, 0x01, 0x51, 0x07, 0xea, 0x34, 0x70, 0xc3, 0x4f, 0xec, 0xd1, 0x8c, + 0xd6, 0x19, 0x2a, 0xa4, 0xf7, 0xb2, 0xba, 0x1c, 0x26, 0x54, 0x42, 0x87, 0xb4, 0x69, 0x03, 0x14, 0x94, 0xd7, 0x42, + 0xbe, 0x55, 0xd0, 0x85, 0x45, 0x2d, 0x03, 0xec, 0x29, 0x41, 0x47, 0x0e, 0x0e, 0xaa, 0x86, 0x8a, 0xeb, 0xa5, 0x1a, + 0xf2, 0x54, 0xa9, 0x6c, 0x52, 0x64, 0x58, 0xbc, 0xc5, 0x1e, 0x7e, 0xff, 0xe7, 0x68, 0xee, 0xeb, 0xc3, 0x3f, 0xc7, + 0x68, 0xbc, 0xf6, 0x0f, 0xca, 0x8d, 0xdd, 0x34, 0x5d, 0xaf, 0xc8, 0x8c, 0xea, 0xe2, 0xce, 0x8b, 0xa1, 0x94, 0x69, + 0x79, 0x79, 0x38, 0xbf, 0xae, 0x3b, 0xfd, 0xe3, 0xd7, 0x60, 0x23, 0x00, 0x34, 0x5d, 0x34, 0x9f, 0xab, 0x05, 0x57, + 0xbd, 0xa7, 0x99, 0x73, 0xfc, 0xeb, 0xfa, 0x87, 0xb7, 0xf6, 0x0f, 0xa2, 0x71, 0xa8, 0xea, 0xf9, 0x84, 0x2b, 0x3c, + 0x19, 0x69, 0x2a, 0x8d, 0x97, 0xcf, 0x68, 0xee, 0x86, 0xed, 0xd3, 0xb9, 0x2e, 0xed, 0xb2, 0x98, 0x90, 0x19, 0xd8, + 0xc2, 0x1a, 0xb5, 0xd2, 0xdb, 0x80, 0xdc, 0x11, 0xa1, 0x4c, 0xad, 0x7f, 0xac, 0xa1, 0x05, 0x46, 0x7b, 0x63, 0x4a, + 0x5a, 0x46, 0x58, 0x49, 0x53, 0x9a, 0xe0, 0x1c, 0xd8, 0xcc, 0xe5, 0x5d, 0x5e, 0xd9, 0xd5, 0x13, 0x43, 0x95, 0x06, + 0xd0, 0x3a, 0xb2, 0xf3, 0x96, 0xf2, 0x01, 0xa6, 0x7a, 0x6e, 0x1e, 0x9b, 0xe1, 0xe8, 0x03, 0x88, 0x8e, 0xcd, 0xe0, + 0x14, 0xc0, 0xe6, 0xd7, 0x0a, 0x01, 0x44, 0x1b, 0xc4, 0x9a, 0xc4, 0x52, 0x2a, 0x95, 0x77, 0x70, 0xfb, 0x42, 0x34, + 0xb4, 0xe5, 0x92, 0x9f, 0xc6, 0xb5, 0x51, 0xca, 0x33, 0x9f, 0x62, 0x0a, 0xd5, 0x90, 0xa4, 0x69, 0x2b, 0xc0, 0xc4, + 0xa2, 0x1b, 0x6a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0xb0, 0x0d, 0xb8, 0x95, 0x71, 0x82, 0xd5, 0x6f, 0x21, 0x86, + 0xbf, 0x5d, 0x31, 0x0b, 0x91, 0x64, 0x31, 0x55, 0x99, 0xf6, 0xbe, 0xed, 0xfd, 0xbd, 0xca, 0x06, 0x55, 0xba, 0x29, + 0x1b, 0x87, 0xa6, 0x95, 0xb0, 0x5f, 0x4d, 0x40, 0x83, 0x1d, 0xf0, 0x31, 0x55, 0x50, 0x1c, 0x99, 0xcf, 0x89, 0x97, + 0xa5, 0x3a, 0x17, 0xd7, 0x88, 0x78, 0xad, 0xe0, 0xa7, 0xf3, 0x64, 0xa4, 0xfe, 0x04, 0x5e, 0xeb, 0x3c, 0xac, 0x11, + 0x1b, 0x10, 0x67, 0x5b, 0x9a, 0xc1, 0x44, 0x7b, 0x2c, 0x83, 0x88, 0x7d, 0x05, 0xd2, 0x71, 0x37, 0x94, 0xe3, 0xd0, + 0xd8, 0x15, 0x50, 0xec, 0x8b, 0x48, 0xd8, 0x91, 0xec, 0x46, 0x40, 0xbb, 0x8e, 0xef, 0xd6, 0xf9, 0xa1, 0xe7, 0xd8, + 0xb9, 0x6a, 0x80, 0xb7, 0xd4, 0xa7, 0x43, 0x0f, 0x3d, 0xb6, 0xea, 0x42, 0xab, 0x75, 0xf8, 0x98, 0x76, 0x1d, 0xe7, + 0x95, 0xa3, 0x1a, 0xd4, 0x48, 0x4d, 0xc2, 0x6d, 0x5e, 0x74, 0x47, 0x92, 0x2f, 0x9e, 0x4a, 0xb9, 0xf3, 0xc3, 0xc6, + 0x73, 0xe2, 0xd8, 0x80, 0x84, 0xb3, 0x28, 0x7e, 0xc4, 0x14, 0xba, 0xaa, 0xa1, 0x7a, 0x41, 0x94, 0x12, 0x79, 0x0e, + 0x54, 0xec, 0xf0, 0x85, 0x93, 0xf8, 0xf9, 0xfd, 0xdb, 0x0f, 0x1f, 0x54, 0x03, 0x73, 0x6f, 0xa6, 0x72, 0xef, 0x6c, + 0x43, 0xed, 0xc1, 0xfe, 0x8d, 0xfb, 0x8e, 0xde, 0x30, 0x94, 0xaf, 0x2c, 0xef, 0x39, 0x5a, 0x56, 0xdb, 0x72, 0xec, + 0xe6, 0x61, 0x5f, 0xa6, 0xcc, 0xe0, 0x41, 0xf3, 0x6a, 0xc0, 0x0d, 0xbb, 0xaf, 0xb7, 0x52, 0xc9, 0xca, 0x0f, 0x6f, + 0x1b, 0x4a, 0xdd, 0x4d, 0x43, 0x29, 0x70, 0x53, 0x35, 0x5c, 0xb5, 0x8e, 0x56, 0xd2, 0xed, 0x0c, 0xa9, 0x93, 0xf7, + 0x81, 0x4b, 0x62, 0x69, 0xbe, 0x60, 0xd0, 0x2c, 0x76, 0x7a, 0x75, 0xd4, 0x0d, 0xc5, 0x8c, 0x0f, 0x11, 0xb0, 0xf5, + 0x02, 0x30, 0xb1, 0x23, 0xb2, 0x1e, 0xac, 0x4c, 0xb9, 0x09, 0x03, 0x59, 0xa9, 0x13, 0x4a, 0x61, 0xde, 0x66, 0x64, + 0x15, 0x93, 0xc4, 0xcd, 0xd6, 0x09, 0xb9, 0x0d, 0xa2, 0xfb, 0x27, 0x85, 0x01, 0xfb, 0x9e, 0xca, 0x4b, 0x7f, 0xb1, + 0x14, 0xb5, 0xcf, 0x35, 0x32, 0x12, 0x0b, 0xb8, 0xf3, 0x03, 0xf9, 0x7f, 0xfe, 0x6d, 0x59, 0xff, 0xf9, 0xf7, 0xde, + 0xaa, 0xd0, 0x7d, 0x3e, 0x31, 0xb2, 0xd1, 0x01, 0xfb, 0xa2, 0xf9, 0x4b, 0x65, 0x98, 0x37, 0xd7, 0xa9, 0x2d, 0x02, + 0xbc, 0xaf, 0x2d, 0x41, 0xad, 0xb0, 0xbc, 0x6f, 0x1e, 0x35, 0x30, 0x98, 0xd7, 0xde, 0x91, 0x41, 0xa5, 0x2f, 0x1a, + 0xda, 0x44, 0x1f, 0x1c, 0xb4, 0x22, 0xbf, 0x1f, 0xc2, 0xfb, 0xe6, 0xf0, 0x85, 0xc3, 0x67, 0xa2, 0xc1, 0xd7, 0x93, + 0x89, 0xc8, 0xe6, 0x26, 0x37, 0x05, 0xa3, 0xfa, 0xf3, 0x5a, 0x09, 0xbb, 0x3c, 0x07, 0xb6, 0x4e, 0xbd, 0xdd, 0x47, + 0xaf, 0x27, 0x68, 0xfe, 0x75, 0x36, 0x4d, 0x0a, 0x62, 0xa5, 0x15, 0xb5, 0x51, 0xf3, 0xed, 0x5a, 0xa7, 0x35, 0xbc, + 0x06, 0xa5, 0x98, 0xe2, 0x2b, 0x9f, 0xe8, 0xc6, 0xeb, 0x09, 0x93, 0xed, 0x30, 0x8b, 0xd3, 0x41, 0x75, 0x6b, 0x33, + 0xc9, 0x68, 0x09, 0xe8, 0x86, 0x42, 0x35, 0x2e, 0x58, 0x99, 0x14, 0xa2, 0x34, 0x14, 0xa9, 0x03, 0x53, 0x3f, 0xc9, + 0x31, 0xc3, 0xc8, 0xbb, 0x36, 0xab, 0xac, 0x9f, 0xf7, 0x5b, 0x65, 0x5d, 0x1d, 0x64, 0x95, 0xf5, 0xf3, 0x57, 0xb7, + 0xca, 0x7a, 0x27, 0x5b, 0x65, 0xc1, 0x22, 0xbe, 0x25, 0x07, 0x99, 0x4a, 0x71, 0x3b, 0x89, 0xe8, 0x3e, 0x1d, 0x39, + 0x8c, 0xa4, 0x4d, 0xbd, 0x25, 0x01, 0x36, 0x9d, 0xad, 0x4a, 0x10, 0x2d, 0xc0, 0x6c, 0xea, 0x8f, 0x37, 0x70, 0x0a, + 0xa2, 0x85, 0x6c, 0xde, 0x14, 0xb2, 0x18, 0xab, 0x45, 0xdc, 0x24, 0x6a, 0x52, 0x64, 0x1b, 0x3c, 0xca, 0x92, 0x79, + 0xac, 0x4b, 0x79, 0xa4, 0x85, 0xbd, 0x58, 0x87, 0x1b, 0x1d, 0x0d, 0xd0, 0x5e, 0x49, 0x34, 0xec, 0xbc, 0xe4, 0xd1, + 0x24, 0xe4, 0x1e, 0x84, 0x5d, 0x2e, 0x8d, 0xcc, 0xb0, 0x55, 0x7f, 0xdd, 0x38, 0xdf, 0x5f, 0x3b, 0xc3, 0xae, 0x03, + 0xee, 0xd0, 0xc0, 0xe4, 0x61, 0x81, 0x3d, 0xec, 0x76, 0xa1, 0xe0, 0x5e, 0x2a, 0xe8, 0x40, 0x81, 0x2f, 0x15, 0xf4, + 0xa0, 0xc0, 0x93, 0x0a, 0x4e, 0xa0, 0x60, 0x26, 0x15, 0xf4, 0xa1, 0xe0, 0x4e, 0xcd, 0xaf, 0x43, 0x31, 0xdc, 0xbe, + 0x7e, 0x63, 0x50, 0xa6, 0x82, 0x97, 0xf5, 0x0d, 0x07, 0xec, 0x94, 0xdc, 0xc5, 0x20, 0x32, 0xa8, 0x80, 0x6f, 0x90, + 0x18, 0xf7, 0x4b, 0x42, 0x43, 0x33, 0xbf, 0xc1, 0x3b, 0xc7, 0xca, 0x22, 0xb0, 0x54, 0xe6, 0x21, 0x0f, 0x38, 0x1c, + 0x14, 0x55, 0x07, 0x99, 0xcd, 0x50, 0xac, 0x1c, 0x0f, 0x1b, 0x21, 0xad, 0x65, 0xf1, 0x8e, 0x7e, 0xce, 0x14, 0x5b, + 0xa0, 0xb0, 0xf1, 0xd0, 0x64, 0xc1, 0xe0, 0xd7, 0xd0, 0xf4, 0xbf, 0x21, 0xd3, 0xf5, 0x42, 0xb9, 0x8c, 0x16, 0x7b, + 0x95, 0xf6, 0xf2, 0x2b, 0x18, 0xa5, 0x4a, 0x35, 0x20, 0x26, 0xdf, 0x96, 0xec, 0x5b, 0xf4, 0x31, 0x2f, 0xd7, 0xcf, + 0x60, 0x6c, 0x4a, 0x46, 0x4d, 0x46, 0xe0, 0x3b, 0x00, 0x23, 0x49, 0x6b, 0x7e, 0x09, 0x70, 0x96, 0x9e, 0xaf, 0x5c, + 0x69, 0x3c, 0xe3, 0x1f, 0x49, 0x9a, 0xba, 0x0b, 0x5e, 0xbf, 0x3e, 0x4e, 0x30, 0x93, 0x11, 0xfc, 0x17, 0x02, 0x10, + 0x84, 0x69, 0x7e, 0xcd, 0x1a, 0x22, 0x89, 0xee, 0x15, 0xb0, 0xb7, 0x81, 0x0d, 0x55, 0x58, 0x06, 0xf8, 0x16, 0x2c, + 0x61, 0x59, 0x87, 0x0f, 0x87, 0xff, 0x8e, 0x04, 0xd5, 0xc2, 0xcc, 0x5d, 0x54, 0x8b, 0xe8, 0x3e, 0xc8, 0xe5, 0xb1, + 0x09, 0x15, 0x7a, 0xa9, 0xf0, 0x4b, 0x74, 0xc2, 0x41, 0xb4, 0xf8, 0x43, 0x15, 0xc2, 0x3b, 0x14, 0xf9, 0x1f, 0x42, + 0xc3, 0xcf, 0x26, 0x16, 0xc2, 0x58, 0xb1, 0x00, 0x84, 0x83, 0x30, 0x5b, 0x9a, 0xe8, 0xcc, 0xa5, 0x75, 0x42, 0xdd, + 0xb0, 0x70, 0x6d, 0xb7, 0x55, 0x17, 0xd6, 0x41, 0xb2, 0x98, 0xba, 0x9a, 0xd3, 0xe9, 0x1b, 0xfc, 0xcf, 0xb2, 0x7b, + 0x7a, 0x8e, 0x3d, 0x28, 0x33, 0xff, 0x6e, 0x3b, 0x8f, 0xc2, 0xcc, 0x9c, 0xbb, 0x2b, 0x3f, 0x78, 0x18, 0xac, 0xa2, + 0x30, 0x4a, 0x63, 0xd7, 0x23, 0xc3, 0x82, 0xa1, 0x1e, 0x62, 0x70, 0x04, 0xe6, 0x9f, 0xe7, 0x58, 0x9d, 0x84, 0xac, + 0x68, 0x6b, 0x11, 0xfb, 0x60, 0x1e, 0x90, 0x4d, 0xce, 0x3e, 0x5f, 0xaa, 0x4c, 0xab, 0xe2, 0x96, 0xa3, 0x2d, 0x80, + 0x22, 0x65, 0x81, 0x15, 0x20, 0x9c, 0xd0, 0x30, 0x76, 0x67, 0x18, 0x0b, 0xd0, 0xea, 0xf4, 0x12, 0xb2, 0x52, 0xac, + 0x5e, 0x6b, 0xe7, 0x49, 0x74, 0x3f, 0x86, 0xd1, 0x62, 0x63, 0x33, 0x25, 0xc1, 0x1c, 0xdf, 0x98, 0xe8, 0xcb, 0xc1, + 0xfb, 0x31, 0x91, 0x11, 0x87, 0xde, 0xc8, 0x6a, 0x08, 0xaf, 0x07, 0x1d, 0xc5, 0x1e, 0xae, 0xfc, 0xd0, 0xa4, 0xd3, + 0xe9, 0xdb, 0xb1, 0xd4, 0x97, 0x0c, 0x3f, 0x7d, 0x8b, 0xd5, 0x1d, 0xc5, 0x1e, 0x02, 0xb3, 0x36, 0x0f, 0xa2, 0xfb, + 0xc1, 0xd2, 0x9f, 0xcd, 0x48, 0x38, 0xc4, 0x31, 0x8b, 0x42, 0x12, 0x04, 0x7e, 0x9c, 0xfa, 0xe9, 0x70, 0xe5, 0x6e, + 0x58, 0xaf, 0xc7, 0x6d, 0xbd, 0x76, 0x59, 0xaf, 0xdd, 0x83, 0x7b, 0x95, 0xba, 0x01, 0xbf, 0x11, 0xda, 0x0f, 0x1b, + 0x5a, 0x4f, 0xb1, 0x2b, 0xf3, 0x3c, 0xb8, 0xd7, 0x38, 0x21, 0xdb, 0x95, 0x9b, 0x2c, 0xfc, 0x70, 0x60, 0xe7, 0xd6, + 0xdd, 0x96, 0x6e, 0x8c, 0xa7, 0xa7, 0xa7, 0xa7, 0xb9, 0x35, 0xe3, 0x4f, 0xf6, 0x6c, 0x96, 0x5b, 0x1e, 0x7f, 0x9a, + 0xcf, 0x6d, 0x7b, 0x3e, 0xcf, 0x2d, 0x9f, 0x17, 0x74, 0x3b, 0xde, 0xac, 0xdb, 0xc9, 0xad, 0x7b, 0xa9, 0x46, 0x6e, + 0x11, 0xf6, 0x94, 0x90, 0xd9, 0x10, 0x37, 0x12, 0x35, 0xe4, 0x1c, 0xf4, 0x6d, 0x3b, 0x47, 0x0c, 0x70, 0x5d, 0xc2, + 0x4d, 0x28, 0xeb, 0xb9, 0xd9, 0x1e, 0x5c, 0x53, 0x29, 0x3e, 0xe7, 0x79, 0x8d, 0xf5, 0x66, 0x6e, 0xf2, 0xe9, 0x46, + 0x91, 0x66, 0xe1, 0xba, 0xb4, 0xda, 0x96, 0x83, 0xc1, 0xdc, 0x0c, 0x20, 0x48, 0xd6, 0x70, 0x1a, 0x25, 0x70, 0x66, + 0x13, 0x77, 0xe6, 0xaf, 0xd3, 0x81, 0xd3, 0x89, 0x37, 0xbc, 0x88, 0xed, 0xf5, 0xa2, 0x00, 0xcf, 0xde, 0x20, 0x8d, + 0x02, 0x7f, 0xc6, 0x8b, 0xda, 0xce, 0x92, 0xd3, 0xd1, 0x87, 0xe8, 0x22, 0xee, 0x63, 0xa0, 0x03, 0x37, 0x08, 0x14, + 0xab, 0x9b, 0x2a, 0xc4, 0x4d, 0x51, 0xc4, 0xab, 0xd8, 0x29, 0x85, 0x0b, 0xba, 0x83, 0x3b, 0xc7, 0xf1, 0x46, 0xec, + 0x79, 0xe7, 0x24, 0xde, 0xe4, 0xdf, 0xae, 0xc8, 0xcc, 0x77, 0x15, 0xad, 0xd8, 0x4d, 0x8e, 0x0d, 0x62, 0x60, 0x7d, + 0xdb, 0xb2, 0x4d, 0xf9, 0xb1, 0x80, 0x60, 0x82, 0x4f, 0xfc, 0x55, 0x1c, 0x25, 0x99, 0x1b, 0x66, 0x79, 0x3e, 0xb9, + 0xc9, 0xf3, 0xe1, 0x95, 0xaf, 0x5d, 0xff, 0x43, 0xa3, 0xf7, 0x34, 0x55, 0x9b, 0xe4, 0xfa, 0x8d, 0xf1, 0x96, 0xc8, + 0x56, 0x1a, 0x70, 0x8d, 0xa1, 0x85, 0x86, 0x5c, 0x99, 0xde, 0x92, 0xf5, 0xca, 0x14, 0xc8, 0xa2, 0x3a, 0xb5, 0xfa, + 0x28, 0x57, 0xc1, 0x1b, 0x08, 0x2a, 0xbc, 0x25, 0xa3, 0x2b, 0xc9, 0xe2, 0x03, 0x88, 0x15, 0xac, 0x4c, 0x2d, 0xf9, + 0x9f, 0xb5, 0xd1, 0x8c, 0xdf, 0xed, 0xa7, 0x19, 0x7f, 0xc9, 0x0e, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, 0xb3, + 0xba, 0x25, 0xff, 0x45, 0x34, 0x52, 0x85, 0x90, 0x1f, 0xae, 0xa6, 0x84, 0xc6, 0xc8, 0xb9, 0xf8, 0xdd, 0x86, 0xf7, + 0xbc, 0x37, 0x9a, 0xf5, 0x8d, 0xde, 0xdc, 0x20, 0x8f, 0x7d, 0x17, 0x8e, 0xfe, 0x9e, 0xc8, 0xcf, 0xf3, 0xf9, 0xe8, + 0x4d, 0x24, 0x15, 0x88, 0x27, 0x66, 0xff, 0x50, 0x8a, 0x67, 0x40, 0xdf, 0x70, 0xbb, 0x47, 0xcc, 0xf8, 0x00, 0xee, + 0xd0, 0xd4, 0xce, 0x77, 0x26, 0xec, 0xbd, 0x86, 0xe5, 0x21, 0x68, 0xc2, 0xc8, 0x92, 0x3b, 0xbd, 0xd4, 0x44, 0x89, + 0x0b, 0x92, 0x31, 0x2f, 0xd5, 0xef, 0x1f, 0x2e, 0x66, 0xda, 0x45, 0xa4, 0xe7, 0x7e, 0xfa, 0xae, 0xea, 0x72, 0xc2, + 0xd4, 0x2f, 0x23, 0x79, 0x3a, 0x39, 0xb3, 0xd9, 0x92, 0x53, 0x3a, 0xc3, 0x6b, 0xda, 0xfc, 0xbc, 0x34, 0xd3, 0x81, + 0xdc, 0x90, 0xa5, 0x96, 0xaa, 0x5d, 0xc6, 0xcc, 0xde, 0x7f, 0xcb, 0x28, 0x40, 0xcc, 0x96, 0x85, 0x9e, 0xba, 0x33, + 0xda, 0xdc, 0x9f, 0xe5, 0xb9, 0x3e, 0xe4, 0x80, 0x90, 0x2e, 0x5a, 0xb2, 0x8f, 0x88, 0x4b, 0xef, 0x85, 0x59, 0x01, + 0x53, 0xd2, 0x51, 0x0d, 0xdc, 0x05, 0xe8, 0xb4, 0x99, 0xbe, 0x8e, 0xc1, 0x4c, 0x55, 0x28, 0xf8, 0xa8, 0xad, 0x83, + 0x34, 0x21, 0x50, 0xc2, 0x0a, 0xf8, 0xf3, 0x57, 0xbc, 0xa0, 0x6e, 0x35, 0x49, 0x81, 0x83, 0x4a, 0x79, 0xf0, 0xab, + 0xe7, 0x72, 0x6d, 0x8a, 0x76, 0x58, 0x1d, 0x7c, 0xc8, 0x55, 0x41, 0xfb, 0xe1, 0xf6, 0x1b, 0x9f, 0x1d, 0x41, 0x83, + 0x71, 0x45, 0x77, 0xbf, 0xc7, 0x26, 0x10, 0x48, 0x89, 0xf4, 0xde, 0xb0, 0xd2, 0x7b, 0xe5, 0xc5, 0x96, 0xc7, 0xa4, + 0xc8, 0xdc, 0xd8, 0x04, 0x16, 0x1f, 0x71, 0x2f, 0xc3, 0x78, 0x52, 0xf8, 0x8b, 0xe1, 0x3a, 0x05, 0xdc, 0x88, 0x8c, + 0x2a, 0xe2, 0x9f, 0xa1, 0xb7, 0x4e, 0xd2, 0x28, 0x19, 0xc4, 0x91, 0x1f, 0x66, 0x24, 0xc9, 0x11, 0x54, 0xd7, 0x08, + 0x1f, 0x0e, 0x9e, 0x9b, 0x6d, 0x14, 0xbb, 0x9e, 0x9f, 0x3d, 0x0c, 0x6c, 0x46, 0x52, 0xd8, 0x43, 0x46, 0x1d, 0xd8, + 0x8d, 0xf5, 0x07, 0x0c, 0x9a, 0x2f, 0x91, 0xf0, 0x4b, 0xea, 0xe4, 0x8c, 0xbc, 0xcd, 0x87, 0xd2, 0x5b, 0x1a, 0x95, + 0x03, 0xc8, 0x0f, 0x37, 0x31, 0x17, 0x80, 0xe5, 0x61, 0xa9, 0xed, 0x19, 0x59, 0x18, 0x88, 0xb5, 0x41, 0x2e, 0xcf, + 0xff, 0xac, 0x9e, 0xae, 0xd8, 0xcd, 0xc5, 0x40, 0xf1, 0xe8, 0x87, 0x8c, 0x6c, 0xe0, 0x42, 0x0e, 0x2b, 0xe3, 0x90, + 0x9a, 0x53, 0x32, 0x8f, 0x12, 0x42, 0x23, 0xb8, 0x3a, 0xa7, 0xf1, 0xe6, 0xf0, 0xee, 0x77, 0x4f, 0xbf, 0xb9, 0x9f, + 0x30, 0xca, 0x34, 0xde, 0x99, 0xbe, 0xa7, 0xb7, 0xfa, 0x7d, 0x06, 0xa4, 0x21, 0x85, 0xbc, 0x47, 0x83, 0x65, 0x0d, + 0x54, 0x75, 0xd8, 0x18, 0x28, 0x2b, 0x8e, 0xd8, 0x9d, 0x97, 0x90, 0xc0, 0xcd, 0xfc, 0x3b, 0x4e, 0x33, 0x76, 0x4f, + 0xe2, 0x0d, 0x5f, 0x63, 0xbc, 0xf0, 0x1e, 0xb1, 0x48, 0x95, 0xa1, 0xf0, 0x45, 0xaa, 0x16, 0xe3, 0x22, 0x0d, 0x6b, + 0xb3, 0xe1, 0xb1, 0x23, 0x2a, 0x37, 0x7d, 0x2f, 0xde, 0xc8, 0x57, 0x74, 0xd1, 0x4c, 0xdc, 0xd4, 0xd5, 0xa0, 0x5f, + 0x2b, 0x7f, 0x36, 0x0b, 0x48, 0x5e, 0x5a, 0xe8, 0xf2, 0x5a, 0x4a, 0xc0, 0x11, 0x70, 0x70, 0xa7, 0x69, 0x14, 0xac, + 0x33, 0xd2, 0x0c, 0x2e, 0x0a, 0x9c, 0x8e, 0x5d, 0x00, 0x07, 0x7f, 0x97, 0xc7, 0xda, 0x03, 0x72, 0x1b, 0xb6, 0x89, + 0x3d, 0x84, 0x18, 0xbf, 0x66, 0xb7, 0x3c, 0x74, 0x78, 0x25, 0x06, 0x6d, 0x34, 0x4c, 0xc4, 0x80, 0x6b, 0x89, 0x62, + 0x6f, 0xc5, 0x72, 0x58, 0x99, 0x88, 0x73, 0x2a, 0x8a, 0xf2, 0xf2, 0x64, 0xfe, 0x98, 0x33, 0xf6, 0xaa, 0xf9, 0x8c, + 0xbd, 0xe2, 0x67, 0x6c, 0xf7, 0xce, 0x7c, 0x3a, 0x77, 0xe0, 0xbf, 0x61, 0x31, 0xa1, 0x81, 0xad, 0x74, 0xe3, 0x8d, + 0xe2, 0xc4, 0x1b, 0xc5, 0xec, 0xc4, 0x1b, 0x05, 0xbb, 0x46, 0x93, 0x0c, 0xc3, 0xea, 0xe8, 0x86, 0xad, 0x40, 0x21, + 0xfc, 0xd9, 0xa5, 0x57, 0xce, 0x31, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, 0xee, 0xa3, 0x4e, 0xcf, 0x12, 0x47, + 0xda, 0xba, 0x95, 0xb9, 0xd3, 0x29, 0x99, 0x0d, 0xe6, 0x91, 0xb7, 0x4e, 0xff, 0xc5, 0xc6, 0xcf, 0x80, 0xb8, 0x13, + 0x11, 0x54, 0xfa, 0xe1, 0x4d, 0x41, 0x51, 0x72, 0x47, 0x78, 0x0f, 0x5b, 0xb1, 0x4e, 0x03, 0x1a, 0x90, 0xb8, 0x63, + 0x1d, 0x37, 0x6c, 0xf2, 0x66, 0x40, 0xff, 0x61, 0xab, 0xd4, 0x8e, 0x62, 0xbe, 0x00, 0x2c, 0x3b, 0xc1, 0xf1, 0x78, + 0x68, 0xb0, 0xd5, 0xb4, 0x4f, 0x9b, 0x87, 0x7b, 0xcd, 0xbf, 0x74, 0xc3, 0x2f, 0x15, 0x76, 0x6f, 0x31, 0x57, 0x90, + 0xdd, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x3b, 0x2e, 0x84, 0xa2, 0xee, 0x81, 0x58, 0xfe, 0xe9, 0xab, 0x63, 0xf8, + 0x8f, 0x52, 0xf5, 0xbf, 0x64, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xf6, 0x9a, 0x92, 0x4a, 0x48, 0x88, 0x1f, 0x5e, 0x7f, + 0x3e, 0x7f, 0x5c, 0x83, 0x83, 0x6b, 0x53, 0x6b, 0xa6, 0x6a, 0xed, 0xef, 0xa3, 0x08, 0x92, 0x65, 0xd6, 0xab, 0x73, + 0xf0, 0x50, 0xf3, 0xf2, 0x6c, 0x04, 0x8d, 0x38, 0x1f, 0x41, 0xb5, 0xf8, 0x2a, 0xb6, 0xa1, 0xac, 0xc4, 0xdb, 0x36, + 0x56, 0xe2, 0xcd, 0x7e, 0x56, 0xe2, 0xaf, 0x07, 0xb1, 0x12, 0x6f, 0xbe, 0x3a, 0x2b, 0xf1, 0xb6, 0xce, 0x4a, 0x5c, + 0x45, 0xdc, 0x84, 0xd5, 0xb8, 0x58, 0xb3, 0x9f, 0x1f, 0xa9, 0x52, 0xee, 0x32, 0x1a, 0xf5, 0x6c, 0x1a, 0x64, 0xf8, + 0xea, 0x77, 0x33, 0x16, 0xb8, 0x11, 0xdf, 0xa3, 0x45, 0x57, 0xc1, 0x5a, 0x30, 0xcc, 0x8e, 0xdf, 0x91, 0x8a, 0x83, + 0x28, 0x5c, 0xfc, 0x0c, 0x4a, 0x59, 0x10, 0x07, 0x26, 0xd2, 0x0b, 0x3f, 0xfd, 0x39, 0x8a, 0xd7, 0xf1, 0x05, 0xf4, + 0xf5, 0xd1, 0x4f, 0xfd, 0x69, 0x40, 0x84, 0xef, 0x2f, 0xb5, 0x40, 0x63, 0x32, 0x71, 0x30, 0xfa, 0xe4, 0x3f, 0xdd, + 0x0d, 0xff, 0x89, 0x66, 0xa1, 0xec, 0x37, 0x35, 0x6d, 0x53, 0x9b, 0x19, 0x11, 0xae, 0x04, 0x94, 0x06, 0xfd, 0x78, + 0x66, 0xe4, 0x2a, 0xd2, 0x1b, 0x66, 0xc9, 0xed, 0x1d, 0x5a, 0xfb, 0x21, 0x35, 0xa6, 0x66, 0xad, 0x1b, 0x22, 0xe8, + 0x55, 0x5d, 0x0c, 0xbf, 0x8a, 0xd6, 0x29, 0x99, 0x45, 0xf7, 0xa1, 0x6a, 0x84, 0xc2, 0xac, 0x1f, 0x34, 0x9c, 0xa2, + 0x0d, 0xa6, 0x6b, 0xfc, 0x80, 0x84, 0x72, 0x94, 0x68, 0x2a, 0x64, 0x0b, 0x5d, 0xc7, 0x26, 0x55, 0x35, 0x9b, 0x38, + 0x45, 0x55, 0xe4, 0x15, 0x7a, 0xa2, 0x69, 0xd1, 0xe8, 0x71, 0x2d, 0xb9, 0xa9, 0x46, 0x64, 0x31, 0xa9, 0x70, 0xaa, + 0x85, 0x5c, 0xb8, 0xc8, 0x23, 0x4f, 0x34, 0x2c, 0x1c, 0x7b, 0x43, 0x9d, 0x45, 0x8b, 0xb7, 0x10, 0xb7, 0x23, 0x5f, + 0xb3, 0xf5, 0x60, 0x71, 0x18, 0xe8, 0xe3, 0x6b, 0x09, 0x8c, 0xef, 0xee, 0x48, 0x12, 0xb8, 0x0f, 0x9a, 0x9e, 0x47, + 0xe1, 0x8f, 0x00, 0x80, 0x37, 0xd1, 0x7d, 0x28, 0x57, 0xc0, 0xf4, 0x28, 0x0d, 0x7b, 0xa9, 0x31, 0x62, 0x08, 0xb8, + 0x8a, 0x48, 0x23, 0x80, 0xc4, 0xb4, 0x0b, 0xf2, 0x77, 0x83, 0xfe, 0xfb, 0x0f, 0x3d, 0x37, 0x2e, 0x23, 0xf1, 0xa1, + 0xbf, 0xc5, 0x07, 0x7c, 0xe6, 0xf9, 0xf3, 0x27, 0xed, 0xd3, 0x2e, 0x27, 0x44, 0x6f, 0x68, 0xad, 0xb7, 0x9e, 0x02, + 0x18, 0xc5, 0x55, 0xb4, 0xf6, 0x96, 0x68, 0x6b, 0xfa, 0xf5, 0xe6, 0x9b, 0x41, 0x9f, 0x98, 0x17, 0x54, 0x4c, 0xbd, + 0x52, 0x54, 0x40, 0x01, 0xbf, 0xff, 0x16, 0x42, 0x5e, 0xfe, 0x0f, 0xc1, 0x50, 0xdf, 0x35, 0x8c, 0x8b, 0xf7, 0x1f, + 0xb7, 0x79, 0x87, 0x90, 0xbe, 0x92, 0x05, 0x93, 0xe0, 0xca, 0xb5, 0x66, 0x24, 0x93, 0x57, 0x81, 0x26, 0x07, 0x6e, + 0x6b, 0x8b, 0x49, 0xc7, 0xbf, 0x42, 0x2c, 0xca, 0xa6, 0x33, 0x5b, 0x7f, 0x83, 0x30, 0x6c, 0x55, 0x41, 0x32, 0xcc, + 0xe4, 0x81, 0x20, 0xfa, 0xaa, 0xbe, 0x5b, 0xf9, 0xa1, 0x81, 0x71, 0xd7, 0xeb, 0x6f, 0xdc, 0x0d, 0x44, 0x1e, 0x06, + 0xe4, 0x56, 0x7d, 0x05, 0x85, 0x86, 0xec, 0xa9, 0x06, 0xc9, 0x95, 0xd4, 0x46, 0x48, 0x70, 0x2d, 0xde, 0xe4, 0x4f, + 0x8a, 0xa2, 0x28, 0x82, 0x8d, 0x50, 0x04, 0x1f, 0x81, 0xe5, 0xc8, 0x0e, 0x80, 0xb6, 0x24, 0x8f, 0x37, 0xb4, 0x04, + 0x38, 0x03, 0xd4, 0xc9, 0xf2, 0x02, 0x16, 0x5c, 0xaf, 0x67, 0xf3, 0x02, 0xce, 0xd0, 0x43, 0x60, 0x34, 0x37, 0x81, + 0x18, 0xbc, 0x03, 0x05, 0x19, 0x76, 0x7c, 0xcb, 0x24, 0xc1, 0x8a, 0x4d, 0x1f, 0x27, 0x43, 0xd2, 0x1c, 0x85, 0x2d, + 0x94, 0xb0, 0x20, 0x68, 0x1d, 0x2a, 0x41, 0x95, 0x0d, 0xd2, 0x80, 0x1b, 0x91, 0x2f, 0xda, 0x64, 0x2b, 0x12, 0xae, + 0x55, 0xcc, 0xc2, 0x84, 0x51, 0xf1, 0xa0, 0xce, 0x1b, 0x4a, 0x6c, 0x01, 0xb6, 0x69, 0x6e, 0xb9, 0xa4, 0x77, 0x61, + 0xca, 0x50, 0xaa, 0x6b, 0x78, 0x4c, 0xb1, 0x99, 0x32, 0xdc, 0x56, 0xbd, 0x21, 0xd8, 0x92, 0x46, 0x55, 0xd7, 0x29, + 0x6a, 0x8c, 0x0c, 0x7d, 0xd0, 0x78, 0x14, 0x4c, 0x5c, 0xc4, 0xc1, 0xae, 0xb9, 0xd5, 0x45, 0x13, 0x1a, 0x19, 0xb7, + 0x22, 0x28, 0x4a, 0xf4, 0x7a, 0x37, 0x6c, 0x9c, 0x10, 0x0a, 0xa8, 0xb5, 0x1f, 0xaf, 0xd6, 0x4f, 0xcb, 0xa4, 0x3f, + 0x91, 0x07, 0x7a, 0x91, 0x50, 0x50, 0x7d, 0x22, 0x0f, 0x60, 0xfb, 0xf7, 0x16, 0xa4, 0x29, 0xea, 0x0e, 0x74, 0x6d, + 0x40, 0x70, 0x7d, 0x0f, 0xc2, 0x43, 0xed, 0x38, 0x40, 0x76, 0xbe, 0x03, 0x8b, 0x23, 0x88, 0x21, 0x8f, 0x32, 0x3f, + 0xc4, 0xcc, 0xca, 0x5e, 0x6b, 0x84, 0xb1, 0xd9, 0x70, 0x34, 0xf4, 0x17, 0x8e, 0x6d, 0x1f, 0xd5, 0xea, 0x83, 0x20, + 0xbb, 0xa9, 0xb6, 0x6e, 0x64, 0x23, 0xc7, 0x36, 0xfd, 0x17, 0x56, 0x67, 0x58, 0xbb, 0xa3, 0xa5, 0xe8, 0x8d, 0x13, + 0x14, 0x7f, 0x8d, 0x9f, 0x6d, 0xb5, 0xda, 0x81, 0xd4, 0xab, 0x56, 0xeb, 0x38, 0xb6, 0x9c, 0xc9, 0xbf, 0x26, 0xf5, + 0xab, 0x9f, 0xc6, 0x8e, 0xa4, 0x99, 0x44, 0x26, 0x10, 0x7f, 0x58, 0x83, 0x63, 0xf4, 0x67, 0xe5, 0xa5, 0xa2, 0xd1, + 0xe3, 0xa3, 0xeb, 0x13, 0x91, 0xa0, 0x9a, 0xbb, 0x75, 0xc9, 0x1d, 0x54, 0xbe, 0x98, 0x56, 0x31, 0x1c, 0x8b, 0x74, + 0x4a, 0x0a, 0x8d, 0xde, 0x4e, 0x6a, 0x01, 0xfb, 0x6f, 0xb9, 0x3e, 0xad, 0x29, 0x44, 0x02, 0x80, 0x1a, 0x10, 0xad, + 0x7c, 0x6f, 0x87, 0xeb, 0xb8, 0xdc, 0x5d, 0xf9, 0x92, 0x3c, 0xbc, 0x33, 0xbc, 0x74, 0x50, 0x87, 0x26, 0xfa, 0x6b, + 0xbe, 0xee, 0x1e, 0xd9, 0x25, 0x09, 0x67, 0xe5, 0x0e, 0x2b, 0xf7, 0xd7, 0xe1, 0xdd, 0x95, 0x30, 0x0a, 0x84, 0xf1, + 0x8f, 0x1a, 0x30, 0x4a, 0x1e, 0x85, 0xb8, 0xf9, 0xe9, 0x71, 0xf3, 0x0f, 0xa2, 0x62, 0xb0, 0x01, 0x8d, 0xc1, 0x25, + 0x9a, 0x49, 0x42, 0x71, 0x88, 0x15, 0x8d, 0x8e, 0xb8, 0x1a, 0x27, 0x44, 0x5b, 0x77, 0x62, 0xc6, 0x6d, 0x0a, 0x8b, + 0x36, 0x3e, 0x8b, 0xfe, 0x78, 0xa8, 0xd4, 0xda, 0xdf, 0x2f, 0xb5, 0xce, 0xf6, 0x49, 0xad, 0xa9, 0x47, 0xd3, 0x7d, + 0xe2, 0xc6, 0x92, 0x53, 0x1c, 0x27, 0xce, 0x65, 0xdf, 0xb8, 0x92, 0xa8, 0x1b, 0x1d, 0xa0, 0x78, 0xab, 0x5a, 0x6f, + 0xd4, 0x4a, 0x10, 0xc5, 0xdf, 0x12, 0x83, 0xc2, 0x15, 0xea, 0xb2, 0x6c, 0xfc, 0xaa, 0x90, 0x8d, 0x53, 0xae, 0xa6, + 0xf0, 0x65, 0xe1, 0xd4, 0xbf, 0xe4, 0x27, 0x26, 0xb8, 0x83, 0xc2, 0x5f, 0xac, 0x18, 0xa9, 0xe4, 0x01, 0x55, 0x30, + 0x1a, 0x92, 0x5f, 0x1d, 0xe7, 0x32, 0xca, 0xee, 0x75, 0xe5, 0xaa, 0x85, 0x03, 0x54, 0x51, 0x0e, 0x52, 0x77, 0x1c, + 0xb2, 0x28, 0x96, 0xb7, 0x4d, 0xd9, 0x03, 0x46, 0x7e, 0x2d, 0x6d, 0x12, 0xe1, 0xaa, 0x42, 0x01, 0xcc, 0xc5, 0xf4, + 0x15, 0xbd, 0xb6, 0xb0, 0x81, 0xc0, 0x41, 0x36, 0x78, 0xd6, 0xed, 0x97, 0xce, 0xd3, 0x0c, 0x05, 0x85, 0x16, 0x5e, + 0x96, 0x41, 0x20, 0x7c, 0x6f, 0xb6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xec, 0x7e, 0x07, 0xf1, 0xa2, 0x62, 0xcb, 0x8a, + 0x7c, 0x3c, 0x99, 0x26, 0x35, 0xcf, 0xc5, 0xaa, 0xf5, 0x4e, 0xa9, 0x10, 0x67, 0xcb, 0x9c, 0x53, 0xca, 0x32, 0x7a, + 0x56, 0x63, 0xc0, 0xbf, 0xcb, 0xb6, 0x4e, 0xb2, 0x0e, 0x31, 0x9a, 0xbc, 0x99, 0x25, 0xae, 0xf7, 0x49, 0x1a, 0x32, + 0x97, 0x73, 0x82, 0x0c, 0xb8, 0xac, 0x29, 0x18, 0xba, 0x18, 0x7c, 0x91, 0x0c, 0xac, 0x4e, 0x2a, 0x49, 0x5f, 0x06, + 0x4f, 0xed, 0xae, 0xfb, 0x6a, 0x7e, 0x5c, 0x11, 0x8a, 0x76, 0x7a, 0x65, 0x91, 0x79, 0xcb, 0x38, 0xb2, 0xe5, 0x7a, + 0x35, 0xdd, 0xca, 0xb2, 0x55, 0x49, 0xe4, 0x5a, 0x17, 0xb3, 0xca, 0x9f, 0x9d, 0xcf, 0xe7, 0x65, 0x41, 0xa3, 0xad, + 0x1c, 0xa3, 0xb0, 0xf0, 0xa9, 0x6d, 0xdb, 0xd5, 0xb1, 0xef, 0x06, 0xbb, 0x89, 0x72, 0xdb, 0xd3, 0xc6, 0x11, 0x23, + 0x6c, 0xf7, 0xc1, 0xaf, 0x0e, 0x8e, 0xdc, 0x2a, 0x4e, 0x76, 0xc9, 0x2c, 0x62, 0x48, 0x8d, 0x21, 0xfc, 0x8c, 0xac, + 0xd2, 0x81, 0x47, 0x50, 0x07, 0x63, 0x49, 0x07, 0x1a, 0x0d, 0x07, 0xcc, 0x05, 0x98, 0x8a, 0x38, 0x7c, 0x57, 0xd8, + 0x0a, 0xca, 0xc3, 0x6b, 0xc2, 0x7b, 0xfe, 0x11, 0x3c, 0x28, 0xdb, 0xba, 0x4c, 0x1b, 0xa7, 0xd5, 0xb3, 0xff, 0x5c, + 0xaa, 0xa7, 0xc0, 0x05, 0xb8, 0xe5, 0x0a, 0x6d, 0x2a, 0x9f, 0xc5, 0xff, 0x17, 0xf2, 0xff, 0x57, 0xf1, 0xa6, 0x6c, + 0x3f, 0x72, 0x0a, 0x12, 0xed, 0xe2, 0xb4, 0xd0, 0x51, 0x37, 0xed, 0x01, 0x61, 0x65, 0x30, 0x97, 0x15, 0xe8, 0xa0, + 0xa4, 0x2f, 0xa5, 0xdc, 0x68, 0x10, 0xbf, 0x23, 0xc5, 0x0c, 0x4b, 0x5c, 0x88, 0x10, 0x8b, 0x84, 0x71, 0x30, 0x07, + 0xe3, 0xe5, 0x29, 0xea, 0x0f, 0x4a, 0x7b, 0x02, 0xb4, 0xf1, 0xb5, 0xb9, 0x1d, 0x24, 0xee, 0xaf, 0xea, 0xb5, 0x78, + 0xc7, 0x00, 0x32, 0x07, 0x0e, 0x21, 0x1a, 0x12, 0x28, 0x95, 0xcd, 0x4d, 0x47, 0x29, 0xde, 0xca, 0x7a, 0x36, 0x3e, + 0x30, 0xec, 0xae, 0xb9, 0x0a, 0xed, 0x9b, 0x6b, 0x0b, 0x60, 0xb2, 0x6c, 0xfb, 0xe1, 0xb3, 0x09, 0x4b, 0x2c, 0xef, + 0x47, 0x07, 0x97, 0x1c, 0xf7, 0xaf, 0x89, 0x77, 0x67, 0x4a, 0xcf, 0x3f, 0xca, 0x17, 0xff, 0xda, 0x28, 0xd0, 0xbb, + 0x2a, 0x49, 0xe8, 0x98, 0xb5, 0x78, 0x47, 0x3f, 0xa8, 0xf6, 0xca, 0x0f, 0x0f, 0xaf, 0xeb, 0x6e, 0x0e, 0xae, 0x0b, + 0x17, 0xc6, 0xc1, 0x95, 0xe1, 0xc6, 0xa1, 0x96, 0x0b, 0xd9, 0xe8, 0xaf, 0x92, 0x40, 0x51, 0x76, 0xfc, 0x55, 0xb1, + 0x15, 0xa5, 0xf2, 0xaf, 0xd6, 0x40, 0x7c, 0x1e, 0x94, 0x52, 0x41, 0xe1, 0x59, 0xd1, 0xd4, 0xbe, 0x72, 0xaa, 0xf4, + 0xbb, 0xca, 0x89, 0xad, 0x52, 0x2e, 0x6c, 0xa4, 0xf6, 0x3a, 0x85, 0x43, 0xdf, 0xb1, 0xad, 0x8e, 0xcf, 0x16, 0xfc, + 0x92, 0x98, 0xfb, 0x41, 0x40, 0x51, 0x45, 0x9a, 0x25, 0xd1, 0x27, 0x52, 0x56, 0xb3, 0xd0, 0x32, 0x66, 0x04, 0xd2, + 0xe1, 0x8f, 0x70, 0x76, 0x3c, 0x37, 0x1e, 0xe0, 0xd9, 0x90, 0x0b, 0xc1, 0x80, 0x93, 0x96, 0xe2, 0x27, 0xe0, 0x0e, + 0x9e, 0xaa, 0xe3, 0x33, 0x08, 0x1a, 0xa8, 0xcc, 0x46, 0xea, 0x8f, 0x9d, 0xbe, 0xe2, 0xf4, 0xee, 0xcc, 0xae, 0x67, + 0x9b, 0x8e, 0x75, 0xac, 0xd8, 0xd6, 0x89, 0xd9, 0xb1, 0xfa, 0x4a, 0xc7, 0xea, 0xc1, 0xbf, 0x9e, 0x63, 0xbd, 0x52, + 0x6c, 0x78, 0x52, 0x1c, 0xab, 0x8b, 0xff, 0x76, 0xac, 0xfe, 0x5d, 0x97, 0xde, 0xf4, 0xae, 0x70, 0xab, 0xaa, 0x8c, + 0x02, 0x9c, 0x40, 0xd4, 0xa3, 0xf1, 0xd9, 0x3a, 0x25, 0xca, 0x66, 0xa4, 0xbe, 0x52, 0x95, 0x65, 0x42, 0xe6, 0x23, + 0xf5, 0xa9, 0x2b, 0x95, 0x3a, 0xa7, 0x8d, 0xc5, 0x9d, 0x7e, 0x63, 0x71, 0xf7, 0xa4, 0xb1, 0xf8, 0xb8, 0x57, 0x2e, + 0x3e, 0x5a, 0xd0, 0x57, 0x52, 0xce, 0xbe, 0x95, 0x9b, 0x25, 0xfe, 0x46, 0x73, 0x14, 0x40, 0xd7, 0x26, 0xfc, 0xd3, + 0xef, 0xe8, 0xa2, 0xd5, 0x14, 0x5a, 0x09, 0x68, 0xf4, 0x4f, 0x15, 0xe7, 0xe4, 0x2f, 0x9d, 0x13, 0x0f, 0xea, 0x41, + 0x86, 0x49, 0xf8, 0xbb, 0xeb, 0x9e, 0x7a, 0xb6, 0x02, 0x0d, 0x1d, 0xf8, 0x6f, 0xd9, 0xeb, 0x78, 0xf4, 0xc1, 0x86, + 0xf7, 0x1f, 0x9d, 0x7e, 0x6a, 0x9b, 0x0e, 0xfc, 0xf7, 0x9b, 0x50, 0xb9, 0x83, 0xc2, 0x5f, 0xee, 0xf7, 0xd8, 0x56, + 0xba, 0xa7, 0xcb, 0x8e, 0xf5, 0xea, 0xae, 0x6f, 0x9d, 0x2e, 0x9d, 0xfe, 0x47, 0xfa, 0x14, 0x98, 0x1d, 0xeb, 0x15, + 0xfc, 0x7d, 0xec, 0xda, 0x4b, 0xd3, 0xb1, 0x4e, 0xef, 0xba, 0x56, 0x37, 0x30, 0x4f, 0xac, 0x53, 0xf8, 0xfb, 0x0d, + 0xc0, 0x0b, 0x70, 0x65, 0x29, 0x41, 0x15, 0xd8, 0x18, 0x15, 0xfb, 0x0d, 0xf9, 0x23, 0x9d, 0x63, 0xa5, 0x77, 0xfc, + 0x97, 0xd3, 0x3b, 0xf3, 0x78, 0xe9, 0x74, 0xee, 0xcc, 0xd6, 0x9f, 0x1f, 0x01, 0xf2, 0xbb, 0x17, 0x0e, 0xc0, 0x88, + 0x39, 0x40, 0xfe, 0x34, 0x31, 0x2e, 0xdb, 0xc4, 0xe8, 0xef, 0xf7, 0x8b, 0xd1, 0x7f, 0x58, 0x1f, 0x22, 0x46, 0x7f, + 0xff, 0xd5, 0xc5, 0xe8, 0x97, 0x55, 0x2b, 0xee, 0xf7, 0xd5, 0x58, 0xe5, 0xbf, 0x6c, 0xab, 0x44, 0xb2, 0xef, 0x6a, + 0xd7, 0x57, 0xeb, 0x1b, 0x88, 0xb6, 0xf3, 0x3e, 0x1a, 0xfd, 0xb0, 0x2e, 0x99, 0x28, 0x45, 0x80, 0x01, 0xde, 0x47, + 0x14, 0x03, 0xfc, 0xb6, 0x1e, 0x81, 0x5d, 0x04, 0xbb, 0x35, 0xfd, 0x99, 0xb9, 0x74, 0x83, 0xb9, 0xb8, 0x71, 0xa1, + 0x64, 0x88, 0xc5, 0x60, 0x33, 0x0f, 0x97, 0x09, 0x28, 0x6b, 0xd6, 0xab, 0x30, 0x1d, 0x9c, 0xd8, 0x80, 0xe6, 0x3b, + 0xf3, 0x24, 0xaf, 0x34, 0xb6, 0x78, 0x7c, 0xa2, 0x5b, 0x66, 0xd3, 0xdf, 0xfa, 0x1e, 0x4d, 0xd6, 0x9a, 0x7b, 0x77, + 0xea, 0xfd, 0x2a, 0x60, 0x0b, 0xc2, 0x4d, 0xfa, 0x80, 0xd8, 0x68, 0x7a, 0x5f, 0x36, 0x1c, 0xab, 0x98, 0x0a, 0xb6, + 0x8f, 0x14, 0x46, 0x52, 0x6d, 0xef, 0x94, 0x0d, 0xcf, 0xf6, 0x4d, 0xb3, 0xe1, 0xf3, 0xa5, 0xe6, 0x3b, 0xac, 0xde, + 0x44, 0xc7, 0x55, 0x50, 0x55, 0x32, 0x6d, 0x35, 0x02, 0xa4, 0xa0, 0x3d, 0x0b, 0xd3, 0xb8, 0x82, 0xf0, 0xb1, 0x15, + 0xbc, 0x8d, 0x6d, 0xe9, 0x5d, 0xa9, 0x4f, 0xd9, 0x9c, 0xee, 0xc5, 0x16, 0xe9, 0x41, 0xff, 0x37, 0x20, 0x6c, 0xd8, + 0x7d, 0x3c, 0x8d, 0x64, 0x38, 0x6f, 0xa5, 0x7e, 0x29, 0xa9, 0x9d, 0x2f, 0x9d, 0x6d, 0x9d, 0xb4, 0x69, 0x35, 0xa4, + 0x75, 0xc8, 0x8a, 0xdf, 0xd1, 0xf8, 0x79, 0x6a, 0xb6, 0x9a, 0x53, 0xd3, 0x62, 0xb4, 0xcc, 0xdd, 0xd5, 0x19, 0xaf, + 0xf7, 0x14, 0x36, 0xb1, 0xc1, 0x1e, 0x64, 0xc7, 0xf1, 0xed, 0x1c, 0xb2, 0x22, 0x0f, 0x90, 0x88, 0x90, 0x28, 0xa8, + 0x0e, 0xda, 0xd8, 0x0e, 0x77, 0x98, 0x7f, 0xc8, 0x1d, 0xb3, 0x4e, 0xd0, 0x56, 0x77, 0x97, 0xc5, 0x88, 0x70, 0x6d, + 0xd8, 0x96, 0x14, 0xa8, 0x4e, 0xaf, 0x6f, 0x38, 0x27, 0x86, 0xd5, 0xef, 0xe9, 0x39, 0x3f, 0x70, 0x72, 0x97, 0x25, + 0x80, 0x80, 0xc9, 0xae, 0x18, 0xa6, 0x1f, 0xfa, 0x99, 0xef, 0x06, 0x39, 0xa0, 0xfa, 0x32, 0xcd, 0xfb, 0xcf, 0x75, + 0x9a, 0xc1, 0x1c, 0x39, 0x49, 0x86, 0xe6, 0xca, 0xe6, 0x94, 0x64, 0xf7, 0x84, 0x84, 0x2d, 0xaa, 0xdc, 0xaa, 0xf5, + 0xf3, 0x1f, 0x67, 0x0b, 0x9a, 0x53, 0x3b, 0x8b, 0x69, 0x16, 0xb2, 0xfd, 0xc1, 0x4d, 0x75, 0xf3, 0x89, 0xf1, 0x53, + 0x1b, 0xc2, 0xfd, 0xe7, 0x7e, 0x84, 0x9b, 0x91, 0x43, 0x10, 0xee, 0x3f, 0xbf, 0x3a, 0xc2, 0xfd, 0x49, 0x46, 0xb8, + 0x25, 0x4f, 0x95, 0x42, 0x26, 0xfa, 0x01, 0x9f, 0x35, 0x08, 0xf2, 0xfb, 0x52, 0x3d, 0xa2, 0xe4, 0xa5, 0x2a, 0x25, + 0x5f, 0xfd, 0x58, 0xca, 0x26, 0x83, 0x2c, 0x3b, 0x06, 0x25, 0xa5, 0x99, 0x2b, 0x20, 0x31, 0xa9, 0x48, 0xb1, 0x0d, + 0x7d, 0x5e, 0x84, 0x59, 0x60, 0xbd, 0x67, 0x6c, 0x09, 0xa8, 0x20, 0x7e, 0x88, 0x92, 0x95, 0x8b, 0x01, 0xd9, 0x54, + 0xcc, 0x42, 0x07, 0x0f, 0x36, 0x78, 0x47, 0x79, 0x51, 0x38, 0x13, 0x72, 0x74, 0x32, 0xba, 0xa6, 0xf4, 0xa0, 0xfa, + 0x40, 0xdc, 0x44, 0x35, 0xe8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xfb, 0x45, 0xe7, 0xf8, 0xc5, 0x89, 0x0d, 0xff, 0x73, + 0x48, 0x37, 0x37, 0x58, 0xc5, 0x55, 0x14, 0x42, 0x22, 0x0c, 0x5e, 0xb3, 0xad, 0xda, 0x3d, 0x21, 0x9f, 0x8a, 0x5a, + 0xfd, 0xe6, 0x4a, 0x33, 0xf7, 0xa1, 0xa8, 0xd3, 0x58, 0x63, 0x19, 0xad, 0xa5, 0x61, 0x35, 0x8c, 0xc6, 0x0f, 0xd7, + 0x20, 0x19, 0x92, 0x6a, 0xc8, 0xaf, 0xd9, 0x74, 0x8b, 0x79, 0x91, 0x6e, 0x7e, 0x53, 0x64, 0xdb, 0xe1, 0x59, 0x3f, + 0xf6, 0x42, 0x90, 0x09, 0xd5, 0x6d, 0x8c, 0xd5, 0x8d, 0xf9, 0x66, 0x14, 0xc8, 0x75, 0x57, 0xa4, 0x54, 0xc7, 0x05, + 0xca, 0x92, 0x75, 0xe8, 0xd1, 0xac, 0xe9, 0xee, 0x34, 0xd5, 0xfc, 0x23, 0x88, 0xd6, 0x89, 0x1f, 0xd6, 0x71, 0xd5, + 0xdc, 0xb1, 0x5d, 0xa4, 0x26, 0x48, 0xf9, 0xaa, 0xb8, 0x2f, 0x32, 0x23, 0xa1, 0x09, 0x4d, 0x71, 0x69, 0xcd, 0x91, + 0xfb, 0x42, 0x34, 0x7c, 0x91, 0x19, 0x90, 0x54, 0x14, 0x96, 0xfb, 0xf9, 0x73, 0x5a, 0x0b, 0xd2, 0xfc, 0xd1, 0x69, + 0x9d, 0x7b, 0x22, 0x35, 0x98, 0xaa, 0xb8, 0x8b, 0x48, 0xc5, 0xd4, 0x60, 0x03, 0xcf, 0x88, 0x5e, 0xbe, 0x1c, 0x8f, + 0x1c, 0x9d, 0x25, 0xa9, 0x2c, 0x65, 0x54, 0xba, 0x3c, 0x4c, 0x35, 0xae, 0x37, 0x3a, 0x6d, 0xc5, 0x7e, 0xb8, 0xe0, + 0x9a, 0x69, 0x81, 0xbd, 0x20, 0xc3, 0x01, 0x55, 0x81, 0xb9, 0x5c, 0x45, 0xcd, 0xeb, 0xdc, 0x91, 0x04, 0x12, 0x6c, + 0x8e, 0xd4, 0xae, 0x65, 0x5b, 0xb6, 0x2a, 0x1a, 0xce, 0xfd, 0xc5, 0x68, 0x1b, 0x65, 0x2e, 0xe4, 0x8a, 0x09, 0xa2, + 0x05, 0x78, 0x7e, 0x64, 0x7e, 0x16, 0x40, 0xe2, 0x11, 0x70, 0x01, 0x59, 0x51, 0xae, 0x31, 0x67, 0xf6, 0xb8, 0x6e, + 0xf2, 0x09, 0x93, 0xcf, 0x71, 0xa7, 0x2f, 0x0c, 0x49, 0xf3, 0x23, 0x5c, 0x86, 0x9a, 0xaa, 0x41, 0xea, 0x43, 0x92, + 0xa4, 0xa6, 0x6c, 0xdf, 0x3e, 0x50, 0xa0, 0x0d, 0xa4, 0x25, 0xc7, 0x0e, 0xe6, 0x89, 0xbb, 0x82, 0x18, 0xdd, 0xdb, + 0xdc, 0x60, 0x98, 0x56, 0x65, 0xa8, 0x56, 0x71, 0x5e, 0x9d, 0x18, 0x4a, 0xc7, 0x31, 0x14, 0x1b, 0xd0, 0xad, 0x9a, + 0x1b, 0xdb, 0xfc, 0x66, 0xb8, 0x4f, 0x45, 0x47, 0xf1, 0xcb, 0x53, 0x3a, 0x0f, 0xaa, 0x9c, 0x63, 0xc2, 0xcf, 0x8c, + 0x06, 0x14, 0xd4, 0xa4, 0xe8, 0xd9, 0x3e, 0x15, 0xd3, 0x5f, 0x91, 0x4d, 0xa6, 0x63, 0x62, 0x0e, 0x56, 0xc5, 0xd7, + 0xb7, 0xe8, 0x9a, 0xe6, 0x87, 0x8a, 0xff, 0xf9, 0xb3, 0xe6, 0x83, 0xf9, 0xfd, 0x48, 0x82, 0x0f, 0x3c, 0xeb, 0x25, + 0x80, 0xf9, 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0xcc, 0x7f, 0x30, 0xc5, 0x9e, 0x15, 0xb8, + 0xe1, 0x02, 0x50, 0x9a, 0x1b, 0x2e, 0x6a, 0x06, 0x04, 0xd4, 0xbb, 0xae, 0x52, 0x5a, 0x74, 0x55, 0x28, 0xf7, 0xd3, + 0xef, 0x1f, 0xae, 0x68, 0xe2, 0x21, 0x48, 0x72, 0xed, 0xce, 0xd0, 0x15, 0xac, 0xd0, 0x3d, 0xbc, 0x1c, 0x7d, 0x73, + 0xb6, 0x22, 0x99, 0x4b, 0x05, 0x97, 0xc0, 0xe2, 0x01, 0x39, 0xa0, 0x78, 0x3c, 0x69, 0x28, 0x65, 0xf0, 0x66, 0xe4, + 0xce, 0xf7, 0x18, 0x9f, 0x66, 0x28, 0xec, 0x9e, 0x32, 0xd1, 0x46, 0x69, 0xe4, 0x18, 0xd4, 0x44, 0xd6, 0x73, 0x31, + 0xec, 0xe0, 0x28, 0x8c, 0xd4, 0xf1, 0x37, 0xc2, 0x9b, 0xa8, 0x6d, 0x11, 0x20, 0xfb, 0xdf, 0x75, 0x42, 0x82, 0x7f, + 0x8d, 0xbe, 0x81, 0x8b, 0xfb, 0x9b, 0x1b, 0x55, 0x1f, 0x66, 0x16, 0xf2, 0x31, 0xdf, 0x34, 0x64, 0xc1, 0x43, 0x1e, + 0x95, 0x31, 0x9b, 0x5d, 0x89, 0xd9, 0x84, 0xdf, 0xfb, 0x59, 0xd7, 0xf1, 0x19, 0x5e, 0x68, 0x63, 0xe0, 0x2e, 0xb6, + 0x25, 0x9e, 0xd3, 0x19, 0x22, 0x83, 0x3a, 0x0d, 0x5c, 0xef, 0x13, 0xe7, 0x50, 0xe5, 0x87, 0x43, 0x78, 0x51, 0x41, + 0xd9, 0x35, 0xee, 0x65, 0xdc, 0xca, 0x5b, 0xfc, 0x32, 0x7e, 0xea, 0x7e, 0xe9, 0x67, 0x82, 0x19, 0xc6, 0x87, 0x1c, + 0xb4, 0x39, 0x38, 0xbe, 0x82, 0xfd, 0x01, 0x06, 0xd5, 0x39, 0xfd, 0x4b, 0xef, 0xce, 0xb1, 0x97, 0x1d, 0xc7, 0x02, + 0x36, 0x67, 0xd9, 0xb5, 0xfa, 0x81, 0xd9, 0xb5, 0xfa, 0xf0, 0xf7, 0x11, 0x58, 0x2f, 0xb3, 0x63, 0x1d, 0x7f, 0x74, + 0x3a, 0x81, 0x79, 0x6a, 0xf5, 0xe1, 0xef, 0x92, 0xb6, 0xfa, 0x05, 0x99, 0x1e, 0x60, 0x78, 0xbe, 0x29, 0x61, 0x01, + 0xe9, 0xb7, 0xd0, 0x22, 0x18, 0xa5, 0xeb, 0xad, 0x41, 0x13, 0x01, 0x28, 0x43, 0x35, 0x78, 0x94, 0xc0, 0x70, 0xa8, + 0x41, 0x5a, 0x6e, 0x0c, 0x28, 0xcf, 0x0d, 0x32, 0xc2, 0x22, 0xc5, 0x7c, 0xfb, 0x31, 0x62, 0x6d, 0x9a, 0x03, 0x70, + 0xf3, 0x4c, 0x45, 0x54, 0x75, 0xf1, 0xb7, 0x18, 0x03, 0xeb, 0xf0, 0x90, 0xe1, 0x12, 0x56, 0x2a, 0xb2, 0xe5, 0xe5, + 0xfb, 0x07, 0x8e, 0x7e, 0xa3, 0x44, 0x64, 0x6b, 0xf9, 0xaa, 0x7d, 0x33, 0x75, 0x86, 0xe8, 0xfd, 0xf7, 0xf6, 0x83, + 0x49, 0x4a, 0x69, 0x3f, 0x3c, 0xba, 0xe7, 0xcc, 0x4f, 0xc4, 0xf0, 0x24, 0x14, 0xed, 0x34, 0x47, 0x2e, 0xd7, 0x21, + 0xad, 0xc5, 0x05, 0x50, 0xc9, 0x77, 0x6e, 0x20, 0x99, 0x5e, 0x48, 0x2d, 0x9f, 0x08, 0xcc, 0xff, 0xfc, 0x79, 0x31, + 0x38, 0xb3, 0x32, 0xee, 0x33, 0xa7, 0x07, 0xd7, 0x6e, 0x8f, 0x74, 0x77, 0x5a, 0x01, 0xed, 0x0f, 0x0f, 0x5b, 0xc4, + 0x93, 0xe4, 0x9a, 0x7e, 0xae, 0x63, 0x6c, 0x35, 0x45, 0xaa, 0x69, 0x18, 0x21, 0xb0, 0x6e, 0x85, 0xd5, 0x51, 0xf5, + 0x61, 0xc8, 0x15, 0x66, 0xe1, 0x8e, 0x90, 0xb8, 0x8c, 0x17, 0x53, 0x01, 0x34, 0x3b, 0xe6, 0xb1, 0xc7, 0xa5, 0xf1, + 0x7f, 0x3d, 0x09, 0x74, 0x2f, 0x02, 0x0d, 0x5f, 0xe5, 0xb4, 0x96, 0xdc, 0x4d, 0xc4, 0xbd, 0x4a, 0x2f, 0x54, 0x92, + 0x9e, 0xab, 0x50, 0x04, 0xf9, 0x8e, 0x30, 0xc5, 0x99, 0x30, 0x6f, 0x12, 0xb7, 0x45, 0x51, 0x60, 0xf8, 0x10, 0x13, + 0x5a, 0xe3, 0xae, 0x4e, 0xfa, 0xf3, 0xe7, 0xad, 0x97, 0x10, 0x55, 0x27, 0xcb, 0x99, 0x1e, 0x55, 0x19, 0xbf, 0xa9, + 0x32, 0x8a, 0x11, 0xfd, 0x22, 0xd6, 0xe0, 0x56, 0x59, 0x74, 0xef, 0xe1, 0xcf, 0x29, 0x71, 0x33, 0x8b, 0xe9, 0x41, + 0x34, 0xe9, 0x72, 0x37, 0x1c, 0xd2, 0x05, 0x7b, 0x2c, 0x16, 0x7f, 0x8b, 0x05, 0x9b, 0x7b, 0xb6, 0xfd, 0xb8, 0x66, + 0x7e, 0xc8, 0xd0, 0xc7, 0x67, 0xbb, 0x08, 0x9e, 0xf2, 0x2e, 0x73, 0x69, 0x84, 0x0d, 0xf9, 0xca, 0x8d, 0x32, 0x97, + 0xe7, 0x15, 0x01, 0xba, 0x7c, 0xd8, 0xa8, 0x30, 0x94, 0x7c, 0x95, 0xc7, 0xef, 0xae, 0xbe, 0x53, 0xd8, 0xfe, 0xa7, + 0xfa, 0x2d, 0x64, 0x64, 0x68, 0x14, 0xfc, 0x11, 0x8d, 0x82, 0xaf, 0xb0, 0xb4, 0x12, 0x10, 0x4b, 0x3e, 0x3f, 0xa2, + 0x10, 0x54, 0x15, 0x12, 0x7a, 0x54, 0xeb, 0xb7, 0x5a, 0x07, 0x99, 0x1f, 0xbb, 0x49, 0x76, 0x04, 0x4d, 0x4d, 0x40, + 0x72, 0x6a, 0x9b, 0x07, 0x33, 0x55, 0x1c, 0x72, 0xa1, 0x5a, 0x16, 0x72, 0xcd, 0xe1, 0xdc, 0x0f, 0x84, 0xe2, 0x90, + 0x7f, 0xc0, 0xf5, 0x3c, 0x12, 0x67, 0x23, 0xd5, 0x8d, 0x21, 0x1b, 0x02, 0xc6, 0x37, 0x3e, 0x8a, 0xbc, 0x8c, 0x64, + 0x66, 0x9a, 0x25, 0xc4, 0x5d, 0xa9, 0x22, 0xd6, 0x67, 0xbd, 0xbf, 0x74, 0x3d, 0x5d, 0xf9, 0x99, 0x08, 0x96, 0x47, + 0x27, 0x08, 0x2a, 0x3c, 0x18, 0xe2, 0x78, 0x92, 0x33, 0x10, 0x5e, 0x46, 0x8b, 0xca, 0x8e, 0x2a, 0x28, 0x97, 0x73, + 0x0c, 0xc5, 0xca, 0x22, 0xe0, 0xcf, 0xd0, 0x23, 0xe7, 0x96, 0x79, 0x5d, 0x8b, 0x98, 0x7e, 0xea, 0xf8, 0x8c, 0xb1, + 0xb7, 0x0a, 0x06, 0x0a, 0x50, 0x7b, 0x36, 0x04, 0x9b, 0x6d, 0xf3, 0xc7, 0x3e, 0x62, 0x95, 0xe1, 0x6a, 0xa2, 0x3d, + 0x63, 0xdc, 0x6f, 0x3a, 0x96, 0x2b, 0x20, 0x84, 0x4a, 0x2a, 0xde, 0xa5, 0x33, 0x16, 0x0e, 0x40, 0x38, 0x2a, 0xa4, + 0x95, 0x3e, 0x7f, 0x7e, 0x3d, 0xf9, 0xcf, 0xbf, 0x21, 0x38, 0xf9, 0xd2, 0xe1, 0x5e, 0xd0, 0xd7, 0x72, 0x2d, 0x46, + 0x7d, 0x1a, 0x13, 0x54, 0xef, 0x93, 0x19, 0x0f, 0x0b, 0xc2, 0xb7, 0x56, 0x3e, 0xb9, 0xe1, 0xa1, 0x9e, 0x20, 0x01, + 0x81, 0xce, 0x7d, 0xb5, 0x27, 0xb0, 0xbc, 0x13, 0x1e, 0x22, 0x40, 0xf9, 0x75, 0xf3, 0x7d, 0x1f, 0xb2, 0xf4, 0xd6, + 0xf2, 0x02, 0x48, 0x03, 0xc4, 0x3d, 0x34, 0x3e, 0x73, 0x99, 0xf0, 0x15, 0xc8, 0x8f, 0x74, 0x70, 0x04, 0xd3, 0x5c, + 0x46, 0x2b, 0x62, 0xf9, 0xd1, 0xd1, 0x3d, 0x99, 0x9a, 0x6e, 0xec, 0x53, 0xf9, 0x32, 0xca, 0xdd, 0x14, 0x4a, 0xf9, + 0x09, 0x05, 0x2d, 0xa5, 0xaf, 0xf3, 0x02, 0x94, 0x51, 0x01, 0x28, 0xf8, 0xe9, 0x8e, 0xcb, 0x01, 0xfc, 0x2c, 0x1e, + 0x31, 0xbe, 0x8c, 0xe5, 0xcf, 0x69, 0x1c, 0x3e, 0x1e, 0x72, 0xaf, 0x78, 0x30, 0xa3, 0xf9, 0x5c, 0x0e, 0xba, 0x67, + 0x95, 0xbf, 0x2f, 0xa0, 0x52, 0xec, 0xd9, 0x28, 0xa6, 0x5f, 0xaa, 0x7f, 0x42, 0xfc, 0x84, 0x6c, 0xb9, 0x2c, 0x3e, + 0x23, 0x9c, 0xe7, 0x5a, 0xf0, 0x3e, 0x01, 0x92, 0xa7, 0xb4, 0x12, 0x43, 0x14, 0xd5, 0xc8, 0xd0, 0x2d, 0xa4, 0xc9, + 0x93, 0xd1, 0x88, 0xe2, 0xb1, 0x2a, 0x3a, 0x03, 0x28, 0x35, 0x44, 0xcf, 0x87, 0xc9, 0x66, 0xd0, 0xd0, 0xa4, 0x1e, + 0x5c, 0xd8, 0xa8, 0x3a, 0x9d, 0xfa, 0x18, 0x8f, 0x5c, 0xbe, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5b, 0x58, 0x40, + 0xe0, 0xbc, 0x9f, 0x0a, 0x1e, 0x57, 0xbe, 0xa5, 0x28, 0xdb, 0x0c, 0xdc, 0x87, 0x48, 0xd2, 0xac, 0x33, 0x27, 0xfb, + 0x4b, 0x2c, 0xbd, 0xe2, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0x22, 0x90, 0xd7, 0x4f, 0x93, 0x1c, 0x32, 0x7c, 0xdf, 0x61, + 0x92, 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xec, 0x08, 0xe6, 0x07, + 0x81, 0x01, 0x4a, 0x94, 0x91, 0xaf, 0x43, 0xf4, 0x01, 0x37, 0xa5, 0xd6, 0x01, 0x17, 0x33, 0x4e, 0xd4, 0x21, 0xe7, + 0x28, 0xa2, 0x83, 0x96, 0xaa, 0xd4, 0x89, 0x15, 0xbb, 0x99, 0xca, 0xdb, 0x1f, 0xb1, 0xff, 0xb7, 0x35, 0x86, 0xeb, + 0xcf, 0x87, 0x19, 0xe1, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x4a, 0xb0, 0xee, 0xa8, 0x50, 0xec, + 0xe3, 0x5d, 0xb5, 0x0a, 0xd2, 0x48, 0x54, 0x8b, 0x5d, 0x4d, 0x7d, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, + 0x65, 0x36, 0x82, 0xaa, 0x5c, 0xd8, 0xee, 0xc6, 0x31, 0xad, 0xac, 0x0f, 0xcf, 0x8e, 0x28, 0xdf, 0x39, 0xa6, 0x3b, + 0x6c, 0x7c, 0x06, 0xd6, 0x85, 0x74, 0xd1, 0xdd, 0x38, 0x66, 0x4b, 0x4a, 0x7f, 0xd1, 0x37, 0x47, 0xcb, 0x6c, 0x15, + 0x8c, 0xff, 0x0f, 0x00, 0xa3, 0x9b, 0x76, 0x11, 0x5a, 0x03, 0x00}; } // namespace web_server } // namespace esphome From 2eebee1de7d4f8b38ee84e15ff29500f0ca5eb57 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 01:49:00 -1000 Subject: [PATCH 1786/2607] Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) --- esphome/dashboard/status/mqtt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/dashboard/status/mqtt.py b/esphome/dashboard/status/mqtt.py index 0e53c21679..8c35dd2535 100644 --- a/esphome/dashboard/status/mqtt.py +++ b/esphome/dashboard/status/mqtt.py @@ -18,7 +18,7 @@ class MqttStatusThread(threading.Thread): """Run the status thread.""" dashboard = DASHBOARD entries = dashboard.entries - current_entries = entries.async_all() + current_entries = entries.all() config = mqtt.config_from_env() topic = "esphome/discover/#" @@ -33,7 +33,7 @@ class MqttStatusThread(threading.Thread): return for entry in current_entries: if entry.name == data["name"]: - entries.async_set_state(entry, EntryState.ONLINE) + entries.set_state(entry, EntryState.ONLINE) return def on_connect(client, userdata, flags, return_code): @@ -53,11 +53,11 @@ class MqttStatusThread(threading.Thread): client.loop_start() while not dashboard.stop_event.wait(2): - current_entries = entries.async_all() + current_entries = entries.all() # will be set to true on on_message for entry in current_entries: if entry.no_mdns: - entries.async_set_state(entry, EntryState.OFFLINE) + entries.set_state(entry, EntryState.OFFLINE) client.publish("esphome/discover", None, retain=False) dashboard.mqtt_ping_request.wait() From efde677ca905548986d4ed02d7154bc7b17e3249 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 01:52:24 -1000 Subject: [PATCH 1787/2607] Fix DashboardEntries.all() call (#6783) --- esphome/dashboard/entries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/dashboard/entries.py b/esphome/dashboard/entries.py index cd318ba8a7..7a9bff4ec1 100644 --- a/esphome/dashboard/entries.py +++ b/esphome/dashboard/entries.py @@ -103,7 +103,7 @@ class DashboardEntries: def all(self) -> list[DashboardEntry]: """Return all entries.""" - return asyncio.run_coroutine_threadsafe(self._async_all, self._loop).result() + return asyncio.run_coroutine_threadsafe(self._async_all(), self._loop).result() def async_all(self) -> list[DashboardEntry]: """Return all entries.""" From cd0f55794053cb19d2f966e2489cd67ec6d45786 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 21 May 2024 10:53:16 +1200 Subject: [PATCH 1788/2607] [remote_receiver] Add better error message for tolerance breaking change (#6784) --- esphome/components/remote_receiver/__init__.py | 8 +++++++- tests/components/remote_receiver/esp32-common.yaml | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 6fe20153f4..e5085bb33c 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -63,7 +63,13 @@ def validate_tolerance(value): if "%" in str(value): type_ = TYPE_PERCENTAGE else: - type_ = TYPE_TIME + try: + cv.positive_time_period_microseconds(value) + type_ = TYPE_TIME + except cv.Invalid as exc: + raise cv.Invalid( + "Tolerance must be a percentage or time. Configurations made before 2024.5.0 treated the value as a percentage." + ) from exc return TOLERANCE_SCHEMA( { diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index 0e71143fc3..ad76bf51f0 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -3,6 +3,7 @@ remote_receiver: pin: ${pin} rmt_channel: ${rmt_channel} dump: all + tolerance: 25% on_abbwelcome: then: - logger.log: From 5eb8efd8b3e3d6d626a869126cced35606082262 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Tue, 21 May 2024 10:55:56 +1200 Subject: [PATCH 1789/2607] Update webserver local assets to 20240519-215627 (#6779) --- .../components/web_server/server_index_v3.h | 7970 ++++++++--------- 1 file changed, 3977 insertions(+), 3993 deletions(-) diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 66cd9de47a..f2f278b08f 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -10,4004 +10,3988 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0x6d, 0x7b, 0xdb, 0xb6, 0xb2, 0x28, 0xfa, - 0xf9, 0x9e, 0x5f, 0x61, 0x73, 0xa7, 0x2e, 0x61, 0x41, 0xb4, 0x24, 0x5b, 0x8e, 0x43, 0x19, 0xd6, 0x71, 0x9c, 0xa4, - 0x49, 0x9b, 0x26, 0x69, 0x9c, 0x26, 0x4d, 0x54, 0x6d, 0x07, 0x22, 0x21, 0x09, 0x0d, 0x45, 0xa8, 0x04, 0x14, 0xdb, - 0x95, 0xf4, 0xdf, 0xef, 0x33, 0x78, 0x21, 0x41, 0x49, 0xc9, 0x5a, 0xeb, 0xdc, 0x73, 0xee, 0x73, 0x76, 0xf7, 0x8a, - 0x45, 0xbc, 0x63, 0x30, 0x18, 0xcc, 0x0c, 0x66, 0x06, 0xe7, 0xfb, 0xa9, 0x48, 0xd4, 0xfd, 0x9c, 0xed, 0x4d, 0xd5, - 0x2c, 0xbb, 0x38, 0xb7, 0xff, 0x32, 0x9a, 0x5e, 0x9c, 0x67, 0x3c, 0xff, 0xb2, 0x57, 0xb0, 0x8c, 0xf0, 0x44, 0xe4, - 0x7b, 0xd3, 0x82, 0x8d, 0x49, 0x4a, 0x15, 0x8d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xc5, 0xf9, 0x8c, 0x29, 0xba, - 0x97, 0x4c, 0x69, 0x21, 0x99, 0x22, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbb, 0x38, 0x97, 0x49, 0xc1, 0xe7, 0x6a, 0x0f, - 0x9a, 0x24, 0x33, 0x91, 0x2e, 0x32, 0x76, 0x71, 0x74, 0x74, 0x7b, 0x7b, 0x1b, 0xfd, 0x25, 0xff, 0xc7, 0x57, 0x5a, - 0xec, 0xfd, 0x52, 0x90, 0xd7, 0xa3, 0xbf, 0x58, 0xa2, 0xa2, 0x94, 0x8d, 0x79, 0xce, 0xde, 0x14, 0x62, 0xce, 0x0a, - 0x75, 0xdf, 0x83, 0xcc, 0x9f, 0x0a, 0x12, 0x72, 0xac, 0x30, 0x43, 0xe4, 0x42, 0xed, 0xf1, 0x7c, 0x8f, 0xf7, 0x7f, - 0x29, 0x74, 0xca, 0x92, 0xe5, 0x8b, 0x19, 0x2b, 0xe8, 0x28, 0x63, 0xf1, 0x7e, 0x0b, 0x27, 0x22, 0x1f, 0xf3, 0xc9, - 0xa2, 0xfc, 0xbe, 0x2d, 0xb8, 0x72, 0xbf, 0xbf, 0xd2, 0x6c, 0xc1, 0x62, 0xb6, 0x46, 0x31, 0x1f, 0xa8, 0x21, 0x61, - 0xba, 0xe5, 0x2f, 0x55, 0xc3, 0xe1, 0x4f, 0xba, 0xc9, 0xfb, 0x39, 0x13, 0xe3, 0x3d, 0xb5, 0x4f, 0x02, 0x79, 0x3f, - 0x1b, 0x89, 0x2c, 0xe8, 0xab, 0x46, 0x10, 0xc4, 0x50, 0x06, 0x33, 0xd4, 0x4b, 0x44, 0x2e, 0xd5, 0x9e, 0xe4, 0xe4, - 0x96, 0xe7, 0xa9, 0xb8, 0xc5, 0x5f, 0x25, 0x91, 0x3c, 0xba, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x1d, 0x1c, - 0x84, 0xf6, 0xfb, 0xfe, 0xea, 0xfa, 0x9a, 0x10, 0xf2, 0x55, 0xf0, 0x74, 0xaf, 0xb5, 0x5a, 0x79, 0xa9, 0x51, 0x4e, - 0x15, 0xff, 0xca, 0x4c, 0x25, 0x74, 0x70, 0x10, 0xd0, 0x54, 0xcc, 0x15, 0x4b, 0xaf, 0xd5, 0x7d, 0xc6, 0xae, 0xa7, - 0x8c, 0x29, 0x19, 0xf0, 0x7c, 0xef, 0x89, 0x48, 0x16, 0x33, 0x96, 0xab, 0x68, 0x5e, 0x08, 0x25, 0x60, 0x60, 0x07, - 0x07, 0x41, 0xc1, 0xe6, 0x19, 0x4d, 0x18, 0xe4, 0x5f, 0x5d, 0x5f, 0x57, 0x35, 0xaa, 0x42, 0xf8, 0x56, 0x92, 0x6b, - 0x3d, 0xf4, 0x10, 0xe1, 0xe7, 0x92, 0xe4, 0xec, 0x76, 0xef, 0x03, 0xa3, 0x5f, 0x7e, 0xa5, 0xf3, 0x5e, 0x92, 0x51, - 0x29, 0xf7, 0x9e, 0x89, 0xa5, 0x9e, 0x46, 0xb1, 0x48, 0x94, 0x28, 0x42, 0x85, 0x19, 0x96, 0x68, 0xc9, 0xc7, 0xa1, - 0x9a, 0x72, 0x19, 0xdd, 0x3c, 0x48, 0xa4, 0x7c, 0xcb, 0xe4, 0x22, 0x53, 0x0f, 0xc8, 0x7e, 0x0b, 0xcb, 0x7d, 0x42, - 0x6e, 0x25, 0x52, 0xd3, 0x42, 0xdc, 0xee, 0x3d, 0x2d, 0x0a, 0x51, 0x84, 0xc1, 0xd5, 0xf5, 0xb5, 0x29, 0xb1, 0xc7, - 0xe5, 0x5e, 0x2e, 0xd4, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xda, 0xfb, 0x5d, 0xb2, 0xbd, 0xcf, 0x8b, 0x5c, 0xd2, 0x31, - 0xbb, 0xba, 0xbe, 0xfe, 0xbc, 0x27, 0x8a, 0xbd, 0xcf, 0x89, 0x94, 0x9f, 0xf7, 0x78, 0x2e, 0x15, 0xa3, 0x69, 0x14, - 0xa0, 0x9e, 0xee, 0x2c, 0x91, 0xf2, 0x1d, 0xbb, 0x53, 0x44, 0x61, 0xfd, 0xa9, 0x08, 0x5b, 0x4f, 0x98, 0xda, 0x93, - 0xe5, 0xbc, 0x42, 0xb4, 0xcc, 0x98, 0xda, 0x53, 0x44, 0xe7, 0x0b, 0x0b, 0x7f, 0x66, 0x3e, 0x55, 0x8f, 0x8f, 0xc3, - 0xaf, 0xf2, 0xe0, 0x40, 0x95, 0x80, 0x46, 0x4b, 0xbb, 0x42, 0x84, 0xed, 0xbb, 0xb4, 0x83, 0x03, 0x16, 0x65, 0x2c, - 0x9f, 0xa8, 0x29, 0x21, 0xa4, 0xdd, 0x93, 0x07, 0x07, 0xa1, 0x22, 0xcf, 0x65, 0x34, 0x61, 0x2a, 0x64, 0x08, 0xe1, - 0xaa, 0xf6, 0xc1, 0x41, 0x68, 0x80, 0x20, 0x88, 0xd2, 0x80, 0xab, 0xc1, 0x18, 0x45, 0x16, 0xfa, 0xd7, 0xf7, 0x79, - 0x12, 0xfa, 0xe3, 0x47, 0x58, 0x1e, 0x1c, 0x3c, 0x97, 0x91, 0x84, 0x16, 0xb1, 0x42, 0x68, 0x5d, 0x30, 0xb5, 0x28, - 0xf2, 0x3d, 0xb5, 0x56, 0xe2, 0x5a, 0x15, 0x3c, 0x9f, 0x84, 0x68, 0xe9, 0xd2, 0xbc, 0x8a, 0xeb, 0xb5, 0x19, 0xee, - 0x6f, 0x05, 0xe1, 0xe4, 0x02, 0x7a, 0x7c, 0x26, 0x42, 0x8b, 0x83, 0x9c, 0x90, 0x40, 0xea, 0xba, 0x41, 0x9f, 0xc7, - 0xbc, 0x11, 0x04, 0xd8, 0x8c, 0x12, 0xdf, 0x4a, 0x84, 0xb9, 0x02, 0xd4, 0x8d, 0xa2, 0x48, 0x21, 0x72, 0xb1, 0x74, - 0x60, 0xe1, 0xde, 0x44, 0xfb, 0x7c, 0xd0, 0x1a, 0xc6, 0x2a, 0x2a, 0x58, 0xba, 0x48, 0x58, 0x18, 0x4a, 0x9c, 0x63, - 0x81, 0xc8, 0x85, 0x6c, 0x84, 0x05, 0xb9, 0x80, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xd9, 0x41, 0x16, - 0x6e, 0x84, 0x00, 0x62, 0x3b, 0xa0, 0x82, 0x90, 0x20, 0x5f, 0xcc, 0x46, 0xac, 0x08, 0xca, 0x62, 0xbd, 0x1a, 0x5e, - 0x2c, 0x24, 0xdb, 0x4b, 0xa4, 0xdc, 0x1b, 0x2f, 0xf2, 0x44, 0x71, 0x91, 0xef, 0x05, 0x8d, 0xa2, 0x11, 0x18, 0x7c, - 0x28, 0xd1, 0x21, 0x40, 0x6b, 0x14, 0xe6, 0xa8, 0xc1, 0x07, 0xa2, 0xd1, 0x1e, 0x62, 0x18, 0x25, 0xea, 0xd9, 0xf6, - 0x2c, 0x04, 0x18, 0xe6, 0x30, 0xc9, 0x35, 0xfe, 0x64, 0x76, 0x3e, 0x4c, 0xf1, 0xab, 0xec, 0xf3, 0x68, 0x7b, 0xa7, - 0x10, 0x15, 0xcd, 0xe8, 0x3c, 0x64, 0xe4, 0x82, 0x69, 0xec, 0xa2, 0x79, 0x02, 0x63, 0xad, 0x2d, 0x5c, 0x9f, 0xc5, - 0x2c, 0xaa, 0x70, 0x0a, 0xc5, 0x2a, 0x1a, 0x8b, 0xe2, 0x29, 0x4d, 0xa6, 0x50, 0xaf, 0xc4, 0x98, 0xd4, 0x6d, 0xb8, - 0xa4, 0x60, 0x54, 0xb1, 0xa7, 0x19, 0x83, 0xaf, 0x30, 0xd0, 0x35, 0x03, 0x84, 0x73, 0xd8, 0xea, 0x19, 0x57, 0xaf, - 0x44, 0x9e, 0xb0, 0x5e, 0xee, 0xe1, 0x97, 0x5e, 0xf9, 0x4b, 0xa5, 0x0a, 0x3e, 0x5a, 0x28, 0x16, 0x06, 0x39, 0x94, - 0x08, 0x70, 0x8e, 0xb0, 0x8c, 0x14, 0xbb, 0x53, 0x57, 0x22, 0x57, 0x2c, 0x57, 0x84, 0x39, 0xa8, 0x62, 0x1e, 0xd1, - 0xf9, 0x9c, 0xe5, 0xe9, 0xd5, 0x94, 0x67, 0x69, 0x28, 0xd1, 0x1a, 0xad, 0xf1, 0x07, 0x49, 0x60, 0x92, 0xe4, 0x82, - 0xc7, 0xf0, 0xcf, 0xb7, 0xa7, 0x13, 0x2a, 0x72, 0xa1, 0xb7, 0x05, 0x23, 0x41, 0xd0, 0x1b, 0x8b, 0x22, 0xb4, 0x53, - 0xd8, 0x03, 0xd2, 0x05, 0x7d, 0xbc, 0x5d, 0x64, 0x4c, 0x22, 0xd6, 0x20, 0x25, 0xa6, 0x39, 0x08, 0xff, 0x56, 0x84, - 0x0c, 0x16, 0x80, 0xa3, 0x98, 0x6b, 0x12, 0xf8, 0x92, 0xdb, 0x4d, 0x95, 0x96, 0x44, 0xed, 0x77, 0x49, 0x52, 0x1e, - 0xa9, 0x62, 0x21, 0x15, 0x4b, 0xdf, 0xdd, 0xcf, 0x99, 0xc4, 0x3f, 0x17, 0xe4, 0x77, 0xd9, 0xff, 0x5d, 0x46, 0x6c, - 0x36, 0x57, 0xf7, 0xd7, 0x9a, 0x9a, 0xc7, 0x41, 0x80, 0x3f, 0xea, 0xa2, 0x05, 0xa3, 0x09, 0x90, 0x34, 0x0b, 0xb2, - 0x37, 0x22, 0xbb, 0x1f, 0xf3, 0x2c, 0xbb, 0x5e, 0xcc, 0xe7, 0xa2, 0x50, 0x58, 0x49, 0xb2, 0x54, 0xa2, 0x82, 0x0f, - 0xac, 0xe8, 0x52, 0xde, 0x72, 0x95, 0x4c, 0x43, 0x85, 0x96, 0x09, 0x95, 0x6c, 0xef, 0xb1, 0x10, 0x19, 0xa3, 0x79, - 0xcc, 0x09, 0xef, 0xff, 0x5c, 0xc4, 0xf9, 0x22, 0xcb, 0x7a, 0xa3, 0x82, 0xd1, 0x2f, 0x3d, 0x9d, 0x6d, 0x0e, 0x87, - 0x58, 0xff, 0xbe, 0x2c, 0x0a, 0x7a, 0x0f, 0x05, 0x09, 0x81, 0x62, 0x7d, 0x1e, 0xff, 0x7c, 0xfd, 0xfa, 0x55, 0x64, - 0xf6, 0x0a, 0x1f, 0xdf, 0x87, 0xbc, 0xdc, 0x7f, 0x7c, 0x8d, 0xc7, 0x85, 0x98, 0x6d, 0x74, 0x6d, 0x40, 0xc7, 0x7b, - 0xdf, 0x18, 0x02, 0x23, 0x7c, 0xdf, 0x34, 0xed, 0x8f, 0xe0, 0x95, 0xc6, 0x7c, 0xc8, 0x24, 0xb6, 0x5f, 0xf8, 0x27, - 0x36, 0xc9, 0x21, 0x47, 0xdf, 0x1f, 0xad, 0x2a, 0xee, 0x97, 0x8c, 0xe8, 0x71, 0xce, 0xe1, 0x60, 0x84, 0x31, 0x26, - 0x54, 0x25, 0xd3, 0x25, 0xd3, 0x8d, 0xad, 0xdd, 0x88, 0xd9, 0x7a, 0x8d, 0x5f, 0x09, 0x87, 0xf5, 0x6a, 0x9f, 0x10, - 0xae, 0xe9, 0x15, 0x51, 0xab, 0x15, 0x27, 0x84, 0x23, 0xfc, 0x96, 0x93, 0x25, 0x75, 0x13, 0x82, 0x93, 0x0d, 0xb6, - 0x67, 0x6c, 0xa8, 0x0c, 0x9c, 0x80, 0x5f, 0x59, 0xa1, 0x58, 0x11, 0x2b, 0x89, 0x0b, 0x36, 0xce, 0x60, 0x1c, 0xfb, - 0x6d, 0x3c, 0xa5, 0xf2, 0x6a, 0x4a, 0xf3, 0x09, 0x4b, 0xe3, 0x57, 0x62, 0x8d, 0x99, 0x24, 0xc1, 0x98, 0xe7, 0x34, - 0xe3, 0xff, 0xb0, 0x34, 0xb0, 0xe7, 0xc2, 0x63, 0xb5, 0xc7, 0xee, 0x14, 0xcb, 0x53, 0xb9, 0xf7, 0xfc, 0xdd, 0xaf, - 0x2f, 0xed, 0x62, 0xd6, 0xce, 0x0a, 0xb4, 0x94, 0x8b, 0x39, 0x2b, 0x42, 0x84, 0xed, 0x59, 0xf1, 0x94, 0x6b, 0x3a, - 0xf9, 0x2b, 0x9d, 0x9b, 0x14, 0x2e, 0x7f, 0x9f, 0xa7, 0x54, 0xb1, 0x37, 0x2c, 0x4f, 0x79, 0x3e, 0x21, 0xfb, 0x6d, - 0x93, 0x3e, 0xa5, 0x36, 0x23, 0x2d, 0x93, 0x6e, 0x1e, 0x3c, 0xcd, 0xf4, 0xdc, 0xcb, 0xcf, 0x45, 0x88, 0xd6, 0x52, - 0x51, 0xc5, 0x93, 0x3d, 0x9a, 0xa6, 0x2f, 0x72, 0xae, 0xb8, 0x1e, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xcc, 0xa9, - 0xe1, 0x46, 0x1e, 0x22, 0x1c, 0x86, 0xf6, 0x2c, 0x98, 0x22, 0xbb, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb3, 0xd8, - 0x64, 0x92, 0xc1, 0x10, 0x45, 0xf3, 0x85, 0x84, 0xc5, 0x76, 0x5d, 0xc0, 0x41, 0x23, 0x46, 0x92, 0x15, 0x5f, 0x59, - 0x5a, 0x22, 0x88, 0x0c, 0xd1, 0x72, 0xa3, 0x0f, 0xbb, 0x3d, 0x14, 0x19, 0x0c, 0x7b, 0x3e, 0x09, 0x67, 0x16, 0xd9, - 0x0d, 0xa7, 0xc2, 0x99, 0x2c, 0x89, 0x4a, 0x08, 0x07, 0x6a, 0x49, 0x58, 0x72, 0xe2, 0xe6, 0x37, 0x0f, 0x25, 0xf0, - 0x10, 0x3e, 0xe5, 0x70, 0x67, 0xee, 0xd3, 0xaf, 0xfa, 0xf0, 0xc8, 0xb1, 0x44, 0x58, 0x99, 0x91, 0xe6, 0x08, 0xad, - 0x11, 0x56, 0x6e, 0xb8, 0x86, 0x28, 0x39, 0xbe, 0x08, 0x4e, 0x6d, 0xf2, 0x96, 0xeb, 0x63, 0x1b, 0x68, 0x1b, 0x55, - 0xec, 0xe0, 0x20, 0x64, 0x51, 0x89, 0x18, 0x64, 0xbf, 0x6d, 0x17, 0xc9, 0x83, 0xd6, 0x37, 0xc6, 0x0d, 0x3d, 0x6b, - 0x06, 0x67, 0x9f, 0x45, 0xb9, 0xb8, 0x4c, 0x12, 0x26, 0xa5, 0x28, 0x0e, 0x0e, 0xf6, 0x75, 0xf9, 0x92, 0xb3, 0x80, - 0x45, 0x7c, 0x7d, 0x9b, 0x57, 0x43, 0x40, 0xd5, 0x69, 0xeb, 0xf8, 0x26, 0x52, 0xf1, 0x4d, 0x8e, 0x09, 0x89, 0x83, - 0x9b, 0x9b, 0xa0, 0xa1, 0xb0, 0x85, 0xc3, 0x84, 0xb9, 0xae, 0xef, 0x9f, 0x30, 0xc3, 0x16, 0x6a, 0x26, 0x64, 0x0b, - 0x34, 0x3b, 0xf9, 0xc1, 0xb0, 0x3e, 0x24, 0xac, 0x70, 0x8e, 0xd6, 0xde, 0x8a, 0xee, 0x6c, 0x5a, 0xf3, 0x37, 0x66, - 0xe9, 0x96, 0x13, 0xcd, 0x53, 0x78, 0xeb, 0x38, 0x60, 0xc3, 0x35, 0xd6, 0xb0, 0x77, 0xb3, 0x11, 0x7a, 0xa0, 0x03, - 0x35, 0xec, 0xd9, 0x7c, 0x92, 0x1b, 0xc8, 0x15, 0xec, 0xef, 0x05, 0x93, 0xca, 0x20, 0x72, 0xa8, 0xb0, 0xc0, 0x70, - 0x46, 0x6d, 0x32, 0x9d, 0x35, 0x96, 0x74, 0xd7, 0xd8, 0x5e, 0xcf, 0xe1, 0x6c, 0x94, 0x80, 0xd4, 0xdf, 0xc7, 0x27, - 0x18, 0xab, 0x42, 0xab, 0xd5, 0x5b, 0xee, 0x5a, 0xa9, 0xd6, 0xb2, 0xe4, 0xd7, 0x36, 0x16, 0x85, 0x49, 0x64, 0x0f, - 0xe7, 0xfd, 0xb6, 0x1d, 0xbf, 0x1c, 0x92, 0xfd, 0x56, 0x89, 0xc5, 0x16, 0xac, 0x66, 0x3c, 0x06, 0x8a, 0xaf, 0x4d, - 0x53, 0x48, 0x9f, 0xf5, 0x35, 0x7c, 0x89, 0xa6, 0x5b, 0xb8, 0x3a, 0x25, 0x03, 0xe0, 0x3a, 0xa2, 0xe9, 0xf0, 0x5b, - 0xf8, 0xe4, 0x28, 0x42, 0xa8, 0xb6, 0xf3, 0x2a, 0xc2, 0xf1, 0xb5, 0x4e, 0x38, 0x36, 0xa6, 0x11, 0xcc, 0xcb, 0x2a, - 0x41, 0x89, 0x66, 0x76, 0xab, 0x57, 0x59, 0x58, 0xea, 0xc1, 0x54, 0x53, 0xf2, 0x9a, 0x78, 0x45, 0x67, 0x4c, 0x86, - 0x0c, 0xe1, 0x6f, 0x15, 0x30, 0xf8, 0x09, 0x45, 0x86, 0xde, 0x19, 0x9a, 0xc3, 0x19, 0x0a, 0xec, 0x2e, 0x30, 0x69, - 0xf5, 0x2d, 0x97, 0x63, 0x36, 0xc8, 0x87, 0x15, 0x6f, 0xe7, 0x4d, 0x5e, 0x1f, 0xce, 0x92, 0xd4, 0xf6, 0x9b, 0x49, - 0x33, 0x40, 0xd3, 0x2c, 0x84, 0x44, 0x78, 0xbf, 0xb5, 0xb9, 0x92, 0xae, 0x54, 0x35, 0xc7, 0xc1, 0x10, 0xd6, 0x41, - 0x1f, 0x1b, 0x11, 0x97, 0xfa, 0x6f, 0x6d, 0xab, 0x01, 0xd8, 0xae, 0x01, 0x33, 0xa2, 0x71, 0x46, 0x55, 0xd8, 0x3e, - 0x6a, 0x01, 0x63, 0xfa, 0x95, 0xc1, 0xa9, 0x82, 0xd0, 0xf6, 0x54, 0x58, 0xb4, 0xc8, 0xe5, 0x94, 0x8f, 0x55, 0xf8, - 0x41, 0x6a, 0xa2, 0xc2, 0x32, 0xc9, 0x40, 0xc2, 0xf1, 0xd8, 0x63, 0x4d, 0x70, 0x3e, 0xc0, 0x30, 0x4a, 0x56, 0x8c, - 0xb9, 0x91, 0x6a, 0xc2, 0x05, 0xe4, 0xa1, 0x62, 0xad, 0x2b, 0x32, 0xe3, 0x4a, 0x4b, 0xe0, 0x1e, 0xdb, 0x7d, 0xd3, - 0x62, 0x6c, 0xa9, 0x81, 0xf4, 0x38, 0x58, 0x19, 0xfb, 0x24, 0xc2, 0x26, 0xaa, 0x48, 0x89, 0x97, 0xe2, 0x96, 0x15, - 0x57, 0x14, 0x06, 0x1f, 0x9b, 0xea, 0x6b, 0x73, 0x14, 0x68, 0x8a, 0xaf, 0x7a, 0x0e, 0x5f, 0x6e, 0xf4, 0xc4, 0xdf, - 0x14, 0x62, 0xc6, 0x25, 0x03, 0xbe, 0xcd, 0xc0, 0x3f, 0x87, 0x8d, 0xa6, 0x77, 0x24, 0x1c, 0x37, 0xac, 0xc4, 0xaf, - 0xcb, 0x97, 0x75, 0xfc, 0xba, 0x79, 0xf0, 0x74, 0xe2, 0x28, 0x60, 0x7d, 0x1f, 0x23, 0x1c, 0x5a, 0xf1, 0xc2, 0x3b, - 0xe9, 0xa2, 0x29, 0xb2, 0xc7, 0xfc, 0x6a, 0xa5, 0x3c, 0x31, 0xae, 0xc6, 0x39, 0x32, 0xb3, 0x6d, 0xd0, 0x9a, 0xa6, - 0x29, 0xb0, 0x78, 0x85, 0xc8, 0x32, 0xef, 0xb0, 0xc2, 0xb2, 0x57, 0x1e, 0x4f, 0x37, 0x0f, 0x9e, 0x5e, 0x7f, 0xef, - 0x84, 0x82, 0x7c, 0xff, 0x90, 0x72, 0x03, 0xcd, 0x53, 0x56, 0x80, 0x5c, 0xe9, 0xad, 0x96, 0x3d, 0x67, 0xaf, 0x44, - 0x9e, 0xb3, 0x44, 0xb1, 0x14, 0x84, 0x16, 0x60, 0x83, 0xa7, 0x42, 0xaa, 0x32, 0xb1, 0x1a, 0xbd, 0xf4, 0x85, 0xd0, - 0x28, 0xa1, 0x59, 0x16, 0x1a, 0x01, 0x65, 0x26, 0xbe, 0xb2, 0x1d, 0xa3, 0xee, 0xd5, 0x86, 0x5c, 0x36, 0xc3, 0xbc, - 0x66, 0x58, 0x24, 0xe7, 0x19, 0x4f, 0x58, 0x79, 0x78, 0x5d, 0x47, 0x3c, 0x4f, 0xd9, 0x1d, 0xd0, 0x11, 0x74, 0x71, - 0x71, 0xd1, 0xc2, 0x6d, 0xb4, 0x36, 0x00, 0x5f, 0x6e, 0x01, 0xf6, 0x3b, 0xc7, 0xa6, 0x11, 0xc4, 0x97, 0x3b, 0xc9, - 0x1a, 0xf2, 0xce, 0x4a, 0xee, 0x04, 0x2d, 0x43, 0x9e, 0x11, 0x4e, 0x59, 0xc6, 0x14, 0x73, 0xe4, 0x1c, 0x98, 0x69, - 0xb3, 0x75, 0xdf, 0x96, 0xf0, 0x2b, 0xd1, 0xc9, 0xed, 0x32, 0xb7, 0xe6, 0xb2, 0x14, 0xdd, 0xab, 0xe5, 0xa9, 0xa0, - 0xdd, 0x57, 0x66, 0x79, 0xa8, 0x52, 0x34, 0x99, 0x1a, 0x89, 0x3d, 0xdc, 0x9a, 0x52, 0xd5, 0x86, 0x25, 0xed, 0xe5, - 0x26, 0xfa, 0x54, 0xd8, 0x61, 0xee, 0x02, 0xc1, 0xb5, 0x25, 0x0a, 0x0c, 0x84, 0x40, 0xb3, 0x6c, 0x57, 0x34, 0xcb, - 0x46, 0x34, 0xf9, 0x52, 0xc7, 0xfe, 0x0a, 0x0d, 0xc8, 0x26, 0x35, 0xf6, 0xb2, 0x3c, 0x92, 0xe5, 0xcf, 0xdb, 0x51, - 0xe9, 0xda, 0x46, 0x09, 0xf7, 0x5b, 0x15, 0xda, 0xd7, 0x17, 0xfa, 0x9b, 0xd8, 0xae, 0x47, 0x24, 0xed, 0xcc, 0x42, - 0xa0, 0x02, 0xff, 0x12, 0xe3, 0x1c, 0x3d, 0xb0, 0x78, 0x07, 0x82, 0xc7, 0x7a, 0x63, 0x20, 0x0a, 0x2d, 0xd7, 0x29, - 0x97, 0xdf, 0x86, 0xc0, 0xff, 0x96, 0x51, 0x3e, 0xf1, 0x7a, 0xf8, 0x77, 0x07, 0x5a, 0xd2, 0x38, 0xcb, 0x38, 0x97, - 0x23, 0xb3, 0x0c, 0x85, 0x23, 0x34, 0xbf, 0x00, 0xf3, 0xa2, 0xf1, 0xfd, 0xb5, 0xc9, 0xd2, 0x7c, 0x19, 0x0c, 0x23, - 0xef, 0xf9, 0x0c, 0x45, 0x0d, 0x05, 0x2c, 0x51, 0x35, 0x67, 0xae, 0xa8, 0x89, 0x92, 0x96, 0x6b, 0x37, 0xe2, 0xb8, - 0xa5, 0xb9, 0x05, 0x09, 0xc3, 0x30, 0x27, 0xba, 0x0d, 0xc3, 0xdf, 0x57, 0xb3, 0xc8, 0xb7, 0x66, 0x91, 0x47, 0x9e, - 0xb4, 0x85, 0x2a, 0x64, 0xf6, 0xaa, 0xc7, 0x4a, 0x22, 0xbf, 0x14, 0xb0, 0xac, 0x11, 0x50, 0x68, 0x54, 0x12, 0xdc, - 0x8c, 0x28, 0x5c, 0x58, 0x51, 0xc7, 0xe2, 0x1a, 0x90, 0x8c, 0xaa, 0x8a, 0x40, 0x66, 0x73, 0xd4, 0x64, 0x5f, 0x81, - 0x0b, 0xb4, 0xc1, 0xdf, 0xaf, 0xd7, 0x16, 0x4a, 0x0c, 0xd9, 0xd5, 0xa9, 0x31, 0xc6, 0x1e, 0x58, 0xb0, 0x20, 0xb9, - 0x61, 0x86, 0x0d, 0xeb, 0xb3, 0x09, 0x9c, 0xb2, 0xdd, 0x7d, 0x42, 0x44, 0x05, 0x9b, 0x3c, 0xda, 0xc1, 0x5d, 0x09, - 0x84, 0xa9, 0x63, 0x4b, 0x8b, 0x6a, 0xe2, 0x84, 0x04, 0x4e, 0x3b, 0x11, 0xf4, 0x97, 0x35, 0xe1, 0x30, 0xf6, 0x8a, - 0xad, 0x63, 0x20, 0xaa, 0xc5, 0x2e, 0x78, 0xef, 0xc2, 0x9a, 0x5a, 0x3b, 0x1e, 0xc4, 0x8b, 0x1a, 0xc4, 0x3d, 0xd0, - 0x0a, 0x43, 0xbc, 0xc4, 0x90, 0xd0, 0x7a, 0xe5, 0x90, 0xe1, 0xc2, 0x2c, 0xc4, 0x16, 0x14, 0x37, 0xd9, 0x4f, 0x8d, - 0x85, 0x20, 0xcb, 0xe6, 0xc0, 0xdf, 0xf9, 0x47, 0x44, 0x08, 0x83, 0x97, 0xab, 0xd5, 0x16, 0xda, 0xed, 0xe4, 0x42, - 0x51, 0x54, 0x49, 0x87, 0xab, 0xd5, 0x2b, 0x81, 0x42, 0xcb, 0xff, 0x62, 0x86, 0xfa, 0x8e, 0xe8, 0x5e, 0xbe, 0x84, - 0x52, 0x9a, 0x1d, 0xad, 0x52, 0x4a, 0xc1, 0xa1, 0x8e, 0xb5, 0xf5, 0x85, 0x52, 0x1e, 0xe5, 0xbe, 0xda, 0x22, 0x60, - 0x3a, 0xd1, 0x9e, 0xd4, 0xd5, 0x94, 0xaf, 0x6c, 0xd3, 0x12, 0x21, 0x14, 0xe7, 0x5a, 0x96, 0xd9, 0xdf, 0x25, 0x5f, - 0x1e, 0x1c, 0xe4, 0x5e, 0x43, 0x37, 0x25, 0xa5, 0xf8, 0x2b, 0x84, 0x53, 0x59, 0xde, 0xe7, 0x9a, 0x7d, 0xf9, 0xcb, - 0x9d, 0x43, 0x5b, 0xd2, 0x69, 0xab, 0x07, 0x82, 0x39, 0xbd, 0xa5, 0x5c, 0xed, 0x95, 0xad, 0x18, 0xc1, 0x3c, 0x64, - 0x68, 0x69, 0xb9, 0x8d, 0xa8, 0x60, 0xc0, 0x3f, 0x02, 0x59, 0x70, 0x5c, 0xb4, 0x41, 0xfc, 0x64, 0xca, 0x40, 0x95, - 0xed, 0x18, 0x89, 0x52, 0x3c, 0xdc, 0xb7, 0x07, 0x89, 0x6d, 0x78, 0xf7, 0xd8, 0xd7, 0x9b, 0xd5, 0x6b, 0xd2, 0xc0, - 0x9c, 0x15, 0x63, 0x51, 0xcc, 0x5c, 0xde, 0x7a, 0xe3, 0xdb, 0x12, 0x47, 0x3e, 0x0e, 0x77, 0xb6, 0x6d, 0x45, 0x80, - 0xde, 0x86, 0xec, 0x5d, 0x49, 0xed, 0xb5, 0xd3, 0xb4, 0x3c, 0x80, 0x8d, 0x82, 0xd0, 0x61, 0x66, 0xee, 0x4b, 0xf9, - 0x56, 0xbd, 0xda, 0x33, 0xba, 0x93, 0xfd, 0x76, 0xaf, 0x94, 0xfc, 0x1c, 0x36, 0xf4, 0x8c, 0x8e, 0xc3, 0x9e, 0xaa, - 0x62, 0x91, 0xa5, 0x76, 0xb0, 0x70, 0xc4, 0x59, 0x3c, 0xba, 0xe5, 0x59, 0x56, 0xa5, 0xfe, 0x27, 0xa4, 0x3d, 0xb7, - 0xa4, 0x5d, 0x38, 0xd2, 0x0e, 0xa4, 0x02, 0x48, 0xbb, 0x69, 0xae, 0xaa, 0x2e, 0xb6, 0xb6, 0xa7, 0x30, 0x44, 0x3d, - 0xd7, 0xe2, 0x34, 0xf4, 0xb7, 0x70, 0x23, 0x40, 0x25, 0xf3, 0xf5, 0x25, 0xb4, 0xfa, 0x18, 0x10, 0x03, 0x8d, 0x4e, - 0x93, 0xf9, 0x9a, 0x8a, 0x2f, 0x21, 0xc2, 0xf9, 0x9a, 0x95, 0x98, 0x7d, 0xf9, 0x14, 0x94, 0x76, 0xde, 0x74, 0xe0, - 0x1c, 0xd3, 0xc9, 0xff, 0x11, 0x1f, 0xe5, 0x66, 0x27, 0xed, 0xec, 0x72, 0x37, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0xd2, - 0xef, 0x53, 0x7b, 0x3d, 0x3d, 0x59, 0x4e, 0xaf, 0x5a, 0xef, 0xd5, 0x2a, 0xdc, 0x48, 0x01, 0x8d, 0xbe, 0x95, 0x52, - 0x8a, 0xb2, 0x75, 0xa0, 0x01, 0x3e, 0x64, 0x20, 0x61, 0x6d, 0x26, 0x5d, 0x9e, 0x72, 0x2f, 0xff, 0x95, 0x9e, 0x47, - 0x2b, 0xee, 0x4d, 0xfd, 0x2b, 0x31, 0x9b, 0x03, 0x43, 0xb6, 0x81, 0xd2, 0x13, 0x66, 0x3b, 0xac, 0xf2, 0xd7, 0x3b, - 0xd2, 0x6a, 0x75, 0xf4, 0x7e, 0xac, 0x61, 0x53, 0x29, 0x35, 0xef, 0xb7, 0xd6, 0x8b, 0x32, 0xa9, 0x24, 0x1c, 0xbb, - 0x74, 0x2b, 0x57, 0x9b, 0x9a, 0x19, 0x97, 0xf1, 0x3a, 0x94, 0x86, 0x0e, 0x4b, 0xa0, 0x75, 0x1e, 0xf9, 0x71, 0xe8, - 0xee, 0xaf, 0xff, 0xba, 0x02, 0xce, 0x72, 0xbd, 0x01, 0xbe, 0xe5, 0x7a, 0xfd, 0x58, 0x59, 0x49, 0x1b, 0x3f, 0xde, - 0x21, 0xf7, 0x96, 0xd0, 0xab, 0x32, 0xad, 0xcc, 0x38, 0x18, 0x42, 0xda, 0x16, 0x0b, 0x49, 0x96, 0x33, 0x91, 0xb2, - 0x38, 0x10, 0x73, 0x96, 0x07, 0x6b, 0xd0, 0xb3, 0x5a, 0x04, 0xf8, 0x28, 0xc3, 0xe5, 0xdb, 0xba, 0xbe, 0x35, 0x7e, - 0xac, 0xd6, 0xa0, 0x0a, 0x7b, 0xc9, 0x77, 0x28, 0x63, 0xdf, 0xb3, 0x42, 0x6a, 0x9e, 0xb4, 0x64, 0x6f, 0x5f, 0xf2, - 0xea, 0x80, 0x7a, 0xc9, 0xe3, 0x6f, 0x57, 0xa9, 0x04, 0x92, 0xa0, 0x1d, 0x9d, 0x46, 0xc7, 0x01, 0xd2, 0x1a, 0xe3, - 0x67, 0x4e, 0x63, 0xbc, 0x28, 0x35, 0xc6, 0xcf, 0x15, 0x59, 0x6c, 0x68, 0x8c, 0xff, 0x96, 0xe4, 0xb9, 0xea, 0x3f, - 0x77, 0xda, 0xf4, 0x37, 0x22, 0xe3, 0xc9, 0x7d, 0x18, 0x64, 0x5c, 0x35, 0xe1, 0x36, 0x31, 0xc0, 0x4b, 0x93, 0x01, - 0xaa, 0x46, 0xad, 0xef, 0x5e, 0x3b, 0xf9, 0x0f, 0x73, 0x49, 0x82, 0x07, 0x19, 0x57, 0x0f, 0x02, 0x3c, 0x55, 0xe4, - 0x33, 0xfc, 0x7a, 0xb0, 0x0c, 0x7f, 0xa5, 0x6a, 0x1a, 0x15, 0x34, 0x4f, 0xc5, 0x2c, 0x44, 0x8d, 0x20, 0x40, 0x91, - 0xd4, 0x42, 0xc8, 0x23, 0xb4, 0x7e, 0xf0, 0x19, 0xff, 0x23, 0x48, 0xd0, 0x0f, 0x1a, 0x53, 0x85, 0x15, 0x25, 0x9f, - 0xcf, 0x1f, 0x2c, 0xff, 0x11, 0xeb, 0x8b, 0xcf, 0xf8, 0xa9, 0x2a, 0xd5, 0xfa, 0xf8, 0x8e, 0x91, 0x10, 0x91, 0x8b, - 0xa7, 0x6e, 0x48, 0x57, 0x62, 0x66, 0x14, 0xfc, 0x01, 0xc2, 0x5f, 0x41, 0xaf, 0x7b, 0xc1, 0x2b, 0x22, 0x64, 0xef, - 0x60, 0xf6, 0x49, 0x20, 0xb4, 0xf2, 0x20, 0x38, 0x38, 0xf0, 0xd2, 0x4a, 0x16, 0x02, 0xff, 0x25, 0x48, 0x4d, 0x54, - 0xc7, 0x8c, 0x42, 0x4b, 0x7f, 0x89, 0x90, 0x23, 0xd7, 0x4c, 0xe8, 0x34, 0xd5, 0x76, 0xc7, 0xf2, 0x81, 0xd1, 0x3d, - 0x44, 0x5c, 0xb1, 0x82, 0x2a, 0x51, 0x0c, 0x91, 0xcf, 0x96, 0xe0, 0x57, 0x9c, 0x7c, 0x1e, 0xec, 0xfd, 0x3f, 0xff, - 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xf0, 0x33, 0x96, 0x8c, 0x1c, 0x9d, 0x87, 0xfd, 0x38, 0xdc, 0x6f, 0x36, 0x57, 0x7f, - 0x1e, 0x0d, 0xfe, 0x9b, 0x36, 0xff, 0xb9, 0x6c, 0x7e, 0x1a, 0xa2, 0x55, 0xf8, 0xe7, 0x51, 0x7f, 0x60, 0xbf, 0x06, - 0xff, 0x7d, 0xf1, 0xa7, 0x1c, 0x1e, 0x9a, 0xc4, 0x07, 0x08, 0x1d, 0x4d, 0xf0, 0x1f, 0x92, 0x1c, 0x35, 0x9b, 0x17, - 0x47, 0x13, 0xfc, 0x8b, 0x24, 0x47, 0xf0, 0xf7, 0x5e, 0x91, 0xb7, 0x6c, 0xf2, 0xf4, 0x6e, 0x1e, 0x7e, 0xbe, 0x58, - 0x3d, 0x58, 0xbe, 0xe2, 0x6b, 0x68, 0x77, 0xf0, 0xdf, 0x7f, 0xfe, 0x29, 0x83, 0x1f, 0x2f, 0xc8, 0xd1, 0xb0, 0x81, - 0x42, 0x9d, 0x7c, 0x48, 0xcc, 0x9f, 0xb0, 0x1f, 0x0f, 0xfe, 0xdb, 0x0e, 0x25, 0xf8, 0xf1, 0xcf, 0xcf, 0xe7, 0x17, - 0x64, 0xb8, 0x0a, 0x83, 0xd5, 0x8f, 0x68, 0x85, 0xd0, 0xea, 0x01, 0xfa, 0x8c, 0x83, 0x49, 0x80, 0xf0, 0x4f, 0x92, - 0x1c, 0xfd, 0x78, 0x34, 0xc1, 0xbf, 0x49, 0x72, 0x14, 0x1c, 0x4d, 0xf0, 0x7b, 0x41, 0x8e, 0xfe, 0x3b, 0xec, 0xc7, - 0x46, 0x09, 0xb7, 0xd2, 0xea, 0x8f, 0x15, 0xdc, 0x84, 0xd0, 0x82, 0xd1, 0x95, 0xe2, 0x2a, 0x63, 0xe8, 0xc1, 0x11, - 0xc7, 0x8f, 0x05, 0x00, 0x2b, 0x54, 0xa0, 0xa4, 0xd1, 0x97, 0xb0, 0xcb, 0x1b, 0x58, 0x78, 0xc0, 0xa0, 0x07, 0x31, - 0xc7, 0x46, 0x4f, 0x20, 0x63, 0x65, 0x6e, 0x6f, 0x25, 0x5c, 0xdf, 0xe2, 0x2b, 0xf2, 0x58, 0x84, 0x6d, 0x84, 0x39, - 0x85, 0x1f, 0x1d, 0x84, 0x3f, 0x28, 0x7b, 0xe1, 0x09, 0xdb, 0xdc, 0x60, 0x58, 0x2e, 0x0c, 0x3f, 0x13, 0x20, 0xfc, - 0x72, 0x47, 0xa6, 0x9a, 0x82, 0xfa, 0x01, 0xe1, 0x4f, 0xb5, 0xeb, 0x51, 0x7c, 0xa5, 0x48, 0x89, 0x1c, 0xef, 0x0a, - 0xc6, 0x3e, 0xd0, 0xec, 0x0b, 0x2b, 0xc2, 0xa7, 0x0a, 0xb7, 0x3b, 0x8f, 0xb0, 0x56, 0x55, 0xef, 0xb7, 0x51, 0xaf, - 0xbc, 0xdd, 0x7a, 0x2e, 0xcc, 0x7d, 0x02, 0x9c, 0xc2, 0x75, 0x7d, 0x0d, 0xac, 0xfd, 0x3e, 0xdf, 0x52, 0x6a, 0x15, - 0xf4, 0x36, 0x40, 0xf5, 0xab, 0x54, 0x9e, 0x7f, 0xa5, 0x19, 0x4f, 0xf7, 0x14, 0x9b, 0xcd, 0x33, 0xaa, 0xd8, 0x9e, - 0x9d, 0xf3, 0x1e, 0x85, 0x86, 0x82, 0x92, 0xa7, 0xf8, 0x5b, 0x56, 0x9b, 0xf6, 0x6f, 0x27, 0xe7, 0xc1, 0xde, 0x09, - 0xe1, 0x3e, 0xcb, 0xf2, 0x25, 0x92, 0x96, 0xd7, 0x65, 0x9b, 0x37, 0x82, 0xcd, 0x36, 0x28, 0xcb, 0x86, 0xfa, 0xfc, - 0xce, 0x31, 0xdc, 0x6f, 0x12, 0xd2, 0xe9, 0x07, 0xe7, 0xf2, 0xeb, 0xe4, 0x22, 0x80, 0x9b, 0x9c, 0x82, 0x48, 0xa6, - 0x95, 0x47, 0x50, 0x82, 0x92, 0x56, 0x8f, 0x9e, 0xb3, 0x1e, 0x6d, 0x34, 0x1c, 0x9b, 0x9d, 0x10, 0x3e, 0xa0, 0xa6, - 0x7e, 0x86, 0xa7, 0x38, 0x25, 0xcd, 0x36, 0x5e, 0x90, 0x96, 0xae, 0xd2, 0x5b, 0x9c, 0x27, 0xb6, 0x9f, 0x83, 0x83, - 0xb0, 0x88, 0x32, 0x2a, 0xd5, 0x0b, 0xd0, 0x08, 0x90, 0x05, 0x9e, 0x92, 0x22, 0x62, 0x77, 0x2c, 0x09, 0x13, 0x84, - 0xa7, 0x96, 0x06, 0xa1, 0x1e, 0x5a, 0x10, 0xaf, 0x18, 0xc8, 0x19, 0x44, 0xb2, 0xfe, 0x74, 0xd0, 0x1e, 0x12, 0x42, - 0x82, 0xfd, 0x66, 0x33, 0xe8, 0x17, 0xe4, 0x0f, 0x19, 0x43, 0x8a, 0xc7, 0x4e, 0x93, 0x5f, 0x20, 0xa9, 0xe3, 0x25, - 0x85, 0xef, 0x45, 0xa4, 0x98, 0x54, 0x21, 0x24, 0x83, 0x92, 0x20, 0x77, 0x18, 0x1e, 0x9c, 0x1f, 0x05, 0x0d, 0x48, - 0xd5, 0x28, 0x8a, 0x70, 0x41, 0xee, 0x15, 0x8a, 0xa7, 0x83, 0xe3, 0xa1, 0x7f, 0x46, 0x98, 0x54, 0xe8, 0xff, 0x5e, - 0xf5, 0xa7, 0x83, 0x96, 0xee, 0xff, 0x22, 0xe8, 0x87, 0x05, 0xc9, 0xf7, 0xed, 0x3d, 0x4f, 0x2c, 0x99, 0x9e, 0x2f, - 0x8a, 0xed, 0x00, 0x6d, 0xdf, 0x29, 0x69, 0x76, 0xe2, 0x30, 0xf5, 0x67, 0xd2, 0x84, 0x0e, 0x2d, 0x28, 0x70, 0x46, - 0xa0, 0x3c, 0x2e, 0x08, 0x74, 0x5a, 0x55, 0xbb, 0x57, 0xb1, 0x4d, 0xf8, 0x31, 0xf8, 0xb1, 0xff, 0x9b, 0x8c, 0x7f, - 0x92, 0x66, 0x04, 0xbf, 0xc9, 0xd5, 0x0a, 0xfe, 0xfe, 0x24, 0xfb, 0x30, 0x2c, 0x9d, 0xf6, 0x87, 0x4d, 0xfb, 0x05, - 0xd2, 0x24, 0x8b, 0xf5, 0x80, 0x71, 0x5e, 0xf2, 0x63, 0x66, 0x71, 0xc6, 0xc4, 0xcc, 0xe0, 0xe0, 0x80, 0x0f, 0x68, - 0xa3, 0x3d, 0x84, 0x1b, 0x81, 0x42, 0xc9, 0x0f, 0x5c, 0x4d, 0xc3, 0xe0, 0xe8, 0x22, 0x40, 0xfd, 0x60, 0x0f, 0x56, - 0xb9, 0x27, 0x1a, 0xc4, 0xc2, 0x3a, 0x69, 0x28, 0x1a, 0xa7, 0x17, 0xa4, 0xd5, 0x0f, 0xa5, 0x21, 0xf2, 0x19, 0xc2, - 0x89, 0xa5, 0xa9, 0x2d, 0x9c, 0xa2, 0x06, 0x97, 0x0d, 0xf7, 0x9d, 0xa2, 0xc6, 0x54, 0x35, 0xc6, 0x28, 0x4e, 0xe0, - 0x6f, 0x98, 0x12, 0x42, 0x9a, 0x9d, 0xb2, 0xa2, 0x3b, 0x2c, 0x29, 0x8a, 0xc7, 0x4e, 0x3d, 0x3a, 0xd0, 0x9b, 0x43, - 0x34, 0x42, 0x3e, 0x60, 0xc3, 0xd5, 0x2a, 0x38, 0xef, 0x5f, 0x04, 0xa8, 0x11, 0x3a, 0xb4, 0x3b, 0x72, 0x78, 0x87, - 0x10, 0x96, 0xc3, 0xb5, 0xbd, 0x81, 0xba, 0x65, 0xb5, 0xdb, 0xa6, 0x65, 0xb5, 0xff, 0x3d, 0xb2, 0xc0, 0xd6, 0xa5, - 0xdc, 0x63, 0xf8, 0xdb, 0x39, 0x4c, 0xd5, 0xe1, 0xb6, 0x20, 0x2d, 0x5c, 0x10, 0xa7, 0xee, 0xa6, 0x44, 0x55, 0xf8, - 0x9f, 0x90, 0xaa, 0x38, 0x1e, 0x64, 0x78, 0x3a, 0x24, 0x92, 0x6a, 0xf9, 0xa5, 0xe7, 0x94, 0xe9, 0x2c, 0x23, 0xb7, - 0x6c, 0xe3, 0xfe, 0x37, 0x83, 0x3b, 0x99, 0x2b, 0x15, 0x25, 0x8b, 0xa2, 0x60, 0xb9, 0x7a, 0x25, 0x52, 0xcb, 0xd8, - 0xb1, 0x0c, 0x64, 0x2b, 0xb8, 0xd8, 0xc5, 0xc0, 0xd5, 0x75, 0xdc, 0x4e, 0x49, 0xb7, 0xb2, 0x17, 0x24, 0x35, 0x0c, - 0x97, 0xbe, 0xee, 0xed, 0x2d, 0xac, 0x28, 0x1d, 0x22, 0x9c, 0xda, 0x7b, 0xe0, 0x30, 0x8a, 0xa2, 0x45, 0x94, 0x40, - 0x36, 0x74, 0x20, 0xd1, 0x5a, 0xef, 0xab, 0x30, 0x27, 0x57, 0x2a, 0xca, 0xd9, 0x9d, 0xee, 0x36, 0x44, 0xd5, 0x21, - 0xee, 0xf6, 0xdb, 0x39, 0xed, 0x69, 0x02, 0x94, 0x47, 0xb9, 0x48, 0x19, 0x40, 0x08, 0xee, 0xfe, 0x6d, 0xd2, 0x94, - 0x4a, 0xff, 0x66, 0xab, 0x1a, 0xe0, 0xc0, 0x57, 0x79, 0x2f, 0x40, 0x4f, 0xac, 0x65, 0xe8, 0xb2, 0xb0, 0x51, 0x9e, - 0x23, 0xc4, 0xc7, 0xe1, 0x22, 0x82, 0x1b, 0x41, 0x8d, 0x49, 0x5c, 0xa2, 0xd5, 0x6a, 0xe1, 0xe3, 0xd6, 0xb4, 0x52, - 0x4c, 0x8f, 0xc9, 0x74, 0x50, 0x34, 0x1a, 0x5a, 0x79, 0x9d, 0x1a, 0xbc, 0x58, 0x20, 0x3c, 0x2e, 0xf7, 0x9a, 0x2b, - 0x37, 0x27, 0xf5, 0xae, 0xc2, 0x71, 0x5d, 0x09, 0xdc, 0xe0, 0x12, 0x69, 0xfd, 0xa2, 0x82, 0xd6, 0xf1, 0x84, 0x1c, - 0x85, 0x83, 0xa8, 0xff, 0x3f, 0x87, 0xa8, 0x1f, 0x46, 0x87, 0xe8, 0xc8, 0xd0, 0x92, 0x31, 0xea, 0x25, 0xa6, 0x8f, - 0xa5, 0xbe, 0xfd, 0x6c, 0x63, 0xad, 0x80, 0x8c, 0x05, 0xce, 0xe9, 0x8c, 0xc5, 0x13, 0xd8, 0xf5, 0x0e, 0x79, 0xe6, - 0x18, 0x90, 0x29, 0x9e, 0x58, 0xda, 0x12, 0x05, 0x7d, 0x41, 0xcb, 0xaf, 0x7e, 0xd0, 0xa7, 0xd5, 0xd7, 0xff, 0x0c, - 0xfa, 0x09, 0x8d, 0xaf, 0xf8, 0xda, 0x2a, 0xc9, 0x6b, 0x7d, 0x9c, 0xba, 0x3e, 0xd6, 0x66, 0x71, 0x3c, 0xe0, 0xa5, - 0x28, 0xdf, 0xd2, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0x94, 0x47, 0x8a, 0x4e, 0x00, 0xaa, 0xde, 0x22, 0xe4, - 0xbe, 0x6d, 0x80, 0x37, 0x65, 0xc0, 0x16, 0x87, 0xb4, 0x00, 0xcd, 0xc5, 0x45, 0x0b, 0x2d, 0x6b, 0x85, 0x2d, 0x67, - 0x55, 0xbf, 0x8b, 0x2f, 0x89, 0xf7, 0x18, 0xa8, 0xf2, 0xf9, 0xa2, 0x37, 0x6e, 0x34, 0x50, 0xee, 0xf0, 0x2b, 0x1d, - 0x8c, 0x87, 0xf8, 0x0e, 0x50, 0x08, 0xd7, 0x30, 0x0a, 0xd7, 0xe6, 0xd8, 0xb1, 0x73, 0x6c, 0x34, 0xc4, 0x1a, 0xf5, - 0xbc, 0xca, 0x0b, 0x5b, 0x79, 0xbd, 0x36, 0x90, 0xd9, 0xc4, 0xb8, 0x33, 0xa4, 0x53, 0xc0, 0x10, 0x8c, 0x10, 0xf2, - 0x8f, 0x40, 0x3b, 0x9b, 0x85, 0x46, 0xa1, 0xba, 0xde, 0xbd, 0x40, 0x51, 0xcd, 0xe9, 0x11, 0x02, 0x2c, 0xa0, 0x6a, - 0xa9, 0x46, 0x9e, 0x2a, 0x9c, 0x36, 0xda, 0x1a, 0xdd, 0x9b, 0xed, 0x5e, 0xbd, 0xb1, 0x87, 0x55, 0x63, 0x38, 0x6d, - 0x90, 0x69, 0xb5, 0xc3, 0xd7, 0xa2, 0xd1, 0x58, 0xd7, 0xef, 0x4b, 0xdd, 0x26, 0xae, 0xdd, 0x5f, 0x3c, 0xdd, 0x32, - 0xf1, 0x70, 0xa7, 0x6f, 0x75, 0xde, 0xca, 0x88, 0xe7, 0x39, 0x2b, 0xe0, 0x84, 0x25, 0x0a, 0xcb, 0xf5, 0xba, 0x3c, - 0xf5, 0x7f, 0x57, 0xc6, 0x66, 0x8c, 0x70, 0xa0, 0x43, 0x5a, 0x6a, 0xc3, 0x02, 0x17, 0x98, 0x6a, 0x2a, 0x42, 0x08, - 0xf9, 0xa0, 0x9c, 0x79, 0x8c, 0xd2, 0x24, 0x29, 0x21, 0xde, 0xd9, 0x1d, 0xe6, 0x84, 0x45, 0x37, 0x0f, 0xae, 0xc4, - 0x77, 0x45, 0xba, 0x81, 0x1c, 0xc6, 0xba, 0x58, 0x66, 0x09, 0x59, 0x46, 0xbe, 0x82, 0x9c, 0x53, 0x5e, 0xb0, 0x44, - 0x9a, 0x20, 0x3e, 0xe1, 0x05, 0xd3, 0x8c, 0xfb, 0x03, 0x27, 0x37, 0x26, 0x75, 0x4e, 0x33, 0xf1, 0xb5, 0x3f, 0x00, - 0xcd, 0x0c, 0x94, 0x43, 0x82, 0x6c, 0x15, 0xbb, 0x79, 0x70, 0xf9, 0x7a, 0x97, 0x0c, 0xbd, 0x5a, 0x59, 0xe9, 0x39, - 0x01, 0xd6, 0x07, 0x67, 0xd5, 0x50, 0x13, 0xfb, 0x23, 0x0e, 0x13, 0xcd, 0x44, 0x65, 0x21, 0x07, 0x64, 0xba, 0x79, - 0x70, 0xf9, 0x2e, 0xe4, 0x5a, 0x37, 0x85, 0xb0, 0x3f, 0xef, 0xb0, 0x20, 0x21, 0x25, 0x0c, 0x99, 0xc9, 0x97, 0x74, - 0xac, 0xf0, 0x4e, 0xf7, 0x98, 0xea, 0x4c, 0x10, 0x3b, 0x06, 0x72, 0x48, 0x12, 0x0b, 0x02, 0x92, 0x20, 0x9c, 0xd4, - 0xe4, 0x3a, 0xa2, 0xd7, 0x40, 0x77, 0x76, 0x0d, 0x8b, 0x11, 0x19, 0xf6, 0x10, 0xe1, 0x44, 0x77, 0xab, 0xd6, 0xe6, - 0x38, 0xc9, 0xe9, 0xa6, 0xa1, 0x5b, 0x25, 0xcf, 0xbe, 0x07, 0xc1, 0xcb, 0x7d, 0xbc, 0xb2, 0x6d, 0x97, 0x09, 0x4f, - 0x9c, 0x45, 0xda, 0xcd, 0x83, 0xcb, 0x5f, 0xad, 0x51, 0xda, 0x9c, 0x3a, 0xf2, 0xbf, 0x25, 0xa3, 0x5e, 0xfe, 0x1a, - 0x55, 0xb9, 0xba, 0xf0, 0xcd, 0x83, 0xcb, 0xdf, 0x77, 0x15, 0x83, 0xf4, 0xf5, 0xa2, 0x52, 0x12, 0xe8, 0xf1, 0x2d, - 0x59, 0x16, 0x2f, 0xed, 0x59, 0x11, 0xcb, 0x35, 0xd6, 0x27, 0x54, 0x9c, 0xaf, 0x4b, 0xdd, 0xca, 0x13, 0x2c, 0x88, - 0xbe, 0x4a, 0xaa, 0x2f, 0x9b, 0x45, 0x63, 0x2e, 0xf2, 0xeb, 0x44, 0xcc, 0xd9, 0x37, 0xee, 0x97, 0x9e, 0x2a, 0x14, - 0xf1, 0x19, 0x18, 0xe2, 0xe8, 0xb1, 0x4b, 0xbc, 0xdf, 0x42, 0xbd, 0x8d, 0xf3, 0x4c, 0x68, 0x44, 0x2d, 0xea, 0x87, - 0x0d, 0xa6, 0xa4, 0x85, 0x13, 0xd2, 0xc2, 0x19, 0xc9, 0x07, 0x2d, 0x73, 0x62, 0xf4, 0xb2, 0xb2, 0x69, 0x73, 0xee, - 0xc0, 0x76, 0xcf, 0xcc, 0xbe, 0x35, 0x87, 0xf2, 0xb4, 0x97, 0x69, 0xfd, 0xa5, 0x3e, 0xe8, 0xa7, 0x1a, 0x35, 0x9e, - 0xb0, 0xb0, 0xc0, 0x85, 0x6e, 0xf9, 0x9a, 0x8f, 0x32, 0xb0, 0x53, 0x81, 0x99, 0x61, 0x85, 0xe2, 0xb2, 0x6c, 0xdb, - 0x96, 0xcd, 0x22, 0xbd, 0x56, 0x05, 0xce, 0x22, 0x20, 0xe5, 0x38, 0xb3, 0x76, 0x3d, 0x72, 0xbb, 0xca, 0xe9, 0xc1, - 0x41, 0x68, 0x2b, 0xd1, 0xb0, 0x70, 0xf9, 0xd5, 0x0d, 0xe0, 0x7b, 0x43, 0x35, 0xa6, 0x48, 0x4f, 0xa0, 0xd1, 0x48, - 0x86, 0x6b, 0xba, 0x4f, 0x48, 0x98, 0xd5, 0xa1, 0xe8, 0x46, 0xaf, 0x99, 0xc1, 0x0d, 0x00, 0x34, 0x1a, 0xe5, 0x75, - 0xef, 0x06, 0xc4, 0x9e, 0x2a, 0x2c, 0xd6, 0x5f, 0xc3, 0xd2, 0x9a, 0xa8, 0xb5, 0x65, 0x87, 0xe5, 0x46, 0x81, 0xa4, - 0x8f, 0xbb, 0xd2, 0xcd, 0xc7, 0xdb, 0x1a, 0xba, 0xdc, 0x0b, 0x6b, 0x03, 0x81, 0xb5, 0xd5, 0x96, 0x2d, 0xe4, 0x48, - 0x5b, 0x07, 0xc5, 0xae, 0x10, 0x5c, 0x70, 0x41, 0xa1, 0xc6, 0xda, 0x62, 0xf9, 0x13, 0xb6, 0x6d, 0xce, 0x89, 0x73, - 0x64, 0xb5, 0x65, 0x7a, 0x18, 0x1a, 0x60, 0x9d, 0x12, 0x30, 0xcf, 0xc9, 0xcb, 0x6f, 0xa3, 0xfe, 0xa5, 0x87, 0xfa, - 0x8f, 0x09, 0xf3, 0xb6, 0x81, 0x59, 0x82, 0x48, 0x58, 0x05, 0x45, 0xee, 0xb2, 0xae, 0xe6, 0x04, 0xb4, 0x71, 0x75, - 0xa8, 0xe6, 0xfe, 0x15, 0xe5, 0x37, 0x28, 0x8b, 0xbf, 0x53, 0xb4, 0x3e, 0x13, 0xbb, 0xfb, 0xe4, 0xb0, 0xba, 0xa0, - 0x83, 0xae, 0x77, 0x29, 0x07, 0x7d, 0x52, 0x78, 0xf9, 0xfb, 0xf7, 0xef, 0x56, 0xaf, 0xe6, 0xdb, 0x3b, 0xd8, 0x33, - 0x2b, 0x85, 0x59, 0x7b, 0x1b, 0xb8, 0x6e, 0x64, 0x0a, 0xfd, 0x97, 0x77, 0xe2, 0x75, 0x2a, 0xb4, 0xb1, 0x19, 0xdd, - 0x71, 0x08, 0xa3, 0x6d, 0xb7, 0x75, 0x09, 0xe6, 0x35, 0x0b, 0x74, 0xc9, 0x18, 0xb7, 0xd2, 0xe2, 0x1b, 0x64, 0xe4, - 0x52, 0x17, 0x60, 0x79, 0xba, 0x3b, 0xfb, 0xf1, 0xda, 0xe2, 0x89, 0x19, 0x1a, 0x5a, 0x6a, 0x42, 0x68, 0xf0, 0x1e, - 0x30, 0xc7, 0x1c, 0x11, 0x00, 0xa2, 0x97, 0x1a, 0x52, 0x15, 0xc8, 0x82, 0xa0, 0x52, 0xe4, 0x3f, 0xdf, 0x27, 0xe4, - 0x65, 0xa5, 0xc8, 0x7c, 0x5b, 0x19, 0x73, 0x01, 0x62, 0xa0, 0x18, 0x2e, 0x12, 0xca, 0x04, 0x73, 0x19, 0xfa, 0x41, - 0xb9, 0xf2, 0x5a, 0xda, 0x8c, 0x2a, 0x6e, 0xdc, 0xbb, 0x29, 0xd5, 0x2a, 0x3e, 0x93, 0xef, 0x20, 0xb1, 0x91, 0xfb, - 0x00, 0x72, 0x19, 0xd5, 0x83, 0x84, 0xef, 0x77, 0xba, 0xb4, 0x6b, 0x77, 0xfd, 0x65, 0xd3, 0x22, 0x66, 0x63, 0x5d, - 0x22, 0x9e, 0x4b, 0x56, 0xa8, 0xc7, 0x6c, 0x2c, 0x0a, 0xb8, 0xff, 0x28, 0xc1, 0x82, 0xd6, 0x0f, 0x3c, 0x1d, 0xa0, - 0x9e, 0xa0, 0x77, 0xe9, 0xb0, 0x31, 0x43, 0xfd, 0xeb, 0x8b, 0xbe, 0x03, 0xbf, 0xd9, 0xac, 0xf5, 0xf2, 0xe0, 0xe0, - 0x2b, 0xab, 0x00, 0x65, 0x87, 0xa9, 0x87, 0xe1, 0x11, 0x2f, 0xc3, 0xe5, 0xd8, 0x9b, 0xe1, 0x07, 0x61, 0xa5, 0x32, - 0x70, 0x84, 0xc3, 0x27, 0x42, 0xcf, 0x89, 0x5a, 0x4f, 0x36, 0xe9, 0xbd, 0xd5, 0x66, 0x48, 0x5f, 0xac, 0x01, 0x72, - 0x0f, 0x72, 0xb9, 0x51, 0x32, 0xe5, 0x95, 0xad, 0x6d, 0x39, 0x88, 0x2b, 0x00, 0x57, 0x98, 0x83, 0x90, 0xe2, 0xa1, - 0x61, 0xbe, 0x53, 0x68, 0x79, 0x2e, 0x80, 0xfd, 0xc7, 0x79, 0x04, 0x22, 0x2d, 0xaa, 0x6d, 0x5c, 0x84, 0x70, 0xae, - 0x25, 0x1e, 0xcf, 0x38, 0xe1, 0xf2, 0xf9, 0x2e, 0x0d, 0xb5, 0x43, 0x6d, 0xa6, 0xcf, 0x20, 0x28, 0x21, 0x50, 0x59, - 0x21, 0xfa, 0x1a, 0x4a, 0xcb, 0xcd, 0x95, 0xf7, 0x70, 0xec, 0x76, 0x2f, 0xa7, 0xa1, 0xb9, 0xdb, 0x82, 0xe3, 0xa3, - 0x88, 0x16, 0x61, 0xad, 0xeb, 0x5e, 0xa1, 0xab, 0x61, 0x0b, 0x3a, 0xea, 0xc3, 0xa9, 0xd0, 0xf7, 0x84, 0x57, 0x15, - 0x49, 0xfd, 0x64, 0x2d, 0xa0, 0x1c, 0x31, 0xac, 0x4c, 0x53, 0xbc, 0xf9, 0x7f, 0xb2, 0xe6, 0x6b, 0xe5, 0x31, 0xc1, - 0xf4, 0x30, 0x6e, 0xcd, 0x2a, 0xb0, 0x35, 0xe0, 0xd8, 0xf2, 0x2f, 0xe1, 0x2d, 0xaa, 0x53, 0x8a, 0xeb, 0x4e, 0x3d, - 0x26, 0xe0, 0x2d, 0x58, 0xcf, 0x6c, 0x6e, 0xfd, 0xe7, 0xfa, 0x60, 0x94, 0x38, 0xaf, 0x11, 0x78, 0xa1, 0x09, 0x3c, - 0x02, 0xc6, 0xcd, 0x99, 0x96, 0xf7, 0xad, 0x11, 0x8d, 0x74, 0x27, 0x9e, 0xc5, 0x33, 0xc3, 0x72, 0x6f, 0x7d, 0x6c, - 0xac, 0x48, 0x2c, 0x09, 0xd8, 0x16, 0x61, 0x4b, 0xe4, 0x05, 0xc2, 0x79, 0xa3, 0xd1, 0xcb, 0xcf, 0x59, 0xa5, 0x55, - 0xa9, 0x86, 0x29, 0xe1, 0x96, 0x18, 0xf0, 0xbe, 0x76, 0xa2, 0xe6, 0x08, 0x97, 0x66, 0xee, 0x39, 0xa8, 0xef, 0x2f, - 0xdf, 0x86, 0x3e, 0x7d, 0xf3, 0xcb, 0x96, 0x17, 0xb1, 0x30, 0xa5, 0xb0, 0xba, 0xc3, 0x79, 0xf3, 0x7d, 0xb3, 0x11, - 0x18, 0xf7, 0x7e, 0x1b, 0x83, 0x8d, 0x1b, 0xea, 0x29, 0x43, 0x1a, 0xca, 0x4d, 0xd8, 0x43, 0x95, 0xbd, 0xa3, 0xdf, - 0x59, 0x4f, 0x55, 0xd2, 0xae, 0x22, 0xf9, 0x7a, 0x2d, 0x59, 0x65, 0x34, 0xb0, 0x61, 0xd8, 0xa9, 0x8f, 0x99, 0x6d, - 0x05, 0xfe, 0xd5, 0x9c, 0x28, 0xec, 0x21, 0xeb, 0x9b, 0x6f, 0x5d, 0xa7, 0x54, 0xc3, 0x84, 0xed, 0x6d, 0xcf, 0xc7, - 0x2b, 0xbe, 0xeb, 0x7c, 0xc4, 0xc2, 0x6e, 0x7d, 0x7d, 0x36, 0xb6, 0xff, 0x8d, 0xb3, 0xd1, 0xaa, 0xed, 0xdd, 0xf1, - 0x08, 0xdc, 0x49, 0xed, 0x78, 0xcc, 0xeb, 0xc7, 0xa3, 0xc0, 0xee, 0xf4, 0xbe, 0xe8, 0xac, 0x56, 0x72, 0xd0, 0x02, - 0xb5, 0x53, 0x10, 0xc0, 0xcf, 0xb6, 0xf9, 0xe9, 0x91, 0x64, 0xa3, 0x43, 0x0e, 0xcb, 0xf3, 0xbe, 0x8d, 0x22, 0x30, - 0xa0, 0x0e, 0xb5, 0xad, 0x97, 0x46, 0x6c, 0x8b, 0x43, 0x16, 0xcb, 0x89, 0x2c, 0xaf, 0xae, 0x60, 0xc4, 0xfa, 0xd8, - 0xb0, 0x02, 0x66, 0xb8, 0xd3, 0xaa, 0xd0, 0x89, 0x9f, 0xff, 0x9a, 0x39, 0xad, 0x1d, 0x31, 0x86, 0x93, 0xa8, 0x59, - 0x31, 0xd8, 0x11, 0x58, 0x86, 0x71, 0x5f, 0x4b, 0xa8, 0xd5, 0xa9, 0x8e, 0x6a, 0x47, 0x12, 0x6e, 0x81, 0xda, 0x6d, - 0x5f, 0x9f, 0x4b, 0xab, 0xd5, 0xce, 0x83, 0x05, 0x17, 0x1e, 0x6e, 0x3f, 0x27, 0xaa, 0x46, 0x52, 0x28, 0xb1, 0x12, - 0x14, 0xce, 0x34, 0xaa, 0x2a, 0x22, 0x06, 0xad, 0x21, 0xf0, 0xa4, 0xbd, 0xe4, 0x5c, 0x54, 0x42, 0x72, 0xd2, 0x68, - 0xa0, 0xac, 0xec, 0x98, 0x0e, 0x64, 0x23, 0x19, 0x62, 0x86, 0x13, 0x23, 0xb0, 0xc0, 0xe9, 0x15, 0x66, 0x55, 0xd7, - 0x83, 0x64, 0x88, 0x70, 0xb1, 0x5a, 0x85, 0x66, 0x68, 0x19, 0x5a, 0xad, 0x32, 0x7f, 0x68, 0x3a, 0x1f, 0x2a, 0xbe, - 0xec, 0x2b, 0xf2, 0x52, 0x9f, 0x87, 0x2f, 0x61, 0x90, 0x0d, 0x12, 0x66, 0x56, 0x25, 0x98, 0x81, 0xe6, 0xaa, 0x21, - 0x06, 0x49, 0xa3, 0x3d, 0xf4, 0x68, 0xd8, 0x20, 0x19, 0x92, 0x6c, 0x0d, 0x96, 0xb3, 0xb9, 0x3d, 0x30, 0xff, 0x82, - 0x83, 0xed, 0x2f, 0x7d, 0xce, 0x98, 0x06, 0xfd, 0x35, 0xd9, 0x54, 0x19, 0x94, 0x78, 0x65, 0x17, 0xd7, 0x95, 0xab, - 0x19, 0x58, 0x94, 0x85, 0xb0, 0xbd, 0x66, 0xee, 0x83, 0xf0, 0x5f, 0x62, 0xbb, 0xa0, 0xa5, 0x11, 0xf7, 0x06, 0xe2, - 0x3b, 0xdb, 0xed, 0x28, 0x8a, 0x68, 0x31, 0xd1, 0x57, 0x22, 0x8e, 0x12, 0xeb, 0x3d, 0x70, 0x6c, 0xc7, 0xe9, 0xf5, - 0x3c, 0x28, 0x3b, 0x1b, 0x12, 0x33, 0x7e, 0xc7, 0xec, 0x38, 0xc7, 0x95, 0x82, 0xee, 0xd6, 0x45, 0x98, 0xc1, 0xd0, - 0xff, 0xe5, 0xc1, 0x9c, 0xd8, 0xc1, 0x18, 0x34, 0xd9, 0x80, 0xdb, 0x37, 0xe0, 0x51, 0xd0, 0x0d, 0xb8, 0x7d, 0x1b, - 0xbe, 0x0e, 0x5a, 0xc9, 0x37, 0x07, 0xe8, 0x91, 0x09, 0x33, 0xd2, 0x2a, 0xc1, 0x1b, 0x66, 0x77, 0x93, 0x23, 0x33, - 0x64, 0x15, 0x0e, 0x57, 0x45, 0x42, 0xb9, 0xb1, 0x17, 0x2a, 0x26, 0xd5, 0xe3, 0xfe, 0x65, 0xfc, 0x12, 0xf9, 0x4a, - 0x83, 0xba, 0x71, 0x0c, 0x60, 0x95, 0xd5, 0xd6, 0xbf, 0x3c, 0x38, 0x00, 0xf3, 0x68, 0x60, 0xed, 0xa2, 0x84, 0xce, - 0xd5, 0xa2, 0x00, 0xfe, 0x2a, 0x77, 0xbf, 0x21, 0x19, 0xdc, 0x4e, 0x74, 0x1a, 0xfc, 0x80, 0x84, 0x39, 0x95, 0x92, - 0x7f, 0x35, 0x69, 0xf6, 0x37, 0x2e, 0x88, 0xc3, 0xe8, 0xdc, 0x70, 0x8a, 0x02, 0xf5, 0x84, 0x45, 0xd7, 0x3a, 0xe4, - 0x9e, 0x7e, 0x65, 0xb9, 0x7a, 0xc9, 0xa5, 0x62, 0x39, 0x00, 0xa0, 0x42, 0x3c, 0x98, 0x52, 0x8e, 0x60, 0xeb, 0xd6, - 0x6a, 0xd1, 0x34, 0xfd, 0x6e, 0x15, 0x55, 0x67, 0x8b, 0xa6, 0x34, 0x4f, 0x33, 0xd3, 0x89, 0x6f, 0x33, 0xe9, 0xec, - 0x44, 0xcb, 0x92, 0xbe, 0xc5, 0x4e, 0xc5, 0x7e, 0x68, 0x5a, 0x1f, 0x4a, 0xe2, 0xce, 0x05, 0x77, 0x96, 0x7e, 0x97, - 0x8f, 0x81, 0x2b, 0xf5, 0x6f, 0xac, 0x82, 0x3f, 0x13, 0xac, 0x3c, 0xf2, 0x1a, 0xd5, 0xc7, 0xe9, 0x50, 0x27, 0xdb, - 0x52, 0x2e, 0x94, 0x46, 0x61, 0x1b, 0x27, 0x85, 0xc6, 0x94, 0xd3, 0x6f, 0x4b, 0x5c, 0xbf, 0xba, 0x63, 0xc4, 0x1d, - 0x1d, 0xf2, 0xdf, 0xa5, 0xd2, 0x68, 0x59, 0x22, 0x18, 0x72, 0x3b, 0xf2, 0x67, 0x09, 0x57, 0xb1, 0x19, 0x57, 0xcf, - 0xd5, 0x2c, 0xdb, 0xf0, 0xc4, 0xe9, 0xfd, 0x5c, 0x5e, 0x23, 0xff, 0x2c, 0xc3, 0x5b, 0x86, 0x9f, 0x30, 0xb8, 0x37, - 0x7e, 0xc6, 0xbd, 0x2a, 0xdb, 0xf7, 0xc5, 0xcf, 0xbc, 0xfb, 0xe2, 0x67, 0x3c, 0xde, 0x2e, 0xea, 0xdd, 0x13, 0x77, - 0xa2, 0xb3, 0xa8, 0x15, 0x38, 0x3e, 0x6a, 0x4a, 0x2b, 0xff, 0x4a, 0xb3, 0x35, 0x70, 0x65, 0x13, 0x07, 0xc6, 0x79, - 0x75, 0x11, 0x8a, 0x59, 0x73, 0x46, 0xc3, 0xe1, 0x7f, 0x6b, 0x9d, 0xec, 0xc9, 0x23, 0x8c, 0x14, 0xf2, 0x86, 0x16, - 0xea, 0x01, 0x6c, 0xb8, 0x62, 0xcb, 0x07, 0x90, 0x12, 0x50, 0xb6, 0xfd, 0x7b, 0x5d, 0x54, 0x8e, 0x07, 0xfd, 0xdc, - 0x38, 0x1f, 0xf9, 0xed, 0x93, 0xa2, 0xe4, 0xea, 0xea, 0x42, 0xc8, 0x9d, 0xd6, 0x12, 0x20, 0x4c, 0x9d, 0x6b, 0x1e, - 0xb3, 0x34, 0x99, 0xc5, 0xcb, 0x75, 0xa9, 0x3a, 0x28, 0x0c, 0x57, 0xc7, 0x11, 0x2e, 0xd6, 0xfa, 0x06, 0xfd, 0x1f, - 0x8e, 0xff, 0xe2, 0x96, 0x46, 0x7e, 0x2a, 0x29, 0xd0, 0xe3, 0xdd, 0xbe, 0x36, 0x3b, 0x48, 0xa4, 0x99, 0x43, 0x69, - 0x29, 0x00, 0x58, 0xad, 0xf1, 0x75, 0xed, 0x70, 0xea, 0x89, 0xb0, 0xb3, 0xf9, 0xa6, 0x21, 0x2c, 0x66, 0xa5, 0x05, - 0x8f, 0xee, 0x66, 0x87, 0xe5, 0xa8, 0x93, 0xc5, 0x55, 0xb9, 0xc7, 0x6a, 0xfd, 0xa2, 0x6f, 0x80, 0xb2, 0x32, 0x44, - 0x5b, 0xad, 0xc2, 0x3a, 0xbc, 0x89, 0xf4, 0xae, 0x41, 0x10, 0x96, 0x9e, 0x01, 0x47, 0x8d, 0xf1, 0x36, 0x75, 0x42, - 0xb4, 0x69, 0xbf, 0xe4, 0x58, 0xf7, 0xda, 0x38, 0x7c, 0x45, 0x83, 0xa9, 0xee, 0x6b, 0x1e, 0xb0, 0x99, 0x5d, 0xd9, - 0x91, 0x07, 0xa1, 0x29, 0x75, 0xc6, 0xb9, 0x95, 0x15, 0xed, 0x0e, 0xf8, 0xa2, 0xef, 0x98, 0xe7, 0x5a, 0xd0, 0x6d, - 0xe7, 0x7b, 0xb6, 0x4d, 0x4f, 0xc4, 0xb7, 0x6c, 0x9b, 0x6a, 0x9c, 0xf0, 0x7e, 0x0b, 0x7d, 0xdf, 0x10, 0xd6, 0xf4, - 0xb5, 0xbb, 0xc8, 0xff, 0x42, 0x77, 0x6d, 0x40, 0x4f, 0x03, 0x66, 0x47, 0x63, 0x3e, 0xa8, 0xf5, 0xfa, 0x53, 0xe9, - 0xbf, 0xa0, 0x6d, 0x85, 0x3e, 0x99, 0x5d, 0x60, 0xc5, 0x4a, 0xed, 0x10, 0x1c, 0xfe, 0xc3, 0xc9, 0x24, 0x13, 0x23, - 0x9a, 0xbd, 0x83, 0x1e, 0xab, 0xdc, 0xe7, 0xf7, 0x69, 0x41, 0x15, 0xb3, 0xb4, 0xa6, 0x1a, 0xc5, 0x3f, 0xdc, 0x1b, - 0xc6, 0x3f, 0xdc, 0x50, 0xee, 0xaa, 0x05, 0xbc, 0x7c, 0x59, 0x36, 0x11, 0x7f, 0x5a, 0x97, 0xfe, 0x56, 0xf9, 0xee, - 0x5e, 0x36, 0x49, 0x9a, 0xca, 0xcb, 0xd9, 0xe6, 0xe1, 0x66, 0x53, 0x61, 0xf8, 0xd7, 0x37, 0x06, 0xbb, 0x4d, 0xe6, - 0xfe, 0xf2, 0xc8, 0xdc, 0x5f, 0x3c, 0xfe, 0x6e, 0x2d, 0x8f, 0xe2, 0x1d, 0x47, 0xc7, 0xda, 0x32, 0xc6, 0x8c, 0xfa, - 0xad, 0x02, 0x83, 0x06, 0x45, 0x2e, 0x3c, 0x6f, 0x87, 0xea, 0xf4, 0x72, 0xf6, 0x47, 0x61, 0xb2, 0x90, 0x4a, 0xcc, - 0x6c, 0xa3, 0xd2, 0xfa, 0x38, 0xe9, 0x4c, 0x50, 0x60, 0xeb, 0x3b, 0xfc, 0xb8, 0xee, 0x46, 0xb6, 0xfc, 0xc2, 0xf3, - 0x34, 0xce, 0xb1, 0x3d, 0x5b, 0x64, 0x2c, 0xd6, 0xc4, 0x99, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0xcf, 0xb9, 0x9c, 0xb2, - 0x22, 0x2c, 0xd0, 0xf2, 0x5b, 0x9d, 0x15, 0x70, 0x9b, 0x63, 0x3a, 0xc3, 0x69, 0x69, 0x39, 0xa0, 0x22, 0x68, 0x0d, - 0x74, 0x46, 0x33, 0xa6, 0xa6, 0x22, 0x05, 0xc3, 0x97, 0x28, 0x2d, 0xdd, 0xa9, 0x0e, 0x0e, 0xf6, 0xc3, 0x40, 0xeb, - 0x2f, 0xc0, 0x07, 0xdd, 0xcf, 0x41, 0xfd, 0x25, 0x38, 0x06, 0x55, 0x5d, 0x33, 0xb4, 0x64, 0x9b, 0x3e, 0x34, 0x2a, - 0xfa, 0xc2, 0xee, 0x31, 0x47, 0xeb, 0x75, 0x6c, 0x46, 0x1d, 0x8c, 0x39, 0xcb, 0xd2, 0x00, 0x7f, 0x61, 0xf7, 0x71, - 0xe9, 0xb6, 0xae, 0xbd, 0xac, 0xf5, 0x22, 0x06, 0xe2, 0x36, 0x0f, 0x70, 0xd5, 0x49, 0xbc, 0x5c, 0x63, 0x51, 0xf0, - 0x09, 0xe0, 0xe8, 0x2f, 0xec, 0x3e, 0xb6, 0xed, 0x79, 0xae, 0x82, 0x68, 0xe9, 0x40, 0x1f, 0x79, 0xc9, 0xfe, 0x32, - 0x58, 0x81, 0x63, 0xa0, 0xeb, 0x0e, 0x49, 0xad, 0x5c, 0x25, 0x42, 0x22, 0xb4, 0xfe, 0x77, 0xa7, 0x82, 0x17, 0xfe, - 0x39, 0xa7, 0x6a, 0x16, 0xb7, 0x1b, 0x95, 0x18, 0x54, 0xa8, 0x2c, 0x48, 0x3e, 0x86, 0xdc, 0xed, 0x3e, 0xeb, 0xfd, - 0xe0, 0xe9, 0xcc, 0x16, 0xd4, 0x36, 0x1a, 0xa7, 0xfa, 0x17, 0xaa, 0xee, 0xa0, 0x66, 0xaa, 0xaa, 0xb8, 0xf7, 0x31, - 0x04, 0xc0, 0x83, 0xb5, 0x0c, 0xd5, 0x0e, 0xa1, 0x6b, 0x67, 0xa6, 0x3a, 0xa6, 0x24, 0x5c, 0xba, 0x39, 0xc4, 0xdc, - 0x07, 0xa3, 0x5a, 0x03, 0x1a, 0x5a, 0x04, 0x33, 0x96, 0x87, 0x7c, 0x1c, 0xca, 0xad, 0x33, 0x54, 0xe8, 0x33, 0x34, - 0xf2, 0x40, 0xfe, 0x8d, 0x33, 0x93, 0x69, 0x68, 0x68, 0xde, 0x52, 0x1f, 0x80, 0x76, 0x75, 0x2d, 0x0e, 0xf9, 0x2b, - 0x5a, 0x3a, 0xef, 0x99, 0x45, 0x17, 0xb5, 0x61, 0x85, 0xba, 0x1d, 0xb4, 0x8e, 0x61, 0x4a, 0xcc, 0x14, 0x58, 0x3b, - 0xbd, 0x0f, 0x77, 0x76, 0xb5, 0x61, 0x11, 0xb9, 0x69, 0x11, 0x07, 0x93, 0x90, 0xa2, 0x25, 0x0f, 0x29, 0x16, 0x60, - 0x07, 0x59, 0xac, 0xcb, 0xf1, 0x33, 0x7f, 0x39, 0x6a, 0x56, 0xd2, 0xbb, 0x1d, 0x0c, 0x81, 0xcb, 0x57, 0x60, 0x1b, - 0x8a, 0xb9, 0x23, 0x2c, 0x3c, 0xd4, 0x9e, 0x7e, 0xde, 0xba, 0xcd, 0xcd, 0x82, 0xb8, 0x15, 0x18, 0xd3, 0x70, 0xe9, - 0xcd, 0xc2, 0x77, 0x2a, 0xb7, 0x0e, 0x87, 0xf6, 0x9a, 0xb0, 0x32, 0x5e, 0x0d, 0x73, 0xb2, 0x71, 0xf4, 0x7c, 0xdf, - 0xc6, 0xf3, 0xef, 0x05, 0x2b, 0xee, 0xaf, 0x19, 0xd8, 0x58, 0x0b, 0x70, 0x37, 0xae, 0x96, 0xa1, 0x32, 0x90, 0xef, - 0x0b, 0xcd, 0xba, 0xac, 0xf1, 0x77, 0xa3, 0x62, 0xac, 0xf5, 0x3d, 0xa5, 0xa7, 0xad, 0x31, 0xdb, 0x85, 0x7d, 0xd3, - 0x75, 0x93, 0xf5, 0xb4, 0x22, 0xae, 0x82, 0xb4, 0xbd, 0x5b, 0xc0, 0x85, 0xef, 0x0f, 0x3b, 0xc8, 0x87, 0x9b, 0xaa, - 0x1b, 0x48, 0x82, 0x6b, 0x3f, 0xf1, 0xed, 0xa9, 0xee, 0xb2, 0xd6, 0xfd, 0xf6, 0x54, 0x6b, 0x97, 0x85, 0xda, 0x90, - 0x08, 0xdb, 0x7e, 0x4a, 0xff, 0x69, 0xb9, 0x5e, 0xa3, 0x35, 0x0c, 0xef, 0x3d, 0xef, 0x85, 0xe1, 0x7b, 0x67, 0xa1, - 0x18, 0xc1, 0x45, 0xee, 0x75, 0x26, 0x1c, 0x21, 0xaf, 0x46, 0xf0, 0x9e, 0x6f, 0x0d, 0xe1, 0x3d, 0xf7, 0x9c, 0x5e, - 0x41, 0x6a, 0x9a, 0xe4, 0x2c, 0x75, 0xf4, 0x13, 0x19, 0x24, 0xd4, 0x7c, 0xdc, 0x6b, 0x4e, 0xb8, 0xfa, 0x1c, 0x03, - 0xff, 0x85, 0x47, 0x0b, 0xa5, 0x44, 0x8e, 0x79, 0x3e, 0x5f, 0x28, 0x2c, 0xf5, 0xe8, 0x97, 0x63, 0x91, 0xab, 0xe6, - 0x98, 0xce, 0x78, 0x76, 0x1f, 0x2f, 0x78, 0x73, 0x26, 0x72, 0x21, 0xe7, 0x34, 0x61, 0x58, 0xde, 0x4b, 0xc5, 0x66, - 0xcd, 0x05, 0xc7, 0xcf, 0x59, 0xf6, 0x95, 0x29, 0x9e, 0x50, 0xfc, 0x56, 0x8c, 0x84, 0x12, 0xf8, 0xf5, 0xdd, 0xfd, - 0x84, 0xe5, 0xf8, 0xf7, 0xd1, 0x22, 0x57, 0x0b, 0x2c, 0x69, 0x2e, 0x9b, 0x92, 0x15, 0x7c, 0xdc, 0x6b, 0x36, 0xe7, - 0x05, 0x9f, 0xd1, 0xe2, 0xbe, 0x99, 0x88, 0x4c, 0x14, 0xf1, 0x7f, 0xb5, 0x8e, 0xe9, 0xa3, 0xf1, 0x49, 0x4f, 0x15, - 0x34, 0x97, 0x1c, 0x16, 0x26, 0xa6, 0x59, 0xb6, 0x77, 0xdc, 0x6d, 0xcd, 0xe4, 0xbe, 0xb9, 0xf0, 0xa3, 0xb9, 0x5a, - 0x7f, 0xc6, 0x1f, 0x04, 0x8c, 0x32, 0x1a, 0xa9, 0xdc, 0x0e, 0x72, 0x99, 0x2c, 0x0a, 0x29, 0x8a, 0x78, 0x2e, 0x78, - 0xae, 0x58, 0xd1, 0x1b, 0x89, 0x22, 0x65, 0x45, 0xb3, 0xa0, 0x29, 0x5f, 0xc8, 0xf8, 0x64, 0x7e, 0xd7, 0xab, 0xf7, - 0x60, 0xf2, 0xe3, 0x5c, 0xe4, 0xac, 0x07, 0xfc, 0xc6, 0xa4, 0x10, 0x8b, 0x3c, 0xb5, 0xc3, 0x58, 0xe4, 0x92, 0xa9, - 0xde, 0x9c, 0xa6, 0x60, 0x07, 0x1c, 0x9f, 0xcd, 0xef, 0x7a, 0x7a, 0xd6, 0xb7, 0x8c, 0x4f, 0xa6, 0x2a, 0xee, 0xb6, - 0x5a, 0xe6, 0x5b, 0xf2, 0x7f, 0x58, 0xdc, 0xee, 0x44, 0x9d, 0xee, 0xfc, 0x0e, 0x38, 0x78, 0xc5, 0x8a, 0x26, 0xc0, - 0x02, 0x2a, 0xb5, 0xa3, 0xd6, 0xa3, 0xe3, 0x87, 0x90, 0x01, 0x36, 0x0e, 0x4d, 0x3d, 0x21, 0x30, 0x76, 0x8f, 0x17, - 0xf3, 0x39, 0x2b, 0xc0, 0x8b, 0xbe, 0x37, 0xa3, 0xc5, 0x84, 0xe7, 0xcd, 0x42, 0x37, 0xda, 0x3c, 0x9b, 0xdf, 0xad, - 0x61, 0x3e, 0xb1, 0x31, 0x5b, 0xb5, 0xd3, 0xb2, 0x5f, 0x4b, 0x6f, 0x88, 0x3a, 0x26, 0x4d, 0x5c, 0x4c, 0x46, 0x34, - 0x6c, 0x77, 0x1e, 0x62, 0xf7, 0xbf, 0xa8, 0x83, 0x3c, 0xb0, 0x35, 0xd3, 0x45, 0xa1, 0x6f, 0x51, 0xe3, 0xb6, 0x34, - 0xcd, 0x4e, 0xc5, 0x57, 0x56, 0xb8, 0x56, 0xf5, 0xc7, 0x72, 0x6b, 0xde, 0xff, 0x49, 0xa3, 0x9f, 0xf1, 0x84, 0xc2, - 0x1a, 0x68, 0xe4, 0x18, 0x68, 0x79, 0x10, 0x66, 0x3a, 0x5c, 0xde, 0xf2, 0x54, 0x4d, 0xe3, 0x76, 0xab, 0xf5, 0x43, - 0xb5, 0x62, 0xbd, 0xa9, 0x01, 0x5d, 0xbb, 0x60, 0xb3, 0xda, 0x3a, 0xce, 0x68, 0x89, 0x6d, 0xcb, 0xb9, 0xb0, 0x4b, - 0x5e, 0xb0, 0x4c, 0x47, 0x93, 0x59, 0x5b, 0x94, 0xdb, 0x1a, 0x27, 0xcf, 0xa7, 0xac, 0xe0, 0xaa, 0x57, 0xff, 0xaa, - 0x3a, 0xde, 0x5e, 0xfd, 0xb5, 0x91, 0x43, 0x97, 0xa6, 0x86, 0xbd, 0xf4, 0xbc, 0x82, 0x8f, 0xed, 0xd5, 0xff, 0x4a, - 0x8b, 0x70, 0x03, 0x31, 0xb1, 0x5f, 0x03, 0xad, 0xbd, 0x39, 0x17, 0x60, 0x92, 0x39, 0xc4, 0xdf, 0x80, 0x42, 0x42, - 0xb3, 0x24, 0x84, 0x11, 0xed, 0x35, 0xf7, 0x8e, 0x0b, 0x36, 0x43, 0x0e, 0x10, 0xd1, 0xc3, 0x6e, 0xc1, 0x66, 0xeb, - 0x48, 0x57, 0x5f, 0x6a, 0x14, 0xa1, 0x19, 0x9f, 0xe4, 0x71, 0xc2, 0x00, 0x7d, 0xd7, 0x11, 0xcb, 0x15, 0x57, 0xf7, - 0xcd, 0x42, 0xdc, 0x2e, 0x53, 0x2e, 0xe7, 0x19, 0xbd, 0x8f, 0xc7, 0x19, 0xbb, 0xeb, 0xe9, 0x52, 0x4d, 0xae, 0xd8, - 0x4c, 0xda, 0xb2, 0x3d, 0x48, 0x6f, 0xa6, 0xc6, 0x6c, 0x02, 0xa0, 0x27, 0x6e, 0x37, 0xf7, 0x4f, 0x74, 0x2c, 0xf7, - 0x18, 0x95, 0xac, 0x29, 0x16, 0x6a, 0xaf, 0x25, 0x7b, 0x33, 0x9e, 0x37, 0xed, 0x40, 0x4e, 0x5a, 0xf3, 0xbb, 0xde, - 0x36, 0xe4, 0xbd, 0xfe, 0x23, 0x76, 0x37, 0xa7, 0x79, 0xca, 0xd2, 0xa5, 0x57, 0xad, 0x03, 0xf5, 0xfc, 0x52, 0x71, - 0xae, 0xa6, 0x4d, 0x6d, 0xeb, 0x15, 0x76, 0x72, 0xf4, 0x0d, 0xd4, 0x7a, 0xd4, 0xc2, 0xe6, 0xff, 0xa3, 0x36, 0xf2, - 0x2b, 0xef, 0x41, 0xd8, 0x25, 0x3e, 0xbe, 0x6f, 0xc2, 0xdf, 0x25, 0xf8, 0x16, 0xf1, 0x84, 0x66, 0x16, 0x22, 0x33, - 0x9e, 0xa6, 0x59, 0x6d, 0x44, 0x17, 0x5e, 0x67, 0x6d, 0xb4, 0x84, 0xf9, 0xc7, 0xad, 0xbd, 0xd6, 0x9e, 0x9e, 0x8b, - 0xdd, 0xe6, 0x27, 0x27, 0x0f, 0x8f, 0x1f, 0xb1, 0x5e, 0xc6, 0x73, 0x56, 0x9b, 0xea, 0x77, 0x41, 0xed, 0x37, 0xdc, - 0xb1, 0x0d, 0xb7, 0xf7, 0xda, 0x7b, 0x27, 0xad, 0x1f, 0xdc, 0x6e, 0xcd, 0xd8, 0x58, 0xc5, 0xed, 0xd3, 0xf9, 0x5d, - 0x7d, 0xfb, 0x9e, 0xb9, 0xa6, 0x6f, 0x0b, 0x3a, 0x8f, 0x73, 0x01, 0x7f, 0x7a, 0xb0, 0xc9, 0xc6, 0x99, 0xb8, 0x8d, - 0xa7, 0x3c, 0x4d, 0x59, 0x6e, 0x0a, 0x94, 0x89, 0x2c, 0xcb, 0xf8, 0x5c, 0x72, 0xb3, 0x1a, 0x16, 0x77, 0xbb, 0x1b, - 0x50, 0xf5, 0x07, 0x74, 0xec, 0x0d, 0xa8, 0x5b, 0x0d, 0xa8, 0xea, 0xdf, 0x1f, 0x61, 0x67, 0x63, 0xae, 0xba, 0x54, - 0xaf, 0x86, 0x49, 0x7f, 0x2d, 0xa4, 0x02, 0x98, 0x97, 0x46, 0x1a, 0x40, 0xc5, 0x9b, 0x23, 0xa6, 0x6e, 0x19, 0xcb, - 0xbf, 0x3d, 0x88, 0x8b, 0x58, 0xe4, 0xd9, 0xbd, 0xf9, 0x5c, 0xfa, 0x5d, 0xd2, 0x85, 0x12, 0xeb, 0x68, 0xc4, 0x73, - 0x5a, 0xdc, 0xdf, 0x48, 0x96, 0x4b, 0x51, 0xdc, 0x88, 0xf1, 0x78, 0xf9, 0x2d, 0xd2, 0xf2, 0x10, 0xad, 0x23, 0xc9, - 0xf3, 0x49, 0xc6, 0x0c, 0x51, 0xd2, 0x88, 0x60, 0x89, 0xb9, 0x69, 0x57, 0x37, 0x59, 0x1b, 0xb4, 0xbf, 0xf3, 0x74, - 0xbb, 0xc3, 0x38, 0x6e, 0xde, 0xb2, 0xd1, 0x17, 0xae, 0x0c, 0x9e, 0x35, 0xe5, 0x2d, 0x78, 0xbc, 0xe8, 0x65, 0x98, - 0xb3, 0x62, 0xe9, 0x68, 0x78, 0xcb, 0xa3, 0x3a, 0x51, 0x92, 0xf1, 0x19, 0x55, 0xcc, 0xa3, 0x54, 0x65, 0x27, 0x93, - 0x82, 0xa7, 0xdb, 0x38, 0xd2, 0x83, 0xe4, 0xa6, 0x33, 0xa8, 0x82, 0x9e, 0x16, 0xb3, 0x5c, 0xc6, 0x05, 0x9b, 0x33, - 0xaa, 0xc2, 0x63, 0xdc, 0x1e, 0x17, 0xa8, 0x37, 0xa1, 0xf3, 0x18, 0xf0, 0xc2, 0x75, 0xd9, 0x86, 0x25, 0xd8, 0xde, - 0xae, 0xeb, 0xcf, 0xf8, 0x8b, 0xd4, 0x87, 0x97, 0xa2, 0xa3, 0x26, 0x84, 0x1f, 0x63, 0x45, 0xb9, 0xc5, 0x79, 0xae, - 0x11, 0x56, 0xaf, 0xcf, 0xe6, 0x26, 0xf5, 0x8f, 0xa0, 0x93, 0x56, 0xcb, 0xf5, 0xd3, 0x34, 0x75, 0xe2, 0x76, 0xd4, - 0x65, 0xb3, 0x5d, 0xe4, 0xa1, 0x4e, 0x0b, 0xdb, 0x9d, 0xf9, 0xdd, 0x9e, 0xfe, 0xa7, 0xb5, 0xd7, 0xda, 0xa6, 0x7d, - 0xdb, 0xcb, 0x74, 0x8c, 0x1c, 0x62, 0x29, 0x31, 0x8f, 0xdb, 0x6c, 0xd6, 0x5b, 0x48, 0x38, 0xe7, 0x34, 0x69, 0xd6, - 0xe7, 0xe7, 0x5a, 0xcf, 0x04, 0xd0, 0x88, 0xf2, 0x1c, 0x8e, 0x15, 0x73, 0xb4, 0x42, 0x1f, 0x52, 0x80, 0x1d, 0xf8, - 0xce, 0x46, 0xeb, 0xc3, 0x6a, 0xed, 0x55, 0x03, 0x83, 0x7f, 0xd6, 0x9f, 0x2b, 0xc6, 0xf4, 0x05, 0xf3, 0x04, 0x03, - 0xde, 0x88, 0xba, 0xab, 0x96, 0x15, 0x06, 0x52, 0x55, 0xc9, 0x28, 0xda, 0x95, 0x62, 0x46, 0xef, 0x8c, 0x4f, 0xc5, - 0x8c, 0xe7, 0x60, 0xb1, 0x85, 0xb0, 0xf2, 0x6c, 0xdb, 0xa7, 0x7e, 0x43, 0xa9, 0x0a, 0xa1, 0xe1, 0xc3, 0x4e, 0xd4, - 0xed, 0x22, 0xdc, 0xc2, 0x9d, 0x6e, 0xd7, 0x13, 0x46, 0xc6, 0x6a, 0x57, 0xd1, 0x5d, 0x25, 0xf3, 0x1d, 0x25, 0x8f, - 0x74, 0xa3, 0x47, 0xed, 0x56, 0x0b, 0x6b, 0xbf, 0xf1, 0xb2, 0x30, 0xcb, 0x77, 0x34, 0xdb, 0x6e, 0xb5, 0xa0, 0x59, - 0xf8, 0x63, 0xe7, 0xf5, 0x0b, 0x59, 0xb6, 0xe2, 0x16, 0x6e, 0xc7, 0x6d, 0xdc, 0x89, 0x3b, 0xf8, 0x38, 0x3e, 0xc6, - 0x27, 0xf1, 0x09, 0xee, 0xc6, 0x5d, 0x7c, 0x1a, 0x9f, 0xe2, 0x87, 0xf1, 0x43, 0x7c, 0x16, 0x9f, 0xe1, 0x47, 0xf1, - 0x23, 0x7c, 0x19, 0xb7, 0x5b, 0xf8, 0x71, 0xdc, 0x6e, 0xe3, 0xab, 0xb8, 0xdd, 0xc1, 0x4f, 0xe2, 0xf6, 0x31, 0x7e, - 0x1a, 0xb7, 0x4f, 0xf0, 0xb3, 0xb8, 0xdd, 0xc5, 0x14, 0x72, 0x47, 0x90, 0x9b, 0x40, 0x6e, 0x0a, 0xb9, 0x0c, 0x72, - 0xc7, 0x71, 0xbb, 0xbb, 0xc6, 0xd2, 0xc4, 0x9a, 0x08, 0x5a, 0xed, 0xce, 0xf1, 0x49, 0xf7, 0xf4, 0xe1, 0xd9, 0xa3, - 0xcb, 0xc7, 0x57, 0x4f, 0x9e, 0x3e, 0x0b, 0x86, 0x78, 0xa4, 0x5d, 0x3e, 0xa4, 0x1c, 0xf0, 0x83, 0x76, 0x77, 0x88, - 0x6f, 0xdc, 0x67, 0xc8, 0x0f, 0x3a, 0x27, 0x2d, 0x74, 0x71, 0x71, 0x32, 0x6c, 0x94, 0xb9, 0xef, 0xb5, 0xa7, 0x49, - 0x95, 0x45, 0x08, 0x09, 0x21, 0x07, 0xe1, 0x7b, 0x5d, 0xef, 0x3d, 0x0b, 0x79, 0x54, 0xa0, 0x83, 0x03, 0xfd, 0x63, - 0xe2, 0x7e, 0x8c, 0xdc, 0x0f, 0xea, 0x2d, 0xd2, 0x1d, 0x0d, 0xad, 0xab, 0xb1, 0x2a, 0x0d, 0xfd, 0x4b, 0x1b, 0x9a, - 0x3d, 0x6e, 0xad, 0xd9, 0xff, 0x2b, 0x30, 0xd6, 0x2a, 0xe4, 0xc4, 0x68, 0x84, 0xba, 0x7d, 0x46, 0x96, 0x45, 0xdc, - 0xe9, 0x76, 0x0f, 0x7e, 0x19, 0xf0, 0x41, 0x7b, 0x38, 0x3c, 0x6c, 0x3f, 0xc4, 0x93, 0x32, 0xa1, 0x63, 0x12, 0x46, - 0x65, 0xc2, 0xb1, 0x49, 0xa0, 0xb1, 0xa9, 0x0d, 0x49, 0x27, 0x3a, 0x09, 0x4a, 0xac, 0x63, 0xdd, 0xf6, 0x43, 0xd3, - 0xf6, 0x23, 0x30, 0xa3, 0xd2, 0xcd, 0xdb, 0xa6, 0xcf, 0xcf, 0x4f, 0x56, 0xb6, 0x51, 0x3c, 0x89, 0x6d, 0x6b, 0x2e, - 0xf1, 0x64, 0x38, 0xc4, 0x23, 0x9d, 0xd8, 0xad, 0x12, 0x4f, 0x87, 0x43, 0xdb, 0xd5, 0x23, 0xdd, 0xd5, 0xc3, 0x2a, - 0xeb, 0x6c, 0x38, 0xd4, 0x5d, 0x22, 0xeb, 0x34, 0x2f, 0xd5, 0xde, 0xd7, 0x52, 0x71, 0xc1, 0xcf, 0x3b, 0xdd, 0x6e, - 0x1f, 0x30, 0x4c, 0x1b, 0xc3, 0x3a, 0x18, 0xdd, 0x7a, 0x30, 0xba, 0x87, 0xdf, 0xfd, 0x11, 0x8d, 0x6f, 0x68, 0x09, - 0xa4, 0x7e, 0xf0, 0x5f, 0x41, 0x43, 0x69, 0x98, 0xeb, 0x3f, 0x13, 0xf3, 0x67, 0x84, 0x1a, 0x5f, 0x29, 0x80, 0x1b, - 0x54, 0x31, 0x4e, 0x97, 0xaa, 0x7b, 0xfc, 0x42, 0xc1, 0xb7, 0x65, 0x2a, 0x33, 0xda, 0x5f, 0x4d, 0x6f, 0x47, 0xab, - 0xa9, 0xfc, 0x8a, 0xfe, 0x0c, 0xff, 0x94, 0x87, 0xe1, 0xa0, 0xd9, 0x88, 0xd8, 0x9f, 0x29, 0x38, 0xd1, 0xf4, 0xe3, - 0x94, 0x4d, 0x50, 0x7f, 0xf0, 0xa7, 0xc4, 0xc3, 0x86, 0x97, 0xf1, 0xc3, 0x76, 0x0a, 0xb8, 0xd8, 0x6c, 0x26, 0x86, - 0x3f, 0xa0, 0x3e, 0xea, 0xff, 0x29, 0x0f, 0xff, 0x44, 0x0f, 0x8e, 0xaa, 0xb9, 0xfc, 0x2e, 0xec, 0x16, 0xae, 0xe2, - 0xee, 0x1c, 0x96, 0x5b, 0x98, 0xe1, 0x76, 0x93, 0x41, 0x94, 0x32, 0xf0, 0xc1, 0x26, 0xa1, 0x68, 0xf0, 0xa3, 0xe3, - 0x16, 0xfa, 0xa1, 0xdd, 0x01, 0xad, 0x42, 0x53, 0x1e, 0x6e, 0x6f, 0xfa, 0xa2, 0x79, 0x8c, 0x1f, 0x35, 0x0b, 0xdc, - 0x46, 0xb8, 0xd9, 0x76, 0xea, 0xde, 0x41, 0x1e, 0xb6, 0x10, 0xce, 0xc3, 0x33, 0xf8, 0xe7, 0x04, 0x0d, 0xab, 0x0d, - 0x79, 0x4d, 0x37, 0x7b, 0x07, 0x87, 0x51, 0x12, 0xe6, 0x0d, 0x7e, 0x74, 0xda, 0x42, 0x3f, 0x9c, 0xea, 0x8e, 0xd8, - 0xa1, 0xda, 0xd1, 0x95, 0xc0, 0x27, 0x4d, 0x01, 0x1d, 0xb5, 0xca, 0x7e, 0x64, 0xd8, 0x45, 0x58, 0x86, 0xc7, 0xf0, - 0x4f, 0xdb, 0xef, 0xe7, 0xd7, 0xad, 0x7e, 0xf4, 0xbc, 0xdb, 0x38, 0xea, 0x1a, 0xff, 0xd3, 0xdc, 0x5c, 0x06, 0x37, - 0xd8, 0x45, 0x5b, 0xdf, 0x62, 0xb5, 0x8f, 0xe0, 0x03, 0x61, 0x75, 0x48, 0x72, 0xcc, 0x0e, 0xc1, 0x71, 0x15, 0xec, - 0x35, 0xf2, 0xf3, 0xe3, 0x5e, 0xde, 0x68, 0x20, 0x90, 0x0f, 0x0f, 0x49, 0xbb, 0xa9, 0x9a, 0x0c, 0xc3, 0xef, 0x06, - 0x29, 0xa3, 0xa1, 0xc9, 0xaa, 0xd7, 0x2b, 0xdb, 0xab, 0xb9, 0xf2, 0x76, 0xd8, 0x01, 0x62, 0x62, 0x3f, 0x54, 0x4d, - 0x86, 0x8e, 0x64, 0x23, 0x54, 0xe7, 0xac, 0x7f, 0x1a, 0xb7, 0x90, 0xc6, 0xce, 0xbc, 0x1f, 0xb2, 0x26, 0x87, 0xf4, - 0x4e, 0x1c, 0xf2, 0xa6, 0x82, 0x5f, 0x27, 0x1e, 0xb4, 0x24, 0xe0, 0x5d, 0xe5, 0x86, 0x53, 0x1c, 0x75, 0xba, 0x5d, - 0x2c, 0x09, 0x8f, 0x26, 0xfa, 0x57, 0x4e, 0x78, 0x34, 0xd2, 0xbf, 0x04, 0x29, 0xe1, 0x65, 0x7a, 0xc7, 0x05, 0xf1, - 0x56, 0x55, 0xa7, 0x50, 0x58, 0xd0, 0x02, 0x1d, 0x75, 0xdc, 0x7d, 0x38, 0x9e, 0xba, 0x39, 0x80, 0xfc, 0x5f, 0x68, - 0x53, 0x48, 0xd1, 0x2c, 0x70, 0x46, 0xe8, 0x45, 0xd4, 0xed, 0x4f, 0x8f, 0xc2, 0x4e, 0x53, 0x34, 0x0b, 0x14, 0x4f, - 0x8f, 0x74, 0x4d, 0x9c, 0x90, 0x2b, 0x6a, 0x5a, 0xc3, 0x53, 0xb8, 0xc4, 0x4c, 0x48, 0x72, 0x78, 0xda, 0x6a, 0x44, - 0x5d, 0x84, 0x07, 0xc9, 0xaa, 0x85, 0xb3, 0xd5, 0xaa, 0x85, 0xa9, 0xbf, 0x0c, 0xd2, 0x01, 0xa4, 0x54, 0x51, 0x6d, - 0x06, 0xa5, 0xe9, 0xf3, 0x50, 0xc1, 0x85, 0xbc, 0x02, 0x37, 0x17, 0x05, 0x0e, 0x38, 0x31, 0xb7, 0x37, 0x61, 0x48, - 0x87, 0xe5, 0x1b, 0xfb, 0x4a, 0xab, 0x2b, 0xe9, 0xd6, 0xd5, 0x8e, 0xfc, 0x57, 0x19, 0xfe, 0x2e, 0xb0, 0x49, 0xab, - 0x8a, 0xbd, 0xa6, 0xdb, 0xc5, 0x7e, 0xa5, 0x5b, 0xc5, 0xde, 0xec, 0x28, 0x76, 0xbd, 0x5d, 0xec, 0xa3, 0xf0, 0x54, - 0x6c, 0xfc, 0x87, 0xe3, 0xd3, 0x56, 0xe3, 0x18, 0x90, 0xf5, 0xf8, 0xb4, 0x55, 0x15, 0x7a, 0x40, 0xab, 0xb5, 0x52, - 0xe4, 0x0b, 0x35, 0x4e, 0x06, 0xdc, 0x79, 0x3b, 0xeb, 0x85, 0x33, 0xbe, 0xd6, 0xa5, 0x63, 0xf5, 0xa0, 0x0b, 0x46, - 0x1c, 0x52, 0x53, 0x3b, 0x35, 0x38, 0x1d, 0xf6, 0xa7, 0x2c, 0x6c, 0x40, 0x2a, 0x8a, 0xc7, 0xca, 0xfe, 0x42, 0xe5, - 0x5d, 0xee, 0x47, 0x01, 0x49, 0x9d, 0x21, 0xc2, 0x82, 0x34, 0xd4, 0xe0, 0x78, 0xa8, 0xcf, 0xbb, 0x02, 0x7e, 0x9f, - 0xe8, 0xdf, 0xa5, 0x26, 0xc5, 0x7a, 0x22, 0x4c, 0x6f, 0x47, 0x41, 0x5f, 0x92, 0xd7, 0x34, 0xd4, 0xc6, 0xe5, 0x28, - 0x2e, 0x33, 0xe4, 0x57, 0xc8, 0x78, 0x53, 0x66, 0x48, 0x72, 0x25, 0xed, 0x6f, 0xbc, 0x2c, 0x62, 0x30, 0x34, 0xc1, - 0x93, 0x18, 0x8c, 0x4c, 0xf0, 0x28, 0x96, 0xe0, 0x08, 0x41, 0x63, 0xe6, 0x99, 0xaf, 0x5f, 0x5a, 0xd5, 0x95, 0xbe, - 0x6e, 0x25, 0x1a, 0x4b, 0x7b, 0x0c, 0x4e, 0x8a, 0x8f, 0x22, 0x84, 0xbf, 0x0d, 0x85, 0x30, 0x83, 0x36, 0x19, 0xc2, - 0x3c, 0x2a, 0x08, 0xa4, 0x61, 0x1e, 0x4d, 0x08, 0x83, 0x26, 0x79, 0x34, 0x22, 0x6c, 0xd0, 0xf1, 0xd0, 0xe4, 0xa9, - 0x86, 0x1d, 0x00, 0x87, 0xd7, 0x6f, 0xb0, 0x95, 0x69, 0x1c, 0xae, 0xc6, 0xa1, 0x09, 0x49, 0x58, 0x1e, 0xc2, 0x2c, - 0x60, 0x73, 0xea, 0x9f, 0x9d, 0x2a, 0xee, 0x23, 0x8f, 0xa8, 0xa6, 0xde, 0x9f, 0x81, 0xac, 0x86, 0x0f, 0x96, 0x6c, - 0x8d, 0xf7, 0x1e, 0x2c, 0xe5, 0xfa, 0x07, 0xf8, 0x93, 0xdb, 0x3f, 0x4a, 0x9f, 0x7e, 0x6b, 0xf4, 0x39, 0x86, 0x62, - 0x3b, 0x4a, 0xa1, 0xcf, 0xce, 0x0f, 0x2e, 0x27, 0xcb, 0xbb, 0x38, 0x48, 0x69, 0xf1, 0x25, 0xc0, 0x9f, 0xe2, 0x20, - 0x03, 0x46, 0x30, 0xc0, 0x1f, 0xe3, 0xa0, 0x60, 0x01, 0xfe, 0x23, 0x0e, 0x46, 0xd9, 0x22, 0xc0, 0x1f, 0xe2, 0x60, - 0x52, 0x04, 0xf8, 0x3d, 0x68, 0x29, 0x53, 0xbe, 0x98, 0x05, 0xf8, 0xf7, 0x38, 0x90, 0xda, 0x0d, 0x00, 0x5f, 0xc6, - 0x01, 0x63, 0x01, 0x7e, 0x17, 0x07, 0x22, 0x0b, 0xf0, 0x75, 0x1c, 0x88, 0x22, 0xc0, 0x8f, 0xe3, 0xa0, 0xa0, 0x01, - 0xbe, 0x8a, 0x03, 0x28, 0x34, 0x09, 0xf0, 0x93, 0x38, 0x80, 0x96, 0x65, 0x80, 0xdf, 0xc6, 0x01, 0xcf, 0x03, 0xfc, - 0x5b, 0x1c, 0xa8, 0x45, 0xf1, 0xf7, 0x42, 0x70, 0x19, 0xe0, 0xa7, 0x71, 0x30, 0xe5, 0x01, 0x7e, 0x13, 0x07, 0x85, - 0x08, 0xf0, 0xeb, 0x38, 0xa0, 0x59, 0x80, 0x5f, 0xc5, 0x41, 0xc6, 0x02, 0xfc, 0x6b, 0x1c, 0xa4, 0x2c, 0xc0, 0x2f, - 0xe3, 0xe0, 0x9e, 0x65, 0x99, 0x08, 0xf0, 0xb3, 0x38, 0x60, 0x79, 0x80, 0x7f, 0x89, 0x83, 0x64, 0x1a, 0xe0, 0x9f, - 0xe2, 0x80, 0x16, 0x5f, 0x64, 0x80, 0x9f, 0xc7, 0x01, 0xa3, 0x01, 0x7e, 0x61, 0x3a, 0x9a, 0x04, 0xf8, 0xe7, 0x38, - 0xb8, 0x9d, 0x06, 0x6b, 0x9c, 0xe7, 0x64, 0xf9, 0x9a, 0x27, 0xec, 0x0f, 0x16, 0x07, 0xe3, 0xd6, 0xf8, 0x6c, 0x3c, - 0x0e, 0x30, 0xcd, 0x15, 0xff, 0x7b, 0xc1, 0x6e, 0x9f, 0x2a, 0x48, 0xa4, 0x6c, 0x94, 0x3e, 0x0c, 0x30, 0xfd, 0x7b, - 0x41, 0xe3, 0x60, 0x3c, 0xd6, 0x05, 0xfe, 0x5e, 0xd0, 0x19, 0x2d, 0xde, 0xb2, 0x38, 0x78, 0x38, 0x1e, 0x8f, 0xd3, - 0x93, 0x00, 0xd3, 0x7f, 0x16, 0x1f, 0x75, 0x0b, 0xba, 0xc0, 0x88, 0xf1, 0x09, 0xd4, 0xed, 0x8e, 0xbb, 0x69, 0x12, - 0xe0, 0x11, 0x97, 0x7f, 0x2f, 0xe0, 0x7b, 0xcc, 0x4e, 0x92, 0x93, 0x00, 0x8f, 0x32, 0x9a, 0x7c, 0x89, 0x83, 0x96, - 0xfe, 0x95, 0xff, 0xc2, 0xd2, 0xd7, 0x33, 0xa1, 0x75, 0xf8, 0x63, 0x36, 0x4a, 0xd2, 0x00, 0xeb, 0xc1, 0x8c, 0xe1, - 0xef, 0x57, 0xfe, 0x8e, 0xa9, 0x38, 0x38, 0xa3, 0x9d, 0x11, 0xeb, 0x04, 0x78, 0xf4, 0xe6, 0x36, 0x8f, 0x03, 0xda, - 0xed, 0xd0, 0x0e, 0x0d, 0xf0, 0x68, 0x51, 0x64, 0xf7, 0xb7, 0x42, 0xa4, 0x00, 0x84, 0xd1, 0xd9, 0xd9, 0xc3, 0x00, - 0x27, 0xf4, 0x57, 0x05, 0xb5, 0xbb, 0xe3, 0x47, 0x8c, 0xb6, 0x02, 0xfc, 0x0b, 0x2d, 0xd4, 0xc7, 0x85, 0xb4, 0x03, - 0x6d, 0x41, 0x8a, 0x48, 0xde, 0x81, 0x7e, 0x3b, 0x48, 0x3b, 0xa7, 0x8f, 0xda, 0x2c, 0xc0, 0xc9, 0xf5, 0x6b, 0xe8, - 0xed, 0xe1, 0xb8, 0xdb, 0x82, 0x8f, 0x1c, 0x04, 0x45, 0x56, 0x40, 0x23, 0xa7, 0x27, 0x8f, 0xba, 0x2c, 0xd5, 0x89, - 0x92, 0x67, 0x5f, 0xf4, 0xec, 0xcf, 0x60, 0x3e, 0x49, 0xc1, 0x67, 0x52, 0xe4, 0x71, 0x90, 0x26, 0xed, 0x93, 0x63, - 0x48, 0xb8, 0xa7, 0xb9, 0x03, 0xce, 0x1d, 0x54, 0x3d, 0x1b, 0x05, 0xf8, 0xce, 0xa4, 0x9e, 0x8d, 0xf4, 0xc7, 0xe4, - 0xdd, 0xaf, 0xf9, 0x9b, 0x34, 0x0e, 0x46, 0x67, 0x67, 0xa7, 0x2d, 0x48, 0xf8, 0x40, 0xef, 0xe3, 0x80, 0x3e, 0x82, - 0xff, 0x20, 0xfb, 0xe3, 0x33, 0xe8, 0x10, 0x46, 0x78, 0x37, 0xf9, 0xe8, 0xe7, 0x7c, 0x99, 0xd2, 0x2f, 0x3c, 0x0e, - 0x46, 0xe9, 0xe8, 0xe1, 0x29, 0xd4, 0x9b, 0xd1, 0xc9, 0x33, 0x45, 0xa1, 0xdd, 0x56, 0x4b, 0xb7, 0xfc, 0x8e, 0x7f, - 0x65, 0xba, 0x7a, 0xb7, 0x7b, 0x3a, 0xea, 0xc0, 0x08, 0xae, 0x41, 0xc3, 0x01, 0xe3, 0x39, 0x4b, 0x74, 0x83, 0xd7, - 0xc9, 0xd3, 0x34, 0x0e, 0x1e, 0x3d, 0x3a, 0xee, 0x24, 0x49, 0x80, 0xef, 0x3e, 0xa6, 0xa6, 0xb6, 0xce, 0x93, 0x00, - 0xfb, 0x38, 0x60, 0x8f, 0x1e, 0x9d, 0x3e, 0xa4, 0xf0, 0xfd, 0x5c, 0xb7, 0x75, 0x36, 0x1e, 0x25, 0x67, 0xd0, 0xd6, - 0xef, 0x30, 0x9d, 0x93, 0xb3, 0xe3, 0x54, 0xf7, 0xf5, 0xbb, 0x1e, 0x75, 0x67, 0x7c, 0x32, 0x3e, 0xd1, 0x99, 0x7a, - 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x0e, 0x12, 0x96, 0xb6, 0x03, 0x7c, 0x67, 0x17, 0xee, 0xd1, 0x49, 0xab, 0x95, 0x1e, - 0x07, 0x38, 0xbd, 0x9c, 0xcf, 0xdf, 0x6a, 0x08, 0xb6, 0x4f, 0x1e, 0x99, 0x6f, 0xf9, 0xe5, 0x1e, 0x9a, 0x1e, 0x69, - 0xa0, 0xa5, 0x7c, 0xa6, 0x5b, 0x3e, 0x7d, 0x04, 0xff, 0xe9, 0x6f, 0xdd, 0x74, 0xf9, 0x2d, 0xd2, 0x89, 0x59, 0x94, - 0x36, 0x7b, 0xd4, 0x82, 0x1a, 0x63, 0xfe, 0x71, 0x54, 0x70, 0x40, 0xa3, 0x51, 0x07, 0xfe, 0x2f, 0xc0, 0xe3, 0xec, - 0xfa, 0xb5, 0xc5, 0xd9, 0xf1, 0x98, 0x8e, 0x5b, 0x01, 0x1e, 0x8b, 0x8f, 0x52, 0x7d, 0xb8, 0xcc, 0xe3, 0xa0, 0xd3, - 0x39, 0x1b, 0xe9, 0x32, 0x8b, 0x5f, 0x24, 0xd7, 0x78, 0xdc, 0xd2, 0xad, 0x4c, 0xe8, 0x5b, 0x39, 0xba, 0x16, 0xb0, - 0x92, 0xf0, 0x5f, 0x80, 0x27, 0xa0, 0x16, 0xb3, 0xad, 0x9c, 0x99, 0xed, 0x30, 0x79, 0xa7, 0x51, 0x33, 0x7d, 0x08, - 0xf0, 0x72, 0xcb, 0x98, 0x52, 0xda, 0xed, 0xb4, 0x02, 0xac, 0x47, 0x7d, 0xd6, 0x82, 0xff, 0x02, 0x6c, 0x20, 0xa7, - 0xe1, 0x3a, 0xf9, 0xf8, 0xec, 0xe5, 0x6d, 0x1c, 0xd0, 0x74, 0x3c, 0x86, 0x25, 0xd1, 0x93, 0x71, 0xc5, 0xa6, 0x22, - 0x67, 0xf7, 0xbf, 0xde, 0xda, 0xed, 0xa2, 0x13, 0x94, 0x85, 0xce, 0xe9, 0xa3, 0xd1, 0x49, 0x80, 0xdf, 0xa6, 0x9c, - 0xe6, 0xb0, 0x4a, 0x49, 0xda, 0x4d, 0xba, 0x89, 0x4e, 0x98, 0x88, 0x38, 0x38, 0x81, 0x25, 0xef, 0x04, 0x98, 0x7f, - 0xbd, 0xbe, 0x37, 0xe8, 0x06, 0xb5, 0x2d, 0x82, 0x8c, 0x5b, 0xec, 0xf4, 0x2c, 0x09, 0x70, 0x46, 0xbf, 0x3e, 0xfb, - 0xb5, 0x88, 0x03, 0x76, 0xca, 0x4e, 0xc7, 0xd4, 0x7d, 0xff, 0x21, 0xa7, 0xba, 0x46, 0x6b, 0xdc, 0x85, 0xa4, 0xdb, - 0x5c, 0x8f, 0xf5, 0x61, 0x32, 0xd6, 0x18, 0xf2, 0x6a, 0x26, 0xf2, 0xe4, 0xe9, 0x78, 0x2c, 0x0c, 0x16, 0x53, 0xd8, - 0x84, 0x9f, 0x00, 0xda, 0x34, 0x4d, 0xcf, 0xd8, 0x69, 0x80, 0x3f, 0x99, 0x5d, 0x62, 0x27, 0xf0, 0xc9, 0x60, 0x36, - 0xb3, 0xbb, 0xfd, 0x93, 0x01, 0x0a, 0xcc, 0x77, 0x4c, 0xc7, 0x34, 0xed, 0x04, 0xf8, 0x93, 0x86, 0x4b, 0x7a, 0x0c, - 0xff, 0x41, 0x01, 0xe8, 0xec, 0x51, 0x8b, 0xb1, 0x47, 0x2d, 0xfd, 0xe5, 0xe7, 0xd9, 0x99, 0x8f, 0x4e, 0x93, 0x76, - 0x80, 0x3f, 0x59, 0x74, 0x1c, 0x8f, 0x69, 0x0b, 0xd0, 0xf1, 0x93, 0x45, 0xc7, 0x4e, 0x6b, 0xd4, 0xa1, 0xfa, 0xdb, - 0x60, 0xcd, 0xd9, 0xc3, 0x84, 0xc1, 0xe4, 0x3e, 0x19, 0x84, 0x7c, 0xf8, 0xf0, 0xec, 0xec, 0xd1, 0x23, 0xf8, 0xd4, - 0x6d, 0x97, 0x9f, 0x52, 0x5d, 0x66, 0x1a, 0xc9, 0x5a, 0xc9, 0x09, 0xd0, 0xc9, 0x4f, 0x7a, 0x8c, 0xe3, 0xf1, 0x98, - 0xb5, 0x02, 0x9c, 0xf1, 0x19, 0x33, 0x98, 0x60, 0x7e, 0xeb, 0x8e, 0x8e, 0x3b, 0x49, 0x7a, 0xdc, 0x09, 0x70, 0xf6, - 0xf6, 0x99, 0x9e, 0x4d, 0x0b, 0x66, 0xef, 0xb6, 0x9c, 0xc3, 0x9a, 0x19, 0x7d, 0x03, 0x83, 0x84, 0x95, 0x86, 0xca, - 0xef, 0x3d, 0x7a, 0x78, 0x7a, 0x9a, 0xa4, 0x30, 0xd0, 0xf7, 0xd0, 0x2d, 0x80, 0xf1, 0xbd, 0xd9, 0x7c, 0x23, 0xda, - 0xed, 0xc2, 0x74, 0xdf, 0xcf, 0x17, 0xc5, 0xfc, 0x55, 0x1c, 0x3c, 0x3a, 0x7e, 0xd8, 0x4a, 0x47, 0x01, 0x7e, 0x6f, - 0x27, 0x78, 0x9c, 0x8c, 0x8e, 0x1f, 0xb6, 0x03, 0xfc, 0x5e, 0xef, 0xb7, 0x87, 0xa3, 0xd3, 0x33, 0x38, 0x37, 0xde, - 0xcb, 0x79, 0xf1, 0x76, 0xa2, 0x0b, 0x8c, 0xe9, 0x23, 0x68, 0xf6, 0x37, 0xbd, 0x1b, 0xd3, 0x36, 0x6c, 0xe4, 0xf7, - 0x7a, 0x93, 0x69, 0x3c, 0x79, 0xd8, 0xee, 0x9e, 0x75, 0x03, 0x3c, 0xe3, 0x69, 0x0e, 0x04, 0x5e, 0x6f, 0x94, 0x47, - 0xed, 0x47, 0x0f, 0x5b, 0x01, 0x9e, 0xbd, 0x55, 0xc9, 0x47, 0x3a, 0xd3, 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa9, - 0xee, 0xdf, 0x48, 0x4b, 0x8f, 0x59, 0x3b, 0xc0, 0x33, 0x91, 0x24, 0x54, 0xbe, 0x35, 0x09, 0xa3, 0x6e, 0x80, 0x73, - 0xfa, 0x95, 0xfe, 0x25, 0xdc, 0x66, 0x4a, 0x19, 0x4d, 0x75, 0x9a, 0xc6, 0xe1, 0x00, 0xbf, 0x4b, 0xe1, 0x16, 0x2e, - 0x0e, 0xc6, 0xe9, 0xb8, 0x0b, 0xe0, 0x01, 0x02, 0x64, 0xb0, 0x1b, 0xa0, 0x01, 0x5f, 0xe9, 0xe3, 0x51, 0x1c, 0x9c, - 0x8e, 0xce, 0x58, 0xe7, 0x38, 0xc0, 0x25, 0x35, 0xa2, 0x5d, 0xc8, 0xd7, 0x9f, 0x1f, 0xf5, 0x96, 0x3a, 0x31, 0x09, - 0x1a, 0x40, 0x29, 0x7d, 0xd8, 0x4a, 0x4f, 0x03, 0x3c, 0x7f, 0xcd, 0xdc, 0x1e, 0x63, 0x8c, 0x9d, 0x01, 0x2c, 0x21, - 0x49, 0x23, 0xd0, 0xd9, 0x78, 0xf4, 0xe8, 0x4c, 0x7f, 0x03, 0x18, 0xe8, 0x98, 0x31, 0x00, 0xd2, 0xfc, 0x35, 0x2b, - 0x01, 0x91, 0x8e, 0x1e, 0xb6, 0x80, 0xbe, 0xcc, 0xe9, 0x9c, 0xde, 0xd3, 0xdb, 0xa7, 0x73, 0x3d, 0xa7, 0x71, 0xda, - 0x0d, 0xf0, 0xfc, 0xf9, 0x2f, 0xf3, 0xc5, 0x78, 0xac, 0x27, 0x44, 0x47, 0x8f, 0x02, 0x3c, 0x67, 0xc5, 0x02, 0xd6, - 0xe8, 0xac, 0x7b, 0x3c, 0x0e, 0xb0, 0x45, 0xc3, 0xa4, 0x95, 0x8c, 0xe0, 0x9a, 0x71, 0x31, 0x8b, 0x83, 0x34, 0xa5, - 0xad, 0x14, 0x2e, 0x1d, 0xc5, 0xed, 0xaf, 0x85, 0x41, 0x23, 0xa6, 0xf1, 0xc1, 0xae, 0x21, 0xcc, 0x17, 0xe0, 0xf1, - 0x71, 0xc4, 0x92, 0x84, 0xda, 0xc4, 0xd3, 0xd3, 0xe3, 0x63, 0xc0, 0x3d, 0x33, 0x43, 0x83, 0x20, 0x6f, 0xe4, 0xfd, - 0xa8, 0x10, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, 0xfe, 0xb5, 0xa6, 0xab, 0xed, 0xd3, 0x47, 0xb0, 0x00, - 0x92, 0xa6, 0xe9, 0x2b, 0x73, 0xb8, 0x9d, 0x8d, 0x4e, 0xba, 0xed, 0xe3, 0x00, 0xbb, 0x8d, 0x40, 0xcf, 0x5a, 0x0f, - 0x3b, 0x50, 0x22, 0x4f, 0xef, 0x4d, 0x89, 0xf1, 0x09, 0x3d, 0x39, 0x6d, 0x05, 0xd8, 0x6d, 0x0d, 0x76, 0x36, 0xea, - 0x3e, 0x84, 0x4f, 0x39, 0x65, 0x59, 0xa6, 0xf1, 0xbb, 0x0b, 0x70, 0x91, 0xfc, 0x59, 0x4e, 0xe3, 0x80, 0xb6, 0xba, - 0x9d, 0x4e, 0x0a, 0x9f, 0xd9, 0x57, 0x56, 0xc4, 0x41, 0xd2, 0x82, 0xff, 0x02, 0xec, 0xed, 0x24, 0x36, 0x0a, 0xb0, - 0xc6, 0xbb, 0x53, 0xda, 0xd5, 0x7b, 0xdf, 0xee, 0xaa, 0xd6, 0x59, 0x0b, 0x36, 0xac, 0xdd, 0x54, 0xf6, 0x4b, 0xe6, - 0xe2, 0xd6, 0x92, 0x58, 0x1a, 0x60, 0x0f, 0x41, 0xc7, 0x0f, 0xc7, 0x01, 0x76, 0x3b, 0xee, 0xe4, 0xf4, 0xac, 0x03, - 0xa4, 0x4c, 0x01, 0xa1, 0x48, 0x3b, 0xa3, 0x13, 0x20, 0x4d, 0x8a, 0xbd, 0x36, 0x78, 0x12, 0x60, 0xf5, 0x54, 0xaa, - 0x57, 0x71, 0x90, 0x9e, 0x8d, 0xc6, 0xe9, 0x59, 0x80, 0x95, 0x98, 0x51, 0x25, 0x34, 0x05, 0x3c, 0x3e, 0x79, 0x18, - 0x60, 0x8d, 0xe6, 0x2d, 0xd6, 0x4a, 0x5b, 0x01, 0xb6, 0x47, 0x09, 0x63, 0x67, 0x1d, 0x98, 0xd6, 0xcf, 0xcf, 0x15, - 0xe0, 0x72, 0xca, 0x46, 0xc7, 0x01, 0x2e, 0xe9, 0xbd, 0x26, 0x44, 0xf0, 0x25, 0x67, 0xe2, 0x8b, 0x65, 0x3d, 0x80, - 0xd4, 0xb9, 0x0d, 0x0f, 0xcb, 0xf0, 0xf2, 0xd6, 0xa0, 0x11, 0xd5, 0x5b, 0xdc, 0xbb, 0x86, 0x7d, 0x42, 0x43, 0xc7, - 0xb6, 0x73, 0xb2, 0x5c, 0xe3, 0x32, 0xba, 0xe9, 0x17, 0x76, 0x2f, 0xc3, 0x1c, 0x4c, 0xe2, 0x6b, 0x29, 0x32, 0x47, - 0xce, 0x9e, 0xdf, 0xba, 0x6c, 0x82, 0x20, 0x29, 0x49, 0xab, 0x27, 0xcf, 0x9d, 0x1b, 0x69, 0x4f, 0x42, 0xcc, 0x03, - 0x48, 0x2f, 0x08, 0x25, 0x0a, 0x42, 0xc3, 0x18, 0x61, 0xd2, 0x59, 0xd7, 0x6b, 0x99, 0x52, 0x18, 0x7b, 0x7d, 0x4a, - 0xa8, 0x0b, 0x0a, 0x0f, 0x77, 0xc4, 0xf9, 0x40, 0x0c, 0x51, 0x4f, 0x10, 0x1d, 0xe2, 0xf9, 0x45, 0xae, 0xc2, 0x3c, - 0x1f, 0x14, 0x43, 0xdc, 0x3e, 0x45, 0x18, 0x82, 0x27, 0x90, 0x81, 0xb8, 0xb8, 0x68, 0x9f, 0x1e, 0x68, 0xa1, 0xef, - 0xe2, 0xe2, 0xcc, 0xfc, 0x80, 0x7f, 0x87, 0x55, 0xc0, 0x6a, 0x18, 0xdf, 0x63, 0xe6, 0x69, 0xf4, 0x34, 0x7f, 0xfd, - 0x98, 0xad, 0x56, 0xe1, 0x63, 0x46, 0x60, 0xc6, 0xf8, 0x31, 0x8b, 0xf4, 0xa5, 0x85, 0x71, 0x8d, 0x21, 0x03, 0xd0, - 0x9c, 0xb5, 0x30, 0x84, 0x51, 0x77, 0x9c, 0xf7, 0x63, 0x36, 0xe0, 0x75, 0xb7, 0xea, 0x2a, 0x76, 0xf1, 0xc1, 0xc1, - 0xb2, 0x88, 0x95, 0x11, 0x13, 0x94, 0x11, 0x13, 0x94, 0x11, 0x13, 0x54, 0x15, 0x3d, 0xfe, 0xa4, 0x0f, 0x52, 0x8a, - 0x56, 0xb6, 0x58, 0x9e, 0xfa, 0x1d, 0xa8, 0x3d, 0x40, 0x3b, 0xd9, 0xaf, 0x94, 0x1d, 0xa5, 0xae, 0x62, 0xa7, 0x02, - 0x63, 0x67, 0xa2, 0xd5, 0x76, 0x1c, 0xfd, 0x3b, 0xea, 0x8e, 0x97, 0x35, 0xb1, 0xec, 0xdd, 0x4e, 0xb1, 0x0c, 0x56, - 0x52, 0x8b, 0x66, 0xfb, 0x26, 0x10, 0x87, 0x1a, 0x3c, 0xd4, 0x82, 0x59, 0x15, 0x1d, 0xae, 0x01, 0x49, 0x3d, 0x90, - 0x42, 0xce, 0xb4, 0x94, 0x56, 0xa0, 0x38, 0x55, 0x61, 0x01, 0x1a, 0x4a, 0xa7, 0xa0, 0x2c, 0x83, 0x98, 0x36, 0x34, - 0x40, 0x72, 0x23, 0xa3, 0x19, 0x59, 0xad, 0x0b, 0xa2, 0x0b, 0x68, 0xc2, 0xb4, 0xc4, 0x02, 0x0d, 0x48, 0xdd, 0x80, - 0xb4, 0x95, 0x41, 0x9c, 0xb1, 0xd9, 0x27, 0x3a, 0x3b, 0xd7, 0xd9, 0x79, 0x99, 0x2d, 0x5c, 0xb6, 0x11, 0x12, 0x85, - 0xce, 0x16, 0x65, 0x36, 0xc8, 0x6c, 0x78, 0x12, 0xe7, 0x78, 0x14, 0x0b, 0x23, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0xea, - 0x6b, 0x73, 0x0f, 0x0e, 0xc2, 0x52, 0x4e, 0xd2, 0x6a, 0xe2, 0x07, 0x4b, 0x1e, 0x15, 0x5a, 0x06, 0xe2, 0xd1, 0xc4, - 0xfe, 0x1d, 0xad, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfa, 0x46, 0x49, 0xf4, 0xd9, 0x29, 0x51, 0x1f, 0x73, 0x1d, 0xfe, - 0xe6, 0x9c, 0x44, 0xad, 0xd6, 0x71, 0xfb, 0xb8, 0x75, 0xd6, 0xe7, 0x87, 0xed, 0x4e, 0xf4, 0xa8, 0x13, 0x6b, 0x45, - 0xc4, 0x5c, 0xdc, 0x82, 0x02, 0xe6, 0xa8, 0x13, 0x9d, 0xa0, 0xc3, 0x76, 0xd4, 0xea, 0x76, 0x9b, 0xf0, 0x0f, 0x7e, - 0xaf, 0xca, 0x6a, 0x27, 0xad, 0x93, 0x6e, 0x9f, 0x1f, 0x6d, 0x54, 0x0a, 0x79, 0x03, 0x0a, 0xa2, 0x23, 0x5d, 0x09, - 0x43, 0xfd, 0x6a, 0x79, 0x9f, 0x6d, 0xe9, 0x79, 0xde, 0xab, 0x30, 0x37, 0xaa, 0x38, 0x80, 0xaa, 0xfb, 0x9a, 0x68, - 0x20, 0xba, 0xaf, 0x51, 0x19, 0xa2, 0x76, 0x59, 0x80, 0xa8, 0xfd, 0x98, 0x87, 0xb2, 0xc1, 0x0e, 0x43, 0x93, 0xaf, - 0xa0, 0x6e, 0x13, 0xc2, 0xc6, 0xe1, 0x89, 0xcd, 0xcd, 0xfd, 0xdc, 0x09, 0x42, 0xcd, 0x1c, 0x72, 0x47, 0x36, 0x57, - 0xf8, 0xb9, 0x23, 0x84, 0x9a, 0x02, 0x72, 0x69, 0xcc, 0x23, 0x0a, 0x39, 0x2a, 0xa2, 0x4d, 0x0d, 0xc9, 0x6a, 0x51, - 0x9e, 0x33, 0x37, 0x6c, 0x3e, 0x86, 0xe5, 0xd1, 0x04, 0xc5, 0x0a, 0xd2, 0x10, 0x35, 0xaf, 0xd2, 0xe6, 0xb4, 0x70, - 0xa9, 0xc6, 0x81, 0x8c, 0x06, 0xfc, 0x73, 0xc8, 0xf4, 0x7b, 0x13, 0xad, 0xfe, 0xf1, 0x69, 0x2b, 0x6e, 0x83, 0x8f, - 0x34, 0xc8, 0xda, 0xd2, 0xc8, 0xda, 0xd2, 0xc9, 0xda, 0xd2, 0xc9, 0xda, 0x20, 0xc0, 0x7b, 0x7d, 0xff, 0x2d, 0x6a, - 0x76, 0x27, 0xbc, 0x34, 0x62, 0x31, 0x56, 0x0a, 0xa1, 0x5a, 0xad, 0x96, 0x6b, 0x30, 0x31, 0x2a, 0x6b, 0x88, 0xbc, - 0x52, 0x7f, 0x2e, 0x8b, 0xb8, 0x85, 0x27, 0x31, 0x68, 0xb9, 0x5b, 0x98, 0xea, 0xcd, 0xed, 0xa8, 0xc2, 0x66, 0xf8, - 0x9a, 0xbe, 0x53, 0x27, 0x5f, 0x90, 0x63, 0xad, 0x3d, 0x5e, 0x16, 0x31, 0x37, 0x34, 0x83, 0x1b, 0x9a, 0xc1, 0x0d, - 0xcd, 0x80, 0x46, 0x70, 0x59, 0x58, 0x97, 0x8d, 0x28, 0x81, 0x2b, 0x81, 0xc1, 0xf1, 0x10, 0xa2, 0xf7, 0x85, 0x8a, - 0xe8, 0x51, 0x6f, 0x74, 0xde, 0x86, 0x68, 0x65, 0xa6, 0xa4, 0x8a, 0xa8, 0x76, 0xda, 0x2e, 0xc7, 0xfc, 0xaa, 0x86, - 0xf6, 0x11, 0x3c, 0x25, 0x73, 0xa9, 0xc2, 0x16, 0xd8, 0x6c, 0x04, 0x45, 0xd0, 0xd7, 0x64, 0x21, 0xd6, 0x3a, 0x1b, - 0x6b, 0x8b, 0xfd, 0x65, 0xc3, 0x05, 0xd6, 0x50, 0x02, 0xff, 0x01, 0x85, 0x2f, 0xac, 0xf2, 0xc9, 0x2f, 0x4d, 0x4d, - 0xad, 0x9d, 0x98, 0x39, 0x12, 0x7a, 0x60, 0x2f, 0xee, 0x82, 0x3d, 0xf5, 0x25, 0x11, 0xb9, 0xf6, 0x56, 0x24, 0x55, - 0xb8, 0x62, 0xf0, 0xde, 0x25, 0x77, 0x54, 0xfb, 0xb2, 0xbc, 0x30, 0x7f, 0x5e, 0x51, 0xcf, 0xd9, 0xaf, 0x98, 0x8c, - 0x9c, 0x8f, 0xec, 0x8d, 0x0e, 0xea, 0x43, 0xf6, 0xf7, 0x8d, 0x29, 0xb7, 0xfe, 0xda, 0xb4, 0xe5, 0xd6, 0x89, 0x3a, - 0x1b, 0x76, 0xa8, 0x5b, 0xa3, 0xbf, 0x9d, 0xab, 0x5a, 0x31, 0x19, 0x21, 0x8f, 0x66, 0x6b, 0xb0, 0xe6, 0x15, 0xb0, - 0xa4, 0xad, 0x57, 0x7a, 0x30, 0x42, 0xef, 0x7a, 0xcc, 0xeb, 0x62, 0x32, 0xda, 0xf9, 0xe6, 0x88, 0xe9, 0xb1, 0xff, - 0x96, 0x7a, 0x3d, 0x38, 0xd5, 0xf6, 0x94, 0xdd, 0x7d, 0xaf, 0xce, 0xed, 0xce, 0x3a, 0x32, 0xfb, 0x5e, 0x9d, 0xa7, - 0xbb, 0xea, 0xcc, 0xf8, 0x5d, 0xe8, 0xf6, 0x8e, 0xf2, 0xd4, 0xd8, 0xda, 0x3e, 0x68, 0x32, 0x82, 0x20, 0xf1, 0xf0, - 0xd7, 0x84, 0x72, 0xe9, 0x39, 0x12, 0x0e, 0xab, 0x20, 0xfa, 0x51, 0x37, 0x66, 0x98, 0x92, 0xce, 0x61, 0xa1, 0x83, - 0xb9, 0xc8, 0x88, 0x36, 0xf3, 0x88, 0xe2, 0x8c, 0x84, 0x21, 0x3d, 0x4c, 0x20, 0x24, 0x4d, 0xbb, 0x4f, 0xe3, 0x90, - 0x36, 0x12, 0x74, 0x14, 0xb6, 0x1b, 0xf4, 0x30, 0x41, 0xa8, 0xd1, 0x06, 0x9d, 0xa9, 0x20, 0xed, 0x66, 0x06, 0x41, - 0x2a, 0x35, 0x29, 0xce, 0x0e, 0x65, 0x54, 0x34, 0xc4, 0x61, 0x1e, 0x15, 0x8d, 0xa8, 0x8b, 0x65, 0x34, 0x29, 0x93, - 0x27, 0x3a, 0x79, 0x62, 0x92, 0x47, 0x65, 0xf2, 0x48, 0x27, 0x8f, 0x4c, 0x32, 0x25, 0xc5, 0xa1, 0x8c, 0x68, 0x23, - 0x6c, 0x37, 0x0b, 0x74, 0x08, 0x23, 0x70, 0xa3, 0x27, 0xd2, 0x8f, 0x0d, 0xbe, 0xd6, 0xc6, 0x35, 0x73, 0x91, 0xd9, - 0x68, 0x9d, 0x15, 0x90, 0x4a, 0x8f, 0x27, 0xa8, 0xf3, 0xcc, 0x03, 0x13, 0x56, 0xe6, 0x8f, 0x8b, 0x45, 0xb7, 0x4e, - 0x32, 0x91, 0x7b, 0x1e, 0x5d, 0x60, 0x84, 0xfe, 0xc5, 0xfa, 0xb1, 0x00, 0x54, 0xd7, 0x34, 0x9b, 0x4f, 0xe9, 0x96, - 0xdb, 0x6c, 0x31, 0x19, 0xd9, 0x9d, 0x55, 0x36, 0xc3, 0x68, 0x61, 0x62, 0x3c, 0xd7, 0x1d, 0x1c, 0x01, 0xd4, 0xce, - 0xa9, 0x32, 0xa2, 0x5a, 0x49, 0x6e, 0x6a, 0x4c, 0x0a, 0x76, 0x2f, 0x13, 0x9a, 0xb1, 0xb0, 0x3a, 0x80, 0xab, 0x61, - 0x32, 0xf2, 0x02, 0x4c, 0xe1, 0x8b, 0xc3, 0xe8, 0xb8, 0xa1, 0xa2, 0xc9, 0x61, 0xd4, 0x7d, 0xd4, 0x50, 0xd1, 0xe8, - 0x30, 0x6a, 0xb7, 0x2b, 0x9c, 0x8d, 0x0a, 0xa2, 0xa2, 0x09, 0x51, 0xa0, 0x31, 0x34, 0x8d, 0x8a, 0x39, 0x05, 0xdb, - 0xae, 0x7f, 0x63, 0x18, 0x0d, 0x3b, 0x8c, 0x9c, 0x4d, 0x4c, 0xb8, 0xcb, 0xad, 0x31, 0xf8, 0xdd, 0x74, 0xba, 0xdd, - 0xa6, 0x8a, 0x0a, 0xac, 0xcc, 0x4a, 0x36, 0x55, 0x34, 0xc1, 0xca, 0x2c, 0x5f, 0x53, 0x45, 0x23, 0xd3, 0x94, 0xd6, - 0x01, 0x82, 0xde, 0xb1, 0x04, 0xd6, 0x73, 0xe6, 0x41, 0xbe, 0xe3, 0xbc, 0x53, 0xd6, 0xa0, 0x35, 0xfc, 0x5e, 0xb9, - 0xa6, 0x2b, 0x28, 0xa9, 0x02, 0x1b, 0x1f, 0xf6, 0xad, 0xa2, 0xed, 0xaa, 0x49, 0xf6, 0xaf, 0xcb, 0x96, 0xcd, 0x16, - 0x42, 0xd5, 0x0b, 0x5e, 0xd6, 0x30, 0xc4, 0x96, 0xb2, 0x07, 0xf7, 0x3f, 0x94, 0x84, 0x10, 0xd4, 0x4e, 0x9f, 0x42, - 0x9c, 0x38, 0x3d, 0x32, 0x24, 0xf1, 0x46, 0x63, 0x8d, 0x42, 0xef, 0xbc, 0x7d, 0xea, 0x53, 0xd5, 0xad, 0x48, 0x77, - 0x84, 0x04, 0x8b, 0xdc, 0xd8, 0x42, 0xa6, 0x81, 0xc7, 0x82, 0x58, 0xed, 0x6e, 0xed, 0x80, 0x38, 0x38, 0xd8, 0x3c, - 0x2f, 0xdc, 0x9b, 0x03, 0x5b, 0xef, 0x0c, 0x54, 0x86, 0x74, 0xee, 0x25, 0x24, 0x63, 0x62, 0xcb, 0x3d, 0x44, 0x71, - 0x31, 0xa7, 0x1e, 0x6a, 0x0a, 0x3f, 0xa8, 0x02, 0xee, 0xd9, 0x9c, 0xe6, 0xa9, 0xce, 0xd0, 0x7d, 0x0d, 0xbd, 0xb1, - 0xbd, 0xf1, 0x27, 0x54, 0x1a, 0x09, 0xfe, 0xcb, 0x8e, 0xbd, 0x4e, 0xec, 0x4b, 0x2d, 0x7e, 0xa3, 0x7f, 0xf9, 0x26, - 0xb9, 0x15, 0x6c, 0xac, 0x33, 0xf6, 0x6a, 0x55, 0x7b, 0x97, 0xc7, 0xbc, 0xfe, 0x82, 0x0e, 0x0e, 0xb8, 0x7c, 0x06, - 0x56, 0xc4, 0x2c, 0x6c, 0xf8, 0x87, 0xef, 0xdf, 0xb5, 0xd3, 0xfa, 0x2f, 0x7d, 0xae, 0xc6, 0xde, 0x41, 0x77, 0x59, - 0xcb, 0xdf, 0xb9, 0x12, 0x7d, 0x15, 0x73, 0xbb, 0xd6, 0x7f, 0x55, 0x36, 0xda, 0x5b, 0x2f, 0x44, 0x1d, 0x1c, 0xf0, - 0x2a, 0x4e, 0x53, 0xf0, 0x43, 0x80, 0xfa, 0x5a, 0x06, 0x79, 0x96, 0x09, 0x0a, 0x37, 0xa2, 0x70, 0xc5, 0x10, 0x37, - 0xf8, 0x91, 0xc2, 0x7f, 0x88, 0xff, 0x4f, 0x8d, 0x1c, 0xaa, 0xb8, 0xc1, 0x3d, 0x01, 0xcc, 0x67, 0x85, 0xaa, 0x08, - 0x89, 0x1a, 0xd2, 0xbe, 0xc9, 0x35, 0x2a, 0x0f, 0x73, 0x3a, 0x9f, 0x67, 0xf7, 0xfa, 0x91, 0x2c, 0x8f, 0xa3, 0xaa, - 0x2e, 0x9a, 0x6c, 0x78, 0x3a, 0x5c, 0x00, 0x4f, 0x0f, 0xb8, 0x87, 0xb4, 0x7b, 0x69, 0x79, 0xb9, 0x2d, 0x11, 0x48, - 0x66, 0x39, 0x11, 0xcd, 0x76, 0x2f, 0xbf, 0x00, 0xb9, 0xac, 0xd9, 0x44, 0xca, 0x46, 0xed, 0xc6, 0x1c, 0x64, 0xb2, - 0xdc, 0xb8, 0x90, 0xee, 0x99, 0x82, 0x20, 0xb9, 0x09, 0x2d, 0xb2, 0xed, 0x2e, 0xc5, 0xc7, 0x21, 0xa0, 0x11, 0x32, - 0x02, 0x9f, 0x2f, 0x2c, 0x72, 0xe0, 0x3a, 0x0b, 0xd7, 0xf1, 0x37, 0x5a, 0x2a, 0x06, 0xf9, 0x70, 0x88, 0x0b, 0xfd, - 0x2e, 0x44, 0x39, 0x1f, 0xb8, 0x69, 0x2a, 0xdf, 0x19, 0xf2, 0x44, 0x14, 0xbe, 0x5a, 0xed, 0xc3, 0x33, 0x3e, 0xb6, - 0x4d, 0xf0, 0x39, 0xb5, 0x3f, 0xab, 0x27, 0x3b, 0x60, 0x1c, 0x8c, 0xb4, 0xf4, 0x45, 0xa1, 0x95, 0x37, 0xd9, 0xb9, - 0xec, 0x35, 0x1a, 0x4c, 0x47, 0x58, 0x22, 0x10, 0x4e, 0x0d, 0x1c, 0x02, 0xe1, 0x8f, 0x09, 0x9a, 0x24, 0x99, 0x09, - 0x3d, 0x07, 0x31, 0xb1, 0x6b, 0x09, 0xab, 0x55, 0x6e, 0x42, 0x9b, 0xe8, 0x1c, 0x13, 0xe4, 0xa4, 0xec, 0xa7, 0x8c, - 0xa1, 0x5a, 0x99, 0x71, 0x70, 0xbb, 0xd5, 0xdf, 0x56, 0xfb, 0x79, 0x8f, 0x9b, 0x6b, 0x3c, 0xae, 0x03, 0x06, 0x68, - 0x40, 0x2d, 0x37, 0x36, 0xb8, 0x31, 0x70, 0x0f, 0x8d, 0x35, 0x2e, 0xdb, 0x84, 0xa0, 0x2c, 0x1d, 0xe4, 0xcd, 0xcd, - 0xad, 0x0b, 0x18, 0x98, 0xeb, 0x39, 0xe5, 0x48, 0x0d, 0x40, 0x8e, 0x1e, 0x12, 0xe8, 0xdc, 0xfc, 0xac, 0xe8, 0x42, - 0x25, 0x13, 0x97, 0x63, 0xfc, 0xc5, 0xbb, 0xcd, 0x1b, 0x04, 0x37, 0x37, 0x7a, 0x93, 0xdf, 0xdc, 0x04, 0xd8, 0xb7, - 0x2a, 0x0f, 0x3c, 0x5e, 0x30, 0x18, 0x96, 0x31, 0xa5, 0xf4, 0xc6, 0x6f, 0xb6, 0xab, 0xc6, 0xde, 0xd3, 0x0a, 0xef, - 0x60, 0x79, 0x74, 0xe3, 0x5b, 0x5e, 0x98, 0x03, 0x0e, 0xf0, 0x66, 0x03, 0x3e, 0xec, 0xbd, 0x09, 0x73, 0x74, 0x70, - 0xf0, 0x26, 0x14, 0xa8, 0x7f, 0xcd, 0xf4, 0x9d, 0x1b, 0xb8, 0x61, 0x0f, 0xb8, 0x1e, 0xbe, 0xf0, 0x10, 0xe0, 0x9a, - 0x6d, 0x4a, 0x36, 0x6f, 0x75, 0xd0, 0x8b, 0x18, 0x82, 0x6a, 0x43, 0x68, 0x5f, 0x0b, 0x12, 0xe8, 0xf5, 0x8d, 0x0f, - 0xed, 0x1e, 0x23, 0x0c, 0x58, 0xf8, 0xd2, 0x49, 0x8e, 0x45, 0x33, 0x56, 0x4c, 0x58, 0xb1, 0x5a, 0xbd, 0xa7, 0xc6, - 0xf1, 0x6d, 0x23, 0x46, 0x63, 0xde, 0x6b, 0x34, 0xa8, 0x1e, 0x3f, 0x88, 0x0f, 0x74, 0x88, 0xf7, 0xdf, 0x84, 0x05, - 0x42, 0x60, 0x61, 0xc4, 0xf3, 0x85, 0x73, 0xf2, 0x4a, 0x6a, 0xeb, 0x52, 0xa0, 0xb2, 0x91, 0x8c, 0xb4, 0xf0, 0x94, - 0x24, 0xe5, 0x1a, 0x9d, 0x4f, 0x7b, 0x8d, 0x46, 0x86, 0x44, 0x98, 0x0c, 0xb2, 0x21, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, - 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0xb2, 0xf3, 0x5d, 0x9a, 0xb1, 0xc6, 0x8f, 0xe9, 0xda, 0x03, 0xc6, 0x63, 0xea, - 0x11, 0x89, 0x5d, 0x40, 0x96, 0x06, 0xc8, 0xb9, 0x03, 0xb2, 0xd4, 0x40, 0xce, 0x51, 0x7f, 0x0e, 0xd1, 0x8a, 0x72, - 0x14, 0x6f, 0x51, 0xf4, 0x7a, 0x5c, 0x4d, 0xeb, 0xb3, 0x81, 0xb9, 0x0e, 0xed, 0x60, 0x97, 0x03, 0x1e, 0x3a, 0xb1, - 0x6e, 0x80, 0x39, 0x59, 0x06, 0x81, 0x0e, 0x31, 0x8b, 0xef, 0xf4, 0x9f, 0xe8, 0x0e, 0xdf, 0x9b, 0x1f, 0xf7, 0x9e, - 0x32, 0xe9, 0x79, 0x4d, 0xdb, 0xc0, 0x6d, 0x40, 0xb6, 0x20, 0x0a, 0x00, 0xad, 0x6d, 0x74, 0x41, 0x59, 0x7f, 0x70, - 0x2d, 0x37, 0x71, 0x20, 0x64, 0x83, 0xe4, 0x58, 0x7a, 0xa4, 0xf3, 0xcf, 0x3f, 0x03, 0xd4, 0x97, 0x10, 0xc6, 0xc7, - 0x9e, 0x6c, 0xcd, 0x36, 0x6a, 0x04, 0x51, 0x10, 0x87, 0x2e, 0x4a, 0x04, 0xec, 0x8c, 0x20, 0xf0, 0x1e, 0x5b, 0x29, - 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x3d, 0xa8, 0x2a, 0xee, 0xc5, 0xc5, 0x72, 0x33, 0xca, 0x90, 0x86, 0xaa, 0xd4, 0x21, - 0x5e, 0x90, 0x79, 0x81, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0x06, 0x72, 0xe8, 0x3d, 0x29, 0x56, 0x5d, 0x87, 0x2b, 0x7f, - 0xe1, 0x42, 0x9a, 0x0f, 0xd4, 0x70, 0xb5, 0x32, 0x7f, 0xc9, 0x07, 0x2d, 0xcd, 0xc0, 0xdb, 0x70, 0xde, 0x6d, 0xbc, - 0xdc, 0x2d, 0x8b, 0x45, 0x4a, 0xfc, 0x0e, 0x56, 0x83, 0x2e, 0x68, 0x9f, 0x9d, 0x6a, 0xdb, 0x41, 0x7d, 0xae, 0x35, - 0x0a, 0x5e, 0xc8, 0xdc, 0xea, 0x48, 0xc3, 0x73, 0xe5, 0xe7, 0xd5, 0x42, 0xdf, 0x26, 0x79, 0x19, 0xc1, 0x14, 0x8e, - 0x94, 0x08, 0xcc, 0xc6, 0x35, 0x9d, 0x84, 0x1f, 0x75, 0x2a, 0x69, 0x59, 0x48, 0x80, 0x02, 0x47, 0xfa, 0x72, 0x5e, - 0x47, 0xa8, 0x67, 0x68, 0x07, 0x91, 0xf3, 0x4c, 0x68, 0xea, 0xb2, 0xa5, 0x0d, 0x25, 0x15, 0xcc, 0xc4, 0x42, 0xb2, - 0xc5, 0x1c, 0xce, 0xf7, 0x32, 0x2d, 0xc9, 0x78, 0xf2, 0xa5, 0x9e, 0x02, 0xe6, 0x9f, 0x77, 0x6a, 0xc6, 0xf2, 0x45, - 0x60, 0xe7, 0xf9, 0xca, 0x88, 0xfb, 0x6f, 0x5e, 0xe0, 0xc7, 0xa4, 0x73, 0xf8, 0x0a, 0x7f, 0xa4, 0xe4, 0x71, 0xe3, - 0x15, 0x9e, 0x70, 0x62, 0x78, 0x83, 0xe8, 0xcd, 0xeb, 0xeb, 0x17, 0xef, 0x5e, 0xbc, 0x7f, 0x7a, 0xf3, 0xe2, 0xd5, - 0xb3, 0x17, 0xaf, 0x5e, 0xbc, 0xfb, 0x88, 0xff, 0xa6, 0xe4, 0xd5, 0x51, 0xfb, 0xac, 0x85, 0x3f, 0x90, 0x57, 0x47, - 0x1d, 0x7c, 0xa7, 0xc8, 0xab, 0xa3, 0x13, 0x9c, 0xe5, 0xe4, 0xd5, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0x94, 0x69, 0x32, - 0x13, 0x93, 0x76, 0x0b, 0xff, 0x6d, 0xbf, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x9b, 0xc6, 0x0f, 0x50, 0x86, 0x8e, - 0xa4, 0x36, 0x44, 0x39, 0xf7, 0xd0, 0x69, 0x9a, 0xfb, 0xe8, 0x64, 0x62, 0x28, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, - 0xb6, 0x1d, 0x7e, 0xd4, 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd5, 0x62, 0x8c, 0x33, - 0x21, 0x8a, 0x70, 0x01, 0x8c, 0x80, 0xd6, 0x5a, 0xf0, 0xa3, 0x32, 0x58, 0x93, 0x3c, 0x27, 0xed, 0x7e, 0x3b, 0x96, - 0xe7, 0xa4, 0xd3, 0xef, 0xc0, 0x9f, 0x6e, 0xbf, 0x1b, 0xb7, 0x5b, 0xe8, 0xd0, 0x1b, 0xc7, 0x1f, 0x35, 0xb4, 0x1e, - 0x0c, 0xb1, 0xed, 0x42, 0xfe, 0x5d, 0x28, 0xa7, 0xd2, 0x93, 0x56, 0x1d, 0xdb, 0xee, 0xc9, 0x73, 0xa6, 0xf5, 0xb0, - 0xfc, 0x07, 0x40, 0x6d, 0xed, 0x4f, 0x52, 0x6e, 0x1c, 0xfb, 0x8b, 0x1f, 0x49, 0x54, 0x8b, 0x08, 0x13, 0xb2, 0x55, - 0x0b, 0x01, 0xd3, 0xa8, 0xb3, 0xc1, 0x1c, 0x28, 0x92, 0xa2, 0x50, 0x2e, 0xaa, 0x7d, 0xde, 0x14, 0x28, 0x9a, 0x8b, - 0x79, 0x58, 0x53, 0x35, 0xfc, 0xea, 0x99, 0x39, 0xee, 0x73, 0xf9, 0x8a, 0xbe, 0x0a, 0x6b, 0x3c, 0x8f, 0xcf, 0xda, - 0xf9, 0xdb, 0xe2, 0x17, 0x6b, 0x45, 0x51, 0x03, 0x57, 0x09, 0x58, 0x37, 0xaa, 0xa6, 0x3a, 0x87, 0xe7, 0xfb, 0x58, - 0x43, 0x5d, 0x10, 0x8f, 0x7a, 0xfe, 0x54, 0x9a, 0x71, 0x95, 0xca, 0x68, 0xa7, 0x88, 0xd6, 0x66, 0x41, 0x4e, 0x11, - 0x7d, 0x9e, 0x6b, 0x20, 0x08, 0xc2, 0x07, 0x72, 0x08, 0x07, 0xbe, 0x19, 0xa0, 0xd0, 0x74, 0x0e, 0xd4, 0x4a, 0x95, - 0x99, 0x90, 0xfe, 0xd4, 0xb1, 0x09, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xf4, 0x27, 0x16, 0xc8, 0x1b, 0xfa, 0x6f, 0xfe, - 0x06, 0x38, 0x0c, 0x35, 0x2a, 0xfa, 0x76, 0x35, 0xb2, 0x9e, 0xdf, 0x3e, 0x6b, 0x1d, 0xbd, 0xf2, 0xf2, 0xd3, 0xdc, - 0xd9, 0x7b, 0xfc, 0xe5, 0x51, 0x72, 0x13, 0x4d, 0xab, 0x8d, 0x5d, 0x20, 0xb4, 0x9e, 0x0f, 0x90, 0x43, 0x85, 0x8e, - 0xf4, 0x4b, 0x86, 0x3d, 0xa4, 0x0e, 0x49, 0xbb, 0x05, 0xd1, 0xcb, 0x76, 0x50, 0xbe, 0x9f, 0x36, 0x60, 0xaa, 0xa2, - 0xbb, 0x26, 0xd0, 0x6a, 0x78, 0xdc, 0xe8, 0xbe, 0xc9, 0xa3, 0x7b, 0x9c, 0x7b, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1e, - 0x4a, 0x64, 0xa3, 0xbe, 0x9a, 0x0d, 0xa0, 0x68, 0xde, 0x31, 0x8f, 0xec, 0x39, 0xe3, 0xa8, 0xf3, 0x66, 0xd4, 0x3d, - 0x7c, 0x75, 0x70, 0x10, 0x8a, 0x06, 0x79, 0x8c, 0xf0, 0x92, 0x82, 0x11, 0x35, 0x38, 0x9d, 0x71, 0xc3, 0xc4, 0xc7, - 0xb9, 0x47, 0x1d, 0x17, 0x79, 0xed, 0x58, 0xab, 0x3a, 0x2b, 0x77, 0x83, 0x1b, 0x53, 0x07, 0x35, 0xbc, 0x34, 0x33, - 0xba, 0x4e, 0x0d, 0xca, 0x35, 0x0f, 0x31, 0xd8, 0x96, 0x8d, 0x8f, 0x14, 0xfd, 0xf0, 0xb8, 0xf9, 0xca, 0x9b, 0x70, - 0xcd, 0x34, 0xe9, 0x71, 0xe3, 0x31, 0xfa, 0xe1, 0xb1, 0xe7, 0xe3, 0xc7, 0x2b, 0xf6, 0xc4, 0x71, 0x23, 0x3f, 0x19, - 0xae, 0xf4, 0x27, 0x90, 0xec, 0x0b, 0xf2, 0x13, 0x60, 0x39, 0x25, 0x3f, 0x85, 0xa2, 0x99, 0x83, 0x41, 0xd7, 0x4f, - 0x61, 0x01, 0x3f, 0x32, 0xf2, 0x53, 0x08, 0xd8, 0x8e, 0xa7, 0xfa, 0x47, 0x51, 0xbd, 0xae, 0x0a, 0x6a, 0x14, 0xe3, - 0x5e, 0x56, 0xac, 0x56, 0xf2, 0xe0, 0x40, 0x98, 0x5f, 0xf4, 0x22, 0x39, 0x38, 0xc8, 0xce, 0xa7, 0x9e, 0xed, 0xad, - 0xda, 0x45, 0x5f, 0x34, 0x42, 0x61, 0xcf, 0x34, 0x8d, 0xfb, 0x33, 0xfe, 0xe4, 0x53, 0x56, 0xdd, 0x40, 0xf3, 0xb8, - 0xf3, 0xf0, 0xf4, 0x0c, 0xc3, 0xbf, 0x0f, 0xbd, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, 0xb3, 0xe6, 0x69, 0x85, 0x6c, - 0x17, 0x1e, 0x3e, 0x63, 0x86, 0x9a, 0xf2, 0xe0, 0x80, 0x9f, 0x7b, 0xb8, 0x8c, 0x19, 0x6a, 0x78, 0x16, 0x7b, 0x0f, - 0x4a, 0x7b, 0x32, 0xcd, 0x35, 0xc1, 0xab, 0xb6, 0x7c, 0x50, 0x0c, 0xcf, 0x95, 0xa5, 0x26, 0x7e, 0xec, 0xeb, 0x9c, - 0xb4, 0xec, 0x26, 0xeb, 0xc9, 0x66, 0x7e, 0xd1, 0xee, 0x21, 0x41, 0xf2, 0x86, 0xbc, 0xb8, 0x68, 0x63, 0x50, 0xc9, - 0xf7, 0x73, 0x22, 0x62, 0x49, 0x9c, 0x7f, 0xde, 0x32, 0x13, 0x71, 0x8e, 0xa7, 0x3c, 0x2e, 0xe5, 0xec, 0xd7, 0xce, - 0x7a, 0x5a, 0x7b, 0x4c, 0xea, 0x9e, 0x19, 0x96, 0xfd, 0xbc, 0xf4, 0xf4, 0x83, 0x4d, 0x9a, 0x0f, 0xe1, 0xd1, 0xc0, - 0x12, 0xf3, 0x98, 0x71, 0x6f, 0x63, 0x10, 0x94, 0x39, 0x6f, 0xb4, 0x21, 0x13, 0x3e, 0xd7, 0x71, 0x0e, 0x03, 0xd5, - 0x85, 0xcf, 0x81, 0x4c, 0x25, 0x95, 0x61, 0xb6, 0x6b, 0x18, 0x0a, 0x48, 0x28, 0x70, 0x41, 0x98, 0x27, 0xc1, 0xc3, - 0xed, 0x87, 0x47, 0x38, 0xea, 0xe4, 0xc2, 0x4c, 0xee, 0x3c, 0x87, 0xee, 0xe4, 0xf0, 0x5c, 0xf5, 0x90, 0x6c, 0x34, - 0x2c, 0xb7, 0x7d, 0x21, 0xf5, 0x20, 0x9a, 0xed, 0xe1, 0x05, 0xeb, 0xa1, 0xbc, 0xd9, 0x2c, 0x0d, 0x20, 0x2f, 0x5a, - 0xab, 0x55, 0x7e, 0xee, 0x1a, 0xe9, 0xbb, 0x73, 0x5c, 0xf3, 0x5d, 0x4e, 0xf0, 0xfc, 0x4d, 0x90, 0x41, 0x00, 0x54, - 0x15, 0xf8, 0x6c, 0x31, 0x0f, 0x70, 0xa0, 0xdf, 0x93, 0x83, 0xbf, 0xfa, 0x1d, 0xb0, 0x00, 0x07, 0xf6, 0x89, 0xb9, - 0x60, 0x58, 0x0d, 0x96, 0x27, 0x65, 0x74, 0x74, 0x1e, 0xdd, 0x00, 0xe3, 0xa0, 0xfe, 0x02, 0x4e, 0xbb, 0xfc, 0x1d, - 0x65, 0x36, 0x4e, 0x88, 0x74, 0xaf, 0x9e, 0xd9, 0x51, 0xad, 0x77, 0x7b, 0x66, 0x72, 0x1c, 0xb8, 0xaa, 0xf0, 0x7a, - 0xc0, 0x77, 0x9e, 0x5d, 0x6c, 0xdb, 0xd7, 0xbe, 0x97, 0x65, 0x0f, 0xc0, 0x79, 0xaf, 0xd7, 0x08, 0xff, 0x26, 0x76, - 0x3e, 0xfd, 0x1b, 0xdc, 0x88, 0xfc, 0x09, 0x55, 0x34, 0x68, 0xbc, 0xd6, 0x86, 0x6f, 0x46, 0xce, 0xea, 0x7d, 0x6b, - 0x1c, 0xec, 0xdf, 0xea, 0x1e, 0x22, 0x37, 0xd4, 0x5e, 0x29, 0x32, 0xb2, 0xaf, 0x8e, 0xd7, 0x21, 0x3c, 0xd3, 0xb7, - 0x1d, 0xf0, 0x70, 0x63, 0xa4, 0xe0, 0x4f, 0x6c, 0xf8, 0x24, 0x0a, 0x21, 0x51, 0x6b, 0x5e, 0xcc, 0x90, 0x62, 0xfa, - 0xd0, 0x1e, 0xaf, 0x6b, 0xe4, 0x73, 0xdd, 0xe3, 0xbc, 0x4e, 0x4c, 0xab, 0x6e, 0xb4, 0xd4, 0xc1, 0x36, 0x59, 0x70, - 0x56, 0xf5, 0xae, 0x25, 0x94, 0xea, 0x41, 0x37, 0xfd, 0x28, 0x67, 0xb3, 0xad, 0x5f, 0x39, 0x36, 0xcf, 0xbe, 0xe5, - 0x60, 0xc8, 0xbb, 0x5f, 0x46, 0xab, 0xba, 0x80, 0x63, 0x37, 0xf4, 0x20, 0x2b, 0xc8, 0xc5, 0xd2, 0x3e, 0xc9, 0xc6, - 0x07, 0x62, 0xb8, 0x2e, 0x1f, 0x68, 0xf3, 0xf0, 0xa0, 0x1a, 0xa9, 0x4c, 0x7c, 0xce, 0xc0, 0xbd, 0x6e, 0x58, 0xd3, - 0x0f, 0xf1, 0x7f, 0xe0, 0x80, 0xaf, 0x90, 0x34, 0x36, 0xea, 0x27, 0x78, 0x38, 0x09, 0x14, 0xde, 0xa6, 0xee, 0x27, - 0xe1, 0x7b, 0xa8, 0xd6, 0x75, 0x2a, 0xc6, 0x09, 0xb4, 0xae, 0x58, 0x29, 0x0b, 0x7b, 0xc7, 0x5d, 0x88, 0xd6, 0xb1, - 0x75, 0x18, 0xb5, 0xaf, 0x2d, 0x5d, 0xe6, 0xe0, 0xff, 0xc2, 0x45, 0xfe, 0xac, 0x80, 0xf0, 0x59, 0xbe, 0x3e, 0xed, - 0x67, 0xe1, 0x3f, 0x27, 0x3c, 0x80, 0x7b, 0xc2, 0x92, 0xe7, 0x2c, 0x9f, 0xc0, 0x86, 0x05, 0xca, 0x81, 0x42, 0xe5, - 0x58, 0xae, 0x56, 0xa1, 0xd4, 0x41, 0x15, 0x6c, 0x4c, 0x5d, 0xfb, 0x78, 0x86, 0xd6, 0xdf, 0x41, 0x5d, 0xec, 0xd4, - 0x23, 0xda, 0x84, 0x15, 0xf9, 0x97, 0x4e, 0x79, 0xe2, 0xf5, 0xb5, 0xab, 0x0f, 0x59, 0x4d, 0xb9, 0x1f, 0x6a, 0x7d, - 0xef, 0x3b, 0x3e, 0x63, 0x62, 0x01, 0xaf, 0x16, 0x61, 0x46, 0x24, 0x53, 0xee, 0x1b, 0x28, 0x08, 0x84, 0x9c, 0xe3, - 0x3e, 0x3e, 0x02, 0x5f, 0xe5, 0x68, 0x9d, 0x48, 0xdc, 0x5b, 0x18, 0x81, 0x8e, 0x55, 0x19, 0xf4, 0x03, 0x70, 0x5a, - 0x02, 0x11, 0x8a, 0x90, 0x80, 0xe5, 0x69, 0xd0, 0x0f, 0xb4, 0x8f, 0x54, 0x00, 0x56, 0x63, 0xa0, 0xe4, 0x0e, 0xf0, - 0x3c, 0xaf, 0x88, 0x98, 0x5f, 0x53, 0x79, 0x95, 0x58, 0xac, 0xcd, 0xb4, 0x8f, 0x3a, 0x15, 0x08, 0x8b, 0x64, 0x53, - 0x50, 0x56, 0x1b, 0xea, 0x02, 0x2c, 0x88, 0xc6, 0x58, 0x1e, 0xdd, 0x00, 0x37, 0xc7, 0x52, 0x5b, 0x74, 0xc9, 0xaf, - 0x41, 0x3d, 0x1d, 0x17, 0xf8, 0x46, 0x33, 0x6c, 0x69, 0x4c, 0xd7, 0x84, 0xe3, 0x84, 0x14, 0x11, 0xbd, 0x83, 0xa0, - 0x12, 0x33, 0x9e, 0xc7, 0x19, 0x9e, 0xd1, 0xbb, 0x78, 0x8a, 0x67, 0x3c, 0x7f, 0x62, 0x96, 0x3d, 0x4e, 0x21, 0xc9, - 0x7d, 0x2c, 0xd6, 0x44, 0xbf, 0x89, 0xf5, 0xbb, 0x64, 0xc5, 0x63, 0xe0, 0x55, 0x64, 0x88, 0x7a, 0xa9, 0xb6, 0x29, - 0x67, 0xaa, 0x32, 0x5e, 0x7f, 0xad, 0x42, 0x8a, 0x13, 0x9c, 0xa1, 0x28, 0x13, 0x98, 0xf5, 0x65, 0xfc, 0x1a, 0x02, - 0x4a, 0x27, 0xd8, 0xbc, 0xa7, 0xc5, 0xef, 0x58, 0xf6, 0x4c, 0x14, 0xef, 0xf5, 0x96, 0xcf, 0x10, 0x14, 0x02, 0x17, - 0x15, 0xd9, 0x84, 0xdb, 0xbd, 0x45, 0x5f, 0x54, 0x4d, 0xd1, 0x3b, 0xd3, 0x94, 0x1d, 0xe2, 0x14, 0x22, 0xf1, 0x46, - 0x53, 0xde, 0x68, 0x63, 0xd6, 0x6f, 0x7d, 0xa7, 0xd1, 0x29, 0x2a, 0x4b, 0x22, 0x0c, 0x4f, 0x04, 0x37, 0xf3, 0x58, - 0x10, 0xd9, 0xcc, 0xad, 0x84, 0xb7, 0xd4, 0xc0, 0x8e, 0x73, 0x9c, 0x88, 0x45, 0xae, 0x62, 0xe1, 0xe1, 0x0d, 0xad, - 0x36, 0xd7, 0xf2, 0xce, 0x40, 0x4c, 0xe1, 0x7b, 0xf3, 0x83, 0xe1, 0x1b, 0xad, 0xe2, 0x7f, 0x0b, 0x86, 0x3d, 0x32, - 0x96, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x19, 0x7e, 0xf2, 0x0e, 0xc0, 0x67, 0x58, 0xc8, 0x7b, 0x48, 0x65, 0x3a, - 0xf5, 0x1e, 0x52, 0x19, 0xa4, 0x6a, 0x57, 0xf2, 0x7d, 0x59, 0x29, 0x8b, 0xfc, 0x06, 0x49, 0x8e, 0x4b, 0x75, 0xb0, - 0x20, 0x32, 0x82, 0x76, 0xb5, 0x28, 0x37, 0xe3, 0x39, 0xc4, 0x14, 0x84, 0xc6, 0xcd, 0x37, 0xbd, 0x83, 0xef, 0x7b, - 0x93, 0xcf, 0x5c, 0xfe, 0xbd, 0xc9, 0xd7, 0x1d, 0x39, 0x8c, 0xaf, 0xdf, 0x76, 0x6a, 0xcb, 0x78, 0x61, 0xb1, 0xf6, - 0x43, 0xf9, 0x82, 0x4b, 0x4b, 0xbf, 0x94, 0x4d, 0xda, 0x78, 0xe2, 0x21, 0x65, 0xb3, 0xe2, 0xe1, 0x3a, 0xb8, 0xdd, - 0x3a, 0x0c, 0x79, 0x93, 0xb4, 0x11, 0x3a, 0xb4, 0xc2, 0x55, 0x1e, 0x6a, 0xc9, 0xe9, 0xf0, 0xf1, 0x11, 0xdc, 0xbd, - 0xcc, 0xf2, 0x0d, 0x5f, 0x29, 0x53, 0xad, 0xd9, 0x6e, 0x1d, 0xf2, 0x9d, 0x55, 0x1a, 0x6d, 0x3c, 0x63, 0x64, 0x09, - 0xce, 0x65, 0xb4, 0x30, 0xaa, 0x06, 0xf0, 0x21, 0x7d, 0x91, 0xff, 0xb6, 0xa0, 0xa9, 0xfe, 0x3e, 0x34, 0x29, 0xaf, - 0x17, 0xca, 0x25, 0x35, 0x39, 0x0c, 0xa2, 0x83, 0x6c, 0x49, 0x2f, 0x27, 0xe4, 0x47, 0x24, 0xea, 0xa2, 0xf3, 0x76, - 0x3f, 0xea, 0x1e, 0xf2, 0x43, 0x1e, 0x03, 0x0f, 0x1b, 0x36, 0x5d, 0x85, 0x66, 0xdb, 0xd5, 0xb9, 0x5a, 0x8c, 0x78, - 0x62, 0x9b, 0xaf, 0x3a, 0x28, 0x53, 0xcd, 0x1c, 0x21, 0x0b, 0x50, 0xcc, 0xf5, 0xe2, 0x65, 0xd7, 0xbb, 0x39, 0xe4, - 0x31, 0xf4, 0x03, 0xb5, 0x3a, 0xa6, 0x56, 0x39, 0xb8, 0xdf, 0x16, 0x80, 0x60, 0xae, 0xa3, 0xda, 0x5c, 0x4c, 0x7a, - 0x33, 0xac, 0x3a, 0x3b, 0xe4, 0xd5, 0x08, 0xfd, 0x32, 0xdb, 0xfd, 0xb9, 0xa9, 0x55, 0x5d, 0x1e, 0x7a, 0x10, 0xf9, - 0x6d, 0xc1, 0x73, 0xbf, 0x53, 0xbf, 0x5b, 0x9b, 0xe3, 0x77, 0x5a, 0x9f, 0xa5, 0x57, 0x64, 0xbb, 0xd7, 0xad, 0x99, - 0xd6, 0x67, 0x7b, 0x0d, 0x3e, 0x82, 0x30, 0x29, 0xbd, 0xd2, 0x89, 0x90, 0x21, 0x3f, 0xfc, 0x80, 0x6c, 0xeb, 0xaf, - 0x17, 0xca, 0xe5, 0x97, 0x88, 0x00, 0xd9, 0x55, 0xd7, 0x65, 0x75, 0xe8, 0xa3, 0x6c, 0xe2, 0xd5, 0x21, 0xf7, 0x56, - 0xee, 0xe9, 0xdd, 0x5c, 0xc4, 0x0e, 0x5f, 0xfb, 0xad, 0x78, 0x0b, 0x39, 0x81, 0x78, 0xd8, 0xee, 0xfc, 0xb2, 0x20, - 0x67, 0x37, 0xb7, 0x50, 0xd2, 0x9f, 0xb8, 0x2b, 0xfd, 0x81, 0x99, 0xeb, 0x06, 0x7e, 0x1e, 0x75, 0x61, 0xea, 0x9b, - 0x3d, 0x1c, 0x76, 0xa0, 0x0f, 0x0d, 0x87, 0xcd, 0x06, 0x5d, 0x66, 0x05, 0x91, 0x2b, 0x5e, 0x18, 0x3c, 0xbb, 0x20, - 0xed, 0x3e, 0x8f, 0xed, 0x66, 0xd2, 0xa2, 0x51, 0xbb, 0xc9, 0xbd, 0x99, 0x01, 0x7e, 0xd9, 0xb2, 0x7e, 0x11, 0xb7, - 0x4e, 0x1e, 0x94, 0x5c, 0xb1, 0x6a, 0x7d, 0x2a, 0x78, 0xd5, 0x1b, 0x8e, 0x37, 0xd3, 0xdd, 0xba, 0xc1, 0xed, 0xae, - 0x83, 0x27, 0xbc, 0xc0, 0x62, 0xd0, 0xda, 0x4d, 0x7c, 0x02, 0x1c, 0x50, 0xd4, 0x7a, 0xd8, 0x05, 0x17, 0xca, 0x12, - 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x0c, 0x1c, 0x4d, 0x49, 0x8f, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, 0xd8, 0xc1, - 0x51, 0xbb, 0xdd, 0xe9, 0xe2, 0xe8, 0xa4, 0x0b, 0x03, 0x6d, 0x44, 0xdd, 0xc3, 0x59, 0x6e, 0x00, 0xe8, 0xe5, 0xac, - 0x6d, 0xbb, 0x8f, 0x21, 0x5a, 0x93, 0x2f, 0x5e, 0xf3, 0xc3, 0x30, 0x6c, 0x47, 0x0f, 0x5b, 0xed, 0xee, 0x59, 0x03, - 0x00, 0xd4, 0xb4, 0x1f, 0xb6, 0xc6, 0xeb, 0x85, 0xaa, 0x57, 0x29, 0x11, 0xbe, 0x5e, 0xad, 0xe1, 0xaa, 0x35, 0xda, - 0xeb, 0x6a, 0x0a, 0xae, 0xaa, 0x15, 0xce, 0x4d, 0x11, 0xa7, 0xb4, 0xf1, 0xb7, 0x45, 0x68, 0x06, 0x12, 0x82, 0x74, - 0x1e, 0x75, 0x3b, 0x5d, 0x64, 0xc6, 0xa2, 0x2c, 0x7e, 0x94, 0xfb, 0x64, 0xab, 0x48, 0x43, 0x01, 0x92, 0x94, 0xb3, - 0x13, 0x0b, 0x90, 0xa8, 0x39, 0xb9, 0x68, 0x37, 0x67, 0x2c, 0x72, 0x13, 0xd0, 0xa9, 0xb0, 0x9c, 0xe5, 0x2a, 0xd8, - 0x24, 0x0f, 0x10, 0xe7, 0x60, 0x5c, 0xf4, 0xb0, 0xdb, 0x7f, 0x18, 0x75, 0x4f, 0x3b, 0x86, 0xe8, 0xf1, 0xf3, 0x4e, - 0x2d, 0x4d, 0x4f, 0x3d, 0xea, 0xea, 0x34, 0xe8, 0x3a, 0x7a, 0xd8, 0x85, 0x32, 0x36, 0xc5, 0x2f, 0x05, 0x51, 0x26, - 0xaa, 0x62, 0x10, 0x5a, 0x22, 0xae, 0xe5, 0x9e, 0xd6, 0xb2, 0xcf, 0x4e, 0x8e, 0x1f, 0x76, 0x7d, 0xa8, 0x95, 0xb3, - 0xd0, 0x0b, 0x6d, 0x27, 0xe2, 0x66, 0x07, 0x4b, 0x8b, 0x0e, 0xa3, 0x6e, 0xbc, 0x35, 0x41, 0xb3, 0x69, 0x0e, 0x35, - 0x0e, 0x78, 0x0a, 0xc7, 0x4b, 0x69, 0xf5, 0x25, 0xde, 0xfd, 0x58, 0x65, 0x68, 0xe2, 0x2b, 0x9c, 0xdd, 0x3d, 0xa5, - 0xf7, 0x90, 0xa4, 0x7f, 0x55, 0x79, 0x45, 0xf3, 0xaf, 0x54, 0xbe, 0xa1, 0x10, 0x3a, 0x23, 0x1f, 0x06, 0x36, 0xb0, - 0x77, 0x3d, 0xf7, 0x27, 0x70, 0x11, 0x66, 0x39, 0x5c, 0x68, 0x3a, 0x25, 0x68, 0xc5, 0x0b, 0x8c, 0x7c, 0x56, 0x57, - 0x0f, 0xab, 0xcf, 0x63, 0x6b, 0x52, 0xe0, 0xeb, 0xb6, 0x9e, 0xf3, 0xef, 0x95, 0x8b, 0xca, 0xab, 0xec, 0xa8, 0x8b, - 0x22, 0x7b, 0x59, 0x1e, 0xb5, 0x51, 0xe4, 0x99, 0x90, 0xd8, 0x23, 0x39, 0x49, 0xc8, 0x20, 0xb8, 0x0b, 0x70, 0x70, - 0x1f, 0xe0, 0xc0, 0xf8, 0x30, 0x7f, 0x00, 0x37, 0xf2, 0x00, 0x07, 0xc6, 0x95, 0x39, 0xc0, 0x81, 0x62, 0x39, 0x44, - 0xd4, 0x0a, 0x86, 0x38, 0x83, 0xd2, 0xda, 0xb3, 0xba, 0x2c, 0x7d, 0xe5, 0xbe, 0x4a, 0xd7, 0x6b, 0x93, 0xe2, 0x49, - 0x99, 0x53, 0xbd, 0x43, 0xcd, 0x8b, 0xd0, 0x01, 0x75, 0xcc, 0x7a, 0x80, 0x41, 0x00, 0xa1, 0xf7, 0xee, 0x45, 0xb9, - 0x2a, 0x18, 0x07, 0x3b, 0x86, 0x95, 0x06, 0x9f, 0xf3, 0xc0, 0x3f, 0xc3, 0x02, 0x3c, 0xce, 0x5d, 0x61, 0x10, 0x2b, - 0xdc, 0xef, 0x4c, 0x88, 0xb9, 0xfb, 0xad, 0x44, 0xf9, 0x0b, 0xde, 0x21, 0xb1, 0x16, 0x2d, 0x60, 0xb9, 0x65, 0x62, - 0xff, 0x8c, 0x58, 0x7d, 0x04, 0x37, 0x63, 0x1b, 0x9f, 0x0d, 0x24, 0xc2, 0x1b, 0x2d, 0x50, 0x39, 0xf9, 0xf0, 0xc6, - 0xc4, 0x0a, 0xd2, 0x9f, 0x10, 0x2c, 0x0c, 0xe2, 0x01, 0x0b, 0xb8, 0xd0, 0x98, 0x14, 0x4c, 0xca, 0xc0, 0x04, 0xd1, - 0x0b, 0x44, 0xee, 0x5e, 0x45, 0x74, 0x29, 0xe3, 0x3c, 0xd0, 0x1d, 0xd6, 0x67, 0x6b, 0xc4, 0xe1, 0x4c, 0x14, 0x32, - 0x36, 0x4f, 0xa4, 0x38, 0x30, 0xce, 0xcb, 0xf7, 0x07, 0xe3, 0x2c, 0x59, 0x63, 0x73, 0x87, 0x5d, 0x16, 0xb2, 0x57, - 0xda, 0x7e, 0xa9, 0x24, 0x59, 0x7f, 0x6b, 0x42, 0xb2, 0x36, 0x23, 0x6f, 0xa2, 0xd5, 0x80, 0xaa, 0x48, 0x1a, 0x50, - 0xd8, 0x44, 0x63, 0x89, 0x97, 0x65, 0xc9, 0x78, 0x59, 0x2e, 0xc3, 0x49, 0xab, 0xb5, 0x5e, 0xe3, 0x82, 0xe9, 0xa8, - 0x30, 0x3b, 0x4b, 0x40, 0xbe, 0x9c, 0x8a, 0x5b, 0x2f, 0x57, 0xc6, 0xe5, 0x2c, 0xf5, 0x12, 0x05, 0x9e, 0x11, 0x6c, - 0xb0, 0xc6, 0x5f, 0xb9, 0xe4, 0x00, 0x4f, 0x3b, 0xbb, 0x91, 0x10, 0x19, 0xa3, 0x10, 0x3c, 0xcc, 0x6b, 0x72, 0x8d, - 0xa7, 0x3c, 0x65, 0xbb, 0xdb, 0x04, 0x33, 0xe6, 0x7f, 0xaf, 0x45, 0x87, 0x40, 0x86, 0xdd, 0xd3, 0xa8, 0x03, 0x8b, - 0xb8, 0x82, 0x0e, 0x7c, 0x19, 0x3c, 0xf5, 0x71, 0x33, 0xa3, 0xf7, 0x62, 0xa1, 0x00, 0x2e, 0x0b, 0x25, 0xde, 0xd8, - 0xb8, 0x07, 0xfb, 0x2d, 0xec, 0x42, 0x20, 0x2c, 0x21, 0x64, 0x40, 0x0b, 0x9b, 0x10, 0x15, 0x2d, 0x3c, 0x12, 0x4a, - 0x89, 0x59, 0xdc, 0xc2, 0x3a, 0x5e, 0x44, 0x6b, 0x5d, 0x06, 0xf5, 0xba, 0xc9, 0xdd, 0x5b, 0x92, 0xd5, 0x26, 0x58, - 0x58, 0xe9, 0x50, 0x11, 0xe5, 0xdd, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbf, 0x7e, 0x65, 0x43, 0x36, 0xf3, 0x31, - 0xb8, 0x6c, 0x5a, 0xd5, 0xd8, 0x8d, 0x7e, 0x84, 0x29, 0xac, 0x14, 0xa5, 0x46, 0x38, 0x85, 0x96, 0x5f, 0xe4, 0x2a, - 0x8b, 0xcc, 0xe5, 0xc5, 0x33, 0x51, 0xcc, 0xa8, 0xb9, 0x31, 0xc2, 0x37, 0xb9, 0x7d, 0x75, 0x5d, 0x3f, 0xec, 0x52, - 0x4d, 0xf2, 0xdd, 0xe6, 0x55, 0xc4, 0x22, 0xd1, 0xf2, 0x2b, 0x68, 0x03, 0x74, 0xe5, 0xf2, 0xd1, 0xdc, 0x82, 0xd8, - 0xc0, 0xf7, 0x1e, 0x79, 0x79, 0x6b, 0xa8, 0x4b, 0x10, 0x34, 0xb8, 0xc6, 0x4f, 0x56, 0xf0, 0xc4, 0xbb, 0x2e, 0xd4, - 0xec, 0x91, 0x15, 0x2f, 0x82, 0x56, 0x50, 0x7f, 0x74, 0x56, 0xab, 0x12, 0x5c, 0xd0, 0xd4, 0x28, 0x13, 0x20, 0x7a, - 0x94, 0xef, 0xdb, 0x71, 0x10, 0x4d, 0xdc, 0xdd, 0xf3, 0x45, 0xdb, 0xd1, 0xd9, 0xac, 0x52, 0x27, 0x96, 0x57, 0x26, - 0xe0, 0xe1, 0x68, 0x5e, 0x90, 0x41, 0xd8, 0x4b, 0x64, 0xa5, 0xf6, 0xd0, 0xe5, 0xa2, 0x5e, 0x98, 0x9d, 0xb7, 0x59, - 0xf3, 0x64, 0xb5, 0xca, 0x2e, 0xda, 0xac, 0xdd, 0x35, 0xef, 0xcd, 0x05, 0x32, 0x01, 0x9a, 0xcb, 0xc7, 0x3c, 0x09, - 0x40, 0x3b, 0x3b, 0x4e, 0x74, 0x38, 0x05, 0x17, 0x21, 0x99, 0x2c, 0x54, 0xd5, 0x97, 0x00, 0xe3, 0x52, 0x62, 0xf4, - 0xf8, 0x05, 0xea, 0xb7, 0xe3, 0x6d, 0x57, 0xe9, 0x66, 0xfb, 0xd0, 0xbb, 0x70, 0x29, 0x10, 0xee, 0x40, 0xc8, 0x03, - 0xd0, 0xef, 0x2e, 0x73, 0x30, 0x0d, 0x02, 0x54, 0xce, 0x41, 0xa4, 0xe5, 0xb3, 0xc5, 0xec, 0x59, 0x41, 0xf5, 0x32, - 0x3c, 0xe1, 0x13, 0xae, 0x64, 0x4c, 0x41, 0xba, 0xdd, 0x95, 0xbe, 0xde, 0x2d, 0x41, 0x25, 0xb5, 0xc0, 0xb3, 0x91, - 0xe2, 0xc9, 0x17, 0x69, 0x17, 0x0e, 0x61, 0xbd, 0xb2, 0x12, 0x27, 0x68, 0x8d, 0x33, 0x31, 0xa1, 0x05, 0x57, 0xd3, - 0xd9, 0xbf, 0xb5, 0x3a, 0x6c, 0xa0, 0x86, 0xfa, 0xc2, 0x0a, 0x40, 0x42, 0xf3, 0x74, 0xb5, 0xe2, 0x47, 0xdf, 0xbf, - 0x4f, 0x72, 0x3e, 0xe1, 0x6d, 0xdc, 0xc1, 0xc7, 0xb8, 0x8b, 0xdb, 0x2d, 0xdc, 0xee, 0xc2, 0xd5, 0x7d, 0x92, 0x2d, - 0x52, 0x06, 0xf6, 0xb1, 0xab, 0x95, 0xba, 0x88, 0xce, 0x0e, 0xcb, 0x70, 0xfb, 0xaa, 0x88, 0x2c, 0xba, 0x78, 0x51, - 0xdf, 0x6d, 0xb8, 0xbc, 0x20, 0xf0, 0x63, 0xb5, 0x8d, 0x7d, 0xd5, 0x49, 0xa9, 0x5f, 0xb8, 0x38, 0xee, 0x83, 0x3d, - 0xb7, 0x59, 0xd9, 0x26, 0x98, 0x7d, 0x9b, 0x9f, 0x71, 0xf5, 0xb3, 0xa9, 0x4a, 0xc4, 0x70, 0xd0, 0xab, 0xd0, 0x03, - 0x5d, 0x90, 0xf6, 0xc1, 0x01, 0x58, 0x1d, 0x79, 0xb3, 0xe1, 0x26, 0xfa, 0x01, 0x6f, 0xd6, 0xd2, 0x20, 0x58, 0x01, - 0x18, 0x77, 0xbe, 0xe1, 0x64, 0x69, 0x60, 0xab, 0x80, 0x0a, 0xab, 0xc2, 0x0f, 0x28, 0xe7, 0x93, 0x0a, 0x2d, 0x44, - 0xc3, 0x11, 0x66, 0x23, 0x9d, 0xec, 0xb7, 0xb0, 0x18, 0x8f, 0x25, 0x53, 0x70, 0x74, 0x14, 0xec, 0x2b, 0x2b, 0xa4, - 0x3e, 0x45, 0x46, 0x6c, 0xc2, 0xf3, 0x4b, 0xf5, 0x89, 0x15, 0x42, 0x7f, 0x6a, 0x0d, 0x46, 0x1c, 0xe8, 0x55, 0x0c, - 0x70, 0x92, 0xf1, 0x39, 0x54, 0x9d, 0x14, 0xe0, 0xf4, 0x03, 0x7f, 0x79, 0x1a, 0xfb, 0x6d, 0x02, 0xf9, 0xfa, 0x60, - 0xc2, 0xba, 0xe0, 0xb4, 0xa0, 0xb7, 0xaf, 0xf3, 0x2b, 0xd8, 0x51, 0x97, 0x05, 0xa3, 0x90, 0x0d, 0x49, 0xef, 0xa0, - 0x29, 0xf8, 0x80, 0x36, 0x5f, 0x6a, 0xc0, 0xc5, 0x67, 0xfa, 0xc3, 0x54, 0x74, 0x41, 0x0b, 0xa3, 0xb2, 0x2d, 0x9d, - 0xa9, 0x4f, 0xe9, 0x2a, 0xd3, 0x84, 0x85, 0x2a, 0xa7, 0xb0, 0xc6, 0x36, 0xea, 0x89, 0x3f, 0x98, 0x94, 0xca, 0x69, - 0x3c, 0x18, 0xea, 0xbf, 0xaf, 0x4d, 0xc9, 0x16, 0xb6, 0x41, 0x67, 0xd6, 0x58, 0xbf, 0x18, 0xea, 0x95, 0x6f, 0x63, - 0xb8, 0x87, 0x85, 0x67, 0x2b, 0x6b, 0xe4, 0xf3, 0xc4, 0x91, 0xcd, 0x93, 0xf5, 0x5a, 0x0f, 0x44, 0xc6, 0xa0, 0x07, - 0x7a, 0xeb, 0xb6, 0x4d, 0x0b, 0xb6, 0x47, 0xf9, 0xd5, 0x6d, 0xe1, 0x19, 0x87, 0x57, 0x38, 0x5d, 0x7b, 0xd7, 0xaa, - 0x10, 0x5f, 0x2c, 0x48, 0x5a, 0x5e, 0x8a, 0x99, 0x8e, 0xd7, 0xd9, 0x31, 0xf6, 0x46, 0x0e, 0xf4, 0xfc, 0xfa, 0x8b, - 0x81, 0xb5, 0xfb, 0xfd, 0xa6, 0x2c, 0x98, 0xd1, 0x11, 0xcb, 0xca, 0x09, 0x25, 0xee, 0xfc, 0x7c, 0xc3, 0xa3, 0x0a, - 0x15, 0xec, 0xf3, 0x55, 0xb0, 0xa7, 0x4d, 0x84, 0xcb, 0x19, 0xfd, 0xcb, 0xfc, 0x30, 0x81, 0x75, 0x4a, 0x2d, 0x5b, - 0x52, 0x08, 0x29, 0x2f, 0x4d, 0x9a, 0x39, 0x7a, 0xe0, 0x88, 0x7c, 0x09, 0x5d, 0x00, 0xaf, 0x9f, 0x16, 0x62, 0xae, - 0x11, 0xc1, 0xfe, 0xb6, 0xe3, 0xd6, 0xbe, 0x02, 0xe0, 0xed, 0xb0, 0x57, 0xfd, 0xd3, 0x02, 0xf6, 0x37, 0x28, 0x4b, - 0xba, 0xf1, 0x76, 0xcc, 0xf1, 0x5f, 0x08, 0x08, 0x97, 0x6e, 0xf0, 0x30, 0xb2, 0xe8, 0x54, 0xb2, 0x66, 0xe5, 0xcf, - 0xad, 0x92, 0x80, 0x61, 0xf5, 0x82, 0x3e, 0x1b, 0xb7, 0x55, 0xdc, 0x64, 0xfe, 0x07, 0x15, 0x34, 0x16, 0x7c, 0x6b, - 0x24, 0x15, 0xcb, 0xe2, 0xb6, 0x4f, 0x9d, 0xff, 0xaa, 0x73, 0x5c, 0xfb, 0xaa, 0xf6, 0x44, 0xe6, 0x48, 0x87, 0x27, - 0x0e, 0xd0, 0xc1, 0xc1, 0x46, 0x06, 0x1d, 0x03, 0xe0, 0x91, 0x65, 0xbf, 0xdc, 0xf2, 0x39, 0x76, 0x4c, 0x6b, 0x1e, - 0x8b, 0xc0, 0x67, 0xee, 0x1c, 0x37, 0x67, 0x26, 0xf2, 0x84, 0xca, 0xa9, 0x2b, 0x0c, 0x70, 0x7c, 0xbc, 0x95, 0x0a, - 0xf8, 0x1e, 0xac, 0x77, 0x4c, 0x60, 0x83, 0xdf, 0x32, 0x93, 0xda, 0x55, 0xd0, 0x2d, 0xd0, 0x72, 0x17, 0x53, 0xb9, - 0xb1, 0xc0, 0xc1, 0xe6, 0x44, 0x76, 0x0e, 0x7d, 0xa3, 0x4e, 0xc9, 0x7a, 0x3c, 0xd9, 0x6d, 0xf4, 0x95, 0xcb, 0x5d, - 0xc9, 0x15, 0x6d, 0x1b, 0xb1, 0xea, 0x99, 0x5c, 0x55, 0x99, 0x3a, 0x55, 0xd7, 0xbc, 0x95, 0xa5, 0x4d, 0x69, 0x97, - 0x64, 0xee, 0xb6, 0x98, 0x7f, 0x15, 0xde, 0x68, 0x94, 0x17, 0xa1, 0x60, 0x8f, 0x25, 0x87, 0x3d, 0x4e, 0xe0, 0x7a, - 0x61, 0xb5, 0x0a, 0xe1, 0xcf, 0xae, 0x31, 0xec, 0x32, 0x5d, 0xfa, 0xc0, 0x37, 0xf8, 0x15, 0x2f, 0x52, 0xaf, 0xb5, - 0x83, 0x04, 0xeb, 0x2e, 0x3b, 0x68, 0x38, 0x4e, 0xdc, 0x17, 0xbc, 0x13, 0xad, 0x9c, 0xcb, 0xc1, 0x24, 0xf9, 0xc6, - 0xdb, 0x72, 0x25, 0x6b, 0x59, 0x0b, 0xf3, 0xbe, 0x21, 0xc1, 0x10, 0xb3, 0x29, 0xad, 0xe3, 0x56, 0xd4, 0x46, 0x81, - 0x2d, 0x56, 0xa1, 0xff, 0xb7, 0x8a, 0x24, 0x26, 0xf3, 0xbf, 0x4e, 0x4f, 0x4f, 0x6d, 0x8a, 0xb5, 0xf9, 0x93, 0xda, - 0x03, 0x4e, 0x27, 0xb0, 0xaf, 0x3c, 0x61, 0x5a, 0x87, 0xfc, 0x16, 0x86, 0x42, 0x24, 0xb9, 0x70, 0xec, 0x12, 0x44, - 0xe5, 0x02, 0xca, 0x03, 0xec, 0xdf, 0x93, 0x8d, 0x72, 0xee, 0x9d, 0x24, 0x17, 0x47, 0xb8, 0x6c, 0x90, 0x7d, 0xd5, - 0x9f, 0x03, 0x63, 0x26, 0x03, 0x4f, 0x03, 0x04, 0xd8, 0xfc, 0xd6, 0x2c, 0xad, 0xb5, 0x94, 0xc1, 0x81, 0x12, 0x8b, - 0x64, 0x6a, 0x34, 0xff, 0xf6, 0x43, 0x97, 0xb5, 0x6f, 0xec, 0x40, 0x50, 0x2e, 0xb2, 0xb4, 0xe1, 0x30, 0x83, 0x1f, - 0xcb, 0xc8, 0x97, 0x7b, 0xaf, 0xd8, 0x82, 0xfd, 0x88, 0xf7, 0xaa, 0x14, 0xf8, 0xb8, 0x2c, 0x38, 0xcd, 0x7e, 0xc4, - 0x7b, 0x55, 0x04, 0x4c, 0x70, 0x85, 0xd4, 0x41, 0x24, 0xb1, 0x7e, 0x4f, 0x3a, 0x0e, 0x72, 0xa0, 0xa0, 0x59, 0xa0, - 0x0f, 0xb2, 0xe7, 0x36, 0x68, 0x62, 0xd4, 0xc1, 0x36, 0xee, 0x97, 0x09, 0x85, 0x6a, 0x22, 0x88, 0x43, 0x20, 0xb9, - 0x72, 0x36, 0xfa, 0xeb, 0xf1, 0xc6, 0x82, 0x68, 0x65, 0x32, 0xb9, 0x78, 0xce, 0xc3, 0x7c, 0x73, 0xb1, 0x90, 0x5f, - 0xcd, 0x5b, 0xa0, 0x5a, 0x95, 0x2a, 0xdd, 0x2f, 0xbe, 0x5d, 0x30, 0xf1, 0x8a, 0xe8, 0xad, 0x77, 0x79, 0x07, 0xcf, - 0x9d, 0xdf, 0x05, 0x2e, 0x09, 0x9e, 0x04, 0xd7, 0x98, 0xea, 0x5e, 0x80, 0x07, 0x42, 0xcf, 0xa4, 0x0a, 0xb0, 0xce, - 0x93, 0x10, 0x49, 0x6c, 0xbf, 0x85, 0x2d, 0x6b, 0xf4, 0x22, 0x77, 0x42, 0x0a, 0x9c, 0xab, 0xba, 0x89, 0x19, 0xe5, - 0x3a, 0xba, 0xd8, 0xa5, 0x9c, 0xb3, 0x44, 0x19, 0x04, 0xd8, 0xb7, 0x68, 0x28, 0xf2, 0xe7, 0x1a, 0x14, 0xfa, 0x2d, - 0x6b, 0x9b, 0x72, 0x05, 0x8b, 0xe7, 0xa5, 0x00, 0x51, 0xe3, 0xf9, 0xa4, 0xac, 0x33, 0xcf, 0x16, 0x13, 0x9e, 0x57, - 0xc8, 0x50, 0x30, 0x39, 0x17, 0x39, 0x3c, 0x25, 0x51, 0x16, 0xd1, 0x74, 0xa8, 0x86, 0xef, 0x86, 0x84, 0x95, 0x75, - 0xf4, 0x31, 0xc5, 0xf3, 0xaa, 0x06, 0x30, 0x17, 0x97, 0xfe, 0x9b, 0xf3, 0xf2, 0x75, 0xfe, 0x4e, 0xcc, 0xab, 0x7c, - 0x47, 0xe3, 0x5c, 0xc4, 0x76, 0x6b, 0x37, 0x8c, 0xd6, 0xfa, 0xb5, 0x27, 0x6f, 0xfb, 0x7e, 0xe0, 0xd5, 0x0b, 0x68, - 0x6b, 0xfd, 0x5e, 0x54, 0x99, 0x35, 0x62, 0xe5, 0xe3, 0x08, 0x55, 0x7b, 0xf5, 0xaa, 0xb9, 0xad, 0x08, 0x50, 0x29, - 0x78, 0xba, 0x95, 0xff, 0x44, 0x99, 0x7c, 0x73, 0x0e, 0x95, 0xe1, 0x81, 0x1c, 0x19, 0xaa, 0x7a, 0xc0, 0x45, 0xf9, - 0xa1, 0x9f, 0xbe, 0x0a, 0x74, 0xe0, 0xdc, 0x5d, 0x17, 0xc8, 0x9c, 0xc9, 0x50, 0xe0, 0xe5, 0x80, 0x0e, 0x63, 0x23, - 0x0f, 0xc5, 0x02, 0x6c, 0x7b, 0x6e, 0x0b, 0xae, 0x5c, 0x84, 0x5e, 0x3c, 0x60, 0xc3, 0x78, 0x59, 0x8f, 0xe2, 0x6b, - 0xe2, 0x08, 0x3b, 0x73, 0x4e, 0x1d, 0xf6, 0x96, 0x0e, 0x71, 0x46, 0xc0, 0xf6, 0xd8, 0xb1, 0xa7, 0x6f, 0xc2, 0x04, - 0xf5, 0xeb, 0x1c, 0xfe, 0x72, 0x8d, 0x33, 0x9c, 0xa0, 0xf8, 0x32, 0x84, 0x0b, 0xac, 0x35, 0x06, 0xf0, 0x25, 0x86, - 0x54, 0x81, 0x47, 0x6a, 0xa2, 0x25, 0x56, 0x7b, 0x11, 0x88, 0x96, 0xca, 0xbf, 0x1d, 0x67, 0x2e, 0x0e, 0xb6, 0xe6, - 0x5e, 0x9f, 0x69, 0xe1, 0x70, 0x92, 0x84, 0xb5, 0x73, 0x86, 0x93, 0x8b, 0x7d, 0x5e, 0x3b, 0x31, 0xc1, 0xda, 0xdb, - 0x3f, 0x55, 0x40, 0x8f, 0x06, 0xa7, 0x8a, 0xa1, 0x21, 0x10, 0x33, 0x01, 0xbc, 0x99, 0xfd, 0xa3, 0xcd, 0xc3, 0xf9, - 0x60, 0x8d, 0xbd, 0xaf, 0xb8, 0xd6, 0xd5, 0xa6, 0x12, 0x65, 0xbd, 0xc6, 0x83, 0x69, 0x82, 0xd3, 0x04, 0xcf, 0x93, - 0xa1, 0x77, 0xdc, 0xcc, 0x12, 0xdf, 0xa4, 0x6b, 0xb5, 0x7a, 0x6a, 0xcd, 0x08, 0x91, 0xf9, 0x69, 0xe8, 0x0f, 0xea, - 0x03, 0xc2, 0xc7, 0x90, 0x05, 0xb4, 0xa4, 0x6f, 0xff, 0x36, 0xcc, 0x33, 0xd9, 0xa8, 0x11, 0xf2, 0xc8, 0x90, 0x91, - 0xbe, 0xfb, 0x51, 0x66, 0x99, 0xd6, 0x1a, 0xc1, 0xfc, 0x6e, 0x2f, 0x68, 0xb8, 0xf6, 0x3c, 0x2d, 0x5b, 0x69, 0xb6, - 0x03, 0x88, 0x62, 0x8c, 0x93, 0x94, 0xb7, 0x46, 0x62, 0xb5, 0x0a, 0x4d, 0x0a, 0xe1, 0xd1, 0x8c, 0x51, 0xb9, 0x28, - 0xf4, 0xcb, 0x71, 0x61, 0x8e, 0x22, 0xcd, 0xef, 0x62, 0x6b, 0x23, 0x9a, 0x83, 0xdb, 0x23, 0x18, 0x6e, 0x84, 0x92, - 0x88, 0x9a, 0xc8, 0x3d, 0x4a, 0x2a, 0xcb, 0x20, 0x49, 0xa4, 0x16, 0xf9, 0xcd, 0x75, 0xa9, 0x39, 0x0c, 0xec, 0x1f, - 0xed, 0x0b, 0x08, 0x37, 0x6f, 0x13, 0x5a, 0x8c, 0xe8, 0x04, 0xd8, 0x58, 0x88, 0x43, 0xb8, 0x95, 0xb0, 0x5a, 0x0d, - 0x86, 0x3d, 0x43, 0x9e, 0xed, 0xcb, 0x79, 0x65, 0x43, 0xbb, 0x1b, 0x80, 0xab, 0x6e, 0x43, 0xcd, 0x95, 0xd6, 0xfd, - 0x50, 0xfd, 0xb8, 0x17, 0xb7, 0x49, 0xf6, 0x7d, 0x8e, 0xea, 0x09, 0xee, 0x9a, 0x05, 0xb8, 0x0e, 0x5d, 0x85, 0x53, - 0xbc, 0x30, 0x36, 0x9c, 0xfa, 0x25, 0x27, 0xaa, 0x1f, 0x70, 0x82, 0x77, 0xa3, 0x09, 0x1b, 0x24, 0x43, 0x9c, 0xba, - 0x38, 0xdf, 0xfb, 0x6f, 0xc3, 0x14, 0xa1, 0x82, 0x68, 0x98, 0x1a, 0x97, 0xed, 0xb4, 0xb2, 0xdb, 0xd7, 0x99, 0x9a, - 0x61, 0xd0, 0x46, 0xcc, 0xa9, 0x6f, 0xc4, 0x9c, 0x35, 0x1a, 0x68, 0x41, 0x52, 0x30, 0x62, 0x5e, 0x78, 0xad, 0x2d, - 0xcc, 0x2b, 0x9f, 0x5e, 0x7b, 0x0b, 0x84, 0x7a, 0x1c, 0x68, 0x9a, 0x82, 0xf7, 0x3c, 0xaa, 0xf7, 0xd4, 0xdd, 0xeb, - 0x52, 0x47, 0x1d, 0x50, 0x24, 0x8c, 0x2f, 0xdc, 0x24, 0x8c, 0x6b, 0xb8, 0x19, 0xf7, 0x58, 0x8f, 0xdb, 0xda, 0x36, - 0xe4, 0x03, 0x31, 0x48, 0x86, 0xc3, 0x9e, 0x70, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x5e, 0x00, 0xa9, 0x16, 0xef, 0xab, - 0xda, 0xbc, 0xf2, 0xe6, 0xee, 0x61, 0xd1, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, 0x1f, 0xaa, 0xe2, 0x83, 0x1d, - 0x75, 0x20, 0x0a, 0x5a, 0xdc, 0xaa, 0x09, 0xa4, 0xc6, 0xcc, 0x2e, 0x54, 0xcd, 0x1c, 0x1d, 0x4a, 0x08, 0x43, 0x96, - 0x57, 0xdd, 0xdd, 0xe7, 0x9e, 0x6a, 0x88, 0xc3, 0xa9, 0x7f, 0x65, 0x8c, 0x58, 0xc3, 0xa0, 0x93, 0x06, 0xda, 0x48, - 0xd2, 0x2c, 0x1f, 0x3c, 0xfa, 0x03, 0x56, 0x02, 0x2e, 0xf8, 0xb2, 0x4e, 0xd2, 0x86, 0x04, 0x6f, 0x59, 0xa2, 0x34, - 0x1f, 0xc2, 0x2d, 0x82, 0xf2, 0xc8, 0xc4, 0xda, 0xb4, 0x95, 0x0c, 0xe4, 0xaa, 0x2e, 0x6f, 0x3c, 0xf4, 0xbc, 0x4f, - 0xaa, 0xdd, 0x00, 0x1c, 0x99, 0x37, 0xb0, 0x64, 0x6b, 0x9f, 0x80, 0x47, 0x3e, 0xae, 0x10, 0xc4, 0x2d, 0x85, 0x8a, - 0x74, 0xa0, 0xea, 0x6b, 0xd8, 0xa0, 0x78, 0x0e, 0x0e, 0x82, 0x56, 0x82, 0xc3, 0xe0, 0x5d, 0x66, 0x34, 0xc9, 0x1a, - 0xb7, 0x66, 0x24, 0x9c, 0xaf, 0x56, 0x2d, 0x74, 0xf8, 0xb7, 0x7e, 0x8b, 0x79, 0x5c, 0x2a, 0xdc, 0xc7, 0x95, 0xc2, - 0x1d, 0x2c, 0x01, 0xc9, 0xd8, 0xd3, 0xb5, 0x63, 0xe1, 0xab, 0xd1, 0x21, 0x4c, 0xf8, 0x0b, 0x08, 0x1a, 0x6d, 0x8f, - 0x25, 0xd0, 0xb3, 0x6f, 0x15, 0x30, 0xba, 0xf6, 0xb2, 0x04, 0xd2, 0x82, 0xbb, 0xdb, 0x04, 0x5a, 0x85, 0xa8, 0x7d, - 0xfe, 0xf4, 0x73, 0x0e, 0x3c, 0xb2, 0xfe, 0x5c, 0x33, 0xcd, 0xba, 0x17, 0xf4, 0x56, 0x37, 0x1f, 0x8e, 0x71, 0x73, - 0x6c, 0xc0, 0x79, 0xd4, 0x81, 0x9f, 0x06, 0xa2, 0x47, 0x1d, 0x6c, 0x53, 0xf1, 0xb8, 0x04, 0xb2, 0x8f, 0x9e, 0xd6, - 0x40, 0x0a, 0x58, 0xe9, 0xd0, 0x68, 0x91, 0x26, 0x68, 0xb5, 0x9a, 0x9c, 0x93, 0x16, 0x42, 0x4b, 0x79, 0xcb, 0x55, - 0x32, 0x05, 0x1f, 0x69, 0x50, 0x0c, 0xbc, 0xa1, 0x6a, 0x1a, 0x22, 0x3c, 0x46, 0xcb, 0x94, 0x8d, 0xe9, 0x22, 0x53, - 0x71, 0xde, 0xe7, 0x91, 0x89, 0xa4, 0xcb, 0x4c, 0x24, 0xb8, 0xa3, 0x0e, 0x9e, 0x68, 0xfe, 0xf2, 0xb1, 0x36, 0x07, - 0x29, 0x12, 0x9d, 0x3c, 0xd1, 0x09, 0x98, 0x47, 0x49, 0x26, 0x24, 0x33, 0xcd, 0xf4, 0x8c, 0x6d, 0x39, 0xc4, 0xe2, - 0x0e, 0x54, 0xc1, 0xb5, 0x15, 0x65, 0x10, 0x4f, 0x49, 0xde, 0xcf, 0x8f, 0x3a, 0xf1, 0x04, 0xf3, 0x08, 0x38, 0xbd, - 0x77, 0x22, 0x64, 0x8d, 0xf2, 0x56, 0x74, 0x86, 0x0e, 0xa7, 0x58, 0x56, 0x97, 0xa8, 0x33, 0x74, 0x38, 0x41, 0x78, - 0xd6, 0x20, 0x59, 0x0e, 0x1e, 0xc3, 0x3c, 0xff, 0x3f, 0x52, 0xfe, 0x9b, 0xc3, 0x86, 0x98, 0xcf, 0x6f, 0x61, 0xa7, - 0xb0, 0x34, 0x88, 0x33, 0x02, 0x5e, 0x8b, 0xed, 0x53, 0x9c, 0x90, 0x49, 0x33, 0x73, 0x01, 0xf7, 0x74, 0x2b, 0x8d, - 0x3b, 0x85, 0x0e, 0x13, 0x9c, 0x6e, 0x26, 0x85, 0x7a, 0xae, 0xcd, 0x2c, 0x4e, 0xe0, 0x7c, 0xaf, 0x46, 0x61, 0xcb, - 0x2f, 0x36, 0x93, 0xfc, 0xf2, 0x16, 0xb8, 0xcd, 0x14, 0xcb, 0x26, 0xc5, 0x19, 0x9e, 0x35, 0x5f, 0xe1, 0x59, 0xf3, - 0x43, 0x99, 0xd1, 0x58, 0x60, 0x09, 0xc1, 0xfb, 0x20, 0x11, 0xcf, 0xaa, 0xe4, 0x14, 0xcb, 0x86, 0x2e, 0x8f, 0x67, - 0x8d, 0xaa, 0x74, 0x73, 0x81, 0x65, 0x43, 0x97, 0x6e, 0x7c, 0xc0, 0xb3, 0xc6, 0xab, 0x7f, 0x31, 0xe9, 0x20, 0x06, - 0x74, 0x99, 0xa3, 0x65, 0x62, 0x86, 0x78, 0xfd, 0xdb, 0xdb, 0x77, 0xed, 0x9b, 0xce, 0xe1, 0x04, 0xbb, 0xf5, 0x4b, - 0x34, 0x8e, 0x25, 0x2a, 0x64, 0x4d, 0x80, 0x68, 0x82, 0x3b, 0x87, 0x53, 0xdc, 0x39, 0x4c, 0x6c, 0x53, 0xeb, 0x59, - 0x83, 0xdc, 0x29, 0x1f, 0x8a, 0x2a, 0x88, 0x7d, 0xf8, 0xb8, 0xc9, 0xc6, 0x13, 0x54, 0x03, 0x25, 0x3a, 0x9c, 0xd4, - 0x40, 0x05, 0xdf, 0x8b, 0xda, 0x77, 0x55, 0xaf, 0xc2, 0x20, 0x03, 0x25, 0xe4, 0xaf, 0xb9, 0x06, 0x4f, 0x2d, 0x45, - 0x43, 0xc6, 0x4f, 0x31, 0x40, 0xf9, 0x0e, 0x28, 0xb4, 0xf2, 0x44, 0x0f, 0xdd, 0x9b, 0x8e, 0x4e, 0xfc, 0xff, 0x79, - 0x32, 0xe5, 0xd0, 0xcb, 0x2d, 0xb3, 0x35, 0x3d, 0x3b, 0x19, 0x7f, 0xf8, 0xc0, 0x63, 0xfd, 0x5f, 0x3b, 0x50, 0xac, - 0x41, 0x8a, 0xff, 0x2f, 0x1d, 0x9d, 0x0f, 0x46, 0xc8, 0x0a, 0xe2, 0xc2, 0x22, 0xfe, 0xf7, 0x87, 0xe5, 0x75, 0x5f, - 0x6c, 0x75, 0x5f, 0xe8, 0xee, 0xfd, 0xa6, 0xb5, 0x2a, 0x27, 0xae, 0x2a, 0x19, 0xf2, 0x5f, 0xa7, 0x5b, 0x5b, 0xa0, - 0x91, 0x35, 0x7a, 0x36, 0xf1, 0x1b, 0xdc, 0x6f, 0xc7, 0x3b, 0x90, 0x79, 0xcd, 0xcd, 0xd3, 0xa0, 0x70, 0xf8, 0x7a, - 0x77, 0xaa, 0x17, 0x2d, 0xf0, 0xde, 0x94, 0x5a, 0x5f, 0x19, 0xfa, 0x96, 0x83, 0xc5, 0xa6, 0x29, 0xb7, 0x36, 0x96, - 0x8e, 0xba, 0x58, 0xbb, 0x22, 0x42, 0xa5, 0xbb, 0x0b, 0x50, 0x8a, 0x8f, 0x55, 0x93, 0xe9, 0xaf, 0x73, 0x15, 0xe9, - 0x4b, 0xa8, 0x86, 0xfe, 0xbc, 0xbf, 0x50, 0x91, 0x12, 0x73, 0x93, 0x77, 0x7f, 0x0e, 0x7d, 0x82, 0x86, 0xb5, 0xe1, - 0xd9, 0xed, 0xb3, 0xc2, 0xea, 0x77, 0xaa, 0x43, 0xd0, 0x3f, 0x80, 0x2c, 0x69, 0x31, 0x7d, 0x60, 0xdd, 0x1a, 0xb6, - 0x5d, 0x34, 0xcb, 0x44, 0xd3, 0x6a, 0x53, 0xe7, 0x9a, 0x3d, 0xcc, 0xe7, 0x3e, 0x4f, 0xc1, 0x0b, 0xa3, 0x1f, 0xdf, - 0xc1, 0x6e, 0xdc, 0xd5, 0x18, 0x89, 0xba, 0x92, 0xa9, 0x84, 0x7e, 0x74, 0x87, 0x59, 0x74, 0xaf, 0xbd, 0x18, 0x73, - 0xed, 0xef, 0xa3, 0x03, 0xe5, 0x07, 0x95, 0x24, 0x07, 0x96, 0xfd, 0x0d, 0x16, 0xdd, 0x81, 0x79, 0x62, 0x59, 0x4d, - 0x60, 0x15, 0xdd, 0x7b, 0x8b, 0x28, 0x74, 0x23, 0x6b, 0xcd, 0x80, 0xea, 0x66, 0x8c, 0x7a, 0x70, 0x1f, 0x02, 0x3d, - 0xf4, 0xcb, 0x52, 0xca, 0x76, 0x16, 0xd7, 0xba, 0x57, 0xba, 0xfb, 0xcd, 0x01, 0x79, 0x7c, 0xa1, 0xc7, 0x35, 0xfd, - 0xab, 0x49, 0x44, 0x23, 0xf6, 0x0f, 0x67, 0xc5, 0xd5, 0xa2, 0xd0, 0x98, 0x26, 0xfb, 0x2a, 0x4a, 0xe6, 0x6d, 0x30, - 0xd5, 0x4b, 0xe6, 0x9d, 0x3b, 0x6c, 0xbf, 0xef, 0xcd, 0xf7, 0x3d, 0x96, 0x7d, 0xa6, 0x33, 0x62, 0xa6, 0x8b, 0xb9, - 0xef, 0x7b, 0xf3, 0x7d, 0x8f, 0xb7, 0x07, 0x73, 0xeb, 0x2e, 0x14, 0x4b, 0x76, 0x86, 0x0b, 0x30, 0x2c, 0xf7, 0xb8, - 0x9b, 0x5a, 0x96, 0x0e, 0x02, 0x5b, 0x4b, 0x80, 0x38, 0x9f, 0x4f, 0xc3, 0x8a, 0x57, 0x43, 0xc0, 0x7d, 0x3a, 0xd7, - 0xf6, 0x2a, 0x15, 0x78, 0x4c, 0xd0, 0x88, 0xe8, 0xd8, 0x36, 0xfa, 0x59, 0x2f, 0xe0, 0xf2, 0x88, 0x2a, 0xf5, 0x24, - 0x11, 0xf0, 0xaa, 0x5a, 0xe5, 0xad, 0x8b, 0x94, 0x5f, 0xc4, 0xcb, 0x71, 0xc5, 0x1e, 0x53, 0xc9, 0x00, 0x56, 0x65, - 0x49, 0x97, 0x40, 0xea, 0xf9, 0xde, 0x44, 0xbf, 0x6c, 0x22, 0x4f, 0xae, 0x6f, 0x4b, 0xbf, 0x30, 0x35, 0x2d, 0xc4, - 0x62, 0x32, 0x05, 0x1f, 0x5a, 0x60, 0x19, 0x0a, 0x5d, 0xaf, 0xb2, 0xf5, 0xaf, 0x49, 0x6e, 0x12, 0x28, 0x9c, 0x6a, - 0x8a, 0x88, 0x26, 0x6a, 0x41, 0x33, 0x6d, 0x49, 0xca, 0xf3, 0xc9, 0x63, 0x71, 0xf7, 0x12, 0xb0, 0x9b, 0x12, 0xd5, - 0xd8, 0x91, 0xf7, 0x16, 0x76, 0x00, 0x4e, 0x08, 0xdb, 0x55, 0xf1, 0x52, 0x82, 0xce, 0x1f, 0x67, 0x84, 0xed, 0xaa, - 0xfa, 0x84, 0x99, 0xec, 0x29, 0xd9, 0x18, 0x6e, 0x3f, 0x4c, 0x1a, 0x19, 0x3a, 0xea, 0xc4, 0x59, 0xcf, 0x11, 0x03, - 0x03, 0x50, 0x0f, 0xb8, 0x5b, 0xdb, 0xb3, 0xbc, 0xbb, 0x21, 0x79, 0x94, 0xb2, 0x44, 0x98, 0xeb, 0x72, 0x9d, 0xb2, - 0x5a, 0x75, 0x2a, 0x2a, 0x58, 0xe0, 0xa9, 0xb7, 0x17, 0xa8, 0xf9, 0xda, 0x41, 0x71, 0xae, 0x93, 0x4d, 0xd3, 0xf3, - 0xb2, 0xef, 0xde, 0x8e, 0x45, 0xc6, 0x26, 0xed, 0xed, 0x0e, 0x22, 0x61, 0x38, 0x61, 0xe5, 0x71, 0xc2, 0x55, 0x6d, - 0x8f, 0x00, 0xdd, 0x78, 0x22, 0x37, 0x16, 0x64, 0xb9, 0xae, 0x8c, 0xee, 0x3d, 0xbf, 0x5b, 0x4a, 0x84, 0x1d, 0x6d, - 0x49, 0x30, 0x5d, 0x82, 0x56, 0xd3, 0xe9, 0x37, 0x99, 0x6b, 0xcf, 0x0d, 0x6f, 0x8a, 0xb6, 0xb9, 0xbd, 0x49, 0xc7, - 0x7a, 0x7b, 0xe8, 0x18, 0xca, 0x20, 0x06, 0x3a, 0x1f, 0xf1, 0x5e, 0xa3, 0x91, 0x20, 0x50, 0xc8, 0x24, 0x43, 0x2c, - 0x22, 0xa7, 0x45, 0x3f, 0x38, 0xd0, 0xf0, 0xa8, 0x12, 0x10, 0xa6, 0x20, 0x84, 0xf8, 0x5d, 0x6b, 0x84, 0xf5, 0x97, - 0xab, 0x96, 0x0b, 0x1b, 0xa9, 0x36, 0x74, 0xf0, 0xff, 0xf2, 0x97, 0xad, 0x9e, 0x59, 0x2e, 0x8a, 0xc6, 0xcd, 0x4c, - 0x83, 0x45, 0x80, 0xf4, 0x68, 0xb2, 0x1d, 0x14, 0x77, 0xe7, 0x62, 0xbd, 0x21, 0x20, 0x31, 0x83, 0x09, 0xca, 0x86, - 0x75, 0x63, 0x0c, 0xf3, 0xa8, 0xd2, 0xb2, 0xd6, 0x24, 0x66, 0xcf, 0x97, 0xce, 0x5f, 0xf7, 0xe5, 0x5d, 0xcc, 0xf0, - 0x7d, 0x2c, 0xf1, 0x2d, 0x78, 0xd2, 0xc4, 0x02, 0xdb, 0xc7, 0x0b, 0x8a, 0x35, 0x51, 0x3d, 0xc7, 0xde, 0x16, 0xb0, - 0xce, 0x7a, 0x8f, 0x48, 0xef, 0x77, 0xf5, 0xab, 0x0d, 0xbe, 0x5b, 0xf8, 0x15, 0x58, 0x3f, 0x7b, 0x27, 0x29, 0x96, - 0x0d, 0xd1, 0x2c, 0xec, 0x91, 0x01, 0xe5, 0x2a, 0x7e, 0xd9, 0x4f, 0xdd, 0x2a, 0x86, 0x6b, 0x1f, 0xaf, 0xf0, 0x87, - 0x8d, 0x76, 0x1b, 0x79, 0x59, 0xdc, 0xec, 0x4d, 0xd9, 0x10, 0x55, 0xd3, 0x3b, 0x32, 0x37, 0x52, 0xea, 0x5f, 0x1f, - 0x70, 0x6b, 0xab, 0x7d, 0x37, 0xcd, 0xb7, 0x0e, 0x9d, 0xab, 0xa6, 0x5d, 0x6a, 0xad, 0x08, 0xf6, 0x7e, 0xb6, 0x70, - 0x73, 0x6b, 0xc0, 0x1e, 0xfc, 0xdc, 0x1d, 0xcd, 0x55, 0x02, 0xd1, 0xe9, 0x8d, 0x66, 0x7c, 0x15, 0xfe, 0x99, 0x36, - 0xc2, 0x7e, 0xfc, 0x67, 0xf4, 0x67, 0xda, 0x40, 0x7d, 0x14, 0xce, 0xef, 0x56, 0x6c, 0xb6, 0x82, 0x60, 0x6b, 0x0f, - 0x8e, 0xf0, 0x6b, 0xbf, 0x24, 0x57, 0x34, 0xe3, 0xc9, 0xca, 0xbe, 0x84, 0xb7, 0xb2, 0xcf, 0x04, 0xad, 0xf4, 0xe3, - 0x4e, 0xab, 0x50, 0x8c, 0x32, 0x08, 0x2c, 0x1c, 0xee, 0x35, 0xfb, 0x83, 0x56, 0xf3, 0xd1, 0xd0, 0xfc, 0xab, 0x23, - 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x04, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, 0xe9, 0x55, 0x82, - 0x8c, 0xef, 0xc9, 0x6a, 0xc5, 0x6c, 0x34, 0x6b, 0xab, 0xc1, 0x2f, 0x63, 0x33, 0x1d, 0xb6, 0xa3, 0x4e, 0xcf, 0x89, - 0xb1, 0xa4, 0x01, 0x91, 0xa6, 0x31, 0x83, 0x40, 0x52, 0x4b, 0xcd, 0x61, 0xcd, 0xef, 0x82, 0xb8, 0xba, 0x3f, 0x82, - 0x94, 0x1f, 0x82, 0x98, 0x1f, 0x11, 0x08, 0xa0, 0x6d, 0x98, 0xa3, 0xb2, 0x21, 0xe7, 0xbb, 0xf4, 0x40, 0x3b, 0x33, - 0x34, 0xf8, 0x6a, 0xd5, 0xaa, 0x86, 0x29, 0x8b, 0xfa, 0x30, 0x97, 0x6b, 0x2c, 0xc9, 0x1b, 0xd0, 0x35, 0xe7, 0x44, - 0xf6, 0x7d, 0x57, 0x79, 0x78, 0x08, 0x18, 0x0b, 0x02, 0x4e, 0xfa, 0x7d, 0xd9, 0x2f, 0xc8, 0xc5, 0x65, 0x08, 0x3e, - 0x66, 0x98, 0x0f, 0xd4, 0xa0, 0x18, 0x0e, 0x51, 0x6c, 0x9d, 0xce, 0x62, 0x1d, 0x71, 0xc5, 0xf3, 0x4b, 0x2e, 0xc0, - 0x2f, 0x39, 0x47, 0x6c, 0x50, 0x0c, 0xc9, 0x83, 0x24, 0x14, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, 0xd2, 0x37, 0x30, - 0xd5, 0xc3, 0xd2, 0x17, 0xd9, 0x60, 0x31, 0x67, 0x2c, 0x81, 0xe0, 0x66, 0xc0, 0x5e, 0x6a, 0x43, 0xa2, 0xb6, 0x06, - 0x0a, 0xee, 0x02, 0xdf, 0xcc, 0xe8, 0xe9, 0x56, 0x1b, 0x83, 0xc0, 0xe2, 0x85, 0xbe, 0x86, 0x31, 0x08, 0xa4, 0x2f, - 0x57, 0x1d, 0xf6, 0x97, 0x1f, 0x26, 0xcb, 0x0f, 0x5e, 0xa1, 0x4d, 0x76, 0x4a, 0xab, 0x44, 0x3d, 0xbe, 0xca, 0x13, - 0x47, 0x13, 0x64, 0x62, 0xa8, 0x74, 0xc3, 0x32, 0x71, 0x25, 0x7d, 0x26, 0x9a, 0x6c, 0x37, 0x1c, 0x33, 0xe7, 0xbb, - 0xd9, 0xfe, 0x61, 0xdd, 0xce, 0x39, 0xe1, 0x5a, 0x2b, 0xa9, 0xb5, 0x51, 0xcf, 0x34, 0x55, 0xb5, 0xc1, 0xfc, 0x2e, - 0xad, 0x96, 0x16, 0x5b, 0x57, 0xef, 0x9e, 0xff, 0x2c, 0x5d, 0x19, 0x7f, 0x8b, 0x55, 0xa1, 0x15, 0x19, 0x6e, 0xb7, - 0x90, 0x33, 0x67, 0xba, 0x74, 0x8a, 0x5c, 0xa8, 0x0e, 0x7f, 0x51, 0x4f, 0xea, 0x97, 0x2a, 0x83, 0x86, 0x74, 0xe8, - 0xf7, 0x3a, 0x01, 0xe5, 0x1f, 0x4c, 0x4c, 0x64, 0x2c, 0xba, 0xa5, 0x45, 0x1e, 0xfe, 0xf8, 0x22, 0xd7, 0xb1, 0xaa, - 0xf6, 0x60, 0x20, 0x7b, 0xba, 0xe2, 0x1e, 0xdc, 0x9a, 0xf0, 0x31, 0x67, 0x69, 0xbc, 0x17, 0xfc, 0xd8, 0x90, 0x8d, - 0x1f, 0x83, 0x1f, 0xc1, 0xdd, 0xd9, 0x3e, 0x8b, 0x58, 0xc6, 0x85, 0x70, 0xf7, 0x58, 0x97, 0xa5, 0x4a, 0x19, 0x2b, - 0xa7, 0x5b, 0xf6, 0x2f, 0xa4, 0xde, 0x24, 0xe1, 0xa5, 0x25, 0xd6, 0x26, 0x05, 0x2b, 0x9f, 0x92, 0xc2, 0xb3, 0x2b, - 0xfa, 0x56, 0x8b, 0xd9, 0x4b, 0x2d, 0xe9, 0xae, 0xaf, 0x2e, 0x4b, 0x15, 0x34, 0x1c, 0x84, 0xb6, 0xb4, 0x81, 0x04, - 0x18, 0xb8, 0x94, 0x3e, 0x9d, 0xf6, 0x4c, 0x22, 0xb3, 0x24, 0x84, 0x77, 0x0f, 0x2a, 0x98, 0xff, 0xce, 0x36, 0xc2, - 0xaa, 0xc0, 0xe5, 0x4a, 0x15, 0xf5, 0x52, 0x10, 0x08, 0x40, 0x5f, 0x7a, 0x0f, 0x8a, 0xf3, 0xa2, 0xd7, 0x68, 0x08, - 0xd0, 0xc2, 0x52, 0x7d, 0xad, 0x8a, 0xe9, 0xbe, 0xff, 0x9c, 0x9f, 0xf7, 0xe1, 0x1c, 0xd2, 0x36, 0xde, 0xd4, 0xa4, - 0x84, 0x9a, 0x1d, 0xb4, 0x0f, 0x56, 0xd9, 0x5e, 0xf9, 0xb7, 0x21, 0x45, 0x26, 0x7f, 0xc0, 0x7e, 0xa0, 0xb6, 0xc3, - 0xa1, 0x2d, 0x58, 0xf5, 0x52, 0x46, 0xc1, 0x80, 0x95, 0x03, 0x6e, 0x4f, 0x46, 0x09, 0x4d, 0xa6, 0x0c, 0xd4, 0xfd, - 0xa6, 0x68, 0x35, 0xb7, 0x27, 0x75, 0xbf, 0x21, 0xed, 0xec, 0x23, 0xb5, 0xb3, 0x4f, 0x0e, 0x5e, 0x2c, 0x82, 0xfc, - 0x21, 0x42, 0x85, 0xc3, 0xbc, 0x29, 0xd1, 0x51, 0x07, 0xb8, 0x33, 0x70, 0xe0, 0x01, 0x5b, 0x94, 0x83, 0x03, 0x6a, - 0x2d, 0xee, 0x69, 0x23, 0x71, 0xde, 0x9e, 0x50, 0xbb, 0x08, 0x25, 0x6e, 0xd6, 0xcc, 0xb4, 0xa0, 0xb5, 0x42, 0x3b, - 0x8f, 0x7b, 0xbc, 0xcd, 0xb3, 0x5a, 0xfc, 0x84, 0x0d, 0x6b, 0xaa, 0xfa, 0x0d, 0x34, 0x47, 0xb5, 0x20, 0x37, 0x4f, - 0xb5, 0xb7, 0x2a, 0x19, 0x04, 0xc1, 0xd0, 0x70, 0x2a, 0x44, 0x93, 0x8c, 0x41, 0x6b, 0xe8, 0xdd, 0x6a, 0xaf, 0x56, - 0xdc, 0x21, 0xbe, 0xac, 0x79, 0xab, 0xe9, 0x5b, 0x00, 0x5a, 0x84, 0x41, 0x79, 0x6f, 0x12, 0x80, 0xf7, 0x6d, 0x19, - 0x21, 0x6d, 0x39, 0x30, 0x6f, 0x36, 0x96, 0x8a, 0xcd, 0x77, 0x74, 0x32, 0x8c, 0x03, 0x33, 0xa2, 0x00, 0xdf, 0x94, - 0x90, 0x84, 0xab, 0xa4, 0x1b, 0x99, 0x88, 0x39, 0x93, 0x31, 0xc7, 0x37, 0x85, 0x10, 0xea, 0xda, 0x7c, 0x09, 0x5c, - 0xdd, 0xc9, 0x48, 0x7c, 0x33, 0x61, 0xea, 0x1d, 0x2d, 0x26, 0x0c, 0xfc, 0x8a, 0xdc, 0xed, 0x58, 0x4c, 0xc9, 0xc5, - 0x53, 0x19, 0x0e, 0x28, 0x86, 0x07, 0x47, 0x87, 0x58, 0xe9, 0x10, 0x28, 0x15, 0x2e, 0xb2, 0xdb, 0xbd, 0x37, 0x85, - 0xb8, 0xbb, 0x0f, 0x0b, 0x6c, 0x1d, 0x00, 0x4b, 0xa7, 0x49, 0x80, 0x7f, 0xf9, 0x98, 0x8f, 0xd1, 0x98, 0x53, 0xad, - 0xeb, 0xb7, 0xbf, 0xa3, 0x1b, 0xa0, 0xb7, 0xa5, 0xa3, 0xe0, 0xa0, 0x35, 0x84, 0x5c, 0xb8, 0x0b, 0x83, 0x8b, 0x2f, - 0xbf, 0xb6, 0x28, 0xb4, 0x37, 0x16, 0x40, 0xef, 0xaf, 0x04, 0x2c, 0xd8, 0x30, 0xc7, 0x14, 0x5e, 0x6b, 0x9d, 0x30, - 0xe5, 0x45, 0x05, 0x79, 0x52, 0xbe, 0xc7, 0x59, 0xab, 0xfd, 0x96, 0x8d, 0xe1, 0x0e, 0x23, 0xfa, 0x76, 0xe1, 0xc8, - 0x82, 0x07, 0x64, 0x9a, 0xc4, 0x34, 0xfb, 0xc6, 0x45, 0x1e, 0x79, 0x3d, 0x0e, 0x77, 0xb5, 0xe4, 0xe7, 0xeb, 0x15, - 0x5d, 0x63, 0x08, 0x45, 0xe1, 0xf7, 0xfb, 0x15, 0x1e, 0x28, 0xad, 0x0c, 0xda, 0xa0, 0x61, 0x71, 0x9b, 0xff, 0x02, - 0x67, 0x0c, 0xad, 0x17, 0x32, 0x77, 0x74, 0xc6, 0xe1, 0xcc, 0x62, 0xc6, 0x94, 0xc0, 0xa8, 0x94, 0x28, 0xe8, 0x04, - 0x1c, 0x9d, 0xab, 0x0f, 0x92, 0x87, 0xd5, 0xb1, 0x02, 0xf0, 0x24, 0x53, 0xf8, 0x27, 0xdb, 0x04, 0xeb, 0x7e, 0xab, - 0x66, 0x98, 0xfa, 0x8b, 0xda, 0x76, 0x2d, 0x5f, 0xfa, 0x38, 0xd2, 0xc6, 0x10, 0x5a, 0xe7, 0xee, 0x1e, 0x50, 0xc4, - 0x06, 0xbd, 0x88, 0x15, 0xbe, 0x91, 0x8b, 0x91, 0x5e, 0x5f, 0xed, 0x3a, 0xa6, 0x00, 0x51, 0xac, 0xbb, 0x26, 0xbe, - 0xa9, 0x9e, 0x3f, 0x95, 0x71, 0x0e, 0x67, 0x10, 0x84, 0x38, 0x29, 0x2f, 0x1b, 0x62, 0x41, 0x2e, 0x74, 0xa7, 0x42, - 0x77, 0x5a, 0x21, 0x94, 0x4d, 0x8f, 0xca, 0xfb, 0x57, 0x08, 0x61, 0xa0, 0xcb, 0xec, 0xc0, 0xaa, 0x7c, 0x0b, 0xab, - 0xe0, 0xd5, 0x8b, 0x0d, 0xac, 0x12, 0x70, 0x3c, 0x97, 0x68, 0x54, 0x54, 0x38, 0xa4, 0x49, 0x9f, 0x8f, 0x45, 0x90, - 0x00, 0x58, 0xf4, 0x2e, 0xb1, 0x79, 0xdf, 0xc3, 0x21, 0xbf, 0x27, 0x11, 0xf9, 0xd3, 0x8d, 0x68, 0x06, 0xef, 0xe2, - 0xca, 0xbe, 0x43, 0x08, 0x58, 0x7a, 0x8e, 0xe1, 0x3d, 0xe4, 0xef, 0xbf, 0xc3, 0x6a, 0x2d, 0xc8, 0xe3, 0x7f, 0x89, - 0x92, 0xd0, 0xd8, 0x7f, 0x8e, 0x87, 0x16, 0x09, 0xfd, 0x81, 0x6f, 0x8e, 0xb0, 0xc2, 0xc1, 0xad, 0x22, 0x2e, 0x83, - 0x5b, 0x7c, 0xac, 0x43, 0x0f, 0x00, 0x4b, 0x28, 0xf6, 0x41, 0xbe, 0x81, 0x62, 0x1a, 0x07, 0x14, 0x59, 0xfa, 0x17, - 0xb8, 0x60, 0xb5, 0x50, 0xde, 0xdf, 0xb6, 0x9c, 0x94, 0x56, 0xbb, 0xe4, 0xd5, 0xe6, 0x40, 0xe5, 0xa7, 0x7f, 0xe1, - 0x2b, 0xf5, 0x43, 0xcd, 0xf6, 0x0b, 0xdf, 0x58, 0xa0, 0xc7, 0xa0, 0x08, 0xb0, 0xbf, 0xd7, 0x84, 0x3b, 0x8a, 0x5e, - 0xe6, 0x62, 0xbf, 0x6d, 0xaf, 0x7b, 0x89, 0xb9, 0xbc, 0xae, 0xb2, 0xe6, 0x60, 0x0a, 0x0d, 0x0e, 0xaa, 0x70, 0x46, - 0x60, 0x2e, 0x5f, 0x94, 0x05, 0xe7, 0x20, 0xde, 0xf7, 0xa5, 0xce, 0x29, 0xa3, 0x01, 0xbc, 0x48, 0xca, 0x47, 0xa7, - 0xfa, 0x1c, 0x5c, 0xc6, 0x35, 0x9b, 0xf8, 0x44, 0xba, 0x54, 0x60, 0x25, 0x8d, 0x71, 0x68, 0x40, 0x53, 0x3a, 0x07, - 0xb3, 0x0d, 0xa0, 0xe0, 0xf6, 0x7c, 0xd8, 0x58, 0x28, 0xef, 0x2d, 0xda, 0xda, 0xd3, 0xd1, 0x84, 0x58, 0x93, 0x26, - 0xef, 0x6e, 0x5b, 0x23, 0x83, 0x33, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, 0x84, 0x27, 0x28, - 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xb2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x5a, 0x6a, 0x20, 0x2b, 0x6a, 0x90, - 0x7b, 0xd4, 0x40, 0xd4, 0xb7, 0x7f, 0x01, 0x0b, 0x61, 0x22, 0x54, 0x49, 0x2f, 0x20, 0xc2, 0x5c, 0x69, 0x3e, 0xa0, - 0x88, 0x7c, 0xc8, 0x6b, 0x40, 0x85, 0x94, 0xbc, 0x04, 0xa3, 0x71, 0x78, 0xbd, 0x07, 0xdc, 0x2f, 0x0d, 0xc3, 0xe0, - 0x38, 0x05, 0x9d, 0xff, 0xd6, 0xe5, 0x43, 0xf5, 0x72, 0x75, 0x10, 0xc2, 0x4f, 0x24, 0x64, 0x98, 0x46, 0x7e, 0x01, - 0xb2, 0x99, 0x63, 0x71, 0x70, 0x20, 0x40, 0xe0, 0x87, 0x28, 0xc2, 0x1e, 0xcf, 0xf0, 0x32, 0xd9, 0x20, 0x7a, 0x6e, - 0x56, 0x79, 0x35, 0x2b, 0xe1, 0xcd, 0xaa, 0x70, 0x34, 0x8e, 0xae, 0x09, 0x03, 0xc1, 0x85, 0x9a, 0x7d, 0x83, 0x10, - 0x28, 0x5b, 0x6e, 0x35, 0x5d, 0x7a, 0x0a, 0xe6, 0xa3, 0x61, 0xf0, 0x96, 0xc1, 0x8b, 0xba, 0xda, 0xe4, 0x9f, 0x29, - 0x96, 0x28, 0xcd, 0x3c, 0x36, 0x3c, 0x27, 0x75, 0x8a, 0xa2, 0xbf, 0x04, 0xcf, 0xc3, 0xa0, 0x79, 0x11, 0xa0, 0x06, - 0xfc, 0xdb, 0xe0, 0xa8, 0x47, 0x23, 0x9a, 0xa6, 0x2e, 0xf8, 0x4d, 0x42, 0xf4, 0x26, 0x5b, 0xad, 0x64, 0x45, 0xd0, - 0x23, 0xb3, 0xc1, 0x80, 0x95, 0x78, 0x02, 0x3b, 0xd6, 0x70, 0xb0, 0xe4, 0x85, 0x0c, 0x73, 0x77, 0x4a, 0xe1, 0x1c, - 0x43, 0x3a, 0xc2, 0x89, 0x17, 0xb3, 0xf1, 0x3f, 0x9f, 0xa9, 0xbf, 0x7e, 0x6e, 0xbe, 0x96, 0x11, 0x11, 0x2e, 0x88, - 0x5c, 0x8d, 0x1d, 0x91, 0x5e, 0xd8, 0x32, 0x35, 0xb0, 0x65, 0x7e, 0x70, 0xd6, 0xd5, 0x43, 0x13, 0x2e, 0x0e, 0x0c, - 0xa8, 0x91, 0x67, 0xb4, 0x82, 0x33, 0x52, 0x0e, 0x1c, 0x94, 0x10, 0x8a, 0x15, 0xe1, 0x94, 0x5c, 0x40, 0x24, 0xbc, - 0x04, 0xf5, 0xc0, 0xb0, 0xc0, 0x93, 0xa0, 0xa6, 0x20, 0x41, 0x25, 0xae, 0x76, 0x0a, 0xb3, 0xce, 0xf4, 0x6c, 0xa7, - 0xa8, 0x67, 0x83, 0xfc, 0xfc, 0xa2, 0xc2, 0x14, 0x58, 0xda, 0x83, 0x83, 0x02, 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, - 0x40, 0x4f, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0x4a, 0x7b, 0x1d, 0x68, 0x5b, 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, - 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x7d, 0x15, 0x6f, 0x47, 0x48, 0xec, 0x7f, 0x54, 0x3a, 0xd0, 0x98, 0x25, 0xdd, 0xd5, - 0xc6, 0x7c, 0x55, 0xd3, 0x23, 0x56, 0x93, 0x10, 0x36, 0x48, 0x97, 0xe3, 0xd3, 0x9e, 0xc1, 0x15, 0xab, 0xd0, 0x72, - 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x16, 0x51, 0xc9, 0x86, 0x61, 0x06, 0x61, - 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0x33, 0x7f, 0x4a, 0x1f, 0x6c, 0xba, 0x76, 0xe6, 0x11, 0x40, - 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x37, 0x2a, 0x33, 0xbf, 0x96, 0xb6, 0x95, 0xdb, 0xf6, 0x18, 0x7b, 0x21, 0xb7, - 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x08, 0x55, 0x6d, 0xc8, 0x5a, 0x1b, 0x3a, 0xd0, 0x2f, - 0xd2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x59, 0x2e, 0xc1, 0x22, 0xbc, 0x74, 0x08, 0x7f, 0x97, 0x83, 0x33, 0x3c, 0x66, - 0x58, 0xac, 0x56, 0x50, 0xcf, 0xe1, 0x7d, 0xb2, 0x19, 0x9c, 0x54, 0x6c, 0x8c, 0x5d, 0x98, 0x89, 0x87, 0x65, 0x13, - 0x02, 0x27, 0xd0, 0xaf, 0xab, 0x88, 0xfa, 0xfb, 0xed, 0xf8, 0xa9, 0x0c, 0x6b, 0x3b, 0x10, 0x6b, 0xd6, 0x1b, 0xac, - 0x3e, 0x80, 0x96, 0xff, 0x93, 0xb8, 0x87, 0xca, 0xbc, 0x9b, 0x84, 0x7c, 0x73, 0x11, 0x7b, 0xac, 0x87, 0x18, 0xa9, - 0x2d, 0xee, 0x0e, 0x21, 0xfe, 0x9f, 0xad, 0x28, 0x06, 0x3c, 0xaa, 0xf8, 0xe7, 0x10, 0xf5, 0x20, 0x14, 0xb5, 0xf1, - 0xb0, 0x01, 0x4a, 0xbb, 0x5c, 0x57, 0x62, 0xa4, 0x4f, 0x20, 0xdf, 0xda, 0xf0, 0x82, 0xfa, 0x24, 0xca, 0x41, 0x4e, - 0xf6, 0xa2, 0x92, 0x26, 0x1b, 0xc2, 0x5c, 0x6f, 0x0b, 0xc7, 0xf4, 0xd5, 0x06, 0x2d, 0xc2, 0x17, 0xc0, 0xce, 0x70, - 0x2d, 0x59, 0x5a, 0xf0, 0xe5, 0x35, 0xf0, 0xb9, 0x35, 0xd7, 0x14, 0x25, 0x47, 0xfd, 0x17, 0x52, 0xdf, 0xfa, 0xc3, - 0xef, 0xd8, 0x13, 0x1f, 0xa9, 0xd5, 0x91, 0x6c, 0x84, 0x5a, 0xb3, 0x76, 0xbc, 0x6c, 0x33, 0xc2, 0xa0, 0x34, 0xd1, - 0xfb, 0x2a, 0x64, 0x95, 0x3b, 0x3b, 0x95, 0xde, 0x9c, 0xbe, 0xe6, 0x95, 0x73, 0x2a, 0x37, 0x8c, 0x6a, 0xa9, 0x69, - 0x80, 0x08, 0x57, 0x2e, 0x91, 0xbc, 0x4f, 0x74, 0xf8, 0x07, 0x8d, 0x71, 0xf5, 0x48, 0xe1, 0xef, 0x77, 0xc5, 0x0e, - 0xd9, 0x8e, 0x0e, 0xb7, 0x11, 0x34, 0xcf, 0x57, 0xf0, 0x80, 0xa3, 0x92, 0x21, 0x44, 0x39, 0xb9, 0xd8, 0xcf, 0x6b, - 0xa6, 0x6c, 0x37, 0x01, 0x42, 0x48, 0x39, 0x9c, 0x75, 0x0e, 0x91, 0xb5, 0xd0, 0x23, 0x55, 0x94, 0xc3, 0x2d, 0x9a, - 0x6b, 0x03, 0x54, 0x68, 0x81, 0x74, 0xf9, 0x85, 0xdd, 0xc7, 0x02, 0xa2, 0x97, 0xaf, 0x6d, 0x08, 0x63, 0x6b, 0x65, - 0x89, 0x0b, 0x3d, 0x6a, 0x13, 0x46, 0xd7, 0x6e, 0x0c, 0x6b, 0x03, 0xa3, 0xa7, 0x41, 0x49, 0x0b, 0x42, 0x5d, 0xf7, - 0xe8, 0x79, 0xa2, 0x03, 0x3d, 0x66, 0x84, 0x36, 0x18, 0x9e, 0x12, 0x05, 0x96, 0x4d, 0x05, 0x58, 0xf0, 0x2d, 0x8b, - 0x38, 0xd7, 0x36, 0x9b, 0x2c, 0xfc, 0xa8, 0x42, 0xfd, 0xb4, 0x5f, 0x56, 0x31, 0xcf, 0x85, 0xa5, 0x6e, 0xcf, 0x13, - 0x17, 0x8f, 0xee, 0xe9, 0x9b, 0xeb, 0x17, 0x2f, 0x5f, 0xbf, 0x5a, 0xad, 0xda, 0xac, 0xd9, 0x3e, 0xc1, 0x3f, 0xa9, - 0x32, 0x1e, 0x6c, 0x19, 0x05, 0xe8, 0xe0, 0x60, 0x9f, 0x6b, 0x17, 0x9e, 0x2f, 0x7c, 0x0e, 0x71, 0x83, 0xd4, 0x10, - 0x27, 0x45, 0x19, 0x13, 0xe4, 0x2e, 0xe8, 0x07, 0xf7, 0x01, 0x28, 0xa1, 0x2a, 0xf2, 0xf7, 0x61, 0x73, 0xf6, 0x7b, - 0x10, 0x98, 0x08, 0xea, 0x43, 0x04, 0x10, 0x88, 0x57, 0x8a, 0x0b, 0xc2, 0x5c, 0x02, 0x44, 0xf1, 0x5e, 0xc0, 0x9b, - 0x90, 0x3a, 0x6a, 0xd5, 0x22, 0x0f, 0x0b, 0x20, 0x89, 0x26, 0x1c, 0x25, 0x3d, 0xd2, 0x01, 0xbc, 0x21, 0x28, 0xa5, - 0xf9, 0xd5, 0xcb, 0xac, 0xbb, 0x54, 0x86, 0xfa, 0xad, 0x38, 0xc3, 0x53, 0xfb, 0x39, 0x85, 0xcf, 0x69, 0xcf, 0x9d, - 0x0e, 0xf2, 0x30, 0xc3, 0x0b, 0x22, 0x0f, 0xdd, 0xb3, 0x88, 0xcb, 0x79, 0xc1, 0xbe, 0x72, 0xb1, 0x90, 0xf1, 0xf2, - 0x2e, 0x16, 0xd1, 0x5d, 0x33, 0x3d, 0x0c, 0x8b, 0xe8, 0xae, 0x99, 0x47, 0x77, 0x08, 0xdf, 0xc7, 0x22, 0xba, 0x37, - 0x29, 0xf7, 0xcd, 0x1c, 0x6e, 0xbe, 0x70, 0x0e, 0x87, 0xa2, 0x29, 0xda, 0x58, 0x6c, 0x16, 0x35, 0x29, 0xb6, 0xa8, - 0x87, 0xc1, 0xbf, 0xef, 0xd8, 0xf8, 0x7e, 0xf8, 0x12, 0x5c, 0x9a, 0x34, 0x91, 0x9f, 0x40, 0xfa, 0x69, 0x55, 0x06, - 0xee, 0x53, 0xd2, 0xea, 0x4d, 0xcf, 0x65, 0xb3, 0xdd, 0x6b, 0x34, 0xa6, 0xb0, 0x77, 0x13, 0x92, 0xb9, 0x62, 0xd3, - 0x86, 0x8e, 0xaf, 0xb3, 0x9f, 0xac, 0x56, 0xfb, 0x19, 0xd2, 0x1b, 0x6e, 0xc2, 0x42, 0x35, 0x98, 0x0e, 0x71, 0x0b, - 0x3f, 0x4f, 0x10, 0x5a, 0xb2, 0xc1, 0x74, 0x48, 0xd8, 0x60, 0xda, 0x68, 0x0f, 0x8d, 0xa1, 0x9d, 0xde, 0x8a, 0x6b, - 0x08, 0xa1, 0x39, 0x1d, 0x1e, 0xe9, 0x92, 0xc2, 0xe6, 0x9b, 0x2f, 0x5a, 0x05, 0xf4, 0xcb, 0x6b, 0xc1, 0xcb, 0x04, - 0xee, 0x40, 0x5f, 0xf4, 0xdc, 0x3c, 0xdd, 0x5a, 0x90, 0xe3, 0xa3, 0xca, 0xd5, 0x9e, 0x22, 0xac, 0x7b, 0xca, 0x0f, - 0x8b, 0x43, 0xdd, 0x8c, 0xed, 0x52, 0xd8, 0x6f, 0x5f, 0x33, 0xf2, 0xd1, 0xc2, 0x02, 0x10, 0xa4, 0x82, 0x47, 0x52, - 0xd8, 0x70, 0x4a, 0x3e, 0x5c, 0x2c, 0x54, 0xb6, 0x60, 0x92, 0x91, 0x56, 0x2f, 0xd3, 0x96, 0xfe, 0x99, 0x8d, 0x68, - 0x4a, 0x31, 0x25, 0x89, 0x2b, 0x99, 0x69, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x10, 0xa7, 0x04, 0xe2, - 0x21, 0xf5, 0x0a, 0x6d, 0xe0, 0x15, 0x4e, 0x9b, 0xc5, 0x80, 0x0d, 0xd1, 0xd1, 0x31, 0xa6, 0x83, 0xcf, 0xc9, 0xbc, - 0x0d, 0x8f, 0x05, 0x7e, 0x1e, 0x92, 0x69, 0x53, 0x94, 0x09, 0x12, 0x12, 0xd2, 0xa6, 0x38, 0x84, 0xbd, 0x84, 0x70, - 0x62, 0x2a, 0x26, 0x03, 0x36, 0x6c, 0x4e, 0xcb, 0x8a, 0x1d, 0x57, 0xb1, 0x21, 0xca, 0x04, 0x53, 0xb1, 0x61, 0x2b, - 0xfa, 0xaf, 0x33, 0x68, 0x10, 0xf8, 0x00, 0x60, 0x00, 0x00, 0x85, 0xbc, 0x68, 0xbe, 0x38, 0x27, 0x6e, 0xb3, 0x9b, - 0x7b, 0xfc, 0x16, 0x58, 0xa0, 0xd5, 0xf6, 0xff, 0x2e, 0x94, 0x01, 0x7b, 0xca, 0x42, 0xc7, 0xcc, 0x2d, 0x8c, 0x8a, - 0x0e, 0xa0, 0x52, 0x22, 0x4c, 0xa1, 0x21, 0xb3, 0x9f, 0x68, 0xa8, 0x79, 0x5a, 0x83, 0x6c, 0xa0, 0x86, 0xcd, 0x04, - 0x8e, 0x18, 0x78, 0x87, 0x86, 0x4c, 0xb5, 0x31, 0x61, 0x98, 0xc1, 0x14, 0x13, 0x0d, 0x9e, 0x69, 0xdc, 0x5a, 0x0b, - 0x2d, 0xcb, 0xf5, 0xb3, 0xfe, 0xdf, 0x2a, 0xcc, 0x07, 0x45, 0xb3, 0x3d, 0x44, 0xfb, 0x84, 0x98, 0x8f, 0x21, 0x6c, - 0x32, 0x9b, 0xda, 0xd0, 0xdf, 0x47, 0x9d, 0xd8, 0x7c, 0xc2, 0x9f, 0xe1, 0x5a, 0xef, 0x00, 0x1d, 0x78, 0x50, 0xaf, - 0xbf, 0xa8, 0xa9, 0xbc, 0x3e, 0xee, 0x8c, 0x52, 0xb9, 0xeb, 0xdd, 0x69, 0x4f, 0x53, 0xec, 0x7b, 0xeb, 0xe1, 0xf2, - 0xa1, 0x1e, 0x02, 0x66, 0x0c, 0xfa, 0x96, 0x19, 0x7d, 0x2f, 0x44, 0x72, 0x41, 0x04, 0x16, 0x1a, 0x6b, 0x18, 0xec, - 0xad, 0x83, 0x03, 0x5d, 0x8d, 0x35, 0xe0, 0x79, 0x52, 0x04, 0x82, 0x81, 0x8b, 0xa0, 0x0c, 0x68, 0x92, 0xeb, 0xdb, - 0x70, 0xf2, 0x91, 0xd9, 0x5f, 0xb8, 0xbc, 0x7d, 0x2c, 0x8c, 0xb6, 0x55, 0x27, 0xdf, 0x97, 0x05, 0xee, 0xcb, 0x7b, - 0x49, 0xa3, 0xe0, 0x46, 0xe6, 0x26, 0x2f, 0xd7, 0x77, 0xeb, 0xae, 0x54, 0x67, 0x77, 0x33, 0x9d, 0xb2, 0x99, 0xce, - 0x76, 0x33, 0xbe, 0x66, 0xe6, 0x5b, 0x56, 0x91, 0xfa, 0x64, 0x8d, 0xe4, 0x9c, 0xe6, 0x3f, 0xd1, 0x39, 0x18, 0x05, - 0x73, 0x73, 0xaf, 0x0a, 0x27, 0x57, 0x46, 0x2e, 0xf6, 0x33, 0x4d, 0x5c, 0x91, 0xbe, 0x50, 0x87, 0x00, 0x2f, 0x2f, - 0xca, 0xc7, 0x07, 0xb8, 0xc8, 0x7f, 0x15, 0xa9, 0x8d, 0x72, 0x9a, 0x0b, 0x25, 0x72, 0x16, 0x20, 0x8d, 0xaa, 0x36, - 0x06, 0xf6, 0xd2, 0xec, 0x3d, 0xd9, 0xe7, 0x83, 0x2a, 0x62, 0xde, 0x50, 0x3f, 0xf7, 0xf1, 0x3d, 0x4d, 0xb1, 0x55, - 0x13, 0x27, 0xe4, 0x43, 0x12, 0x66, 0x20, 0x9b, 0x0d, 0xaa, 0xd7, 0x7e, 0x1b, 0x6d, 0x5c, 0x34, 0x43, 0xd9, 0xd7, - 0x4f, 0x9c, 0xfc, 0x50, 0x68, 0xe3, 0x00, 0xe3, 0xe8, 0x8f, 0x30, 0x35, 0x60, 0x4f, 0x22, 0x47, 0xa1, 0xa3, 0x3b, - 0x93, 0x76, 0xef, 0xa7, 0xdd, 0xeb, 0xb4, 0x0e, 0x94, 0x03, 0xd2, 0x6c, 0xcb, 0x74, 0xee, 0xdd, 0xf7, 0x3d, 0xbc, - 0x74, 0xbb, 0x86, 0x48, 0xdc, 0xf3, 0xc7, 0xda, 0x18, 0xe2, 0x0d, 0xd8, 0x88, 0xca, 0x83, 0x83, 0x3f, 0xac, 0xf7, - 0x6d, 0x25, 0xcb, 0xca, 0x6f, 0x84, 0x03, 0xdb, 0x60, 0x2a, 0x6d, 0x5e, 0x2a, 0x92, 0x05, 0xd8, 0x75, 0xee, 0xef, - 0x8e, 0x87, 0xff, 0x52, 0xfa, 0x4c, 0x8b, 0x71, 0x15, 0x7f, 0x25, 0xd2, 0xd2, 0x43, 0x54, 0x41, 0x04, 0xd2, 0xca, - 0xba, 0xd4, 0x37, 0x1d, 0xbd, 0x9e, 0xd2, 0x54, 0xdc, 0xbe, 0x15, 0x42, 0x0d, 0xcd, 0x8b, 0xdc, 0x2a, 0x82, 0x47, - 0x0b, 0x6b, 0x0c, 0xcd, 0x7d, 0xe9, 0x9d, 0x64, 0x02, 0xa2, 0xd6, 0xc7, 0xed, 0x4b, 0x22, 0xa1, 0xac, 0xee, 0x42, - 0x38, 0xdc, 0x85, 0x60, 0x5e, 0x06, 0x6d, 0x83, 0xd8, 0xed, 0x36, 0x68, 0x5b, 0x28, 0x89, 0x34, 0x81, 0xdb, 0xbd, - 0xc1, 0xc2, 0xde, 0x87, 0x97, 0x63, 0x39, 0x96, 0xee, 0x9a, 0xcc, 0x3c, 0x00, 0x04, 0x6a, 0x1f, 0x56, 0x3c, 0xb1, - 0x20, 0x88, 0xac, 0xe1, 0xe8, 0x7b, 0xce, 0x6e, 0x8d, 0xe5, 0xf0, 0x6c, 0xbe, 0x50, 0x2c, 0xd5, 0x77, 0xd4, 0x80, - 0x3f, 0x75, 0x3f, 0xaf, 0x9f, 0x92, 0x9a, 0x6e, 0xfc, 0x01, 0x84, 0x91, 0xb0, 0xca, 0x0e, 0xad, 0x90, 0x30, 0xc1, - 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0xa5, 0xc3, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x00, 0x9b, 0x78, 0x63, - 0x5e, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x07, 0xcd, 0xa0, 0xc1, 0x62, 0x1b, 0x94, - 0xd9, 0x45, 0x18, 0xcf, 0xcf, 0x4f, 0x74, 0x9c, 0xf6, 0x52, 0xaf, 0xfe, 0x5b, 0x02, 0x06, 0xf8, 0x12, 0xbc, 0xc4, - 0xfc, 0xe8, 0xae, 0x03, 0xd5, 0x80, 0xfa, 0xa2, 0xc1, 0x86, 0x68, 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xd9, 0x6b, 0x2e, - 0x69, 0xae, 0xb9, 0xa4, 0xbd, 0xe6, 0x92, 0xee, 0x9a, 0x4b, 0xea, 0x6b, 0x2e, 0xe9, 0xae, 0xb9, 0x1c, 0x08, 0x3f, - 0x79, 0x71, 0x1c, 0x43, 0x0e, 0x71, 0x15, 0x95, 0x89, 0x8c, 0x07, 0x17, 0x9e, 0xfb, 0x2c, 0x92, 0xe5, 0xf2, 0xfb, - 0x31, 0xe4, 0xb6, 0x6c, 0x25, 0xb4, 0xdb, 0x14, 0x93, 0x10, 0x39, 0xfd, 0xe0, 0xa0, 0x74, 0x77, 0x06, 0x1f, 0xf5, - 0x98, 0xe3, 0xa5, 0x71, 0xa2, 0xfd, 0x03, 0x74, 0xf2, 0xfa, 0xd7, 0xc7, 0x58, 0xac, 0x89, 0xb4, 0x26, 0xf7, 0xfb, - 0x6d, 0x47, 0x29, 0x3e, 0x25, 0x3a, 0x3c, 0x39, 0x8f, 0x94, 0x16, 0x41, 0x10, 0xa2, 0x24, 0xc7, 0x09, 0x11, 0x66, - 0xbf, 0x3b, 0x57, 0x78, 0xad, 0x8a, 0x72, 0x66, 0x25, 0x57, 0x19, 0x38, 0xb1, 0x6b, 0x2b, 0x0c, 0xd4, 0x03, 0x17, - 0x82, 0x44, 0x27, 0xfc, 0xd1, 0xcc, 0x0c, 0x39, 0x4b, 0xca, 0xa4, 0x8f, 0xcd, 0x4c, 0x13, 0xb0, 0x82, 0xec, 0x3b, - 0x98, 0x2d, 0xef, 0x62, 0x8a, 0xef, 0xe3, 0x04, 0xff, 0xbf, 0xec, 0xbd, 0xeb, 0x92, 0xdb, 0x46, 0x96, 0x2e, 0xfa, - 0x2a, 0x55, 0x0c, 0x99, 0x06, 0xc4, 0x24, 0x8b, 0xa5, 0xbd, 0x67, 0x22, 0x0e, 0x58, 0x29, 0x86, 0x2c, 0x59, 0xdd, - 0x72, 0x5b, 0x97, 0x56, 0xa9, 0xdd, 0x76, 0x33, 0x78, 0x68, 0x14, 0x90, 0x24, 0x20, 0x83, 0x00, 0x0d, 0x80, 0x55, - 0xa4, 0x48, 0xbc, 0xfb, 0x8e, 0xb5, 0x56, 0x5e, 0x41, 0xb0, 0xa4, 0x9e, 0xd9, 0xf3, 0xeb, 0x9c, 0x3f, 0x52, 0x31, - 0x91, 0x48, 0xe4, 0x3d, 0x57, 0xae, 0xcb, 0xf7, 0xdd, 0x15, 0xbb, 0xa0, 0xb4, 0x7d, 0x41, 0x94, 0xe1, 0x6f, 0xe9, - 0xf5, 0xf2, 0x10, 0xe2, 0x7d, 0x7a, 0x69, 0x7e, 0x91, 0xb6, 0xa2, 0x00, 0x0f, 0x11, 0x7a, 0x54, 0x07, 0x82, 0x9d, - 0xf1, 0x84, 0x07, 0x70, 0xb2, 0x9a, 0xe5, 0xfc, 0x49, 0x0a, 0xe2, 0x44, 0xc1, 0x21, 0xe0, 0x6a, 0x77, 0x9b, 0x7e, - 0x01, 0xc3, 0x97, 0x0e, 0xb6, 0x1c, 0xde, 0x15, 0xbb, 0x1e, 0x2b, 0xf9, 0x07, 0x60, 0xdf, 0xea, 0xc9, 0x58, 0xdd, - 0x1e, 0x38, 0xeb, 0x52, 0x8a, 0x8e, 0x37, 0xc5, 0xe1, 0xed, 0xf9, 0xec, 0xb0, 0x0b, 0x22, 0xb6, 0x0f, 0x32, 0xac, - 0x75, 0xd2, 0xf0, 0x9f, 0x68, 0xeb, 0x60, 0x31, 0xc2, 0xfe, 0x2f, 0xeb, 0x81, 0x97, 0x90, 0x1a, 0x0a, 0x5c, 0x0c, - 0xb6, 0x1c, 0xad, 0xed, 0x32, 0x0d, 0xdc, 0xd4, 0xa0, 0xd7, 0x0f, 0x14, 0xa2, 0xbc, 0x64, 0x34, 0x37, 0x82, 0x4d, - 0x63, 0xc8, 0xc5, 0xe1, 0xb8, 0x59, 0x0e, 0x79, 0x49, 0xd3, 0x69, 0x10, 0x4a, 0x77, 0x96, 0x0d, 0x24, 0x51, 0xf6, - 0x41, 0xa8, 0x5d, 0x5b, 0x0e, 0xbb, 0xc0, 0xf6, 0xe5, 0x8f, 0x86, 0xb1, 0x7f, 0xb5, 0x7c, 0x2a, 0xa4, 0x8b, 0x78, - 0x05, 0x82, 0xa8, 0xfd, 0x3c, 0x1b, 0x6e, 0xfd, 0xab, 0xcd, 0x53, 0xa1, 0xfc, 0xc6, 0x2b, 0x5b, 0x0e, 0xa9, 0xb3, - 0x16, 0xbe, 0x30, 0x1e, 0x1e, 0x5c, 0x19, 0xda, 0x8e, 0x47, 0xa1, 0xff, 0x36, 0x6b, 0x04, 0x37, 0x36, 0xb4, 0xcf, - 0x17, 0x3e, 0x6c, 0x6d, 0x34, 0xd6, 0x14, 0xd3, 0x2d, 0xf4, 0x6f, 0x32, 0x5b, 0xda, 0xd3, 0xa8, 0xe4, 0xc5, 0xb9, - 0x69, 0xc4, 0x42, 0x18, 0x30, 0xf4, 0x93, 0xf9, 0x00, 0xaa, 0xb9, 0xd3, 0x11, 0xc8, 0xe4, 0x03, 0x3d, 0x58, 0x93, - 0x5a, 0xf5, 0xd7, 0x30, 0x93, 0xff, 0x47, 0x2a, 0x2c, 0x46, 0x77, 0xdb, 0x30, 0x53, 0x7f, 0x44, 0xf2, 0x0f, 0x56, - 0xf1, 0x7d, 0xea, 0x85, 0xda, 0x8f, 0x85, 0x15, 0x18, 0x94, 0xa8, 0x1a, 0xd0, 0x03, 0x11, 0x54, 0x65, 0x90, 0x66, - 0x58, 0x9d, 0x83, 0x7e, 0xf7, 0xb4, 0xea, 0x48, 0x0e, 0x69, 0xad, 0x86, 0x54, 0x30, 0x55, 0x6a, 0x50, 0x1d, 0x8f, - 0xab, 0x94, 0xe9, 0x32, 0xe0, 0x92, 0xbe, 0x4a, 0x95, 0x52, 0xf8, 0x4f, 0x04, 0xa0, 0x73, 0x70, 0x8f, 0xaf, 0xc7, - 0x40, 0x9a, 0x61, 0xe1, 0xb7, 0x66, 0xa7, 0xd7, 0x24, 0xdc, 0x26, 0xc1, 0xc5, 0x00, 0xe7, 0xe8, 0x3a, 0x2c, 0x57, - 0x29, 0x44, 0x50, 0x95, 0x50, 0xdf, 0xdc, 0x34, 0x28, 0x6d, 0x35, 0x08, 0x6b, 0x12, 0xea, 0x4c, 0xb2, 0x51, 0x69, - 0xbb, 0x51, 0x98, 0x2d, 0xe2, 0x7a, 0x46, 0x58, 0x73, 0x36, 0x53, 0x0d, 0x4c, 0x1a, 0x8e, 0x9b, 0x46, 0x6b, 0x51, - 0xa1, 0xa6, 0x30, 0xaf, 0x71, 0x55, 0xa9, 0xea, 0x6e, 0xcf, 0x2d, 0xa5, 0x65, 0x7b, 0xd5, 0x4d, 0xb2, 0x21, 0x97, - 0xa1, 0x0c, 0x83, 0xad, 0x1c, 0xc1, 0x04, 0x92, 0xe4, 0xcc, 0xdf, 0xca, 0x3f, 0xd4, 0xa6, 0x6b, 0x01, 0x73, 0x8c, - 0x59, 0x36, 0x2c, 0xe8, 0x15, 0xb8, 0x07, 0x5a, 0xe9, 0xd5, 0x34, 0xbb, 0xaa, 0x82, 0x64, 0x58, 0xe8, 0x65, 0x93, - 0xf1, 0x3f, 0x85, 0x91, 0x26, 0x33, 0x56, 0xb2, 0xc8, 0x76, 0x75, 0x4a, 0x9c, 0xc7, 0x09, 0x6c, 0x8f, 0xa6, 0xb7, - 0x7c, 0x9f, 0x41, 0x54, 0x10, 0x28, 0x98, 0x31, 0x5f, 0x76, 0xf5, 0xcc, 0xf7, 0x99, 0x65, 0xea, 0x3e, 0x1e, 0x8d, - 0x19, 0xdb, 0xef, 0xf7, 0xab, 0x7e, 0x5f, 0xcd, 0xb7, 0x7e, 0x3f, 0x79, 0x6e, 0xfe, 0xf6, 0x80, 0x41, 0x41, 0x4e, - 0x44, 0x53, 0x21, 0x82, 0x7f, 0x48, 0x9e, 0x22, 0x19, 0xdd, 0x69, 0x9f, 0x5b, 0xce, 0x96, 0xf9, 0x09, 0x08, 0xe6, - 0xf1, 0x78, 0xad, 0xc0, 0xae, 0x25, 0x8a, 0x84, 0x2c, 0xff, 0x29, 0x18, 0xcf, 0xdc, 0x07, 0x58, 0x32, 0x00, 0x61, - 0xab, 0x3c, 0x5d, 0xef, 0xf9, 0x2a, 0x78, 0xa7, 0xe3, 0x5d, 0x63, 0x45, 0x06, 0xe2, 0x16, 0xd8, 0x88, 0xb5, 0xf6, - 0x80, 0x9c, 0x29, 0xc0, 0xf1, 0xe2, 0x78, 0xbc, 0x94, 0xbf, 0x74, 0xb3, 0x75, 0x02, 0x95, 0x02, 0xb7, 0x47, 0x27, - 0x07, 0xff, 0x1d, 0x68, 0x06, 0xe5, 0x30, 0x6f, 0x76, 0xbf, 0x33, 0x27, 0x3f, 0x3d, 0xc5, 0x3f, 0xe1, 0x21, 0x3a, - 0xfd, 0x76, 0x6f, 0xfe, 0xa0, 0xa8, 0x3c, 0x1e, 0xd5, 0xe2, 0x07, 0x9e, 0x1f, 0xf8, 0x85, 0x6f, 0x02, 0xb3, 0xc9, - 0xd4, 0x3b, 0xfb, 0x26, 0xaf, 0x98, 0x7a, 0x8d, 0xe7, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xdd, 0xc8, 0x89, - 0x76, 0xaa, 0x30, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, 0x96, 0x78, - 0x96, 0x2e, 0xaf, 0x27, 0x75, 0xb9, 0xd7, 0x8a, 0xa7, 0x03, 0xb0, 0xb8, 0x6d, 0xc0, 0x0b, 0xe0, 0xde, 0x62, 0xeb, - 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, 0x42, 0x30, - 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, 0x77, 0xf9, - 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0xe5, 0x60, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, 0x52, 0x3c, - 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfd, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xb3, 0x7b, 0x72, 0x65, - 0x20, 0x81, 0xa6, 0x03, 0xe0, 0x21, 0x54, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, 0x05, 0xf7, - 0xe9, 0xa7, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa7, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x2a, 0xfb, 0xa6, - 0x02, 0x2a, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, 0x53, 0x71, - 0x73, 0xad, 0xd3, 0xc5, 0xf3, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, 0x07, 0xf1, - 0xb6, 0xb6, 0xa7, 0x3f, 0xf6, 0x10, 0xe9, 0x78, 0x20, 0x17, 0xea, 0x6b, 0x48, 0x25, 0x17, 0xea, 0x06, 0x62, 0x17, - 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0xdb, 0x1a, 0x05, 0x2b, 0x01, 0x67, 0xda, 0x5b, 0x30, 0xd8, 0xc0, 0xba, 0x65, - 0x19, 0xfc, 0x0d, 0xd7, 0x34, 0x81, 0x1b, 0x16, 0x59, 0xef, 0x0d, 0xb6, 0xd2, 0x5b, 0x70, 0xb4, 0x4c, 0x9c, 0x4b, - 0x49, 0x56, 0xb6, 0xc8, 0xb8, 0x7a, 0x14, 0x52, 0x35, 0x3d, 0xdc, 0x89, 0xfa, 0x41, 0x88, 0x3c, 0x58, 0xa7, 0x2c, - 0x2a, 0xd6, 0x20, 0xb3, 0x07, 0x7f, 0x0f, 0x19, 0x39, 0xca, 0x81, 0xa3, 0xd0, 0x5f, 0x9a, 0x40, 0xe7, 0xf9, 0x29, - 0xd4, 0x79, 0x24, 0xd8, 0x4a, 0x3d, 0x14, 0x56, 0x5e, 0x40, 0x74, 0xb0, 0x85, 0xb1, 0xdc, 0x93, 0x50, 0xb1, 0x29, - 0x13, 0x79, 0x1c, 0xd4, 0x12, 0x30, 0x56, 0x10, 0xcc, 0x59, 0x25, 0x5d, 0x90, 0xf2, 0x46, 0x0f, 0x8b, 0xcc, 0xfd, - 0x9d, 0xa0, 0xfc, 0xdf, 0xa9, 0x9c, 0x70, 0x7d, 0x19, 0x02, 0x1c, 0xed, 0x77, 0x20, 0x4a, 0x8c, 0xf5, 0x8b, 0x16, - 0xef, 0x64, 0xe6, 0x6c, 0x6a, 0x07, 0x09, 0x32, 0xb6, 0xc7, 0xaf, 0x10, 0x5a, 0x2d, 0x14, 0x59, 0x34, 0x5c, 0x30, - 0xdd, 0x9e, 0xd2, 0xaa, 0x7b, 0xd8, 0xf0, 0xac, 0xf4, 0x50, 0xa9, 0x6f, 0x63, 0x02, 0xcb, 0x2a, 0x65, 0xf8, 0x76, - 0x42, 0xd5, 0x89, 0x41, 0xc5, 0xba, 0x65, 0x4b, 0x38, 0xc4, 0x62, 0xd2, 0x58, 0x67, 0x03, 0x1e, 0xb1, 0x04, 0xfe, - 0xd9, 0xf2, 0x31, 0x5b, 0xf2, 0x68, 0xb2, 0xbd, 0x59, 0xf6, 0xfb, 0xa5, 0x17, 0x7a, 0xf5, 0x2c, 0xfb, 0x2e, 0x9a, - 0xcf, 0xaa, 0xb9, 0x8f, 0x8a, 0x8b, 0xc9, 0x60, 0xb0, 0xf5, 0xb3, 0xe1, 0x90, 0x25, 0xc3, 0xe1, 0x24, 0xfb, 0x0e, - 0x5e, 0xfb, 0x8e, 0x47, 0x6a, 0x49, 0x25, 0x37, 0x19, 0xec, 0xef, 0x03, 0x1e, 0xf9, 0xac, 0xf3, 0xd3, 0xb2, 0xe9, - 0xd2, 0xfd, 0xcc, 0x8e, 0xbb, 0xd0, 0x1d, 0x60, 0xe3, 0x6d, 0x83, 0x8e, 0xfc, 0xeb, 0x1d, 0x52, 0xea, 0x26, 0x03, - 0xb0, 0x1b, 0x0d, 0x70, 0xc8, 0x54, 0x2f, 0x45, 0x56, 0x2f, 0x65, 0xaa, 0x97, 0x64, 0xe5, 0x12, 0x2c, 0x24, 0xa6, - 0xca, 0x6d, 0x65, 0xe5, 0x96, 0x0d, 0xd7, 0xc3, 0xc1, 0x36, 0x8a, 0xcb, 0x66, 0x05, 0xf7, 0x85, 0x35, 0x05, 0xfe, - 0xdf, 0xb1, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x5b, 0x74, 0x4c, 0x82, 0x0b, 0xc4, 0x3d, 0xbb, 0x03, 0x3b, 0x2c, 0xfc, - 0x05, 0xd7, 0xc9, 0x31, 0xdb, 0xe3, 0xa3, 0xd0, 0x2b, 0xd8, 0x9d, 0x4f, 0x40, 0xbb, 0x60, 0x6b, 0x80, 0x6c, 0x6c, - 0x87, 0x8f, 0x56, 0xc7, 0xe3, 0x5b, 0xcf, 0x67, 0x0f, 0xf8, 0xe3, 0x72, 0x75, 0x3c, 0xee, 0x3d, 0xa3, 0xde, 0xbb, - 0xe5, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xed, 0x0d, 0x8f, 0x27, 0x83, 0xc1, 0xad, 0xbf, 0xe0, 0xf5, 0xec, 0x16, 0xb4, - 0x03, 0x97, 0x0b, 0xa9, 0x6b, 0xf6, 0xee, 0x78, 0xe6, 0x2d, 0x70, 0x6c, 0xee, 0xe0, 0xe8, 0xed, 0xf7, 0xbd, 0x15, - 0x8f, 0xbc, 0x3b, 0x52, 0x31, 0xad, 0xb9, 0xe2, 0x78, 0xdb, 0xe1, 0x7e, 0xba, 0xe6, 0x21, 0x3c, 0xc2, 0xaa, 0x4c, - 0x6f, 0x83, 0xf7, 0x3e, 0x5b, 0x6b, 0x16, 0xb8, 0x07, 0xcc, 0xb1, 0x21, 0x3b, 0xa1, 0x99, 0xf8, 0x6b, 0xec, 0x9f, - 0x5b, 0xd5, 0x3f, 0x34, 0xff, 0x4b, 0xdd, 0x4f, 0xe0, 0xf6, 0x45, 0x16, 0x24, 0xf6, 0x9e, 0xdf, 0xb2, 0x7b, 0x6e, - 0xd8, 0x66, 0x2f, 0x4c, 0xd9, 0x67, 0x4a, 0x8d, 0x1f, 0x29, 0x75, 0x63, 0x19, 0x56, 0x32, 0x77, 0x5f, 0x46, 0xe0, - 0x70, 0x40, 0x7e, 0x5a, 0x21, 0x0e, 0x42, 0xeb, 0x26, 0xab, 0xb9, 0xa2, 0x9c, 0x0b, 0x6d, 0x99, 0x79, 0x15, 0xb0, - 0x98, 0xa5, 0x14, 0x1a, 0x0b, 0x00, 0x04, 0x93, 0x42, 0x6b, 0xef, 0x65, 0x00, 0x39, 0x41, 0xc3, 0x9f, 0x9a, 0xab, - 0xa2, 0xac, 0x65, 0x4b, 0x42, 0x94, 0xed, 0x7a, 0x78, 0x8d, 0x90, 0x69, 0xfd, 0xfe, 0x25, 0x91, 0xac, 0x4d, 0xf2, - 0x9b, 0x1a, 0x2d, 0x01, 0x39, 0x59, 0x02, 0x26, 0x7e, 0xae, 0xf9, 0x04, 0xe0, 0x49, 0xc7, 0x83, 0xfc, 0x3b, 0x5e, - 0x33, 0x41, 0x64, 0x1b, 0xb9, 0x3f, 0x29, 0x9e, 0x23, 0x19, 0x41, 0xf1, 0x5d, 0xad, 0x32, 0x16, 0x86, 0x79, 0xa0, - 0x80, 0xbc, 0x07, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, 0xe8, - 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x3d, 0x89, 0x6e, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, 0x67, - 0xd1, 0x77, 0xf9, 0x7c, 0x42, 0x4a, 0xb2, 0xe3, 0x31, 0x1b, 0x55, 0x75, 0xb1, 0x99, 0x86, 0xf2, 0xa7, 0x87, 0xe0, - 0xeb, 0x05, 0xf5, 0x9a, 0xac, 0x52, 0xfd, 0x1d, 0x55, 0xca, 0x8b, 0x86, 0xd7, 0xfe, 0x77, 0xb9, 0xdc, 0xf7, 0x80, - 0xb4, 0x96, 0x97, 0x5c, 0xbe, 0x1f, 0x21, 0xc6, 0x88, 0x1f, 0x78, 0x25, 0x8f, 0x58, 0xa8, 0xa6, 0x70, 0xcd, 0x23, - 0x04, 0x79, 0xcb, 0x74, 0xf0, 0xb7, 0x9e, 0x38, 0xdd, 0x9f, 0x28, 0xed, 0xe2, 0x0b, 0x8b, 0xba, 0x27, 0x6b, 0xeb, - 0x06, 0xe4, 0x60, 0xc3, 0x74, 0x51, 0x90, 0x6d, 0x4a, 0x23, 0x68, 0xa3, 0xe5, 0xc0, 0x86, 0x93, 0xab, 0x0d, 0x67, - 0xae, 0x21, 0xb8, 0x2f, 0x2f, 0xd3, 0xd1, 0x02, 0x3e, 0xa4, 0xba, 0xbd, 0xc4, 0xcf, 0x87, 0x0d, 0x8f, 0x80, 0xcc, - 0x8e, 0xf8, 0xcc, 0x26, 0x92, 0x4e, 0xea, 0x52, 0x01, 0xbb, 0x5d, 0xbc, 0x05, 0x39, 0x62, 0xe6, 0xbe, 0x42, 0xf5, - 0x2d, 0x1a, 0x70, 0x65, 0xac, 0x7d, 0x4d, 0x32, 0x16, 0xde, 0x94, 0xd3, 0x70, 0x90, 0xc3, 0x73, 0xfa, 0xda, 0x72, - 0x9b, 0x65, 0x3f, 0x17, 0x10, 0x04, 0x51, 0x12, 0x8f, 0x0f, 0x78, 0x5f, 0xe6, 0x43, 0x8d, 0x92, 0x8f, 0x65, 0x23, - 0x95, 0x5e, 0x89, 0xfe, 0x6e, 0xcc, 0x25, 0x06, 0x7c, 0x9b, 0xb7, 0x05, 0x85, 0xcb, 0xea, 0x78, 0xbc, 0xac, 0x46, - 0xc6, 0xb3, 0x0c, 0x54, 0x2b, 0xd3, 0x3a, 0x88, 0xcd, 0x7c, 0xb1, 0xf0, 0x17, 0x3b, 0x27, 0x11, 0x51, 0x10, 0xd8, - 0x91, 0xf0, 0x20, 0x52, 0xbf, 0xcc, 0x3d, 0xdd, 0xa9, 0x3e, 0x3b, 0x2c, 0x6c, 0x22, 0xbd, 0xa0, 0x64, 0xf2, 0x49, - 0x70, 0x50, 0xfd, 0x1d, 0x84, 0x0d, 0xe1, 0xcd, 0xab, 0x5e, 0x67, 0x99, 0x9a, 0x95, 0x20, 0x61, 0xc6, 0x1c, 0xc1, - 0xe3, 0xb0, 0xd3, 0xd8, 0x96, 0xc7, 0x16, 0x1c, 0x9d, 0xb7, 0x61, 0x2b, 0xb6, 0x66, 0x77, 0xaa, 0x4e, 0x0b, 0x1e, - 0x4e, 0x87, 0xd7, 0x01, 0xae, 0xbe, 0xcd, 0x25, 0xe7, 0x2b, 0x3a, 0xc1, 0x36, 0x03, 0x1e, 0x4d, 0xc4, 0x6c, 0xf3, - 0x5d, 0xa4, 0x16, 0xcf, 0x66, 0xc8, 0x17, 0xb4, 0xfe, 0xc4, 0x6c, 0x65, 0x92, 0x57, 0x03, 0xbe, 0x98, 0x6c, 0xbe, - 0x8b, 0xe0, 0xd5, 0xef, 0xc0, 0x8a, 0x91, 0x39, 0xb3, 0x6c, 0xf3, 0x5d, 0x84, 0x63, 0xb6, 0xfa, 0x2e, 0xa2, 0x51, - 0x5b, 0xcb, 0x7d, 0xe9, 0xae, 0x01, 0x61, 0xe5, 0x8e, 0xc5, 0xf0, 0x1a, 0x88, 0x67, 0xda, 0x48, 0xba, 0x91, 0x86, - 0xde, 0x98, 0x87, 0xd3, 0x38, 0xd8, 0x50, 0x2b, 0xe4, 0x99, 0x21, 0x66, 0xf1, 0x77, 0xd1, 0x9c, 0xad, 0xb1, 0x22, - 0x5b, 0x1e, 0x0f, 0xae, 0x27, 0xdb, 0x1b, 0xbe, 0x01, 0xf2, 0xb3, 0xc9, 0xd6, 0x6c, 0x51, 0x77, 0x5c, 0xcc, 0xb6, - 0xdf, 0x45, 0xf3, 0xc9, 0x1a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x35, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, 0x3d, - 0xb6, 0x19, 0x07, 0x2b, 0xb6, 0xb9, 0x0e, 0xee, 0xd8, 0x66, 0x0c, 0x44, 0x1c, 0xd4, 0xef, 0xde, 0x16, 0x16, 0x5f, - 0xc4, 0x36, 0xd7, 0x26, 0x6d, 0xfb, 0x5d, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xcd, 0xbc, 0x35, 0x83, 0x4b, - 0xc8, 0xd2, 0x8b, 0xd9, 0x76, 0x78, 0xcd, 0x36, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0x56, 0xfc, 0x8e, 0x25, 0x7c, 0xdd, - 0xc4, 0x37, 0x5b, 0xd0, 0x88, 0x9e, 0x64, 0xd0, 0x57, 0x50, 0x33, 0x73, 0x5e, 0x5a, 0x50, 0xb9, 0x87, 0x16, 0x1c, - 0x50, 0x90, 0xb6, 0x01, 0x82, 0x24, 0x9e, 0xdd, 0xcb, 0x70, 0x73, 0x2b, 0x85, 0x01, 0x37, 0x81, 0x19, 0x30, 0x30, - 0xfd, 0x0c, 0x7e, 0x58, 0xe9, 0x12, 0x21, 0xce, 0x7e, 0x4a, 0x49, 0x32, 0xcf, 0x4f, 0x45, 0x9a, 0xbb, 0x85, 0xeb, - 0x14, 0x66, 0x45, 0x81, 0xea, 0xa7, 0xa4, 0x34, 0xb0, 0x50, 0x89, 0x4c, 0xa5, 0xe0, 0x97, 0xcd, 0x79, 0x94, 0x9d, - 0xa2, 0x73, 0x5d, 0x5e, 0x4f, 0x9c, 0xd3, 0x49, 0xdf, 0x7f, 0xe0, 0x18, 0xb6, 0x90, 0x81, 0x0b, 0x7f, 0xea, 0x09, - 0xe3, 0xd4, 0x0a, 0xc4, 0x54, 0xf2, 0xec, 0x29, 0x7c, 0x26, 0xb4, 0x3a, 0xba, 0xf0, 0xfd, 0xa0, 0xd0, 0x26, 0xe9, - 0x16, 0x24, 0x29, 0x78, 0x8a, 0x5e, 0x72, 0xde, 0x06, 0x2a, 0xc5, 0x88, 0x16, 0x44, 0xda, 0x5a, 0x66, 0x0e, 0xd2, - 0x96, 0xe6, 0xbb, 0x26, 0x7e, 0x0e, 0x0b, 0xb8, 0x88, 0x16, 0x76, 0xa5, 0xe0, 0x51, 0x15, 0x2b, 0xf7, 0x36, 0xcf, - 0x11, 0xce, 0xe8, 0x5a, 0x26, 0x00, 0xae, 0xf7, 0xab, 0xb0, 0x56, 0x78, 0x45, 0xcd, 0x22, 0x2f, 0x6a, 0xfa, 0x64, - 0x0b, 0xdc, 0xc7, 0xa2, 0x44, 0x81, 0xb3, 0x16, 0x0c, 0xd8, 0x0a, 0x4b, 0x76, 0x52, 0xd8, 0x14, 0x2d, 0xa1, 0x77, - 0xc0, 0x4f, 0x07, 0x35, 0x93, 0x01, 0x34, 0x01, 0x34, 0x1e, 0xff, 0x02, 0x50, 0xd3, 0xdb, 0x5a, 0x6c, 0xaa, 0xa0, - 0x54, 0xca, 0x4d, 0xf8, 0x19, 0x18, 0x66, 0xf8, 0xa1, 0x90, 0xdb, 0x44, 0x89, 0x9c, 0x1f, 0x8b, 0x52, 0x2c, 0x4b, - 0x51, 0x25, 0xed, 0x86, 0x82, 0x47, 0x84, 0xdb, 0xa0, 0x31, 0x73, 0x7b, 0xa2, 0x8b, 0x56, 0x84, 0x72, 0x6c, 0x37, - 0x31, 0xd2, 0x28, 0xb3, 0xb3, 0x5d, 0x27, 0x0b, 0xed, 0xf7, 0x55, 0x0e, 0x59, 0x07, 0xac, 0x91, 0x7c, 0xbd, 0xe6, - 0xd0, 0x6d, 0xa3, 0xbc, 0x78, 0xf0, 0x7c, 0x05, 0xa7, 0x39, 0x9e, 0xd8, 0x5d, 0xaf, 0x3b, 0x45, 0x22, 0x5e, 0xe1, - 0xa4, 0xaa, 0x46, 0xb2, 0x70, 0xdc, 0xb9, 0xd3, 0x5a, 0xac, 0x95, 0x4c, 0xe3, 0x72, 0xd0, 0x00, 0xd0, 0x0c, 0x3e, - 0x95, 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, - 0x11, 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0xf3, 0x4a, - 0x0f, 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, - 0x3c, 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, - 0x5d, 0x28, 0xe7, 0x4c, 0xce, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, - 0x8c, 0x4e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x56, 0xa9, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, - 0xc6, 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, - 0x94, 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x07, 0x59, 0x14, 0x38, 0x80, - 0xab, 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0x0e, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, - 0xcc, 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, - 0xb4, 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x4f, 0x5f, - 0xa7, 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7d, 0x41, 0x11, 0x17, 0x35, 0xb8, - 0xf2, 0xce, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, - 0x0e, 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x46, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xac, 0x58, 0x3e, 0x5a, 0xa8, 0xcc, - 0x08, 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xd3, 0x3d, 0xba, 0xab, 0xce, - 0x32, 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, - 0x77, 0x9d, 0xe5, 0x5b, 0xa9, 0x66, 0x6b, 0x28, 0x2a, 0xb5, 0x92, 0x14, 0x07, 0x19, 0xae, 0xdb, 0xdc, 0x87, 0xcd, - 0x14, 0xf4, 0x8c, 0x91, 0xc8, 0x3c, 0x7f, 0x22, 0x5f, 0x82, 0x73, 0xc6, 0x59, 0x21, 0x30, 0x61, 0xac, 0xde, 0xb5, - 0x96, 0x4a, 0x43, 0x8a, 0xb1, 0x93, 0x51, 0x96, 0x55, 0x96, 0x2e, 0xb3, 0xb5, 0x84, 0x2d, 0xab, 0xc8, 0x2d, 0x6c, - 0x99, 0xc9, 0x6a, 0xbe, 0xcf, 0xb9, 0x83, 0xf2, 0xcd, 0x36, 0x19, 0x3f, 0x48, 0x64, 0xef, 0x36, 0x50, 0xc2, 0xf3, - 0xd1, 0x7f, 0x20, 0xfd, 0x36, 0xc3, 0x38, 0xe5, 0xb6, 0x92, 0x16, 0xe0, 0xf4, 0x8f, 0xc7, 0xf7, 0x39, 0x06, 0x0d, - 0x8e, 0x30, 0x8e, 0xac, 0xdf, 0xbf, 0xcb, 0xbd, 0x1a, 0x13, 0x75, 0xf4, 0x42, 0xbf, 0x9f, 0xd3, 0xc3, 0x69, 0x3e, - 0x5a, 0xa7, 0x3b, 0x64, 0x27, 0xb4, 0xb1, 0xf2, 0x83, 0x5a, 0x01, 0xb3, 0xb7, 0x3e, 0x9f, 0x0e, 0x40, 0xc7, 0x02, - 0x24, 0x9a, 0xcd, 0x44, 0x62, 0x4e, 0xba, 0x27, 0xe1, 0xe9, 0x81, 0x05, 0x0e, 0x30, 0x39, 0xff, 0x87, 0xf0, 0x66, - 0x60, 0x83, 0x46, 0x89, 0xbe, 0x46, 0x57, 0xb5, 0xb9, 0xd1, 0xf1, 0xd2, 0x53, 0x48, 0x64, 0x05, 0xcb, 0xe7, 0xbe, - 0xdc, 0xc0, 0x69, 0x0f, 0x35, 0x87, 0xca, 0x12, 0x3c, 0x3d, 0x97, 0xf9, 0xf1, 0xb8, 0xc9, 0xa0, 0xb0, 0xfd, 0x46, - 0x68, 0x6f, 0xcc, 0x52, 0x0d, 0x15, 0xe1, 0xa0, 0xf3, 0xb5, 0x98, 0xd5, 0x23, 0xfa, 0x7b, 0x7e, 0x3c, 0xae, 0x09, - 0x0c, 0x38, 0x2c, 0x65, 0x26, 0x5a, 0x28, 0x96, 0xd6, 0xd9, 0x8c, 0xea, 0xc0, 0x03, 0x13, 0x73, 0x16, 0xee, 0x01, - 0xb4, 0x49, 0xad, 0x02, 0xbd, 0x8a, 0xe8, 0x27, 0xee, 0xd7, 0xf6, 0xeb, 0xf5, 0xc8, 0x2c, 0x1d, 0xb9, 0x31, 0x16, - 0x00, 0x1c, 0x78, 0x59, 0x93, 0x3c, 0x27, 0x5f, 0x43, 0xbb, 0x27, 0x17, 0xf2, 0x27, 0x28, 0x5b, 0x78, 0xa5, 0x9a, - 0x56, 0x16, 0x6b, 0xae, 0xaa, 0x57, 0x17, 0x3c, 0x37, 0x99, 0xd6, 0x69, 0x25, 0x54, 0xac, 0x5f, 0x43, 0x5d, 0xe2, - 0xb5, 0xa6, 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x79, 0x6d, - 0x1c, 0x3e, 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0xab, 0x1a, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, - 0xc5, 0xc4, 0xee, 0xd0, 0xaa, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, - 0x01, 0x2f, 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x72, 0x26, - 0xc0, 0x0f, 0x4a, 0xad, 0xe9, 0x83, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, - 0xe7, 0xe3, 0xe5, 0xb5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x55, 0xab, 0x7f, 0x98, 0xea, 0x5b, - 0xe8, 0x4e, 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, - 0x1c, 0xec, 0x0d, 0x70, 0xe2, 0x97, 0xc7, 0xa3, 0xb8, 0xa9, 0x7c, 0x76, 0xd9, 0x35, 0xb2, 0x72, 0x00, 0x73, 0x88, - 0x82, 0x71, 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xcd, 0xf8, 0xf4, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0x55, - 0xdf, 0x3d, 0x03, 0xd2, 0xb2, 0x7e, 0x3f, 0x7a, 0x7e, 0x3d, 0x7d, 0x36, 0x8c, 0x02, 0x70, 0xec, 0xb2, 0x97, 0x97, - 0x31, 0x5f, 0x5d, 0x33, 0xcb, 0x14, 0x16, 0xf9, 0x66, 0x40, 0x75, 0xc9, 0x6a, 0xe9, 0x7a, 0x05, 0x58, 0xba, 0xfc, - 0xe6, 0x21, 0x4c, 0x0d, 0x68, 0x64, 0xcd, 0xdd, 0x69, 0xae, 0x05, 0x4a, 0x3d, 0xef, 0x67, 0x86, 0x7c, 0x5d, 0x06, - 0x5d, 0x41, 0xba, 0xe7, 0x11, 0xe9, 0xe5, 0x41, 0x3a, 0xdd, 0x1f, 0x4a, 0x01, 0x96, 0xfa, 0x52, 0x7c, 0x06, 0x85, - 0x45, 0xe3, 0x1b, 0x01, 0xda, 0x1a, 0xaa, 0x69, 0xaf, 0x14, 0x55, 0x2f, 0xe8, 0x95, 0xe2, 0x73, 0x4f, 0x0f, 0x95, - 0xf9, 0xb2, 0x74, 0xf4, 0x3f, 0xa3, 0xe6, 0x82, 0x13, 0x62, 0x26, 0xe6, 0x00, 0x2a, 0x41, 0x1b, 0xdf, 0xfa, 0x64, - 0xe3, 0x53, 0xbd, 0x8a, 0x9b, 0x3e, 0xaf, 0xad, 0x65, 0x4e, 0x08, 0x9b, 0xee, 0x25, 0x40, 0x45, 0x5e, 0x09, 0x8f, - 0x60, 0xf9, 0xe5, 0x0f, 0x79, 0xba, 0x42, 0xb4, 0x8e, 0x7b, 0x96, 0xb9, 0x34, 0xf6, 0xaf, 0x0d, 0xa6, 0xaf, 0x6f, - 0xb7, 0x45, 0x7e, 0x6a, 0x62, 0xc2, 0x7a, 0xac, 0xe8, 0x9b, 0x77, 0xe1, 0x5a, 0xa0, 0xc0, 0xa1, 0x44, 0x62, 0x9b, - 0x2a, 0x14, 0xf1, 0x20, 0xe9, 0xd3, 0x45, 0xeb, 0xd3, 0x00, 0x53, 0x6b, 0x39, 0x30, 0x87, 0x70, 0x15, 0x17, 0x3e, - 0x7a, 0xfa, 0x16, 0xb3, 0x70, 0x3e, 0xf1, 0x3e, 0x7a, 0xc5, 0xc8, 0x7c, 0xdc, 0x47, 0xa5, 0x92, 0xfe, 0x79, 0x3c, - 0xce, 0xf2, 0xb9, 0xef, 0xd0, 0x47, 0x7a, 0xa8, 0x72, 0x41, 0xd9, 0x1b, 0x63, 0x12, 0x81, 0xd2, 0x18, 0xef, 0xe3, - 0xe0, 0x38, 0xef, 0xd3, 0x00, 0x52, 0xfb, 0xc4, 0x7b, 0x52, 0x72, 0x78, 0xce, 0x31, 0x27, 0x94, 0x56, 0x84, 0xe5, - 0x7c, 0x91, 0xa1, 0x5c, 0x77, 0x4e, 0xc1, 0x24, 0x87, 0x04, 0xc3, 0x5f, 0x35, 0x6f, 0x62, 0x05, 0xc2, 0xae, 0x91, - 0x33, 0x47, 0x4f, 0xaa, 0x24, 0x2c, 0x05, 0x1c, 0x95, 0x99, 0x67, 0xd8, 0x1b, 0x9e, 0x18, 0x46, 0x0e, 0x56, 0xf9, - 0xa3, 0x3a, 0x11, 0xb9, 0x47, 0x17, 0x18, 0x95, 0x85, 0x57, 0x0d, 0x5d, 0x69, 0x50, 0x49, 0x76, 0xfa, 0x15, 0xd7, - 0x80, 0xda, 0x1a, 0x23, 0x96, 0x83, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, - 0x95, 0xdc, 0xf5, 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, - 0x2c, 0x85, 0x23, 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, - 0x42, 0x9a, 0x6c, 0x5f, 0xcf, 0x3f, 0xe4, 0x5a, 0x90, 0x95, 0x5b, 0xce, 0xe9, 0xb0, 0xf8, 0xc6, 0xd9, 0x57, 0x39, - 0x79, 0x8a, 0x59, 0x46, 0x7a, 0xa7, 0x98, 0x17, 0xf0, 0xa7, 0xb2, 0xd4, 0x93, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, - 0x97, 0xde, 0xb6, 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0x0f, 0xf1, 0x48, 0x9e, 0x61, 0x5b, 0x96, 0xb0, 0xd0, 0x2a, - 0x18, 0x03, 0x48, 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x8f, 0xc7, 0xcb, 0xad, 0x39, 0x4b, 0x0e, 0xe0, 0xfa, 0xca, - 0x13, 0xf3, 0x0e, 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x5b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, - 0x62, 0xad, 0x63, 0xc9, 0xad, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0x7f, 0x70, 0x83, 0xab, - 0x6b, 0x63, 0x50, 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0x8b, 0x8a, 0x7c, 0xf9, 0xad, - 0x9d, 0x03, 0x82, 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, - 0x33, 0xd8, 0xc4, 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, - 0xab, 0x85, 0x48, 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, - 0x41, 0x27, 0x68, 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, - 0x07, 0x99, 0x13, 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, - 0x74, 0x28, 0x59, 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, - 0x0a, 0x5c, 0x08, 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xd5, 0xb4, 0x90, 0xa6, 0x81, 0x6a, - 0x9a, 0x3b, 0xe6, 0x81, 0xbd, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0x55, 0xfc, 0x83, 0x74, 0x2f, 0xce, - 0xe1, 0x2f, 0x6b, 0xfa, 0x20, 0xc2, 0x46, 0x0e, 0x1a, 0x4b, 0x89, 0xb1, 0x51, 0xe1, 0xdf, 0x12, 0x65, 0x43, 0x86, - 0x80, 0x10, 0xd2, 0x46, 0x45, 0x3f, 0xac, 0x2f, 0xef, 0x32, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, - 0xa9, 0x47, 0x3c, 0x5e, 0x1b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, - 0x28, 0x17, 0xbc, 0xe2, 0x39, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xa8, 0xe8, 0xf3, 0x39, 0xf0, 0x4c, - 0x40, 0xa0, 0x63, 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0xb7, 0x48, - 0x94, 0xfa, 0x8a, 0x94, 0xa4, 0x6f, 0x45, 0x8d, 0x57, 0x62, 0x15, 0x91, 0x40, 0x86, 0x1a, 0x22, 0x56, 0xd5, 0x53, - 0xf7, 0xa6, 0x98, 0x0c, 0x06, 0xb9, 0x2f, 0xa7, 0x27, 0xde, 0xd0, 0x50, 0x79, 0xd7, 0x15, 0xed, 0xf4, 0x44, 0x2b, - 0xe5, 0x2d, 0xa4, 0x25, 0x68, 0x1a, 0x46, 0x9a, 0x43, 0xa9, 0x6b, 0xe9, 0x6e, 0x0c, 0xe2, 0x4b, 0x26, 0x7a, 0xb6, - 0x53, 0x3b, 0x4a, 0x5b, 0xd2, 0x1e, 0x42, 0x7a, 0xee, 0x92, 0x8f, 0x21, 0x42, 0x4c, 0x55, 0xa5, 0xbc, 0x09, 0xd1, - 0xc9, 0xfd, 0x80, 0x21, 0x11, 0xe8, 0x73, 0x8e, 0x61, 0x5d, 0x34, 0xd4, 0x18, 0x6c, 0x6d, 0xb6, 0x50, 0xc2, 0x7c, - 0xc9, 0x78, 0x2a, 0x19, 0x34, 0x00, 0x32, 0xe0, 0xb3, 0x97, 0x81, 0xe5, 0xaf, 0x20, 0x7e, 0xb4, 0xf1, 0xf1, 0xf8, - 0x67, 0x4d, 0x21, 0xb6, 0x7f, 0xc2, 0x66, 0x08, 0x8f, 0xea, 0x01, 0xcf, 0x7c, 0x13, 0x27, 0x68, 0x05, 0x24, 0x65, - 0x76, 0x34, 0x91, 0xbd, 0xea, 0x21, 0x9c, 0xca, 0x0a, 0xd4, 0x51, 0xd6, 0x59, 0x09, 0x3f, 0xc2, 0x54, 0xb7, 0x12, - 0x6b, 0x81, 0x36, 0x57, 0x2b, 0xd6, 0x02, 0x38, 0xf0, 0x2b, 0x08, 0x9e, 0xa8, 0xe6, 0xe0, 0x62, 0x50, 0x80, 0xcf, - 0x01, 0xf0, 0x22, 0x77, 0xe1, 0xc1, 0x3c, 0xb2, 0xac, 0x46, 0x18, 0x8e, 0x2a, 0x62, 0xfd, 0x9a, 0xed, 0xc8, 0x07, - 0x6e, 0xc7, 0xf8, 0x5c, 0x7b, 0x2c, 0x59, 0x0e, 0x46, 0x99, 0x7b, 0xb5, 0x44, 0xcf, 0x9b, 0x34, 0x6e, 0x46, 0x4f, - 0x0e, 0xb5, 0xfc, 0x5f, 0xd0, 0xcb, 0xa0, 0xbf, 0x85, 0x5b, 0x5e, 0xf3, 0xbb, 0x05, 0x91, 0x66, 0x7a, 0x05, 0x91, - 0x32, 0x6a, 0x44, 0xc6, 0x10, 0x36, 0xa9, 0x6e, 0x65, 0x93, 0xea, 0x42, 0xc0, 0xd3, 0x09, 0xa9, 0xae, 0x85, 0xb4, - 0x51, 0x4d, 0xeb, 0x40, 0xc6, 0x22, 0xbd, 0xfb, 0xf1, 0x2f, 0x2f, 0x3e, 0xbd, 0xf9, 0xe5, 0xc7, 0xc5, 0x9b, 0x77, - 0xaf, 0xdf, 0xbc, 0x7b, 0xf3, 0xe9, 0x37, 0x82, 0xf0, 0x98, 0x0a, 0x95, 0xe1, 0xc3, 0xfb, 0xdb, 0x37, 0x4e, 0x06, - 0xdb, 0x9b, 0x21, 0x6b, 0xdf, 0xc8, 0xc1, 0x10, 0x88, 0x6c, 0x10, 0x32, 0xc8, 0x4e, 0x6d, 0xfb, 0x33, 0x31, 0xc7, - 0xd8, 0x3b, 0x81, 0xc9, 0x16, 0x24, 0x87, 0x65, 0x5e, 0x32, 0x22, 0x57, 0x8e, 0xd6, 0x0f, 0x68, 0xc1, 0x5b, 0x70, - 0x91, 0x49, 0xf3, 0xd5, 0x2f, 0x04, 0xb1, 0x4f, 0x2b, 0xa9, 0xf2, 0xd5, 0xb6, 0xe6, 0xf9, 0xf6, 0x7e, 0x9f, 0xd3, - 0x8a, 0x99, 0x4b, 0x23, 0x6a, 0x01, 0x0e, 0xc0, 0x97, 0xf0, 0xc7, 0x8d, 0xb6, 0xa4, 0xc9, 0x2c, 0xfa, 0x2c, 0x84, - 0xa0, 0x4b, 0x03, 0x69, 0x62, 0x8f, 0xbc, 0xd4, 0x27, 0x0b, 0x09, 0xdc, 0x11, 0xc3, 0xa7, 0x15, 0x41, 0xaf, 0x18, - 0x51, 0x5c, 0x72, 0x85, 0x4a, 0x29, 0xf9, 0x37, 0xca, 0x2e, 0x2a, 0xe4, 0xac, 0x60, 0xf7, 0x8a, 0x1c, 0x19, 0x3f, - 0x08, 0x26, 0xbe, 0x0a, 0xdc, 0x7f, 0x89, 0x77, 0x38, 0x53, 0x1c, 0xc9, 0x09, 0x7f, 0xc8, 0x30, 0xb0, 0xbf, 0x02, - 0x9f, 0x57, 0x87, 0x79, 0x79, 0xab, 0x4f, 0xb9, 0x25, 0x1f, 0x4f, 0x96, 0x37, 0x60, 0xb0, 0x5f, 0xaa, 0xe6, 0x6e, - 0x78, 0x3d, 0x5b, 0xce, 0xd9, 0x61, 0x16, 0xcd, 0x83, 0x15, 0x9b, 0x65, 0xf3, 0x60, 0xdd, 0xf0, 0x0d, 0xbb, 0xe3, - 0x1b, 0xab, 0x6a, 0x1b, 0xbb, 0x6a, 0x93, 0x2d, 0xbf, 0x03, 0x09, 0xe1, 0x36, 0xf3, 0x72, 0x96, 0xb0, 0x95, 0xcf, - 0xb6, 0x20, 0xd1, 0xae, 0xd9, 0x16, 0x2e, 0x62, 0x1b, 0xfe, 0x63, 0xee, 0x6d, 0x59, 0xc9, 0x2e, 0xc7, 0xac, 0xc2, - 0xf9, 0xe7, 0xc3, 0x03, 0xda, 0x0b, 0xf5, 0xb3, 0x6b, 0xf5, 0x6c, 0xa2, 0xec, 0x66, 0xdb, 0xd1, 0xe2, 0x3e, 0xad, - 0xb6, 0x61, 0x86, 0x9e, 0xe5, 0xf0, 0xd1, 0x56, 0x0a, 0x7e, 0x7a, 0x81, 0x5f, 0xb2, 0xa3, 0xb6, 0xd2, 0xb6, 0x5d, - 0x95, 0xd8, 0x0a, 0x5a, 0x14, 0x59, 0xad, 0xf0, 0xc0, 0x8a, 0x3f, 0x87, 0x05, 0x8c, 0x3d, 0xc7, 0x39, 0xaf, 0xfd, - 0x11, 0x32, 0xde, 0x3b, 0x00, 0x68, 0x99, 0xe3, 0x00, 0x8f, 0x58, 0x31, 0x8a, 0x06, 0xef, 0xf2, 0x5a, 0x59, 0xad, - 0x34, 0x27, 0xa1, 0x6d, 0xc4, 0xaa, 0xe5, 0x48, 0xd5, 0x8c, 0x48, 0x1f, 0xa4, 0xe7, 0x7d, 0x8f, 0xa8, 0x06, 0x7b, - 0x32, 0xaf, 0x03, 0xfb, 0xf4, 0xb2, 0xb5, 0xaa, 0x3b, 0xbf, 0xa7, 0x4a, 0x97, 0x1c, 0xd9, 0xf2, 0xd3, 0x65, 0xf8, - 0xa0, 0xfe, 0x94, 0x5c, 0x1f, 0x0a, 0x1c, 0xe1, 0xb1, 0x0a, 0x38, 0x5f, 0xcf, 0x45, 0xbb, 0x13, 0x61, 0x57, 0x2e, - 0x01, 0x21, 0xbe, 0xa4, 0x69, 0x8e, 0xc7, 0x11, 0x4d, 0x44, 0xd8, 0xc4, 0xe8, 0x2f, 0xec, 0x3e, 0x94, 0x58, 0x2e, - 0x2b, 0x0d, 0x4a, 0x2e, 0x19, 0xbc, 0x27, 0xed, 0x35, 0x68, 0x96, 0x57, 0xae, 0x26, 0x13, 0x39, 0x28, 0x1f, 0x8f, - 0x05, 0xec, 0xa5, 0xc6, 0x4f, 0x13, 0x7e, 0xc2, 0xf2, 0xd6, 0xde, 0x9a, 0x52, 0x54, 0xd2, 0x00, 0x15, 0xf8, 0x98, - 0xc1, 0xff, 0xee, 0x0c, 0xb1, 0x60, 0x8a, 0x4e, 0x1f, 0xce, 0xc4, 0xdc, 0x7a, 0x6e, 0x95, 0x75, 0x92, 0xad, 0x51, - 0x4e, 0xc0, 0xbf, 0xa5, 0x3a, 0x4e, 0x12, 0xe1, 0xd4, 0x7b, 0xc4, 0x45, 0xdd, 0xcb, 0x21, 0xea, 0x86, 0xbd, 0xc9, - 0x75, 0xb0, 0xe5, 0x34, 0x0d, 0x4e, 0xc4, 0xaf, 0xd4, 0x67, 0xef, 0x33, 0x8b, 0x47, 0x1d, 0xd9, 0x88, 0x92, 0x34, - 0x8e, 0x45, 0x0e, 0xdb, 0xfb, 0x42, 0xee, 0xff, 0xfd, 0x3e, 0x84, 0x93, 0x56, 0x41, 0x52, 0x7a, 0x02, 0x11, 0xe1, - 0xe8, 0xf0, 0x23, 0xc2, 0x13, 0xa9, 0x2a, 0x7c, 0x52, 0x9f, 0xb9, 0x31, 0xbb, 0x17, 0xe6, 0xa8, 0xde, 0x01, 0x0c, - 0x63, 0xbd, 0xb3, 0x08, 0x49, 0xb4, 0xd2, 0x8c, 0xb6, 0x1e, 0x10, 0x23, 0xde, 0x6f, 0x2c, 0x32, 0x18, 0x6b, 0x4b, - 0x22, 0x01, 0x7c, 0x45, 0x42, 0x86, 0xb6, 0x8d, 0xc0, 0x8c, 0xe1, 0xed, 0xac, 0xb8, 0x74, 0x1d, 0xb6, 0x39, 0x87, - 0x2f, 0x64, 0xa1, 0x59, 0x47, 0x94, 0x26, 0x08, 0xf9, 0x07, 0x9c, 0x2c, 0x14, 0x46, 0xf3, 0xea, 0x24, 0x9d, 0x24, - 0xd6, 0xf7, 0x5d, 0xa5, 0x82, 0xcd, 0xe6, 0x16, 0xf5, 0x65, 0x27, 0xc9, 0x2f, 0xc1, 0x49, 0xc7, 0x49, 0x16, 0x39, - 0x88, 0x5a, 0x54, 0xce, 0x6d, 0x12, 0x96, 0x76, 0x75, 0xaa, 0xed, 0x66, 0x53, 0x94, 0x75, 0xf5, 0x4a, 0x44, 0x8a, - 0xde, 0x47, 0x3d, 0x7a, 0x22, 0x21, 0x15, 0x5a, 0x95, 0xda, 0xe7, 0x11, 0xb8, 0x6d, 0x6a, 0xc5, 0xb6, 0x5c, 0xc2, - 0x12, 0x35, 0xfe, 0x13, 0xf4, 0x51, 0x2e, 0x1e, 0x64, 0x80, 0x46, 0xc7, 0x53, 0xf3, 0xd6, 0x23, 0xaf, 0x9c, 0xe4, - 0x97, 0x56, 0x9b, 0xf4, 0x0b, 0x20, 0x33, 0xda, 0x3f, 0x5a, 0x4a, 0x20, 0x33, 0x30, 0x93, 0x96, 0x86, 0x44, 0x8e, - 0x62, 0x96, 0xe6, 0x7f, 0xe0, 0x8a, 0xad, 0x10, 0x69, 0x58, 0xcd, 0x3d, 0xfe, 0x22, 0xf7, 0x6a, 0xb9, 0x96, 0x99, - 0xe6, 0x66, 0x89, 0x63, 0xc5, 0xe2, 0xa2, 0x5e, 0x57, 0x22, 0x0b, 0x84, 0x38, 0xc2, 0x34, 0xd6, 0x53, 0x6f, 0x94, - 0x56, 0x1f, 0x90, 0x50, 0xe6, 0x47, 0xec, 0xed, 0xd8, 0xeb, 0x41, 0x16, 0xe2, 0xd8, 0x72, 0xb0, 0xd9, 0x7a, 0x9f, - 0xca, 0x54, 0xc4, 0x17, 0x75, 0x71, 0xb1, 0xad, 0xc4, 0x45, 0x9d, 0x88, 0x8b, 0xef, 0x21, 0xe7, 0xf7, 0x17, 0x54, - 0xf4, 0xc5, 0x43, 0x5a, 0x27, 0xc5, 0xb6, 0xa6, 0x27, 0xaf, 0xb1, 0x8c, 0xef, 0x2f, 0x88, 0xab, 0xe6, 0x82, 0x46, - 0x32, 0x1e, 0x5d, 0x7c, 0xc8, 0x80, 0xe4, 0xf5, 0x22, 0x5d, 0xc3, 0xe0, 0x5d, 0x84, 0x79, 0x7c, 0x51, 0x8a, 0x15, - 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x3a, 0xfc, 0x43, 0x5c, 0x00, 0xb4, 0xeb, 0x45, 0x5a, 0x5f, 0xa4, 0xd5, - 0x45, 0x5e, 0xd4, 0x17, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, 0x4f, 0x5f, 0xd9, 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, - 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x72, 0xe1, 0xb5, 0xfb, 0xdb, 0xe6, 0xfe, 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, - 0x46, 0x74, 0x41, 0x3d, 0x5d, 0x49, 0x4a, 0x05, 0x05, 0x04, 0x4e, 0x34, 0x6b, 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, - 0x5b, 0xb2, 0x8d, 0xcf, 0x9f, 0xc7, 0x32, 0x4c, 0x7b, 0x1b, 0xe0, 0x5f, 0x65, 0x6f, 0xba, 0x09, 0x96, 0x78, 0xdf, - 0x42, 0xb6, 0xa1, 0x37, 0xaf, 0xf8, 0x0b, 0xaf, 0x52, 0x7f, 0xb3, 0x7f, 0x00, 0x10, 0x06, 0xc4, 0xac, 0xfa, 0x68, - 0xe2, 0xde, 0x5b, 0x59, 0xf6, 0x4e, 0x96, 0x7d, 0x0f, 0xfd, 0x9a, 0xc4, 0xa8, 0xb4, 0xb2, 0x94, 0x4e, 0x96, 0x12, - 0xb2, 0x80, 0x4f, 0x8c, 0xa6, 0x36, 0x02, 0x08, 0xdb, 0x51, 0x2a, 0x5f, 0x00, 0xc2, 0x49, 0x02, 0x12, 0x62, 0x09, - 0x17, 0xa3, 0x7b, 0x2b, 0x19, 0x30, 0x1c, 0x42, 0x30, 0x07, 0xed, 0xb0, 0x37, 0x74, 0x13, 0xf1, 0xd7, 0xeb, 0xa2, - 0x7c, 0x13, 0x93, 0x4f, 0xc1, 0xfe, 0xec, 0xe3, 0x12, 0x1e, 0x97, 0x67, 0x1f, 0x87, 0xe8, 0x91, 0x70, 0xf6, 0x31, - 0xf8, 0x1e, 0xc9, 0x79, 0xdd, 0xf5, 0x38, 0x41, 0x6e, 0x21, 0xdd, 0xdf, 0x8e, 0x49, 0x80, 0xe6, 0x35, 0x2c, 0x47, - 0x4d, 0xc5, 0x35, 0x33, 0x63, 0x3c, 0x6f, 0xf4, 0xfe, 0xd8, 0xf1, 0x96, 0x29, 0x14, 0xb3, 0x98, 0xd7, 0xf0, 0x7b, - 0x56, 0x05, 0xea, 0xae, 0xb7, 0x49, 0x6e, 0x99, 0xd5, 0x73, 0xb4, 0xfb, 0xbe, 0xaf, 0x13, 0x41, 0xed, 0xef, 0xb0, - 0xe7, 0x99, 0xf5, 0xae, 0x8a, 0x81, 0x4b, 0x95, 0xec, 0x90, 0xa9, 0x6a, 0x7a, 0xa0, 0x52, 0x1a, 0x3c, 0xbd, 0xb4, - 0x2e, 0x5f, 0x2a, 0x6d, 0xe4, 0x99, 0xe6, 0x37, 0x80, 0x17, 0x53, 0x97, 0xc5, 0xfe, 0xab, 0xfb, 0x0a, 0x6e, 0xe3, - 0xfd, 0xfe, 0x32, 0xf7, 0xcc, 0x4f, 0x5c, 0x00, 0xf6, 0xa6, 0x42, 0xeb, 0x04, 0x4a, 0x0d, 0xeb, 0xf0, 0x65, 0x22, - 0xa2, 0x3f, 0xda, 0xe5, 0x3a, 0x73, 0x1d, 0x30, 0xa2, 0x88, 0xdf, 0xc6, 0xa3, 0x3f, 0x40, 0x71, 0x6d, 0xec, 0x01, - 0x61, 0x1d, 0x12, 0xfa, 0x8c, 0x00, 0xa4, 0x1e, 0x73, 0x94, 0x80, 0x66, 0x45, 0x73, 0xc7, 0xc0, 0xc1, 0x2f, 0xaf, - 0x94, 0xfe, 0x61, 0x99, 0x7b, 0x64, 0x4e, 0x69, 0x9b, 0x69, 0xac, 0xd6, 0xe4, 0x02, 0xe1, 0x15, 0x95, 0xac, 0xc2, - 0x67, 0xf3, 0x46, 0xf4, 0xfb, 0xf2, 0x08, 0x4f, 0xab, 0x1f, 0x77, 0x18, 0xdf, 0x0a, 0x88, 0x46, 0x02, 0xa0, 0x9f, - 0x00, 0xe6, 0x45, 0x36, 0xb3, 0xfb, 0x38, 0xa0, 0x4a, 0x89, 0xa6, 0x71, 0x36, 0xcf, 0x6f, 0xe9, 0x4d, 0xd9, 0x41, - 0xe7, 0x4e, 0x15, 0xb8, 0xe0, 0xaa, 0x64, 0xbc, 0xb2, 0x9e, 0xc9, 0xe7, 0x37, 0x77, 0xdb, 0x34, 0x8b, 0xdf, 0x97, - 0xff, 0xc0, 0xb1, 0xd5, 0x75, 0x78, 0x64, 0xea, 0x74, 0xed, 0x3c, 0xd2, 0xda, 0x0b, 0x01, 0x11, 0xed, 0x1a, 0x6a, - 0xbd, 0xb0, 0xd0, 0x23, 0x3d, 0x11, 0xce, 0x49, 0xa2, 0xa6, 0x1d, 0x68, 0x69, 0x84, 0xbe, 0xbe, 0xca, 0x8b, 0x2e, - 0x06, 0x6b, 0x5f, 0x8e, 0x59, 0x0e, 0x5d, 0xaa, 0x1e, 0xab, 0x87, 0xc6, 0x66, 0x0e, 0x3d, 0x6b, 0x55, 0x9e, 0x79, - 0xf9, 0xf1, 0x88, 0xf8, 0x30, 0xfa, 0x4b, 0x7e, 0xbf, 0xff, 0x8a, 0xe6, 0x1f, 0x13, 0x6a, 0xfc, 0x6c, 0x33, 0x40, - 0xd7, 0xbe, 0x2b, 0x0f, 0x44, 0x3d, 0xd7, 0x2a, 0x41, 0x88, 0x37, 0x88, 0x89, 0x66, 0xc4, 0x1c, 0x9c, 0x76, 0xa8, - 0xf9, 0x27, 0xa9, 0x01, 0x21, 0x4a, 0xbc, 0x8e, 0x29, 0x0b, 0x72, 0xda, 0xc4, 0x91, 0x7e, 0x14, 0x4e, 0xe4, 0x47, - 0x51, 0x15, 0xd9, 0x3d, 0x5c, 0x30, 0x98, 0x7a, 0x4f, 0xfb, 0x25, 0xfa, 0x2d, 0xe1, 0xc8, 0x39, 0x5a, 0x15, 0x82, - 0xc8, 0x19, 0x61, 0xad, 0x21, 0x4c, 0x10, 0x1b, 0xc4, 0xcb, 0xbe, 0x4b, 0x32, 0x1c, 0x29, 0xb8, 0xac, 0x63, 0xc7, - 0x98, 0xab, 0xa3, 0xea, 0x35, 0x80, 0xf1, 0xaa, 0x10, 0x34, 0x1b, 0x45, 0x76, 0x09, 0x51, 0x45, 0x8e, 0x27, 0xa0, - 0x76, 0x50, 0x1a, 0x9b, 0xe9, 0xe5, 0x38, 0x80, 0x09, 0x8e, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x2b, 0xd5, - 0xcf, 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x9c, 0xe9, - 0x72, 0x60, 0xdc, 0xb7, 0x3c, 0xa7, 0x38, 0xc3, 0x8f, 0x5e, 0x3e, 0xab, 0xe7, 0xfe, 0x74, 0x4b, 0xed, 0xc7, 0xdc, - 0xa8, 0x87, 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, - 0xfc, 0x43, 0x99, 0xae, 0x53, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, - 0xa2, 0xac, 0xdf, 0x87, 0xdf, 0x37, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, - 0x93, 0x41, 0x0d, 0xda, 0xf0, 0x2d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, - 0xec, 0x4f, 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xeb, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xa7, 0x97, 0xfc, - 0x06, 0xbd, 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, - 0x8f, 0x51, 0xc9, 0x62, 0x4b, 0x8f, 0x95, 0xd3, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x0e, 0xc1, - 0x12, 0x18, 0x17, 0xb1, 0xe1, 0xdb, 0x41, 0xc5, 0xe2, 0xd9, 0x76, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1e, 0x0b, 0x09, - 0x36, 0x93, 0xcd, 0x36, 0x73, 0xb6, 0xf1, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, - 0x35, 0x58, 0xad, 0xa6, 0xec, 0x54, 0x53, 0xf6, 0x4e, 0x53, 0x4e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, - 0x88, 0x4d, 0xa2, 0x9b, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, - 0x50, 0x85, 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, - 0xbe, 0xa5, 0x8e, 0x07, 0x94, 0x6d, 0xfe, 0x26, 0xf6, 0x41, 0x88, 0xdc, 0x8d, 0x7b, 0xf5, 0x33, 0xe2, 0xbd, 0xfd, - 0x09, 0xc6, 0x4f, 0x76, 0xda, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8c, 0xca, 0x24, 0x41, 0x2d, 0x4b, 0xe2, - 0x6f, 0x79, 0x32, 0xa8, 0xd8, 0x12, 0x3c, 0x68, 0xe7, 0x2c, 0x03, 0xfc, 0x15, 0xab, 0x45, 0xbf, 0xd5, 0xde, 0x12, - 0xe4, 0xa7, 0xad, 0xdd, 0x28, 0x4c, 0x8c, 0x20, 0x51, 0xb7, 0x2b, 0x03, 0xf9, 0xe1, 0x03, 0x4e, 0xc7, 0x53, 0x4f, - 0x19, 0x73, 0x2b, 0xd3, 0xcb, 0x74, 0xae, 0xe4, 0x1b, 0xb9, 0x97, 0x3e, 0xf6, 0x12, 0xec, 0x1c, 0xf0, 0x06, 0xd2, - 0x06, 0xde, 0xc2, 0x76, 0xe1, 0xb5, 0x41, 0xc2, 0x8c, 0x00, 0x5b, 0x9c, 0x1e, 0x23, 0x25, 0x30, 0x84, 0xe3, 0x2c, - 0x05, 0x60, 0x1a, 0x7d, 0x99, 0xcd, 0xed, 0xcb, 0xac, 0xd6, 0x6c, 0xa9, 0x9c, 0xee, 0x9d, 0x5b, 0xb7, 0xf3, 0x89, - 0x04, 0x00, 0x93, 0x3a, 0x07, 0xe2, 0xcc, 0x04, 0xbb, 0x34, 0x89, 0x2c, 0x1f, 0xc3, 0x7c, 0x25, 0x5e, 0x97, 0xc5, - 0x5a, 0x75, 0x45, 0xdb, 0x67, 0xa6, 0x9a, 0x91, 0x4e, 0x42, 0x05, 0x14, 0x14, 0x72, 0xad, 0x4f, 0xdf, 0x85, 0xef, - 0x82, 0x42, 0x03, 0xb3, 0xe5, 0xb8, 0xa7, 0xc9, 0x1a, 0xa9, 0x37, 0xf2, 0x7e, 0x9f, 0x5c, 0x03, 0xa9, 0xce, 0x1c, - 0x5a, 0xf6, 0x04, 0x9d, 0x64, 0x4f, 0x6e, 0xca, 0x52, 0xa8, 0x03, 0xa9, 0x07, 0x0c, 0x21, 0xda, 0xa6, 0x8f, 0x3f, - 0x19, 0x12, 0x5d, 0x80, 0x2d, 0x44, 0x1b, 0xf8, 0xf1, 0x27, 0xd8, 0x67, 0x41, 0x78, 0x4c, 0xf3, 0xb7, 0x90, 0x74, - 0x6a, 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0x95, - 0x94, 0xea, 0x00, 0x6d, 0x4a, 0xb9, 0xab, 0x2b, 0x3f, 0x88, 0xb6, 0xe0, 0xc8, 0x22, 0xfe, 0x3e, 0x43, 0x44, 0x30, - 0x33, 0x88, 0xb0, 0x6b, 0xa1, 0xee, 0xf6, 0x9c, 0x5a, 0x16, 0xf5, 0xb6, 0xe7, 0x94, 0xba, 0x0d, 0xc3, 0x77, 0x13, - 0xcc, 0x14, 0x37, 0xfc, 0x8f, 0xcc, 0x0b, 0xf5, 0xc6, 0x63, 0x51, 0xa0, 0x7b, 0xfe, 0x61, 0xc9, 0xf3, 0xd9, 0x56, - 0x99, 0x30, 0x57, 0x7c, 0x39, 0x0b, 0x65, 0x57, 0x4b, 0xe3, 0xce, 0x67, 0x6f, 0xa9, 0xe6, 0x83, 0x7f, 0x3c, 0x26, - 0x10, 0x6f, 0x14, 0xdf, 0xac, 0x1a, 0xb9, 0x75, 0x4d, 0xb6, 0x37, 0x25, 0xa0, 0x7e, 0x5f, 0x6e, 0x70, 0xbf, 0xc5, - 0xfa, 0x77, 0x4f, 0x83, 0x8c, 0xd5, 0x0c, 0x57, 0x4c, 0xe1, 0x53, 0x00, 0x18, 0x1c, 0x4e, 0x05, 0x69, 0x81, 0xb7, - 0xbc, 0x1c, 0x5e, 0x4f, 0xb6, 0x64, 0xd2, 0xdd, 0xfa, 0xc8, 0x9d, 0x05, 0xaa, 0xde, 0x6f, 0x28, 0x4e, 0x1a, 0x24, - 0x1a, 0x7b, 0x0d, 0xbe, 0xc8, 0x32, 0xca, 0x45, 0x13, 0xf7, 0x31, 0xf9, 0x4a, 0x0f, 0x60, 0xa5, 0x42, 0x09, 0x10, - 0xfd, 0xc6, 0xb2, 0xd8, 0x88, 0xb6, 0xc5, 0x06, 0x96, 0x52, 0x3e, 0xd7, 0xab, 0xe9, 0xb3, 0x57, 0xa2, 0x79, 0x1f, - 0xcd, 0x38, 0xa5, 0xd1, 0x80, 0xe3, 0x34, 0x0a, 0x77, 0xef, 0xef, 0x45, 0xb9, 0xcc, 0xc0, 0x92, 0xad, 0xc2, 0x29, - 0xae, 0x1b, 0x75, 0x46, 0xbc, 0xc8, 0x63, 0x05, 0xd0, 0xf1, 0x98, 0x00, 0xa8, 0x2e, 0x08, 0xa8, 0x88, 0x96, 0xd2, - 0x5b, 0xa1, 0xc5, 0x42, 0xbd, 0xe1, 0x28, 0x85, 0x3f, 0xd2, 0x9f, 0x07, 0xd5, 0x14, 0x80, 0xd8, 0xf5, 0x71, 0xf4, - 0xba, 0x28, 0xe9, 0x53, 0xc5, 0xac, 0x92, 0x83, 0x09, 0xec, 0xea, 0x44, 0x86, 0x9a, 0x43, 0xde, 0xbc, 0x2b, 0x6f, - 0x6e, 0xf2, 0x36, 0xc6, 0x29, 0xf9, 0x91, 0x9b, 0x8e, 0x35, 0x62, 0xe0, 0x95, 0xa7, 0x75, 0x9a, 0x20, 0x4d, 0x2e, - 0x80, 0x61, 0x88, 0xef, 0x32, 0xef, 0x85, 0xe7, 0x48, 0x55, 0x90, 0xcc, 0xf6, 0x99, 0xa7, 0x2e, 0xa2, 0xfa, 0xca, - 0xa9, 0xa5, 0x33, 0xa7, 0x1f, 0x01, 0xbc, 0xc7, 0xd4, 0xa4, 0x21, 0x1f, 0xe1, 0xb6, 0x14, 0x5f, 0xef, 0xd4, 0x35, - 0x5e, 0x1a, 0x9d, 0xbb, 0x97, 0x2f, 0xdd, 0x69, 0xd0, 0x4f, 0x41, 0x50, 0xce, 0x17, 0xa5, 0x80, 0x3d, 0x65, 0x36, - 0xd7, 0xab, 0x55, 0x2b, 0xb4, 0x8e, 0xc7, 0xb1, 0x76, 0x14, 0xd2, 0xea, 0x2c, 0x60, 0xab, 0x91, 0x4e, 0x09, 0x10, - 0x82, 0xe3, 0x34, 0xec, 0x0c, 0xe3, 0x2e, 0x9d, 0x46, 0x64, 0xbd, 0x52, 0x92, 0x2e, 0xcc, 0x20, 0xf9, 0x27, 0x79, - 0x3d, 0x03, 0x5a, 0x02, 0x38, 0x14, 0xb1, 0x84, 0x87, 0x93, 0xe4, 0x06, 0xa0, 0xd3, 0xe1, 0xa0, 0xd2, 0xd0, 0x9c, - 0xf9, 0x2c, 0x99, 0x4f, 0x62, 0xa9, 0xaa, 0x3c, 0x1e, 0x3d, 0xe5, 0x66, 0xd0, 0xef, 0x67, 0xd3, 0x52, 0xb9, 0x00, - 0x04, 0xb1, 0x2e, 0x0c, 0x10, 0x8f, 0xb4, 0xf0, 0x64, 0xd1, 0xa7, 0x24, 0x7e, 0x39, 0x4b, 0xe6, 0x26, 0x1b, 0xde, - 0x81, 0x11, 0x6c, 0xc6, 0x75, 0x49, 0x99, 0xf6, 0xa8, 0xfc, 0x9e, 0xd1, 0x53, 0xdb, 0xd7, 0x5a, 0x6d, 0x11, 0xeb, - 0x3a, 0xb8, 0x2a, 0x51, 0x4f, 0xf1, 0x41, 0x49, 0x82, 0xf7, 0x2b, 0xe7, 0x66, 0xa4, 0x7c, 0x2d, 0x2a, 0x3f, 0x68, - 0x67, 0x6a, 0xe5, 0xc0, 0x11, 0xa8, 0xb0, 0x8a, 0x4a, 0x5e, 0xef, 0x3a, 0x04, 0x4f, 0xee, 0x4a, 0x05, 0xca, 0xc1, - 0xcf, 0x41, 0x8c, 0xae, 0x6f, 0x3a, 0x6b, 0xa8, 0x99, 0x46, 0x95, 0x47, 0xd0, 0xb9, 0x03, 0x78, 0x52, 0xf0, 0x52, - 0xab, 0x1f, 0x8f, 0x47, 0xcf, 0xfc, 0xe0, 0x2f, 0x33, 0x7d, 0x0b, 0x31, 0x51, 0x4e, 0x35, 0x42, 0xe2, 0x4a, 0x49, - 0x22, 0x3e, 0x5d, 0xb4, 0xac, 0x18, 0x95, 0xe1, 0x03, 0xb0, 0x00, 0x51, 0xf9, 0xea, 0x54, 0xe5, 0xc5, 0x48, 0xdb, - 0x12, 0x78, 0x4d, 0xfe, 0x21, 0x72, 0xcd, 0x5b, 0x5f, 0x77, 0x95, 0xa1, 0x6f, 0x65, 0x05, 0x3a, 0x82, 0xad, 0x2c, - 0x25, 0x07, 0x7c, 0x52, 0xdf, 0x55, 0x5b, 0x9f, 0x53, 0xb6, 0x11, 0x6e, 0xf2, 0xeb, 0xd8, 0xc1, 0x91, 0xf2, 0x1b, - 0xbc, 0x14, 0xc0, 0x5e, 0x03, 0xf6, 0xe6, 0x8a, 0x15, 0xcd, 0xa3, 0x43, 0xda, 0x16, 0x68, 0x64, 0xe6, 0x76, 0xae, - 0xee, 0xdb, 0xf2, 0x28, 0x8d, 0x21, 0x32, 0xed, 0x91, 0xe9, 0x60, 0x33, 0xca, 0x7f, 0x4b, 0xf9, 0xad, 0xc2, 0x31, - 0xf0, 0xed, 0xdc, 0x3b, 0x80, 0xaa, 0xa7, 0x0d, 0x32, 0xd6, 0x0c, 0x43, 0x2b, 0xbb, 0x5c, 0x0a, 0x2d, 0x41, 0x4b, - 0xdd, 0x04, 0xc1, 0xf9, 0x11, 0x51, 0x8e, 0x00, 0x74, 0x91, 0x02, 0x26, 0xf8, 0x39, 0x6d, 0x77, 0xbf, 0xbf, 0x49, - 0x3d, 0x72, 0xef, 0x0a, 0x95, 0xcd, 0xf2, 0x4d, 0x8e, 0x30, 0xf6, 0x13, 0x8d, 0x19, 0x74, 0x72, 0x45, 0x4e, 0x78, - 0xd6, 0xea, 0xb0, 0xae, 0x9b, 0x32, 0x28, 0x8b, 0x63, 0x9e, 0x4f, 0x67, 0xbf, 0x3f, 0x39, 0xd4, 0x0d, 0xb2, 0x90, - 0xff, 0xce, 0x7a, 0x48, 0x06, 0xdd, 0x83, 0x50, 0x88, 0xde, 0x3c, 0x98, 0xe1, 0x7f, 0x6c, 0xcb, 0xb3, 0x6f, 0xb8, - 0x51, 0x27, 0x80, 0x39, 0xe2, 0x7a, 0xe9, 0x29, 0xda, 0x7a, 0xb8, 0x05, 0xb2, 0x0d, 0x5e, 0xde, 0xda, 0x6b, 0xa0, - 0xa2, 0x38, 0xfe, 0x15, 0xcf, 0xd4, 0xca, 0x06, 0x3f, 0x3d, 0x65, 0x3b, 0xf0, 0xf0, 0x22, 0x04, 0x14, 0xc3, 0xb2, - 0xf1, 0x2b, 0xcb, 0x71, 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, - 0x93, 0x7b, 0x2b, 0x72, 0xca, 0x5c, 0xe9, 0x61, 0x74, 0x5d, 0x92, 0xbe, 0x49, 0x3e, 0xb6, 0x86, 0xed, 0x77, 0xed, - 0x7e, 0x33, 0x44, 0x10, 0x42, 0x39, 0x7e, 0xce, 0xe8, 0x84, 0xc6, 0x87, 0x35, 0xd7, 0x3b, 0xbd, 0x7e, 0xef, 0x12, - 0x2f, 0xd8, 0x1a, 0x0d, 0xf0, 0x74, 0xe8, 0x62, 0x9e, 0xa8, 0xa1, 0xd3, 0x75, 0xed, 0x1c, 0x3c, 0x30, 0xc8, 0xf2, - 0xe4, 0x1b, 0x86, 0x25, 0xf6, 0x27, 0x11, 0x4f, 0xda, 0xaa, 0x8d, 0xed, 0x89, 0x6a, 0xa3, 0x66, 0xe0, 0x07, 0xaf, - 0xa0, 0xc0, 0xe8, 0x82, 0xb4, 0x06, 0xe3, 0x70, 0x04, 0x20, 0x2b, 0xc6, 0xf1, 0xc8, 0x60, 0x02, 0x43, 0xba, 0xa1, - 0x28, 0x00, 0x0f, 0x8f, 0xd3, 0x41, 0xc8, 0x00, 0xd2, 0x05, 0x0f, 0x0d, 0xdb, 0x24, 0xa4, 0xfc, 0x3c, 0x2f, 0x6b, - 0x35, 0x84, 0xbe, 0xb3, 0x50, 0x1d, 0xfb, 0x91, 0xf6, 0x8a, 0x75, 0xad, 0x4a, 0x27, 0xb6, 0x3a, 0x40, 0xdf, 0x90, - 0x81, 0x6f, 0x1d, 0x5b, 0x00, 0x44, 0x4b, 0xfc, 0x96, 0x7a, 0xb5, 0x2f, 0x63, 0x56, 0xa8, 0xd7, 0x17, 0xa6, 0x5d, - 0xaf, 0xa4, 0x45, 0x01, 0x15, 0xb7, 0xad, 0xda, 0x9e, 0xc8, 0xf9, 0x8f, 0xef, 0x3a, 0xda, 0xf1, 0xd9, 0xa9, 0xb1, - 0x25, 0x94, 0xb9, 0xc5, 0x13, 0x59, 0x1d, 0x6d, 0xa9, 0x4e, 0xf5, 0x01, 0x97, 0x9a, 0x54, 0x67, 0xda, 0xa7, 0xc9, - 0x12, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xc1, 0xf9, 0x64, 0x50, 0x30, 0xb7, 0x48, 0x40, 0x02, 0xdb, 0xda, 0xda, - 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xf2, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, 0xce, 0xde, 0x69, 0x2d, 0x20, 0x80, - 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, 0xe5, 0x6f, 0x29, 0x2a, 0x62, 0xcf, - 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, 0x3a, 0x6a, 0x72, 0xd7, 0xcd, 0x55, - 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xbe, 0xd6, 0x95, 0x53, 0xef, 0x83, 0x8a, 0x23, 0x06, 0x82, 0x9b, 0xee, 0xf1, 0xc1, - 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, 0x68, 0xc5, 0xf4, 0x11, 0x00, 0x11, - 0x60, 0x95, 0xa8, 0xff, 0xcd, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, 0xb6, 0xde, 0x3f, 0xaf, 0x91, 0x56, - 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, 0xff, 0x9f, 0xfb, 0x00, 0x35, 0xa2, - 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2a, 0x7c, 0xe3, 0x87, 0x8c, 0xf3, 0xc1, 0x0c, 0x1d, 0xd5, 0xe6, - 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, 0x4f, 0xdc, 0x67, 0x5c, 0x7b, 0x41, - 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, 0x65, 0x93, 0x48, 0x7d, 0x33, 0x06, - 0x05, 0x40, 0xf1, 0x3c, 0x27, 0xb9, 0x74, 0x91, 0xe6, 0x95, 0x28, 0x6b, 0xdd, 0x8c, 0x9c, 0x15, 0xc3, 0x9c, 0xd5, - 0x7e, 0x50, 0xdc, 0xe4, 0x66, 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x7c, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, - 0xd2, 0xbb, 0x1c, 0xb7, 0xce, 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, - 0x3f, 0xe3, 0xcf, 0x09, 0x4c, 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x9c, 0x97, 0x93, - 0x70, 0x38, 0xf4, 0x41, 0x1f, 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, - 0x10, 0xd1, 0x42, 0x43, 0x1f, 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, - 0xda, 0xd0, 0x22, 0xc5, 0x45, 0xa3, 0xcc, 0x66, 0x95, 0xec, 0x84, 0xad, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, - 0x54, 0xad, 0xa7, 0x7a, 0x3d, 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa2, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, - 0xa3, 0x6a, 0x93, 0xa5, 0x11, 0x55, 0x6e, 0x52, 0xb9, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0xcd, 0xb5, 0xb3, 0x35, 0x38, - 0x71, 0xe4, 0xb9, 0xe4, 0x96, 0xef, 0xce, 0x2b, 0xba, 0x3b, 0xd5, 0xbe, 0x05, 0xb8, 0x37, 0xc3, 0x86, 0xcc, 0x79, - 0x8d, 0x9d, 0x06, 0x61, 0x12, 0xf8, 0x11, 0xfb, 0x98, 0x21, 0x1b, 0x0c, 0xe8, 0x28, 0xa4, 0x26, 0xc0, 0x32, 0x47, - 0x02, 0x26, 0x7f, 0x3d, 0xf7, 0x9b, 0x45, 0x91, 0xc3, 0x62, 0xfc, 0xb0, 0xc5, 0x48, 0x63, 0xb5, 0x06, 0xc3, 0x72, - 0x85, 0xc8, 0x9f, 0xda, 0x33, 0xd4, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, 0xa7, 0x4f, 0x75, 0x7d, 0xfe, 0xdb, - 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xc1, 0x2d, 0xce, 0x1d, 0x89, 0xde, 0xa9, 0xd2, 0xcc, 0x2e, - 0xed, 0x9a, 0x5d, 0x9b, 0xd2, 0x6e, 0xc9, 0xf5, 0xea, 0x2b, 0xe5, 0x8d, 0x9d, 0x57, 0x4c, 0xf7, 0x1f, 0x84, 0xde, - 0x51, 0xce, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, 0x26, 0x55, 0xbb, 0x84, 0x93, 0xae, - 0x61, 0x95, 0xf9, 0xf6, 0x3f, 0xf2, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, 0xfd, 0x29, 0x88, 0xab, 0xfa, 0xc3, - 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe4, 0x9e, 0x42, 0xd8, 0x60, 0xf6, 0xf3, - 0xd3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x9a, 0x11, 0xde, 0xef, 0x18, 0xe7, 0xfe, 0xcd, - 0x0f, 0x6a, 0x72, 0x84, 0x88, 0x76, 0x11, 0x0e, 0x00, 0xe2, 0x4e, 0x53, 0x59, 0x87, 0x1a, 0xa0, 0x0f, 0x08, 0xac, - 0x43, 0xdf, 0x66, 0x00, 0x07, 0x7d, 0xb4, 0x79, 0x16, 0x81, 0xbc, 0xee, 0xdd, 0xb3, 0xb7, 0x6c, 0xef, 0xf3, 0xe7, - 0xeb, 0xd4, 0xbb, 0x47, 0x87, 0xe0, 0xcb, 0xb1, 0x3f, 0xbd, 0x0e, 0x0c, 0x2e, 0x34, 0x7b, 0xfb, 0x54, 0xb0, 0x3d, - 0xdb, 0x3f, 0x45, 0xa4, 0xa2, 0xee, 0xfc, 0xc3, 0x6b, 0x13, 0x3d, 0xef, 0xbc, 0xb0, 0xe2, 0x4b, 0x00, 0x0f, 0x64, - 0x31, 0xa0, 0xf8, 0x2c, 0xbd, 0x7f, 0xb2, 0x04, 0xd4, 0xe4, 0x77, 0x7c, 0xe3, 0xbd, 0xa3, 0xd4, 0x05, 0xfc, 0x39, - 0xa0, 0xf4, 0x49, 0xc5, 0xbd, 0xd5, 0xf0, 0xce, 0xbf, 0x7a, 0x06, 0xce, 0x13, 0xeb, 0xe1, 0x02, 0xfe, 0x2a, 0xf8, - 0xd0, 0x5b, 0x0d, 0x30, 0xb1, 0xe4, 0x43, 0x6f, 0x3d, 0x80, 0x54, 0x85, 0x0b, 0x89, 0xb1, 0x0f, 0xbf, 0x06, 0x15, - 0xc3, 0x3f, 0x7e, 0xd3, 0x18, 0xac, 0xbf, 0x06, 0x85, 0x46, 0x63, 0x2d, 0x55, 0xc8, 0x52, 0x2c, 0x2e, 0x04, 0xd8, - 0x84, 0xe3, 0x6e, 0x5f, 0xac, 0x6a, 0xbb, 0x11, 0xf4, 0xe7, 0x23, 0xbe, 0x47, 0x63, 0x75, 0x55, 0xce, 0x45, 0xf9, - 0x11, 0xe9, 0x53, 0x1d, 0x1f, 0xa3, 0x62, 0x5b, 0x77, 0xa7, 0x53, 0xad, 0x3a, 0xd2, 0x7e, 0x53, 0xae, 0xc1, 0x8e, - 0xd7, 0xc9, 0x89, 0xa5, 0xf0, 0xa2, 0xc3, 0xce, 0x4b, 0xa7, 0x44, 0x87, 0x61, 0xbc, 0xdb, 0xaa, 0x67, 0x0c, 0xe5, - 0x95, 0xc1, 0x98, 0x2e, 0x78, 0xc4, 0x9f, 0x0f, 0x2a, 0x19, 0x1a, 0xf3, 0x01, 0xd9, 0x30, 0x94, 0x0f, 0x2d, 0x32, - 0x24, 0x44, 0xbc, 0x87, 0x4a, 0xc0, 0xb6, 0x05, 0x65, 0x52, 0xc0, 0x59, 0x34, 0xf8, 0xad, 0xf6, 0x2a, 0xe0, 0x3d, - 0x88, 0xfc, 0x46, 0xba, 0x94, 0x4b, 0x6c, 0x74, 0xe2, 0x58, 0x16, 0xda, 0x79, 0x5c, 0x7f, 0x1d, 0x83, 0xfa, 0xbd, - 0xd2, 0x6f, 0x50, 0xce, 0xfe, 0x28, 0x59, 0xa7, 0x8d, 0x27, 0xc6, 0xdf, 0x5d, 0xe5, 0x9f, 0xa2, 0xa5, 0x1e, 0xfe, - 0x3f, 0x63, 0x0a, 0xa5, 0x7f, 0x99, 0x96, 0xd1, 0x76, 0xbd, 0x14, 0xa5, 0xc8, 0x23, 0x71, 0xf6, 0xb5, 0xc8, 0xce, - 0xe5, 0x3b, 0x9f, 0x42, 0xbf, 0x00, 0xb4, 0xec, 0x13, 0x64, 0xf4, 0x0f, 0x4c, 0xf0, 0xe1, 0x0f, 0xda, 0xb9, 0xb6, - 0xe2, 0xe3, 0x49, 0x75, 0x63, 0xed, 0xdd, 0x8e, 0x17, 0x89, 0x51, 0x8c, 0x55, 0xbe, 0xea, 0x66, 0xe5, 0x44, 0x25, - 0x07, 0x46, 0xba, 0x26, 0x7b, 0x95, 0x92, 0x75, 0x3b, 0xdd, 0x4a, 0x20, 0xa2, 0x0a, 0xbc, 0xc7, 0xb8, 0x8a, 0x7d, - 0x04, 0xd3, 0x75, 0xc7, 0x65, 0xb4, 0xe3, 0x3d, 0xe3, 0xd5, 0x89, 0xb2, 0x82, 0xdb, 0x8d, 0x68, 0x4f, 0xe8, 0xe8, - 0xa7, 0x49, 0x6d, 0x59, 0x38, 0x00, 0xb9, 0x4b, 0x18, 0xcb, 0x86, 0x60, 0xc5, 0xa0, 0xf4, 0xf5, 0x9a, 0x92, 0x65, - 0x01, 0x16, 0x9d, 0x5d, 0x46, 0x20, 0x86, 0x75, 0xd3, 0x9c, 0xd1, 0xf1, 0xd2, 0xc5, 0xf9, 0xa0, 0x55, 0xa4, 0xe0, - 0x19, 0x2d, 0x3a, 0xe6, 0xa6, 0x23, 0xdd, 0x18, 0xed, 0xed, 0x0f, 0x06, 0x21, 0xc5, 0xf3, 0x07, 0xb6, 0x5a, 0x17, - 0x17, 0x89, 0x57, 0xc8, 0x44, 0x0b, 0x62, 0x29, 0x02, 0x33, 0x5e, 0x68, 0x1a, 0x61, 0x82, 0x32, 0x25, 0x58, 0xb4, - 0x46, 0x87, 0xf6, 0x87, 0x25, 0xec, 0x1e, 0x63, 0x04, 0x08, 0x54, 0x99, 0x3e, 0x87, 0xad, 0x09, 0xb3, 0xad, 0x8b, - 0x2d, 0xd0, 0x56, 0x31, 0x34, 0x08, 0x6b, 0x43, 0xcc, 0xc7, 0x34, 0x5f, 0xfd, 0x13, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, - 0xc1, 0xed, 0x9a, 0x84, 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xaa, 0x1d, 0x6b, - 0xa9, 0x77, 0xac, 0x8d, 0xde, 0xb1, 0x56, 0x0d, 0xff, 0x90, 0x79, 0x31, 0x4b, 0x40, 0xbf, 0xbb, 0xe6, 0xaa, 0x41, - 0xd0, 0x8c, 0x2d, 0xbb, 0x83, 0xdf, 0x12, 0x6b, 0xb7, 0xf4, 0xaf, 0x96, 0x6c, 0x61, 0xfa, 0x40, 0xb7, 0x0e, 0xb0, - 0x8c, 0xa8, 0xc9, 0xf7, 0xc8, 0xbb, 0xe9, 0xac, 0x28, 0xdc, 0x9e, 0xd8, 0xc2, 0x67, 0x6f, 0xcd, 0x9b, 0xf7, 0x4f, - 0x23, 0xc8, 0xbd, 0xe7, 0xde, 0xfd, 0xf0, 0xad, 0x7f, 0xa5, 0x5b, 0x20, 0x27, 0xb3, 0x9c, 0x81, 0xd4, 0x11, 0x9f, - 0x20, 0x5a, 0xd9, 0x53, 0xbe, 0x13, 0x72, 0x67, 0xdb, 0x3c, 0xbd, 0x77, 0xb7, 0xb5, 0xd5, 0xd3, 0x7b, 0x96, 0x8f, - 0x28, 0x56, 0x9c, 0xa6, 0x48, 0x98, 0x45, 0x5b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xfd, 0xd3, 0x8e, - 0x8e, 0x97, 0x73, 0xc0, 0xee, 0xfe, 0x93, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0xf7, 0x4f, 0x33, 0x8d, 0xe7, - 0x70, 0x22, 0x9f, 0x8e, 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, - 0xd6, 0x35, 0x6f, 0xaf, 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, - 0x70, 0xba, 0xe4, 0xb1, 0xef, 0xd3, 0x2c, 0xad, 0xf7, 0xa8, 0xb5, 0xc8, 0x2d, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, - 0x61, 0xa9, 0xe9, 0x9f, 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2d, 0xae, 0x7e, 0x38, 0x2f, 0x94, - 0x6b, 0x37, 0x6f, 0xe3, 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x4e, 0x94, - 0x5d, 0x2c, 0xe1, 0x1e, 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf5, 0x8c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, - 0x62, 0x5b, 0xb8, 0x7a, 0xc6, 0xb6, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0xad, 0x6a, 0x8e, - 0x35, 0xd4, 0x6c, 0x63, 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0x56, 0x6d, 0xc5, 0xc7, 0xda, 0x5a, 0x97, 0xee, 0xf5, - 0x1e, 0xd5, 0x05, 0xb0, 0xf5, 0xdf, 0x9d, 0xae, 0x5c, 0xcf, 0x67, 0x04, 0xf0, 0xb5, 0xe0, 0xe3, 0xc9, 0x02, 0xbd, - 0x4a, 0x16, 0xfe, 0xdd, 0x40, 0x8d, 0xbf, 0xd3, 0xb9, 0x0b, 0x80, 0xae, 0xa4, 0xbc, 0x02, 0xf2, 0x0e, 0x2a, 0xcc, - 0x2d, 0xbb, 0xf2, 0xfe, 0xec, 0x3b, 0xec, 0x2d, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x83, 0x53, 0x41, 0x32, 0xb0, 0x97, - 0x15, 0xdb, 0x07, 0xb1, 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x80, 0x20, 0xae, 0xe0, 0x0e, 0xe2, 0xf0, 0xe4, 0x9f, - 0x83, 0xfb, 0xd6, 0x66, 0x7d, 0xcf, 0xac, 0xce, 0x09, 0x36, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0xd6, 0xfd, 0xbe, - 0xb7, 0xd7, 0x8e, 0x4f, 0x2b, 0xa9, 0x13, 0x3b, 0xaf, 0xd5, 0x5a, 0xb0, 0xb7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x80, - 0x5f, 0x70, 0x37, 0xe0, 0xf7, 0x1d, 0x6b, 0xcb, 0x7b, 0xcb, 0x16, 0x6c, 0x0f, 0x97, 0xa0, 0xa6, 0xbd, 0xec, 0xcf, - 0x2a, 0x17, 0xb4, 0x63, 0x97, 0xc4, 0xc3, 0x19, 0xb3, 0x5c, 0x99, 0x59, 0x27, 0xf9, 0x8d, 0xe8, 0x8c, 0xe9, 0xac, - 0xf5, 0x7c, 0xce, 0xe7, 0x93, 0x42, 0x83, 0xfa, 0x5d, 0x12, 0x1f, 0x51, 0xd1, 0x79, 0x02, 0x5b, 0xcb, 0x0a, 0xc8, - 0xbd, 0x2e, 0xc1, 0x5a, 0xab, 0x5d, 0xfa, 0xbd, 0x6a, 0xc0, 0x6d, 0xca, 0x61, 0x4d, 0x40, 0xd0, 0x9c, 0x59, 0x51, - 0x8f, 0xd9, 0x8e, 0x71, 0xf3, 0xd3, 0xcb, 0x1f, 0x9c, 0xb0, 0x64, 0xc5, 0x6a, 0x7f, 0xfa, 0xc3, 0x53, 0x4f, 0x7f, - 0xa7, 0xf6, 0xaf, 0x84, 0x1f, 0x8c, 0xff, 0x5d, 0xbb, 0xaf, 0xb5, 0x18, 0x95, 0xad, 0x72, 0x84, 0xc6, 0xdd, 0x4a, - 0x9a, 0x2c, 0x3f, 0x09, 0x4f, 0x58, 0x0b, 0x9e, 0x99, 0x33, 0x20, 0x2b, 0x60, 0x85, 0xb5, 0x4c, 0xc2, 0x39, 0xc6, - 0x6a, 0x69, 0xab, 0x6f, 0xd1, 0x34, 0xa7, 0x87, 0x73, 0x6d, 0x50, 0xa6, 0x9c, 0x9d, 0x11, 0xab, 0xe1, 0x32, 0x2c, - 0x4d, 0x28, 0x42, 0xf6, 0x60, 0x07, 0x37, 0x76, 0xca, 0x52, 0xca, 0x70, 0x8e, 0xc1, 0x84, 0x27, 0x62, 0x54, 0xee, - 0xfb, 0x87, 0x92, 0x57, 0x6d, 0x39, 0x28, 0x47, 0xd8, 0x47, 0x12, 0x25, 0x70, 0x2b, 0xd2, 0x42, 0x91, 0xb2, 0xf8, - 0xdb, 0x01, 0xba, 0xc0, 0x0b, 0xa8, 0xab, 0x51, 0xb7, 0x3f, 0x1c, 0xf1, 0xf0, 0x91, 0xa9, 0x0f, 0x8c, 0x58, 0x12, - 0xa8, 0xed, 0x45, 0x96, 0xae, 0x40, 0x85, 0xdf, 0xc3, 0xd5, 0x44, 0xec, 0xe7, 0x96, 0x14, 0x15, 0xd9, 0x48, 0x6f, - 0x68, 0x0d, 0x1e, 0xa1, 0x35, 0xe5, 0x07, 0x27, 0xd5, 0x26, 0x9d, 0x77, 0x84, 0x1c, 0xab, 0x6f, 0x2d, 0x61, 0xb4, - 0x2b, 0x7a, 0xf1, 0xe0, 0xe8, 0x3d, 0xcf, 0x57, 0xbd, 0xf2, 0x27, 0xae, 0x98, 0x27, 0xb7, 0x11, 0xa8, 0x5b, 0x41, - 0x75, 0x7b, 0xaf, 0x12, 0x2c, 0x58, 0xd2, 0xee, 0xe3, 0xb7, 0xb3, 0x76, 0x20, 0x2a, 0x63, 0x95, 0xbe, 0x26, 0x09, - 0x7b, 0x62, 0xd0, 0x29, 0x54, 0x55, 0x76, 0x77, 0xb4, 0x05, 0xae, 0x53, 0x96, 0xa2, 0x17, 0xb6, 0xc8, 0xdd, 0xf2, - 0xef, 0x9e, 0x2b, 0x72, 0xf6, 0x6b, 0x40, 0x70, 0x6a, 0xbe, 0x22, 0xbe, 0x9c, 0xe0, 0x51, 0x75, 0x0b, 0x1c, 0xe7, - 0xef, 0x00, 0xfe, 0xf1, 0x78, 0x0d, 0x9a, 0x80, 0x58, 0xb0, 0x5e, 0x1a, 0xf7, 0x58, 0x2f, 0x2e, 0xb6, 0xab, 0x24, - 0xdf, 0x82, 0x33, 0x03, 0xa5, 0x5a, 0xfa, 0x81, 0x53, 0xb5, 0x80, 0x0a, 0x07, 0xb3, 0x93, 0x7a, 0x61, 0x19, 0xf5, - 0x98, 0x3e, 0x3f, 0x83, 0x83, 0x23, 0x24, 0x00, 0xee, 0x97, 0x7d, 0x40, 0x02, 0x1e, 0x3a, 0xb3, 0x03, 0xc2, 0x09, - 0xb3, 0xa8, 0x0a, 0x24, 0x92, 0x23, 0xfd, 0xec, 0x31, 0x13, 0xc9, 0x1f, 0xcc, 0x7a, 0xce, 0x29, 0xd1, 0x63, 0x3d, - 0x75, 0x84, 0xf4, 0x58, 0xcf, 0x3a, 0x22, 0x7a, 0xac, 0x67, 0x1d, 0x1f, 0x3d, 0xd6, 0x33, 0xc7, 0x4e, 0x0f, 0x02, - 0x13, 0x20, 0xf2, 0x80, 0xf5, 0x68, 0x32, 0xf5, 0x14, 0xf7, 0x00, 0xd1, 0x20, 0xb0, 0x9e, 0x14, 0xce, 0x7b, 0x80, - 0x3c, 0x46, 0x62, 0x75, 0xd0, 0xfb, 0x8f, 0xf1, 0x77, 0x3d, 0x23, 0x23, 0x8f, 0x5b, 0x87, 0xd5, 0xff, 0xfa, 0x4f, - 0x08, 0x80, 0xc3, 0xb3, 0xa9, 0x77, 0x3d, 0x86, 0xac, 0xb2, 0x8c, 0x40, 0xf2, 0x13, 0x83, 0x2f, 0x5f, 0x00, 0x54, - 0x7d, 0xa6, 0x6b, 0x35, 0x39, 0x6a, 0x8f, 0x39, 0x74, 0xc5, 0x00, 0xb0, 0x0d, 0x4b, 0x54, 0xd5, 0xc2, 0x26, 0x2c, - 0x6e, 0x3f, 0xc3, 0x68, 0x2e, 0x9b, 0x5e, 0xd0, 0x40, 0x3d, 0x42, 0xf0, 0x4b, 0xeb, 0xa1, 0xb5, 0x96, 0x29, 0x87, - 0xae, 0x8d, 0xa2, 0xca, 0x86, 0xba, 0x84, 0xd5, 0x46, 0x44, 0x35, 0x51, 0xa4, 0x5c, 0x33, 0x8a, 0x62, 0xa9, 0x82, - 0x43, 0x26, 0x56, 0x10, 0x35, 0x4f, 0x5b, 0x6d, 0x15, 0x1c, 0x56, 0x80, 0xb0, 0x16, 0xd6, 0x42, 0x3a, 0x83, 0xda, - 0x3b, 0xfd, 0x48, 0xf9, 0xcb, 0x0b, 0xb9, 0x9d, 0x5b, 0x28, 0xc2, 0xed, 0x39, 0x28, 0x6f, 0xea, 0xaa, 0x54, 0x44, - 0xa3, 0x25, 0x50, 0xca, 0x8a, 0x20, 0xb2, 0x00, 0x01, 0x1c, 0x37, 0x10, 0xf8, 0xbc, 0xc6, 0x27, 0xd0, 0x28, 0x04, - 0xf2, 0x03, 0xeb, 0x70, 0xe3, 0x21, 0x2d, 0xb5, 0x46, 0x44, 0x89, 0xf8, 0xc9, 0xd5, 0x73, 0x6c, 0x5f, 0x3d, 0x8d, - 0xb5, 0xa5, 0x34, 0x41, 0xfc, 0xc4, 0x62, 0x0b, 0x31, 0x41, 0x54, 0x87, 0xe8, 0x04, 0x96, 0x13, 0x42, 0x14, 0xfe, - 0x10, 0xfa, 0xa9, 0x81, 0xbf, 0x64, 0xcb, 0x22, 0xaf, 0x09, 0x16, 0x33, 0x67, 0x80, 0x56, 0x45, 0xe0, 0x99, 0xce, - 0x96, 0xca, 0x9c, 0xe6, 0xd1, 0x91, 0x1d, 0x5c, 0x76, 0x1d, 0xec, 0xa5, 0x2f, 0x63, 0x27, 0xcb, 0xa6, 0x51, 0x1b, - 0x1b, 0x22, 0xe1, 0x15, 0xf9, 0xcb, 0x2c, 0x35, 0xce, 0x91, 0x6a, 0x7d, 0xd7, 0xc5, 0x6a, 0x45, 0xdb, 0x84, 0x55, - 0x88, 0x50, 0xb7, 0x0d, 0x95, 0x4b, 0x61, 0x36, 0x36, 0x4d, 0x03, 0x7c, 0xa1, 0xa8, 0x54, 0xca, 0x53, 0x5b, 0xa9, - 0xe4, 0x84, 0x77, 0x7d, 0x55, 0x8b, 0xd4, 0x15, 0xc1, 0x36, 0x66, 0xa8, 0x87, 0x72, 0xa3, 0xc6, 0xbe, 0xee, 0x58, - 0xa5, 0x77, 0x98, 0xa0, 0x62, 0xe4, 0x45, 0x0e, 0x2e, 0x4a, 0x0a, 0x32, 0x57, 0x43, 0x98, 0x3f, 0x6a, 0xf8, 0xb4, - 0xb0, 0xdc, 0x43, 0x09, 0x98, 0x1d, 0x35, 0xbc, 0x8c, 0x10, 0x88, 0xb8, 0x54, 0xf6, 0x15, 0x13, 0xbf, 0xa7, 0x60, - 0x96, 0x4c, 0xe8, 0x5e, 0xc4, 0xc2, 0x08, 0x6d, 0x7c, 0x92, 0x24, 0x53, 0xb9, 0x3e, 0x41, 0x17, 0x2a, 0x5c, 0x20, - 0x23, 0xb4, 0x48, 0xf3, 0x4f, 0x87, 0x53, 0x09, 0x3e, 0xa2, 0x4e, 0x01, 0xc7, 0xf3, 0xcb, 0xc2, 0xfa, 0xc9, 0x2a, - 0x89, 0xb9, 0xac, 0xcd, 0x7f, 0xd9, 0xc9, 0x31, 0xd8, 0xe5, 0x69, 0xe2, 0xb8, 0xfa, 0x8f, 0xaa, 0xa4, 0x78, 0xf8, - 0x39, 0xcd, 0x01, 0x45, 0x30, 0xb3, 0xa7, 0x18, 0x1f, 0xfb, 0x2c, 0x53, 0xc0, 0xdf, 0xae, 0xb7, 0x96, 0x4c, 0xec, - 0x92, 0x76, 0x2b, 0x65, 0xfc, 0x52, 0x1b, 0x76, 0x1c, 0x5c, 0x1a, 0x80, 0xe2, 0xac, 0xd1, 0x61, 0x79, 0xad, 0xdb, - 0x56, 0x8e, 0x0a, 0xd4, 0xfa, 0xdf, 0xbb, 0x85, 0x29, 0x6f, 0xf3, 0x52, 0x79, 0x9b, 0x87, 0x26, 0x40, 0x20, 0x32, - 0x43, 0x9e, 0x35, 0x1d, 0x93, 0xc4, 0xbd, 0x23, 0x25, 0xed, 0x3b, 0x52, 0xfc, 0xe8, 0x1d, 0x09, 0xf9, 0x96, 0xd0, - 0x91, 0x7d, 0xc9, 0xc9, 0x09, 0x94, 0x19, 0xec, 0xe5, 0x0d, 0x93, 0xfd, 0x03, 0xda, 0x0b, 0xe7, 0xb2, 0xbc, 0xe6, - 0x6f, 0x85, 0xb7, 0xf1, 0xa7, 0x9b, 0xf3, 0xae, 0xaa, 0x77, 0x5f, 0x99, 0x99, 0xc7, 0x63, 0x71, 0x3c, 0xe6, 0x26, - 0x68, 0x77, 0xc1, 0xc5, 0xa0, 0x62, 0xf7, 0x6e, 0x7c, 0xfc, 0x5b, 0x8e, 0x22, 0xb6, 0x52, 0x1e, 0x49, 0x17, 0x2a, - 0x31, 0xbc, 0x36, 0xf0, 0x30, 0x7b, 0x3e, 0x9e, 0xec, 0x6f, 0xee, 0x27, 0x83, 0xc1, 0x5e, 0xf5, 0xed, 0x8e, 0xd7, - 0xb3, 0xfd, 0x9c, 0x3d, 0xf0, 0xbb, 0xe9, 0x2e, 0x38, 0x34, 0xb0, 0xed, 0xee, 0x6f, 0xc4, 0xf1, 0xb8, 0x7f, 0xce, - 0x17, 0xfe, 0xe1, 0x01, 0x01, 0x9d, 0xf9, 0xe5, 0xb8, 0x8d, 0xf1, 0x73, 0xdb, 0x76, 0xd5, 0xda, 0x03, 0x3c, 0xfd, - 0x8f, 0xde, 0xed, 0x6c, 0x39, 0xf7, 0xd9, 0x13, 0xfe, 0x00, 0xfe, 0xf9, 0xb8, 0x49, 0x22, 0xf5, 0x89, 0x76, 0x99, - 0xbc, 0x05, 0x07, 0xf2, 0xbd, 0xcf, 0xde, 0xf0, 0x87, 0xd9, 0x72, 0xce, 0x8b, 0xe3, 0xf1, 0xfd, 0x34, 0x44, 0xb2, - 0xa6, 0xb0, 0x22, 0x96, 0x14, 0xcf, 0x0f, 0xc2, 0xd3, 0xf7, 0x22, 0x32, 0x44, 0x5a, 0xee, 0xdd, 0x21, 0xbb, 0x65, - 0x91, 0x1f, 0xc0, 0x07, 0xd9, 0xde, 0x9f, 0xc8, 0x9a, 0xd2, 0xfd, 0xe2, 0x89, 0x7f, 0x3c, 0xd2, 0x5f, 0x6f, 0xfc, - 0xe3, 0xf1, 0x3d, 0x7b, 0x40, 0x70, 0x74, 0xbe, 0x87, 0xfe, 0xd1, 0xb7, 0x0e, 0xa8, 0xca, 0xf0, 0xed, 0x6c, 0x3b, - 0xf7, 0x9f, 0xaf, 0xd9, 0x0a, 0xb8, 0x50, 0x94, 0x17, 0xda, 0x2d, 0x7b, 0x40, 0xaf, 0x33, 0x72, 0x22, 0x9a, 0xed, - 0xe7, 0x3e, 0x8b, 0xf1, 0xb9, 0xba, 0x2f, 0x26, 0x5f, 0xbd, 0x2f, 0xee, 0xd9, 0xae, 0xfb, 0xbe, 0x28, 0xdf, 0x74, - 0xd7, 0xcf, 0x8e, 0xed, 0xd9, 0x03, 0xcc, 0xb0, 0xb7, 0xfc, 0xb6, 0x39, 0x75, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, - 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0xb9, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x97, 0xde, - 0xa2, 0xd4, 0x45, 0x4f, 0xfb, 0x14, 0xe4, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x7c, - 0xa6, 0x1d, 0x3d, 0xaf, 0xbf, 0xed, 0x3d, 0x93, 0xdf, 0xc8, 0xc0, 0x16, 0x22, 0x29, 0x1c, 0xc7, 0x57, 0xcf, 0xce, - 0xf8, 0xaf, 0x5a, 0x1e, 0xb5, 0xda, 0x2f, 0x94, 0xfa, 0xf4, 0x25, 0x1d, 0xd1, 0xc4, 0xbd, 0x68, 0xcb, 0xb0, 0x46, - 0x59, 0x53, 0x4b, 0x87, 0x61, 0x5c, 0xc3, 0xbe, 0x3c, 0x70, 0xe8, 0x3b, 0x20, 0xd0, 0xe6, 0xa9, 0x14, 0x68, 0xe1, - 0x18, 0x46, 0x61, 0x16, 0x52, 0x1e, 0x17, 0x66, 0x29, 0xef, 0xa9, 0x40, 0x8b, 0x5b, 0x75, 0x8f, 0xa9, 0xed, 0x16, - 0x44, 0x58, 0xbd, 0x65, 0x5c, 0x5e, 0x37, 0xaa, 0x70, 0x5b, 0x80, 0xa2, 0x08, 0xca, 0xe0, 0x40, 0x72, 0xdb, 0x42, - 0x49, 0xb3, 0x51, 0x58, 0x8b, 0x55, 0x51, 0xee, 0x7b, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, - 0x75, 0x28, 0x17, 0xe9, 0xbf, 0x65, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xfb, 0x97, - 0xf4, 0xb3, 0xc1, 0x32, 0x72, 0x4a, 0xfd, 0x10, 0x8d, 0xee, 0xd2, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, - 0x0a, 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, - 0x26, 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, - 0x90, 0xdc, 0xa9, 0x73, 0x7f, 0x54, 0x4e, 0xfe, 0x1d, 0x0d, 0x91, 0x57, 0xdc, 0x20, 0x56, 0x16, 0x5c, 0x62, 0x31, - 0x54, 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xc7, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, - 0x13, 0x3e, 0x6e, 0xad, 0x45, 0x88, 0x3a, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, - 0x14, 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xc8, 0x49, 0xcf, 0x5f, 0x9a, 0x14, 0x65, - 0xcc, 0xf8, 0x20, 0xca, 0x48, 0xe4, 0x75, 0xb8, 0x12, 0xd3, 0x02, 0xf9, 0x46, 0x4f, 0x1f, 0x04, 0xd7, 0xf0, 0x6e, - 0xc8, 0xbd, 0x02, 0x6c, 0x09, 0xd8, 0x01, 0xee, 0x95, 0x19, 0xe5, 0x3a, 0xad, 0xeb, 0xb7, 0xd6, 0x43, 0x31, 0x0c, - 0x9f, 0x5a, 0x02, 0xdb, 0xc9, 0x3a, 0x3a, 0xd1, 0xc3, 0x87, 0xff, 0x75, 0x55, 0x73, 0xd4, 0xa9, 0x5c, 0xce, 0x4e, - 0x27, 0x2c, 0x45, 0xcc, 0xa0, 0xfb, 0xeb, 0xee, 0xa5, 0x00, 0xba, 0x5d, 0x16, 0xf3, 0x6c, 0xb4, 0x97, 0x7f, 0x4b, - 0x37, 0x56, 0x94, 0x36, 0xf1, 0x2e, 0xeb, 0x8d, 0xfd, 0xe1, 0xe8, 0x3f, 0x9e, 0xbe, 0x9b, 0x10, 0xaa, 0xce, 0x96, - 0x6d, 0x74, 0x9c, 0xcb, 0xff, 0xfa, 0xcf, 0x31, 0x59, 0x41, 0x50, 0x10, 0x96, 0x9d, 0x62, 0xa2, 0x82, 0x51, 0xa4, - 0xd8, 0xf0, 0xf1, 0x64, 0x83, 0x3a, 0xe1, 0x8d, 0xbf, 0xd4, 0x3a, 0x61, 0x62, 0x64, 0xa5, 0xf2, 0x37, 0x2c, 0x67, - 0x2b, 0x95, 0x59, 0x40, 0xe6, 0x41, 0x35, 0xd9, 0x18, 0x0d, 0xe6, 0x9a, 0xd7, 0xb3, 0xcd, 0x5c, 0x2a, 0x9f, 0xc1, - 0x94, 0xb3, 0x1c, 0x9c, 0x2d, 0x85, 0xdd, 0x93, 0x40, 0xd1, 0x9a, 0xa1, 0x1b, 0x7f, 0x8a, 0xad, 0x7a, 0x95, 0x56, - 0x35, 0xc0, 0x03, 0x42, 0x0c, 0x0c, 0xb5, 0x57, 0x0b, 0x0f, 0xad, 0x05, 0xb0, 0xf1, 0x47, 0xa5, 0x1f, 0x8c, 0x27, - 0x4b, 0xbe, 0x40, 0xfe, 0xe5, 0xc8, 0x51, 0xbb, 0xf7, 0xfb, 0xde, 0x3d, 0x48, 0xc1, 0x91, 0x6b, 0xa1, 0x40, 0x22, - 0xa0, 0x05, 0xdf, 0xfa, 0xca, 0x07, 0xe3, 0x2d, 0x6a, 0xab, 0x41, 0x41, 0xed, 0xe8, 0x96, 0xc7, 0x8e, 0xde, 0xf9, - 0xfe, 0x8c, 0xbe, 0x7a, 0xa1, 0x85, 0xe3, 0xaf, 0x9c, 0x91, 0x1b, 0xb6, 0xee, 0x90, 0x23, 0x9a, 0x49, 0x87, 0x10, - 0xb1, 0x66, 0x1b, 0xf6, 0x96, 0x54, 0xce, 0x9d, 0x43, 0x76, 0xfe, 0x08, 0x55, 0x7a, 0xad, 0xc7, 0xb7, 0x13, 0xa5, - 0xbb, 0x3d, 0xdd, 0x4d, 0xbe, 0x65, 0x13, 0x11, 0x83, 0x01, 0x6d, 0x10, 0xce, 0xc8, 0x3a, 0x44, 0x2a, 0x1d, 0x20, - 0x04, 0x8e, 0x09, 0x68, 0xfa, 0xf7, 0xaf, 0x49, 0x14, 0x70, 0xa4, 0x8d, 0x90, 0xb5, 0xec, 0x78, 0xac, 0x40, 0xa3, - 0xdc, 0xfc, 0xe1, 0x15, 0xea, 0x34, 0x07, 0xe6, 0xe9, 0x12, 0xf6, 0x1c, 0x3c, 0xd2, 0x8b, 0xd3, 0x23, 0xfd, 0xbf, - 0xa3, 0x89, 0x1a, 0xff, 0xfb, 0x9a, 0x28, 0xa5, 0x45, 0x72, 0x54, 0x4b, 0xdf, 0xa4, 0x8e, 0x82, 0x8b, 0xbc, 0xa3, - 0x16, 0xb2, 0x67, 0xd9, 0xb8, 0x51, 0xcd, 0xfb, 0xff, 0xb5, 0x32, 0xff, 0x5f, 0xd3, 0xca, 0x30, 0x25, 0x3b, 0x96, - 0x6a, 0xe6, 0x81, 0x56, 0x31, 0xcc, 0x7e, 0x26, 0x09, 0x91, 0xe1, 0xd2, 0x80, 0x1f, 0x55, 0x70, 0x88, 0xd3, 0x6a, - 0x93, 0x85, 0x7b, 0x54, 0xa2, 0xde, 0x89, 0x55, 0x9a, 0xbf, 0xa8, 0xff, 0x25, 0xca, 0x02, 0xa6, 0xf6, 0xaa, 0x4c, - 0xe3, 0x80, 0x2c, 0xfc, 0x59, 0x58, 0xe2, 0xe4, 0xc6, 0x36, 0xfe, 0x2c, 0xc7, 0xd3, 0x7e, 0xd5, 0x99, 0x79, 0x20, - 0x81, 0x1a, 0x88, 0x3f, 0x72, 0x2e, 0x2b, 0x8b, 0x07, 0x84, 0x6e, 0xfe, 0xb1, 0x2c, 0x8b, 0xd2, 0xeb, 0x7d, 0x4a, - 0xd2, 0xea, 0x62, 0x2d, 0xea, 0xa4, 0x88, 0x15, 0x94, 0x4d, 0x0a, 0x30, 0xfa, 0xb0, 0xf2, 0x44, 0x1c, 0x5c, 0x20, - 0x50, 0xc3, 0x45, 0x9d, 0x84, 0x00, 0x34, 0xac, 0x10, 0xf6, 0x2f, 0xa0, 0x85, 0x17, 0x61, 0x1c, 0x6e, 0x00, 0x26, - 0x27, 0xad, 0x2e, 0x36, 0x65, 0x71, 0x9f, 0xc6, 0x22, 0x1e, 0xf5, 0x14, 0x25, 0xcb, 0xc7, 0xca, 0x95, 0x73, 0xfd, - 0xc3, 0x1f, 0x14, 0xc0, 0x6e, 0xc0, 0x6c, 0x5b, 0x60, 0x07, 0x00, 0x09, 0x0a, 0x64, 0x0b, 0x75, 0x1a, 0x5d, 0xa8, - 0xa5, 0x02, 0xef, 0xb9, 0x1e, 0xe0, 0x1f, 0x2b, 0xc0, 0x32, 0xae, 0x0b, 0x19, 0x30, 0x82, 0x00, 0x46, 0xe0, 0xa0, - 0x04, 0x0c, 0x9d, 0x61, 0x6d, 0xf1, 0xb8, 0x43, 0x73, 0xa5, 0xdb, 0x92, 0x9b, 0x46, 0x39, 0x5b, 0x89, 0x00, 0xfa, - 0xea, 0xa6, 0xc4, 0xe9, 0x72, 0xd9, 0x4a, 0xc2, 0xbe, 0x7d, 0xdf, 0x4e, 0x15, 0x79, 0x7c, 0x92, 0x86, 0xbc, 0x02, - 0x4f, 0x32, 0x8e, 0x24, 0x51, 0x22, 0xf8, 0x58, 0x35, 0x66, 0x1c, 0x5e, 0xb4, 0x29, 0xa7, 0x0e, 0x66, 0xbd, 0x00, - 0x9c, 0x27, 0x68, 0xcb, 0x00, 0x63, 0x01, 0x83, 0x73, 0x21, 0x96, 0x3c, 0x45, 0xf0, 0x4b, 0x27, 0x52, 0x18, 0x77, - 0x39, 0x0c, 0xf3, 0xa0, 0xe8, 0x5d, 0x52, 0x7f, 0xf4, 0xfb, 0xa8, 0x4d, 0x06, 0x43, 0x50, 0x09, 0xa0, 0xb2, 0x6e, - 0x90, 0x18, 0x58, 0x95, 0x16, 0x12, 0x97, 0x10, 0x2f, 0xf3, 0xd5, 0xb4, 0x8e, 0x82, 0xf7, 0xf5, 0x84, 0x10, 0x4e, - 0x30, 0x3e, 0xc4, 0x0d, 0x10, 0x30, 0x58, 0xc5, 0x05, 0x06, 0xc9, 0x73, 0x89, 0xee, 0x8f, 0xe7, 0x3b, 0x06, 0xb8, - 0x72, 0xde, 0x53, 0xed, 0xea, 0x81, 0xbd, 0x5c, 0xa5, 0x4b, 0x46, 0x08, 0x2b, 0xfe, 0x2f, 0x22, 0xef, 0xdb, 0x61, - 0x02, 0x6a, 0x1b, 0xf9, 0x63, 0x90, 0x98, 0xcb, 0x44, 0x11, 0xc4, 0xa3, 0xac, 0x60, 0x49, 0x1a, 0x6c, 0x47, 0x49, - 0x0a, 0x1a, 0x4d, 0x8c, 0x21, 0x53, 0xa1, 0x1d, 0x92, 0x46, 0xb3, 0x31, 0xd9, 0xc7, 0x90, 0xd7, 0x70, 0xb1, 0x58, - 0xe0, 0x7d, 0x3f, 0x0b, 0xd5, 0xc1, 0xb6, 0x34, 0x87, 0x80, 0x93, 0x04, 0x7b, 0xea, 0x8a, 0x94, 0x84, 0xd9, 0xe8, - 0x53, 0xc8, 0xb9, 0x01, 0x1d, 0x27, 0x8d, 0xa1, 0xfa, 0xc0, 0x24, 0xbc, 0x89, 0xd0, 0x49, 0x59, 0x21, 0x2c, 0xe0, - 0xbe, 0x91, 0xd1, 0x68, 0x25, 0x0d, 0x02, 0x6f, 0x33, 0x6c, 0x05, 0x36, 0xa1, 0xe1, 0x2f, 0x32, 0x0f, 0xd3, 0x6a, - 0x56, 0x82, 0x39, 0xdf, 0x40, 0x25, 0xc6, 0x93, 0xe5, 0x0d, 0xdf, 0xba, 0x58, 0x89, 0xc9, 0x6c, 0x39, 0x9f, 0x6c, - 0x24, 0xd5, 0x1c, 0x08, 0x19, 0x19, 0x5b, 0xc2, 0xfe, 0x61, 0x60, 0x28, 0x1d, 0xd8, 0xd1, 0x54, 0xd3, 0x26, 0x01, - 0x26, 0xd3, 0x25, 0xe7, 0xc3, 0x6b, 0x44, 0x93, 0xd5, 0xa9, 0x7b, 0x99, 0xaa, 0x76, 0x70, 0x4d, 0xce, 0xe4, 0xf4, - 0x48, 0x3d, 0xd5, 0xba, 0x97, 0x6a, 0xb4, 0x1b, 0xe6, 0xa3, 0x9d, 0x1f, 0x80, 0x5b, 0xa7, 0xb0, 0xd3, 0xf7, 0xc3, - 0x7c, 0xb4, 0xf7, 0x35, 0xec, 0x2e, 0x29, 0x04, 0xaa, 0x3f, 0xcb, 0x9a, 0xcc, 0xc5, 0x9b, 0xe2, 0xc1, 0x2b, 0xd8, - 0x33, 0x7f, 0xa0, 0x7f, 0x95, 0xec, 0x99, 0x6f, 0x33, 0xb9, 0xfe, 0x99, 0x76, 0x8d, 0xc6, 0x4c, 0xc7, 0x6b, 0xe7, - 0x60, 0x85, 0x06, 0xc8, 0x2f, 0xd8, 0xd1, 0xde, 0xe4, 0x20, 0x10, 0xa0, 0x7b, 0x09, 0x8e, 0xa2, 0x80, 0xa8, 0x69, - 0x55, 0x79, 0x74, 0xba, 0xf7, 0x0f, 0xf8, 0x46, 0x09, 0xd8, 0xe4, 0xa9, 0x75, 0x6f, 0x19, 0xfb, 0xc7, 0x23, 0x84, - 0xd0, 0xcb, 0xe9, 0x37, 0xda, 0xb1, 0x7a, 0xb4, 0x67, 0x12, 0xfc, 0x1c, 0x31, 0xe9, 0x15, 0x8c, 0x61, 0xe8, 0xc2, - 0x2a, 0x46, 0xf2, 0x0c, 0xc8, 0x1a, 0xbf, 0x41, 0x74, 0x01, 0x8b, 0x5e, 0xef, 0xd5, 0x09, 0x0d, 0x22, 0xa0, 0xd2, - 0x6b, 0xfe, 0x52, 0xe4, 0x73, 0x55, 0x88, 0xde, 0x07, 0x6b, 0xe7, 0xcd, 0x8c, 0x64, 0x99, 0x34, 0x52, 0xed, 0x56, - 0x16, 0x9b, 0xca, 0x9b, 0x9d, 0x91, 0x2e, 0xe6, 0x18, 0x2a, 0x83, 0xc7, 0x01, 0x28, 0x3d, 0xff, 0x12, 0x7a, 0x25, - 0x43, 0xa6, 0x59, 0xa2, 0x99, 0xdd, 0x37, 0xfe, 0x64, 0x9d, 0x7a, 0x31, 0x22, 0x66, 0x03, 0x5b, 0x88, 0xdb, 0xa2, - 0xd2, 0x6d, 0x51, 0x28, 0x5b, 0x14, 0xe9, 0x43, 0xed, 0x42, 0x77, 0x66, 0xe1, 0xb3, 0xdc, 0xb4, 0xef, 0x4d, 0x66, - 0xc6, 0x06, 0x68, 0xbb, 0x08, 0xdf, 0x40, 0x07, 0x2a, 0x84, 0xfc, 0x47, 0x44, 0x44, 0x22, 0x60, 0x97, 0x73, 0x77, - 0x62, 0xd3, 0x21, 0x99, 0x87, 0x98, 0x15, 0x6a, 0x94, 0x97, 0x3c, 0x39, 0x19, 0x90, 0x9c, 0x50, 0xb7, 0xfb, 0xfd, - 0xcb, 0xa5, 0x0b, 0x6a, 0xbf, 0xa1, 0xd8, 0x31, 0xba, 0x29, 0xe0, 0x5c, 0xf0, 0x28, 0xef, 0xa5, 0x77, 0x09, 0x68, - 0x8e, 0xed, 0x29, 0xb2, 0x01, 0x9c, 0xde, 0x76, 0x21, 0xc0, 0xf6, 0x59, 0xb3, 0x8d, 0x3f, 0x59, 0xdf, 0x44, 0x53, - 0xaf, 0xe4, 0x33, 0xdd, 0x45, 0x89, 0xdb, 0x45, 0xb1, 0xec, 0xa2, 0x6d, 0x03, 0xc1, 0x8e, 0x6b, 0x3f, 0x00, 0xde, - 0xd0, 0xa8, 0xdf, 0x2f, 0x5b, 0x3d, 0x7b, 0xf6, 0xb5, 0xd3, 0x9e, 0xcd, 0x7c, 0x56, 0x9a, 0x9e, 0xfd, 0x35, 0x75, - 0x7b, 0x56, 0x4e, 0xf6, 0xa2, 0x73, 0xb2, 0x4f, 0x67, 0xf3, 0x40, 0x70, 0xb9, 0x73, 0x5f, 0x56, 0x53, 0x3d, 0xed, - 0x72, 0x3f, 0x68, 0x0d, 0x91, 0xf9, 0xc2, 0xa7, 0xbc, 0x7b, 0x5d, 0xc1, 0x02, 0x96, 0xe0, 0x6e, 0xbd, 0x34, 0xff, - 0x15, 0xbb, 0xbf, 0x17, 0xf4, 0xd2, 0xfc, 0x37, 0xfa, 0x93, 0x02, 0x38, 0x00, 0x8d, 0xa9, 0xdd, 0x02, 0x0f, 0x31, - 0x54, 0x50, 0xb8, 0x9b, 0x95, 0x73, 0xaf, 0x06, 0x38, 0x4c, 0xd2, 0x37, 0xb4, 0x7a, 0xa5, 0xc5, 0xae, 0x97, 0xc9, - 0x5e, 0x01, 0x1e, 0xaa, 0x90, 0x87, 0xc7, 0x63, 0xd4, 0x31, 0xec, 0xa0, 0x8e, 0x80, 0x61, 0x0f, 0xa1, 0xb1, 0x05, - 0x9e, 0x8f, 0x9f, 0x32, 0x7e, 0x10, 0xa0, 0x36, 0x42, 0x78, 0xbc, 0x5a, 0x94, 0x21, 0xb6, 0xec, 0x0d, 0x52, 0x49, - 0xfd, 0x2c, 0x10, 0x65, 0xb4, 0x0a, 0x68, 0xab, 0x3d, 0x65, 0x69, 0xbc, 0x85, 0x50, 0xb1, 0xd4, 0xc7, 0x10, 0x1a, - 0x38, 0xfc, 0x8e, 0x47, 0x90, 0xe0, 0x4b, 0xae, 0xc9, 0xe6, 0xde, 0xe4, 0xf7, 0xb4, 0xcf, 0x1f, 0x8f, 0x97, 0xd7, - 0x08, 0x4a, 0x97, 0xc2, 0x47, 0x2a, 0x11, 0xd5, 0x53, 0xdc, 0x94, 0x90, 0xcd, 0x92, 0x95, 0x7e, 0xf0, 0xab, 0xfa, - 0x05, 0x00, 0xb2, 0x10, 0x68, 0x13, 0x99, 0xfd, 0xe9, 0x42, 0x45, 0x17, 0x00, 0x87, 0xf8, 0xe3, 0x27, 0x88, 0xbe, - 0xa1, 0x65, 0x5a, 0x3e, 0x4e, 0x78, 0x08, 0x5a, 0x5b, 0xd2, 0x49, 0xc4, 0x4a, 0x81, 0x0d, 0x91, 0xf0, 0xfd, 0xfe, - 0x65, 0x2c, 0xe9, 0x40, 0xa3, 0x56, 0xf7, 0xc6, 0xad, 0xee, 0x95, 0xaf, 0xeb, 0x4e, 0x6e, 0x7c, 0x50, 0xb4, 0xcf, - 0xe6, 0x8d, 0xca, 0xf7, 0x6d, 0x9d, 0xb3, 0x3f, 0xdf, 0x3b, 0x72, 0x4e, 0x7c, 0x7b, 0x0f, 0xa1, 0xe8, 0xa1, 0x29, - 0xb2, 0x2c, 0x09, 0x03, 0x5a, 0x6b, 0xd7, 0x9e, 0x65, 0x74, 0xf0, 0xda, 0x37, 0x84, 0x88, 0x3c, 0xc5, 0x27, 0x21, - 0xb7, 0x38, 0x3e, 0x28, 0xd0, 0x3f, 0x33, 0xfe, 0xcc, 0x89, 0x1f, 0xb6, 0xfa, 0x05, 0x70, 0x6e, 0xba, 0xf7, 0xee, - 0xc4, 0xac, 0xc7, 0x50, 0xca, 0xc6, 0xff, 0xfd, 0x3e, 0x91, 0x05, 0x3a, 0x1d, 0xd1, 0x30, 0x10, 0xdc, 0x45, 0xf5, - 0x7f, 0xaf, 0x78, 0xdd, 0xb3, 0x56, 0xe7, 0xcb, 0x4f, 0x9d, 0x9f, 0xf4, 0xea, 0x65, 0xdc, 0x03, 0x72, 0x74, 0x80, - 0x70, 0x5e, 0xf7, 0x1b, 0xb6, 0xff, 0xe6, 0x97, 0xf7, 0x27, 0x2f, 0x03, 0x9b, 0x14, 0x89, 0x6d, 0x25, 0x9f, 0xf5, - 0x40, 0xe1, 0xd7, 0x63, 0xbd, 0xba, 0xd8, 0xf4, 0x58, 0x0f, 0xb5, 0x80, 0xe8, 0x61, 0x01, 0xea, 0xbf, 0x9e, 0x7d, - 0x1a, 0x0a, 0x07, 0xd9, 0x38, 0x55, 0xa0, 0xc8, 0x82, 0x3f, 0x17, 0xa3, 0x4d, 0x41, 0x80, 0xc8, 0x96, 0x90, 0x96, - 0x9f, 0xcd, 0x1e, 0x97, 0x5a, 0x92, 0xc1, 0x37, 0x01, 0x99, 0x1d, 0x58, 0x39, 0x41, 0xe9, 0xb8, 0x33, 0xe0, 0xca, - 0x16, 0x8f, 0x76, 0xfb, 0xd3, 0x20, 0x3b, 0x6b, 0x4e, 0x1a, 0xed, 0xc3, 0x3e, 0x05, 0x4e, 0x1a, 0x10, 0x7b, 0x44, - 0xa0, 0xef, 0xb6, 0xb9, 0xf4, 0xd1, 0xe1, 0x9c, 0x17, 0xf2, 0xcf, 0xa9, 0xc4, 0xe0, 0x1e, 0x4a, 0xac, 0x81, 0x40, - 0xe5, 0x19, 0xaa, 0x1c, 0x36, 0xc8, 0xf1, 0xcf, 0x8e, 0x64, 0x26, 0x31, 0x59, 0xe4, 0x6e, 0xcd, 0x54, 0xf8, 0x81, - 0x00, 0xfe, 0x73, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x01, 0x7f, 0x4c, 0xe1, 0xe7, 0x3c, 0x85, - 0x9d, 0xf6, 0xb0, 0x29, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, 0x3f, - 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x75, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x05, 0x39, - 0xdb, 0x14, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xf2, 0x51, 0x5a, 0xfd, 0x55, 0xff, - 0x04, 0xe6, 0x6d, 0x2a, 0x46, 0xb5, 0x8a, 0xc9, 0x6f, 0xf4, 0xfb, 0xc5, 0xa0, 0xf5, 0x21, 0x83, 0x8f, 0x5e, 0x9b, - 0x06, 0x7f, 0x74, 0x1a, 0xec, 0x30, 0xd1, 0x08, 0x80, 0x64, 0x4e, 0x2d, 0x79, 0x28, 0xfa, 0x23, 0xa8, 0xb0, 0x46, - 0xb9, 0x53, 0x30, 0x58, 0xff, 0xf1, 0x68, 0x07, 0xa6, 0x5e, 0x1c, 0x6d, 0xc9, 0x0e, 0x9a, 0xfb, 0x06, 0xb8, 0x5f, - 0x23, 0x5b, 0xcc, 0x2a, 0x80, 0x66, 0xaf, 0x11, 0x19, 0x9f, 0xbc, 0x00, 0xc6, 0x6c, 0x93, 0x85, 0x91, 0x88, 0x83, - 0xb1, 0x6a, 0xcc, 0x98, 0x81, 0x81, 0x0b, 0x74, 0x2d, 0x93, 0x92, 0x34, 0xa4, 0x83, 0x01, 0x2b, 0x65, 0x0b, 0x07, - 0xbc, 0x68, 0x4e, 0xdb, 0xf1, 0xba, 0x45, 0xe3, 0x81, 0xed, 0x62, 0x87, 0xfb, 0x1f, 0x8a, 0xdd, 0xdb, 0x70, 0x47, - 0x7a, 0x85, 0x8a, 0x25, 0xf4, 0xf3, 0xaf, 0xb2, 0xcf, 0x1a, 0x4e, 0x4e, 0x85, 0x66, 0x68, 0x29, 0x12, 0x4a, 0xf1, - 0x4e, 0x4f, 0x0a, 0x8c, 0x65, 0x2c, 0xfc, 0x03, 0x70, 0x4e, 0x17, 0x8a, 0xc8, 0x1d, 0x38, 0x8e, 0x6f, 0xa1, 0x82, - 0x51, 0xc3, 0xc1, 0xcb, 0x18, 0xb6, 0x45, 0x31, 0x0b, 0x09, 0xa7, 0x10, 0x2e, 0x56, 0x59, 0xbf, 0x2f, 0x7f, 0x51, - 0x17, 0x5d, 0x65, 0xb2, 0xee, 0x93, 0x70, 0x64, 0xc6, 0x72, 0xea, 0x85, 0xe4, 0x79, 0xcf, 0x93, 0x69, 0xf2, 0xb4, - 0x0a, 0x22, 0x80, 0x7c, 0x0e, 0xef, 0xc3, 0x34, 0x03, 0xab, 0x34, 0x29, 0x3f, 0x42, 0xe9, 0x8b, 0xcf, 0x73, 0x3f, - 0xd0, 0xd9, 0x2b, 0x93, 0x0c, 0x6f, 0xe6, 0xad, 0x37, 0xa9, 0x75, 0x5d, 0x3c, 0xe0, 0xef, 0x9c, 0xc1, 0xc6, 0xb9, - 0xce, 0x04, 0x07, 0x5e, 0x24, 0xb5, 0x5e, 0x33, 0xfe, 0x3c, 0xc3, 0x75, 0xa9, 0xda, 0xe8, 0xa3, 0x10, 0x5d, 0x41, - 0xa6, 0x02, 0x14, 0x8a, 0xb4, 0x7f, 0x50, 0x6a, 0x6e, 0x52, 0x69, 0x23, 0x01, 0x74, 0x0f, 0x93, 0x06, 0x5b, 0x0c, - 0x65, 0x2c, 0x4d, 0xa2, 0xdc, 0x69, 0x10, 0x57, 0xf6, 0xe7, 0x5c, 0xe2, 0xd0, 0xb2, 0x48, 0xfe, 0xbd, 0xef, 0xe9, - 0x2b, 0xa4, 0xee, 0x64, 0x81, 0xcc, 0x18, 0x2f, 0xf2, 0xf8, 0x13, 0x10, 0x66, 0x83, 0x36, 0x2a, 0x0a, 0x21, 0x64, - 0x83, 0x18, 0x34, 0x5e, 0xe4, 0xf1, 0x0f, 0x8a, 0xc6, 0x43, 0x3e, 0x8a, 0x7c, 0xf5, 0x57, 0xa9, 0xff, 0x0a, 0x7d, - 0x66, 0x82, 0x47, 0xa8, 0x26, 0xfa, 0x77, 0xcf, 0x67, 0xf7, 0xa0, 0x36, 0x8c, 0xc2, 0xcc, 0x94, 0x9f, 0xfb, 0xa6, - 0x38, 0x7b, 0xfd, 0x15, 0x5d, 0x65, 0x5b, 0xf7, 0xa3, 0x8f, 0x27, 0x04, 0xd6, 0xc6, 0xe8, 0x8a, 0x1b, 0x03, 0xc8, - 0x61, 0xf2, 0x7e, 0x45, 0x69, 0x15, 0xa4, 0x41, 0xe8, 0xa0, 0x21, 0xe8, 0x95, 0x44, 0x1f, 0x48, 0x2c, 0x62, 0x0c, - 0x2f, 0xc4, 0x33, 0x52, 0x93, 0x89, 0x86, 0x78, 0x45, 0xec, 0x87, 0x68, 0xc9, 0xa9, 0x89, 0x6e, 0x84, 0x29, 0x06, - 0x12, 0x3b, 0x83, 0xe4, 0x24, 0xa9, 0x95, 0x5f, 0x3c, 0x93, 0x84, 0x25, 0x76, 0x1e, 0x62, 0x30, 0xa9, 0xa5, 0x3b, - 0xbd, 0xa9, 0xd2, 0x97, 0x13, 0x2d, 0x07, 0xed, 0x03, 0xb0, 0x4b, 0x49, 0xef, 0x9f, 0x14, 0x8a, 0xf8, 0x10, 0xc6, - 0x31, 0x84, 0x6f, 0x11, 0xd5, 0x15, 0x38, 0xd7, 0x0a, 0x34, 0x56, 0x03, 0x0f, 0xcd, 0x2c, 0x9f, 0x0f, 0x39, 0xfd, - 0x54, 0x5a, 0xfe, 0x18, 0xd1, 0xd8, 0x68, 0xdd, 0x1c, 0x8f, 0x07, 0x5a, 0xf5, 0xd2, 0x39, 0xe8, 0xba, 0x99, 0xc4, - 0xc4, 0x0d, 0xa4, 0xeb, 0x47, 0xbf, 0x99, 0xb0, 0x17, 0x51, 0x21, 0x97, 0x42, 0x50, 0xd0, 0xea, 0x40, 0xe0, 0x50, - 0x78, 0x8b, 0x32, 0x5f, 0xc5, 0xb4, 0x81, 0x30, 0xf8, 0xfc, 0x40, 0x7e, 0xbe, 0x29, 0x48, 0xc5, 0x8e, 0x75, 0xed, - 0xf7, 0xb7, 0xa5, 0x07, 0x78, 0x72, 0x26, 0xc9, 0xd3, 0x66, 0x08, 0x2b, 0x02, 0x68, 0xcc, 0x6a, 0xb2, 0x38, 0xe1, - 0xca, 0x1c, 0x7e, 0xcc, 0xbd, 0x92, 0xa5, 0x4c, 0x9d, 0xa7, 0x7a, 0x01, 0x44, 0x1d, 0x6f, 0xd0, 0x8a, 0xd4, 0xaf, - 0xd0, 0xd9, 0x6b, 0x56, 0x42, 0xc6, 0xc3, 0x4b, 0xce, 0xd3, 0xd1, 0x03, 0x4b, 0x78, 0x84, 0x7f, 0x25, 0x13, 0x7d, - 0xf8, 0x3d, 0x70, 0xb8, 0x19, 0x27, 0x3c, 0x72, 0x9b, 0x7d, 0xa8, 0xc2, 0x35, 0xdc, 0x4c, 0x0b, 0x40, 0x72, 0x0b, - 0x92, 0x26, 0xa0, 0x84, 0x44, 0x26, 0x64, 0xd6, 0x94, 0xfc, 0xdc, 0xd2, 0x36, 0x58, 0xc3, 0xa4, 0xf3, 0x80, 0x17, - 0xad, 0x3e, 0x5a, 0x4d, 0xb4, 0xcb, 0xac, 0x9a, 0x0f, 0x71, 0x86, 0x6a, 0x8e, 0xbb, 0x0b, 0xf8, 0x39, 0xe0, 0x39, - 0xcb, 0x9b, 0x74, 0xb4, 0x1f, 0x70, 0xe1, 0xc9, 0x75, 0x9e, 0x8e, 0x76, 0xf8, 0x4b, 0xee, 0x0f, 0x00, 0x1d, 0x4c, - 0x5d, 0x02, 0x7f, 0xaa, 0xb6, 0x9a, 0x4a, 0xfd, 0xd2, 0xda, 0xaf, 0xeb, 0xce, 0x6a, 0xc1, 0x19, 0xa2, 0x2f, 0x43, - 0x07, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, - 0x82, 0x7b, 0xc9, 0x9f, 0x1f, 0x10, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, - 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xa9, 0x34, 0x26, 0x45, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0xeb, 0x7a, 0x1b, 0xb7, 0xb2, 0x20, 0xfa, + 0xfb, 0xcc, 0x53, 0x48, 0xbd, 0x1d, 0xa5, 0x21, 0x82, 0x2d, 0x92, 0xba, 0x58, 0x6e, 0x0a, 0xe2, 0xf8, 0x1a, 0x3b, + 0x71, 0x6c, 0xc7, 0x72, 0xec, 0xd8, 0x0c, 0xb7, 0x02, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, + 0xe4, 0xbb, 0x9f, 0xaf, 0x70, 0xe9, 0x46, 0x93, 0xb4, 0xd7, 0x5a, 0x73, 0x66, 0xce, 0x37, 0x3b, 0x7b, 0x59, 0x6c, + 0xdc, 0x51, 0x28, 0x14, 0xaa, 0x0a, 0x55, 0x85, 0x8b, 0xfd, 0x91, 0xcc, 0xf4, 0xdd, 0x9c, 0xed, 0x4d, 0xf5, 0x2c, + 0xbf, 0xbc, 0x70, 0xff, 0x32, 0x3a, 0xba, 0xbc, 0xc8, 0xb9, 0xf8, 0xbc, 0x57, 0xb0, 0x9c, 0xf0, 0x4c, 0x8a, 0xbd, + 0x69, 0xc1, 0xc6, 0x64, 0x44, 0x35, 0x4d, 0xf9, 0x8c, 0x4e, 0xd8, 0xde, 0xd1, 0xe5, 0xc5, 0x8c, 0x69, 0xba, 0x97, + 0x4d, 0x69, 0xa1, 0x98, 0x26, 0xbf, 0xbf, 0x7b, 0xd6, 0x3c, 0xbf, 0xbc, 0x50, 0x59, 0xc1, 0xe7, 0x7a, 0x0f, 0x9a, + 0x24, 0x33, 0x39, 0x5a, 0xe4, 0xec, 0xf2, 0xe8, 0xe8, 0xe6, 0xe6, 0x26, 0xf9, 0x5b, 0xfd, 0x8f, 0x2f, 0xb4, 0xd8, + 0xfb, 0xa5, 0x20, 0xaf, 0x87, 0x7f, 0xb3, 0x4c, 0x27, 0x23, 0x36, 0xe6, 0x82, 0xbd, 0x29, 0xe4, 0x9c, 0x15, 0xfa, + 0xae, 0x0b, 0x99, 0x3f, 0x15, 0x24, 0xe6, 0x58, 0x63, 0x86, 0xc8, 0xa5, 0xde, 0xe3, 0x62, 0x8f, 0xf7, 0x7e, 0x29, + 0x4c, 0xca, 0x92, 0x89, 0xc5, 0x8c, 0x15, 0x74, 0x98, 0xb3, 0x74, 0xbf, 0x85, 0x33, 0x29, 0xc6, 0x7c, 0xb2, 0x28, + 0xbf, 0x6f, 0x0a, 0xae, 0xfd, 0xef, 0x2f, 0x34, 0x5f, 0xb0, 0x94, 0xad, 0x51, 0xca, 0xfb, 0x7a, 0x40, 0x98, 0x69, + 0xf9, 0x73, 0xd5, 0x70, 0xfc, 0x93, 0x69, 0xf2, 0x6e, 0xce, 0xe4, 0x78, 0x4f, 0xef, 0x93, 0x48, 0xdd, 0xcd, 0x86, + 0x32, 0x8f, 0x7a, 0xba, 0x11, 0x45, 0x29, 0x94, 0xc1, 0x0c, 0x75, 0x33, 0x29, 0x94, 0xde, 0x13, 0x9c, 0xdc, 0x70, + 0x31, 0x92, 0x37, 0xf8, 0x46, 0x10, 0xc1, 0x93, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x83, 0x83, 0xd8, + 0x7d, 0xdf, 0x3d, 0xbe, 0xba, 0x22, 0x84, 0x7c, 0x91, 0x7c, 0xb4, 0xd7, 0x5a, 0xad, 0x82, 0xd4, 0x44, 0x50, 0xcd, + 0xbf, 0x30, 0x5b, 0x09, 0x1d, 0x1c, 0x44, 0x74, 0x24, 0xe7, 0x9a, 0x8d, 0xae, 0xf4, 0x5d, 0xce, 0xae, 0xa6, 0x8c, + 0x69, 0x15, 0x71, 0xb1, 0xf7, 0x44, 0x66, 0x8b, 0x19, 0x13, 0x3a, 0x99, 0x17, 0x52, 0x4b, 0x18, 0xd8, 0xc1, 0x41, + 0x54, 0xb0, 0x79, 0x4e, 0x33, 0x06, 0xf9, 0x8f, 0xaf, 0xae, 0xaa, 0x1a, 0x55, 0x21, 0xfc, 0x59, 0x90, 0x2b, 0x33, + 0xf4, 0x18, 0xe1, 0x0f, 0x82, 0x08, 0x76, 0xb3, 0xf7, 0x81, 0xd1, 0xcf, 0xbf, 0xd2, 0x79, 0x37, 0xcb, 0xa9, 0x52, + 0x7b, 0xcf, 0xe4, 0xd2, 0x4c, 0xa3, 0x58, 0x64, 0x5a, 0x16, 0xb1, 0xc6, 0x0c, 0x0b, 0xb4, 0xe4, 0xe3, 0x58, 0x4f, + 0xb9, 0x4a, 0xae, 0xef, 0x65, 0x4a, 0xbd, 0x65, 0x6a, 0x91, 0xeb, 0x7b, 0x64, 0xbf, 0x85, 0xc5, 0x3e, 0x21, 0x9f, + 0x05, 0xd2, 0xd3, 0x42, 0xde, 0xec, 0x3d, 0x2d, 0x0a, 0x59, 0xc4, 0xd1, 0xe3, 0xab, 0x2b, 0x5b, 0x62, 0x8f, 0xab, + 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0xbf, 0x16, 0x42, 0xd1, 0x31, 0x7b, + 0x7c, 0x75, 0xf5, 0xd7, 0x9e, 0x2c, 0xf6, 0xfe, 0xca, 0x94, 0xfa, 0x6b, 0x8f, 0x0b, 0xa5, 0x19, 0x1d, 0x25, 0x11, + 0xea, 0x9a, 0xce, 0x32, 0xa5, 0xde, 0xb1, 0x5b, 0x4d, 0x34, 0x36, 0x9f, 0x9a, 0xb0, 0xf5, 0x84, 0xe9, 0x3d, 0x55, + 0xce, 0x2b, 0x46, 0xcb, 0x9c, 0xe9, 0x3d, 0x4d, 0x4c, 0xbe, 0x74, 0xf0, 0x67, 0xf6, 0x53, 0x77, 0xf9, 0x38, 0xbe, + 0x11, 0x07, 0x07, 0xba, 0x04, 0x34, 0x5a, 0xba, 0x15, 0x22, 0x6c, 0xdf, 0xa7, 0x1d, 0x1c, 0xb0, 0x24, 0x67, 0x62, + 0xa2, 0xa7, 0x84, 0x90, 0x76, 0x57, 0x1c, 0x1c, 0xc4, 0x9a, 0x7c, 0x10, 0xc9, 0x84, 0xe9, 0x98, 0x21, 0x84, 0xab, + 0xda, 0x07, 0x07, 0xb1, 0x05, 0x82, 0x24, 0xda, 0x00, 0xae, 0x06, 0x63, 0x94, 0x38, 0xe8, 0x5f, 0xdd, 0x89, 0x2c, + 0x0e, 0xc7, 0x8f, 0xb0, 0x38, 0x38, 0xf8, 0x20, 0x12, 0x05, 0x2d, 0x62, 0x8d, 0xd0, 0xba, 0x60, 0x7a, 0x51, 0x88, + 0x3d, 0xbd, 0xd6, 0xf2, 0x4a, 0x17, 0x5c, 0x4c, 0x62, 0xb4, 0xf4, 0x69, 0x41, 0xc5, 0xf5, 0xda, 0x0e, 0xf7, 0xb7, + 0x82, 0x70, 0x72, 0x09, 0x3d, 0x3e, 0x93, 0xb1, 0xc3, 0x41, 0x4e, 0x48, 0xa4, 0x4c, 0xdd, 0xa8, 0xc7, 0x53, 0xde, + 0x88, 0x22, 0x6c, 0x47, 0x89, 0x3f, 0x0b, 0x84, 0xb9, 0x06, 0xd4, 0x4d, 0x92, 0x44, 0x23, 0x72, 0xb9, 0xf4, 0x60, + 0xe1, 0xc1, 0x44, 0x7b, 0xbc, 0xdf, 0x1a, 0xa4, 0x3a, 0x29, 0xd8, 0x68, 0x91, 0xb1, 0x38, 0x16, 0x58, 0x61, 0x89, + 0xc8, 0xa5, 0x68, 0xc4, 0x05, 0xb9, 0x84, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xb9, 0x41, 0x16, 0x7e, + 0x84, 0x00, 0x62, 0x37, 0xa0, 0x82, 0x90, 0x48, 0x2c, 0x66, 0x43, 0x56, 0x44, 0x65, 0xb1, 0x6e, 0x0d, 0x2f, 0x16, + 0x8a, 0xed, 0x65, 0x4a, 0xed, 0x8d, 0x17, 0x22, 0xd3, 0x5c, 0x8a, 0xbd, 0xa8, 0x51, 0x34, 0x22, 0x8b, 0x0f, 0x25, + 0x3a, 0x44, 0x68, 0x8d, 0x62, 0x85, 0x1a, 0xbc, 0x2f, 0x1b, 0xed, 0x01, 0x86, 0x51, 0xa2, 0xae, 0x6b, 0xcf, 0x41, + 0x80, 0x61, 0x0e, 0x93, 0x5c, 0xe3, 0x4f, 0x76, 0xe7, 0xc3, 0x14, 0x6f, 0x44, 0x8f, 0x27, 0xdb, 0x3b, 0x85, 0xe8, + 0x64, 0x46, 0xe7, 0x31, 0x23, 0x97, 0xcc, 0x60, 0x17, 0x15, 0x19, 0x8c, 0xb5, 0xb6, 0x70, 0x3d, 0x96, 0xb2, 0xa4, + 0xc2, 0x29, 0x94, 0xea, 0x64, 0x2c, 0x8b, 0xa7, 0x34, 0x9b, 0x42, 0xbd, 0x12, 0x63, 0x46, 0x7e, 0xc3, 0x65, 0x05, + 0xa3, 0x9a, 0x3d, 0xcd, 0x19, 0x7c, 0xc5, 0x91, 0xa9, 0x19, 0x21, 0xac, 0x60, 0xab, 0xe7, 0x5c, 0xbf, 0x92, 0x22, + 0x63, 0x5d, 0x15, 0xe0, 0x97, 0x59, 0xf9, 0x87, 0x5a, 0x17, 0x7c, 0xb8, 0xd0, 0x2c, 0x8e, 0x04, 0x94, 0x88, 0xb0, + 0x42, 0x58, 0x24, 0x9a, 0xdd, 0xea, 0xc7, 0x52, 0x68, 0x26, 0x34, 0x61, 0x1e, 0xaa, 0x98, 0x27, 0x74, 0x3e, 0x67, + 0x62, 0xf4, 0x78, 0xca, 0xf3, 0x51, 0x2c, 0xd0, 0x1a, 0xad, 0xf1, 0xef, 0x82, 0xc0, 0x24, 0xc9, 0x25, 0x4f, 0xe1, + 0x9f, 0x6f, 0x4f, 0x27, 0xd6, 0xe4, 0xd2, 0x6c, 0x0b, 0x46, 0xa2, 0xa8, 0x3b, 0x96, 0x45, 0xec, 0xa6, 0xb0, 0x07, + 0xa4, 0x0b, 0xfa, 0x78, 0xbb, 0xc8, 0x99, 0x42, 0xac, 0x41, 0x44, 0xb9, 0x8e, 0x0e, 0xc2, 0xbf, 0x15, 0x31, 0x83, + 0x05, 0xe0, 0x28, 0xe5, 0x86, 0x04, 0xbe, 0xe4, 0x6e, 0x53, 0x8d, 0x4a, 0xa2, 0xf6, 0x51, 0x90, 0x11, 0x4f, 0x74, + 0xb1, 0x50, 0x9a, 0x8d, 0xde, 0xdd, 0xcd, 0x99, 0xc2, 0x3f, 0x17, 0xe4, 0xa3, 0xe8, 0x7d, 0x14, 0x09, 0x9b, 0xcd, + 0xf5, 0xdd, 0x95, 0xa1, 0xe6, 0x69, 0x14, 0xe1, 0x7f, 0x4c, 0xd1, 0x82, 0xd1, 0x0c, 0x48, 0x9a, 0x03, 0xd9, 0x1b, + 0x99, 0xdf, 0x8d, 0x79, 0x9e, 0x5f, 0x2d, 0xe6, 0x73, 0x59, 0x68, 0xac, 0x05, 0x59, 0x6a, 0x59, 0xc1, 0x07, 0x56, + 0x74, 0xa9, 0x6e, 0xb8, 0xce, 0xa6, 0xb1, 0x46, 0xcb, 0x8c, 0x2a, 0xb6, 0xf7, 0x48, 0xca, 0x9c, 0x51, 0x91, 0x72, + 0xc2, 0x7b, 0x3f, 0x17, 0xa9, 0x58, 0xe4, 0x79, 0x77, 0x58, 0x30, 0xfa, 0xb9, 0x6b, 0xb2, 0xed, 0xe1, 0x90, 0x9a, + 0xdf, 0x0f, 0x8b, 0x82, 0xde, 0x41, 0x41, 0x42, 0xa0, 0x58, 0x8f, 0xa7, 0x3f, 0x5f, 0xbd, 0x7e, 0x95, 0xd8, 0xbd, + 0xc2, 0xc7, 0x77, 0x31, 0x2f, 0xf7, 0x1f, 0x5f, 0xe3, 0x71, 0x21, 0x67, 0x1b, 0x5d, 0x5b, 0xd0, 0xf1, 0xee, 0x37, + 0x86, 0xc0, 0x08, 0xdf, 0xb7, 0x4d, 0x87, 0x23, 0x78, 0x65, 0x30, 0x1f, 0x32, 0x89, 0xeb, 0x17, 0xfe, 0x49, 0x6d, + 0x72, 0xcc, 0xd1, 0xf7, 0x47, 0xab, 0x8b, 0xbb, 0x25, 0x23, 0x66, 0x9c, 0x73, 0x38, 0x18, 0x61, 0x8c, 0x19, 0xd5, + 0xd9, 0x74, 0xc9, 0x4c, 0x63, 0x6b, 0x3f, 0x62, 0xb6, 0x5e, 0xe3, 0xaf, 0xd2, 0x63, 0xbd, 0xde, 0x27, 0x84, 0x1b, + 0x7a, 0x45, 0xf4, 0x6a, 0xc5, 0x09, 0xe1, 0x08, 0xbf, 0xe5, 0x64, 0x49, 0xfd, 0x84, 0xe0, 0x64, 0x83, 0xed, 0x99, + 0x5a, 0x2a, 0x03, 0x27, 0xe0, 0x17, 0x56, 0x68, 0x56, 0xa4, 0x5a, 0xe0, 0x82, 0x8d, 0x73, 0x18, 0xc7, 0x7e, 0x1b, + 0x4f, 0xa9, 0x7a, 0x3c, 0xa5, 0x62, 0xc2, 0x46, 0xe9, 0x57, 0xb9, 0xc6, 0x4c, 0x90, 0x68, 0xcc, 0x05, 0xcd, 0xf9, + 0x57, 0x36, 0x8a, 0xdc, 0xb9, 0xf0, 0x48, 0xef, 0xb1, 0x5b, 0xcd, 0xc4, 0x48, 0xed, 0x3d, 0x7f, 0xf7, 0xeb, 0x4b, + 0xb7, 0x98, 0xb5, 0xb3, 0x02, 0x2d, 0xd5, 0x62, 0xce, 0x8a, 0x18, 0x61, 0x77, 0x56, 0x3c, 0xe5, 0x86, 0x4e, 0xfe, + 0x4a, 0xe7, 0x36, 0x85, 0xab, 0xdf, 0xe7, 0x23, 0xaa, 0xd9, 0x1b, 0x26, 0x46, 0x5c, 0x4c, 0xc8, 0x7e, 0xdb, 0xa6, + 0x4f, 0xa9, 0xcb, 0x18, 0x95, 0x49, 0xd7, 0xf7, 0x9e, 0xe6, 0x66, 0xee, 0xe5, 0xe7, 0x22, 0x46, 0x6b, 0xa5, 0xa9, + 0xe6, 0xd9, 0x1e, 0x1d, 0x8d, 0x5e, 0x08, 0xae, 0xb9, 0x19, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xec, 0xa9, 0xe1, + 0x47, 0x1e, 0x23, 0x1c, 0xc7, 0xee, 0x2c, 0x98, 0x22, 0xb7, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb1, 0xd4, 0x66, + 0x92, 0xfe, 0x00, 0x25, 0xf3, 0x85, 0x82, 0xc5, 0xf6, 0x5d, 0xc0, 0x41, 0x23, 0x87, 0x8a, 0x15, 0x5f, 0xd8, 0xa8, + 0x44, 0x10, 0x15, 0xa3, 0xe5, 0x46, 0x1f, 0x6e, 0x7b, 0x68, 0xd2, 0x1f, 0x74, 0x43, 0x12, 0xce, 0x1c, 0xb2, 0x5b, + 0x4e, 0x85, 0x33, 0x55, 0x12, 0x95, 0x18, 0x0e, 0xd4, 0x92, 0xb0, 0x28, 0xe2, 0xe7, 0x37, 0x8f, 0x05, 0xf0, 0x10, + 0x21, 0xe5, 0xf0, 0x67, 0xee, 0xd3, 0x2f, 0xe6, 0xf0, 0x50, 0x58, 0x20, 0xac, 0xed, 0x48, 0x15, 0x42, 0x6b, 0x84, + 0xb5, 0x1f, 0xae, 0x25, 0x4a, 0x9e, 0x2f, 0x82, 0x53, 0x9b, 0xbc, 0xe5, 0xe6, 0xd8, 0x06, 0xda, 0x46, 0x35, 0x3b, + 0x38, 0x88, 0x59, 0x52, 0x22, 0x06, 0xd9, 0x6f, 0xbb, 0x45, 0x0a, 0xa0, 0xf5, 0x8d, 0x71, 0x43, 0xcf, 0x86, 0xc1, + 0xd9, 0x67, 0x89, 0x90, 0x0f, 0xb3, 0x8c, 0x29, 0x25, 0x8b, 0x83, 0x83, 0x7d, 0x53, 0xbe, 0xe4, 0x2c, 0x60, 0x11, + 0x5f, 0xdf, 0x88, 0x6a, 0x08, 0xa8, 0x3a, 0x6d, 0x3d, 0xdf, 0x44, 0x2a, 0xbe, 0xc9, 0x33, 0x21, 0x69, 0x74, 0x7d, + 0x1d, 0x35, 0x34, 0x76, 0x70, 0x98, 0x30, 0xdf, 0xf5, 0xdd, 0x13, 0x66, 0xd9, 0x42, 0xc3, 0x84, 0x6c, 0x81, 0x66, + 0x27, 0x3f, 0x18, 0xd7, 0x87, 0x84, 0x35, 0x56, 0x68, 0x1d, 0xac, 0xe8, 0xce, 0xa6, 0x0d, 0x7f, 0x63, 0x97, 0x6e, + 0x39, 0x31, 0x3c, 0x45, 0xb0, 0x8e, 0x7d, 0x36, 0x58, 0x63, 0x03, 0x7b, 0x3f, 0x1b, 0x69, 0x06, 0xda, 0xd7, 0x83, + 0xae, 0xcb, 0x27, 0xca, 0x42, 0xae, 0x60, 0xff, 0x2c, 0x98, 0xd2, 0x16, 0x91, 0x63, 0x8d, 0x25, 0x86, 0x33, 0x6a, + 0x93, 0xe9, 0xac, 0xb1, 0xa4, 0xbb, 0xc6, 0xf6, 0x7a, 0x0e, 0x67, 0xa3, 0x02, 0xa4, 0xfe, 0x3e, 0x3e, 0xc1, 0x58, + 0x35, 0x5a, 0xad, 0xde, 0x72, 0xdf, 0x4a, 0xb5, 0x96, 0x25, 0xbf, 0xb6, 0xb1, 0x28, 0x4c, 0x20, 0x77, 0x38, 0xef, + 0xb7, 0xdd, 0xf8, 0xc5, 0x80, 0xec, 0xb7, 0x4a, 0x2c, 0x76, 0x60, 0xb5, 0xe3, 0xb1, 0x50, 0x7c, 0x6d, 0x9b, 0x42, + 0xe6, 0xac, 0xaf, 0xe1, 0x4b, 0x32, 0xdd, 0xc2, 0xd5, 0x29, 0xe9, 0x03, 0xd7, 0x91, 0x4c, 0x07, 0xdf, 0xc2, 0x27, + 0x4f, 0x11, 0x62, 0xbd, 0x9d, 0x57, 0x11, 0x8e, 0x2f, 0x75, 0xc2, 0xb1, 0x31, 0x8d, 0x68, 0x5e, 0x56, 0x89, 0x4a, + 0x34, 0x73, 0x5b, 0xbd, 0xca, 0xc2, 0xc2, 0x0c, 0xa6, 0x9a, 0x52, 0xd0, 0xc4, 0x2b, 0x3a, 0x63, 0x2a, 0x66, 0x08, + 0x7f, 0xab, 0x80, 0xc5, 0x4f, 0x28, 0x32, 0x08, 0xce, 0x50, 0x05, 0x67, 0x28, 0xb0, 0xbb, 0xc0, 0xa4, 0xd5, 0xb7, + 0x9c, 0xc2, 0xac, 0xaf, 0x06, 0x15, 0x6f, 0x17, 0x4c, 0xde, 0x1c, 0xce, 0x0e, 0xc1, 0x3d, 0xfc, 0x6c, 0x9a, 0x05, + 0x9a, 0x61, 0x21, 0x14, 0xc2, 0xfb, 0xad, 0xcd, 0x95, 0xf4, 0xa5, 0xaa, 0x39, 0xf6, 0x07, 0xb0, 0x0e, 0xe6, 0xd8, + 0x48, 0xb8, 0x32, 0x7f, 0x6b, 0x5b, 0x0d, 0xc0, 0x76, 0x05, 0x98, 0x91, 0x8c, 0x73, 0xaa, 0xe3, 0xf6, 0x51, 0x0b, + 0x18, 0xd3, 0x2f, 0x0c, 0x4e, 0x15, 0x84, 0xb6, 0xa7, 0xc2, 0x92, 0x85, 0x50, 0x53, 0x3e, 0xd6, 0xf1, 0xef, 0xc2, + 0x10, 0x15, 0x96, 0x2b, 0x06, 0x12, 0x4e, 0xc0, 0x1e, 0x1b, 0x82, 0xf3, 0xbb, 0x80, 0x7e, 0xba, 0xe5, 0x41, 0xe4, + 0x46, 0x6a, 0x08, 0x17, 0x90, 0x87, 0x8a, 0xb5, 0xae, 0xc8, 0x4c, 0xc9, 0xb8, 0x01, 0xf7, 0xd8, 0xee, 0xd9, 0x16, + 0x53, 0x47, 0x0d, 0x44, 0xc0, 0xc1, 0x8a, 0x34, 0x24, 0x11, 0x2e, 0x51, 0x27, 0x5a, 0xbe, 0x94, 0x37, 0xac, 0x78, + 0x4c, 0x61, 0xf0, 0xa9, 0xad, 0xbe, 0xb6, 0x47, 0x81, 0xa1, 0xf8, 0xba, 0xeb, 0xf1, 0xe5, 0xda, 0x4c, 0xfc, 0x4d, + 0x21, 0x67, 0x5c, 0x31, 0xe0, 0xdb, 0x2c, 0xfc, 0x05, 0x6c, 0x34, 0xb3, 0x23, 0xe1, 0xb8, 0x61, 0x25, 0x7e, 0x3d, + 0x7c, 0x59, 0xc7, 0xaf, 0xeb, 0x7b, 0x4f, 0x27, 0x9e, 0x02, 0xd6, 0xf7, 0x31, 0xc2, 0xb1, 0x13, 0x2f, 0x82, 0x93, + 0x2e, 0x99, 0x22, 0x77, 0xcc, 0xaf, 0x56, 0x3a, 0x10, 0xe3, 0x6a, 0x9c, 0x23, 0xb3, 0xdb, 0x06, 0xad, 0xe9, 0x68, + 0x04, 0x2c, 0x5e, 0x21, 0xf3, 0x3c, 0x38, 0xac, 0xb0, 0xe8, 0x96, 0xc7, 0xd3, 0xf5, 0xbd, 0xa7, 0x57, 0xdf, 0x3b, + 0xa1, 0x20, 0x3f, 0x3c, 0xa4, 0xfc, 0x40, 0xc5, 0x88, 0x15, 0x20, 0x57, 0x06, 0xab, 0xe5, 0xce, 0xd9, 0xc7, 0x52, + 0x08, 0x96, 0x69, 0x36, 0x02, 0xa1, 0x45, 0x10, 0x9d, 0x4c, 0xa5, 0xd2, 0x65, 0x62, 0x35, 0x7a, 0x11, 0x0a, 0xa1, + 0x49, 0x46, 0xf3, 0x3c, 0xb6, 0x02, 0xca, 0x4c, 0x7e, 0x61, 0x3b, 0x46, 0xdd, 0xad, 0x0d, 0xb9, 0x6c, 0x86, 0x05, + 0xcd, 0xb0, 0x44, 0xcd, 0x73, 0x9e, 0xb1, 0xf2, 0xf0, 0xba, 0x4a, 0xb8, 0x18, 0xb1, 0x5b, 0xa0, 0x23, 0xe8, 0xf2, + 0xf2, 0xb2, 0x85, 0xdb, 0x68, 0x6d, 0x01, 0xbe, 0xdc, 0x02, 0xec, 0x77, 0x8e, 0x4d, 0x2b, 0x88, 0x2f, 0x77, 0x92, + 0x35, 0x14, 0x9c, 0x95, 0xdc, 0x0b, 0x5a, 0x96, 0x3c, 0x23, 0x3c, 0x62, 0x39, 0xd3, 0xcc, 0x93, 0x73, 0x60, 0xa6, + 0xed, 0xd6, 0x7d, 0x5b, 0xc2, 0xaf, 0x44, 0x27, 0xbf, 0xcb, 0xfc, 0x9a, 0xab, 0x52, 0x74, 0xaf, 0x96, 0xa7, 0x82, + 0x76, 0x4f, 0xdb, 0xe5, 0xa1, 0x5a, 0xd3, 0x6c, 0x6a, 0x25, 0xf6, 0x78, 0x6b, 0x4a, 0x55, 0x1b, 0x8e, 0xb4, 0x97, + 0x9b, 0xe8, 0x53, 0xe1, 0x86, 0xb9, 0x0b, 0x04, 0x57, 0x8e, 0x28, 0x30, 0x10, 0x02, 0xed, 0xb2, 0x3d, 0xa6, 0x79, + 0x3e, 0xa4, 0xd9, 0xe7, 0x3a, 0xf6, 0x57, 0x68, 0x40, 0x36, 0xa9, 0x71, 0x90, 0x15, 0x90, 0xac, 0x70, 0xde, 0x9e, + 0x4a, 0xd7, 0x36, 0x4a, 0xbc, 0xdf, 0xaa, 0xd0, 0xbe, 0xbe, 0xd0, 0xdf, 0xc4, 0x76, 0x33, 0x22, 0xe1, 0x66, 0x16, + 0x03, 0x15, 0xf8, 0x97, 0x18, 0xe7, 0xe9, 0x81, 0xc3, 0x3b, 0x10, 0x3c, 0xd6, 0x1b, 0x03, 0xd1, 0x68, 0xb9, 0x1e, + 0x71, 0xf5, 0x6d, 0x08, 0xfc, 0x6f, 0x19, 0xe5, 0x93, 0xa0, 0x87, 0x7f, 0x77, 0xa0, 0x25, 0x8d, 0x73, 0x8c, 0x73, + 0x39, 0x32, 0xc7, 0x50, 0x78, 0x42, 0xf3, 0x0b, 0x30, 0x2f, 0x06, 0xdf, 0x5f, 0xdb, 0x2c, 0xc3, 0x97, 0xc1, 0x30, + 0x54, 0x37, 0x64, 0x28, 0x6a, 0x28, 0xe0, 0x88, 0xaa, 0x30, 0x67, 0xae, 0xac, 0x89, 0x92, 0x8e, 0x6b, 0xb7, 0xe2, + 0xb8, 0xa3, 0xb9, 0x05, 0x89, 0xe3, 0x58, 0x81, 0x34, 0xe7, 0xf9, 0xfb, 0x6a, 0x16, 0x6a, 0x6b, 0x16, 0x2a, 0x09, + 0xa4, 0x2d, 0x54, 0x21, 0x73, 0x50, 0x3d, 0xd5, 0x02, 0x85, 0xa5, 0x80, 0x65, 0x4d, 0x80, 0x42, 0xa3, 0x92, 0xe0, + 0xe6, 0x44, 0xe3, 0xc2, 0x89, 0x3a, 0x0e, 0xd7, 0x80, 0x64, 0x54, 0x55, 0x24, 0xb2, 0x9b, 0xa3, 0x26, 0xfb, 0x4a, + 0x5c, 0xa0, 0x0d, 0xfe, 0x7e, 0xbd, 0x76, 0x50, 0x62, 0xc8, 0xad, 0x4e, 0x8d, 0x31, 0x0e, 0xc0, 0x82, 0x25, 0x71, + 0xcc, 0xb0, 0x65, 0x7d, 0x36, 0x81, 0x53, 0xb6, 0xbb, 0x4f, 0x88, 0xac, 0x60, 0x53, 0x63, 0x2a, 0x3d, 0x77, 0x25, + 0x11, 0xa6, 0x9e, 0x2d, 0x2d, 0xaa, 0x89, 0x13, 0x12, 0x79, 0xed, 0x44, 0xd4, 0x5b, 0xd6, 0x84, 0xc3, 0x34, 0x28, + 0xb6, 0x4e, 0x81, 0xa8, 0x16, 0xbb, 0xe0, 0xbd, 0x0b, 0x6b, 0x6a, 0xed, 0x04, 0x10, 0x2f, 0x6a, 0x10, 0x0f, 0x40, + 0x2b, 0x2d, 0xf1, 0x92, 0x03, 0x42, 0xeb, 0x95, 0x63, 0x86, 0x0b, 0xbb, 0x10, 0x5b, 0x50, 0xdc, 0x64, 0x3f, 0x0d, + 0x16, 0x82, 0x2c, 0xab, 0x80, 0xbf, 0x0b, 0x8f, 0x88, 0x18, 0x06, 0x2f, 0x56, 0xab, 0x2d, 0xb4, 0xdb, 0xc9, 0x85, + 0xa2, 0xa4, 0x92, 0x0e, 0x57, 0xab, 0xaf, 0x12, 0xc5, 0x8e, 0xff, 0xc5, 0x0c, 0xf5, 0x3c, 0xd1, 0x7d, 0xf8, 0x12, + 0x4a, 0x19, 0x76, 0xb4, 0x4a, 0x29, 0x05, 0x87, 0x3a, 0xd6, 0xd6, 0x17, 0x4a, 0x07, 0x94, 0xfb, 0xf1, 0x16, 0x01, + 0x33, 0x89, 0xee, 0xa4, 0xae, 0xa6, 0xfc, 0xd8, 0x35, 0x2d, 0x10, 0x42, 0xa9, 0x32, 0xb2, 0xcc, 0xfe, 0x2e, 0xf9, + 0xf2, 0xe0, 0x40, 0x05, 0x0d, 0x5d, 0x97, 0x94, 0xe2, 0xef, 0x18, 0x4e, 0x65, 0x75, 0x27, 0x0c, 0xfb, 0xf2, 0xb7, + 0x3f, 0x87, 0xb6, 0xa4, 0xd3, 0x56, 0x17, 0x04, 0x73, 0x7a, 0x43, 0xb9, 0xde, 0x2b, 0x5b, 0xb1, 0x82, 0x79, 0xcc, + 0xd0, 0xd2, 0x71, 0x1b, 0x49, 0xc1, 0x80, 0x7f, 0x04, 0xb2, 0xe0, 0xb9, 0x68, 0x8b, 0xf8, 0xd9, 0x94, 0x81, 0x2a, + 0xdb, 0x33, 0x12, 0xa5, 0x78, 0xb8, 0xef, 0x0e, 0x12, 0xd7, 0xf0, 0xee, 0xb1, 0xaf, 0x37, 0xab, 0xd7, 0xa4, 0x81, + 0x39, 0x2b, 0xc6, 0xb2, 0x98, 0xf9, 0xbc, 0xf5, 0xc6, 0xb7, 0x23, 0x8e, 0x7c, 0x1c, 0xef, 0x6c, 0xdb, 0x89, 0x00, + 0xdd, 0x0d, 0xd9, 0xbb, 0x92, 0xda, 0x6b, 0xa7, 0x69, 0x79, 0x00, 0x5b, 0x05, 0xa1, 0xc7, 0x4c, 0x15, 0x4a, 0xf9, + 0x4e, 0xbd, 0xda, 0xb5, 0xba, 0x93, 0xfd, 0x76, 0xb7, 0x94, 0xfc, 0x3c, 0x36, 0x74, 0xad, 0x8e, 0xc3, 0x9d, 0xaa, + 0x72, 0x91, 0x8f, 0xdc, 0x60, 0x05, 0xc2, 0xcc, 0xe1, 0xd1, 0x0d, 0xcf, 0xf3, 0x2a, 0xf5, 0x3f, 0x21, 0xed, 0xca, + 0x91, 0x76, 0xe9, 0x49, 0x3b, 0x90, 0x0a, 0x20, 0xed, 0xb6, 0xb9, 0xaa, 0xba, 0xdc, 0xda, 0x9e, 0xd2, 0x12, 0x75, + 0x65, 0xc4, 0x69, 0xe8, 0x6f, 0xe1, 0x47, 0x80, 0x4a, 0xe6, 0xeb, 0x73, 0xec, 0xf4, 0x31, 0x20, 0x06, 0x5a, 0x9d, + 0x26, 0x0b, 0x35, 0x15, 0x9f, 0x63, 0x84, 0xd5, 0x9a, 0x95, 0x98, 0xfd, 0xf0, 0x29, 0x28, 0xed, 0x82, 0xe9, 0xc0, + 0x39, 0x66, 0x92, 0xff, 0x23, 0x3e, 0xca, 0xcf, 0x4e, 0xb8, 0xd9, 0x29, 0x3f, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0x46, + 0xdf, 0xa7, 0xf6, 0x66, 0x7a, 0xa2, 0x9c, 0x5e, 0xb5, 0xde, 0xab, 0x55, 0xbc, 0x91, 0x02, 0x1a, 0x7d, 0x27, 0xa5, + 0x14, 0x65, 0xeb, 0x40, 0x03, 0x42, 0xc8, 0x40, 0xc2, 0xda, 0x4e, 0xba, 0x3c, 0xe5, 0x5e, 0xfe, 0x2b, 0x3d, 0x8f, + 0x51, 0xdc, 0xdb, 0xfa, 0x8f, 0xe5, 0x6c, 0x0e, 0x0c, 0xd9, 0x06, 0x4a, 0x4f, 0x98, 0xeb, 0xb0, 0xca, 0x5f, 0xef, + 0x48, 0xab, 0xd5, 0x31, 0xfb, 0xb1, 0x86, 0x4d, 0xa5, 0xd4, 0xbc, 0xdf, 0x5a, 0x2f, 0xca, 0xa4, 0x92, 0x70, 0xec, + 0xd2, 0xad, 0x3c, 0xde, 0xd4, 0xcc, 0xf8, 0x8c, 0xd7, 0xb1, 0xb0, 0x74, 0x58, 0x00, 0xad, 0x0b, 0xc8, 0x8f, 0x47, + 0xf7, 0x70, 0xfd, 0xd7, 0x15, 0x70, 0x96, 0xeb, 0x0d, 0xf0, 0x2d, 0xd7, 0xeb, 0x47, 0xda, 0x49, 0xda, 0xf8, 0xd1, + 0x0e, 0xb9, 0xb7, 0x84, 0x5e, 0x95, 0xe9, 0x64, 0xc6, 0xfe, 0x00, 0xd2, 0xb6, 0x58, 0x48, 0xb2, 0x9c, 0xc9, 0x11, + 0x4b, 0x23, 0x39, 0x67, 0x22, 0x5a, 0x83, 0x9e, 0xd5, 0x21, 0xc0, 0x3f, 0x22, 0x5e, 0xbe, 0xad, 0xeb, 0x5b, 0xd3, + 0x47, 0x7a, 0x0d, 0xaa, 0xb0, 0x97, 0x7c, 0x87, 0x32, 0xf6, 0x3d, 0x2b, 0x94, 0xe1, 0x49, 0x4b, 0xf6, 0xf6, 0x25, + 0xaf, 0x0e, 0xa8, 0x97, 0x3c, 0xfd, 0x76, 0x95, 0x4a, 0x20, 0x89, 0xda, 0xc9, 0x59, 0x72, 0x1c, 0x21, 0xa3, 0x31, + 0x7e, 0xe6, 0x35, 0xc6, 0x8b, 0x52, 0x63, 0xfc, 0x5c, 0x93, 0xc5, 0x86, 0xc6, 0xf8, 0x0f, 0x41, 0x9e, 0xeb, 0xde, + 0x73, 0xaf, 0x4d, 0x7f, 0x23, 0x73, 0x9e, 0xdd, 0xc5, 0x51, 0xce, 0x75, 0x13, 0x6e, 0x13, 0x23, 0xbc, 0xb4, 0x19, + 0xa0, 0x6a, 0x34, 0xfa, 0xee, 0xb5, 0x97, 0xff, 0xb0, 0x10, 0x24, 0xba, 0x97, 0x73, 0x7d, 0x2f, 0xc2, 0x53, 0x4d, + 0xfe, 0x82, 0x5f, 0xf7, 0x96, 0xf1, 0xaf, 0x54, 0x4f, 0x93, 0x82, 0x8a, 0x91, 0x9c, 0xc5, 0xa8, 0x11, 0x45, 0x28, + 0x51, 0x46, 0x08, 0x79, 0x80, 0xd6, 0xf7, 0xfe, 0xc2, 0xaf, 0x24, 0x89, 0x7a, 0x51, 0x63, 0xaa, 0xb1, 0xa6, 0xe4, + 0xaf, 0x8b, 0x7b, 0xcb, 0x57, 0x72, 0x7d, 0xf9, 0x17, 0x7e, 0xaa, 0x4b, 0xb5, 0x3e, 0xbe, 0x65, 0x24, 0x46, 0xe4, + 0xf2, 0xa9, 0x1f, 0xd2, 0x63, 0x39, 0xb3, 0x0a, 0xfe, 0x08, 0xe1, 0x2f, 0xa0, 0xd7, 0xbd, 0xe4, 0x15, 0x11, 0x72, + 0x77, 0x30, 0xfb, 0x24, 0x92, 0x46, 0x79, 0x10, 0x1d, 0x1c, 0x04, 0x69, 0x25, 0x0b, 0x81, 0xff, 0x96, 0xa4, 0x26, + 0xaa, 0x63, 0x46, 0xa1, 0xa5, 0xbf, 0x65, 0xcc, 0x91, 0x6f, 0x26, 0xf6, 0x9a, 0x6a, 0xb7, 0x63, 0x79, 0xdf, 0xea, + 0x1e, 0x12, 0xae, 0x59, 0x41, 0xb5, 0x2c, 0x06, 0x28, 0x64, 0x4b, 0xf0, 0x57, 0x4e, 0xfe, 0xea, 0xef, 0xfd, 0x3f, + 0xff, 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xe0, 0x2f, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, + 0xfe, 0x3c, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x34, 0x40, 0xab, 0xf8, 0xcf, 0xa3, 0x5e, 0xdf, 0x7d, + 0xf5, 0xff, 0xfb, 0xf2, 0x4f, 0x35, 0x38, 0xb4, 0x89, 0xf7, 0x10, 0x3a, 0x9a, 0xe0, 0x5f, 0x04, 0x39, 0x6a, 0x36, + 0x2f, 0x8f, 0x26, 0xf8, 0x27, 0x41, 0x8e, 0xe0, 0xef, 0x9d, 0x26, 0x6f, 0xd9, 0xe4, 0xe9, 0xed, 0x3c, 0xfe, 0xeb, + 0x72, 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf9, 0xa7, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, + 0x06, 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0x3f, 0xff, 0xba, + 0xb8, 0x24, 0x83, 0x55, 0x1c, 0xad, 0x7e, 0x44, 0x2b, 0x84, 0x56, 0xf7, 0xd0, 0x5f, 0x38, 0x9a, 0x44, 0x08, 0xff, + 0x26, 0xc8, 0xd1, 0x8f, 0x47, 0x13, 0xfc, 0x49, 0x90, 0xa3, 0xe8, 0x68, 0x82, 0xdf, 0x4b, 0x72, 0xf4, 0xdf, 0x71, + 0x2f, 0xb5, 0x4a, 0xb8, 0x95, 0x51, 0x7f, 0xac, 0xe0, 0x26, 0x84, 0x16, 0x8c, 0xae, 0x34, 0xd7, 0x39, 0x43, 0xf7, + 0x8e, 0x38, 0x7e, 0x24, 0x01, 0x58, 0xb1, 0x06, 0x25, 0x8d, 0xb9, 0x84, 0x5d, 0x5e, 0xc3, 0xc2, 0x03, 0x06, 0xdd, + 0x4b, 0x39, 0xb6, 0x7a, 0x02, 0x95, 0x6a, 0x7b, 0x7b, 0xab, 0xe0, 0xfa, 0x16, 0x3f, 0x26, 0x8f, 0x64, 0xdc, 0x46, + 0x98, 0x53, 0xf8, 0xd1, 0x41, 0xf8, 0x83, 0x76, 0x17, 0x9e, 0xb0, 0xcd, 0x2d, 0x86, 0x09, 0x69, 0xf9, 0x99, 0x08, + 0xe1, 0x97, 0x3b, 0x32, 0xf5, 0x14, 0xd4, 0x0f, 0x08, 0xff, 0x5c, 0xbb, 0x1e, 0xc5, 0x8f, 0x35, 0x29, 0x91, 0xe3, + 0x5d, 0xc1, 0xd8, 0x07, 0x9a, 0x7f, 0x66, 0x45, 0xfc, 0x54, 0xe3, 0x76, 0xe7, 0x01, 0x36, 0xaa, 0xea, 0xfd, 0x36, + 0xea, 0x96, 0xb7, 0x5b, 0xcf, 0xa5, 0xbd, 0x4f, 0x80, 0x53, 0xb8, 0xae, 0xaf, 0x81, 0xb5, 0xdf, 0xe7, 0x5b, 0x4a, + 0xad, 0x82, 0xde, 0x44, 0xa8, 0x7e, 0x95, 0xca, 0xc5, 0x17, 0x9a, 0xf3, 0xd1, 0x9e, 0x66, 0xb3, 0x79, 0x4e, 0x35, + 0xdb, 0x73, 0x73, 0xde, 0xa3, 0xd0, 0x50, 0x54, 0xf2, 0x14, 0x7f, 0x88, 0x6a, 0xd3, 0xfe, 0x21, 0x92, 0x6a, 0xef, + 0xc4, 0x70, 0x9f, 0xe5, 0xf8, 0x12, 0x41, 0xcb, 0xeb, 0xb2, 0xcd, 0x1b, 0xc1, 0x66, 0x1b, 0x94, 0x65, 0x03, 0x73, + 0x7e, 0x2b, 0x0c, 0xf7, 0x9b, 0x84, 0x74, 0x7a, 0xd1, 0x85, 0xfa, 0x32, 0xb9, 0x8c, 0xe0, 0x26, 0xa7, 0x20, 0x82, + 0x19, 0xe5, 0x11, 0x94, 0xa0, 0xa4, 0xd5, 0xa5, 0x17, 0xac, 0x4b, 0x1b, 0x0d, 0xcf, 0x66, 0x67, 0x84, 0xf7, 0xa9, + 0xad, 0x9f, 0xe3, 0x29, 0x1e, 0x91, 0x66, 0x1b, 0x2f, 0x48, 0xcb, 0x54, 0xe9, 0x2e, 0x2e, 0x32, 0xd7, 0xcf, 0xc1, + 0x41, 0x5c, 0x24, 0x39, 0x55, 0xfa, 0x05, 0x68, 0x04, 0xc8, 0x02, 0x4f, 0x49, 0x91, 0xb0, 0x5b, 0x96, 0xc5, 0x19, + 0xc2, 0x53, 0x47, 0x83, 0x50, 0x17, 0x2d, 0x48, 0x50, 0x0c, 0xe4, 0x0c, 0x22, 0x58, 0x6f, 0xda, 0x6f, 0x0f, 0x08, + 0x21, 0xd1, 0x7e, 0xb3, 0x19, 0xf5, 0x0a, 0xf2, 0x8b, 0x48, 0x21, 0x25, 0x60, 0xa7, 0xc9, 0x4f, 0x90, 0xd4, 0x09, + 0x92, 0xe2, 0xf7, 0x32, 0xd1, 0x4c, 0xe9, 0x18, 0x92, 0x41, 0x49, 0xa0, 0x3c, 0x86, 0x47, 0x17, 0x47, 0x51, 0x03, + 0x52, 0x0d, 0x8a, 0x22, 0x5c, 0x90, 0x3b, 0x8d, 0xd2, 0x69, 0xff, 0x78, 0x10, 0x9e, 0x11, 0x36, 0x15, 0xfa, 0xbf, + 0xd3, 0xbd, 0x69, 0xbf, 0x65, 0xfa, 0xbf, 0x8c, 0x7a, 0x71, 0x41, 0x94, 0x65, 0xe3, 0x7a, 0x2a, 0x15, 0xcc, 0xcc, + 0x17, 0xa5, 0x6e, 0x80, 0xae, 0xef, 0x11, 0x69, 0x76, 0xd2, 0x78, 0x14, 0xce, 0xa4, 0x09, 0x1d, 0x3a, 0x50, 0xe0, + 0x9c, 0x40, 0x79, 0x5c, 0x10, 0xe8, 0xb4, 0xaa, 0x76, 0xa7, 0x53, 0x97, 0xf0, 0x63, 0xf4, 0x63, 0xef, 0x93, 0x48, + 0x7f, 0x13, 0x76, 0x04, 0x9f, 0xc4, 0x6a, 0x05, 0x7f, 0x7f, 0x13, 0x3d, 0x18, 0x96, 0x49, 0xfb, 0xc5, 0xa5, 0xfd, + 0x04, 0x69, 0x82, 0xa5, 0x66, 0xc0, 0x58, 0x95, 0xfc, 0x98, 0x5d, 0x9c, 0x31, 0xb1, 0x33, 0x38, 0x38, 0xe0, 0x7d, + 0xda, 0x68, 0x0f, 0xe0, 0x46, 0xa0, 0xd0, 0xea, 0x03, 0xd7, 0xd3, 0x38, 0x3a, 0xba, 0x8c, 0x50, 0x2f, 0xda, 0x83, + 0x55, 0xee, 0xca, 0x06, 0x71, 0xb0, 0xce, 0x1a, 0x9a, 0xa6, 0xa3, 0x4b, 0xd2, 0xea, 0xc5, 0xc2, 0x12, 0xf9, 0x1c, + 0xe1, 0xcc, 0xd1, 0xd4, 0x16, 0x1e, 0xa1, 0x86, 0x10, 0x0d, 0xff, 0x3d, 0x42, 0x8d, 0xa9, 0x6e, 0x8c, 0x51, 0x9a, + 0xc1, 0xdf, 0x78, 0x44, 0x08, 0x69, 0x76, 0xca, 0x8a, 0xfe, 0xb0, 0xa4, 0x28, 0x1d, 0x7b, 0xf5, 0x68, 0xdf, 0x6c, + 0x0e, 0xd9, 0x88, 0x79, 0x9f, 0x0d, 0x56, 0xab, 0xe8, 0xa2, 0x77, 0x19, 0xa1, 0x46, 0xec, 0xd1, 0xee, 0xc8, 0xe3, + 0x1d, 0x42, 0x58, 0x0c, 0xd6, 0xee, 0x06, 0xea, 0x86, 0xd5, 0x6e, 0x9b, 0x96, 0xd5, 0xfe, 0x0f, 0xc8, 0x02, 0x5b, + 0x97, 0x72, 0x8f, 0xe5, 0x6f, 0xe7, 0x30, 0x55, 0x8f, 0xdb, 0x92, 0xb4, 0x70, 0x41, 0xbc, 0xba, 0x9b, 0x12, 0x5d, + 0xe1, 0x7f, 0x46, 0xaa, 0xe2, 0xb8, 0x9f, 0xe3, 0xe9, 0x80, 0x08, 0x6a, 0xe4, 0x97, 0xae, 0x57, 0xa6, 0xb3, 0x9c, + 0xdc, 0xb0, 0x8d, 0xfb, 0xdf, 0x1c, 0xee, 0x64, 0x1e, 0xeb, 0x24, 0x5b, 0x14, 0x05, 0x13, 0xfa, 0x95, 0x1c, 0x39, + 0xc6, 0x8e, 0xe5, 0x20, 0x5b, 0xc1, 0xc5, 0x2e, 0x06, 0xae, 0xae, 0xe3, 0x77, 0xca, 0x68, 0x2b, 0x7b, 0x41, 0x46, + 0x96, 0xe1, 0x32, 0xd7, 0xbd, 0xdd, 0x85, 0x13, 0xa5, 0x63, 0x84, 0x47, 0xee, 0x1e, 0x38, 0x4e, 0x92, 0x64, 0x91, + 0x64, 0x90, 0x0d, 0x1d, 0x28, 0xb4, 0x36, 0xfb, 0x2a, 0x56, 0xe4, 0xb1, 0x4e, 0x04, 0xbb, 0x35, 0xdd, 0xc6, 0xa8, + 0x3a, 0xc4, 0xfd, 0x7e, 0xbb, 0xa0, 0x5d, 0x43, 0x80, 0x54, 0x22, 0xe4, 0x88, 0x01, 0x84, 0xe0, 0xee, 0xdf, 0x25, + 0x4d, 0xa9, 0x0a, 0x6f, 0xb6, 0xaa, 0x01, 0xf6, 0x43, 0x95, 0xf7, 0x02, 0xf4, 0xc4, 0x86, 0x3d, 0x2b, 0x0b, 0x5b, + 0xe5, 0x39, 0x42, 0x7c, 0x1c, 0x2f, 0x12, 0xb8, 0x11, 0x34, 0x98, 0x24, 0x04, 0x5a, 0xad, 0x16, 0x21, 0x6e, 0x4d, + 0x2b, 0xc5, 0xf4, 0x98, 0x4c, 0xfb, 0x45, 0xa3, 0x61, 0x94, 0xd7, 0x23, 0x8b, 0x17, 0x0b, 0x84, 0xc7, 0xe5, 0x5e, + 0xf3, 0xe5, 0xe6, 0xa4, 0xde, 0x55, 0x3c, 0xae, 0x2b, 0x81, 0x1b, 0x42, 0x20, 0xa3, 0x5f, 0xd4, 0xd0, 0x3a, 0x9e, + 0x90, 0xa3, 0xb8, 0x9f, 0xf4, 0xfe, 0xe7, 0x00, 0xf5, 0xe2, 0xe4, 0x10, 0x1d, 0x59, 0x5a, 0x32, 0x46, 0xdd, 0xcc, + 0xf6, 0xb1, 0x34, 0xb7, 0x9f, 0x6d, 0x6c, 0x14, 0x90, 0xa9, 0xc4, 0x82, 0xce, 0x58, 0x3a, 0x81, 0x5d, 0xef, 0x91, + 0x67, 0x8e, 0x01, 0x99, 0xd2, 0x89, 0xa3, 0x2d, 0x49, 0xd4, 0x93, 0xb4, 0xfc, 0xea, 0x45, 0x3d, 0x5a, 0x7d, 0xfd, + 0xcf, 0xa8, 0x97, 0xd1, 0xf4, 0x31, 0x5f, 0x3b, 0x25, 0x79, 0xad, 0x8f, 0x33, 0xdf, 0xc7, 0xda, 0x2e, 0x4e, 0x00, + 0xbc, 0x11, 0xda, 0xd6, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0xa4, 0x12, 0x4d, 0x27, 0x00, 0xd5, 0x60, 0x11, + 0x54, 0x68, 0x1b, 0x10, 0x4c, 0x19, 0xb0, 0xc5, 0x23, 0x2d, 0x40, 0x73, 0x71, 0xd9, 0x42, 0xcb, 0x5a, 0x61, 0xc7, + 0x59, 0xd5, 0xef, 0xe2, 0x4b, 0xe2, 0x3d, 0x06, 0xaa, 0x7c, 0xb1, 0xe8, 0x8e, 0x1b, 0x0d, 0xa4, 0x3c, 0x7e, 0x8d, + 0xfa, 0xe3, 0x01, 0xbe, 0x05, 0x14, 0xc2, 0x35, 0x8c, 0xc2, 0xb5, 0x39, 0x76, 0xdc, 0x1c, 0x1b, 0x0d, 0xb9, 0x46, + 0xdd, 0xa0, 0xf2, 0xc2, 0x55, 0x5e, 0xaf, 0x2d, 0x64, 0x36, 0x31, 0xee, 0x1c, 0x99, 0x14, 0x30, 0x04, 0x23, 0x84, + 0xbc, 0x92, 0x68, 0x67, 0xb3, 0xd0, 0x28, 0x54, 0x37, 0xbb, 0x17, 0x28, 0xaa, 0x3d, 0x3d, 0x62, 0x80, 0x05, 0x54, + 0x2d, 0xd5, 0xc8, 0x53, 0x8d, 0x47, 0x8d, 0xb6, 0x41, 0xf7, 0x66, 0xbb, 0x5b, 0x6f, 0xec, 0x7e, 0xd5, 0x18, 0x1e, + 0x35, 0xc8, 0xb4, 0xda, 0xe1, 0x6b, 0xd9, 0x68, 0xac, 0xeb, 0xf7, 0xa5, 0x7e, 0x13, 0xd7, 0xee, 0x2f, 0x9e, 0x6e, + 0x99, 0x78, 0xf8, 0xd3, 0xb7, 0x3a, 0x6f, 0x45, 0xc2, 0x85, 0x60, 0x05, 0x9c, 0xb0, 0x44, 0x63, 0xb1, 0x5e, 0x97, + 0xa7, 0xfe, 0xef, 0xda, 0xda, 0x8c, 0x11, 0x0e, 0x74, 0xc8, 0x48, 0x6d, 0x58, 0xe2, 0x02, 0x53, 0x43, 0x45, 0x08, + 0x21, 0x1f, 0xb4, 0x37, 0x8f, 0xd1, 0x86, 0x24, 0x65, 0x24, 0x38, 0xbb, 0x63, 0x45, 0x58, 0x72, 0x7d, 0xef, 0xb1, + 0xfc, 0xae, 0x48, 0xd7, 0x17, 0x83, 0xd4, 0x14, 0xcb, 0x1d, 0x21, 0xcb, 0xc9, 0x17, 0x90, 0x73, 0xca, 0x0b, 0x96, + 0xc4, 0x10, 0xc4, 0x27, 0xbc, 0x60, 0x86, 0x71, 0xbf, 0xe7, 0xe5, 0xc6, 0xac, 0xce, 0x69, 0x66, 0xa1, 0xf6, 0x07, + 0xa0, 0x99, 0x83, 0x72, 0x48, 0x92, 0xad, 0x62, 0xd7, 0xf7, 0x1e, 0xbe, 0xde, 0x25, 0x43, 0xaf, 0x56, 0x4e, 0x7a, + 0xce, 0x80, 0xf5, 0xc1, 0x79, 0x35, 0xd4, 0xcc, 0xfd, 0x48, 0xe3, 0xcc, 0x30, 0x51, 0x79, 0xcc, 0x01, 0x99, 0xae, + 0xef, 0x3d, 0x7c, 0x17, 0x73, 0xa3, 0x9b, 0x42, 0x38, 0x9c, 0x77, 0x5c, 0x90, 0x98, 0x12, 0x86, 0xec, 0xe4, 0x4b, + 0x3a, 0x56, 0x04, 0xa7, 0x7b, 0x4a, 0x4d, 0x26, 0x88, 0x1d, 0x7d, 0x31, 0x20, 0x99, 0x03, 0x01, 0xc9, 0x10, 0xce, + 0x6a, 0x72, 0x1d, 0x31, 0x6b, 0x60, 0x3a, 0xbb, 0x82, 0xc5, 0x48, 0x2c, 0x7b, 0x88, 0x70, 0x66, 0xba, 0xd5, 0x6b, + 0x7b, 0x9c, 0x28, 0xba, 0x69, 0xe8, 0x56, 0xc9, 0xb3, 0xef, 0x41, 0xf0, 0xf2, 0x1f, 0xaf, 0x5c, 0xdb, 0x65, 0xc2, + 0x13, 0x6f, 0x91, 0x76, 0x7d, 0xef, 0xe1, 0xaf, 0xce, 0x28, 0x6d, 0x4e, 0x3d, 0xf9, 0xdf, 0x92, 0x51, 0x1f, 0xfe, + 0x9a, 0x54, 0xb9, 0xa6, 0xf0, 0xf5, 0xbd, 0x87, 0xbf, 0xef, 0x2a, 0x06, 0xe9, 0xeb, 0x45, 0xa5, 0x24, 0x30, 0xe3, + 0x5b, 0xb2, 0x3c, 0x5d, 0xba, 0xb3, 0x22, 0x15, 0x6b, 0x6c, 0x4e, 0xa8, 0x54, 0xad, 0x4b, 0xdd, 0xca, 0x13, 0x2c, + 0x89, 0xb9, 0x4a, 0xaa, 0x2f, 0x9b, 0x43, 0x63, 0x2e, 0xc5, 0x55, 0x26, 0xe7, 0xec, 0x1b, 0xf7, 0x4b, 0x4f, 0x35, + 0x4a, 0xf8, 0x0c, 0x0c, 0x71, 0xcc, 0xd8, 0x05, 0xde, 0x6f, 0xa1, 0xee, 0xc6, 0x79, 0x26, 0x0d, 0xa2, 0x16, 0xf5, + 0xc3, 0x06, 0x53, 0xd2, 0xc2, 0x19, 0x69, 0xe1, 0x9c, 0xa8, 0x7e, 0xcb, 0x9e, 0x18, 0xdd, 0xbc, 0x6c, 0xda, 0x9e, + 0x3b, 0xb0, 0xdd, 0x73, 0xbb, 0x6f, 0xed, 0xa1, 0x3c, 0xed, 0xe6, 0x46, 0x7f, 0x69, 0x0e, 0xfa, 0xa9, 0x41, 0x8d, + 0x27, 0x2c, 0x2e, 0x70, 0x61, 0x5a, 0xbe, 0xe2, 0xc3, 0x1c, 0xec, 0x54, 0x60, 0x66, 0x58, 0xa3, 0xb4, 0x2c, 0xdb, + 0x76, 0x65, 0xf3, 0xc4, 0xac, 0x55, 0x81, 0xf3, 0x04, 0x48, 0x39, 0xce, 0x9d, 0x5d, 0x8f, 0xda, 0xae, 0x72, 0x76, + 0x70, 0x10, 0xbb, 0x4a, 0x34, 0x2e, 0x7c, 0x7e, 0x75, 0x03, 0xf8, 0xde, 0x52, 0x8d, 0x29, 0x32, 0x13, 0x68, 0x34, + 0xb2, 0xc1, 0x9a, 0xee, 0x13, 0x12, 0xe7, 0x75, 0x28, 0xfa, 0xd1, 0x1b, 0x66, 0x70, 0x03, 0x00, 0x8d, 0x46, 0x79, + 0xdd, 0xbb, 0x01, 0xb1, 0xa7, 0x1a, 0xcb, 0xf5, 0x97, 0xb8, 0xb4, 0x26, 0x6a, 0x6d, 0xd9, 0x61, 0xf9, 0x51, 0x20, + 0x11, 0xe2, 0xae, 0xf0, 0xf3, 0x09, 0xb6, 0x86, 0x80, 0x72, 0x2f, 0x9c, 0x0d, 0x04, 0x36, 0x56, 0x5b, 0xae, 0x90, + 0x27, 0x6d, 0x1d, 0x94, 0xfa, 0x42, 0x70, 0xc1, 0x05, 0x85, 0x1a, 0x6b, 0x87, 0xe5, 0x4f, 0xd8, 0xb6, 0x39, 0x27, + 0x56, 0xc8, 0x69, 0xcb, 0xcc, 0x30, 0x0c, 0xc0, 0x3a, 0x25, 0x60, 0x9e, 0x93, 0x97, 0xdf, 0x46, 0xfd, 0x87, 0x01, + 0xea, 0x3f, 0x22, 0x2c, 0xd8, 0x06, 0x56, 0x57, 0x92, 0x48, 0xa7, 0xa0, 0x50, 0x3e, 0xeb, 0xf1, 0x9c, 0x80, 0x36, + 0xae, 0x0e, 0xd5, 0xda, 0x15, 0xe5, 0x37, 0x28, 0x4b, 0xb8, 0x53, 0x8c, 0x3e, 0x13, 0xfb, 0xfb, 0xe4, 0xb8, 0xba, + 0xa0, 0x83, 0xae, 0x77, 0x29, 0x07, 0x43, 0x52, 0xf8, 0xf0, 0xf7, 0xef, 0xdf, 0xad, 0x3e, 0x9e, 0x6f, 0xef, 0xe0, + 0xc0, 0xac, 0x14, 0x66, 0x1d, 0x6c, 0xe0, 0xba, 0x91, 0x29, 0xf4, 0x5f, 0xde, 0x89, 0xd7, 0xa9, 0xd0, 0xc6, 0x66, + 0xf4, 0xc7, 0x21, 0x8c, 0xb6, 0xdd, 0x36, 0x25, 0x58, 0xd0, 0x2c, 0xd0, 0x25, 0x6b, 0xdc, 0x4a, 0x8b, 0x6f, 0x90, + 0x91, 0x87, 0xa6, 0x00, 0x13, 0xa3, 0xdd, 0xd9, 0x8f, 0xd6, 0x0e, 0x4f, 0xec, 0xd0, 0xd0, 0xd2, 0x10, 0x42, 0x8b, + 0xf7, 0x80, 0x39, 0xf6, 0x88, 0x00, 0x10, 0xbd, 0x34, 0x90, 0xaa, 0x40, 0x16, 0x45, 0x95, 0x22, 0xff, 0xf9, 0x3e, + 0x21, 0x2f, 0x2b, 0x45, 0xe6, 0xdb, 0xca, 0x98, 0x0b, 0x10, 0x03, 0xa5, 0x70, 0x91, 0x50, 0x26, 0xd8, 0xcb, 0xd0, + 0x0f, 0xda, 0x97, 0x37, 0xd2, 0x66, 0x52, 0x71, 0xe3, 0xc1, 0x4d, 0xa9, 0x51, 0xf1, 0xd9, 0x7c, 0x0f, 0x89, 0x8d, + 0xdc, 0x7b, 0x90, 0xcb, 0xa8, 0x19, 0x24, 0x7c, 0xbf, 0x33, 0xa5, 0x7d, 0xbb, 0xeb, 0xcf, 0x9b, 0x16, 0x31, 0x1b, + 0xeb, 0x92, 0x70, 0xa1, 0x58, 0xa1, 0x1f, 0xb1, 0xb1, 0x2c, 0xe0, 0xfe, 0xa3, 0x04, 0x0b, 0x5a, 0xdf, 0x0b, 0x74, + 0x80, 0x66, 0x82, 0xc1, 0xa5, 0xc3, 0xc6, 0x0c, 0xcd, 0xaf, 0xcf, 0xe6, 0x0e, 0xfc, 0x7a, 0xb3, 0xd6, 0xcb, 0x83, + 0x83, 0x2f, 0xac, 0x02, 0x94, 0x1b, 0xa6, 0x19, 0x46, 0x40, 0xbc, 0x2c, 0x97, 0xe3, 0x6e, 0x86, 0xef, 0xc5, 0x95, + 0xca, 0xc0, 0x13, 0x8e, 0x90, 0x08, 0x3d, 0x27, 0x7a, 0x3d, 0xd9, 0xa4, 0xf7, 0x4e, 0x9b, 0x21, 0x42, 0xb1, 0x06, + 0xc8, 0x3d, 0xc8, 0xe5, 0x56, 0xc9, 0xa4, 0x2a, 0x5b, 0xdb, 0x72, 0x10, 0x8f, 0x01, 0x5c, 0xb1, 0x11, 0x52, 0x02, + 0x34, 0xdc, 0x2d, 0xb4, 0x3c, 0x97, 0xc0, 0xfe, 0x63, 0x95, 0x80, 0x48, 0x8b, 0x6a, 0x1b, 0x17, 0x21, 0x6c, 0x4d, + 0x7d, 0x02, 0xe3, 0x84, 0x87, 0xcf, 0x77, 0x69, 0xa8, 0x3d, 0x6a, 0x33, 0x73, 0x06, 0x41, 0x09, 0x89, 0xca, 0x0a, + 0xc9, 0x97, 0x58, 0x38, 0x6e, 0xce, 0xdf, 0xc3, 0x01, 0x29, 0x56, 0x34, 0xb6, 0x77, 0x5b, 0x70, 0x7c, 0x14, 0xc9, + 0x22, 0xae, 0x75, 0xdd, 0x2d, 0x4c, 0x35, 0xec, 0x40, 0x47, 0x43, 0x38, 0x15, 0xe6, 0x9e, 0xf0, 0x71, 0x45, 0x52, + 0x7f, 0xb6, 0x26, 0xda, 0xda, 0x13, 0xc3, 0xca, 0x34, 0x25, 0x98, 0xff, 0xcf, 0xd6, 0xea, 0xba, 0x2c, 0x84, 0x99, + 0x19, 0xc6, 0x8d, 0x5d, 0x05, 0xb6, 0x06, 0x1c, 0x5b, 0xfe, 0x2d, 0x83, 0x45, 0xf5, 0x4a, 0x71, 0xd3, 0x69, 0xc0, + 0x04, 0xbc, 0x05, 0xeb, 0x99, 0xcd, 0xad, 0xff, 0xdc, 0x1c, 0x8c, 0x02, 0xab, 0x1a, 0x81, 0x97, 0x86, 0xc0, 0x23, + 0x60, 0xdc, 0xbc, 0x69, 0x79, 0xcf, 0x19, 0xd1, 0x08, 0x7f, 0xe2, 0x39, 0x3c, 0xb3, 0x2c, 0xf7, 0xd6, 0xc7, 0xc6, + 0x8a, 0xa4, 0x82, 0x80, 0x6d, 0x11, 0x76, 0x44, 0x5e, 0x22, 0xac, 0x1a, 0x8d, 0xae, 0xba, 0x60, 0x95, 0x56, 0xa5, + 0x1a, 0xa6, 0x80, 0x5b, 0x62, 0xc0, 0xfb, 0xda, 0x89, 0x0a, 0x86, 0x04, 0xde, 0xfa, 0x5b, 0x81, 0xfa, 0xfe, 0xe1, + 0xdb, 0x38, 0xa4, 0x6f, 0x61, 0xd9, 0xf2, 0x22, 0x16, 0xa6, 0x14, 0x57, 0x77, 0x38, 0x6f, 0xbe, 0x6f, 0x36, 0x02, + 0xe3, 0xde, 0x6f, 0x63, 0xb0, 0x71, 0x43, 0x5d, 0x6d, 0x49, 0x43, 0xb9, 0x09, 0xbb, 0xa8, 0xb2, 0x77, 0x0c, 0x3b, + 0xeb, 0xea, 0x4a, 0xda, 0xd5, 0x44, 0xad, 0xd7, 0x8a, 0x55, 0x46, 0x03, 0x1b, 0x86, 0x9d, 0xe6, 0x98, 0xd9, 0x56, + 0xe0, 0x3f, 0x9e, 0x13, 0x8d, 0x03, 0x64, 0x7d, 0xf3, 0xad, 0xeb, 0x94, 0x6a, 0x98, 0xb0, 0xbd, 0xdd, 0xf9, 0xf8, + 0x98, 0xef, 0x3a, 0x1f, 0xb1, 0x74, 0x5b, 0xdf, 0x9c, 0x8d, 0xed, 0x7f, 0xe3, 0x6c, 0x74, 0x6a, 0x7b, 0x7f, 0x3c, + 0x02, 0x77, 0x52, 0x3b, 0x1e, 0xeb, 0x6b, 0x4a, 0x24, 0x16, 0x6e, 0x39, 0x2e, 0x3b, 0xab, 0x95, 0xe8, 0xb7, 0x40, + 0xed, 0x14, 0x45, 0xf0, 0xb3, 0x6d, 0x7f, 0x06, 0x24, 0xd9, 0xea, 0x90, 0x63, 0x51, 0x8a, 0x32, 0x28, 0x01, 0x03, + 0xea, 0xd8, 0xd8, 0x7a, 0x19, 0xc4, 0x76, 0x38, 0xe4, 0xb0, 0x9c, 0x88, 0xf2, 0xea, 0x0a, 0x46, 0x6c, 0x8e, 0x0d, + 0x27, 0x60, 0xc6, 0x3b, 0xad, 0x0a, 0xbd, 0xf8, 0xf9, 0xaf, 0x99, 0xd3, 0xda, 0x11, 0x63, 0x39, 0x89, 0x9a, 0x15, + 0x83, 0x1b, 0x81, 0x63, 0x18, 0xf7, 0x8d, 0x84, 0x5a, 0x9d, 0xea, 0xa8, 0x76, 0x24, 0xe1, 0x16, 0xa8, 0xdd, 0xf6, + 0xcd, 0xb9, 0xb4, 0x5a, 0xed, 0x3c, 0x58, 0x70, 0x11, 0xe0, 0xf6, 0x73, 0xa2, 0x6b, 0x24, 0x85, 0x12, 0x27, 0x41, + 0xe1, 0xdc, 0xa0, 0xaa, 0x26, 0xb2, 0xdf, 0x1a, 0x00, 0x4f, 0xda, 0xcd, 0x2e, 0x64, 0x25, 0x24, 0x67, 0x8d, 0x06, + 0xca, 0xcb, 0x8e, 0x69, 0x5f, 0x34, 0xb2, 0x01, 0x66, 0x38, 0xb3, 0x02, 0x0b, 0x9c, 0x5e, 0x71, 0x5e, 0x75, 0xdd, + 0xcf, 0x06, 0x08, 0x17, 0xab, 0x55, 0x6c, 0x87, 0x96, 0xa3, 0xd5, 0x2a, 0x0f, 0x87, 0x66, 0xf2, 0xa1, 0xe2, 0xcb, + 0x9e, 0x26, 0x2f, 0xcd, 0x79, 0xf8, 0x12, 0x06, 0xd9, 0x20, 0x71, 0xee, 0x54, 0x82, 0x39, 0x68, 0xae, 0x1a, 0xb2, + 0x9f, 0x35, 0xda, 0x83, 0x80, 0x86, 0xf5, 0xb3, 0x01, 0xc9, 0xd7, 0x60, 0x39, 0xab, 0xdc, 0x81, 0xf9, 0x37, 0x1c, + 0x6c, 0x7f, 0x9b, 0x73, 0xc6, 0x36, 0x18, 0xae, 0xc9, 0xa6, 0xca, 0xa0, 0xc4, 0x2b, 0xb7, 0xb8, 0xbe, 0x5c, 0xcd, + 0xc0, 0xa2, 0x2c, 0x84, 0xdd, 0x35, 0x73, 0x0f, 0x84, 0xff, 0x12, 0xdb, 0x25, 0x2d, 0x8d, 0xb8, 0x37, 0x10, 0xdf, + 0xdb, 0x6e, 0x27, 0x49, 0x42, 0x8b, 0x89, 0xb9, 0x12, 0xf1, 0x37, 0xbc, 0x66, 0x0f, 0x1c, 0xbb, 0x71, 0x06, 0x3d, + 0xf7, 0xcb, 0xce, 0x06, 0xc4, 0x8e, 0xdf, 0x33, 0x3b, 0xde, 0x71, 0xa5, 0xa0, 0xbb, 0x75, 0x11, 0x76, 0x30, 0xf4, + 0x7f, 0x79, 0x30, 0x27, 0x6e, 0x30, 0x16, 0x4d, 0x36, 0xe0, 0xf6, 0x0d, 0x78, 0x14, 0x74, 0x03, 0x6e, 0xdf, 0x86, + 0xaf, 0x87, 0x56, 0xf6, 0xcd, 0x01, 0x06, 0x64, 0xc2, 0x8e, 0xb4, 0x4a, 0x08, 0x86, 0x79, 0xba, 0xc9, 0x91, 0x59, + 0xb2, 0x0a, 0x87, 0xab, 0x26, 0xb1, 0xd8, 0xd8, 0x0b, 0x15, 0x93, 0x1a, 0x08, 0xc6, 0x22, 0x7d, 0x89, 0x42, 0xa5, + 0x41, 0xdd, 0x38, 0x06, 0xb0, 0xca, 0x69, 0xeb, 0x5f, 0x1e, 0x1c, 0x80, 0xd0, 0x00, 0xac, 0x5d, 0x92, 0xd1, 0xb9, + 0x5e, 0x14, 0xc0, 0x5f, 0x29, 0xff, 0x1b, 0x92, 0xc1, 0xed, 0xc4, 0xa4, 0xc1, 0x0f, 0x48, 0x98, 0x53, 0xa5, 0xf8, + 0x17, 0x9b, 0xe6, 0x7e, 0xe3, 0x82, 0x78, 0x8c, 0x56, 0x96, 0x53, 0x94, 0xa8, 0x2b, 0x1d, 0xba, 0xd6, 0x21, 0xf7, + 0xf4, 0x0b, 0x13, 0xfa, 0x25, 0x57, 0x9a, 0x09, 0x00, 0x40, 0x85, 0x78, 0x30, 0x25, 0x85, 0x60, 0xeb, 0xd6, 0x6a, + 0xd1, 0xd1, 0xe8, 0xbb, 0x55, 0x74, 0x9d, 0x2d, 0x9a, 0x52, 0x31, 0xca, 0x6d, 0x27, 0xa1, 0xcd, 0xa4, 0xb7, 0x13, + 0x2d, 0x4b, 0x86, 0x16, 0x3b, 0x15, 0xfb, 0x61, 0x68, 0x7d, 0x2c, 0x88, 0x3f, 0x17, 0xfc, 0x59, 0xfa, 0x5d, 0x3e, + 0x06, 0xae, 0xd4, 0xbf, 0xb1, 0x0a, 0xe1, 0x4c, 0xb0, 0x0e, 0xc8, 0x6b, 0x52, 0x1f, 0xa7, 0x47, 0x9d, 0x7c, 0x4b, + 0xb9, 0x50, 0x1a, 0x85, 0x6d, 0x9c, 0x14, 0x06, 0x53, 0xce, 0xbe, 0x2d, 0x71, 0xfd, 0xea, 0x8f, 0x11, 0x7f, 0x74, + 0x88, 0x7f, 0x97, 0x4a, 0xa3, 0x65, 0x89, 0x60, 0xc8, 0xef, 0x48, 0xad, 0xe0, 0x2a, 0x36, 0xe7, 0xfa, 0xb9, 0x9e, + 0xe5, 0x1b, 0x9e, 0x38, 0x5d, 0xad, 0x4a, 0xa9, 0x40, 0xc5, 0x37, 0x0c, 0x3f, 0x61, 0x70, 0x6f, 0xfc, 0x8c, 0x07, + 0x55, 0xb6, 0xef, 0x8b, 0x9f, 0x05, 0xf7, 0xc5, 0xcf, 0x78, 0xba, 0x5d, 0x34, 0xb8, 0x27, 0xee, 0x24, 0xe7, 0x49, + 0x2b, 0xf2, 0x7c, 0xd4, 0x94, 0x56, 0xfe, 0x95, 0x76, 0x6b, 0xe0, 0xca, 0x26, 0x0e, 0x8c, 0xf3, 0xea, 0x22, 0x14, + 0x73, 0xe6, 0x8c, 0x96, 0xc3, 0xff, 0xd6, 0x3a, 0xb9, 0x93, 0x47, 0x5a, 0x29, 0xe4, 0x0d, 0x2d, 0xf4, 0x3d, 0xd8, + 0x70, 0xc5, 0x96, 0x0f, 0x20, 0x25, 0xa0, 0x6c, 0xfb, 0xf7, 0xba, 0x08, 0xc4, 0x71, 0x65, 0x9d, 0x8f, 0xc2, 0xf6, + 0x49, 0x51, 0x72, 0x75, 0x75, 0x21, 0xe4, 0xd6, 0x68, 0x09, 0x10, 0xa6, 0xde, 0x35, 0x8f, 0x39, 0x9a, 0xcc, 0xd2, + 0xe5, 0xba, 0x54, 0x1d, 0x14, 0x96, 0xab, 0xe3, 0x08, 0x17, 0x6b, 0x73, 0x83, 0xfe, 0x8a, 0xe3, 0xbf, 0xb9, 0xa3, + 0x91, 0x9f, 0x4a, 0x0a, 0xf4, 0x68, 0xb7, 0xaf, 0xcd, 0x0e, 0x12, 0x69, 0xe7, 0x50, 0x5a, 0x0a, 0x00, 0x56, 0x1b, + 0x7c, 0x5d, 0x7b, 0x9c, 0x7a, 0x22, 0xdd, 0x6c, 0xbe, 0x69, 0x08, 0x8b, 0x59, 0x69, 0xc1, 0x63, 0xba, 0xd9, 0x61, + 0x39, 0xea, 0x65, 0x71, 0x5d, 0xee, 0xb1, 0x5a, 0xbf, 0xe8, 0x1b, 0xa0, 0xac, 0x0c, 0xd1, 0x56, 0xab, 0xb8, 0x0e, + 0x6f, 0x22, 0x82, 0x6b, 0x10, 0x84, 0x45, 0x60, 0xc0, 0x51, 0x63, 0xbc, 0x6d, 0x9d, 0x18, 0x6d, 0xda, 0x2f, 0x79, + 0xd6, 0xbd, 0x36, 0x8e, 0x50, 0xd1, 0x60, 0xab, 0x87, 0x9a, 0x07, 0x6c, 0x67, 0x57, 0x76, 0x14, 0x40, 0x68, 0x4a, + 0xbd, 0x71, 0x6e, 0x65, 0x45, 0xbb, 0x03, 0xbe, 0xe8, 0x3b, 0xe6, 0xb9, 0x0e, 0x74, 0xdb, 0xf9, 0x81, 0x6d, 0xd3, + 0x13, 0xf9, 0x2d, 0xdb, 0xa6, 0x1a, 0x27, 0xbc, 0xdf, 0x42, 0xdf, 0x37, 0x84, 0xb5, 0x7d, 0xed, 0x2e, 0xf2, 0xbf, + 0xd0, 0x5d, 0x1b, 0xd0, 0xd3, 0x82, 0xd9, 0xd3, 0x98, 0x0f, 0x7a, 0xbd, 0xfe, 0x54, 0xfa, 0x2f, 0x18, 0x5b, 0xa1, + 0x4f, 0x76, 0x17, 0x38, 0xb1, 0xd2, 0x38, 0x04, 0xc7, 0xaf, 0x38, 0x99, 0xe4, 0x72, 0x48, 0xf3, 0x77, 0xd0, 0x63, + 0x95, 0xfb, 0xfc, 0x6e, 0x54, 0x50, 0xcd, 0x1c, 0xad, 0xa9, 0x46, 0xf1, 0x8a, 0x07, 0xc3, 0x78, 0xc5, 0x2d, 0xe5, + 0xae, 0x5a, 0xc0, 0xcb, 0x97, 0x65, 0x13, 0xe9, 0xa7, 0x75, 0x29, 0x83, 0xa9, 0xdd, 0xbd, 0x6c, 0x92, 0x34, 0x56, + 0x92, 0x34, 0xa6, 0xe2, 0xcd, 0xa6, 0xe2, 0xf8, 0xef, 0x6f, 0x0c, 0x76, 0x9b, 0xcc, 0xfd, 0x1d, 0x90, 0xb9, 0xbf, + 0x79, 0xfa, 0xdd, 0x5a, 0x01, 0xc5, 0x3b, 0x4e, 0x8e, 0x8d, 0x65, 0x8c, 0x1d, 0xf5, 0x5b, 0x0d, 0x06, 0x0d, 0x9a, + 0x5c, 0x06, 0xde, 0x0e, 0xd5, 0xe9, 0xe5, 0xed, 0x8f, 0xe2, 0x6c, 0xa1, 0xb4, 0x9c, 0xb9, 0x46, 0x95, 0xf3, 0x71, + 0x32, 0x99, 0xa0, 0xc0, 0x36, 0x77, 0xf8, 0x69, 0xdd, 0x8d, 0x6c, 0xf9, 0x99, 0x8b, 0x51, 0xaa, 0xb0, 0x3b, 0x5b, + 0x54, 0x2a, 0xd7, 0xc4, 0x9b, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0x17, 0x5c, 0x4d, 0x59, 0x11, 0x17, 0x68, 0xf9, 0xad, + 0xce, 0x0a, 0xb8, 0xcd, 0xb1, 0x9d, 0xe1, 0x51, 0x69, 0x39, 0xa0, 0x13, 0x68, 0x0d, 0x74, 0x46, 0x33, 0xa6, 0xa7, + 0x72, 0x04, 0x86, 0x2f, 0xc9, 0xa8, 0x74, 0xa7, 0x3a, 0x38, 0xd8, 0x8f, 0x23, 0xa3, 0xbf, 0x00, 0x1f, 0xf4, 0x30, + 0x07, 0xf5, 0x96, 0xe0, 0x18, 0x54, 0x75, 0xcd, 0xd0, 0x92, 0x6d, 0xfa, 0xd0, 0xe8, 0xe4, 0x33, 0xbb, 0xc3, 0x1c, + 0xad, 0xd7, 0xa9, 0x1d, 0x75, 0x34, 0xe6, 0x2c, 0x1f, 0x45, 0xf8, 0x33, 0xbb, 0x4b, 0x4b, 0xb7, 0x75, 0xe3, 0x65, + 0x6d, 0x16, 0x31, 0x92, 0x37, 0x22, 0xc2, 0x55, 0x27, 0xe9, 0x72, 0x8d, 0x65, 0xc1, 0x27, 0x80, 0xa3, 0xbf, 0xb0, + 0xbb, 0xd4, 0xb5, 0x17, 0xb8, 0x0a, 0xa2, 0xa5, 0x07, 0x7d, 0x12, 0x24, 0x87, 0xcb, 0xe0, 0x04, 0x8e, 0xbe, 0xa9, + 0x3b, 0x20, 0xb5, 0x72, 0x95, 0x08, 0x89, 0xd0, 0xfa, 0xdf, 0x9d, 0x0a, 0x5e, 0x84, 0xe7, 0x9c, 0xae, 0x59, 0xdc, + 0x6e, 0x54, 0x62, 0x50, 0xa1, 0xb2, 0x20, 0xf9, 0x18, 0x73, 0xbf, 0xfb, 0x9c, 0xf7, 0x43, 0xa0, 0x33, 0x5b, 0x50, + 0xd7, 0x68, 0x3a, 0x32, 0xbf, 0x50, 0x75, 0x07, 0x35, 0xd3, 0x55, 0xc5, 0xbd, 0x8f, 0x31, 0x00, 0x1e, 0xac, 0x65, + 0xa8, 0x71, 0x08, 0x5d, 0x7b, 0x33, 0xd5, 0x31, 0x25, 0xf1, 0xd2, 0xcf, 0x21, 0xe5, 0x21, 0x18, 0xf5, 0x1a, 0xd0, + 0xd0, 0x21, 0x98, 0xb5, 0x3c, 0xe4, 0xe3, 0x58, 0x6c, 0x9d, 0xa1, 0xd2, 0x9c, 0xa1, 0x49, 0x00, 0xf2, 0x6f, 0x9c, + 0x99, 0xcc, 0x40, 0xc3, 0xf0, 0x96, 0xe6, 0x00, 0x74, 0xab, 0xeb, 0x70, 0x28, 0x5c, 0xd1, 0xd2, 0x79, 0xcf, 0x2e, + 0xba, 0xac, 0x0d, 0x2b, 0x36, 0xed, 0xa0, 0x75, 0x0a, 0x53, 0x62, 0xb6, 0xc0, 0xda, 0xeb, 0x7d, 0xb8, 0xb7, 0xab, + 0x8d, 0x8b, 0xc4, 0x4f, 0x8b, 0x78, 0x98, 0xc4, 0x14, 0x2d, 0x79, 0x4c, 0xb1, 0x04, 0x3b, 0xc8, 0x62, 0x5d, 0x8e, + 0x9f, 0x85, 0xcb, 0x51, 0xb3, 0x92, 0xde, 0xed, 0x60, 0x08, 0x5c, 0xbe, 0x06, 0xdb, 0x50, 0xcc, 0x3d, 0x61, 0xe1, + 0xb1, 0xf1, 0xf4, 0x0b, 0xd6, 0x6d, 0x6e, 0x17, 0xc4, 0xaf, 0xc0, 0x98, 0xc6, 0xcb, 0x60, 0x16, 0xa1, 0x53, 0xb9, + 0x73, 0x38, 0x74, 0xd7, 0x84, 0x95, 0xf1, 0x6a, 0xac, 0xc8, 0xc6, 0xd1, 0xf3, 0x7d, 0x1b, 0xcf, 0x7f, 0x16, 0xac, + 0xb8, 0xbb, 0x62, 0x60, 0x63, 0x2d, 0xc1, 0xdd, 0xb8, 0x5a, 0x86, 0xca, 0x40, 0xbe, 0x27, 0x0d, 0xeb, 0xb2, 0xc6, + 0xdf, 0x8d, 0x8a, 0xb1, 0x36, 0xf7, 0x94, 0x81, 0xb6, 0xc6, 0x6e, 0x17, 0xf6, 0x4d, 0xd7, 0x4d, 0xd6, 0x35, 0x8a, + 0xb8, 0x0a, 0xd2, 0xee, 0x6e, 0x01, 0x17, 0xa1, 0x3f, 0x6c, 0x5f, 0x0d, 0x36, 0x55, 0x37, 0x90, 0x04, 0xd7, 0x7e, + 0xf2, 0xdb, 0x53, 0xdd, 0x65, 0xad, 0xfb, 0xed, 0xa9, 0xd6, 0x2e, 0x0b, 0x8d, 0x21, 0x11, 0x76, 0xfd, 0x94, 0xfe, + 0xd3, 0x62, 0xbd, 0x46, 0x6b, 0x18, 0xde, 0x7b, 0xde, 0x8d, 0xe3, 0xf7, 0xde, 0x42, 0x31, 0x81, 0x8b, 0xdc, 0xab, + 0x5c, 0x7a, 0x42, 0x5e, 0x8d, 0xe0, 0x3d, 0xdf, 0x1a, 0xc2, 0x7b, 0x1e, 0x38, 0xbd, 0x82, 0xd4, 0x34, 0x11, 0x6c, + 0xe4, 0xe9, 0x27, 0xb2, 0x48, 0x68, 0xf8, 0xb8, 0xd7, 0x9c, 0x70, 0xfd, 0x57, 0x0a, 0xfc, 0x17, 0x1e, 0x2e, 0xb4, + 0x96, 0x02, 0x73, 0x31, 0x5f, 0x68, 0xac, 0xcc, 0xe8, 0x97, 0x63, 0x29, 0x74, 0x73, 0x4c, 0x67, 0x3c, 0xbf, 0x4b, + 0x17, 0xbc, 0x39, 0x93, 0x42, 0xaa, 0x39, 0xcd, 0x18, 0x56, 0x77, 0x4a, 0xb3, 0x59, 0x73, 0xc1, 0xf1, 0x73, 0x96, + 0x7f, 0x61, 0x9a, 0x67, 0x14, 0xbf, 0x95, 0x43, 0xa9, 0x25, 0x7e, 0x7d, 0x7b, 0x37, 0x61, 0x02, 0xff, 0x3e, 0x5c, + 0x08, 0xbd, 0xc0, 0x8a, 0x0a, 0xd5, 0x54, 0xac, 0xe0, 0xe3, 0x6e, 0xb3, 0x39, 0x2f, 0xf8, 0x8c, 0x16, 0x77, 0xcd, + 0x4c, 0xe6, 0xb2, 0x48, 0xff, 0xab, 0x75, 0x4c, 0x1f, 0x8c, 0x4f, 0xba, 0xba, 0xa0, 0x42, 0x71, 0x58, 0x98, 0x94, + 0xe6, 0xf9, 0xde, 0xf1, 0x69, 0x6b, 0xa6, 0xf6, 0xed, 0x85, 0x1f, 0x15, 0x7a, 0xfd, 0x17, 0xfe, 0x20, 0x61, 0x94, + 0xc9, 0x50, 0x0b, 0x37, 0xc8, 0x65, 0xb6, 0x28, 0x94, 0x2c, 0xd2, 0xb9, 0xe4, 0x42, 0xb3, 0xa2, 0x3b, 0x94, 0xc5, + 0x88, 0x15, 0xcd, 0x82, 0x8e, 0xf8, 0x42, 0xa5, 0x27, 0xf3, 0xdb, 0x6e, 0xbd, 0x07, 0x9b, 0x9f, 0x0a, 0x29, 0x58, + 0x17, 0xf8, 0x8d, 0x49, 0x21, 0x17, 0x62, 0xe4, 0x86, 0xb1, 0x10, 0x8a, 0xe9, 0xee, 0x9c, 0x8e, 0xc0, 0x0e, 0x38, + 0x3d, 0x9f, 0xdf, 0x76, 0xcd, 0xac, 0x6f, 0x18, 0x9f, 0x4c, 0x75, 0x7a, 0xda, 0x6a, 0xd9, 0x6f, 0xc5, 0xbf, 0xb2, + 0xb4, 0xdd, 0x49, 0x3a, 0xa7, 0xf3, 0x5b, 0xe0, 0xe0, 0x35, 0x2b, 0x9a, 0x00, 0x0b, 0xa8, 0xd4, 0x4e, 0x5a, 0x0f, + 0x8e, 0xef, 0x43, 0x06, 0xd8, 0x38, 0x34, 0xcd, 0x84, 0xc0, 0xd8, 0x3d, 0x5d, 0xcc, 0xe7, 0xac, 0x00, 0x2f, 0xfa, + 0xee, 0x8c, 0x16, 0x13, 0x2e, 0x9a, 0x85, 0x69, 0xb4, 0x79, 0x3e, 0xbf, 0x5d, 0xc3, 0x7c, 0x52, 0x6b, 0xb6, 0xea, + 0xa6, 0xe5, 0xbe, 0x96, 0xc1, 0x10, 0x4d, 0x4c, 0x9a, 0xb4, 0x98, 0x0c, 0x69, 0xdc, 0xee, 0xdc, 0xc7, 0xfe, 0x7f, + 0x49, 0x07, 0x05, 0x60, 0x6b, 0x8e, 0x16, 0x85, 0xb9, 0x45, 0x4d, 0xdb, 0xca, 0x36, 0x3b, 0x95, 0x5f, 0x58, 0xe1, + 0x5b, 0x35, 0x1f, 0xcb, 0xad, 0x79, 0xff, 0x27, 0x8d, 0xfe, 0x85, 0x27, 0x14, 0xd6, 0xc0, 0x20, 0x47, 0xdf, 0xc8, + 0x83, 0x30, 0xd3, 0xc1, 0xf2, 0x86, 0x8f, 0xf4, 0x34, 0x6d, 0xb7, 0x5a, 0x3f, 0x54, 0x2b, 0xd6, 0x9d, 0x5a, 0xd0, + 0xb5, 0x0b, 0x36, 0xab, 0xad, 0xe3, 0x8c, 0x96, 0xd8, 0xb6, 0x9c, 0x4b, 0xb7, 0xe4, 0x05, 0xcb, 0x4d, 0x34, 0x99, + 0xb5, 0x43, 0xb9, 0xad, 0x71, 0x72, 0x31, 0x65, 0x05, 0xd7, 0xdd, 0xfa, 0x57, 0xd5, 0xf1, 0xf6, 0xea, 0xaf, 0xad, + 0x1c, 0xba, 0xb4, 0x35, 0xdc, 0xa5, 0xe7, 0x63, 0xf8, 0xd8, 0x5e, 0xfd, 0x2f, 0xb4, 0x88, 0x37, 0x10, 0x13, 0x87, + 0x35, 0xd0, 0x3a, 0x98, 0x73, 0x01, 0x26, 0x99, 0x03, 0xfc, 0x0d, 0x28, 0x64, 0x34, 0xcf, 0x62, 0x18, 0xd1, 0x5e, + 0x73, 0xef, 0xb8, 0x60, 0x33, 0xe4, 0x01, 0x91, 0xdc, 0x3f, 0x2d, 0xd8, 0x6c, 0x9d, 0x98, 0xea, 0x4b, 0x83, 0x22, + 0x34, 0xe7, 0x13, 0x91, 0x66, 0x0c, 0xd0, 0x77, 0x9d, 0x30, 0xa1, 0xb9, 0xbe, 0x6b, 0x16, 0xf2, 0x66, 0x39, 0xe2, + 0x6a, 0x9e, 0xd3, 0xbb, 0x74, 0x9c, 0xb3, 0xdb, 0xae, 0x29, 0xd5, 0xe4, 0x9a, 0xcd, 0x94, 0x2b, 0xdb, 0x85, 0xf4, + 0xe6, 0xc8, 0x9a, 0x4d, 0x00, 0xf4, 0xe4, 0xcd, 0xe6, 0xfe, 0x49, 0x8e, 0xd5, 0x1e, 0xa3, 0x8a, 0x35, 0xe5, 0x42, + 0xef, 0xb5, 0x54, 0x77, 0xc6, 0x45, 0xd3, 0x0d, 0xe4, 0xa4, 0x35, 0xbf, 0xed, 0x6e, 0x43, 0x3e, 0xe8, 0x3f, 0x61, + 0xb7, 0x73, 0x2a, 0x46, 0x6c, 0xb4, 0x0c, 0xaa, 0x75, 0xa0, 0x5e, 0x58, 0x2a, 0x15, 0x7a, 0xda, 0x34, 0xb6, 0x5e, + 0x71, 0x47, 0xa0, 0x6f, 0xa0, 0xd6, 0x83, 0x16, 0xb6, 0xff, 0x9f, 0xb4, 0x51, 0x58, 0x79, 0x0f, 0xc2, 0x2e, 0xf1, + 0xf1, 0x5d, 0x13, 0xfe, 0x2e, 0xc1, 0xb7, 0x88, 0x67, 0x34, 0x77, 0x10, 0x99, 0xf1, 0xd1, 0x28, 0xaf, 0x8d, 0xe8, + 0x32, 0xe8, 0xac, 0x8d, 0x96, 0x30, 0xff, 0xb4, 0xb5, 0xd7, 0xda, 0x33, 0x73, 0x71, 0xdb, 0xfc, 0xe4, 0xe4, 0xfe, + 0xf1, 0x03, 0xd6, 0xcd, 0xb9, 0x60, 0xb5, 0xa9, 0x7e, 0x17, 0xd4, 0x61, 0xc3, 0x1d, 0xd7, 0x70, 0x7b, 0xaf, 0xbd, + 0x77, 0xd2, 0xfa, 0xc1, 0xef, 0xd6, 0x9c, 0x8d, 0x75, 0xda, 0x3e, 0x9b, 0xdf, 0xd6, 0xb7, 0xef, 0xb9, 0x6f, 0xfa, + 0xa6, 0xa0, 0xf3, 0x54, 0x48, 0xf8, 0xd3, 0x85, 0x4d, 0x36, 0xce, 0xe5, 0x4d, 0x3a, 0xe5, 0xa3, 0x11, 0x13, 0xb6, + 0x40, 0x99, 0xc8, 0xf2, 0x9c, 0xcf, 0x15, 0xb7, 0xab, 0xe1, 0x70, 0xf7, 0x74, 0x03, 0xaa, 0xe1, 0x80, 0x8e, 0x83, + 0x01, 0x9d, 0x56, 0x03, 0xaa, 0xfa, 0x0f, 0x47, 0xd8, 0xd9, 0x98, 0xab, 0x29, 0xd5, 0xad, 0x61, 0xd2, 0xdf, 0x0b, + 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, + 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, + 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, + 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x70, 0xe7, 0x99, 0x76, 0x07, 0x69, 0xda, 0xbc, 0x61, + 0xc3, 0xcf, 0x5c, 0x5b, 0x3c, 0x6b, 0xaa, 0x1b, 0xf0, 0x78, 0x31, 0xcb, 0x30, 0x67, 0xc5, 0xd2, 0xd3, 0xf0, 0x56, + 0x8d, 0xea, 0x5c, 0x09, 0x73, 0x7a, 0x68, 0x3a, 0x6c, 0x42, 0xfc, 0x2f, 0x56, 0x94, 0x7b, 0x8c, 0x0b, 0x83, 0x31, + 0x06, 0x40, 0x9b, 0xbb, 0x24, 0x3c, 0x03, 0x4e, 0x5a, 0x2d, 0x7f, 0x3e, 0x34, 0x6d, 0x9d, 0xb4, 0x9d, 0x9c, 0xb2, + 0xd9, 0xae, 0xfd, 0x59, 0x27, 0x46, 0xed, 0xce, 0xfc, 0x76, 0xcf, 0xfc, 0xd3, 0xda, 0x6b, 0x6d, 0x13, 0x9f, 0x6d, + 0x38, 0x1d, 0x23, 0xbf, 0xb2, 0x5a, 0xce, 0xd3, 0x36, 0x9b, 0x75, 0x17, 0x0a, 0x0e, 0x1a, 0x43, 0x1b, 0xcd, 0x01, + 0xb6, 0x36, 0x33, 0x81, 0x75, 0xa4, 0x5c, 0x00, 0x5d, 0xb7, 0x67, 0x1b, 0xf4, 0xa1, 0x24, 0x18, 0x62, 0xef, 0x6c, + 0xb4, 0x3e, 0xac, 0xd6, 0x5e, 0x35, 0x30, 0xf8, 0x67, 0xfd, 0x57, 0xc5, 0x19, 0xbe, 0x60, 0x01, 0x67, 0xce, 0x1b, + 0xc9, 0xe9, 0xaa, 0xe5, 0xb8, 0xf1, 0x91, 0xae, 0x84, 0x04, 0xe3, 0xcb, 0x30, 0xa3, 0xb7, 0xd6, 0xa9, 0x61, 0xc6, + 0x05, 0x98, 0x4c, 0x21, 0xac, 0x03, 0xe3, 0xf2, 0x69, 0xd8, 0xd0, 0x48, 0xc7, 0xd0, 0xf0, 0x61, 0x27, 0x39, 0x3d, + 0x45, 0xb8, 0x85, 0x3b, 0xa7, 0xa7, 0x81, 0x34, 0x30, 0xd6, 0xbb, 0x8a, 0xee, 0x2a, 0xa9, 0x76, 0x94, 0x3c, 0x32, + 0x8d, 0x1e, 0xb5, 0x5b, 0x2d, 0x6c, 0x1c, 0xb7, 0xcb, 0xc2, 0x5c, 0xed, 0x68, 0xb6, 0xdd, 0x6a, 0x41, 0xb3, 0xf0, + 0xc7, 0xcd, 0xeb, 0x17, 0xb2, 0x6c, 0xa5, 0x2d, 0xdc, 0x4e, 0xdb, 0xb8, 0x93, 0x76, 0xf0, 0x71, 0x7a, 0x8c, 0x4f, + 0xd2, 0x13, 0x7c, 0x9a, 0x9e, 0xe2, 0xb3, 0xf4, 0x0c, 0xdf, 0x4f, 0xef, 0xe3, 0xf3, 0xf4, 0x1c, 0x3f, 0x48, 0x1f, + 0xe0, 0x87, 0x69, 0xbb, 0x85, 0x1f, 0xa5, 0xed, 0x36, 0x7e, 0x9c, 0xb6, 0x3b, 0xf8, 0x49, 0xda, 0x3e, 0xc6, 0x4f, + 0xd3, 0xf6, 0x09, 0x7e, 0x96, 0xb6, 0x4f, 0x31, 0x85, 0xdc, 0x21, 0xe4, 0x66, 0x90, 0x3b, 0x82, 0x5c, 0x06, 0xb9, + 0xe3, 0xb4, 0x7d, 0xba, 0xc6, 0xca, 0x06, 0x7b, 0x88, 0x5a, 0xed, 0xce, 0xf1, 0xc9, 0xe9, 0xd9, 0xfd, 0xf3, 0x07, + 0x0f, 0x1f, 0x3d, 0x7e, 0xf2, 0xf4, 0x59, 0x34, 0xc0, 0x43, 0xe3, 0x73, 0xa1, 0x44, 0x9f, 0x1f, 0xb4, 0x4f, 0x07, + 0xf8, 0xda, 0x7f, 0xc6, 0xfc, 0xa0, 0x73, 0xd2, 0x42, 0x97, 0x97, 0x27, 0x83, 0x46, 0x99, 0xfb, 0xde, 0xb8, 0x7a, + 0x54, 0x59, 0x84, 0x90, 0x18, 0x72, 0x10, 0xbe, 0x33, 0xf5, 0xde, 0xb3, 0x98, 0x27, 0x05, 0x3a, 0x38, 0x30, 0x3f, + 0x26, 0xfe, 0xc7, 0xd0, 0xff, 0xa0, 0xc1, 0x22, 0xdd, 0xd2, 0xd8, 0xf9, 0xfa, 0xea, 0xd2, 0xd2, 0xbe, 0x34, 0x62, + 0xd9, 0xe3, 0xce, 0x9c, 0xfc, 0xbf, 0x22, 0x6b, 0x2e, 0x42, 0x4e, 0xac, 0x4a, 0xe6, 0xb4, 0xc7, 0xc8, 0xb2, 0x48, + 0x3b, 0xa7, 0xa7, 0x07, 0xbf, 0xf4, 0x79, 0xbf, 0x3d, 0x18, 0x1c, 0xb6, 0xef, 0xe3, 0x49, 0x99, 0xd0, 0xb1, 0x09, + 0xc3, 0x32, 0xe1, 0xd8, 0x26, 0xd0, 0xd4, 0xd6, 0x86, 0xa4, 0x13, 0x93, 0x04, 0x25, 0xd6, 0xa9, 0x69, 0xfb, 0xbe, + 0x6d, 0xfb, 0x01, 0xd8, 0x31, 0x99, 0xe6, 0x5d, 0xd3, 0x17, 0x17, 0x27, 0x2b, 0xd7, 0x28, 0x9e, 0xa4, 0xae, 0x35, + 0x9f, 0x78, 0x32, 0x18, 0xe0, 0xa1, 0x49, 0x3c, 0xad, 0x12, 0xcf, 0x06, 0x03, 0xd7, 0xd5, 0x03, 0xd3, 0xd5, 0xfd, + 0x2a, 0xeb, 0x7c, 0x30, 0x30, 0x5d, 0x22, 0xe7, 0xb5, 0xae, 0xf4, 0xde, 0x97, 0x52, 0x73, 0xc0, 0x2f, 0x3a, 0xa7, + 0xa7, 0x3d, 0xc0, 0x30, 0x63, 0x8d, 0xea, 0x61, 0x74, 0x13, 0xc0, 0xe8, 0x0e, 0x7e, 0xf7, 0x86, 0x34, 0xbd, 0xa6, + 0x25, 0x90, 0x7a, 0xd1, 0x7f, 0x45, 0x0d, 0x6d, 0x60, 0x6e, 0xfe, 0x4c, 0xec, 0x9f, 0x21, 0x6a, 0x7c, 0xa1, 0x00, + 0x6e, 0xd0, 0x85, 0x78, 0x65, 0xa6, 0xe9, 0xf1, 0x33, 0x05, 0xe7, 0x92, 0xa9, 0xca, 0x69, 0x6f, 0x35, 0xbd, 0x19, + 0xae, 0xa6, 0xea, 0x0b, 0xfa, 0x33, 0xfe, 0x53, 0x1d, 0xc6, 0xfd, 0x66, 0x23, 0x61, 0x7f, 0x8e, 0xc0, 0x8b, 0xa5, + 0x97, 0x8e, 0xd8, 0x04, 0xf5, 0xfa, 0x7f, 0x2a, 0x3c, 0x68, 0x04, 0x19, 0x3f, 0x6c, 0xa7, 0x80, 0x8f, 0xcb, 0x66, + 0x62, 0xfc, 0x03, 0xea, 0xa1, 0xde, 0x9f, 0xea, 0xf0, 0x4f, 0x74, 0xef, 0xa8, 0x9a, 0xcb, 0xef, 0xd2, 0x6d, 0xe1, + 0x2a, 0xf0, 0xcd, 0x61, 0xb9, 0x85, 0x19, 0x6e, 0x37, 0x19, 0x84, 0x09, 0x03, 0x27, 0x68, 0x12, 0xcb, 0x06, 0x3f, + 0x3a, 0x6e, 0xa1, 0x1f, 0xda, 0x1d, 0x10, 0xeb, 0x9b, 0xe2, 0x70, 0x7b, 0xd3, 0x17, 0xcd, 0x63, 0xfc, 0xa0, 0x59, + 0xe0, 0x36, 0xc2, 0xcd, 0xb6, 0xd7, 0xb7, 0xf6, 0x55, 0xdc, 0x42, 0x58, 0xc5, 0xe7, 0xf0, 0xcf, 0x09, 0x1a, 0x54, + 0x1b, 0xf2, 0x8a, 0x6e, 0xf6, 0x0e, 0x1e, 0x9b, 0x24, 0x56, 0x0d, 0x7e, 0x74, 0xd6, 0x42, 0x3f, 0x9c, 0x99, 0x8e, + 0xd8, 0xa1, 0xde, 0xd1, 0x95, 0xc4, 0x27, 0x4d, 0x09, 0x1d, 0xb5, 0xca, 0x7e, 0x44, 0x7c, 0x8a, 0xb0, 0x88, 0x8f, + 0xe1, 0x9f, 0x76, 0xd8, 0xcf, 0xaf, 0x5b, 0xfd, 0x98, 0x79, 0xb7, 0x71, 0x72, 0x6a, 0x1d, 0x40, 0x95, 0xbd, 0x8d, + 0x6d, 0xb0, 0xcb, 0xb6, 0xb9, 0x46, 0x6a, 0x1f, 0xc1, 0x07, 0xc2, 0xfa, 0x90, 0x28, 0xcc, 0x0e, 0xc1, 0x73, 0x14, + 0x0c, 0x26, 0xd4, 0xc5, 0x71, 0x57, 0x35, 0x1a, 0x48, 0xf4, 0xd5, 0xe0, 0x90, 0xb4, 0x9b, 0xba, 0xc9, 0x30, 0xfc, + 0x6e, 0x90, 0x32, 0x1c, 0x99, 0xa8, 0x7a, 0x7d, 0xec, 0x7a, 0xb5, 0x77, 0xce, 0x1e, 0x3b, 0x08, 0x21, 0xaa, 0x17, + 0xeb, 0x26, 0x43, 0x47, 0xa2, 0x11, 0xeb, 0x0b, 0xd6, 0x3b, 0x4b, 0x5b, 0xc8, 0x60, 0xa7, 0xea, 0xc5, 0xac, 0xc9, + 0x21, 0xbd, 0x93, 0xc6, 0xbc, 0xa9, 0xe1, 0xd7, 0x49, 0x30, 0x0b, 0x01, 0x78, 0x57, 0xf9, 0xc1, 0x14, 0x47, 0x9d, + 0xd3, 0x53, 0x2c, 0x08, 0x4f, 0x26, 0xe6, 0x97, 0x22, 0x3c, 0x19, 0x9a, 0x5f, 0x92, 0x94, 0xf0, 0xb2, 0xbd, 0xe3, + 0x82, 0x04, 0xab, 0x6a, 0x52, 0x28, 0x2c, 0x68, 0x81, 0x8e, 0x3a, 0xfe, 0x42, 0x1a, 0x4f, 0xfd, 0x1c, 0x40, 0x00, + 0x2f, 0x8c, 0x2d, 0xa2, 0x6c, 0x16, 0x38, 0x27, 0xf4, 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, + 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, 0xb6, 0x86, 0xa7, 0x70, 0x8b, 0x98, 0x91, 0xec, 0xf0, 0xac, + 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, + 0xa5, 0x8e, 0x68, 0x33, 0x2a, 0x4c, 0x8f, 0xc7, 0x1a, 0x6e, 0xc4, 0x35, 0xf8, 0x99, 0x68, 0xf0, 0x80, 0x49, 0xb9, + 0xbb, 0x8a, 0x42, 0x26, 0x2e, 0xde, 0x38, 0xd4, 0x1a, 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x4d, 0xa3, 0x88, 0x7f, 0x97, + 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, + 0x03, 0x1d, 0x17, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, + 0xad, 0x34, 0xf9, 0x4c, 0xad, 0x95, 0x3f, 0xf7, 0xee, 0xc6, 0x66, 0xe1, 0xac, 0xb3, 0x73, 0xe9, 0xd9, 0xdc, 0x3f, + 0x05, 0x2b, 0x0a, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, + 0xa1, 0xf2, 0x32, 0xf5, 0xa3, 0x84, 0xa4, 0xce, 0x00, 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, + 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x95, 0xe1, 0x5c, 0x01, 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0xeb, + 0x6e, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0xb0, + 0xf4, 0xc0, 0x93, 0x14, 0xac, 0x3c, 0xf0, 0x30, 0x15, 0xe0, 0x89, 0x40, 0x53, 0x16, 0xd8, 0x8f, 0x3f, 0x74, 0xba, + 0x23, 0x73, 0xdf, 0x49, 0x0c, 0x96, 0x76, 0x19, 0x9c, 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, + 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, + 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0x5f, 0x21, 0x6b, 0xdb, 0x38, 0xdc, 0x4d, 0x43, 0x13, 0x82, 0x70, 0x15, + 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0xf0, 0x22, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, + 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, + 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x47, 0x34, 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, + 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, + 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0x26, 0x1c, 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x76, 0xf8, + 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, + 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, + 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, + 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, + 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, + 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, + 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, + 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, + 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, + 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, + 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, + 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, 0x26, 0x8d, 0x12, 0x7d, 0xcc, 0x86, 0xd9, 0x28, 0xc2, 0x66, + 0x30, 0x63, 0xf8, 0xfb, 0x85, 0xbf, 0x63, 0x3a, 0x8d, 0xce, 0x69, 0x67, 0xc8, 0x3a, 0x11, 0x1e, 0xbe, 0xb9, 0x11, + 0x69, 0x44, 0x4f, 0x3b, 0xb4, 0x43, 0x23, 0x3c, 0x5c, 0x14, 0xf9, 0xdd, 0x8d, 0x94, 0x23, 0x00, 0xc2, 0xf0, 0xfc, + 0xfc, 0x7e, 0x84, 0x33, 0xfa, 0xab, 0x86, 0xda, 0xa7, 0xe3, 0x07, 0x8c, 0xb6, 0x22, 0xfc, 0x0b, 0x2d, 0xf4, 0xc7, + 0x85, 0x72, 0x03, 0x6d, 0x41, 0x8a, 0xcc, 0xde, 0x81, 0x82, 0x39, 0x1a, 0x75, 0xce, 0x1e, 0xb4, 0x59, 0x84, 0xb3, + 0xab, 0xd7, 0xd0, 0xdb, 0xfd, 0xf1, 0x69, 0x0b, 0x3e, 0x04, 0x48, 0x6a, 0xac, 0x80, 0x46, 0xce, 0x4e, 0x1e, 0x9c, + 0xb2, 0x91, 0x49, 0x54, 0x3c, 0xff, 0x6c, 0x66, 0x7f, 0x0e, 0xf3, 0xc9, 0x0a, 0x3e, 0x53, 0x52, 0xa4, 0xd1, 0x28, + 0x6b, 0x9f, 0x1c, 0x43, 0xc2, 0x1d, 0x15, 0x1e, 0x38, 0xb7, 0x50, 0xf5, 0x7c, 0x18, 0xe1, 0x5b, 0x9b, 0x7a, 0x3e, + 0x34, 0x1f, 0x93, 0x77, 0xbf, 0x8a, 0x37, 0xa3, 0x34, 0x1a, 0x9e, 0x9f, 0x9f, 0xb5, 0x20, 0xe1, 0x03, 0xbd, 0x4b, + 0x23, 0xfa, 0x00, 0xfe, 0x83, 0xec, 0x8f, 0xcf, 0xa0, 0x43, 0x18, 0xe1, 0xed, 0xe4, 0x63, 0x98, 0xf3, 0x79, 0x4a, + 0x3f, 0xf3, 0x34, 0x1a, 0x8e, 0x86, 0xf7, 0xcf, 0xa0, 0xde, 0x8c, 0x4e, 0x9e, 0x69, 0x0a, 0xed, 0xb6, 0x5a, 0xa6, + 0xe5, 0x77, 0xfc, 0x0b, 0x33, 0xd5, 0x4f, 0x4f, 0xcf, 0x86, 0x1d, 0x18, 0xc1, 0x15, 0xa8, 0x18, 0x60, 0x3c, 0xe7, + 0x99, 0x69, 0xf0, 0x2a, 0x7b, 0x3a, 0x4a, 0xa3, 0x07, 0x0f, 0x8e, 0x3b, 0x59, 0x16, 0xe1, 0xdb, 0x8f, 0x23, 0x5b, + 0xdb, 0xe4, 0x29, 0x80, 0x7d, 0x1a, 0xb1, 0x07, 0x0f, 0xce, 0xee, 0x53, 0xf8, 0x7e, 0x6e, 0xda, 0x3a, 0x1f, 0x0f, + 0xb3, 0x73, 0x68, 0xeb, 0x77, 0x98, 0xce, 0xc9, 0xf9, 0xf1, 0xc8, 0xf4, 0xf5, 0xbb, 0x19, 0x75, 0x67, 0x7c, 0x32, + 0x3e, 0x31, 0x99, 0x66, 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x8d, 0x32, 0x36, 0x6a, 0x47, 0xf8, 0xd6, 0x2d, 0xdc, 0x83, + 0x93, 0x56, 0x6b, 0x74, 0x1c, 0xe1, 0xd1, 0xc3, 0xf9, 0xfc, 0xad, 0x81, 0x60, 0xfb, 0xe4, 0x81, 0xfd, 0x56, 0x9f, + 0xef, 0xa0, 0xe9, 0xa1, 0x01, 0xda, 0x88, 0xcf, 0x4c, 0xcb, 0x67, 0x0f, 0xe0, 0x3f, 0xf3, 0x6d, 0x9a, 0x2e, 0xbf, + 0xe5, 0x68, 0x62, 0x17, 0xa5, 0xcd, 0x1e, 0xb4, 0xa0, 0xc6, 0x98, 0x7f, 0x1c, 0x16, 0x1c, 0xd0, 0x68, 0xd8, 0x81, + 0xff, 0x8b, 0xf0, 0x38, 0xbf, 0x7a, 0xed, 0x70, 0x76, 0x3c, 0xa6, 0xe3, 0x56, 0x84, 0xc7, 0xf2, 0xa3, 0xd2, 0x1f, + 0x1e, 0x8a, 0x34, 0xea, 0x74, 0xce, 0x87, 0xa6, 0xcc, 0xe2, 0x17, 0xc5, 0x0d, 0x1e, 0xb7, 0x4c, 0x2b, 0x13, 0xfa, + 0x56, 0x0d, 0xaf, 0x24, 0xac, 0x24, 0xfc, 0x17, 0xe1, 0x09, 0xe8, 0xa5, 0x5c, 0x2b, 0xe7, 0x76, 0x3b, 0x4c, 0xde, + 0x19, 0xd4, 0x1c, 0xdd, 0x07, 0x78, 0xf9, 0x65, 0x1c, 0x51, 0x7a, 0xda, 0x69, 0x45, 0xd8, 0x8c, 0xfa, 0xbc, 0x05, + 0xff, 0x45, 0xd8, 0x42, 0xce, 0xc0, 0x75, 0xf2, 0xf1, 0xd9, 0xcb, 0x9b, 0x34, 0xa2, 0xa3, 0xf1, 0x18, 0x96, 0xc4, + 0x4c, 0xc6, 0x17, 0x9b, 0x4a, 0xc1, 0xee, 0x7e, 0xbd, 0x71, 0xdb, 0xc5, 0x24, 0x68, 0x07, 0x9d, 0xb3, 0x07, 0xc3, + 0x93, 0x08, 0xbf, 0x1d, 0x71, 0x2a, 0x60, 0x95, 0xb2, 0xd1, 0x69, 0x76, 0x9a, 0x99, 0x84, 0x89, 0x4c, 0xa3, 0x13, + 0x58, 0xf2, 0x4e, 0x84, 0xf9, 0x97, 0xab, 0x3b, 0x8b, 0x6e, 0x50, 0xdb, 0x21, 0xc8, 0xb8, 0xc5, 0xce, 0xce, 0xb3, + 0x08, 0xe7, 0xf4, 0xcb, 0xb3, 0x5f, 0x8b, 0x34, 0x62, 0x67, 0xec, 0x6c, 0x4c, 0xfd, 0xf7, 0x1f, 0x6a, 0x6a, 0x6a, + 0xb4, 0xc6, 0xa7, 0x90, 0x74, 0x23, 0xcc, 0x58, 0xef, 0x67, 0x63, 0x83, 0x21, 0xaf, 0x66, 0x52, 0x64, 0x4f, 0xc7, + 0x63, 0x69, 0xb1, 0x98, 0xc2, 0x26, 0xfc, 0x04, 0xd0, 0xa6, 0xa3, 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x27, 0xbb, 0x4b, + 0xdc, 0x04, 0x3e, 0x59, 0xcc, 0x66, 0x6e, 0xb7, 0x7f, 0xb2, 0x40, 0x81, 0xf9, 0x8e, 0xe9, 0x98, 0x8e, 0x3a, 0x11, + 0xfe, 0x64, 0xe0, 0x32, 0x3a, 0x86, 0xff, 0xa0, 0x00, 0x74, 0xf6, 0xa0, 0xc5, 0xd8, 0x83, 0x96, 0xf9, 0x0a, 0xf3, + 0xdc, 0xcc, 0x87, 0x67, 0x59, 0x3b, 0xc2, 0x9f, 0x1c, 0x3a, 0x8e, 0xc7, 0xb4, 0x05, 0xe8, 0xf8, 0xc9, 0xa1, 0x63, + 0xa7, 0x35, 0xec, 0x50, 0xf3, 0x6d, 0xb1, 0xe6, 0xfc, 0x7e, 0xc6, 0x60, 0x72, 0x9f, 0x2c, 0x42, 0xde, 0xbf, 0x7f, + 0x7e, 0xfe, 0xe0, 0x01, 0x7c, 0x9a, 0xb6, 0xcb, 0x4f, 0xa5, 0x1f, 0xe6, 0x06, 0xc9, 0x5a, 0xd9, 0x09, 0xd0, 0xc9, + 0x4f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, + 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, + 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, + 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, + 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, + 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, + 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, + 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, + 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, + 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, + 0x87, 0x23, 0xfc, 0x6e, 0x04, 0xd7, 0x60, 0x69, 0x34, 0x1e, 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, + 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, + 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, + 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, + 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, + 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, + 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, + 0x21, 0xdc, 0xf3, 0x2d, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, 0x08, 0x6e, 0xfd, 0xe4, 0xcd, 0xaf, 0x85, 0x45, 0x23, + 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, + 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, + 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, + 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, + 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, + 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, + 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, + 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, + 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, + 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, + 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, + 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, + 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, + 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0x3d, 0xe8, 0x13, 0x1a, 0x7b, 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xe1, 0x45, 0x3f, + 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x5c, 0x00, 0x9c, 0x41, 0xbd, 0xf3, 0x99, 0x04, 0x41, 0x52, + 0x90, 0x56, 0x57, 0x5c, 0x78, 0x3f, 0xce, 0xae, 0x80, 0xa0, 0x03, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0xc4, 0x66, 0xb1, + 0xc2, 0xa4, 0x37, 0x6f, 0x37, 0x32, 0xa5, 0xb4, 0x06, 0xf3, 0x94, 0x50, 0x1f, 0x95, 0x1d, 0x2e, 0x69, 0x21, 0x6e, + 0x11, 0xea, 0x4a, 0x62, 0x62, 0x2c, 0xbf, 0x10, 0x3a, 0x56, 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0x5e, + 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0x11, + 0xa3, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, + 0x47, 0x2c, 0x31, 0xb7, 0x06, 0xd6, 0x37, 0x85, 0xf4, 0x41, 0x73, 0xd6, 0xc2, 0x10, 0xc7, 0xdc, 0x73, 0xde, 0x8f, + 0x58, 0x9f, 0xd7, 0xfd, 0x9a, 0xab, 0xe0, 0xc1, 0x07, 0x07, 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, + 0x56, 0x4c, 0xd0, 0x55, 0xf8, 0xf6, 0x93, 0x1e, 0x48, 0x29, 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, + 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, + 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, 0x49, 0x23, 0x9a, 0xed, 0xdb, 0x48, 0x18, 0xba, 0x7f, + 0xdf, 0x08, 0x66, 0x55, 0x78, 0xb6, 0x06, 0x24, 0x75, 0x41, 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, + 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x45, 0xb4, 0x61, 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, + 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, + 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, + 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, + 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, + 0x46, 0x49, 0xf4, 0x97, 0x57, 0xa2, 0x3e, 0xe2, 0x26, 0xfe, 0xcc, 0x05, 0x49, 0x5a, 0xad, 0xe3, 0xf6, 0x71, 0xeb, + 0xbc, 0xc7, 0x0f, 0xdb, 0x9d, 0xe4, 0x41, 0x27, 0x35, 0x8a, 0x88, 0xb9, 0xbc, 0x01, 0x05, 0xcc, 0x51, 0x27, 0x39, + 0x41, 0x87, 0xed, 0xa4, 0x75, 0x7a, 0xda, 0x84, 0x7f, 0xf0, 0x7b, 0x5d, 0x56, 0x3b, 0x69, 0x9d, 0x9c, 0xf6, 0xf8, + 0xd1, 0x46, 0xa5, 0x98, 0x37, 0xa0, 0x20, 0x3a, 0x32, 0x95, 0x30, 0xd4, 0xaf, 0x96, 0xf7, 0xd9, 0x96, 0x9e, 0xe7, + 0xbd, 0x8e, 0x95, 0x55, 0xc5, 0x01, 0x54, 0xfd, 0xd7, 0xc4, 0x00, 0xd1, 0x7f, 0x0d, 0xcb, 0x18, 0xb1, 0xcb, 0x02, + 0x44, 0xed, 0x47, 0x3c, 0x16, 0x0d, 0x76, 0x18, 0xdb, 0x7c, 0x0d, 0x75, 0x9b, 0x10, 0xb7, 0x0d, 0x4f, 0x5c, 0xae, + 0x0a, 0x73, 0x27, 0x08, 0x35, 0x15, 0xe4, 0x0e, 0x5d, 0xae, 0x0c, 0x73, 0x87, 0x08, 0x35, 0x25, 0xe4, 0xd2, 0x94, + 0x27, 0x14, 0x72, 0x74, 0x42, 0x9b, 0x06, 0x92, 0xd5, 0xa2, 0x3c, 0x67, 0x7e, 0xd8, 0x7c, 0x0c, 0xcb, 0x63, 0x08, + 0x8a, 0x13, 0xa4, 0x05, 0xbc, 0xed, 0x51, 0x6a, 0x73, 0x5a, 0xb8, 0x54, 0xe3, 0x40, 0x46, 0x03, 0xfe, 0x39, 0x64, + 0xe6, 0xc1, 0x87, 0x56, 0xef, 0xf8, 0xac, 0x95, 0xb6, 0xc1, 0x49, 0x19, 0x64, 0x6d, 0x61, 0x65, 0x6d, 0xe1, 0x65, + 0x6d, 0xe1, 0x65, 0x6d, 0x10, 0xe0, 0x83, 0xbe, 0xff, 0x91, 0x35, 0xc3, 0x0f, 0x5e, 0x5a, 0x91, 0x58, 0x33, 0x81, + 0x58, 0xaf, 0x56, 0xcb, 0x35, 0xd8, 0xf8, 0x94, 0x35, 0xa4, 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, + 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, 0x3f, 0xa6, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, + 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, + 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0xf0, 0x79, 0xb1, 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x5c, 0x98, + 0x2d, 0xa9, 0x13, 0x6a, 0xbc, 0xa6, 0xcb, 0x31, 0x7f, 0xad, 0xa1, 0x7d, 0x02, 0x6f, 0xb9, 0x3c, 0xd4, 0x71, 0x0b, + 0x8c, 0x26, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, 0x8d, 0x33, 0x86, 0xfe, 0xbc, 0xe1, 0x83, 0x6a, 0x29, + 0x41, 0xf8, 0x82, 0xc1, 0x67, 0x56, 0x39, 0xc5, 0x97, 0xb6, 0x9e, 0xce, 0x50, 0xcb, 0x1e, 0x09, 0x5d, 0x30, 0xd8, + 0xf6, 0xd1, 0x96, 0x7a, 0x82, 0x48, 0x65, 0xdc, 0x05, 0x49, 0x15, 0x2f, 0x18, 0xdc, 0x67, 0xc9, 0x2d, 0x35, 0xce, + 0x24, 0x2f, 0xec, 0x9f, 0xaf, 0x34, 0xf0, 0xb6, 0x2b, 0x26, 0x43, 0xef, 0xa4, 0x7a, 0x6d, 0xa2, 0xea, 0x90, 0xfd, + 0x7d, 0x6b, 0x4b, 0x6d, 0xbe, 0x36, 0x8d, 0xa9, 0x4d, 0xa2, 0xc9, 0x86, 0x1d, 0xea, 0xd7, 0xe8, 0x1f, 0xef, 0x2b, + 0x56, 0x4c, 0x86, 0x28, 0xa0, 0xd9, 0x06, 0xac, 0xaa, 0x02, 0x96, 0x72, 0xf5, 0x4a, 0x17, 0x42, 0xe8, 0xdd, 0x8c, + 0x79, 0x5d, 0x4c, 0x86, 0x3b, 0x1f, 0xfd, 0xb0, 0x3d, 0xf6, 0xde, 0xd2, 0xa0, 0x07, 0xaf, 0xda, 0x9e, 0xb2, 0xdb, + 0xef, 0xd5, 0xb9, 0xd9, 0x59, 0x47, 0xe5, 0xdf, 0xab, 0xf3, 0x74, 0x57, 0x9d, 0x19, 0xbf, 0x8d, 0xfd, 0xde, 0xd1, + 0x81, 0x1a, 0xdb, 0x18, 0xe8, 0x4c, 0x86, 0x10, 0xa5, 0x1d, 0xfe, 0xda, 0x58, 0x2a, 0x5d, 0x4f, 0xc2, 0x61, 0x15, + 0x64, 0x2f, 0x39, 0x4d, 0x19, 0xa6, 0xa4, 0x73, 0x58, 0x98, 0x68, 0x2a, 0x22, 0xa1, 0x4d, 0x95, 0x50, 0x9c, 0x93, + 0x38, 0xa6, 0x87, 0x19, 0xc4, 0x84, 0x69, 0xf7, 0x68, 0x1a, 0xd3, 0x46, 0x86, 0x8e, 0xe2, 0x76, 0x83, 0x1e, 0x66, + 0x08, 0x35, 0xda, 0xa0, 0x33, 0x95, 0xa4, 0xdd, 0xcc, 0x21, 0x4a, 0xa4, 0x21, 0xc5, 0xf9, 0xa1, 0x48, 0x8a, 0x86, + 0x3c, 0x54, 0x49, 0xd1, 0x48, 0x4e, 0xb1, 0x48, 0x26, 0x65, 0xf2, 0xc4, 0x24, 0x4f, 0x6c, 0xf2, 0xb0, 0x4c, 0x1e, + 0x9a, 0xe4, 0xa1, 0x4d, 0xa6, 0xa4, 0x38, 0x14, 0x09, 0x6d, 0xc4, 0xed, 0x66, 0x81, 0x0e, 0x61, 0x04, 0x7e, 0xf4, + 0x44, 0x84, 0xc1, 0xb9, 0xd7, 0xc6, 0xba, 0x65, 0x2e, 0x73, 0x17, 0x2e, 0xb3, 0x02, 0x52, 0xe9, 0x72, 0x04, 0x75, + 0x9e, 0x05, 0x60, 0xc2, 0xda, 0xfe, 0xf1, 0xc1, 0xe0, 0xd6, 0x59, 0x2e, 0x45, 0xe0, 0x52, 0x05, 0x56, 0xe0, 0x9f, + 0x9d, 0x23, 0x09, 0x40, 0x75, 0x4d, 0xf3, 0xf9, 0x94, 0x6e, 0xf9, 0xad, 0x16, 0x93, 0xa1, 0xdb, 0x59, 0x65, 0x33, + 0x8c, 0x16, 0x36, 0xc8, 0x72, 0xdd, 0xc3, 0x10, 0x40, 0xed, 0xbd, 0x1a, 0x13, 0x6a, 0x94, 0xe4, 0xb6, 0xc6, 0xa4, + 0x60, 0x77, 0x2a, 0xa3, 0x39, 0x8b, 0xab, 0x03, 0xb8, 0x1a, 0x26, 0x23, 0x2f, 0xc0, 0x16, 0xbd, 0x38, 0x4c, 0x8e, + 0x1b, 0x3a, 0x99, 0x1c, 0x26, 0xa7, 0x0f, 0x1a, 0x3a, 0x19, 0x1e, 0x26, 0xed, 0x76, 0x85, 0xb3, 0x49, 0x41, 0x74, + 0x32, 0x21, 0x1a, 0x34, 0x86, 0xb6, 0x51, 0x39, 0xa7, 0x60, 0x5c, 0xf5, 0x6f, 0x0c, 0xa3, 0xe1, 0x86, 0x21, 0xd8, + 0xc4, 0xc6, 0x9b, 0xdc, 0x1a, 0x43, 0xd8, 0x4d, 0xe7, 0xf4, 0xb4, 0xa9, 0x93, 0x02, 0x6b, 0xbb, 0x92, 0x4d, 0x9d, + 0x4c, 0xb0, 0xb6, 0xcb, 0xd7, 0xd4, 0xc9, 0xd0, 0x36, 0x65, 0x74, 0x80, 0x4c, 0x04, 0xc0, 0x7a, 0xce, 0x02, 0xc8, + 0x77, 0xbc, 0x7b, 0xc8, 0x1a, 0xb4, 0x86, 0xdf, 0x2b, 0xd7, 0xf4, 0x05, 0x15, 0xd5, 0x60, 0x64, 0xc3, 0xbe, 0x55, + 0xb4, 0x5d, 0x35, 0xc9, 0xfe, 0x75, 0xd9, 0xb2, 0xd9, 0x42, 0xea, 0x7a, 0xc1, 0x87, 0x35, 0x0c, 0x71, 0xa5, 0xdc, + 0xc1, 0xfd, 0x8a, 0x92, 0x18, 0xa2, 0xca, 0x99, 0x53, 0x88, 0x13, 0xaf, 0x47, 0x86, 0x24, 0xde, 0x68, 0xac, 0x51, + 0x1c, 0x9c, 0xb7, 0x4f, 0x43, 0xaa, 0xba, 0x15, 0x6a, 0x8e, 0x90, 0x68, 0x21, 0xac, 0x31, 0xe2, 0x28, 0x0a, 0x58, + 0x10, 0xa7, 0xdd, 0xad, 0x1d, 0x10, 0x07, 0x07, 0x9b, 0xe7, 0x85, 0x0f, 0xfa, 0xbf, 0x15, 0xe8, 0xbf, 0xb2, 0x64, + 0xf3, 0x4f, 0x11, 0x59, 0x1b, 0x57, 0x1e, 0x20, 0x8a, 0x0f, 0xfa, 0x74, 0xdf, 0x50, 0xf8, 0x7e, 0x15, 0xf1, 0xce, + 0xe5, 0x34, 0xcf, 0x4c, 0x86, 0xe9, 0x6b, 0x10, 0x8c, 0xed, 0x4d, 0x38, 0xa1, 0xd2, 0x4a, 0xef, 0x5f, 0x76, 0x1c, + 0x74, 0xe2, 0x9e, 0x4a, 0x09, 0x1b, 0xfd, 0x3b, 0xb4, 0x89, 0xad, 0x60, 0xe3, 0xbc, 0xa1, 0x57, 0xab, 0xda, 0xc3, + 0x38, 0xf6, 0xf9, 0x15, 0x74, 0x70, 0xc0, 0xd5, 0x33, 0x30, 0xe3, 0x65, 0x71, 0x23, 0x3c, 0x7c, 0xff, 0xa9, 0x9d, + 0xd6, 0x7f, 0x9b, 0x73, 0x35, 0x0d, 0x0e, 0xba, 0x87, 0xb5, 0xfc, 0x9d, 0x2b, 0xd1, 0xd3, 0x29, 0x77, 0x6b, 0xfd, + 0x77, 0x65, 0x24, 0xbd, 0xf5, 0x44, 0xd3, 0xc1, 0x01, 0xaf, 0x02, 0x25, 0x45, 0x3f, 0x44, 0xa8, 0x67, 0x64, 0x90, + 0x67, 0xb9, 0xa4, 0x70, 0x23, 0x0a, 0x57, 0x0c, 0x69, 0x83, 0x1f, 0x69, 0xfc, 0x87, 0xfc, 0xff, 0xd4, 0xc8, 0xa1, + 0x4e, 0x1b, 0x3c, 0x10, 0xc0, 0x42, 0x56, 0xa8, 0x0a, 0x51, 0x68, 0x20, 0x1d, 0xda, 0x3c, 0xa3, 0xf2, 0x30, 0xa7, + 0xf3, 0x79, 0x7e, 0x67, 0x5e, 0xa9, 0x0a, 0x38, 0xaa, 0xea, 0xa2, 0xc9, 0xc5, 0x87, 0xc3, 0x05, 0xf0, 0xf4, 0x80, + 0x7b, 0xc8, 0xf8, 0x77, 0x96, 0x97, 0xdb, 0x02, 0x81, 0x64, 0xa6, 0x88, 0x6c, 0xb6, 0xbb, 0xea, 0x12, 0xe4, 0xb2, + 0x66, 0x13, 0x69, 0x17, 0x36, 0x1b, 0x73, 0x90, 0xc9, 0x94, 0xf5, 0xe1, 0xdc, 0xb3, 0x05, 0x41, 0x72, 0x93, 0x46, + 0x64, 0xdb, 0x5d, 0x8a, 0x8f, 0x63, 0x40, 0x23, 0x64, 0x05, 0xbe, 0x50, 0x58, 0xe4, 0xc0, 0x75, 0x16, 0xbe, 0xe3, + 0x6f, 0xb4, 0x54, 0xf4, 0xd5, 0x60, 0x80, 0x0b, 0xf3, 0x30, 0x43, 0x39, 0x9f, 0x42, 0x05, 0x0f, 0xfd, 0x04, 0x22, + 0x0a, 0x5f, 0xad, 0xf6, 0xe1, 0x1d, 0x1d, 0xd7, 0x26, 0x38, 0x7d, 0xba, 0x9f, 0xd5, 0x9b, 0x19, 0x30, 0x0e, 0x46, + 0x5a, 0xe6, 0xa2, 0xd0, 0xc9, 0x9b, 0xec, 0x42, 0x74, 0x1b, 0x0d, 0x66, 0x42, 0x1c, 0x11, 0x88, 0x67, 0x06, 0x1e, + 0x79, 0xf0, 0xc7, 0x46, 0x2d, 0x52, 0xcc, 0xc6, 0x7e, 0x83, 0xa0, 0xd4, 0xb5, 0x84, 0xd5, 0x4a, 0xd9, 0xd8, 0x22, + 0x26, 0xc7, 0x46, 0x19, 0x29, 0xfb, 0x29, 0x83, 0x98, 0x56, 0x66, 0x1c, 0xdc, 0x6d, 0xf5, 0xb7, 0xd5, 0x7e, 0xde, + 0xe3, 0xf6, 0x1a, 0x8f, 0x1b, 0x8f, 0x7d, 0x03, 0xa8, 0xe5, 0xc6, 0x06, 0xb7, 0x16, 0xe6, 0xb1, 0x35, 0x87, 0x65, + 0x9b, 0x10, 0x14, 0xa5, 0x87, 0xba, 0xbd, 0xb9, 0xf5, 0x11, 0xfb, 0x94, 0x99, 0x93, 0x42, 0xba, 0x0f, 0x72, 0xf4, + 0x80, 0x40, 0xe7, 0xf6, 0x67, 0x45, 0x17, 0x2a, 0x99, 0xb8, 0x1c, 0xe3, 0x2f, 0xc1, 0x6d, 0x5e, 0x3f, 0xba, 0xbe, + 0x36, 0x9b, 0xfc, 0xfa, 0x3a, 0xc2, 0xa1, 0x59, 0x77, 0x14, 0xf0, 0x82, 0xd1, 0xa0, 0x0c, 0xea, 0x64, 0x36, 0x7e, + 0xb3, 0x5d, 0x35, 0xf6, 0x9e, 0x56, 0x78, 0x07, 0xcb, 0x63, 0x1a, 0xdf, 0x72, 0x83, 0xec, 0x73, 0x80, 0x37, 0xeb, + 0xf3, 0x41, 0xf7, 0x4d, 0xac, 0xd0, 0xc1, 0xc1, 0x9b, 0x58, 0xa2, 0xde, 0x15, 0x33, 0x77, 0x6e, 0xe0, 0x07, 0xdd, + 0xe7, 0x66, 0xf8, 0x32, 0x40, 0x80, 0x2b, 0xb6, 0x29, 0xd9, 0xbc, 0x35, 0x51, 0x27, 0x52, 0x88, 0x6a, 0x0d, 0xb1, + 0x75, 0x1d, 0x48, 0xa0, 0xd7, 0x37, 0x21, 0xb4, 0xbb, 0x8c, 0x30, 0x60, 0xe1, 0x4b, 0x2f, 0x35, 0x96, 0xcc, 0x58, + 0x31, 0x61, 0xc5, 0x6a, 0xf5, 0x9e, 0x5a, 0xcf, 0xb3, 0x8d, 0x20, 0x89, 0xaa, 0xdb, 0x68, 0x50, 0x33, 0x7e, 0x10, + 0x1f, 0xe8, 0x00, 0xef, 0xbf, 0x89, 0x0b, 0x84, 0xc0, 0xc2, 0x88, 0x8b, 0x85, 0xf7, 0xb2, 0xca, 0x6a, 0xeb, 0x52, + 0xa0, 0xb2, 0x91, 0x9c, 0xb4, 0xf0, 0x94, 0x64, 0xe5, 0x1a, 0x5d, 0x4c, 0xbb, 0x8d, 0x46, 0x8e, 0x64, 0x9c, 0xf5, + 0xf3, 0x01, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0x72, 0xf3, 0x5d, 0xda, 0xb1, 0xa6, + 0x8f, 0xe8, 0x3a, 0x00, 0xc6, 0x23, 0x1a, 0x10, 0x89, 0x5d, 0x40, 0x16, 0x16, 0xc8, 0xca, 0x03, 0x59, 0x18, 0x20, + 0x2b, 0xd4, 0x9b, 0x43, 0xb8, 0x20, 0x85, 0xd2, 0x2d, 0x8a, 0x5e, 0x0f, 0x6c, 0xe9, 0x9c, 0x26, 0x30, 0x37, 0xb1, + 0x15, 0xdc, 0x72, 0x80, 0x03, 0x85, 0xf3, 0xc3, 0x53, 0x64, 0x19, 0x45, 0x26, 0xc6, 0x2b, 0xbe, 0x35, 0x7f, 0x92, + 0x5b, 0x7c, 0x67, 0x7f, 0xdc, 0x05, 0xca, 0xa4, 0xe7, 0x35, 0x6d, 0x03, 0x77, 0x11, 0xd1, 0xa2, 0x24, 0x02, 0xb4, + 0x76, 0xe1, 0xfd, 0x44, 0xfd, 0xc5, 0x33, 0x65, 0x03, 0x31, 0x88, 0x06, 0x51, 0x58, 0x04, 0xa4, 0xf3, 0xcf, 0x3f, + 0x23, 0xd4, 0x13, 0x10, 0x47, 0xc7, 0x9d, 0x6c, 0xcd, 0x36, 0x6a, 0x44, 0x49, 0x94, 0xc6, 0x3e, 0x4c, 0x03, 0xec, + 0x8c, 0x28, 0x0a, 0x5e, 0x3b, 0x29, 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x33, 0xa8, 0x2a, 0xf0, 0xc4, 0xe5, 0x72, 0x33, + 0xcc, 0x8f, 0x81, 0xaa, 0x30, 0x31, 0x56, 0x90, 0x7d, 0x02, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0xfa, 0x62, 0x10, 0xbc, + 0xe9, 0x55, 0x5d, 0x87, 0xeb, 0x70, 0xe1, 0x62, 0x0a, 0x71, 0xd6, 0x57, 0x2b, 0xfb, 0x97, 0x7c, 0x30, 0xd2, 0x0c, + 0x3c, 0xce, 0x16, 0x9c, 0xb1, 0x62, 0xb7, 0x2c, 0x96, 0x68, 0xf9, 0x3b, 0x98, 0xed, 0xb9, 0xa8, 0x79, 0xdc, 0x4d, + 0xb5, 0xed, 0xa1, 0x3e, 0x37, 0x1a, 0x85, 0x20, 0x66, 0x6d, 0x75, 0xa4, 0xe1, 0xb9, 0x0e, 0xf3, 0x6a, 0xb1, 0x67, + 0x33, 0x55, 0x86, 0x10, 0x85, 0x23, 0x25, 0x01, 0xbb, 0x6d, 0x43, 0x27, 0xe1, 0x47, 0x9d, 0x4a, 0x3a, 0x16, 0x12, + 0xa0, 0xc0, 0x91, 0xb9, 0x9c, 0x37, 0x21, 0xe2, 0x19, 0xda, 0x41, 0xe4, 0x02, 0x13, 0x9a, 0xba, 0x6c, 0xe9, 0x62, + 0x39, 0x45, 0x33, 0xb9, 0x50, 0x6c, 0x31, 0x87, 0xf3, 0xbd, 0x4c, 0xcb, 0x72, 0x9e, 0x7d, 0xae, 0xa7, 0x80, 0xfd, + 0xe5, 0xad, 0x9e, 0x31, 0xb1, 0x88, 0xdc, 0x3c, 0xbf, 0x5a, 0x71, 0xff, 0xcd, 0x0b, 0xfc, 0x88, 0x74, 0x0e, 0xbf, + 0xe2, 0x8f, 0x94, 0x3c, 0x6a, 0x7c, 0xc5, 0x13, 0x4e, 0x2c, 0x6f, 0x90, 0xbc, 0x79, 0x7d, 0xf5, 0xe2, 0xdd, 0x8b, + 0xf7, 0x4f, 0xaf, 0x5f, 0xbc, 0x7a, 0xf6, 0xe2, 0xd5, 0x8b, 0x77, 0x1f, 0xf1, 0x3f, 0x94, 0x7c, 0x3d, 0x6a, 0x9f, + 0xb7, 0xf0, 0x07, 0xf2, 0xf5, 0xa8, 0x83, 0x6f, 0x35, 0xf9, 0x7a, 0x74, 0x82, 0x73, 0x45, 0xbe, 0x1e, 0x76, 0x8e, + 0x8e, 0xf1, 0x42, 0xdb, 0x26, 0x73, 0x39, 0x69, 0xb7, 0xf0, 0x3f, 0xee, 0x0b, 0xc4, 0xfb, 0x6a, 0x16, 0x13, 0xb6, + 0x61, 0xfc, 0x60, 0xca, 0xd0, 0xa1, 0x32, 0x86, 0x28, 0x17, 0x01, 0x3a, 0x4d, 0x55, 0x88, 0x4e, 0x36, 0x88, 0x31, + 0xd8, 0x30, 0x02, 0x5a, 0x71, 0xe2, 0xda, 0xe1, 0x47, 0x6d, 0x76, 0x0c, 0xf4, 0x89, 0x97, 0xc2, 0x71, 0xa9, 0xc2, + 0x69, 0x3b, 0x2d, 0xc6, 0x38, 0x97, 0xb2, 0x88, 0x17, 0xc0, 0x08, 0x18, 0xad, 0x05, 0x3f, 0x2a, 0xa3, 0x25, 0x89, + 0x0b, 0xd2, 0xee, 0xb5, 0x53, 0x71, 0x41, 0x3a, 0xbd, 0x0e, 0xfc, 0x39, 0xed, 0x9d, 0xa6, 0xed, 0x16, 0x3a, 0x0c, + 0xc6, 0xf1, 0x47, 0x0d, 0xad, 0xfb, 0x03, 0xec, 0xba, 0x50, 0xff, 0x14, 0xda, 0xab, 0xf4, 0x84, 0x53, 0xc7, 0xb6, + 0xbb, 0xe2, 0x82, 0x19, 0x3d, 0x2c, 0xff, 0x01, 0x50, 0xdb, 0x38, 0x74, 0x94, 0x1b, 0xc7, 0xfd, 0xe2, 0x47, 0x02, + 0xd5, 0x42, 0xb2, 0xc4, 0x6c, 0xd5, 0x42, 0xc0, 0x34, 0x9a, 0x6c, 0x30, 0x07, 0x4a, 0x94, 0x2c, 0xb4, 0x0f, 0x2b, + 0xaf, 0x9a, 0x12, 0x25, 0x73, 0x39, 0x8f, 0x6b, 0xaa, 0x86, 0x5f, 0x03, 0x33, 0xc7, 0x7d, 0xae, 0x5e, 0xd1, 0x57, + 0x71, 0x8d, 0xe7, 0x09, 0x59, 0xbb, 0x70, 0x5b, 0xfc, 0xe2, 0xac, 0x28, 0x6a, 0xe0, 0x2a, 0x01, 0xeb, 0x47, 0xd5, + 0xd4, 0x17, 0xf0, 0x7e, 0x1e, 0x6b, 0xe8, 0x4b, 0x12, 0x50, 0xcf, 0x9f, 0x4a, 0x33, 0xae, 0x52, 0x19, 0xed, 0x15, + 0xd1, 0xc6, 0x2c, 0xc8, 0x2b, 0xa2, 0x2f, 0x94, 0x01, 0x82, 0x24, 0xbc, 0x2f, 0x06, 0x70, 0xe0, 0xdb, 0x01, 0x4a, + 0x43, 0xe7, 0x40, 0xad, 0x54, 0x99, 0x09, 0x99, 0x4f, 0x13, 0x1c, 0x00, 0x34, 0x4f, 0x95, 0x0a, 0xca, 0x7c, 0x62, + 0x89, 0x82, 0xa1, 0xff, 0x16, 0x6e, 0x80, 0xc3, 0xd8, 0xa0, 0x62, 0x90, 0x7d, 0x4f, 0xd4, 0xf3, 0xdb, 0xe7, 0xad, + 0xa3, 0xaf, 0x41, 0xfe, 0x48, 0x79, 0x7b, 0x8f, 0xbf, 0x03, 0x4a, 0x6e, 0xc3, 0x59, 0xb5, 0xb1, 0x8f, 0x44, 0xd6, + 0x0d, 0x01, 0x72, 0xa8, 0xd1, 0x91, 0x79, 0x4a, 0xb0, 0x8b, 0xf4, 0x21, 0x69, 0xb7, 0x20, 0x7c, 0xd8, 0x0e, 0xca, + 0xf7, 0xd3, 0x06, 0x4c, 0x75, 0x72, 0xdb, 0x04, 0x5a, 0x0d, 0xaf, 0x0b, 0xdd, 0x35, 0x79, 0x72, 0x87, 0x55, 0x80, + 0x33, 0xec, 0x90, 0x35, 0xc4, 0xa1, 0x40, 0x2e, 0xec, 0xaa, 0xdd, 0x00, 0x9a, 0x8a, 0x8e, 0x7d, 0xe5, 0xce, 0x1b, + 0x47, 0x5d, 0x34, 0x93, 0xd3, 0xc3, 0xaf, 0x07, 0x07, 0xb1, 0x6c, 0x90, 0x47, 0x08, 0x2f, 0x29, 0x58, 0x31, 0x83, + 0xd7, 0x17, 0xb7, 0x4c, 0x7c, 0xaa, 0x02, 0xea, 0xb8, 0x50, 0xb5, 0x63, 0xad, 0xea, 0xac, 0xdc, 0x0d, 0x7e, 0x4c, + 0x1d, 0xd4, 0x08, 0xd2, 0xec, 0xe8, 0x3a, 0x35, 0x28, 0xd7, 0x5c, 0xb4, 0x60, 0x5b, 0x36, 0x3e, 0x52, 0xf4, 0xc3, + 0xa3, 0xe6, 0xd7, 0x60, 0xc2, 0x35, 0xd3, 0xa4, 0x47, 0x8d, 0x47, 0xe8, 0x87, 0x47, 0x81, 0x93, 0x1d, 0xaf, 0xd8, + 0x13, 0xcf, 0x8d, 0xfc, 0x64, 0xb9, 0xd2, 0x9f, 0x40, 0xb2, 0x2f, 0xc8, 0x4f, 0x80, 0xe5, 0x94, 0xfc, 0x14, 0xcb, + 0x26, 0x04, 0x1f, 0x24, 0x3f, 0xc5, 0x05, 0xfc, 0xc8, 0xc9, 0x4f, 0x31, 0x60, 0x3b, 0x9e, 0x9a, 0x1f, 0x45, 0x09, + 0x0c, 0x70, 0xec, 0x92, 0xd6, 0xbf, 0xab, 0x58, 0xad, 0xc4, 0xc1, 0x81, 0xb4, 0xbf, 0xe8, 0x65, 0x76, 0x70, 0x90, + 0x5f, 0x4c, 0xab, 0xbe, 0x99, 0xde, 0x45, 0x5f, 0x0c, 0x42, 0xe1, 0xc0, 0x34, 0x8d, 0x87, 0x33, 0xfe, 0x14, 0x52, + 0x56, 0xd3, 0x40, 0xf3, 0xb8, 0x73, 0xff, 0xec, 0x1c, 0xc3, 0xbf, 0xf7, 0x83, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, + 0xb3, 0xe6, 0x59, 0x85, 0x6c, 0x97, 0x01, 0x3e, 0x63, 0x86, 0x9a, 0xe2, 0xe0, 0x80, 0x5f, 0x04, 0xb8, 0x8c, 0x19, + 0x6a, 0x04, 0x16, 0x7b, 0x0f, 0x4b, 0x7b, 0x32, 0xc3, 0x35, 0xc1, 0xb3, 0xb2, 0xbc, 0x5f, 0x0c, 0x2e, 0xb4, 0xa3, + 0x26, 0x61, 0xf0, 0x69, 0x45, 0x5a, 0x6e, 0x93, 0x75, 0x45, 0x53, 0x5d, 0xb6, 0xbb, 0x48, 0x12, 0xd5, 0x10, 0x97, + 0x97, 0x6d, 0x0c, 0x2a, 0xf9, 0x9e, 0x22, 0x32, 0x15, 0xc4, 0x3b, 0xc8, 0x2d, 0x73, 0x99, 0x2a, 0x3c, 0xe5, 0xa9, + 0xf0, 0x72, 0xf6, 0x6b, 0x6f, 0x3d, 0x6d, 0x5c, 0x16, 0x4d, 0xcf, 0x0c, 0x8b, 0x9e, 0x2a, 0x5d, 0xed, 0x60, 0x93, + 0xaa, 0x01, 0xbc, 0xda, 0x57, 0x62, 0x1e, 0xb3, 0xfe, 0x65, 0x0c, 0xa2, 0x22, 0xab, 0x46, 0x1b, 0x32, 0xe1, 0x73, + 0x9d, 0x2a, 0x18, 0xa8, 0x29, 0x7c, 0x01, 0x64, 0x2a, 0xab, 0x0c, 0xb3, 0x7d, 0xc3, 0x50, 0x40, 0x40, 0x81, 0x4b, + 0xc2, 0x02, 0x09, 0x1e, 0x6e, 0x3f, 0x02, 0xc2, 0x51, 0x27, 0x17, 0x76, 0x72, 0x17, 0x0a, 0xba, 0x13, 0x83, 0x0b, + 0xdd, 0x45, 0xa2, 0xd1, 0x70, 0xdc, 0xf6, 0xa5, 0x30, 0x83, 0x68, 0xb6, 0x07, 0x97, 0xac, 0x8b, 0x54, 0xb3, 0x59, + 0x1a, 0x40, 0x5e, 0xb6, 0x56, 0x2b, 0x75, 0xe1, 0x1b, 0xe9, 0xf9, 0x73, 0xdc, 0xf0, 0x5d, 0x5e, 0xf0, 0xfc, 0x4d, + 0x92, 0x7e, 0x04, 0x54, 0x15, 0xf8, 0x6c, 0x39, 0x8f, 0x70, 0x64, 0x1e, 0x74, 0x83, 0xbf, 0xe6, 0x21, 0xae, 0x08, + 0x47, 0xee, 0x8d, 0xb7, 0x68, 0x50, 0x0d, 0x96, 0x67, 0x65, 0x78, 0x72, 0x9e, 0x5c, 0x03, 0xe3, 0xa0, 0xff, 0x56, + 0x68, 0x59, 0xfd, 0x4e, 0x72, 0x17, 0xa8, 0x43, 0xf9, 0x67, 0xc7, 0xdc, 0xa8, 0xd6, 0xbb, 0x5d, 0x23, 0x39, 0x8e, + 0x7c, 0x55, 0x08, 0xdf, 0xff, 0x9d, 0x77, 0x0f, 0xdb, 0xee, 0xb9, 0xed, 0x65, 0xd9, 0x03, 0x70, 0xde, 0xeb, 0x35, + 0xc2, 0xbf, 0xc9, 0x9d, 0x6f, 0xef, 0x46, 0xd7, 0x52, 0x3c, 0xa1, 0x9a, 0x46, 0x8d, 0x37, 0xc6, 0xf0, 0xcd, 0xca, + 0x59, 0xdd, 0x6f, 0x8d, 0x83, 0xfd, 0x5b, 0xdd, 0x43, 0xe8, 0x84, 0xda, 0x33, 0x41, 0x56, 0xf6, 0x35, 0x01, 0x33, + 0x64, 0x60, 0xfa, 0xb6, 0x03, 0x1e, 0x7e, 0x8c, 0x14, 0x1c, 0x7a, 0x2d, 0x9f, 0x44, 0x21, 0x26, 0x69, 0xcd, 0x8d, + 0x18, 0x52, 0x6c, 0x1f, 0xc6, 0xe5, 0x74, 0x8d, 0x42, 0xae, 0x7b, 0xac, 0xea, 0xc4, 0xb4, 0xea, 0xc6, 0x48, 0x1d, + 0x6c, 0x93, 0x05, 0x67, 0x55, 0xef, 0x46, 0x42, 0xa9, 0x5e, 0x54, 0x33, 0xaf, 0x62, 0x36, 0xdb, 0xe6, 0x99, 0x61, + 0xfb, 0xee, 0x9a, 0x02, 0x43, 0xde, 0xfd, 0x32, 0x5c, 0xd4, 0x25, 0x1c, 0xbb, 0x71, 0x00, 0x59, 0x49, 0x2e, 0x97, + 0xee, 0x4d, 0x34, 0xde, 0x97, 0x83, 0x75, 0xf9, 0x42, 0x5a, 0x80, 0x07, 0xd5, 0x48, 0x45, 0x16, 0x72, 0x06, 0xfe, + 0x79, 0xc1, 0x9a, 0x7e, 0x88, 0x7f, 0x85, 0x03, 0xbe, 0x42, 0xd2, 0xd4, 0xaa, 0x9f, 0xe0, 0xe5, 0x22, 0x50, 0x78, + 0xdb, 0xba, 0x9f, 0x64, 0xe8, 0x22, 0x5a, 0xd7, 0xa9, 0x58, 0x2f, 0xcc, 0xba, 0x62, 0xa5, 0x2c, 0x1c, 0x1c, 0x77, + 0x31, 0x5a, 0xa7, 0xce, 0x63, 0xd3, 0x3d, 0x77, 0xf4, 0x50, 0xf0, 0x99, 0x71, 0xa4, 0x7b, 0x56, 0x40, 0xfc, 0xaa, + 0x50, 0x9f, 0xf6, 0xb3, 0x0c, 0xdf, 0xf3, 0xed, 0xc3, 0x3d, 0x61, 0xc9, 0x73, 0x96, 0x6f, 0x50, 0xc3, 0x02, 0x29, + 0xa0, 0x50, 0x0a, 0x8b, 0xd5, 0x2a, 0x16, 0x26, 0xaa, 0x81, 0x0b, 0x6a, 0xeb, 0x5e, 0xaf, 0x30, 0xfa, 0x3b, 0xa8, + 0x8b, 0xbd, 0x7a, 0xc4, 0x98, 0xb0, 0xa2, 0xf0, 0xd2, 0x49, 0x65, 0x41, 0x5f, 0xbb, 0xfa, 0x10, 0xd5, 0x94, 0x7b, + 0xb1, 0xd1, 0xf7, 0xbe, 0xe3, 0x33, 0x26, 0x17, 0xf0, 0x6c, 0x10, 0x66, 0x44, 0x31, 0xed, 0xbf, 0x81, 0x82, 0xc0, + 0xdb, 0x33, 0x3c, 0xc4, 0x47, 0xe0, 0xab, 0x3c, 0xad, 0x93, 0x99, 0x7f, 0x8c, 0x22, 0x32, 0xc1, 0x22, 0xa3, 0x5e, + 0x04, 0x5e, 0x43, 0x20, 0x42, 0x11, 0x12, 0x31, 0x31, 0x8a, 0x7a, 0x91, 0x71, 0x52, 0x8a, 0xc0, 0x6a, 0x0c, 0x94, + 0xdc, 0x11, 0x9e, 0xab, 0x8a, 0x88, 0x85, 0x35, 0x75, 0x50, 0x89, 0xa5, 0xc6, 0x4c, 0xfb, 0xa8, 0x53, 0x81, 0xb0, + 0xc8, 0x36, 0x05, 0x65, 0xbd, 0xa1, 0x2e, 0xc0, 0x92, 0x18, 0xd3, 0x5b, 0x9e, 0x5c, 0x03, 0x37, 0xc7, 0x46, 0xae, + 0xe8, 0x92, 0x5f, 0x81, 0x7a, 0x3a, 0x2d, 0xf0, 0xb5, 0x61, 0xd8, 0x46, 0x29, 0x5d, 0x13, 0x8e, 0x33, 0x52, 0x24, + 0xf4, 0x16, 0xa2, 0x3a, 0xcc, 0xb8, 0x48, 0x73, 0x3c, 0xa3, 0xb7, 0xe9, 0x14, 0xcf, 0xb8, 0x78, 0x62, 0x97, 0x3d, + 0x1d, 0x41, 0x92, 0xff, 0x58, 0xac, 0x89, 0x79, 0x94, 0xea, 0x77, 0xc5, 0x8a, 0x47, 0xc0, 0xab, 0xa8, 0x18, 0x75, + 0x47, 0xc6, 0xa6, 0x9c, 0xe9, 0xca, 0x78, 0xfd, 0xb5, 0x8e, 0x29, 0xce, 0x70, 0x8e, 0x92, 0x5c, 0x62, 0xd6, 0x13, + 0xe9, 0x6b, 0x88, 0xe8, 0x9c, 0x61, 0xfb, 0xa0, 0x15, 0xbf, 0x65, 0xf9, 0x33, 0x59, 0xbc, 0x37, 0x5b, 0x3e, 0x47, + 0x50, 0x08, 0x5c, 0x54, 0x44, 0x13, 0x6e, 0xf7, 0x16, 0x3d, 0x59, 0x35, 0x45, 0x6f, 0x6d, 0x53, 0x6e, 0x88, 0x53, + 0x08, 0x85, 0x9b, 0x4c, 0x79, 0xa3, 0x8d, 0x59, 0xaf, 0xf5, 0x9d, 0x46, 0xa7, 0xa8, 0x2c, 0x89, 0x30, 0xac, 0x55, + 0x53, 0xa5, 0x92, 0x88, 0xa6, 0x72, 0x12, 0xde, 0xd2, 0x00, 0x3b, 0x55, 0x38, 0x93, 0x0b, 0xa1, 0x53, 0x19, 0xe0, + 0x0d, 0xad, 0x36, 0xd7, 0xf2, 0xd6, 0x42, 0x4c, 0xe3, 0x3b, 0xfb, 0x83, 0xe1, 0x6b, 0xa3, 0xe2, 0x7f, 0x0b, 0x86, + 0x3d, 0x2a, 0x15, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x59, 0x7e, 0xf2, 0x16, 0xc0, 0x67, 0x59, 0xc8, 0x3b, 0x48, + 0x65, 0x26, 0xf5, 0x0e, 0x52, 0x19, 0xa4, 0x1a, 0x5f, 0xee, 0x7d, 0x51, 0x29, 0x8b, 0xc2, 0x06, 0x89, 0xc2, 0xa5, + 0x3a, 0x58, 0x12, 0x91, 0x40, 0xbb, 0x46, 0x94, 0x9b, 0x71, 0x01, 0x41, 0xfd, 0xa0, 0x71, 0xfb, 0x4d, 0x6f, 0xe1, + 0xfb, 0xce, 0xe6, 0x33, 0x9f, 0x7f, 0x67, 0xf3, 0x4d, 0x47, 0x1e, 0xe3, 0xeb, 0xb7, 0x9d, 0xc6, 0x32, 0x5e, 0x3a, + 0xac, 0xfd, 0x50, 0x3e, 0xa1, 0xd2, 0x32, 0x4f, 0x55, 0x93, 0x36, 0x9e, 0x04, 0x48, 0xd9, 0xac, 0x78, 0xb8, 0x0e, + 0x6e, 0xb7, 0x0e, 0x63, 0xde, 0x24, 0x6d, 0x84, 0x0e, 0x9d, 0x70, 0x25, 0x62, 0x23, 0x39, 0x1d, 0x3e, 0x3a, 0x82, + 0xbb, 0x97, 0x99, 0xda, 0xf0, 0x95, 0xb2, 0xd5, 0x9a, 0xed, 0xd6, 0x21, 0xdf, 0x59, 0xa5, 0xd1, 0xc6, 0x33, 0x46, + 0x96, 0xe0, 0x5c, 0x46, 0x0b, 0xab, 0x6a, 0x00, 0x27, 0xce, 0x17, 0xe2, 0xb7, 0x05, 0x1d, 0x99, 0xef, 0x43, 0x9b, + 0xf2, 0x7a, 0xa1, 0x7d, 0x52, 0x93, 0xc3, 0x20, 0x3a, 0xc8, 0x95, 0x0c, 0x72, 0x62, 0x7e, 0x44, 0x92, 0x53, 0x74, + 0xd1, 0xee, 0x25, 0xa7, 0x87, 0xfc, 0x90, 0xa7, 0xc0, 0xc3, 0xc6, 0x4d, 0x5f, 0xa1, 0xd9, 0xf6, 0x75, 0x1e, 0x2f, + 0x86, 0x3c, 0x73, 0xcd, 0x57, 0x1d, 0x94, 0xa9, 0x76, 0x8e, 0x90, 0x05, 0x28, 0xe6, 0x7b, 0x09, 0xb2, 0xeb, 0xdd, + 0x1c, 0xf2, 0x14, 0xfa, 0x81, 0x5a, 0x1d, 0x5b, 0xab, 0x1c, 0xdc, 0x6f, 0x0b, 0x40, 0x30, 0xdf, 0x51, 0x6d, 0x2e, + 0x36, 0xbd, 0x19, 0x57, 0x9d, 0x1d, 0xf2, 0x6a, 0x84, 0x61, 0x99, 0xed, 0xfe, 0xfc, 0xd4, 0xaa, 0x2e, 0x0f, 0x03, + 0x88, 0xfc, 0xb6, 0xe0, 0x22, 0xec, 0x34, 0xec, 0xd6, 0xe5, 0x84, 0x9d, 0xd6, 0x67, 0x19, 0x14, 0xd9, 0xee, 0x75, + 0x6b, 0xa6, 0xf5, 0xd9, 0x5e, 0x81, 0x8f, 0x20, 0x4c, 0xca, 0xac, 0x74, 0x06, 0x57, 0xe8, 0x87, 0x1f, 0x90, 0x6b, + 0xfd, 0xf5, 0x42, 0xfb, 0xfc, 0x12, 0x11, 0x20, 0xbb, 0xea, 0xba, 0xac, 0x0e, 0x7d, 0x94, 0x4d, 0x7c, 0x3d, 0xe4, + 0xc1, 0xca, 0x3d, 0xbd, 0x9d, 0xcb, 0xd4, 0xe3, 0x6b, 0xaf, 0x95, 0x6e, 0x21, 0x27, 0x10, 0x0f, 0xd7, 0x5d, 0x58, + 0x16, 0xe4, 0xec, 0xe6, 0x16, 0x4a, 0x86, 0x13, 0xf7, 0xa5, 0x3f, 0x30, 0x7b, 0xdd, 0xc0, 0x2f, 0x92, 0x53, 0x98, + 0xfa, 0x66, 0x0f, 0x87, 0x1d, 0xe8, 0xc3, 0xc0, 0x61, 0xb3, 0x41, 0x9f, 0x59, 0x41, 0xe4, 0x31, 0x2f, 0x2c, 0x9e, + 0x5d, 0x92, 0x76, 0x8f, 0xa7, 0x6e, 0x33, 0x19, 0xd1, 0xa8, 0xdd, 0xe4, 0xc1, 0xcc, 0x00, 0xbf, 0x5c, 0xd9, 0xb0, + 0x88, 0x5f, 0xa7, 0x00, 0x4a, 0xbe, 0x58, 0xb5, 0x3e, 0x15, 0xbc, 0xea, 0x0d, 0xa7, 0x9b, 0xe9, 0x7e, 0xdd, 0xe0, + 0x76, 0xd7, 0xc3, 0x13, 0x9e, 0x40, 0xb1, 0x68, 0xed, 0x27, 0x3e, 0x01, 0x0e, 0x28, 0x69, 0xdd, 0x3f, 0x05, 0x17, + 0xca, 0x12, 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x2c, 0x1c, 0x6d, 0xc9, 0x80, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, + 0xd8, 0xc1, 0x49, 0xbb, 0xdd, 0x39, 0xc5, 0xc9, 0xc9, 0x29, 0x0c, 0xb4, 0x91, 0x9c, 0x1e, 0xce, 0x94, 0x05, 0x60, + 0x90, 0xb3, 0x76, 0xed, 0x3e, 0x82, 0x70, 0x49, 0xa1, 0x78, 0xcd, 0x0f, 0xe3, 0xb8, 0x9d, 0xdc, 0x6f, 0xb5, 0x4f, + 0xcf, 0x1b, 0x00, 0xa0, 0xa6, 0xfb, 0x70, 0x35, 0x5e, 0x2f, 0x74, 0xbd, 0x4a, 0x89, 0xf0, 0xf5, 0x6a, 0x0d, 0x5f, + 0xad, 0xd1, 0x5e, 0x57, 0x53, 0xf0, 0x55, 0x9d, 0x70, 0x6e, 0x8b, 0x78, 0xa5, 0x4d, 0xb8, 0x2d, 0x62, 0x3b, 0x90, + 0x18, 0xa4, 0xf3, 0xe4, 0xb4, 0x73, 0x8a, 0xec, 0x58, 0xb4, 0xc3, 0x8f, 0x72, 0x9f, 0x6c, 0x15, 0x69, 0x68, 0x40, + 0x92, 0x72, 0x76, 0x72, 0x01, 0x12, 0x35, 0x27, 0x97, 0xed, 0xe6, 0x8c, 0x25, 0x7e, 0x02, 0x26, 0x15, 0x96, 0xb3, + 0x5c, 0x05, 0x97, 0x14, 0x00, 0xe2, 0x02, 0x8c, 0x8b, 0xee, 0x9f, 0xf6, 0xee, 0x27, 0xa7, 0x67, 0x1d, 0x4b, 0xf4, + 0xf8, 0x45, 0xa7, 0x96, 0x66, 0xa6, 0x9e, 0x9c, 0x9a, 0x34, 0xe8, 0x3a, 0xb9, 0x7f, 0x0a, 0x65, 0x5c, 0x4a, 0x58, + 0x0a, 0xc2, 0x3c, 0x54, 0xc5, 0x20, 0xb6, 0x43, 0x5a, 0xcb, 0x3d, 0xab, 0x65, 0x9f, 0x9f, 0x1c, 0xdf, 0x3f, 0x0d, + 0xa1, 0x56, 0xce, 0xc2, 0x2c, 0xb4, 0x9b, 0x88, 0x9f, 0x1d, 0x2c, 0x2d, 0x3a, 0x4c, 0x4e, 0xd3, 0xad, 0x09, 0xda, + 0x4d, 0x73, 0x68, 0x70, 0x20, 0x50, 0x38, 0x3e, 0x15, 0x4e, 0x5f, 0x12, 0xdc, 0x8f, 0x55, 0x86, 0x26, 0xa1, 0xc2, + 0xd9, 0xdf, 0x53, 0x06, 0x2f, 0x39, 0x86, 0x57, 0x95, 0x8f, 0xa9, 0xf8, 0x42, 0xd5, 0x1b, 0x0a, 0xb1, 0x2b, 0xc4, + 0x20, 0x72, 0x91, 0xb5, 0xeb, 0xb9, 0x3f, 0x81, 0x8b, 0x30, 0x13, 0x70, 0xa1, 0xe9, 0x95, 0xa0, 0x15, 0x2f, 0x30, + 0x0c, 0x1d, 0x6a, 0xcd, 0xb0, 0x7a, 0x3c, 0x75, 0x26, 0x05, 0xa1, 0x6e, 0xeb, 0x39, 0xff, 0x5e, 0xb9, 0xa4, 0xbc, + 0xca, 0x4e, 0x4e, 0x51, 0xe2, 0x2e, 0xcb, 0x93, 0x36, 0x4a, 0x02, 0x13, 0x12, 0x77, 0x24, 0x67, 0x19, 0xe9, 0x47, + 0xb7, 0x11, 0x8e, 0xee, 0x22, 0x1c, 0x59, 0x1f, 0xe6, 0x0f, 0xe0, 0x3c, 0x1f, 0xe1, 0xc8, 0xba, 0x32, 0x47, 0x38, + 0xd2, 0x4c, 0x40, 0x48, 0xab, 0x68, 0x80, 0x73, 0x28, 0x6d, 0x3c, 0xab, 0xcb, 0xd2, 0x8f, 0xfd, 0x57, 0xe9, 0x7a, + 0x6d, 0x53, 0x02, 0x29, 0x73, 0x6a, 0x76, 0xa8, 0x7d, 0x92, 0x39, 0xa2, 0x9e, 0x59, 0x8f, 0x30, 0x08, 0x20, 0xf4, + 0xce, 0x3f, 0xe9, 0x56, 0x45, 0xc3, 0x60, 0xc7, 0xb0, 0xd2, 0xe0, 0x67, 0x1e, 0x85, 0x67, 0x58, 0x84, 0xc7, 0xc2, + 0x17, 0x06, 0xb1, 0xc2, 0xff, 0xce, 0xa5, 0x9c, 0xfb, 0xdf, 0x5a, 0x96, 0xbf, 0xe0, 0x21, 0x10, 0x67, 0xd1, 0x02, + 0x96, 0x5b, 0x36, 0xf8, 0xce, 0x90, 0xd5, 0x47, 0x70, 0x3d, 0x76, 0x01, 0xd2, 0x40, 0x22, 0xbc, 0x36, 0x02, 0x95, + 0x97, 0x0f, 0xaf, 0x6d, 0xb0, 0x1e, 0xf3, 0x09, 0xd1, 0xba, 0x20, 0x20, 0xaf, 0x84, 0x0b, 0x8d, 0x49, 0xc1, 0x94, + 0x8a, 0x6c, 0x14, 0xbb, 0x48, 0x0a, 0xff, 0x2c, 0xa1, 0x4f, 0x19, 0x8b, 0xc8, 0x74, 0x58, 0x9f, 0xad, 0x15, 0x87, + 0x73, 0x59, 0xa8, 0xd4, 0xbe, 0x51, 0xe2, 0xc1, 0x58, 0x3d, 0x55, 0x9f, 0xe6, 0xd9, 0x1a, 0xdb, 0x3b, 0xec, 0xb2, + 0x90, 0xbb, 0xd2, 0x0e, 0x4b, 0x65, 0xd9, 0xfa, 0x5b, 0x13, 0x52, 0xb5, 0x19, 0x05, 0x13, 0xad, 0x06, 0x54, 0x85, + 0xb2, 0x80, 0xc2, 0x36, 0x1c, 0x4a, 0xba, 0x2c, 0x4b, 0xa6, 0xcb, 0x72, 0x19, 0x4e, 0x5a, 0xad, 0xf5, 0x1a, 0x17, + 0xcc, 0x84, 0x65, 0xd9, 0x59, 0x02, 0xf2, 0xd5, 0x54, 0xde, 0x04, 0xb9, 0x2a, 0x2d, 0x67, 0x69, 0x96, 0x28, 0x0a, + 0x8c, 0x60, 0xa3, 0x35, 0xfe, 0xc2, 0x15, 0x07, 0x78, 0xba, 0xd9, 0x0d, 0xa5, 0xcc, 0x19, 0x85, 0xe8, 0x5d, 0x41, + 0x93, 0x6b, 0x3c, 0xe5, 0x23, 0xb6, 0xbb, 0x4d, 0x30, 0x63, 0xfe, 0xf7, 0x5a, 0xf4, 0x08, 0x64, 0xd9, 0x3d, 0x83, + 0x3a, 0xb0, 0x88, 0x2b, 0xe8, 0x20, 0x94, 0xc1, 0x47, 0x21, 0x6e, 0xe6, 0xf4, 0x4e, 0x2e, 0x34, 0xc0, 0x65, 0xa1, + 0xe5, 0x1b, 0x17, 0xeb, 0x60, 0xbf, 0x85, 0x7d, 0xd8, 0x83, 0x25, 0x84, 0x0c, 0x68, 0x61, 0x1b, 0x23, 0xa2, 0x85, + 0x87, 0x52, 0x6b, 0x39, 0x4b, 0x5b, 0xd8, 0x04, 0x6c, 0x68, 0xad, 0xcb, 0xa8, 0x5a, 0xd7, 0xe5, 0x63, 0x8e, 0xd5, + 0x26, 0x58, 0x38, 0xe9, 0x50, 0x13, 0x1d, 0xdc, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbd, 0x7e, 0xe5, 0x62, 0x26, + 0xf3, 0x31, 0xb8, 0x6c, 0x3a, 0xd5, 0xd8, 0xb5, 0x79, 0x05, 0x29, 0xae, 0x14, 0xa5, 0x56, 0x38, 0x85, 0x96, 0x5f, + 0x08, 0x9d, 0x27, 0xf6, 0xf2, 0xe2, 0x99, 0x2c, 0x66, 0xd4, 0xde, 0x18, 0xe1, 0x6b, 0xe5, 0x9e, 0x3d, 0x37, 0x2f, + 0xab, 0x54, 0x93, 0x7c, 0xb7, 0x79, 0x15, 0xb1, 0xc8, 0x8c, 0xfc, 0x0a, 0xda, 0x00, 0x53, 0xb9, 0x7c, 0xb5, 0xb6, + 0x20, 0x2e, 0xf2, 0x7c, 0x40, 0x5e, 0xde, 0x5a, 0xea, 0x12, 0x45, 0x0d, 0x6e, 0xf0, 0x93, 0x15, 0x3c, 0x0b, 0xae, + 0x0b, 0x0d, 0x7b, 0xe4, 0xc4, 0x8b, 0xa8, 0x15, 0xd5, 0x5f, 0x7d, 0x35, 0xaa, 0x04, 0x1f, 0xb5, 0x34, 0xc9, 0x25, + 0x88, 0x1e, 0xe5, 0x03, 0x73, 0x1c, 0x44, 0x13, 0x7f, 0xf7, 0x7c, 0xd9, 0xf6, 0x74, 0x36, 0xaf, 0xd4, 0x89, 0xe5, + 0x95, 0x09, 0x78, 0x38, 0xda, 0x27, 0x5c, 0x10, 0x0e, 0x12, 0x59, 0xa9, 0x3d, 0xf4, 0xb9, 0xa8, 0x1b, 0xe7, 0x17, + 0x6d, 0xd6, 0x3c, 0x59, 0xad, 0xf2, 0xcb, 0x36, 0x6b, 0x9f, 0xda, 0x07, 0xdf, 0x22, 0x95, 0x01, 0xcd, 0xe5, 0x63, + 0x9e, 0x45, 0xa0, 0x9d, 0x1d, 0x67, 0x26, 0x9c, 0x82, 0x0f, 0x51, 0x4c, 0x16, 0xba, 0xea, 0x4b, 0x82, 0x71, 0x29, + 0xb1, 0x7a, 0xfc, 0x02, 0xf5, 0xda, 0xe9, 0xb6, 0xab, 0x74, 0xb3, 0x7d, 0x18, 0x5c, 0xb8, 0x14, 0x08, 0x77, 0x20, + 0xe4, 0x01, 0xe8, 0x77, 0x97, 0x02, 0x4c, 0x83, 0x00, 0x95, 0x15, 0x88, 0xb4, 0x7c, 0xb6, 0x98, 0x3d, 0x2b, 0xa8, + 0x59, 0x86, 0x27, 0x7c, 0xc2, 0xb5, 0x4a, 0x29, 0x48, 0xb7, 0xbb, 0xd2, 0xd7, 0xbb, 0x25, 0xa8, 0xac, 0x16, 0xf9, + 0x35, 0xd1, 0x3c, 0xfb, 0xac, 0xdc, 0xc2, 0x21, 0x6c, 0x56, 0x56, 0xe0, 0x0c, 0xad, 0x71, 0x2e, 0x27, 0xb4, 0xe0, + 0x7a, 0x3a, 0xfb, 0xb7, 0x56, 0x87, 0xf5, 0xf5, 0xc0, 0x5c, 0x58, 0x01, 0x48, 0xa8, 0x18, 0xad, 0x56, 0xfc, 0xe8, + 0xfb, 0xf7, 0x49, 0xde, 0x27, 0xbc, 0x8d, 0x3b, 0xf8, 0x18, 0x9f, 0xe2, 0x76, 0x0b, 0xb7, 0x4f, 0xe1, 0xea, 0x3e, + 0xcb, 0x17, 0x23, 0xa6, 0x62, 0x78, 0xf9, 0x4b, 0x5f, 0x26, 0xe7, 0x87, 0x65, 0xbc, 0x7b, 0x5d, 0x24, 0x0e, 0x5d, + 0x82, 0xb0, 0xeb, 0x2e, 0x5e, 0x5d, 0x14, 0x85, 0xc1, 0xd2, 0xc6, 0xa1, 0xea, 0xa4, 0xd4, 0x2f, 0x5c, 0x1e, 0xf7, + 0xc0, 0x9e, 0xdb, 0xae, 0x6c, 0x13, 0xcc, 0xbe, 0xed, 0xcf, 0xb4, 0xfa, 0xd9, 0xd4, 0x25, 0x62, 0x78, 0xe8, 0x55, + 0xe8, 0x81, 0x2e, 0x49, 0xfb, 0xe0, 0x00, 0xac, 0x8e, 0x82, 0xd9, 0x70, 0x1b, 0xfd, 0x80, 0x37, 0x6b, 0x69, 0x10, + 0xac, 0x00, 0x8c, 0x3b, 0xdf, 0x70, 0xb2, 0xb4, 0xb0, 0xd5, 0x40, 0x85, 0x75, 0x11, 0x46, 0x74, 0x0b, 0x49, 0x85, + 0x11, 0xa2, 0xe1, 0x08, 0x73, 0x91, 0x4e, 0xf6, 0x5b, 0x58, 0x8e, 0xc7, 0x8a, 0x69, 0x38, 0x3a, 0x0a, 0xf6, 0x85, + 0x15, 0xca, 0x9c, 0x22, 0x43, 0x36, 0xe1, 0xe2, 0xa1, 0xfe, 0xc4, 0x0a, 0x69, 0x3e, 0x8d, 0x06, 0x23, 0x8d, 0xcc, + 0x2a, 0x46, 0x38, 0xcb, 0xf9, 0x1c, 0xaa, 0x4e, 0x0a, 0x70, 0xfa, 0x81, 0xbf, 0x7c, 0x94, 0x86, 0x6d, 0x02, 0xf9, + 0xfa, 0x60, 0x83, 0xd9, 0xe0, 0x51, 0x41, 0x6f, 0x5e, 0x8b, 0xc7, 0xb0, 0xa3, 0x1e, 0x16, 0x8c, 0x42, 0x36, 0x24, + 0xbd, 0x83, 0xa6, 0xe0, 0x03, 0xda, 0x7c, 0x69, 0x00, 0x97, 0x9e, 0x9b, 0x0f, 0x5b, 0xd1, 0x47, 0x0d, 0x4c, 0xca, + 0xb6, 0x4c, 0xa6, 0x39, 0xa5, 0xab, 0x4c, 0x1b, 0x97, 0xa9, 0x9c, 0xc2, 0x1a, 0xbb, 0xa8, 0x27, 0xe1, 0x60, 0x46, + 0x54, 0x4d, 0xd3, 0xfe, 0xc0, 0xfc, 0x7d, 0x6d, 0x4b, 0xb6, 0xb0, 0x0b, 0xb5, 0xb3, 0xc6, 0xe6, 0xc9, 0xce, 0xa0, + 0x7c, 0x1b, 0xc3, 0x3d, 0x2c, 0xbc, 0x1b, 0x59, 0x23, 0x9f, 0x27, 0x9e, 0x6c, 0x9e, 0xac, 0xd7, 0x66, 0x20, 0x2a, + 0x05, 0x3d, 0xd0, 0x5b, 0xbf, 0x6d, 0x5a, 0xb0, 0x3d, 0xca, 0xaf, 0xd3, 0x16, 0x9e, 0x71, 0x78, 0x06, 0xd3, 0xb7, + 0x77, 0xa5, 0x0b, 0xf9, 0xd9, 0x81, 0xa4, 0x15, 0xa4, 0xd8, 0xe9, 0x04, 0x9d, 0x1d, 0xe3, 0x60, 0xe4, 0x40, 0xcf, + 0xaf, 0x3e, 0x5b, 0x58, 0xfb, 0xdf, 0x6f, 0xca, 0x82, 0x39, 0x1d, 0xb2, 0xbc, 0x9c, 0x50, 0xe6, 0xcf, 0xcf, 0x37, + 0x3c, 0xa9, 0x50, 0xc1, 0xbd, 0x1f, 0x05, 0x7b, 0xda, 0x86, 0x98, 0x9c, 0xd1, 0xbf, 0xed, 0x0f, 0x1b, 0x11, 0xa8, + 0xd4, 0xb2, 0x65, 0x85, 0x54, 0xea, 0xa1, 0x4d, 0xb3, 0x47, 0x0f, 0x1c, 0x91, 0x2f, 0xa1, 0x0b, 0xe0, 0xf5, 0x47, + 0x85, 0x9c, 0x1b, 0x44, 0x70, 0xbf, 0xdd, 0xb8, 0x8d, 0xaf, 0x00, 0x78, 0x3b, 0xec, 0x55, 0xff, 0xb4, 0x80, 0xfd, + 0x8d, 0xca, 0x92, 0x7e, 0xbc, 0x1d, 0x7b, 0xfc, 0x17, 0x12, 0xe2, 0x95, 0x5b, 0x3c, 0x4c, 0x1c, 0x3a, 0x95, 0xac, + 0x59, 0xf9, 0x73, 0xab, 0x24, 0x60, 0x58, 0xbd, 0x60, 0xc8, 0xc6, 0x6d, 0x15, 0xb7, 0x99, 0xff, 0x41, 0x05, 0x83, + 0x05, 0xdf, 0x1a, 0x49, 0xc5, 0xb2, 0xf8, 0xed, 0x53, 0xe7, 0xbf, 0xea, 0x1c, 0xd7, 0xbe, 0xae, 0xbd, 0x51, 0x39, + 0x34, 0xf1, 0x81, 0x23, 0x74, 0x70, 0xb0, 0x91, 0x41, 0xc7, 0x00, 0x78, 0xe4, 0xd8, 0x2f, 0xbf, 0x7c, 0x9e, 0x1d, + 0x33, 0x9a, 0xc7, 0x22, 0x0a, 0x99, 0x3b, 0xcf, 0xcd, 0xd9, 0x89, 0x3c, 0xa1, 0x6a, 0xea, 0x0b, 0x03, 0x1c, 0x1f, + 0x6d, 0xa5, 0x02, 0xbe, 0x47, 0xeb, 0x1d, 0x13, 0xd8, 0xe0, 0xb7, 0xec, 0xa4, 0x76, 0x15, 0xf4, 0x0b, 0xb4, 0xdc, + 0xc5, 0x54, 0x6e, 0x2c, 0x70, 0xb4, 0x39, 0x91, 0x9d, 0x43, 0xdf, 0xa8, 0x53, 0xb2, 0x1e, 0x4f, 0x76, 0x1b, 0x7d, + 0x49, 0xb1, 0x2b, 0xb9, 0xa2, 0x6d, 0x43, 0x56, 0xbd, 0x53, 0xab, 0x2b, 0x53, 0xa7, 0xea, 0x9a, 0xb7, 0xb2, 0xb4, + 0x29, 0xed, 0x92, 0xec, 0xdd, 0x16, 0x0b, 0xaf, 0xc2, 0x1b, 0x8d, 0xf2, 0x22, 0x14, 0xec, 0xb1, 0xc4, 0xa0, 0xcb, + 0x09, 0x5c, 0x2f, 0xac, 0x56, 0x31, 0xfc, 0xd9, 0x35, 0x86, 0x5d, 0xa6, 0x4b, 0x1f, 0xf8, 0x06, 0xbf, 0x12, 0x84, + 0xca, 0x75, 0x76, 0x90, 0x60, 0xdd, 0xe5, 0x06, 0x0d, 0xc7, 0x89, 0xff, 0x82, 0x87, 0x9a, 0xb5, 0x77, 0x39, 0x98, + 0x64, 0xdf, 0x78, 0xdc, 0xad, 0x64, 0x2d, 0x6b, 0x71, 0xd6, 0x37, 0x24, 0x18, 0x62, 0x37, 0xa5, 0x73, 0xdc, 0x4a, + 0xda, 0x28, 0x72, 0xc5, 0x2a, 0xf4, 0xff, 0x56, 0x91, 0xcc, 0x66, 0xfe, 0xd7, 0xd9, 0xd9, 0x99, 0x4b, 0x71, 0x36, + 0x7f, 0xca, 0x78, 0xc0, 0x99, 0x04, 0xf6, 0x85, 0x67, 0xcc, 0xe8, 0x90, 0xdf, 0xc2, 0x50, 0x88, 0x20, 0x97, 0xc2, + 0xb1, 0x4b, 0xf0, 0xce, 0x20, 0x50, 0x1e, 0x60, 0xff, 0x9e, 0x6c, 0x94, 0xf3, 0x0f, 0x15, 0xf9, 0x40, 0xbe, 0x65, + 0x83, 0xec, 0x8b, 0xf9, 0xec, 0x5b, 0x33, 0x19, 0x88, 0xcd, 0x1f, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, + 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, 0x0f, 0x53, 0xd6, 0x3d, 0x72, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0xc5, + 0xa3, 0x8c, 0x7e, 0x2c, 0x43, 0x4f, 0xee, 0xbd, 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, + 0x69, 0xfe, 0x23, 0xde, 0xab, 0x42, 0x50, 0x82, 0x2b, 0xa4, 0x89, 0xe2, 0x88, 0xcd, 0x83, 0xce, 0x69, 0x24, 0x80, + 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0xa8, 0x85, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0x16, 0xa9, 0x0d, 0xe1, + 0x0d, 0x91, 0xdc, 0xca, 0xd9, 0x98, 0xaf, 0x47, 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, + 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, + 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, 0x93, 0xdb, 0x60, 0xaa, 0x7f, 0x82, 0x1d, 0x08, 0x3d, 0x53, 0x3a, + 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, + 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, + 0xcc, 0x63, 0xd2, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, + 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, 0xde, 0x72, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, + 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, 0xcc, 0xc5, 0xc3, 0xf0, 0xd1, 0x77, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, + 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0x32, 0xdd, 0xd9, 0x0d, 0xa3, 0xb5, 0x79, 0x6e, 0x29, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, + 0x04, 0xd9, 0xda, 0x3c, 0xd8, 0x54, 0x66, 0x0d, 0x59, 0xf9, 0x3a, 0x41, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, + 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, + 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x22, 0xd7, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, + 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, 0x53, 0x70, 0xed, 0x43, 0xe4, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, + 0x18, 0x5d, 0x1b, 0xc8, 0xd7, 0x9b, 0x73, 0x9a, 0xb8, 0xb3, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, + 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, + 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x03, + 0x51, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, + 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, + 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, + 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, + 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0xa7, 0x1a, 0x35, 0x62, 0x9e, + 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, + 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, + 0xaa, 0x16, 0x85, 0x79, 0xba, 0x2d, 0x56, 0x28, 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0x52, 0x9a, 0x04, 0xc3, + 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, + 0x71, 0x38, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, + 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, 0xec, 0x9e, 0xae, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, + 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0xd7, 0xb5, 0xb8, 0x4b, 0x72, 0x0f, 0x64, 0x54, 0x6f, 0x60, 0xd7, 0x2c, 0xc0, + 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, 0x69, 0x9e, 0x52, 0xa2, 0xe6, 0x05, 0x25, 0x78, 0xb8, 0x99, 0xb0, + 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x68, 0x7b, 0xff, 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, + 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, + 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x67, 0x36, 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x0f, 0x6a, + 0x54, 0x0f, 0x9a, 0xfb, 0xe7, 0x9d, 0x8e, 0x3a, 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, + 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x9e, + 0xe0, 0xa8, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, 0xe6, 0xfe, 0x65, 0xcf, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, + 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, + 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, + 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, 0x5e, 0xdd, 0x01, 0x2b, 0x01, 0x1f, 0xfd, 0xd8, 0x24, 0x19, 0x43, + 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, + 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, + 0x20, 0x7e, 0x29, 0x74, 0x62, 0x22, 0x45, 0x5f, 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, + 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0x63, 0xc8, 0xe3, 0x52, + 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x71, 0xba, 0x5f, + 0x40, 0xd4, 0x66, 0x77, 0x2c, 0x81, 0x9e, 0x7d, 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, + 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0xde, 0x53, 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, + 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, + 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, + 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, + 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, 0x6c, 0x28, 0x5b, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, + 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, + 0x6d, 0xcb, 0x21, 0x18, 0x76, 0xa4, 0x0b, 0x6e, 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, + 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, + 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xd0, + 0xe5, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, + 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, + 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, + 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, + 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, + 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, + 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, + 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, + 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, + 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, + 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, + 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, + 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, + 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0xdf, + 0xe6, 0x84, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, + 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, + 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, + 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, + 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, + 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, + 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, 0xa9, 0x3e, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, + 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, + 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, + 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, + 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, + 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, + 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, + 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0xef, 0x6a, 0x01, 0x97, + 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, + 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x0b, 0xb3, 0x9f, + 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, + 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, + 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, + 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, + 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, + 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, + 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, + 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, + 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, 0x9a, 0xce, 0x3c, 0x8a, 0x5c, 0x7b, 0xef, 0x77, 0x53, 0xb4, 0xf5, + 0xaf, 0x0f, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, + 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, + 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, + 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, + 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, + 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, + 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, + 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, + 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, + 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, + 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, + 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, + 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0x3d, 0x45, 0xb7, 0x72, 0xef, 0xf4, + 0xac, 0xcc, 0xeb, 0x4a, 0xab, 0x58, 0x0e, 0x73, 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, + 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, + 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, + 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, + 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, + 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, + 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, 0x89, 0x17, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, + 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, + 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, + 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, + 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, + 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, + 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, + 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, + 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, 0xbd, 0xbb, 0xe1, 0xbb, 0x70, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, + 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0x3c, 0x15, 0x19, + 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, + 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, + 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, 0x67, 0xf7, 0x2e, 0x61, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, + 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, + 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, + 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, + 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, + 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, 0x55, 0x31, 0xdd, 0x0f, 0xdf, 0xd3, 0x0b, 0x3e, 0xbc, 0x43, 0xda, + 0xc6, 0xa3, 0x96, 0x94, 0x50, 0xbb, 0x83, 0xf6, 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, + 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, 0xca, 0x28, 0x18, 0xc2, 0x3e, 0x60, 0x1f, 0x8b, 0x24, 0xa3, 0xd9, + 0x94, 0x81, 0xba, 0xdf, 0x16, 0xad, 0xe6, 0xf6, 0xa4, 0xee, 0x37, 0x64, 0x9c, 0x7d, 0x84, 0x71, 0xf6, 0x51, 0xe0, + 0xc5, 0x22, 0xc9, 0x1f, 0x32, 0xd6, 0x38, 0x56, 0x4d, 0x81, 0x8e, 0x3a, 0xc0, 0x9d, 0x81, 0x03, 0x0f, 0xd8, 0xa2, + 0x1c, 0x1c, 0x50, 0x67, 0x71, 0x4f, 0x1b, 0x99, 0xf7, 0xf6, 0x84, 0xda, 0x45, 0x2c, 0x70, 0xb3, 0x66, 0xa6, 0x05, + 0xad, 0x15, 0xc6, 0x79, 0x3c, 0xe0, 0x6d, 0x9e, 0xd5, 0xe2, 0x27, 0x6c, 0x58, 0x53, 0xd5, 0x6f, 0xa0, 0x39, 0xaa, + 0x05, 0xb9, 0x79, 0x62, 0xbc, 0x55, 0x49, 0x3f, 0x8a, 0x06, 0x96, 0x53, 0x21, 0x86, 0x64, 0xf4, 0x5b, 0x83, 0xe0, + 0x56, 0x7b, 0xb5, 0xe2, 0x1e, 0xf1, 0x45, 0xcd, 0x5b, 0xcd, 0xdc, 0x02, 0xd0, 0x22, 0x8e, 0xca, 0x7b, 0x93, 0x08, + 0xbc, 0x6f, 0xcb, 0x08, 0x69, 0xcb, 0xbe, 0x7d, 0x34, 0xb1, 0x54, 0x6c, 0xbe, 0xa3, 0x93, 0x41, 0x1a, 0xd9, 0x11, + 0x45, 0xf8, 0xba, 0x84, 0x24, 0x5c, 0x25, 0x5d, 0xab, 0x4c, 0xce, 0x99, 0x4a, 0x39, 0xbe, 0x2e, 0xa4, 0xd4, 0x57, + 0xf6, 0x4b, 0xe2, 0xea, 0x4e, 0x46, 0xe0, 0xeb, 0x09, 0xd3, 0xef, 0x68, 0x31, 0x61, 0xe0, 0x57, 0xe4, 0x6f, 0xc7, + 0x52, 0x4a, 0x2e, 0x9f, 0x88, 0xb8, 0x4f, 0x31, 0xbc, 0xf8, 0x39, 0xc0, 0xda, 0x84, 0x40, 0x29, 0x71, 0x11, 0x2e, + 0x88, 0xde, 0x14, 0xf2, 0xf6, 0x2e, 0x2e, 0xb0, 0x73, 0x00, 0x2c, 0x9d, 0x26, 0x01, 0xfe, 0xe5, 0x63, 0x3e, 0x56, + 0x63, 0x4e, 0x8d, 0xae, 0xdf, 0xfd, 0x4e, 0xae, 0x81, 0xde, 0x96, 0x8e, 0x82, 0xfd, 0xd6, 0x00, 0x72, 0xe1, 0x2e, + 0x0c, 0x2e, 0xbe, 0xc2, 0xda, 0xb2, 0x30, 0xde, 0x58, 0x00, 0xbd, 0xbf, 0x33, 0xb0, 0x60, 0xc3, 0x1c, 0x53, 0x78, + 0x2e, 0x75, 0xc2, 0x74, 0x10, 0x15, 0xe4, 0x49, 0xf9, 0x20, 0x66, 0xad, 0xf6, 0x5b, 0x36, 0x86, 0x3b, 0x8c, 0xe4, + 0xdb, 0x85, 0x13, 0x07, 0x1e, 0x90, 0x69, 0x32, 0xdb, 0xec, 0x1b, 0x1f, 0x79, 0xe4, 0xf5, 0x38, 0xde, 0xd5, 0x52, + 0x98, 0x6f, 0x56, 0x74, 0x8d, 0x21, 0x14, 0x45, 0xd8, 0xef, 0x17, 0x15, 0x53, 0x54, 0x19, 0xb4, 0x41, 0xc3, 0xf2, + 0x46, 0xfc, 0x02, 0x67, 0x0c, 0xad, 0x17, 0xb2, 0x77, 0x74, 0xd6, 0xe1, 0xcc, 0x61, 0xc6, 0x94, 0xc0, 0xa8, 0xb4, + 0x2c, 0xe8, 0x04, 0x1c, 0x9d, 0xab, 0x0f, 0xa2, 0xe2, 0xea, 0x58, 0x01, 0x78, 0x92, 0x29, 0xfc, 0x93, 0x6f, 0x82, + 0x75, 0xbf, 0x55, 0x33, 0x4c, 0xfd, 0x45, 0x6f, 0xbb, 0x96, 0x2f, 0x43, 0x1c, 0x69, 0x63, 0x08, 0xad, 0x73, 0x7b, + 0x07, 0x28, 0xe2, 0x82, 0x5e, 0xa4, 0x1a, 0x5f, 0xab, 0xc5, 0xd0, 0xac, 0xaf, 0x71, 0x1d, 0xd3, 0x06, 0x51, 0xac, + 0xbb, 0x26, 0xbe, 0xae, 0xde, 0x1f, 0x55, 0xa9, 0x82, 0x33, 0x48, 0x20, 0xac, 0xca, 0xcb, 0x86, 0x54, 0x92, 0x4b, + 0xd3, 0xa9, 0x34, 0x9d, 0x56, 0x08, 0xe5, 0xd2, 0x93, 0xf2, 0xfe, 0x15, 0x42, 0x18, 0x98, 0x32, 0x3b, 0xb0, 0x4a, + 0x6d, 0x61, 0x15, 0xbc, 0x7a, 0xb1, 0x81, 0x55, 0x12, 0x8e, 0xe7, 0x12, 0x8d, 0x8a, 0x0a, 0x87, 0x0c, 0xe9, 0x0b, + 0xb1, 0x08, 0x12, 0x00, 0x8b, 0xde, 0x65, 0x2e, 0xef, 0x7b, 0x38, 0x14, 0xf6, 0x24, 0x93, 0x70, 0xba, 0x09, 0xcd, + 0xe1, 0x61, 0x5a, 0xd5, 0xf3, 0x08, 0x01, 0x4b, 0xcf, 0x31, 0x3c, 0x48, 0xfc, 0xfd, 0x87, 0x50, 0x9d, 0x05, 0x79, + 0xfa, 0x2f, 0x51, 0x12, 0x1a, 0xfb, 0xcf, 0xf1, 0xd0, 0x21, 0x61, 0x38, 0xf0, 0xcd, 0x11, 0x56, 0x38, 0xb8, 0x55, + 0xc4, 0x67, 0x70, 0x87, 0x8f, 0x75, 0xe8, 0x01, 0x60, 0x09, 0xc5, 0x21, 0xc8, 0x37, 0x50, 0xcc, 0xe0, 0x80, 0x26, + 0xcb, 0xf0, 0x02, 0x17, 0xac, 0x16, 0xca, 0xfb, 0xdb, 0x96, 0x97, 0xd2, 0x6a, 0x97, 0xbc, 0xc6, 0x1c, 0xa8, 0xfc, + 0x0c, 0x2f, 0x7c, 0x85, 0x79, 0x29, 0xd9, 0x7d, 0xe1, 0x6b, 0x07, 0xf4, 0x14, 0x02, 0x46, 0xba, 0xdf, 0x6b, 0xc2, + 0x3d, 0x45, 0x2f, 0x73, 0x71, 0xd8, 0x76, 0xd0, 0xbd, 0xc0, 0x5c, 0x5d, 0x55, 0x59, 0x73, 0x30, 0x85, 0x06, 0x07, + 0x55, 0x38, 0x23, 0x30, 0x57, 0x2f, 0xca, 0x82, 0x73, 0x10, 0xef, 0x7b, 0xc2, 0xe4, 0x94, 0xd1, 0x00, 0x5e, 0x64, + 0xe5, 0xa3, 0x53, 0x3d, 0x0e, 0x2e, 0xe3, 0x86, 0x4d, 0x7c, 0x21, 0x7c, 0x2a, 0xb0, 0x92, 0xd6, 0x38, 0x34, 0xa2, + 0x23, 0x3a, 0x07, 0xb3, 0x0d, 0xa0, 0xe0, 0xee, 0x7c, 0xd8, 0x58, 0xa8, 0xe0, 0x31, 0xd8, 0xda, 0xdb, 0xcd, 0x84, + 0x38, 0x93, 0xa6, 0xe0, 0x6e, 0xdb, 0x20, 0x83, 0x37, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, + 0x84, 0x27, 0x28, 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xa2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x3a, 0x6a, 0x20, + 0x2a, 0x6a, 0xa0, 0x02, 0x6a, 0x20, 0xeb, 0xdb, 0xbf, 0x80, 0x85, 0xb0, 0x11, 0xaa, 0x44, 0x10, 0x10, 0x61, 0xae, + 0x0d, 0x1f, 0x50, 0x24, 0x21, 0xe4, 0x0d, 0xa0, 0x62, 0x4a, 0x5e, 0x82, 0xd1, 0x38, 0xbc, 0xde, 0x03, 0xee, 0x97, + 0x96, 0x61, 0xf0, 0x9c, 0x82, 0xc9, 0x7f, 0xeb, 0xf3, 0xa1, 0x7a, 0xb9, 0x3a, 0x08, 0xe1, 0x17, 0x10, 0x2b, 0xc2, + 0xf1, 0x17, 0xbf, 0x00, 0xd9, 0x54, 0x58, 0x1e, 0x1c, 0x48, 0x10, 0xf8, 0x21, 0x8a, 0x70, 0xc0, 0x33, 0xbc, 0xcc, + 0x36, 0x88, 0x9e, 0x9f, 0x95, 0xaa, 0x66, 0x25, 0x83, 0x59, 0x15, 0x9e, 0xc6, 0xd1, 0x35, 0x61, 0x20, 0xb8, 0x50, + 0xbb, 0x6f, 0x10, 0x02, 0x65, 0xcb, 0x8d, 0xa1, 0x4b, 0x4f, 0xc1, 0x7c, 0x34, 0x8e, 0xde, 0x32, 0x78, 0xd2, 0xd6, + 0x98, 0xfc, 0x33, 0x6d, 0x1e, 0xb8, 0x4f, 0xf7, 0xa2, 0x46, 0xe0, 0xa4, 0x4e, 0x51, 0xf2, 0xb7, 0xe4, 0x22, 0x8e, + 0x9a, 0x97, 0x11, 0x6a, 0xc0, 0xbf, 0x0d, 0x8e, 0xba, 0x34, 0xa1, 0xa3, 0x91, 0x0f, 0x7e, 0x93, 0x11, 0xb3, 0xc9, + 0x56, 0x2b, 0x51, 0x11, 0xf4, 0xc4, 0x6e, 0x30, 0x60, 0x25, 0x5e, 0x00, 0xfb, 0x60, 0x39, 0x58, 0xf2, 0x4e, 0xc4, + 0xca, 0x9f, 0x52, 0x18, 0xac, 0x9e, 0x33, 0x84, 0x70, 0x16, 0xc4, 0x6c, 0xfc, 0xcf, 0x67, 0x1a, 0xae, 0x9f, 0x9f, + 0xaf, 0x63, 0x44, 0xa4, 0x0f, 0x22, 0x57, 0x63, 0x47, 0x44, 0x10, 0xb6, 0x4c, 0xf7, 0x5d, 0x99, 0x1f, 0xbc, 0x75, + 0xf5, 0xc0, 0x86, 0x8b, 0x03, 0x03, 0x6a, 0x14, 0x18, 0xad, 0xe0, 0x9c, 0x94, 0x03, 0x07, 0x25, 0x84, 0x66, 0x45, + 0x3c, 0x25, 0x97, 0x10, 0x09, 0x2f, 0x43, 0x5d, 0x30, 0x2c, 0x08, 0x24, 0xa8, 0x29, 0x48, 0x50, 0x99, 0xaf, 0x3d, + 0x82, 0x59, 0xe7, 0x66, 0xb6, 0x53, 0xd4, 0x75, 0x41, 0x7e, 0x7e, 0xd1, 0xf1, 0x08, 0x58, 0xda, 0x83, 0x83, 0x02, + 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, 0xc0, 0x40, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0xda, 0x78, 0x1d, 0x18, 0x5b, + 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x3d, 0x9d, 0x6e, 0x47, 0x48, 0xec, 0x7d, 0xd4, + 0x26, 0xd0, 0x98, 0x23, 0xdd, 0xd5, 0xc6, 0xfc, 0x5a, 0xd3, 0x23, 0x56, 0x93, 0x90, 0x2e, 0x48, 0x97, 0xe7, 0xd3, + 0x9e, 0xc1, 0x15, 0xab, 0x34, 0x72, 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x17, + 0x49, 0xc9, 0x86, 0x61, 0x06, 0x61, 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0xb3, 0x7f, 0x4a, 0x1f, + 0x6c, 0xba, 0xf6, 0xe6, 0x11, 0x40, 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x36, 0x2a, 0xb3, 0xb0, 0x96, 0xb1, 0x95, + 0xdb, 0xf6, 0x18, 0x7b, 0x27, 0xb6, 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x88, 0x75, 0x6d, + 0xc8, 0x46, 0x1b, 0xda, 0x37, 0x4f, 0xc2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x39, 0x2e, 0xc1, 0x21, 0xbc, 0xf0, 0x08, + 0x7f, 0x0b, 0x2c, 0x52, 0x81, 0x19, 0x96, 0xab, 0x15, 0xd4, 0xf3, 0x78, 0x9f, 0x6d, 0x06, 0x27, 0x95, 0x1b, 0x63, + 0x97, 0x76, 0xe2, 0x71, 0xd9, 0x84, 0xc4, 0x19, 0xf4, 0xeb, 0x2b, 0xa2, 0xde, 0x7e, 0x3b, 0x7d, 0xe2, 0xdf, 0x2b, + 0x73, 0x3b, 0x10, 0x1b, 0xd6, 0x1b, 0xac, 0x3e, 0x80, 0x96, 0xbf, 0xca, 0xfc, 0x43, 0x65, 0xc1, 0x4d, 0x82, 0xda, + 0x5c, 0xc4, 0x2e, 0xeb, 0x22, 0x46, 0x6a, 0x8b, 0xbb, 0x43, 0x88, 0x7f, 0xb5, 0x15, 0xc5, 0x80, 0x27, 0x15, 0xff, + 0x1c, 0xa3, 0x2e, 0x84, 0xa2, 0xb6, 0x1e, 0x36, 0x40, 0x69, 0x97, 0xeb, 0x4a, 0x8c, 0x0c, 0x09, 0xe4, 0x5b, 0x17, + 0x5e, 0xd0, 0x9c, 0x44, 0x0a, 0xe4, 0xe4, 0x20, 0x2a, 0x69, 0xb6, 0x21, 0xcc, 0x75, 0xb7, 0x70, 0xcc, 0x5c, 0x6d, + 0xd0, 0x22, 0x7e, 0x01, 0xec, 0x0c, 0x37, 0x92, 0xa5, 0x03, 0x9f, 0xaa, 0x81, 0xcf, 0xaf, 0xb9, 0xa1, 0x28, 0x0a, + 0xf5, 0xde, 0xd9, 0x47, 0xe6, 0xe0, 0x77, 0x1a, 0x88, 0x8f, 0xd4, 0xe9, 0x48, 0x36, 0x42, 0xad, 0x39, 0x3b, 0x5e, + 0xb6, 0x19, 0x61, 0x50, 0xd8, 0xe8, 0x7d, 0x15, 0xb2, 0x8a, 0x9d, 0x9d, 0x8a, 0x60, 0x4e, 0x5f, 0x54, 0xe5, 0x9c, + 0xca, 0x2d, 0xa3, 0x5a, 0x6a, 0x1a, 0x20, 0xc2, 0x95, 0x4f, 0x24, 0xef, 0x33, 0x13, 0xfe, 0xc1, 0x60, 0x5c, 0x3d, + 0x52, 0xf8, 0xfb, 0x5d, 0xb1, 0x43, 0xb6, 0xa3, 0xc3, 0x6d, 0x04, 0xcd, 0x0b, 0x15, 0x3c, 0xe0, 0xa8, 0x64, 0x09, + 0x91, 0x22, 0x97, 0xfb, 0xaa, 0x66, 0xca, 0x76, 0x1d, 0x21, 0x84, 0xb4, 0xc7, 0x59, 0x37, 0xb4, 0x7a, 0xe8, 0x91, + 0x2a, 0xca, 0xe1, 0x16, 0xcd, 0x75, 0x01, 0x2a, 0x8c, 0x40, 0xba, 0xfc, 0xcc, 0xee, 0x52, 0x09, 0xd1, 0xcb, 0xd7, + 0x2e, 0x84, 0xb1, 0xb3, 0xb2, 0xc4, 0x85, 0x19, 0xb5, 0x0d, 0xa3, 0xeb, 0x36, 0x86, 0xb3, 0x81, 0x31, 0xd3, 0xa0, + 0xa4, 0x05, 0xa1, 0xae, 0xbb, 0xf4, 0x22, 0x33, 0x81, 0x1e, 0x73, 0x42, 0x1b, 0x0c, 0x4f, 0x89, 0x06, 0xcb, 0xa6, + 0x02, 0x2c, 0xf8, 0x96, 0x45, 0x6a, 0x6d, 0x36, 0x59, 0xfc, 0x51, 0xc7, 0xe6, 0x69, 0xbf, 0xbc, 0x62, 0x9e, 0x0b, + 0x47, 0xdd, 0x9e, 0x67, 0x3e, 0x1e, 0xdd, 0xd3, 0x37, 0x57, 0x2f, 0x5e, 0xbe, 0x7e, 0xb5, 0x5a, 0xb5, 0x59, 0xb3, + 0x7d, 0x82, 0x7f, 0xd2, 0x65, 0x3c, 0xd8, 0x32, 0x0a, 0xd0, 0xc1, 0xc1, 0x3e, 0x37, 0x2e, 0x3c, 0x9f, 0xf9, 0x1c, + 0xe2, 0x06, 0xe9, 0x01, 0xce, 0x8a, 0x32, 0x26, 0xc8, 0x6d, 0xd4, 0x8b, 0xee, 0x22, 0x50, 0x42, 0x55, 0xe4, 0xef, + 0xc3, 0xe6, 0xec, 0xf7, 0x20, 0x30, 0x11, 0xd4, 0x87, 0x08, 0x20, 0x10, 0xaf, 0x14, 0x17, 0x84, 0xf9, 0x04, 0x88, + 0xe2, 0xbd, 0x00, 0xce, 0xd4, 0x44, 0xad, 0x5a, 0xa8, 0xb8, 0x00, 0x92, 0x68, 0xc3, 0x51, 0xd2, 0x23, 0x13, 0xc0, + 0x1b, 0x82, 0x52, 0xda, 0x5f, 0xdd, 0xdc, 0xb9, 0x4b, 0xe5, 0xa8, 0xd7, 0x4a, 0x73, 0x3c, 0x75, 0x9f, 0x53, 0xf8, + 0x9c, 0x76, 0xfd, 0xe9, 0x20, 0x0e, 0x73, 0xbc, 0x20, 0xe2, 0xd0, 0x3f, 0x8b, 0xb8, 0x9c, 0x17, 0xec, 0x0b, 0x97, + 0x0b, 0x95, 0x2e, 0x6f, 0x53, 0x99, 0xdc, 0x36, 0x47, 0x87, 0x71, 0x91, 0xdc, 0x36, 0x55, 0x72, 0x8b, 0xf0, 0x5d, + 0x2a, 0x93, 0x3b, 0x9b, 0x72, 0xd7, 0x54, 0x70, 0xf3, 0x85, 0x05, 0x1c, 0x8a, 0xb6, 0x68, 0x63, 0xb1, 0x59, 0xd4, + 0xa6, 0xb8, 0xa2, 0x01, 0x06, 0xff, 0xbe, 0x63, 0xe3, 0x87, 0xe1, 0x4b, 0x70, 0x69, 0xd2, 0x44, 0x7e, 0x02, 0xe9, + 0xa7, 0x55, 0x19, 0xb8, 0x4f, 0x49, 0xab, 0x3b, 0xbd, 0x10, 0xcd, 0x76, 0xb7, 0xd1, 0x98, 0xc2, 0xde, 0xcd, 0x48, + 0xee, 0x8b, 0x4d, 0x1b, 0x26, 0xbe, 0xce, 0x7e, 0xb6, 0x5a, 0xed, 0xe7, 0xc8, 0x6c, 0xb8, 0x09, 0x8b, 0x75, 0x7f, + 0x3a, 0xc0, 0x2d, 0xfc, 0x3c, 0x43, 0x68, 0xc9, 0xfa, 0xd3, 0x01, 0x61, 0xfd, 0x69, 0xa3, 0x3d, 0xb0, 0x86, 0x76, + 0x66, 0x2b, 0xae, 0x21, 0x84, 0xe6, 0x74, 0x70, 0x64, 0x4a, 0x4a, 0x97, 0x6f, 0xbf, 0x68, 0x15, 0xd0, 0x4f, 0xd5, + 0x82, 0x97, 0x49, 0xdc, 0x81, 0xbe, 0xe8, 0x85, 0x7d, 0xba, 0xb5, 0x20, 0xc7, 0x47, 0x95, 0xab, 0x3d, 0x45, 0xd8, + 0xf4, 0xa4, 0x0e, 0x8b, 0x43, 0xd3, 0x8c, 0xeb, 0x52, 0xba, 0xef, 0x50, 0x33, 0xf2, 0xd1, 0xc1, 0x02, 0x10, 0xa4, + 0x82, 0x47, 0x56, 0xb8, 0x70, 0x4a, 0x21, 0x5c, 0x1c, 0x54, 0xb6, 0x60, 0x92, 0x93, 0x56, 0x37, 0x37, 0x96, 0xfe, + 0xb9, 0x8b, 0x68, 0x4a, 0x31, 0x25, 0x99, 0x2f, 0x99, 0x1b, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x00, + 0x8f, 0x08, 0xc4, 0x43, 0xea, 0x16, 0xc6, 0xc0, 0x2b, 0x9e, 0x36, 0x8b, 0x3e, 0x1b, 0xa0, 0xa3, 0x63, 0x4c, 0xfb, + 0x7f, 0x65, 0xf3, 0x36, 0x3c, 0x16, 0xf8, 0xd7, 0x80, 0x4c, 0x9b, 0xb2, 0x4c, 0x10, 0x90, 0x30, 0x6a, 0xca, 0x43, + 0xd8, 0x4b, 0x08, 0x67, 0xb6, 0x62, 0xd6, 0x67, 0x83, 0xe6, 0xb4, 0xac, 0xd8, 0xf1, 0x15, 0x1b, 0xb2, 0x4c, 0xb0, + 0x15, 0x1b, 0xae, 0x62, 0xf8, 0x3a, 0x83, 0x01, 0x41, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x28, 0x88, 0xe6, 0x8b, 0x15, + 0xf1, 0x9b, 0xdd, 0xde, 0xe3, 0xb7, 0xc0, 0x02, 0xad, 0xb6, 0xff, 0x77, 0xa1, 0x0c, 0xd8, 0x53, 0x16, 0x26, 0x66, + 0x6e, 0x61, 0x55, 0x74, 0x00, 0x95, 0x12, 0x61, 0x0a, 0x03, 0x99, 0xfd, 0xcc, 0x40, 0x2d, 0xd0, 0x1a, 0xe4, 0x7d, + 0x3d, 0x68, 0x66, 0x70, 0xc4, 0xc0, 0x3b, 0x34, 0x64, 0x6a, 0x8c, 0x09, 0xe3, 0x1c, 0xa6, 0x98, 0x19, 0xf0, 0x4c, + 0xd3, 0xd6, 0x5a, 0x1a, 0x59, 0xae, 0x97, 0xf7, 0xfe, 0xd1, 0xb1, 0xea, 0x17, 0xcd, 0xf6, 0x00, 0xed, 0x13, 0x62, + 0x3f, 0x06, 0xb0, 0xc9, 0x5c, 0x6a, 0xc3, 0x7c, 0x1f, 0x75, 0x52, 0xfb, 0x09, 0x7f, 0x06, 0x6b, 0xb3, 0x03, 0x40, + 0x47, 0x86, 0xcd, 0xfa, 0xcb, 0x9a, 0xca, 0xeb, 0xe3, 0xce, 0x28, 0x95, 0xbb, 0xde, 0x9d, 0x0e, 0x34, 0xc5, 0xa1, + 0xb7, 0x1e, 0x2e, 0x1f, 0xea, 0x21, 0x60, 0xc6, 0x60, 0x6e, 0x99, 0xd1, 0xf7, 0x42, 0x24, 0x17, 0x44, 0x62, 0x69, + 0xb0, 0x86, 0xc1, 0xde, 0x3a, 0x38, 0x30, 0xd5, 0x58, 0x03, 0x9e, 0x27, 0x45, 0x20, 0x18, 0xf8, 0x08, 0xca, 0x80, + 0x26, 0xca, 0xdc, 0x86, 0x93, 0x8f, 0xcc, 0xfd, 0xc2, 0xe5, 0xed, 0x63, 0xe1, 0xb4, 0xad, 0xe6, 0x7a, 0xbc, 0x2c, + 0x70, 0x57, 0xde, 0x4b, 0x5a, 0x05, 0x37, 0xb2, 0x37, 0x79, 0xca, 0xdc, 0xad, 0xfb, 0x52, 0x9d, 0xdd, 0xcd, 0x74, + 0xca, 0x66, 0x3a, 0xdb, 0xcd, 0x84, 0x9a, 0x99, 0x6f, 0x59, 0x45, 0x9a, 0x93, 0x35, 0x51, 0x73, 0x2a, 0x7e, 0xa2, + 0x73, 0xd0, 0x8e, 0x72, 0x7b, 0xaf, 0x0a, 0x27, 0x57, 0x4e, 0x2e, 0xf7, 0x73, 0x43, 0x5c, 0x91, 0xb9, 0x50, 0x87, + 0x00, 0x2f, 0x2f, 0xca, 0xc7, 0x07, 0xb8, 0x14, 0xbf, 0xca, 0x91, 0x8b, 0x72, 0x2a, 0xa4, 0x96, 0x82, 0x45, 0xc8, + 0xa0, 0xaa, 0x8b, 0x81, 0xbd, 0xb4, 0x7b, 0x4f, 0xf4, 0x78, 0xbf, 0x8a, 0x98, 0x37, 0x30, 0xcf, 0x7d, 0x7c, 0x4f, + 0x53, 0xec, 0xd4, 0xc4, 0x19, 0xf9, 0x90, 0xc5, 0x39, 0xc8, 0x66, 0xfd, 0xea, 0xb5, 0xdf, 0x46, 0x1b, 0x17, 0xcd, + 0x58, 0xf4, 0xcc, 0x13, 0x27, 0x3f, 0x14, 0xc6, 0x38, 0xc0, 0x3a, 0xfa, 0x23, 0x4c, 0x2d, 0xd8, 0xb3, 0xc4, 0x53, + 0xe8, 0xe4, 0xd6, 0xa6, 0xdd, 0x85, 0x69, 0x77, 0x26, 0xad, 0x03, 0xe5, 0x80, 0x34, 0xbb, 0x32, 0x9d, 0x3b, 0xff, + 0x7d, 0x07, 0x2f, 0xdd, 0xae, 0x21, 0x12, 0xf7, 0xfc, 0x91, 0x31, 0x86, 0x78, 0x03, 0x36, 0xa2, 0xea, 0xe0, 0xe0, + 0x0f, 0xe7, 0x7d, 0x5b, 0xc9, 0x7d, 0xdf, 0x0a, 0x07, 0xb6, 0xc1, 0x54, 0xba, 0xbc, 0x91, 0xcc, 0x16, 0x60, 0xd7, + 0xb9, 0xff, 0x8d, 0x78, 0xf8, 0x22, 0x64, 0x5a, 0xac, 0xab, 0xf8, 0x2b, 0x39, 0x2a, 0x3d, 0x44, 0x35, 0x44, 0x20, + 0xad, 0xac, 0x4b, 0x43, 0xd3, 0xd1, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x81, 0x7d, 0x91, 0x5b, 0x27, + 0xf0, 0x68, 0x61, 0x8d, 0xa1, 0xb9, 0x2b, 0xbd, 0x93, 0x6c, 0x40, 0xd4, 0xfa, 0xb8, 0x43, 0x49, 0x24, 0x16, 0xd5, + 0x5d, 0x08, 0x87, 0xbb, 0x10, 0xcc, 0xcb, 0xa0, 0x6d, 0x10, 0xbb, 0xdd, 0x05, 0x6d, 0x03, 0xa7, 0x6e, 0x1b, 0xb8, + 0x3d, 0x18, 0x2c, 0xec, 0x7d, 0x78, 0x39, 0x96, 0x63, 0xe1, 0xaf, 0xc9, 0xec, 0x03, 0x40, 0xa0, 0xf6, 0x61, 0xc5, + 0x13, 0x07, 0x82, 0xc4, 0x19, 0x8e, 0xbe, 0xe7, 0xec, 0xc6, 0x5a, 0x0e, 0xcf, 0xe6, 0x0b, 0xcd, 0x46, 0xe6, 0x8e, + 0x1a, 0x54, 0x7c, 0x75, 0x3f, 0xaf, 0x9f, 0xb2, 0x9a, 0x6e, 0xfc, 0x1e, 0x84, 0x91, 0x70, 0xca, 0x0e, 0xa3, 0x90, + 0xb0, 0xc1, 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0x6d, 0xc2, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x08, 0xdb, + 0x78, 0x63, 0x41, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x45, 0xcd, 0xa8, 0xc1, 0x52, + 0x17, 0x94, 0xd9, 0x47, 0x18, 0x57, 0x17, 0x27, 0x26, 0x4e, 0x7b, 0xa9, 0x57, 0xff, 0x2d, 0x03, 0x03, 0x7c, 0x01, + 0x5e, 0x62, 0x61, 0x74, 0xd7, 0xbe, 0x6e, 0x40, 0x7d, 0xd9, 0x60, 0x03, 0xb4, 0x5a, 0xb5, 0xca, 0x67, 0xa0, 0xdc, + 0x35, 0x97, 0xb0, 0xd7, 0x5c, 0xc2, 0x5d, 0x73, 0x09, 0x7f, 0xcd, 0x25, 0xcc, 0x35, 0x97, 0xf0, 0xd7, 0x5c, 0x1e, + 0x84, 0x9f, 0x82, 0x38, 0x8e, 0x31, 0x87, 0xb8, 0x8a, 0xda, 0x46, 0xc6, 0x83, 0x0b, 0xcf, 0x7d, 0x96, 0xa8, 0x72, + 0xf9, 0xc3, 0x18, 0x72, 0x5b, 0xb6, 0x12, 0xc6, 0x6d, 0x8a, 0x29, 0x88, 0x9c, 0x7e, 0x70, 0x50, 0xba, 0x3b, 0x83, + 0x8f, 0x7a, 0xca, 0xf1, 0xd2, 0x3a, 0xd1, 0xfe, 0x01, 0x3a, 0x79, 0xf3, 0xeb, 0x63, 0x2a, 0xd7, 0x44, 0x38, 0x93, + 0xfb, 0xfd, 0xb6, 0xa7, 0x14, 0x9f, 0x32, 0x13, 0x9e, 0x9c, 0x27, 0xda, 0x88, 0x20, 0x08, 0x51, 0xa2, 0x70, 0x46, + 0xa4, 0xdd, 0xef, 0xde, 0x15, 0xde, 0xa8, 0xa2, 0xbc, 0x59, 0xc9, 0xe3, 0x1c, 0x9c, 0xd8, 0x8d, 0x15, 0x06, 0xea, + 0x82, 0x0b, 0x41, 0x66, 0x12, 0xfe, 0x68, 0xe6, 0x96, 0x9c, 0x65, 0x65, 0xd2, 0xc7, 0x66, 0x6e, 0x08, 0x58, 0x41, + 0xf6, 0x3d, 0xcc, 0x96, 0xb7, 0x29, 0xc5, 0x77, 0x69, 0x86, 0x87, 0xf2, 0x36, 0x2d, 0x42, 0x5b, 0x10, 0x7f, 0xf1, + 0x37, 0x8e, 0x23, 0x41, 0xc1, 0xdf, 0x27, 0xe2, 0x62, 0x8f, 0x6f, 0x78, 0x01, 0x2e, 0x33, 0x63, 0x51, 0x9d, 0x32, + 0xfc, 0x0d, 0x4b, 0x78, 0x08, 0x4e, 0xa6, 0xb1, 0x22, 0xf7, 0x38, 0xb0, 0x13, 0x92, 0x80, 0xc3, 0xd5, 0xed, 0x15, + 0xff, 0x0a, 0x17, 0x5f, 0xa5, 0xb3, 0x65, 0x73, 0x28, 0x6f, 0x23, 0x5c, 0x90, 0x37, 0xf0, 0xfa, 0xd6, 0xff, 0xcb, + 0xde, 0xdb, 0x36, 0xb7, 0x6d, 0x64, 0xeb, 0xa2, 0x7f, 0x45, 0x62, 0xd9, 0x0c, 0x60, 0x36, 0x29, 0xca, 0xe7, 0xcc, + 0x54, 0x5d, 0x50, 0x6d, 0x96, 0x63, 0xc7, 0x13, 0x67, 0x22, 0xdb, 0x63, 0x79, 0x32, 0xc9, 0xb0, 0x78, 0x19, 0x08, + 0x68, 0x0a, 0x70, 0x40, 0x80, 0x01, 0x40, 0x89, 0x34, 0x89, 0xff, 0x7e, 0x6a, 0xad, 0xd5, 0xaf, 0x20, 0x28, 0x7b, + 0xf6, 0x3e, 0xfb, 0xd3, 0xbd, 0x5f, 0x6c, 0xb1, 0xd1, 0x68, 0xf4, 0x7b, 0xaf, 0x5e, 0x2f, 0xcf, 0xd3, 0x93, 0xb1, + 0xba, 0x3d, 0x70, 0xd6, 0xa5, 0x14, 0x1d, 0x6f, 0x8a, 0xc3, 0xdb, 0xf3, 0xd9, 0x7e, 0x1b, 0x44, 0x6c, 0x17, 0x64, + 0x58, 0xeb, 0xa4, 0xe1, 0x3f, 0xd1, 0xd6, 0xc1, 0x62, 0x84, 0xfd, 0x5f, 0xd6, 0x03, 0x2f, 0x21, 0x35, 0x14, 0xb8, + 0x18, 0x6c, 0x38, 0x5a, 0xdb, 0x65, 0x1a, 0xb8, 0xa9, 0x41, 0xaf, 0xef, 0x29, 0x44, 0x79, 0xc9, 0x68, 0x6e, 0x04, + 0xeb, 0xc6, 0x90, 0x8b, 0xc3, 0x71, 0xb3, 0x1c, 0xf2, 0x92, 0xa6, 0xd3, 0x20, 0x94, 0xee, 0x2c, 0x6b, 0x48, 0xa2, + 0xec, 0x83, 0x50, 0xbb, 0xb6, 0xec, 0xb7, 0x81, 0xed, 0xcb, 0x1f, 0x0d, 0x63, 0xff, 0x62, 0xf9, 0x4c, 0x48, 0x17, + 0xf1, 0x1c, 0x04, 0x51, 0xfb, 0x79, 0x36, 0xdc, 0xf8, 0x17, 0xeb, 0x67, 0x42, 0xf9, 0x8d, 0xe7, 0xb6, 0x1c, 0x52, + 0x67, 0x2d, 0x7c, 0x61, 0x3c, 0x3c, 0xb8, 0x32, 0xb4, 0x1d, 0x0e, 0x42, 0xff, 0x6d, 0xd6, 0x08, 0x6e, 0x6c, 0x68, + 0x9f, 0x2f, 0x7c, 0xd8, 0xda, 0x68, 0xac, 0x29, 0xa6, 0x5b, 0xe8, 0xdf, 0x64, 0xb6, 0xb4, 0xa7, 0x51, 0xc9, 0x8b, + 0x53, 0xd3, 0x88, 0x85, 0x30, 0x60, 0xe8, 0x27, 0xf3, 0x01, 0x54, 0x73, 0xc7, 0x23, 0x90, 0xc9, 0x07, 0x7a, 0xb0, + 0x26, 0xb5, 0xea, 0xaf, 0x61, 0x26, 0xff, 0x8f, 0x54, 0x58, 0x8c, 0xee, 0xb6, 0x61, 0xa6, 0xfe, 0x88, 0xe4, 0x1f, + 0x2c, 0xe7, 0xbb, 0xd4, 0x0b, 0xb5, 0x1f, 0x0b, 0x2b, 0x30, 0x28, 0x51, 0x35, 0xa0, 0x07, 0x22, 0xa8, 0xca, 0x20, + 0xcd, 0xb0, 0x3a, 0x07, 0xfd, 0xee, 0x69, 0xd5, 0x91, 0x1c, 0xd2, 0x5a, 0x0d, 0xa9, 0x60, 0xaa, 0xd4, 0x20, 0x3f, + 0x1c, 0xee, 0x52, 0xa6, 0xcb, 0x80, 0x4b, 0xfa, 0x5d, 0xaa, 0x94, 0xc2, 0x7f, 0x22, 0x00, 0x9d, 0x83, 0x7b, 0x7c, + 0x39, 0x06, 0xd2, 0x0c, 0x0b, 0xbf, 0x35, 0x3b, 0xbe, 0x26, 0xe1, 0x36, 0x09, 0x2e, 0x06, 0x38, 0x47, 0x57, 0x61, + 0x79, 0x97, 0x42, 0x04, 0x55, 0x09, 0xf5, 0xad, 0x4c, 0x83, 0xd2, 0x56, 0x83, 0xb0, 0x26, 0xa1, 0xce, 0x24, 0x1b, + 0x95, 0xb6, 0x1b, 0x85, 0xd9, 0x22, 0xae, 0x67, 0x84, 0x35, 0x67, 0x33, 0xd5, 0xc0, 0xa4, 0xe1, 0xb8, 0x69, 0xb4, + 0x16, 0x15, 0x6a, 0x0a, 0xf3, 0x1a, 0x57, 0x95, 0xaa, 0xee, 0xe6, 0xd4, 0x52, 0x5a, 0xb6, 0x57, 0xdd, 0x24, 0x1b, + 0x72, 0x19, 0xca, 0x30, 0xd8, 0xc8, 0x11, 0x4c, 0x20, 0x49, 0xce, 0xfc, 0x8d, 0xfc, 0x43, 0x6d, 0xba, 0x16, 0x30, + 0xc7, 0x98, 0x65, 0xc3, 0x82, 0x5e, 0x81, 0x7b, 0xa0, 0x95, 0x9e, 0x4f, 0xb3, 0x8b, 0x3c, 0x48, 0x86, 0x85, 0x5e, + 0x36, 0x19, 0xff, 0x53, 0x18, 0x69, 0x32, 0x63, 0x25, 0x8b, 0x6c, 0x57, 0xa7, 0xc4, 0x79, 0x9c, 0xc0, 0xf6, 0x68, + 0x7a, 0xcb, 0xf7, 0x19, 0x44, 0x05, 0x81, 0x82, 0x19, 0xf3, 0x65, 0x17, 0xcf, 0x7d, 0x9f, 0x59, 0xa6, 0xee, 0xc3, + 0xc1, 0x98, 0xb1, 0xfd, 0x7e, 0x3f, 0xef, 0xf7, 0xd5, 0x7c, 0xeb, 0xf7, 0x93, 0x17, 0xe6, 0x6f, 0x0f, 0x18, 0x14, + 0xe4, 0x44, 0x34, 0x15, 0x22, 0xf8, 0x87, 0xe4, 0x19, 0x92, 0xd1, 0x1d, 0xf7, 0xb9, 0xe5, 0x6c, 0x59, 0x1d, 0x81, + 0x60, 0x1e, 0x0e, 0x97, 0x0a, 0xec, 0x5a, 0xa2, 0x48, 0xc8, 0xf2, 0x9f, 0x81, 0xf1, 0xcc, 0x7d, 0x80, 0x25, 0x03, + 0x10, 0xb6, 0xca, 0xd3, 0xf5, 0x9e, 0xaf, 0x82, 0x77, 0x3a, 0xde, 0x35, 0x56, 0x64, 0x20, 0x6e, 0x81, 0x8d, 0x58, + 0x6b, 0x0f, 0xc8, 0x99, 0x02, 0x1c, 0x2f, 0x0e, 0x87, 0x73, 0xf9, 0x4b, 0x37, 0x5b, 0x27, 0x50, 0x29, 0x70, 0x7b, + 0x74, 0x72, 0xf0, 0xdf, 0x81, 0x66, 0x50, 0x0e, 0xf3, 0x7a, 0xfb, 0x3b, 0x73, 0xf2, 0xd3, 0x53, 0xfc, 0x13, 0x1e, + 0xa2, 0xd3, 0x6f, 0xf7, 0xe6, 0x0f, 0x8a, 0xca, 0xc3, 0x41, 0x2d, 0xfe, 0x73, 0xce, 0x2b, 0xf8, 0x85, 0x6f, 0x02, + 0xb3, 0xc9, 0xd4, 0x3b, 0xf9, 0x26, 0xcf, 0x99, 0x7a, 0x8d, 0x57, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xed, + 0xc8, 0x89, 0x76, 0xca, 0x31, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, + 0x96, 0x78, 0x96, 0xce, 0x2f, 0x27, 0x75, 0xb9, 0xd3, 0x8a, 0xa7, 0x3d, 0xb0, 0xb8, 0xad, 0xc1, 0x0b, 0xe0, 0xde, + 0x62, 0xeb, 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, + 0x40, 0x30, 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, + 0x77, 0xf9, 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0x65, 0x6f, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, + 0x52, 0x3c, 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfc, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xbd, 0x7d, + 0x72, 0x61, 0x20, 0x81, 0xa6, 0x03, 0xf0, 0xe3, 0x55, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, + 0x05, 0xf7, 0xe9, 0x67, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa3, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x3c, + 0xfb, 0xa6, 0x02, 0x72, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, + 0x53, 0x71, 0x75, 0xa9, 0xd3, 0xc5, 0x8b, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, + 0x07, 0xf1, 0xb6, 0xb6, 0xa3, 0x3f, 0x76, 0x10, 0xe9, 0xb8, 0x27, 0x17, 0xea, 0x4b, 0x48, 0x25, 0x17, 0xea, 0x06, + 0x62, 0x17, 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0x75, 0x8d, 0x82, 0x95, 0x80, 0x33, 0xed, 0x1a, 0x0c, 0x36, 0xb0, + 0x6e, 0x59, 0x06, 0x7f, 0xc3, 0x35, 0x4d, 0xe0, 0x86, 0x45, 0xd6, 0x7b, 0x83, 0xad, 0x74, 0x0d, 0x8e, 0x96, 0x89, + 0x73, 0x29, 0xc9, 0xca, 0x16, 0x19, 0x57, 0x8f, 0x42, 0xaa, 0xa6, 0xfb, 0x5b, 0x51, 0x3f, 0x08, 0x91, 0x07, 0xab, + 0x94, 0x45, 0xc5, 0x0a, 0x64, 0xf6, 0xe0, 0x1f, 0x21, 0x23, 0x47, 0x39, 0x70, 0x14, 0xfa, 0x5b, 0x13, 0xe8, 0x3c, + 0x3f, 0x85, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, + 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, + 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, + 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, + 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, + 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, + 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, + 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, + 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, + 0x74, 0xe9, 0x7e, 0x66, 0xc7, 0x5d, 0xe8, 0x0e, 0xb0, 0xf1, 0xb6, 0x41, 0x47, 0xfe, 0xf5, 0x0e, 0x29, 0x75, 0x93, + 0x01, 0xd8, 0x8d, 0x06, 0x38, 0x64, 0xaa, 0x97, 0x22, 0xab, 0x97, 0x32, 0xd5, 0x4b, 0xb2, 0x72, 0x09, 0x16, 0x12, + 0x53, 0xe5, 0x36, 0xb2, 0x72, 0xcb, 0x86, 0xeb, 0xe1, 0x60, 0x6b, 0xc5, 0x65, 0x73, 0x07, 0xf7, 0x85, 0x15, 0x05, + 0xfe, 0xdf, 0xb2, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x35, 0x3a, 0x26, 0xc1, 0x05, 0xe2, 0x9e, 0xdd, 0x82, 0x1d, 0x16, + 0xfe, 0x82, 0xeb, 0xe4, 0x98, 0xed, 0xf0, 0x51, 0xe8, 0x15, 0xec, 0xd6, 0x27, 0xa0, 0x5d, 0xb0, 0x35, 0x40, 0x36, + 0xb6, 0xc5, 0x47, 0x77, 0x87, 0xc3, 0xb5, 0xe7, 0xb3, 0x07, 0xfc, 0x71, 0x7e, 0x77, 0x38, 0xec, 0x3c, 0xa3, 0xde, + 0xbb, 0xe1, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xcd, 0x15, 0x8f, 0x27, 0x83, 0xc1, 0x8d, 0xbf, 0xe0, 0xf5, 0xec, 0x06, + 0xb4, 0x03, 0xe7, 0x0b, 0xa9, 0x6b, 0xf6, 0x6e, 0x79, 0xe6, 0x2d, 0x70, 0x6c, 0x6e, 0xe1, 0xe8, 0xed, 0xf7, 0xbd, + 0x3b, 0x1e, 0x79, 0xb7, 0xa4, 0x62, 0x5a, 0x71, 0xc5, 0xf1, 0xb6, 0xc5, 0xfd, 0x74, 0xc5, 0x43, 0x78, 0x84, 0x55, + 0x99, 0xde, 0x04, 0xef, 0x7d, 0xb6, 0xd2, 0x2c, 0x70, 0x0f, 0x98, 0x63, 0x4d, 0x76, 0x42, 0x33, 0xf1, 0x57, 0xd8, + 0x3f, 0x37, 0xaa, 0x7f, 0x68, 0xfe, 0x97, 0xba, 0x9f, 0xc0, 0xed, 0x8b, 0x2c, 0x48, 0xec, 0x3d, 0xbf, 0x61, 0xf7, + 0xdc, 0xb0, 0xcd, 0x9e, 0x99, 0xb2, 0x4f, 0x94, 0x1a, 0x3f, 0x52, 0xea, 0xda, 0x32, 0xac, 0x64, 0xee, 0xbe, 0x8c, + 0xc0, 0xe1, 0x80, 0xfc, 0x74, 0x87, 0x38, 0x08, 0xad, 0x9b, 0xac, 0xe6, 0x8a, 0x72, 0x2e, 0xb4, 0x65, 0xe6, 0xe5, + 0xc0, 0x62, 0x96, 0x52, 0x68, 0x2c, 0x00, 0x10, 0x4c, 0x0a, 0xad, 0xbd, 0x97, 0x01, 0xe4, 0x04, 0x0d, 0x7f, 0x6c, + 0xae, 0x8a, 0xb2, 0x96, 0x2d, 0x09, 0x51, 0xb6, 0xeb, 0xe1, 0x25, 0x42, 0xa6, 0xf5, 0xfb, 0xe7, 0x44, 0xb2, 0x36, + 0xa9, 0xae, 0x6a, 0xb4, 0x04, 0x54, 0x64, 0x09, 0x98, 0xf8, 0x95, 0xe6, 0x13, 0x80, 0x27, 0x1d, 0x0f, 0xaa, 0xa7, + 0xbc, 0x66, 0x82, 0xc8, 0x36, 0x2a, 0x7f, 0x52, 0xbc, 0x40, 0x32, 0x82, 0xe2, 0x69, 0xad, 0x32, 0x16, 0x86, 0x79, + 0xa0, 0x80, 0xbc, 0x7b, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, + 0xe8, 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x39, 0x89, 0xae, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, + 0x67, 0xd1, 0xd3, 0x6a, 0x3e, 0x21, 0x25, 0xd9, 0xe1, 0x90, 0x8d, 0xaa, 0xba, 0x58, 0x4f, 0x43, 0xf9, 0xd3, 0x43, + 0xf0, 0xf5, 0x82, 0x7a, 0x4d, 0x56, 0xa9, 0x7e, 0x4a, 0x95, 0xf2, 0xa2, 0xe1, 0xa5, 0xff, 0xb4, 0x92, 0xfb, 0x1e, + 0x90, 0xd6, 0xf2, 0x92, 0xcb, 0xf7, 0x23, 0xc4, 0x18, 0xf1, 0x03, 0xaf, 0xe4, 0x11, 0x0b, 0xd5, 0x14, 0xae, 0x79, + 0x84, 0x20, 0x6f, 0x99, 0x0e, 0xfe, 0xd6, 0x13, 0xa7, 0xfb, 0x13, 0xa5, 0x5d, 0x7c, 0x61, 0x51, 0xf7, 0x64, 0x6d, + 0xdd, 0x80, 0x1c, 0x6c, 0x98, 0x2e, 0x0a, 0xb2, 0x4d, 0x69, 0x04, 0x6d, 0xb4, 0x1c, 0xd8, 0x70, 0x2a, 0xb5, 0xe1, + 0xcc, 0x35, 0x04, 0xf7, 0xf9, 0x79, 0x3a, 0x5a, 0xc0, 0x87, 0x54, 0xb7, 0x97, 0xf8, 0xf9, 0xb0, 0xe1, 0x11, 0x90, + 0xd9, 0x11, 0x9f, 0xd9, 0x44, 0xd2, 0x49, 0x9d, 0x2b, 0x60, 0xb7, 0xb3, 0x6b, 0x90, 0x23, 0x66, 0xee, 0x2b, 0x54, + 0xdf, 0xa2, 0x01, 0x57, 0xc6, 0xda, 0xd7, 0x24, 0x63, 0xe1, 0x55, 0x39, 0x0d, 0x07, 0x00, 0x43, 0x97, 0xd1, 0xd7, + 0x96, 0x9b, 0x2c, 0xfb, 0xb9, 0x80, 0x20, 0x88, 0x92, 0x78, 0x7c, 0xc0, 0xfb, 0xb2, 0x1a, 0x6a, 0x94, 0x7c, 0x2c, + 0x1b, 0xa9, 0xf4, 0x4a, 0xf4, 0x77, 0x63, 0x2e, 0x31, 0xe0, 0x75, 0xd5, 0x16, 0x14, 0xce, 0xf3, 0xc3, 0xe1, 0x3c, + 0x1f, 0x19, 0xcf, 0x32, 0x50, 0xad, 0x4c, 0xeb, 0x20, 0x36, 0xf3, 0xc5, 0xc2, 0x5f, 0xec, 0x9c, 0x44, 0x44, 0x41, + 0x60, 0x47, 0xc2, 0x83, 0x48, 0xfd, 0xaa, 0xf2, 0x74, 0xa7, 0xfa, 0x6c, 0xbf, 0xb0, 0x89, 0xf4, 0x82, 0x92, 0xc9, + 0x27, 0xc1, 0x5e, 0xf5, 0x77, 0x10, 0x36, 0x84, 0x37, 0xaf, 0x7a, 0x9d, 0x65, 0x6a, 0x56, 0x82, 0x84, 0x19, 0x73, + 0x04, 0x8f, 0xc3, 0x4e, 0x63, 0x1b, 0x1e, 0x5b, 0x70, 0x74, 0xde, 0x9a, 0xdd, 0xb1, 0x15, 0xbb, 0x55, 0x75, 0x5a, + 0xf0, 0x70, 0x3a, 0xbc, 0x0c, 0x70, 0xf5, 0xad, 0xcf, 0x39, 0xbf, 0xa3, 0x13, 0x6c, 0x3d, 0xe0, 0xd1, 0x44, 0xcc, + 0xd6, 0x4f, 0x23, 0xb5, 0x78, 0xd6, 0x43, 0xbe, 0xa0, 0xf5, 0x27, 0x66, 0x77, 0x26, 0xf9, 0x6e, 0xc0, 0x17, 0x93, + 0xf5, 0xd3, 0x08, 0x5e, 0x7d, 0x0a, 0x56, 0x8c, 0xcc, 0x99, 0x65, 0xeb, 0xa7, 0x11, 0x8e, 0xd9, 0xdd, 0xd3, 0x88, + 0x46, 0x6d, 0x25, 0xf7, 0xa5, 0xdb, 0x06, 0x84, 0x95, 0x5b, 0x16, 0xc3, 0x6b, 0x20, 0x9e, 0x69, 0x23, 0xe9, 0x5a, + 0x1a, 0x7a, 0x63, 0x1e, 0x4e, 0xe3, 0x60, 0x4d, 0xad, 0x90, 0x67, 0x86, 0x98, 0xc5, 0x4f, 0xa3, 0x39, 0x5b, 0x61, + 0x45, 0x36, 0x3c, 0x1e, 0x5c, 0x4e, 0x36, 0x57, 0x7c, 0x0d, 0xe4, 0x67, 0x93, 0x8d, 0xd9, 0xa2, 0x6e, 0xb9, 0x98, + 0x6d, 0x9e, 0x46, 0xf3, 0xc9, 0x0a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x0d, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, + 0x3d, 0xb6, 0x1e, 0x07, 0x77, 0x6c, 0x7d, 0x19, 0xdc, 0xb2, 0xf5, 0x18, 0x88, 0x38, 0xa8, 0xdf, 0xbd, 0x0d, 0x2c, + 0xbe, 0x88, 0xad, 0x2f, 0x4d, 0xda, 0xe6, 0x69, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xc9, 0xbc, 0x15, 0x83, + 0x4b, 0xc8, 0xd2, 0x8b, 0xd9, 0x66, 0x78, 0xc9, 0xd6, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0xee, 0xf8, 0x2d, 0x4b, 0xf8, + 0xaa, 0x89, 0xaf, 0x36, 0xa0, 0x11, 0x3d, 0xca, 0xa0, 0xaf, 0xa0, 0x66, 0xe6, 0xbc, 0xb2, 0x30, 0x2a, 0xf7, 0x2d, + 0x38, 0xa0, 0x20, 0x6d, 0x03, 0x04, 0x49, 0x3c, 0xbb, 0x57, 0xe1, 0xfa, 0x46, 0x0a, 0x03, 0x6e, 0x02, 0x33, 0x60, + 0x60, 0xfa, 0x19, 0xfc, 0xb0, 0xd2, 0x25, 0x42, 0x9c, 0xfd, 0x94, 0x92, 0x64, 0x9e, 0x9f, 0x8a, 0x34, 0x77, 0x0b, + 0xd7, 0x29, 0xcc, 0x8a, 0x02, 0xd5, 0x4f, 0x49, 0x69, 0x60, 0xa1, 0x12, 0x99, 0x4a, 0xc1, 0x2f, 0x9b, 0xf3, 0x28, + 0x3b, 0x46, 0xe7, 0x3a, 0xbf, 0x9c, 0x38, 0xa7, 0x93, 0xbe, 0xff, 0xc0, 0x31, 0x6c, 0x21, 0x03, 0x17, 0xfe, 0xd4, + 0x13, 0xc6, 0xa9, 0x15, 0x88, 0xa9, 0xe4, 0xd9, 0x53, 0xf8, 0x4c, 0x68, 0x75, 0x74, 0xe1, 0xfb, 0x41, 0xa1, 0x4d, + 0xd2, 0x2d, 0x48, 0x52, 0xf0, 0x14, 0x3d, 0xe7, 0xbc, 0x0d, 0x54, 0x8a, 0x11, 0x2d, 0x88, 0xb4, 0xb5, 0xcc, 0x1c, + 0xa4, 0x2d, 0xcd, 0x77, 0x4d, 0xfc, 0x1c, 0x16, 0x70, 0x11, 0x2d, 0x6c, 0x0d, 0x8f, 0xaa, 0x58, 0xb9, 0x37, 0x79, + 0x8e, 0x70, 0x46, 0x97, 0x32, 0x01, 0x70, 0xbd, 0x5f, 0x87, 0xb5, 0xc2, 0x2b, 0x6a, 0x16, 0x79, 0x51, 0xd3, 0x27, + 0x5b, 0xe0, 0x3e, 0x16, 0x25, 0x0a, 0x9c, 0xb5, 0x60, 0xc0, 0x56, 0x58, 0xb2, 0x93, 0xc2, 0xa6, 0x68, 0x09, 0xbd, + 0x3d, 0x7e, 0x3a, 0xa8, 0x99, 0x0c, 0xa0, 0x09, 0xa0, 0xf1, 0xf8, 0x17, 0x80, 0x9a, 0xde, 0xd4, 0x62, 0x5d, 0x05, + 0xa5, 0x52, 0x6e, 0xc2, 0xcf, 0xc0, 0x30, 0xc3, 0x0f, 0x85, 0xdc, 0x26, 0x4a, 0xe4, 0xfc, 0x58, 0x94, 0x62, 0x59, + 0x8a, 0x2a, 0x69, 0x37, 0x14, 0x3c, 0x22, 0xdc, 0x06, 0x8d, 0x99, 0xdb, 0x13, 0x5d, 0xb4, 0x22, 0x94, 0x63, 0xb3, + 0x8e, 0x91, 0x46, 0x99, 0x9d, 0xec, 0x3a, 0x59, 0x68, 0xbf, 0xaf, 0x72, 0xc8, 0x3a, 0x60, 0x8d, 0xe4, 0xeb, 0x35, + 0x87, 0x6e, 0x1b, 0xe5, 0xc5, 0x83, 0xe7, 0x2b, 0x38, 0xcd, 0xf1, 0xc4, 0xee, 0x7a, 0xdd, 0x29, 0x12, 0xf1, 0x0a, + 0x27, 0x55, 0x3e, 0x92, 0x85, 0xe3, 0xce, 0x9d, 0xd6, 0x62, 0x55, 0xb9, 0xac, 0xa7, 0x16, 0x47, 0x04, 0x3e, 0x95, + 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, 0x11, + 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0x8b, 0x5c, 0x0f, + 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, 0x3c, + 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, 0x5d, + 0x28, 0xe7, 0x4c, 0xc5, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, 0x8c, + 0x8e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x96, 0xab, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, 0xc6, + 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, 0x98, + 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x7b, 0x59, 0x14, 0x38, 0x80, 0xab, + 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0xf6, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, 0xcc, + 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, 0xb4, + 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x8f, 0x5f, 0xa7, + 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7e, 0x41, 0x11, 0x17, 0x35, 0xb8, 0xf2, + 0x4e, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, 0x0e, + 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x44, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xcc, 0x59, 0x35, 0x5a, 0xa8, 0xcc, 0x08, + 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xe3, 0x3d, 0xba, 0xab, 0xce, 0x32, + 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, 0x77, + 0x9d, 0xe5, 0xab, 0x9b, 0xad, 0xa1, 0xa8, 0xd4, 0x4a, 0x52, 0x1c, 0x64, 0xb8, 0x6e, 0x2b, 0x1f, 0x2e, 0x2e, 0xa0, + 0x67, 0x8c, 0x44, 0xe6, 0xf9, 0x13, 0xf9, 0x12, 0x9c, 0x33, 0xce, 0x0a, 0x81, 0x09, 0x63, 0xf5, 0xae, 0xb5, 0x54, + 0x1a, 0x52, 0x8c, 0x1d, 0x8d, 0xb2, 0xac, 0xb2, 0x74, 0x99, 0xad, 0x25, 0x6c, 0x59, 0x4e, 0x6e, 0x61, 0xcb, 0x4c, + 0x56, 0xf3, 0x7d, 0xc5, 0x1d, 0x94, 0x6f, 0xb6, 0xce, 0xf8, 0x5e, 0x22, 0x7b, 0xb7, 0x81, 0x12, 0x5e, 0x8c, 0xfe, + 0x82, 0xf4, 0xdb, 0x0c, 0xe3, 0x94, 0xdb, 0x4a, 0x5a, 0x80, 0xd3, 0x3f, 0x1c, 0xde, 0x57, 0x18, 0x34, 0x38, 0xc2, + 0x38, 0xb2, 0x7e, 0xff, 0xb6, 0xf2, 0x6a, 0x4c, 0xd4, 0xf1, 0x59, 0xfd, 0x7e, 0x45, 0x0f, 0xa7, 0xd5, 0x68, 0x95, + 0x6e, 0x91, 0x9d, 0xd0, 0xc6, 0xca, 0x0f, 0x6a, 0x05, 0xcc, 0xde, 0xfa, 0x7c, 0x3a, 0x00, 0x1d, 0x0b, 0x90, 0x68, + 0x36, 0x13, 0x89, 0x39, 0xe9, 0x9e, 0x84, 0xc7, 0x07, 0x16, 0x38, 0xc0, 0x54, 0xfc, 0x9f, 0xc2, 0x9b, 0x81, 0x0d, + 0x1a, 0x25, 0xfa, 0x1a, 0x5d, 0xd5, 0xe6, 0x46, 0xc7, 0x4b, 0x4f, 0x21, 0x91, 0x15, 0xac, 0x9a, 0xfb, 0x72, 0x03, + 0xa7, 0x3d, 0xd4, 0x1c, 0x2a, 0x4b, 0xf0, 0xb7, 0x5f, 0xe6, 0x87, 0xc3, 0x3a, 0x83, 0xc2, 0x76, 0x6b, 0xa1, 0xbd, + 0x31, 0x4b, 0x35, 0x54, 0x84, 0x83, 0xce, 0x57, 0x62, 0x56, 0x8f, 0xe8, 0xef, 0xf9, 0xe1, 0xb0, 0x22, 0x30, 0xe0, + 0xb0, 0x94, 0x99, 0x68, 0xa1, 0x58, 0x5a, 0x67, 0x33, 0xaa, 0x03, 0x0f, 0x4c, 0xcc, 0x59, 0xb8, 0x03, 0xd0, 0x26, + 0xb5, 0x0a, 0xf4, 0x2a, 0xa2, 0x9f, 0xb8, 0x5f, 0xdb, 0xaf, 0xd7, 0x23, 0xb3, 0x74, 0xe4, 0xc6, 0x58, 0x00, 0x70, + 0xe0, 0x79, 0x4d, 0xf2, 0x9c, 0x7c, 0x0d, 0xed, 0x9e, 0x5c, 0xc8, 0x9f, 0xa0, 0x6c, 0xe1, 0xb9, 0x6a, 0x5a, 0x59, + 0xac, 0xb8, 0xaa, 0x5e, 0x5d, 0xf0, 0xca, 0x64, 0x5a, 0xa5, 0x95, 0xa8, 0x94, 0x60, 0x40, 0x5d, 0xe2, 0xb5, 0xa6, + 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x7e, 0x69, 0x1c, 0x3e, + 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0x2b, 0x1f, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, 0xc5, 0xc4, + 0xee, 0xd0, 0xbc, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, 0x01, 0x2f, + 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x2a, 0x26, 0xc0, 0x0f, + 0x4a, 0xad, 0xe9, 0xbd, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, 0xe7, 0xe3, + 0xf9, 0xa5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x79, 0xab, 0x7f, 0x98, 0xea, 0x5b, 0xe8, 0x4e, + 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, 0x1c, 0xec, + 0x0d, 0x70, 0xe2, 0x97, 0x87, 0x83, 0xb8, 0xca, 0x7d, 0x76, 0xde, 0x35, 0xb2, 0x72, 0x00, 0x2b, 0x88, 0x82, 0x71, + 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xd5, 0xf8, 0xf8, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0xe4, 0x4f, 0x9f, + 0x03, 0x69, 0x59, 0xbf, 0x1f, 0xbd, 0xb8, 0x9c, 0x3e, 0x1f, 0x46, 0x01, 0x38, 0x76, 0xd9, 0xcb, 0xcb, 0x98, 0xaf, + 0x2e, 0x99, 0x65, 0x0a, 0x8b, 0x7c, 0x33, 0xa0, 0xba, 0x64, 0xb5, 0x74, 0xbd, 0x02, 0x2c, 0x5d, 0x7e, 0xf3, 0x10, + 0xa6, 0x06, 0x34, 0xb2, 0xe6, 0xee, 0x34, 0xd7, 0x02, 0xa5, 0x9e, 0xf7, 0x33, 0x43, 0xbe, 0x2e, 0x83, 0xae, 0x20, + 0xdd, 0xf3, 0x88, 0xf4, 0x72, 0x2f, 0x9d, 0xee, 0xf7, 0xa5, 0x00, 0x4b, 0x7d, 0x29, 0x3e, 0x83, 0xc2, 0xa2, 0xf1, + 0x8d, 0x00, 0x6d, 0x0d, 0xd5, 0xb4, 0x57, 0x8a, 0xaa, 0x17, 0xf4, 0x4a, 0xf1, 0xb9, 0xa7, 0x87, 0xca, 0x7c, 0x59, + 0x3a, 0xfa, 0x9f, 0x50, 0x73, 0xc1, 0x09, 0x31, 0x13, 0x73, 0x00, 0x95, 0xa0, 0x8d, 0x6f, 0x75, 0xb4, 0xf1, 0xa9, + 0x5e, 0xc5, 0x4d, 0x9f, 0xd7, 0xd6, 0x32, 0x27, 0x84, 0x4d, 0xf7, 0x12, 0xa0, 0x22, 0xaf, 0x84, 0x47, 0xb0, 0xfc, + 0xf2, 0x87, 0x3c, 0x5d, 0x21, 0x5a, 0xc7, 0x3d, 0xcb, 0x5c, 0x1a, 0xfb, 0x37, 0x06, 0xd3, 0xd7, 0xb7, 0xdb, 0x22, + 0x3f, 0x35, 0x31, 0x61, 0x3d, 0x56, 0xf4, 0xcd, 0xbb, 0x70, 0x25, 0x50, 0xe0, 0x50, 0x22, 0xb1, 0x4d, 0x15, 0x8a, + 0x78, 0x90, 0xf4, 0xe9, 0xa2, 0xf5, 0x69, 0x80, 0xa9, 0xb5, 0x1c, 0x98, 0x43, 0xb8, 0x8a, 0x0b, 0x1f, 0x3d, 0x7d, + 0x8b, 0x59, 0x38, 0x9f, 0x78, 0x1f, 0xbd, 0x62, 0x64, 0x3e, 0xee, 0xa3, 0x52, 0x49, 0xff, 0x3c, 0x1c, 0x66, 0xd5, + 0xdc, 0x77, 0xe8, 0x23, 0x3d, 0x54, 0xb9, 0xa0, 0xec, 0x8d, 0x31, 0x89, 0x40, 0x69, 0x8c, 0xf7, 0x71, 0x70, 0x9c, + 0xf7, 0x69, 0x00, 0xa9, 0x7d, 0xe2, 0x3d, 0x29, 0x39, 0x3c, 0xe7, 0x98, 0x13, 0x4a, 0x2b, 0xc2, 0x2a, 0xbe, 0xc8, + 0x50, 0xae, 0x3b, 0xa5, 0x60, 0x92, 0x43, 0x82, 0xe1, 0xaf, 0x9a, 0x37, 0xb1, 0x02, 0x61, 0xd7, 0xcc, 0xab, 0xd1, + 0x93, 0x2a, 0x09, 0x4b, 0x01, 0x47, 0x65, 0xe6, 0x19, 0xf6, 0x86, 0x27, 0x86, 0x91, 0x83, 0xe5, 0xfe, 0xa8, 0x4e, + 0x44, 0xee, 0xd1, 0x05, 0x46, 0x65, 0xe1, 0x79, 0x43, 0x57, 0x1a, 0x54, 0x92, 0x1d, 0x7f, 0xc5, 0x35, 0xa0, 0xb6, + 0xc6, 0x88, 0xa1, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, 0x95, 0xdc, 0xf5, + 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, 0x2c, 0x85, 0x23, + 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, 0x42, 0x9a, 0x6c, + 0x5f, 0xcf, 0xdf, 0x1b, 0x41, 0x56, 0x6e, 0x39, 0xc7, 0xc3, 0xe2, 0x1b, 0x67, 0x5f, 0xe5, 0xe4, 0x29, 0x66, 0x19, + 0xe9, 0x9d, 0x62, 0x5e, 0xc0, 0x9f, 0xca, 0x52, 0x9f, 0xa3, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, 0x97, 0xde, 0xa6, + 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0xf7, 0xf1, 0x48, 0x9e, 0x61, 0x1b, 0x96, 0xb0, 0xd0, 0x2a, 0x18, 0x03, 0x48, + 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x0e, 0x87, 0xf3, 0x8d, 0x39, 0x4b, 0xf6, 0xe0, 0xfa, 0xca, 0x13, 0xf3, 0x0e, + 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x1b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, 0x62, 0xad, 0x63, + 0xa9, 0xac, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0xbf, 0x77, 0x83, 0xab, 0x6b, 0x63, 0x50, + 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0xb3, 0x9c, 0x7c, 0xf9, 0xad, 0x9d, 0x03, 0x82, + 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, 0x33, 0xd8, 0xc4, + 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, 0xab, 0x85, 0x48, + 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, 0x5e, 0x27, 0x68, + 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, 0x7b, 0x99, 0x13, + 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, 0x74, 0x28, 0x59, + 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, 0x0a, 0x5c, 0x08, + 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xf9, 0xb4, 0x90, 0xa6, 0x81, 0x7c, 0x5a, 0x39, 0xe6, + 0x81, 0x9d, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0xe5, 0x1c, 0xab, 0x88, 0xde, 0xe7, 0x1f, 0x2a, 0x7b, + 0xfa, 0x20, 0xc2, 0x46, 0x05, 0x1a, 0x4b, 0x89, 0xb1, 0x91, 0xe3, 0xdf, 0x12, 0x65, 0x43, 0x86, 0x80, 0x10, 0xd2, + 0x46, 0x4e, 0x3f, 0xac, 0x2f, 0x6f, 0x33, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, 0xa9, 0x47, 0x3c, + 0x5e, 0x6b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, 0x28, 0x17, 0x3c, + 0xe7, 0x15, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xc8, 0xe9, 0xf3, 0x15, 0xf0, 0x4c, 0x40, 0xa0, 0x63, + 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0x37, 0x48, 0x94, 0xfa, 0x9a, + 0x94, 0xa4, 0xd7, 0xa2, 0xc6, 0x2b, 0xb1, 0x8a, 0x48, 0x20, 0x43, 0x0d, 0x11, 0xab, 0xea, 0xa9, 0x7b, 0x55, 0x4c, + 0x06, 0x83, 0xca, 0x97, 0xd3, 0x13, 0x6f, 0x68, 0xa8, 0xbc, 0xeb, 0x8a, 0x76, 0x7a, 0xa2, 0x95, 0xf2, 0x16, 0xd2, + 0x12, 0x34, 0x0d, 0x23, 0xcd, 0xa1, 0xd4, 0x95, 0x74, 0x37, 0x06, 0xf1, 0x25, 0x13, 0x3d, 0xdb, 0xa9, 0x1d, 0xa5, + 0x2d, 0x69, 0x0f, 0x21, 0x3d, 0x77, 0xc9, 0xc7, 0x2c, 0xe4, 0xea, 0x4e, 0x39, 0x29, 0xaf, 0x42, 0x74, 0x72, 0xdf, + 0x63, 0x48, 0x04, 0xfa, 0x9c, 0x63, 0x58, 0x17, 0x0d, 0x75, 0x0e, 0x2b, 0xc4, 0x6c, 0xa1, 0x84, 0xf9, 0x92, 0xf1, + 0x54, 0x32, 0x68, 0x00, 0x64, 0xc0, 0x67, 0x2f, 0x03, 0xcb, 0x5f, 0x41, 0xfc, 0x68, 0xe3, 0xc3, 0xe1, 0xcf, 0x9a, + 0x42, 0x6c, 0xff, 0x84, 0xcd, 0x10, 0x1e, 0xd5, 0x03, 0x9e, 0xf9, 0x26, 0x4e, 0xd0, 0x0a, 0x48, 0xca, 0xec, 0x68, + 0x22, 0x7b, 0xd5, 0x43, 0x38, 0x95, 0x15, 0xa8, 0xa3, 0xac, 0xb3, 0x12, 0x7e, 0x84, 0xa9, 0x6e, 0x25, 0xd6, 0x02, + 0x6d, 0xae, 0x56, 0xac, 0x05, 0x70, 0xe0, 0xe7, 0x10, 0x3c, 0x91, 0xcf, 0xc1, 0xc5, 0xa0, 0x00, 0x9f, 0x03, 0xe0, + 0x45, 0xee, 0xc2, 0x83, 0x79, 0x64, 0x59, 0x8d, 0x30, 0x1c, 0x55, 0xc4, 0xfa, 0x35, 0xdb, 0x91, 0x0f, 0xdc, 0x8e, + 0xf1, 0xb9, 0xf6, 0x58, 0xb2, 0x1c, 0x8c, 0x32, 0xf7, 0x6a, 0x89, 0x9e, 0x37, 0x69, 0xdc, 0x8c, 0x9e, 0xec, 0x6b, + 0xf9, 0xbf, 0xa0, 0x97, 0x41, 0x7f, 0x0b, 0xb7, 0xbc, 0xe6, 0x77, 0x0b, 0x22, 0xcd, 0xf4, 0x0a, 0x22, 0x65, 0xd4, + 0x88, 0x8c, 0x21, 0x6c, 0x52, 0xdd, 0xdc, 0x26, 0xd5, 0x85, 0x80, 0xa7, 0x23, 0x52, 0x5d, 0x0b, 0x69, 0x23, 0x9f, + 0xd6, 0x81, 0x8c, 0x45, 0x7a, 0xf7, 0xc3, 0xdf, 0x5e, 0x7e, 0x7a, 0xfb, 0xcb, 0x0f, 0x8b, 0xb7, 0xef, 0xde, 0xbc, + 0x7d, 0xf7, 0xf6, 0xd3, 0x6f, 0x04, 0xe1, 0x31, 0x15, 0x2a, 0xc3, 0x87, 0xf7, 0x37, 0x6f, 0x9d, 0x0c, 0xb6, 0x37, + 0x43, 0xd6, 0xbe, 0x91, 0x83, 0x21, 0x10, 0xd9, 0x20, 0x64, 0x90, 0x9d, 0xda, 0xf6, 0x67, 0x62, 0x8e, 0xb1, 0x77, + 0x02, 0x93, 0x2d, 0xe0, 0x1c, 0xcb, 0xbc, 0x64, 0x44, 0xae, 0x0a, 0xad, 0x1f, 0xd0, 0x82, 0x6b, 0x70, 0x91, 0x49, + 0xf3, 0xbb, 0x5f, 0x08, 0x62, 0x9f, 0x56, 0x52, 0xee, 0xab, 0x6d, 0xcd, 0xf3, 0xed, 0xfd, 0x5e, 0xc2, 0xf9, 0xcf, + 0xa5, 0x11, 0xb5, 0x00, 0x07, 0xe0, 0x73, 0xf8, 0xe3, 0x4a, 0x5b, 0xd2, 0x64, 0x16, 0xed, 0x67, 0x0c, 0x41, 0x97, + 0x06, 0x1f, 0xc4, 0x1e, 0x79, 0xa9, 0x4f, 0x16, 0x12, 0xb8, 0x23, 0x86, 0x4f, 0x2b, 0x82, 0x5e, 0x31, 0xa2, 0xb8, + 0xe4, 0x0a, 0x95, 0x52, 0xf2, 0x6f, 0x94, 0x5d, 0x54, 0xc8, 0x59, 0xc1, 0xee, 0x15, 0x39, 0x32, 0x7e, 0x10, 0x4c, + 0x7c, 0x39, 0xb8, 0xff, 0x12, 0xef, 0x70, 0xa6, 0x38, 0x92, 0x13, 0xfe, 0x90, 0x61, 0x60, 0x7f, 0x0e, 0x3e, 0xaf, + 0x0e, 0xf3, 0xf2, 0x46, 0x9f, 0x72, 0x4b, 0x3e, 0x9e, 0x2c, 0xaf, 0xc0, 0x60, 0xbf, 0x54, 0xcd, 0x5d, 0xf3, 0x7a, + 0xb6, 0x9c, 0xb3, 0xfd, 0x2c, 0x9a, 0x07, 0x77, 0x6c, 0x96, 0xcd, 0x83, 0x55, 0xc3, 0xd7, 0xec, 0x96, 0xaf, 0xad, + 0xaa, 0xad, 0xed, 0xaa, 0x4d, 0x36, 0xfc, 0x16, 0x24, 0x84, 0x9b, 0xcc, 0x03, 0xde, 0xe3, 0x3b, 0x9f, 0x6d, 0x40, + 0xa2, 0x5d, 0xb1, 0x0d, 0x5c, 0xc4, 0xd6, 0xfc, 0x87, 0xca, 0xdb, 0xb0, 0x92, 0x9d, 0x8f, 0x59, 0x8e, 0xf3, 0xcf, + 0x87, 0x07, 0xb4, 0x17, 0xea, 0x67, 0x97, 0xea, 0xd9, 0x44, 0xd9, 0xcd, 0x36, 0xa3, 0xc5, 0x7d, 0x5a, 0x6d, 0xc2, + 0x0c, 0x3d, 0xcb, 0xe1, 0xa3, 0xad, 0x14, 0xfc, 0xf4, 0x02, 0xbf, 0x64, 0x47, 0x6d, 0xa5, 0x6d, 0xbb, 0x2a, 0xb1, + 0x15, 0xb4, 0x28, 0xb2, 0x5a, 0xe1, 0x81, 0x39, 0x7f, 0x01, 0x0b, 0x18, 0x7b, 0x8e, 0x73, 0x5e, 0xfb, 0x23, 0x64, + 0xbc, 0x77, 0x00, 0xd0, 0x32, 0xc7, 0x01, 0x1e, 0xb1, 0x62, 0x14, 0x0d, 0xde, 0xf9, 0xa5, 0xb2, 0x5a, 0x69, 0x4e, + 0x42, 0xdb, 0x88, 0x55, 0xcb, 0x91, 0xaa, 0x19, 0x91, 0x3e, 0x48, 0xcf, 0xfb, 0x1e, 0x51, 0x0d, 0xf6, 0x64, 0x5e, + 0x07, 0xf6, 0xe9, 0x55, 0x6b, 0x55, 0x77, 0x7e, 0x4f, 0x95, 0x2e, 0x39, 0xb2, 0xe5, 0xa7, 0xcb, 0xf0, 0x41, 0xfd, + 0x29, 0xb9, 0x3e, 0x14, 0x38, 0xc2, 0x63, 0x15, 0x70, 0xbe, 0x5e, 0x89, 0x76, 0x27, 0xc2, 0xae, 0x5c, 0x02, 0x42, + 0x7c, 0x49, 0xd3, 0x1c, 0x8f, 0x23, 0x9a, 0x88, 0xb0, 0x89, 0xd1, 0x5f, 0xd8, 0x7d, 0x28, 0xb1, 0x9c, 0xe7, 0x1a, + 0x94, 0x5c, 0x32, 0x78, 0x4f, 0xda, 0x6b, 0xd0, 0x2c, 0xaf, 0x4a, 0x4d, 0x26, 0x72, 0x50, 0x3e, 0x1c, 0x0a, 0xd8, + 0x4b, 0x8d, 0x9f, 0x26, 0xfc, 0x84, 0xe5, 0xad, 0xbd, 0x35, 0xa5, 0xa8, 0xa4, 0x01, 0x2a, 0xf0, 0x31, 0x83, 0xff, + 0xdd, 0x19, 0x62, 0xc1, 0x14, 0x1d, 0x3f, 0x9c, 0x89, 0xb9, 0xf5, 0xdc, 0x2a, 0xeb, 0x28, 0x5b, 0xa3, 0x9c, 0x80, + 0x7f, 0x4b, 0x75, 0x9c, 0x24, 0xc2, 0xa9, 0xf7, 0x88, 0x8b, 0xba, 0x97, 0x43, 0xd4, 0x0d, 0x7b, 0x5b, 0xe9, 0x60, + 0xcb, 0x69, 0x1a, 0x1c, 0x89, 0x5f, 0xa9, 0xcf, 0xde, 0x67, 0x16, 0x8f, 0x3a, 0xb2, 0x11, 0x25, 0x69, 0x1c, 0x8b, + 0x1c, 0xb6, 0xf7, 0x85, 0xdc, 0xff, 0xfb, 0x7d, 0x08, 0x27, 0xad, 0x82, 0xa4, 0xf4, 0x04, 0x22, 0xc2, 0xd1, 0xe1, + 0x47, 0x84, 0x27, 0x52, 0x55, 0xf8, 0xa4, 0x3e, 0x71, 0x63, 0x76, 0x2f, 0xcc, 0x51, 0xbd, 0x05, 0x18, 0xc6, 0x7a, + 0x6b, 0x11, 0x92, 0x68, 0xa5, 0x19, 0x6d, 0x3d, 0x20, 0x46, 0xbc, 0x5f, 0x5b, 0x64, 0x30, 0xd6, 0x96, 0x44, 0x02, + 0xf8, 0x1d, 0x09, 0x19, 0xda, 0x36, 0x02, 0x33, 0x86, 0xb7, 0xb3, 0xe2, 0xd2, 0x75, 0xd8, 0xe6, 0x1c, 0xbe, 0x90, + 0x85, 0x66, 0x1d, 0x51, 0x9a, 0x20, 0xe4, 0x1f, 0x70, 0xb2, 0x50, 0x18, 0xcd, 0xeb, 0xa3, 0x74, 0x92, 0x58, 0xdf, + 0x77, 0x95, 0x0a, 0x36, 0x9b, 0x1b, 0xd4, 0x97, 0x1d, 0x25, 0xbf, 0x02, 0x27, 0x1d, 0x27, 0x59, 0xe4, 0x20, 0x6a, + 0x51, 0x39, 0x37, 0x49, 0x58, 0xda, 0xd5, 0xa9, 0x36, 0xeb, 0x75, 0x51, 0xd6, 0xd5, 0x6b, 0x11, 0x29, 0x7a, 0x1f, + 0xf5, 0xe8, 0x89, 0x84, 0x54, 0x68, 0x55, 0x6a, 0x97, 0x47, 0xe0, 0xb6, 0xa9, 0x15, 0xdb, 0x72, 0x09, 0x4b, 0xd4, + 0xf8, 0x4f, 0xd0, 0x47, 0xb9, 0x78, 0x90, 0x01, 0x1a, 0x1d, 0x4f, 0xcd, 0x5b, 0x8f, 0xbc, 0x72, 0x94, 0x5f, 0x5a, + 0x6d, 0xd2, 0x2f, 0x80, 0xcc, 0x68, 0xff, 0x68, 0x29, 0x81, 0xcc, 0xc0, 0x4c, 0x5a, 0x1a, 0x12, 0x39, 0x8a, 0x59, + 0x9a, 0xff, 0x81, 0x2b, 0xb6, 0x42, 0xa4, 0x61, 0x35, 0xf7, 0xf8, 0xcb, 0xca, 0xab, 0xe5, 0x5a, 0x66, 0x9a, 0x9b, + 0x25, 0x8e, 0x15, 0x8b, 0x8b, 0x7a, 0x5d, 0x89, 0x2c, 0x10, 0xe2, 0x08, 0xd3, 0x58, 0x4f, 0xbd, 0x51, 0x5a, 0x7d, + 0x40, 0x42, 0x99, 0x1f, 0xb0, 0xb7, 0x63, 0xaf, 0x07, 0x59, 0x88, 0x63, 0xcb, 0xc1, 0x66, 0xeb, 0x7d, 0x2a, 0x53, + 0x11, 0x9f, 0xd5, 0xc5, 0xd9, 0xa6, 0x12, 0x67, 0x75, 0x22, 0xce, 0xbe, 0x83, 0x9c, 0xdf, 0x9d, 0x51, 0xd1, 0x67, + 0x0f, 0x69, 0x9d, 0x14, 0x9b, 0x9a, 0x9e, 0xbc, 0xc1, 0x32, 0xbe, 0x3b, 0x23, 0xae, 0x9a, 0x33, 0x1a, 0xc9, 0x78, + 0x74, 0xf6, 0x21, 0x03, 0x92, 0xd7, 0xb3, 0x74, 0x05, 0x83, 0x77, 0x16, 0xe6, 0xf1, 0x59, 0x29, 0xee, 0xc0, 0xe2, + 0x54, 0x76, 0xbe, 0x07, 0x19, 0x56, 0xe1, 0x1f, 0xe2, 0x0c, 0xa0, 0x5d, 0xcf, 0xd2, 0xfa, 0x2c, 0xad, 0xce, 0xf2, + 0xa2, 0x3e, 0x53, 0x52, 0x38, 0x84, 0xf1, 0xc3, 0x7b, 0xfa, 0xca, 0x2e, 0x6f, 0xb3, 0xb8, 0xcb, 0x22, 0x7f, 0x8a, + 0x5e, 0x45, 0xc4, 0xa4, 0x51, 0x09, 0xaf, 0xdd, 0xdf, 0x36, 0xf7, 0x0f, 0xaf, 0x1b, 0xbb, 0x9f, 0xdd, 0x31, 0xa2, + 0x0b, 0xea, 0xf1, 0x4a, 0x52, 0x2a, 0x28, 0x20, 0x70, 0xa2, 0x59, 0xe3, 0xc1, 0x1d, 0x07, 0xbc, 0x1a, 0xd8, 0x92, + 0xad, 0x7d, 0xfe, 0x22, 0x96, 0x61, 0xda, 0x9b, 0x00, 0xff, 0x2a, 0x7b, 0xd3, 0x75, 0xb0, 0xc4, 0xfb, 0x16, 0xb2, + 0x0d, 0xbd, 0x7d, 0xcd, 0x5f, 0x7a, 0xb9, 0xfa, 0x9b, 0xfd, 0x13, 0x80, 0x30, 0x20, 0x66, 0xd5, 0x47, 0x13, 0xf7, + 0xce, 0xca, 0xb2, 0x73, 0xb2, 0xec, 0x7a, 0xe8, 0xd7, 0x24, 0x46, 0xa5, 0x95, 0xa5, 0x74, 0xb2, 0x94, 0x90, 0x05, + 0x7c, 0x62, 0x34, 0xb5, 0x11, 0x40, 0xd8, 0x8e, 0x52, 0xf9, 0x42, 0xe5, 0x45, 0x14, 0xce, 0x09, 0x9e, 0x27, 0x62, + 0x74, 0x6f, 0x25, 0x03, 0x86, 0x43, 0x08, 0xe6, 0xa0, 0x2d, 0xf6, 0x86, 0x6e, 0x22, 0xfe, 0x7a, 0x53, 0x94, 0x6f, + 0x63, 0xf2, 0x29, 0xd8, 0x9d, 0x7c, 0x5c, 0xc2, 0xe3, 0xf2, 0xe4, 0xe3, 0x10, 0x3d, 0x12, 0x4e, 0x3e, 0x06, 0xdf, + 0x23, 0x39, 0xaf, 0xbb, 0x1e, 0x27, 0xc8, 0x2d, 0xa4, 0xfb, 0xdb, 0x31, 0x09, 0xd0, 0xbc, 0x86, 0xe5, 0xa8, 0xa9, + 0xb8, 0x66, 0x66, 0x8c, 0xe7, 0x8d, 0xde, 0x1f, 0x3b, 0xde, 0x32, 0x85, 0x62, 0x16, 0xf3, 0x1a, 0x7e, 0xcf, 0xaa, + 0x40, 0xdd, 0xf5, 0x36, 0xc9, 0x2d, 0xb3, 0x7a, 0x8e, 0x76, 0xdf, 0xf7, 0x75, 0x22, 0xa8, 0xfd, 0x1d, 0xf6, 0x3c, + 0xb3, 0xde, 0x55, 0x31, 0x70, 0xa9, 0x92, 0x1d, 0x32, 0x55, 0x4d, 0x0f, 0x54, 0x4a, 0x83, 0xa7, 0x97, 0xd6, 0xe5, + 0x4b, 0xa5, 0x8d, 0x3c, 0xd3, 0xfc, 0x06, 0xf0, 0x62, 0xea, 0xb2, 0xd8, 0x7d, 0x75, 0x5f, 0xc1, 0x6d, 0xbc, 0xdf, + 0x5f, 0x56, 0x9e, 0xf9, 0x89, 0x0b, 0xc0, 0xde, 0x54, 0x68, 0x9d, 0x40, 0xa9, 0x61, 0x1d, 0xbe, 0x4a, 0x44, 0xf4, + 0x47, 0xbb, 0x5c, 0x67, 0xae, 0x03, 0x46, 0x14, 0xf1, 0xdb, 0x78, 0xf4, 0x07, 0x28, 0xae, 0x8d, 0x3d, 0x20, 0xac, + 0x43, 0x42, 0x9f, 0x11, 0x80, 0xd4, 0x63, 0x8e, 0x12, 0xd0, 0xac, 0x68, 0xee, 0x98, 0xfc, 0x5c, 0x5f, 0x29, 0xfd, + 0xfd, 0xb2, 0xf2, 0xc8, 0x9c, 0xd2, 0x36, 0xd3, 0x58, 0xad, 0xa9, 0x04, 0xc2, 0x2b, 0x2a, 0x59, 0x85, 0xcf, 0xe6, + 0x8d, 0xe8, 0xf7, 0xe5, 0x11, 0x9e, 0x56, 0x3f, 0x6c, 0x31, 0xbe, 0x15, 0x10, 0x8d, 0x04, 0x40, 0x3f, 0x01, 0xcc, + 0x8b, 0x6c, 0x66, 0xf7, 0x71, 0x40, 0x95, 0x12, 0x4d, 0xe3, 0x6c, 0x9e, 0xdf, 0xd2, 0x9b, 0xb2, 0x83, 0x4e, 0x9d, + 0x2a, 0x70, 0xc1, 0x55, 0xc9, 0x78, 0x65, 0x3d, 0x91, 0xcf, 0x6f, 0x6e, 0x37, 0x69, 0x16, 0xbf, 0x2f, 0xff, 0x89, + 0x63, 0xab, 0xeb, 0xf0, 0xc8, 0xd4, 0xe9, 0xda, 0x79, 0xa4, 0xb5, 0x17, 0x02, 0x22, 0xda, 0x35, 0xd4, 0x7a, 0x61, + 0xa1, 0x47, 0x7a, 0x22, 0x9c, 0x93, 0x44, 0x4d, 0x3b, 0xd0, 0xd2, 0x08, 0x7d, 0x7d, 0xcd, 0xe9, 0x2f, 0x0c, 0xd6, + 0x3e, 0x1f, 0x33, 0x20, 0x2b, 0xd1, 0x8f, 0xd5, 0x43, 0x63, 0x33, 0x87, 0x9e, 0xb5, 0x2a, 0xcf, 0xbc, 0xea, 0x70, + 0x40, 0x7c, 0x18, 0xfd, 0x25, 0xbf, 0xdf, 0x7f, 0x4d, 0xf3, 0x8f, 0x09, 0x35, 0x7e, 0xb6, 0x19, 0xa0, 0x6b, 0xdf, + 0x95, 0x07, 0xa2, 0x9e, 0x6b, 0x95, 0x20, 0xc4, 0x1b, 0xc4, 0x44, 0x33, 0x62, 0x0e, 0x4e, 0x3b, 0xd4, 0xfc, 0x93, + 0xd4, 0x80, 0x10, 0x25, 0x5e, 0xc7, 0x94, 0x05, 0x39, 0x6d, 0xe2, 0x48, 0x3f, 0x0a, 0x27, 0xf2, 0xa3, 0xa8, 0x8a, + 0xec, 0x1e, 0x2e, 0x18, 0x4c, 0xbd, 0xa7, 0xfd, 0x12, 0xfd, 0x96, 0x70, 0xe4, 0x1c, 0xad, 0x0a, 0x41, 0xe4, 0x84, + 0xb0, 0xd6, 0x10, 0x26, 0x88, 0x0d, 0xe2, 0x65, 0xdf, 0x25, 0x19, 0x8e, 0x14, 0x5c, 0xd6, 0xb1, 0x63, 0xcc, 0xd5, + 0x51, 0xf5, 0x1a, 0xc0, 0x78, 0xe5, 0x08, 0x9a, 0x8d, 0x22, 0xbb, 0x84, 0xa8, 0x22, 0xc7, 0x13, 0x50, 0x3b, 0x28, + 0x8d, 0xcd, 0xf4, 0x7c, 0x1c, 0xe4, 0xa3, 0x45, 0x85, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x73, 0xd5, 0xcf, + 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x8a, 0xe9, 0x72, + 0x60, 0xdc, 0x37, 0xbc, 0xa2, 0x38, 0xc3, 0x8f, 0x1e, 0x6c, 0x71, 0xfe, 0x74, 0x43, 0xed, 0xc7, 0xdc, 0xa8, 0x87, + 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, 0xfc, 0x43, + 0x99, 0xae, 0x52, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, 0xa2, 0xac, + 0xdf, 0x87, 0xdf, 0x57, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, 0x93, 0x41, + 0x0d, 0xda, 0xf0, 0x0d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, 0xec, 0x4f, + 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xe3, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xc7, 0x97, 0xfc, 0x06, 0xbd, + 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, 0x8f, 0x51, + 0xc9, 0x62, 0x4b, 0x8f, 0x55, 0xd1, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x05, 0xc1, 0x12, 0x18, + 0x17, 0xb1, 0xe6, 0x9b, 0x41, 0xce, 0xe2, 0xd9, 0x66, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1c, 0x0a, 0x09, 0x36, 0x93, + 0xcd, 0xd6, 0x73, 0xb6, 0xf6, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, 0x35, 0x58, + 0xad, 0xa6, 0x6c, 0x55, 0x53, 0x76, 0x4e, 0x53, 0x8e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, 0x88, 0x4d, + 0xa2, 0xab, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, 0x50, 0x85, + 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, 0xbe, 0xa5, + 0x8e, 0x7b, 0x94, 0x6d, 0xfe, 0x2e, 0x76, 0x41, 0x88, 0xdc, 0x8d, 0x3b, 0xf5, 0x33, 0xe2, 0xbd, 0xdd, 0x11, 0xc6, + 0x4f, 0x76, 0xdc, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8b, 0x79, 0x35, 0x49, 0x50, 0xcb, 0x92, 0xf8, 0x1b, + 0x9e, 0x0c, 0x72, 0xb6, 0x04, 0x0f, 0xda, 0x39, 0xcb, 0x00, 0x7f, 0xc5, 0x6a, 0xd1, 0x6f, 0xb5, 0xb7, 0x04, 0xf9, + 0x69, 0x63, 0x37, 0x0a, 0x13, 0x23, 0x48, 0xd4, 0xed, 0xca, 0x40, 0x7e, 0xf8, 0x80, 0xd3, 0xf1, 0xd8, 0x53, 0xc6, + 0xdc, 0xca, 0xf4, 0x32, 0x9d, 0x2b, 0xf9, 0x46, 0xee, 0xa5, 0x8f, 0xbd, 0x04, 0x3b, 0x07, 0xbc, 0x81, 0xb4, 0x81, + 0x37, 0xb0, 0x5d, 0x78, 0x6d, 0x90, 0x30, 0x23, 0xc0, 0x16, 0xc7, 0xc7, 0x48, 0x09, 0x0c, 0xe1, 0x38, 0x4b, 0x01, + 0x98, 0x46, 0x5f, 0x66, 0x2b, 0xfb, 0x32, 0xab, 0x35, 0x5b, 0x2a, 0xa7, 0x7b, 0xe7, 0xd6, 0xed, 0x7c, 0x22, 0x01, + 0xc0, 0xa4, 0xce, 0x81, 0x38, 0x33, 0xc1, 0x2e, 0x4d, 0x22, 0xcb, 0xc7, 0x30, 0xbf, 0x13, 0x6f, 0xca, 0x62, 0xa5, + 0xba, 0xa2, 0xed, 0x33, 0x93, 0xcf, 0x48, 0x27, 0xa1, 0x02, 0x0a, 0x0a, 0xb9, 0xd6, 0xa7, 0xef, 0xc2, 0x77, 0x41, + 0xa1, 0x81, 0xd9, 0x2a, 0xdc, 0xd3, 0x64, 0x8d, 0xd4, 0x1b, 0x55, 0xbf, 0x4f, 0xae, 0x81, 0x54, 0x67, 0x0e, 0x2d, + 0x7b, 0x52, 0x61, 0x80, 0xd8, 0x51, 0x9f, 0x91, 0x50, 0x07, 0x52, 0x0f, 0x18, 0x42, 0xb4, 0x4d, 0x1f, 0x7f, 0x32, + 0x24, 0xba, 0x00, 0x5b, 0x88, 0x36, 0xf0, 0xe3, 0x4f, 0xb0, 0xcf, 0x82, 0xf0, 0x98, 0xe6, 0xd7, 0x90, 0x74, 0x6c, + 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0xb9, 0x94, + 0xea, 0x58, 0xa9, 0xb7, 0x6d, 0xed, 0x07, 0xd1, 0x16, 0x1c, 0x59, 0xc4, 0xdf, 0x67, 0x88, 0x08, 0x66, 0x06, 0x11, + 0x76, 0x2d, 0xd4, 0xdd, 0x9e, 0x52, 0xcb, 0xa2, 0xde, 0xf6, 0x94, 0x52, 0xb7, 0x61, 0xf8, 0x6e, 0x82, 0x99, 0xe2, + 0x86, 0xff, 0x91, 0x79, 0xa1, 0xde, 0x78, 0x2c, 0x0a, 0x74, 0xcf, 0xdf, 0x2f, 0x79, 0x35, 0xdb, 0x28, 0x13, 0xe6, + 0x1d, 0x5f, 0xce, 0x42, 0xd9, 0xd5, 0xd2, 0xb8, 0xf3, 0xd9, 0x5b, 0xaa, 0xf9, 0xe0, 0x1f, 0x0e, 0x09, 0xc4, 0x1b, + 0xc5, 0x57, 0x77, 0x8d, 0xdc, 0xba, 0x26, 0x9b, 0xab, 0x12, 0x50, 0xbf, 0xcf, 0xd7, 0xb8, 0xdf, 0x62, 0xfd, 0xbb, + 0xa7, 0x41, 0xc6, 0x6a, 0x86, 0x2b, 0xa6, 0xf0, 0x29, 0x00, 0x0c, 0x0e, 0xa7, 0x82, 0xb4, 0xc0, 0x1b, 0x5e, 0x0e, + 0x2f, 0x27, 0x1b, 0x32, 0xe9, 0x6e, 0x7c, 0xe4, 0xce, 0x02, 0x55, 0xef, 0x37, 0x14, 0x27, 0x0d, 0x12, 0x8d, 0xbd, + 0x06, 0x5f, 0x66, 0x19, 0xe5, 0xa2, 0x89, 0xfb, 0x98, 0x7c, 0xa5, 0x07, 0x30, 0x57, 0xa1, 0x04, 0x88, 0x7e, 0x63, + 0x59, 0x6c, 0x44, 0xdb, 0x62, 0x03, 0x4b, 0xa9, 0x9a, 0xeb, 0xd5, 0xf4, 0xd9, 0x2b, 0xd1, 0xbc, 0x8f, 0x66, 0x9c, + 0xd2, 0x68, 0xc0, 0x71, 0x1a, 0x85, 0xdb, 0xf7, 0xf7, 0xa2, 0x5c, 0x66, 0x60, 0xc9, 0x56, 0xe1, 0x14, 0x97, 0x8d, + 0x3a, 0x23, 0x5e, 0xe6, 0xb1, 0x02, 0xe8, 0x78, 0x4c, 0x00, 0x54, 0x17, 0x04, 0x54, 0x44, 0x4b, 0xe9, 0xad, 0xd0, + 0x62, 0xa1, 0xde, 0x70, 0x94, 0xc2, 0x1f, 0xe9, 0xcf, 0x83, 0x7c, 0x0a, 0x40, 0xec, 0xfa, 0x38, 0x7a, 0x53, 0x94, + 0xf4, 0xa9, 0x62, 0x96, 0xcb, 0xc1, 0x04, 0x76, 0x75, 0x22, 0x43, 0xad, 0x20, 0x6f, 0xd5, 0x95, 0xb7, 0x32, 0x79, + 0x1b, 0xe3, 0x94, 0xfc, 0xc8, 0x4d, 0xc7, 0x1a, 0x31, 0xf0, 0xca, 0xd3, 0x3a, 0x4d, 0x90, 0x26, 0x17, 0xc0, 0x30, + 0xc4, 0xb7, 0x99, 0xf7, 0xd2, 0x73, 0xa4, 0x2a, 0x48, 0x66, 0xbb, 0xcc, 0x53, 0x17, 0x51, 0x7d, 0xe5, 0xd4, 0xd2, + 0x99, 0xd3, 0x8f, 0x00, 0xde, 0x63, 0x6a, 0xd2, 0x90, 0x8f, 0x70, 0x5b, 0x8a, 0xaf, 0xb7, 0xea, 0x1a, 0x2f, 0x8d, + 0xce, 0xdd, 0xcb, 0x97, 0xee, 0x34, 0xe8, 0xa7, 0x20, 0x28, 0xe7, 0xcb, 0x52, 0xc0, 0x9e, 0x32, 0x9b, 0xeb, 0xd5, + 0xaa, 0x15, 0x5a, 0x87, 0xc3, 0x58, 0x3b, 0x0a, 0x69, 0x75, 0x16, 0xb0, 0xd5, 0x48, 0xa7, 0x04, 0x08, 0xc1, 0x71, + 0x1a, 0x76, 0x82, 0x71, 0x97, 0x4e, 0x23, 0xb2, 0x5e, 0x29, 0x49, 0x17, 0x66, 0x90, 0xfc, 0x93, 0xbc, 0x9e, 0x01, + 0x2d, 0x01, 0x1c, 0x8a, 0x58, 0xc2, 0xc3, 0x49, 0x72, 0x05, 0xd0, 0xe9, 0x70, 0x50, 0x69, 0x68, 0xce, 0x6a, 0x96, + 0xcc, 0x27, 0xb1, 0x54, 0x55, 0x1e, 0x0e, 0x9e, 0x72, 0x33, 0xe8, 0xf7, 0xb3, 0x69, 0xa9, 0x5c, 0x00, 0x82, 0x58, + 0x17, 0x06, 0x88, 0x47, 0x5a, 0x78, 0xb2, 0xe8, 0x53, 0x12, 0xbf, 0x9c, 0x25, 0x73, 0x93, 0x0d, 0xef, 0xc0, 0x08, + 0x36, 0xe3, 0xba, 0xa4, 0x4c, 0x7b, 0x54, 0x7e, 0xcf, 0xe8, 0xa9, 0xed, 0x6b, 0xad, 0xb6, 0x88, 0x75, 0x1d, 0x5c, + 0x95, 0xa8, 0xa7, 0xf8, 0xa0, 0x24, 0xc1, 0xfb, 0xb5, 0x73, 0x33, 0x52, 0xbe, 0x16, 0xb9, 0x1f, 0xb4, 0x33, 0xb5, + 0x72, 0xe0, 0x08, 0xe4, 0x58, 0x45, 0x25, 0xaf, 0x77, 0x1d, 0x82, 0x47, 0x77, 0xa5, 0x02, 0xe5, 0xe0, 0x17, 0x20, + 0x46, 0xd7, 0x57, 0x9d, 0x35, 0xd4, 0x4c, 0xa3, 0xca, 0x23, 0xe8, 0xd4, 0x01, 0x3c, 0x29, 0x78, 0xa9, 0xd5, 0x8f, + 0x87, 0x83, 0x67, 0x7e, 0xf0, 0x57, 0x99, 0xbe, 0x85, 0x98, 0x28, 0xa7, 0x1a, 0x21, 0x71, 0xa5, 0x24, 0x11, 0x1f, + 0x2f, 0x5a, 0x56, 0x8c, 0xca, 0xf0, 0x81, 0x57, 0xaa, 0x7c, 0x75, 0xaa, 0xf2, 0x62, 0xa4, 0x6d, 0x09, 0xbc, 0x26, + 0xff, 0x10, 0xb9, 0xe6, 0xad, 0xaf, 0xbb, 0xca, 0xd0, 0x6b, 0x59, 0x81, 0x8e, 0x60, 0x2b, 0x4b, 0xc9, 0x01, 0x9f, + 0x54, 0x77, 0xd5, 0xaa, 0xf5, 0x39, 0x65, 0x1b, 0xe1, 0x26, 0xbf, 0x8e, 0x1d, 0x1c, 0x29, 0xbf, 0xc1, 0x73, 0x01, + 0xec, 0x35, 0x60, 0x6f, 0xce, 0x59, 0xd1, 0x3c, 0x3a, 0xa4, 0x6d, 0x81, 0x46, 0x66, 0x6e, 0xe7, 0xea, 0xbe, 0x2d, + 0x8f, 0xd2, 0x18, 0x22, 0xd3, 0x1e, 0x99, 0x0e, 0x36, 0xa3, 0xfc, 0xb7, 0x94, 0xdf, 0x2a, 0x1c, 0x03, 0xdf, 0x4e, + 0xbd, 0x03, 0xa8, 0x7a, 0xda, 0x20, 0x63, 0xcd, 0x30, 0xb4, 0xb2, 0xcb, 0xa5, 0xd0, 0x12, 0xb4, 0xd4, 0x4d, 0x10, + 0x9c, 0x1f, 0x11, 0xe5, 0x08, 0x40, 0x17, 0x29, 0x60, 0x82, 0x9f, 0xd2, 0x76, 0xf7, 0xfb, 0xeb, 0xd4, 0x23, 0xf7, + 0xae, 0x50, 0xa3, 0x84, 0x12, 0x8c, 0xfd, 0x44, 0x63, 0x06, 0x1d, 0x5d, 0x91, 0x13, 0x9e, 0xb5, 0x3a, 0xac, 0xeb, + 0xa6, 0x0c, 0xca, 0xe2, 0x98, 0x57, 0xd3, 0xd9, 0xef, 0x4f, 0xf6, 0x75, 0x83, 0x2c, 0xe4, 0xbf, 0xb3, 0x1e, 0x92, + 0x41, 0xf7, 0x20, 0x14, 0xa2, 0x37, 0x0f, 0x66, 0xf8, 0x1f, 0xdb, 0xf0, 0xec, 0x1b, 0x6e, 0xd4, 0x09, 0x60, 0x8e, + 0xb8, 0x5e, 0x7a, 0x8a, 0xb6, 0x1e, 0x6e, 0x81, 0x6c, 0x8d, 0x97, 0xb7, 0xf6, 0x1a, 0xc8, 0x29, 0x8e, 0xff, 0x8e, + 0x67, 0x6a, 0x65, 0x83, 0x9f, 0x9e, 0xb2, 0x1d, 0x78, 0x78, 0x11, 0x02, 0x8a, 0x61, 0xd9, 0xf8, 0x3b, 0xcb, 0x71, + 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, 0x5b, 0x79, 0x77, 0xe4, + 0x94, 0x79, 0xa7, 0x87, 0xd1, 0x75, 0x49, 0xfa, 0x26, 0xf9, 0xd8, 0x1a, 0xb6, 0xdf, 0xb5, 0xfb, 0xcd, 0x10, 0x41, + 0x08, 0xe5, 0xf8, 0x39, 0xa3, 0x13, 0x1a, 0x1f, 0x56, 0xb3, 0xd3, 0xeb, 0xf7, 0xce, 0xf1, 0x82, 0xad, 0xd1, 0x00, + 0x8f, 0x87, 0x2e, 0xe6, 0x89, 0x1a, 0x3a, 0x5d, 0xd7, 0xce, 0xc1, 0x03, 0x83, 0x2c, 0x4f, 0xbe, 0x61, 0x58, 0x62, + 0x7f, 0x12, 0xf1, 0xa4, 0xad, 0xda, 0xd8, 0x1c, 0xa9, 0x36, 0x6a, 0x06, 0x7e, 0xf0, 0x0a, 0x0a, 0x8c, 0x2e, 0x48, + 0x2b, 0x30, 0x0e, 0x47, 0x00, 0xb2, 0x62, 0x1c, 0x8f, 0x0c, 0x26, 0x30, 0xa4, 0x1b, 0x8a, 0x02, 0xf0, 0xf0, 0x38, + 0x1e, 0x84, 0x0c, 0x20, 0x5d, 0xf0, 0xd0, 0xb0, 0x4d, 0x42, 0xca, 0xcf, 0xf3, 0xbc, 0x56, 0x43, 0xe8, 0x3b, 0x0b, + 0xd5, 0xb1, 0x1f, 0x69, 0xaf, 0x58, 0xd7, 0xaa, 0x74, 0x64, 0xab, 0x03, 0xf4, 0x0d, 0x19, 0xf8, 0xd6, 0xb1, 0x05, + 0x40, 0xb4, 0xc4, 0x6f, 0xa9, 0x57, 0xfb, 0x32, 0x66, 0x85, 0x7a, 0x7d, 0x61, 0xda, 0xf5, 0x5a, 0x5a, 0x14, 0x50, + 0x71, 0xdb, 0xaa, 0xed, 0x91, 0x9c, 0xff, 0xf8, 0xae, 0xa3, 0x1d, 0x9f, 0x9d, 0x1a, 0x5b, 0x42, 0x99, 0x5b, 0x3c, + 0x91, 0xd5, 0xd1, 0x96, 0xea, 0x54, 0x1f, 0x70, 0xa9, 0x49, 0x75, 0x66, 0x60, 0x78, 0x8d, 0x00, 0xe5, 0x16, 0x22, + 0x69, 0x1c, 0xf6, 0xce, 0x27, 0x83, 0x82, 0xb9, 0x45, 0x02, 0x12, 0xd8, 0xc6, 0xd6, 0x2e, 0x9a, 0xeb, 0xd7, 0x6f, + 0xa9, 0x57, 0xb5, 0xa9, 0xea, 0xc1, 0x1b, 0x2f, 0x70, 0xf6, 0x4e, 0x6b, 0x01, 0x01, 0x14, 0xb6, 0x96, 0xe5, 0xe0, + 0xdc, 0xed, 0xaa, 0x96, 0x8a, 0x32, 0xea, 0xf7, 0xcf, 0x7f, 0x4b, 0x51, 0x11, 0x7b, 0xaa, 0x38, 0x65, 0xfd, 0x76, + 0xcb, 0x5c, 0x54, 0x96, 0xbc, 0x41, 0x15, 0xad, 0xd5, 0x51, 0x53, 0xb9, 0x6e, 0xae, 0x5a, 0x32, 0x41, 0x8c, 0xee, + 0xd3, 0xb5, 0xce, 0x9d, 0x7a, 0xef, 0x55, 0x1c, 0x31, 0x10, 0xdc, 0x74, 0x8f, 0x0f, 0x0e, 0x42, 0xa3, 0xa2, 0x5c, + 0x70, 0xa3, 0xb4, 0xaa, 0xa4, 0x14, 0xf2, 0x56, 0x45, 0x73, 0xa6, 0x8f, 0x00, 0x88, 0x00, 0xab, 0x44, 0xfd, 0x1f, + 0xbe, 0x34, 0xc6, 0x83, 0x07, 0xbe, 0x26, 0xd7, 0xb1, 0xf5, 0xfe, 0x69, 0x8d, 0xb4, 0xda, 0x38, 0x26, 0xb5, 0xea, + 0x65, 0xab, 0x78, 0xd9, 0xbd, 0x4e, 0xc5, 0xe0, 0xf9, 0xff, 0xdc, 0x07, 0xa8, 0x11, 0x2d, 0x65, 0x70, 0xeb, 0x6a, + 0x80, 0xc6, 0x87, 0x63, 0xe1, 0x1b, 0x3f, 0x64, 0x9c, 0x0f, 0x66, 0xe8, 0xa8, 0x36, 0x07, 0x07, 0x04, 0x47, 0x75, + 0x8f, 0xc6, 0x84, 0x59, 0x38, 0xf7, 0x20, 0x50, 0x7d, 0xe2, 0x3e, 0xe3, 0xda, 0x0b, 0xda, 0x04, 0x3e, 0x59, 0xd7, + 0x35, 0x45, 0x80, 0x8b, 0xd8, 0x98, 0x88, 0x21, 0x2e, 0x9b, 0x44, 0xea, 0x9b, 0x31, 0x28, 0x00, 0x8a, 0x17, 0x15, + 0xc9, 0xa5, 0x8b, 0x34, 0xaf, 0x44, 0x59, 0xeb, 0x66, 0x54, 0xac, 0x18, 0x02, 0xc0, 0x43, 0x50, 0x5c, 0x55, 0x66, + 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x6a, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, 0xd2, 0x3b, 0x1f, 0xb7, 0xce, + 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, 0x3f, 0xe3, 0x2f, 0x08, 0x4c, + 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x82, 0x97, 0x93, 0x70, 0x38, 0xf4, 0x41, 0x1f, + 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, 0x10, 0xd1, 0x42, 0x43, 0x1f, + 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, 0xda, 0xd0, 0x22, 0xc5, 0x45, + 0xa3, 0xcc, 0x66, 0xb9, 0xec, 0x84, 0x8d, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, 0x54, 0xad, 0xa7, 0x7a, 0x3d, + 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa4, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, 0xa3, 0x6a, 0x9d, 0xa5, 0x11, + 0x55, 0x6e, 0x92, 0xbb, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0x97, 0x29, 0x3b, 0x5b, 0x83, 0x13, 0x47, 0x9e, 0x4b, 0x6e, + 0xf9, 0xee, 0xbc, 0xa2, 0xbb, 0x53, 0xed, 0x5b, 0x80, 0x7b, 0x33, 0x6c, 0xc8, 0x9c, 0xd7, 0xd8, 0x69, 0x10, 0x26, + 0x81, 0x1f, 0xb1, 0x8f, 0x19, 0xb2, 0xc1, 0x80, 0x8e, 0x42, 0xfa, 0x5f, 0x5b, 0xe6, 0x48, 0xc0, 0xe4, 0xaf, 0xe7, + 0x7e, 0xb3, 0x28, 0x72, 0x58, 0x8c, 0x1f, 0x36, 0x18, 0x69, 0xac, 0xd6, 0x60, 0x58, 0xde, 0x21, 0xf2, 0xa7, 0x76, + 0xc7, 0x34, 0xd5, 0xf1, 0x66, 0xbd, 0xd6, 0xfc, 0xea, 0xe9, 0x53, 0x5d, 0x9f, 0xff, 0xf6, 0xfd, 0x65, 0x58, 0x33, + 0xfb, 0x43, 0x10, 0x4a, 0xbb, 0x77, 0x8b, 0x73, 0x47, 0xa2, 0x77, 0xac, 0x34, 0xb3, 0x4b, 0xbb, 0x64, 0x97, 0xa6, + 0xb4, 0x1b, 0x72, 0xbd, 0xfa, 0x4a, 0x79, 0x63, 0xe7, 0x15, 0xd3, 0xfd, 0x7b, 0xa1, 0x77, 0x94, 0x53, 0x35, 0x81, + 0x88, 0x26, 0xed, 0x48, 0xdc, 0xee, 0x95, 0xe1, 0xf3, 0x49, 0xde, 0x2e, 0xe1, 0xa8, 0x6b, 0x58, 0x6e, 0xbe, 0xfd, + 0xcf, 0xbc, 0xea, 0xac, 0x70, 0xfb, 0xa5, 0x31, 0x6b, 0x7f, 0x0a, 0xe2, 0xaa, 0xfe, 0xf0, 0x9e, 0xd4, 0x4c, 0xc9, + 0xff, 0x55, 0x8f, 0x81, 0xab, 0x9f, 0x4c, 0x3b, 0xba, 0xa7, 0x10, 0x36, 0x98, 0xfd, 0xfc, 0xf8, 0xa1, 0x05, 0xab, + 0xea, 0x02, 0x45, 0x72, 0x00, 0x9d, 0xbb, 0x64, 0x84, 0xf7, 0x3b, 0xc6, 0xb9, 0x7f, 0xf5, 0xbd, 0x9a, 0x1c, 0x21, + 0xa2, 0x5d, 0x84, 0x03, 0x80, 0xb8, 0xd3, 0x54, 0xd6, 0xa1, 0x06, 0xe8, 0x03, 0x02, 0xeb, 0xd0, 0xb7, 0x19, 0xc0, + 0x41, 0x1f, 0x6d, 0x9e, 0x45, 0x20, 0xaf, 0x7b, 0xf7, 0xec, 0x9a, 0xed, 0x7c, 0xfe, 0x62, 0x95, 0x7a, 0xf7, 0xe8, + 0x10, 0x7c, 0x3e, 0xf6, 0xa7, 0x97, 0x81, 0xc1, 0x85, 0x66, 0xd7, 0xcf, 0x04, 0xdb, 0xb1, 0xdd, 0x33, 0x44, 0x2a, + 0xea, 0xce, 0x3f, 0xbc, 0x34, 0xd1, 0xf3, 0xce, 0x0b, 0x77, 0x7c, 0x09, 0xe0, 0x81, 0x2c, 0x06, 0x14, 0x9f, 0xa5, + 0xf7, 0x2f, 0x96, 0x80, 0x9a, 0xfc, 0x96, 0xaf, 0xbd, 0x2f, 0x94, 0xba, 0x80, 0x3f, 0x07, 0x94, 0x3e, 0xc9, 0xb9, + 0x77, 0x37, 0xbc, 0xf5, 0x2f, 0x9e, 0x83, 0xf3, 0xc4, 0x6a, 0xb8, 0x80, 0xbf, 0x0a, 0x3e, 0xf4, 0xee, 0x06, 0x98, + 0x58, 0xf2, 0xa1, 0xb7, 0x1a, 0x40, 0xaa, 0xc2, 0x85, 0xc4, 0xd8, 0x87, 0x5f, 0x83, 0x9c, 0xe1, 0x1f, 0xbf, 0x69, + 0x0c, 0xd6, 0x5f, 0x83, 0x42, 0xa3, 0xb1, 0x96, 0x2a, 0x64, 0x29, 0x16, 0x67, 0x02, 0x6c, 0xc2, 0x71, 0xb7, 0x2f, + 0x56, 0xb5, 0x59, 0x0b, 0xfa, 0xf3, 0x11, 0xdf, 0xa3, 0xb1, 0xba, 0x2a, 0xe7, 0xa2, 0xfc, 0x88, 0xf4, 0xa9, 0x8e, + 0x8f, 0x51, 0xb1, 0xa9, 0xbb, 0xd3, 0xa9, 0x56, 0x1d, 0x69, 0xbf, 0x29, 0xd7, 0x60, 0xc7, 0xeb, 0xe4, 0xc8, 0x52, + 0x78, 0xd6, 0x61, 0xe7, 0xa5, 0x53, 0xa2, 0xc3, 0x30, 0xde, 0x6d, 0xd5, 0x33, 0x86, 0xf2, 0xdc, 0x60, 0x4c, 0x17, + 0x3c, 0xe2, 0x2f, 0x06, 0xb9, 0x0c, 0x8d, 0xf9, 0x80, 0x6c, 0x18, 0xca, 0x87, 0x16, 0x19, 0x12, 0x22, 0xde, 0x43, + 0x25, 0x60, 0xdb, 0x82, 0x32, 0x29, 0xe0, 0x2c, 0x1a, 0xfc, 0x56, 0x7b, 0x39, 0xf0, 0x1e, 0x44, 0x7e, 0x23, 0x5d, + 0xca, 0x25, 0x36, 0x3a, 0x71, 0x2c, 0x0b, 0xed, 0x3c, 0xae, 0xbf, 0x8e, 0x41, 0xfd, 0x5e, 0xe9, 0x37, 0x28, 0x67, + 0x7f, 0x94, 0xac, 0xd3, 0xc6, 0x13, 0xe3, 0x1f, 0xae, 0xf2, 0x4f, 0xd1, 0x52, 0x0f, 0xff, 0x9f, 0x31, 0x85, 0xd2, + 0xbf, 0x4a, 0xcb, 0x68, 0xb3, 0x5a, 0x8a, 0x52, 0xe4, 0x91, 0x38, 0xf9, 0x5a, 0x64, 0xe7, 0xf2, 0x9d, 0x4f, 0xa1, + 0x5f, 0x00, 0x5a, 0xf6, 0x09, 0x32, 0xfa, 0x7b, 0x26, 0xf8, 0xf0, 0x7b, 0xed, 0x5c, 0x9b, 0xf3, 0xf1, 0x24, 0xbf, + 0xb2, 0xf6, 0x6e, 0xc7, 0x8b, 0xc4, 0x28, 0xc6, 0x72, 0x5f, 0x75, 0xb3, 0x72, 0xa2, 0x92, 0x03, 0x23, 0x5d, 0x93, + 0xbd, 0x5c, 0xc9, 0xba, 0x9d, 0x6e, 0x25, 0x10, 0x51, 0x05, 0xde, 0x63, 0x5c, 0xc5, 0x3e, 0x82, 0xe9, 0xba, 0xe3, + 0x32, 0xda, 0xf1, 0x9e, 0xf1, 0xea, 0x44, 0x59, 0xc1, 0xed, 0x46, 0xb4, 0x27, 0x74, 0xf4, 0xd3, 0xa4, 0xb6, 0x2c, + 0x1c, 0x80, 0xdc, 0x25, 0x8c, 0x65, 0x43, 0xb0, 0x62, 0x50, 0xfa, 0x7a, 0x4d, 0xc9, 0xb2, 0x00, 0x8b, 0xce, 0x2e, + 0x23, 0x10, 0xc3, 0xba, 0x69, 0x4e, 0xe8, 0x78, 0xe9, 0xe2, 0xbc, 0xd7, 0x2a, 0x52, 0xf0, 0x8c, 0x16, 0x1d, 0x73, + 0xd3, 0x91, 0x6e, 0x8c, 0xf6, 0xf6, 0x7b, 0x83, 0x90, 0xe2, 0xf9, 0x03, 0x5b, 0xad, 0x8b, 0x8b, 0xc4, 0x2b, 0x64, + 0xa2, 0x05, 0xb1, 0x14, 0x81, 0x19, 0x2f, 0x34, 0x8d, 0x30, 0x41, 0x99, 0x12, 0x2c, 0x5a, 0xa3, 0x43, 0xfb, 0xc3, + 0x12, 0x76, 0x8f, 0x31, 0x02, 0x04, 0xaa, 0x4c, 0x9f, 0xc3, 0xd6, 0x84, 0xd9, 0xd4, 0xc5, 0x06, 0x68, 0xab, 0x18, + 0x1a, 0x84, 0xb5, 0x21, 0xe6, 0x63, 0x9a, 0xdf, 0xfd, 0x0b, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, 0xde, 0xed, 0x9a, 0x84, + 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xa8, 0x1d, 0x6b, 0xa9, 0x77, 0xac, 0xb5, + 0xde, 0xb1, 0xee, 0x1a, 0xfe, 0x21, 0xf3, 0x62, 0x96, 0x80, 0x7e, 0x77, 0xc5, 0x55, 0x83, 0xa0, 0x19, 0x1b, 0x76, + 0x0b, 0xbf, 0x25, 0xd6, 0x6e, 0xe9, 0x5f, 0x2c, 0xd9, 0xc2, 0xf4, 0x81, 0x6e, 0x1d, 0x60, 0x19, 0x51, 0x93, 0xef, + 0x91, 0x77, 0xd3, 0x59, 0x51, 0xb8, 0x3d, 0xb1, 0x85, 0xcf, 0xae, 0xcd, 0x9b, 0xf7, 0xcf, 0x22, 0xc8, 0xbd, 0xe3, + 0xde, 0xfd, 0xf0, 0xda, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, 0xea, 0x88, 0x4f, 0x10, 0xad, 0xec, 0x29, + 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, + 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, + 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, + 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, + 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, + 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, + 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0xbe, 0x3f, 0x2d, 0x94, 0x6b, 0x37, 0x6f, 0xe3, + 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x8e, 0x94, 0x5d, 0x2c, 0xe1, 0x1e, + 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf1, 0x9c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, 0x62, 0x5b, 0xb8, 0x78, + 0xce, 0x36, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0x8d, 0x6a, 0x8e, 0x35, 0xd4, 0x6c, 0x6d, + 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0xee, 0xda, 0x8a, 0x8f, 0x95, 0xb5, 0x2e, 0xdd, 0xeb, 0x3d, 0xaa, 0x0b, 0x60, + 0xeb, 0xbf, 0x3d, 0x5e, 0xb9, 0x9e, 0xcf, 0x08, 0xe0, 0x6b, 0xc1, 0xc7, 0x93, 0x05, 0x7a, 0x95, 0x2c, 0xfc, 0xdb, + 0x81, 0x1a, 0x7f, 0xa7, 0x73, 0x17, 0x00, 0x5d, 0x49, 0x79, 0x05, 0xe4, 0x1d, 0xe4, 0x98, 0x5b, 0x76, 0xe5, 0xfd, + 0xc9, 0x77, 0xd8, 0x35, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, + 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x84, 0x20, 0xae, 0xe0, 0x16, 0xe2, 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, + 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, + 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xd7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x40, 0xfc, 0x74, 0x3b, 0xe0, + 0xf7, 0x1d, 0x6b, 0xcb, 0xbb, 0x66, 0x0b, 0xb6, 0x83, 0x4b, 0x50, 0xd3, 0x5e, 0xf6, 0x27, 0x95, 0x0b, 0xda, 0xb1, + 0x4b, 0xe2, 0xe1, 0x8c, 0x59, 0xa5, 0xcc, 0xac, 0x93, 0xea, 0x4a, 0x74, 0xc6, 0x74, 0xd6, 0x7a, 0x3e, 0x57, 0xf3, + 0x49, 0xa1, 0x41, 0xfd, 0xce, 0x89, 0x8f, 0xa8, 0xe8, 0x3c, 0x81, 0xad, 0x65, 0x05, 0xb1, 0xda, 0xe7, 0x60, 0xad, + 0xd5, 0x2e, 0xfd, 0x5e, 0x3e, 0xe0, 0x36, 0xe5, 0xb0, 0x0e, 0x0c, 0x6a, 0x4e, 0xac, 0xa8, 0xc7, 0x6c, 0xc7, 0xb8, + 0xf9, 0xe9, 0xe5, 0x0f, 0x4e, 0x58, 0xb2, 0x62, 0xb5, 0x3f, 0xfd, 0xfe, 0x99, 0xa7, 0xbf, 0x53, 0xfb, 0x17, 0xc2, + 0x0f, 0xc6, 0xff, 0xa9, 0xdd, 0xd7, 0x5a, 0x8c, 0xca, 0x56, 0x39, 0x42, 0xe3, 0x6e, 0x25, 0x4d, 0x96, 0x9f, 0x84, + 0x27, 0xac, 0x05, 0xcf, 0x72, 0xbd, 0x44, 0xb3, 0x02, 0x56, 0x58, 0xcb, 0x24, 0x5c, 0x61, 0xac, 0x96, 0xb6, 0xfa, + 0x16, 0x4d, 0x73, 0x7c, 0x38, 0xd7, 0x06, 0x65, 0xca, 0xd9, 0x19, 0xb1, 0x1a, 0x2e, 0xc3, 0xd2, 0x84, 0x22, 0x64, + 0xf7, 0x76, 0x70, 0x63, 0xa7, 0x2c, 0xa5, 0x0c, 0xe7, 0x18, 0x4c, 0x78, 0x24, 0x46, 0x55, 0xbe, 0xbf, 0x2f, 0x29, + 0x72, 0xda, 0x96, 0x83, 0x2a, 0x84, 0x7d, 0x24, 0x51, 0x02, 0xb7, 0x22, 0x2d, 0x14, 0x29, 0x8b, 0xbf, 0x1d, 0xa0, + 0x0b, 0xbc, 0x80, 0xba, 0x1a, 0x75, 0xfb, 0xc3, 0x11, 0x0f, 0x1f, 0x99, 0xfa, 0xc0, 0x88, 0x25, 0x81, 0xda, 0x5e, + 0x66, 0xe9, 0x1d, 0xa8, 0xf0, 0x7b, 0xb8, 0x9a, 0x88, 0xfd, 0xdc, 0x92, 0xa2, 0x22, 0x1b, 0xe9, 0x0d, 0xad, 0xc1, + 0x23, 0xb4, 0xa6, 0x7c, 0xef, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, + 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0xef, + 0x55, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, 0xac, 0xd2, 0xd7, 0x24, 0x61, 0x4f, 0x0c, + 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, 0xd2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, + 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x57, 0xc4, 0x97, 0x23, 0x3c, 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, + 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, + 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, + 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, + 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, + 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, + 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, + 0x58, 0x1d, 0xf4, 0xfe, 0x32, 0x7e, 0xda, 0x33, 0x32, 0xf2, 0xb8, 0x75, 0x58, 0xfd, 0xaf, 0xbf, 0x42, 0x00, 0x1c, + 0x9e, 0x4d, 0xbd, 0xcb, 0x31, 0x64, 0x95, 0x65, 0x04, 0x92, 0x9f, 0x18, 0x7c, 0xf9, 0x02, 0xa0, 0xea, 0x33, 0x5d, + 0xab, 0xc9, 0x51, 0x7b, 0xcc, 0xa1, 0x2b, 0x06, 0x80, 0x6d, 0x58, 0xa2, 0xaa, 0x16, 0x36, 0x61, 0x71, 0xfb, 0x19, + 0x46, 0x73, 0xd9, 0xf4, 0x82, 0x06, 0xea, 0x11, 0x82, 0x5f, 0x5a, 0x0f, 0xad, 0xb5, 0x4c, 0x39, 0x74, 0x6d, 0x14, + 0x55, 0x36, 0xd4, 0x25, 0xac, 0xd6, 0x22, 0xaa, 0x89, 0x22, 0xe5, 0x92, 0x51, 0x14, 0x4b, 0x15, 0xec, 0x33, 0x71, + 0x07, 0x51, 0xf3, 0xb4, 0xd5, 0x56, 0xc1, 0xfe, 0x0e, 0x10, 0xd6, 0xc2, 0x5a, 0x48, 0x67, 0x50, 0x7b, 0xa7, 0x1f, + 0x29, 0x7f, 0x79, 0x21, 0xb7, 0x73, 0x0b, 0x45, 0xb8, 0x3d, 0x07, 0xe5, 0x4d, 0x5d, 0x95, 0x8a, 0x68, 0xb4, 0x04, + 0x4a, 0x99, 0x13, 0x44, 0x16, 0x20, 0x80, 0xe3, 0x06, 0x02, 0x9f, 0xd7, 0xf8, 0x04, 0x1a, 0x85, 0x40, 0x7e, 0x60, + 0x15, 0xae, 0x3d, 0xa4, 0xa5, 0xd6, 0x88, 0x28, 0x11, 0x3f, 0xba, 0x7a, 0x8e, 0xed, 0xab, 0xa7, 0xb1, 0xb6, 0x94, + 0x26, 0x88, 0x9f, 0x58, 0x6c, 0x21, 0x26, 0x88, 0xea, 0x10, 0x1d, 0xc1, 0x72, 0x42, 0x88, 0xc2, 0x1f, 0x42, 0x3f, + 0x35, 0xf0, 0x97, 0x6c, 0x59, 0xe4, 0x35, 0xc1, 0x62, 0x56, 0x0c, 0xd0, 0xaa, 0x08, 0x3c, 0xd3, 0xd9, 0x52, 0x99, + 0xd3, 0x3c, 0x3a, 0xb2, 0x83, 0xf3, 0xae, 0x83, 0xbd, 0xf4, 0x65, 0xec, 0x64, 0xd9, 0x34, 0x6a, 0x63, 0x43, 0x24, + 0xbc, 0x22, 0x7f, 0x95, 0xa5, 0xc6, 0x39, 0x32, 0x97, 0xeb, 0xbb, 0x2e, 0xee, 0xee, 0x68, 0x9b, 0xb0, 0x0a, 0x11, + 0xea, 0xb6, 0xa1, 0x72, 0x29, 0xcc, 0xc6, 0xa6, 0x69, 0x80, 0x2f, 0x14, 0x95, 0x4a, 0x55, 0x6a, 0x2b, 0x95, 0x9c, + 0xf0, 0xae, 0xaf, 0x6a, 0x91, 0xba, 0x22, 0xd8, 0xc6, 0x0c, 0xf5, 0x50, 0x6e, 0xd4, 0xd8, 0xd7, 0x1d, 0xab, 0xf4, + 0x0e, 0x13, 0xe4, 0x8c, 0xbc, 0xc8, 0xc1, 0x45, 0x49, 0x41, 0xe6, 0x6a, 0x08, 0xf3, 0x47, 0x0d, 0x9f, 0x16, 0x96, + 0x7b, 0x28, 0x01, 0xb3, 0xa3, 0x86, 0x97, 0x11, 0x02, 0x11, 0x97, 0xca, 0xbe, 0x62, 0xe2, 0xf7, 0x14, 0xcc, 0x92, + 0x09, 0xdd, 0x8b, 0x58, 0x18, 0xa1, 0x8d, 0x4f, 0x92, 0x64, 0xea, 0x69, 0x0a, 0x6e, 0xe4, 0x32, 0xcc, 0xd1, 0x08, + 0x2d, 0xf9, 0xc8, 0x81, 0xf4, 0xb5, 0x9c, 0x4a, 0xf0, 0x11, 0x75, 0x0a, 0x38, 0x9e, 0x9f, 0x17, 0xd6, 0x4f, 0x96, + 0x4b, 0xcc, 0x65, 0x6d, 0xfe, 0xcb, 0x8e, 0x8e, 0xc1, 0x2e, 0x4f, 0x13, 0xc7, 0xd5, 0x7f, 0x54, 0x25, 0xc5, 0xc3, + 0xcf, 0x69, 0x0e, 0x28, 0x82, 0x99, 0x3d, 0xc5, 0xf8, 0xd8, 0x67, 0x99, 0x02, 0xfe, 0x76, 0xbd, 0xb5, 0x64, 0x62, + 0x97, 0xb4, 0x9b, 0x2b, 0xe3, 0x97, 0xda, 0xb0, 0xe3, 0xe0, 0xdc, 0x00, 0x14, 0x67, 0x8d, 0x0e, 0xcb, 0x6b, 0xdd, + 0xb6, 0x2a, 0x54, 0xa0, 0xd6, 0xff, 0xd9, 0x2d, 0x4c, 0x79, 0x9b, 0x97, 0xca, 0xdb, 0x3c, 0x34, 0x01, 0x02, 0x91, + 0x19, 0xf2, 0xac, 0xe9, 0x98, 0x24, 0xee, 0x1d, 0x29, 0x69, 0xdf, 0x91, 0xe2, 0x47, 0xef, 0x48, 0xc8, 0xb7, 0x84, + 0x8e, 0xec, 0x4b, 0x4e, 0x4e, 0xa0, 0xcc, 0x60, 0x2f, 0xaf, 0x99, 0xec, 0x1f, 0xd0, 0x5e, 0x38, 0x97, 0xe5, 0x15, + 0xbf, 0x16, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, + 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, 0xf1, 0xf1, 0xd7, 0x1c, 0x45, 0x6c, 0xa5, 0x3c, 0x92, 0x2e, 0x54, + 0x62, 0x78, 0x69, 0xe0, 0x61, 0x76, 0x7c, 0x3c, 0xd9, 0x5d, 0xdd, 0x4f, 0x06, 0x83, 0x9d, 0xea, 0xdb, 0x2d, 0xaf, + 0x67, 0xbb, 0x39, 0x7b, 0xe0, 0xb7, 0xd3, 0x6d, 0xb0, 0x6f, 0x60, 0xdb, 0xdd, 0x5d, 0x89, 0xc3, 0x61, 0xf7, 0x82, + 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, + 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, + 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe5, 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, + 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, + 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xfa, + 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xf5, 0x6c, 0x33, + 0xf7, 0x5f, 0xac, 0xd8, 0x1d, 0x70, 0xa1, 0x28, 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, + 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, + 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, 0xd7, 0xfc, 0xa6, 0x39, 0x76, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, + 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0x95, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x57, 0x0b, + 0x39, 0xf3, 0xcc, 0x40, 0xdf, 0x56, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x6a, 0xa6, + 0x6d, 0x51, 0x97, 0xdf, 0xf6, 0x9e, 0xc9, 0x6f, 0x64, 0x60, 0x0b, 0x91, 0x14, 0x8e, 0xe3, 0x8b, 0xe7, 0x27, 0xfc, + 0x57, 0x2d, 0x8f, 0x5a, 0xed, 0x17, 0x4a, 0x7d, 0xfa, 0x8a, 0x8e, 0x68, 0xe2, 0x5e, 0xb4, 0x65, 0x58, 0xa3, 0xac, + 0xa9, 0xa5, 0xc3, 0x30, 0xae, 0x61, 0x5f, 0x1e, 0x38, 0xf4, 0x1d, 0x10, 0x68, 0xab, 0x54, 0x0a, 0xb4, 0x70, 0x0c, + 0xa3, 0x30, 0x0b, 0x29, 0x8f, 0x0b, 0xb3, 0x94, 0xf7, 0x58, 0xa0, 0xc5, 0xad, 0xba, 0xc7, 0xd4, 0x76, 0x0b, 0x22, + 0xac, 0xde, 0x32, 0xce, 0x2f, 0x1b, 0x55, 0xb8, 0x2d, 0x40, 0x51, 0x04, 0x65, 0xb0, 0x27, 0xb9, 0x6d, 0xa1, 0xa4, + 0xd9, 0x28, 0xac, 0xc5, 0x5d, 0x51, 0xee, 0x7a, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, 0x75, + 0x28, 0x17, 0xe9, 0x7f, 0x64, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xe7, 0x97, 0xf4, + 0x93, 0xc1, 0x32, 0x72, 0x4a, 0x7d, 0x1f, 0x8d, 0x6e, 0xd3, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, 0x0a, + 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, 0x26, + 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, 0x90, + 0xdc, 0xa9, 0x2b, 0x7f, 0x54, 0x4e, 0xfe, 0x13, 0x0d, 0x91, 0x57, 0x5c, 0x21, 0x56, 0x16, 0x5c, 0x62, 0x31, 0x54, + 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xcb, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, 0x11, + 0x3e, 0x6e, 0xad, 0x45, 0x08, 0x56, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, 0x14, + 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xa8, 0x48, 0xcf, 0x5f, 0x9a, 0x94, 0x5c, 0x1a, + 0x33, 0x3e, 0x88, 0x32, 0x12, 0x79, 0x1d, 0xde, 0x89, 0x69, 0x81, 0x7c, 0xa3, 0xc7, 0x0f, 0x82, 0x4b, 0x78, 0x37, + 0xe4, 0x5e, 0x01, 0xb6, 0x04, 0xec, 0x00, 0xf7, 0xca, 0x8c, 0x72, 0x9d, 0xd6, 0xf5, 0x5b, 0xeb, 0xa1, 0x18, 0x86, + 0xcf, 0x2c, 0x81, 0xed, 0x68, 0x1d, 0x1d, 0xe9, 0xe1, 0xc3, 0xff, 0xba, 0xaa, 0x39, 0xea, 0x54, 0x2e, 0x67, 0xc7, + 0x13, 0x96, 0x22, 0x66, 0xd0, 0xfd, 0x75, 0xfb, 0x4a, 0x00, 0xdd, 0x2e, 0x8b, 0x79, 0x36, 0xda, 0xc9, 0xbf, 0xa5, + 0x1b, 0x2b, 0x4a, 0x9b, 0x78, 0x97, 0xf5, 0xc6, 0xfe, 0x70, 0xf4, 0x97, 0x67, 0x5f, 0x26, 0x84, 0xaa, 0xb3, 0x61, + 0x6b, 0x1d, 0xe7, 0xf2, 0xbf, 0xfe, 0x3a, 0x26, 0x2b, 0x08, 0x0a, 0xc2, 0xb2, 0x53, 0x4c, 0x54, 0x30, 0x8a, 0x14, + 0x6b, 0x3e, 0x9e, 0xac, 0x51, 0x27, 0xbc, 0xf6, 0x97, 0x5a, 0x27, 0x4c, 0x8c, 0xac, 0x54, 0xfe, 0x9a, 0x55, 0xec, + 0x4e, 0x65, 0x16, 0x90, 0x79, 0x90, 0x4f, 0xd6, 0x46, 0x83, 0xb9, 0xe2, 0xf5, 0x6c, 0x3d, 0x97, 0xca, 0x67, 0x30, + 0xe5, 0x2c, 0x07, 0x27, 0x4b, 0x61, 0xf7, 0x24, 0x50, 0xb4, 0x66, 0xe8, 0xda, 0x9f, 0x62, 0xab, 0x5e, 0xa7, 0x55, + 0x0d, 0xf0, 0x80, 0x10, 0x03, 0x43, 0xed, 0xd5, 0xc2, 0x43, 0x6b, 0x01, 0xac, 0xfd, 0x51, 0xe9, 0x07, 0xe3, 0xc9, + 0x92, 0x2f, 0x90, 0x7f, 0x39, 0x72, 0xd4, 0xee, 0xfd, 0xbe, 0x77, 0x0f, 0x52, 0x70, 0xe4, 0x5a, 0x28, 0x90, 0x08, + 0x68, 0xc1, 0x37, 0xbe, 0xf2, 0xc1, 0xb8, 0x46, 0x6d, 0x35, 0x28, 0xa8, 0x1d, 0xdd, 0xf2, 0xd8, 0xd1, 0x3b, 0xdf, + 0x9f, 0xd0, 0x57, 0x2f, 0xb4, 0x70, 0xfc, 0x95, 0x33, 0x72, 0xcd, 0x56, 0x1d, 0x72, 0x44, 0x33, 0xe9, 0x10, 0x22, + 0x56, 0x6c, 0xcd, 0xae, 0x49, 0xe5, 0xdc, 0x39, 0x64, 0xa7, 0x8f, 0x50, 0xa5, 0xd7, 0x7a, 0x7c, 0x3b, 0x51, 0xba, + 0xdb, 0xe3, 0xdd, 0xe4, 0x5b, 0x36, 0x11, 0x31, 0x18, 0xd0, 0x06, 0xe1, 0x8c, 0xac, 0x43, 0xa4, 0xd2, 0x01, 0x42, + 0xe0, 0x98, 0x80, 0xa6, 0xff, 0xf8, 0x9a, 0x44, 0x01, 0x47, 0xda, 0x08, 0x59, 0xcb, 0x0e, 0x87, 0x1c, 0x34, 0xca, + 0xcd, 0x1f, 0x5e, 0xa1, 0x4e, 0x73, 0x60, 0x9e, 0x2e, 0x61, 0xcf, 0xc1, 0x23, 0xbd, 0x38, 0x3e, 0xd2, 0xff, 0x3b, + 0x9a, 0xa8, 0xf1, 0x7f, 0xae, 0x89, 0x52, 0x5a, 0x24, 0x47, 0xb5, 0xf4, 0x4d, 0xea, 0x28, 0xb8, 0xc8, 0x3b, 0x6a, + 0x21, 0x7b, 0x96, 0x8d, 0x1b, 0xd5, 0xbc, 0xff, 0x5f, 0x2b, 0xf3, 0xff, 0x35, 0xad, 0x0c, 0x53, 0xb2, 0x63, 0xa9, + 0x66, 0x1e, 0x68, 0x15, 0xc3, 0xec, 0x67, 0x92, 0x10, 0x19, 0x2e, 0x0d, 0xf8, 0x51, 0x05, 0xfb, 0x38, 0xad, 0xd6, + 0x59, 0xb8, 0x43, 0x25, 0xea, 0xad, 0xb8, 0x4b, 0xf3, 0x97, 0xf5, 0xbf, 0x45, 0x59, 0xc0, 0xd4, 0xbe, 0x2b, 0xd3, + 0x38, 0x20, 0x0b, 0x7f, 0x16, 0x96, 0x38, 0xb9, 0xb1, 0x8d, 0x3f, 0xcb, 0xf1, 0xb4, 0x5f, 0x75, 0x66, 0x1e, 0x48, + 0xa0, 0x06, 0xe2, 0x8f, 0x9c, 0xcb, 0xca, 0xe2, 0x01, 0xa1, 0x9b, 0x7f, 0x28, 0xcb, 0xa2, 0xf4, 0x7a, 0x9f, 0x92, + 0xb4, 0x3a, 0x5b, 0x89, 0x3a, 0x29, 0x62, 0x05, 0x65, 0x93, 0x02, 0x8c, 0x3e, 0xac, 0x3c, 0x11, 0x07, 0x67, 0x08, + 0xd4, 0x70, 0x56, 0x27, 0x21, 0x00, 0x0d, 0x2b, 0x84, 0xfd, 0x33, 0x68, 0xe1, 0x59, 0x18, 0x87, 0x6b, 0x80, 0xc9, + 0x49, 0xab, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, 0x88, 0x47, 0x3d, 0x45, 0xc9, 0xf2, 0x26, 0x77, 0xe5, 0x5c, 0x7f, + 0xff, 0x07, 0x05, 0xb0, 0x1b, 0x30, 0xdb, 0x16, 0xd8, 0x01, 0x40, 0x82, 0x02, 0xd9, 0x42, 0x9d, 0x46, 0x67, 0x6a, + 0xa9, 0xc0, 0x7b, 0xae, 0x07, 0xf8, 0x9b, 0x1c, 0xb0, 0x8c, 0xeb, 0x42, 0x06, 0x8c, 0x20, 0x80, 0x11, 0x38, 0x28, + 0x01, 0x43, 0x67, 0x88, 0xdb, 0xaa, 0x9c, 0xb5, 0xd0, 0x5c, 0xe9, 0xb6, 0xe4, 0xa6, 0x51, 0xce, 0x56, 0x22, 0x80, + 0xbe, 0xba, 0x29, 0x71, 0xba, 0x5c, 0xb6, 0x92, 0xb0, 0x6f, 0xdf, 0xb7, 0x53, 0x45, 0x1e, 0x1f, 0xa5, 0x21, 0xaf, + 0xc0, 0x93, 0x8c, 0x23, 0x49, 0x94, 0x08, 0xde, 0xe4, 0x8d, 0x19, 0x87, 0x97, 0x6d, 0xca, 0xa9, 0xbd, 0x59, 0x2f, + 0x00, 0xe7, 0x09, 0xda, 0x32, 0xc0, 0x58, 0xc0, 0xe0, 0x5c, 0x88, 0x25, 0x4f, 0x11, 0xfc, 0xd2, 0x89, 0x14, 0xc6, + 0x5d, 0x0e, 0xc3, 0x3c, 0x28, 0x7a, 0x97, 0xd4, 0x1f, 0xfd, 0x3e, 0x6a, 0x93, 0xc1, 0x10, 0x54, 0x02, 0xa8, 0xac, + 0x1b, 0x24, 0x06, 0x56, 0xa5, 0x85, 0xc4, 0x25, 0xc4, 0xcb, 0x7c, 0x35, 0xad, 0xa3, 0xe0, 0x7d, 0x3d, 0x21, 0x84, + 0x13, 0x8c, 0x0f, 0x71, 0x03, 0x04, 0x0c, 0x56, 0x71, 0x81, 0x41, 0xf2, 0x5c, 0xa2, 0xfb, 0xe3, 0xf9, 0x8e, 0x01, + 0xae, 0x9c, 0xf7, 0x54, 0xbb, 0x7a, 0x60, 0x2f, 0x57, 0xe9, 0x92, 0x11, 0xc2, 0x8a, 0xff, 0x8b, 0xc8, 0xfb, 0x76, + 0x98, 0x80, 0xda, 0x46, 0xfe, 0x18, 0x24, 0xe6, 0x32, 0x51, 0x04, 0xf1, 0x28, 0x2b, 0x58, 0x92, 0x06, 0x9b, 0x51, + 0x92, 0x82, 0x46, 0x13, 0x63, 0xc8, 0x54, 0x68, 0x87, 0xa4, 0xd1, 0x6c, 0x4c, 0xf6, 0x31, 0xe4, 0x35, 0x5c, 0x2c, + 0x16, 0x78, 0xdf, 0xcf, 0x42, 0x75, 0xb0, 0x2d, 0xcd, 0x21, 0xe0, 0x24, 0xc1, 0x9e, 0xba, 0x22, 0x25, 0x61, 0x36, + 0xfa, 0x14, 0x72, 0x6e, 0x40, 0xc7, 0x49, 0x63, 0xa8, 0x3e, 0x30, 0x09, 0xaf, 0x22, 0x74, 0x52, 0x56, 0x08, 0x0b, + 0xb8, 0x6f, 0x64, 0x34, 0x5a, 0x49, 0x83, 0xc0, 0xdb, 0x0c, 0x5b, 0x81, 0x4d, 0x68, 0xf8, 0xcb, 0xcc, 0xc3, 0xb4, + 0x9a, 0x95, 0x60, 0xce, 0x37, 0x50, 0x89, 0xf1, 0x64, 0x79, 0xc5, 0x37, 0x2e, 0x56, 0x62, 0x32, 0x5b, 0xce, 0x27, + 0x6b, 0x49, 0x35, 0x97, 0x7b, 0x6b, 0x96, 0xb1, 0x25, 0xec, 0x1f, 0x06, 0x86, 0xd2, 0x81, 0x1d, 0x4d, 0x35, 0x6d, + 0x12, 0x60, 0x32, 0x9d, 0x73, 0x3e, 0xbc, 0x44, 0x34, 0x59, 0x9d, 0xba, 0x93, 0xa9, 0x6a, 0x07, 0xd7, 0xe4, 0x4c, + 0x4e, 0x8f, 0xd4, 0x53, 0xad, 0x7b, 0xc9, 0x47, 0xdb, 0x61, 0x35, 0xda, 0xfa, 0x01, 0xb8, 0x75, 0x0a, 0x3b, 0x7d, + 0x37, 0xac, 0x46, 0x3b, 0x5f, 0xc3, 0xee, 0x92, 0x42, 0xa0, 0xfa, 0xb3, 0xac, 0xc9, 0x5c, 0xbc, 0x2e, 0x1e, 0xbc, + 0x82, 0x3d, 0xf7, 0x07, 0xfa, 0x57, 0xc9, 0x9e, 0xfb, 0x36, 0x93, 0xeb, 0x9f, 0x69, 0xd7, 0x68, 0xcc, 0x74, 0xbc, + 0x76, 0x05, 0x56, 0x68, 0x80, 0xfc, 0x82, 0x1d, 0xed, 0x6d, 0x0e, 0x02, 0x01, 0xba, 0x97, 0xe0, 0x28, 0x0a, 0x88, + 0x9a, 0x56, 0x95, 0x47, 0xa7, 0x7b, 0x7f, 0x8f, 0x6f, 0x94, 0x80, 0x4d, 0x9e, 0x5a, 0xf7, 0x96, 0xb1, 0x7f, 0x38, + 0x40, 0x08, 0xbd, 0x9c, 0x7e, 0xa3, 0x2d, 0xab, 0x47, 0x3b, 0x96, 0xfb, 0x86, 0x51, 0x4f, 0xc1, 0x18, 0x86, 0x2e, + 0xac, 0x62, 0x24, 0xcf, 0x80, 0xac, 0xf1, 0x1b, 0x44, 0x17, 0xb0, 0xe8, 0xf5, 0x5e, 0x1f, 0xd1, 0x20, 0x02, 0x2a, + 0xbd, 0xe6, 0x2f, 0x45, 0x3e, 0x57, 0x85, 0xe8, 0xbd, 0xb7, 0x76, 0xde, 0xcc, 0x48, 0x96, 0x49, 0x23, 0xd5, 0x6e, + 0x65, 0xb1, 0xae, 0xbc, 0xd9, 0x09, 0xe9, 0x62, 0x8e, 0xa1, 0x32, 0x78, 0x1c, 0x80, 0xd2, 0xf3, 0x6f, 0xa1, 0x57, + 0x32, 0x64, 0x9a, 0x25, 0x9a, 0xd9, 0x5d, 0xe3, 0x4f, 0x56, 0xa9, 0x17, 0x23, 0x62, 0x36, 0xb0, 0x85, 0xb8, 0x2d, + 0x2a, 0xdd, 0x16, 0x85, 0xb2, 0x45, 0x91, 0x3e, 0xd4, 0xce, 0x74, 0x67, 0x16, 0x3e, 0xab, 0x4c, 0xfb, 0xde, 0x66, + 0x66, 0x6c, 0x80, 0xb6, 0x8b, 0xf0, 0x0d, 0x74, 0xa0, 0x42, 0xc8, 0x7f, 0x40, 0x44, 0x24, 0x02, 0x76, 0x39, 0x75, + 0x27, 0x36, 0x1d, 0x92, 0x79, 0x88, 0x59, 0xa1, 0x46, 0x79, 0xc9, 0x93, 0xa3, 0x01, 0xa9, 0x08, 0x75, 0xbb, 0xdf, + 0x3f, 0x5f, 0xba, 0xa0, 0xf6, 0x6b, 0x8a, 0x1d, 0xa3, 0x9b, 0x02, 0xce, 0x05, 0x8f, 0xf2, 0x9e, 0x7b, 0xe7, 0x80, + 0xe6, 0xd8, 0x9e, 0x22, 0x6b, 0xc0, 0xe9, 0x6d, 0x17, 0x02, 0x6c, 0x9f, 0x35, 0x5b, 0xfb, 0x93, 0xd5, 0x55, 0x34, + 0xf5, 0x4a, 0x3e, 0xd3, 0x5d, 0x94, 0xb8, 0x5d, 0x14, 0xcb, 0x2e, 0xda, 0x34, 0x10, 0xec, 0xb8, 0xf2, 0x03, 0xe0, + 0x0d, 0x8d, 0xfa, 0xfd, 0xb2, 0xd5, 0xb3, 0x27, 0x5f, 0x3b, 0xee, 0xd9, 0xcc, 0x67, 0xa5, 0xe9, 0xd9, 0x5f, 0x53, + 0xb7, 0x67, 0xe5, 0x64, 0x2f, 0x3a, 0x27, 0xfb, 0x74, 0x36, 0x0f, 0x04, 0x97, 0x3b, 0xf7, 0x79, 0x3e, 0xd5, 0xd3, + 0xae, 0xf2, 0x83, 0xd6, 0x10, 0x99, 0x2f, 0x7c, 0xaa, 0xba, 0xd7, 0x15, 0x2c, 0x60, 0x09, 0xee, 0xd6, 0x4b, 0xf3, + 0x5f, 0xb1, 0xfb, 0x7b, 0x41, 0x2f, 0xcd, 0x7f, 0xa3, 0x3f, 0x29, 0x80, 0x03, 0xd0, 0x98, 0xda, 0x2d, 0xf0, 0x10, + 0x43, 0x05, 0x85, 0xbb, 0x59, 0x39, 0xf7, 0x6a, 0x80, 0xc3, 0x24, 0x7d, 0x43, 0xab, 0x57, 0x5a, 0xec, 0x7a, 0x99, + 0xec, 0x15, 0xe0, 0xa1, 0x0a, 0x79, 0x78, 0x38, 0x44, 0x1d, 0xc3, 0x0e, 0xea, 0x08, 0x18, 0xf6, 0x10, 0x1a, 0x5b, + 0xe0, 0xf9, 0xf8, 0x29, 0xe3, 0x7b, 0x01, 0x6a, 0x23, 0x84, 0xc7, 0xab, 0x45, 0x19, 0x62, 0xcb, 0xde, 0x22, 0x95, + 0xd4, 0xcf, 0x02, 0x51, 0x46, 0xab, 0x80, 0xb6, 0xda, 0x63, 0x96, 0xc6, 0x1b, 0x08, 0x15, 0x4b, 0x7d, 0x0c, 0xa1, + 0x81, 0xc3, 0xef, 0x70, 0x00, 0x09, 0xbe, 0xe4, 0x9a, 0x6c, 0xee, 0x6d, 0x7e, 0x4f, 0xfb, 0xfc, 0xe1, 0x70, 0x7e, + 0x89, 0xa0, 0x74, 0x29, 0x7c, 0xa4, 0x12, 0x51, 0x3d, 0xc5, 0x4d, 0x09, 0xd9, 0x2c, 0x59, 0xe9, 0x07, 0xbf, 0xaa, + 0x5f, 0x00, 0x20, 0x0b, 0x81, 0x36, 0x91, 0xd9, 0x9f, 0xce, 0x54, 0x74, 0x01, 0x70, 0x88, 0x3f, 0x7e, 0x82, 0xe8, + 0x1b, 0x5a, 0xa6, 0xe5, 0xe3, 0x84, 0x87, 0xa0, 0xb5, 0x25, 0x9d, 0x44, 0xac, 0x14, 0xd8, 0x10, 0x09, 0xdf, 0xef, + 0x9f, 0xc7, 0x92, 0x0e, 0x34, 0x6a, 0x75, 0x6f, 0xdc, 0xea, 0x5e, 0xf9, 0xba, 0xee, 0xe4, 0xc6, 0x07, 0x45, 0xfb, + 0x6c, 0xde, 0xa8, 0x7c, 0xdf, 0xd6, 0x39, 0xbb, 0xd3, 0xbd, 0x23, 0xe7, 0xc4, 0xb7, 0xf7, 0x10, 0x8a, 0x1e, 0x9a, + 0x22, 0xcb, 0x92, 0x30, 0xa0, 0xb5, 0x76, 0xed, 0x59, 0x46, 0x07, 0xaf, 0x7d, 0x43, 0x88, 0xc8, 0x53, 0x7c, 0x12, + 0x72, 0x8b, 0xe3, 0x83, 0x02, 0xfd, 0x33, 0xe3, 0xcf, 0x9c, 0xf8, 0x61, 0xab, 0x5f, 0x00, 0xe7, 0xa6, 0x7b, 0xef, + 0x4e, 0xcc, 0x7a, 0x0c, 0xa5, 0x6c, 0xfc, 0xdf, 0xef, 0x13, 0x59, 0xa0, 0xd3, 0x11, 0x0d, 0x03, 0xc1, 0x5d, 0x54, + 0xff, 0xf7, 0x8a, 0xd7, 0x3d, 0x6b, 0x75, 0xbe, 0xfc, 0xd4, 0xe9, 0x49, 0xaf, 0x5e, 0xc6, 0x3d, 0xa0, 0x42, 0x07, + 0x08, 0xe7, 0x75, 0xbf, 0x61, 0xbb, 0x6f, 0x7e, 0x79, 0x77, 0xf4, 0x32, 0xb0, 0x49, 0x91, 0xd8, 0x56, 0xf2, 0x59, + 0x0f, 0x14, 0x7e, 0x3d, 0xd6, 0xab, 0x8b, 0x75, 0x8f, 0xf5, 0x50, 0x0b, 0x88, 0x1e, 0x16, 0xa0, 0xfe, 0xeb, 0xd9, + 0xa7, 0xa1, 0x70, 0x90, 0x8d, 0x53, 0x05, 0x8a, 0x2c, 0xf8, 0x0b, 0x31, 0x5a, 0x17, 0x04, 0x88, 0x6c, 0x09, 0x69, + 0xd5, 0xc9, 0xec, 0x71, 0xa9, 0x25, 0x19, 0x7c, 0x13, 0x90, 0xd9, 0x81, 0x95, 0x13, 0x94, 0x8e, 0x5b, 0x03, 0xae, + 0x6c, 0xf1, 0x68, 0xb7, 0x3f, 0x0d, 0xb2, 0xb3, 0xe6, 0xa4, 0xd1, 0x3e, 0xec, 0xd3, 0x3c, 0x40, 0x20, 0x92, 0xa9, + 0x08, 0x72, 0xcd, 0xbd, 0x25, 0x7d, 0x74, 0x38, 0xe7, 0x85, 0xfc, 0x73, 0x2a, 0x75, 0x88, 0x43, 0x89, 0x35, 0x10, + 0xa8, 0x3c, 0x43, 0x95, 0xc3, 0x06, 0x39, 0xfe, 0xd9, 0x91, 0xcc, 0x24, 0x26, 0x8b, 0xdc, 0xad, 0x99, 0x0a, 0x3f, + 0x10, 0x7c, 0xcc, 0x72, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x02, 0x7f, 0x4c, 0xe1, 0x57, 0x3c, + 0x85, 0x9d, 0x76, 0xbf, 0x2e, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, + 0x3f, 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x65, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x06, + 0x15, 0x5b, 0x17, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xaa, 0x51, 0x5a, 0xfd, 0xa8, + 0x7f, 0x02, 0xf3, 0x36, 0x15, 0xa3, 0x5a, 0xc5, 0xe4, 0x37, 0xfa, 0xfd, 0x62, 0xd0, 0xfa, 0x90, 0xc1, 0x47, 0xaf, + 0x4d, 0x83, 0x3f, 0x3a, 0x0d, 0x76, 0x98, 0x68, 0x04, 0x40, 0x32, 0xa7, 0x96, 0x3c, 0x14, 0xfd, 0x11, 0xe4, 0x58, + 0xa3, 0xca, 0x29, 0x18, 0xac, 0xff, 0x78, 0xb4, 0x03, 0x53, 0x2f, 0x8e, 0xb6, 0x64, 0x07, 0xad, 0x7c, 0x03, 0xdc, + 0xaf, 0x91, 0x2d, 0x66, 0x39, 0x40, 0xb3, 0xd7, 0x88, 0x8c, 0x4f, 0x5e, 0x00, 0x63, 0xb6, 0xce, 0xc2, 0x48, 0xc4, + 0xc1, 0x58, 0x35, 0x66, 0xcc, 0xc0, 0xc0, 0x05, 0xba, 0x96, 0x49, 0x49, 0x1a, 0xd2, 0xc1, 0x80, 0x95, 0xb2, 0x85, + 0x03, 0x5e, 0x34, 0xc7, 0xed, 0x78, 0xd3, 0xa2, 0xf1, 0xc0, 0x76, 0xb1, 0xfd, 0xfd, 0xf7, 0xc5, 0xf6, 0x3a, 0xdc, + 0x92, 0x5e, 0x21, 0x67, 0x09, 0xfd, 0xfc, 0x51, 0xf6, 0x59, 0xc3, 0xc9, 0xa9, 0xd0, 0x0c, 0x2d, 0x45, 0x42, 0x29, + 0xde, 0xe9, 0x49, 0x81, 0xb1, 0x8c, 0x85, 0xbf, 0x07, 0xce, 0xe9, 0x42, 0x11, 0xb9, 0x03, 0xc7, 0xf1, 0x0d, 0x54, + 0x30, 0x6a, 0x38, 0x78, 0x19, 0xc3, 0xb6, 0x28, 0x66, 0x21, 0xe1, 0x14, 0xc2, 0xc5, 0x2a, 0xeb, 0xf7, 0xe5, 0x2f, + 0xea, 0xa2, 0x8b, 0x4c, 0xd6, 0x7d, 0x12, 0x8e, 0xcc, 0x58, 0x4e, 0xbd, 0x90, 0x3c, 0xef, 0x79, 0x32, 0x4d, 0x9e, + 0xe5, 0x41, 0x04, 0x90, 0xcf, 0xe1, 0x7d, 0x98, 0x66, 0x60, 0x95, 0x26, 0xe5, 0x47, 0x28, 0x7d, 0xf1, 0x79, 0xe5, + 0x07, 0x3a, 0x7b, 0x6e, 0x92, 0xe1, 0xcd, 0xaa, 0xf5, 0x26, 0xb5, 0xae, 0x8b, 0x07, 0xfc, 0x8b, 0x33, 0xd8, 0x38, + 0xd7, 0x99, 0xe0, 0xc0, 0x8b, 0xa4, 0xd6, 0x6b, 0xc6, 0x5f, 0x64, 0xb8, 0x2e, 0x55, 0x1b, 0x7d, 0x14, 0xa2, 0x73, + 0xc8, 0x54, 0x80, 0x42, 0x91, 0xf6, 0x0f, 0x4a, 0xad, 0x4c, 0x2a, 0x6d, 0x24, 0x80, 0xee, 0x61, 0xd2, 0x60, 0x8b, + 0xa1, 0x8c, 0xa5, 0x49, 0x94, 0x3b, 0x0d, 0xe2, 0xca, 0xfe, 0x5c, 0x49, 0x1c, 0x5a, 0x16, 0xc9, 0xbf, 0x77, 0x3d, + 0x7d, 0x85, 0xd4, 0x9d, 0x2c, 0x90, 0x19, 0xe3, 0x65, 0x1e, 0x7f, 0x02, 0xc2, 0x6c, 0xd0, 0x46, 0x45, 0x21, 0x84, + 0x6c, 0x10, 0x83, 0xc6, 0xcb, 0x3c, 0xfe, 0x5e, 0xd1, 0x78, 0xc8, 0x47, 0x91, 0xaf, 0xfe, 0x2a, 0xf5, 0x5f, 0xa1, + 0xcf, 0x4c, 0xf0, 0x08, 0xd5, 0x44, 0xff, 0xee, 0xf9, 0xec, 0x1e, 0xd4, 0x86, 0x51, 0x98, 0x99, 0xf2, 0x2b, 0xdf, + 0x14, 0x67, 0xaf, 0xbf, 0xa2, 0xab, 0x6c, 0xeb, 0x7e, 0xf4, 0xf1, 0x88, 0xc0, 0xda, 0x18, 0x5d, 0x71, 0x63, 0x00, + 0x39, 0x4c, 0xde, 0xaf, 0x28, 0x2d, 0x87, 0x34, 0x08, 0x1d, 0x34, 0x04, 0xbd, 0x92, 0xe8, 0x03, 0x89, 0x45, 0x8c, + 0xe1, 0x85, 0x78, 0x46, 0x6a, 0x32, 0xd1, 0x10, 0xaf, 0x88, 0xfd, 0x10, 0x2d, 0x39, 0x35, 0xd1, 0x8d, 0x30, 0xc5, + 0x40, 0x62, 0x67, 0x90, 0x9c, 0x24, 0xb5, 0xf2, 0x8b, 0x67, 0x92, 0xb0, 0xc4, 0xce, 0x43, 0x0c, 0x26, 0xb5, 0x74, + 0xa7, 0x37, 0x55, 0x7a, 0x77, 0xa4, 0xe5, 0xa0, 0x7d, 0x00, 0x76, 0x29, 0xe9, 0xfd, 0x93, 0x42, 0x11, 0x1f, 0xc2, + 0x38, 0x86, 0xf0, 0x2d, 0xa2, 0xba, 0x02, 0xe7, 0x5a, 0x81, 0xc6, 0x6a, 0xe0, 0xa1, 0x99, 0x55, 0xf3, 0x21, 0xa7, + 0x9f, 0x4a, 0xcb, 0x1f, 0x23, 0x1a, 0x1b, 0xad, 0x9b, 0xc3, 0x61, 0x4f, 0xab, 0x5e, 0x3a, 0x07, 0x5d, 0x36, 0x93, + 0x98, 0xb8, 0x81, 0x74, 0xfd, 0xe8, 0x37, 0x13, 0xf6, 0x22, 0x2a, 0xe4, 0x52, 0x08, 0x0a, 0x5a, 0x1d, 0x08, 0x1c, + 0x0a, 0x6f, 0x51, 0xe6, 0x8b, 0x98, 0x36, 0x10, 0x06, 0x9f, 0x1f, 0xc8, 0xcf, 0x37, 0x05, 0xa9, 0xd8, 0xb1, 0xae, + 0xfd, 0xfe, 0xa6, 0xf4, 0x00, 0x4f, 0xce, 0x24, 0x79, 0xda, 0x0c, 0x61, 0x45, 0x00, 0x8d, 0x59, 0x4d, 0x16, 0x27, + 0x5c, 0x99, 0xc3, 0x8f, 0x95, 0x57, 0xb2, 0x94, 0xa9, 0xf3, 0x54, 0x2f, 0x80, 0xa8, 0xe3, 0x0d, 0x5a, 0x91, 0xfa, + 0x15, 0x3a, 0x7b, 0xcd, 0x4a, 0xc8, 0x78, 0x78, 0xce, 0x79, 0x3a, 0x7a, 0x60, 0x09, 0x8f, 0xf0, 0xaf, 0x64, 0xa2, + 0x0f, 0xbf, 0x07, 0x0e, 0x37, 0xe3, 0x84, 0x47, 0x6e, 0xb3, 0xf7, 0x55, 0xb8, 0x82, 0x9b, 0x69, 0x01, 0x48, 0x6e, + 0x41, 0xd2, 0x04, 0x94, 0x90, 0xc8, 0x84, 0xcc, 0x9a, 0x92, 0x9f, 0x5b, 0xda, 0x06, 0x6b, 0x98, 0x74, 0x1e, 0xf0, + 0xa2, 0xd5, 0x47, 0xab, 0x89, 0x76, 0x99, 0xe5, 0xf3, 0x21, 0xce, 0x50, 0xcd, 0x71, 0x77, 0x06, 0x3f, 0x07, 0xbc, + 0x62, 0x55, 0x93, 0x8e, 0x76, 0x03, 0x2e, 0x3c, 0xb9, 0xce, 0xd3, 0xd1, 0x16, 0x7f, 0xc9, 0xfd, 0x01, 0xa0, 0x83, + 0xa9, 0x4b, 0xe0, 0x4f, 0xd5, 0x56, 0x53, 0xa9, 0x5f, 0x5a, 0xfb, 0x75, 0xdd, 0x59, 0xad, 0xdc, 0xb3, 0x2e, 0x43, + 0x7b, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, + 0x82, 0x7b, 0xc9, 0x5f, 0xec, 0x11, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, + 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xb1, 0x34, 0x26, 0x45, 0x05, 0xe9, 0x9c, 0x0e, 0x37, 0xaf, 0x8e, 0xf3, 0x84, 0x65, 0x7c, 0xdc, 0x3e, 0x53, 0x20, 0xc4, 0x16, 0xcf, 0x90, - 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x3c, 0xd6, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, - 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1b, 0xfe, 0x25, 0x43, 0x75, 0x77, 0x08, - 0x4c, 0x6c, 0xd9, 0x91, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x5b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, - 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x15, 0x5e, 0x2e, 0x5b, 0x79, 0x3c, 0x26, 0xd6, 0x5d, 0xd8, 0xd1, - 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0x54, 0x66, 0x17, 0x12, 0x83, 0x9c, 0xa5, 0xfa, - 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xf9, 0x69, 0x9f, 0x8a, 0xd1, 0x46, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, - 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x4a, 0x1f, 0xc7, 0xc7, 0xa3, 0x14, 0x33, - 0xae, 0x4f, 0xc4, 0x8c, 0xeb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xe3, 0xf1, 0x9a, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, - 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4d, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x4d, 0xea, 0x65, 0xe4, - 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x72, 0xda, 0xad, 0x4b, 0x26, - 0xec, 0x2d, 0x25, 0x97, 0x56, 0x79, 0xf9, 0x74, 0xeb, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, + 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x38, 0xd4, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, + 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1a, 0xfe, 0x2e, 0x43, 0x75, 0x77, 0x08, + 0x4c, 0x6c, 0xd9, 0x81, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x1b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, + 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x11, 0x5e, 0x25, 0x5b, 0x79, 0x38, 0x24, 0xd6, 0x5d, 0xd8, 0xd1, + 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0xe4, 0x66, 0x17, 0x12, 0x83, 0x8a, 0xa5, 0xfa, + 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xd5, 0x71, 0x9f, 0x8a, 0xd1, 0x5a, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, + 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x5c, 0x1f, 0xc7, 0x87, 0x83, 0x14, 0x33, + 0x2e, 0x8f, 0xc4, 0x8c, 0xcb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xc3, 0xe1, 0x92, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, + 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4b, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x75, 0xea, 0x65, 0xe4, + 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x2a, 0xda, 0xad, 0x4b, 0x26, + 0xec, 0x2d, 0xa5, 0x92, 0x56, 0x79, 0xf9, 0x74, 0xe3, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, 0x12, 0xb5, 0x32, 0x4c, 0x16, 0xce, 0x4b, 0xa6, 0x9e, 0x0c, 0x78, 0xcc, 0x4a, 0x1e, 0xc9, 0x4e, 0x6f, 0x0c, 0x82, - 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x7c, 0x95, 0x0b, 0x0c, 0xb7, 0xdb, 0xb0, 0xad, - 0xaa, 0xb3, 0xdc, 0xd4, 0x72, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0xb7, 0x10, 0x8c, - 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x03, 0x96, 0xd2, 0xd1, 0x9e, 0x97, - 0xa8, 0x52, 0xf8, 0x9b, 0xe0, 0x87, 0x30, 0x8e, 0x7f, 0x28, 0x76, 0xea, 0x40, 0xbc, 0x2b, 0x76, 0x48, 0xfb, 0x22, + 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x74, 0x95, 0x0b, 0x0c, 0xb7, 0x5b, 0xb3, 0x8d, + 0xaa, 0xb3, 0xdc, 0xd4, 0x2a, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0x37, 0x10, 0x8c, + 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x05, 0x96, 0xd2, 0xd1, 0x8e, 0x97, + 0xa8, 0x52, 0xf8, 0xbb, 0xe0, 0xfb, 0x30, 0x8e, 0xbf, 0x2f, 0xb6, 0xea, 0x40, 0xbc, 0x2d, 0xb6, 0x48, 0xfb, 0x22, 0xff, 0x42, 0x1c, 0xf0, 0x5a, 0xd7, 0x94, 0xd7, 0xd6, 0x9c, 0x06, 0xb6, 0x86, 0x91, 0x92, 0xc2, 0xb9, 0xf9, 0xf3, - 0x78, 0xa4, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x45, 0x09, 0x7e, 0x13, - 0xf2, 0xaf, 0xe3, 0x51, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0x3b, 0x7c, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, + 0x70, 0xa0, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x44, 0x09, 0x8e, 0x5c, + 0xf2, 0xaf, 0xc3, 0x41, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0xdb, 0x7f, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, 0x24, 0xff, 0x6a, 0x9a, 0x79, 0xc3, 0x64, 0xcd, 0x14, 0x8e, 0x43, 0xc3, 0x08, 0x69, 0x40, 0xb7, 0x41, 0x6d, 0x78, - 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0xd7, 0x13, 0x71, 0x49, 0x97, 0x24, 0xf5, 0x54, 0x42, - 0x49, 0x08, 0x76, 0xed, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, - 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xcb, - 0x79, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8b, 0x6d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, - 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xcc, 0xe5, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, - 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0xbf, 0xaa, 0x6c, 0x6c, 0x05, 0xe4, 0x90, 0x64, 0xb2, 0x58, 0x8d, 0xee, - 0xc4, 0xb2, 0x28, 0xc5, 0xcf, 0x58, 0x0f, 0xd7, 0x6c, 0xe1, 0x3e, 0x03, 0x42, 0xfb, 0x89, 0xd2, 0xde, 0x44, 0x9a, - 0xa0, 0x7b, 0xc5, 0xd6, 0x00, 0x32, 0x80, 0xa2, 0xae, 0x76, 0xeb, 0x73, 0x7e, 0x8e, 0xa4, 0x19, 0x0e, 0xa3, 0xdb, - 0xa7, 0xab, 0x60, 0x35, 0xb8, 0x46, 0xad, 0xf4, 0x35, 0x8b, 0x5b, 0x18, 0x54, 0x07, 0xb3, 0x84, 0x83, 0x9a, 0x59, - 0x6b, 0x23, 0x10, 0x4c, 0xf6, 0x50, 0x90, 0x33, 0x57, 0xb0, 0x0f, 0x0a, 0xd6, 0x92, 0xd7, 0xc1, 0xe1, 0xd6, 0xbe, - 0xac, 0x14, 0x57, 0xcf, 0xae, 0x92, 0xd6, 0x85, 0xa5, 0xbc, 0x7a, 0xd6, 0x80, 0xc1, 0xe5, 0x04, 0x9b, 0x2a, 0xf7, - 0x27, 0x5b, 0x00, 0xdd, 0x0a, 0x29, 0xe2, 0x45, 0x29, 0x6c, 0x5b, 0xf9, 0xcc, 0x09, 0x1b, 0x6c, 0xd9, 0x03, 0xdc, - 0x2b, 0x83, 0x92, 0xc1, 0x85, 0x18, 0xb7, 0x9b, 0x7d, 0x80, 0x2b, 0x18, 0x0a, 0x63, 0x1b, 0xfe, 0x3a, 0xf3, 0x22, - 0x25, 0xe0, 0x66, 0x88, 0xf2, 0xb5, 0x85, 0x93, 0x49, 0x4f, 0xae, 0x25, 0x8b, 0x01, 0x0b, 0x1a, 0x7c, 0x47, 0xad, - 0xbf, 0x33, 0xf9, 0x37, 0x9e, 0x1e, 0xfa, 0xc1, 0xe7, 0xcc, 0x5b, 0xfa, 0xec, 0x75, 0x2e, 0xa3, 0x35, 0x49, 0x94, - 0x57, 0x0f, 0x97, 0x20, 0x37, 0x2c, 0x47, 0x0f, 0x6c, 0x09, 0xe2, 0xc4, 0x72, 0x94, 0x50, 0x46, 0x57, 0xb8, 0x57, - 0x99, 0x2d, 0x13, 0x81, 0x14, 0x07, 0x96, 0x52, 0xee, 0x2d, 0x36, 0xc1, 0x12, 0xf7, 0x27, 0x92, 0x0b, 0x28, 0x79, - 0x00, 0xe5, 0x4a, 0x01, 0x01, 0x9f, 0x0e, 0xa0, 0x7c, 0x29, 0x2f, 0xc2, 0x9f, 0x38, 0x51, 0x83, 0xe5, 0xe8, 0xa1, - 0x61, 0x7f, 0xf5, 0x42, 0xcb, 0xfe, 0xb0, 0xd2, 0x9a, 0x86, 0x35, 0x5f, 0xc1, 0xb4, 0x98, 0xb8, 0x7d, 0xb9, 0xb6, - 0xab, 0xe2, 0xb3, 0xb5, 0x3a, 0xbb, 0xa9, 0x21, 0x09, 0xfb, 0x8a, 0xac, 0x02, 0x1c, 0xac, 0x8a, 0xb8, 0x67, 0x59, - 0x1e, 0xc2, 0xe8, 0xcf, 0x6d, 0x5a, 0x0a, 0x0b, 0x55, 0xd2, 0x3f, 0x34, 0xa5, 0x40, 0x2a, 0x13, 0x9d, 0x68, 0x21, - 0xb8, 0x02, 0x83, 0xc0, 0xbd, 0xc8, 0x6b, 0x00, 0x8c, 0x01, 0x97, 0x02, 0x65, 0xd9, 0x96, 0x10, 0x52, 0xdd, 0xcf, - 0x40, 0x6d, 0x27, 0xee, 0xd3, 0x88, 0xac, 0x85, 0xe8, 0xab, 0x60, 0xcc, 0x9c, 0xd7, 0xd2, 0x2d, 0x36, 0x5d, 0x6f, - 0xd7, 0xb7, 0xe8, 0x5c, 0xda, 0x72, 0xf3, 0x13, 0xb6, 0x58, 0x2b, 0x50, 0x36, 0x21, 0x69, 0xbb, 0xe2, 0x15, 0xca, - 0x26, 0xb4, 0xb4, 0x0f, 0xd4, 0xa3, 0x42, 0x75, 0xb2, 0xf5, 0x52, 0x3e, 0xb5, 0x08, 0xab, 0xc5, 0x55, 0xee, 0x07, - 0xa0, 0x9b, 0x4a, 0xab, 0x17, 0x75, 0x8d, 0xa6, 0x50, 0xab, 0x85, 0xe3, 0x46, 0x3b, 0x9b, 0x2e, 0xd3, 0x15, 0xe2, - 0xac, 0x4a, 0x3b, 0xf4, 0x0f, 0x99, 0x76, 0xbd, 0xec, 0xe8, 0x37, 0xe3, 0xea, 0x02, 0x17, 0x62, 0x03, 0x3e, 0xe7, - 0xfe, 0xf2, 0x7a, 0xcf, 0xe2, 0x1e, 0x44, 0x3c, 0x03, 0x7b, 0x52, 0xfb, 0x43, 0xf5, 0xa9, 0x2b, 0x18, 0xb2, 0x30, - 0x4a, 0xfd, 0x45, 0xca, 0x7b, 0x4f, 0x70, 0xdc, 0x3f, 0x57, 0x3d, 0xf6, 0xd7, 0x8c, 0x1f, 0xea, 0x62, 0x1b, 0x25, - 0x14, 0xd5, 0xd0, 0x5b, 0x17, 0xdb, 0x4a, 0xc4, 0xc5, 0x43, 0xde, 0x63, 0x98, 0x0c, 0x63, 0x21, 0x53, 0xe1, 0x4f, - 0x99, 0x0a, 0x1e, 0x21, 0x94, 0xb8, 0xdd, 0xf4, 0x48, 0xbb, 0x09, 0x71, 0x4a, 0xb5, 0x28, 0x65, 0x32, 0xfe, 0xad, - 0x9f, 0x40, 0x79, 0x4e, 0xd1, 0x32, 0xfd, 0xa4, 0x70, 0x99, 0xbe, 0xdd, 0x9c, 0x96, 0x9e, 0x89, 0x50, 0x67, 0x2e, - 0xb6, 0xb5, 0x4e, 0xc7, 0xd8, 0x29, 0x9d, 0xda, 0xb0, 0x77, 0xb9, 0xe2, 0xb2, 0xa2, 0xf0, 0x6f, 0x24, 0xb2, 0xea, - 0x19, 0x71, 0xfc, 0x9f, 0x59, 0xfb, 0x0c, 0xab, 0xc0, 0x2f, 0x03, 0x79, 0xbf, 0x00, 0xf8, 0xb8, 0xae, 0xcb, 0xf4, - 0x6e, 0x0b, 0xb4, 0x21, 0x34, 0xfc, 0x3d, 0x1f, 0x19, 0x30, 0xdd, 0x47, 0x38, 0x43, 0x7a, 0xa8, 0x73, 0x4e, 0x67, - 0x65, 0x3a, 0xe7, 0x2a, 0xac, 0x25, 0x38, 0xc8, 0x49, 0x53, 0xc9, 0x75, 0x09, 0x6a, 0x26, 0x70, 0xfb, 0xd0, 0x1e, - 0x11, 0x42, 0x6d, 0xca, 0x6a, 0x7a, 0x09, 0x35, 0xef, 0xe4, 0xb4, 0xa3, 0x49, 0x09, 0xae, 0x1a, 0x3a, 0x2b, 0xd7, - 0x7f, 0x1d, 0x8f, 0xbd, 0xbb, 0xac, 0x88, 0xfe, 0xe8, 0xa1, 0xbf, 0xe3, 0xee, 0x36, 0xfd, 0x02, 0xd1, 0x32, 0xd6, - 0xdf, 0x90, 0x01, 0x1d, 0x4f, 0x86, 0x77, 0xc5, 0xae, 0xc7, 0xde, 0xe5, 0x78, 0x81, 0x55, 0xd7, 0x8f, 0x3f, 0x40, - 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, 0x89, 0xb6, 0x85, 0x0f, 0x61, 0xa1, 0xef, 0x72, 0xd8, 0x84, 0xa1, - 0x79, 0xd4, 0x3d, 0x4a, 0xda, 0x85, 0xbe, 0xf4, 0xb5, 0xec, 0x2b, 0xdf, 0xb9, 0x02, 0x58, 0xd9, 0x67, 0x36, 0xdc, - 0x93, 0xfe, 0x94, 0xea, 0xc3, 0xf6, 0xb7, 0x64, 0x01, 0x85, 0x16, 0xd6, 0x53, 0x39, 0x3b, 0x37, 0x25, 0x4f, 0xb3, - 0xe9, 0x61, 0x03, 0x7b, 0xd4, 0x3d, 0x7a, 0x4d, 0x05, 0x97, 0xd7, 0x66, 0xf4, 0xfe, 0x61, 0x28, 0x54, 0x47, 0x9d, - 0x3b, 0xc8, 0xa6, 0xb4, 0x2e, 0x39, 0xbf, 0x59, 0xb9, 0xa3, 0x30, 0xbf, 0x0f, 0xc1, 0x33, 0xac, 0x7b, 0x77, 0x71, - 0xde, 0xfb, 0xb3, 0x35, 0x47, 0xfe, 0x9a, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0x0e, 0xbb, - 0xa0, 0x82, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, - 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xbb, 0xc0, 0xd0, 0xb6, 0x4d, 0x89, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x39, 0x51, 0xa1, - 0x59, 0xa4, 0xad, 0x92, 0xf1, 0xef, 0x44, 0x9b, 0x29, 0xd9, 0x63, 0x6b, 0xe0, 0xbd, 0x04, 0xe5, 0x64, 0x98, 0x62, - 0xf8, 0x8e, 0xaf, 0x77, 0x1e, 0x73, 0xcf, 0x39, 0x65, 0x9b, 0x94, 0x1d, 0xc1, 0x72, 0x22, 0x1b, 0xdf, 0x52, 0xbc, - 0xe1, 0xfb, 0xbb, 0x4a, 0x94, 0x00, 0x7a, 0x59, 0xf0, 0xe7, 0xd2, 0xe6, 0x0a, 0xdd, 0xee, 0xde, 0x51, 0x0a, 0xbf, - 0xe4, 0xe5, 0xf1, 0xb8, 0x4b, 0xbd, 0x10, 0x3a, 0x5f, 0xc4, 0xef, 0xc0, 0x1c, 0xc6, 0x10, 0x9b, 0x11, 0x20, 0xcc, - 0xf1, 0x01, 0x75, 0xb0, 0x7e, 0x04, 0xa0, 0x71, 0x02, 0x05, 0x18, 0x7d, 0xb5, 0x2d, 0xe8, 0x5b, 0x5e, 0x5c, 0x44, - 0x88, 0x1a, 0x05, 0x98, 0x28, 0x69, 0x16, 0xc3, 0x70, 0xa0, 0xf3, 0xfb, 0xf6, 0xae, 0x2e, 0x05, 0x0e, 0xbd, 0x63, - 0x19, 0xfe, 0xdb, 0xff, 0x58, 0x5b, 0x5a, 0x55, 0xb6, 0x5b, 0xe3, 0x34, 0xf3, 0xbf, 0xdd, 0x16, 0xfa, 0xfe, 0x4b, - 0xa1, 0x78, 0xde, 0xf1, 0xba, 0xfd, 0x05, 0xa2, 0xf7, 0x75, 0x2b, 0x57, 0xa5, 0x76, 0xc3, 0x4c, 0xf9, 0x43, 0x9a, - 0xc7, 0xc5, 0xc3, 0x28, 0x6e, 0x1d, 0x79, 0x93, 0xf4, 0x92, 0xf3, 0x2f, 0xe0, 0x6c, 0xfd, 0x05, 0xc8, 0x78, 0x5f, - 0x0a, 0xe3, 0x88, 0x49, 0x1c, 0x7c, 0x07, 0x31, 0x8a, 0xb6, 0x25, 0x6c, 0xc8, 0xed, 0xd3, 0x12, 0x34, 0x33, 0xfd, - 0x3e, 0x4a, 0x94, 0xd6, 0x7c, 0xff, 0x8b, 0x9c, 0xef, 0x2f, 0x85, 0xbc, 0x59, 0xc9, 0x0f, 0x9f, 0xac, 0x30, 0xf0, - 0x3d, 0x4e, 0xbf, 0x88, 0x1e, 0x5b, 0x95, 0x3e, 0x7c, 0x57, 0x5a, 0xfa, 0xac, 0xa2, 0xfe, 0x8e, 0x8a, 0x9a, 0x97, - 0x62, 0x44, 0xc4, 0x83, 0xa0, 0x9d, 0x6d, 0x97, 0xda, 0xb5, 0x04, 0xed, 0x82, 0x4d, 0x61, 0xff, 0x7a, 0x6c, 0xc8, - 0xab, 0x7e, 0xff, 0xe7, 0xca, 0x6b, 0xf1, 0xba, 0xeb, 0xd0, 0x94, 0x9f, 0x0a, 0x0f, 0x21, 0x80, 0xb5, 0x0c, 0x94, - 0xf1, 0x1c, 0x60, 0xd2, 0x45, 0x5e, 0xa3, 0x6c, 0x3a, 0x11, 0xf8, 0x98, 0x65, 0x37, 0x4e, 0x32, 0x0d, 0x30, 0xa3, - 0x9a, 0x62, 0xcc, 0x8a, 0x78, 0xb8, 0xf8, 0x88, 0x75, 0xd3, 0xd3, 0x2a, 0xb4, 0x7c, 0x0d, 0xc1, 0xba, 0xc8, 0x32, - 0x8e, 0x62, 0x26, 0x00, 0xd8, 0x7c, 0x04, 0xf9, 0x8a, 0xae, 0x0e, 0x49, 0x2b, 0x55, 0xde, 0xaf, 0x33, 0x22, 0xa3, - 0x49, 0x88, 0xe6, 0xb7, 0xf0, 0xc0, 0xbe, 0x6d, 0x66, 0x54, 0xa9, 0x67, 0x54, 0xee, 0x33, 0x1c, 0x96, 0xc2, 0x31, - 0xe2, 0xff, 0x2d, 0x55, 0x3d, 0x22, 0xd0, 0xab, 0x32, 0xad, 0xa2, 0x22, 0xcf, 0x45, 0x84, 0x08, 0xd5, 0xd2, 0x39, - 0x1c, 0xfa, 0xb1, 0xdf, 0xc7, 0x81, 0x30, 0x2f, 0xfe, 0xf4, 0x58, 0x57, 0xfe, 0x54, 0xe0, 0x5a, 0x49, 0x81, 0x53, - 0x51, 0x23, 0x44, 0x08, 0xef, 0x4f, 0xe0, 0x59, 0x4d, 0x7d, 0xbf, 0xb1, 0x4c, 0x74, 0xff, 0xc8, 0x80, 0xf2, 0x07, - 0xe4, 0xeb, 0x5c, 0x8a, 0x33, 0x75, 0xf2, 0x98, 0x38, 0xe3, 0x00, 0xc4, 0x7c, 0x5d, 0xa2, 0xd1, 0xd8, 0xff, 0x80, - 0x04, 0x43, 0xf5, 0x83, 0x9d, 0x6e, 0xea, 0xfd, 0x33, 0x93, 0x38, 0x8a, 0x3e, 0x6d, 0x93, 0xa7, 0x92, 0xa5, 0xd1, - 0xc2, 0xd1, 0x7b, 0xc4, 0x30, 0x0e, 0xa7, 0xf3, 0x29, 0xc9, 0x36, 0x26, 0xab, 0x00, 0xd2, 0xc9, 0x4c, 0x1d, 0x53, - 0xea, 0x68, 0x9c, 0xeb, 0x05, 0x55, 0xe8, 0xb1, 0x2e, 0x79, 0x05, 0xd6, 0x93, 0x1f, 0xbd, 0xd2, 0x9f, 0x0a, 0x39, - 0x87, 0x8d, 0x44, 0x50, 0xf8, 0x01, 0xae, 0x06, 0x2b, 0x05, 0x0c, 0xa6, 0xbe, 0x85, 0xaf, 0x89, 0xe7, 0x28, 0x78, - 0x14, 0x76, 0x31, 0xb6, 0xe6, 0xbe, 0xf3, 0x49, 0x41, 0xb9, 0x67, 0xc5, 0x9c, 0xe7, 0xc0, 0xb9, 0x0c, 0x0a, 0x61, - 0x3a, 0x9e, 0xe5, 0xff, 0x4c, 0xf2, 0x7a, 0x62, 0x43, 0x80, 0x0c, 0xfe, 0x9c, 0x38, 0x2d, 0xdd, 0xa1, 0x3b, 0x0f, - 0x3d, 0x8b, 0x38, 0x6c, 0xf4, 0x64, 0x53, 0x16, 0xbb, 0x14, 0xf5, 0x12, 0xe6, 0x07, 0xf2, 0xf3, 0x96, 0xfc, 0x10, - 0xa2, 0x78, 0x1b, 0xfc, 0x9a, 0xb1, 0x58, 0xe0, 0x5f, 0x7f, 0xcb, 0x18, 0x4d, 0xb4, 0xe0, 0x5f, 0x59, 0x83, 0x44, - 0xc5, 0x3f, 0x65, 0x93, 0x1c, 0xb8, 0x4c, 0xd5, 0x87, 0xcf, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x39, 0xe8, - 0xd4, 0xe7, 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x96, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4b, 0xa9, 0x1a, 0xbf, - 0x65, 0x14, 0xbf, 0x93, 0xfb, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xf9, 0x7b, 0xc3, 0x99, 0x5d, 0xf6, 0xab, 0xb7, - 0x89, 0xcc, 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x35, 0x13, 0x7f, 0xae, 0x0c, 0xa7, 0xc4, 0xe5, 0xa5, 0x87, 0x2b, 0x36, - 0xad, 0x5e, 0xd2, 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0xa9, 0xf2, 0x00, 0x82, - 0x99, 0xd4, 0x04, 0x80, 0xb4, 0x10, 0x95, 0x42, 0xe4, 0x2f, 0x71, 0x56, 0x5f, 0xf2, 0xde, 0x36, 0x8f, 0x89, 0xb4, - 0xba, 0xd7, 0xef, 0xa7, 0x17, 0x69, 0x4e, 0x41, 0x0d, 0xa7, 0x59, 0xa7, 0x3f, 0x64, 0x41, 0x9d, 0xc8, 0x55, 0xfa, - 0x77, 0x37, 0xc8, 0xcb, 0xf8, 0xbe, 0xee, 0x7a, 0xfe, 0x44, 0xfd, 0xbd, 0xb7, 0xfe, 0xb6, 0x40, 0x70, 0x27, 0xa7, - 0x7e, 0xb2, 0x2a, 0xe5, 0x89, 0x71, 0x69, 0xef, 0xf9, 0x4d, 0x5d, 0x14, 0x59, 0x9d, 0x6e, 0x3e, 0x48, 0x3d, 0x8d, - 0xee, 0x8b, 0x03, 0x18, 0x83, 0xf7, 0x00, 0x78, 0xa6, 0x43, 0x03, 0xa4, 0xef, 0x19, 0x79, 0xb8, 0xcf, 0x2d, 0xf9, - 0x49, 0x65, 0x6d, 0x92, 0xb0, 0xa2, 0xd8, 0x0c, 0x63, 0x84, 0x92, 0x71, 0x1a, 0x3b, 0xbf, 0xdf, 0x57, 0x7f, 0xef, - 0x31, 0x8a, 0x8a, 0x8a, 0x3b, 0x45, 0xa3, 0xb2, 0xaa, 0x47, 0xdb, 0xc1, 0xf1, 0x78, 0x59, 0xd9, 0x38, 0xda, 0x7a, - 0x05, 0x1c, 0xac, 0x50, 0x29, 0x7b, 0x25, 0xc2, 0xf2, 0xc3, 0x95, 0xdf, 0xef, 0xc3, 0xbf, 0x32, 0xd2, 0xc2, 0xf3, - 0xa7, 0xf8, 0x6b, 0x51, 0x17, 0x18, 0x9e, 0x41, 0x6b, 0x34, 0x87, 0x60, 0x82, 0xbf, 0x77, 0xa0, 0x5e, 0x5a, 0x69, - 0x1f, 0x41, 0xb7, 0x02, 0x3d, 0xa8, 0x87, 0x3e, 0x4d, 0xda, 0x17, 0x12, 0x75, 0x7b, 0xab, 0xd3, 0xe8, 0x8f, 0x0a, - 0x2e, 0xa7, 0x30, 0x39, 0xdc, 0xd0, 0xa7, 0x75, 0xb8, 0xfb, 0x04, 0x4f, 0x7f, 0x06, 0xca, 0xad, 0xe3, 0x11, 0xc5, - 0x16, 0x70, 0xf3, 0x58, 0x87, 0x9f, 0x8b, 0x52, 0x46, 0xd4, 0xc7, 0xd3, 0x02, 0xb4, 0x77, 0x01, 0x3a, 0x60, 0x69, - 0x10, 0xaf, 0x90, 0x3c, 0x67, 0x23, 0x80, 0x65, 0x07, 0x96, 0xb3, 0x8c, 0x53, 0x98, 0x67, 0xf9, 0x5c, 0xad, 0xb4, - 0x8b, 0x32, 0xf1, 0x6a, 0x96, 0x81, 0xb3, 0xc0, 0x55, 0xee, 0xb3, 0x4c, 0xab, 0x9e, 0xf2, 0x04, 0x7d, 0x5e, 0xc9, - 0x09, 0xae, 0x04, 0x27, 0x1b, 0x90, 0x5f, 0x80, 0x24, 0x4d, 0x29, 0x6b, 0xca, 0xe7, 0xd7, 0x74, 0x43, 0x46, 0xcf, - 0x79, 0xcf, 0x8b, 0x86, 0xa1, 0x7f, 0xe5, 0x95, 0x10, 0xbe, 0x89, 0xdb, 0x36, 0x4a, 0x61, 0x7f, 0x11, 0x58, 0x7c, - 0xc2, 0x7e, 0xf4, 0x96, 0xfe, 0x74, 0x1c, 0x84, 0x43, 0xe4, 0x86, 0x8a, 0x39, 0xb0, 0xa7, 0x01, 0x8b, 0x4d, 0x7c, - 0xb3, 0x9d, 0xc4, 0x83, 0x81, 0xaf, 0x33, 0x16, 0xb3, 0x18, 0x68, 0x90, 0xe3, 0xc1, 0xf5, 0x5c, 0x9f, 0x10, 0xfa, - 0x61, 0x44, 0xe5, 0xa8, 0x40, 0xe7, 0x20, 0x1a, 0x2c, 0x01, 0x4f, 0xbd, 0x95, 0x0d, 0x92, 0x8c, 0x49, 0x26, 0x71, - 0xad, 0x49, 0xaa, 0xc3, 0x09, 0xad, 0x03, 0x1d, 0x57, 0x17, 0xd0, 0xf9, 0xb8, 0xee, 0x7d, 0xbc, 0x1a, 0x2e, 0xa8, - 0xf4, 0x2b, 0x31, 0xf0, 0xea, 0xe9, 0x38, 0xb8, 0xa6, 0x5b, 0xe1, 0x62, 0x1d, 0xee, 0x7e, 0x96, 0x0f, 0x1c, 0x77, - 0x54, 0xd2, 0x10, 0x18, 0xbc, 0x3d, 0x74, 0x37, 0x33, 0x34, 0xd4, 0x49, 0xfb, 0x30, 0x0e, 0xe5, 0x10, 0xab, 0x56, - 0x5c, 0x49, 0x6f, 0x04, 0xdf, 0x2e, 0x14, 0x63, 0xd9, 0xd8, 0xb5, 0xa1, 0x28, 0xfc, 0x15, 0xc0, 0x0e, 0xb5, 0xbf, - 0x52, 0xc9, 0xc7, 0xc8, 0xa8, 0xa6, 0x81, 0x8e, 0x01, 0x58, 0xb2, 0x34, 0x91, 0x54, 0x91, 0x46, 0xe2, 0x8f, 0xcc, - 0x58, 0x47, 0x4d, 0xd7, 0x17, 0x4c, 0x55, 0x8b, 0xa4, 0xdb, 0x99, 0xc4, 0x72, 0x22, 0x49, 0x6d, 0xf7, 0x11, 0x31, - 0x18, 0xf8, 0x60, 0x23, 0xa6, 0x99, 0x08, 0x47, 0x3c, 0x2a, 0x91, 0x45, 0x97, 0xdf, 0x46, 0x99, 0xb4, 0x7d, 0x59, - 0x91, 0x2d, 0x08, 0xa6, 0x27, 0xd1, 0x07, 0x49, 0xd0, 0xba, 0x48, 0xa4, 0x19, 0x21, 0xc0, 0x8f, 0x27, 0xe5, 0x8d, - 0xfe, 0x1c, 0x34, 0xad, 0x04, 0x2f, 0x19, 0x24, 0x8f, 0xc4, 0xcf, 0xa4, 0x60, 0x16, 0x63, 0xf9, 0x60, 0x80, 0xe5, - 0xe4, 0x4f, 0x1d, 0x93, 0xf4, 0x5f, 0x3a, 0x9d, 0xb0, 0x5f, 0x78, 0x95, 0xad, 0xe5, 0x4d, 0x73, 0xef, 0x85, 0x97, - 0xb3, 0x54, 0xc3, 0x32, 0xe8, 0xbf, 0x26, 0xda, 0x05, 0x5b, 0x5b, 0xc6, 0x84, 0x55, 0x3f, 0x80, 0xb4, 0x47, 0xba, - 0xbc, 0x7c, 0x58, 0x31, 0xc1, 0xa3, 0x2b, 0x6b, 0x1e, 0x44, 0x57, 0xc2, 0x47, 0x2e, 0xbb, 0x49, 0x72, 0x33, 0x9e, - 0xf8, 0xe1, 0x60, 0xa0, 0x00, 0x68, 0x69, 0x9d, 0x14, 0x83, 0xf0, 0xa9, 0x90, 0x03, 0x69, 0x74, 0x54, 0x05, 0x58, - 0x2c, 0xb3, 0x9b, 0x72, 0x92, 0x0d, 0x06, 0x3e, 0x88, 0x8d, 0x89, 0xdd, 0xd0, 0x6c, 0xee, 0xb3, 0x33, 0x05, 0x59, - 0x6d, 0x0e, 0x5b, 0x33, 0xdd, 0x02, 0x03, 0x80, 0x41, 0x44, 0xb0, 0xdc, 0x67, 0x46, 0x3e, 0xa2, 0x4e, 0x4f, 0x61, - 0x04, 0x04, 0xbf, 0x9e, 0x08, 0x44, 0x2e, 0x12, 0xa8, 0x07, 0x98, 0x09, 0x30, 0xa3, 0x8a, 0xe1, 0x35, 0xb0, 0x8b, - 0x57, 0xe6, 0x15, 0x83, 0xfe, 0x45, 0x93, 0x2c, 0xd1, 0x54, 0xe2, 0x68, 0x8c, 0x9c, 0x4a, 0x63, 0x64, 0x40, 0xec, - 0xe2, 0xf8, 0xf7, 0x94, 0x1e, 0x05, 0x29, 0xfb, 0x9c, 0x1b, 0xe2, 0x70, 0x14, 0x5f, 0xc1, 0xaa, 0x71, 0x3c, 0xd6, - 0xe6, 0xf5, 0x74, 0x56, 0xcf, 0x07, 0x22, 0x80, 0xff, 0x86, 0x82, 0xfd, 0xa2, 0xa9, 0xc8, 0x0d, 0x52, 0xe7, 0xf1, - 0x98, 0x82, 0x7c, 0xaa, 0x9b, 0xfc, 0x43, 0xee, 0xee, 0xa7, 0xb3, 0xb9, 0x35, 0x47, 0xaf, 0x6a, 0x5c, 0xb7, 0x56, - 0x37, 0x14, 0x12, 0xad, 0x69, 0x52, 0xdc, 0xe4, 0x93, 0x62, 0xc0, 0x2b, 0x5f, 0xa8, 0x2e, 0xb6, 0x46, 0xb0, 0xf0, - 0xe7, 0x16, 0x08, 0x93, 0x71, 0x2f, 0x3e, 0x59, 0xc8, 0x29, 0xed, 0xda, 0x6a, 0xb7, 0xb5, 0x49, 0xd3, 0x58, 0x35, - 0xbc, 0x86, 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, - 0x2d, 0x86, 0xff, 0x29, 0xdd, 0x9b, 0x53, 0x1b, 0xe4, 0x00, 0xb6, 0x7b, 0x0f, 0xb7, 0x63, 0xf4, 0x40, 0x06, 0x6f, - 0x04, 0x10, 0x8d, 0xaf, 0xa7, 0xd6, 0x8c, 0x89, 0x86, 0x05, 0x2b, 0x87, 0x91, 0x1f, 0x20, 0xe3, 0xe5, 0x14, 0x58, - 0xd9, 0x4f, 0x8a, 0xb8, 0xf6, 0x87, 0x91, 0x7f, 0xf5, 0x2c, 0xc8, 0xb8, 0x17, 0x0d, 0x3b, 0xbe, 0x00, 0x7b, 0xf5, - 0xd5, 0x33, 0x16, 0x0d, 0x78, 0x7e, 0x53, 0x4f, 0xb3, 0x60, 0x98, 0xb1, 0xe8, 0xa6, 0x18, 0x82, 0x0f, 0xed, 0xf3, - 0x72, 0x10, 0xfa, 0xbe, 0xd9, 0x39, 0x74, 0x37, 0x24, 0xf2, 0x08, 0xfb, 0x2b, 0xb8, 0xed, 0x6a, 0x89, 0x19, 0xe0, - 0x06, 0x56, 0x11, 0x33, 0xd8, 0xf2, 0x57, 0xcf, 0x0c, 0x97, 0x50, 0xfe, 0x5c, 0x6a, 0x36, 0x0a, 0x34, 0x27, 0xe7, - 0x68, 0x4e, 0x56, 0x42, 0x2d, 0xf9, 0xa4, 0xc2, 0xa9, 0x3a, 0x9f, 0x68, 0xbb, 0xd1, 0x18, 0x03, 0x17, 0xed, 0xb9, - 0x2d, 0x8c, 0xcc, 0x74, 0x91, 0xa2, 0x01, 0x0b, 0xcf, 0xc4, 0x29, 0x8d, 0x01, 0xed, 0xcb, 0x81, 0xa5, 0x0d, 0xf9, - 0xab, 0x9c, 0x19, 0x68, 0x1b, 0x52, 0x1a, 0x35, 0x03, 0x7f, 0xa6, 0x26, 0xcc, 0xaf, 0x60, 0x25, 0x82, 0xa8, 0x2e, - 0xc0, 0x24, 0xa9, 0xc8, 0x68, 0xa4, 0xac, 0x44, 0x72, 0x0e, 0x78, 0x1f, 0xc1, 0x93, 0x45, 0xec, 0x6a, 0x7f, 0x4a, - 0xff, 0xab, 0xc3, 0xe7, 0xda, 0x7f, 0x2a, 0x80, 0x85, 0x5c, 0x1a, 0x44, 0x06, 0x0a, 0x87, 0xd4, 0x54, 0x22, 0x4e, - 0x1c, 0xcf, 0xc0, 0xd7, 0x70, 0x81, 0xa6, 0x80, 0xfe, 0xa0, 0x66, 0x14, 0x91, 0x85, 0xbf, 0x7a, 0x76, 0x53, 0xb7, - 0x7a, 0x9e, 0x39, 0xaf, 0x41, 0x33, 0x03, 0x21, 0x3d, 0x4e, 0xd5, 0xdb, 0x90, 0xe8, 0xbc, 0xbc, 0xd4, 0x2f, 0x13, - 0x22, 0x59, 0x11, 0x79, 0xfa, 0x3e, 0x07, 0xf3, 0x88, 0x22, 0x74, 0x70, 0x65, 0x1e, 0x8f, 0x97, 0x82, 0xc2, 0x77, - 0x94, 0xe7, 0x03, 0x4e, 0xb3, 0x28, 0x01, 0x6d, 0x20, 0xab, 0x4c, 0x99, 0x9b, 0xa4, 0x65, 0xea, 0x3e, 0x80, 0x95, - 0x20, 0x47, 0x37, 0xa7, 0xa0, 0x50, 0x46, 0x82, 0x52, 0x5a, 0x0d, 0x42, 0xa9, 0x0e, 0x8b, 0x20, 0x72, 0xc8, 0x42, - 0xc0, 0xcd, 0x54, 0x34, 0x5a, 0xd2, 0xf0, 0x08, 0xe7, 0x06, 0x0a, 0x01, 0x48, 0xec, 0xa9, 0xa2, 0x8c, 0xcb, 0x61, - 0xce, 0xd6, 0x3c, 0x1c, 0xe2, 0xac, 0x49, 0x5b, 0x9e, 0x83, 0x38, 0x96, 0x4b, 0xbe, 0xc9, 0x11, 0x0c, 0x22, 0xf4, - 0x19, 0xf2, 0x27, 0xcb, 0xf9, 0x77, 0xe7, 0x30, 0xed, 0x08, 0x1f, 0x76, 0xb5, 0x05, 0x17, 0xb3, 0xbb, 0xf9, 0x04, - 0xe2, 0x5b, 0xee, 0xe6, 0xa7, 0x18, 0x22, 0x0b, 0x7f, 0xb0, 0x1a, 0x4a, 0xae, 0x28, 0x74, 0x59, 0x8f, 0x48, 0x91, - 0x3d, 0xdd, 0x70, 0x04, 0xc1, 0x81, 0x56, 0x0d, 0x32, 0x34, 0x12, 0x5f, 0x3d, 0x83, 0xac, 0xc1, 0x86, 0x7f, 0xce, - 0xc9, 0x59, 0xdd, 0x9f, 0x6c, 0xa1, 0x9a, 0x64, 0xb2, 0x56, 0x54, 0xce, 0x5f, 0xaf, 0xca, 0xf2, 0x6c, 0x55, 0x86, - 0xeb, 0x41, 0x57, 0x55, 0x96, 0x1c, 0xa9, 0x0d, 0xd0, 0x9a, 0xae, 0x10, 0x43, 0x21, 0x6b, 0xb0, 0xb4, 0xaa, 0xb2, - 0xa1, 0x3e, 0x81, 0x40, 0x1f, 0x60, 0x19, 0x35, 0xfb, 0xe9, 0xf0, 0x9f, 0xc1, 0x3f, 0x55, 0xc8, 0x52, 0x9d, 0xd6, - 0x99, 0xf8, 0x35, 0x58, 0x32, 0xfc, 0xe3, 0xb7, 0x60, 0x03, 0x58, 0x02, 0x64, 0xb9, 0xdb, 0xda, 0x68, 0xbd, 0xf2, - 0x0a, 0xf1, 0xae, 0xd6, 0x17, 0xfd, 0xd6, 0x6d, 0xa2, 0x56, 0x80, 0x11, 0x0a, 0x2d, 0x02, 0x6c, 0xf5, 0xc0, 0x3d, - 0x05, 0x3f, 0x10, 0xc3, 0xb9, 0x26, 0xad, 0xa9, 0x13, 0x5e, 0x67, 0xe3, 0x48, 0x44, 0xf5, 0x0e, 0x2e, 0xee, 0xf5, - 0xce, 0xe2, 0x6f, 0x54, 0x20, 0x00, 0xb2, 0x98, 0x62, 0xe3, 0xbc, 0x21, 0xbd, 0x32, 0xec, 0x24, 0xf4, 0xde, 0xb0, - 0x13, 0xc8, 0x8b, 0xc3, 0x4e, 0xa1, 0x4b, 0xb4, 0x9d, 0x22, 0x35, 0xd1, 0x76, 0xd2, 0x62, 0x1d, 0x96, 0x10, 0xfc, - 0xaa, 0xbd, 0x75, 0x94, 0xed, 0x8b, 0x2c, 0x61, 0xda, 0x02, 0x46, 0xb9, 0x55, 0x9f, 0x39, 0x45, 0xac, 0x95, 0xbd, - 0xd3, 0x49, 0x95, 0xbb, 0xc8, 0xa7, 0x56, 0x53, 0x64, 0xf2, 0x0f, 0xa7, 0x2d, 0x92, 0x4f, 0x7e, 0x6e, 0x37, 0x4c, - 0xa6, 0x7f, 0x3c, 0xf9, 0x02, 0xba, 0x22, 0x3b, 0x7d, 0x02, 0x01, 0x99, 0x0a, 0xaa, 0xd5, 0xad, 0x62, 0x9a, 0xb7, - 0xab, 0xec, 0xf6, 0x42, 0x89, 0xe1, 0x74, 0x76, 0x12, 0x1e, 0x6d, 0x86, 0x0c, 0x1c, 0x82, 0x40, 0x21, 0x54, 0x14, - 0xc3, 0x23, 0x50, 0x6b, 0x24, 0x1f, 0xe0, 0x47, 0xbb, 0x53, 0x41, 0xa4, 0x76, 0x53, 0x71, 0xe3, 0xe4, 0xa6, 0xeb, - 0xa5, 0x40, 0xad, 0x53, 0xb2, 0x02, 0x28, 0x21, 0xea, 0x4f, 0x62, 0x57, 0xbf, 0x84, 0x2b, 0x36, 0x3f, 0x34, 0x8a, - 0x9e, 0x5c, 0x9f, 0xa2, 0x6e, 0xc5, 0xd5, 0x69, 0xda, 0x6a, 0x8e, 0x1d, 0x67, 0xc8, 0xc1, 0xb3, 0x82, 0x60, 0x3b, - 0x2a, 0x51, 0xbe, 0x6d, 0x37, 0x1d, 0x13, 0x5b, 0xfd, 0xb3, 0xa8, 0xb6, 0x2b, 0xa8, 0x88, 0x88, 0x4f, 0xb2, 0x9b, - 0x27, 0xed, 0x77, 0xb0, 0xc7, 0x5a, 0x0d, 0x22, 0xfb, 0x0c, 0xae, 0x72, 0x9d, 0x16, 0xb9, 0x2d, 0x83, 0xf3, 0x0f, - 0xaf, 0x76, 0x15, 0x36, 0x39, 0xd6, 0xd5, 0xd5, 0x4c, 0x75, 0x52, 0xb1, 0x81, 0xb1, 0xa6, 0xb5, 0x54, 0xf3, 0x18, - 0x92, 0xee, 0xca, 0xe2, 0xac, 0x4a, 0xba, 0xe9, 0xb9, 0x71, 0xa6, 0x10, 0x03, 0x67, 0xab, 0xd1, 0x72, 0x86, 0x21, - 0xba, 0x3e, 0xcc, 0x12, 0xbf, 0xd5, 0x53, 0xee, 0xf3, 0x70, 0xe7, 0x77, 0xf5, 0x82, 0x93, 0xc9, 0x7e, 0x72, 0x9a, - 0xbb, 0x5d, 0xa4, 0xfd, 0xc4, 0xb7, 0x61, 0xfe, 0xf5, 0x0d, 0x62, 0x25, 0xea, 0x7f, 0x54, 0x00, 0x34, 0xb8, 0xcd, - 0x63, 0x89, 0x52, 0x7f, 0x50, 0xd5, 0x0f, 0x6a, 0xa6, 0x6a, 0x1a, 0x08, 0xe6, 0x54, 0x0a, 0xf8, 0xc3, 0xed, 0xc2, - 0x15, 0x8f, 0xb8, 0x61, 0x61, 0xfc, 0xd3, 0xab, 0xd9, 0xb9, 0xa0, 0x32, 0x70, 0x33, 0xfe, 0xd3, 0x13, 0xec, 0x1c, - 0xd6, 0x0a, 0xc8, 0x0a, 0x7f, 0x7a, 0xd5, 0x23, 0xef, 0xe7, 0xfc, 0x4f, 0x2f, 0x7f, 0xe4, 0x7d, 0xc4, 0x79, 0xf9, - 0x13, 0x49, 0x9d, 0x10, 0xd5, 0xe5, 0x4f, 0xc2, 0x14, 0x5b, 0xa7, 0xf9, 0x2b, 0x52, 0xf8, 0x04, 0x9f, 0x81, 0xef, - 0x70, 0x1d, 0xee, 0xcc, 0x6f, 0xf0, 0xd8, 0xb1, 0xd8, 0x76, 0xa9, 0x2f, 0xa0, 0x1c, 0x81, 0x45, 0x54, 0xf6, 0xdb, - 0xb9, 0xfd, 0x6a, 0x61, 0x94, 0x31, 0x76, 0x5f, 0xb2, 0x12, 0xa5, 0xb3, 0x7e, 0xbf, 0x90, 0x82, 0x91, 0x5d, 0x58, - 0xa3, 0x3d, 0x4a, 0xd5, 0xab, 0x6f, 0xc3, 0x3a, 0x4a, 0xd2, 0x7c, 0x25, 0xa3, 0x8f, 0x64, 0xd8, 0x91, 0xbe, 0x92, - 0x12, 0xed, 0xb5, 0x0a, 0xcb, 0xd1, 0xec, 0xd7, 0x25, 0x07, 0xca, 0xeb, 0x56, 0x50, 0xbe, 0x6a, 0x02, 0xe8, 0x95, - 0x6a, 0x9f, 0x01, 0x23, 0xa7, 0xb0, 0x54, 0x1e, 0xac, 0xc4, 0xb9, 0xe8, 0xb3, 0xe2, 0x78, 0xf4, 0x2c, 0x34, 0xf3, - 0x0a, 0x1e, 0x84, 0x3b, 0x0b, 0x23, 0x15, 0x2e, 0x84, 0xe2, 0x79, 0x85, 0xb1, 0x15, 0x15, 0x70, 0x20, 0xc3, 0x0f, - 0x08, 0xbc, 0x97, 0xfd, 0x2b, 0x18, 0x0c, 0x13, 0xdc, 0xc8, 0xa8, 0x93, 0x2b, 0xf6, 0x27, 0x06, 0x66, 0x50, 0x4f, - 0x6a, 0xf7, 0xd9, 0x83, 0x0a, 0xec, 0x85, 0x33, 0xa0, 0xbd, 0x1b, 0xa3, 0x9f, 0x55, 0xb1, 0x71, 0xd2, 0x3f, 0x15, - 0x1b, 0x48, 0xa6, 0xc3, 0xe2, 0x64, 0x9b, 0x86, 0x47, 0xf2, 0xe4, 0x38, 0xdd, 0xf4, 0x8f, 0xc7, 0x31, 0x7e, 0x1c, - 0xe5, 0xd7, 0x16, 0xf0, 0x2a, 0x6e, 0x21, 0x8d, 0x45, 0x8a, 0xde, 0x81, 0x98, 0x43, 0xd1, 0x4b, 0xf6, 0x5b, 0xc6, - 0xcb, 0x89, 0xa0, 0x94, 0x24, 0x36, 0xbc, 0x23, 0x3d, 0x4d, 0xeb, 0xd1, 0x4e, 0x06, 0xec, 0xd7, 0xa3, 0x3d, 0xfd, - 0x05, 0x8a, 0x47, 0x0b, 0x7f, 0x49, 0x7f, 0x17, 0x77, 0x73, 0xcf, 0xf9, 0xa6, 0xf1, 0x1d, 0x71, 0x81, 0x62, 0xcd, - 0xee, 0xaf, 0x69, 0xe9, 0xac, 0x03, 0xc1, 0x01, 0x6f, 0xb1, 0x8b, 0xf6, 0xfd, 0xc6, 0x75, 0x7a, 0x3a, 0x7c, 0xeb, - 0xd6, 0x28, 0xdf, 0xfb, 0x87, 0x44, 0x39, 0x38, 0xbc, 0x72, 0xd1, 0xfc, 0xed, 0xa7, 0x0c, 0x49, 0x85, 0xe6, 0x06, - 0xdb, 0xc9, 0x16, 0x61, 0x6d, 0x8c, 0x83, 0x9c, 0xad, 0xca, 0x30, 0x02, 0x06, 0x75, 0xec, 0x7f, 0xf4, 0xd9, 0xb4, - 0x21, 0xfb, 0x00, 0x50, 0xb9, 0x0a, 0x01, 0x7b, 0x00, 0x4e, 0x34, 0xc2, 0x0d, 0x70, 0xab, 0xd1, 0x92, 0x0e, 0xea, - 0xb6, 0x60, 0x20, 0x5a, 0xc2, 0xc6, 0x09, 0x5d, 0xdf, 0x57, 0x84, 0x8f, 0xca, 0xb7, 0x0f, 0xe5, 0xaf, 0x9e, 0xb3, - 0xff, 0xde, 0x61, 0x4d, 0x4d, 0xb9, 0x05, 0xcc, 0x9c, 0xb5, 0xc8, 0x2b, 0x84, 0x4e, 0x91, 0xdf, 0xab, 0xba, 0x12, - 0xc3, 0x65, 0x2d, 0xca, 0xce, 0xec, 0xd6, 0x89, 0xde, 0x39, 0x05, 0xb5, 0x54, 0x36, 0x20, 0x01, 0x6e, 0x20, 0xc5, - 0xb6, 0xc0, 0x92, 0xce, 0x06, 0x28, 0xfe, 0x0d, 0x2a, 0xed, 0xfe, 0xdf, 0x39, 0x13, 0xd4, 0x6c, 0xa3, 0xba, 0xbf, - 0xd2, 0x4f, 0x55, 0x4d, 0x62, 0x01, 0x2e, 0x27, 0x69, 0xde, 0xf1, 0x08, 0xab, 0x7f, 0x9a, 0x2c, 0x45, 0xa0, 0x57, - 0x11, 0xed, 0x4a, 0x40, 0x82, 0x76, 0x76, 0x16, 0x2a, 0x02, 0x05, 0xfa, 0xfa, 0x0f, 0xdb, 0x34, 0x8b, 0xe5, 0x6a, - 0xb6, 0x87, 0x89, 0xb2, 0x58, 0x0f, 0x11, 0xe4, 0xcc, 0xd4, 0xc1, 0x7e, 0x4f, 0x33, 0x9a, 0x85, 0x37, 0xa6, 0x04, - 0x97, 0xe2, 0x2a, 0x2a, 0x72, 0xf0, 0x39, 0xc4, 0x17, 0x3e, 0x15, 0x72, 0x83, 0x88, 0xa6, 0x3f, 0xe4, 0x9e, 0x79, - 0x83, 0x85, 0x92, 0x9f, 0x10, 0x7f, 0xc9, 0xda, 0x18, 0xf7, 0x4b, 0xa7, 0xda, 0x2f, 0x15, 0x82, 0xfb, 0xcf, 0xb6, - 0xd8, 0xa8, 0xf2, 0x44, 0x8f, 0x3e, 0xc5, 0xfa, 0x9f, 0x2d, 0xa0, 0x54, 0xf7, 0x6d, 0x70, 0x2a, 0x1e, 0x85, 0xdb, - 0xba, 0xb8, 0x45, 0x68, 0x81, 0x72, 0x54, 0x15, 0xdb, 0x32, 0x22, 0x4e, 0xd8, 0x6d, 0x5d, 0xf4, 0x34, 0x07, 0x3a, - 0x75, 0x58, 0x9a, 0xc8, 0x13, 0xa1, 0xdd, 0x82, 0xee, 0x69, 0x8e, 0x95, 0x78, 0x21, 0x4b, 0x07, 0x59, 0x27, 0xd2, - 0x84, 0xca, 0x5d, 0x5d, 0x75, 0x52, 0x2a, 0x75, 0xc3, 0xeb, 0x54, 0x33, 0xfe, 0x2e, 0xcd, 0x9f, 0x58, 0xf6, 0xeb, - 0xd6, 0x6f, 0xb5, 0xda, 0x1b, 0xab, 0x47, 0x25, 0x6b, 0x8e, 0xb3, 0x09, 0x49, 0xe9, 0x13, 0xb6, 0x9b, 0x49, 0xd7, - 0x3a, 0xf0, 0x24, 0xb8, 0x1c, 0x7a, 0x02, 0x2a, 0x06, 0x4d, 0xbc, 0xdd, 0x05, 0xea, 0x11, 0x78, 0x06, 0xaa, 0x19, - 0x24, 0xd7, 0x01, 0xbf, 0xac, 0xb5, 0x3c, 0x65, 0x84, 0x61, 0xb5, 0xb3, 0x68, 0x39, 0x58, 0x49, 0x78, 0xae, 0x08, - 0x5c, 0xbb, 0x12, 0x78, 0x35, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, - 0xa7, 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, - 0x36, 0x9f, 0x43, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, - 0xcf, 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, - 0x76, 0x7a, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, - 0x88, 0xc2, 0x2c, 0xfb, 0x6b, 0x51, 0xfc, 0x51, 0xe9, 0x3b, 0x02, 0x1d, 0xdd, 0x79, 0x51, 0xa7, 0xcb, 0xfd, 0x07, - 0xc2, 0x78, 0xf2, 0xea, 0x13, 0xa2, 0x5b, 0xdf, 0x67, 0xee, 0x57, 0x80, 0x1b, 0xc1, 0x1d, 0x44, 0x7b, 0xb7, 0xd4, - 0x27, 0xb5, 0xfa, 0x5a, 0xaf, 0x9d, 0xa7, 0xe7, 0x37, 0x9d, 0xdb, 0xef, 0xa1, 0x39, 0xd9, 0x7a, 0x4f, 0x0b, 0x6b, - 0x65, 0xe9, 0xa9, 0x2a, 0xd8, 0x9b, 0xe5, 0xb9, 0x2a, 0x98, 0x3c, 0xf0, 0x9a, 0xfd, 0x82, 0x06, 0x57, 0x3a, 0xd9, - 0x78, 0xcf, 0xd4, 0xc0, 0x2d, 0x0a, 0x4b, 0x87, 0x5f, 0x72, 0x33, 0x79, 0x89, 0xfb, 0x4b, 0x45, 0x2e, 0xf6, 0x9d, - 0x33, 0xba, 0x33, 0xb3, 0xee, 0x55, 0x85, 0xab, 0x05, 0xb9, 0x3a, 0xb0, 0xb5, 0xec, 0xe2, 0x70, 0xc3, 0x22, 0x0a, - 0x10, 0x88, 0xe9, 0x95, 0x5a, 0xfb, 0x13, 0x1a, 0x84, 0x6a, 0x30, 0xf0, 0x0b, 0x0c, 0x56, 0x05, 0x0a, 0x1f, 0x28, - 0x92, 0xbf, 0xf2, 0x04, 0xec, 0xe2, 0x19, 0xa0, 0x5b, 0xb1, 0x59, 0x31, 0x42, 0x84, 0x4c, 0x56, 0xb1, 0x9a, 0xce, - 0x20, 0x9f, 0xfa, 0xe2, 0x1b, 0x5b, 0x75, 0x3e, 0x6f, 0x6b, 0xaa, 0x9c, 0x3b, 0x14, 0xba, 0xbb, 0xa9, 0x3b, 0xb7, - 0x2e, 0xf2, 0xdc, 0x21, 0xe4, 0x4a, 0xc5, 0x4a, 0x4c, 0x43, 0xcd, 0x93, 0x34, 0xa3, 0xfe, 0x62, 0x9f, 0x8a, 0x1a, - 0x85, 0x53, 0xfe, 0x74, 0x0c, 0xaa, 0x70, 0x55, 0x43, 0x1c, 0x4b, 0x55, 0x3c, 0xb2, 0x41, 0xa0, 0x79, 0x75, 0xa7, - 0x92, 0x26, 0x64, 0x72, 0x23, 0x7c, 0x6a, 0x52, 0xca, 0xd3, 0xb4, 0x49, 0x2b, 0x45, 0xea, 0xe0, 0x83, 0x3a, 0xd5, - 0x78, 0x6e, 0xe6, 0xcf, 0x01, 0xcc, 0xb8, 0xba, 0xe1, 0xd7, 0x8a, 0xcb, 0xa8, 0xad, 0xcc, 0xa4, 0xfd, 0xc9, 0xd1, - 0xd8, 0x28, 0x56, 0xe3, 0x46, 0x19, 0x61, 0xa5, 0x34, 0x27, 0xc5, 0x72, 0x3c, 0xff, 0x80, 0xc1, 0x9a, 0x27, 0xb0, - 0x83, 0x89, 0x4a, 0x79, 0x1f, 0x01, 0xf1, 0x75, 0x92, 0xae, 0x12, 0x48, 0x91, 0xfe, 0xa5, 0x4b, 0xee, 0x32, 0x36, - 0x10, 0x63, 0x56, 0xcc, 0x8c, 0xfe, 0x07, 0x77, 0x49, 0x7f, 0x12, 0x02, 0xe0, 0x26, 0x9a, 0x42, 0xa7, 0xce, 0x93, - 0xab, 0x2a, 0x58, 0x5e, 0x79, 0x68, 0xc5, 0x88, 0x07, 0xff, 0xf9, 0x3c, 0x44, 0x10, 0x73, 0x4c, 0xf1, 0xf4, 0x0b, - 0xa3, 0xff, 0x08, 0xae, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, 0x21, 0xdc, 0xec, 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, - 0x6a, 0xf8, 0xd7, 0xdc, 0x83, 0xfe, 0xaf, 0x33, 0x61, 0xa9, 0xfd, 0xf4, 0x74, 0x00, 0x15, 0xbc, 0xaf, 0x78, 0x1b, - 0x11, 0xdf, 0x27, 0x7e, 0x1a, 0x0f, 0xb6, 0x4f, 0xb7, 0x60, 0xad, 0xfb, 0x50, 0x19, 0xeb, 0x2a, 0x61, 0x03, 0x01, - 0x5f, 0xa3, 0xa8, 0x3d, 0xaf, 0xdd, 0xee, 0xc1, 0x7f, 0xfa, 0x57, 0x21, 0x03, 0x26, 0x4e, 0xdf, 0x67, 0x4e, 0xd6, - 0xe8, 0x2a, 0x93, 0xe9, 0x43, 0x27, 0x7d, 0xab, 0xd3, 0x7d, 0x27, 0xfc, 0x23, 0x67, 0x16, 0x1f, 0x6e, 0xe9, 0x2b, - 0x4d, 0x8a, 0x3b, 0x60, 0x65, 0xf3, 0xa8, 0x20, 0xd4, 0xb9, 0x88, 0xbe, 0x32, 0xe5, 0x5b, 0x42, 0xcd, 0xa1, 0xb1, - 0xa4, 0x94, 0xee, 0x35, 0xf4, 0x3a, 0xad, 0xf5, 0xdb, 0x28, 0xc1, 0x98, 0xe8, 0x78, 0xf2, 0x32, 0x1e, 0x2b, 0xef, - 0xe3, 0x71, 0x23, 0x15, 0xf2, 0x00, 0x44, 0xa0, 0x62, 0xfc, 0xe9, 0xca, 0x53, 0x91, 0x5e, 0x18, 0xaf, 0x42, 0x29, - 0x28, 0x0c, 0xe8, 0x0a, 0xa4, 0x80, 0x47, 0xed, 0x89, 0xce, 0xc2, 0x2e, 0xe1, 0x1e, 0xdd, 0x04, 0x8c, 0xf5, 0xf9, - 0xaf, 0xb9, 0x97, 0x33, 0xe1, 0x0e, 0x2f, 0x06, 0xa8, 0x4d, 0xbd, 0xba, 0xfb, 0xb8, 0x56, 0xe7, 0x70, 0x08, 0x0e, - 0x56, 0x83, 0x08, 0x4e, 0xe7, 0x73, 0x47, 0xb3, 0x2c, 0x40, 0xe5, 0x64, 0x95, 0x91, 0x37, 0x4f, 0x16, 0xbd, 0xba, - 0xef, 0x2d, 0xd3, 0xb2, 0xaa, 0x83, 0x8c, 0x65, 0x61, 0x05, 0xb8, 0x3a, 0xb4, 0x7e, 0x10, 0x2e, 0x0b, 0xe7, 0x0f, - 0x84, 0x20, 0x76, 0xaf, 0xb6, 0x25, 0xd7, 0x47, 0xf5, 0xd3, 0x67, 0x6c, 0xc3, 0x25, 0xea, 0xa4, 0x33, 0x11, 0x80, - 0xd8, 0x53, 0xb3, 0x8a, 0x6e, 0x80, 0xa4, 0x4e, 0xb3, 0x8a, 0x6e, 0xa8, 0xd9, 0xc6, 0x38, 0x00, 0xca, 0x58, 0xc0, - 0xbe, 0x9b, 0x8e, 0x83, 0xf5, 0xd3, 0x58, 0x5e, 0x87, 0x56, 0x4f, 0xb7, 0xca, 0x67, 0x50, 0xb7, 0xda, 0x18, 0x13, - 0xdb, 0xcd, 0x97, 0x73, 0xfd, 0x6e, 0xb0, 0xf4, 0xed, 0xa0, 0x39, 0xa7, 0xec, 0x95, 0x2e, 0x7b, 0x6d, 0x97, 0x4d, - 0x3d, 0x77, 0x52, 0xb4, 0x1a, 0x03, 0x7a, 0x03, 0x0b, 0xd6, 0xe7, 0x22, 0xcd, 0x56, 0xa5, 0x2a, 0x01, 0x2f, 0x8c, - 0x35, 0x5b, 0xf9, 0x8d, 0xcc, 0x90, 0x84, 0x79, 0x9c, 0x89, 0xb7, 0x74, 0xaf, 0x85, 0xc9, 0x71, 0x2a, 0x92, 0x29, - 0xa1, 0x53, 0xba, 0xb3, 0x0d, 0x9d, 0xab, 0x30, 0x8a, 0x68, 0xad, 0xa4, 0xd2, 0x48, 0x60, 0x6a, 0x06, 0x28, 0x99, - 0x2b, 0x70, 0x4a, 0x97, 0xfb, 0xdf, 0x89, 0x18, 0x67, 0xbe, 0x28, 0x99, 0x01, 0xdd, 0xf2, 0xeb, 0x62, 0xd3, 0x4a, - 0x91, 0x11, 0xe6, 0xcd, 0x69, 0x7b, 0x5d, 0x1f, 0x02, 0xb9, 0x5a, 0x0e, 0x28, 0x1a, 0x07, 0x85, 0x0e, 0x97, 0x2a, - 0x01, 0xf6, 0x45, 0xe2, 0x67, 0x84, 0x2d, 0xed, 0x81, 0xdc, 0x1e, 0x9d, 0x09, 0x73, 0xc9, 0x49, 0x59, 0x76, 0x29, - 0xcd, 0xe0, 0x72, 0xe2, 0x4a, 0x70, 0x91, 0xde, 0xae, 0xa7, 0x49, 0x4b, 0xdb, 0xc7, 0x86, 0x73, 0x34, 0xb4, 0x0d, - 0xba, 0x63, 0x7f, 0x68, 0x2e, 0x16, 0xb1, 0x75, 0xb1, 0x18, 0x76, 0x66, 0x3f, 0x59, 0x2c, 0x40, 0x0e, 0x00, 0x47, - 0xdd, 0x96, 0x8f, 0xd9, 0x12, 0x38, 0xad, 0xa6, 0xd9, 0xd4, 0xdb, 0xf2, 0xfc, 0xa9, 0xea, 0xe9, 0x25, 0xaf, 0x9e, - 0x0a, 0x33, 0x16, 0x5b, 0x5e, 0x3d, 0xb5, 0x8e, 0x9c, 0xfc, 0xa9, 0x50, 0xa2, 0x75, 0x01, 0xcd, 0xc0, 0x6b, 0x0a, - 0x18, 0xb1, 0x64, 0x32, 0xa5, 0x8a, 0x3c, 0xee, 0x4d, 0xb7, 0x6a, 0xf0, 0x82, 0xc2, 0x21, 0x90, 0xd2, 0xe9, 0x57, - 0xcf, 0x98, 0x7e, 0xef, 0xea, 0x59, 0x87, 0xac, 0x6d, 0x98, 0x2e, 0xb7, 0xc3, 0x64, 0x50, 0xfa, 0x4f, 0xcd, 0xc4, - 0xb8, 0xb2, 0x26, 0x09, 0x20, 0xfe, 0x8d, 0xfd, 0x0e, 0x29, 0xdc, 0xbc, 0xbf, 0x1c, 0xc6, 0x8f, 0xbc, 0x1f, 0x23, - 0x7b, 0x92, 0x66, 0x88, 0x35, 0x93, 0x0a, 0xb9, 0xfb, 0x6a, 0xfd, 0x63, 0x62, 0x37, 0xd9, 0x03, 0x0b, 0x40, 0x6c, - 0x4d, 0x5b, 0xdd, 0xf2, 0x7e, 0xdf, 0x33, 0x45, 0x80, 0x1f, 0x94, 0x7f, 0x72, 0x67, 0x48, 0x06, 0x65, 0xd7, 0x0d, - 0x21, 0x1e, 0x94, 0x4d, 0xd3, 0x5e, 0x6f, 0x07, 0x67, 0x1e, 0xab, 0xeb, 0xb4, 0xb3, 0xb8, 0x5a, 0x64, 0x90, 0x56, - 0x1f, 0xb2, 0xd3, 0xcc, 0x3e, 0x3b, 0x59, 0x2a, 0xdd, 0xef, 0x43, 0x44, 0xdc, 0x49, 0xd6, 0xf6, 0xdb, 0x2d, 0xb8, - 0x86, 0x93, 0x41, 0xe8, 0xca, 0xde, 0x2e, 0xa3, 0x8d, 0x0b, 0x71, 0xda, 0x33, 0x9d, 0x2f, 0xf8, 0xf2, 0x28, 0xed, - 0x3c, 0x38, 0xd5, 0x13, 0x7d, 0x6e, 0xba, 0xab, 0x4c, 0xae, 0x75, 0x58, 0x8d, 0x41, 0x6d, 0x16, 0xb6, 0x70, 0x17, - 0xb6, 0xd1, 0x41, 0x6b, 0x5f, 0x16, 0xfc, 0x53, 0x06, 0xe0, 0x4b, 0xcf, 0x96, 0x5d, 0xaf, 0x49, 0xab, 0xd7, 0x32, - 0x0a, 0xb1, 0xa5, 0xed, 0xd5, 0xa7, 0xa3, 0x7c, 0xdc, 0x9c, 0x51, 0x5c, 0xc8, 0x51, 0x7e, 0xf4, 0x1a, 0xa2, 0xae, - 0x75, 0x1d, 0x17, 0x8b, 0x0e, 0x37, 0xae, 0xba, 0xed, 0xc6, 0xf5, 0x23, 0xe2, 0xad, 0xd1, 0x26, 0x85, 0x5a, 0x19, - 0x3b, 0x82, 0x97, 0x55, 0xc3, 0x21, 0x13, 0xc3, 0xa1, 0x84, 0x4c, 0x7d, 0xec, 0xde, 0xd0, 0xb4, 0xcf, 0x4f, 0x5b, - 0x3f, 0x62, 0xa9, 0x71, 0x14, 0x1b, 0xde, 0xf9, 0x3b, 0x8f, 0xad, 0x71, 0x25, 0x5f, 0x06, 0xb3, 0x5d, 0x41, 0xb5, - 0x35, 0xde, 0xb0, 0x57, 0xf1, 0x1f, 0x72, 0xa9, 0xe4, 0x6f, 0x7f, 0x86, 0x6b, 0x78, 0x6b, 0x4b, 0x07, 0x4d, 0x35, - 0xab, 0x98, 0xb9, 0x17, 0x9c, 0x7e, 0xdc, 0xbd, 0x22, 0x18, 0xfc, 0x9e, 0x8e, 0x82, 0x5c, 0x2c, 0xd5, 0x1a, 0x50, - 0x90, 0x4e, 0xec, 0x98, 0xca, 0x02, 0xc3, 0x00, 0xde, 0x90, 0x01, 0xf2, 0x98, 0xc2, 0xdd, 0x50, 0xe1, 0x85, 0xbf, - 0xe4, 0x64, 0x97, 0xc0, 0xb6, 0x66, 0x7c, 0xcc, 0x70, 0x07, 0x21, 0xff, 0x08, 0xb6, 0x62, 0x6b, 0x76, 0xc7, 0x16, - 0x0c, 0xc9, 0xc6, 0x71, 0x18, 0x63, 0x3e, 0x9e, 0xc4, 0x37, 0x62, 0x12, 0x0f, 0x78, 0x84, 0x8e, 0x11, 0x1b, 0x5e, - 0xcf, 0x62, 0x39, 0x80, 0x6c, 0xc5, 0x95, 0x0e, 0x08, 0xa1, 0xb1, 0xa1, 0x25, 0xaf, 0x0b, 0x83, 0x8b, 0x1d, 0xfb, - 0x2c, 0x47, 0x91, 0x8c, 0x43, 0xb0, 0x68, 0x55, 0x03, 0x0b, 0x13, 0xbb, 0xe3, 0xc5, 0x6c, 0x3d, 0xc7, 0x7f, 0x8e, - 0x47, 0x04, 0xc0, 0x0e, 0x0e, 0x0d, 0x5b, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x2b, 0xcb, 0xd3, 0x85, 0xdd, 0xf3, 0xb7, - 0x7c, 0xcc, 0x2e, 0x7f, 0xf4, 0x20, 0x72, 0xf6, 0xf2, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xbb, 0xd4, 0xcb, 0xd9, 0x1d, - 0x51, 0x10, 0xde, 0x81, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0xbe, 0xe5, 0x0b, 0x8c, 0x15, 0xbb, 0x48, 0x97, 0x1e, 0x66, - 0x84, 0xda, 0xd3, 0xf9, 0xb2, 0x51, 0x93, 0x70, 0x7b, 0xb3, 0x9c, 0x0c, 0x06, 0x5b, 0x7f, 0xcf, 0x37, 0xc0, 0x07, - 0x73, 0xf9, 0xa3, 0xb7, 0xa7, 0x72, 0xe1, 0x3f, 0xaf, 0xb3, 0xe4, 0xbd, 0xcf, 0xde, 0x0e, 0xf8, 0x02, 0xf0, 0x96, - 0xd0, 0x81, 0xeb, 0xde, 0x67, 0x12, 0xaf, 0xed, 0xad, 0xbe, 0x46, 0x20, 0x91, 0x2f, 0x00, 0x23, 0x26, 0xe6, 0xf7, - 0x5b, 0x88, 0xc0, 0x48, 0xc0, 0xb7, 0x55, 0x7b, 0xc4, 0xef, 0xb8, 0x01, 0xfc, 0xca, 0x7c, 0xf6, 0xc0, 0x43, 0xfd, - 0x33, 0xf1, 0xd9, 0x2d, 0x7f, 0xcf, 0x9f, 0x7b, 0x52, 0x92, 0x2e, 0x67, 0xef, 0xe7, 0x70, 0x3d, 0x94, 0xf2, 0x74, - 0x48, 0x3f, 0x1b, 0x83, 0x01, 0x84, 0x42, 0xe6, 0xad, 0x07, 0xac, 0x49, 0x21, 0xfe, 0x05, 0x7c, 0x3b, 0x4a, 0xd8, - 0xbc, 0xf5, 0x76, 0xbe, 0x96, 0x37, 0x6f, 0xbd, 0x07, 0x9f, 0xa2, 0x00, 0xab, 0xa0, 0x94, 0x05, 0x56, 0x41, 0xd8, - 0x68, 0x23, 0x8c, 0x81, 0xab, 0x77, 0x8d, 0xa1, 0xae, 0xe7, 0x88, 0x6d, 0x2b, 0x7d, 0x17, 0xbe, 0x83, 0x0c, 0xf8, - 0xe0, 0x75, 0x51, 0x12, 0x7d, 0x4e, 0x4d, 0x91, 0xb4, 0xee, 0xb9, 0xdf, 0x5a, 0x77, 0xb4, 0xa6, 0xd4, 0x47, 0x6e, - 0xc6, 0xc7, 0x63, 0xfd, 0x5c, 0x68, 0x91, 0x60, 0x0a, 0x1a, 0xd7, 0xa0, 0x2d, 0x40, 0xd0, 0xe7, 0x01, 0xb2, 0x96, - 0x14, 0x0b, 0xbe, 0xfd, 0x15, 0x62, 0xf0, 0xca, 0xf4, 0xce, 0xe5, 0x2a, 0x23, 0x61, 0x7b, 0xe1, 0xd7, 0xc3, 0xda, - 0x9f, 0x38, 0xb5, 0xb0, 0xb4, 0x9a, 0x83, 0xfa, 0xa9, 0x2d, 0xc7, 0xa9, 0xaa, 0xfd, 0x4b, 0x92, 0x54, 0xbb, 0x4a, - 0xcb, 0xe9, 0xbd, 0x7d, 0xd3, 0x65, 0x82, 0x8d, 0xfd, 0x80, 0xaa, 0x23, 0xab, 0x61, 0xf7, 0x85, 0xfa, 0xa2, 0xa7, - 0x64, 0x42, 0xf3, 0x51, 0x45, 0xf3, 0xec, 0x7e, 0xb3, 0xa3, 0xfe, 0xd3, 0xeb, 0xa1, 0x08, 0x90, 0xac, 0xd2, 0x62, - 0x29, 0x72, 0x36, 0xf6, 0xd3, 0x61, 0x92, 0xa9, 0xf0, 0x82, 0x74, 0x74, 0xf7, 0x1b, 0xf7, 0xb7, 0xdc, 0x40, 0xd6, - 0x68, 0xd5, 0x06, 0x63, 0xa5, 0x68, 0x19, 0xac, 0x6f, 0xc6, 0xfd, 0xbe, 0xb8, 0x19, 0x4f, 0x45, 0x50, 0x03, 0x71, - 0x91, 0x78, 0x3e, 0x9e, 0xd6, 0xc4, 0x92, 0xda, 0x15, 0x18, 0xa3, 0xc7, 0x55, 0x51, 0xfb, 0xd4, 0xcf, 0x21, 0x14, - 0xa9, 0xd6, 0xcc, 0xb1, 0xc6, 0x8d, 0x11, 0x71, 0x87, 0x95, 0x6b, 0xa7, 0xf6, 0x3a, 0x00, 0xcb, 0xab, 0x71, 0x41, - 0xd8, 0x26, 0xa7, 0xce, 0x05, 0xac, 0x46, 0x43, 0xaa, 0xdd, 0x70, 0xeb, 0x65, 0xe7, 0x37, 0x8f, 0x13, 0x5b, 0x1b, - 0xe1, 0x96, 0x02, 0xca, 0x28, 0xbf, 0xb1, 0x9c, 0xb0, 0x3b, 0xd5, 0x3b, 0x52, 0xb5, 0x23, 0xce, 0x5c, 0xc0, 0x2a, - 0xc3, 0x53, 0xab, 0x6f, 0x62, 0x70, 0x22, 0xe4, 0xad, 0x74, 0xbc, 0xf6, 0x23, 0xee, 0x57, 0xf7, 0x75, 0xaf, 0x04, - 0x3f, 0x09, 0x79, 0xfd, 0x96, 0x77, 0x00, 0x58, 0xf1, 0x21, 0x2f, 0xa6, 0x85, 0xa3, 0x75, 0x19, 0x94, 0x01, 0x22, - 0x34, 0x03, 0xa0, 0x93, 0xab, 0x83, 0x28, 0x0d, 0x5c, 0x71, 0x87, 0x08, 0x3f, 0x8d, 0x9e, 0x56, 0xcf, 0xc3, 0xa7, - 0xf9, 0x34, 0xbc, 0xaa, 0x82, 0xe8, 0x2a, 0x0f, 0xa2, 0xa7, 0xf9, 0x4d, 0xf8, 0xb4, 0x9a, 0x46, 0x57, 0x55, 0x10, - 0x5e, 0xe5, 0x8d, 0x7d, 0xd7, 0xee, 0xee, 0x09, 0x79, 0xdb, 0xd5, 0x1f, 0xb9, 0x54, 0xf6, 0x94, 0xe9, 0xe5, 0x65, - 0xad, 0x57, 0x6a, 0xb7, 0xb9, 0x5e, 0xa3, 0x66, 0xea, 0xa3, 0xec, 0x2f, 0xb6, 0xb1, 0xf0, 0x64, 0x0e, 0xa1, 0xcf, - 0x48, 0x8b, 0xb9, 0xc7, 0xb9, 0xde, 0x1c, 0x48, 0x61, 0x60, 0xc4, 0xa4, 0x92, 0x91, 0xd3, 0x0b, 0x5c, 0x84, 0x72, - 0xc4, 0xb0, 0x96, 0xae, 0xf6, 0x59, 0x97, 0xde, 0x40, 0x5d, 0x53, 0xec, 0x6b, 0xc8, 0xc0, 0x8b, 0xa6, 0xd7, 0xc1, - 0x18, 0x90, 0x23, 0xf0, 0x8e, 0xcf, 0x96, 0x70, 0x60, 0x6e, 0x00, 0xfa, 0xe6, 0x51, 0x5f, 0x97, 0x15, 0xdf, 0xa8, - 0xbe, 0x99, 0x6e, 0x46, 0x4a, 0xf9, 0xb1, 0xe6, 0xab, 0xab, 0x67, 0xec, 0x8e, 0x6b, 0x54, 0x94, 0x5f, 0xf4, 0x62, - 0xbd, 0x07, 0xae, 0xba, 0x5f, 0xe0, 0x36, 0x8b, 0xc7, 0xae, 0x3c, 0x60, 0xd9, 0x8e, 0x3d, 0xb0, 0x5b, 0xf6, 0x9e, - 0x3d, 0x61, 0x6f, 0xd8, 0x17, 0xf6, 0x13, 0xaa, 0x36, 0x94, 0x90, 0xe7, 0x2f, 0xf8, 0x9d, 0x34, 0x3d, 0x4a, 0x54, - 0xb2, 0x07, 0xdb, 0x4c, 0x33, 0xdc, 0xb2, 0xf7, 0x7c, 0x31, 0x5c, 0xb3, 0x37, 0x90, 0x0d, 0x65, 0xe2, 0xc1, 0x9a, - 0xfd, 0xc4, 0x15, 0x88, 0x99, 0x3e, 0x0b, 0x4b, 0x4b, 0x54, 0x34, 0x65, 0xa2, 0x0c, 0xfd, 0x86, 0xe3, 0x8b, 0xec, - 0x27, 0x2c, 0x42, 0x7e, 0x66, 0xb8, 0x66, 0x0f, 0x7c, 0x31, 0x58, 0xb3, 0xf7, 0xda, 0x40, 0x34, 0xd8, 0xba, 0xa5, - 0x11, 0x92, 0x95, 0x2e, 0x4b, 0x4a, 0xd3, 0x3b, 0xfb, 0x1a, 0xb8, 0x65, 0xb7, 0x58, 0xbb, 0x27, 0x58, 0x34, 0x0a, - 0xfc, 0x83, 0x35, 0xfb, 0xc2, 0x25, 0x80, 0x9a, 0x5b, 0x9e, 0xf4, 0x0a, 0xd5, 0x05, 0xd2, 0xfd, 0xe0, 0x09, 0xa7, - 0x17, 0xd9, 0x17, 0x2c, 0x83, 0xbe, 0x32, 0x5c, 0xb3, 0x1d, 0xd6, 0xee, 0xd6, 0x58, 0xb6, 0xac, 0xea, 0x49, 0x44, - 0x60, 0x14, 0x54, 0x4a, 0xcb, 0xbf, 0x11, 0xcb, 0xa6, 0x6e, 0x1a, 0xd4, 0x86, 0xfe, 0x7c, 0x30, 0xfa, 0x0f, 0x5f, - 0xbf, 0xfb, 0xc1, 0x2b, 0xf5, 0xb5, 0xf7, 0x17, 0xc7, 0xb5, 0xb2, 0x44, 0xd7, 0xca, 0x5f, 0x79, 0x39, 0xfb, 0x65, - 0x3e, 0xd1, 0xb5, 0xa4, 0x1d, 0x86, 0x7c, 0x4d, 0x67, 0xbf, 0x74, 0x38, 0x5b, 0xfe, 0xea, 0xfb, 0x8d, 0xe9, 0x62, - 0xf5, 0x59, 0xdd, 0xbb, 0x0f, 0x83, 0x6d, 0xe3, 0xd4, 0x7b, 0x7f, 0xbe, 0xde, 0xd8, 0xcc, 0x5a, 0x7b, 0x66, 0xfe, - 0x0f, 0x57, 0x7a, 0x87, 0x43, 0x77, 0xcb, 0x77, 0xc3, 0xad, 0x3d, 0x0a, 0xf2, 0xfb, 0x52, 0x69, 0x9c, 0xd5, 0xfc, - 0x85, 0x97, 0x77, 0x49, 0xb1, 0x80, 0x68, 0xf4, 0xc9, 0x48, 0x42, 0xd7, 0xcc, 0xc4, 0x33, 0xc4, 0x57, 0x19, 0x20, - 0x73, 0x81, 0x68, 0x76, 0xcf, 0xc7, 0x93, 0xfb, 0x9b, 0x78, 0x72, 0x3f, 0xe0, 0x9f, 0x4c, 0x0b, 0xda, 0x8b, 0xed, - 0xde, 0x67, 0xbf, 0xf2, 0xc2, 0x5e, 0x8e, 0xbf, 0xf8, 0xec, 0x9d, 0x70, 0x57, 0xe8, 0x2f, 0x3e, 0xfb, 0x22, 0xf8, - 0xaf, 0x23, 0x4d, 0x94, 0xc1, 0xbe, 0xd4, 0xfc, 0xd7, 0x11, 0x32, 0x7e, 0xb0, 0xcf, 0x82, 0xbf, 0x03, 0xdf, 0xef, - 0x2a, 0x41, 0xab, 0xf8, 0xe7, 0x5a, 0xfd, 0x7c, 0x2f, 0xe3, 0x72, 0xe0, 0x4d, 0x68, 0x05, 0xbd, 0x79, 0x57, 0xcb, - 0x9f, 0xc4, 0xc3, 0x91, 0xaa, 0xa7, 0x86, 0x7f, 0x16, 0x8b, 0x59, 0xd4, 0x27, 0xe9, 0x54, 0xde, 0xe4, 0x2d, 0xcf, - 0xa4, 0x75, 0xf9, 0x1e, 0x42, 0x81, 0xdf, 0xda, 0x10, 0x05, 0x7b, 0x8e, 0x1b, 0xc1, 0x5b, 0x06, 0xf0, 0x91, 0xd9, - 0x74, 0xc7, 0x6f, 0xf9, 0x13, 0xfe, 0x85, 0xef, 0x83, 0x07, 0xfe, 0x9e, 0xbf, 0xe1, 0x3f, 0xf1, 0x3d, 0x5b, 0x4a, - 0xb4, 0xd3, 0x7a, 0x77, 0x1d, 0xec, 0x58, 0xbd, 0xbf, 0x0e, 0x1e, 0x58, 0xbd, 0x7b, 0x16, 0xdc, 0xb2, 0x7a, 0xff, - 0x2c, 0x78, 0xcf, 0x76, 0xd7, 0xc1, 0x13, 0xb6, 0xbf, 0x0e, 0xde, 0xb0, 0xdd, 0xb3, 0xe0, 0x0b, 0xdb, 0x3f, 0x0b, - 0x7e, 0x92, 0x18, 0x0f, 0x5f, 0x84, 0xe4, 0x38, 0xf9, 0x52, 0x33, 0xc3, 0xa7, 0x1b, 0x7c, 0x16, 0xd6, 0x2f, 0xaa, - 0x63, 0xf0, 0xb9, 0x66, 0xba, 0xc5, 0x81, 0x10, 0x4c, 0xb7, 0x37, 0xb8, 0xa3, 0x27, 0xa6, 0x55, 0x41, 0x2a, 0x58, - 0x57, 0x3b, 0x83, 0x45, 0xdd, 0xb4, 0xce, 0x64, 0xc7, 0x2f, 0x31, 0xee, 0xf0, 0x4b, 0x5c, 0xb0, 0x65, 0xd3, 0xe9, - 0xa4, 0x73, 0xfe, 0x24, 0xd0, 0x9b, 0xbf, 0xde, 0xf5, 0x73, 0xe9, 0x3b, 0x53, 0x34, 0x5c, 0x6b, 0x8d, 0x5b, 0x3b, - 0x7d, 0x68, 0xed, 0xf4, 0x4c, 0xaa, 0xd0, 0x22, 0x16, 0x95, 0x45, 0x55, 0x21, 0x93, 0x78, 0x90, 0x69, 0x7d, 0x5a, - 0xc2, 0x48, 0x91, 0x09, 0x68, 0xf4, 0x05, 0x1d, 0x03, 0x15, 0x59, 0x14, 0xd8, 0x92, 0x6f, 0x07, 0x09, 0xdb, 0xf0, - 0x78, 0x3a, 0x4c, 0x82, 0x25, 0x5b, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x56, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, - 0x79, 0x6f, 0x9d, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x96, 0xeb, 0x0d, 0x7e, 0xe7, 0xec, 0xe7, 0x1b, 0xb5, 0xbf, 0x83, - 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xcf, 0xed, 0x2d, 0x7d, 0x67, - 0xb6, 0xe9, 0x7f, 0xb7, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xd6, 0x9f, 0x3c, - 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xcf, 0x3f, 0x8d, 0x76, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, - 0x68, 0xef, 0xe4, 0xb9, 0xbd, 0x23, 0xee, 0x78, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, - 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xf3, 0xd9, 0xa7, 0xf9, 0x64, 0xc7, 0x4f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, - 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x7b, 0x7e, 0xba, 0x89, 0x0f, 0xff, 0xed, - 0x4a, 0xef, 0xbf, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, + 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0x97, 0x13, 0x71, 0x4e, 0x97, 0x24, 0xf5, 0x54, 0x42, + 0x49, 0x08, 0x76, 0xe9, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, + 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xab, + 0x78, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8a, 0x4d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, + 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xac, 0xe4, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, + 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0x1f, 0x55, 0x36, 0x76, 0x07, 0xe4, 0x90, 0x64, 0xb2, 0xb8, 0x1b, 0xdd, + 0x8a, 0x65, 0x51, 0x8a, 0x9f, 0xb1, 0x1e, 0xae, 0xd9, 0xc2, 0x7d, 0x06, 0x84, 0xf6, 0x13, 0xa5, 0xbd, 0x89, 0x34, + 0x41, 0xf7, 0x1d, 0x5b, 0x01, 0xc8, 0x00, 0x8a, 0xba, 0xda, 0xad, 0xcf, 0xf9, 0x39, 0x92, 0x66, 0x38, 0x8c, 0x6e, + 0x9f, 0xde, 0x05, 0x77, 0x83, 0x4b, 0xd4, 0x4a, 0x5f, 0xb2, 0xb8, 0x85, 0x41, 0xb5, 0x37, 0x4b, 0x38, 0xa8, 0x99, + 0xb5, 0x36, 0x02, 0xc1, 0x64, 0x0f, 0x05, 0x15, 0x73, 0x05, 0xfb, 0xa0, 0x60, 0x2d, 0x79, 0x1d, 0x1c, 0x6e, 0xed, + 0xcb, 0x4a, 0x71, 0xf1, 0xfc, 0x22, 0x69, 0x5d, 0x58, 0xca, 0x8b, 0xe7, 0x0d, 0x18, 0x5c, 0x8e, 0xb0, 0xa9, 0x2a, + 0x7f, 0xb2, 0x01, 0xd0, 0xad, 0x90, 0x22, 0x5e, 0x94, 0xc2, 0xb6, 0x95, 0xcf, 0x9c, 0xb0, 0xc1, 0x86, 0x3d, 0xc0, + 0xbd, 0x32, 0x28, 0x19, 0x5c, 0x88, 0x71, 0xbb, 0xd9, 0x05, 0xb8, 0x82, 0xa1, 0x30, 0xb6, 0xe6, 0x6f, 0x32, 0x2f, + 0x52, 0x02, 0x6e, 0x86, 0x28, 0x5f, 0x1b, 0x38, 0x99, 0xf4, 0xe4, 0x5a, 0xb2, 0x18, 0xb0, 0xa0, 0xc1, 0x77, 0xd4, + 0xfa, 0x3b, 0x93, 0x7f, 0xe3, 0xe9, 0xa1, 0x1f, 0x7c, 0xce, 0xbc, 0xa5, 0xcf, 0xde, 0x54, 0x32, 0x5a, 0x93, 0x44, + 0x79, 0xf5, 0x70, 0x09, 0x72, 0xc3, 0x72, 0xf4, 0xc0, 0x96, 0x20, 0x4e, 0x2c, 0x47, 0x09, 0x65, 0x74, 0x85, 0x7b, + 0x95, 0xd9, 0x32, 0x11, 0x48, 0x71, 0x60, 0x29, 0xe5, 0xde, 0x62, 0x1d, 0x2c, 0x71, 0x7f, 0x22, 0xb9, 0x80, 0x92, + 0x07, 0x50, 0xae, 0x14, 0x10, 0xf0, 0xe9, 0x00, 0xca, 0x97, 0xf2, 0x22, 0xfc, 0x89, 0x13, 0x35, 0x58, 0x8e, 0x1e, + 0x1a, 0xf6, 0xa3, 0x17, 0x5a, 0xf6, 0x87, 0x3b, 0xad, 0x69, 0x58, 0xf1, 0x3b, 0x98, 0x16, 0x13, 0xb7, 0x2f, 0x57, + 0x76, 0x55, 0x7c, 0xb6, 0x52, 0x67, 0x37, 0x35, 0x24, 0x61, 0x5f, 0x91, 0x55, 0x80, 0x83, 0x55, 0x11, 0xf7, 0x2c, + 0xcb, 0x7d, 0x18, 0xfd, 0xb9, 0x49, 0x4b, 0x61, 0xa1, 0x4a, 0xfa, 0xfb, 0xa6, 0x14, 0x48, 0x65, 0xa2, 0x13, 0x2d, + 0x04, 0x57, 0x60, 0x10, 0xb8, 0x17, 0x79, 0x0d, 0x80, 0x31, 0xe0, 0x52, 0xa0, 0x2c, 0xdb, 0x12, 0x42, 0xaa, 0xfb, + 0x19, 0xa8, 0xed, 0xc4, 0x7d, 0x1a, 0x91, 0xb5, 0x10, 0x7d, 0x15, 0x8c, 0x99, 0xf3, 0x52, 0xba, 0xc5, 0xa6, 0xab, + 0xcd, 0xea, 0x06, 0x9d, 0x4b, 0x5b, 0x6e, 0x7e, 0xc2, 0x16, 0x6b, 0x05, 0xca, 0x26, 0x24, 0x6d, 0xe7, 0x3c, 0x47, + 0xd9, 0x84, 0x96, 0xf6, 0x9e, 0x7a, 0x54, 0xa8, 0x4e, 0xb6, 0x5e, 0xaa, 0xa6, 0x16, 0x61, 0xb5, 0xb8, 0xa8, 0xfc, + 0x00, 0x74, 0x53, 0x69, 0xf5, 0xb2, 0xae, 0xd1, 0x14, 0x6a, 0xb5, 0x70, 0xdc, 0x68, 0x67, 0xd3, 0x65, 0x7a, 0x87, + 0x38, 0xab, 0xd2, 0x0e, 0xfd, 0x7d, 0xa6, 0x5d, 0x2f, 0x3b, 0xfa, 0xcd, 0xb8, 0xba, 0xc0, 0x85, 0xd8, 0x80, 0xcf, + 0xb9, 0xbf, 0xbc, 0xde, 0xf3, 0xb8, 0xe7, 0x1f, 0x0e, 0xc8, 0x9e, 0xd4, 0xfe, 0x50, 0x7d, 0xec, 0x0a, 0x86, 0x2c, + 0x8c, 0x52, 0x7f, 0x91, 0xf2, 0xde, 0x13, 0x1c, 0xf7, 0xcf, 0x55, 0x8f, 0xfd, 0x98, 0xf1, 0x7d, 0x5d, 0x6c, 0xa2, + 0x84, 0xa2, 0x1a, 0x7a, 0xab, 0x62, 0x53, 0x89, 0xb8, 0x78, 0xc8, 0x7b, 0x0c, 0x93, 0x61, 0x2c, 0x64, 0x2a, 0xfc, + 0x29, 0x53, 0xc1, 0x23, 0x84, 0x12, 0x37, 0xeb, 0x1e, 0x69, 0x37, 0x21, 0x4e, 0xa9, 0x16, 0xa5, 0x4c, 0xc6, 0xbf, + 0xf5, 0x13, 0x28, 0xcf, 0x29, 0x5a, 0xa6, 0x1f, 0x15, 0x2e, 0xd3, 0x37, 0xeb, 0xe3, 0xd2, 0x33, 0x11, 0xea, 0xcc, + 0xc5, 0xa6, 0xd6, 0xe9, 0x18, 0x3b, 0xa5, 0x53, 0x1b, 0xf6, 0xa5, 0x52, 0x5c, 0x56, 0x14, 0xfe, 0x8d, 0x44, 0x56, + 0x3d, 0x23, 0x8e, 0xff, 0x2b, 0x6b, 0x9f, 0x61, 0x15, 0xf8, 0x65, 0x20, 0xef, 0x17, 0x00, 0x1f, 0xd7, 0x75, 0x99, + 0xde, 0x6e, 0x80, 0x36, 0x84, 0x86, 0xbf, 0xe7, 0x23, 0x03, 0xa6, 0xfb, 0x08, 0x67, 0x48, 0x0f, 0x75, 0xce, 0xe9, + 0xac, 0x4c, 0xe7, 0x5c, 0x85, 0xb5, 0x04, 0x7b, 0x39, 0x69, 0x72, 0xb9, 0x2e, 0x41, 0xcd, 0x04, 0x6e, 0x1f, 0xda, + 0x23, 0x42, 0xa8, 0x4d, 0x59, 0x4d, 0x2f, 0xa1, 0xe6, 0x9d, 0x9c, 0x76, 0x34, 0x29, 0xc1, 0x55, 0x43, 0x67, 0xe5, + 0xfa, 0xaf, 0xc3, 0xa1, 0x77, 0x9b, 0x15, 0xd1, 0x1f, 0x3d, 0xf4, 0x77, 0xdc, 0xde, 0xa4, 0x5f, 0x20, 0x5a, 0xc6, + 0xfa, 0x1b, 0x32, 0xa0, 0xe3, 0xc9, 0xf0, 0xb6, 0xd8, 0xf6, 0xd8, 0x17, 0xd4, 0x60, 0xe9, 0xeb, 0xc7, 0x1f, 0x20, + 0xa1, 0xea, 0xda, 0x17, 0x16, 0x4f, 0x98, 0xa7, 0x44, 0xdb, 0xc2, 0x87, 0xb0, 0xd0, 0x2f, 0x10, 0x19, 0x09, 0xe1, + 0xa6, 0xb2, 0x7b, 0x94, 0xb4, 0x0b, 0x7d, 0xe9, 0x6b, 0xd9, 0x57, 0xbe, 0x73, 0x01, 0xb0, 0xb2, 0xcf, 0x6d, 0xb8, + 0x27, 0xfd, 0x29, 0xd5, 0x87, 0xed, 0x6f, 0xc9, 0x02, 0x0a, 0x2d, 0xac, 0xa7, 0x72, 0x76, 0xae, 0x4b, 0x9e, 0x66, + 0xd3, 0xfd, 0x1a, 0xf6, 0xa8, 0x7b, 0xf4, 0x9a, 0x0a, 0xce, 0x2f, 0xcd, 0xe8, 0xfd, 0xd3, 0x50, 0xa8, 0x8e, 0x3a, + 0x77, 0x90, 0x75, 0x69, 0x5d, 0x72, 0x7e, 0xb3, 0x72, 0x47, 0x61, 0x7e, 0x1f, 0x82, 0x67, 0x58, 0xf7, 0xee, 0xe2, + 0xbc, 0xf7, 0x67, 0x6b, 0x8e, 0xfc, 0x98, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0xf6, 0xdb, + 0x20, 0x87, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, + 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xdb, 0x20, 0xd7, 0x5d, 0x30, 0xcd, 0x91, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x92, 0x0a, + 0xcd, 0x22, 0x6d, 0x95, 0x8c, 0x7f, 0x47, 0xda, 0x4c, 0xc9, 0x1e, 0x5b, 0x03, 0xef, 0x25, 0x28, 0x27, 0xc3, 0x14, + 0xc3, 0x77, 0x7c, 0xbd, 0xf3, 0x98, 0x7b, 0xce, 0x31, 0xdb, 0xa4, 0xec, 0x08, 0x26, 0xc9, 0xc6, 0x37, 0x14, 0x6f, + 0xf8, 0xfe, 0xb6, 0x12, 0x25, 0x80, 0x5e, 0x16, 0xfc, 0x85, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, + 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, + 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, + 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, + 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, + 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, + 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, + 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, + 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, 0xf3, 0xfd, 0x95, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, + 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, + 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, + 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, + 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, + 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, + 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, + 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, + 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, + 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, + 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, + 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, + 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, + 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, + 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, + 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, + 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, + 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, + 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, + 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, + 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, + 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, + 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, + 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd1, + 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, + 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe1, 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, + 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, + 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, + 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, + 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, + 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, + 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, + 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, + 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, + 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, + 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, + 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, + 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0x7c, 0xa1, 0x56, 0xda, 0x59, 0x99, + 0x78, 0x35, 0xcb, 0xc0, 0x59, 0xe0, 0xa2, 0xf2, 0x59, 0xa6, 0x55, 0x4f, 0x55, 0x82, 0x3e, 0xaf, 0xe4, 0x04, 0x57, + 0x82, 0x93, 0x0d, 0xc8, 0x2f, 0x40, 0x92, 0xa6, 0x94, 0x35, 0xe5, 0x8b, 0x4b, 0xba, 0x21, 0xa3, 0xe7, 0xbc, 0xe7, + 0x45, 0xc3, 0xd0, 0xbf, 0xf0, 0x4a, 0x08, 0xdf, 0xc4, 0x6d, 0x1b, 0xa5, 0xb0, 0xbf, 0x09, 0x2c, 0x3e, 0x61, 0x3f, + 0x78, 0x4b, 0x7f, 0x3a, 0x0e, 0xc2, 0x21, 0x72, 0x43, 0xc5, 0x1c, 0xd8, 0xd3, 0x80, 0xc5, 0x26, 0xbe, 0xda, 0x4c, + 0xe2, 0xc1, 0xc0, 0xd7, 0x19, 0x8b, 0x59, 0x0c, 0x34, 0xc8, 0xf1, 0xe0, 0x72, 0xae, 0x4f, 0x08, 0xfd, 0x30, 0xa2, + 0x72, 0x54, 0xa0, 0x73, 0x10, 0x0d, 0x96, 0x80, 0xa7, 0xde, 0xca, 0x06, 0x49, 0xc6, 0x24, 0x93, 0xb8, 0xd6, 0x24, + 0xd5, 0xe1, 0x84, 0xd6, 0x81, 0x8e, 0xab, 0x0b, 0xe8, 0x7c, 0x5c, 0xf7, 0x3e, 0x5e, 0x0d, 0x17, 0x54, 0xfa, 0x85, + 0x18, 0x78, 0xf5, 0x74, 0x1c, 0x5c, 0xd2, 0xad, 0x70, 0xb1, 0x0a, 0xb7, 0x3f, 0xcb, 0x07, 0x8e, 0x3b, 0x2a, 0x69, + 0x08, 0x0c, 0xde, 0x1e, 0xba, 0x9b, 0x19, 0x1a, 0xea, 0xa4, 0x7d, 0x18, 0x87, 0x72, 0x88, 0x55, 0x2b, 0x2e, 0xa4, + 0x37, 0x82, 0x6f, 0x17, 0x8a, 0xb1, 0x6c, 0xec, 0xd2, 0x50, 0x14, 0xfe, 0x0a, 0x60, 0x87, 0xda, 0x5f, 0xa9, 0xe4, + 0x63, 0x64, 0x54, 0xd3, 0x40, 0xc7, 0x00, 0x2c, 0x59, 0x9a, 0x48, 0xaa, 0x48, 0x23, 0xf1, 0x47, 0x66, 0xac, 0xa3, + 0xa6, 0xeb, 0x0b, 0xa6, 0xaa, 0x45, 0xd2, 0xed, 0x4c, 0x62, 0x39, 0x91, 0xa4, 0xb6, 0xfb, 0x88, 0x18, 0x0c, 0x7c, + 0xb0, 0x11, 0xd3, 0x4c, 0x84, 0x23, 0x1e, 0x95, 0xc8, 0xa2, 0xcb, 0x6f, 0xa3, 0x4c, 0xda, 0xbe, 0xac, 0xc8, 0x16, + 0x04, 0xd3, 0x93, 0xe8, 0x83, 0x24, 0xe5, 0x54, 0x24, 0xd2, 0x8c, 0x10, 0xe0, 0xc7, 0x93, 0xf2, 0x4a, 0x7f, 0x0e, + 0x9a, 0x56, 0x82, 0x97, 0x0c, 0x92, 0x47, 0xe2, 0x67, 0x52, 0x30, 0x8b, 0xb1, 0x6a, 0x30, 0xc0, 0x72, 0xaa, 0x67, + 0x8e, 0x49, 0xfa, 0x6f, 0x9d, 0x4e, 0xd8, 0x2f, 0xbd, 0xdc, 0xd6, 0xf2, 0xa6, 0xb9, 0xf7, 0xd2, 0xab, 0x58, 0xaa, + 0x61, 0x19, 0xf4, 0x5f, 0x13, 0xed, 0x82, 0xad, 0x2d, 0x63, 0xc2, 0xaa, 0x1f, 0x40, 0xda, 0x23, 0x5d, 0x5e, 0x35, + 0xcc, 0x99, 0xe0, 0xd1, 0x85, 0x35, 0x0f, 0xa2, 0x0b, 0xe1, 0x23, 0x97, 0xdd, 0x24, 0xb9, 0x1a, 0x4f, 0xfc, 0x70, + 0x30, 0x50, 0x00, 0xb4, 0xb4, 0x4e, 0x8a, 0x41, 0xf8, 0x4c, 0xc8, 0x81, 0x34, 0x3a, 0xaa, 0x02, 0x2c, 0x96, 0xd9, + 0x55, 0x39, 0xc9, 0x06, 0x03, 0x1f, 0xc4, 0xc6, 0xc4, 0x6e, 0x68, 0x36, 0xf7, 0xd9, 0x89, 0x82, 0xac, 0x36, 0x87, + 0xad, 0x99, 0x6e, 0x81, 0x01, 0xc0, 0x20, 0x22, 0x58, 0xee, 0x73, 0x23, 0x1f, 0x51, 0xa7, 0xa7, 0x30, 0x02, 0x82, + 0x5f, 0x4e, 0x04, 0x22, 0x17, 0x09, 0xd4, 0x03, 0xcc, 0x04, 0x98, 0x51, 0xc5, 0xf0, 0x12, 0xd8, 0xc5, 0x73, 0xf3, + 0x8a, 0x41, 0xff, 0xa2, 0x49, 0x96, 0x68, 0x2a, 0x71, 0x34, 0x46, 0x4e, 0xa5, 0x31, 0x32, 0x20, 0x76, 0x71, 0xfc, + 0x7b, 0x4a, 0x8f, 0x82, 0x94, 0x7d, 0xae, 0x0c, 0x71, 0x38, 0x8a, 0xaf, 0x60, 0xd5, 0x38, 0x1c, 0x6a, 0xf3, 0x7a, + 0x3a, 0xab, 0xe7, 0x03, 0x11, 0xc0, 0x7f, 0x43, 0xc1, 0x7e, 0xd1, 0x54, 0xe4, 0x06, 0xa9, 0xf3, 0x70, 0x48, 0x41, + 0x3e, 0xd5, 0x4d, 0xfe, 0xbe, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, + 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, + 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, + 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, + 0x7f, 0x95, 0xee, 0xcd, 0xa9, 0x0d, 0x72, 0x00, 0xdb, 0xbd, 0x87, 0xdb, 0x31, 0x7a, 0x20, 0x83, 0x37, 0x42, 0xce, + 0x39, 0xbf, 0x9c, 0x5a, 0x33, 0x26, 0x1a, 0x16, 0xac, 0x1c, 0x46, 0x7e, 0x80, 0x8c, 0x97, 0x53, 0x60, 0x65, 0x3f, + 0x2a, 0xe2, 0xd2, 0x1f, 0x46, 0xfe, 0xc5, 0xf3, 0x20, 0xe3, 0x5e, 0x34, 0xec, 0xf8, 0x02, 0xec, 0xd5, 0x17, 0xcf, + 0x59, 0x34, 0xe0, 0xd5, 0x55, 0x3d, 0xcd, 0x82, 0x61, 0xc6, 0xa2, 0xab, 0x62, 0x08, 0x3e, 0xb4, 0x2f, 0xca, 0x41, + 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x47, 0x70, 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, + 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x85, 0xd4, 0x6c, 0x14, 0x68, 0x4e, 0xae, 0xd0, 0x9c, + 0xac, 0x84, 0x5a, 0xf2, 0x49, 0x85, 0x13, 0x76, 0x3e, 0xc9, 0x95, 0xdd, 0x68, 0x8c, 0x81, 0x8b, 0xf6, 0xdc, 0x16, + 0x46, 0x66, 0x3a, 0x4b, 0xd1, 0x80, 0x85, 0x67, 0xe2, 0x94, 0xc6, 0x80, 0xf6, 0xe5, 0xc0, 0xd2, 0x86, 0xfc, 0x28, + 0x67, 0x06, 0xda, 0x86, 0x94, 0x46, 0xcd, 0xc0, 0x9f, 0xa9, 0x09, 0xf3, 0x2b, 0x58, 0x89, 0x20, 0xaa, 0x0b, 0x30, + 0x49, 0x72, 0x32, 0x1a, 0x29, 0x2b, 0x91, 0x9c, 0x03, 0xde, 0x47, 0xf0, 0x64, 0x11, 0xdb, 0xda, 0x9f, 0xd2, 0xff, + 0xea, 0xf0, 0xb9, 0xf4, 0x9f, 0x09, 0x60, 0x21, 0x97, 0x06, 0x91, 0x81, 0xc2, 0x21, 0x35, 0x95, 0x88, 0x13, 0xc7, + 0x33, 0xf0, 0x0d, 0x5c, 0xa0, 0x29, 0xa0, 0x3f, 0xa8, 0x19, 0x45, 0x64, 0xe1, 0xaf, 0x9e, 0xdd, 0xd4, 0x8d, 0x9e, + 0x67, 0xce, 0x6b, 0xd0, 0xcc, 0x40, 0x48, 0x8f, 0x53, 0xf5, 0x36, 0x24, 0x3a, 0x2f, 0x2f, 0xf5, 0xcb, 0x84, 0x48, + 0x56, 0x44, 0x9e, 0xbe, 0xcf, 0xc1, 0x3c, 0xa2, 0x08, 0x1d, 0x5c, 0x99, 0x87, 0xc3, 0xb9, 0xa0, 0xf0, 0x1d, 0xe5, + 0xf9, 0x80, 0xd3, 0x2c, 0x4a, 0x40, 0x1b, 0xc8, 0x72, 0x53, 0xe6, 0x3a, 0x69, 0x99, 0xba, 0xf7, 0x60, 0x25, 0xa8, + 0xd0, 0xcd, 0x29, 0x28, 0x94, 0x91, 0xa0, 0x94, 0x56, 0x83, 0x50, 0xaa, 0xc3, 0x22, 0x88, 0x1c, 0xb2, 0x10, 0x70, + 0x33, 0x15, 0x8d, 0x96, 0x34, 0x3c, 0xc2, 0xb9, 0x81, 0x42, 0x00, 0x12, 0x7b, 0xaa, 0x28, 0xe3, 0x72, 0x08, 0xf8, + 0x28, 0xe1, 0x10, 0x67, 0x4d, 0xda, 0xf2, 0x1c, 0xc4, 0xb1, 0x5c, 0xf2, 0x75, 0x85, 0x60, 0x10, 0xa1, 0xcf, 0x90, + 0x3f, 0x59, 0xce, 0xbf, 0x5b, 0x87, 0x69, 0x47, 0xf8, 0xb0, 0xab, 0x2d, 0xb8, 0x98, 0xdd, 0xce, 0x27, 0x10, 0xdf, + 0x72, 0x3b, 0x3f, 0xc6, 0x10, 0x59, 0xf8, 0x83, 0xbb, 0xa1, 0xe4, 0x8a, 0x42, 0x97, 0xf5, 0x88, 0x14, 0xd9, 0xd3, + 0x35, 0x47, 0x10, 0x1c, 0x68, 0xd5, 0x20, 0x43, 0x23, 0xf1, 0xc5, 0x73, 0xc8, 0x1a, 0xac, 0xf9, 0xe7, 0x8a, 0x9c, + 0xd5, 0xfd, 0xc9, 0x06, 0xaa, 0x49, 0x26, 0x6b, 0x45, 0xe5, 0xfc, 0xf5, 0xaa, 0x2c, 0x4f, 0x56, 0x65, 0xb8, 0x1a, + 0x74, 0x55, 0x65, 0xc9, 0x91, 0xda, 0x00, 0xad, 0xe9, 0x0a, 0x31, 0x14, 0xb2, 0x06, 0x4b, 0xab, 0x2a, 0x6b, 0xea, + 0x13, 0x08, 0xf4, 0x01, 0x96, 0x51, 0xb3, 0x9f, 0x0e, 0xff, 0x15, 0xfc, 0x4b, 0x85, 0x2c, 0xd5, 0x69, 0x9d, 0x89, + 0x5f, 0x83, 0x25, 0xc3, 0x3f, 0x7e, 0x0b, 0xd6, 0x80, 0x25, 0x40, 0x96, 0xbb, 0x8d, 0x8d, 0xd6, 0x2b, 0xaf, 0x10, + 0x5f, 0x6a, 0x7d, 0xd1, 0x6f, 0xdd, 0x26, 0x6a, 0x05, 0x18, 0xa1, 0xd0, 0x22, 0xc0, 0x56, 0x0f, 0xdc, 0x53, 0xf0, + 0x03, 0x31, 0x9c, 0x6b, 0xd2, 0x9a, 0x3a, 0xe1, 0x75, 0x36, 0x8e, 0x44, 0x54, 0x6f, 0xe1, 0xe2, 0x5e, 0x6f, 0x2d, + 0xfe, 0x46, 0x05, 0x02, 0x20, 0x8b, 0x29, 0xd6, 0xce, 0x1b, 0xd2, 0x2b, 0xc3, 0x4e, 0x42, 0xef, 0x0d, 0x3b, 0x81, + 0xbc, 0x38, 0xec, 0x14, 0xba, 0x44, 0xdb, 0x29, 0x52, 0x13, 0x6d, 0x27, 0x2d, 0x56, 0x61, 0x09, 0xc1, 0xaf, 0xda, + 0x5b, 0x47, 0xd9, 0xbe, 0xc8, 0x12, 0xa6, 0x2d, 0x60, 0x94, 0x5b, 0xf5, 0x99, 0x53, 0xc4, 0x4a, 0xd9, 0x3b, 0x9d, + 0x54, 0xb9, 0x8b, 0x7c, 0x6a, 0x35, 0x45, 0x26, 0x7f, 0x7f, 0xdc, 0x22, 0xf9, 0xe4, 0xe7, 0x76, 0xc3, 0x64, 0xfa, + 0xc7, 0xa3, 0x2f, 0xa0, 0x2b, 0xb2, 0xd3, 0x27, 0x10, 0x90, 0xa9, 0xa0, 0x5a, 0xdd, 0x2a, 0xa6, 0x79, 0xbb, 0xca, + 0x6e, 0x2f, 0x94, 0x18, 0x4e, 0x67, 0x27, 0xe1, 0xd1, 0x66, 0xc8, 0xc0, 0x21, 0x08, 0x14, 0x42, 0x45, 0x31, 0x3c, + 0x02, 0xb5, 0x46, 0xf2, 0x01, 0x7e, 0xb4, 0x3b, 0x15, 0x44, 0x6a, 0x37, 0x15, 0x37, 0x4e, 0x6e, 0xba, 0x5e, 0x0a, + 0xd4, 0x3a, 0x25, 0x2b, 0x80, 0x12, 0xa2, 0xfe, 0x24, 0xb6, 0xf5, 0x2b, 0xb8, 0x62, 0xf3, 0x7d, 0xa3, 0xe8, 0xc9, + 0xf5, 0x29, 0xea, 0x56, 0x5c, 0x9d, 0xa6, 0xad, 0xe6, 0xd8, 0x71, 0x86, 0x1c, 0x3c, 0x2b, 0x08, 0xb6, 0xa3, 0x12, + 0xe5, 0x75, 0xbb, 0xe9, 0x98, 0xd8, 0xea, 0x9f, 0x45, 0xb5, 0xb9, 0x83, 0x8a, 0x88, 0xf8, 0x28, 0xbb, 0x79, 0xd2, + 0x7e, 0x07, 0x7b, 0xac, 0xd5, 0x20, 0xb2, 0xcf, 0xe0, 0x2a, 0xd7, 0x69, 0x91, 0xdb, 0x32, 0x38, 0xff, 0xf0, 0x6a, + 0x57, 0x61, 0x93, 0x63, 0x5d, 0x5d, 0xcd, 0x54, 0x27, 0x15, 0x1b, 0x18, 0x6b, 0x5a, 0x4b, 0x35, 0x8f, 0x21, 0xe9, + 0xae, 0x2c, 0xce, 0xaa, 0xa4, 0x9b, 0x9e, 0x1b, 0x67, 0x0a, 0x31, 0x70, 0xb6, 0x1a, 0x2d, 0x67, 0x18, 0xa2, 0xeb, + 0xc3, 0x2c, 0xf1, 0x5b, 0x3d, 0xe5, 0x3e, 0x0f, 0xb7, 0x7e, 0x57, 0x2f, 0x38, 0x99, 0xec, 0x27, 0xc7, 0xb9, 0xdb, + 0x45, 0xda, 0x4f, 0x7c, 0x1b, 0xe6, 0x5f, 0xdf, 0x20, 0xee, 0x44, 0xfd, 0xcf, 0x0a, 0x80, 0x06, 0x37, 0x79, 0x2c, + 0x51, 0xea, 0xf7, 0xaa, 0xfa, 0x41, 0xcd, 0x54, 0x4d, 0x03, 0xc1, 0x9c, 0x4a, 0x01, 0x7f, 0xb8, 0x5d, 0xb8, 0xe2, + 0x11, 0x37, 0x2c, 0x8c, 0x7f, 0x7a, 0x35, 0x3b, 0x15, 0x54, 0x06, 0x6e, 0xc6, 0x7f, 0x7a, 0x82, 0x9d, 0xc2, 0x5a, + 0x01, 0x59, 0xe1, 0x4f, 0x2f, 0x7f, 0xe4, 0xfd, 0x8a, 0xff, 0xe9, 0x55, 0x8f, 0xbc, 0x8f, 0x38, 0x2f, 0x7f, 0x22, + 0xa9, 0x13, 0xa2, 0xba, 0xfc, 0x49, 0x98, 0x62, 0xab, 0x34, 0x7f, 0x4d, 0x0a, 0x9f, 0xe0, 0x33, 0xf0, 0x1d, 0xae, + 0xc2, 0xad, 0xf9, 0x0d, 0x1e, 0x3b, 0x16, 0xdb, 0x2e, 0xf5, 0x05, 0x94, 0x23, 0xb0, 0x88, 0xdc, 0x7e, 0xbb, 0xb2, + 0x5f, 0x2d, 0x8c, 0x32, 0xc6, 0xee, 0x4b, 0x56, 0xa2, 0x74, 0xd6, 0xef, 0x17, 0x52, 0x30, 0xb2, 0x0b, 0x6b, 0xb4, + 0x47, 0xa9, 0x7a, 0xf5, 0x3a, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, + 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, + 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, + 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0x5e, 0xe4, 0x18, 0x5b, 0x91, 0x03, 0x07, 0x32, 0xfc, 0x80, 0xc0, + 0x7b, 0xd9, 0xbf, 0x82, 0xc1, 0x30, 0xc1, 0x8d, 0x8c, 0x3a, 0x39, 0x67, 0x7f, 0x62, 0x60, 0x06, 0xf5, 0xa4, 0x76, + 0x9f, 0xdd, 0xab, 0xc0, 0x5e, 0x38, 0x03, 0xda, 0xbb, 0x31, 0xfa, 0x59, 0x15, 0x6b, 0x27, 0xfd, 0x53, 0xb1, 0x86, + 0x64, 0x3a, 0x2c, 0x8e, 0xb6, 0x69, 0x78, 0x24, 0x4f, 0x8e, 0xe3, 0x4d, 0xff, 0x70, 0x18, 0xe3, 0xc7, 0x51, 0x7e, + 0x6d, 0x01, 0xaf, 0xe2, 0x16, 0xd2, 0x58, 0xa4, 0xe8, 0x1d, 0x88, 0x39, 0x14, 0xbd, 0x64, 0xbf, 0x65, 0xbc, 0x9c, + 0x08, 0x4a, 0x49, 0x62, 0xc3, 0x3b, 0xd2, 0xd3, 0xb4, 0x1e, 0x6d, 0x65, 0xc0, 0x7e, 0x3d, 0xda, 0xd1, 0x5f, 0xa0, + 0x78, 0xb4, 0xf0, 0x97, 0xf4, 0x77, 0x71, 0x37, 0xf7, 0x9c, 0x6f, 0x1a, 0xdf, 0x11, 0x17, 0x28, 0xd6, 0xec, 0xfe, + 0x9a, 0x96, 0xce, 0x3a, 0x10, 0x1c, 0xf0, 0x16, 0xbb, 0x68, 0xdf, 0x6f, 0x5c, 0xa7, 0xa7, 0xfd, 0xb7, 0x6e, 0x8d, + 0xf2, 0xbd, 0x7f, 0x4a, 0x94, 0x83, 0xfd, 0x6b, 0x17, 0xcd, 0xdf, 0x7e, 0xca, 0x90, 0x54, 0x68, 0x6e, 0xb0, 0x9d, + 0x6c, 0x11, 0xd6, 0xc6, 0x38, 0xa8, 0xd8, 0x5d, 0x19, 0x46, 0xc0, 0xa0, 0x8e, 0xfd, 0x8f, 0x3e, 0x9b, 0x36, 0x64, + 0x1f, 0x00, 0x2a, 0x57, 0x21, 0x60, 0x0f, 0xc0, 0x89, 0x46, 0xb8, 0x01, 0x6e, 0x35, 0x5a, 0xd2, 0x41, 0xdd, 0x16, + 0x0c, 0x44, 0x4b, 0xd8, 0xc8, 0xdb, 0xae, 0x4e, 0x5f, 0x11, 0x3e, 0xd4, 0x4e, 0x4a, 0x87, 0xf2, 0x57, 0xcf, 0xd9, + 0xff, 0xec, 0xb0, 0xa6, 0xa6, 0xdc, 0x00, 0x66, 0xce, 0x4a, 0xe4, 0x15, 0x42, 0xa7, 0xc8, 0xef, 0x55, 0x5d, 0x89, + 0xe1, 0xb2, 0x16, 0x65, 0x67, 0x76, 0xeb, 0x44, 0xef, 0x9c, 0x82, 0x5a, 0x2a, 0x1b, 0xe4, 0x24, 0xd5, 0xe6, 0x23, + 0x6b, 0x05, 0x25, 0xea, 0x1a, 0x05, 0x8e, 0x4f, 0xb9, 0x76, 0xff, 0xef, 0x9c, 0x09, 0x6a, 0xb6, 0x51, 0xdd, 0x5f, + 0xeb, 0xa7, 0xaa, 0x26, 0xb1, 0x00, 0x97, 0x93, 0x34, 0xef, 0x78, 0x84, 0xd5, 0x3f, 0x4e, 0x96, 0x22, 0xd0, 0xeb, + 0x88, 0x76, 0x25, 0x20, 0x41, 0x3b, 0x39, 0x0b, 0x15, 0x81, 0x02, 0x7d, 0xfd, 0xfb, 0x4d, 0x9a, 0xc5, 0x72, 0x35, + 0xdb, 0xc3, 0x44, 0x59, 0xac, 0x87, 0x08, 0x72, 0x66, 0xea, 0x60, 0xbf, 0xa7, 0x19, 0xcd, 0xc2, 0x2b, 0x53, 0x82, + 0x4b, 0x71, 0x15, 0x15, 0x39, 0xf8, 0x1c, 0xe2, 0x0b, 0x9f, 0x0a, 0xb9, 0x41, 0x44, 0xd3, 0xef, 0x25, 0xaa, 0x1d, + 0x29, 0x90, 0x43, 0xc9, 0x4f, 0x88, 0xbf, 0x64, 0x6d, 0x8c, 0xfb, 0xa5, 0x53, 0xed, 0x57, 0x0a, 0xc1, 0xfd, 0x67, + 0x5b, 0x6c, 0x54, 0x79, 0xa2, 0x47, 0x9f, 0x62, 0xfd, 0x4f, 0x16, 0x50, 0xaa, 0xfb, 0x36, 0x38, 0x15, 0x8f, 0xc2, + 0x4d, 0x5d, 0xdc, 0x20, 0xb4, 0x40, 0x39, 0xaa, 0x8a, 0x4d, 0x19, 0x11, 0x27, 0xec, 0xa6, 0x2e, 0x7a, 0x9a, 0x03, + 0x9d, 0x3a, 0x2c, 0x4d, 0xe4, 0x89, 0xd0, 0x6e, 0x41, 0xf7, 0x34, 0xc7, 0x4a, 0xbc, 0x94, 0xa5, 0x83, 0xac, 0x13, + 0x69, 0x42, 0xe5, 0xae, 0xae, 0x3a, 0x2a, 0x95, 0xba, 0xe1, 0x4d, 0xaa, 0x19, 0x7f, 0x97, 0xe6, 0x4f, 0x2c, 0xfb, + 0x4d, 0xeb, 0xb7, 0x5a, 0xed, 0x8d, 0xd5, 0xa3, 0x92, 0x35, 0xc7, 0xd9, 0x84, 0xa4, 0xf4, 0x09, 0xdb, 0xcd, 0xa4, + 0x6b, 0x1d, 0x78, 0x12, 0x5c, 0x0e, 0x3d, 0x01, 0x15, 0x83, 0x26, 0xde, 0xee, 0x02, 0xf5, 0x08, 0x3c, 0x03, 0xe5, + 0x13, 0xb5, 0x0e, 0xf8, 0x79, 0xad, 0xe5, 0x29, 0x23, 0x0c, 0xab, 0x9d, 0x45, 0xcb, 0xc1, 0x79, 0xa7, 0x08, 0x5c, + 0xbb, 0x12, 0x78, 0x3e, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, 0xa7, + 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, 0x36, + 0x9f, 0x7d, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, 0xcf, + 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, 0x76, + 0x7c, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, 0x88, + 0xc2, 0x2c, 0xfb, 0xb1, 0x28, 0xfe, 0xa8, 0xf4, 0x1d, 0x81, 0x8e, 0xee, 0xbc, 0xa8, 0xd3, 0xe5, 0xee, 0x03, 0x61, + 0x3c, 0x79, 0xf5, 0x11, 0xd1, 0xad, 0xef, 0x33, 0xf7, 0x2b, 0xc0, 0x8d, 0xe0, 0x0e, 0xa2, 0xbd, 0x5b, 0xea, 0x93, + 0x5a, 0x7d, 0xad, 0xd7, 0xce, 0xd3, 0xf3, 0x9b, 0xce, 0xed, 0x77, 0xdf, 0x1c, 0x6d, 0xbd, 0xc7, 0x85, 0xb5, 0xb2, + 0xf4, 0x54, 0x15, 0xec, 0xcd, 0xf2, 0x54, 0x15, 0x4c, 0x1e, 0x78, 0xcd, 0x7e, 0x41, 0x83, 0x2b, 0x1d, 0x6d, 0xbc, + 0x27, 0x6a, 0xe0, 0x16, 0x85, 0xa5, 0xc3, 0x2f, 0xb9, 0x99, 0xbc, 0xc2, 0xfd, 0xa5, 0x22, 0x17, 0xfb, 0xce, 0x19, + 0xdd, 0x99, 0x59, 0xf7, 0xaa, 0xc2, 0xd5, 0x82, 0x5c, 0x1d, 0xd8, 0x5a, 0x76, 0x71, 0xb8, 0x61, 0x11, 0x05, 0x08, + 0xc4, 0xf4, 0x4a, 0xad, 0xfd, 0x11, 0x0d, 0x42, 0x3e, 0x18, 0xf8, 0x05, 0x06, 0xab, 0x02, 0x85, 0x0f, 0x14, 0xc9, + 0x5f, 0x7b, 0x02, 0x76, 0xf1, 0x0c, 0xd0, 0xad, 0xd8, 0xac, 0x18, 0x21, 0x42, 0x26, 0xcb, 0x59, 0x4d, 0x67, 0x90, + 0x4f, 0x7d, 0xf1, 0x8d, 0xad, 0x3a, 0x9d, 0xb7, 0x35, 0x55, 0x4e, 0x1d, 0x0a, 0xdd, 0xdd, 0xd4, 0x9d, 0x5b, 0x17, + 0x79, 0xea, 0x10, 0x72, 0xa5, 0x62, 0x25, 0xa6, 0xa1, 0xe6, 0x49, 0x9a, 0x51, 0x7f, 0xb1, 0xf7, 0x7b, 0x8d, 0xc2, + 0x29, 0x7f, 0x3a, 0x06, 0x55, 0xb8, 0xaa, 0x21, 0x8e, 0xa5, 0x2a, 0x1e, 0xd9, 0x20, 0xd0, 0xbc, 0xba, 0x55, 0x49, + 0x13, 0x32, 0xb9, 0x11, 0x3e, 0x35, 0x29, 0xe5, 0x69, 0xda, 0xa4, 0x95, 0x22, 0x75, 0xf0, 0x41, 0x9d, 0x6a, 0x3c, + 0x37, 0xab, 0x17, 0x00, 0x66, 0x9c, 0x5f, 0xf1, 0x4b, 0xc5, 0x65, 0xd4, 0x56, 0x66, 0xd2, 0xfe, 0xe4, 0x68, 0x6c, + 0xd4, 0xe5, 0xb4, 0x51, 0x46, 0x58, 0x29, 0xcd, 0x49, 0xb1, 0x1c, 0xcf, 0x3f, 0x60, 0xb0, 0xe6, 0x09, 0xec, 0x60, + 0xa2, 0x52, 0xde, 0x47, 0x40, 0x7c, 0x9d, 0xa4, 0x77, 0x09, 0xa4, 0x48, 0xff, 0xd2, 0x25, 0x77, 0x19, 0x1b, 0x88, + 0x31, 0x2b, 0x66, 0x46, 0xff, 0x83, 0xbb, 0xa4, 0x3f, 0x09, 0x01, 0x70, 0x13, 0x4d, 0xa1, 0x53, 0xe7, 0xc9, 0x45, + 0x1e, 0x2c, 0x2f, 0x3c, 0xb4, 0x62, 0xc4, 0x83, 0xbf, 0xbe, 0x08, 0x11, 0xc4, 0x1c, 0x53, 0x3c, 0xfd, 0xc2, 0xe8, + 0x2f, 0xc1, 0x25, 0x46, 0x10, 0xba, 0x7b, 0xe7, 0x30, 0x84, 0x9b, 0x3d, 0xc8, 0xa0, 0xfe, 0x50, 0x87, 0x44, 0x0d, + 0x7f, 0xac, 0x3c, 0xe8, 0xff, 0x3a, 0x13, 0x96, 0xda, 0x4f, 0x4f, 0x07, 0x50, 0xc1, 0xfb, 0x8a, 0xb7, 0x11, 0xf1, + 0x7d, 0xe2, 0x67, 0xf1, 0x60, 0xf3, 0x6c, 0x03, 0xd6, 0xba, 0x27, 0xb9, 0xb1, 0xae, 0x12, 0x36, 0x10, 0xf0, 0x35, + 0x8a, 0xda, 0xf3, 0xda, 0xed, 0x1e, 0xfc, 0xd5, 0xbf, 0x08, 0x19, 0x30, 0x71, 0xfa, 0x3e, 0x73, 0xb2, 0x46, 0x17, + 0x99, 0x4c, 0x1f, 0x3a, 0xe9, 0x1b, 0x9d, 0xee, 0x3b, 0xe1, 0x1f, 0x15, 0xb3, 0xf8, 0x70, 0x4b, 0x5f, 0x69, 0x52, + 0xdc, 0x01, 0x2b, 0x9b, 0x47, 0x05, 0xa1, 0xce, 0x45, 0xf4, 0x95, 0x29, 0xdf, 0x12, 0x6a, 0xf6, 0x8d, 0x25, 0xa5, + 0x74, 0xaf, 0xa1, 0x37, 0x69, 0xad, 0xdf, 0x46, 0x09, 0xc6, 0x44, 0xc7, 0x93, 0x97, 0xf1, 0x58, 0x79, 0x1f, 0x8f, + 0x1b, 0xa9, 0x90, 0x07, 0x20, 0x02, 0x15, 0xe3, 0x4f, 0x57, 0x9e, 0x9c, 0xf4, 0xc2, 0x78, 0x15, 0x4a, 0x41, 0x61, + 0x40, 0x57, 0x20, 0x05, 0x3c, 0x6a, 0x4f, 0x74, 0x16, 0x76, 0x09, 0xf7, 0xe8, 0x26, 0x60, 0xac, 0xcf, 0x3f, 0x02, + 0x9a, 0xbb, 0x70, 0x87, 0x17, 0x03, 0xd4, 0xa6, 0x5e, 0xdd, 0x7d, 0x5c, 0xab, 0x73, 0x38, 0x04, 0x07, 0xab, 0x41, + 0x04, 0xa7, 0xf3, 0xa9, 0xa3, 0x59, 0x16, 0xa0, 0x72, 0xb2, 0xdc, 0xc8, 0x9b, 0x47, 0x8b, 0x5e, 0xdd, 0xf7, 0x96, + 0x69, 0x59, 0xd5, 0x41, 0xc6, 0xb2, 0xb0, 0x02, 0x5c, 0x1d, 0x5a, 0x3f, 0x08, 0x97, 0x85, 0xf3, 0x07, 0x42, 0x10, + 0xbb, 0x57, 0xdb, 0x92, 0xe7, 0x6a, 0x0e, 0x3f, 0x7b, 0xce, 0xd6, 0x5c, 0xa2, 0x4e, 0x3a, 0x13, 0x01, 0x88, 0x3d, + 0x35, 0xab, 0xe8, 0x1a, 0x48, 0xea, 0x34, 0xab, 0xe8, 0x9a, 0x9a, 0x6d, 0x8c, 0x03, 0xf9, 0x68, 0x95, 0x02, 0xf6, + 0xdd, 0x74, 0x1c, 0xac, 0x9e, 0xc5, 0xf2, 0x3a, 0x74, 0xf7, 0x6c, 0xa3, 0x7c, 0x06, 0x75, 0xab, 0x8d, 0x31, 0xb1, + 0xdd, 0x7c, 0x39, 0xd7, 0x6f, 0x07, 0x4b, 0xdf, 0x0e, 0x9a, 0x73, 0xca, 0xbe, 0xd3, 0x65, 0xaf, 0xec, 0xb2, 0xa9, + 0xe7, 0x8e, 0x8a, 0x56, 0x63, 0x40, 0x6f, 0x60, 0xc1, 0xfa, 0x5c, 0xa4, 0xd9, 0xaa, 0x54, 0x25, 0xe0, 0x85, 0xb1, + 0x62, 0x77, 0x7e, 0x23, 0x33, 0x24, 0x61, 0x1e, 0x67, 0xe2, 0x9a, 0xee, 0xb5, 0x30, 0x39, 0x8e, 0x45, 0x32, 0x25, + 0x74, 0x4a, 0x77, 0xb6, 0xa1, 0x73, 0x15, 0x46, 0x11, 0xad, 0x95, 0x54, 0x1a, 0x09, 0x4c, 0xcd, 0x00, 0x25, 0x73, + 0x05, 0x4e, 0xe9, 0x72, 0xff, 0x3b, 0x12, 0xe3, 0xcc, 0x17, 0x25, 0x33, 0xa0, 0x5b, 0x7e, 0x5d, 0xac, 0x5b, 0x29, + 0x32, 0xc2, 0xbc, 0x39, 0x6e, 0xaf, 0xeb, 0x43, 0x20, 0x57, 0xcb, 0x1e, 0x45, 0xe3, 0xa0, 0xd0, 0xe1, 0x52, 0x25, + 0xc0, 0xbe, 0x48, 0xfc, 0x8c, 0xb0, 0xa5, 0x3d, 0x90, 0xdb, 0xa3, 0x33, 0x61, 0xce, 0x39, 0x29, 0xcb, 0xce, 0xa5, + 0x19, 0x5c, 0x4e, 0x5c, 0x09, 0x2e, 0xd2, 0xdb, 0xf6, 0x34, 0x69, 0x69, 0xfb, 0xd8, 0x70, 0x8e, 0x86, 0xb6, 0x41, + 0x77, 0xec, 0x0f, 0xcd, 0xc5, 0x22, 0xb6, 0x2e, 0x16, 0xc3, 0xce, 0xec, 0x47, 0x8b, 0x05, 0xc8, 0x01, 0xe0, 0xa8, + 0xdb, 0xf0, 0x31, 0x5b, 0x02, 0xa7, 0xd5, 0x34, 0x9b, 0x7a, 0x1b, 0x5e, 0x3d, 0x53, 0x3d, 0xbd, 0xe4, 0xf9, 0x33, + 0x61, 0xc6, 0x62, 0xc3, 0xf3, 0x67, 0xd6, 0x91, 0x53, 0x3d, 0x13, 0x4a, 0xb4, 0x2e, 0xa0, 0x19, 0x78, 0x4d, 0x01, + 0x23, 0x96, 0x4c, 0xa6, 0x54, 0x91, 0xc7, 0xbd, 0xe9, 0x46, 0x0d, 0x5e, 0x50, 0x38, 0x04, 0x52, 0x3a, 0xfd, 0xe2, + 0x39, 0xd3, 0xef, 0x5d, 0x3c, 0xef, 0x90, 0xb5, 0x0d, 0xd3, 0xe5, 0x66, 0x98, 0x0c, 0x4a, 0xff, 0x99, 0x99, 0x18, + 0x17, 0xd6, 0x24, 0x01, 0xc4, 0xbf, 0xb1, 0xdf, 0x21, 0x85, 0x9b, 0xf7, 0x97, 0xc3, 0xf8, 0x91, 0xf7, 0x63, 0x64, + 0x4f, 0xd2, 0x0c, 0xb1, 0x66, 0x52, 0x21, 0x77, 0x5f, 0xad, 0x7f, 0x4c, 0xec, 0x26, 0x7b, 0x60, 0x01, 0x88, 0xad, + 0x69, 0xab, 0x5b, 0xde, 0xef, 0x7b, 0xa6, 0x08, 0xf0, 0x83, 0xf2, 0x8f, 0xee, 0x0c, 0xc9, 0xa0, 0xec, 0xba, 0x21, + 0xc4, 0x83, 0xb2, 0x69, 0xda, 0xeb, 0x6d, 0xef, 0xcc, 0x63, 0x75, 0x9d, 0x76, 0x16, 0x57, 0x8b, 0x0c, 0xd2, 0xea, + 0x43, 0x76, 0x9c, 0xd9, 0x67, 0x47, 0x4b, 0xa5, 0xfb, 0x7d, 0x88, 0x88, 0x3b, 0xca, 0xda, 0x7e, 0xbb, 0x05, 0xd7, + 0x70, 0x34, 0x08, 0x5d, 0xd9, 0xdb, 0x65, 0xb4, 0x71, 0x21, 0x8e, 0x7b, 0xa6, 0xf3, 0x05, 0x5f, 0x1e, 0xa5, 0x9d, + 0x07, 0xa7, 0x7a, 0xa2, 0xcf, 0x4d, 0x77, 0x95, 0xc9, 0xb5, 0x0e, 0xab, 0x31, 0xa8, 0xcd, 0xc2, 0x16, 0xee, 0xc2, + 0x36, 0x3a, 0x68, 0xed, 0xcb, 0x82, 0x7f, 0xca, 0x00, 0x7c, 0xe9, 0xd9, 0xb2, 0xed, 0x35, 0x69, 0xf5, 0x46, 0x46, + 0x21, 0xb6, 0xb4, 0xbd, 0xfa, 0x74, 0x94, 0x8f, 0x9b, 0x13, 0x8a, 0x0b, 0x39, 0xca, 0x8f, 0x5e, 0x43, 0xd4, 0xb5, + 0xae, 0xe3, 0x62, 0xd1, 0xe1, 0xc6, 0x55, 0xb7, 0xdd, 0xb8, 0x7e, 0x40, 0xbc, 0x35, 0xda, 0xa4, 0x50, 0x2b, 0x63, + 0x47, 0xf0, 0xb2, 0x7c, 0x38, 0x64, 0x62, 0x38, 0x94, 0x90, 0xa9, 0x8f, 0xdd, 0x1b, 0x9a, 0xf6, 0xf9, 0x69, 0xeb, + 0x47, 0x2c, 0x35, 0x8e, 0x62, 0xc3, 0x3b, 0x7d, 0xe7, 0xb1, 0x35, 0xae, 0xe4, 0xcb, 0x60, 0xb6, 0x2b, 0xa8, 0xb6, + 0xc6, 0x1b, 0xf6, 0x72, 0xfe, 0x7d, 0x25, 0x95, 0xfc, 0xed, 0xcf, 0x70, 0x0d, 0x6f, 0x6d, 0xe9, 0xa0, 0xa9, 0x66, + 0x39, 0xcb, 0xf5, 0xbd, 0xe0, 0xf8, 0xe3, 0xee, 0x15, 0xc1, 0xe0, 0xf7, 0x74, 0x14, 0xe4, 0x62, 0xa9, 0xd6, 0x80, + 0x82, 0x74, 0x64, 0xc7, 0x54, 0x16, 0x18, 0x06, 0xf0, 0x86, 0x0c, 0x90, 0xc7, 0x14, 0xee, 0x86, 0x0a, 0x2f, 0xfc, + 0xa5, 0x22, 0xbb, 0x04, 0xb6, 0x35, 0xe3, 0x63, 0x86, 0x3b, 0x08, 0xf9, 0x47, 0xb0, 0x3b, 0xb6, 0x62, 0xb7, 0x6c, + 0xc1, 0x90, 0x6c, 0x1c, 0x87, 0x31, 0xe6, 0xe3, 0x49, 0x7c, 0x25, 0x26, 0xf1, 0x80, 0x47, 0xe8, 0x18, 0xb1, 0xe6, + 0xf5, 0x2c, 0x96, 0x03, 0xc8, 0xee, 0xb8, 0xd2, 0x01, 0x21, 0x34, 0x36, 0xb4, 0xe4, 0x4d, 0x61, 0x70, 0xb1, 0x63, + 0x9f, 0x91, 0x48, 0xc6, 0x21, 0x58, 0xb4, 0xaa, 0x81, 0x85, 0x89, 0xdd, 0xf2, 0x62, 0xb6, 0x9a, 0xe3, 0x3f, 0x87, + 0x03, 0x02, 0x60, 0x07, 0xfb, 0x86, 0xdd, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x77, 0x96, 0xa7, 0x0b, 0xbb, 0xe7, 0xd7, + 0x7c, 0xcc, 0xce, 0x7f, 0xf0, 0x20, 0x72, 0xf6, 0xfc, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xdb, 0xd4, 0xab, 0xd8, 0x2d, + 0x51, 0x10, 0xde, 0x82, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0x5e, 0xf3, 0x05, 0xc6, 0x8a, 0x9d, 0xa5, 0x4b, 0x0f, 0x33, + 0x42, 0xed, 0xe9, 0x7c, 0x59, 0xab, 0x49, 0xb8, 0xb9, 0x5a, 0x4e, 0x06, 0x83, 0x8d, 0xbf, 0xe3, 0x6b, 0xe0, 0x83, + 0x39, 0xff, 0xc1, 0xdb, 0x51, 0xb9, 0xf0, 0x9f, 0xd7, 0x59, 0xf2, 0xce, 0x67, 0xd7, 0x03, 0xbe, 0x00, 0xbc, 0x25, + 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0xbb, 0xd6, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0xbe, + 0x86, 0x08, 0x8c, 0x04, 0x7c, 0x5b, 0xb5, 0x47, 0xfc, 0x96, 0x1b, 0xc0, 0xaf, 0xcc, 0x67, 0x0f, 0x3c, 0xd4, 0x3f, + 0x13, 0x9f, 0xdd, 0xf0, 0xf7, 0xfc, 0x85, 0x27, 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, + 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, + 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, + 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, + 0xde, 0x14, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, + 0x7c, 0x38, 0xd4, 0x2f, 0x84, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, + 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, + 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, 0xaa, 0xda, 0xbf, 0x25, 0x49, 0xb5, 0xab, 0xb4, + 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, + 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, + 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, + 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, + 0x89, 0x17, 0xe3, 0x69, 0x4d, 0x2c, 0xa9, 0x5d, 0x81, 0x31, 0x7a, 0x5c, 0x15, 0xb5, 0x4f, 0xfd, 0x02, 0x42, 0x91, + 0x6a, 0xcd, 0x1c, 0x6b, 0xdc, 0x18, 0x11, 0x77, 0x58, 0xb9, 0x76, 0x6a, 0xaf, 0x03, 0xb0, 0xbc, 0x1a, 0x17, 0x84, + 0x4d, 0x72, 0xec, 0x5c, 0xc0, 0x6a, 0x34, 0xa4, 0xda, 0x0d, 0xb7, 0x5e, 0x76, 0x7e, 0xf3, 0x38, 0xb1, 0xb5, 0x11, + 0x6e, 0x29, 0xa0, 0x8c, 0xf2, 0x1b, 0xcb, 0x09, 0xbb, 0x53, 0xbd, 0x23, 0x55, 0x3b, 0xe2, 0xc4, 0x05, 0x2c, 0x37, + 0x3c, 0xb5, 0xfa, 0x26, 0x06, 0x27, 0x42, 0xd5, 0x4a, 0xc7, 0x6b, 0x3f, 0xe2, 0x7e, 0x75, 0x5f, 0xf7, 0x4a, 0xf0, + 0x93, 0x90, 0xd7, 0x6f, 0x79, 0x07, 0x80, 0x15, 0x1f, 0xf2, 0x62, 0x5a, 0x38, 0x5a, 0x97, 0x41, 0x19, 0x20, 0x42, + 0x33, 0x00, 0x3a, 0xb9, 0x3a, 0x88, 0xd2, 0xc0, 0x15, 0x77, 0x88, 0xf0, 0xd3, 0xe8, 0x59, 0xfe, 0x22, 0x7c, 0x56, + 0x4d, 0xc3, 0x8b, 0x3c, 0x88, 0x2e, 0xaa, 0x20, 0x7a, 0x56, 0x5d, 0x85, 0xcf, 0xf2, 0x69, 0x74, 0x91, 0x07, 0xe1, + 0x45, 0xd5, 0xd8, 0x77, 0xed, 0xee, 0x9e, 0x90, 0xb7, 0x5d, 0xfd, 0x91, 0x73, 0x65, 0x4f, 0x99, 0x9e, 0x9f, 0xd7, + 0x7a, 0xa5, 0x76, 0x9b, 0xeb, 0x35, 0x6a, 0xa6, 0x3e, 0xca, 0xfe, 0x66, 0x1b, 0x0b, 0x8f, 0xe6, 0x10, 0xfa, 0x8c, + 0xb4, 0x98, 0x7b, 0x9c, 0xeb, 0xcd, 0x9e, 0x14, 0x06, 0x46, 0x4c, 0x2a, 0x19, 0x39, 0xbd, 0xc0, 0x45, 0xa8, 0x42, + 0x0c, 0x6b, 0xe9, 0x6a, 0x9f, 0x75, 0xe9, 0x0d, 0xd4, 0x35, 0xc5, 0xbe, 0x86, 0x0c, 0xbc, 0x68, 0x7a, 0x19, 0x8c, + 0x01, 0x39, 0x02, 0xef, 0xf8, 0x6c, 0x09, 0x07, 0xe6, 0x1a, 0xa0, 0x6f, 0x1e, 0xf5, 0x75, 0xb9, 0xe3, 0x6b, 0xd5, + 0x37, 0xd3, 0xf5, 0x48, 0x29, 0x3f, 0x56, 0xfc, 0xee, 0xe2, 0x39, 0xbb, 0xe5, 0x1a, 0x15, 0xe5, 0x17, 0xbd, 0x58, + 0xef, 0x81, 0xab, 0xee, 0x17, 0xb8, 0xcd, 0xe2, 0xb1, 0x2b, 0x0f, 0x58, 0xb6, 0x65, 0x0f, 0xec, 0x86, 0xbd, 0x67, + 0x4f, 0xd8, 0x5b, 0xf6, 0x8e, 0xfd, 0x84, 0xaa, 0x0d, 0x25, 0xe4, 0xf9, 0x0b, 0x7e, 0x2b, 0x4d, 0x8f, 0x12, 0x95, + 0xec, 0xc1, 0x36, 0xd3, 0x0c, 0x37, 0xec, 0x3d, 0x5f, 0x0c, 0x57, 0xec, 0x2d, 0x64, 0x43, 0x99, 0x78, 0xb0, 0x62, + 0x3f, 0x71, 0x05, 0x62, 0xa6, 0xcf, 0xc2, 0xd2, 0x12, 0x15, 0x4d, 0x99, 0x28, 0x43, 0xbf, 0xe5, 0xf8, 0x22, 0xfb, + 0x09, 0x8b, 0x90, 0x9f, 0x19, 0xae, 0xd8, 0x03, 0x5f, 0x0c, 0x56, 0xec, 0xbd, 0x36, 0x10, 0x0d, 0x36, 0x6e, 0x69, + 0x84, 0x64, 0xa5, 0xcb, 0x92, 0xd2, 0xf4, 0xd6, 0xbe, 0x06, 0x6e, 0xd8, 0x0d, 0xd6, 0xee, 0x09, 0x16, 0x8d, 0x02, + 0xff, 0x60, 0xc5, 0xde, 0x71, 0x09, 0xa0, 0xe6, 0x96, 0x27, 0xbd, 0x42, 0x75, 0x81, 0x74, 0x3f, 0x78, 0xc2, 0xe9, + 0x45, 0xf6, 0x0e, 0xcb, 0xa0, 0xaf, 0x0c, 0x57, 0x6c, 0x8b, 0xb5, 0xbb, 0x31, 0x96, 0x2d, 0xab, 0x7a, 0x12, 0x11, + 0x18, 0x05, 0x95, 0xd2, 0xf2, 0x6f, 0xc4, 0xb2, 0xa9, 0x9b, 0x06, 0xb5, 0xa1, 0x3f, 0x1f, 0x8c, 0xfe, 0xe2, 0xeb, + 0x77, 0x3f, 0x78, 0xa5, 0xbe, 0xf6, 0xfe, 0xe2, 0xb8, 0x56, 0x96, 0xe8, 0x5a, 0xf9, 0x2b, 0x2f, 0x67, 0xbf, 0xcc, + 0x27, 0xba, 0x96, 0xb4, 0xc3, 0x90, 0xaf, 0xe9, 0xec, 0x97, 0x0e, 0x67, 0xcb, 0x5f, 0x7d, 0xbf, 0x31, 0x5d, 0xac, + 0x3e, 0xab, 0x7b, 0xf7, 0x61, 0xb0, 0x69, 0x9c, 0x7a, 0xef, 0x4e, 0xd7, 0x1b, 0x9b, 0x59, 0x6b, 0xcf, 0xcc, 0xff, + 0xe1, 0x4a, 0x6f, 0x71, 0xe8, 0x6e, 0xf8, 0x76, 0xb8, 0xb1, 0x47, 0x41, 0x7e, 0x5f, 0x2a, 0x8d, 0xb3, 0x9a, 0xbf, + 0xf4, 0x3a, 0xa5, 0x58, 0x40, 0x34, 0xfa, 0x64, 0x24, 0xa1, 0x4b, 0x66, 0xe2, 0x19, 0xe2, 0x8b, 0x0c, 0x90, 0xb9, + 0x40, 0x34, 0xbb, 0xe7, 0xe3, 0xc9, 0xfd, 0x55, 0x3c, 0xb9, 0x1f, 0xf0, 0x4f, 0xa6, 0x05, 0xed, 0xc5, 0x76, 0xef, + 0xb3, 0x5f, 0x79, 0x61, 0x2f, 0xc7, 0x5f, 0x7c, 0xf6, 0x45, 0xb8, 0x2b, 0xf4, 0x17, 0x9f, 0xbd, 0x13, 0xfc, 0xd7, + 0x91, 0x26, 0xca, 0x60, 0xef, 0x6a, 0xfe, 0xeb, 0x08, 0x19, 0x3f, 0xd8, 0x67, 0xc1, 0xbf, 0x80, 0xef, 0x77, 0x95, + 0xa0, 0x55, 0xfc, 0x73, 0xad, 0x7e, 0xbe, 0x97, 0x71, 0x39, 0xf0, 0x26, 0xb4, 0x82, 0xde, 0xbc, 0xad, 0xe5, 0x4f, + 0xe2, 0xe1, 0x48, 0xd5, 0x53, 0xc3, 0x3f, 0x8b, 0xc5, 0x2c, 0xea, 0xa3, 0x74, 0x2a, 0x6f, 0x72, 0xcd, 0x33, 0x69, + 0x5d, 0xbe, 0x87, 0x50, 0xe0, 0x6b, 0x1b, 0xa2, 0x60, 0xc7, 0x71, 0x23, 0xb8, 0x66, 0xef, 0x84, 0xcf, 0xb2, 0xe9, + 0x96, 0xdf, 0xf0, 0x27, 0xfc, 0x1d, 0xdf, 0x05, 0x0f, 0xfc, 0x3d, 0x7f, 0xcb, 0x7f, 0xe2, 0x3b, 0xb6, 0x94, 0x68, + 0xa7, 0xf5, 0xf6, 0x32, 0xd8, 0xb2, 0x7a, 0x77, 0x19, 0x3c, 0xb0, 0x7a, 0xfb, 0x3c, 0xb8, 0x61, 0xf5, 0xee, 0x79, + 0xf0, 0x9e, 0x6d, 0x2f, 0x83, 0x27, 0x6c, 0x77, 0x19, 0xbc, 0x65, 0xdb, 0xe7, 0xc1, 0x3b, 0xb6, 0x7b, 0x1e, 0xfc, + 0x24, 0x31, 0x1e, 0xde, 0x09, 0xc9, 0x71, 0xf2, 0xae, 0x66, 0x86, 0x4f, 0x37, 0xf8, 0x2c, 0xac, 0x5f, 0x54, 0xc7, + 0xe0, 0x73, 0xcd, 0x74, 0x8b, 0x03, 0x21, 0x98, 0x6e, 0x6f, 0x70, 0x4b, 0x4f, 0x4c, 0xab, 0x82, 0x54, 0xb0, 0xae, + 0x76, 0x06, 0x8b, 0xba, 0x69, 0x9d, 0xc9, 0x8e, 0x5f, 0x62, 0xdc, 0xe1, 0x97, 0xb8, 0x60, 0xcb, 0xa6, 0xd3, 0x49, + 0xe7, 0xf4, 0x49, 0xa0, 0x37, 0x7f, 0xbd, 0xeb, 0x57, 0xd2, 0x77, 0xa6, 0x68, 0x78, 0xae, 0xb4, 0xc6, 0xad, 0x9d, + 0x3e, 0xb4, 0x76, 0x7a, 0x26, 0x55, 0x68, 0x11, 0x8b, 0xca, 0xa2, 0xaa, 0x90, 0x49, 0x3c, 0xc8, 0xb4, 0x3e, 0x2d, + 0x61, 0xa4, 0xc8, 0x04, 0x34, 0xfa, 0x82, 0x8e, 0x81, 0x9c, 0x2c, 0x0a, 0x6c, 0xc9, 0x37, 0x83, 0x84, 0xad, 0x79, + 0x3c, 0x1d, 0x26, 0xc1, 0x92, 0xdd, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x52, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, + 0x79, 0x6f, 0x95, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x56, 0xe9, 0x0d, 0x7e, 0xeb, 0xec, 0xe7, 0x6b, 0xb5, 0xbf, 0x83, + 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xaf, 0xec, 0x2d, 0x7d, 0x6b, + 0xb6, 0xe9, 0xff, 0xb4, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xc6, 0x9f, 0x3c, + 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xc7, 0x3f, 0x8d, 0xb6, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, + 0x68, 0xef, 0xe4, 0x95, 0xbd, 0x23, 0x6e, 0x79, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, + 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xab, 0xd9, 0xa7, 0xf9, 0x64, 0xcb, 0x8f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, + 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x3b, 0x7e, 0xbc, 0x89, 0x0f, 0xff, 0xe3, + 0x4a, 0xef, 0xbe, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, 0xf8, 0x13, 0xcd, 0xd2, 0x20, 0xb2, 0x14, 0x8a, 0x3f, 0x99, 0x69, 0xa7, 0xee, 0x54, 0x59, 0xdd, 0x2d, 0xdf, 0xe2, - 0x1e, 0x7f, 0xc7, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0xef, 0x6e, 0x16, 0x93, 0xc1, 0xe0, 0xce, 0x3f, 0xdc, 0xf3, 0x70, - 0x76, 0x37, 0x67, 0x6f, 0xf9, 0x3d, 0x2d, 0xa6, 0x89, 0x6a, 0x7a, 0xf1, 0x98, 0xe0, 0x75, 0xe7, 0xfb, 0x13, 0x8b, - 0xff, 0xd5, 0xbe, 0x68, 0xde, 0xf9, 0x03, 0x69, 0x8d, 0x96, 0xbb, 0xfa, 0xfb, 0xc7, 0x15, 0x13, 0x77, 0x20, 0x5e, - 0xbc, 0xb7, 0x35, 0x0d, 0x6f, 0xf8, 0x47, 0xef, 0xad, 0x3f, 0x7d, 0xab, 0x63, 0x6e, 0x26, 0xea, 0x48, 0x7a, 0x73, - 0xf5, 0x8c, 0xfd, 0xca, 0x3f, 0xc9, 0xe3, 0xe4, 0x9d, 0x90, 0x93, 0xf6, 0x16, 0xb9, 0x9b, 0xe8, 0x94, 0xf8, 0xe2, - 0x26, 0x12, 0x16, 0x04, 0xc2, 0x70, 0xd4, 0xfc, 0x61, 0x52, 0x4e, 0xbd, 0x3d, 0x70, 0xbb, 0x72, 0x5b, 0xff, 0x7c, - 0xc7, 0x39, 0x5f, 0x0c, 0xaf, 0xa7, 0x5f, 0xba, 0x5d, 0x7a, 0x54, 0x34, 0x9b, 0x0a, 0x74, 0xbb, 0xc3, 0xd8, 0xab, - 0xb3, 0x99, 0x65, 0x2e, 0xf9, 0xd2, 0x97, 0xda, 0xcc, 0x3c, 0xa6, 0xf7, 0x9b, 0x69, 0x86, 0x44, 0xbe, 0x40, 0xc8, - 0x74, 0x3c, 0xae, 0x2e, 0xb1, 0x3c, 0x3e, 0x7c, 0xf3, 0xf4, 0xc9, 0xe0, 0x09, 0x46, 0x6e, 0x59, 0xd1, 0x20, 0x5f, - 0xf8, 0x30, 0xab, 0x5b, 0xb7, 0x8d, 0xab, 0x67, 0xc3, 0x5f, 0x20, 0x6f, 0xd0, 0xf5, 0xd0, 0x14, 0xd1, 0x2a, 0xbf, - 0xa3, 0xe8, 0x33, 0x25, 0x07, 0x1d, 0x4f, 0xa0, 0x76, 0x48, 0x81, 0xfb, 0xe5, 0x29, 0x07, 0xfd, 0x06, 0x96, 0xda, - 0xef, 0x5f, 0x7e, 0x22, 0x1e, 0x69, 0x18, 0xef, 0x1f, 0xc2, 0xe8, 0x8f, 0xb8, 0x2c, 0x36, 0x70, 0xba, 0x0e, 0xe0, - 0x73, 0x4f, 0xf5, 0xed, 0x6b, 0xe5, 0xfb, 0x7e, 0xe0, 0xed, 0xf8, 0x2d, 0xfb, 0xc2, 0xbd, 0xeb, 0xe1, 0x1b, 0xff, - 0xe9, 0x13, 0x10, 0x9d, 0x60, 0x5c, 0x3e, 0x63, 0x24, 0x6c, 0x47, 0x31, 0x6a, 0x15, 0x7e, 0xae, 0x21, 0x44, 0xeb, - 0x13, 0x32, 0x76, 0x41, 0xfa, 0x07, 0x05, 0xe8, 0x27, 0x04, 0x56, 0x93, 0xd4, 0x28, 0x30, 0x89, 0xef, 0x6a, 0x48, - 0x20, 0x05, 0x0b, 0x84, 0xde, 0x40, 0xf1, 0xa9, 0xe0, 0x5f, 0x86, 0x9f, 0x49, 0xf2, 0x5b, 0xd4, 0x7c, 0x0c, 0x7f, - 0xc3, 0xd0, 0x4c, 0xaa, 0x87, 0xb4, 0x8e, 0x12, 0xef, 0x27, 0xff, 0x10, 0x85, 0x95, 0x50, 0xc7, 0x42, 0x90, 0x8a, - 0x21, 0x17, 0xe2, 0xea, 0xd9, 0xe4, 0xae, 0x14, 0xe1, 0x1f, 0x13, 0x7c, 0x26, 0x17, 0x9a, 0x7c, 0x46, 0x4f, 0x1a, - 0xf9, 0xfe, 0x83, 0x7c, 0x5f, 0x76, 0x6a, 0xb0, 0xa8, 0x87, 0xfc, 0xae, 0x76, 0xdf, 0x97, 0x53, 0x82, 0x1e, 0xd9, - 0x0f, 0x68, 0x0a, 0x06, 0x6a, 0x02, 0x52, 0x86, 0xe0, 0x0e, 0xae, 0xfa, 0x9e, 0x2a, 0xc8, 0x97, 0xdf, 0xfb, 0x2c, - 0x64, 0xb8, 0xca, 0x82, 0x90, 0xe4, 0x52, 0x21, 0x85, 0x8d, 0xbb, 0x7a, 0xf0, 0x59, 0x63, 0x92, 0x48, 0xc8, 0x29, - 0x01, 0x49, 0xd2, 0xde, 0x40, 0x92, 0x88, 0xe9, 0x3f, 0x5c, 0x27, 0x4d, 0xb3, 0x96, 0xd2, 0x0d, 0x71, 0xaa, 0xbe, - 0x45, 0x9a, 0xb3, 0xe0, 0x3d, 0x83, 0xa5, 0x23, 0xc5, 0x8a, 0x2f, 0xc6, 0x60, 0xac, 0x83, 0x85, 0x56, 0xb2, 0xb8, - 0x5f, 0x25, 0x61, 0x1a, 0x89, 0x2a, 0xef, 0x84, 0xfc, 0xf9, 0x4f, 0x25, 0xfe, 0xe8, 0x2d, 0x0d, 0x44, 0x20, 0xf8, - 0x01, 0x5a, 0x0f, 0x58, 0xe3, 0xc1, 0x4f, 0xac, 0x2e, 0xc3, 0xbc, 0xca, 0xa8, 0xbc, 0xd9, 0x9e, 0xed, 0xe6, 0x4c, - 0x55, 0x2d, 0xf8, 0x2c, 0x0c, 0x2d, 0xda, 0xc5, 0xba, 0x39, 0xbb, 0xcd, 0x1b, 0x7c, 0x67, 0x92, 0x44, 0x6a, 0x29, - 0x89, 0xb4, 0xd5, 0xf5, 0xe9, 0xd2, 0xeb, 0x16, 0x15, 0x34, 0x46, 0x80, 0x5e, 0x92, 0xee, 0x2a, 0x9f, 0x50, 0xbc, - 0xb2, 0x1a, 0x56, 0xc3, 0x4b, 0x87, 0x22, 0x8c, 0xb5, 0x37, 0xe7, 0xf2, 0xec, 0x0e, 0xac, 0x47, 0x68, 0xed, 0xca, - 0xd5, 0x21, 0x6c, 0x3f, 0xd1, 0x7b, 0x4e, 0xae, 0xfe, 0x06, 0x54, 0x81, 0x73, 0x47, 0x43, 0x7d, 0xd2, 0x4e, 0x21, - 0xdb, 0x79, 0xb0, 0x24, 0xa8, 0x4a, 0xc9, 0x4d, 0xb9, 0x16, 0xa5, 0x94, 0x29, 0x5f, 0xcb, 0x6c, 0x65, 0xf7, 0xc9, - 0x00, 0xe2, 0xd9, 0xa0, 0x40, 0x72, 0x51, 0x5b, 0xcd, 0x41, 0xfa, 0x68, 0x96, 0x38, 0xd6, 0x0e, 0x0a, 0x2f, 0xcb, - 0xc1, 0xcc, 0x65, 0x2e, 0x97, 0x83, 0x82, 0x55, 0x7a, 0xab, 0x99, 0x66, 0xaa, 0x2f, 0x2a, 0x7b, 0x9b, 0xf1, 0x32, - 0xfd, 0x37, 0x4b, 0x06, 0x3c, 0xba, 0x7a, 0xe6, 0x07, 0x90, 0x26, 0x79, 0x1d, 0x20, 0x09, 0x36, 0x07, 0xbb, 0xd8, - 0x61, 0xd8, 0x2a, 0x56, 0xf6, 0xe4, 0xf9, 0x72, 0x87, 0xa6, 0x5c, 0xc2, 0x48, 0x4e, 0xcc, 0xa5, 0xd4, 0xf7, 0x25, - 0xd5, 0x0d, 0x05, 0x27, 0x9b, 0x26, 0xa0, 0x14, 0xd0, 0x6e, 0xc1, 0x7f, 0xe1, 0x53, 0x43, 0xa7, 0x05, 0x58, 0x6a, - 0xbb, 0x01, 0xff, 0x85, 0x7e, 0xb1, 0x7d, 0x44, 0xfd, 0xc0, 0x3c, 0x38, 0x98, 0xb5, 0x95, 0x31, 0x20, 0x22, 0x71, - 0x05, 0x79, 0x24, 0xf8, 0x41, 0xb1, 0xa7, 0xcb, 0xc4, 0x81, 0x33, 0xc5, 0xc5, 0x52, 0x6a, 0x33, 0xf3, 0xda, 0x6f, - 0xa9, 0x89, 0x37, 0x51, 0x12, 0x15, 0xb6, 0x43, 0x1a, 0xbd, 0xa4, 0x8c, 0xa9, 0x82, 0x0d, 0xd1, 0x7d, 0xdd, 0x04, - 0x53, 0xe0, 0x4d, 0x55, 0x05, 0x44, 0xa8, 0xbd, 0xc8, 0xf2, 0xfc, 0xa6, 0x0b, 0xac, 0x2e, 0xf8, 0xd4, 0x98, 0x66, - 0x17, 0xac, 0xe4, 0x6a, 0x26, 0x7d, 0xe6, 0xed, 0x40, 0x0b, 0x79, 0x97, 0x97, 0x45, 0x2b, 0x74, 0x3d, 0x88, 0x16, - 0xfe, 0x41, 0x73, 0x3c, 0x7a, 0xb6, 0xad, 0xa6, 0x36, 0xfb, 0x5a, 0x8b, 0x05, 0x32, 0x10, 0x0d, 0x7d, 0xa1, 0x62, - 0x14, 0xee, 0x2a, 0xcd, 0xd5, 0x6a, 0x5f, 0x95, 0x41, 0x02, 0x13, 0x41, 0xd6, 0xb2, 0xf0, 0x1e, 0xdd, 0xab, 0x47, - 0x9a, 0x57, 0x12, 0x3c, 0x73, 0xf1, 0x17, 0x00, 0x42, 0x79, 0x92, 0x90, 0x03, 0x72, 0x00, 0x7f, 0x4b, 0x51, 0x2a, - 0x0d, 0xf0, 0xcf, 0xea, 0x72, 0x6c, 0xeb, 0xfb, 0x3b, 0xad, 0x62, 0x70, 0xfd, 0xf9, 0xba, 0xeb, 0x59, 0x3b, 0xc4, - 0x39, 0xb7, 0xd5, 0x6b, 0xcb, 0x34, 0x8f, 0x91, 0xba, 0x06, 0xe0, 0x4e, 0xa4, 0x47, 0x20, 0x92, 0x99, 0x68, 0x90, - 0xb3, 0xe7, 0x7c, 0x3c, 0x15, 0x8f, 0x49, 0x7b, 0xb9, 0xef, 0x9b, 0x0b, 0x7d, 0x30, 0xc6, 0xbe, 0x05, 0x0d, 0xe2, - 0xa3, 0xd5, 0xd6, 0x0a, 0xc4, 0x7a, 0xa7, 0xd4, 0x87, 0x6e, 0x8c, 0x82, 0x0e, 0x1e, 0x71, 0x23, 0x17, 0x1c, 0xdb, - 0x5d, 0x5b, 0x4f, 0xe9, 0x2b, 0x00, 0x73, 0x1d, 0xa8, 0x64, 0x18, 0xa4, 0x2e, 0x13, 0x85, 0x49, 0x7e, 0x99, 0x90, - 0x84, 0x88, 0xea, 0x6c, 0x39, 0x4a, 0x95, 0x69, 0x01, 0x97, 0x19, 0x19, 0x60, 0x36, 0x69, 0xd6, 0x4f, 0x2e, 0x5f, - 0x62, 0x18, 0x01, 0xf1, 0x33, 0xfa, 0xb1, 0x56, 0x89, 0x97, 0x8c, 0xee, 0x1c, 0x75, 0x83, 0x2a, 0xc9, 0x5c, 0xbf, - 0xb9, 0x9d, 0x45, 0xca, 0xbc, 0x60, 0xb8, 0x5d, 0xa5, 0xf9, 0x87, 0xb0, 0x4e, 0xf0, 0xdb, 0x00, 0x95, 0xf4, 0xa9, - 0xf0, 0xa2, 0x11, 0x40, 0xa8, 0xef, 0x55, 0x19, 0x9f, 0x0a, 0x2f, 0x1b, 0xed, 0x58, 0x46, 0x29, 0x54, 0x17, 0xcc, - 0x6e, 0x4d, 0x17, 0xa2, 0x5b, 0x55, 0x03, 0x6d, 0xe0, 0xda, 0x15, 0x52, 0xba, 0x81, 0x6a, 0x57, 0x6e, 0x58, 0x80, - 0x68, 0x33, 0x11, 0x18, 0x2e, 0xff, 0x3e, 0x7f, 0xa9, 0x62, 0x78, 0xfa, 0xfd, 0xd0, 0x3b, 0xec, 0x82, 0x68, 0xb4, - 0xbb, 0x66, 0xfb, 0x20, 0x1a, 0xed, 0xaf, 0x1b, 0x46, 0xbf, 0x9f, 0xd1, 0xef, 0x67, 0x0d, 0xe8, 0x48, 0x84, 0x09, - 0xb3, 0xd7, 0x6f, 0xd4, 0xf2, 0x95, 0x5a, 0xbf, 0x53, 0xcb, 0x97, 0x6a, 0x78, 0xeb, 0x40, 0x12, 0x41, 0x64, 0xa9, - 0x6a, 0x1e, 0x24, 0x45, 0xaa, 0xa5, 0xcb, 0x31, 0x5a, 0x8c, 0xa8, 0xa5, 0xac, 0x39, 0xd5, 0x89, 0xb4, 0x73, 0x50, - 0x32, 0xc0, 0xd1, 0xe2, 0xaa, 0xc6, 0x74, 0xb3, 0xa2, 0x25, 0x10, 0x23, 0xac, 0x6c, 0xcb, 0xc5, 0x4d, 0xea, 0xa3, - 0x2b, 0xf2, 0x6d, 0xcb, 0x95, 0x6f, 0x5b, 0xc1, 0xab, 0xaf, 0x28, 0x94, 0x4b, 0xae, 0x95, 0xed, 0xd3, 0x42, 0x29, - 0x94, 0x71, 0x0d, 0xb6, 0xf6, 0x4d, 0x60, 0xc8, 0x7c, 0xa4, 0xa8, 0xb1, 0xbd, 0x68, 0x94, 0x43, 0x90, 0xad, 0x83, - 0x51, 0xa7, 0x2c, 0x58, 0x7c, 0xbb, 0x43, 0x06, 0x32, 0xd0, 0x51, 0xd5, 0xc6, 0xab, 0x9d, 0x95, 0xfe, 0xb0, 0xbc, - 0x7a, 0xc6, 0x12, 0x2b, 0x9d, 0xfc, 0xa6, 0x42, 0x7f, 0x10, 0xa2, 0x6f, 0xca, 0x96, 0x83, 0x17, 0x5d, 0x6c, 0x65, - 0x40, 0xbc, 0x61, 0x7a, 0x6f, 0x6b, 0x25, 0xcb, 0x5d, 0x53, 0xbe, 0x98, 0xf1, 0x84, 0xe3, 0xe8, 0xcb, 0xd5, 0x22, - 0xac, 0xd5, 0x22, 0x3b, 0x01, 0x1e, 0x5a, 0xab, 0xa5, 0x90, 0xab, 0x45, 0x38, 0x33, 0x5d, 0xa8, 0x99, 0x9e, 0x81, - 0xe6, 0x51, 0xa8, 0x59, 0x9e, 0x00, 0x16, 0xbc, 0x30, 0x33, 0x5c, 0x98, 0x19, 0x8e, 0x43, 0x6a, 0x9c, 0x1e, 0xf4, - 0x5e, 0xe7, 0x9e, 0x5b, 0xee, 0x46, 0xa7, 0x61, 0xde, 0x4e, 0x36, 0x98, 0xd3, 0x83, 0x70, 0x02, 0xf1, 0x81, 0x25, - 0x02, 0xf4, 0x68, 0x58, 0x1d, 0x35, 0x54, 0x8e, 0xe2, 0xcb, 0x02, 0x90, 0x2c, 0x09, 0x40, 0xf2, 0xa0, 0xc6, 0xb9, - 0xb4, 0xfc, 0xba, 0x4a, 0x42, 0x8e, 0xc8, 0x78, 0x29, 0xed, 0xee, 0x09, 0x2f, 0x47, 0x46, 0x68, 0x9e, 0x2c, 0x52, - 0xaf, 0x62, 0x19, 0x1b, 0x23, 0x70, 0x51, 0xe8, 0x37, 0x79, 0xbf, 0x9f, 0x96, 0x5e, 0x45, 0xed, 0xfc, 0x04, 0xfe, - 0x96, 0xe7, 0xce, 0x22, 0x47, 0xc8, 0xab, 0x91, 0x49, 0x58, 0x5e, 0x2a, 0xf5, 0xf4, 0x25, 0xcc, 0xa0, 0xee, 0xde, - 0x28, 0x00, 0xd7, 0x42, 0x39, 0xd5, 0x96, 0x70, 0x65, 0xaa, 0x0c, 0xf6, 0x79, 0xc8, 0x65, 0x68, 0x87, 0x44, 0x1e, - 0x29, 0xac, 0xfb, 0xf6, 0xd5, 0xb3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x8f, 0x00, 0x73, 0x30, 0xf5, 0xa2, - 0x01, 0x2f, 0xd5, 0x9c, 0xf9, 0xe8, 0x55, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x53, 0xf9, 0xc8, 0xf8, - 0x96, 0xf9, 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, - 0x6c, 0x50, 0x09, 0xb6, 0x0d, 0xdf, 0x48, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, - 0x1b, 0xb3, 0x31, 0x2b, 0xd4, 0xce, 0x53, 0xc9, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, - 0x71, 0xce, 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, - 0xa6, 0x25, 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, - 0xe8, 0x95, 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x2b, - 0xfe, 0x42, 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd0, 0xb4, 0x04, - 0x75, 0x80, 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x25, 0xe7, 0xef, 0x6a, 0x43, - 0x84, 0x8c, 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, - 0xc0, 0xe3, 0xaa, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x9c, 0xf6, 0x4e, 0xd3, 0xb0, 0xc3, 0x17, 0xa0, 0x29, 0x86, 0x72, - 0x3c, 0xdf, 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xce, 0x42, 0xda, 0x96, - 0x63, 0xb4, 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xca, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x79, 0xd5, 0x63, 0x36, - 0xc9, 0x8a, 0x45, 0xae, 0x22, 0xce, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, - 0x41, 0xc9, 0x72, 0x59, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xde, 0x9c, - 0x53, 0xa8, 0x7d, 0xc5, 0xc3, 0xea, 0xfc, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, - 0x7c, 0xe7, 0xab, 0x74, 0x45, 0xa1, 0x3b, 0xce, 0x4c, 0x3c, 0x57, 0x81, 0xb1, 0x6f, 0xed, 0x08, 0x0a, 0x87, 0xa6, - 0xeb, 0x80, 0xc3, 0x34, 0x3a, 0x61, 0xf1, 0x4f, 0xe9, 0x38, 0x79, 0x55, 0x2b, 0x44, 0x92, 0xbf, 0x0b, 0x17, 0x86, - 0xc4, 0x82, 0xbc, 0x24, 0xd4, 0x11, 0x19, 0xb1, 0x1a, 0x15, 0x1b, 0xa1, 0xa2, 0xe2, 0x14, 0x8f, 0xb7, 0x0a, 0x8a, - 0x4b, 0x51, 0xaa, 0x94, 0x8a, 0xdc, 0xa8, 0x14, 0x10, 0xcb, 0x06, 0xde, 0x2d, 0xe0, 0x00, 0x08, 0x3a, 0xcb, 0xfd, - 0xc6, 0x76, 0xb7, 0x91, 0xf9, 0xcc, 0x34, 0x4f, 0xab, 0x0f, 0xea, 0xef, 0xf7, 0x4b, 0x8c, 0xad, 0xf1, 0xf4, 0xf7, - 0x6d, 0x5a, 0x70, 0xf3, 0x37, 0x0c, 0xd1, 0x0a, 0x10, 0x31, 0x4b, 0x7b, 0x28, 0x64, 0xc1, 0x84, 0x65, 0xa8, 0xca, - 0x53, 0x8e, 0x7a, 0xd5, 0xe4, 0x0e, 0x20, 0xd4, 0xd0, 0xaf, 0x8d, 0x4e, 0x75, 0x55, 0x82, 0xf0, 0x7d, 0x57, 0xa8, - 0xc7, 0xe6, 0x80, 0x27, 0x03, 0xe0, 0xaf, 0xc8, 0x6b, 0x3d, 0xb6, 0x7f, 0xd0, 0x1b, 0xf5, 0x06, 0x08, 0xa2, 0x73, - 0x59, 0xf8, 0x27, 0x9c, 0xeb, 0xd4, 0x9f, 0x71, 0x21, 0x88, 0x6f, 0x3d, 0x09, 0xef, 0xc5, 0x45, 0x1a, 0x07, 0x17, - 0xbd, 0x81, 0xb9, 0x08, 0x14, 0x17, 0x69, 0x7e, 0x01, 0x61, 0xf9, 0x88, 0x89, 0x58, 0xb3, 0x15, 0xc0, 0x04, 0x96, - 0x3a, 0x0e, 0x59, 0x75, 0x6c, 0xbf, 0xff, 0x7a, 0x64, 0xc8, 0xd2, 0x11, 0x06, 0x46, 0xff, 0x06, 0x14, 0xa1, 0x12, - 0x96, 0x99, 0xed, 0xc1, 0xa4, 0xab, 0x3d, 0xab, 0xe7, 0xcd, 0x36, 0xef, 0xea, 0x1d, 0xab, 0x69, 0x15, 0x35, 0x2d, - 0xb7, 0x9a, 0x36, 0xa9, 0xa0, 0x66, 0xa2, 0xdf, 0xd7, 0xa0, 0xa8, 0xd5, 0x1c, 0xc0, 0xd8, 0x30, 0xf9, 0xf5, 0x2c, - 0x9f, 0xf7, 0xfb, 0x9e, 0x7c, 0x04, 0xbf, 0x90, 0xad, 0xcc, 0xad, 0xb1, 0x7c, 0xfa, 0x8a, 0x48, 0xcc, 0x0c, 0xcc, - 0xd1, 0xea, 0x04, 0xdf, 0xeb, 0x56, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x35, 0x0c, 0x9e, 0x27, 0x7c, 0x70, - 0x91, 0xa3, 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x6b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, - 0x78, 0x90, 0xfd, 0xfe, 0x1a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0x37, 0x75, 0x51, 0x56, 0xd0, 0xb1, - 0xf4, 0xf3, 0x4e, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x96, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, - 0x2e, 0x3e, 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0x67, 0xb8, 0xcf, 0x6f, 0x3c, 0xf0, 0x83, 0x99, 0xa5, - 0x73, 0x45, 0x9c, 0x51, 0xf9, 0xa3, 0xcf, 0x45, 0x9a, 0x53, 0x1e, 0xe0, 0x3e, 0x14, 0x73, 0xfb, 0x2d, 0x90, 0x7e, - 0xe8, 0x2d, 0x90, 0x7d, 0x74, 0xce, 0xc9, 0x6b, 0x40, 0xa4, 0x43, 0x18, 0xdc, 0x9c, 0x04, 0x1d, 0xab, 0x86, 0x77, - 0x16, 0xd8, 0x69, 0x2f, 0x8d, 0x7b, 0x69, 0x7e, 0x91, 0xf6, 0xfb, 0x06, 0x35, 0x33, 0x45, 0x38, 0x78, 0x9c, 0x91, - 0x8b, 0xa4, 0x05, 0x5b, 0x4a, 0xfb, 0xaf, 0x06, 0x8e, 0xa8, 0x10, 0xa0, 0xf9, 0xef, 0xc2, 0x7b, 0x02, 0x10, 0x9b, - 0xb4, 0x01, 0x57, 0x3d, 0xa6, 0xa3, 0xb1, 0x25, 0x51, 0xab, 0xce, 0x06, 0x48, 0x9c, 0x2a, 0xad, 0xa7, 0xdc, 0xac, - 0x29, 0x0c, 0x52, 0x65, 0xa1, 0x7e, 0x63, 0x3d, 0x99, 0xac, 0x72, 0x91, 0x11, 0x47, 0x65, 0x7a, 0x57, 0x33, 0x82, - 0xe9, 0xd2, 0xcf, 0x17, 0xb0, 0x64, 0xe3, 0x8f, 0x38, 0x79, 0x4b, 0xc0, 0xb1, 0x9d, 0xb5, 0xab, 0x6a, 0x97, 0xe3, - 0xd6, 0x6e, 0x0e, 0xf0, 0xbd, 0xde, 0x68, 0x34, 0xd2, 0xce, 0x71, 0x02, 0x86, 0xaa, 0xa7, 0x96, 0x42, 0x8f, 0xd5, - 0x0a, 0x50, 0xb7, 0x23, 0x97, 0x59, 0x32, 0x98, 0x2f, 0x8c, 0xe3, 0x97, 0xe6, 0xa3, 0x8f, 0x97, 0xca, 0xda, 0x75, - 0xc4, 0xd7, 0x7f, 0x94, 0xd5, 0xfa, 0x96, 0x77, 0x55, 0x13, 0xf0, 0x45, 0x15, 0x50, 0xfa, 0x0d, 0xef, 0xc9, 0xde, - 0xc5, 0xd7, 0x6e, 0xb1, 0x4b, 0xbe, 0xe5, 0x2d, 0xea, 0x3c, 0x5f, 0x39, 0xb8, 0x51, 0xa5, 0xdb, 0x7b, 0xc9, 0x02, - 0xd7, 0xde, 0x49, 0xd3, 0x58, 0xcf, 0xfc, 0xe8, 0x61, 0x11, 0xb2, 0x9d, 0x8f, 0xbd, 0xaf, 0x9a, 0xa7, 0x67, 0x0d, - 0xbd, 0x49, 0x0d, 0x7d, 0xec, 0x45, 0xd9, 0x3e, 0x35, 0x8d, 0xe8, 0x35, 0x6c, 0xe8, 0x63, 0x6f, 0xc9, 0xc9, 0x21, - 0x11, 0xe0, 0xd4, 0x98, 0x3f, 0x3e, 0x9c, 0xce, 0xf0, 0x77, 0x0c, 0xa8, 0x04, 0x62, 0x3e, 0x3f, 0xa6, 0x1d, 0x05, - 0x98, 0x51, 0xa5, 0xb7, 0xcf, 0x0f, 0x6c, 0xc7, 0xcb, 0x7a, 0x68, 0xe9, 0xdd, 0xb3, 0xa3, 0xdb, 0xf1, 0xaa, 0x1a, - 0x5f, 0xca, 0x21, 0xcf, 0xf3, 0xd9, 0x68, 0x34, 0x12, 0x06, 0x92, 0x3b, 0xd7, 0x1b, 0x58, 0x81, 0xb4, 0x2d, 0xaa, - 0x0f, 0xe5, 0xd2, 0xdb, 0xab, 0x43, 0x3b, 0xf7, 0x27, 0xd5, 0xf1, 0x58, 0x8c, 0xcc, 0x31, 0x9e, 0xfb, 0xc7, 0x63, - 0xa1, 0xe4, 0x28, 0x59, 0x4b, 0x10, 0x9d, 0xd2, 0x78, 0x2a, 0xeb, 0xb5, 0x13, 0x91, 0x57, 0x23, 0xce, 0x43, 0xf0, - 0x57, 0x2f, 0x67, 0xa5, 0xfe, 0x54, 0xf8, 0xe8, 0xa7, 0x4a, 0xe9, 0x05, 0xaf, 0x0a, 0x08, 0x11, 0xfb, 0xbb, 0x81, - 0x76, 0x50, 0x82, 0x43, 0x09, 0xf7, 0x1e, 0xaf, 0x93, 0xaf, 0xbc, 0x6a, 0x26, 0x63, 0x94, 0x7b, 0x83, 0x7c, 0xce, - 0x00, 0xa6, 0xd2, 0x67, 0xe0, 0x77, 0x09, 0x50, 0xa7, 0xf8, 0x14, 0x9d, 0xea, 0xcd, 0xc3, 0xa6, 0xeb, 0xd3, 0x12, - 0x45, 0x11, 0xdd, 0xf9, 0xf9, 0x18, 0x10, 0x3b, 0xbb, 0x36, 0x23, 0xed, 0xda, 0x6f, 0xd0, 0x60, 0x95, 0x26, 0xad, - 0x95, 0x53, 0xc2, 0x6e, 0x57, 0x23, 0x5b, 0xfa, 0x51, 0x0a, 0xc4, 0xca, 0x71, 0x22, 0x91, 0x3d, 0xd8, 0xc8, 0x09, - 0xdc, 0xa2, 0xbd, 0xa3, 0x03, 0x50, 0xb9, 0x51, 0x90, 0x5f, 0xcd, 0x89, 0xdc, 0xf1, 0x7d, 0xef, 0xfb, 0x41, 0x3d, - 0xf8, 0xbe, 0x77, 0x91, 0x92, 0xdc, 0x11, 0x5e, 0xa8, 0x29, 0x21, 0xe2, 0x8b, 0xef, 0x07, 0xd5, 0x00, 0xcf, 0x12, - 0x2d, 0xd2, 0x22, 0xa1, 0x5a, 0x5d, 0xe3, 0x26, 0xbc, 0x48, 0x24, 0xf7, 0xd0, 0xbe, 0xf3, 0x88, 0x58, 0x00, 0x32, - 0x16, 0x9f, 0xcd, 0x1b, 0x0a, 0x75, 0x37, 0x31, 0x5b, 0x74, 0x97, 0xc5, 0x7e, 0x7f, 0x93, 0xa7, 0x75, 0x4f, 0xc7, - 0xc7, 0xe0, 0x0b, 0x52, 0x4d, 0x80, 0x47, 0xfb, 0x2b, 0x73, 0xbc, 0x7a, 0xb5, 0x39, 0x52, 0x16, 0xaa, 0x44, 0xfd, - 0x16, 0xab, 0x59, 0x0f, 0x61, 0xb8, 0xb3, 0xcc, 0x58, 0xdb, 0x0b, 0x9e, 0xcb, 0x59, 0x15, 0xdb, 0xe5, 0xf8, 0x8a, - 0xa5, 0x36, 0x97, 0xa8, 0x1c, 0xad, 0xc7, 0xda, 0x14, 0x23, 0xbf, 0x52, 0x48, 0x94, 0x45, 0xc7, 0xd6, 0x42, 0x01, - 0xf1, 0x02, 0xf4, 0x25, 0x7b, 0xd3, 0x00, 0xeb, 0x8d, 0x5e, 0x45, 0x84, 0x96, 0x8f, 0x54, 0x78, 0x9b, 0x9b, 0x2a, - 0xb3, 0xb2, 0x59, 0xb4, 0xfb, 0x29, 0xe7, 0x39, 0x82, 0xd5, 0x1b, 0xb5, 0x47, 0x01, 0x6a, 0x0f, 0x2d, 0x94, 0x01, - 0xa4, 0x34, 0xcd, 0x00, 0x90, 0x01, 0x40, 0xa6, 0x8a, 0xf8, 0x4c, 0x80, 0x4a, 0x5b, 0xdd, 0x28, 0x70, 0x22, 0xbd, - 0x02, 0x9a, 0x05, 0x56, 0xfa, 0x48, 0x41, 0x06, 0x8b, 0x2d, 0x02, 0xb0, 0x72, 0xe4, 0x0c, 0xd3, 0x18, 0xb2, 0x8d, - 0x26, 0x2e, 0x49, 0xf3, 0xfb, 0x30, 0x4b, 0x25, 0x9e, 0xc4, 0x8f, 0xb2, 0xc6, 0x08, 0x00, 0xa4, 0xef, 0xd3, 0x8b, - 0x22, 0x8b, 0x09, 0x07, 0xce, 0x7a, 0xea, 0xa0, 0xa8, 0xc9, 0xb9, 0xd6, 0xb4, 0x7a, 0x56, 0x9b, 0x3c, 0x64, 0x81, - 0xce, 0x1e, 0x8c, 0x49, 0x2d, 0xdf, 0xf3, 0xc8, 0xfe, 0xca, 0xe9, 0x8c, 0xf0, 0x5d, 0x77, 0x70, 0xea, 0xbf, 0xdb, - 0x1a, 0x98, 0x98, 0x12, 0x80, 0x8d, 0xc1, 0xd1, 0x84, 0xf8, 0x9d, 0x8e, 0xc9, 0xd4, 0x26, 0x45, 0x20, 0xf0, 0x10, - 0xbc, 0x82, 0xeb, 0x0b, 0x19, 0x30, 0x20, 0x68, 0x3b, 0x8b, 0x3c, 0x4d, 0x00, 0x4e, 0xbc, 0xe0, 0x3b, 0x80, 0xe3, - 0xd4, 0xab, 0x42, 0xf6, 0xec, 0xa5, 0x98, 0xce, 0xe6, 0xc1, 0x43, 0x42, 0xfb, 0x17, 0x13, 0x7e, 0xd3, 0x5d, 0x25, - 0x57, 0xa6, 0xd6, 0xbd, 0x89, 0xae, 0x72, 0x95, 0xd3, 0xa7, 0x39, 0xc7, 0x30, 0x67, 0xb0, 0x0a, 0xc8, 0x39, 0x1b, - 0xf2, 0xe7, 0x97, 0x00, 0xd8, 0xb2, 0x16, 0x5e, 0xc4, 0x9f, 0x87, 0xb2, 0x5a, 0x00, 0xf7, 0xc8, 0x79, 0x64, 0x7e, - 0xf9, 0x6a, 0x3b, 0x94, 0x73, 0x8a, 0xc2, 0x58, 0xce, 0x4d, 0x4b, 0x8a, 0xd3, 0xa1, 0xa7, 0x60, 0x32, 0xb5, 0xe5, - 0xef, 0x5d, 0xe2, 0x32, 0x7b, 0x33, 0x09, 0xe7, 0xeb, 0xc8, 0xb6, 0xb5, 0xea, 0x1e, 0xba, 0x21, 0x18, 0xf4, 0x31, - 0x82, 0x96, 0xd5, 0x9b, 0x5f, 0x31, 0x18, 0x28, 0x6c, 0xdf, 0x9a, 0x6e, 0x5a, 0x74, 0x8a, 0x03, 0xce, 0xac, 0x75, - 0x8d, 0x4a, 0x55, 0x71, 0xe8, 0x25, 0xef, 0x96, 0x95, 0xdb, 0x65, 0xe9, 0x85, 0x20, 0x35, 0xea, 0x2a, 0x42, 0xa4, - 0x54, 0xec, 0xf0, 0x9e, 0xfc, 0x1a, 0x98, 0x78, 0x66, 0xe5, 0x28, 0x8d, 0xe7, 0x00, 0x13, 0xa4, 0xd0, 0x37, 0xe5, - 0x57, 0x80, 0x1b, 0xba, 0x88, 0xc2, 0xec, 0x4d, 0x5c, 0x05, 0xb5, 0xd5, 0xf4, 0x7b, 0x07, 0x27, 0xf6, 0xb2, 0xee, - 0xf7, 0x53, 0xa2, 0xf1, 0xc3, 0xd0, 0x0b, 0xfc, 0x7b, 0x3c, 0x3d, 0x34, 0x41, 0x6a, 0x5e, 0x79, 0x80, 0x57, 0x74, - 0xb9, 0xb5, 0x29, 0x57, 0x34, 0x2e, 0xe6, 0x35, 0x22, 0xc2, 0xa7, 0x8e, 0x62, 0xbb, 0xcd, 0x8f, 0x53, 0x1b, 0x83, - 0x41, 0x08, 0xf7, 0xad, 0x8c, 0xdf, 0x27, 0x5e, 0x35, 0x8b, 0xe6, 0xa0, 0x28, 0xcd, 0x34, 0x49, 0x48, 0x21, 0xbd, - 0x04, 0xe8, 0xa3, 0x41, 0xa8, 0xd5, 0x95, 0x7f, 0x24, 0x5e, 0xaa, 0xa6, 0xb5, 0x79, 0x8a, 0x35, 0x0a, 0xc4, 0x2c, - 0x9a, 0x37, 0x2c, 0xa3, 0x43, 0x52, 0x5d, 0x2e, 0x4d, 0x33, 0xfe, 0xb0, 0x9a, 0xa1, 0x5a, 0x71, 0xd2, 0x04, 0x35, - 0x4a, 0xb7, 0x70, 0x01, 0xfc, 0x1b, 0xdd, 0x71, 0x54, 0xa3, 0x48, 0xd1, 0x80, 0x4f, 0x20, 0xa6, 0xab, 0x30, 0x9b, - 0x27, 0xac, 0x35, 0x75, 0xcd, 0xe8, 0xf7, 0x65, 0x9c, 0x90, 0x49, 0x42, 0x72, 0x3e, 0x5c, 0xae, 0x1f, 0x49, 0x75, - 0x01, 0xa4, 0xca, 0x39, 0x9b, 0xf5, 0x7a, 0x73, 0xc0, 0xe8, 0x85, 0xf5, 0x0b, 0x1b, 0x57, 0x70, 0x79, 0x4d, 0x98, - 0xbb, 0xea, 0x47, 0x98, 0x65, 0x50, 0x05, 0xa4, 0xf9, 0xb1, 0xa0, 0xd3, 0x2b, 0x17, 0x88, 0xfa, 0xf5, 0x48, 0x5d, - 0x50, 0x66, 0xe9, 0xdc, 0x22, 0x02, 0x01, 0xaf, 0x61, 0xf5, 0x04, 0x92, 0x7d, 0xf9, 0xd8, 0xa7, 0x19, 0x05, 0xaa, - 0x23, 0x00, 0x65, 0xb3, 0x7e, 0x08, 0xfb, 0x07, 0x84, 0x13, 0xea, 0x6f, 0xde, 0xca, 0x59, 0x43, 0xf2, 0x40, 0xaa, - 0x09, 0x8f, 0xe1, 0xd4, 0x58, 0xe0, 0x4b, 0x8b, 0xde, 0x54, 0xf0, 0x9a, 0xe0, 0xb8, 0x17, 0x68, 0xed, 0x5b, 0xc0, - 0x11, 0x22, 0xb8, 0x0c, 0x4d, 0x9c, 0xf6, 0xf6, 0xbd, 0x00, 0x09, 0xcd, 0x2d, 0x9c, 0xeb, 0xb7, 0x2e, 0x68, 0x71, - 0x8a, 0x9c, 0x2c, 0xba, 0xc0, 0x40, 0x17, 0x64, 0xde, 0xf8, 0x67, 0x0e, 0x2b, 0x17, 0x20, 0x7b, 0xa9, 0x58, 0x49, - 0xc4, 0xb6, 0x57, 0x7f, 0x94, 0xca, 0x7e, 0x7b, 0x61, 0x4d, 0xe0, 0x97, 0x89, 0xfd, 0x12, 0x99, 0x7c, 0xd3, 0x53, - 0x93, 0xaf, 0x8c, 0x85, 0x4e, 0x2d, 0x83, 0x73, 0x7a, 0x62, 0x70, 0xee, 0xed, 0xad, 0xda, 0x94, 0x30, 0x14, 0x24, - 0x81, 0xa6, 0x4b, 0x0f, 0xeb, 0xa6, 0x3f, 0x3f, 0x69, 0xf1, 0x6b, 0xd5, 0xbe, 0x75, 0x3f, 0x0e, 0xb1, 0x8b, 0x5f, - 0x26, 0x9e, 0x61, 0x1f, 0xf5, 0x81, 0x03, 0x4c, 0x46, 0x4c, 0x5c, 0xf7, 0xfb, 0x50, 0xd8, 0x6c, 0x3c, 0x1f, 0xd5, - 0xc5, 0xcf, 0xc5, 0x03, 0x40, 0x39, 0x54, 0x60, 0x97, 0x43, 0x19, 0xca, 0x88, 0x4d, 0x6d, 0xb9, 0xe7, 0xf7, 0x97, - 0x61, 0x0e, 0xf2, 0x8e, 0xc6, 0xc4, 0xb9, 0x00, 0x31, 0x0c, 0xbe, 0xfe, 0xfd, 0x93, 0x43, 0xda, 0x7c, 0x7f, 0x01, - 0xdf, 0x1d, 0x5d, 0x7c, 0x40, 0x8e, 0x9b, 0x8b, 0x4d, 0x59, 0xdc, 0xa7, 0xb1, 0xb8, 0xf8, 0x1e, 0x52, 0xbf, 0xbf, - 0x28, 0xca, 0x8b, 0xef, 0x55, 0x65, 0xbe, 0xbf, 0xa0, 0x05, 0x37, 0xfa, 0xdd, 0x9a, 0x78, 0xff, 0xc8, 0x35, 0xed, - 0xd9, 0x12, 0xc2, 0xb1, 0xb4, 0xfa, 0x11, 0x94, 0x88, 0x8a, 0x14, 0x55, 0x86, 0xb2, 0x5a, 0x3b, 0xce, 0xfb, 0x44, - 0xc3, 0x63, 0xd3, 0x84, 0xc4, 0xd5, 0x12, 0xd6, 0xa1, 0x9e, 0x9d, 0x36, 0xc9, 0x8e, 0xf3, 0x40, 0x1d, 0x10, 0x15, - 0x7f, 0x5e, 0x8d, 0x76, 0xf4, 0x35, 0xf8, 0xd6, 0xf1, 0x58, 0x8d, 0xf6, 0xe6, 0xa7, 0x4f, 0xd6, 0x4a, 0x19, 0x6c, - 0xa4, 0x18, 0x85, 0x90, 0x28, 0x6e, 0xd7, 0x63, 0x00, 0xfc, 0xef, 0x1f, 0x8f, 0xf4, 0x7b, 0x2f, 0x7f, 0xab, 0xdd, - 0xd2, 0xaa, 0xe7, 0x87, 0x16, 0x61, 0xc6, 0xab, 0xda, 0xb0, 0xb3, 0x1d, 0x24, 0xa0, 0xf4, 0xa1, 0x69, 0x50, 0x53, - 0x44, 0x3f, 0x61, 0x35, 0xb1, 0x9c, 0xc3, 0x82, 0x94, 0x38, 0xc4, 0x70, 0x8c, 0x76, 0xe8, 0x71, 0xba, 0xa8, 0x79, - 0x2a, 0xdf, 0x21, 0xe3, 0xd6, 0xf7, 0x01, 0xc9, 0xa5, 0x70, 0xf9, 0xc1, 0x0b, 0x0d, 0x26, 0x7a, 0x91, 0x57, 0x45, - 0x26, 0x46, 0x82, 0x46, 0xf9, 0x0d, 0x89, 0x33, 0x17, 0x58, 0x8b, 0x0b, 0x85, 0x10, 0x16, 0x12, 0x2a, 0x77, 0x51, - 0x52, 0x7a, 0x70, 0xf1, 0xe4, 0x50, 0x36, 0xbf, 0x13, 0x26, 0xc4, 0x68, 0x01, 0x34, 0x38, 0xfb, 0x76, 0x79, 0x0f, - 0x61, 0x99, 0x7b, 0xbf, 0xbf, 0x59, 0xe5, 0x05, 0xc4, 0x65, 0x5e, 0x48, 0xc5, 0x6a, 0x79, 0x01, 0x34, 0x79, 0x22, - 0xbe, 0x08, 0x2b, 0x39, 0x0d, 0xaa, 0x8e, 0x62, 0xd5, 0x36, 0x5e, 0x56, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, - 0xdd, 0x67, 0xaf, 0x95, 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, - 0xe7, 0x26, 0xc8, 0x3f, 0xbe, 0x39, 0xa3, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, - 0x9b, 0x23, 0x35, 0x79, 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, - 0x67, 0x2b, 0x2a, 0x2f, 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xaa, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, - 0x62, 0x86, 0x29, 0xd6, 0x5f, 0xd8, 0xf2, 0xdb, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x6b, 0x16, 0xc2, - 0xf1, 0xb8, 0x9d, 0x14, 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0xc7, 0x63, 0x57, 0xcb, 0x36, 0xc2, 0x83, 0x87, 0xaa, - 0x85, 0xdb, 0x86, 0x55, 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, - 0x1b, 0x1b, 0xe0, 0x1a, 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, - 0x09, 0xa3, 0x15, 0xc2, 0xef, 0xa1, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, - 0x4a, 0xb1, 0x34, 0x6f, 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0xf3, 0xd0, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, - 0xcd, 0xe6, 0xc0, 0x7d, 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x67, 0xcb, 0xe3, - 0xf0, 0x2d, 0xfc, 0xcb, 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xcb, 0x15, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, - 0xad, 0xa8, 0x0d, 0x7f, 0xc3, 0xbf, 0x84, 0x7d, 0x84, 0xfd, 0x96, 0xe3, 0x4d, 0xd2, 0x10, 0x90, 0x09, 0xc4, 0x85, - 0x85, 0x20, 0xc1, 0xdf, 0x72, 0xc9, 0x3f, 0x27, 0x7c, 0xb6, 0x28, 0x81, 0xac, 0x0e, 0xa3, 0xf8, 0x84, 0x62, 0xa2, - 0x10, 0x86, 0x5b, 0x42, 0xef, 0xe8, 0xbf, 0x11, 0x25, 0xd9, 0xa4, 0xb2, 0x62, 0x3d, 0x90, 0x49, 0x12, 0x4c, 0xb0, - 0xf2, 0x42, 0xf9, 0xc2, 0xbd, 0x50, 0x6a, 0xad, 0x05, 0xad, 0x5f, 0xfe, 0x24, 0xf1, 0x0c, 0xe8, 0x1e, 0xc8, 0x18, - 0x74, 0x1b, 0x51, 0x4d, 0x72, 0x4c, 0x1f, 0xa5, 0xf3, 0x0c, 0x54, 0x40, 0x17, 0x9b, 0x2c, 0xac, 0x97, 0x45, 0xb9, - 0x6e, 0x85, 0x87, 0xca, 0xd2, 0x47, 0xea, 0x31, 0xe6, 0x85, 0x79, 0x72, 0x26, 0x1f, 0x3c, 0x02, 0x34, 0x3c, 0xca, - 0xd3, 0xaa, 0xa3, 0xb4, 0x7e, 0x60, 0x19, 0x30, 0x02, 0x67, 0xca, 0x80, 0x47, 0x58, 0x06, 0xe6, 0x69, 0x97, 0xa1, - 0x06, 0xb1, 0x46, 0xd5, 0x95, 0xda, 0x60, 0xce, 0x14, 0x25, 0x9f, 0x62, 0x69, 0x85, 0x31, 0x34, 0x75, 0xe5, 0x91, - 0xf5, 0x92, 0x13, 0xf6, 0x6c, 0x37, 0x90, 0x6e, 0x61, 0xab, 0xc0, 0x05, 0x5d, 0xcb, 0x12, 0xe5, 0xa2, 0x5b, 0x46, - 0x94, 0x89, 0x90, 0xfa, 0xd9, 0xc3, 0x99, 0x56, 0xfb, 0x8d, 0x9d, 0x74, 0x68, 0x8f, 0x14, 0xbd, 0x60, 0x20, 0x3e, - 0xed, 0x91, 0x52, 0xcf, 0x1a, 0xb9, 0x0c, 0x6c, 0xe9, 0x52, 0xd5, 0xf3, 0x5f, 0xa0, 0x7c, 0x07, 0x33, 0xe3, 0x6c, - 0xf6, 0xbb, 0xde, 0xdc, 0x9e, 0x1c, 0xea, 0xe6, 0x77, 0xd6, 0xeb, 0xc1, 0xd6, 0x20, 0x13, 0x5f, 0x28, 0xea, 0x29, - 0xab, 0x10, 0x2b, 0x32, 0xfb, 0x5f, 0xc2, 0xfb, 0x1d, 0xde, 0x1a, 0xa1, 0x59, 0x19, 0x0f, 0xf3, 0xd1, 0x93, 0x83, - 0x68, 0x7e, 0xef, 0x2c, 0xdb, 0xca, 0x55, 0xc9, 0x6c, 0xbf, 0x9f, 0x24, 0xcd, 0xd9, 0xe3, 0x35, 0x92, 0x3a, 0xc0, - 0xc7, 0xeb, 0x33, 0x7c, 0xa4, 0x12, 0x4a, 0x2d, 0xa8, 0x6a, 0xd0, 0xfa, 0xd8, 0xef, 0xad, 0xe7, 0xf4, 0xf1, 0x53, - 0x39, 0xdd, 0x92, 0x22, 0x8c, 0x1f, 0x18, 0x4c, 0xd9, 0x89, 0x53, 0x97, 0xaa, 0x19, 0xd2, 0xbb, 0x6e, 0x95, 0xd4, - 0x65, 0x8f, 0x12, 0x41, 0xa8, 0x83, 0xf5, 0x8b, 0xfd, 0x10, 0x66, 0xb6, 0xe8, 0x0f, 0x9b, 0xd5, 0x9c, 0x50, 0x10, - 0x01, 0xa2, 0x55, 0xde, 0x07, 0x4e, 0x49, 0xc2, 0xac, 0xb9, 0x21, 0xdd, 0x7a, 0x2b, 0xa5, 0xbd, 0x92, 0x02, 0xfa, - 0x65, 0x7e, 0x3c, 0xa2, 0xf9, 0xcd, 0xec, 0x5c, 0x95, 0xb4, 0xe5, 0x00, 0x22, 0x75, 0xde, 0xb4, 0x2f, 0x1d, 0x0e, - 0xfe, 0x83, 0xba, 0x12, 0xe5, 0x44, 0xd0, 0x51, 0xb4, 0x60, 0xb4, 0x5a, 0xb5, 0xab, 0xc8, 0xa6, 0x42, 0xb6, 0x24, - 0xc2, 0x89, 0x92, 0xbd, 0x12, 0xea, 0xa3, 0x5c, 0xed, 0x99, 0x86, 0xf8, 0x33, 0x01, 0x9b, 0x36, 0xf8, 0x5b, 0xe0, - 0x5e, 0x06, 0x67, 0xa6, 0x7d, 0x1a, 0x46, 0x40, 0x64, 0x0e, 0xc1, 0x7e, 0x7e, 0xd7, 0x83, 0x1c, 0x1e, 0x74, 0xa4, - 0xbf, 0xaa, 0x67, 0x05, 0x9e, 0xb9, 0x67, 0x9e, 0xbf, 0x3e, 0x93, 0x9e, 0x57, 0xf0, 0x40, 0x73, 0x1f, 0x66, 0xfc, - 0x45, 0x59, 0x86, 0xfb, 0xd1, 0xb2, 0x2c, 0xd6, 0x5e, 0xa4, 0xf7, 0xf1, 0x4c, 0x8a, 0x81, 0x44, 0x87, 0x99, 0xd1, - 0x55, 0xac, 0xe3, 0x1c, 0xc6, 0xbd, 0x3d, 0x09, 0x2b, 0xb4, 0x7f, 0x96, 0xd8, 0xeb, 0x02, 0x00, 0x1c, 0xb2, 0x06, - 0xad, 0xf0, 0x4e, 0xb7, 0xb7, 0x7b, 0x5c, 0x52, 0xa2, 0xb8, 0x51, 0xf3, 0xb3, 0x1a, 0x5a, 0x26, 0xa8, 0x65, 0xd6, - 0x9d, 0x4c, 0xa6, 0x48, 0x02, 0xdf, 0x86, 0xbd, 0x66, 0x79, 0x35, 0x6f, 0xe4, 0xf6, 0xf0, 0x2e, 0x5c, 0x8b, 0x58, - 0x5b, 0xd0, 0x49, 0x47, 0xc6, 0xe1, 0x5e, 0x68, 0x6e, 0xa4, 0x87, 0x27, 0x55, 0x12, 0x96, 0x22, 0x86, 0x5b, 0x20, - 0x3b, 0xa8, 0x6d, 0x25, 0x28, 0x81, 0x04, 0xf6, 0x43, 0x29, 0x96, 0xe9, 0x4e, 0x00, 0x98, 0x03, 0xff, 0x53, 0x1a, - 0xbb, 0xdd, 0x9d, 0x87, 0x78, 0xd5, 0xc8, 0xfb, 0x06, 0x21, 0xd8, 0x5f, 0x81, 0x9c, 0x06, 0x0c, 0x22, 0xc5, 0x48, - 0x16, 0x0c, 0x24, 0x00, 0x15, 0xdf, 0x80, 0x49, 0x6e, 0x5a, 0x79, 0x7e, 0x50, 0xe9, 0x0e, 0xa6, 0x7d, 0xd0, 0xbd, - 0xb8, 0xd6, 0x0c, 0x90, 0x7f, 0x27, 0x11, 0xff, 0x5b, 0xed, 0x95, 0xac, 0x62, 0x99, 0xdf, 0x98, 0x8b, 0x4e, 0x06, - 0x57, 0x0d, 0xe1, 0x17, 0xb3, 0x6c, 0xce, 0xa3, 0x59, 0xa6, 0x43, 0xfd, 0x8b, 0xe6, 0xa4, 0x14, 0xc0, 0x50, 0xc7, - 0x0b, 0xb0, 0xc6, 0xbb, 0xd2, 0x4d, 0x2b, 0x1e, 0x69, 0x8c, 0x51, 0x50, 0xa1, 0x83, 0xd0, 0xdf, 0x6a, 0x80, 0xd7, - 0x60, 0x92, 0x1b, 0x21, 0xf7, 0xc1, 0x05, 0xdd, 0xd0, 0x2d, 0xe7, 0x2e, 0x41, 0x4d, 0xaa, 0x96, 0x5f, 0x85, 0x50, - 0xef, 0x6a, 0xc9, 0xa5, 0xda, 0x7c, 0x6a, 0x94, 0x35, 0x82, 0x4c, 0x8e, 0xd2, 0xef, 0x53, 0x2e, 0xdc, 0xdc, 0x98, - 0xac, 0x8f, 0x47, 0xaf, 0xe0, 0xa6, 0xc6, 0x3f, 0x56, 0x92, 0x45, 0xd4, 0x1a, 0x12, 0x61, 0x6b, 0xb7, 0x42, 0xf7, - 0x1e, 0x37, 0x4a, 0xf3, 0x28, 0xdb, 0xc6, 0xa2, 0xf2, 0x7a, 0x09, 0x58, 0x8b, 0x7b, 0x40, 0x86, 0x4a, 0x4b, 0x3f, - 0x67, 0x05, 0x40, 0x06, 0x48, 0x61, 0xe3, 0x47, 0xa4, 0xbd, 0xfa, 0xe0, 0xa5, 0x7e, 0xbf, 0x6f, 0x4c, 0xf9, 0xef, - 0x1f, 0x72, 0x60, 0x26, 0x14, 0x65, 0xbd, 0x87, 0x09, 0x54, 0x79, 0xa9, 0x4f, 0xda, 0xb3, 0x9a, 0x3f, 0xdf, 0xd4, - 0x1e, 0x90, 0x5a, 0xf9, 0x16, 0x73, 0xd5, 0x2b, 0xfb, 0x62, 0x73, 0x48, 0xab, 0x5b, 0xa3, 0x71, 0x10, 0x2c, 0xad, - 0xde, 0x68, 0x95, 0x43, 0xd5, 0xf0, 0x1c, 0x44, 0x2a, 0xeb, 0xea, 0x9a, 0x3b, 0x57, 0xd7, 0x82, 0x23, 0x81, 0x6c, - 0xc9, 0x21, 0x2c, 0x8d, 0x85, 0xdc, 0x2b, 0x8f, 0xc7, 0xc2, 0xef, 0xf7, 0xd3, 0x59, 0x8e, 0x97, 0x16, 0xa0, 0x4c, - 0xdb, 0xd4, 0x5e, 0xe8, 0x1f, 0x8f, 0x3f, 0x82, 0xd7, 0x88, 0x7f, 0x3c, 0x96, 0xfd, 0xfe, 0x47, 0x73, 0x93, 0xb9, - 0x1c, 0x2b, 0xa5, 0xec, 0x35, 0x2a, 0xdd, 0xdf, 0x24, 0xbc, 0xf7, 0xbf, 0x47, 0xff, 0x7b, 0x74, 0xdd, 0x53, 0x01, - 0x60, 0x09, 0x9f, 0xe1, 0x0d, 0x9d, 0xa9, 0xcb, 0x39, 0x93, 0xee, 0xee, 0xca, 0x0f, 0xbd, 0xa7, 0xf1, 0xe1, 0x7b, - 0x73, 0xd3, 0xc6, 0x5f, 0xf3, 0x13, 0x4d, 0x42, 0xc7, 0x45, 0xff, 0x78, 0xfc, 0x94, 0x68, 0x7d, 0x5a, 0xaa, 0xf4, - 0x69, 0x0a, 0x3c, 0xc9, 0xb0, 0xe1, 0xba, 0x85, 0xe9, 0x68, 0x7e, 0xdc, 0x7c, 0x95, 0xbc, 0x38, 0x4b, 0xe1, 0xda, - 0x0b, 0x3a, 0x97, 0x29, 0x58, 0x57, 0x86, 0xe0, 0x66, 0x10, 0x40, 0xea, 0x10, 0xd2, 0xac, 0x69, 0xf8, 0x97, 0xdc, - 0x15, 0xbc, 0xb5, 0xc7, 0xbb, 0xc1, 0x88, 0x52, 0x47, 0xfa, 0xa4, 0x0d, 0xa1, 0x4b, 0x2a, 0xf9, 0x8f, 0x22, 0x8f, - 0x31, 0x66, 0xe3, 0x15, 0x91, 0x7d, 0x16, 0xf9, 0xcb, 0x02, 0x00, 0x8b, 0x00, 0x01, 0x39, 0x9d, 0x3b, 0x92, 0xf8, - 0xcf, 0xc9, 0xb7, 0x7f, 0x4c, 0x97, 0xf6, 0xa1, 0x2c, 0x56, 0xa5, 0xa8, 0xaa, 0x93, 0xd2, 0xf6, 0xb6, 0x5c, 0x0f, - 0xf4, 0xa1, 0xfd, 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, - 0x58, 0x3f, 0x7f, 0xd8, 0xbf, 0x89, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, - 0xc3, 0x54, 0xe2, 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0xbf, 0xe7, 0x30, 0xff, 0x75, - 0x7b, 0xb0, 0x3e, 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0xe7, 0xc2, 0x22, 0xf9, - 0xf5, 0xc9, 0x91, 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x89, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9d, 0xff, 0x95, 0x99, 0xff, - 0x03, 0x8c, 0x49, 0x28, 0x9e, 0x73, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0xcf, 0x81, - 0x83, 0xf9, 0x39, 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0xd7, 0x16, 0xcf, 0x95, - 0x5c, 0x10, 0xfa, 0xba, 0x0a, 0xb3, 0x71, 0x5d, 0x6c, 0x2b, 0x51, 0x6c, 0x21, 0x6c, 0x04, 0xd4, 0xb2, 0xd5, 0xb4, - 0xb6, 0x15, 0xb2, 0x3f, 0x89, 0x16, 0x6d, 0x97, 0xa1, 0x9a, 0x8c, 0xb2, 0x74, 0x33, 0x05, 0x52, 0xbd, 0x00, 0xce, - 0x22, 0xf3, 0xca, 0x3b, 0x67, 0x0f, 0xd8, 0xa1, 0xf1, 0x14, 0x18, 0x51, 0xe9, 0x8f, 0xaa, 0x31, 0x3a, 0x3d, 0xd1, - 0xef, 0x57, 0x53, 0x0a, 0xf9, 0xfa, 0x09, 0x30, 0xb9, 0x6a, 0xb9, 0x00, 0x7d, 0x19, 0xea, 0xa0, 0x12, 0xa5, 0x56, - 0x0c, 0x23, 0x16, 0x7e, 0x12, 0xc8, 0xde, 0x4c, 0x41, 0xcd, 0x2a, 0x4a, 0x42, 0x25, 0x2a, 0x25, 0x5b, 0x13, 0xd4, - 0xd2, 0xfb, 0xa2, 0xa8, 0x0f, 0x15, 0x38, 0x4a, 0x46, 0xda, 0x2c, 0xa7, 0xcc, 0xb8, 0x28, 0x73, 0xd1, 0x0f, 0xf6, - 0x2f, 0xc0, 0xf8, 0x92, 0xf9, 0x2c, 0xf7, 0x1d, 0x9d, 0xd3, 0x76, 0x5c, 0xa0, 0xcc, 0x2d, 0xa7, 0xad, 0x96, 0x3c, - 0x26, 0xef, 0x59, 0xb0, 0xed, 0xbf, 0x48, 0x90, 0x57, 0x11, 0xe6, 0x13, 0xaa, 0x6c, 0xfe, 0x9e, 0x7b, 0xc4, 0x3e, - 0xda, 0xe1, 0xc2, 0x44, 0xa4, 0xb7, 0x60, 0x49, 0x0c, 0xb3, 0x52, 0x84, 0xf1, 0x1e, 0xbc, 0x7f, 0xb6, 0x95, 0x18, - 0x5d, 0xa0, 0x93, 0xfb, 0xc5, 0x43, 0x5a, 0x27, 0x17, 0x6f, 0x5e, 0x5d, 0x7c, 0xdf, 0x1b, 0x14, 0xa3, 0x34, 0x1e, - 0xf4, 0xbe, 0xbf, 0x58, 0x6f, 0x01, 0x22, 0x53, 0x5c, 0xc4, 0x64, 0x4a, 0x13, 0xf1, 0x05, 0x19, 0x06, 0x2f, 0xea, - 0x44, 0x5c, 0xd0, 0xc4, 0x74, 0x5f, 0xa3, 0x34, 0xf9, 0x76, 0x14, 0xe6, 0xf0, 0x72, 0x29, 0xb6, 0x95, 0x88, 0xc1, - 0x4e, 0xa9, 0xe6, 0xd9, 0xc9, 0x59, 0x2c, 0x3d, 0x06, 0x5d, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, - 0x05, 0x84, 0x1e, 0xf0, 0xcc, 0xcf, 0xe3, 0x51, 0x24, 0x10, 0x6a, 0xc1, 0x9c, 0x4c, 0x23, 0xba, 0x21, 0xbd, 0xc4, - 0x3e, 0x03, 0xb3, 0x90, 0xd2, 0x3c, 0xb8, 0xb9, 0x5a, 0xb4, 0xdc, 0x39, 0x2b, 0x47, 0x61, 0xb5, 0x11, 0x51, 0x8d, - 0x54, 0xc7, 0xe0, 0xbc, 0x03, 0x11, 0x00, 0x8a, 0x11, 0x3c, 0xe3, 0x51, 0xbf, 0x1f, 0xa9, 0xa0, 0x9c, 0x84, 0x7e, - 0x51, 0xe8, 0x97, 0xc6, 0xa0, 0x8c, 0xf9, 0x97, 0x50, 0x13, 0x03, 0xd4, 0x3b, 0x1e, 0x2a, 0x8e, 0x00, 0x5c, 0xce, - 0x11, 0x33, 0xce, 0x7b, 0xdc, 0x45, 0xe3, 0x54, 0xbc, 0x13, 0xea, 0x3a, 0x58, 0x2a, 0xd4, 0x79, 0x53, 0x1f, 0xe9, - 0x39, 0x69, 0x12, 0x34, 0x88, 0x1b, 0x78, 0xbc, 0x1a, 0x02, 0xaa, 0xb5, 0x90, 0x7a, 0x0b, 0x9d, 0x52, 0xd5, 0x21, - 0xb0, 0x06, 0xb8, 0x44, 0x61, 0x3b, 0x61, 0x72, 0x44, 0xdb, 0xb2, 0x14, 0xf9, 0x09, 0x1b, 0xb4, 0x4b, 0x46, 0xa6, - 0x0e, 0x2e, 0x97, 0xcb, 0x89, 0xa8, 0x7f, 0xcd, 0xb7, 0x00, 0xce, 0x0b, 0xf9, 0xad, 0xdd, 0x6c, 0x99, 0x64, 0xbb, - 0xfe, 0x3f, 0xbc, 0x7d, 0x09, 0x77, 0xdb, 0x46, 0xb2, 0xee, 0x5f, 0x11, 0xf1, 0x1c, 0x06, 0x6d, 0x36, 0x29, 0x52, - 0xb1, 0x33, 0x09, 0xa8, 0x16, 0xaf, 0xe2, 0x25, 0x71, 0x26, 0x5e, 0x62, 0x39, 0x99, 0xcc, 0xf0, 0xf1, 0x2a, 0x10, - 0xd0, 0x12, 0x11, 0x43, 0x68, 0x06, 0x00, 0xb5, 0x84, 0xc4, 0x7f, 0x7f, 0xa7, 0xaa, 0x77, 0x10, 0x94, 0x3d, 0xf3, - 0xee, 0x7b, 0xc7, 0xe7, 0x58, 0x44, 0xa3, 0xd1, 0x7b, 0x57, 0x57, 0xd7, 0xf2, 0x55, 0x65, 0x63, 0x96, 0x94, 0xbc, - 0x5a, 0x89, 0xa2, 0xca, 0x6e, 0xf8, 0x4f, 0xe6, 0xa5, 0x1f, 0x40, 0x0a, 0xed, 0x48, 0x5f, 0xb7, 0xbb, 0xa3, 0xc4, - 0x38, 0xa6, 0x1c, 0xd7, 0x52, 0xe9, 0x5e, 0x8d, 0xaa, 0x13, 0x37, 0x5b, 0xe5, 0x5a, 0x66, 0x69, 0xca, 0x8b, 0x57, - 0x45, 0x9a, 0x25, 0x4e, 0x72, 0xac, 0x02, 0x54, 0xdb, 0xc8, 0x57, 0x36, 0x36, 0xf2, 0xf3, 0xac, 0xc2, 0x80, 0xc1, - 0x5e, 0xa3, 0x5a, 0xa1, 0xa6, 0x74, 0xe0, 0x0b, 0xf1, 0x1e, 0x23, 0x6e, 0xb3, 0x22, 0x01, 0x86, 0x1f, 0x13, 0xd5, - 0x25, 0x3d, 0x85, 0x28, 0x0f, 0x32, 0x1e, 0xf7, 0x73, 0x8e, 0x88, 0xd7, 0x46, 0x65, 0x0e, 0x4c, 0xb6, 0x52, 0x41, - 0x22, 0xd8, 0x5d, 0x36, 0x57, 0x8b, 0x68, 0x21, 0xef, 0x42, 0xbd, 0x78, 0xbb, 0xed, 0x25, 0x92, 0x0e, 0x58, 0xf9, - 0x69, 0xf0, 0x32, 0xce, 0x72, 0x9e, 0x1e, 0xd4, 0xe2, 0x40, 0x6e, 0xa8, 0x03, 0xe9, 0xcc, 0x01, 0x3b, 0xef, 0xcb, - 0xfa, 0x40, 0xad, 0xe9, 0x03, 0xd5, 0xce, 0x03, 0xb8, 0x60, 0xe0, 0xce, 0xbd, 0xca, 0x6e, 0x78, 0x71, 0x00, 0xca, - 0x40, 0x63, 0x3c, 0xd0, 0x54, 0xf5, 0x48, 0x4e, 0x8c, 0x0a, 0x5c, 0x9d, 0xa8, 0x83, 0x39, 0xa0, 0xdf, 0x03, 0x52, - 0x54, 0xeb, 0xed, 0x4a, 0x1d, 0xb4, 0x01, 0xfd, 0x69, 0xa9, 0xfb, 0xa0, 0xa2, 0xc5, 0xcb, 0x90, 0xc0, 0xde, 0x90, - 0x2a, 0xa4, 0x56, 0x2d, 0xab, 0x40, 0xf1, 0x86, 0xb3, 0x78, 0x77, 0xae, 0x25, 0x1b, 0xe7, 0x25, 0x02, 0x7b, 0x65, - 0x45, 0x1d, 0x67, 0xc5, 0xa9, 0x93, 0xca, 0x1b, 0xe5, 0x24, 0x53, 0x69, 0xdf, 0xb2, 0x82, 0xba, 0x3b, 0x44, 0xdf, - 0x22, 0xf5, 0x61, 0xf0, 0x22, 0xac, 0xc9, 0x8c, 0xf7, 0xfb, 0x62, 0x26, 0xa2, 0x62, 0x56, 0x1d, 0x16, 0x91, 0x44, - 0x68, 0xdb, 0x27, 0x02, 0x7a, 0x50, 0x02, 0xe4, 0x0a, 0x80, 0xea, 0x87, 0x84, 0x3f, 0x0f, 0x49, 0x7d, 0x3a, 0x85, - 0x3e, 0xa5, 0xb2, 0x5e, 0x71, 0x0a, 0xaa, 0x1b, 0x6f, 0x64, 0xbd, 0x0a, 0x5a, 0x3c, 0x96, 0x63, 0xb5, 0xa1, 0x6d, - 0x4e, 0x8d, 0x77, 0xbd, 0xde, 0x60, 0xd2, 0xe6, 0x42, 0xae, 0xc2, 0x90, 0x44, 0xb7, 0x85, 0x13, 0x3e, 0xc4, 0x60, - 0x65, 0xb5, 0x36, 0xbf, 0x8e, 0xfd, 0x91, 0x15, 0x29, 0xee, 0x67, 0x43, 0x9c, 0xbb, 0x78, 0x3c, 0xa7, 0xfa, 0x46, - 0x49, 0x8b, 0x74, 0x9b, 0xef, 0xd5, 0x65, 0x48, 0x51, 0x51, 0x4d, 0x1a, 0x55, 0x66, 0xd0, 0x7d, 0xdb, 0xbc, 0x55, - 0x3d, 0xc2, 0x04, 0x78, 0xa5, 0x32, 0xa8, 0x46, 0xe3, 0x81, 0x58, 0xd5, 0xa3, 0x72, 0x5d, 0x14, 0x88, 0x36, 0x0c, - 0x39, 0x66, 0x86, 0x90, 0x64, 0x7f, 0xf1, 0xef, 0x64, 0x70, 0x85, 0x32, 0xbe, 0xd5, 0x70, 0xde, 0xb5, 0xf1, 0xec, - 0x6e, 0x22, 0x37, 0x27, 0x16, 0xd6, 0xb8, 0x0f, 0xfe, 0x51, 0xab, 0x9d, 0x05, 0x94, 0x35, 0xad, 0x6a, 0x38, 0xdc, - 0xa3, 0x3a, 0x16, 0xa5, 0x06, 0x24, 0x76, 0xc8, 0x72, 0xd9, 0x3a, 0x66, 0xd0, 0x80, 0xfe, 0x2e, 0xbb, 0x5e, 0x5f, - 0x23, 0x6a, 0x5b, 0x81, 0xac, 0x93, 0x90, 0xfe, 0x25, 0xed, 0x51, 0x57, 0xf6, 0x54, 0xee, 0xb7, 0x6d, 0xaa, 0x1c, - 0x1a, 0x20, 0x79, 0xec, 0xe6, 0x2c, 0x90, 0x1d, 0x09, 0xa2, 0x40, 0x6e, 0xbd, 0x60, 0xea, 0x9c, 0x32, 0x65, 0x07, - 0xf2, 0x73, 0xa9, 0xcf, 0xb0, 0xcf, 0x38, 0x62, 0xf4, 0x52, 0x89, 0xc1, 0xd4, 0x47, 0x1b, 0xd5, 0xb4, 0x56, 0x80, - 0xaa, 0x9f, 0x6e, 0xe0, 0x4f, 0x54, 0x36, 0x68, 0xa8, 0x35, 0x12, 0x85, 0xa4, 0x89, 0x12, 0x3a, 0x96, 0x96, 0x2a, - 0x98, 0x42, 0x27, 0x91, 0x30, 0x04, 0x34, 0x4c, 0x88, 0x4a, 0x2a, 0xf1, 0xd6, 0x00, 0xce, 0x7c, 0xbc, 0xa8, 0xd6, - 0xa5, 0x32, 0x98, 0xfb, 0x21, 0xbe, 0xe1, 0xaf, 0x9e, 0x5b, 0xa3, 0xfa, 0x96, 0xb5, 0xbe, 0xa3, 0x05, 0xf9, 0x21, - 0xe4, 0x14, 0x1d, 0x98, 0xd8, 0xc9, 0x06, 0x0f, 0xe6, 0xa2, 0x51, 0xa1, 0x2e, 0xde, 0xaa, 0xf8, 0x2b, 0xca, 0x04, - 0xef, 0x01, 0x4f, 0x11, 0x65, 0x78, 0x58, 0x69, 0xab, 0x6a, 0x7c, 0x2a, 0x58, 0x4b, 0x0f, 0x56, 0xf2, 0x74, 0x9d, - 0xf0, 0x10, 0xf4, 0x48, 0x84, 0x9d, 0x84, 0xe5, 0x3c, 0x5e, 0xc0, 0x71, 0x52, 0x12, 0x50, 0x3b, 0xa8, 0x2b, 0xf8, - 0x7c, 0x81, 0xee, 0xaf, 0x02, 0x3d, 0xc0, 0xd0, 0x82, 0xd8, 0x0f, 0x7d, 0x3a, 0xba, 0x8e, 0x57, 0x9e, 0x8a, 0x84, - 0xcf, 0x4b, 0xb0, 0x1d, 0x92, 0xea, 0x29, 0xd0, 0x42, 0x25, 0x52, 0x3f, 0x0c, 0x7c, 0x87, 0x02, 0xbe, 0x56, 0x3a, - 0x40, 0x4d, 0x3f, 0x63, 0x9a, 0x1a, 0x67, 0xa8, 0x7c, 0xe6, 0xdc, 0x33, 0xa3, 0xe5, 0xcc, 0x80, 0x31, 0xa8, 0xdb, - 0x68, 0x8a, 0xe2, 0x9c, 0x7c, 0x16, 0x94, 0x71, 0x9a, 0xc5, 0x39, 0xf8, 0x6d, 0xc6, 0x25, 0x66, 0x4c, 0xe2, 0x9a, - 0x5f, 0x89, 0x12, 0xb4, 0xdd, 0xb9, 0x4c, 0x6d, 0x1a, 0x10, 0x90, 0xfd, 0x00, 0x56, 0x2f, 0x9e, 0x8e, 0xca, 0x7a, - 0x77, 0x29, 0x53, 0x88, 0xb2, 0x0a, 0xc1, 0xa6, 0x99, 0x2e, 0xd9, 0x69, 0x28, 0xb5, 0x39, 0x10, 0xdf, 0x08, 0x8d, - 0xfb, 0xa7, 0x61, 0x6c, 0x34, 0xc5, 0xc6, 0xee, 0x6d, 0xbb, 0xfd, 0xad, 0x70, 0xd2, 0x69, 0x4e, 0x7a, 0x8c, 0xfd, - 0x56, 0x84, 0xe5, 0xc8, 0x74, 0x84, 0xc0, 0x92, 0x73, 0x3e, 0x75, 0x5f, 0xd1, 0x62, 0x9e, 0x80, 0xe9, 0x88, 0x8a, - 0x90, 0x0b, 0x94, 0x1d, 0xa3, 0xb8, 0x03, 0x83, 0x0b, 0x66, 0x42, 0x10, 0x4b, 0x4f, 0x5d, 0x48, 0x96, 0x24, 0x65, - 0xf0, 0x3c, 0x75, 0x30, 0xe0, 0xd7, 0x4c, 0x9a, 0xbb, 0x48, 0xeb, 0xd3, 0x25, 0x99, 0xa6, 0xc8, 0x40, 0xac, 0xc3, - 0x4d, 0x96, 0x46, 0x89, 0x14, 0x91, 0x2d, 0xd1, 0x3f, 0x52, 0x53, 0x2c, 0x15, 0xae, 0x17, 0xa9, 0x12, 0xa1, 0xd5, - 0x3c, 0xc5, 0x93, 0x3a, 0x6d, 0xd2, 0x11, 0xc6, 0x9b, 0x04, 0xa5, 0x5c, 0x03, 0x03, 0x55, 0x50, 0xb5, 0x14, 0x36, - 0xe5, 0x76, 0xab, 0x2e, 0x56, 0xd5, 0x3c, 0x5e, 0xe0, 0xcb, 0x0a, 0x47, 0xf1, 0xef, 0xdc, 0x89, 0x35, 0x25, 0xb7, - 0x07, 0x35, 0x23, 0x4a, 0xe8, 0xdf, 0x39, 0x5c, 0x24, 0xbe, 0x13, 0x2a, 0xee, 0x1f, 0x5a, 0x84, 0x9c, 0xcb, 0x83, - 0x54, 0x73, 0x43, 0x3b, 0xc2, 0x7f, 0xcd, 0xf5, 0x69, 0x67, 0x74, 0x5f, 0xcd, 0xa8, 0xf0, 0x7b, 0x1d, 0x3c, 0x63, - 0xd4, 0x67, 0x03, 0x87, 0x15, 0xa2, 0xd0, 0x86, 0x9d, 0x14, 0x52, 0xb4, 0x30, 0x14, 0xf2, 0x2f, 0xa1, 0xd5, 0x09, - 0xb7, 0x66, 0x94, 0x05, 0xe3, 0xd3, 0xe2, 0xb8, 0x9a, 0x0e, 0x06, 0x05, 0xa9, 0xb5, 0x85, 0x1e, 0x5c, 0x0f, 0x1c, - 0xff, 0x1e, 0xb8, 0x85, 0x38, 0x70, 0xc8, 0xd5, 0x90, 0x6b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8f, 0x2a, 0x19, 0xbc, - 0x9a, 0xc8, 0x16, 0xfc, 0xbd, 0x08, 0x03, 0xf4, 0x49, 0x0a, 0xc0, 0x64, 0x30, 0xe5, 0x77, 0x20, 0x51, 0x3a, 0x97, - 0x37, 0xa4, 0x5f, 0x8a, 0x92, 0x5f, 0xf2, 0x92, 0x17, 0x89, 0x2d, 0xc0, 0xf0, 0x0e, 0xa6, 0xd7, 0x51, 0x4d, 0x25, - 0x10, 0xaf, 0xee, 0x71, 0xc4, 0xb5, 0xf7, 0x9f, 0xee, 0xb1, 0x01, 0x6a, 0x35, 0x8e, 0x0d, 0x2e, 0x73, 0x0c, 0x2e, - 0xe8, 0x4a, 0x62, 0xab, 0xa9, 0x86, 0x11, 0x81, 0x81, 0x0b, 0x38, 0x08, 0x4b, 0x24, 0xc7, 0x56, 0xf1, 0x9a, 0x78, - 0x52, 0xda, 0x07, 0x86, 0xa3, 0x4d, 0x72, 0x5c, 0x9b, 0x65, 0x3b, 0x81, 0xf3, 0x45, 0xe7, 0xa4, 0xe9, 0x58, 0x36, - 0x78, 0x9f, 0xd7, 0xe7, 0xd7, 0xfe, 0x21, 0xa1, 0x32, 0xd8, 0x0d, 0x6f, 0x07, 0xbb, 0xb1, 0xc2, 0xaf, 0x79, 0xb5, - 0x50, 0xf1, 0x59, 0xf4, 0x25, 0xcb, 0x6d, 0xad, 0x73, 0x4b, 0x12, 0x4a, 0x01, 0xed, 0xb2, 0x2c, 0xa8, 0x89, 0x00, - 0x74, 0x3f, 0xfc, 0x05, 0x42, 0x67, 0xf8, 0xdb, 0x63, 0x70, 0x45, 0x0a, 0xf7, 0x0e, 0x41, 0x65, 0x4c, 0x37, 0x77, - 0x6a, 0x03, 0xbe, 0x18, 0xf7, 0x67, 0x4c, 0x1d, 0xfd, 0x36, 0x13, 0xbb, 0xba, 0x6e, 0x87, 0x2c, 0xc3, 0x47, 0xb8, - 0x52, 0x00, 0x2c, 0x13, 0xfe, 0x62, 0x6c, 0x49, 0xf9, 0x09, 0xc0, 0xa9, 0xa9, 0x88, 0x3e, 0x41, 0xa0, 0xe1, 0x94, - 0x68, 0x39, 0xba, 0x91, 0x8e, 0x68, 0x1a, 0x69, 0x4d, 0xb5, 0x42, 0x7b, 0xeb, 0x61, 0x91, 0xd6, 0x34, 0x9c, 0xb8, - 0x0f, 0x8a, 0x79, 0x95, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0x51, 0x1f, 0x21, 0x2e, 0x61, 0x49, 0x14, 0x61, - 0x71, 0x4c, 0xf1, 0x63, 0x42, 0x37, 0xbe, 0xb6, 0xe9, 0x03, 0xd2, 0x5f, 0x5c, 0xb3, 0x6e, 0xca, 0xb2, 0x71, 0xed, - 0xa1, 0xe2, 0xc5, 0xd4, 0x0f, 0x7e, 0x98, 0xc8, 0x62, 0xdc, 0x2f, 0x6a, 0x57, 0x6a, 0x05, 0x30, 0xcc, 0x5d, 0xf5, - 0xf4, 0xfb, 0x7e, 0xb6, 0x1c, 0x08, 0x95, 0xdb, 0x19, 0x24, 0x7d, 0x2a, 0x9e, 0x1f, 0x1c, 0xd1, 0xca, 0x42, 0xcf, - 0x1d, 0x97, 0xc6, 0x87, 0xca, 0x6b, 0x53, 0x23, 0x5a, 0x23, 0x43, 0x65, 0xea, 0x80, 0xf5, 0xfd, 0x43, 0xb8, 0xbb, - 0xa8, 0x69, 0xa8, 0x74, 0xcf, 0x5d, 0x8b, 0x82, 0x13, 0x77, 0x80, 0xb1, 0xb8, 0x90, 0x34, 0x2a, 0x08, 0x93, 0x7a, - 0x34, 0x38, 0xc9, 0x5e, 0x5d, 0x9d, 0x9c, 0x29, 0xe6, 0x09, 0x6c, 0x54, 0xcb, 0xb6, 0xbf, 0xa2, 0x54, 0x97, 0x72, - 0x73, 0x45, 0xf1, 0x3d, 0xa4, 0xcd, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x33, 0x05, 0x17, 0xc6, 0xc1, 0xba, 0xe3, - 0x4e, 0xd9, 0x73, 0x45, 0x99, 0xc6, 0x06, 0x77, 0xed, 0x31, 0x26, 0xda, 0x7e, 0x77, 0xc9, 0x93, 0x8f, 0xc8, 0x82, - 0x7f, 0x97, 0x15, 0xe0, 0x99, 0x6c, 0x5f, 0xc9, 0xfc, 0x3f, 0xb8, 0x57, 0x5b, 0xf3, 0xce, 0x98, 0x7f, 0x3a, 0xd6, - 0xc3, 0x9d, 0xc3, 0xe4, 0x06, 0xe8, 0x0c, 0xe8, 0xe6, 0x5a, 0xa4, 0x1c, 0x90, 0x01, 0x8c, 0x45, 0x32, 0x1a, 0xf0, - 0xa1, 0x95, 0x65, 0xdb, 0x77, 0x5a, 0x5e, 0x10, 0xf6, 0x12, 0xb8, 0xe9, 0xfe, 0xda, 0xf4, 0xcc, 0xa9, 0x5a, 0x89, - 0xa2, 0x4b, 0x63, 0x63, 0x59, 0x2a, 0x81, 0xdd, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x78, 0x39, 0xcd, 0x0d, 0x75, 0xdb, - 0xd8, 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0x35, 0x22, 0xf4, 0x54, 0x8a, - 0xd0, 0xa7, 0xa9, 0xdf, 0x07, 0xb3, 0xaa, 0xd6, 0x5e, 0x9c, 0xa3, 0x41, 0xaa, 0x18, 0xf9, 0xb7, 0x37, 0xbc, 0xbc, - 0xcc, 0xc5, 0x2d, 0x60, 0x20, 0x93, 0x46, 0x2b, 0x2c, 0xaf, 0xc1, 0x9d, 0x1f, 0x1d, 0xc7, 0x19, 0xc0, 0x26, 0x41, - 0xb0, 0x56, 0x84, 0x47, 0x56, 0x89, 0x33, 0x00, 0x41, 0x76, 0x27, 0x4d, 0xc5, 0x73, 0x2d, 0x31, 0xa6, 0x2f, 0x70, - 0x57, 0x39, 0x3b, 0xd9, 0xe4, 0x66, 0xd1, 0xfb, 0x33, 0xac, 0x3a, 0x52, 0x19, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, - 0x06, 0x4d, 0x11, 0x52, 0x3e, 0x64, 0x4f, 0xda, 0xbf, 0x02, 0x1a, 0x9c, 0x67, 0xe9, 0x9d, 0xb1, 0xca, 0xdf, 0x28, - 0x21, 0x4e, 0x14, 0x53, 0x2b, 0xbe, 0x89, 0x12, 0x75, 0x7e, 0x26, 0xda, 0x0d, 0x04, 0x52, 0x7f, 0xc0, 0xa0, 0x1a, - 0x65, 0x98, 0xc0, 0x75, 0x20, 0x8a, 0xcd, 0x89, 0xea, 0x2d, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x01, 0x50, 0xef, 0xd8, - 0xfa, 0x08, 0x68, 0x96, 0xbe, 0x69, 0xad, 0x73, 0x4d, 0x28, 0xb4, 0x13, 0x98, 0x64, 0x90, 0xe4, 0x59, 0x67, 0x98, - 0xa0, 0xda, 0x8c, 0x49, 0xe7, 0x7d, 0x80, 0xee, 0xae, 0x45, 0x5d, 0x7c, 0xd3, 0xb9, 0x83, 0xf6, 0x71, 0xfd, 0x4a, - 0x8b, 0xec, 0xf1, 0xe7, 0x2d, 0x11, 0x16, 0x81, 0xb3, 0x56, 0xe7, 0xab, 0x47, 0x38, 0x30, 0x15, 0x99, 0x86, 0xbd, - 0x44, 0x2a, 0x59, 0xb6, 0xdb, 0x5e, 0x6f, 0xaf, 0x88, 0xab, 0xc7, 0x58, 0xed, 0xdc, 0xcc, 0xcd, 0x9d, 0x6a, 0x5d, - 0xec, 0xde, 0xb4, 0xdd, 0x14, 0x33, 0x6a, 0xad, 0xdd, 0xae, 0x39, 0x21, 0x4f, 0xbe, 0x15, 0xd5, 0x4a, 0x9d, 0xae, - 0x0d, 0xda, 0x21, 0x9e, 0x75, 0x91, 0xc1, 0x8d, 0xf2, 0xb9, 0x15, 0x3a, 0xc9, 0x38, 0xab, 0x56, 0x5d, 0xb0, 0xb9, - 0xe6, 0xf5, 0x52, 0xa4, 0x51, 0x45, 0xd1, 0xe6, 0x3c, 0x2a, 0x68, 0x22, 0xd6, 0x45, 0x1d, 0x89, 0x06, 0xf5, 0xa2, - 0x46, 0x63, 0x80, 0x80, 0x4c, 0xe7, 0xbe, 0x07, 0x55, 0x30, 0x1b, 0x8a, 0x48, 0x4c, 0xdf, 0x83, 0xa5, 0x7d, 0x01, - 0xfb, 0xa2, 0xd9, 0x57, 0x67, 0x8b, 0x6f, 0x75, 0x84, 0x60, 0x12, 0xb3, 0x07, 0xc2, 0xc0, 0xf9, 0xc6, 0x90, 0xd3, - 0x2e, 0x71, 0x99, 0xef, 0x96, 0xb0, 0x87, 0xdb, 0x15, 0xec, 0xc4, 0xce, 0x93, 0xe2, 0xe6, 0x4a, 0x76, 0x52, 0xce, - 0xc7, 0xa0, 0xfd, 0x12, 0xf2, 0xda, 0xa5, 0xb8, 0xf5, 0x78, 0x10, 0xd0, 0x60, 0x50, 0x6a, 0xfe, 0x75, 0xa2, 0x3d, - 0x3c, 0x69, 0x40, 0x90, 0x94, 0x83, 0x8b, 0xb6, 0x63, 0xf8, 0x3e, 0x99, 0x8a, 0x63, 0x8e, 0x16, 0xef, 0xd0, 0xea, - 0x04, 0xa2, 0x78, 0x81, 0xbd, 0x9b, 0x56, 0x15, 0x6a, 0x11, 0x94, 0xa3, 0xe5, 0x2f, 0x64, 0x75, 0x08, 0x28, 0xa4, - 0x7c, 0x45, 0xa1, 0x6c, 0x9d, 0x18, 0xea, 0xe1, 0x17, 0xf3, 0xc9, 0x42, 0xcd, 0xc0, 0x40, 0xcc, 0x8f, 0x16, 0x6a, - 0x16, 0x06, 0x62, 0xfe, 0xd5, 0xa2, 0xb1, 0xeb, 0x40, 0x11, 0x10, 0xc7, 0x85, 0xa3, 0x93, 0xd2, 0xca, 0x6c, 0x01, - 0xdd, 0x3c, 0x44, 0xd0, 0xff, 0x6e, 0x0e, 0x41, 0x2b, 0x17, 0xda, 0x91, 0x1b, 0xd0, 0x76, 0x1c, 0x02, 0x73, 0xc5, - 0xa4, 0x95, 0x0e, 0x40, 0x74, 0xcc, 0xc6, 0x60, 0x88, 0x2d, 0x3f, 0x38, 0x66, 0xe3, 0xa9, 0x4b, 0x82, 0x80, 0xd1, - 0xfd, 0x41, 0x43, 0x82, 0xdf, 0xe1, 0x55, 0xfa, 0x64, 0x83, 0xbe, 0x66, 0xce, 0xdd, 0xd0, 0xb9, 0xb8, 0x82, 0x53, - 0xb5, 0xbd, 0x27, 0xa1, 0x9b, 0x4c, 0x3b, 0x40, 0xaf, 0x26, 0x6e, 0xc8, 0xaf, 0x8c, 0x46, 0xa3, 0x62, 0x64, 0x00, - 0x20, 0x88, 0xe6, 0x1c, 0xfc, 0x9c, 0x86, 0xcb, 0x97, 0xb7, 0x9e, 0x4d, 0x31, 0x02, 0x5a, 0xc8, 0x44, 0xf3, 0x00, - 0x65, 0x55, 0x63, 0x68, 0x86, 0xde, 0x21, 0xc7, 0x0f, 0x0f, 0xbe, 0xce, 0xf8, 0x89, 0xc3, 0xb5, 0x87, 0x73, 0xe1, - 0xba, 0xac, 0x69, 0x99, 0x43, 0xe7, 0xd9, 0xc7, 0xf1, 0x1e, 0xc6, 0xc9, 0xa7, 0x59, 0x28, 0x67, 0xbc, 0xa6, 0xff, - 0x51, 0xe9, 0x7e, 0x87, 0x43, 0x4e, 0x57, 0xb0, 0xe2, 0x66, 0x75, 0xa8, 0xf9, 0x59, 0xe4, 0x8d, 0x23, 0xde, 0x90, - 0xa8, 0xee, 0x3e, 0xef, 0x4d, 0x98, 0xd2, 0x8e, 0x71, 0x00, 0x70, 0xa2, 0x56, 0x0d, 0xbb, 0xd2, 0xb8, 0x56, 0x07, - 0x31, 0x0c, 0x25, 0x6c, 0x95, 0x38, 0xaa, 0xa4, 0xbf, 0x01, 0x08, 0x8b, 0xa1, 0x38, 0xde, 0x1a, 0xd6, 0x07, 0xd8, - 0x0f, 0x55, 0xa0, 0x6e, 0x4e, 0x21, 0x67, 0x00, 0x90, 0x04, 0xdc, 0xd1, 0x53, 0x4d, 0x43, 0x65, 0x9b, 0xe3, 0xa1, - 0x65, 0x74, 0x05, 0x0f, 0xf4, 0xd4, 0x96, 0x0c, 0x8c, 0xab, 0x3c, 0xf6, 0x36, 0xfb, 0xdb, 0xa3, 0x54, 0xe4, 0x3b, - 0x9b, 0xd4, 0x34, 0xab, 0x46, 0x63, 0x1f, 0x47, 0xe8, 0x69, 0x05, 0x68, 0xbd, 0xb6, 0x54, 0xb4, 0xdf, 0x47, 0x31, - 0x6a, 0x5c, 0x4a, 0xb0, 0x0a, 0x1d, 0x09, 0x0e, 0x11, 0x46, 0x08, 0xfd, 0xbe, 0x08, 0x37, 0xae, 0x20, 0x83, 0x28, - 0xb8, 0x16, 0x15, 0x7f, 0xc8, 0xf2, 0xa2, 0x6d, 0xa9, 0xaa, 0x3e, 0x69, 0xda, 0x12, 0x78, 0x1d, 0x0e, 0xb0, 0x9d, - 0x7f, 0xea, 0x89, 0x5c, 0x2b, 0x1b, 0x25, 0x7c, 0x47, 0x5c, 0x0b, 0xa2, 0x9b, 0x46, 0xd7, 0xeb, 0xd9, 0x21, 0x5a, - 0x9a, 0xe2, 0xd0, 0x21, 0xfb, 0xdc, 0x3d, 0xb7, 0x65, 0x7c, 0xfb, 0x09, 0x72, 0xe7, 0x3b, 0x7b, 0x49, 0xc2, 0x20, - 0x6f, 0xd9, 0x40, 0xb1, 0x8e, 0xad, 0xa0, 0x00, 0xa3, 0xb6, 0xfc, 0x05, 0x74, 0x6c, 0x30, 0xa8, 0x09, 0x3e, 0x49, - 0x6c, 0x1b, 0x8f, 0xfc, 0x11, 0xe7, 0x86, 0x0e, 0xaf, 0x0d, 0x79, 0x20, 0x4e, 0x61, 0x9f, 0x28, 0x61, 0xff, 0x82, - 0x82, 0xee, 0x48, 0x2f, 0x57, 0x89, 0xab, 0xe2, 0x01, 0xaa, 0xec, 0x78, 0xae, 0xf9, 0x92, 0x16, 0x5a, 0x69, 0x64, - 0x15, 0x1d, 0x11, 0xb7, 0x60, 0x32, 0x66, 0xab, 0x6a, 0x54, 0x71, 0x2c, 0x50, 0xa4, 0x63, 0xce, 0x76, 0x0e, 0xd6, - 0x00, 0x78, 0x0a, 0x9b, 0x8b, 0x33, 0x2c, 0x28, 0xed, 0xb2, 0xa5, 0x2f, 0x81, 0x55, 0xf3, 0x30, 0xce, 0xcb, 0x8e, - 0x2f, 0x77, 0x47, 0xdb, 0x7b, 0xe8, 0x8d, 0xe8, 0x8d, 0xd7, 0xe7, 0x51, 0xd3, 0xcf, 0x9e, 0xe1, 0xda, 0x50, 0x90, - 0x07, 0x9a, 0xea, 0x10, 0x46, 0x8b, 0xc0, 0x34, 0xe5, 0x27, 0x6c, 0x3c, 0x1d, 0x0e, 0x35, 0x19, 0x74, 0x9a, 0x89, - 0xf1, 0xbf, 0x3e, 0x83, 0xd6, 0xe9, 0x89, 0xf3, 0x3e, 0x6d, 0x5f, 0x41, 0xeb, 0x3b, 0x94, 0xc9, 0x9d, 0x83, 0xe1, - 0x03, 0x2d, 0x98, 0x84, 0xa9, 0xc2, 0x1b, 0x22, 0x15, 0xec, 0xcd, 0xd2, 0x38, 0xec, 0x9b, 0x85, 0x42, 0x4b, 0x45, - 0xfc, 0x6a, 0x4d, 0xfc, 0xe4, 0x75, 0xe6, 0xdf, 0xa6, 0x7d, 0x72, 0x10, 0x4b, 0x43, 0x62, 0x24, 0xe2, 0x17, 0xa7, - 0xd2, 0x76, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x64, 0xec, 0x49, 0x8d, 0xa7, 0x86, 0xfb, 0x5e, 0xc7, - 0xac, 0xc3, 0x2c, 0x76, 0xb3, 0x46, 0x42, 0x61, 0x9c, 0x9a, 0xe0, 0x94, 0x62, 0x15, 0xc9, 0xe8, 0x78, 0xa6, 0x30, - 0x88, 0x2a, 0x29, 0x21, 0xd6, 0x94, 0xad, 0x85, 0x89, 0x5d, 0x67, 0x0b, 0x53, 0xd4, 0x45, 0xa8, 0x37, 0x03, 0x9d, - 0x05, 0x0d, 0xf9, 0x1d, 0x1a, 0xad, 0xa8, 0x9a, 0x04, 0x0c, 0xe3, 0x28, 0xd5, 0xf8, 0xb7, 0x08, 0xb5, 0x1e, 0x06, - 0x00, 0xb6, 0x79, 0x27, 0xb2, 0xa2, 0x7e, 0x55, 0x20, 0x04, 0x9a, 0xb5, 0x9f, 0x2a, 0xeb, 0x9d, 0x59, 0xd0, 0x8a, - 0x76, 0x73, 0xe5, 0x73, 0x81, 0x13, 0xaa, 0x53, 0x79, 0x81, 0x7a, 0x29, 0xca, 0xd7, 0x22, 0xe5, 0xad, 0xb8, 0x98, - 0x07, 0x82, 0x7d, 0xc8, 0x47, 0x70, 0x5e, 0xa1, 0x53, 0xb9, 0xde, 0x26, 0xd2, 0x2c, 0x49, 0x30, 0x16, 0x68, 0x9b, - 0x97, 0x60, 0x26, 0x14, 0x33, 0x86, 0x5f, 0x43, 0x70, 0xb1, 0x9d, 0x93, 0x70, 0xb3, 0x9f, 0x07, 0x86, 0xd0, 0xe4, - 0x55, 0x4b, 0x34, 0x6c, 0xec, 0x78, 0x1d, 0xb9, 0x26, 0xdc, 0x87, 0xb5, 0x58, 0x93, 0x31, 0xc6, 0x95, 0xb9, 0x91, - 0xf1, 0xa3, 0x05, 0x1e, 0x8c, 0x49, 0xeb, 0x4f, 0x20, 0xd3, 0x52, 0xca, 0x3a, 0x5f, 0x68, 0x31, 0x93, 0x4c, 0x74, - 0x6e, 0xdf, 0xf8, 0x2c, 0xef, 0x22, 0xf2, 0xb7, 0xf2, 0x7b, 0x92, 0x0f, 0xf7, 0xee, 0x83, 0xc4, 0x1a, 0x94, 0x46, - 0x5c, 0x5a, 0x94, 0xa7, 0x0f, 0x74, 0xdd, 0xa4, 0x88, 0xd3, 0xf3, 0x55, 0x5c, 0x56, 0x3c, 0x85, 0x4a, 0x15, 0x75, - 0x8b, 0x7a, 0x13, 0xb0, 0x37, 0x44, 0x92, 0x64, 0x2c, 0x8d, 0x8d, 0xd8, 0xc5, 0x23, 0x3d, 0x7b, 0xc3, 0x2c, 0xbd, - 0xac, 0xd1, 0x90, 0x96, 0x3a, 0x67, 0xa1, 0x94, 0xf9, 0x4b, 0xfe, 0x33, 0x68, 0x24, 0xe8, 0xa8, 0x4f, 0x31, 0x9e, - 0x01, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x08, 0x4a, 0xb3, 0x23, 0x76, 0xfc, 0xd4, 0xe4, 0xe1, 0x5d, - 0xc8, 0x3a, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0xa8, 0x1a, 0xc9, 0x19, 0x40, 0xd3, 0x41, 0x91, 0xf3, 0xb8, - 0x08, 0x66, 0x3d, 0x9d, 0x18, 0xf5, 0xb8, 0xfa, 0x05, 0x1a, 0x6a, 0xb7, 0x59, 0x59, 0x9e, 0xd5, 0xf7, 0x9f, 0xc3, - 0x81, 0x4d, 0x4d, 0x05, 0x3d, 0xde, 0xd4, 0xe2, 0xea, 0x4a, 0x76, 0xdb, 0x2d, 0x44, 0xcb, 0xe9, 0xbc, 0x6b, 0xe9, - 0xbc, 0x5e, 0xb0, 0x5e, 0x77, 0xba, 0x5e, 0xdc, 0x7e, 0x19, 0x1e, 0xc2, 0xda, 0xce, 0x27, 0x8a, 0x3f, 0xf3, 0xdb, - 0xee, 0xe2, 0x2d, 0x54, 0xb3, 0x00, 0x00, 0xd2, 0x83, 0x28, 0x58, 0x66, 0x29, 0x0f, 0xa8, 0xd8, 0xc7, 0x51, 0x96, - 0x52, 0x2f, 0x67, 0x18, 0x3f, 0x65, 0x1a, 0x6b, 0x9c, 0x15, 0xaa, 0xd0, 0xd8, 0xe8, 0x4e, 0x57, 0x19, 0x62, 0xfb, - 0x09, 0x9c, 0x2d, 0xc0, 0xfd, 0xd1, 0x43, 0xa1, 0xee, 0x4d, 0x5a, 0x9a, 0xa8, 0xf9, 0xae, 0x3d, 0x83, 0x8c, 0xe2, - 0x64, 0x95, 0x57, 0xd0, 0x8d, 0x3a, 0x6b, 0xa3, 0x4a, 0xdf, 0x43, 0xd4, 0xab, 0x18, 0x3c, 0xca, 0x5d, 0x5e, 0x1b, - 0x9d, 0x4c, 0x8b, 0x48, 0xb9, 0xf3, 0x93, 0x66, 0x99, 0xa5, 0x4a, 0x87, 0xed, 0x32, 0xec, 0xad, 0x31, 0xe9, 0x4d, - 0x48, 0x03, 0x23, 0xf1, 0xe9, 0x8c, 0x0a, 0x21, 0xa0, 0x2d, 0xc7, 0xdf, 0xe1, 0x33, 0x34, 0x4d, 0x81, 0xa5, 0x8a, - 0x5b, 0xd8, 0x0e, 0x9f, 0xff, 0x64, 0xd4, 0x02, 0x10, 0xc1, 0xca, 0xd5, 0xbb, 0x38, 0x25, 0x34, 0xe7, 0xca, 0x0c, - 0x00, 0x59, 0x50, 0xca, 0x2d, 0x3f, 0x25, 0xd3, 0xc1, 0x12, 0x45, 0xd9, 0xcb, 0xa9, 0x1b, 0x1d, 0x1b, 0x3f, 0xa4, - 0xe7, 0x02, 0xb6, 0x0b, 0xf9, 0xad, 0xbd, 0x7a, 0x89, 0x9a, 0x34, 0xa6, 0x59, 0x0f, 0xf0, 0xe5, 0x1a, 0x4d, 0x42, - 0x0b, 0xca, 0xa4, 0x29, 0x80, 0xc6, 0x4d, 0xd5, 0x0a, 0x26, 0xa5, 0x46, 0xc2, 0x96, 0x3a, 0x92, 0x65, 0xdf, 0x07, - 0xa7, 0xde, 0x23, 0xe8, 0x01, 0xf3, 0x08, 0xf4, 0xf4, 0x5f, 0xba, 0x6a, 0xff, 0x92, 0xa3, 0x93, 0xab, 0x26, 0x6a, - 0xfa, 0xbd, 0xb2, 0x23, 0x43, 0xca, 0xa5, 0x19, 0x08, 0x26, 0x1d, 0xf3, 0xd4, 0xd8, 0x3a, 0x46, 0x44, 0x0f, 0x9c, - 0x7d, 0xba, 0x5b, 0x4d, 0x2d, 0x00, 0xd1, 0xf1, 0xeb, 0x27, 0xaf, 0xae, 0xe3, 0x2b, 0x8d, 0xa2, 0xe4, 0x59, 0xc4, - 0x48, 0xd3, 0xbe, 0x5a, 0xc0, 0xe0, 0xfd, 0xf2, 0xfe, 0x27, 0x99, 0xa5, 0x71, 0x7b, 0xb0, 0x31, 0xa2, 0xaa, 0x5f, - 0x2a, 0x5e, 0xfa, 0x02, 0xac, 0x7d, 0x96, 0x28, 0x90, 0xfb, 0xbd, 0x49, 0xd3, 0xdf, 0x44, 0xde, 0xcd, 0x86, 0xf5, - 0xc6, 0x4d, 0xbb, 0xd4, 0x96, 0xec, 0xc8, 0x48, 0xe4, 0xf4, 0x62, 0xd0, 0xe3, 0x47, 0x2b, 0x8d, 0xd2, 0xb0, 0x41, - 0x55, 0x2a, 0x7e, 0xaf, 0x45, 0x70, 0xf2, 0x58, 0x95, 0x18, 0xd3, 0x80, 0xd9, 0x56, 0x36, 0x0a, 0xd4, 0x41, 0x2a, - 0x6d, 0x75, 0x14, 0xb6, 0xdf, 0x58, 0x49, 0xf5, 0xef, 0x7f, 0x6a, 0x43, 0x3e, 0x5f, 0x0a, 0x2a, 0x08, 0xd8, 0x19, - 0x78, 0x3d, 0x95, 0xc2, 0x40, 0x2a, 0xd8, 0x49, 0x05, 0x28, 0x5f, 0x44, 0x8e, 0xd5, 0x6e, 0x5f, 0xad, 0x1a, 0xa3, - 0x2d, 0x20, 0x34, 0x90, 0x1e, 0x5d, 0xf6, 0x71, 0x1b, 0xe3, 0x40, 0xe2, 0xc0, 0x09, 0xb6, 0x73, 0x75, 0x8d, 0x46, - 0x42, 0xf3, 0x87, 0x46, 0x03, 0x5e, 0xd3, 0x1a, 0x14, 0xea, 0x39, 0x8e, 0x86, 0xca, 0x0e, 0x29, 0x88, 0xd8, 0xa0, - 0x84, 0x7d, 0x7b, 0x3e, 0xd4, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x43, 0x85, 0xfd, 0xdc, 0x2e, 0x21, 0x63, 0xd5, 0x21, - 0xad, 0x3c, 0xc0, 0xf1, 0x42, 0xca, 0xfc, 0x2d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x6d, 0xc4, 0x02, 0x96, 0x04, 0xed, - 0xf5, 0x40, 0xdd, 0x32, 0x08, 0x75, 0x4c, 0x4f, 0x04, 0x3e, 0xa5, 0x5c, 0x7e, 0x5a, 0x92, 0x66, 0x5a, 0x32, 0x0b, - 0x7a, 0xe9, 0x5a, 0xf9, 0x15, 0xde, 0x47, 0xbb, 0x7b, 0x57, 0x5f, 0x58, 0xc7, 0x10, 0x0c, 0xbb, 0x72, 0x9b, 0xd3, - 0x50, 0x00, 0x36, 0x3c, 0x55, 0x65, 0xb9, 0x46, 0x4d, 0x64, 0x16, 0x87, 0x24, 0x02, 0xc9, 0xb6, 0xbf, 0xb9, 0xb5, - 0x60, 0xdb, 0x59, 0xa8, 0x9e, 0xfa, 0xcb, 0xd9, 0xee, 0x7b, 0x86, 0x97, 0x3b, 0x72, 0x6f, 0xdf, 0x86, 0xf2, 0x87, - 0xfd, 0xab, 0xe4, 0xff, 0xaa, 0x92, 0xfd, 0x56, 0x99, 0x4d, 0x5b, 0xbc, 0xdf, 0x75, 0xdc, 0x72, 0x8c, 0x06, 0x81, - 0x35, 0x05, 0x1a, 0xd2, 0x93, 0xc6, 0x34, 0x51, 0x21, 0x95, 0x19, 0xd3, 0x78, 0x74, 0x01, 0x9a, 0xc3, 0x74, 0x9e, - 0xc7, 0x00, 0x1c, 0xe0, 0x1e, 0x79, 0x84, 0xba, 0xa7, 0xf3, 0x3c, 0x38, 0x0f, 0x06, 0xc5, 0x20, 0x50, 0x9f, 0xd8, - 0xe6, 0x04, 0x0b, 0xd0, 0xb9, 0xc5, 0x0c, 0x82, 0x4d, 0x1a, 0x33, 0x87, 0xf8, 0x38, 0x99, 0x0e, 0x06, 0x31, 0xd9, - 0x00, 0x48, 0x5f, 0xbc, 0x30, 0xce, 0x41, 0xa5, 0x5a, 0x90, 0xad, 0xba, 0x4b, 0xbf, 0x62, 0xa7, 0xda, 0x69, 0xde, - 0xef, 0xe7, 0xf3, 0x62, 0x10, 0x78, 0x15, 0x96, 0xda, 0xfb, 0x8f, 0xfa, 0x5f, 0x6a, 0x9d, 0x34, 0xc1, 0x30, 0xb5, - 0xa7, 0xa8, 0x5e, 0x71, 0x34, 0xa3, 0xde, 0xed, 0x58, 0x2a, 0x5f, 0x40, 0x14, 0x0f, 0x0c, 0x59, 0x2b, 0xef, 0xce, - 0xc1, 0x6b, 0x73, 0xe3, 0xcd, 0x11, 0x05, 0xd8, 0xbe, 0x30, 0x4e, 0x28, 0x2e, 0xba, 0x6c, 0x88, 0x63, 0xb0, 0xd3, - 0xd5, 0x5b, 0x81, 0x56, 0xe3, 0xbd, 0x78, 0xd7, 0x6c, 0xfc, 0x8d, 0x38, 0x50, 0x65, 0x1e, 0x5c, 0x02, 0xe2, 0xec, - 0x41, 0x5c, 0x1f, 0x60, 0xa9, 0x07, 0xc1, 0xc0, 0x20, 0x87, 0xb4, 0xab, 0x55, 0x43, 0x11, 0xc9, 0xf3, 0x18, 0x0c, - 0x98, 0x74, 0x43, 0x1a, 0x32, 0xed, 0x95, 0x12, 0xd2, 0xc6, 0x58, 0x0b, 0x28, 0xc3, 0xe1, 0x6a, 0xc7, 0x6e, 0xd8, - 0x9e, 0x6e, 0x1d, 0x0a, 0x25, 0x8c, 0x5e, 0xdd, 0xf8, 0x87, 0x9a, 0xe7, 0x89, 0xa0, 0x06, 0x55, 0x6b, 0x3f, 0x1d, - 0x94, 0x27, 0xe5, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0xa2, 0xc0, 0x8b, 0xf6, 0x0e, 0xf2, 0x9c, 0xfe, 0x54, 0xfa, - 0x20, 0x7a, 0x6e, 0x19, 0x2e, 0xb4, 0x8f, 0x6b, 0x05, 0x32, 0x69, 0x3a, 0x9a, 0xda, 0xda, 0x1d, 0xde, 0x31, 0x81, - 0x7e, 0x53, 0x96, 0x52, 0x26, 0xba, 0x96, 0x25, 0x3b, 0xe9, 0xe5, 0xd2, 0x1b, 0x2a, 0x65, 0x27, 0xcb, 0x36, 0xe7, - 0x97, 0x7a, 0x09, 0xfd, 0xbe, 0x72, 0x07, 0xc2, 0x37, 0x72, 0xbd, 0x21, 0x2f, 0x1b, 0x22, 0x96, 0x43, 0xcc, 0xc0, - 0xf1, 0x42, 0x48, 0xd7, 0xee, 0xd2, 0x57, 0xd5, 0xed, 0x6c, 0xe5, 0x92, 0x16, 0x78, 0x2b, 0x05, 0x56, 0x91, 0x5a, - 0xbd, 0x9e, 0x4c, 0xdc, 0xf7, 0x51, 0x6c, 0x3e, 0x02, 0xb6, 0xd1, 0x3b, 0x1a, 0xbd, 0x5b, 0xc4, 0x06, 0x5f, 0x45, - 0x35, 0x2d, 0x39, 0x40, 0x70, 0xb7, 0x25, 0xb5, 0x34, 0xb3, 0x88, 0xfb, 0x92, 0x07, 0x68, 0xdf, 0xc5, 0xe1, 0x4c, - 0x2a, 0xc1, 0xb6, 0xae, 0x75, 0xce, 0x2a, 0x39, 0xa0, 0x9f, 0xe8, 0xf8, 0xa7, 0xd5, 0xa3, 0x22, 0x86, 0x55, 0x36, - 0x92, 0x56, 0x68, 0x0f, 0x4a, 0x97, 0x70, 0xf1, 0x05, 0x78, 0xd9, 0xde, 0xaf, 0xec, 0x3e, 0x5f, 0x62, 0xff, 0x30, - 0xaf, 0x9c, 0xe0, 0x91, 0xd3, 0x78, 0x73, 0x0f, 0xab, 0x3e, 0x57, 0x0a, 0xe1, 0x54, 0x4a, 0x43, 0x01, 0xc0, 0x20, - 0x09, 0x6a, 0xb8, 0xd2, 0xb6, 0x19, 0xa4, 0x34, 0x86, 0xdd, 0xad, 0xde, 0xe8, 0xff, 0x94, 0x0a, 0x17, 0xa0, 0x94, - 0x0d, 0xdc, 0x90, 0x75, 0xaa, 0xe5, 0x3a, 0xa6, 0xe0, 0xf9, 0x2e, 0x39, 0x02, 0x85, 0x1d, 0x18, 0x99, 0xd1, 0x84, - 0xfd, 0x82, 0xb7, 0xa1, 0x9c, 0xbd, 0x34, 0x92, 0x27, 0xbb, 0x2f, 0x69, 0x45, 0x13, 0x32, 0xad, 0xcc, 0xfe, 0x6d, - 0x6d, 0xd8, 0xe7, 0xa1, 0x18, 0x89, 0x02, 0x17, 0x07, 0x9d, 0x03, 0xd8, 0x1f, 0xe4, 0xd2, 0x36, 0x9f, 0x49, 0xbf, - 0x2f, 0xdf, 0x3f, 0xcb, 0xb3, 0xe4, 0xe3, 0xce, 0x7b, 0xcd, 0xd3, 0x2c, 0x19, 0x50, 0x89, 0x98, 0x1a, 0x57, 0xc5, - 0x70, 0xa9, 0x5c, 0x8c, 0x3d, 0x92, 0x11, 0xef, 0xa5, 0x0e, 0x31, 0x62, 0x7c, 0x91, 0x1d, 0x92, 0x92, 0xd3, 0x65, - 0xd3, 0xd9, 0x73, 0x25, 0x9a, 0x41, 0x63, 0xb8, 0x1d, 0xef, 0x25, 0xb5, 0x02, 0x64, 0x54, 0xe8, 0x9e, 0x01, 0xae, - 0xe1, 0xfe, 0x92, 0xf0, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xd8, 0x2b, 0x13, 0x12, 0x72, 0xe3, 0x00, 0x8b, 0xd8, 0x34, - 0x1f, 0x43, 0x01, 0x40, 0xad, 0x1a, 0xe9, 0x95, 0xbe, 0x24, 0x54, 0x26, 0x21, 0x18, 0x5d, 0x91, 0xf0, 0x2a, 0xa0, - 0x71, 0xa6, 0x13, 0x0d, 0x6c, 0x70, 0x40, 0x9f, 0xd7, 0x3a, 0x51, 0xdb, 0x90, 0x07, 0xb4, 0x36, 0x69, 0x00, 0x83, - 0x0f, 0x92, 0x24, 0xfa, 0x6a, 0xa9, 0x93, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x73, 0xe1, 0xf8, 0x58, 0x82, 0xff, - 0x91, 0x26, 0x82, 0x3f, 0x84, 0x02, 0x64, 0x8a, 0xaa, 0x62, 0x9a, 0xb1, 0x93, 0xac, 0xdb, 0x98, 0xc4, 0xf1, 0xb4, - 0xbb, 0x2b, 0xa5, 0x4b, 0x17, 0xf8, 0x95, 0x65, 0x88, 0x63, 0xfd, 0x2c, 0x5e, 0xb1, 0xd3, 0x90, 0x2b, 0xbc, 0xf4, - 0x67, 0xf1, 0x0a, 0x67, 0x88, 0xd6, 0xad, 0x04, 0x22, 0xfd, 0x57, 0x4d, 0xe0, 0x10, 0xfb, 0x09, 0x06, 0xb9, 0xa8, - 0x9d, 0x07, 0x02, 0x79, 0x5b, 0x41, 0x44, 0xfc, 0xec, 0x2a, 0x8c, 0x48, 0xbd, 0x93, 0xa4, 0xbf, 0xfc, 0x51, 0x64, - 0x85, 0xf3, 0x0d, 0x3c, 0xfa, 0xcd, 0x32, 0x29, 0xfa, 0x0b, 0x19, 0xcc, 0xc1, 0x7e, 0x22, 0xe3, 0x52, 0xd4, 0xee, - 0x13, 0x76, 0xc1, 0x89, 0xf1, 0xe0, 0xf4, 0x1a, 0x01, 0xf6, 0x6b, 0xf7, 0xc9, 0x19, 0xb3, 0xbf, 0x8c, 0x1b, 0x5f, - 0xa6, 0x23, 0x3e, 0xf0, 0xd1, 0x1d, 0xe5, 0xa3, 0x7b, 0x27, 0xd3, 0x1f, 0x1e, 0x94, 0xc8, 0xa8, 0xaa, 0xf9, 0x6a, - 0xc5, 0xd3, 0xd9, 0x5d, 0x12, 0x65, 0xa3, 0x9a, 0x17, 0x30, 0xbd, 0xe0, 0x78, 0x97, 0xac, 0x2f, 0xb2, 0xe4, 0x15, - 0xc4, 0x1e, 0x58, 0x09, 0x89, 0xc5, 0x0f, 0xcb, 0x4c, 0x2e, 0xe6, 0x42, 0xd4, 0xa2, 0xe0, 0xc1, 0xec, 0x26, 0x89, - 0xfe, 0x5a, 0x3a, 0x48, 0x6a, 0x7a, 0xca, 0x36, 0x8d, 0x25, 0xd4, 0xda, 0xd7, 0x91, 0x6e, 0x94, 0x05, 0x00, 0xdc, - 0xb3, 0x8b, 0x34, 0x12, 0xac, 0x1a, 0x4e, 0x1a, 0xc6, 0x75, 0x7a, 0x89, 0xa9, 0x71, 0xc3, 0x6a, 0x9a, 0x58, 0x0b, - 0x19, 0xd0, 0xfb, 0x03, 0x5e, 0x0e, 0x3e, 0x67, 0x45, 0x28, 0xa4, 0x35, 0x70, 0x71, 0x5c, 0xf6, 0xfb, 0xe2, 0xb8, - 0xdc, 0x6e, 0x8b, 0x93, 0xb8, 0xdf, 0x17, 0x27, 0xb1, 0xe6, 0x1f, 0xa4, 0x62, 0x5b, 0x9b, 0x1b, 0x24, 0x34, 0x17, - 0x10, 0xb5, 0x68, 0x04, 0x7f, 0x68, 0x96, 0xf3, 0x22, 0xca, 0x8f, 0x93, 0x7e, 0xbf, 0xb7, 0x9c, 0x55, 0x83, 0x7c, - 0x98, 0x44, 0xf9, 0x30, 0x71, 0x9c, 0x10, 0x7f, 0x75, 0x9c, 0x10, 0x25, 0x0d, 0x5c, 0xc1, 0x99, 0x01, 0x88, 0x02, - 0x2e, 0xfd, 0xa3, 0xaa, 0x96, 0x52, 0xd5, 0x12, 0xcb, 0x5a, 0x12, 0x55, 0x41, 0xc3, 0x6e, 0xca, 0xb0, 0xc0, 0x52, - 0xe8, 0x92, 0xfd, 0xb1, 0x04, 0x9e, 0x28, 0xe7, 0xf5, 0x06, 0x18, 0xd8, 0x08, 0xef, 0x1c, 0x3a, 0x9c, 0xc4, 0xba, - 0x61, 0x12, 0x32, 0xe9, 0x92, 0xae, 0xe8, 0x15, 0xf2, 0xb3, 0x97, 0x60, 0xb0, 0x74, 0xcc, 0xf2, 0xe9, 0x60, 0x70, - 0x49, 0x56, 0xac, 0x98, 0x87, 0xf1, 0x20, 0x5c, 0xcf, 0xf2, 0xe1, 0x65, 0x74, 0x49, 0xc8, 0x17, 0xe5, 0x82, 0xf6, - 0x56, 0xa3, 0xea, 0x63, 0x06, 0xc1, 0xfd, 0xd2, 0x59, 0x98, 0xe9, 0x38, 0x1f, 0xab, 0xd1, 0x1d, 0x5d, 0x41, 0xfc, - 0x1a, 0xb8, 0x91, 0x90, 0x08, 0x3a, 0x72, 0x45, 0x57, 0x74, 0x4d, 0x85, 0x9e, 0x61, 0x0c, 0xd1, 0x6d, 0x8e, 0x93, - 0x04, 0x1c, 0x93, 0x6d, 0xf1, 0xd1, 0x58, 0x16, 0xde, 0xf5, 0x1d, 0xa1, 0xbd, 0x5e, 0x62, 0x07, 0xe9, 0xbb, 0xf6, - 0x20, 0x01, 0x23, 0x32, 0x92, 0x03, 0xa5, 0x47, 0x46, 0x50, 0x3d, 0xa9, 0x38, 0x24, 0xb1, 0x3b, 0x24, 0x72, 0x1c, - 0x12, 0x77, 0x1c, 0x72, 0x35, 0x0e, 0xc8, 0xdd, 0x2f, 0xd9, 0x98, 0xa6, 0x6c, 0x4c, 0xd7, 0x72, 0x54, 0xe8, 0x35, - 0xbd, 0x50, 0xd4, 0xf1, 0x9c, 0xbd, 0x86, 0x03, 0x7b, 0x10, 0xe6, 0xb3, 0x78, 0xf8, 0x3a, 0x7a, 0x4d, 0xc8, 0x17, - 0x82, 0xde, 0xc8, 0x4b, 0x19, 0x84, 0x41, 0xbc, 0x06, 0xe7, 0x52, 0x1b, 0xea, 0xe4, 0x5a, 0xef, 0x38, 0x7c, 0xba, - 0xf2, 0x9e, 0x2e, 0x20, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x25, 0x2b, 0xe6, 0xe7, 0xe1, 0x98, 0x00, 0x0e, - 0x8f, 0x1a, 0xce, 0xcb, 0xd1, 0x1d, 0xbd, 0x1c, 0xdd, 0x13, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0xc7, 0x2c, 0x9e, 0x0e, - 0x06, 0x6b, 0xa4, 0xea, 0x32, 0xf7, 0x9a, 0x2c, 0xe8, 0x25, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x2b, 0xd6, 0x9a, 0x86, - 0xbf, 0x66, 0xf0, 0xf1, 0x3d, 0xbb, 0x1c, 0xdd, 0xd3, 0x3b, 0xf6, 0x7a, 0x3b, 0x9e, 0x02, 0x33, 0xb5, 0x9a, 0x85, - 0xf7, 0xc7, 0x57, 0xb3, 0x2b, 0x76, 0x1f, 0xdd, 0x9f, 0x40, 0x43, 0xaf, 0xd9, 0x3d, 0x02, 0x2e, 0xa5, 0x8f, 0x97, - 0x83, 0xd7, 0xe4, 0x70, 0x30, 0x48, 0x49, 0x14, 0xde, 0x84, 0x4e, 0x2b, 0x5f, 0xd3, 0x7b, 0x42, 0x57, 0xec, 0x0e, - 0x47, 0xe3, 0x8a, 0xe1, 0x07, 0x17, 0xec, 0xbe, 0xb9, 0x09, 0x9d, 0xdd, 0x1c, 0x57, 0x9d, 0x20, 0x46, 0xe8, 0x6b, - 0x60, 0x69, 0x96, 0x0d, 0x33, 0x01, 0x4f, 0xfa, 0x22, 0xa3, 0x44, 0xa1, 0x19, 0x88, 0xb3, 0x12, 0x10, 0x4b, 0xa2, - 0xee, 0x37, 0x1b, 0x9d, 0xc3, 0x72, 0xee, 0xf7, 0x7b, 0xb5, 0xa6, 0x07, 0x88, 0x9c, 0xd9, 0x49, 0x0f, 0x7a, 0x2e, - 0x3d, 0xc0, 0x4f, 0xd4, 0xaa, 0x41, 0x9c, 0xcc, 0xef, 0x96, 0xd1, 0xaf, 0x0e, 0x7d, 0xf8, 0xa1, 0x9b, 0xf2, 0x54, - 0xf9, 0xbf, 0x4f, 0x79, 0x8a, 0x3c, 0x7a, 0x5d, 0x3b, 0x20, 0x78, 0xce, 0x9a, 0x94, 0x1a, 0x89, 0x7a, 0x74, 0xbe, - 0x8a, 0x41, 0x1b, 0x89, 0xda, 0x06, 0xf5, 0x84, 0x16, 0x56, 0x10, 0x21, 0xe7, 0xe8, 0x39, 0x18, 0xa4, 0x42, 0xa8, - 0x1c, 0xb9, 0x28, 0xd1, 0x10, 0x24, 0x17, 0x15, 0x97, 0xe1, 0x73, 0x08, 0x95, 0xa7, 0x8f, 0x35, 0x11, 0xd6, 0xf4, - 0x18, 0x0c, 0xb0, 0x2d, 0xfc, 0xdb, 0x0e, 0xb9, 0xa8, 0xf8, 0x15, 0x9e, 0xcd, 0x6d, 0x82, 0x51, 0xb2, 0xb8, 0x15, - 0xda, 0x06, 0xb1, 0x1f, 0x0b, 0x82, 0xf5, 0x08, 0x1a, 0x8f, 0x2a, 0x7d, 0x44, 0xb8, 0x51, 0x7c, 0x24, 0x3d, 0x8d, - 0x35, 0x89, 0xe4, 0x48, 0x22, 0xf9, 0x00, 0x08, 0x27, 0x41, 0x7f, 0x71, 0xdb, 0x64, 0xdb, 0x42, 0xa2, 0xd1, 0x9f, - 0x96, 0x4c, 0xc9, 0xee, 0x65, 0x8f, 0x5d, 0x45, 0x90, 0x3d, 0xa6, 0xff, 0x74, 0xfa, 0xf0, 0xcf, 0x25, 0xce, 0xa0, - 0xf1, 0x7c, 0x91, 0x9d, 0x99, 0x39, 0x83, 0x1b, 0x39, 0x5d, 0x56, 0xae, 0xcb, 0x97, 0xfc, 0x80, 0xdf, 0xd5, 0xbc, - 0x48, 0xab, 0x83, 0x9f, 0xeb, 0x36, 0x9e, 0x53, 0xb5, 0x5e, 0xd9, 0x38, 0x2b, 0xd2, 0x38, 0xd5, 0x91, 0xba, 0x68, - 0x6b, 0x58, 0xcf, 0xef, 0x11, 0x75, 0x25, 0x2d, 0x47, 0x4f, 0x21, 0x56, 0x7e, 0xca, 0xe5, 0x3a, 0xcf, 0x7f, 0xda, - 0x49, 0xc5, 0x29, 0xf6, 0x53, 0x90, 0x2a, 0xb5, 0x5c, 0x40, 0xd5, 0x1c, 0xb5, 0xdc, 0x2d, 0xf5, 0x0e, 0xb0, 0x6e, - 0x9b, 0xf2, 0x63, 0x69, 0x76, 0xe1, 0x24, 0x7b, 0xf7, 0x27, 0x5d, 0x86, 0x01, 0xa3, 0x50, 0x66, 0xd5, 0xb5, 0xb2, - 0x2f, 0x34, 0x4e, 0xc3, 0x70, 0xe5, 0xc7, 0x0b, 0x48, 0x17, 0x30, 0x8e, 0x13, 0x25, 0x13, 0xe3, 0xf6, 0xa8, 0xad, - 0x50, 0x7d, 0xce, 0x56, 0x20, 0x60, 0xae, 0xe1, 0xec, 0xba, 0x8e, 0xb6, 0x3b, 0xe2, 0x94, 0x51, 0xb5, 0x8a, 0x8b, - 0xef, 0xe3, 0x55, 0x35, 0xb3, 0x43, 0x1b, 0xf9, 0x63, 0x3a, 0xfd, 0x7b, 0x12, 0xba, 0x85, 0x50, 0xb8, 0xe5, 0x16, - 0x46, 0x9e, 0xdc, 0x1e, 0x96, 0x71, 0x83, 0x5e, 0x89, 0x2b, 0xd5, 0x37, 0x2d, 0x85, 0x54, 0x23, 0x5f, 0xfb, 0x02, - 0x7a, 0x3d, 0xf6, 0x7e, 0x2a, 0xcc, 0xdb, 0x9e, 0x31, 0x97, 0x08, 0x56, 0xb2, 0xec, 0xf6, 0x9d, 0x1a, 0x53, 0x31, - 0x83, 0x2e, 0xb6, 0x9d, 0x45, 0xa7, 0x1b, 0xf9, 0xa7, 0x99, 0xfb, 0x65, 0xde, 0xe1, 0xae, 0xa8, 0xde, 0x02, 0x17, - 0x9a, 0x95, 0x55, 0xdd, 0x96, 0x0d, 0x9b, 0xc6, 0x6b, 0x59, 0x28, 0x36, 0xc0, 0xb0, 0xe7, 0xae, 0x85, 0x07, 0x88, - 0x9b, 0x70, 0xcf, 0x2e, 0x1a, 0xb8, 0x31, 0x7c, 0x5e, 0x49, 0xae, 0x2b, 0x8d, 0xbe, 0xf4, 0xc9, 0xd2, 0xaa, 0xe1, - 0x64, 0x31, 0xe2, 0x45, 0xba, 0x68, 0x32, 0xb3, 0x16, 0x3e, 0xe1, 0x65, 0x38, 0xe7, 0x0b, 0xad, 0x9b, 0x52, 0xa5, - 0x97, 0x2c, 0x56, 0x9d, 0xde, 0xac, 0x14, 0x56, 0x4a, 0xc4, 0x8d, 0x59, 0x26, 0x50, 0x96, 0xa2, 0x91, 0xc2, 0x9b, - 0xb2, 0x65, 0x2b, 0xa9, 0xe5, 0x3d, 0x73, 0x70, 0x1f, 0xfb, 0x01, 0x31, 0x91, 0x75, 0x60, 0x52, 0x34, 0x74, 0x40, - 0xbb, 0xea, 0xd2, 0x35, 0xa3, 0x1e, 0x0c, 0x72, 0x43, 0x12, 0xb1, 0x82, 0x14, 0x2b, 0x58, 0x37, 0xac, 0x9c, 0xe7, - 0x0b, 0x7a, 0xc9, 0xc4, 0x3c, 0x5d, 0xd0, 0x15, 0x13, 0xf3, 0x35, 0xde, 0x84, 0x2e, 0xe1, 0x84, 0x24, 0x9b, 0x58, - 0x2a, 0x60, 0x2f, 0xf1, 0xf2, 0x86, 0x67, 0xaa, 0xa2, 0x65, 0x57, 0x92, 0x03, 0x8c, 0x2f, 0xaa, 0x30, 0x2c, 0x86, - 0x97, 0x60, 0x2d, 0x71, 0x18, 0xae, 0xe6, 0x7c, 0x21, 0x7f, 0x43, 0xc0, 0xf9, 0x24, 0x94, 0xec, 0x82, 0xd9, 0x0b, - 0x64, 0x7a, 0x3d, 0xe7, 0x0b, 0x39, 0x12, 0xaa, 0xe0, 0x6b, 0x63, 0x6c, 0x12, 0x3b, 0x82, 0x96, 0x59, 0x3c, 0x1f, - 0x2f, 0xa2, 0xb8, 0x81, 0x65, 0x78, 0x26, 0x67, 0xa6, 0x25, 0xff, 0xd1, 0x76, 0x52, 0xea, 0x06, 0x2b, 0xc9, 0x1f, - 0x1e, 0x1f, 0x5d, 0x02, 0x19, 0x33, 0xbb, 0x82, 0xe9, 0x0f, 0x5d, 0x1f, 0x19, 0xdc, 0x73, 0x53, 0xce, 0xb8, 0x0c, - 0x12, 0xa5, 0x05, 0x0e, 0x72, 0x96, 0xb4, 0xb5, 0x08, 0xdf, 0x3d, 0x2a, 0xca, 0x3e, 0x13, 0xba, 0x01, 0xdd, 0x47, - 0x82, 0x3e, 0xd0, 0x7b, 0xa5, 0x0a, 0x97, 0xd5, 0x36, 0x13, 0x70, 0x17, 0x09, 0xf2, 0x5b, 0xa1, 0x53, 0x35, 0x06, - 0x55, 0x34, 0x8b, 0x58, 0xb8, 0xf7, 0x11, 0x37, 0xca, 0xe6, 0x9f, 0xfa, 0x1e, 0x2f, 0x25, 0x0c, 0x6e, 0x48, 0x4d, - 0x9f, 0xcc, 0x9b, 0x2b, 0xf6, 0x1e, 0x3a, 0xea, 0x50, 0x6b, 0xbc, 0xaf, 0x5e, 0x72, 0x0a, 0x31, 0x4a, 0x28, 0x3a, - 0x09, 0x06, 0x70, 0xbb, 0x84, 0x14, 0x7b, 0x83, 0xdd, 0xf8, 0xd7, 0xbc, 0x28, 0xb8, 0x58, 0xd7, 0x75, 0xe0, 0x06, - 0x34, 0x9c, 0x2f, 0x76, 0x43, 0x18, 0x8e, 0x69, 0xeb, 0x1a, 0x06, 0x61, 0xc6, 0x30, 0x12, 0x82, 0xd3, 0xbf, 0xe8, - 0x2b, 0x9a, 0xc4, 0xab, 0xef, 0xf8, 0x5f, 0x19, 0x2f, 0x25, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x74, 0x93, - 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0x58, 0xd3, 0x54, 0xfc, 0x2d, 0x17, 0x1f, 0xfc, 0x54, 0x74, 0x3c, 0x1a, 0x37, - 0xad, 0xce, 0xc8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0xa0, 0x1b, 0xa9, 0xdf, 0xda, 0x87, 0xc0, - 0x29, 0xd3, 0xe0, 0x9d, 0x07, 0x74, 0x73, 0xee, 0x82, 0x27, 0x8f, 0xe9, 0xb9, 0x45, 0x4f, 0xae, 0xd9, 0x49, 0xdd, - 0x43, 0xed, 0xbd, 0x1e, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0xd0, 0x38, 0x57, 0xf7, 0x1f, 0x8b, 0x5d, 0x0e, - 0xdf, 0x72, 0x96, 0x1b, 0xc0, 0x52, 0x11, 0x8d, 0x04, 0x8f, 0x02, 0xd4, 0xa5, 0x2a, 0x84, 0x2d, 0x66, 0x71, 0xa8, - 0xcc, 0x56, 0xad, 0x87, 0x82, 0x1c, 0x17, 0x23, 0x70, 0x08, 0x5d, 0x57, 0x83, 0x62, 0xb4, 0xcc, 0xea, 0xf7, 0xf8, - 0x5b, 0xb1, 0x0e, 0x49, 0xb6, 0x8f, 0x75, 0xe0, 0x86, 0x75, 0x98, 0x7e, 0xd4, 0x48, 0x01, 0x68, 0xb2, 0x11, 0xd8, - 0x04, 0xe0, 0xbd, 0xdd, 0x47, 0x84, 0x5a, 0x99, 0xee, 0x65, 0x2c, 0xe4, 0xf7, 0x5e, 0x12, 0x94, 0xe0, 0x27, 0xd4, - 0x96, 0xa5, 0xe0, 0x9d, 0x47, 0x3a, 0x27, 0x4d, 0x56, 0xbc, 0x07, 0x71, 0x5a, 0xf8, 0xc0, 0xde, 0x82, 0xe0, 0x9c, - 0x25, 0xbd, 0xc7, 0xdb, 0xac, 0x92, 0xda, 0xa8, 0x81, 0x02, 0xf8, 0xdd, 0xe0, 0x1e, 0x41, 0xbe, 0xbc, 0xe1, 0x5a, - 0x89, 0xdb, 0x90, 0x0f, 0x4b, 0x7a, 0x44, 0x06, 0xe6, 0xb9, 0x1a, 0xc6, 0xf4, 0x88, 0x1c, 0x9b, 0x67, 0x61, 0x07, - 0x70, 0x20, 0xd4, 0xa8, 0xd2, 0x23, 0x68, 0xd0, 0x6f, 0xa6, 0x45, 0x86, 0x64, 0xfd, 0xa8, 0x1b, 0x8c, 0x88, 0xbf, - 0x20, 0xa2, 0x2e, 0xfe, 0xf9, 0x60, 0xae, 0x7b, 0xcc, 0x05, 0xc2, 0x1c, 0x0c, 0x38, 0x88, 0xdb, 0x20, 0xd4, 0x07, - 0xcc, 0xe6, 0x2e, 0xaa, 0xe8, 0xbd, 0x31, 0xcc, 0xec, 0xe8, 0x0f, 0x37, 0x12, 0x7c, 0x9d, 0xb5, 0x41, 0x9d, 0x17, - 0x87, 0x40, 0x10, 0xdc, 0x17, 0xaa, 0x9a, 0xab, 0x1e, 0xd8, 0x78, 0xcb, 0x7e, 0x6c, 0xb7, 0xe3, 0x69, 0x65, 0xaf, - 0xfd, 0x15, 0x85, 0x93, 0x4f, 0xca, 0xbf, 0xde, 0xeb, 0x0c, 0x16, 0x8c, 0x0c, 0x5f, 0x3a, 0xfb, 0x17, 0xbe, 0x56, - 0xd2, 0xbd, 0x6a, 0x50, 0x90, 0xc7, 0x47, 0x92, 0xfe, 0xed, 0x95, 0x95, 0x4f, 0xcd, 0xf4, 0x6f, 0xb7, 0x7a, 0x7d, - 0x1e, 0x8f, 0x26, 0xdb, 0x6d, 0x4f, 0x19, 0xb8, 0x52, 0x1d, 0x43, 0x08, 0x9d, 0xeb, 0xc9, 0xe1, 0x11, 0x44, 0x45, - 0xf0, 0xe3, 0x6e, 0x16, 0x9e, 0x44, 0xc6, 0x8d, 0xd3, 0x59, 0x78, 0x82, 0x1d, 0xee, 0x44, 0x25, 0x2e, 0x46, 0xad, - 0x0d, 0x4e, 0xcf, 0x93, 0x10, 0x42, 0x39, 0x60, 0x65, 0x77, 0xf2, 0xcf, 0xbd, 0x34, 0x13, 0x92, 0x93, 0xd5, 0xed, - 0x94, 0xee, 0x60, 0x9a, 0x1f, 0xe8, 0x11, 0x1c, 0x70, 0x67, 0x7f, 0x35, 0x1f, 0xc3, 0x24, 0x53, 0xe4, 0x14, 0xc9, - 0x2f, 0xd2, 0x53, 0x48, 0xda, 0xa1, 0xa7, 0x92, 0x00, 0x4e, 0xa8, 0xf9, 0x18, 0x7e, 0xc3, 0xb8, 0x7f, 0xe7, 0xbf, - 0xb6, 0x53, 0x11, 0x3d, 0xa1, 0x58, 0xa6, 0x22, 0xa7, 0x49, 0x56, 0x26, 0x10, 0xb5, 0x51, 0x36, 0x23, 0xfa, 0xca, - 0xc6, 0x7c, 0x94, 0x84, 0xcf, 0xa9, 0xf5, 0x7f, 0x86, 0xf0, 0x69, 0x74, 0x46, 0x80, 0xcb, 0x2b, 0xaf, 0x2e, 0xc2, - 0xa7, 0x4f, 0xe8, 0xc1, 0xe4, 0xeb, 0x23, 0x7a, 0x70, 0xf4, 0xd5, 0x53, 0x02, 0xb0, 0x68, 0x57, 0x17, 0xe1, 0xd1, - 0xd3, 0xa7, 0xf4, 0xe0, 0xdb, 0x6f, 0xe9, 0xc1, 0xe4, 0xab, 0x23, 0x2f, 0x6d, 0xf2, 0xf4, 0x5b, 0x7a, 0xf0, 0xf5, - 0x13, 0x2f, 0xed, 0x68, 0xfc, 0x94, 0x1e, 0x7c, 0xf3, 0xb5, 0x4e, 0xfb, 0x1b, 0x64, 0xfb, 0xf6, 0x08, 0xff, 0xd3, - 0x69, 0x93, 0xa7, 0x5f, 0xd1, 0x83, 0xc9, 0x18, 0x2a, 0x79, 0x6a, 0x2b, 0x19, 0x4f, 0xe0, 0xe3, 0xaf, 0xe0, 0xbf, - 0xbf, 0x91, 0x60, 0x41, 0x6b, 0xc1, 0x92, 0x0a, 0xf5, 0x67, 0x28, 0xe2, 0x44, 0xd5, 0x44, 0xc2, 0x43, 0xcc, 0x2c, - 0xbf, 0x89, 0xc3, 0x80, 0xd8, 0x74, 0x28, 0x88, 0x1e, 0x8c, 0x47, 0x4f, 0x49, 0xe0, 0xc2, 0xd3, 0xdd, 0xba, 0x20, - 0x63, 0x49, 0x35, 0xcf, 0xbe, 0x48, 0x34, 0x63, 0xe0, 0x00, 0x58, 0x7d, 0x74, 0x73, 0xd5, 0x62, 0x9e, 0x7d, 0x51, - 0x8b, 0xdd, 0x5c, 0xbf, 0xb5, 0x00, 0xe5, 0xdd, 0x55, 0xcb, 0x6e, 0x4b, 0x19, 0x3a, 0xad, 0x35, 0xfa, 0xec, 0x23, - 0xa6, 0x0f, 0x06, 0xce, 0x0d, 0xfb, 0xef, 0x3b, 0xe5, 0xb4, 0xbe, 0x51, 0x28, 0xd4, 0xa8, 0x3c, 0x24, 0xec, 0x04, - 0x8a, 0x1e, 0x0c, 0x80, 0x27, 0x70, 0x70, 0xdf, 0xfe, 0xcd, 0x32, 0x3e, 0x76, 0x94, 0xf1, 0x33, 0xca, 0x10, 0xd0, - 0xa8, 0x87, 0x99, 0x4d, 0x0f, 0x1b, 0xdd, 0xe8, 0x25, 0x0b, 0x79, 0x32, 0xf9, 0x9e, 0xc1, 0xae, 0xd6, 0xb5, 0x38, - 0xd0, 0xa2, 0x68, 0x71, 0x79, 0x90, 0xf2, 0x59, 0xcd, 0xfe, 0xbe, 0x44, 0xf5, 0x56, 0xe4, 0xbd, 0x11, 0xd9, 0xac, - 0x66, 0xdf, 0xeb, 0x37, 0xc0, 0xcd, 0xb0, 0xdf, 0xe4, 0x93, 0x1b, 0x38, 0x83, 0x0b, 0xd3, 0x1e, 0x69, 0x62, 0x04, - 0x58, 0x01, 0x19, 0x38, 0xf0, 0x00, 0xe8, 0xa0, 0x3b, 0xda, 0xdb, 0xad, 0x4c, 0xf1, 0xfb, 0x6c, 0x60, 0x00, 0x35, - 0xf3, 0x36, 0xb1, 0x65, 0xff, 0xcb, 0x93, 0x97, 0xa0, 0x70, 0xcb, 0x2f, 0x6f, 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, - 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x55, 0x40, 0xf5, 0x96, 0x8f, 0x36, 0x5c, 0xaa, 0x27, 0x81, 0x33, 0xb8, - 0x14, 0x65, 0xc2, 0xdf, 0x2a, 0xb1, 0x3f, 0x5a, 0x3f, 0xba, 0xbe, 0x3d, 0x0e, 0xac, 0x7d, 0x8f, 0x8f, 0xd4, 0x67, - 0xde, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0xaf, 0x1a, 0x23, 0xf1, 0x28, 0x80, 0x37, 0xd0, 0x11, 0x29, 0x34, 0x52, 0x2d, - 0x70, 0x0c, 0x85, 0xb4, 0x40, 0x1c, 0x79, 0x75, 0x83, 0x2d, 0x88, 0x08, 0xc1, 0xc3, 0xed, 0x5f, 0x4b, 0x19, 0x38, - 0xaa, 0xdf, 0xe7, 0xc2, 0x75, 0x7b, 0xd2, 0x76, 0xe4, 0x38, 0xf5, 0x53, 0x07, 0xdf, 0x9c, 0x34, 0x8d, 0xb6, 0x5c, - 0x49, 0x99, 0x61, 0x59, 0xd8, 0x49, 0xa8, 0xe4, 0x1e, 0xb5, 0x03, 0xc9, 0x17, 0x72, 0x88, 0x64, 0x81, 0x51, 0x28, - 0xc8, 0x70, 0x42, 0xc1, 0x66, 0xaa, 0x5a, 0x66, 0x97, 0x75, 0xb8, 0x91, 0x0a, 0x65, 0x4e, 0xd1, 0xb7, 0x1b, 0x1c, - 0x48, 0x48, 0x94, 0x55, 0x6f, 0xe2, 0x37, 0x21, 0x82, 0xd5, 0x71, 0x65, 0x0b, 0xc5, 0x9d, 0xfd, 0xc9, 0xd3, 0x2e, - 0xfe, 0x48, 0xbb, 0x80, 0xda, 0x58, 0x4c, 0xc3, 0x89, 0x89, 0x7d, 0x63, 0xbf, 0x30, 0x9a, 0x1e, 0x80, 0xfa, 0xae, - 0xa4, 0x18, 0x41, 0x7e, 0xa5, 0xed, 0x63, 0x7b, 0x8c, 0x89, 0x19, 0xc4, 0x1a, 0x96, 0x39, 0x33, 0xd9, 0x37, 0xc2, - 0x4e, 0x00, 0xb8, 0x11, 0x5a, 0x23, 0x21, 0xf0, 0x78, 0x1d, 0xe2, 0x79, 0x29, 0xc3, 0xb7, 0x66, 0x84, 0x8e, 0xc1, - 0x9b, 0xca, 0x34, 0x32, 0x13, 0xae, 0x60, 0x50, 0x1f, 0xdb, 0x2a, 0x0a, 0xab, 0xa9, 0x2c, 0x3b, 0x01, 0xb8, 0x81, - 0xec, 0x58, 0x5f, 0x3c, 0x67, 0xf5, 0x3c, 0x5b, 0x44, 0x3a, 0x28, 0x60, 0x5e, 0x19, 0x06, 0xed, 0xcd, 0x1e, 0xd9, - 0x8e, 0x45, 0xe8, 0x86, 0xfb, 0x08, 0xc6, 0xd3, 0xf6, 0x05, 0x2b, 0x88, 0x46, 0x88, 0x87, 0x19, 0x33, 0xf8, 0x5e, - 0x69, 0xca, 0x53, 0xd9, 0x12, 0x08, 0x1c, 0x85, 0x50, 0x17, 0xbb, 0x46, 0x09, 0x36, 0x93, 0x17, 0xcc, 0x60, 0xc7, - 0x8e, 0xd4, 0x74, 0xc9, 0x3a, 0x1d, 0xca, 0x29, 0x2d, 0xd4, 0x94, 0x2a, 0x5f, 0xc3, 0x6a, 0x5e, 0xa0, 0x87, 0x1e, - 0xb8, 0x1e, 0x28, 0x87, 0xbc, 0x82, 0x4e, 0x74, 0x04, 0x9d, 0x56, 0x9b, 0xb0, 0x73, 0x23, 0xd5, 0xb2, 0x06, 0x79, - 0xc7, 0x50, 0xef, 0x88, 0x17, 0x4e, 0xa0, 0x2e, 0x84, 0x08, 0xd9, 0xdb, 0x22, 0x7d, 0x44, 0xb3, 0xac, 0x7a, 0x09, - 0x65, 0x71, 0xc4, 0xd6, 0x05, 0x2b, 0x6d, 0x34, 0xb9, 0xe4, 0x11, 0x4f, 0x11, 0x11, 0xf0, 0x54, 0x6a, 0xd7, 0x77, - 0x5a, 0x42, 0x68, 0x96, 0x02, 0x71, 0xb3, 0x51, 0x9c, 0x1b, 0x13, 0xc8, 0x02, 0xe8, 0xdb, 0x4f, 0xd9, 0xb5, 0x13, - 0x0e, 0x76, 0x73, 0x9d, 0x15, 0xcf, 0xf9, 0x65, 0x56, 0xf0, 0x14, 0xc1, 0xae, 0xee, 0xf4, 0x03, 0xb7, 0x6c, 0x1b, - 0x58, 0xbe, 0x7d, 0x07, 0x0b, 0xa6, 0x0a, 0x95, 0x52, 0x22, 0x2b, 0xa2, 0x0a, 0x32, 0xbb, 0xcc, 0xdd, 0xeb, 0xac, - 0x78, 0x1d, 0xdf, 0x81, 0x37, 0x85, 0xc7, 0x4f, 0x8f, 0x2e, 0xf0, 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, - 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x29, 0x68, 0x6d, 0x0d, 0x81, 0x13, 0x7f, 0x5a, 0x76, 0xef, 0x3a, 0x2b, 0xb4, - 0x7d, 0xc6, 0x75, 0x7c, 0xc7, 0x0a, 0x09, 0x66, 0x81, 0x71, 0xee, 0xdb, 0x52, 0x92, 0xeb, 0xac, 0xd0, 0x02, 0x92, - 0xeb, 0xf8, 0x8e, 0xfa, 0x32, 0x0e, 0x65, 0x45, 0xe7, 0xc4, 0xf9, 0xdd, 0x1d, 0x7e, 0x81, 0xa1, 0x56, 0xc6, 0xfd, - 0x3e, 0x48, 0xcc, 0x84, 0x69, 0xca, 0x4c, 0x44, 0x42, 0xa1, 0x85, 0xd4, 0x94, 0x0f, 0x26, 0x64, 0x77, 0xa5, 0x1a, - 0x46, 0xd4, 0x7c, 0x15, 0x56, 0xb3, 0x71, 0x34, 0x21, 0x74, 0xd2, 0xb1, 0xde, 0x75, 0x6b, 0x21, 0xd3, 0xe8, 0x69, - 0xe4, 0xf8, 0x74, 0x96, 0xac, 0x9e, 0x96, 0xc7, 0x8c, 0x4f, 0xcb, 0xc1, 0x80, 0xa8, 0xd0, 0xc1, 0x1b, 0xac, 0x07, - 0x4c, 0x69, 0x6c, 0xbc, 0x35, 0xdd, 0xea, 0x97, 0x42, 0x86, 0xa4, 0x77, 0x0c, 0x48, 0x32, 0x61, 0x83, 0xdd, 0x82, - 0x44, 0xd1, 0xf1, 0xbf, 0x93, 0x5b, 0x70, 0xd7, 0x83, 0xd1, 0x8f, 0xee, 0xeb, 0x18, 0xff, 0xa1, 0xb6, 0x05, 0x51, - 0x9f, 0x2a, 0xd6, 0xeb, 0x48, 0x94, 0x21, 0x17, 0xe1, 0x67, 0x47, 0x43, 0x34, 0x51, 0xed, 0xb1, 0xa0, 0x58, 0x5f, - 0x5f, 0xf0, 0x12, 0xa7, 0x9f, 0xd9, 0xcb, 0x15, 0x6c, 0x0b, 0x5a, 0x6b, 0x1a, 0xf5, 0x26, 0x7e, 0x13, 0x99, 0xcb, - 0x82, 0x2a, 0xf2, 0x39, 0x0a, 0x59, 0xf3, 0x30, 0xac, 0x87, 0xed, 0x41, 0x24, 0x87, 0xed, 0x49, 0xf0, 0x1a, 0x03, - 0x0b, 0x64, 0x87, 0x46, 0xe0, 0x22, 0x34, 0xf2, 0xb7, 0x63, 0x70, 0xe1, 0x32, 0x88, 0x2c, 0x43, 0x15, 0xbf, 0xa9, - 0xdd, 0x04, 0xd9, 0x2b, 0x74, 0x9a, 0xc2, 0xaa, 0xa4, 0x49, 0x3e, 0xfc, 0x7a, 0x29, 0x4a, 0xcc, 0xe4, 0x74, 0xd9, - 0xa1, 0xaf, 0xed, 0xf6, 0x0e, 0x74, 0xc1, 0xaa, 0x4f, 0xce, 0xd7, 0x8f, 0x3b, 0x7b, 0x02, 0x46, 0xb1, 0x32, 0x87, - 0x2f, 0xa4, 0x54, 0x3e, 0x28, 0xcd, 0xc7, 0x30, 0xaf, 0x14, 0xc7, 0x6e, 0x00, 0x93, 0x80, 0x7d, 0x86, 0x54, 0x87, - 0x69, 0xc7, 0x3e, 0x47, 0x1b, 0x58, 0x12, 0x70, 0xf8, 0x47, 0x99, 0x68, 0xdc, 0xab, 0x7b, 0x95, 0xfa, 0x21, 0x5b, - 0xe6, 0x0b, 0xe0, 0xf3, 0x61, 0xd7, 0x46, 0x05, 0xca, 0x26, 0x22, 0x41, 0x61, 0xcb, 0x63, 0x90, 0xf6, 0x28, 0xa6, - 0xab, 0x92, 0x27, 0x19, 0x4a, 0x29, 0x12, 0xe5, 0x13, 0x9c, 0xc3, 0x1b, 0xdc, 0x8f, 0x32, 0x20, 0xbc, 0x0c, 0x39, - 0x1d, 0xa5, 0x54, 0x59, 0xc0, 0x48, 0xea, 0x01, 0xa2, 0xbc, 0x0c, 0xe4, 0x78, 0xdb, 0xed, 0x84, 0xae, 0xd8, 0x72, - 0x38, 0xa1, 0x48, 0x4a, 0xae, 0xb0, 0xdc, 0x6b, 0xd0, 0x79, 0x5c, 0xb0, 0xde, 0x0b, 0xc0, 0x22, 0x38, 0x87, 0xbf, - 0x31, 0xa1, 0x37, 0xf0, 0x37, 0x27, 0xf4, 0x35, 0x0b, 0xaf, 0x87, 0x57, 0xe4, 0x30, 0x4c, 0x07, 0x13, 0x29, 0x18, - 0xbb, 0x67, 0xcb, 0x22, 0x94, 0x89, 0xab, 0xc3, 0x4b, 0xf2, 0xf8, 0x92, 0xde, 0xd1, 0x5b, 0x7a, 0x46, 0xdf, 0x02, - 0xe1, 0xbf, 0x3f, 0x9e, 0xf0, 0xe1, 0xe4, 0x49, 0xbf, 0xdf, 0xbb, 0xe8, 0xf7, 0x7b, 0xe7, 0xda, 0x80, 0x42, 0xed, - 0xa2, 0xab, 0x86, 0xaa, 0x5f, 0xd7, 0xcd, 0x62, 0xfa, 0x56, 0x6e, 0xdc, 0x84, 0x67, 0x79, 0x78, 0x7d, 0x78, 0x4f, - 0x86, 0xf8, 0x78, 0x99, 0x0b, 0x51, 0x86, 0x57, 0x87, 0xf7, 0x84, 0xbe, 0x3d, 0x01, 0xbd, 0x29, 0xd6, 0xf7, 0xf6, - 0xf1, 0xbd, 0xaa, 0x8d, 0xd0, 0x17, 0x61, 0x02, 0xdb, 0xe4, 0x8e, 0x99, 0xbb, 0xf6, 0x64, 0x0c, 0xb1, 0x4c, 0xee, - 0x9d, 0xf2, 0xee, 0x1f, 0xdf, 0x91, 0xc3, 0x3b, 0xf0, 0x14, 0x35, 0xe4, 0x6f, 0x16, 0xde, 0xb2, 0x56, 0x0d, 0x8f, - 0xef, 0xe9, 0x59, 0xab, 0x11, 0x8f, 0xef, 0x49, 0x14, 0xde, 0xb2, 0x2b, 0x7a, 0xc6, 0xae, 0x09, 0xbd, 0xe8, 0xf7, - 0xcf, 0xfb, 0x7d, 0xd1, 0xef, 0xff, 0x3d, 0x0e, 0xc3, 0x78, 0x58, 0x92, 0x43, 0x41, 0xef, 0x0f, 0x27, 0xfc, 0x2b, - 0x32, 0x0b, 0x55, 0xf3, 0xe5, 0x82, 0x33, 0x2a, 0x6f, 0x99, 0xeb, 0x9e, 0x82, 0xb5, 0xc2, 0x3d, 0x93, 0x4f, 0x6f, - 0xe9, 0x2d, 0x2b, 0xe9, 0x19, 0x8b, 0x49, 0x74, 0x03, 0xad, 0xb8, 0x98, 0x95, 0xd1, 0x2d, 0x3d, 0x63, 0xe7, 0xb3, - 0x38, 0x3a, 0xa3, 0x6f, 0x59, 0x3e, 0x9c, 0x40, 0xde, 0xb3, 0xe1, 0x2d, 0x39, 0x7c, 0x4b, 0xa2, 0xf0, 0xad, 0xfa, - 0x7d, 0x4f, 0xaf, 0x78, 0xf8, 0x96, 0x3a, 0xd5, 0xbc, 0x25, 0xba, 0x7a, 0xaf, 0xf6, 0xb7, 0x24, 0x72, 0x07, 0xf3, - 0xad, 0xb1, 0xa7, 0x79, 0x64, 0x69, 0x63, 0x5a, 0x84, 0xa0, 0x6f, 0x2e, 0xc2, 0x5b, 0x42, 0xa6, 0xfe, 0xd8, 0xc1, - 0x80, 0xce, 0x1e, 0x45, 0x09, 0xa1, 0xb7, 0x6e, 0xa9, 0xb7, 0x38, 0x86, 0x7a, 0x84, 0x64, 0xda, 0x19, 0xa6, 0xe1, - 0x3a, 0x78, 0xa5, 0xc0, 0x3a, 0x2e, 0xfa, 0xfd, 0x70, 0xdd, 0xef, 0x43, 0xa4, 0xfb, 0x72, 0xa6, 0x63, 0xbb, 0x59, - 0xb2, 0x49, 0x6f, 0x41, 0xfb, 0xff, 0x6a, 0x30, 0x80, 0xce, 0x38, 0x25, 0x85, 0xb7, 0x83, 0x57, 0x8f, 0xef, 0x89, - 0xac, 0xa3, 0xa4, 0x95, 0x08, 0x4b, 0xfa, 0x9a, 0x66, 0x00, 0xf8, 0xf5, 0x6a, 0x30, 0x20, 0x91, 0xfe, 0x8c, 0x4c, - 0x5f, 0x1d, 0xbf, 0x9d, 0x0e, 0x06, 0xaf, 0xf4, 0x36, 0xf9, 0x8b, 0xed, 0x29, 0x05, 0xd6, 0xdf, 0x79, 0xbf, 0xff, - 0xd7, 0x49, 0x4c, 0x2e, 0x4a, 0x1e, 0x7f, 0x9c, 0xfa, 0x6d, 0xf9, 0xcb, 0x46, 0x55, 0x3b, 0xef, 0xf7, 0xd7, 0xfd, - 0xfe, 0x19, 0x60, 0x17, 0xcd, 0xac, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x96, 0x22, 0x29, 0x92, 0x43, 0x63, 0x68, 0x5b, - 0x2c, 0xdb, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xc8, 0xaf, 0x28, 0x6e, 0x48, 0x14, 0xf6, 0xce, 0xb7, 0xdb, 0x33, 0xc6, - 0x58, 0x4c, 0x40, 0xfa, 0xe1, 0xbe, 0x3e, 0x6b, 0xbc, 0x18, 0x62, 0x95, 0x40, 0x66, 0x73, 0xb3, 0x34, 0x87, 0x40, - 0xc4, 0x61, 0xd3, 0xbf, 0xd7, 0xf7, 0xf2, 0xaa, 0xb1, 0x7c, 0xeb, 0xcf, 0x00, 0x42, 0x24, 0x58, 0xc8, 0x67, 0x38, - 0x06, 0x55, 0x06, 0xc0, 0xbf, 0x91, 0x9c, 0x79, 0x01, 0xa0, 0xe6, 0x64, 0xbb, 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb2, - 0xd1, 0xdf, 0x9e, 0x3e, 0xae, 0x1f, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, 0x61, 0x16, 0x6b, 0x7d, 0x08, 0x46, - 0xf0, 0x8a, 0x7d, 0xbc, 0xc9, 0x3e, 0x9b, 0x7d, 0x44, 0xc2, 0xea, 0x31, 0x8e, 0xbc, 0x48, 0x5b, 0x7a, 0xbb, 0x3d, - 0x0c, 0x26, 0x2f, 0xd2, 0x4f, 0xb0, 0x9d, 0x2e, 0xff, 0xe6, 0xc0, 0x78, 0xc2, 0xc1, 0x68, 0x2f, 0x0a, 0xea, 0x4c, - 0xdb, 0x6e, 0x6b, 0xf7, 0x12, 0xf8, 0x06, 0x53, 0x41, 0xc7, 0x66, 0x58, 0xb8, 0x41, 0x4d, 0xe4, 0xd1, 0x32, 0xa8, - 0x1b, 0x69, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0xd2, 0x71, 0x0b, 0x34, 0x43, 0x86, 0xba, 0xdc, 0xd3, 0xfa, 0x5f, 0xbc, - 0x14, 0x1a, 0x3e, 0xc3, 0x8a, 0x08, 0x1d, 0x6e, 0x8d, 0xbb, 0xdc, 0x5a, 0xf5, 0x09, 0x6e, 0xad, 0x40, 0x12, 0xab, - 0x61, 0x49, 0xf5, 0xe5, 0x28, 0x61, 0x27, 0x05, 0xe3, 0x33, 0xa0, 0xe3, 0x31, 0x3c, 0x08, 0x56, 0xcd, 0x44, 0x94, - 0xa0, 0x7d, 0xa2, 0x8d, 0x30, 0xf8, 0x27, 0x60, 0xf6, 0xd3, 0x1c, 0xfe, 0x0a, 0x32, 0x4d, 0x8e, 0x21, 0x20, 0xc4, - 0xf1, 0x78, 0x16, 0x87, 0x63, 0x12, 0x25, 0x27, 0xf0, 0x04, 0xff, 0x95, 0xe1, 0x98, 0x34, 0xea, 0x0e, 0x23, 0xe4, - 0xe5, 0x36, 0x61, 0x00, 0x57, 0x36, 0x9e, 0x4d, 0x22, 0x23, 0xdd, 0x15, 0x8f, 0x47, 0xe3, 0xa7, 0x64, 0x1a, 0x87, - 0x62, 0x90, 0x10, 0x0a, 0xde, 0xbd, 0x61, 0x31, 0x4c, 0x14, 0x3c, 0x1b, 0xb0, 0x79, 0x85, 0x65, 0xf3, 0x04, 0x9c, - 0x80, 0x30, 0x4c, 0xc8, 0xb1, 0xee, 0x41, 0x4a, 0x51, 0xe7, 0x39, 0xf6, 0x53, 0x1d, 0x41, 0x98, 0x1d, 0xb5, 0x54, - 0x7c, 0x05, 0x40, 0x97, 0x38, 0x38, 0xd4, 0x20, 0x61, 0x54, 0xb3, 0xb0, 0x70, 0xa8, 0x94, 0xae, 0xee, 0xb0, 0xf2, - 0x28, 0xbf, 0x6e, 0xd0, 0x61, 0x45, 0x06, 0x13, 0x5a, 0x9c, 0x4c, 0xf8, 0x57, 0x10, 0xc0, 0xc3, 0x8b, 0xf8, 0x25, - 0x71, 0x62, 0x20, 0xbc, 0x0a, 0x32, 0x50, 0x69, 0x23, 0x1b, 0x33, 0x32, 0x15, 0x1f, 0x40, 0x98, 0x94, 0x83, 0x5b, - 0xb1, 0xce, 0x53, 0x88, 0x0a, 0xb6, 0xce, 0xeb, 0x83, 0x2b, 0xb0, 0x64, 0x8f, 0x6b, 0x88, 0x13, 0xb6, 0x5e, 0x01, - 0x76, 0xee, 0xa3, 0x4d, 0xd1, 0x1c, 0xc8, 0xef, 0x0e, 0xb0, 0xe5, 0xf0, 0xaa, 0x16, 0x07, 0x93, 0xf1, 0x78, 0x3c, - 0xfa, 0x1d, 0x8e, 0x0e, 0x20, 0xb4, 0x24, 0xd2, 0x7c, 0x32, 0x40, 0xe3, 0xae, 0x6b, 0xee, 0x8c, 0x0b, 0x45, 0x59, - 0xe9, 0x64, 0x42, 0x40, 0xfc, 0xac, 0xfb, 0x06, 0xfb, 0x8a, 0xab, 0xf8, 0x27, 0xbb, 0x9f, 0xe8, 0x15, 0x2d, 0x57, - 0xea, 0xe8, 0xdd, 0xdb, 0xb3, 0x57, 0x1f, 0x5e, 0xfd, 0xfa, 0xe2, 0xfc, 0xd5, 0x9b, 0x97, 0xaf, 0xde, 0xbc, 0xfa, - 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xd7, 0x56, 0xc4, 0x8c, 0xbd, 0x73, 0x8f, 0x71, 0x6a, 0x71, 0x85, 0xb3, 0x47, 0xf6, - 0x16, 0x0b, 0xb0, 0x09, 0x9a, 0x5b, 0xa8, 0xa8, 0x62, 0x34, 0x6a, 0x75, 0x4f, 0x40, 0x46, 0xa3, 0x46, 0x36, 0x1e, - 0x56, 0x6c, 0x8d, 0x5c, 0xbc, 0x65, 0x38, 0xf8, 0xc8, 0xfc, 0x96, 0x9c, 0x09, 0x37, 0xa3, 0xad, 0x58, 0x11, 0xf0, - 0xf9, 0x5a, 0x17, 0xb5, 0xc3, 0x85, 0xc8, 0xbd, 0x6d, 0x9e, 0x43, 0x42, 0x1d, 0x22, 0xd7, 0xc1, 0xfb, 0x7a, 0x64, - 0x8f, 0x8f, 0x9c, 0x27, 0xe9, 0x19, 0xea, 0x72, 0x34, 0x7c, 0xe4, 0x3d, 0xa3, 0x13, 0x73, 0xa3, 0x75, 0xa8, 0xe7, - 0x25, 0xec, 0x6f, 0x29, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x58, 0xdd, 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, - 0x7e, 0xa4, 0x6a, 0x02, 0x69, 0x51, 0x20, 0x75, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, 0x52, 0xff, 0x0c, 0x3d, 0x02, 0x68, - 0x2e, 0x3b, 0x86, 0x04, 0xea, 0xc5, 0x6b, 0x5c, 0xff, 0x9c, 0x7c, 0x59, 0xd1, 0xce, 0x17, 0xdf, 0x41, 0x88, 0x61, - 0xf7, 0x8a, 0xe0, 0x4d, 0xb8, 0x9d, 0x64, 0x7b, 0x69, 0xd1, 0xf7, 0xaa, 0xeb, 0x18, 0x8f, 0xbb, 0x3d, 0x57, 0x0a, - 0xff, 0xd6, 0x05, 0xf6, 0x40, 0xfe, 0x75, 0xbc, 0x60, 0x21, 0x60, 0x33, 0x1e, 0x9a, 0x45, 0x62, 0xfd, 0xde, 0xe9, - 0x84, 0x1c, 0x1e, 0x4d, 0xf9, 0x90, 0x15, 0xb4, 0x1a, 0xb0, 0xa2, 0xd9, 0xa1, 0xe6, 0xbc, 0x4d, 0xc8, 0xab, 0x5d, - 0x1a, 0x5e, 0x0d, 0xf9, 0x43, 0x97, 0xa4, 0x0f, 0xdc, 0x73, 0xa8, 0x36, 0xcd, 0xc5, 0x90, 0xa6, 0x9c, 0xee, 0x52, - 0x19, 0x10, 0x22, 0x5d, 0xc7, 0x35, 0x69, 0xd4, 0x51, 0xb5, 0xb4, 0x92, 0x8e, 0x9b, 0x6c, 0xf3, 0x89, 0x4b, 0xb6, - 0xbc, 0x5d, 0xbb, 0xd7, 0xea, 0xf6, 0x85, 0x19, 0xc8, 0xdf, 0x1f, 0x88, 0x6a, 0xa2, 0x21, 0xba, 0x80, 0x0a, 0xfe, - 0x01, 0x5e, 0x9e, 0x3c, 0x52, 0x0a, 0xd0, 0x7d, 0x67, 0x47, 0xd7, 0x1e, 0xf7, 0x66, 0xb1, 0xb5, 0xc4, 0x39, 0xab, - 0x5d, 0x67, 0x79, 0x59, 0xb6, 0x44, 0xd7, 0xa9, 0xd8, 0xcf, 0x61, 0x47, 0xdf, 0x9d, 0x6d, 0x00, 0x44, 0x29, 0xac, - 0xed, 0xd9, 0x5f, 0x39, 0x67, 0x7f, 0x65, 0xce, 0x7e, 0xb3, 0x09, 0xa4, 0x0f, 0x2b, 0xb4, 0xec, 0xa5, 0x28, 0x6a, - 0xdd, 0xe4, 0xb1, 0xaf, 0xcb, 0x42, 0x5a, 0xcc, 0x0f, 0x0d, 0xed, 0x7a, 0x32, 0xa6, 0x02, 0xd5, 0x23, 0x3f, 0x60, - 0xab, 0x0e, 0x0b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0xb9, 0xef, 0x6e, 0xf7, 0x7f, 0x73, 0xa1, 0x83, 0xdb, - 0xda, 0xb2, 0x72, 0xd4, 0xd5, 0x71, 0x89, 0x77, 0xb5, 0xe5, 0xc3, 0x77, 0xb5, 0x77, 0x99, 0x5a, 0x76, 0x35, 0xa0, - 0x06, 0x15, 0xeb, 0x6b, 0x5e, 0x66, 0x49, 0x63, 0x14, 0x1a, 0x6f, 0x39, 0x84, 0xf6, 0x70, 0x0e, 0x2e, 0x90, 0xc3, - 0x12, 0x42, 0x3f, 0xd6, 0x5a, 0x00, 0xe8, 0xb2, 0xd8, 0x6f, 0x79, 0x98, 0x91, 0x81, 0x2b, 0xf1, 0x2b, 0x84, 0x2b, - 0x2e, 0x3e, 0xdc, 0xc9, 0x4c, 0xd0, 0xab, 0xc4, 0x46, 0xcd, 0x15, 0xed, 0x98, 0x1f, 0xee, 0x17, 0x18, 0x0d, 0xc2, - 0x69, 0x4b, 0x76, 0x58, 0x75, 0xcc, 0x72, 0x0d, 0x47, 0x6d, 0x61, 0xcb, 0x2c, 0x5a, 0xd7, 0xcf, 0x7a, 0x98, 0xa9, - 0x33, 0xe5, 0x2d, 0xc8, 0xbe, 0x90, 0xbb, 0x9f, 0xaa, 0x8a, 0x2b, 0x72, 0x32, 0x19, 0x4f, 0x49, 0x35, 0x18, 0xb4, - 0x92, 0x8f, 0x31, 0x79, 0x38, 0xdc, 0x61, 0x2e, 0x2b, 0xd5, 0x0f, 0xa7, 0x0f, 0x50, 0x9f, 0xb7, 0x25, 0xc9, 0xa6, - 0x66, 0x7f, 0x82, 0x59, 0x2c, 0x10, 0x47, 0x0b, 0xbf, 0x38, 0x5f, 0x00, 0xc8, 0x32, 0x2c, 0x33, 0x25, 0x2c, 0x82, - 0x2b, 0x3d, 0x74, 0xb2, 0x64, 0xe2, 0x78, 0x3c, 0x73, 0x7b, 0x6e, 0x19, 0x1c, 0x42, 0xa2, 0x89, 0x31, 0x7e, 0x71, - 0xb3, 0x60, 0x1c, 0x87, 0xe2, 0x44, 0x78, 0xdf, 0x15, 0x24, 0x1a, 0x6b, 0x53, 0x65, 0x75, 0x95, 0xa8, 0x87, 0x09, - 0x79, 0x5c, 0x92, 0xc3, 0x92, 0x2e, 0xdd, 0xb1, 0xc4, 0xf4, 0xc3, 0xf8, 0x70, 0x32, 0x26, 0x8f, 0xe3, 0xc7, 0x13, - 0x0d, 0x37, 0xec, 0xe6, 0xc8, 0x87, 0x4b, 0x72, 0xe8, 0x57, 0x09, 0xa6, 0xa8, 0xba, 0x67, 0x6e, 0x25, 0xc9, 0x60, - 0x39, 0x48, 0x1f, 0xb7, 0xf2, 0x62, 0xad, 0x6a, 0xbc, 0xd7, 0xc7, 0x7c, 0x4a, 0x2a, 0xef, 0xc6, 0xb0, 0xa6, 0xd7, - 0xf1, 0x1f, 0xa2, 0x8c, 0x0a, 0x01, 0x88, 0x84, 0xa0, 0xde, 0xce, 0x2e, 0xb3, 0x24, 0x2e, 0xd2, 0x28, 0x6d, 0x08, - 0x4d, 0x4f, 0xd8, 0x64, 0x3c, 0x4b, 0x59, 0x7a, 0x3c, 0x79, 0x3a, 0x9b, 0x3c, 0x8d, 0x8e, 0xc6, 0x51, 0x3a, 0x18, - 0x40, 0xf2, 0xd1, 0x18, 0x5c, 0xec, 0xe0, 0x37, 0x3b, 0x82, 0xa1, 0x3b, 0x41, 0x96, 0xb0, 0x84, 0xa6, 0x7d, 0x5e, - 0x93, 0xd4, 0x70, 0x5e, 0xca, 0x9e, 0xc4, 0x77, 0x74, 0xed, 0x38, 0xb8, 0xb8, 0x2d, 0xbc, 0xb4, 0x2d, 0xbc, 0xdc, - 0x6d, 0xa1, 0xb6, 0x20, 0x28, 0xc5, 0xff, 0x8f, 0x1b, 0xc6, 0xbe, 0xbb, 0x84, 0x5e, 0x5c, 0x37, 0xd9, 0x68, 0x55, - 0x8a, 0x5a, 0xc0, 0x6d, 0x42, 0x8a, 0xc2, 0x46, 0xf1, 0x6a, 0x95, 0x2b, 0x17, 0xb1, 0x79, 0x4d, 0x01, 0xdc, 0x05, - 0xce, 0x56, 0x60, 0xa1, 0xb5, 0x81, 0xdc, 0x5f, 0xbc, 0x14, 0xcc, 0xa8, 0x7d, 0xf4, 0x3d, 0xf2, 0x8f, 0x10, 0xc1, - 0x96, 0x4e, 0xc6, 0xb3, 0x0a, 0x11, 0x2d, 0x3e, 0x25, 0xef, 0xfd, 0x37, 0x8e, 0x22, 0x73, 0x34, 0x8f, 0x51, 0xa1, - 0x65, 0x3c, 0xe2, 0xcc, 0xc9, 0xe4, 0x64, 0xe0, 0x6e, 0x06, 0x23, 0xfd, 0xb5, 0xb7, 0x19, 0x63, 0xdb, 0xa3, 0x7a, - 0xa1, 0x85, 0xa2, 0x7f, 0xe1, 0x3b, 0x5d, 0x2f, 0xe0, 0x12, 0xca, 0x81, 0x5d, 0x5f, 0x5d, 0xf1, 0x0a, 0x40, 0x84, - 0xb2, 0xa2, 0xdf, 0xef, 0xfd, 0xa1, 0xa1, 0x49, 0x2b, 0x5e, 0xbe, 0xce, 0x0a, 0xe3, 0x8c, 0x03, 0x4d, 0x05, 0xea, - 0xff, 0xb1, 0x36, 0xcf, 0x74, 0x4c, 0x66, 0xee, 0xe3, 0x70, 0x42, 0x22, 0xff, 0x35, 0xf9, 0xc4, 0x69, 0xfa, 0x89, - 0x2b, 0xda, 0x7f, 0x20, 0x33, 0xd7, 0x1c, 0x32, 0xd4, 0x5f, 0x58, 0xe6, 0x49, 0xeb, 0x75, 0x62, 0x76, 0x52, 0xb1, - 0x7a, 0x06, 0xe8, 0xe9, 0x25, 0x3c, 0xc8, 0x6b, 0x59, 0x3c, 0x85, 0xd9, 0x07, 0x35, 0x62, 0x75, 0xcc, 0xc6, 0xb3, - 0x50, 0x84, 0x13, 0xb0, 0xef, 0x9d, 0x8c, 0xe1, 0x3e, 0x20, 0xc2, 0x8f, 0x75, 0x58, 0x51, 0x94, 0x92, 0x97, 0xf0, - 0x1b, 0x14, 0x13, 0x00, 0x11, 0x08, 0x79, 0xfb, 0x7d, 0x21, 0x93, 0xf0, 0x75, 0x81, 0x29, 0xa5, 0xfc, 0xe0, 0x3f, - 0x91, 0xaa, 0x5b, 0xa6, 0x5f, 0xae, 0x1f, 0x77, 0x26, 0x24, 0x9f, 0x6e, 0x53, 0xe2, 0x3b, 0x08, 0xee, 0x2c, 0x40, - 0x07, 0x51, 0xa3, 0x19, 0xdb, 0xc3, 0xfc, 0x6e, 0xb5, 0x9f, 0xdf, 0xad, 0xfe, 0xdf, 0xf1, 0xbb, 0xd5, 0x43, 0x8c, - 0x61, 0x6d, 0xa0, 0xe1, 0x67, 0xc1, 0x38, 0x88, 0xfe, 0x73, 0x3e, 0x71, 0x2f, 0x4f, 0x7d, 0x9d, 0x15, 0xd3, 0x3d, - 0x4c, 0xb3, 0x4b, 0x50, 0x10, 0x56, 0x71, 0x97, 0x9e, 0xac, 0x6b, 0x73, 0x6b, 0x25, 0x43, 0xcc, 0xf3, 0x00, 0x6b, - 0x14, 0xd6, 0x0e, 0xd0, 0x3d, 0xaa, 0x36, 0x88, 0x15, 0xc1, 0xc3, 0x98, 0x19, 0xe9, 0xfb, 0x76, 0xab, 0x55, 0x98, - 0x0f, 0x72, 0x51, 0x90, 0x5d, 0x7f, 0x3c, 0x1b, 0x47, 0x21, 0x36, 0xe0, 0x3f, 0x66, 0xac, 0x3c, 0xd9, 0x7c, 0x27, - 0x23, 0xb5, 0x63, 0xf2, 0x34, 0xd9, 0x25, 0xbd, 0x03, 0xde, 0x21, 0x3f, 0x6f, 0x3e, 0x86, 0xa5, 0xd0, 0xfc, 0x96, - 0xb8, 0x8a, 0xcb, 0xac, 0x5e, 0x5e, 0x67, 0x09, 0x32, 0x5d, 0xf0, 0xe2, 0xb3, 0x99, 0x2e, 0xe7, 0x63, 0x75, 0xc0, - 0x38, 0x4a, 0xf1, 0xc6, 0x13, 0xa5, 0xa7, 0x2d, 0xcf, 0x0a, 0x79, 0x79, 0x92, 0x31, 0xdb, 0xb3, 0x0a, 0x9c, 0x4e, - 0xc1, 0x04, 0x5f, 0xfd, 0xb4, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x4b, 0xb1, 0xd2, 0x58, 0x4e, 0x06, 0xba, - 0x13, 0x30, 0x43, 0x45, 0x81, 0x17, 0x28, 0xf8, 0x8b, 0x06, 0x46, 0xf4, 0xa5, 0xfd, 0x4d, 0x06, 0x1a, 0xe9, 0x52, - 0x9f, 0x08, 0x63, 0xcb, 0xed, 0x94, 0x69, 0x2b, 0xca, 0x19, 0x67, 0xef, 0xe5, 0x95, 0x02, 0x0c, 0xf0, 0x36, 0xb7, - 0xd1, 0x45, 0x82, 0x5e, 0x0b, 0x52, 0xe7, 0x0d, 0xdc, 0xcd, 0x32, 0xd2, 0xc2, 0xc5, 0xc7, 0xb5, 0xc3, 0x82, 0x3b, - 0xf6, 0x0b, 0xb1, 0xd0, 0x9a, 0x69, 0x30, 0x66, 0x73, 0x82, 0x05, 0x56, 0x32, 0x50, 0x60, 0x31, 0x53, 0x96, 0xa6, - 0xf5, 0x90, 0x1f, 0x1e, 0xa1, 0xb5, 0x69, 0x3d, 0xe0, 0x87, 0x47, 0x4d, 0x94, 0x1d, 0x43, 0x96, 0x13, 0x37, 0x83, - 0x7c, 0xdd, 0x44, 0x3a, 0x45, 0x67, 0x77, 0xeb, 0x4b, 0xdd, 0x51, 0xdd, 0x80, 0xeb, 0x07, 0x20, 0x80, 0x0d, 0xc0, - 0x21, 0x50, 0x0e, 0x96, 0x42, 0x04, 0x8b, 0x32, 0x89, 0xf6, 0x35, 0x74, 0xde, 0x28, 0xf8, 0x2f, 0x70, 0x17, 0x11, - 0x2b, 0xf7, 0x13, 0x04, 0xfe, 0x8a, 0x32, 0xa5, 0x4c, 0x71, 0x3f, 0x51, 0xea, 0x15, 0xca, 0x99, 0x6f, 0xcd, 0x07, - 0xd1, 0x9a, 0x08, 0x55, 0x8c, 0x21, 0xf8, 0xb7, 0xb2, 0x4c, 0x59, 0xaa, 0x4a, 0xf5, 0xa1, 0xf6, 0x5a, 0x2b, 0xad, - 0xe5, 0xe3, 0xc8, 0x79, 0x8d, 0xa1, 0x63, 0x13, 0x6b, 0x29, 0x27, 0x53, 0x67, 0x6f, 0x0e, 0x45, 0x64, 0x01, 0xa7, - 0x13, 0x36, 0x9e, 0x26, 0xc7, 0x62, 0x9a, 0x58, 0xc8, 0xfc, 0x9c, 0x61, 0x64, 0x55, 0x0d, 0xc2, 0x22, 0x6d, 0x28, - 0x4d, 0x01, 0x3a, 0x39, 0x21, 0x64, 0x8a, 0xa1, 0x28, 0xf2, 0x91, 0xea, 0x87, 0xf1, 0x66, 0xb5, 0x5f, 0xbc, 0x53, - 0x00, 0xa7, 0x61, 0x02, 0x81, 0xc0, 0xcb, 0xf8, 0x36, 0x2b, 0xae, 0xc0, 0x63, 0x78, 0x00, 0x5f, 0x82, 0x9b, 0x5c, - 0xca, 0x7e, 0xab, 0xc3, 0x1c, 0xd7, 0x16, 0x30, 0x68, 0xb0, 0x7a, 0x10, 0x1d, 0x2e, 0xa5, 0x7e, 0x57, 0x01, 0x62, - 0x63, 0x0a, 0xff, 0xb3, 0xb5, 0x61, 0xcf, 0xbe, 0x97, 0x4d, 0x43, 0xeb, 0x84, 0xd3, 0xe2, 0x2a, 0x87, 0x28, 0x2a, - 0x83, 0x18, 0xdc, 0x91, 0x1c, 0x3e, 0xef, 0x5d, 0x15, 0x5e, 0x12, 0x70, 0x2b, 0x8b, 0x45, 0xb8, 0xa2, 0xcb, 0xd1, - 0x1d, 0x5d, 0x8f, 0x6e, 0xe9, 0x98, 0x4e, 0xbe, 0x19, 0x83, 0x45, 0xb6, 0x4a, 0xbd, 0xa7, 0xeb, 0xd1, 0x92, 0x7e, - 0x3b, 0xa6, 0x47, 0x7f, 0x03, 0x13, 0x3e, 0x3c, 0x4c, 0xe8, 0x25, 0x38, 0x76, 0x91, 0x06, 0x3d, 0x35, 0x5d, 0x83, - 0xc3, 0x7a, 0x94, 0x0f, 0xf9, 0x28, 0xa7, 0x7c, 0x54, 0x0e, 0xeb, 0x11, 0x78, 0x3a, 0xd6, 0x43, 0x3e, 0xaa, 0x29, - 0x1f, 0x5d, 0x0c, 0xeb, 0xd1, 0x05, 0xf1, 0x9b, 0xfe, 0xaa, 0xe6, 0xd7, 0x15, 0x4b, 0x61, 0x5b, 0xc0, 0xf2, 0xb5, - 0xab, 0x2c, 0x49, 0xdd, 0x55, 0xad, 0x4f, 0x66, 0xc3, 0xd9, 0x9b, 0xeb, 0x2e, 0x27, 0x06, 0x8f, 0xdb, 0xa4, 0xc3, - 0xd5, 0x97, 0x13, 0x79, 0xd2, 0x4b, 0xe4, 0x87, 0xf1, 0x54, 0x9d, 0x43, 0x60, 0x26, 0x31, 0x0b, 0x63, 0x86, 0xcd, - 0x54, 0x69, 0xa0, 0xc0, 0xc9, 0x46, 0x8e, 0x8b, 0x62, 0x36, 0xca, 0x29, 0xbc, 0x8f, 0x09, 0x89, 0xf0, 0xac, 0x3a, - 0xa9, 0x47, 0x25, 0xc4, 0x1c, 0x61, 0x21, 0x3e, 0x42, 0xbf, 0xe4, 0x47, 0x0e, 0x12, 0x78, 0x86, 0x7d, 0x2d, 0x07, - 0x31, 0x1c, 0xf1, 0xa6, 0xb2, 0x7a, 0x16, 0x26, 0x50, 0x59, 0x3d, 0x2c, 0x74, 0x65, 0x25, 0xcd, 0x46, 0xb5, 0x5b, - 0x59, 0x8d, 0x63, 0x94, 0x10, 0x12, 0x15, 0xaa, 0x32, 0x50, 0x9f, 0x24, 0x2c, 0x2c, 0x54, 0x65, 0x17, 0xf2, 0xa3, - 0x0b, 0xb7, 0xb2, 0x0b, 0x70, 0x21, 0x1d, 0x24, 0xee, 0x55, 0x2a, 0x4f, 0xdb, 0xd7, 0x41, 0x6f, 0x55, 0xd1, 0x0d, - 0xbf, 0xab, 0xcb, 0x38, 0x2a, 0xa8, 0x8d, 0x01, 0x8d, 0x0b, 0x23, 0x12, 0x54, 0xad, 0x51, 0xf0, 0x87, 0x04, 0x51, - 0x69, 0x0c, 0x5e, 0x9d, 0x49, 0xd7, 0x4a, 0xad, 0x69, 0x35, 0x28, 0x06, 0x25, 0xdc, 0x9f, 0xf2, 0xd6, 0x42, 0xfa, - 0x1e, 0x22, 0x2a, 0x43, 0x79, 0x83, 0x7f, 0x60, 0xf0, 0x64, 0xb6, 0x4a, 0xc3, 0x64, 0x74, 0x4f, 0xe3, 0xd1, 0x12, - 0xe1, 0x60, 0xd8, 0x3a, 0x95, 0x78, 0xeb, 0x97, 0x90, 0x7e, 0x47, 0xe3, 0xd1, 0x2d, 0x4d, 0x8d, 0xcd, 0xa9, 0x86, - 0xba, 0xea, 0x8d, 0xe9, 0x5d, 0x04, 0xaf, 0xef, 0xa3, 0x25, 0x85, 0xad, 0x74, 0x9a, 0x67, 0x57, 0x45, 0x94, 0x52, - 0x44, 0x20, 0x5c, 0x23, 0x72, 0xe0, 0x52, 0xa1, 0x0d, 0xae, 0x07, 0x50, 0x86, 0x82, 0x0b, 0x5c, 0x0e, 0xe2, 0xd1, - 0xd2, 0x21, 0x53, 0x4b, 0x75, 0x91, 0x45, 0xf8, 0x68, 0x6b, 0xa3, 0x25, 0x79, 0x46, 0x2c, 0x8c, 0x4b, 0x18, 0x42, - 0x55, 0x58, 0xa1, 0x0b, 0x12, 0x36, 0x70, 0x64, 0x2f, 0x2c, 0xeb, 0x70, 0x03, 0xa6, 0x45, 0xf7, 0x60, 0x1e, 0x05, - 0x0a, 0x07, 0x9b, 0x20, 0xdc, 0x84, 0xa2, 0x9d, 0xa3, 0xd0, 0x39, 0x9c, 0x09, 0x4a, 0x77, 0x26, 0x08, 0x69, 0x57, - 0x37, 0xd9, 0x12, 0xae, 0xc1, 0xf6, 0x0e, 0x9d, 0x8a, 0x4a, 0xaa, 0xce, 0x2d, 0x98, 0x2c, 0xe1, 0x11, 0xb6, 0x84, - 0xa9, 0x99, 0x4e, 0xe1, 0x06, 0x7c, 0x78, 0xb4, 0x33, 0xdf, 0xe5, 0xec, 0xcd, 0x21, 0xd8, 0x76, 0x4a, 0x1f, 0x10, - 0x43, 0xec, 0x96, 0x6c, 0x3c, 0x5d, 0x1e, 0x17, 0xd3, 0x25, 0x12, 0x3b, 0x4d, 0xb7, 0x18, 0x9f, 0x2f, 0x17, 0x34, - 0xc1, 0xb3, 0x8d, 0xd5, 0xf3, 0xa5, 0x46, 0x4b, 0x49, 0x19, 0xae, 0xb7, 0x25, 0xfa, 0xff, 0xcb, 0x8b, 0x5f, 0x0a, - 0xf0, 0x12, 0x8c, 0x05, 0x80, 0x70, 0x0f, 0xa6, 0x05, 0xa9, 0x89, 0xb2, 0xb1, 0x4c, 0xc3, 0x14, 0x17, 0x81, 0x4e, - 0xe9, 0xf7, 0xc3, 0x9c, 0xa5, 0xc4, 0x81, 0x0e, 0x35, 0xa3, 0xb4, 0x4e, 0x5d, 0x21, 0x08, 0xf0, 0x48, 0xf2, 0x1c, - 0x9b, 0x7c, 0x33, 0x9e, 0x05, 0x72, 0x20, 0x82, 0x28, 0x3b, 0xc6, 0x47, 0x0c, 0x5c, 0x14, 0xa9, 0xb8, 0x9d, 0xb6, - 0x88, 0xcb, 0xdd, 0x63, 0x16, 0xe2, 0x24, 0x61, 0xae, 0x59, 0x36, 0x64, 0x75, 0x84, 0x09, 0xaa, 0x30, 0x30, 0xcb, - 0x1b, 0xb2, 0xfa, 0xf0, 0x08, 0x22, 0xb5, 0x9a, 0x32, 0x56, 0x5d, 0x65, 0x7c, 0x0b, 0x40, 0xd6, 0x8c, 0xb1, 0xa3, - 0xbf, 0x8d, 0x67, 0xf2, 0x9b, 0x28, 0xe4, 0x27, 0x47, 0x7f, 0x83, 0xe4, 0xe3, 0x6f, 0x91, 0x99, 0x83, 0x64, 0xaf, - 0xa0, 0x2b, 0x7f, 0xd6, 0x15, 0x94, 0x26, 0xae, 0xbd, 0x42, 0xad, 0x3d, 0xa1, 0xd7, 0x5e, 0x89, 0xee, 0xd4, 0x9a, - 0xf7, 0x90, 0xb6, 0xb3, 0x60, 0x82, 0x8e, 0x66, 0x77, 0xa0, 0x83, 0xb7, 0x8a, 0xa0, 0x17, 0x49, 0xa8, 0x3d, 0x42, - 0xa5, 0x51, 0x2f, 0xec, 0xc8, 0x6e, 0xd6, 0x25, 0x73, 0x0c, 0x98, 0x63, 0x73, 0x0e, 0x55, 0xc3, 0x5c, 0x1e, 0xd4, - 0x29, 0x2b, 0x86, 0x39, 0x1e, 0xc0, 0x6b, 0x26, 0x86, 0xd5, 0x20, 0x57, 0x28, 0xdf, 0x97, 0xac, 0x1c, 0x16, 0x83, - 0x5c, 0x71, 0x33, 0x53, 0x3f, 0x36, 0x6d, 0xa2, 0xc2, 0x33, 0xaf, 0xd8, 0xc9, 0xaa, 0x07, 0x7c, 0x2c, 0x78, 0x32, - 0xbb, 0x9e, 0x8f, 0xaf, 0x81, 0x93, 0xd9, 0xdc, 0x45, 0x4b, 0x7a, 0x1f, 0xa5, 0xf4, 0x36, 0x5a, 0xd3, 0x65, 0x74, - 0xa9, 0x4d, 0x8c, 0x93, 0x06, 0xce, 0x01, 0x68, 0x15, 0x40, 0xe2, 0xc9, 0x5f, 0xef, 0x79, 0x52, 0x87, 0x4b, 0x9a, - 0x82, 0xdb, 0xb0, 0x6b, 0x9f, 0x79, 0xed, 0x4a, 0xa4, 0x36, 0x88, 0xb1, 0x66, 0x0c, 0x15, 0x37, 0xce, 0xba, 0x8f, - 0xaa, 0x06, 0x76, 0xae, 0x8d, 0x4d, 0x54, 0x0f, 0x27, 0xd3, 0x02, 0x10, 0x5b, 0x8b, 0xe1, 0xd0, 0x1e, 0x21, 0xbb, - 0xc7, 0x8f, 0x0a, 0xf4, 0xdc, 0x13, 0x06, 0xdb, 0xb6, 0xe5, 0x0f, 0x0c, 0x61, 0x4a, 0x3f, 0x7d, 0xe4, 0x17, 0x84, - 0x4c, 0xaf, 0xe0, 0x6c, 0x04, 0xea, 0x68, 0x84, 0x4e, 0xbf, 0xd5, 0x61, 0xa9, 0x0e, 0xf0, 0xcd, 0x5d, 0x94, 0xd0, - 0xfb, 0x28, 0x77, 0xc8, 0xda, 0xb2, 0x61, 0x62, 0x7a, 0x9e, 0x85, 0xbc, 0x7d, 0xa0, 0x17, 0x0b, 0x00, 0xd1, 0x1a, - 0xc4, 0xae, 0xd4, 0xf5, 0x08, 0x9c, 0x86, 0xd0, 0x24, 0x34, 0x82, 0xab, 0x0a, 0xc2, 0x08, 0xd8, 0x92, 0xf0, 0x37, - 0x98, 0xa8, 0xc0, 0x17, 0xe0, 0x22, 0x93, 0xa6, 0x39, 0x0f, 0x1a, 0x77, 0x24, 0xcf, 0xca, 0xb6, 0xb7, 0x2b, 0x8c, - 0x26, 0x18, 0x7b, 0xa2, 0x7d, 0x1e, 0x29, 0x46, 0x71, 0x99, 0x84, 0xd9, 0xe8, 0x4e, 0x9e, 0xe7, 0x34, 0x1b, 0xdd, - 0xab, 0x5f, 0x35, 0x1d, 0xd3, 0xef, 0x54, 0x40, 0x1b, 0x29, 0x7d, 0xeb, 0x38, 0x1b, 0xd0, 0x7a, 0xb1, 0xd0, 0xfe, - 0xd7, 0x62, 0x74, 0x47, 0xc5, 0xe8, 0xde, 0xb5, 0xa4, 0x9a, 0x4c, 0xcb, 0xe3, 0x0a, 0x0d, 0xa9, 0x3a, 0xbf, 0x2f, - 0x81, 0x9f, 0x2b, 0xb4, 0xef, 0xb4, 0xfe, 0xde, 0x69, 0xff, 0x45, 0x27, 0x4f, 0x20, 0x59, 0xa2, 0x92, 0xd5, 0x23, - 0xb0, 0x63, 0x5f, 0xe7, 0x71, 0xa9, 0x47, 0x29, 0xa6, 0xc6, 0xa4, 0x1f, 0x03, 0x57, 0x4c, 0x7b, 0x25, 0xb8, 0x5a, - 0x6e, 0xb7, 0x32, 0x86, 0x26, 0xec, 0xd9, 0x31, 0x44, 0x3d, 0xd7, 0x8e, 0x51, 0xc2, 0x73, 0x0f, 0x88, 0x95, 0xcc, - 0x5b, 0xba, 0x04, 0x24, 0xf0, 0xd6, 0xc1, 0xa4, 0x28, 0x46, 0x29, 0xc0, 0x4f, 0xa8, 0x3c, 0x0e, 0xfa, 0x84, 0x7c, - 0xa1, 0x50, 0x27, 0x84, 0xb7, 0x25, 0x70, 0xfc, 0x61, 0x7d, 0x54, 0x08, 0x5e, 0xe5, 0xb8, 0xfe, 0x0a, 0xe3, 0xfa, - 0x4b, 0x85, 0xe3, 0x8e, 0x65, 0xbb, 0x7e, 0xde, 0xa6, 0x46, 0x2f, 0xc1, 0xc2, 0x77, 0x23, 0xcd, 0x23, 0xb9, 0x41, - 0x48, 0x95, 0x60, 0xa5, 0x76, 0x21, 0xc1, 0xfc, 0x4b, 0x39, 0x5b, 0x9d, 0xb9, 0xea, 0x91, 0x07, 0xe5, 0x6c, 0x6a, - 0xfa, 0x3d, 0x09, 0xda, 0x7d, 0x47, 0x9a, 0xc3, 0x5b, 0x74, 0xf8, 0xec, 0x1a, 0x4b, 0xcc, 0x9d, 0x44, 0xc9, 0xf3, - 0x49, 0x60, 0xab, 0xe7, 0xd9, 0xb5, 0xf4, 0xb1, 0xda, 0xc5, 0xf1, 0xd3, 0xe7, 0x4f, 0x5c, 0x87, 0x69, 0xe5, 0x29, - 0x41, 0xc0, 0x9b, 0x43, 0xdb, 0x15, 0xca, 0x80, 0x86, 0xfa, 0x06, 0x8e, 0x73, 0x35, 0xac, 0x15, 0x01, 0x53, 0x52, - 0x1e, 0x15, 0xe0, 0x50, 0xe7, 0x91, 0xbb, 0x69, 0x58, 0x6b, 0xba, 0xe6, 0xf5, 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, - 0x3f, 0x3c, 0x1a, 0xd4, 0xf8, 0x93, 0xf8, 0xa3, 0xd1, 0xce, 0x0d, 0x77, 0x9a, 0x0a, 0x33, 0xd7, 0x62, 0x45, 0x76, - 0x47, 0xc9, 0xc9, 0xef, 0xe8, 0x85, 0xb1, 0x3f, 0xff, 0xb9, 0x98, 0x70, 0xd2, 0x12, 0x13, 0xa2, 0xa5, 0x83, 0x12, - 0x1d, 0xec, 0x28, 0xaf, 0xcc, 0x4b, 0xbc, 0x74, 0x8e, 0xff, 0x7d, 0x3d, 0xd6, 0xae, 0x02, 0xa1, 0xd5, 0xc9, 0xc3, - 0xf6, 0x64, 0x81, 0xa8, 0x01, 0xd5, 0xec, 0xb2, 0x1c, 0x69, 0xda, 0x59, 0x93, 0x8d, 0x27, 0x73, 0xdd, 0xcd, 0xe2, - 0xd9, 0x4c, 0x76, 0x2c, 0x2c, 0x3d, 0x0c, 0xc6, 0x4e, 0x15, 0x7d, 0x0e, 0x5a, 0x7e, 0x04, 0xcf, 0x7d, 0xe5, 0x99, - 0xcb, 0x66, 0x69, 0xf1, 0x02, 0x9d, 0x73, 0xaa, 0x21, 0x87, 0x1c, 0x80, 0xe3, 0x02, 0x8d, 0x25, 0x8a, 0x28, 0x08, - 0x1a, 0x13, 0x84, 0x5d, 0x95, 0xee, 0x48, 0x9f, 0x76, 0xf1, 0x69, 0x2b, 0xf4, 0x3d, 0xde, 0x67, 0x20, 0x31, 0x75, - 0x24, 0x0f, 0xb5, 0xd7, 0x1c, 0x95, 0x3c, 0x8b, 0x53, 0x85, 0xcf, 0x2f, 0x65, 0x67, 0xfe, 0xdd, 0x6a, 0x4c, 0xf1, - 0x1f, 0x69, 0xda, 0x77, 0x2e, 0x4d, 0x13, 0xdd, 0xb5, 0x3c, 0x68, 0x29, 0x2c, 0x38, 0x6e, 0x1b, 0x77, 0xfd, 0xfa, - 0x39, 0xaa, 0x61, 0x61, 0x73, 0x38, 0x13, 0x3a, 0xb4, 0x77, 0x95, 0x9d, 0xb9, 0x3e, 0xa2, 0x56, 0x5d, 0xac, 0xda, - 0x80, 0x92, 0x25, 0xe7, 0xd6, 0xe9, 0x88, 0x95, 0xbe, 0x3b, 0x0c, 0x77, 0xe6, 0x51, 0xb1, 0xbb, 0xdb, 0xed, 0x84, - 0xb4, 0xed, 0x83, 0xf1, 0xbe, 0x84, 0x85, 0x58, 0xef, 0xb0, 0x83, 0xef, 0xc3, 0xfa, 0x31, 0x1f, 0xfc, 0x1c, 0xca, - 0x75, 0x55, 0x3f, 0xcf, 0xa4, 0xa1, 0xcf, 0xcb, 0x52, 0x5c, 0xcb, 0x4e, 0xb9, 0x42, 0xb7, 0x96, 0xa9, 0xf7, 0x9b, - 0xf8, 0x4d, 0x2b, 0x40, 0x8c, 0xd3, 0x15, 0x23, 0xc5, 0x1b, 0x1a, 0x61, 0x9c, 0x87, 0xdb, 0x64, 0x51, 0x4b, 0x95, - 0x40, 0xd4, 0xe6, 0x27, 0x8f, 0x79, 0xa4, 0xd5, 0x99, 0xf0, 0xdd, 0x63, 0xee, 0x4a, 0xd7, 0x76, 0x9b, 0xf8, 0xa9, - 0xa6, 0x1d, 0xee, 0x0e, 0x74, 0x47, 0xeb, 0x1e, 0x6e, 0x9e, 0xc9, 0xcf, 0x23, 0xfd, 0xc5, 0x00, 0x9b, 0xb5, 0xcb, - 0xb8, 0xec, 0x18, 0xee, 0x3b, 0xd3, 0x83, 0xb1, 0x80, 0x40, 0x62, 0x86, 0x5e, 0x06, 0x36, 0x70, 0x81, 0xbd, 0xc2, - 0x80, 0x21, 0xae, 0x6e, 0xc9, 0xb9, 0xb2, 0xb2, 0x75, 0x91, 0xb7, 0x51, 0x21, 0xd8, 0x34, 0x1d, 0x37, 0x49, 0x0e, - 0xc1, 0x09, 0x5b, 0xee, 0x7d, 0xed, 0xb5, 0x33, 0xfc, 0xc7, 0xa0, 0xb2, 0x6e, 0x89, 0x8e, 0x51, 0xdb, 0x63, 0xa5, - 0xee, 0xd5, 0xbc, 0xca, 0x7d, 0xe4, 0x58, 0xbf, 0xe9, 0x97, 0x9a, 0x7d, 0xc1, 0x6b, 0x29, 0x38, 0x34, 0xb6, 0x5b, - 0x61, 0x17, 0x8b, 0x73, 0xb4, 0x1a, 0x59, 0x6b, 0xab, 0xbd, 0x46, 0x2a, 0xba, 0x7f, 0xcd, 0x71, 0x62, 0x2d, 0x85, - 0xcd, 0x87, 0x0f, 0x17, 0x6c, 0x9b, 0x00, 0x06, 0x2d, 0x3a, 0x0b, 0x94, 0x20, 0x93, 0x95, 0xaa, 0xdd, 0x4c, 0x89, - 0x5b, 0xee, 0x67, 0x5d, 0x66, 0x3b, 0x8f, 0x5f, 0x3b, 0x69, 0x9f, 0xf8, 0x1c, 0xfd, 0x30, 0xbf, 0x33, 0x4e, 0x4a, - 0xd6, 0x30, 0xae, 0xe5, 0xff, 0x57, 0xd3, 0xab, 0x32, 0x4b, 0xa3, 0x8d, 0xe6, 0xc1, 0x4c, 0xa8, 0x4d, 0x17, 0x1a, - 0xa3, 0xb6, 0xcb, 0x46, 0x12, 0xd1, 0xfa, 0x0e, 0x04, 0x33, 0x92, 0xfb, 0xaa, 0xda, 0xbc, 0x52, 0x6d, 0xe0, 0x1d, - 0x3e, 0xb1, 0xd1, 0x3d, 0xdb, 0x13, 0x42, 0xf9, 0xee, 0x69, 0xa1, 0x57, 0x2d, 0xad, 0x3c, 0xb6, 0xab, 0x72, 0x2e, - 0x46, 0xb5, 0x7a, 0xc2, 0x64, 0xc3, 0x82, 0xc9, 0xfe, 0x7f, 0x5f, 0x66, 0x69, 0x9b, 0xa2, 0x03, 0xd3, 0xe9, 0xfb, - 0x74, 0xd2, 0x0d, 0xae, 0x33, 0x60, 0x11, 0xc1, 0x96, 0x0a, 0xc7, 0xa3, 0x50, 0x6e, 0x90, 0x30, 0x11, 0x5c, 0x47, - 0xbd, 0xec, 0x68, 0x99, 0x94, 0x55, 0x01, 0xcf, 0x2f, 0x5d, 0x65, 0x3a, 0x8e, 0x86, 0x7e, 0xff, 0x3a, 0xd5, 0xa1, - 0x5f, 0x69, 0xe1, 0x9c, 0x23, 0xcb, 0xcc, 0x51, 0x75, 0xc8, 0x30, 0x46, 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x86, - 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x8c, 0x81, 0x5c, 0x2a, 0x83, 0x7a, 0x45, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, - 0x42, 0x2f, 0x59, 0xe1, 0xde, 0x85, 0xd6, 0x20, 0x50, 0x14, 0x7e, 0xca, 0xf4, 0x42, 0xb5, 0xf3, 0x92, 0x26, 0xb4, - 0xa4, 0x2b, 0xd2, 0x80, 0xbe, 0xd7, 0xca, 0xd9, 0xd1, 0xc9, 0x4e, 0xcf, 0x7a, 0xcc, 0xca, 0xe1, 0x64, 0x1a, 0xc3, - 0x35, 0x2d, 0xb6, 0xd7, 0xb4, 0xa5, 0x7f, 0xe3, 0xf2, 0x36, 0x8e, 0x47, 0xbb, 0x40, 0xda, 0xa6, 0xb8, 0xfd, 0xd4, - 0xe1, 0xf6, 0xd7, 0x0d, 0x5b, 0x4e, 0x7b, 0xeb, 0xed, 0xb6, 0x97, 0x82, 0x8d, 0xa8, 0xc3, 0xc7, 0xaf, 0xa5, 0x74, - 0xdd, 0x70, 0xf9, 0x29, 0x3c, 0x3b, 0x7c, 0xfd, 0xd2, 0x05, 0x97, 0xa3, 0x75, 0x9b, 0xbb, 0x5f, 0xee, 0x22, 0xcb, - 0x7d, 0xd6, 0xd0, 0x72, 0x35, 0x43, 0x3e, 0x79, 0xd6, 0xda, 0x3b, 0xd4, 0x82, 0xe5, 0xac, 0x9b, 0xf0, 0xc4, 0x60, - 0xc7, 0x5e, 0x7b, 0x9b, 0xa3, 0xd6, 0x97, 0x2c, 0x8f, 0x04, 0xba, 0x24, 0x4f, 0x37, 0xfd, 0x83, 0x08, 0xf3, 0xd1, - 0x1d, 0xcd, 0x01, 0x57, 0xac, 0x36, 0x97, 0x0c, 0xd2, 0xd4, 0xed, 0x25, 0x2e, 0x7d, 0x85, 0x43, 0xb2, 0xc1, 0x27, - 0xcd, 0x54, 0x7d, 0x72, 0xc9, 0x83, 0xff, 0xb7, 0x51, 0xab, 0xf4, 0xec, 0x24, 0x7b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, - 0x4c, 0x34, 0x12, 0xf0, 0xd4, 0x2c, 0x86, 0x7a, 0x54, 0x97, 0x71, 0x51, 0xe5, 0x3a, 0xe6, 0xd8, 0xde, 0xae, 0xa1, - 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xfa, 0x0e, 0x6c, 0x04, 0x3a, 0x2a, 0x51, 0x5f, 0x86, 0x99, 0xbe, 0x0c, 0xd3, - 0xae, 0xad, 0x02, 0xc3, 0x2b, 0xb7, 0x4a, 0x22, 0x5d, 0x8d, 0x7a, 0x5c, 0xcf, 0x92, 0xdf, 0x8b, 0xbc, 0x7b, 0x4d, - 0x3a, 0x12, 0x7f, 0xba, 0x74, 0xe4, 0xf5, 0x30, 0x20, 0xe2, 0x73, 0x96, 0x86, 0x6d, 0x14, 0x04, 0xa7, 0x96, 0x3b, - 0x90, 0xe6, 0x23, 0x40, 0xe6, 0xc7, 0x69, 0xf8, 0x4e, 0x89, 0x73, 0xc8, 0x46, 0x6a, 0x9c, 0xd8, 0x52, 0xab, 0x87, - 0xe0, 0xce, 0x7b, 0xcd, 0x63, 0x08, 0x7c, 0xf8, 0x01, 0x37, 0x83, 0x8c, 0x6e, 0x4b, 0x74, 0x94, 0x36, 0x87, 0xba, - 0xe5, 0x23, 0x4f, 0xa8, 0x64, 0x64, 0x78, 0x31, 0xb4, 0x77, 0x47, 0x60, 0x54, 0x5b, 0x81, 0xcc, 0xb0, 0x3c, 0x3c, - 0x1a, 0xa6, 0x52, 0x50, 0x34, 0x14, 0xc3, 0x25, 0xca, 0x01, 0x31, 0x09, 0x04, 0x46, 0xe5, 0x20, 0x55, 0x95, 0xc9, - 0x17, 0x83, 0x54, 0xdd, 0xaa, 0x48, 0x73, 0x9e, 0x85, 0x35, 0x55, 0x2d, 0xa2, 0x63, 0x3a, 0x14, 0x74, 0xa9, 0x77, - 0x6a, 0xae, 0xa4, 0x17, 0x72, 0x39, 0x3e, 0x53, 0x69, 0x30, 0x8a, 0x67, 0x36, 0x45, 0xbd, 0x95, 0xfb, 0xd9, 0x7d, - 0x8b, 0x29, 0x0d, 0x62, 0x53, 0x3b, 0x8b, 0x18, 0x56, 0xed, 0x87, 0xac, 0xce, 0x41, 0xbb, 0x0b, 0xca, 0xc6, 0x5a, - 0x3b, 0xcf, 0x7b, 0xc1, 0xcc, 0x41, 0xdb, 0x58, 0xfb, 0x3e, 0xf4, 0x5a, 0x8c, 0xda, 0x1b, 0x53, 0x85, 0x7b, 0x02, - 0x3f, 0x4d, 0xd0, 0x74, 0x27, 0xf2, 0x1c, 0x75, 0xc8, 0xbb, 0xfb, 0x99, 0x25, 0x3b, 0x93, 0x4f, 0x62, 0x99, 0x34, - 0xed, 0x63, 0x12, 0xa3, 0x96, 0x18, 0x46, 0x17, 0x6e, 0x64, 0x52, 0xfb, 0xb9, 0x33, 0xfd, 0x88, 0x67, 0xf2, 0xb0, - 0x1d, 0x1a, 0x75, 0xa5, 0x61, 0x2d, 0x29, 0xa2, 0xba, 0xa0, 0xb7, 0xa6, 0x3a, 0x3a, 0xa2, 0x4e, 0x47, 0x60, 0x75, - 0x45, 0x1b, 0xd4, 0x00, 0x4c, 0xc6, 0x8d, 0xa9, 0xcd, 0xe5, 0x60, 0x1a, 0xa3, 0x2a, 0x78, 0x4a, 0x77, 0x85, 0xd2, - 0xbd, 0x49, 0xd3, 0xb4, 0x86, 0xd8, 0x00, 0x06, 0x04, 0x76, 0xf4, 0xe4, 0xf4, 0x07, 0x3e, 0x2a, 0x00, 0x0d, 0xbc, - 0xdb, 0x99, 0xca, 0x91, 0xa8, 0x77, 0x72, 0xd3, 0xfa, 0xa9, 0x4e, 0x55, 0x2e, 0x80, 0x8a, 0x3b, 0x4b, 0xe7, 0x97, - 0x7a, 0xc4, 0x02, 0x18, 0xf7, 0xc0, 0x9a, 0xea, 0x9d, 0x66, 0x60, 0x3d, 0x91, 0xe7, 0x59, 0xc5, 0x13, 0x51, 0xc0, - 0x8c, 0x88, 0xeb, 0x6b, 0x51, 0xc0, 0x30, 0xc8, 0x01, 0x40, 0x8b, 0xe6, 0x2a, 0x9a, 0xf0, 0xaf, 0x1a, 0xba, 0x2f, - 0x0f, 0xff, 0x4a, 0xe5, 0xfa, 0x7a, 0xdc, 0x80, 0xa1, 0xf2, 0xba, 0xe6, 0x3b, 0x99, 0xbe, 0xe6, 0x4f, 0x9c, 0x4c, - 0x4b, 0xb1, 0x2e, 0x77, 0xb2, 0x7c, 0xf5, 0x35, 0x7f, 0xaa, 0xf2, 0x1c, 0x3d, 0x69, 0x68, 0x1a, 0xdf, 0xef, 0x64, - 0xf9, 0xe6, 0xeb, 0x27, 0x26, 0xcf, 0x57, 0xe3, 0x86, 0xde, 0x72, 0xfe, 0xd1, 0x66, 0x9a, 0xa8, 0xaa, 0xc6, 0x4f, - 0xbe, 0x31, 0xb9, 0x9e, 0x34, 0xf4, 0x5a, 0x14, 0xf5, 0x72, 0xa7, 0xa8, 0xa3, 0xaf, 0x8f, 0xbe, 0xe1, 0x5f, 0xeb, - 0xee, 0x1d, 0x35, 0xf4, 0xcf, 0x75, 0x5c, 0xd6, 0xbc, 0xdc, 0x29, 0xee, 0x6f, 0xdf, 0x7c, 0xf3, 0xc4, 0x64, 0x7c, - 0xd2, 0xd0, 0x7b, 0x1e, 0x77, 0xb4, 0x7d, 0xf2, 0xf4, 0x09, 0xff, 0x5b, 0xd3, 0xd0, 0x5f, 0x98, 0x1b, 0x1c, 0xf5, - 0x34, 0x73, 0xf4, 0xf0, 0x89, 0xf0, 0x51, 0x03, 0x86, 0x0e, 0x1a, 0x40, 0x2e, 0x8c, 0x9a, 0x66, 0x8f, 0x57, 0x2e, - 0xb8, 0x7d, 0x9f, 0xc7, 0x69, 0xbc, 0x82, 0x83, 0x60, 0x83, 0xc6, 0x59, 0x25, 0x70, 0xaa, 0xc0, 0x7b, 0x46, 0x05, - 0xcd, 0x2a, 0xf1, 0x0f, 0xce, 0x3f, 0xc2, 0xa0, 0x21, 0xa4, 0x8d, 0x8c, 0x0c, 0xf4, 0x76, 0xa5, 0x22, 0x1b, 0xa1, - 0xff, 0xa6, 0x1f, 0x07, 0xc7, 0x85, 0xd1, 0xeb, 0xf7, 0xc3, 0x92, 0x55, 0x61, 0x49, 0x08, 0xfd, 0x23, 0x2c, 0xc1, - 0xa1, 0xa4, 0x64, 0x4e, 0x3e, 0xed, 0x7b, 0xae, 0x8c, 0xc2, 0x42, 0x10, 0xdd, 0x45, 0xe6, 0x01, 0x55, 0x8f, 0xae, - 0x43, 0x37, 0xc4, 0xcb, 0x0a, 0x4b, 0x86, 0x0e, 0x66, 0x30, 0x43, 0x50, 0xfc, 0x6b, 0x1e, 0x0a, 0xf0, 0x89, 0x07, - 0xf8, 0xe8, 0x31, 0x99, 0x71, 0x79, 0xad, 0x7d, 0x7b, 0x19, 0x96, 0x34, 0x50, 0x6d, 0x87, 0xa0, 0x03, 0x91, 0xfb, - 0x02, 0x3c, 0x05, 0x06, 0x2e, 0x2c, 0xec, 0x52, 0xec, 0xfa, 0xab, 0xff, 0xa2, 0x59, 0x47, 0x1b, 0x7e, 0xf4, 0x17, - 0xe3, 0xc2, 0x9e, 0x91, 0xa9, 0x38, 0x2e, 0x86, 0x93, 0xe9, 0x60, 0x20, 0x6c, 0x1c, 0xb7, 0xd3, 0x6c, 0xfe, 0xcb, - 0x5c, 0x2c, 0x16, 0xa8, 0xfb, 0xc6, 0x79, 0x9d, 0xa9, 0xbf, 0x91, 0x72, 0x3e, 0x78, 0x7d, 0xfa, 0xdb, 0xf9, 0xd9, - 0xe9, 0x4b, 0x70, 0x3e, 0xf8, 0xf0, 0xe2, 0xfb, 0x17, 0xef, 0x65, 0x70, 0x77, 0x39, 0xe7, 0xfd, 0xbe, 0x95, 0xfa, - 0x84, 0x7c, 0x58, 0x93, 0xc3, 0x30, 0x7e, 0x5c, 0x4a, 0xa3, 0x07, 0x72, 0xcc, 0x0c, 0x14, 0x32, 0x54, 0xd1, 0x98, - 0xdf, 0xc5, 0x70, 0xe2, 0x80, 0x59, 0xdc, 0x7b, 0x22, 0x5c, 0xb7, 0xe5, 0x26, 0xc8, 0x9a, 0x38, 0x71, 0xfa, 0xc1, - 0xc9, 0x54, 0x58, 0xb6, 0xb0, 0x64, 0x50, 0x36, 0xb4, 0xe9, 0x34, 0x9b, 0x97, 0x0b, 0xd3, 0x2e, 0xbb, 0x40, 0x46, - 0x69, 0x76, 0x79, 0x19, 0x4a, 0xe8, 0xea, 0x13, 0xd0, 0x00, 0xe8, 0x46, 0x95, 0xb6, 0x45, 0x7c, 0xe6, 0x96, 0x1f, - 0x8d, 0x9d, 0xe6, 0xdd, 0xa1, 0xee, 0x49, 0x37, 0xab, 0xf6, 0x06, 0x74, 0x30, 0xa1, 0xdc, 0x0e, 0xba, 0x0e, 0x26, - 0x23, 0xdb, 0xf2, 0xcb, 0xbc, 0x5e, 0xe8, 0xe6, 0xd8, 0x61, 0xa8, 0x9d, 0x92, 0xd7, 0xc2, 0x43, 0x64, 0x20, 0x19, - 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0xfd, 0x60, 0xd7, 0x3b, 0x7e, 0x93, 0x0b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x51, - 0x25, 0x9d, 0xcb, 0x05, 0xe3, 0xf3, 0x6a, 0x71, 0x02, 0x6e, 0xe7, 0xf3, 0x6a, 0x11, 0x61, 0x50, 0xbe, 0x0c, 0x62, - 0x95, 0x80, 0xdd, 0x8b, 0x85, 0xf0, 0xed, 0x84, 0x36, 0x30, 0x1b, 0x48, 0xb0, 0x41, 0x61, 0x56, 0x1a, 0xa2, 0xdc, - 0x49, 0x8f, 0x36, 0x88, 0x3c, 0xc4, 0xea, 0x79, 0xdd, 0xf6, 0x64, 0xd3, 0x17, 0x13, 0x5c, 0x65, 0x31, 0x13, 0xd3, - 0xf8, 0x98, 0x95, 0xd3, 0x18, 0x4a, 0x89, 0xd3, 0x34, 0x8c, 0xe9, 0x84, 0x56, 0x84, 0x24, 0x8c, 0xcf, 0xe3, 0x05, - 0x4d, 0x50, 0x4a, 0x10, 0x42, 0xc8, 0x8f, 0x11, 0xda, 0xe6, 0xc0, 0x92, 0x37, 0xdb, 0xcf, 0xd1, 0xcf, 0xed, 0x18, - 0x2e, 0xa3, 0x22, 0x74, 0x83, 0xce, 0x1a, 0xee, 0x8d, 0xa8, 0xa4, 0x31, 0x56, 0x0c, 0x41, 0xc0, 0x4b, 0x8c, 0x4a, - 0x58, 0x92, 0x98, 0xd5, 0x10, 0x45, 0xa0, 0x98, 0xc7, 0x0b, 0x56, 0x52, 0xdf, 0xe6, 0x34, 0x56, 0x26, 0x41, 0x3d, - 0x8b, 0xa5, 0x76, 0x20, 0xa4, 0x0a, 0xb1, 0xc7, 0x67, 0x55, 0x74, 0xa3, 0x0c, 0x0d, 0x00, 0x05, 0x4a, 0xca, 0xc5, - 0x6f, 0x3f, 0xdf, 0xc3, 0x4d, 0x42, 0xff, 0xb3, 0x8d, 0x8e, 0x76, 0x96, 0xcb, 0x43, 0x6f, 0xbe, 0xa0, 0x71, 0x9e, - 0x43, 0x28, 0x36, 0x8d, 0x40, 0x5e, 0x64, 0x35, 0x44, 0xb4, 0xb8, 0x0f, 0x74, 0x48, 0x38, 0x68, 0xd3, 0x2f, 0x90, - 0xea, 0x89, 0xc9, 0xa5, 0x27, 0x06, 0xc6, 0xed, 0x90, 0x09, 0x05, 0x1c, 0xe9, 0x79, 0xf6, 0x97, 0x8f, 0xb1, 0xa6, - 0xa8, 0x99, 0x8e, 0xb7, 0x21, 0x11, 0x0d, 0x5a, 0x10, 0xcd, 0xe0, 0xfd, 0x73, 0xcd, 0xf1, 0xaa, 0x03, 0x3f, 0xe0, - 0x9d, 0x8d, 0x33, 0x2f, 0x67, 0x1e, 0x91, 0x53, 0x1f, 0xe5, 0x88, 0x7e, 0xc9, 0xc3, 0x7a, 0xa4, 0x92, 0x31, 0x56, - 0x12, 0x07, 0xbd, 0x0d, 0x16, 0xcc, 0x09, 0x5d, 0xf1, 0xd0, 0xf0, 0xf1, 0x2f, 0x91, 0xc9, 0xa8, 0x68, 0xa1, 0xd8, - 0x8d, 0xca, 0x60, 0xc4, 0x39, 0x0d, 0x33, 0x34, 0x59, 0xd2, 0xc5, 0x52, 0x91, 0xe6, 0x4a, 0x9a, 0x06, 0xb8, 0x04, - 0x1a, 0x3c, 0x1f, 0xf4, 0x43, 0x43, 0x3d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, 0xfb, 0xd0, 0xe1, 0xff, 0xe7, 0xd8, - 0x05, 0x22, 0xed, 0xcd, 0x75, 0x64, 0x3c, 0xd2, 0x78, 0x38, 0x28, 0xda, 0xc7, 0xde, 0x4f, 0xfc, 0xcc, 0x19, 0x7d, - 0x48, 0x2a, 0xdf, 0xe1, 0x83, 0xe5, 0x8e, 0x37, 0xd5, 0xb3, 0x32, 0x82, 0xf5, 0xb0, 0xdd, 0xe2, 0x82, 0x68, 0xbb, - 0x00, 0x52, 0xc7, 0x78, 0xb5, 0x74, 0x8d, 0x57, 0xe3, 0x3d, 0xc6, 0xab, 0xf6, 0x4c, 0x0d, 0x73, 0xb2, 0x41, 0x7d, - 0x96, 0x94, 0xe7, 0xe7, 0x28, 0x13, 0xf4, 0x5d, 0xce, 0x0a, 0x2a, 0x53, 0x09, 0xed, 0xc5, 0x6e, 0xc6, 0xf8, 0x8e, - 0x60, 0x9c, 0x15, 0x8b, 0x91, 0x40, 0x65, 0x2a, 0x69, 0xc2, 0x5e, 0x09, 0xea, 0x31, 0x78, 0xaf, 0x31, 0x44, 0xb5, - 0x8c, 0x5d, 0xb7, 0x81, 0xd0, 0x50, 0x5b, 0x8f, 0xf6, 0x8c, 0xf5, 0xe8, 0x76, 0x5b, 0x6b, 0x7f, 0x3b, 0xb1, 0x2e, - 0x13, 0x44, 0x15, 0x96, 0xa3, 0x09, 0xf0, 0xa6, 0x89, 0xb9, 0x2d, 0x59, 0xa5, 0x05, 0x86, 0xcf, 0xfe, 0x23, 0x2c, - 0xac, 0x4a, 0xa2, 0x20, 0xb3, 0x22, 0x1a, 0xd8, 0x73, 0xf0, 0x79, 0x5c, 0xc3, 0x1a, 0x80, 0x48, 0x8e, 0xe8, 0xe1, - 0xfa, 0x47, 0x28, 0x6c, 0x66, 0x41, 0x66, 0x02, 0x32, 0xf3, 0x22, 0x6d, 0x67, 0x1d, 0x4c, 0xac, 0x49, 0xad, 0x33, - 0x16, 0x62, 0xa8, 0x91, 0x1f, 0x40, 0x19, 0x62, 0xf1, 0xc9, 0x07, 0x13, 0x2a, 0x64, 0x28, 0x55, 0xaf, 0x9b, 0xdd, - 0xc0, 0x2b, 0x1f, 0xb2, 0x6b, 0x5e, 0xd5, 0xf1, 0xf5, 0x4a, 0x5b, 0x12, 0x73, 0xb6, 0xcf, 0x6d, 0x8f, 0x56, 0xfa, - 0xd5, 0x9b, 0x17, 0xdf, 0x9f, 0x7a, 0xaf, 0x76, 0x11, 0x47, 0x43, 0xb0, 0xad, 0x18, 0x63, 0xf4, 0x16, 0x97, 0x06, - 0x13, 0xe9, 0x1a, 0x81, 0xde, 0xa5, 0xa0, 0xdf, 0xfe, 0x5c, 0x4f, 0xc0, 0x6b, 0xae, 0x96, 0x5f, 0xf2, 0x11, 0xb0, - 0x44, 0xf5, 0xac, 0x30, 0x3b, 0x2b, 0xb3, 0xbd, 0xdd, 0x8a, 0xf4, 0xb4, 0x4b, 0x8d, 0x0c, 0xc4, 0xab, 0xed, 0x30, - 0x16, 0x2e, 0x6c, 0xd3, 0xcd, 0x60, 0xd7, 0x4b, 0xc7, 0x12, 0x79, 0xbb, 0x2d, 0xa0, 0x43, 0x66, 0xc0, 0x9d, 0x97, - 0xf1, 0x1d, 0xbc, 0x2c, 0x9c, 0x6e, 0xfa, 0xc1, 0x13, 0xc0, 0x4c, 0xb8, 0xb4, 0x96, 0xc5, 0x31, 0xe3, 0x09, 0xcc, - 0x1f, 0x2d, 0x7d, 0x91, 0xb7, 0x24, 0xb4, 0x7a, 0x7f, 0x85, 0xd5, 0x08, 0xec, 0x4e, 0xce, 0x3e, 0x66, 0xab, 0xd9, - 0x12, 0x50, 0xf3, 0xaf, 0xb3, 0x02, 0x68, 0xae, 0x59, 0x0b, 0xa6, 0x29, 0xd4, 0x5f, 0xd7, 0xcf, 0xe2, 0x55, 0x9c, - 0x80, 0xea, 0x06, 0xbc, 0x45, 0xee, 0x95, 0xe8, 0x4a, 0xa3, 0x8b, 0xd2, 0x07, 0xca, 0x31, 0xa4, 0xd0, 0xd2, 0xf7, - 0x5e, 0x25, 0xcf, 0x3d, 0x0d, 0xb8, 0xa4, 0x50, 0xf3, 0x64, 0x4b, 0x19, 0x0b, 0x80, 0x85, 0x0e, 0x66, 0x92, 0x6c, - 0x45, 0x77, 0x1a, 0x93, 0x02, 0xde, 0x6a, 0xe0, 0x8f, 0x22, 0xab, 0xe5, 0x5d, 0xb1, 0x0a, 0x0b, 0xc7, 0xfe, 0xba, - 0xdf, 0x8f, 0x1d, 0xfb, 0xeb, 0x4b, 0x45, 0xeb, 0xe2, 0x76, 0x03, 0x48, 0x83, 0x01, 0x44, 0x4e, 0xd5, 0x40, 0xe8, - 0x88, 0x62, 0xbe, 0xef, 0xdf, 0xa9, 0xce, 0x22, 0x41, 0xe8, 0x77, 0xea, 0x75, 0xa4, 0x24, 0xa0, 0x53, 0xab, 0xd9, - 0xc9, 0x40, 0x99, 0x7d, 0x40, 0x40, 0x54, 0x37, 0x23, 0x9b, 0x2f, 0xa4, 0x73, 0xb1, 0x0c, 0x1f, 0x3e, 0xa6, 0x10, - 0x50, 0xb8, 0xa3, 0x46, 0xeb, 0x6d, 0x88, 0x04, 0xca, 0x08, 0x45, 0x8c, 0x79, 0xb1, 0x92, 0x84, 0xcc, 0xc7, 0x0b, - 0x14, 0x5c, 0x59, 0x60, 0x57, 0xce, 0x26, 0xc3, 0x22, 0xe2, 0x2c, 0xdc, 0xff, 0xcd, 0x64, 0x41, 0x50, 0x73, 0xe5, - 0x06, 0x72, 0xdc, 0xc9, 0xe4, 0xed, 0x29, 0xaf, 0x86, 0x8a, 0x89, 0x08, 0x02, 0xc3, 0x0d, 0x3f, 0xe3, 0xe3, 0xa3, - 0x05, 0x01, 0x15, 0x99, 0x31, 0x0b, 0xd1, 0x2f, 0x8e, 0xbf, 0x02, 0xd4, 0x98, 0xd1, 0xd1, 0x53, 0x00, 0x85, 0x85, - 0x80, 0xe8, 0x63, 0x90, 0xd1, 0x56, 0xf0, 0xbb, 0x92, 0xbf, 0x5b, 0x27, 0xbe, 0x0b, 0xfd, 0x5a, 0xd1, 0xcb, 0x18, - 0x18, 0x8e, 0x68, 0x72, 0x18, 0xf2, 0xc1, 0x64, 0x00, 0xda, 0x12, 0x67, 0xf7, 0xb5, 0xb4, 0xe2, 0xfa, 0x74, 0xe9, - 0x74, 0xff, 0xa4, 0x3e, 0x48, 0x22, 0x15, 0xac, 0x90, 0xc4, 0x00, 0x42, 0x59, 0xca, 0x6d, 0xb2, 0x04, 0xcb, 0x0a, - 0xbd, 0xa4, 0xb9, 0x46, 0x49, 0xdc, 0xdd, 0x0c, 0x1c, 0xa3, 0x66, 0x9d, 0x86, 0x45, 0xcb, 0x8d, 0x1a, 0xe0, 0x73, - 0x12, 0x56, 0x9a, 0x1b, 0xce, 0x4c, 0x38, 0x67, 0x3a, 0x5c, 0x1d, 0x73, 0xf6, 0x9a, 0x23, 0x18, 0x47, 0x82, 0x37, - 0x1e, 0xba, 0x64, 0x0a, 0x2a, 0x32, 0x65, 0x1c, 0x4c, 0x7b, 0x80, 0x7b, 0xcf, 0xc1, 0x38, 0x8c, 0x0d, 0x6a, 0x43, - 0xea, 0x53, 0xe7, 0x2e, 0x04, 0x82, 0xb4, 0xd6, 0xcb, 0x7c, 0x86, 0xa7, 0x67, 0x84, 0xb2, 0x3f, 0xe4, 0xf0, 0x01, - 0xf0, 0xb2, 0x24, 0x27, 0x13, 0xfe, 0xf4, 0xf1, 0x6e, 0xa0, 0x2a, 0x3e, 0x08, 0x0e, 0xe2, 0x22, 0x3d, 0x08, 0x06, - 0x15, 0xfc, 0x2a, 0xf9, 0x41, 0x2d, 0xc4, 0xc1, 0x65, 0x5c, 0x1e, 0xc4, 0xab, 0xb8, 0xac, 0x0f, 0x6e, 0xb3, 0x7a, - 0x79, 0xa0, 0x3b, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x07, 0xc1, 0xa0, 0xd4, 0x53, 0xbb, 0x62, 0x85, 0x77, - 0x9c, 0xe9, 0x10, 0x65, 0x81, 0x1f, 0x20, 0xcc, 0x3b, 0x0d, 0x80, 0x4f, 0x5d, 0xb3, 0x94, 0x5e, 0x62, 0xb8, 0x81, - 0x6a, 0xba, 0x86, 0x3e, 0x00, 0x8f, 0xbc, 0xa6, 0x31, 0x2c, 0x81, 0xcb, 0xc1, 0x80, 0xac, 0x21, 0x72, 0xc1, 0x9a, - 0x9a, 0x20, 0x0e, 0xe1, 0x5a, 0xda, 0x69, 0x17, 0x3b, 0x14, 0x76, 0xbb, 0x05, 0x44, 0xe5, 0x09, 0xe9, 0xf7, 0xcd, - 0x37, 0xd4, 0xbd, 0x60, 0x2f, 0xc1, 0xfe, 0xaa, 0xac, 0xc3, 0x44, 0x48, 0xcd, 0xf7, 0x15, 0x3b, 0x19, 0xc8, 0x88, - 0xc3, 0x3b, 0x8e, 0x14, 0x6d, 0x54, 0x2e, 0xc3, 0x9e, 0x2c, 0x3d, 0x5f, 0x89, 0x6b, 0x6e, 0xfd, 0xb8, 0x6a, 0x21, - 0xf2, 0x3a, 0x5b, 0x49, 0xf6, 0x6f, 0xc6, 0x15, 0xf7, 0x07, 0xd6, 0x9f, 0xfe, 0x2b, 0xb8, 0xb6, 0x3a, 0xef, 0x7c, - 0xae, 0x11, 0x39, 0x4b, 0x28, 0x97, 0x34, 0x26, 0x0f, 0x6f, 0xe9, 0xfb, 0xdc, 0xea, 0xdb, 0x4c, 0xa7, 0xf6, 0x59, - 0x85, 0x85, 0x0b, 0xd1, 0x8a, 0xe0, 0xd0, 0x10, 0x0b, 0xff, 0x08, 0xd0, 0xd7, 0x3e, 0x53, 0x41, 0x49, 0x9a, 0xf3, - 0x1a, 0xbd, 0x5b, 0x21, 0xe1, 0xa5, 0x62, 0x97, 0x1e, 0x06, 0x52, 0xc6, 0xed, 0xa1, 0x24, 0x4c, 0x4a, 0x5e, 0x84, - 0xf7, 0x5e, 0x7d, 0x93, 0x7b, 0x1e, 0x62, 0xf4, 0x22, 0xc7, 0x4e, 0x40, 0x5b, 0x77, 0x89, 0xce, 0x86, 0x27, 0x6e, - 0xc3, 0x73, 0xd6, 0xa2, 0xd1, 0x74, 0xc9, 0x92, 0x7e, 0x3f, 0x06, 0x13, 0xef, 0x94, 0xe5, 0xf0, 0x2b, 0x5f, 0xd0, - 0x35, 0x03, 0x4c, 0x31, 0x7a, 0x09, 0x09, 0x29, 0x22, 0x91, 0xac, 0xe5, 0x49, 0xf2, 0x89, 0xee, 0x42, 0x70, 0x84, - 0xcb, 0x59, 0x1a, 0x2d, 0xf7, 0x9a, 0x59, 0x20, 0x79, 0x86, 0xbe, 0xab, 0x60, 0x7b, 0x63, 0x17, 0xa4, 0x9c, 0x1f, - 0x57, 0xd3, 0xc1, 0x80, 0x13, 0x05, 0x37, 0x5e, 0x48, 0x71, 0xad, 0x6a, 0x71, 0xc7, 0x30, 0x16, 0xea, 0xb6, 0x88, - 0xc1, 0x01, 0xbb, 0x68, 0x65, 0xb7, 0x0f, 0xb0, 0xab, 0x1c, 0xef, 0x52, 0x65, 0x77, 0x7a, 0xcc, 0xf8, 0xcb, 0x56, - 0x91, 0x4e, 0x5a, 0xed, 0x27, 0xf2, 0x3e, 0x77, 0xd0, 0xe5, 0x72, 0xac, 0x78, 0xcb, 0x41, 0x45, 0x1e, 0xf3, 0x91, - 0xa4, 0xba, 0x9f, 0xe1, 0x08, 0xf3, 0x60, 0xdd, 0xfa, 0x93, 0x43, 0x5d, 0xe0, 0x10, 0x79, 0x52, 0xaf, 0x29, 0xa0, - 0x7b, 0xaf, 0x1e, 0x77, 0xf5, 0xdb, 0xd0, 0x5d, 0xa0, 0x44, 0x3b, 0x15, 0x7b, 0x7e, 0x4c, 0xd4, 0xea, 0x4c, 0x3d, - 0xa1, 0x7f, 0xad, 0xc5, 0xfd, 0x85, 0x76, 0x15, 0xf7, 0xbd, 0xcb, 0x67, 0x1c, 0xea, 0xec, 0x86, 0x50, 0x00, 0xae, - 0xda, 0xd1, 0xa9, 0x6b, 0x43, 0x7a, 0xa9, 0x44, 0x37, 0xc1, 0xc1, 0xf6, 0xfa, 0x8c, 0xa3, 0xe8, 0x47, 0xab, 0x91, - 0x6f, 0xa3, 0xea, 0xb1, 0x18, 0xc4, 0x8f, 0x4b, 0xba, 0x8c, 0xaa, 0xc7, 0xe5, 0x20, 0x7e, 0x2c, 0x9a, 0x66, 0xf7, - 0x5c, 0xd9, 0xdf, 0x47, 0xe4, 0x59, 0x77, 0xf6, 0x52, 0x01, 0x1b, 0x03, 0xcf, 0xae, 0x05, 0x84, 0x53, 0x70, 0x44, - 0xb6, 0x86, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x61, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, 0x59, 0xff, 0xe8, - 0xc3, 0x29, 0x10, 0xd0, 0xed, 0xb6, 0x59, 0x57, 0x6b, 0x40, 0x31, 0x0d, 0xc7, 0xfc, 0xb0, 0x1c, 0xdd, 0xba, 0xee, - 0xfa, 0x87, 0xe5, 0x68, 0x49, 0x86, 0x13, 0x3d, 0xf9, 0xf1, 0xc9, 0x78, 0x16, 0x47, 0x93, 0xa6, 0xe3, 0xb4, 0x50, - 0xf8, 0xa7, 0xce, 0x2d, 0x14, 0x81, 0x53, 0x31, 0x82, 0x23, 0xa7, 0xca, 0x49, 0xc9, 0xc3, 0xf0, 0x3f, 0xa8, 0x77, - 0xb4, 0x69, 0xaf, 0xe3, 0x3a, 0x59, 0x66, 0xc5, 0x95, 0x0a, 0x1f, 0xae, 0xa2, 0x8b, 0x9b, 0x80, 0x76, 0xce, 0x65, - 0xda, 0xf2, 0xeb, 0xc4, 0xa3, 0x27, 0xb6, 0x66, 0x06, 0xdc, 0xba, 0x1b, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, - 0xc4, 0xdc, 0xfe, 0x55, 0xda, 0xfc, 0x4a, 0xda, 0x67, 0xc9, 0x48, 0xd1, 0x26, 0x23, 0x35, 0x18, 0x61, 0x8a, 0x22, - 0x89, 0xeb, 0xb0, 0x80, 0x20, 0xd8, 0x9f, 0x51, 0x5c, 0x8b, 0xa5, 0x77, 0x1a, 0x84, 0x09, 0xa6, 0x0b, 0xca, 0xaf, - 0x6e, 0xe7, 0xb6, 0xd2, 0x62, 0x8f, 0xe4, 0xf7, 0xb9, 0xb5, 0x5d, 0x51, 0xe4, 0xef, 0xf3, 0x06, 0xd4, 0x03, 0xa2, - 0xdc, 0xd7, 0x47, 0x29, 0x70, 0xd2, 0xe2, 0x86, 0x02, 0xa3, 0x17, 0x74, 0x75, 0x22, 0x77, 0xec, 0xd4, 0x9c, 0xa9, - 0x98, 0xc9, 0xb8, 0xf2, 0x7e, 0xcf, 0xdc, 0x07, 0x4d, 0x41, 0x2b, 0x30, 0xf0, 0xd6, 0x67, 0x3c, 0x3a, 0xd0, 0xdd, - 0x6a, 0x9d, 0x16, 0x6c, 0x16, 0xd4, 0x65, 0xdd, 0xb6, 0xf1, 0xa0, 0x11, 0x07, 0x45, 0xb2, 0x2a, 0x54, 0x4b, 0x78, - 0x22, 0x10, 0x30, 0x65, 0xd7, 0x3c, 0xd2, 0x82, 0x9a, 0xde, 0x84, 0xc2, 0x86, 0x82, 0xbf, 0x52, 0x54, 0xd3, 0x9b, - 0x50, 0x9f, 0x89, 0x53, 0x0c, 0x22, 0x98, 0x11, 0x9b, 0xfd, 0x16, 0x50, 0x7f, 0x6b, 0x46, 0x9b, 0xa6, 0x31, 0xda, - 0x2a, 0xe4, 0x92, 0x22, 0x69, 0xf9, 0x6f, 0xd5, 0x54, 0x50, 0x52, 0xcb, 0x45, 0x6f, 0xe2, 0xbb, 0xe8, 0xf1, 0x4c, - 0x4b, 0x02, 0xa5, 0x5b, 0xee, 0x18, 0xfd, 0x21, 0x0c, 0xf0, 0x88, 0x8e, 0x13, 0x0b, 0xe6, 0x56, 0x27, 0x2c, 0x9b, - 0x57, 0x8b, 0xd1, 0x4a, 0x40, 0xd8, 0xe0, 0x63, 0x96, 0xcd, 0x0b, 0xf5, 0x10, 0xba, 0xc2, 0xd2, 0xb7, 0x60, 0x17, - 0x1b, 0xac, 0x44, 0x15, 0x80, 0xef, 0x05, 0xdd, 0xac, 0x44, 0x15, 0x09, 0xd9, 0xfd, 0xb8, 0xc1, 0x12, 0x64, 0x5a, - 0x29, 0xd3, 0x92, 0x06, 0x0b, 0x02, 0x5f, 0x55, 0x55, 0x3e, 0x24, 0xdb, 0x0a, 0xe4, 0x53, 0x47, 0x0d, 0x38, 0x05, - 0xb2, 0x0a, 0x2c, 0x48, 0x80, 0xca, 0xd0, 0x56, 0x81, 0x69, 0x25, 0xa6, 0xe9, 0x2a, 0x6c, 0x94, 0xd9, 0xa1, 0xd0, - 0xeb, 0x25, 0x9f, 0xc5, 0x83, 0x30, 0x19, 0xc6, 0xe4, 0x31, 0x42, 0xed, 0x1f, 0xe6, 0x51, 0xac, 0xe4, 0x92, 0x2b, - 0xeb, 0x17, 0x7f, 0xfb, 0x09, 0x7b, 0xdd, 0x73, 0x0c, 0x16, 0x60, 0x2d, 0x6d, 0xaf, 0xb3, 0xe2, 0x9d, 0x68, 0x05, - 0xc7, 0xc1, 0x2c, 0xd2, 0x61, 0xd5, 0x91, 0x23, 0xea, 0x8b, 0x5c, 0x7b, 0x17, 0x21, 0x72, 0x90, 0xde, 0x63, 0x80, - 0xdd, 0x08, 0x5f, 0x87, 0xc6, 0xe6, 0x56, 0x55, 0x88, 0xbf, 0x51, 0x22, 0xf1, 0x93, 0x10, 0x1f, 0xd7, 0x2b, 0x99, - 0xab, 0xd6, 0x78, 0xac, 0xaa, 0x19, 0x3c, 0x53, 0xbe, 0xc7, 0xca, 0xbf, 0xb5, 0xdd, 0x1c, 0xe7, 0x3d, 0x78, 0xd0, - 0xba, 0xdf, 0x3a, 0x12, 0x42, 0x73, 0xe5, 0x24, 0x4d, 0x47, 0x8d, 0x8e, 0x99, 0xac, 0x16, 0x95, 0x30, 0xb9, 0x3b, - 0xa5, 0x63, 0xa0, 0xa2, 0x03, 0xb8, 0x96, 0xa8, 0x0e, 0x7a, 0x52, 0xb2, 0x31, 0x1c, 0x71, 0x06, 0x07, 0xed, 0x38, - 0x46, 0xf1, 0x72, 0x2e, 0xc5, 0xcb, 0xf9, 0x09, 0xe3, 0x00, 0xad, 0x05, 0x48, 0xf5, 0x0a, 0xf6, 0x33, 0x97, 0xb0, - 0xc0, 0xfa, 0xce, 0x77, 0x64, 0x80, 0x0c, 0x71, 0xb2, 0x39, 0x4e, 0xf6, 0xb8, 0x51, 0x73, 0x5f, 0xe1, 0xe3, 0xa4, - 0x59, 0x38, 0x75, 0x15, 0xed, 0xba, 0x96, 0xac, 0x98, 0x97, 0x83, 0x09, 0x04, 0x65, 0x29, 0xe6, 0xe5, 0x70, 0xb2, - 0xa0, 0x39, 0xfc, 0x58, 0x78, 0xe8, 0x10, 0xcb, 0x41, 0x02, 0x97, 0xce, 0x1e, 0x03, 0xde, 0x50, 0x28, 0x71, 0x37, - 0xd6, 0x91, 0x63, 0x1d, 0xe5, 0x61, 0x18, 0x03, 0xae, 0xac, 0x15, 0x78, 0xef, 0xbf, 0x3e, 0xfa, 0x80, 0xac, 0xca, - 0x15, 0x5e, 0x8e, 0x72, 0xd7, 0x95, 0x46, 0x5d, 0x52, 0x7a, 0x95, 0x13, 0x3c, 0x95, 0x6c, 0xb7, 0x3d, 0x63, 0x4f, - 0xe5, 0x20, 0xf1, 0x8e, 0x11, 0xbd, 0x98, 0x7a, 0x99, 0x39, 0x81, 0x33, 0xdb, 0x5e, 0xb6, 0x31, 0x3f, 0x76, 0x80, - 0x83, 0x45, 0x10, 0x12, 0x37, 0x84, 0x61, 0x62, 0x27, 0xc5, 0x50, 0x09, 0xe1, 0xba, 0x16, 0x5e, 0xc7, 0x69, 0x19, - 0x83, 0x8b, 0xb4, 0xb2, 0x4d, 0xdc, 0x43, 0xd7, 0x1d, 0x3f, 0xe6, 0x56, 0xc7, 0x68, 0xcb, 0x7c, 0xb8, 0xa3, 0xd3, - 0x07, 0x16, 0x03, 0x50, 0xf7, 0x60, 0x56, 0xb7, 0xcf, 0x24, 0xae, 0x4f, 0xbb, 0x8a, 0x90, 0x08, 0x44, 0x51, 0x2a, - 0x23, 0x4c, 0xff, 0x4e, 0x73, 0x59, 0x4d, 0xeb, 0x07, 0x79, 0xe6, 0x90, 0x67, 0xa1, 0xb3, 0x3d, 0x68, 0xed, 0xef, - 0x06, 0xed, 0xc4, 0x6d, 0xf7, 0xce, 0xff, 0x5b, 0xd6, 0xb5, 0xd5, 0x9a, 0xea, 0x71, 0xbb, 0xfa, 0x81, 0xb7, 0x57, - 0x7b, 0x32, 0x06, 0xcc, 0x4a, 0x38, 0x67, 0x54, 0xc5, 0xcb, 0x8c, 0x57, 0x78, 0x52, 0xad, 0x3c, 0x1f, 0xef, 0xdb, - 0x6c, 0xa4, 0x1f, 0xc8, 0x14, 0x10, 0xcf, 0x6f, 0x53, 0xad, 0x3e, 0x4e, 0x51, 0x02, 0xfe, 0x4e, 0xc5, 0x37, 0xa2, - 0x1f, 0xcd, 0x8b, 0x2b, 0x5e, 0xbf, 0xbd, 0x2d, 0xf4, 0x8b, 0xe7, 0x46, 0xe7, 0x4f, 0x5f, 0x97, 0x2e, 0x74, 0x38, - 0x6a, 0xef, 0xa0, 0xc8, 0x82, 0x55, 0x27, 0x13, 0x2d, 0x6b, 0xab, 0x66, 0x1f, 0x25, 0x5c, 0x4c, 0x54, 0xa3, 0x67, - 0x9d, 0x39, 0x61, 0x4a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x96, 0x0c, 0xd4, 0x69, 0x52, 0x88, 0x1e, 0x56, 0x33, - 0x8c, 0x57, 0x0c, 0xa0, 0x30, 0xa5, 0x04, 0x51, 0xb4, 0x06, 0xc1, 0x40, 0x13, 0xfa, 0xfd, 0xdb, 0x54, 0x65, 0xa0, - 0x45, 0x33, 0x15, 0x20, 0xaa, 0x83, 0x68, 0xab, 0xbc, 0x0c, 0x7f, 0x5c, 0xd2, 0x22, 0xa3, 0x79, 0x45, 0x97, 0x15, - 0x4d, 0x32, 0x7a, 0xc9, 0xa5, 0xa8, 0x78, 0x5d, 0x31, 0x49, 0xdb, 0x35, 0x61, 0xff, 0x97, 0x47, 0xd7, 0x5b, 0xb1, - 0xd6, 0xd0, 0xee, 0x04, 0x19, 0xa1, 0xf9, 0x42, 0x05, 0x21, 0x43, 0xe5, 0x24, 0x74, 0xad, 0x56, 0x78, 0x05, 0x36, - 0x99, 0x66, 0xa3, 0x65, 0x5c, 0x85, 0x81, 0xf9, 0x2a, 0x30, 0x98, 0x1c, 0x98, 0x74, 0xb6, 0xbe, 0x78, 0x26, 0xae, - 0x57, 0xa2, 0xe0, 0x45, 0x2d, 0x21, 0xfa, 0x35, 0xee, 0xbb, 0x8e, 0xab, 0xce, 0xfc, 0x5a, 0xe9, 0x43, 0xdf, 0xba, - 0xac, 0x8d, 0xfd, 0x42, 0xe3, 0x18, 0xec, 0x7c, 0x44, 0x34, 0xa4, 0x41, 0xad, 0x5a, 0x1c, 0xea, 0x00, 0x5d, 0x2a, - 0xa4, 0x90, 0x21, 0x53, 0x99, 0x2c, 0x41, 0xc6, 0x37, 0x7e, 0x2f, 0x44, 0x3d, 0xfa, 0x73, 0xcd, 0xcb, 0xfb, 0x33, - 0x9e, 0x73, 0x1c, 0xa3, 0x20, 0x89, 0x8b, 0x9b, 0xb8, 0x0a, 0x88, 0x6b, 0x79, 0x15, 0x1c, 0xa5, 0x3a, 0x6c, 0xcc, - 0x4e, 0xd5, 0xa8, 0xf5, 0x12, 0xe8, 0x2b, 0x23, 0x7d, 0x63, 0x30, 0x34, 0x11, 0x95, 0xd0, 0xf7, 0x4a, 0xdd, 0xd3, - 0xea, 0x86, 0x01, 0xc4, 0x9f, 0x4b, 0xbd, 0x50, 0xeb, 0xb5, 0x1f, 0x73, 0x43, 0x47, 0x08, 0x1a, 0x7d, 0xd5, 0x2c, - 0x1a, 0xc7, 0x2d, 0x4d, 0x46, 0xc6, 0x8d, 0x36, 0x39, 0xbf, 0x02, 0x19, 0x9f, 0x35, 0x17, 0x9a, 0x34, 0x0d, 0x95, - 0x50, 0x85, 0xd1, 0xe6, 0xce, 0x4b, 0xa7, 0xf7, 0xe0, 0xce, 0xa6, 0xcd, 0x8e, 0x94, 0x4b, 0x63, 0x43, 0x4b, 0x5e, - 0xad, 0x44, 0x51, 0x41, 0x18, 0xe7, 0xde, 0x98, 0x5e, 0xc7, 0x59, 0x51, 0xc7, 0x59, 0x71, 0x5a, 0xad, 0x78, 0x52, - 0xbf, 0x87, 0x5b, 0x9c, 0xb4, 0xba, 0x69, 0x2a, 0xb8, 0xd2, 0x25, 0x07, 0x18, 0x4c, 0x4d, 0xc6, 0x3d, 0xb6, 0x06, - 0x17, 0xf5, 0xef, 0xd1, 0x52, 0x60, 0x2c, 0x54, 0x55, 0x7c, 0x7c, 0x51, 0x89, 0x7c, 0x5d, 0x83, 0x76, 0xf7, 0xb2, - 0x8e, 0x8e, 0x9e, 0xac, 0xee, 0xa6, 0xf2, 0x06, 0x13, 0x3d, 0x39, 0x5a, 0xdd, 0xf5, 0xb2, 0xeb, 0x95, 0x28, 0xeb, - 0xb8, 0xa8, 0xa7, 0x12, 0x91, 0x2c, 0x89, 0xf3, 0x24, 0x9c, 0x8c, 0xc7, 0x5f, 0x1c, 0x0c, 0x0f, 0x20, 0x03, 0x99, - 0xfe, 0x35, 0x94, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x15, 0xf2, 0x6e, 0x17, 0x8d, 0x26, 0x0d, 0xd6, 0x33, 0x4c, - 0xd4, 0xcc, 0x8c, 0xf8, 0xdd, 0x2a, 0x2e, 0x52, 0x88, 0x5f, 0xa7, 0x8a, 0x3f, 0x7a, 0x32, 0xf6, 0xca, 0x37, 0x9f, - 0x3e, 0x6d, 0x7e, 0x6f, 0x74, 0x58, 0x6b, 0xdd, 0xee, 0x67, 0xbf, 0x1f, 0xcb, 0xf9, 0x3e, 0x39, 0x3e, 0x54, 0x3f, - 0x7e, 0x6f, 0x9a, 0xe9, 0xeb, 0x32, 0x9c, 0xff, 0x33, 0x94, 0xf3, 0x79, 0x5a, 0x96, 0xf1, 0x7d, 0x43, 0x16, 0x74, - 0x5d, 0x59, 0x6f, 0x12, 0xea, 0x6c, 0x03, 0x7a, 0x44, 0xa6, 0xeb, 0x8a, 0xc1, 0x37, 0xef, 0xeb, 0x30, 0xe0, 0xd5, - 0x6a, 0xc8, 0x8b, 0x3a, 0xab, 0xef, 0x87, 0x98, 0x27, 0xc0, 0x4f, 0x35, 0x6f, 0xf6, 0xac, 0xd4, 0xc4, 0xe6, 0xb2, - 0xe4, 0xfc, 0x2f, 0x1e, 0x4a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1c, 0x8c, 0xc9, 0xd7, 0x54, 0x75, 0x66, - 0xf2, 0x35, 0x98, 0x20, 0x65, 0xed, 0x6f, 0xa4, 0x71, 0x62, 0x34, 0xa6, 0x37, 0x2f, 0xf3, 0x6c, 0x05, 0x4c, 0xf0, - 0x52, 0xfd, 0x68, 0x08, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xb3, 0x92, 0x8e, 0x46, 0xa3, 0x8f, 0x59, 0x43, - 0xe8, 0x65, 0xd5, 0xf1, 0xfe, 0x3d, 0xa7, 0x17, 0x22, 0xbd, 0x8f, 0x82, 0x80, 0x2e, 0xb3, 0x34, 0xe5, 0x85, 0x2c, - 0xeb, 0x2c, 0x6d, 0xe7, 0x95, 0x2d, 0x44, 0xe0, 0x1f, 0xd5, 0x46, 0x84, 0x20, 0x22, 0xf4, 0xed, 0x4e, 0xcf, 0x46, - 0xa3, 0xd1, 0x59, 0xaa, 0xab, 0xb5, 0x0c, 0xf9, 0x6b, 0x34, 0x1f, 0xb0, 0x76, 0xf9, 0x60, 0x7d, 0xa3, 0xa3, 0x9d, - 0x1c, 0xfe, 0xf7, 0x70, 0x36, 0x1f, 0x0f, 0xbf, 0x1d, 0x2d, 0x1e, 0x1f, 0xd2, 0x20, 0x70, 0x41, 0xab, 0x43, 0x65, - 0xcd, 0x31, 0x2d, 0x8e, 0xc7, 0x53, 0x52, 0x0c, 0xd8, 0x13, 0xe3, 0x4b, 0xf3, 0xc5, 0x13, 0x40, 0x22, 0x45, 0x11, - 0x6a, 0x60, 0xa5, 0x7f, 0x78, 0x15, 0x79, 0x55, 0x00, 0x3e, 0x9a, 0x89, 0x64, 0xa0, 0xb5, 0x80, 0xe3, 0x08, 0xca, - 0x6b, 0x8c, 0x69, 0x44, 0x8f, 0xb1, 0x4c, 0x47, 0x05, 0x1d, 0x4f, 0xab, 0xdb, 0xac, 0x4e, 0x96, 0x18, 0xd8, 0x28, - 0xae, 0x78, 0xf0, 0x45, 0x10, 0x15, 0xec, 0xe8, 0xe9, 0x54, 0xc2, 0xfb, 0x62, 0x52, 0xca, 0xaf, 0x20, 0xf1, 0xdb, - 0x31, 0x42, 0xa0, 0x12, 0xe5, 0xb1, 0x88, 0x35, 0xbe, 0xcc, 0x45, 0x0c, 0x1e, 0x9c, 0x95, 0xe2, 0x59, 0xcc, 0x49, - 0x60, 0xec, 0x2f, 0x5a, 0xcd, 0x11, 0xd0, 0x9c, 0x50, 0x30, 0x71, 0x58, 0x50, 0xf1, 0xc5, 0x04, 0xbd, 0x82, 0xc0, - 0xad, 0x3a, 0x82, 0xe3, 0xce, 0x58, 0x36, 0xa8, 0xe5, 0x93, 0xb2, 0xc3, 0xf9, 0xff, 0xae, 0xe8, 0x62, 0x70, 0x68, - 0x87, 0xe6, 0xad, 0x72, 0x5f, 0xad, 0x91, 0x51, 0xaa, 0xc3, 0x67, 0x29, 0x31, 0xc6, 0xa7, 0x9c, 0x9d, 0x6c, 0x74, - 0x77, 0x46, 0x75, 0x99, 0x5d, 0x87, 0x44, 0xf5, 0xca, 0x82, 0x62, 0x06, 0x51, 0x36, 0xc2, 0xf5, 0x03, 0xd6, 0x22, - 0x4e, 0x27, 0x6f, 0x78, 0x59, 0x67, 0x89, 0x7c, 0x7f, 0xe3, 0xbd, 0x07, 0x6a, 0x20, 0x1b, 0xf4, 0xae, 0x64, 0x30, - 0xcf, 0x6f, 0x4b, 0x00, 0xed, 0xac, 0x78, 0x79, 0xc3, 0x5d, 0xba, 0x11, 0x04, 0x8d, 0x6d, 0xe6, 0x95, 0x17, 0x6c, - 0x02, 0xbe, 0x7a, 0x57, 0x02, 0xe6, 0x46, 0x08, 0x52, 0x53, 0x08, 0x85, 0x03, 0x17, 0xf8, 0xba, 0x2e, 0xb3, 0x8b, - 0x75, 0xcd, 0x31, 0xd8, 0x47, 0x61, 0xb5, 0x98, 0xd2, 0x09, 0x8f, 0x87, 0x01, 0xfe, 0x08, 0xa8, 0x0c, 0xb8, 0xa1, - 0x3d, 0xec, 0xe0, 0x85, 0xfc, 0x65, 0xdf, 0xc8, 0x3d, 0xc2, 0x5e, 0xa7, 0x21, 0x04, 0xd7, 0xc1, 0x87, 0x00, 0x96, - 0x14, 0xa1, 0x6f, 0xf1, 0x54, 0x0d, 0x83, 0xcb, 0x3c, 0x5b, 0xa9, 0xa4, 0x7a, 0xd4, 0xd1, 0x7c, 0x28, 0xb5, 0x23, - 0x39, 0xa0, 0x4e, 0x7a, 0x8c, 0xe9, 0xa5, 0x4c, 0x97, 0x45, 0x59, 0x23, 0x94, 0x77, 0x6a, 0x62, 0x6c, 0x98, 0x3e, - 0x0e, 0x91, 0x5f, 0xde, 0x95, 0x32, 0xf4, 0x0b, 0x5f, 0x00, 0xf8, 0x15, 0xdc, 0xee, 0x77, 0xe3, 0xbb, 0xc8, 0xec, - 0xe7, 0x9c, 0x1d, 0xfe, 0xf7, 0x3c, 0x1e, 0xfe, 0x35, 0x1e, 0x7e, 0xbb, 0x18, 0x84, 0x43, 0xf3, 0x93, 0x3c, 0x7e, - 0x74, 0x48, 0x5f, 0x72, 0xc3, 0x95, 0xc0, 0xc2, 0xf7, 0x82, 0xdb, 0xc8, 0x95, 0x10, 0x44, 0x01, 0xde, 0x28, 0xec, - 0x6a, 0x9c, 0x00, 0xc0, 0x5f, 0xf0, 0x5f, 0x01, 0x1a, 0x09, 0xd9, 0x8b, 0x06, 0xe8, 0x07, 0xe4, 0xef, 0x93, 0xaf, - 0x3c, 0x03, 0x39, 0x10, 0x4f, 0xc8, 0x18, 0x28, 0x44, 0x95, 0x31, 0x91, 0xb0, 0xbf, 0x26, 0xfb, 0x76, 0xdb, 0x6b, - 0x4b, 0x7e, 0xf0, 0x4b, 0x37, 0xd3, 0x44, 0xcf, 0x3b, 0xdc, 0x50, 0x56, 0x62, 0x15, 0x22, 0x36, 0x9e, 0xfa, 0x95, - 0x33, 0x88, 0x35, 0x79, 0x93, 0x81, 0x0f, 0x83, 0xf9, 0x62, 0x3c, 0x03, 0x69, 0x11, 0xdc, 0x71, 0x4a, 0x7e, 0x99, - 0x81, 0x5b, 0x73, 0x11, 0xe3, 0x05, 0xdb, 0x2c, 0x89, 0x7e, 0xbf, 0x97, 0x67, 0x61, 0xae, 0x70, 0x96, 0xf3, 0x46, - 0x8b, 0xdd, 0x51, 0x27, 0x0c, 0xe2, 0x76, 0x35, 0x04, 0x43, 0x39, 0x04, 0x65, 0x47, 0x5b, 0x6c, 0xbd, 0xa6, 0x9e, - 0x52, 0xf7, 0x56, 0xd6, 0x57, 0x8e, 0xfe, 0x10, 0x59, 0x81, 0x85, 0xb4, 0x6b, 0x8e, 0x55, 0xcd, 0x31, 0xd2, 0x9e, - 0x7e, 0xbf, 0xf2, 0xc8, 0x4f, 0x67, 0xe1, 0x41, 0x20, 0x4b, 0x15, 0x3b, 0x65, 0x51, 0x6e, 0x4a, 0x73, 0xc6, 0xb0, - 0xa1, 0x79, 0x66, 0xe2, 0xba, 0xcc, 0x7a, 0xbd, 0x30, 0x44, 0x87, 0x46, 0x2c, 0x15, 0x6b, 0x83, 0xf0, 0x3e, 0x3a, - 0x61, 0x74, 0x0d, 0xb2, 0xba, 0xf0, 0x9c, 0x13, 0xe4, 0xcb, 0xc0, 0x64, 0x4d, 0x56, 0xeb, 0xe4, 0x84, 0x47, 0x2f, - 0x5f, 0x36, 0x82, 0x06, 0x39, 0x49, 0x51, 0x6f, 0x62, 0x77, 0xec, 0xa3, 0x16, 0x52, 0xe3, 0xa6, 0x99, 0xf6, 0x14, - 0xa9, 0xe8, 0xb1, 0x5e, 0x2d, 0x7f, 0x81, 0x65, 0x81, 0x21, 0x1f, 0x84, 0xf6, 0x14, 0xad, 0xc0, 0x0c, 0x37, 0x26, - 0x83, 0xa6, 0x1f, 0x16, 0x6d, 0x11, 0x3a, 0x23, 0xb7, 0x25, 0x84, 0x6d, 0x1b, 0x84, 0xb5, 0xf3, 0x44, 0xbe, 0x78, - 0xe2, 0x30, 0xc2, 0x21, 0xd7, 0x9b, 0xb9, 0xf2, 0x30, 0xcc, 0xaf, 0x85, 0xdf, 0x3c, 0xd5, 0x5c, 0x27, 0x2a, 0x66, - 0x05, 0xdb, 0xed, 0xb2, 0x22, 0xf8, 0xf7, 0x63, 0x36, 0xc3, 0xbf, 0x59, 0xbf, 0xdf, 0x0b, 0xf1, 0x17, 0xc7, 0xe0, - 0x3d, 0xf3, 0x6a, 0xc1, 0x3e, 0x82, 0x4c, 0x85, 0x44, 0x98, 0x2a, 0x8d, 0xdf, 0x58, 0x0d, 0x16, 0x70, 0xfa, 0x03, - 0x99, 0x0b, 0x33, 0x99, 0xcb, 0x8b, 0x6d, 0xc8, 0x69, 0x6b, 0x9c, 0xb2, 0x51, 0x96, 0x48, 0xd7, 0x85, 0x6c, 0x14, - 0xe7, 0x59, 0x5c, 0xf1, 0x6a, 0xbb, 0x55, 0x87, 0x63, 0x52, 0x72, 0xf4, 0x2b, 0x40, 0x2a, 0x55, 0xb0, 0x8e, 0x54, - 0x3b, 0xfe, 0x22, 0x2c, 0x71, 0x9f, 0xf2, 0x79, 0xb9, 0x30, 0x7b, 0x6b, 0x5e, 0x2e, 0x98, 0xbc, 0x95, 0xf6, 0xc2, - 0x12, 0x9a, 0x57, 0x10, 0xb2, 0xc1, 0x54, 0xc7, 0xa2, 0x35, 0x66, 0xd5, 0xbc, 0x5c, 0x40, 0x18, 0x99, 0x72, 0x01, - 0x36, 0x53, 0xbc, 0x00, 0x2f, 0x92, 0x18, 0x60, 0xe2, 0x62, 0x32, 0x85, 0x78, 0xe6, 0xb2, 0x9c, 0x78, 0xa1, 0xef, - 0x97, 0x89, 0x45, 0xca, 0x80, 0x57, 0x8d, 0x46, 0x13, 0x33, 0x0d, 0x47, 0x9d, 0x20, 0x27, 0x3a, 0xbf, 0x9b, 0x5a, - 0x11, 0x62, 0x4f, 0x1c, 0x01, 0x97, 0x15, 0xd3, 0x85, 0x17, 0x1d, 0x88, 0x31, 0x72, 0x70, 0x8a, 0x4f, 0x0c, 0x8e, - 0xc2, 0xe0, 0xdc, 0x38, 0x27, 0x48, 0x19, 0xc6, 0x64, 0x23, 0xd8, 0xb5, 0x08, 0xab, 0x79, 0xbc, 0x00, 0x65, 0x5d, - 0xbc, 0x00, 0xcb, 0x1a, 0x6d, 0x80, 0x09, 0xf2, 0x2a, 0xee, 0x84, 0x7e, 0xa2, 0xb8, 0x42, 0x84, 0x63, 0xe5, 0xfa, - 0xa8, 0x6c, 0x87, 0xbe, 0xc0, 0xeb, 0xbd, 0x34, 0xc7, 0xcd, 0x7a, 0x2c, 0x10, 0xd8, 0x10, 0x30, 0x36, 0x52, 0x69, - 0xb2, 0xb5, 0xf6, 0x8d, 0x9e, 0x07, 0x3e, 0xcd, 0x46, 0x85, 0xa8, 0xcf, 0x2f, 0x41, 0x84, 0xe2, 0xa2, 0xc1, 0x23, - 0xbf, 0x88, 0x3b, 0x4b, 0xbf, 0x35, 0x2d, 0x2a, 0xd8, 0xc9, 0x06, 0x40, 0xfa, 0x54, 0xb4, 0x28, 0x29, 0xa7, 0x28, - 0x48, 0x63, 0x37, 0x05, 0xac, 0x24, 0x77, 0x01, 0x43, 0xb0, 0xb1, 0x83, 0xca, 0xea, 0x14, 0x11, 0x49, 0x02, 0x91, - 0x15, 0xc3, 0x82, 0xe2, 0xd8, 0x16, 0x88, 0xfa, 0x69, 0xca, 0x32, 0x83, 0xa1, 0xa3, 0xe2, 0x3e, 0x4f, 0x1d, 0x4a, - 0x14, 0x04, 0x54, 0x0d, 0x39, 0x48, 0x6c, 0x4d, 0x03, 0xe1, 0x01, 0x79, 0x44, 0x67, 0xac, 0xbf, 0xcf, 0x3a, 0xcf, - 0x2e, 0x34, 0x47, 0xe5, 0x6a, 0x57, 0xe8, 0x31, 0xc2, 0x93, 0x4c, 0xc3, 0xe4, 0x3b, 0xe7, 0x99, 0x56, 0x53, 0xf4, - 0x1c, 0x7c, 0xb2, 0x53, 0x8c, 0x48, 0xb7, 0x67, 0xd0, 0x75, 0xf0, 0xaa, 0x0e, 0x1b, 0xed, 0x5a, 0x42, 0x48, 0xe8, - 0x5a, 0x14, 0x31, 0xeb, 0x19, 0x03, 0xea, 0xed, 0xb6, 0xa7, 0xe6, 0x6a, 0xff, 0xdc, 0x6d, 0xb7, 0x3d, 0xec, 0xd6, - 0xf3, 0xb4, 0xdb, 0x0a, 0xbc, 0x96, 0x1f, 0xb4, 0xc7, 0x9f, 0xdb, 0xf1, 0xe7, 0x1a, 0xc9, 0xa3, 0xb0, 0x34, 0xd3, - 0xd4, 0x07, 0xe1, 0x70, 0xd3, 0x7b, 0xaf, 0x49, 0xdf, 0x67, 0xa1, 0xa0, 0x97, 0x95, 0x57, 0x5d, 0x63, 0x4d, 0x2a, - 0x1f, 0x5c, 0xff, 0x0f, 0xaf, 0x02, 0x3c, 0xe2, 0xe4, 0xce, 0xde, 0xdb, 0xa0, 0xd2, 0x6b, 0x0b, 0x47, 0x8a, 0xd0, - 0x03, 0x92, 0xb0, 0xaf, 0x65, 0x2d, 0x6e, 0xf3, 0x2c, 0x7b, 0x98, 0x3e, 0xbd, 0x4a, 0x5d, 0xab, 0x7b, 0xbb, 0xcc, - 0x32, 0x7d, 0xe0, 0xd5, 0x14, 0x07, 0x34, 0xea, 0xa2, 0x7d, 0xd7, 0x59, 0x55, 0x81, 0x97, 0x07, 0x5c, 0x9f, 0xcf, - 0xb8, 0x0b, 0x37, 0x77, 0x55, 0xfb, 0x9b, 0xf4, 0x2c, 0x9b, 0x67, 0x8b, 0xed, 0x36, 0xc4, 0xbf, 0x5d, 0x2d, 0xb2, - 0x34, 0x79, 0x0e, 0x3a, 0x3c, 0x8c, 0xdc, 0xc3, 0x54, 0xe3, 0x9c, 0xcd, 0xff, 0xb2, 0xf2, 0x9c, 0x04, 0x4e, 0x81, - 0x5e, 0xcc, 0x1e, 0x81, 0x0c, 0x46, 0x3b, 0xf5, 0x57, 0x33, 0xb5, 0x66, 0x20, 0xfa, 0x56, 0x15, 0x01, 0x8e, 0x2e, - 0x36, 0x12, 0x8d, 0x2c, 0x38, 0x69, 0x08, 0x58, 0x6c, 0x9a, 0xf2, 0x3e, 0x18, 0xda, 0x56, 0x97, 0xf7, 0xce, 0x92, - 0xe6, 0xb8, 0x0e, 0xac, 0x6d, 0xbf, 0x1e, 0x62, 0x5d, 0x76, 0xbd, 0x40, 0xee, 0x97, 0x37, 0xb4, 0x37, 0x6e, 0x12, - 0x98, 0xb5, 0x4d, 0x63, 0x18, 0x3f, 0x53, 0xfa, 0x4f, 0x6a, 0x70, 0xa5, 0xf1, 0xd3, 0x5c, 0x5b, 0x25, 0x98, 0x7d, - 0xe3, 0xf8, 0x0e, 0x40, 0x38, 0x36, 0x97, 0x1e, 0x9f, 0x65, 0x0e, 0x3d, 0x06, 0xa2, 0xa3, 0x3f, 0x2a, 0xec, 0x47, - 0x66, 0xf7, 0xba, 0x01, 0xf0, 0xe6, 0x75, 0xbb, 0xa0, 0x79, 0xb1, 0x80, 0x40, 0xa2, 0x4e, 0x79, 0xa5, 0xe1, 0x33, - 0x63, 0x76, 0x05, 0x64, 0xa8, 0x24, 0x60, 0x93, 0xd4, 0x75, 0x2e, 0xc4, 0xb2, 0xc3, 0xd2, 0x7c, 0x24, 0x61, 0x27, - 0x21, 0xa0, 0xbd, 0x06, 0xc1, 0x2c, 0xf8, 0xaf, 0x60, 0x50, 0x0c, 0x82, 0x28, 0x88, 0x82, 0x80, 0x0c, 0x4a, 0xf8, - 0x85, 0x38, 0x63, 0x04, 0x63, 0x94, 0x40, 0x87, 0xdf, 0x71, 0xe6, 0x32, 0x22, 0x2f, 0xbc, 0x30, 0x96, 0x76, 0x00, - 0x2e, 0x84, 0xc8, 0x79, 0x8c, 0x3e, 0x16, 0xef, 0x38, 0xcb, 0x08, 0x7d, 0xe7, 0x9c, 0xca, 0x8f, 0xb8, 0x17, 0xdc, - 0x6e, 0x77, 0xd8, 0x5e, 0xf2, 0x30, 0xa3, 0xbd, 0x31, 0x7d, 0xc7, 0x49, 0x94, 0x79, 0xce, 0xc3, 0x1c, 0x7a, 0x56, - 0x1b, 0xd6, 0x8a, 0x6a, 0x72, 0x83, 0x62, 0x5d, 0x64, 0x99, 0xac, 0x0c, 0x57, 0xce, 0x69, 0x85, 0xeb, 0xce, 0xac, - 0x17, 0x90, 0x94, 0x55, 0x8a, 0xa5, 0x33, 0xe1, 0xab, 0x4d, 0xcb, 0x9e, 0xb7, 0x4e, 0x21, 0xa7, 0x21, 0x32, 0xfa, - 0xa1, 0x25, 0xa0, 0x9a, 0x56, 0x5c, 0xd5, 0xe0, 0xb2, 0xab, 0xdb, 0xc3, 0x75, 0x7b, 0x74, 0x33, 0x3e, 0x40, 0x8c, - 0x38, 0x8e, 0x2d, 0x03, 0xbb, 0x09, 0x8b, 0x67, 0x63, 0x7d, 0x5f, 0x76, 0xe9, 0xad, 0xad, 0xc5, 0x21, 0xac, 0x3d, - 0x67, 0x85, 0x84, 0x00, 0x69, 0xa9, 0x2b, 0xdd, 0x6e, 0x83, 0x00, 0x06, 0xb8, 0xdf, 0xef, 0x01, 0xd7, 0xaa, 0xd9, - 0x49, 0x7d, 0x6b, 0x36, 0xc4, 0x5e, 0x52, 0x78, 0x0c, 0x44, 0xa9, 0xf8, 0xcf, 0x20, 0xa0, 0x78, 0xee, 0x86, 0x60, - 0x5f, 0xc9, 0x4e, 0x36, 0x65, 0xbf, 0xff, 0xbc, 0xc4, 0x07, 0x94, 0x83, 0x82, 0x58, 0x57, 0xc5, 0xad, 0xd0, 0xec, - 0x93, 0xfc, 0x10, 0xc7, 0x22, 0xcf, 0x42, 0x4b, 0x58, 0x6a, 0x4d, 0x58, 0xb8, 0x64, 0xa4, 0x83, 0x38, 0x68, 0x48, - 0xe7, 0x60, 0xd5, 0x36, 0xd8, 0x70, 0xaf, 0xf7, 0xb2, 0x0a, 0x2b, 0x9a, 0x39, 0xc3, 0xf2, 0xde, 0x01, 0x00, 0xeb, - 0xf5, 0x70, 0xa1, 0x38, 0x64, 0xc2, 0x43, 0x9f, 0xc4, 0x97, 0x86, 0x5d, 0x9f, 0x29, 0x59, 0xc9, 0x68, 0x34, 0xaa, - 0x1b, 0x29, 0xf9, 0x30, 0xdf, 0xbd, 0x69, 0xa1, 0x56, 0x8a, 0x38, 0xe5, 0x29, 0x58, 0x7a, 0x6b, 0x4a, 0x37, 0x5f, - 0xd0, 0x15, 0x2f, 0x52, 0xf9, 0xd3, 0x41, 0x9b, 0xf4, 0x88, 0x6b, 0xe6, 0xeb, 0x2c, 0xcc, 0xf0, 0x43, 0xc0, 0x47, - 0xf3, 0x30, 0xb3, 0xe9, 0x0a, 0x96, 0x16, 0xc4, 0x91, 0x71, 0xc9, 0x43, 0x9b, 0x07, 0xb0, 0xfe, 0xf4, 0x21, 0x89, - 0x9f, 0xc2, 0xcf, 0x99, 0x4e, 0xeb, 0xf8, 0x0c, 0x67, 0x33, 0x2a, 0xe4, 0x8d, 0xa0, 0xfd, 0x1a, 0x12, 0x89, 0x46, - 0x36, 0xf6, 0x18, 0x8a, 0xd6, 0xdd, 0x06, 0xae, 0xfc, 0x86, 0xde, 0xb9, 0x34, 0x08, 0xb0, 0xad, 0xb1, 0x18, 0x38, - 0xe3, 0xf1, 0x07, 0xaa, 0x6a, 0xf4, 0x15, 0x45, 0x37, 0x4c, 0x26, 0x9a, 0x3b, 0x8e, 0xed, 0xa8, 0x76, 0x95, 0xad, - 0x58, 0x61, 0x6c, 0x79, 0xed, 0x5b, 0x5a, 0x9a, 0x12, 0x50, 0x0d, 0x86, 0x3b, 0x01, 0x7c, 0x46, 0x84, 0x3c, 0x10, - 0x44, 0xf7, 0xc1, 0x41, 0x73, 0x96, 0xe0, 0x79, 0x18, 0xc2, 0x1f, 0x58, 0x38, 0xb0, 0x2c, 0x65, 0x3f, 0x97, 0xd3, - 0x18, 0xce, 0xdd, 0x5c, 0xee, 0xf0, 0xd9, 0x12, 0x14, 0x79, 0x72, 0x4e, 0xf5, 0xe5, 0x2b, 0xf7, 0xf6, 0x7b, 0x4c, - 0x30, 0x8f, 0x9e, 0x6d, 0xf8, 0xad, 0xa6, 0xdb, 0xf8, 0xc2, 0xda, 0x81, 0x13, 0xe6, 0xc2, 0x69, 0x2e, 0xb6, 0x4b, - 0x0d, 0x71, 0xd7, 0x78, 0x42, 0x84, 0x57, 0x8a, 0x58, 0x64, 0x9e, 0x4c, 0xc7, 0x60, 0x63, 0xc8, 0x36, 0x95, 0xcf, - 0x94, 0x42, 0xbc, 0x9a, 0xca, 0x0b, 0x53, 0x2b, 0x95, 0x55, 0x1a, 0x61, 0xa6, 0x80, 0x45, 0x95, 0x81, 0xcf, 0x7e, - 0x8d, 0x14, 0xd7, 0xd4, 0xf3, 0x17, 0x2e, 0xdf, 0x4c, 0xb7, 0xd9, 0x7c, 0xfa, 0x32, 0x8f, 0xaf, 0xb6, 0xdb, 0xb0, - 0xfb, 0x05, 0x98, 0x5f, 0x56, 0x52, 0xa3, 0x06, 0x4e, 0x0f, 0x21, 0xfa, 0x39, 0xef, 0xc9, 0x39, 0xb1, 0x9c, 0x5c, - 0xbb, 0x79, 0xb3, 0x9d, 0x14, 0x2d, 0xb0, 0x80, 0x13, 0x17, 0xe9, 0x40, 0x4b, 0x05, 0xa7, 0x2c, 0xe3, 0x9d, 0x4d, - 0x6f, 0x29, 0x15, 0x5e, 0x2d, 0x14, 0x09, 0xa9, 0xed, 0xbd, 0xc4, 0x8c, 0x1a, 0x70, 0x4e, 0xf2, 0x0e, 0x02, 0x4e, - 0x6a, 0xaa, 0xb1, 0x46, 0x71, 0xaa, 0x13, 0x9c, 0x57, 0x6a, 0xe8, 0x12, 0xe5, 0xc4, 0x6d, 0xb7, 0x55, 0xd1, 0x42, - 0x7d, 0x3c, 0xc8, 0x59, 0x22, 0x8f, 0x07, 0x14, 0xba, 0xc8, 0xa3, 0x21, 0x5f, 0x90, 0x52, 0xad, 0x1c, 0xa5, 0x5a, - 0xdd, 0x95, 0x0c, 0x14, 0x72, 0x15, 0xe4, 0x0d, 0x31, 0xee, 0x5a, 0x99, 0xb7, 0xb8, 0x72, 0x42, 0x4a, 0x93, 0xf0, - 0xb9, 0xa5, 0x18, 0x58, 0xc1, 0xde, 0x98, 0xba, 0xc2, 0x25, 0x42, 0xdb, 0xdd, 0x86, 0x98, 0x64, 0xb0, 0x6e, 0xb6, - 0xdb, 0x57, 0x65, 0x38, 0xcf, 0x16, 0x54, 0x8c, 0xb2, 0x14, 0x21, 0xc4, 0xb4, 0x87, 0xae, 0xe9, 0x82, 0x9e, 0x18, - 0x6a, 0xdb, 0xe3, 0x24, 0xe9, 0x62, 0x4d, 0x92, 0x18, 0xc5, 0x17, 0xa2, 0x94, 0x6b, 0x8d, 0x10, 0x3c, 0xdc, 0xff, - 0x48, 0x21, 0x86, 0x9b, 0x5e, 0x77, 0xbf, 0xee, 0xdc, 0x10, 0xff, 0x80, 0x40, 0x02, 0x05, 0x7b, 0x55, 0x8e, 0x2e, - 0xb2, 0x22, 0xc5, 0x9d, 0x2a, 0xa3, 0xe2, 0xca, 0x75, 0xe0, 0xb7, 0xdc, 0xf0, 0xaf, 0x86, 0x28, 0x40, 0x5c, 0xe3, - 0x4a, 0x31, 0x9e, 0xb5, 0xb5, 0x14, 0xc9, 0x28, 0x36, 0x24, 0x2a, 0x9c, 0xa8, 0xe8, 0x2e, 0x4f, 0xa3, 0x7b, 0x68, - 0xd7, 0x20, 0xb8, 0x6a, 0xee, 0x6c, 0xa4, 0xf9, 0x82, 0x10, 0x39, 0x01, 0x02, 0x36, 0xaa, 0x3e, 0xb5, 0x56, 0xd5, - 0xc3, 0xac, 0xf2, 0xb9, 0x3a, 0x88, 0x57, 0x15, 0xf0, 0xb0, 0xce, 0xf6, 0xbe, 0xaa, 0x1c, 0xd6, 0x06, 0xdf, 0x6e, - 0xb7, 0xab, 0x6a, 0x1e, 0x04, 0x0e, 0xa3, 0xf9, 0x9d, 0x94, 0x98, 0xf7, 0xc6, 0x14, 0x56, 0xbc, 0xeb, 0xd2, 0xd6, - 0x4d, 0x6a, 0x8d, 0x05, 0xea, 0x0e, 0xd7, 0x07, 0x3c, 0x4f, 0x81, 0xa3, 0x1d, 0x15, 0x53, 0x61, 0x74, 0xe5, 0xd8, - 0x95, 0x0a, 0x03, 0x43, 0xff, 0x90, 0xb2, 0x0d, 0x98, 0xe3, 0x81, 0xb5, 0x0d, 0xfa, 0x29, 0x49, 0x2d, 0xcc, 0x18, - 0x8d, 0x59, 0xc4, 0xba, 0x8e, 0x8e, 0xb8, 0x8a, 0xde, 0xce, 0xa3, 0xbf, 0x3d, 0x1d, 0xd3, 0x32, 0x2e, 0x52, 0x71, - 0x0d, 0x2a, 0x08, 0x50, 0x86, 0xa0, 0xe1, 0xbf, 0xa2, 0x06, 0xa0, 0x41, 0xb0, 0x03, 0xf0, 0x8f, 0x4e, 0xa7, 0x41, - 0x53, 0x93, 0x8b, 0x49, 0x2a, 0x8b, 0x9c, 0xb5, 0xa1, 0xcc, 0x64, 0x72, 0x48, 0x1e, 0x17, 0x80, 0xe7, 0x88, 0xcd, - 0x92, 0x36, 0x17, 0x72, 0xb3, 0xc9, 0xd7, 0x92, 0x1d, 0xb9, 0xf3, 0x8a, 0xd6, 0x6b, 0x51, 0xd9, 0x49, 0xcc, 0x17, - 0xd3, 0x3b, 0x23, 0x0c, 0x9c, 0xea, 0xd6, 0xdc, 0xee, 0x40, 0xa7, 0x99, 0xfa, 0x74, 0x6e, 0x02, 0xc4, 0x01, 0x86, - 0xeb, 0x6e, 0x7e, 0xbb, 0x20, 0xf4, 0x8e, 0xdd, 0x19, 0xb1, 0xea, 0xad, 0x91, 0x8b, 0xe8, 0xb4, 0xdb, 0xc1, 0x04, - 0x2e, 0xe3, 0xac, 0x34, 0x2f, 0x94, 0xba, 0xa1, 0xec, 0x68, 0x9b, 0x30, 0x9f, 0x77, 0xb4, 0x1b, 0x2e, 0xf8, 0x46, - 0xac, 0x63, 0xdd, 0x90, 0xa6, 0x12, 0x3d, 0x3a, 0x50, 0xdb, 0x21, 0xa0, 0x39, 0x1b, 0xd3, 0x25, 0x40, 0x6d, 0xc2, - 0x7e, 0x59, 0x83, 0x59, 0xca, 0x25, 0xf4, 0xb5, 0xdb, 0x27, 0xf9, 0x52, 0xf6, 0xa4, 0x72, 0x96, 0x28, 0xf8, 0x72, - 0xa4, 0xe0, 0x95, 0x95, 0xf3, 0x58, 0xcf, 0x21, 0xe0, 0xb1, 0xc8, 0x12, 0x9d, 0x93, 0xe2, 0x0a, 0x94, 0xa9, 0x70, - 0x04, 0xea, 0xaa, 0x11, 0x4b, 0x38, 0xc0, 0xed, 0xc5, 0xd3, 0x80, 0x50, 0x90, 0xea, 0xae, 0xcd, 0x8a, 0xbc, 0x63, - 0x27, 0x9b, 0x3b, 0x30, 0x8b, 0xad, 0xd7, 0x55, 0xeb, 0x2b, 0x93, 0x6c, 0x3f, 0x6e, 0x08, 0xb6, 0xdd, 0x91, 0xf2, - 0x85, 0x77, 0xf4, 0x96, 0x6c, 0x6e, 0xfb, 0xfd, 0x10, 0xfa, 0x43, 0xa8, 0xea, 0xd0, 0x5d, 0x67, 0x87, 0xee, 0x5c, - 0xe6, 0xd7, 0xe8, 0xf9, 0xa4, 0x37, 0xc4, 0x07, 0x34, 0xd1, 0xa2, 0xab, 0xf8, 0x1e, 0x36, 0x75, 0x54, 0x53, 0x59, - 0x79, 0x94, 0x50, 0x50, 0x01, 0x67, 0xbc, 0x3a, 0xe3, 0x18, 0xdb, 0x54, 0x3d, 0xbd, 0x53, 0xbc, 0xda, 0x5a, 0xaf, - 0xcd, 0x6a, 0x7d, 0x01, 0x16, 0x01, 0x17, 0x3c, 0xba, 0x56, 0xb4, 0xe4, 0xca, 0x61, 0xea, 0xcf, 0x71, 0x54, 0x82, - 0xcb, 0x38, 0xcb, 0x79, 0x1a, 0xd0, 0x4b, 0xbf, 0xff, 0xa1, 0xb2, 0x95, 0x5a, 0x7a, 0x67, 0xee, 0x4d, 0x48, 0x36, - 0xff, 0x63, 0x03, 0xf5, 0x3a, 0xc4, 0x88, 0xa8, 0x7a, 0x41, 0xbf, 0x65, 0x10, 0x1b, 0x33, 0xa8, 0xd6, 0x49, 0xc2, - 0xab, 0x2a, 0xd0, 0x4a, 0xad, 0x35, 0x5b, 0xeb, 0xf3, 0xec, 0x11, 0x3b, 0x79, 0xd4, 0x63, 0xec, 0x8e, 0xd0, 0x44, - 0xe9, 0x84, 0x74, 0x8d, 0x91, 0xa3, 0x05, 0x52, 0x1d, 0x8a, 0xb2, 0xcb, 0xf0, 0x2d, 0x0a, 0x59, 0xda, 0xfb, 0x5c, - 0x9f, 0xc8, 0xf2, 0x1b, 0x65, 0x74, 0x11, 0xc9, 0x44, 0x90, 0x8d, 0xdf, 0x22, 0x60, 0x2f, 0x34, 0x3b, 0x20, 0x9b, - 0x25, 0x3b, 0xa3, 0xe7, 0xc6, 0x04, 0x06, 0x5e, 0xbf, 0x95, 0x89, 0x7a, 0x94, 0x25, 0xd1, 0x95, 0x46, 0x2e, 0xf7, - 0x21, 0x89, 0xce, 0x43, 0xe2, 0xe6, 0x86, 0xa5, 0x75, 0x13, 0xa2, 0x98, 0x59, 0x6f, 0x78, 0xd9, 0xdd, 0x47, 0xde, - 0xb6, 0xd2, 0x3e, 0xd5, 0x77, 0x26, 0x8d, 0x4c, 0xa1, 0xaf, 0xc3, 0x49, 0xbf, 0x0f, 0x7f, 0x15, 0xfd, 0xc0, 0x5b, - 0x0a, 0xfe, 0x62, 0x8f, 0x48, 0x93, 0xb0, 0x00, 0xe0, 0x08, 0x73, 0x5e, 0xfb, 0x13, 0xf8, 0x88, 0x9d, 0x6c, 0x1e, - 0x85, 0x67, 0xde, 0xcc, 0xdd, 0x87, 0x78, 0xa9, 0x4a, 0x7a, 0xce, 0x3c, 0xe9, 0x81, 0x58, 0x85, 0x7a, 0xbf, 0xde, - 0x31, 0xa3, 0x4f, 0x00, 0x22, 0x75, 0x67, 0x1c, 0x4a, 0xf1, 0x63, 0xdd, 0x65, 0xb2, 0x49, 0x59, 0x9b, 0x89, 0x92, - 0x2a, 0x12, 0x7f, 0x11, 0x40, 0xbf, 0x61, 0x38, 0x1a, 0x80, 0xf7, 0x56, 0x63, 0xaf, 0x87, 0xc6, 0x19, 0x53, 0x4d, - 0xcf, 0x36, 0x6a, 0x79, 0x5b, 0x0a, 0xa1, 0xc7, 0x22, 0xba, 0xb3, 0xc7, 0x62, 0x78, 0x46, 0xdf, 0x42, 0x85, 0xaf, - 0x43, 0x8c, 0xa6, 0x4b, 0x9a, 0x66, 0xba, 0x96, 0x5b, 0xe9, 0x96, 0xd0, 0x1c, 0xa3, 0xf8, 0x38, 0x6d, 0xbb, 0xa7, - 0x5a, 0x68, 0x4f, 0x28, 0x0f, 0xef, 0x68, 0x4d, 0x6f, 0x0d, 0x8b, 0x60, 0x91, 0x96, 0x9d, 0xfc, 0x84, 0x5e, 0x38, - 0x02, 0x93, 0xb2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x33, 0x35, 0x52, 0x0e, 0x47, 0xe1, 0x4b, 0x36, 0x20, - 0x57, 0x50, 0x8b, 0x35, 0x66, 0x27, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x33, 0x29, 0x88, 0x64, 0x44, 0x73, 0x0b, - 0xf1, 0xf4, 0x0f, 0xd0, 0xf4, 0x41, 0x5a, 0x98, 0xd2, 0x35, 0x0a, 0x78, 0x40, 0xdf, 0xd4, 0xef, 0xe7, 0xf8, 0xdc, - 0x38, 0x96, 0x58, 0xd8, 0xe3, 0x25, 0xa1, 0x4b, 0x27, 0x6e, 0x14, 0x48, 0x9b, 0x2d, 0xab, 0x00, 0xac, 0x48, 0x02, - 0x8d, 0x48, 0xd0, 0x52, 0xc7, 0x8a, 0xcb, 0x36, 0x68, 0x40, 0x12, 0x15, 0x14, 0xb2, 0x44, 0x02, 0xf8, 0x61, 0x04, - 0x21, 0x8a, 0x62, 0x10, 0xf7, 0xaa, 0xe5, 0x15, 0x37, 0x54, 0x83, 0x13, 0x45, 0x30, 0xc1, 0x2a, 0x9d, 0x02, 0xb1, - 0x2d, 0xd6, 0x2b, 0xf0, 0xbc, 0xb4, 0x17, 0x49, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x95, 0x4e, 0xdb, 0xe5, 0xed, 0x88, - 0x96, 0x6a, 0x36, 0x77, 0x5e, 0x2c, 0x0c, 0xf7, 0x58, 0xbb, 0xdb, 0x81, 0xf6, 0xc2, 0x7a, 0x47, 0x44, 0x0d, 0x56, - 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xaa, 0x5e, 0x59, 0x26, 0xa0, 0xa6, 0xab, 0xb8, 0x5e, 0x46, 0xd9, 0x08, 0xfe, - 0x6c, 0xb7, 0xc1, 0x61, 0x00, 0x16, 0x90, 0xbf, 0xbc, 0xff, 0x29, 0xc2, 0xf0, 0x4c, 0xbf, 0xbc, 0xff, 0x69, 0xbb, - 0x7d, 0x3a, 0x1e, 0x6b, 0xae, 0xc0, 0xaa, 0x75, 0x80, 0x3f, 0xd0, 0x6c, 0x83, 0x59, 0xb2, 0xdb, 0xed, 0x53, 0xe0, - 0x20, 0x24, 0xdb, 0xa0, 0x77, 0xb1, 0x74, 0xe4, 0x92, 0xac, 0x86, 0xda, 0x91, 0x80, 0x55, 0xb7, 0xc3, 0x52, 0xec, - 0x52, 0x1f, 0x19, 0x82, 0x51, 0x2d, 0xfa, 0x17, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, 0xb2, 0xae, 0x57, 0x55, - 0x74, 0x78, 0x18, 0xaf, 0xb2, 0x51, 0x95, 0xc1, 0x36, 0xaf, 0x6e, 0xae, 0x00, 0x50, 0x21, 0xa0, 0xde, 0xbb, 0x75, - 0x91, 0xe9, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0x8d, 0x6e, 0x72, 0x4a, 0xcc, 0x03, 0xd8, - 0x1c, 0x6e, 0xb7, 0x1e, 0xbf, 0x70, 0x32, 0x7a, 0x3a, 0x5b, 0x66, 0xca, 0xa0, 0x93, 0xeb, 0xfd, 0x4f, 0x22, 0x27, - 0x0d, 0x15, 0x9f, 0x64, 0xfa, 0x22, 0x03, 0x3e, 0x8f, 0xbd, 0xa9, 0x42, 0x97, 0xe5, 0xf2, 0x5a, 0x03, 0x6c, 0x6c, - 0x76, 0x79, 0x3f, 0x4a, 0x39, 0x44, 0xa4, 0x08, 0x8c, 0xba, 0x66, 0x99, 0x11, 0xd7, 0xa6, 0xe2, 0xbe, 0xa5, 0x0a, - 0x7b, 0x53, 0x39, 0xce, 0x2a, 0x5c, 0x3b, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x02, 0x85, 0xa8, 0x1c, 0x8d, 0xe9, 0xac, - 0x40, 0x2a, 0x73, 0x98, 0x50, 0xcc, 0x61, 0xdf, 0xfd, 0x92, 0x5a, 0x73, 0x19, 0x57, 0xb8, 0xf7, 0xc2, 0x95, 0x99, - 0xdc, 0x09, 0x00, 0x45, 0x92, 0xb5, 0xff, 0xfc, 0x09, 0xa9, 0xf1, 0x3f, 0x53, 0xa5, 0x01, 0xe8, 0xfd, 0x0c, 0x35, - 0x59, 0x82, 0x80, 0xad, 0x98, 0xba, 0x68, 0xfa, 0x46, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x15, 0xdb, 0xc8, 0xf8, 0x39, - 0x51, 0x4d, 0x4b, 0x9e, 0xae, 0x8b, 0x34, 0x2e, 0x92, 0xfb, 0x88, 0x37, 0x53, 0x2c, 0x89, 0x55, 0x9a, 0x02, 0xfd, - 0xec, 0x77, 0xe1, 0xa7, 0xd2, 0x33, 0x01, 0xa7, 0x85, 0xbb, 0xad, 0x9c, 0xcd, 0x64, 0x18, 0x67, 0x64, 0xca, 0x25, - 0x62, 0xb7, 0xd1, 0xf7, 0xe8, 0x13, 0xfc, 0xc9, 0xd1, 0x13, 0x42, 0xef, 0xc4, 0xb4, 0x40, 0x50, 0xba, 0x22, 0x35, - 0xae, 0x9a, 0xd8, 0xaf, 0x29, 0x44, 0x71, 0xa8, 0x18, 0x84, 0xee, 0xd4, 0xed, 0x93, 0x7c, 0x9f, 0x29, 0xfb, 0x8d, - 0x2e, 0x5b, 0x90, 0x4d, 0x05, 0x1d, 0x13, 0xd6, 0xdb, 0xd3, 0xd9, 0xb3, 0x33, 0xe7, 0x37, 0x68, 0xc2, 0x41, 0x75, - 0x03, 0xed, 0x2a, 0xc9, 0x34, 0x46, 0xb1, 0x59, 0x8c, 0xb5, 0x1b, 0x13, 0x11, 0x04, 0x9d, 0x2e, 0x66, 0x61, 0xbb, - 0x9d, 0x10, 0x5f, 0x02, 0x09, 0x14, 0xb8, 0x72, 0x51, 0x4e, 0x42, 0x22, 0x2f, 0x64, 0x6a, 0xb2, 0x6e, 0x04, 0x0b, - 0xd4, 0x1a, 0x3b, 0x0a, 0xe8, 0x29, 0x37, 0x4f, 0x01, 0x7d, 0x5f, 0xb2, 0x53, 0x3e, 0x08, 0x86, 0x18, 0x5f, 0x35, - 0xa0, 0xb7, 0x42, 0x3e, 0x82, 0x87, 0x30, 0xb0, 0x5c, 0xf4, 0x65, 0xc9, 0x10, 0x56, 0xe8, 0xcf, 0x94, 0x4d, 0xbe, - 0xfe, 0xc6, 0xce, 0xef, 0xb5, 0x12, 0xb3, 0x83, 0x50, 0xdc, 0x5c, 0x4f, 0x80, 0xf8, 0xd5, 0xfc, 0x1a, 0xac, 0xab, - 0x95, 0xc4, 0xdb, 0x91, 0x3c, 0x54, 0xae, 0x1c, 0xdd, 0x7c, 0x52, 0xe9, 0x4f, 0x20, 0x48, 0x8d, 0x95, 0x94, 0xdb, - 0xef, 0x3e, 0x0a, 0x5b, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xed, 0xad, 0xe4, 0xc2, 0x17, 0xfe, 0x63, 0x9d, 0xef, 0x31, - 0x76, 0x88, 0x38, 0xc3, 0xe9, 0xf7, 0xc1, 0xb0, 0xbd, 0x5b, 0x99, 0x36, 0x24, 0xba, 0x96, 0x1f, 0x01, 0xfd, 0x1f, - 0xab, 0xf1, 0x3b, 0x45, 0x49, 0x5f, 0x12, 0xe7, 0x08, 0x57, 0xc4, 0x2b, 0x34, 0xd5, 0xeb, 0x8d, 0x1b, 0xfa, 0xa6, - 0xd4, 0x2f, 0x94, 0x82, 0xc3, 0xbc, 0xd5, 0x0a, 0x0f, 0x3c, 0xf3, 0xfe, 0xa8, 0x3c, 0x41, 0xf7, 0x6f, 0xb8, 0x37, - 0xfe, 0xa8, 0x58, 0x86, 0x37, 0xe5, 0x2c, 0xd3, 0x77, 0xb8, 0xdb, 0xac, 0x48, 0xc5, 0x2d, 0x63, 0xc1, 0xba, 0x90, - 0xe6, 0xab, 0x69, 0x30, 0xdb, 0x34, 0x91, 0x4c, 0xb6, 0xdf, 0xff, 0xe5, 0x9d, 0xb0, 0xd9, 0x20, 0x38, 0xab, 0x45, - 0x19, 0x5f, 0xf1, 0x60, 0xaa, 0x54, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0x63, 0xb5, 0x77, 0xf0, 0x64, 0xa8, - 0x99, 0x0e, 0x71, 0x6d, 0x74, 0x16, 0xf0, 0x56, 0x8f, 0xe6, 0x69, 0x0d, 0xbb, 0xcc, 0x55, 0x52, 0xfc, 0xd1, 0x92, - 0x64, 0x63, 0xfd, 0x9e, 0x0c, 0xdb, 0xc8, 0x67, 0xae, 0x01, 0x63, 0xe6, 0x56, 0xc8, 0x20, 0x77, 0x3d, 0x60, 0x84, - 0x90, 0x08, 0x54, 0xd6, 0x62, 0xe2, 0xbc, 0xd2, 0xe1, 0x1f, 0x6d, 0x60, 0x9c, 0x18, 0x03, 0xe3, 0x7c, 0x14, 0x21, - 0xa7, 0xa7, 0x7c, 0x90, 0x78, 0xb3, 0xf5, 0x97, 0x2c, 0x91, 0xde, 0x08, 0x42, 0x2f, 0xe0, 0xf7, 0xb8, 0xc5, 0x03, - 0x79, 0xc1, 0x29, 0xed, 0xcd, 0xe9, 0xf0, 0x65, 0x49, 0x86, 0x7f, 0x82, 0x77, 0x57, 0x6c, 0x2e, 0xcb, 0x09, 0x2c, - 0xee, 0xd8, 0x29, 0x9e, 0xe6, 0xb2, 0xc5, 0x09, 0x71, 0x88, 0x45, 0xee, 0x12, 0x0b, 0x18, 0x51, 0xcd, 0x68, 0xfc, - 0x78, 0xf6, 0xf6, 0x8d, 0xc2, 0x6c, 0xca, 0xdd, 0x0f, 0x60, 0x44, 0x95, 0xb4, 0xdd, 0x0c, 0xf8, 0x72, 0x84, 0x06, - 0xdb, 0xa9, 0x1d, 0xec, 0x7e, 0x5f, 0xa7, 0x9d, 0x14, 0x4e, 0x36, 0x2b, 0x06, 0xdd, 0x51, 0xda, 0x2c, 0xa5, 0x41, - 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0xab, 0xc5, 0xaa, 0xce, 0x87, 0xe1, 0x92, 0xc6, 0x46, 0x56, 0x6e, 0x76, 0x13, 0x8e, - 0x6c, 0x02, 0x5c, 0x9f, 0x84, 0xb2, 0xf2, 0xe7, 0xa0, 0x05, 0x9d, 0x09, 0x1c, 0xd1, 0x76, 0x1b, 0x42, 0x04, 0x8e, - 0x72, 0x38, 0x99, 0x85, 0xe5, 0x70, 0x28, 0x07, 0xbe, 0x24, 0x24, 0x7a, 0x53, 0xce, 0xb3, 0x85, 0x44, 0xec, 0x71, - 0x77, 0xd2, 0xaf, 0xa5, 0xe4, 0x94, 0x7b, 0x7f, 0x54, 0x64, 0xf3, 0x5b, 0x8a, 0x31, 0x07, 0xad, 0x66, 0x33, 0x03, - 0x09, 0xeb, 0x69, 0x4d, 0xe4, 0x3a, 0x32, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, 0x75, 0x8b, 0x23, 0xd6, 0xd3, - 0x7a, 0x0f, 0x2a, 0x40, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x5e, 0x56, 0xa1, 0xa0, 0x9c, 0xf8, 0xcc, 0x8c, 0x11, - 0x0d, 0x96, 0x20, 0x24, 0x8d, 0xab, 0xfa, 0xb5, 0x48, 0xb3, 0xcb, 0x0c, 0x10, 0x13, 0xac, 0xff, 0x9c, 0xf0, 0xde, - 0x3c, 0x93, 0xf3, 0xd2, 0x95, 0x38, 0x33, 0x30, 0x1f, 0x5d, 0x6f, 0x69, 0x49, 0xa2, 0x12, 0x68, 0x94, 0xab, 0xe5, - 0xf9, 0xfb, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x69, 0x3b, 0xc4, 0x4f, 0x58, 0x4d, 0x9c, 0xd3, 0xba, 0x96, 0x22, - 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xc8, 0xe1, 0x03, 0x83, 0x0a, 0x2b, 0xf9, 0x29, 0x70, 0xf8, 0x8c, - 0x81, 0xa4, 0xab, 0x45, 0x70, 0x35, 0x3a, 0xc2, 0x8a, 0x32, 0xb5, 0xc4, 0x14, 0x12, 0xdd, 0x7a, 0xa1, 0x35, 0x86, - 0x51, 0x76, 0x15, 0xf9, 0xdf, 0xab, 0xee, 0xfd, 0x51, 0x6d, 0xb7, 0x30, 0xc9, 0x8e, 0xc7, 0x15, 0x6c, 0x6a, 0xd4, - 0x0a, 0xe1, 0xec, 0x9c, 0xd6, 0xa8, 0x1d, 0xeb, 0x85, 0x05, 0x90, 0x07, 0xb0, 0x15, 0xf1, 0x28, 0x83, 0x60, 0x6f, - 0xca, 0x79, 0xb5, 0xb0, 0xa2, 0x1c, 0x21, 0xf1, 0xbe, 0xc4, 0x28, 0xe5, 0x70, 0x15, 0x0b, 0x4b, 0x86, 0xfc, 0xea, - 0xe8, 0xb2, 0x14, 0xd7, 0x20, 0x29, 0xd1, 0x0c, 0x95, 0xe1, 0x75, 0x71, 0xd5, 0x16, 0x84, 0xf6, 0x2e, 0x2a, 0x50, - 0x47, 0x82, 0xe0, 0xc5, 0xab, 0x21, 0x66, 0x1b, 0xb9, 0xbb, 0xa2, 0xbd, 0xe4, 0x80, 0x5a, 0xdd, 0xb5, 0x5d, 0x6f, - 0xd2, 0x36, 0xdb, 0x88, 0x0b, 0xff, 0x82, 0xd2, 0x4f, 0xf9, 0xa0, 0x74, 0xa9, 0x04, 0x6e, 0x7c, 0xb9, 0xc9, 0xb2, - 0xcb, 0x7b, 0x5c, 0xfa, 0xb5, 0x37, 0x7e, 0xfd, 0x7e, 0x4f, 0x2e, 0x04, 0x2f, 0x15, 0x98, 0x6f, 0x97, 0x99, 0xaa, - 0xb5, 0xa6, 0xd4, 0x5c, 0x82, 0x6b, 0x6b, 0x3f, 0x82, 0x8a, 0xb8, 0xae, 0xc8, 0x64, 0x72, 0x80, 0x0e, 0x9c, 0xac, - 0x70, 0x2b, 0x0b, 0xf0, 0xd8, 0x09, 0xc8, 0x76, 0xcb, 0xc3, 0x40, 0x1d, 0x3a, 0x81, 0xbb, 0x25, 0xcf, 0x90, 0x59, - 0x33, 0x8f, 0x3f, 0x2b, 0xc1, 0x3f, 0xb6, 0xe0, 0x27, 0x14, 0x77, 0x1a, 0x99, 0x7f, 0x2b, 0xad, 0x5b, 0xdc, 0xbf, - 0x93, 0x69, 0x42, 0x51, 0x99, 0xd0, 0xb8, 0x95, 0xfe, 0x4b, 0x07, 0x4b, 0x92, 0xd9, 0x3f, 0x08, 0xf8, 0x60, 0xe6, - 0x3d, 0x31, 0xef, 0x49, 0x73, 0xba, 0xb5, 0x82, 0x21, 0x40, 0xa1, 0x9f, 0x93, 0xb9, 0xa6, 0xea, 0xf9, 0xe7, 0x35, - 0x5f, 0x73, 0xbf, 0xc5, 0x26, 0xe9, 0x81, 0x06, 0x3b, 0x79, 0x14, 0xa5, 0xb0, 0x12, 0x75, 0xae, 0x25, 0xea, 0x55, - 0xc3, 0x32, 0x54, 0x27, 0x38, 0x35, 0x4f, 0xd5, 0xb0, 0xfb, 0x89, 0x68, 0xad, 0x24, 0x2d, 0x31, 0x60, 0xad, 0x23, - 0x0f, 0xc9, 0xed, 0x5a, 0xc7, 0x9d, 0x86, 0xba, 0x34, 0x89, 0x12, 0x60, 0x84, 0x0b, 0x70, 0x04, 0xfd, 0x54, 0x86, - 0x1c, 0xae, 0xa9, 0x52, 0xbf, 0xa0, 0x28, 0x79, 0xe2, 0x28, 0x6a, 0x95, 0x22, 0xdd, 0x7c, 0x94, 0x63, 0x37, 0x5c, - 0xe3, 0x84, 0x9c, 0x68, 0xa1, 0xbf, 0x3d, 0x96, 0x72, 0x86, 0x16, 0x0f, 0xf2, 0x04, 0xeb, 0xe5, 0x2d, 0x05, 0x8a, - 0x3e, 0xba, 0x8c, 0xba, 0xe6, 0x15, 0xda, 0xbe, 0x2c, 0xfb, 0xfd, 0xdc, 0xd4, 0x93, 0xb2, 0x93, 0xcd, 0x52, 0xef, - 0x43, 0x54, 0x4c, 0xe1, 0xae, 0x4f, 0x14, 0x7f, 0x15, 0xaa, 0xab, 0xb6, 0xc8, 0xf9, 0x88, 0x23, 0x2e, 0x46, 0x4e, - 0x9a, 0x9f, 0xe5, 0xd4, 0x4b, 0x71, 0xbf, 0xac, 0xe4, 0xd7, 0x4a, 0x5b, 0x31, 0x5a, 0xa0, 0xfe, 0x54, 0xaa, 0xbc, - 0x5f, 0x94, 0x00, 0xf7, 0x54, 0xb1, 0x37, 0x60, 0x5f, 0xa1, 0x10, 0x7e, 0x5b, 0x02, 0xfe, 0x8d, 0xe4, 0x06, 0x8c, - 0x02, 0x03, 0x8c, 0x26, 0xdb, 0x73, 0x9a, 0xc0, 0x01, 0x57, 0x29, 0x15, 0x05, 0xad, 0xf4, 0xd0, 0x50, 0x53, 0x18, - 0x3d, 0x43, 0x19, 0xb7, 0xcc, 0xec, 0xdc, 0x18, 0x3b, 0x2d, 0xf0, 0x3c, 0x7f, 0x3e, 0x27, 0xf4, 0xb0, 0x56, 0x07, - 0xa9, 0xd1, 0x49, 0x74, 0x7f, 0xec, 0xc2, 0xc9, 0xf5, 0xc2, 0x59, 0x36, 0x2c, 0x81, 0xee, 0xc0, 0x05, 0x31, 0xee, - 0xf7, 0x73, 0x38, 0x32, 0xf5, 0xc8, 0x97, 0x2c, 0xa7, 0x31, 0x5b, 0x52, 0xe5, 0x69, 0x77, 0x55, 0x87, 0x39, 0x5d, - 0x1a, 0x19, 0x6f, 0xca, 0x8a, 0x79, 0x0e, 0x1a, 0x49, 0xf8, 0xd3, 0x6d, 0xed, 0x92, 0xce, 0x97, 0x90, 0x01, 0xfe, - 0x80, 0x44, 0x14, 0xb1, 0xaf, 0xff, 0xad, 0xc6, 0x49, 0x3d, 0x51, 0xda, 0xb0, 0x84, 0xae, 0x99, 0xaa, 0x9f, 0x5e, - 0xb2, 0xb5, 0xb7, 0x14, 0xb6, 0xdb, 0xd0, 0x4f, 0x60, 0x8a, 0x73, 0x25, 0xd3, 0x4b, 0xd4, 0x49, 0x01, 0x15, 0x0b, - 0x2f, 0x71, 0xf9, 0xa5, 0x84, 0x42, 0x73, 0xe7, 0xcb, 0x85, 0x56, 0x62, 0x42, 0xab, 0xc4, 0xe7, 0x0f, 0x95, 0xfe, - 0x5a, 0x7b, 0xc4, 0xfd, 0x2b, 0x0d, 0x13, 0x5d, 0x24, 0x2a, 0x44, 0x67, 0xbf, 0x82, 0x2c, 0xa7, 0x02, 0x1c, 0xcb, - 0x33, 0xd1, 0xd0, 0x1f, 0x53, 0x88, 0x83, 0x0e, 0x0d, 0x7a, 0x57, 0x8a, 0xeb, 0xac, 0xe2, 0x21, 0xde, 0x13, 0x1c, - 0xcd, 0xe8, 0x7e, 0x83, 0x0f, 0x65, 0xed, 0xd1, 0xab, 0xc8, 0xc6, 0x51, 0xee, 0x37, 0xbf, 0x56, 0xe1, 0x1c, 0xa2, - 0x55, 0x2e, 0xa8, 0x52, 0x57, 0x5b, 0x00, 0x2a, 0xc7, 0xf6, 0xea, 0x11, 0x9c, 0x6e, 0xea, 0xfa, 0x56, 0x87, 0xd6, - 0x1c, 0x40, 0x98, 0x43, 0xb2, 0x69, 0xb8, 0xda, 0x01, 0xf6, 0x48, 0xac, 0xd7, 0x40, 0x63, 0xed, 0xd6, 0xec, 0xb4, - 0x47, 0x71, 0x98, 0xc8, 0x4c, 0x5b, 0xa4, 0x68, 0x73, 0xb7, 0x4e, 0x8b, 0xa2, 0x0d, 0x9a, 0x21, 0xec, 0xde, 0x75, - 0xf8, 0xba, 0x15, 0x61, 0x7d, 0xbf, 0xed, 0x0b, 0x8c, 0x86, 0x36, 0xd7, 0xee, 0x39, 0x86, 0x6e, 0xd8, 0x60, 0x13, - 0x39, 0x0f, 0x91, 0x0f, 0x33, 0x79, 0x20, 0x8a, 0xc6, 0x18, 0xb0, 0x3d, 0xe2, 0x6a, 0xd3, 0x4a, 0x7e, 0x5e, 0xc6, - 0x9c, 0xed, 0x19, 0xe3, 0x94, 0xd6, 0xd7, 0xb8, 0xe6, 0xb8, 0x2c, 0xa4, 0x6a, 0x8c, 0x67, 0x3c, 0x0c, 0x3b, 0x5f, - 0xe0, 0xce, 0xac, 0x31, 0x78, 0x11, 0x96, 0x4a, 0x76, 0x2a, 0x57, 0x9f, 0xc3, 0x16, 0x47, 0xb3, 0x31, 0xa7, 0xbf, - 0xff, 0x72, 0xc5, 0x17, 0xe8, 0xa6, 0x66, 0xfd, 0x08, 0x82, 0xac, 0x40, 0x87, 0x2c, 0xa9, 0x7a, 0xfc, 0xae, 0x04, - 0x6a, 0x0f, 0xf3, 0xf0, 0x5d, 0xc9, 0x8a, 0xf8, 0x26, 0xbb, 0x8a, 0x6b, 0x51, 0x8e, 0x6e, 0x78, 0x91, 0x8a, 0xd2, - 0x48, 0x8d, 0x83, 0xd3, 0xd5, 0x2a, 0xe7, 0x01, 0x98, 0xca, 0x1b, 0x46, 0xd9, 0x54, 0x96, 0xa9, 0xc1, 0x55, 0xf2, - 0xf4, 0x5a, 0x89, 0xce, 0xab, 0x9b, 0xab, 0x20, 0xc2, 0x5f, 0x17, 0xfa, 0xc7, 0x75, 0x5c, 0x7d, 0x0c, 0x22, 0x63, - 0x53, 0xa7, 0x7f, 0xa0, 0x54, 0x1e, 0xfc, 0xa7, 0x40, 0xa6, 0xfb, 0x5d, 0x09, 0x96, 0xd9, 0xa6, 0xe2, 0xe3, 0x18, - 0x6b, 0x1d, 0x4e, 0xc8, 0x4c, 0x96, 0xe8, 0xbc, 0x4b, 0xd6, 0x25, 0x58, 0xfb, 0x49, 0x2c, 0x63, 0x99, 0x6b, 0x86, - 0x95, 0xc9, 0x8a, 0xf4, 0xac, 0xac, 0xd9, 0x61, 0x68, 0x9c, 0x68, 0xe6, 0xe8, 0x2d, 0xa0, 0x1e, 0xc8, 0xe1, 0x15, - 0x2d, 0xd6, 0xcc, 0xf1, 0xb1, 0xf1, 0x5e, 0x3f, 0x3a, 0xbc, 0x72, 0x04, 0x4a, 0xe6, 0x4e, 0x8e, 0xc2, 0x44, 0xf0, - 0xac, 0xd5, 0xe3, 0x8b, 0x3c, 0x2b, 0x60, 0xe5, 0x4c, 0xc6, 0x63, 0xea, 0x2c, 0xad, 0xd6, 0xcd, 0xd1, 0x22, 0xb9, - 0x66, 0x8f, 0xeb, 0xc7, 0x9c, 0x1c, 0xf2, 0x96, 0xa9, 0x6d, 0xdb, 0x3a, 0xce, 0xd1, 0xe4, 0x4b, 0xd3, 0xfd, 0x6a, - 0x6d, 0x22, 0xa2, 0x4b, 0xe7, 0x3e, 0xeb, 0x15, 0xdc, 0xfa, 0xa6, 0xd0, 0xf4, 0x5a, 0x00, 0x10, 0x9d, 0x32, 0xe0, - 0x2f, 0x59, 0xb1, 0x1e, 0xd5, 0xbc, 0xaa, 0x41, 0xc2, 0x82, 0x22, 0xbc, 0x29, 0xf6, 0xa6, 0xb4, 0x37, 0x4e, 0xc7, - 0x61, 0x07, 0x2e, 0xa6, 0xe8, 0x8e, 0x03, 0x76, 0xfd, 0x5a, 0x2b, 0x1a, 0xa9, 0x5f, 0xb6, 0x2f, 0xb1, 0xea, 0x8b, - 0x52, 0xe6, 0x99, 0x9c, 0x12, 0x8b, 0xdd, 0x56, 0x2e, 0xac, 0xa8, 0xdf, 0x30, 0xe1, 0xd2, 0x95, 0x20, 0x20, 0xd3, - 0x92, 0xf5, 0x4a, 0xbd, 0x8b, 0xc4, 0x1a, 0x08, 0x19, 0x18, 0xbe, 0x06, 0xeb, 0xa2, 0xe2, 0xda, 0x0a, 0xd6, 0xb9, - 0xe7, 0xab, 0x84, 0x42, 0x14, 0x3c, 0xb0, 0x13, 0xf4, 0x43, 0xeb, 0xe6, 0x6d, 0x29, 0x51, 0x06, 0xf1, 0xb8, 0x95, - 0x53, 0x0e, 0x12, 0x08, 0xc0, 0x3d, 0x95, 0x21, 0x38, 0x24, 0xc8, 0x3a, 0xb8, 0x9a, 0x71, 0x04, 0x57, 0x97, 0xce, - 0x5c, 0x5c, 0x03, 0xac, 0x4b, 0x7f, 0x2e, 0x13, 0x5c, 0x58, 0x8d, 0xa8, 0x34, 0x67, 0x9c, 0x62, 0x10, 0x23, 0x43, - 0xd0, 0x57, 0x86, 0xd2, 0x5e, 0x81, 0xa6, 0xf1, 0x9a, 0xad, 0xa4, 0x0f, 0x00, 0xbd, 0x60, 0x2b, 0x69, 0xec, 0x8f, - 0x5f, 0x9f, 0xb3, 0x95, 0x92, 0x06, 0x4f, 0xaf, 0x67, 0x17, 0xb3, 0xf3, 0x01, 0x3b, 0x8a, 0x42, 0x65, 0xc0, 0x10, - 0x58, 0x24, 0xfe, 0x60, 0x10, 0x16, 0xb2, 0x11, 0x83, 0x42, 0x46, 0xc1, 0x72, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, - 0xc3, 0x02, 0x43, 0x5e, 0x79, 0x2f, 0x48, 0x40, 0xa8, 0x2e, 0x0d, 0x5d, 0x1e, 0xc3, 0xe1, 0xe4, 0x60, 0x02, 0xa9, - 0x98, 0x99, 0xc9, 0xc2, 0xd8, 0x98, 0x44, 0x10, 0xef, 0xb4, 0xb3, 0x5e, 0x28, 0xb7, 0xbb, 0xc6, 0x42, 0x8d, 0xc3, - 0xe0, 0xb3, 0x2a, 0x9e, 0x1c, 0x0c, 0xbb, 0x2a, 0xc6, 0x51, 0xb8, 0xd1, 0xca, 0xb7, 0xf3, 0x63, 0x00, 0xaf, 0x3d, - 0x1f, 0xba, 0x72, 0x89, 0xf3, 0xc3, 0x27, 0xe4, 0xf1, 0x13, 0x42, 0xcf, 0xd9, 0xf9, 0x17, 0x4f, 0xe8, 0xb9, 0x24, - 0x27, 0x07, 0x93, 0xe8, 0x86, 0xe9, 0x06, 0x1c, 0x1e, 0xc9, 0x26, 0xd0, 0xab, 0xd1, 0xba, 0x90, 0x0b, 0x4c, 0x39, - 0x34, 0x85, 0xdf, 0x8e, 0x0f, 0x82, 0xc1, 0x4d, 0xbb, 0xe9, 0x37, 0xed, 0xb6, 0x3a, 0x5e, 0x5d, 0x07, 0x47, 0xd1, - 0x6e, 0x31, 0x93, 0x6f, 0xc6, 0x07, 0x76, 0x0e, 0xb0, 0xbe, 0x87, 0xc7, 0x44, 0x37, 0x69, 0x67, 0x54, 0xdc, 0x9a, - 0xbe, 0xc2, 0x3e, 0xf8, 0x45, 0x76, 0xf4, 0x61, 0xf8, 0x6f, 0x75, 0xa2, 0x39, 0xff, 0xe2, 0x08, 0xc8, 0x11, 0xc8, - 0x40, 0xb1, 0x44, 0x30, 0xc3, 0x81, 0xa6, 0x80, 0x82, 0x4c, 0x8d, 0x3b, 0x55, 0xc3, 0x2f, 0x47, 0x4d, 0xce, 0xc8, - 0x0d, 0x4c, 0x0d, 0xb6, 0x05, 0x3f, 0x90, 0xdd, 0x50, 0xdf, 0x28, 0x74, 0x23, 0xe5, 0x64, 0xa6, 0x5f, 0x52, 0xfd, - 0x83, 0xdd, 0x40, 0x00, 0x63, 0x0b, 0x2f, 0x28, 0xd8, 0x97, 0xc7, 0x57, 0x07, 0xb8, 0x8a, 0x00, 0x25, 0x8b, 0x05, - 0x5f, 0x0e, 0xae, 0xd4, 0xe6, 0x3e, 0x08, 0xc8, 0xe0, 0xcb, 0xe0, 0xe4, 0xcb, 0x81, 0x18, 0x04, 0xc7, 0x87, 0x57, - 0x27, 0x81, 0x35, 0xee, 0x87, 0x10, 0x8f, 0xb2, 0xa2, 0x98, 0x69, 0x34, 0x1f, 0xf4, 0x82, 0x92, 0x89, 0xb9, 0xa9, - 0x57, 0x1a, 0x9f, 0xd1, 0x74, 0x6a, 0x90, 0xbf, 0xc3, 0x94, 0xc5, 0xfa, 0x77, 0x30, 0xe1, 0xd7, 0x41, 0x64, 0x83, - 0xa0, 0xce, 0xf2, 0x28, 0xa6, 0x4b, 0x76, 0x5f, 0x85, 0x29, 0x4d, 0x0e, 0x73, 0x42, 0xa2, 0x70, 0x29, 0xc1, 0xf3, - 0xe4, 0xeb, 0x04, 0xe2, 0xb8, 0xda, 0xcf, 0x01, 0xd7, 0x8d, 0xe6, 0x87, 0x09, 0x69, 0x15, 0x61, 0x23, 0xb2, 0x6c, - 0x1a, 0x7a, 0xc9, 0xc2, 0x15, 0xbd, 0x02, 0x66, 0x4a, 0xac, 0xc3, 0x2b, 0xe0, 0xf2, 0xd6, 0xf3, 0xd5, 0x82, 0x5d, - 0x79, 0xd2, 0x37, 0xcd, 0x17, 0x5f, 0x1a, 0x9f, 0x3c, 0xe0, 0x21, 0xad, 0x1f, 0x5e, 0x0a, 0x36, 0x00, 0x37, 0x19, - 0xbf, 0xfd, 0x4e, 0xdc, 0xa9, 0x79, 0x69, 0x4f, 0x31, 0xce, 0x4c, 0x3b, 0x31, 0x69, 0x27, 0xe4, 0xee, 0x7d, 0x7b, - 0x13, 0xeb, 0x93, 0xbd, 0x8a, 0xd6, 0xd2, 0x65, 0xd5, 0x30, 0x24, 0xe5, 0x9a, 0x21, 0x7f, 0x8f, 0x92, 0x53, 0x23, - 0xf0, 0x64, 0x97, 0xbc, 0x4e, 0x96, 0xee, 0x41, 0x65, 0xac, 0x06, 0xcc, 0x31, 0x62, 0x58, 0x28, 0x1c, 0xfb, 0xd7, - 0x19, 0x2b, 0xd7, 0xae, 0x40, 0x23, 0x46, 0xee, 0xed, 0x75, 0xc6, 0x9c, 0x98, 0xab, 0xc9, 0xda, 0x09, 0x55, 0xe7, - 0xa4, 0xe7, 0x2d, 0xde, 0xcb, 0x2a, 0x35, 0xb4, 0x44, 0xf4, 0x60, 0x2c, 0xcd, 0x28, 0x65, 0xa2, 0xd2, 0xa0, 0x91, - 0x8a, 0x8d, 0x6d, 0xf0, 0x4b, 0x70, 0x42, 0xe5, 0x8e, 0x3a, 0xdb, 0xb5, 0x53, 0x2a, 0x1c, 0x60, 0x59, 0xaa, 0x55, - 0xe5, 0x76, 0x99, 0x09, 0x56, 0x0f, 0x82, 0xd1, 0x1f, 0x95, 0x28, 0x66, 0x78, 0x67, 0x64, 0xc1, 0x14, 0xac, 0x04, - 0x65, 0x2d, 0xc3, 0x62, 0xc8, 0x51, 0x8b, 0xa7, 0x7d, 0x52, 0x85, 0xfa, 0xd1, 0x11, 0x24, 0x77, 0xb9, 0x6e, 0x05, - 0xc9, 0x7d, 0x32, 0x7e, 0xa2, 0x06, 0x3a, 0x5d, 0x2b, 0xc7, 0x43, 0x97, 0xdf, 0x46, 0x7c, 0x6d, 0xd5, 0x7b, 0xaa, - 0xb4, 0x0a, 0x55, 0xa0, 0xc4, 0x8a, 0xd2, 0x95, 0x5a, 0xd0, 0xfd, 0x2e, 0x02, 0x60, 0x11, 0x1b, 0xb3, 0xf1, 0xae, - 0x6d, 0x56, 0x08, 0x1a, 0x5d, 0x76, 0xb2, 0x89, 0x07, 0x2c, 0x51, 0xad, 0x1d, 0x4c, 0x68, 0x7c, 0xc2, 0x8a, 0x7e, - 0x3f, 0x3f, 0x01, 0x7a, 0xaa, 0x8c, 0x98, 0x4a, 0x38, 0xf2, 0x3f, 0xb7, 0x22, 0x5d, 0x14, 0xd8, 0xac, 0xc9, 0xbb, - 0x35, 0x96, 0x91, 0xa8, 0xcb, 0x94, 0x2a, 0xaf, 0x72, 0x0c, 0x98, 0xd6, 0xeb, 0x96, 0xe3, 0xca, 0xae, 0xe2, 0xc8, - 0x51, 0x61, 0x19, 0x71, 0x5e, 0x8d, 0xe3, 0xad, 0xc6, 0x37, 0x38, 0xd4, 0x6c, 0xda, 0xa5, 0x3b, 0x84, 0xb0, 0x10, - 0x5e, 0x67, 0x70, 0x1b, 0x51, 0x76, 0x12, 0xa8, 0xbc, 0xd1, 0xd7, 0x09, 0x69, 0x73, 0xbb, 0x5e, 0x3b, 0x06, 0xe9, - 0x44, 0x1f, 0x28, 0xf5, 0x08, 0x5a, 0xa3, 0x58, 0x50, 0x39, 0xe2, 0x91, 0xe5, 0xe1, 0xad, 0x41, 0xac, 0x92, 0x2f, - 0x29, 0x2a, 0x45, 0x03, 0xf4, 0xbf, 0xe4, 0xb7, 0x07, 0xbf, 0xbc, 0xff, 0xe9, 0x8c, 0xc7, 0x65, 0xb2, 0x7c, 0x17, - 0x97, 0xf1, 0x75, 0x15, 0x6e, 0xe4, 0x18, 0xc5, 0x0d, 0x99, 0x56, 0x03, 0x26, 0xf4, 0x4a, 0xf2, 0x77, 0xa5, 0x22, - 0xc4, 0x58, 0x67, 0xb2, 0xae, 0x6a, 0x71, 0xed, 0x55, 0xba, 0x2e, 0x33, 0xfc, 0xb8, 0xe5, 0x73, 0x7a, 0x08, 0x40, - 0x9e, 0xda, 0x85, 0x34, 0x12, 0xaa, 0x10, 0x6d, 0x2e, 0xe2, 0x74, 0x7d, 0x3c, 0xf6, 0xba, 0x5e, 0xb0, 0xa7, 0xe3, - 0xaf, 0xa6, 0xaf, 0xb3, 0x30, 0x1b, 0x54, 0x64, 0x54, 0x2f, 0x79, 0xd1, 0x32, 0xe5, 0x94, 0x26, 0x01, 0xe8, 0xe3, - 0xd9, 0x63, 0xec, 0x68, 0x3c, 0x26, 0x9b, 0xb6, 0x78, 0x80, 0x87, 0xcb, 0x75, 0x58, 0x92, 0x99, 0xaa, 0x23, 0x0a, - 0x0a, 0x7e, 0x57, 0x07, 0x80, 0xe4, 0x68, 0xaa, 0xd2, 0x5c, 0x1a, 0x7b, 0x3a, 0x9e, 0x50, 0x81, 0xdd, 0x0e, 0x49, - 0xe3, 0x54, 0x68, 0x67, 0x5e, 0xb8, 0x1e, 0x45, 0x42, 0xbb, 0x2c, 0xed, 0x54, 0x2a, 0xe4, 0x9e, 0x99, 0xd9, 0xae, - 0x41, 0x0c, 0x86, 0x50, 0xd5, 0x5d, 0x38, 0x75, 0xef, 0x36, 0xd7, 0x98, 0xed, 0x80, 0xf7, 0x1a, 0x34, 0x43, 0xca, - 0x5b, 0xf4, 0x5b, 0x5b, 0x44, 0x43, 0x57, 0x6b, 0x30, 0x2b, 0x46, 0xd9, 0x52, 0x94, 0xae, 0x29, 0x28, 0x05, 0xa3, - 0xcb, 0xb5, 0xb3, 0x70, 0x5f, 0x0b, 0xef, 0xc2, 0x92, 0xa9, 0xd5, 0x22, 0xa5, 0x84, 0xf2, 0xa6, 0xa2, 0xa5, 0x84, - 0x91, 0xd4, 0xf0, 0xd4, 0xae, 0x17, 0x78, 0x9c, 0xe7, 0x41, 0xd4, 0xf2, 0x02, 0x3b, 0xad, 0xc9, 0x29, 0x38, 0x7a, - 0xe9, 0x9c, 0x9a, 0x02, 0xff, 0x98, 0x49, 0x10, 0xd3, 0xa1, 0xbc, 0xdf, 0xe0, 0xe6, 0xff, 0x47, 0xc9, 0x02, 0x87, - 0x6f, 0xbd, 0xc2, 0x6d, 0xf4, 0x8f, 0xd2, 0xa5, 0xa5, 0xcf, 0x84, 0xeb, 0xea, 0xe2, 0x48, 0x7b, 0xb3, 0x51, 0xb2, - 0xcc, 0xf2, 0xf4, 0x8d, 0x48, 0x79, 0x45, 0xa4, 0x09, 0x46, 0xc5, 0x4e, 0x2a, 0xef, 0x86, 0x07, 0x46, 0x8c, 0xde, - 0x8d, 0xef, 0xc7, 0x0c, 0x64, 0xc3, 0x60, 0xf5, 0xcd, 0x52, 0x91, 0xac, 0xaf, 0x01, 0x53, 0x44, 0xca, 0x4f, 0x5e, - 0xe4, 0x1c, 0x9e, 0x42, 0x75, 0xfd, 0x02, 0xb7, 0xb9, 0xca, 0xf5, 0x39, 0xff, 0x31, 0xa3, 0x3f, 0x22, 0xd0, 0x49, - 0xbc, 0x02, 0xb9, 0xc7, 0x33, 0xa8, 0x1b, 0x61, 0x6a, 0x39, 0x06, 0x07, 0x42, 0x34, 0x90, 0xa2, 0x66, 0x81, 0x84, - 0xba, 0xd0, 0xc0, 0x1a, 0xf2, 0x82, 0x39, 0xbc, 0xc8, 0x45, 0xf2, 0x71, 0xaa, 0x7d, 0xe6, 0x87, 0x31, 0xc6, 0x4c, - 0x0e, 0x06, 0x61, 0x3d, 0x0b, 0x86, 0xe3, 0xd1, 0xe4, 0xe8, 0x29, 0x9c, 0xdb, 0xc1, 0x38, 0x20, 0x83, 0xa0, 0xa9, - 0x56, 0x71, 0x41, 0xab, 0x9b, 0x2b, 0x53, 0x06, 0x7e, 0xdc, 0x04, 0x83, 0x7f, 0x94, 0x8e, 0xe2, 0x1d, 0x34, 0x27, - 0xe7, 0x22, 0x04, 0x1b, 0xfb, 0x35, 0x01, 0x49, 0x59, 0x4f, 0xf1, 0x93, 0xea, 0x70, 0x63, 0x52, 0xfb, 0xa7, 0x0f, - 0x2f, 0x38, 0xec, 0x90, 0x40, 0x81, 0x34, 0x9e, 0x66, 0xa3, 0x57, 0x52, 0x91, 0xfb, 0xae, 0xe4, 0x70, 0x67, 0xee, - 0x59, 0xd3, 0x23, 0xab, 0x90, 0xf0, 0xb3, 0x80, 0x1b, 0xf9, 0xab, 0xe2, 0x26, 0xce, 0xb3, 0xf4, 0xc0, 0x7f, 0x73, - 0x50, 0xdd, 0x17, 0x75, 0x7c, 0x37, 0x0a, 0xb4, 0x35, 0x21, 0x77, 0x55, 0x4f, 0x80, 0x9e, 0x00, 0x5b, 0x00, 0x0c, - 0x88, 0x77, 0xcc, 0x4c, 0x66, 0x3c, 0x02, 0x8f, 0x40, 0xdf, 0x07, 0xb2, 0xbc, 0xb7, 0x2e, 0x49, 0xee, 0x66, 0x2a, - 0xcc, 0x55, 0xaf, 0xd8, 0x29, 0xc8, 0x78, 0xb5, 0x15, 0xbb, 0x6e, 0x7d, 0xe6, 0x4d, 0x87, 0x57, 0xe0, 0x85, 0x00, - 0xb7, 0xc8, 0x7e, 0xdf, 0x17, 0x54, 0x56, 0x5a, 0x45, 0xbc, 0x93, 0xdc, 0xa0, 0x7f, 0xbb, 0x33, 0x36, 0x92, 0xe4, - 0x56, 0x0f, 0x0f, 0xa0, 0xca, 0xe4, 0x5c, 0x71, 0x3b, 0x87, 0xa8, 0xad, 0xbb, 0x71, 0xc0, 0x6a, 0x83, 0x76, 0x59, - 0x73, 0x04, 0x17, 0x5e, 0x1c, 0x64, 0x90, 0x13, 0x67, 0x65, 0x24, 0xd5, 0xb8, 0x9a, 0xd4, 0x82, 0x4f, 0xf2, 0x74, - 0x0f, 0x59, 0xea, 0x09, 0x50, 0xe4, 0x38, 0x16, 0x43, 0xba, 0xf1, 0x26, 0xf0, 0xf8, 0xbd, 0x08, 0x41, 0x9a, 0xb6, - 0xdd, 0xfa, 0x23, 0x50, 0x74, 0x0f, 0x4c, 0x41, 0x9a, 0x46, 0x9b, 0x1a, 0x28, 0xa8, 0x3d, 0xd4, 0x48, 0x45, 0x9c, - 0x9d, 0xbc, 0x06, 0x1d, 0x22, 0xf8, 0x7e, 0xa7, 0x59, 0xd5, 0xf1, 0x62, 0x42, 0xf0, 0xe4, 0x7d, 0x71, 0x97, 0x55, - 0x75, 0x15, 0xbd, 0x4f, 0xd1, 0x10, 0x2a, 0x11, 0x45, 0xf4, 0x12, 0xe2, 0xe9, 0x55, 0xf8, 0xbb, 0x8a, 0x7e, 0x4a, - 0x69, 0x9c, 0xa6, 0x98, 0xfe, 0xbc, 0x84, 0x9f, 0xcf, 0x00, 0xd5, 0x11, 0x77, 0x42, 0x74, 0x21, 0xc0, 0x5e, 0x0d, - 0xa2, 0x59, 0xd5, 0x1c, 0x30, 0x34, 0xa3, 0xfb, 0x8a, 0x22, 0x46, 0x1b, 0x66, 0xff, 0xa1, 0x44, 0xa1, 0x90, 0x2c, - 0xe6, 0xd7, 0xca, 0x3c, 0x44, 0x3f, 0x62, 0x91, 0xa7, 0xef, 0x5e, 0xe9, 0x21, 0x8d, 0xee, 0x05, 0x55, 0x5b, 0x1b, - 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xad, 0xe9, 0x79, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, 0x4f, 0xbc, 0x7b, 0xf5, 0x4c, - 0x5a, 0x98, 0x3c, 0xcf, 0x40, 0x71, 0x70, 0xfa, 0xee, 0xd5, 0x6b, 0x91, 0xae, 0x73, 0x1e, 0x9d, 0x0b, 0x24, 0xad, - 0xa7, 0xef, 0x5e, 0xfd, 0x8c, 0xe6, 0x5e, 0x3f, 0x95, 0xf0, 0xfe, 0x25, 0xf0, 0x96, 0x51, 0xbc, 0x86, 0x3e, 0xc9, - 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd4, 0x5a, 0x45, 0xbf, 0xa4, 0x8d, 0x23, 0xad, 0xfa, 0x67, 0xe9, 0x52, 0x3b, 0x47, - 0xc0, 0x73, 0x97, 0x67, 0xc5, 0xc7, 0xc8, 0x88, 0x76, 0x82, 0xe8, 0xcb, 0x83, 0xbb, 0xeb, 0xbc, 0xa8, 0x22, 0x7c, - 0xc1, 0xd0, 0x2e, 0x28, 0x3a, 0x3c, 0xbc, 0xbd, 0xbd, 0x1d, 0xdd, 0x7e, 0x35, 0x12, 0xe5, 0xd5, 0xe1, 0xe4, 0xdb, - 0x6f, 0xbf, 0x3d, 0xc4, 0xb7, 0xc1, 0x97, 0x6d, 0xb7, 0xf7, 0x9a, 0xf0, 0x01, 0x0b, 0x10, 0xa1, 0xfa, 0x4b, 0xb8, - 0xa2, 0x80, 0x16, 0x6e, 0xf0, 0x65, 0xf0, 0xa5, 0x3a, 0x74, 0xbe, 0x3c, 0xae, 0x6e, 0xae, 0x64, 0xf9, 0x5d, 0x25, - 0x1f, 0x8d, 0xc7, 0xe3, 0x43, 0x90, 0x40, 0x7d, 0x39, 0xe0, 0x83, 0xe0, 0x24, 0x18, 0x64, 0x70, 0xa1, 0xa9, 0x6e, - 0xae, 0x4e, 0x02, 0xc7, 0x34, 0xd7, 0x63, 0x11, 0x2d, 0x88, 0x4b, 0x70, 0x78, 0x45, 0x83, 0x2f, 0x03, 0x62, 0x53, - 0xbe, 0x80, 0x94, 0x2f, 0x8e, 0x9e, 0xba, 0x69, 0xff, 0x4b, 0xa6, 0x7d, 0xe5, 0xa6, 0x1d, 0x63, 0xda, 0x57, 0xcf, - 0xdc, 0xb4, 0x13, 0x99, 0xf6, 0xc2, 0x4d, 0xfb, 0xdf, 0xd5, 0x00, 0x52, 0x0f, 0x5c, 0xeb, 0xbf, 0x0b, 0xa7, 0x35, - 0x78, 0x0a, 0x45, 0xd9, 0x75, 0x7c, 0xc5, 0xa1, 0xd1, 0x83, 0xbb, 0xeb, 0x9c, 0x06, 0x03, 0x6c, 0xaf, 0x63, 0xe4, - 0xe1, 0x7c, 0xf0, 0xe5, 0xba, 0xcc, 0xc3, 0xe0, 0xcb, 0x01, 0x16, 0x32, 0xf8, 0x32, 0x20, 0x5f, 0xaa, 0x23, 0xed, - 0xae, 0x62, 0x9b, 0xc0, 0x86, 0x22, 0x1d, 0x9a, 0x00, 0x61, 0xae, 0x34, 0xae, 0xa1, 0x7f, 0x96, 0xdd, 0xd9, 0xf0, - 0x96, 0x28, 0xdd, 0x74, 0x83, 0x86, 0xbe, 0x05, 0xef, 0x04, 0x68, 0x54, 0x14, 0xdc, 0xc4, 0x65, 0x38, 0x1c, 0x56, - 0x37, 0x57, 0x04, 0xec, 0x32, 0x57, 0x3c, 0xae, 0xa3, 0xa0, 0x10, 0x43, 0xf9, 0x33, 0x90, 0x91, 0xaf, 0x02, 0x04, - 0x44, 0x82, 0xff, 0x82, 0x86, 0xbe, 0x13, 0x6c, 0x13, 0x0c, 0x6f, 0xf9, 0xc5, 0xc7, 0xac, 0x1e, 0x4a, 0xd1, 0xe2, - 0x5d, 0x45, 0xe1, 0x07, 0xfc, 0xb5, 0x55, 0x47, 0x7f, 0x82, 0x1b, 0xb7, 0xaf, 0x61, 0x7f, 0x27, 0x2c, 0x8b, 0xfa, - 0x4e, 0xcc, 0xb3, 0xc5, 0xb4, 0x75, 0xa0, 0xbf, 0x15, 0xa4, 0x9e, 0x67, 0x83, 0x60, 0x18, 0x0c, 0xf8, 0x82, 0xbd, - 0x15, 0x73, 0xee, 0x98, 0x4f, 0x3d, 0x12, 0xee, 0x34, 0xcf, 0xb2, 0x01, 0xf8, 0xa6, 0x20, 0x3f, 0x72, 0xf8, 0xdf, - 0xf3, 0x21, 0x0a, 0x0f, 0x07, 0x8f, 0x0e, 0xc9, 0x2c, 0x58, 0xdd, 0xa1, 0x47, 0x67, 0x14, 0x64, 0xc5, 0x92, 0x97, - 0x59, 0xed, 0x2c, 0x95, 0xfb, 0x75, 0xdb, 0xcb, 0x63, 0xef, 0xd9, 0xbc, 0x8a, 0x8b, 0x40, 0x9e, 0x73, 0xa0, 0x78, - 0x43, 0xd9, 0x53, 0xe1, 0x4b, 0x48, 0x95, 0x21, 0x6f, 0x58, 0x0c, 0x58, 0x70, 0xdc, 0x1b, 0x0e, 0x0f, 0x82, 0x81, - 0x55, 0xe7, 0x0e, 0x82, 0x83, 0xe1, 0xf0, 0x24, 0xb0, 0xf7, 0xa1, 0x6c, 0x64, 0xef, 0x8c, 0xb4, 0x64, 0xff, 0x2c, - 0xc3, 0x82, 0x82, 0x78, 0x4c, 0x28, 0xf1, 0x97, 0x02, 0x97, 0x19, 0x00, 0xf4, 0x91, 0x94, 0x80, 0x69, 0x58, 0x99, - 0x01, 0x84, 0xe6, 0xa6, 0x31, 0x3b, 0x07, 0xe6, 0x91, 0x26, 0x20, 0xde, 0x03, 0x8a, 0x01, 0x88, 0x25, 0x01, 0xce, - 0x5d, 0x10, 0xc5, 0xaa, 0x90, 0x47, 0x00, 0x7a, 0x8f, 0x3f, 0x89, 0x2e, 0x05, 0x93, 0x54, 0xac, 0x42, 0x10, 0xc4, - 0xf1, 0xd9, 0x5d, 0xd5, 0x9a, 0x9c, 0x25, 0x3a, 0x98, 0x91, 0x04, 0xd8, 0x10, 0x0d, 0x3b, 0x07, 0xf7, 0x73, 0x50, - 0x7a, 0x18, 0xbd, 0x13, 0x72, 0xc1, 0xf7, 0xdc, 0xb2, 0x50, 0x77, 0x70, 0xf5, 0x84, 0x83, 0xe0, 0x9e, 0x2b, 0x16, - 0x60, 0x54, 0x97, 0xeb, 0xaa, 0xe6, 0xe9, 0x87, 0xfb, 0x15, 0xc4, 0xbe, 0xc3, 0x01, 0x7d, 0x27, 0xf2, 0x2c, 0xb9, - 0x0f, 0xad, 0x3d, 0xd7, 0x46, 0xa6, 0xff, 0xf0, 0xe1, 0xf5, 0x4f, 0x11, 0x88, 0x1c, 0x1b, 0x4d, 0xe9, 0xef, 0x39, - 0x9e, 0x4d, 0x6e, 0x84, 0x27, 0x77, 0x63, 0xdf, 0x73, 0x73, 0x7a, 0xf4, 0xfb, 0x50, 0x37, 0xbd, 0xe7, 0xb3, 0x7b, - 0x3e, 0xb2, 0xc5, 0xa1, 0xba, 0xc2, 0x7e, 0x7d, 0xbb, 0x76, 0x8d, 0x90, 0x1e, 0x9e, 0x67, 0xca, 0xbd, 0xf9, 0x51, - 0x0e, 0x86, 0x41, 0x30, 0x55, 0x42, 0x49, 0x88, 0xba, 0xc1, 0xa4, 0x80, 0x21, 0x3a, 0x50, 0xcb, 0x6a, 0x8a, 0x9c, - 0x9b, 0x1c, 0x59, 0x78, 0x3f, 0x60, 0x4a, 0xe8, 0xe0, 0xe5, 0x90, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc0, 0x6f, 0x15, - 0x30, 0xfd, 0x72, 0x51, 0x59, 0x07, 0xd1, 0x03, 0x30, 0xc6, 0x2d, 0x78, 0x09, 0x5d, 0x61, 0x37, 0x6b, 0x19, 0x15, - 0x03, 0xc1, 0xe3, 0x90, 0x03, 0x74, 0xb0, 0x0b, 0x5a, 0x56, 0x96, 0xf2, 0x56, 0x65, 0x2d, 0x55, 0xe4, 0x65, 0x28, - 0xab, 0x62, 0x89, 0xf9, 0x5e, 0xb0, 0x1f, 0x4a, 0xf4, 0x2c, 0x9f, 0x56, 0x5d, 0xf0, 0x42, 0x28, 0xc1, 0xb2, 0x5d, - 0xef, 0x44, 0x20, 0xea, 0x4c, 0x75, 0xae, 0xfa, 0x0a, 0xc7, 0x8e, 0xa7, 0xaf, 0x45, 0xca, 0x95, 0x09, 0x85, 0xe2, - 0xf3, 0x85, 0xab, 0x98, 0x28, 0xd9, 0x2d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd7, 0x6a, 0x33, 0x48, 0xd1, 0x31, - 0x6f, 0x50, 0x70, 0x2d, 0x15, 0x0a, 0x5a, 0x7b, 0x1b, 0x7f, 0x82, 0x23, 0x37, 0xba, 0x3d, 0xf4, 0x7e, 0xab, 0xe3, - 0xab, 0x37, 0xe8, 0xdb, 0x69, 0x7e, 0x8e, 0x6a, 0xf1, 0xcb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, 0xe0, 0xd2, - 0x42, 0x3d, 0x67, 0xef, 0x4e, 0xdf, 0x80, 0x1f, 0x25, 0xfe, 0xfe, 0xf5, 0xfb, 0xa0, 0x21, 0xd3, 0x78, 0x56, 0xea, - 0x0f, 0x4d, 0x0e, 0x08, 0x4d, 0x62, 0xd3, 0xcc, 0xfb, 0x59, 0xec, 0xb3, 0xef, 0x8a, 0xad, 0xa7, 0xa5, 0x8f, 0x24, - 0xa5, 0xb9, 0x7d, 0x30, 0x20, 0x50, 0x07, 0x88, 0xe4, 0xec, 0x4b, 0x1a, 0x43, 0x9a, 0xcb, 0xec, 0xbb, 0x11, 0xf1, - 0x5e, 0xec, 0x84, 0x10, 0xe3, 0x12, 0x8b, 0x46, 0x0d, 0xf9, 0x8c, 0x47, 0xd2, 0xb0, 0xe8, 0x3d, 0x26, 0x10, 0x6b, - 0x38, 0x2d, 0xdf, 0x23, 0xe6, 0x31, 0xde, 0x0d, 0x94, 0xec, 0x21, 0xca, 0xa8, 0xcd, 0xee, 0x59, 0x7c, 0x7f, 0x5c, - 0x87, 0x99, 0xb1, 0xbc, 0x1c, 0xc2, 0xdf, 0x40, 0x19, 0x80, 0x53, 0x8e, 0x2c, 0x5f, 0xad, 0x37, 0xba, 0x5c, 0x62, - 0x6a, 0x13, 0x41, 0x2c, 0x1e, 0x95, 0x0e, 0x6b, 0x57, 0xa5, 0xaa, 0x5d, 0x6d, 0x7d, 0x26, 0x7a, 0x35, 0x68, 0xe5, - 0xda, 0xf6, 0x78, 0x08, 0x77, 0xa9, 0xa4, 0x15, 0x26, 0xb0, 0x5e, 0x65, 0x15, 0x2a, 0xd8, 0x9c, 0x80, 0x06, 0xd7, - 0x22, 0x05, 0xe0, 0x2c, 0xa5, 0x46, 0xa3, 0x5a, 0xd8, 0x67, 0xe4, 0x7c, 0x16, 0x5b, 0x0b, 0xf1, 0xb4, 0x00, 0x0c, - 0xd7, 0xc7, 0xa0, 0xe4, 0xdd, 0x18, 0x94, 0xd3, 0x8f, 0x12, 0xde, 0x3a, 0x38, 0xaf, 0x96, 0x71, 0x2a, 0x6e, 0x01, - 0x8b, 0x31, 0x70, 0x53, 0xb1, 0x54, 0x27, 0x21, 0x59, 0xf2, 0xe4, 0x23, 0x5a, 0x6d, 0xa4, 0x01, 0x70, 0x95, 0x53, - 0x6d, 0xb9, 0x27, 0x41, 0x42, 0x6d, 0x29, 0x32, 0x21, 0xae, 0xeb, 0x38, 0x59, 0x9e, 0x61, 0x6a, 0xb8, 0x81, 0x5e, - 0x44, 0x81, 0x58, 0xf1, 0x02, 0x48, 0x7a, 0xce, 0xfe, 0x95, 0x29, 0xac, 0xf1, 0x67, 0x02, 0x05, 0x4c, 0x0a, 0x35, - 0x18, 0x2b, 0x65, 0x2f, 0x84, 0x8e, 0xf6, 0x16, 0x04, 0x8d, 0x7d, 0xf9, 0x27, 0xd4, 0xfd, 0x0c, 0x5a, 0x11, 0x7a, - 0x60, 0x88, 0xe2, 0x02, 0x77, 0x68, 0x6a, 0x96, 0x9c, 0x03, 0x8c, 0x58, 0x18, 0xef, 0xb3, 0xc6, 0x6c, 0xf5, 0x67, - 0x4b, 0xc0, 0x36, 0x4d, 0xb5, 0x4f, 0x61, 0x98, 0x10, 0x1d, 0x1b, 0xd8, 0x28, 0x2b, 0xcd, 0x86, 0xd2, 0xed, 0xa4, - 0x4b, 0xe6, 0xb4, 0x70, 0x9a, 0xf7, 0x18, 0x5b, 0x8e, 0x64, 0xee, 0x7e, 0x3f, 0xd4, 0x3f, 0x59, 0x4e, 0x9f, 0xa9, - 0x90, 0xcd, 0xce, 0x78, 0xd0, 0x9c, 0x28, 0x75, 0x55, 0x47, 0x3f, 0xa0, 0x03, 0x30, 0xd3, 0x06, 0x20, 0xd3, 0x06, - 0x9b, 0x76, 0x95, 0xa8, 0xb8, 0x24, 0x61, 0xa9, 0x24, 0xb0, 0xb3, 0x7d, 0xc9, 0xce, 0x26, 0x20, 0x8e, 0xe1, 0xae, - 0xa3, 0xc5, 0x4e, 0x88, 0x0f, 0x6f, 0x71, 0x90, 0x80, 0xa8, 0x43, 0x56, 0x97, 0x90, 0x8d, 0x36, 0x74, 0x71, 0x2f, - 0x4a, 0x61, 0xc2, 0x5a, 0x26, 0x55, 0x89, 0x0e, 0x82, 0x54, 0xed, 0xb6, 0x08, 0x2c, 0x51, 0xb0, 0x03, 0xd8, 0x7b, - 0x3b, 0xea, 0x7a, 0xd4, 0x64, 0x75, 0xf2, 0x25, 0xf8, 0x38, 0xcd, 0xba, 0x0a, 0xd2, 0x0b, 0xbb, 0x2e, 0xd7, 0x3c, - 0x50, 0xb1, 0xa9, 0xa4, 0x31, 0x71, 0x97, 0x16, 0x19, 0xe2, 0x01, 0x63, 0x2c, 0x5d, 0x08, 0xe4, 0x9b, 0xed, 0x8e, - 0x9b, 0x9a, 0x20, 0xf4, 0x13, 0xd6, 0x94, 0xc0, 0x4e, 0x67, 0x7b, 0x6a, 0xfc, 0x7c, 0x40, 0xc4, 0x61, 0x40, 0x81, - 0x64, 0xe3, 0x90, 0xe6, 0x48, 0x5f, 0x90, 0x34, 0x61, 0x60, 0x68, 0xc9, 0x73, 0x82, 0xac, 0x28, 0x74, 0x6c, 0x5d, - 0x95, 0x71, 0xae, 0x08, 0x73, 0xb4, 0xe4, 0x94, 0xf8, 0x9c, 0x20, 0x13, 0xdb, 0xd3, 0x36, 0x3d, 0x19, 0x96, 0x92, - 0x05, 0xfa, 0x57, 0x10, 0x25, 0xf6, 0x4c, 0x33, 0x2a, 0x07, 0xed, 0x02, 0x16, 0x28, 0xe5, 0x7b, 0xd0, 0x78, 0x6b, - 0x68, 0xa3, 0x60, 0x88, 0xed, 0xfe, 0x04, 0xfb, 0xb5, 0x76, 0x5a, 0x97, 0x29, 0x96, 0x93, 0x29, 0x44, 0x7b, 0x21, - 0xfd, 0x1b, 0x45, 0xa2, 0x3b, 0x45, 0x68, 0x12, 0xd6, 0x51, 0xf6, 0xa4, 0x4d, 0x0d, 0xa0, 0xa7, 0x4e, 0xc0, 0xf3, - 0xce, 0xb5, 0x0c, 0xbb, 0x48, 0xf5, 0x57, 0x06, 0x9f, 0x52, 0x0d, 0x82, 0x14, 0xb5, 0x49, 0xc1, 0x9c, 0xd7, 0xa1, - 0xa4, 0xce, 0x9c, 0xb6, 0xcc, 0xa8, 0x3a, 0x2a, 0x42, 0xca, 0x09, 0xfe, 0x93, 0x57, 0x42, 0x11, 0x9b, 0x30, 0xc1, - 0x03, 0x1f, 0xe6, 0x19, 0x36, 0xf0, 0x76, 0xfb, 0x2e, 0x0d, 0x93, 0x36, 0xdb, 0x90, 0x82, 0xb4, 0x42, 0xc7, 0xc5, - 0x80, 0xca, 0x5e, 0xe1, 0x7e, 0xc1, 0x76, 0xd2, 0x14, 0x3c, 0x08, 0xbd, 0x06, 0x26, 0x76, 0x75, 0xf1, 0x75, 0x98, - 0xd0, 0x70, 0x49, 0x95, 0xb3, 0x93, 0x92, 0x34, 0xb7, 0xd7, 0xe5, 0xa5, 0xe9, 0x83, 0x8a, 0x1d, 0xd6, 0x35, 0x3c, - 0xd0, 0x3c, 0xbf, 0x8b, 0x2b, 0xa6, 0x68, 0xa2, 0xb6, 0x1e, 0x92, 0x96, 0x1c, 0xeb, 0x66, 0xba, 0xc2, 0xd5, 0x32, - 0x53, 0xc0, 0xee, 0x02, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x89, 0xcd, 0x66, 0xab, 0x86, 0x4c, 0xf3, - 0x7d, 0xd9, 0x72, 0x1d, 0x10, 0xce, 0x50, 0xdf, 0xdc, 0x25, 0xc7, 0x8a, 0xb6, 0xb9, 0x49, 0x80, 0xe3, 0xed, 0x14, - 0x90, 0x74, 0x2c, 0x41, 0x1b, 0xdf, 0xd2, 0x1d, 0x44, 0xaa, 0xa7, 0x82, 0xee, 0x9d, 0x2f, 0xd2, 0xf8, 0x5f, 0x80, - 0x6d, 0xd4, 0x46, 0x9b, 0x66, 0x65, 0xeb, 0x30, 0x91, 0x16, 0xd6, 0xc8, 0x42, 0x2e, 0xc1, 0x07, 0x73, 0xb7, 0xa9, - 0xd3, 0xd3, 0x0e, 0x22, 0xec, 0x76, 0xd1, 0xe1, 0x11, 0xc6, 0x92, 0x35, 0x48, 0x34, 0xab, 0xb0, 0xa6, 0xfe, 0x72, - 0x88, 0x72, 0xaa, 0x97, 0x4c, 0xb4, 0xa4, 0x2e, 0xa5, 0x88, 0x52, 0x30, 0x37, 0x9e, 0x16, 0x9e, 0x29, 0x21, 0x42, - 0x56, 0x08, 0x0b, 0x54, 0x6b, 0xa0, 0xa5, 0x7c, 0xd0, 0xeb, 0xd0, 0xc9, 0x42, 0x63, 0x0a, 0xa2, 0x8f, 0x48, 0x73, - 0x23, 0x96, 0x8c, 0xee, 0x8e, 0x51, 0x4c, 0x20, 0x54, 0xb5, 0x93, 0x17, 0x56, 0x9f, 0x92, 0x6d, 0x75, 0x10, 0xd7, - 0x98, 0x26, 0x7b, 0x08, 0x6a, 0x8c, 0x82, 0x36, 0xab, 0x1b, 0xfd, 0xa5, 0x0c, 0x5d, 0xbb, 0x70, 0xec, 0x46, 0x49, - 0x04, 0x44, 0x60, 0x75, 0x9a, 0x8a, 0x01, 0x59, 0xe7, 0xb1, 0x8d, 0xd0, 0xa4, 0xba, 0x85, 0x28, 0x6f, 0x54, 0x34, - 0x1f, 0xd7, 0x21, 0xd9, 0x6e, 0xb1, 0x2c, 0xf0, 0x65, 0x3f, 0x5b, 0xef, 0x81, 0xfc, 0x7e, 0xbd, 0xfe, 0x24, 0xe4, - 0xf7, 0xab, 0xec, 0x73, 0x20, 0xbf, 0x5f, 0xaf, 0xff, 0xa7, 0x21, 0xbf, 0xcf, 0xd6, 0x0e, 0xe4, 0xb7, 0x1c, 0x8c, - 0xdf, 0x4a, 0x16, 0xbc, 0x7d, 0x13, 0xd0, 0xe7, 0x82, 0x05, 0x6f, 0x5f, 0xbe, 0x74, 0x84, 0xe9, 0xdf, 0xe9, 0x38, - 0x2f, 0x5a, 0x16, 0x8c, 0xb8, 0x2d, 0xf0, 0x0a, 0xb5, 0x4e, 0x2e, 0x50, 0x51, 0x06, 0xc0, 0xeb, 0xd5, 0x3f, 0xb2, - 0x7a, 0x19, 0x06, 0x87, 0x01, 0x99, 0x59, 0x48, 0xd0, 0xe1, 0x04, 0x6e, 0x6f, 0x68, 0x64, 0x59, 0x7f, 0x16, 0x7c, - 0xf8, 0x68, 0x34, 0x8a, 0xcb, 0x2b, 0xbc, 0xd4, 0xe9, 0x8d, 0x84, 0x80, 0xc7, 0x19, 0xaf, 0x4c, 0x88, 0x88, 0x65, - 0x5c, 0x9d, 0xab, 0xd8, 0x2c, 0x95, 0xd9, 0x8a, 0x10, 0x71, 0xfe, 0x1c, 0x70, 0xea, 0xcd, 0xde, 0x8c, 0xb1, 0x1f, - 0x92, 0x23, 0x56, 0x01, 0x64, 0x9f, 0xad, 0xd5, 0xbb, 0x8b, 0xb8, 0xe2, 0xef, 0xe2, 0x7a, 0xc9, 0xa0, 0x97, 0x70, - 0x17, 0x29, 0x78, 0x52, 0x3b, 0x6c, 0x93, 0x04, 0x2a, 0xcf, 0x14, 0x50, 0x79, 0xc7, 0x7b, 0x1a, 0x9a, 0x61, 0x51, - 0x3e, 0xc0, 0x5a, 0xba, 0x9c, 0x81, 0xd1, 0xe2, 0x8b, 0x1b, 0x5e, 0xd4, 0x3f, 0x01, 0x9e, 0x7a, 0xc1, 0x4b, 0xb8, - 0x25, 0x20, 0x17, 0xeb, 0x39, 0x21, 0xd0, 0xca, 0xf5, 0xec, 0x90, 0x51, 0x63, 0xb4, 0x68, 0xc2, 0xeb, 0x37, 0xde, - 0x84, 0xd0, 0xbb, 0x13, 0x74, 0x45, 0x18, 0x09, 0xef, 0xcf, 0x35, 0x3f, 0xcf, 0xc0, 0x7c, 0xbe, 0x02, 0x28, 0x0d, - 0x84, 0x43, 0x65, 0x52, 0x6e, 0x81, 0x09, 0x1b, 0x6d, 0xae, 0x94, 0xa5, 0x0e, 0x52, 0x29, 0x95, 0x70, 0xba, 0x15, - 0x4d, 0x05, 0xe0, 0x70, 0x47, 0x02, 0xc0, 0x4c, 0x4d, 0x61, 0x10, 0xdd, 0x36, 0xa5, 0x59, 0x1a, 0x59, 0x45, 0x9a, - 0xc5, 0x27, 0xa5, 0x12, 0x74, 0xfa, 0x3c, 0x89, 0x6b, 0x7e, 0x25, 0x4a, 0x08, 0x85, 0xdb, 0x4a, 0x69, 0x0c, 0x16, - 0x80, 0x3c, 0xee, 0xac, 0xcd, 0xd6, 0xac, 0x94, 0x29, 0xe7, 0xc5, 0xfa, 0x9a, 0x97, 0x59, 0x72, 0xbe, 0xcc, 0xaa, - 0x5a, 0x94, 0xf7, 0x6c, 0xae, 0xb2, 0x2e, 0xa2, 0x6a, 0xa4, 0x24, 0x5e, 0xe7, 0x35, 0xbf, 0x5e, 0x41, 0xe8, 0x87, - 0x75, 0x09, 0xac, 0xe7, 0xde, 0x2f, 0x65, 0x64, 0xd2, 0xb0, 0xf3, 0x3b, 0xb2, 0x00, 0xbd, 0x2b, 0xac, 0x11, 0xb9, - 0x00, 0x98, 0x5e, 0x33, 0xa7, 0x92, 0xaa, 0x94, 0xfe, 0x6b, 0x8d, 0x33, 0xef, 0x2f, 0xaa, 0x71, 0x6b, 0xed, 0x19, - 0xad, 0xad, 0x9f, 0x2a, 0xe1, 0x94, 0x80, 0x12, 0xb1, 0x13, 0x5c, 0x31, 0x29, 0x5d, 0x1b, 0xb4, 0x16, 0xb0, 0xac, - 0xc0, 0x1c, 0x59, 0x71, 0x75, 0x7e, 0x2b, 0x65, 0x35, 0x3d, 0x49, 0xcd, 0xd2, 0x28, 0x96, 0x28, 0x42, 0x4b, 0x16, - 0xae, 0x59, 0xb2, 0x27, 0xd7, 0x3a, 0x4a, 0x3c, 0x3c, 0xb0, 0xb8, 0x3d, 0xe8, 0xc7, 0x49, 0x3b, 0x65, 0xbb, 0xdd, - 0xc9, 0x04, 0x6c, 0x48, 0x2b, 0x09, 0x22, 0x83, 0x2c, 0x67, 0xc3, 0x49, 0x04, 0x70, 0x2d, 0x8a, 0x84, 0xfe, 0xb9, - 0xe6, 0x1a, 0xd0, 0x3e, 0x54, 0x5e, 0x85, 0x72, 0x15, 0xcd, 0xc1, 0xce, 0xcb, 0xed, 0x35, 0x04, 0x96, 0xe9, 0x9c, - 0x97, 0xc5, 0xfe, 0x35, 0xa0, 0xcc, 0x91, 0xd5, 0x0b, 0xb2, 0x6f, 0xc6, 0x55, 0xb6, 0x07, 0xa7, 0xb7, 0x35, 0x07, - 0x7b, 0x5b, 0xa3, 0x50, 0x7a, 0x13, 0x1e, 0x0e, 0x9f, 0x8e, 0x8d, 0x3f, 0x03, 0xae, 0x72, 0xf3, 0x5b, 0xee, 0x04, - 0xfb, 0x6c, 0x76, 0x03, 0xf5, 0x5d, 0x22, 0xda, 0x35, 0xd2, 0x6a, 0xcf, 0xb8, 0x35, 0xa4, 0xb1, 0x2b, 0xcd, 0x88, - 0xb9, 0x7e, 0x97, 0x47, 0xeb, 0xf9, 0xa3, 0x4d, 0xa6, 0xaa, 0x6c, 0x7e, 0xcf, 0x4c, 0x50, 0x3c, 0x8f, 0x4c, 0x35, - 0x6a, 0x0d, 0xba, 0x98, 0x74, 0x1d, 0xd9, 0xd4, 0x8c, 0xb2, 0xac, 0x93, 0xd6, 0x8d, 0xe4, 0x23, 0x97, 0x31, 0xc2, - 0xba, 0xb3, 0xf0, 0x3b, 0x9e, 0x84, 0x5d, 0x0d, 0x93, 0xd7, 0x10, 0xdd, 0x05, 0x84, 0xe9, 0x04, 0xe5, 0x43, 0xf8, - 0xfb, 0xa3, 0x8d, 0x4f, 0x3b, 0x9b, 0x43, 0xe7, 0x33, 0xfc, 0x9d, 0xa5, 0xf0, 0xb7, 0x6e, 0x7e, 0xa7, 0x9b, 0x6b, - 0x5e, 0x2f, 0x45, 0x1a, 0x05, 0xef, 0xde, 0x9e, 0x7d, 0x08, 0x14, 0xfc, 0x3b, 0x5e, 0x82, 0xb4, 0xda, 0x5b, 0x03, - 0x4d, 0x81, 0x1a, 0x28, 0x17, 0x57, 0x88, 0x80, 0xa8, 0x20, 0xf4, 0xcf, 0x96, 0xe2, 0xf6, 0x34, 0xcf, 0x5d, 0x4e, - 0x5d, 0x53, 0x77, 0xc5, 0xbc, 0x7a, 0xa4, 0x31, 0x04, 0x81, 0xe3, 0x28, 0xab, 0xce, 0x95, 0x8a, 0x28, 0x3d, 0xbf, - 0xb8, 0x3f, 0x57, 0x62, 0x28, 0x03, 0x41, 0xf9, 0xec, 0xf7, 0xe3, 0x34, 0xbb, 0x39, 0xc0, 0x23, 0x88, 0x05, 0x60, - 0xbf, 0x9f, 0xf3, 0x8b, 0x75, 0x5d, 0x8b, 0x62, 0x58, 0x8a, 0xdb, 0xe0, 0xe4, 0x58, 0x3e, 0xe8, 0x0c, 0xb1, 0x7c, - 0x0c, 0x0e, 0xfe, 0x2b, 0xc9, 0xb3, 0xe4, 0x23, 0x0b, 0x1e, 0x6d, 0x32, 0x76, 0xd2, 0x3a, 0x68, 0xc6, 0x4d, 0x70, - 0x02, 0x6d, 0x3d, 0x38, 0xcd, 0xf3, 0xe3, 0x43, 0xf9, 0xc5, 0xc9, 0xf1, 0x61, 0x9a, 0xdd, 0x9c, 0x38, 0xd1, 0x00, - 0xac, 0x71, 0x2f, 0xe2, 0xae, 0xd9, 0xcb, 0x3b, 0x78, 0xf1, 0x26, 0x3c, 0x34, 0xec, 0x0e, 0x88, 0x8c, 0x74, 0x2c, - 0x15, 0x14, 0x33, 0x85, 0x31, 0x1c, 0xee, 0xdb, 0x6d, 0x68, 0x2c, 0x8f, 0x12, 0x07, 0x96, 0xa7, 0x04, 0x76, 0x08, - 0xb3, 0xd0, 0x84, 0xd0, 0xa4, 0x21, 0xa1, 0x06, 0x0f, 0x8a, 0x09, 0x2d, 0x1b, 0x0a, 0xe7, 0xdd, 0xeb, 0x78, 0xa5, - 0x25, 0x6d, 0x4a, 0x72, 0xa1, 0x5b, 0x3f, 0xf3, 0xc6, 0x31, 0x6a, 0x8f, 0xaa, 0x86, 0xf3, 0xea, 0x15, 0xfb, 0x06, - 0x16, 0x84, 0xab, 0x61, 0x4d, 0x83, 0x16, 0x69, 0x01, 0xe1, 0xa8, 0x2b, 0xd3, 0xe3, 0x34, 0x9c, 0x17, 0x54, 0x2c, - 0x08, 0x3b, 0x09, 0x37, 0xc8, 0xdb, 0x17, 0x54, 0xb2, 0xfa, 0xa2, 0xb1, 0xd8, 0x9a, 0x72, 0x76, 0x4e, 0x1e, 0x6d, - 0x64, 0xcc, 0xde, 0x82, 0x9d, 0xf8, 0xf3, 0x55, 0xc7, 0x17, 0xc3, 0x25, 0x07, 0x27, 0xa0, 0xe0, 0xe0, 0xbf, 0xd2, - 0x8b, 0xdc, 0x4c, 0x8a, 0x5c, 0x91, 0xcb, 0xb8, 0x48, 0x73, 0xfe, 0x21, 0xbe, 0xf8, 0x01, 0xf3, 0x3c, 0xbf, 0xc8, - 0x9f, 0x41, 0x86, 0x26, 0x38, 0x79, 0xb4, 0x49, 0xea, 0xd1, 0x8b, 0x37, 0x1f, 0x5e, 0x7d, 0xf8, 0xe7, 0xf9, 0xb3, - 0xd3, 0x0f, 0x2f, 0xbe, 0x7f, 0xfb, 0xfe, 0xd5, 0x8b, 0xb3, 0xb9, 0xf1, 0xba, 0x95, 0x60, 0x6e, 0x64, 0xb1, 0xdd, - 0xda, 0x7c, 0xbf, 0xbc, 0x79, 0xfe, 0xe2, 0xe5, 0xab, 0x37, 0x2f, 0x9e, 0x37, 0x72, 0x2e, 0xdb, 0x0d, 0x81, 0x1d, - 0x1a, 0x67, 0x05, 0x2f, 0xa1, 0x78, 0x75, 0xbb, 0xc3, 0x66, 0x2b, 0x0c, 0x42, 0xbf, 0xe9, 0x2a, 0x5c, 0x03, 0x2c, - 0xb2, 0x03, 0xb5, 0x59, 0xa0, 0xe1, 0x42, 0x6f, 0x1c, 0x77, 0x89, 0xb9, 0xbd, 0x79, 0x81, 0xdf, 0xbd, 0x17, 0xb7, - 0xba, 0x2b, 0x6a, 0x84, 0x24, 0xbc, 0xd8, 0xec, 0xd9, 0xef, 0xc7, 0xae, 0x48, 0x0f, 0xe5, 0x1e, 0xb2, 0x5c, 0xf8, - 0xd5, 0x04, 0x07, 0xca, 0xbc, 0x30, 0x80, 0xe8, 0x18, 0xc1, 0xc9, 0xf1, 0xa1, 0x9b, 0xfb, 0xe4, 0xf7, 0xe8, 0x27, - 0xa7, 0x73, 0x58, 0x2a, 0x8c, 0x83, 0x9f, 0xb6, 0x73, 0x2c, 0x02, 0x7d, 0xb6, 0x07, 0xa7, 0x5c, 0x41, 0x9a, 0x5c, - 0x09, 0x12, 0x99, 0x49, 0x94, 0x66, 0x33, 0xba, 0xb4, 0xdf, 0xd5, 0x5f, 0xdb, 0x67, 0x14, 0x43, 0xf0, 0xa2, 0x12, - 0x25, 0xd8, 0xb8, 0x38, 0x89, 0x49, 0x0e, 0x82, 0x0f, 0x1e, 0x40, 0xef, 0xda, 0xa1, 0x2e, 0x0e, 0x9c, 0x90, 0x32, - 0xd8, 0xcf, 0x4e, 0xa2, 0x0f, 0xe3, 0x74, 0xd8, 0xfe, 0xd4, 0xe9, 0xee, 0xef, 0xc4, 0xfe, 0x38, 0x50, 0x5d, 0x6c, - 0x11, 0x1d, 0xd3, 0xec, 0xfd, 0x21, 0x49, 0xe6, 0x6f, 0xff, 0x4f, 0x73, 0x4f, 0xbb, 0xdd, 0xb6, 0x71, 0xe5, 0xff, - 0x3e, 0x05, 0x0c, 0xbb, 0x0e, 0x60, 0x03, 0x10, 0x40, 0x8a, 0x92, 0x4c, 0x8a, 0x52, 0x13, 0xdb, 0x39, 0x51, 0xaa, - 0xd4, 0x39, 0x8e, 0xea, 0x6d, 0xa3, 0xe8, 0x98, 0x43, 0x70, 0x48, 0xa2, 0x02, 0x01, 0x1e, 0x00, 0x94, 0xa8, 0xd0, - 0xe8, 0x53, 0xec, 0xff, 0xed, 0x73, 0xec, 0xfe, 0xeb, 0x13, 0xed, 0x23, 0xec, 0xb9, 0x77, 0x3e, 0x30, 0xf8, 0x22, - 0xa9, 0xc4, 0x69, 0xf7, 0xa4, 0xaa, 0x89, 0xc1, 0xcc, 0x60, 0xe6, 0xce, 0xcc, 0x9d, 0xfb, 0x7d, 0x03, 0xeb, 0x3f, - 0x62, 0x6b, 0x46, 0xac, 0x05, 0xb1, 0x6e, 0xd3, 0x9b, 0xbc, 0x71, 0xcd, 0x64, 0xba, 0x1b, 0x4c, 0x89, 0x68, 0x18, - 0x10, 0x37, 0x83, 0x73, 0x33, 0x9c, 0xc6, 0x0f, 0xc4, 0x05, 0x77, 0x45, 0x92, 0x19, 0x15, 0x89, 0x66, 0xc4, 0xdb, - 0x8c, 0x43, 0xc6, 0x2c, 0xc1, 0xcb, 0x30, 0xe8, 0xe3, 0xba, 0xa1, 0x6a, 0x37, 0x02, 0xc2, 0x18, 0x43, 0xf3, 0x09, - 0xb7, 0xac, 0x08, 0x1c, 0x3f, 0x4b, 0xc2, 0x3f, 0xd2, 0x07, 0x20, 0x5e, 0xd3, 0x2c, 0x5e, 0x02, 0xcb, 0x42, 0x66, - 0x5c, 0x04, 0x65, 0x19, 0xe9, 0x7e, 0x1f, 0x84, 0x64, 0x59, 0xb8, 0xe9, 0x81, 0xee, 0x75, 0xb2, 0x78, 0x36, 0x0b, - 0xa9, 0xa1, 0x8b, 0x1c, 0x2a, 0xba, 0x25, 0x3f, 0x73, 0xfe, 0xc4, 0x15, 0x81, 0x4b, 0xcd, 0xbc, 0xed, 0xf0, 0x0a, - 0xe8, 0x51, 0x19, 0xd9, 0x8f, 0x11, 0xf0, 0x28, 0xa2, 0xbe, 0x43, 0x2d, 0x0f, 0x5f, 0xe3, 0x02, 0x39, 0xd8, 0x93, - 0x78, 0x35, 0x0e, 0xa9, 0x8d, 0x07, 0x0a, 0x3e, 0xb9, 0x19, 0xaf, 0xc6, 0x63, 0x48, 0x56, 0xf3, 0xc4, 0xb5, 0x20, - 0xfc, 0x4e, 0x9c, 0x22, 0x5b, 0x9c, 0x9b, 0x03, 0x80, 0xa2, 0x93, 0x95, 0x87, 0xcf, 0xb2, 0x77, 0x82, 0xc4, 0x8b, - 0x7d, 0x20, 0x03, 0x16, 0xb8, 0x01, 0x2f, 0x0c, 0xf5, 0x1f, 0x60, 0x7f, 0xa7, 0xfa, 0xa0, 0x09, 0xb9, 0x0c, 0xaf, - 0xf5, 0x1f, 0x70, 0xb1, 0x30, 0x89, 0xf3, 0x6b, 0x76, 0x3e, 0x74, 0x4b, 0x67, 0xba, 0xff, 0x15, 0xa6, 0x73, 0x00, - 0xd9, 0xf7, 0x9b, 0x80, 0xcc, 0xa2, 0x38, 0xcd, 0x02, 0x5f, 0xbf, 0x19, 0x5c, 0x04, 0xc6, 0xf5, 0x22, 0x33, 0xcc, - 0x1b, 0xcb, 0xcf, 0xd4, 0x4c, 0x30, 0x02, 0x25, 0x63, 0x22, 0x98, 0xb6, 0x4a, 0xea, 0x19, 0xdd, 0x5a, 0x51, 0x20, - 0x7f, 0xac, 0xe4, 0x67, 0x43, 0xa8, 0x57, 0x49, 0x2b, 0x83, 0xf9, 0xb1, 0x74, 0x6c, 0x69, 0x0e, 0x18, 0xc3, 0xf6, - 0x7a, 0xb5, 0x41, 0x62, 0x21, 0x2b, 0xee, 0x63, 0x0c, 0x85, 0x2c, 0xfc, 0x87, 0xd8, 0xf3, 0x13, 0xd5, 0xf6, 0xb5, - 0x74, 0xb3, 0x8f, 0xbe, 0x2c, 0x53, 0x1e, 0x40, 0x21, 0x80, 0xe1, 0x49, 0x14, 0x67, 0x1a, 0xc4, 0xf7, 0x81, 0x2f, - 0x8e, 0xaa, 0xb6, 0x72, 0xbc, 0x57, 0xc3, 0xcc, 0x39, 0xba, 0xf9, 0x0a, 0xaf, 0x57, 0x83, 0x47, 0x79, 0x2b, 0x05, - 0xf2, 0x60, 0x3c, 0x53, 0x0a, 0x0b, 0x98, 0xc5, 0x97, 0xf1, 0x7d, 0x55, 0x1d, 0xf4, 0x7a, 0xb4, 0xfb, 0x76, 0x37, - 0x04, 0x05, 0x2f, 0x92, 0x1b, 0x1a, 0x3c, 0x3f, 0xab, 0x20, 0xa5, 0x2a, 0xa7, 0x0a, 0xed, 0x5f, 0x04, 0x95, 0x94, - 0x81, 0xb9, 0x1c, 0xde, 0x36, 0x80, 0xf4, 0x38, 0x21, 0x30, 0xca, 0x91, 0x6c, 0x95, 0xc9, 0x9f, 0x84, 0xc3, 0x4b, - 0x79, 0xdc, 0xe9, 0x10, 0xa5, 0xb2, 0xf3, 0x60, 0x36, 0xd7, 0xcf, 0x33, 0xbe, 0x23, 0x55, 0x7a, 0xf7, 0x23, 0xbc, - 0xea, 0x37, 0xbd, 0x81, 0x84, 0x54, 0x0d, 0xf5, 0xc3, 0xf8, 0x1e, 0xbc, 0xd9, 0x8b, 0x5e, 0x39, 0x35, 0xdd, 0xda, - 0xb9, 0xf9, 0x52, 0xd6, 0x80, 0xac, 0xe2, 0x66, 0x7f, 0x4b, 0x83, 0xf6, 0x6f, 0x56, 0x7b, 0xb1, 0xe2, 0x47, 0x8d, - 0xc1, 0xfe, 0x2c, 0x63, 0xa8, 0xf4, 0x32, 0x88, 0x86, 0xd1, 0x99, 0x2c, 0x5a, 0x90, 0x35, 0x36, 0x30, 0xcf, 0xeb, - 0x45, 0xfd, 0xc8, 0x8a, 0x87, 0xf1, 0x9e, 0x75, 0x63, 0x6e, 0x78, 0x4c, 0xcf, 0x47, 0x29, 0xcd, 0xce, 0x1b, 0xc6, - 0x02, 0x1b, 0x61, 0xf8, 0x6c, 0x13, 0xe5, 0xa3, 0x7e, 0x4b, 0x15, 0xf6, 0xd6, 0x22, 0xbb, 0x3b, 0x89, 0xb7, 0x76, - 0x12, 0xe7, 0xa3, 0xc7, 0x6c, 0x73, 0x9f, 0xef, 0xf2, 0x70, 0xe0, 0x37, 0x61, 0xfa, 0xb0, 0x71, 0xcf, 0x43, 0x30, - 0xda, 0xd2, 0x6e, 0x4f, 0x70, 0xb7, 0xff, 0xef, 0x7f, 0xfd, 0xe7, 0x7f, 0x17, 0x64, 0xef, 0x38, 0x39, 0x3b, 0xc5, - 0x8c, 0x64, 0x40, 0xc5, 0xe5, 0xa7, 0x07, 0xec, 0x37, 0x16, 0xff, 0x8b, 0x46, 0x45, 0xc4, 0xa8, 0xfe, 0x47, 0x3d, - 0x83, 0x22, 0x8b, 0xbb, 0xc8, 0xa1, 0xae, 0x90, 0xe0, 0x40, 0x43, 0x45, 0xcb, 0x55, 0x86, 0x51, 0xbf, 0x61, 0x1c, - 0x34, 0xd7, 0x35, 0x8c, 0x22, 0x0c, 0xb4, 0x58, 0xc1, 0x0c, 0xe6, 0xba, 0x16, 0x4c, 0xea, 0x65, 0x9c, 0xc9, 0x05, - 0x62, 0x04, 0xa9, 0x38, 0x94, 0x99, 0xc3, 0x63, 0xc2, 0xa7, 0xe3, 0x5b, 0x45, 0xca, 0x0c, 0xc3, 0x47, 0xdd, 0x72, - 0xc3, 0xfd, 0xec, 0xb3, 0x7e, 0x06, 0xfb, 0x4e, 0x73, 0x04, 0xf0, 0x3d, 0x87, 0xed, 0x33, 0x7c, 0xb6, 0x21, 0xc0, - 0xaf, 0xe5, 0x3a, 0x4c, 0xb4, 0xf0, 0x19, 0x2c, 0xa6, 0x07, 0x88, 0x9d, 0x95, 0x6b, 0x68, 0x34, 0x34, 0xe4, 0xa6, - 0x41, 0xcb, 0x24, 0x58, 0x90, 0xe4, 0x81, 0x59, 0x12, 0x59, 0xaa, 0xb9, 0x91, 0xa9, 0x6b, 0x8c, 0x7a, 0x63, 0xf3, - 0x65, 0x84, 0x9c, 0xae, 0xfd, 0x41, 0x96, 0x51, 0x3e, 0x39, 0x81, 0xbe, 0x74, 0xf8, 0xd6, 0x47, 0xfd, 0x25, 0x75, - 0x26, 0x34, 0x23, 0x41, 0xc8, 0x9a, 0x0c, 0x8c, 0xa8, 0x65, 0x36, 0x51, 0x79, 0x36, 0x69, 0x19, 0x65, 0xe3, 0x64, - 0x18, 0x05, 0xc7, 0xc6, 0x8d, 0x33, 0x43, 0x14, 0xda, 0xbc, 0x80, 0xec, 0x9d, 0xb2, 0x97, 0x00, 0xf8, 0x49, 0x7d, - 0x17, 0xe5, 0xed, 0x4b, 0xd4, 0x50, 0xfb, 0xb7, 0x59, 0x36, 0x0a, 0xcb, 0x96, 0xc2, 0xb2, 0xd1, 0xc8, 0x8f, 0x27, - 0xf4, 0xcf, 0xef, 0x2f, 0x64, 0xa6, 0x3f, 0x10, 0x5a, 0x8f, 0xf8, 0x25, 0x12, 0x21, 0x37, 0x91, 0x20, 0x27, 0xc1, - 0x72, 0xf2, 0x69, 0x72, 0xab, 0x25, 0xb9, 0xae, 0x9d, 0xb3, 0x49, 0xd3, 0x09, 0x9b, 0xc9, 0x30, 0xc6, 0x56, 0x49, - 0x7e, 0x7a, 0xc0, 0x6a, 0x33, 0x2a, 0x97, 0x55, 0x02, 0xf8, 0x25, 0x30, 0xeb, 0x02, 0x7c, 0x90, 0x94, 0x78, 0xe8, - 0x15, 0xe2, 0x05, 0x67, 0x81, 0xaa, 0x41, 0xef, 0xbc, 0xcc, 0xb8, 0x60, 0x2b, 0xbd, 0x38, 0xd4, 0x31, 0x04, 0x26, - 0x12, 0xe7, 0x5a, 0xab, 0x9c, 0x9c, 0xa2, 0x13, 0x21, 0xf2, 0xe9, 0xf3, 0x0e, 0x1e, 0x75, 0xa4, 0x00, 0x6b, 0x43, - 0x29, 0xc9, 0x75, 0x6d, 0xc1, 0x19, 0x25, 0x1e, 0x01, 0x0d, 0xc2, 0xa3, 0xb8, 0x70, 0xcf, 0xea, 0xda, 0x82, 0xac, - 0x71, 0xe6, 0xe2, 0x0d, 0x59, 0x1b, 0x1e, 0x7f, 0x55, 0x9c, 0xc9, 0xa8, 0xbc, 0xe0, 0x02, 0xc5, 0x80, 0xef, 0x93, - 0x14, 0xd0, 0xcd, 0xd1, 0xa6, 0xa4, 0x61, 0x71, 0xe7, 0x62, 0x71, 0x27, 0x2d, 0x8b, 0x3b, 0xd9, 0xb2, 0xb8, 0x21, - 0x5f, 0x48, 0x4d, 0x82, 0x2e, 0x41, 0x7f, 0xd6, 0x02, 0x29, 0x32, 0x06, 0xa3, 0xcf, 0x0f, 0x28, 0xc2, 0xc9, 0x4e, - 0x43, 0xb0, 0xe7, 0x6c, 0x81, 0x55, 0x13, 0x5c, 0x14, 0x40, 0xd4, 0x27, 0x2e, 0x8f, 0xab, 0x44, 0xad, 0xd6, 0x1c, - 0xb6, 0xaa, 0x5f, 0xa5, 0x79, 0x43, 0xd6, 0xd0, 0x32, 0xe6, 0x2d, 0x33, 0x9d, 0x6f, 0x99, 0xa9, 0x5f, 0x3a, 0xf3, - 0x7c, 0xda, 0xec, 0xf4, 0xaa, 0x93, 0x62, 0xa4, 0xd0, 0x3a, 0xc3, 0x2d, 0x53, 0xde, 0x87, 0xed, 0xb8, 0x58, 0xd9, - 0x51, 0x4b, 0x92, 0xa6, 0xf7, 0x71, 0x02, 0x4a, 0x62, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x11, 0x44, 0x3c, 0xfe, 0x54, - 0xeb, 0x66, 0x2a, 0xde, 0xab, 0x5b, 0xaa, 0xd3, 0xeb, 0xb1, 0x1a, 0x4b, 0x92, 0x65, 0x34, 0x41, 0xa0, 0x13, 0x48, - 0x54, 0xf0, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0xd0, 0x2c, 0xae, 0x03, 0x44, 0xed, 0x4b, 0xe0, 0x83, 0x12, 0x41, - 0x34, 0x2b, 0xb1, 0x2c, 0x13, 0x09, 0x78, 0x4e, 0xdf, 0x24, 0x8a, 0xb7, 0xa5, 0x77, 0x64, 0x3a, 0x4b, 0x32, 0xf9, - 0x01, 0x6c, 0x11, 0x8c, 0x8e, 0x05, 0x7e, 0x05, 0x6a, 0xe4, 0xca, 0x84, 0x31, 0x66, 0x7e, 0x81, 0x24, 0x11, 0x4b, - 0x72, 0xab, 0x4d, 0x70, 0xf8, 0x26, 0xf6, 0xf4, 0x66, 0xd3, 0xc9, 0x0f, 0x66, 0x81, 0x59, 0xc3, 0x9a, 0x80, 0xda, - 0xc2, 0xe1, 0x99, 0x94, 0xc0, 0x84, 0x96, 0x77, 0x64, 0x82, 0xb2, 0xea, 0x1a, 0x52, 0x30, 0xbb, 0x42, 0xbc, 0x35, - 0x4a, 0xe0, 0x76, 0xbb, 0x76, 0x6f, 0xf2, 0xe7, 0x33, 0xfc, 0xe5, 0xdd, 0xe4, 0xcf, 0xc7, 0xf8, 0xab, 0x73, 0x83, - 0xc9, 0x36, 0x1b, 0xc4, 0x7a, 0xca, 0x9c, 0xf5, 0xb3, 0xd2, 0x7e, 0x62, 0x26, 0xb3, 0x8f, 0xd8, 0x36, 0x7c, 0x81, - 0x9f, 0x3e, 0xdb, 0x44, 0xe0, 0x24, 0xae, 0xce, 0x21, 0x75, 0x12, 0x33, 0x6f, 0x2c, 0x9f, 0xb5, 0x94, 0x8f, 0xcd, - 0x7f, 0x31, 0x81, 0x80, 0xbb, 0x24, 0x2e, 0xee, 0x94, 0xb2, 0x50, 0xf2, 0xe3, 0x38, 0x88, 0x48, 0xf2, 0xf0, 0x91, - 0xc9, 0x14, 0x0c, 0xc1, 0x67, 0x4b, 0x61, 0x2b, 0x63, 0x05, 0xcb, 0x1a, 0xfa, 0x4c, 0xd1, 0x49, 0x3d, 0x70, 0x0a, - 0x61, 0xf8, 0x97, 0x44, 0xa1, 0x3d, 0x4b, 0xe2, 0x28, 0xbe, 0x20, 0xa5, 0x0f, 0x7d, 0x7c, 0xb6, 0x31, 0x68, 0xbd, - 0x9b, 0x9a, 0xb8, 0xa2, 0x44, 0x10, 0xc0, 0xf2, 0xa0, 0x68, 0x6b, 0x31, 0x09, 0xfa, 0xa8, 0x82, 0x1f, 0xc7, 0x6b, - 0xfb, 0xd9, 0x26, 0x3b, 0xd7, 0x17, 0x24, 0xb9, 0xa5, 0x13, 0xdb, 0x0f, 0x12, 0x3f, 0xa4, 0x7a, 0x5f, 0x1f, 0x87, - 0x24, 0xba, 0xe5, 0x8f, 0x76, 0xbc, 0xca, 0xd0, 0xa8, 0x66, 0xa7, 0x24, 0x4c, 0xc0, 0x84, 0x09, 0xf0, 0x91, 0x41, - 0x6b, 0x80, 0x82, 0xf6, 0x5a, 0x8a, 0xbf, 0x0b, 0x82, 0xb2, 0xa8, 0x65, 0x81, 0x4d, 0x38, 0xd8, 0xf9, 0x80, 0x93, - 0xbd, 0xa5, 0xe3, 0x7a, 0xe9, 0x96, 0x3a, 0x55, 0xa6, 0xf7, 0x90, 0x59, 0x62, 0x3f, 0x62, 0x0f, 0xbf, 0xfc, 0x73, - 0x50, 0xf2, 0x98, 0xcf, 0x71, 0xe2, 0xb0, 0xfd, 0x83, 0x6a, 0x63, 0x92, 0xa6, 0xab, 0x05, 0x9d, 0x30, 0x7b, 0x82, - 0xf3, 0x62, 0x28, 0x65, 0x46, 0x5c, 0x1d, 0xce, 0x4f, 0xab, 0xce, 0xf1, 0xe1, 0x6b, 0xb0, 0x73, 0x02, 0x62, 0x30, - 0x9e, 0x4e, 0xf5, 0x42, 0xbc, 0xb6, 0xa3, 0x99, 0x77, 0xf8, 0xd3, 0xea, 0xeb, 0xb7, 0xee, 0xd7, 0xb2, 0x71, 0xa4, - 0x9b, 0xf9, 0x48, 0x18, 0x6d, 0x70, 0x9a, 0x56, 0x19, 0xaf, 0x98, 0xd1, 0x94, 0x44, 0xed, 0xd3, 0xb9, 0x2e, 0xed, - 0xb2, 0x25, 0xa5, 0x13, 0xb0, 0xe7, 0xb7, 0x6a, 0xa5, 0x1f, 0x43, 0x7a, 0x47, 0xa5, 0x41, 0x48, 0xfd, 0x63, 0x0d, - 0x2d, 0x30, 0x62, 0x25, 0x37, 0x34, 0xe1, 0x84, 0x95, 0x32, 0xa5, 0x11, 0xce, 0x81, 0xcf, 0x5c, 0xdd, 0xe5, 0x95, - 0x5d, 0x3d, 0xb2, 0x74, 0x65, 0x00, 0xad, 0x23, 0x3b, 0x6f, 0x29, 0xef, 0x63, 0xba, 0xfa, 0xe6, 0xb1, 0x59, 0x9e, - 0xd9, 0x87, 0x08, 0xff, 0x1c, 0x4e, 0x21, 0x6c, 0x7e, 0x43, 0x4a, 0x22, 0x07, 0x6d, 0x10, 0x6b, 0x92, 0x5a, 0xeb, - 0x4c, 0xf0, 0x29, 0x6c, 0xa4, 0xd1, 0x59, 0x40, 0x08, 0x86, 0x1b, 0xd7, 0x46, 0x2b, 0xcf, 0x7c, 0x8c, 0x69, 0xa0, - 0x23, 0x9a, 0xa6, 0xad, 0x00, 0x93, 0x8b, 0x6e, 0xe9, 0x45, 0xed, 0x32, 0x3c, 0x8a, 0x72, 0xcb, 0xb5, 0xe0, 0x56, - 0xc6, 0x09, 0x56, 0xbf, 0x85, 0x18, 0xfe, 0xe3, 0x82, 0x5b, 0xb9, 0x25, 0xb3, 0xb1, 0xce, 0x2d, 0x90, 0xda, 0xde, - 0xdf, 0xeb, 0x7c, 0x50, 0xa5, 0x9b, 0xb2, 0x71, 0x68, 0x46, 0x09, 0xfb, 0xd5, 0xc4, 0xb4, 0xd8, 0x81, 0x18, 0x53, - 0x05, 0xc5, 0xd1, 0xe9, 0x94, 0xfa, 0x59, 0x6a, 0x0a, 0x59, 0xab, 0x8c, 0x39, 0x0d, 0xbe, 0x86, 0x4f, 0x86, 0xfa, - 0x9f, 0x20, 0xf2, 0x86, 0x08, 0xcd, 0xc6, 0x07, 0x24, 0xf8, 0x9d, 0x66, 0x30, 0xb1, 0x1e, 0xcb, 0x20, 0xe2, 0x5f, - 0xf9, 0xf4, 0x49, 0x98, 0x48, 0x94, 0xca, 0x71, 0x68, 0xfc, 0x0a, 0x28, 0xf6, 0x45, 0x2c, 0x6d, 0xe1, 0xb6, 0x23, - 0xa0, 0x6d, 0xc7, 0x77, 0xe3, 0x7d, 0xdd, 0xf3, 0xdc, 0x5c, 0xb7, 0xc0, 0xe3, 0xf3, 0x76, 0xdf, 0x43, 0x8f, 0xad, - 0xba, 0xd0, 0x6a, 0x15, 0x3d, 0xa6, 0x5d, 0xc7, 0x7b, 0xe5, 0xe9, 0x16, 0x33, 0xb4, 0x55, 0x70, 0x9b, 0x1f, 0xdf, - 0xd1, 0xe4, 0x57, 0x4f, 0xa5, 0xdc, 0xf9, 0x7e, 0xe3, 0x39, 0xf2, 0x5c, 0x40, 0xc2, 0x59, 0xbc, 0x7c, 0xc4, 0x14, - 0xba, 0xba, 0xa5, 0xfb, 0x61, 0x9c, 0x52, 0x75, 0x0e, 0x4c, 0x5e, 0xf1, 0x2b, 0x27, 0xf1, 0xfd, 0xfb, 0xb7, 0x3f, - 0xfc, 0xa0, 0x5b, 0x98, 0x3f, 0x38, 0x55, 0x7b, 0xe7, 0x1b, 0x6a, 0x07, 0xf6, 0x6f, 0xdc, 0x77, 0xec, 0x86, 0x61, - 0x7c, 0x65, 0x79, 0xcf, 0xb1, 0xb2, 0xda, 0x96, 0xe3, 0x37, 0x0f, 0xff, 0x32, 0x63, 0x06, 0xf7, 0x9a, 0x57, 0x03, - 0x6e, 0xd8, 0x7e, 0xbd, 0x95, 0x4a, 0x16, 0x41, 0xf4, 0xb1, 0xa1, 0x94, 0xac, 0x1b, 0x4a, 0x51, 0x36, 0x58, 0xc5, - 0x1f, 0xab, 0x78, 0xa1, 0xdc, 0xce, 0x90, 0xfe, 0x7d, 0x17, 0xb8, 0x14, 0x96, 0xe6, 0x57, 0x0c, 0x9a, 0xe7, 0x7f, - 0xa8, 0x8e, 0xba, 0xa1, 0x98, 0xf3, 0x21, 0x12, 0xb6, 0x5c, 0x97, 0xa3, 0xaa, 0xc9, 0xcb, 0x94, 0x9b, 0xda, 0xb8, - 0x59, 0x60, 0xfa, 0xa4, 0x70, 0xbe, 0xd9, 0x51, 0x19, 0x84, 0xb4, 0xb2, 0x76, 0x41, 0x13, 0x6c, 0xed, 0x3d, 0xff, - 0xe7, 0x3f, 0x1c, 0xe7, 0x9f, 0xff, 0xd8, 0x59, 0x15, 0xfa, 0xce, 0x81, 0x1d, 0xde, 0x55, 0x33, 0x1f, 0xa1, 0xd0, - 0x29, 0x1b, 0xbe, 0x1e, 0x8d, 0x06, 0x46, 0x09, 0x64, 0xe0, 0x33, 0x72, 0x5e, 0x2b, 0xe1, 0x78, 0xb5, 0xef, 0x9a, - 0x18, 0xcc, 0x01, 0x1a, 0xca, 0xeb, 0xab, 0x75, 0xb3, 0x33, 0xa7, 0x84, 0x5a, 0x5f, 0xb5, 0x9d, 0x0e, 0xa5, 0x98, - 0xb8, 0x2e, 0x1f, 0x99, 0x3c, 0xc7, 0x00, 0x8c, 0x8b, 0xab, 0x0f, 0x4a, 0x2b, 0x07, 0x7e, 0x36, 0x59, 0x79, 0x7c, - 0xbc, 0xac, 0x32, 0x42, 0xba, 0xd7, 0x08, 0x59, 0xdb, 0xf2, 0x18, 0x79, 0x7f, 0xb5, 0x51, 0xb2, 0x72, 0x31, 0x4e, - 0x0b, 0x45, 0x66, 0x3c, 0xca, 0x08, 0x67, 0x9a, 0xb8, 0x4a, 0xb0, 0xa4, 0xf6, 0xad, 0xa8, 0x2e, 0x94, 0x21, 0xec, - 0x5e, 0xf6, 0x73, 0x3d, 0x8c, 0xef, 0xd1, 0x59, 0x4f, 0xd5, 0x27, 0x73, 0x61, 0xc8, 0x69, 0x9a, 0x25, 0x71, 0x34, - 0x3b, 0xab, 0x5c, 0xde, 0x75, 0x3b, 0x1f, 0x90, 0x60, 0xb1, 0xaa, 0x65, 0xb1, 0x89, 0x3a, 0xca, 0xed, 0x5b, 0xea, - 0x7c, 0xc7, 0x4c, 0x98, 0x6a, 0x42, 0xb9, 0x1c, 0x45, 0xd7, 0x0d, 0x6a, 0x70, 0x95, 0x94, 0x2b, 0xbf, 0x96, 0x8f, - 0x07, 0x1c, 0xae, 0x67, 0xa3, 0x1c, 0x93, 0x1d, 0xbd, 0x6b, 0x33, 0x10, 0xfd, 0x7e, 0xb7, 0x81, 0xe8, 0xd5, 0x5e, - 0x06, 0xa2, 0xdf, 0x7f, 0x76, 0x03, 0xd1, 0x77, 0xaa, 0x81, 0x28, 0x6c, 0xe9, 0xb7, 0x74, 0x2f, 0xab, 0x4d, 0x61, - 0x0d, 0x15, 0xdf, 0xa7, 0x43, 0x8f, 0x53, 0xa6, 0xa9, 0x3f, 0xa7, 0xc0, 0x6d, 0xf3, 0x6d, 0x1a, 0xc6, 0x33, 0xb0, - 0xe0, 0xfc, 0xed, 0x6d, 0x2d, 0xc3, 0x78, 0xa6, 0x5a, 0x5a, 0xa6, 0x3c, 0xdc, 0x73, 0x11, 0xc2, 0x8d, 0x59, 0x37, - 0xba, 0x96, 0x38, 0x7b, 0xf6, 0xa1, 0xa9, 0xa4, 0xb4, 0x97, 0xa6, 0xab, 0x1d, 0x61, 0xff, 0xd8, 0x47, 0xd3, 0x49, - 0xd9, 0xb0, 0xf3, 0x32, 0x96, 0x49, 0x7b, 0x8a, 0x1e, 0xa4, 0x8b, 0x00, 0x0b, 0x12, 0xb3, 0xd1, 0x7f, 0x5a, 0x7b, - 0x5f, 0x5d, 0x7b, 0x83, 0xae, 0x07, 0x91, 0x19, 0x80, 0x57, 0xc3, 0x02, 0x77, 0xd0, 0xed, 0x42, 0xc1, 0xbd, 0x52, - 0xd0, 0x81, 0x82, 0x40, 0x29, 0xe8, 0x41, 0x81, 0xaf, 0x14, 0x1c, 0x41, 0xc1, 0x44, 0x29, 0x38, 0x86, 0x82, 0x3b, - 0x3d, 0xbf, 0x2e, 0x12, 0x39, 0x1d, 0x9b, 0x37, 0x16, 0xe3, 0x0d, 0x44, 0xd9, 0xb1, 0xe5, 0x81, 0x19, 0x23, 0x99, - 0xf5, 0x63, 0x8b, 0xc9, 0xe9, 0xfa, 0x89, 0x75, 0x3f, 0xa7, 0x2c, 0x4a, 0xfc, 0x1b, 0xbc, 0x3a, 0x9c, 0x2c, 0x06, - 0xa7, 0x09, 0x11, 0x7d, 0x45, 0xc0, 0x41, 0xd3, 0x4d, 0x10, 0xbd, 0x0c, 0xe4, 0xca, 0x89, 0x08, 0x36, 0xca, 0x5a, - 0x16, 0xef, 0xd8, 0xe7, 0x6c, 0xb9, 0x05, 0x0a, 0x4b, 0x2e, 0x43, 0x95, 0xef, 0x7d, 0x0e, 0x7b, 0x9e, 0x37, 0x74, - 0xbc, 0x9a, 0x69, 0x97, 0xf1, 0x6c, 0xa7, 0x69, 0x8e, 0xfa, 0x0a, 0x46, 0xa9, 0x33, 0x0d, 0x88, 0x2d, 0xb6, 0x25, - 0xff, 0x16, 0x7b, 0xcc, 0xcb, 0xf5, 0x33, 0x18, 0x9b, 0x96, 0x31, 0xc3, 0x30, 0xf8, 0x0e, 0xc0, 0x48, 0x39, 0xf5, - 0x97, 0x00, 0x67, 0xe5, 0xf9, 0x8a, 0x28, 0xe3, 0x39, 0xfb, 0x8e, 0xa6, 0x29, 0x99, 0x89, 0xfa, 0xf5, 0x71, 0x82, - 0x31, 0x9c, 0x64, 0xa3, 0x10, 0x80, 0x20, 0x13, 0x0b, 0x6a, 0x36, 0x4f, 0x49, 0x7c, 0xaf, 0x81, 0x55, 0x1d, 0x6c, - 0xa8, 0xc2, 0xfe, 0x27, 0x70, 0x60, 0x09, 0xcb, 0x38, 0x08, 0x0e, 0xff, 0x1d, 0x0d, 0xab, 0x85, 0x19, 0x99, 0x55, - 0x8b, 0xd8, 0x3e, 0xc8, 0xd5, 0xb1, 0x49, 0x93, 0x98, 0x52, 0xe1, 0xaf, 0xb1, 0xcb, 0x08, 0xe3, 0xd9, 0x6f, 0x6a, - 0x94, 0xb1, 0xc5, 0x30, 0xe7, 0x36, 0xb5, 0x82, 0x6c, 0xe4, 0x20, 0x8c, 0x35, 0x07, 0x40, 0xd8, 0x8f, 0xb2, 0xb9, - 0x8d, 0x7e, 0xa5, 0x46, 0x27, 0x32, 0x2d, 0x07, 0xd7, 0x76, 0x53, 0xf5, 0xa6, 0xef, 0x27, 0xb3, 0x31, 0x31, 0xbc, - 0xce, 0xb1, 0x25, 0xfe, 0x1c, 0xb7, 0x67, 0xe6, 0xd8, 0x83, 0x36, 0x09, 0xee, 0x36, 0xd3, 0x38, 0xca, 0xec, 0x29, - 0x59, 0x04, 0xe1, 0x43, 0x7f, 0x11, 0x47, 0x71, 0xba, 0x24, 0x3e, 0x1d, 0x14, 0x7c, 0xf1, 0x00, 0xe3, 0xb4, 0x70, - 0x57, 0x61, 0xcf, 0xe9, 0x24, 0x74, 0xc1, 0x5a, 0xcb, 0x30, 0x2c, 0xd3, 0x90, 0xae, 0x73, 0xfe, 0xf9, 0x52, 0x65, - 0x56, 0x15, 0xb7, 0x1c, 0x6b, 0x01, 0x84, 0x25, 0x8f, 0xf1, 0x02, 0x91, 0xcd, 0x06, 0x4b, 0x32, 0xc1, 0xb0, 0xa4, - 0x4e, 0xa7, 0x97, 0xd0, 0x85, 0xe6, 0xf4, 0x5a, 0x3b, 0x4f, 0xe2, 0xfb, 0x33, 0x18, 0x2d, 0x36, 0xb6, 0x53, 0x1a, - 0x4e, 0xf1, 0x8d, 0x8d, 0x6e, 0x65, 0xa2, 0x1f, 0x1b, 0xf9, 0x69, 0xe8, 0x8d, 0x2e, 0x06, 0xf0, 0xba, 0xdf, 0xd1, - 0xdc, 0xc1, 0x22, 0x88, 0x6c, 0x36, 0x9d, 0x63, 0x77, 0xa9, 0xf4, 0xa5, 0xc2, 0xcf, 0xdc, 0x60, 0x75, 0x4f, 0x73, - 0x07, 0xc0, 0x73, 0x4d, 0xc3, 0xf8, 0xbe, 0x3f, 0x0f, 0x26, 0x13, 0x1a, 0x0d, 0x70, 0xcc, 0xb2, 0x90, 0x86, 0x61, - 0xb0, 0x4c, 0x83, 0x74, 0xb0, 0x20, 0x6b, 0xde, 0xeb, 0x61, 0x5b, 0xaf, 0x5d, 0xde, 0x6b, 0x77, 0xef, 0x5e, 0x95, - 0x6e, 0xc0, 0x85, 0x8d, 0xf5, 0xc3, 0x87, 0xd6, 0xd3, 0xdc, 0xca, 0x3c, 0xf7, 0xee, 0x75, 0x99, 0xd0, 0xcd, 0x82, - 0x24, 0xb3, 0x20, 0xea, 0xbb, 0xb9, 0x73, 0xb7, 0x61, 0x1b, 0xe3, 0xe9, 0xc9, 0xc9, 0x49, 0xee, 0x4c, 0xc4, 0x93, - 0x3b, 0x99, 0xe4, 0x8e, 0x2f, 0x9e, 0xa6, 0x53, 0xd7, 0x9d, 0x4e, 0x73, 0x27, 0x10, 0x05, 0xdd, 0x8e, 0x3f, 0xe9, - 0x76, 0x72, 0xe7, 0x5e, 0xa9, 0x91, 0x3b, 0x94, 0x3f, 0x25, 0x74, 0x32, 0xc0, 0x8d, 0xc4, 0xec, 0xbc, 0xfb, 0xc7, - 0xae, 0x9b, 0x23, 0x06, 0xb8, 0x2e, 0xe1, 0x26, 0x14, 0xd9, 0xdc, 0x6c, 0xf6, 0xae, 0xa9, 0x15, 0x9f, 0xf3, 0xfd, - 0xc6, 0x7a, 0x13, 0x92, 0xdc, 0xde, 0x68, 0xca, 0x2c, 0x08, 0x61, 0xd5, 0x36, 0x02, 0x0c, 0xf6, 0xba, 0x0f, 0xf1, - 0xfa, 0x06, 0xe3, 0x38, 0x81, 0x33, 0x9b, 0x90, 0x49, 0xb0, 0x4a, 0xfb, 0x5e, 0x67, 0xb9, 0x16, 0x45, 0x7c, 0xaf, - 0x17, 0x05, 0x78, 0xf6, 0xfa, 0x69, 0x1c, 0x06, 0x13, 0x51, 0xd4, 0x76, 0x96, 0xbc, 0x8e, 0x39, 0xc0, 0x68, 0x15, - 0x01, 0xc6, 0x5c, 0x21, 0x61, 0xa8, 0x39, 0xdd, 0x54, 0xa3, 0x24, 0x45, 0x49, 0xad, 0xe6, 0xa6, 0x0c, 0x2e, 0x18, - 0x99, 0xc2, 0x3b, 0x5c, 0xae, 0xe5, 0x9e, 0xf7, 0x8e, 0x96, 0xeb, 0xfc, 0x0f, 0x0b, 0x3a, 0x09, 0x88, 0x66, 0x14, - 0xbb, 0xc9, 0x73, 0x41, 0x9a, 0x6b, 0x6e, 0x5a, 0xb6, 0xa9, 0x38, 0x16, 0x10, 0xd7, 0xf4, 0x49, 0xb0, 0x58, 0xc6, - 0x49, 0x46, 0xa2, 0x2c, 0xcf, 0x47, 0x37, 0x79, 0x3e, 0xb8, 0x0a, 0x8c, 0xeb, 0xbf, 0x1a, 0xec, 0x9e, 0x66, 0xda, - 0x8f, 0xdc, 0xbc, 0xb1, 0xde, 0x52, 0xd5, 0x52, 0x0a, 0xae, 0x31, 0xb4, 0x92, 0x52, 0x2b, 0xb3, 0x5b, 0xb2, 0x5e, - 0x99, 0x01, 0x59, 0x56, 0x67, 0x96, 0x57, 0xe5, 0x2a, 0x78, 0x03, 0x41, 0x85, 0xb7, 0x74, 0x78, 0xa5, 0x58, 0x5d, - 0x01, 0xb1, 0x82, 0x95, 0x99, 0x53, 0xd1, 0xb3, 0x36, 0x9a, 0xf1, 0xcb, 0xdd, 0x34, 0xe3, 0x8f, 0xd9, 0x3e, 0x34, - 0xe3, 0x97, 0x9f, 0x9d, 0x66, 0x7c, 0x56, 0x77, 0x2a, 0xba, 0x88, 0x87, 0xba, 0x94, 0xd5, 0xc3, 0xd5, 0x94, 0xb0, - 0x70, 0x5d, 0x17, 0xbf, 0xd8, 0x07, 0x48, 0xf4, 0xc6, 0x12, 0x50, 0xb2, 0x9b, 0x1b, 0x68, 0xf1, 0x77, 0xd1, 0xf0, - 0x2f, 0x89, 0xfa, 0x3c, 0x9d, 0x0e, 0xdf, 0xc4, 0x4a, 0x81, 0x7c, 0xe2, 0xf6, 0x0f, 0xa5, 0xd0, 0x2a, 0xec, 0x8d, - 0xb0, 0x6e, 0xc6, 0xe4, 0x33, 0x10, 0x99, 0x81, 0x59, 0xf3, 0x4f, 0xa4, 0xfd, 0xe6, 0xa0, 0x3c, 0x04, 0x43, 0x9a, - 0x52, 0x0b, 0xff, 0xbb, 0x9a, 0x44, 0x70, 0x46, 0x33, 0xee, 0x30, 0xff, 0xd5, 0xc3, 0xc5, 0xc4, 0xb8, 0x88, 0xcd, - 0x3c, 0x48, 0xdf, 0x55, 0xbd, 0xdf, 0xb8, 0x16, 0x65, 0xa8, 0x4e, 0x27, 0xe7, 0x76, 0x93, 0x6a, 0x76, 0x79, 0x78, - 0xcd, 0x9a, 0x9f, 0x97, 0x66, 0xda, 0x57, 0x1b, 0x72, 0x0e, 0xb4, 0x76, 0x19, 0x73, 0xd7, 0xa3, 0x0d, 0xa7, 0x00, - 0x31, 0x71, 0x1f, 0x06, 0x0d, 0x98, 0xb0, 0xe6, 0xc1, 0x24, 0xcf, 0xcd, 0x81, 0x00, 0x84, 0x72, 0xd1, 0xd2, 0x5d, - 0x44, 0x5c, 0x7a, 0x2f, 0xad, 0x03, 0xb8, 0xae, 0x8d, 0x29, 0xd2, 0x2e, 0x40, 0x35, 0xcd, 0xd5, 0x6e, 0x1c, 0x66, - 0xba, 0xc6, 0xc0, 0xc7, 0x4c, 0x16, 0x94, 0x09, 0x81, 0x2e, 0x55, 0xc2, 0x5f, 0xbc, 0x12, 0x05, 0x75, 0xdb, 0x68, - 0x06, 0x1c, 0xd4, 0xad, 0x43, 0x88, 0x0f, 0x21, 0x9e, 0x66, 0x68, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xb4, 0x1f, - 0x6e, 0x3f, 0x60, 0xcf, 0x96, 0x24, 0xaa, 0xf0, 0x92, 0xbb, 0x6c, 0x7c, 0x81, 0x94, 0x48, 0xef, 0x2d, 0x27, 0xbd, - 0xd7, 0x5e, 0x6c, 0x44, 0x78, 0x9c, 0x8c, 0x2c, 0x6d, 0xe0, 0x1c, 0x11, 0xf7, 0x72, 0x8c, 0xa7, 0x44, 0xe2, 0x19, - 0xac, 0x52, 0xc0, 0x8d, 0xc8, 0x70, 0x22, 0xfe, 0x19, 0xf8, 0xab, 0x24, 0x8d, 0x93, 0xfe, 0x32, 0x0e, 0xa2, 0x8c, - 0x26, 0x39, 0x82, 0xea, 0x1a, 0xe1, 0x23, 0xc0, 0x73, 0xb3, 0x89, 0x97, 0xc4, 0x0f, 0xb2, 0x87, 0xbe, 0xcb, 0x49, - 0x0a, 0x77, 0xc0, 0xa9, 0x03, 0xb7, 0xb1, 0x7e, 0x9f, 0x43, 0xf3, 0x25, 0x12, 0x7e, 0x49, 0x9d, 0x9c, 0x51, 0xb7, - 0xf9, 0x40, 0x79, 0xcb, 0x02, 0x04, 0x01, 0xf9, 0x41, 0x12, 0x7b, 0x06, 0x58, 0x1e, 0x96, 0xda, 0x9d, 0xd0, 0x99, - 0x85, 0x58, 0x1b, 0xc4, 0xeb, 0xe2, 0xcf, 0xe9, 0x99, 0x9a, 0xdb, 0x5c, 0x0c, 0x14, 0x8f, 0xb9, 0xcf, 0xc8, 0xfa, - 0x04, 0xd2, 0xe9, 0x59, 0xfb, 0xd4, 0x1c, 0xd3, 0x69, 0x9c, 0x50, 0x16, 0x4c, 0xda, 0x3b, 0x59, 0xae, 0xf7, 0xef, - 0x7e, 0xfb, 0xf4, 0x9b, 0xfb, 0x89, 0xe2, 0xcc, 0x10, 0x9d, 0x99, 0x3b, 0x7a, 0xab, 0xdf, 0x67, 0x40, 0x1a, 0x32, - 0xc8, 0xfb, 0x2c, 0x6e, 0x5f, 0x5f, 0xd7, 0x07, 0x8d, 0x31, 0xfb, 0x96, 0x31, 0xbf, 0xf3, 0x12, 0x1a, 0x92, 0x2c, - 0xb8, 0x13, 0x34, 0x63, 0xf7, 0x68, 0xb9, 0x16, 0x6b, 0x8c, 0x17, 0xde, 0x23, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, - 0xd5, 0x62, 0x5c, 0xa4, 0x41, 0x6d, 0x36, 0x22, 0x8c, 0x4d, 0xe5, 0xa6, 0xef, 0x2d, 0xd7, 0xea, 0x15, 0x5d, 0x34, - 0x93, 0x37, 0x75, 0x35, 0xfe, 0xe0, 0x22, 0x98, 0x4c, 0x42, 0x9a, 0x97, 0x16, 0xba, 0xbc, 0x96, 0x0a, 0x70, 0x24, - 0x1c, 0xc8, 0x38, 0x8d, 0xc3, 0x55, 0x46, 0x9b, 0xc1, 0xc5, 0x80, 0xd3, 0x71, 0x0b, 0xe0, 0xe0, 0xef, 0xf2, 0x58, - 0x7b, 0x40, 0x6e, 0xc3, 0x36, 0x71, 0x07, 0x10, 0x6e, 0xdc, 0xee, 0x96, 0x87, 0x0e, 0xaf, 0xe4, 0xa0, 0xad, 0x86, - 0x89, 0x58, 0x70, 0x2d, 0x31, 0xec, 0xad, 0x39, 0x1e, 0x2f, 0x93, 0x21, 0x97, 0x65, 0x51, 0x5e, 0x9e, 0xcc, 0x6f, - 0x73, 0xc6, 0x5e, 0x35, 0x9f, 0xb1, 0x57, 0xe2, 0x8c, 0x6d, 0xdf, 0x99, 0x4f, 0xa7, 0x1e, 0xfc, 0x37, 0x28, 0x26, - 0xd4, 0x77, 0xb5, 0xee, 0x72, 0xad, 0x79, 0xcb, 0xb5, 0x66, 0x77, 0x96, 0x6b, 0x0d, 0xbb, 0x46, 0xcb, 0x0a, 0xcb, - 0xe9, 0x98, 0x96, 0xab, 0x41, 0x21, 0xfc, 0xb9, 0xa5, 0x57, 0xde, 0x21, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, - 0xf6, 0xa3, 0xce, 0xce, 0x92, 0x40, 0xda, 0xa6, 0x93, 0x91, 0xf1, 0x98, 0x4e, 0xfa, 0xd3, 0xd8, 0x5f, 0xa5, 0x7f, - 0xe7, 0xe3, 0xe7, 0x40, 0xdc, 0x8a, 0x08, 0x2a, 0xfd, 0x88, 0xa6, 0xa0, 0xef, 0xb8, 0xa3, 0xa2, 0x87, 0x8d, 0x5c, - 0xa7, 0x3e, 0x8b, 0x8d, 0xde, 0x71, 0x0e, 0x1b, 0x36, 0x79, 0x33, 0xa0, 0x7f, 0xb3, 0x55, 0x6a, 0x47, 0x31, 0xbf, - 0x02, 0x2c, 0x5b, 0xc1, 0xf1, 0x78, 0x68, 0xf0, 0xd5, 0x74, 0x4f, 0x9a, 0x87, 0x7b, 0x2d, 0xbe, 0x74, 0x23, 0x2e, - 0x15, 0x7e, 0x6f, 0x71, 0x87, 0xaf, 0xed, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x5b, 0x2e, 0x84, 0xa2, 0xee, 0x9e, - 0x58, 0xfe, 0xe9, 0xab, 0x43, 0xf8, 0x8f, 0x51, 0xf5, 0x3f, 0x66, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xff, 0x81, 0x91, - 0x4a, 0x48, 0x88, 0xef, 0x5f, 0x7f, 0x3a, 0x7d, 0x5c, 0x83, 0xbd, 0x6b, 0x33, 0xa3, 0xa4, 0x6a, 0xed, 0xaf, 0xe2, - 0x18, 0xf2, 0xf6, 0xd6, 0xab, 0x0b, 0xf0, 0x30, 0x17, 0x8f, 0x6c, 0x08, 0x8d, 0x04, 0x1f, 0xc1, 0x94, 0xf1, 0x3a, - 0xb6, 0x61, 0xac, 0xc4, 0xdb, 0x36, 0x56, 0xe2, 0xcd, 0x6e, 0x56, 0xe2, 0xdb, 0xbd, 0x58, 0x89, 0x37, 0x9f, 0x9d, - 0x95, 0x78, 0x5b, 0x67, 0x25, 0xae, 0x62, 0x61, 0x89, 0x6a, 0x5d, 0xac, 0xf8, 0xcf, 0x0f, 0x4c, 0xb7, 0x76, 0x19, - 0x0f, 0x7b, 0x2e, 0x8b, 0x77, 0x7e, 0xf5, 0x8b, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd1, 0x30, 0xab, 0x60, 0x2d, 0x38, - 0x66, 0xc7, 0xef, 0x28, 0xc5, 0x61, 0x1c, 0xcd, 0xbe, 0x07, 0xdd, 0x2a, 0x88, 0x03, 0x13, 0xe5, 0x45, 0x90, 0x7e, - 0x1f, 0x2f, 0x57, 0xcb, 0x0b, 0xe8, 0xeb, 0x43, 0x90, 0x06, 0xe3, 0x90, 0xca, 0x30, 0x04, 0xcc, 0x90, 0x8c, 0xcb, - 0xc4, 0xc1, 0x76, 0x53, 0xfc, 0x24, 0x6b, 0xf1, 0x13, 0xad, 0x3b, 0xf9, 0x6f, 0x66, 0xa1, 0xa6, 0x37, 0x33, 0x22, - 0x10, 0xb0, 0xab, 0x32, 0xe8, 0xc7, 0x33, 0x23, 0x57, 0xb1, 0xd9, 0x30, 0x4b, 0x61, 0xb6, 0xd0, 0xda, 0x0f, 0xad, - 0x31, 0x35, 0x2b, 0xd3, 0x92, 0xf1, 0xf7, 0xea, 0x62, 0xf8, 0x45, 0xbc, 0x4a, 0xe9, 0x24, 0xbe, 0x8f, 0x74, 0x2b, - 0x95, 0xae, 0x35, 0xa0, 0xa8, 0x94, 0x6d, 0x30, 0x73, 0xac, 0xd4, 0xcc, 0xe8, 0x90, 0xb8, 0x78, 0xb5, 0xb4, 0x99, - 0xc6, 0xd8, 0xc6, 0x29, 0xea, 0x32, 0xc5, 0xd9, 0x13, 0xc3, 0x88, 0x87, 0x8f, 0x6b, 0x29, 0x2c, 0x2e, 0x62, 0x87, - 0x4b, 0x85, 0x53, 0x23, 0x15, 0xc2, 0x45, 0x11, 0x04, 0xa7, 0x61, 0xe1, 0xf8, 0x1b, 0xe6, 0x12, 0x5e, 0xbc, 0x85, - 0x10, 0x42, 0xf9, 0x8a, 0xaf, 0x07, 0x0f, 0x09, 0xc3, 0x1e, 0x5f, 0x2b, 0x60, 0x7c, 0x77, 0x47, 0x93, 0x90, 0x3c, - 0x18, 0x66, 0x1e, 0x47, 0xdf, 0x01, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0x33, 0x35, 0x35, 0xec, 0xa5, 0xc6, - 0xe0, 0x45, 0xe0, 0xae, 0xa5, 0x8c, 0x00, 0x72, 0x64, 0xcf, 0xe8, 0x5f, 0x2c, 0xf6, 0xef, 0x5f, 0xcd, 0xdc, 0xba, - 0x8c, 0xe5, 0x87, 0xfe, 0xbc, 0xdc, 0xe3, 0x33, 0xcf, 0x9f, 0x3f, 0x69, 0x9f, 0xb6, 0x01, 0xe9, 0xc2, 0x45, 0xe6, - 0x6b, 0xa3, 0xa1, 0xb5, 0xd9, 0x7a, 0x0a, 0x60, 0x14, 0x57, 0xf1, 0xca, 0x9f, 0xa3, 0xc9, 0xe8, 0xe7, 0x9b, 0x6f, - 0x06, 0x7d, 0x62, 0x8a, 0x62, 0x39, 0xf5, 0x4a, 0x51, 0x01, 0x05, 0xfc, 0xfe, 0x5b, 0x88, 0xbe, 0xfb, 0x6f, 0x04, - 0x43, 0x7d, 0xd7, 0x70, 0x2e, 0x3e, 0x78, 0xdc, 0xe6, 0x1d, 0x40, 0x26, 0x5d, 0x1e, 0xd7, 0x46, 0x28, 0xd7, 0x9a, - 0x91, 0x4c, 0x5e, 0x05, 0x9a, 0x1a, 0x43, 0xb2, 0x2d, 0x3c, 0xa6, 0xf8, 0x0a, 0x75, 0x18, 0x9b, 0xce, 0x4d, 0xf6, - 0x2d, 0xca, 0xb1, 0x55, 0x05, 0xc9, 0x70, 0xcb, 0x05, 0x8a, 0xe8, 0xab, 0xfa, 0x6e, 0x11, 0x44, 0x16, 0xa6, 0x80, - 0xa8, 0xbf, 0x21, 0x6b, 0x08, 0x82, 0x0e, 0xc8, 0xad, 0xfa, 0x0a, 0x0a, 0x2d, 0xaa, 0x78, 0x8b, 0x42, 0x9e, 0x37, - 0xbd, 0x11, 0x12, 0x42, 0x8b, 0x37, 0xfa, 0x9d, 0xa6, 0x69, 0x9a, 0x64, 0x23, 0x34, 0xc9, 0x47, 0x60, 0x39, 0xb2, - 0x03, 0xa0, 0x2d, 0xc9, 0x97, 0x6b, 0x56, 0x02, 0x9c, 0x01, 0x98, 0x78, 0xc8, 0x02, 0x1e, 0xe7, 0xb3, 0xe7, 0x8a, - 0x02, 0xc1, 0xd0, 0x43, 0x8c, 0x46, 0x92, 0x40, 0x38, 0xf0, 0xbe, 0x86, 0x0c, 0x3b, 0xbe, 0xe5, 0x92, 0x60, 0xcd, - 0x65, 0x8f, 0xa3, 0x01, 0x6d, 0x0e, 0x08, 0x99, 0x2a, 0x58, 0x10, 0xb4, 0x0e, 0x95, 0xf8, 0xee, 0x16, 0x6d, 0xc0, - 0x8d, 0xc8, 0x17, 0xad, 0xb3, 0x05, 0x8d, 0x56, 0x3a, 0x26, 0x84, 0xc3, 0xe0, 0xe2, 0x50, 0xe7, 0x0d, 0x23, 0xb6, - 0x00, 0xdb, 0x34, 0xb7, 0x9c, 0xb3, 0xbb, 0x30, 0xe2, 0x28, 0x95, 0x58, 0x3e, 0x57, 0x6c, 0x46, 0x1c, 0xb7, 0x55, - 0x6f, 0x08, 0xbe, 0xa4, 0x71, 0xd5, 0x7d, 0x91, 0xd9, 0x14, 0x43, 0x1f, 0x2c, 0x34, 0x0e, 0x17, 0x17, 0x09, 0xb0, - 0x1b, 0xa4, 0xba, 0x68, 0x52, 0x23, 0x43, 0x2a, 0x82, 0xa2, 0xc4, 0xac, 0x77, 0xc3, 0xc7, 0x09, 0x51, 0xc9, 0x5a, - 0xfb, 0xf1, 0x6b, 0xfd, 0xb4, 0x4c, 0xfa, 0x96, 0x3e, 0xb0, 0x8b, 0x84, 0x81, 0xea, 0x96, 0x3e, 0x80, 0x09, 0xdf, - 0x5b, 0x90, 0xa6, 0xe8, 0x5b, 0xd0, 0xb5, 0x05, 0x79, 0x3e, 0x7c, 0x88, 0x54, 0xb7, 0xe5, 0x00, 0xb9, 0xf9, 0x16, - 0x2c, 0x8e, 0x20, 0x86, 0x94, 0xee, 0xe2, 0x10, 0x73, 0x63, 0x79, 0xa3, 0x11, 0xc6, 0x76, 0xc3, 0xd1, 0x30, 0x5f, - 0x78, 0xae, 0x7b, 0x50, 0xab, 0x0f, 0x82, 0xec, 0xa6, 0xda, 0xa6, 0x95, 0x0d, 0x3d, 0xd7, 0x0e, 0x5e, 0x38, 0x9d, - 0x41, 0xed, 0x8e, 0x56, 0x02, 0xc9, 0x8e, 0x50, 0xfc, 0x75, 0xf6, 0x6c, 0x63, 0xa4, 0x2d, 0xe0, 0x2d, 0x8c, 0xcf, - 0x71, 0x6c, 0x39, 0x97, 0x7f, 0x8d, 0xea, 0x57, 0x3f, 0x0b, 0x63, 0xcb, 0x92, 0x1a, 0x8d, 0x20, 0x14, 0xba, 0x01, - 0xc7, 0xe8, 0xf7, 0xda, 0x4b, 0xcd, 0x60, 0xc7, 0xc7, 0x34, 0x47, 0x03, 0x81, 0x51, 0x84, 0x5b, 0x97, 0xda, 0x41, - 0xe5, 0x8b, 0x51, 0x15, 0xc3, 0xf1, 0xa0, 0xcb, 0xb4, 0xd0, 0xe8, 0x6d, 0xa5, 0x16, 0xb0, 0xff, 0x96, 0xeb, 0xd3, - 0x19, 0x43, 0xbc, 0x0f, 0xa8, 0x01, 0x89, 0x13, 0x76, 0x76, 0xb8, 0x5a, 0x96, 0xbb, 0x2b, 0x5f, 0x92, 0xfb, 0x77, - 0x86, 0x97, 0x0e, 0xea, 0xd0, 0x64, 0x7f, 0xcd, 0xd7, 0xdd, 0x23, 0xbb, 0xa4, 0xd1, 0xa4, 0xdc, 0x61, 0xe5, 0xfe, - 0xda, 0xbf, 0xbb, 0x12, 0x46, 0x81, 0x8c, 0x22, 0x71, 0x03, 0x46, 0xc9, 0xe3, 0x08, 0x37, 0x3f, 0x3b, 0x6e, 0xc1, - 0x5e, 0x54, 0x0c, 0x36, 0x60, 0xe1, 0x00, 0x65, 0x33, 0x45, 0x28, 0x0e, 0x61, 0xeb, 0xd1, 0x19, 0xde, 0x10, 0x84, - 0x68, 0xeb, 0x4e, 0xcc, 0x84, 0x69, 0x60, 0xd1, 0x26, 0xe0, 0x81, 0x68, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, - 0xd9, 0x2e, 0xa9, 0x35, 0x73, 0x4c, 0xba, 0x4f, 0xc8, 0x52, 0xf1, 0x6d, 0x13, 0xc4, 0xb9, 0xea, 0xe2, 0x56, 0x12, - 0x75, 0xa3, 0x1f, 0x93, 0x68, 0x55, 0xeb, 0x8d, 0x19, 0xfb, 0xa1, 0xf8, 0x5b, 0x61, 0x50, 0x84, 0x42, 0x5d, 0x95, - 0x8d, 0x5f, 0x15, 0xb2, 0x71, 0xc6, 0xd5, 0x14, 0x2e, 0x29, 0x82, 0xfa, 0x57, 0xdc, 0xbd, 0x24, 0x77, 0x50, 0xb8, - 0x7d, 0x15, 0x23, 0x55, 0x1c, 0x99, 0x0a, 0x46, 0x43, 0x71, 0x8f, 0x13, 0x5c, 0x46, 0xd9, 0x4b, 0xae, 0x5c, 0xb5, - 0xf0, 0x63, 0x2a, 0xca, 0x41, 0xea, 0x8e, 0x43, 0x96, 0xc5, 0xea, 0xb6, 0x29, 0x3b, 0xb2, 0xa8, 0xaf, 0x95, 0x4d, - 0x22, 0x3d, 0x4e, 0x18, 0x80, 0x85, 0x98, 0xbe, 0xa2, 0xd7, 0x96, 0x36, 0x10, 0x38, 0xc8, 0x06, 0x07, 0xb9, 0xdd, - 0xd2, 0x79, 0x96, 0x2c, 0xa5, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0x84, 0xef, 0xcd, 0xa6, 0xe1, 0x96, 0xc7, 0x4b, 0x9e, - 0xdf, 0xef, 0x20, 0x5e, 0xd4, 0x5c, 0x55, 0x91, 0x8f, 0x27, 0xd3, 0x66, 0x56, 0xb6, 0x58, 0xb5, 0xde, 0x29, 0x13, - 0xe2, 0x6c, 0xb8, 0x8f, 0x49, 0x59, 0x46, 0xcf, 0x6b, 0xf4, 0xc5, 0x77, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0x26, 0xb6, - 0xb0, 0xb3, 0x84, 0xf8, 0xb7, 0xca, 0x90, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0xc1, 0x80, 0x60, 0x1c, 0x58, - 0xda, 0x77, 0x3a, 0xa9, 0x22, 0x7d, 0xe9, 0x3f, 0x75, 0xbb, 0xe4, 0xd5, 0xf4, 0xb0, 0x22, 0x14, 0xed, 0xf4, 0xca, - 0x22, 0xf3, 0x96, 0x71, 0x64, 0xf3, 0xd5, 0x62, 0xbc, 0x51, 0x65, 0xab, 0x8a, 0xc8, 0xb5, 0x2e, 0x66, 0x55, 0x3f, - 0x3b, 0x9d, 0x4e, 0xcb, 0x82, 0x46, 0x57, 0x3b, 0x44, 0x61, 0xe1, 0x53, 0xd7, 0x75, 0xab, 0x63, 0xdf, 0x0e, 0x76, - 0x1b, 0xe5, 0xb6, 0x27, 0x8d, 0x23, 0x46, 0xd8, 0xee, 0x82, 0x5f, 0x1d, 0x1c, 0xb9, 0x53, 0x9c, 0xec, 0x92, 0x59, - 0xc4, 0x80, 0x19, 0x43, 0x04, 0x19, 0x5d, 0xa4, 0x7d, 0x9f, 0xa2, 0x0e, 0xc6, 0x51, 0x0e, 0x34, 0x1a, 0x0e, 0xd8, - 0x33, 0x30, 0x15, 0xf1, 0xc4, 0xae, 0x70, 0x35, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0x78, 0x50, 0x36, 0x75, - 0x99, 0x36, 0x4e, 0xab, 0xe7, 0xfe, 0xbe, 0x54, 0x4f, 0x83, 0x0b, 0x70, 0x23, 0x14, 0xda, 0x4c, 0x3e, 0x8b, 0xff, - 0x2f, 0xe5, 0xff, 0xaf, 0x96, 0xeb, 0xb2, 0xfd, 0xc8, 0x09, 0x48, 0xb4, 0x8b, 0xd3, 0xc2, 0x46, 0xdd, 0xb4, 0x07, - 0xa4, 0x95, 0xc1, 0x54, 0x55, 0xa0, 0x83, 0x92, 0xbe, 0x94, 0xfd, 0xa7, 0x41, 0xfc, 0x8e, 0x14, 0x33, 0x2c, 0x71, - 0x21, 0x42, 0x2c, 0x72, 0x57, 0xc2, 0x1c, 0xac, 0x97, 0x27, 0xa8, 0x3f, 0x28, 0xed, 0x09, 0xd0, 0xc6, 0xd7, 0xe6, - 0xb6, 0x97, 0xb8, 0xbf, 0xaa, 0xd7, 0x12, 0x1d, 0x03, 0xc8, 0x3c, 0x38, 0x84, 0x68, 0x48, 0xa0, 0x55, 0x36, 0x37, - 0x1b, 0xa5, 0x7c, 0xab, 0xea, 0xd9, 0xc4, 0xc0, 0xb0, 0xbb, 0xe6, 0x2a, 0xac, 0x6f, 0xa1, 0x2d, 0x80, 0xc9, 0xf2, - 0xed, 0x87, 0xcf, 0x36, 0x2c, 0xb1, 0xba, 0x1f, 0x3d, 0x5c, 0x72, 0xdc, 0xbf, 0x36, 0xde, 0x9d, 0x29, 0x3b, 0xff, - 0x28, 0x5f, 0xfc, 0xb6, 0x51, 0xa0, 0x77, 0x55, 0x92, 0xd0, 0x71, 0xa3, 0xef, 0x8e, 0xb9, 0x57, 0xed, 0x45, 0x10, - 0xed, 0x5f, 0x97, 0xac, 0xf7, 0xae, 0x0b, 0x17, 0xc6, 0xde, 0x95, 0xe1, 0xc6, 0x61, 0x96, 0x0b, 0xd9, 0xf0, 0x5b, - 0x45, 0xa0, 0xa8, 0xfa, 0xef, 0xea, 0xd8, 0x8a, 0x51, 0xf9, 0x57, 0x2b, 0x20, 0x3e, 0xf7, 0xca, 0xee, 0xa2, 0x89, - 0x04, 0x8d, 0xfa, 0xb1, 0x76, 0xa2, 0x1d, 0x77, 0xb5, 0x23, 0x57, 0x67, 0x5c, 0xd8, 0x50, 0xef, 0x75, 0x0a, 0xbf, - 0xbc, 0x43, 0x57, 0x3f, 0x3b, 0x9d, 0x89, 0x4b, 0x62, 0x1a, 0x84, 0x21, 0x43, 0x15, 0x60, 0xfe, 0x7b, 0x4b, 0xcb, - 0x6a, 0x16, 0x56, 0xc6, 0x8d, 0x40, 0x3a, 0xe2, 0x11, 0xce, 0x8e, 0x4f, 0x96, 0x7d, 0x3c, 0x1b, 0x6a, 0x21, 0x18, - 0x70, 0xb2, 0x52, 0xfc, 0x04, 0xdc, 0xc1, 0x63, 0xfd, 0xec, 0x14, 0xe2, 0x97, 0x6a, 0x93, 0xa1, 0xfe, 0x5d, 0xe7, - 0x58, 0xf3, 0x7a, 0x77, 0x76, 0xd7, 0x77, 0x6d, 0xcf, 0x39, 0xd4, 0x5c, 0xe7, 0xc8, 0xee, 0x38, 0xc7, 0x5a, 0xc7, - 0xe9, 0xc1, 0xbf, 0xbe, 0xe7, 0xbc, 0xd2, 0x5c, 0x78, 0xd2, 0x3c, 0xa7, 0x8b, 0xff, 0x76, 0x9c, 0xe3, 0xbb, 0x2e, - 0xbb, 0xe9, 0x89, 0xf4, 0x8e, 0xaa, 0x8c, 0x02, 0x7c, 0x39, 0xf4, 0x83, 0xb3, 0xd3, 0x55, 0x4a, 0xb5, 0xf5, 0x50, - 0x7f, 0xa5, 0x6b, 0xf3, 0x84, 0x4e, 0x87, 0xfa, 0x53, 0xa2, 0x94, 0x7a, 0x27, 0x8d, 0xc5, 0x9d, 0xe3, 0xc6, 0xe2, - 0xee, 0x51, 0x63, 0xf1, 0x61, 0xaf, 0x5c, 0x7c, 0x30, 0x63, 0xaf, 0x94, 0xf4, 0xa1, 0x0b, 0x92, 0x25, 0xc1, 0xda, - 0xf0, 0x34, 0x40, 0xd7, 0x36, 0xfc, 0x73, 0xdc, 0x31, 0x65, 0xab, 0x31, 0xb4, 0x92, 0xd0, 0x38, 0x3e, 0xd1, 0xbc, - 0xa3, 0x6f, 0x3a, 0x47, 0x3e, 0xd4, 0x83, 0x64, 0xb7, 0xf0, 0x77, 0xd7, 0x3d, 0xf1, 0x5d, 0x0d, 0x1a, 0x7a, 0xf0, - 0xdf, 0xbc, 0xd7, 0xf1, 0xd9, 0x83, 0x0b, 0xef, 0x3f, 0x78, 0xc7, 0xa9, 0x6b, 0x7b, 0xf0, 0xdf, 0xcf, 0x52, 0xe5, - 0x0e, 0x0a, 0x7f, 0xb5, 0xdf, 0x43, 0x57, 0xeb, 0x9e, 0xcc, 0x3b, 0xce, 0xab, 0xbb, 0x63, 0xe7, 0x64, 0xee, 0x1d, - 0x7f, 0x60, 0x4f, 0xa1, 0xdd, 0x71, 0x5e, 0xc1, 0xdf, 0x87, 0xae, 0x3b, 0xb7, 0x3d, 0xe7, 0xe4, 0xae, 0xeb, 0x74, - 0x43, 0xfb, 0xc8, 0x39, 0x81, 0xbf, 0x9f, 0x01, 0xbc, 0x00, 0x57, 0x9e, 0x9d, 0x58, 0x83, 0x8d, 0x51, 0xb1, 0xdf, - 0x50, 0x3f, 0xd2, 0x39, 0xd4, 0x7a, 0x87, 0xdf, 0x9c, 0xdc, 0xd9, 0x87, 0x73, 0xaf, 0x73, 0x67, 0xb7, 0xfe, 0xfc, - 0x00, 0x90, 0xdf, 0xbe, 0x70, 0x00, 0x46, 0x4c, 0x47, 0xf4, 0xbb, 0x91, 0x75, 0xd9, 0x26, 0x46, 0x7f, 0xbf, 0x5b, - 0x8c, 0xfe, 0xf5, 0x6a, 0x1f, 0x31, 0xfa, 0xfb, 0xcf, 0x2e, 0x46, 0xbf, 0xac, 0x5a, 0x71, 0xbf, 0xaf, 0xa6, 0x4d, - 0xf8, 0x71, 0x53, 0x25, 0x92, 0x03, 0x62, 0x5c, 0x5f, 0xad, 0x6e, 0x20, 0xe2, 0xd5, 0xfb, 0x78, 0xf8, 0xf5, 0xaa, - 0x64, 0xa2, 0x14, 0x03, 0x06, 0x78, 0x1f, 0x33, 0x0c, 0xf0, 0xa7, 0xd5, 0x10, 0xec, 0x22, 0xf8, 0xad, 0x19, 0x4c, - 0xec, 0x39, 0x09, 0xa7, 0xf2, 0xc6, 0x85, 0x92, 0x01, 0x16, 0x83, 0xdd, 0x3d, 0x5c, 0x26, 0xa0, 0xac, 0x59, 0x2d, - 0xa2, 0xb4, 0x7f, 0xe4, 0x02, 0x9a, 0xef, 0x4c, 0x93, 0xbc, 0xd2, 0xd8, 0x11, 0x31, 0xc2, 0x3e, 0x72, 0xcb, 0xfc, - 0xd6, 0xf7, 0x68, 0xb2, 0xd6, 0xdc, 0xbb, 0x57, 0xef, 0x57, 0x03, 0x5b, 0x10, 0x61, 0xd2, 0x07, 0xc4, 0x46, 0xd3, - 0xfb, 0xb2, 0xe1, 0x58, 0xc5, 0x54, 0xb0, 0x7d, 0xa4, 0x30, 0x92, 0x6a, 0x7b, 0xaf, 0x6c, 0x78, 0xb6, 0x6b, 0x9a, - 0x0d, 0x9f, 0x2f, 0x35, 0xdf, 0x62, 0xf5, 0x26, 0x3b, 0xae, 0x82, 0xaa, 0x92, 0xf4, 0xaf, 0x11, 0x20, 0x05, 0xed, - 0x59, 0x98, 0xc6, 0x15, 0x84, 0x8f, 0xab, 0xe1, 0x6d, 0xec, 0x2a, 0xef, 0x4a, 0x7d, 0xaa, 0xe6, 0x74, 0x2f, 0x36, - 0x48, 0x0f, 0x06, 0x3f, 0x03, 0x61, 0xc3, 0xef, 0xe3, 0x71, 0xac, 0xc2, 0x79, 0xa3, 0xf4, 0xcb, 0x48, 0xed, 0x7c, - 0xee, 0x6d, 0xea, 0xa4, 0x4d, 0xab, 0x21, 0xad, 0x47, 0x17, 0xe2, 0x8e, 0xc6, 0xcf, 0x33, 0xb3, 0xd5, 0x9c, 0x99, - 0x16, 0xa3, 0x65, 0xee, 0xb6, 0xce, 0x44, 0xbd, 0xa7, 0xb0, 0x89, 0x2d, 0xfe, 0xa0, 0xfa, 0x7f, 0x6f, 0xa6, 0x90, - 0xa0, 0xbd, 0x8f, 0x44, 0x84, 0x42, 0x41, 0x75, 0xd0, 0xc6, 0x76, 0xb0, 0xc5, 0xfc, 0x43, 0xed, 0x98, 0x77, 0x82, - 0xb6, 0xba, 0xdb, 0x2c, 0x46, 0xa4, 0x6b, 0xc3, 0xa6, 0xa4, 0x40, 0xf5, 0x7a, 0xc7, 0x96, 0x77, 0x64, 0x39, 0xc7, - 0x3d, 0x33, 0x17, 0x07, 0x4e, 0xed, 0xb2, 0x04, 0x10, 0x30, 0xd9, 0x95, 0xc3, 0x0c, 0xa2, 0x20, 0x0b, 0x48, 0x98, - 0x03, 0xaa, 0x2f, 0xd3, 0xbc, 0x7f, 0x5b, 0xa5, 0x19, 0xcc, 0x51, 0x90, 0x64, 0x68, 0xae, 0x6c, 0x8f, 0x69, 0x76, - 0x4f, 0x69, 0xd4, 0xa2, 0xca, 0xad, 0x5a, 0x3f, 0xff, 0x76, 0xb6, 0xa0, 0x39, 0xb3, 0xb3, 0x18, 0x67, 0x11, 0xdf, - 0x1f, 0xc2, 0x54, 0x37, 0x1f, 0x59, 0x3f, 0xb7, 0x21, 0xdc, 0xbf, 0xed, 0x46, 0xb8, 0x19, 0xdd, 0x07, 0xe1, 0xfe, - 0xed, 0xb3, 0x23, 0xdc, 0x9f, 0x55, 0x84, 0x5b, 0xf2, 0x54, 0x29, 0x64, 0xa2, 0x3f, 0xe0, 0xb3, 0x01, 0xf1, 0xc6, - 0x5f, 0xea, 0x07, 0x8c, 0xbc, 0xd4, 0x95, 0x3c, 0xd0, 0x1f, 0x4a, 0x89, 0xad, 0x90, 0x65, 0xc7, 0xd0, 0xc3, 0x2c, - 0x89, 0x0e, 0xe4, 0x48, 0x76, 0x85, 0xfb, 0x21, 0xf4, 0x79, 0x11, 0x65, 0xa1, 0xf3, 0x9e, 0xb3, 0x25, 0xa0, 0x82, - 0xf8, 0x3a, 0x4e, 0x16, 0x04, 0x83, 0x22, 0xea, 0x98, 0x10, 0x13, 0x1e, 0x5c, 0x70, 0x18, 0xf3, 0xe3, 0x68, 0x22, - 0xe5, 0xe8, 0x74, 0x78, 0xcd, 0xe8, 0x41, 0xfd, 0x81, 0x92, 0x44, 0xb7, 0xd8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xf7, - 0x45, 0xe7, 0xf0, 0xc5, 0x91, 0x0b, 0xff, 0xf3, 0x68, 0x37, 0xb7, 0x78, 0xc5, 0x45, 0x1c, 0x41, 0x4e, 0x1e, 0x51, - 0xb3, 0xad, 0xda, 0x3d, 0xa5, 0xb7, 0x45, 0xad, 0xe3, 0xe6, 0x4a, 0x13, 0xf2, 0x50, 0xd4, 0x69, 0xac, 0x31, 0x8f, - 0x57, 0xca, 0xb0, 0x1a, 0x46, 0x13, 0x44, 0x2b, 0x90, 0x0c, 0x29, 0x35, 0xd4, 0xd7, 0x7c, 0xba, 0xc5, 0xbc, 0x68, - 0x37, 0xbf, 0x29, 0x12, 0x7f, 0x89, 0x04, 0x44, 0x3b, 0x21, 0xc8, 0x85, 0xea, 0x2e, 0xa6, 0x0d, 0xc0, 0x68, 0x6f, - 0x1a, 0xa4, 0xdd, 0x14, 0x0b, 0x44, 0xd8, 0x02, 0x65, 0xc9, 0x2a, 0xf2, 0x0d, 0xfc, 0x49, 0xc6, 0xa9, 0x11, 0x1c, - 0x40, 0x4c, 0x5e, 0xfc, 0xb0, 0x89, 0xab, 0x46, 0xce, 0xdc, 0x22, 0x4b, 0x4a, 0x24, 0x56, 0x85, 0xbc, 0xc8, 0xac, - 0x84, 0xe5, 0x56, 0xc6, 0xa5, 0xb5, 0x87, 0xe4, 0x85, 0x6c, 0xf8, 0x22, 0xb3, 0x20, 0xbf, 0x31, 0x2c, 0xf7, 0xf3, - 0xe7, 0xac, 0x16, 0x64, 0x1c, 0x65, 0xd3, 0x3a, 0xf7, 0x65, 0x96, 0x42, 0x5d, 0x23, 0xb3, 0x58, 0xc7, 0x2c, 0x85, - 0x7d, 0xdf, 0x8a, 0x5f, 0xbe, 0x3c, 0x1b, 0x7a, 0x26, 0xcf, 0x97, 0x5b, 0x4a, 0xee, 0x76, 0xb9, 0x9f, 0x6a, 0xdc, - 0x6c, 0x74, 0xda, 0x5a, 0x06, 0xd1, 0x4c, 0x68, 0xa6, 0x25, 0xf6, 0x82, 0x64, 0x2b, 0x4c, 0x05, 0x46, 0x84, 0x8a, - 0x5a, 0xd4, 0xb9, 0xa3, 0x09, 0xe4, 0xfa, 0x1d, 0xea, 0x5d, 0xc7, 0x75, 0x5c, 0x5d, 0x36, 0x9c, 0x06, 0xb3, 0xe1, - 0x26, 0xce, 0x08, 0xa4, 0xad, 0x0a, 0xe3, 0x19, 0x78, 0x7e, 0x64, 0x41, 0x16, 0x42, 0x0e, 0x24, 0x70, 0x01, 0x59, - 0x30, 0xae, 0x31, 0xe7, 0xf6, 0xb8, 0x24, 0xb9, 0xc5, 0x3c, 0x98, 0xc2, 0xe9, 0x0b, 0x23, 0xcb, 0x7c, 0x07, 0x97, - 0xa1, 0xa1, 0x1b, 0x90, 0x85, 0x95, 0x26, 0xa9, 0xad, 0xda, 0xb7, 0xf7, 0x35, 0x68, 0x63, 0xea, 0x7c, 0x12, 0xd3, - 0x84, 0x2c, 0x20, 0x5d, 0xc0, 0x26, 0xb7, 0x38, 0xa6, 0xd5, 0x39, 0xaa, 0xd5, 0xbc, 0x57, 0x47, 0x96, 0xd6, 0xf1, - 0x2c, 0xcd, 0x05, 0x74, 0xab, 0xe7, 0xd6, 0x26, 0xbf, 0x19, 0xec, 0x52, 0xd1, 0x31, 0xfc, 0xf2, 0x94, 0xcd, 0x83, - 0x29, 0xe7, 0xb8, 0xf0, 0x33, 0x63, 0x41, 0x3d, 0x0d, 0x25, 0x90, 0x7f, 0xc0, 0xc4, 0xf4, 0x57, 0x74, 0x9d, 0x99, - 0x98, 0x23, 0x88, 0x57, 0x09, 0xcc, 0x0d, 0xba, 0xa6, 0x05, 0x91, 0x16, 0x7c, 0xfa, 0x64, 0x04, 0x60, 0x7e, 0x3f, - 0x54, 0xe0, 0x03, 0xcf, 0x66, 0x09, 0x60, 0x41, 0xa1, 0x58, 0x42, 0x60, 0x81, 0x6f, 0x0c, 0xfc, 0x5b, 0x14, 0x8b, - 0x1f, 0x5c, 0xb1, 0xe7, 0x84, 0x24, 0x9a, 0x01, 0x4a, 0x23, 0xd1, 0xac, 0x66, 0x40, 0xc0, 0xbc, 0xeb, 0x2a, 0xa5, - 0x45, 0x57, 0x85, 0x72, 0x3f, 0xfd, 0xea, 0xe1, 0x8a, 0xe5, 0x40, 0x33, 0x74, 0xb8, 0xe5, 0xd0, 0x15, 0xac, 0xd0, - 0x3d, 0xbc, 0x1c, 0x7e, 0x71, 0xba, 0xa0, 0x19, 0x61, 0x82, 0x4b, 0x60, 0xf1, 0x80, 0x1c, 0xd0, 0x7c, 0x91, 0xbf, - 0x98, 0x31, 0x78, 0x13, 0x7a, 0x17, 0xf8, 0x9c, 0x4f, 0xb3, 0x34, 0x7e, 0x4f, 0xd9, 0x68, 0xa3, 0x34, 0xf4, 0x2c, - 0x66, 0x22, 0xeb, 0x13, 0x0c, 0xfd, 0x39, 0x8c, 0x62, 0xfd, 0xec, 0x0b, 0xe9, 0x4d, 0xd4, 0xb6, 0x08, 0x90, 0x88, - 0xf4, 0x3a, 0xa1, 0xe1, 0xdf, 0x87, 0x5f, 0xc0, 0xc5, 0xfd, 0xc5, 0x8d, 0x6e, 0x0e, 0x32, 0x07, 0xf9, 0x98, 0x2f, - 0x1a, 0x12, 0x72, 0x22, 0x8f, 0xca, 0x99, 0xcd, 0xae, 0xc2, 0x6c, 0xc2, 0xef, 0xdd, 0xac, 0x2b, 0xb8, 0xa9, 0x3e, - 0x84, 0xf4, 0x0c, 0xb8, 0x8b, 0x4d, 0x89, 0xe7, 0xf4, 0x06, 0xc8, 0xa0, 0x8e, 0x43, 0xe2, 0xdf, 0x0a, 0x0e, 0x55, - 0x7d, 0xd8, 0x87, 0x17, 0x95, 0x94, 0x5d, 0xe3, 0x5e, 0xc6, 0xad, 0xbc, 0xc1, 0x2f, 0xe3, 0xa7, 0xee, 0xe7, 0x41, - 0x26, 0x99, 0x61, 0x7c, 0xc8, 0xd1, 0x37, 0x16, 0xc6, 0x57, 0xb0, 0x3f, 0xc0, 0xa0, 0x7a, 0x27, 0xdf, 0xf4, 0xee, - 0x3c, 0x77, 0xde, 0xf1, 0x1c, 0x60, 0x73, 0xe6, 0x5d, 0xe7, 0x38, 0xb4, 0xbb, 0xce, 0x31, 0xfc, 0x7d, 0x00, 0xd6, - 0xcb, 0xee, 0x38, 0x87, 0x1f, 0xbc, 0x4e, 0x68, 0x9f, 0x38, 0xc7, 0xf0, 0x77, 0xc9, 0x5a, 0xfd, 0x88, 0x4c, 0x0f, - 0x30, 0x3c, 0x5f, 0x94, 0xb0, 0x80, 0xf2, 0x5b, 0x6a, 0x11, 0xac, 0xd2, 0xf5, 0xd6, 0xa0, 0x89, 0x00, 0x94, 0xa1, - 0x5b, 0x22, 0x4a, 0x60, 0x3a, 0x30, 0xd2, 0x21, 0xcf, 0x6d, 0x21, 0x0c, 0x32, 0x84, 0xd7, 0xa4, 0xc8, 0xbc, 0xd0, - 0x78, 0x8c, 0x78, 0x9b, 0xe6, 0x30, 0xfb, 0x22, 0x69, 0x1a, 0x53, 0x5d, 0xfc, 0x79, 0x89, 0xf1, 0x71, 0xa8, 0x59, - 0xc3, 0x4a, 0x45, 0xe2, 0xce, 0x7c, 0xf7, 0xc0, 0xd1, 0x6f, 0x94, 0xca, 0xc4, 0x51, 0x9f, 0xb5, 0x6f, 0xae, 0xce, - 0x90, 0xbd, 0xff, 0xd2, 0x7e, 0x30, 0x5f, 0x32, 0xeb, 0x47, 0x44, 0xd8, 0x9d, 0x04, 0x89, 0x1c, 0x9e, 0x82, 0xa2, - 0xbd, 0xe6, 0xfc, 0x04, 0x26, 0x64, 0xd8, 0xb9, 0x00, 0x2a, 0xf9, 0x8e, 0x84, 0x8a, 0xe9, 0x85, 0xd2, 0xf2, 0x89, - 0xc4, 0xfc, 0xcf, 0x9f, 0x17, 0x83, 0xb3, 0x2b, 0xe3, 0x3e, 0xf5, 0x7a, 0x70, 0xed, 0xf6, 0x68, 0x77, 0xab, 0x15, - 0xd0, 0xee, 0x10, 0xcd, 0x45, 0x3c, 0x49, 0xa1, 0xe9, 0x17, 0x3a, 0xc6, 0x56, 0x53, 0xa4, 0x9a, 0x86, 0x11, 0xc2, - 0x5b, 0x57, 0x58, 0x1d, 0xdd, 0x1c, 0xa4, 0xfb, 0x84, 0xa5, 0xe6, 0xbc, 0x98, 0x0e, 0xa0, 0xd9, 0x32, 0x8f, 0x1d, - 0x2e, 0x8d, 0xff, 0xee, 0x49, 0xa0, 0x7b, 0x11, 0x68, 0xf8, 0x2a, 0xa7, 0xb5, 0xe4, 0x6e, 0x22, 0xef, 0x55, 0x76, - 0xa1, 0xd2, 0xf4, 0x5c, 0x87, 0x22, 0x48, 0xbd, 0x86, 0xd9, 0x16, 0xa5, 0x79, 0x93, 0xbc, 0x2d, 0x8a, 0x02, 0x2b, - 0x80, 0xc8, 0xef, 0x86, 0x70, 0x75, 0x32, 0x9f, 0x3f, 0x6f, 0xbd, 0x84, 0x98, 0x3a, 0x59, 0x4d, 0x3a, 0xab, 0xab, - 0xf8, 0x4d, 0x57, 0x51, 0x8c, 0xec, 0x17, 0xb1, 0x86, 0xb0, 0xca, 0x62, 0x7b, 0x0f, 0x7f, 0x8e, 0x29, 0xc9, 0x1c, - 0xae, 0x07, 0x31, 0x94, 0xcb, 0xdd, 0xf2, 0x68, 0x17, 0xec, 0xb1, 0x78, 0x18, 0x2d, 0x1e, 0x33, 0xee, 0xd9, 0xe6, - 0xc3, 0x8a, 0xfb, 0x21, 0x43, 0x1f, 0x9f, 0xdc, 0x22, 0x06, 0xca, 0xbb, 0x8c, 0xb0, 0x40, 0x19, 0xea, 0x95, 0x1b, - 0x67, 0x44, 0xa4, 0x38, 0x02, 0xba, 0x7c, 0xd0, 0xa8, 0x30, 0x54, 0x7c, 0x95, 0xcf, 0xde, 0x5d, 0x7d, 0xa9, 0xf1, - 0xfd, 0xcf, 0xf4, 0x5b, 0xc8, 0xc8, 0xb0, 0x5c, 0x17, 0x43, 0x96, 0xeb, 0x42, 0xe3, 0x59, 0x67, 0x20, 0x63, 0x44, - 0x7e, 0xc0, 0x20, 0xa8, 0x6b, 0x34, 0xf2, 0x99, 0xd6, 0x6f, 0xb1, 0x0a, 0xb3, 0x60, 0x49, 0x92, 0xec, 0x00, 0x9a, - 0xda, 0x80, 0xe4, 0xf4, 0x36, 0x0f, 0x66, 0xa6, 0x38, 0x14, 0x42, 0xb5, 0x2c, 0x12, 0x9a, 0xc3, 0x69, 0x10, 0x4a, - 0xc5, 0xa1, 0xf8, 0x00, 0xf1, 0x7d, 0xba, 0xcc, 0x86, 0x3a, 0x59, 0x42, 0xce, 0x13, 0x0c, 0x63, 0x7a, 0x10, 0xfb, - 0x19, 0xcd, 0xec, 0x34, 0x4b, 0x28, 0x59, 0xe8, 0x32, 0x64, 0x67, 0xbd, 0xbf, 0x74, 0x35, 0x5e, 0x04, 0x99, 0x8c, - 0x79, 0xc7, 0x26, 0x08, 0x2a, 0x3c, 0x18, 0x22, 0x84, 0x33, 0x60, 0x20, 0xbc, 0x8c, 0x67, 0x95, 0x1d, 0x55, 0x50, - 0x2e, 0xe7, 0x4a, 0x5c, 0x09, 0x10, 0x8e, 0xfa, 0x71, 0xf8, 0x91, 0x7b, 0x5d, 0xcb, 0xd0, 0x7c, 0xfa, 0xd9, 0x29, - 0x67, 0x6f, 0x35, 0x0c, 0x14, 0xa0, 0xf7, 0x5c, 0x08, 0x36, 0xdb, 0xe6, 0x8f, 0x7d, 0xc0, 0x2b, 0xab, 0x91, 0x15, - 0xfa, 0x97, 0x7c, 0x2c, 0x57, 0x40, 0x08, 0x95, 0x54, 0xbc, 0x73, 0xef, 0x4c, 0x3a, 0x00, 0xe1, 0xa8, 0x90, 0x56, - 0xfa, 0xf4, 0xe9, 0xf5, 0xe8, 0x9f, 0xff, 0x80, 0x14, 0x04, 0x73, 0x4f, 0x78, 0x41, 0x5f, 0xab, 0xb5, 0x38, 0xf5, - 0x69, 0x8d, 0x50, 0xbd, 0x4f, 0x27, 0x22, 0x2a, 0x8c, 0xd8, 0x5a, 0xf9, 0xe8, 0x46, 0x44, 0x6c, 0x82, 0x34, 0x23, - 0xa6, 0xf0, 0xd5, 0x1e, 0xc1, 0xf2, 0x8e, 0x44, 0x88, 0x00, 0xed, 0xa7, 0xf5, 0x57, 0xc7, 0x9a, 0x5e, 0xe4, 0x0e, - 0x68, 0xd0, 0x41, 0xb3, 0x3d, 0x74, 0x76, 0x4a, 0xb8, 0xf0, 0x15, 0xc8, 0x8f, 0xb4, 0x7f, 0x00, 0xd3, 0x9c, 0xc7, - 0x0b, 0xea, 0x04, 0xf1, 0xc1, 0x3d, 0x1d, 0xdb, 0x64, 0x19, 0x30, 0xf9, 0x32, 0xca, 0xdd, 0x34, 0x46, 0xf9, 0x49, - 0x05, 0x2d, 0xa3, 0xaf, 0xf3, 0x02, 0x94, 0x71, 0x01, 0x28, 0xf8, 0x49, 0xce, 0xca, 0x71, 0xf8, 0x1c, 0x91, 0x17, - 0xa2, 0x8c, 0xe5, 0xcf, 0x59, 0x38, 0x3d, 0x11, 0x39, 0xaf, 0x78, 0xb0, 0xe3, 0xe9, 0x54, 0x8d, 0x9d, 0xe7, 0x94, - 0xbf, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0xc9, 0xbe, 0x54, 0xff, 0x84, 0xfc, 0x09, 0xb1, 0x40, 0x78, 0x98, 0x45, - 0x38, 0xcf, 0xb5, 0x18, 0x7c, 0x12, 0x24, 0x4f, 0x59, 0x25, 0x8e, 0x28, 0xaa, 0xd1, 0xd9, 0x5b, 0x48, 0x93, 0x27, - 0xc3, 0x21, 0xc3, 0x63, 0x55, 0x74, 0x06, 0x50, 0x6a, 0xc8, 0x91, 0x01, 0x93, 0xcd, 0xa0, 0xa1, 0xcd, 0x3c, 0xb8, - 0xb0, 0x51, 0x75, 0x3a, 0xf5, 0x31, 0x1e, 0x10, 0xb1, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5f, 0x58, 0x40, 0xe0, - 0xa2, 0x9f, 0x0a, 0x1e, 0xd7, 0xfe, 0xc0, 0x50, 0xb6, 0x1d, 0x92, 0x87, 0x58, 0xd1, 0xac, 0x73, 0x27, 0xfb, 0x4b, - 0x2c, 0xbd, 0x12, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0xb3, 0x00, 0xd4, 0x4f, 0x93, 0x1a, 0xb6, 0x7f, 0xd7, 0x61, 0x52, - 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xf4, 0x00, 0xe6, 0x07, 0x81, - 0x01, 0x4a, 0x94, 0x51, 0x60, 0x42, 0xf4, 0x01, 0x92, 0x32, 0xeb, 0x80, 0x8b, 0x89, 0x20, 0xea, 0x90, 0x73, 0x94, - 0x41, 0x3e, 0x4b, 0x55, 0xea, 0xc4, 0x8a, 0xdb, 0x4c, 0xe5, 0xed, 0xce, 0xc0, 0xf1, 0xa7, 0x15, 0xa6, 0xdf, 0xc8, - 0x07, 0x19, 0x15, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x46, 0xb0, 0x6e, 0xa9, 0x50, 0xec, 0xe3, - 0x6d, 0xb5, 0x0a, 0xd2, 0x48, 0x56, 0x5b, 0x12, 0x43, 0x7f, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, 0x65, - 0x36, 0x84, 0xaa, 0x42, 0xd8, 0x4e, 0x96, 0x4b, 0x56, 0xd9, 0x1c, 0x9c, 0x1e, 0x30, 0xbe, 0xf3, 0x8c, 0xed, 0xb0, - 0xb3, 0x53, 0xb0, 0x2e, 0x64, 0x8b, 0x4e, 0x96, 0x4b, 0xbe, 0xa4, 0xec, 0x17, 0x7b, 0x73, 0x30, 0xcf, 0x16, 0xe1, - 0xd9, 0xff, 0x01, 0xff, 0xd7, 0x9f, 0x05, 0x1b, 0x5f, 0x03, 0x00}; + 0x1e, 0x7f, 0xcb, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0x6f, 0xaf, 0x16, 0x93, 0xc1, 0xe0, 0xd6, 0xdf, 0xdf, 0xf3, 0x70, + 0x76, 0x3b, 0x67, 0xd7, 0xfc, 0x9e, 0x16, 0xd3, 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, + 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, + 0xde, 0xdb, 0x9a, 0x86, 0xb7, 0xfc, 0xa3, 0x77, 0xed, 0x4f, 0xaf, 0x75, 0xcc, 0xcd, 0x44, 0x1d, 0x49, 0x6f, 0x2f, + 0x9e, 0xb3, 0x5f, 0xf9, 0x27, 0x79, 0x9c, 0x7c, 0x11, 0x72, 0xd2, 0xde, 0x20, 0x77, 0x13, 0x9d, 0x12, 0xef, 0xdc, + 0x44, 0xc2, 0x82, 0x40, 0x18, 0x8e, 0x9a, 0x3f, 0x4c, 0xca, 0xa9, 0xb7, 0x03, 0x6e, 0x57, 0x6e, 0xeb, 0x9f, 0x6f, + 0x39, 0xe7, 0x8b, 0xe1, 0xe5, 0xf4, 0x5d, 0xb7, 0x4b, 0x8f, 0x8a, 0x66, 0x53, 0x81, 0x6e, 0xb7, 0x18, 0x7b, 0x75, + 0x32, 0xb3, 0xcc, 0x25, 0x5f, 0x7a, 0x57, 0x9b, 0x99, 0xc7, 0xf4, 0x7e, 0x33, 0xcd, 0x90, 0xc8, 0x17, 0x08, 0x99, + 0x0e, 0x87, 0xbb, 0x73, 0x2c, 0x8f, 0x0f, 0xdf, 0x3e, 0x7b, 0x32, 0x78, 0x82, 0x91, 0x5b, 0x56, 0x34, 0xc8, 0x3b, + 0x3e, 0xcc, 0xea, 0xd6, 0x6d, 0xe3, 0xe2, 0xf9, 0xf0, 0x17, 0xc8, 0x1b, 0x74, 0x3d, 0x34, 0x45, 0xb4, 0xca, 0xef, + 0x28, 0xfa, 0x44, 0xc9, 0x41, 0xc7, 0x13, 0xa8, 0x1d, 0x52, 0xe0, 0xbe, 0x7b, 0xc6, 0x41, 0xbf, 0x81, 0xa5, 0xf6, + 0xfb, 0xe7, 0x9f, 0x88, 0x47, 0x1a, 0xc6, 0xfb, 0xfb, 0x30, 0xfa, 0x23, 0x2e, 0x8b, 0x35, 0x9c, 0xae, 0x03, 0xf8, + 0xdc, 0x33, 0x7d, 0xfb, 0xba, 0xf3, 0x7d, 0x3f, 0xf0, 0xb6, 0xfc, 0x86, 0xbd, 0xe3, 0xde, 0xe5, 0xf0, 0xad, 0xff, + 0xec, 0x09, 0x88, 0x4e, 0x30, 0x2e, 0x9f, 0x31, 0x12, 0xb6, 0xa3, 0x18, 0xb5, 0x0a, 0x3f, 0xd7, 0x10, 0xa2, 0xf5, + 0x09, 0x19, 0xbb, 0x20, 0xfd, 0x83, 0x02, 0xf4, 0x13, 0x02, 0xab, 0x49, 0x6a, 0x14, 0x98, 0xc4, 0xb7, 0x35, 0x24, + 0x90, 0x82, 0x05, 0x42, 0x6f, 0xa0, 0xf8, 0x54, 0xf0, 0x77, 0xc3, 0xcf, 0x24, 0xf9, 0x2d, 0x6a, 0x3e, 0x86, 0xbf, + 0x61, 0x68, 0x26, 0xd5, 0x43, 0x5a, 0x47, 0x89, 0xf7, 0x93, 0xbf, 0x8f, 0xc2, 0x4a, 0xa8, 0x63, 0x21, 0x48, 0xc5, + 0x90, 0x0b, 0x71, 0xf1, 0x7c, 0x72, 0x5b, 0x8a, 0xf0, 0x8f, 0x09, 0x3e, 0x93, 0x0b, 0x4d, 0x3e, 0xa3, 0x27, 0x8d, + 0x7c, 0xff, 0x41, 0xbe, 0x2f, 0x3b, 0x35, 0x58, 0xd4, 0x43, 0x7e, 0x5b, 0xbb, 0xef, 0xcb, 0x29, 0x41, 0x8f, 0xec, + 0x07, 0x34, 0x05, 0x03, 0x35, 0x01, 0x29, 0x43, 0x70, 0x0b, 0x57, 0x7d, 0x4f, 0x15, 0xe4, 0xcb, 0xef, 0x7d, 0x16, + 0x32, 0x5c, 0x65, 0x41, 0x48, 0x72, 0xa9, 0x90, 0xc2, 0xc6, 0x6d, 0x3d, 0xf8, 0xac, 0x31, 0x49, 0x24, 0xe4, 0x94, + 0x80, 0x24, 0x69, 0x6f, 0x20, 0x49, 0xc4, 0xf4, 0x1f, 0xae, 0x93, 0xa6, 0x59, 0x49, 0xe9, 0x86, 0x38, 0x55, 0xaf, + 0x91, 0xe6, 0x2c, 0x78, 0xcf, 0x60, 0xe9, 0x48, 0xb1, 0xe2, 0x9d, 0x31, 0x18, 0xeb, 0x60, 0xa1, 0x3b, 0x59, 0xdc, + 0xaf, 0x92, 0x30, 0x8d, 0x44, 0x95, 0x2f, 0x42, 0xfe, 0xfc, 0x97, 0x12, 0x7f, 0xf4, 0x96, 0x06, 0x22, 0x10, 0xfc, + 0x00, 0xad, 0x07, 0xac, 0xf1, 0xe0, 0x27, 0x56, 0x97, 0x61, 0x5e, 0x65, 0x54, 0xde, 0x6c, 0xc7, 0xb6, 0x73, 0xa6, + 0xaa, 0x16, 0x7c, 0x16, 0x86, 0x16, 0xed, 0x6c, 0xd5, 0x9c, 0xdc, 0xe6, 0x0d, 0xbe, 0x33, 0x49, 0x22, 0xb5, 0x94, + 0x44, 0xda, 0xea, 0xfa, 0x74, 0xe9, 0x75, 0x8b, 0x0a, 0x1a, 0x23, 0x40, 0x2f, 0x49, 0x77, 0x95, 0x4f, 0x28, 0x5e, + 0x59, 0x0d, 0xab, 0xe1, 0xa5, 0x43, 0x11, 0xc6, 0xda, 0x9b, 0x2b, 0x79, 0x76, 0x07, 0xd6, 0x23, 0xb4, 0x76, 0x55, + 0xea, 0x10, 0xb6, 0x9f, 0xe8, 0x3d, 0xa7, 0x52, 0x7f, 0x03, 0xaa, 0xc0, 0xa9, 0xa3, 0xa1, 0x3e, 0x6a, 0xa7, 0x90, + 0xed, 0xdc, 0x5b, 0x12, 0x54, 0xae, 0xe4, 0xa6, 0x4a, 0x8b, 0x52, 0xca, 0x94, 0xaf, 0x65, 0xb6, 0xb2, 0xfb, 0x64, + 0x00, 0xf1, 0x6c, 0x50, 0x20, 0xb9, 0xa8, 0xad, 0xe6, 0x20, 0x7d, 0x34, 0x4b, 0x1c, 0x6b, 0x07, 0x85, 0x97, 0x55, + 0x60, 0xe6, 0x32, 0x97, 0xcb, 0x41, 0xc1, 0x72, 0xbd, 0xd5, 0x4c, 0x33, 0xd5, 0x17, 0xb9, 0xbd, 0xcd, 0x78, 0x99, + 0xfe, 0x9b, 0x25, 0x03, 0x1e, 0x5d, 0x3c, 0xf7, 0x03, 0x48, 0x93, 0xbc, 0x0e, 0x90, 0x04, 0x9b, 0x83, 0x5d, 0xec, + 0x30, 0x6c, 0x15, 0x2b, 0x7b, 0xf2, 0x74, 0xb9, 0x43, 0x53, 0x2e, 0x61, 0x24, 0x27, 0xe6, 0x52, 0xea, 0xfb, 0x92, + 0xea, 0x86, 0x82, 0x93, 0x4d, 0x13, 0x50, 0x0a, 0x68, 0xb7, 0xe0, 0xbf, 0xf0, 0xa9, 0xa1, 0xd3, 0x02, 0x2c, 0xb5, + 0xdd, 0x80, 0xff, 0x42, 0xbf, 0xd8, 0x3e, 0xa2, 0x7e, 0x60, 0x1e, 0xec, 0xcd, 0xda, 0xca, 0x18, 0x10, 0x91, 0xb8, + 0x82, 0x3c, 0x12, 0xfc, 0xa0, 0xd8, 0xd3, 0x65, 0xe2, 0xc0, 0x99, 0xe2, 0x62, 0x29, 0xb5, 0x99, 0x79, 0xed, 0xb7, + 0xd4, 0xc4, 0x9b, 0x28, 0x89, 0x0a, 0xdb, 0x21, 0x8d, 0x5e, 0x52, 0xc6, 0x54, 0xc1, 0x86, 0xe8, 0xbe, 0x6e, 0x82, + 0x29, 0xf0, 0xa6, 0xaa, 0x02, 0x22, 0xd4, 0x5e, 0x64, 0x79, 0x7e, 0xd3, 0x05, 0x56, 0x17, 0x7c, 0x6c, 0x4c, 0xb3, + 0x0b, 0x56, 0x72, 0x35, 0x93, 0x3e, 0xf3, 0x76, 0xa0, 0x85, 0xbc, 0xcb, 0xcb, 0xa2, 0x15, 0xba, 0x1e, 0x44, 0x0b, + 0x7f, 0xaf, 0x39, 0x1e, 0x3d, 0xdb, 0x56, 0x53, 0x9b, 0x7d, 0xad, 0xc5, 0x02, 0x19, 0x88, 0x86, 0xbe, 0x90, 0x33, + 0x0a, 0x77, 0x95, 0xe6, 0x6a, 0xb5, 0xaf, 0xca, 0x20, 0x81, 0x89, 0x20, 0x6b, 0x59, 0x78, 0x8f, 0xee, 0xd5, 0x23, + 0xcd, 0x2b, 0x09, 0x9e, 0xb9, 0xf8, 0x0b, 0x00, 0xa1, 0x3c, 0x49, 0xc8, 0x01, 0x39, 0x80, 0xbf, 0xa5, 0x28, 0x95, + 0x06, 0xf8, 0x67, 0x75, 0x39, 0xb6, 0xf5, 0xfd, 0x9d, 0x56, 0x31, 0xb8, 0xfe, 0x7c, 0xdd, 0xf5, 0xac, 0x1d, 0xe2, + 0x5c, 0xd9, 0xea, 0xb5, 0x65, 0x9a, 0xc7, 0x48, 0x5d, 0x03, 0x70, 0x27, 0xd2, 0x23, 0x10, 0xc9, 0x4c, 0x34, 0xc8, + 0xd9, 0x0b, 0x3e, 0x9e, 0x8a, 0xc7, 0xa4, 0xbd, 0xca, 0xf7, 0xcd, 0x85, 0x3e, 0x18, 0x63, 0xdf, 0x82, 0x06, 0xf1, + 0xd1, 0x6a, 0x6b, 0x05, 0x62, 0xbd, 0x55, 0xea, 0x43, 0x37, 0x46, 0x41, 0x07, 0x8f, 0xb8, 0x91, 0x0b, 0x8e, 0xed, + 0xae, 0xad, 0xa7, 0xf4, 0x15, 0x80, 0xb9, 0x0e, 0x54, 0x32, 0x0c, 0x52, 0xe7, 0x89, 0xc2, 0x24, 0x3f, 0x4f, 0x48, + 0x42, 0x44, 0x75, 0xb6, 0x1c, 0xa5, 0xdc, 0xb4, 0x80, 0xcb, 0x8c, 0x0c, 0x30, 0x9b, 0x34, 0xeb, 0x27, 0x97, 0x2f, + 0x41, 0x2a, 0x0d, 0x11, 0xdc, 0xb0, 0xbd, 0x64, 0x74, 0xeb, 0xa8, 0x1b, 0x54, 0x49, 0xe6, 0xfa, 0xcd, 0xed, 0x2c, + 0x52, 0xe6, 0xcd, 0x47, 0x18, 0x6b, 0xf2, 0x21, 0xac, 0x13, 0xfc, 0x36, 0x40, 0x25, 0x7d, 0x2a, 0xbc, 0x68, 0x04, + 0x10, 0xea, 0x3b, 0x55, 0xc6, 0xa7, 0xc2, 0xcb, 0x46, 0x5b, 0x96, 0x51, 0x0a, 0xd5, 0x05, 0xb3, 0x5b, 0xd3, 0x85, + 0xe8, 0x56, 0xd5, 0x40, 0x1b, 0xb8, 0x76, 0x1d, 0x28, 0xa0, 0xa1, 0xda, 0x95, 0x1b, 0x16, 0x80, 0xd5, 0x4c, 0x04, + 0x86, 0xcb, 0xbf, 0xcf, 0x5f, 0xa9, 0x18, 0x9e, 0x7e, 0x3f, 0xf4, 0xf6, 0xdb, 0x20, 0x1a, 0x6d, 0x2f, 0xd9, 0x2e, + 0x88, 0x46, 0xbb, 0xcb, 0x86, 0xd1, 0xef, 0xe7, 0xf4, 0xfb, 0x79, 0x03, 0x3a, 0x12, 0x61, 0xc2, 0xec, 0xf5, 0x1b, + 0xb5, 0x7c, 0xa5, 0xd6, 0xef, 0xd4, 0xf2, 0xa5, 0x1a, 0xde, 0xda, 0x93, 0x44, 0x10, 0x59, 0xaa, 0x9a, 0x07, 0x49, + 0x91, 0x6a, 0xe9, 0x72, 0x8c, 0x16, 0x23, 0x6a, 0x29, 0x6b, 0x8e, 0x75, 0x22, 0xed, 0x1c, 0x94, 0x0c, 0x70, 0xb4, + 0xb8, 0xaa, 0x31, 0xdd, 0xac, 0x68, 0x09, 0xc4, 0x08, 0x2b, 0xdb, 0x72, 0x71, 0x93, 0xfa, 0xe8, 0x9c, 0x7c, 0xdb, + 0x2a, 0xe5, 0xdb, 0x56, 0xf0, 0xfc, 0x2b, 0x0a, 0xe5, 0x92, 0x6b, 0xd7, 0xb2, 0x69, 0xa1, 0x14, 0xca, 0xb8, 0x06, + 0x5b, 0xfb, 0x26, 0x30, 0x64, 0x3e, 0x52, 0xd4, 0xd8, 0x5e, 0x34, 0xca, 0x21, 0xc8, 0xd6, 0xc1, 0xa8, 0x53, 0x16, + 0x2c, 0xbe, 0xdd, 0x21, 0x03, 0x19, 0xe8, 0xa8, 0x6a, 0xe3, 0xd5, 0xce, 0x4a, 0x7f, 0x58, 0x5e, 0x3c, 0x67, 0x89, + 0x95, 0x4e, 0x7e, 0x53, 0xa1, 0x3f, 0x08, 0xd1, 0x37, 0x65, 0xc3, 0xc1, 0x8b, 0x2e, 0xb6, 0x32, 0x20, 0xde, 0x30, + 0xbd, 0xb7, 0xb1, 0x92, 0xe5, 0xae, 0x29, 0x5f, 0xcc, 0x78, 0xc2, 0x71, 0xf4, 0xe5, 0x6a, 0x11, 0xd6, 0x6a, 0x91, + 0x9d, 0x00, 0x0f, 0xad, 0xd5, 0x52, 0xc8, 0xd5, 0x22, 0x9c, 0x99, 0x2e, 0xd4, 0x4c, 0xcf, 0x40, 0xf3, 0x28, 0xd4, + 0x2c, 0x4f, 0x00, 0x0b, 0x5e, 0x98, 0x19, 0x2e, 0xcc, 0x0c, 0xc7, 0x21, 0x35, 0x4e, 0x0f, 0x7a, 0xaf, 0x73, 0xcf, + 0x2d, 0x77, 0xa3, 0xd3, 0x30, 0x6f, 0x47, 0x1b, 0xcc, 0xf1, 0x41, 0x38, 0x81, 0xf8, 0xc0, 0x12, 0x01, 0x7a, 0x34, + 0xac, 0x8e, 0x1a, 0x2a, 0x47, 0xf1, 0x65, 0x01, 0x48, 0x96, 0x04, 0x20, 0xb9, 0x57, 0xe3, 0x5c, 0x5a, 0x7e, 0x5d, + 0x25, 0x21, 0x47, 0x64, 0xbc, 0x94, 0x76, 0xf7, 0x84, 0x97, 0x23, 0x23, 0x34, 0x4f, 0x16, 0xa9, 0x97, 0xb3, 0x8c, + 0x8d, 0x11, 0xb8, 0x28, 0xf4, 0x9b, 0xaa, 0xdf, 0x4f, 0x4b, 0x2f, 0xa7, 0x76, 0x7e, 0x02, 0x7f, 0xcb, 0x53, 0x67, + 0x91, 0x23, 0xe4, 0xd5, 0xc8, 0x24, 0x2c, 0x2f, 0x95, 0x7a, 0xfa, 0x12, 0x66, 0x50, 0x77, 0x6f, 0x14, 0x80, 0x6b, + 0x91, 0x4b, 0xa7, 0xda, 0x12, 0xae, 0x4c, 0xb9, 0xc1, 0x3e, 0x0f, 0x79, 0x4e, 0x42, 0xa8, 0x44, 0x1e, 0x29, 0xac, + 0xfb, 0xf6, 0xc5, 0xf3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x0e, 0x00, 0x73, 0x30, 0xf5, 0xa2, 0x01, 0x2f, + 0xd5, 0x9c, 0xf9, 0xe8, 0xe5, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x33, 0xf9, 0xc8, 0xf8, 0x96, 0xf9, + 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, 0x6c, 0x50, + 0x09, 0x36, 0x0d, 0x5f, 0x4b, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, 0x1b, 0xb3, + 0x31, 0x2b, 0xd4, 0xce, 0x93, 0xcb, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, 0x71, 0xce, + 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, 0xa6, 0x25, + 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, 0xe8, 0x95, + 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x73, 0xfe, 0x52, + 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd1, 0xb4, 0x04, 0x75, 0x80, + 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x39, 0xe7, 0x5f, 0x6a, 0x43, 0x84, 0x8c, + 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, 0xc0, 0xe3, + 0xbc, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x1c, 0xf7, 0x4e, 0xd3, 0xb0, 0xfd, 0x17, 0xa0, 0x29, 0x86, 0x72, 0x3c, 0xdf, + 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xca, 0x42, 0xda, 0x96, 0x63, 0xb4, + 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xdc, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x7d, 0xdd, 0x63, 0x36, 0xc9, 0x8a, + 0x45, 0xae, 0x22, 0x4e, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, 0x41, 0xc9, + 0x72, 0x5e, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xd5, 0x9c, 0x52, 0xa8, + 0x7d, 0xc5, 0xc3, 0xea, 0xf4, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, 0x7c, 0xe7, + 0xeb, 0xf4, 0x8e, 0x42, 0x77, 0x9c, 0x99, 0x78, 0xaa, 0x02, 0x63, 0xdf, 0xda, 0x11, 0x14, 0x0e, 0x4d, 0xd7, 0x01, + 0x87, 0x69, 0x74, 0xc2, 0xe2, 0x9f, 0xd2, 0x71, 0xf2, 0xa2, 0x56, 0x88, 0x24, 0xff, 0x10, 0x2e, 0x0c, 0x89, 0x05, + 0x79, 0x49, 0xa8, 0x23, 0x32, 0x62, 0x35, 0x2a, 0xd6, 0x42, 0x45, 0xc5, 0x29, 0x1e, 0x6f, 0x15, 0x14, 0x97, 0xa2, + 0x54, 0x29, 0x15, 0xb9, 0x51, 0x29, 0x20, 0x96, 0x0d, 0xbc, 0x5b, 0xc0, 0x01, 0x10, 0x74, 0x96, 0xbb, 0xb5, 0xed, + 0x6e, 0x23, 0xf3, 0x99, 0x69, 0x9e, 0x56, 0x1f, 0xd4, 0xdf, 0xef, 0x97, 0x18, 0x5b, 0xe3, 0xe9, 0xef, 0xdb, 0xb4, + 0xe0, 0xe6, 0x6f, 0x18, 0xa2, 0x3b, 0x40, 0xc4, 0x2c, 0xed, 0xa1, 0x90, 0x05, 0x13, 0x96, 0xa1, 0x2a, 0x4f, 0x39, + 0xea, 0xe5, 0x93, 0x5b, 0x80, 0x50, 0x43, 0xbf, 0x36, 0x3a, 0xd5, 0x55, 0x09, 0xc2, 0xf7, 0x5d, 0xa1, 0x1e, 0x9b, + 0x03, 0x9e, 0x0c, 0x80, 0xbf, 0x22, 0xaf, 0xf5, 0xd8, 0xfe, 0x41, 0x6f, 0xd4, 0x1b, 0x20, 0x88, 0xce, 0x79, 0xe1, + 0x1f, 0x71, 0xae, 0x53, 0x7f, 0xc6, 0x85, 0x20, 0xbe, 0xf5, 0x24, 0xbc, 0x17, 0x67, 0x69, 0x1c, 0x9c, 0xf5, 0x06, + 0xe6, 0x22, 0x50, 0x9c, 0xa5, 0xf9, 0x19, 0x88, 0xe5, 0x88, 0x89, 0x58, 0xb3, 0x3b, 0x80, 0x09, 0x2c, 0x75, 0x1c, + 0xb2, 0xea, 0xd8, 0x7e, 0xff, 0xcd, 0xc8, 0x90, 0xa5, 0x23, 0x0c, 0x8c, 0xfe, 0x5d, 0x81, 0x00, 0x05, 0xcb, 0xcc, + 0xf6, 0x60, 0xd2, 0xd5, 0x9e, 0xd5, 0xf3, 0x66, 0x93, 0x77, 0xf5, 0x8e, 0xd5, 0xb4, 0x9c, 0x9a, 0x56, 0x59, 0x4d, + 0x9b, 0xe4, 0x50, 0x33, 0xd1, 0xef, 0x6b, 0x50, 0xd4, 0x7c, 0x0e, 0x60, 0x6c, 0x98, 0xfc, 0x66, 0x56, 0xcd, 0xfb, + 0x7d, 0x4f, 0x3e, 0x82, 0x5f, 0xc8, 0x56, 0xe6, 0xd6, 0x58, 0x3e, 0x7d, 0x4d, 0x24, 0x66, 0x06, 0xe6, 0xe8, 0xee, + 0x08, 0xdf, 0xeb, 0x46, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x0d, 0x0c, 0x9e, 0x27, 0x7c, 0x70, 0x91, 0xa3, + 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x1b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, 0x78, 0x90, + 0xfd, 0xfe, 0x0a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0xd7, 0x75, 0x51, 0x56, 0xd0, 0xb1, 0xf4, 0xf3, + 0x56, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x92, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, 0x2e, 0x3e, + 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0xe7, 0x7c, 0xb4, 0x2e, 0xd6, 0x1e, 0xf8, 0xc1, 0xcc, 0xd2, 0xb9, + 0x22, 0xce, 0xc8, 0xfd, 0xd1, 0xe7, 0x22, 0xcd, 0x29, 0x0f, 0x70, 0x1f, 0x8a, 0xb9, 0xfd, 0x16, 0x48, 0x3f, 0xf4, + 0x16, 0xc8, 0x3e, 0x3a, 0xe7, 0xe4, 0x0d, 0x20, 0xd2, 0x21, 0x0c, 0x6e, 0x45, 0x82, 0x8e, 0x55, 0xc3, 0x5b, 0x0b, + 0xec, 0xb4, 0x97, 0xc6, 0xbd, 0x34, 0x3f, 0x4b, 0xfb, 0x7d, 0x83, 0x9a, 0x99, 0x22, 0x1c, 0x3c, 0xce, 0xc8, 0x45, + 0xd2, 0x82, 0x2d, 0xa5, 0xfd, 0x57, 0x03, 0x47, 0x10, 0xf2, 0xf7, 0x3f, 0x84, 0xf7, 0x04, 0x20, 0x36, 0x69, 0x03, + 0xae, 0x7a, 0x4c, 0x47, 0x63, 0x4b, 0xa2, 0x56, 0x9d, 0x0d, 0x90, 0x38, 0x55, 0x5a, 0x4f, 0xb9, 0x59, 0x53, 0x18, + 0xa4, 0xca, 0x42, 0xfd, 0xc6, 0x7a, 0x32, 0x59, 0xe5, 0x22, 0x23, 0x8e, 0xca, 0xf4, 0xa5, 0x66, 0x04, 0xd3, 0xa5, + 0x9f, 0x2f, 0x60, 0xc9, 0xc6, 0x1f, 0x71, 0xf2, 0x96, 0x80, 0x63, 0x3b, 0x6b, 0x57, 0xd5, 0x2e, 0xc7, 0xad, 0xdd, + 0x1c, 0xe0, 0x7b, 0xbd, 0xd1, 0x68, 0xa4, 0x9d, 0xe3, 0x04, 0x0c, 0x55, 0x4f, 0x2d, 0x85, 0x1e, 0xab, 0x15, 0xa0, + 0x6e, 0x47, 0x2e, 0xb3, 0x64, 0x30, 0x5f, 0x18, 0xc7, 0xaf, 0xcc, 0x47, 0x1f, 0x2f, 0x95, 0xb5, 0xeb, 0x88, 0xaf, + 0xff, 0x20, 0xab, 0xf5, 0x2d, 0xef, 0xaa, 0x26, 0xe0, 0x8b, 0x2a, 0xa0, 0xf4, 0x1b, 0xde, 0x93, 0xbd, 0x8b, 0xaf, + 0xdd, 0x60, 0x97, 0x7c, 0xcb, 0x5b, 0xd4, 0x79, 0xbe, 0x72, 0x70, 0xa3, 0x4a, 0xb7, 0xf7, 0x92, 0x05, 0xae, 0xbd, + 0xa3, 0xa6, 0xb1, 0x9e, 0xf9, 0xd1, 0xc3, 0x22, 0x64, 0x3b, 0x1f, 0x7b, 0x5f, 0x35, 0x4f, 0xcf, 0x1a, 0x7a, 0x93, + 0x1a, 0xfa, 0xd8, 0x8b, 0xb2, 0x7d, 0x6a, 0x1a, 0xd1, 0x6b, 0xd8, 0xd0, 0xc7, 0xde, 0x92, 0x93, 0x43, 0x22, 0xc0, + 0xa9, 0x31, 0x7f, 0x7c, 0x38, 0x9d, 0xe1, 0xef, 0x18, 0x50, 0x09, 0xc4, 0x7c, 0x7a, 0x4c, 0x3b, 0x0a, 0x30, 0xa3, + 0x4a, 0x6f, 0x9f, 0x1e, 0xd8, 0x8e, 0x97, 0xf5, 0xd0, 0xd2, 0xbb, 0x27, 0x47, 0xb7, 0xe3, 0x55, 0x35, 0xbe, 0x94, + 0x43, 0x9e, 0xe7, 0xb3, 0xd1, 0x68, 0x24, 0x0c, 0x24, 0x77, 0xa5, 0x37, 0xb0, 0x02, 0x69, 0x5b, 0x54, 0x1f, 0xca, + 0xa5, 0xb7, 0x53, 0x87, 0x76, 0xe5, 0x4f, 0xf2, 0xc3, 0xa1, 0x18, 0x99, 0x63, 0x1c, 0xc0, 0x4d, 0x0a, 0x25, 0x47, + 0xc9, 0x5a, 0x82, 0xe8, 0x94, 0xc6, 0x53, 0x59, 0xaf, 0xad, 0x88, 0xbc, 0x1a, 0x71, 0x1e, 0x82, 0x1f, 0x3d, 0x50, + 0x8b, 0xbf, 0xd0, 0x82, 0xd8, 0x63, 0x9f, 0x2a, 0xa5, 0x17, 0xbc, 0x2a, 0x20, 0x44, 0xec, 0xef, 0x06, 0xda, 0x41, + 0x09, 0x0e, 0x25, 0xdc, 0x07, 0x84, 0x85, 0x7e, 0xed, 0xe5, 0x33, 0x19, 0xa3, 0xdc, 0x1b, 0x54, 0x73, 0x06, 0x30, + 0x95, 0x3e, 0x03, 0xbf, 0x4b, 0x80, 0x3a, 0xc5, 0xa7, 0xe8, 0x54, 0x6f, 0x1e, 0x36, 0x5d, 0x9f, 0x96, 0x28, 0x8a, + 0xe8, 0xce, 0xcf, 0xc7, 0x80, 0xd8, 0xd9, 0xb5, 0x19, 0x69, 0xd7, 0x7e, 0x83, 0x06, 0x2b, 0x25, 0x89, 0x76, 0x4e, + 0x09, 0xbb, 0x9d, 0x8f, 0x6c, 0xe9, 0x47, 0x29, 0x10, 0x73, 0xc7, 0x89, 0x44, 0xf6, 0x60, 0x23, 0x27, 0x70, 0x8b, + 0xf6, 0x8e, 0x0e, 0x40, 0xe5, 0x46, 0x41, 0x7e, 0x35, 0x47, 0x72, 0xc7, 0x77, 0xbd, 0xef, 0x06, 0xf5, 0xe0, 0xbb, + 0xde, 0x59, 0x4a, 0x72, 0x47, 0x78, 0xa6, 0xa6, 0x84, 0x88, 0xcf, 0xbe, 0x1b, 0xe4, 0x03, 0x3c, 0x4b, 0xb4, 0x48, + 0x8b, 0x84, 0x6a, 0x75, 0x8d, 0x9b, 0xf0, 0x22, 0x91, 0xdc, 0x43, 0xbb, 0xce, 0x23, 0x62, 0x01, 0xc8, 0x58, 0x7c, + 0x36, 0x6f, 0x28, 0xd4, 0xdd, 0xc4, 0x6c, 0xd1, 0x5d, 0x16, 0xfb, 0xfd, 0x6d, 0x9e, 0xd6, 0x3d, 0x1d, 0x1f, 0x83, + 0x2f, 0x48, 0x35, 0x01, 0x1e, 0xed, 0xaf, 0xcd, 0xf1, 0xea, 0xd5, 0xe6, 0x48, 0x59, 0xa8, 0x12, 0xf5, 0x5b, 0xac, + 0x66, 0x3d, 0x84, 0xe1, 0xce, 0x32, 0x63, 0x6d, 0x2f, 0x78, 0x25, 0x67, 0x55, 0x6c, 0x97, 0xe3, 0x2b, 0x96, 0xda, + 0x4a, 0xa2, 0x72, 0xb4, 0x1e, 0x6b, 0x53, 0x8c, 0xfc, 0x4a, 0x21, 0x51, 0x16, 0x1d, 0x5b, 0x0b, 0x05, 0xc4, 0x0b, + 0xd0, 0x97, 0xec, 0x4c, 0x03, 0xac, 0x37, 0x7a, 0x15, 0x11, 0x5a, 0x3e, 0x52, 0xe1, 0x4d, 0x6e, 0xaa, 0xcc, 0xca, + 0x66, 0xd1, 0xee, 0xa7, 0x8a, 0x57, 0x08, 0x56, 0x6f, 0xd4, 0x1e, 0x05, 0xa8, 0x3d, 0xb4, 0x50, 0x06, 0x90, 0xd2, + 0x34, 0x03, 0x40, 0x06, 0x00, 0x99, 0x2a, 0xe2, 0x33, 0x01, 0x2a, 0x6d, 0x75, 0xa3, 0xc0, 0x89, 0xf4, 0x1a, 0x68, + 0x16, 0x58, 0xe9, 0x23, 0x05, 0x19, 0x2c, 0xb6, 0x08, 0xc0, 0xca, 0x91, 0x33, 0x4c, 0x63, 0xc8, 0x36, 0x9a, 0xb8, + 0x24, 0xcd, 0xef, 0xc3, 0x2c, 0x95, 0x78, 0x12, 0x3f, 0xc8, 0x1a, 0x23, 0x00, 0x90, 0xbe, 0x4f, 0x2f, 0x8a, 0x2c, + 0x26, 0x1c, 0x38, 0xeb, 0xa9, 0x83, 0xa2, 0x26, 0xe7, 0x5a, 0xd3, 0xea, 0x59, 0x6d, 0xf2, 0x90, 0x05, 0x3a, 0x7b, + 0x30, 0x26, 0xb5, 0x7c, 0xcf, 0x23, 0xfb, 0x2b, 0xc7, 0x33, 0xc2, 0x77, 0xdd, 0xc1, 0xa9, 0xff, 0x6e, 0x6a, 0x60, + 0x62, 0x4a, 0x00, 0x36, 0x06, 0x47, 0x13, 0xe2, 0x77, 0x3a, 0x26, 0x53, 0x9b, 0x14, 0x81, 0xc0, 0x43, 0xf0, 0x0a, + 0x9e, 0x1b, 0x2e, 0xb7, 0xdc, 0xd8, 0x59, 0xe4, 0x69, 0x02, 0x70, 0xe2, 0x05, 0xdf, 0x02, 0x1c, 0xa7, 0x5e, 0x15, + 0xb2, 0x67, 0xcf, 0xc5, 0x74, 0x36, 0x0f, 0x1e, 0x12, 0xda, 0xbf, 0x98, 0xf0, 0x9b, 0xee, 0x2a, 0xb9, 0x32, 0xb5, + 0xee, 0x4d, 0x74, 0x95, 0xcb, 0x9d, 0x3e, 0xad, 0x38, 0x86, 0x39, 0x83, 0x55, 0x40, 0xce, 0xd9, 0x90, 0xbf, 0x38, + 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0xfe, 0x22, 0x94, 0xd5, 0x02, 0xb8, 0x47, 0xce, 0x23, 0xf3, 0xcb, 0x57, 0xdb, + 0xa1, 0x9c, 0x53, 0x14, 0xc6, 0x72, 0x6a, 0x5a, 0x52, 0x9c, 0x0e, 0x3d, 0x05, 0x93, 0xa9, 0x2d, 0x7f, 0x6f, 0x13, + 0x97, 0xd9, 0x9b, 0x49, 0x38, 0x5f, 0x47, 0xb6, 0xad, 0x55, 0xf7, 0xd0, 0x0d, 0xc1, 0xa0, 0x8f, 0x11, 0xb4, 0x6c, + 0xae, 0xef, 0xd6, 0x83, 0x81, 0xc2, 0xf6, 0xad, 0xe9, 0xa6, 0x45, 0xa7, 0x38, 0xe0, 0xcc, 0x5a, 0xd7, 0xa8, 0x54, + 0x15, 0x87, 0x5e, 0xf2, 0x6e, 0x59, 0x95, 0x5d, 0x96, 0x5e, 0x08, 0x52, 0xa3, 0xae, 0x22, 0x44, 0x4a, 0xc5, 0x0e, + 0xef, 0xc9, 0xaf, 0x81, 0x89, 0x67, 0x56, 0x8e, 0xd2, 0x78, 0x0e, 0x30, 0x41, 0x0a, 0x7d, 0x53, 0x7e, 0x05, 0xb8, + 0xa1, 0x8b, 0x28, 0xcc, 0xde, 0xc6, 0x55, 0x50, 0x5b, 0x4d, 0xbf, 0x77, 0x70, 0x62, 0xcf, 0xeb, 0x7e, 0x3f, 0x25, + 0x1a, 0x3f, 0x0c, 0xbd, 0xc0, 0xbf, 0xc7, 0xd3, 0x7d, 0x13, 0xa4, 0xe6, 0x95, 0x07, 0x78, 0x45, 0x97, 0x5b, 0x9b, + 0x72, 0x45, 0xe3, 0x62, 0x5e, 0x23, 0x22, 0x7c, 0xea, 0x28, 0xb6, 0xdb, 0xfc, 0x38, 0xb5, 0x31, 0x18, 0x84, 0x70, + 0xdf, 0xca, 0xf8, 0x7d, 0xe2, 0xe5, 0xb3, 0x68, 0x0e, 0x8a, 0xd2, 0x4c, 0x93, 0x84, 0x14, 0xd2, 0x4b, 0x80, 0x3e, + 0x1a, 0x84, 0x5a, 0x5d, 0xf9, 0x47, 0xe2, 0xa5, 0x6a, 0x5a, 0x9b, 0xa7, 0x58, 0xa3, 0x40, 0xcc, 0xa2, 0x79, 0xc3, + 0x32, 0x3a, 0x24, 0xd5, 0xe5, 0xd2, 0x34, 0xe3, 0x0f, 0xab, 0x19, 0xaa, 0x15, 0x47, 0x4d, 0x50, 0xa3, 0x74, 0x03, + 0x17, 0xc0, 0xbf, 0xd3, 0x1d, 0x47, 0x35, 0x8a, 0x14, 0x0d, 0xf8, 0x04, 0x81, 0x61, 0xcd, 0xe6, 0x09, 0x6b, 0x4d, + 0x5d, 0x33, 0xfa, 0x7d, 0x19, 0x27, 0x64, 0x92, 0x90, 0x9c, 0x0f, 0x97, 0xeb, 0x47, 0x52, 0x5d, 0x00, 0xa9, 0x72, + 0xc5, 0x66, 0xbd, 0xde, 0x1c, 0x30, 0x7a, 0x61, 0xfd, 0xc2, 0xc6, 0x15, 0x9c, 0x5f, 0x12, 0xe6, 0xae, 0xfa, 0x11, + 0x66, 0x19, 0x54, 0x01, 0x69, 0x7e, 0x2c, 0x78, 0xf3, 0xdc, 0x05, 0xa2, 0x7e, 0x33, 0x52, 0x17, 0x94, 0x59, 0x3a, + 0xb7, 0x88, 0x40, 0xc0, 0x6b, 0x58, 0x3d, 0x81, 0x64, 0x5f, 0x3e, 0xf6, 0x69, 0x46, 0x81, 0xea, 0x08, 0x40, 0xd9, + 0xac, 0x1f, 0xc2, 0xfe, 0x01, 0xe1, 0x84, 0xfa, 0x9b, 0x37, 0x72, 0xd6, 0x90, 0x3c, 0x90, 0x6a, 0xc2, 0x63, 0x38, + 0x35, 0x16, 0xf8, 0xd2, 0xa2, 0x37, 0x15, 0xbc, 0x26, 0x38, 0xee, 0x05, 0x5a, 0xfb, 0x16, 0x70, 0x84, 0x08, 0x2e, + 0x43, 0x13, 0xa7, 0xbd, 0x5d, 0x2f, 0x40, 0x42, 0x73, 0x0b, 0xe7, 0xfa, 0xda, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, + 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, + 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, 0x2a, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, + 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, + 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xab, 0xc4, 0x33, 0xec, + 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, + 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x2a, 0xcc, 0x41, 0xde, + 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, + 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, + 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, + 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, + 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0x2f, 0xf2, 0xd1, + 0x96, 0xbe, 0x06, 0xdf, 0x3a, 0x1c, 0xf2, 0xd1, 0xce, 0xfc, 0xf4, 0xc9, 0x5a, 0x29, 0x83, 0x8d, 0x14, 0xa3, 0x10, + 0x12, 0xc5, 0x6d, 0x7b, 0x0c, 0x80, 0xff, 0xfd, 0xc3, 0x81, 0x7e, 0xef, 0xe4, 0x6f, 0xb5, 0x5b, 0x5a, 0xf5, 0xfc, + 0xd0, 0x22, 0xcc, 0x78, 0x5d, 0x1b, 0x76, 0xb6, 0xbd, 0x04, 0x94, 0xde, 0x37, 0x0d, 0x6a, 0x8a, 0xe8, 0x27, 0xac, + 0x26, 0x56, 0x71, 0x58, 0x90, 0x12, 0x87, 0x18, 0x8e, 0xd1, 0x0e, 0x3d, 0x4e, 0x17, 0x35, 0x4f, 0xee, 0x3b, 0x64, + 0xdc, 0xfa, 0x3e, 0x20, 0xb9, 0x14, 0xce, 0x3f, 0x78, 0xa1, 0xc1, 0x44, 0x2f, 0xf2, 0xaa, 0xc8, 0xc4, 0x48, 0xd0, + 0x28, 0xbf, 0x25, 0x71, 0xe6, 0x0c, 0x6b, 0x71, 0xa6, 0x10, 0xc2, 0x42, 0x42, 0xe5, 0x2e, 0x4a, 0x4a, 0x0f, 0xce, + 0x9e, 0xec, 0xcb, 0xe6, 0x77, 0xc2, 0x84, 0x18, 0x2d, 0x80, 0x06, 0x67, 0xd7, 0x2e, 0xef, 0x21, 0x2c, 0x73, 0xef, + 0xf7, 0xb7, 0x77, 0x79, 0x01, 0x71, 0x99, 0x67, 0x52, 0xb1, 0x5a, 0x9e, 0x01, 0x4d, 0x9e, 0x88, 0xcf, 0xc2, 0x4a, + 0x4e, 0x83, 0xaa, 0xa3, 0x58, 0xbd, 0x8d, 0xe7, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, 0xdd, 0x67, 0x6f, 0x94, + 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, 0xe7, 0x26, 0xc8, 0x3f, + 0xbe, 0x3e, 0xa1, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, 0x9b, 0x23, 0x35, 0x79, + 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, 0x67, 0x2b, 0x73, 0x2f, + 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xba, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, 0x62, 0x86, 0x29, 0xd6, + 0x5f, 0xd8, 0xf0, 0x9b, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x63, 0x16, 0xc2, 0xe1, 0xb0, 0x99, 0x14, + 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0x87, 0x43, 0x57, 0xcb, 0xd6, 0xc2, 0x83, 0x87, 0xaa, 0x85, 0x9b, 0x86, 0xe5, + 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, 0x1b, 0x6b, 0xe0, 0x1a, + 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, 0x09, 0xa3, 0x15, 0xc2, + 0xef, 0xbe, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, 0x4a, 0xb1, 0x34, 0x6f, + 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0x73, 0xdf, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, 0xcd, 0xe6, 0xc0, 0x7d, + 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x27, 0xcb, 0xe3, 0xf0, 0x2d, 0xfc, 0xcb, + 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xab, 0x14, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, 0x8d, 0xa8, 0x0d, 0x7f, + 0xc3, 0xbf, 0x85, 0x7d, 0x84, 0xfd, 0x86, 0x26, 0x08, 0x03, 0x58, 0x7f, 0x26, 0x10, 0x17, 0x16, 0x82, 0x04, 0x7f, + 0xab, 0x24, 0xff, 0x9c, 0xf0, 0xd9, 0xa2, 0x04, 0xb2, 0x3a, 0x8c, 0xe2, 0x13, 0x8a, 0x89, 0x42, 0x18, 0x6e, 0x09, + 0xbd, 0xa3, 0xff, 0x46, 0x94, 0x64, 0x93, 0xdc, 0x8a, 0xf5, 0x40, 0x26, 0x49, 0x30, 0xc1, 0xca, 0x0b, 0xe5, 0x4b, + 0xf7, 0x42, 0xa9, 0xb5, 0x16, 0xb4, 0x7e, 0xf9, 0x93, 0xc4, 0x33, 0xa0, 0x7b, 0x20, 0x63, 0xd0, 0x6d, 0x44, 0x35, + 0xc9, 0x31, 0x7d, 0x94, 0xce, 0x33, 0x50, 0x01, 0x9d, 0xad, 0xb3, 0xb0, 0x5e, 0x16, 0xe5, 0xaa, 0x15, 0x1e, 0x2a, + 0x4b, 0x1f, 0xa9, 0xc7, 0x98, 0x17, 0xe6, 0xc9, 0x89, 0x7c, 0xf0, 0x08, 0xd0, 0xf0, 0x28, 0x4f, 0xab, 0x8e, 0xd2, + 0xfa, 0x81, 0x65, 0xc0, 0x08, 0x9c, 0x28, 0x03, 0x1e, 0x61, 0x19, 0x98, 0xa7, 0x5d, 0x86, 0x1a, 0xc4, 0x1a, 0x55, + 0x57, 0x6a, 0x83, 0x39, 0x51, 0x94, 0x7c, 0x8a, 0xa5, 0x15, 0xc6, 0xd0, 0xd4, 0x95, 0x47, 0xd6, 0x4b, 0x4e, 0xd8, + 0x93, 0xdd, 0x40, 0xba, 0x85, 0x8d, 0x02, 0x17, 0x74, 0x2d, 0x4b, 0x94, 0x8b, 0x6e, 0x19, 0x51, 0x26, 0x42, 0xea, + 0x67, 0x0f, 0x67, 0x5a, 0xed, 0x37, 0x76, 0xd2, 0xbe, 0x3d, 0x52, 0xf4, 0x82, 0x81, 0xf8, 0xb4, 0x47, 0x4a, 0x3d, + 0x6b, 0xe4, 0x32, 0xb0, 0xa5, 0x4b, 0x55, 0xcf, 0x7f, 0x83, 0xf2, 0x1d, 0xcc, 0x8c, 0xb3, 0xd9, 0xef, 0x7a, 0x73, + 0x7b, 0xb2, 0xaf, 0x9b, 0xdf, 0x59, 0xaf, 0x07, 0x5b, 0x83, 0x4c, 0x7c, 0xa9, 0xa8, 0xa7, 0xac, 0x42, 0xac, 0xc8, + 0xec, 0x7f, 0x0b, 0xef, 0x77, 0x78, 0x6b, 0x84, 0x66, 0x65, 0x3c, 0xcc, 0x47, 0x4f, 0xf6, 0xa2, 0xf9, 0xbd, 0xb3, + 0x6c, 0x2b, 0x57, 0x25, 0xb3, 0xfd, 0x7e, 0x94, 0x34, 0x67, 0x8f, 0xd7, 0x48, 0xea, 0x00, 0x1f, 0xaf, 0xcf, 0xf0, + 0x91, 0x4a, 0x28, 0xb5, 0xa0, 0xaa, 0x41, 0xeb, 0x63, 0xbf, 0xb7, 0x9e, 0xd3, 0xc7, 0x8f, 0xe5, 0x74, 0x4b, 0x8a, + 0x30, 0x7e, 0x60, 0x30, 0x65, 0x27, 0x4e, 0x5d, 0xf2, 0x66, 0x48, 0xef, 0xba, 0x55, 0x52, 0x97, 0x3d, 0x4a, 0x04, + 0xa1, 0x0e, 0xd6, 0x2f, 0xf6, 0x43, 0x98, 0xd9, 0xa2, 0x3f, 0x6c, 0x56, 0x73, 0x42, 0x41, 0x04, 0x88, 0x56, 0x79, + 0x1f, 0x38, 0x26, 0x09, 0xb3, 0xe6, 0x86, 0x74, 0xeb, 0xcd, 0x95, 0xf6, 0x4a, 0x0a, 0xe8, 0xe7, 0x20, 0x73, 0xfb, + 0xe8, 0x96, 0xab, 0x96, 0x79, 0x2e, 0x6d, 0x39, 0x60, 0xd1, 0x42, 0x74, 0x66, 0xe7, 0xd2, 0xe1, 0xe0, 0x3f, 0xa8, + 0x2b, 0x51, 0x45, 0x04, 0x1d, 0x45, 0x0b, 0x46, 0xab, 0x55, 0xbb, 0x9c, 0x6c, 0x2a, 0x64, 0x4b, 0x22, 0x9c, 0x28, + 0xd9, 0x2b, 0xa1, 0x3e, 0xca, 0xd5, 0x9e, 0x69, 0x88, 0x3f, 0x13, 0xb0, 0x69, 0x83, 0xbf, 0x05, 0xee, 0x65, 0x70, + 0x66, 0xda, 0xa7, 0x61, 0x04, 0x44, 0xe6, 0x10, 0xec, 0xe7, 0x77, 0x3d, 0xa8, 0xe0, 0x41, 0x47, 0xfa, 0xeb, 0x7a, + 0x56, 0xe0, 0x99, 0x7b, 0xe2, 0xf9, 0x9b, 0x13, 0xe9, 0x45, 0x0e, 0x0f, 0x34, 0xf7, 0x61, 0xc6, 0x5f, 0x96, 0x65, + 0xb8, 0x1b, 0x2d, 0xcb, 0x62, 0xe5, 0x45, 0x7a, 0x1f, 0xcf, 0xa4, 0x18, 0x48, 0x74, 0x98, 0x19, 0x5d, 0xc5, 0x3a, + 0xce, 0x61, 0xdc, 0xdb, 0x93, 0xb0, 0x42, 0xfb, 0x67, 0x89, 0xbd, 0x2e, 0x00, 0xc0, 0x21, 0x6b, 0xd0, 0x0a, 0xef, + 0x74, 0x7b, 0xbb, 0xc7, 0x25, 0x25, 0x8a, 0x1b, 0x35, 0x3f, 0xab, 0xa1, 0x65, 0x82, 0x5a, 0x66, 0xdd, 0xc9, 0x64, + 0x8a, 0x24, 0xf0, 0x6d, 0xd8, 0x1b, 0x56, 0xe4, 0xf3, 0x46, 0x6e, 0x0f, 0xef, 0xc2, 0x95, 0x88, 0xb5, 0x05, 0x9d, + 0x74, 0x64, 0x1c, 0xee, 0x85, 0xe6, 0x46, 0xba, 0x7f, 0x52, 0x25, 0x61, 0x29, 0x62, 0xb8, 0x05, 0xb2, 0xbd, 0xda, + 0x56, 0x82, 0x12, 0x48, 0x60, 0x3f, 0x94, 0x62, 0x99, 0x6e, 0x05, 0x80, 0x39, 0xf0, 0x3f, 0x25, 0x0c, 0xa1, 0xbb, + 0xf3, 0x10, 0xaf, 0x1a, 0x79, 0xdf, 0x20, 0x04, 0xfb, 0x6b, 0x90, 0xd3, 0x80, 0x41, 0xa4, 0x18, 0xc9, 0x82, 0x81, + 0x04, 0x20, 0xe7, 0x6b, 0x30, 0xc9, 0x4d, 0x73, 0xcf, 0x0f, 0x72, 0xdd, 0xc1, 0xb4, 0x0f, 0xba, 0x17, 0xd7, 0x9a, + 0xe5, 0xe0, 0x15, 0x13, 0xf1, 0xbf, 0xd7, 0x5e, 0xc9, 0x72, 0x96, 0xf9, 0x8d, 0xb9, 0xe8, 0x64, 0x70, 0xd5, 0x10, + 0x7e, 0x31, 0xcb, 0xe6, 0x3c, 0x9a, 0x65, 0x3a, 0xd4, 0xbf, 0x68, 0x8e, 0x4a, 0x01, 0x0c, 0x75, 0xbc, 0x00, 0x6b, + 0xbc, 0x2b, 0xdd, 0xb4, 0xe2, 0x91, 0xc6, 0x18, 0x05, 0x15, 0x3a, 0x08, 0xfd, 0xbd, 0x06, 0x78, 0x0d, 0x26, 0xb9, + 0x11, 0x2a, 0x1f, 0x5c, 0xd0, 0x0d, 0xdd, 0x72, 0xe5, 0x12, 0xd4, 0xa4, 0x6a, 0xf9, 0xe5, 0x08, 0xf5, 0xae, 0x96, + 0x5c, 0xaa, 0xcd, 0xa7, 0x46, 0x59, 0x23, 0xc8, 0xe4, 0x28, 0xfd, 0x3e, 0xe5, 0xc2, 0xad, 0x8c, 0xc9, 0xfa, 0x70, + 0xf0, 0x0a, 0x6e, 0x6a, 0xfc, 0x3a, 0x27, 0x16, 0x51, 0x7b, 0x48, 0x84, 0xad, 0xdd, 0x0a, 0xdd, 0x7b, 0xdc, 0x28, + 0xcd, 0xa3, 0x6c, 0x13, 0x8b, 0xca, 0xeb, 0x25, 0x60, 0x2d, 0xee, 0x01, 0x19, 0x2a, 0x2d, 0xfd, 0x8a, 0x15, 0x00, + 0x19, 0x20, 0x85, 0x8d, 0x1f, 0x90, 0xf6, 0xea, 0x83, 0x97, 0xfa, 0xfd, 0xbe, 0x31, 0xe5, 0xbf, 0x7f, 0xc8, 0x81, + 0x99, 0x50, 0x94, 0xf5, 0x0e, 0x26, 0x10, 0x5c, 0x3b, 0x49, 0x7b, 0x56, 0xf3, 0x17, 0xeb, 0xda, 0x03, 0x52, 0x2b, + 0xdf, 0x62, 0xae, 0x7a, 0x6d, 0x5f, 0x6c, 0xf6, 0x69, 0x75, 0x63, 0x34, 0x0e, 0x82, 0xa5, 0xd5, 0x5b, 0xad, 0x72, + 0xc8, 0x1b, 0x5e, 0x81, 0x48, 0x65, 0x5d, 0x5d, 0x2b, 0xe7, 0xea, 0x5a, 0x70, 0x24, 0x90, 0x2d, 0x79, 0x0e, 0xff, + 0x85, 0xdc, 0x2b, 0x0f, 0x87, 0xc2, 0xef, 0xf7, 0xd3, 0x19, 0x69, 0x65, 0x81, 0x32, 0x6d, 0x5d, 0x7b, 0xa1, 0x7f, + 0x38, 0xfc, 0x00, 0x5e, 0x23, 0xfe, 0xe1, 0x50, 0xf6, 0xfb, 0x1f, 0xcd, 0x4d, 0xe6, 0x7c, 0xac, 0x94, 0xb2, 0x97, + 0xa8, 0x74, 0x7f, 0x9b, 0xf0, 0xde, 0xff, 0x1e, 0xfd, 0xef, 0xd1, 0x65, 0x4f, 0x05, 0x80, 0x25, 0x7c, 0x86, 0x37, + 0x74, 0xa6, 0x2e, 0xe7, 0x4c, 0xba, 0xbb, 0x2b, 0x3f, 0xf4, 0x9e, 0xc6, 0x87, 0xef, 0xcd, 0x4d, 0x1b, 0x7f, 0xad, + 0x8e, 0x34, 0x09, 0x1d, 0x17, 0xfd, 0xc3, 0xe1, 0x53, 0xa2, 0xf5, 0x69, 0xa9, 0xd2, 0xa7, 0x29, 0xf0, 0x24, 0xc3, + 0x86, 0xeb, 0x16, 0xa6, 0xa3, 0xf9, 0x71, 0xf3, 0x55, 0xf2, 0xe2, 0x2c, 0x85, 0x6b, 0x6f, 0x3e, 0x4b, 0xe7, 0x53, + 0xb0, 0xae, 0x0c, 0xf3, 0x59, 0x3d, 0x0f, 0x20, 0x75, 0x08, 0x69, 0xd6, 0x34, 0xfc, 0x5b, 0xe5, 0x0a, 0xde, 0xda, + 0xe3, 0xdd, 0x60, 0x44, 0xa9, 0x23, 0x7d, 0xd2, 0x86, 0xd0, 0x25, 0x95, 0xfc, 0x47, 0x91, 0xc7, 0x18, 0xb3, 0xf1, + 0x9a, 0xc8, 0x3e, 0x8b, 0xfc, 0x55, 0x01, 0x80, 0x45, 0x80, 0x80, 0x9c, 0xce, 0x1d, 0x49, 0xfc, 0xe7, 0xe4, 0xdb, + 0x3f, 0xa6, 0x4b, 0xfb, 0x50, 0x16, 0x77, 0xa5, 0xa8, 0xaa, 0xa3, 0xd2, 0x76, 0xb6, 0x5c, 0x0f, 0xf4, 0xa1, 0xfd, + 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, 0x58, 0x3f, 0xbf, + 0xdf, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, 0xc3, 0x54, 0xe2, + 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0x7f, 0x54, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, + 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0x17, 0xc2, 0x22, 0xf9, 0xf5, 0xc9, 0x91, + 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x91, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9e, 0xff, 0xb9, 0x99, 0xff, 0x03, 0x74, 0x86, + 0x2c, 0x5e, 0x70, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0x2f, 0x80, 0x83, 0xf9, 0x05, + 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0x37, 0x16, 0xcf, 0x95, 0x5c, 0x10, 0xfa, + 0xba, 0x0a, 0xb3, 0x71, 0x55, 0x6c, 0x2a, 0x51, 0x6c, 0xea, 0x1e, 0xa9, 0x65, 0xf3, 0x69, 0x6d, 0x2b, 0x64, 0x7f, + 0x12, 0x2d, 0xda, 0x2e, 0x43, 0x35, 0x19, 0x65, 0xe9, 0x7a, 0x0a, 0xa4, 0x7a, 0x01, 0x9c, 0x45, 0xe6, 0x95, 0x2f, + 0xce, 0x1e, 0xb0, 0x45, 0xe3, 0x29, 0x30, 0xa2, 0xd2, 0x1f, 0x79, 0x63, 0x74, 0x7a, 0xa2, 0xdf, 0xcf, 0xa7, 0x14, + 0xf2, 0xf5, 0x13, 0x60, 0x72, 0xd5, 0x72, 0x01, 0xfa, 0x32, 0xd4, 0x41, 0x25, 0x4a, 0xad, 0x18, 0x46, 0x2c, 0xfc, + 0x24, 0x90, 0xbd, 0x99, 0x82, 0x9a, 0x55, 0x94, 0x84, 0x4a, 0x54, 0x4a, 0xb6, 0x26, 0xa8, 0xa5, 0xf7, 0x45, 0x51, + 0xef, 0x2b, 0x70, 0x94, 0x8c, 0xb4, 0x59, 0x4e, 0x99, 0x71, 0x51, 0xe6, 0xa2, 0x1f, 0xec, 0xdf, 0x95, 0xe7, 0x37, + 0x32, 0x9f, 0xe5, 0xbe, 0xa3, 0x73, 0xda, 0x8e, 0x0b, 0x94, 0xb9, 0xe5, 0xb4, 0xd5, 0x92, 0xc7, 0xe4, 0x3d, 0x0b, + 0xb6, 0xfd, 0x97, 0x09, 0xf2, 0x2a, 0xc2, 0x7c, 0x42, 0x95, 0xcd, 0x3f, 0x20, 0xcc, 0x16, 0x07, 0xf6, 0xd8, 0x85, + 0x89, 0x48, 0x6f, 0xc1, 0x92, 0x18, 0x66, 0xa5, 0x08, 0xe3, 0x1d, 0x78, 0xff, 0x6c, 0x2a, 0x31, 0x3a, 0x43, 0x27, + 0xf7, 0xb3, 0x87, 0xb4, 0x4e, 0xce, 0xde, 0xbe, 0x3e, 0xfb, 0xae, 0x37, 0x28, 0x46, 0x69, 0x3c, 0xe8, 0x7d, 0x77, + 0xb6, 0xda, 0x00, 0x44, 0xa6, 0x38, 0x8b, 0xc9, 0x94, 0x26, 0xe2, 0x33, 0x32, 0x0c, 0x9e, 0xd5, 0x89, 0x38, 0xa3, + 0x89, 0xe9, 0xbe, 0x46, 0x69, 0xf2, 0xed, 0x28, 0xcc, 0xe1, 0xe5, 0x52, 0x6c, 0x2a, 0x11, 0x83, 0x9d, 0x52, 0xcd, + 0xb3, 0xbc, 0x7d, 0x16, 0xe7, 0xa3, 0x0e, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, 0x05, 0x84, 0x1e, + 0x00, 0x27, 0x5d, 0xf9, 0xf3, 0x70, 0x10, 0x09, 0x84, 0x5a, 0x30, 0x27, 0xd3, 0x88, 0x6e, 0x48, 0xaf, 0xb0, 0xcf, + 0xc0, 0x2c, 0xa4, 0x34, 0x0f, 0x6e, 0xae, 0x16, 0x2d, 0x77, 0xc5, 0xca, 0x51, 0x58, 0xad, 0x45, 0x54, 0x23, 0xd5, + 0x31, 0x38, 0xef, 0x40, 0x04, 0x80, 0x62, 0x04, 0xcf, 0x78, 0xd4, 0xef, 0x47, 0x2a, 0x28, 0x27, 0xa1, 0x5f, 0x14, + 0xfa, 0xa5, 0x31, 0x28, 0x63, 0xfe, 0x2e, 0xd4, 0xc4, 0x00, 0xf5, 0x96, 0x87, 0x8a, 0x23, 0x00, 0x97, 0x73, 0xc4, + 0x8c, 0xf3, 0x1e, 0x77, 0xd1, 0x38, 0x15, 0xef, 0x84, 0xba, 0x0e, 0x96, 0x0a, 0x75, 0xde, 0xd4, 0x47, 0x7a, 0x4e, + 0x9a, 0x04, 0x0d, 0xe2, 0x06, 0x1e, 0xaf, 0x86, 0x80, 0x6a, 0x25, 0xa4, 0xde, 0x42, 0xa7, 0x54, 0x75, 0x08, 0xac, + 0x01, 0x2e, 0x51, 0xd8, 0x56, 0x98, 0x1c, 0xd1, 0xa6, 0x2c, 0x45, 0x7e, 0xc4, 0x06, 0xed, 0x92, 0x91, 0xa9, 0x83, + 0xcb, 0xe5, 0x72, 0x22, 0xea, 0x5f, 0xf3, 0x2d, 0x80, 0xf3, 0x42, 0x7e, 0x6b, 0x37, 0x5b, 0x26, 0xd9, 0xae, 0x2b, + 0xc3, 0x59, 0x52, 0x8a, 0x6a, 0x5d, 0xe4, 0x55, 0x7a, 0x2f, 0x7e, 0xd6, 0x0f, 0x5d, 0x02, 0x29, 0xf4, 0x23, 0xbd, + 0x6e, 0x37, 0x47, 0xaa, 0x71, 0x74, 0x39, 0xb6, 0xa7, 0xd2, 0x4e, 0xf6, 0xaa, 0xc5, 0x9b, 0x2d, 0x73, 0x25, 0x69, + 0x1c, 0x8b, 0xfc, 0x6d, 0x1e, 0xa7, 0x91, 0x95, 0x1c, 0xfe, 0x1f, 0xde, 0xbe, 0x85, 0xbb, 0x6d, 0x1b, 0x5b, 0xf7, + 0xaf, 0x58, 0xbc, 0xa9, 0x4a, 0x44, 0x90, 0x2c, 0x39, 0x49, 0x67, 0x4a, 0x19, 0xd6, 0x71, 0xf3, 0x68, 0xd3, 0x36, + 0x71, 0x1a, 0xa7, 0x9d, 0xce, 0xe8, 0xea, 0xb8, 0x34, 0x09, 0x5b, 0x6c, 0x68, 0x40, 0x25, 0x29, 0x3f, 0x22, 0xf1, + 0xbf, 0xdf, 0xb5, 0x37, 0x9e, 0xa4, 0x68, 0x27, 0x33, 0xf7, 0xdc, 0xbb, 0xb2, 0x56, 0x2c, 0x82, 0x20, 0xde, 0xd8, + 0xd8, 0xd8, 0x8f, 0x6f, 0xeb, 0x00, 0xd5, 0x2e, 0xf2, 0x95, 0x8b, 0x8d, 0xfc, 0x22, 0x2b, 0x31, 0x60, 0x70, 0xa3, + 0x51, 0xad, 0x50, 0x53, 0x26, 0xf0, 0x85, 0x7c, 0x8f, 0x11, 0xb7, 0x59, 0x99, 0x00, 0xc3, 0x8f, 0x89, 0xfa, 0x92, + 0x9e, 0x42, 0x94, 0x07, 0x15, 0x8f, 0xfb, 0x05, 0x47, 0xc4, 0x6b, 0xab, 0x32, 0x07, 0x26, 0x5b, 0xab, 0x20, 0x11, + 0xec, 0x2e, 0x9b, 0xeb, 0x45, 0xb4, 0x50, 0x77, 0xa1, 0x5e, 0xbc, 0xdd, 0xf6, 0x12, 0x45, 0x07, 0x9c, 0xfc, 0x34, + 0x78, 0x15, 0x67, 0x39, 0x4f, 0xf7, 0x2a, 0xb9, 0xa7, 0x36, 0xd4, 0x9e, 0x72, 0xe6, 0x80, 0x9d, 0xf7, 0x75, 0xb5, + 0xa7, 0xd7, 0xf4, 0x9e, 0x6e, 0xe7, 0x1e, 0x5c, 0x30, 0x70, 0xe7, 0x5e, 0x66, 0xd7, 0x5c, 0xec, 0x81, 0x32, 0xd0, + 0x1a, 0x0f, 0xd4, 0xa2, 0x1a, 0xa9, 0x89, 0xd1, 0x81, 0xab, 0x13, 0x7d, 0x30, 0x07, 0xf4, 0x7b, 0x88, 0x15, 0xde, + 0x7a, 0xbb, 0xd2, 0x07, 0x6d, 0x40, 0x7f, 0x5e, 0x9a, 0x3e, 0xe8, 0x68, 0xf1, 0x2a, 0x24, 0x70, 0x63, 0x48, 0x35, + 0x52, 0xab, 0x91, 0x55, 0xa0, 0x78, 0xc3, 0x5b, 0xbc, 0x3b, 0xd7, 0x92, 0x8d, 0xf7, 0x12, 0x81, 0xbd, 0x32, 0x51, + 0xc5, 0x99, 0x38, 0xf6, 0x52, 0x79, 0xad, 0x9d, 0x64, 0x84, 0xf1, 0x2d, 0x2b, 0xa9, 0xbf, 0x43, 0xcc, 0x2d, 0xd2, + 0x1c, 0x06, 0x2f, 0xc3, 0x8a, 0xcc, 0x78, 0xbf, 0x2f, 0x67, 0x32, 0x2a, 0x67, 0x62, 0xbf, 0x8c, 0x14, 0x42, 0xdb, + 0x7d, 0x22, 0xa0, 0x07, 0x25, 0x40, 0xbe, 0x00, 0xa8, 0x7a, 0x48, 0xf8, 0xf3, 0x90, 0xd4, 0xa7, 0x53, 0xe8, 0x53, + 0x68, 0xeb, 0x15, 0xaf, 0xa0, 0xaa, 0x6e, 0x8c, 0x6c, 0xa3, 0x82, 0x16, 0x8f, 0xe5, 0x59, 0x6d, 0x18, 0x9b, 0x53, + 0xeb, 0x5d, 0x6f, 0x36, 0x98, 0xb2, 0xb9, 0x50, 0xab, 0x30, 0x24, 0xd1, 0x4d, 0xe9, 0x85, 0x0f, 0xb1, 0x58, 0x59, + 0xad, 0xcd, 0x6f, 0x62, 0x7f, 0x64, 0x22, 0xc5, 0xfd, 0x6c, 0x89, 0x73, 0x17, 0x8f, 0xe7, 0x55, 0x5f, 0x6b, 0x69, + 0x91, 0x69, 0xf3, 0x9d, 0xbe, 0x0c, 0x69, 0x2a, 0x6a, 0x48, 0xa3, 0xce, 0x0c, 0xba, 0x6f, 0x97, 0x57, 0x54, 0x23, + 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, 0x1e, 0x88, 0xa2, 0x1a, 0x15, 0x6b, 0x21, 0x10, 0x6d, 0x18, 0x72, 0xcc, + 0x2c, 0x21, 0xc9, 0x3e, 0xf1, 0xef, 0x54, 0x70, 0x85, 0x22, 0xbe, 0x31, 0x70, 0xde, 0x95, 0xf5, 0xec, 0xae, 0x23, + 0x3f, 0x27, 0x16, 0x56, 0xfb, 0x0f, 0xcd, 0xa3, 0xd6, 0x38, 0x0b, 0x68, 0x6b, 0x5a, 0xdd, 0x70, 0xb8, 0x47, 0x75, + 0x2c, 0x4a, 0x03, 0x48, 0xec, 0x91, 0xe5, 0xa2, 0x75, 0xcc, 0xa0, 0x01, 0xfd, 0x6d, 0x76, 0xb5, 0xbe, 0x42, 0xd4, + 0xb6, 0x12, 0x59, 0x27, 0xa9, 0xfc, 0x4b, 0xda, 0xa3, 0xae, 0xed, 0xa9, 0xfc, 0x6f, 0xdb, 0x54, 0x39, 0xb4, 0x40, + 0xf2, 0xd8, 0xcd, 0x59, 0xa0, 0x3a, 0x12, 0x44, 0x81, 0xda, 0x7a, 0xc1, 0xd4, 0x3b, 0x65, 0x8a, 0x0e, 0xe4, 0xe7, + 0xc2, 0x9c, 0x61, 0x5f, 0x70, 0xc4, 0x98, 0xa5, 0x12, 0x83, 0xa9, 0x8f, 0x31, 0xaa, 0x69, 0xad, 0x00, 0x5d, 0x3f, + 0xdd, 0xc0, 0x9f, 0xa8, 0xa8, 0xd1, 0x50, 0x6b, 0x24, 0x85, 0xa2, 0x89, 0x0a, 0x3a, 0x96, 0x16, 0x3a, 0x98, 0x42, + 0x27, 0x91, 0xb0, 0x04, 0x34, 0x4c, 0x88, 0x4e, 0x2a, 0xf0, 0xd6, 0x00, 0xce, 0x7c, 0x5c, 0x94, 0xeb, 0x42, 0x1b, + 0xcc, 0xfd, 0x10, 0x5f, 0xf3, 0xd7, 0x2f, 0x9c, 0x51, 0x7d, 0xcb, 0x5a, 0xdf, 0xd3, 0x82, 0xfc, 0x10, 0x72, 0x8a, + 0x0e, 0x4c, 0xec, 0x68, 0x83, 0xc6, 0x18, 0x65, 0xad, 0x43, 0x5d, 0x9c, 0xe8, 0xf8, 0x2b, 0xda, 0x04, 0xef, 0x01, + 0x4f, 0x11, 0x6d, 0x78, 0x28, 0x8c, 0x55, 0x35, 0x3e, 0x95, 0xac, 0xa5, 0x07, 0x2b, 0x78, 0xba, 0x4e, 0x78, 0x08, + 0x7a, 0x24, 0xc2, 0x8e, 0xc2, 0x62, 0x1e, 0x2f, 0xe0, 0x38, 0x29, 0x08, 0xa8, 0x1d, 0xf4, 0x15, 0x7c, 0xbe, 0x40, + 0xf7, 0x57, 0x89, 0x1e, 0x60, 0x68, 0x41, 0xdc, 0x0c, 0x7d, 0x3a, 0xba, 0x8a, 0x57, 0x0d, 0x15, 0x09, 0x9f, 0x17, + 0x60, 0x3b, 0xa4, 0xd4, 0x53, 0xa0, 0x85, 0x4a, 0x94, 0x7e, 0x18, 0xf8, 0x0e, 0x0d, 0x7c, 0xad, 0x75, 0x80, 0x86, + 0x7e, 0xc6, 0x34, 0xb5, 0xce, 0x50, 0xf9, 0xcc, 0xbb, 0x67, 0x46, 0xcb, 0x99, 0x05, 0x63, 0xd0, 0xb7, 0xd1, 0x14, + 0xc5, 0x39, 0xf9, 0x2c, 0x28, 0xe2, 0x34, 0x8b, 0x73, 0xf0, 0xdb, 0x8c, 0x0b, 0xcc, 0x98, 0xc4, 0x15, 0xbf, 0x94, + 0x05, 0x68, 0xbb, 0x73, 0x95, 0x5a, 0xd7, 0x20, 0x20, 0xfb, 0x01, 0xac, 0x5e, 0x1a, 0x3a, 0x2a, 0xe7, 0xdd, 0xa5, + 0x4d, 0x21, 0x62, 0x11, 0x82, 0x4d, 0x33, 0x5d, 0xb2, 0xe3, 0x50, 0x69, 0x73, 0x20, 0xbe, 0x11, 0x1a, 0xf7, 0x4f, + 0xc3, 0xd8, 0x6a, 0x8a, 0xad, 0xdd, 0xdb, 0x76, 0xfb, 0x7b, 0xe9, 0xa5, 0xd3, 0x9c, 0xf4, 0x18, 0xfb, 0xbd, 0x0c, + 0x8b, 0x91, 0xed, 0x08, 0x81, 0x25, 0xe7, 0x7d, 0xea, 0xbf, 0xa2, 0xe5, 0x3c, 0x01, 0xd3, 0x11, 0x1d, 0x21, 0x17, + 0x28, 0x3b, 0x46, 0x71, 0x07, 0x06, 0x57, 0xf4, 0xfb, 0x60, 0x95, 0x61, 0x2e, 0x24, 0x4b, 0x92, 0x32, 0x78, 0x9e, + 0x7a, 0x18, 0xf0, 0x6b, 0xa6, 0xcc, 0x5d, 0x94, 0xf5, 0xe9, 0x92, 0x4c, 0x53, 0x64, 0x20, 0xd6, 0xe1, 0x26, 0x4b, + 0xa3, 0x44, 0x89, 0xc8, 0x96, 0xe8, 0x1f, 0x69, 0x28, 0x96, 0x0e, 0xd7, 0x8b, 0x54, 0x89, 0x50, 0x31, 0x4f, 0xf1, + 0xa4, 0x4e, 0xeb, 0x74, 0x84, 0xf1, 0x26, 0x41, 0x29, 0x57, 0xc3, 0x40, 0x95, 0x54, 0x2f, 0x85, 0x4d, 0xb1, 0xdd, + 0xea, 0x8b, 0x95, 0x98, 0xc7, 0x0b, 0x7c, 0x29, 0x70, 0x14, 0x7f, 0xe2, 0x5e, 0xac, 0x29, 0xb5, 0x3d, 0xa8, 0x1d, + 0x51, 0x42, 0x7f, 0xe2, 0x70, 0x91, 0xf8, 0x4e, 0xea, 0xb8, 0x7f, 0x68, 0x11, 0x72, 0xa6, 0x0e, 0x52, 0xc3, 0x0d, + 0xed, 0x08, 0xff, 0x0d, 0xd7, 0x67, 0x9c, 0xd1, 0x9b, 0x6a, 0x46, 0x8d, 0xdf, 0xeb, 0xe1, 0x19, 0xa3, 0x3e, 0x1b, + 0x38, 0xac, 0x10, 0x85, 0x36, 0xec, 0xa8, 0x54, 0xa2, 0x85, 0xa1, 0x54, 0x7f, 0x09, 0x15, 0x47, 0xdc, 0x99, 0x51, + 0x96, 0x8c, 0x4f, 0xcb, 0x43, 0x31, 0x1d, 0x0c, 0x4a, 0x52, 0x19, 0x0b, 0x3d, 0xb8, 0x1e, 0x78, 0xfe, 0x3d, 0x70, + 0x0b, 0xf1, 0xe0, 0x90, 0xc5, 0x90, 0x1b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8d, 0x4a, 0x15, 0xbc, 0x9a, 0xa8, 0x16, + 0xfc, 0x54, 0x86, 0x01, 0xfa, 0x24, 0x05, 0x60, 0x32, 0x98, 0xf2, 0x5b, 0x90, 0x28, 0x9d, 0xa9, 0x1b, 0xd2, 0xaf, + 0xa2, 0xe0, 0x17, 0xbc, 0xe0, 0x22, 0x71, 0x05, 0x58, 0xde, 0xc1, 0xf6, 0x3a, 0xaa, 0xa8, 0x02, 0xe2, 0x35, 0x3d, + 0x8e, 0xb8, 0xf1, 0xfe, 0x33, 0x3d, 0xb6, 0x40, 0xad, 0xd6, 0xb1, 0xc1, 0x67, 0x8e, 0xc1, 0x05, 0x5d, 0x4b, 0x6c, + 0x0d, 0xd5, 0xb0, 0x22, 0x30, 0x70, 0x01, 0x07, 0x61, 0x89, 0xe2, 0xd8, 0x4a, 0x5e, 0x91, 0x86, 0x94, 0xf6, 0x81, + 0xe1, 0x68, 0x93, 0x1c, 0xdf, 0x66, 0xd9, 0x4d, 0xe0, 0x7c, 0xd1, 0x39, 0x69, 0x26, 0x96, 0x0d, 0xde, 0xe7, 0xcd, + 0xf9, 0x75, 0xff, 0x90, 0x50, 0x15, 0xec, 0x86, 0xb7, 0x83, 0xdd, 0x38, 0xe1, 0xd7, 0x5c, 0x2c, 0x74, 0x7c, 0x16, + 0x73, 0xc9, 0xf2, 0x5b, 0xeb, 0xdd, 0x92, 0xa4, 0x56, 0x40, 0xfb, 0x2c, 0x0b, 0x6a, 0x22, 0x00, 0xdd, 0x0f, 0x7f, + 0x81, 0xd0, 0x19, 0xfe, 0xf6, 0x18, 0x5c, 0x91, 0xc2, 0x7b, 0x87, 0x40, 0x58, 0xd3, 0xcd, 0x9d, 0xda, 0x80, 0x2f, + 0xc6, 0xfd, 0x19, 0x53, 0x4f, 0xbf, 0xcd, 0xe4, 0xae, 0xae, 0xdb, 0x23, 0xcb, 0xf0, 0x11, 0xae, 0x14, 0x00, 0xcb, + 0x84, 0xbf, 0x18, 0x5b, 0x52, 0x7d, 0x02, 0x70, 0x6a, 0x3a, 0xa2, 0x4f, 0x10, 0x18, 0x38, 0x25, 0x5a, 0x8c, 0xae, + 0x95, 0x23, 0x9a, 0x41, 0x5a, 0xd3, 0xad, 0x30, 0xde, 0x7a, 0xd0, 0x42, 0xcf, 0x34, 0x9c, 0xf8, 0x0f, 0x9a, 0x79, + 0x55, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0xd1, 0x1c, 0x21, 0x3e, 0x61, 0x49, 0x34, 0x61, 0xf1, 0x4c, 0xf1, + 0x63, 0x42, 0x37, 0x4d, 0x6d, 0xd3, 0x07, 0xa4, 0xbf, 0xb8, 0x66, 0xfd, 0x94, 0x65, 0xed, 0xdb, 0x43, 0xc5, 0x8b, + 0x69, 0x33, 0xf8, 0x61, 0xa2, 0x8a, 0xf1, 0xbf, 0xa8, 0x7c, 0xa9, 0x15, 0xc0, 0x30, 0x77, 0xd5, 0xd3, 0xef, 0x37, + 0xb3, 0xe5, 0x40, 0xa8, 0xfc, 0xce, 0x20, 0xe9, 0xd3, 0xf1, 0xfc, 0xc0, 0x26, 0x51, 0x5b, 0xe8, 0xf9, 0xe3, 0x52, + 0x37, 0xa1, 0xf2, 0xda, 0xd4, 0x88, 0x56, 0xc8, 0x50, 0xd9, 0x3a, 0x60, 0x7d, 0xff, 0x10, 0xee, 0x2e, 0x6a, 0x1a, + 0x6a, 0xdd, 0x73, 0xd7, 0xa2, 0xe0, 0xc4, 0x1f, 0x60, 0x2c, 0x2e, 0x24, 0xb5, 0x0e, 0xc2, 0xa4, 0x1f, 0x2d, 0x4e, + 0x72, 0xa3, 0xae, 0x4e, 0xce, 0x14, 0xf3, 0x04, 0x2e, 0xaa, 0x65, 0xdb, 0x5f, 0x51, 0xa9, 0x4b, 0xb9, 0xbd, 0xa2, + 0x34, 0x3d, 0xa4, 0xed, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x0b, 0x05, 0x17, 0xd6, 0xc1, 0xba, 0xe3, 0x4e, 0xd9, + 0x13, 0x9e, 0x28, 0xd3, 0xda, 0xe0, 0xae, 0x1b, 0x8c, 0x89, 0xb1, 0xdf, 0x5d, 0xf2, 0xe4, 0x23, 0xb2, 0xe0, 0xdf, + 0x65, 0x02, 0x3c, 0x93, 0xdd, 0x2b, 0x95, 0xff, 0x07, 0xff, 0x6a, 0x6b, 0xdf, 0x59, 0xf3, 0x4f, 0xcf, 0x7a, 0xb8, + 0x73, 0x98, 0xfc, 0x00, 0x9d, 0x01, 0xdd, 0x5c, 0xc9, 0x94, 0x03, 0x32, 0x80, 0xb5, 0x48, 0x46, 0x03, 0x3e, 0xb4, + 0xb2, 0x6c, 0xfb, 0x4e, 0xab, 0x0b, 0xc2, 0xbd, 0x04, 0x6e, 0x7a, 0x7f, 0x6d, 0x66, 0xe6, 0x74, 0xad, 0x44, 0xd3, + 0xa5, 0xb1, 0xb5, 0x2c, 0x55, 0xc0, 0xee, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x70, 0x39, 0xcd, 0x2d, 0x75, 0xdb, 0xb8, + 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0xb5, 0x22, 0xf4, 0x54, 0x89, 0xd0, + 0xa7, 0x69, 0xb3, 0x0f, 0x76, 0x55, 0xad, 0x1b, 0x71, 0x8e, 0x06, 0xa9, 0x66, 0xe4, 0x4f, 0xae, 0x79, 0x71, 0x91, + 0xcb, 0x1b, 0xc0, 0x40, 0x26, 0xb5, 0x51, 0x58, 0x5e, 0x81, 0x3b, 0x3f, 0x3a, 0x8e, 0x33, 0x31, 0xca, 0x31, 0x58, + 0x2b, 0xc2, 0x23, 0xeb, 0xc4, 0x19, 0x80, 0x20, 0xfb, 0x93, 0xa6, 0xe3, 0xb9, 0x16, 0x18, 0xd3, 0x17, 0xb8, 0xab, + 0x9c, 0x1d, 0x6d, 0x72, 0xbb, 0xe8, 0x9b, 0x33, 0xac, 0x3b, 0x52, 0x5a, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, 0x06, + 0x6d, 0x11, 0x4a, 0x3e, 0xe4, 0x4e, 0xda, 0x4f, 0x01, 0x0d, 0xce, 0xb2, 0xf4, 0xd6, 0x5a, 0xe5, 0x6f, 0xb4, 0x10, + 0x27, 0x8a, 0xa9, 0x13, 0xdf, 0x44, 0x89, 0x3e, 0x3f, 0x13, 0xe3, 0x06, 0x02, 0xa9, 0x3f, 0x60, 0x50, 0x8d, 0x22, + 0x4c, 0xe0, 0x3a, 0x10, 0xc5, 0xf6, 0x44, 0x6d, 0x2c, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x41, 0x19, 0xc6, 0xea, 0xe2, + 0x40, 0x1b, 0x2c, 0x7d, 0xdd, 0x5a, 0xe7, 0x86, 0x50, 0x18, 0x27, 0x30, 0xc5, 0x20, 0xa9, 0xb3, 0xce, 0x32, 0x41, + 0x95, 0x1d, 0x93, 0xce, 0xfb, 0x00, 0xdd, 0x5d, 0x8b, 0xa6, 0xf8, 0xba, 0x73, 0x07, 0xdd, 0xc7, 0xf5, 0x6b, 0x2d, + 0x72, 0x83, 0x3f, 0x6f, 0x89, 0xb0, 0x08, 0x9c, 0xb5, 0x26, 0x5f, 0x35, 0xc2, 0x81, 0x29, 0xc9, 0x34, 0xec, 0x25, + 0xca, 0xa6, 0x7b, 0xbb, 0xed, 0xf5, 0xee, 0x15, 0x71, 0xf5, 0x18, 0xab, 0xbc, 0x9b, 0xb9, 0xbd, 0x53, 0xad, 0xc5, + 0xee, 0x4d, 0xdb, 0x4f, 0xb1, 0xa3, 0xd6, 0xda, 0xed, 0x86, 0x13, 0x6a, 0xc8, 0xb7, 0xa2, 0x4a, 0xab, 0xd3, 0x8d, + 0x41, 0x3b, 0xc4, 0xb3, 0x16, 0x19, 0xdc, 0x28, 0x5f, 0x38, 0xa1, 0x93, 0x8a, 0xb3, 0xea, 0xd4, 0x05, 0x9b, 0x2b, + 0x5e, 0x2d, 0x65, 0x1a, 0x09, 0x8a, 0x36, 0xe7, 0x51, 0x49, 0x13, 0xb9, 0x16, 0x55, 0x24, 0x6b, 0xd4, 0x8b, 0x5a, + 0x8d, 0x01, 0x02, 0x32, 0x9d, 0x35, 0x3d, 0xa8, 0x82, 0xd9, 0x50, 0x46, 0x72, 0xfa, 0x1e, 0x2c, 0xed, 0x91, 0x63, + 0xad, 0xef, 0xab, 0xb3, 0xc5, 0xb7, 0x7a, 0x42, 0x30, 0x85, 0xd9, 0x03, 0x61, 0xe0, 0x9a, 0xc6, 0x90, 0xd3, 0x2e, + 0x71, 0x59, 0xd3, 0x2d, 0xe1, 0x1e, 0x6e, 0x57, 0xb2, 0x23, 0x37, 0x4f, 0x9a, 0x9b, 0x2b, 0xd8, 0x51, 0x31, 0x1f, + 0x83, 0xf6, 0x4b, 0xaa, 0x6b, 0x97, 0xe6, 0xd6, 0xe3, 0x41, 0x40, 0x83, 0x41, 0x61, 0xf8, 0xd7, 0x89, 0xf1, 0xf0, + 0xa4, 0x01, 0x41, 0x52, 0x2e, 0xc2, 0xb1, 0x6f, 0x44, 0x3f, 0x99, 0xca, 0x43, 0x8e, 0x16, 0xef, 0xd0, 0xea, 0x04, + 0xa2, 0x78, 0x89, 0x50, 0x12, 0xa3, 0x2a, 0x34, 0x22, 0x28, 0x4f, 0xcb, 0x5f, 0xaa, 0xea, 0x10, 0x50, 0x48, 0xfb, + 0x8a, 0x42, 0xd9, 0x26, 0x31, 0x34, 0xc3, 0x2f, 0xe7, 0x93, 0x85, 0x9e, 0x81, 0x81, 0x9c, 0x1f, 0x2c, 0xf4, 0x2c, + 0x0c, 0xe4, 0xfc, 0xc9, 0xa2, 0x76, 0xeb, 0x40, 0x13, 0x10, 0xcf, 0x85, 0xa3, 0x93, 0xd2, 0xaa, 0x6c, 0x01, 0xdd, + 0x3c, 0x44, 0xd0, 0x7f, 0xb2, 0x87, 0xa0, 0x93, 0x0b, 0xed, 0xc8, 0x0d, 0x68, 0x3b, 0x0e, 0x81, 0xbd, 0x62, 0x52, + 0x61, 0x02, 0x10, 0x1d, 0xb2, 0x31, 0x18, 0x62, 0xab, 0x0f, 0x0e, 0xd9, 0x78, 0xea, 0x93, 0x20, 0x60, 0x74, 0x7f, + 0x30, 0x90, 0xe0, 0xb7, 0x78, 0x95, 0x3e, 0xda, 0x08, 0x74, 0xd3, 0x77, 0x77, 0x43, 0xef, 0xe2, 0x0a, 0x4e, 0xd5, + 0xee, 0x9e, 0x84, 0x6e, 0x32, 0xed, 0x00, 0xbd, 0x86, 0xb8, 0x21, 0xbf, 0x32, 0x1a, 0x8d, 0x6c, 0x4a, 0x48, 0x88, + 0xe1, 0x1c, 0x9a, 0x39, 0x2d, 0x97, 0xaf, 0x6e, 0x3d, 0x1b, 0x90, 0x61, 0xa6, 0xb7, 0x4c, 0xd6, 0x0f, 0x50, 0x56, + 0x3d, 0x86, 0x76, 0xe8, 0x3d, 0x72, 0xfc, 0xf0, 0xe0, 0x9b, 0x8c, 0x9f, 0x39, 0x5c, 0x7b, 0x38, 0x17, 0xbe, 0xcb, + 0x9a, 0x91, 0x39, 0x74, 0x9e, 0x7d, 0x1c, 0xef, 0x61, 0x9c, 0x7c, 0x9e, 0x85, 0xf2, 0xc6, 0x6b, 0xfa, 0x1f, 0x95, + 0xde, 0xec, 0x70, 0xc8, 0xe9, 0x0a, 0x56, 0xdc, 0xac, 0x0a, 0x0d, 0x3f, 0x8b, 0xbc, 0x71, 0xc4, 0x6b, 0x12, 0x55, + 0xdd, 0xe7, 0xbd, 0x0d, 0x53, 0xda, 0x31, 0x0e, 0x00, 0x4e, 0xd4, 0xaa, 0x61, 0x57, 0x1a, 0xd7, 0xea, 0x20, 0x86, + 0xa1, 0x84, 0xad, 0x12, 0x47, 0x42, 0xf9, 0x1b, 0x80, 0xb0, 0x18, 0x8a, 0xe3, 0xad, 0x61, 0x7d, 0x80, 0xfd, 0xd0, + 0x05, 0x9a, 0xe6, 0x94, 0x6a, 0x06, 0x00, 0x49, 0xc0, 0x1f, 0x3d, 0xdd, 0x34, 0x54, 0xb6, 0x79, 0x1e, 0x5a, 0x56, + 0x57, 0xf0, 0x40, 0x4f, 0x5d, 0xc9, 0xc0, 0xb8, 0xaa, 0x63, 0x6f, 0x73, 0x7f, 0x7b, 0xb4, 0x8a, 0x7c, 0x67, 0x93, + 0xda, 0x66, 0x55, 0x68, 0xec, 0xe3, 0x09, 0x3d, 0x9d, 0x00, 0xad, 0xd7, 0x96, 0x8a, 0xf6, 0xfb, 0x28, 0x46, 0x8d, + 0x0b, 0x05, 0x56, 0x61, 0x22, 0xc1, 0x21, 0xc2, 0x08, 0xa1, 0xdf, 0x97, 0xe1, 0xc6, 0x17, 0x64, 0x10, 0x0d, 0xd7, + 0xa2, 0xe3, 0x0f, 0x39, 0x5e, 0xb4, 0x2d, 0x55, 0x35, 0x27, 0x4d, 0x5b, 0x02, 0x6f, 0xc2, 0x01, 0xb6, 0xf3, 0x4f, + 0x1b, 0x22, 0x57, 0xe1, 0xa2, 0x84, 0xef, 0x88, 0x6b, 0x41, 0x74, 0x53, 0x9b, 0x7a, 0x1b, 0x76, 0x88, 0x8e, 0xa6, + 0x78, 0x74, 0xc8, 0x3d, 0x77, 0xcf, 0x6d, 0x11, 0xdf, 0x7c, 0x86, 0xdc, 0x35, 0x9d, 0xbd, 0x14, 0x61, 0x50, 0xb7, + 0x6c, 0xa0, 0x58, 0x87, 0x4e, 0x50, 0x80, 0x51, 0x5b, 0x3e, 0x01, 0x1d, 0x1b, 0x0c, 0x2a, 0x82, 0x4f, 0x0a, 0xdb, + 0xa6, 0x41, 0xfe, 0x88, 0x77, 0x43, 0x87, 0xd7, 0x96, 0x3c, 0x10, 0xaf, 0xb0, 0xcf, 0x94, 0x70, 0xff, 0x82, 0x82, + 0xee, 0x28, 0x2f, 0x57, 0x85, 0xab, 0xd2, 0x00, 0x54, 0xd9, 0xf1, 0x5c, 0x6b, 0x4a, 0x5a, 0xc0, 0x4a, 0x49, 0xdd, + 0xf9, 0x4d, 0x44, 0xdc, 0x92, 0xa9, 0x98, 0xad, 0xba, 0x51, 0xe5, 0xa1, 0x44, 0x91, 0x8e, 0x3d, 0xdb, 0x39, 0x58, + 0x03, 0xe0, 0x29, 0x6c, 0x2f, 0xce, 0xb0, 0xa0, 0x8c, 0xcb, 0x96, 0xb9, 0x04, 0x8a, 0xfa, 0x61, 0x9c, 0x97, 0x1d, + 0x5f, 0xee, 0x8e, 0xb6, 0xf7, 0xd0, 0x1b, 0xb1, 0x31, 0x5e, 0x5f, 0x46, 0x4d, 0xbf, 0x78, 0x86, 0x2b, 0x4b, 0x41, + 0x1e, 0x68, 0xaa, 0x47, 0x18, 0x1d, 0x02, 0xd3, 0x94, 0x1f, 0xb1, 0xf1, 0x74, 0x38, 0x34, 0x64, 0xd0, 0x6b, 0x26, + 0xc6, 0xff, 0xfa, 0x02, 0x5a, 0x67, 0x26, 0xae, 0xf1, 0x69, 0xfb, 0x0a, 0x5a, 0xdd, 0xa2, 0x4c, 0xee, 0x0c, 0x0c, + 0x1f, 0x68, 0xc9, 0x14, 0x4c, 0x15, 0xde, 0x10, 0xa9, 0x64, 0x9f, 0x96, 0xd6, 0x61, 0xdf, 0x2e, 0x14, 0x5a, 0x68, + 0xe2, 0x57, 0x19, 0xe2, 0xa7, 0xae, 0x33, 0xff, 0x36, 0xed, 0x53, 0x83, 0x58, 0x58, 0x12, 0xa3, 0x10, 0xbf, 0x38, + 0x55, 0xb6, 0x13, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x55, 0xec, 0x49, 0xa1, 0xf1, 0xd4, 0x70, 0xdf, + 0x0b, 0x1d, 0xb3, 0x0e, 0xb3, 0xb8, 0xcd, 0x1a, 0x49, 0x8d, 0x71, 0x2a, 0x4c, 0x70, 0x4a, 0xb9, 0x8a, 0x04, 0x46, + 0xc7, 0xb3, 0x85, 0x41, 0x54, 0x49, 0x4c, 0x32, 0xb6, 0x16, 0xc2, 0xc4, 0xae, 0x73, 0x85, 0x69, 0xea, 0x22, 0xf5, + 0x9b, 0x81, 0xc9, 0x82, 0x86, 0xfc, 0x1e, 0x8d, 0xd6, 0x54, 0x4d, 0x01, 0x86, 0x71, 0x94, 0x6a, 0xfc, 0x5b, 0x84, + 0xda, 0x0c, 0x03, 0x00, 0xdb, 0xbc, 0x93, 0x99, 0xa8, 0x5e, 0x0b, 0x84, 0x40, 0x73, 0xf6, 0x53, 0x45, 0xb5, 0x33, + 0x0b, 0x46, 0xd1, 0x6e, 0xaf, 0x7c, 0x3e, 0x70, 0x42, 0x79, 0xac, 0x2e, 0x50, 0xaf, 0x64, 0xf1, 0x46, 0xa6, 0xbc, + 0x15, 0x17, 0x73, 0x4f, 0xb2, 0x0f, 0xf9, 0x08, 0xce, 0x2b, 0x74, 0x2a, 0x37, 0xdb, 0x44, 0x99, 0x25, 0x49, 0xc6, + 0x02, 0x63, 0xf3, 0x12, 0xcc, 0xa4, 0x66, 0xc6, 0xf0, 0x6b, 0x08, 0x2e, 0xb6, 0x73, 0x12, 0x6e, 0xee, 0xe7, 0x81, + 0x21, 0x34, 0xb9, 0x68, 0x89, 0x86, 0xad, 0x1d, 0xaf, 0x27, 0xd7, 0x84, 0xfb, 0xb0, 0x11, 0x6b, 0x32, 0xc6, 0xb8, + 0x36, 0x37, 0xb2, 0x7e, 0xb4, 0xc0, 0x83, 0x31, 0x65, 0xfd, 0x09, 0x64, 0x5a, 0x49, 0x59, 0xe7, 0x0b, 0x23, 0x66, + 0x52, 0x89, 0xde, 0xed, 0x1b, 0x9f, 0xd5, 0x5d, 0x44, 0xfd, 0xd6, 0x7e, 0x4f, 0xea, 0xe1, 0xce, 0x7f, 0x50, 0x58, + 0x83, 0xca, 0x88, 0xcb, 0x88, 0xf2, 0xcc, 0x81, 0x6e, 0x9a, 0x14, 0x71, 0x7a, 0xb6, 0x8a, 0x8b, 0x92, 0xa7, 0x50, + 0xa9, 0xa6, 0x6e, 0x51, 0x6f, 0x02, 0xf6, 0x86, 0x48, 0x92, 0xac, 0xa5, 0xb1, 0x15, 0xbb, 0x34, 0x48, 0xcf, 0xbd, + 0x61, 0x96, 0x5e, 0x55, 0x68, 0x48, 0x4b, 0xbd, 0xb3, 0x50, 0xc9, 0xfc, 0x15, 0xff, 0x19, 0xd4, 0x0a, 0x74, 0xb4, + 0x49, 0x31, 0x9e, 0x03, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x09, 0x4a, 0xbd, 0x23, 0x76, 0xfc, 0xdc, + 0xe4, 0xe1, 0x5d, 0xc8, 0x39, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0x48, 0x8c, 0xd4, 0x0c, 0xa0, 0xe9, 0xa0, + 0xcc, 0x79, 0x2c, 0x82, 0x59, 0xcf, 0x24, 0x46, 0x3d, 0xae, 0x7f, 0x81, 0x86, 0xda, 0x6f, 0x56, 0x96, 0x67, 0xd5, + 0xdd, 0x97, 0x70, 0x60, 0x53, 0x5b, 0x41, 0x8f, 0xd7, 0x95, 0xbc, 0xbc, 0x54, 0xdd, 0xf6, 0x0b, 0x31, 0x72, 0xba, + 0xc6, 0xb5, 0x74, 0x5e, 0x2d, 0x58, 0xaf, 0x3b, 0xdd, 0x2c, 0xee, 0x66, 0x19, 0x0d, 0x84, 0xb5, 0x9d, 0x4f, 0x34, + 0x7f, 0xd6, 0x6c, 0xbb, 0x8f, 0xb7, 0x20, 0x66, 0x01, 0x00, 0xa4, 0x07, 0x51, 0xb0, 0xcc, 0x52, 0x1e, 0x50, 0x79, + 0x1f, 0x47, 0x59, 0x28, 0xbd, 0x9c, 0x65, 0xfc, 0xb4, 0x69, 0xac, 0x75, 0x56, 0x28, 0x43, 0x6b, 0xa3, 0x3b, 0x5d, + 0x65, 0x88, 0xed, 0x27, 0x71, 0xb6, 0x00, 0xf7, 0xc7, 0x0c, 0x85, 0x86, 0xce, 0x32, 0xd2, 0x44, 0xc3, 0x77, 0xdd, + 0x33, 0xc8, 0x28, 0x4e, 0xd6, 0x79, 0x25, 0xdd, 0xe8, 0xb3, 0x36, 0x12, 0xe6, 0x1e, 0xa2, 0x5f, 0xc5, 0xe0, 0x51, + 0xee, 0xf3, 0xda, 0xe8, 0x64, 0x5a, 0x46, 0xda, 0x9d, 0x9f, 0xd4, 0xcb, 0x2c, 0xd5, 0x3a, 0x6c, 0x9f, 0x61, 0x6f, + 0x8d, 0x49, 0x6f, 0x42, 0x6a, 0x18, 0x89, 0xcf, 0x67, 0xd4, 0x08, 0x01, 0x6d, 0x39, 0xfe, 0x0e, 0x9f, 0x61, 0x68, + 0x0a, 0x2c, 0x55, 0xdc, 0xc2, 0x6e, 0xf8, 0x9a, 0x4f, 0x56, 0x2d, 0x00, 0x11, 0xac, 0x7c, 0xbd, 0x8b, 0x57, 0x42, + 0x7d, 0xa6, 0xcd, 0x00, 0x90, 0x05, 0xa5, 0xdc, 0xf1, 0x53, 0x2a, 0x1d, 0x2c, 0x51, 0xb4, 0xbd, 0x9c, 0xbe, 0xd1, + 0xb1, 0xf1, 0x43, 0x7a, 0x2e, 0x60, 0xbb, 0x90, 0xdf, 0xba, 0x57, 0x2f, 0x51, 0x91, 0xda, 0x36, 0xeb, 0x01, 0xbe, + 0xdc, 0xa0, 0x49, 0x18, 0x41, 0x99, 0x32, 0x05, 0x30, 0xb8, 0xa9, 0x46, 0xc1, 0xa4, 0xd5, 0x48, 0xd8, 0x52, 0x4f, + 0xb2, 0xdc, 0xf4, 0xc1, 0xa9, 0xee, 0x11, 0xf4, 0x68, 0x87, 0x93, 0x96, 0xfd, 0x5a, 0xc1, 0xd1, 0xc9, 0xd5, 0x10, + 0x35, 0xf3, 0x5e, 0xdb, 0x91, 0x21, 0xe5, 0x32, 0x0c, 0x04, 0x53, 0x8e, 0x79, 0x7a, 0x6c, 0x3d, 0x23, 0xa2, 0x07, + 0xce, 0x3e, 0xd3, 0xad, 0xba, 0x92, 0x80, 0xe8, 0xf8, 0xcd, 0xd3, 0xd7, 0x57, 0xf1, 0xa5, 0x41, 0x51, 0x6a, 0x58, + 0xc4, 0x28, 0xd3, 0xbe, 0x4a, 0xc2, 0xe0, 0xfd, 0xfa, 0xfe, 0x67, 0x95, 0xa5, 0xf6, 0x7b, 0xb0, 0xb1, 0xa2, 0xaa, + 0x5f, 0x4b, 0x5e, 0x34, 0x05, 0x58, 0xf7, 0x59, 0xa2, 0x40, 0xee, 0xf7, 0x36, 0xcd, 0x7c, 0x13, 0x35, 0x6e, 0x36, + 0xac, 0x37, 0xae, 0xdb, 0xa5, 0xb6, 0x64, 0x47, 0x56, 0x22, 0x67, 0x16, 0x83, 0x19, 0x3f, 0x2a, 0x0c, 0x4a, 0xc3, + 0x06, 0x55, 0xa9, 0xf8, 0xbd, 0x11, 0xc1, 0xa9, 0x63, 0x55, 0x61, 0x4c, 0x03, 0x66, 0x5b, 0x51, 0x6b, 0x50, 0x07, + 0xa5, 0xb4, 0x35, 0x51, 0xd8, 0x7e, 0x67, 0x05, 0x35, 0xbf, 0xff, 0x69, 0x0c, 0xf9, 0x9a, 0x52, 0x50, 0x49, 0xc0, + 0xce, 0xa0, 0xd1, 0x53, 0x25, 0x0c, 0xa4, 0x20, 0x78, 0x02, 0x94, 0x2f, 0xa2, 0xc6, 0x6a, 0xb7, 0xaf, 0x4e, 0x8d, + 0xd1, 0x16, 0x10, 0x5a, 0x48, 0x8f, 0x2e, 0xfb, 0xb8, 0x8d, 0x75, 0x20, 0xf1, 0xe0, 0x04, 0xdb, 0xb9, 0xba, 0x46, + 0x23, 0xa1, 0xf9, 0x43, 0xa3, 0x01, 0xaf, 0x69, 0x05, 0x0a, 0xf5, 0x1c, 0x47, 0x43, 0x67, 0x87, 0x14, 0x44, 0x6c, + 0xd0, 0xc2, 0xbe, 0x7b, 0x3e, 0x34, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x4d, 0xa5, 0xfb, 0xdc, 0x2d, 0x21, 0x6b, 0xd5, + 0xa1, 0xac, 0x3c, 0xc0, 0xf1, 0x42, 0xc9, 0xfc, 0x1d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x63, 0xc4, 0x02, 0x96, 0x04, + 0xed, 0xf5, 0x40, 0xfd, 0x32, 0x08, 0x15, 0xce, 0xf4, 0x44, 0xe2, 0x53, 0xca, 0xd5, 0xa7, 0x05, 0xa9, 0xa7, 0x05, + 0x73, 0xa0, 0x97, 0xbe, 0x95, 0x5f, 0xd9, 0xf8, 0x68, 0x77, 0xef, 0x9a, 0x0b, 0xeb, 0x18, 0x82, 0x61, 0x0b, 0xbf, + 0x39, 0x35, 0x05, 0x60, 0xc3, 0x63, 0x5d, 0x96, 0x6f, 0xd4, 0x44, 0x66, 0x71, 0x48, 0x22, 0x90, 0x6c, 0x37, 0x37, + 0xb7, 0x11, 0x6c, 0x7b, 0x0b, 0xb5, 0xa1, 0xfe, 0xf2, 0xb6, 0xfb, 0x3d, 0xc3, 0xcb, 0x3d, 0xb9, 0x77, 0xd3, 0x86, + 0xf2, 0x87, 0xfb, 0x57, 0xc9, 0xff, 0x55, 0x25, 0xf7, 0x5b, 0x65, 0xd6, 0x6d, 0xf1, 0x7e, 0xd7, 0x71, 0xcb, 0x31, + 0x1a, 0x04, 0xd6, 0x14, 0x18, 0x48, 0x4f, 0x1a, 0xd3, 0x44, 0x87, 0x54, 0x66, 0xcc, 0xe0, 0xd1, 0x05, 0x68, 0x0e, + 0xd3, 0x79, 0x1e, 0x03, 0x70, 0x80, 0x7f, 0xe4, 0x11, 0xea, 0x9f, 0xce, 0xf3, 0xe0, 0x2c, 0x18, 0x94, 0x83, 0x40, + 0x7f, 0xe2, 0x9a, 0x13, 0x2c, 0x40, 0xe7, 0x16, 0x33, 0x08, 0x36, 0x69, 0xcd, 0x1c, 0xe2, 0xc3, 0x64, 0x3a, 0x18, + 0xc4, 0x64, 0x03, 0x20, 0x7d, 0xf1, 0xc2, 0x3a, 0x07, 0x15, 0x7a, 0x41, 0xb6, 0xea, 0x2e, 0x9a, 0x15, 0x7b, 0xd5, + 0x4e, 0xf3, 0x7e, 0x3f, 0x9f, 0x97, 0x83, 0xa0, 0x51, 0x61, 0x61, 0xbc, 0xff, 0x68, 0xf3, 0x4b, 0xa3, 0x93, 0x26, + 0x18, 0xa6, 0xf6, 0x18, 0xd5, 0x2b, 0x9e, 0x66, 0xb4, 0x71, 0x3b, 0x56, 0xca, 0x17, 0x10, 0xc5, 0x03, 0x43, 0xd6, + 0xca, 0xbb, 0x73, 0xf0, 0xba, 0xdc, 0x78, 0x73, 0x44, 0x01, 0x76, 0x53, 0x18, 0x27, 0x35, 0x17, 0x5d, 0xd4, 0xc4, + 0x33, 0xd8, 0xe9, 0xea, 0xad, 0x44, 0xab, 0xf1, 0x5e, 0xbc, 0x6b, 0x36, 0xfe, 0x56, 0xee, 0xe9, 0x32, 0xf7, 0x2e, + 0x00, 0x71, 0x76, 0x2f, 0xae, 0xf6, 0xb0, 0xd4, 0xbd, 0x60, 0x60, 0x91, 0x43, 0xda, 0xd5, 0xea, 0xa1, 0x88, 0xd4, + 0x79, 0x0c, 0x06, 0x4c, 0xa6, 0x21, 0x35, 0x99, 0xf6, 0x0a, 0x05, 0x69, 0x63, 0xad, 0x05, 0xb4, 0xe1, 0xb0, 0xd8, + 0xb1, 0x1b, 0x76, 0xa7, 0x5b, 0x87, 0x42, 0x09, 0xa3, 0x57, 0xd7, 0xcd, 0x43, 0xad, 0xe1, 0x89, 0xa0, 0x07, 0xd5, + 0x68, 0x3f, 0x3d, 0x94, 0x27, 0xed, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0x52, 0xe0, 0x45, 0x7b, 0x07, 0x79, 0xce, + 0x7c, 0xaa, 0x7c, 0x10, 0x1b, 0x6e, 0x19, 0x3e, 0xb4, 0x8f, 0x6f, 0x05, 0x32, 0xa9, 0x3b, 0x9a, 0xda, 0xda, 0x1d, + 0x8d, 0x63, 0x02, 0xfd, 0xa6, 0x1c, 0xa5, 0x4c, 0x4c, 0x2d, 0x4b, 0x76, 0xd4, 0xcb, 0x95, 0x37, 0x54, 0xca, 0x8e, + 0x96, 0x6d, 0xce, 0x2f, 0x6d, 0x24, 0xf4, 0xfb, 0xda, 0x1d, 0x08, 0xdf, 0xa8, 0xf5, 0x86, 0xbc, 0x6c, 0x88, 0x58, + 0x0e, 0x31, 0x03, 0xc7, 0x0b, 0xa9, 0x5c, 0xbb, 0x8b, 0xa6, 0xaa, 0x6e, 0x67, 0x2b, 0x17, 0xb4, 0xc4, 0x5b, 0x29, + 0xb0, 0x8a, 0xd4, 0xe9, 0xf5, 0x54, 0xe2, 0x7d, 0x1f, 0xc5, 0xf6, 0x23, 0x60, 0x1b, 0x1b, 0x47, 0x63, 0xe3, 0x16, + 0xb1, 0xc1, 0x57, 0x51, 0x45, 0x0b, 0x0e, 0x10, 0xdc, 0x6d, 0x49, 0x2d, 0xcd, 0x1c, 0xe2, 0xbe, 0xe2, 0x01, 0xda, + 0x77, 0x71, 0xc4, 0xa9, 0x00, 0xdb, 0xba, 0xd6, 0x39, 0xab, 0xe5, 0x80, 0xcd, 0x44, 0xcf, 0x3f, 0xad, 0x1a, 0x89, + 0x18, 0x56, 0xd9, 0x48, 0x59, 0xa1, 0x3d, 0x28, 0x5d, 0xc2, 0xc5, 0x17, 0xe0, 0x65, 0xfb, 0x7e, 0x65, 0xf7, 0xd9, + 0x12, 0xfb, 0x87, 0x79, 0xd5, 0x04, 0x8f, 0xbc, 0xc6, 0xdb, 0x7b, 0x98, 0xf8, 0x52, 0x29, 0x84, 0x57, 0x29, 0x0d, + 0x25, 0x00, 0x83, 0x24, 0xa8, 0xe1, 0x4a, 0xdb, 0x66, 0x90, 0xca, 0x18, 0x76, 0xb7, 0x7a, 0xab, 0xff, 0xd3, 0x2a, + 0x5c, 0x54, 0xb2, 0x18, 0x93, 0x40, 0xe7, 0x54, 0xcb, 0x4d, 0x4c, 0xc1, 0xb3, 0x5d, 0x72, 0x04, 0x0a, 0x3b, 0x01, + 0xdc, 0x50, 0xc2, 0x7e, 0xc5, 0xdb, 0x50, 0xce, 0x5e, 0x59, 0xc9, 0x93, 0xdb, 0x97, 0x54, 0xd0, 0x84, 0x4c, 0x85, + 0xdd, 0xbf, 0xad, 0x0d, 0xfb, 0x22, 0x94, 0x23, 0x29, 0x70, 0x71, 0xd0, 0x39, 0x80, 0xfd, 0x41, 0x2e, 0x63, 0xf3, + 0x99, 0xf4, 0xfb, 0xea, 0xfd, 0xf3, 0x3c, 0x4b, 0x3e, 0xee, 0xbc, 0x37, 0x3c, 0xcd, 0x92, 0x01, 0x95, 0x88, 0xa9, + 0x75, 0x55, 0x0c, 0x97, 0xda, 0xc5, 0xb8, 0x41, 0x32, 0xe2, 0x7b, 0xa9, 0x43, 0x8c, 0x18, 0x5f, 0x64, 0x87, 0xa4, + 0xe4, 0x74, 0x59, 0x77, 0xf6, 0x5c, 0x8b, 0x66, 0xd0, 0x18, 0x6e, 0xc7, 0x7b, 0x49, 0xaf, 0x00, 0x15, 0x15, 0xba, + 0x67, 0x81, 0x6b, 0x78, 0x73, 0x49, 0x34, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xb8, 0x57, 0x26, 0x24, 0xd5, 0xc6, 0x01, + 0x16, 0xb1, 0xae, 0x3f, 0x86, 0x12, 0x80, 0x5a, 0x0d, 0xd2, 0x2b, 0x7d, 0x45, 0xa8, 0x4a, 0x42, 0x30, 0x3a, 0x91, + 0xf0, 0x32, 0xa0, 0x71, 0x66, 0x12, 0x2d, 0x6c, 0x70, 0x40, 0x5f, 0x54, 0x26, 0xd1, 0xd8, 0x90, 0x07, 0xb4, 0xb2, + 0x69, 0x00, 0x83, 0x0f, 0x92, 0x24, 0xfa, 0x7a, 0x69, 0x92, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x4b, 0xe9, 0xf9, + 0x58, 0xfe, 0xcb, 0x3b, 0x94, 0x7e, 0x08, 0x25, 0xc8, 0x14, 0x75, 0xc5, 0x34, 0x63, 0x47, 0x59, 0xb7, 0x31, 0x89, + 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x79, 0xbc, 0x62, 0xc7, 0x21, 0xd7, + 0x78, 0xe9, 0xcf, 0xe3, 0x15, 0xce, 0x10, 0xad, 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, + 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x4e, 0x92, 0xf9, 0xf2, + 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, + 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x5a, + 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1b, 0x50, 0x22, 0xa3, 0xb2, + 0xe2, 0xab, 0x15, 0x4f, 0x67, 0xb7, 0x49, 0x94, 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0x59, 0x9f, 0x67, + 0xc9, 0x6b, 0x88, 0x3d, 0xb0, 0x92, 0x0a, 0x8b, 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x76, + 0x9d, 0x44, 0x6f, 0x97, 0x1e, 0x92, 0x9a, 0x99, 0xb2, 0x4d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x1b, 0x6d, 0x01, + 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, + 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x0f, 0x8b, 0x7e, 0x5f, + 0x1e, 0x16, 0xdb, 0x6d, 0x79, 0x14, 0xf7, 0xfb, 0xf2, 0x28, 0x36, 0xfc, 0x83, 0x52, 0x6c, 0x1b, 0x73, 0x83, 0x84, + 0xe6, 0x12, 0xa2, 0x16, 0x8d, 0xe0, 0x0f, 0xcd, 0x72, 0x2e, 0xa2, 0xfc, 0x30, 0xe9, 0xf7, 0x7b, 0xcb, 0x99, 0x18, + 0xe4, 0xc3, 0x24, 0xca, 0x87, 0x89, 0xe7, 0x84, 0xf8, 0x9b, 0xe7, 0x84, 0xa8, 0x68, 0xe0, 0x0a, 0xce, 0x0c, 0x40, + 0x14, 0xf0, 0xe9, 0x1f, 0xd5, 0xb5, 0x14, 0xba, 0x96, 0x58, 0xd5, 0x92, 0xe8, 0x0a, 0x6a, 0x76, 0x5d, 0x84, 0x25, + 0x96, 0x42, 0x97, 0xec, 0xcf, 0x25, 0xf0, 0x44, 0x39, 0xaf, 0x36, 0xc0, 0xc0, 0x46, 0x78, 0xe7, 0x30, 0xe1, 0x24, + 0xd6, 0x35, 0xa0, 0x9d, 0x6e, 0x6a, 0x7a, 0x41, 0x57, 0xf4, 0x12, 0xf9, 0xd9, 0x0b, 0x30, 0x58, 0x3a, 0x64, 0xf9, + 0x74, 0x30, 0xb8, 0x20, 0x2b, 0x56, 0xce, 0xc3, 0x78, 0x10, 0xae, 0x67, 0xf9, 0xf0, 0x22, 0xba, 0x20, 0xe4, 0xab, + 0x62, 0x41, 0x7b, 0xab, 0x51, 0xf9, 0x31, 0x83, 0xe0, 0x7e, 0xe9, 0x2c, 0xcc, 0x4c, 0x9c, 0x8f, 0xd5, 0xe8, 0x96, + 0xae, 0x20, 0x7e, 0x0d, 0xdc, 0x48, 0x48, 0x04, 0x1d, 0xb9, 0xa4, 0x2b, 0xba, 0xa6, 0xd2, 0xcc, 0x30, 0x86, 0xe8, + 0xb6, 0xc7, 0x49, 0x02, 0x8e, 0xc9, 0xae, 0xf8, 0x68, 0xac, 0x0a, 0xef, 0xfa, 0x8e, 0xd0, 0x5e, 0x2f, 0x71, 0x83, + 0xf4, 0x5d, 0x7b, 0x90, 0x80, 0x11, 0x19, 0xa9, 0x81, 0x32, 0x23, 0x23, 0xa9, 0x99, 0x54, 0x1c, 0x92, 0xd8, 0x1f, + 0x12, 0x35, 0x0e, 0x89, 0x3f, 0x0e, 0xb9, 0x1e, 0x07, 0xe4, 0xee, 0x97, 0x6c, 0x4c, 0x53, 0x36, 0xa6, 0x6b, 0x35, + 0x2a, 0xf4, 0x8a, 0x9e, 0x6b, 0xea, 0x78, 0xc6, 0xde, 0xc0, 0x81, 0x3d, 0x08, 0xf3, 0x59, 0x3c, 0x7c, 0x13, 0xbd, + 0x21, 0xe4, 0x2b, 0x49, 0xaf, 0xd5, 0xa5, 0x0c, 0xc2, 0x20, 0x5e, 0x81, 0x73, 0xa9, 0x0b, 0x75, 0x72, 0x65, 0x76, + 0x1c, 0x3e, 0x5d, 0x36, 0x9e, 0xce, 0x21, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x05, 0x2b, 0xe7, 0x67, 0xe1, + 0x98, 0x00, 0x0e, 0x8f, 0x1e, 0xce, 0x8b, 0xd1, 0x2d, 0xbd, 0x18, 0xdd, 0x11, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0x87, + 0x2c, 0x9e, 0x0e, 0x06, 0x6b, 0xa4, 0xea, 0x2a, 0xf7, 0x9a, 0x2c, 0xe8, 0x05, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x13, + 0x6b, 0x43, 0xc3, 0xdf, 0x30, 0xf8, 0xf8, 0x8e, 0x5d, 0x8c, 0xee, 0xe8, 0x2d, 0x7b, 0xb3, 0x1d, 0x4f, 0x81, 0x99, + 0x5a, 0xcd, 0xc2, 0xbb, 0xc3, 0xcb, 0xd9, 0x25, 0xbb, 0x8b, 0xee, 0x8e, 0xa0, 0xa1, 0x57, 0xec, 0x0e, 0x01, 0x97, + 0xd2, 0xc7, 0xcb, 0xc1, 0x1b, 0xb2, 0x3f, 0x18, 0xa4, 0x24, 0x0a, 0xaf, 0x43, 0xaf, 0x95, 0x6f, 0xe8, 0x1d, 0xa1, + 0x2b, 0x76, 0x8b, 0xa3, 0x71, 0xc9, 0xf0, 0x83, 0x73, 0x76, 0x57, 0x5f, 0x87, 0xde, 0x6e, 0x4e, 0x44, 0x27, 0x88, + 0x11, 0xfa, 0x1a, 0x38, 0x9a, 0xe5, 0xc2, 0x4c, 0xc0, 0x93, 0xb9, 0xc8, 0x68, 0x51, 0x68, 0x06, 0xe2, 0xac, 0x04, + 0xc4, 0x92, 0xa8, 0xfb, 0xcd, 0x46, 0x67, 0xb0, 0x9c, 0xfb, 0xfd, 0x5e, 0x65, 0xe8, 0x01, 0x22, 0x67, 0x76, 0xd2, + 0x83, 0x9e, 0x4f, 0x0f, 0xf0, 0x13, 0xbd, 0x6a, 0x10, 0x27, 0xf3, 0xbb, 0x65, 0xf4, 0x9b, 0x47, 0x1f, 0x7e, 0xe8, + 0xa6, 0x3c, 0x22, 0xff, 0xf7, 0x29, 0x4f, 0x99, 0x47, 0x6f, 0x2a, 0x0f, 0x04, 0xcf, 0x5b, 0x93, 0x4a, 0x23, 0x51, + 0x8d, 0xce, 0x56, 0x31, 0x68, 0x23, 0x51, 0xdb, 0xa0, 0x9f, 0xd0, 0xc2, 0x0a, 0x22, 0xe4, 0x1c, 0xbc, 0x00, 0x83, + 0x54, 0x08, 0x95, 0xa3, 0x16, 0x25, 0x1a, 0x82, 0xe4, 0xb2, 0xe4, 0x2a, 0x7c, 0x0e, 0xa1, 0xea, 0xf4, 0x71, 0x26, + 0xc2, 0x86, 0x1e, 0x87, 0x3e, 0x00, 0xfc, 0xaf, 0x3b, 0xe4, 0xa2, 0xe4, 0x97, 0x78, 0x36, 0xb7, 0x09, 0x46, 0xc1, + 0x12, 0xd1, 0x0c, 0x6d, 0x83, 0xd8, 0x8f, 0x25, 0xc1, 0x7a, 0x24, 0x8d, 0x47, 0xa5, 0x39, 0x22, 0xfc, 0x28, 0x3e, + 0x8a, 0x9e, 0xc6, 0x86, 0x44, 0x72, 0x24, 0x91, 0x7c, 0x00, 0x84, 0x93, 0xa0, 0xbf, 0xb8, 0x6b, 0xb2, 0x6b, 0x21, + 0x31, 0xe8, 0x4f, 0x4b, 0xa6, 0x65, 0xf7, 0xaa, 0xc7, 0xbe, 0x22, 0xc8, 0x1d, 0xd3, 0x7f, 0x79, 0x7d, 0xf8, 0xe7, + 0x12, 0x67, 0xd0, 0x7a, 0xbe, 0xa8, 0xce, 0xcc, 0xbc, 0xc1, 0x8d, 0xbc, 0x2e, 0x6b, 0xd7, 0xe5, 0x0b, 0xbe, 0xc7, + 0x6f, 0x2b, 0x2e, 0xd2, 0x72, 0xef, 0x97, 0xaa, 0x8d, 0xe7, 0x54, 0xae, 0x57, 0x2e, 0xce, 0x8a, 0x32, 0x4e, 0xf5, + 0xa4, 0x2e, 0xc6, 0x1a, 0xb6, 0xe1, 0xf7, 0x88, 0xba, 0x92, 0x96, 0xa3, 0xa7, 0x94, 0xab, 0x66, 0xca, 0xc5, 0x3a, + 0xcf, 0x7f, 0xde, 0x49, 0xc5, 0x29, 0x6e, 0xa6, 0x20, 0x55, 0x6a, 0xb9, 0x80, 0xea, 0x39, 0x6a, 0xb9, 0x5b, 0x9a, + 0x1d, 0xe0, 0xdc, 0x36, 0xd5, 0xc7, 0xca, 0xec, 0xc2, 0x4b, 0x6e, 0xdc, 0x9f, 0x4c, 0x19, 0x16, 0x8c, 0x42, 0x9b, + 0x55, 0x57, 0xda, 0xbe, 0xd0, 0x3a, 0x0d, 0xc3, 0x95, 0x1f, 0x2f, 0x20, 0x5d, 0xc0, 0x38, 0x5e, 0x94, 0x4c, 0x8c, + 0xdb, 0xa3, 0xb7, 0x82, 0xf8, 0x92, 0xad, 0x40, 0xc0, 0x5c, 0xc3, 0xdb, 0x75, 0x1d, 0x6d, 0xf7, 0xc4, 0x29, 0xa3, + 0x72, 0x15, 0x8b, 0xef, 0xe3, 0x95, 0x81, 0x4c, 0x56, 0xc7, 0x63, 0x63, 0x4c, 0xa7, 0x3f, 0x25, 0xa1, 0x5f, 0x08, + 0x05, 0x9f, 0xf5, 0xd2, 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, + 0xe4, 0xab, 0xa6, 0x80, 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, + 0x9d, 0x1a, 0x53, 0x31, 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, + 0xa8, 0xdf, 0x02, 0x17, 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, + 0xbe, 0x85, 0x07, 0x88, 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, + 0xa9, 0xd2, 0xc4, 0x70, 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, + 0xe8, 0xa6, 0x74, 0xe9, 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, + 0xac, 0x95, 0xf0, 0xa6, 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, + 0x14, 0x0d, 0x1d, 0xd0, 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, + 0x35, 0x2b, 0xe6, 0xf9, 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, + 0x21, 0xc9, 0x26, 0x56, 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, + 0x32, 0x0c, 0xcb, 0xe1, 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x70, 0x3e, 0x09, 0x15, + 0xbb, 0x60, 0xf7, 0x02, 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, + 0x65, 0x16, 0xcf, 0xc7, 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, + 0xbe, 0xc1, 0x2a, 0xf2, 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, + 0xdc, 0x94, 0x33, 0xae, 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, + 0x49, 0xd3, 0x80, 0xee, 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, + 0xad, 0xd0, 0xab, 0x1a, 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, + 0x12, 0x06, 0x3f, 0xa4, 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, + 0x14, 0x62, 0x94, 0x50, 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, + 0x7c, 0x5d, 0x55, 0x81, 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, + 0x48, 0x08, 0x5e, 0xff, 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, + 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, + 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, + 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, + 0x4f, 0xae, 0xd8, 0x51, 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, + 0xf7, 0x1f, 0xcb, 0x5d, 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, + 0x84, 0x2d, 0xe6, 0x70, 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, + 0xb4, 0xcc, 0xaa, 0xf7, 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, + 0x02, 0xd0, 0x64, 0x23, 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, + 0x92, 0xa0, 0x84, 0x66, 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, + 0x07, 0xf6, 0x16, 0x04, 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, + 0x08, 0xf2, 0xd5, 0x18, 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, + 0xe4, 0xd0, 0x3e, 0x4b, 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb7, 0x2d, 0xb2, 0x24, 0xeb, + 0xc7, 0xd2, 0x28, 0x62, 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3e, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, + 0x0e, 0xe2, 0x36, 0x08, 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, + 0x6f, 0xb2, 0xd6, 0xa8, 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, + 0xdb, 0xed, 0x78, 0x2a, 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, + 0xa5, 0xb7, 0x7f, 0xe1, 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, + 0x4e, 0xff, 0x76, 0x6b, 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xb4, 0x81, 0x2b, 0xd5, 0x2a, 0x04, 0xec, 0x42, + 0x49, 0xf6, 0x0f, 0x20, 0x2a, 0x42, 0x33, 0xee, 0x66, 0xd9, 0x90, 0xc8, 0xf8, 0x71, 0x3a, 0xcb, 0x86, 0x60, 0x87, + 0x7b, 0x51, 0x89, 0xcb, 0x51, 0x6b, 0x83, 0xd3, 0xb3, 0x24, 0x84, 0x50, 0x0e, 0x58, 0xd9, 0xad, 0xfa, 0x73, 0xa7, + 0xcc, 0x84, 0xd4, 0x64, 0x75, 0x3b, 0xa5, 0x7b, 0x98, 0xe6, 0x7b, 0x66, 0x04, 0x07, 0xdc, 0xdb, 0x5f, 0xf5, 0xc7, + 0x30, 0xc9, 0x34, 0x39, 0x45, 0xf2, 0x8b, 0xf4, 0x14, 0x92, 0x76, 0xe8, 0xa9, 0x22, 0x80, 0x13, 0x6a, 0x3f, 0x86, + 0xdf, 0x30, 0xee, 0xdf, 0x35, 0x5f, 0xbb, 0xa9, 0x88, 0x9e, 0x52, 0x2c, 0x53, 0x93, 0xd3, 0x24, 0x2b, 0x12, 0x88, + 0xda, 0xa8, 0x9a, 0x11, 0x3d, 0x71, 0x31, 0x1f, 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, + 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xec, 0x29, 0xdd, 0x9b, 0x7c, 0x73, 0x40, 0xf7, 0x0e, 0x9e, 0x3c, 0x23, 0x00, + 0x8b, 0x76, 0x79, 0x1e, 0x1e, 0x3c, 0x7b, 0x46, 0xf7, 0xbe, 0xfd, 0x96, 0xee, 0x4d, 0x9e, 0x1c, 0x34, 0xd2, 0x26, + 0xcf, 0xbe, 0xa5, 0x7b, 0xdf, 0x3c, 0x6d, 0xa4, 0x1d, 0x8c, 0x9f, 0xd1, 0xbd, 0xbf, 0x7f, 0x63, 0xd2, 0xfe, 0x06, + 0xd9, 0xbe, 0x3d, 0xc0, 0xff, 0x4c, 0xda, 0xe4, 0xd9, 0x13, 0xba, 0x37, 0x19, 0x43, 0x25, 0xcf, 0x5c, 0x25, 0xe3, + 0x09, 0x7c, 0xfc, 0x04, 0xfe, 0xfb, 0x1b, 0x09, 0x16, 0xb4, 0x92, 0x2c, 0x17, 0xa8, 0x3f, 0x43, 0x11, 0x27, 0xaa, + 0x26, 0x12, 0x1e, 0x62, 0x66, 0xf5, 0x4d, 0x1c, 0x06, 0xc4, 0xa5, 0x43, 0x41, 0x74, 0x6f, 0x3c, 0x7a, 0x46, 0x02, + 0x1f, 0x9e, 0xee, 0xc6, 0x07, 0x19, 0xcb, 0xc5, 0x3c, 0xfb, 0x2a, 0x37, 0xb1, 0x15, 0x3c, 0x00, 0xab, 0x8f, 0x7e, + 0xae, 0x4a, 0xce, 0xb3, 0xaf, 0x2a, 0xb9, 0x9b, 0xeb, 0xf7, 0x16, 0xa0, 0xbc, 0xbf, 0x6a, 0xd9, 0x4d, 0xa1, 0x42, + 0xa7, 0xb5, 0x46, 0x9f, 0x7d, 0xc4, 0xf4, 0xc1, 0xc0, 0xbb, 0x61, 0xff, 0xb4, 0x53, 0x4e, 0xeb, 0x1b, 0x8d, 0x42, + 0x8d, 0xca, 0x43, 0xc2, 0x8e, 0xa0, 0xe8, 0xc1, 0x00, 0x78, 0x02, 0x0f, 0xf7, 0xed, 0xdf, 0x2c, 0xe3, 0x63, 0x47, + 0x19, 0xbf, 0xa0, 0x0c, 0x01, 0x8d, 0x7a, 0x98, 0xdd, 0xf4, 0xb0, 0xd1, 0xad, 0x5e, 0xb2, 0x54, 0x27, 0x53, 0xd3, + 0x33, 0xd8, 0xd7, 0xba, 0x96, 0x7b, 0x46, 0x14, 0x2d, 0x2f, 0xf6, 0x52, 0x3e, 0xab, 0xd8, 0x4f, 0x4b, 0x54, 0x6f, + 0x45, 0x8d, 0x37, 0x32, 0x9b, 0x55, 0xec, 0x7b, 0xf3, 0x06, 0xb8, 0x19, 0xf6, 0xbb, 0x7a, 0xf2, 0x03, 0x67, 0x70, + 0x69, 0xdb, 0xa3, 0x4c, 0x8c, 0x00, 0x2b, 0x20, 0x03, 0x07, 0x1e, 0x00, 0x1d, 0xf4, 0x47, 0x7b, 0xbb, 0x55, 0x29, + 0xcd, 0x3e, 0x5b, 0x18, 0x40, 0xc3, 0xbc, 0x4d, 0x5c, 0xd9, 0xff, 0x6a, 0xc8, 0x4b, 0x50, 0xb8, 0xd5, 0x2c, 0x6f, + 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x65, 0x40, 0xcd, 0x96, 0x8f, 0x36, + 0x5c, 0xa9, 0x27, 0x81, 0x33, 0xb8, 0x90, 0x45, 0xc2, 0x4f, 0xb4, 0xd8, 0x1f, 0xad, 0x1f, 0x7d, 0xdf, 0x1e, 0x0f, + 0xd6, 0xbe, 0xc7, 0x47, 0xfa, 0xb3, 0xc6, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0x17, 0xb5, 0x95, 0x78, 0x94, 0xc0, 0x1b, + 0x98, 0x88, 0x14, 0x06, 0xa9, 0x16, 0x38, 0x06, 0xe5, 0x8d, 0x85, 0x58, 0xaa, 0xae, 0x6e, 0xb0, 0x05, 0x91, 0x21, + 0x78, 0xb8, 0xfd, 0x6b, 0xa9, 0x02, 0x47, 0xf5, 0xfb, 0x5c, 0xfa, 0x6e, 0x4f, 0xc6, 0x8e, 0x1c, 0xa7, 0x7e, 0x2a, + 0x1c, 0xfc, 0x37, 0xa9, 0x6b, 0x63, 0xb9, 0x92, 0x32, 0xcb, 0xb2, 0xb0, 0xa3, 0x50, 0xcb, 0x3d, 0x2a, 0x0f, 0x92, + 0x2f, 0xe4, 0x10, 0xc9, 0x02, 0xa3, 0x50, 0x90, 0xe1, 0x84, 0x8a, 0xd1, 0x5a, 0x94, 0xcb, 0xec, 0xa2, 0x0a, 0x37, + 0x4a, 0xa1, 0xcc, 0x29, 0xfa, 0x76, 0x83, 0x03, 0x09, 0x89, 0xb2, 0xf2, 0x6d, 0xfc, 0x36, 0x44, 0xb0, 0x3a, 0xae, + 0x6d, 0xa1, 0xb8, 0xb7, 0x3f, 0x79, 0xda, 0xc5, 0x1f, 0x19, 0x17, 0x50, 0x17, 0x8b, 0x69, 0x38, 0xb1, 0xb1, 0x6f, + 0xdc, 0x17, 0x56, 0xd3, 0x03, 0x50, 0xdf, 0xa5, 0x12, 0x23, 0xa8, 0xaf, 0x8c, 0x7d, 0x6c, 0x8f, 0x31, 0x39, 0x83, + 0x58, 0xc3, 0x2a, 0x67, 0xa6, 0xfa, 0x46, 0xd8, 0x11, 0x00, 0x37, 0x42, 0x6b, 0x14, 0x04, 0x1e, 0xaf, 0x42, 0x3c, + 0x2f, 0x55, 0xf8, 0xd6, 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, + 0x61, 0xb5, 0x95, 0x65, 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, + 0x5c, 0x0a, 0xcb, 0xa0, 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, + 0x44, 0x23, 0xc4, 0xc3, 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, + 0xa3, 0x04, 0x97, 0xa9, 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, + 0x6a, 0x5f, 0x43, 0x31, 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, + 0x4d, 0xd8, 0xb9, 0x91, 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, + 0xdb, 0x22, 0x73, 0x44, 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, + 0xf1, 0x14, 0x11, 0x01, 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, + 0x81, 0x2c, 0x80, 0xbe, 0xfd, 0x9c, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, + 0x04, 0xbb, 0xba, 0x35, 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, + 0x44, 0x02, 0x32, 0xfb, 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, + 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, + 0x17, 0x7f, 0x5a, 0x75, 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, + 0x6d, 0x29, 0xc9, 0x55, 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, + 0xee, 0x0e, 0xbf, 0xc4, 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, + 0x2a, 0xca, 0x07, 0x13, 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, + 0xac, 0x77, 0xd3, 0x5a, 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, + 0x30, 0x20, 0xda, 0xa5, 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, + 0x9e, 0x01, 0x49, 0x26, 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, + 0xfb, 0x7a, 0xc6, 0x7f, 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, + 0x10, 0x43, 0x54, 0x7b, 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, + 0x43, 0xa3, 0xde, 0xc6, 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, + 0x88, 0x64, 0xbf, 0x3d, 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, + 0xb8, 0x2c, 0x22, 0xcb, 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, + 0xbf, 0x5e, 0xc9, 0x02, 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, + 0xe3, 0xce, 0x9e, 0x80, 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, + 0xb7, 0x80, 0x49, 0xc0, 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, + 0xd6, 0xfe, 0xd5, 0x5d, 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, + 0xa4, 0xb0, 0xe5, 0x31, 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, + 0x0d, 0xee, 0x47, 0x15, 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, + 0x72, 0xbc, 0xed, 0x76, 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, + 0x59, 0xef, 0x25, 0x60, 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, + 0x4b, 0xb2, 0x1f, 0xa6, 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, + 0x41, 0x6f, 0xe9, 0x0d, 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, + 0xfb, 0xfd, 0xde, 0x99, 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, + 0x9b, 0xf0, 0x2c, 0x0f, 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, + 0x93, 0x23, 0xd0, 0x9b, 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, + 0xde, 0xb5, 0x27, 0x63, 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, + 0x7f, 0xb3, 0xf0, 0x86, 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, + 0xd2, 0x53, 0x76, 0x45, 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0xa7, 0x38, 0x0c, 0xe3, 0x61, 0x41, + 0xf6, 0x25, 0xbd, 0xdb, 0x9f, 0xf0, 0x27, 0x64, 0x16, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, + 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0x4e, 0xe8, 0x0d, 0x2b, 0xe8, 0x29, 0x8b, 0x49, 0x74, 0x0d, 0xad, 0x38, 0x9f, + 0x15, 0xd1, 0x0d, 0x3d, 0x65, 0x67, 0xb3, 0x38, 0x3a, 0xa5, 0x27, 0x2c, 0x1f, 0x4e, 0x20, 0xef, 0xe9, 0xf0, 0x86, + 0xec, 0x9f, 0x90, 0x28, 0x3c, 0xd1, 0xbf, 0xef, 0xe8, 0x25, 0x0f, 0x4f, 0xa8, 0x57, 0xcd, 0x09, 0x31, 0xd5, 0x37, + 0x6a, 0x3f, 0x21, 0x91, 0x3f, 0x98, 0x27, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, + 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, 0x06, 0x74, 0xf6, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, + 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, 0xd7, 0xc1, 0x6b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0xeb, 0x7e, 0x1f, 0x22, + 0xdd, 0x17, 0x33, 0x13, 0xdb, 0xcd, 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0xd7, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, + 0xbc, 0x19, 0xbc, 0x7e, 0x7c, 0x47, 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x1b, 0x9a, 0x01, 0xe0, 0xd7, 0xeb, + 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, 0x7d, 0x7d, 0x78, 0x32, 0x1d, 0x0c, 0x5e, 0x9b, 0x6d, 0xf2, 0x96, 0xdd, 0x53, + 0x0a, 0xac, 0xbf, 0xb3, 0x7e, 0xff, 0xed, 0x51, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xd6, 0x45, + 0x55, 0x3b, 0xeb, 0xf7, 0xd7, 0xfd, 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9c, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x8e, 0x22, + 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, 0xac, 0xda, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, + 0xec, 0x9d, 0x6d, 0xb7, 0xa7, 0x8c, 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, + 0xcc, 0xe6, 0x66, 0x69, 0x0f, 0x81, 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0x2f, 0x00, + 0x42, 0x24, 0x59, 0xc8, 0x67, 0x38, 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xbb, + 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, 0xd1, 0xdf, 0x9e, 0x3d, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, + 0x61, 0x17, 0x6b, 0xb5, 0x0f, 0x46, 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0xbe, 0x98, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, + 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, 0x18, 0x4c, 0x2e, 0xd2, 0xcf, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, + 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, 0xdb, 0x6e, 0x2b, 0xff, 0x12, 0xf8, 0x16, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, + 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, + 0xba, 0xdc, 0xe3, 0xea, 0x5f, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, + 0x0c, 0xb7, 0x56, 0x22, 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, + 0x86, 0x07, 0xc9, 0xc4, 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, + 0x24, 0xd3, 0xe4, 0x10, 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, + 0x8e, 0x49, 0xad, 0xef, 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, + 0x78, 0x34, 0x7e, 0x46, 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, + 0x9b, 0x57, 0x3a, 0x36, 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, + 0xea, 0x23, 0x08, 0xb3, 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, + 0xa3, 0x52, 0xa6, 0xba, 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, + 0x10, 0xc0, 0xa3, 0x11, 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, + 0xde, 0x83, 0x30, 0x29, 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, + 0x57, 0x10, 0x27, 0x6c, 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, + 0x25, 0xf7, 0x26, 0xe3, 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, + 0x57, 0xdc, 0x1b, 0x17, 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, + 0x76, 0x3f, 0x31, 0x2b, 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xf6, 0xf2, 0xec, 0xf5, + 0xdb, 0x57, 0xaf, 0xdf, 0xbe, 0xfe, 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, + 0x6a, 0xf1, 0x85, 0xb3, 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, + 0x20, 0xa3, 0x51, 0x21, 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, + 0xdb, 0xd1, 0xd6, 0xac, 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, + 0xc8, 0x75, 0xf0, 0xbe, 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, + 0x13, 0x73, 0x6d, 0x74, 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, + 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, + 0xc2, 0xfc, 0x0c, 0x1b, 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, + 0xce, 0x17, 0xdf, 0x42, 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, + 0x31, 0x1e, 0x77, 0xf7, 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, + 0xbe, 0x5d, 0x24, 0xce, 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, + 0x35, 0xe7, 0x6d, 0x42, 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, + 0x17, 0x43, 0x9a, 0x72, 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, + 0xd7, 0xd9, 0xe6, 0x33, 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, + 0xc4, 0x40, 0x74, 0x01, 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, + 0x31, 0x8b, 0xad, 0x25, 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x84, 0x1d, 0x7d, + 0xf7, 0xb6, 0x01, 0x10, 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, + 0x2b, 0xb4, 0xec, 0x95, 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, + 0xa6, 0x12, 0xd5, 0x23, 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, + 0xee, 0xff, 0xe6, 0x42, 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, + 0x5d, 0xa6, 0x97, 0x5d, 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, + 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, + 0x7c, 0x89, 0x5f, 0x29, 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, + 0xfe, 0x17, 0x18, 0x0d, 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, + 0xeb, 0x67, 0x35, 0xcc, 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, + 0x29, 0x11, 0x83, 0x41, 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, + 0x1a, 0x5b, 0x92, 0x6c, 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, + 0x32, 0xd3, 0xc2, 0xa2, 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, + 0x4d, 0xac, 0xf1, 0x8b, 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, + 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, + 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, + 0xcc, 0xaf, 0x24, 0x19, 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, + 0xdc, 0x18, 0xd6, 0xf4, 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, + 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, + 0x60, 0x1c, 0xa5, 0x83, 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, + 0x0b, 0x68, 0xda, 0x97, 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, + 0x0b, 0xd7, 0xc2, 0x8b, 0xdd, 0x16, 0x0a, 0x4d, 0xb6, 0x0b, 0xf9, 0xff, 0xe3, 0x86, 0x71, 0xdf, 0x5d, 0xc2, 0x2c, + 0xae, 0xeb, 0x6c, 0xb4, 0x2a, 0x64, 0x25, 0xe1, 0x36, 0xa1, 0x44, 0x61, 0xa3, 0x78, 0xb5, 0xca, 0xb5, 0x8b, 0xd8, + 0xbc, 0xa2, 0x00, 0xee, 0x02, 0x71, 0x8a, 0x81, 0x85, 0x36, 0x06, 0x72, 0x9f, 0x78, 0x21, 0x99, 0x55, 0xfb, 0x98, + 0x7b, 0xe4, 0x9f, 0x21, 0x18, 0xa3, 0x8a, 0xa3, 0xf1, 0x4c, 0x61, 0x5d, 0x7c, 0x4e, 0xde, 0xfb, 0x6f, 0x1c, 0x45, + 0xf6, 0x68, 0x06, 0x3d, 0x41, 0xe4, 0x3c, 0xe2, 0xec, 0xc9, 0xe4, 0x65, 0xe0, 0x7e, 0x06, 0x2b, 0xfd, 0x75, 0xb7, + 0x19, 0x6b, 0xdb, 0xa3, 0x7b, 0x61, 0x84, 0xa2, 0x9f, 0xf0, 0x9d, 0xa9, 0x17, 0x70, 0x09, 0xd5, 0xc0, 0xae, 0x2f, + 0x2f, 0x79, 0x09, 0x20, 0x42, 0x99, 0xe8, 0xf7, 0x7b, 0x7f, 0x1a, 0x68, 0xd2, 0x92, 0x17, 0x6f, 0x32, 0x61, 0x9d, + 0x71, 0xa0, 0xa9, 0x40, 0xfd, 0x3f, 0x56, 0xf6, 0x99, 0x8e, 0xc9, 0xcc, 0x7f, 0x1c, 0x4e, 0x48, 0xd4, 0x7c, 0x4d, + 0x3e, 0x73, 0x9a, 0x7e, 0xe6, 0x8a, 0xf6, 0x1f, 0xc8, 0xcc, 0x0d, 0x87, 0x0c, 0xf5, 0x97, 0x8e, 0x79, 0x32, 0x7a, + 0x9d, 0x98, 0x1d, 0x09, 0x56, 0xcd, 0x20, 0x0a, 0x7b, 0x01, 0x0f, 0xea, 0x5a, 0x16, 0x4f, 0x61, 0xf6, 0x41, 0x8d, + 0x28, 0x0e, 0xd9, 0x78, 0x16, 0xca, 0x70, 0x02, 0xf6, 0xbd, 0x93, 0x31, 0xdc, 0x07, 0x64, 0xf8, 0xb1, 0x0a, 0xb1, + 0x73, 0x90, 0xf6, 0xb1, 0x42, 0xc5, 0x04, 0x40, 0x04, 0x42, 0xde, 0x7e, 0x5f, 0xaa, 0x24, 0x7c, 0x5d, 0x62, 0x4a, + 0xa1, 0x3e, 0xf8, 0x4f, 0xa4, 0xea, 0x8e, 0xe9, 0x57, 0xeb, 0xc7, 0x9f, 0x09, 0xc5, 0xa7, 0xbb, 0x94, 0xf8, 0x16, + 0x82, 0x3b, 0x4b, 0xd0, 0x41, 0x54, 0x68, 0xc6, 0xf6, 0x30, 0xbf, 0x2b, 0xee, 0xe7, 0x77, 0xc5, 0xff, 0x3b, 0x7e, + 0x57, 0x3c, 0xc4, 0x18, 0x56, 0x16, 0x1a, 0x7e, 0x16, 0x8c, 0x83, 0xe8, 0x3f, 0xe7, 0x13, 0xef, 0xe5, 0xa9, 0xaf, + 0x32, 0x31, 0xbd, 0x87, 0x69, 0xf6, 0x09, 0x0a, 0xc2, 0x2a, 0xee, 0xd2, 0x93, 0x75, 0x65, 0x6f, 0xad, 0x64, 0x88, + 0x79, 0x1e, 0x60, 0x8d, 0xc2, 0xca, 0x03, 0xba, 0x47, 0xd5, 0x06, 0x71, 0x22, 0x78, 0x18, 0x33, 0x2b, 0x7d, 0xdf, + 0x6e, 0x8d, 0x0a, 0xf3, 0x41, 0x2e, 0x0a, 0xb2, 0x9b, 0x8f, 0x67, 0xe3, 0x28, 0xc4, 0x06, 0xfc, 0xc7, 0x8c, 0x55, + 0x43, 0x36, 0xdf, 0xc9, 0x48, 0xed, 0x98, 0x3c, 0x4d, 0x76, 0x49, 0xef, 0x80, 0x77, 0xc8, 0xcf, 0xeb, 0x8f, 0x61, + 0x21, 0x0d, 0xbf, 0x25, 0x2f, 0xe3, 0x22, 0xab, 0x96, 0x57, 0x59, 0x82, 0x4c, 0x17, 0xbc, 0xf8, 0x62, 0xa6, 0xcb, + 0xfb, 0x58, 0x1f, 0x30, 0x9e, 0x52, 0xbc, 0x6e, 0x88, 0xd2, 0xd7, 0x2d, 0xcf, 0x0a, 0x75, 0x79, 0x52, 0x31, 0xdb, + 0xb3, 0x12, 0x9c, 0x4e, 0xc1, 0x04, 0x5f, 0xff, 0x74, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x0b, 0xb9, 0x32, + 0x58, 0x4e, 0x16, 0xba, 0x13, 0x30, 0x43, 0xa5, 0xc0, 0x0b, 0x14, 0xfc, 0x45, 0x03, 0x23, 0xfa, 0xca, 0xfd, 0x26, + 0x03, 0x83, 0x74, 0x69, 0x4e, 0x84, 0xb1, 0xe3, 0x76, 0x8a, 0xb4, 0x15, 0xe5, 0x8c, 0xb3, 0xf7, 0xea, 0x4a, 0x01, + 0x06, 0x78, 0x9b, 0x9b, 0xe8, 0x3c, 0x41, 0xaf, 0x05, 0xa5, 0xf3, 0x06, 0xee, 0x66, 0x19, 0x19, 0xe1, 0xe2, 0xe3, + 0xca, 0x63, 0xc1, 0x3d, 0xfb, 0x85, 0x58, 0x1a, 0xcd, 0x34, 0x18, 0xb3, 0x79, 0xc1, 0x02, 0x85, 0x0a, 0x14, 0x58, + 0xce, 0xb4, 0xa5, 0x69, 0x35, 0xe4, 0xfb, 0x07, 0x68, 0x6d, 0x5a, 0x0d, 0xf8, 0xfe, 0x41, 0x1d, 0x65, 0x87, 0x90, + 0xe5, 0xc8, 0xcf, 0xa0, 0x5e, 0xd7, 0x91, 0x49, 0x31, 0xd9, 0xfd, 0xfa, 0x52, 0x7f, 0x54, 0x37, 0xe0, 0xfa, 0x01, + 0x08, 0x60, 0x03, 0x70, 0x08, 0x54, 0x83, 0xa5, 0x11, 0xc1, 0xa2, 0x4c, 0xa1, 0x7d, 0x0d, 0xbd, 0x37, 0x1a, 0xfe, + 0x0b, 0xdc, 0x45, 0xe4, 0xca, 0xff, 0x04, 0x81, 0xbf, 0xa2, 0x4c, 0x2b, 0x53, 0xfc, 0x4f, 0xb4, 0x7a, 0x85, 0x72, + 0xd6, 0xb4, 0xe6, 0x83, 0x68, 0x4d, 0x84, 0x6a, 0xc6, 0x10, 0xfc, 0x5b, 0x59, 0xa6, 0x2d, 0x55, 0x95, 0xfa, 0xd0, + 0x78, 0xad, 0x15, 0xce, 0xf2, 0x71, 0xe4, 0xbd, 0xc6, 0xd0, 0xb1, 0x89, 0xb3, 0x94, 0x53, 0xa9, 0xb3, 0x4f, 0xfb, + 0x32, 0x72, 0x80, 0xd3, 0x09, 0x1b, 0x4f, 0x93, 0x43, 0x39, 0x4d, 0x1c, 0x64, 0x7e, 0xce, 0x30, 0xb2, 0xaa, 0x01, + 0x61, 0x51, 0x36, 0x94, 0xb6, 0x00, 0x93, 0x9c, 0x10, 0x32, 0xc5, 0x50, 0x14, 0xf9, 0x48, 0xf7, 0xc3, 0x7a, 0xb3, + 0xba, 0x2f, 0xde, 0x69, 0x80, 0xd3, 0x30, 0x81, 0x40, 0xe0, 0x45, 0x7c, 0x93, 0x89, 0x4b, 0xf0, 0x18, 0x1e, 0xc0, + 0x97, 0xe0, 0x26, 0x97, 0xb2, 0xdf, 0xab, 0x30, 0xc7, 0xb5, 0x05, 0x0c, 0x1a, 0xac, 0x1e, 0x44, 0x87, 0x4b, 0x69, + 0xb3, 0xab, 0x00, 0xb1, 0x31, 0x85, 0x58, 0x16, 0x6c, 0x6d, 0xd9, 0xb3, 0xef, 0x55, 0xd3, 0xd0, 0x3a, 0xe1, 0x58, + 0x5c, 0xe6, 0x10, 0x45, 0x65, 0x10, 0x83, 0x3b, 0x92, 0xc7, 0xe7, 0x3d, 0x12, 0xe1, 0x05, 0x01, 0xb7, 0xb2, 0x58, + 0x86, 0x2b, 0xba, 0x1c, 0xdd, 0xd2, 0xf5, 0xe8, 0x86, 0x8e, 0xe9, 0xe4, 0xef, 0x63, 0xb0, 0xc8, 0xd6, 0xa9, 0x77, + 0x74, 0x3d, 0x5a, 0xd2, 0x6f, 0xc7, 0xf4, 0xe0, 0x6f, 0x60, 0xc2, 0x87, 0x87, 0x09, 0xbd, 0x00, 0xc7, 0x2e, 0x52, + 0xa3, 0xa7, 0xa6, 0x6f, 0x70, 0x58, 0x8d, 0xf2, 0x21, 0x1f, 0xe5, 0x94, 0x8f, 0x8a, 0x61, 0x35, 0x02, 0x4f, 0xc7, + 0x6a, 0xc8, 0x47, 0x15, 0xe5, 0xa3, 0xf3, 0x61, 0x35, 0x3a, 0x27, 0xcd, 0xa6, 0xbf, 0xae, 0xf8, 0x55, 0xc9, 0x52, + 0xd8, 0x16, 0xb0, 0x7c, 0x3d, 0xaf, 0xa8, 0xd4, 0x5f, 0xd5, 0xe6, 0x64, 0xb6, 0x9c, 0xbd, 0xbd, 0xee, 0x72, 0x62, + 0xf1, 0xb8, 0x6d, 0x3a, 0x5c, 0x7d, 0x39, 0x51, 0x27, 0xbd, 0x42, 0x7e, 0x18, 0x4f, 0x85, 0x3a, 0x87, 0xc0, 0x4c, + 0x62, 0x16, 0xc6, 0x0c, 0x9b, 0xa9, 0xd3, 0x40, 0x81, 0x93, 0x8d, 0x3c, 0x17, 0xc5, 0x6c, 0x94, 0x53, 0x78, 0x1f, + 0x13, 0x12, 0x09, 0x38, 0xab, 0x8e, 0xaa, 0x51, 0x01, 0x31, 0x47, 0x58, 0x88, 0x8f, 0xd0, 0x2f, 0xf5, 0x91, 0x87, + 0x04, 0x9e, 0x61, 0x5f, 0x8b, 0x41, 0x0c, 0x47, 0xbc, 0xad, 0xac, 0x9a, 0x85, 0x09, 0x54, 0x56, 0x0d, 0x4b, 0x53, + 0x59, 0x41, 0xb3, 0x51, 0xe5, 0x57, 0x56, 0xe1, 0x18, 0x25, 0x84, 0x44, 0xa5, 0xae, 0x0c, 0xd4, 0x27, 0x09, 0x0b, + 0x4b, 0x5d, 0xd9, 0xb9, 0xfa, 0xe8, 0xdc, 0xaf, 0xec, 0x1c, 0x5c, 0x48, 0x07, 0x89, 0x7f, 0x95, 0xca, 0xd3, 0xf6, + 0x75, 0xb0, 0xb1, 0xaa, 0xe8, 0x86, 0xdf, 0x56, 0x45, 0x1c, 0x95, 0xd4, 0xc5, 0x80, 0xc6, 0x85, 0x11, 0x49, 0xaa, + 0xd7, 0x28, 0xf8, 0x43, 0x82, 0xa8, 0x34, 0x06, 0xaf, 0xce, 0xa4, 0x6b, 0xa5, 0x56, 0x54, 0x0c, 0xca, 0x41, 0x01, + 0xf7, 0xa7, 0xbc, 0xb5, 0x90, 0xbe, 0x87, 0x88, 0xca, 0x50, 0xde, 0xe0, 0x1f, 0x18, 0x3c, 0x99, 0xad, 0xd2, 0x30, + 0x19, 0xdd, 0xd1, 0x78, 0xb4, 0x44, 0x38, 0x18, 0xb6, 0x4e, 0x15, 0xde, 0xfa, 0x05, 0xa4, 0xdf, 0xd2, 0x78, 0x74, + 0x43, 0x53, 0x6b, 0x73, 0x6a, 0xa0, 0xae, 0x7a, 0x63, 0x7a, 0x1b, 0xc1, 0xeb, 0xbb, 0x68, 0x49, 0x61, 0x2b, 0x1d, + 0xe7, 0xd9, 0xa5, 0x88, 0x52, 0x8a, 0x08, 0x84, 0x6b, 0x44, 0x0e, 0x5c, 0x6a, 0xb4, 0xc1, 0xf5, 0x00, 0xca, 0xd0, + 0x70, 0x81, 0xcb, 0x41, 0x3c, 0x5a, 0x7a, 0x64, 0x6a, 0xa9, 0x2f, 0xb2, 0x08, 0x1f, 0xed, 0x6c, 0xb4, 0x14, 0xcf, + 0x88, 0x85, 0x71, 0x05, 0x43, 0xa8, 0x0b, 0x2b, 0x4d, 0x41, 0xd2, 0x05, 0x8e, 0xec, 0x85, 0x45, 0x15, 0x6e, 0xc0, + 0xb4, 0xe8, 0x0e, 0xcc, 0xa3, 0x40, 0xe1, 0xe0, 0x12, 0xa4, 0x9f, 0x50, 0xb6, 0x73, 0x94, 0x26, 0x87, 0x37, 0x41, + 0xe9, 0xce, 0x04, 0x21, 0xed, 0xea, 0x26, 0x5b, 0xd2, 0x37, 0xd8, 0xde, 0xa1, 0x53, 0x51, 0x41, 0xf5, 0xb9, 0x05, + 0x93, 0x25, 0x1b, 0x84, 0x2d, 0x61, 0x7a, 0xa6, 0xd7, 0x80, 0x3d, 0xbd, 0x7f, 0xb0, 0x33, 0xdf, 0xc5, 0xec, 0xd3, + 0x7e, 0x19, 0x8d, 0x95, 0x05, 0x6f, 0x6e, 0x89, 0xdd, 0x92, 0x8d, 0xa7, 0xcb, 0xc3, 0x72, 0xba, 0x44, 0x62, 0x67, + 0xe8, 0x16, 0xe3, 0xf3, 0xe5, 0x82, 0x26, 0x78, 0xb6, 0xb1, 0x6a, 0xbe, 0x34, 0x68, 0x29, 0x29, 0xc3, 0xf5, 0xb6, + 0x44, 0xff, 0x7f, 0x75, 0xf1, 0x4b, 0x01, 0x5e, 0x82, 0xb1, 0x00, 0x10, 0xee, 0xc1, 0xb4, 0x20, 0xb5, 0x51, 0x36, + 0x96, 0x69, 0x98, 0xe2, 0x22, 0x30, 0x29, 0xfd, 0x7e, 0x98, 0xb3, 0x94, 0x78, 0xd0, 0xa1, 0xee, 0xd4, 0x4e, 0x7d, + 0x21, 0x08, 0xf0, 0x48, 0xea, 0x1c, 0x9b, 0xfc, 0x7d, 0x3c, 0x0b, 0xd4, 0x40, 0x04, 0x51, 0x76, 0x88, 0x8f, 0x18, + 0xb8, 0x28, 0xd2, 0x71, 0x3b, 0x5d, 0x11, 0x17, 0xbb, 0xc7, 0x2c, 0xc4, 0x49, 0xc2, 0x5c, 0xb3, 0x6c, 0xc8, 0xaa, + 0x08, 0x13, 0x74, 0x61, 0x60, 0x96, 0x37, 0x64, 0xd5, 0xfe, 0x01, 0x44, 0x6a, 0xb5, 0x65, 0xac, 0xba, 0xca, 0xf8, + 0x16, 0x80, 0xac, 0x19, 0x63, 0x07, 0x7f, 0x1b, 0xcf, 0xd4, 0x37, 0x51, 0xc8, 0x8f, 0x0e, 0xfe, 0x06, 0xc9, 0x87, + 0xdf, 0x22, 0x33, 0x07, 0xc9, 0x8d, 0x82, 0x2e, 0x9b, 0xb3, 0xae, 0xa1, 0x34, 0x71, 0xed, 0x95, 0x7a, 0xed, 0x49, + 0xb3, 0xf6, 0x0a, 0x74, 0xa7, 0x36, 0xbc, 0x87, 0xb2, 0x9d, 0x05, 0x13, 0x74, 0x34, 0xbb, 0x03, 0x1d, 0xbc, 0x53, + 0x04, 0xbd, 0x4c, 0x42, 0xe3, 0x11, 0xaa, 0x8c, 0x7a, 0x61, 0x47, 0x76, 0xb3, 0x2e, 0x99, 0x67, 0xc0, 0x1c, 0xdb, + 0x73, 0x48, 0x0c, 0x73, 0x75, 0x50, 0xa7, 0xac, 0x1c, 0xe6, 0x78, 0x00, 0xaf, 0x99, 0x1c, 0x8a, 0x41, 0xae, 0x51, + 0xbe, 0x2f, 0x58, 0x31, 0x2c, 0x07, 0xb9, 0xe6, 0x66, 0xa6, 0xcd, 0xd8, 0xb4, 0x89, 0x0e, 0xcf, 0xbc, 0x62, 0x47, + 0xab, 0x1e, 0xf0, 0xb1, 0xe0, 0xc9, 0xec, 0x7b, 0x3e, 0xbe, 0x01, 0x4e, 0x66, 0x73, 0x1b, 0x2d, 0xe9, 0x5d, 0x94, + 0xd2, 0x9b, 0x68, 0x4d, 0x97, 0xd1, 0x85, 0x31, 0x31, 0x4e, 0x6a, 0x38, 0x07, 0xa0, 0x55, 0x00, 0x89, 0xa7, 0x7e, + 0xbd, 0xe7, 0x49, 0x15, 0x2e, 0x69, 0x0a, 0x6e, 0xc3, 0xbe, 0x7d, 0xe6, 0x95, 0x2f, 0x91, 0xda, 0x20, 0xc6, 0x9a, + 0x35, 0x54, 0xdc, 0x78, 0xeb, 0x3e, 0x12, 0x35, 0xec, 0x5c, 0x17, 0x9b, 0xa8, 0x1a, 0x4e, 0xa6, 0x25, 0x20, 0xb6, + 0x96, 0xc3, 0xa1, 0x3b, 0x42, 0x76, 0x8f, 0x1f, 0x1d, 0xe8, 0xb9, 0x27, 0x2d, 0xb6, 0x6d, 0xcb, 0x1f, 0x18, 0xc2, + 0x94, 0x7e, 0xfe, 0xc8, 0x07, 0xc4, 0x8a, 0x4b, 0x38, 0x1b, 0x81, 0x3a, 0x5a, 0xa1, 0xd3, 0xef, 0x55, 0x58, 0xe8, + 0x03, 0x7c, 0x73, 0x1b, 0x25, 0xf4, 0x2e, 0xca, 0x3d, 0xb2, 0xb6, 0xac, 0x99, 0x9c, 0x9e, 0x65, 0x21, 0x6f, 0x1f, + 0xe8, 0xe5, 0x02, 0x40, 0xb4, 0x06, 0xb1, 0x2f, 0x75, 0x3d, 0x00, 0xa7, 0x21, 0x34, 0x09, 0x8d, 0xe0, 0xaa, 0x82, + 0x30, 0x02, 0xae, 0x24, 0xfc, 0x0d, 0x26, 0x2a, 0xf0, 0x05, 0xb8, 0xc8, 0xa4, 0x69, 0xce, 0x83, 0xda, 0x1f, 0xc9, + 0xd3, 0xa2, 0xed, 0xed, 0x0a, 0xa3, 0x09, 0xc6, 0x9e, 0x68, 0x9f, 0x47, 0xca, 0x51, 0x5c, 0x24, 0x61, 0x36, 0xba, + 0x55, 0xe7, 0x39, 0xcd, 0x46, 0x77, 0xfa, 0x57, 0x45, 0xc7, 0xf4, 0x3b, 0x1d, 0xd0, 0x46, 0x49, 0xdf, 0x3a, 0xce, + 0x06, 0xb4, 0x5e, 0x2c, 0x8d, 0xff, 0xb5, 0x1c, 0xdd, 0x52, 0x39, 0xba, 0xf3, 0x2d, 0xa9, 0x26, 0xd3, 0xe2, 0x50, + 0xa0, 0x21, 0x55, 0xe7, 0xf7, 0x05, 0xf0, 0x73, 0xa5, 0xf1, 0x9d, 0x36, 0xdf, 0x7b, 0xed, 0x3f, 0xef, 0xe4, 0x09, + 0x14, 0x4b, 0x54, 0xb0, 0x6a, 0x04, 0x76, 0xec, 0xeb, 0x3c, 0x2e, 0xcc, 0x28, 0xc5, 0xd4, 0x9a, 0xf4, 0x63, 0xe0, + 0x8a, 0x69, 0xaf, 0x00, 0x57, 0xcb, 0xed, 0x56, 0xc5, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, + 0x36, 0xdc, 0x03, 0x62, 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, + 0x9d, 0xc7, 0x43, 0x9f, 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, + 0x3c, 0xd7, 0x5f, 0x69, 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, + 0x6e, 0x94, 0x79, 0x24, 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, + 0x3d, 0xf2, 0xa0, 0x9c, 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, + 0x12, 0x73, 0x27, 0x51, 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, + 0x13, 0x57, 0xe1, 0x5a, 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, + 0x1a, 0x56, 0x9a, 0x80, 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, + 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, + 0x02, 0x33, 0x57, 0x72, 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, + 0x5a, 0x62, 0x42, 0xb4, 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, + 0xda, 0x55, 0x20, 0xb4, 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, + 0xb2, 0x69, 0xc8, 0x5c, 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, + 0x2d, 0x3f, 0x82, 0x17, 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, + 0xb9, 0xdd, 0x96, 0x68, 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, + 0x2b, 0xd0, 0xf7, 0xf8, 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, + 0xfc, 0x4a, 0x76, 0xd6, 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, + 0x2d, 0x85, 0x05, 0xc7, 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, + 0xb2, 0x33, 0xd7, 0x07, 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, + 0xe1, 0xce, 0x3c, 0x6a, 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, + 0xf7, 0x7d, 0x58, 0x3d, 0xe6, 0x83, 0x5f, 0x70, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, + 0x53, 0xbe, 0xd0, 0xad, 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, + 0x18, 0xd7, 0xc0, 0x6d, 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, + 0x31, 0xf7, 0xa5, 0x6b, 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, + 0xe7, 0x91, 0xf9, 0x62, 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, + 0x43, 0x2f, 0x03, 0x17, 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, + 0xa8, 0x10, 0xac, 0xeb, 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x63, 0x20, + 0x9c, 0x5b, 0xa2, 0x67, 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, + 0x5f, 0xf0, 0x5a, 0x0a, 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, + 0x8a, 0xde, 0xbf, 0xe6, 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, + 0x4a, 0x50, 0xc9, 0x5a, 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, + 0x7c, 0x8e, 0x7e, 0x98, 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, + 0xc6, 0xf0, 0x60, 0x36, 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, + 0x7d, 0x89, 0x36, 0xaf, 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, + 0xab, 0x96, 0x8a, 0x06, 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, + 0x59, 0xda, 0xa6, 0xe8, 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, + 0x51, 0x6a, 0x37, 0x48, 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, + 0x1d, 0x47, 0x43, 0xbf, 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, + 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, + 0x4d, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, + 0xe9, 0xb9, 0x6e, 0xe7, 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, + 0xf5, 0x98, 0x15, 0xc3, 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, + 0xb4, 0x0b, 0xa4, 0x6d, 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, + 0xd8, 0x88, 0x7a, 0x7c, 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, + 0x5a, 0xb5, 0xb9, 0xfb, 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, + 0x5a, 0xb0, 0x9c, 0x75, 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, + 0x92, 0x67, 0x9a, 0xfe, 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, + 0x12, 0x57, 0xbe, 0xc2, 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, + 0x6e, 0x92, 0x1b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, + 0x28, 0x73, 0x13, 0x73, 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, + 0x3a, 0xd1, 0x5c, 0x86, 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, + 0xdc, 0xcc, 0x52, 0xb3, 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, + 0x2c, 0x0d, 0xd7, 0x28, 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, + 0x90, 0x8d, 0xd2, 0x38, 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, + 0x15, 0xdd, 0x96, 0x98, 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0xc5, 0xd0, 0xde, 0x1d, + 0x81, 0x51, 0xe5, 0x04, 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, + 0x24, 0x10, 0x18, 0x15, 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, + 0xb7, 0x88, 0x8e, 0xe9, 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, + 0x9e, 0xba, 0x14, 0xfd, 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, + 0xb2, 0x2a, 0x07, 0xed, 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, + 0x6f, 0xc4, 0xa8, 0xbd, 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, + 0x9f, 0x39, 0xb2, 0x33, 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, + 0xda, 0xcf, 0x9d, 0xe9, 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, + 0x35, 0xd5, 0xd1, 0x01, 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, + 0x53, 0x5b, 0x55, 0xc1, 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, + 0xa7, 0xa6, 0x3f, 0x68, 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, + 0x57, 0x95, 0x0f, 0xa0, 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, + 0x58, 0x4f, 0xe4, 0x79, 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, + 0x68, 0x2e, 0xa3, 0x09, 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, + 0x15, 0xdf, 0xc9, 0xf4, 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, + 0x73, 0xf0, 0xb4, 0xa6, 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, + 0xf9, 0x47, 0x97, 0x69, 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, + 0xa2, 0x0e, 0xbe, 0x39, 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, + 0x71, 0x7f, 0xfb, 0xfb, 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, + 0x7f, 0xab, 0x6b, 0xfa, 0x2b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, + 0x06, 0x90, 0x4b, 0xab, 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, + 0xe3, 0xac, 0x02, 0x38, 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x07, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, + 0x46, 0x45, 0x06, 0x3a, 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, + 0xc1, 0x44, 0x58, 0x10, 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, + 0x10, 0x44, 0x77, 0x91, 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, + 0x10, 0x14, 0xff, 0x86, 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, + 0x82, 0x06, 0xba, 0xed, 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, + 0xf5, 0x5f, 0x0d, 0xeb, 0xe8, 0xc2, 0x8f, 0xfe, 0x6a, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, + 0x0c, 0xa4, 0x8b, 0xe3, 0x76, 0x9c, 0xcd, 0x7f, 0x9d, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, + 0xd2, 0xce, 0x07, 0x6f, 0x8e, 0x7f, 0x3f, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, + 0x0a, 0xee, 0xae, 0xe6, 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, + 0x40, 0x0e, 0x99, 0x85, 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, + 0x6f, 0xb9, 0x0d, 0xb2, 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, + 0xce, 0xe6, 0xc5, 0xc2, 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, + 0xa6, 0x51, 0x85, 0x6b, 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, + 0x03, 0x3a, 0x98, 0x50, 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x75, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, + 0x54, 0x5e, 0xc9, 0x6b, 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, + 0x93, 0x4b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, + 0x7c, 0x2e, 0x16, 0x11, 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, + 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, + 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, + 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, + 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, + 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, + 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, + 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, + 0xb3, 0x5c, 0x1d, 0x7a, 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, + 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, 0x42, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, + 0x91, 0x9e, 0x67, 0x9f, 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, + 0x3f, 0x57, 0x1c, 0xaf, 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, + 0x97, 0x3c, 0xac, 0x46, 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, + 0xff, 0x0a, 0x99, 0x8c, 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, + 0x93, 0x66, 0xa1, 0x4c, 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, + 0xf7, 0xd0, 0xe1, 0xff, 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, + 0x7d, 0x33, 0xf1, 0x0b, 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, + 0xc3, 0x76, 0x8b, 0x0b, 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, + 0x67, 0x6a, 0x98, 0x93, 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, + 0xd0, 0x5e, 0xec, 0x67, 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, + 0x1e, 0x83, 0xf7, 0x06, 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, + 0xb7, 0x95, 0xf1, 0xb7, 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, + 0x5a, 0x60, 0xf8, 0xec, 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, + 0xac, 0x01, 0x88, 0xe4, 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, + 0xeb, 0x60, 0xe2, 0x4c, 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, + 0xa9, 0x42, 0xa9, 0x36, 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, + 0x67, 0xf7, 0xb9, 0xed, 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, + 0x15, 0x63, 0x8c, 0xde, 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, + 0xc5, 0xf5, 0xf2, 0x4b, 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, + 0x5d, 0x69, 0x64, 0x20, 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, + 0x6d, 0x09, 0x1d, 0xb2, 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, + 0x0b, 0x67, 0x59, 0x1c, 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, + 0x81, 0xdd, 0xc9, 0xe9, 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, + 0x42, 0x9b, 0xeb, 0xfa, 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, + 0xfa, 0x40, 0x39, 0x96, 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, + 0xb1, 0x00, 0x58, 0xe8, 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, + 0xee, 0x8a, 0x65, 0x58, 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, + 0x6a, 0x0c, 0x20, 0x72, 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, + 0x5e, 0x4f, 0x4a, 0x02, 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, + 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, + 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, + 0xfb, 0xbf, 0x99, 0x2c, 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, + 0x82, 0xc0, 0x70, 0xc3, 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, + 0x1a, 0x33, 0x3a, 0x78, 0x06, 0xa0, 0xb0, 0x10, 0x10, 0x7d, 0x0c, 0x32, 0x5a, 0x01, 0xbf, 0x85, 0xfa, 0xdd, 0x3a, + 0xf1, 0x7d, 0xe8, 0x57, 0x41, 0x2f, 0x62, 0x60, 0x38, 0xa2, 0xc9, 0x7e, 0xc8, 0x07, 0x93, 0x01, 0x68, 0x4b, 0xbc, + 0xdd, 0xd7, 0xd2, 0x8a, 0x9b, 0xd3, 0xa5, 0xd3, 0xfd, 0x93, 0x36, 0x41, 0x12, 0xa9, 0x64, 0xa5, 0x22, 0x06, 0x10, + 0xca, 0x52, 0x6d, 0x93, 0x25, 0x58, 0x56, 0x98, 0x25, 0xcd, 0x0d, 0x4a, 0xe2, 0xee, 0x66, 0xe0, 0x18, 0x35, 0xeb, + 0x38, 0x2c, 0x5b, 0x6e, 0xd4, 0x00, 0x9f, 0x93, 0xb0, 0xc2, 0xde, 0x70, 0x66, 0xd2, 0x3b, 0xd3, 0xe1, 0xea, 0x98, + 0xb3, 0x37, 0x1c, 0xc1, 0x38, 0x12, 0xbc, 0xf1, 0xd0, 0x25, 0xd3, 0x50, 0x91, 0x29, 0xe3, 0x60, 0xda, 0x03, 0xdc, + 0x7b, 0x0e, 0xc6, 0x61, 0x6c, 0x50, 0x59, 0x52, 0x9f, 0x7a, 0x77, 0x21, 0x10, 0xa4, 0xb5, 0x5e, 0xe6, 0x33, 0x3c, + 0x3d, 0x23, 0x94, 0xfd, 0x21, 0x87, 0x2f, 0xc0, 0x8e, 0x82, 0x1c, 0x4d, 0xf8, 0xb3, 0xc7, 0xbb, 0x81, 0xaa, 0xf8, + 0x20, 0xd8, 0x8b, 0x45, 0xba, 0x17, 0x0c, 0x04, 0xfc, 0x2a, 0xf8, 0x5e, 0x25, 0xe5, 0xde, 0x45, 0x5c, 0xec, 0xc5, + 0xab, 0xb8, 0xa8, 0xf6, 0x6e, 0xb2, 0x6a, 0xb9, 0x67, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x7b, 0xc1, + 0xa0, 0x30, 0x53, 0xbb, 0x62, 0x65, 0xe3, 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, + 0xea, 0x9a, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, 0x88, 0xe9, 0x1a, 0xfa, 0x00, 0x3c, 0xf2, 0x9a, 0xc6, 0xb0, 0x04, 0x2e, + 0x06, 0x03, 0xb2, 0x86, 0xc8, 0x05, 0x6b, 0x6a, 0x83, 0x38, 0x84, 0x6b, 0x65, 0xa7, 0xbd, 0x0b, 0xcc, 0xb4, 0xdd, + 0x02, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, 0x1b, 0xea, 0x5f, 0xb0, 0x97, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, + 0xe6, 0xfb, 0x92, 0x1d, 0x0d, 0x54, 0xc4, 0xe1, 0x1d, 0x47, 0x8a, 0x36, 0x2a, 0x97, 0x65, 0x4f, 0x96, 0x0d, 0x5f, + 0x89, 0x2b, 0xee, 0xfc, 0xb8, 0x2a, 0x29, 0xf3, 0x2a, 0x5b, 0x29, 0xf6, 0x6f, 0xc6, 0x35, 0xf7, 0x07, 0xd6, 0x9f, + 0xcd, 0x57, 0x70, 0x6d, 0xf5, 0xde, 0x35, 0xb9, 0x46, 0xe4, 0x2c, 0xa1, 0x5c, 0x52, 0xdb, 0x3c, 0xbc, 0xa5, 0xef, + 0xf3, 0xab, 0x6f, 0x33, 0x9d, 0xc6, 0x67, 0x15, 0x16, 0x2e, 0x44, 0x2b, 0x82, 0x43, 0x43, 0x2e, 0x9a, 0x47, 0x80, + 0xb9, 0xf6, 0xd9, 0x0a, 0x0a, 0x52, 0x9f, 0x55, 0xe8, 0xdd, 0x0a, 0x09, 0xaf, 0x34, 0xbb, 0xf4, 0x30, 0x90, 0x32, + 0x6e, 0x0f, 0x2d, 0x61, 0xd2, 0xf2, 0x22, 0xbc, 0xf7, 0x9a, 0x9b, 0xdc, 0x8b, 0x10, 0xa3, 0x17, 0x79, 0x76, 0x02, + 0xc6, 0xba, 0x4b, 0x76, 0x36, 0x3c, 0xf1, 0x1b, 0x9e, 0xb3, 0x16, 0x8d, 0xa6, 0x4b, 0x96, 0xf4, 0xfb, 0x31, 0x98, + 0x78, 0xa7, 0x2c, 0x87, 0x5f, 0xf9, 0x82, 0xae, 0x19, 0x60, 0x8a, 0xd1, 0x0b, 0x48, 0x48, 0x11, 0x89, 0x64, 0xad, + 0x4e, 0x92, 0xcf, 0x74, 0x17, 0x80, 0xd1, 0x2f, 0x66, 0x69, 0xb4, 0xbc, 0xd7, 0xcc, 0x02, 0xc9, 0x33, 0xf4, 0x5d, + 0x07, 0xdb, 0x1b, 0xfb, 0x20, 0xe5, 0xfc, 0x50, 0x4c, 0x07, 0x03, 0x4e, 0x34, 0xdc, 0x78, 0xa9, 0xc4, 0xb5, 0xba, + 0xc5, 0x1d, 0xc3, 0x58, 0xea, 0xdb, 0x22, 0x06, 0x07, 0xec, 0xa2, 0x95, 0xdd, 0x3e, 0xc0, 0xbe, 0x72, 0xbc, 0x4b, + 0x95, 0xdd, 0xe9, 0x31, 0xd3, 0x5c, 0xb6, 0x9a, 0x74, 0x52, 0x71, 0x3f, 0x91, 0x6f, 0x72, 0x07, 0x5d, 0x2e, 0xc7, + 0x9a, 0xb7, 0x1c, 0x80, 0x8a, 0x7e, 0xa4, 0xa8, 0xee, 0x17, 0x38, 0xc2, 0x3c, 0x58, 0xb7, 0xf9, 0x64, 0xdf, 0x14, + 0x38, 0x44, 0x9e, 0xb4, 0xd1, 0x14, 0xd0, 0xbd, 0x8b, 0xc7, 0x5d, 0xfd, 0xb6, 0x74, 0x17, 0x28, 0xd1, 0x4e, 0xc5, + 0x0d, 0x3f, 0x26, 0xea, 0x74, 0xa6, 0x0d, 0xa1, 0x7f, 0x65, 0xc4, 0xfd, 0xa5, 0x71, 0x15, 0x6f, 0x7a, 0x97, 0xcf, + 0x38, 0xd4, 0xd9, 0x0d, 0xa1, 0x00, 0x5c, 0xb5, 0xa7, 0x53, 0x37, 0x86, 0xf4, 0x4a, 0x89, 0x6e, 0x83, 0x83, 0xdd, + 0xeb, 0x33, 0x8e, 0xa2, 0x1f, 0xa3, 0x46, 0xbe, 0x89, 0xc4, 0x63, 0x39, 0x88, 0x1f, 0x17, 0x74, 0x19, 0x89, 0xc7, + 0xc5, 0x20, 0x7e, 0x2c, 0xeb, 0x7a, 0xf7, 0x5c, 0xb9, 0xbf, 0x8f, 0xc8, 0xb3, 0xee, 0xec, 0xa5, 0x12, 0x36, 0x06, + 0x9e, 0x5d, 0x0b, 0x08, 0xa7, 0xe0, 0x89, 0x6c, 0x2d, 0x7d, 0xe8, 0xdc, 0xee, 0x63, 0xcb, 0x24, 0x41, 0xd0, 0xf3, + 0x36, 0x9b, 0x44, 0xb1, 0xb3, 0xcd, 0xa3, 0x0f, 0xa7, 0x40, 0x42, 0xb7, 0xdb, 0x66, 0x5d, 0xad, 0x01, 0xc5, 0x34, + 0x1c, 0xf3, 0xfd, 0x62, 0x74, 0xe3, 0xbb, 0xeb, 0xef, 0x17, 0xa3, 0x25, 0x19, 0x4e, 0xcc, 0xe4, 0xc7, 0x47, 0xe3, + 0x59, 0x1c, 0x4d, 0xea, 0x8e, 0xd3, 0x42, 0xe3, 0x9f, 0x7a, 0xb7, 0x50, 0x04, 0x4e, 0xc5, 0x08, 0x8e, 0x9c, 0x0a, + 0xe5, 0xa4, 0xd4, 0xc0, 0xf0, 0xdf, 0xab, 0x76, 0xb4, 0x69, 0x6f, 0xe2, 0x2a, 0x59, 0x66, 0xe2, 0x52, 0x87, 0x0f, + 0xd7, 0xd1, 0xc5, 0x6d, 0x40, 0x3b, 0xef, 0x32, 0xed, 0xf8, 0x75, 0xd2, 0xa0, 0x27, 0xae, 0x66, 0x06, 0xdc, 0xba, + 0x1f, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, 0xc4, 0xdc, 0xfe, 0x4d, 0xd9, 0xfc, 0x2a, 0xda, 0xe7, 0xc8, 0x48, + 0xd9, 0x26, 0x23, 0x15, 0x18, 0x61, 0x4a, 0x91, 0xc4, 0x55, 0x08, 0x81, 0xec, 0xbf, 0xa4, 0xb8, 0x16, 0x4b, 0xef, + 0x35, 0x08, 0x13, 0x6c, 0x17, 0xb4, 0x5f, 0xdd, 0xce, 0x6d, 0xa5, 0xc5, 0x1e, 0xa9, 0xef, 0x73, 0x67, 0xbb, 0xa2, + 0xc9, 0xdf, 0x97, 0x0d, 0x68, 0x03, 0x88, 0xf2, 0xbe, 0x3e, 0x2a, 0x81, 0x93, 0x11, 0x37, 0x94, 0x18, 0xbd, 0xa0, + 0xab, 0x13, 0xb9, 0x67, 0xa7, 0xe6, 0x4d, 0xc5, 0x4c, 0xc5, 0x95, 0x6f, 0xf6, 0xcc, 0x7f, 0x30, 0x14, 0x54, 0x80, + 0x81, 0xb7, 0x39, 0xe3, 0xd1, 0x81, 0xee, 0xc6, 0xe8, 0xb4, 0x60, 0xb3, 0xa0, 0x2e, 0xeb, 0xa6, 0x8d, 0x07, 0x8d, + 0x38, 0x28, 0x8a, 0x55, 0xa1, 0x46, 0xc2, 0x13, 0x81, 0x80, 0x29, 0xbb, 0xe2, 0x91, 0x11, 0xd4, 0xf4, 0x26, 0x14, + 0x36, 0x14, 0xfc, 0x55, 0xa2, 0x9a, 0xde, 0x84, 0x36, 0x99, 0x38, 0xcd, 0x20, 0x82, 0x19, 0xb1, 0xdd, 0x6f, 0x01, + 0x6d, 0x6e, 0xcd, 0x68, 0x53, 0xd7, 0x56, 0x5b, 0x85, 0x5c, 0x52, 0xa4, 0x2c, 0xff, 0x9d, 0x9a, 0x0a, 0x4a, 0x6a, + 0xb9, 0xe8, 0x4d, 0x9a, 0x2e, 0x7a, 0x3c, 0x33, 0x92, 0x40, 0xe5, 0x96, 0x3b, 0x46, 0x7f, 0x08, 0x0b, 0x3c, 0x62, + 0xe2, 0xc4, 0x82, 0xb9, 0xd5, 0x11, 0xcb, 0xe6, 0x62, 0x31, 0x5a, 0x49, 0x08, 0x1b, 0x7c, 0xc8, 0xb2, 0x79, 0xa9, + 0x1f, 0x42, 0x5f, 0x58, 0x7a, 0x02, 0x76, 0xb1, 0xc1, 0x4a, 0x96, 0x01, 0xf8, 0x5e, 0xd0, 0xcd, 0x4a, 0x96, 0x91, + 0x54, 0xdd, 0x8f, 0x6b, 0x2c, 0x41, 0xa5, 0x15, 0x2a, 0x2d, 0xa9, 0xb1, 0x20, 0xf0, 0x55, 0xd5, 0xe5, 0x43, 0xb2, + 0xab, 0x40, 0x3d, 0x75, 0xd4, 0x80, 0x53, 0xa0, 0xaa, 0xc0, 0x82, 0x24, 0xa8, 0x0c, 0x5d, 0x15, 0x98, 0x56, 0x60, + 0x9a, 0xa9, 0xc2, 0x45, 0x99, 0x1d, 0x4a, 0xb3, 0x5e, 0xf2, 0x59, 0x3c, 0x08, 0x93, 0x61, 0x4c, 0x1e, 0x23, 0xd4, + 0xfe, 0x7e, 0x1e, 0xc5, 0x5a, 0x2e, 0xb9, 0x72, 0x7e, 0xf1, 0x37, 0x9f, 0xb1, 0xd7, 0x3d, 0xc3, 0x60, 0x01, 0xce, + 0xd2, 0xf6, 0x2a, 0x13, 0xef, 0x64, 0x2b, 0x38, 0x0e, 0x66, 0x51, 0x0e, 0xab, 0x9e, 0x1c, 0xd1, 0x5c, 0xe4, 0xda, + 0xbb, 0x08, 0x91, 0x83, 0xcc, 0x1e, 0x03, 0xec, 0x46, 0xf8, 0x3a, 0xb4, 0x36, 0xb7, 0xba, 0x42, 0xfc, 0x8d, 0x12, + 0x89, 0x9f, 0xa5, 0xfc, 0xb8, 0x5e, 0xa9, 0x5c, 0x95, 0xc1, 0x63, 0xd5, 0xcd, 0xe0, 0x99, 0xf6, 0x3d, 0xd6, 0xfe, + 0xad, 0xed, 0xe6, 0x78, 0xef, 0xc1, 0x83, 0xd6, 0xff, 0xd6, 0x93, 0x10, 0xda, 0x2b, 0x27, 0xa9, 0x3b, 0x6a, 0xf4, + 0xcc, 0x64, 0x8d, 0xa8, 0x84, 0xa9, 0xdd, 0xa9, 0x1c, 0x03, 0x35, 0x1d, 0xc0, 0xb5, 0x44, 0x4d, 0xd0, 0x93, 0x82, + 0x8d, 0xe1, 0x88, 0xb3, 0x38, 0x68, 0x87, 0x31, 0x8a, 0x97, 0x73, 0x25, 0x5e, 0xce, 0x8f, 0x18, 0x07, 0x68, 0x2d, + 0x40, 0xaa, 0xd7, 0xb0, 0x9f, 0xb9, 0x82, 0x05, 0x36, 0x77, 0xbe, 0x03, 0x0b, 0x64, 0x88, 0x93, 0xcd, 0x71, 0xb2, + 0xc7, 0xb5, 0x9e, 0x7b, 0x81, 0x8f, 0x93, 0x7a, 0xe1, 0xd5, 0x55, 0xb6, 0xeb, 0x5a, 0xb2, 0x72, 0x5e, 0x0c, 0x26, + 0x10, 0x94, 0xa5, 0x9c, 0x17, 0xc3, 0xc9, 0x82, 0xe6, 0xf0, 0x63, 0xd1, 0x40, 0x87, 0x58, 0x0e, 0x12, 0xb8, 0x74, + 0xf6, 0x18, 0xf0, 0x86, 0x52, 0x8b, 0xbb, 0xb1, 0x8e, 0x1c, 0xeb, 0x28, 0xf6, 0xc3, 0x18, 0x70, 0x65, 0x9d, 0xc0, + 0xfb, 0xfe, 0xeb, 0x63, 0x13, 0x90, 0x55, 0xbb, 0xc2, 0xab, 0x51, 0xee, 0xba, 0xd2, 0xe8, 0x4b, 0x4a, 0x4f, 0x78, + 0xc1, 0x53, 0xc9, 0x76, 0xdb, 0x33, 0x70, 0xb6, 0xc4, 0x43, 0xe2, 0x1d, 0x23, 0x7a, 0x31, 0x6d, 0x64, 0xe6, 0x04, + 0xce, 0x6c, 0x77, 0xd9, 0xc6, 0xfc, 0xd8, 0x01, 0x0e, 0x16, 0x41, 0x48, 0xdc, 0x10, 0x86, 0x89, 0x1d, 0x95, 0x43, + 0x2d, 0x84, 0xeb, 0x5a, 0x78, 0x1d, 0xa7, 0x65, 0x0c, 0x2e, 0xd2, 0xda, 0x36, 0xf1, 0x1e, 0xba, 0xee, 0xf9, 0x31, + 0xb7, 0x3a, 0x46, 0x5b, 0x48, 0xbf, 0x1d, 0x9d, 0xde, 0x73, 0x18, 0x80, 0xa6, 0x07, 0xb3, 0xaa, 0x7d, 0x26, 0x71, + 0x73, 0xda, 0x09, 0x42, 0x22, 0x10, 0x45, 0xe9, 0x8c, 0x30, 0xfd, 0x3b, 0xcd, 0x65, 0x15, 0xad, 0x1e, 0xe4, 0x99, + 0x43, 0x9e, 0x85, 0xde, 0xf6, 0xa0, 0x55, 0x73, 0x37, 0x18, 0x27, 0x6e, 0xb7, 0x77, 0xfe, 0xdf, 0xb2, 0xae, 0xad, + 0xd6, 0x88, 0xc7, 0xed, 0xea, 0x07, 0x8d, 0xbd, 0xda, 0x53, 0x31, 0x60, 0x56, 0xd2, 0x3b, 0xa3, 0x4a, 0x5e, 0x64, + 0xbc, 0xc4, 0x93, 0x6a, 0xd5, 0xf0, 0xf1, 0xbe, 0xc9, 0x46, 0xe6, 0x81, 0x4c, 0x01, 0xf1, 0xfc, 0x26, 0x35, 0xea, + 0xe3, 0x14, 0x25, 0xe0, 0xef, 0x74, 0x7c, 0x23, 0xfa, 0xd1, 0xbe, 0xb8, 0xe4, 0xd5, 0xc9, 0x8d, 0x30, 0x2f, 0x5e, + 0x58, 0x9d, 0x3f, 0x7d, 0x53, 0xf8, 0xd0, 0xe1, 0xa8, 0xbd, 0x83, 0x22, 0x4b, 0x26, 0x8e, 0x26, 0x46, 0xd6, 0x26, + 0x66, 0x1f, 0x15, 0x5c, 0x4c, 0x54, 0xa1, 0x67, 0x9d, 0x3d, 0x61, 0x0a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x16, + 0x0c, 0xd4, 0x69, 0x4a, 0x88, 0x1e, 0x8a, 0x19, 0xc6, 0x2b, 0x06, 0x50, 0x98, 0x42, 0x81, 0x28, 0x3a, 0xfb, 0x70, + 0xa0, 0x09, 0xfd, 0xfe, 0x4d, 0xaa, 0x33, 0xd0, 0xb2, 0x9e, 0x4a, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, + 0x2e, 0x69, 0x99, 0xd1, 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, + 0x21, 0xec, 0xff, 0x6a, 0xd0, 0xf5, 0x56, 0xac, 0x35, 0xb4, 0x3b, 0x41, 0x46, 0x68, 0xbe, 0xd0, 0x41, 0xc8, 0x50, + 0x39, 0x09, 0x5d, 0xab, 0x34, 0x5e, 0x81, 0x4b, 0xa6, 0xd9, 0x68, 0x19, 0x97, 0x61, 0x60, 0xbf, 0x0a, 0x2c, 0x26, + 0x07, 0x26, 0x9d, 0xae, 0xcf, 0x9f, 0xcb, 0xab, 0x95, 0x14, 0x5c, 0x54, 0x0a, 0xa2, 0xdf, 0xe0, 0xbe, 0x9b, 0xb8, + 0xea, 0xac, 0x59, 0x2b, 0x7d, 0xe8, 0x5b, 0x9f, 0xb5, 0x71, 0x5f, 0x18, 0x1c, 0x83, 0x9d, 0x8f, 0x88, 0x81, 0x34, + 0xa8, 0x74, 0x8b, 0x43, 0x13, 0xa0, 0x4b, 0x87, 0x14, 0xb2, 0x64, 0x2a, 0x53, 0x25, 0xa8, 0xf8, 0xc6, 0xef, 0xa5, + 0xac, 0x46, 0x7f, 0xad, 0x79, 0x71, 0x77, 0xca, 0x73, 0x8e, 0x63, 0x14, 0x24, 0xb1, 0xb8, 0x8e, 0xcb, 0x80, 0xf8, + 0x96, 0x57, 0xc1, 0x41, 0x6a, 0xc2, 0xc6, 0xec, 0x54, 0x8d, 0x5a, 0x2f, 0x89, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, + 0x13, 0x51, 0x05, 0x7d, 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, + 0x6e, 0x98, 0x08, 0x41, 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, + 0xf1, 0x39, 0x73, 0xa1, 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, + 0xd9, 0x91, 0x76, 0x69, 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, + 0x2a, 0xce, 0xc4, 0x71, 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, + 0x61, 0x30, 0x35, 0x15, 0xf7, 0xd8, 0x19, 0x5c, 0x54, 0x7f, 0x44, 0x4b, 0x89, 0xb1, 0x50, 0x75, 0xf1, 0xf1, 0x79, + 0x29, 0xf3, 0x75, 0x05, 0xda, 0xdd, 0x8b, 0x2a, 0x3a, 0x78, 0xba, 0xba, 0x9d, 0xaa, 0x1b, 0x4c, 0xf4, 0xf4, 0x60, + 0x75, 0xdb, 0xcb, 0xae, 0x56, 0xb2, 0xa8, 0x62, 0x51, 0x4d, 0x15, 0x22, 0x59, 0x12, 0xe7, 0x49, 0x38, 0x19, 0x8f, + 0xbf, 0xda, 0x1b, 0xee, 0x41, 0x06, 0x32, 0xfd, 0x34, 0x54, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x95, 0xea, 0x6e, + 0x17, 0x8d, 0x26, 0x35, 0xd6, 0x33, 0x4c, 0xf4, 0xcc, 0x8c, 0xf8, 0xed, 0x2a, 0x16, 0x29, 0xc4, 0xaf, 0xd3, 0xc5, + 0x1f, 0x3c, 0x1d, 0x37, 0xca, 0xb7, 0x9f, 0x3e, 0xab, 0xff, 0xa8, 0x4d, 0x58, 0x6b, 0xd3, 0xee, 0xe7, 0x7f, 0x1c, + 0xaa, 0xf9, 0x3e, 0x3a, 0xdc, 0xd7, 0x3f, 0xfe, 0xa8, 0xeb, 0xe9, 0x9b, 0x22, 0x9c, 0xff, 0x33, 0x54, 0xf3, 0x79, + 0x5c, 0x14, 0xf1, 0x5d, 0x0d, 0x91, 0x3c, 0x85, 0xf3, 0x26, 0xa1, 0xde, 0x36, 0xa0, 0x07, 0x64, 0x7a, 0x21, 0x18, + 0x7c, 0xf3, 0xbe, 0x0a, 0x03, 0x5e, 0xae, 0x86, 0x5c, 0x54, 0x59, 0x75, 0x37, 0xc4, 0x3c, 0x01, 0x7e, 0x6a, 0x78, + 0xb3, 0xe7, 0x85, 0x21, 0x36, 0x17, 0x05, 0xe7, 0x9f, 0x78, 0xa8, 0x8c, 0xa3, 0xc7, 0x68, 0x1c, 0x3d, 0xa6, 0x6a, + 0x30, 0x26, 0xdf, 0x50, 0xdd, 0x99, 0xc9, 0x37, 0x60, 0x82, 0x94, 0xb5, 0xbf, 0x51, 0xc6, 0x89, 0xd1, 0x98, 0x5e, + 0xbf, 0xca, 0xb3, 0x15, 0x30, 0xc1, 0x4b, 0xfd, 0xa3, 0x26, 0xf4, 0x3d, 0x6f, 0x67, 0x1f, 0x8d, 0x46, 0xcf, 0x0b, + 0x3a, 0x1a, 0x8d, 0x3e, 0x66, 0x35, 0xa1, 0x2b, 0xd1, 0xf1, 0xfe, 0x3d, 0xa7, 0xe7, 0x32, 0xbd, 0x8b, 0x82, 0x80, + 0x2e, 0xb3, 0x34, 0xe5, 0x42, 0x95, 0x75, 0x9a, 0xb6, 0xf3, 0xaa, 0x16, 0x22, 0xf0, 0x8f, 0x6e, 0x23, 0x42, 0x10, + 0x11, 0x7a, 0xb2, 0xd3, 0xb3, 0xd1, 0x68, 0x74, 0x9a, 0x9a, 0x6a, 0x1d, 0x43, 0xfe, 0x06, 0xcd, 0x07, 0x9c, 0x5d, + 0x3e, 0x58, 0xdf, 0x98, 0x68, 0x27, 0xfb, 0xff, 0x3d, 0x9c, 0xcd, 0xc7, 0xc3, 0x6f, 0x47, 0x8b, 0xc7, 0xfb, 0x34, + 0x08, 0x7c, 0xd0, 0xea, 0x50, 0x5b, 0x73, 0x4c, 0xcb, 0xc3, 0xf1, 0x94, 0x94, 0x03, 0xf6, 0xd4, 0xfa, 0xd2, 0x7c, + 0xf5, 0x14, 0x90, 0x48, 0x51, 0x84, 0x1a, 0x38, 0xe9, 0x1f, 0x5e, 0x45, 0x5e, 0x0b, 0xc0, 0x47, 0xb3, 0x91, 0x0c, + 0x8c, 0x16, 0x70, 0x1c, 0x41, 0x79, 0xb5, 0x35, 0x8d, 0xe8, 0x31, 0x96, 0x99, 0xa8, 0xa0, 0xe3, 0x69, 0x79, 0x93, + 0x55, 0xc9, 0x12, 0x03, 0x1b, 0xc5, 0x25, 0x0f, 0xbe, 0x0a, 0xa2, 0x92, 0x1d, 0x3c, 0x9b, 0x2a, 0x78, 0x5f, 0x4c, + 0x4a, 0xf9, 0x25, 0x24, 0x7e, 0x3b, 0x46, 0x08, 0x54, 0xa2, 0x3d, 0x16, 0xb1, 0xc6, 0x57, 0xb9, 0x8c, 0xc1, 0x83, + 0xb3, 0xd4, 0x3c, 0x8b, 0x3d, 0x09, 0xac, 0xfd, 0x45, 0xab, 0x39, 0x12, 0x9a, 0x13, 0x4a, 0x26, 0xf7, 0x4b, 0x2a, + 0xbf, 0x9a, 0xa0, 0x57, 0x10, 0xb8, 0x55, 0x47, 0x70, 0xdc, 0x59, 0xcb, 0x06, 0xbd, 0x7c, 0x52, 0xb6, 0x3f, 0xff, + 0xdf, 0x25, 0x5d, 0x0c, 0xf6, 0xdd, 0xd0, 0x9c, 0x68, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x9e, 0x12, 0x6b, + 0x7c, 0xca, 0xd9, 0xd1, 0xc6, 0x74, 0x67, 0x54, 0x15, 0xd9, 0x55, 0x48, 0x74, 0xaf, 0x1c, 0x28, 0x66, 0x10, 0x65, + 0x23, 0x5c, 0x3f, 0x60, 0x2d, 0xe2, 0x75, 0xf2, 0x9a, 0x17, 0x55, 0x96, 0xa8, 0xf7, 0xd7, 0x8d, 0xf7, 0x40, 0x0d, + 0x54, 0x83, 0xde, 0x15, 0x0c, 0xe6, 0xf9, 0xa4, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, + 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, + 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xae, 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, + 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x93, 0x86, 0x10, + 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, 0x9e, 0xe0, 0xa9, 0x1a, 0x06, 0x17, 0x79, 0xb6, 0xd2, 0x49, 0xd5, 0xa8, + 0xa3, 0xf9, 0x50, 0x6a, 0x47, 0x72, 0x40, 0xbd, 0xf4, 0x18, 0xd3, 0x0b, 0x95, 0xae, 0x8a, 0x72, 0x46, 0x28, 0xef, + 0xf4, 0xc4, 0xb8, 0x30, 0x7d, 0x1c, 0x22, 0xbf, 0xbc, 0x2b, 0x54, 0xe8, 0x17, 0xbe, 0x00, 0xf0, 0x2b, 0xb8, 0xdd, + 0xef, 0xc6, 0x77, 0x51, 0xd9, 0xcf, 0x38, 0xdb, 0xff, 0xef, 0x79, 0x3c, 0xfc, 0x34, 0x1e, 0x7e, 0xbb, 0x18, 0x84, + 0x43, 0xfb, 0x93, 0x3c, 0x7e, 0xb4, 0x4f, 0x5f, 0x71, 0xcb, 0x95, 0xc0, 0xc2, 0x6f, 0x04, 0xb7, 0x51, 0x2b, 0x21, + 0x88, 0x02, 0xbc, 0x51, 0xb8, 0xd5, 0x38, 0x01, 0x80, 0xbf, 0xe0, 0xbf, 0x02, 0x34, 0x12, 0x72, 0x17, 0x0d, 0xd0, + 0x0f, 0xa8, 0xdf, 0x47, 0x4f, 0x1a, 0x06, 0x72, 0x20, 0x9e, 0x50, 0x31, 0x50, 0x88, 0x2e, 0x63, 0xa2, 0x60, 0x7f, + 0x6d, 0xf6, 0xed, 0xb6, 0xd7, 0x96, 0xfc, 0xe0, 0x97, 0x7e, 0xa6, 0x89, 0x99, 0x77, 0xb8, 0xa1, 0xac, 0xe4, 0x2a, + 0x44, 0x6c, 0x3c, 0xfd, 0x2b, 0x67, 0x10, 0x6b, 0xf2, 0x3a, 0x03, 0x1f, 0x06, 0xfb, 0xc5, 0x78, 0x06, 0x6c, 0x03, + 0xdc, 0x71, 0x0a, 0x7e, 0x91, 0x81, 0x5b, 0xb3, 0x88, 0xf1, 0x82, 0x6d, 0x97, 0x44, 0xbf, 0xdf, 0xcb, 0xb3, 0x30, + 0xd7, 0x38, 0xcb, 0x79, 0x6d, 0xc4, 0xee, 0xa8, 0x13, 0x06, 0x71, 0xbb, 0x1e, 0x82, 0xa1, 0x1a, 0x82, 0xa2, 0xa3, + 0x2d, 0xae, 0x5e, 0x5b, 0x4f, 0x61, 0x7a, 0xab, 0xea, 0x2b, 0x46, 0x7f, 0xca, 0x4c, 0x60, 0x21, 0xed, 0x9a, 0x63, + 0x5d, 0x73, 0x8c, 0xb4, 0xa7, 0xdf, 0x17, 0x0d, 0xf2, 0xd3, 0x59, 0x78, 0x10, 0xa8, 0x52, 0xe5, 0x4e, 0x59, 0x94, + 0xdb, 0xd2, 0xbc, 0x31, 0xac, 0x69, 0x9e, 0xd9, 0xb8, 0x2e, 0xb3, 0x5e, 0x2f, 0x0c, 0xd1, 0xa1, 0x11, 0x4b, 0xc5, + 0xda, 0x20, 0xbc, 0x8f, 0x49, 0x18, 0x5d, 0x81, 0xac, 0x2e, 0x3c, 0xe3, 0x04, 0xf9, 0x32, 0x30, 0x59, 0x53, 0xd5, + 0x7a, 0x39, 0xe1, 0xb1, 0x91, 0x2f, 0x1b, 0x41, 0x83, 0xbc, 0xa4, 0xa8, 0x37, 0x71, 0x3b, 0xf6, 0x51, 0x0b, 0xa9, + 0x71, 0x53, 0x4f, 0x7b, 0x9a, 0x54, 0xf4, 0x58, 0xaf, 0x52, 0xbf, 0xc0, 0xb2, 0xc0, 0x92, 0x0f, 0x42, 0x7b, 0x9a, + 0x56, 0x60, 0x86, 0x6b, 0x9b, 0xc1, 0xd0, 0x0f, 0x87, 0xb6, 0x08, 0x9d, 0x51, 0xdb, 0x12, 0xc2, 0xb6, 0x0d, 0xc2, + 0xca, 0x7b, 0x22, 0x5f, 0x3d, 0xf5, 0x18, 0xe1, 0x90, 0x9b, 0xcd, 0x2c, 0x1a, 0x18, 0xe6, 0x57, 0xb2, 0xd9, 0x3c, + 0xdd, 0x5c, 0x2f, 0x2a, 0xa6, 0x80, 0xed, 0xb6, 0x12, 0x04, 0xff, 0x7e, 0xcc, 0x66, 0xf8, 0x37, 0xeb, 0xf7, 0x7b, + 0x21, 0xfe, 0xe2, 0x18, 0xbc, 0x67, 0x2e, 0x16, 0xec, 0x23, 0xc8, 0x54, 0x48, 0x84, 0xa9, 0xca, 0xf8, 0x8d, 0x55, + 0x60, 0x01, 0x67, 0x3e, 0x50, 0xb9, 0x30, 0x93, 0xbd, 0xbc, 0xb8, 0x86, 0x1c, 0xb7, 0xc6, 0x29, 0x1b, 0x65, 0x89, + 0x72, 0x5d, 0xc8, 0x46, 0x71, 0x9e, 0xc5, 0x25, 0x2f, 0xb7, 0x5b, 0x7d, 0x38, 0x26, 0x05, 0x07, 0xf6, 0x54, 0x51, + 0xa9, 0x92, 0x75, 0xa4, 0xba, 0xf1, 0x97, 0x61, 0x81, 0xfb, 0x94, 0xcf, 0x0b, 0x43, 0x23, 0xf6, 0xe0, 0xf2, 0xce, + 0xd4, 0xad, 0xb4, 0x17, 0x16, 0xd0, 0xbc, 0x92, 0x90, 0x0d, 0xa6, 0x7a, 0x16, 0xad, 0x31, 0x13, 0xf3, 0x62, 0x01, + 0x61, 0x64, 0x8a, 0x05, 0xd8, 0x4c, 0x71, 0x01, 0x5e, 0x24, 0x31, 0xc0, 0xc4, 0xc5, 0x64, 0x0a, 0xf1, 0xcc, 0x55, + 0x39, 0xf1, 0xc2, 0xdc, 0x2f, 0x13, 0x87, 0x94, 0x01, 0xaf, 0x6a, 0x83, 0x26, 0x66, 0x1b, 0x8e, 0x3a, 0x41, 0x4e, + 0x4c, 0x7e, 0x3f, 0x55, 0x10, 0xe2, 0x4e, 0x1c, 0x09, 0x97, 0x15, 0xdb, 0x85, 0x97, 0x1d, 0x88, 0x31, 0x6a, 0x70, + 0xca, 0xcf, 0x0c, 0x8e, 0xc6, 0xe0, 0xdc, 0x78, 0x27, 0x48, 0x11, 0xc6, 0x64, 0x23, 0xd9, 0x95, 0x0c, 0xc5, 0x3c, + 0x5e, 0x80, 0xb2, 0x2e, 0x5e, 0x80, 0x65, 0x8d, 0x31, 0xc0, 0x04, 0x79, 0x15, 0xf7, 0x42, 0x3f, 0x51, 0x5c, 0x21, + 0xd2, 0xb3, 0x72, 0x7d, 0x54, 0xb4, 0x43, 0x5f, 0xe0, 0xf5, 0x5e, 0x99, 0xe3, 0x66, 0x3d, 0x16, 0x48, 0x6c, 0x08, + 0x18, 0x1b, 0xe9, 0x34, 0xd5, 0x5a, 0xf7, 0xc6, 0xcc, 0x03, 0x9f, 0x66, 0x23, 0x21, 0xab, 0xb3, 0x0b, 0x10, 0xa1, + 0xf8, 0x68, 0xf0, 0xc8, 0x2f, 0xe2, 0xce, 0x32, 0x6f, 0x6d, 0x8b, 0x4a, 0x76, 0xb4, 0x01, 0x90, 0x3e, 0x1d, 0x2d, + 0x4a, 0xc9, 0x29, 0x4a, 0x52, 0xbb, 0x4d, 0x01, 0x2b, 0xc9, 0x5f, 0xc0, 0x10, 0x6c, 0x6c, 0x4f, 0x38, 0x9d, 0x22, + 0xc4, 0x27, 0x9a, 0x22, 0xb2, 0x62, 0x58, 0x52, 0x1c, 0xdb, 0x12, 0x51, 0x3f, 0x6d, 0x59, 0x76, 0x30, 0x4c, 0x54, + 0xdc, 0x17, 0xa9, 0x47, 0x89, 0x82, 0x80, 0xea, 0x21, 0x07, 0x89, 0xad, 0x6d, 0x20, 0x3c, 0x20, 0x8f, 0xe8, 0x8d, + 0xf5, 0xf7, 0x59, 0xe7, 0xd9, 0x85, 0xe6, 0xa8, 0x5c, 0xef, 0x0a, 0x33, 0x46, 0x78, 0x92, 0x19, 0x98, 0x7c, 0xef, + 0x3c, 0x33, 0x6a, 0x8a, 0x9e, 0x87, 0x4f, 0x76, 0x8c, 0x11, 0xe9, 0xee, 0x19, 0x74, 0x13, 0xbc, 0xaa, 0xc3, 0x46, + 0xbb, 0x52, 0x10, 0x12, 0xa6, 0x16, 0x4d, 0xcc, 0x7a, 0xd6, 0x80, 0x7a, 0xbb, 0xed, 0xe9, 0xb9, 0xba, 0x7f, 0xee, + 0xb6, 0xdb, 0x1e, 0x76, 0xeb, 0x45, 0xda, 0x6d, 0x05, 0x5e, 0xa9, 0x0f, 0xda, 0xe3, 0xcf, 0xdd, 0xf8, 0x73, 0x83, + 0xe4, 0x51, 0x3a, 0x9a, 0x69, 0xeb, 0x83, 0x70, 0xb8, 0xe9, 0x5d, 0xa3, 0x49, 0xdf, 0x67, 0xa1, 0xa4, 0x2b, 0xd1, + 0xa8, 0xae, 0x76, 0x26, 0x95, 0x0f, 0xae, 0xff, 0x87, 0x57, 0x01, 0x1e, 0x71, 0x6a, 0x67, 0xdf, 0xdb, 0xa0, 0xa2, + 0xd1, 0x16, 0x8e, 0x14, 0xa1, 0x07, 0x24, 0xe1, 0xbe, 0x96, 0xb5, 0xb8, 0xcd, 0xd3, 0xec, 0x61, 0xfa, 0xf4, 0x3a, + 0xf5, 0xad, 0xee, 0xdd, 0x32, 0xcb, 0xcc, 0x81, 0x57, 0x51, 0x1c, 0xd0, 0xa8, 0x8b, 0xf6, 0x5d, 0x65, 0x65, 0x09, + 0x5e, 0x1e, 0x70, 0x7d, 0x3e, 0xe5, 0x3e, 0xdc, 0xdc, 0x65, 0xd5, 0xdc, 0xa4, 0xa7, 0xd9, 0x3c, 0x5b, 0x6c, 0xb7, + 0x21, 0xfe, 0xed, 0x6a, 0x91, 0xa3, 0xc9, 0x73, 0xd0, 0xe1, 0x61, 0xe4, 0x1e, 0xa6, 0x1b, 0xe7, 0x6d, 0xfe, 0x4f, + 0xa2, 0xe1, 0x24, 0x70, 0x0c, 0xf4, 0x62, 0xf6, 0x08, 0x64, 0x30, 0xc6, 0xa9, 0x5f, 0xcc, 0xf4, 0x9a, 0x81, 0xe8, + 0x5b, 0x22, 0x02, 0x1c, 0x5d, 0x6c, 0x24, 0x1a, 0x59, 0x70, 0x52, 0x13, 0xb0, 0xd8, 0xb4, 0xe5, 0x7d, 0xb0, 0xb4, + 0xad, 0x2a, 0xee, 0xbc, 0x25, 0xcd, 0x71, 0x1d, 0x38, 0xdb, 0x7e, 0x33, 0xc4, 0xa6, 0xec, 0x6a, 0x81, 0xdc, 0x2f, + 0xaf, 0x69, 0x6f, 0x5c, 0x27, 0x30, 0x6b, 0x9b, 0xda, 0x32, 0x7e, 0xb6, 0xf4, 0x9f, 0xf5, 0xe0, 0x2a, 0xe3, 0xa7, + 0xb9, 0xb1, 0x4a, 0xb0, 0xfb, 0xc6, 0xf3, 0x1d, 0x80, 0x70, 0x6c, 0x3e, 0x3d, 0x3e, 0xcd, 0x3c, 0x7a, 0x0c, 0x44, + 0xc7, 0x7c, 0x54, 0xba, 0x8f, 0xec, 0xee, 0xf5, 0x03, 0xe0, 0xcd, 0xab, 0x76, 0x41, 0xf3, 0x72, 0x01, 0x81, 0x44, + 0xbd, 0xf2, 0x0a, 0xcb, 0x67, 0xc6, 0xec, 0x12, 0xc8, 0x50, 0x41, 0xc0, 0x26, 0xa9, 0xeb, 0x5c, 0x88, 0x55, 0x87, + 0x95, 0xf9, 0x48, 0xc2, 0x8e, 0x42, 0x34, 0xe7, 0x0c, 0x66, 0xc1, 0x7f, 0x05, 0x83, 0x72, 0x10, 0x44, 0x41, 0x14, + 0x04, 0x64, 0x50, 0xc0, 0x2f, 0xc4, 0x19, 0x23, 0x18, 0xa3, 0x04, 0x3a, 0xfc, 0x8e, 0x33, 0x9f, 0x11, 0x79, 0xd9, + 0x08, 0x63, 0xe9, 0x06, 0xe0, 0x5c, 0xca, 0x9c, 0xc7, 0xe8, 0x63, 0xf1, 0x8e, 0xb3, 0x8c, 0xd0, 0x77, 0xde, 0xa9, + 0xfc, 0x88, 0x37, 0x82, 0xdb, 0xed, 0x0e, 0xdb, 0x2b, 0x1e, 0x66, 0xb4, 0x37, 0xa6, 0xef, 0x38, 0x89, 0xb2, 0x86, + 0xf3, 0x30, 0x87, 0x9e, 0x55, 0x96, 0xb5, 0xa2, 0x86, 0xdc, 0xa0, 0x58, 0x17, 0x59, 0x26, 0x27, 0xc3, 0x55, 0x73, + 0x2a, 0x70, 0xdd, 0xd9, 0xf5, 0x02, 0x92, 0x32, 0xa1, 0x59, 0x3a, 0x1b, 0xbe, 0xda, 0xb6, 0xec, 0x45, 0xeb, 0x14, + 0xf2, 0x1a, 0xa2, 0xa2, 0x1f, 0x3a, 0x02, 0x6a, 0x68, 0xc5, 0x65, 0x05, 0x2e, 0xbb, 0xa6, 0x3d, 0xdc, 0xb4, 0xc7, + 0x34, 0xe3, 0x03, 0xc4, 0x88, 0xe3, 0xd8, 0x32, 0xb0, 0x9b, 0x70, 0x78, 0x36, 0xce, 0xf7, 0x65, 0x97, 0xde, 0xba, + 0x5a, 0x3c, 0xc2, 0xda, 0xf3, 0x56, 0x48, 0x08, 0x90, 0x96, 0xa6, 0xd2, 0xed, 0x36, 0x08, 0x60, 0x80, 0xfb, 0xfd, + 0x1e, 0x70, 0xad, 0x86, 0x9d, 0x34, 0xb7, 0x66, 0x4b, 0xec, 0x15, 0x85, 0xc7, 0x40, 0x94, 0x9a, 0xff, 0x0c, 0x02, + 0x8a, 0xe7, 0x6e, 0x08, 0xf6, 0x95, 0xec, 0x68, 0x53, 0xf4, 0xfb, 0x2f, 0x0a, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, + 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, + 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x9f, 0x00, 0x16, 0x3c, 0xf3, 0x86, 0xe5, + 0xbd, 0x07, 0x00, 0xd6, 0xeb, 0xe1, 0x42, 0x71, 0x2f, 0x5f, 0x35, 0xd0, 0x27, 0xf1, 0xa5, 0x65, 0xd7, 0x67, 0x5a, + 0x56, 0x32, 0x1a, 0x8d, 0xaa, 0x5a, 0x49, 0x3e, 0x1c, 0x79, 0x69, 0xa1, 0x56, 0xca, 0x38, 0xe5, 0x29, 0x58, 0x7a, + 0x1b, 0x4a, 0x37, 0x5f, 0xd0, 0x15, 0x17, 0xa9, 0xfa, 0xe9, 0xa1, 0x4d, 0x36, 0x88, 0x6b, 0xd6, 0xd4, 0x59, 0xd8, + 0xe1, 0x87, 0x80, 0x8f, 0xf6, 0x61, 0xe6, 0xd2, 0x35, 0x2c, 0x2d, 0x88, 0x23, 0xe3, 0x82, 0x87, 0x2e, 0x0f, 0x60, + 0xfd, 0x99, 0x43, 0x12, 0x3f, 0x85, 0x9f, 0x33, 0x93, 0xd6, 0xf1, 0x19, 0xce, 0x66, 0x54, 0xaa, 0x1b, 0x41, 0xfb, + 0x35, 0x24, 0x12, 0x83, 0x6c, 0xdc, 0x60, 0x28, 0x5a, 0x77, 0x1b, 0xb8, 0xf2, 0x5b, 0x7a, 0xe7, 0xd3, 0x20, 0xc0, + 0xb6, 0xc6, 0x62, 0x00, 0x30, 0x14, 0x7f, 0xa0, 0xaa, 0xc6, 0x5c, 0x51, 0x4c, 0xc3, 0x54, 0xa2, 0xbd, 0xe3, 0xb8, + 0x8e, 0x1a, 0x57, 0x59, 0xc1, 0x4a, 0x6b, 0xcb, 0xeb, 0xde, 0xd2, 0xc2, 0x96, 0x80, 0x6a, 0x30, 0xdc, 0x09, 0xe0, + 0x33, 0x22, 0xd5, 0x81, 0x20, 0xbb, 0x0f, 0x0e, 0x9a, 0xb3, 0x04, 0xcf, 0xc3, 0x10, 0xfe, 0xc0, 0xc2, 0x81, 0x65, + 0xa9, 0xfa, 0xb9, 0x9c, 0xc6, 0x70, 0xee, 0xe6, 0x6a, 0x87, 0xcf, 0x96, 0xa0, 0xc8, 0x53, 0x73, 0x6a, 0x2e, 0x5f, + 0x79, 0x63, 0xbf, 0xc7, 0x04, 0xf3, 0x98, 0xd9, 0x86, 0xdf, 0x7a, 0xba, 0xad, 0x2f, 0xac, 0x1b, 0x38, 0x69, 0x2f, + 0x9c, 0xf6, 0x62, 0xbb, 0x34, 0x10, 0x77, 0x75, 0x43, 0x88, 0xf0, 0x5a, 0x13, 0x8b, 0xac, 0x21, 0xd3, 0xb1, 0xd8, + 0x18, 0xaa, 0x4d, 0xc5, 0x73, 0xad, 0x10, 0x2f, 0xa7, 0xea, 0xc2, 0xd4, 0x4a, 0x65, 0xc2, 0x20, 0xcc, 0x94, 0xb0, + 0xa8, 0x32, 0xf0, 0xd9, 0xaf, 0x90, 0xe2, 0xda, 0x7a, 0xde, 0xe2, 0xf2, 0xcd, 0x4c, 0x9b, 0xed, 0xa7, 0xaf, 0xf2, + 0xf8, 0x72, 0xbb, 0x0d, 0xbb, 0x5f, 0x80, 0xf9, 0x65, 0xa9, 0x34, 0x6a, 0xe0, 0xf4, 0x10, 0xa2, 0x9f, 0xf3, 0x3d, + 0x39, 0x27, 0x8e, 0x93, 0x6b, 0x37, 0x6f, 0xb6, 0x93, 0x62, 0x04, 0x16, 0x70, 0xe2, 0x22, 0x1d, 0x68, 0xa9, 0xe0, + 0xb4, 0x65, 0xbc, 0xb7, 0xe9, 0x1d, 0xa5, 0xc2, 0xab, 0x85, 0x26, 0x21, 0x95, 0xbb, 0x97, 0xd8, 0x51, 0x03, 0xce, + 0x49, 0xdd, 0x41, 0xc0, 0x49, 0x4d, 0x37, 0xd6, 0x2a, 0x4e, 0x4d, 0x82, 0xf7, 0x4a, 0x0f, 0x5d, 0xa2, 0x9d, 0xb8, + 0xdd, 0xb6, 0x2a, 0x5b, 0xa8, 0x8f, 0x7b, 0x39, 0x4b, 0xd4, 0xf1, 0x80, 0x42, 0x17, 0x75, 0x34, 0xe4, 0x0b, 0x52, + 0xe8, 0x95, 0xa3, 0x55, 0xab, 0xbb, 0x92, 0x81, 0x52, 0xad, 0x82, 0xbc, 0x26, 0xd6, 0x5d, 0x2b, 0x6b, 0x2c, 0xae, + 0x9c, 0x90, 0xc2, 0x26, 0x7c, 0x69, 0x29, 0x16, 0x56, 0xb0, 0x37, 0xa6, 0xbe, 0x70, 0x89, 0xd0, 0x76, 0xb7, 0x21, + 0x26, 0x19, 0xac, 0x9b, 0xed, 0xf6, 0x75, 0x11, 0xce, 0xb3, 0x05, 0x95, 0xa3, 0x2c, 0x45, 0x08, 0x31, 0xe3, 0xa1, + 0x6b, 0xbb, 0x60, 0x26, 0x86, 0xba, 0xf6, 0x78, 0x49, 0xa6, 0x58, 0x9b, 0x24, 0x47, 0xf1, 0xb9, 0x2c, 0xd4, 0x5a, + 0x23, 0x04, 0x0f, 0xf7, 0x3f, 0x53, 0x88, 0xe1, 0x66, 0xd6, 0xdd, 0x6f, 0x3b, 0x37, 0xc4, 0x3f, 0x21, 0x90, 0x40, + 0xc9, 0x5e, 0x17, 0xa3, 0xf3, 0x4c, 0xa4, 0xb8, 0x53, 0x55, 0x54, 0x5c, 0xb5, 0x0e, 0x9a, 0x2d, 0xb7, 0xf7, 0x62, + 0x4b, 0x14, 0x20, 0xae, 0xb1, 0xd0, 0x8c, 0x67, 0xe5, 0x2c, 0x45, 0x32, 0x8a, 0x0d, 0x89, 0x4a, 0x2f, 0x2a, 0xba, + 0xcf, 0xd3, 0x98, 0x1e, 0xba, 0x35, 0x08, 0xae, 0x9a, 0x3b, 0x1b, 0x69, 0xbe, 0x20, 0x44, 0x4d, 0x80, 0x84, 0x8d, + 0x6a, 0x4e, 0xad, 0x4b, 0xf1, 0x30, 0xab, 0x7c, 0xa6, 0x0f, 0xe2, 0x4b, 0x01, 0x3c, 0xac, 0xb7, 0xbd, 0xaf, 0x84, + 0xc7, 0xda, 0xe0, 0xdb, 0xed, 0xf6, 0x52, 0xcc, 0x83, 0xc0, 0x63, 0x34, 0xbf, 0x53, 0x12, 0xf3, 0xde, 0x98, 0xc2, + 0x8a, 0xf7, 0x5d, 0xda, 0xba, 0x49, 0xad, 0xb5, 0x40, 0xdd, 0xe1, 0xfa, 0x80, 0xe7, 0x29, 0x71, 0xb4, 0xa3, 0x72, + 0x2a, 0xad, 0xae, 0x1c, 0xbb, 0x22, 0x30, 0x30, 0xf4, 0x0f, 0x29, 0xdb, 0x80, 0x39, 0x1e, 0x58, 0xdb, 0xa0, 0x9f, + 0x92, 0xd2, 0xc2, 0x8c, 0xd1, 0x98, 0x45, 0xae, 0xab, 0xe8, 0x80, 0xeb, 0xe8, 0xed, 0x3c, 0xfa, 0xdb, 0xb3, 0x31, + 0x2d, 0x62, 0x91, 0xca, 0x2b, 0x50, 0x41, 0x80, 0x32, 0x04, 0x0d, 0xff, 0x35, 0x35, 0x00, 0x0d, 0x82, 0x1b, 0x80, + 0x7f, 0x74, 0x3a, 0x0d, 0xda, 0x9a, 0x7c, 0x4c, 0x52, 0x55, 0xe4, 0xac, 0x0d, 0x65, 0xa6, 0x92, 0x43, 0xf2, 0xb8, + 0x04, 0x3c, 0x47, 0x6c, 0x96, 0xb2, 0xb9, 0x50, 0x9b, 0x4d, 0xbd, 0x56, 0xec, 0xc8, 0x6d, 0xa3, 0x68, 0xb3, 0x16, + 0xb5, 0x9d, 0xc4, 0x7c, 0x31, 0xbd, 0xb5, 0xc2, 0xc0, 0xa9, 0x69, 0xcd, 0xcd, 0x0e, 0x74, 0x9a, 0xad, 0xcf, 0xe4, + 0x26, 0x40, 0x1c, 0x60, 0xb8, 0x6e, 0xe7, 0x37, 0x0b, 0x42, 0x6f, 0xd9, 0xad, 0x15, 0xab, 0xde, 0x58, 0xb9, 0x88, + 0x49, 0xbb, 0x19, 0x4c, 0xe0, 0x32, 0xce, 0x0a, 0xfb, 0x42, 0xab, 0x1b, 0x8a, 0x8e, 0xb6, 0x49, 0xfb, 0x79, 0x47, + 0xbb, 0xe1, 0x82, 0x6f, 0xc5, 0x3a, 0xce, 0x0d, 0x69, 0xaa, 0xd0, 0xa3, 0x03, 0xbd, 0x1d, 0x02, 0x9a, 0xb3, 0x31, + 0x5d, 0xd2, 0x14, 0x2f, 0xd0, 0x74, 0x0d, 0x66, 0x29, 0x17, 0xd0, 0xd7, 0x6e, 0x9f, 0xe4, 0x0b, 0xd5, 0x13, 0xe1, + 0x2d, 0x51, 0xf0, 0xe5, 0x48, 0xc1, 0x2b, 0x2b, 0xe7, 0xb1, 0x99, 0x43, 0xc0, 0x63, 0x51, 0x25, 0x7a, 0x27, 0xc5, + 0x25, 0x28, 0x53, 0xe1, 0x08, 0x34, 0x55, 0x23, 0x96, 0x70, 0x80, 0xdb, 0x8b, 0xa7, 0x01, 0xa1, 0x20, 0xd5, 0x5d, + 0xdb, 0x15, 0x79, 0xcb, 0x8e, 0x36, 0xb7, 0x60, 0x16, 0x5b, 0xad, 0xcb, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, + 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, 0x43, 0x36, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, + 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x55, 0x7c, 0x07, 0x9b, + 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, + 0x5e, 0x6d, 0x6d, 0xd6, 0x66, 0xb9, 0x3e, 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, + 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x36, 0xce, + 0xdc, 0xeb, 0x90, 0x6c, 0xfe, 0xc7, 0x06, 0xea, 0x4d, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x3e, 0x61, 0x10, 0x1b, 0x33, + 0x28, 0xd7, 0x49, 0xc2, 0xcb, 0x32, 0x30, 0x4a, 0xad, 0x35, 0x5b, 0x9b, 0xf3, 0xec, 0x11, 0x3b, 0x7a, 0xd4, 0x63, + 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x04, 0x85, + 0x2c, 0xed, 0x7d, 0x6e, 0x4e, 0x64, 0xf5, 0x8d, 0x36, 0xba, 0x88, 0x54, 0x22, 0xc8, 0xc6, 0x6f, 0x10, 0xb0, 0x17, + 0x9a, 0x1d, 0x90, 0xcd, 0x92, 0x9d, 0xd2, 0x33, 0x6b, 0x02, 0x03, 0xaf, 0x4f, 0x54, 0xa2, 0x19, 0x65, 0x45, 0x74, + 0x95, 0x91, 0xcb, 0x5d, 0x48, 0xa2, 0xb3, 0x90, 0xf8, 0xb9, 0x61, 0x69, 0x5d, 0x87, 0x28, 0x66, 0x36, 0x1b, 0x5e, + 0x75, 0xf7, 0x51, 0x63, 0x5b, 0x19, 0x9f, 0xea, 0x5b, 0x9b, 0x46, 0xa6, 0xd0, 0xd7, 0xe1, 0xa4, 0xdf, 0x87, 0xbf, + 0x9a, 0x7e, 0xe0, 0x2d, 0x05, 0x7f, 0xb1, 0x47, 0xa4, 0x4e, 0x58, 0x00, 0x70, 0x84, 0x39, 0xaf, 0x9a, 0x13, 0xf8, + 0x88, 0x1d, 0x6d, 0x1e, 0x85, 0xa7, 0x8d, 0x99, 0xbb, 0x0b, 0xf1, 0x52, 0x95, 0xf4, 0xbc, 0x79, 0x32, 0x03, 0xb1, + 0x0a, 0xcd, 0x7e, 0xbd, 0x65, 0x56, 0x9f, 0x00, 0x44, 0xea, 0xd6, 0x3a, 0x94, 0xe2, 0xc7, 0xa6, 0xcb, 0x64, 0x93, + 0xb2, 0x36, 0x13, 0xa5, 0x54, 0x24, 0xcd, 0x45, 0x00, 0xfd, 0x86, 0xe1, 0xa8, 0x01, 0xde, 0x5b, 0x8f, 0xbd, 0x19, + 0x1a, 0x6f, 0x4c, 0x0d, 0x3d, 0xdb, 0xe8, 0xe5, 0xed, 0x28, 0x84, 0x19, 0x8b, 0xe8, 0xd6, 0x1d, 0x8b, 0xe1, 0x29, + 0x3d, 0x81, 0x0a, 0xdf, 0x84, 0x18, 0x4d, 0x97, 0xd4, 0xf5, 0x74, 0xad, 0xb6, 0xd2, 0x0d, 0xa1, 0x39, 0x46, 0xf1, + 0xf1, 0xda, 0x76, 0x47, 0x8d, 0xd0, 0x9e, 0x50, 0x1e, 0xde, 0xd2, 0x8a, 0xde, 0x58, 0x16, 0xc1, 0xc9, 0x8f, 0xbd, + 0xfc, 0x84, 0x9e, 0x7b, 0x02, 0x93, 0xa2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x3d, 0xb5, 0x52, 0x0e, 0x4f, + 0xe1, 0x4b, 0x36, 0x20, 0x57, 0xd0, 0x8b, 0x35, 0x66, 0x47, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x37, 0x29, 0x65, + 0x88, 0xd6, 0x77, 0x0e, 0xe2, 0xe9, 0x1f, 0xa0, 0xe9, 0x83, 0xb4, 0x30, 0xa5, 0x6b, 0x14, 0xf0, 0x80, 0xbe, 0xa9, + 0xdf, 0xcf, 0xf1, 0xb9, 0xf6, 0x2c, 0xb1, 0xb0, 0xc7, 0x4b, 0x42, 0x97, 0x5e, 0xdc, 0x28, 0x90, 0x36, 0x3b, 0x56, + 0x01, 0x58, 0x91, 0x04, 0x1a, 0x91, 0x80, 0xa5, 0x8e, 0x27, 0x2e, 0xdb, 0xa0, 0x01, 0x49, 0x54, 0x52, 0xc8, 0x12, + 0x49, 0xe0, 0x87, 0x11, 0x84, 0x28, 0x8a, 0x41, 0xdc, 0xab, 0x97, 0x57, 0x5c, 0x53, 0x03, 0x4e, 0x14, 0xc1, 0x04, + 0xeb, 0x74, 0x0a, 0xc4, 0x56, 0xac, 0x57, 0xe0, 0x79, 0xe9, 0x38, 0x71, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x97, 0x4e, + 0xbb, 0xe5, 0xed, 0x89, 0x96, 0x2a, 0x36, 0xf7, 0x5e, 0x2c, 0x2c, 0xf7, 0x58, 0xf9, 0xdb, 0x81, 0xf6, 0xc2, 0x6a, + 0x47, 0x44, 0x0d, 0x56, 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xea, 0x5e, 0x39, 0x26, 0xa0, 0xa2, 0xab, 0xb8, 0x5a, + 0x46, 0xd9, 0x08, 0xfe, 0x6c, 0xb7, 0xc1, 0x7e, 0x00, 0x16, 0x90, 0xbf, 0xbe, 0xff, 0x39, 0xc2, 0xf0, 0x4c, 0xbf, + 0xbe, 0xff, 0x79, 0xbb, 0x7d, 0x36, 0x1e, 0x1b, 0xae, 0xc0, 0xa9, 0x75, 0x80, 0x3f, 0x30, 0x6c, 0x83, 0x5d, 0xb2, + 0xdb, 0xed, 0x33, 0xe0, 0x20, 0x14, 0xdb, 0x60, 0x76, 0xb1, 0x72, 0xe4, 0x52, 0xac, 0x86, 0xde, 0x91, 0x80, 0x55, + 0xb7, 0xc3, 0x52, 0xec, 0x52, 0x1f, 0x15, 0x82, 0x51, 0x2f, 0xfa, 0x97, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, + 0xb2, 0xaa, 0x56, 0x65, 0xb4, 0xbf, 0x1f, 0xaf, 0xb2, 0x51, 0x99, 0xc1, 0x36, 0x2f, 0xaf, 0x2f, 0x01, 0x50, 0x21, + 0xa0, 0x8d, 0x77, 0x6b, 0x91, 0x99, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0xad, 0x6e, 0x72, + 0x4a, 0xec, 0x03, 0xd8, 0x1c, 0x6e, 0xb7, 0x0d, 0x7e, 0xe1, 0x68, 0xf4, 0x6c, 0xb6, 0xcc, 0xb4, 0x41, 0x27, 0x37, + 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, 0xc9, 0xf4, 0x65, 0x06, 0x7c, 0x1e, 0x7b, 0x2b, 0x42, 0x9f, 0xe5, 0x6a, + 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x32, 0x23, 0xbe, 0x4d, + 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x56, 0x78, 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x12, 0x85, 0xa8, + 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x9a, 0x3a, 0x73, 0x19, 0x5f, 0xb8, + 0xf7, 0xd2, 0x97, 0x99, 0xdc, 0x4a, 0x00, 0x45, 0x52, 0xb5, 0xff, 0xf2, 0x19, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, + 0xe8, 0xfd, 0x02, 0x35, 0x39, 0x82, 0x80, 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, + 0x6d, 0x54, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, 0x4f, 0xd7, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, + 0x1b, 0x21, 0xeb, 0x97, 0x66, 0x17, 0x7e, 0x2e, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, + 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, 0x1e, 0x73, 0x82, 0x3f, 0x3d, 0x78, 0x4a, 0xe8, 0xad, 0x9c, 0x96, 0x08, + 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, + 0x6c, 0xd9, 0x6f, 0x4d, 0xd9, 0x92, 0x6c, 0x04, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbc, 0xdf, 0xa0, + 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, + 0x9c, 0x85, 0xed, 0x76, 0x42, 0x7c, 0x09, 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, + 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x20, 0xa0, 0xc7, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x8e, 0xf9, 0x20, 0x18, + 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x57, 0x05, 0x43, 0x58, 0xa1, 0xbf, + 0x52, 0x36, 0xf9, 0xe6, 0xef, 0x6e, 0x7e, 0xcf, 0xb5, 0x98, 0x1d, 0x84, 0xe2, 0xf6, 0x7a, 0x02, 0xc4, 0xaf, 0xe2, + 0x57, 0x60, 0x5d, 0xad, 0x25, 0xde, 0x6e, 0x7a, 0xfe, 0x14, 0xbe, 0x1c, 0xdd, 0x7e, 0x52, 0x9a, 0x4f, 0x20, 0x48, + 0x8d, 0x93, 0x94, 0xbb, 0xef, 0x3e, 0x4a, 0x57, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xdd, 0x5b, 0xc9, 0x59, 0x53, 0xf8, + 0x8f, 0x75, 0xbe, 0xc7, 0xd8, 0x21, 0xf2, 0x14, 0xa7, 0xbf, 0x01, 0x86, 0x7d, 0xe7, 0xdf, 0xca, 0xac, 0x21, 0xd1, + 0xb9, 0xfa, 0x08, 0xe8, 0xff, 0x58, 0x8f, 0xdf, 0x31, 0x4a, 0xfa, 0x92, 0x38, 0x47, 0xb8, 0x22, 0x5e, 0xa2, 0xa9, + 0x5e, 0x6f, 0x5c, 0xd3, 0x4f, 0x85, 0x79, 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0x9b, 0x68, + 0x08, 0xba, 0x7f, 0xc7, 0xbd, 0xf1, 0x9b, 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, + 0x1b, 0xc6, 0x82, 0xb5, 0x50, 0xe6, 0xab, 0x69, 0x30, 0xdb, 0xd4, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x6d, 0x9c, 0xb0, + 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, + 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x71, 0x05, 0xbb, 0xcc, + 0x57, 0x52, 0xfc, 0xd9, 0x92, 0x64, 0x63, 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, + 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, + 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x63, 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0xa7, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, + 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, 0x53, 0xba, 0x9b, 0xd3, 0xfe, 0xab, 0x82, 0x0c, 0xff, 0x02, 0xef, 0xae, + 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, + 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, 0xe4, 0xad, 0xc6, 0x6c, 0xca, 0xfd, 0x0f, 0x60, 0x44, 0xb5, 0xb4, 0xdd, + 0x0e, 0xf8, 0x72, 0x84, 0x06, 0xdb, 0xa9, 0x1b, 0xec, 0x7e, 0xdf, 0xa4, 0x1d, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, + 0x51, 0xda, 0x2c, 0x95, 0x41, 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x92, 0xc6, 0x56, + 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, + 0xed, 0x36, 0x84, 0x08, 0x1c, 0xc5, 0x70, 0x32, 0x0b, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0xa9, 0x98, + 0x67, 0x0b, 0x85, 0xd8, 0xe3, 0xef, 0xa4, 0xdf, 0x0a, 0xc5, 0x29, 0xf7, 0x7e, 0x13, 0x64, 0xf3, 0x7b, 0x8a, 0x31, + 0x07, 0x9d, 0x66, 0x33, 0x03, 0x09, 0xeb, 0x71, 0x45, 0xd4, 0x3a, 0xb2, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, + 0x75, 0x8b, 0x27, 0xd6, 0x33, 0x7a, 0x0f, 0x2a, 0x41, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x3e, 0x89, 0x50, 0x52, + 0x4e, 0x9a, 0xcc, 0x8c, 0x15, 0x0d, 0x16, 0x20, 0x24, 0x8d, 0xcb, 0xea, 0x8d, 0x4c, 0xb3, 0x8b, 0x0c, 0x10, 0x13, + 0x9c, 0xff, 0x9c, 0x6c, 0xbc, 0x79, 0xae, 0xe6, 0xa5, 0x2b, 0x71, 0x66, 0x61, 0x3e, 0xba, 0xde, 0xd2, 0x82, 0x44, + 0x05, 0xd0, 0x28, 0x5f, 0xcb, 0xf3, 0xd3, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x65, 0x3b, 0xc4, 0x8f, 0x58, 0x45, + 0xbc, 0xd3, 0xba, 0x52, 0x22, 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xa8, 0xe1, 0x83, 0x30, 0x83, 0x4e, + 0xf2, 0x83, 0x9e, 0xd1, 0xb1, 0x35, 0x90, 0xf4, 0xb5, 0x08, 0xbe, 0x46, 0x47, 0x3a, 0x51, 0xa6, 0x91, 0x98, 0x42, + 0xa2, 0x5f, 0x2f, 0xb4, 0xc6, 0x32, 0xca, 0xbe, 0x22, 0xff, 0x7b, 0xdd, 0xbd, 0xdf, 0xc4, 0x76, 0x0b, 0x93, 0xec, + 0x79, 0x5c, 0xc1, 0xa6, 0x46, 0xad, 0x10, 0xce, 0xce, 0x71, 0x85, 0xda, 0xb1, 0x5e, 0x58, 0x02, 0x79, 0x00, 0x5b, + 0x91, 0x06, 0x65, 0x90, 0xec, 0x53, 0x31, 0x17, 0x0b, 0x27, 0xca, 0x91, 0x0a, 0xef, 0x4b, 0x8e, 0x52, 0x0e, 0x57, + 0xb1, 0xb0, 0x60, 0xc8, 0xaf, 0x8e, 0x2e, 0x0a, 0x79, 0x05, 0x92, 0x12, 0xc3, 0x50, 0x59, 0x5e, 0x17, 0x57, 0x6d, + 0x49, 0x68, 0xef, 0x0c, 0x40, 0x58, 0x0a, 0x10, 0xbc, 0x34, 0x6a, 0x88, 0xd9, 0x46, 0xed, 0xae, 0xe8, 0x5e, 0x72, + 0x40, 0x9d, 0xee, 0xda, 0xad, 0x37, 0x65, 0x9b, 0x6d, 0xc5, 0x85, 0x7f, 0x42, 0xe9, 0xc7, 0x7c, 0x50, 0xf8, 0x54, + 0x02, 0x37, 0xbe, 0xda, 0x64, 0xd9, 0xc5, 0x1d, 0x2e, 0xfd, 0xaa, 0x31, 0x7e, 0xfd, 0x7e, 0x4f, 0x2d, 0x84, 0x46, + 0x2a, 0x30, 0xdf, 0x3e, 0x33, 0x55, 0x19, 0x4d, 0xa9, 0xbd, 0x04, 0x57, 0xce, 0x7e, 0x04, 0x15, 0x71, 0x5d, 0x91, + 0xc9, 0xd4, 0x00, 0xed, 0x79, 0x59, 0xe1, 0x56, 0x16, 0xe0, 0xb1, 0x13, 0x90, 0xed, 0x96, 0x87, 0x81, 0x3e, 0x74, + 0x02, 0x7f, 0x4b, 0x9e, 0x22, 0xb3, 0x66, 0x1f, 0x7f, 0xd1, 0x82, 0x7f, 0x6c, 0xc1, 0xcf, 0x28, 0xee, 0xb4, 0x32, + 0xff, 0x56, 0x5a, 0xb7, 0xb8, 0x7f, 0x27, 0xd3, 0x84, 0xa2, 0x32, 0xa1, 0xf6, 0x2b, 0xfd, 0x97, 0x09, 0x96, 0xa4, + 0xb2, 0x7f, 0x90, 0xf0, 0xc1, 0xac, 0xf1, 0xc4, 0x1a, 0x4f, 0x86, 0xd3, 0xad, 0x34, 0x0c, 0x01, 0x0a, 0xfd, 0xbc, + 0xcc, 0x15, 0xd5, 0xcf, 0xbf, 0xac, 0xf9, 0x9a, 0x37, 0x5b, 0x6c, 0x93, 0x1e, 0x68, 0xb0, 0x97, 0x47, 0x53, 0x0a, + 0x27, 0x51, 0xe7, 0x46, 0xa2, 0x2e, 0x6a, 0x96, 0xa1, 0x3a, 0xc1, 0xab, 0x79, 0xaa, 0x87, 0xbd, 0x99, 0x88, 0xd6, + 0x4a, 0xca, 0x12, 0x03, 0xd6, 0x3a, 0xf2, 0x90, 0xdc, 0xad, 0x75, 0xdc, 0x69, 0xa8, 0x4b, 0x53, 0x28, 0x01, 0x56, + 0xb8, 0x00, 0x47, 0xd0, 0xcf, 0x45, 0xc8, 0xe1, 0x9a, 0xaa, 0xf4, 0x0b, 0x9a, 0x92, 0x27, 0x9e, 0xa2, 0x56, 0x2b, + 0xd2, 0xed, 0x47, 0x39, 0x76, 0xc3, 0x37, 0x4e, 0xc8, 0x89, 0x11, 0xfa, 0xbb, 0x63, 0x29, 0x67, 0x68, 0xf1, 0xa0, + 0x4e, 0xb0, 0x5e, 0xde, 0x52, 0xa0, 0x98, 0xa3, 0xcb, 0xaa, 0x6b, 0x5e, 0xa3, 0xed, 0xcb, 0xb2, 0xdf, 0xcf, 0x6d, + 0x3d, 0x29, 0x3b, 0xda, 0x2c, 0xcd, 0x3e, 0x44, 0xc5, 0x14, 0xee, 0xfa, 0x44, 0xf3, 0x57, 0xa1, 0xbe, 0x6a, 0xcb, + 0x9c, 0x8f, 0x38, 0xe2, 0x62, 0xe4, 0xa4, 0xfe, 0x45, 0x4d, 0xbd, 0x12, 0xf7, 0xab, 0x4a, 0xbe, 0x13, 0xc6, 0x8a, + 0xd1, 0x01, 0xf5, 0xa7, 0x4a, 0xe5, 0xfd, 0xb2, 0x00, 0xb8, 0x27, 0xc1, 0x3e, 0x81, 0x7d, 0x85, 0x46, 0xf8, 0x6d, + 0x09, 0xf8, 0x37, 0x8a, 0x1b, 0xb0, 0x0a, 0x0c, 0x30, 0x9a, 0x6c, 0xcf, 0x69, 0x02, 0x07, 0x9c, 0xd0, 0x2a, 0x0a, + 0x2a, 0xcc, 0xd0, 0x50, 0x5b, 0x18, 0x3d, 0x45, 0x19, 0xb7, 0xca, 0xec, 0xdd, 0x18, 0x3b, 0x2d, 0xf0, 0x1a, 0xfe, + 0x7c, 0x5e, 0xe8, 0x61, 0xa3, 0x0e, 0xd2, 0xa3, 0x93, 0x98, 0xfe, 0xb8, 0x85, 0x93, 0x9b, 0x85, 0xb3, 0xac, 0x59, + 0x02, 0xdd, 0x81, 0x0b, 0x62, 0xdc, 0xef, 0xe7, 0x70, 0x64, 0x9a, 0x91, 0x2f, 0x58, 0x4e, 0x63, 0xb6, 0xa4, 0xda, + 0xd3, 0xee, 0xb2, 0x0a, 0x73, 0xba, 0xb4, 0x32, 0xde, 0x94, 0x81, 0xca, 0x68, 0xbb, 0x0d, 0xe1, 0x4f, 0xb7, 0xb5, + 0x4b, 0x3a, 0x5f, 0x42, 0x06, 0xf8, 0x03, 0x12, 0x51, 0xc4, 0xbe, 0xfe, 0xb7, 0x1a, 0xa7, 0xf4, 0x44, 0x69, 0xcd, + 0x12, 0xba, 0x66, 0xba, 0x7e, 0x7a, 0xc1, 0xd6, 0x8d, 0xa5, 0xb0, 0xdd, 0x86, 0xcd, 0x04, 0xa6, 0x39, 0x57, 0x32, + 0xbd, 0x40, 0x9d, 0x14, 0x50, 0xb1, 0xf0, 0x02, 0x97, 0x5f, 0x4a, 0x28, 0x34, 0x77, 0xbe, 0x5c, 0x18, 0x25, 0x26, + 0xb4, 0x4a, 0x7e, 0xf9, 0x50, 0x99, 0xaf, 0x8d, 0x47, 0xdc, 0xbf, 0xd2, 0x30, 0x31, 0x45, 0xa2, 0x42, 0x74, 0xf6, + 0x1b, 0xc8, 0x72, 0x04, 0xe0, 0x58, 0x9e, 0xca, 0x9a, 0xfe, 0x98, 0x42, 0x1c, 0x74, 0x68, 0xd0, 0xbb, 0x42, 0x5e, + 0x65, 0x25, 0x0f, 0xf1, 0x9e, 0xe0, 0x69, 0x46, 0xef, 0x37, 0xf8, 0xd0, 0xd6, 0x1e, 0x3d, 0x41, 0x36, 0x9e, 0x72, + 0xbf, 0xfe, 0x4e, 0x84, 0x73, 0x88, 0x56, 0xb9, 0xa0, 0x5a, 0x5d, 0xed, 0x00, 0xa8, 0x3c, 0xdb, 0xab, 0x47, 0x70, + 0xba, 0xe9, 0xeb, 0x5b, 0x15, 0x3a, 0x73, 0x00, 0x69, 0x0f, 0xc9, 0xba, 0xe6, 0x7a, 0x07, 0xb8, 0x23, 0xb1, 0x5a, + 0x03, 0x8d, 0x75, 0x5b, 0xb3, 0xd3, 0x1e, 0xc5, 0x63, 0x22, 0x33, 0x63, 0x91, 0x62, 0xcc, 0xdd, 0x3a, 0x2d, 0x8a, + 0x36, 0x68, 0x86, 0xb0, 0x7b, 0xd7, 0xe1, 0xeb, 0x56, 0x84, 0xf5, 0xfb, 0x6d, 0x5f, 0x60, 0x34, 0x8c, 0xb9, 0x76, + 0xcf, 0x33, 0x74, 0xc3, 0x06, 0xdb, 0xc8, 0x79, 0x88, 0x7c, 0x98, 0xa9, 0x03, 0x51, 0xd6, 0xd6, 0x80, 0xed, 0x11, + 0xd7, 0x9b, 0x56, 0xf1, 0xf3, 0x2a, 0xe6, 0x6c, 0xcf, 0x1a, 0xa7, 0xb4, 0xbe, 0xc6, 0x35, 0xc7, 0x55, 0x21, 0xa2, + 0xb6, 0x9e, 0xf1, 0x30, 0xec, 0x7c, 0x81, 0x3b, 0xb3, 0xc2, 0xe0, 0x45, 0x58, 0x2a, 0xd9, 0xa9, 0x5c, 0x7f, 0x0e, + 0x5b, 0x1c, 0xa4, 0xf2, 0xa5, 0xd7, 0xdf, 0x7f, 0xf9, 0xe2, 0x0b, 0x74, 0x53, 0x73, 0x7e, 0x04, 0x41, 0x26, 0xd0, + 0x21, 0x4b, 0xa9, 0x1e, 0xbf, 0x2b, 0x80, 0xda, 0xc3, 0x3c, 0x7c, 0x57, 0x30, 0x11, 0x5f, 0x67, 0x97, 0x71, 0x25, + 0x8b, 0xd1, 0x35, 0x17, 0xa9, 0x2c, 0xac, 0xd4, 0x38, 0x38, 0x5e, 0xad, 0x72, 0x1e, 0x80, 0xa9, 0xbc, 0x65, 0x94, + 0x6d, 0x65, 0x99, 0x1e, 0x5c, 0x2d, 0x4f, 0xaf, 0xb4, 0xe8, 0xbc, 0xbc, 0xbe, 0x0c, 0x22, 0xfc, 0x75, 0x6e, 0x7e, + 0x5c, 0xc5, 0xe5, 0xc7, 0x20, 0xb2, 0x36, 0x75, 0xe6, 0x07, 0x4a, 0xe5, 0xc1, 0x7f, 0x0a, 0x64, 0xba, 0xdf, 0x15, + 0x60, 0x99, 0x6d, 0x2b, 0x3e, 0x8c, 0xb1, 0xd6, 0xe1, 0x84, 0xcc, 0x54, 0x89, 0xde, 0xbb, 0x64, 0x5d, 0x80, 0xb5, + 0x9f, 0xc2, 0x32, 0x56, 0xb9, 0x66, 0x58, 0x99, 0xaa, 0xc8, 0xcc, 0xca, 0x9a, 0xed, 0x87, 0xd6, 0x89, 0x66, 0x8e, + 0xde, 0x02, 0xfa, 0x81, 0xec, 0x5f, 0xd2, 0x72, 0xcd, 0x3c, 0x1f, 0x9b, 0xc6, 0xeb, 0x47, 0xfb, 0x97, 0x6e, 0xc1, + 0xde, 0xda, 0x3b, 0x39, 0x0a, 0x13, 0xc1, 0xb3, 0xd6, 0x8c, 0x2f, 0xf2, 0xac, 0x80, 0x95, 0x33, 0x19, 0x8f, 0xa9, + 0xb7, 0xb4, 0x5a, 0x37, 0x47, 0x87, 0xe4, 0x9a, 0x3d, 0xae, 0x1e, 0x73, 0xb2, 0xcf, 0x5b, 0xa6, 0xb6, 0x6d, 0xeb, + 0x38, 0x4f, 0x93, 0xaf, 0x4c, 0xf7, 0xc5, 0xda, 0x46, 0x44, 0x57, 0xce, 0x7d, 0xce, 0x2b, 0xb8, 0xf5, 0x4d, 0x69, + 0xe8, 0xb5, 0x04, 0x20, 0x3a, 0x6d, 0xc0, 0x5f, 0xb0, 0x72, 0x3d, 0xaa, 0x78, 0x59, 0x81, 0x84, 0x05, 0x45, 0x78, + 0x53, 0xec, 0x4d, 0xe1, 0x6e, 0x9c, 0x9e, 0xc3, 0x0e, 0x5c, 0x4c, 0xd1, 0x1d, 0x27, 0x26, 0xb3, 0xd2, 0x68, 0x45, + 0x23, 0xfd, 0xcb, 0xf5, 0x25, 0xd6, 0x7d, 0xd1, 0xca, 0x3c, 0x9b, 0x53, 0x61, 0xb1, 0xbb, 0xca, 0xa5, 0x13, 0xf5, + 0x5b, 0x26, 0x5c, 0xb9, 0x12, 0x04, 0x64, 0x5a, 0xb0, 0x5e, 0x61, 0x76, 0x91, 0x5c, 0x03, 0x21, 0x03, 0xc3, 0xd7, + 0x60, 0x2d, 0x4a, 0x6e, 0xac, 0x60, 0xbd, 0x7b, 0xbe, 0x4e, 0x10, 0x52, 0xf0, 0xc0, 0x4d, 0xd0, 0x0f, 0xad, 0x9b, + 0xb7, 0xa3, 0x44, 0x19, 0xc4, 0xe3, 0xd6, 0x4e, 0x39, 0x48, 0x20, 0x00, 0xf7, 0x54, 0x85, 0xe0, 0x50, 0x20, 0xeb, + 0xe0, 0x6a, 0xc6, 0x11, 0x5c, 0x5d, 0x39, 0x73, 0x71, 0x03, 0xb0, 0xae, 0xfc, 0xb9, 0x6c, 0x70, 0x61, 0x3d, 0xa2, + 0xca, 0x9c, 0x71, 0x8a, 0x41, 0x8c, 0x2c, 0x41, 0x5f, 0x59, 0x4a, 0x7b, 0x09, 0x9a, 0xc6, 0x2b, 0xb6, 0x52, 0x3e, + 0x00, 0xf4, 0x9c, 0xad, 0x94, 0xb1, 0x3f, 0x7e, 0x7d, 0xc6, 0x56, 0x5a, 0x1a, 0x3c, 0xbd, 0x9a, 0x9d, 0xcf, 0xce, + 0x06, 0xec, 0x20, 0x0a, 0xb5, 0x01, 0x43, 0xe0, 0x90, 0xf8, 0x83, 0x41, 0xa8, 0xf1, 0x4e, 0x06, 0x2a, 0x20, 0x16, + 0xf1, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, 0x43, 0x0c, 0x7e, 0xd5, 0x7c, 0x41, 0x02, 0x42, 0x4d, 0x69, 0xe8, 0xf2, + 0x18, 0x0e, 0x27, 0x7b, 0x13, 0x48, 0xc5, 0xcc, 0x4c, 0x15, 0xc6, 0xc6, 0x24, 0x82, 0x78, 0xa7, 0x9d, 0xf5, 0x42, + 0xb9, 0xdd, 0x35, 0x1a, 0xc8, 0x95, 0xc1, 0x17, 0x55, 0x3c, 0xd9, 0x1b, 0x76, 0x55, 0x8c, 0xa3, 0x70, 0x6d, 0x94, + 0x6f, 0x67, 0x87, 0x00, 0x5e, 0x7b, 0x36, 0xf4, 0xe5, 0x12, 0x67, 0xfb, 0x4f, 0xc9, 0xe3, 0xa7, 0x84, 0x9e, 0xb1, + 0xb3, 0xaf, 0x9e, 0xd2, 0x33, 0x45, 0x4e, 0xf6, 0x26, 0xd1, 0x35, 0xb3, 0x98, 0x2f, 0x07, 0xaa, 0x09, 0xf4, 0x72, + 0xb4, 0x16, 0x6a, 0x81, 0x69, 0x87, 0xa6, 0xf0, 0xdb, 0xf1, 0x5e, 0x30, 0xb8, 0x6e, 0x37, 0xfd, 0xba, 0xdd, 0x56, + 0xcf, 0xab, 0x6b, 0xef, 0x20, 0xda, 0x2d, 0x66, 0xf2, 0xf7, 0xf1, 0x9e, 0x9b, 0x03, 0xac, 0xef, 0xe1, 0x31, 0x31, + 0x4d, 0xda, 0x19, 0x15, 0xbf, 0xa6, 0x27, 0xd8, 0x87, 0x66, 0x91, 0x1d, 0x7d, 0x18, 0xfe, 0x5b, 0x9d, 0xa8, 0xcf, + 0xbe, 0x3a, 0x00, 0x72, 0x04, 0x32, 0x50, 0x2c, 0x11, 0xcc, 0x70, 0xa0, 0x29, 0xa0, 0x20, 0xd3, 0xe3, 0x4e, 0xf5, + 0xf0, 0xab, 0x51, 0x53, 0x33, 0x72, 0x0d, 0x53, 0x83, 0x6d, 0xc1, 0x0f, 0x54, 0x37, 0xf4, 0x37, 0x1a, 0xdd, 0x48, + 0x3b, 0x99, 0x99, 0x97, 0xd4, 0xc6, 0x75, 0xbb, 0x86, 0x00, 0xc6, 0x0e, 0x5e, 0x50, 0xb2, 0xaf, 0x0f, 0x2f, 0xf7, + 0x70, 0x15, 0x01, 0x4a, 0x16, 0x0b, 0xbe, 0x1e, 0x5c, 0xea, 0xcd, 0xbd, 0x17, 0x90, 0xc1, 0xd7, 0xc1, 0xd1, 0xd7, + 0x03, 0x39, 0x08, 0x0e, 0xf7, 0x2f, 0x8f, 0x02, 0x67, 0xdc, 0x0f, 0x21, 0x1e, 0x55, 0x45, 0x31, 0x13, 0xa6, 0x8a, + 0xc4, 0xd6, 0x9e, 0xdb, 0x7a, 0x95, 0xf1, 0x19, 0x4d, 0xa7, 0x16, 0xf9, 0x3b, 0x4c, 0x59, 0x6c, 0x7e, 0x07, 0x13, + 0x7e, 0x15, 0x44, 0x2e, 0x08, 0xea, 0x2c, 0x8f, 0x62, 0xba, 0x64, 0xb7, 0x22, 0x4c, 0x69, 0xb2, 0x9f, 0x13, 0x12, + 0x85, 0x4b, 0x05, 0x9e, 0xa7, 0x5e, 0x27, 0x10, 0xc7, 0xd5, 0x7d, 0x7e, 0x2b, 0xc2, 0x25, 0xcd, 0xf7, 0x13, 0xd2, + 0x2a, 0xc2, 0x45, 0x64, 0xd9, 0xd4, 0xf4, 0x82, 0x85, 0x2b, 0x7a, 0x09, 0xcc, 0x94, 0x5c, 0x87, 0x97, 0xc0, 0xe5, + 0xad, 0xe7, 0xab, 0x05, 0xbb, 0x6c, 0x48, 0xdf, 0x0c, 0x5f, 0x7c, 0x61, 0x7d, 0xf2, 0x80, 0x87, 0x74, 0x7e, 0x78, + 0x29, 0xd8, 0x00, 0x5c, 0x67, 0xfc, 0xe6, 0x3b, 0x79, 0xab, 0xe7, 0xa5, 0x3d, 0xc5, 0x38, 0x33, 0xed, 0xc4, 0xa4, + 0x9d, 0x90, 0xfb, 0xf7, 0xed, 0x4d, 0x6c, 0x4e, 0xf6, 0x32, 0x5a, 0x2b, 0x97, 0x55, 0xcb, 0x90, 0x14, 0x6b, 0x86, + 0xfc, 0x3d, 0x4a, 0x4e, 0xad, 0xc0, 0x93, 0x5d, 0xf0, 0x2a, 0x59, 0xfa, 0x07, 0x95, 0xb5, 0x1a, 0xb0, 0xc7, 0x88, + 0x65, 0xa1, 0x70, 0xec, 0xdf, 0x64, 0xac, 0x58, 0xfb, 0x02, 0x8d, 0x18, 0xb9, 0xb7, 0x37, 0x19, 0xf3, 0x62, 0xae, + 0x26, 0x6b, 0x2f, 0x54, 0x9d, 0x97, 0x9e, 0xb7, 0x78, 0x2f, 0xa7, 0xd4, 0x30, 0x12, 0xd1, 0xbd, 0xb1, 0x32, 0xa3, + 0x54, 0x89, 0x5a, 0x83, 0x46, 0x04, 0x1b, 0xbb, 0xe0, 0x97, 0xe0, 0x84, 0xca, 0x3d, 0x75, 0xb6, 0x6f, 0xa7, 0x54, + 0x7a, 0xc0, 0xb2, 0xd4, 0xa8, 0xca, 0xdd, 0x32, 0x93, 0xac, 0x1a, 0x04, 0xa3, 0x3f, 0x4b, 0x29, 0x66, 0x78, 0x67, + 0x64, 0xc1, 0x14, 0xac, 0x04, 0x55, 0x2d, 0xc3, 0x72, 0xc8, 0x51, 0x8b, 0x67, 0x7c, 0x52, 0xa5, 0xfe, 0xd1, 0x11, + 0x24, 0x77, 0xb9, 0x6e, 0x05, 0xc9, 0x7d, 0x3a, 0x7e, 0xaa, 0x07, 0x3a, 0x5d, 0x6b, 0xc7, 0x43, 0x9f, 0xdf, 0x46, + 0x7c, 0x6d, 0xdd, 0x7b, 0xaa, 0xb5, 0x0a, 0x65, 0xa0, 0xc5, 0x8a, 0xca, 0x95, 0x5a, 0xd2, 0xfb, 0x5d, 0x04, 0xc0, + 0x22, 0x36, 0x66, 0xe3, 0x5d, 0xdb, 0xac, 0x10, 0x34, 0xba, 0xec, 0x68, 0x13, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, + 0xd0, 0xf8, 0x88, 0x95, 0xfd, 0x7e, 0x7e, 0x04, 0xf4, 0x54, 0x1b, 0x31, 0x15, 0x70, 0xe4, 0x7f, 0x69, 0x45, 0xa6, + 0x28, 0xb0, 0x59, 0x53, 0x77, 0x6b, 0x2c, 0x23, 0xd1, 0x97, 0x29, 0x5d, 0x9e, 0xf0, 0x0c, 0x98, 0xd6, 0xeb, 0x96, + 0xe3, 0xca, 0xae, 0xe2, 0xc8, 0x53, 0x61, 0x59, 0x71, 0x5e, 0x85, 0xe3, 0xad, 0xc7, 0x37, 0xd8, 0x37, 0x6c, 0xda, + 0x85, 0x3f, 0x84, 0xb0, 0x10, 0xde, 0x64, 0x70, 0x1b, 0xd1, 0x76, 0x12, 0xa8, 0xbc, 0x31, 0xd7, 0x09, 0x65, 0x73, + 0xbb, 0x5e, 0x7b, 0x06, 0xe9, 0xc4, 0x1c, 0x28, 0xd5, 0x08, 0x5a, 0xa3, 0x59, 0x50, 0x35, 0xe2, 0x91, 0xe3, 0xe1, + 0x9d, 0x41, 0xac, 0x96, 0x2f, 0x69, 0x2a, 0x45, 0x03, 0x30, 0x2e, 0x80, 0xcb, 0xd3, 0xaf, 0xef, 0x7f, 0x3e, 0xe5, + 0x71, 0x91, 0x2c, 0xdf, 0xc5, 0x45, 0x7c, 0x55, 0x86, 0x1b, 0x35, 0x46, 0x71, 0x4d, 0xa6, 0x62, 0xc0, 0xa4, 0x59, + 0x49, 0xcd, 0x5d, 0xa9, 0x09, 0x31, 0xd6, 0x99, 0xac, 0xcb, 0x4a, 0x5e, 0x35, 0x2a, 0x5d, 0x17, 0x19, 0x7e, 0xdc, + 0xf2, 0x39, 0xdd, 0x07, 0x20, 0x4f, 0xe3, 0x42, 0x1a, 0x49, 0x5d, 0x88, 0x31, 0x17, 0xf1, 0xba, 0x3e, 0x1e, 0x37, + 0xba, 0x5e, 0xb2, 0x67, 0xe3, 0x27, 0xd3, 0x37, 0x59, 0x98, 0x0d, 0x04, 0x19, 0x55, 0x4b, 0x2e, 0x5a, 0xa6, 0x9c, + 0xca, 0x24, 0x00, 0x7d, 0x3c, 0x7b, 0x8c, 0x1d, 0x8c, 0xc7, 0x64, 0xd3, 0x16, 0x0f, 0xf0, 0x70, 0xb9, 0x0e, 0x0b, + 0x32, 0xd3, 0x75, 0x44, 0x81, 0xe0, 0xb7, 0x55, 0x00, 0x48, 0x8e, 0xb6, 0x2a, 0xc3, 0xa5, 0xb1, 0x67, 0xe3, 0x09, + 0x95, 0xd8, 0xed, 0x90, 0xd4, 0x5e, 0x85, 0x6e, 0xe6, 0xa5, 0xef, 0x51, 0x24, 0x8d, 0xcb, 0xd2, 0x4e, 0xa5, 0x52, + 0xed, 0x99, 0x99, 0xeb, 0x1a, 0xc4, 0x60, 0x08, 0x75, 0xdd, 0xa5, 0x57, 0xf7, 0x6e, 0x73, 0xad, 0xd9, 0x0e, 0x78, + 0xaf, 0x41, 0x33, 0x94, 0xbc, 0xc5, 0xbc, 0x75, 0x45, 0xd4, 0x74, 0xb5, 0x06, 0xb3, 0x62, 0x94, 0x2d, 0x45, 0xe9, + 0x9a, 0x82, 0x52, 0x30, 0xba, 0x58, 0x7b, 0x0b, 0xf7, 0x8d, 0x6c, 0x5c, 0x58, 0x32, 0xbd, 0x5a, 0x94, 0x94, 0x50, + 0xdd, 0x54, 0x8c, 0x94, 0x30, 0x52, 0x1a, 0x9e, 0xca, 0xf7, 0x02, 0x8f, 0xf3, 0x3c, 0x88, 0x5a, 0x5e, 0x60, 0xc7, + 0x15, 0x39, 0x06, 0x47, 0x2f, 0x93, 0xd3, 0x50, 0xe0, 0x1f, 0x33, 0x05, 0x62, 0x3a, 0x54, 0xf7, 0x1b, 0xdc, 0xfc, + 0xff, 0x28, 0x58, 0xe0, 0xf1, 0xad, 0x97, 0xb8, 0x8d, 0xfe, 0x51, 0xf8, 0xb4, 0xf4, 0xb9, 0xf4, 0x5d, 0x5d, 0x3c, + 0x69, 0x6f, 0x36, 0x4a, 0x96, 0x59, 0x9e, 0xbe, 0x95, 0x29, 0x07, 0x91, 0x19, 0x5a, 0x83, 0xb2, 0x23, 0xd1, 0xb8, + 0xe1, 0x81, 0x11, 0x63, 0xe3, 0xc6, 0xf7, 0x63, 0x06, 0xb2, 0x61, 0xb0, 0xfa, 0x66, 0xa9, 0x4c, 0xd6, 0x57, 0x80, + 0x29, 0xa2, 0xe4, 0x27, 0x2f, 0x73, 0x0e, 0x4f, 0xa1, 0xbe, 0x7e, 0x81, 0xdb, 0x5c, 0xe9, 0xfb, 0x9c, 0xff, 0x98, + 0xd1, 0x1f, 0x11, 0xe8, 0x24, 0x5e, 0x81, 0xdc, 0xe3, 0x39, 0xd4, 0x8d, 0x30, 0xb5, 0x1c, 0x83, 0x03, 0x21, 0x1a, + 0x88, 0xa8, 0x58, 0xa0, 0xa0, 0x2e, 0x0c, 0xb0, 0x86, 0xba, 0x60, 0x0e, 0xcf, 0x73, 0x99, 0x7c, 0x9c, 0x1a, 0x9f, + 0xf9, 0x61, 0x8c, 0x31, 0x93, 0x83, 0x41, 0x58, 0xcd, 0x82, 0xe1, 0x78, 0x34, 0x39, 0x78, 0x06, 0xe7, 0x76, 0x30, + 0x0e, 0xc8, 0x20, 0xa8, 0xcb, 0x55, 0x2c, 0x68, 0x79, 0x7d, 0x69, 0xcb, 0xc0, 0x8f, 0xeb, 0x60, 0xf0, 0x8f, 0xc2, + 0x53, 0xbc, 0x83, 0xe6, 0xe4, 0x4c, 0x86, 0x60, 0x63, 0xbf, 0x26, 0x20, 0x29, 0xeb, 0x69, 0x7e, 0x52, 0x1f, 0x6e, + 0x4c, 0x69, 0xff, 0xcc, 0xe1, 0x05, 0x87, 0x1d, 0x12, 0x28, 0x90, 0xc6, 0xd3, 0x6c, 0xf4, 0x5a, 0x29, 0x72, 0xdf, + 0x15, 0x1c, 0xee, 0xcc, 0x3d, 0x67, 0x7a, 0xe4, 0x14, 0x12, 0xcd, 0x2c, 0xe0, 0x46, 0xfe, 0x5a, 0x5c, 0xc7, 0x79, + 0x96, 0xee, 0x35, 0xdf, 0xec, 0x95, 0x77, 0xa2, 0x8a, 0x6f, 0x47, 0x81, 0xb1, 0x26, 0xe4, 0xbe, 0xea, 0x09, 0xd0, + 0x13, 0x60, 0x0b, 0x80, 0x01, 0xf1, 0x8e, 0x99, 0xc9, 0x8c, 0x47, 0xe0, 0x11, 0xd8, 0xf4, 0x81, 0x2c, 0xee, 0x9c, + 0x4b, 0x92, 0xbf, 0x99, 0x4a, 0x7b, 0xd5, 0x2b, 0x77, 0x0a, 0xb2, 0x5e, 0x6d, 0xe5, 0xae, 0x5b, 0x9f, 0x7d, 0xd3, + 0xe1, 0x15, 0x78, 0x2e, 0xc1, 0x2d, 0xb2, 0xdf, 0x6f, 0x0a, 0x2a, 0x85, 0x51, 0x11, 0xef, 0x24, 0xd7, 0xe8, 0xdf, + 0xee, 0x8d, 0x8d, 0x22, 0xb9, 0xe5, 0xc3, 0x03, 0xa8, 0x33, 0x79, 0x57, 0xdc, 0xce, 0x21, 0x6a, 0xeb, 0x6e, 0x3c, + 0xb0, 0xda, 0xa0, 0x5d, 0xd6, 0x1c, 0xc1, 0x85, 0x17, 0x7b, 0x19, 0x8c, 0x05, 0xce, 0xca, 0x48, 0xa9, 0x71, 0x0d, + 0xa9, 0x05, 0x9f, 0xe4, 0xe9, 0x3d, 0x64, 0xa9, 0x27, 0x41, 0x91, 0xe3, 0x59, 0x0c, 0x99, 0xc6, 0xdb, 0xc0, 0xe3, + 0x77, 0x32, 0x04, 0x69, 0xda, 0x76, 0xdb, 0x1c, 0x81, 0xb2, 0x7b, 0x60, 0x4a, 0x52, 0xd7, 0xc6, 0xd4, 0x40, 0x43, + 0xed, 0xa1, 0x46, 0x2a, 0xe2, 0xec, 0xe8, 0x0d, 0xe8, 0x10, 0xc1, 0xf7, 0x3b, 0xcd, 0xca, 0x8e, 0x17, 0x13, 0x82, + 0x27, 0xef, 0xcb, 0xdb, 0xac, 0xac, 0xca, 0xe8, 0x7d, 0x8a, 0x86, 0x50, 0x89, 0x14, 0xd1, 0x2b, 0x88, 0xa7, 0x57, + 0xe2, 0xef, 0x32, 0xfa, 0x39, 0xa5, 0x71, 0x9a, 0x62, 0xfa, 0x8b, 0x02, 0x7e, 0x3e, 0x07, 0x54, 0x47, 0xdc, 0x09, + 0xd1, 0xb9, 0x04, 0x7b, 0x35, 0x88, 0x66, 0x55, 0x71, 0xc0, 0xd0, 0x8c, 0x6e, 0x05, 0x45, 0x8c, 0x36, 0xcc, 0xfe, + 0x43, 0x81, 0x42, 0x21, 0x55, 0xcc, 0x77, 0xc2, 0x3e, 0x44, 0x3f, 0x62, 0x91, 0xc7, 0xef, 0x5e, 0x9b, 0x21, 0x8d, + 0xee, 0x24, 0xd5, 0x5b, 0x1b, 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xae, 0xe9, 0x59, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, + 0x4f, 0xbc, 0x7b, 0xfd, 0x5c, 0x59, 0x98, 0xbc, 0xc8, 0x40, 0x71, 0x70, 0xfc, 0xee, 0xf5, 0x1b, 0x99, 0xae, 0x73, + 0x1e, 0x9d, 0x49, 0x24, 0xad, 0xc7, 0xef, 0x5e, 0xff, 0x82, 0xe6, 0x5e, 0x3f, 0x17, 0xf0, 0xfe, 0x15, 0xf0, 0x96, + 0x51, 0xbc, 0x86, 0x3e, 0xa9, 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd5, 0x5a, 0x46, 0xbf, 0xa6, 0xb5, 0x27, 0xad, 0xfa, + 0x67, 0xe1, 0x53, 0x3b, 0x4f, 0xc0, 0x73, 0x9b, 0x67, 0xe2, 0x63, 0x64, 0x45, 0x3b, 0x41, 0xf4, 0xf5, 0xde, 0xed, + 0x55, 0x2e, 0xca, 0x08, 0x5f, 0x30, 0xb4, 0x0b, 0x8a, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0x46, 0x37, 0x4f, 0x46, 0xb2, + 0xb8, 0xdc, 0x9f, 0x7c, 0xfb, 0xed, 0xb7, 0xfb, 0xf8, 0x36, 0xf8, 0xba, 0xed, 0xf6, 0x5e, 0x11, 0x3e, 0x60, 0x01, + 0x22, 0x54, 0x7f, 0x0d, 0x57, 0x14, 0xd0, 0xc2, 0x0d, 0xbe, 0x0e, 0xbe, 0xd6, 0x87, 0xce, 0xd7, 0x87, 0xe5, 0xf5, + 0xa5, 0x2a, 0xbf, 0xab, 0xe4, 0x83, 0xf1, 0x78, 0xbc, 0x0f, 0x12, 0xa8, 0xaf, 0x07, 0x7c, 0x10, 0x1c, 0x05, 0x83, + 0x0c, 0x2e, 0x34, 0xe5, 0xf5, 0xe5, 0x51, 0xe0, 0x99, 0xe6, 0x36, 0x58, 0x44, 0x07, 0xe2, 0x12, 0xec, 0x5f, 0xd2, + 0xe0, 0xeb, 0x80, 0xb8, 0x94, 0xaf, 0x20, 0xe5, 0xab, 0x83, 0x67, 0x7e, 0xda, 0xff, 0x52, 0x69, 0x4f, 0xfc, 0xb4, + 0x43, 0x4c, 0x7b, 0xf2, 0xdc, 0x4f, 0x3b, 0x52, 0x69, 0x2f, 0xfd, 0xb4, 0xff, 0x5d, 0x0e, 0x20, 0x75, 0xcf, 0xb7, + 0xfe, 0x3b, 0xf7, 0x5a, 0x83, 0xa7, 0x50, 0x94, 0x5d, 0xc5, 0x97, 0x1c, 0x1a, 0x3d, 0xb8, 0xbd, 0xca, 0x69, 0x30, + 0xc0, 0xf6, 0x7a, 0x26, 0x21, 0xde, 0x07, 0x5f, 0xaf, 0x8b, 0x3c, 0x0c, 0xbe, 0x1e, 0x60, 0x21, 0x83, 0xaf, 0x03, + 0xf2, 0xb5, 0x31, 0x90, 0x11, 0x6c, 0x13, 0xb8, 0x50, 0xa4, 0x43, 0x1b, 0x20, 0xcc, 0x97, 0xc6, 0xd5, 0xf4, 0xaf, + 0xa2, 0x3b, 0x1b, 0xde, 0x12, 0x95, 0x9b, 0x6e, 0x50, 0xd3, 0x13, 0xf0, 0x4e, 0x80, 0x46, 0x45, 0xc1, 0x75, 0x5c, + 0x84, 0xc3, 0x61, 0x79, 0x7d, 0x49, 0xc0, 0x2e, 0x73, 0xc5, 0xe3, 0x2a, 0x0a, 0x84, 0x1c, 0xaa, 0x9f, 0x81, 0x8a, + 0x7c, 0x15, 0x20, 0x20, 0x12, 0xfc, 0x17, 0xd4, 0xf4, 0x9d, 0x64, 0x9b, 0x60, 0x78, 0xc3, 0xcf, 0x3f, 0x66, 0xd5, + 0x50, 0x89, 0x16, 0xaf, 0x05, 0x85, 0x1f, 0xf0, 0xd7, 0x55, 0x1d, 0xfd, 0x05, 0x6e, 0xdc, 0x4d, 0x0d, 0xfb, 0x3b, + 0xe9, 0x58, 0xd4, 0x77, 0x72, 0x9e, 0x2d, 0xa6, 0xad, 0x03, 0xfd, 0x44, 0x92, 0x6a, 0x9e, 0x0d, 0x82, 0x61, 0x30, + 0xe0, 0x0b, 0x76, 0x22, 0xe7, 0xdc, 0x33, 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x65, 0x03, 0xf0, 0x4d, 0x41, 0x7e, + 0x64, 0xff, 0xbf, 0xe7, 0x43, 0x14, 0x1e, 0x0e, 0x1e, 0xed, 0x93, 0x59, 0xb0, 0xba, 0x45, 0x8f, 0xce, 0x28, 0xc8, + 0xc4, 0x92, 0x17, 0x59, 0xe5, 0x2d, 0x95, 0xbb, 0x75, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x15, 0x8b, 0x40, 0x9d, + 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb0, 0x37, 0x1c, + 0xee, 0x05, 0x03, 0xa7, 0xce, 0x1d, 0x04, 0x7b, 0xc3, 0xe1, 0x51, 0xe0, 0xee, 0x43, 0xd9, 0xc8, 0xdd, 0x19, 0x69, + 0xc1, 0xfe, 0x59, 0x84, 0x25, 0x05, 0xf1, 0x98, 0xd4, 0xe2, 0x2f, 0x0d, 0x2e, 0x33, 0x00, 0xe8, 0x23, 0x25, 0x01, + 0x33, 0xb0, 0x32, 0x03, 0x08, 0xcd, 0x4d, 0x63, 0x76, 0x06, 0xcc, 0x23, 0x70, 0xcc, 0x23, 0x64, 0x1c, 0x00, 0xb1, + 0x24, 0xc0, 0xb9, 0x0b, 0xa2, 0x58, 0x17, 0xf2, 0x08, 0x40, 0xef, 0xf1, 0x27, 0x31, 0xa5, 0x60, 0x92, 0x8e, 0x55, + 0x08, 0x82, 0x38, 0x3e, 0xbb, 0x16, 0xad, 0xc9, 0x59, 0xa2, 0x83, 0x19, 0x49, 0x80, 0x0d, 0x31, 0xb0, 0x73, 0x70, + 0x3f, 0x07, 0xa5, 0x87, 0xd5, 0x3b, 0x21, 0x17, 0x7c, 0xc7, 0x3d, 0xd9, 0x2c, 0x5c, 0x3d, 0xe1, 0x20, 0xb8, 0xe3, + 0x9a, 0x05, 0x18, 0x55, 0xc5, 0xba, 0xac, 0x78, 0xfa, 0xe1, 0x6e, 0x05, 0xb1, 0xef, 0x70, 0x40, 0xdf, 0xc9, 0x3c, + 0x4b, 0xee, 0x42, 0x67, 0xcf, 0xb5, 0x51, 0xe9, 0x3f, 0x7c, 0x78, 0xf3, 0x73, 0x04, 0x22, 0xc7, 0xda, 0x50, 0xfa, + 0x3b, 0x8e, 0x67, 0x93, 0x1f, 0xe1, 0xc9, 0xdf, 0xd8, 0x77, 0xdc, 0x9e, 0x1e, 0xfd, 0x3e, 0xd4, 0x4d, 0xef, 0xf8, + 0xec, 0x8e, 0x8f, 0x5c, 0x71, 0xa8, 0xae, 0x70, 0x5f, 0xdf, 0xac, 0x7d, 0x23, 0xa4, 0x87, 0xe7, 0x99, 0xf2, 0xc6, + 0xfc, 0x68, 0x07, 0xc3, 0x20, 0x98, 0x6a, 0xa1, 0x24, 0x44, 0xdd, 0x60, 0x4a, 0xc0, 0x10, 0xed, 0xe9, 0x65, 0x35, + 0x45, 0xce, 0x4d, 0x8d, 0x2c, 0xbc, 0x1f, 0x30, 0x2d, 0x74, 0x68, 0xe4, 0x50, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc2, + 0x6f, 0x95, 0x30, 0xfd, 0x6a, 0x51, 0x39, 0x07, 0xd1, 0x3d, 0x30, 0xc6, 0x15, 0xbc, 0x80, 0xae, 0xb0, 0xeb, 0xb5, + 0x8a, 0x8a, 0x81, 0xe0, 0x71, 0xc8, 0x01, 0x7a, 0xd8, 0x05, 0x2d, 0x2b, 0x4b, 0x75, 0xab, 0x72, 0x96, 0x2a, 0xea, + 0x32, 0x94, 0x95, 0xb1, 0xc2, 0x7c, 0x2f, 0xd9, 0x0f, 0x05, 0x7a, 0x96, 0x4f, 0x45, 0x17, 0xbc, 0x10, 0x4a, 0xb0, + 0x5c, 0xd7, 0x3b, 0x11, 0x88, 0x3a, 0x3f, 0xf4, 0xae, 0xfa, 0x1a, 0xc7, 0x8e, 0xa7, 0x6f, 0x64, 0xca, 0xb5, 0x09, + 0x85, 0xe6, 0xf3, 0xa5, 0xaf, 0x98, 0x28, 0xd8, 0x0d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd6, 0x7a, 0x33, 0x28, + 0xd1, 0x31, 0xaf, 0x51, 0x70, 0xad, 0x14, 0x0a, 0x46, 0x7b, 0x1b, 0x7f, 0x86, 0x23, 0xb7, 0xba, 0x3d, 0xf4, 0x7e, + 0xab, 0xe2, 0xcb, 0xb7, 0xe8, 0xdb, 0x69, 0x7f, 0x8e, 0x2a, 0xf9, 0xeb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, + 0xe2, 0xd2, 0x42, 0x3d, 0xa7, 0xef, 0x8e, 0xdf, 0x82, 0x1f, 0x25, 0xfe, 0xfe, 0xed, 0xfb, 0xa0, 0x26, 0xd3, 0x78, + 0x56, 0x98, 0x0f, 0x6d, 0x0e, 0x08, 0x4d, 0xe2, 0xd2, 0xec, 0xfb, 0x59, 0xdc, 0x64, 0xdf, 0x35, 0x5b, 0x4f, 0x8b, + 0x26, 0x92, 0x94, 0xe1, 0xf6, 0xc1, 0x80, 0x40, 0x1f, 0x20, 0x8a, 0xb3, 0x2f, 0x68, 0x0c, 0x69, 0x3e, 0xb3, 0xef, + 0x47, 0xc4, 0x7b, 0xb9, 0x13, 0x42, 0x8c, 0x2b, 0x2c, 0x1a, 0x3d, 0xe4, 0x33, 0x1e, 0x29, 0xc3, 0xa2, 0xf7, 0x98, + 0x40, 0x9c, 0xe1, 0xb4, 0x7a, 0x8f, 0x98, 0xc7, 0x78, 0x37, 0xd0, 0xb2, 0x87, 0x28, 0xa3, 0x2e, 0x7b, 0xc3, 0xe2, + 0xfb, 0xe3, 0x3a, 0xcc, 0xac, 0xe5, 0xe5, 0x10, 0xfe, 0x06, 0xda, 0x00, 0x9c, 0x72, 0x64, 0xf9, 0x2a, 0xb3, 0xd1, + 0xd5, 0x12, 0xd3, 0x9b, 0x08, 0x62, 0xf1, 0xe8, 0x74, 0x58, 0xbb, 0x3a, 0x55, 0xef, 0x6a, 0xe7, 0x33, 0xd1, 0xab, + 0x40, 0x2b, 0xd7, 0xb6, 0xc7, 0x43, 0xb8, 0x4b, 0x2d, 0xad, 0xb0, 0x11, 0xe5, 0x5c, 0x3c, 0xdd, 0x39, 0x36, 0x27, + 0xa0, 0xc1, 0x95, 0x4c, 0x01, 0x38, 0x4b, 0xab, 0xd1, 0xa8, 0x11, 0xf6, 0x59, 0x39, 0x9f, 0xc3, 0xd6, 0x42, 0x3c, + 0x2d, 0x00, 0xc3, 0x6d, 0x62, 0x50, 0xf2, 0x6e, 0x0c, 0xca, 0xe9, 0x47, 0x05, 0x6f, 0x1d, 0x9c, 0x95, 0xcb, 0x38, + 0x95, 0x37, 0x80, 0xc5, 0x18, 0xf8, 0xa9, 0x58, 0xaa, 0x97, 0x90, 0x2c, 0x79, 0xf2, 0x11, 0xad, 0x36, 0xd2, 0x00, + 0xb8, 0xca, 0xa9, 0xb1, 0xdc, 0x53, 0x20, 0xa1, 0xae, 0x14, 0x95, 0x10, 0x57, 0x55, 0x9c, 0x2c, 0x4f, 0x31, 0x35, + 0xdc, 0x40, 0x2f, 0xa2, 0x40, 0xae, 0xb8, 0x00, 0x92, 0x9e, 0xb3, 0x7f, 0x65, 0x1a, 0x6b, 0xfc, 0xb9, 0x44, 0x01, + 0x93, 0x46, 0x0d, 0xc6, 0x4a, 0xd9, 0x4b, 0x69, 0xa2, 0xbd, 0x05, 0x41, 0xed, 0x5e, 0xfe, 0x05, 0x75, 0x3f, 0x87, + 0x56, 0x84, 0x0d, 0x30, 0x44, 0x79, 0x8e, 0x3b, 0x34, 0xb5, 0x4b, 0xce, 0x03, 0x46, 0x74, 0xde, 0x67, 0xb5, 0xdd, + 0xea, 0xcf, 0x97, 0x80, 0x6d, 0x9a, 0x1a, 0x9f, 0xc2, 0x30, 0x21, 0x26, 0x36, 0xb0, 0x55, 0x56, 0xda, 0x0d, 0x65, + 0xda, 0x49, 0x97, 0xcc, 0x6b, 0xe1, 0x34, 0xef, 0x31, 0xb6, 0x1c, 0xa9, 0xdc, 0xfd, 0x7e, 0x68, 0x7e, 0xb2, 0x9c, + 0x3e, 0xd7, 0x21, 0x9b, 0xbd, 0xf1, 0xa0, 0x39, 0xd1, 0xea, 0xaa, 0x8e, 0x7e, 0x40, 0x07, 0x60, 0xa6, 0x2d, 0x40, + 0xa6, 0x0b, 0x36, 0xed, 0x2b, 0x51, 0x71, 0x49, 0xc2, 0x52, 0x49, 0x60, 0x67, 0x37, 0x25, 0x3b, 0x9b, 0x80, 0x78, + 0x86, 0xbb, 0x9e, 0x16, 0x3b, 0x21, 0x4d, 0x78, 0x8b, 0xbd, 0x04, 0x44, 0x1d, 0xaa, 0xba, 0x84, 0x6c, 0x8c, 0xa1, + 0x8b, 0x7f, 0x51, 0x0a, 0x13, 0xd6, 0x32, 0xa9, 0x4a, 0x4c, 0x10, 0xa4, 0x72, 0xb7, 0x45, 0x60, 0x89, 0x82, 0x1d, + 0xc0, 0xde, 0xbb, 0x51, 0x37, 0xa3, 0xa6, 0xaa, 0x53, 0x2f, 0xc1, 0xc7, 0x69, 0xd6, 0x55, 0x90, 0x59, 0xd8, 0x55, + 0xb1, 0xe6, 0x81, 0x8e, 0x4d, 0xa5, 0x8c, 0x89, 0xbb, 0xb4, 0xc8, 0x10, 0x0f, 0x18, 0x63, 0xe9, 0x42, 0x20, 0xdf, + 0x6c, 0x77, 0xdc, 0xf4, 0x04, 0xa1, 0x9f, 0xb0, 0xa1, 0x04, 0x6e, 0x3a, 0xdb, 0x53, 0xd3, 0xcc, 0x07, 0x44, 0x1c, + 0x06, 0x14, 0x48, 0x36, 0x0e, 0x69, 0x8e, 0xf4, 0x05, 0x49, 0x13, 0x06, 0x86, 0x56, 0x3c, 0x27, 0xc8, 0x8a, 0x42, + 0xcf, 0xd6, 0x55, 0x1b, 0xe7, 0xca, 0x30, 0x47, 0x4b, 0x4e, 0x85, 0xcf, 0x09, 0x32, 0xb1, 0x7b, 0xda, 0x66, 0x26, + 0xc3, 0x51, 0xb2, 0xc0, 0xfc, 0x0a, 0xa2, 0xc4, 0x9d, 0x69, 0x56, 0xe5, 0x60, 0x5c, 0xc0, 0x02, 0xad, 0x7c, 0x0f, + 0xea, 0xc6, 0x1a, 0xda, 0x68, 0x18, 0x62, 0xb7, 0x3f, 0xc1, 0x7e, 0xad, 0x9d, 0xd6, 0x65, 0x8a, 0xe5, 0x65, 0x0a, + 0xd1, 0x5e, 0xc8, 0xfc, 0x46, 0x91, 0xe8, 0x4e, 0x11, 0x86, 0x84, 0x75, 0x94, 0x3d, 0x69, 0x53, 0x03, 0xe8, 0xa9, + 0x17, 0xf0, 0xbc, 0x73, 0x2d, 0xc3, 0x2e, 0xd2, 0xfd, 0x55, 0xc1, 0xa7, 0x74, 0x83, 0x20, 0x45, 0x6f, 0x52, 0x30, + 0xe7, 0xf5, 0x28, 0xa9, 0x37, 0xa7, 0x2d, 0x33, 0xaa, 0x8e, 0x8a, 0x90, 0x72, 0x82, 0xff, 0xe4, 0xa5, 0xd4, 0xc4, + 0x26, 0x4c, 0xf0, 0xc0, 0x87, 0x79, 0x86, 0x0d, 0xbc, 0xdd, 0xbe, 0x4b, 0xc3, 0xa4, 0xcd, 0x36, 0xa4, 0x20, 0xad, + 0x30, 0x71, 0x31, 0xa0, 0xb2, 0xd7, 0xb8, 0x5f, 0xb0, 0x9d, 0x34, 0x05, 0x0f, 0xc2, 0x46, 0x03, 0x13, 0xb7, 0xba, + 0xf8, 0x3a, 0x4c, 0x68, 0xb8, 0xa4, 0xda, 0xd9, 0x49, 0x4b, 0x9a, 0xdb, 0xeb, 0xf2, 0xc2, 0xf6, 0x41, 0xc7, 0x0e, + 0xeb, 0x1a, 0x1e, 0x68, 0x5e, 0xb3, 0x8b, 0x2b, 0xa6, 0x69, 0xa2, 0xb1, 0x1e, 0x52, 0x96, 0x1c, 0xeb, 0x7a, 0xba, + 0xc2, 0xd5, 0x32, 0xd3, 0xc0, 0xee, 0x12, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x81, 0xcd, 0x66, 0xab, + 0x9a, 0x4c, 0xf3, 0xfb, 0xb2, 0xe5, 0x26, 0x20, 0x9c, 0xa5, 0xbe, 0xb9, 0x4f, 0x8e, 0x35, 0x6d, 0xf3, 0x93, 0x00, + 0xc7, 0xdb, 0x2b, 0x20, 0xe9, 0x58, 0x82, 0x2e, 0xbe, 0xa5, 0x3f, 0x88, 0xd4, 0x4c, 0x05, 0xbd, 0x77, 0xbe, 0x48, + 0xdd, 0xfc, 0x02, 0x6c, 0xa3, 0x36, 0xc6, 0x34, 0x2b, 0x5b, 0x87, 0x89, 0xb2, 0xb0, 0x46, 0x16, 0x72, 0x09, 0x3e, + 0x98, 0xbb, 0x4d, 0x9d, 0x1e, 0x77, 0x10, 0x61, 0xbf, 0x8b, 0x1e, 0x8f, 0x30, 0x56, 0xac, 0x41, 0x62, 0x58, 0x85, + 0x35, 0x6d, 0x2e, 0x87, 0x28, 0xa7, 0x66, 0xc9, 0x44, 0x4b, 0xea, 0x53, 0x8a, 0x28, 0x05, 0x73, 0xe3, 0x69, 0xd9, + 0x30, 0x25, 0x44, 0xc8, 0x0a, 0xe9, 0x80, 0x6a, 0x2d, 0xb4, 0x54, 0x13, 0xf4, 0x3a, 0xf4, 0xb2, 0xd0, 0x98, 0x82, + 0xe8, 0x23, 0x32, 0xdc, 0x88, 0x23, 0xa3, 0xbb, 0x63, 0x14, 0x13, 0x08, 0x55, 0xed, 0xe5, 0x85, 0xd5, 0xa7, 0x65, + 0x5b, 0x1d, 0xc4, 0x15, 0x22, 0xdf, 0x77, 0x13, 0xd4, 0x18, 0x05, 0x6d, 0x4e, 0x37, 0xfa, 0x6b, 0x11, 0xfa, 0x76, + 0xe1, 0xd8, 0x8d, 0x82, 0x48, 0x88, 0xc0, 0xea, 0x35, 0x15, 0x03, 0xb2, 0xce, 0x63, 0x17, 0xa1, 0x49, 0x77, 0x0b, + 0x51, 0xde, 0xa8, 0xac, 0x3f, 0xae, 0x43, 0xb2, 0xdd, 0x62, 0x59, 0xe0, 0xcb, 0x7e, 0xba, 0xbe, 0x07, 0xf2, 0xfb, + 0xcd, 0xfa, 0xb3, 0x90, 0xdf, 0xaf, 0xb3, 0x2f, 0x81, 0xfc, 0x7e, 0xb3, 0xfe, 0x9f, 0x86, 0xfc, 0x3e, 0x5d, 0x7b, + 0x90, 0xdf, 0x6a, 0x30, 0x7e, 0x2f, 0x58, 0x70, 0xf2, 0x36, 0xa0, 0x2f, 0x24, 0x0b, 0x4e, 0x5e, 0xbd, 0xf2, 0x8d, + 0x40, 0x84, 0x46, 0xae, 0x37, 0xb2, 0x60, 0xc4, 0x6d, 0x81, 0x57, 0xa8, 0x75, 0xf2, 0x81, 0x8a, 0x32, 0x00, 0x5e, + 0x2f, 0xff, 0x91, 0x55, 0xcb, 0x30, 0xd8, 0x0f, 0xc8, 0xcc, 0x41, 0x82, 0x0e, 0x27, 0x70, 0x7b, 0x43, 0x23, 0xcb, + 0xea, 0x8b, 0xe0, 0xc3, 0x47, 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0xa5, 0xce, 0x6c, 0x24, 0x04, 0x3c, 0xce, 0x78, 0x69, + 0x43, 0x44, 0x2c, 0xe3, 0xf2, 0x4c, 0xc7, 0x66, 0x29, 0xed, 0x56, 0x84, 0x88, 0xf3, 0x67, 0x80, 0x53, 0x6f, 0xf7, + 0x66, 0x8c, 0xfd, 0x50, 0x1c, 0xb1, 0x0e, 0x20, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, + 0x06, 0xbd, 0x84, 0xbb, 0x88, 0xe0, 0x49, 0xe5, 0xb1, 0x4d, 0x0a, 0xa8, 0x3c, 0xd3, 0x40, 0xe5, 0x1d, 0xef, 0x69, + 0x68, 0x87, 0x45, 0xfb, 0x00, 0x1b, 0xe9, 0x72, 0x06, 0x46, 0x8b, 0x2f, 0xaf, 0xb9, 0xa8, 0x7e, 0x06, 0x3c, 0x75, + 0xc1, 0x0b, 0xb8, 0x25, 0x20, 0x17, 0xdb, 0x70, 0x42, 0xa0, 0xc2, 0xf7, 0xec, 0x50, 0x51, 0x63, 0x8c, 0x68, 0xa2, + 0xd1, 0x6f, 0xbc, 0x09, 0xa1, 0x77, 0x27, 0xe8, 0x8a, 0x30, 0x12, 0xde, 0x5f, 0x6b, 0x7e, 0x96, 0x81, 0xf9, 0xbc, + 0x00, 0x28, 0x0d, 0x84, 0x43, 0x65, 0x4a, 0x6e, 0x81, 0x09, 0x1b, 0x63, 0xae, 0x94, 0xa5, 0x1e, 0x52, 0x29, 0x55, + 0x70, 0xba, 0x82, 0xa6, 0x12, 0x70, 0xb8, 0x23, 0x09, 0x60, 0xa6, 0xb6, 0x30, 0x88, 0x6e, 0x9b, 0xd2, 0x2c, 0x8d, + 0x9c, 0x22, 0xcd, 0xe1, 0x93, 0x52, 0x05, 0x3a, 0x7d, 0x96, 0xc4, 0x15, 0xbf, 0x94, 0x05, 0x84, 0xc2, 0x6d, 0xa5, + 0x50, 0xa4, 0xdf, 0x67, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0x39, 0x5b, 0x66, 0x65, 0x05, 0xf9, 0xe6, 0xfa, 0xf4, 0x5b, + 0xd4, 0xd3, 0x02, 0xe7, 0x4d, 0x4d, 0x0a, 0x33, 0xf3, 0x78, 0xac, 0x76, 0x3a, 0xa8, 0x57, 0xbd, 0xd7, 0x06, 0xfb, + 0xbd, 0x39, 0xd1, 0xe3, 0xd6, 0x7a, 0xb0, 0x9a, 0xd4, 0x66, 0xaa, 0x82, 0x38, 0x02, 0xea, 0xc0, 0x8e, 0x70, 0x16, + 0x53, 0xba, 0xb6, 0x08, 0x2a, 0x60, 0xed, 0x80, 0x39, 0x32, 0x71, 0x79, 0x76, 0xa3, 0xe4, 0x27, 0x3d, 0x45, 0x61, + 0xd2, 0x28, 0x56, 0xc8, 0x3e, 0x4b, 0x16, 0xae, 0x59, 0x72, 0x4f, 0xae, 0x75, 0x94, 0x34, 0x30, 0xba, 0xe2, 0xf6, + 0x40, 0x1c, 0x26, 0xed, 0x94, 0xed, 0x76, 0x27, 0x13, 0xb0, 0x06, 0xad, 0x24, 0x88, 0xd6, 0xb1, 0x9c, 0x0d, 0x27, + 0x11, 0x40, 0xa8, 0x68, 0xb2, 0xf6, 0xd7, 0x9a, 0x1b, 0x90, 0xf9, 0x50, 0x7b, 0xfa, 0x39, 0x91, 0xbc, 0x1e, 0x59, + 0xcf, 0x38, 0x4e, 0x4f, 0xfb, 0x1c, 0x0c, 0xb3, 0xfc, 0x21, 0x81, 0x48, 0x30, 0x9d, 0xd3, 0xb3, 0x98, 0x6a, 0x33, + 0x61, 0xc3, 0xa3, 0xd0, 0x2f, 0xfb, 0x4e, 0x03, 0xe0, 0x26, 0x3c, 0x1c, 0x3e, 0x1b, 0x93, 0x5a, 0xdb, 0xac, 0xe3, + 0x02, 0xb2, 0xbf, 0xd5, 0x22, 0x73, 0xcf, 0x76, 0xa1, 0xd1, 0xa6, 0xb7, 0x41, 0xbb, 0x46, 0x2a, 0xee, 0xe9, 0x7e, + 0x4d, 0x6a, 0xb7, 0x60, 0xac, 0x04, 0xe9, 0x0f, 0x75, 0x6a, 0x9d, 0x3d, 0xda, 0x64, 0xba, 0xca, 0xfa, 0x8f, 0xcc, + 0xc6, 0x9b, 0x6b, 0x50, 0x80, 0x5a, 0x2f, 0x25, 0x1f, 0xee, 0xad, 0x23, 0x9b, 0x9e, 0x18, 0x96, 0x75, 0x92, 0x91, + 0x91, 0x7a, 0xe4, 0x2a, 0xfc, 0x56, 0x77, 0x16, 0x7e, 0xcb, 0x93, 0xb0, 0xab, 0x61, 0x8a, 0xc3, 0x37, 0x5d, 0x40, + 0x04, 0x4c, 0x90, 0xeb, 0x87, 0x7f, 0x3c, 0xda, 0x34, 0xc9, 0x52, 0xbd, 0xef, 0x7d, 0x86, 0xbf, 0xb3, 0x14, 0xfe, + 0x56, 0xf5, 0x1f, 0x74, 0x73, 0xc5, 0xab, 0xa5, 0x4c, 0xa3, 0xe0, 0xdd, 0xc9, 0xe9, 0x87, 0x40, 0x23, 0xab, 0xe3, + 0xfd, 0xc2, 0x68, 0x94, 0x0d, 0x86, 0x13, 0x68, 0x58, 0x72, 0x79, 0x89, 0xe0, 0x82, 0x1a, 0x9d, 0xfe, 0x74, 0x29, + 0x6f, 0x8e, 0xf3, 0xdc, 0x67, 0x82, 0x0d, 0xe1, 0xd4, 0x7c, 0x61, 0x83, 0xea, 0x84, 0x20, 0xcb, 0x1b, 0x65, 0xe5, + 0x99, 0xd6, 0xbe, 0xa4, 0x67, 0xe7, 0x77, 0x67, 0x5a, 0xc2, 0x63, 0xd1, 0x1d, 0x9f, 0xff, 0x71, 0x98, 0x66, 0xd7, + 0x7b, 0x48, 0xdd, 0x59, 0x00, 0xa6, 0xf1, 0x39, 0x3f, 0x5f, 0x57, 0x95, 0x14, 0xc3, 0x42, 0xde, 0x04, 0x47, 0x87, + 0xea, 0xc1, 0x64, 0x88, 0xd5, 0x63, 0xb0, 0xf7, 0x5f, 0x49, 0x9e, 0x25, 0x1f, 0x59, 0xf0, 0x68, 0x93, 0xb1, 0xa3, + 0x16, 0x0d, 0x1f, 0xd7, 0xc1, 0x11, 0xb4, 0x75, 0xef, 0x38, 0xcf, 0x0f, 0xf7, 0xd5, 0x17, 0x47, 0x87, 0xfb, 0x69, + 0x76, 0x7d, 0xe4, 0x01, 0xed, 0x3b, 0xbb, 0x59, 0x84, 0x34, 0x73, 0xf7, 0x62, 0x70, 0x90, 0x4d, 0x78, 0x68, 0x39, + 0x09, 0x90, 0xc6, 0x98, 0x30, 0x25, 0x28, 0xc1, 0x09, 0x63, 0x38, 0x37, 0xb7, 0xdb, 0xd0, 0x1a, 0xf5, 0x24, 0x1e, + 0xe2, 0x4d, 0x01, 0x9c, 0x06, 0x66, 0xa1, 0x09, 0xa1, 0x49, 0x4d, 0x42, 0x83, 0xcb, 0x13, 0x13, 0x5a, 0xd4, 0x14, + 0x8e, 0x92, 0x37, 0xf1, 0xca, 0x08, 0xb1, 0xb4, 0x50, 0xc0, 0xb4, 0x7e, 0xd6, 0x18, 0xc7, 0xa8, 0x3d, 0xaa, 0x06, + 0x29, 0xab, 0x57, 0xde, 0x37, 0xb0, 0x20, 0xb7, 0x0c, 0x2b, 0x1a, 0xb4, 0x28, 0x04, 0xc8, 0x1d, 0x7d, 0x71, 0x19, + 0xa7, 0xe1, 0xbc, 0xa4, 0x72, 0x41, 0xd8, 0x51, 0xb8, 0x41, 0xb6, 0xb9, 0x54, 0x54, 0x38, 0x92, 0xb5, 0x83, 0xad, + 0x54, 0xb3, 0x73, 0xf4, 0x68, 0x23, 0x10, 0x29, 0xb1, 0x64, 0x47, 0xcd, 0xf9, 0xaa, 0xe2, 0xf3, 0xe1, 0x92, 0x83, + 0x7f, 0x4d, 0xb0, 0xf7, 0x5f, 0xe9, 0x79, 0x6e, 0x27, 0x45, 0xad, 0xc8, 0x65, 0x2c, 0xd2, 0x9c, 0x7f, 0x88, 0xcf, + 0x7f, 0xc0, 0x3c, 0x2f, 0xce, 0xf3, 0xe7, 0x90, 0xa1, 0x0e, 0x8e, 0x1e, 0x6d, 0x92, 0x6a, 0xf4, 0xf2, 0xed, 0x87, + 0xd7, 0x1f, 0xfe, 0x79, 0xf6, 0xfc, 0xf8, 0xc3, 0xcb, 0xef, 0x4f, 0xde, 0xbf, 0x7e, 0x79, 0x3a, 0xb7, 0x0e, 0xad, + 0x0a, 0x27, 0x8d, 0x2c, 0xb6, 0x5b, 0x97, 0xef, 0xd7, 0xb7, 0x2f, 0x5e, 0xbe, 0x7a, 0xfd, 0xf6, 0xe5, 0x8b, 0x5a, + 0xcd, 0x65, 0xbb, 0x21, 0xb0, 0x43, 0xe3, 0x4c, 0xf0, 0x02, 0x8a, 0xd7, 0xd1, 0x1a, 0xb1, 0xd9, 0x1a, 0xde, 0xaf, + 0xd9, 0x74, 0x1d, 0x09, 0x01, 0x16, 0xd9, 0x9e, 0xde, 0x2c, 0xd0, 0x70, 0x69, 0x36, 0x8e, 0xbf, 0xc4, 0xfc, 0xde, + 0xbc, 0xc4, 0xef, 0xde, 0xcb, 0x1b, 0xd3, 0x15, 0x3d, 0x42, 0x0a, 0xb9, 0x6b, 0xf6, 0xfc, 0x8f, 0x43, 0x5f, 0x5a, + 0x86, 0x22, 0x05, 0x55, 0x2e, 0xfc, 0xaa, 0x83, 0x3d, 0x6d, 0xb9, 0x17, 0x40, 0xe0, 0x89, 0xe0, 0xe8, 0x70, 0xdf, + 0xcf, 0x7d, 0xf4, 0x47, 0xf4, 0xb3, 0xd7, 0x39, 0x2c, 0x15, 0xc6, 0xa1, 0x99, 0xb6, 0x73, 0xba, 0x41, 0x68, 0x24, + 0x77, 0xfe, 0xa9, 0x15, 0x64, 0xc8, 0x95, 0x24, 0x91, 0x9d, 0x44, 0x65, 0x91, 0x62, 0x4a, 0xfb, 0x43, 0xff, 0x75, + 0x7d, 0xc6, 0x1b, 0x3e, 0x17, 0xa5, 0x2c, 0x02, 0xe8, 0x47, 0x3b, 0x5e, 0xc4, 0x9e, 0x17, 0x97, 0x05, 0x7b, 0xd4, + 0x49, 0xde, 0x61, 0x44, 0xf6, 0xdb, 0x9f, 0x7a, 0x1d, 0xfb, 0x83, 0xb8, 0x1f, 0x7b, 0xba, 0x33, 0x2d, 0xf2, 0x62, + 0x1b, 0x78, 0x7f, 0x5c, 0x8f, 0xf9, 0x49, 0x46, 0xff, 0x21, 0xe9, 0x65, 0x4c, 0xaf, 0x62, 0x7a, 0x2a, 0x16, 0x75, + 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, + 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, + 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, + 0xdc, 0xb3, 0x2e, 0xb7, 0x6d, 0x5c, 0xfd, 0xbf, 0x4f, 0x01, 0xc3, 0xae, 0x03, 0xd8, 0x00, 0x04, 0x90, 0xa2, 0x28, + 0x93, 0x22, 0x95, 0xc4, 0x76, 0xa6, 0xea, 0x28, 0x71, 0xc6, 0x56, 0x3d, 0x6d, 0x14, 0x8d, 0x08, 0x82, 0x4b, 0x12, + 0x35, 0x08, 0x60, 0x00, 0x50, 0xa2, 0x42, 0xa3, 0xcf, 0xd2, 0x67, 0xe9, 0x93, 0x7d, 0x73, 0xce, 0x5e, 0xb0, 0xb8, + 0x91, 0x54, 0xec, 0xb4, 0xdf, 0xa4, 0xaa, 0x89, 0xc5, 0xee, 0x62, 0xf7, 0xec, 0xee, 0xd9, 0x73, 0x3f, 0xee, 0x82, + 0xc9, 0x5e, 0x0c, 0x8d, 0x1c, 0xf6, 0xb9, 0xcf, 0x9f, 0x89, 0x85, 0x5b, 0x12, 0x08, 0x3e, 0x2b, 0x8b, 0x16, 0x8b, + 0x80, 0x68, 0x2a, 0x4f, 0x1e, 0xa2, 0x1a, 0xe2, 0x33, 0xe7, 0x4f, 0x6c, 0x1e, 0xb1, 0x53, 0xcf, 0xdb, 0x8e, 0x16, + 0x9f, 0x31, 0x11, 0x21, 0xed, 0x28, 0xe5, 0x8a, 0xb2, 0xd9, 0x3b, 0x54, 0x6f, 0xb0, 0x75, 0x29, 0x8e, 0xae, 0x39, + 0x8b, 0xd6, 0xd3, 0x80, 0x98, 0xb8, 0xdd, 0xe1, 0x93, 0xdb, 0xe9, 0x7a, 0x3a, 0x85, 0x2c, 0x2d, 0x4f, 0x6c, 0x03, + 0xe2, 0xce, 0x44, 0x29, 0xf2, 0x83, 0xb9, 0x3e, 0x84, 0x49, 0x59, 0x59, 0x75, 0xf8, 0x60, 0x2b, 0x02, 0xa2, 0x1e, + 0xfa, 0x81, 0x0c, 0x78, 0xbf, 0x86, 0x53, 0x3b, 0x52, 0x3f, 0xc0, 0xee, 0x4b, 0xd5, 0x61, 0xd3, 0xd1, 0x1f, 0x5d, + 0xab, 0x1f, 0x10, 0xc6, 0x98, 0xbd, 0xf8, 0x35, 0xdd, 0xbd, 0xaa, 0xa1, 0x52, 0xa5, 0xf7, 0x1a, 0xf3, 0x18, 0x80, + 0xd0, 0xf7, 0x8d, 0xef, 0x2e, 0xc2, 0x28, 0xcd, 0x7c, 0x4f, 0xbd, 0x19, 0x5e, 0xf8, 0xda, 0xf5, 0x2a, 0xd3, 0xf4, + 0x1b, 0xc3, 0xcb, 0xe4, 0x14, 0x28, 0x1c, 0x61, 0x62, 0x06, 0x94, 0xb6, 0x4a, 0xf2, 0x09, 0xda, 0x59, 0x91, 0xa3, + 0x66, 0xac, 0xe4, 0x65, 0x23, 0xa8, 0x57, 0xc9, 0xa7, 0x82, 0x89, 0xa1, 0x54, 0x6c, 0xa9, 0x0f, 0x29, 0xa7, 0xf2, + 0x7a, 0xbd, 0xc5, 0xab, 0x3c, 0x2b, 0x6e, 0x4b, 0x8c, 0x01, 0xcc, 0x1d, 0x67, 0xe8, 0xf3, 0x13, 0xd9, 0xe8, 0xb3, + 0x74, 0xef, 0x4e, 0xbe, 0x2b, 0xd3, 0x05, 0x70, 0x7f, 0x83, 0xc5, 0x45, 0x18, 0x65, 0x0a, 0x04, 0xb6, 0x81, 0x2f, + 0x4e, 0xaa, 0x46, 0x62, 0xac, 0x57, 0x4d, 0xcf, 0x19, 0x32, 0xf8, 0x1e, 0x2f, 0x3f, 0x8d, 0x85, 0x37, 0x2b, 0x45, + 0xb0, 0xa0, 0xcc, 0x42, 0x08, 0x0b, 0x98, 0x45, 0x97, 0xd1, 0x7d, 0x55, 0x0f, 0xf2, 0x7a, 0xb2, 0xff, 0xee, 0xd5, + 0x38, 0x99, 0xcc, 0xb3, 0xfa, 0x69, 0x2c, 0x31, 0x29, 0x27, 0x74, 0x2a, 0x67, 0x0a, 0x0d, 0x3f, 0x38, 0x0d, 0x93, + 0x81, 0x9d, 0x18, 0xde, 0x05, 0x80, 0x92, 0xd8, 0x35, 0x3d, 0xc9, 0x6f, 0x79, 0xea, 0x64, 0x9e, 0xb8, 0x58, 0xba, + 0x9c, 0x01, 0xbb, 0x86, 0xf1, 0x3a, 0xc3, 0x50, 0xbb, 0x30, 0x00, 0x92, 0xab, 0x0a, 0x86, 0xee, 0x04, 0x2c, 0x5d, + 0x90, 0x89, 0xb9, 0xaa, 0xf8, 0xb3, 0x7a, 0x19, 0x23, 0x7a, 0x01, 0x79, 0x21, 0x7e, 0x47, 0x41, 0x15, 0x3c, 0x26, + 0x6c, 0x1a, 0x9e, 0x51, 0xc4, 0xa9, 0xd7, 0x3c, 0x54, 0xe8, 0x34, 0x60, 0x06, 0x8f, 0xf6, 0x33, 0xd4, 0x82, 0xc6, + 0xc9, 0x42, 0xf8, 0xcd, 0xd2, 0x34, 0x27, 0xcf, 0xb6, 0x61, 0x7e, 0xfe, 0x6c, 0x9b, 0xe6, 0xa3, 0x67, 0x5b, 0x17, + 0x28, 0xb9, 0x5c, 0x85, 0x89, 0x16, 0x8e, 0x3a, 0xc5, 0xf4, 0x60, 0x53, 0xd1, 0x72, 0x05, 0x35, 0xf5, 0x23, 0xa6, + 0x8f, 0x8f, 0x13, 0x7f, 0xe5, 0x26, 0x0f, 0x54, 0x7d, 0x6f, 0xc8, 0x3a, 0x7e, 0x5d, 0x55, 0x28, 0x5e, 0xa7, 0xf3, + 0xa5, 0x28, 0x5e, 0x55, 0xbe, 0x15, 0x65, 0x84, 0x4d, 0x4e, 0xe8, 0x30, 0xe1, 0x5b, 0xb7, 0xea, 0x4b, 0x62, 0xcd, + 0x48, 0xe6, 0xfa, 0x01, 0x6d, 0x32, 0xe4, 0xc9, 0xe9, 0x6b, 0xb3, 0x49, 0xcb, 0xb3, 0x09, 0xcb, 0xdb, 0x05, 0x27, + 0x43, 0x31, 0x3e, 0x1d, 0x37, 0xce, 0x0c, 0x93, 0x56, 0x35, 0x2f, 0x20, 0x7d, 0xf7, 0x5f, 0x85, 0x3e, 0x01, 0xe8, + 0x87, 0x00, 0x7d, 0x12, 0x7a, 0xd1, 0x8c, 0xfc, 0xed, 0xfd, 0x85, 0xc8, 0x92, 0x05, 0x02, 0x9f, 0x09, 0xdb, 0x87, + 0x29, 0x92, 0x0b, 0x09, 0x92, 0x0a, 0x34, 0x9f, 0x95, 0x22, 0x76, 0x4c, 0x92, 0xab, 0xca, 0x39, 0x1d, 0x3b, 0x99, + 0xd1, 0x51, 0x8f, 0x22, 0x6c, 0x95, 0xe4, 0x67, 0x47, 0xb4, 0x36, 0xbd, 0xdc, 0x68, 0x25, 0x00, 0x43, 0x02, 0x33, + 0x2c, 0xa0, 0x00, 0x09, 0x3d, 0x47, 0x4e, 0xc1, 0x3f, 0x58, 0x2b, 0x14, 0xab, 0x3b, 0xe7, 0x65, 0xca, 0x04, 0x5b, + 0xa9, 0xe3, 0x33, 0x4c, 0xd1, 0x05, 0xd7, 0x33, 0x04, 0xf5, 0x38, 0x3b, 0xa2, 0x8f, 0x4a, 0xe5, 0x00, 0x14, 0x9d, + 0x70, 0x4e, 0x6e, 0xc0, 0x3a, 0x78, 0xd4, 0xc9, 0x80, 0x8c, 0xf0, 0x50, 0xea, 0xe6, 0xaa, 0xb2, 0x62, 0x94, 0x10, + 0x8b, 0x1e, 0x04, 0xa1, 0x05, 0x6c, 0x38, 0xaa, 0xaa, 0xb2, 0x72, 0x37, 0x38, 0x73, 0xfe, 0xc6, 0xdd, 0x68, 0x0e, + 0x7b, 0x55, 0x1c, 0xad, 0xb4, 0x7c, 0xb4, 0x3c, 0xb6, 0xb8, 0xe0, 0x37, 0x20, 0x18, 0xe9, 0x25, 0xea, 0x63, 0x1b, + 0x16, 0x77, 0xc9, 0x17, 0x77, 0xd6, 0xb2, 0xb8, 0xb3, 0x1d, 0x8b, 0x1b, 0xb0, 0x85, 0x54, 0x04, 0xe8, 0x12, 0xf4, + 0x05, 0x13, 0xc0, 0x63, 0x74, 0xc5, 0x80, 0x9d, 0x33, 0x84, 0x93, 0x99, 0x06, 0x60, 0x0b, 0xd5, 0x02, 0xab, 0x26, + 0xb8, 0x48, 0x80, 0xa8, 0x4f, 0x5c, 0x9c, 0x3a, 0x3e, 0x6f, 0x48, 0xb9, 0xa9, 0x05, 0xd5, 0xf9, 0xc2, 0x2e, 0xa5, + 0xe9, 0xc4, 0xb5, 0x65, 0xcb, 0x4c, 0x97, 0x3b, 0x66, 0xea, 0x95, 0x8e, 0x2e, 0x9b, 0x36, 0x3d, 0x84, 0xf2, 0xa4, + 0x60, 0x0f, 0x82, 0x7d, 0x28, 0x6e, 0x99, 0xf2, 0x3e, 0x6c, 0x47, 0xa9, 0xd2, 0x8e, 0x8a, 0xdd, 0x34, 0xbd, 0x8f, + 0x12, 0x50, 0xb0, 0x40, 0x37, 0x8f, 0xdb, 0x52, 0x2b, 0x3f, 0x64, 0xb1, 0x5b, 0x5a, 0x37, 0x53, 0xf1, 0x5e, 0xde, + 0x52, 0x9d, 0x5e, 0x8f, 0xd6, 0x88, 0xdd, 0x2c, 0x23, 0x09, 0x02, 0xdd, 0x85, 0x20, 0xdf, 0xff, 0x4f, 0xb6, 0x59, + 0x03, 0x0e, 0x09, 0xf4, 0x02, 0xab, 0x23, 0x86, 0x8e, 0x81, 0x94, 0x4a, 0xf8, 0xbd, 0x2b, 0xc5, 0x81, 0x4b, 0x04, + 0xe0, 0x7f, 0xc2, 0xe3, 0xaa, 0x25, 0x92, 0xa7, 0x92, 0x73, 0xa2, 0x5b, 0xb1, 0x3b, 0xfb, 0x00, 0x7a, 0x3c, 0xad, + 0x63, 0x80, 0x4d, 0xae, 0x1c, 0xf5, 0x2d, 0xa1, 0xb4, 0x9d, 0x57, 0x20, 0x49, 0xc4, 0x92, 0xcc, 0xe2, 0x09, 0x9c, + 0x25, 0x5d, 0x73, 0x7e, 0xb3, 0xed, 0xe4, 0x47, 0x0b, 0x5f, 0xaf, 0x61, 0x4d, 0x40, 0x6d, 0xc1, 0x68, 0x2c, 0x58, + 0xac, 0xc0, 0x70, 0x4e, 0x74, 0x10, 0xf4, 0x5e, 0x43, 0xfa, 0x52, 0x9b, 0xf3, 0xaf, 0x93, 0x04, 0x2e, 0xa9, 0x6b, + 0xfb, 0x26, 0x7f, 0xbe, 0xc0, 0x5f, 0xce, 0x4d, 0xfe, 0x7c, 0x8a, 0xbf, 0x3a, 0x37, 0x98, 0xa8, 0xae, 0x81, 0x6f, + 0x97, 0xe6, 0xac, 0x8e, 0x4b, 0xfb, 0x89, 0x9a, 0x9b, 0x3d, 0x62, 0xdb, 0xb0, 0x05, 0x7e, 0xfa, 0x6c, 0x9b, 0x82, + 0x83, 0xa5, 0x3c, 0x87, 0xd0, 0x4a, 0xf4, 0xbc, 0xb1, 0x7c, 0xd1, 0x52, 0x3e, 0xd5, 0xff, 0xcb, 0xf7, 0x3c, 0xee, + 0x92, 0xa8, 0xb8, 0x53, 0xca, 0x52, 0x87, 0xdb, 0xa9, 0x1f, 0xba, 0xc9, 0xc3, 0x2d, 0xe5, 0x26, 0x34, 0x4e, 0xaa, + 0x0b, 0x69, 0x0a, 0xa5, 0x26, 0xcb, 0xda, 0xad, 0x4c, 0x92, 0xe7, 0x3e, 0xb0, 0x8b, 0x7e, 0xf4, 0xf7, 0x44, 0xa2, + 0xd2, 0x4a, 0xfc, 0x26, 0x5b, 0x90, 0xd2, 0x87, 0x6e, 0x9f, 0x6d, 0x35, 0x52, 0xef, 0xa6, 0x32, 0xdb, 0x0a, 0x19, + 0x08, 0xcb, 0x83, 0xbc, 0xeb, 0x6a, 0xe6, 0x0f, 0x50, 0x7d, 0x35, 0x8d, 0x36, 0xe6, 0xb3, 0x6d, 0x76, 0xae, 0xae, + 0xdc, 0xe4, 0x13, 0x99, 0x99, 0x9e, 0x9f, 0x78, 0x01, 0x51, 0x07, 0xea, 0x34, 0x70, 0xc3, 0x4f, 0xec, 0xd1, 0x8c, + 0xd6, 0x19, 0x2a, 0xa4, 0xf7, 0xb2, 0xba, 0x1c, 0x26, 0x54, 0x42, 0x87, 0xb4, 0x69, 0x03, 0x14, 0x94, 0xd7, 0x42, + 0xbe, 0x55, 0xd0, 0x85, 0x45, 0x2d, 0x03, 0xec, 0x29, 0x41, 0x47, 0x0e, 0x0e, 0xaa, 0x86, 0x8a, 0xeb, 0xa5, 0x1a, + 0xf2, 0x54, 0xa9, 0x6c, 0x52, 0x64, 0x58, 0xbc, 0xc5, 0x1e, 0x7e, 0xff, 0xe7, 0x68, 0xee, 0xeb, 0xc3, 0x3f, 0xc7, + 0x68, 0xbc, 0xf6, 0x0f, 0xca, 0x8d, 0xdd, 0x34, 0x5d, 0xaf, 0xc8, 0x8c, 0xea, 0xe2, 0xce, 0x8b, 0xa1, 0x94, 0x69, + 0x79, 0x79, 0x38, 0xbf, 0xae, 0x3b, 0xfd, 0xe3, 0xd7, 0x60, 0x23, 0x00, 0x34, 0x5d, 0x34, 0x9f, 0xab, 0x05, 0x57, + 0xbd, 0xa7, 0x99, 0x73, 0xfc, 0xeb, 0xfa, 0x87, 0xb7, 0xf6, 0x0f, 0xa2, 0x71, 0xa8, 0xea, 0xf9, 0x84, 0x2b, 0x3c, + 0x19, 0x69, 0x2a, 0x8d, 0x97, 0xcf, 0x68, 0xee, 0x86, 0xed, 0xd3, 0xb9, 0x2e, 0xed, 0xb2, 0x98, 0x90, 0x19, 0xd8, + 0xc2, 0x1a, 0xb5, 0xd2, 0xdb, 0x80, 0xdc, 0x11, 0xa1, 0x4c, 0xad, 0x7f, 0xac, 0xa1, 0x05, 0x46, 0x7b, 0x63, 0x4a, + 0x5a, 0x46, 0x58, 0x49, 0x53, 0x9a, 0xe0, 0x1c, 0xd8, 0xcc, 0xe5, 0x5d, 0x5e, 0xd9, 0xd5, 0x13, 0x43, 0x95, 0x06, + 0xd0, 0x3a, 0xb2, 0xf3, 0x96, 0xf2, 0x01, 0xa6, 0x7a, 0x6e, 0x1e, 0x9b, 0xe1, 0xe8, 0x03, 0x88, 0x8e, 0xcd, 0xe0, + 0x14, 0xc0, 0xe6, 0xd7, 0x0a, 0x01, 0x44, 0x1b, 0xc4, 0x9a, 0xc4, 0x52, 0x2a, 0x95, 0x77, 0x70, 0xfb, 0x42, 0x34, + 0xb4, 0xe5, 0x92, 0x9f, 0xc6, 0xb5, 0x51, 0xca, 0x33, 0x9f, 0x62, 0x0a, 0xd5, 0x90, 0xa4, 0x69, 0x2b, 0xc0, 0xc4, + 0xa2, 0x1b, 0x6a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0xb0, 0x0d, 0xb8, 0x95, 0x71, 0x82, 0xd5, 0x6f, 0x21, 0x86, + 0xbf, 0x5d, 0x31, 0x0b, 0x91, 0x64, 0x31, 0x55, 0x99, 0xf6, 0xbe, 0xed, 0xfd, 0xbd, 0xca, 0x06, 0x55, 0xba, 0x29, + 0x1b, 0x87, 0xa6, 0x95, 0xb0, 0x5f, 0x4d, 0x40, 0x83, 0x1d, 0xf0, 0x31, 0x55, 0x50, 0x1c, 0x99, 0xcf, 0x89, 0x97, + 0xa5, 0x3a, 0x17, 0xd7, 0x88, 0x78, 0xad, 0xe0, 0xa7, 0xf3, 0x64, 0xa4, 0xfe, 0x04, 0x5e, 0xeb, 0x3c, 0xac, 0x11, + 0x1b, 0x10, 0x67, 0x5b, 0x9a, 0xc1, 0x44, 0x7b, 0x2c, 0x83, 0x88, 0x7d, 0x05, 0xd2, 0x71, 0x37, 0x94, 0xe3, 0xd0, + 0xd8, 0x15, 0x50, 0xec, 0x8b, 0x48, 0xd8, 0x91, 0xec, 0x46, 0x40, 0xbb, 0x8e, 0xef, 0xd6, 0xf9, 0xa1, 0xe7, 0xd8, + 0xb9, 0x6a, 0x80, 0xb7, 0xd4, 0xa7, 0x43, 0x0f, 0x3d, 0xb6, 0xea, 0x42, 0xab, 0x75, 0xf8, 0x98, 0x76, 0x1d, 0xe7, + 0x95, 0xa3, 0x1a, 0xd4, 0x48, 0x4d, 0xc2, 0x6d, 0x5e, 0x74, 0x47, 0x92, 0x2f, 0x9e, 0x4a, 0xb9, 0xf3, 0xc3, 0xc6, + 0x73, 0xe2, 0xd8, 0x80, 0x84, 0xb3, 0x28, 0x7e, 0xc4, 0x14, 0xba, 0xaa, 0xa1, 0x7a, 0x41, 0x94, 0x12, 0x79, 0x0e, + 0x54, 0xec, 0xf0, 0x85, 0x93, 0xf8, 0xf9, 0xfd, 0xdb, 0x0f, 0x1f, 0x54, 0x03, 0x73, 0x6f, 0xa6, 0x72, 0xef, 0x6c, + 0x43, 0xed, 0xc1, 0xfe, 0x8d, 0xfb, 0x8e, 0xde, 0x30, 0x94, 0xaf, 0x2c, 0xef, 0x39, 0x5a, 0x56, 0xdb, 0x72, 0xec, + 0xe6, 0x61, 0x5f, 0xa6, 0xcc, 0xe0, 0x41, 0xf3, 0x6a, 0xc0, 0x0d, 0xbb, 0xaf, 0xb7, 0x52, 0xc9, 0xca, 0x0f, 0x6f, + 0x1b, 0x4a, 0xdd, 0x4d, 0x43, 0x29, 0x70, 0x53, 0x35, 0x5c, 0xb5, 0x8e, 0x56, 0xd2, 0xed, 0x0c, 0xa9, 0x93, 0xf7, + 0x81, 0x4b, 0x62, 0x69, 0xbe, 0x60, 0xd0, 0x2c, 0x76, 0x7a, 0x75, 0xd4, 0x0d, 0xc5, 0x8c, 0x0f, 0x11, 0xb0, 0xf5, + 0x02, 0x30, 0xb1, 0x23, 0xb2, 0x1e, 0xac, 0x4c, 0xb9, 0x09, 0x03, 0x59, 0xa9, 0x13, 0x4a, 0x61, 0xde, 0x66, 0x64, + 0x15, 0x93, 0xc4, 0xcd, 0xd6, 0x09, 0xb9, 0x0d, 0xa2, 0xfb, 0x27, 0x85, 0x01, 0xfb, 0x9e, 0xca, 0x4b, 0x7f, 0xb1, + 0x14, 0xb5, 0xcf, 0x35, 0x32, 0x12, 0x0b, 0xb8, 0xf3, 0x03, 0xf9, 0x7f, 0xfe, 0x6d, 0x59, 0xff, 0xf9, 0xf7, 0xde, + 0xaa, 0xd0, 0x7d, 0x3e, 0x31, 0xb2, 0xd1, 0x01, 0xfb, 0xa2, 0xf9, 0x4b, 0x65, 0x98, 0x37, 0xd7, 0xa9, 0x2d, 0x02, + 0xbc, 0xaf, 0x2d, 0x41, 0xad, 0xb0, 0xbc, 0x6f, 0x1e, 0x35, 0x30, 0x98, 0xd7, 0xde, 0x91, 0x41, 0xa5, 0x2f, 0x1a, + 0xda, 0x44, 0x1f, 0x1c, 0xb4, 0x22, 0xbf, 0x1f, 0xc2, 0xfb, 0xe6, 0xf0, 0x85, 0xc3, 0x67, 0xa2, 0xc1, 0xd7, 0x93, + 0x89, 0xc8, 0xe6, 0x26, 0x37, 0x05, 0xa3, 0xfa, 0xf3, 0x5a, 0x09, 0xbb, 0x3c, 0x07, 0xb6, 0x4e, 0xbd, 0xdd, 0x47, + 0xaf, 0x27, 0x68, 0xfe, 0x75, 0x36, 0x4d, 0x0a, 0x62, 0xa5, 0x15, 0xb5, 0x51, 0xf3, 0xed, 0x5a, 0xa7, 0x35, 0xbc, + 0x06, 0xa5, 0x98, 0xe2, 0x2b, 0x9f, 0xe8, 0xc6, 0xeb, 0x09, 0x93, 0xed, 0x30, 0x8b, 0xd3, 0x41, 0x75, 0x6b, 0x33, + 0xc9, 0x68, 0x09, 0xe8, 0x86, 0x42, 0x35, 0x2e, 0x58, 0x99, 0x14, 0xa2, 0x34, 0x14, 0xa9, 0x03, 0x53, 0x3f, 0xc9, + 0x31, 0xc3, 0xc8, 0xbb, 0x36, 0xab, 0xac, 0x9f, 0xf7, 0x5b, 0x65, 0x5d, 0x1d, 0x64, 0x95, 0xf5, 0xf3, 0x57, 0xb7, + 0xca, 0x7a, 0x27, 0x5b, 0x65, 0xc1, 0x22, 0xbe, 0x25, 0x07, 0x99, 0x4a, 0x71, 0x3b, 0x89, 0xe8, 0x3e, 0x1d, 0x39, + 0x8c, 0xa4, 0x4d, 0xbd, 0x25, 0x01, 0x36, 0x9d, 0xad, 0x4a, 0x10, 0x2d, 0xc0, 0x6c, 0xea, 0x8f, 0x37, 0x70, 0x0a, + 0xa2, 0x85, 0x6c, 0xde, 0x14, 0xb2, 0x18, 0xab, 0x45, 0xdc, 0x24, 0x6a, 0x52, 0x64, 0x1b, 0x3c, 0xca, 0x92, 0x79, + 0xac, 0x4b, 0x79, 0xa4, 0x85, 0xbd, 0x58, 0x87, 0x1b, 0x1d, 0x0d, 0xd0, 0x5e, 0x49, 0x34, 0xec, 0xbc, 0xe4, 0xd1, + 0x24, 0xe4, 0x1e, 0x84, 0x5d, 0x2e, 0x8d, 0xcc, 0xb0, 0x55, 0x7f, 0xdd, 0x38, 0xdf, 0x5f, 0x3b, 0xc3, 0xae, 0x03, + 0xee, 0xd0, 0xc0, 0xe4, 0x61, 0x81, 0x3d, 0xec, 0x76, 0xa1, 0xe0, 0x5e, 0x2a, 0xe8, 0x40, 0x81, 0x2f, 0x15, 0xf4, + 0xa0, 0xc0, 0x93, 0x0a, 0x4e, 0xa0, 0x60, 0x26, 0x15, 0xf4, 0xa1, 0xe0, 0x4e, 0xcd, 0xaf, 0x43, 0x31, 0xdc, 0xbe, + 0x7e, 0x63, 0x50, 0xa6, 0x82, 0x97, 0xf5, 0x0d, 0x07, 0xec, 0x94, 0xdc, 0xc5, 0x20, 0x32, 0xa8, 0x80, 0x6f, 0x90, + 0x18, 0xf7, 0x4b, 0x42, 0x43, 0x33, 0xbf, 0xc1, 0x3b, 0xc7, 0xca, 0x22, 0xb0, 0x54, 0xe6, 0x21, 0x0f, 0x38, 0x1c, + 0x14, 0x55, 0x07, 0x99, 0xcd, 0x50, 0xac, 0x1c, 0x0f, 0x1b, 0x21, 0xad, 0x65, 0xf1, 0x8e, 0x7e, 0xce, 0x14, 0x5b, + 0xa0, 0xb0, 0xf1, 0xd0, 0x64, 0xc1, 0xe0, 0xd7, 0xd0, 0xf4, 0xbf, 0x21, 0xd3, 0xf5, 0x42, 0xb9, 0x8c, 0x16, 0x7b, + 0x95, 0xf6, 0xf2, 0x2b, 0x18, 0xa5, 0x4a, 0x35, 0x20, 0x26, 0xdf, 0x96, 0xec, 0x5b, 0xf4, 0x31, 0x2f, 0xd7, 0xcf, + 0x60, 0x6c, 0x4a, 0x46, 0x4d, 0x46, 0xe0, 0x3b, 0x00, 0x23, 0x49, 0x6b, 0x7e, 0x09, 0x70, 0x96, 0x9e, 0xaf, 0x5c, + 0x69, 0x3c, 0xe3, 0x1f, 0x49, 0x9a, 0xba, 0x0b, 0x5e, 0xbf, 0x3e, 0x4e, 0x30, 0x93, 0x11, 0xfc, 0x17, 0x02, 0x10, + 0x84, 0x69, 0x7e, 0xcd, 0x1a, 0x22, 0x89, 0xee, 0x15, 0xb0, 0xb7, 0x81, 0x0d, 0x55, 0x58, 0x06, 0xf8, 0x16, 0x2c, + 0x61, 0x59, 0x87, 0x0f, 0x87, 0xff, 0x8e, 0x04, 0xd5, 0xc2, 0xcc, 0x5d, 0x54, 0x8b, 0xe8, 0x3e, 0xc8, 0xe5, 0xb1, + 0x09, 0x15, 0x7a, 0xa9, 0xf0, 0x4b, 0x74, 0xc2, 0x41, 0xb4, 0xf8, 0x43, 0x15, 0xc2, 0x3b, 0x14, 0xf9, 0x1f, 0x42, + 0xc3, 0xcf, 0x26, 0x16, 0xc2, 0x58, 0xb1, 0x00, 0x84, 0x83, 0x30, 0x5b, 0x9a, 0xe8, 0xcc, 0xa5, 0x75, 0x42, 0xdd, + 0xb0, 0x70, 0x6d, 0xb7, 0x55, 0x17, 0xd6, 0x41, 0xb2, 0x98, 0xba, 0x9a, 0xd3, 0xe9, 0x1b, 0xfc, 0xcf, 0xb2, 0x7b, + 0x7a, 0x8e, 0x3d, 0x28, 0x33, 0xff, 0x6e, 0x3b, 0x8f, 0xc2, 0xcc, 0x9c, 0xbb, 0x2b, 0x3f, 0x78, 0x18, 0xac, 0xa2, + 0x30, 0x4a, 0x63, 0xd7, 0x23, 0xc3, 0x82, 0xa1, 0x1e, 0x62, 0x70, 0x04, 0xe6, 0x9f, 0xe7, 0x58, 0x9d, 0x84, 0xac, + 0x68, 0x6b, 0x11, 0xfb, 0x60, 0x1e, 0x90, 0x4d, 0xce, 0x3e, 0x5f, 0xaa, 0x4c, 0xab, 0xe2, 0x96, 0xa3, 0x2d, 0x80, + 0x22, 0x65, 0x81, 0x15, 0x20, 0x9c, 0xd0, 0x30, 0x76, 0x67, 0x18, 0x0b, 0xd0, 0xea, 0xf4, 0x12, 0xb2, 0x52, 0xac, + 0x5e, 0x6b, 0xe7, 0x49, 0x74, 0x3f, 0x86, 0xd1, 0x62, 0x63, 0x33, 0x25, 0xc1, 0x1c, 0xdf, 0x98, 0xe8, 0xcb, 0xc1, + 0xfb, 0x31, 0x91, 0x11, 0x87, 0xde, 0xc8, 0x6a, 0x08, 0xaf, 0x07, 0x1d, 0xc5, 0x1e, 0xae, 0xfc, 0xd0, 0xa4, 0xd3, + 0xe9, 0xdb, 0xb1, 0xd4, 0x97, 0x0c, 0x3f, 0x7d, 0x8b, 0xd5, 0x1d, 0xc5, 0x1e, 0x02, 0xb3, 0x36, 0x0f, 0xa2, 0xfb, + 0xc1, 0xd2, 0x9f, 0xcd, 0x48, 0x38, 0xc4, 0x31, 0x8b, 0x42, 0x12, 0x04, 0x7e, 0x9c, 0xfa, 0xe9, 0x70, 0xe5, 0x6e, + 0x58, 0xaf, 0xc7, 0x6d, 0xbd, 0x76, 0x59, 0xaf, 0xdd, 0x83, 0x7b, 0x95, 0xba, 0x01, 0xbf, 0x11, 0xda, 0x0f, 0x1b, + 0x5a, 0x4f, 0xb1, 0x2b, 0xf3, 0x3c, 0xb8, 0xd7, 0x38, 0x21, 0xdb, 0x95, 0x9b, 0x2c, 0xfc, 0x70, 0x60, 0xe7, 0xd6, + 0xdd, 0x96, 0x6e, 0x8c, 0xa7, 0xa7, 0xa7, 0xa7, 0xb9, 0x35, 0xe3, 0x4f, 0xf6, 0x6c, 0x96, 0x5b, 0x1e, 0x7f, 0x9a, + 0xcf, 0x6d, 0x7b, 0x3e, 0xcf, 0x2d, 0x9f, 0x17, 0x74, 0x3b, 0xde, 0xac, 0xdb, 0xc9, 0xad, 0x7b, 0xa9, 0x46, 0x6e, + 0x11, 0xf6, 0x94, 0x90, 0xd9, 0x10, 0x37, 0x12, 0x35, 0xe4, 0x1c, 0xf4, 0x6d, 0x3b, 0x47, 0x0c, 0x70, 0x5d, 0xc2, + 0x4d, 0x28, 0xeb, 0xb9, 0xd9, 0x1e, 0x5c, 0x53, 0x29, 0x3e, 0xe7, 0x79, 0x8d, 0xf5, 0x66, 0x6e, 0xf2, 0xe9, 0x46, + 0x91, 0x66, 0xe1, 0xba, 0xb4, 0xda, 0x96, 0x83, 0xc1, 0xdc, 0x0c, 0x20, 0x48, 0xd6, 0x70, 0x1a, 0x25, 0x70, 0x66, + 0x13, 0x77, 0xe6, 0xaf, 0xd3, 0x81, 0xd3, 0x89, 0x37, 0xbc, 0x88, 0xed, 0xf5, 0xa2, 0x00, 0xcf, 0xde, 0x20, 0x8d, + 0x02, 0x7f, 0xc6, 0x8b, 0xda, 0xce, 0x92, 0xd3, 0xd1, 0x87, 0xe8, 0x22, 0xee, 0x63, 0xa0, 0x03, 0x37, 0x08, 0x14, + 0xab, 0x9b, 0x2a, 0xc4, 0x4d, 0x51, 0xc4, 0xab, 0xd8, 0x29, 0x85, 0x0b, 0xba, 0x83, 0x3b, 0xc7, 0xf1, 0x46, 0xec, + 0x79, 0xe7, 0x24, 0xde, 0xe4, 0xdf, 0xae, 0xc8, 0xcc, 0x77, 0x15, 0xad, 0xd8, 0x4d, 0x8e, 0x0d, 0x62, 0x60, 0x7d, + 0xdb, 0xb2, 0x4d, 0xf9, 0xb1, 0x80, 0x60, 0x82, 0x4f, 0xfc, 0x55, 0x1c, 0x25, 0x99, 0x1b, 0x66, 0x79, 0x3e, 0xb9, + 0xc9, 0xf3, 0xe1, 0x95, 0xaf, 0x5d, 0xff, 0x43, 0xa3, 0xf7, 0x34, 0x55, 0x9b, 0xe4, 0xfa, 0x8d, 0xf1, 0x96, 0xc8, + 0x56, 0x1a, 0x70, 0x8d, 0xa1, 0x85, 0x86, 0x5c, 0x99, 0xde, 0x92, 0xf5, 0xca, 0x14, 0xc8, 0xa2, 0x3a, 0xb5, 0xfa, + 0x28, 0x57, 0xc1, 0x1b, 0x08, 0x2a, 0xbc, 0x25, 0xa3, 0x2b, 0xc9, 0xe2, 0x03, 0x88, 0x15, 0xac, 0x4c, 0x2d, 0xf9, + 0x9f, 0xb5, 0xd1, 0x8c, 0xdf, 0xed, 0xa7, 0x19, 0x7f, 0xc9, 0x0e, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, 0xb3, + 0xba, 0x25, 0xff, 0x45, 0x34, 0x52, 0x85, 0x90, 0x1f, 0xae, 0xa6, 0x84, 0xc6, 0xc8, 0xb9, 0xf8, 0xdd, 0x86, 0xf7, + 0xbc, 0x37, 0x9a, 0xf5, 0x8d, 0xde, 0xdc, 0x20, 0x8f, 0x7d, 0x17, 0x8e, 0xfe, 0x9e, 0xc8, 0xcf, 0xf3, 0xf9, 0xe8, + 0x4d, 0x24, 0x15, 0x88, 0x27, 0x66, 0xff, 0x50, 0x8a, 0x67, 0x40, 0xdf, 0x70, 0xbb, 0x47, 0xcc, 0xf8, 0x00, 0xee, + 0xd0, 0xd4, 0xce, 0x77, 0x26, 0xec, 0xbd, 0x86, 0xe5, 0x21, 0x68, 0xc2, 0xc8, 0x92, 0x3b, 0xbd, 0xd4, 0x44, 0x89, + 0x0b, 0x92, 0x31, 0x2f, 0xd5, 0xef, 0x1f, 0x2e, 0x66, 0xda, 0x45, 0xa4, 0xe7, 0x7e, 0xfa, 0xae, 0xea, 0x72, 0xc2, + 0xd4, 0x2f, 0x23, 0x79, 0x3a, 0x39, 0xb3, 0xd9, 0x92, 0x53, 0x3a, 0xc3, 0x6b, 0xda, 0xfc, 0xbc, 0x34, 0xd3, 0x81, + 0xdc, 0x90, 0xa5, 0x96, 0xaa, 0x5d, 0xc6, 0xcc, 0xde, 0x7f, 0xcb, 0x28, 0x40, 0xcc, 0x96, 0x85, 0x9e, 0xba, 0x33, + 0xda, 0xdc, 0x9f, 0xe5, 0xb9, 0x3e, 0xe4, 0x80, 0x90, 0x2e, 0x5a, 0xb2, 0x8f, 0x88, 0x4b, 0xef, 0x85, 0x59, 0x01, + 0x53, 0xd2, 0x51, 0x0d, 0xdc, 0x05, 0xe8, 0xb4, 0x99, 0xbe, 0x8e, 0xc1, 0x4c, 0x55, 0x28, 0xf8, 0xa8, 0xad, 0x83, + 0x34, 0x21, 0x50, 0xc2, 0x0a, 0xf8, 0xf3, 0x57, 0xbc, 0xa0, 0x6e, 0x35, 0x49, 0x81, 0x83, 0x4a, 0x79, 0xf0, 0xab, + 0xe7, 0x72, 0x6d, 0x8a, 0x76, 0x58, 0x1d, 0x7c, 0xc8, 0x55, 0x41, 0xfb, 0xe1, 0xf6, 0x1b, 0x9f, 0x1d, 0x41, 0x83, + 0x71, 0x45, 0x77, 0xbf, 0xc7, 0x26, 0x10, 0x48, 0x89, 0xf4, 0xde, 0xb0, 0xd2, 0x7b, 0xe5, 0xc5, 0x96, 0xc7, 0xa4, + 0xc8, 0xdc, 0xd8, 0x04, 0x16, 0x1f, 0x71, 0x2f, 0xc3, 0x78, 0x52, 0xf8, 0x8b, 0xe1, 0x3a, 0x05, 0xdc, 0x88, 0x8c, + 0x2a, 0xe2, 0x9f, 0xa1, 0xb7, 0x4e, 0xd2, 0x28, 0x19, 0xc4, 0x91, 0x1f, 0x66, 0x24, 0xc9, 0x11, 0x54, 0xd7, 0x08, + 0x1f, 0x0e, 0x9e, 0x9b, 0x6d, 0x14, 0xbb, 0x9e, 0x9f, 0x3d, 0x0c, 0x6c, 0x46, 0x52, 0xd8, 0x43, 0x46, 0x1d, 0xd8, + 0x8d, 0xf5, 0x07, 0x0c, 0x9a, 0x2f, 0x91, 0xf0, 0x4b, 0xea, 0xe4, 0x8c, 0xbc, 0xcd, 0x87, 0xd2, 0x5b, 0x1a, 0x95, + 0x03, 0xc8, 0x0f, 0x37, 0x31, 0x17, 0x80, 0xe5, 0x61, 0xa9, 0xed, 0x19, 0x59, 0x18, 0x88, 0xb5, 0x41, 0x2e, 0xcf, + 0xff, 0xac, 0x9e, 0xae, 0xd8, 0xcd, 0xc5, 0x40, 0xf1, 0xe8, 0x87, 0x8c, 0x6c, 0xe0, 0x42, 0x0e, 0x2b, 0xe3, 0x90, + 0x9a, 0x53, 0x32, 0x8f, 0x12, 0x42, 0x23, 0xb8, 0x3a, 0xa7, 0xf1, 0xe6, 0xf0, 0xee, 0x77, 0x4f, 0xbf, 0xb9, 0x9f, + 0x30, 0xca, 0x34, 0xde, 0x99, 0xbe, 0xa7, 0xb7, 0xfa, 0x7d, 0x06, 0xa4, 0x21, 0x85, 0xbc, 0x47, 0x83, 0x65, 0x0d, + 0x54, 0x75, 0xd8, 0x18, 0x28, 0x2b, 0x8e, 0xd8, 0x9d, 0x97, 0x90, 0xc0, 0xcd, 0xfc, 0x3b, 0x4e, 0x33, 0x76, 0x4f, + 0xe2, 0x0d, 0x5f, 0x63, 0xbc, 0xf0, 0x1e, 0xb1, 0x48, 0x95, 0xa1, 0xf0, 0x45, 0xaa, 0x16, 0xe3, 0x22, 0x0d, 0x6b, + 0xb3, 0xe1, 0xb1, 0x23, 0x2a, 0x37, 0x7d, 0x2f, 0xde, 0xc8, 0x57, 0x74, 0xd1, 0x4c, 0xdc, 0xd4, 0xd5, 0xa0, 0x5f, + 0x2b, 0x7f, 0x36, 0x0b, 0x48, 0x5e, 0x5a, 0xe8, 0xf2, 0x5a, 0x4a, 0xc0, 0x11, 0x70, 0x70, 0xa7, 0x69, 0x14, 0xac, + 0x33, 0xd2, 0x0c, 0x2e, 0x0a, 0x9c, 0x8e, 0x5d, 0x00, 0x07, 0x7f, 0x97, 0xc7, 0xda, 0x03, 0x72, 0x1b, 0xb6, 0x89, + 0x3d, 0x84, 0x18, 0xbf, 0x66, 0xb7, 0x3c, 0x74, 0x78, 0x25, 0x06, 0x6d, 0x34, 0x4c, 0xc4, 0x80, 0x6b, 0x89, 0x62, + 0x6f, 0xc5, 0x72, 0x58, 0x99, 0x88, 0x73, 0x2a, 0x8a, 0xf2, 0xf2, 0x64, 0xfe, 0x98, 0x33, 0xf6, 0xaa, 0xf9, 0x8c, + 0xbd, 0xe2, 0x67, 0x6c, 0xf7, 0xce, 0x7c, 0x3a, 0x77, 0xe0, 0xbf, 0x61, 0x31, 0xa1, 0x81, 0xad, 0x74, 0xe3, 0x8d, + 0xe2, 0xc4, 0x1b, 0xc5, 0xec, 0xc4, 0x1b, 0x05, 0xbb, 0x46, 0x93, 0x0c, 0xc3, 0xea, 0xe8, 0x86, 0xad, 0x40, 0x21, + 0xfc, 0xd9, 0xa5, 0x57, 0xce, 0x31, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, 0xee, 0xa3, 0x4e, 0xcf, 0x12, 0x47, + 0xda, 0xba, 0x95, 0xb9, 0xd3, 0x29, 0x99, 0x0d, 0xe6, 0x91, 0xb7, 0x4e, 0xff, 0xc5, 0xc6, 0xcf, 0x80, 0xb8, 0x13, + 0x11, 0x54, 0xfa, 0xe1, 0x4d, 0x41, 0x51, 0x72, 0x47, 0x78, 0x0f, 0x5b, 0xb1, 0x4e, 0x03, 0x1a, 0x90, 0xb8, 0x63, + 0x1d, 0x37, 0x6c, 0xf2, 0x66, 0x40, 0xff, 0x61, 0xab, 0xd4, 0x8e, 0x62, 0xbe, 0x00, 0x2c, 0x3b, 0xc1, 0xf1, 0x78, + 0x68, 0xb0, 0xd5, 0xb4, 0x4f, 0x9b, 0x87, 0x7b, 0xcd, 0xbf, 0x74, 0xc3, 0x2f, 0x15, 0x76, 0x6f, 0x31, 0x57, 0x90, + 0xdd, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x3b, 0x2e, 0x84, 0xa2, 0xee, 0x81, 0x58, 0xfe, 0xe9, 0xab, 0x63, 0xf8, + 0x8f, 0x52, 0xf5, 0xbf, 0x64, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xf6, 0x9a, 0x92, 0x4a, 0x48, 0x88, 0x1f, 0x5e, 0x7f, + 0x3e, 0x7f, 0x5c, 0x83, 0x83, 0x6b, 0x53, 0x6b, 0xa6, 0x6a, 0xed, 0xef, 0xa3, 0x08, 0x92, 0x65, 0xd6, 0xab, 0x73, + 0xf0, 0x50, 0xf3, 0xf2, 0x6c, 0x04, 0x8d, 0x38, 0x1f, 0x41, 0xb5, 0xf8, 0x2a, 0xb6, 0xa1, 0xac, 0xc4, 0xdb, 0x36, + 0x56, 0xe2, 0xcd, 0x7e, 0x56, 0xe2, 0xaf, 0x07, 0xb1, 0x12, 0x6f, 0xbe, 0x3a, 0x2b, 0xf1, 0xb6, 0xce, 0x4a, 0x5c, + 0x45, 0xdc, 0x84, 0xd5, 0xb8, 0x58, 0xb3, 0x9f, 0x1f, 0xa9, 0x52, 0xee, 0x32, 0x1a, 0xf5, 0x6c, 0x1a, 0x64, 0xf8, + 0xea, 0x77, 0x33, 0x16, 0xb8, 0x11, 0xdf, 0xa3, 0x45, 0x57, 0xc1, 0x5a, 0x30, 0xcc, 0x8e, 0xdf, 0x91, 0x8a, 0x83, + 0x28, 0x5c, 0xfc, 0x0c, 0x4a, 0x59, 0x10, 0x07, 0x26, 0xd2, 0x0b, 0x3f, 0xfd, 0x39, 0x8a, 0xd7, 0xf1, 0x05, 0xf4, + 0xf5, 0xd1, 0x4f, 0xfd, 0x69, 0x40, 0x84, 0xef, 0x2f, 0xb5, 0x40, 0x63, 0x32, 0x71, 0x30, 0xfa, 0xe4, 0x3f, 0xdd, + 0x0d, 0xff, 0x89, 0x66, 0xa1, 0xec, 0x37, 0x35, 0x6d, 0x53, 0x9b, 0x19, 0x11, 0xae, 0x04, 0x94, 0x06, 0xfd, 0x78, + 0x66, 0xe4, 0x2a, 0xd2, 0x1b, 0x66, 0xc9, 0xed, 0x1d, 0x5a, 0xfb, 0x21, 0x35, 0xa6, 0x66, 0xad, 0x1b, 0x22, 0xe8, + 0x55, 0x5d, 0x0c, 0xbf, 0x8a, 0xd6, 0x29, 0x99, 0x45, 0xf7, 0xa1, 0x6a, 0x84, 0xc2, 0xac, 0x1f, 0x34, 0x9c, 0xa2, + 0x0d, 0xa6, 0x6b, 0xfc, 0x80, 0x84, 0x72, 0x94, 0x68, 0x2a, 0x64, 0x0b, 0x5d, 0xc7, 0x26, 0x55, 0x35, 0x9b, 0x38, + 0x45, 0x55, 0xe4, 0x15, 0x7a, 0xa2, 0x69, 0xd1, 0xe8, 0x71, 0x2d, 0xb9, 0xa9, 0x46, 0x64, 0x31, 0xa9, 0x70, 0xaa, + 0x85, 0x5c, 0xb8, 0xc8, 0x23, 0x4f, 0x34, 0x2c, 0x1c, 0x7b, 0x43, 0x9d, 0x45, 0x8b, 0xb7, 0x10, 0xb7, 0x23, 0x5f, + 0xb3, 0xf5, 0x60, 0x71, 0x18, 0xe8, 0xe3, 0x6b, 0x09, 0x8c, 0xef, 0xee, 0x48, 0x12, 0xb8, 0x0f, 0x9a, 0x9e, 0x47, + 0xe1, 0x8f, 0x00, 0x80, 0x37, 0xd1, 0x7d, 0x28, 0x57, 0xc0, 0xf4, 0x28, 0x0d, 0x7b, 0xa9, 0x31, 0x62, 0x08, 0xb8, + 0x8a, 0x48, 0x23, 0x80, 0xc4, 0xb4, 0x0b, 0xf2, 0x77, 0x83, 0xfe, 0xfb, 0x0f, 0x3d, 0x37, 0x2e, 0x23, 0xf1, 0xa1, + 0xbf, 0xc5, 0x07, 0x7c, 0xe6, 0xf9, 0xf3, 0x27, 0xed, 0xd3, 0x2e, 0x27, 0x44, 0x6f, 0x68, 0xad, 0xb7, 0x9e, 0x02, + 0x18, 0xc5, 0x55, 0xb4, 0xf6, 0x96, 0x68, 0x6b, 0xfa, 0xf5, 0xe6, 0x9b, 0x41, 0x9f, 0x98, 0x17, 0x54, 0x4c, 0xbd, + 0x52, 0x54, 0x40, 0x01, 0xbf, 0xff, 0x16, 0x42, 0x5e, 0xfe, 0x0f, 0xc1, 0x50, 0xdf, 0x35, 0x8c, 0x8b, 0xf7, 0x1f, + 0xb7, 0x79, 0x87, 0x90, 0xbe, 0x92, 0x05, 0x93, 0xe0, 0xca, 0xb5, 0x66, 0x24, 0x93, 0x57, 0x81, 0x26, 0x07, 0x6e, + 0x6b, 0x8b, 0x49, 0xc7, 0xbf, 0x42, 0x2c, 0xca, 0xa6, 0x33, 0x5b, 0x7f, 0x83, 0x30, 0x6c, 0x55, 0x41, 0x32, 0xcc, + 0xe4, 0x81, 0x20, 0xfa, 0xaa, 0xbe, 0x5b, 0xf9, 0xa1, 0x81, 0x71, 0xd7, 0xeb, 0x6f, 0xdc, 0x0d, 0x44, 0x1e, 0x06, + 0xe4, 0x56, 0x7d, 0x05, 0x85, 0x86, 0xec, 0xa9, 0x06, 0xc9, 0x95, 0xd4, 0x46, 0x48, 0x70, 0x2d, 0xde, 0xe4, 0x4f, + 0x8a, 0xa2, 0x28, 0x82, 0x8d, 0x50, 0x04, 0x1f, 0x81, 0xe5, 0xc8, 0x0e, 0x80, 0xb6, 0x24, 0x8f, 0x37, 0xb4, 0x04, + 0x38, 0x03, 0xd4, 0xc9, 0xf2, 0x02, 0x16, 0x5c, 0xaf, 0x67, 0xf3, 0x02, 0xce, 0xd0, 0x43, 0x60, 0x34, 0x37, 0x81, + 0x18, 0xbc, 0x03, 0x05, 0x19, 0x76, 0x7c, 0xcb, 0x24, 0xc1, 0x8a, 0x4d, 0x1f, 0x27, 0x43, 0xd2, 0x1c, 0x85, 0x2d, + 0x94, 0xb0, 0x20, 0x68, 0x1d, 0x2a, 0x41, 0x95, 0x0d, 0xd2, 0x80, 0x1b, 0x91, 0x2f, 0xda, 0x64, 0x2b, 0x12, 0xae, + 0x55, 0xcc, 0xc2, 0x84, 0x51, 0xf1, 0xa0, 0xce, 0x1b, 0x4a, 0x6c, 0x01, 0xb6, 0x69, 0x6e, 0xb9, 0xa4, 0x77, 0x61, + 0xca, 0x50, 0xaa, 0x6b, 0x78, 0x4c, 0xb1, 0x99, 0x32, 0xdc, 0x56, 0xbd, 0x21, 0xd8, 0x92, 0x46, 0x55, 0xd7, 0x29, + 0x6a, 0x8c, 0x0c, 0x7d, 0xd0, 0x78, 0x14, 0x4c, 0x5c, 0xc4, 0xc1, 0xae, 0xb9, 0xd5, 0x45, 0x13, 0x1a, 0x19, 0xb7, + 0x22, 0x28, 0x4a, 0xf4, 0x7a, 0x37, 0x6c, 0x9c, 0x10, 0x0a, 0xa8, 0xb5, 0x1f, 0xaf, 0xd6, 0x4f, 0xcb, 0xa4, 0x3f, + 0x91, 0x07, 0x7a, 0x91, 0x50, 0x50, 0x7d, 0x22, 0x0f, 0x60, 0xfb, 0xf7, 0x16, 0xa4, 0x29, 0xea, 0x0e, 0x74, 0x6d, + 0x40, 0x70, 0x7d, 0x0f, 0xc2, 0x43, 0xed, 0x38, 0x40, 0x76, 0xbe, 0x03, 0x8b, 0x23, 0x88, 0x21, 0x8f, 0x32, 0x3f, + 0xc4, 0xcc, 0xca, 0x5e, 0x6b, 0x84, 0xb1, 0xd9, 0x70, 0x34, 0xf4, 0x17, 0x8e, 0x6d, 0x1f, 0xd5, 0xea, 0x83, 0x20, + 0xbb, 0xa9, 0xb6, 0x6e, 0x64, 0x23, 0xc7, 0x36, 0xfd, 0x17, 0x56, 0x67, 0x58, 0xbb, 0xa3, 0xa5, 0xe8, 0x8d, 0x13, + 0x14, 0x7f, 0x8d, 0x9f, 0x6d, 0xb5, 0xda, 0x81, 0xd4, 0xab, 0x56, 0xeb, 0x38, 0xb6, 0x9c, 0xc9, 0xbf, 0x26, 0xf5, + 0xab, 0x9f, 0xc6, 0x8e, 0xa4, 0x99, 0x44, 0x26, 0x10, 0x7f, 0x58, 0x83, 0x63, 0xf4, 0x67, 0xe5, 0xa5, 0xa2, 0xd1, + 0xe3, 0xa3, 0xeb, 0x13, 0x91, 0xa0, 0x9a, 0xbb, 0x75, 0xc9, 0x1d, 0x54, 0xbe, 0x98, 0x56, 0x31, 0x1c, 0x8b, 0x74, + 0x4a, 0x0a, 0x8d, 0xde, 0x4e, 0x6a, 0x01, 0xfb, 0x6f, 0xb9, 0x3e, 0xad, 0x29, 0x44, 0x02, 0x80, 0x1a, 0x10, 0xad, + 0x7c, 0x6f, 0x87, 0xeb, 0xb8, 0xdc, 0x5d, 0xf9, 0x92, 0x3c, 0xbc, 0x33, 0xbc, 0x74, 0x50, 0x87, 0x26, 0xfa, 0x6b, + 0xbe, 0xee, 0x1e, 0xd9, 0x25, 0x09, 0x67, 0xe5, 0x0e, 0x2b, 0xf7, 0xd7, 0xe1, 0xdd, 0x95, 0x30, 0x0a, 0x84, 0xf1, + 0x8f, 0x1a, 0x30, 0x4a, 0x1e, 0x85, 0xb8, 0xf9, 0xe9, 0x71, 0xf3, 0x0f, 0xa2, 0x62, 0xb0, 0x01, 0x8d, 0xc1, 0x25, + 0x9a, 0x49, 0x42, 0x71, 0x88, 0x15, 0x8d, 0x8e, 0xb8, 0x1a, 0x27, 0x44, 0x5b, 0x77, 0x62, 0xc6, 0x6d, 0x0a, 0x8b, + 0x36, 0x3e, 0x8b, 0xfe, 0x78, 0xa8, 0xd4, 0xda, 0xdf, 0x2f, 0xb5, 0xce, 0xf6, 0x49, 0xad, 0xa9, 0x47, 0xd3, 0x7d, + 0xe2, 0xc6, 0x92, 0x53, 0x1c, 0x27, 0xce, 0x65, 0xdf, 0xb8, 0x92, 0xa8, 0x1b, 0x1d, 0xa0, 0x78, 0xab, 0x5a, 0x6f, + 0xd4, 0x4a, 0x10, 0xc5, 0xdf, 0x12, 0x83, 0xc2, 0x15, 0xea, 0xb2, 0x6c, 0xfc, 0xaa, 0x90, 0x8d, 0x53, 0xae, 0xa6, + 0xf0, 0x65, 0xe1, 0xd4, 0xbf, 0xe4, 0x27, 0x26, 0xb8, 0x83, 0xc2, 0x5f, 0xac, 0x18, 0xa9, 0xe4, 0x01, 0x55, 0x30, + 0x1a, 0x92, 0x5f, 0x1d, 0xe7, 0x32, 0xca, 0xee, 0x75, 0xe5, 0xaa, 0x85, 0x03, 0x54, 0x51, 0x0e, 0x52, 0x77, 0x1c, + 0xb2, 0x28, 0x96, 0xb7, 0x4d, 0xd9, 0x03, 0x46, 0x7e, 0x2d, 0x6d, 0x12, 0xe1, 0xaa, 0x42, 0x01, 0xcc, 0xc5, 0xf4, + 0x15, 0xbd, 0xb6, 0xb0, 0x81, 0xc0, 0x41, 0x36, 0x78, 0xd6, 0xed, 0x97, 0xce, 0xd3, 0x0c, 0x05, 0x85, 0x16, 0x5e, + 0x96, 0x41, 0x20, 0x7c, 0x6f, 0xb6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xec, 0x7e, 0x07, 0xf1, 0xa2, 0x62, 0xcb, 0x8a, + 0x7c, 0x3c, 0x99, 0x26, 0x35, 0xcf, 0xc5, 0xaa, 0xf5, 0x4e, 0xa9, 0x10, 0x67, 0xcb, 0x9c, 0x53, 0xca, 0x32, 0x7a, + 0x56, 0x63, 0xc0, 0xbf, 0xcb, 0xb6, 0x4e, 0xb2, 0x0e, 0x31, 0x9a, 0xbc, 0x99, 0x25, 0xae, 0xf7, 0x49, 0x1a, 0x32, + 0x97, 0x73, 0x82, 0x0c, 0xb8, 0xac, 0x29, 0x18, 0xba, 0x18, 0x7c, 0x91, 0x0c, 0xac, 0x4e, 0x2a, 0x49, 0x5f, 0x06, + 0x4f, 0xed, 0xae, 0xfb, 0x6a, 0x7e, 0x5c, 0x11, 0x8a, 0x76, 0x7a, 0x65, 0x91, 0x79, 0xcb, 0x38, 0xb2, 0xe5, 0x7a, + 0x35, 0xdd, 0xca, 0xb2, 0x55, 0x49, 0xe4, 0x5a, 0x17, 0xb3, 0xca, 0x9f, 0x9d, 0xcf, 0xe7, 0x65, 0x41, 0xa3, 0xad, + 0x1c, 0xa3, 0xb0, 0xf0, 0xa9, 0x6d, 0xdb, 0xd5, 0xb1, 0xef, 0x06, 0xbb, 0x89, 0x72, 0xdb, 0xd3, 0xc6, 0x11, 0x23, + 0x6c, 0xf7, 0xc1, 0xaf, 0x0e, 0x8e, 0xdc, 0x2a, 0x4e, 0x76, 0xc9, 0x2c, 0x62, 0x48, 0x8d, 0x21, 0xfc, 0x8c, 0xac, + 0xd2, 0x81, 0x47, 0x50, 0x07, 0x63, 0x49, 0x07, 0x1a, 0x0d, 0x07, 0xcc, 0x05, 0x98, 0x8a, 0x38, 0x7c, 0x57, 0xd8, + 0x0a, 0xca, 0xc3, 0x6b, 0xc2, 0x7b, 0xfe, 0x11, 0x3c, 0x28, 0xdb, 0xba, 0x4c, 0x1b, 0xa7, 0xd5, 0xb3, 0xff, 0x5c, + 0xaa, 0xa7, 0xc0, 0x05, 0xb8, 0xe5, 0x0a, 0x6d, 0x2a, 0x9f, 0xc5, 0xff, 0x17, 0xf2, 0xff, 0x57, 0xf1, 0xa6, 0x6c, + 0x3f, 0x72, 0x0a, 0x12, 0xed, 0xe2, 0xb4, 0xd0, 0x51, 0x37, 0xed, 0x01, 0x61, 0x65, 0x30, 0x97, 0x15, 0xe8, 0xa0, + 0xa4, 0x2f, 0xa5, 0xdc, 0x68, 0x10, 0xbf, 0x23, 0xc5, 0x0c, 0x4b, 0x5c, 0x88, 0x10, 0x8b, 0x84, 0x71, 0x30, 0x07, + 0xe3, 0xe5, 0x29, 0xea, 0x0f, 0x4a, 0x7b, 0x02, 0xb4, 0xf1, 0xb5, 0xb9, 0x1d, 0x24, 0xee, 0xaf, 0xea, 0xb5, 0x78, + 0xc7, 0x00, 0x32, 0x07, 0x0e, 0x21, 0x1a, 0x12, 0x28, 0x95, 0xcd, 0x4d, 0x47, 0x29, 0xde, 0xca, 0x7a, 0x36, 0x3e, + 0x30, 0xec, 0xae, 0xb9, 0x0a, 0xed, 0x9b, 0x6b, 0x0b, 0x60, 0xb2, 0x6c, 0xfb, 0xe1, 0xb3, 0x09, 0x4b, 0x2c, 0xef, + 0x47, 0x07, 0x97, 0x1c, 0xf7, 0xaf, 0x89, 0x77, 0x67, 0x4a, 0xcf, 0x3f, 0xca, 0x17, 0xff, 0xda, 0x28, 0xd0, 0xbb, + 0x2a, 0x49, 0xe8, 0x98, 0xb5, 0x78, 0x47, 0x3f, 0xa8, 0xf6, 0xca, 0x0f, 0x0f, 0xaf, 0xeb, 0x6e, 0x0e, 0xae, 0x0b, + 0x17, 0xc6, 0xc1, 0x95, 0xe1, 0xc6, 0xa1, 0x96, 0x0b, 0xd9, 0xe8, 0xaf, 0x92, 0x40, 0x51, 0x76, 0xfc, 0x55, 0xb1, + 0x15, 0xa5, 0xf2, 0xaf, 0xd6, 0x40, 0x7c, 0x1e, 0x94, 0x52, 0x41, 0xe1, 0x59, 0xd1, 0xd4, 0xbe, 0x72, 0xaa, 0xf4, + 0xbb, 0xca, 0x89, 0xad, 0x52, 0x2e, 0x6c, 0xa4, 0xf6, 0x3a, 0x85, 0x43, 0xdf, 0xb1, 0xad, 0x8e, 0xcf, 0x16, 0xfc, + 0x92, 0x98, 0xfb, 0x41, 0x40, 0x51, 0x45, 0x9a, 0x25, 0xd1, 0x27, 0x52, 0x56, 0xb3, 0xd0, 0x32, 0x66, 0x04, 0xd2, + 0xe1, 0x8f, 0x70, 0x76, 0x3c, 0x37, 0x1e, 0xe0, 0xd9, 0x90, 0x0b, 0xc1, 0x80, 0x93, 0x96, 0xe2, 0x27, 0xe0, 0x0e, + 0x9e, 0xaa, 0xe3, 0x33, 0x08, 0x1a, 0xa8, 0xcc, 0x46, 0xea, 0x8f, 0x9d, 0xbe, 0xe2, 0xf4, 0xee, 0xcc, 0xae, 0x67, + 0x9b, 0x8e, 0x75, 0xac, 0xd8, 0xd6, 0x89, 0xd9, 0xb1, 0xfa, 0x4a, 0xc7, 0xea, 0xc1, 0xbf, 0x9e, 0x63, 0xbd, 0x52, + 0x6c, 0x78, 0x52, 0x1c, 0xab, 0x8b, 0xff, 0x76, 0xac, 0xfe, 0x5d, 0x97, 0xde, 0xf4, 0xae, 0x70, 0xab, 0xaa, 0x8c, + 0x02, 0x9c, 0x40, 0xd4, 0xa3, 0xf1, 0xd9, 0x3a, 0x25, 0xca, 0x66, 0xa4, 0xbe, 0x52, 0x95, 0x65, 0x42, 0xe6, 0x23, + 0xf5, 0xa9, 0x2b, 0x95, 0x3a, 0xa7, 0x8d, 0xc5, 0x9d, 0x7e, 0x63, 0x71, 0xf7, 0xa4, 0xb1, 0xf8, 0xb8, 0x57, 0x2e, + 0x3e, 0x5a, 0xd0, 0x57, 0x52, 0xce, 0xbe, 0x95, 0x9b, 0x25, 0xfe, 0x46, 0x73, 0x14, 0x40, 0xd7, 0x26, 0xfc, 0xd3, + 0xef, 0xe8, 0xa2, 0xd5, 0x14, 0x5a, 0x09, 0x68, 0xf4, 0x4f, 0x15, 0xe7, 0xe4, 0x2f, 0x9d, 0x13, 0x0f, 0xea, 0x41, + 0x86, 0x49, 0xf8, 0xbb, 0xeb, 0x9e, 0x7a, 0xb6, 0x02, 0x0d, 0x1d, 0xf8, 0x6f, 0xd9, 0xeb, 0x78, 0xf4, 0xc1, 0x86, + 0xf7, 0x1f, 0x9d, 0x7e, 0x6a, 0x9b, 0x0e, 0xfc, 0xf7, 0x9b, 0x50, 0xb9, 0x83, 0xc2, 0x5f, 0xee, 0xf7, 0xd8, 0x56, + 0xba, 0xa7, 0xcb, 0x8e, 0xf5, 0xea, 0xae, 0x6f, 0x9d, 0x2e, 0x9d, 0xfe, 0x47, 0xfa, 0x14, 0x98, 0x1d, 0xeb, 0x15, + 0xfc, 0x7d, 0xec, 0xda, 0x4b, 0xd3, 0xb1, 0x4e, 0xef, 0xba, 0x56, 0x37, 0x30, 0x4f, 0xac, 0x53, 0xf8, 0xfb, 0x0d, + 0xc0, 0x0b, 0x70, 0x65, 0x29, 0x41, 0x15, 0xd8, 0x18, 0x15, 0xfb, 0x0d, 0xf9, 0x23, 0x9d, 0x63, 0xa5, 0x77, 0xfc, + 0x97, 0xd3, 0x3b, 0xf3, 0x78, 0xe9, 0x74, 0xee, 0xcc, 0xd6, 0x9f, 0x1f, 0x01, 0xf2, 0xbb, 0x17, 0x0e, 0xc0, 0x88, + 0x39, 0x40, 0xfe, 0x34, 0x31, 0x2e, 0xdb, 0xc4, 0xe8, 0xef, 0xf7, 0x8b, 0xd1, 0x7f, 0x58, 0x1f, 0x22, 0x46, 0x7f, + 0xff, 0xd5, 0xc5, 0xe8, 0x97, 0x55, 0x2b, 0xee, 0xf7, 0xd5, 0x58, 0xe5, 0xbf, 0x6c, 0xab, 0x44, 0xb2, 0xef, 0x6a, + 0xd7, 0x57, 0xeb, 0x1b, 0x88, 0xb6, 0xf3, 0x3e, 0x1a, 0xfd, 0xb0, 0x2e, 0x99, 0x28, 0x45, 0x80, 0x01, 0xde, 0x47, + 0x14, 0x03, 0xfc, 0xb6, 0x1e, 0x81, 0x5d, 0x04, 0xbb, 0x35, 0xfd, 0x99, 0xb9, 0x74, 0x83, 0xb9, 0xb8, 0x71, 0xa1, + 0x64, 0x88, 0xc5, 0x60, 0x33, 0x0f, 0x97, 0x09, 0x28, 0x6b, 0xd6, 0xab, 0x30, 0x1d, 0x9c, 0xd8, 0x80, 0xe6, 0x3b, + 0xf3, 0x24, 0xaf, 0x34, 0xb6, 0x78, 0x7c, 0xa2, 0x5b, 0x66, 0xd3, 0xdf, 0xfa, 0x1e, 0x4d, 0xd6, 0x9a, 0x7b, 0x77, + 0xea, 0xfd, 0x2a, 0x60, 0x0b, 0xc2, 0x4d, 0xfa, 0x80, 0xd8, 0x68, 0x7a, 0x5f, 0x36, 0x1c, 0xab, 0x98, 0x0a, 0xb6, + 0x8f, 0x14, 0x46, 0x52, 0x6d, 0xef, 0x94, 0x0d, 0xcf, 0xf6, 0x4d, 0xb3, 0xe1, 0xf3, 0xa5, 0xe6, 0x3b, 0xac, 0xde, + 0x44, 0xc7, 0x55, 0x50, 0x55, 0x32, 0x6d, 0x35, 0x02, 0xa4, 0xa0, 0x3d, 0x0b, 0xd3, 0xb8, 0x82, 0xf0, 0xb1, 0x15, + 0xbc, 0x8d, 0x6d, 0xe9, 0x5d, 0xa9, 0x4f, 0xd9, 0x9c, 0xee, 0xc5, 0x16, 0xe9, 0x41, 0xff, 0x37, 0x20, 0x6c, 0xd8, + 0x7d, 0x3c, 0x8d, 0x64, 0x38, 0x6f, 0xa5, 0x7e, 0x29, 0xa9, 0x9d, 0x2f, 0x9d, 0x6d, 0x9d, 0xb4, 0x69, 0x35, 0xa4, + 0x75, 0xc8, 0x8a, 0xdf, 0xd1, 0xf8, 0x79, 0x6a, 0xb6, 0x9a, 0x53, 0xd3, 0x62, 0xb4, 0xcc, 0xdd, 0xd5, 0x19, 0xaf, + 0xf7, 0x14, 0x36, 0xb1, 0xc1, 0x1e, 0x64, 0xc7, 0xf1, 0xed, 0x1c, 0xb2, 0x22, 0x0f, 0x90, 0x88, 0x90, 0x28, 0xa8, + 0x0e, 0xda, 0xd8, 0x0e, 0x77, 0x98, 0x7f, 0xc8, 0x1d, 0xb3, 0x4e, 0xd0, 0x56, 0x77, 0x97, 0xc5, 0x88, 0x70, 0x6d, + 0xd8, 0x96, 0x14, 0xa8, 0x4e, 0xaf, 0x6f, 0x38, 0x27, 0x86, 0xd5, 0xef, 0xe9, 0x39, 0x3f, 0x70, 0x72, 0x97, 0x25, + 0x80, 0x80, 0xc9, 0xae, 0x18, 0xa6, 0x1f, 0xfa, 0x99, 0xef, 0x06, 0x39, 0xa0, 0xfa, 0x32, 0xcd, 0xfb, 0xcf, 0x75, + 0x9a, 0xc1, 0x1c, 0x39, 0x49, 0x86, 0xe6, 0xca, 0xe6, 0x94, 0x64, 0xf7, 0x84, 0x84, 0x2d, 0xaa, 0xdc, 0xaa, 0xf5, + 0xf3, 0x1f, 0x67, 0x0b, 0x9a, 0x53, 0x3b, 0x8b, 0x69, 0x16, 0xb2, 0xfd, 0xc1, 0x4d, 0x75, 0xf3, 0x89, 0xf1, 0x53, + 0x1b, 0xc2, 0xfd, 0xe7, 0x7e, 0x84, 0x9b, 0x91, 0x43, 0x10, 0xee, 0x3f, 0xbf, 0x3a, 0xc2, 0xfd, 0x49, 0x46, 0xb8, + 0x25, 0x4f, 0x95, 0x42, 0x26, 0xfa, 0x01, 0x9f, 0x35, 0x08, 0xf2, 0xfb, 0x52, 0x3d, 0xa2, 0xe4, 0xa5, 0x2a, 0x25, + 0x5f, 0xfd, 0x58, 0xca, 0x26, 0x83, 0x2c, 0x3b, 0x06, 0x25, 0xa5, 0x99, 0x2b, 0x20, 0x31, 0xa9, 0x48, 0xb1, 0x0d, + 0x7d, 0x5e, 0x84, 0x59, 0x60, 0xbd, 0x67, 0x6c, 0x09, 0xa8, 0x20, 0x7e, 0x88, 0x92, 0x95, 0x8b, 0x01, 0xd9, 0x54, + 0xcc, 0x42, 0x07, 0x0f, 0x36, 0x78, 0x47, 0x79, 0x51, 0x38, 0x13, 0x72, 0x74, 0x32, 0xba, 0xa6, 0xf4, 0xa0, 0xfa, + 0x40, 0xdc, 0x44, 0x35, 0xe8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xfb, 0x45, 0xe7, 0xf8, 0xc5, 0x89, 0x0d, 0xff, 0x73, + 0x48, 0x37, 0x37, 0x58, 0xc5, 0x55, 0x14, 0x42, 0x22, 0x0c, 0x5e, 0xb3, 0xad, 0xda, 0x3d, 0x21, 0x9f, 0x8a, 0x5a, + 0xfd, 0xe6, 0x4a, 0x33, 0xf7, 0xa1, 0xa8, 0xd3, 0x58, 0x63, 0x19, 0xad, 0xa5, 0x61, 0x35, 0x8c, 0xc6, 0x0f, 0xd7, + 0x20, 0x19, 0x92, 0x6a, 0xc8, 0xaf, 0xd9, 0x74, 0x8b, 0x79, 0x91, 0x6e, 0x7e, 0x53, 0x64, 0xdb, 0xe1, 0x59, 0x3f, + 0xf6, 0x42, 0x90, 0x09, 0xd5, 0x6d, 0x8c, 0xd5, 0x8d, 0xf9, 0x66, 0x14, 0xc8, 0x75, 0x57, 0xa4, 0x54, 0xc7, 0x05, + 0xca, 0x92, 0x75, 0xe8, 0xd1, 0xac, 0xe9, 0xee, 0x34, 0xd5, 0xfc, 0x23, 0x88, 0xd6, 0x89, 0x1f, 0xd6, 0x71, 0xd5, + 0xdc, 0xb1, 0x5d, 0xa4, 0x26, 0x48, 0xf9, 0xaa, 0xb8, 0x2f, 0x32, 0x23, 0xa1, 0x09, 0x4d, 0x71, 0x69, 0xcd, 0x91, + 0xfb, 0x42, 0x34, 0x7c, 0x91, 0x19, 0x90, 0x54, 0x14, 0x96, 0xfb, 0xf9, 0x73, 0x5a, 0x0b, 0xd2, 0xfc, 0xd1, 0x69, + 0x9d, 0x7b, 0x22, 0x35, 0x98, 0xaa, 0xb8, 0x8b, 0x48, 0xc5, 0xd4, 0x60, 0x03, 0xcf, 0x88, 0x5e, 0xbe, 0x1c, 0x8f, + 0x1c, 0x9d, 0x25, 0xa9, 0x2c, 0x65, 0x54, 0xba, 0x3c, 0x4c, 0x35, 0xae, 0x37, 0x3a, 0x6d, 0xc5, 0x7e, 0xb8, 0xe0, + 0x9a, 0x69, 0x81, 0xbd, 0x20, 0xc3, 0x01, 0x55, 0x81, 0xb9, 0x5c, 0x45, 0xcd, 0xeb, 0xdc, 0x91, 0x04, 0x12, 0x6c, + 0x8e, 0xd4, 0xae, 0x65, 0x5b, 0xb6, 0x2a, 0x1a, 0xce, 0xfd, 0xc5, 0x68, 0x1b, 0x65, 0x2e, 0xe4, 0x8a, 0x09, 0xa2, + 0x05, 0x78, 0x7e, 0x64, 0x7e, 0x16, 0x40, 0xe2, 0x11, 0x70, 0x01, 0x59, 0x51, 0xae, 0x31, 0x67, 0xf6, 0xb8, 0x6e, + 0xf2, 0x09, 0x93, 0xcf, 0x71, 0xa7, 0x2f, 0x0c, 0x49, 0xf3, 0x23, 0x5c, 0x86, 0x9a, 0xaa, 0x41, 0xea, 0x43, 0x92, + 0xa4, 0xa6, 0x6c, 0xdf, 0x3e, 0x50, 0xa0, 0x0d, 0xa4, 0x25, 0xc7, 0x0e, 0xe6, 0x89, 0xbb, 0x82, 0x18, 0xdd, 0xdb, + 0xdc, 0x60, 0x98, 0x56, 0x65, 0xa8, 0x56, 0x71, 0x5e, 0x9d, 0x18, 0x4a, 0xc7, 0x31, 0x14, 0x1b, 0xd0, 0xad, 0x9a, + 0x1b, 0xdb, 0xfc, 0x66, 0xb8, 0x4f, 0x45, 0x47, 0xf1, 0xcb, 0x53, 0x3a, 0x0f, 0xaa, 0x9c, 0x63, 0xc2, 0xcf, 0x8c, + 0x06, 0x14, 0xd4, 0xa4, 0xe8, 0xd9, 0x3e, 0x15, 0xd3, 0x5f, 0x91, 0x4d, 0xa6, 0x63, 0x62, 0x0e, 0x56, 0xc5, 0xd7, + 0xb7, 0xe8, 0x9a, 0xe6, 0x87, 0x8a, 0xff, 0xf9, 0xb3, 0xe6, 0x83, 0xf9, 0xfd, 0x48, 0x82, 0x0f, 0x3c, 0xeb, 0x25, + 0x80, 0xf9, 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0xcc, 0x7f, 0x30, 0xc5, 0x9e, 0x15, 0xb8, + 0xe1, 0x02, 0x50, 0x9a, 0x1b, 0x2e, 0x6a, 0x06, 0x04, 0xd4, 0xbb, 0xae, 0x52, 0x5a, 0x74, 0x55, 0x28, 0xf7, 0xd3, + 0xef, 0x1f, 0xae, 0x68, 0xe2, 0x21, 0x48, 0x72, 0xed, 0xce, 0xd0, 0x15, 0xac, 0xd0, 0x3d, 0xbc, 0x1c, 0x7d, 0x73, + 0xb6, 0x22, 0x99, 0x4b, 0x05, 0x97, 0xc0, 0xe2, 0x01, 0x39, 0xa0, 0x78, 0x3c, 0x69, 0x28, 0x65, 0xf0, 0x66, 0xe4, + 0xce, 0xf7, 0x18, 0x9f, 0x66, 0x28, 0xec, 0x9e, 0x32, 0xd1, 0x46, 0x69, 0xe4, 0x18, 0xd4, 0x44, 0xd6, 0x73, 0x31, + 0xec, 0xe0, 0x28, 0x8c, 0xd4, 0xf1, 0x37, 0xc2, 0x9b, 0xa8, 0x6d, 0x11, 0x20, 0xfb, 0xdf, 0x75, 0x42, 0x82, 0x7f, + 0x8d, 0xbe, 0x81, 0x8b, 0xfb, 0x9b, 0x1b, 0x55, 0x1f, 0x66, 0x16, 0xf2, 0x31, 0xdf, 0x34, 0x64, 0xc1, 0x43, 0x1e, + 0x95, 0x31, 0x9b, 0x5d, 0x89, 0xd9, 0x84, 0xdf, 0xfb, 0x59, 0xd7, 0xf1, 0x19, 0x5e, 0x68, 0x63, 0xe0, 0x2e, 0xb6, + 0x25, 0x9e, 0xd3, 0x19, 0x22, 0x83, 0x3a, 0x0d, 0x5c, 0xef, 0x13, 0xe7, 0x50, 0xe5, 0x87, 0x43, 0x78, 0x51, 0x41, + 0xd9, 0x35, 0xee, 0x65, 0xdc, 0xca, 0x5b, 0xfc, 0x32, 0x7e, 0xea, 0x7e, 0xe9, 0x67, 0x82, 0x19, 0xc6, 0x87, 0x1c, + 0xb4, 0x39, 0x38, 0xbe, 0x82, 0xfd, 0x01, 0x06, 0xd5, 0x39, 0xfd, 0x4b, 0xef, 0xce, 0xb1, 0x97, 0x1d, 0xc7, 0x02, + 0x36, 0x67, 0xd9, 0xb5, 0xfa, 0x81, 0xd9, 0xb5, 0xfa, 0xf0, 0xf7, 0x11, 0x58, 0x2f, 0xb3, 0x63, 0x1d, 0x7f, 0x74, + 0x3a, 0x81, 0x79, 0x6a, 0xf5, 0xe1, 0xef, 0x92, 0xb6, 0xfa, 0x05, 0x99, 0x1e, 0x60, 0x78, 0xbe, 0x29, 0x61, 0x01, + 0xe9, 0xb7, 0xd0, 0x22, 0x18, 0xa5, 0xeb, 0xad, 0x41, 0x13, 0x01, 0x28, 0x43, 0x35, 0x78, 0x94, 0xc0, 0x70, 0xa8, + 0x41, 0x5a, 0x6e, 0x0c, 0x28, 0xcf, 0x0d, 0x32, 0xc2, 0x22, 0xc5, 0x7c, 0xfb, 0x31, 0x62, 0x6d, 0x9a, 0x03, 0x70, + 0xf3, 0x4c, 0x45, 0x54, 0x75, 0xf1, 0xb7, 0x18, 0x03, 0xeb, 0xf0, 0x90, 0xe1, 0x12, 0x56, 0x2a, 0xb2, 0xe5, 0xe5, + 0xfb, 0x07, 0x8e, 0x7e, 0xa3, 0x44, 0x64, 0x6b, 0xf9, 0xaa, 0x7d, 0x33, 0x75, 0x86, 0xe8, 0xfd, 0xf7, 0xf6, 0x83, + 0x49, 0x4a, 0x69, 0x3f, 0x3c, 0xba, 0xe7, 0xcc, 0x4f, 0xc4, 0xf0, 0x24, 0x14, 0xed, 0x34, 0x47, 0x2e, 0xd7, 0x21, + 0xad, 0xc5, 0x05, 0x50, 0xc9, 0x77, 0x6e, 0x20, 0x99, 0x5e, 0x48, 0x2d, 0x9f, 0x08, 0xcc, 0xff, 0xfc, 0x79, 0x31, + 0x38, 0xb3, 0x32, 0xee, 0x33, 0xa7, 0x07, 0xd7, 0x6e, 0x8f, 0x74, 0x77, 0x5a, 0x01, 0xed, 0x0f, 0x0f, 0x5b, 0xc4, + 0x93, 0xe4, 0x9a, 0x7e, 0xae, 0x63, 0x6c, 0x35, 0x45, 0xaa, 0x69, 0x18, 0x21, 0xb0, 0x6e, 0x85, 0xd5, 0x51, 0xf5, + 0x61, 0xc8, 0x15, 0x66, 0xe1, 0x8e, 0x90, 0xb8, 0x8c, 0x17, 0x53, 0x01, 0x34, 0x3b, 0xe6, 0xb1, 0xc7, 0xa5, 0xf1, + 0x7f, 0x3d, 0x09, 0x74, 0x2f, 0x02, 0x0d, 0x5f, 0xe5, 0xb4, 0x96, 0xdc, 0x4d, 0xc4, 0xbd, 0x4a, 0x2f, 0x54, 0x92, + 0x9e, 0xab, 0x50, 0x04, 0xf9, 0x8e, 0x30, 0xc5, 0x99, 0x30, 0x6f, 0x12, 0xb7, 0x45, 0x51, 0x60, 0xf8, 0x10, 0x13, + 0x5a, 0xe3, 0xae, 0x4e, 0xfa, 0xf3, 0xe7, 0xad, 0x97, 0x10, 0x55, 0x27, 0xcb, 0x99, 0x1e, 0x55, 0x19, 0xbf, 0xa9, + 0x32, 0x8a, 0x11, 0xfd, 0x22, 0xd6, 0xe0, 0x56, 0x59, 0x74, 0xef, 0xe1, 0xcf, 0x29, 0x71, 0x33, 0x8b, 0xe9, 0x41, + 0x34, 0xe9, 0x72, 0x37, 0x1c, 0xd2, 0x05, 0x7b, 0x2c, 0x16, 0x7f, 0x8b, 0x05, 0x9b, 0x7b, 0xb6, 0xfd, 0xb8, 0x66, + 0x7e, 0xc8, 0xd0, 0xc7, 0x67, 0xbb, 0x08, 0x9e, 0xf2, 0x2e, 0x73, 0x69, 0x84, 0x0d, 0xf9, 0xca, 0x8d, 0x32, 0x97, + 0xe7, 0x15, 0x01, 0xba, 0x7c, 0xd8, 0xa8, 0x30, 0x94, 0x7c, 0x95, 0xc7, 0xef, 0xae, 0xbe, 0x53, 0xd8, 0xfe, 0xa7, + 0xfa, 0x2d, 0x64, 0x64, 0x68, 0x14, 0xfc, 0x11, 0x8d, 0x82, 0xaf, 0xb0, 0xb4, 0x12, 0x10, 0x4b, 0x3e, 0x3f, 0xa2, + 0x10, 0x54, 0x15, 0x12, 0x7a, 0x54, 0xeb, 0xb7, 0x5a, 0x07, 0x99, 0x1f, 0xbb, 0x49, 0x76, 0x04, 0x4d, 0x4d, 0x40, + 0x72, 0x6a, 0x9b, 0x07, 0x33, 0x55, 0x1c, 0x72, 0xa1, 0x5a, 0x16, 0x72, 0xcd, 0xe1, 0xdc, 0x0f, 0x84, 0xe2, 0x90, + 0x7f, 0xc0, 0xf5, 0x3c, 0x12, 0x67, 0x23, 0xd5, 0x8d, 0x21, 0x1b, 0x02, 0xc6, 0x37, 0x3e, 0x8a, 0xbc, 0x8c, 0x64, + 0x66, 0x9a, 0x25, 0xc4, 0x5d, 0xa9, 0x22, 0xd6, 0x67, 0xbd, 0xbf, 0x74, 0x3d, 0x5d, 0xf9, 0x99, 0x08, 0x96, 0x47, + 0x27, 0x08, 0x2a, 0x3c, 0x18, 0xe2, 0x78, 0x92, 0x33, 0x10, 0x5e, 0x46, 0x8b, 0xca, 0x8e, 0x2a, 0x28, 0x97, 0x73, + 0x0c, 0xc5, 0xca, 0x22, 0xe0, 0xcf, 0xd0, 0x23, 0xe7, 0x96, 0x79, 0x5d, 0x8b, 0x98, 0x7e, 0xea, 0xf8, 0x8c, 0xb1, + 0xb7, 0x0a, 0x06, 0x0a, 0x50, 0x7b, 0x36, 0x04, 0x9b, 0x6d, 0xf3, 0xc7, 0x3e, 0x62, 0x95, 0xe1, 0x6a, 0xa2, 0x3d, + 0x63, 0xdc, 0x6f, 0x3a, 0x96, 0x2b, 0x20, 0x84, 0x4a, 0x2a, 0xde, 0xa5, 0x33, 0x16, 0x0e, 0x40, 0x38, 0x2a, 0xa4, + 0x95, 0x3e, 0x7f, 0x7e, 0x3d, 0xf9, 0xcf, 0xbf, 0x21, 0x38, 0xf9, 0xd2, 0xe1, 0x5e, 0xd0, 0xd7, 0x72, 0x2d, 0x46, + 0x7d, 0x1a, 0x13, 0x54, 0xef, 0x93, 0x19, 0x0f, 0x0b, 0xc2, 0xb7, 0x56, 0x3e, 0xb9, 0xe1, 0xa1, 0x9e, 0x20, 0x01, + 0x81, 0xce, 0x7d, 0xb5, 0x27, 0xb0, 0xbc, 0x13, 0x1e, 0x22, 0x40, 0xf9, 0x75, 0xf3, 0x7d, 0x1f, 0xb2, 0xf4, 0xd6, + 0xf2, 0x02, 0x48, 0x03, 0xc4, 0x3d, 0x34, 0x3e, 0x73, 0x99, 0xf0, 0x15, 0xc8, 0x8f, 0x74, 0x70, 0x04, 0xd3, 0x5c, + 0x46, 0x2b, 0x62, 0xf9, 0xd1, 0xd1, 0x3d, 0x99, 0x9a, 0x6e, 0xec, 0x53, 0xf9, 0x32, 0xca, 0xdd, 0x14, 0x4a, 0xf9, + 0x09, 0x05, 0x2d, 0xa5, 0xaf, 0xf3, 0x02, 0x94, 0x51, 0x01, 0x28, 0xf8, 0xe9, 0x8e, 0xcb, 0x01, 0xfc, 0x2c, 0x1e, + 0x31, 0xbe, 0x8c, 0xe5, 0xcf, 0x69, 0x1c, 0x3e, 0x1e, 0x72, 0xaf, 0x78, 0x30, 0xa3, 0xf9, 0x5c, 0x0e, 0xba, 0x67, + 0x95, 0xbf, 0x2f, 0xa0, 0x52, 0xec, 0xd9, 0x28, 0xa6, 0x5f, 0xaa, 0x7f, 0x42, 0xfc, 0x84, 0x6c, 0xb9, 0x2c, 0x3e, + 0x23, 0x9c, 0xe7, 0x5a, 0xf0, 0x3e, 0x01, 0x92, 0xa7, 0xb4, 0x12, 0x43, 0x14, 0xd5, 0xc8, 0xd0, 0x2d, 0xa4, 0xc9, + 0x93, 0xd1, 0x88, 0xe2, 0xb1, 0x2a, 0x3a, 0x03, 0x28, 0x35, 0x44, 0xcf, 0x87, 0xc9, 0x66, 0xd0, 0xd0, 0xa4, 0x1e, + 0x5c, 0xd8, 0xa8, 0x3a, 0x9d, 0xfa, 0x18, 0x8f, 0x5c, 0xbe, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5b, 0x58, 0x40, + 0xe0, 0xbc, 0x9f, 0x0a, 0x1e, 0x57, 0xbe, 0xa5, 0x28, 0xdb, 0x0c, 0xdc, 0x87, 0x48, 0xd2, 0xac, 0x33, 0x27, 0xfb, + 0x4b, 0x2c, 0xbd, 0xe2, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0x22, 0x90, 0xd7, 0x4f, 0x93, 0x1c, 0x32, 0x7c, 0xdf, 0x61, + 0x92, 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xec, 0x08, 0xe6, 0x07, + 0x81, 0x01, 0x4a, 0x94, 0x91, 0xaf, 0x43, 0xf4, 0x01, 0x37, 0xa5, 0xd6, 0x01, 0x17, 0x33, 0x4e, 0xd4, 0x21, 0xe7, + 0x28, 0xa2, 0x83, 0x96, 0xaa, 0xd4, 0x89, 0x15, 0xbb, 0x99, 0xca, 0xdb, 0x1f, 0xb1, 0xff, 0xb7, 0x35, 0x86, 0xeb, + 0xcf, 0x87, 0x19, 0xe1, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x4a, 0xb0, 0xee, 0xa8, 0x50, 0xec, + 0xe3, 0x5d, 0xb5, 0x0a, 0xd2, 0x48, 0x54, 0x8b, 0x5d, 0x4d, 0x7d, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, + 0x65, 0x36, 0x82, 0xaa, 0x5c, 0xd8, 0xee, 0xc6, 0x31, 0xad, 0xac, 0x0f, 0xcf, 0x8e, 0x28, 0xdf, 0x39, 0xa6, 0x3b, + 0x6c, 0x7c, 0x06, 0xd6, 0x85, 0x74, 0xd1, 0xdd, 0x38, 0x66, 0x4b, 0x4a, 0x7f, 0xd1, 0x37, 0x47, 0xcb, 0x6c, 0x15, + 0x8c, 0xff, 0x0f, 0x00, 0xa3, 0x9b, 0x76, 0x11, 0x5a, 0x03, 0x00}; } // namespace web_server } // namespace esphome From fcdf36e991342e29213f07c4f09fd639c83d7e54 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 21 May 2024 11:07:20 +1200 Subject: [PATCH 1790/2607] Bump version to 2024.5.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 9d2b8b78ea..48b8aa8656 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.1" +__version__ = "2024.5.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 76abf2200cb297e1b89abaf44d8997f047848d95 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 21 May 2024 20:08:53 -0500 Subject: [PATCH 1791/2607] Uncouple safe_mode from OTA (#6759) --- CODEOWNERS | 2 +- esphome/components/esphome/ota/__init__.py | 30 ++--- .../components/esphome/ota/ota_esphome.cpp | 98 +------------- esphome/components/esphome/ota/ota_esphome.h | 27 +--- esphome/components/ota/__init__.py | 4 +- esphome/components/safe_mode/__init__.py | 53 +++++++- .../components/safe_mode/button/__init__.py | 13 +- .../safe_mode/button/safe_mode_button.cpp | 6 +- .../safe_mode/button/safe_mode_button.h | 6 +- esphome/components/safe_mode/safe_mode.cpp | 125 ++++++++++++++++++ esphome/components/safe_mode/safe_mode.h | 44 ++++++ .../components/safe_mode/switch/__init__.py | 13 +- .../safe_mode/switch/safe_mode_switch.cpp | 9 +- .../safe_mode/switch/safe_mode_switch.h | 6 +- esphome/cpp_helpers.py | 17 +-- tests/components/ota/common.yaml | 3 - tests/components/safe_mode/common.yaml | 6 +- tests/test1.yaml | 7 +- tests/test2.yaml | 4 +- tests/test3.yaml | 6 +- tests/test4.yaml | 3 +- 21 files changed, 282 insertions(+), 200 deletions(-) create mode 100644 esphome/components/safe_mode/safe_mode.cpp create mode 100644 esphome/components/safe_mode/safe_mode.h diff --git a/CODEOWNERS b/CODEOWNERS index dc6c8caa87..22e581275b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -306,7 +306,7 @@ esphome/components/rp2040_pwm/* @jesserockz esphome/components/rpi_dpi_rgb/* @clydebarrow esphome/components/rtl87xx/* @kuba2k2 esphome/components/rtttl/* @glmnet -esphome/components/safe_mode/* @jsuanet @paulmonigatti +esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti esphome/components/scd4x/* @martgras @sjtrny esphome/components/script/* @esphome/core esphome/components/sdm_meter/* @jesserockz @polyfaces diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index abe9323b53..c5903974c2 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,19 +1,16 @@ -from esphome.cpp_generator import RawExpression import esphome.codegen as cg import esphome.config_validation as cv from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent from esphome.const import ( CONF_ID, CONF_NUM_ATTEMPTS, - CONF_OTA, CONF_PASSWORD, CONF_PORT, CONF_REBOOT_TIMEOUT, CONF_SAFE_MODE, CONF_VERSION, - KEY_PAST_SAFE_MODE, ) -from esphome.core import CORE, coroutine_with_priority +from esphome.core import coroutine_with_priority CODEOWNERS = ["@esphome/core"] @@ -28,7 +25,6 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(ESPHomeOTAComponent), - cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean, cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), cv.SplitDefault( CONF_PORT, @@ -39,10 +35,15 @@ CONFIG_SCHEMA = ( rtl87xx=8892, ): cv.port, cv.Optional(CONF_PASSWORD): cv.string, - cv.Optional( - CONF_REBOOT_TIMEOUT, default="5min" - ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, + cv.Optional(CONF_NUM_ATTEMPTS): cv.invalid( + f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode" + ), + cv.Optional(CONF_REBOOT_TIMEOUT): cv.invalid( + f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode" + ), + cv.Optional(CONF_SAFE_MODE): cv.invalid( + f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode" + ), } ) .extend(BASE_OTA_SCHEMA) @@ -50,10 +51,8 @@ CONFIG_SCHEMA = ( ) -@coroutine_with_priority(50.0) +@coroutine_with_priority(52.0) async def to_code(config): - CORE.data[CONF_OTA] = {} - var = cg.new_Pvariable(config[CONF_ID]) await ota_to_code(var, config) cg.add(var.set_port(config[CONF_PORT])) @@ -63,10 +62,3 @@ async def to_code(config): cg.add_define("USE_OTA_VERSION", config[CONF_VERSION]) await cg.register_component(var, config) - - if config[CONF_SAFE_MODE]: - condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] - ) - cg.add(RawExpression(f"if ({condition}) return")) - CORE.data[CONF_OTA][KEY_PAST_SAFE_MODE] = True diff --git a/esphome/components/esphome/ota/ota_esphome.cpp b/esphome/components/esphome/ota/ota_esphome.cpp index f2f1cfc6a8..9d5044aaeb 100644 --- a/esphome/components/esphome/ota/ota_esphome.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -78,23 +78,9 @@ void ESPHomeOTAComponent::dump_config() { ESP_LOGCONFIG(TAG, " Password configured"); } #endif - if (this->has_safe_mode_ && this->safe_mode_rtc_value_ > 1 && - this->safe_mode_rtc_value_ != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGW(TAG, "Last reset occurred too quickly; safe mode will be invoked in %" PRIu32 " restarts", - this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_); - } } -void ESPHomeOTAComponent::loop() { - this->handle_(); - - if (this->has_safe_mode_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) { - this->has_safe_mode_ = false; - // successful boot, reset counter - ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter"); - this->clean_rtc(); - } -} +void ESPHomeOTAComponent::loop() { this->handle_(); } static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; @@ -423,86 +409,4 @@ bool ESPHomeOTAComponent::writeall_(const uint8_t *buf, size_t len) { float ESPHomeOTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } uint16_t ESPHomeOTAComponent::get_port() const { return this->port_; } void ESPHomeOTAComponent::set_port(uint16_t port) { this->port_ = port; } - -void ESPHomeOTAComponent::set_safe_mode_pending(const bool &pending) { - if (!this->has_safe_mode_) - return; - - uint32_t current_rtc = this->read_rtc_(); - - if (pending && current_rtc != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGI(TAG, "Device will enter safe mode on next boot"); - this->write_rtc_(ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC); - } - - if (!pending && current_rtc == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) { - ESP_LOGI(TAG, "Safe mode pending has been cleared"); - this->clean_rtc(); - } -} -bool ESPHomeOTAComponent::get_safe_mode_pending() { - return this->has_safe_mode_ && this->read_rtc_() == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC; -} - -bool ESPHomeOTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { - this->has_safe_mode_ = true; - this->safe_mode_start_time_ = millis(); - this->safe_mode_enable_time_ = enable_time; - this->safe_mode_num_attempts_ = num_attempts; - this->rtc_ = global_preferences->make_preference(233825507UL, false); - this->safe_mode_rtc_value_ = this->read_rtc_(); - - bool is_manual_safe_mode = this->safe_mode_rtc_value_ == ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC; - - if (is_manual_safe_mode) { - ESP_LOGI(TAG, "Safe mode has been entered manually"); - } else { - ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts", this->safe_mode_rtc_value_); - } - - if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) { - this->clean_rtc(); - - if (!is_manual_safe_mode) { - ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode"); - } - - this->status_set_error(); - this->set_timeout(enable_time, []() { - ESP_LOGE(TAG, "No OTA attempt made, restarting"); - App.reboot(); - }); - - // Delay here to allow power to stabilise before Wi-Fi/Ethernet is initialised. - delay(300); // NOLINT - App.setup(); - - ESP_LOGI(TAG, "Waiting for OTA attempt"); - - return true; - } else { - // increment counter - this->write_rtc_(this->safe_mode_rtc_value_ + 1); - return false; - } -} - -void ESPHomeOTAComponent::write_rtc_(uint32_t val) { - this->rtc_.save(&val); - global_preferences->sync(); -} - -uint32_t ESPHomeOTAComponent::read_rtc_() { - uint32_t val; - if (!this->rtc_.load(&val)) - return 0; - return val; -} - -void ESPHomeOTAComponent::clean_rtc() { this->write_rtc_(0); } - -void ESPHomeOTAComponent::on_safe_shutdown() { - if (this->has_safe_mode_ && this->read_rtc_() != ESPHomeOTAComponent::ENTER_SAFE_MODE_MAGIC) - this->clean_rtc(); -} } // namespace esphome diff --git a/esphome/components/esphome/ota/ota_esphome.h b/esphome/components/esphome/ota/ota_esphome.h index e8f36f05ca..42629b4346 100644 --- a/esphome/components/esphome/ota/ota_esphome.h +++ b/esphome/components/esphome/ota/ota_esphome.h @@ -15,17 +15,9 @@ class ESPHomeOTAComponent : public ota::OTAComponent { void set_auth_password(const std::string &password) { password_ = password; } #endif // USE_OTA_PASSWORD - /// Manually set the port OTA should listen on. + /// Manually set the port OTA should listen on void set_port(uint16_t port); - bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time); - - /// Set to true if the next startup will enter safe mode - void set_safe_mode_pending(const bool &pending); - bool get_safe_mode_pending(); - - // ========== INTERNAL METHODS ========== - // (In most use cases you won't need these) void setup() override; void dump_config() override; float get_setup_priority() const override; @@ -33,14 +25,7 @@ class ESPHomeOTAComponent : public ota::OTAComponent { uint16_t get_port() const; - void clean_rtc(); - - void on_safe_shutdown() override; - protected: - void write_rtc_(uint32_t val); - uint32_t read_rtc_(); - void handle_(); bool readall_(uint8_t *buf, size_t len); bool writeall_(const uint8_t *buf, size_t len); @@ -53,16 +38,6 @@ class ESPHomeOTAComponent : public ota::OTAComponent { std::unique_ptr server_; std::unique_ptr client_; - - bool has_safe_mode_{false}; ///< stores whether safe mode can be enabled - uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled - uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should be on for - uint32_t safe_mode_rtc_value_; - uint8_t safe_mode_num_attempts_; - ESPPreferenceObject rtc_; - - static const uint32_t ENTER_SAFE_MODE_MAGIC = - 0x5afe5afe; ///< a magic number to indicate that safe mode should be entered on next boot }; } // namespace esphome diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 3d2956931c..4e447bfb2d 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -6,7 +6,7 @@ from esphome.core import CORE, coroutine_with_priority from esphome.const import CONF_ESPHOME, CONF_OTA, CONF_PLATFORM, CONF_TRIGGER_ID CODEOWNERS = ["@esphome/core"] -AUTO_LOAD = ["md5"] +AUTO_LOAD = ["md5", "safe_mode"] IS_PLATFORM_COMPONENT = True @@ -76,7 +76,7 @@ BASE_OTA_SCHEMA = cv.Schema( ) -@coroutine_with_priority(51.0) +@coroutine_with_priority(54.0) async def to_code(config): cg.add_define("USE_OTA") diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index ab884bfee4..7f227d7dd1 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -1,5 +1,56 @@ +from esphome.cpp_generator import RawExpression import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import ( + CONF_DISABLED, + CONF_ID, + CONF_NUM_ATTEMPTS, + CONF_REBOOT_TIMEOUT, + CONF_SAFE_MODE, + KEY_PAST_SAFE_MODE, +) +from esphome.core import CORE, coroutine_with_priority -CODEOWNERS = ["@paulmonigatti", "@jsuanet"] + +CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] safe_mode_ns = cg.esphome_ns.namespace("safe_mode") +SafeModeComponent = safe_mode_ns.class_("SafeModeComponent", cg.Component) + + +def _remove_id_if_disabled(value): + value = value.copy() + if value[CONF_DISABLED]: + value.pop(CONF_ID) + return value + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(SafeModeComponent), + cv.Optional(CONF_DISABLED, default=False): cv.boolean, + cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, + cv.Optional( + CONF_REBOOT_TIMEOUT, default="5min" + ): cv.positive_time_period_milliseconds, + } + ).extend(cv.COMPONENT_SCHEMA), + _remove_id_if_disabled, +) + + +@coroutine_with_priority(50.0) +async def to_code(config): + if config[CONF_DISABLED]: + return + + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + condition = var.should_enter_safe_mode( + config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] + ) + cg.add(RawExpression(f"if ({condition}) return")) + CORE.data[CONF_SAFE_MODE] = {} + CORE.data[CONF_SAFE_MODE][KEY_PAST_SAFE_MODE] = True diff --git a/esphome/components/safe_mode/button/__init__.py b/esphome/components/safe_mode/button/__init__.py index bd51d2e038..5662db8f7e 100644 --- a/esphome/components/safe_mode/button/__init__.py +++ b/esphome/components/safe_mode/button/__init__.py @@ -1,16 +1,15 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import button -from esphome.components.esphome.ota import ESPHomeOTAComponent from esphome.const import ( - CONF_ESPHOME, + CONF_SAFE_MODE, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_CONFIG, ICON_RESTART_ALERT, ) -from .. import safe_mode_ns +from .. import safe_mode_ns, SafeModeComponent -DEPENDENCIES = ["ota.esphome"] +DEPENDENCIES = ["safe_mode"] SafeModeButton = safe_mode_ns.class_("SafeModeButton", button.Button, cg.Component) @@ -21,7 +20,7 @@ CONFIG_SCHEMA = ( entity_category=ENTITY_CATEGORY_CONFIG, icon=ICON_RESTART_ALERT, ) - .extend({cv.GenerateID(CONF_ESPHOME): cv.use_id(ESPHomeOTAComponent)}) + .extend({cv.GenerateID(CONF_SAFE_MODE): cv.use_id(SafeModeComponent)}) .extend(cv.COMPONENT_SCHEMA) ) @@ -30,5 +29,5 @@ async def to_code(config): var = await button.new_button(config) await cg.register_component(var, config) - ota = await cg.get_variable(config[CONF_ESPHOME]) - cg.add(var.set_ota(ota)) + safe_mode_component = await cg.get_variable(config[CONF_SAFE_MODE]) + cg.add(var.set_safe_mode(safe_mode_component)) diff --git a/esphome/components/safe_mode/button/safe_mode_button.cpp b/esphome/components/safe_mode/button/safe_mode_button.cpp index d513b79c12..261688807a 100644 --- a/esphome/components/safe_mode/button/safe_mode_button.cpp +++ b/esphome/components/safe_mode/button/safe_mode_button.cpp @@ -8,11 +8,13 @@ namespace safe_mode { static const char *const TAG = "safe_mode.button"; -void SafeModeButton::set_ota(esphome::ESPHomeOTAComponent *ota) { this->ota_ = ota; } +void SafeModeButton::set_safe_mode(SafeModeComponent *safe_mode_component) { + this->safe_mode_component_ = safe_mode_component; +} void SafeModeButton::press_action() { ESP_LOGI(TAG, "Restarting device in safe mode..."); - this->ota_->set_safe_mode_pending(true); + this->safe_mode_component_->set_safe_mode_pending(true); // Let MQTT settle a bit delay(100); // NOLINT diff --git a/esphome/components/safe_mode/button/safe_mode_button.h b/esphome/components/safe_mode/button/safe_mode_button.h index a306735b7f..fea0955abb 100644 --- a/esphome/components/safe_mode/button/safe_mode_button.h +++ b/esphome/components/safe_mode/button/safe_mode_button.h @@ -1,7 +1,7 @@ #pragma once #include "esphome/components/button/button.h" -#include "esphome/components/esphome/ota/ota_esphome.h" +#include "esphome/components/safe_mode/safe_mode.h" #include "esphome/core/component.h" namespace esphome { @@ -10,10 +10,10 @@ namespace safe_mode { class SafeModeButton : public button::Button, public Component { public: void dump_config() override; - void set_ota(esphome::ESPHomeOTAComponent *ota); + void set_safe_mode(SafeModeComponent *safe_mode_component); protected: - esphome::ESPHomeOTAComponent *ota_; + SafeModeComponent *safe_mode_component_; void press_action() override; }; diff --git a/esphome/components/safe_mode/safe_mode.cpp b/esphome/components/safe_mode/safe_mode.cpp new file mode 100644 index 0000000000..06772ae1e0 --- /dev/null +++ b/esphome/components/safe_mode/safe_mode.cpp @@ -0,0 +1,125 @@ +#include "safe_mode.h" + +#include "esphome/core/application.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "esphome/core/util.h" + +#include +#include +#include + +namespace esphome { +namespace safe_mode { + +static const char *const TAG = "safe_mode"; + +void SafeModeComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Safe Mode:"); + ESP_LOGCONFIG(TAG, " Invoke after %u boot attempts", this->safe_mode_num_attempts_); + ESP_LOGCONFIG(TAG, " Remain in safe mode for %" PRIu32 " seconds", + this->safe_mode_enable_time_ / 1000); // because milliseconds + + if (this->safe_mode_rtc_value_ > 1 && this->safe_mode_rtc_value_ != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) { + auto remaining_restarts = this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_; + if (remaining_restarts) { + ESP_LOGW(TAG, "Last reset occurred too quickly; safe mode will be invoked in %" PRIu32 " restarts", + remaining_restarts); + } else { + ESP_LOGW(TAG, "SAFE MODE IS ACTIVE"); + } + } +} + +float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } + +void SafeModeComponent::loop() { + if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) { + // successful boot, reset counter + ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter"); + this->clean_rtc(); + this->boot_successful_ = true; + } +} + +void SafeModeComponent::set_safe_mode_pending(const bool &pending) { + uint32_t current_rtc = this->read_rtc_(); + + if (pending && current_rtc != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) { + ESP_LOGI(TAG, "Device will enter safe mode on next boot"); + this->write_rtc_(SafeModeComponent::ENTER_SAFE_MODE_MAGIC); + } + + if (!pending && current_rtc == SafeModeComponent::ENTER_SAFE_MODE_MAGIC) { + ESP_LOGI(TAG, "Safe mode pending has been cleared"); + this->clean_rtc(); + } +} + +bool SafeModeComponent::get_safe_mode_pending() { + return this->read_rtc_() == SafeModeComponent::ENTER_SAFE_MODE_MAGIC; +} + +bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { + this->safe_mode_start_time_ = millis(); + this->safe_mode_enable_time_ = enable_time; + this->safe_mode_num_attempts_ = num_attempts; + this->rtc_ = global_preferences->make_preference(233825507UL, false); + this->safe_mode_rtc_value_ = this->read_rtc_(); + + bool is_manual_safe_mode = this->safe_mode_rtc_value_ == SafeModeComponent::ENTER_SAFE_MODE_MAGIC; + + if (is_manual_safe_mode) { + ESP_LOGI(TAG, "Safe mode invoked manually"); + } else { + ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts", this->safe_mode_rtc_value_); + } + + if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) { + this->clean_rtc(); + + if (!is_manual_safe_mode) { + ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode"); + } + + this->status_set_error(); + this->set_timeout(enable_time, []() { + ESP_LOGW(TAG, "Safe mode enable time has elapsed -- restarting"); + App.reboot(); + }); + + // Delay here to allow power to stabilize before Wi-Fi/Ethernet is initialised + delay(300); // NOLINT + App.setup(); + + ESP_LOGW(TAG, "SAFE MODE IS ACTIVE"); + + return true; + } else { + // increment counter + this->write_rtc_(this->safe_mode_rtc_value_ + 1); + return false; + } +} + +void SafeModeComponent::write_rtc_(uint32_t val) { + this->rtc_.save(&val); + global_preferences->sync(); +} + +uint32_t SafeModeComponent::read_rtc_() { + uint32_t val; + if (!this->rtc_.load(&val)) + return 0; + return val; +} + +void SafeModeComponent::clean_rtc() { this->write_rtc_(0); } + +void SafeModeComponent::on_safe_shutdown() { + if (this->read_rtc_() != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) + this->clean_rtc(); +} + +} // namespace safe_mode +} // namespace esphome diff --git a/esphome/components/safe_mode/safe_mode.h b/esphome/components/safe_mode/safe_mode.h new file mode 100644 index 0000000000..6c7450a6ff --- /dev/null +++ b/esphome/components/safe_mode/safe_mode.h @@ -0,0 +1,44 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace safe_mode { + +/// SafeModeComponent provides a safe way to recover from repeated boot failures +class SafeModeComponent : public Component { + public: + bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time); + + /// Set to true if the next startup will enter safe mode + void set_safe_mode_pending(const bool &pending); + bool get_safe_mode_pending(); + + void dump_config() override; + float get_setup_priority() const override; + void loop() override; + + void clean_rtc(); + + void on_safe_shutdown() override; + + protected: + void write_rtc_(uint32_t val); + uint32_t read_rtc_(); + + bool boot_successful_{false}; ///< set to true after boot is considered successful + uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled + uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for + uint32_t safe_mode_rtc_value_; + uint8_t safe_mode_num_attempts_; + ESPPreferenceObject rtc_; + + static const uint32_t ENTER_SAFE_MODE_MAGIC = + 0x5afe5afe; ///< a magic number to indicate that safe mode should be entered on next boot +}; + +} // namespace safe_mode +} // namespace esphome diff --git a/esphome/components/safe_mode/switch/__init__.py b/esphome/components/safe_mode/switch/__init__.py index 0f8e500482..7271358149 100644 --- a/esphome/components/safe_mode/switch/__init__.py +++ b/esphome/components/safe_mode/switch/__init__.py @@ -1,15 +1,14 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import switch -from esphome.components.esphome.ota import ESPHomeOTAComponent from esphome.const import ( - CONF_ESPHOME, + CONF_SAFE_MODE, ENTITY_CATEGORY_CONFIG, ICON_RESTART_ALERT, ) -from .. import safe_mode_ns +from .. import safe_mode_ns, SafeModeComponent -DEPENDENCIES = ["ota.esphome"] +DEPENDENCIES = ["safe_mode"] SafeModeSwitch = safe_mode_ns.class_("SafeModeSwitch", switch.Switch, cg.Component) @@ -20,7 +19,7 @@ CONFIG_SCHEMA = ( entity_category=ENTITY_CATEGORY_CONFIG, icon=ICON_RESTART_ALERT, ) - .extend({cv.GenerateID(CONF_ESPHOME): cv.use_id(ESPHomeOTAComponent)}) + .extend({cv.GenerateID(CONF_SAFE_MODE): cv.use_id(SafeModeComponent)}) .extend(cv.COMPONENT_SCHEMA) ) @@ -29,5 +28,5 @@ async def to_code(config): var = await switch.new_switch(config) await cg.register_component(var, config) - ota = await cg.get_variable(config[CONF_ESPHOME]) - cg.add(var.set_ota(ota)) + safe_mode_component = await cg.get_variable(config[CONF_SAFE_MODE]) + cg.add(var.set_safe_mode(safe_mode_component)) diff --git a/esphome/components/safe_mode/switch/safe_mode_switch.cpp b/esphome/components/safe_mode/switch/safe_mode_switch.cpp index 71408df140..13b35ed210 100644 --- a/esphome/components/safe_mode/switch/safe_mode_switch.cpp +++ b/esphome/components/safe_mode/switch/safe_mode_switch.cpp @@ -6,9 +6,11 @@ namespace esphome { namespace safe_mode { -static const char *const TAG = "safe_mode_switch"; +static const char *const TAG = "safe_mode.switch"; -void SafeModeSwitch::set_ota(esphome::ESPHomeOTAComponent *ota) { this->ota_ = ota; } +void SafeModeSwitch::set_safe_mode(SafeModeComponent *safe_mode_component) { + this->safe_mode_component_ = safe_mode_component; +} void SafeModeSwitch::write_state(bool state) { // Acknowledge @@ -16,13 +18,14 @@ void SafeModeSwitch::write_state(bool state) { if (state) { ESP_LOGI(TAG, "Restarting device in safe mode..."); - this->ota_->set_safe_mode_pending(true); + this->safe_mode_component_->set_safe_mode_pending(true); // Let MQTT settle a bit delay(100); // NOLINT App.safe_reboot(); } } + void SafeModeSwitch::dump_config() { LOG_SWITCH("", "Safe Mode Switch", this); } } // namespace safe_mode diff --git a/esphome/components/safe_mode/switch/safe_mode_switch.h b/esphome/components/safe_mode/switch/safe_mode_switch.h index 5bd15a44de..24e660c803 100644 --- a/esphome/components/safe_mode/switch/safe_mode_switch.h +++ b/esphome/components/safe_mode/switch/safe_mode_switch.h @@ -1,6 +1,6 @@ #pragma once -#include "esphome/components/esphome/ota/ota_esphome.h" +#include "esphome/components/safe_mode/safe_mode.h" #include "esphome/components/switch/switch.h" #include "esphome/core/component.h" @@ -10,10 +10,10 @@ namespace safe_mode { class SafeModeSwitch : public switch_::Switch, public Component { public: void dump_config() override; - void set_ota(esphome::ESPHomeOTAComponent *ota); + void set_safe_mode(SafeModeComponent *safe_mode_component); protected: - esphome::ESPHomeOTAComponent *ota_; + SafeModeComponent *safe_mode_component_; void write_state(bool state) override; }; diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index ce494e5d9d..825224bb9d 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -3,12 +3,9 @@ import logging from esphome.const import ( CONF_DISABLED_BY_DEFAULT, CONF_ENTITY_CATEGORY, - CONF_ESPHOME, CONF_ICON, CONF_INTERNAL, CONF_NAME, - CONF_OTA, - CONF_PLATFORM, CONF_SAFE_MODE, CONF_SETUP_PRIORITY, CONF_TYPE_ID, @@ -141,22 +138,12 @@ async def build_registry_list(registry, config): async def past_safe_mode(): - ota_conf = {} - for ota_item in CORE.config.get(CONF_OTA, []): - if ota_item[CONF_PLATFORM] == CONF_ESPHOME: - ota_conf = ota_item - break - - if not ota_conf: - return - - safe_mode_enabled = ota_conf[CONF_SAFE_MODE] - if not safe_mode_enabled: + if CONF_SAFE_MODE not in CORE.config: return def _safe_mode_generator(): while True: - if CORE.data.get(CONF_OTA, {}).get(KEY_PAST_SAFE_MODE, False): + if CORE.data.get(CONF_SAFE_MODE, {}).get(KEY_PAST_SAFE_MODE, False): return yield diff --git a/tests/components/ota/common.yaml b/tests/components/ota/common.yaml index 4910e2d891..1433dada1f 100644 --- a/tests/components/ota/common.yaml +++ b/tests/components/ota/common.yaml @@ -4,11 +4,8 @@ wifi: ota: - platform: esphome - safe_mode: true password: "superlongpasswordthatnoonewillknow" port: 3286 - reboot_timeout: 2min - num_attempts: 5 on_begin: then: - logger.log: "OTA start" diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml index 1dfc516254..9c1d1ad3f9 100644 --- a/tests/components/safe_mode/common.yaml +++ b/tests/components/safe_mode/common.yaml @@ -2,9 +2,9 @@ wifi: ssid: MySSID password: password1 -ota: - - platform: esphome - safe_mode: true +safe_mode: + num_attempts: 3 + reboot_timeout: 2min button: - platform: safe_mode diff --git a/tests/test1.yaml b/tests/test1.yaml index dc46b55c44..2a20a1bb45 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -264,13 +264,14 @@ uart: parity: EVEN baud_rate: 9600 +safe_mode: + num_attempts: 3 + reboot_timeout: 2min + ota: - platform: esphome - safe_mode: true password: "superlongpasswordthatnoonewillknow" port: 3286 - reboot_timeout: 2min - num_attempts: 5 on_state_change: then: lambda: >- diff --git a/tests/test2.yaml b/tests/test2.yaml index 54ff4807a3..92977697c1 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -79,11 +79,11 @@ uart: sequence: - lambda: UARTDebug::log_hex(direction, bytes, ':'); +safe_mode: + ota: - platform: esphome - safe_mode: true port: 3286 - num_attempts: 15 logger: level: DEBUG diff --git a/tests/test3.yaml b/tests/test3.yaml index 7554d4bcb2..d10413b142 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -327,11 +327,13 @@ modbus: vbus: uart_id: uart_4 +safe_mode: + num_attempts: 5 + reboot_timeout: 10min + ota: - platform: esphome - safe_mode: true port: 3286 - reboot_timeout: 15min logger: hardware_uart: UART1 diff --git a/tests/test4.yaml b/tests/test4.yaml index 86beee81c6..c9e8a27317 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -102,9 +102,10 @@ uart: baud_rate: 1200 parity: EVEN +safe_mode: + ota: - platform: esphome - safe_mode: true port: 3286 logger: From 1ca7c2d7ddc44f8debe288a98fbca3e40796f5cf Mon Sep 17 00:00:00 2001 From: Jeroen van Oort Date: Wed, 22 May 2024 06:17:32 +0200 Subject: [PATCH 1792/2607] Add support for acting as Modbus server (#4874) Co-authored-by: Jeroen van Oort Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/modbus/__init__.py | 35 ++++++++++++ esphome/components/modbus/modbus.cpp | 27 ++++++--- esphome/components/modbus/modbus.h | 9 +++ .../components/modbus_controller/__init__.py | 52 +++++++++++++++-- .../modbus_controller/modbus_controller.cpp | 57 +++++++++++++++++-- .../modbus_controller/modbus_controller.h | 22 +++++++ .../modbus_controller/test.esp32.yaml | 22 ++++++- 7 files changed, 203 insertions(+), 21 deletions(-) diff --git a/esphome/components/modbus/__init__.py b/esphome/components/modbus/__init__.py index 6fea7033f2..ae0c818c28 100644 --- a/esphome/components/modbus/__init__.py +++ b/esphome/components/modbus/__init__.py @@ -1,5 +1,9 @@ +from __future__ import annotations +from typing import Literal + import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv from esphome.cpp_helpers import gpio_pin_expression from esphome.components import uart from esphome.const import ( @@ -17,13 +21,21 @@ Modbus = modbus_ns.class_("Modbus", cg.Component, uart.UARTDevice) ModbusDevice = modbus_ns.class_("ModbusDevice") MULTI_CONF = True +CONF_ROLE = "role" CONF_MODBUS_ID = "modbus_id" CONF_SEND_WAIT_TIME = "send_wait_time" +ModbusRole = modbus_ns.enum("ModbusRole") +MODBUS_ROLES = { + "client": ModbusRole.CLIENT, + "server": ModbusRole.SERVER, +} + CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(Modbus), + cv.Optional(CONF_ROLE, default="client"): cv.enum(MODBUS_ROLES), cv.Optional(CONF_FLOW_CONTROL_PIN): pins.gpio_output_pin_schema, cv.Optional( CONF_SEND_WAIT_TIME, default="250ms" @@ -43,6 +55,7 @@ async def to_code(config): await uart.register_uart_device(var, config) + cg.add(var.set_role(config[CONF_ROLE])) if CONF_FLOW_CONTROL_PIN in config: pin = await gpio_pin_expression(config[CONF_FLOW_CONTROL_PIN]) cg.add(var.set_flow_control_pin(pin)) @@ -62,6 +75,28 @@ def modbus_device_schema(default_address): return cv.Schema(schema) +def final_validate_modbus_device( + name: str, *, role: Literal["server", "client"] | None = None +): + def validate_role(value): + assert role in MODBUS_ROLES + if value != role: + raise cv.Invalid(f"Component {name} requires role to be {role}") + return value + + def validate_hub(hub_config): + hub_schema = {} + if role is not None: + hub_schema[cv.Required(CONF_ROLE)] = validate_role + + return cv.Schema(hub_schema, extra=cv.ALLOW_EXTRA)(hub_config) + + return cv.Schema( + {cv.Required(CONF_MODBUS_ID): fv.id_declaration_match_schema(validate_hub)}, + extra=cv.ALLOW_EXTRA, + ) + + async def register_modbus_device(var, config): parent = await cg.get_variable(config[CONF_MODBUS_ID]) cg.add(var.set_parent(parent)) diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index 137fb0b26b..f8dd4c18b9 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -77,7 +77,13 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { ESP_LOGD(TAG, "Modbus user-defined function %02X found", function_code); } else { - // the response for write command mirrors the requests and data startes at offset 2 instead of 3 for read commands + // data starts at 2 and length is 4 for read registers commands + if (this->role == ModbusRole::SERVER && (function_code == 0x3 || function_code == 0x4)) { + data_offset = 2; + data_len = 4; + } + + // the response for write command mirrors the requests and data starts at offset 2 instead of 3 for read commands if (function_code == 0x5 || function_code == 0x06 || function_code == 0xF || function_code == 0x10) { data_offset = 2; data_len = 4; @@ -123,6 +129,9 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { // Ignore modbus exception not related to a pending command ESP_LOGD(TAG, "Ignoring Modbus error - not expecting a response"); } + } else if (this->role == ModbusRole::SERVER && (function_code == 0x3 || function_code == 0x4)) { + device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8), + uint16_t(data[3]) | (uint16_t(data[2]) << 8)); } else { device->on_modbus_data(data); } @@ -164,16 +173,18 @@ void Modbus::send(uint8_t address, uint8_t function_code, uint16_t start_address std::vector data; data.push_back(address); data.push_back(function_code); - data.push_back(start_address >> 8); - data.push_back(start_address >> 0); - if (function_code != 0x5 && function_code != 0x6) { - data.push_back(number_of_entities >> 8); - data.push_back(number_of_entities >> 0); + if (this->role == ModbusRole::CLIENT) { + data.push_back(start_address >> 8); + data.push_back(start_address >> 0); + if (function_code != 0x5 && function_code != 0x6) { + data.push_back(number_of_entities >> 8); + data.push_back(number_of_entities >> 0); + } } if (payload != nullptr) { - if (function_code == 0xF || function_code == 0x10) { // Write multiple - data.push_back(payload_len); // Byte count is required for write + if (this->role == ModbusRole::SERVER || function_code == 0xF || function_code == 0x10) { // Write multiple + data.push_back(payload_len); // Byte count is required for write } else { payload_len = 2; // Write single register or coil } diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index dd8732c6e9..4a78ed4aab 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -8,6 +8,11 @@ namespace esphome { namespace modbus { +enum ModbusRole { + CLIENT, + SERVER, +}; + class ModbusDevice; class Modbus : public uart::UARTDevice, public Component { @@ -27,11 +32,14 @@ class Modbus : public uart::UARTDevice, public Component { void send(uint8_t address, uint8_t function_code, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len = 0, const uint8_t *payload = nullptr); void send_raw(const std::vector &payload); + void set_role(ModbusRole role) { this->role = role; } void set_flow_control_pin(GPIOPin *flow_control_pin) { this->flow_control_pin_ = flow_control_pin; } uint8_t waiting_for_response{0}; void set_send_wait_time(uint16_t time_in_ms) { send_wait_time_ = time_in_ms; } void set_disable_crc(bool disable_crc) { disable_crc_ = disable_crc; } + ModbusRole role; + protected: GPIOPin *flow_control_pin_{nullptr}; @@ -50,6 +58,7 @@ class ModbusDevice { void set_address(uint8_t address) { address_ = address; } virtual void on_modbus_data(const std::vector &data) = 0; virtual void on_modbus_error(uint8_t function_code, uint8_t exception_code) {} + virtual void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers){}; void send(uint8_t function, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len = 0, const uint8_t *payload = nullptr) { this->parent_->send(this->address_, function, start_address, number_of_entities, payload_len, payload); diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 8703771c3a..b8ab48fcc6 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -23,6 +23,8 @@ CODEOWNERS = ["@martgras"] AUTO_LOAD = ["modbus"] +CONF_READ_LAMBDA = "read_lambda" +CONF_SERVER_REGISTERS = "server_registers" MULTI_CONF = True modbus_controller_ns = cg.esphome_ns.namespace("modbus_controller") @@ -31,6 +33,7 @@ ModbusController = modbus_controller_ns.class_( ) SensorItem = modbus_controller_ns.struct("SensorItem") +ServerRegister = modbus_controller_ns.struct("ServerRegister") ModbusFunctionCode_ns = modbus_controller_ns.namespace("ModbusFunctionCode") ModbusFunctionCode = ModbusFunctionCode_ns.enum("ModbusFunctionCode") @@ -94,10 +97,18 @@ TYPE_REGISTER_MAP = { "FP32_R": 2, } -MULTI_CONF = True - _LOGGER = logging.getLogger(__name__) +ModbusServerRegisterSchema = cv.Schema( + { + cv.GenerateID(): cv.declare_id(ServerRegister), + cv.Required(CONF_ADDRESS): cv.positive_int, + cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE), + cv.Required(CONF_READ_LAMBDA): cv.returning_lambda, + } +) + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -106,6 +117,9 @@ CONFIG_SCHEMA = cv.All( CONF_COMMAND_THROTTLE, default="0ms" ): cv.positive_time_period_milliseconds, cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int, + cv.Optional( + CONF_SERVER_REGISTERS, + ): cv.ensure_list(ModbusServerRegisterSchema), } ) .extend(cv.polling_component_schema("60s")) @@ -154,6 +168,17 @@ def validate_modbus_register(config): return config +def _final_validate(config): + if CONF_SERVER_REGISTERS in config: + return modbus.final_validate_modbus_device("modbus_controller", role="server")( + config + ) + return config + + +FINAL_VALIDATE_SCHEMA = _final_validate + + def modbus_calc_properties(config): byte_offset = 0 reg_count = 0 @@ -183,7 +208,7 @@ def modbus_calc_properties(config): async def add_modbus_base_properties( - var, config, sensor_type, lamdba_param_type=cg.float_, lamdba_return_type=float + var, config, sensor_type, lambda_param_type=cg.float_, lambda_return_type=float ): if CONF_CUSTOM_COMMAND in config: cg.add(var.set_custom_data(config[CONF_CUSTOM_COMMAND])) @@ -196,13 +221,13 @@ async def add_modbus_base_properties( config[CONF_LAMBDA], [ (sensor_type.operator("ptr"), "item"), - (lamdba_param_type, "x"), + (lambda_param_type, "x"), ( cg.std_vector.template(cg.uint8).operator("const").operator("ref"), "data", ), ], - return_type=cg.optional.template(lamdba_return_type), + return_type=cg.optional.template(lambda_return_type), ) cg.add(var.set_template(template_)) @@ -211,6 +236,23 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE])) cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES])) + if CONF_SERVER_REGISTERS in config: + for server_register in config[CONF_SERVER_REGISTERS]: + cg.add( + var.add_server_register( + cg.new_Pvariable( + server_register[CONF_ID], + server_register[CONF_ADDRESS], + server_register[CONF_VALUE_TYPE], + TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]], + await cg.process_lambda( + server_register[CONF_READ_LAMBDA], + [], + return_type=cg.float_, + ), + ) + ) + ) await register_modbus_device(var, config) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 7565dc5e1b..9f73988b03 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -7,10 +7,7 @@ namespace modbus_controller { static const char *const TAG = "modbus_controller"; -void ModbusController::setup() { - // Modbus::setup(); - this->create_register_ranges_(); -} +void ModbusController::setup() { this->create_register_ranges_(); } /* To work with the existing modbus class and avoid polling for responses a command queue is used. @@ -102,6 +99,51 @@ void ModbusController::on_modbus_error(uint8_t function_code, uint8_t exception_ } } +void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t start_address, + uint16_t number_of_registers) { + ESP_LOGD(TAG, + "Received read holding/input registers for device 0x%X. FC: 0x%X. Start address: 0x%X. Number of registers: " + "0x%X.", + this->address_, function_code, start_address, number_of_registers); + + std::vector sixteen_bit_response; + for (uint16_t current_address = start_address; current_address < start_address + number_of_registers;) { + bool found = false; + for (auto *server_register : this->server_registers_) { + if (server_register->address == current_address) { + float value = server_register->read_lambda(); + + ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %0.1f.", + server_register->address, static_cast(server_register->value_type), + server_register->register_count, value); + number_to_payload(sixteen_bit_response, value, server_register->value_type); + current_address += server_register->register_count; + found = true; + break; + } + } + + if (!found) { + ESP_LOGW(TAG, "Could not match any register to address %02X. Sending exception response.", current_address); + std::vector error_response; + error_response.push_back(this->address_); + error_response.push_back(0x81); + error_response.push_back(0x02); + this->send_raw(error_response); + return; + } + } + + std::vector response; + for (auto v : sixteen_bit_response) { + auto decoded_value = decode_value(v); + response.push_back(decoded_value[0]); + response.push_back(decoded_value[1]); + } + + this->send(function_code, start_address, number_of_registers, response.size(), response.data()); +} + SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const { auto reg_it = find_if(begin(register_ranges_), end(register_ranges_), [=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); @@ -190,7 +232,7 @@ void ModbusController::update() { // walk through the sensors and determine the register ranges to read size_t ModbusController::create_register_ranges_() { register_ranges_.clear(); - if (sensorset_.empty()) { + if (this->parent_->role == modbus::ModbusRole::CLIENT && sensorset_.empty()) { ESP_LOGW(TAG, "No sensors registered"); return 0; } @@ -309,6 +351,11 @@ void ModbusController::dump_config() { ESP_LOGCONFIG(TAG, " Range type=%zu start=0x%X count=%d skip_updates=%d", static_cast(it.register_type), it.start_address, it.register_count, it.skip_updates); } + ESP_LOGCONFIG(TAG, "server registers"); + for (auto &r : server_registers_) { + ESP_LOGCONFIG(TAG, " Address=0x%02X value_type=%zu register_count=%u", r->address, + static_cast(r->value_type), r->register_count); + } #endif } diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index a389375523..9b7d59c93f 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace esphome { @@ -251,6 +252,21 @@ class SensorItem { bool force_new_range{false}; }; +class ServerRegister { + public: + ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count, + std::function read_lambda) { + this->address = address; + this->value_type = value_type; + this->register_count = register_count; + this->read_lambda = std::move(read_lambda); + } + uint16_t address; + SensorValueType value_type; + uint8_t register_count; + std::function read_lambda; +}; + // ModbusController::create_register_ranges_ tries to optimize register range // for this the sensors must be ordered by register_type, start_address and bitmask class SensorItemsComparator { @@ -418,10 +434,14 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { void queue_command(const ModbusCommandItem &command); /// Registers a sensor with the controller. Called by esphomes code generator void add_sensor_item(SensorItem *item) { sensorset_.insert(item); } + /// Registers a server register with the controller. Called by esphomes code generator + void add_server_register(ServerRegister *server_register) { server_registers_.push_back(server_register); } /// called when a modbus response was parsed without errors void on_modbus_data(const std::vector &data) override; /// called when a modbus error response was received void on_modbus_error(uint8_t function_code, uint8_t exception_code) override; + /// called when a modbus request (function code 3 or 4) was parsed without errors + void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers) final; /// default delegate called by process_modbus_data when a response has retrieved from the incoming queue void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector &data); /// default delegate called by process_modbus_data when a response for a write response has retrieved from the @@ -452,6 +472,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { void dump_sensors_(); /// Collection of all sensors for this component SensorSet sensorset_; + /// Collection of all server registers for this component + std::vector server_registers_; /// Continuous range of modbus registers std::vector register_ranges_; /// Hold the pending requests to be sent diff --git a/tests/components/modbus_controller/test.esp32.yaml b/tests/components/modbus_controller/test.esp32.yaml index c5fe3fd057..3e022b10ab 100644 --- a/tests/components/modbus_controller/test.esp32.yaml +++ b/tests/components/modbus_controller/test.esp32.yaml @@ -1,14 +1,30 @@ uart: - - id: uart_modbus + - id: uart_modbus_client tx_pin: 17 rx_pin: 16 baud_rate: 9600 + - id: uart_modbus_server + tx_pin: 1 + rx_pin: 3 + baud_rate: 9600 modbus: - id: mod_bus1 - flow_control_pin: 15 + - id: mod_bus1 + uart_id: uart_modbus_client + flow_control_pin: 15 + - id: mod_bus2 + uart_id: uart_modbus_server + role: server modbus_controller: - id: modbus_controller1 address: 0x2 modbus_id: mod_bus1 + - id: modbus_controller2 + address: 0x2 + modbus_id: mod_bus2 + server_registers: + - address: 0x0000 + value_type: S_DWORD_R + read_lambda: |- + return 42.3; From 9a6fde21ee2fa4049e8c12760b8a12cf49cf4c94 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 22 May 2024 14:43:13 -0500 Subject: [PATCH 1793/2607] Add on_safe_mode trigger (#6790) --- esphome/components/safe_mode/__init__.py | 14 ++++++++++++++ esphome/components/safe_mode/automation.h | 17 +++++++++++++++++ esphome/components/safe_mode/safe_mode.cpp | 2 ++ esphome/components/safe_mode/safe_mode.h | 5 +++++ tests/components/safe_mode/common.yaml | 2 ++ 5 files changed, 40 insertions(+) create mode 100644 esphome/components/safe_mode/automation.h diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index 7f227d7dd1..92b285e279 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -7,15 +7,20 @@ from esphome.const import ( CONF_NUM_ATTEMPTS, CONF_REBOOT_TIMEOUT, CONF_SAFE_MODE, + CONF_TRIGGER_ID, KEY_PAST_SAFE_MODE, ) from esphome.core import CORE, coroutine_with_priority +from esphome import automation CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] +CONF_ON_SAFE_MODE = "on_safe_mode" + safe_mode_ns = cg.esphome_ns.namespace("safe_mode") SafeModeComponent = safe_mode_ns.class_("SafeModeComponent", cg.Component) +SafeModeTrigger = safe_mode_ns.class_("SafeModeTrigger", automation.Trigger.template()) def _remove_id_if_disabled(value): @@ -34,6 +39,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional( CONF_REBOOT_TIMEOUT, default="5min" ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_ON_SAFE_MODE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SafeModeTrigger), + } + ), } ).extend(cv.COMPONENT_SCHEMA), _remove_id_if_disabled, @@ -48,6 +58,10 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) + for conf in config.get(CONF_ON_SAFE_MODE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + condition = var.should_enter_safe_mode( config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] ) diff --git a/esphome/components/safe_mode/automation.h b/esphome/components/safe_mode/automation.h new file mode 100644 index 0000000000..d1388449ee --- /dev/null +++ b/esphome/components/safe_mode/automation.h @@ -0,0 +1,17 @@ +#pragma once +#include "safe_mode.h" + +#include "esphome/core/automation.h" + +namespace esphome { +namespace safe_mode { + +class SafeModeTrigger : public Trigger<> { + public: + explicit SafeModeTrigger(SafeModeComponent *parent) { + parent->add_on_safe_mode_callback([this, parent]() { trigger(); }); + } +}; + +} // namespace safe_mode +} // namespace esphome diff --git a/esphome/components/safe_mode/safe_mode.cpp b/esphome/components/safe_mode/safe_mode.cpp index 06772ae1e0..6934dcb9d9 100644 --- a/esphome/components/safe_mode/safe_mode.cpp +++ b/esphome/components/safe_mode/safe_mode.cpp @@ -94,6 +94,8 @@ bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t en ESP_LOGW(TAG, "SAFE MODE IS ACTIVE"); + this->safe_mode_callback_.call(); + return true; } else { // increment counter diff --git a/esphome/components/safe_mode/safe_mode.h b/esphome/components/safe_mode/safe_mode.h index 6c7450a6ff..0ec3c29529 100644 --- a/esphome/components/safe_mode/safe_mode.h +++ b/esphome/components/safe_mode/safe_mode.h @@ -25,6 +25,10 @@ class SafeModeComponent : public Component { void on_safe_shutdown() override; + void add_on_safe_mode_callback(std::function &&callback) { + this->safe_mode_callback_.add(std::move(callback)); + } + protected: void write_rtc_(uint32_t val); uint32_t read_rtc_(); @@ -35,6 +39,7 @@ class SafeModeComponent : public Component { uint32_t safe_mode_rtc_value_; uint8_t safe_mode_num_attempts_; ESPPreferenceObject rtc_; + CallbackManager safe_mode_callback_{}; static const uint32_t ENTER_SAFE_MODE_MAGIC = 0x5afe5afe; ///< a magic number to indicate that safe mode should be entered on next boot diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml index 9c1d1ad3f9..ce8bf2f0cf 100644 --- a/tests/components/safe_mode/common.yaml +++ b/tests/components/safe_mode/common.yaml @@ -5,6 +5,8 @@ wifi: safe_mode: num_attempts: 3 reboot_timeout: 2min + on_safe_mode: + - logger.log: Time for safe mode button: - platform: safe_mode From 7f9383c83b1a4758b3950bf91333222d4ba40ca3 Mon Sep 17 00:00:00 2001 From: Penny Wood Date: Thu, 23 May 2024 05:31:56 +0800 Subject: [PATCH 1794/2607] [sx1509] Output open drain pin mode (#6788) --- esphome/components/sx1509/__init__.py | 4 ++ esphome/components/sx1509/sx1509.cpp | 56 ++++++++++++++----- .../components/sx1509/test.esp32-c3-idf.yaml | 18 ++++++ tests/components/sx1509/test.esp32-c3.yaml | 18 ++++++ tests/components/sx1509/test.esp32-idf.yaml | 18 ++++++ tests/components/sx1509/test.esp32.yaml | 18 ++++++ tests/components/sx1509/test.esp8266.yaml | 18 ++++++ tests/components/sx1509/test.rp2040.yaml | 18 ++++++ 8 files changed, 155 insertions(+), 13 deletions(-) diff --git a/esphome/components/sx1509/__init__.py b/esphome/components/sx1509/__init__.py index faef940125..e4f79dc2bc 100644 --- a/esphome/components/sx1509/__init__.py +++ b/esphome/components/sx1509/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_OUTPUT, CONF_PULLDOWN, CONF_PULLUP, + CONF_OPEN_DRAIN, ) CONF_KEYPAD = "keypad" @@ -79,6 +80,8 @@ def validate_mode(value): raise cv.Invalid("Pulldown only available with input") if value[CONF_PULLUP] and value[CONF_PULLDOWN]: raise cv.Invalid("Can only have one of pullup or pulldown") + if value[CONF_OPEN_DRAIN] and not value[CONF_OUTPUT]: + raise cv.Invalid("Open drain available only with output") return value @@ -94,6 +97,7 @@ SX1509_PIN_SCHEMA = cv.All( cv.Optional(CONF_PULLUP, default=False): cv.boolean, cv.Optional(CONF_PULLDOWN, default=False): cv.boolean, cv.Optional(CONF_OUTPUT, default=False): cv.boolean, + cv.Optional(CONF_OPEN_DRAIN, default=False): cv.boolean, }, validate_mode, ), diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index ee90e0e410..855a90bacd 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -86,33 +86,63 @@ void SX1509Component::digital_write(uint8_t pin, bool bit_value) { } void SX1509Component::pin_mode(uint8_t pin, gpio::Flags flags) { + ESP_LOGI(TAG, "Configuring pin %u with flags %x", pin, flags); + + uint16_t temp_word = 0; + this->read_byte_16(REG_DIR_B, &this->ddr_mask_); - if (flags == gpio::FLAG_OUTPUT) { + if (flags & gpio::FLAG_OUTPUT) { + // Always disable input buffer + this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word); + temp_word |= (1 << pin); + this->write_byte_16(REG_INPUT_DISABLE_B, temp_word); + + if (flags & gpio::FLAG_OPEN_DRAIN) { + // Pullup must be disabled for open drain mode + this->read_byte_16(REG_PULL_UP_B, &temp_word); + temp_word &= ~(1 << pin); + this->write_byte_16(REG_PULL_UP_B, temp_word); + this->read_byte_16(REG_OPEN_DRAIN_B, &temp_word); + temp_word |= (1 << pin); + this->write_byte_16(REG_OPEN_DRAIN_B, temp_word); + ESP_LOGD(TAG, "Open drain output mode set for %u", pin); + } else { + ESP_LOGD(TAG, "Output Mode for %u", pin); + } + + // Set direction to output this->ddr_mask_ &= ~(1 << pin); + this->write_byte_16(REG_DIR_B, this->ddr_mask_); } else { - this->ddr_mask_ |= (1 << pin); + ESP_LOGD(TAG, "Input Mode for %u", pin); - uint16_t temp_pullup; - this->read_byte_16(REG_PULL_UP_B, &temp_pullup); - uint16_t temp_pulldown; - this->read_byte_16(REG_PULL_DOWN_B, &temp_pulldown); + // Always enable input buffer + this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word); + temp_word &= ~(1 << pin); + this->write_byte_16(REG_INPUT_DISABLE_B, temp_word); + // Pullup + this->read_byte_16(REG_PULL_UP_B, &temp_word); if (flags & gpio::FLAG_PULLUP) { - temp_pullup |= (1 << pin); + temp_word |= (1 << pin); } else { - temp_pullup &= ~(1 << pin); + temp_word &= ~(1 << pin); } + this->write_byte_16(REG_PULL_UP_B, temp_word); + // Pulldown + this->read_byte_16(REG_PULL_DOWN_B, &temp_word); if (flags & gpio::FLAG_PULLDOWN) { - temp_pulldown |= (1 << pin); + temp_word |= (1 << pin); } else { - temp_pulldown &= ~(1 << pin); + temp_word &= ~(1 << pin); } + this->write_byte_16(REG_PULL_DOWN_B, temp_word); - this->write_byte_16(REG_PULL_UP_B, temp_pullup); - this->write_byte_16(REG_PULL_DOWN_B, temp_pulldown); + // Set direction to input + this->ddr_mask_ |= (1 << pin); + this->write_byte_16(REG_DIR_B, this->ddr_mask_); } - this->write_byte_16(REG_DIR_B, this->ddr_mask_); } void SX1509Component::setup_led_driver(uint8_t pin) { diff --git a/tests/components/sx1509/test.esp32-c3-idf.yaml b/tests/components/sx1509/test.esp32-c3-idf.yaml index ced849b3df..0397812880 100644 --- a/tests/components/sx1509/test.esp32-c3-idf.yaml +++ b/tests/components/sx1509/test.esp32-c3-idf.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true diff --git a/tests/components/sx1509/test.esp32-c3.yaml b/tests/components/sx1509/test.esp32-c3.yaml index ced849b3df..0397812880 100644 --- a/tests/components/sx1509/test.esp32-c3.yaml +++ b/tests/components/sx1509/test.esp32-c3.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true diff --git a/tests/components/sx1509/test.esp32-idf.yaml b/tests/components/sx1509/test.esp32-idf.yaml index 1698f2abc4..aa1d161a43 100644 --- a/tests/components/sx1509/test.esp32-idf.yaml +++ b/tests/components/sx1509/test.esp32-idf.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true diff --git a/tests/components/sx1509/test.esp32.yaml b/tests/components/sx1509/test.esp32.yaml index 1698f2abc4..aa1d161a43 100644 --- a/tests/components/sx1509/test.esp32.yaml +++ b/tests/components/sx1509/test.esp32.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true diff --git a/tests/components/sx1509/test.esp8266.yaml b/tests/components/sx1509/test.esp8266.yaml index ced849b3df..0397812880 100644 --- a/tests/components/sx1509/test.esp8266.yaml +++ b/tests/components/sx1509/test.esp8266.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true diff --git a/tests/components/sx1509/test.rp2040.yaml b/tests/components/sx1509/test.rp2040.yaml index ced849b3df..0397812880 100644 --- a/tests/components/sx1509/test.rp2040.yaml +++ b/tests/components/sx1509/test.rp2040.yaml @@ -13,3 +13,21 @@ binary_sensor: pin: sx1509: sx1509_hub number: 3 + +switch: + - platform: gpio + name: GPIO SX1509 Test Out Open Drain + pin: + sx1509: sx1509_hub + number: 0 + mode: + output: true + open_drain: true + + - platform: gpio + name: GPIO SX1509 Test Out Standard + pin: + sx1509: sx1509_hub + number: 1 + mode: + output: true From 4ab7a5d964c5a2d956e873292ef061d21d8ddf66 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 23 May 2024 17:04:33 +1200 Subject: [PATCH 1795/2607] [ledc] Change some logging lines from debug to verbose (#6796) --- esphome/components/ledc/ledc_output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 0533143d37..1040ac25b6 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -52,12 +52,12 @@ float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency) { } optional ledc_bit_depth_for_frequency(float frequency) { - ESP_LOGD(TAG, "Calculating resolution bit-depth for frequency %f", frequency); + ESP_LOGV(TAG, "Calculating resolution bit-depth for frequency %f", frequency); for (int i = MAX_RES_BITS; i >= 1; i--) { const float min_frequency = ledc_min_frequency_for_bit_depth(i, (frequency < 100)); const float max_frequency = ledc_max_frequency_for_bit_depth(i); if (min_frequency <= frequency && frequency <= max_frequency) { - ESP_LOGD(TAG, "Resolution calculated as %d", i); + ESP_LOGV(TAG, "Resolution calculated as %d", i); return i; } } From aed0593793d8595d3e32737ffe77805dd02e1f95 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Thu, 23 May 2024 23:07:39 +0200 Subject: [PATCH 1796/2607] [haier] ``text_sensor`` and ``button`` platforms (#6780) --- CODEOWNERS | 4 + esphome/components/haier/automation.h | 4 +- .../haier/binary_sensor/__init__.py | 1 + esphome/components/haier/button/__init__.py | 41 ++++++ .../components/haier/button/self_cleaning.cpp | 9 ++ .../components/haier/button/self_cleaning.h | 18 +++ .../haier/button/steri_cleaning.cpp | 9 ++ .../components/haier/button/steri_cleaning.h | 18 +++ esphome/components/haier/climate.py | 7 +- esphome/components/haier/haier_base.cpp | 3 +- esphome/components/haier/haier_base.h | 3 +- esphome/components/haier/hon_climate.cpp | 130 +++++++++++------- esphome/components/haier/hon_climate.h | 59 ++++---- esphome/components/haier/hon_packet.h | 5 +- esphome/components/haier/sensor/__init__.py | 1 + .../components/haier/text_sensor/__init__.py | 54 ++++++++ platformio.ini | 2 +- tests/components/haier/test.esp32-c3-idf.yaml | 18 +++ tests/components/haier/test.esp32-c3.yaml | 18 +++ tests/components/haier/test.esp32-idf.yaml | 18 +++ tests/components/haier/test.esp32.yaml | 18 +++ tests/components/haier/test.esp8266.yaml | 18 +++ tests/components/haier/test.rp2040.yaml | 18 +++ 23 files changed, 396 insertions(+), 80 deletions(-) create mode 100644 esphome/components/haier/button/__init__.py create mode 100644 esphome/components/haier/button/self_cleaning.cpp create mode 100644 esphome/components/haier/button/self_cleaning.h create mode 100644 esphome/components/haier/button/steri_cleaning.cpp create mode 100644 esphome/components/haier/button/steri_cleaning.h create mode 100644 esphome/components/haier/text_sensor/__init__.py diff --git a/CODEOWNERS b/CODEOWNERS index 22e581275b..e099ca42ac 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -152,6 +152,10 @@ esphome/components/grove_tb6612fng/* @max246 esphome/components/growatt_solar/* @leeuwte esphome/components/gt911/* @clydebarrow @jesserockz esphome/components/haier/* @paveldn +esphome/components/haier/binary_sensor/* @paveldn +esphome/components/haier/button/* @paveldn +esphome/components/haier/sensor/* @paveldn +esphome/components/haier/text_sensor/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal esphome/components/hbridge/fan/* @WeekendWarrior esphome/components/hbridge/light/* @DotNetDann diff --git a/esphome/components/haier/automation.h b/esphome/components/haier/automation.h index 84e4554db8..55df7ecc1d 100644 --- a/esphome/components/haier/automation.h +++ b/esphome/components/haier/automation.h @@ -46,7 +46,7 @@ template class BeeperOffAction : public Action { template class VerticalAirflowAction : public Action { public: VerticalAirflowAction(HonClimate *parent) : parent_(parent) {} - TEMPLATABLE_VALUE(AirflowVerticalDirection, direction) + TEMPLATABLE_VALUE(hon_protocol::VerticalSwingMode, direction) void play(Ts... x) { this->parent_->set_vertical_airflow(this->direction_.value(x...)); } protected: @@ -56,7 +56,7 @@ template class VerticalAirflowAction : public Action { template class HorizontalAirflowAction : public Action { public: HorizontalAirflowAction(HonClimate *parent) : parent_(parent) {} - TEMPLATABLE_VALUE(AirflowHorizontalDirection, direction) + TEMPLATABLE_VALUE(hon_protocol::HorizontalSwingMode, direction) void play(Ts... x) { this->parent_->set_horizontal_airflow(this->direction_.value(x...)); } protected: diff --git a/esphome/components/haier/binary_sensor/__init__.py b/esphome/components/haier/binary_sensor/__init__.py index 4f72560a7b..8e9d5ec578 100644 --- a/esphome/components/haier/binary_sensor/__init__.py +++ b/esphome/components/haier/binary_sensor/__init__.py @@ -11,6 +11,7 @@ from ..climate import ( HonClimate, ) +CODEOWNERS = ["@paveldn"] BinarySensorTypeEnum = HonClimate.enum("SubBinarySensorType", True) # Haier sensors diff --git a/esphome/components/haier/button/__init__.py b/esphome/components/haier/button/__init__.py new file mode 100644 index 0000000000..efe6180aaf --- /dev/null +++ b/esphome/components/haier/button/__init__.py @@ -0,0 +1,41 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import button +from ..climate import ( + CONF_HAIER_ID, + HonClimate, + haier_ns, +) + +CODEOWNERS = ["@paveldn"] +SelfCleaningButton = haier_ns.class_("SelfCleaningButton", button.Button) +SteriCleaningButton = haier_ns.class_("SteriCleaningButton", button.Button) + + +# Haier buttons +CONF_SELF_CLEANING = "self_cleaning" +CONF_STERI_CLEANING = "steri_cleaning" + +# Additional icons +ICON_SPRAY_BOTTLE = "mdi:spray-bottle" + +CONFIG_SCHEMA = cv.Schema( + { + cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + cv.Optional(CONF_SELF_CLEANING): button.button_schema( + SelfCleaningButton, + icon=ICON_SPRAY_BOTTLE, + ), + cv.Optional(CONF_STERI_CLEANING): button.button_schema( + SteriCleaningButton, + icon=ICON_SPRAY_BOTTLE, + ), + } +) + + +async def to_code(config): + for button_type in [CONF_SELF_CLEANING, CONF_STERI_CLEANING]: + if conf := config.get(button_type): + btn = await button.new_button(conf) + await cg.register_parented(btn, config[CONF_HAIER_ID]) diff --git a/esphome/components/haier/button/self_cleaning.cpp b/esphome/components/haier/button/self_cleaning.cpp new file mode 100644 index 0000000000..128726036e --- /dev/null +++ b/esphome/components/haier/button/self_cleaning.cpp @@ -0,0 +1,9 @@ +#include "self_cleaning.h" + +namespace esphome { +namespace haier { + +void SelfCleaningButton::press_action() { this->parent_->start_self_cleaning(); } + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/button/self_cleaning.h b/esphome/components/haier/button/self_cleaning.h new file mode 100644 index 0000000000..308fb70f06 --- /dev/null +++ b/esphome/components/haier/button/self_cleaning.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../hon_climate.h" + +namespace esphome { +namespace haier { + +class SelfCleaningButton : public button::Button, public Parented { + public: + SelfCleaningButton() = default; + + protected: + void press_action() override; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/button/steri_cleaning.cpp b/esphome/components/haier/button/steri_cleaning.cpp new file mode 100644 index 0000000000..02b723f1a4 --- /dev/null +++ b/esphome/components/haier/button/steri_cleaning.cpp @@ -0,0 +1,9 @@ +#include "steri_cleaning.h" + +namespace esphome { +namespace haier { + +void SteriCleaningButton::press_action() { this->parent_->start_steri_cleaning(); } + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/button/steri_cleaning.h b/esphome/components/haier/button/steri_cleaning.h new file mode 100644 index 0000000000..6cad313fb3 --- /dev/null +++ b/esphome/components/haier/button/steri_cleaning.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../hon_climate.h" + +namespace esphome { +namespace haier { + +class SteriCleaningButton : public button::Button, public Parented { + public: + SteriCleaningButton() = default; + + protected: + void press_action() override; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index b16244fd90..1562708a4f 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -55,6 +55,7 @@ PROTOCOL_HON = "HON" PROTOCOL_SMARTAIR2 = "SMARTAIR2" haier_ns = cg.esphome_ns.namespace("haier") +hon_protocol_ns = haier_ns.namespace("hon_protocol") HaierClimateBase = haier_ns.class_( "HaierClimateBase", uart.UARTDevice, climate.Climate, cg.Component ) @@ -63,7 +64,7 @@ Smartair2Climate = haier_ns.class_("Smartair2Climate", HaierClimateBase) CONF_HAIER_ID = "haier_id" -AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection", True) +AirflowVerticalDirection = hon_protocol_ns.enum("VerticalSwingMode", True) AIRFLOW_VERTICAL_DIRECTION_OPTIONS = { "HEALTH_UP": AirflowVerticalDirection.HEALTH_UP, "MAX_UP": AirflowVerticalDirection.MAX_UP, @@ -73,7 +74,7 @@ AIRFLOW_VERTICAL_DIRECTION_OPTIONS = { "HEALTH_DOWN": AirflowVerticalDirection.HEALTH_DOWN, } -AirflowHorizontalDirection = haier_ns.enum("AirflowHorizontalDirection", True) +AirflowHorizontalDirection = hon_protocol_ns.enum("HorizontalSwingMode", True) AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS = { "MAX_LEFT": AirflowHorizontalDirection.MAX_LEFT, "LEFT": AirflowHorizontalDirection.LEFT, @@ -483,4 +484,4 @@ async def to_code(config): trigger, [(cg.uint8, "code"), (cg.const_char_ptr, "message")], conf ) # https://github.com/paveldn/HaierProtocol - cg.add_library("pavlodn/HaierProtocol", "0.9.25") + cg.add_library("pavlodn/HaierProtocol", "0.9.28") diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index a3f68bb081..1fca3dfb85 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -234,6 +234,7 @@ void HaierClimateBase::setup() { this->haier_protocol_.set_default_timeout_handler( std::bind(&esphome::haier::HaierClimateBase::timeout_default_handler_, this, std::placeholders::_1)); this->set_handlers(); + this->initialization(); } void HaierClimateBase::dump_config() { @@ -326,7 +327,7 @@ ClimateTraits HaierClimateBase::traits() { return traits_; } void HaierClimateBase::control(const ClimateCall &call) { ESP_LOGD("Control", "Control call"); - if (this->protocol_phase_ < ProtocolPhases::IDLE) { + if (!this->valid_connection()) { ESP_LOGW(TAG, "Can't send control packet, first poll answer not received"); return; // cancel the control, we cant do it without a poll answer. } diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index 504c841e5f..f261a106a2 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -44,7 +44,7 @@ class HaierClimateBase : public esphome::Component, void set_supported_modes(const std::set &modes); void set_supported_swing_modes(const std::set &modes); void set_supported_presets(const std::set &presets); - bool valid_connection() { return this->protocol_phase_ >= ProtocolPhases::IDLE; }; + bool valid_connection() const { return this->protocol_phase_ >= ProtocolPhases::IDLE; }; size_t available() noexcept override { return esphome::uart::UARTDevice::available(); }; size_t read_array(uint8_t *data, size_t len) noexcept override { return esphome::uart::UARTDevice::read_array(data, len) ? len : 0; @@ -80,6 +80,7 @@ class HaierClimateBase : public esphome::Component, virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; virtual haier_protocol::HaierMessage get_control_message() = 0; virtual haier_protocol::HaierMessage get_power_message(bool state) = 0; + virtual void initialization(){}; virtual bool prepare_pending_action(); virtual void process_protocol_reset(); esphome::climate::ClimateTraits traits() override; diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 9933cb4c8f..903f7964da 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -19,38 +19,6 @@ constexpr uint8_t CONTROL_MESSAGE_RETRIES = 5; constexpr std::chrono::milliseconds CONTROL_MESSAGE_RETRIES_INTERVAL = std::chrono::milliseconds(500); constexpr size_t ALARM_STATUS_REQUEST_INTERVAL_MS = 600000; -hon_protocol::VerticalSwingMode get_vertical_swing_mode(AirflowVerticalDirection direction) { - switch (direction) { - case AirflowVerticalDirection::HEALTH_UP: - return hon_protocol::VerticalSwingMode::HEALTH_UP; - case AirflowVerticalDirection::MAX_UP: - return hon_protocol::VerticalSwingMode::MAX_UP; - case AirflowVerticalDirection::UP: - return hon_protocol::VerticalSwingMode::UP; - case AirflowVerticalDirection::DOWN: - return hon_protocol::VerticalSwingMode::DOWN; - case AirflowVerticalDirection::HEALTH_DOWN: - return hon_protocol::VerticalSwingMode::HEALTH_DOWN; - default: - return hon_protocol::VerticalSwingMode::CENTER; - } -} - -hon_protocol::HorizontalSwingMode get_horizontal_swing_mode(AirflowHorizontalDirection direction) { - switch (direction) { - case AirflowHorizontalDirection::MAX_LEFT: - return hon_protocol::HorizontalSwingMode::MAX_LEFT; - case AirflowHorizontalDirection::LEFT: - return hon_protocol::HorizontalSwingMode::LEFT; - case AirflowHorizontalDirection::RIGHT: - return hon_protocol::HorizontalSwingMode::RIGHT; - case AirflowHorizontalDirection::MAX_RIGHT: - return hon_protocol::HorizontalSwingMode::MAX_RIGHT; - default: - return hon_protocol::HorizontalSwingMode::CENTER; - } -} - HonClimate::HonClimate() : cleaning_status_(CleaningState::NO_CLEANING), got_valid_outdoor_temp_(false), active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -66,17 +34,21 @@ void HonClimate::set_beeper_state(bool state) { this->beeper_status_ = state; } bool HonClimate::get_beeper_state() const { return this->beeper_status_; } -AirflowVerticalDirection HonClimate::get_vertical_airflow() const { return this->vertical_direction_; }; +esphome::optional HonClimate::get_vertical_airflow() const { + return this->current_vertical_swing_; +}; -void HonClimate::set_vertical_airflow(AirflowVerticalDirection direction) { - this->vertical_direction_ = direction; +void HonClimate::set_vertical_airflow(hon_protocol::VerticalSwingMode direction) { + this->pending_vertical_direction_ = direction; this->force_send_control_ = true; } -AirflowHorizontalDirection HonClimate::get_horizontal_airflow() const { return this->horizontal_direction_; } +esphome::optional HonClimate::get_horizontal_airflow() const { + return this->current_horizontal_swing_; +} -void HonClimate::set_horizontal_airflow(AirflowHorizontalDirection direction) { - this->horizontal_direction_ = direction; +void HonClimate::set_horizontal_airflow(hon_protocol::HorizontalSwingMode direction) { + this->pending_horizontal_direction_ = direction; this->force_send_control_ = true; } @@ -148,6 +120,11 @@ haier_protocol::HandlerError HonClimate::get_device_version_answer_handler_(haie this->hvac_hardware_info_.value().hardware_version_ = std::string(tmp); strncpy(tmp, answr->device_name, 8); this->hvac_hardware_info_.value().device_name_ = std::string(tmp); +#ifdef USE_TEXT_SENSOR + this->update_sub_text_sensor_(SubTextSensorType::APPLIANCE_NAME, this->hvac_hardware_info_.value().device_name_); + this->update_sub_text_sensor_(SubTextSensorType::PROTOCOL_VERSION, + this->hvac_hardware_info_.value().protocol_version_); +#endif this->hvac_hardware_info_.value().functions_[0] = (answr->functions[1] & 0x01) != 0; // interactive mode support this->hvac_hardware_info_.value().functions_[1] = (answr->functions[1] & 0x02) != 0; // controller-device mode support @@ -488,6 +465,19 @@ haier_protocol::HaierMessage HonClimate::get_power_message(bool state) { } } +void HonClimate::initialization() { + constexpr uint32_t restore_settings_version = 0xE834D8DCUL; + this->rtc_ = global_preferences->make_preference(this->get_object_id_hash() ^ restore_settings_version); + HonSettings recovered; + if (this->rtc_.load(&recovered)) { + this->settings_ = recovered; + } else { + this->settings_ = {hon_protocol::VerticalSwingMode::CENTER, hon_protocol::HorizontalSwingMode::CENTER}; + } + this->current_vertical_swing_ = this->settings_.last_vertiacal_swing; + this->current_horizontal_swing_ = this->settings_.last_horizontal_swing; +} + haier_protocol::HaierMessage HonClimate::get_control_message() { uint8_t control_out_buffer[sizeof(hon_protocol::HaierPacketControl)]; memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(hon_protocol::HaierPacketControl)); @@ -560,16 +550,16 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { if (climate_control.swing_mode.has_value()) { switch (climate_control.swing_mode.value()) { case CLIMATE_SWING_OFF: - out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); - out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); + out_data->horizontal_swing_mode = (uint8_t) this->settings_.last_horizontal_swing; + out_data->vertical_swing_mode = (uint8_t) this->settings_.last_vertiacal_swing; break; case CLIMATE_SWING_VERTICAL: - out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); + out_data->horizontal_swing_mode = (uint8_t) this->settings_.last_horizontal_swing; out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::AUTO; break; case CLIMATE_SWING_HORIZONTAL: out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::AUTO; - out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); + out_data->vertical_swing_mode = (uint8_t) this->settings_.last_vertiacal_swing; break; case CLIMATE_SWING_BOTH: out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::AUTO; @@ -631,11 +621,14 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { break; } } - } else { - if (out_data->vertical_swing_mode != (uint8_t) hon_protocol::VerticalSwingMode::AUTO) - out_data->vertical_swing_mode = (uint8_t) get_vertical_swing_mode(this->vertical_direction_); - if (out_data->horizontal_swing_mode != (uint8_t) hon_protocol::HorizontalSwingMode::AUTO) - out_data->horizontal_swing_mode = (uint8_t) get_horizontal_swing_mode(this->horizontal_direction_); + } + if (this->pending_vertical_direction_.has_value()) { + out_data->vertical_swing_mode = (uint8_t) this->pending_vertical_direction_.value(); + this->pending_vertical_direction_.reset(); + } + if (this->pending_horizontal_direction_.has_value()) { + out_data->horizontal_swing_mode = (uint8_t) this->pending_horizontal_direction_.value(); + this->pending_horizontal_direction_.reset(); } out_data->beeper_status = ((!this->beeper_status_) || (!has_hvac_settings)) ? 1 : 0; control_out_buffer[4] = 0; // This byte should be cleared before setting values @@ -737,6 +730,33 @@ void HonClimate::update_sub_binary_sensor_(SubBinarySensorType type, uint8_t val } #endif // USE_BINARY_SENSOR +#ifdef USE_TEXT_SENSOR +void HonClimate::set_sub_text_sensor(SubTextSensorType type, text_sensor::TextSensor *sens) { + this->sub_text_sensors_[(size_t) type] = sens; + switch (type) { + case SubTextSensorType::APPLIANCE_NAME: + if (this->hvac_hardware_info_.has_value()) + sens->publish_state(this->hvac_hardware_info_.value().device_name_); + break; + case SubTextSensorType::PROTOCOL_VERSION: + if (this->hvac_hardware_info_.has_value()) + sens->publish_state(this->hvac_hardware_info_.value().protocol_version_); + break; + case SubTextSensorType::CLEANING_STATUS: + sens->publish_state(this->get_cleaning_status_text()); + break; + default: + break; + } +} + +void HonClimate::update_sub_text_sensor_(SubTextSensorType type, const std::string &value) { + size_t index = (size_t) type; + if (this->sub_text_sensors_[index] != nullptr) + this->sub_text_sensors_[index]->publish_state(value); +} +#endif // USE_TEXT_SENSOR + haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { size_t expected_size = 2 + sizeof(hon_protocol::HaierPacketControl) + sizeof(hon_protocol::HaierPacketSensors) + this->extra_control_packet_bytes_; @@ -896,6 +916,9 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * PendingAction({ActionRequest::TURN_POWER_OFF, esphome::optional()}); } this->cleaning_status_ = new_cleaning; +#ifdef USE_TEXT_SENSOR + this->update_sub_text_sensor_(SubTextSensorType::CLEANING_STATUS, this->get_cleaning_status_text()); +#endif // USE_TEXT_SENSOR } } { @@ -941,6 +964,19 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * this->swing_mode = CLIMATE_SWING_OFF; } } + // Saving last known non auto mode for vertical and horizontal swing + this->current_vertical_swing_ = (hon_protocol::VerticalSwingMode) packet.control.vertical_swing_mode; + this->current_horizontal_swing_ = (hon_protocol::HorizontalSwingMode) packet.control.horizontal_swing_mode; + bool save_settings = ((this->current_vertical_swing_.value() != hon_protocol::VerticalSwingMode::AUTO) && + (this->current_vertical_swing_.value() != hon_protocol::VerticalSwingMode::AUTO_SPECIAL) && + (this->current_vertical_swing_.value() != this->settings_.last_vertiacal_swing)) || + ((this->current_horizontal_swing_.value() != hon_protocol::HorizontalSwingMode::AUTO) && + (this->current_horizontal_swing_.value() != this->settings_.last_horizontal_swing)); + if (save_settings) { + this->settings_.last_vertiacal_swing = this->current_vertical_swing_.value(); + this->settings_.last_horizontal_swing = this->current_horizontal_swing_.value(); + this->rtc_.save(&this->settings_); + } should_publish = should_publish || (old_swing_mode != this->swing_mode); } this->last_valid_status_timestamp_ = std::chrono::steady_clock::now(); diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index c4fae20a98..7b4fcee6b9 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -7,29 +7,16 @@ #ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" #endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif #include "esphome/core/automation.h" #include "haier_base.h" +#include "hon_packet.h" namespace esphome { namespace haier { -enum class AirflowVerticalDirection : uint8_t { - HEALTH_UP = 0, - MAX_UP = 1, - UP = 2, - CENTER = 3, - DOWN = 4, - HEALTH_DOWN = 5, -}; - -enum class AirflowHorizontalDirection : uint8_t { - MAX_LEFT = 0, - LEFT = 1, - CENTER = 2, - RIGHT = 3, - MAX_RIGHT = 4, -}; - enum class CleaningState : uint8_t { NO_CLEANING = 0, SELF_CLEAN = 1, @@ -38,6 +25,11 @@ enum class CleaningState : uint8_t { enum class HonControlMethod { MONITOR_ONLY = 0, SET_GROUP_PARAMETERS, SET_SINGLE_PARAMETER }; +struct HonSettings { + hon_protocol::VerticalSwingMode last_vertiacal_swing; + hon_protocol::HorizontalSwingMode last_horizontal_swing; +}; + class HonClimate : public HaierClimateBase { #ifdef USE_SENSOR public: @@ -80,6 +72,20 @@ class HonClimate : public HaierClimateBase { protected: void update_sub_binary_sensor_(SubBinarySensorType type, uint8_t value); binary_sensor::BinarySensor *sub_binary_sensors_[(size_t) SubBinarySensorType::SUB_BINARY_SENSOR_TYPE_COUNT]{nullptr}; +#endif +#ifdef USE_TEXT_SENSOR + public: + enum class SubTextSensorType { + CLEANING_STATUS = 0, + PROTOCOL_VERSION, + APPLIANCE_NAME, + SUB_TEXT_SENSOR_TYPE_COUNT, + }; + void set_sub_text_sensor(SubTextSensorType type, text_sensor::TextSensor *sens); + + protected: + void update_sub_text_sensor_(SubTextSensorType type, const std::string &value); + text_sensor::TextSensor *sub_text_sensors_[(size_t) SubTextSensorType::SUB_TEXT_SENSOR_TYPE_COUNT]{nullptr}; #endif public: HonClimate(); @@ -89,10 +95,10 @@ class HonClimate : public HaierClimateBase { void dump_config() override; void set_beeper_state(bool state); bool get_beeper_state() const; - AirflowVerticalDirection get_vertical_airflow() const; - void set_vertical_airflow(AirflowVerticalDirection direction); - AirflowHorizontalDirection get_horizontal_airflow() const; - void set_horizontal_airflow(AirflowHorizontalDirection direction); + esphome::optional get_vertical_airflow() const; + void set_vertical_airflow(hon_protocol::VerticalSwingMode direction); + esphome::optional get_horizontal_airflow() const; + void set_horizontal_airflow(hon_protocol::HorizontalSwingMode direction); std::string get_cleaning_status_text() const; CleaningState get_cleaning_status() const; void start_self_cleaning(); @@ -108,6 +114,7 @@ class HonClimate : public HaierClimateBase { void process_phase(std::chrono::steady_clock::time_point now) override; haier_protocol::HaierMessage get_control_message() override; haier_protocol::HaierMessage get_power_message(bool state) override; + void initialization() override; bool prepare_pending_action() override; void process_protocol_reset() override; bool should_get_big_data_(); @@ -147,9 +154,9 @@ class HonClimate : public HaierClimateBase { bool beeper_status_; CleaningState cleaning_status_; bool got_valid_outdoor_temp_; - AirflowVerticalDirection vertical_direction_; - AirflowHorizontalDirection horizontal_direction_; - esphome::optional hvac_hardware_info_; + esphome::optional pending_vertical_direction_{}; + esphome::optional pending_horizontal_direction_{}; + esphome::optional hvac_hardware_info_{}; uint8_t active_alarms_[8]; int extra_control_packet_bytes_; HonControlMethod control_method_; @@ -159,6 +166,10 @@ class HonClimate : public HaierClimateBase { float active_alarm_count_{NAN}; std::chrono::steady_clock::time_point last_alarm_request_; int big_data_sensors_{0}; + esphome::optional current_vertical_swing_{}; + esphome::optional current_horizontal_swing_{}; + HonSettings settings_; + ESPPreferenceObject rtc_; }; class HaierAlarmStartTrigger : public Trigger { diff --git a/esphome/components/haier/hon_packet.h b/esphome/components/haier/hon_packet.h index bbca7bb653..a03ac2831f 100644 --- a/esphome/components/haier/hon_packet.h +++ b/esphome/components/haier/hon_packet.h @@ -13,7 +13,10 @@ enum class VerticalSwingMode : uint8_t { UP = 0x04, CENTER = 0x06, DOWN = 0x08, - AUTO = 0x0C + MAX_DOWN = 0x0A, + AUTO = 0x0C, + // Auto for special modes + AUTO_SPECIAL = 0x0E }; enum class HorizontalSwingMode : uint8_t { diff --git a/esphome/components/haier/sensor/__init__.py b/esphome/components/haier/sensor/__init__.py index 01f997baa5..b2717631e0 100644 --- a/esphome/components/haier/sensor/__init__.py +++ b/esphome/components/haier/sensor/__init__.py @@ -31,6 +31,7 @@ from ..climate import ( HonClimate, ) +CODEOWNERS = ["@paveldn"] SensorTypeEnum = HonClimate.enum("SubSensorType", True) # Haier sensors diff --git a/esphome/components/haier/text_sensor/__init__.py b/esphome/components/haier/text_sensor/__init__.py new file mode 100644 index 0000000000..528b70d83e --- /dev/null +++ b/esphome/components/haier/text_sensor/__init__.py @@ -0,0 +1,54 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import ( + ENTITY_CATEGORY_DIAGNOSTIC, + ENTITY_CATEGORY_NONE, +) +from ..climate import ( + CONF_HAIER_ID, + HonClimate, +) + +CODEOWNERS = ["@paveldn"] +TextSensorTypeEnum = HonClimate.enum("SubTextSensorType", True) + +# Haier text sensors +CONF_CLEANING_STATUS = "cleaning_status" +CONF_PROTOCOL_VERSION = "protocol_version" +CONF_APPLIANCE_NAME = "appliance_name" + +# Additional icons +ICON_SPRAY_BOTTLE = "mdi:spray-bottle" +ICON_TEXT_BOX = "mdi:text-box-outline" + +TEXT_SENSOR_TYPES = { + CONF_CLEANING_STATUS: text_sensor.text_sensor_schema( + icon=ICON_SPRAY_BOTTLE, + entity_category=ENTITY_CATEGORY_NONE, + ), + CONF_PROTOCOL_VERSION: text_sensor.text_sensor_schema( + icon=ICON_TEXT_BOX, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + CONF_APPLIANCE_NAME: text_sensor.text_sensor_schema( + icon=ICON_TEXT_BOX, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + +CONFIG_SCHEMA = cv.Schema( + { + cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + } +).extend({cv.Optional(type): schema for type, schema in TEXT_SENSOR_TYPES.items()}) + + +async def to_code(config): + paren = await cg.get_variable(config[CONF_HAIER_ID]) + + for type, _ in TEXT_SENSOR_TYPES.items(): + if conf := config.get(type): + sens = await text_sensor.new_text_sensor(conf) + text_sensor_type = getattr(TextSensorTypeEnum, type.upper()) + cg.add(paren.set_sub_text_sensor(text_sensor_type, sens)) diff --git a/platformio.ini b/platformio.ini index d342b32b02..65c742cf91 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,7 +39,7 @@ lib_deps = bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 - pavlodn/HaierProtocol@0.9.25 ; haier + pavlodn/HaierProtocol@0.9.28 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library build_flags = diff --git a/tests/components/haier/test.esp32-c3-idf.yaml b/tests/components/haier/test.esp32-c3-idf.yaml index 72cfb781a7..fed573bd1d 100644 --- a/tests/components/haier/test.esp32-c3-idf.yaml +++ b/tests/components/haier/test.esp32-c3-idf.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.esp32-c3.yaml b/tests/components/haier/test.esp32-c3.yaml index 72cfb781a7..fed573bd1d 100644 --- a/tests/components/haier/test.esp32-c3.yaml +++ b/tests/components/haier/test.esp32-c3.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.esp32-idf.yaml b/tests/components/haier/test.esp32-idf.yaml index d3eeb04d65..efff532d25 100644 --- a/tests/components/haier/test.esp32-idf.yaml +++ b/tests/components/haier/test.esp32-idf.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.esp32.yaml b/tests/components/haier/test.esp32.yaml index d3eeb04d65..efff532d25 100644 --- a/tests/components/haier/test.esp32.yaml +++ b/tests/components/haier/test.esp32.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.esp8266.yaml b/tests/components/haier/test.esp8266.yaml index 72cfb781a7..fed573bd1d 100644 --- a/tests/components/haier/test.esp8266.yaml +++ b/tests/components/haier/test.esp8266.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.rp2040.yaml b/tests/components/haier/test.rp2040.yaml index 72cfb781a7..fed573bd1d 100644 --- a/tests/components/haier/test.rp2040.yaml +++ b/tests/components/haier/test.rp2040.yaml @@ -93,3 +93,21 @@ binary_sensor: name: Haier Indoor Fan Status outdoor_fan_status: name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version From c2d67659f3a2bca35cc5ca97708470c9e9f46fd5 Mon Sep 17 00:00:00 2001 From: polyfloyd Date: Thu, 23 May 2024 23:08:28 +0200 Subject: [PATCH 1797/2607] mpr121: Add GPIO support (#6776) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mpr121/__init__.py | 88 ++++++++++++++++++- .../__init__.py} | 7 +- .../binary_sensor/mpr121_binary_sensor.cpp | 20 +++++ .../binary_sensor/mpr121_binary_sensor.h | 26 ++++++ esphome/components/mpr121/mpr121.cpp | 87 ++++++++++++++++-- esphome/components/mpr121/mpr121.h | 68 ++++++++++---- tests/components/mpr121/common.yaml | 41 +++++++++ .../components/mpr121/test.esp32-c3-idf.yaml | 29 +----- tests/components/mpr121/test.esp32-c3.yaml | 29 +----- tests/components/mpr121/test.esp32-idf.yaml | 29 +----- tests/components/mpr121/test.esp32.yaml | 29 +----- tests/components/mpr121/test.esp8266.yaml | 29 +----- tests/components/mpr121/test.rp2040.yaml | 29 +----- tests/test3.1.yaml | 27 ------ 14 files changed, 332 insertions(+), 206 deletions(-) rename esphome/components/mpr121/{binary_sensor.py => binary_sensor/__init__.py} (82%) create mode 100644 esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.cpp create mode 100644 esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.h create mode 100644 tests/components/mpr121/common.yaml diff --git a/esphome/components/mpr121/__init__.py b/esphome/components/mpr121/__init__.py index dabfb47ad6..1f8e804e88 100644 --- a/esphome/components/mpr121/__init__.py +++ b/esphome/components/mpr121/__init__.py @@ -1,19 +1,32 @@ import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv +from esphome import pins from esphome.components import i2c -from esphome.const import CONF_ID +from esphome.const import ( + CONF_BINARY_SENSOR, + CONF_CHANNEL, + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, +) CONF_TOUCH_THRESHOLD = "touch_threshold" CONF_RELEASE_THRESHOLD = "release_threshold" CONF_TOUCH_DEBOUNCE = "touch_debounce" CONF_RELEASE_DEBOUNCE = "release_debounce" +CONF_MAX_TOUCH_CHANNEL = "max_touch_channel" +CONF_MPR121 = "mpr121" +CONF_MPR121_ID = "mpr121_id" DEPENDENCIES = ["i2c"] -AUTO_LOAD = ["binary_sensor"] mpr121_ns = cg.esphome_ns.namespace("mpr121") -CONF_MPR121_ID = "mpr121_id" MPR121Component = mpr121_ns.class_("MPR121Component", cg.Component, i2c.I2CDevice) +MPR121GPIOPin = mpr121_ns.class_("MPR121GPIOPin", cg.GPIOPin) MULTI_CONF = True CONFIG_SCHEMA = ( @@ -28,6 +41,7 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_RELEASE_THRESHOLD, default=0x06): cv.int_range( min=0x05, max=0x30 ), + cv.Optional(CONF_MAX_TOUCH_CHANNEL): cv.int_range(min=3, max=11), } ) .extend(cv.COMPONENT_SCHEMA) @@ -35,11 +49,79 @@ CONFIG_SCHEMA = ( ) +def _final_validate(config): + fconf = fv.full_config.get() + max_touch_channel = 3 + if (binary_sensors := fconf.get(CONF_BINARY_SENSOR)) is not None: + for binary_sensor in binary_sensors: + if binary_sensor.get(CONF_MPR121_ID) == config[CONF_ID]: + max_touch_channel = max(max_touch_channel, binary_sensor[CONF_CHANNEL]) + if max_touch_channel_in_config := config.get(CONF_MAX_TOUCH_CHANNEL): + if max_touch_channel != max_touch_channel_in_config: + raise cv.Invalid( + "Max touch channel must equal the highest binary sensor channel or be removed for auto calculation", + path=[CONF_MAX_TOUCH_CHANNEL], + ) + path = fconf.get_path_for_id(config[CONF_ID])[:-1] + this_config = fconf.get_config_for_path(path) + this_config[CONF_MAX_TOUCH_CHANNEL] = max_touch_channel + + +FINAL_VALIDATE_SCHEMA = _final_validate + + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_touch_debounce(config[CONF_TOUCH_DEBOUNCE])) cg.add(var.set_release_debounce(config[CONF_RELEASE_DEBOUNCE])) cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) cg.add(var.set_release_threshold(config[CONF_RELEASE_THRESHOLD])) + cg.add(var.set_max_touch_channel(config[CONF_MAX_TOUCH_CHANNEL])) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) + + +def validate_mode(value): + if bool(value[CONF_INPUT]) == bool(value[CONF_OUTPUT]): + raise cv.Invalid("Mode must be either input or output") + return value + + +# https://www.nxp.com/docs/en/data-sheet/MPR121.pdf, page 4 +# +# Among the 12 electrode inputs, 8 inputs are designed as multifunctional pins. When these pins are +# not configured as electrodes, they may be used to drive LEDs or used for general purpose input or +# output. +MPR121_GPIO_PIN_SCHEMA = pins.gpio_base_schema( + MPR121GPIOPin, + cv.int_range(min=4, max=11), + modes=[CONF_INPUT, CONF_OUTPUT], + mode_validator=validate_mode, +).extend( + { + cv.Required(CONF_MPR121): cv.use_id(MPR121Component), + } +) + + +def mpr121_pin_final_validate(pin_config, parent_config): + if pin_config[CONF_NUMBER] <= parent_config[CONF_MAX_TOUCH_CHANNEL]: + raise cv.Invalid( + "Pin number must be higher than the max touch channel of the MPR121 component", + ) + + +@pins.PIN_SCHEMA_REGISTRY.register( + CONF_MPR121, MPR121_GPIO_PIN_SCHEMA, mpr121_pin_final_validate +) +async def mpr121_gpio_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_MPR121]) + + cg.add(var.set_parent(parent)) + + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/mpr121/binary_sensor.py b/esphome/components/mpr121/binary_sensor/__init__.py similarity index 82% rename from esphome/components/mpr121/binary_sensor.py rename to esphome/components/mpr121/binary_sensor/__init__.py index 131fbcfc5b..292c631c37 100644 --- a/esphome/components/mpr121/binary_sensor.py +++ b/esphome/components/mpr121/binary_sensor/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor from esphome.const import CONF_CHANNEL -from . import ( +from .. import ( mpr121_ns, MPR121Component, CONF_MPR121_ID, @@ -11,9 +11,9 @@ from . import ( ) DEPENDENCIES = ["mpr121"] -MPR121Channel = mpr121_ns.class_("MPR121Channel", binary_sensor.BinarySensor) +MPR121BinarySensor = mpr121_ns.class_("MPR121BinarySensor", binary_sensor.BinarySensor) -CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(MPR121Channel).extend( +CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(MPR121BinarySensor).extend( { cv.GenerateID(CONF_MPR121_ID): cv.use_id(MPR121Component), cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=11), @@ -27,6 +27,7 @@ async def to_code(config): var = await binary_sensor.new_binary_sensor(config) hub = await cg.get_variable(config[CONF_MPR121_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) + cg.register_parented(var, hub) if CONF_TOUCH_THRESHOLD in config: cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) diff --git a/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.cpp b/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.cpp new file mode 100644 index 0000000000..dce0e73b9a --- /dev/null +++ b/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.cpp @@ -0,0 +1,20 @@ +#include "mpr121_binary_sensor.h" + +namespace esphome { +namespace mpr121 { + +void MPR121BinarySensor::setup() { + uint8_t touch_threshold = this->touch_threshold_.value_or(this->parent_->get_touch_threshold()); + this->parent_->write_byte(MPR121_TOUCHTH_0 + 2 * this->channel_, touch_threshold); + + uint8_t release_threshold = this->release_threshold_.value_or(this->parent_->get_release_threshold()); + this->parent_->write_byte(MPR121_RELEASETH_0 + 2 * this->channel_, release_threshold); +} + +void MPR121BinarySensor::process(uint16_t data) { + bool new_state = data & (1 << this->channel_); + this->publish_state(new_state); +} + +} // namespace mpr121 +} // namespace esphome diff --git a/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.h b/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.h new file mode 100644 index 0000000000..577ba82893 --- /dev/null +++ b/esphome/components/mpr121/binary_sensor/mpr121_binary_sensor.h @@ -0,0 +1,26 @@ +#pragma once + +#include "esphome/components/binary_sensor/binary_sensor.h" + +#include "../mpr121.h" + +namespace esphome { +namespace mpr121 { + +class MPR121BinarySensor : public binary_sensor::BinarySensor, public MPR121Channel, public Parented { + public: + void set_channel(uint8_t channel) { this->channel_ = channel; } + void set_touch_threshold(uint8_t touch_threshold) { this->touch_threshold_ = touch_threshold; }; + void set_release_threshold(uint8_t release_threshold) { this->release_threshold_ = release_threshold; }; + + void setup() override; + void process(uint16_t data) override; + + protected: + uint8_t channel_{0}; + optional touch_threshold_{}; + optional release_threshold_{}; +}; + +} // namespace mpr121 +} // namespace esphome diff --git a/esphome/components/mpr121/mpr121.cpp b/esphome/components/mpr121/mpr121.cpp index 7ba3da7b4d..de364c59ff 100644 --- a/esphome/components/mpr121/mpr121.cpp +++ b/esphome/components/mpr121/mpr121.cpp @@ -1,6 +1,9 @@ #include "mpr121.h" -#include "esphome/core/log.h" + +#include + #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace mpr121 { @@ -20,10 +23,7 @@ void MPR121Component::setup() { // set touch sensitivity for all 12 channels for (auto *channel : this->channels_) { - this->write_byte(MPR121_TOUCHTH_0 + 2 * channel->channel_, - channel->touch_threshold_.value_or(this->touch_threshold_)); - this->write_byte(MPR121_RELEASETH_0 + 2 * channel->channel_, - channel->release_threshold_.value_or(this->release_threshold_)); + channel->setup(); } this->write_byte(MPR121_MHDR, 0x01); this->write_byte(MPR121_NHDR, 0x01); @@ -44,8 +44,15 @@ void MPR121Component::setup() { this->write_byte(MPR121_CONFIG1, 0x10); // 0.5uS encoding, 1ms period this->write_byte(MPR121_CONFIG2, 0x20); - // start with first 5 bits of baseline tracking - this->write_byte(MPR121_ECR, 0x8F); + + // Write the Electrode Configuration Register + // * Highest 2 bits is "Calibration Lock", which we set to a value corresponding to 5 bits. + // * The 2 bits below is "Proximity Enable" and are left at 0. + // * The 4 least significant bits control how many electrodes are enabled. Electrodes are enabled + // as a range, starting at 0 up to the highest channel index used. + this->write_byte(MPR121_ECR, 0x80 | (this->max_touch_channel_ + 1)); + + this->flush_gpio_(); } void MPR121Component::set_touch_debounce(uint8_t debounce) { @@ -86,6 +93,72 @@ void MPR121Component::loop() { for (auto *channel : this->channels_) channel->process(val); + + this->read_byte(MPR121_GPIODATA, &this->gpio_input_); +} + +bool MPR121Component::digital_read(uint8_t ionum) { return (this->gpio_input_ & (1 << ionum)) != 0; } + +void MPR121Component::digital_write(uint8_t ionum, bool value) { + if (value) { + this->gpio_output_ |= (1 << ionum); + } else { + this->gpio_output_ &= ~(1 << ionum); + } + this->flush_gpio_(); +} + +void MPR121Component::pin_mode(uint8_t ionum, gpio::Flags flags) { + this->gpio_enable_ |= (1 << ionum); + if (flags & gpio::FLAG_INPUT) { + this->gpio_direction_ &= ~(1 << ionum); + } else if (flags & gpio::FLAG_OUTPUT) { + this->gpio_direction_ |= 1 << ionum; + } + this->flush_gpio_(); +} + +bool MPR121Component::flush_gpio_() { + if (this->is_failed()) { + return false; + } + + // TODO: The CTL registers can configure internal pullup/pulldown resistors. + this->write_byte(MPR121_GPIOCTL0, 0x00); + this->write_byte(MPR121_GPIOCTL1, 0x00); + this->write_byte(MPR121_GPIOEN, this->gpio_enable_); + this->write_byte(MPR121_GPIODIR, this->gpio_direction_); + + if (!this->write_byte(MPR121_GPIODATA, this->gpio_output_)) { + this->status_set_warning(); + return false; + } + + this->status_clear_warning(); + return true; +} + +void MPR121GPIOPin::setup() { this->pin_mode(this->flags_); } + +void MPR121GPIOPin::pin_mode(gpio::Flags flags) { + assert(this->pin_ >= 4); + this->parent_->pin_mode(this->pin_ - 4, flags); +} + +bool MPR121GPIOPin::digital_read() { + assert(this->pin_ >= 4); + return this->parent_->digital_read(this->pin_ - 4) != this->inverted_; +} + +void MPR121GPIOPin::digital_write(bool value) { + assert(this->pin_ >= 4); + this->parent_->digital_write(this->pin_ - 4, value != this->inverted_); +} + +std::string MPR121GPIOPin::dump_summary() const { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "ELE%u on MPR121", this->pin_); + return buffer; } } // namespace mpr121 diff --git a/esphome/components/mpr121/mpr121.h b/esphome/components/mpr121/mpr121.h index 8b7735fa28..f2dc2fe9c9 100644 --- a/esphome/components/mpr121/mpr121.h +++ b/esphome/components/mpr121/mpr121.h @@ -1,8 +1,10 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" + #include "esphome/components/i2c/i2c.h" -#include "esphome/components/binary_sensor/binary_sensor.h" #include @@ -39,6 +41,9 @@ enum { MPR121_UPLIMIT = 0x7D, MPR121_LOWLIMIT = 0x7E, MPR121_TARGETLIMIT = 0x7F, + MPR121_GPIOCTL0 = 0x73, + MPR121_GPIOCTL1 = 0x74, + MPR121_GPIODATA = 0x75, MPR121_GPIODIR = 0x76, MPR121_GPIOEN = 0x77, MPR121_GPIOSET = 0x78, @@ -47,19 +52,10 @@ enum { MPR121_SOFTRESET = 0x80, }; -class MPR121Channel : public binary_sensor::BinarySensor { - friend class MPR121Component; - +class MPR121Channel { public: - void set_channel(uint8_t channel) { channel_ = channel; } - void process(uint16_t data) { this->publish_state(static_cast(data & (1 << this->channel_))); } - void set_touch_threshold(uint8_t touch_threshold) { this->touch_threshold_ = touch_threshold; }; - void set_release_threshold(uint8_t release_threshold) { this->release_threshold_ = release_threshold; }; - - protected: - uint8_t channel_{0}; - optional touch_threshold_{}; - optional release_threshold_{}; + virtual void setup() = 0; + virtual void process(uint16_t data) = 0; }; class MPR121Component : public Component, public i2c::I2CDevice { @@ -69,23 +65,63 @@ class MPR121Component : public Component, public i2c::I2CDevice { void set_release_debounce(uint8_t debounce); void set_touch_threshold(uint8_t touch_threshold) { this->touch_threshold_ = touch_threshold; }; void set_release_threshold(uint8_t release_threshold) { this->release_threshold_ = release_threshold; }; - uint8_t get_touch_threshold() { return this->touch_threshold_; }; - uint8_t get_release_threshold() { return this->release_threshold_; }; + uint8_t get_touch_threshold() const { return this->touch_threshold_; }; + uint8_t get_release_threshold() const { return this->release_threshold_; }; void setup() override; void dump_config() override; - float get_setup_priority() const override { return setup_priority::DATA; } + float get_setup_priority() const override { return setup_priority::IO; } void loop() override; + void set_max_touch_channel(uint8_t max_touch_channel) { this->max_touch_channel_ = max_touch_channel; } + + // GPIO helper functions. + bool digital_read(uint8_t ionum); + void digital_write(uint8_t ionum, bool value); + void pin_mode(uint8_t ionum, gpio::Flags flags); + protected: std::vector channels_{}; uint8_t debounce_{0}; uint8_t touch_threshold_{}; uint8_t release_threshold_{}; + uint8_t max_touch_channel_{3}; enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, WRONG_CHIP_STATE, } error_code_{NONE}; + + bool flush_gpio_(); + + /// The enable mask - zero means high Z, 1 means GPIO usage + uint8_t gpio_enable_{0x00}; + /// Mask for the pin mode - 1 means output, 0 means input + uint8_t gpio_direction_{0x00}; + /// The mask to write as output state - 1 means HIGH, 0 means LOW + uint8_t gpio_output_{0x00}; + /// The mask to read as input state - 1 means HIGH, 0 means LOW + uint8_t gpio_input_{0x00}; +}; + +/// Helper class to expose a MPR121 pin as an internal input GPIO pin. +class MPR121GPIOPin : public GPIOPin { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + std::string dump_summary() const override; + + void set_parent(MPR121Component *parent) { this->parent_ = parent; } + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } + + protected: + MPR121Component *parent_; + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; }; } // namespace mpr121 diff --git a/tests/components/mpr121/common.yaml b/tests/components/mpr121/common.yaml new file mode 100644 index 0000000000..fcf61b57f3 --- /dev/null +++ b/tests/components/mpr121/common.yaml @@ -0,0 +1,41 @@ +i2c: + - id: i2c_mpr121 + scl: ${i2c_scl} + sda: ${i2c_sda} + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: mpr121 + id: touchkey0 + name: touchkey0 + channel: 0 + - platform: mpr121 + id: bin1 + name: touchkey1 + channel: 1 + - platform: mpr121 + id: bin2 + name: touchkey2 + channel: 2 + - platform: mpr121 + id: bin3 + name: touchkey3 + channel: 6 + +output: + - platform: gpio + id: gpio1 + pin: + mpr121: mpr121_first + number: 7 + mode: OUTPUT + - platform: gpio + id: gpio2 + pin: + mpr121: mpr121_first + number: 11 + mode: OUTPUT + inverted: true diff --git a/tests/components/mpr121/test.esp32-c3-idf.yaml b/tests/components/mpr121/test.esp32-c3-idf.yaml index 517e092560..d7ae0d5161 100644 --- a/tests/components/mpr121/test.esp32-c3-idf.yaml +++ b/tests/components/mpr121/test.esp32-c3-idf.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/components/mpr121/test.esp32-c3.yaml b/tests/components/mpr121/test.esp32-c3.yaml index 517e092560..d7ae0d5161 100644 --- a/tests/components/mpr121/test.esp32-c3.yaml +++ b/tests/components/mpr121/test.esp32-c3.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/components/mpr121/test.esp32-idf.yaml b/tests/components/mpr121/test.esp32-idf.yaml index 96996fd8ee..1037d5d35b 100644 --- a/tests/components/mpr121/test.esp32-idf.yaml +++ b/tests/components/mpr121/test.esp32-idf.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 16 - sda: 17 +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/components/mpr121/test.esp32.yaml b/tests/components/mpr121/test.esp32.yaml index 96996fd8ee..1037d5d35b 100644 --- a/tests/components/mpr121/test.esp32.yaml +++ b/tests/components/mpr121/test.esp32.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 16 - sda: 17 +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/components/mpr121/test.esp8266.yaml b/tests/components/mpr121/test.esp8266.yaml index 517e092560..d7ae0d5161 100644 --- a/tests/components/mpr121/test.esp8266.yaml +++ b/tests/components/mpr121/test.esp8266.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/components/mpr121/test.rp2040.yaml b/tests/components/mpr121/test.rp2040.yaml index 517e092560..d7ae0d5161 100644 --- a/tests/components/mpr121/test.rp2040.yaml +++ b/tests/components/mpr121/test.rp2040.yaml @@ -1,26 +1,5 @@ -i2c: - - id: i2c_mpr121 - scl: 5 - sda: 4 +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 -mpr121: - id: mpr121_first - address: 0x5A - -binary_sensor: - - platform: mpr121 - id: touchkey0 - name: touchkey0 - channel: 0 - - platform: mpr121 - id: bin1 - name: touchkey1 - channel: 1 - - platform: mpr121 - id: bin2 - name: touchkey2 - channel: 2 - - platform: mpr121 - id: bin3 - name: touchkey3 - channel: 3 +<<: !include common.yaml diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index a7d8dcb3f4..018a4d94f3 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -344,10 +344,6 @@ apds9960: address: 0x20 update_interval: 60s -mpr121: - id: mpr121_first - address: 0x5A - binary_sensor: - platform: apds9960 direction: up @@ -371,25 +367,6 @@ binary_sensor: direction: right name: APDS9960 Right - - platform: mpr121 - id: touchkey0 - channel: 0 - name: touchkey0 - - platform: mpr121 - channel: 1 - name: touchkey1 - id: bin1 - - platform: mpr121 - channel: 2 - name: touchkey2 - id: bin2 - - platform: mpr121 - channel: 3 - name: touchkey3 - id: bin3 - on_press: - then: - - switch.toggle: mpr121_toggle - platform: ttp229_lsf channel: 1 name: TTP229 LSF Test @@ -443,10 +420,6 @@ grove_tb6612fng: address: 0x14 switch: - - platform: template - name: mpr121_toggle - id: mpr121_toggle - optimistic: true - platform: gpio id: gpio_switch1 pin: From 9d03f472335be2c696547c8484421dba8252f145 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 23 May 2024 23:11:34 +0200 Subject: [PATCH 1798/2607] [nextion] Add basic functions to Intelligent series (#6791) --- esphome/components/nextion/nextion.h | 67 +++++++++++++++++++ .../components/nextion/nextion_commands.cpp | 20 +++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index dfa74f644d..4546baa4d8 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -952,6 +952,73 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ bool set_protocol_reparse_mode(bool active_mode); + // ======== Nextion Intelligent Series ======== + + /** + * Set the video id of a component. + * @param component The component name. + * @param vid_id The video ID. + * + * Example: + * ```cpp + * it.set_component_vid("textview", 1); + * ``` + * + * This will change the video id of the component `textview`. + * + * Note: Requires Nextion Intelligent series display. + */ + void set_component_vid(const char *component, uint8_t vid_id); + + /** + * Set the drag availability of a component. + * @param component The component name. + * @param drag False: Drag not available, True: Drag available. + * + * Example: + * ```cpp + * it.set_component_drag("textview", true); + * ``` + * + * This will enable drag to the component `textview`. + * + * Note: Requires Nextion Intelligent series display. + */ + void set_component_drag(const char *component, bool drag); + + /** + * Set the opaqueness (fading) of a component. + * @param component The component name. + * @param aph An integer between 0 and 127 related to the opaqueness/fading level. + * + * Example: + * ```cpp + * it.set_component_aph("textview", 64); + * ``` + * + * This will set the opaqueness level of the component `textview` to 64. + * + * Note: Requires Nextion Intelligent series display. + */ + void set_component_aph(const char *component, uint8_t aph); + + /** + * Set the position of a component. + * @param component The component name. + * @param x The new X (horizontal) coordinate for the component. + * @param y The new Y (vertical) coordinate for the component. + * + * Example: + * ```cpp + * it.set_component_aph("textview", 64, 35); + * ``` + * + * This will move the component `textview` to the column 64 of row 35 of the display. + * + * Note: Requires Nextion Intelligent series display. + */ + void set_component_position(const char *component, uint32_t x, uint32_t y); + // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void register_touch_component(NextionComponentBase *obj) { this->touch_.push_back(obj); } diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index fdd6c74d99..398e9dd502 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -148,7 +148,25 @@ void Nextion::set_component_pic(const char *component, uint8_t pic_id) { } void Nextion::set_component_picc(const char *component, uint8_t pic_id) { - this->add_no_result_to_queue_with_printf_("set_component_pic", "%s.picc=%" PRIu8, component, pic_id); + this->add_no_result_to_queue_with_printf_("set_component_picc", "%s.picc=%" PRIu8, component, pic_id); +} + +// Set video +void Nextion::set_component_vid(const char *component, uint8_t vid_id) { + this->add_no_result_to_queue_with_printf_("set_component_vid", "%s.vid=%" PRIu8, component, vid_id); +} + +void Nextion::set_component_drag(const char *component, bool drag) { + this->add_no_result_to_queue_with_printf_("set_component_drag", "%s.drag=%i", component, drag ? 1 : 0); +} + +void Nextion::set_component_aph(const char *component, uint8_t aph) { + this->add_no_result_to_queue_with_printf_("set_component_aph", "%s.aph=%" PRIu8, component, aph); +} + +void Nextion::set_component_position(const char *component, uint32_t x, uint32_t y) { + this->add_no_result_to_queue_with_printf_("set_component_position_x", "%s.x=%" PRIu32, component, x); + this->add_no_result_to_queue_with_printf_("set_component_position_y", "%s.y=%" PRIu32, component, y); } void Nextion::set_component_text_printf(const char *component, const char *format, ...) { From 863bee28d9649f3179b75b3a5ebb833d9c7232a5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 25 May 2024 07:42:24 +1200 Subject: [PATCH 1799/2607] [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) --- .../voice_assistant/voice_assistant.cpp | 96 +++++++++++++++---- .../voice_assistant/voice_assistant.h | 4 + 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 109e52f8eb..59ba39c527 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -71,6 +71,12 @@ void VoiceAssistant::setup() { ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); global_voice_assistant = this; +} + +bool VoiceAssistant::allocate_buffers_() { + if (this->send_buffer_ != nullptr) { + return true; // Already allocated + } #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { @@ -78,8 +84,7 @@ void VoiceAssistant::setup() { this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE); if (this->speaker_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate speaker buffer"); - this->mark_failed(); - return; + return false; } } #endif @@ -88,8 +93,7 @@ void VoiceAssistant::setup() { this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE); if (this->input_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate input buffer"); - this->mark_failed(); - return; + return false; } #ifdef USE_ESP_ADF @@ -99,17 +103,71 @@ void VoiceAssistant::setup() { this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t)); if (this->ring_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate ring buffer"); - this->mark_failed(); - return; + return false; } ExternalRAMAllocator send_allocator(ExternalRAMAllocator::ALLOW_FAILURE); this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE); if (send_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate send buffer"); - this->mark_failed(); - return; + return false; } + + return true; +} + +void VoiceAssistant::clear_buffers_() { + if (this->send_buffer_ != nullptr) { + memset(this->send_buffer_, 0, SEND_BUFFER_SIZE); + } + + if (this->input_buffer_ != nullptr) { + memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + } + + if (this->ring_buffer_ != nullptr) { + this->ring_buffer_->reset(); + } + +#ifdef USE_SPEAKER + if (this->speaker_buffer_ != nullptr) { + memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + + this->speaker_buffer_size_ = 0; + this->speaker_buffer_index_ = 0; + this->speaker_bytes_received_ = 0; + } +#endif +} + +void VoiceAssistant::deallocate_buffers_() { + ExternalRAMAllocator send_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + send_deallocator.deallocate(this->send_buffer_, SEND_BUFFER_SIZE); + this->send_buffer_ = nullptr; + + if (this->ring_buffer_ != nullptr) { + this->ring_buffer_.reset(); + this->ring_buffer_ = nullptr; + } + +#ifdef USE_ESP_ADF + if (this->vad_instance_ != nullptr) { + vad_destroy(this->vad_instance_); + this->vad_instance_ = nullptr; + } +#endif + + ExternalRAMAllocator input_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + input_deallocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE); + this->input_buffer_ = nullptr; + +#ifdef USE_SPEAKER + if (this->speaker_buffer_ != nullptr) { + ExternalRAMAllocator speaker_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + speaker_deallocator.deallocate(this->speaker_buffer_, SPEAKER_BUFFER_SIZE); + this->speaker_buffer_ = nullptr; + } +#endif } int VoiceAssistant::read_microphone_() { @@ -138,14 +196,13 @@ void VoiceAssistant::loop() { } this->continuous_ = false; this->signal_stop_(); + this->clear_buffers_(); return; } switch (this->state_) { case State::IDLE: { if (this->continuous_ && this->desired_state_ == State::IDLE) { this->idle_trigger_->trigger(); - - this->ring_buffer_->reset(); #ifdef USE_ESP_ADF if (this->use_wake_word_) { this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); @@ -161,8 +218,15 @@ void VoiceAssistant::loop() { } case State::START_MICROPHONE: { ESP_LOGD(TAG, "Starting Microphone"); - memset(this->send_buffer_, 0, SEND_BUFFER_SIZE); - memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + if (!this->allocate_buffers_()) { + this->status_set_error("Failed to allocate buffers"); + return; + } + if (this->status_has_error()) { + this->status_clear_error(); + } + this->clear_buffers_(); + this->mic_->start(); this->high_freq_.start(); this->set_state_(State::STARTING_MICROPHONE); @@ -343,10 +407,9 @@ void VoiceAssistant::loop() { this->speaker_->stop(); this->cancel_timeout("speaker-timeout"); this->cancel_timeout("playing"); - this->speaker_buffer_size_ = 0; - this->speaker_buffer_index_ = 0; - this->speaker_bytes_received_ = 0; - memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + + this->clear_buffers_(); + this->wait_for_stream_end_ = false; this->stream_ended_ = false; @@ -507,7 +570,6 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) { if (this->state_ == State::IDLE) { this->continuous_ = continuous; this->silence_detection_ = silence_detection; - this->ring_buffer_->reset(); #ifdef USE_ESP_ADF if (this->use_wake_word_) { this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 1c0ea12f4f..17141365d4 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -151,6 +151,10 @@ class VoiceAssistant : public Component { void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; } protected: + bool allocate_buffers_(); + void clear_buffers_(); + void deallocate_buffers_(); + int read_microphone_(); void set_state_(State state); void set_state_(State state, State desired_state); From 04db724295e4e5a537e1532b426a9c64bc19a7aa Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 25 May 2024 07:42:24 +1200 Subject: [PATCH 1800/2607] [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) --- .../voice_assistant/voice_assistant.cpp | 96 +++++++++++++++---- .../voice_assistant/voice_assistant.h | 4 + 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 109e52f8eb..59ba39c527 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -71,6 +71,12 @@ void VoiceAssistant::setup() { ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); global_voice_assistant = this; +} + +bool VoiceAssistant::allocate_buffers_() { + if (this->send_buffer_ != nullptr) { + return true; // Already allocated + } #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { @@ -78,8 +84,7 @@ void VoiceAssistant::setup() { this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE); if (this->speaker_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate speaker buffer"); - this->mark_failed(); - return; + return false; } } #endif @@ -88,8 +93,7 @@ void VoiceAssistant::setup() { this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE); if (this->input_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate input buffer"); - this->mark_failed(); - return; + return false; } #ifdef USE_ESP_ADF @@ -99,17 +103,71 @@ void VoiceAssistant::setup() { this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t)); if (this->ring_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate ring buffer"); - this->mark_failed(); - return; + return false; } ExternalRAMAllocator send_allocator(ExternalRAMAllocator::ALLOW_FAILURE); this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE); if (send_buffer_ == nullptr) { ESP_LOGW(TAG, "Could not allocate send buffer"); - this->mark_failed(); - return; + return false; } + + return true; +} + +void VoiceAssistant::clear_buffers_() { + if (this->send_buffer_ != nullptr) { + memset(this->send_buffer_, 0, SEND_BUFFER_SIZE); + } + + if (this->input_buffer_ != nullptr) { + memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + } + + if (this->ring_buffer_ != nullptr) { + this->ring_buffer_->reset(); + } + +#ifdef USE_SPEAKER + if (this->speaker_buffer_ != nullptr) { + memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + + this->speaker_buffer_size_ = 0; + this->speaker_buffer_index_ = 0; + this->speaker_bytes_received_ = 0; + } +#endif +} + +void VoiceAssistant::deallocate_buffers_() { + ExternalRAMAllocator send_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + send_deallocator.deallocate(this->send_buffer_, SEND_BUFFER_SIZE); + this->send_buffer_ = nullptr; + + if (this->ring_buffer_ != nullptr) { + this->ring_buffer_.reset(); + this->ring_buffer_ = nullptr; + } + +#ifdef USE_ESP_ADF + if (this->vad_instance_ != nullptr) { + vad_destroy(this->vad_instance_); + this->vad_instance_ = nullptr; + } +#endif + + ExternalRAMAllocator input_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + input_deallocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE); + this->input_buffer_ = nullptr; + +#ifdef USE_SPEAKER + if (this->speaker_buffer_ != nullptr) { + ExternalRAMAllocator speaker_deallocator(ExternalRAMAllocator::ALLOW_FAILURE); + speaker_deallocator.deallocate(this->speaker_buffer_, SPEAKER_BUFFER_SIZE); + this->speaker_buffer_ = nullptr; + } +#endif } int VoiceAssistant::read_microphone_() { @@ -138,14 +196,13 @@ void VoiceAssistant::loop() { } this->continuous_ = false; this->signal_stop_(); + this->clear_buffers_(); return; } switch (this->state_) { case State::IDLE: { if (this->continuous_ && this->desired_state_ == State::IDLE) { this->idle_trigger_->trigger(); - - this->ring_buffer_->reset(); #ifdef USE_ESP_ADF if (this->use_wake_word_) { this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); @@ -161,8 +218,15 @@ void VoiceAssistant::loop() { } case State::START_MICROPHONE: { ESP_LOGD(TAG, "Starting Microphone"); - memset(this->send_buffer_, 0, SEND_BUFFER_SIZE); - memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t)); + if (!this->allocate_buffers_()) { + this->status_set_error("Failed to allocate buffers"); + return; + } + if (this->status_has_error()) { + this->status_clear_error(); + } + this->clear_buffers_(); + this->mic_->start(); this->high_freq_.start(); this->set_state_(State::STARTING_MICROPHONE); @@ -343,10 +407,9 @@ void VoiceAssistant::loop() { this->speaker_->stop(); this->cancel_timeout("speaker-timeout"); this->cancel_timeout("playing"); - this->speaker_buffer_size_ = 0; - this->speaker_buffer_index_ = 0; - this->speaker_bytes_received_ = 0; - memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE); + + this->clear_buffers_(); + this->wait_for_stream_end_ = false; this->stream_ended_ = false; @@ -507,7 +570,6 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) { if (this->state_ == State::IDLE) { this->continuous_ = continuous; this->silence_detection_ = silence_detection; - this->ring_buffer_->reset(); #ifdef USE_ESP_ADF if (this->use_wake_word_) { this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD); diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 1c0ea12f4f..17141365d4 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -151,6 +151,10 @@ class VoiceAssistant : public Component { void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; } protected: + bool allocate_buffers_(); + void clear_buffers_(); + void deallocate_buffers_(); + int read_microphone_(); void set_state_(State state); void set_state_(State state, State desired_state); From af755380b7e8f8b90cfd1f45c9dcbf09bb94c101 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 25 May 2024 08:14:39 +1200 Subject: [PATCH 1801/2607] Bump version to 2024.5.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 48b8aa8656..0c53287909 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.2" +__version__ = "2024.5.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6d341ce4e7f41c09d723f9663e61e0c0dd51d159 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 27 May 2024 07:15:05 +1200 Subject: [PATCH 1802/2607] [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797) Co-authored-by: Samuel Sieb --- esphome/components/web_server_base/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 1970b5a0c5..4f894619b0 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -37,4 +37,4 @@ async def to_code(config): cg.add_library("FS", None) cg.add_library("Update", None) # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json - cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.2.0") + cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.2.2") diff --git a/platformio.ini b/platformio.ini index 65c742cf91..fd0ae7c6d8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,7 +58,7 @@ lib_deps = SPI ; spi (Arduino built-in) Wire ; i2c (Arduino built-int) heman/AsyncMqttClient-esphome@1.0.0 ; mqtt - esphome/ESPAsyncWebServer-esphome@3.2.0 ; web_server_base + esphome/ESPAsyncWebServer-esphome@3.2.2 ; web_server_base fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps freekode/TM1651@1.0.1 ; tm1651 From 4125b48b86a4da0ba27704ab11f2033a8275540c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1o=20Domadenik?= Date: Sun, 26 May 2024 21:23:00 +0200 Subject: [PATCH 1803/2607] Fix incorrect naming of the AdaFruit MagTag display. (#6810) --- esphome/components/waveshare_epaper/display.py | 4 ++-- .../components/waveshare_epaper/waveshare_epaper.cpp | 12 ++++++------ .../components/waveshare_epaper/waveshare_epaper.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index bba60efc0a..9ad948e915 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -48,7 +48,7 @@ WaveshareEPaper2P9InBV3 = waveshare_epaper_ns.class_( WaveshareEPaper2P9InV2R2 = waveshare_epaper_ns.class_( "WaveshareEPaper2P9InV2R2", WaveshareEPaper ) -GDEY029T94 = waveshare_epaper_ns.class_("GDEY029T94", WaveshareEPaper) +GDEW029T5 = waveshare_epaper_ns.class_("GDEW029T5", WaveshareEPaper) WaveshareEPaper2P9InDKE = waveshare_epaper_ns.class_( "WaveshareEPaper2P9InDKE", WaveshareEPaper ) @@ -110,7 +110,7 @@ MODELS = { "2.13in-ttgo-b74": ("a", WaveshareEPaperTypeAModel.TTGO_EPAPER_2_13_IN_B74), "2.90in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN), "2.90inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN_V2), - "gdey029t94": ("c", GDEY029T94), + "gdew029t5": ("c", GDEW029T5), "2.70in": ("b", WaveshareEPaper2P7In), "2.70in-b": ("b", WaveshareEPaper2P7InB), "2.70in-bv2": ("b", WaveshareEPaper2P7InBV2), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 7224aa44ed..5428f4ec80 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1514,7 +1514,7 @@ void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every) // - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h // ======================================================== -void GDEY029T94::initialize() { +void GDEW029T5::initialize() { // from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37 // EPD hardware init start this->reset_(); @@ -1560,7 +1560,7 @@ void GDEY029T94::initialize() { // EPD hardware init end } -void HOT GDEY029T94::display() { +void HOT GDEW029T5::display() { // COMMAND DATA START TRANSMISSION 2 (B/W only) this->command(0x13); delay(2); @@ -1580,11 +1580,11 @@ void HOT GDEY029T94::display() { // NOTE: power off < deep sleep this->command(0x02); } -int GDEY029T94::get_width_internal() { return 128; } -int GDEY029T94::get_height_internal() { return 296; } -void GDEY029T94::dump_config() { +int GDEW029T5::get_width_internal() { return 128; } +int GDEW029T5::get_height_internal() { return 296; } +void GDEW029T5::dump_config() { LOG_DISPLAY("", "Waveshare E-Paper (Good Display)", this); - ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEY029T94"); + ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEW029T5"); LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Busy Pin: ", this->busy_pin_); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 3c4470c30c..4a5844ae88 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -227,7 +227,7 @@ class WaveshareEPaper2P7InBV2 : public WaveshareEPaperBWR { int get_height_internal() override; }; -class GDEY029T94 : public WaveshareEPaper { +class GDEW029T5 : public WaveshareEPaper { public: void initialize() override; From 17c6bf57cdcdffe00af8578ec1c4fd3e00e6d451 Mon Sep 17 00:00:00 2001 From: august huber Date: Sun, 26 May 2024 15:40:38 -0400 Subject: [PATCH 1804/2607] [tuya] add support for extended services (#6808) --- esphome/components/tuya/tuya.cpp | 24 ++++++++++++++++++++++++ esphome/components/tuya/tuya.h | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 1cc9681d09..402953bb3b 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -269,6 +269,30 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff ESP_LOGV(TAG, "Network status requested, reported as %i", wifi_status); break; } + case TuyaCommandType::EXTENDED_SERVICES: { + uint8_t subcommand = buffer[0]; + switch ((TuyaExtendedServicesCommandType) subcommand) { + case TuyaExtendedServicesCommandType::RESET_NOTIFICATION: { + this->send_command_( + TuyaCommand{.cmd = TuyaCommandType::EXTENDED_SERVICES, + .payload = std::vector{ + static_cast(TuyaExtendedServicesCommandType::RESET_NOTIFICATION), 0x00}}); + ESP_LOGV(TAG, "Reset status notification enabled"); + break; + } + case TuyaExtendedServicesCommandType::MODULE_RESET: { + ESP_LOGE(TAG, "EXTENDED_SERVICES::MODULE_RESET is not handled"); + break; + } + case TuyaExtendedServicesCommandType::UPDATE_IN_PROGRESS: { + ESP_LOGE(TAG, "EXTENDED_SERVICES::UPDATE_IN_PROGRESS is not handled"); + break; + } + default: + ESP_LOGE(TAG, "Invalid extended services subcommand (0x%02X) received", subcommand); + } + break; + } default: ESP_LOGE(TAG, "Invalid command (0x%02X) received", command); } diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index 7dc405e3dd..6db417d474 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -60,6 +60,13 @@ enum class TuyaCommandType : uint8_t { WIFI_RSSI = 0x24, VACUUM_MAP_UPLOAD = 0x28, GET_NETWORK_STATUS = 0x2B, + EXTENDED_SERVICES = 0x34, +}; + +enum class TuyaExtendedServicesCommandType : uint8_t { + RESET_NOTIFICATION = 0x04, + MODULE_RESET = 0x05, + UPDATE_IN_PROGRESS = 0x0A, }; enum class TuyaInitState : uint8_t { From e285196709771e22a42b2eb0c69add723d546ca5 Mon Sep 17 00:00:00 2001 From: august huber Date: Sun, 26 May 2024 15:41:29 -0400 Subject: [PATCH 1805/2607] fix libretiny regression from #6715 (#6806) --- esphome/components/debug/debug_libretiny.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp index 725cd870ca..c3418cf96c 100644 --- a/esphome/components/debug/debug_libretiny.cpp +++ b/esphome/components/debug/debug_libretiny.cpp @@ -12,7 +12,7 @@ std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_na uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } void DebugComponent::get_device_info_(std::string &device_info) { - reset_reason = get_reset_reason_(); + str::string reset_reason = get_reset_reason_(); ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); From 6e4fd428e72ec5fb4d04802de1d0f8c65f1c961d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 27 May 2024 22:19:22 +0200 Subject: [PATCH 1806/2607] [helpers] Move Base64 string to cpp (#6819) --- esphome/core/helpers.cpp | 4 ++++ esphome/core/helpers.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index fdc0eed774..dee771d4e9 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -433,6 +433,10 @@ int8_t step_to_accuracy_decimals(float step) { return str.length() - dot_pos - 1; } +static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + static inline bool is_base64(char c) { return (isalnum(c) || (c == '+') || (c == '/')); } std::string base64_encode(const std::vector &buf) { return base64_encode(buf.data(), buf.size()); } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 809e7d6767..4af840f77b 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -435,10 +435,6 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals); /// Derive accuracy in decimals from an increment step. int8_t step_to_accuracy_decimals(float step); -static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - std::string base64_encode(const uint8_t *buf, size_t buf_len); std::string base64_encode(const std::vector &buf); From 54b51269ab465fb4f8f849f1f52b6b42977635c8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 27 May 2024 07:15:05 +1200 Subject: [PATCH 1807/2607] [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797) Co-authored-by: Samuel Sieb --- esphome/components/web_server_base/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 1970b5a0c5..4f894619b0 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -37,4 +37,4 @@ async def to_code(config): cg.add_library("FS", None) cg.add_library("Update", None) # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json - cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.2.0") + cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.2.2") diff --git a/platformio.ini b/platformio.ini index d342b32b02..67a631dda8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,7 +58,7 @@ lib_deps = SPI ; spi (Arduino built-in) Wire ; i2c (Arduino built-int) heman/AsyncMqttClient-esphome@1.0.0 ; mqtt - esphome/ESPAsyncWebServer-esphome@3.2.0 ; web_server_base + esphome/ESPAsyncWebServer-esphome@3.2.2 ; web_server_base fastled/FastLED@3.3.2 ; fastled_base mikalhart/TinyGPSPlus@1.0.2 ; gps freekode/TM1651@1.0.1 ; tm1651 From f07479419c30e3ae89fcdefff254601dbdedd36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 27 May 2024 22:19:22 +0200 Subject: [PATCH 1808/2607] [helpers] Move Base64 string to cpp (#6819) --- esphome/core/helpers.cpp | 4 ++++ esphome/core/helpers.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index fdc0eed774..dee771d4e9 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -433,6 +433,10 @@ int8_t step_to_accuracy_decimals(float step) { return str.length() - dot_pos - 1; } +static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + static inline bool is_base64(char c) { return (isalnum(c) || (c == '+') || (c == '/')); } std::string base64_encode(const std::vector &buf) { return base64_encode(buf.data(), buf.size()); } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 809e7d6767..4af840f77b 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -435,10 +435,6 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals); /// Derive accuracy in decimals from an increment step. int8_t step_to_accuracy_decimals(float step); -static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - std::string base64_encode(const uint8_t *buf, size_t buf_len); std::string base64_encode(const std::vector &buf); From 4cd4b168b44e073c3e874ba625cc10b3bb7c9bae Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 28 May 2024 08:29:19 +1200 Subject: [PATCH 1809/2607] Bump version to 2024.5.4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 0c53287909..ad5858dcf3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.3" +__version__ = "2024.5.4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 497cf8742f495918ed368eafdeafe72d53c5b9e2 Mon Sep 17 00:00:00 2001 From: pimdo <38102897+pimdo@users.noreply.github.com> Date: Tue, 28 May 2024 02:42:59 +0100 Subject: [PATCH 1810/2607] Make i2s_audio compatible with IDF 5+ (#6534) * Update i2s_audio.cpp Replace usage of I2S_NUM_MAX with I2S_NUM_1 * Update i2s_audio_microphone.cpp Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256 * Update i2s_audio_speaker.cpp Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256 * Update voice_assistant.cpp Fix msg.event_type format * check SOC_I2S_NUM for c3 * use I2S_NUM_AUTO * Update i2s_audio.cpp * Couple tweaks * Why did they take away I2S_NUM_MAX Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Keith Burzinski Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/i2s_audio/i2s_audio.cpp | 4 ++++ .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 2 +- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp | 2 +- esphome/components/voice_assistant/voice_assistant.cpp | 5 +++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/i2s_audio/i2s_audio.cpp b/esphome/components/i2s_audio/i2s_audio.cpp index c1a608c064..ad73b383fe 100644 --- a/esphome/components/i2s_audio/i2s_audio.cpp +++ b/esphome/components/i2s_audio/i2s_audio.cpp @@ -9,6 +9,10 @@ namespace i2s_audio { static const char *const TAG = "i2s_audio"; +#if defined(USE_ESP_IDF) && (ESP_IDF_VERSION_MAJOR >= 5) +static const uint8_t I2S_NUM_MAX = SOC_I2S_NUM; // because IDF 5+ took this away :( +#endif + void I2SAudioComponent::setup() { static i2s_port_t next_port_num = I2S_NUM_0; diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 1475df0975..a672348d85 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -57,7 +57,7 @@ void I2SAudioMicrophone::start_() { .use_apll = this->use_apll_, .tx_desc_auto_clear = false, .fixed_mclk = 0, - .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, + .mclk_multiple = I2S_MCLK_MULTIPLE_256, .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 95e63035fe..69536742cb 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -51,7 +51,7 @@ void I2SAudioSpeaker::player_task(void *params) { .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = I2S_PIN_NO_CHANGE, - .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, + .mclk_multiple = I2S_MCLK_MULTIPLE_256, .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; #if SOC_I2S_SUPPORTS_DAC diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 59ba39c527..712a0ab137 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -4,6 +4,7 @@ #include "esphome/core/log.h" +#include #include namespace esphome { @@ -622,7 +623,7 @@ void VoiceAssistant::signal_stop_() { } void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { - ESP_LOGD(TAG, "Event Type: %d", msg.event_type); + ESP_LOGD(TAG, "Event Type: %" PRId32, msg.event_type); switch (msg.event_type) { case api::enums::VOICE_ASSISTANT_RUN_START: ESP_LOGD(TAG, "Assist Pipeline running"); @@ -785,7 +786,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->defer([this]() { this->stt_vad_end_trigger_->trigger(); }); break; default: - ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type); + ESP_LOGD(TAG, "Unhandled event type: %" PRId32, msg.event_type); break; } } From db6f6f0cb7d1df10ac10b37e6dac46a0747406b7 Mon Sep 17 00:00:00 2001 From: DAVe3283 Date: Tue, 28 May 2024 13:40:34 -0600 Subject: [PATCH 1811/2607] Fix compile errors on ESP32-C6 with latest ESP-IDF (#6822) * Use PRI macros to fix ESP32-C6 compile * Fix compile error on latest ESP-IDF framework & platform --- esphome/components/ade7880/ade7880.cpp | 23 +++++++------- .../components/ade7953_base/ade7953_base.cpp | 3 +- .../fingerprint_grow/fingerprint_grow.cpp | 14 ++++----- esphome/components/he60r/he60r.cpp | 3 +- esphome/components/mhz19/mhz19.cpp | 5 +-- .../remote_base/abbwelcome_protocol.h | 4 ++- .../remote_base/byronsx_protocol.cpp | 22 +++++++------ .../remote_base/drayton_protocol.cpp | 17 +++++----- .../remote_base/keeloq_protocol.cpp | 31 ++++++++++--------- .../uart/uart_component_esp_idf.cpp | 2 +- esphome/components/xgzp68xx/xgzp68xx.cpp | 5 +-- 11 files changed, 73 insertions(+), 56 deletions(-) diff --git a/esphome/components/ade7880/ade7880.cpp b/esphome/components/ade7880/ade7880.cpp index 31b72d51a6..a03f1227f1 100644 --- a/esphome/components/ade7880/ade7880.cpp +++ b/esphome/components/ade7880/ade7880.cpp @@ -10,6 +10,7 @@ #include "ade7880.h" #include "ade7880_registers.h" #include "esphome/core/log.h" +#include namespace esphome { namespace ade7880 { @@ -156,7 +157,7 @@ void ADE7880::update() { }); } - ESP_LOGD(TAG, "update took %u ms", millis() - start); + ESP_LOGD(TAG, "update took %" PRIu32 " ms", millis() - start); } void ADE7880::dump_config() { @@ -176,9 +177,9 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Forward Active Energy", this->channel_a_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_a_->reverse_active_energy); ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %u", this->channel_a_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_a_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %d", this->channel_a_->power_gain_calibration); + ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_a_->current_gain_calibration); + ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration); + ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_a_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration); } @@ -192,9 +193,9 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Forward Active Energy", this->channel_b_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_b_->reverse_active_energy); ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %u", this->channel_b_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_b_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %d", this->channel_b_->power_gain_calibration); + ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_b_->current_gain_calibration); + ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration); + ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_b_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration); } @@ -208,9 +209,9 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Forward Active Energy", this->channel_c_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_c_->reverse_active_energy); ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %u", this->channel_c_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_c_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %d", this->channel_c_->power_gain_calibration); + ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_c_->current_gain_calibration); + ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration); + ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_c_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration); } @@ -218,7 +219,7 @@ void ADE7880::dump_config() { ESP_LOGCONFIG(TAG, " Neutral:"); LOG_SENSOR(" ", "Current", this->channel_n_->current); ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %u", this->channel_n_->current_gain_calibration); + ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_n_->current_gain_calibration); } LOG_I2C_DEVICE(this); diff --git a/esphome/components/ade7953_base/ade7953_base.cpp b/esphome/components/ade7953_base/ade7953_base.cpp index 862f5567a8..79161c5676 100644 --- a/esphome/components/ade7953_base/ade7953_base.cpp +++ b/esphome/components/ade7953_base/ade7953_base.cpp @@ -1,5 +1,6 @@ #include "ade7953_base.h" #include "esphome/core/log.h" +#include namespace esphome { namespace ade7953_base { @@ -105,7 +106,7 @@ void ADE7953::update() { this->last_update_ = now; // prevent DIV/0 pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000; - ESP_LOGVV(TAG, "ADE7953::update() diff=%d pf=%f", diff, pf); + ESP_LOGVV(TAG, "ADE7953::update() diff=%" PRIu32 " pf=%f", diff, pf); } // Apparent power diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index bd0817350a..8f58db9159 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -541,34 +541,34 @@ void FingerprintGrowComponent::dump_config() { ESP_LOGCONFIG(TAG, " Sensor Power Pin: %s", this->has_power_pin_ ? this->sensor_power_pin_->dump_summary().c_str() : "None"); if (this->idle_period_to_sleep_ms_ < UINT32_MAX) { - ESP_LOGCONFIG(TAG, " Idle Period to Sleep: %u ms", this->idle_period_to_sleep_ms_); + ESP_LOGCONFIG(TAG, " Idle Period to Sleep: %" PRIu32 " ms", this->idle_period_to_sleep_ms_); } else { ESP_LOGCONFIG(TAG, " Idle Period to Sleep: Never"); } LOG_UPDATE_INTERVAL(this); if (this->fingerprint_count_sensor_) { LOG_SENSOR(" ", "Fingerprint Count", this->fingerprint_count_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->fingerprint_count_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %u", (uint16_t) this->fingerprint_count_sensor_->get_state()); } if (this->status_sensor_) { LOG_SENSOR(" ", "Status", this->status_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->status_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %u", (uint8_t) this->status_sensor_->get_state()); } if (this->capacity_sensor_) { LOG_SENSOR(" ", "Capacity", this->capacity_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->capacity_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %u", (uint16_t) this->capacity_sensor_->get_state()); } if (this->security_level_sensor_) { LOG_SENSOR(" ", "Security Level", this->security_level_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->security_level_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %u", (uint8_t) this->security_level_sensor_->get_state()); } if (this->last_finger_id_sensor_) { LOG_SENSOR(" ", "Last Finger ID", this->last_finger_id_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_finger_id_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %" PRIu32, (uint32_t) this->last_finger_id_sensor_->get_state()); } if (this->last_confidence_sensor_) { LOG_SENSOR(" ", "Last Confidence", this->last_confidence_sensor_); - ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_confidence_sensor_->get_state()); + ESP_LOGCONFIG(TAG, " Current Value: %" PRIu32, (uint32_t) this->last_confidence_sensor_->get_state()); } } diff --git a/esphome/components/he60r/he60r.cpp b/esphome/components/he60r/he60r.cpp index d6e6122b1b..96ad1f04be 100644 --- a/esphome/components/he60r/he60r.cpp +++ b/esphome/components/he60r/he60r.cpp @@ -1,6 +1,7 @@ #include "he60r.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" +#include namespace esphome { namespace he60r { @@ -127,7 +128,7 @@ void HE60rCover::update_() { if (toggles_needed_ != 0) { if ((this->counter_++ & 0x3) == 0) { toggles_needed_--; - ESP_LOGD(TAG, "Writing byte 0x30, still needed=%d", toggles_needed_); + ESP_LOGD(TAG, "Writing byte 0x30, still needed=%" PRIu32, toggles_needed_); this->write_byte(TOGGLE_BYTE); } else { this->write_byte(QUERY_BYTE); diff --git a/esphome/components/mhz19/mhz19.cpp b/esphome/components/mhz19/mhz19.cpp index 019f6cee51..574aee1bd5 100644 --- a/esphome/components/mhz19/mhz19.cpp +++ b/esphome/components/mhz19/mhz19.cpp @@ -1,5 +1,6 @@ #include "mhz19.h" #include "esphome/core/log.h" +#include namespace esphome { namespace mhz19 { @@ -32,7 +33,7 @@ void MHZ19Component::update() { uint32_t now_ms = millis(); uint32_t warmup_ms = this->warmup_seconds_ * 1000; if (now_ms < warmup_ms) { - ESP_LOGW(TAG, "MHZ19 warming up, %ds left", (warmup_ms - now_ms) / 1000); + ESP_LOGW(TAG, "MHZ19 warming up, %" PRIu32 " s left", (warmup_ms - now_ms) / 1000); this->status_set_warning(); return; } @@ -110,7 +111,7 @@ void MHZ19Component::dump_config() { ESP_LOGCONFIG(TAG, " Automatic baseline calibration disabled on boot"); } - ESP_LOGCONFIG(TAG, " Warmup seconds: %ds", this->warmup_seconds_); + ESP_LOGCONFIG(TAG, " Warmup time: %" PRIu32 " s", this->warmup_seconds_); } } // namespace mhz19 diff --git a/esphome/components/remote_base/abbwelcome_protocol.h b/esphome/components/remote_base/abbwelcome_protocol.h index 0493993926..f2d0f5b547 100644 --- a/esphome/components/remote_base/abbwelcome_protocol.h +++ b/esphome/components/remote_base/abbwelcome_protocol.h @@ -4,6 +4,7 @@ #include "esphome/core/helpers.h" #include "remote_base.h" #include +#include #include #include @@ -144,7 +145,8 @@ class ABBWelcomeData { std::string to_string(uint8_t max_print_bytes = 255) const { std::string info; if (this->is_valid()) { - info = str_sprintf(this->get_three_byte_address() ? "[%06X %s %06X] Type: %02X" : "[%04X %s %04X] Type: %02X", + info = str_sprintf(this->get_three_byte_address() ? "[%06" PRIX32 " %s %06" PRIX32 "] Type: %02X" + : "[%04" PRIX32 " %s %04" PRIX32 "] Type: %02X", this->get_source_address(), this->get_retransmission() ? "»" : ">", this->get_destination_address(), this->get_message_type()); if (this->get_data_size()) diff --git a/esphome/components/remote_base/byronsx_protocol.cpp b/esphome/components/remote_base/byronsx_protocol.cpp index 3096283b30..2d4c60ff8b 100644 --- a/esphome/components/remote_base/byronsx_protocol.cpp +++ b/esphome/components/remote_base/byronsx_protocol.cpp @@ -1,5 +1,6 @@ #include "byronsx_protocol.h" #include "esphome/core/log.h" +#include namespace esphome { namespace remote_base { @@ -57,7 +58,7 @@ void ByronSXProtocol::encode(RemoteTransmitData *dst, const ByronSXData &data) { out_data <<= NBITS_COMMAND; out_data |= data.command; - ESP_LOGV(TAG, "Send ByronSX: out_data %03x", out_data); + ESP_LOGV(TAG, "Send ByronSX: out_data %03" PRIx32, out_data); // Initial Mark start bit dst->mark(1 * BIT_TIME_US); @@ -90,13 +91,16 @@ optional ByronSXProtocol::decode(RemoteReceiveData src) { return {}; } - ESP_LOGVV(TAG, "%3d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", src.size(), src.peek(0), - src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), src.peek(7), src.peek(8), - src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), src.peek(15), - src.peek(16), src.peek(17), src.peek(18), src.peek(19)); + ESP_LOGVV(TAG, + "%3" PRId32 ": %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 + " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 + " %" PRId32 " %" PRId32 " %" PRId32, + src.size(), src.peek(0), src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), + src.peek(7), src.peek(8), src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), + src.peek(15), src.peek(16), src.peek(17), src.peek(18), src.peek(19)); - ESP_LOGVV(TAG, " %d %d %d %d %d %d", src.peek(20), src.peek(21), src.peek(22), src.peek(23), src.peek(24), - src.peek(25)); + ESP_LOGVV(TAG, " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32, src.peek(20), + src.peek(21), src.peek(22), src.peek(23), src.peek(24), src.peek(25)); // Read data bits uint32_t out_data = 0; @@ -107,10 +111,10 @@ optional ByronSXProtocol::decode(RemoteReceiveData src) { } else if (src.expect_space(BIT_TIME_US) && src.expect_mark(2 * BIT_TIME_US)) { out_data |= 0 << bit; } else { - ESP_LOGV(TAG, "Decode ByronSX: Fail 2, %2d %08x", bit, out_data); + ESP_LOGV(TAG, "Decode ByronSX: Fail 2, %2d %08" PRIx32, bit, out_data); return {}; } - ESP_LOGVV(TAG, "Decode ByronSX: Data, %2d %08x", bit, out_data); + ESP_LOGVV(TAG, "Decode ByronSX: Data, %2d %08" PRIx32, bit, out_data); } // last bit followed by a long space diff --git a/esphome/components/remote_base/drayton_protocol.cpp b/esphome/components/remote_base/drayton_protocol.cpp index acfb7a0f16..73c0fb116c 100644 --- a/esphome/components/remote_base/drayton_protocol.cpp +++ b/esphome/components/remote_base/drayton_protocol.cpp @@ -151,12 +151,12 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { // Look for sync pulse, after. If sucessful index points to space of sync symbol while (src.size() - src.get_index() >= MIN_RX_SRC) { - ESP_LOGVV(TAG, "Decode Drayton: sync search %d, %" PRId32 " %" PRId32, src.size() - src.get_index(), src.peek(), - src.peek(1)); + ESP_LOGVV(TAG, "Decode Drayton: sync search %" PRIu32 ", %" PRId32 " %" PRId32, src.size() - src.get_index(), + src.peek(), src.peek(1)); if (src.peek_mark(2 * BIT_TIME_US) && (src.peek_space(2 * BIT_TIME_US, 1) || src.peek_space(3 * BIT_TIME_US, 1))) { src.advance(1); - ESP_LOGVV(TAG, "Decode Drayton: Found SYNC, - %d", src.get_index()); + ESP_LOGVV(TAG, "Decode Drayton: Found SYNC, - %" PRIu32, src.get_index()); break; } else { src.advance(2); @@ -174,14 +174,16 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { // Checks next bit to leave index pointing correctly uint32_t out_data = 0; uint8_t bit = NDATABITS - 1; - ESP_LOGVV(TAG, "Decode Drayton: first bit %d %" PRId32 ", %" PRId32, src.peek(0), src.peek(1), src.peek(2)); + ESP_LOGVV(TAG, "Decode Drayton: first bit %" PRId32 " %" PRId32 ", %" PRId32, src.peek(0), src.peek(1), + src.peek(2)); if (src.expect_space(3 * BIT_TIME_US) && (src.expect_mark(BIT_TIME_US) || src.peek_mark(2 * BIT_TIME_US))) { out_data |= 0 << bit; } else if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US) && (src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) { out_data |= 1 << bit; } else { - ESP_LOGV(TAG, "Decode Drayton: Fail 2, - %d %d %d", src.peek(-1), src.peek(0), src.peek(1)); + ESP_LOGV(TAG, "Decode Drayton: Fail 2, - %" PRId32 " %" PRId32 " %" PRId32, src.peek(-1), src.peek(0), + src.peek(1)); continue; } @@ -202,7 +204,8 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { } if (bit > 0) { - ESP_LOGVV(TAG, "Decode Drayton: Fail 3, %d %" PRId32 " %" PRId32, src.peek(-1), src.peek(0), src.peek(1)); + ESP_LOGVV(TAG, "Decode Drayton: Fail 3, %" PRId32 " %" PRId32 " %" PRId32, src.peek(-1), src.peek(0), + src.peek(1)); continue; } @@ -214,7 +217,7 @@ optional DraytonProtocol::decode(RemoteReceiveData src) { continue; } - ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08x", bit, out_data); + ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08" PRIx32, bit, out_data); out.channel = (uint8_t) (out_data & 0x1F); out_data >>= NBITS_CHANNEL; diff --git a/esphome/components/remote_base/keeloq_protocol.cpp b/esphome/components/remote_base/keeloq_protocol.cpp index 09d9ea4f53..72540c37f1 100644 --- a/esphome/components/remote_base/keeloq_protocol.cpp +++ b/esphome/components/remote_base/keeloq_protocol.cpp @@ -52,7 +52,7 @@ void KeeloqProtocol::encode(RemoteTransmitData *dst, const KeeloqData &data) { // Encrypted field out_data = data.encrypted; - ESP_LOGV(TAG, "Send Keeloq: Encrypted data %04x", out_data); + ESP_LOGV(TAG, "Send Keeloq: Encrypted data %04" PRIx32, out_data); for (uint32_t mask = 1, cnt = 0; cnt < NBITS_ENCRYPTED_DATA; cnt++, mask <<= 1) { if (out_data & mask) { @@ -68,7 +68,7 @@ void KeeloqProtocol::encode(RemoteTransmitData *dst, const KeeloqData &data) { out_data = (data.command & 0x0f); out_data <<= NBITS_SERIAL; out_data |= data.address; - ESP_LOGV(TAG, "Send Keeloq: Fixed data %04x", out_data); + ESP_LOGV(TAG, "Send Keeloq: Fixed data %04" PRIx32, out_data); for (uint32_t mask = 1, cnt = 0; cnt < (NBITS_FIXED_DATA - 2); cnt++, mask <<= 1) { if (out_data & mask) { @@ -111,21 +111,24 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { return {}; } - ESP_LOGVV(TAG, "%2d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", src.size(), src.peek(0), - src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), src.peek(7), src.peek(8), - src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), src.peek(15), - src.peek(16), src.peek(17), src.peek(18), src.peek(19)); + ESP_LOGVV(TAG, + "%2" PRId32 ": %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 + " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 + " %" PRId32 " %" PRId32 " %" PRId32, + src.size(), src.peek(0), src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), + src.peek(7), src.peek(8), src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), + src.peek(15), src.peek(16), src.peek(17), src.peek(18), src.peek(19)); // Check preamble bits int8_t bit = NBITS_PREAMBLE - 1; while (--bit >= 0) { if (!src.expect_mark(BIT_TIME_US) || !src.expect_space(BIT_TIME_US)) { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 1, %d %d", bit + 1, src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 1, %d %" PRId32, bit + 1, src.peek()); return {}; } } if (!src.expect_mark(BIT_TIME_US) || !src.expect_space(10 * BIT_TIME_US)) { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 1, %d %d", bit + 1, src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 1, %d %" PRId32, bit + 1, src.peek()); return {}; } @@ -137,11 +140,11 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { } else if (src.expect_mark(BIT_TIME_US) && src.expect_space(2 * BIT_TIME_US)) { out_data |= 1 << bit; } else { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 2, %d %d", src.get_index(), src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 2, %" PRIu32 " %" PRId32, src.get_index(), src.peek()); return {}; } } - ESP_LOGVV(TAG, "Decode KeeLoq: Data, %d %08x", bit, out_data); + ESP_LOGVV(TAG, "Decode KeeLoq: Data, %d %08" PRIx32, bit, out_data); out.encrypted = out_data; // Read Serial Number and Button Status @@ -152,11 +155,11 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { } else if (src.expect_mark(BIT_TIME_US) && src.expect_space(2 * BIT_TIME_US)) { out_data |= 1 << bit; } else { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 3, %d %d", src.get_index(), src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 3, %" PRIu32 " %" PRId32, src.get_index(), src.peek()); return {}; } } - ESP_LOGVV(TAG, "Decode KeeLoq: Data, %2d %08x", bit, out_data); + ESP_LOGVV(TAG, "Decode KeeLoq: Data, %2d %08" PRIx32, bit, out_data); out.command = (out_data >> 28) & 0xf; out.address = out_data & 0xfffffff; @@ -166,7 +169,7 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { } else if (src.expect_mark(BIT_TIME_US) && src.expect_space(2 * BIT_TIME_US)) { out.vlow = true; } else { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 4, %08x", src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 4, %" PRId32, src.peek()); return {}; } @@ -176,7 +179,7 @@ optional KeeloqProtocol::decode(RemoteReceiveData src) { } else if (src.expect_mark(BIT_TIME_US) && src.peek_space_at_least(2 * BIT_TIME_US)) { out.repeat = true; } else { - ESP_LOGV(TAG, "Decode KeeLoq: Fail 5, %08x", src.peek()); + ESP_LOGV(TAG, "Decode KeeLoq: Fail 5, %" PRId32, src.peek()); return {}; } diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 2dd6ab105f..c66753b0c4 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -69,7 +69,7 @@ void IDFUARTComponent::setup() { this->mark_failed(); return; } - this->uart_num_ = next_uart_num++; + this->uart_num_ = static_cast(next_uart_num++); ESP_LOGCONFIG(TAG, "Setting up UART %u...", this->uart_num_); this->lock_ = xSemaphoreCreateMutex(); diff --git a/esphome/components/xgzp68xx/xgzp68xx.cpp b/esphome/components/xgzp68xx/xgzp68xx.cpp index ea3583c3c5..dff00fb696 100644 --- a/esphome/components/xgzp68xx/xgzp68xx.cpp +++ b/esphome/components/xgzp68xx/xgzp68xx.cpp @@ -3,6 +3,7 @@ #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/components/i2c/i2c.h" +#include namespace esphome { namespace xgzp68xx { @@ -37,8 +38,8 @@ void XGZP68XXComponent::update() { temperature_raw = encode_uint16(data[3], data[4]); // Convert the pressure data to hPa - ESP_LOGV(TAG, "Got raw pressure=%d, raw temperature=%d ", pressure_raw, temperature_raw); - ESP_LOGV(TAG, "K value is %d ", this->k_value_); + ESP_LOGV(TAG, "Got raw pressure=%" PRIu32 ", raw temperature=%u", pressure_raw, temperature_raw); + ESP_LOGV(TAG, "K value is %u", this->k_value_); // The most significant bit of both pressure and temperature will be 1 to indicate a negative value. // This is directly from the datasheet, and the calculations below will handle this. From 06996def725aececb406739857f59873f72271ca Mon Sep 17 00:00:00 2001 From: DAVe3283 Date: Tue, 28 May 2024 14:44:47 -0600 Subject: [PATCH 1812/2607] Use uint8_t instead of uint32_t for 8-bit values on mitsubishi (#6824) This solves some printf formatting issues on ESP-IDF and saves RAM on all platforms. --- esphome/components/mitsubishi/mitsubishi.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index 081c24a050..fd57adc586 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -6,7 +6,7 @@ namespace mitsubishi { static const char *const TAG = "mitsubishi.climate"; -const uint32_t MITSUBISHI_OFF = 0x00; +const uint8_t MITSUBISHI_OFF = 0x00; const uint8_t MITSUBISHI_MODE_AUTO = 0x20; const uint8_t MITSUBISHI_MODE_COOL = 0x18; @@ -109,8 +109,8 @@ void MitsubishiClimate::transmit_state() { // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00 // Byte 16: Constant 0x00 // Byte 17: Checksum: SUM[Byte0...Byte16] - uint32_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; switch (this->mode) { case climate::CLIMATE_MODE_HEAT: @@ -249,7 +249,7 @@ void MitsubishiClimate::transmit_state() { data->set_carrier_frequency(38000); // repeat twice - for (uint16_t r = 0; r < 2; r++) { + for (uint8_t r = 0; r < 2; r++) { // Header data->mark(MITSUBISHI_HEADER_MARK); data->space(MITSUBISHI_HEADER_SPACE); From 2b691ad5adde275544f1e7896463083a84f028af Mon Sep 17 00:00:00 2001 From: Frederik <5511687+fightforlife@users.noreply.github.com> Date: Wed, 29 May 2024 00:02:45 +0200 Subject: [PATCH 1813/2607] Make SPI Ethernet (W5500) compatible with ESP-IDF v5 (#6778) * change MAC PHY init order according to IDF examples * add idfv5 specific w5500 config init * esp_mac.h needs to be included directly starting with idf5 * Header fix * Couple tweaks --------- Co-authored-by: Keith Burzinski --- esphome/components/ethernet/ethernet_component.cpp | 8 ++++++-- esphome/components/ethernet/ethernet_component.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 3af462d593..2a4e5cbad3 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -98,11 +98,15 @@ void EthernetComponent::setup() { .post_cb = nullptr, }; +#if USE_ESP_IDF && (ESP_IDF_VERSION_MAJOR >= 5) + eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); +#else spi_device_handle_t spi_handle = nullptr; err = spi_bus_add_device(host, &devcfg, &spi_handle); ESPHL_ERROR_CHECK(err, "SPI bus add device error"); eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); +#endif w5500_config.int_gpio_num = this->interrupt_pin_; phy_config.phy_addr = this->phy_addr_spi_; phy_config.reset_gpio_num = this->reset_pin_; @@ -614,14 +618,14 @@ void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) { err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); - ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04X", phy_rmii_mode); + ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04" PRIX32, phy_rmii_mode); err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA); ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed"); err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); - ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04X", phy_rmii_mode); + ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04" PRIX32, phy_rmii_mode); err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0); ESPHL_ERROR_CHECK(err, "Setting Page 0 failed"); diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 6276885fd1..3705e3e06a 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -10,6 +10,7 @@ #include "esp_eth.h" #include "esp_eth_mac.h" #include "esp_netif.h" +#include "esp_mac.h" namespace esphome { namespace ethernet { From ec3164f80058c43ea21d7bc5c7f62bdf7679703f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 29 May 2024 14:36:49 +1000 Subject: [PATCH 1814/2607] [wake_on_lan] Make component platform independent (#6815) --- CODEOWNERS | 2 +- .../components/socket/lwip_raw_tcp_impl.cpp | 3 +- esphome/components/wake_on_lan/__init__.py | 2 +- esphome/components/wake_on_lan/button.py | 34 +++++---- .../components/wake_on_lan/wake_on_lan.cpp | 70 +++++++++++++------ esphome/components/wake_on_lan/wake_on_lan.h | 15 ++-- .../wake_on_lan/test.esp32-c3-idf.yaml | 1 + .../wake_on_lan/test.esp32-idf.yaml | 1 + 8 files changed, 84 insertions(+), 44 deletions(-) create mode 100644 tests/components/wake_on_lan/test.esp32-c3-idf.yaml create mode 100644 tests/components/wake_on_lan/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index e099ca42ac..8b6143859a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -414,7 +414,7 @@ esphome/components/veml3235/* @kbx81 esphome/components/veml7700/* @latonita esphome/components/version/* @esphome/core esphome/components/voice_assistant/* @jesserockz -esphome/components/wake_on_lan/* @willwill2will54 +esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/waveshare_epaper/* @clydebarrow esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_idf/* @dentra diff --git a/esphome/components/socket/lwip_raw_tcp_impl.cpp b/esphome/components/socket/lwip_raw_tcp_impl.cpp index bd59b81caa..1d998902ff 100644 --- a/esphome/components/socket/lwip_raw_tcp_impl.cpp +++ b/esphome/components/socket/lwip_raw_tcp_impl.cpp @@ -469,7 +469,8 @@ class LWIPRawImpl : public Socket { } ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override { // return ::sendto(fd_, buf, len, flags, to, tolen); - return 0; + errno = ENOSYS; + return -1; } int setblocking(bool blocking) override { if (pcb_ == nullptr) { diff --git a/esphome/components/wake_on_lan/__init__.py b/esphome/components/wake_on_lan/__init__.py index 3548fb02f4..90539e5d3c 100644 --- a/esphome/components/wake_on_lan/__init__.py +++ b/esphome/components/wake_on_lan/__init__.py @@ -1 +1 @@ -CODEOWNERS = ["@willwill2will54"] +CODEOWNERS = ["@willwill2will54", "@clydebarrow"] diff --git a/esphome/components/wake_on_lan/button.py b/esphome/components/wake_on_lan/button.py index 778ea60cfa..b09e87e811 100644 --- a/esphome/components/wake_on_lan/button.py +++ b/esphome/components/wake_on_lan/button.py @@ -2,6 +2,16 @@ import esphome.codegen as cg from esphome.components import button import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.core import CORE + +DEPENDENCIES = ["network"] + + +def AUTO_LOAD(): + if CORE.is_esp8266 or CORE.is_rp2040: + return [] + return ["socket"] + CONF_TARGET_MAC_ADDRESS = "target_mac_address" @@ -9,25 +19,19 @@ wake_on_lan_ns = cg.esphome_ns.namespace("wake_on_lan") WakeOnLanButton = wake_on_lan_ns.class_("WakeOnLanButton", button.Button, cg.Component) -DEPENDENCIES = ["network"] - -CONFIG_SCHEMA = cv.All( +CONFIG_SCHEMA = ( button.button_schema(WakeOnLanButton) .extend(cv.COMPONENT_SCHEMA) .extend( - cv.Schema( - { - cv.Required(CONF_TARGET_MAC_ADDRESS): cv.mac_address, - } - ), - ), - cv.only_with_arduino, + { + cv.Required(CONF_TARGET_MAC_ADDRESS): cv.mac_address, + } + ) ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - - yield cg.add(var.set_macaddr(*config[CONF_TARGET_MAC_ADDRESS].parts)) - yield cg.register_component(var, config) - yield button.register_button(var, config) + cg.add(var.set_macaddr(*config[CONF_TARGET_MAC_ADDRESS].parts)) + await cg.register_component(var, config) + await button.register_button(var, config) diff --git a/esphome/components/wake_on_lan/wake_on_lan.cpp b/esphome/components/wake_on_lan/wake_on_lan.cpp index f414bf6c71..080e1bbac8 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.cpp +++ b/esphome/components/wake_on_lan/wake_on_lan.cpp @@ -1,5 +1,3 @@ -#ifdef USE_ARDUINO - #include "wake_on_lan.h" #include "esphome/core/log.h" #include "esphome/components/network/ip_address.h" @@ -22,40 +20,68 @@ void WakeOnLanButton::set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, ui void WakeOnLanButton::dump_config() { LOG_BUTTON("", "Wake-on-LAN Button", this); - ESP_LOGCONFIG(TAG, " Target MAC address: %02X:%02X:%02X:%02X:%02X:%02X", macaddr_[0], macaddr_[1], macaddr_[2], - macaddr_[3], macaddr_[4], macaddr_[5]); + ESP_LOGCONFIG(TAG, " Target MAC address: %02X:%02X:%02X:%02X:%02X:%02X", this->macaddr_[0], this->macaddr_[1], + this->macaddr_[2], this->macaddr_[3], this->macaddr_[4], this->macaddr_[5]); } void WakeOnLanButton::press_action() { + if (!network::is_connected()) { + ESP_LOGW(TAG, "Network not connected"); + return; + } ESP_LOGI(TAG, "Sending Wake-on-LAN Packet..."); - bool begin_status = false; - bool end_status = false; +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + struct sockaddr_storage saddr {}; + auto addr_len = + socket::set_sockaddr(reinterpret_cast(&saddr), sizeof(saddr), "255.255.255.255", this->port_); + uint8_t buffer[6 + sizeof this->macaddr_ * 16]; + memcpy(buffer, PREFIX, sizeof(PREFIX)); + for (size_t i = 0; i != 16; i++) { + memcpy(buffer + i * sizeof(this->macaddr_) + sizeof(PREFIX), this->macaddr_, sizeof(this->macaddr_)); + } + if (this->broadcast_socket_->sendto(buffer, sizeof(buffer), 0, reinterpret_cast(&saddr), + addr_len) <= 0) + ESP_LOGW(TAG, "sendto() error %d", errno); +#else IPAddress broadcast = IPAddress(255, 255, 255, 255); -#ifdef USE_ESP8266 for (auto ip : esphome::network::get_ip_addresses()) { if (ip.is_ip4()) { - begin_status = this->udp_client_.beginPacketMulticast(broadcast, 9, ip, 128); - break; + if (this->udp_client_.beginPacketMulticast(broadcast, 9, ip, 128) != 0) { + this->udp_client_.write(PREFIX, 6); + for (size_t i = 0; i < 16; i++) { + this->udp_client_.write(macaddr_, 6); + } + if (this->udp_client_.endPacket() != 0) + return; + ESP_LOGW(TAG, "WOL broadcast failed"); + return; + } } } + ESP_LOGW(TAG, "No ip4 addresses to broadcast to"); #endif -#ifdef USE_ESP32 - begin_status = this->udp_client_.beginPacket(broadcast, 9); -#endif +} - if (begin_status) { - this->udp_client_.write(PREFIX, 6); - for (size_t i = 0; i < 16; i++) { - this->udp_client_.write(macaddr_, 6); - } - end_status = this->udp_client_.endPacket(); +void WakeOnLanButton::setup() { +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (this->broadcast_socket_ == nullptr) { + this->mark_failed(); + this->status_set_error("Could not create socket"); + return; } - if (!begin_status || end_status) { - ESP_LOGE(TAG, "Sending Wake-on-LAN Packet Failed!"); + int enable = 1; + auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + if (err != 0) { + this->status_set_warning("Socket unable to set reuseaddr"); + // we can still continue } + err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int)); + if (err != 0) { + this->status_set_warning("Socket unable to set broadcast"); + } +#endif } } // namespace wake_on_lan } // namespace esphome - -#endif diff --git a/esphome/components/wake_on_lan/wake_on_lan.h b/esphome/components/wake_on_lan/wake_on_lan.h index 72f900e3fa..42cb3a9268 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.h +++ b/esphome/components/wake_on_lan/wake_on_lan.h @@ -1,10 +1,12 @@ #pragma once -#ifdef USE_ARDUINO - #include "esphome/components/button/button.h" #include "esphome/core/component.h" +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) +#include "esphome/components/socket/socket.h" +#else #include "WiFiUdp.h" +#endif namespace esphome { namespace wake_on_lan { @@ -14,14 +16,19 @@ class WakeOnLanButton : public button::Button, public Component { void set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f); void dump_config() override; + void setup() override; + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } protected: +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + std::unique_ptr broadcast_socket_{}; +#else WiFiUDP udp_client_{}; +#endif void press_action() override; + uint16_t port_{9}; uint8_t macaddr_[6]; }; } // namespace wake_on_lan } // namespace esphome - -#endif diff --git a/tests/components/wake_on_lan/test.esp32-c3-idf.yaml b/tests/components/wake_on_lan/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/wake_on_lan/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/wake_on_lan/test.esp32-idf.yaml b/tests/components/wake_on_lan/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/wake_on_lan/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From bff24e297774d7f79deea30c9cdaed4bc23e47d4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 29 May 2024 00:05:19 -0500 Subject: [PATCH 1815/2607] Fix a bunch of components for IDF 5 compatibility and #6802 (#6805) --- esphome/components/ade7880/ade7880.cpp | 1 + .../components/ade7953_base/ade7953_base.cpp | 1 + esphome/components/ags10/ags10.cpp | 4 +- .../components/ct_clamp/ct_clamp_sensor.cpp | 5 ++- .../fingerprint_grow/fingerprint_grow.cpp | 2 +- esphome/components/he60r/he60r.cpp | 7 ++-- esphome/components/htu31d/htu31d.cpp | 4 +- .../components/ina2xx_base/ina2xx_base.cpp | 8 ++-- esphome/components/jsn_sr04t/jsn_sr04t.cpp | 4 +- esphome/components/mhz19/mhz19.cpp | 1 + .../micro_wake_word/micro_wake_word.cpp | 3 +- .../remote_base/byronsx_protocol.cpp | 1 + .../remote_base/drayton_protocol.cpp | 2 + esphome/components/sonoff_d1/sonoff_d1.cpp | 3 +- esphome/components/weikai/weikai.cpp | 4 +- esphome/components/wl_134/wl_134.cpp | 4 +- esphome/components/xgzp68xx/xgzp68xx.cpp | 1 + .../remote_receiver/esp32-common.yaml | 40 +++++++++---------- 18 files changed, 55 insertions(+), 40 deletions(-) diff --git a/esphome/components/ade7880/ade7880.cpp b/esphome/components/ade7880/ade7880.cpp index a03f1227f1..4a45b3b321 100644 --- a/esphome/components/ade7880/ade7880.cpp +++ b/esphome/components/ade7880/ade7880.cpp @@ -10,6 +10,7 @@ #include "ade7880.h" #include "ade7880_registers.h" #include "esphome/core/log.h" + #include namespace esphome { diff --git a/esphome/components/ade7953_base/ade7953_base.cpp b/esphome/components/ade7953_base/ade7953_base.cpp index 79161c5676..2511b4e04c 100644 --- a/esphome/components/ade7953_base/ade7953_base.cpp +++ b/esphome/components/ade7953_base/ade7953_base.cpp @@ -1,5 +1,6 @@ #include "ade7953_base.h" #include "esphome/core/log.h" + #include namespace esphome { diff --git a/esphome/components/ags10/ags10.cpp b/esphome/components/ags10/ags10.cpp index dfaa00e2e9..422380da83 100644 --- a/esphome/components/ags10/ags10.cpp +++ b/esphome/components/ags10/ags10.cpp @@ -1,5 +1,7 @@ #include "ags10.h" +#include + namespace esphome { namespace ags10 { static const char *const TAG = "ags10"; @@ -35,7 +37,7 @@ void AGS10Component::setup() { auto resistance = this->read_resistance_(); if (resistance) { - ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08X", *resistance); + ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08" PRIX32, *resistance); if (this->resistance_ != nullptr) { this->resistance_->publish_state(*resistance); } diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.cpp b/esphome/components/ct_clamp/ct_clamp_sensor.cpp index d555befcde..0aa0258a9b 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.cpp +++ b/esphome/components/ct_clamp/ct_clamp_sensor.cpp @@ -1,6 +1,7 @@ #include "ct_clamp_sensor.h" #include "esphome/core/log.h" +#include #include namespace esphome { @@ -37,8 +38,8 @@ void CTClampSensor::update() { float rms_ac = 0; if (rms_ac_squared > 0) rms_ac = std::sqrt(rms_ac_squared); - ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac, - this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); + ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %" PRIu32 " different samples (%" PRIu32 " SPS)", + this->name_.c_str(), rms_ac, this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); this->publish_state(rms_ac); }); diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index 8f58db9159..c2cab368c9 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -377,7 +377,7 @@ uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) this->write((uint8_t) (wire_length >> 8)); this->write((uint8_t) (wire_length & 0xFF)); - uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND; + uint16_t sum = (wire_length >> 8) + (wire_length & 0xFF) + COMMAND; for (auto data : *p_data_buffer) { this->write(data); sum += data; diff --git a/esphome/components/he60r/he60r.cpp b/esphome/components/he60r/he60r.cpp index 96ad1f04be..05f3f528a5 100644 --- a/esphome/components/he60r/he60r.cpp +++ b/esphome/components/he60r/he60r.cpp @@ -1,6 +1,7 @@ #include "he60r.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" + #include namespace esphome { @@ -125,10 +126,10 @@ void HE60rCover::process_rx_(uint8_t data) { } void HE60rCover::update_() { - if (toggles_needed_ != 0) { + if (this->toggles_needed_ != 0) { if ((this->counter_++ & 0x3) == 0) { - toggles_needed_--; - ESP_LOGD(TAG, "Writing byte 0x30, still needed=%" PRIu32, toggles_needed_); + this->toggles_needed_--; + ESP_LOGD(TAG, "Writing byte 0x30, still needed=%" PRIu32, this->toggles_needed_); this->write_byte(TOGGLE_BYTE); } else { this->write_byte(QUERY_BYTE); diff --git a/esphome/components/htu31d/htu31d.cpp b/esphome/components/htu31d/htu31d.cpp index 928250a5b2..bf4689d837 100644 --- a/esphome/components/htu31d/htu31d.cpp +++ b/esphome/components/htu31d/htu31d.cpp @@ -12,6 +12,8 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace htu31d { @@ -204,7 +206,7 @@ uint32_t HTU31DComponent::read_serial_num_() { return 0; } - ESP_LOGD(TAG, "Found serial: 0x%X", serial); + ESP_LOGD(TAG, "Found serial: 0x%" PRIX32, serial); return serial; } diff --git a/esphome/components/ina2xx_base/ina2xx_base.cpp b/esphome/components/ina2xx_base/ina2xx_base.cpp index 5d947d0537..924bf91e5e 100644 --- a/esphome/components/ina2xx_base/ina2xx_base.cpp +++ b/esphome/components/ina2xx_base/ina2xx_base.cpp @@ -483,7 +483,7 @@ bool INA2XX::read_power_w_(float &power_out) { uint64_t power_reading{0}; auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_POWER, 3, power_reading); - ESP_LOGV(TAG, "read_power_w_ ret=%s, reading_lsb=%d", OKFAILED(ret), (uint32_t) power_reading); + ESP_LOGV(TAG, "read_power_w_ ret=%s, reading_lsb=%" PRIu32, OKFAILED(ret), (uint32_t) power_reading); if (ret) { power_out = this->cfg_.power_coeff * this->current_lsb_ * (float) power_reading; } @@ -503,8 +503,8 @@ bool INA2XX::read_energy_(double &joules_out, double &watt_hours_out) { uint64_t previous_energy = this->energy_overflows_count_ * (((uint64_t) 1) << 40); auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_ENERGY, 5, joules_reading); - ESP_LOGV(TAG, "read_energy_j_ ret=%s, reading_lsb=0x%" PRIX64 ", current_lsb=%f, overflow_cnt=%d", OKFAILED(ret), - joules_reading, this->current_lsb_, this->energy_overflows_count_); + ESP_LOGV(TAG, "read_energy_j_ ret=%s, reading_lsb=0x%" PRIX64 ", current_lsb=%f, overflow_cnt=%" PRIu32, + OKFAILED(ret), joules_reading, this->current_lsb_, this->energy_overflows_count_); if (ret) { joules_out = this->cfg_.energy_coeff * this->current_lsb_ * (double) joules_reading + (double) previous_energy; watt_hours_out = joules_out / 3600.0; @@ -528,7 +528,7 @@ bool INA2XX::read_charge_(double &coulombs_out, double &_hours_out) { auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_CHARGE, 5, raw); coulombs_reading = this->two_complement_(raw, 40); - ESP_LOGV(TAG, "read_charge_c_ ret=%d, curr_charge=%f + 39-bit overflow_cnt=%d", ret, coulombs_reading, + ESP_LOGV(TAG, "read_charge_c_ ret=%d, curr_charge=%f + 39-bit overflow_cnt=%" PRIu32, ret, coulombs_reading, this->charge_overflows_count_); if (ret) { coulombs_out = this->current_lsb_ * (double) coulombs_reading + (double) previous_charge; diff --git a/esphome/components/jsn_sr04t/jsn_sr04t.cpp b/esphome/components/jsn_sr04t/jsn_sr04t.cpp index 70e21a137d..b96bf8f762 100644 --- a/esphome/components/jsn_sr04t/jsn_sr04t.cpp +++ b/esphome/components/jsn_sr04t/jsn_sr04t.cpp @@ -2,8 +2,6 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include - // Very basic support for JSN_SR04T V3.0 distance sensor in mode 2 namespace esphome { @@ -38,7 +36,7 @@ void Jsnsr04tComponent::check_buffer_() { uint16_t distance = encode_uint16(this->buffer_[1], this->buffer_[2]); if (distance > 250) { float meters = distance / 1000.0f; - ESP_LOGV(TAG, "Distance from sensor: %" PRIu32 "mm, %.3fm", distance, meters); + ESP_LOGV(TAG, "Distance from sensor: %umm, %.3fm", distance, meters); this->publish_state(meters); } else { ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str()); diff --git a/esphome/components/mhz19/mhz19.cpp b/esphome/components/mhz19/mhz19.cpp index 574aee1bd5..c3c8120362 100644 --- a/esphome/components/mhz19/mhz19.cpp +++ b/esphome/components/mhz19/mhz19.cpp @@ -1,5 +1,6 @@ #include "mhz19.h" #include "esphome/core/log.h" + #include namespace esphome { diff --git a/esphome/components/micro_wake_word/micro_wake_word.cpp b/esphome/components/micro_wake_word/micro_wake_word.cpp index f637f8b2bb..5a89708127 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.cpp +++ b/esphome/components/micro_wake_word/micro_wake_word.cpp @@ -20,6 +20,7 @@ #include #include +#include #include namespace esphome { @@ -316,7 +317,7 @@ float MicroWakeWord::perform_streaming_inference_() { return false; } - ESP_LOGV(TAG, "Streaming Inference Latency=%u ms", (millis() - prior_invoke)); + ESP_LOGV(TAG, "Streaming Inference Latency=%" PRIu32 " ms", (millis() - prior_invoke)); TfLiteTensor *output = this->streaming_interpreter_->output(0); diff --git a/esphome/components/remote_base/byronsx_protocol.cpp b/esphome/components/remote_base/byronsx_protocol.cpp index 2d4c60ff8b..6bfa4b7ff9 100644 --- a/esphome/components/remote_base/byronsx_protocol.cpp +++ b/esphome/components/remote_base/byronsx_protocol.cpp @@ -1,5 +1,6 @@ #include "byronsx_protocol.h" #include "esphome/core/log.h" + #include namespace esphome { diff --git a/esphome/components/remote_base/drayton_protocol.cpp b/esphome/components/remote_base/drayton_protocol.cpp index 73c0fb116c..da2e985af0 100644 --- a/esphome/components/remote_base/drayton_protocol.cpp +++ b/esphome/components/remote_base/drayton_protocol.cpp @@ -1,6 +1,8 @@ #include "drayton_protocol.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace remote_base { diff --git a/esphome/components/sonoff_d1/sonoff_d1.cpp b/esphome/components/sonoff_d1/sonoff_d1.cpp index 6ae80296fd..e70ec7b70d 100644 --- a/esphome/components/sonoff_d1/sonoff_d1.cpp +++ b/esphome/components/sonoff_d1/sonoff_d1.cpp @@ -128,7 +128,8 @@ bool SonoffD1Output::read_ack_(const uint8_t *cmd, const size_t len) { // Expected acknowledgement from rf chip uint8_t ref_buffer[7] = {0xAA, 0x55, cmd[2], cmd[3], 0x00, 0x00, 0x00}; uint8_t buffer[sizeof(ref_buffer)] = {0}; - uint32_t pos = 0, buf_len = sizeof(ref_buffer); + uint32_t pos = 0; + size_t buf_len = sizeof(ref_buffer); // Update the reference checksum this->populate_checksum_(ref_buffer, sizeof(ref_buffer)); diff --git a/esphome/components/weikai/weikai.cpp b/esphome/components/weikai/weikai.cpp index a04bc0a574..00bce9bcff 100644 --- a/esphome/components/weikai/weikai.cpp +++ b/esphome/components/weikai/weikai.cpp @@ -375,8 +375,8 @@ void WeikaiChannel::set_baudrate_() { this->parent_->page1_ = false; // switch back to page 0 this->reg(WKREG_SPAGE) = 0; - ESP_LOGV(TAG, " Crystal=%d baudrate=%d => registers [%d %d %d]", this->parent_->crystal_, this->baud_rate_, - baud_high, baud_low, baud_dec); + ESP_LOGV(TAG, " Crystal=%" PRId32 " baudrate=%" PRId32 " => registers [%d %d %d]", this->parent_->crystal_, + this->baud_rate_, baud_high, baud_low, baud_dec); } inline bool WeikaiChannel::tx_fifo_is_not_empty_() { return this->reg(WKREG_FSR) & FSR_TFDAT; } diff --git a/esphome/components/wl_134/wl_134.cpp b/esphome/components/wl_134/wl_134.cpp index 3ffa0c63ce..403f8bd1b3 100644 --- a/esphome/components/wl_134/wl_134.cpp +++ b/esphome/components/wl_134/wl_134.cpp @@ -1,6 +1,8 @@ #include "wl_134.h" #include "esphome/core/log.h" +#include + namespace esphome { namespace wl_134 { @@ -71,7 +73,7 @@ Wl134Component::Rfid134Error Wl134Component::read_packet_() { ESP_LOGV(TAG, "isData: %s", reading.isData ? "true" : "false"); ESP_LOGV(TAG, "isAnimal: %s", reading.isAnimal ? "true" : "false"); ESP_LOGV(TAG, "Reserved0: %d", reading.reserved0); - ESP_LOGV(TAG, "Reserved1: %d", reading.reserved1); + ESP_LOGV(TAG, "Reserved1: %" PRId32, reading.reserved1); char buf[20]; sprintf(buf, "%03d%012lld", reading.country, reading.id); diff --git a/esphome/components/xgzp68xx/xgzp68xx.cpp b/esphome/components/xgzp68xx/xgzp68xx.cpp index dff00fb696..ad6217845d 100644 --- a/esphome/components/xgzp68xx/xgzp68xx.cpp +++ b/esphome/components/xgzp68xx/xgzp68xx.cpp @@ -3,6 +3,7 @@ #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/components/i2c/i2c.h" + #include namespace esphome { diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index c3987f8cd9..7e5d2cce32 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -32,8 +32,8 @@ remote_receiver: on_coolix: then: - logger.log: - format: "on_coolix: %u %u" - args: ["x.first", "x.second"] + format: "on_coolix: %lu %lu" + args: ["long(x.first)", "long(x.second)"] on_dish: then: - logger.log: @@ -52,13 +52,13 @@ remote_receiver: on_jvc: then: - logger.log: - format: "on_jvc: %u" - args: ["x.data"] + format: "on_jvc: %lu" + args: ["long(x.data)"] on_keeloq: then: - logger.log: - format: "on_keeloq: %u %u %u" - args: ["x.encrypted", "x.address", "x.command"] + format: "on_keeloq: %lu %lu %u" + args: ["long(x.encrypted)", "long(x.address)", "x.command"] on_haier: then: - logger.log: @@ -67,13 +67,13 @@ remote_receiver: on_lg: then: - logger.log: - format: "on_lg: %u %u" - args: ["x.data", "x.nbits"] + format: "on_lg: %lu %u" + args: ["long(x.data)", "x.nbits"] on_magiquest: then: - logger.log: - format: "on_magiquest: %u %u" - args: ["x.magnitude", "x.wand_id"] + format: "on_magiquest: %u %lu" + args: ["x.magnitude", "long(x.wand_id)"] on_midea: then: - logger.log: @@ -87,13 +87,13 @@ remote_receiver: on_nexa: then: - logger.log: - format: "on_nexa: %u %u %u %u %u" - args: ["x.device", "x.group", "x.state", "x.channel", "x.level"] + format: "on_nexa: %lu %u %u %u %u" + args: ["long(x.device)", "x.group", "x.state", "x.channel", "x.level"] on_panasonic: then: - logger.log: - format: "on_panasonic: %u %u" - args: ["x.address", "x.command"] + format: "on_panasonic: %u %lu" + args: ["x.address", "long(x.command)"] on_pioneer: then: - logger.log: @@ -107,8 +107,8 @@ remote_receiver: on_raw: then: - logger.log: - format: "on_raw: %u" - args: ["x.front()"] + format: "on_raw: %lu" + args: ["long(x.front())"] on_rc5: then: - logger.log: @@ -132,13 +132,13 @@ remote_receiver: on_samsung36: then: - logger.log: - format: "on_samsung36: %u %u" - args: ["x.address", "x.command"] + format: "on_samsung36: %u %lu" + args: ["x.address", "long(x.command)"] on_sony: then: - logger.log: - format: "on_sony: %u %u" - args: ["x.data", "x.nbits"] + format: "on_sony: %lu %u" + args: ["long(x.data)", "x.nbits"] on_toshiba_ac: then: - logger.log: From 60433c5e645690f358be94c2e3136aecfd84fa59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 17:09:13 +1200 Subject: [PATCH 1816/2607] Bump docker/login-action from 3.1.0 to 3.2.0 (#6823) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47dc217bf7..563d485b6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,12 +96,12 @@ jobs: uses: docker/setup-qemu-action@v3.0.0 - name: Log in to docker hub - uses: docker/login-action@v3.1.0 + uses: docker/login-action@v3.2.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry - uses: docker/login-action@v3.1.0 + uses: docker/login-action@v3.2.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -188,13 +188,13 @@ jobs: - name: Log in to docker hub if: matrix.registry == 'dockerhub' - uses: docker/login-action@v3.1.0 + uses: docker/login-action@v3.2.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry if: matrix.registry == 'ghcr' - uses: docker/login-action@v3.1.0 + uses: docker/login-action@v3.2.0 with: registry: ghcr.io username: ${{ github.actor }} From 6d5d382f3db98e2a9997fed9e62811f91bad06f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 17:10:47 +1200 Subject: [PATCH 1817/2607] Bump pytest-cov from 4.1.0 to 5.0.0 (#6580) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index ae833841ca..0052e7545c 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -6,7 +6,7 @@ pre-commit # Unit tests pytest==8.2.0 -pytest-cov==4.1.0 +pytest-cov==5.0.0 pytest-mock==3.14.0 pytest-asyncio==0.23.6 asyncmock==0.4.2 From 439fd9471863e4bf12cdc5e11b098ab0b7b96874 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 17:11:02 +1200 Subject: [PATCH 1818/2607] Bump peter-evans/create-pull-request from 6.0.4 to 6.0.5 (#6635) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 9a8c9d1753..e65e851f3c 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.4 + uses: peter-evans/create-pull-request@v6.0.5 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From 5ae32e81c360a73f7ebe14d330d6e9d58eac324a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 17:11:34 +1200 Subject: [PATCH 1819/2607] Bump black from 24.4.0 to 24.4.2 (#6646) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 418716e4f4..74acfa1c1d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.2.0 + rev: 24.4.2 hooks: - id: black args: diff --git a/requirements_test.txt b/requirements_test.txt index 0052e7545c..94abe1cd76 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==3.1.0 flake8==7.0.0 # also change in .pre-commit-config.yaml when updating -black==24.4.0 # also change in .pre-commit-config.yaml when updating +black==24.4.2 # also change in .pre-commit-config.yaml when updating pyupgrade==3.15.2 # also change in .pre-commit-config.yaml when updating pre-commit From 854d3f2e4a919c27f723d940295f0adec1614168 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 13:09:19 +1200 Subject: [PATCH 1820/2607] [voice_assistant] Timers (#6821) Co-authored-by: Keith Burzinski --- esphome/components/api/api.proto | 19 ++++ esphome/components/api/api_connection.cpp | 9 ++ esphome/components/api/api_connection.h | 1 + esphome/components/api/api_pb2.cpp | 92 +++++++++++++++++++ esphome/components/api/api_pb2.h | 23 +++++ esphome/components/api/api_pb2_service.cpp | 13 +++ esphome/components/api/api_pb2_service.h | 3 + .../components/voice_assistant/__init__.py | 66 +++++++++++++ .../voice_assistant/voice_assistant.cpp | 53 +++++++++++ .../voice_assistant/voice_assistant.h | 42 +++++++++ 10 files changed, 321 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 774ca7ed9b..0becec2348 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1517,6 +1517,25 @@ message VoiceAssistantAudio { bool end = 2; } +enum VoiceAssistantTimerEvent { + VOICE_ASSISTANT_TIMER_STARTED = 0; + VOICE_ASSISTANT_TIMER_UPDATED = 1; + VOICE_ASSISTANT_TIMER_CANCELLED = 2; + VOICE_ASSISTANT_TIMER_FINISHED = 3; +} + +message VoiceAssistantTimerEventResponse { + option (id) = 115; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + VoiceAssistantTimerEvent event_type = 1; + string timer_id = 2; + string name = 3; + uint32 total_seconds = 4; + uint32 seconds_left = 5; + bool is_active = 6; +} // ==================== ALARM CONTROL PANEL ==================== enum AlarmControlPanelState { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 2804dba31f..253f04aa39 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1193,6 +1193,15 @@ void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &msg) { voice_assistant::global_voice_assistant->on_audio(msg); } }; +void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return; + } + + voice_assistant::global_voice_assistant->on_timer_event(msg); + } +}; #endif diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index ee466c5d10..293da17fa4 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -150,6 +150,7 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; + void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index a48087e348..9db6482c49 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -475,6 +475,22 @@ template<> const char *proto_enum_to_string(enums::V } #endif #ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::VoiceAssistantTimerEvent value) { + switch (value) { + case enums::VOICE_ASSISTANT_TIMER_STARTED: + return "VOICE_ASSISTANT_TIMER_STARTED"; + case enums::VOICE_ASSISTANT_TIMER_UPDATED: + return "VOICE_ASSISTANT_TIMER_UPDATED"; + case enums::VOICE_ASSISTANT_TIMER_CANCELLED: + return "VOICE_ASSISTANT_TIMER_CANCELLED"; + case enums::VOICE_ASSISTANT_TIMER_FINISHED: + return "VOICE_ASSISTANT_TIMER_FINISHED"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef HAS_PROTO_MESSAGE_DUMP template<> const char *proto_enum_to_string(enums::AlarmControlPanelState value) { switch (value) { case enums::ALARM_STATE_DISARMED: @@ -6857,6 +6873,82 @@ void VoiceAssistantAudio::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->event_type = value.as_enum(); + return true; + } + case 4: { + this->total_seconds = value.as_uint32(); + return true; + } + case 5: { + this->seconds_left = value.as_uint32(); + return true; + } + case 6: { + this->is_active = value.as_bool(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantTimerEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->timer_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + default: + return false; + } +} +void VoiceAssistantTimerEventResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_enum(1, this->event_type); + buffer.encode_string(2, this->timer_id); + buffer.encode_string(3, this->name); + buffer.encode_uint32(4, this->total_seconds); + buffer.encode_uint32(5, this->seconds_left); + buffer.encode_bool(6, this->is_active); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantTimerEventResponse {\n"); + out.append(" event_type: "); + out.append(proto_enum_to_string(this->event_type)); + out.append("\n"); + + out.append(" timer_id: "); + out.append("'").append(this->timer_id).append("'"); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" total_seconds: "); + sprintf(buffer, "%" PRIu32, this->total_seconds); + out.append(buffer); + out.append("\n"); + + out.append(" seconds_left: "); + sprintf(buffer, "%" PRIu32, this->seconds_left); + out.append(buffer); + out.append("\n"); + + out.append(" is_active: "); + out.append(YESNO(this->is_active)); + out.append("\n"); + out.append("}"); +} +#endif bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 807b150d82..54cbd20559 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -191,6 +191,12 @@ enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_TTS_STREAM_START = 98, VOICE_ASSISTANT_TTS_STREAM_END = 99, }; +enum VoiceAssistantTimerEvent : uint32_t { + VOICE_ASSISTANT_TIMER_STARTED = 0, + VOICE_ASSISTANT_TIMER_UPDATED = 1, + VOICE_ASSISTANT_TIMER_CANCELLED = 2, + VOICE_ASSISTANT_TIMER_FINISHED = 3, +}; enum AlarmControlPanelState : uint32_t { ALARM_STATE_DISARMED = 0, ALARM_STATE_ARMED_HOME = 1, @@ -1775,6 +1781,23 @@ class VoiceAssistantAudio : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantTimerEventResponse : public ProtoMessage { + public: + enums::VoiceAssistantTimerEvent event_type{}; + std::string timer_id{}; + std::string name{}; + uint32_t total_seconds{0}; + uint32_t seconds_left{0}; + bool is_active{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 093fe917e0..7c95bb03ad 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -484,6 +484,8 @@ bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAud return this->send_message_(msg, 106); } #endif +#ifdef USE_VOICE_ASSISTANT +#endif #ifdef USE_ALARM_CONTROL_PANEL bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( const ListEntitiesAlarmControlPanelResponse &msg) { @@ -1093,6 +1095,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str()); #endif this->on_date_time_command_request(msg); +#endif + break; + } + case 115: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantTimerEventResponse msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_timer_event_response(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 196d904aca..2f8a2b3def 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -244,6 +244,9 @@ class APIServerConnectionBase : public ProtoService { bool send_voice_assistant_audio(const VoiceAssistantAudio &msg); virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){}; #endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){}; +#endif #ifdef USE_ALARM_CONTROL_PANEL bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); #endif diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index 3ba0c58ce4..c18f0a6850 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -44,6 +44,12 @@ CONF_VOLUME_MULTIPLIER = "volume_multiplier" CONF_WAKE_WORD = "wake_word" +CONF_ON_TIMER_STARTED = "on_timer_started" +CONF_ON_TIMER_UPDATED = "on_timer_updated" +CONF_ON_TIMER_CANCELLED = "on_timer_cancelled" +CONF_ON_TIMER_FINISHED = "on_timer_finished" +CONF_ON_TIMER_TICK = "on_timer_tick" + voice_assistant_ns = cg.esphome_ns.namespace("voice_assistant") VoiceAssistant = voice_assistant_ns.class_("VoiceAssistant", cg.Component) @@ -64,6 +70,8 @@ ConnectedCondition = voice_assistant_ns.class_( "ConnectedCondition", automation.Condition, cg.Parented.template(VoiceAssistant) ) +Timer = voice_assistant_ns.struct("Timer") + def tts_stream_validate(config): if CONF_SPEAKER not in config and ( @@ -131,6 +139,21 @@ CONFIG_SCHEMA = cv.All( single=True ), cv.Optional(CONF_ON_IDLE): automation.validate_automation(single=True), + cv.Optional(CONF_ON_TIMER_STARTED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_TIMER_UPDATED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_TIMER_CANCELLED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_TIMER_FINISHED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_TIMER_TICK): automation.validate_automation( + single=True + ), } ).extend(cv.COMPONENT_SCHEMA), tts_stream_validate, @@ -270,6 +293,49 @@ async def to_code(config): config[CONF_ON_IDLE], ) + has_timers = False + if on_timer_started := config.get(CONF_ON_TIMER_STARTED): + await automation.build_automation( + var.get_timer_started_trigger(), + [(Timer, "timer")], + on_timer_started, + ) + has_timers = True + + if on_timer_updated := config.get(CONF_ON_TIMER_UPDATED): + await automation.build_automation( + var.get_timer_updated_trigger(), + [(Timer, "timer")], + on_timer_updated, + ) + has_timers = True + + if on_timer_cancelled := config.get(CONF_ON_TIMER_CANCELLED): + await automation.build_automation( + var.get_timer_cancelled_trigger(), + [(Timer, "timer")], + on_timer_cancelled, + ) + has_timers = True + + if on_timer_finished := config.get(CONF_ON_TIMER_FINISHED): + await automation.build_automation( + var.get_timer_finished_trigger(), + [(Timer, "timer")], + on_timer_finished, + ) + has_timers = True + + if on_timer_tick := config.get(CONF_ON_TIMER_TICK): + await automation.build_automation( + var.get_timer_tick_trigger(), + [(cg.std_vector.template(Timer), "timers")], + on_timer_tick, + ) + has_timers = True + + cg.add(var.set_has_timers(has_timers)) + cg.add_define("USE_VOICE_ASSISTANT") diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 712a0ab137..0bd8194190 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -798,12 +798,65 @@ void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { this->speaker_buffer_index_ += msg.data.length(); this->speaker_buffer_size_ += msg.data.length(); this->speaker_bytes_received_ += msg.data.length(); + ESP_LOGD(TAG, "Received audio: %d bytes from API", msg.data.length()); } else { ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); } #endif } +void VoiceAssistant::on_timer_event(const api::VoiceAssistantTimerEventResponse &msg) { + Timer timer = { + .id = msg.timer_id, + .name = msg.name, + .total_seconds = msg.total_seconds, + .seconds_left = msg.seconds_left, + .is_active = msg.is_active, + }; + this->timers_[timer.id] = timer; + ESP_LOGD(TAG, "Timer Event"); + ESP_LOGD(TAG, " Type: %d", msg.event_type); + ESP_LOGD(TAG, " %s", timer.to_string().c_str()); + + switch (msg.event_type) { + case api::enums::VOICE_ASSISTANT_TIMER_STARTED: + this->timer_started_trigger_->trigger(timer); + break; + case api::enums::VOICE_ASSISTANT_TIMER_UPDATED: + this->timer_updated_trigger_->trigger(timer); + break; + case api::enums::VOICE_ASSISTANT_TIMER_CANCELLED: + this->timer_cancelled_trigger_->trigger(timer); + this->timers_.erase(timer.id); + break; + case api::enums::VOICE_ASSISTANT_TIMER_FINISHED: + this->timer_finished_trigger_->trigger(timer); + this->timers_.erase(timer.id); + break; + } + + if (this->timers_.empty()) { + this->cancel_interval("timer-event"); + this->timer_tick_running_ = false; + } else if (!this->timer_tick_running_) { + this->set_interval("timer-event", 1000, [this]() { this->timer_tick_(); }); + this->timer_tick_running_ = true; + } +} + +void VoiceAssistant::timer_tick_() { + std::vector res; + res.reserve(this->timers_.size()); + for (auto &pair : this->timers_) { + auto &timer = pair.second; + if (timer.is_active && timer.seconds_left > 0) { + timer.seconds_left--; + } + res.push_back(timer); + } + this->timer_tick_trigger_->trigger(res); +} + VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace voice_assistant diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 17141365d4..a160972e22 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -24,6 +24,9 @@ #include #endif +#include +#include + namespace esphome { namespace voice_assistant { @@ -36,6 +39,7 @@ enum VoiceAssistantFeature : uint32_t { FEATURE_VOICE_ASSISTANT = 1 << 0, FEATURE_SPEAKER = 1 << 1, FEATURE_API_AUDIO = 1 << 2, + FEATURE_TIMERS = 1 << 3, }; enum class State { @@ -59,6 +63,20 @@ enum AudioMode : uint8_t { AUDIO_MODE_API, }; +struct Timer { + std::string id; + std::string name; + uint32_t total_seconds; + uint32_t seconds_left; + bool is_active; + + std::string to_string() const { + return str_sprintf("Timer(id=%s, name=%s, total_seconds=%" PRIu32 ", seconds_left=%" PRIu32 ", is_active=%s)", + this->id.c_str(), this->name.c_str(), this->total_seconds, this->seconds_left, + YESNO(this->is_active)); + } +}; + class VoiceAssistant : public Component { public: void setup() override; @@ -100,6 +118,11 @@ class VoiceAssistant : public Component { flags |= VoiceAssistantFeature::FEATURE_SPEAKER; } #endif + + if (this->has_timers_) { + flags |= VoiceAssistantFeature::FEATURE_TIMERS; + } + return flags; } @@ -108,6 +131,7 @@ class VoiceAssistant : public Component { void on_event(const api::VoiceAssistantEventResponse &msg); void on_audio(const api::VoiceAssistantAudio &msg); + void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg); bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } @@ -150,6 +174,14 @@ class VoiceAssistant : public Component { void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; } + Trigger *get_timer_started_trigger() const { return this->timer_started_trigger_; } + Trigger *get_timer_updated_trigger() const { return this->timer_updated_trigger_; } + Trigger *get_timer_cancelled_trigger() const { return this->timer_cancelled_trigger_; } + Trigger *get_timer_finished_trigger() const { return this->timer_finished_trigger_; } + Trigger> *get_timer_tick_trigger() const { return this->timer_tick_trigger_; } + void set_has_timers(bool has_timers) { this->has_timers_ = has_timers; } + const std::unordered_map &get_timers() const { return this->timers_; } + protected: bool allocate_buffers_(); void clear_buffers_(); @@ -186,6 +218,16 @@ class VoiceAssistant : public Component { api::APIConnection *api_client_{nullptr}; + std::unordered_map timers_; + void timer_tick_(); + Trigger *timer_started_trigger_ = new Trigger(); + Trigger *timer_finished_trigger_ = new Trigger(); + Trigger *timer_updated_trigger_ = new Trigger(); + Trigger *timer_cancelled_trigger_ = new Trigger(); + Trigger> *timer_tick_trigger_ = new Trigger>(); + bool has_timers_{false}; + bool timer_tick_running_{false}; + microphone::Microphone *mic_{nullptr}; #ifdef USE_SPEAKER void write_speaker_(); From a7fc1a62981cf6ae51c2f44d71185c3d89071927 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Thu, 30 May 2024 03:54:20 +0200 Subject: [PATCH 1821/2607] [web_server] add entity sorting for v3 (#6445) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../alarm_control_panel/__init__.py | 7 + esphome/components/binary_sensor/__init__.py | 127 ++++++----- esphome/components/button/__init__.py | 31 ++- esphome/components/climate/__init__.py | 185 ++++++++-------- esphome/components/cover/__init__.py | 67 +++--- esphome/components/datetime/__init__.py | 30 ++- esphome/components/fan/__init__.py | 137 ++++++------ esphome/components/light/__init__.py | 59 ++--- esphome/components/lock/__init__.py | 39 ++-- esphome/components/number/__init__.py | 50 +++-- esphome/components/select/__init__.py | 31 ++- esphome/components/sensor/__init__.py | 87 ++++---- esphome/components/switch/__init__.py | 43 ++-- esphome/components/text/__init__.py | 33 +-- esphome/components/text_sensor/__init__.py | 51 +++-- esphome/components/valve/__init__.py | 55 +++-- esphome/components/web_server/__init__.py | 58 +++++ esphome/components/web_server/web_server.cpp | 204 ++++++++++++------ esphome/components/web_server/web_server.h | 9 + esphome/const.py | 2 + 20 files changed, 802 insertions(+), 503 deletions(-) diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 35d239c267..7ad4358011 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -1,5 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.components import web_server from esphome import automation from esphome.automation import maybe_simple_id from esphome.core import CORE, coroutine_with_priority @@ -8,6 +9,7 @@ from esphome.const import ( CONF_ON_STATE, CONF_TRIGGER_ID, CONF_CODE, + CONF_WEB_SERVER_ID, ) from esphome.cpp_helpers import setup_entity @@ -76,6 +78,8 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_( ) ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( + web_server.WEBSERVER_SORTING_SCHEMA +).extend( { cv.GenerateID(): cv.declare_id(AlarmControlPanel), cv.Optional(CONF_ON_STATE): automation.validate_automation( @@ -185,6 +189,9 @@ async def setup_alarm_control_panel_core_(var, config): for conf in config.get(CONF_ON_READY, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) async def register_alarm_control_panel(var, config): diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 2f788d7103..11a1887206 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -4,7 +4,7 @@ from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity from esphome import automation, core from esphome.automation import Condition, maybe_simple_id -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DELAY, CONF_DEVICE_CLASS, @@ -27,6 +27,7 @@ from esphome.const import ( CONF_TIMING, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY_CHARGING, DEVICE_CLASS_CARBON_MONOXIDE, @@ -385,70 +386,76 @@ def validate_click_timing(value): return value -BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(BinarySensor), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( - mqtt.MQTTBinarySensorComponent - ), - cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean, - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_FILTERS): validate_filters, - cv.Optional(CONF_ON_PRESS): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger), - } - ), - cv.Optional(CONF_ON_RELEASE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger), - } - ), - cv.Optional(CONF_ON_CLICK): cv.All( - automation.validate_automation( +BINARY_SENSOR_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(BinarySensor), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( + mqtt.MQTTBinarySensorComponent + ), + cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean, + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_FILTERS): validate_filters, + cv.Optional(CONF_ON_PRESS): automation.validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger), } ), - validate_click_timing, - ), - cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All( - automation.validate_automation( + cv.Optional(CONF_ON_RELEASE): automation.validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), - cv.Optional( - CONF_MIN_LENGTH, default="50ms" - ): cv.positive_time_period_milliseconds, - cv.Optional( - CONF_MAX_LENGTH, default="350ms" - ): cv.positive_time_period_milliseconds, + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger), } ), - validate_click_timing, - ), - cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger), - cv.Required(CONF_TIMING): cv.All( - [parse_multi_click_timing_str], validate_multi_click_timing + cv.Optional(CONF_ON_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } ), - cv.Optional( - CONF_INVALID_COOLDOWN, default="1s" - ): cv.positive_time_period_milliseconds, - } - ), - cv.Optional(CONF_ON_STATE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), - } - ), - } + validate_click_timing, + ), + cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All( + automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + DoubleClickTrigger + ), + cv.Optional( + CONF_MIN_LENGTH, default="50ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_MAX_LENGTH, default="350ms" + ): cv.positive_time_period_milliseconds, + } + ), + validate_click_timing, + ), + cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger), + cv.Required(CONF_TIMING): cv.All( + [parse_multi_click_timing_str], validate_multi_click_timing + ), + cv.Optional( + CONF_INVALID_COOLDOWN, default="1s" + ): cv.positive_time_period_milliseconds, + } + ), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), + } + ), + } + ) ) _UNDEF = object() @@ -536,6 +543,10 @@ async def setup_binary_sensor_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_binary_sensor(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 5dcbf7ad01..773ab9d37f 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_ON_PRESS, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, @@ -43,16 +44,20 @@ ButtonPressTrigger = button_ns.class_( validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") -BUTTON_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_ON_PRESS): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger), - } - ), - } +BUTTON_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_ON_PRESS): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger), + } + ), + } + ) ) _UNDEF = object() @@ -92,6 +97,10 @@ async def setup_button_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_button(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index 7b0a27feae..ccd7a3da4e 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.cpp_helpers import setup_entity from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ACTION_STATE_TOPIC, CONF_AWAY, @@ -44,6 +44,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_VISUAL, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, ) from esphome.core import CORE, coroutine_with_priority @@ -150,93 +151,97 @@ VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any( ), ) -CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(Climate), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent), - cv.Optional(CONF_VISUAL, default={}): cv.Schema( - { - cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature, - cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature, - cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA, - cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int, - cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int, - } - ), - cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_MODE_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_ON_CONTROL): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger), - } - ), - cv.Optional(CONF_ON_STATE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), - } - ), - } +CLIMATE_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(Climate), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent), + cv.Optional(CONF_VISUAL, default={}): cv.Schema( + { + cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature, + cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature, + cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA, + cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int, + cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int, + } + ), + cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_MODE_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_ON_CONTROL): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger), + } + ), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), + } + ), + } + ) ) @@ -403,6 +408,10 @@ async def setup_climate_core_(var, config): trigger, [(ClimateCall.operator("ref"), "x")], conf ) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_climate(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 8e0371017d..313b2c5928 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id, Condition -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ID, CONF_DEVICE_CLASS, @@ -16,6 +16,7 @@ from esphome.const import ( CONF_TILT_STATE_TOPIC, CONF_STOP, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_TRIGGER_ID, DEVICE_CLASS_AWNING, DEVICE_CLASS_BLIND, @@ -88,34 +89,38 @@ CoverClosedTrigger = cover_ns.class_( CONF_ON_CLOSED = "on_closed" -COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(Cover), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent), - cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), - cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_TILT_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_ON_OPEN): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger), - } - ), - cv.Optional(CONF_ON_CLOSED): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger), - } - ), - } +COVER_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(Cover), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent), + cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), + cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_TILT_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_ON_OPEN): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger), + } + ), + cv.Optional(CONF_ON_CLOSED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger), + } + ), + } + ) ) @@ -132,6 +137,10 @@ async def setup_cover_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 262f1e2315..c118216a2d 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt, time +from esphome.components import mqtt, web_server, time from esphome.const import ( CONF_ID, CONF_ON_TIME, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_TYPE, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_DATE, CONF_DATETIME, CONF_TIME, @@ -63,16 +64,20 @@ DATETIME_MODES = [ ] -_DATETIME_SCHEMA = cv.Schema( - { - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), - } - ), - cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), - } -).extend(cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)) +_DATETIME_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), + } + ), + cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), + } + ) +) def date_schema(class_: MockObjClass) -> cv.Schema: @@ -128,6 +133,9 @@ async def setup_datetime_core_(var, config): if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) for conf in config.get(CONF_ON_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 14cf6cc9c9..847a59baa1 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -2,10 +2,11 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_OSCILLATING, CONF_OSCILLATION_COMMAND_TOPIC, CONF_OSCILLATION_STATE_TOPIC, @@ -79,67 +80,75 @@ FanPresetSetTrigger = fan_ns.class_( FanIsOnCondition = fan_ns.class_("FanIsOnCondition", automation.Condition.template()) FanIsOffCondition = fan_ns.class_("FanIsOffCondition", automation.Condition.template()) -FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(Fan), - cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( - RESTORE_MODES, upper=True, space="_" - ), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent), - cv.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_SPEED_LEVEL_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_SPEED_LEVEL_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_SPEED_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.publish_topic - ), - cv.Optional(CONF_SPEED_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_ON_STATE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanStateTrigger), - } - ), - cv.Optional(CONF_ON_TURN_ON): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOnTrigger), - } - ), - cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOffTrigger), - } - ), - cv.Optional(CONF_ON_DIRECTION_SET): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanDirectionSetTrigger), - } - ), - cv.Optional(CONF_ON_OSCILLATING_SET): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanOscillatingSetTrigger), - } - ), - cv.Optional(CONF_ON_SPEED_SET): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanSpeedSetTrigger), - } - ), - cv.Optional(CONF_ON_PRESET_SET): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanPresetSetTrigger), - } - ), - } +FAN_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(Fan), + cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( + RESTORE_MODES, upper=True, space="_" + ), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent), + cv.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_SPEED_LEVEL_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_SPEED_LEVEL_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_SPEED_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.publish_topic + ), + cv.Optional(CONF_SPEED_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanStateTrigger), + } + ), + cv.Optional(CONF_ON_TURN_ON): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOnTrigger), + } + ), + cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOffTrigger), + } + ), + cv.Optional(CONF_ON_DIRECTION_SET): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + FanDirectionSetTrigger + ), + } + ), + cv.Optional(CONF_ON_OSCILLATING_SET): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + FanOscillatingSetTrigger + ), + } + ), + cv.Optional(CONF_ON_SPEED_SET): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanSpeedSetTrigger), + } + ), + cv.Optional(CONF_ON_PRESET_SET): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanPresetSetTrigger), + } + ), + } + ) ) _PRESET_MODES_SCHEMA = cv.All( @@ -209,6 +218,10 @@ async def setup_fan_core_(var, config): if (speed_command_topic := config.get(CONF_SPEED_COMMAND_TOPIC)) is not None: cg.add(mqtt_.set_custom_speed_command_topic(speed_command_topic)) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + for conf in config.get(CONF_ON_STATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(Fan.operator("ptr"), "x")], conf) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index fdc4676758..161b4d8cd9 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv import esphome.automation as auto -from esphome.components import mqtt, power_supply +from esphome.components import mqtt, power_supply, web_server from esphome.const import ( CONF_COLOR_CORRECT, CONF_DEFAULT_TRANSITION_LENGTH, @@ -10,6 +10,7 @@ from esphome.const import ( CONF_GAMMA_CORRECT, CONF_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_POWER_SUPPLY, CONF_RESTORE_MODE, CONF_ON_TURN_OFF, @@ -56,29 +57,35 @@ RESTORE_MODES = { "RESTORE_AND_ON": LightRestoreMode.LIGHT_RESTORE_AND_ON, } -LIGHT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(LightState), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTJSONLightComponent), - cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( - RESTORE_MODES, upper=True, space="_" - ), - cv.Optional(CONF_ON_TURN_ON): auto.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightTurnOnTrigger), - } - ), - cv.Optional(CONF_ON_TURN_OFF): auto.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightTurnOffTrigger), - } - ), - cv.Optional(CONF_ON_STATE): auto.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger), - } - ), - } +LIGHT_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(LightState), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( + mqtt.MQTTJSONLightComponent + ), + cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( + RESTORE_MODES, upper=True, space="_" + ), + cv.Optional(CONF_ON_TURN_ON): auto.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightTurnOnTrigger), + } + ), + cv.Optional(CONF_ON_TURN_OFF): auto.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightTurnOffTrigger), + } + ), + cv.Optional(CONF_ON_STATE): auto.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger), + } + ), + } + ) ) BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend( @@ -173,6 +180,10 @@ async def setup_light_core_(light_var, output_var, config): mqtt_ = cg.new_Pvariable(mqtt_id, light_var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, light_var, config) + async def register_light(output_var, config): light_var = cg.new_Pvariable(config[CONF_ID], output_var) diff --git a/esphome/components/lock/__init__.py b/esphome/components/lock/__init__.py index 457ffa278a..c2d6054ed9 100644 --- a/esphome/components/lock/__init__.py +++ b/esphome/components/lock/__init__.py @@ -2,13 +2,14 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition, maybe_simple_id -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ID, CONF_ON_LOCK, CONF_ON_UNLOCK, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -30,20 +31,24 @@ LockCondition = lock_ns.class_("LockCondition", Condition) LockLockTrigger = lock_ns.class_("LockLockTrigger", automation.Trigger.template()) LockUnlockTrigger = lock_ns.class_("LockUnlockTrigger", automation.Trigger.template()) -LOCK_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTLockComponent), - cv.Optional(CONF_ON_LOCK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LockLockTrigger), - } - ), - cv.Optional(CONF_ON_UNLOCK): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LockUnlockTrigger), - } - ), - } +LOCK_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTLockComponent), + cv.Optional(CONF_ON_LOCK): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LockLockTrigger), + } + ), + cv.Optional(CONF_ON_UNLOCK): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LockUnlockTrigger), + } + ), + } + ) ) @@ -61,6 +66,10 @@ async def setup_lock_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_lock(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 8c3b15d22d..303535c138 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.components import mqtt +from esphome.components import web_server from esphome.const import ( CONF_ABOVE, CONF_BELOW, @@ -18,6 +19,7 @@ from esphome.const import ( CONF_VALUE, CONF_OPERATION, CONF_CYCLE, + CONF_WEB_SERVER_ID, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, DEVICE_CLASS_ATMOSPHERIC_PRESSURE, @@ -167,26 +169,30 @@ NUMBER_OPERATION_OPTIONS = { validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") validate_unit_of_measurement = cv.string_strict -NUMBER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTNumberComponent), - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(NumberStateTrigger), - } - ), - cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger), - cv.Optional(CONF_ABOVE): cv.templatable(cv.float_), - cv.Optional(CONF_BELOW): cv.templatable(cv.float_), - }, - cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW), - ), - cv.Optional(CONF_UNIT_OF_MEASUREMENT): validate_unit_of_measurement, - cv.Optional(CONF_MODE, default="AUTO"): cv.enum(NUMBER_MODES, upper=True), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - } +NUMBER_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTNumberComponent), + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(NumberStateTrigger), + } + ), + cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger), + cv.Optional(CONF_ABOVE): cv.templatable(cv.float_), + cv.Optional(CONF_BELOW): cv.templatable(cv.float_), + }, + cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW), + ), + cv.Optional(CONF_UNIT_OF_MEASUREMENT): validate_unit_of_measurement, + cv.Optional(CONF_MODE, default="AUTO"): cv.enum(NUMBER_MODES, upper=True), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + } + ) ) _UNDEF = object() @@ -248,6 +254,10 @@ async def setup_number_core_( mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_number( var, config, *, min_value: float, max_value: float, step: float diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index 1d234d5617..073fbef1d4 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ENTITY_CATEGORY, CONF_ICON, @@ -10,6 +10,7 @@ from esphome.const import ( CONF_OPTION, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_CYCLE, CONF_MODE, CONF_OPERATION, @@ -47,16 +48,20 @@ SELECT_OPERATION_OPTIONS = { } -SELECT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSelectComponent), - cv.GenerateID(): cv.declare_id(Select), - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SelectStateTrigger), - } - ), - } +SELECT_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSelectComponent), + cv.GenerateID(): cv.declare_id(Select), + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SelectStateTrigger), + } + ), + } + ) ) _UNDEF = object() @@ -99,6 +104,10 @@ async def setup_select_core_(var, config, *, options: list[str]): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_select(var, config, *, options: list[str]): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index ef5c4cc645..6077f5dc1f 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -3,7 +3,7 @@ import math import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DEVICE_CLASS, CONF_ABOVE, @@ -31,6 +31,7 @@ from esphome.const import ( CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_FORCE_UPDATE, CONF_VALUE, CONF_MIN_VALUE, @@ -252,43 +253,49 @@ validate_accuracy_decimals = cv.int_ validate_icon = cv.icon validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") -SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSensorComponent), - cv.GenerateID(): cv.declare_id(Sensor), - cv.Optional(CONF_UNIT_OF_MEASUREMENT): validate_unit_of_measurement, - cv.Optional(CONF_ACCURACY_DECIMALS): validate_accuracy_decimals, - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_STATE_CLASS): validate_state_class, - cv.Optional(CONF_ENTITY_CATEGORY): sensor_entity_category, - cv.Optional("last_reset_type"): cv.invalid( - "last_reset_type has been removed since 2021.9.0. state_class: total_increasing should be used for total values." - ), - cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean, - cv.Optional(CONF_EXPIRE_AFTER): cv.All( - cv.requires_component("mqtt"), - cv.Any(None, cv.positive_time_period_milliseconds), - ), - cv.Optional(CONF_FILTERS): validate_filters, - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorStateTrigger), - } - ), - cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorRawStateTrigger), - } - ), - cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger), - cv.Optional(CONF_ABOVE): cv.templatable(cv.float_), - cv.Optional(CONF_BELOW): cv.templatable(cv.float_), - }, - cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW), - ), - } +SENSOR_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSensorComponent), + cv.GenerateID(): cv.declare_id(Sensor), + cv.Optional(CONF_UNIT_OF_MEASUREMENT): validate_unit_of_measurement, + cv.Optional(CONF_ACCURACY_DECIMALS): validate_accuracy_decimals, + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_STATE_CLASS): validate_state_class, + cv.Optional(CONF_ENTITY_CATEGORY): sensor_entity_category, + cv.Optional("last_reset_type"): cv.invalid( + "last_reset_type has been removed since 2021.9.0. state_class: total_increasing should be used for total values." + ), + cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean, + cv.Optional(CONF_EXPIRE_AFTER): cv.All( + cv.requires_component("mqtt"), + cv.Any(None, cv.positive_time_period_milliseconds), + ), + cv.Optional(CONF_FILTERS): validate_filters, + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorStateTrigger), + } + ), + cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + SensorRawStateTrigger + ), + } + ), + cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger), + cv.Optional(CONF_ABOVE): cv.templatable(cv.float_), + cv.Optional(CONF_BELOW): cv.templatable(cv.float_), + }, + cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW), + ), + } + ) ) _UNDEF = object() @@ -772,6 +779,10 @@ async def setup_sensor_core_(var, config): else: cg.add(mqtt_.set_expire_after(expire_after)) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_sensor(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index e997ec7ca5..3539d0e34e 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition, maybe_simple_id -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, @@ -10,6 +10,7 @@ from esphome.const import ( CONF_ID, CONF_INVERTED, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, CONF_RESTORE_MODE, @@ -64,22 +65,26 @@ SwitchTurnOffTrigger = switch_ns.class_( validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True) -_SWITCH_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSwitchComponent), - cv.Optional(CONF_INVERTED): cv.boolean, - cv.Optional(CONF_ON_TURN_ON): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOnTrigger), - } - ), - cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOffTrigger), - } - ), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - } +_SWITCH_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSwitchComponent), + cv.Optional(CONF_INVERTED): cv.boolean, + cv.Optional(CONF_ON_TURN_ON): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOnTrigger), + } + ), + cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOffTrigger), + } + ), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + } + ) ) _UNDEF = object() @@ -151,6 +156,10 @@ async def setup_switch_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: cg.add(var.set_device_class(device_class)) diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index 4ca055a730..5a8e763495 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -2,13 +2,14 @@ from typing import Optional import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_ID, CONF_MODE, CONF_ON_VALUE, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_VALUE, ) @@ -38,17 +39,21 @@ TEXT_MODES = { "PASSWORD": TextMode.TEXT_MODE_PASSWORD, # to be implemented for keys, passwords, etc. } -TEXT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextComponent), - cv.GenerateID(): cv.declare_id(Text), - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TextStateTrigger), - } - ), - cv.Required(CONF_MODE): cv.enum(TEXT_MODES, upper=True), - } +TEXT_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextComponent), + cv.GenerateID(): cv.declare_id(Text), + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TextStateTrigger), + } + ), + cv.Required(CONF_MODE): cv.enum(TEXT_MODES, upper=True), + } + ) ) @@ -77,6 +82,10 @@ async def setup_text_core_( mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_text( var, diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index 6c28b57b3d..f4e795924c 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, @@ -12,6 +12,7 @@ from esphome.const import ( CONF_ON_RAW_VALUE, CONF_TRIGGER_ID, CONF_MQTT_ID, + CONF_WEB_SERVER_ID, CONF_STATE, CONF_FROM, CONF_TO, @@ -124,25 +125,31 @@ async def map_filter_to_code(config, filter_id): validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") -TEXT_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextSensor), - cv.GenerateID(): cv.declare_id(TextSensor), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_FILTERS): validate_filters, - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TextSensorStateTrigger), - } - ), - cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( - TextSensorStateRawTrigger - ), - } - ), - } +TEXT_SENSOR_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextSensor), + cv.GenerateID(): cv.declare_id(TextSensor), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_FILTERS): validate_filters, + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + TextSensorStateTrigger + ), + } + ), + cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + TextSensorStateRawTrigger + ), + } + ), + } + ) ) _UNDEF = object() @@ -205,6 +212,10 @@ async def setup_text_sensor_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_text_sensor(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index ea6bfc6055..c03d13fec8 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id, Condition -from esphome.components import mqtt +from esphome.components import mqtt, web_server from esphome.const import ( CONF_DEVICE_CLASS, CONF_ID, @@ -14,6 +14,7 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, @@ -70,28 +71,32 @@ ValveClosedTrigger = valve_ns.class_( CONF_ON_CLOSED = "on_closed" -VALVE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( - { - cv.GenerateID(): cv.declare_id(Valve), - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTValveComponent), - cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), - cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( - cv.requires_component("mqtt"), cv.subscribe_topic - ), - cv.Optional(CONF_ON_OPEN): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveOpenTrigger), - } - ), - cv.Optional(CONF_ON_CLOSED): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveClosedTrigger), - } - ), - } +VALVE_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(Valve), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTValveComponent), + cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), + cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( + cv.requires_component("mqtt"), cv.subscribe_topic + ), + cv.Optional(CONF_ON_OPEN): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveOpenTrigger), + } + ), + cv.Optional(CONF_ON_CLOSED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValveClosedTrigger), + } + ), + } + ) ) @@ -119,6 +124,10 @@ async def setup_valve_core_(var, config): mqtt_.set_custom_position_command_topic(position_command_topic_config) ) + if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: + web_server_ = await cg.get_variable(webserver_id) + web_server.add_entity_to_sorting_list(web_server_, var, config) + async def register_valve(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index fa614fb5a6..232ab40d10 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import gzip import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv from esphome.components import web_server_base from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID from esphome.const import ( @@ -19,6 +22,8 @@ from esphome.const import ( CONF_LOG, CONF_VERSION, CONF_LOCAL, + CONF_WEB_SERVER_ID, + CONF_WEB_SERVER_SORTING_WEIGHT, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, @@ -64,6 +69,46 @@ def validate_ota(config): return config +def _validate_no_sorting_weight( + webserver_version: int, config: dict, path: list[str] | None = None +) -> None: + if path is None: + path = [] + if CONF_WEB_SERVER_SORTING_WEIGHT in config: + raise cv.FinalExternalInvalid( + f"Sorting weight on entities is not supported in web_server version {webserver_version}", + path=path + [CONF_WEB_SERVER_SORTING_WEIGHT], + ) + for p, value in config.items(): + if isinstance(value, dict): + _validate_no_sorting_weight(webserver_version, value, path + [p]) + elif isinstance(value, list): + for i, item in enumerate(value): + if isinstance(item, dict): + _validate_no_sorting_weight(webserver_version, item, path + [p, i]) + + +def _final_validate_sorting_weight(config): + if (webserver_version := config.get(CONF_VERSION)) != 3: + _validate_no_sorting_weight(webserver_version, fv.full_config.get()) + + return config + + +FINAL_VALIDATE_SCHEMA = _final_validate_sorting_weight + + +WEBSERVER_SORTING_SCHEMA = cv.Schema( + { + cv.OnlyWith(CONF_WEB_SERVER_ID, "web_server"): cv.use_id(WebServer), + cv.Optional(CONF_WEB_SERVER_SORTING_WEIGHT): cv.All( + cv.requires_component("web_server"), + cv.float_, + ), + } +) + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -108,6 +153,19 @@ CONFIG_SCHEMA = cv.All( ) +def add_entity_to_sorting_list(web_server, entity, config): + sorting_weight = 50 + if CONF_WEB_SERVER_SORTING_WEIGHT in config: + sorting_weight = config[CONF_WEB_SERVER_SORTING_WEIGHT] + + cg.add( + web_server.add_entity_to_sorting_list( + entity, + sorting_weight, + ) + ) + + def build_index_html(config) -> str: html = "" css_include = config.get(CONF_CSS_INCLUDE) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index d72307991f..5bb36f9600 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -435,7 +435,7 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM request->send(404); } std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { + return json::build_json([this, obj, value, start_config](JsonObject root) { std::string state; if (std::isnan(value)) { state = "NA"; @@ -446,6 +446,9 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail } set_json_icon_state_value(root, obj, "sensor-" + obj->get_object_id(), state, value, start_config); if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } if (!obj->get_unit_of_measurement().empty()) root["uom"] = obj->get_unit_of_measurement(); } @@ -471,8 +474,13 @@ void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const } std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std::string &value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { + return json::build_json([this, obj, value, start_config](JsonObject root) { set_json_icon_state_value(root, obj, "text_sensor-" + obj->get_object_id(), value, value, start_config); + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif @@ -483,14 +491,6 @@ void WebServer::on_switch_update(switch_::Switch *obj, bool state) { return; this->events_.send(this->switch_json(obj, state, DETAIL_STATE).c_str(), "state"); } -std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { - set_json_icon_state_value(root, obj, "switch-" + obj->get_object_id(), value ? "ON" : "OFF", value, start_config); - if (start_config == DETAIL_ALL) { - root["assumed_state"] = obj->assumed_state(); - } - }); -} void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (switch_::Switch *obj : App.get_switches()) { if (obj->get_object_id() != match.id) @@ -515,14 +515,20 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM } request->send(404); } +std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail start_config) { + return json::build_json([this, obj, value, start_config](JsonObject root) { + set_json_icon_state_value(root, obj, "switch-" + obj->get_object_id(), value ? "ON" : "OFF", value, start_config); + if (start_config == DETAIL_ALL) { + root["assumed_state"] = obj->assumed_state(); + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_BUTTON -std::string WebServer::button_json(button::Button *obj, JsonDetail start_config) { - return json::build_json( - [obj, start_config](JsonObject root) { set_json_id(root, obj, "button-" + obj->get_object_id(), start_config); }); -} - void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (button::Button *obj : App.get_buttons()) { if (obj->get_object_id() != match.id) @@ -538,6 +544,16 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM } request->send(404); } +std::string WebServer::button_json(button::Button *obj, JsonDetail start_config) { + return json::build_json([this, obj, start_config](JsonObject root) { + set_json_id(root, obj, "button-" + obj->get_object_id(), start_config); + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_BINARY_SENSOR @@ -546,12 +562,6 @@ void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool s return; this->events_.send(this->binary_sensor_json(obj, state, DETAIL_STATE).c_str(), "state"); } -std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { - set_json_icon_state_value(root, obj, "binary_sensor-" + obj->get_object_id(), value ? "ON" : "OFF", value, - start_config); - }); -} void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) { if (obj->get_object_id() != match.id) @@ -562,6 +572,17 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con } request->send(404); } +std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool value, JsonDetail start_config) { + return json::build_json([this, obj, value, start_config](JsonObject root) { + set_json_icon_state_value(root, obj, "binary_sensor-" + obj->get_object_id(), value ? "ON" : "OFF", value, + start_config); + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_FAN @@ -570,19 +591,6 @@ void WebServer::on_fan_update(fan::Fan *obj) { return; this->events_.send(this->fan_json(obj, DETAIL_STATE).c_str(), "state"); } -std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { - set_json_icon_state_value(root, obj, "fan-" + obj->get_object_id(), obj->state ? "ON" : "OFF", obj->state, - start_config); - const auto traits = obj->get_traits(); - if (traits.supports_speed()) { - root["speed_level"] = obj->speed; - root["speed_count"] = traits.supported_speed_count(); - } - if (obj->get_traits().supports_oscillation()) - root["oscillation"] = obj->oscillating; - }); -} void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (fan::Fan *obj : App.get_fans()) { if (obj->get_object_id() != match.id) @@ -635,6 +643,24 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc } request->send(404); } +std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) { + return json::build_json([this, obj, start_config](JsonObject root) { + set_json_icon_state_value(root, obj, "fan-" + obj->get_object_id(), obj->state ? "ON" : "OFF", obj->state, + start_config); + const auto traits = obj->get_traits(); + if (traits.supports_speed()) { + root["speed_level"] = obj->speed; + root["speed_count"] = traits.supported_speed_count(); + } + if (obj->get_traits().supports_oscillation()) + root["oscillation"] = obj->oscillating; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_LIGHT @@ -729,7 +755,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa request->send(404); } std::string WebServer::light_json(light::LightState *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_id(root, obj, "light-" + obj->get_object_id(), start_config); root["state"] = obj->remote_values.is_on() ? "ON" : "OFF"; @@ -740,6 +766,9 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi for (auto const &option : obj->get_effects()) { opt.add(option->get_name()); } + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } } }); } @@ -803,7 +832,7 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa request->send(404); } std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_icon_state_value(root, obj, "cover-" + obj->get_object_id(), obj->is_fully_closed() ? "CLOSED" : "OPEN", obj->position, start_config); root["current_operation"] = cover::cover_operation_to_str(obj->current_operation); @@ -812,6 +841,11 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) { root["position"] = obj->position; if (obj->get_traits().get_supports_tilt()) root["tilt"] = obj->tilt; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif @@ -852,7 +886,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM } std::string WebServer::number_json(number::Number *obj, float value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { + return json::build_json([this, obj, value, start_config](JsonObject root) { set_json_id(root, obj, "number-" + obj->get_object_id(), start_config); if (start_config == DETAIL_ALL) { root["min_value"] = @@ -864,6 +898,9 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail root["mode"] = (int) obj->traits.get_mode(); if (!obj->traits.get_unit_of_measurement().empty()) root["uom"] = obj->traits.get_unit_of_measurement(); + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } } if (std::isnan(value)) { root["value"] = "\"NaN\""; @@ -919,11 +956,16 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat } std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_id(root, obj, "date-" + obj->get_object_id(), start_config); std::string value = str_sprintf("%d-%02d-%02d", obj->year, obj->month, obj->day); root["value"] = value; root["state"] = value; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif // USE_DATETIME_DATE @@ -967,11 +1009,16 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat request->send(404); } std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_id(root, obj, "time-" + obj->get_object_id(), start_config); std::string value = str_sprintf("%02d:%02d:%02d", obj->hour, obj->minute, obj->second); root["value"] = value; root["state"] = value; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif // USE_DATETIME_TIME @@ -1015,12 +1062,17 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur request->send(404); } std::string WebServer::datetime_json(datetime::DateTimeEntity *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_id(root, obj, "datetime-" + obj->get_object_id(), start_config); std::string value = str_sprintf("%d-%02d-%02d %02d:%02d:%02d", obj->year, obj->month, obj->day, obj->hour, obj->minute, obj->second); root["value"] = value; root["state"] = value; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif // USE_DATETIME_DATETIME @@ -1060,11 +1112,8 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat } std::string WebServer::text_json(text::Text *obj, const std::string &value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { + return json::build_json([this, obj, value, start_config](JsonObject root) { set_json_id(root, obj, "text-" + obj->get_object_id(), start_config); - if (start_config == DETAIL_ALL) { - root["mode"] = (int) obj->traits.get_mode(); - } root["min_length"] = obj->traits.get_min_length(); root["max_length"] = obj->traits.get_max_length(); root["pattern"] = obj->traits.get_pattern(); @@ -1074,6 +1123,12 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json root["state"] = value; } root["value"] = value; + if (start_config == DETAIL_ALL) { + root["mode"] = (int) obj->traits.get_mode(); + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } }); } #endif @@ -1119,13 +1174,16 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM request->send(404); } std::string WebServer::select_json(select::Select *obj, const std::string &value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { + return json::build_json([this, obj, value, start_config](JsonObject root) { set_json_icon_state_value(root, obj, "select-" + obj->get_object_id(), value, value, start_config); if (start_config == DETAIL_ALL) { JsonArray opt = root.createNestedArray("option"); for (auto &option : obj->traits.get_options()) { opt.add(option); } + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } } }); } @@ -1140,7 +1198,6 @@ void WebServer::on_climate_update(climate::Climate *obj) { return; this->events_.send(this->climate_json(obj, DETAIL_STATE).c_str(), "state"); } - void WebServer::handle_climate_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (auto *obj : App.get_climates()) { if (obj->get_object_id() != match.id) @@ -1188,9 +1245,8 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url } request->send(404); } - std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_id(root, obj, "climate-" + obj->get_object_id(), start_config); const auto traits = obj->get_traits(); int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals(); @@ -1227,6 +1283,9 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf for (auto const &custom_preset : traits.get_supported_custom_presets()) opt.add(custom_preset); } + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } } bool has_state = false; @@ -1283,12 +1342,6 @@ void WebServer::on_lock_update(lock::Lock *obj) { return; this->events_.send(this->lock_json(obj, obj->state, DETAIL_STATE).c_str(), "state"); } -std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { - set_json_icon_state_value(root, obj, "lock-" + obj->get_object_id(), lock::lock_state_to_string(value), value, - start_config); - }); -} void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (lock::Lock *obj : App.get_locks()) { if (obj->get_object_id() != match.id) @@ -1313,6 +1366,17 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat } request->send(404); } +std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDetail start_config) { + return json::build_json([this, obj, value, start_config](JsonObject root) { + set_json_icon_state_value(root, obj, "lock-" + obj->get_object_id(), lock::lock_state_to_string(value), value, + start_config); + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_VALVE @@ -1366,13 +1430,16 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa request->send(404); } std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) { - return json::build_json([obj, start_config](JsonObject root) { + return json::build_json([this, obj, start_config](JsonObject root) { set_json_icon_state_value(root, obj, "valve-" + obj->get_object_id(), obj->is_fully_closed() ? "CLOSED" : "OPEN", obj->position, start_config); root["current_operation"] = valve::valve_operation_to_str(obj->current_operation); if (obj->get_traits().get_supports_position()) root["position"] = obj->position; + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } }); } #endif @@ -1383,15 +1450,6 @@ void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlP return; this->events_.send(this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE).c_str(), "state"); } -std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmControlPanel *obj, - alarm_control_panel::AlarmControlPanelState value, - JsonDetail start_config) { - return json::build_json([obj, value, start_config](JsonObject root) { - char buf[16]; - set_json_icon_state_value(root, obj, "alarm-control-panel-" + obj->get_object_id(), - PSTR_LOCAL(alarm_control_panel_state_to_string(value)), value, start_config); - }); -} void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match) { for (alarm_control_panel::AlarmControlPanel *obj : App.get_alarm_control_panels()) { if (obj->get_object_id() != match.id) @@ -1405,6 +1463,20 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques } request->send(404); } +std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmControlPanel *obj, + alarm_control_panel::AlarmControlPanelState value, + JsonDetail start_config) { + return json::build_json([this, obj, value, start_config](JsonObject root) { + char buf[16]; + set_json_icon_state_value(root, obj, "alarm-control-panel-" + obj->get_object_id(), + PSTR_LOCAL(alarm_control_panel_state_to_string(value)), value, start_config); + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} #endif #ifdef USE_EVENT @@ -1709,6 +1781,10 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { bool WebServer::isRequestHandlerTrivial() { return false; } +void WebServer::add_entity_to_sorting_list(EntityBase *entity, float weight) { + this->sorting_entitys_[entity] = SortingComponents{weight}; +} + void WebServer::schedule_(std::function &&f) { #ifdef USE_ESP32 xSemaphoreTake(this->to_schedule_lock_, portMAX_DELAY); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index dda14a7e05..0fb40e2c33 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -5,8 +5,10 @@ #include "esphome/components/web_server_base/web_server_base.h" #include "esphome/core/component.h" #include "esphome/core/controller.h" +#include "esphome/core/entity_base.h" #include +#include #ifdef USE_ESP32 #include #include @@ -39,6 +41,10 @@ struct UrlMatch { bool valid; ///< Whether this match is valid }; +struct SortingComponents { + float weight; +}; + enum JsonDetail { DETAIL_ALL, DETAIL_STATE }; /** This class allows users to create a web server with their ESP nodes. @@ -320,12 +326,15 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { /// This web handle is not trivial. bool isRequestHandlerTrivial() override; + void add_entity_to_sorting_list(EntityBase *entity, float weight); + protected: void schedule_(std::function &&f); friend ListEntitiesIterator; web_server_base::WebServerBase *base_; AsyncEventSource events_{"/events"}; ListEntitiesIterator entities_iterator_; + std::map sorting_entitys_; #if USE_WEBSERVER_VERSION == 1 const char *css_url_{nullptr}; const char *js_url_{nullptr}; diff --git a/esphome/const.py b/esphome/const.py index 616b686052..1aafffb5d0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -904,6 +904,8 @@ CONF_WARM_WHITE = "warm_white" CONF_WARM_WHITE_COLOR_TEMPERATURE = "warm_white_color_temperature" CONF_WATCHDOG_THRESHOLD = "watchdog_threshold" CONF_WEB_SERVER = "web_server" +CONF_WEB_SERVER_ID = "web_server_id" +CONF_WEB_SERVER_SORTING_WEIGHT = "web_server_sorting_weight" CONF_WEIGHT = "weight" CONF_WHILE = "while" CONF_WHITE = "white" From c130ddbe9cabcfa88ade0d489414aecc82850548 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Wed, 29 May 2024 20:58:13 -0500 Subject: [PATCH 1822/2607] [micro_wake_word] Ensure model string is Path (#6826) --- esphome/components/micro_wake_word/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 9073d103f1..def2808e54 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -329,11 +329,14 @@ async def to_code(config): file: Path = base_dir / h.hexdigest()[:8] / model_config[CONF_FILE] elif model_config[CONF_TYPE] == TYPE_LOCAL: - file = model_config[CONF_PATH] + file = Path(model_config[CONF_PATH]) elif model_config[CONF_TYPE] == TYPE_HTTP: file = _compute_local_file_path(model_config) / "manifest.json" + else: + raise ValueError("Unsupported config type: {model_config[CONF_TYPE]}") + manifest, data = _load_model_data(file) rhs = [HexInt(x) for x in data] From 9de8eaff24f63a0acc25fdc555babfc3b54c7b27 Mon Sep 17 00:00:00 2001 From: Erdem Date: Thu, 30 May 2024 08:31:09 +0300 Subject: [PATCH 1823/2607] Fix DHT reading timing for SI7021 on ESP32 (#6604) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/dht/dht.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/dht/dht.cpp b/esphome/components/dht/dht.cpp index 5112092073..db1c851d5f 100644 --- a/esphome/components/dht/dht.cpp +++ b/esphome/components/dht/dht.cpp @@ -86,9 +86,14 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r if (this->model_ == DHT_MODEL_DHT11) { delayMicroseconds(18000); } else if (this->model_ == DHT_MODEL_SI7021) { +#ifdef USE_ESP8266 delayMicroseconds(500); this->pin_->digital_write(true); delayMicroseconds(40); +#else + delayMicroseconds(400); + this->pin_->digital_write(true); +#endif } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) { delayMicroseconds(2000); } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) { From 63fc8ab10a52fc118c89218e40ccc919877a19f9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 19:59:15 +1200 Subject: [PATCH 1824/2607] [core] Const-ify some Component fields (#6831) --- esphome/core/component.cpp | 8 ++++---- esphome/core/component.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 594e8ff7df..ae73a451d9 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -1,11 +1,11 @@ #include "esphome/core/component.h" +#include +#include #include "esphome/core/application.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include -#include namespace esphome { @@ -140,8 +140,8 @@ void Component::set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std: float backoff_increase_factor) { // NOLINT App.scheduler.set_retry(this, "", initial_wait_time, max_attempts, std::move(f), backoff_increase_factor); } -bool Component::is_failed() { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; } -bool Component::is_ready() { +bool Component::is_failed() const { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; } +bool Component::is_ready() const { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP || (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP; } diff --git a/esphome/core/component.h b/esphome/core/component.h index e6ffe96d1e..a6bd8f81ac 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -118,9 +118,9 @@ class Component { */ virtual void mark_failed(); - bool is_failed(); + bool is_failed() const; - bool is_ready(); + bool is_ready() const; virtual bool can_proceed(); From 8aba890e6974b40fffa14271b63371d179949733 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 20:00:09 +1200 Subject: [PATCH 1825/2607] [voice_assistant] Half the microphone ringbuffer size (#6830) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 0bd8194190..c2fd14fbd5 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -18,7 +18,7 @@ static const char *const TAG = "voice_assistant"; static const size_t SAMPLE_RATE_HZ = 16000; static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms -static const size_t BUFFER_SIZE = 1024 * SAMPLE_RATE_HZ / 1000; +static const size_t BUFFER_SIZE = 512 * SAMPLE_RATE_HZ / 1000; static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t); static const size_t RECEIVE_SIZE = 1024; static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; From dd2788133683cc7485008559de7d1a4b7ae21825 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 20:01:39 +1200 Subject: [PATCH 1826/2607] [i2s_speaker] Add buffer allocation failure checks (#6829) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 69536742cb..546c2c98f7 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -19,10 +19,27 @@ void I2SAudioSpeaker::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker..."); this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent)); + if (this->buffer_queue_ == nullptr) { + ESP_LOGE(TAG, "Failed to create buffer queue"); + this->mark_failed(); + return; + } + this->event_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(TaskEvent)); + if (this->event_queue_ == nullptr) { + ESP_LOGE(TAG, "Failed to create event queue"); + this->mark_failed(); + return; + } } -void I2SAudioSpeaker::start() { this->state_ = speaker::STATE_STARTING; } +void I2SAudioSpeaker::start() { + if (this->is_failed()) { + ESP_LOGE(TAG, "Cannot start audio, speaker failed to setup"); + return; + } + this->state_ = speaker::STATE_STARTING; +} void I2SAudioSpeaker::start_() { if (!this->parent_->try_lock()) { return; // Waiting for another i2s component to return lock @@ -141,6 +158,8 @@ void I2SAudioSpeaker::player_task(void *params) { } void I2SAudioSpeaker::stop() { + if (this->is_failed()) + return; if (this->state_ == speaker::STATE_STOPPED) return; if (this->state_ == speaker::STATE_STARTING) { @@ -200,6 +219,10 @@ void I2SAudioSpeaker::loop() { } size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length) { + if (this->is_failed()) { + ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup"); + return 0; + } if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) { this->start(); } From 8dfe1d52203e5ab6d07baaea74b981bf3c6cab98 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 30 May 2024 08:46:52 +0000 Subject: [PATCH 1827/2607] LTR-303, LTR-329, LTR-553, LTR-556, LTR-559, LTR-659 Series of Lite-On Light (ALS) and Proximity(PS) sensors (#6076) * LTR303 and LTR329 light sensors * LTR303 tidy up * LTR303 unused var * LTR303 tidy up + test * LTR303 auto sensitivity mode * LTR303 auto sensitivity mode tidy * LTR303 State machine version * LTR303 name fix * publish split * minor * new definitions for LTR * als-ps test * als-ps test * als-ps test * ps options * ps options * trgger bug fixed * trgger bug fixed * Minor comments * ltr303->ltr_als_ps * codeowners, tests * tidy up * tidy up * tidy up * gain enum name fix * auto gain fix * tweaks * new style tests * als/ps separate init * logd->logv * reconfiguration count changed * old-style tests removed * const py * ambient light const in vmel7700 and ltr390 * Update esphome/components/ltr_als_ps/ltr_als_ps.cpp Co-authored-by: Keith Burzinski * Apply suggestions from code review Co-authored-by: Keith Burzinski * remove commented code --------- Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/ltr390/sensor.py | 8 +- esphome/components/ltr_als_ps/__init__.py | 1 + esphome/components/ltr_als_ps/ltr_als_ps.cpp | 519 ++++++++++++++++++ esphome/components/ltr_als_ps/ltr_als_ps.h | 184 +++++++ .../components/ltr_als_ps/ltr_definitions.h | 275 ++++++++++ esphome/components/ltr_als_ps/sensor.py | 271 +++++++++ esphome/components/veml7700/sensor.py | 8 +- esphome/const.py | 1 + tests/components/ltr_als_ps/common.yaml | 11 + .../ltr_als_ps/test.esp32-c3-idf.yaml | 6 + .../components/ltr_als_ps/test.esp32-c3.yaml | 6 + .../components/ltr_als_ps/test.esp32-idf.yaml | 6 + tests/components/ltr_als_ps/test.esp32.yaml | 6 + tests/components/ltr_als_ps/test.esp8266.yaml | 6 + tests/components/ltr_als_ps/test.rp2040.yaml | 6 + 16 files changed, 1307 insertions(+), 8 deletions(-) create mode 100644 esphome/components/ltr_als_ps/__init__.py create mode 100644 esphome/components/ltr_als_ps/ltr_als_ps.cpp create mode 100644 esphome/components/ltr_als_ps/ltr_als_ps.h create mode 100644 esphome/components/ltr_als_ps/ltr_definitions.h create mode 100644 esphome/components/ltr_als_ps/sensor.py create mode 100644 tests/components/ltr_als_ps/common.yaml create mode 100644 tests/components/ltr_als_ps/test.esp32-c3-idf.yaml create mode 100644 tests/components/ltr_als_ps/test.esp32-c3.yaml create mode 100644 tests/components/ltr_als_ps/test.esp32-idf.yaml create mode 100644 tests/components/ltr_als_ps/test.esp32.yaml create mode 100644 tests/components/ltr_als_ps/test.esp8266.yaml create mode 100644 tests/components/ltr_als_ps/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 8b6143859a..0dc5339193 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -210,6 +210,7 @@ esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core esphome/components/ltr390/* @sjtrny +esphome/components/ltr_als_ps/* @latonita esphome/components/matrix_keypad/* @ssieb esphome/components/max31865/* @DAVe3283 esphome/components/max44009/* @berfenger diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py index fe8cad00b6..8b2676599c 100644 --- a/esphome/components/ltr390/sensor.py +++ b/esphome/components/ltr390/sensor.py @@ -2,14 +2,15 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( - CONF_ID, + CONF_AMBIENT_LIGHT, CONF_GAIN, + CONF_ID, CONF_LIGHT, CONF_RESOLUTION, - UNIT_LUX, - ICON_BRIGHTNESS_5, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ILLUMINANCE, + ICON_BRIGHTNESS_5, + UNIT_LUX, ) CODEOWNERS = ["@sjtrny"] @@ -21,7 +22,6 @@ LTR390Component = ltr390_ns.class_( "LTR390Component", cg.PollingComponent, i2c.I2CDevice ) -CONF_AMBIENT_LIGHT = "ambient_light" CONF_UV_INDEX = "uv_index" CONF_UV = "uv" CONF_WINDOW_CORRECTION_FACTOR = "window_correction_factor" diff --git a/esphome/components/ltr_als_ps/__init__.py b/esphome/components/ltr_als_ps/__init__.py new file mode 100644 index 0000000000..dd06cfffea --- /dev/null +++ b/esphome/components/ltr_als_ps/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@latonita"] diff --git a/esphome/components/ltr_als_ps/ltr_als_ps.cpp b/esphome/components/ltr_als_ps/ltr_als_ps.cpp new file mode 100644 index 0000000000..ae299c9b66 --- /dev/null +++ b/esphome/components/ltr_als_ps/ltr_als_ps.cpp @@ -0,0 +1,519 @@ +#include "ltr_als_ps.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +using esphome::i2c::ErrorCode; + +namespace esphome { +namespace ltr_als_ps { + +static const char *const TAG = "ltr_als_ps"; + +static const uint8_t MAX_TRIES = 5; + +template T get_next(const T (&array)[size], const T val) { + size_t i = 0; + size_t idx = -1; + while (idx == -1 && i < size) { + if (array[i] == val) { + idx = i; + break; + } + i++; + } + if (idx == -1 || i + 1 >= size) + return val; + return array[i + 1]; +} + +template T get_prev(const T (&array)[size], const T val) { + size_t i = size - 1; + size_t idx = -1; + while (idx == -1 && i > 0) { + if (array[i] == val) { + idx = i; + break; + } + i--; + } + if (idx == -1 || i == 0) + return val; + return array[i - 1]; +} + +static uint16_t get_itime_ms(IntegrationTime time) { + static const uint16_t ALS_INT_TIME[8] = {100, 50, 200, 400, 150, 250, 300, 350}; + return ALS_INT_TIME[time & 0b111]; +} + +static uint16_t get_meas_time_ms(MeasurementRepeatRate rate) { + static const uint16_t ALS_MEAS_RATE[8] = {50, 100, 200, 500, 1000, 2000, 2000, 2000}; + return ALS_MEAS_RATE[rate & 0b111]; +} + +static float get_gain_coeff(AlsGain gain) { + static const float ALS_GAIN[8] = {1, 2, 4, 8, 0, 0, 48, 96}; + return ALS_GAIN[gain & 0b111]; +} + +static float get_ps_gain_coeff(PsGain gain) { + static const float PS_GAIN[4] = {16, 0, 32, 64}; + return PS_GAIN[gain & 0b11]; +} + +void LTRAlsPsComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up LTR-303/329/55x/659"); + // As per datasheet we need to wait at least 100ms after power on to get ALS chip responsive + this->set_timeout(100, [this]() { this->state_ = State::DELAYED_SETUP; }); +} + +void LTRAlsPsComponent::dump_config() { + auto get_device_type = [](LtrType typ) { + switch (typ) { + case LtrType::LTR_TYPE_ALS_ONLY: + return "ALS only"; + case LtrType::LTR_TYPE_PS_ONLY: + return "PS only"; + case LtrType::LTR_TYPE_ALS_AND_PS: + return "ALS + PS"; + default: + return "Unknown"; + } + }; + + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Device type: %s", get_device_type(this->ltr_type_)); + if (this->is_als_()) { + ESP_LOGCONFIG(TAG, " Automatic mode: %s", ONOFF(this->automatic_mode_enabled_)); + ESP_LOGCONFIG(TAG, " Gain: %.0fx", get_gain_coeff(this->gain_)); + ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); + ESP_LOGCONFIG(TAG, " Measurement repeat rate: %d ms", get_meas_time_ms(this->repeat_rate_)); + ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + LOG_SENSOR(" ", "ALS calculated lux", this->ambient_light_sensor_); + LOG_SENSOR(" ", "CH1 Infrared counts", this->infrared_counts_sensor_); + LOG_SENSOR(" ", "CH0 Visible+IR counts", this->full_spectrum_counts_sensor_); + LOG_SENSOR(" ", "Actual gain", this->actual_gain_sensor_); + } + if (this->is_ps_()) { + ESP_LOGCONFIG(TAG, " Proximity gain: %.0fx", get_ps_gain_coeff(this->ps_gain_)); + ESP_LOGCONFIG(TAG, " Proximity cooldown time: %d s", this->ps_cooldown_time_s_); + ESP_LOGCONFIG(TAG, " Proximity high threshold: %d", this->ps_threshold_high_); + ESP_LOGCONFIG(TAG, " Proximity low threshold: %d", this->ps_threshold_low_); + LOG_SENSOR(" ", "Proximity counts", this->proximity_counts_sensor_); + } + LOG_UPDATE_INTERVAL(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with I2C LTR-303/329/55x/659 failed!"); + } +} + +void LTRAlsPsComponent::update() { + ESP_LOGV(TAG, "Updating"); + if (this->is_ready() && this->state_ == State::IDLE) { + ESP_LOGV(TAG, "Initiating new data collection"); + + this->state_ = this->automatic_mode_enabled_ ? State::COLLECTING_DATA_AUTO : State::WAITING_FOR_DATA; + + this->als_readings_.ch0 = 0; + this->als_readings_.ch1 = 0; + this->als_readings_.gain = this->gain_; + this->als_readings_.integration_time = this->integration_time_; + this->als_readings_.lux = 0; + this->als_readings_.number_of_adjustments = 0; + + } else { + ESP_LOGV(TAG, "Component not ready yet"); + } +} + +void LTRAlsPsComponent::loop() { + ErrorCode err = i2c::ERROR_OK; + static uint8_t tries{0}; + + switch (this->state_) { + case State::DELAYED_SETUP: + err = this->write(nullptr, 0); + if (err != i2c::ERROR_OK) { + ESP_LOGV(TAG, "i2c connection failed"); + this->mark_failed(); + } + this->configure_reset_(); + if (this->is_als_()) { + this->configure_als_(); + this->configure_integration_time_(this->integration_time_); + } + if (this->is_ps_()) { + this->configure_ps_(); + } + + this->state_ = State::IDLE; + break; + + case State::IDLE: + if (this->is_ps_()) { + check_and_trigger_ps_(); + } + break; + + case State::WAITING_FOR_DATA: + if (this->is_als_data_ready_(this->als_readings_) == DataAvail::DATA_OK) { + tries = 0; + ESP_LOGV(TAG, "Reading sensor data having gain = %.0fx, time = %d ms", get_gain_coeff(this->als_readings_.gain), + get_itime_ms(this->als_readings_.integration_time)); + this->read_sensor_data_(this->als_readings_); + this->state_ = State::DATA_COLLECTED; + this->apply_lux_calculation_(this->als_readings_); + } else if (tries >= MAX_TRIES) { + ESP_LOGW(TAG, "Can't get data after several tries."); + tries = 0; + this->status_set_warning(); + this->state_ = State::IDLE; + return; + } else { + tries++; + } + break; + + case State::COLLECTING_DATA_AUTO: + case State::DATA_COLLECTED: + // first measurement in auto mode (COLLECTING_DATA_AUTO state) require device reconfiguration + if (this->state_ == State::COLLECTING_DATA_AUTO || this->are_adjustments_required_(this->als_readings_)) { + this->state_ = State::ADJUSTMENT_IN_PROGRESS; + ESP_LOGD(TAG, "Reconfiguring sensitivity: gain = %.0fx, time = %d ms", get_gain_coeff(this->als_readings_.gain), + get_itime_ms(this->als_readings_.integration_time)); + this->configure_integration_time_(this->als_readings_.integration_time); + this->configure_gain_(this->als_readings_.gain); + // if sensitivity adjustment needed - need to wait for first data samples after setting new parameters + this->set_timeout(2 * get_meas_time_ms(this->repeat_rate_), + [this]() { this->state_ = State::WAITING_FOR_DATA; }); + } else { + this->state_ = State::READY_TO_PUBLISH; + } + break; + + case State::ADJUSTMENT_IN_PROGRESS: + // nothing to be done, just waiting for the timeout + break; + + case State::READY_TO_PUBLISH: + this->publish_data_part_1_(this->als_readings_); + this->state_ = State::KEEP_PUBLISHING; + break; + + case State::KEEP_PUBLISHING: + this->publish_data_part_2_(this->als_readings_); + this->status_clear_warning(); + this->state_ = State::IDLE; + break; + + default: + break; + } +} + +void LTRAlsPsComponent::check_and_trigger_ps_() { + static uint32_t last_high_trigger_time{0}; + static uint32_t last_low_trigger_time{0}; + uint16_t ps_data = this->read_ps_data_(); + uint32_t now = millis(); + + if (ps_data != this->ps_readings_) { + this->ps_readings_ = ps_data; + // Higher values - object is closer to sensor + if (ps_data > this->ps_threshold_high_ && now - last_high_trigger_time >= this->ps_cooldown_time_s_ * 1000) { + last_high_trigger_time = now; + ESP_LOGV(TAG, "Proximity high threshold triggered. Value = %d, Trigger level = %d", ps_data, + this->ps_threshold_high_); + this->on_ps_high_trigger_callback_.call(); + } else if (ps_data < this->ps_threshold_low_ && now - last_low_trigger_time >= this->ps_cooldown_time_s_ * 1000) { + last_low_trigger_time = now; + ESP_LOGV(TAG, "Proximity low threshold triggered. Value = %d, Trigger level = %d", ps_data, + this->ps_threshold_low_); + this->on_ps_low_trigger_callback_.call(); + } + } +} + +bool LTRAlsPsComponent::check_part_number_() { + uint8_t manuf_id = this->reg((uint8_t) CommandRegisters::MANUFAC_ID).get(); + if (manuf_id != 0x05) { // 0x05 is Lite-On Semiconductor Corp. ID + ESP_LOGW(TAG, "Unknown manufacturer ID: 0x%02X", manuf_id); + this->mark_failed(); + return false; + } + + // Things getting not really funny here, we can't identify device type by part number ID + // ======================== ========= ===== ================= + // Device Part ID Rev Capabilities + // ======================== ========= ===== ================= + // Ltr-329/ltr-303 0x0a 0x00 Als 16b + // Ltr-553/ltr-556/ltr-556 0x09 0x02 Als 16b + Ps 11b diff nm sens + // Ltr-659 0x09 0x02 Ps 11b and ps gain + // + // There are other devices which might potentially work with default settings, + // but registers layout is different and we can't use them properly. For ex. ltr-558 + + PartIdRegister part_id{0}; + part_id.raw = this->reg((uint8_t) CommandRegisters::PART_ID).get(); + if (part_id.part_number_id != 0x0a && part_id.part_number_id != 0x09) { + ESP_LOGW(TAG, "Unknown part number ID: 0x%02X. It might not work properly.", part_id.part_number_id); + this->status_set_warning(); + return true; + } + return true; +} + +void LTRAlsPsComponent::configure_reset_() { + ESP_LOGV(TAG, "Resetting"); + + AlsControlRegister als_ctrl{0}; + als_ctrl.sw_reset = true; + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + + uint8_t tries = MAX_TRIES; + do { + ESP_LOGV(TAG, "Waiting for chip to reset"); + delay(2); + als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + } while (als_ctrl.sw_reset && tries--); // while sw reset bit is on - keep waiting + + if (als_ctrl.sw_reset) { + ESP_LOGW(TAG, "Reset timed out"); + } +} + +void LTRAlsPsComponent::configure_als_() { + AlsControlRegister als_ctrl{0}; + + als_ctrl.sw_reset = false; + als_ctrl.active_mode = true; + als_ctrl.gain = this->gain_; + + ESP_LOGV(TAG, "Setting active mode and gain reg 0x%02X", als_ctrl.raw); + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(5); + + uint8_t tries = MAX_TRIES; + do { + ESP_LOGV(TAG, "Waiting for device to become active..."); + delay(2); + als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + } while (!als_ctrl.active_mode && tries--); // while active mode is not set - keep waiting + + if (!als_ctrl.active_mode) { + ESP_LOGW(TAG, "Failed to activate device"); + } +} + +void LTRAlsPsComponent::configure_ps_() { + PsMeasurementRateRegister ps_meas{0}; + ps_meas.ps_measurement_rate = PsMeasurementRate::PS_MEAS_RATE_50MS; + this->reg((uint8_t) CommandRegisters::PS_MEAS_RATE) = ps_meas.raw; + + PsControlRegister ps_ctrl{0}; + ps_ctrl.ps_mode_active = true; + ps_ctrl.ps_mode_xxx = true; + this->reg((uint8_t) CommandRegisters::PS_CONTR) = ps_ctrl.raw; +} + +uint16_t LTRAlsPsComponent::read_ps_data_() { + AlsPsStatusRegister als_status{0}; + als_status.raw = this->reg((uint8_t) CommandRegisters::ALS_PS_STATUS).get(); + if (!als_status.ps_new_data || als_status.data_invalid) { + return this->ps_readings_; + } + + uint8_t ps_low = this->reg((uint8_t) CommandRegisters::PS_DATA_0).get(); + PsData1Register ps_high; + ps_high.raw = this->reg((uint8_t) CommandRegisters::PS_DATA_1).get(); + + uint16_t val = encode_uint16(ps_high.ps_data_high, ps_low); + if (ps_high.ps_saturation_flag) { + return 0x7ff; // full 11 bit range + } + return val; +} + +void LTRAlsPsComponent::configure_gain_(AlsGain gain) { + AlsControlRegister als_ctrl{0}; + als_ctrl.active_mode = true; + als_ctrl.gain = gain; + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + + AlsControlRegister read_als_ctrl{0}; + read_als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + if (read_als_ctrl.gain != gain) { + ESP_LOGW(TAG, "Failed to set gain. We will try one more time."); + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + } +} + +void LTRAlsPsComponent::configure_integration_time_(IntegrationTime time) { + MeasurementRateRegister meas{0}; + meas.measurement_repeat_rate = this->repeat_rate_; + meas.integration_time = time; + this->reg((uint8_t) CommandRegisters::MEAS_RATE) = meas.raw; + delay(2); + + MeasurementRateRegister read_meas{0}; + read_meas.raw = this->reg((uint8_t) CommandRegisters::MEAS_RATE).get(); + if (read_meas.integration_time != time) { + ESP_LOGW(TAG, "Failed to set integration time. We will try one more time."); + this->reg((uint8_t) CommandRegisters::MEAS_RATE) = meas.raw; + delay(2); + } +} + +DataAvail LTRAlsPsComponent::is_als_data_ready_(AlsReadings &data) { + AlsPsStatusRegister als_status{0}; + + als_status.raw = this->reg((uint8_t) CommandRegisters::ALS_PS_STATUS).get(); + if (!als_status.als_new_data) + return DataAvail::NO_DATA; + + if (als_status.data_invalid) { + ESP_LOGW(TAG, "Data available but not valid"); + return DataAvail::BAD_DATA; + } + ESP_LOGV(TAG, "Data ready, reported gain is %.0f", get_gain_coeff(als_status.gain)); + if (data.gain != als_status.gain) { + ESP_LOGW(TAG, "Actual gain differs from requested (%.0f)", get_gain_coeff(data.gain)); + return DataAvail::BAD_DATA; + } + return DataAvail::DATA_OK; +} + +void LTRAlsPsComponent::read_sensor_data_(AlsReadings &data) { + data.ch1 = 0; + data.ch0 = 0; + uint8_t ch1_0 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH1_0).get(); + uint8_t ch1_1 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH1_1).get(); + uint8_t ch0_0 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH0_0).get(); + uint8_t ch0_1 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH0_1).get(); + data.ch1 = encode_uint16(ch1_1, ch1_0); + data.ch0 = encode_uint16(ch0_1, ch0_0); + + ESP_LOGV(TAG, "Got sensor data: CH1 = %d, CH0 = %d", data.ch1, data.ch0); +} + +bool LTRAlsPsComponent::are_adjustments_required_(AlsReadings &data) { + if (!this->automatic_mode_enabled_) + return false; + + if (data.number_of_adjustments > 15) { + // sometimes sensors fail to change sensitivity. this prevents us from infinite loop + ESP_LOGW(TAG, "Too many sensitivity adjustments done. Apparently, sensor reconfiguration fails. Stopping."); + return false; + } + data.number_of_adjustments++; + + // Recommended thresholds as per datasheet + static const uint16_t LOW_INTENSITY_THRESHOLD = 1000; + static const uint16_t HIGH_INTENSITY_THRESHOLD = 30000; + static const AlsGain GAINS[GAINS_COUNT] = {GAIN_1, GAIN_2, GAIN_4, GAIN_8, GAIN_48, GAIN_96}; + static const IntegrationTime INT_TIMES[TIMES_COUNT] = { + INTEGRATION_TIME_50MS, INTEGRATION_TIME_100MS, INTEGRATION_TIME_150MS, INTEGRATION_TIME_200MS, + INTEGRATION_TIME_250MS, INTEGRATION_TIME_300MS, INTEGRATION_TIME_350MS, INTEGRATION_TIME_400MS}; + + if (data.ch0 <= LOW_INTENSITY_THRESHOLD) { + AlsGain next_gain = get_next(GAINS, data.gain); + if (next_gain != data.gain) { + data.gain = next_gain; + ESP_LOGV(TAG, "Low illuminance. Increasing gain."); + return true; + } + IntegrationTime next_time = get_next(INT_TIMES, data.integration_time); + if (next_time != data.integration_time) { + data.integration_time = next_time; + ESP_LOGV(TAG, "Low illuminance. Increasing integration time."); + return true; + } + } else if (data.ch0 >= HIGH_INTENSITY_THRESHOLD) { + AlsGain prev_gain = get_prev(GAINS, data.gain); + if (prev_gain != data.gain) { + data.gain = prev_gain; + ESP_LOGV(TAG, "High illuminance. Decreasing gain."); + return true; + } + IntegrationTime prev_time = get_prev(INT_TIMES, data.integration_time); + if (prev_time != data.integration_time) { + data.integration_time = prev_time; + ESP_LOGV(TAG, "High illuminance. Decreasing integration time."); + return true; + } + } else { + ESP_LOGD(TAG, "Illuminance is sufficient."); + return false; + } + ESP_LOGD(TAG, "Can't adjust sensitivity anymore."); + return false; +} + +void LTRAlsPsComponent::apply_lux_calculation_(AlsReadings &data) { + if ((data.ch0 == 0xFFFF) || (data.ch1 == 0xFFFF)) { + ESP_LOGW(TAG, "Sensors got saturated"); + data.lux = 0.0f; + return; + } + + if ((data.ch0 == 0x0000) && (data.ch1 == 0x0000)) { + ESP_LOGW(TAG, "Sensors blacked out"); + data.lux = 0.0f; + return; + } + + float ch0 = data.ch0; + float ch1 = data.ch1; + float ratio = ch1 / (ch0 + ch1); + float als_gain = get_gain_coeff(data.gain); + float als_time = ((float) get_itime_ms(data.integration_time)) / 100.0f; + float inv_pfactor = this->glass_attenuation_factor_; + float lux = 0.0f; + + if (ratio < 0.45) { + lux = (1.7743 * ch0 + 1.1059 * ch1); + } else if (ratio < 0.64 && ratio >= 0.45) { + lux = (4.2785 * ch0 - 1.9548 * ch1); + } else if (ratio < 0.85 && ratio >= 0.64) { + lux = (0.5926 * ch0 + 0.1185 * ch1); + } else { + ESP_LOGW(TAG, "Impossible ch1/(ch0 + ch1) ratio"); + lux = 0.0f; + } + lux = inv_pfactor * lux / als_gain / als_time; + data.lux = lux; + + ESP_LOGV(TAG, "Lux calculation: ratio %.3f, gain %.0fx, int time %.1f, inv_pfactor %.3f, lux %.3f", ratio, als_gain, + als_time, inv_pfactor, lux); +} + +void LTRAlsPsComponent::publish_data_part_1_(AlsReadings &data) { + if (this->proximity_counts_sensor_ != nullptr) { + this->proximity_counts_sensor_->publish_state(this->ps_readings_); + } + if (this->ambient_light_sensor_ != nullptr) { + this->ambient_light_sensor_->publish_state(data.lux); + } + if (this->infrared_counts_sensor_ != nullptr) { + this->infrared_counts_sensor_->publish_state(data.ch1); + } + if (this->full_spectrum_counts_sensor_ != nullptr) { + this->full_spectrum_counts_sensor_->publish_state(data.ch0); + } +} + +void LTRAlsPsComponent::publish_data_part_2_(AlsReadings &data) { + if (this->actual_gain_sensor_ != nullptr) { + this->actual_gain_sensor_->publish_state(get_gain_coeff(data.gain)); + } + if (this->actual_integration_time_sensor_ != nullptr) { + this->actual_integration_time_sensor_->publish_state(get_itime_ms(data.integration_time)); + } +} +} // namespace ltr_als_ps +} // namespace esphome diff --git a/esphome/components/ltr_als_ps/ltr_als_ps.h b/esphome/components/ltr_als_ps/ltr_als_ps.h new file mode 100644 index 0000000000..4cbbcea54c --- /dev/null +++ b/esphome/components/ltr_als_ps/ltr_als_ps.h @@ -0,0 +1,184 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/optional.h" +#include "esphome/core/automation.h" + +#include "ltr_definitions.h" + +namespace esphome { +namespace ltr_als_ps { + +enum DataAvail : uint8_t { NO_DATA, BAD_DATA, DATA_OK }; + +enum LtrType : uint8_t { + LTR_TYPE_UNKNOWN = 0, + LTR_TYPE_ALS_ONLY = 1, + LTR_TYPE_PS_ONLY = 2, + LTR_TYPE_ALS_AND_PS = 3, +}; + +class LTRAlsPsComponent : public PollingComponent, public i2c::I2CDevice { + public: + // + // EspHome framework functions + // + float get_setup_priority() const override { return setup_priority::DATA; } + void setup() override; + void dump_config() override; + void update() override; + void loop() override; + + // Configuration setters : General + // + void set_ltr_type(LtrType type) { this->ltr_type_ = type; } + + // Configuration setters : ALS + // + void set_als_auto_mode(bool enable) { this->automatic_mode_enabled_ = enable; } + void set_als_gain(AlsGain gain) { this->gain_ = gain; } + void set_als_integration_time(IntegrationTime time) { this->integration_time_ = time; } + void set_als_meas_repeat_rate(MeasurementRepeatRate rate) { this->repeat_rate_ = rate; } + void set_als_glass_attenuation_factor(float factor) { this->glass_attenuation_factor_ = factor; } + + // Configuration setters : PS + // + void set_ps_high_threshold(uint16_t threshold) { this->ps_threshold_high_ = threshold; } + void set_ps_low_threshold(uint16_t threshold) { this->ps_threshold_low_ = threshold; } + void set_ps_cooldown_time_s(uint16_t time) { this->ps_cooldown_time_s_ = time; } + void set_ps_gain(PsGain gain) { this->ps_gain_ = gain; } + + // Sensors setters + // + void set_ambient_light_sensor(sensor::Sensor *sensor) { this->ambient_light_sensor_ = sensor; } + void set_full_spectrum_counts_sensor(sensor::Sensor *sensor) { this->full_spectrum_counts_sensor_ = sensor; } + void set_infrared_counts_sensor(sensor::Sensor *sensor) { this->infrared_counts_sensor_ = sensor; } + void set_actual_gain_sensor(sensor::Sensor *sensor) { this->actual_gain_sensor_ = sensor; } + void set_actual_integration_time_sensor(sensor::Sensor *sensor) { this->actual_integration_time_sensor_ = sensor; } + void set_proximity_counts_sensor(sensor::Sensor *sensor) { this->proximity_counts_sensor_ = sensor; } + + protected: + // + // Internal state machine, used to split all the actions into + // small steps in loop() to make sure we are not blocking execution + // + enum class State : uint8_t { + NOT_INITIALIZED, + DELAYED_SETUP, + IDLE, + WAITING_FOR_DATA, + COLLECTING_DATA_AUTO, + DATA_COLLECTED, + ADJUSTMENT_IN_PROGRESS, + READY_TO_PUBLISH, + KEEP_PUBLISHING + } state_{State::NOT_INITIALIZED}; + + LtrType ltr_type_{LtrType::LTR_TYPE_ALS_ONLY}; + + // + // Current measurements data + // + struct AlsReadings { + uint16_t ch0{0}; + uint16_t ch1{0}; + AlsGain gain{AlsGain::GAIN_1}; + IntegrationTime integration_time{IntegrationTime::INTEGRATION_TIME_100MS}; + float lux{0.0f}; + uint8_t number_of_adjustments{0}; + } als_readings_; + uint16_t ps_readings_{0xfffe}; + + inline bool is_als_() const { + return this->ltr_type_ == LtrType::LTR_TYPE_ALS_ONLY || this->ltr_type_ == LtrType::LTR_TYPE_ALS_AND_PS; + } + inline bool is_ps_() const { + return this->ltr_type_ == LtrType::LTR_TYPE_PS_ONLY || this->ltr_type_ == LtrType::LTR_TYPE_ALS_AND_PS; + } + + // + // Device interaction and data manipulation + // + bool check_part_number_(); + + void configure_reset_(); + void configure_als_(); + void configure_integration_time_(IntegrationTime time); + void configure_gain_(AlsGain gain); + DataAvail is_als_data_ready_(AlsReadings &data); + void read_sensor_data_(AlsReadings &data); + bool are_adjustments_required_(AlsReadings &data); + void apply_lux_calculation_(AlsReadings &data); + void publish_data_part_1_(AlsReadings &data); + void publish_data_part_2_(AlsReadings &data); + + void configure_ps_(); + uint16_t read_ps_data_(); + void check_and_trigger_ps_(); + + // + // Component configuration + // + bool automatic_mode_enabled_{true}; + AlsGain gain_{AlsGain::GAIN_1}; + IntegrationTime integration_time_{IntegrationTime::INTEGRATION_TIME_100MS}; + MeasurementRepeatRate repeat_rate_{MeasurementRepeatRate::REPEAT_RATE_500MS}; + float glass_attenuation_factor_{1.0}; + + uint16_t ps_cooldown_time_s_{5}; + PsGain ps_gain_{PsGain::PS_GAIN_16}; + uint16_t ps_threshold_high_{0xffff}; + uint16_t ps_threshold_low_{0x0000}; + + // + // Sensors for publishing data + // + sensor::Sensor *infrared_counts_sensor_{nullptr}; // direct reading CH1, infrared only + sensor::Sensor *full_spectrum_counts_sensor_{nullptr}; // direct reading CH0, infrared + visible light + sensor::Sensor *ambient_light_sensor_{nullptr}; // calculated lux + sensor::Sensor *actual_gain_sensor_{nullptr}; // actual gain of reading + sensor::Sensor *actual_integration_time_sensor_{nullptr}; // actual integration time + sensor::Sensor *proximity_counts_sensor_{nullptr}; // proximity sensor + + bool is_any_als_sensor_enabled_() const { + return this->ambient_light_sensor_ != nullptr || this->full_spectrum_counts_sensor_ != nullptr || + this->infrared_counts_sensor_ != nullptr || this->actual_gain_sensor_ != nullptr || + this->actual_integration_time_sensor_ != nullptr; + } + bool is_any_ps_sensor_enabled_() const { return this->proximity_counts_sensor_ != nullptr; } + + // + // Trigger section for the automations + // + friend class LTRPsHighTrigger; + friend class LTRPsLowTrigger; + + CallbackManager on_ps_high_trigger_callback_; + CallbackManager on_ps_low_trigger_callback_; + + void add_on_ps_high_trigger_callback_(std::function callback) { + this->on_ps_high_trigger_callback_.add(std::move(callback)); + } + + void add_on_ps_low_trigger_callback_(std::function callback) { + this->on_ps_low_trigger_callback_.add(std::move(callback)); + } +}; + +class LTRPsHighTrigger : public Trigger<> { + public: + explicit LTRPsHighTrigger(LTRAlsPsComponent *parent) { + parent->add_on_ps_high_trigger_callback_([this]() { this->trigger(); }); + } +}; + +class LTRPsLowTrigger : public Trigger<> { + public: + explicit LTRPsLowTrigger(LTRAlsPsComponent *parent) { + parent->add_on_ps_low_trigger_callback_([this]() { this->trigger(); }); + } +}; +} // namespace ltr_als_ps +} // namespace esphome diff --git a/esphome/components/ltr_als_ps/ltr_definitions.h b/esphome/components/ltr_als_ps/ltr_definitions.h new file mode 100644 index 0000000000..739445e9a0 --- /dev/null +++ b/esphome/components/ltr_als_ps/ltr_definitions.h @@ -0,0 +1,275 @@ +#pragma once + +#include + +namespace esphome { +namespace ltr_als_ps { + +enum class CommandRegisters : uint8_t { + ALS_CONTR = 0x80, // ALS operation mode control and SW reset + PS_CONTR = 0x81, // PS operation mode control + PS_LED = 0x82, // PS LED pulse frequency control + PS_N_PULSES = 0x83, // PS number of pulses control + PS_MEAS_RATE = 0x84, // PS measurement rate in active mode + MEAS_RATE = 0x85, // ALS measurement rate in active mode + PART_ID = 0x86, // Part Number ID and Revision ID + MANUFAC_ID = 0x87, // Manufacturer ID + ALS_DATA_CH1_0 = 0x88, // ALS measurement CH1 data, lower byte - infrared only + ALS_DATA_CH1_1 = 0x89, // ALS measurement CH1 data, upper byte - infrared only + ALS_DATA_CH0_0 = 0x8A, // ALS measurement CH0 data, lower byte - visible + infrared + ALS_DATA_CH0_1 = 0x8B, // ALS measurement CH0 data, upper byte - visible + infrared + ALS_PS_STATUS = 0x8C, // ALS PS new data status + PS_DATA_0 = 0x8D, // PS measurement data, lower byte + PS_DATA_1 = 0x8E, // PS measurement data, upper byte + ALS_PS_INTERRUPT = 0x8F, // Interrupt status + PS_THRES_UP_0 = 0x90, // PS interrupt upper threshold, lower byte + PS_THRES_UP_1 = 0x91, // PS interrupt upper threshold, upper byte + PS_THRES_LOW_0 = 0x92, // PS interrupt lower threshold, lower byte + PS_THRES_LOW_1 = 0x93, // PS interrupt lower threshold, upper byte + PS_OFFSET_1 = 0x94, // PS offset, upper byte + PS_OFFSET_0 = 0x95, // PS offset, lower byte + // 0x96 - reserved + ALS_THRES_UP_0 = 0x97, // ALS interrupt upper threshold, lower byte + ALS_THRES_UP_1 = 0x98, // ALS interrupt upper threshold, upper byte + ALS_THRES_LOW_0 = 0x99, // ALS interrupt lower threshold, lower byte + ALS_THRES_LOW_1 = 0x9A, // ALS interrupt lower threshold, upper byte + // 0x9B - reserved + // 0x9C - reserved + // 0x9D - reserved + INTERRUPT_PERSIST = 0x9E // Interrupt persistence filter +}; + +// ALS Sensor gain levels +enum AlsGain : uint8_t { + GAIN_1 = 0, // default + GAIN_2 = 1, + GAIN_4 = 2, + GAIN_8 = 3, + GAIN_48 = 6, + GAIN_96 = 7, +}; +static const uint8_t GAINS_COUNT = 6; + +// ALS Sensor integration times +enum IntegrationTime : uint8_t { + INTEGRATION_TIME_100MS = 0, // default + INTEGRATION_TIME_50MS = 1, + INTEGRATION_TIME_200MS = 2, + INTEGRATION_TIME_400MS = 3, + INTEGRATION_TIME_150MS = 4, + INTEGRATION_TIME_250MS = 5, + INTEGRATION_TIME_300MS = 6, + INTEGRATION_TIME_350MS = 7 +}; +static const uint8_t TIMES_COUNT = 8; + +// ALS Sensor measurement repeat rate +enum MeasurementRepeatRate { + REPEAT_RATE_50MS = 0, + REPEAT_RATE_100MS = 1, + REPEAT_RATE_200MS = 2, + REPEAT_RATE_500MS = 3, // default + REPEAT_RATE_1000MS = 4, + REPEAT_RATE_2000MS = 5 +}; + +// PS Sensor gain levels +enum PsGain : uint8_t { + PS_GAIN_16 = 0, // default + PS_GAIN_32 = 2, + PS_GAIN_64 = 3, +}; + +// PS Mode +enum PsMode : uint8_t { + PS_MODE_STANDBY_00 = 0, // default + PS_MODE_STANDBY_01 = 1, + PS_MODE_ACTIVE_10 = 2, + PS_MODE_ACTIVE_11 = 3, +}; + +// LED Pulse Modulation Frequency +enum PsLedFreq : uint8_t { + PS_LED_FREQ_30KHZ = 0, + PS_LED_FREQ_40KHZ = 1, + PS_LED_FREQ_50KHZ = 2, + PS_LED_FREQ_60KHZ = 3, // default + PS_LED_FREQ_70KHZ = 4, + PS_LED_FREQ_80KHZ = 5, + PS_LED_FREQ_90KHZ = 6, + PS_LED_FREQ_100KHZ = 7, +}; + +// LED current duty +enum PsLedDuty : uint8_t { + PS_LED_DUTY_25 = 0, + PS_LED_DUTY_50 = 1, + PS_LED_DUTY_75 = 2, + PS_LED_DUTY_100 = 3, // default +}; + +// LED pulsed current level +enum PsLedCurrent : uint8_t { + PS_LED_CURRENT_5MA = 0, + PS_LED_CURRENT_10MA = 1, + PS_LED_CURRENT_20MA = 2, + PS_LED_CURRENT_50MA = 3, + PS_LED_CURRENT_100MA = 4, // default + PS_LED_CURRENT_100MA1 = 5, + PS_LED_CURRENT_100MA2 = 6, + PS_LED_CURRENT_100MA3 = 7, +}; + +// PS measurement rate +enum PsMeasurementRate : uint8_t { + PS_MEAS_RATE_50MS = 0, + PS_MEAS_RATE_70MS = 1, + PS_MEAS_RATE_100MS = 2, + PS_MEAS_RATE_200MS = 3, + PS_MEAS_RATE_500MS = 4, // default + PS_MEAS_RATE_1000MS = 5, + PS_MEAS_RATE_2000MS = 6, + PS_MEAS_RATE_2000MS1 = 7, + PS_MEAS_RATE_10MS = 8, +}; + +// +// ALS_CONTR Register (0x80) +// +union AlsControlRegister { + uint8_t raw; + struct { + bool active_mode : 1; + bool sw_reset : 1; + AlsGain gain : 3; + uint8_t reserved : 3; + } __attribute__((packed)); +}; + +// +// PS_CONTR Register (0x81) +// +union PsControlRegister { + uint8_t raw; + struct { + bool ps_mode_xxx : 1; + bool ps_mode_active : 1; + PsGain ps_gain : 2; // only LTR-659/558 + bool reserved_4 : 1; + bool ps_saturation_indicator_enable : 1; + bool reserved_6 : 1; + bool reserved_7 : 1; + } __attribute__((packed)); +}; + +// +// PS_LED Register (0x82) +// +union PsLedRegister { + uint8_t raw; + struct { + PsLedCurrent ps_led_current : 3; + PsLedDuty ps_led_duty : 2; + PsLedFreq ps_led_freq : 3; + } __attribute__((packed)); +}; + +// +// PS_N_PULSES Register (0x83) +// +union PsNPulsesRegister { + uint8_t raw; + struct { + uint8_t number_of_pulses : 4; + uint8_t reserved : 4; + } __attribute__((packed)); +}; + +// +// PS_MEAS_RATE Register (0x84) +// +union PsMeasurementRateRegister { + uint8_t raw; + struct { + PsMeasurementRate ps_measurement_rate : 4; + uint8_t reserved : 4; + } __attribute__((packed)); +}; + +// +// ALS_MEAS_RATE Register (0x85) +// +union MeasurementRateRegister { + uint8_t raw; + struct { + MeasurementRepeatRate measurement_repeat_rate : 3; + IntegrationTime integration_time : 3; + bool reserved_6 : 1; + bool reserved_7 : 1; + } __attribute__((packed)); +}; + +// +// PART_ID Register (0x86) (Read Only) +// +union PartIdRegister { + uint8_t raw; + struct { + uint8_t part_number_id : 4; + uint8_t revision_id : 4; + } __attribute__((packed)); +}; + +// +// ALS_PS_STATUS Register (0x8C) (Read Only) +// +union AlsPsStatusRegister { + uint8_t raw; + struct { + bool ps_new_data : 1; // 0 - old data, 1 - new data + bool ps_interrupt : 1; // 0 - interrupt signal not active, 1 - interrupt signal active + bool als_new_data : 1; // 0 - old data, 1 - new data + bool als_interrupt : 1; // 0 - interrupt signal not active, 1 - interrupt signal active + AlsGain gain : 3; // current ALS gain + bool data_invalid : 1; + } __attribute__((packed)); +}; + +// +// PS_DATA_1 Register (0x8E) (Read Only) +// +union PsData1Register { + uint8_t raw; + struct { + uint8_t ps_data_high : 3; + uint8_t reserved : 4; + bool ps_saturation_flag : 1; + } __attribute__((packed)); +}; + +// +// INTERRUPT Register (0x8F) (Read Only) +// +union InterruptRegister { + uint8_t raw; + struct { + bool ps_interrupt : 1; + bool als_interrupt : 1; + bool interrupt_polarity : 1; // 0 - active low (default), 1 - active high + uint8_t reserved : 5; + } __attribute__((packed)); +}; + +// +// INTERRUPT_PERSIST Register (0x9E) +// +union InterruptPersistRegister { + uint8_t raw; + struct { + uint8_t als_persist : 4; // 0 - every ALS cycle, 1 - every 2 ALS cycles, ... 15 - every 16 ALS cycles + uint8_t ps_persist : 4; // 0 - every PS cycle, 1 - every 2 PS cycles, ... 15 - every 16 PS cycles + } __attribute__((packed)); +}; + +} // namespace ltr_als_ps +} // namespace esphome diff --git a/esphome/components/ltr_als_ps/sensor.py b/esphome/components/ltr_als_ps/sensor.py new file mode 100644 index 0000000000..ac9f7e6788 --- /dev/null +++ b/esphome/components/ltr_als_ps/sensor.py @@ -0,0 +1,271 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ACTUAL_GAIN, + CONF_AMBIENT_LIGHT, + CONF_AUTO_MODE, + CONF_GAIN, + CONF_GLASS_ATTENUATION_FACTOR, + CONF_ID, + CONF_INTEGRATION_TIME, + CONF_NAME, + CONF_REPEAT, + CONF_TRIGGER_ID, + CONF_TYPE, + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_ILLUMINANCE, + ICON_BRIGHTNESS_5, + ICON_BRIGHTNESS_6, + ICON_TIMER, + STATE_CLASS_MEASUREMENT, + UNIT_LUX, + UNIT_MILLISECOND, +) + +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" +CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" +CONF_INFRARED_COUNTS = "infrared_counts" +CONF_ON_PS_HIGH_THRESHOLD = "on_ps_high_threshold" +CONF_ON_PS_LOW_THRESHOLD = "on_ps_low_threshold" +CONF_PS_COOLDOWN = "ps_cooldown" +CONF_PS_COUNTS = "ps_counts" +CONF_PS_GAIN = "ps_gain" +CONF_PS_HIGH_THRESHOLD = "ps_high_threshold" +CONF_PS_LOW_THRESHOLD = "ps_low_threshold" +ICON_BRIGHTNESS_7 = "mdi:brightness-7" +ICON_GAIN = "mdi:multiplication" +ICON_PROXIMITY = "mdi:hand-wave-outline" +UNIT_COUNTS = "#" + +ltr_als_ps_ns = cg.esphome_ns.namespace("ltr_als_ps") + +LTRAlsPsComponent = ltr_als_ps_ns.class_( + "LTRAlsPsComponent", cg.PollingComponent, i2c.I2CDevice +) + +LtrType = ltr_als_ps_ns.enum("LtrType") +LTR_TYPES = { + "ALS": LtrType.LTR_TYPE_ALS_ONLY, + "PS": LtrType.LTR_TYPE_PS_ONLY, + "ALS_PS": LtrType.LTR_TYPE_ALS_AND_PS, +} + +AlsGain = ltr_als_ps_ns.enum("AlsGain") +ALS_GAINS = { + "1X": AlsGain.GAIN_1, + "2X": AlsGain.GAIN_2, + "4X": AlsGain.GAIN_4, + "8X": AlsGain.GAIN_8, + "48X": AlsGain.GAIN_48, + "96X": AlsGain.GAIN_96, +} + +IntegrationTime = ltr_als_ps_ns.enum("IntegrationTime") +INTEGRATION_TIMES = { + 50: IntegrationTime.INTEGRATION_TIME_50MS, + 100: IntegrationTime.INTEGRATION_TIME_100MS, + 150: IntegrationTime.INTEGRATION_TIME_150MS, + 200: IntegrationTime.INTEGRATION_TIME_200MS, + 250: IntegrationTime.INTEGRATION_TIME_250MS, + 300: IntegrationTime.INTEGRATION_TIME_300MS, + 350: IntegrationTime.INTEGRATION_TIME_350MS, + 400: IntegrationTime.INTEGRATION_TIME_400MS, +} + +MeasurementRepeatRate = ltr_als_ps_ns.enum("MeasurementRepeatRate") +MEASUREMENT_REPEAT_RATES = { + 50: MeasurementRepeatRate.REPEAT_RATE_50MS, + 100: MeasurementRepeatRate.REPEAT_RATE_100MS, + 200: MeasurementRepeatRate.REPEAT_RATE_200MS, + 500: MeasurementRepeatRate.REPEAT_RATE_500MS, + 1000: MeasurementRepeatRate.REPEAT_RATE_1000MS, + 2000: MeasurementRepeatRate.REPEAT_RATE_2000MS, +} + +PsGain = ltr_als_ps_ns.enum("PsGain") +PS_GAINS = { + "16X": PsGain.PS_GAIN_16, + "32X": PsGain.PS_GAIN_32, + "64X": PsGain.PS_GAIN_64, +} + +LTRPsHighTrigger = ltr_als_ps_ns.class_( + "LTRPsHighTrigger", automation.Trigger.template() +) +LTRPsLowTrigger = ltr_als_ps_ns.class_("LTRPsLowTrigger", automation.Trigger.template()) + + +def validate_integration_time(value): + value = cv.positive_time_period_milliseconds(value).total_milliseconds + return cv.enum(INTEGRATION_TIMES, int=True)(value) + + +def validate_repeat_rate(value): + value = cv.positive_time_period_milliseconds(value).total_milliseconds + return cv.enum(MEASUREMENT_REPEAT_RATES, int=True)(value) + + +def validate_time_and_repeat_rate(config): + integraton_time = config[CONF_INTEGRATION_TIME] + repeat_rate = config[CONF_REPEAT] + if integraton_time > repeat_rate: + raise cv.Invalid( + f"Measurement repeat rate ({repeat_rate}ms) shall be greater or equal to integration time ({integraton_time}ms)" + ) + return config + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(LTRAlsPsComponent), + cv.Optional(CONF_TYPE, default="ALS_PS"): cv.enum(LTR_TYPES, upper=True), + cv.Optional(CONF_AUTO_MODE, default=True): cv.boolean, + cv.Optional(CONF_GAIN, default="1X"): cv.enum(ALS_GAINS, upper=True), + cv.Optional( + CONF_INTEGRATION_TIME, default="100ms" + ): validate_integration_time, + cv.Optional(CONF_REPEAT, default="500ms"): validate_repeat_rate, + cv.Optional(CONF_GLASS_ATTENUATION_FACTOR, default=1.0): cv.float_range( + min=1.0 + ), + cv.Optional( + CONF_PS_COOLDOWN, default="5s" + ): cv.positive_time_period_seconds, + cv.Optional(CONF_PS_GAIN, default="16X"): cv.enum(PS_GAINS, upper=True), + cv.Optional(CONF_PS_HIGH_THRESHOLD, default=65535): cv.int_range( + min=0, max=65535 + ), + cv.Optional(CONF_PS_LOW_THRESHOLD, default=0): cv.int_range( + min=0, max=65535 + ), + cv.Optional(CONF_ON_PS_HIGH_THRESHOLD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LTRPsHighTrigger), + } + ), + cv.Optional(CONF_ON_PS_LOW_THRESHOLD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LTRPsLowTrigger), + } + ), + cv.Optional(CONF_AMBIENT_LIGHT): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_BRIGHTNESS_6, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_INFRARED_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_5, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_FULL_SPECTRUM_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_7, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_PS_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_PROXIMITY, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_GAIN): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_GAIN, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_INTEGRATION_TIME): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_MILLISECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x29)), + validate_time_and_repeat_rate, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if als_config := config.get(CONF_AMBIENT_LIGHT): + sens = await sensor.new_sensor(als_config) + cg.add(var.set_ambient_light_sensor(sens)) + + if infrared_cnt_config := config.get(CONF_INFRARED_COUNTS): + sens = await sensor.new_sensor(infrared_cnt_config) + cg.add(var.set_infrared_counts_sensor(sens)) + + if full_spect_cnt_config := config.get(CONF_FULL_SPECTRUM_COUNTS): + sens = await sensor.new_sensor(full_spect_cnt_config) + cg.add(var.set_full_spectrum_counts_sensor(sens)) + + if act_gain_config := config.get(CONF_ACTUAL_GAIN): + sens = await sensor.new_sensor(act_gain_config) + cg.add(var.set_actual_gain_sensor(sens)) + + if act_itime_config := config.get(CONF_ACTUAL_INTEGRATION_TIME): + sens = await sensor.new_sensor(act_itime_config) + cg.add(var.set_actual_integration_time_sensor(sens)) + + if prox_cnt_config := config.get(CONF_PS_COUNTS): + sens = await sensor.new_sensor(prox_cnt_config) + cg.add(var.set_proximity_counts_sensor(sens)) + + for prox_high_tr in config.get(CONF_ON_PS_HIGH_THRESHOLD, []): + trigger = cg.new_Pvariable(prox_high_tr[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], prox_high_tr) + + for prox_low_tr in config.get(CONF_ON_PS_LOW_THRESHOLD, []): + trigger = cg.new_Pvariable(prox_low_tr[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], prox_low_tr) + + cg.add(var.set_ltr_type(config[CONF_TYPE])) + + cg.add(var.set_als_auto_mode(config[CONF_AUTO_MODE])) + cg.add(var.set_als_gain(config[CONF_GAIN])) + cg.add(var.set_als_integration_time(config[CONF_INTEGRATION_TIME])) + cg.add(var.set_als_meas_repeat_rate(config[CONF_REPEAT])) + cg.add(var.set_als_glass_attenuation_factor(config[CONF_GLASS_ATTENUATION_FACTOR])) + + cg.add(var.set_ps_cooldown_time_s(config[CONF_PS_COOLDOWN])) + cg.add(var.set_ps_gain(config[CONF_PS_GAIN])) + cg.add(var.set_ps_high_threshold(config[CONF_PS_HIGH_THRESHOLD])) + cg.add(var.set_ps_low_threshold(config[CONF_PS_LOW_THRESHOLD])) diff --git a/esphome/components/veml7700/sensor.py b/esphome/components/veml7700/sensor.py index 7ce05b47e4..7b0f75e70c 100644 --- a/esphome/components/veml7700/sensor.py +++ b/esphome/components/veml7700/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ACTUAL_GAIN, + CONF_AMBIENT_LIGHT, CONF_AUTO_MODE, CONF_FULL_SPECTRUM, CONF_GAIN, @@ -11,13 +12,13 @@ from esphome.const import ( CONF_INFRARED, CONF_INTEGRATION_TIME, CONF_NAME, - UNIT_LUX, - UNIT_MILLISECOND, + DEVICE_CLASS_ILLUMINANCE, ICON_BRIGHTNESS_5, ICON_BRIGHTNESS_6, ICON_TIMER, - DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT, + UNIT_LUX, + UNIT_MILLISECOND, ) CODEOWNERS = ["@latonita"] @@ -28,7 +29,6 @@ ICON_MULTIPLICATION = "mdi:multiplication" ICON_BRIGHTNESS_7 = "mdi:brightness-7" CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" -CONF_AMBIENT_LIGHT = "ambient_light" CONF_AMBIENT_LIGHT_COUNTS = "ambient_light_counts" CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" CONF_LUX_COMPENSATION = "lux_compensation" diff --git a/esphome/const.py b/esphome/const.py index 1aafffb5d0..ed0a9b1f64 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -49,6 +49,7 @@ CONF_AFTER = "after" CONF_ALLOW_OTHER_USES = "allow_other_uses" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" +CONF_AMBIENT_LIGHT = "ambient_light" CONF_ANALOG = "analog" CONF_AND = "and" CONF_ANGLE = "angle" diff --git a/tests/components/ltr_als_ps/common.yaml b/tests/components/ltr_als_ps/common.yaml new file mode 100644 index 0000000000..aa5c8abed7 --- /dev/null +++ b/tests/components/ltr_als_ps/common.yaml @@ -0,0 +1,11 @@ +sensor: + - platform: ltr_als_ps + address: 0x23 + i2c_id: i2c_als_ps + gain: 1x + integration_time: 100ms + ps_cooldown: 5 s + ambient_light: "Ambient light" + full_spectrum_counts: "Full spectrum counts" + infrared_counts: "Infrared counts" + actual_gain: "Actual gain" diff --git a/tests/components/ltr_als_ps/test.esp32-c3-idf.yaml b/tests/components/ltr_als_ps/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..d64d70f018 --- /dev/null +++ b/tests/components/ltr_als_ps/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr_als_ps/test.esp32-c3.yaml b/tests/components/ltr_als_ps/test.esp32-c3.yaml new file mode 100644 index 0000000000..d64d70f018 --- /dev/null +++ b/tests/components/ltr_als_ps/test.esp32-c3.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr_als_ps/test.esp32-idf.yaml b/tests/components/ltr_als_ps/test.esp32-idf.yaml new file mode 100644 index 0000000000..2349292a64 --- /dev/null +++ b/tests/components/ltr_als_ps/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ltr_als_ps/test.esp32.yaml b/tests/components/ltr_als_ps/test.esp32.yaml new file mode 100644 index 0000000000..2349292a64 --- /dev/null +++ b/tests/components/ltr_als_ps/test.esp32.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ltr_als_ps/test.esp8266.yaml b/tests/components/ltr_als_ps/test.esp8266.yaml new file mode 100644 index 0000000000..d64d70f018 --- /dev/null +++ b/tests/components/ltr_als_ps/test.esp8266.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr_als_ps/test.rp2040.yaml b/tests/components/ltr_als_ps/test.rp2040.yaml new file mode 100644 index 0000000000..d64d70f018 --- /dev/null +++ b/tests/components/ltr_als_ps/test.rp2040.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_als_ps + scl: 5 + sda: 4 + +<<: !include common.yaml From 2894a138e78418d2f61845fca6832053ca48292a Mon Sep 17 00:00:00 2001 From: NonaSuomy Date: Fri, 31 May 2024 01:13:11 -0400 Subject: [PATCH 1828/2607] Update const.py added missing millimeter (#6834) * Update const.py added missing millimeter Added missing millimeter * Fixed UNIT_MILLIMETER in multiple locations. --- esphome/components/a02yyuw/sensor.py | 4 ++-- esphome/components/hydreon_rgxx/sensor.py | 8 ++++---- esphome/components/mopeka_pro_check/sensor.py | 3 +-- esphome/components/mopeka_std_check/sensor.py | 3 +-- esphome/const.py | 1 + 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/esphome/components/a02yyuw/sensor.py b/esphome/components/a02yyuw/sensor.py index 5232b04546..d491a51be9 100644 --- a/esphome/components/a02yyuw/sensor.py +++ b/esphome/components/a02yyuw/sensor.py @@ -4,11 +4,11 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, ICON_ARROW_EXPAND_VERTICAL, DEVICE_CLASS_DISTANCE, + UNIT_MILLIMETER, ) CODEOWNERS = ["@TH-Braemer"] DEPENDENCIES = ["uart"] -UNIT_MILLIMETERS = "mm" a02yyuw_ns = cg.esphome_ns.namespace("a02yyuw") A02yyuwComponent = a02yyuw_ns.class_( @@ -17,7 +17,7 @@ A02yyuwComponent = a02yyuw_ns.class_( CONFIG_SCHEMA = sensor.sensor_schema( A02yyuwComponent, - unit_of_measurement=UNIT_MILLIMETERS, + unit_of_measurement=UNIT_MILLIMETER, icon=ICON_ARROW_EXPAND_VERTICAL, accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT, diff --git a/esphome/components/hydreon_rgxx/sensor.py b/esphome/components/hydreon_rgxx/sensor.py index 72b74bf624..fb2099c85e 100644 --- a/esphome/components/hydreon_rgxx/sensor.py +++ b/esphome/components/hydreon_rgxx/sensor.py @@ -12,13 +12,13 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, UNIT_CELSIUS, + UNIT_MILLIMETER, ICON_THERMOMETER, ) from . import RGModel, RG15Resolution, HydreonRGxxComponent UNIT_INTENSITY = "intensity" -UNIT_MILLIMETERS = "mm" UNIT_MILLIMETERS_PER_HOUR = "mm/h" CONF_ACC = "acc" @@ -85,19 +85,19 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_RESOLUTION): cv.enum(RG15_RESOLUTION, upper=False), cv.Optional(CONF_ACC): sensor.sensor_schema( - unit_of_measurement=UNIT_MILLIMETERS, + unit_of_measurement=UNIT_MILLIMETER, accuracy_decimals=2, device_class=DEVICE_CLASS_PRECIPITATION, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_EVENT_ACC): sensor.sensor_schema( - unit_of_measurement=UNIT_MILLIMETERS, + unit_of_measurement=UNIT_MILLIMETER, accuracy_decimals=2, device_class=DEVICE_CLASS_PRECIPITATION, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TOTAL_ACC): sensor.sensor_schema( - unit_of_measurement=UNIT_MILLIMETERS, + unit_of_measurement=UNIT_MILLIMETER, accuracy_decimals=2, device_class=DEVICE_CLASS_PRECIPITATION, state_class=STATE_CLASS_TOTAL_INCREASING, diff --git a/esphome/components/mopeka_pro_check/sensor.py b/esphome/components/mopeka_pro_check/sensor.py index 51a515ef0c..0ba33e94de 100644 --- a/esphome/components/mopeka_pro_check/sensor.py +++ b/esphome/components/mopeka_pro_check/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, UNIT_CELSIUS, + UNIT_MILLIMETER, STATE_CLASS_MEASUREMENT, CONF_BATTERY_LEVEL, DEVICE_CLASS_BATTERY, @@ -25,8 +26,6 @@ ICON_PROPANE_TANK = "mdi:propane-tank" TANK_TYPE_CUSTOM = "CUSTOM" -UNIT_MILLIMETER = "mm" - def small_distance(value): """small_distance is stored in mm""" diff --git a/esphome/components/mopeka_std_check/sensor.py b/esphome/components/mopeka_std_check/sensor.py index bbba798e95..ac745cf3d5 100644 --- a/esphome/components/mopeka_std_check/sensor.py +++ b/esphome/components/mopeka_std_check/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, UNIT_CELSIUS, + UNIT_MILLIMETER, STATE_CLASS_MEASUREMENT, CONF_BATTERY_LEVEL, DEVICE_CLASS_BATTERY, @@ -26,8 +27,6 @@ ICON_PROPANE_TANK = "mdi:propane-tank" TANK_TYPE_CUSTOM = "CUSTOM" -UNIT_MILLIMETER = "mm" - def small_distance(value): """small_distance is stored in mm""" diff --git a/esphome/const.py b/esphome/const.py index ed0a9b1f64..dcb353ab1c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1035,6 +1035,7 @@ UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" UNIT_MICROTESLA = "µT" UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" +UNIT_MILLIMETER = "mm" UNIT_MILLISECOND = "ms" UNIT_MILLISIEMENS_PER_CENTIMETER = "mS/cm" UNIT_MINUTE = "min" From 1f301df51d4389f16e6a059c2ac87186c9631be8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Fri, 31 May 2024 00:49:11 -0500 Subject: [PATCH 1829/2607] Fix log message in VA for IDF 5 (#6839) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index c2fd14fbd5..e4fd2f2e9d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -815,7 +815,7 @@ void VoiceAssistant::on_timer_event(const api::VoiceAssistantTimerEventResponse }; this->timers_[timer.id] = timer; ESP_LOGD(TAG, "Timer Event"); - ESP_LOGD(TAG, " Type: %d", msg.event_type); + ESP_LOGD(TAG, " Type: %" PRId32, msg.event_type); ESP_LOGD(TAG, " %s", timer.to_string().c_str()); switch (msg.event_type) { From 41e13fa6f437cac86916a99cf45ef8ce1a627d44 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 31 May 2024 17:49:48 -0700 Subject: [PATCH 1830/2607] Replace random non-ascii-print characters with standard substitutes (#6840) --- esphome/components/api/custom_api_device.h | 2 +- esphome/components/ethernet/ethernet_component.cpp | 8 ++++---- esphome/components/feedback/feedback_cover.cpp | 4 ++-- esphome/components/max6956/max6956.h | 2 +- esphome/components/ntc/sensor.py | 2 +- esphome/components/wifi/wifi_component.cpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/esphome/components/api/custom_api_device.h b/esphome/components/api/custom_api_device.h index 9f125a6149..845a35fc54 100644 --- a/esphome/components/api/custom_api_device.h +++ b/esphome/components/api/custom_api_device.h @@ -105,7 +105,7 @@ class CustomAPIDevice { /** Subscribe to the state (or attribute state) of an entity from Home Assistant. * * Usage: - *å + * * ```cpp * void setup() override { * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast"); diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 2a4e5cbad3..087a3b1750 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -576,11 +576,11 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { /* * Bit 7 is `RMII Reference Clock Select`. Default is `0`. * KSZ8081RNA: - * 0 - clock input to XI (Pin 8) is 25 MHz for RMII – 25 MHz clock mode. - * 1 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. + * 0 - clock input to XI (Pin 8) is 25 MHz for RMII - 25 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode. * KSZ8081RND: - * 0 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. - * 1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII – 25 MHz clock mode. + * 0 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII - 25 MHz clock mode. */ if ((phy_control_2 & (1 << 7)) != (1 << 7)) { phy_control_2 |= 1 << 7; diff --git a/esphome/components/feedback/feedback_cover.cpp b/esphome/components/feedback/feedback_cover.cpp index 117c626f58..fa3166ba65 100644 --- a/esphome/components/feedback/feedback_cover.cpp +++ b/esphome/components/feedback/feedback_cover.cpp @@ -244,7 +244,7 @@ void FeedbackCover::loop() { // update current position at requested interval, regardless of who started the movement // so that we also update UI if there was an external movement - // don´t save intermediate positions + // don't save intermediate positions if (now - this->last_publish_time_ > this->update_interval_) { this->publish_state(false); this->last_publish_time_ = now; @@ -274,7 +274,7 @@ void FeedbackCover::control(const CoverCall &call) { if (pos == this->position) { // already at target, - // for covers with built in end stop, if we don´t have sensors we should send the command again + // for covers with built in end stop, if we don't have sensors we should send the command again // to make sure the assumed state is not wrong if (this->has_built_in_endstop_ && ((pos == COVER_OPEN #ifdef USE_BINARY_SENSOR diff --git a/esphome/components/max6956/max6956.h b/esphome/components/max6956/max6956.h index 141164ab30..759fa45b07 100644 --- a/esphome/components/max6956/max6956.h +++ b/esphome/components/max6956/max6956.h @@ -29,7 +29,7 @@ enum MAX6956GPIORegisters { MAX6956_PORT_CONFIG_START = 0x09, // Port Configuration P7, P6, P5, P4 MAX6956_CURRENT_START = 0x12, // Current054 MAX6956_1PORT_VALUE_START = 0x20, // Port 0 only (virtual port, no action) - MAX6956_8PORTS_VALUE_START = 0x44, // 8 ports 4–11 (data bits D0–D7) + MAX6956_8PORTS_VALUE_START = 0x44, // 8 ports 4-11 (data bits D0-D7) }; enum MAX6956GPIOFlag { FLAG_LED = 0x20 }; diff --git a/esphome/components/ntc/sensor.py b/esphome/components/ntc/sensor.py index 06fc55fc43..961511fe00 100644 --- a/esphome/components/ntc/sensor.py +++ b/esphome/components/ntc/sensor.py @@ -100,7 +100,7 @@ def process_calibration(value): elif isinstance(value, list): if len(value) != 3: raise cv.Invalid( - "Steinhart–Hart Calibration must consist of exactly three values" + "Steinhart-Hart Calibration must consist of exactly three values" ) value = cv.Schema([validate_calibration_parameter])(value) a, b, c = calc_steinhart_hart(value) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 2f34f2b05b..1359e0b7c5 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -58,7 +58,7 @@ void WiFiComponent::setup() { void WiFiComponent::start() { ESP_LOGCONFIG(TAG, "Starting WiFi..."); - ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); + ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); this->last_connected_ = millis(); uint32_t hash = this->has_sta() ? fnv1_hash(App.get_compilation_time()) : 88491487UL; From 2beb1f033611c0984c3c4d11734e967cc8a1416f Mon Sep 17 00:00:00 2001 From: Simone Rossetto Date: Sat, 1 Jun 2024 04:36:51 +0200 Subject: [PATCH 1831/2607] Wireguard support for bk72 microcontrollers (#6842) * Bump esp_wireguard to v0.4.1 * add support for bk72 microcontrollers (thanks to kuba2k2) * fix compilation error using esp-idf v5 (thanks to kbx81) * fix crash on vpn disconnection with alive tcp connection (thanks to jefftharris) * Disable ipv6 for bk72 wireguard test * Completely remove ipv6 entry from bk72 wg test --- esphome/components/wireguard/__init__.py | 2 +- platformio.ini | 8 +-- tests/components/wireguard/test.bk72xx.yaml | 59 +++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 tests/components/wireguard/test.bk72xx.yaml diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 7612c7d964..177ad6d356 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -122,7 +122,7 @@ async def to_code(config): # the '+1' modifier is relative to the device's own address that will # be automatically added to the provided list. cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}") - cg.add_library("droscy/esp_wireguard", "0.4.0") + cg.add_library("droscy/esp_wireguard", "0.4.1") await cg.register_component(var, config) diff --git a/platformio.ini b/platformio.ini index fd0ae7c6d8..6b34b2f05d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -94,7 +94,7 @@ lib_deps = ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir - droscy/esp_wireguard@0.4.0 ; wireguard + droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:arduino.build_flags} -Wno-nonnull-compare @@ -124,7 +124,7 @@ lib_deps = DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir - droscy/esp_wireguard@0.4.0 ; wireguard + droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_ESP32 @@ -143,7 +143,7 @@ framework = espidf lib_deps = ${common:idf.lib_deps} espressif/esp32-camera@1.0.0 ; esp32_camera - droscy/esp_wireguard@0.4.0 ; wireguard + droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:idf.build_flags} -Wno-nonnull-compare @@ -174,6 +174,8 @@ build_flags = extends = common:arduino platform = libretiny framework = arduino +lib_deps = + droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_LIBRETINY diff --git a/tests/components/wireguard/test.bk72xx.yaml b/tests/components/wireguard/test.bk72xx.yaml new file mode 100644 index 0000000000..85325139a9 --- /dev/null +++ b/tests/components/wireguard/test.bk72xx.yaml @@ -0,0 +1,59 @@ +wifi: + ssid: "MySSID1" + password: "password1" + +time: + - platform: sntp + +wireguard: + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your vpn, they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' From 2353b2b5e1e66874a84f5f0e1e2ae0fff5780407 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sat, 1 Jun 2024 18:40:50 -0400 Subject: [PATCH 1832/2607] Add messages when WiFi and Ethernet components set 'warning' flag. (#6850) --- esphome/components/ethernet/ethernet_component.cpp | 2 +- esphome/components/wifi/wifi_component.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 087a3b1750..7672dc2dcb 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -410,7 +410,7 @@ void EthernetComponent::start_connect_() { global_eth_component->ipv6_count_ = 0; #endif /* USE_NETWORK_IPV6 */ this->connect_begin_ = millis(); - this->status_set_warning(); + this->status_set_warning("waiting for IP configuration"); esp_err_t err; err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str()); diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 1359e0b7c5..8c40f87879 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -135,7 +135,7 @@ void WiFiComponent::loop() { switch (this->state_) { case WIFI_COMPONENT_STATE_COOLDOWN: { - this->status_set_warning(); + this->status_set_warning("waiting to reconnect"); if (millis() - this->action_started_ > 5000) { if (this->fast_connect_ || this->retry_hidden_) { this->start_connecting(this->sta_[0], false); @@ -146,13 +146,13 @@ void WiFiComponent::loop() { break; } case WIFI_COMPONENT_STATE_STA_SCANNING: { - this->status_set_warning(); + this->status_set_warning("scanning for networks"); this->check_scanning_finished(); break; } case WIFI_COMPONENT_STATE_STA_CONNECTING: case WIFI_COMPONENT_STATE_STA_CONNECTING_2: { - this->status_set_warning(); + this->status_set_warning("associating to network"); this->check_connecting_finished(); break; } From b8d2a6f574e4f49d12d3e677220c9dd92a364aae Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 3 Jun 2024 05:23:49 +0200 Subject: [PATCH 1833/2607] [sntp] fix for ESP-IDF > 5.0 (#6769) * Make sntp work with ESP-IDF >= 5.0 * Set operatingmode on other than ESP-IDF --------- Co-authored-by: Keith Burzinski --- esphome/components/sntp/sntp_component.cpp | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/esphome/components/sntp/sntp_component.cpp b/esphome/components/sntp/sntp_component.cpp index 6a60e8d5c1..a0e791be75 100644 --- a/esphome/components/sntp/sntp_component.cpp +++ b/esphome/components/sntp/sntp_component.cpp @@ -1,16 +1,11 @@ #include "sntp_component.h" #include "esphome/core/log.h" -#if defined(USE_ESP32) || defined(USE_LIBRETINY) -#include "lwip/apps/sntp.h" #ifdef USE_ESP_IDF #include "esp_sntp.h" -#endif -#endif -#ifdef USE_ESP8266 +#elif USE_ESP8266 #include "sntp.h" -#endif -#ifdef USE_RP2040 +#else #include "lwip/apps/sntp.h" #endif @@ -27,14 +22,14 @@ static const char *const TAG = "sntp"; void SNTPComponent::setup() { #ifndef USE_HOST ESP_LOGCONFIG(TAG, "Setting up SNTP..."); -#if defined(USE_ESP32) || defined(USE_LIBRETINY) - if (sntp_enabled()) { - sntp_stop(); +#if defined(USE_ESP_IDF) + if (esp_sntp_enabled()) { + esp_sntp_stop(); } - sntp_setoperatingmode(SNTP_OPMODE_POLL); -#endif -#ifdef USE_ESP8266 + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); +#else sntp_stop(); + sntp_setoperatingmode(SNTP_OPMODE_POLL); #endif sntp_setservername(0, strdup(this->server_1_.c_str())); @@ -45,7 +40,7 @@ void SNTPComponent::setup() { sntp_setservername(2, strdup(this->server_3_.c_str())); } #ifdef USE_ESP_IDF - sntp_set_sync_interval(this->get_update_interval()); + esp_sntp_set_sync_interval(this->get_update_interval()); #endif sntp_init(); From 05491e756bb76c43c669009ac7afb5da877b5ee1 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Mon, 3 Jun 2024 18:34:47 -0700 Subject: [PATCH 1834/2607] Avoid unsafe git error when container user and file config volume permissions don't match (#6843) --- docker/Dockerfile | 3 +++ script/setup | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 3c661b7e1c..f6234235f7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -100,6 +100,9 @@ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "a --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ && /platformio_install_deps.py /platformio.ini --libraries +# Avoid unsafe git error when container user and file config volume permissions don't match +RUN git config --system --add safe.directory '/config/*' + # ======================= docker-type image ======================= FROM base AS docker diff --git a/script/setup b/script/setup index 1a18a6a9ea..aeb1b39bc1 100755 --- a/script/setup +++ b/script/setup @@ -13,11 +13,6 @@ if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ] && [ ! "$ESPHOME_NO_VENV" source $location fi -# Avoid unsafe git error when running inside devcontainer -if [ -n "$DEVCONTAINER" ]; then - git config --global --add safe.directory "$PWD" -fi - pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt -r requirements_dev.txt pip3 install setuptools wheel pip3 install -e ".[dev,test,displays]" --config-settings editable_mode=compat From 78b48209aa2456e05bc2c94357e58809d9c7403f Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Mon, 3 Jun 2024 19:57:05 -0700 Subject: [PATCH 1835/2607] Add Ethernet MAC address to ethernet_info (#6835) --- .../ethernet/ethernet_component.cpp | 54 +++++++++++++------ .../components/ethernet/ethernet_component.h | 4 ++ .../ethernet_info_text_sensor.cpp | 1 + .../ethernet_info/ethernet_info_text_sensor.h | 7 +++ .../components/ethernet_info/text_sensor.py | 11 ++++ tests/components/ethernet_info/common.yaml | 2 + 6 files changed, 63 insertions(+), 16 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 7672dc2dcb..6bb9732fef 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -28,6 +28,13 @@ EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non- return; \ } +#define ESPHL_ERROR_CHECK_RET(err, message, ret) \ + if ((err) != ESP_OK) { \ + ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \ + this->mark_failed(); \ + return ret; \ + } + EthernetComponent::EthernetComponent() { global_eth_component = this; } void EthernetComponent::setup() { @@ -498,22 +505,9 @@ void EthernetComponent::dump_connect_params_() { } #endif /* USE_NETWORK_IPV6 */ - esp_err_t err; - - uint8_t mac[6]; - err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, &mac); - ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error"); - ESP_LOGCONFIG(TAG, " MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - eth_duplex_t duplex_mode; - err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode); - ESPHL_ERROR_CHECK(err, "ETH_CMD_G_DUPLEX_MODE error"); - ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(duplex_mode == ETH_DUPLEX_FULL)); - - eth_speed_t speed; - err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed); - ESPHL_ERROR_CHECK(err, "ETH_CMD_G_SPEED error"); - ESP_LOGCONFIG(TAG, " Link Speed: %u", speed == ETH_SPEED_100M ? 100 : 10); + ESP_LOGCONFIG(TAG, " MAC Address: %s", this->get_eth_mac_address_pretty().c_str()); + ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL)); + ESP_LOGCONFIG(TAG, " Link Speed: %u", this->get_link_speed() == ETH_SPEED_100M ? 100 : 10); } #ifdef USE_ETHERNET_SPI @@ -546,6 +540,34 @@ std::string EthernetComponent::get_use_address() const { void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; } +void EthernetComponent::get_eth_mac_address_raw(uint8_t *mac) { + esp_err_t err; + err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, mac); + ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error"); +} + +std::string EthernetComponent::get_eth_mac_address_pretty() { + uint8_t mac[6]; + get_mac_address_raw(mac); + return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +eth_duplex_t EthernetComponent::get_duplex_mode() { + esp_err_t err; + eth_duplex_t duplex_mode; + err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode); + ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_DUPLEX_MODE error", ETH_DUPLEX_HALF); + return duplex_mode; +} + +eth_speed_t EthernetComponent::get_link_speed() { + esp_err_t err; + eth_speed_t speed; + err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed); + ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_SPEED error", ETH_SPEED_10M); + return speed; +} + bool EthernetComponent::powerdown() { ESP_LOGI(TAG, "Powering down ethernet PHY"); if (this->phy_ == nullptr) { diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 3705e3e06a..e57aa5fe12 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -74,6 +74,10 @@ class EthernetComponent : public Component { network::IPAddress get_dns_address(uint8_t num); std::string get_use_address() const; void set_use_address(const std::string &use_address); + void get_eth_mac_address_raw(uint8_t *mac); + std::string get_eth_mac_address_pretty(); + eth_duplex_t get_duplex_mode(); + eth_speed_t get_link_speed(); bool powerdown(); protected: diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp index c8b2b5885b..329fb9113a 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.cpp @@ -10,6 +10,7 @@ static const char *const TAG = "ethernet_info"; void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); } void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); } +void MACAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo MAC Address", this); } } // namespace ethernet_info } // namespace esphome diff --git a/esphome/components/ethernet_info/ethernet_info_text_sensor.h b/esphome/components/ethernet_info/ethernet_info_text_sensor.h index 82a7dcf56e..94eed886e5 100644 --- a/esphome/components/ethernet_info/ethernet_info_text_sensor.h +++ b/esphome/components/ethernet_info/ethernet_info_text_sensor.h @@ -59,6 +59,13 @@ class DNSAddressEthernetInfo : public PollingComponent, public text_sensor::Text std::string last_results_; }; +class MACAddressEthernetInfo : public Component, public text_sensor::TextSensor { + public: + void setup() override { this->publish_state(ethernet::global_eth_component->get_eth_mac_address_pretty()); } + std::string unique_id() override { return get_mac_address() + "-ethernetinfo-mac"; } + void dump_config() override; +}; + } // namespace ethernet_info } // namespace esphome diff --git a/esphome/components/ethernet_info/text_sensor.py b/esphome/components/ethernet_info/text_sensor.py index 292673c182..a545475870 100644 --- a/esphome/components/ethernet_info/text_sensor.py +++ b/esphome/components/ethernet_info/text_sensor.py @@ -4,6 +4,7 @@ from esphome.components import text_sensor from esphome.const import ( CONF_IP_ADDRESS, CONF_DNS_ADDRESS, + CONF_MAC_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC, ) @@ -19,6 +20,10 @@ DNSAddressEthernetInfo = ethernet_info_ns.class_( "DNSAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent ) +MACAddressEthernetInfo = ethernet_info_ns.class_( + "MACAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent +) + CONFIG_SCHEMA = cv.Schema( { cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema( @@ -36,6 +41,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema( DNSAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema( + MACAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ), } ) @@ -51,3 +59,6 @@ async def to_code(config): if conf := config.get(CONF_DNS_ADDRESS): dns_info = await text_sensor.new_text_sensor(config[CONF_DNS_ADDRESS]) await cg.register_component(dns_info, config[CONF_DNS_ADDRESS]) + if conf := config.get(CONF_MAC_ADDRESS): + mac_info = await text_sensor.new_text_sensor(config[CONF_MAC_ADDRESS]) + await cg.register_component(mac_info, config[CONF_MAC_ADDRESS]) diff --git a/tests/components/ethernet_info/common.yaml b/tests/components/ethernet_info/common.yaml index dade4d7ca5..d9a6f515b1 100644 --- a/tests/components/ethernet_info/common.yaml +++ b/tests/components/ethernet_info/common.yaml @@ -17,3 +17,5 @@ text_sensor: name: IP Address dns_address: name: DNS Address + mac_address: + name: MAC Address From cdf83c5d8c1f8ff99d77b63b04177d253feecbb3 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:09:46 +1000 Subject: [PATCH 1836/2607] Add host time platform; remove host support from sntp. (#6854) --- CODEOWNERS | 3 +- esphome/components/host/__init__.py | 2 +- esphome/components/host/time/__init__.py | 20 +++++++++++ esphome/components/host/time/host_time.h | 15 +++++++++ esphome/components/sntp/sntp_component.cpp | 4 +-- esphome/components/sntp/time.py | 39 ++++++++++++++++------ tests/components/host/common.yaml | 7 +--- tests/components/sntp/test.bk72xx.yaml | 1 + 8 files changed, 69 insertions(+), 22 deletions(-) create mode 100644 esphome/components/host/time/__init__.py create mode 100644 esphome/components/host/time/host_time.h create mode 100644 tests/components/sntp/test.bk72xx.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 0dc5339193..82f61c3b80 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -167,7 +167,8 @@ esphome/components/homeassistant/* @OttoWinter esphome/components/honeywell_hih_i2c/* @Benichou34 esphome/components/honeywellabp/* @RubyBailey esphome/components/honeywellabp2_i2c/* @jpfaff -esphome/components/host/* @esphome/core +esphome/components/host/* @clydebarrow @esphome/core +esphome/components/host/time/* @clydebarrow esphome/components/hrxl_maxsonar_wr/* @netmikey esphome/components/hte501/* @Stock-M esphome/components/htu31d/* @betterengineering diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 3bd3b6b172..39e418c9ea 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -16,7 +16,7 @@ from .const import KEY_HOST # force import gpio to register pin schema from .gpio import host_pin_to_code # noqa -CODEOWNERS = ["@esphome/core"] +CODEOWNERS = ["@esphome/core", "@clydebarrow"] AUTO_LOAD = ["network"] diff --git a/esphome/components/host/time/__init__.py b/esphome/components/host/time/__init__.py new file mode 100644 index 0000000000..76a88d98a1 --- /dev/null +++ b/esphome/components/host/time/__init__.py @@ -0,0 +1,20 @@ +import esphome.codegen as cg +from esphome.const import CONF_ID +import esphome.config_validation as cv +from esphome.components import time as time_ + +CODEOWNERS = ["@clydebarrow"] + +time_ns = cg.esphome_ns.namespace("host") +HostTime = time_ns.class_("HostTime", time_.RealTimeClock) +CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(HostTime), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await time_.register_time(var, config) diff --git a/esphome/components/host/time/host_time.h b/esphome/components/host/time/host_time.h new file mode 100644 index 0000000000..4f1473b809 --- /dev/null +++ b/esphome/components/host/time/host_time.h @@ -0,0 +1,15 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/time/real_time_clock.h" + +namespace esphome { +namespace host { + +class HostTime : public time::RealTimeClock { + public: + void update() override {} +}; + +} // namespace host +} // namespace esphome diff --git a/esphome/components/sntp/sntp_component.cpp b/esphome/components/sntp/sntp_component.cpp index a0e791be75..4ded98d483 100644 --- a/esphome/components/sntp/sntp_component.cpp +++ b/esphome/components/sntp/sntp_component.cpp @@ -20,7 +20,6 @@ namespace sntp { static const char *const TAG = "sntp"; void SNTPComponent::setup() { -#ifndef USE_HOST ESP_LOGCONFIG(TAG, "Setting up SNTP..."); #if defined(USE_ESP_IDF) if (esp_sntp_enabled()) { @@ -44,7 +43,6 @@ void SNTPComponent::setup() { #endif sntp_init(); -#endif } void SNTPComponent::dump_config() { ESP_LOGCONFIG(TAG, "SNTP Time:"); @@ -54,7 +52,7 @@ void SNTPComponent::dump_config() { ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); } void SNTPComponent::update() { -#if !defined(USE_ESP_IDF) && !defined(USE_HOST) +#if !defined(USE_ESP_IDF) // force resync if (sntp_enabled()) { sntp_stop(); diff --git a/esphome/components/sntp/time.py b/esphome/components/sntp/time.py index b1362f5421..7cc82e3dff 100644 --- a/esphome/components/sntp/time.py +++ b/esphome/components/sntp/time.py @@ -2,24 +2,41 @@ from esphome.components import time as time_ import esphome.config_validation as cv import esphome.codegen as cg from esphome.core import CORE -from esphome.const import CONF_ID, CONF_SERVERS - +from esphome.const import ( + CONF_ID, + CONF_SERVERS, + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, + PLATFORM_RTL87XX, + PLATFORM_BK72XX, +) DEPENDENCIES = ["network"] sntp_ns = cg.esphome_ns.namespace("sntp") SNTPComponent = sntp_ns.class_("SNTPComponent", time_.RealTimeClock) - DEFAULT_SERVERS = ["0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org"] -CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(SNTPComponent), - cv.Optional(CONF_SERVERS, default=DEFAULT_SERVERS): cv.All( - cv.ensure_list(cv.Any(cv.domain, cv.hostname)), cv.Length(min=1, max=3) - ), - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = cv.All( + time_.TIME_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(SNTPComponent), + cv.Optional(CONF_SERVERS, default=DEFAULT_SERVERS): cv.All( + cv.ensure_list(cv.Any(cv.domain, cv.hostname)), cv.Length(min=1, max=3) + ), + } + ).extend(cv.COMPONENT_SCHEMA), + cv.only_on( + [ + PLATFORM_ESP32, + PLATFORM_ESP8266, + PLATFORM_RP2040, + PLATFORM_BK72XX, + PLATFORM_RTL87XX, + ] + ), +) async def to_code(config): diff --git a/tests/components/host/common.yaml b/tests/components/host/common.yaml index 3d14c190a6..fca0c5d597 100644 --- a/tests/components/host/common.yaml +++ b/tests/components/host/common.yaml @@ -1,15 +1,10 @@ time: - - platform: sntp + - platform: host id: esptime timezone: Australia/Sydney logger: level: VERBOSE - logs: - lvgl: INFO - display: DEBUG - sensor: INFO - vnc: DEBUG host: mac_address: "62:23:45:AF:B3:DD" diff --git a/tests/components/sntp/test.bk72xx.yaml b/tests/components/sntp/test.bk72xx.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sntp/test.bk72xx.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 2d56d8d84feb8df4341725bfe0a409a44b5305a8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 3 Jun 2024 22:10:44 -0500 Subject: [PATCH 1837/2607] [wireguard] Implement workaround for crash on IDF 5+ (#6846) --- esphome/components/wireguard/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 177ad6d356..5d5f620b51 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -7,7 +7,10 @@ from esphome.const import ( CONF_TIME_ID, CONF_ADDRESS, CONF_REBOOT_TIMEOUT, + KEY_CORE, + KEY_FRAMEWORK_VERSION, ) +from esphome.components.esp32 import CORE, add_idf_sdkconfig_option from esphome.components import time from esphome.core import TimePeriod from esphome import automation @@ -117,6 +120,13 @@ async def to_code(config): if config[CONF_REQUIRE_CONNECTION_TO_PROCEED]: cg.add(var.disable_auto_proceed()) + # Workaround for crash on IDF 5+ + # See https://github.com/trombik/esp_wireguard/issues/33#issuecomment-1568503651 + if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version( + 5, 0, 0 + ): + add_idf_sdkconfig_option("CONFIG_LWIP_PPP_SUPPORT", True) + # This flag is added here because the esp_wireguard library statically # set the size of its allowed_ips list at compile time using this value; # the '+1' modifier is relative to the device's own address that will From eb75778f84e32eed1f5a497471f86bb964906166 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 3 Jun 2024 22:18:20 -0500 Subject: [PATCH 1838/2607] [improv_serial] Fix for IDF 4.4.7 (#6855) --- esphome/components/improv_serial/improv_serial_component.cpp | 1 + esphome/components/improv_serial/improv_serial_component.h | 1 + 2 files changed, 2 insertions(+) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 40297bee68..2937720496 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -109,6 +109,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) case logger::UART_SELECTION_USB_SERIAL_JTAG: usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); + usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7 break; #endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 default: diff --git a/esphome/components/improv_serial/improv_serial_component.h b/esphome/components/improv_serial/improv_serial_component.h index 8583d0762b..f737f93d86 100644 --- a/esphome/components/improv_serial/improv_serial_component.h +++ b/esphome/components/improv_serial/improv_serial_component.h @@ -17,6 +17,7 @@ #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ defined(USE_ESP32_VARIANT_ESP32H2) #include +#include #endif #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #include From 69d38f61371f4f0548b50bedd1ca48784fa51028 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:02:18 +1200 Subject: [PATCH 1839/2607] [ft5x06] Interrupt pin and code quality improvements (#6851) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- .../components/ft5x06/touchscreen/__init__.py | 8 +- .../ft5x06/touchscreen/ft5x06_touchscreen.cpp | 102 ++++++++++++++++++ .../ft5x06/touchscreen/ft5x06_touchscreen.h | 94 ++-------------- 3 files changed, 119 insertions(+), 85 deletions(-) create mode 100644 esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp diff --git a/esphome/components/ft5x06/touchscreen/__init__.py b/esphome/components/ft5x06/touchscreen/__init__.py index adeeac0d1a..4ceb50c709 100644 --- a/esphome/components/ft5x06/touchscreen/__init__.py +++ b/esphome/components/ft5x06/touchscreen/__init__.py @@ -1,8 +1,9 @@ +from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, touchscreen -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN from .. import ft5x06_ns FT5x06ButtonListener = ft5x06_ns.class_("FT5x06ButtonListener") @@ -16,6 +17,7 @@ FT5x06Touchscreen = ft5x06_ns.class_( CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(FT5x06Touchscreen), + cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, } ).extend(i2c.i2c_device_schema(0x48)) @@ -24,3 +26,7 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await i2c.register_i2c_device(var, config) await touchscreen.register_touchscreen(var, config) + + if interrupt_pin := config.get(CONF_INTERRUPT_PIN): + pin = await cg.gpio_pin_expression(interrupt_pin) + cg.add(var.set_interrupt_pin(pin)) diff --git a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp new file mode 100644 index 0000000000..bd603fdc10 --- /dev/null +++ b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp @@ -0,0 +1,102 @@ +#include "ft5x06_touchscreen.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace ft5x06 { + +static const char *const TAG = "ft5x06.touchscreen"; + +void FT5x06Touchscreen::setup() { + ESP_LOGCONFIG(TAG, "Setting up FT5x06 Touchscreen..."); + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->setup(); + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->interrupt_pin_->setup(); + this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); + } + + // wait 200ms after reset. + this->set_timeout(200, [this] { this->continue_setup_(); }); +} + +void FT5x06Touchscreen::continue_setup_() { + uint8_t data[4]; + if (!this->set_mode_(FT5X06_OP_MODE)) + return; + + if (!this->err_check_(this->read_register(FT5X06_VENDOR_ID_REG, data, 1), "Read Vendor ID")) + return; + switch (data[0]) { + case FT5X06_ID_1: + case FT5X06_ID_2: + case FT5X06_ID_3: + this->vendor_id_ = (VendorId) data[0]; + ESP_LOGD(TAG, "Read vendor ID 0x%X", data[0]); + break; + + default: + ESP_LOGE(TAG, "Unknown vendor ID 0x%X", data[0]); + this->mark_failed(); + return; + } + // reading the chip registers to get max x/y does not seem to work. + if (this->display_ != nullptr) { + if (this->x_raw_max_ == this->x_raw_min_) { + this->x_raw_max_ = this->display_->get_native_width(); + } + if (this->y_raw_max_ == this->y_raw_min_) { + this->y_raw_max_ = this->display_->get_native_height(); + } + } + ESP_LOGCONFIG(TAG, "FT5x06 Touchscreen setup complete"); +} + +void FT5x06Touchscreen::update_touches() { + uint8_t touch_cnt; + uint8_t data[MAX_TOUCHES][6]; + + if (!this->read_byte(FT5X06_TD_STATUS, &touch_cnt) || touch_cnt > MAX_TOUCHES) { + ESP_LOGW(TAG, "Failed to read status"); + return; + } + if (touch_cnt == 0) + return; + + if (!this->read_bytes(FT5X06_TOUCH_DATA, (uint8_t *) data, touch_cnt * 6)) { + ESP_LOGW(TAG, "Failed to read touch data"); + return; + } + for (uint8_t i = 0; i != touch_cnt; i++) { + uint8_t status = data[i][0] >> 6; + uint8_t id = data[i][2] >> 3; + uint16_t x = encode_uint16(data[i][0] & 0x0F, data[i][1]); + uint16_t y = encode_uint16(data[i][2] & 0xF, data[i][3]); + + ESP_LOGD(TAG, "Read %X status, id: %d, pos %d/%d", status, id, x, y); + if (status == 0 || status == 2) { + this->add_raw_touch_position_(id, x, y); + } + } +} + +void FT5x06Touchscreen::dump_config() { + ESP_LOGCONFIG(TAG, "FT5x06 Touchscreen:"); + ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, " Vendor ID: 0x%X", (int) this->vendor_id_); +} + +bool FT5x06Touchscreen::err_check_(i2c::ErrorCode err, const char *msg) { + if (err != i2c::ERROR_OK) { + this->mark_failed(); + ESP_LOGE(TAG, "%s failed - err 0x%X", msg, err); + return false; + } + return true; +} +bool FT5x06Touchscreen::set_mode_(FTMode mode) { + return this->err_check_(this->write_register(FT5X06_MODE_REG, (uint8_t *) &mode, 1), "Set mode"); +} + +} // namespace ft5x06 +} // namespace esphome diff --git a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h index 7ddd2e44d7..23e5a0c49f 100644 --- a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h +++ b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.h @@ -3,14 +3,12 @@ #include "esphome/components/i2c/i2c.h" #include "esphome/components/touchscreen/touchscreen.h" #include "esphome/core/component.h" +#include "esphome/core/gpio.h" #include "esphome/core/hal.h" -#include "esphome/core/log.h" namespace esphome { namespace ft5x06 { -static const char *const TAG = "ft5x06.touchscreen"; - enum VendorId { FT5X06_ID_UNKNOWN = 0, FT5X06_ID_1 = 0x51, @@ -39,91 +37,19 @@ static const size_t MAX_TOUCHES = 5; // max number of possible touches reported class FT5x06Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice { public: - void setup() override { - esph_log_config(TAG, "Setting up FT5x06 Touchscreen..."); - // wait 200ms after reset. - this->set_timeout(200, [this] { this->continue_setup_(); }); - } + void setup() override; + void dump_config() override; + void update_touches() override; - void continue_setup_(void) { - uint8_t data[4]; - if (!this->set_mode_(FT5X06_OP_MODE)) - return; - - if (!this->err_check_(this->read_register(FT5X06_VENDOR_ID_REG, data, 1), "Read Vendor ID")) - return; - switch (data[0]) { - case FT5X06_ID_1: - case FT5X06_ID_2: - case FT5X06_ID_3: - this->vendor_id_ = (VendorId) data[0]; - esph_log_d(TAG, "Read vendor ID 0x%X", data[0]); - break; - - default: - esph_log_e(TAG, "Unknown vendor ID 0x%X", data[0]); - this->mark_failed(); - return; - } - // reading the chip registers to get max x/y does not seem to work. - if (this->display_ != nullptr) { - if (this->x_raw_max_ == this->x_raw_min_) { - this->x_raw_max_ = this->display_->get_native_width(); - } - if (this->y_raw_max_ == this->y_raw_min_) { - this->y_raw_max_ = this->display_->get_native_height(); - } - } - esph_log_config(TAG, "FT5x06 Touchscreen setup complete"); - } - - void update_touches() override { - uint8_t touch_cnt; - uint8_t data[MAX_TOUCHES][6]; - - if (!this->read_byte(FT5X06_TD_STATUS, &touch_cnt) || touch_cnt > MAX_TOUCHES) { - esph_log_w(TAG, "Failed to read status"); - return; - } - if (touch_cnt == 0) - return; - - if (!this->read_bytes(FT5X06_TOUCH_DATA, (uint8_t *) data, touch_cnt * 6)) { - esph_log_w(TAG, "Failed to read touch data"); - return; - } - for (uint8_t i = 0; i != touch_cnt; i++) { - uint8_t status = data[i][0] >> 6; - uint8_t id = data[i][2] >> 3; - uint16_t x = encode_uint16(data[i][0] & 0x0F, data[i][1]); - uint16_t y = encode_uint16(data[i][2] & 0xF, data[i][3]); - - esph_log_d(TAG, "Read %X status, id: %d, pos %d/%d", status, id, x, y); - if (status == 0 || status == 2) { - this->add_raw_touch_position_(id, x, y); - } - } - } - - void dump_config() override { - esph_log_config(TAG, "FT5x06 Touchscreen:"); - esph_log_config(TAG, " Address: 0x%02X", this->address_); - esph_log_config(TAG, " Vendor ID: 0x%X", (int) this->vendor_id_); - } + void set_interrupt_pin(InternalGPIOPin *interrupt_pin) { this->interrupt_pin_ = interrupt_pin; } protected: - bool err_check_(i2c::ErrorCode err, const char *msg) { - if (err != i2c::ERROR_OK) { - this->mark_failed(); - esph_log_e(TAG, "%s failed - err 0x%X", msg, err); - return false; - } - return true; - } - bool set_mode_(FTMode mode) { - return this->err_check_(this->write_register(FT5X06_MODE_REG, (uint8_t *) &mode, 1), "Set mode"); - } + void continue_setup_(); + bool err_check_(i2c::ErrorCode err, const char *msg); + bool set_mode_(FTMode mode); VendorId vendor_id_{FT5X06_ID_UNKNOWN}; + + InternalGPIOPin *interrupt_pin_{nullptr}; }; } // namespace ft5x06 From ac9f57600db0f44a9a1b048e5228d6b67df29d50 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 20:00:09 +1200 Subject: [PATCH 1840/2607] [voice_assistant] Half the microphone ringbuffer size (#6830) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 59ba39c527..421bca9afb 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -17,7 +17,7 @@ static const char *const TAG = "voice_assistant"; static const size_t SAMPLE_RATE_HZ = 16000; static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms -static const size_t BUFFER_SIZE = 1024 * SAMPLE_RATE_HZ / 1000; +static const size_t BUFFER_SIZE = 512 * SAMPLE_RATE_HZ / 1000; static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t); static const size_t RECEIVE_SIZE = 1024; static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; From ce4a3d995006a6f2b0a7afbee2f47c9807f54831 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 May 2024 20:01:39 +1200 Subject: [PATCH 1841/2607] [i2s_speaker] Add buffer allocation failure checks (#6829) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 95e63035fe..7f03a43da4 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -19,10 +19,27 @@ void I2SAudioSpeaker::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker..."); this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent)); + if (this->buffer_queue_ == nullptr) { + ESP_LOGE(TAG, "Failed to create buffer queue"); + this->mark_failed(); + return; + } + this->event_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(TaskEvent)); + if (this->event_queue_ == nullptr) { + ESP_LOGE(TAG, "Failed to create event queue"); + this->mark_failed(); + return; + } } -void I2SAudioSpeaker::start() { this->state_ = speaker::STATE_STARTING; } +void I2SAudioSpeaker::start() { + if (this->is_failed()) { + ESP_LOGE(TAG, "Cannot start audio, speaker failed to setup"); + return; + } + this->state_ = speaker::STATE_STARTING; +} void I2SAudioSpeaker::start_() { if (!this->parent_->try_lock()) { return; // Waiting for another i2s component to return lock @@ -141,6 +158,8 @@ void I2SAudioSpeaker::player_task(void *params) { } void I2SAudioSpeaker::stop() { + if (this->is_failed()) + return; if (this->state_ == speaker::STATE_STOPPED) return; if (this->state_ == speaker::STATE_STARTING) { @@ -200,6 +219,10 @@ void I2SAudioSpeaker::loop() { } size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length) { + if (this->is_failed()) { + ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup"); + return 0; + } if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) { this->start(); } From 388b2c2de0e92f4f5a8d18379e651a266b3750fa Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 3 Jun 2024 22:18:20 -0500 Subject: [PATCH 1842/2607] [improv_serial] Fix for IDF 4.4.7 (#6855) --- esphome/components/improv_serial/improv_serial_component.cpp | 1 + esphome/components/improv_serial/improv_serial_component.h | 1 + 2 files changed, 2 insertions(+) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 40297bee68..2937720496 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -109,6 +109,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) case logger::UART_SELECTION_USB_SERIAL_JTAG: usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); + usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7 break; #endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 default: diff --git a/esphome/components/improv_serial/improv_serial_component.h b/esphome/components/improv_serial/improv_serial_component.h index 8583d0762b..f737f93d86 100644 --- a/esphome/components/improv_serial/improv_serial_component.h +++ b/esphome/components/improv_serial/improv_serial_component.h @@ -17,6 +17,7 @@ #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ defined(USE_ESP32_VARIANT_ESP32H2) #include +#include #endif #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #include From 664ee56dc5c3170bab8722dea504cbf072e95ccb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:51:29 +1200 Subject: [PATCH 1843/2607] Bump version to 2024.5.5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index ad5858dcf3..658773b3db 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.5.4" +__version__ = "2024.5.5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 594856899a657ce5787f00d3432982869d29a8e9 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Wed, 5 Jun 2024 02:51:56 -0400 Subject: [PATCH 1844/2607] [ethernet] Add config option to set arbitrary PHY register values (#6836) --- esphome/components/ethernet/__init__.py | 29 ++++++++++ .../ethernet/ethernet_component.cpp | 58 +++++++------------ .../components/ethernet/ethernet_component.h | 12 +++- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index ade94cb9f5..697436415b 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -11,6 +11,7 @@ from esphome.components.esp32.const import ( from esphome.const import ( CONF_DOMAIN, CONF_ID, + CONF_VALUE, CONF_MANUAL_IP, CONF_STATIC_IP, CONF_TYPE, @@ -26,6 +27,8 @@ from esphome.const import ( CONF_INTERRUPT_PIN, CONF_RESET_PIN, CONF_SPI, + CONF_PAGE_ID, + CONF_ADDRESS, ) from esphome.core import CORE, coroutine_with_priority from esphome.components.network import IPAddress @@ -36,11 +39,13 @@ DEPENDENCIES = ["esp32"] AUTO_LOAD = ["network"] ethernet_ns = cg.esphome_ns.namespace("ethernet") +PHYRegister = ethernet_ns.struct("PHYRegister") CONF_PHY_ADDR = "phy_addr" CONF_MDC_PIN = "mdc_pin" CONF_MDIO_PIN = "mdio_pin" CONF_CLK_MODE = "clk_mode" CONF_POWER_PIN = "power_pin" +CONF_PHY_REGISTERS = "phy_registers" CONF_CLOCK_SPEED = "clock_speed" @@ -117,6 +122,13 @@ BASE_SCHEMA = cv.Schema( } ).extend(cv.COMPONENT_SCHEMA) +PHY_REGISTER_SCHEMA = cv.Schema( + { + cv.Required(CONF_ADDRESS): cv.hex_int, + cv.Required(CONF_VALUE): cv.hex_int, + cv.Optional(CONF_PAGE_ID): cv.hex_int, + } +) RMII_SCHEMA = BASE_SCHEMA.extend( cv.Schema( { @@ -127,6 +139,7 @@ RMII_SCHEMA = BASE_SCHEMA.extend( ), cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31), cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number, + cv.Optional(CONF_PHY_REGISTERS): cv.ensure_list(PHY_REGISTER_SCHEMA), } ) ) @@ -198,6 +211,15 @@ def manual_ip(config): ) +def phy_register(address: int, value: int, page: int): + return cg.StructInitializer( + PHYRegister, + ("address", address), + ("value", value), + ("page", page), + ) + + @coroutine_with_priority(60.0) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) @@ -225,6 +247,13 @@ async def to_code(config): cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]])) if CONF_POWER_PIN in config: cg.add(var.set_power_pin(config[CONF_POWER_PIN])) + for register_value in config.get(CONF_PHY_REGISTERS, []): + reg = phy_register( + register_value.get(CONF_ADDRESS), + register_value.get(CONF_VALUE), + register_value.get(CONF_PAGE_ID), + ) + cg.add(var.add_phy_register(reg)) cg.add(var.set_type(ETHERNET_TYPES[config[CONF_TYPE]])) cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 6bb9732fef..75bdd29be7 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -195,9 +195,9 @@ void EthernetComponent::setup() { // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide. this->ksz8081_set_clock_reference_(mac); } - if (this->type_ == ETHERNET_TYPE_RTL8201 && this->clk_mode_ == EMAC_CLK_EXT_IN) { - // Change in default behavior of RTL8201FI may require register setting to enable external clock - this->rtl8201_set_rmii_mode_(mac); + + for (const auto &phy_register : this->phy_registers_) { + this->write_phy_register_(mac, phy_register); } #endif @@ -527,6 +527,7 @@ void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_ this->clk_mode_ = clk_mode; this->clk_gpio_ = clk_gpio; } +void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); } #endif void EthernetComponent::set_type(EthernetType type) { this->type_ = type; } void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; } @@ -613,44 +614,27 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); } } -constexpr uint8_t RTL8201_RMSR_REG_ADDR = 0x10; -void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) { + +void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data) { esp_err_t err; - uint32_t phy_rmii_mode; - err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07); - ESPHL_ERROR_CHECK(err, "Setting Page 7 failed"); + constexpr uint8_t eth_phy_psr_reg_addr = 0x1F; - /* - * RTL8201 RMII Mode Setting Register (RMSR) - * Page 7 Register 16 - * - * bit 0 Reserved 0 - * bit 1 Rg_rmii_rxdsel 1 (default) - * bit 2 Rg_rmii_rxdv_sel: 0 (default) - * bit 3 RMII Mode: 1 (RMII Mode) - * bit 4~7 Rg_rmii_rx_offset: 1111 (default) - * bit 8~11 Rg_rmii_tx_offset: 1111 (default) - * bit 12 Rg_rmii_clkdir: 1 (Input) - * bit 13~15 Reserved 000 - * - * Binary: 0001 1111 1111 1010 - * Hex: 0x1FFA - * - */ + if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) { + ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page); + err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, register_data.page); + ESPHL_ERROR_CHECK(err, "Select PHY Register page failed"); + } - err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); - ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); - ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04" PRIX32, phy_rmii_mode); + ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address); + ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value); + err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value); + ESPHL_ERROR_CHECK(err, "Writing PHY Register failed"); - err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA); - ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed"); - - err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode)); - ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed"); - ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04" PRIX32, phy_rmii_mode); - - err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0); - ESPHL_ERROR_CHECK(err, "Setting Page 0 failed"); + if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) { + ESP_LOGD(TAG, "Select PHY Register Page 0x%02" PRIX32, 0x0); + err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0); + ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed"); + } } #endif diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index e57aa5fe12..f0fe6cab87 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -35,6 +35,12 @@ struct ManualIP { network::IPAddress dns2; ///< The second DNS server. 0.0.0.0 for default. }; +struct PHYRegister { + uint32_t address; + uint32_t value; + uint32_t page; +}; + enum class EthernetComponentState { STOPPED, CONNECTING, @@ -66,6 +72,7 @@ class EthernetComponent : public Component { void set_mdc_pin(uint8_t mdc_pin); void set_mdio_pin(uint8_t mdio_pin); void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio); + void add_phy_register(PHYRegister register_value); #endif void set_type(EthernetType type); void set_manual_ip(const ManualIP &manual_ip); @@ -91,8 +98,8 @@ class EthernetComponent : public Component { void dump_connect_params_(); /// @brief Set `RMII Reference Clock Select` bit for KSZ8081. void ksz8081_set_clock_reference_(esp_eth_mac_t *mac); - /// @brief Set `RMII Mode Setting Register` for RTL8201. - void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac); + /// @brief Set arbitratry PHY registers from config. + void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data); std::string use_address_; #ifdef USE_ETHERNET_SPI @@ -111,6 +118,7 @@ class EthernetComponent : public Component { uint8_t mdio_pin_{18}; emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN}; emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO}; + std::vector phy_registers_{}; #endif EthernetType type_{ETHERNET_TYPE_UNKNOWN}; optional manual_ip_{}; From f36a96c8e20c3b593f7dc48ba9f74e2c1fafe97e Mon Sep 17 00:00:00 2001 From: svxa <59204027+svxa@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:35:19 +0200 Subject: [PATCH 1845/2607] Add carrier_frequency option to remote_transmitter.transmit_aeha (#6792) --- esphome/components/remote_base/__init__.py | 14 +++++++++++++- esphome/components/remote_base/aeha_protocol.cpp | 1 - esphome/components/remote_base/aeha_protocol.h | 2 ++ .../remote_transmitter/common-buttons.yaml | 1 + tests/test1.yaml | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 9d49026aa3..3d1c10a092 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1769,7 +1769,17 @@ def aeha_dumper(var, config): pass -@register_action("aeha", AEHAAction, AEHA_SCHEMA) +@register_action( + "aeha", + AEHAAction, + AEHA_SCHEMA.extend( + { + cv.Optional(CONF_CARRIER_FREQUENCY, default="38000Hz"): cv.All( + cv.frequency, cv.int_ + ), + } + ), +) async def aeha_action(var, config, args): template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) @@ -1777,6 +1787,8 @@ async def aeha_action(var, config, args): config[CONF_DATA], args, cg.std_vector.template(cg.uint8) ) cg.add(var.set_data(template_)) + templ = await cg.templatable(config[CONF_CARRIER_FREQUENCY], args, cg.uint32) + cg.add(var.set_carrier_frequency(templ)) # Haier diff --git a/esphome/components/remote_base/aeha_protocol.cpp b/esphome/components/remote_base/aeha_protocol.cpp index 40bdadf634..04fe731817 100644 --- a/esphome/components/remote_base/aeha_protocol.cpp +++ b/esphome/components/remote_base/aeha_protocol.cpp @@ -16,7 +16,6 @@ static const uint16_t BIT_ZERO_LOW_US = BITWISE; static const uint16_t TRAILER = BITWISE; void AEHAProtocol::encode(RemoteTransmitData *dst, const AEHAData &data) { - dst->set_carrier_frequency(38000); dst->reserve(2 + 32 + (data.data.size() * 2) + 1); dst->item(HEADER_HIGH_US, HEADER_LOW_US); diff --git a/esphome/components/remote_base/aeha_protocol.h b/esphome/components/remote_base/aeha_protocol.h index c41f3f8df1..51718eefcb 100644 --- a/esphome/components/remote_base/aeha_protocol.h +++ b/esphome/components/remote_base/aeha_protocol.h @@ -30,12 +30,14 @@ template class AEHAAction : public RemoteTransmitterActionBase, data) + TEMPLATABLE_VALUE(uint32_t, carrier_frequency); void set_data(const std::vector &data) { data_ = data; } void encode(RemoteTransmitData *dst, Ts... x) override { AEHAData data{}; data.address = this->address_.value(x...); data.data = this->data_.value(x...); + dst->set_carrier_frequency(this->carrier_frequency_.value(x...)); AEHAProtocol().encode(dst, data); } }; diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml index e727017e85..c6a2453b20 100644 --- a/tests/components/remote_transmitter/common-buttons.yaml +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -118,6 +118,7 @@ button: on_press: remote_transmitter.transmit_aeha: address: 0x8008 + carrier_frequency: 36700Hz data: [ 0x00, diff --git a/tests/test1.yaml b/tests/test1.yaml index 2a20a1bb45..c49ff307e5 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2906,6 +2906,7 @@ switch: turn_on_action: remote_transmitter.transmit_aeha: address: 0x8008 + carrier_frequency: 36700Hz data: [ 0x00, From c52d5c02791850317bc9302ef86a18fec6b01dd2 Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Wed, 5 Jun 2024 17:52:19 +1000 Subject: [PATCH 1846/2607] Add `invert_position_report` to `tuya.cover` (#6020) --- esphome/components/tuya/cover/__init__.py | 3 +++ esphome/components/tuya/cover/tuya_cover.cpp | 9 ++++++--- esphome/components/tuya/cover/tuya_cover.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/esphome/components/tuya/cover/__init__.py b/esphome/components/tuya/cover/__init__.py index f886c7030f..2dd66f814d 100644 --- a/esphome/components/tuya/cover/__init__.py +++ b/esphome/components/tuya/cover/__init__.py @@ -16,6 +16,7 @@ CONF_DIRECTION_DATAPOINT = "direction_datapoint" CONF_POSITION_DATAPOINT = "position_datapoint" CONF_POSITION_REPORT_DATAPOINT = "position_report_datapoint" CONF_INVERT_POSITION = "invert_position" +CONF_INVERT_POSITION_REPORT = "invert_position_report" TuyaCover = tuya_ns.class_("TuyaCover", cover.Cover, cg.Component) @@ -47,6 +48,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MIN_VALUE, default=0): cv.int_, cv.Optional(CONF_MAX_VALUE, default=100): cv.int_, cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean, + cv.Optional(CONF_INVERT_POSITION_REPORT, default=False): cv.boolean, cv.Optional(CONF_RESTORE_MODE, default="RESTORE"): cv.enum( RESTORE_MODES, upper=True ), @@ -71,6 +73,7 @@ async def to_code(config): cg.add(var.set_min_value(config[CONF_MIN_VALUE])) cg.add(var.set_max_value(config[CONF_MAX_VALUE])) cg.add(var.set_invert_position(config[CONF_INVERT_POSITION])) + cg.add(var.set_invert_position_report(config[CONF_INVERT_POSITION_REPORT])) cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) diff --git a/esphome/components/tuya/cover/tuya_cover.cpp b/esphome/components/tuya/cover/tuya_cover.cpp index fcb961f45e..14bf937cf7 100644 --- a/esphome/components/tuya/cover/tuya_cover.cpp +++ b/esphome/components/tuya/cover/tuya_cover.cpp @@ -51,7 +51,7 @@ void TuyaCover::setup() { return; } auto pos = float(datapoint.value_uint - this->min_value_) / this->value_range_; - this->position = 1.0f - pos; + this->position = this->invert_position_report_ ? pos : 1.0f - pos; this->publish_state(); }); } @@ -62,7 +62,7 @@ void TuyaCover::control(const cover::CoverCall &call) { this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_STOP); } else { auto pos = this->position; - pos = 1.0f - pos; + pos = this->invert_position_report_ ? pos : 1.0f - pos; auto position_int = static_cast(pos * this->value_range_); position_int = position_int + this->min_value_; @@ -78,7 +78,7 @@ void TuyaCover::control(const cover::CoverCall &call) { this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_CLOSE); } } else { - pos = 1.0f - pos; + pos = this->invert_position_report_ ? pos : 1.0f - pos; auto position_int = static_cast(pos * this->value_range_); position_int = position_int + this->min_value_; @@ -112,6 +112,9 @@ void TuyaCover::dump_config() { ESP_LOGCONFIG(TAG, " Configured as Inverted, but direction_datapoint isn't configured"); } } + if (this->invert_position_report_) { + ESP_LOGCONFIG(TAG, " Position Reporting Inverted"); + } if (this->control_id_.has_value()) { ESP_LOGCONFIG(TAG, " Control has datapoint ID %u", *this->control_id_); } diff --git a/esphome/components/tuya/cover/tuya_cover.h b/esphome/components/tuya/cover/tuya_cover.h index 87c72b0e66..bb5a00bc59 100644 --- a/esphome/components/tuya/cover/tuya_cover.h +++ b/esphome/components/tuya/cover/tuya_cover.h @@ -25,6 +25,7 @@ class TuyaCover : public cover::Cover, public Component { void set_min_value(uint32_t min_value) { min_value_ = min_value; } void set_max_value(uint32_t max_value) { max_value_ = max_value; } void set_invert_position(bool invert_position) { invert_position_ = invert_position; } + void set_invert_position_report(bool invert_position_report) { invert_position_report_ = invert_position_report; } void set_restore_mode(TuyaCoverRestoreMode restore_mode) { restore_mode_ = restore_mode; } protected: @@ -42,6 +43,7 @@ class TuyaCover : public cover::Cover, public Component { uint32_t max_value_; uint32_t value_range_; bool invert_position_; + bool invert_position_report_; }; } // namespace tuya From cc217d8a83a049d259b163fd01e38141373b3e9d Mon Sep 17 00:00:00 2001 From: zry98 Date: Wed, 5 Jun 2024 10:11:19 +0200 Subject: [PATCH 1847/2607] [Tuya Climate] Support both datapoint and pins for active state (#6789) --- esphome/components/tuya/climate/__init__.py | 15 ++-- .../components/tuya/climate/tuya_climate.cpp | 76 +++++++++++-------- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index 56eb377ed7..363e7c764b 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -189,8 +189,6 @@ CONFIG_SCHEMA = cv.All( cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT), validate_temperature_multipliers, validate_cooling_values, - cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_HEATING_STATE_PIN), - cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_COOLING_STATE_PIN), ) @@ -207,6 +205,12 @@ async def to_code(config): if switch_datapoint := config.get(CONF_SWITCH_DATAPOINT): cg.add(var.set_switch_id(switch_datapoint)) + if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): + heating_state_pin = await cg.gpio_pin_expression(heating_state_pin_config) + cg.add(var.set_heating_state_pin(heating_state_pin)) + if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): + cooling_state_pin = await cg.gpio_pin_expression(cooling_state_pin_config) + cg.add(var.set_cooling_state_pin(cooling_state_pin)) if active_state_config := config.get(CONF_ACTIVE_STATE): cg.add(var.set_active_state_id(active_state_config.get(CONF_DATAPOINT))) if (heating_value := active_state_config.get(CONF_HEATING_VALUE)) is not None: @@ -217,13 +221,6 @@ async def to_code(config): cg.add(var.set_active_state_drying_value(drying_value)) if (fanonly_value := active_state_config.get(CONF_FANONLY_VALUE)) is not None: cg.add(var.set_active_state_fanonly_value(fanonly_value)) - else: - if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): - heating_state_pin = await cg.gpio_pin_expression(heating_state_pin_config) - cg.add(var.set_heating_state_pin(heating_state_pin)) - if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): - cooling_state_pin = await cg.gpio_pin_expression(cooling_state_pin_config) - cg.add(var.set_cooling_state_pin(cooling_state_pin)) if target_temperature_datapoint := config.get(CONF_TARGET_TEMPERATURE_DATAPOINT): cg.add(var.set_target_temperature_id(target_temperature_datapoint)) diff --git a/esphome/components/tuya/climate/tuya_climate.cpp b/esphome/components/tuya/climate/tuya_climate.cpp index 274e19a69e..7827a4e3ab 100644 --- a/esphome/components/tuya/climate/tuya_climate.cpp +++ b/esphome/components/tuya/climate/tuya_climate.cpp @@ -24,6 +24,14 @@ void TuyaClimate::setup() { this->publish_state(); }); } + if (this->heating_state_pin_ != nullptr) { + this->heating_state_pin_->setup(); + this->heating_state_ = this->heating_state_pin_->digital_read(); + } + if (this->cooling_state_pin_ != nullptr) { + this->cooling_state_pin_->setup(); + this->cooling_state_ = this->cooling_state_pin_->digital_read(); + } if (this->active_state_id_.has_value()) { this->parent_->register_listener(*this->active_state_id_, [this](const TuyaDatapoint &datapoint) { ESP_LOGV(TAG, "MCU reported active state is: %u", datapoint.value_enum); @@ -31,15 +39,6 @@ void TuyaClimate::setup() { this->compute_state_(); this->publish_state(); }); - } else { - if (this->heating_state_pin_ != nullptr) { - this->heating_state_pin_->setup(); - this->heating_state_ = this->heating_state_pin_->digital_read(); - } - if (this->cooling_state_pin_ != nullptr) { - this->cooling_state_pin_->setup(); - this->cooling_state_ = this->cooling_state_pin_->digital_read(); - } } if (this->target_temperature_id_.has_value()) { this->parent_->register_listener(*this->target_temperature_id_, [this](const TuyaDatapoint &datapoint) { @@ -113,9 +112,6 @@ void TuyaClimate::setup() { } void TuyaClimate::loop() { - if (this->active_state_id_.has_value()) - return; - bool state_changed = false; if (this->heating_state_pin_ != nullptr) { bool heating_state = this->heating_state_pin_->digital_read(); @@ -147,14 +143,18 @@ void TuyaClimate::control(const climate::ClimateCall &call) { this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state); const climate::ClimateMode new_mode = *call.get_mode(); - if (new_mode == climate::CLIMATE_MODE_HEAT && this->supports_heat_) { - this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_heating_value_); - } else if (new_mode == climate::CLIMATE_MODE_COOL && this->supports_cool_) { - this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_cooling_value_); - } else if (new_mode == climate::CLIMATE_MODE_DRY && this->active_state_drying_value_.has_value()) { - this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_drying_value_); - } else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY && this->active_state_fanonly_value_.has_value()) { - this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_fanonly_value_); + if (this->active_state_id_.has_value()) { + if (new_mode == climate::CLIMATE_MODE_HEAT && this->supports_heat_) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_heating_value_); + } else if (new_mode == climate::CLIMATE_MODE_COOL && this->supports_cool_) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_cooling_value_); + } else if (new_mode == climate::CLIMATE_MODE_DRY && this->active_state_drying_value_.has_value()) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_drying_value_); + } else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY && this->active_state_fanonly_value_.has_value()) { + this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_fanonly_value_); + } + } else { + ESP_LOGW(TAG, "Active state (mode) datapoint not configured"); } } @@ -422,7 +422,32 @@ void TuyaClimate::compute_state_() { } climate::ClimateAction target_action = climate::CLIMATE_ACTION_IDLE; - if (this->active_state_id_.has_value()) { + if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) { + // Use state from input pins + if (this->heating_state_) { + target_action = climate::CLIMATE_ACTION_HEATING; + this->mode = climate::CLIMATE_MODE_HEAT; + } else if (this->cooling_state_) { + target_action = climate::CLIMATE_ACTION_COOLING; + this->mode = climate::CLIMATE_MODE_COOL; + } + if (this->active_state_id_.has_value()) { + // Both are available, use MCU datapoint as mode + if (this->supports_heat_ && this->active_state_heating_value_.has_value() && + this->active_state_ == this->active_state_heating_value_) { + this->mode = climate::CLIMATE_MODE_HEAT; + } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() && + this->active_state_ == this->active_state_cooling_value_) { + this->mode = climate::CLIMATE_MODE_COOL; + } else if (this->active_state_drying_value_.has_value() && + this->active_state_ == this->active_state_drying_value_) { + this->mode = climate::CLIMATE_MODE_DRY; + } else if (this->active_state_fanonly_value_.has_value() && + this->active_state_ == this->active_state_fanonly_value_) { + this->mode = climate::CLIMATE_MODE_FAN_ONLY; + } + } + } else if (this->active_state_id_.has_value()) { // Use state from MCU datapoint if (this->supports_heat_ && this->active_state_heating_value_.has_value() && this->active_state_ == this->active_state_heating_value_) { @@ -441,15 +466,6 @@ void TuyaClimate::compute_state_() { target_action = climate::CLIMATE_ACTION_FAN; this->mode = climate::CLIMATE_MODE_FAN_ONLY; } - } else if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) { - // Use state from input pins - if (this->heating_state_) { - target_action = climate::CLIMATE_ACTION_HEATING; - this->mode = climate::CLIMATE_MODE_HEAT; - } else if (this->cooling_state_) { - target_action = climate::CLIMATE_ACTION_COOLING; - this->mode = climate::CLIMATE_MODE_COOL; - } } else { // Fallback to active state calc based on temp and hysteresis const float temp_diff = this->target_temperature - this->current_temperature; From 7143e9cd9e2073351cfd239e242e2132a36eec0b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 6 Jun 2024 05:27:06 +1000 Subject: [PATCH 1848/2607] [config] Allow file: scheme for git external components (#6844) --- esphome/config_validation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 5fc72921e1..7259e3c062 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1949,13 +1949,13 @@ def url(value): except ValueError as e: raise Invalid("Not a valid URL") from e - if not parsed.scheme or not parsed.netloc: - raise Invalid("Expected a URL scheme and host") - return parsed.geturl() + if parsed.scheme and parsed.netloc or parsed.scheme == "file": + return parsed.geturl() + raise Invalid("Expected a file scheme or a URL scheme with host") def git_ref(value): - if re.match(r"[a-zA-Z0-9\-_.\./]+", value) is None: + if re.match(r"[a-zA-Z0-9_./-]+", value) is None: raise Invalid("Not a valid git ref") return value From 8ef4aaa70eac95656f2742b7e57d1010cfb235b5 Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Thu, 6 Jun 2024 04:35:28 +0200 Subject: [PATCH 1849/2607] [ota] http_request update platform (#5586) Co-authored-by: Keith Burzinski Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> --- CODEOWNERS | 1 + .../components/http_request/ota/__init__.py | 189 +++++++++++ .../components/http_request/ota/automation.h | 42 +++ .../http_request/ota/ota_http_request.cpp | 293 ++++++++++++++++++ .../http_request/ota/ota_http_request.h | 72 +++++ .../ota/ota_http_request_arduino.cpp | 134 ++++++++ .../ota/ota_http_request_arduino.h | 42 +++ .../http_request/ota/ota_http_request_idf.cpp | 86 +++++ .../http_request/ota/ota_http_request_idf.h | 24 ++ .../components/http_request/ota/watchdog.cpp | 71 +++++ .../components/http_request/ota/watchdog.h | 27 ++ esphome/core/defines.h | 1 + .../{common.yaml => common_http_request.yaml} | 4 - tests/components/http_request/common_ota.yaml | 36 +++ .../http_request/test-nossl.esp8266.yaml | 38 +++ .../http_request/test.esp32-c3-idf.yaml | 4 + .../http_request/test.esp32-c3.yaml | 7 +- .../http_request/test.esp32-idf.yaml | 4 + tests/components/http_request/test.esp32.yaml | 7 +- .../components/http_request/test.esp8266.yaml | 7 +- .../components/http_request/test.rp2040.yaml | 4 + 21 files changed, 1083 insertions(+), 10 deletions(-) create mode 100644 esphome/components/http_request/ota/__init__.py create mode 100644 esphome/components/http_request/ota/automation.h create mode 100644 esphome/components/http_request/ota/ota_http_request.cpp create mode 100644 esphome/components/http_request/ota/ota_http_request.h create mode 100644 esphome/components/http_request/ota/ota_http_request_arduino.cpp create mode 100644 esphome/components/http_request/ota/ota_http_request_arduino.h create mode 100644 esphome/components/http_request/ota/ota_http_request_idf.cpp create mode 100644 esphome/components/http_request/ota/ota_http_request_idf.h create mode 100644 esphome/components/http_request/ota/watchdog.cpp create mode 100644 esphome/components/http_request/ota/watchdog.h rename tests/components/http_request/{common.yaml => common_http_request.yaml} (95%) create mode 100644 tests/components/http_request/common_ota.yaml create mode 100644 tests/components/http_request/test-nossl.esp8266.yaml create mode 100644 tests/components/http_request/test.esp32-c3-idf.yaml create mode 100644 tests/components/http_request/test.esp32-idf.yaml create mode 100644 tests/components/http_request/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 82f61c3b80..90574ca9ba 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -171,6 +171,7 @@ esphome/components/host/* @clydebarrow @esphome/core esphome/components/host/time/* @clydebarrow esphome/components/hrxl_maxsonar_wr/* @netmikey esphome/components/hte501/* @Stock-M +esphome/components/http_request/ota/* @oarcher esphome/components/htu31d/* @betterengineering esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hyt271/* @Philippe12 diff --git a/esphome/components/http_request/ota/__init__.py b/esphome/components/http_request/ota/__init__.py new file mode 100644 index 0000000000..6a56fac83a --- /dev/null +++ b/esphome/components/http_request/ota/__init__.py @@ -0,0 +1,189 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.const import ( + CONF_ESP8266_DISABLE_SSL_SUPPORT, + CONF_ID, + CONF_PASSWORD, + CONF_TIMEOUT, + CONF_URL, + CONF_USERNAME, +) +from esphome.components import esp32 +from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent +from esphome.core import CORE, coroutine_with_priority +from .. import http_request_ns + +CODEOWNERS = ["@oarcher"] + +AUTO_LOAD = ["md5"] +DEPENDENCIES = ["network"] + +CONF_MD5 = "md5" +CONF_MD5_URL = "md5_url" +CONF_VERIFY_SSL = "verify_ssl" +CONF_WATCHDOG_TIMEOUT = "watchdog_timeout" + +OtaHttpRequestComponent = http_request_ns.class_( + "OtaHttpRequestComponent", OTAComponent +) +OtaHttpRequestComponentArduino = http_request_ns.class_( + "OtaHttpRequestComponentArduino", OtaHttpRequestComponent +) +OtaHttpRequestComponentIDF = http_request_ns.class_( + "OtaHttpRequestComponentIDF", OtaHttpRequestComponent +) +OtaHttpRequestComponentFlashAction = http_request_ns.class_( + "OtaHttpRequestComponentFlashAction", automation.Action +) + + +def validate_ssl_verification(config): + error_message = "" + + if CORE.is_esp32: + if not CORE.using_esp_idf and config[CONF_VERIFY_SSL]: + error_message = "ESPHome supports certificate verification only via ESP-IDF" + + if CORE.is_rp2040 and config[CONF_VERIFY_SSL]: + error_message = "ESPHome does not support certificate verification in Arduino" + + if ( + CORE.is_esp8266 + and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT] + and config[CONF_VERIFY_SSL] + ): + error_message = "ESPHome does not support certificate verification in Arduino" + + if len(error_message) > 0: + raise cv.Invalid( + f"{error_message}. Set '{CONF_VERIFY_SSL}: false' to skip certificate validation and allow less secure HTTPS connections." + ) + + return config + + +def _declare_request_class(value): + if CORE.using_esp_idf: + return cv.declare_id(OtaHttpRequestComponentIDF)(value) + + if CORE.is_esp8266 or CORE.is_esp32 or CORE.is_rp2040: + return cv.declare_id(OtaHttpRequestComponentArduino)(value) + return NotImplementedError + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): _declare_request_class, + cv.SplitDefault(CONF_ESP8266_DISABLE_SSL_SUPPORT, esp8266=False): cv.All( + cv.only_on_esp8266, cv.boolean + ), + cv.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, + cv.Optional( + CONF_TIMEOUT, default="5min" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_WATCHDOG_TIMEOUT): cv.All( + cv.Any(cv.only_on_esp32, cv.only_on_rp2040), + cv.positive_not_null_time_period, + cv.positive_time_period_milliseconds, + ), + } + ) + .extend(BASE_OTA_SCHEMA) + .extend(cv.COMPONENT_SCHEMA), + cv.require_framework_version( + esp8266_arduino=cv.Version(2, 5, 1), + esp32_arduino=cv.Version(0, 0, 0), + esp_idf=cv.Version(0, 0, 0), + rp2040_arduino=cv.Version(0, 0, 0), + ), + validate_ssl_verification, +) + + +@coroutine_with_priority(52.0) +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await ota_to_code(var, config) + + cg.add(var.set_timeout(config[CONF_TIMEOUT])) + + if timeout_ms := config.get(CONF_WATCHDOG_TIMEOUT): + cg.add_define( + "USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT", + timeout_ms, + ) + + if CORE.is_esp8266 and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT]: + cg.add_define("USE_HTTP_REQUEST_ESP8266_HTTPS") + + if CORE.is_esp32: + if CORE.using_esp_idf: + esp32.add_idf_sdkconfig_option( + "CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", + config.get(CONF_VERIFY_SSL), + ) + esp32.add_idf_sdkconfig_option( + "CONFIG_ESP_TLS_INSECURE", + not config.get(CONF_VERIFY_SSL), + ) + esp32.add_idf_sdkconfig_option( + "CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY", + not config.get(CONF_VERIFY_SSL), + ) + else: + cg.add_library("WiFiClientSecure", None) + cg.add_library("HTTPClient", None) + if CORE.is_esp8266: + cg.add_library("ESP8266HTTPClient", None) + if CORE.is_rp2040 and CORE.using_arduino: + cg.add_library("HTTPClient", None) + + await cg.register_component(var, config) + + +OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.use_id(OtaHttpRequestComponent), + cv.Optional(CONF_MD5_URL): cv.templatable(cv.url), + cv.Optional(CONF_MD5): cv.templatable(cv.string), + cv.Optional(CONF_PASSWORD): cv.templatable(cv.string), + cv.Optional(CONF_USERNAME): cv.templatable(cv.string), + cv.Required(CONF_URL): cv.templatable(cv.url), + } + ), + cv.has_exactly_one_key(CONF_MD5, CONF_MD5_URL), +) + + +@automation.register_action( + "ota_http_request.flash", + OtaHttpRequestComponentFlashAction, + OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA, +) +async def ota_http_request_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + if md5_url := config.get(CONF_MD5_URL): + template_ = await cg.templatable(md5_url, args, cg.std_string) + cg.add(var.set_md5_url(template_)) + + if md5_str := config.get(CONF_MD5): + template_ = await cg.templatable(md5_str, args, cg.std_string) + cg.add(var.set_md5(template_)) + + if password_str := config.get(CONF_PASSWORD): + template_ = await cg.templatable(password_str, args, cg.std_string) + cg.add(var.set_password(template_)) + + if username_str := config.get(CONF_USERNAME): + template_ = await cg.templatable(username_str, args, cg.std_string) + cg.add(var.set_username(template_)) + + template_ = await cg.templatable(config[CONF_URL], args, cg.std_string) + cg.add(var.set_url(template_)) + + return var diff --git a/esphome/components/http_request/ota/automation.h b/esphome/components/http_request/ota/automation.h new file mode 100644 index 0000000000..d4c21f1c72 --- /dev/null +++ b/esphome/components/http_request/ota/automation.h @@ -0,0 +1,42 @@ +#pragma once +#include "ota_http_request.h" + +#include "esphome/core/automation.h" + +namespace esphome { +namespace http_request { + +template class OtaHttpRequestComponentFlashAction : public Action { + public: + OtaHttpRequestComponentFlashAction(OtaHttpRequestComponent *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(std::string, md5_url) + TEMPLATABLE_VALUE(std::string, md5) + TEMPLATABLE_VALUE(std::string, password) + TEMPLATABLE_VALUE(std::string, url) + TEMPLATABLE_VALUE(std::string, username) + + void play(Ts... x) override { + if (this->md5_url_.has_value()) { + this->parent_->set_md5_url(this->md5_url_.value(x...)); + } + if (this->md5_.has_value()) { + this->parent_->set_md5(this->md5_.value(x...)); + } + if (this->password_.has_value()) { + this->parent_->set_password(this->password_.value(x...)); + } + if (this->username_.has_value()) { + this->parent_->set_username(this->username_.value(x...)); + } + this->parent_->set_url(this->url_.value(x...)); + + this->parent_->flash(); + // Normally never reached due to reboot + } + + protected: + OtaHttpRequestComponent *parent_; +}; + +} // namespace http_request +} // namespace esphome diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp new file mode 100644 index 0000000000..cf0816c858 --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -0,0 +1,293 @@ +#include "ota_http_request.h" +#include "watchdog.h" + +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" + +#include "esphome/components/md5/md5.h" +#include "esphome/components/ota/ota_backend_arduino_esp32.h" +#include "esphome/components/ota/ota_backend_arduino_esp8266.h" +#include "esphome/components/ota/ota_backend_arduino_rp2040.h" +#include "esphome/components/ota/ota_backend_esp_idf.h" +#include "esphome/components/ota/ota_backend.h" + +namespace esphome { +namespace http_request { + +void OtaHttpRequestComponent::setup() { +#ifdef USE_OTA_STATE_CALLBACK + ota::register_ota_platform(this); +#endif +} + +void OtaHttpRequestComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Over-The-Air updates via HTTP request:"); + ESP_LOGCONFIG(TAG, " Timeout: %llus", this->timeout_ / 1000); +#ifdef USE_ESP8266 +#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS + ESP_LOGCONFIG(TAG, " ESP8266 SSL support: No"); +#else + ESP_LOGCONFIG(TAG, " ESP8266 SSL support: Yes"); +#endif +#endif +#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE + ESP_LOGCONFIG(TAG, " TLS server verification: Yes"); +#else + ESP_LOGCONFIG(TAG, " TLS server verification: No"); +#endif +#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT + ESP_LOGCONFIG(TAG, " Watchdog timeout: %ds", USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT / 1000); +#endif +}; + +void OtaHttpRequestComponent::set_md5_url(const std::string &url) { + if (!this->validate_url_(url)) { + this->md5_url_.clear(); // URL was not valid; prevent flashing until it is + return; + } + this->md5_url_ = url; + this->md5_expected_.clear(); // to be retrieved later +} + +void OtaHttpRequestComponent::set_url(const std::string &url) { + if (!this->validate_url_(url)) { + this->url_.clear(); // URL was not valid; prevent flashing until it is + return; + } + this->url_ = url; +} + +bool OtaHttpRequestComponent::check_status() { + // status can be -1, or HTTP status code + if (this->status_ < 100) { + ESP_LOGE(TAG, "HTTP server did not respond (error %d)", this->status_); + return false; + } + if (this->status_ >= 310) { + ESP_LOGE(TAG, "HTTP error %d", this->status_); + return false; + } + ESP_LOGV(TAG, "HTTP status %d", this->status_); + return true; +} + +void OtaHttpRequestComponent::flash() { + if (this->url_.empty()) { + ESP_LOGE(TAG, "URL not set; cannot start update"); + return; + } + + ESP_LOGI(TAG, "Starting update..."); +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); +#endif + + auto ota_status = this->do_ota_(); + + switch (ota_status) { + case ota::OTA_RESPONSE_OK: +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, ota_status); +#endif + delay(10); + App.safe_reboot(); + break; + + default: +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_ERROR, 0.0f, ota_status); +#endif + this->md5_computed_.clear(); // will be reset at next attempt + this->md5_expected_.clear(); // will be reset at next attempt + break; + } +} + +void OtaHttpRequestComponent::cleanup_(std::unique_ptr backend) { + if (this->update_started_) { + ESP_LOGV(TAG, "Aborting OTA backend"); + backend->abort(); + } + ESP_LOGV(TAG, "Aborting HTTP connection"); + this->http_end(); +}; + +uint8_t OtaHttpRequestComponent::do_ota_() { + uint8_t buf[this->http_recv_buffer_ + 1]; + uint32_t last_progress = 0; + uint32_t update_start_time = millis(); + md5::MD5Digest md5_receive; + std::unique_ptr md5_receive_str(new char[33]); + + if (this->md5_expected_.empty() && !this->http_get_md5_()) { + return OTA_MD5_INVALID; + } + + ESP_LOGD(TAG, "MD5 expected: %s", this->md5_expected_.c_str()); + + auto url_with_auth = this->get_url_with_auth_(this->url_); + if (url_with_auth.empty()) { + return OTA_BAD_URL; + } + ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str()); + ESP_LOGI(TAG, "Connecting to: %s", this->url_.c_str()); + this->http_init(url_with_auth); + if (!this->check_status()) { + this->http_end(); + return OTA_CONNECTION_ERROR; + } + + // we will compute MD5 on the fly for verification -- Arduino OTA seems to ignore it + md5_receive.init(); + ESP_LOGV(TAG, "MD5Digest initialized"); + + ESP_LOGV(TAG, "OTA backend begin"); + auto backend = ota::make_ota_backend(); + auto error_code = backend->begin(this->body_length_); + if (error_code != ota::OTA_RESPONSE_OK) { + ESP_LOGW(TAG, "backend->begin error: %d", error_code); + this->cleanup_(std::move(backend)); + return error_code; + } + + this->bytes_read_ = 0; + while (this->bytes_read_ < this->body_length_) { + // read a maximum of chunk_size bytes into buf. (real read size returned) + int bufsize = this->http_read(buf, this->http_recv_buffer_); + ESP_LOGVV(TAG, "bytes_read_ = %u, body_length_ = %u, bufsize = %i", this->bytes_read_, this->body_length_, bufsize); + + // feed watchdog and give other tasks a chance to run + App.feed_wdt(); + yield(); + + if (bufsize < 0) { + ESP_LOGE(TAG, "Stream closed"); + this->cleanup_(std::move(backend)); + return OTA_CONNECTION_ERROR; + } else if (bufsize > 0 && bufsize <= this->http_recv_buffer_) { + // add read bytes to MD5 + md5_receive.add(buf, bufsize); + + // write bytes to OTA backend + this->update_started_ = true; + error_code = backend->write(buf, bufsize); + if (error_code != ota::OTA_RESPONSE_OK) { + // error code explanation available at + // https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h + ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code, + this->bytes_read_ - bufsize, this->body_length_); + this->cleanup_(std::move(backend)); + return error_code; + } + } + + uint32_t now = millis(); + if ((now - last_progress > 1000) or (this->bytes_read_ == this->body_length_)) { + last_progress = now; + float percentage = this->bytes_read_ * 100.0f / this->body_length_; + ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0); +#endif + } + } // while + + ESP_LOGI(TAG, "Done in %.0f seconds", float(millis() - update_start_time) / 1000); + + // verify MD5 is as expected and act accordingly + md5_receive.calculate(); + md5_receive.get_hex(md5_receive_str.get()); + this->md5_computed_ = md5_receive_str.get(); + if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) { + ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str()); + this->cleanup_(std::move(backend)); + return ota::OTA_RESPONSE_ERROR_MD5_MISMATCH; + } else { + backend->set_update_md5(md5_receive_str.get()); + } + + this->http_end(); + + // feed watchdog and give other tasks a chance to run + App.feed_wdt(); + yield(); + delay(100); // NOLINT + + error_code = backend->end(); + if (error_code != ota::OTA_RESPONSE_OK) { + ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); + this->cleanup_(std::move(backend)); + return error_code; + } + + ESP_LOGI(TAG, "Update complete"); + return ota::OTA_RESPONSE_OK; +} + +std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) { + if (this->username_.empty() || this->password_.empty()) { + return url; + } + + auto start_char = url.find("://"); + if ((start_char == std::string::npos) || (start_char < 4)) { + ESP_LOGE(TAG, "Incorrect URL prefix"); + return {}; + } + + ESP_LOGD(TAG, "Using basic HTTP authentication"); + + start_char += 3; // skip '://' characters + auto url_with_auth = + url.substr(0, start_char) + this->username_ + ":" + this->password_ + "@" + url.substr(start_char); + return url_with_auth; +} + +bool OtaHttpRequestComponent::http_get_md5_() { + if (this->md5_url_.empty()) { + return false; + } + + auto url_with_auth = this->get_url_with_auth_(this->md5_url_); + if (url_with_auth.empty()) { + return false; + } + + ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str()); + ESP_LOGI(TAG, "Connecting to: %s", this->md5_url_.c_str()); + this->http_init(url_with_auth); + if (!this->check_status()) { + this->http_end(); + return false; + } + int length = this->body_length_; + if (length < 0) { + this->http_end(); + return false; + } + if (length < MD5_SIZE) { + ESP_LOGE(TAG, "MD5 file must be %u bytes; %u bytes reported by HTTP server. Aborting", MD5_SIZE, + this->body_length_); + this->http_end(); + return false; + } + + this->bytes_read_ = 0; + this->md5_expected_.resize(MD5_SIZE); + auto read_len = this->http_read((uint8_t *) this->md5_expected_.data(), MD5_SIZE); + this->http_end(); + + return read_len == MD5_SIZE; +} + +bool OtaHttpRequestComponent::validate_url_(const std::string &url) { + if ((url.length() < 8) || (url.find("http") != 0) || (url.find("://") == std::string::npos)) { + ESP_LOGE(TAG, "URL is invalid and/or must be prefixed with 'http://' or 'https://'"); + return false; + } + return true; +} + +} // namespace http_request +} // namespace esphome diff --git a/esphome/components/http_request/ota/ota_http_request.h b/esphome/components/http_request/ota/ota_http_request.h new file mode 100644 index 0000000000..9fbdf2ec25 --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request.h @@ -0,0 +1,72 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/components/ota/ota_backend.h" + +#include +#include +#include + +namespace esphome { +namespace http_request { + +static const char *const TAG = "http_request.ota"; +static const uint8_t MD5_SIZE = 32; + +enum OtaHttpRequestError : uint8_t { + OTA_MD5_INVALID = 0x10, + OTA_BAD_URL = 0x11, + OTA_CONNECTION_ERROR = 0x12, +}; + +class OtaHttpRequestComponent : public ota::OTAComponent { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + + void set_md5_url(const std::string &md5_url); + void set_md5(const std::string &md5) { this->md5_expected_ = md5; } + void set_password(const std::string &password) { this->password_ = password; } + void set_timeout(const uint64_t timeout) { this->timeout_ = timeout; } + void set_url(const std::string &url); + void set_username(const std::string &username) { this->username_ = username; } + + std::string md5_computed() { return this->md5_computed_; } + std::string md5_expected() { return this->md5_expected_; } + + bool check_status(); + + void flash(); + + virtual void http_init(const std::string &url){}; + virtual int http_read(uint8_t *buf, size_t len) { return 0; }; + virtual void http_end(){}; + + protected: + void cleanup_(std::unique_ptr backend); + uint8_t do_ota_(); + std::string get_url_with_auth_(const std::string &url); + bool http_get_md5_(); + bool secure_() { return this->url_.find("https:") != std::string::npos; }; + bool validate_url_(const std::string &url); + + std::string md5_computed_{}; + std::string md5_expected_{}; + std::string md5_url_{}; + std::string password_{}; + std::string username_{}; + std::string url_{}; + size_t body_length_ = 0; + size_t bytes_read_ = 0; + int status_ = -1; + uint64_t timeout_ = 0; + bool update_started_ = false; + const uint16_t http_recv_buffer_ = 256; // the firmware GET chunk size + const uint16_t max_http_recv_buffer_ = 512; // internal max http buffer size must be > HTTP_RECV_BUFFER_ (TLS + // overhead) and must be a power of two from 512 to 4096 +}; + +} // namespace http_request +} // namespace esphome diff --git a/esphome/components/http_request/ota/ota_http_request_arduino.cpp b/esphome/components/http_request/ota/ota_http_request_arduino.cpp new file mode 100644 index 0000000000..d1dc638d5e --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request_arduino.cpp @@ -0,0 +1,134 @@ +#include "ota_http_request.h" +#include "watchdog.h" + +#ifdef USE_ARDUINO +#include "ota_http_request_arduino.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/components/network/util.h" +#include "esphome/components/md5/md5.h" + +namespace esphome { +namespace http_request { + +struct Header { + const char *name; + const char *value; +}; + +void OtaHttpRequestComponentArduino::http_init(const std::string &url) { + const char *header_keys[] = {"Content-Length", "Content-Type"}; + const size_t header_count = sizeof(header_keys) / sizeof(header_keys[0]); + watchdog::WatchdogManager wdts; + +#ifdef USE_ESP8266 + if (this->stream_ptr_ == nullptr && this->set_stream_ptr_()) { + ESP_LOGE(TAG, "Unable to set client"); + return; + } +#endif // USE_ESP8266 + +#ifdef USE_RP2040 + this->client_.setInsecure(); +#endif + + App.feed_wdt(); + +#if defined(USE_ESP32) || defined(USE_RP2040) + this->status_ = this->client_.begin(url.c_str()); +#endif +#ifdef USE_ESP8266 + this->client_.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + this->status_ = this->client_.begin(*this->stream_ptr_, url.c_str()); +#endif + + if (!this->status_) { + this->client_.end(); + return; + } + + this->client_.setReuse(true); + + // returned needed headers must be collected before the requests + this->client_.collectHeaders(header_keys, header_count); + + // HTTP GET + this->status_ = this->client_.GET(); + + this->body_length_ = (size_t) this->client_.getSize(); + +#if defined(USE_ESP32) || defined(USE_RP2040) + if (this->stream_ptr_ == nullptr) { + this->set_stream_ptr_(); + } +#endif +} + +int OtaHttpRequestComponentArduino::http_read(uint8_t *buf, const size_t max_len) { +#ifdef USE_ESP8266 +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 1, 0) // && USE_ARDUINO_VERSION_CODE < VERSION_CODE(?, ?, ?) + if (!this->secure_()) { + ESP_LOGW(TAG, "Using HTTP on Arduino version >= 3.1 is **very** slow. Consider setting framework version to 3.0.2 " + "in your YAML, or use HTTPS"); + } +#endif // USE_ARDUINO_VERSION_CODE +#endif // USE_ESP8266 + + watchdog::WatchdogManager wdts; + + // Since arduino8266 >= 3.1 using this->stream_ptr_ is broken (https://github.com/esp8266/Arduino/issues/9035) + WiFiClient *stream_ptr = this->client_.getStreamPtr(); + if (stream_ptr == nullptr) { + ESP_LOGE(TAG, "Stream pointer vanished!"); + return -1; + } + + int available_data = stream_ptr->available(); + int bufsize = std::min((int) max_len, available_data); + if (bufsize > 0) { + stream_ptr->readBytes(buf, bufsize); + this->bytes_read_ += bufsize; + buf[bufsize] = '\0'; // not fed to ota + } + + return bufsize; +} + +void OtaHttpRequestComponentArduino::http_end() { + watchdog::WatchdogManager wdts; + this->client_.end(); +} + +int OtaHttpRequestComponentArduino::set_stream_ptr_() { +#ifdef USE_ESP8266 +#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS + if (this->secure_()) { + ESP_LOGV(TAG, "ESP8266 HTTPS connection with WiFiClientSecure"); + this->stream_ptr_ = std::make_unique(); + WiFiClientSecure *secure_client = static_cast(this->stream_ptr_.get()); + secure_client->setBufferSizes(this->max_http_recv_buffer_, 512); + secure_client->setInsecure(); + } else { + this->stream_ptr_ = std::make_unique(); + } +#else + ESP_LOGV(TAG, "ESP8266 HTTP connection with WiFiClient"); + if (this->secure_()) { + ESP_LOGE(TAG, "Can't use HTTPS connection with esp8266_disable_ssl_support"); + return -1; + } + this->stream_ptr_ = std::make_unique(); +#endif // USE_HTTP_REQUEST_ESP8266_HTTPS +#endif // USE_ESP8266 + +#if defined(USE_ESP32) || defined(USE_RP2040) + this->stream_ptr_ = std::unique_ptr(this->client_.getStreamPtr()); +#endif + return 0; +} + +} // namespace http_request +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/http_request/ota/ota_http_request_arduino.h b/esphome/components/http_request/ota/ota_http_request_arduino.h new file mode 100644 index 0000000000..02bc046520 --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request_arduino.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ota_http_request.h" + +#ifdef USE_ARDUINO +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" + +#include +#include +#include + +#if defined(USE_ESP32) || defined(USE_RP2040) +#include +#endif +#ifdef USE_ESP8266 +#include +#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS +#include +#endif +#endif + +namespace esphome { +namespace http_request { + +class OtaHttpRequestComponentArduino : public OtaHttpRequestComponent { + public: + void http_init(const std::string &url) override; + int http_read(uint8_t *buf, size_t len) override; + void http_end() override; + + protected: + int set_stream_ptr_(); + HTTPClient client_{}; + std::unique_ptr stream_ptr_; +}; + +} // namespace http_request +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/http_request/ota/ota_http_request_idf.cpp b/esphome/components/http_request/ota/ota_http_request_idf.cpp new file mode 100644 index 0000000000..9fa565d9bb --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request_idf.cpp @@ -0,0 +1,86 @@ +#include "ota_http_request_idf.h" +#include "watchdog.h" + +#ifdef USE_ESP_IDF +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" +#include "esphome/components/md5/md5.h" +#include "esphome/components/network/util.h" + +#include "esp_event.h" +#include "esp_http_client.h" +#include "esp_idf_version.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_system.h" +#include "esp_task_wdt.h" +#include "esp_tls.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "nvs_flash.h" + +#include +#include +#include +#include +#include +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE +#include "esp_crt_bundle.h" +#endif + +namespace esphome { +namespace http_request { + +void OtaHttpRequestComponentIDF::http_init(const std::string &url) { + App.feed_wdt(); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + esp_http_client_config_t config = {nullptr}; + config.url = url.c_str(); + config.method = HTTP_METHOD_GET; + config.timeout_ms = (int) this->timeout_; + config.buffer_size = this->max_http_recv_buffer_; + config.auth_type = HTTP_AUTH_TYPE_BASIC; + config.max_authorization_retries = -1; +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE + if (this->secure_()) { + config.crt_bundle_attach = esp_crt_bundle_attach; + } +#endif +#pragma GCC diagnostic pop + + watchdog::WatchdogManager wdts; + this->client_ = esp_http_client_init(&config); + if ((this->status_ = esp_http_client_open(this->client_, 0)) == ESP_OK) { + this->body_length_ = esp_http_client_fetch_headers(this->client_); + this->status_ = esp_http_client_get_status_code(this->client_); + } +} + +int OtaHttpRequestComponentIDF::http_read(uint8_t *buf, const size_t max_len) { + watchdog::WatchdogManager wdts; + int bufsize = std::min(max_len, this->body_length_ - this->bytes_read_); + + App.feed_wdt(); + int read_len = esp_http_client_read(this->client_, (char *) buf, bufsize); + if (read_len > 0) { + this->bytes_read_ += bufsize; + buf[bufsize] = '\0'; // not fed to ota + } + + return read_len; +} + +void OtaHttpRequestComponentIDF::http_end() { + watchdog::WatchdogManager wdts; + + esp_http_client_close(this->client_); + esp_http_client_cleanup(this->client_); +} + +} // namespace http_request +} // namespace esphome + +#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/ota/ota_http_request_idf.h b/esphome/components/http_request/ota/ota_http_request_idf.h new file mode 100644 index 0000000000..9783b2a3e1 --- /dev/null +++ b/esphome/components/http_request/ota/ota_http_request_idf.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ota_http_request.h" + +#ifdef USE_ESP_IDF +#include "esp_http_client.h" + +namespace esphome { +namespace http_request { + +class OtaHttpRequestComponentIDF : public OtaHttpRequestComponent { + public: + void http_init(const std::string &url) override; + int http_read(uint8_t *buf, size_t len) override; + void http_end() override; + + protected: + esp_http_client_handle_t client_{}; +}; + +} // namespace http_request +} // namespace esphome + +#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/ota/watchdog.cpp b/esphome/components/http_request/ota/watchdog.cpp new file mode 100644 index 0000000000..663c9afaac --- /dev/null +++ b/esphome/components/http_request/ota/watchdog.cpp @@ -0,0 +1,71 @@ +#include "watchdog.h" + +#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT + +#include "esphome/core/application.h" +#include "esphome/core/log.h" + +#include +#include +#ifdef USE_ESP32 +#include "esp_idf_version.h" +#include "esp_task_wdt.h" +#endif +#ifdef USE_RP2040 +#include "hardware/watchdog.h" +#include "pico/stdlib.h" +#endif + +namespace esphome { +namespace http_request { +namespace watchdog { + +static const char *const TAG = "watchdog.http_request.ota"; + +WatchdogManager::WatchdogManager() { + this->saved_timeout_ms_ = this->get_timeout_(); + this->set_timeout_(USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT); +} + +WatchdogManager::~WatchdogManager() { this->set_timeout_(this->saved_timeout_ms_); } + +void WatchdogManager::set_timeout_(uint32_t timeout_ms) { + ESP_LOGV(TAG, "Adjusting WDT to %" PRIu32 "ms", timeout_ms); +#ifdef USE_ESP32 +#if ESP_IDF_VERSION_MAJOR >= 5 + esp_task_wdt_config_t wdt_config = { + .timeout_ms = timeout_ms, + .idle_core_mask = 0x03, + .trigger_panic = true, + }; + esp_task_wdt_reconfigure(&wdt_config); +#else + esp_task_wdt_init(timeout_ms, true); +#endif // ESP_IDF_VERSION_MAJOR +#endif // USE_ESP32 + +#ifdef USE_RP2040 + watchdog_enable(timeout_ms, true); +#endif +} + +uint32_t WatchdogManager::get_timeout_() { + uint32_t timeout_ms = 0; + +#ifdef USE_ESP32 + timeout_ms = (uint32_t) CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; +#endif // USE_ESP32 + +#ifdef USE_RP2040 + timeout_ms = watchdog_get_count() / 1000; +#endif + + ESP_LOGVV(TAG, "get_timeout: %" PRIu32 "ms", timeout_ms); + + return timeout_ms; +} + +} // namespace watchdog +} // namespace http_request +} // namespace esphome +#endif diff --git a/esphome/components/http_request/ota/watchdog.h b/esphome/components/http_request/ota/watchdog.h new file mode 100644 index 0000000000..0a09dcd6fa --- /dev/null +++ b/esphome/components/http_request/ota/watchdog.h @@ -0,0 +1,27 @@ +#pragma once + +#include "esphome/core/defines.h" + +#include + +namespace esphome { +namespace http_request { +namespace watchdog { + +class WatchdogManager { +#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT + public: + WatchdogManager(); + ~WatchdogManager(); + + private: + uint32_t get_timeout_(); + void set_timeout_(uint32_t timeout_ms); + + uint32_t saved_timeout_ms_{0}; +#endif +}; + +} // namespace watchdog +} // namespace http_request +} // namespace esphome diff --git a/esphome/core/defines.h b/esphome/core/defines.h index c2ad0f641c..76b6af6592 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -33,6 +33,7 @@ #define USE_GRAPH #define USE_GRAPHICAL_DISPLAY_MENU #define USE_HOMEASSISTANT_TIME +#define USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT 8000 // NOLINT #define USE_JSON #define USE_LIGHT #define USE_LOCK diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common_http_request.yaml similarity index 95% rename from tests/components/http_request/common.yaml rename to tests/components/http_request/common_http_request.yaml index 848fe3f509..b00768c736 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common_http_request.yaml @@ -28,10 +28,6 @@ esphome: body: "Some data" verify_ssl: false -wifi: - ssid: MySSID - password: password1 - http_request: useragent: esphome/tagreader timeout: 10s diff --git a/tests/components/http_request/common_ota.yaml b/tests/components/http_request/common_ota.yaml new file mode 100644 index 0000000000..10e7d54c3f --- /dev/null +++ b/tests/components/http_request/common_ota.yaml @@ -0,0 +1,36 @@ +wifi: + ssid: MySSID + password: password1 + +ota: + - platform: http_request + verify_ssl: ${verify_ssl} + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: 'ESP_LOGD("ota", "State %d", state);' + +button: + - platform: template + name: Firmware update + on_press: + then: + - ota_http_request.flash: + md5_url: http://my.ha.net:8123/local/esphome/firmware.md5 + url: http://my.ha.net:8123/local/esphome/firmware.bin + - logger.log: "This message should be not displayed (reboot)" diff --git a/tests/components/http_request/test-nossl.esp8266.yaml b/tests/components/http_request/test-nossl.esp8266.yaml new file mode 100644 index 0000000000..65116d5550 --- /dev/null +++ b/tests/components/http_request/test-nossl.esp8266.yaml @@ -0,0 +1,38 @@ +<<: !include common_http_request.yaml + +wifi: + ssid: MySSID + password: password1 + +ota: + - platform: http_request + esp8266_disable_ssl_support: true + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: 'ESP_LOGD("ota", "State %d", state);' + +button: + - platform: template + name: Firmware update + on_press: + then: + - ota_http_request.flash: + md5_url: http://my.ha.net:8123/local/esphome/firmware.md5 + url: http://my.ha.net:8123/local/esphome/firmware.bin + - logger.log: "This message should be not displayed (reboot)" diff --git a/tests/components/http_request/test.esp32-c3-idf.yaml b/tests/components/http_request/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..da629e83a9 --- /dev/null +++ b/tests/components/http_request/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + verify_ssl: "true" + +<<: !include common_ota.yaml diff --git a/tests/components/http_request/test.esp32-c3.yaml b/tests/components/http_request/test.esp32-c3.yaml index 25cb37a0b4..1f597bb500 100644 --- a/tests/components/http_request/test.esp32-c3.yaml +++ b/tests/components/http_request/test.esp32-c3.yaml @@ -1,2 +1,5 @@ -packages: - common: !include common.yaml +substitutions: + verify_ssl: "false" + +<<: !include common_http_request.yaml +<<: !include common_ota.yaml diff --git a/tests/components/http_request/test.esp32-idf.yaml b/tests/components/http_request/test.esp32-idf.yaml new file mode 100644 index 0000000000..da629e83a9 --- /dev/null +++ b/tests/components/http_request/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + verify_ssl: "true" + +<<: !include common_ota.yaml diff --git a/tests/components/http_request/test.esp32.yaml b/tests/components/http_request/test.esp32.yaml index 25cb37a0b4..1f597bb500 100644 --- a/tests/components/http_request/test.esp32.yaml +++ b/tests/components/http_request/test.esp32.yaml @@ -1,2 +1,5 @@ -packages: - common: !include common.yaml +substitutions: + verify_ssl: "false" + +<<: !include common_http_request.yaml +<<: !include common_ota.yaml diff --git a/tests/components/http_request/test.esp8266.yaml b/tests/components/http_request/test.esp8266.yaml index 25cb37a0b4..1f597bb500 100644 --- a/tests/components/http_request/test.esp8266.yaml +++ b/tests/components/http_request/test.esp8266.yaml @@ -1,2 +1,5 @@ -packages: - common: !include common.yaml +substitutions: + verify_ssl: "false" + +<<: !include common_http_request.yaml +<<: !include common_ota.yaml diff --git a/tests/components/http_request/test.rp2040.yaml b/tests/components/http_request/test.rp2040.yaml new file mode 100644 index 0000000000..077e4d82da --- /dev/null +++ b/tests/components/http_request/test.rp2040.yaml @@ -0,0 +1,4 @@ +substitutions: + verify_ssl: "false" + +<<: !include common_ota.yaml From ccab57fc583189976248b7574eb4ca448860b16a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:30:49 +1200 Subject: [PATCH 1850/2607] [logger] Fix defines for development (#6870) * [logger] Fix defines for development * Set debugging flags for rp2040 --- esphome/components/logger/__init__.py | 27 ++++++++++++++++++++------- esphome/core/defines.h | 9 +++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index c05f3d54aa..99aa39c4ba 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -112,11 +112,18 @@ HARDWARE_UART_TO_UART_SELECTION = { } HARDWARE_UART_TO_SERIAL = { - UART0: cg.global_ns.Serial, - UART0_SWAP: cg.global_ns.Serial, - UART1: cg.global_ns.Serial1, - UART2: cg.global_ns.Serial2, - DEFAULT: cg.global_ns.Serial, + PLATFORM_ESP8266: { + UART0: cg.global_ns.Serial, + UART0_SWAP: cg.global_ns.Serial, + UART1: cg.global_ns.Serial1, + UART2: cg.global_ns.Serial2, + DEFAULT: cg.global_ns.Serial, + }, + PLATFORM_RP2040: { + UART0: cg.global_ns.Serial1, + UART1: cg.global_ns.Serial2, + USB_CDC: cg.global_ns.Serial, + }, } is_log_level = cv.one_of(*LOG_LEVELS, upper=True) @@ -244,8 +251,14 @@ async def to_code(config): is_at_least_very_verbose = this_severity >= very_verbose_severity has_serial_logging = baud_rate != 0 - if CORE.is_esp8266 and has_serial_logging and is_at_least_verbose: - debug_serial_port = HARDWARE_UART_TO_SERIAL[config.get(CONF_HARDWARE_UART)] + if ( + (CORE.is_esp8266 or CORE.is_rp2040) + and has_serial_logging + and is_at_least_verbose + ): + debug_serial_port = HARDWARE_UART_TO_SERIAL[CORE.target_platform][ + config.get(CONF_HARDWARE_UART) + ] cg.add_build_flag(f"-DDEBUG_ESP_PORT={debug_serial_port}") cg.add_build_flag("-DLWIP_DEBUG") DEBUG_COMPONENTS = { diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 76b6af6592..affcd78089 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -101,6 +101,14 @@ #ifdef USE_ESP_IDF #define USE_ESP_IDF_VERSION_CODE VERSION_CODE(4, 4, 2) #endif + +#if defined(USE_ESP32_VARIANT_ESP32S2) +#define USE_LOGGER_USB_CDC +#elif defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C3) || \ + defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) +#define USE_LOGGER_USB_CDC +#define USE_LOGGER_USB_SERIAL_JTAG +#endif #endif // ESP8266-specific feature flags @@ -123,6 +131,7 @@ #ifdef USE_RP2040 #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 3, 0) +#define USE_LOGGER_USB_CDC #define USE_SOCKET_IMPL_LWIP_TCP #define USE_SPI #endif From 276eea2b69f71a91dd87c672ad8c72d8883592a3 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 7 Jun 2024 12:36:07 -0700 Subject: [PATCH 1851/2607] [docker] Avoid unsafe git error when container user and file config volume permissions don't match (#6873) --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index f6234235f7..36be700f55 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -101,7 +101,7 @@ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "a && /platformio_install_deps.py /platformio.ini --libraries # Avoid unsafe git error when container user and file config volume permissions don't match -RUN git config --system --add safe.directory '/config/*' +RUN git config --system --add safe.directory '*' # ======================= docker-type image ======================= From 861a23d039cdc3900087958fb0586bffd790fd7c Mon Sep 17 00:00:00 2001 From: RFDarter Date: Fri, 7 Jun 2024 21:37:05 +0200 Subject: [PATCH 1852/2607] [datetime] Add logs on DateCall perform (#6868) --- esphome/components/datetime/date_entity.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/esphome/components/datetime/date_entity.cpp b/esphome/components/datetime/date_entity.cpp index 19399c1e59..b5bcef43af 100644 --- a/esphome/components/datetime/date_entity.cpp +++ b/esphome/components/datetime/date_entity.cpp @@ -80,6 +80,17 @@ void DateCall::validate_() { void DateCall::perform() { this->validate_(); + ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str()); + + if (this->year_.has_value()) { + ESP_LOGD(TAG, " Year: %d", *this->year_); + } + if (this->month_.has_value()) { + ESP_LOGD(TAG, " Month: %d", *this->month_); + } + if (this->day_.has_value()) { + ESP_LOGD(TAG, " Day: %d", *this->day_); + } this->parent_->control(*this); } From 8718e15a6a6dc56323e8e1ce1163da8b6eec9e9f Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:43:22 +0200 Subject: [PATCH 1853/2607] fix: arduino media player sets wrong state for announcements (#6849) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../i2s_audio/media_player/i2s_audio_media_player.cpp | 11 ++++++++--- .../i2s_audio/media_player/i2s_audio_media_player.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 1890e27bdf..ef494fac2e 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -27,6 +27,11 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->start(); } } + + if (this->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING) { + this->is_announcement_ = true; + } + if (call.get_volume().has_value()) { this->volume = call.get_volume().value(); this->set_volume_(volume); @@ -171,9 +176,8 @@ void I2SAudioMediaPlayer::start_() { if (this->current_url_.has_value()) { this->audio_->connecttohost(this->current_url_.value().c_str()); this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; - if (this->is_announcement_.has_value()) { - this->state = this->is_announcement_.value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING - : media_player::MEDIA_PLAYER_STATE_PLAYING; + if (this->is_announcement_) { + this->state = media_player::MEDIA_PLAYER_STATE_ANNOUNCING; } this->publish_state(); } @@ -202,6 +206,7 @@ void I2SAudioMediaPlayer::stop_() { this->high_freq_.stop(); this->state = media_player::MEDIA_PLAYER_STATE_IDLE; this->publish_state(); + this->is_announcement_ = false; } media_player::MediaPlayerTraits I2SAudioMediaPlayer::get_traits() { diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index d7d9b1f74a..5afe778122 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -78,7 +78,7 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, HighFrequencyLoopRequester high_freq_; optional current_url_{}; - optional is_announcement_{}; + bool is_announcement_{false}; }; } // namespace i2s_audio From d77ea461571e338ee1344f56e225fd4de26d66c7 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Fri, 7 Jun 2024 22:29:10 +0200 Subject: [PATCH 1854/2607] [datetime] datetime-datetime strptime support value string without seconds (#6867) --- esphome/core/time.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index add671701f..f7aa4fdddb 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -84,6 +84,16 @@ bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { esp_time.hour = hour; esp_time.minute = minute; esp_time.second = second; + } else if (sscanf(time_to_parse.c_str(), "%04hu-%02hhu-%02hhu %02hhu:%02hhu %n", &year, &month, &day, // NOLINT + &hour, // NOLINT + &minute, &num) == 5 && // NOLINT + num == time_to_parse.size()) { + esp_time.year = year; + esp_time.month = month; + esp_time.day_of_month = day; + esp_time.hour = hour; + esp_time.minute = minute; + esp_time.second = 0; } else if (sscanf(time_to_parse.c_str(), "%02hhu:%02hhu:%02hhu %n", &hour, &minute, &second, &num) == 3 && // NOLINT num == time_to_parse.size()) { esp_time.hour = hour; From 38b7bed2faa522e7e065d8362d6ea0bcaf1c64d5 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Sat, 8 Jun 2024 21:55:57 +1200 Subject: [PATCH 1855/2607] Update webserver local assets to 20240608-093147 (#6874) --- .../components/web_server/server_index_v2.h | 1231 +++++++++-------- .../components/web_server/server_index_v3.h | 721 +++++----- 2 files changed, 977 insertions(+), 975 deletions(-) diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index 31c2d1fd85..7417f37015 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -11,623 +11,624 @@ namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xd9, 0x92, 0xdb, 0x46, 0xb6, 0xe0, 0xf3, - 0xdc, 0xaf, 0x40, 0xc1, 0xd5, 0x25, 0x64, 0x33, 0x89, 0x22, 0x59, 0xda, 0x0c, 0x56, 0x92, 0x5d, 0x2a, 0xc9, 0x2d, - 0xbb, 0xb5, 0xd8, 0x2a, 0xc9, 0x6e, 0x9b, 0x66, 0x57, 0xa1, 0x88, 0x24, 0x99, 0x16, 0x88, 0xa4, 0x13, 0xc9, 0x5a, + 0xdc, 0xaf, 0x40, 0xa5, 0xab, 0x4b, 0xc8, 0x66, 0x12, 0x45, 0xb2, 0xb4, 0x19, 0xac, 0x24, 0xbb, 0x54, 0x92, 0x5b, + 0x76, 0x6b, 0xb1, 0x55, 0x92, 0xdd, 0x36, 0xcd, 0xae, 0x42, 0x11, 0x49, 0x32, 0x2d, 0x10, 0x49, 0x03, 0xc9, 0x5a, 0x4c, 0xe2, 0xc6, 0x7c, 0xc0, 0x44, 0x4c, 0xc4, 0x3c, 0xcd, 0xcb, 0xc4, 0xdc, 0x87, 0xf9, 0x88, 0x79, 0xbe, 0x9f, 0x72, 0x7f, 0x60, 0xe6, 0x13, 0x26, 0x4e, 0x2e, 0x40, 0x82, 0x4b, 0xa9, 0xbc, 0xdc, 0x1b, 0x13, 0x0a, 0x49, 0x44, - 0xae, 0x27, 0x4f, 0x9e, 0x3c, 0x7b, 0x02, 0xc7, 0x7b, 0x09, 0x1f, 0xc9, 0xdb, 0x39, 0xf5, 0xa6, 0x72, 0x96, 0xf6, - 0x8e, 0xcd, 0xbf, 0x34, 0x4e, 0x7a, 0xc7, 0x29, 0xcb, 0x3e, 0x7a, 0x82, 0xa6, 0x84, 0x8d, 0x78, 0xe6, 0x4d, 0x05, - 0x1d, 0x93, 0x24, 0x96, 0x71, 0xc4, 0x66, 0xf1, 0x84, 0x7a, 0x87, 0xbd, 0xe3, 0x19, 0x95, 0xb1, 0x37, 0x9a, 0xc6, - 0x22, 0xa7, 0x92, 0x7c, 0x78, 0xff, 0x45, 0xf3, 0x69, 0xef, 0x38, 0x1f, 0x09, 0x36, 0x97, 0x1e, 0x0c, 0x49, 0x66, - 0x3c, 0x59, 0xa4, 0xb4, 0x77, 0x78, 0x78, 0x7d, 0x7d, 0x1d, 0xfe, 0x94, 0xff, 0xd3, 0x88, 0x67, 0xb9, 0xf4, 0x5e, - 0x91, 0x6b, 0x96, 0x25, 0xfc, 0x1a, 0x53, 0x49, 0x5e, 0x85, 0x67, 0xd3, 0x38, 0xe1, 0xd7, 0xef, 0x38, 0x97, 0x07, - 0x07, 0x81, 0x7e, 0xbc, 0x3d, 0x3d, 0x3b, 0x23, 0x84, 0x5c, 0x71, 0x96, 0x78, 0xad, 0xd5, 0xaa, 0x2a, 0x0c, 0xb3, - 0x58, 0xb2, 0x2b, 0xaa, 0xbb, 0xa0, 0x83, 0x03, 0x3f, 0x4e, 0xf8, 0x5c, 0xd2, 0xe4, 0x4c, 0xde, 0xa6, 0xf4, 0x6c, - 0x4a, 0xa9, 0xcc, 0x7d, 0x96, 0x79, 0xcf, 0xf9, 0x68, 0x31, 0xa3, 0x99, 0x0c, 0xe7, 0x82, 0x4b, 0x0e, 0x90, 0x1c, - 0x1c, 0xf8, 0x82, 0xce, 0xd3, 0x78, 0x44, 0xa1, 0xfe, 0xf4, 0xec, 0xac, 0xea, 0x51, 0x35, 0xc2, 0x4c, 0x92, 0xb3, - 0xdb, 0xd9, 0x25, 0x4f, 0x03, 0x84, 0x53, 0x49, 0x32, 0x7a, 0xed, 0x7d, 0x47, 0xe3, 0x8f, 0xaf, 0xe3, 0x79, 0x77, - 0x94, 0xc6, 0x79, 0xee, 0x5d, 0xca, 0xa5, 0x5a, 0x82, 0x58, 0x8c, 0x24, 0x17, 0x81, 0xc4, 0x14, 0x33, 0xb4, 0x64, - 0xe3, 0x40, 0x4e, 0x59, 0x1e, 0x9e, 0xef, 0x8f, 0xf2, 0xfc, 0x1d, 0xcd, 0x17, 0xa9, 0xdc, 0x27, 0x7b, 0x2d, 0xcc, - 0xf6, 0x08, 0x61, 0x12, 0xc9, 0xa9, 0xe0, 0xd7, 0xde, 0x0b, 0x21, 0xb8, 0x08, 0xfc, 0xd3, 0xb3, 0x33, 0xdd, 0xc2, - 0x63, 0xb9, 0x97, 0x71, 0xe9, 0x95, 0xe3, 0xc5, 0x97, 0x29, 0x0d, 0xbd, 0x0f, 0x39, 0xf5, 0x2e, 0x16, 0x59, 0x1e, - 0x8f, 0xe9, 0xe9, 0xd9, 0xd9, 0x85, 0xc7, 0x85, 0x77, 0x31, 0xca, 0xf3, 0x0b, 0x8f, 0x65, 0xb9, 0xa4, 0x71, 0x12, - 0xfa, 0xa8, 0xab, 0x26, 0x1b, 0xe5, 0xf9, 0x7b, 0x7a, 0x23, 0x89, 0xc4, 0xea, 0x51, 0x12, 0x5a, 0x4c, 0xa8, 0xf4, - 0xf2, 0x72, 0x5d, 0x01, 0x5a, 0xa6, 0x54, 0x7a, 0x92, 0xa8, 0x7a, 0xde, 0xd5, 0xb8, 0xa7, 0xfa, 0x51, 0x76, 0xd9, - 0x38, 0xa0, 0xf2, 0xe0, 0x40, 0x96, 0x78, 0x46, 0x7a, 0x69, 0x1e, 0x23, 0x74, 0xcf, 0x96, 0x1d, 0x1c, 0xd0, 0x30, - 0xa5, 0xd9, 0x44, 0x4e, 0x09, 0x21, 0xed, 0x2e, 0x3b, 0x38, 0x08, 0x24, 0x49, 0x65, 0x38, 0xa1, 0x32, 0xa0, 0x08, - 0xe1, 0xaa, 0xf7, 0xc1, 0x41, 0xa0, 0x91, 0xc0, 0x89, 0x46, 0x5c, 0x0d, 0xc7, 0x28, 0x34, 0xd8, 0x3f, 0xbb, 0xcd, - 0x46, 0x81, 0x0b, 0x3f, 0xc2, 0xec, 0xe0, 0x20, 0x95, 0x61, 0x0e, 0x23, 0x62, 0x89, 0x50, 0x21, 0xa8, 0x5c, 0x88, - 0xcc, 0x93, 0x85, 0xe4, 0x67, 0x52, 0xb0, 0x6c, 0x12, 0xa0, 0xa5, 0x2d, 0x73, 0x3a, 0x16, 0x85, 0x06, 0xf7, 0x6b, - 0x49, 0x04, 0xe9, 0xc1, 0x8c, 0x97, 0x32, 0x80, 0x5d, 0xe4, 0x63, 0x4f, 0x10, 0xe2, 0xe7, 0xaa, 0xaf, 0xdf, 0x17, - 0x91, 0x68, 0xf8, 0x3e, 0xd6, 0x50, 0x62, 0x26, 0x11, 0xfe, 0x48, 0x02, 0x81, 0xc3, 0x30, 0x94, 0x88, 0xf4, 0x96, - 0x16, 0x2b, 0xc2, 0x59, 0x67, 0x5f, 0x0c, 0x5a, 0xc3, 0x48, 0x86, 0x82, 0x26, 0x8b, 0x11, 0x0d, 0x02, 0x86, 0x73, - 0x9c, 0x21, 0xd2, 0x63, 0x8d, 0x80, 0x93, 0x1e, 0x6c, 0x37, 0xaf, 0xef, 0x35, 0x21, 0x7b, 0x2d, 0x64, 0x60, 0xe4, - 0x16, 0x40, 0xc0, 0xb0, 0x81, 0x87, 0x13, 0xe2, 0x67, 0x8b, 0xd9, 0x25, 0x15, 0x7e, 0xd9, 0xac, 0x5b, 0x23, 0x8b, - 0x45, 0x4e, 0xbd, 0x51, 0x9e, 0x7b, 0xe3, 0x45, 0x36, 0x92, 0x8c, 0x67, 0x9e, 0xdf, 0xe0, 0x0d, 0x5f, 0x93, 0x43, - 0x49, 0x0d, 0x3e, 0x2a, 0x50, 0x90, 0xa3, 0x86, 0x18, 0x64, 0x8d, 0xf6, 0x10, 0x03, 0x94, 0xa8, 0x6b, 0xc6, 0x33, - 0x08, 0xa0, 0x58, 0xc0, 0x1a, 0x0b, 0xfc, 0x41, 0xc2, 0x2a, 0xd5, 0x12, 0xa9, 0xec, 0x8b, 0x70, 0xf3, 0xa0, 0x10, - 0x19, 0xce, 0xe2, 0x79, 0x40, 0x49, 0x8f, 0x2a, 0xe2, 0x8a, 0xb3, 0x11, 0xc0, 0x5a, 0xdb, 0xb7, 0x3e, 0x8d, 0x68, - 0x58, 0x91, 0x14, 0x8a, 0x64, 0x38, 0xe6, 0xe2, 0x45, 0x3c, 0x9a, 0x42, 0xbf, 0x92, 0x60, 0x12, 0x7b, 0xde, 0x46, - 0x82, 0xc6, 0x92, 0xbe, 0x48, 0x29, 0x3c, 0x05, 0xbe, 0xea, 0xe9, 0x23, 0x9c, 0x93, 0x57, 0x61, 0xca, 0xe4, 0x1b, - 0x9e, 0x8d, 0x68, 0x37, 0x77, 0xa8, 0x8b, 0xc1, 0xbe, 0x9f, 0x48, 0x29, 0xd8, 0xe5, 0x42, 0xd2, 0xc0, 0xcf, 0xa0, - 0x85, 0x8f, 0x73, 0x84, 0x59, 0x28, 0xe9, 0x8d, 0x3c, 0xe5, 0x99, 0xa4, 0x99, 0x24, 0xd4, 0x22, 0x15, 0x8b, 0x30, - 0x9e, 0xcf, 0x69, 0x96, 0x9c, 0x4e, 0x59, 0x9a, 0x04, 0x0c, 0x15, 0xa8, 0xc0, 0xb1, 0x24, 0xb0, 0x46, 0xd2, 0x13, - 0x11, 0xfc, 0xb3, 0x7b, 0x35, 0x81, 0x24, 0x3d, 0x75, 0x28, 0x28, 0xf1, 0xfd, 0xee, 0x98, 0x8b, 0xc0, 0xac, 0xc0, - 0xe3, 0x63, 0x4f, 0xc2, 0x1c, 0xef, 0x16, 0x29, 0xcd, 0x11, 0x6d, 0x10, 0x56, 0x6e, 0xa3, 0x41, 0xf0, 0xd7, 0x40, - 0xf1, 0x05, 0x0a, 0x04, 0x8a, 0x44, 0xf7, 0x2a, 0x16, 0xde, 0x17, 0xe6, 0x44, 0xfd, 0x64, 0xb9, 0xd9, 0x54, 0x92, - 0x9f, 0x42, 0x29, 0x16, 0xb9, 0xa4, 0xc9, 0xfb, 0xdb, 0x39, 0xcd, 0xf1, 0x4b, 0x49, 0xa6, 0xb2, 0x3f, 0x95, 0x21, - 0x9d, 0xcd, 0xe5, 0xed, 0x99, 0x62, 0x8c, 0x91, 0xef, 0xe3, 0x11, 0xb4, 0x14, 0x34, 0x1e, 0x01, 0x33, 0x33, 0xd8, - 0xfa, 0x9a, 0xa7, 0xb7, 0x63, 0x96, 0xa6, 0x67, 0x8b, 0xf9, 0x9c, 0x0b, 0x89, 0xff, 0x4a, 0x96, 0x92, 0x57, 0xa8, - 0x81, 0xbd, 0x5c, 0xe6, 0xd7, 0x4c, 0x8e, 0xa6, 0x81, 0x44, 0xcb, 0x51, 0x9c, 0x53, 0xef, 0x19, 0xe7, 0x29, 0x8d, - 0xb3, 0x48, 0x10, 0xd1, 0x7f, 0x29, 0xa3, 0x6c, 0x91, 0xa6, 0xdd, 0x4b, 0x41, 0xe3, 0x8f, 0x5d, 0x55, 0xfd, 0xf6, - 0xf2, 0x27, 0x3a, 0x92, 0x91, 0xfa, 0x7d, 0x22, 0x44, 0x7c, 0x0b, 0x0d, 0x09, 0x81, 0x66, 0x7d, 0x11, 0x7d, 0x75, - 0xf6, 0xf6, 0x4d, 0xa8, 0x0f, 0x09, 0x1b, 0xdf, 0x06, 0xa2, 0x3c, 0x78, 0xa2, 0xc0, 0x63, 0xc1, 0x67, 0x6b, 0x53, - 0x6b, 0xac, 0x89, 0xee, 0x0e, 0x10, 0x28, 0x11, 0x7b, 0x7a, 0x68, 0x17, 0x82, 0x37, 0x8a, 0xe6, 0xa1, 0x92, 0x98, - 0x79, 0xe1, 0x9f, 0x48, 0x17, 0x07, 0x02, 0xdd, 0x0d, 0xad, 0x14, 0xb7, 0x4b, 0x4a, 0x14, 0x9c, 0x73, 0x90, 0x30, - 0x00, 0xe3, 0x28, 0x96, 0xa3, 0xe9, 0x92, 0xaa, 0xc1, 0x0a, 0x0b, 0x31, 0x2d, 0x0a, 0x7c, 0x5d, 0xd2, 0xbb, 0xdc, - 0x23, 0x44, 0x28, 0x46, 0x45, 0xe4, 0x6a, 0x25, 0x08, 0x11, 0x08, 0x7f, 0x47, 0x96, 0xb1, 0x5d, 0x4f, 0xb4, 0xd7, - 0xc2, 0x70, 0x2e, 0x23, 0xcd, 0x5d, 0xf0, 0x88, 0x67, 0x57, 0x54, 0x48, 0x2a, 0xa2, 0xbf, 0x62, 0x41, 0xc7, 0x29, - 0x40, 0xb1, 0xd7, 0xc6, 0xd3, 0x38, 0x3f, 0x9d, 0xc6, 0xd9, 0x84, 0x26, 0xd1, 0xb5, 0x2c, 0xf0, 0xdf, 0x89, 0x3f, - 0x66, 0x59, 0x9c, 0xb2, 0x5f, 0x68, 0xe2, 0x1b, 0x69, 0x70, 0xe2, 0xd1, 0x1b, 0x49, 0xb3, 0x24, 0xf7, 0x5e, 0xbe, - 0x7f, 0xfd, 0xca, 0xec, 0x63, 0x4d, 0x40, 0xa0, 0x65, 0xbe, 0x98, 0x53, 0x11, 0x20, 0x6c, 0x04, 0xc4, 0x0b, 0xa6, - 0x98, 0xe3, 0xeb, 0x78, 0xae, 0x4b, 0x58, 0xfe, 0x61, 0x9e, 0xc4, 0x92, 0x7e, 0x4d, 0xb3, 0x84, 0x65, 0x13, 0xb2, - 0xd7, 0xd6, 0xe5, 0xd3, 0xd8, 0x54, 0x24, 0x65, 0xd1, 0xf9, 0xfe, 0x8b, 0x54, 0xad, 0xbb, 0x7c, 0x5c, 0x04, 0xa8, - 0xc8, 0x65, 0x2c, 0xd9, 0xc8, 0x8b, 0x93, 0xe4, 0xcb, 0x8c, 0x49, 0xa6, 0x00, 0x14, 0xb0, 0x3d, 0x40, 0xa2, 0x54, - 0x8b, 0x0a, 0x0b, 0x78, 0x80, 0x70, 0x10, 0x18, 0x01, 0x30, 0x45, 0x66, 0xbf, 0x0e, 0x0e, 0x2a, 0x76, 0xdf, 0xa7, - 0x91, 0xae, 0x24, 0x83, 0x21, 0x0a, 0xe7, 0x8b, 0x1c, 0x36, 0xda, 0x4e, 0x01, 0xd2, 0x85, 0x5f, 0xe6, 0x54, 0x5c, - 0xd1, 0xa4, 0x24, 0x8e, 0x3c, 0x40, 0xcb, 0xb5, 0x39, 0xcc, 0xb1, 0x90, 0x64, 0x30, 0xec, 0xba, 0x7c, 0x9b, 0x1a, - 0x3a, 0x17, 0x7c, 0x4e, 0x85, 0x64, 0x34, 0x2f, 0x59, 0x49, 0x00, 0x52, 0xb4, 0x64, 0x27, 0x39, 0xb1, 0xeb, 0x9b, - 0x07, 0x0c, 0x53, 0x54, 0x63, 0x18, 0x56, 0xd0, 0xbe, 0xb8, 0x52, 0x12, 0x23, 0xc7, 0x0c, 0x61, 0xa9, 0x21, 0xcd, - 0x11, 0x2a, 0x10, 0x96, 0x16, 0x5c, 0xcd, 0x8a, 0xcc, 0x6c, 0xb7, 0x20, 0xaa, 0xc9, 0x77, 0x4a, 0x54, 0x03, 0x43, - 0x8b, 0x25, 0x3d, 0x38, 0x08, 0x68, 0x58, 0x12, 0x05, 0xd9, 0x6b, 0x9b, 0x3d, 0x72, 0x90, 0xb5, 0x03, 0x6c, 0x98, - 0x58, 0x62, 0x8a, 0xf0, 0x1e, 0x0d, 0x33, 0x7e, 0x32, 0x1a, 0xd1, 0x3c, 0xe7, 0xe2, 0xe0, 0x60, 0x4f, 0xb5, 0x2f, - 0xb5, 0x09, 0xd8, 0xc3, 0xb7, 0xd7, 0x59, 0x05, 0x01, 0xaa, 0x24, 0xac, 0x91, 0x0b, 0x12, 0xe4, 0x94, 0x52, 0x38, - 0xfc, 0xbe, 0x55, 0x3c, 0x22, 0xff, 0xfc, 0xdc, 0x6f, 0x48, 0x6c, 0xd0, 0x30, 0xa1, 0x76, 0xea, 0xdb, 0xe7, 0x54, - 0xab, 0x56, 0x4a, 0xf1, 0xd8, 0xc0, 0x8c, 0x3e, 0x3f, 0x61, 0x42, 0xc7, 0x2c, 0x73, 0x96, 0x5d, 0x03, 0x09, 0x4b, - 0x9c, 0xa3, 0xc2, 0xd9, 0xd0, 0xad, 0x43, 0x2b, 0x9d, 0x46, 0xef, 0xdc, 0x72, 0xa2, 0xf4, 0x08, 0x67, 0x1b, 0x07, - 0x74, 0x58, 0x60, 0x85, 0x7a, 0xbb, 0x9a, 0x4c, 0x01, 0x3a, 0x90, 0xc3, 0xae, 0xa9, 0x27, 0xb9, 0xc6, 0x9c, 0xa0, - 0x3f, 0x2f, 0x68, 0x2e, 0x35, 0x1d, 0x07, 0x12, 0x67, 0x98, 0xa1, 0x02, 0x8e, 0xdb, 0x98, 0x4d, 0x16, 0x02, 0xd4, - 0x1d, 0x38, 0x8a, 0x34, 0x5b, 0xcc, 0xa8, 0x7d, 0xda, 0x06, 0xdb, 0xdb, 0x39, 0x08, 0xc4, 0x1c, 0x68, 0xfa, 0x6e, - 0x72, 0x02, 0x58, 0x25, 0x5a, 0xad, 0xbe, 0xb3, 0x83, 0x54, 0x5b, 0x59, 0xaa, 0x68, 0x6b, 0x7b, 0xf2, 0x77, 0x64, - 0xe4, 0xf1, 0x5e, 0x5b, 0x43, 0xff, 0xf7, 0x21, 0xd9, 0x6b, 0x95, 0x14, 0x6c, 0x70, 0xaa, 0x81, 0xd1, 0x28, 0x7c, - 0xab, 0x07, 0x42, 0x4a, 0xba, 0xd7, 0x88, 0x25, 0x9c, 0x6e, 0xd0, 0xe9, 0x94, 0x0c, 0x40, 0xcf, 0x08, 0xa7, 0xc3, - 0x5d, 0xc4, 0x64, 0xb9, 0x41, 0x20, 0x37, 0xeb, 0x2a, 0xa6, 0x71, 0x55, 0x67, 0x1a, 0x6b, 0x8b, 0xf0, 0xe7, 0x65, - 0x17, 0xbf, 0xa4, 0x31, 0x73, 0xcc, 0xab, 0x2a, 0xcc, 0x14, 0x30, 0xd5, 0x92, 0x9c, 0x21, 0xde, 0xc4, 0x33, 0x9a, - 0x07, 0x14, 0xe1, 0x5d, 0x0d, 0x34, 0x71, 0x42, 0x93, 0xa1, 0x23, 0x36, 0x73, 0x10, 0x9b, 0x0c, 0x69, 0xad, 0xac, - 0x7e, 0xdc, 0x72, 0x4c, 0x07, 0xf9, 0xb0, 0x52, 0xe6, 0x9c, 0xc5, 0x2b, 0x79, 0x6c, 0xa8, 0xdb, 0xe2, 0x4f, 0x97, - 0x69, 0xa4, 0x29, 0xa5, 0x21, 0x47, 0x78, 0xaf, 0xb5, 0xbe, 0x8f, 0xb6, 0x55, 0xb5, 0xc6, 0xc1, 0x10, 0xf6, 0x41, - 0x89, 0x8b, 0x90, 0xe5, 0xea, 0xff, 0xda, 0x39, 0x03, 0xb4, 0x9d, 0x01, 0x59, 0x84, 0xe3, 0x34, 0x96, 0x41, 0xfb, - 0xb0, 0x05, 0x9a, 0xe8, 0x15, 0x05, 0x69, 0x82, 0xd0, 0xe6, 0x52, 0x68, 0xb8, 0xc8, 0xf2, 0x29, 0x1b, 0xcb, 0x20, - 0x96, 0x8a, 0xa1, 0xd0, 0x34, 0xa7, 0x9e, 0xac, 0xe9, 0xc3, 0x8a, 0xd9, 0xc4, 0x40, 0x6a, 0xa5, 0xf2, 0x45, 0x2d, - 0xa4, 0x8a, 0x69, 0x01, 0x6f, 0xa8, 0x74, 0xe9, 0x8a, 0xc7, 0xd8, 0xd6, 0x0c, 0xf4, 0xc5, 0x76, 0x5f, 0x8f, 0x18, - 0x19, 0x56, 0xc0, 0x1c, 0x95, 0x95, 0x45, 0x2e, 0x7f, 0x30, 0x85, 0x32, 0x94, 0xfc, 0x15, 0xbf, 0xa6, 0xe2, 0x34, - 0x06, 0xe0, 0x23, 0xdd, 0xbd, 0xd0, 0x62, 0x40, 0x71, 0x7b, 0xd9, 0xb5, 0xf4, 0x72, 0xae, 0x16, 0xfe, 0xb5, 0xe0, - 0x33, 0x96, 0x53, 0xd0, 0xd4, 0x34, 0xfe, 0x33, 0x38, 0x65, 0xea, 0x38, 0x82, 0xa8, 0xa1, 0x25, 0x7d, 0x9d, 0xbc, - 0xaa, 0xd3, 0xd7, 0xf9, 0xfe, 0x8b, 0x89, 0x65, 0x7f, 0xf5, 0x43, 0x8c, 0x70, 0x60, 0xec, 0x09, 0x47, 0xca, 0x85, - 0x53, 0x64, 0xc4, 0xfb, 0x6a, 0x25, 0x1d, 0xb3, 0xad, 0xa6, 0x2b, 0x52, 0x7d, 0x6c, 0x50, 0x11, 0x27, 0x09, 0x68, - 0x75, 0x82, 0xa7, 0xa9, 0x23, 0xa8, 0x30, 0xeb, 0x96, 0xa2, 0xe9, 0x7c, 0xff, 0xc5, 0xd9, 0x5d, 0xd2, 0x09, 0xea, - 0x5d, 0x01, 0x65, 0x01, 0xcd, 0x12, 0x2a, 0xc0, 0x8c, 0x74, 0x76, 0xcb, 0xc8, 0xd8, 0x53, 0x9e, 0x65, 0x74, 0x24, - 0x69, 0x02, 0x56, 0x0a, 0x23, 0x32, 0x9c, 0xf2, 0x5c, 0x96, 0x85, 0x15, 0xf4, 0xcc, 0x81, 0x9e, 0x85, 0xa3, 0x38, - 0x4d, 0x03, 0x6d, 0x91, 0xcc, 0xf8, 0x15, 0xdd, 0x02, 0x75, 0xb7, 0x06, 0x72, 0x39, 0x0c, 0x75, 0x86, 0xa1, 0x61, - 0x3e, 0x4f, 0xd9, 0x88, 0x96, 0x82, 0xeb, 0x2c, 0x64, 0x59, 0x42, 0x6f, 0x80, 0x8f, 0xa0, 0x5e, 0xaf, 0xd7, 0xc2, - 0x6d, 0x54, 0x68, 0x84, 0x2f, 0x37, 0x10, 0x7b, 0x87, 0xc8, 0x04, 0x22, 0x23, 0xbd, 0xe5, 0x36, 0x7e, 0x40, 0x91, - 0x23, 0x27, 0x99, 0xb5, 0xac, 0x34, 0x6f, 0x46, 0x38, 0xa1, 0x29, 0x95, 0xd4, 0xf2, 0x72, 0xd0, 0x9f, 0xf5, 0xd1, - 0x7d, 0x57, 0xe2, 0xaf, 0x24, 0x27, 0x7b, 0xca, 0xec, 0x9e, 0xe7, 0xa5, 0xa5, 0x5e, 0x6d, 0x4f, 0x85, 0xed, 0xbe, - 0xd4, 0xdb, 0x13, 0x4b, 0x19, 0x8f, 0xa6, 0xda, 0x44, 0x0f, 0x36, 0x96, 0x54, 0x8d, 0x61, 0xf8, 0x7a, 0x79, 0x88, - 0x3e, 0x58, 0x30, 0xb7, 0xa1, 0xe0, 0xcc, 0x30, 0x05, 0x0a, 0x56, 0x9f, 0xde, 0xb6, 0xd3, 0x38, 0x4d, 0x2f, 0xe3, - 0xd1, 0xc7, 0x3a, 0xf5, 0x57, 0x64, 0x40, 0xd6, 0xb9, 0xb1, 0x53, 0xe5, 0xb0, 0x2c, 0x77, 0xdd, 0x96, 0x4b, 0xd7, - 0x0e, 0x4a, 0xb0, 0xd7, 0xaa, 0xc8, 0xbe, 0xbe, 0xd1, 0x3b, 0xa9, 0x5d, 0x41, 0xc4, 0xcc, 0xca, 0x02, 0xe0, 0x02, - 0x9f, 0xa4, 0x38, 0xcb, 0x0f, 0x0c, 0xdd, 0x81, 0xad, 0x51, 0xac, 0x01, 0x22, 0xd1, 0xb2, 0x48, 0x58, 0xbe, 0x1b, - 0x03, 0x7f, 0x08, 0x94, 0xcf, 0x9d, 0x19, 0xee, 0x0b, 0x68, 0xc9, 0xe3, 0x8c, 0xca, 0x5c, 0x42, 0x66, 0xb4, 0x09, - 0xcb, 0x68, 0xfe, 0x06, 0x9a, 0x8b, 0xa2, 0xf7, 0xb7, 0xba, 0x0a, 0x74, 0x32, 0x80, 0x22, 0xef, 0xba, 0xca, 0x44, - 0x8d, 0x02, 0x0c, 0x4f, 0x65, 0x4a, 0xe4, 0x66, 0x35, 0xe3, 0xd1, 0xa8, 0xeb, 0xda, 0xfe, 0x36, 0x2c, 0x97, 0x93, - 0x20, 0x08, 0x72, 0xb0, 0xdf, 0xac, 0x5e, 0x5f, 0x2d, 0x22, 0xdf, 0x58, 0x44, 0x1e, 0x3a, 0x46, 0x16, 0xaa, 0x68, - 0xd9, 0xe9, 0x1e, 0xfd, 0x15, 0xb9, 0x8d, 0x40, 0x59, 0x0d, 0x81, 0x3f, 0xa3, 0x92, 0xdd, 0xa6, 0x44, 0x62, 0x6e, - 0x0c, 0x1c, 0x43, 0x69, 0xc0, 0x30, 0xaa, 0x2e, 0x19, 0xd2, 0x47, 0xa3, 0x66, 0xec, 0x66, 0x98, 0xa3, 0x35, 0xcd, - 0xbe, 0x28, 0x0c, 0x8e, 0x28, 0x32, 0x7b, 0x53, 0x53, 0x89, 0x1d, 0xac, 0xe0, 0x8c, 0x18, 0x35, 0x58, 0x6b, 0x3d, - 0xeb, 0xb8, 0x29, 0xc7, 0x85, 0x83, 0x5a, 0xa1, 0xa6, 0xa6, 0x4f, 0x5a, 0xc5, 0x2a, 0x43, 0x78, 0x6a, 0x35, 0x52, - 0x5e, 0xad, 0x9b, 0x10, 0xdf, 0x7a, 0x23, 0xfc, 0xfe, 0xb2, 0x66, 0x12, 0x46, 0x4e, 0xb3, 0x22, 0x02, 0x96, 0xca, - 0xb7, 0xa1, 0x7b, 0x1b, 0xcd, 0xd4, 0xc6, 0x71, 0x10, 0xce, 0x5d, 0x84, 0x3b, 0x98, 0xcd, 0x34, 0xe7, 0xca, 0x86, - 0x64, 0x5a, 0xef, 0x1b, 0x50, 0xcc, 0xf5, 0x3e, 0x6c, 0x20, 0x71, 0x5d, 0xf1, 0x54, 0x24, 0x08, 0x06, 0x6c, 0x0e, - 0xca, 0x9d, 0x2b, 0x1f, 0x02, 0x80, 0x9d, 0xad, 0x56, 0x1b, 0x44, 0xb7, 0x55, 0xff, 0x44, 0x61, 0x65, 0x14, 0xae, - 0x56, 0xd7, 0x12, 0x05, 0x46, 0xf3, 0xc5, 0x14, 0xf5, 0x2d, 0xc7, 0x3d, 0x79, 0x05, 0xad, 0x94, 0x22, 0x5a, 0x95, - 0x94, 0x26, 0x43, 0x9d, 0x66, 0xeb, 0xfb, 0x24, 0x1d, 0xb6, 0x7d, 0xba, 0xc1, 0xbd, 0x54, 0xa1, 0x11, 0xd3, 0xd5, - 0x92, 0x4f, 0xcd, 0xd0, 0x0c, 0x21, 0x14, 0xe5, 0xca, 0x8a, 0xd9, 0xdb, 0x66, 0x58, 0x1e, 0x1c, 0xe4, 0xce, 0x40, - 0xe7, 0x25, 0x9b, 0xf8, 0x29, 0x00, 0x91, 0x9c, 0xdf, 0x66, 0x4a, 0x77, 0xf9, 0xc9, 0x0a, 0xa1, 0x0d, 0xb3, 0xb4, - 0xd5, 0x05, 0x6b, 0x3c, 0xbe, 0x8e, 0x99, 0xf4, 0xca, 0x51, 0xb4, 0x35, 0x1e, 0x50, 0xb4, 0x34, 0xaa, 0x46, 0x28, - 0x28, 0x28, 0x8f, 0xc0, 0x13, 0xac, 0x0a, 0xad, 0xe9, 0x7e, 0x34, 0xa5, 0xe0, 0x08, 0xb6, 0x5a, 0x44, 0x69, 0x17, - 0xee, 0x19, 0x29, 0x62, 0x06, 0xde, 0x0e, 0x7b, 0xb1, 0xde, 0xbd, 0x66, 0x07, 0xcc, 0xa9, 0x18, 0x73, 0x31, 0xb3, - 0x75, 0xc5, 0xda, 0xb3, 0xe1, 0x8c, 0x6c, 0x1c, 0x6c, 0x1d, 0xdb, 0xa8, 0xff, 0xdd, 0x35, 0xa3, 0xbb, 0x32, 0xd7, - 0x6b, 0xa2, 0xb4, 0x94, 0xbe, 0xda, 0x1f, 0x68, 0x29, 0x33, 0x77, 0xcd, 0x7b, 0xe3, 0x4c, 0xed, 0x6a, 0x87, 0xc9, - 0x5e, 0xbb, 0x5b, 0xda, 0x7c, 0x96, 0x1a, 0xba, 0xda, 0xb1, 0x61, 0x44, 0x2a, 0x5f, 0xa4, 0x89, 0x01, 0x96, 0x21, - 0x4c, 0x0d, 0x1d, 0x5d, 0xb3, 0x34, 0xad, 0x4a, 0x7f, 0x0d, 0x5f, 0xcf, 0x0d, 0x5f, 0xcf, 0x2c, 0x5f, 0x07, 0x4e, - 0x01, 0x7c, 0x5d, 0x0f, 0x57, 0x75, 0xcf, 0x36, 0x4e, 0x67, 0xa6, 0x39, 0x7a, 0xae, 0xec, 0x68, 0x98, 0x6f, 0x61, - 0x21, 0x40, 0xa5, 0xe6, 0xf5, 0x31, 0x30, 0x4e, 0x18, 0x30, 0x00, 0xb5, 0x0b, 0x93, 0xba, 0x2e, 0x8a, 0x8f, 0x01, - 0xc2, 0x79, 0x41, 0x4b, 0xca, 0x3e, 0x79, 0x01, 0x4e, 0x3a, 0x67, 0x39, 0x20, 0xc4, 0x54, 0xf1, 0xaf, 0x52, 0xa2, - 0xec, 0xea, 0x98, 0x59, 0x5d, 0x6e, 0x57, 0x07, 0x9c, 0xbe, 0x5a, 0x5d, 0x72, 0x37, 0xaf, 0x57, 0xcb, 0x63, 0xe5, - 0xf2, 0xaa, 0xfd, 0x5e, 0xad, 0x82, 0xb5, 0x12, 0xf0, 0xdf, 0x1b, 0x13, 0x45, 0x94, 0xa3, 0x03, 0x0f, 0x70, 0x31, - 0x03, 0x05, 0x85, 0x5e, 0x74, 0x29, 0xe2, 0x5e, 0x7d, 0xca, 0xc1, 0xa3, 0xdc, 0xf4, 0xba, 0xff, 0x29, 0x9f, 0xcd, - 0x41, 0x1b, 0x5b, 0x23, 0xe9, 0x09, 0x35, 0x13, 0x56, 0xf5, 0xc5, 0x96, 0xb2, 0x5a, 0x1f, 0x75, 0x1e, 0x6b, 0xd4, - 0x54, 0xda, 0xcb, 0x7b, 0xad, 0x62, 0x51, 0x16, 0x95, 0x8c, 0x63, 0x9b, 0x53, 0xe5, 0x74, 0xdd, 0x25, 0x63, 0x2b, - 0xde, 0x06, 0x4c, 0xf3, 0x61, 0x06, 0xbc, 0xce, 0x61, 0x3f, 0x96, 0xdc, 0xdd, 0xfd, 0x2f, 0x2a, 0xe4, 0x2c, 0x8b, - 0x35, 0xf4, 0x2d, 0x8b, 0xe2, 0x44, 0x1b, 0xd9, 0xf8, 0x64, 0xb7, 0x35, 0x5c, 0xd5, 0x19, 0x63, 0x71, 0x30, 0xc4, - 0x27, 0x9b, 0xaa, 0x23, 0x59, 0xce, 0x78, 0x42, 0x23, 0x9f, 0xcf, 0x69, 0xe6, 0x17, 0xe0, 0x55, 0x35, 0x7b, 0x3f, - 0x92, 0xc1, 0xf2, 0x5d, 0xdd, 0xbd, 0x1a, 0x9d, 0x14, 0xe0, 0xfd, 0xfa, 0x62, 0xd3, 0xf1, 0xfa, 0x2d, 0x15, 0xb9, - 0x52, 0x44, 0x4b, 0x9d, 0xf6, 0x8b, 0x4a, 0x2c, 0x7d, 0x11, 0xed, 0x6c, 0x5f, 0x99, 0x20, 0x7e, 0x3b, 0x7c, 0x1c, - 0x1e, 0xf9, 0x48, 0xb9, 0x85, 0xbf, 0x32, 0x07, 0xfe, 0xb9, 0x75, 0x0b, 0xbf, 0x20, 0xcf, 0xeb, 0x5e, 0xe1, 0x44, - 0x92, 0x17, 0xfd, 0x17, 0xd6, 0x62, 0xe6, 0x29, 0x1b, 0xdd, 0x06, 0x7e, 0xca, 0x64, 0x13, 0x42, 0x6f, 0x3e, 0x5e, - 0xea, 0x0a, 0x70, 0x29, 0x2a, 0x77, 0x76, 0x61, 0x6d, 0x3d, 0x2c, 0x25, 0xf1, 0xf7, 0x53, 0x26, 0xf7, 0x7d, 0x3c, - 0x23, 0x17, 0xf0, 0x63, 0x7f, 0x19, 0xbc, 0x8e, 0xe5, 0x34, 0x14, 0x71, 0x96, 0xf0, 0x59, 0x80, 0x1a, 0xbe, 0x8f, - 0xc2, 0x5c, 0xd9, 0x1b, 0x9f, 0xa3, 0x62, 0xff, 0x02, 0xdf, 0x48, 0xe2, 0xf7, 0xfd, 0xc6, 0x0c, 0xbf, 0x91, 0xe4, - 0xe2, 0x78, 0x7f, 0x79, 0x23, 0x8b, 0xde, 0x05, 0xbe, 0x29, 0x3d, 0xf6, 0xf8, 0x6b, 0x12, 0x20, 0xd2, 0xbb, 0x31, - 0xd0, 0x9c, 0xf2, 0x99, 0xf6, 0xdc, 0xfb, 0x08, 0x7f, 0x80, 0xb8, 0x8a, 0xa8, 0xb8, 0x8d, 0x09, 0xad, 0xec, 0x11, - 0x9f, 0x2b, 0x17, 0x81, 0x7f, 0x70, 0xe0, 0x94, 0x95, 0xaa, 0x02, 0x3e, 0x91, 0xa4, 0x66, 0x90, 0xe3, 0xf7, 0x2a, - 0x42, 0x73, 0x22, 0x03, 0x81, 0xec, 0x30, 0x81, 0xf5, 0x43, 0x9b, 0xa3, 0x29, 0x06, 0xda, 0xc3, 0x10, 0x32, 0x49, - 0x45, 0x2c, 0xb9, 0x18, 0x22, 0x57, 0xfd, 0xc0, 0x7f, 0x23, 0x17, 0x03, 0xef, 0x3f, 0xfd, 0xd3, 0x8f, 0xe3, 0x1f, - 0xc5, 0xf0, 0x02, 0xbf, 0x25, 0x87, 0xc7, 0x41, 0x3f, 0x0a, 0xf6, 0x9a, 0xcd, 0xd5, 0x8f, 0x87, 0x83, 0x7f, 0xc4, - 0xcd, 0x5f, 0x4e, 0x9a, 0x3f, 0x0c, 0xd1, 0x2a, 0xf8, 0xf1, 0xb0, 0x3f, 0x30, 0x4f, 0x83, 0x7f, 0xf4, 0x7e, 0xcc, - 0x87, 0x7f, 0xd6, 0x85, 0xfb, 0x08, 0x1d, 0x4e, 0xf0, 0x42, 0x92, 0xc3, 0x66, 0xb3, 0x77, 0x38, 0xc1, 0x73, 0x49, - 0x0e, 0xe1, 0xff, 0x4b, 0xf2, 0x8e, 0x4e, 0x5e, 0xdc, 0xcc, 0x83, 0x8b, 0xde, 0x6a, 0x7f, 0xf9, 0xb7, 0x02, 0x46, - 0x1d, 0xfc, 0xe3, 0xc7, 0x1f, 0x73, 0xff, 0x41, 0x8f, 0x1c, 0x0e, 0x1b, 0x28, 0x80, 0xd2, 0x3f, 0x13, 0xf5, 0x6f, - 0xd0, 0x8f, 0x06, 0xff, 0x30, 0x50, 0xf8, 0x0f, 0x7e, 0xbc, 0x38, 0xee, 0x91, 0xe1, 0x2a, 0xf0, 0x57, 0x0f, 0xd0, - 0x0a, 0xa1, 0xd5, 0x3e, 0xba, 0xc0, 0xfe, 0xc4, 0x47, 0x78, 0x22, 0xc9, 0xe1, 0x83, 0xc3, 0x09, 0xbe, 0x92, 0xe4, - 0xd0, 0x3f, 0x9c, 0xe0, 0x17, 0x92, 0x1c, 0xfe, 0x23, 0xe8, 0x47, 0xda, 0xc3, 0xb6, 0x52, 0xee, 0x8d, 0x15, 0x04, - 0x37, 0x62, 0x41, 0xe3, 0x95, 0x64, 0x32, 0xa5, 0x68, 0xff, 0x90, 0xe1, 0x33, 0x85, 0xa6, 0x40, 0x82, 0x13, 0x06, - 0x6c, 0xbb, 0x60, 0x79, 0x0e, 0x9b, 0x0d, 0x34, 0xb3, 0x1f, 0x09, 0xac, 0xfd, 0x00, 0x79, 0x24, 0xf1, 0x55, 0x9c, - 0x2e, 0x68, 0x1e, 0xd1, 0x02, 0xe1, 0x11, 0x39, 0x93, 0x41, 0x1b, 0xe1, 0x77, 0x12, 0x7e, 0x74, 0x10, 0x3e, 0x33, - 0x01, 0x4c, 0x38, 0xc8, 0x9a, 0xa8, 0x32, 0xae, 0x35, 0x16, 0x1f, 0xe1, 0xf9, 0x96, 0x4a, 0x39, 0x05, 0xef, 0x02, - 0xc2, 0xe3, 0x5a, 0xb8, 0x13, 0x5f, 0x13, 0x4b, 0x12, 0xef, 0x05, 0xa5, 0xdf, 0xc5, 0xe9, 0x47, 0x2a, 0x82, 0x1b, - 0xdc, 0xee, 0x7c, 0x8e, 0x95, 0x0b, 0x7a, 0xaf, 0x8d, 0xba, 0x65, 0xac, 0xea, 0x54, 0xea, 0x18, 0x01, 0x08, 0xd9, - 0xba, 0x2f, 0x06, 0x76, 0x7c, 0x4f, 0x6c, 0x38, 0xac, 0x44, 0x7c, 0xed, 0xa3, 0x7a, 0x5c, 0x94, 0x65, 0x57, 0x71, - 0xca, 0x12, 0x4f, 0xd2, 0xd9, 0x3c, 0x8d, 0x25, 0xf5, 0xcc, 0x7a, 0xbd, 0x18, 0x06, 0xf2, 0x4b, 0x95, 0x21, 0x71, - 0x0c, 0xce, 0xc4, 0x06, 0x9c, 0xe0, 0xac, 0x04, 0x10, 0x9d, 0x32, 0x6a, 0xc7, 0xeb, 0x2a, 0xf8, 0xb5, 0x1e, 0xdf, - 0x6b, 0xb6, 0xc1, 0x11, 0x36, 0x54, 0xe2, 0x39, 0xc7, 0x19, 0x01, 0x21, 0xda, 0xe9, 0xfb, 0xc7, 0xf9, 0xd5, 0xa4, - 0xe7, 0x43, 0x6c, 0x86, 0x93, 0xb7, 0xca, 0x2f, 0x04, 0x0d, 0xa6, 0xa4, 0xd5, 0x9d, 0x1e, 0xd3, 0xee, 0xb4, 0xd1, - 0xb0, 0x3a, 0x74, 0x4a, 0xc4, 0x60, 0xaa, 0xbb, 0xc7, 0x38, 0xc1, 0x0b, 0xd2, 0x6c, 0xe3, 0x09, 0x69, 0xa9, 0x2e, - 0xdd, 0xc9, 0x71, 0x6a, 0xa6, 0x39, 0x38, 0x08, 0x78, 0x98, 0xc6, 0xb9, 0xfc, 0x12, 0x8c, 0x7d, 0x32, 0xc1, 0x09, - 0xe1, 0x21, 0xbd, 0xa1, 0xa3, 0x20, 0x45, 0x38, 0x31, 0x9c, 0x06, 0x75, 0xd1, 0x84, 0x38, 0xcd, 0xc0, 0x88, 0x20, - 0x6f, 0xfb, 0xc9, 0xa0, 0x3d, 0x24, 0x84, 0xf8, 0x7b, 0xcd, 0xa6, 0xdf, 0xe7, 0x64, 0x21, 0x23, 0x28, 0x71, 0x54, - 0x65, 0x32, 0x87, 0xa2, 0x8e, 0x53, 0x14, 0xbc, 0x90, 0xa1, 0xa4, 0xb9, 0x0c, 0xa0, 0x18, 0xcc, 0xff, 0xdc, 0x12, - 0xb6, 0x7f, 0x7c, 0xe8, 0x37, 0xa0, 0x54, 0x11, 0x27, 0xc2, 0x9c, 0x5c, 0xa2, 0x28, 0x19, 0x1c, 0x0d, 0x5d, 0xfe, - 0xaf, 0x0a, 0x61, 0xf2, 0xcb, 0x7e, 0x32, 0x68, 0xa9, 0xc9, 0x7b, 0x7e, 0x3f, 0xe0, 0x24, 0xd7, 0x0a, 0x5a, 0x3f, - 0x8f, 0xde, 0xaa, 0xa5, 0xa2, 0xc8, 0x00, 0x67, 0xe6, 0x5d, 0x90, 0x66, 0x27, 0x0a, 0x16, 0xee, 0x22, 0x9a, 0x30, - 0x99, 0xc1, 0x02, 0x8e, 0x09, 0xb4, 0xc7, 0x9c, 0xc0, 0x8c, 0x55, 0xb7, 0xcb, 0xc8, 0x3c, 0x3f, 0xf0, 0x1f, 0xf4, - 0xaf, 0x64, 0x34, 0x91, 0x7a, 0xfa, 0x2b, 0xb9, 0x5a, 0xc1, 0xff, 0x13, 0xd9, 0xe7, 0xe4, 0x52, 0x15, 0x2d, 0x4c, - 0xd1, 0x1c, 0x8a, 0xde, 0x46, 0x00, 0x2a, 0xce, 0x4b, 0x25, 0x4b, 0xef, 0xc9, 0x15, 0x51, 0xb0, 0x1f, 0x1c, 0x88, - 0xc1, 0xb4, 0xd1, 0x1e, 0x82, 0x7f, 0x5f, 0xc8, 0xfc, 0x3b, 0x26, 0xa7, 0x81, 0x7f, 0xd8, 0xf3, 0x51, 0xdf, 0xf7, - 0x60, 0x6b, 0xbb, 0x59, 0x83, 0x68, 0x0c, 0xa7, 0x8d, 0x37, 0x32, 0x5a, 0xf4, 0x48, 0xab, 0x1f, 0x30, 0xe3, 0xcf, - 0x43, 0x38, 0x35, 0x8c, 0xb3, 0x85, 0x17, 0xa8, 0x21, 0x65, 0xc3, 0x3e, 0x2f, 0x50, 0x63, 0xd6, 0xb8, 0x42, 0x51, - 0xda, 0x98, 0x35, 0x82, 0x05, 0x21, 0xa4, 0xd9, 0x29, 0xbb, 0x59, 0xe9, 0x37, 0x45, 0xd1, 0x95, 0x75, 0x76, 0x0e, - 0xd4, 0x71, 0xc8, 0x1a, 0x81, 0x18, 0xd0, 0xe1, 0x6a, 0xe5, 0x1f, 0xf7, 0x7b, 0x3e, 0x6a, 0x04, 0x96, 0xd0, 0x0e, - 0x2d, 0xa5, 0x21, 0x84, 0xd9, 0xb0, 0x30, 0xa1, 0xa4, 0x97, 0xb5, 0xb0, 0xd1, 0xb2, 0x3a, 0xec, 0x0e, 0x0f, 0xa0, - 0x45, 0x69, 0xc7, 0x68, 0x7d, 0x75, 0x0e, 0xcb, 0xb4, 0xc4, 0x9c, 0x91, 0x16, 0xe6, 0xc4, 0xfa, 0xae, 0xa7, 0x44, - 0x56, 0x04, 0x9f, 0x92, 0xaa, 0x39, 0x1e, 0xc4, 0x38, 0x19, 0x92, 0xd7, 0xda, 0x1e, 0xe9, 0x5a, 0xbf, 0x38, 0x4d, - 0xc9, 0xcb, 0xb5, 0xe8, 0x6d, 0x0c, 0xb1, 0x95, 0xeb, 0x70, 0xb4, 0x10, 0x82, 0x66, 0xf2, 0x0d, 0x4f, 0x8c, 0x9a, - 0x46, 0x53, 0xb0, 0x94, 0x20, 0x2c, 0x8b, 0x41, 0x47, 0xeb, 0xd8, 0x93, 0xb1, 0xd8, 0xa8, 0x9e, 0x90, 0x85, 0x56, - 0x9f, 0x54, 0xb0, 0xb6, 0x3b, 0x31, 0x76, 0x71, 0x80, 0xf0, 0xc2, 0x44, 0x71, 0x83, 0x30, 0x0c, 0x27, 0xe1, 0x08, - 0xaa, 0x61, 0x82, 0x1c, 0x15, 0xea, 0x1c, 0x05, 0x39, 0xb9, 0x0e, 0x33, 0x7a, 0xa3, 0x66, 0x0d, 0x50, 0x25, 0x99, - 0xed, 0xf1, 0x3a, 0x9e, 0x76, 0x15, 0xbb, 0xc9, 0xc3, 0x8c, 0x27, 0x14, 0xd0, 0x03, 0x71, 0x7b, 0x53, 0x34, 0x8d, - 0x73, 0x37, 0x3e, 0x55, 0xc1, 0x37, 0x70, 0x9d, 0xd7, 0x13, 0xf0, 0xf8, 0x2a, 0x5d, 0xab, 0x6c, 0xac, 0xdd, 0xe0, - 0x08, 0xb1, 0x71, 0x30, 0x09, 0x21, 0xae, 0xa7, 0x48, 0x48, 0x82, 0x29, 0x37, 0x71, 0x89, 0x6a, 0x56, 0x8e, 0x79, - 0x45, 0x92, 0x01, 0x6f, 0x34, 0x94, 0x17, 0x7a, 0xa1, 0x49, 0x62, 0x82, 0xf0, 0x55, 0x79, 0xb6, 0x6c, 0xbb, 0xb7, - 0x92, 0xd4, 0xa7, 0x0a, 0xae, 0xea, 0xee, 0xdc, 0x86, 0x94, 0x48, 0x79, 0x0a, 0x65, 0x30, 0x43, 0xf8, 0x19, 0x39, - 0x0c, 0x06, 0x61, 0xff, 0x2f, 0x43, 0xd4, 0x0f, 0xc2, 0x3f, 0xa3, 0x43, 0xcd, 0x39, 0xae, 0x50, 0x37, 0xd5, 0x73, - 0x2c, 0x55, 0xfc, 0xb2, 0x8d, 0x95, 0x27, 0x31, 0xca, 0x70, 0x16, 0xcf, 0x68, 0xf4, 0x0c, 0x0e, 0xb9, 0x25, 0x9c, - 0xb7, 0x12, 0x03, 0x25, 0x45, 0xcf, 0x0c, 0x2f, 0x09, 0xfd, 0xfe, 0x2b, 0x59, 0x3e, 0xf5, 0xfd, 0xfe, 0xf3, 0xea, - 0xe9, 0x2f, 0x7e, 0xff, 0x17, 0x19, 0xfd, 0x5c, 0x18, 0x6f, 0x77, 0x6d, 0x8e, 0xc7, 0x76, 0x8e, 0x42, 0x6f, 0x8d, - 0x83, 0xbb, 0x05, 0xda, 0x74, 0x74, 0x4c, 0x50, 0xc1, 0xc6, 0x25, 0x33, 0xca, 0x43, 0x19, 0x4f, 0x00, 0xa9, 0xce, - 0x1e, 0xe4, 0x6e, 0x5c, 0xbf, 0x5a, 0x31, 0x90, 0x8a, 0xa5, 0x57, 0x40, 0xe6, 0xa4, 0xd7, 0x42, 0xcb, 0x5a, 0x5b, - 0xa5, 0x33, 0xd5, 0xe3, 0xe8, 0x25, 0x9f, 0xbe, 0x22, 0xad, 0xee, 0xd5, 0xf1, 0xa4, 0x7b, 0xd5, 0x68, 0xa0, 0xdc, - 0x92, 0xd6, 0x62, 0x70, 0x35, 0xc4, 0x5f, 0x83, 0x53, 0xcf, 0xa5, 0x25, 0x5c, 0x5b, 0x5e, 0xc7, 0x2c, 0xaf, 0xd1, - 0xc8, 0x0a, 0xd4, 0x75, 0xba, 0x4e, 0x74, 0xd7, 0xa2, 0xd0, 0x38, 0x59, 0x27, 0xb5, 0xa7, 0x48, 0x95, 0x40, 0x32, - 0x14, 0x21, 0xe4, 0x46, 0xa2, 0xad, 0xa3, 0xc2, 0x98, 0xd0, 0x5d, 0x9d, 0x59, 0x60, 0x9f, 0x5a, 0x4a, 0x04, 0x80, - 0x05, 0xe8, 0x5a, 0x7a, 0x82, 0x67, 0x78, 0xd1, 0x68, 0x2b, 0x32, 0x6f, 0xb6, 0xbb, 0xf5, 0xb1, 0x9e, 0x54, 0x63, - 0xe1, 0x45, 0x83, 0xcc, 0x4a, 0x2c, 0x15, 0x59, 0xa3, 0x51, 0xd4, 0x83, 0x9d, 0xf6, 0xe4, 0xd6, 0x02, 0x10, 0x37, - 0xeb, 0x49, 0x19, 0x56, 0xc2, 0x56, 0x32, 0x95, 0x85, 0x2c, 0xcb, 0xa8, 0x00, 0x29, 0x4a, 0x24, 0x66, 0x45, 0x51, - 0x49, 0x76, 0x10, 0xa3, 0x98, 0x12, 0x01, 0x9c, 0x47, 0xd9, 0x5d, 0x38, 0xc3, 0x1c, 0x4f, 0x15, 0xdf, 0x20, 0x84, - 0x9c, 0xd9, 0x74, 0x16, 0xa9, 0x78, 0x50, 0x4a, 0x98, 0x23, 0x93, 0x72, 0x42, 0xc3, 0xf3, 0xfd, 0x53, 0x7e, 0xa7, - 0x4d, 0x36, 0x60, 0xc3, 0x48, 0x35, 0x4b, 0x0d, 0xe7, 0x8a, 0xc9, 0x87, 0x40, 0xa2, 0x32, 0x3a, 0x12, 0x2a, 0x06, - 0xf8, 0x9c, 0x09, 0xaa, 0x74, 0xf0, 0x7d, 0x6b, 0xf7, 0xa5, 0x75, 0x05, 0x32, 0x75, 0xbd, 0x37, 0x80, 0xc8, 0x18, - 0x9c, 0x3b, 0x19, 0xd9, 0x68, 0x76, 0xbe, 0x7f, 0xf2, 0x76, 0x9b, 0x0d, 0xbc, 0x5a, 0x19, 0xeb, 0x57, 0xe9, 0x36, - 0x38, 0xae, 0x20, 0x4d, 0xcd, 0x8f, 0x28, 0x48, 0x95, 0x8a, 0x14, 0x07, 0x02, 0xa8, 0xe8, 0x7c, 0xff, 0xe4, 0x7d, - 0x20, 0x94, 0x6f, 0x09, 0x61, 0x77, 0xd9, 0x01, 0x27, 0xc1, 0x94, 0x50, 0xa4, 0xd7, 0x5e, 0xb2, 0x2e, 0xee, 0x08, - 0xf0, 0x68, 0xaa, 0x2a, 0xc1, 0x82, 0x18, 0xb0, 0x21, 0x49, 0x0d, 0x06, 0x48, 0x8a, 0x70, 0x5a, 0xb3, 0xcb, 0x08, - 0x6c, 0x80, 0x9a, 0xeb, 0x0c, 0x76, 0x22, 0xd4, 0xaa, 0x1f, 0xc2, 0xa9, 0x9a, 0x55, 0x16, 0x5a, 0x78, 0x3c, 0xdb, - 0xc8, 0x4a, 0xab, 0xcc, 0xd1, 0x6f, 0xc1, 0x76, 0xb2, 0x0f, 0x6f, 0x88, 0xb5, 0x24, 0x4c, 0xc1, 0x73, 0x9b, 0x3e, - 0x76, 0xbe, 0x7f, 0xf2, 0xda, 0x64, 0x90, 0xcd, 0x63, 0xcb, 0xef, 0x37, 0x4c, 0xcc, 0x93, 0xd7, 0x61, 0x55, 0xab, - 0x1a, 0x9f, 0xef, 0x9f, 0x7c, 0xd8, 0xd6, 0x0c, 0xca, 0x8b, 0x45, 0x65, 0xe3, 0x2b, 0xf8, 0x96, 0x34, 0x8d, 0x96, - 0x46, 0x38, 0x44, 0xac, 0xc0, 0x4a, 0x20, 0x45, 0x79, 0x51, 0xba, 0x46, 0x9e, 0xe3, 0x8c, 0xa8, 0x30, 0x50, 0x7d, - 0xd7, 0x8c, 0x9a, 0xc7, 0x78, 0x76, 0x36, 0xe2, 0x73, 0xba, 0x23, 0x36, 0x74, 0x83, 0x42, 0x36, 0x83, 0xd4, 0x19, - 0x05, 0x3a, 0xc3, 0x7b, 0x2d, 0xd4, 0xad, 0x8b, 0xaf, 0x4c, 0x11, 0x29, 0xaf, 0xc9, 0x16, 0x3c, 0x25, 0x2d, 0x9c, - 0x92, 0x16, 0x8e, 0x49, 0x3e, 0x68, 0x69, 0x01, 0xd1, 0x8d, 0xcb, 0x71, 0xb5, 0x98, 0x81, 0xac, 0x30, 0x73, 0x5a, - 0xb5, 0x00, 0x4e, 0xba, 0xb1, 0xf2, 0x3d, 0x2a, 0x99, 0x9e, 0x28, 0xb2, 0x78, 0x1f, 0x70, 0xcc, 0xd5, 0xc0, 0x67, - 0xec, 0x32, 0x85, 0xc4, 0x12, 0x58, 0x15, 0x96, 0x28, 0x2a, 0x9b, 0xb6, 0x4d, 0xd3, 0x38, 0x54, 0xfb, 0xc4, 0x71, - 0x1c, 0x02, 0xe7, 0xc6, 0xb1, 0xc9, 0xc3, 0xc9, 0x37, 0xbb, 0x3c, 0x3e, 0x38, 0x08, 0x74, 0xa7, 0x2f, 0x65, 0xc0, - 0x6d, 0x7d, 0x15, 0xb9, 0xfb, 0x56, 0xf3, 0x8a, 0x04, 0x29, 0xf8, 0x1b, 0x8d, 0x74, 0x58, 0x40, 0x18, 0x3a, 0x88, - 0xeb, 0x18, 0xb4, 0xc0, 0x2b, 0x5d, 0xaf, 0xbe, 0xfc, 0x46, 0xa3, 0x8c, 0xd2, 0xd6, 0xb1, 0x75, 0x83, 0xb3, 0xe2, - 0x2a, 0x28, 0x53, 0x7f, 0x5a, 0x1b, 0xf9, 0x52, 0x16, 0x04, 0xc4, 0x5c, 0x9a, 0x65, 0x76, 0x31, 0xce, 0x91, 0x60, - 0xd0, 0xee, 0x4b, 0x93, 0xb5, 0x80, 0x55, 0x76, 0x95, 0x69, 0x64, 0xd9, 0x59, 0x07, 0x45, 0xb6, 0x11, 0x44, 0xa5, - 0xa0, 0x51, 0xa3, 0x30, 0xe4, 0xfd, 0x7e, 0x33, 0xe7, 0x12, 0xe7, 0xc8, 0x38, 0xb9, 0x14, 0x14, 0x0a, 0x59, 0x9d, - 0x12, 0x29, 0x2f, 0xc9, 0x7c, 0x37, 0xc9, 0x9f, 0x38, 0x24, 0xff, 0x8c, 0x50, 0x87, 0xfc, 0xb5, 0x8b, 0x23, 0xe4, - 0xc6, 0xb9, 0x90, 0xdb, 0xaa, 0xd3, 0x39, 0x01, 0x27, 0x5a, 0x1d, 0xa3, 0xb5, 0xb0, 0xe2, 0x0e, 0x86, 0xe2, 0x9e, - 0x10, 0xe5, 0x86, 0xc4, 0x36, 0x06, 0x1c, 0x54, 0x41, 0x35, 0x98, 0x7a, 0x9b, 0x4f, 0xcf, 0xe5, 0x80, 0x27, 0x1f, - 0xee, 0x8e, 0x87, 0x9e, 0xce, 0x37, 0x4f, 0xae, 0x93, 0xfb, 0x09, 0xab, 0x76, 0x0e, 0x6e, 0x3d, 0x13, 0x14, 0xe6, - 0x2f, 0xe3, 0xd8, 0x75, 0xe6, 0xb3, 0x76, 0x08, 0xad, 0xfc, 0x03, 0x68, 0xdb, 0x6d, 0xd5, 0x82, 0x3a, 0xc3, 0x02, - 0x3f, 0xd2, 0x19, 0xa8, 0xb1, 0xd8, 0xc1, 0x3e, 0x4e, 0x54, 0x03, 0x9a, 0x25, 0xdb, 0xab, 0x9f, 0x15, 0x86, 0x4c, - 0x34, 0x68, 0x68, 0x09, 0xfc, 0x4f, 0x93, 0x3c, 0xd0, 0x8d, 0x92, 0x0b, 0x80, 0xa0, 0xb9, 0xc2, 0x53, 0x85, 0x30, - 0xdf, 0xaf, 0xbc, 0xef, 0x2f, 0xf7, 0x08, 0x99, 0x57, 0xde, 0xc7, 0x77, 0x55, 0xea, 0x15, 0x90, 0x05, 0x8a, 0xc0, - 0x7c, 0x2c, 0x0b, 0x74, 0xf8, 0xf2, 0xcc, 0x36, 0x57, 0x26, 0x64, 0x58, 0x69, 0xdc, 0x4e, 0x68, 0x53, 0xb9, 0xe5, - 0x74, 0xbd, 0x45, 0xc3, 0x5a, 0xed, 0x3e, 0xd4, 0xbe, 0x97, 0x0a, 0x46, 0x78, 0x7e, 0xaf, 0x5a, 0xdb, 0x71, 0x8b, - 0x8f, 0xeb, 0xf9, 0x2b, 0x6b, 0x9b, 0x12, 0xb2, 0x2c, 0xa7, 0x42, 0x3e, 0xa3, 0x63, 0x2e, 0x20, 0x66, 0x51, 0xe2, - 0x04, 0x15, 0xfb, 0x8e, 0xdf, 0x4e, 0xad, 0xcf, 0x09, 0x14, 0xac, 0x2d, 0x50, 0xfd, 0xfa, 0xa8, 0x82, 0xd6, 0xe7, - 0xeb, 0xbd, 0xe6, 0x07, 0x07, 0x1f, 0x2a, 0x34, 0x19, 0x28, 0x15, 0x14, 0x0e, 0xd3, 0xd2, 0x2a, 0x8d, 0x89, 0xe4, - 0xee, 0x07, 0xa5, 0x13, 0xc0, 0x32, 0x0c, 0x97, 0xf7, 0xbc, 0x24, 0xb2, 0x98, 0xac, 0xb3, 0x78, 0xe3, 0x9c, 0x60, - 0xae, 0xe1, 0x02, 0x1c, 0x1e, 0x4c, 0x6d, 0xed, 0x2d, 0xca, 0xab, 0x64, 0xd8, 0x12, 0x86, 0x53, 0x40, 0x56, 0xa0, - 0xcc, 0x10, 0x87, 0x02, 0xb7, 0x9a, 0x25, 0xa7, 0xa0, 0x57, 0x4e, 0x71, 0x1e, 0x4e, 0x21, 0xfd, 0xb5, 0x76, 0x64, - 0x11, 0xc2, 0x3a, 0x31, 0xc7, 0x49, 0x25, 0x38, 0x79, 0xb9, 0xcd, 0xa5, 0x6c, 0x89, 0x9a, 0x2a, 0xa9, 0xa3, 0x5a, - 0xa0, 0xb2, 0x43, 0x78, 0x15, 0x30, 0xa3, 0xb8, 0xd9, 0xb8, 0x19, 0x30, 0xe0, 0x67, 0x32, 0xd0, 0xc1, 0x28, 0x90, - 0x19, 0x3c, 0x5c, 0x04, 0xb5, 0xa9, 0xbb, 0x5c, 0x75, 0xc3, 0x06, 0x71, 0x53, 0x17, 0x4d, 0x5c, 0xc5, 0xf5, 0x4e, - 0x2b, 0x5e, 0x3a, 0xd6, 0x19, 0xd4, 0xd2, 0x72, 0xc1, 0x2a, 0x91, 0xc4, 0x59, 0xfe, 0x58, 0x27, 0x45, 0x97, 0x8d, - 0x30, 0x55, 0x60, 0xbc, 0x54, 0x7b, 0x40, 0x0b, 0xa0, 0xaf, 0xe5, 0x89, 0x74, 0x76, 0xd4, 0x3a, 0xb1, 0xd5, 0x9c, - 0x8e, 0xd4, 0x7f, 0x07, 0xa9, 0x2e, 0xeb, 0x67, 0xfe, 0xa5, 0x92, 0x85, 0x0c, 0xe7, 0x35, 0xc6, 0x9e, 0x29, 0xc6, - 0x8e, 0x40, 0x4f, 0xb3, 0x89, 0xdf, 0x7d, 0x93, 0xf1, 0xc2, 0x8c, 0x94, 0x33, 0x24, 0xf6, 0x75, 0x19, 0x2d, 0x77, - 0x7e, 0xaf, 0xed, 0x46, 0xc4, 0x08, 0x64, 0x01, 0x61, 0xc3, 0xd9, 0x33, 0x84, 0xf3, 0x46, 0xa3, 0x9b, 0x1f, 0xd3, - 0xca, 0x49, 0x52, 0xc1, 0xc8, 0x20, 0xa0, 0x0b, 0x04, 0x5f, 0x93, 0xa1, 0x10, 0xf2, 0xb7, 0x99, 0xd9, 0x39, 0xf8, - 0xda, 0x4f, 0xde, 0x05, 0x2e, 0x57, 0x73, 0xdb, 0x96, 0x41, 0x53, 0x58, 0x4f, 0x50, 0x05, 0x5c, 0xbe, 0xbe, 0x3b, - 0xc1, 0x03, 0xe0, 0xde, 0x6b, 0x63, 0x48, 0x45, 0x43, 0x5d, 0xa9, 0x59, 0x42, 0x79, 0xfa, 0xba, 0xa8, 0xca, 0x4a, - 0x74, 0x27, 0xeb, 0xca, 0xca, 0x98, 0x95, 0x24, 0x2f, 0x8a, 0x9c, 0x56, 0xe1, 0xfd, 0xb5, 0xf4, 0x4b, 0x25, 0x5c, - 0x36, 0xbd, 0xed, 0xa7, 0x73, 0x22, 0xb1, 0x43, 0xa8, 0x5f, 0xef, 0x8a, 0x7d, 0x54, 0x60, 0xc2, 0xb9, 0x36, 0x42, - 0xf1, 0xe7, 0x6d, 0x42, 0x11, 0x67, 0xe6, 0xc8, 0x2b, 0x81, 0xd8, 0xbe, 0x87, 0x40, 0x34, 0x6e, 0x76, 0x2b, 0x13, - 0x41, 0x1d, 0xa9, 0xc9, 0xc4, 0xfa, 0x96, 0x92, 0x0c, 0x33, 0xb3, 0x1b, 0xbd, 0xce, 0x6a, 0xc5, 0x06, 0x2d, 0x70, - 0x23, 0xf9, 0x3e, 0xfc, 0x6c, 0xeb, 0x9f, 0x0e, 0x27, 0xd6, 0x6e, 0xe0, 0x80, 0x95, 0x26, 0x0b, 0x0a, 0x21, 0xc1, - 0x39, 0x50, 0x49, 0x59, 0x8a, 0xa6, 0x0d, 0x05, 0x19, 0x02, 0x27, 0xac, 0x0c, 0x33, 0x01, 0xc4, 0x4a, 0x56, 0x18, - 0x03, 0x32, 0xd8, 0x9a, 0xfb, 0x67, 0xcd, 0xcb, 0x4f, 0x6b, 0xa2, 0x35, 0xb9, 0xa2, 0xd5, 0x87, 0x5a, 0xbe, 0x81, - 0x81, 0xc0, 0xe8, 0x87, 0x7b, 0xca, 0x04, 0xad, 0x44, 0x39, 0x72, 0xe5, 0x10, 0x6e, 0x81, 0x13, 0x6d, 0xef, 0x83, - 0x8e, 0xf0, 0x6e, 0x91, 0x26, 0x98, 0x3b, 0x74, 0xfd, 0x92, 0xc8, 0x1a, 0x2b, 0x99, 0x12, 0x63, 0x29, 0xe1, 0x58, - 0x91, 0xa9, 0x24, 0xd9, 0xa0, 0x35, 0x04, 0x05, 0xb4, 0x9b, 0x1e, 0x67, 0x95, 0x09, 0x9c, 0x36, 0x1a, 0x28, 0xb6, - 0xb3, 0x4e, 0x07, 0xac, 0x91, 0x0e, 0x31, 0xc5, 0xa9, 0x36, 0x4c, 0xce, 0x0e, 0x0e, 0x82, 0xb8, 0x9a, 0x77, 0x90, - 0x0e, 0x11, 0xe6, 0xab, 0x55, 0xa0, 0xc0, 0x8a, 0xd1, 0x6a, 0x15, 0xbb, 0x60, 0xa9, 0x6a, 0xe8, 0x36, 0xef, 0x4b, - 0x32, 0x57, 0x02, 0x70, 0x0e, 0x10, 0x36, 0x48, 0x10, 0x1b, 0xf7, 0x5e, 0x0c, 0xee, 0xa8, 0x46, 0x36, 0x48, 0x1b, - 0xed, 0xa1, 0xc3, 0xb8, 0x06, 0xe9, 0x90, 0xc4, 0x05, 0x3f, 0x38, 0xd8, 0xcb, 0x8d, 0x88, 0xfc, 0x09, 0x44, 0xd9, - 0x4f, 0x4a, 0xb2, 0xe8, 0x01, 0xdd, 0xdd, 0x58, 0x77, 0x06, 0x94, 0x14, 0x65, 0xb6, 0xd5, 0xb6, 0xab, 0x65, 0x41, - 0x94, 0x8d, 0xb0, 0x09, 0x06, 0xf7, 0xc1, 0xb2, 0x2f, 0xc9, 0xfc, 0x95, 0x2c, 0x73, 0xac, 0x7f, 0xde, 0x9a, 0x59, - 0x1d, 0x86, 0x61, 0x2c, 0x26, 0x2a, 0x96, 0x61, 0xc3, 0xb0, 0x8a, 0xf8, 0x8f, 0x0c, 0x98, 0xce, 0xc4, 0x83, 0x72, - 0xae, 0x21, 0xd1, 0xe0, 0x5b, 0xd5, 0xc6, 0xde, 0x25, 0xf9, 0x69, 0xab, 0x97, 0x41, 0x43, 0xf2, 0xfc, 0xb7, 0x42, - 0xf2, 0xd0, 0x40, 0xa2, 0xc9, 0x63, 0x0d, 0x67, 0x3b, 0x70, 0xf1, 0x93, 0x5c, 0xc3, 0xd9, 0x6e, 0xdc, 0x5a, 0x4c, - 0xfd, 0xb2, 0x0b, 0x3e, 0x87, 0x37, 0x68, 0x40, 0xab, 0x02, 0x07, 0xca, 0x47, 0xeb, 0xba, 0x97, 0x66, 0xa5, 0x20, - 0x4c, 0x25, 0x09, 0x58, 0xfd, 0x00, 0x54, 0xda, 0xa8, 0x63, 0xf8, 0xb2, 0x68, 0x8e, 0x1c, 0x97, 0x40, 0x3d, 0x75, - 0x05, 0xc8, 0xc9, 0x78, 0xdb, 0xe7, 0x07, 0x07, 0x60, 0x1b, 0x80, 0x12, 0x17, 0x8e, 0xe2, 0xb9, 0x5c, 0x08, 0x50, - 0xa5, 0x72, 0xfb, 0x1b, 0x8a, 0xe1, 0x16, 0x88, 0x2a, 0x83, 0x1f, 0x50, 0x30, 0x8f, 0xf3, 0x9c, 0x5d, 0xe9, 0x32, - 0xf3, 0x1b, 0x73, 0x62, 0x49, 0x39, 0xd7, 0x3a, 0x61, 0x86, 0xba, 0x99, 0xa1, 0xd3, 0x3a, 0xda, 0x5e, 0x5c, 0xd1, - 0x4c, 0xbe, 0x62, 0xb9, 0xa4, 0x19, 0x2c, 0xbf, 0xa2, 0x38, 0x58, 0x51, 0x8e, 0xe0, 0xc0, 0xd6, 0x7a, 0xc5, 0x49, - 0x72, 0x67, 0x17, 0x59, 0xd7, 0x81, 0xa6, 0x71, 0x96, 0xa4, 0x7a, 0x12, 0x37, 0x9f, 0xd1, 0xe6, 0x70, 0x96, 0x2d, - 0xdd, 0x7c, 0x9a, 0x4a, 0xd9, 0x50, 0xdc, 0x3d, 0x60, 0xc4, 0x4a, 0x02, 0x2b, 0x3d, 0xef, 0xd4, 0x5a, 0x20, 0xe2, - 0xbd, 0x63, 0x13, 0xdc, 0x95, 0x60, 0xe9, 0x70, 0xd4, 0xb0, 0x0e, 0xa7, 0xa5, 0x9b, 0x2f, 0xb7, 0x5e, 0x69, 0xdb, - 0x26, 0x1c, 0x14, 0x9d, 0x3c, 0xde, 0x6d, 0x59, 0xbd, 0xb6, 0x92, 0xc3, 0x4a, 0x0b, 0x76, 0x5f, 0xc6, 0x8c, 0x96, - 0x96, 0xbc, 0x90, 0x3d, 0x8a, 0xfb, 0x92, 0x3c, 0x87, 0x3b, 0x43, 0x2f, 0xe5, 0x2c, 0x5d, 0xbb, 0x1a, 0xd3, 0xdd, - 0x2f, 0xb5, 0xff, 0x7d, 0x19, 0xbc, 0xc4, 0xef, 0x21, 0xb0, 0xfb, 0x55, 0xd5, 0x7c, 0x33, 0xa0, 0xfb, 0x55, 0x85, - 0xa0, 0xaf, 0xa2, 0x8d, 0x76, 0x4e, 0x20, 0xb7, 0x13, 0x3e, 0x0d, 0x5b, 0xbe, 0xd5, 0x96, 0x7e, 0xd6, 0x61, 0x24, - 0x9d, 0x69, 0xa9, 0xce, 0x03, 0xae, 0xf2, 0xd4, 0x20, 0x5f, 0xae, 0x6e, 0x21, 0x51, 0x93, 0x61, 0xa8, 0x75, 0xf8, - 0x5d, 0xdb, 0x63, 0x64, 0x4c, 0xa6, 0xed, 0x8c, 0xaf, 0x63, 0x21, 0xf7, 0xe1, 0x94, 0xf1, 0x8d, 0x7b, 0x78, 0x53, - 0x02, 0x1e, 0xb4, 0xfb, 0x4d, 0xe1, 0x18, 0xdb, 0xb9, 0xbe, 0x07, 0xe4, 0x8e, 0x4f, 0xb8, 0xd5, 0xdd, 0xea, 0x56, - 0xc6, 0xd7, 0x60, 0xff, 0x23, 0x3c, 0xb5, 0x97, 0xe3, 0xa8, 0xe1, 0xc0, 0x34, 0x5a, 0x16, 0xa5, 0x53, 0x80, 0x6b, - 0xe5, 0x4d, 0x20, 0xcc, 0x0b, 0x15, 0xe0, 0xfe, 0x01, 0x7f, 0x63, 0x58, 0xe2, 0xb8, 0xe4, 0x38, 0x27, 0xf7, 0xe5, - 0x88, 0x1a, 0xfc, 0x32, 0x7e, 0x0f, 0x74, 0xac, 0x28, 0xb4, 0xb0, 0x54, 0xf4, 0x9c, 0x9b, 0x85, 0xec, 0x4c, 0x4b, - 0xc5, 0xb4, 0x4c, 0xa9, 0x51, 0xd3, 0x6c, 0xc9, 0xe3, 0xb4, 0x56, 0xb6, 0x2c, 0x4f, 0x55, 0x6d, 0x5e, 0xb4, 0x03, - 0x8b, 0x55, 0x68, 0x71, 0xb5, 0x0a, 0xea, 0xa8, 0x26, 0xcc, 0x89, 0x64, 0x20, 0xcc, 0x9c, 0x8c, 0x8a, 0x9a, 0x66, - 0xad, 0xfb, 0x04, 0x68, 0x3d, 0xa1, 0xc8, 0xea, 0xe6, 0x35, 0x38, 0x5c, 0x17, 0x82, 0xee, 0xee, 0xfa, 0x14, 0xb0, - 0x5e, 0x5d, 0x39, 0x91, 0x83, 0xa1, 0x9f, 0xcb, 0x54, 0xd9, 0x2a, 0xa7, 0x75, 0x0b, 0x7e, 0xd1, 0x1d, 0xc9, 0xb2, - 0x06, 0x75, 0x9b, 0xf5, 0x4e, 0xb2, 0xd1, 0x73, 0xbe, 0x2b, 0xd9, 0xa8, 0xa6, 0xed, 0xee, 0xb5, 0xd0, 0xdd, 0x69, - 0xa9, 0x7a, 0xae, 0xed, 0x4d, 0x7e, 0xc3, 0x74, 0x6d, 0xa0, 0x4d, 0x8d, 0x66, 0xcb, 0x55, 0xce, 0x8a, 0x62, 0x5c, - 0x5e, 0x26, 0x50, 0xb9, 0x3b, 0x63, 0x4d, 0xff, 0xc6, 0x6a, 0x54, 0xd7, 0x71, 0x83, 0x1f, 0xc8, 0x24, 0xe5, 0x97, - 0x71, 0xfa, 0x1e, 0xe6, 0xab, 0x2a, 0x5f, 0xde, 0x26, 0x22, 0x96, 0xd4, 0x70, 0x97, 0x0a, 0x86, 0x1f, 0x1c, 0x18, - 0x7e, 0xd0, 0x7c, 0xba, 0xea, 0x8f, 0x97, 0xaf, 0xca, 0x01, 0xa2, 0x71, 0x61, 0x59, 0xc6, 0xb9, 0xdc, 0x3e, 0xc7, - 0x3a, 0x0b, 0x3b, 0x2f, 0x59, 0xd8, 0xb9, 0x0c, 0xd6, 0x87, 0x0a, 0x82, 0x6f, 0xb6, 0x8f, 0xb2, 0xc9, 0xd9, 0xbe, - 0xa9, 0x0e, 0xfe, 0x37, 0xd1, 0x9d, 0x7d, 0x1c, 0x2e, 0x77, 0x14, 0x1e, 0xa9, 0x74, 0x15, 0x0d, 0xf2, 0x3b, 0x48, - 0x3b, 0x90, 0xa4, 0xe7, 0xdc, 0x39, 0xa8, 0xe4, 0x94, 0x4d, 0x04, 0x0a, 0x46, 0x8b, 0x5c, 0xf2, 0x99, 0x19, 0x33, - 0x37, 0xd7, 0x8c, 0x54, 0x25, 0xb8, 0xa2, 0x55, 0xb4, 0x3d, 0xaa, 0x5f, 0xe4, 0x5a, 0x7e, 0x64, 0x59, 0x12, 0xe5, - 0xd8, 0x48, 0x91, 0x3c, 0xca, 0x0a, 0x62, 0x93, 0x8d, 0x37, 0xeb, 0xf0, 0x98, 0x65, 0x2c, 0x9f, 0x52, 0x11, 0x70, - 0xb4, 0xdc, 0x35, 0x19, 0x87, 0x80, 0x8c, 0x9e, 0x0c, 0x7f, 0x5b, 0x5d, 0xf8, 0x0b, 0x61, 0x34, 0xf0, 0x03, 0xcd, - 0xa8, 0x9c, 0xf2, 0x04, 0x12, 0x53, 0xc2, 0xa4, 0xbc, 0xd1, 0x74, 0x70, 0xb0, 0x17, 0xf8, 0xca, 0x2d, 0x01, 0x57, - 0xbf, 0xdd, 0x1a, 0xd4, 0x5f, 0xc2, 0xf5, 0x9c, 0x6a, 0x6a, 0x8a, 0x96, 0x74, 0xfd, 0x26, 0x8b, 0x0c, 0x3f, 0xd2, - 0x5b, 0x2c, 0x50, 0x51, 0x44, 0x1a, 0x6a, 0x7f, 0xcc, 0x68, 0x9a, 0xf8, 0xf8, 0x23, 0xbd, 0x8d, 0xca, 0xdb, 0xe2, - 0xea, 0x72, 0xb3, 0xda, 0x40, 0x9f, 0x5f, 0x67, 0x3e, 0xae, 0x26, 0x89, 0x96, 0x05, 0xe6, 0x82, 0x4d, 0x80, 0x38, - 0xff, 0x46, 0x6f, 0x23, 0x3d, 0x1e, 0x73, 0x2e, 0xeb, 0xa1, 0xa5, 0x45, 0x7d, 0xe8, 0x14, 0xbb, 0xdb, 0x60, 0x0c, - 0x8a, 0x81, 0xea, 0x3b, 0x24, 0xb5, 0x76, 0x95, 0x79, 0x88, 0x50, 0x71, 0xdf, 0xa5, 0xe0, 0x2f, 0x5c, 0xd1, 0x26, - 0x6b, 0xa9, 0xaf, 0x6b, 0x9d, 0x28, 0x74, 0xa8, 0x72, 0x3d, 0xce, 0x03, 0x61, 0x4f, 0x9d, 0xb9, 0x83, 0xe0, 0x38, - 0xc2, 0xbe, 0x90, 0x66, 0xd0, 0xe8, 0x5b, 0x9d, 0x12, 0x52, 0x45, 0x92, 0x5e, 0x57, 0xfd, 0xbc, 0xf3, 0x00, 0xf0, - 0x0e, 0x29, 0x2d, 0xb1, 0xba, 0x8e, 0x59, 0xd8, 0x74, 0xd1, 0xef, 0x24, 0x09, 0x96, 0x76, 0x09, 0x91, 0x70, 0xb1, - 0x28, 0x0b, 0xa0, 0x42, 0x43, 0x5f, 0x3a, 0x03, 0x90, 0x8d, 0x03, 0xb6, 0x21, 0x35, 0x33, 0x25, 0x35, 0x43, 0x07, - 0xe3, 0x3b, 0xa4, 0x24, 0x55, 0xc8, 0x50, 0x4a, 0xa4, 0x12, 0x7a, 0x66, 0x73, 0x0d, 0x09, 0xb9, 0x1b, 0x5a, 0x5e, - 0x9f, 0xd3, 0x7b, 0x9e, 0xd5, 0xc0, 0x0a, 0xd4, 0x38, 0xa8, 0x88, 0x60, 0x49, 0x54, 0x37, 0x28, 0xac, 0x3b, 0x47, - 0xd8, 0xfc, 0xd6, 0x80, 0x87, 0x76, 0x59, 0xc4, 0xa2, 0x24, 0x98, 0xa2, 0xa5, 0x08, 0xa6, 0x38, 0x83, 0x7c, 0x44, - 0x5e, 0x94, 0xf0, 0x53, 0x77, 0x37, 0x6a, 0xd9, 0xca, 0xdb, 0xaf, 0xf8, 0x81, 0x32, 0x2f, 0x21, 0x47, 0x13, 0x0b, - 0xcb, 0x53, 0x44, 0xa0, 0xee, 0xda, 0x39, 0xdb, 0xf6, 0x95, 0x49, 0xd1, 0x31, 0x80, 0x7d, 0x27, 0x83, 0xa5, 0xb3, - 0x0a, 0xf7, 0x2e, 0xb7, 0xb9, 0xf2, 0x67, 0x82, 0x7d, 0x55, 0x12, 0x69, 0x90, 0x93, 0x35, 0x89, 0x73, 0x77, 0xae, - 0xe5, 0xcf, 0x0b, 0x2a, 0x6e, 0xcf, 0x28, 0xe4, 0x3a, 0x73, 0xb8, 0xeb, 0x5b, 0x6d, 0x43, 0x95, 0xa7, 0xde, 0xcf, - 0x94, 0xb2, 0x52, 0xd4, 0x2f, 0x01, 0xae, 0x5f, 0x11, 0x2c, 0x54, 0xb4, 0xd1, 0x71, 0xc4, 0xe8, 0xd3, 0x42, 0x77, - 0x5e, 0x9e, 0xa4, 0x5d, 0x06, 0xfe, 0xb5, 0x0a, 0xd3, 0x26, 0x58, 0x80, 0xb9, 0x7b, 0x21, 0x75, 0x90, 0x0f, 0xd7, - 0xbd, 0x32, 0x50, 0x04, 0xe1, 0xbb, 0x6c, 0xf7, 0x52, 0xb7, 0x65, 0xcd, 0xee, 0x5e, 0x6a, 0x2d, 0xe8, 0xa7, 0x52, - 0x7e, 0xb0, 0x99, 0xa7, 0xbc, 0xbc, 0xcc, 0x8a, 0x02, 0x15, 0x00, 0xde, 0xf7, 0xdd, 0x20, 0xf8, 0xde, 0x24, 0x0d, - 0x86, 0x10, 0x8b, 0x3d, 0x4b, 0xb9, 0x65, 0xe2, 0xd5, 0xfc, 0xdf, 0x6f, 0xcc, 0xff, 0xbd, 0x73, 0xe5, 0x14, 0x4c, - 0xa3, 0x49, 0x46, 0x13, 0xcb, 0x3a, 0x91, 0x26, 0x40, 0xa5, 0xb7, 0xe5, 0x92, 0x7c, 0xbc, 0x88, 0x40, 0xe3, 0x5a, - 0x8e, 0x79, 0x26, 0x9b, 0xe3, 0x78, 0xc6, 0xd2, 0xdb, 0x68, 0xc1, 0x9a, 0x33, 0x9e, 0xf1, 0x7c, 0x1e, 0x8f, 0x28, - 0xce, 0x6f, 0x73, 0x49, 0x67, 0xcd, 0x05, 0xc3, 0x2f, 0x69, 0x7a, 0x45, 0x25, 0x1b, 0xc5, 0xd8, 0x3f, 0x11, 0x2c, - 0x4e, 0xbd, 0x37, 0xb1, 0x10, 0xfc, 0xda, 0xc7, 0xef, 0xf8, 0x25, 0x97, 0x1c, 0xbf, 0xbd, 0xb9, 0x9d, 0xd0, 0x0c, - 0x7f, 0xb8, 0x5c, 0x64, 0x72, 0x81, 0xf3, 0x38, 0xcb, 0x9b, 0x39, 0x15, 0x6c, 0xdc, 0x1d, 0xf1, 0x94, 0x8b, 0x26, - 0xa4, 0x6c, 0xcf, 0x68, 0x94, 0xb2, 0xc9, 0x54, 0x7a, 0x49, 0x2c, 0x3e, 0x76, 0x9b, 0xcd, 0xb9, 0x60, 0xb3, 0x58, - 0xdc, 0x36, 0x55, 0x8b, 0xe8, 0xb3, 0xd6, 0x51, 0xfc, 0xf9, 0xf8, 0x61, 0x57, 0x8a, 0x38, 0xcb, 0x19, 0x6c, 0x53, - 0x14, 0xa7, 0xa9, 0x77, 0xf4, 0xa8, 0x35, 0xcb, 0xf7, 0x74, 0x20, 0x2f, 0xce, 0x64, 0x71, 0x81, 0x3f, 0x02, 0xdc, - 0xe1, 0xa5, 0xcc, 0xf0, 0xe5, 0x42, 0x4a, 0x9e, 0x2d, 0x47, 0x0b, 0x91, 0x73, 0x11, 0xcd, 0x39, 0xcb, 0x24, 0x15, - 0xdd, 0x4b, 0x2e, 0x12, 0x2a, 0x9a, 0x22, 0x4e, 0xd8, 0x22, 0x8f, 0x1e, 0xce, 0x6f, 0xba, 0xa0, 0x59, 0x4c, 0x04, - 0x5f, 0x64, 0x89, 0x99, 0x8b, 0x65, 0x53, 0x2a, 0x98, 0x74, 0x2b, 0xd4, 0x2b, 0x4c, 0xa2, 0x94, 0x65, 0x34, 0x16, - 0xcd, 0x09, 0x74, 0x06, 0xb3, 0xa8, 0x95, 0xd0, 0x09, 0x16, 0x93, 0xcb, 0x38, 0x68, 0x77, 0x9e, 0x60, 0xfb, 0x37, - 0x7c, 0x84, 0xbc, 0xd6, 0xf6, 0xe2, 0x76, 0xab, 0xf5, 0x27, 0xd4, 0x5d, 0x9b, 0x45, 0x01, 0x14, 0xb5, 0xe7, 0x37, - 0x5e, 0xce, 0x21, 0xa7, 0x6d, 0x5b, 0xcf, 0xee, 0x3c, 0x4e, 0x20, 0x21, 0x38, 0xea, 0xcc, 0x6f, 0x0a, 0x58, 0x5d, - 0xa4, 0x93, 0x4c, 0xcd, 0x22, 0xcd, 0xd3, 0xf2, 0xb7, 0x42, 0xfc, 0x74, 0x3b, 0xc4, 0x1d, 0x0b, 0x71, 0x85, 0xf5, - 0x66, 0xb2, 0x10, 0x2a, 0xb6, 0x1a, 0xb5, 0x73, 0x0d, 0xc8, 0x94, 0x5f, 0x51, 0x61, 0xe1, 0x50, 0x0f, 0xbf, 0x19, - 0x8c, 0xce, 0x76, 0x30, 0x9e, 0x7e, 0x0a, 0x0c, 0x91, 0x25, 0xcb, 0xfa, 0xbe, 0xb6, 0x05, 0x9d, 0x75, 0xa7, 0x14, - 0xe8, 0x29, 0xea, 0xc0, 0xef, 0x6b, 0x96, 0xc8, 0xa9, 0xfe, 0xa9, 0xc8, 0xf9, 0x5a, 0xd7, 0x3d, 0x6a, 0xb5, 0xf4, - 0x73, 0xce, 0x7e, 0xa1, 0x51, 0x3b, 0x84, 0x06, 0xc5, 0x05, 0xfe, 0x5b, 0x79, 0x99, 0xb7, 0xce, 0x3d, 0xf1, 0x0f, - 0xee, 0x2d, 0x5f, 0x27, 0x49, 0xb1, 0xba, 0x11, 0x8d, 0x85, 0x95, 0x95, 0x5a, 0xf8, 0x80, 0xdb, 0x4e, 0x9d, 0x27, - 0xc2, 0x7a, 0xe5, 0x2d, 0x4e, 0xd6, 0xff, 0x41, 0xe7, 0x5d, 0x44, 0x10, 0xe9, 0x70, 0x92, 0x0d, 0x79, 0x37, 0xeb, - 0x91, 0x56, 0x37, 0x6b, 0x36, 0x51, 0xc0, 0x89, 0x18, 0x64, 0x26, 0x3d, 0x2f, 0x60, 0x7d, 0xae, 0x8c, 0xed, 0x1c, - 0x45, 0x1c, 0xae, 0x9a, 0xae, 0x56, 0x55, 0x18, 0x80, 0xa9, 0xeb, 0x1a, 0x7f, 0x93, 0xa6, 0x01, 0xce, 0x1d, 0x4e, - 0x9e, 0xd9, 0x17, 0xbb, 0x08, 0xcb, 0x2b, 0x52, 0x3e, 0x52, 0x98, 0x0b, 0xe7, 0xb1, 0x9c, 0x82, 0x97, 0xa2, 0x14, - 0x3f, 0x55, 0x12, 0x93, 0x7f, 0xe8, 0xa3, 0xbe, 0x28, 0x33, 0xdc, 0x20, 0x93, 0x4f, 0x14, 0x30, 0xca, 0x37, 0x92, - 0xc0, 0x88, 0xf8, 0x17, 0xa2, 0x6d, 0x3a, 0x6b, 0xd1, 0x8d, 0xef, 0x6b, 0xd1, 0xd1, 0x4c, 0x32, 0x95, 0xbb, 0x6d, - 0x23, 0x0e, 0xd3, 0x38, 0x3f, 0x1f, 0xe9, 0xbb, 0x92, 0x79, 0x75, 0x33, 0x20, 0x56, 0xd0, 0x6b, 0x23, 0x8d, 0x0a, - 0x65, 0x8f, 0x7e, 0x2f, 0x77, 0xda, 0x27, 0xe2, 0x2e, 0xfb, 0xa4, 0x5c, 0x78, 0xce, 0x17, 0x62, 0x04, 0xe1, 0x48, - 0x23, 0xf5, 0x36, 0x1d, 0x37, 0xbe, 0x52, 0x31, 0x7c, 0x2c, 0x9d, 0x4c, 0x50, 0x89, 0x99, 0xfb, 0x52, 0x09, 0xaa, - 0x42, 0x5e, 0xfa, 0xbe, 0x86, 0x11, 0x71, 0x76, 0x49, 0x20, 0xb3, 0x13, 0x95, 0xd4, 0x18, 0x64, 0xa4, 0x97, 0x85, - 0x8b, 0x8c, 0xfd, 0xbc, 0xa0, 0xe7, 0x0c, 0x74, 0x4d, 0x16, 0xb2, 0x44, 0xc5, 0x9a, 0x40, 0xf6, 0x35, 0xdb, 0x10, - 0xbc, 0x60, 0x89, 0xde, 0x98, 0x4c, 0x55, 0x9a, 0xdc, 0x26, 0xbf, 0xe9, 0x83, 0xbf, 0x18, 0xb4, 0x03, 0x86, 0x13, - 0x3e, 0x8b, 0x59, 0x16, 0x29, 0x97, 0x6f, 0x39, 0x58, 0x04, 0xad, 0x31, 0x4b, 0xa2, 0xcc, 0x6c, 0x4f, 0x1b, 0x85, - 0x3f, 0x71, 0x96, 0xa9, 0xae, 0x45, 0x97, 0x2b, 0x84, 0x6a, 0xf4, 0x11, 0x8b, 0xe0, 0x13, 0x2d, 0xd7, 0x38, 0xc2, - 0x6e, 0x75, 0x79, 0xed, 0xbc, 0xb6, 0x03, 0xad, 0xb5, 0x8d, 0xd2, 0x46, 0x00, 0x5f, 0x2f, 0xcd, 0xb9, 0x90, 0x41, - 0x30, 0xc5, 0x29, 0x22, 0xbd, 0xa9, 0x72, 0x76, 0x1d, 0xa7, 0xea, 0xbf, 0x7e, 0xb3, 0x1d, 0xb5, 0x4b, 0xf3, 0xbd, - 0x76, 0x1b, 0x58, 0x27, 0x47, 0x99, 0x1b, 0xa5, 0x6a, 0x19, 0xe5, 0x6f, 0xbd, 0xd4, 0xea, 0xb9, 0x5c, 0x2e, 0x36, - 0xc7, 0x4d, 0x8b, 0xaa, 0xa0, 0x06, 0x84, 0x0a, 0x16, 0xed, 0x98, 0x0a, 0x15, 0xd5, 0xba, 0x4b, 0x55, 0xf2, 0x42, - 0x8b, 0xe8, 0xf3, 0xfd, 0xa5, 0x30, 0x33, 0x16, 0x17, 0xcc, 0x3a, 0x99, 0xea, 0x24, 0x57, 0x18, 0x8c, 0x38, 0x7a, - 0xe8, 0xb6, 0x66, 0x1a, 0x96, 0x5b, 0x22, 0xb6, 0xd2, 0x6d, 0xa8, 0x1f, 0xa9, 0x20, 0x55, 0xb8, 0x6b, 0x63, 0x00, - 0xc8, 0xd5, 0xdb, 0x06, 0x18, 0x98, 0xad, 0xb9, 0xb4, 0x4b, 0x00, 0x6d, 0x6c, 0x4c, 0xe1, 0x22, 0xcd, 0xc5, 0xfe, - 0xf2, 0x1b, 0x59, 0x1c, 0x3a, 0x4d, 0xd5, 0x6f, 0x96, 0xc0, 0xff, 0x20, 0x01, 0x97, 0x5a, 0x29, 0x8d, 0xfc, 0xaf, - 0xdf, 0x9e, 0xbd, 0xf7, 0xf1, 0x25, 0x4f, 0x6e, 0x23, 0x5f, 0x8a, 0x05, 0xf5, 0x0b, 0x14, 0xca, 0x29, 0xcd, 0xca, - 0x97, 0xf1, 0xf0, 0x94, 0x86, 0x29, 0x9f, 0xe8, 0x4b, 0x99, 0xeb, 0x46, 0xf2, 0xe8, 0xe2, 0x58, 0xbd, 0x64, 0xaa, - 0x77, 0x2c, 0xf5, 0xeb, 0xbd, 0xa4, 0x80, 0x9f, 0x3d, 0x08, 0xa1, 0x1c, 0x1f, 0xca, 0xa9, 0x7a, 0x38, 0x83, 0x03, - 0xa3, 0x9e, 0xf6, 0x97, 0x1b, 0xc4, 0xd4, 0x87, 0x21, 0xa6, 0x3d, 0xbd, 0x84, 0x5c, 0xb5, 0xba, 0x88, 0x46, 0x17, - 0x17, 0xc5, 0xf1, 0x21, 0x8c, 0x75, 0x68, 0xc7, 0x05, 0x08, 0x6d, 0xff, 0x92, 0xc0, 0xe0, 0x65, 0x43, 0x82, 0xf4, - 0x60, 0x08, 0x98, 0x37, 0xe9, 0xc1, 0x22, 0x81, 0xc0, 0xa0, 0x77, 0x52, 0x96, 0xa8, 0x13, 0xab, 0x8b, 0x76, 0x41, - 0xa0, 0x1b, 0x56, 0x74, 0xaf, 0xbd, 0xa9, 0xd5, 0xfe, 0x5a, 0x90, 0x12, 0x17, 0xba, 0x0b, 0x04, 0xff, 0x2b, 0xc8, - 0x8e, 0x0f, 0x35, 0x1e, 0x2e, 0xdc, 0x57, 0x9b, 0xe8, 0xd7, 0x0e, 0x94, 0xd8, 0x1a, 0xe4, 0x12, 0x7f, 0x94, 0xf8, - 0xe3, 0x85, 0x6a, 0x6a, 0x85, 0x11, 0x68, 0x49, 0x20, 0xb4, 0x5b, 0x56, 0xeb, 0x18, 0xf1, 0x34, 0x8d, 0xe7, 0x39, - 0x8d, 0xec, 0x0f, 0x23, 0x97, 0x40, 0xbc, 0x6d, 0x2a, 0x02, 0x26, 0xbd, 0xe6, 0x14, 0xd4, 0x85, 0x4d, 0x2d, 0xe5, - 0x2a, 0x16, 0x41, 0xb3, 0x39, 0x6a, 0x5e, 0x4e, 0x50, 0x21, 0xa7, 0x4b, 0x57, 0xaa, 0x3d, 0x6e, 0xb5, 0xba, 0x90, - 0x0b, 0xd9, 0x8c, 0x53, 0x36, 0xc9, 0xa2, 0x94, 0x8e, 0x65, 0x21, 0xe1, 0x96, 0xda, 0xd2, 0xaa, 0x11, 0x61, 0xe7, - 0x91, 0xa0, 0x33, 0x2f, 0x84, 0x7f, 0xef, 0x9e, 0xb8, 0x90, 0x49, 0x94, 0xc9, 0x69, 0x53, 0x65, 0xdd, 0xc2, 0x9d, - 0x01, 0x39, 0xad, 0x3d, 0x2f, 0x9d, 0x89, 0x46, 0x14, 0x54, 0xac, 0x42, 0x0a, 0x4f, 0x4e, 0xb1, 0x14, 0x6e, 0xbb, - 0x0c, 0x2d, 0x37, 0x56, 0xb0, 0x29, 0xe9, 0x8f, 0x50, 0x91, 0x2b, 0xc5, 0x78, 0xb3, 0xb1, 0x55, 0x97, 0xea, 0x4f, - 0x1b, 0xe8, 0x73, 0x14, 0xbb, 0x42, 0x3b, 0x96, 0x97, 0xba, 0xc7, 0x7d, 0x90, 0x59, 0x53, 0x39, 0xb1, 0xdb, 0x03, - 0x15, 0x2c, 0x9b, 0x2f, 0xe4, 0x40, 0x39, 0xb5, 0x05, 0x5c, 0x90, 0x18, 0x62, 0xa7, 0x04, 0x70, 0x30, 0x5c, 0x6a, - 0x60, 0x46, 0x71, 0x3a, 0x0a, 0x00, 0x22, 0xaf, 0xe9, 0x3d, 0x15, 0x74, 0x86, 0xba, 0x33, 0x96, 0x35, 0x75, 0xdd, - 0x23, 0x47, 0x2d, 0x09, 0x9f, 0xc0, 0x53, 0x11, 0xaa, 0xd1, 0xb0, 0xca, 0x5d, 0xdd, 0x82, 0xcb, 0x8b, 0x61, 0x51, - 0x74, 0x85, 0x0c, 0x06, 0xaf, 0x03, 0x34, 0xc4, 0xbf, 0x38, 0x2f, 0x67, 0xf1, 0xed, 0x51, 0xf1, 0x71, 0x07, 0xed, - 0x68, 0xe2, 0x9e, 0x05, 0xd5, 0xec, 0x17, 0x02, 0x0d, 0xdf, 0x05, 0x3e, 0xcd, 0xe7, 0x4d, 0xcd, 0xbb, 0x9a, 0x8a, - 0x64, 0x7d, 0xe8, 0x8a, 0x8c, 0xa7, 0xf6, 0x7b, 0xb9, 0x54, 0x6c, 0xc9, 0x5c, 0xd2, 0xd0, 0xce, 0x84, 0x61, 0x79, - 0xa9, 0xc7, 0x3c, 0xbb, 0xd7, 0x78, 0x50, 0x8d, 0x9f, 0x5c, 0x9c, 0xd4, 0x79, 0x1c, 0xf0, 0xa5, 0xf2, 0x05, 0x76, - 0x71, 0x9a, 0xc2, 0x84, 0x17, 0x56, 0x7d, 0x71, 0x5f, 0xfa, 0x31, 0x90, 0xc3, 0x00, 0x15, 0xe6, 0x9c, 0x3e, 0x53, - 0x2a, 0xa5, 0xf3, 0xd6, 0xbc, 0x3d, 0x69, 0x83, 0x45, 0x5a, 0xfa, 0x32, 0x08, 0x77, 0xd7, 0xf2, 0xa2, 0xbb, 0x15, - 0xef, 0xd2, 0x0a, 0xa9, 0xa7, 0x16, 0x44, 0x7c, 0x91, 0x25, 0xbe, 0xf7, 0x97, 0x51, 0xca, 0x46, 0x1f, 0x89, 0xbf, - 0xbf, 0x0c, 0xd0, 0xe6, 0xb5, 0x47, 0xc5, 0x15, 0x2c, 0xc3, 0x46, 0x75, 0x47, 0x7a, 0x16, 0x3a, 0xbc, 0x58, 0xbf, - 0x15, 0xc7, 0xef, 0xed, 0x2f, 0x81, 0xf1, 0xe8, 0x79, 0x7a, 0x17, 0xc5, 0x79, 0xf5, 0xae, 0xab, 0x0a, 0x0a, 0x40, - 0xb3, 0x2e, 0xf7, 0x14, 0x51, 0x11, 0xff, 0x93, 0x94, 0xe6, 0x7b, 0x9a, 0xa9, 0x01, 0x9c, 0xd2, 0xf0, 0x37, 0xdf, - 0xfb, 0x4b, 0x59, 0x46, 0x4b, 0x8f, 0x86, 0x4a, 0xc9, 0x20, 0x3e, 0xcc, 0x05, 0x66, 0x6c, 0x98, 0x50, 0x19, 0xb3, - 0x54, 0x77, 0xe9, 0x5a, 0x03, 0x7c, 0x6d, 0x45, 0xab, 0x55, 0x5e, 0x5f, 0x0b, 0xab, 0x63, 0x50, 0xad, 0xec, 0xf8, - 0xb0, 0x82, 0x5b, 0xad, 0x4c, 0x9d, 0x49, 0x37, 0x34, 0x58, 0xad, 0x50, 0xd7, 0x79, 0x7f, 0x19, 0xa9, 0x6b, 0x43, - 0x00, 0x20, 0x37, 0x00, 0x42, 0xd0, 0x5a, 0x5f, 0x8b, 0x09, 0x52, 0xc2, 0x43, 0x19, 0x8b, 0x09, 0x95, 0x6b, 0x88, - 0x4d, 0x75, 0x8e, 0x6a, 0xd7, 0x06, 0xa8, 0x37, 0xa0, 0x8d, 0xeb, 0xd0, 0x5e, 0x00, 0xd2, 0xfb, 0xfb, 0x4b, 0x56, - 0x90, 0xfd, 0x25, 0xcd, 0x46, 0x3c, 0xa1, 0x1f, 0xde, 0x7d, 0x09, 0x97, 0x1c, 0x79, 0x06, 0x86, 0xc5, 0x14, 0x81, - 0xe0, 0x54, 0x9b, 0xa3, 0x45, 0x08, 0x57, 0x22, 0x44, 0x73, 0x02, 0x4f, 0xcd, 0xa5, 0x40, 0x2c, 0x7c, 0xaf, 0xaf, - 0x21, 0xa7, 0x89, 0x86, 0x99, 0x64, 0xaa, 0x17, 0x2f, 0x8e, 0x0f, 0x75, 0x6b, 0x2d, 0x02, 0x74, 0x23, 0x40, 0x82, - 0x3a, 0xa7, 0x15, 0x0e, 0x20, 0xaf, 0xd9, 0xc5, 0x43, 0xc2, 0xae, 0x4a, 0x62, 0x53, 0x17, 0xa8, 0x7a, 0xc7, 0x69, - 0x7c, 0x49, 0xd3, 0xde, 0xfe, 0x32, 0x5b, 0xad, 0x5a, 0xc5, 0xf1, 0xa1, 0x7e, 0xf4, 0x8e, 0x15, 0xdf, 0xd0, 0x2f, - 0xbc, 0x54, 0x5b, 0x0c, 0xb7, 0x12, 0x21, 0xdb, 0xd3, 0xa6, 0x39, 0x45, 0x66, 0x80, 0xc2, 0xf7, 0x54, 0x82, 0x85, - 0x6a, 0x54, 0x2a, 0x44, 0x85, 0xef, 0xb1, 0x64, 0xb3, 0x2c, 0x97, 0x74, 0x0e, 0xa5, 0xd3, 0xd5, 0xaa, 0x5d, 0xf8, - 0xde, 0x8c, 0x65, 0xf0, 0x94, 0xad, 0x56, 0xea, 0xc2, 0xdf, 0x8c, 0x65, 0x41, 0x0b, 0xc8, 0xd6, 0xf7, 0x66, 0xf1, - 0x8d, 0x5a, 0xb0, 0xad, 0x89, 0x6f, 0x82, 0xb6, 0xa9, 0x0a, 0x4b, 0xfc, 0xe4, 0x40, 0x71, 0xd5, 0x8e, 0xa6, 0x66, - 0x47, 0x13, 0xbc, 0xd0, 0x57, 0x99, 0x48, 0x90, 0x90, 0x74, 0xfb, 0x8e, 0x26, 0x76, 0x47, 0x17, 0x3b, 0x76, 0x74, - 0x71, 0xc7, 0x8e, 0xc6, 0x66, 0xf7, 0xbc, 0x12, 0x77, 0x7c, 0xb5, 0x6a, 0xb7, 0x2a, 0xec, 0x1d, 0x1f, 0x26, 0xec, - 0x0a, 0x76, 0x03, 0xd4, 0x3c, 0xc9, 0x66, 0x74, 0x3b, 0x51, 0xd6, 0x51, 0x4c, 0x7f, 0x15, 0x26, 0x2b, 0x2c, 0x64, - 0x75, 0x2c, 0xb8, 0x74, 0x5d, 0xc6, 0xdc, 0xfe, 0x48, 0xca, 0x66, 0x80, 0x87, 0x1c, 0xf0, 0x30, 0x35, 0x78, 0xb8, - 0x28, 0xce, 0x41, 0x24, 0xa8, 0xe5, 0xdc, 0x8b, 0xf4, 0xa0, 0xb5, 0xdf, 0xdb, 0x4d, 0x62, 0x10, 0x0d, 0xbf, 0xe6, - 0x22, 0xf1, 0x23, 0xdd, 0xf4, 0x57, 0x61, 0x66, 0xc6, 0x32, 0x93, 0x5b, 0xb5, 0x93, 0xb4, 0xaa, 0x7a, 0x97, 0xc0, - 0x3a, 0x8f, 0x1e, 0xe9, 0x16, 0xf3, 0x58, 0x4a, 0x2a, 0x32, 0x43, 0xa8, 0xbe, 0xff, 0xff, 0x05, 0xd1, 0x6d, 0x61, - 0x23, 0xb1, 0x65, 0x23, 0x96, 0xde, 0x8c, 0x7e, 0x6e, 0x58, 0xbc, 0x96, 0x46, 0x7b, 0x95, 0xc2, 0x7a, 0x8b, 0x5c, - 0x1b, 0x41, 0x17, 0x81, 0xc9, 0xb2, 0x98, 0xd1, 0xe4, 0x5c, 0xf1, 0xe3, 0xfe, 0xe8, 0xc2, 0xe8, 0xa7, 0x6b, 0xd2, - 0xad, 0xea, 0x80, 0xfd, 0x1f, 0x17, 0x9d, 0x27, 0x0f, 0x4f, 0x7d, 0xac, 0x59, 0x3a, 0x1f, 0x8f, 0x7d, 0x54, 0x78, - 0xf7, 0xeb, 0xd6, 0x7e, 0xf8, 0xe3, 0xe2, 0x8b, 0x17, 0xad, 0x2f, 0xca, 0xce, 0x99, 0x8f, 0x8a, 0x0b, 0x13, 0xce, - 0xb7, 0x92, 0xc9, 0x81, 0xd7, 0xae, 0x68, 0x1c, 0x67, 0xbb, 0x97, 0x33, 0x70, 0x97, 0x93, 0xcf, 0x29, 0x4d, 0xb0, - 0xef, 0xf9, 0x78, 0xa3, 0xf4, 0x3c, 0xa5, 0x57, 0xd4, 0xbe, 0x68, 0x70, 0xcb, 0x64, 0x5b, 0x7a, 0x8c, 0xf8, 0x22, - 0x93, 0x26, 0xaf, 0xc1, 0x70, 0x56, 0x67, 0x49, 0x17, 0x6a, 0x0d, 0xae, 0x49, 0x70, 0xab, 0xc5, 0x5a, 0x5d, 0x58, - 0x15, 0x17, 0xd8, 0x77, 0x00, 0xd8, 0x09, 0x59, 0x7f, 0x47, 0x79, 0xd4, 0xc2, 0xad, 0x5d, 0xb0, 0xe1, 0x36, 0x8a, - 0x7c, 0x7f, 0x68, 0xf1, 0xa4, 0x5c, 0x93, 0xb5, 0xf7, 0x43, 0xec, 0xc4, 0xd7, 0x27, 0x31, 0x70, 0x29, 0x60, 0xb0, - 0x8c, 0xe6, 0xf9, 0x4e, 0x04, 0x94, 0x9b, 0x88, 0xfd, 0xaa, 0xb5, 0xbf, 0x63, 0x14, 0xdc, 0xc2, 0x70, 0xc2, 0x14, - 0xc0, 0x65, 0x80, 0xd4, 0xb4, 0xa2, 0xe3, 0x31, 0x1d, 0x95, 0x9e, 0x5d, 0x08, 0x75, 0x8d, 0x59, 0x2a, 0x21, 0xe2, - 0xa3, 0x42, 0x31, 0xfe, 0x1b, 0x9e, 0x51, 0x1f, 0xd9, 0xe4, 0x4d, 0x03, 0xbf, 0x11, 0xf7, 0xdb, 0xe1, 0xd1, 0x23, - 0xd6, 0x61, 0x31, 0xb3, 0xac, 0x56, 0xd6, 0xab, 0x53, 0x2b, 0xaf, 0x23, 0x92, 0x2b, 0xb7, 0xcd, 0xae, 0x03, 0x74, - 0xbf, 0x63, 0xb2, 0x6c, 0x7f, 0xf1, 0xa8, 0xdd, 0x2a, 0x7c, 0xec, 0xc3, 0x70, 0xf7, 0x3d, 0x25, 0xaa, 0xd7, 0x11, - 0xf4, 0x5a, 0x64, 0xbf, 0xa6, 0x5f, 0xa7, 0xfd, 0x79, 0xdb, 0xc7, 0xfa, 0xbd, 0x01, 0xa8, 0x28, 0x99, 0xc1, 0x08, - 0x7c, 0x9d, 0xbf, 0x7b, 0x29, 0xf5, 0xc1, 0xef, 0x07, 0xcf, 0xe3, 0x76, 0xcb, 0xc7, 0x7e, 0x2e, 0xf9, 0xfc, 0x57, - 0x2c, 0xe1, 0xc8, 0xc7, 0xfe, 0x28, 0xe5, 0x39, 0x75, 0xd7, 0xa0, 0xb5, 0xd7, 0xdf, 0xbf, 0x08, 0x0d, 0xd1, 0x5c, - 0xd0, 0x3c, 0xf7, 0xdc, 0xf1, 0x0d, 0x29, 0x7d, 0x82, 0x61, 0x6e, 0xa5, 0xb8, 0x9c, 0x4a, 0x85, 0x17, 0x7d, 0xa5, - 0xdf, 0xa5, 0x2a, 0x5d, 0xb6, 0x41, 0x6c, 0x4a, 0x04, 0x94, 0x8c, 0x4d, 0x2b, 0x53, 0x9f, 0x9c, 0x79, 0xcb, 0xd1, - 0xd3, 0x13, 0xeb, 0x10, 0xf0, 0xe6, 0x04, 0xb5, 0x92, 0x19, 0xcb, 0xce, 0xb7, 0x94, 0xc6, 0x37, 0x5b, 0x4a, 0x41, - 0x43, 0x2b, 0xa1, 0x33, 0x6f, 0x9b, 0xf9, 0x34, 0xd6, 0x2b, 0x3d, 0xc7, 0x05, 0x31, 0x51, 0x6e, 0xca, 0x4f, 0x40, - 0xea, 0x6c, 0x83, 0x1a, 0xe1, 0xb7, 0x4f, 0x07, 0x25, 0xbf, 0x6a, 0x3a, 0x7a, 0xf3, 0xe9, 0x3d, 0x77, 0x14, 0x9b, - 0xdf, 0x81, 0x7d, 0x73, 0x73, 0x7c, 0x1d, 0xfd, 0x5b, 0x8a, 0x8d, 0xee, 0x51, 0x6e, 0xc1, 0x28, 0x65, 0xb3, 0x6a, - 0x17, 0x36, 0xc1, 0x54, 0x4a, 0x07, 0xa4, 0x0f, 0xb9, 0x83, 0x68, 0xed, 0xe3, 0x1c, 0x2e, 0x45, 0xc2, 0x9b, 0x27, - 0x16, 0x82, 0x9e, 0xa7, 0xfc, 0x7a, 0xfd, 0x4d, 0x5a, 0xbb, 0x1b, 0x4f, 0xd9, 0x64, 0xea, 0xdc, 0x74, 0xa2, 0xa4, - 0x44, 0xfd, 0x9d, 0x13, 0x14, 0xff, 0xfa, 0x2f, 0x61, 0xf8, 0xaf, 0xff, 0xf2, 0xc9, 0xa6, 0x30, 0x7c, 0x71, 0x81, - 0x65, 0x35, 0xec, 0x6e, 0x02, 0xdf, 0x3e, 0x53, 0x1d, 0xe7, 0xdb, 0xdb, 0x6c, 0x6c, 0x02, 0xd4, 0x6f, 0x6c, 0xc1, - 0x46, 0xa1, 0x3e, 0x00, 0xde, 0x6f, 0x01, 0x0c, 0xd6, 0xf5, 0x49, 0xc8, 0xa0, 0xd1, 0xef, 0x02, 0xed, 0x02, 0x45, - 0xf7, 0xda, 0x91, 0xdf, 0x8e, 0xe1, 0x4f, 0xad, 0xe1, 0x77, 0x82, 0x6f, 0x3c, 0x02, 0xa3, 0x8b, 0x8b, 0x32, 0xa5, - 0xcd, 0xed, 0x0a, 0x57, 0xe6, 0xfb, 0x1b, 0x25, 0x46, 0xf6, 0x47, 0x2d, 0xd4, 0x53, 0x17, 0xf2, 0xc8, 0xe8, 0xe2, - 0x35, 0xbc, 0x27, 0xe7, 0xf8, 0x52, 0x58, 0x97, 0xea, 0x1d, 0xfc, 0x19, 0x86, 0xa8, 0xaf, 0x4a, 0x0d, 0xba, 0xc1, - 0x9c, 0xa1, 0x14, 0x34, 0x7e, 0x00, 0x13, 0x8f, 0x2e, 0x8c, 0x7d, 0x77, 0xaa, 0x1d, 0x1f, 0xd1, 0x3a, 0x69, 0x1b, - 0x87, 0x48, 0x0d, 0xe9, 0xd8, 0x7b, 0xaf, 0xf0, 0xa5, 0x1a, 0xd3, 0xca, 0x9e, 0x56, 0xce, 0x25, 0x50, 0xe5, 0x2f, - 0x0a, 0x15, 0x18, 0xff, 0xeb, 0xae, 0xd8, 0xdd, 0xdf, 0x3f, 0x1d, 0xbb, 0xe3, 0xf7, 0x8a, 0xdd, 0xfd, 0xfd, 0x0f, - 0x8f, 0xdd, 0xfd, 0xd5, 0x8d, 0xdd, 0xc1, 0x26, 0x7e, 0x79, 0xaf, 0xf8, 0x9a, 0x8d, 0x7d, 0xf0, 0xeb, 0x9c, 0xb4, - 0x8d, 0x26, 0x9b, 0xf2, 0x09, 0x04, 0xd7, 0xfe, 0xfd, 0x63, 0x65, 0x29, 0x9f, 0xb8, 0x91, 0x32, 0x78, 0x4f, 0x2a, - 0x84, 0xc6, 0xba, 0x36, 0xa6, 0x65, 0xa2, 0x53, 0xad, 0xf2, 0x0e, 0x48, 0xf3, 0xa1, 0x7d, 0x67, 0x81, 0x1f, 0x95, - 0xef, 0x1d, 0x6a, 0xe1, 0x8e, 0x8d, 0x5f, 0x45, 0x2a, 0xf4, 0x55, 0x76, 0xec, 0x34, 0xec, 0x05, 0x07, 0x77, 0x84, - 0xae, 0x7d, 0xaf, 0x8a, 0xbe, 0xef, 0xbe, 0xf4, 0x7f, 0xbc, 0x69, 0x3f, 0x1b, 0xb4, 0xbb, 0x47, 0xed, 0x99, 0x1f, - 0xf9, 0x20, 0xa5, 0x54, 0x41, 0xab, 0x7b, 0x74, 0x04, 0x05, 0xd7, 0x4e, 0x41, 0x07, 0x0a, 0x98, 0x53, 0xf0, 0x08, - 0x0a, 0x46, 0x4e, 0xc1, 0x63, 0x28, 0x48, 0x9c, 0x82, 0x27, 0x50, 0x70, 0xe5, 0x17, 0x03, 0x56, 0x82, 0xfb, 0x04, - 0x0d, 0xb1, 0x36, 0x1e, 0x6c, 0xd9, 0x13, 0xdc, 0x86, 0xa0, 0x59, 0x3c, 0x51, 0xb9, 0x3e, 0xe0, 0x82, 0x8b, 0x38, - 0xbe, 0x9e, 0xd2, 0x2c, 0x82, 0xb0, 0xe5, 0x73, 0x25, 0x63, 0x42, 0xc9, 0xdf, 0xb3, 0x19, 0xb5, 0x5f, 0xa8, 0xb0, - 0x78, 0xf0, 0x7c, 0x34, 0x68, 0x0d, 0x8b, 0x6e, 0xb9, 0x73, 0x3a, 0xda, 0x66, 0xf2, 0x3e, 0xf4, 0x5e, 0x56, 0x75, - 0x7a, 0xba, 0x66, 0xb9, 0xe7, 0x3b, 0xa2, 0x36, 0x8e, 0x3b, 0x60, 0x9c, 0xf2, 0xeb, 0xe6, 0x8d, 0xdf, 0xdb, 0x1e, - 0xc9, 0x01, 0x88, 0xca, 0x48, 0x8e, 0x5a, 0x53, 0xf9, 0xf4, 0x3e, 0x9e, 0x94, 0xbf, 0x5f, 0xd3, 0x3c, 0x8f, 0x27, - 0xa6, 0xe5, 0xee, 0xc8, 0x8d, 0x02, 0xd1, 0x8d, 0xda, 0x58, 0x20, 0x20, 0xfa, 0x02, 0x9b, 0x05, 0xe6, 0xb4, 0x09, - 0xc6, 0x00, 0x76, 0xea, 0x71, 0x1c, 0x35, 0x7d, 0xbd, 0x48, 0xc6, 0x93, 0xaa, 0xe0, 0x78, 0x2e, 0xa8, 0x2a, 0xd5, - 0x18, 0x2e, 0x8e, 0x0f, 0xa1, 0x40, 0x57, 0xef, 0x88, 0xd7, 0x58, 0xdb, 0x7d, 0x77, 0xd4, 0xc6, 0xb3, 0xf1, 0x1a, - 0x37, 0xc3, 0xa5, 0x4c, 0x6f, 0xd9, 0x8c, 0x12, 0x7c, 0xd6, 0x1e, 0xc1, 0x1f, 0x13, 0x83, 0xf8, 0x6c, 0x3c, 0x1e, - 0xdf, 0x19, 0xbf, 0xf9, 0x2c, 0x19, 0xd3, 0x0e, 0x7d, 0xd4, 0x85, 0xec, 0x87, 0xa6, 0xf1, 0xfa, 0xb7, 0x0b, 0x85, - 0xbb, 0xe5, 0xfd, 0x1a, 0x43, 0x80, 0x40, 0x4e, 0x97, 0xf7, 0x8f, 0xe5, 0x14, 0x73, 0x41, 0x97, 0xb3, 0x58, 0x4c, - 0x58, 0x16, 0xb5, 0x8a, 0xf0, 0xca, 0x04, 0x3f, 0x3e, 0x7b, 0xfa, 0xf4, 0x69, 0x11, 0x26, 0xf6, 0xa9, 0x95, 0x24, - 0x45, 0x38, 0x5a, 0x96, 0xcb, 0x68, 0xb5, 0xc6, 0xe3, 0x22, 0x64, 0xb6, 0xe0, 0xa8, 0x33, 0x4a, 0x8e, 0x3a, 0x45, - 0x78, 0xed, 0xb4, 0x28, 0x42, 0x6a, 0x9e, 0x04, 0x4d, 0x6a, 0x29, 0x14, 0x4f, 0x5a, 0xad, 0x22, 0xd4, 0x84, 0xb6, - 0x04, 0x8b, 0x48, 0xff, 0x8c, 0xe2, 0x85, 0xe4, 0xc0, 0x92, 0xbb, 0x5c, 0x06, 0x83, 0x73, 0xf3, 0x7a, 0x0a, 0xfd, - 0x29, 0x87, 0x02, 0x0d, 0xf1, 0x97, 0x6e, 0x98, 0x02, 0x88, 0x59, 0x85, 0x27, 0xb8, 0x8d, 0x62, 0xd4, 0xaa, 0x81, - 0xb2, 0x54, 0xf5, 0x97, 0x84, 0x57, 0xd1, 0x0b, 0xe0, 0x3f, 0xd0, 0x52, 0xbf, 0x47, 0x4d, 0xd2, 0x1d, 0x5c, 0x9f, - 0xd2, 0x4f, 0x72, 0xfd, 0xdb, 0xfb, 0x30, 0x7d, 0x4a, 0xff, 0x68, 0xa6, 0x6f, 0x5e, 0x36, 0xaa, 0x99, 0xbe, 0x66, - 0x6b, 0x33, 0x49, 0xfc, 0xd1, 0x94, 0x8e, 0x3e, 0x5e, 0xf2, 0x9b, 0x26, 0x1c, 0x09, 0xe1, 0x2b, 0x7e, 0xba, 0xff, - 0x5b, 0xd3, 0x2d, 0xec, 0x60, 0xce, 0x97, 0x20, 0x94, 0xd8, 0x7c, 0x9b, 0x11, 0xff, 0xad, 0x35, 0xab, 0x74, 0xc9, - 0x78, 0x4c, 0xfc, 0xb7, 0xe3, 0xb1, 0x6f, 0x2f, 0xd9, 0xc5, 0x92, 0xaa, 0x56, 0x6f, 0x6a, 0x25, 0xaa, 0xd5, 0x17, - 0x5f, 0xb8, 0x65, 0x6e, 0x81, 0x09, 0x72, 0xb8, 0x01, 0x0d, 0x53, 0x93, 0xb0, 0x1c, 0x8e, 0x1a, 0x7c, 0xa0, 0xa2, - 0xfe, 0x96, 0x3f, 0x51, 0x7b, 0x21, 0x73, 0x09, 0xf0, 0x96, 0xb7, 0x48, 0xaf, 0xdf, 0x30, 0x9f, 0x50, 0x9b, 0xf0, - 0xf6, 0xec, 0xf6, 0xcb, 0x24, 0x98, 0x49, 0x54, 0xb0, 0xfc, 0x6d, 0xb6, 0x76, 0x7b, 0x44, 0xc3, 0x48, 0x88, 0xbb, - 0xac, 0x42, 0xf2, 0xc9, 0x24, 0x85, 0x4f, 0x84, 0x2c, 0x6b, 0x6f, 0x1e, 0xd5, 0xdd, 0xfb, 0xb5, 0xf5, 0x46, 0x6e, - 0x47, 0xf3, 0x9e, 0x4e, 0xf5, 0xc5, 0x22, 0x9d, 0x75, 0x7c, 0x65, 0x3e, 0x5d, 0xa3, 0x2c, 0xb2, 0xa5, 0xe1, 0xff, - 0x4b, 0x9d, 0xab, 0x2a, 0x21, 0x4f, 0x43, 0x0f, 0x9c, 0x14, 0x85, 0xc9, 0xf2, 0x4f, 0x58, 0x3e, 0x87, 0x37, 0x62, - 0xea, 0x9e, 0xf4, 0x53, 0x2c, 0x3c, 0xbf, 0x76, 0x22, 0x09, 0xb5, 0xed, 0x2a, 0x6c, 0x28, 0x41, 0xfb, 0x6a, 0x67, - 0xb2, 0xf0, 0x8d, 0xcb, 0xd7, 0x22, 0xd1, 0xf7, 0x34, 0x3e, 0x75, 0x8c, 0xc3, 0x59, 0x21, 0xf8, 0x5d, 0xcb, 0x0d, - 0xb1, 0x55, 0xb6, 0xa0, 0x70, 0x23, 0x65, 0xaa, 0x46, 0x63, 0x4b, 0xf9, 0xe5, 0xf3, 0x79, 0x9c, 0x69, 0x36, 0x4a, - 0x7c, 0xcd, 0x0f, 0xf6, 0x97, 0xd5, 0xce, 0x17, 0xbe, 0x05, 0x5b, 0x13, 0x6f, 0xef, 0xf8, 0x10, 0x3a, 0xf4, 0xbc, - 0x1a, 0xe8, 0xd9, 0x86, 0x3b, 0xff, 0x13, 0x81, 0xf5, 0x8b, 0x30, 0xbf, 0xc6, 0x61, 0x7e, 0xed, 0xfd, 0x79, 0xd9, - 0xbc, 0xa6, 0x97, 0x1f, 0x99, 0x6c, 0xca, 0x78, 0xde, 0x04, 0x85, 0x5f, 0xf9, 0xe5, 0x0c, 0x7b, 0x56, 0xe9, 0x61, - 0xfa, 0x8e, 0x7c, 0x77, 0x91, 0x43, 0xfc, 0x5d, 0xa9, 0xad, 0x51, 0xc6, 0x33, 0xda, 0xad, 0xa7, 0x01, 0xba, 0xe1, - 0x5c, 0x8b, 0xad, 0xe1, 0x92, 0x43, 0xbc, 0x5e, 0xde, 0x46, 0x2d, 0xc3, 0xd6, 0x5b, 0x36, 0x56, 0xdb, 0xda, 0xda, - 0x3e, 0x32, 0xc8, 0x6d, 0x28, 0xe9, 0x25, 0x36, 0x63, 0xd6, 0xbb, 0x62, 0xce, 0x9f, 0x4a, 0x8a, 0x03, 0x6f, 0x9e, - 0xfd, 0xeb, 0x64, 0x13, 0xae, 0x17, 0xab, 0xa4, 0xb8, 0xfb, 0x40, 0x16, 0xc5, 0x63, 0x49, 0x05, 0xbe, 0x4f, 0xcb, - 0x4b, 0x75, 0x7f, 0x65, 0x09, 0x62, 0x26, 0x6a, 0x3f, 0x9d, 0xdf, 0xdc, 0x7f, 0xf8, 0xbb, 0x97, 0x5f, 0x18, 0x1c, - 0xd9, 0xf7, 0xb9, 0xf8, 0x7e, 0x17, 0x0e, 0x42, 0x1a, 0xdf, 0x46, 0x2c, 0x53, 0x32, 0xef, 0x12, 0x5c, 0x72, 0xdd, - 0x39, 0x37, 0xd9, 0x9d, 0x82, 0xa6, 0xea, 0xe3, 0x6d, 0x66, 0x2b, 0x8e, 0x1e, 0xcf, 0x6f, 0xec, 0x6e, 0xb4, 0xd7, - 0xb2, 0x36, 0xff, 0xd0, 0xe4, 0xcc, 0xdd, 0xd9, 0xa0, 0xf5, 0x04, 0xc3, 0x47, 0xf3, 0x9b, 0xae, 0x16, 0xb4, 0x4d, - 0xa1, 0xa1, 0x6a, 0xcd, 0x6f, 0xdc, 0xf4, 0xd4, 0x6a, 0x20, 0x2f, 0x3c, 0xca, 0x3d, 0x1a, 0xe7, 0xb4, 0x0b, 0x6f, - 0xac, 0x66, 0xa3, 0x38, 0x35, 0xc2, 0x7c, 0xc6, 0x92, 0x24, 0xa5, 0x5d, 0x2b, 0xaf, 0xbd, 0xf6, 0x63, 0xc8, 0xee, - 0x74, 0xb7, 0xac, 0xbe, 0x2b, 0x0e, 0xf2, 0x4a, 0x3c, 0xc5, 0x97, 0x39, 0x4f, 0xe1, 0x73, 0x11, 0x5b, 0xd1, 0x69, - 0xd2, 0x1e, 0x5b, 0x15, 0xf2, 0xd4, 0xef, 0xfa, 0x5a, 0x1e, 0xb5, 0xfe, 0xd4, 0x55, 0x1b, 0xde, 0xea, 0x4a, 0x3e, - 0x8f, 0x9a, 0x47, 0xf5, 0x85, 0x40, 0x55, 0xb9, 0x04, 0xbc, 0x65, 0x59, 0x18, 0xa4, 0x95, 0xe6, 0xd3, 0x5e, 0xd8, - 0x36, 0x65, 0x6a, 0x00, 0x78, 0xb5, 0x72, 0x59, 0x54, 0xd4, 0x17, 0xf3, 0xef, 0x73, 0x5a, 0x3e, 0xdf, 0x7e, 0x5a, - 0x3e, 0xb7, 0xa7, 0xe5, 0x6e, 0x8a, 0xfd, 0x6c, 0xdc, 0x86, 0x3f, 0xdd, 0x6a, 0x41, 0x51, 0xcb, 0x3b, 0x9a, 0xdf, - 0x78, 0xa0, 0xa7, 0x35, 0x3b, 0xf3, 0x1b, 0x9d, 0x9c, 0x0b, 0x61, 0x83, 0x16, 0xa4, 0xab, 0xe2, 0x96, 0x07, 0x85, - 0xf0, 0xb7, 0x55, 0xab, 0x6a, 0x3f, 0x84, 0x3a, 0xe8, 0xf5, 0x68, 0xb3, 0xae, 0x73, 0xf7, 0xa1, 0x8d, 0x32, 0x2e, - 0x83, 0xc8, 0x72, 0x63, 0x14, 0xca, 0xf8, 0xf2, 0x92, 0x26, 0xd1, 0x98, 0x8f, 0x16, 0xf9, 0x3f, 0x1b, 0xf8, 0x0d, - 0x12, 0xef, 0x3c, 0xd2, 0x6b, 0xe3, 0xd8, 0xae, 0x3a, 0x55, 0xd8, 0x8e, 0xb0, 0x2c, 0xf7, 0x29, 0xca, 0x47, 0x71, - 0x4a, 0x83, 0x4e, 0xf8, 0x70, 0xcb, 0x21, 0xf8, 0x0f, 0xd9, 0x9b, 0xad, 0x8b, 0xf9, 0xbd, 0xc8, 0xb8, 0x13, 0x09, - 0xbf, 0x0a, 0x07, 0xee, 0x1e, 0xb6, 0x9e, 0x6e, 0x07, 0x77, 0x60, 0x67, 0x1a, 0x5a, 0xa1, 0x60, 0xe4, 0x4e, 0x42, - 0xc7, 0xf1, 0x22, 0x95, 0x77, 0x8f, 0xba, 0x8b, 0x32, 0x36, 0x46, 0xbd, 0x83, 0xa1, 0x57, 0x6d, 0xef, 0xc9, 0xa5, - 0x3f, 0xfb, 0xfc, 0x21, 0xfc, 0xd1, 0x99, 0x46, 0xb7, 0x95, 0xae, 0xae, 0x6d, 0x55, 0xd0, 0xd5, 0xf7, 0x6b, 0xca, - 0xb8, 0x16, 0xe1, 0x4a, 0x1f, 0xbf, 0x6f, 0x6b, 0xd0, 0x2a, 0xef, 0xd5, 0xdc, 0x68, 0x59, 0xbf, 0xaa, 0xf5, 0xaf, - 0x1b, 0xfc, 0x9e, 0x6d, 0x47, 0x5a, 0x73, 0xad, 0xb7, 0x35, 0x5f, 0xaf, 0xdb, 0x68, 0x6c, 0x31, 0xae, 0xda, 0xef, - 0x93, 0xdb, 0xd2, 0x44, 0xd1, 0x81, 0x40, 0xb0, 0x52, 0xf6, 0xb5, 0x95, 0xc2, 0x28, 0x79, 0x00, 0xef, 0x8e, 0xf5, - 0x6e, 0x66, 0x69, 0x96, 0x13, 0x7f, 0x2a, 0xe5, 0x3c, 0xd2, 0x9f, 0x3b, 0xbd, 0x3e, 0x0a, 0xb9, 0x98, 0x1c, 0x76, - 0x5a, 0xad, 0x16, 0xbc, 0xf3, 0xd3, 0xf7, 0xae, 0x18, 0xbd, 0x7e, 0xc6, 0x6f, 0x88, 0xff, 0xc4, 0x7b, 0xea, 0x3d, - 0x39, 0xf2, 0x1e, 0x3d, 0xf6, 0x3d, 0xc5, 0xce, 0x89, 0xff, 0xe4, 0xc8, 0xf7, 0x34, 0x3b, 0x27, 0xfe, 0xa3, 0xc7, - 0x7e, 0xef, 0x78, 0x62, 0x55, 0x32, 0xb8, 0x34, 0xa8, 0xf5, 0x9d, 0x5c, 0x0a, 0xfe, 0x91, 0xd6, 0x0f, 0xae, 0x2e, - 0x33, 0xb9, 0x68, 0x1d, 0xfb, 0x08, 0xa7, 0x77, 0x14, 0xcf, 0x23, 0x45, 0x14, 0x6e, 0x21, 0xb8, 0x65, 0x74, 0xa9, - 0x9a, 0x02, 0xd4, 0xcc, 0x4b, 0xbf, 0x77, 0x0c, 0x79, 0xe3, 0x5e, 0x42, 0xfc, 0xd7, 0x9d, 0x27, 0x5e, 0xfb, 0xf1, - 0x55, 0xf3, 0xe1, 0xa8, 0xd5, 0x6c, 0x7b, 0xed, 0x66, 0x27, 0x7c, 0xe2, 0x75, 0xf4, 0xbf, 0x5e, 0xcb, 0x3b, 0xf2, - 0xda, 0xe1, 0x13, 0xef, 0xc8, 0xeb, 0x84, 0x4f, 0xae, 0x1e, 0xea, 0x7c, 0x82, 0xd8, 0x3f, 0xec, 0x1d, 0xc3, 0xa7, - 0x2b, 0x6f, 0x88, 0xff, 0xb9, 0xaf, 0x3f, 0x10, 0xeb, 0x7f, 0xe6, 0x96, 0xb6, 0x9f, 0x6e, 0x2d, 0xee, 0x3c, 0xd9, - 0x5a, 0x7c, 0xf4, 0x78, 0x6b, 0xf1, 0xc3, 0x47, 0xf5, 0xe2, 0xc3, 0x89, 0xae, 0x2a, 0x4f, 0x39, 0xf1, 0x67, 0xb1, - 0x14, 0xec, 0x26, 0x68, 0x7b, 0x2d, 0xaf, 0xe5, 0x35, 0xe1, 0xbf, 0x27, 0x1d, 0x54, 0xf6, 0xba, 0x84, 0x5e, 0xe5, - 0x2a, 0x9f, 0x3c, 0xf5, 0xda, 0x8f, 0x5f, 0x76, 0x1e, 0x8f, 0xa0, 0x9d, 0x5a, 0x68, 0xdb, 0x6b, 0x5f, 0x1d, 0x3d, - 0x1d, 0xb5, 0x3c, 0xe8, 0xd8, 0x86, 0x3f, 0xd3, 0x47, 0x9d, 0x91, 0x7e, 0x68, 0x41, 0xfd, 0xb7, 0xed, 0x27, 0x79, - 0xab, 0xd9, 0x86, 0x3f, 0xbf, 0x94, 0x1a, 0x31, 0xe8, 0xe3, 0xee, 0xb8, 0x0f, 0x5b, 0xde, 0xd1, 0xd3, 0x69, 0x27, - 0xfc, 0xfc, 0xea, 0x49, 0xf8, 0x74, 0xda, 0x7e, 0xf2, 0xad, 0x7e, 0x4a, 0x9b, 0x9d, 0xf0, 0x73, 0xf8, 0xfb, 0xed, - 0x51, 0x6b, 0xda, 0x6c, 0x87, 0x4f, 0xaf, 0x8e, 0xc2, 0xa3, 0xb4, 0xf9, 0x38, 0x7c, 0x0a, 0x7f, 0xab, 0xe1, 0xa6, - 0x7c, 0x46, 0x7d, 0x0f, 0xf6, 0x7b, 0xcd, 0xdc, 0x72, 0xe7, 0xe8, 0x3c, 0xf4, 0x1e, 0x3d, 0x7c, 0xf9, 0xf4, 0xaa, - 0xf9, 0x70, 0xda, 0xee, 0x5c, 0x35, 0x77, 0xfe, 0xfc, 0x16, 0x10, 0x6f, 0x06, 0x8e, 0x29, 0x5c, 0xe0, 0xb1, 0x88, - 0x53, 0xef, 0x9f, 0x7d, 0x80, 0xf3, 0x5d, 0xe6, 0xb5, 0xf8, 0xb4, 0x79, 0x9d, 0xd1, 0xfb, 0xd8, 0xd7, 0xe2, 0x0f, - 0xb7, 0xaf, 0x73, 0xba, 0xe6, 0x54, 0xbd, 0x95, 0x1b, 0x66, 0xf4, 0xba, 0xed, 0xf5, 0x4e, 0x06, 0x03, 0x06, 0xdf, - 0x39, 0x2a, 0xba, 0xb7, 0xf0, 0x8a, 0x6b, 0xd7, 0xdb, 0xc0, 0xe1, 0x20, 0xdf, 0x4a, 0x7d, 0x92, 0xf9, 0x2e, 0x84, - 0xa4, 0x9f, 0x46, 0xc8, 0xb7, 0xf7, 0xc1, 0x47, 0xfa, 0x87, 0xe3, 0x83, 0xbb, 0xf8, 0xa8, 0xf9, 0x79, 0x95, 0x3d, - 0xab, 0xec, 0xd1, 0x33, 0xf5, 0x1c, 0xc0, 0x1d, 0x8f, 0x86, 0x7f, 0x48, 0xa1, 0x28, 0xf7, 0x75, 0x5c, 0xe1, 0xcd, - 0xaf, 0x71, 0x49, 0xeb, 0x0b, 0x5d, 0xc4, 0x37, 0xc6, 0xff, 0x1c, 0xbe, 0x65, 0x60, 0x1f, 0xae, 0xf4, 0x15, 0x63, - 0xe2, 0x77, 0xc2, 0x56, 0xd8, 0x2a, 0x1d, 0x07, 0x70, 0x89, 0x8f, 0x2c, 0xb9, 0x8c, 0xe1, 0x73, 0x9a, 0x29, 0x9f, - 0xa8, 0x0f, 0x6f, 0xc2, 0xeb, 0xce, 0xd5, 0x27, 0x50, 0xf5, 0x9b, 0xe6, 0x23, 0xdf, 0x37, 0x57, 0xff, 0xe1, 0x92, - 0xd8, 0x37, 0x70, 0x91, 0xce, 0x7a, 0xac, 0x67, 0x60, 0x53, 0xbf, 0xa6, 0x09, 0x8b, 0x03, 0x3f, 0x98, 0x0b, 0x3a, - 0xa6, 0x22, 0x6f, 0xd6, 0x6e, 0x97, 0xa9, 0x8b, 0x65, 0xc8, 0xb7, 0x1f, 0x6e, 0x14, 0xf0, 0xfa, 0x5e, 0x32, 0x30, - 0x5e, 0x2d, 0xdf, 0xa8, 0xf9, 0x7e, 0x81, 0x6d, 0x89, 0x00, 0x8e, 0x5e, 0xa9, 0x06, 0xbe, 0xd6, 0x0d, 0xda, 0x61, - 0xe7, 0x11, 0xd2, 0xbc, 0x04, 0x5e, 0x8b, 0xfa, 0x7d, 0xd0, 0x3c, 0x6a, 0xfd, 0x09, 0x39, 0xdd, 0xca, 0x81, 0x86, - 0xc6, 0xa9, 0x23, 0xaa, 0x0f, 0xde, 0xd6, 0xaf, 0xfe, 0xf9, 0x9a, 0x22, 0x3e, 0xd3, 0x6b, 0x87, 0x17, 0xac, 0x9a, - 0xf8, 0xa1, 0xbe, 0xc0, 0x3e, 0x66, 0x93, 0xc0, 0xfd, 0x9c, 0xa9, 0x7e, 0xed, 0xaa, 0xfa, 0x0a, 0x32, 0x2a, 0xaa, - 0x26, 0x02, 0x2d, 0x95, 0x2f, 0x9e, 0x65, 0x9e, 0x58, 0xad, 0x02, 0x01, 0x8e, 0x58, 0xe2, 0xe0, 0x14, 0x9e, 0x51, - 0x0d, 0xc9, 0x02, 0x97, 0x00, 0x29, 0x04, 0x13, 0xa1, 0xff, 0xaf, 0x8a, 0xed, 0x0f, 0xe3, 0x5e, 0x09, 0xd3, 0x38, - 0x9b, 0x00, 0x15, 0xc6, 0xd9, 0x64, 0xc3, 0x79, 0xa3, 0xc3, 0x09, 0x6b, 0xa5, 0xd5, 0x50, 0x95, 0x93, 0x26, 0x7f, - 0x76, 0xfb, 0xde, 0xbc, 0x9f, 0xc9, 0x07, 0x1f, 0xa8, 0xf2, 0x7d, 0x57, 0xef, 0x92, 0x6d, 0x90, 0x07, 0xfa, 0x03, - 0xe1, 0x2a, 0x21, 0x0d, 0xa4, 0x1f, 0x5c, 0xea, 0xf3, 0x8c, 0xcd, 0x43, 0x7c, 0x2d, 0xfb, 0x12, 0x7a, 0xc5, 0x46, - 0x46, 0x84, 0x61, 0xcf, 0x5c, 0x6c, 0x6e, 0xaa, 0xad, 0x21, 0x6d, 0xac, 0xad, 0xfe, 0x51, 0xac, 0x32, 0x8c, 0x49, - 0xc6, 0xfd, 0xde, 0x83, 0xf2, 0xeb, 0x8c, 0xbb, 0x36, 0x01, 0xbe, 0x5a, 0x3e, 0x10, 0x34, 0xfd, 0x67, 0xf2, 0x00, - 0xbe, 0x5b, 0xfe, 0x60, 0x08, 0x9f, 0xcc, 0x0e, 0x95, 0x28, 0x78, 0x50, 0x7d, 0xbe, 0x1c, 0xf8, 0x60, 0xe3, 0x66, - 0x96, 0xe2, 0xfb, 0x8a, 0x6f, 0x23, 0xaa, 0x3b, 0x8f, 0x2a, 0x51, 0xdd, 0x79, 0xe4, 0x4a, 0xcf, 0xb6, 0xd7, 0xee, - 0x84, 0x8f, 0x1c, 0x01, 0x70, 0xd5, 0x84, 0xff, 0x6b, 0x22, 0xe0, 0x61, 0xf8, 0xa8, 0x94, 0x01, 0xaf, 0xda, 0x9d, - 0xf0, 0x48, 0x8b, 0x9b, 0x4e, 0xf8, 0xe8, 0x07, 0xc5, 0xa0, 0x35, 0x73, 0xae, 0x1f, 0x88, 0x2d, 0xa1, 0x1a, 0x9d, - 0x54, 0xe7, 0xe3, 0xa0, 0xfc, 0x06, 0x9c, 0x39, 0x9f, 0xc6, 0x25, 0xf4, 0x3c, 0x16, 0xf0, 0x21, 0x8e, 0xfa, 0xd9, - 0xad, 0xd5, 0xe1, 0x1a, 0xbf, 0xd8, 0x32, 0x05, 0x9c, 0x70, 0x1f, 0xbb, 0x37, 0x83, 0xe1, 0x5a, 0xad, 0x7a, 0x6d, - 0xb1, 0x7d, 0x7b, 0xdb, 0x6e, 0xd2, 0xd6, 0x0d, 0xed, 0x1b, 0xe2, 0x14, 0xb3, 0x60, 0xea, 0x15, 0xf1, 0x6a, 0x92, - 0x2f, 0x93, 0x62, 0x7d, 0x7e, 0xc8, 0xed, 0x13, 0xdc, 0xb9, 0x1c, 0x4d, 0xab, 0x04, 0xf4, 0x84, 0xc1, 0x75, 0xf6, - 0xa2, 0xb0, 0xa0, 0xd7, 0x9c, 0x81, 0x15, 0x96, 0x14, 0xbf, 0xa0, 0x79, 0xdf, 0x87, 0x22, 0x3f, 0xf2, 0x95, 0x23, - 0xc9, 0x2f, 0x3f, 0x46, 0x52, 0x12, 0x76, 0x55, 0x80, 0xd5, 0x25, 0x12, 0x38, 0xb5, 0x80, 0x1f, 0x1f, 0x1d, 0x1c, - 0xec, 0x3c, 0x2f, 0x4a, 0x1b, 0x83, 0xb5, 0x56, 0x1f, 0x31, 0x70, 0x59, 0x91, 0xef, 0x22, 0xba, 0x1c, 0x57, 0xa1, - 0x10, 0x19, 0x3c, 0x5d, 0xd2, 0x58, 0x86, 0x71, 0xa6, 0x53, 0x14, 0x1c, 0x86, 0x85, 0xdb, 0xf4, 0x08, 0x15, 0x5c, - 0xc6, 0xce, 0x57, 0x4a, 0xcd, 0x39, 0xe7, 0x32, 0xb6, 0x57, 0xfd, 0x32, 0x59, 0xcb, 0x85, 0x9f, 0x76, 0x7a, 0x6f, - 0xdf, 0x9f, 0x78, 0xfa, 0x78, 0x1e, 0x1f, 0x4e, 0x3b, 0xbd, 0x63, 0x65, 0x99, 0xeb, 0x8b, 0x42, 0x44, 0x5f, 0x14, - 0xf2, 0xcc, 0xa5, 0x31, 0x88, 0xd7, 0x14, 0x87, 0x7a, 0xd9, 0xbe, 0x47, 0xb3, 0x91, 0xf6, 0x29, 0xce, 0x16, 0xa9, - 0x64, 0xf0, 0x0a, 0xde, 0x43, 0xe8, 0xda, 0x84, 0x0d, 0x2b, 0x13, 0x4d, 0xad, 0x86, 0x23, 0x33, 0xeb, 0x81, 0x1c, - 0xb3, 0x94, 0xda, 0xd4, 0x52, 0x33, 0x54, 0x99, 0xf9, 0xbc, 0xd9, 0x3a, 0x5f, 0x5c, 0xce, 0x98, 0xf4, 0x6d, 0x7e, - 0xf6, 0x07, 0xd3, 0xe1, 0x58, 0x4d, 0xd5, 0xbb, 0x28, 0x8c, 0x8b, 0xd4, 0x7e, 0x6e, 0x64, 0xed, 0x03, 0xef, 0x7a, - 0xf5, 0x46, 0x42, 0xc0, 0x8d, 0x9f, 0xe9, 0x51, 0xaf, 0x74, 0x4a, 0xba, 0x75, 0xc5, 0xf1, 0xe1, 0xf4, 0xa8, 0x77, - 0x11, 0xcd, 0xcd, 0x78, 0xaf, 0xf8, 0xc6, 0xc7, 0xe2, 0x4b, 0x8e, 0xd9, 0x57, 0xa9, 0xed, 0xfa, 0x0e, 0xa5, 0x01, - 0x78, 0xc4, 0x53, 0xbf, 0x77, 0x6c, 0x94, 0x01, 0x4f, 0x05, 0x5d, 0xfd, 0x47, 0x2d, 0x9b, 0x2d, 0x9f, 0x72, 0xa5, - 0x2d, 0xe9, 0x2e, 0xce, 0x24, 0x35, 0xbf, 0xee, 0xb4, 0xdd, 0x3b, 0x8e, 0x8d, 0x9a, 0x09, 0xcc, 0x23, 0x8f, 0x0e, - 0xa1, 0x33, 0xe8, 0x72, 0x21, 0xe3, 0x87, 0xd7, 0xf4, 0xb2, 0x19, 0xcf, 0x59, 0xe5, 0x44, 0x05, 0xa5, 0xa3, 0x9c, - 0x92, 0x57, 0x33, 0xc1, 0xcf, 0x78, 0x6d, 0x91, 0x8a, 0x85, 0x17, 0xc6, 0x43, 0xab, 0x74, 0x75, 0x1a, 0x4b, 0xdf, - 0xd3, 0x1c, 0xde, 0x7a, 0x72, 0x8d, 0xec, 0x2d, 0xfc, 0xde, 0xbf, 0xfd, 0x8f, 0xff, 0x65, 0x9c, 0xb3, 0xc7, 0x87, - 0xd3, 0xb6, 0x1d, 0x6b, 0x0d, 0xd1, 0xc5, 0x31, 0x5c, 0x30, 0xab, 0xa2, 0x89, 0xf4, 0xa6, 0x39, 0x11, 0x2c, 0x69, - 0x4e, 0xe3, 0x74, 0xec, 0xf7, 0x76, 0x23, 0xc8, 0xbd, 0x59, 0x62, 0xa0, 0xae, 0x17, 0x01, 0x09, 0xfe, 0xa6, 0xbb, - 0x11, 0x36, 0xc5, 0x5e, 0x9d, 0x56, 0xf7, 0xa6, 0x44, 0x75, 0xa0, 0x6a, 0xb7, 0x25, 0x84, 0xf9, 0x2a, 0x91, 0x61, - 0x6a, 0xa2, 0x76, 0x49, 0xa2, 0xf0, 0xbd, 0x32, 0x1a, 0xf2, 0x7f, 0xff, 0xe7, 0x7f, 0xf9, 0x6f, 0xf6, 0x11, 0x82, - 0x1c, 0xff, 0xf6, 0xdf, 0xff, 0xf3, 0xff, 0xf9, 0xdf, 0xff, 0x15, 0x12, 0xeb, 0x4d, 0x20, 0x44, 0xf1, 0x09, 0xaf, - 0x8a, 0x82, 0x68, 0x86, 0xe1, 0x41, 0x32, 0xda, 0x8c, 0xe5, 0x92, 0x8d, 0xea, 0xd7, 0x26, 0xce, 0xd4, 0x84, 0xea, - 0xb0, 0x19, 0xe8, 0xd4, 0xa1, 0x2d, 0x2a, 0x1a, 0xa9, 0xa1, 0x5c, 0xd1, 0x62, 0x71, 0x7c, 0x08, 0xf8, 0xbe, 0xdf, - 0x4d, 0xb3, 0xb0, 0xdc, 0x8e, 0xa5, 0x75, 0xfd, 0x41, 0x49, 0x51, 0x95, 0x7b, 0xe0, 0x94, 0x5f, 0xc2, 0x63, 0xd4, - 0x71, 0x8a, 0xd5, 0xee, 0xd5, 0xfa, 0x74, 0x7f, 0x5a, 0xe4, 0x92, 0x8d, 0x01, 0xe5, 0xda, 0xc1, 0xa8, 0xe2, 0x9f, - 0x4d, 0x50, 0xff, 0xd2, 0xdb, 0x42, 0x8d, 0xa2, 0x6d, 0xc6, 0x87, 0x4f, 0xff, 0x54, 0xfc, 0x65, 0x06, 0x4a, 0x96, - 0x17, 0xcc, 0xe2, 0x1b, 0x63, 0x49, 0x3e, 0x6e, 0xb5, 0xe6, 0x37, 0x68, 0x59, 0xcd, 0x80, 0x77, 0x4d, 0xa6, 0x9c, - 0x92, 0xee, 0x80, 0x2a, 0x70, 0x5a, 0xfa, 0x3f, 0x5b, 0x1e, 0x38, 0x51, 0xbd, 0x56, 0x51, 0xfc, 0x79, 0xa9, 0x5c, - 0x70, 0xec, 0x17, 0x08, 0x70, 0x1a, 0x6f, 0xe5, 0x25, 0x77, 0x17, 0xb7, 0x74, 0x7a, 0x75, 0x74, 0xaf, 0x69, 0x7b, - 0xf3, 0x02, 0x95, 0x1b, 0xa0, 0x75, 0x43, 0xab, 0x0f, 0x21, 0x58, 0x3a, 0x6d, 0xe3, 0x69, 0x67, 0x59, 0x0e, 0x2f, - 0x25, 0x9f, 0xb9, 0x11, 0x59, 0x1a, 0xd3, 0x11, 0x1d, 0x5b, 0x2f, 0xaf, 0xa9, 0xd7, 0xd1, 0xd6, 0x62, 0x7a, 0xb4, - 0x65, 0x2e, 0x03, 0x92, 0x8a, 0xc4, 0x7a, 0xad, 0xe2, 0x33, 0x38, 0x81, 0xcb, 0x71, 0xca, 0x63, 0x19, 0x29, 0x82, - 0xed, 0xba, 0x71, 0xdd, 0x18, 0xd8, 0x0c, 0x5f, 0x3a, 0xf0, 0x74, 0x75, 0x53, 0xf0, 0xb7, 0xd6, 0xaf, 0xb9, 0x15, - 0xa1, 0xea, 0xee, 0x0e, 0xa5, 0xdd, 0x35, 0xdf, 0x9a, 0x70, 0xe9, 0x9b, 0x9a, 0x9f, 0xc3, 0xc8, 0x98, 0x0e, 0xda, - 0x5e, 0xaf, 0x45, 0xb5, 0xae, 0xfd, 0x4a, 0x06, 0xbe, 0x02, 0xd3, 0x5f, 0x6f, 0xa5, 0x0a, 0xa1, 0xd5, 0x1b, 0xf2, - 0x6d, 0x69, 0x05, 0xc5, 0xf3, 0xb9, 0x6a, 0x88, 0xba, 0xc7, 0x87, 0x5a, 0x79, 0x05, 0xee, 0xa1, 0x72, 0x01, 0x74, - 0xe8, 0xdd, 0x34, 0x32, 0x47, 0x41, 0xff, 0x32, 0x41, 0x79, 0xf8, 0x5c, 0x55, 0xef, 0xff, 0x01, 0xb9, 0x37, 0x65, - 0xfc, 0x3f, 0x86, 0x00, 0x00}; + 0xae, 0x27, 0x4f, 0x9e, 0x3c, 0x7b, 0x02, 0xc7, 0x7b, 0xb1, 0x18, 0xc9, 0xdb, 0x39, 0xf3, 0xa6, 0x72, 0x96, 0xf4, + 0x8e, 0xcd, 0xbf, 0x2c, 0x8a, 0x7b, 0xc7, 0x09, 0x4f, 0x3f, 0x7a, 0x19, 0x4b, 0x28, 0x1f, 0x89, 0xd4, 0x9b, 0x66, + 0x6c, 0x4c, 0xe3, 0x48, 0x46, 0x21, 0x9f, 0x45, 0x13, 0xe6, 0x1d, 0xf6, 0x8e, 0x67, 0x4c, 0x46, 0xde, 0x68, 0x1a, + 0x65, 0x39, 0x93, 0xf4, 0xc3, 0xfb, 0x2f, 0x9a, 0x4f, 0x7b, 0xc7, 0xf9, 0x28, 0xe3, 0x73, 0xe9, 0xc1, 0x90, 0x74, + 0x26, 0xe2, 0x45, 0xc2, 0x7a, 0x87, 0x87, 0xd7, 0xd7, 0xd7, 0xc1, 0x4f, 0xf9, 0x3f, 0x8d, 0x44, 0x9a, 0x4b, 0xef, + 0x15, 0xbd, 0xe6, 0x69, 0x2c, 0xae, 0x09, 0x93, 0xf4, 0x55, 0x70, 0x36, 0x8d, 0x62, 0x71, 0xfd, 0x4e, 0x08, 0x79, + 0x70, 0xe0, 0xeb, 0xc7, 0xdb, 0xd3, 0xb3, 0x33, 0x4a, 0xe9, 0x95, 0xe0, 0xb1, 0xd7, 0x5a, 0xad, 0xaa, 0xc2, 0x20, + 0x8d, 0x24, 0xbf, 0x62, 0xba, 0x0b, 0x3e, 0x38, 0x40, 0x51, 0x2c, 0xe6, 0x92, 0xc5, 0x67, 0xf2, 0x36, 0x61, 0x67, + 0x53, 0xc6, 0x64, 0x8e, 0x78, 0xea, 0x3d, 0x17, 0xa3, 0xc5, 0x8c, 0xa5, 0x32, 0x98, 0x67, 0x42, 0x0a, 0x80, 0xe4, + 0xe0, 0x00, 0x65, 0x6c, 0x9e, 0x44, 0x23, 0x06, 0xf5, 0xa7, 0x67, 0x67, 0x55, 0x8f, 0xaa, 0x11, 0xe1, 0x92, 0x9e, + 0xdd, 0xce, 0x2e, 0x45, 0xe2, 0x63, 0x92, 0x48, 0x9a, 0xb2, 0x6b, 0xef, 0x3b, 0x16, 0x7d, 0x7c, 0x1d, 0xcd, 0xbb, + 0xa3, 0x24, 0xca, 0x73, 0xef, 0x52, 0x2e, 0xd5, 0x12, 0xb2, 0xc5, 0x48, 0x8a, 0xcc, 0x97, 0x84, 0x11, 0x8e, 0x97, + 0x7c, 0xec, 0xcb, 0x29, 0xcf, 0x83, 0xf3, 0xfd, 0x51, 0x9e, 0xbf, 0x63, 0xf9, 0x22, 0x91, 0xfb, 0x74, 0xaf, 0x45, + 0xf8, 0x1e, 0xa5, 0x5c, 0x62, 0x39, 0xcd, 0xc4, 0xb5, 0xf7, 0x22, 0xcb, 0x44, 0xe6, 0xa3, 0xd3, 0xb3, 0x33, 0xdd, + 0xc2, 0xe3, 0xb9, 0x97, 0x0a, 0xe9, 0x95, 0xe3, 0x45, 0x97, 0x09, 0x0b, 0xbc, 0x0f, 0x39, 0xf3, 0x2e, 0x16, 0x69, + 0x1e, 0x8d, 0xd9, 0xe9, 0xd9, 0xd9, 0x85, 0x27, 0x32, 0xef, 0x62, 0x94, 0xe7, 0x17, 0x1e, 0x4f, 0x73, 0xc9, 0xa2, + 0x38, 0x40, 0xb8, 0xab, 0x26, 0x1b, 0xe5, 0xf9, 0x7b, 0x76, 0x23, 0xa9, 0x24, 0xea, 0x51, 0x52, 0x56, 0x4c, 0x98, + 0xf4, 0xf2, 0x72, 0x5d, 0x3e, 0x5e, 0x26, 0x4c, 0x7a, 0x92, 0xaa, 0x7a, 0xd1, 0xd5, 0xb8, 0x67, 0xfa, 0x51, 0x76, + 0xf9, 0xd8, 0x67, 0xf2, 0xe0, 0x40, 0x96, 0x78, 0xc6, 0x7a, 0x69, 0x1e, 0xa7, 0x6c, 0xcf, 0x96, 0x1d, 0x1c, 0xb0, + 0x20, 0x61, 0xe9, 0x44, 0x4e, 0x29, 0xa5, 0xed, 0x2e, 0x3f, 0x38, 0xf0, 0x25, 0x4d, 0x64, 0x30, 0x61, 0xd2, 0x67, + 0x18, 0x93, 0xaa, 0xf7, 0xc1, 0x81, 0xaf, 0x91, 0x20, 0xa8, 0x46, 0x5c, 0x0d, 0xc7, 0x38, 0x30, 0xd8, 0x3f, 0xbb, + 0x4d, 0x47, 0xbe, 0x0b, 0x3f, 0x26, 0xfc, 0xe0, 0x20, 0x91, 0x41, 0x0e, 0x23, 0x12, 0x89, 0x71, 0x91, 0x31, 0xb9, + 0xc8, 0x52, 0x4f, 0x16, 0x52, 0x9c, 0xc9, 0x8c, 0xa7, 0x13, 0x1f, 0x2f, 0x6d, 0x99, 0xd3, 0xb1, 0x28, 0x34, 0xb8, + 0x5f, 0x4b, 0x9a, 0xd1, 0x1e, 0xcc, 0x78, 0x29, 0x7d, 0xd8, 0x45, 0x31, 0xf6, 0x32, 0x4a, 0x51, 0xae, 0xfa, 0xa2, + 0x7e, 0x16, 0x66, 0x0d, 0x84, 0x88, 0x86, 0x92, 0x70, 0x89, 0xc9, 0x47, 0xea, 0x67, 0x24, 0x08, 0x02, 0x89, 0x69, + 0x6f, 0x69, 0xb1, 0x92, 0x39, 0xeb, 0xec, 0x67, 0x83, 0xd6, 0x30, 0x94, 0x41, 0xc6, 0xe2, 0xc5, 0x88, 0xf9, 0x3e, + 0x27, 0x39, 0x49, 0x31, 0xed, 0xf1, 0x86, 0x2f, 0x68, 0x0f, 0xb6, 0x5b, 0xd4, 0xf7, 0x9a, 0xd2, 0xbd, 0x16, 0x36, + 0x30, 0x0a, 0x0b, 0x20, 0x60, 0xd8, 0xc0, 0x23, 0x28, 0x45, 0xe9, 0x62, 0x76, 0xc9, 0x32, 0x54, 0x36, 0xeb, 0xd6, + 0xc8, 0x62, 0x91, 0x33, 0x6f, 0x94, 0xe7, 0xde, 0x78, 0x91, 0x8e, 0x24, 0x17, 0xa9, 0x87, 0x1a, 0xa2, 0x81, 0x34, + 0x39, 0x94, 0xd4, 0x80, 0x70, 0x81, 0xfd, 0x1c, 0x37, 0xb2, 0x41, 0xda, 0x68, 0x0f, 0x09, 0x40, 0x89, 0xbb, 0x66, + 0x3c, 0x83, 0x00, 0x46, 0x32, 0x58, 0x63, 0x41, 0x3e, 0x48, 0x58, 0xa5, 0x5a, 0x22, 0x93, 0xfd, 0x2c, 0xd8, 0x3c, + 0x28, 0x54, 0x06, 0xb3, 0x68, 0xee, 0x33, 0xda, 0x63, 0x8a, 0xb8, 0xa2, 0x74, 0x04, 0xb0, 0xd6, 0xf6, 0xad, 0xcf, + 0x42, 0x16, 0x54, 0x24, 0x85, 0x43, 0x19, 0x8c, 0x45, 0xf6, 0x22, 0x1a, 0x4d, 0xa1, 0x5f, 0x49, 0x30, 0xb1, 0x3d, + 0x6f, 0xa3, 0x8c, 0x45, 0x92, 0xbd, 0x48, 0x18, 0x3c, 0xf9, 0x48, 0xf5, 0x44, 0x98, 0xe4, 0xf4, 0x55, 0x90, 0x70, + 0xf9, 0x46, 0xa4, 0x23, 0xd6, 0xcd, 0x1d, 0xea, 0xe2, 0xb0, 0xef, 0x27, 0x52, 0x66, 0xfc, 0x72, 0x21, 0x99, 0x8f, + 0x52, 0x68, 0x81, 0x48, 0x8e, 0x09, 0x0f, 0x24, 0xbb, 0x91, 0xa7, 0x22, 0x95, 0x2c, 0x95, 0x94, 0x59, 0xa4, 0x92, + 0x2c, 0x88, 0xe6, 0x73, 0x96, 0xc6, 0xa7, 0x53, 0x9e, 0xc4, 0x3e, 0xc7, 0x05, 0x2e, 0x48, 0x24, 0x29, 0xac, 0x91, + 0xf6, 0xb2, 0x10, 0xfe, 0xd9, 0xbd, 0x1a, 0x5f, 0xd2, 0x9e, 0x3a, 0x14, 0x8c, 0x22, 0xd4, 0x1d, 0x8b, 0xcc, 0x37, + 0x2b, 0xf0, 0xc4, 0xd8, 0x93, 0x30, 0xc7, 0xbb, 0x45, 0xc2, 0x72, 0xcc, 0x1a, 0x94, 0x97, 0xdb, 0x68, 0x10, 0xfc, + 0x35, 0x50, 0x7c, 0x81, 0xfd, 0x0c, 0x87, 0x59, 0xf7, 0x2a, 0xca, 0xbc, 0x2f, 0xcc, 0x89, 0xfa, 0xc9, 0x72, 0xb3, + 0xa9, 0xa4, 0x3f, 0x05, 0x32, 0x5b, 0xe4, 0x92, 0xc5, 0xef, 0x6f, 0xe7, 0x2c, 0x27, 0xef, 0x25, 0x9d, 0xca, 0xfe, + 0x54, 0x06, 0x6c, 0x36, 0x97, 0xb7, 0x67, 0x8a, 0x31, 0x86, 0x08, 0x91, 0x11, 0xb4, 0xcc, 0x58, 0x34, 0x02, 0x66, + 0x66, 0xb0, 0xf5, 0xb5, 0x48, 0x6e, 0xc7, 0x3c, 0x49, 0xce, 0x16, 0xf3, 0xb9, 0xc8, 0x24, 0xf9, 0x2b, 0x5d, 0x4a, + 0x51, 0xa1, 0x06, 0xf6, 0x72, 0x99, 0x5f, 0x73, 0x39, 0x9a, 0xfa, 0x12, 0x2f, 0x47, 0x51, 0xce, 0xbc, 0x67, 0x42, + 0x24, 0x2c, 0x4a, 0xc3, 0x8c, 0x66, 0xfd, 0xf7, 0x32, 0x4c, 0x17, 0x49, 0xd2, 0xbd, 0xcc, 0x58, 0xf4, 0xb1, 0xab, + 0xaa, 0xdf, 0x5e, 0xfe, 0xc4, 0x46, 0x32, 0x54, 0xbf, 0x4f, 0xb2, 0x2c, 0xba, 0x85, 0x86, 0x94, 0x42, 0xb3, 0x7e, + 0x16, 0x7e, 0x75, 0xf6, 0xf6, 0x4d, 0xa0, 0x0f, 0x09, 0x1f, 0xdf, 0xfa, 0x59, 0x79, 0xf0, 0xb2, 0x82, 0x8c, 0x33, + 0x31, 0x5b, 0x9b, 0x5a, 0x63, 0x2d, 0xeb, 0xee, 0x00, 0x81, 0xd1, 0x6c, 0x4f, 0x0f, 0xed, 0x42, 0xf0, 0x46, 0xd1, + 0x3c, 0x54, 0x52, 0x33, 0x2f, 0xfc, 0x13, 0xea, 0x62, 0x3f, 0xc3, 0x77, 0x43, 0x2b, 0xb3, 0xdb, 0x25, 0xa3, 0x0a, + 0xce, 0x39, 0x48, 0x18, 0x80, 0x71, 0x14, 0xc9, 0xd1, 0x74, 0xc9, 0xd4, 0x60, 0x85, 0x85, 0x98, 0x15, 0x05, 0xb9, + 0x2e, 0xe9, 0x5d, 0xee, 0x51, 0x9a, 0x29, 0x46, 0x45, 0xe5, 0x6a, 0x95, 0x51, 0x9a, 0x61, 0xf2, 0x1d, 0x5d, 0x46, + 0x76, 0x3d, 0xe1, 0x5e, 0x8b, 0xc0, 0xb9, 0x0c, 0x35, 0x77, 0x21, 0x23, 0x91, 0x5e, 0xb1, 0x4c, 0xb2, 0x2c, 0xfc, + 0x2b, 0xc9, 0xd8, 0x38, 0x01, 0x28, 0xf6, 0xda, 0x64, 0x1a, 0xe5, 0xa7, 0xd3, 0x28, 0x9d, 0xb0, 0x38, 0xbc, 0x96, + 0x05, 0xf9, 0x3b, 0x45, 0x63, 0x9e, 0x46, 0x09, 0xff, 0x85, 0xc5, 0xc8, 0x48, 0x83, 0x13, 0x8f, 0xdd, 0x48, 0x96, + 0xc6, 0xb9, 0xf7, 0xf2, 0xfd, 0xeb, 0x57, 0x66, 0x1f, 0x6b, 0x02, 0x02, 0x2f, 0xf3, 0xc5, 0x9c, 0x65, 0x3e, 0x26, + 0x46, 0x40, 0xbc, 0xe0, 0x8a, 0x39, 0xbe, 0x8e, 0xe6, 0xba, 0x84, 0xe7, 0x1f, 0xe6, 0x71, 0x24, 0xd9, 0xd7, 0x2c, + 0x8d, 0x79, 0x3a, 0xa1, 0x7b, 0x6d, 0x5d, 0x3e, 0x8d, 0x4c, 0x45, 0x5c, 0x16, 0x9d, 0xef, 0xbf, 0x48, 0xd4, 0xba, + 0xcb, 0xc7, 0x85, 0x8f, 0x8b, 0x5c, 0x46, 0x92, 0x8f, 0xbc, 0x28, 0x8e, 0xbf, 0x4c, 0xb9, 0xe4, 0x0a, 0xc0, 0x0c, + 0xb6, 0x07, 0x48, 0x94, 0x69, 0x51, 0x61, 0x01, 0xf7, 0x31, 0xf1, 0x7d, 0x23, 0x00, 0xa6, 0xd8, 0xec, 0xd7, 0xc1, + 0x41, 0xc5, 0xee, 0xfb, 0x2c, 0xd4, 0x95, 0x74, 0x30, 0xc4, 0xc1, 0x7c, 0x91, 0xc3, 0x46, 0xdb, 0x29, 0x40, 0xba, + 0x88, 0xcb, 0x9c, 0x65, 0x57, 0x2c, 0x2e, 0x89, 0x23, 0xf7, 0xf1, 0x72, 0x6d, 0x0e, 0x73, 0x2c, 0x24, 0x1d, 0x0c, + 0xbb, 0x2e, 0xdf, 0x66, 0x86, 0xce, 0x33, 0x31, 0x67, 0x99, 0xe4, 0x2c, 0x2f, 0x59, 0x89, 0x0f, 0x52, 0xb4, 0x64, + 0x27, 0x39, 0xb5, 0xeb, 0x9b, 0xfb, 0x9c, 0x30, 0x5c, 0x63, 0x18, 0x56, 0xd0, 0xbe, 0xb8, 0x52, 0x12, 0x23, 0x27, + 0x1c, 0x13, 0xa9, 0x21, 0xcd, 0x31, 0x2e, 0x30, 0x91, 0x16, 0x5c, 0xcd, 0x8a, 0xcc, 0x6c, 0xb7, 0x20, 0xaa, 0xe9, + 0x77, 0x4a, 0x54, 0x03, 0x43, 0x8b, 0x24, 0x3b, 0x38, 0xf0, 0x59, 0x50, 0x12, 0x05, 0xdd, 0x6b, 0x9b, 0x3d, 0x72, + 0x90, 0xb5, 0x03, 0x6c, 0x98, 0x58, 0x12, 0x86, 0xc9, 0x1e, 0x0b, 0x52, 0x71, 0x32, 0x1a, 0xb1, 0x3c, 0x17, 0xd9, + 0xc1, 0xc1, 0x9e, 0x6a, 0x5f, 0x6a, 0x13, 0xb0, 0x87, 0x6f, 0xaf, 0xd3, 0x0a, 0x02, 0x5c, 0x49, 0x58, 0x23, 0x17, + 0x24, 0xc8, 0x29, 0xa5, 0x70, 0xa0, 0xbe, 0x55, 0x3c, 0x42, 0x74, 0x7e, 0x8e, 0x1a, 0x92, 0x18, 0x34, 0x4c, 0x98, + 0x9d, 0xfa, 0xf6, 0x39, 0xd3, 0xaa, 0x95, 0x52, 0x3c, 0x36, 0x30, 0xa3, 0xcf, 0x4f, 0x10, 0xb3, 0x31, 0x4f, 0x9d, + 0x65, 0xd7, 0x40, 0x22, 0x92, 0xe4, 0xb8, 0x70, 0x36, 0x74, 0xeb, 0xd0, 0x4a, 0xa7, 0xd1, 0x3b, 0xb7, 0x9c, 0x28, + 0x3d, 0xc2, 0xd9, 0xc6, 0x01, 0x1b, 0x16, 0x44, 0xa1, 0xde, 0xae, 0x26, 0x55, 0x80, 0x0e, 0xe4, 0xb0, 0x6b, 0xea, + 0x69, 0xae, 0x31, 0x97, 0xb1, 0x9f, 0x17, 0x2c, 0x97, 0x9a, 0x8e, 0x7d, 0x49, 0x52, 0xc2, 0x71, 0x01, 0xc7, 0x6d, + 0xcc, 0x27, 0x8b, 0x0c, 0xd4, 0x1d, 0x38, 0x8a, 0x2c, 0x5d, 0xcc, 0x98, 0x7d, 0xda, 0x06, 0xdb, 0xdb, 0x39, 0x08, + 0xc4, 0x1c, 0x68, 0xfa, 0x6e, 0x72, 0x02, 0x58, 0x25, 0x5e, 0xad, 0xbe, 0xb3, 0x83, 0x54, 0x5b, 0x59, 0xaa, 0x68, + 0x6b, 0x7b, 0xf2, 0x77, 0x6c, 0xe4, 0xf1, 0x5e, 0x5b, 0x43, 0xff, 0xf7, 0x21, 0xdd, 0x6b, 0x95, 0x14, 0x6c, 0x70, + 0xaa, 0x81, 0xd1, 0x28, 0x7c, 0xab, 0x07, 0xc2, 0x4a, 0xba, 0xd7, 0x88, 0x25, 0x98, 0x6e, 0xd0, 0xe9, 0x94, 0x0e, + 0x40, 0xcf, 0x08, 0xa6, 0xc3, 0x5d, 0xc4, 0x64, 0xb9, 0x81, 0x2f, 0x37, 0xeb, 0x2a, 0xa6, 0x71, 0x55, 0x67, 0x1a, + 0x6b, 0x8b, 0x40, 0xf3, 0xb2, 0x0b, 0x2a, 0x69, 0xcc, 0x1c, 0xf3, 0xaa, 0x8a, 0x70, 0x05, 0x4c, 0xb5, 0x24, 0x67, + 0x88, 0x37, 0xd1, 0x8c, 0xe5, 0x3e, 0xc3, 0x64, 0x57, 0x03, 0x4d, 0x9c, 0xd0, 0x64, 0xe8, 0x88, 0xcd, 0x1c, 0xc4, + 0x26, 0xc7, 0x5a, 0x2b, 0xab, 0x1f, 0xb7, 0x9c, 0xb0, 0x41, 0x3e, 0xac, 0x94, 0x39, 0x67, 0xf1, 0x4a, 0x1e, 0x1b, + 0xea, 0xb6, 0xf8, 0xd3, 0x65, 0x1a, 0x69, 0x4a, 0x69, 0xc8, 0x31, 0xd9, 0x6b, 0xad, 0xef, 0xa3, 0x6d, 0x55, 0xad, + 0x71, 0x30, 0x84, 0x7d, 0x50, 0xe2, 0x22, 0xe0, 0xb9, 0xfa, 0xbf, 0x76, 0xce, 0x00, 0x6d, 0x67, 0x40, 0x16, 0xc1, + 0x38, 0x89, 0xa4, 0xdf, 0x3e, 0x6c, 0x81, 0x26, 0x7a, 0xc5, 0x40, 0x9a, 0x60, 0xbc, 0xb9, 0x14, 0x16, 0x2c, 0xd2, + 0x7c, 0xca, 0xc7, 0xd2, 0x8f, 0xa4, 0x62, 0x28, 0x2c, 0xc9, 0x99, 0x27, 0x6b, 0xfa, 0xb0, 0x62, 0x36, 0x11, 0x90, + 0x5a, 0xa9, 0x7c, 0x31, 0x0b, 0xa9, 0x62, 0x5a, 0xc0, 0x1b, 0x2a, 0x5d, 0xba, 0xe2, 0x31, 0xb6, 0x35, 0x07, 0x7d, + 0xb1, 0xdd, 0xd7, 0x23, 0x86, 0x86, 0x15, 0x70, 0x47, 0x65, 0xe5, 0xa1, 0xcb, 0x1f, 0x4c, 0xa1, 0x0c, 0xa4, 0x78, + 0x25, 0xae, 0x59, 0x76, 0x1a, 0x01, 0xf0, 0xa1, 0xee, 0x5e, 0x68, 0x31, 0xa0, 0xb8, 0xbd, 0xec, 0x5a, 0x7a, 0x39, + 0x57, 0x0b, 0xff, 0x3a, 0x13, 0x33, 0x9e, 0x33, 0xd0, 0xd4, 0x34, 0xfe, 0x53, 0x38, 0x65, 0xea, 0x38, 0x82, 0xa8, + 0x61, 0x25, 0x7d, 0x9d, 0xbc, 0xaa, 0xd3, 0xd7, 0xf9, 0xfe, 0x8b, 0x89, 0x65, 0x7f, 0xf5, 0x43, 0x8c, 0x89, 0x6f, + 0xec, 0x09, 0x47, 0xca, 0x05, 0x53, 0x6c, 0xc4, 0xfb, 0x6a, 0x25, 0x1d, 0xb3, 0xad, 0xa6, 0x2b, 0x32, 0x7d, 0x6c, + 0x70, 0x11, 0xc5, 0x31, 0x68, 0x75, 0x99, 0x48, 0x12, 0x47, 0x50, 0x11, 0xde, 0x2d, 0x45, 0xd3, 0xf9, 0xfe, 0x8b, + 0xb3, 0xbb, 0xa4, 0x13, 0xd4, 0xbb, 0x02, 0xca, 0x02, 0x9a, 0xc6, 0x2c, 0x03, 0x33, 0xd2, 0xd9, 0x2d, 0x23, 0x63, + 0x4f, 0x45, 0x9a, 0xb2, 0x91, 0x64, 0x31, 0x58, 0x29, 0x9c, 0xca, 0x60, 0x2a, 0x72, 0x59, 0x16, 0x56, 0xd0, 0x73, + 0x07, 0x7a, 0x1e, 0x8c, 0xa2, 0x24, 0xf1, 0xb5, 0x45, 0x32, 0x13, 0x57, 0x6c, 0x0b, 0xd4, 0xdd, 0x1a, 0xc8, 0xe5, + 0x30, 0xcc, 0x19, 0x86, 0x05, 0xf9, 0x3c, 0xe1, 0x23, 0x56, 0x0a, 0xae, 0xb3, 0x80, 0xa7, 0x31, 0xbb, 0x01, 0x3e, + 0x82, 0x7b, 0xbd, 0x5e, 0x8b, 0xb4, 0x71, 0xa1, 0x11, 0xbe, 0xdc, 0x40, 0xec, 0x1d, 0x22, 0x13, 0x88, 0x8c, 0xf6, + 0x96, 0xdb, 0xf8, 0x01, 0xc3, 0x8e, 0x9c, 0xe4, 0xd6, 0xb2, 0xd2, 0xbc, 0x19, 0x93, 0x98, 0x25, 0x4c, 0x32, 0xcb, + 0xcb, 0x41, 0x7f, 0xd6, 0x47, 0xf7, 0x5d, 0x89, 0xbf, 0x92, 0x9c, 0xec, 0x29, 0xb3, 0x7b, 0x9e, 0x97, 0x96, 0x7a, + 0xb5, 0x3d, 0x15, 0xb6, 0xfb, 0x52, 0x6f, 0x4f, 0x24, 0x65, 0x34, 0x9a, 0x6a, 0x13, 0xdd, 0xdf, 0x58, 0x52, 0x35, + 0x86, 0xe1, 0xeb, 0xe5, 0x21, 0xfa, 0x60, 0xc1, 0xdc, 0x86, 0x82, 0x33, 0xc3, 0x14, 0x18, 0x58, 0x7d, 0x7a, 0xdb, + 0x4e, 0xa3, 0x24, 0xb9, 0x8c, 0x46, 0x1f, 0xeb, 0xd4, 0x5f, 0x91, 0x01, 0x5d, 0xe7, 0xc6, 0x4e, 0x95, 0xc3, 0xb2, + 0xdc, 0x75, 0x5b, 0x2e, 0x5d, 0x3b, 0x28, 0xfe, 0x5e, 0xab, 0x22, 0xfb, 0xfa, 0x46, 0xef, 0xa4, 0x76, 0x05, 0x11, + 0x37, 0x2b, 0xf3, 0x81, 0x0b, 0x7c, 0x92, 0xe2, 0x2c, 0x3f, 0x30, 0x74, 0x07, 0xb6, 0x46, 0xb1, 0x06, 0x88, 0xc4, + 0xcb, 0x22, 0xe6, 0xf9, 0x6e, 0x0c, 0xfc, 0x21, 0x50, 0x3e, 0x77, 0x66, 0xb8, 0x2f, 0xa0, 0x25, 0x8f, 0x33, 0x2a, + 0x73, 0x09, 0x99, 0xd1, 0x26, 0x2c, 0xa3, 0xf9, 0x1b, 0x68, 0x2e, 0x8a, 0xde, 0xdf, 0xea, 0x2a, 0xd0, 0xc9, 0x00, + 0x8a, 0xbc, 0xeb, 0x2a, 0x13, 0x35, 0x0a, 0x30, 0x3c, 0x95, 0x2b, 0x91, 0x9b, 0xd6, 0x8c, 0x47, 0xa3, 0xae, 0x6b, + 0xfb, 0xdb, 0xb0, 0x5c, 0x41, 0x7d, 0xdf, 0xcf, 0xc1, 0x7e, 0xb3, 0x7a, 0x7d, 0xb5, 0x88, 0x7c, 0x63, 0x11, 0x79, + 0xe0, 0x18, 0x59, 0xb8, 0xa2, 0x65, 0xa7, 0x7b, 0xf8, 0x57, 0xec, 0x36, 0x02, 0x65, 0x35, 0x00, 0xfe, 0x8c, 0x4b, + 0x76, 0x9b, 0x50, 0x49, 0x84, 0x31, 0x70, 0x0c, 0xa5, 0x01, 0xc3, 0xa8, 0xba, 0xa4, 0x58, 0x1f, 0x8d, 0x9a, 0xb1, + 0x9b, 0x12, 0x81, 0xd7, 0x34, 0xfb, 0xa2, 0x30, 0x38, 0x62, 0xd8, 0xec, 0x4d, 0x4d, 0x25, 0x76, 0xb0, 0x42, 0x52, + 0x6a, 0xd4, 0x60, 0xad, 0xf5, 0xac, 0xe3, 0xa6, 0x1c, 0x17, 0x0e, 0x6a, 0x85, 0x9a, 0x9a, 0x3e, 0x69, 0x15, 0xab, + 0x14, 0x93, 0xa9, 0xd5, 0x48, 0x45, 0xb5, 0x6e, 0x4a, 0x91, 0xf5, 0x46, 0xa0, 0xfe, 0xb2, 0x66, 0x12, 0x86, 0x4e, + 0xb3, 0x22, 0x04, 0x96, 0x2a, 0xb6, 0xa1, 0x7b, 0x1b, 0xcd, 0xd4, 0xc6, 0x71, 0x10, 0x2e, 0x5c, 0x84, 0x3b, 0x98, + 0x4d, 0x35, 0xe7, 0x4a, 0x87, 0x74, 0x5a, 0xef, 0xeb, 0x33, 0x22, 0xf4, 0x3e, 0x6c, 0x20, 0x71, 0x5d, 0xf1, 0x54, + 0x24, 0x08, 0x06, 0x6c, 0x0e, 0xca, 0x9d, 0x2b, 0x1f, 0x7c, 0x80, 0x9d, 0xaf, 0x56, 0x1b, 0x44, 0xb7, 0x55, 0xff, + 0xc4, 0x41, 0x65, 0x14, 0xae, 0x56, 0xd7, 0x12, 0xfb, 0x46, 0xf3, 0x25, 0x0c, 0xf7, 0x2d, 0xc7, 0x3d, 0x79, 0x05, + 0xad, 0x94, 0x22, 0x5a, 0x95, 0x94, 0x26, 0x43, 0x9d, 0x66, 0xeb, 0xfb, 0x24, 0x1d, 0xb6, 0x7d, 0xba, 0xc1, 0xbd, + 0x54, 0xa1, 0x11, 0xd3, 0xd5, 0x92, 0x4f, 0xcd, 0xd0, 0x1c, 0x63, 0x1c, 0xe6, 0xca, 0x8a, 0xd9, 0xdb, 0x66, 0x58, + 0x1e, 0x1c, 0xe4, 0xce, 0x40, 0xe7, 0x25, 0x9b, 0xf8, 0xc9, 0x07, 0x91, 0x9c, 0xdf, 0xa6, 0x4a, 0x77, 0xf9, 0xc9, + 0x0a, 0xa1, 0x0d, 0xb3, 0xb4, 0xd5, 0x05, 0x6b, 0x3c, 0xba, 0x8e, 0xb8, 0xf4, 0xca, 0x51, 0xb4, 0x35, 0xee, 0x33, + 0xbc, 0x34, 0xaa, 0x46, 0x90, 0x31, 0x50, 0x1e, 0x81, 0x27, 0x58, 0x15, 0x5a, 0xd3, 0xfd, 0x68, 0xca, 0xc0, 0x11, + 0x6c, 0xb5, 0x88, 0xd2, 0x2e, 0xdc, 0x33, 0x52, 0xc4, 0x0c, 0xbc, 0x1d, 0xf6, 0x62, 0xbd, 0x7b, 0xcd, 0x0e, 0x98, + 0xb3, 0x6c, 0x2c, 0xb2, 0x99, 0xad, 0x2b, 0xd6, 0x9e, 0x0d, 0x67, 0xe4, 0x63, 0x7f, 0xeb, 0xd8, 0x46, 0xfd, 0xef, + 0xae, 0x19, 0xdd, 0x95, 0xb9, 0x5e, 0x13, 0xa5, 0xa5, 0xf4, 0xd5, 0xfe, 0x40, 0x4b, 0x99, 0xb9, 0x6b, 0xde, 0x1b, + 0x67, 0x6a, 0x57, 0x3b, 0x4c, 0xf6, 0xda, 0xdd, 0xd2, 0xe6, 0xb3, 0xd4, 0xd0, 0xd5, 0x8e, 0x0d, 0x23, 0x52, 0xc5, + 0x22, 0x89, 0x0d, 0xb0, 0x1c, 0x13, 0x66, 0xe8, 0xe8, 0x9a, 0x27, 0x49, 0x55, 0xfa, 0x6b, 0xf8, 0x7a, 0x6e, 0xf8, + 0x7a, 0x6a, 0xf9, 0x3a, 0x70, 0x0a, 0xe0, 0xeb, 0x7a, 0xb8, 0xaa, 0x7b, 0xba, 0x71, 0x3a, 0x53, 0xcd, 0xd1, 0x73, + 0x65, 0x47, 0xc3, 0x7c, 0x0b, 0x0b, 0x01, 0x2e, 0x35, 0xaf, 0x8f, 0xbe, 0x71, 0xc2, 0x80, 0x01, 0xa8, 0x5d, 0x98, + 0xcc, 0x75, 0x51, 0x7c, 0xf4, 0x31, 0xc9, 0x0b, 0x56, 0x52, 0xf6, 0xc9, 0x0b, 0x70, 0xd2, 0x39, 0xcb, 0x01, 0x21, + 0xa6, 0x8a, 0x7f, 0x95, 0x12, 0x65, 0x57, 0xc7, 0xcd, 0xea, 0x72, 0xbb, 0x3a, 0xe0, 0xf4, 0xd5, 0xea, 0xe2, 0xbb, + 0x79, 0xbd, 0x5a, 0x1e, 0x2f, 0x97, 0x57, 0xed, 0xf7, 0x6a, 0xe5, 0xaf, 0x95, 0x80, 0xff, 0xde, 0x98, 0x28, 0x59, + 0x39, 0x3a, 0xf0, 0x00, 0x17, 0x33, 0x50, 0x50, 0xe8, 0x45, 0x97, 0x22, 0xee, 0xd5, 0xa7, 0x1c, 0x3c, 0xca, 0x4d, + 0xaf, 0xfb, 0x9f, 0x8a, 0xd9, 0x1c, 0xb4, 0xb1, 0x35, 0x92, 0x9e, 0x30, 0x33, 0x61, 0x55, 0x5f, 0x6c, 0x29, 0xab, + 0xf5, 0x51, 0xe7, 0xb1, 0x46, 0x4d, 0xa5, 0xbd, 0xbc, 0xd7, 0x2a, 0x16, 0x65, 0x51, 0xc9, 0x38, 0xb6, 0x39, 0x55, + 0x4e, 0xd7, 0x5d, 0x32, 0xb6, 0xe2, 0xad, 0xcf, 0x35, 0x1f, 0xe6, 0xc0, 0xeb, 0x1c, 0xf6, 0x63, 0xc9, 0xdd, 0xdd, + 0xff, 0xa2, 0x42, 0xce, 0xb2, 0x58, 0x43, 0xdf, 0xb2, 0x28, 0x4e, 0xb4, 0x91, 0x4d, 0x4e, 0x76, 0x5b, 0xc3, 0x55, + 0x9d, 0x31, 0x16, 0x07, 0x43, 0x72, 0xb2, 0xa9, 0x3a, 0xd2, 0xe5, 0x4c, 0xc4, 0x2c, 0x44, 0x62, 0xce, 0x52, 0x54, + 0x80, 0x57, 0xd5, 0xec, 0xfd, 0x48, 0xfa, 0xcb, 0x77, 0x75, 0xf7, 0x6a, 0x78, 0x52, 0x80, 0xf7, 0xeb, 0x8b, 0x4d, + 0xc7, 0xeb, 0xb7, 0x2c, 0xcb, 0x95, 0x22, 0x5a, 0xea, 0xb4, 0x5f, 0x54, 0x62, 0xe9, 0x8b, 0x70, 0x67, 0xfb, 0xca, + 0x04, 0x41, 0xed, 0xe0, 0x71, 0x70, 0x84, 0xb0, 0x72, 0x0b, 0x7f, 0x65, 0x0e, 0xfc, 0x73, 0xeb, 0x16, 0x7e, 0x41, + 0x9f, 0xd7, 0xbd, 0xc2, 0xb1, 0xa4, 0x2f, 0xfa, 0x2f, 0xac, 0xc5, 0x2c, 0x12, 0x3e, 0xba, 0xf5, 0x51, 0xc2, 0x65, + 0x13, 0x42, 0x6f, 0x88, 0x2c, 0x75, 0x05, 0xb8, 0x14, 0x95, 0x3b, 0xbb, 0xb0, 0xb6, 0x1e, 0x91, 0x92, 0xa2, 0xfd, + 0x84, 0xcb, 0x7d, 0x44, 0x66, 0xf4, 0x02, 0x7e, 0xec, 0x2f, 0xfd, 0xd7, 0x91, 0x9c, 0x06, 0x59, 0x94, 0xc6, 0x62, + 0xe6, 0xe3, 0x06, 0x42, 0x38, 0xc8, 0x95, 0xbd, 0xf1, 0x39, 0x2e, 0xf6, 0x2f, 0xc8, 0x8d, 0xa4, 0xa8, 0x8f, 0x1a, + 0x33, 0xf2, 0x52, 0xd2, 0x8b, 0xe3, 0xfd, 0xe5, 0x8d, 0x2c, 0x7a, 0x17, 0xe4, 0xa6, 0xf4, 0xd8, 0x93, 0xaf, 0xa9, + 0x8f, 0x69, 0xef, 0xc6, 0x40, 0x73, 0x2a, 0x66, 0xda, 0x73, 0x8f, 0x30, 0xf9, 0x00, 0x71, 0x95, 0xac, 0xe2, 0x36, + 0x26, 0xb4, 0xb2, 0x47, 0x91, 0x50, 0x2e, 0x02, 0x74, 0x70, 0xe0, 0x94, 0x95, 0xaa, 0x02, 0x39, 0x91, 0xb4, 0x66, + 0x90, 0x93, 0x37, 0x2a, 0x42, 0x73, 0x22, 0xfd, 0x0c, 0xdb, 0x61, 0x7c, 0xeb, 0x87, 0x36, 0x47, 0x33, 0x1b, 0x68, + 0x0f, 0x43, 0xc0, 0x25, 0xcb, 0x22, 0x29, 0xb2, 0x21, 0x76, 0xd5, 0x0f, 0xf2, 0x37, 0x7a, 0x31, 0xf0, 0xfe, 0xd3, + 0x3f, 0xfd, 0x38, 0xfe, 0x31, 0x1b, 0x5e, 0x90, 0xb7, 0xf4, 0xf0, 0xd8, 0xef, 0x87, 0xfe, 0x5e, 0xb3, 0xb9, 0xfa, + 0xf1, 0x70, 0xf0, 0x8f, 0xa8, 0xf9, 0xcb, 0x49, 0xf3, 0x87, 0x21, 0x5e, 0xf9, 0x3f, 0x1e, 0xf6, 0x07, 0xe6, 0x69, + 0xf0, 0x8f, 0xde, 0x8f, 0xf9, 0xf0, 0xcf, 0xba, 0x70, 0x1f, 0xe3, 0xc3, 0x09, 0x59, 0x48, 0x7a, 0xd8, 0x6c, 0xf6, + 0x0e, 0x27, 0x64, 0x2e, 0xe9, 0x21, 0xfc, 0x7f, 0x49, 0xdf, 0xb1, 0xc9, 0x8b, 0x9b, 0xb9, 0x7f, 0xd1, 0x5b, 0xed, + 0x2f, 0xff, 0x56, 0xc0, 0xa8, 0x83, 0x7f, 0xfc, 0xf8, 0x63, 0x8e, 0x1e, 0xf4, 0xe8, 0xe1, 0xb0, 0x81, 0x7d, 0x28, + 0xfd, 0x33, 0x55, 0xff, 0xfa, 0xfd, 0x70, 0xf0, 0x0f, 0x03, 0x05, 0x7a, 0xf0, 0xe3, 0xc5, 0x71, 0x8f, 0x0e, 0x57, + 0x3e, 0x5a, 0x3d, 0xc0, 0x2b, 0x8c, 0x57, 0xfb, 0xf8, 0x82, 0xa0, 0x09, 0xc2, 0x64, 0x22, 0xe9, 0xe1, 0x83, 0xc3, + 0x09, 0xb9, 0x92, 0xf4, 0x10, 0x1d, 0x4e, 0xc8, 0x0b, 0x49, 0x0f, 0xff, 0xe1, 0xf7, 0x43, 0xed, 0x61, 0x5b, 0x29, + 0xf7, 0xc6, 0x0a, 0x82, 0x1b, 0x51, 0xc6, 0xa2, 0x95, 0xe4, 0x32, 0x61, 0x78, 0xff, 0x90, 0x93, 0x33, 0x85, 0x26, + 0x5f, 0x82, 0x13, 0x06, 0x6c, 0x3b, 0x7f, 0x79, 0x0e, 0x9b, 0x0d, 0x34, 0xb3, 0x1f, 0x66, 0x44, 0xfb, 0x01, 0xf2, + 0x50, 0x92, 0xab, 0x28, 0x59, 0xb0, 0x3c, 0x64, 0x05, 0x26, 0x23, 0x7a, 0x26, 0xfd, 0x36, 0x26, 0xef, 0x24, 0xfc, + 0xe8, 0x60, 0x72, 0x66, 0x02, 0x98, 0x70, 0x90, 0x35, 0x51, 0xa5, 0x42, 0x6b, 0x2c, 0x08, 0x93, 0xf9, 0x96, 0x4a, + 0x39, 0x05, 0xef, 0x02, 0x26, 0xe3, 0x5a, 0xb8, 0x93, 0x5c, 0x53, 0x4b, 0x12, 0xef, 0x33, 0xc6, 0xbe, 0x8b, 0x92, + 0x8f, 0x2c, 0xf3, 0x6f, 0x48, 0xbb, 0xf3, 0x39, 0x51, 0x2e, 0xe8, 0xbd, 0x36, 0xee, 0x96, 0xb1, 0xaa, 0x53, 0xa9, + 0x63, 0x04, 0x20, 0x64, 0xeb, 0xbe, 0x18, 0xd8, 0xf1, 0xbd, 0x6c, 0xc3, 0x61, 0x95, 0x45, 0xd7, 0x08, 0xd7, 0xe3, + 0xa2, 0x3c, 0xbd, 0x8a, 0x12, 0x1e, 0x7b, 0x92, 0xcd, 0xe6, 0x49, 0x24, 0x99, 0x67, 0xd6, 0xeb, 0x45, 0x30, 0x10, + 0x2a, 0x55, 0x86, 0xd8, 0x31, 0x38, 0x63, 0x1b, 0x70, 0x82, 0xb3, 0xe2, 0x43, 0x74, 0xca, 0xa8, 0x1d, 0xaf, 0xab, + 0xe0, 0xd7, 0x7a, 0x7c, 0xaf, 0xd9, 0x06, 0x47, 0xd8, 0x50, 0x89, 0xe7, 0x9c, 0xa4, 0x14, 0x84, 0x68, 0xa7, 0x8f, + 0x8e, 0xf3, 0xab, 0x49, 0x0f, 0x41, 0x6c, 0x46, 0xd0, 0xb7, 0xca, 0x2f, 0x04, 0x0d, 0xa6, 0xb4, 0xd5, 0x9d, 0x1e, + 0xb3, 0xee, 0xb4, 0xd1, 0xb0, 0x3a, 0x74, 0x42, 0xb3, 0xc1, 0x54, 0x77, 0x8f, 0x48, 0x4c, 0x16, 0xb4, 0xd9, 0x26, + 0x13, 0xda, 0x52, 0x5d, 0xba, 0x93, 0xe3, 0xc4, 0x4c, 0x73, 0x70, 0xe0, 0x8b, 0x20, 0x89, 0x72, 0xf9, 0x25, 0x18, + 0xfb, 0x74, 0x42, 0x62, 0x2a, 0x02, 0x76, 0xc3, 0x46, 0x7e, 0x82, 0x49, 0x6c, 0x38, 0x0d, 0xee, 0xe2, 0x09, 0x75, + 0x9a, 0x81, 0x11, 0x41, 0xdf, 0xf6, 0xe3, 0x41, 0x7b, 0x48, 0x29, 0x45, 0x7b, 0xcd, 0x26, 0xea, 0x0b, 0xba, 0x90, + 0x21, 0x94, 0x38, 0xaa, 0x32, 0x9d, 0x43, 0x51, 0xc7, 0x29, 0xf2, 0x5f, 0xc8, 0x40, 0xb2, 0x5c, 0xfa, 0x50, 0x0c, + 0xe6, 0x7f, 0x6e, 0x09, 0x1b, 0x1d, 0x1f, 0xa2, 0x06, 0x94, 0x2a, 0xe2, 0xc4, 0x44, 0xd0, 0x4b, 0x1c, 0xc6, 0x83, + 0xa3, 0xa1, 0xcb, 0xff, 0x55, 0x21, 0x4c, 0x7e, 0xd9, 0x8f, 0x07, 0x2d, 0x35, 0x79, 0x0f, 0xf5, 0x7d, 0x41, 0x73, + 0xad, 0xa0, 0xf5, 0xf3, 0xf0, 0xad, 0x5a, 0x2a, 0x0e, 0x0d, 0x70, 0x66, 0xde, 0x05, 0x6d, 0x76, 0x42, 0x7f, 0xe1, + 0x2e, 0xa2, 0x09, 0x93, 0x19, 0x2c, 0x90, 0x88, 0x42, 0x7b, 0x22, 0x28, 0xcc, 0x58, 0x75, 0xbb, 0x0c, 0xcd, 0xf3, + 0x03, 0xf4, 0xa0, 0x7f, 0x25, 0xc3, 0x89, 0xd4, 0xd3, 0x5f, 0xc9, 0xd5, 0x0a, 0xfe, 0x9f, 0xc8, 0xbe, 0xa0, 0x97, + 0xaa, 0x68, 0x61, 0x8a, 0xe6, 0x50, 0xf4, 0x36, 0x04, 0x50, 0x49, 0x5e, 0x2a, 0x59, 0x7a, 0x4f, 0xae, 0xa8, 0x82, + 0xfd, 0xe0, 0x20, 0x1b, 0x4c, 0x1b, 0xed, 0x21, 0xf8, 0xf7, 0x33, 0x99, 0x7f, 0xc7, 0xe5, 0xd4, 0x47, 0x87, 0x3d, + 0x84, 0xfb, 0xc8, 0x83, 0xad, 0xed, 0xa6, 0x0d, 0xaa, 0x31, 0x9c, 0x34, 0x5e, 0xca, 0x70, 0xd1, 0xa3, 0xad, 0xbe, + 0xcf, 0x8d, 0x3f, 0x0f, 0x93, 0xc4, 0x30, 0xce, 0x16, 0x59, 0xe0, 0x86, 0x94, 0x0d, 0xfb, 0xbc, 0xc0, 0x8d, 0x59, + 0xe3, 0x0a, 0x87, 0x49, 0x63, 0xd6, 0xf0, 0x17, 0x94, 0xd2, 0x66, 0xa7, 0xec, 0x66, 0xa5, 0xdf, 0x14, 0x87, 0x57, + 0xd6, 0xd9, 0x39, 0x50, 0xc7, 0x21, 0x6d, 0xf8, 0xd9, 0x80, 0x0d, 0x57, 0x2b, 0x74, 0xdc, 0xef, 0x21, 0xdc, 0xf0, + 0x2d, 0xa1, 0x1d, 0x5a, 0x4a, 0xc3, 0x98, 0xf0, 0x61, 0x61, 0x42, 0x49, 0xef, 0x6b, 0x61, 0xa3, 0x65, 0x75, 0xd8, + 0x1d, 0x1e, 0xc0, 0x8a, 0xd2, 0x8e, 0xd1, 0xfa, 0xea, 0x1c, 0x96, 0x69, 0x89, 0x39, 0xa5, 0x2d, 0x22, 0xa8, 0xf5, + 0x5d, 0x4f, 0xa9, 0xac, 0x08, 0x3e, 0xa1, 0x55, 0x73, 0x32, 0x88, 0x48, 0x3c, 0xa4, 0xaf, 0xb5, 0x3d, 0xd2, 0xb5, + 0x7e, 0x71, 0x96, 0xd0, 0xf7, 0x6b, 0xd1, 0xdb, 0x08, 0x62, 0x2b, 0xd7, 0xc1, 0x68, 0x91, 0x65, 0x2c, 0x95, 0x6f, + 0x44, 0x6c, 0xd4, 0x34, 0x96, 0x80, 0xa5, 0x04, 0x61, 0x59, 0x02, 0x3a, 0x5a, 0xc7, 0x9e, 0x8c, 0xc5, 0x46, 0xf5, + 0x84, 0x2e, 0xb4, 0xfa, 0xa4, 0x82, 0xb5, 0xdd, 0x89, 0xb1, 0x8b, 0x7d, 0x4c, 0x16, 0x26, 0x8a, 0xeb, 0x07, 0x41, + 0x30, 0x09, 0x46, 0x50, 0x0d, 0x13, 0xe4, 0xb8, 0x50, 0xe7, 0xc8, 0xcf, 0xe9, 0x75, 0x90, 0xb2, 0x1b, 0x35, 0xab, + 0x8f, 0x2b, 0xc9, 0x6c, 0x8f, 0xd7, 0xf1, 0xb4, 0xab, 0xd8, 0x4d, 0x1e, 0xa4, 0x22, 0x66, 0x80, 0x1e, 0x88, 0xdb, + 0x9b, 0xa2, 0x69, 0x94, 0xbb, 0xf1, 0xa9, 0x0a, 0xbe, 0x81, 0xeb, 0xbc, 0x9e, 0x80, 0xc7, 0x57, 0xe9, 0x5a, 0x65, + 0x63, 0xed, 0x06, 0xc7, 0x98, 0x8f, 0xfd, 0x49, 0x00, 0x71, 0x3d, 0x45, 0x42, 0x12, 0x4c, 0xb9, 0x89, 0x4b, 0x54, + 0xb3, 0x72, 0xcc, 0x2b, 0x1a, 0x0f, 0x44, 0xa3, 0xa1, 0xbc, 0xd0, 0x0b, 0x4d, 0x12, 0x13, 0x4c, 0xae, 0xca, 0xb3, + 0x65, 0xdb, 0xbd, 0x95, 0xb4, 0x3e, 0x95, 0x7f, 0x55, 0x77, 0xe7, 0x36, 0xa4, 0xc4, 0xca, 0x53, 0x28, 0xfd, 0x19, + 0x26, 0xcf, 0xe8, 0xa1, 0x3f, 0x08, 0xfa, 0x7f, 0x19, 0xe2, 0xbe, 0x1f, 0xfc, 0x19, 0x1f, 0x6a, 0xce, 0x71, 0x85, + 0xbb, 0x89, 0x9e, 0x63, 0xa9, 0xe2, 0x97, 0x6d, 0xa2, 0x3c, 0x89, 0x61, 0x4a, 0xd2, 0x68, 0xc6, 0xc2, 0x67, 0x70, + 0xc8, 0x2d, 0xe1, 0xbc, 0x95, 0x04, 0x28, 0x29, 0x7c, 0x66, 0x78, 0x49, 0x80, 0xfa, 0xaf, 0x64, 0xf9, 0xd4, 0x47, + 0xfd, 0xe7, 0xd5, 0xd3, 0x5f, 0x50, 0xff, 0x17, 0x19, 0xfe, 0x5c, 0x18, 0x6f, 0x77, 0x6d, 0x8e, 0xc7, 0x76, 0x8e, + 0x42, 0x6f, 0x8d, 0x83, 0xbb, 0x05, 0xde, 0x74, 0x74, 0x4c, 0x70, 0xc1, 0xc7, 0x25, 0x33, 0xca, 0x03, 0x19, 0x4d, + 0x00, 0xa9, 0xce, 0x1e, 0xe4, 0x6e, 0x5c, 0xbf, 0x5a, 0x31, 0x90, 0x8a, 0xa5, 0x57, 0x40, 0xe6, 0xa4, 0xd7, 0xc2, + 0xcb, 0x5a, 0x5b, 0xa5, 0x33, 0xd5, 0xe3, 0xe8, 0x25, 0x9f, 0xbe, 0xa2, 0xad, 0xee, 0xd5, 0xf1, 0xa4, 0x7b, 0xd5, + 0x68, 0xe0, 0xdc, 0x92, 0xd6, 0x62, 0x70, 0x35, 0x24, 0x5f, 0x83, 0x53, 0xcf, 0xa5, 0x25, 0x52, 0x5b, 0x5e, 0xc7, + 0x2c, 0xaf, 0xd1, 0x48, 0x0b, 0xdc, 0x75, 0xba, 0x4e, 0x74, 0xd7, 0xa2, 0xd0, 0x38, 0x59, 0x27, 0xb5, 0xa7, 0x58, + 0x95, 0x40, 0x32, 0x14, 0xa5, 0xf4, 0x46, 0xe2, 0xad, 0xa3, 0xc2, 0x98, 0xd0, 0x5d, 0x9d, 0x59, 0x60, 0x9f, 0x5a, + 0x4a, 0xf8, 0x80, 0x05, 0xe8, 0x5a, 0x7a, 0x82, 0x67, 0x64, 0xd1, 0x68, 0x2b, 0x32, 0x6f, 0xb6, 0xbb, 0xf5, 0xb1, + 0x9e, 0x54, 0x63, 0x91, 0x45, 0x83, 0xce, 0x4a, 0x2c, 0x15, 0x69, 0xa3, 0x51, 0xd4, 0x83, 0x9d, 0xf6, 0xe4, 0xd6, + 0x02, 0x10, 0x37, 0xeb, 0x49, 0x19, 0x56, 0xc2, 0x56, 0x32, 0x95, 0x07, 0x3c, 0x4d, 0x59, 0x06, 0x52, 0x94, 0x4a, + 0xc2, 0x8b, 0xa2, 0x92, 0xec, 0x20, 0x46, 0x09, 0xa3, 0x19, 0x70, 0x1e, 0x65, 0x77, 0x91, 0x94, 0x08, 0x32, 0x55, + 0x7c, 0x83, 0x52, 0x7a, 0x66, 0xd3, 0x59, 0xa4, 0xe2, 0x41, 0x09, 0xe5, 0x8e, 0x4c, 0xca, 0x29, 0x0b, 0xce, 0xf7, + 0x4f, 0xc5, 0x9d, 0x36, 0xd9, 0x80, 0x0f, 0x43, 0xd5, 0x2c, 0x31, 0x9c, 0x2b, 0xa2, 0x1f, 0x7c, 0x89, 0xcb, 0xe8, + 0x48, 0xa0, 0x18, 0xe0, 0x73, 0x9e, 0x31, 0xa5, 0x83, 0xef, 0x5b, 0xbb, 0x2f, 0xa9, 0x2b, 0x90, 0x89, 0xeb, 0xbd, + 0x01, 0x44, 0x46, 0xe0, 0xdc, 0x49, 0xe9, 0x46, 0xb3, 0xf3, 0xfd, 0x93, 0xb7, 0xdb, 0x6c, 0xe0, 0xd5, 0xca, 0x58, + 0xbf, 0x4a, 0xb7, 0x21, 0x51, 0x05, 0x69, 0x62, 0x7e, 0x84, 0x7e, 0xa2, 0x54, 0xa4, 0xc8, 0xcf, 0x80, 0x8a, 0xce, + 0xf7, 0x4f, 0xde, 0xfb, 0x99, 0xf2, 0x2d, 0x61, 0xe2, 0x2e, 0xdb, 0x17, 0xd4, 0x9f, 0x52, 0x86, 0xf5, 0xda, 0x4b, + 0xd6, 0x25, 0x1c, 0x01, 0x1e, 0x4e, 0x55, 0x25, 0x58, 0x10, 0x03, 0x3e, 0xa4, 0x89, 0xc1, 0x00, 0x4d, 0x30, 0x49, + 0x6a, 0x76, 0x19, 0x85, 0x0d, 0x50, 0x73, 0x9d, 0xc1, 0x4e, 0x04, 0x5a, 0xf5, 0xc3, 0x24, 0x51, 0xb3, 0xca, 0x42, + 0x0b, 0x8f, 0x67, 0x1b, 0x59, 0x69, 0x95, 0x39, 0xfa, 0x2d, 0xd8, 0x4e, 0xf6, 0xe1, 0x0d, 0xb5, 0x96, 0x84, 0x29, + 0x78, 0x6e, 0xd3, 0xc7, 0xce, 0xf7, 0x4f, 0x5e, 0x9b, 0x0c, 0xb2, 0x79, 0x64, 0xf9, 0xfd, 0x86, 0x89, 0x79, 0xf2, + 0x3a, 0xa8, 0x6a, 0x55, 0xe3, 0xf3, 0xfd, 0x93, 0x0f, 0xdb, 0x9a, 0x41, 0x79, 0xb1, 0xa8, 0x6c, 0x7c, 0x05, 0xdf, + 0x92, 0x25, 0xe1, 0xd2, 0x08, 0x87, 0x90, 0x17, 0x44, 0x09, 0xa4, 0x30, 0x2f, 0x4a, 0xd7, 0xc8, 0x73, 0x92, 0x52, + 0x15, 0x06, 0xaa, 0xef, 0x9a, 0x51, 0xf3, 0xb8, 0x48, 0xcf, 0x46, 0x62, 0xce, 0x76, 0xc4, 0x86, 0x6e, 0x70, 0xc0, + 0x67, 0x90, 0x3a, 0xa3, 0x40, 0xe7, 0x64, 0xaf, 0x85, 0xbb, 0x75, 0xf1, 0x95, 0x2a, 0x22, 0x15, 0x35, 0xd9, 0x42, + 0xa6, 0xb4, 0x45, 0x12, 0xda, 0x22, 0x11, 0xcd, 0x07, 0x2d, 0x2d, 0x20, 0xba, 0x51, 0x39, 0xae, 0x16, 0x33, 0x90, + 0x15, 0x66, 0x4e, 0xab, 0x16, 0xc0, 0x71, 0x37, 0x52, 0xbe, 0x47, 0x25, 0xd3, 0x63, 0x45, 0x16, 0x6f, 0x7c, 0x41, + 0x84, 0x1a, 0xf8, 0x8c, 0x5f, 0x26, 0x90, 0x58, 0x02, 0xab, 0x22, 0x12, 0x87, 0x65, 0xd3, 0xb6, 0x69, 0x1a, 0x05, + 0x6a, 0x9f, 0x04, 0x89, 0x02, 0xe0, 0xdc, 0x24, 0x32, 0x79, 0x38, 0xf9, 0x66, 0x97, 0xc7, 0x07, 0x07, 0xbe, 0xee, + 0xf4, 0xa5, 0xf4, 0x85, 0xad, 0xaf, 0x22, 0x77, 0xdf, 0x6a, 0x5e, 0x11, 0x63, 0x05, 0x7f, 0xa3, 0x91, 0x0c, 0x0b, + 0x08, 0x43, 0xfb, 0x51, 0x1d, 0x83, 0x16, 0x78, 0xa5, 0xeb, 0xd5, 0x97, 0xdf, 0x68, 0x94, 0x51, 0xda, 0x3a, 0xb6, + 0x6e, 0x48, 0x5a, 0x5c, 0xf9, 0x65, 0xea, 0x4f, 0x6b, 0x23, 0x5f, 0xca, 0x82, 0x80, 0xb9, 0x4b, 0xb3, 0xdc, 0x2e, + 0xc6, 0x39, 0x12, 0x1c, 0xda, 0x7d, 0x69, 0xb2, 0x16, 0x88, 0xca, 0xae, 0x32, 0x8d, 0x2c, 0x3b, 0xeb, 0xe0, 0xd0, + 0x36, 0x82, 0xa8, 0x14, 0x34, 0x6a, 0x14, 0x86, 0xbc, 0xdf, 0x6c, 0xe6, 0x5c, 0x92, 0x1c, 0x1b, 0x27, 0x97, 0x82, + 0x42, 0x21, 0xab, 0x53, 0x22, 0xe5, 0x25, 0x9d, 0xef, 0x26, 0xf9, 0x13, 0x87, 0xe4, 0x9f, 0x51, 0xe6, 0x90, 0xbf, + 0x76, 0x71, 0x04, 0xc2, 0x38, 0x17, 0x72, 0x5b, 0x75, 0x3a, 0xa7, 0xe0, 0x44, 0xab, 0x63, 0xb4, 0x16, 0x56, 0xdc, + 0xc1, 0x50, 0xdc, 0x13, 0xa2, 0xdc, 0x90, 0xc4, 0xc6, 0x80, 0xfd, 0x2a, 0xa8, 0x06, 0x53, 0x6f, 0xf3, 0xe9, 0xb9, + 0x1c, 0xf0, 0xe4, 0xc3, 0xdd, 0xf1, 0xd0, 0xd3, 0xf9, 0xe6, 0xc9, 0x75, 0x72, 0x3f, 0x61, 0xd5, 0xce, 0xc1, 0xad, + 0x67, 0x82, 0xc2, 0xfc, 0x65, 0x1c, 0xbb, 0xce, 0x7c, 0xd6, 0x0e, 0xa1, 0x95, 0x7f, 0x00, 0x6d, 0xbb, 0xad, 0x5a, + 0x30, 0x67, 0x58, 0xe0, 0x47, 0x3a, 0x03, 0x35, 0xca, 0x76, 0xb0, 0x8f, 0x13, 0xd5, 0x80, 0xa5, 0xf1, 0xf6, 0xea, + 0x67, 0x85, 0x21, 0x13, 0x0d, 0x1a, 0x5e, 0x02, 0xff, 0xd3, 0x24, 0x0f, 0x74, 0xa3, 0xe4, 0x02, 0x20, 0x68, 0xae, + 0xf0, 0x54, 0x21, 0x0c, 0xa1, 0xca, 0xfb, 0xfe, 0x72, 0x8f, 0xd2, 0x79, 0xe5, 0x7d, 0x7c, 0x57, 0xa5, 0x5e, 0x01, + 0x59, 0xe0, 0x10, 0xcc, 0xc7, 0xb2, 0x40, 0x87, 0x2f, 0xcf, 0x6c, 0x73, 0x65, 0x42, 0x06, 0x95, 0xc6, 0xed, 0x84, + 0x36, 0x95, 0x5b, 0x4e, 0xd7, 0x5b, 0x34, 0xac, 0xd5, 0xee, 0x43, 0xed, 0x1b, 0xa9, 0x60, 0x84, 0xe7, 0xf7, 0xaa, + 0xb5, 0x1d, 0xb7, 0xf8, 0xb8, 0x9e, 0xbf, 0xb2, 0xb6, 0x29, 0x01, 0x4f, 0x73, 0x96, 0xc9, 0x67, 0x6c, 0x2c, 0x32, + 0x88, 0x59, 0x94, 0x38, 0xc1, 0xc5, 0xbe, 0xe3, 0xb7, 0x53, 0xeb, 0x73, 0x02, 0x05, 0x6b, 0x0b, 0x54, 0xbf, 0x3e, + 0xaa, 0xa0, 0xf5, 0xf9, 0x7a, 0xaf, 0xf9, 0xc1, 0xc1, 0x87, 0x0a, 0x4d, 0x06, 0x4a, 0x05, 0x85, 0xc3, 0xb4, 0xb4, + 0x4a, 0x63, 0x22, 0xb9, 0xfb, 0x7e, 0xe9, 0x04, 0xb0, 0x0c, 0xc3, 0xe5, 0x3d, 0x2f, 0xa9, 0x2c, 0x26, 0xeb, 0x2c, + 0xde, 0x38, 0x27, 0xb8, 0x6b, 0xb8, 0x00, 0x87, 0x07, 0x53, 0x5b, 0x7b, 0x8b, 0xf2, 0x2a, 0x19, 0xb6, 0x84, 0xe1, + 0x14, 0x90, 0xe5, 0x2b, 0x33, 0xc4, 0xa1, 0xc0, 0xad, 0x66, 0xc9, 0x29, 0xe8, 0x95, 0x53, 0x92, 0x07, 0x53, 0x48, + 0x7f, 0xad, 0x1d, 0x59, 0x8c, 0x89, 0x4e, 0xcc, 0x71, 0x52, 0x09, 0x4e, 0x5e, 0x6e, 0x73, 0x29, 0x5b, 0xa2, 0x66, + 0x4a, 0xea, 0xa8, 0x16, 0xb8, 0xec, 0x10, 0x5c, 0xf9, 0xdc, 0x28, 0x6e, 0x36, 0x6e, 0x06, 0x0c, 0xf8, 0x99, 0xf4, + 0x75, 0x30, 0x0a, 0x64, 0x86, 0x08, 0x16, 0x7e, 0x6d, 0xea, 0xae, 0x50, 0xdd, 0x88, 0x41, 0xdc, 0xd4, 0x45, 0x93, + 0x50, 0x71, 0xbd, 0xd3, 0x8a, 0x97, 0x8e, 0x75, 0x06, 0xb5, 0xb4, 0x5c, 0xb0, 0x4a, 0x24, 0x71, 0x96, 0x3f, 0xd6, + 0x49, 0xd1, 0x65, 0x23, 0xc2, 0x14, 0x18, 0xef, 0xd5, 0x1e, 0xb0, 0x02, 0xfe, 0x5f, 0x9e, 0x48, 0x67, 0x47, 0xad, + 0x13, 0x5b, 0xcd, 0xe9, 0x48, 0xfd, 0x77, 0x90, 0xea, 0xb2, 0x7e, 0xe6, 0x5f, 0x2a, 0x59, 0xc8, 0x49, 0x5e, 0x63, + 0xec, 0xa9, 0x62, 0xec, 0x18, 0xf4, 0x34, 0x9b, 0xf8, 0xdd, 0x37, 0x19, 0x2f, 0xdc, 0x48, 0x39, 0x43, 0x62, 0x5f, + 0x97, 0xd1, 0x72, 0xe7, 0xf7, 0xda, 0x6e, 0x84, 0x9c, 0x42, 0x16, 0x10, 0x31, 0x9c, 0x3d, 0xc5, 0x24, 0x6f, 0x34, + 0xba, 0xf9, 0x31, 0xab, 0x9c, 0x24, 0x15, 0x8c, 0x1c, 0x02, 0xba, 0x40, 0xf0, 0x35, 0x19, 0x0a, 0x21, 0x7f, 0x9b, + 0x99, 0x9d, 0x83, 0xaf, 0xfd, 0xe4, 0x9d, 0xef, 0x72, 0x35, 0xb7, 0x6d, 0x19, 0x34, 0x85, 0xf5, 0xf8, 0x55, 0xc0, + 0xe5, 0xeb, 0xbb, 0x13, 0x3c, 0x00, 0xee, 0xbd, 0x36, 0x81, 0x54, 0x34, 0xdc, 0x95, 0x9a, 0x25, 0x94, 0xa7, 0xaf, + 0x8b, 0xab, 0xac, 0x44, 0x77, 0xb2, 0xae, 0xac, 0x8c, 0x59, 0x49, 0xf3, 0xa2, 0xc8, 0x59, 0x15, 0xde, 0x5f, 0x4b, + 0xbf, 0x54, 0xc2, 0x65, 0xd3, 0xdb, 0x7e, 0x3a, 0xa7, 0x92, 0x38, 0x84, 0xfa, 0xf5, 0xae, 0xd8, 0x47, 0x05, 0x26, + 0x9c, 0x6b, 0x23, 0x14, 0x7f, 0xde, 0x26, 0x14, 0x49, 0x6a, 0x8e, 0xbc, 0x12, 0x88, 0xed, 0x7b, 0x08, 0x44, 0xe3, + 0x66, 0xb7, 0x32, 0x11, 0xd4, 0x91, 0x9a, 0x4c, 0xac, 0x6f, 0x29, 0x4d, 0x09, 0x37, 0xbb, 0xd1, 0xeb, 0xac, 0x56, + 0x7c, 0xd0, 0x02, 0x37, 0x12, 0x42, 0xf0, 0xb3, 0xad, 0x7f, 0x3a, 0x9c, 0x58, 0xbb, 0x81, 0x7d, 0x5e, 0x9a, 0x2c, + 0x38, 0x80, 0x04, 0x67, 0x5f, 0x25, 0x65, 0x29, 0x9a, 0x36, 0x14, 0x64, 0x08, 0x9c, 0xf2, 0x32, 0xcc, 0x04, 0x10, + 0x2b, 0x59, 0x61, 0x0c, 0x48, 0x7f, 0x6b, 0xee, 0x9f, 0x35, 0x2f, 0x3f, 0xad, 0x89, 0xd6, 0xe4, 0x8a, 0x56, 0x1f, + 0x6a, 0xf9, 0x06, 0x06, 0x02, 0xa3, 0x1f, 0xee, 0x29, 0x13, 0xb4, 0x12, 0xe5, 0xd8, 0x95, 0x43, 0xa4, 0x05, 0x4e, + 0xb4, 0xbd, 0x0f, 0x3a, 0xc2, 0xbb, 0x45, 0x9a, 0x10, 0xe1, 0xd0, 0xf5, 0x4b, 0x2a, 0x6b, 0xac, 0x64, 0x4a, 0x8d, + 0xa5, 0x44, 0x22, 0x45, 0xa6, 0x92, 0xa6, 0x83, 0xd6, 0x10, 0x14, 0xd0, 0x6e, 0x72, 0x9c, 0x56, 0x26, 0x70, 0xd2, + 0x68, 0xe0, 0xc8, 0xce, 0x3a, 0x1d, 0xf0, 0x46, 0x32, 0x24, 0x8c, 0x24, 0xda, 0x30, 0x39, 0x3b, 0x38, 0xf0, 0xa3, + 0x6a, 0xde, 0x41, 0x32, 0xc4, 0x44, 0xac, 0x56, 0xbe, 0x02, 0x2b, 0xc2, 0xab, 0x55, 0xe4, 0x82, 0xa5, 0xaa, 0xa1, + 0xdb, 0xbc, 0x2f, 0xe9, 0x5c, 0x09, 0xc0, 0x39, 0x40, 0xd8, 0xa0, 0x7e, 0x64, 0xdc, 0x7b, 0x11, 0xb8, 0xa3, 0x1a, + 0xe9, 0x20, 0x69, 0xb4, 0x87, 0x0e, 0xe3, 0x1a, 0x24, 0x43, 0x1a, 0x15, 0xe2, 0xe0, 0x60, 0x2f, 0x37, 0x22, 0xf2, + 0x27, 0x10, 0x65, 0x3f, 0x29, 0xc9, 0xa2, 0x07, 0x74, 0x77, 0x63, 0xdd, 0x19, 0x50, 0x52, 0x94, 0xd9, 0x56, 0xdb, + 0xae, 0x96, 0x05, 0x51, 0x36, 0x22, 0x26, 0x18, 0xdc, 0x07, 0xcb, 0xbe, 0x24, 0xf3, 0x57, 0xb2, 0xcc, 0xb1, 0xfe, + 0x79, 0x6b, 0x66, 0x75, 0x10, 0x04, 0x51, 0x36, 0x51, 0xb1, 0x0c, 0x1b, 0x86, 0x55, 0xc4, 0x7f, 0x64, 0xc0, 0x74, + 0x26, 0x1e, 0x94, 0x73, 0x0d, 0xa9, 0x06, 0xdf, 0xaa, 0x36, 0xf6, 0x2e, 0xc9, 0x4f, 0x5b, 0xbd, 0x0c, 0x1a, 0x92, + 0xe7, 0xbf, 0x15, 0x92, 0x87, 0x06, 0x12, 0x4d, 0x1e, 0x6b, 0x38, 0xdb, 0x81, 0x8b, 0x9f, 0xe4, 0x1a, 0xce, 0x76, + 0xe3, 0xd6, 0x62, 0xea, 0x97, 0x5d, 0xf0, 0x39, 0xbc, 0x41, 0x03, 0x5a, 0x15, 0x38, 0x50, 0x3e, 0x5a, 0xd7, 0xbd, + 0x34, 0x2b, 0x05, 0x61, 0x2a, 0xa9, 0xcf, 0xeb, 0x07, 0xa0, 0xd2, 0x46, 0x1d, 0xc3, 0x97, 0x87, 0x73, 0xec, 0xb8, + 0x04, 0xea, 0xa9, 0x2b, 0x40, 0x4e, 0xc6, 0xdb, 0x3e, 0x3f, 0x38, 0x00, 0xdb, 0x00, 0x94, 0xb8, 0x60, 0x14, 0xcd, + 0xe5, 0x22, 0x03, 0x55, 0x2a, 0xb7, 0xbf, 0xa1, 0x18, 0x6e, 0x81, 0xa8, 0x32, 0xf8, 0x01, 0x05, 0xf3, 0x28, 0xcf, + 0xf9, 0x95, 0x2e, 0x33, 0xbf, 0x89, 0xa0, 0x96, 0x94, 0x73, 0xad, 0x13, 0xa6, 0xb8, 0x9b, 0x1a, 0x3a, 0xad, 0xa3, + 0xed, 0xc5, 0x15, 0x4b, 0xe5, 0x2b, 0x9e, 0x4b, 0x96, 0xc2, 0xf2, 0x2b, 0x8a, 0x83, 0x15, 0xe5, 0x18, 0x0e, 0x6c, + 0xad, 0x57, 0x14, 0xc7, 0x77, 0x76, 0x91, 0x75, 0x1d, 0x68, 0x1a, 0xa5, 0x71, 0xa2, 0x27, 0x71, 0xf3, 0x19, 0x6d, + 0x0e, 0x67, 0xd9, 0xd2, 0xcd, 0xa7, 0xa9, 0x94, 0x0d, 0xc5, 0xdd, 0x7d, 0x4e, 0xad, 0x24, 0xb0, 0xd2, 0xf3, 0x4e, + 0xad, 0x05, 0x22, 0xde, 0x3b, 0x36, 0xc1, 0x5d, 0x09, 0x91, 0x0e, 0x47, 0x0d, 0xea, 0x70, 0x5a, 0xba, 0xf9, 0x72, + 0xeb, 0x95, 0xb6, 0x6d, 0xc2, 0x41, 0xd1, 0xc9, 0xe3, 0xdd, 0x96, 0xd5, 0x6b, 0x2b, 0x39, 0xac, 0xb4, 0xe0, 0xf7, + 0x65, 0xcc, 0x78, 0x69, 0xc9, 0x0b, 0xdb, 0xa3, 0xb8, 0x2f, 0xe9, 0x73, 0xb8, 0x33, 0xf4, 0x52, 0xce, 0x92, 0xb5, + 0xab, 0x31, 0xdd, 0xfd, 0x52, 0xfb, 0xdf, 0x97, 0xfe, 0x7b, 0xf2, 0x06, 0x02, 0xbb, 0x5f, 0x55, 0xcd, 0x37, 0x03, + 0xba, 0x5f, 0x55, 0x08, 0xfa, 0x2a, 0xdc, 0x68, 0xe7, 0x04, 0x72, 0x3b, 0xc1, 0xd3, 0xa0, 0x85, 0xac, 0xb6, 0xf4, + 0xb3, 0x0e, 0x23, 0xe9, 0x4c, 0x4b, 0x75, 0x1e, 0x48, 0x95, 0xa7, 0x06, 0xf9, 0x72, 0x75, 0x0b, 0x89, 0x99, 0x0c, + 0x43, 0xad, 0xc3, 0xef, 0xda, 0x1e, 0x23, 0x63, 0x52, 0x6d, 0x67, 0x7c, 0x1d, 0x65, 0x72, 0x1f, 0x4e, 0x99, 0xd8, + 0xb8, 0x87, 0x37, 0xa5, 0xe0, 0x41, 0xbb, 0xdf, 0x14, 0x8e, 0xb1, 0x9d, 0xeb, 0x7b, 0x40, 0xee, 0xf8, 0x54, 0x58, + 0xdd, 0xad, 0x6e, 0x65, 0x7c, 0x0d, 0xf6, 0x3f, 0x26, 0x53, 0x7b, 0x39, 0x8e, 0x19, 0x0e, 0xcc, 0xc2, 0x65, 0x51, + 0x3a, 0x05, 0x84, 0x56, 0xde, 0x32, 0x4c, 0x44, 0xa1, 0x02, 0xdc, 0x3f, 0x90, 0x6f, 0x0c, 0x4b, 0x1c, 0x97, 0x1c, + 0xe7, 0xe4, 0xbe, 0x1c, 0x51, 0x83, 0x5f, 0xc6, 0xef, 0x81, 0x8e, 0x15, 0x85, 0x16, 0x96, 0x8a, 0x9e, 0x0b, 0xb3, + 0x90, 0x9d, 0x69, 0xa9, 0x84, 0x95, 0x29, 0x35, 0x6a, 0x9a, 0x2d, 0x79, 0x9c, 0xd6, 0xca, 0x96, 0xe5, 0xa9, 0xaa, + 0xcd, 0x8b, 0x77, 0x60, 0xb1, 0x0a, 0x2d, 0xae, 0x56, 0x7e, 0x1d, 0xd5, 0x94, 0x3b, 0x91, 0x0c, 0x4c, 0xb8, 0x93, + 0x51, 0x51, 0xd3, 0xac, 0x75, 0x1f, 0x1f, 0xaf, 0x27, 0x14, 0x59, 0xdd, 0xbc, 0x06, 0x87, 0xeb, 0x42, 0xd0, 0xdd, + 0x5d, 0x9f, 0x02, 0xd1, 0xab, 0x2b, 0x27, 0x72, 0x30, 0xf4, 0x73, 0x99, 0x2a, 0x5b, 0xe5, 0xb4, 0x6e, 0xc1, 0x2f, + 0xbe, 0x23, 0x59, 0xd6, 0xa0, 0x6e, 0xb3, 0xde, 0x49, 0x36, 0x7a, 0x2e, 0x76, 0x25, 0x1b, 0xd5, 0xb4, 0xdd, 0xbd, + 0x16, 0xbe, 0x3b, 0x2d, 0x55, 0xcf, 0xb5, 0xbd, 0xc9, 0x6f, 0x98, 0xae, 0x0d, 0xb4, 0xa9, 0xd1, 0x6c, 0xb9, 0xca, + 0x59, 0x51, 0x8c, 0xcb, 0xcb, 0x04, 0x2a, 0x77, 0x67, 0xac, 0xe9, 0xdf, 0x58, 0x8d, 0xea, 0x3a, 0xae, 0xff, 0x03, + 0x9d, 0x24, 0xe2, 0x32, 0x4a, 0xde, 0xc3, 0x7c, 0x55, 0xe5, 0xcb, 0xdb, 0x38, 0x8b, 0x24, 0x33, 0xdc, 0xa5, 0x82, + 0xe1, 0x07, 0x07, 0x86, 0x1f, 0x34, 0x9f, 0xae, 0xfa, 0x93, 0xe5, 0xab, 0x72, 0x80, 0x70, 0x5c, 0x58, 0x96, 0x71, + 0x2e, 0xb7, 0xcf, 0xb1, 0xce, 0xc2, 0xce, 0x4b, 0x16, 0x76, 0x2e, 0xfd, 0xf5, 0xa1, 0x7c, 0xff, 0x9b, 0xed, 0xa3, + 0x6c, 0x72, 0xb6, 0x6f, 0xaa, 0x83, 0xff, 0x4d, 0x78, 0x67, 0x1f, 0x87, 0xcb, 0x1d, 0x05, 0x47, 0x2a, 0x5d, 0x45, + 0x83, 0xfc, 0x0e, 0xd2, 0x0e, 0x24, 0xed, 0x39, 0x77, 0x0e, 0x2a, 0x39, 0x65, 0x13, 0x81, 0xfc, 0xd1, 0x22, 0x97, + 0x62, 0x66, 0xc6, 0xcc, 0xcd, 0x35, 0x23, 0x55, 0x09, 0xae, 0x68, 0x15, 0x6d, 0x0f, 0xeb, 0x17, 0xb9, 0x96, 0x1f, + 0x79, 0x1a, 0x87, 0x39, 0x31, 0x52, 0x24, 0x0f, 0xd3, 0x82, 0xda, 0x64, 0xe3, 0xcd, 0x3a, 0x32, 0xe6, 0x29, 0xcf, + 0xa7, 0x2c, 0xf3, 0x05, 0x5e, 0xee, 0x9a, 0x4c, 0x40, 0x40, 0x46, 0x4f, 0x46, 0xbe, 0xad, 0x2e, 0xfc, 0x05, 0x30, + 0x1a, 0xf8, 0x81, 0x66, 0x4c, 0x4e, 0x45, 0x0c, 0x89, 0x29, 0x41, 0x5c, 0xde, 0x68, 0x3a, 0x38, 0xd8, 0xf3, 0x91, + 0x72, 0x4b, 0xc0, 0xd5, 0x6f, 0xb7, 0x06, 0xf7, 0x97, 0x70, 0x3d, 0xa7, 0x9a, 0x9a, 0xe1, 0x25, 0x5b, 0xbf, 0xc9, + 0x22, 0x83, 0x8f, 0xec, 0x96, 0x64, 0xb8, 0x28, 0x42, 0x0d, 0x35, 0x1a, 0x73, 0x96, 0xc4, 0x88, 0x7c, 0x64, 0xb7, + 0x61, 0x79, 0x5b, 0x5c, 0x5d, 0x6e, 0x56, 0x1b, 0x88, 0xc4, 0x75, 0x8a, 0x48, 0x35, 0x49, 0xb8, 0x2c, 0x88, 0xc8, + 0xf8, 0x04, 0x88, 0xf3, 0x6f, 0xec, 0x36, 0xd4, 0xe3, 0x71, 0xe7, 0xb2, 0x1e, 0x5e, 0x5a, 0xd4, 0x07, 0x4e, 0xb1, + 0xbb, 0x0d, 0xc6, 0xa0, 0x18, 0xa8, 0xbe, 0x43, 0x5a, 0x6b, 0x57, 0x99, 0x87, 0x18, 0x17, 0xf7, 0x5d, 0x0a, 0xf9, + 0xc2, 0x15, 0x6d, 0xb2, 0x96, 0xfa, 0xba, 0xd6, 0x89, 0x41, 0x87, 0x2a, 0xd7, 0xe3, 0xdc, 0xcf, 0xec, 0xa9, 0x33, + 0x77, 0x10, 0x1c, 0x47, 0xd8, 0x17, 0xd2, 0x0c, 0x1a, 0x7e, 0xab, 0x53, 0x42, 0xaa, 0x48, 0xd2, 0xeb, 0xaa, 0x9f, + 0x77, 0xee, 0x03, 0xde, 0x21, 0xa5, 0x25, 0x52, 0xd7, 0x31, 0x0b, 0x9b, 0x2e, 0xfa, 0x9d, 0xa4, 0xfe, 0xd2, 0x2e, + 0x21, 0xcc, 0x5c, 0x2c, 0xca, 0x02, 0xa8, 0xd0, 0xd0, 0x97, 0xce, 0x00, 0xe4, 0x63, 0x9f, 0x6f, 0x48, 0xcd, 0x54, + 0x49, 0xcd, 0xc0, 0xc1, 0xf8, 0x0e, 0x29, 0xc9, 0x14, 0x32, 0x94, 0x12, 0xa9, 0x84, 0x9e, 0xd9, 0x5c, 0x43, 0x42, + 0xee, 0x86, 0x96, 0xd7, 0xe7, 0xf4, 0x9e, 0xa7, 0x35, 0xb0, 0x7c, 0x35, 0x0e, 0x2e, 0x42, 0x58, 0x12, 0xd3, 0x0d, + 0x0a, 0xeb, 0xce, 0xc9, 0x6c, 0x7e, 0xab, 0x2f, 0x02, 0xbb, 0x2c, 0x6a, 0x51, 0xe2, 0x4f, 0xf1, 0x32, 0xf3, 0xa7, + 0x24, 0x85, 0x7c, 0x44, 0x51, 0x94, 0xf0, 0x33, 0x77, 0x37, 0x6a, 0xd9, 0xca, 0xdb, 0xaf, 0xf8, 0x81, 0x32, 0x2f, + 0x21, 0x47, 0x93, 0x64, 0x96, 0xa7, 0x64, 0xbe, 0xba, 0x6b, 0xe7, 0x6c, 0xdb, 0x57, 0x26, 0x45, 0xc7, 0x00, 0xf6, + 0x9d, 0xf4, 0x97, 0xce, 0x2a, 0xdc, 0xbb, 0xdc, 0xe6, 0xca, 0x9f, 0x09, 0xf6, 0x55, 0x49, 0xa4, 0x7e, 0x4e, 0xd7, + 0x24, 0xce, 0xdd, 0xb9, 0x96, 0x3f, 0x2f, 0x58, 0x76, 0x7b, 0xc6, 0x20, 0xd7, 0x59, 0xc0, 0x5d, 0xdf, 0x6a, 0x1b, + 0xaa, 0x3c, 0xf5, 0x7e, 0xaa, 0x94, 0x95, 0xa2, 0x7e, 0x09, 0x70, 0xfd, 0x8a, 0x60, 0xa1, 0xa2, 0x8d, 0x8e, 0x23, + 0x46, 0x9f, 0x16, 0xb6, 0xf3, 0xf2, 0x24, 0xeb, 0x72, 0xf0, 0xaf, 0x55, 0x98, 0x36, 0xc1, 0x02, 0x22, 0xdc, 0x0b, + 0xa9, 0x83, 0x7c, 0xb8, 0xee, 0x95, 0x81, 0x22, 0x08, 0xdf, 0xa5, 0xbb, 0x97, 0xba, 0x2d, 0x6b, 0x76, 0xf7, 0x52, + 0x6b, 0x41, 0x3f, 0x95, 0xf2, 0x43, 0xcc, 0x3c, 0xe5, 0xe5, 0x65, 0x5e, 0x14, 0xb8, 0x00, 0xf0, 0xbe, 0xef, 0xfa, + 0xfe, 0xf7, 0x26, 0x69, 0x30, 0x80, 0x58, 0xec, 0x59, 0x22, 0x2c, 0x13, 0xaf, 0xe6, 0xff, 0x7e, 0x63, 0xfe, 0xef, + 0x9d, 0x2b, 0xa7, 0x60, 0x1a, 0x4d, 0x52, 0x16, 0x5b, 0xd6, 0x89, 0x35, 0x01, 0x2a, 0xbd, 0x2d, 0x97, 0xf4, 0xe3, + 0x45, 0x08, 0x1a, 0xd7, 0x72, 0x2c, 0x52, 0xd9, 0x1c, 0x47, 0x33, 0x9e, 0xdc, 0x86, 0x0b, 0xde, 0x9c, 0x89, 0x54, + 0xe4, 0xf3, 0x68, 0xc4, 0x48, 0x7e, 0x9b, 0x4b, 0x36, 0x6b, 0x2e, 0x38, 0x79, 0xc9, 0x92, 0x2b, 0x26, 0xf9, 0x28, + 0x22, 0xe8, 0x24, 0xe3, 0x51, 0xe2, 0xbd, 0x89, 0xb2, 0x4c, 0x5c, 0x23, 0xf2, 0x4e, 0x5c, 0x0a, 0x29, 0xc8, 0xdb, + 0x9b, 0xdb, 0x09, 0x4b, 0xc9, 0x87, 0xcb, 0x45, 0x2a, 0x17, 0x24, 0x8f, 0xd2, 0xbc, 0x99, 0xb3, 0x8c, 0x8f, 0xbb, + 0x23, 0x91, 0x88, 0xac, 0x09, 0x29, 0xdb, 0x33, 0x16, 0x26, 0x7c, 0x32, 0x95, 0x5e, 0x1c, 0x65, 0x1f, 0xbb, 0xcd, + 0xe6, 0x3c, 0xe3, 0xb3, 0x28, 0xbb, 0x6d, 0xaa, 0x16, 0xe1, 0x67, 0xad, 0xa3, 0xe8, 0xf3, 0xf1, 0xc3, 0xae, 0xcc, + 0xa2, 0x34, 0xe7, 0xb0, 0x4d, 0x61, 0x94, 0x24, 0xde, 0xd1, 0xa3, 0xd6, 0x2c, 0xdf, 0xd3, 0x81, 0xbc, 0x28, 0x95, + 0xc5, 0x05, 0xf9, 0x08, 0x70, 0x07, 0x97, 0x32, 0x25, 0x97, 0x0b, 0x29, 0x45, 0xba, 0x1c, 0x2d, 0xb2, 0x5c, 0x64, + 0xe1, 0x5c, 0xf0, 0x54, 0xb2, 0xac, 0x7b, 0x29, 0xb2, 0x98, 0x65, 0xcd, 0x2c, 0x8a, 0xf9, 0x22, 0x0f, 0x1f, 0xce, + 0x6f, 0xba, 0xa0, 0x59, 0x4c, 0x32, 0xb1, 0x48, 0x63, 0x33, 0x17, 0x4f, 0xa7, 0x2c, 0xe3, 0xd2, 0xad, 0x50, 0xaf, + 0x30, 0x09, 0x13, 0x9e, 0xb2, 0x28, 0x6b, 0x4e, 0xa0, 0x33, 0x98, 0x45, 0xad, 0x98, 0x4d, 0x48, 0x36, 0xb9, 0x8c, + 0xfc, 0x76, 0xe7, 0x09, 0xb1, 0x7f, 0x83, 0x47, 0xd8, 0x6b, 0x6d, 0x2f, 0x6e, 0xb7, 0x5a, 0x7f, 0xc2, 0xdd, 0xb5, + 0x59, 0x14, 0x40, 0x61, 0x7b, 0x7e, 0xe3, 0xe5, 0x02, 0x72, 0xda, 0xb6, 0xf5, 0xec, 0xce, 0xa3, 0x18, 0x12, 0x82, + 0xc3, 0xce, 0xfc, 0xa6, 0x80, 0xd5, 0x85, 0x3a, 0xc9, 0xd4, 0x2c, 0xd2, 0x3c, 0x2d, 0x7f, 0x2b, 0xc4, 0x4f, 0xb7, + 0x43, 0xdc, 0xb1, 0x10, 0x57, 0x58, 0x6f, 0xc6, 0x8b, 0x4c, 0xc5, 0x56, 0xc3, 0x76, 0xae, 0x01, 0x99, 0x8a, 0x2b, + 0x96, 0x59, 0x38, 0xd4, 0xc3, 0x6f, 0x06, 0xa3, 0xb3, 0x1d, 0x8c, 0xa7, 0x9f, 0x02, 0x23, 0x4b, 0xe3, 0x65, 0x7d, + 0x5f, 0xdb, 0x19, 0x9b, 0x75, 0xa7, 0x0c, 0xe8, 0x29, 0xec, 0xc0, 0xef, 0x6b, 0x1e, 0xcb, 0xa9, 0xfe, 0xa9, 0xc8, + 0xf9, 0x5a, 0xd7, 0x3d, 0x6a, 0xb5, 0xf4, 0x73, 0xce, 0x7f, 0x61, 0x61, 0x3b, 0x80, 0x06, 0xc5, 0x05, 0xf9, 0x5b, + 0x79, 0x99, 0xb7, 0xce, 0x3d, 0xc9, 0x0f, 0xee, 0x2d, 0x5f, 0x27, 0x49, 0xb1, 0xba, 0x11, 0x4d, 0x32, 0x2b, 0x2b, + 0xb5, 0xf0, 0x01, 0xb7, 0x9d, 0x3a, 0x4f, 0x94, 0xf7, 0xca, 0x5b, 0x9c, 0xbc, 0xff, 0x83, 0xce, 0xbb, 0x08, 0x21, + 0xd2, 0xe1, 0x24, 0x1b, 0x8a, 0x6e, 0xda, 0xa3, 0xad, 0x6e, 0xda, 0x6c, 0x62, 0x5f, 0xd0, 0x6c, 0x90, 0x9a, 0xf4, + 0x3c, 0x9f, 0xf7, 0x85, 0x32, 0xb6, 0x73, 0x1c, 0x0a, 0xb8, 0x6a, 0xba, 0x5a, 0x55, 0x61, 0x00, 0xae, 0xae, 0x6b, + 0xfc, 0x4d, 0x9a, 0x06, 0x24, 0x77, 0x38, 0x79, 0x6a, 0x5f, 0xec, 0x92, 0x59, 0x5e, 0x91, 0x88, 0x91, 0xc2, 0x5c, + 0x30, 0x8f, 0xe4, 0x14, 0xbc, 0x14, 0xa5, 0xf8, 0xa9, 0x92, 0x98, 0xd0, 0x21, 0xc2, 0xfd, 0xac, 0xcc, 0x70, 0x83, + 0x4c, 0xbe, 0xac, 0x80, 0x51, 0xbe, 0x91, 0x14, 0x46, 0x24, 0xbf, 0x50, 0x6d, 0xd3, 0x59, 0x8b, 0x6e, 0x7c, 0x5f, + 0x8b, 0x8e, 0xa5, 0x92, 0xab, 0xdc, 0x6d, 0x1b, 0x71, 0x98, 0x46, 0xf9, 0xf9, 0x48, 0xdf, 0x95, 0xcc, 0xab, 0x9b, + 0x01, 0x91, 0x82, 0x5e, 0x1b, 0x69, 0x2c, 0x53, 0xf6, 0xe8, 0xf7, 0x72, 0xa7, 0x7d, 0x92, 0xdd, 0x65, 0x9f, 0x94, + 0x0b, 0xcf, 0xc5, 0x22, 0x1b, 0x41, 0x38, 0xd2, 0x48, 0xbd, 0x4d, 0xc7, 0x0d, 0x52, 0x2a, 0x06, 0x22, 0xd2, 0xc9, + 0x04, 0x95, 0x84, 0xbb, 0x2f, 0x95, 0x60, 0x2a, 0xe4, 0xa5, 0xef, 0x6b, 0x18, 0x11, 0x67, 0x97, 0x04, 0x32, 0x3b, + 0x56, 0x49, 0x8d, 0x7e, 0x4a, 0x7b, 0x69, 0xb0, 0x48, 0xf9, 0xcf, 0x0b, 0x76, 0xce, 0x41, 0xd7, 0xe4, 0x01, 0x8f, + 0x55, 0xac, 0x09, 0x64, 0x5f, 0xb3, 0x0d, 0xc1, 0x0b, 0x1e, 0xeb, 0x8d, 0x49, 0x55, 0xa5, 0xc9, 0x6d, 0x42, 0x4d, + 0x04, 0xfe, 0x62, 0xd0, 0x0e, 0x38, 0x89, 0xc5, 0x2c, 0xe2, 0x69, 0xa8, 0x5c, 0xbe, 0xe5, 0x60, 0x21, 0xb4, 0x26, + 0x3c, 0x0e, 0x53, 0xb3, 0x3d, 0x6d, 0x1c, 0xfc, 0x24, 0x78, 0xaa, 0xba, 0x16, 0x5d, 0xa1, 0x10, 0xaa, 0xd1, 0x47, + 0x2d, 0x82, 0x4f, 0xb4, 0x5c, 0x13, 0x98, 0xb8, 0xd5, 0xe5, 0xb5, 0xf3, 0xda, 0x0e, 0xb4, 0xd6, 0x36, 0x4a, 0x1b, + 0x01, 0x62, 0xbd, 0x34, 0x17, 0x99, 0xf4, 0xfd, 0x29, 0x49, 0x30, 0xed, 0x4d, 0x95, 0xb3, 0xeb, 0x38, 0x51, 0xff, + 0xf5, 0x9b, 0xed, 0xb0, 0x5d, 0x9a, 0xef, 0xb5, 0xdb, 0xc0, 0x3a, 0x39, 0xca, 0xdc, 0x28, 0x55, 0xcb, 0x28, 0x7f, + 0xeb, 0xa5, 0x56, 0xcf, 0xe5, 0x72, 0x89, 0x39, 0x6e, 0x5a, 0x54, 0xf9, 0x35, 0x20, 0x54, 0xb0, 0x68, 0xc7, 0x54, + 0xb8, 0xa8, 0xd6, 0x5d, 0xaa, 0x92, 0x17, 0x5a, 0x44, 0x9f, 0xef, 0x2f, 0x33, 0x33, 0x63, 0x71, 0xc1, 0xad, 0x93, + 0xa9, 0x4e, 0x72, 0x85, 0xc1, 0x88, 0xa3, 0x87, 0x6e, 0x6b, 0xa6, 0x61, 0xb9, 0xa5, 0xd9, 0x56, 0xba, 0x0d, 0xf4, + 0x23, 0xcb, 0x68, 0x15, 0xee, 0xda, 0x18, 0x00, 0x72, 0xf5, 0xb6, 0x01, 0x06, 0x66, 0x6b, 0x2e, 0xed, 0x12, 0x40, + 0x1b, 0x1b, 0x33, 0xb8, 0x48, 0x73, 0xb1, 0xbf, 0xfc, 0x46, 0x16, 0x87, 0x4e, 0x53, 0xf5, 0x9b, 0xc7, 0xf0, 0x3f, + 0x48, 0xc0, 0xa5, 0x56, 0x4a, 0x43, 0xf4, 0xf5, 0xdb, 0xb3, 0xf7, 0x88, 0x5c, 0x8a, 0xf8, 0x36, 0x44, 0x32, 0x5b, + 0x30, 0x54, 0xe0, 0x40, 0x4e, 0x59, 0x5a, 0xbe, 0x8c, 0x47, 0x24, 0x2c, 0x48, 0xc4, 0x44, 0x5f, 0xca, 0x5c, 0x37, + 0x92, 0x47, 0x17, 0xc7, 0xea, 0x25, 0x53, 0xbd, 0x63, 0xa9, 0x5f, 0xef, 0x25, 0x33, 0xf8, 0xd9, 0x83, 0x10, 0xca, + 0xf1, 0xa1, 0x9c, 0xaa, 0x87, 0x33, 0x38, 0x30, 0xea, 0x69, 0x7f, 0xb9, 0x41, 0x4c, 0x7d, 0x18, 0x62, 0xda, 0xd3, + 0x4b, 0xc8, 0x55, 0xab, 0x8b, 0x70, 0x74, 0x71, 0x51, 0x1c, 0x1f, 0xc2, 0x58, 0x87, 0x76, 0x5c, 0x80, 0xd0, 0xf6, + 0x2f, 0x09, 0x0c, 0x5e, 0x36, 0x94, 0xd1, 0x1e, 0x0c, 0x01, 0xf3, 0xc6, 0x3d, 0x58, 0x24, 0x10, 0x18, 0xf4, 0x8e, + 0xcb, 0x12, 0x75, 0x62, 0x75, 0xd1, 0x2e, 0x08, 0x74, 0xc3, 0x8a, 0xee, 0xb5, 0x37, 0xb5, 0xda, 0x5f, 0x0b, 0x52, + 0xec, 0x42, 0x77, 0x81, 0xe1, 0x7f, 0x05, 0xd9, 0xf1, 0xa1, 0xc6, 0xc3, 0x85, 0xfb, 0x6a, 0x13, 0xfd, 0xda, 0x81, + 0x12, 0x5b, 0x83, 0x5c, 0x92, 0x8f, 0x92, 0x7c, 0xbc, 0x50, 0x4d, 0xad, 0x30, 0x02, 0x2d, 0x09, 0x84, 0x76, 0xcb, + 0x6a, 0x1d, 0x23, 0x91, 0x24, 0xd1, 0x3c, 0x67, 0xa1, 0xfd, 0x61, 0xe4, 0x12, 0x88, 0xb7, 0x4d, 0x45, 0xc0, 0xa4, + 0xd7, 0x9c, 0x82, 0xba, 0xb0, 0xa9, 0xa5, 0x5c, 0x45, 0x99, 0xdf, 0x6c, 0x8e, 0x9a, 0x97, 0x13, 0x5c, 0xc8, 0xe9, + 0xd2, 0x95, 0x6a, 0x8f, 0x5b, 0xad, 0x2e, 0xe4, 0x42, 0x36, 0xa3, 0x84, 0x4f, 0xd2, 0x30, 0x61, 0x63, 0x59, 0x48, + 0xb8, 0xa5, 0xb6, 0xb4, 0x6a, 0x44, 0xd0, 0x79, 0x94, 0xb1, 0x99, 0x17, 0xc0, 0xbf, 0x77, 0x4f, 0x5c, 0xc8, 0x38, + 0x4c, 0xe5, 0xb4, 0xa9, 0xb2, 0x6e, 0xe1, 0xce, 0x80, 0x9c, 0xd6, 0x9e, 0x97, 0xce, 0x44, 0x23, 0x06, 0x2a, 0x56, + 0x21, 0x33, 0x4f, 0x4e, 0x89, 0xcc, 0xdc, 0x76, 0x29, 0x5e, 0x6e, 0xac, 0x60, 0x53, 0xd2, 0x1f, 0xe1, 0x22, 0x57, + 0x8a, 0xf1, 0x66, 0x63, 0xab, 0x2e, 0xd5, 0x9f, 0x36, 0xd0, 0xe7, 0x28, 0x76, 0x85, 0x76, 0x2c, 0x2f, 0x75, 0x8f, + 0xfb, 0x20, 0xb3, 0xa6, 0x72, 0x12, 0xb7, 0x07, 0x2e, 0x78, 0x3a, 0x5f, 0xc8, 0x81, 0x72, 0x6a, 0x67, 0x70, 0x41, + 0x62, 0x48, 0x9c, 0x12, 0xc0, 0xc1, 0x70, 0xa9, 0x81, 0x19, 0x45, 0xc9, 0xc8, 0x07, 0x88, 0xbc, 0xa6, 0xf7, 0x34, + 0x63, 0x33, 0xdc, 0x9d, 0xf1, 0xb4, 0xa9, 0xeb, 0x1e, 0x39, 0x6a, 0x49, 0xf0, 0x04, 0x9e, 0x8a, 0x40, 0x8d, 0x46, + 0x54, 0xee, 0xea, 0x16, 0x5c, 0x5e, 0x0c, 0x8b, 0xa2, 0x9b, 0x49, 0x7f, 0xf0, 0xda, 0xc7, 0x43, 0xf2, 0x8b, 0xf3, + 0x72, 0x16, 0x64, 0x8f, 0x0a, 0x22, 0x1d, 0xbc, 0xa3, 0x89, 0x7b, 0x16, 0x54, 0xb3, 0x5f, 0x28, 0x34, 0x7c, 0xe7, + 0x23, 0x96, 0xcf, 0x9b, 0x9a, 0x77, 0x35, 0x15, 0xc9, 0x22, 0xe8, 0x8a, 0x8d, 0xa7, 0xf6, 0x7b, 0xb9, 0x54, 0x6c, + 0xc9, 0x5c, 0xd2, 0xd0, 0xce, 0x84, 0x61, 0x79, 0xa9, 0xc7, 0x3c, 0xbb, 0xd7, 0x78, 0x70, 0x8d, 0x9f, 0x5c, 0x9c, + 0xd4, 0x79, 0x1c, 0xf0, 0xa5, 0xf2, 0x05, 0x76, 0x51, 0x92, 0xc0, 0x84, 0x17, 0x56, 0x7d, 0x71, 0x5f, 0xfa, 0x31, + 0x90, 0x43, 0x1f, 0x17, 0xe6, 0x9c, 0x3e, 0x53, 0x2a, 0xa5, 0xf3, 0xd6, 0xbc, 0x3d, 0x69, 0x83, 0x45, 0x5a, 0xfa, + 0x72, 0x08, 0x77, 0xd7, 0xf2, 0xa2, 0xbb, 0x15, 0xef, 0xd2, 0x0a, 0xa9, 0xa7, 0x16, 0x44, 0x51, 0x96, 0xc6, 0xc8, + 0xfb, 0xcb, 0x28, 0xe1, 0xa3, 0x8f, 0x14, 0xed, 0x2f, 0x7d, 0xbc, 0x79, 0xed, 0x51, 0x71, 0x05, 0xcb, 0xb0, 0x71, + 0xdd, 0x91, 0x9e, 0x06, 0x0e, 0x2f, 0xd6, 0x6f, 0xc5, 0x41, 0xbd, 0xfd, 0x25, 0x30, 0x1e, 0x3d, 0x4f, 0xef, 0xa2, + 0x38, 0xaf, 0xde, 0x75, 0x55, 0x41, 0x01, 0x68, 0xd6, 0xe5, 0x9e, 0x22, 0x2a, 0x8a, 0x3e, 0x49, 0x69, 0xc8, 0xd3, + 0x4c, 0x0d, 0xe0, 0x94, 0x86, 0xbf, 0x21, 0xef, 0x2f, 0x65, 0x19, 0x2b, 0x3d, 0x1a, 0x2a, 0x25, 0x83, 0x22, 0x98, + 0x0b, 0xcc, 0xd8, 0x20, 0x66, 0x32, 0xe2, 0x89, 0xee, 0xd2, 0xb5, 0x06, 0xf8, 0xda, 0x8a, 0x56, 0xab, 0xbc, 0xbe, + 0x16, 0x5e, 0xc7, 0xa0, 0x5a, 0xd9, 0xf1, 0x61, 0x05, 0xb7, 0x5a, 0x99, 0x3a, 0x93, 0x6e, 0x68, 0xb0, 0x5a, 0xa1, + 0xae, 0xf3, 0xfe, 0x32, 0x52, 0xd7, 0x86, 0x00, 0x40, 0x61, 0x00, 0x84, 0xa0, 0xb5, 0xbe, 0x16, 0xe3, 0x27, 0x54, + 0x04, 0x32, 0xca, 0x26, 0x4c, 0xae, 0x21, 0x36, 0xd1, 0x39, 0xaa, 0x5d, 0x1b, 0xa0, 0xde, 0x80, 0x36, 0xaa, 0x43, + 0x7b, 0x01, 0x48, 0xef, 0xef, 0x2f, 0x79, 0x41, 0xf7, 0x97, 0x2c, 0x1d, 0x89, 0x98, 0x7d, 0x78, 0xf7, 0x25, 0x5c, + 0x72, 0x14, 0x29, 0x18, 0x16, 0x53, 0x0c, 0x82, 0x53, 0x6d, 0x8e, 0x16, 0x21, 0x42, 0x89, 0x10, 0xcd, 0x09, 0x3c, + 0x35, 0x97, 0x02, 0xb1, 0x40, 0x5e, 0x5f, 0x43, 0xce, 0x62, 0x0d, 0x33, 0x4d, 0x55, 0x2f, 0x51, 0x1c, 0x1f, 0xea, + 0xd6, 0x5a, 0x04, 0xe8, 0x46, 0x80, 0x04, 0x75, 0x4e, 0x2b, 0x1c, 0x40, 0x5e, 0xb3, 0x8b, 0x87, 0x98, 0x5f, 0x95, + 0xc4, 0xa6, 0x2e, 0x50, 0xf5, 0x8e, 0x93, 0xe8, 0x92, 0x25, 0xbd, 0xfd, 0x65, 0xba, 0x5a, 0xb5, 0x8a, 0xe3, 0x43, + 0xfd, 0xe8, 0x1d, 0x2b, 0xbe, 0xa1, 0x5f, 0x78, 0xa9, 0xb6, 0x18, 0x6e, 0x25, 0x42, 0xb6, 0xa7, 0x4d, 0x73, 0x0a, + 0xcd, 0x00, 0x05, 0xf2, 0x54, 0x82, 0x85, 0x6a, 0x54, 0x2a, 0x44, 0x05, 0xf2, 0x78, 0xbc, 0x59, 0x96, 0x4b, 0x36, + 0x87, 0xd2, 0xe9, 0x6a, 0xd5, 0x2e, 0x90, 0x37, 0xe3, 0x29, 0x3c, 0xa5, 0xab, 0x95, 0xba, 0xf0, 0x37, 0xe3, 0xa9, + 0xdf, 0x02, 0xb2, 0x45, 0xde, 0x2c, 0xba, 0x51, 0x0b, 0xb6, 0x35, 0xd1, 0x8d, 0xdf, 0x36, 0x55, 0x41, 0x89, 0x9f, + 0x1c, 0x28, 0xae, 0xda, 0xd1, 0xc4, 0xec, 0x68, 0x4c, 0x16, 0xfa, 0x2a, 0x13, 0xf5, 0x63, 0x9a, 0x6c, 0xdf, 0xd1, + 0xd8, 0xee, 0xe8, 0x62, 0xc7, 0x8e, 0x2e, 0xee, 0xd8, 0xd1, 0xc8, 0xec, 0x9e, 0x57, 0xe2, 0x4e, 0xac, 0x56, 0xed, + 0x56, 0x85, 0xbd, 0xe3, 0xc3, 0x98, 0x5f, 0xc1, 0x6e, 0x80, 0x9a, 0x27, 0xf9, 0x8c, 0x6d, 0x27, 0xca, 0x3a, 0x8a, + 0xd9, 0xaf, 0xc2, 0x64, 0x85, 0x85, 0xb4, 0x8e, 0x05, 0x97, 0xae, 0xcb, 0x98, 0xdb, 0x1f, 0x49, 0xd9, 0x1c, 0xf0, + 0x90, 0x03, 0x1e, 0xa6, 0xf6, 0x05, 0x98, 0x3e, 0x7a, 0x8f, 0x08, 0xf2, 0x90, 0x25, 0xeb, 0x8b, 0xe2, 0x1c, 0x64, + 0x84, 0x5a, 0xdf, 0xbd, 0x68, 0x11, 0x5a, 0xa3, 0xde, 0x6e, 0x9a, 0x83, 0xf0, 0xf8, 0xb5, 0xc8, 0x62, 0x14, 0xea, + 0xa6, 0xbf, 0x0a, 0x55, 0x33, 0x9e, 0x9a, 0x64, 0xab, 0x9d, 0xb4, 0x56, 0xd5, 0xbb, 0x14, 0xd7, 0x79, 0xf4, 0x48, + 0xb7, 0x98, 0x47, 0x52, 0xb2, 0x2c, 0x35, 0x94, 0x8b, 0xd0, 0xff, 0x17, 0x54, 0xb8, 0x85, 0xaf, 0x44, 0x76, 0x03, + 0x2c, 0x01, 0x1a, 0x85, 0xdd, 0xf0, 0x7c, 0x2d, 0x9e, 0xf6, 0x2a, 0x0d, 0xf6, 0x16, 0xbb, 0x46, 0x83, 0x2e, 0x02, + 0x1b, 0x66, 0x31, 0x63, 0xf1, 0xb9, 0x62, 0xd0, 0xfd, 0xd1, 0x85, 0x51, 0x58, 0xd7, 0xc4, 0x5d, 0xd5, 0x81, 0xa0, + 0x1f, 0x17, 0x9d, 0x27, 0x0f, 0x4f, 0x11, 0xd1, 0x3c, 0x5e, 0x8c, 0xc7, 0x08, 0x17, 0xde, 0xfd, 0xba, 0xb5, 0x1f, + 0xfe, 0xb8, 0xf8, 0xe2, 0x45, 0xeb, 0x8b, 0xb2, 0x73, 0x0a, 0x44, 0x64, 0xe2, 0xfb, 0x56, 0x54, 0x39, 0xf0, 0xda, + 0x15, 0x8d, 0xa3, 0x74, 0xf7, 0x72, 0x06, 0xee, 0x72, 0xf2, 0x39, 0x63, 0x31, 0x10, 0x27, 0xd9, 0x28, 0x3d, 0x4f, + 0xd8, 0x15, 0xb3, 0x6f, 0x1e, 0xdc, 0x32, 0xd9, 0x96, 0x1e, 0x23, 0xb1, 0x48, 0xa5, 0x49, 0x74, 0x30, 0xac, 0xd6, + 0x59, 0xd2, 0x85, 0x5a, 0x83, 0x6b, 0x23, 0xdc, 0x6a, 0x39, 0x57, 0x97, 0x5e, 0xc5, 0x05, 0x41, 0x0e, 0x00, 0x3b, + 0x21, 0xeb, 0xef, 0x28, 0x0f, 0x5b, 0xa4, 0xb5, 0x0b, 0x36, 0xd2, 0xc6, 0x21, 0x42, 0x43, 0x8b, 0x27, 0xe5, 0xab, + 0xac, 0xbd, 0x30, 0x62, 0x27, 0xbe, 0x3e, 0x89, 0x81, 0xcb, 0x0c, 0x06, 0x4b, 0x59, 0x9e, 0xef, 0x44, 0x40, 0xb9, + 0x89, 0x04, 0x55, 0xad, 0xd1, 0x8e, 0x51, 0x48, 0x8b, 0xc0, 0x09, 0x53, 0x00, 0x97, 0x11, 0x53, 0xd3, 0x8a, 0x8d, + 0xc7, 0x6c, 0x54, 0xba, 0x7a, 0x21, 0xf6, 0x35, 0xe6, 0x89, 0x84, 0x10, 0x90, 0x8a, 0xcd, 0xa0, 0x37, 0x22, 0x65, + 0x08, 0xdb, 0x6c, 0x4e, 0x03, 0xbf, 0x91, 0xff, 0xdb, 0xe1, 0xd1, 0x23, 0xd6, 0x61, 0x31, 0xb3, 0xac, 0x56, 0xd6, + 0xcd, 0x53, 0x2b, 0xaf, 0x23, 0x52, 0x28, 0x3f, 0xce, 0xae, 0x03, 0x74, 0xbf, 0x63, 0xb2, 0x6c, 0x7f, 0xf1, 0xa8, + 0xdd, 0x2a, 0x10, 0x41, 0x30, 0xdc, 0x7d, 0x4f, 0x89, 0xea, 0x75, 0x04, 0xbd, 0x16, 0xe9, 0xaf, 0xe9, 0xd7, 0x69, + 0x7f, 0xde, 0x46, 0x44, 0xbf, 0x48, 0x00, 0x17, 0x25, 0x33, 0x18, 0x81, 0xf3, 0xf3, 0x77, 0x2f, 0xa5, 0x3e, 0xf8, + 0xfd, 0xe0, 0x79, 0xdc, 0x6e, 0x21, 0x82, 0x72, 0x29, 0xe6, 0xbf, 0x62, 0x09, 0x47, 0x88, 0xa0, 0x51, 0x22, 0x72, + 0xe6, 0xae, 0x41, 0xab, 0xb3, 0xbf, 0x7f, 0x11, 0x1a, 0xa2, 0x79, 0xc6, 0xf2, 0xdc, 0x73, 0xc7, 0x37, 0xa4, 0xf4, + 0x09, 0x86, 0xb9, 0x95, 0xe2, 0x72, 0x26, 0x15, 0x5e, 0xf4, 0x1d, 0x7f, 0x97, 0xaa, 0x74, 0xd9, 0x06, 0xb1, 0x29, + 0x11, 0x50, 0x32, 0x36, 0xad, 0x5d, 0x7d, 0x72, 0xe6, 0x2d, 0x47, 0x4f, 0x4f, 0xac, 0x63, 0xc2, 0x9b, 0x13, 0xd4, + 0x4a, 0x66, 0x3c, 0x3d, 0xdf, 0x52, 0x1a, 0xdd, 0x6c, 0x29, 0x05, 0x95, 0xad, 0x84, 0xce, 0xbc, 0x7e, 0xe6, 0xd3, + 0x58, 0xaf, 0x14, 0x1f, 0x17, 0xc4, 0x58, 0xf9, 0x2d, 0x3f, 0x01, 0xa9, 0xb3, 0x0d, 0x6a, 0x84, 0xdf, 0x3e, 0x1d, + 0x94, 0xfc, 0x9a, 0xe9, 0xca, 0x51, 0x7e, 0xdf, 0x0a, 0xa1, 0xb4, 0x09, 0xfe, 0xeb, 0xe4, 0x57, 0xad, 0x95, 0xdd, + 0x7c, 0x9a, 0xe0, 0x1c, 0xad, 0xea, 0x77, 0x6c, 0xbd, 0xb9, 0xc7, 0xbe, 0xbe, 0xf7, 0x5b, 0x8a, 0x8d, 0xe2, 0x53, + 0xee, 0xff, 0x28, 0xe1, 0xb3, 0x8a, 0x04, 0x36, 0xc1, 0x54, 0x1a, 0x0f, 0x24, 0x33, 0xb9, 0x83, 0x68, 0xd5, 0xe7, + 0x1c, 0xae, 0x68, 0xc2, 0x7b, 0x30, 0x16, 0x19, 0x3b, 0x4f, 0xc4, 0xf5, 0xfa, 0x7b, 0xbd, 0x76, 0x37, 0x9e, 0xf2, + 0xc9, 0xd4, 0xb9, 0x77, 0xc5, 0x68, 0xb9, 0x09, 0x77, 0x4e, 0x50, 0xfc, 0xeb, 0xbf, 0x04, 0xc1, 0xbf, 0xfe, 0xcb, + 0x27, 0x9b, 0xc2, 0xf0, 0xc5, 0x05, 0x91, 0xd5, 0xb0, 0xbb, 0x4f, 0xd7, 0xf6, 0x99, 0xea, 0x38, 0xdf, 0xde, 0x66, + 0x63, 0x13, 0xa0, 0x7e, 0x63, 0x0b, 0x36, 0x0a, 0xf5, 0xe9, 0xf3, 0x7e, 0x0b, 0x60, 0xb0, 0xae, 0x4f, 0x42, 0x06, + 0x8d, 0x7e, 0x17, 0x68, 0x17, 0x38, 0xbc, 0xd7, 0x8e, 0xfc, 0x76, 0x0c, 0x7f, 0x6a, 0x0d, 0xbf, 0x13, 0x7c, 0xe3, + 0x9f, 0x18, 0x5d, 0x5c, 0x94, 0x09, 0x76, 0x6e, 0x57, 0xb8, 0xc0, 0xdf, 0xdf, 0x28, 0x31, 0x8a, 0x47, 0xd8, 0xc2, + 0x3d, 0x75, 0x3d, 0x90, 0x8e, 0x2e, 0x5e, 0xc3, 0x5b, 0x7b, 0x8e, 0x2f, 0x33, 0xeb, 0xe0, 0xbd, 0x43, 0x38, 0xc0, + 0x10, 0xf5, 0x55, 0xa9, 0x41, 0x37, 0x24, 0x03, 0x94, 0x82, 0xb9, 0x01, 0x60, 0x92, 0xd1, 0x85, 0xb1, 0x36, 0x4f, + 0xb5, 0x1b, 0x26, 0x5c, 0x27, 0x6d, 0xe3, 0x9e, 0xa9, 0x21, 0x9d, 0x78, 0xef, 0x15, 0xbe, 0x54, 0x63, 0x56, 0x59, + 0xf7, 0xca, 0xd5, 0x05, 0x76, 0xc4, 0x45, 0xa1, 0xc2, 0xf4, 0x7f, 0xdd, 0x15, 0x49, 0xfc, 0xfb, 0xa7, 0x23, 0x89, + 0xe2, 0x5e, 0x91, 0xc4, 0xbf, 0xff, 0xe1, 0x91, 0xc4, 0xbf, 0xba, 0x91, 0x44, 0xd8, 0xc4, 0x2f, 0xef, 0x15, 0xed, + 0xb3, 0x91, 0x18, 0x71, 0x9d, 0xd3, 0xb6, 0x51, 0xa3, 0x13, 0x31, 0x81, 0x50, 0xdf, 0xbf, 0x7f, 0xe4, 0x2e, 0x11, + 0x13, 0x37, 0x6e, 0x07, 0x6f, 0x6d, 0x85, 0x40, 0x5d, 0xd7, 0x46, 0xd8, 0x4c, 0xac, 0xac, 0x55, 0xde, 0x48, 0x69, + 0x3e, 0xb4, 0x6f, 0x50, 0x40, 0x61, 0xf9, 0x16, 0xa4, 0x16, 0xe9, 0xd8, 0x68, 0x5a, 0xa8, 0x02, 0x71, 0x65, 0xc7, + 0x4e, 0xc3, 0x5e, 0xb7, 0x70, 0x47, 0xe8, 0xda, 0xb7, 0xbc, 0xe8, 0xdb, 0xf7, 0x4b, 0xf4, 0xe3, 0x4d, 0xfb, 0xd9, + 0xa0, 0xdd, 0x3d, 0x6a, 0xcf, 0x50, 0x88, 0x40, 0x44, 0xaa, 0x82, 0x56, 0xf7, 0xe8, 0x08, 0x0a, 0xae, 0x9d, 0x82, + 0x0e, 0x14, 0x70, 0xa7, 0xe0, 0x11, 0x14, 0x8c, 0x9c, 0x82, 0xc7, 0x50, 0x10, 0x3b, 0x05, 0x4f, 0xa0, 0xe0, 0x0a, + 0x15, 0x03, 0x5e, 0x82, 0xfb, 0x04, 0x0f, 0x89, 0xb6, 0x5c, 0x6c, 0xd9, 0x13, 0xd2, 0x86, 0x10, 0x5e, 0x34, 0x51, + 0x99, 0x47, 0xe0, 0x10, 0x0c, 0x05, 0xb9, 0x9e, 0xb2, 0x34, 0x84, 0x20, 0xea, 0x73, 0x25, 0x63, 0x02, 0x29, 0xde, + 0xf3, 0x19, 0xb3, 0xdf, 0xcb, 0xb0, 0x78, 0xf0, 0x10, 0x1e, 0xb4, 0x86, 0x45, 0xb7, 0xdc, 0x39, 0x1d, 0xfb, 0x33, + 0x59, 0x28, 0x7a, 0x2f, 0xab, 0x3a, 0x3d, 0x5d, 0xb3, 0xdc, 0xf3, 0x1d, 0x31, 0x24, 0xc7, 0x17, 0x31, 0x4e, 0xc4, + 0x75, 0xf3, 0x06, 0xf5, 0xb6, 0xc7, 0x95, 0x00, 0xa2, 0x32, 0xae, 0xa4, 0xd6, 0x54, 0x3e, 0xbd, 0x8f, 0x26, 0xe5, + 0xef, 0xd7, 0x2c, 0xcf, 0xa3, 0x89, 0x69, 0xb9, 0x3b, 0x8e, 0xa4, 0x40, 0x74, 0x63, 0x48, 0x16, 0x08, 0x88, 0x05, + 0xc1, 0x66, 0x81, 0x2d, 0x6f, 0x42, 0x43, 0x80, 0x9d, 0x7a, 0x54, 0x49, 0x4d, 0x5f, 0x2f, 0x92, 0xd1, 0xa4, 0x2a, + 0x38, 0x9e, 0x67, 0x4c, 0x95, 0x6a, 0x0c, 0x17, 0xc7, 0x87, 0x50, 0xa0, 0xab, 0x77, 0x44, 0x8f, 0xac, 0xe3, 0x60, + 0x77, 0x0c, 0xc9, 0xb3, 0xd1, 0x23, 0x37, 0xdf, 0xa6, 0x4c, 0xb6, 0xd9, 0x8c, 0x59, 0x7c, 0xd6, 0x1e, 0xc1, 0x1f, + 0x13, 0x11, 0xf9, 0x6c, 0x3c, 0x1e, 0xdf, 0x19, 0x4d, 0xfa, 0x2c, 0x1e, 0xb3, 0x0e, 0x7b, 0xd4, 0x85, 0x5c, 0x8c, + 0xa6, 0x89, 0x41, 0xb4, 0x0b, 0x85, 0xbb, 0xe5, 0xfd, 0x1a, 0x43, 0xb8, 0x42, 0x4e, 0x97, 0xf7, 0x8f, 0x2c, 0x15, + 0xf3, 0x8c, 0x2d, 0x67, 0x51, 0x36, 0xe1, 0x69, 0xd8, 0x2a, 0x82, 0x2b, 0x13, 0x8a, 0xf9, 0xec, 0xe9, 0xd3, 0xa7, + 0x45, 0x10, 0xdb, 0xa7, 0x56, 0x1c, 0x17, 0xc1, 0x68, 0x59, 0x2e, 0xa3, 0xd5, 0x1a, 0x8f, 0x8b, 0x80, 0xdb, 0x82, + 0xa3, 0xce, 0x28, 0x3e, 0xea, 0x14, 0xc1, 0xb5, 0xd3, 0xa2, 0x08, 0x98, 0x79, 0xca, 0x58, 0x5c, 0x4b, 0xe8, 0x78, + 0xd2, 0x6a, 0x15, 0x81, 0x26, 0xb4, 0x25, 0x98, 0x63, 0xfa, 0x67, 0x18, 0x2d, 0xa4, 0x00, 0x96, 0xdc, 0x15, 0xd2, + 0x1f, 0x9c, 0x9b, 0x97, 0x65, 0xe8, 0x0f, 0x4b, 0x14, 0x78, 0x48, 0xbe, 0x74, 0x83, 0x26, 0x40, 0xcc, 0x2a, 0x58, + 0x22, 0x6c, 0x4c, 0xa5, 0x56, 0x0d, 0x94, 0xa5, 0xaa, 0xbf, 0xa4, 0xa2, 0x8a, 0xa5, 0x00, 0xff, 0x81, 0x96, 0xfa, + 0xad, 0x6e, 0x92, 0xed, 0xe0, 0xfa, 0x8c, 0x7d, 0x92, 0xeb, 0xdf, 0xde, 0x87, 0xe9, 0x33, 0xf6, 0x47, 0x33, 0x7d, + 0xf3, 0xea, 0x53, 0xcd, 0xf4, 0x35, 0x5b, 0x9b, 0x49, 0x8a, 0x46, 0x53, 0x36, 0xfa, 0x78, 0x29, 0x6e, 0x9a, 0x70, + 0x24, 0x32, 0xa4, 0xf8, 0xe9, 0xfe, 0x6f, 0x4d, 0xfe, 0xb0, 0x83, 0x39, 0xdf, 0xa5, 0x50, 0x62, 0xf3, 0x6d, 0x4a, + 0xd1, 0x5b, 0x6b, 0xd3, 0xe9, 0x92, 0xf1, 0x98, 0xa2, 0xb7, 0xe3, 0x31, 0xb2, 0x57, 0xfe, 0x22, 0xc9, 0x54, 0xab, + 0x37, 0xb5, 0x12, 0xd5, 0xea, 0x8b, 0x2f, 0xdc, 0x32, 0xb7, 0xc0, 0x84, 0x5c, 0xdc, 0xf0, 0x8a, 0xa9, 0x89, 0x79, + 0x0e, 0x47, 0x0d, 0x3e, 0x97, 0x51, 0x7f, 0xe7, 0x60, 0x56, 0x7b, 0x3d, 0x74, 0x09, 0xf0, 0x96, 0x77, 0x5a, 0xaf, + 0xdf, 0x77, 0x9f, 0x30, 0x9b, 0x7e, 0xf7, 0xec, 0xf6, 0xcb, 0xd8, 0x9f, 0x49, 0x5c, 0xf0, 0xfc, 0x6d, 0xba, 0x76, + 0x97, 0x45, 0xc3, 0x48, 0xa9, 0xbb, 0xac, 0x42, 0x8a, 0xc9, 0x24, 0x81, 0x0f, 0x96, 0x2c, 0x6b, 0xef, 0x41, 0xd5, + 0xdd, 0xfb, 0xb5, 0xf5, 0x86, 0x6e, 0x47, 0xf3, 0xd6, 0x50, 0xf5, 0xfd, 0x24, 0x9d, 0x03, 0x7d, 0x65, 0x3e, 0xa4, + 0xa3, 0xcc, 0xc1, 0xa5, 0xe1, 0xff, 0x4b, 0x9d, 0x39, 0x2b, 0x21, 0x6b, 0x44, 0x0f, 0x1c, 0x17, 0x85, 0xb9, 0x73, + 0x10, 0xf3, 0x7c, 0x0e, 0xef, 0xe7, 0xd4, 0x3d, 0xd9, 0xa7, 0x58, 0x78, 0x7e, 0xed, 0xc4, 0x35, 0x6a, 0xdb, 0x55, + 0xd8, 0xc0, 0x86, 0x76, 0x14, 0xcf, 0x64, 0x81, 0x8c, 0xbf, 0xd9, 0x22, 0x11, 0x79, 0x1a, 0x9f, 0x3a, 0xe2, 0xe2, + 0xac, 0x10, 0x9c, 0xbe, 0xe5, 0x86, 0xd8, 0x2a, 0x5b, 0x50, 0xb8, 0x71, 0x3b, 0x55, 0xa3, 0xb1, 0xa5, 0xa2, 0x04, + 0xf9, 0x3c, 0x4a, 0x35, 0x1b, 0xa5, 0x48, 0xf3, 0x83, 0xfd, 0x65, 0xb5, 0xf3, 0x05, 0xb2, 0x60, 0x6b, 0xe2, 0xed, + 0x1d, 0x1f, 0x42, 0x87, 0x9e, 0x57, 0x03, 0x3d, 0xdd, 0x08, 0x2e, 0x7c, 0x22, 0xcc, 0x7f, 0x11, 0xe4, 0xd7, 0x24, + 0xc8, 0xaf, 0xbd, 0x3f, 0x2f, 0x9b, 0xd7, 0xec, 0xf2, 0x23, 0x97, 0x4d, 0x19, 0xcd, 0x9b, 0xa0, 0xf0, 0x2b, 0xa7, + 0xa0, 0x61, 0xcf, 0x2a, 0x59, 0x4d, 0xdf, 0xd8, 0xef, 0x2e, 0x72, 0xc8, 0x06, 0x50, 0x6a, 0x6b, 0x98, 0x8a, 0x94, + 0x75, 0xeb, 0x49, 0x89, 0x6e, 0x70, 0xd9, 0x62, 0x6b, 0xb8, 0x14, 0x90, 0x3d, 0x20, 0x6f, 0xc3, 0x96, 0x61, 0xeb, + 0x2d, 0x1b, 0x39, 0x6e, 0x6d, 0x6d, 0x1f, 0x1a, 0xe4, 0x36, 0x94, 0xf4, 0xca, 0x36, 0x23, 0xe8, 0xbb, 0x22, 0xe0, + 0x9f, 0x4a, 0xd1, 0x03, 0x57, 0xa2, 0xfd, 0xeb, 0xe4, 0x36, 0xae, 0x17, 0xab, 0x14, 0xbd, 0xfb, 0x40, 0x16, 0x46, + 0x63, 0xc9, 0x32, 0x72, 0x9f, 0x96, 0x97, 0xea, 0x36, 0xcd, 0x12, 0xc4, 0x4c, 0xd8, 0x7e, 0x3a, 0xbf, 0xb9, 0xff, + 0xf0, 0x77, 0x2f, 0xbf, 0x30, 0x38, 0xb2, 0x6f, 0x97, 0x41, 0xa8, 0x0b, 0x07, 0x21, 0x89, 0x6e, 0x43, 0x9e, 0x2a, + 0x99, 0x77, 0x09, 0xfe, 0xc0, 0xee, 0x5c, 0x98, 0x5c, 0xd3, 0x8c, 0x25, 0xea, 0x53, 0x72, 0x66, 0x2b, 0x8e, 0x1e, + 0xcf, 0x6f, 0xec, 0x6e, 0xb4, 0xd7, 0x72, 0x48, 0xff, 0xd0, 0x54, 0xd1, 0xdd, 0xb9, 0xa9, 0xf5, 0x74, 0xc7, 0x47, + 0xf3, 0x9b, 0xae, 0x16, 0xb4, 0xcd, 0x4c, 0x43, 0xd5, 0x9a, 0xdf, 0xb8, 0xc9, 0xb2, 0xd5, 0x40, 0x5e, 0x70, 0x94, + 0x7b, 0x2c, 0xca, 0x59, 0x17, 0xde, 0x9f, 0xcd, 0x47, 0x51, 0x62, 0x84, 0xf9, 0x8c, 0xc7, 0x71, 0xc2, 0xba, 0x56, + 0x5e, 0x7b, 0xed, 0xc7, 0x90, 0x6b, 0xea, 0x6e, 0x59, 0x7d, 0x57, 0x1c, 0xe4, 0x95, 0x78, 0x8a, 0x2e, 0x73, 0x91, + 0xc0, 0xc7, 0x2b, 0xb6, 0xa2, 0xd3, 0x24, 0x61, 0xb6, 0x2a, 0xe4, 0xa9, 0xdf, 0xf5, 0xb5, 0x3c, 0x6a, 0xfd, 0xa9, + 0xab, 0x36, 0xbc, 0xd5, 0x95, 0x62, 0x1e, 0x36, 0x8f, 0xea, 0x0b, 0x81, 0xaa, 0x72, 0x09, 0x64, 0xcb, 0xb2, 0x08, + 0x48, 0x2b, 0xcd, 0xa7, 0xbd, 0xa0, 0x6d, 0xca, 0xd4, 0x00, 0xf0, 0xa2, 0xe7, 0xb2, 0xa8, 0xa8, 0x2f, 0xe6, 0xdf, + 0xe7, 0xb4, 0x7c, 0xbe, 0xfd, 0xb4, 0x7c, 0x6e, 0x4f, 0xcb, 0xdd, 0x14, 0xfb, 0xd9, 0xb8, 0x0d, 0x7f, 0xba, 0xd5, + 0x82, 0xc2, 0x96, 0x77, 0x34, 0xbf, 0xf1, 0x40, 0x4f, 0x6b, 0x76, 0xe6, 0x37, 0x3a, 0x55, 0x18, 0x62, 0x16, 0x2d, + 0x48, 0x9e, 0x25, 0x2d, 0x0f, 0x0a, 0xe1, 0x6f, 0xab, 0x56, 0xd5, 0x7e, 0x08, 0x75, 0xd0, 0xeb, 0xd1, 0x66, 0x5d, + 0xe7, 0xee, 0x43, 0x1b, 0xa6, 0x42, 0xfa, 0xa1, 0xe5, 0xc6, 0x38, 0x90, 0xd1, 0xe5, 0x25, 0x8b, 0xc3, 0xb1, 0x18, + 0x2d, 0xf2, 0x7f, 0x36, 0xf0, 0x1b, 0x24, 0xde, 0x79, 0xa4, 0xd7, 0xc6, 0xb1, 0x5d, 0x75, 0xe2, 0xb2, 0x1d, 0x61, + 0x59, 0xee, 0x53, 0x98, 0x8f, 0xa2, 0x84, 0xf9, 0x9d, 0xe0, 0xe1, 0x96, 0x43, 0xf0, 0x1f, 0xb2, 0x37, 0x5b, 0x17, + 0xf3, 0x7b, 0x91, 0x71, 0x27, 0x12, 0x7e, 0x15, 0x0e, 0xdc, 0x3d, 0x6c, 0x3d, 0xdd, 0x0e, 0xee, 0xc0, 0xce, 0x34, + 0xb4, 0x42, 0xc1, 0xc8, 0x9d, 0x98, 0x8d, 0xa3, 0x45, 0x22, 0xef, 0x1e, 0x75, 0x17, 0x65, 0x6c, 0x8c, 0x7a, 0x07, + 0x43, 0xaf, 0xda, 0xde, 0x93, 0x4b, 0x7f, 0xf6, 0xf9, 0x43, 0xf8, 0xa3, 0xf3, 0x9e, 0x6e, 0x2b, 0x5d, 0x5d, 0xdb, + 0xaa, 0xa0, 0xab, 0xef, 0xd7, 0x94, 0x71, 0x2d, 0xc2, 0x95, 0x3e, 0x7e, 0xdf, 0xd6, 0xa0, 0x55, 0xde, 0xab, 0xb9, + 0xd1, 0xb2, 0x7e, 0x55, 0xeb, 0x5f, 0x37, 0xf8, 0x3d, 0xdb, 0x8e, 0xb4, 0xe6, 0x5a, 0x6f, 0x6b, 0xbe, 0xa5, 0xb7, + 0xd1, 0xd8, 0x62, 0x5c, 0xb5, 0xdf, 0xa7, 0xb7, 0xa5, 0x89, 0xa2, 0xa3, 0x90, 0x60, 0xa5, 0xec, 0x6b, 0x2b, 0x85, + 0x33, 0xfa, 0x00, 0xde, 0x64, 0xeb, 0xdd, 0xcc, 0x92, 0x34, 0xa7, 0x68, 0x2a, 0xe5, 0x3c, 0xd4, 0x1f, 0x5f, 0xbd, + 0x3e, 0x0a, 0x44, 0x36, 0x39, 0xec, 0xb4, 0x5a, 0x2d, 0x78, 0x03, 0x29, 0xf2, 0xae, 0x38, 0xbb, 0x7e, 0x26, 0x6e, + 0x28, 0x7a, 0xe2, 0x3d, 0xf5, 0x9e, 0x1c, 0x79, 0x8f, 0x1e, 0x23, 0x4f, 0xb1, 0x73, 0x8a, 0x9e, 0x1c, 0x21, 0x4f, + 0xb3, 0x73, 0x8a, 0x1e, 0x3d, 0x46, 0xbd, 0xe3, 0x89, 0x55, 0xc9, 0xe0, 0x0a, 0xa3, 0xd6, 0x77, 0x72, 0x99, 0x89, + 0x8f, 0xac, 0x7e, 0x70, 0x75, 0x99, 0xc9, 0x8c, 0xeb, 0xd8, 0x47, 0x38, 0xbd, 0xa3, 0x68, 0x1e, 0x2a, 0xa2, 0x70, + 0x0b, 0xc1, 0x2d, 0xa3, 0x4b, 0xd5, 0x14, 0xa0, 0x66, 0x5e, 0xa2, 0xde, 0x31, 0x64, 0xb1, 0x7b, 0x31, 0x45, 0xaf, + 0x3b, 0x4f, 0xbc, 0xf6, 0xe3, 0xab, 0xe6, 0xc3, 0x51, 0xab, 0xd9, 0xf6, 0xda, 0xcd, 0x4e, 0xf0, 0xc4, 0xeb, 0xe8, + 0x7f, 0xbd, 0x96, 0x77, 0xe4, 0xb5, 0x83, 0x27, 0xde, 0x91, 0xd7, 0x09, 0x9e, 0x5c, 0x3d, 0xd4, 0xc9, 0x0c, 0x11, + 0x3a, 0xec, 0x1d, 0xc3, 0x87, 0x34, 0x6f, 0x28, 0xfa, 0x1c, 0xe9, 0xcf, 0xd5, 0xa2, 0xcf, 0xdc, 0xd2, 0xf6, 0xd3, + 0xad, 0xc5, 0x9d, 0x27, 0x5b, 0x8b, 0x8f, 0x1e, 0x6f, 0x2d, 0x7e, 0xf8, 0xa8, 0x5e, 0x7c, 0x38, 0xd1, 0x55, 0xe5, + 0x29, 0xa7, 0x68, 0x16, 0xc9, 0x8c, 0xdf, 0xf8, 0x6d, 0xaf, 0xe5, 0xb5, 0xbc, 0x26, 0xfc, 0xf7, 0xa4, 0x83, 0xcb, + 0x5e, 0x97, 0xd0, 0xab, 0x5c, 0xe5, 0x93, 0xa7, 0x5e, 0xfb, 0xf1, 0xcb, 0xce, 0xe3, 0x11, 0xb4, 0x53, 0x0b, 0x6d, + 0x7b, 0xed, 0xab, 0xa3, 0xa7, 0xa3, 0x96, 0x07, 0x1d, 0xdb, 0xf0, 0x67, 0xfa, 0xa8, 0x33, 0xd2, 0x0f, 0x2d, 0xa8, + 0xff, 0xb6, 0xfd, 0x24, 0x6f, 0x35, 0xdb, 0xf0, 0xe7, 0x97, 0x52, 0x23, 0x06, 0x7d, 0xdc, 0x1d, 0xf7, 0x61, 0xcb, + 0x3b, 0x7a, 0x3a, 0xed, 0x04, 0x9f, 0x5f, 0x3d, 0x09, 0x9e, 0x4e, 0xdb, 0x4f, 0xbe, 0xd5, 0x4f, 0x49, 0xb3, 0x13, + 0x7c, 0x0e, 0x7f, 0xbf, 0x3d, 0x6a, 0x4d, 0x9b, 0xed, 0xe0, 0xe9, 0xd5, 0x51, 0x70, 0x94, 0x34, 0x1f, 0x07, 0x4f, + 0xe1, 0x6f, 0x35, 0xdc, 0x54, 0xcc, 0x18, 0xf2, 0x60, 0xbf, 0xd7, 0xcc, 0x2d, 0x77, 0x8e, 0xce, 0x43, 0xef, 0xd1, + 0xc3, 0x97, 0x4f, 0xaf, 0x9a, 0x0f, 0xa7, 0xed, 0xce, 0x55, 0x73, 0xe7, 0xcf, 0x6f, 0x01, 0xf1, 0x66, 0xe0, 0x88, + 0xc1, 0x75, 0x22, 0x8b, 0x38, 0xf5, 0x36, 0xdc, 0x07, 0x24, 0xdf, 0x65, 0x5e, 0x67, 0x9f, 0x36, 0xaf, 0x53, 0x76, + 0x1f, 0xfb, 0x3a, 0xfb, 0xc3, 0xed, 0xeb, 0x9c, 0xad, 0x39, 0x55, 0x6f, 0xe5, 0x86, 0x19, 0xbd, 0x6e, 0x7b, 0xbd, + 0x93, 0xfe, 0x80, 0xc3, 0x57, 0x97, 0x8a, 0xee, 0x2d, 0xbc, 0x70, 0xdb, 0xf5, 0x36, 0x08, 0x38, 0xc8, 0xb7, 0x52, + 0x9f, 0x64, 0xb1, 0x0b, 0x21, 0xc9, 0xa7, 0x11, 0xf2, 0xed, 0x7d, 0xf0, 0x91, 0xfc, 0xe1, 0xf8, 0x10, 0x2e, 0x3e, + 0x6a, 0x7e, 0x5e, 0x65, 0xcf, 0x2a, 0x7b, 0xf4, 0x4c, 0x3d, 0xfb, 0x70, 0xe3, 0xa4, 0x81, 0x0e, 0x19, 0x14, 0xe5, + 0x48, 0xc7, 0x15, 0x5e, 0xfe, 0x1a, 0x97, 0xb4, 0xbe, 0x5e, 0x46, 0x91, 0x31, 0xfe, 0xe7, 0xf0, 0x65, 0x05, 0xfb, + 0x70, 0xa5, 0x2f, 0x3c, 0x53, 0xd4, 0x09, 0x5a, 0x41, 0xab, 0x74, 0x1c, 0xc0, 0x95, 0x42, 0xba, 0x14, 0x32, 0x82, + 0x8f, 0x7b, 0x26, 0x62, 0xa2, 0x3e, 0x03, 0x0a, 0x2f, 0x5f, 0x57, 0x1f, 0x64, 0xd5, 0xef, 0xbd, 0x0f, 0x11, 0x32, + 0x2f, 0x22, 0x80, 0x2b, 0x6b, 0xdf, 0xc0, 0xb5, 0x3e, 0xeb, 0xb1, 0x9e, 0x81, 0x4d, 0xfd, 0x9a, 0xc5, 0x3c, 0xf2, + 0x91, 0x3f, 0xcf, 0xd8, 0x98, 0x65, 0x79, 0xb3, 0x76, 0xd7, 0x4d, 0x5d, 0x73, 0xc3, 0xc8, 0x7e, 0x46, 0x32, 0x83, + 0x97, 0x09, 0xd3, 0x81, 0xf1, 0x6a, 0x21, 0xa3, 0xe6, 0xa3, 0x82, 0xd8, 0x92, 0x0c, 0x38, 0x7a, 0xa5, 0x1a, 0x20, + 0xad, 0x1b, 0xb4, 0x83, 0xce, 0x23, 0xac, 0x79, 0x09, 0xbc, 0xa4, 0xf5, 0x7b, 0xbf, 0x79, 0xd4, 0xfa, 0x13, 0x76, + 0xba, 0x95, 0x03, 0x0d, 0x8d, 0x53, 0x27, 0xab, 0x3e, 0xbf, 0x5b, 0xbf, 0x88, 0x88, 0x34, 0x45, 0x7c, 0xa6, 0xd7, + 0x0e, 0xaf, 0x7b, 0x35, 0xf1, 0x43, 0x7d, 0x9d, 0x7e, 0xcc, 0x27, 0xbe, 0xfb, 0x71, 0x55, 0xfd, 0x12, 0x58, 0xf5, + 0x4d, 0x66, 0x5c, 0x54, 0x4d, 0x32, 0xbc, 0x54, 0xbe, 0x78, 0x9e, 0x7a, 0xd9, 0x6a, 0xe5, 0x67, 0xe0, 0x88, 0xa5, + 0x0e, 0x4e, 0xe1, 0x19, 0xd7, 0x90, 0x9c, 0x91, 0x12, 0x20, 0x85, 0x60, 0x9a, 0xe9, 0xff, 0xab, 0x62, 0xfb, 0xc3, + 0xb8, 0x57, 0x82, 0x24, 0x4a, 0x27, 0x40, 0x85, 0x51, 0x3a, 0xd9, 0x70, 0xde, 0xe8, 0x70, 0xc2, 0x5a, 0x69, 0x35, + 0x54, 0xe5, 0xa4, 0xc9, 0x9f, 0xdd, 0xbe, 0x37, 0x6f, 0x8b, 0x42, 0xe0, 0x03, 0x55, 0xbe, 0xef, 0xea, 0xcd, 0xb6, + 0x0d, 0xfa, 0x40, 0x7f, 0xae, 0x5c, 0x65, 0xc3, 0x81, 0xf4, 0x83, 0x2b, 0x86, 0x9e, 0xb1, 0x79, 0x28, 0xd2, 0xb2, + 0x2f, 0x66, 0x57, 0x7c, 0x64, 0x44, 0x18, 0xf1, 0xcc, 0x35, 0xeb, 0xa6, 0xda, 0x1a, 0xda, 0x26, 0xda, 0xea, 0x1f, + 0x45, 0x2a, 0xdf, 0x99, 0xa6, 0x02, 0xf5, 0x1e, 0x94, 0xdf, 0x8a, 0xdc, 0xb5, 0x09, 0xf0, 0x0d, 0xf5, 0x41, 0xc6, + 0x92, 0x7f, 0xa6, 0x0f, 0xe0, 0x2b, 0xea, 0x0f, 0x86, 0xf0, 0x01, 0xef, 0x40, 0x89, 0x82, 0x07, 0xd5, 0xc7, 0xd4, + 0x81, 0x0f, 0x36, 0x6e, 0x66, 0x09, 0xb9, 0xaf, 0xf8, 0x36, 0xa2, 0xba, 0xf3, 0xa8, 0x12, 0xd5, 0x9d, 0x47, 0xae, + 0xf4, 0x6c, 0x7b, 0xed, 0x4e, 0xf0, 0xc8, 0x11, 0x00, 0x57, 0x4d, 0xf8, 0xbf, 0x26, 0x02, 0x1e, 0x06, 0x8f, 0x4a, + 0x19, 0xf0, 0xaa, 0xdd, 0x09, 0x8e, 0xb4, 0xb8, 0xe9, 0x04, 0x8f, 0x7e, 0x50, 0x0c, 0x5a, 0x33, 0xe7, 0xfa, 0x81, + 0xd8, 0x12, 0xaa, 0xd1, 0x19, 0x7d, 0x88, 0xf8, 0xe5, 0x17, 0xe9, 0xcc, 0xf9, 0x34, 0x2e, 0xa1, 0xe7, 0x51, 0x06, + 0x9f, 0x05, 0xa9, 0x9f, 0xdd, 0x5a, 0x1d, 0xa9, 0xf1, 0x8b, 0x2d, 0x53, 0xc0, 0x09, 0x47, 0xc4, 0xbd, 0xa7, 0x0c, + 0x97, 0x7c, 0xd5, 0x4b, 0x94, 0xed, 0xbb, 0xe4, 0x76, 0x93, 0xb6, 0x6e, 0x68, 0xdf, 0x57, 0xa7, 0x98, 0x05, 0x57, + 0x2f, 0xac, 0x57, 0x93, 0x7c, 0x19, 0x17, 0xeb, 0xf3, 0x43, 0x62, 0x61, 0x26, 0x9c, 0xab, 0xda, 0xac, 0x4a, 0x87, + 0x8f, 0x39, 0x5c, 0xae, 0x2f, 0x0a, 0x0b, 0x7a, 0xcd, 0x19, 0x58, 0x61, 0x49, 0xf1, 0x0b, 0x96, 0xf7, 0x11, 0x14, + 0xa1, 0x10, 0x29, 0x47, 0x12, 0x2a, 0x3f, 0x8d, 0x52, 0x12, 0x76, 0x55, 0x40, 0xd4, 0x95, 0x16, 0x38, 0xb5, 0x80, + 0x1f, 0x84, 0x0f, 0x0e, 0x76, 0x9e, 0x17, 0xa5, 0x8d, 0xc1, 0x5a, 0xab, 0x4f, 0x2a, 0xb8, 0xac, 0x08, 0xb9, 0x88, + 0x2e, 0xc7, 0x55, 0x28, 0xc4, 0x06, 0x4f, 0x97, 0x2c, 0x92, 0x41, 0x94, 0xea, 0x14, 0x05, 0x87, 0x61, 0x91, 0x36, + 0x3b, 0xc2, 0x85, 0x90, 0x91, 0xf3, 0xcd, 0x54, 0x73, 0xce, 0x85, 0x8c, 0xec, 0xc5, 0xc3, 0x54, 0xd6, 0x32, 0xf3, + 0xa7, 0x9d, 0xde, 0xdb, 0xf7, 0x27, 0x9e, 0x3e, 0x9e, 0xc7, 0x87, 0xd3, 0x4e, 0xef, 0x58, 0x59, 0xe6, 0xfa, 0xda, + 0x12, 0xd5, 0xd7, 0x96, 0x3c, 0x73, 0x85, 0x0d, 0xe2, 0x35, 0xc5, 0xa1, 0x5e, 0x36, 0xf2, 0x58, 0x3a, 0xd2, 0x3e, + 0xc5, 0xd9, 0x22, 0x91, 0x1c, 0x5e, 0x08, 0x7c, 0x08, 0x5d, 0x9b, 0xb0, 0x61, 0x65, 0x96, 0xab, 0xd5, 0x70, 0x64, + 0x6a, 0x3d, 0x90, 0x63, 0x9e, 0x30, 0x9b, 0xd7, 0x6a, 0x86, 0x2a, 0xf3, 0xb0, 0x37, 0x5b, 0xe7, 0x8b, 0xcb, 0x19, + 0x97, 0xc8, 0x66, 0x8b, 0x7f, 0x30, 0x1d, 0x8e, 0xd5, 0x54, 0xbd, 0x8b, 0xc2, 0xb8, 0x48, 0xed, 0xc7, 0x4f, 0xd6, + 0x3e, 0x37, 0xaf, 0x57, 0x6f, 0x24, 0x04, 0xdc, 0x3f, 0x9a, 0x1e, 0xf5, 0x4a, 0xa7, 0xa4, 0x5b, 0x57, 0x1c, 0x1f, + 0x4e, 0x8f, 0x7a, 0x17, 0xe1, 0xdc, 0x8c, 0xf7, 0x4a, 0x6c, 0x7c, 0xba, 0xbe, 0xe4, 0x98, 0x7d, 0x95, 0x68, 0xaf, + 0x6f, 0x74, 0x1a, 0x80, 0x47, 0x22, 0x41, 0xbd, 0x63, 0xa3, 0x0c, 0x78, 0x2a, 0xe8, 0x8a, 0x1e, 0xb5, 0x6c, 0xee, + 0x7e, 0x22, 0x94, 0xb6, 0xa4, 0xbb, 0x38, 0x93, 0xd4, 0xfc, 0xba, 0xd3, 0x76, 0xef, 0x38, 0x32, 0x6a, 0x26, 0x30, + 0x8f, 0x3c, 0x3c, 0x84, 0xce, 0xa0, 0xcb, 0x05, 0x5c, 0x1c, 0x5e, 0xb3, 0xcb, 0x66, 0x34, 0xe7, 0x95, 0x13, 0x15, + 0x94, 0x8e, 0x72, 0x4a, 0x51, 0xcd, 0x04, 0x3f, 0xa3, 0xb5, 0x45, 0x2a, 0x16, 0x5e, 0x18, 0x0f, 0xad, 0xd2, 0xd5, + 0x59, 0x24, 0x91, 0xa7, 0x39, 0xbc, 0xf5, 0xe4, 0x1a, 0xd9, 0x5b, 0xa0, 0xde, 0xbf, 0xfd, 0x8f, 0xff, 0x65, 0x9c, + 0xb3, 0xc7, 0x87, 0xd3, 0xb6, 0x1d, 0x6b, 0x0d, 0xd1, 0xc5, 0x31, 0x5c, 0x77, 0xab, 0xa2, 0x89, 0xec, 0xa6, 0x39, + 0xc9, 0x78, 0xdc, 0x9c, 0x46, 0xc9, 0x18, 0xf5, 0x76, 0x23, 0xc8, 0xbd, 0xe7, 0x62, 0xa0, 0xae, 0x17, 0x01, 0x09, + 0xfe, 0xa6, 0x9b, 0x1a, 0x36, 0xe1, 0x5f, 0x9d, 0x56, 0xf7, 0xde, 0x46, 0x75, 0xa0, 0x6a, 0x77, 0x37, 0x32, 0xf3, + 0x8d, 0x24, 0xc3, 0xd4, 0xb2, 0xda, 0x95, 0x8d, 0x02, 0x79, 0x65, 0x34, 0xe4, 0xff, 0xfe, 0xcf, 0xff, 0xf2, 0xdf, + 0xec, 0x23, 0x04, 0x39, 0xfe, 0xed, 0xbf, 0xff, 0xe7, 0xff, 0xf3, 0xbf, 0xff, 0x2b, 0xa4, 0xf9, 0x9b, 0x40, 0x88, + 0xe2, 0x13, 0x5e, 0x15, 0x05, 0xd1, 0x0c, 0xc3, 0x83, 0x4c, 0xb8, 0x19, 0xcf, 0x25, 0x1f, 0xd5, 0x2f, 0x71, 0x9c, + 0xa9, 0x09, 0xd5, 0x61, 0x33, 0xd0, 0xa9, 0x43, 0x5b, 0x54, 0x34, 0x52, 0x43, 0xb9, 0xa2, 0xc5, 0xe2, 0xf8, 0x10, + 0xf0, 0x7d, 0xbf, 0x7b, 0x6f, 0x41, 0xb9, 0x1d, 0x4b, 0xeb, 0xfa, 0x83, 0x92, 0xa2, 0x2a, 0xf7, 0xc0, 0x29, 0xbf, + 0x84, 0xc7, 0xb0, 0xe3, 0x14, 0xab, 0xdd, 0xab, 0xf5, 0xe9, 0xfe, 0xb4, 0xc8, 0x25, 0x1f, 0x03, 0xca, 0xb5, 0x83, + 0x51, 0xc5, 0x3f, 0x9b, 0xa0, 0xfe, 0x25, 0xb7, 0x85, 0x1a, 0x45, 0xdb, 0x8c, 0x0f, 0x9f, 0xfe, 0xa9, 0xf8, 0xcb, + 0x0c, 0x94, 0x2c, 0xcf, 0x9f, 0x45, 0x37, 0xc6, 0x92, 0x7c, 0xdc, 0x6a, 0xcd, 0x6f, 0xf0, 0xb2, 0x9a, 0x81, 0xec, + 0x9a, 0x4c, 0x39, 0x25, 0xdd, 0x01, 0x55, 0xe0, 0xb4, 0xf4, 0x7f, 0xb6, 0x3c, 0x70, 0xa2, 0x7a, 0xad, 0xa2, 0xf8, + 0xf3, 0x52, 0xb9, 0xe0, 0xf8, 0x2f, 0x10, 0xe0, 0x34, 0xde, 0xca, 0x4b, 0xe1, 0x2e, 0x6e, 0xe9, 0xf4, 0xea, 0xe8, + 0x5e, 0xd3, 0xf6, 0xe6, 0x75, 0x2e, 0x37, 0x40, 0xeb, 0x86, 0x56, 0x1f, 0x42, 0xb0, 0x74, 0xda, 0x26, 0xd3, 0xce, + 0xb2, 0x1c, 0x5e, 0x4a, 0x31, 0x73, 0x23, 0xb2, 0x2c, 0x62, 0x23, 0x36, 0xb6, 0x5e, 0x5e, 0x53, 0xaf, 0xa3, 0xad, + 0xc5, 0xf4, 0x68, 0xcb, 0x5c, 0x06, 0x24, 0x15, 0x89, 0xf5, 0x5a, 0xc5, 0x67, 0x70, 0x02, 0x97, 0xe3, 0x44, 0x44, + 0x32, 0x54, 0x04, 0xdb, 0x75, 0xe3, 0xba, 0x11, 0xb0, 0x19, 0xb1, 0x74, 0xe0, 0xe9, 0xea, 0xa6, 0xe0, 0x6f, 0xad, + 0x5f, 0xba, 0x2b, 0x02, 0xd5, 0xdd, 0x1d, 0x4a, 0xbb, 0x6b, 0xbe, 0x35, 0xe1, 0xd2, 0x97, 0x35, 0x3f, 0x87, 0x91, + 0x31, 0x1d, 0xbc, 0xbd, 0x5e, 0x8b, 0x6a, 0x5d, 0xfb, 0x95, 0xf4, 0x91, 0x02, 0x13, 0xad, 0xb7, 0x52, 0x85, 0xd0, + 0xea, 0x25, 0xfd, 0xb6, 0xb4, 0x82, 0xa2, 0xf9, 0x5c, 0x35, 0xc4, 0xdd, 0xe3, 0x43, 0xad, 0xbc, 0x02, 0xf7, 0x50, + 0xb9, 0x00, 0x3a, 0xf4, 0x6e, 0x1a, 0x99, 0xa3, 0xa0, 0x7f, 0x99, 0xa0, 0x3c, 0x7c, 0x3c, 0xab, 0xf7, 0xff, 0x00, + 0x08, 0x50, 0x84, 0x3d, 0xcd, 0x86, 0x00, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index f2f278b08f..f649a9385e 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -3632,366 +3632,367 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, - 0xdc, 0xb3, 0x2e, 0xb7, 0x6d, 0x5c, 0xfd, 0xbf, 0x4f, 0x01, 0xc3, 0xae, 0x03, 0xd8, 0x00, 0x04, 0x90, 0xa2, 0x28, - 0x93, 0x22, 0x95, 0xc4, 0x76, 0xa6, 0xea, 0x28, 0x71, 0xc6, 0x56, 0x3d, 0x6d, 0x14, 0x8d, 0x08, 0x82, 0x4b, 0x12, - 0x35, 0x08, 0x60, 0x00, 0x50, 0xa2, 0x42, 0xa3, 0xcf, 0xd2, 0x67, 0xe9, 0x93, 0x7d, 0x73, 0xce, 0x5e, 0xb0, 0xb8, - 0x91, 0x54, 0xec, 0xb4, 0xdf, 0xa4, 0xaa, 0x89, 0xc5, 0xee, 0x62, 0xf7, 0xec, 0xee, 0xd9, 0x73, 0x3f, 0xee, 0x82, - 0xc9, 0x5e, 0x0c, 0x8d, 0x1c, 0xf6, 0xb9, 0xcf, 0x9f, 0x89, 0x85, 0x5b, 0x12, 0x08, 0x3e, 0x2b, 0x8b, 0x16, 0x8b, - 0x80, 0x68, 0x2a, 0x4f, 0x1e, 0xa2, 0x1a, 0xe2, 0x33, 0xe7, 0x4f, 0x6c, 0x1e, 0xb1, 0x53, 0xcf, 0xdb, 0x8e, 0x16, - 0x9f, 0x31, 0x11, 0x21, 0xed, 0x28, 0xe5, 0x8a, 0xb2, 0xd9, 0x3b, 0x54, 0x6f, 0xb0, 0x75, 0x29, 0x8e, 0xae, 0x39, - 0x8b, 0xd6, 0xd3, 0x80, 0x98, 0xb8, 0xdd, 0xe1, 0x93, 0xdb, 0xe9, 0x7a, 0x3a, 0x85, 0x2c, 0x2d, 0x4f, 0x6c, 0x03, - 0xe2, 0xce, 0x44, 0x29, 0xf2, 0x83, 0xb9, 0x3e, 0x84, 0x49, 0x59, 0x59, 0x75, 0xf8, 0x60, 0x2b, 0x02, 0xa2, 0x1e, - 0xfa, 0x81, 0x0c, 0x78, 0xbf, 0x86, 0x53, 0x3b, 0x52, 0x3f, 0xc0, 0xee, 0x4b, 0xd5, 0x61, 0xd3, 0xd1, 0x1f, 0x5d, - 0xab, 0x1f, 0x10, 0xc6, 0x98, 0xbd, 0xf8, 0x35, 0xdd, 0xbd, 0xaa, 0xa1, 0x52, 0xa5, 0xf7, 0x1a, 0xf3, 0x18, 0x80, - 0xd0, 0xf7, 0x8d, 0xef, 0x2e, 0xc2, 0x28, 0xcd, 0x7c, 0x4f, 0xbd, 0x19, 0x5e, 0xf8, 0xda, 0xf5, 0x2a, 0xd3, 0xf4, - 0x1b, 0xc3, 0xcb, 0xe4, 0x14, 0x28, 0x1c, 0x61, 0x62, 0x06, 0x94, 0xb6, 0x4a, 0xf2, 0x09, 0xda, 0x59, 0x91, 0xa3, - 0x66, 0xac, 0xe4, 0x65, 0x23, 0xa8, 0x57, 0xc9, 0xa7, 0x82, 0x89, 0xa1, 0x54, 0x6c, 0xa9, 0x0f, 0x29, 0xa7, 0xf2, - 0x7a, 0xbd, 0xc5, 0xab, 0x3c, 0x2b, 0x6e, 0x4b, 0x8c, 0x01, 0xcc, 0x1d, 0x67, 0xe8, 0xf3, 0x13, 0xd9, 0xe8, 0xb3, - 0x74, 0xef, 0x4e, 0xbe, 0x2b, 0xd3, 0x05, 0x70, 0x7f, 0x83, 0xc5, 0x45, 0x18, 0x65, 0x0a, 0x04, 0xb6, 0x81, 0x2f, - 0x4e, 0xaa, 0x46, 0x62, 0xac, 0x57, 0x4d, 0xcf, 0x19, 0x32, 0xf8, 0x1e, 0x2f, 0x3f, 0x8d, 0x85, 0x37, 0x2b, 0x45, - 0xb0, 0xa0, 0xcc, 0x42, 0x08, 0x0b, 0x98, 0x45, 0x97, 0xd1, 0x7d, 0x55, 0x0f, 0xf2, 0x7a, 0xb2, 0xff, 0xee, 0xd5, - 0x38, 0x99, 0xcc, 0xb3, 0xfa, 0x69, 0x2c, 0x31, 0x29, 0x27, 0x74, 0x2a, 0x67, 0x0a, 0x0d, 0x3f, 0x38, 0x0d, 0x93, - 0x81, 0x9d, 0x18, 0xde, 0x05, 0x80, 0x92, 0xd8, 0x35, 0x3d, 0xc9, 0x6f, 0x79, 0xea, 0x64, 0x9e, 0xb8, 0x58, 0xba, - 0x9c, 0x01, 0xbb, 0x86, 0xf1, 0x3a, 0xc3, 0x50, 0xbb, 0x30, 0x00, 0x92, 0xab, 0x0a, 0x86, 0xee, 0x04, 0x2c, 0x5d, - 0x90, 0x89, 0xb9, 0xaa, 0xf8, 0xb3, 0x7a, 0x19, 0x23, 0x7a, 0x01, 0x79, 0x21, 0x7e, 0x47, 0x41, 0x15, 0x3c, 0x26, - 0x6c, 0x1a, 0x9e, 0x51, 0xc4, 0xa9, 0xd7, 0x3c, 0x54, 0xe8, 0x34, 0x60, 0x06, 0x8f, 0xf6, 0x33, 0xd4, 0x82, 0xc6, - 0xc9, 0x42, 0xf8, 0xcd, 0xd2, 0x34, 0x27, 0xcf, 0xb6, 0x61, 0x7e, 0xfe, 0x6c, 0x9b, 0xe6, 0xa3, 0x67, 0x5b, 0x17, - 0x28, 0xb9, 0x5c, 0x85, 0x89, 0x16, 0x8e, 0x3a, 0xc5, 0xf4, 0x60, 0x53, 0xd1, 0x72, 0x05, 0x35, 0xf5, 0x23, 0xa6, - 0x8f, 0x8f, 0x13, 0x7f, 0xe5, 0x26, 0x0f, 0x54, 0x7d, 0x6f, 0xc8, 0x3a, 0x7e, 0x5d, 0x55, 0x28, 0x5e, 0xa7, 0xf3, - 0xa5, 0x28, 0x5e, 0x55, 0xbe, 0x15, 0x65, 0x84, 0x4d, 0x4e, 0xe8, 0x30, 0xe1, 0x5b, 0xb7, 0xea, 0x4b, 0x62, 0xcd, - 0x48, 0xe6, 0xfa, 0x01, 0x6d, 0x32, 0xe4, 0xc9, 0xe9, 0x6b, 0xb3, 0x49, 0xcb, 0xb3, 0x09, 0xcb, 0xdb, 0x05, 0x27, - 0x43, 0x31, 0x3e, 0x1d, 0x37, 0xce, 0x0c, 0x93, 0x56, 0x35, 0x2f, 0x20, 0x7d, 0xf7, 0x5f, 0x85, 0x3e, 0x01, 0xe8, - 0x87, 0x00, 0x7d, 0x12, 0x7a, 0xd1, 0x8c, 0xfc, 0xed, 0xfd, 0x85, 0xc8, 0x92, 0x05, 0x02, 0x9f, 0x09, 0xdb, 0x87, - 0x29, 0x92, 0x0b, 0x09, 0x92, 0x0a, 0x34, 0x9f, 0x95, 0x22, 0x76, 0x4c, 0x92, 0xab, 0xca, 0x39, 0x1d, 0x3b, 0x99, - 0xd1, 0x51, 0x8f, 0x22, 0x6c, 0x95, 0xe4, 0x67, 0x47, 0xb4, 0x36, 0xbd, 0xdc, 0x68, 0x25, 0x00, 0x43, 0x02, 0x33, - 0x2c, 0xa0, 0x00, 0x09, 0x3d, 0x47, 0x4e, 0xc1, 0x3f, 0x58, 0x2b, 0x14, 0xab, 0x3b, 0xe7, 0x65, 0xca, 0x04, 0x5b, - 0xa9, 0xe3, 0x33, 0x4c, 0xd1, 0x05, 0xd7, 0x33, 0x04, 0xf5, 0x38, 0x3b, 0xa2, 0x8f, 0x4a, 0xe5, 0x00, 0x14, 0x9d, - 0x70, 0x4e, 0x6e, 0xc0, 0x3a, 0x78, 0xd4, 0xc9, 0x80, 0x8c, 0xf0, 0x50, 0xea, 0xe6, 0xaa, 0xb2, 0x62, 0x94, 0x10, - 0x8b, 0x1e, 0x04, 0xa1, 0x05, 0x6c, 0x38, 0xaa, 0xaa, 0xb2, 0x72, 0x37, 0x38, 0x73, 0xfe, 0xc6, 0xdd, 0x68, 0x0e, - 0x7b, 0x55, 0x1c, 0xad, 0xb4, 0x7c, 0xb4, 0x3c, 0xb6, 0xb8, 0xe0, 0x37, 0x20, 0x18, 0xe9, 0x25, 0xea, 0x63, 0x1b, - 0x16, 0x77, 0xc9, 0x17, 0x77, 0xd6, 0xb2, 0xb8, 0xb3, 0x1d, 0x8b, 0x1b, 0xb0, 0x85, 0x54, 0x04, 0xe8, 0x12, 0xf4, - 0x05, 0x13, 0xc0, 0x63, 0x74, 0xc5, 0x80, 0x9d, 0x33, 0x84, 0x93, 0x99, 0x06, 0x60, 0x0b, 0xd5, 0x02, 0xab, 0x26, - 0xb8, 0x48, 0x80, 0xa8, 0x4f, 0x5c, 0x9c, 0x3a, 0x3e, 0x6f, 0x48, 0xb9, 0xa9, 0x05, 0xd5, 0xf9, 0xc2, 0x2e, 0xa5, - 0xe9, 0xc4, 0xb5, 0x65, 0xcb, 0x4c, 0x97, 0x3b, 0x66, 0xea, 0x95, 0x8e, 0x2e, 0x9b, 0x36, 0x3d, 0x84, 0xf2, 0xa4, - 0x60, 0x0f, 0x82, 0x7d, 0x28, 0x6e, 0x99, 0xf2, 0x3e, 0x6c, 0x47, 0xa9, 0xd2, 0x8e, 0x8a, 0xdd, 0x34, 0xbd, 0x8f, - 0x12, 0x50, 0xb0, 0x40, 0x37, 0x8f, 0xdb, 0x52, 0x2b, 0x3f, 0x64, 0xb1, 0x5b, 0x5a, 0x37, 0x53, 0xf1, 0x5e, 0xde, - 0x52, 0x9d, 0x5e, 0x8f, 0xd6, 0x88, 0xdd, 0x2c, 0x23, 0x09, 0x02, 0xdd, 0x85, 0x20, 0xdf, 0xff, 0x4f, 0xb6, 0x59, - 0x03, 0x0e, 0x09, 0xf4, 0x02, 0xab, 0x23, 0x86, 0x8e, 0x81, 0x94, 0x4a, 0xf8, 0xbd, 0x2b, 0xc5, 0x81, 0x4b, 0x04, - 0xe0, 0x7f, 0xc2, 0xe3, 0xaa, 0x25, 0x92, 0xa7, 0x92, 0x73, 0xa2, 0x5b, 0xb1, 0x3b, 0xfb, 0x00, 0x7a, 0x3c, 0xad, - 0x63, 0x80, 0x4d, 0xae, 0x1c, 0xf5, 0x2d, 0xa1, 0xb4, 0x9d, 0x57, 0x20, 0x49, 0xc4, 0x92, 0xcc, 0xe2, 0x09, 0x9c, - 0x25, 0x5d, 0x73, 0x7e, 0xb3, 0xed, 0xe4, 0x47, 0x0b, 0x5f, 0xaf, 0x61, 0x4d, 0x40, 0x6d, 0xc1, 0x68, 0x2c, 0x58, - 0xac, 0xc0, 0x70, 0x4e, 0x74, 0x10, 0xf4, 0x5e, 0x43, 0xfa, 0x52, 0x9b, 0xf3, 0xaf, 0x93, 0x04, 0x2e, 0xa9, 0x6b, - 0xfb, 0x26, 0x7f, 0xbe, 0xc0, 0x5f, 0xce, 0x4d, 0xfe, 0x7c, 0x8a, 0xbf, 0x3a, 0x37, 0x98, 0xa8, 0xae, 0x81, 0x6f, - 0x97, 0xe6, 0xac, 0x8e, 0x4b, 0xfb, 0x89, 0x9a, 0x9b, 0x3d, 0x62, 0xdb, 0xb0, 0x05, 0x7e, 0xfa, 0x6c, 0x9b, 0x82, - 0x83, 0xa5, 0x3c, 0x87, 0xd0, 0x4a, 0xf4, 0xbc, 0xb1, 0x7c, 0xd1, 0x52, 0x3e, 0xd5, 0xff, 0xcb, 0xf7, 0x3c, 0xee, - 0x92, 0xa8, 0xb8, 0x53, 0xca, 0x52, 0x87, 0xdb, 0xa9, 0x1f, 0xba, 0xc9, 0xc3, 0x2d, 0xe5, 0x26, 0x34, 0x4e, 0xaa, - 0x0b, 0x69, 0x0a, 0xa5, 0x26, 0xcb, 0xda, 0xad, 0x4c, 0x92, 0xe7, 0x3e, 0xb0, 0x8b, 0x7e, 0xf4, 0xf7, 0x44, 0xa2, - 0xd2, 0x4a, 0xfc, 0x26, 0x5b, 0x90, 0xd2, 0x87, 0x6e, 0x9f, 0x6d, 0x35, 0x52, 0xef, 0xa6, 0x32, 0xdb, 0x0a, 0x19, - 0x08, 0xcb, 0x83, 0xbc, 0xeb, 0x6a, 0xe6, 0x0f, 0x50, 0x7d, 0x35, 0x8d, 0x36, 0xe6, 0xb3, 0x6d, 0x76, 0xae, 0xae, - 0xdc, 0xe4, 0x13, 0x99, 0x99, 0x9e, 0x9f, 0x78, 0x01, 0x51, 0x07, 0xea, 0x34, 0x70, 0xc3, 0x4f, 0xec, 0xd1, 0x8c, - 0xd6, 0x19, 0x2a, 0xa4, 0xf7, 0xb2, 0xba, 0x1c, 0x26, 0x54, 0x42, 0x87, 0xb4, 0x69, 0x03, 0x14, 0x94, 0xd7, 0x42, - 0xbe, 0x55, 0xd0, 0x85, 0x45, 0x2d, 0x03, 0xec, 0x29, 0x41, 0x47, 0x0e, 0x0e, 0xaa, 0x86, 0x8a, 0xeb, 0xa5, 0x1a, - 0xf2, 0x54, 0xa9, 0x6c, 0x52, 0x64, 0x58, 0xbc, 0xc5, 0x1e, 0x7e, 0xff, 0xe7, 0x68, 0xee, 0xeb, 0xc3, 0x3f, 0xc7, - 0x68, 0xbc, 0xf6, 0x0f, 0xca, 0x8d, 0xdd, 0x34, 0x5d, 0xaf, 0xc8, 0x8c, 0xea, 0xe2, 0xce, 0x8b, 0xa1, 0x94, 0x69, - 0x79, 0x79, 0x38, 0xbf, 0xae, 0x3b, 0xfd, 0xe3, 0xd7, 0x60, 0x23, 0x00, 0x34, 0x5d, 0x34, 0x9f, 0xab, 0x05, 0x57, - 0xbd, 0xa7, 0x99, 0x73, 0xfc, 0xeb, 0xfa, 0x87, 0xb7, 0xf6, 0x0f, 0xa2, 0x71, 0xa8, 0xea, 0xf9, 0x84, 0x2b, 0x3c, - 0x19, 0x69, 0x2a, 0x8d, 0x97, 0xcf, 0x68, 0xee, 0x86, 0xed, 0xd3, 0xb9, 0x2e, 0xed, 0xb2, 0x98, 0x90, 0x19, 0xd8, - 0xc2, 0x1a, 0xb5, 0xd2, 0xdb, 0x80, 0xdc, 0x11, 0xa1, 0x4c, 0xad, 0x7f, 0xac, 0xa1, 0x05, 0x46, 0x7b, 0x63, 0x4a, - 0x5a, 0x46, 0x58, 0x49, 0x53, 0x9a, 0xe0, 0x1c, 0xd8, 0xcc, 0xe5, 0x5d, 0x5e, 0xd9, 0xd5, 0x13, 0x43, 0x95, 0x06, - 0xd0, 0x3a, 0xb2, 0xf3, 0x96, 0xf2, 0x01, 0xa6, 0x7a, 0x6e, 0x1e, 0x9b, 0xe1, 0xe8, 0x03, 0x88, 0x8e, 0xcd, 0xe0, - 0x14, 0xc0, 0xe6, 0xd7, 0x0a, 0x01, 0x44, 0x1b, 0xc4, 0x9a, 0xc4, 0x52, 0x2a, 0x95, 0x77, 0x70, 0xfb, 0x42, 0x34, - 0xb4, 0xe5, 0x92, 0x9f, 0xc6, 0xb5, 0x51, 0xca, 0x33, 0x9f, 0x62, 0x0a, 0xd5, 0x90, 0xa4, 0x69, 0x2b, 0xc0, 0xc4, - 0xa2, 0x1b, 0x6a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0xb0, 0x0d, 0xb8, 0x95, 0x71, 0x82, 0xd5, 0x6f, 0x21, 0x86, - 0xbf, 0x5d, 0x31, 0x0b, 0x91, 0x64, 0x31, 0x55, 0x99, 0xf6, 0xbe, 0xed, 0xfd, 0xbd, 0xca, 0x06, 0x55, 0xba, 0x29, - 0x1b, 0x87, 0xa6, 0x95, 0xb0, 0x5f, 0x4d, 0x40, 0x83, 0x1d, 0xf0, 0x31, 0x55, 0x50, 0x1c, 0x99, 0xcf, 0x89, 0x97, - 0xa5, 0x3a, 0x17, 0xd7, 0x88, 0x78, 0xad, 0xe0, 0xa7, 0xf3, 0x64, 0xa4, 0xfe, 0x04, 0x5e, 0xeb, 0x3c, 0xac, 0x11, - 0x1b, 0x10, 0x67, 0x5b, 0x9a, 0xc1, 0x44, 0x7b, 0x2c, 0x83, 0x88, 0x7d, 0x05, 0xd2, 0x71, 0x37, 0x94, 0xe3, 0xd0, - 0xd8, 0x15, 0x50, 0xec, 0x8b, 0x48, 0xd8, 0x91, 0xec, 0x46, 0x40, 0xbb, 0x8e, 0xef, 0xd6, 0xf9, 0xa1, 0xe7, 0xd8, - 0xb9, 0x6a, 0x80, 0xb7, 0xd4, 0xa7, 0x43, 0x0f, 0x3d, 0xb6, 0xea, 0x42, 0xab, 0x75, 0xf8, 0x98, 0x76, 0x1d, 0xe7, - 0x95, 0xa3, 0x1a, 0xd4, 0x48, 0x4d, 0xc2, 0x6d, 0x5e, 0x74, 0x47, 0x92, 0x2f, 0x9e, 0x4a, 0xb9, 0xf3, 0xc3, 0xc6, - 0x73, 0xe2, 0xd8, 0x80, 0x84, 0xb3, 0x28, 0x7e, 0xc4, 0x14, 0xba, 0xaa, 0xa1, 0x7a, 0x41, 0x94, 0x12, 0x79, 0x0e, - 0x54, 0xec, 0xf0, 0x85, 0x93, 0xf8, 0xf9, 0xfd, 0xdb, 0x0f, 0x1f, 0x54, 0x03, 0x73, 0x6f, 0xa6, 0x72, 0xef, 0x6c, - 0x43, 0xed, 0xc1, 0xfe, 0x8d, 0xfb, 0x8e, 0xde, 0x30, 0x94, 0xaf, 0x2c, 0xef, 0x39, 0x5a, 0x56, 0xdb, 0x72, 0xec, - 0xe6, 0x61, 0x5f, 0xa6, 0xcc, 0xe0, 0x41, 0xf3, 0x6a, 0xc0, 0x0d, 0xbb, 0xaf, 0xb7, 0x52, 0xc9, 0xca, 0x0f, 0x6f, - 0x1b, 0x4a, 0xdd, 0x4d, 0x43, 0x29, 0x70, 0x53, 0x35, 0x5c, 0xb5, 0x8e, 0x56, 0xd2, 0xed, 0x0c, 0xa9, 0x93, 0xf7, - 0x81, 0x4b, 0x62, 0x69, 0xbe, 0x60, 0xd0, 0x2c, 0x76, 0x7a, 0x75, 0xd4, 0x0d, 0xc5, 0x8c, 0x0f, 0x11, 0xb0, 0xf5, - 0x02, 0x30, 0xb1, 0x23, 0xb2, 0x1e, 0xac, 0x4c, 0xb9, 0x09, 0x03, 0x59, 0xa9, 0x13, 0x4a, 0x61, 0xde, 0x66, 0x64, - 0x15, 0x93, 0xc4, 0xcd, 0xd6, 0x09, 0xb9, 0x0d, 0xa2, 0xfb, 0x27, 0x85, 0x01, 0xfb, 0x9e, 0xca, 0x4b, 0x7f, 0xb1, - 0x14, 0xb5, 0xcf, 0x35, 0x32, 0x12, 0x0b, 0xb8, 0xf3, 0x03, 0xf9, 0x7f, 0xfe, 0x6d, 0x59, 0xff, 0xf9, 0xf7, 0xde, - 0xaa, 0xd0, 0x7d, 0x3e, 0x31, 0xb2, 0xd1, 0x01, 0xfb, 0xa2, 0xf9, 0x4b, 0x65, 0x98, 0x37, 0xd7, 0xa9, 0x2d, 0x02, - 0xbc, 0xaf, 0x2d, 0x41, 0xad, 0xb0, 0xbc, 0x6f, 0x1e, 0x35, 0x30, 0x98, 0xd7, 0xde, 0x91, 0x41, 0xa5, 0x2f, 0x1a, - 0xda, 0x44, 0x1f, 0x1c, 0xb4, 0x22, 0xbf, 0x1f, 0xc2, 0xfb, 0xe6, 0xf0, 0x85, 0xc3, 0x67, 0xa2, 0xc1, 0xd7, 0x93, - 0x89, 0xc8, 0xe6, 0x26, 0x37, 0x05, 0xa3, 0xfa, 0xf3, 0x5a, 0x09, 0xbb, 0x3c, 0x07, 0xb6, 0x4e, 0xbd, 0xdd, 0x47, - 0xaf, 0x27, 0x68, 0xfe, 0x75, 0x36, 0x4d, 0x0a, 0x62, 0xa5, 0x15, 0xb5, 0x51, 0xf3, 0xed, 0x5a, 0xa7, 0x35, 0xbc, - 0x06, 0xa5, 0x98, 0xe2, 0x2b, 0x9f, 0xe8, 0xc6, 0xeb, 0x09, 0x93, 0xed, 0x30, 0x8b, 0xd3, 0x41, 0x75, 0x6b, 0x33, - 0xc9, 0x68, 0x09, 0xe8, 0x86, 0x42, 0x35, 0x2e, 0x58, 0x99, 0x14, 0xa2, 0x34, 0x14, 0xa9, 0x03, 0x53, 0x3f, 0xc9, - 0x31, 0xc3, 0xc8, 0xbb, 0x36, 0xab, 0xac, 0x9f, 0xf7, 0x5b, 0x65, 0x5d, 0x1d, 0x64, 0x95, 0xf5, 0xf3, 0x57, 0xb7, - 0xca, 0x7a, 0x27, 0x5b, 0x65, 0xc1, 0x22, 0xbe, 0x25, 0x07, 0x99, 0x4a, 0x71, 0x3b, 0x89, 0xe8, 0x3e, 0x1d, 0x39, - 0x8c, 0xa4, 0x4d, 0xbd, 0x25, 0x01, 0x36, 0x9d, 0xad, 0x4a, 0x10, 0x2d, 0xc0, 0x6c, 0xea, 0x8f, 0x37, 0x70, 0x0a, - 0xa2, 0x85, 0x6c, 0xde, 0x14, 0xb2, 0x18, 0xab, 0x45, 0xdc, 0x24, 0x6a, 0x52, 0x64, 0x1b, 0x3c, 0xca, 0x92, 0x79, - 0xac, 0x4b, 0x79, 0xa4, 0x85, 0xbd, 0x58, 0x87, 0x1b, 0x1d, 0x0d, 0xd0, 0x5e, 0x49, 0x34, 0xec, 0xbc, 0xe4, 0xd1, - 0x24, 0xe4, 0x1e, 0x84, 0x5d, 0x2e, 0x8d, 0xcc, 0xb0, 0x55, 0x7f, 0xdd, 0x38, 0xdf, 0x5f, 0x3b, 0xc3, 0xae, 0x03, - 0xee, 0xd0, 0xc0, 0xe4, 0x61, 0x81, 0x3d, 0xec, 0x76, 0xa1, 0xe0, 0x5e, 0x2a, 0xe8, 0x40, 0x81, 0x2f, 0x15, 0xf4, - 0xa0, 0xc0, 0x93, 0x0a, 0x4e, 0xa0, 0x60, 0x26, 0x15, 0xf4, 0xa1, 0xe0, 0x4e, 0xcd, 0xaf, 0x43, 0x31, 0xdc, 0xbe, - 0x7e, 0x63, 0x50, 0xa6, 0x82, 0x97, 0xf5, 0x0d, 0x07, 0xec, 0x94, 0xdc, 0xc5, 0x20, 0x32, 0xa8, 0x80, 0x6f, 0x90, - 0x18, 0xf7, 0x4b, 0x42, 0x43, 0x33, 0xbf, 0xc1, 0x3b, 0xc7, 0xca, 0x22, 0xb0, 0x54, 0xe6, 0x21, 0x0f, 0x38, 0x1c, - 0x14, 0x55, 0x07, 0x99, 0xcd, 0x50, 0xac, 0x1c, 0x0f, 0x1b, 0x21, 0xad, 0x65, 0xf1, 0x8e, 0x7e, 0xce, 0x14, 0x5b, - 0xa0, 0xb0, 0xf1, 0xd0, 0x64, 0xc1, 0xe0, 0xd7, 0xd0, 0xf4, 0xbf, 0x21, 0xd3, 0xf5, 0x42, 0xb9, 0x8c, 0x16, 0x7b, - 0x95, 0xf6, 0xf2, 0x2b, 0x18, 0xa5, 0x4a, 0x35, 0x20, 0x26, 0xdf, 0x96, 0xec, 0x5b, 0xf4, 0x31, 0x2f, 0xd7, 0xcf, - 0x60, 0x6c, 0x4a, 0x46, 0x4d, 0x46, 0xe0, 0x3b, 0x00, 0x23, 0x49, 0x6b, 0x7e, 0x09, 0x70, 0x96, 0x9e, 0xaf, 0x5c, - 0x69, 0x3c, 0xe3, 0x1f, 0x49, 0x9a, 0xba, 0x0b, 0x5e, 0xbf, 0x3e, 0x4e, 0x30, 0x93, 0x11, 0xfc, 0x17, 0x02, 0x10, - 0x84, 0x69, 0x7e, 0xcd, 0x1a, 0x22, 0x89, 0xee, 0x15, 0xb0, 0xb7, 0x81, 0x0d, 0x55, 0x58, 0x06, 0xf8, 0x16, 0x2c, - 0x61, 0x59, 0x87, 0x0f, 0x87, 0xff, 0x8e, 0x04, 0xd5, 0xc2, 0xcc, 0x5d, 0x54, 0x8b, 0xe8, 0x3e, 0xc8, 0xe5, 0xb1, - 0x09, 0x15, 0x7a, 0xa9, 0xf0, 0x4b, 0x74, 0xc2, 0x41, 0xb4, 0xf8, 0x43, 0x15, 0xc2, 0x3b, 0x14, 0xf9, 0x1f, 0x42, - 0xc3, 0xcf, 0x26, 0x16, 0xc2, 0x58, 0xb1, 0x00, 0x84, 0x83, 0x30, 0x5b, 0x9a, 0xe8, 0xcc, 0xa5, 0x75, 0x42, 0xdd, - 0xb0, 0x70, 0x6d, 0xb7, 0x55, 0x17, 0xd6, 0x41, 0xb2, 0x98, 0xba, 0x9a, 0xd3, 0xe9, 0x1b, 0xfc, 0xcf, 0xb2, 0x7b, - 0x7a, 0x8e, 0x3d, 0x28, 0x33, 0xff, 0x6e, 0x3b, 0x8f, 0xc2, 0xcc, 0x9c, 0xbb, 0x2b, 0x3f, 0x78, 0x18, 0xac, 0xa2, - 0x30, 0x4a, 0x63, 0xd7, 0x23, 0xc3, 0x82, 0xa1, 0x1e, 0x62, 0x70, 0x04, 0xe6, 0x9f, 0xe7, 0x58, 0x9d, 0x84, 0xac, - 0x68, 0x6b, 0x11, 0xfb, 0x60, 0x1e, 0x90, 0x4d, 0xce, 0x3e, 0x5f, 0xaa, 0x4c, 0xab, 0xe2, 0x96, 0xa3, 0x2d, 0x80, - 0x22, 0x65, 0x81, 0x15, 0x20, 0x9c, 0xd0, 0x30, 0x76, 0x67, 0x18, 0x0b, 0xd0, 0xea, 0xf4, 0x12, 0xb2, 0x52, 0xac, - 0x5e, 0x6b, 0xe7, 0x49, 0x74, 0x3f, 0x86, 0xd1, 0x62, 0x63, 0x33, 0x25, 0xc1, 0x1c, 0xdf, 0x98, 0xe8, 0xcb, 0xc1, - 0xfb, 0x31, 0x91, 0x11, 0x87, 0xde, 0xc8, 0x6a, 0x08, 0xaf, 0x07, 0x1d, 0xc5, 0x1e, 0xae, 0xfc, 0xd0, 0xa4, 0xd3, - 0xe9, 0xdb, 0xb1, 0xd4, 0x97, 0x0c, 0x3f, 0x7d, 0x8b, 0xd5, 0x1d, 0xc5, 0x1e, 0x02, 0xb3, 0x36, 0x0f, 0xa2, 0xfb, - 0xc1, 0xd2, 0x9f, 0xcd, 0x48, 0x38, 0xc4, 0x31, 0x8b, 0x42, 0x12, 0x04, 0x7e, 0x9c, 0xfa, 0xe9, 0x70, 0xe5, 0x6e, - 0x58, 0xaf, 0xc7, 0x6d, 0xbd, 0x76, 0x59, 0xaf, 0xdd, 0x83, 0x7b, 0x95, 0xba, 0x01, 0xbf, 0x11, 0xda, 0x0f, 0x1b, - 0x5a, 0x4f, 0xb1, 0x2b, 0xf3, 0x3c, 0xb8, 0xd7, 0x38, 0x21, 0xdb, 0x95, 0x9b, 0x2c, 0xfc, 0x70, 0x60, 0xe7, 0xd6, - 0xdd, 0x96, 0x6e, 0x8c, 0xa7, 0xa7, 0xa7, 0xa7, 0xb9, 0x35, 0xe3, 0x4f, 0xf6, 0x6c, 0x96, 0x5b, 0x1e, 0x7f, 0x9a, - 0xcf, 0x6d, 0x7b, 0x3e, 0xcf, 0x2d, 0x9f, 0x17, 0x74, 0x3b, 0xde, 0xac, 0xdb, 0xc9, 0xad, 0x7b, 0xa9, 0x46, 0x6e, - 0x11, 0xf6, 0x94, 0x90, 0xd9, 0x10, 0x37, 0x12, 0x35, 0xe4, 0x1c, 0xf4, 0x6d, 0x3b, 0x47, 0x0c, 0x70, 0x5d, 0xc2, - 0x4d, 0x28, 0xeb, 0xb9, 0xd9, 0x1e, 0x5c, 0x53, 0x29, 0x3e, 0xe7, 0x79, 0x8d, 0xf5, 0x66, 0x6e, 0xf2, 0xe9, 0x46, - 0x91, 0x66, 0xe1, 0xba, 0xb4, 0xda, 0x96, 0x83, 0xc1, 0xdc, 0x0c, 0x20, 0x48, 0xd6, 0x70, 0x1a, 0x25, 0x70, 0x66, - 0x13, 0x77, 0xe6, 0xaf, 0xd3, 0x81, 0xd3, 0x89, 0x37, 0xbc, 0x88, 0xed, 0xf5, 0xa2, 0x00, 0xcf, 0xde, 0x20, 0x8d, - 0x02, 0x7f, 0xc6, 0x8b, 0xda, 0xce, 0x92, 0xd3, 0xd1, 0x87, 0xe8, 0x22, 0xee, 0x63, 0xa0, 0x03, 0x37, 0x08, 0x14, - 0xab, 0x9b, 0x2a, 0xc4, 0x4d, 0x51, 0xc4, 0xab, 0xd8, 0x29, 0x85, 0x0b, 0xba, 0x83, 0x3b, 0xc7, 0xf1, 0x46, 0xec, - 0x79, 0xe7, 0x24, 0xde, 0xe4, 0xdf, 0xae, 0xc8, 0xcc, 0x77, 0x15, 0xad, 0xd8, 0x4d, 0x8e, 0x0d, 0x62, 0x60, 0x7d, - 0xdb, 0xb2, 0x4d, 0xf9, 0xb1, 0x80, 0x60, 0x82, 0x4f, 0xfc, 0x55, 0x1c, 0x25, 0x99, 0x1b, 0x66, 0x79, 0x3e, 0xb9, - 0xc9, 0xf3, 0xe1, 0x95, 0xaf, 0x5d, 0xff, 0x43, 0xa3, 0xf7, 0x34, 0x55, 0x9b, 0xe4, 0xfa, 0x8d, 0xf1, 0x96, 0xc8, - 0x56, 0x1a, 0x70, 0x8d, 0xa1, 0x85, 0x86, 0x5c, 0x99, 0xde, 0x92, 0xf5, 0xca, 0x14, 0xc8, 0xa2, 0x3a, 0xb5, 0xfa, - 0x28, 0x57, 0xc1, 0x1b, 0x08, 0x2a, 0xbc, 0x25, 0xa3, 0x2b, 0xc9, 0xe2, 0x03, 0x88, 0x15, 0xac, 0x4c, 0x2d, 0xf9, - 0x9f, 0xb5, 0xd1, 0x8c, 0xdf, 0xed, 0xa7, 0x19, 0x7f, 0xc9, 0x0e, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, 0xb3, - 0xba, 0x25, 0xff, 0x45, 0x34, 0x52, 0x85, 0x90, 0x1f, 0xae, 0xa6, 0x84, 0xc6, 0xc8, 0xb9, 0xf8, 0xdd, 0x86, 0xf7, - 0xbc, 0x37, 0x9a, 0xf5, 0x8d, 0xde, 0xdc, 0x20, 0x8f, 0x7d, 0x17, 0x8e, 0xfe, 0x9e, 0xc8, 0xcf, 0xf3, 0xf9, 0xe8, - 0x4d, 0x24, 0x15, 0x88, 0x27, 0x66, 0xff, 0x50, 0x8a, 0x67, 0x40, 0xdf, 0x70, 0xbb, 0x47, 0xcc, 0xf8, 0x00, 0xee, - 0xd0, 0xd4, 0xce, 0x77, 0x26, 0xec, 0xbd, 0x86, 0xe5, 0x21, 0x68, 0xc2, 0xc8, 0x92, 0x3b, 0xbd, 0xd4, 0x44, 0x89, - 0x0b, 0x92, 0x31, 0x2f, 0xd5, 0xef, 0x1f, 0x2e, 0x66, 0xda, 0x45, 0xa4, 0xe7, 0x7e, 0xfa, 0xae, 0xea, 0x72, 0xc2, - 0xd4, 0x2f, 0x23, 0x79, 0x3a, 0x39, 0xb3, 0xd9, 0x92, 0x53, 0x3a, 0xc3, 0x6b, 0xda, 0xfc, 0xbc, 0x34, 0xd3, 0x81, - 0xdc, 0x90, 0xa5, 0x96, 0xaa, 0x5d, 0xc6, 0xcc, 0xde, 0x7f, 0xcb, 0x28, 0x40, 0xcc, 0x96, 0x85, 0x9e, 0xba, 0x33, - 0xda, 0xdc, 0x9f, 0xe5, 0xb9, 0x3e, 0xe4, 0x80, 0x90, 0x2e, 0x5a, 0xb2, 0x8f, 0x88, 0x4b, 0xef, 0x85, 0x59, 0x01, - 0x53, 0xd2, 0x51, 0x0d, 0xdc, 0x05, 0xe8, 0xb4, 0x99, 0xbe, 0x8e, 0xc1, 0x4c, 0x55, 0x28, 0xf8, 0xa8, 0xad, 0x83, - 0x34, 0x21, 0x50, 0xc2, 0x0a, 0xf8, 0xf3, 0x57, 0xbc, 0xa0, 0x6e, 0x35, 0x49, 0x81, 0x83, 0x4a, 0x79, 0xf0, 0xab, - 0xe7, 0x72, 0x6d, 0x8a, 0x76, 0x58, 0x1d, 0x7c, 0xc8, 0x55, 0x41, 0xfb, 0xe1, 0xf6, 0x1b, 0x9f, 0x1d, 0x41, 0x83, - 0x71, 0x45, 0x77, 0xbf, 0xc7, 0x26, 0x10, 0x48, 0x89, 0xf4, 0xde, 0xb0, 0xd2, 0x7b, 0xe5, 0xc5, 0x96, 0xc7, 0xa4, - 0xc8, 0xdc, 0xd8, 0x04, 0x16, 0x1f, 0x71, 0x2f, 0xc3, 0x78, 0x52, 0xf8, 0x8b, 0xe1, 0x3a, 0x05, 0xdc, 0x88, 0x8c, - 0x2a, 0xe2, 0x9f, 0xa1, 0xb7, 0x4e, 0xd2, 0x28, 0x19, 0xc4, 0x91, 0x1f, 0x66, 0x24, 0xc9, 0x11, 0x54, 0xd7, 0x08, - 0x1f, 0x0e, 0x9e, 0x9b, 0x6d, 0x14, 0xbb, 0x9e, 0x9f, 0x3d, 0x0c, 0x6c, 0x46, 0x52, 0xd8, 0x43, 0x46, 0x1d, 0xd8, - 0x8d, 0xf5, 0x07, 0x0c, 0x9a, 0x2f, 0x91, 0xf0, 0x4b, 0xea, 0xe4, 0x8c, 0xbc, 0xcd, 0x87, 0xd2, 0x5b, 0x1a, 0x95, - 0x03, 0xc8, 0x0f, 0x37, 0x31, 0x17, 0x80, 0xe5, 0x61, 0xa9, 0xed, 0x19, 0x59, 0x18, 0x88, 0xb5, 0x41, 0x2e, 0xcf, - 0xff, 0xac, 0x9e, 0xae, 0xd8, 0xcd, 0xc5, 0x40, 0xf1, 0xe8, 0x87, 0x8c, 0x6c, 0xe0, 0x42, 0x0e, 0x2b, 0xe3, 0x90, - 0x9a, 0x53, 0x32, 0x8f, 0x12, 0x42, 0x23, 0xb8, 0x3a, 0xa7, 0xf1, 0xe6, 0xf0, 0xee, 0x77, 0x4f, 0xbf, 0xb9, 0x9f, - 0x30, 0xca, 0x34, 0xde, 0x99, 0xbe, 0xa7, 0xb7, 0xfa, 0x7d, 0x06, 0xa4, 0x21, 0x85, 0xbc, 0x47, 0x83, 0x65, 0x0d, - 0x54, 0x75, 0xd8, 0x18, 0x28, 0x2b, 0x8e, 0xd8, 0x9d, 0x97, 0x90, 0xc0, 0xcd, 0xfc, 0x3b, 0x4e, 0x33, 0x76, 0x4f, - 0xe2, 0x0d, 0x5f, 0x63, 0xbc, 0xf0, 0x1e, 0xb1, 0x48, 0x95, 0xa1, 0xf0, 0x45, 0xaa, 0x16, 0xe3, 0x22, 0x0d, 0x6b, - 0xb3, 0xe1, 0xb1, 0x23, 0x2a, 0x37, 0x7d, 0x2f, 0xde, 0xc8, 0x57, 0x74, 0xd1, 0x4c, 0xdc, 0xd4, 0xd5, 0xa0, 0x5f, - 0x2b, 0x7f, 0x36, 0x0b, 0x48, 0x5e, 0x5a, 0xe8, 0xf2, 0x5a, 0x4a, 0xc0, 0x11, 0x70, 0x70, 0xa7, 0x69, 0x14, 0xac, - 0x33, 0xd2, 0x0c, 0x2e, 0x0a, 0x9c, 0x8e, 0x5d, 0x00, 0x07, 0x7f, 0x97, 0xc7, 0xda, 0x03, 0x72, 0x1b, 0xb6, 0x89, - 0x3d, 0x84, 0x18, 0xbf, 0x66, 0xb7, 0x3c, 0x74, 0x78, 0x25, 0x06, 0x6d, 0x34, 0x4c, 0xc4, 0x80, 0x6b, 0x89, 0x62, - 0x6f, 0xc5, 0x72, 0x58, 0x99, 0x88, 0x73, 0x2a, 0x8a, 0xf2, 0xf2, 0x64, 0xfe, 0x98, 0x33, 0xf6, 0xaa, 0xf9, 0x8c, - 0xbd, 0xe2, 0x67, 0x6c, 0xf7, 0xce, 0x7c, 0x3a, 0x77, 0xe0, 0xbf, 0x61, 0x31, 0xa1, 0x81, 0xad, 0x74, 0xe3, 0x8d, - 0xe2, 0xc4, 0x1b, 0xc5, 0xec, 0xc4, 0x1b, 0x05, 0xbb, 0x46, 0x93, 0x0c, 0xc3, 0xea, 0xe8, 0x86, 0xad, 0x40, 0x21, - 0xfc, 0xd9, 0xa5, 0x57, 0xce, 0x31, 0xbc, 0x83, 0x56, 0xbd, 0xfa, 0xbb, 0xce, 0xee, 0xa3, 0x4e, 0xcf, 0x12, 0x47, - 0xda, 0xba, 0x95, 0xb9, 0xd3, 0x29, 0x99, 0x0d, 0xe6, 0x91, 0xb7, 0x4e, 0xff, 0xc5, 0xc6, 0xcf, 0x80, 0xb8, 0x13, - 0x11, 0x54, 0xfa, 0xe1, 0x4d, 0x41, 0x51, 0x72, 0x47, 0x78, 0x0f, 0x5b, 0xb1, 0x4e, 0x03, 0x1a, 0x90, 0xb8, 0x63, - 0x1d, 0x37, 0x6c, 0xf2, 0x66, 0x40, 0xff, 0x61, 0xab, 0xd4, 0x8e, 0x62, 0xbe, 0x00, 0x2c, 0x3b, 0xc1, 0xf1, 0x78, - 0x68, 0xb0, 0xd5, 0xb4, 0x4f, 0x9b, 0x87, 0x7b, 0xcd, 0xbf, 0x74, 0xc3, 0x2f, 0x15, 0x76, 0x6f, 0x31, 0x57, 0x90, - 0xdd, 0xbd, 0xb6, 0xed, 0x91, 0x5a, 0xaf, 0x3b, 0x2e, 0x84, 0xa2, 0xee, 0x81, 0x58, 0xfe, 0xe9, 0xab, 0x63, 0xf8, - 0x8f, 0x52, 0xf5, 0xbf, 0x64, 0x4d, 0x84, 0xfa, 0x45, 0xd9, 0xf6, 0x9a, 0x92, 0x4a, 0x48, 0x88, 0x1f, 0x5e, 0x7f, - 0x3e, 0x7f, 0x5c, 0x83, 0x83, 0x6b, 0x53, 0x6b, 0xa6, 0x6a, 0xed, 0xef, 0xa3, 0x08, 0x92, 0x65, 0xd6, 0xab, 0x73, - 0xf0, 0x50, 0xf3, 0xf2, 0x6c, 0x04, 0x8d, 0x38, 0x1f, 0x41, 0xb5, 0xf8, 0x2a, 0xb6, 0xa1, 0xac, 0xc4, 0xdb, 0x36, - 0x56, 0xe2, 0xcd, 0x7e, 0x56, 0xe2, 0xaf, 0x07, 0xb1, 0x12, 0x6f, 0xbe, 0x3a, 0x2b, 0xf1, 0xb6, 0xce, 0x4a, 0x5c, - 0x45, 0xdc, 0x84, 0xd5, 0xb8, 0x58, 0xb3, 0x9f, 0x1f, 0xa9, 0x52, 0xee, 0x32, 0x1a, 0xf5, 0x6c, 0x1a, 0x64, 0xf8, - 0xea, 0x77, 0x33, 0x16, 0xb8, 0x11, 0xdf, 0xa3, 0x45, 0x57, 0xc1, 0x5a, 0x30, 0xcc, 0x8e, 0xdf, 0x91, 0x8a, 0x83, - 0x28, 0x5c, 0xfc, 0x0c, 0x4a, 0x59, 0x10, 0x07, 0x26, 0xd2, 0x0b, 0x3f, 0xfd, 0x39, 0x8a, 0xd7, 0xf1, 0x05, 0xf4, - 0xf5, 0xd1, 0x4f, 0xfd, 0x69, 0x40, 0x84, 0xef, 0x2f, 0xb5, 0x40, 0x63, 0x32, 0x71, 0x30, 0xfa, 0xe4, 0x3f, 0xdd, - 0x0d, 0xff, 0x89, 0x66, 0xa1, 0xec, 0x37, 0x35, 0x6d, 0x53, 0x9b, 0x19, 0x11, 0xae, 0x04, 0x94, 0x06, 0xfd, 0x78, - 0x66, 0xe4, 0x2a, 0xd2, 0x1b, 0x66, 0xc9, 0xed, 0x1d, 0x5a, 0xfb, 0x21, 0x35, 0xa6, 0x66, 0xad, 0x1b, 0x22, 0xe8, - 0x55, 0x5d, 0x0c, 0xbf, 0x8a, 0xd6, 0x29, 0x99, 0x45, 0xf7, 0xa1, 0x6a, 0x84, 0xc2, 0xac, 0x1f, 0x34, 0x9c, 0xa2, - 0x0d, 0xa6, 0x6b, 0xfc, 0x80, 0x84, 0x72, 0x94, 0x68, 0x2a, 0x64, 0x0b, 0x5d, 0xc7, 0x26, 0x55, 0x35, 0x9b, 0x38, - 0x45, 0x55, 0xe4, 0x15, 0x7a, 0xa2, 0x69, 0xd1, 0xe8, 0x71, 0x2d, 0xb9, 0xa9, 0x46, 0x64, 0x31, 0xa9, 0x70, 0xaa, - 0x85, 0x5c, 0xb8, 0xc8, 0x23, 0x4f, 0x34, 0x2c, 0x1c, 0x7b, 0x43, 0x9d, 0x45, 0x8b, 0xb7, 0x10, 0xb7, 0x23, 0x5f, - 0xb3, 0xf5, 0x60, 0x71, 0x18, 0xe8, 0xe3, 0x6b, 0x09, 0x8c, 0xef, 0xee, 0x48, 0x12, 0xb8, 0x0f, 0x9a, 0x9e, 0x47, - 0xe1, 0x8f, 0x00, 0x80, 0x37, 0xd1, 0x7d, 0x28, 0x57, 0xc0, 0xf4, 0x28, 0x0d, 0x7b, 0xa9, 0x31, 0x62, 0x08, 0xb8, - 0x8a, 0x48, 0x23, 0x80, 0xc4, 0xb4, 0x0b, 0xf2, 0x77, 0x83, 0xfe, 0xfb, 0x0f, 0x3d, 0x37, 0x2e, 0x23, 0xf1, 0xa1, - 0xbf, 0xc5, 0x07, 0x7c, 0xe6, 0xf9, 0xf3, 0x27, 0xed, 0xd3, 0x2e, 0x27, 0x44, 0x6f, 0x68, 0xad, 0xb7, 0x9e, 0x02, - 0x18, 0xc5, 0x55, 0xb4, 0xf6, 0x96, 0x68, 0x6b, 0xfa, 0xf5, 0xe6, 0x9b, 0x41, 0x9f, 0x98, 0x17, 0x54, 0x4c, 0xbd, - 0x52, 0x54, 0x40, 0x01, 0xbf, 0xff, 0x16, 0x42, 0x5e, 0xfe, 0x0f, 0xc1, 0x50, 0xdf, 0x35, 0x8c, 0x8b, 0xf7, 0x1f, - 0xb7, 0x79, 0x87, 0x90, 0xbe, 0x92, 0x05, 0x93, 0xe0, 0xca, 0xb5, 0x66, 0x24, 0x93, 0x57, 0x81, 0x26, 0x07, 0x6e, - 0x6b, 0x8b, 0x49, 0xc7, 0xbf, 0x42, 0x2c, 0xca, 0xa6, 0x33, 0x5b, 0x7f, 0x83, 0x30, 0x6c, 0x55, 0x41, 0x32, 0xcc, - 0xe4, 0x81, 0x20, 0xfa, 0xaa, 0xbe, 0x5b, 0xf9, 0xa1, 0x81, 0x71, 0xd7, 0xeb, 0x6f, 0xdc, 0x0d, 0x44, 0x1e, 0x06, - 0xe4, 0x56, 0x7d, 0x05, 0x85, 0x86, 0xec, 0xa9, 0x06, 0xc9, 0x95, 0xd4, 0x46, 0x48, 0x70, 0x2d, 0xde, 0xe4, 0x4f, - 0x8a, 0xa2, 0x28, 0x82, 0x8d, 0x50, 0x04, 0x1f, 0x81, 0xe5, 0xc8, 0x0e, 0x80, 0xb6, 0x24, 0x8f, 0x37, 0xb4, 0x04, - 0x38, 0x03, 0xd4, 0xc9, 0xf2, 0x02, 0x16, 0x5c, 0xaf, 0x67, 0xf3, 0x02, 0xce, 0xd0, 0x43, 0x60, 0x34, 0x37, 0x81, - 0x18, 0xbc, 0x03, 0x05, 0x19, 0x76, 0x7c, 0xcb, 0x24, 0xc1, 0x8a, 0x4d, 0x1f, 0x27, 0x43, 0xd2, 0x1c, 0x85, 0x2d, - 0x94, 0xb0, 0x20, 0x68, 0x1d, 0x2a, 0x41, 0x95, 0x0d, 0xd2, 0x80, 0x1b, 0x91, 0x2f, 0xda, 0x64, 0x2b, 0x12, 0xae, - 0x55, 0xcc, 0xc2, 0x84, 0x51, 0xf1, 0xa0, 0xce, 0x1b, 0x4a, 0x6c, 0x01, 0xb6, 0x69, 0x6e, 0xb9, 0xa4, 0x77, 0x61, - 0xca, 0x50, 0xaa, 0x6b, 0x78, 0x4c, 0xb1, 0x99, 0x32, 0xdc, 0x56, 0xbd, 0x21, 0xd8, 0x92, 0x46, 0x55, 0xd7, 0x29, - 0x6a, 0x8c, 0x0c, 0x7d, 0xd0, 0x78, 0x14, 0x4c, 0x5c, 0xc4, 0xc1, 0xae, 0xb9, 0xd5, 0x45, 0x13, 0x1a, 0x19, 0xb7, - 0x22, 0x28, 0x4a, 0xf4, 0x7a, 0x37, 0x6c, 0x9c, 0x10, 0x0a, 0xa8, 0xb5, 0x1f, 0xaf, 0xd6, 0x4f, 0xcb, 0xa4, 0x3f, - 0x91, 0x07, 0x7a, 0x91, 0x50, 0x50, 0x7d, 0x22, 0x0f, 0x60, 0xfb, 0xf7, 0x16, 0xa4, 0x29, 0xea, 0x0e, 0x74, 0x6d, - 0x40, 0x70, 0x7d, 0x0f, 0xc2, 0x43, 0xed, 0x38, 0x40, 0x76, 0xbe, 0x03, 0x8b, 0x23, 0x88, 0x21, 0x8f, 0x32, 0x3f, - 0xc4, 0xcc, 0xca, 0x5e, 0x6b, 0x84, 0xb1, 0xd9, 0x70, 0x34, 0xf4, 0x17, 0x8e, 0x6d, 0x1f, 0xd5, 0xea, 0x83, 0x20, - 0xbb, 0xa9, 0xb6, 0x6e, 0x64, 0x23, 0xc7, 0x36, 0xfd, 0x17, 0x56, 0x67, 0x58, 0xbb, 0xa3, 0xa5, 0xe8, 0x8d, 0x13, - 0x14, 0x7f, 0x8d, 0x9f, 0x6d, 0xb5, 0xda, 0x81, 0xd4, 0xab, 0x56, 0xeb, 0x38, 0xb6, 0x9c, 0xc9, 0xbf, 0x26, 0xf5, - 0xab, 0x9f, 0xc6, 0x8e, 0xa4, 0x99, 0x44, 0x26, 0x10, 0x7f, 0x58, 0x83, 0x63, 0xf4, 0x67, 0xe5, 0xa5, 0xa2, 0xd1, - 0xe3, 0xa3, 0xeb, 0x13, 0x91, 0xa0, 0x9a, 0xbb, 0x75, 0xc9, 0x1d, 0x54, 0xbe, 0x98, 0x56, 0x31, 0x1c, 0x8b, 0x74, - 0x4a, 0x0a, 0x8d, 0xde, 0x4e, 0x6a, 0x01, 0xfb, 0x6f, 0xb9, 0x3e, 0xad, 0x29, 0x44, 0x02, 0x80, 0x1a, 0x10, 0xad, - 0x7c, 0x6f, 0x87, 0xeb, 0xb8, 0xdc, 0x5d, 0xf9, 0x92, 0x3c, 0xbc, 0x33, 0xbc, 0x74, 0x50, 0x87, 0x26, 0xfa, 0x6b, - 0xbe, 0xee, 0x1e, 0xd9, 0x25, 0x09, 0x67, 0xe5, 0x0e, 0x2b, 0xf7, 0xd7, 0xe1, 0xdd, 0x95, 0x30, 0x0a, 0x84, 0xf1, - 0x8f, 0x1a, 0x30, 0x4a, 0x1e, 0x85, 0xb8, 0xf9, 0xe9, 0x71, 0xf3, 0x0f, 0xa2, 0x62, 0xb0, 0x01, 0x8d, 0xc1, 0x25, - 0x9a, 0x49, 0x42, 0x71, 0x88, 0x15, 0x8d, 0x8e, 0xb8, 0x1a, 0x27, 0x44, 0x5b, 0x77, 0x62, 0xc6, 0x6d, 0x0a, 0x8b, - 0x36, 0x3e, 0x8b, 0xfe, 0x78, 0xa8, 0xd4, 0xda, 0xdf, 0x2f, 0xb5, 0xce, 0xf6, 0x49, 0xad, 0xa9, 0x47, 0xd3, 0x7d, - 0xe2, 0xc6, 0x92, 0x53, 0x1c, 0x27, 0xce, 0x65, 0xdf, 0xb8, 0x92, 0xa8, 0x1b, 0x1d, 0xa0, 0x78, 0xab, 0x5a, 0x6f, - 0xd4, 0x4a, 0x10, 0xc5, 0xdf, 0x12, 0x83, 0xc2, 0x15, 0xea, 0xb2, 0x6c, 0xfc, 0xaa, 0x90, 0x8d, 0x53, 0xae, 0xa6, - 0xf0, 0x65, 0xe1, 0xd4, 0xbf, 0xe4, 0x27, 0x26, 0xb8, 0x83, 0xc2, 0x5f, 0xac, 0x18, 0xa9, 0xe4, 0x01, 0x55, 0x30, - 0x1a, 0x92, 0x5f, 0x1d, 0xe7, 0x32, 0xca, 0xee, 0x75, 0xe5, 0xaa, 0x85, 0x03, 0x54, 0x51, 0x0e, 0x52, 0x77, 0x1c, - 0xb2, 0x28, 0x96, 0xb7, 0x4d, 0xd9, 0x03, 0x46, 0x7e, 0x2d, 0x6d, 0x12, 0xe1, 0xaa, 0x42, 0x01, 0xcc, 0xc5, 0xf4, - 0x15, 0xbd, 0xb6, 0xb0, 0x81, 0xc0, 0x41, 0x36, 0x78, 0xd6, 0xed, 0x97, 0xce, 0xd3, 0x0c, 0x05, 0x85, 0x16, 0x5e, - 0x96, 0x41, 0x20, 0x7c, 0x6f, 0xb6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xec, 0x7e, 0x07, 0xf1, 0xa2, 0x62, 0xcb, 0x8a, - 0x7c, 0x3c, 0x99, 0x26, 0x35, 0xcf, 0xc5, 0xaa, 0xf5, 0x4e, 0xa9, 0x10, 0x67, 0xcb, 0x9c, 0x53, 0xca, 0x32, 0x7a, - 0x56, 0x63, 0xc0, 0xbf, 0xcb, 0xb6, 0x4e, 0xb2, 0x0e, 0x31, 0x9a, 0xbc, 0x99, 0x25, 0xae, 0xf7, 0x49, 0x1a, 0x32, - 0x97, 0x73, 0x82, 0x0c, 0xb8, 0xac, 0x29, 0x18, 0xba, 0x18, 0x7c, 0x91, 0x0c, 0xac, 0x4e, 0x2a, 0x49, 0x5f, 0x06, - 0x4f, 0xed, 0xae, 0xfb, 0x6a, 0x7e, 0x5c, 0x11, 0x8a, 0x76, 0x7a, 0x65, 0x91, 0x79, 0xcb, 0x38, 0xb2, 0xe5, 0x7a, - 0x35, 0xdd, 0xca, 0xb2, 0x55, 0x49, 0xe4, 0x5a, 0x17, 0xb3, 0xca, 0x9f, 0x9d, 0xcf, 0xe7, 0x65, 0x41, 0xa3, 0xad, - 0x1c, 0xa3, 0xb0, 0xf0, 0xa9, 0x6d, 0xdb, 0xd5, 0xb1, 0xef, 0x06, 0xbb, 0x89, 0x72, 0xdb, 0xd3, 0xc6, 0x11, 0x23, - 0x6c, 0xf7, 0xc1, 0xaf, 0x0e, 0x8e, 0xdc, 0x2a, 0x4e, 0x76, 0xc9, 0x2c, 0x62, 0x48, 0x8d, 0x21, 0xfc, 0x8c, 0xac, - 0xd2, 0x81, 0x47, 0x50, 0x07, 0x63, 0x49, 0x07, 0x1a, 0x0d, 0x07, 0xcc, 0x05, 0x98, 0x8a, 0x38, 0x7c, 0x57, 0xd8, - 0x0a, 0xca, 0xc3, 0x6b, 0xc2, 0x7b, 0xfe, 0x11, 0x3c, 0x28, 0xdb, 0xba, 0x4c, 0x1b, 0xa7, 0xd5, 0xb3, 0xff, 0x5c, - 0xaa, 0xa7, 0xc0, 0x05, 0xb8, 0xe5, 0x0a, 0x6d, 0x2a, 0x9f, 0xc5, 0xff, 0x17, 0xf2, 0xff, 0x57, 0xf1, 0xa6, 0x6c, - 0x3f, 0x72, 0x0a, 0x12, 0xed, 0xe2, 0xb4, 0xd0, 0x51, 0x37, 0xed, 0x01, 0x61, 0x65, 0x30, 0x97, 0x15, 0xe8, 0xa0, - 0xa4, 0x2f, 0xa5, 0xdc, 0x68, 0x10, 0xbf, 0x23, 0xc5, 0x0c, 0x4b, 0x5c, 0x88, 0x10, 0x8b, 0x84, 0x71, 0x30, 0x07, - 0xe3, 0xe5, 0x29, 0xea, 0x0f, 0x4a, 0x7b, 0x02, 0xb4, 0xf1, 0xb5, 0xb9, 0x1d, 0x24, 0xee, 0xaf, 0xea, 0xb5, 0x78, - 0xc7, 0x00, 0x32, 0x07, 0x0e, 0x21, 0x1a, 0x12, 0x28, 0x95, 0xcd, 0x4d, 0x47, 0x29, 0xde, 0xca, 0x7a, 0x36, 0x3e, - 0x30, 0xec, 0xae, 0xb9, 0x0a, 0xed, 0x9b, 0x6b, 0x0b, 0x60, 0xb2, 0x6c, 0xfb, 0xe1, 0xb3, 0x09, 0x4b, 0x2c, 0xef, - 0x47, 0x07, 0x97, 0x1c, 0xf7, 0xaf, 0x89, 0x77, 0x67, 0x4a, 0xcf, 0x3f, 0xca, 0x17, 0xff, 0xda, 0x28, 0xd0, 0xbb, - 0x2a, 0x49, 0xe8, 0x98, 0xb5, 0x78, 0x47, 0x3f, 0xa8, 0xf6, 0xca, 0x0f, 0x0f, 0xaf, 0xeb, 0x6e, 0x0e, 0xae, 0x0b, - 0x17, 0xc6, 0xc1, 0x95, 0xe1, 0xc6, 0xa1, 0x96, 0x0b, 0xd9, 0xe8, 0xaf, 0x92, 0x40, 0x51, 0x76, 0xfc, 0x55, 0xb1, - 0x15, 0xa5, 0xf2, 0xaf, 0xd6, 0x40, 0x7c, 0x1e, 0x94, 0x52, 0x41, 0xe1, 0x59, 0xd1, 0xd4, 0xbe, 0x72, 0xaa, 0xf4, - 0xbb, 0xca, 0x89, 0xad, 0x52, 0x2e, 0x6c, 0xa4, 0xf6, 0x3a, 0x85, 0x43, 0xdf, 0xb1, 0xad, 0x8e, 0xcf, 0x16, 0xfc, - 0x92, 0x98, 0xfb, 0x41, 0x40, 0x51, 0x45, 0x9a, 0x25, 0xd1, 0x27, 0x52, 0x56, 0xb3, 0xd0, 0x32, 0x66, 0x04, 0xd2, - 0xe1, 0x8f, 0x70, 0x76, 0x3c, 0x37, 0x1e, 0xe0, 0xd9, 0x90, 0x0b, 0xc1, 0x80, 0x93, 0x96, 0xe2, 0x27, 0xe0, 0x0e, - 0x9e, 0xaa, 0xe3, 0x33, 0x08, 0x1a, 0xa8, 0xcc, 0x46, 0xea, 0x8f, 0x9d, 0xbe, 0xe2, 0xf4, 0xee, 0xcc, 0xae, 0x67, - 0x9b, 0x8e, 0x75, 0xac, 0xd8, 0xd6, 0x89, 0xd9, 0xb1, 0xfa, 0x4a, 0xc7, 0xea, 0xc1, 0xbf, 0x9e, 0x63, 0xbd, 0x52, - 0x6c, 0x78, 0x52, 0x1c, 0xab, 0x8b, 0xff, 0x76, 0xac, 0xfe, 0x5d, 0x97, 0xde, 0xf4, 0xae, 0x70, 0xab, 0xaa, 0x8c, - 0x02, 0x9c, 0x40, 0xd4, 0xa3, 0xf1, 0xd9, 0x3a, 0x25, 0xca, 0x66, 0xa4, 0xbe, 0x52, 0x95, 0x65, 0x42, 0xe6, 0x23, - 0xf5, 0xa9, 0x2b, 0x95, 0x3a, 0xa7, 0x8d, 0xc5, 0x9d, 0x7e, 0x63, 0x71, 0xf7, 0xa4, 0xb1, 0xf8, 0xb8, 0x57, 0x2e, - 0x3e, 0x5a, 0xd0, 0x57, 0x52, 0xce, 0xbe, 0x95, 0x9b, 0x25, 0xfe, 0x46, 0x73, 0x14, 0x40, 0xd7, 0x26, 0xfc, 0xd3, - 0xef, 0xe8, 0xa2, 0xd5, 0x14, 0x5a, 0x09, 0x68, 0xf4, 0x4f, 0x15, 0xe7, 0xe4, 0x2f, 0x9d, 0x13, 0x0f, 0xea, 0x41, - 0x86, 0x49, 0xf8, 0xbb, 0xeb, 0x9e, 0x7a, 0xb6, 0x02, 0x0d, 0x1d, 0xf8, 0x6f, 0xd9, 0xeb, 0x78, 0xf4, 0xc1, 0x86, - 0xf7, 0x1f, 0x9d, 0x7e, 0x6a, 0x9b, 0x0e, 0xfc, 0xf7, 0x9b, 0x50, 0xb9, 0x83, 0xc2, 0x5f, 0xee, 0xf7, 0xd8, 0x56, - 0xba, 0xa7, 0xcb, 0x8e, 0xf5, 0xea, 0xae, 0x6f, 0x9d, 0x2e, 0x9d, 0xfe, 0x47, 0xfa, 0x14, 0x98, 0x1d, 0xeb, 0x15, - 0xfc, 0x7d, 0xec, 0xda, 0x4b, 0xd3, 0xb1, 0x4e, 0xef, 0xba, 0x56, 0x37, 0x30, 0x4f, 0xac, 0x53, 0xf8, 0xfb, 0x0d, - 0xc0, 0x0b, 0x70, 0x65, 0x29, 0x41, 0x15, 0xd8, 0x18, 0x15, 0xfb, 0x0d, 0xf9, 0x23, 0x9d, 0x63, 0xa5, 0x77, 0xfc, - 0x97, 0xd3, 0x3b, 0xf3, 0x78, 0xe9, 0x74, 0xee, 0xcc, 0xd6, 0x9f, 0x1f, 0x01, 0xf2, 0xbb, 0x17, 0x0e, 0xc0, 0x88, - 0x39, 0x40, 0xfe, 0x34, 0x31, 0x2e, 0xdb, 0xc4, 0xe8, 0xef, 0xf7, 0x8b, 0xd1, 0x7f, 0x58, 0x1f, 0x22, 0x46, 0x7f, - 0xff, 0xd5, 0xc5, 0xe8, 0x97, 0x55, 0x2b, 0xee, 0xf7, 0xd5, 0x58, 0xe5, 0xbf, 0x6c, 0xab, 0x44, 0xb2, 0xef, 0x6a, - 0xd7, 0x57, 0xeb, 0x1b, 0x88, 0xb6, 0xf3, 0x3e, 0x1a, 0xfd, 0xb0, 0x2e, 0x99, 0x28, 0x45, 0x80, 0x01, 0xde, 0x47, - 0x14, 0x03, 0xfc, 0xb6, 0x1e, 0x81, 0x5d, 0x04, 0xbb, 0x35, 0xfd, 0x99, 0xb9, 0x74, 0x83, 0xb9, 0xb8, 0x71, 0xa1, - 0x64, 0x88, 0xc5, 0x60, 0x33, 0x0f, 0x97, 0x09, 0x28, 0x6b, 0xd6, 0xab, 0x30, 0x1d, 0x9c, 0xd8, 0x80, 0xe6, 0x3b, - 0xf3, 0x24, 0xaf, 0x34, 0xb6, 0x78, 0x7c, 0xa2, 0x5b, 0x66, 0xd3, 0xdf, 0xfa, 0x1e, 0x4d, 0xd6, 0x9a, 0x7b, 0x77, - 0xea, 0xfd, 0x2a, 0x60, 0x0b, 0xc2, 0x4d, 0xfa, 0x80, 0xd8, 0x68, 0x7a, 0x5f, 0x36, 0x1c, 0xab, 0x98, 0x0a, 0xb6, - 0x8f, 0x14, 0x46, 0x52, 0x6d, 0xef, 0x94, 0x0d, 0xcf, 0xf6, 0x4d, 0xb3, 0xe1, 0xf3, 0xa5, 0xe6, 0x3b, 0xac, 0xde, - 0x44, 0xc7, 0x55, 0x50, 0x55, 0x32, 0x6d, 0x35, 0x02, 0xa4, 0xa0, 0x3d, 0x0b, 0xd3, 0xb8, 0x82, 0xf0, 0xb1, 0x15, - 0xbc, 0x8d, 0x6d, 0xe9, 0x5d, 0xa9, 0x4f, 0xd9, 0x9c, 0xee, 0xc5, 0x16, 0xe9, 0x41, 0xff, 0x37, 0x20, 0x6c, 0xd8, - 0x7d, 0x3c, 0x8d, 0x64, 0x38, 0x6f, 0xa5, 0x7e, 0x29, 0xa9, 0x9d, 0x2f, 0x9d, 0x6d, 0x9d, 0xb4, 0x69, 0x35, 0xa4, - 0x75, 0xc8, 0x8a, 0xdf, 0xd1, 0xf8, 0x79, 0x6a, 0xb6, 0x9a, 0x53, 0xd3, 0x62, 0xb4, 0xcc, 0xdd, 0xd5, 0x19, 0xaf, - 0xf7, 0x14, 0x36, 0xb1, 0xc1, 0x1e, 0x64, 0xc7, 0xf1, 0xed, 0x1c, 0xb2, 0x22, 0x0f, 0x90, 0x88, 0x90, 0x28, 0xa8, - 0x0e, 0xda, 0xd8, 0x0e, 0x77, 0x98, 0x7f, 0xc8, 0x1d, 0xb3, 0x4e, 0xd0, 0x56, 0x77, 0x97, 0xc5, 0x88, 0x70, 0x6d, - 0xd8, 0x96, 0x14, 0xa8, 0x4e, 0xaf, 0x6f, 0x38, 0x27, 0x86, 0xd5, 0xef, 0xe9, 0x39, 0x3f, 0x70, 0x72, 0x97, 0x25, - 0x80, 0x80, 0xc9, 0xae, 0x18, 0xa6, 0x1f, 0xfa, 0x99, 0xef, 0x06, 0x39, 0xa0, 0xfa, 0x32, 0xcd, 0xfb, 0xcf, 0x75, - 0x9a, 0xc1, 0x1c, 0x39, 0x49, 0x86, 0xe6, 0xca, 0xe6, 0x94, 0x64, 0xf7, 0x84, 0x84, 0x2d, 0xaa, 0xdc, 0xaa, 0xf5, - 0xf3, 0x1f, 0x67, 0x0b, 0x9a, 0x53, 0x3b, 0x8b, 0x69, 0x16, 0xb2, 0xfd, 0xc1, 0x4d, 0x75, 0xf3, 0x89, 0xf1, 0x53, - 0x1b, 0xc2, 0xfd, 0xe7, 0x7e, 0x84, 0x9b, 0x91, 0x43, 0x10, 0xee, 0x3f, 0xbf, 0x3a, 0xc2, 0xfd, 0x49, 0x46, 0xb8, - 0x25, 0x4f, 0x95, 0x42, 0x26, 0xfa, 0x01, 0x9f, 0x35, 0x08, 0xf2, 0xfb, 0x52, 0x3d, 0xa2, 0xe4, 0xa5, 0x2a, 0x25, - 0x5f, 0xfd, 0x58, 0xca, 0x26, 0x83, 0x2c, 0x3b, 0x06, 0x25, 0xa5, 0x99, 0x2b, 0x20, 0x31, 0xa9, 0x48, 0xb1, 0x0d, - 0x7d, 0x5e, 0x84, 0x59, 0x60, 0xbd, 0x67, 0x6c, 0x09, 0xa8, 0x20, 0x7e, 0x88, 0x92, 0x95, 0x8b, 0x01, 0xd9, 0x54, - 0xcc, 0x42, 0x07, 0x0f, 0x36, 0x78, 0x47, 0x79, 0x51, 0x38, 0x13, 0x72, 0x74, 0x32, 0xba, 0xa6, 0xf4, 0xa0, 0xfa, - 0x40, 0xdc, 0x44, 0x35, 0xe8, 0x6b, 0x58, 0xdc, 0x17, 0x5d, 0xfb, 0x45, 0xe7, 0xf8, 0xc5, 0x89, 0x0d, 0xff, 0x73, - 0x48, 0x37, 0x37, 0x58, 0xc5, 0x55, 0x14, 0x42, 0x22, 0x0c, 0x5e, 0xb3, 0xad, 0xda, 0x3d, 0x21, 0x9f, 0x8a, 0x5a, - 0xfd, 0xe6, 0x4a, 0x33, 0xf7, 0xa1, 0xa8, 0xd3, 0x58, 0x63, 0x19, 0xad, 0xa5, 0x61, 0x35, 0x8c, 0xc6, 0x0f, 0xd7, - 0x20, 0x19, 0x92, 0x6a, 0xc8, 0xaf, 0xd9, 0x74, 0x8b, 0x79, 0x91, 0x6e, 0x7e, 0x53, 0x64, 0xdb, 0xe1, 0x59, 0x3f, - 0xf6, 0x42, 0x90, 0x09, 0xd5, 0x6d, 0x8c, 0xd5, 0x8d, 0xf9, 0x66, 0x14, 0xc8, 0x75, 0x57, 0xa4, 0x54, 0xc7, 0x05, - 0xca, 0x92, 0x75, 0xe8, 0xd1, 0xac, 0xe9, 0xee, 0x34, 0xd5, 0xfc, 0x23, 0x88, 0xd6, 0x89, 0x1f, 0xd6, 0x71, 0xd5, - 0xdc, 0xb1, 0x5d, 0xa4, 0x26, 0x48, 0xf9, 0xaa, 0xb8, 0x2f, 0x32, 0x23, 0xa1, 0x09, 0x4d, 0x71, 0x69, 0xcd, 0x91, - 0xfb, 0x42, 0x34, 0x7c, 0x91, 0x19, 0x90, 0x54, 0x14, 0x96, 0xfb, 0xf9, 0x73, 0x5a, 0x0b, 0xd2, 0xfc, 0xd1, 0x69, - 0x9d, 0x7b, 0x22, 0x35, 0x98, 0xaa, 0xb8, 0x8b, 0x48, 0xc5, 0xd4, 0x60, 0x03, 0xcf, 0x88, 0x5e, 0xbe, 0x1c, 0x8f, - 0x1c, 0x9d, 0x25, 0xa9, 0x2c, 0x65, 0x54, 0xba, 0x3c, 0x4c, 0x35, 0xae, 0x37, 0x3a, 0x6d, 0xc5, 0x7e, 0xb8, 0xe0, - 0x9a, 0x69, 0x81, 0xbd, 0x20, 0xc3, 0x01, 0x55, 0x81, 0xb9, 0x5c, 0x45, 0xcd, 0xeb, 0xdc, 0x91, 0x04, 0x12, 0x6c, - 0x8e, 0xd4, 0xae, 0x65, 0x5b, 0xb6, 0x2a, 0x1a, 0xce, 0xfd, 0xc5, 0x68, 0x1b, 0x65, 0x2e, 0xe4, 0x8a, 0x09, 0xa2, - 0x05, 0x78, 0x7e, 0x64, 0x7e, 0x16, 0x40, 0xe2, 0x11, 0x70, 0x01, 0x59, 0x51, 0xae, 0x31, 0x67, 0xf6, 0xb8, 0x6e, - 0xf2, 0x09, 0x93, 0xcf, 0x71, 0xa7, 0x2f, 0x0c, 0x49, 0xf3, 0x23, 0x5c, 0x86, 0x9a, 0xaa, 0x41, 0xea, 0x43, 0x92, - 0xa4, 0xa6, 0x6c, 0xdf, 0x3e, 0x50, 0xa0, 0x0d, 0xa4, 0x25, 0xc7, 0x0e, 0xe6, 0x89, 0xbb, 0x82, 0x18, 0xdd, 0xdb, - 0xdc, 0x60, 0x98, 0x56, 0x65, 0xa8, 0x56, 0x71, 0x5e, 0x9d, 0x18, 0x4a, 0xc7, 0x31, 0x14, 0x1b, 0xd0, 0xad, 0x9a, - 0x1b, 0xdb, 0xfc, 0x66, 0xb8, 0x4f, 0x45, 0x47, 0xf1, 0xcb, 0x53, 0x3a, 0x0f, 0xaa, 0x9c, 0x63, 0xc2, 0xcf, 0x8c, - 0x06, 0x14, 0xd4, 0xa4, 0xe8, 0xd9, 0x3e, 0x15, 0xd3, 0x5f, 0x91, 0x4d, 0xa6, 0x63, 0x62, 0x0e, 0x56, 0xc5, 0xd7, - 0xb7, 0xe8, 0x9a, 0xe6, 0x87, 0x8a, 0xff, 0xf9, 0xb3, 0xe6, 0x83, 0xf9, 0xfd, 0x48, 0x82, 0x0f, 0x3c, 0xeb, 0x25, - 0x80, 0xf9, 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0xcc, 0x7f, 0x30, 0xc5, 0x9e, 0x15, 0xb8, - 0xe1, 0x02, 0x50, 0x9a, 0x1b, 0x2e, 0x6a, 0x06, 0x04, 0xd4, 0xbb, 0xae, 0x52, 0x5a, 0x74, 0x55, 0x28, 0xf7, 0xd3, - 0xef, 0x1f, 0xae, 0x68, 0xe2, 0x21, 0x48, 0x72, 0xed, 0xce, 0xd0, 0x15, 0xac, 0xd0, 0x3d, 0xbc, 0x1c, 0x7d, 0x73, - 0xb6, 0x22, 0x99, 0x4b, 0x05, 0x97, 0xc0, 0xe2, 0x01, 0x39, 0xa0, 0x78, 0x3c, 0x69, 0x28, 0x65, 0xf0, 0x66, 0xe4, - 0xce, 0xf7, 0x18, 0x9f, 0x66, 0x28, 0xec, 0x9e, 0x32, 0xd1, 0x46, 0x69, 0xe4, 0x18, 0xd4, 0x44, 0xd6, 0x73, 0x31, - 0xec, 0xe0, 0x28, 0x8c, 0xd4, 0xf1, 0x37, 0xc2, 0x9b, 0xa8, 0x6d, 0x11, 0x20, 0xfb, 0xdf, 0x75, 0x42, 0x82, 0x7f, - 0x8d, 0xbe, 0x81, 0x8b, 0xfb, 0x9b, 0x1b, 0x55, 0x1f, 0x66, 0x16, 0xf2, 0x31, 0xdf, 0x34, 0x64, 0xc1, 0x43, 0x1e, - 0x95, 0x31, 0x9b, 0x5d, 0x89, 0xd9, 0x84, 0xdf, 0xfb, 0x59, 0xd7, 0xf1, 0x19, 0x5e, 0x68, 0x63, 0xe0, 0x2e, 0xb6, - 0x25, 0x9e, 0xd3, 0x19, 0x22, 0x83, 0x3a, 0x0d, 0x5c, 0xef, 0x13, 0xe7, 0x50, 0xe5, 0x87, 0x43, 0x78, 0x51, 0x41, - 0xd9, 0x35, 0xee, 0x65, 0xdc, 0xca, 0x5b, 0xfc, 0x32, 0x7e, 0xea, 0x7e, 0xe9, 0x67, 0x82, 0x19, 0xc6, 0x87, 0x1c, - 0xb4, 0x39, 0x38, 0xbe, 0x82, 0xfd, 0x01, 0x06, 0xd5, 0x39, 0xfd, 0x4b, 0xef, 0xce, 0xb1, 0x97, 0x1d, 0xc7, 0x02, - 0x36, 0x67, 0xd9, 0xb5, 0xfa, 0x81, 0xd9, 0xb5, 0xfa, 0xf0, 0xf7, 0x11, 0x58, 0x2f, 0xb3, 0x63, 0x1d, 0x7f, 0x74, - 0x3a, 0x81, 0x79, 0x6a, 0xf5, 0xe1, 0xef, 0x92, 0xb6, 0xfa, 0x05, 0x99, 0x1e, 0x60, 0x78, 0xbe, 0x29, 0x61, 0x01, - 0xe9, 0xb7, 0xd0, 0x22, 0x18, 0xa5, 0xeb, 0xad, 0x41, 0x13, 0x01, 0x28, 0x43, 0x35, 0x78, 0x94, 0xc0, 0x70, 0xa8, - 0x41, 0x5a, 0x6e, 0x0c, 0x28, 0xcf, 0x0d, 0x32, 0xc2, 0x22, 0xc5, 0x7c, 0xfb, 0x31, 0x62, 0x6d, 0x9a, 0x03, 0x70, - 0xf3, 0x4c, 0x45, 0x54, 0x75, 0xf1, 0xb7, 0x18, 0x03, 0xeb, 0xf0, 0x90, 0xe1, 0x12, 0x56, 0x2a, 0xb2, 0xe5, 0xe5, - 0xfb, 0x07, 0x8e, 0x7e, 0xa3, 0x44, 0x64, 0x6b, 0xf9, 0xaa, 0x7d, 0x33, 0x75, 0x86, 0xe8, 0xfd, 0xf7, 0xf6, 0x83, - 0x49, 0x4a, 0x69, 0x3f, 0x3c, 0xba, 0xe7, 0xcc, 0x4f, 0xc4, 0xf0, 0x24, 0x14, 0xed, 0x34, 0x47, 0x2e, 0xd7, 0x21, - 0xad, 0xc5, 0x05, 0x50, 0xc9, 0x77, 0x6e, 0x20, 0x99, 0x5e, 0x48, 0x2d, 0x9f, 0x08, 0xcc, 0xff, 0xfc, 0x79, 0x31, - 0x38, 0xb3, 0x32, 0xee, 0x33, 0xa7, 0x07, 0xd7, 0x6e, 0x8f, 0x74, 0x77, 0x5a, 0x01, 0xed, 0x0f, 0x0f, 0x5b, 0xc4, - 0x93, 0xe4, 0x9a, 0x7e, 0xae, 0x63, 0x6c, 0x35, 0x45, 0xaa, 0x69, 0x18, 0x21, 0xb0, 0x6e, 0x85, 0xd5, 0x51, 0xf5, - 0x61, 0xc8, 0x15, 0x66, 0xe1, 0x8e, 0x90, 0xb8, 0x8c, 0x17, 0x53, 0x01, 0x34, 0x3b, 0xe6, 0xb1, 0xc7, 0xa5, 0xf1, - 0x7f, 0x3d, 0x09, 0x74, 0x2f, 0x02, 0x0d, 0x5f, 0xe5, 0xb4, 0x96, 0xdc, 0x4d, 0xc4, 0xbd, 0x4a, 0x2f, 0x54, 0x92, - 0x9e, 0xab, 0x50, 0x04, 0xf9, 0x8e, 0x30, 0xc5, 0x99, 0x30, 0x6f, 0x12, 0xb7, 0x45, 0x51, 0x60, 0xf8, 0x10, 0x13, - 0x5a, 0xe3, 0xae, 0x4e, 0xfa, 0xf3, 0xe7, 0xad, 0x97, 0x10, 0x55, 0x27, 0xcb, 0x99, 0x1e, 0x55, 0x19, 0xbf, 0xa9, - 0x32, 0x8a, 0x11, 0xfd, 0x22, 0xd6, 0xe0, 0x56, 0x59, 0x74, 0xef, 0xe1, 0xcf, 0x29, 0x71, 0x33, 0x8b, 0xe9, 0x41, - 0x34, 0xe9, 0x72, 0x37, 0x1c, 0xd2, 0x05, 0x7b, 0x2c, 0x16, 0x7f, 0x8b, 0x05, 0x9b, 0x7b, 0xb6, 0xfd, 0xb8, 0x66, - 0x7e, 0xc8, 0xd0, 0xc7, 0x67, 0xbb, 0x08, 0x9e, 0xf2, 0x2e, 0x73, 0x69, 0x84, 0x0d, 0xf9, 0xca, 0x8d, 0x32, 0x97, - 0xe7, 0x15, 0x01, 0xba, 0x7c, 0xd8, 0xa8, 0x30, 0x94, 0x7c, 0x95, 0xc7, 0xef, 0xae, 0xbe, 0x53, 0xd8, 0xfe, 0xa7, - 0xfa, 0x2d, 0x64, 0x64, 0x68, 0x14, 0xfc, 0x11, 0x8d, 0x82, 0xaf, 0xb0, 0xb4, 0x12, 0x10, 0x4b, 0x3e, 0x3f, 0xa2, - 0x10, 0x54, 0x15, 0x12, 0x7a, 0x54, 0xeb, 0xb7, 0x5a, 0x07, 0x99, 0x1f, 0xbb, 0x49, 0x76, 0x04, 0x4d, 0x4d, 0x40, - 0x72, 0x6a, 0x9b, 0x07, 0x33, 0x55, 0x1c, 0x72, 0xa1, 0x5a, 0x16, 0x72, 0xcd, 0xe1, 0xdc, 0x0f, 0x84, 0xe2, 0x90, - 0x7f, 0xc0, 0xf5, 0x3c, 0x12, 0x67, 0x23, 0xd5, 0x8d, 0x21, 0x1b, 0x02, 0xc6, 0x37, 0x3e, 0x8a, 0xbc, 0x8c, 0x64, - 0x66, 0x9a, 0x25, 0xc4, 0x5d, 0xa9, 0x22, 0xd6, 0x67, 0xbd, 0xbf, 0x74, 0x3d, 0x5d, 0xf9, 0x99, 0x08, 0x96, 0x47, - 0x27, 0x08, 0x2a, 0x3c, 0x18, 0xe2, 0x78, 0x92, 0x33, 0x10, 0x5e, 0x46, 0x8b, 0xca, 0x8e, 0x2a, 0x28, 0x97, 0x73, - 0x0c, 0xc5, 0xca, 0x22, 0xe0, 0xcf, 0xd0, 0x23, 0xe7, 0x96, 0x79, 0x5d, 0x8b, 0x98, 0x7e, 0xea, 0xf8, 0x8c, 0xb1, - 0xb7, 0x0a, 0x06, 0x0a, 0x50, 0x7b, 0x36, 0x04, 0x9b, 0x6d, 0xf3, 0xc7, 0x3e, 0x62, 0x95, 0xe1, 0x6a, 0xa2, 0x3d, - 0x63, 0xdc, 0x6f, 0x3a, 0x96, 0x2b, 0x20, 0x84, 0x4a, 0x2a, 0xde, 0xa5, 0x33, 0x16, 0x0e, 0x40, 0x38, 0x2a, 0xa4, - 0x95, 0x3e, 0x7f, 0x7e, 0x3d, 0xf9, 0xcf, 0xbf, 0x21, 0x38, 0xf9, 0xd2, 0xe1, 0x5e, 0xd0, 0xd7, 0x72, 0x2d, 0x46, - 0x7d, 0x1a, 0x13, 0x54, 0xef, 0x93, 0x19, 0x0f, 0x0b, 0xc2, 0xb7, 0x56, 0x3e, 0xb9, 0xe1, 0xa1, 0x9e, 0x20, 0x01, - 0x81, 0xce, 0x7d, 0xb5, 0x27, 0xb0, 0xbc, 0x13, 0x1e, 0x22, 0x40, 0xf9, 0x75, 0xf3, 0x7d, 0x1f, 0xb2, 0xf4, 0xd6, - 0xf2, 0x02, 0x48, 0x03, 0xc4, 0x3d, 0x34, 0x3e, 0x73, 0x99, 0xf0, 0x15, 0xc8, 0x8f, 0x74, 0x70, 0x04, 0xd3, 0x5c, - 0x46, 0x2b, 0x62, 0xf9, 0xd1, 0xd1, 0x3d, 0x99, 0x9a, 0x6e, 0xec, 0x53, 0xf9, 0x32, 0xca, 0xdd, 0x14, 0x4a, 0xf9, - 0x09, 0x05, 0x2d, 0xa5, 0xaf, 0xf3, 0x02, 0x94, 0x51, 0x01, 0x28, 0xf8, 0xe9, 0x8e, 0xcb, 0x01, 0xfc, 0x2c, 0x1e, - 0x31, 0xbe, 0x8c, 0xe5, 0xcf, 0x69, 0x1c, 0x3e, 0x1e, 0x72, 0xaf, 0x78, 0x30, 0xa3, 0xf9, 0x5c, 0x0e, 0xba, 0x67, - 0x95, 0xbf, 0x2f, 0xa0, 0x52, 0xec, 0xd9, 0x28, 0xa6, 0x5f, 0xaa, 0x7f, 0x42, 0xfc, 0x84, 0x6c, 0xb9, 0x2c, 0x3e, - 0x23, 0x9c, 0xe7, 0x5a, 0xf0, 0x3e, 0x01, 0x92, 0xa7, 0xb4, 0x12, 0x43, 0x14, 0xd5, 0xc8, 0xd0, 0x2d, 0xa4, 0xc9, - 0x93, 0xd1, 0x88, 0xe2, 0xb1, 0x2a, 0x3a, 0x03, 0x28, 0x35, 0x44, 0xcf, 0x87, 0xc9, 0x66, 0xd0, 0xd0, 0xa4, 0x1e, - 0x5c, 0xd8, 0xa8, 0x3a, 0x9d, 0xfa, 0x18, 0x8f, 0x5c, 0xbe, 0xbf, 0x4a, 0x3b, 0x10, 0x76, 0x16, 0x5b, 0x58, 0x40, - 0xe0, 0xbc, 0x9f, 0x0a, 0x1e, 0x57, 0xbe, 0xa5, 0x28, 0xdb, 0x0c, 0xdc, 0x87, 0x48, 0xd2, 0xac, 0x33, 0x27, 0xfb, - 0x4b, 0x2c, 0xbd, 0xe2, 0xce, 0x6d, 0xb5, 0x93, 0x24, 0x22, 0x90, 0xd7, 0x4f, 0x93, 0x1c, 0x32, 0x7c, 0xdf, 0x61, - 0x92, 0xeb, 0x96, 0x27, 0x83, 0xd8, 0x31, 0x2f, 0x0e, 0x5a, 0xe9, 0x25, 0x9e, 0xfb, 0xfc, 0xec, 0x08, 0xe6, 0x07, - 0x81, 0x01, 0x4a, 0x94, 0x91, 0xaf, 0x43, 0xf4, 0x01, 0x37, 0xa5, 0xd6, 0x01, 0x17, 0x33, 0x4e, 0xd4, 0x21, 0xe7, - 0x28, 0xa2, 0x83, 0x96, 0xaa, 0xd4, 0x89, 0x15, 0xbb, 0x99, 0xca, 0xdb, 0x1f, 0xb1, 0xff, 0xb7, 0x35, 0x86, 0xeb, - 0xcf, 0x87, 0x19, 0xe1, 0x7e, 0xb7, 0x97, 0x59, 0x8b, 0x6b, 0x6e, 0x5b, 0x15, 0x4a, 0xb0, 0xee, 0xa8, 0x50, 0xec, - 0xe3, 0x5d, 0xb5, 0x0a, 0xd2, 0x48, 0x54, 0x8b, 0x5d, 0x4d, 0x7d, 0x8a, 0x3b, 0xbe, 0x56, 0x1b, 0x4b, 0xa1, 0xde, - 0x65, 0x36, 0x82, 0xaa, 0x5c, 0xd8, 0xee, 0xc6, 0x31, 0xad, 0xac, 0x0f, 0xcf, 0x8e, 0x28, 0xdf, 0x39, 0xa6, 0x3b, - 0x6c, 0x7c, 0x06, 0xd6, 0x85, 0x74, 0xd1, 0xdd, 0x38, 0x66, 0x4b, 0x4a, 0x7f, 0xd1, 0x37, 0x47, 0xcb, 0x6c, 0x15, - 0x8c, 0xff, 0x0f, 0x00, 0xa3, 0x9b, 0x76, 0x11, 0x5a, 0x03, 0x00}; + 0xdc, 0xd3, 0x2f, 0xb7, 0x8d, 0x1b, 0xff, 0x7f, 0x9f, 0x82, 0x61, 0xd2, 0x1c, 0x99, 0x90, 0x34, 0x29, 0x59, 0xb6, + 0x23, 0x59, 0xf6, 0xdd, 0x25, 0xb9, 0xa9, 0x3b, 0xbe, 0xcb, 0x4d, 0xe2, 0x66, 0xda, 0xf3, 0x79, 0x2c, 0x4a, 0x82, + 0x24, 0x36, 0x14, 0xa9, 0x21, 0x29, 0x5b, 0x3e, 0x85, 0x7d, 0x96, 0x3e, 0x4b, 0x9f, 0xec, 0x37, 0xbb, 0x0b, 0x80, + 0xe0, 0x87, 0x3e, 0x7c, 0xc9, 0xb5, 0xbf, 0xb9, 0xba, 0x11, 0x41, 0x00, 0x04, 0x16, 0xc0, 0x62, 0xbf, 0xd7, 0x9f, + 0x72, 0xd9, 0x8b, 0x65, 0xb0, 0xfd, 0x3e, 0xf7, 0xf9, 0x33, 0x73, 0x70, 0x4b, 0x02, 0xc1, 0xe7, 0x64, 0xf1, 0x74, + 0x1a, 0x32, 0x43, 0x17, 0xc9, 0x43, 0x74, 0x4b, 0x7e, 0xe6, 0xfc, 0x89, 0x2b, 0x22, 0x76, 0x9a, 0xf9, 0xa6, 0xa3, + 0x25, 0x66, 0xcc, 0x64, 0x48, 0x3b, 0xa2, 0x5c, 0x51, 0x36, 0x7b, 0x87, 0xea, 0x0d, 0xbe, 0x2e, 0xc5, 0xd1, 0xb5, + 0xc7, 0xf1, 0x72, 0x18, 0x32, 0x1b, 0xb7, 0x3b, 0x7c, 0x72, 0x3d, 0x5c, 0x0e, 0x87, 0x90, 0xa5, 0xe5, 0x89, 0x6b, + 0x41, 0xdc, 0x99, 0x38, 0x45, 0x7e, 0x30, 0x37, 0x7b, 0x30, 0x29, 0x27, 0xab, 0x0e, 0x1f, 0x6c, 0x45, 0x40, 0xd4, + 0x43, 0x1f, 0xc8, 0x80, 0xf7, 0x6b, 0x38, 0xb5, 0x7d, 0xfd, 0x03, 0xec, 0xbe, 0x54, 0xef, 0x35, 0x1d, 0xfd, 0xfe, + 0xb5, 0xfe, 0x01, 0x61, 0x8c, 0xd9, 0x8b, 0x5f, 0xd3, 0xee, 0xd5, 0x2d, 0x9d, 0x94, 0xde, 0x4b, 0xcc, 0x63, 0x00, + 0x42, 0xdf, 0x37, 0x81, 0x3f, 0x8d, 0xe2, 0x34, 0x0b, 0x46, 0xfa, 0x4d, 0xef, 0x22, 0x30, 0xae, 0xe7, 0x99, 0x61, + 0xde, 0x58, 0xa3, 0x4c, 0x4d, 0x81, 0x22, 0x10, 0x26, 0x66, 0x40, 0xd9, 0x54, 0x49, 0x3d, 0x41, 0x5b, 0x2b, 0x0a, + 0xd4, 0x8c, 0x95, 0x46, 0x59, 0x1f, 0xea, 0x55, 0xf2, 0xa9, 0x60, 0x62, 0x28, 0x1d, 0x5b, 0x9a, 0x3d, 0xe2, 0x54, + 0x5e, 0x2f, 0xd7, 0x78, 0x95, 0x67, 0xc5, 0x6d, 0x89, 0x31, 0x80, 0x85, 0xe3, 0x0c, 0x3d, 0x3f, 0x51, 0x8d, 0x3e, + 0x4b, 0xf7, 0xee, 0xe0, 0xbb, 0x32, 0x5d, 0x00, 0xf7, 0x37, 0x58, 0x5c, 0x44, 0x71, 0xa6, 0x41, 0x60, 0x1b, 0xf8, + 0xe2, 0xa0, 0x6a, 0x24, 0xc6, 0x7b, 0x35, 0xcc, 0x9c, 0x23, 0x83, 0xef, 0xf1, 0xf2, 0x33, 0x78, 0x78, 0xb3, 0x52, + 0x04, 0x0b, 0x62, 0x16, 0x22, 0x58, 0xc0, 0x2c, 0xbe, 0x8c, 0xef, 0xab, 0x7a, 0x90, 0xd7, 0x83, 0xdd, 0x77, 0xaf, + 0x21, 0xc8, 0x64, 0x91, 0xd5, 0xcf, 0xe0, 0x89, 0x49, 0x05, 0xa1, 0x53, 0x39, 0x53, 0x68, 0xf8, 0x21, 0x68, 0x98, + 0x0c, 0xec, 0xc4, 0xf0, 0x2e, 0x00, 0x94, 0xc4, 0xaf, 0xe9, 0x41, 0x7e, 0x2b, 0x52, 0x27, 0x8b, 0xc4, 0xc5, 0xca, + 0xe5, 0x0c, 0xd8, 0x35, 0x5a, 0x2c, 0x33, 0x0c, 0xb5, 0x0b, 0x03, 0x60, 0xb9, 0xae, 0x61, 0xe8, 0x4e, 0xc0, 0xd2, + 0x05, 0x99, 0x98, 0xeb, 0x5a, 0x30, 0xae, 0x97, 0x71, 0xa2, 0x17, 0x90, 0x17, 0xe2, 0x77, 0x14, 0x54, 0xc1, 0x63, + 0xc2, 0xa7, 0x31, 0xb2, 0x8a, 0x38, 0xf5, 0xc6, 0x08, 0x15, 0x3a, 0x0d, 0x98, 0x61, 0x44, 0xfd, 0xf4, 0x8c, 0xb0, + 0x71, 0xb2, 0x10, 0x7e, 0xb3, 0x34, 0xcd, 0xc1, 0xb3, 0x75, 0x94, 0x9f, 0x3f, 0x5b, 0xa7, 0x79, 0xff, 0xd9, 0xda, + 0x97, 0xb6, 0x02, 0xfa, 0x95, 0x4e, 0x86, 0x02, 0x03, 0x04, 0xc3, 0x20, 0xbf, 0x2d, 0x3c, 0x77, 0x8a, 0xf9, 0xc2, + 0x2e, 0xa3, 0x72, 0x0d, 0x55, 0xf7, 0x7d, 0xae, 0xa0, 0x5f, 0x24, 0xc1, 0xdc, 0x4f, 0x1e, 0x48, 0x9f, 0x6f, 0xa9, + 0x4a, 0x7f, 0x53, 0xd7, 0x08, 0xd1, 0x13, 0x00, 0x08, 0xe7, 0xeb, 0xda, 0xb7, 0xb2, 0x8c, 0xf1, 0xd9, 0x4a, 0xa5, + 0x26, 0x7c, 0xeb, 0x56, 0x7f, 0xc9, 0x9c, 0x31, 0xcb, 0xfc, 0x20, 0xa4, 0x26, 0x3d, 0x91, 0xad, 0xbe, 0x36, 0xbd, + 0xb4, 0x3c, 0xbd, 0xa8, 0xbc, 0x7f, 0x70, 0x32, 0x74, 0x05, 0xd0, 0xb8, 0x71, 0x66, 0x98, 0xc5, 0xaa, 0x79, 0x45, + 0xe9, 0xdd, 0x7f, 0x75, 0x39, 0x18, 0x2c, 0x47, 0x04, 0xcb, 0xc1, 0xa2, 0x51, 0x3c, 0x66, 0x7f, 0x7b, 0x7f, 0x21, + 0xd3, 0x66, 0x81, 0x04, 0x68, 0xc0, 0x37, 0x66, 0x8a, 0xf4, 0x43, 0x82, 0xb4, 0x03, 0x25, 0xb8, 0xd2, 0xe4, 0x16, + 0x4a, 0x72, 0x5d, 0x3b, 0xa7, 0xb1, 0xb3, 0x31, 0x8d, 0xba, 0x1f, 0x63, 0xab, 0x24, 0x3f, 0x3d, 0xa0, 0xda, 0x74, + 0xdb, 0x51, 0x25, 0x00, 0x43, 0x02, 0x33, 0x2c, 0xa0, 0x00, 0x19, 0x3e, 0xfb, 0x5e, 0xc1, 0x50, 0x38, 0x73, 0x94, + 0xb3, 0x7b, 0xe7, 0x65, 0x52, 0x05, 0x5b, 0xe9, 0x67, 0xa7, 0x98, 0xb3, 0x0b, 0xee, 0x6b, 0x88, 0xf2, 0x71, 0x7a, + 0x40, 0x8f, 0x5a, 0xe5, 0x44, 0x14, 0x9d, 0x08, 0xd6, 0xae, 0xcb, 0x3b, 0x78, 0xd4, 0x51, 0x81, 0x14, 0xf1, 0x50, + 0xea, 0xe7, 0xba, 0x36, 0xe7, 0xa4, 0x11, 0x0f, 0x27, 0x04, 0xb1, 0x06, 0x5c, 0x38, 0xbb, 0xba, 0x36, 0xf7, 0x57, + 0x38, 0x73, 0xf1, 0xc6, 0x5f, 0x19, 0x1e, 0x7f, 0x55, 0x9c, 0xb5, 0xb4, 0x7c, 0xd6, 0x46, 0x7c, 0x71, 0xc1, 0x91, + 0x40, 0x72, 0xd6, 0x33, 0x54, 0xd0, 0x36, 0x2c, 0xee, 0x4c, 0x2c, 0xee, 0x78, 0xc3, 0xe2, 0x8e, 0xb7, 0x2c, 0x6e, + 0xc8, 0x17, 0x52, 0x93, 0xa0, 0x4b, 0xd0, 0x39, 0x4c, 0x02, 0x8f, 0x13, 0x1a, 0x5d, 0x7e, 0xce, 0x10, 0x4e, 0x76, + 0x1a, 0x82, 0x71, 0xd4, 0x06, 0x58, 0x35, 0xc1, 0x45, 0x01, 0x44, 0x7d, 0xe2, 0xf2, 0xd4, 0x89, 0x79, 0x43, 0x0e, + 0x4e, 0x23, 0xac, 0xce, 0x17, 0x76, 0x29, 0xe5, 0x17, 0x37, 0x66, 0x1b, 0x66, 0x3a, 0xdb, 0x32, 0xd3, 0x51, 0xe9, + 0xe8, 0xf2, 0x69, 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0x0c, 0x46, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x1c, + 0xab, 0xec, 0xa8, 0x85, 0x9f, 0xa6, 0xf7, 0x71, 0x02, 0x1a, 0x17, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x1e, 0x44, 0x3c, + 0x98, 0xcb, 0xc6, 0xcd, 0x54, 0xbc, 0x57, 0xb7, 0x54, 0xab, 0xd3, 0xa1, 0x1a, 0x0b, 0x3f, 0xcb, 0x58, 0x82, 0x40, + 0xf7, 0x21, 0xea, 0xf7, 0xff, 0x93, 0x6d, 0xd6, 0x80, 0x43, 0x42, 0x05, 0xab, 0x23, 0x86, 0x5e, 0x00, 0x6d, 0x95, + 0x88, 0x8b, 0x58, 0x09, 0x0c, 0x97, 0x48, 0xc0, 0xff, 0x84, 0xc7, 0xd5, 0x48, 0x14, 0xd7, 0x25, 0xef, 0xc8, 0x74, + 0x16, 0xfe, 0xf8, 0x03, 0x28, 0xf6, 0x8c, 0x96, 0x05, 0x46, 0xba, 0x6a, 0x18, 0xb8, 0x84, 0x88, 0xbd, 0x51, 0x81, + 0x24, 0x11, 0x4b, 0x72, 0x13, 0x28, 0xf0, 0x9e, 0xf4, 0xed, 0xc9, 0xcd, 0xba, 0x95, 0x1f, 0x4c, 0x03, 0xb3, 0x86, + 0x35, 0x01, 0xb5, 0x85, 0xfd, 0x33, 0xc9, 0x73, 0x85, 0x96, 0x77, 0x64, 0x82, 0xe4, 0xf7, 0x1a, 0xf2, 0x99, 0xba, + 0x82, 0xa1, 0x1d, 0x24, 0x70, 0x6b, 0x5d, 0xbb, 0x37, 0xf9, 0xf3, 0x29, 0xfe, 0xf2, 0x6e, 0xf2, 0xe7, 0x43, 0xfc, + 0xd5, 0xba, 0xc1, 0xcc, 0x75, 0x0d, 0x8c, 0xbc, 0x32, 0x67, 0xfd, 0xac, 0xb4, 0x9f, 0xc8, 0xfe, 0xec, 0x11, 0xdb, + 0x86, 0x2f, 0xf0, 0xd3, 0x67, 0xeb, 0x14, 0x3c, 0x2e, 0xd5, 0x39, 0x44, 0x4e, 0x62, 0xe6, 0x8d, 0xe5, 0xd3, 0x0d, + 0xe5, 0x43, 0xf3, 0xbf, 0x7c, 0xf1, 0xe3, 0x2e, 0x89, 0x8b, 0x3b, 0xa5, 0x2c, 0x86, 0xb8, 0x1d, 0x06, 0x91, 0x9f, + 0x3c, 0xdc, 0x12, 0x7b, 0x61, 0x08, 0xda, 0x5d, 0x8a, 0x57, 0x88, 0xbc, 0x2c, 0xab, 0xbb, 0x32, 0x45, 0xc0, 0xfb, + 0xc0, 0x2f, 0xfa, 0xfe, 0xdf, 0x13, 0x85, 0x6c, 0x2b, 0x31, 0xa0, 0x7c, 0x41, 0x4a, 0x1f, 0xba, 0x7d, 0xb6, 0x36, + 0x58, 0xbd, 0x9b, 0xca, 0x6c, 0x2b, 0x74, 0x21, 0x2c, 0x0f, 0x32, 0xb3, 0xf3, 0x71, 0xd0, 0x45, 0x7d, 0xd6, 0x30, + 0x5e, 0xd9, 0xcf, 0xd6, 0xd9, 0xb9, 0x3e, 0xf7, 0x93, 0x4f, 0x6c, 0x6c, 0x8f, 0x82, 0x64, 0x14, 0x32, 0xbd, 0xab, + 0x0f, 0x43, 0x3f, 0xfa, 0xc4, 0x1f, 0xed, 0x78, 0x99, 0xa1, 0x86, 0x7a, 0x27, 0xef, 0x2b, 0x60, 0x42, 0x22, 0x3b, + 0x24, 0x56, 0x1b, 0xa0, 0xa0, 0xbd, 0x96, 0x02, 0xaf, 0x82, 0x50, 0x2c, 0x6a, 0x59, 0x60, 0x60, 0x09, 0x4a, 0x73, + 0xf0, 0x58, 0xb5, 0x74, 0x5c, 0x2f, 0xdd, 0x52, 0xa7, 0x4a, 0xc2, 0x4a, 0x99, 0x72, 0xf1, 0x16, 0x7b, 0xf8, 0xfd, + 0x9f, 0xa3, 0x64, 0xd8, 0xfb, 0x7f, 0x4e, 0xf6, 0xf2, 0x65, 0x33, 0x84, 0x52, 0x9b, 0x3c, 0x25, 0x1e, 0xf1, 0x71, + 0x4e, 0x60, 0x6e, 0xfe, 0xb4, 0xda, 0xd8, 0x4f, 0xd3, 0xe5, 0x9c, 0x8d, 0x49, 0x33, 0x78, 0x5e, 0x0c, 0xaa, 0xcc, + 0x59, 0xa8, 0x03, 0xfb, 0x75, 0xd9, 0x3a, 0x3e, 0x7c, 0x0d, 0x16, 0x0b, 0x40, 0x50, 0xc6, 0x93, 0x89, 0x5e, 0xf0, + 0xf8, 0x3b, 0x9a, 0x79, 0x87, 0xbf, 0x2e, 0x7f, 0x78, 0xeb, 0xfe, 0x20, 0x1b, 0x47, 0x40, 0x18, 0x0b, 0xf5, 0x2b, + 0xa7, 0x8b, 0x95, 0xf1, 0x8a, 0x19, 0x4d, 0xfc, 0x68, 0xf3, 0x74, 0xae, 0x4b, 0x5b, 0x7c, 0xc1, 0xd8, 0x18, 0x08, + 0x6e, 0xab, 0x56, 0x7a, 0x1b, 0xb2, 0x3b, 0x26, 0x55, 0xbb, 0xf5, 0x8f, 0x35, 0xb4, 0xc0, 0xd8, 0x73, 0x5c, 0x65, + 0xcc, 0xa9, 0x3a, 0x65, 0x4a, 0x03, 0x9c, 0x03, 0x9f, 0xb9, 0x7a, 0xc4, 0x2a, 0x47, 0x6a, 0x60, 0xe9, 0xca, 0x00, + 0x36, 0x8e, 0xec, 0x7c, 0x43, 0x79, 0x17, 0x13, 0x4f, 0x37, 0x8f, 0xcd, 0xf2, 0xcc, 0x2e, 0xc4, 0xea, 0xe6, 0x70, + 0x0a, 0xe1, 0xe4, 0x19, 0x85, 0x38, 0x64, 0x13, 0xc4, 0x9a, 0x84, 0x64, 0x3a, 0x49, 0x5f, 0x84, 0xb5, 0x23, 0x9a, + 0xfd, 0x0a, 0x39, 0x54, 0xe3, 0xda, 0x68, 0xe5, 0x99, 0x0f, 0x31, 0xa1, 0x6b, 0xc4, 0xd2, 0x74, 0x23, 0xc0, 0xe4, + 0xa2, 0x5b, 0x7a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0x72, 0x2d, 0x20, 0x09, 0x70, 0x82, 0xd5, 0x6f, 0xe1, 0xf5, + 0x72, 0x3b, 0xe7, 0xf6, 0x2a, 0xc9, 0x74, 0xa8, 0x73, 0x5b, 0x82, 0x4d, 0xef, 0xef, 0x75, 0x3e, 0xa8, 0xd2, 0x35, + 0xdd, 0x38, 0x34, 0xa3, 0x84, 0x7a, 0x6b, 0xe2, 0x22, 0xec, 0x40, 0x8c, 0xa9, 0x82, 0x5f, 0xd9, 0x64, 0xc2, 0x46, + 0x59, 0x6a, 0x0a, 0xe1, 0x91, 0x8c, 0x1e, 0x0b, 0x5e, 0x43, 0x4f, 0xfa, 0xfa, 0x4f, 0xe0, 0x43, 0x2f, 0x82, 0x2c, + 0xf1, 0x01, 0x09, 0x9e, 0xa9, 0x19, 0x4c, 0xd4, 0x63, 0x19, 0x44, 0xfc, 0x2b, 0x90, 0x1c, 0xbc, 0xa1, 0x1c, 0x87, + 0xc6, 0xef, 0x9f, 0x62, 0x5f, 0xc4, 0xd2, 0xaa, 0x65, 0x3b, 0x2a, 0xda, 0x76, 0x7c, 0xd7, 0xde, 0x0f, 0x1d, 0xcf, + 0xcd, 0x75, 0x0b, 0x7c, 0xb7, 0x3e, 0xed, 0x7b, 0xe8, 0xb1, 0x55, 0x1b, 0x5a, 0x2d, 0xa3, 0xc7, 0xb4, 0x6b, 0x79, + 0xaf, 0x3c, 0xdd, 0x22, 0x93, 0x39, 0x05, 0xb7, 0x8d, 0xe2, 0x3b, 0x96, 0x7c, 0xf1, 0x54, 0xca, 0x9d, 0xef, 0x37, + 0x9e, 0x23, 0xcf, 0x05, 0x24, 0x9c, 0xc5, 0x8b, 0x47, 0x4c, 0xa1, 0xad, 0x5b, 0xfa, 0x28, 0x8c, 0x53, 0xa6, 0xce, + 0x81, 0x84, 0x20, 0x5f, 0x38, 0x89, 0x9f, 0xdf, 0xbf, 0xfd, 0xf0, 0x41, 0xb7, 0x30, 0x13, 0x68, 0xaa, 0xf6, 0xce, + 0x37, 0xd4, 0x0e, 0xec, 0xdf, 0xb8, 0xef, 0xe8, 0x86, 0x21, 0xa6, 0xb6, 0xbc, 0xe7, 0xa8, 0xac, 0xb6, 0xe5, 0xf8, + 0xcd, 0xc3, 0xbf, 0x4c, 0x9c, 0xe8, 0x5e, 0xf3, 0x6a, 0xc0, 0x0d, 0xdb, 0xaf, 0xb7, 0x52, 0xc9, 0x3c, 0x88, 0x6e, + 0x1b, 0x4a, 0xfd, 0x55, 0x43, 0x29, 0xb0, 0x72, 0x35, 0x5c, 0xb5, 0x8c, 0xe7, 0x0a, 0x69, 0x00, 0x89, 0x9c, 0x77, + 0x81, 0x4b, 0xe1, 0xa7, 0xbe, 0x60, 0xd0, 0x3c, 0x92, 0x7b, 0x75, 0xd4, 0x0d, 0xc5, 0x9c, 0x09, 0x92, 0xb0, 0x1d, + 0x85, 0x60, 0xf0, 0xc7, 0x54, 0xad, 0x5c, 0x99, 0x6c, 0x94, 0xe6, 0xba, 0x4a, 0x27, 0x44, 0xde, 0xde, 0x66, 0x6c, + 0xbe, 0x60, 0x89, 0x9f, 0x2d, 0x13, 0x76, 0x1b, 0xc6, 0xf7, 0x4f, 0x0a, 0x73, 0xfa, 0x1d, 0x95, 0x67, 0xc1, 0x74, + 0x26, 0x6b, 0x9f, 0x1b, 0xac, 0x2f, 0x17, 0x70, 0xeb, 0x07, 0xf2, 0xff, 0xfc, 0xdb, 0x71, 0xfe, 0xf3, 0xef, 0x9d, + 0x55, 0xa1, 0xfb, 0x7c, 0x60, 0x65, 0xfd, 0x3d, 0xf6, 0x45, 0xf3, 0x97, 0xca, 0x30, 0x6f, 0xae, 0x53, 0x5b, 0x04, + 0x78, 0x5f, 0x5b, 0x82, 0x5a, 0x61, 0x79, 0xdf, 0x3c, 0x6a, 0x60, 0x30, 0xaf, 0x9d, 0x23, 0x83, 0x4a, 0x5f, 0x34, + 0xb4, 0x81, 0xd9, 0xdd, 0x6b, 0x45, 0x7e, 0x3f, 0x84, 0x77, 0xcd, 0xe1, 0x0b, 0x87, 0xcf, 0xe5, 0x92, 0xaf, 0x07, + 0x03, 0x99, 0x5b, 0x4e, 0x6d, 0x0a, 0x26, 0xfe, 0xe7, 0xb5, 0x12, 0x7e, 0x79, 0x76, 0x5d, 0x93, 0x7c, 0xef, 0xfb, + 0xaf, 0x07, 0x68, 0x8c, 0x76, 0x3a, 0x4c, 0x0a, 0x62, 0x65, 0x23, 0x6a, 0x23, 0x63, 0xf2, 0x5a, 0xa7, 0x35, 0xbc, + 0x06, 0xa5, 0x98, 0x70, 0x2c, 0x1f, 0x98, 0xd6, 0xeb, 0x01, 0x17, 0x2c, 0x71, 0xfb, 0xd7, 0x6e, 0x75, 0x6b, 0x73, + 0xb1, 0x6c, 0x09, 0xe8, 0x96, 0x46, 0xfa, 0x1f, 0xac, 0xcc, 0x0a, 0x39, 0x1e, 0x0a, 0xf8, 0x41, 0xa2, 0x30, 0xc8, + 0x31, 0xdf, 0xc9, 0xbb, 0x4d, 0x36, 0x62, 0x3f, 0xef, 0xb6, 0x11, 0xbb, 0xda, 0xcb, 0x46, 0xec, 0xe7, 0xaf, 0x6e, + 0x23, 0xf6, 0x4e, 0xb5, 0x11, 0x83, 0x45, 0x7c, 0xcb, 0xf6, 0x32, 0xdc, 0x12, 0x56, 0x1b, 0xf1, 0x7d, 0xda, 0xf7, + 0x38, 0x49, 0x9b, 0x8e, 0x66, 0x0c, 0x64, 0x04, 0x7c, 0x55, 0xc2, 0x78, 0x0a, 0x46, 0x5c, 0x7f, 0xbc, 0xb9, 0x55, + 0x18, 0x4f, 0x55, 0x63, 0xab, 0x88, 0x47, 0x7c, 0x2d, 0xa2, 0x38, 0x91, 0x81, 0x93, 0x6b, 0x89, 0x98, 0x4f, 0xf6, + 0xa1, 0xa9, 0x64, 0xb5, 0x96, 0xd6, 0x6b, 0x2d, 0x61, 0x02, 0xd5, 0x45, 0xeb, 0x29, 0xd9, 0xb0, 0xf5, 0x52, 0xc4, + 0xb6, 0x50, 0x7b, 0x90, 0x56, 0xc2, 0x14, 0x27, 0x62, 0xad, 0xff, 0xba, 0xf2, 0xbe, 0xbf, 0xf6, 0x7a, 0x6d, 0x0f, + 0x9c, 0xb3, 0x81, 0xc3, 0xc4, 0x02, 0xb7, 0xd7, 0x6e, 0x43, 0xc1, 0xbd, 0x52, 0xd0, 0x82, 0x82, 0x40, 0x29, 0xe8, + 0x40, 0xc1, 0x48, 0x29, 0x38, 0x82, 0x82, 0xb1, 0x52, 0x70, 0x0c, 0x05, 0x77, 0x7a, 0x7e, 0x1d, 0xc9, 0xe1, 0x1e, + 0x9b, 0x37, 0x16, 0x31, 0x15, 0xa2, 0xec, 0xd8, 0xf2, 0xc0, 0x6a, 0xca, 0x9f, 0x76, 0x63, 0x8b, 0xa4, 0x8b, 0xdd, + 0xc4, 0xba, 0x9f, 0x31, 0x0a, 0x14, 0xfd, 0x06, 0xef, 0x1c, 0x27, 0x8b, 0xc1, 0x6e, 0x5a, 0x04, 0x60, 0x10, 0x70, + 0xd0, 0x74, 0x13, 0x04, 0x46, 0x3d, 0xb9, 0x72, 0x22, 0x88, 0x85, 0xb2, 0x96, 0xc5, 0x3b, 0xfa, 0x9c, 0x2d, 0xb7, + 0x40, 0x61, 0x71, 0x62, 0xa8, 0x52, 0xc9, 0xaf, 0x61, 0x77, 0xf0, 0x86, 0x0d, 0x97, 0x53, 0xed, 0x32, 0x9e, 0xee, + 0x34, 0x21, 0x50, 0x5f, 0xc1, 0x28, 0x75, 0x52, 0xbf, 0xd8, 0x62, 0x5b, 0xf2, 0x6f, 0xd1, 0x63, 0x5e, 0xae, 0x9f, + 0xc1, 0xd8, 0xb4, 0x8c, 0x0c, 0x58, 0xe0, 0x3b, 0x00, 0x23, 0x45, 0x87, 0x7f, 0x09, 0x70, 0x56, 0x9e, 0xaf, 0x7c, + 0x65, 0x3c, 0x67, 0x3f, 0xb2, 0x34, 0xf5, 0xa7, 0xa2, 0x7e, 0x7d, 0x9c, 0x60, 0xb4, 0x23, 0xf9, 0x2f, 0x04, 0x20, + 0x48, 0xf2, 0x82, 0x9a, 0x6d, 0x46, 0x12, 0xdf, 0x6b, 0x60, 0xfd, 0x03, 0x1b, 0xaa, 0xb0, 0x53, 0x08, 0x1c, 0x58, + 0xc2, 0xb2, 0x45, 0x01, 0x1c, 0xfe, 0x3b, 0x16, 0x56, 0x0b, 0x33, 0x7f, 0x5a, 0x2d, 0xa2, 0x7d, 0x90, 0xab, 0x63, + 0x93, 0x0a, 0xfd, 0x52, 0xe1, 0x97, 0x68, 0xa8, 0xc3, 0x78, 0xfa, 0x87, 0xaa, 0xa7, 0xb7, 0x98, 0x15, 0x7c, 0x88, + 0xac, 0x20, 0x1b, 0x38, 0x08, 0x63, 0xcd, 0x01, 0x10, 0x76, 0xa3, 0x6c, 0x66, 0xa3, 0x6b, 0x99, 0xd1, 0x8a, 0x4c, + 0xcb, 0xc1, 0xb5, 0x5d, 0x57, 0x1d, 0x6a, 0xbb, 0xc9, 0x74, 0xe8, 0x1b, 0x5e, 0xeb, 0xd8, 0x12, 0x7f, 0x8e, 0xdb, + 0x31, 0x73, 0xec, 0x41, 0x1b, 0x07, 0x77, 0xeb, 0x49, 0x1c, 0x65, 0xf6, 0xc4, 0x9f, 0x07, 0xe1, 0x43, 0x77, 0x1e, + 0x47, 0x71, 0xba, 0xf0, 0x47, 0xac, 0x57, 0x30, 0xd4, 0x3d, 0x0c, 0xd5, 0xc0, 0xbd, 0x05, 0x3d, 0xa7, 0x95, 0xb0, + 0x39, 0xb5, 0x96, 0x91, 0x18, 0x26, 0x21, 0x5b, 0xe5, 0xfc, 0xf3, 0xa5, 0xca, 0x54, 0x15, 0xb7, 0x1c, 0xb5, 0x00, + 0x8a, 0x94, 0x87, 0x79, 0x80, 0xe0, 0x46, 0xbd, 0x85, 0x3f, 0xc6, 0xc8, 0x84, 0x4e, 0xab, 0x93, 0xb0, 0xb9, 0xe6, + 0x74, 0x36, 0x76, 0x9e, 0xc4, 0xf7, 0x67, 0x30, 0x5a, 0x6c, 0x6c, 0xa7, 0x2c, 0x9c, 0xe0, 0x1b, 0x1b, 0x3d, 0x4b, + 0x44, 0x3f, 0x36, 0x32, 0xe2, 0xd0, 0x1b, 0x9b, 0xf7, 0xe0, 0x75, 0xb7, 0xa5, 0xb9, 0xbd, 0x79, 0x10, 0xd9, 0x34, + 0x9d, 0x63, 0x77, 0xa1, 0xf4, 0xa5, 0xc2, 0xcf, 0x5c, 0x63, 0x75, 0x4f, 0x73, 0x7b, 0xc0, 0xac, 0x4d, 0xc2, 0xf8, + 0xbe, 0x3b, 0x0b, 0xc6, 0x63, 0x16, 0xf5, 0x70, 0xcc, 0xb2, 0x90, 0x85, 0x61, 0xb0, 0x48, 0x83, 0xb4, 0x37, 0xf7, + 0x57, 0xbc, 0xd7, 0xc3, 0x4d, 0xbd, 0xb6, 0x79, 0xaf, 0xed, 0xbd, 0x7b, 0x55, 0xba, 0x01, 0x2f, 0x16, 0xea, 0x87, + 0x0f, 0xad, 0xa3, 0xb9, 0x95, 0x79, 0xee, 0xdd, 0xeb, 0x22, 0x61, 0xeb, 0xb9, 0x9f, 0x4c, 0x83, 0xa8, 0xeb, 0xe6, + 0xce, 0xdd, 0x9a, 0x36, 0xc6, 0xd3, 0x93, 0x93, 0x93, 0xdc, 0x19, 0x8b, 0x27, 0x77, 0x3c, 0xce, 0x9d, 0x91, 0x78, + 0x9a, 0x4c, 0x5c, 0x77, 0x32, 0xc9, 0x9d, 0x40, 0x14, 0xb4, 0x5b, 0xa3, 0x71, 0xbb, 0x95, 0x3b, 0xf7, 0x4a, 0x8d, + 0xdc, 0x61, 0xfc, 0x29, 0x61, 0xe3, 0x1e, 0x6e, 0x24, 0x32, 0x2b, 0xed, 0x1e, 0xbb, 0x6e, 0x8e, 0x18, 0xe0, 0xba, + 0x84, 0x9b, 0x50, 0xd6, 0x73, 0xb3, 0xde, 0xbb, 0xa6, 0x56, 0x7c, 0x6e, 0x34, 0x6a, 0xac, 0x37, 0xf6, 0x93, 0x4f, + 0x37, 0x9a, 0x32, 0x0b, 0xdf, 0xa7, 0x6a, 0x6b, 0x01, 0x06, 0x7b, 0xd5, 0x85, 0x90, 0x5d, 0xbd, 0x61, 0x9c, 0xc0, + 0x99, 0x4d, 0xfc, 0x71, 0xb0, 0x4c, 0xbb, 0x5e, 0x6b, 0xb1, 0x12, 0x45, 0x7c, 0xaf, 0x17, 0x05, 0x78, 0xf6, 0xba, + 0x69, 0x1c, 0x06, 0x63, 0x51, 0xb4, 0xe9, 0x2c, 0x79, 0x2d, 0xb3, 0x87, 0x0e, 0xeb, 0x01, 0x86, 0x5d, 0xf0, 0xc3, + 0x50, 0x73, 0xda, 0xa9, 0xc6, 0xfc, 0x14, 0xe5, 0xcb, 0x9a, 0x9b, 0x12, 0x5c, 0xd0, 0x39, 0xdd, 0x3b, 0x5c, 0xac, + 0xe4, 0x9e, 0xf7, 0x8e, 0x16, 0xab, 0xfc, 0xdb, 0x39, 0x1b, 0x07, 0xbe, 0x66, 0x14, 0xbb, 0xc9, 0x73, 0x41, 0x06, + 0x6d, 0xae, 0x37, 0x6c, 0x53, 0x71, 0x2c, 0x20, 0xb4, 0xe1, 0x93, 0x60, 0xbe, 0x88, 0x93, 0xcc, 0x8f, 0xb2, 0x3c, + 0x1f, 0xdc, 0xe4, 0x79, 0xef, 0x2a, 0x30, 0xae, 0xff, 0x61, 0xd0, 0x3d, 0x4d, 0x3a, 0x9b, 0xdc, 0xbc, 0xb1, 0xde, + 0x32, 0xd5, 0x66, 0x04, 0xae, 0x31, 0xb4, 0x17, 0x51, 0x2b, 0xd3, 0x2d, 0x59, 0xaf, 0x4c, 0x40, 0x96, 0xd5, 0xc9, + 0x06, 0xa5, 0x5c, 0x05, 0x6f, 0x20, 0xa8, 0xf0, 0x96, 0xf5, 0xaf, 0x14, 0xfb, 0x13, 0x20, 0x56, 0xb0, 0x32, 0xf9, + 0x15, 0x3c, 0xdb, 0x44, 0x33, 0x7e, 0xb7, 0x9b, 0x66, 0xfc, 0x25, 0xdb, 0x87, 0x66, 0xfc, 0xee, 0xab, 0xd3, 0x8c, + 0xcf, 0xea, 0x7e, 0x05, 0x17, 0x71, 0x5f, 0x97, 0x1a, 0x06, 0xb8, 0x9a, 0x12, 0x8a, 0xd8, 0x73, 0xf1, 0xbb, 0xdd, + 0x00, 0x44, 0x6f, 0x94, 0x83, 0x8e, 0x6e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0xfa, 0x7f, 0x4f, 0xd4, 0xe7, 0xc9, 0xa4, + 0xff, 0x26, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0xbe, 0x28, 0x45, 0x57, 0xa0, 0x37, 0xc2, 0x0a, 0x13, 0xf3, 0x4f, 0x80, + 0x73, 0x36, 0x59, 0x1d, 0x8f, 0xa5, 0xf5, 0x59, 0xaf, 0x3c, 0x04, 0x43, 0x9a, 0x7c, 0x0a, 0x17, 0x9c, 0x9a, 0x28, + 0x71, 0xca, 0x32, 0xee, 0x33, 0xfb, 0xfd, 0xc3, 0xc5, 0xd8, 0xb8, 0x88, 0xcd, 0x3c, 0x48, 0xdf, 0x55, 0x1d, 0x60, + 0xb8, 0xee, 0xa7, 0xaf, 0x4e, 0x27, 0xe7, 0x16, 0x64, 0x6a, 0x82, 0x69, 0x78, 0x4d, 0xcd, 0xcf, 0x4b, 0x33, 0xed, + 0xaa, 0x0d, 0x79, 0xa2, 0xab, 0xda, 0x65, 0xcc, 0xbd, 0x0f, 0xd6, 0x9c, 0x02, 0xc4, 0xdc, 0x5d, 0xe8, 0x37, 0x3c, + 0xa6, 0xe6, 0xc1, 0x38, 0xcf, 0xcd, 0x9e, 0x00, 0x84, 0x72, 0xd1, 0xb2, 0x5d, 0x44, 0x5c, 0x7a, 0x2f, 0x6d, 0x1a, + 0xb8, 0x86, 0x90, 0xd4, 0x7f, 0x17, 0xa0, 0x50, 0xe7, 0xca, 0x42, 0x0e, 0x33, 0x5d, 0x23, 0xf0, 0x91, 0xa1, 0x85, + 0x32, 0x21, 0xd0, 0x00, 0x4b, 0xf8, 0x8b, 0x57, 0xa2, 0xa0, 0x6e, 0xc3, 0x49, 0xc0, 0x41, 0x8b, 0x00, 0xf0, 0xf2, + 0x17, 0x72, 0x6d, 0x42, 0x3b, 0xbc, 0x0e, 0x3e, 0xe4, 0xba, 0xa4, 0xfd, 0x70, 0xfb, 0x9d, 0x9d, 0x1e, 0x40, 0x83, + 0xb3, 0x8a, 0xe1, 0xc0, 0x0e, 0x0b, 0x45, 0x20, 0x25, 0xd2, 0x7b, 0xcb, 0x49, 0xef, 0xb5, 0x17, 0x6b, 0x11, 0x21, + 0x23, 0xf3, 0x17, 0x36, 0xb0, 0xf8, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x82, 0x71, 0xf4, 0x96, 0x29, 0xe0, 0x46, 0x64, + 0x54, 0x11, 0xff, 0xf4, 0x46, 0xcb, 0x24, 0x8d, 0x93, 0xee, 0x22, 0x0e, 0xa2, 0x8c, 0x25, 0x39, 0x82, 0xea, 0x1a, + 0xe1, 0x23, 0xc0, 0x73, 0xb3, 0x8e, 0x17, 0xfe, 0x28, 0xc8, 0x1e, 0xba, 0x2e, 0x27, 0x29, 0xdc, 0x1e, 0xa7, 0x0e, + 0xdc, 0xc6, 0xfa, 0x5d, 0x0e, 0xcd, 0x97, 0x48, 0xf8, 0x25, 0x75, 0x72, 0x46, 0xdd, 0xe6, 0x3d, 0xe5, 0x2d, 0xc5, + 0x08, 0x01, 0xf2, 0xc3, 0x4f, 0xec, 0x29, 0x60, 0x79, 0x58, 0x6a, 0x77, 0xcc, 0xa6, 0x16, 0x62, 0x6d, 0x90, 0xcb, + 0x8b, 0x3f, 0xa7, 0x63, 0x6a, 0x6e, 0x73, 0x31, 0x50, 0x3c, 0xe6, 0x3e, 0x23, 0xeb, 0xfa, 0x90, 0x51, 0xcb, 0xda, + 0xa7, 0xe6, 0x90, 0x4d, 0xe2, 0x84, 0x51, 0x3c, 0x59, 0xef, 0x64, 0xb1, 0xda, 0xbf, 0xfb, 0xed, 0xd3, 0x6f, 0xee, + 0x27, 0x8a, 0x33, 0x43, 0x74, 0x66, 0xee, 0xe8, 0xad, 0x7e, 0x9f, 0x01, 0x69, 0x48, 0x90, 0x1f, 0x51, 0xe8, 0xae, + 0xae, 0xae, 0xf7, 0x1a, 0xc3, 0x76, 0x2d, 0x62, 0x7e, 0xe7, 0x25, 0x2c, 0xf4, 0xb3, 0xe0, 0x4e, 0xd0, 0x8c, 0xed, + 0xa3, 0xc5, 0x4a, 0xac, 0x31, 0x5e, 0x78, 0x8f, 0x58, 0xa4, 0xca, 0x50, 0xc4, 0x22, 0x55, 0x8b, 0x71, 0x91, 0x7a, + 0xb5, 0xd9, 0x88, 0x48, 0x16, 0x95, 0x9b, 0xbe, 0xb3, 0x58, 0xa9, 0x57, 0x74, 0xd1, 0x4c, 0xde, 0xd4, 0xd5, 0x10, + 0x64, 0xf3, 0x60, 0x3c, 0x0e, 0x59, 0x5e, 0x5a, 0xe8, 0xf2, 0x5a, 0x2a, 0xc0, 0x91, 0x70, 0xf0, 0x87, 0x69, 0x1c, + 0x2e, 0x33, 0xd6, 0x0c, 0x2e, 0x02, 0x4e, 0xcb, 0x2d, 0x80, 0x83, 0xbf, 0xcb, 0x63, 0xed, 0x00, 0xb9, 0x0d, 0xdb, + 0xc4, 0xed, 0x41, 0xc4, 0x61, 0xbb, 0x5d, 0x1e, 0x3a, 0xbc, 0x92, 0x83, 0xb6, 0x1a, 0x26, 0x62, 0xc1, 0xb5, 0x44, + 0xd8, 0x5b, 0x73, 0x3c, 0x5e, 0x26, 0xa3, 0xae, 0xca, 0xa2, 0xbc, 0x3c, 0x99, 0x3f, 0xe6, 0x8c, 0xbd, 0x6a, 0x3e, + 0x63, 0xaf, 0xc4, 0x19, 0xdb, 0xbe, 0x33, 0x9f, 0x4e, 0x3c, 0xf8, 0xaf, 0x57, 0x4c, 0xa8, 0xeb, 0x6a, 0xed, 0xc5, + 0x4a, 0xf3, 0x16, 0x2b, 0xcd, 0x6e, 0x2d, 0x56, 0x1a, 0x76, 0x8d, 0xf6, 0x20, 0x96, 0xd3, 0x32, 0x2d, 0x57, 0x83, + 0x42, 0xf8, 0x73, 0x4b, 0xaf, 0xbc, 0x43, 0x78, 0x07, 0xad, 0x3a, 0xf5, 0x77, 0xad, 0xed, 0x47, 0x9d, 0xce, 0x92, + 0x40, 0xda, 0xa6, 0x93, 0xf9, 0xc3, 0x21, 0x1b, 0x77, 0x27, 0xf1, 0x68, 0x99, 0xfe, 0x8b, 0x8f, 0x9f, 0x03, 0x71, + 0x2b, 0x22, 0xa8, 0xf4, 0x23, 0x9a, 0x82, 0xa2, 0xe4, 0x8e, 0x89, 0x1e, 0xd6, 0x72, 0x9d, 0xba, 0x14, 0x1e, 0xb9, + 0xe5, 0x1c, 0x36, 0x6c, 0xf2, 0x66, 0x40, 0xff, 0x61, 0xab, 0xb4, 0x19, 0xc5, 0x7c, 0x01, 0x58, 0xb6, 0x82, 0xe3, + 0xf1, 0xd0, 0xe0, 0xab, 0xe9, 0x9e, 0x34, 0x0f, 0xf7, 0x5a, 0x7c, 0xe9, 0x46, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0x8e, + 0x29, 0xdb, 0x7b, 0xdd, 0xb4, 0x47, 0x6a, 0xbd, 0x6e, 0xb9, 0x10, 0x8a, 0xba, 0x7b, 0x62, 0xf9, 0xa7, 0xaf, 0x0e, + 0xe1, 0x3f, 0xa2, 0xea, 0x7f, 0xc9, 0x9a, 0x08, 0xf5, 0x8b, 0xb2, 0x25, 0x38, 0x91, 0x4a, 0x48, 0x88, 0xef, 0x5f, + 0x7f, 0x32, 0x79, 0x5c, 0x83, 0xbd, 0x6b, 0x93, 0x29, 0x55, 0xb5, 0xf6, 0xf7, 0x71, 0x0c, 0xa9, 0x3b, 0xeb, 0xd5, + 0x05, 0x78, 0xc8, 0xd8, 0x3d, 0xeb, 0x43, 0x23, 0xc1, 0x47, 0x90, 0x16, 0x5f, 0xc7, 0x36, 0xc4, 0x4a, 0xbc, 0xdd, + 0xc4, 0x4a, 0xbc, 0xd9, 0xcd, 0x4a, 0xfc, 0x75, 0x2f, 0x56, 0xe2, 0xcd, 0x57, 0x67, 0x25, 0xde, 0xd6, 0x59, 0x89, + 0xab, 0x58, 0xd8, 0xcf, 0x5a, 0x17, 0x4b, 0xfe, 0xf3, 0x23, 0x29, 0xe5, 0x2e, 0xe3, 0x7e, 0xc7, 0xa5, 0x90, 0xc7, + 0x57, 0xbf, 0x9b, 0xb1, 0xc0, 0x8d, 0xf8, 0x1e, 0xcd, 0xc9, 0x0a, 0xd6, 0x82, 0x63, 0x76, 0xfc, 0x8e, 0x52, 0x1c, + 0xc6, 0xd1, 0xf4, 0x67, 0x50, 0xca, 0x82, 0x38, 0x30, 0x51, 0x5e, 0x04, 0xe9, 0xcf, 0xf1, 0x62, 0xb9, 0xb8, 0x80, + 0xbe, 0x3e, 0x06, 0x69, 0x30, 0x0c, 0x99, 0xf4, 0x44, 0x26, 0xf3, 0x37, 0x2e, 0x13, 0x07, 0x8b, 0x53, 0xf1, 0xd3, + 0x5f, 0x89, 0x9f, 0x68, 0x93, 0xca, 0x7f, 0x93, 0x5d, 0x9d, 0xde, 0xcc, 0x88, 0x08, 0x25, 0xa0, 0x32, 0xe8, 0xc7, + 0x33, 0x23, 0x57, 0xb1, 0xd9, 0x30, 0x4b, 0x61, 0xef, 0xb0, 0xb1, 0x1f, 0x56, 0x63, 0x6a, 0x96, 0xa6, 0x25, 0x43, + 0x70, 0xd5, 0xc5, 0xf0, 0xf3, 0x78, 0x99, 0xb2, 0x71, 0x7c, 0x1f, 0xe9, 0x56, 0x24, 0x9d, 0x0c, 0x40, 0xc3, 0x29, + 0xdb, 0x60, 0xf2, 0xc8, 0x0f, 0x48, 0x28, 0xc7, 0x89, 0xa1, 0x43, 0xee, 0xd2, 0xe5, 0xc2, 0x26, 0x55, 0xb3, 0x8d, + 0x53, 0xd4, 0x65, 0x96, 0xa3, 0x27, 0x86, 0x11, 0xf7, 0x1f, 0xd7, 0x52, 0x98, 0x6a, 0xc4, 0x0e, 0x97, 0x0a, 0xa7, + 0x46, 0x24, 0x84, 0x8b, 0x22, 0x0e, 0x46, 0xc3, 0xc2, 0xf1, 0x37, 0xe4, 0xba, 0x5a, 0xbc, 0x85, 0x28, 0x22, 0xf9, + 0x92, 0xaf, 0x07, 0x8f, 0x0a, 0x41, 0x8f, 0xaf, 0x15, 0x30, 0xbe, 0xbb, 0x63, 0x49, 0xe8, 0x3f, 0x18, 0x66, 0x1e, + 0x47, 0x3f, 0x02, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0x93, 0xb5, 0x34, 0xec, 0xa5, 0xc6, 0xf8, 0x25, 0xe0, + 0xb8, 0xa2, 0x8c, 0x00, 0xd2, 0xe4, 0x4e, 0xd9, 0xdf, 0x2d, 0xfa, 0xf7, 0x1f, 0x66, 0x6e, 0x5d, 0xc6, 0xf2, 0x43, + 0x7f, 0x5b, 0xec, 0xf1, 0x99, 0xe7, 0xcf, 0x9f, 0x6c, 0x9e, 0x76, 0x39, 0x3d, 0x7b, 0x43, 0x6b, 0x73, 0xe3, 0x29, + 0x80, 0x51, 0x5c, 0xc5, 0xcb, 0xd1, 0x0c, 0x0d, 0x5d, 0xbf, 0xde, 0x7c, 0x33, 0xe8, 0x13, 0xb3, 0x94, 0xca, 0xa9, + 0x57, 0x8a, 0x0a, 0x28, 0xe0, 0xf7, 0xdf, 0x42, 0x00, 0xce, 0xff, 0x21, 0x18, 0xea, 0xbb, 0x86, 0x73, 0xf1, 0xc1, + 0xe3, 0x36, 0x6f, 0x0f, 0x92, 0x69, 0xf2, 0xd0, 0x16, 0x42, 0xb9, 0xd6, 0x8c, 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0x30, + 0x72, 0x9b, 0x22, 0xe4, 0x89, 0xaf, 0x30, 0x87, 0xd8, 0x74, 0xee, 0x68, 0x60, 0x31, 0x8e, 0xad, 0x2a, 0x48, 0x86, + 0x9b, 0x3c, 0x30, 0x44, 0x5f, 0xd5, 0x77, 0xf3, 0x20, 0xb2, 0x30, 0x0a, 0x7c, 0xfd, 0x8d, 0xbf, 0x82, 0x38, 0xc8, + 0x80, 0xdc, 0xaa, 0xaf, 0xa0, 0xd0, 0x52, 0xfd, 0xe6, 0x20, 0xd5, 0x93, 0xde, 0x08, 0x09, 0xa1, 0xc5, 0x1b, 0xfc, + 0x49, 0xd3, 0x34, 0x4d, 0xb2, 0x11, 0x9a, 0xe4, 0x23, 0xb0, 0x1c, 0xd9, 0x01, 0xd0, 0x96, 0xe4, 0x8b, 0x15, 0x95, + 0x00, 0x67, 0x80, 0x3a, 0x59, 0x51, 0xc0, 0x43, 0xfd, 0x75, 0x5c, 0x51, 0x20, 0x18, 0x7a, 0x08, 0xd3, 0xe6, 0x27, + 0x10, 0x11, 0xb8, 0xab, 0x21, 0xc3, 0x8e, 0x6f, 0xb9, 0x24, 0x58, 0x73, 0xe9, 0x71, 0xd0, 0x63, 0xcd, 0x31, 0xe1, + 0x22, 0x05, 0x0b, 0x82, 0xd6, 0xa1, 0x12, 0xe2, 0xd9, 0x62, 0x0d, 0xb8, 0x11, 0xf9, 0xa2, 0x55, 0x36, 0x67, 0xd1, + 0x52, 0xc7, 0x9c, 0x50, 0x18, 0xa3, 0x0f, 0xea, 0xbc, 0x21, 0x62, 0x0b, 0xb0, 0x4d, 0x73, 0xcb, 0x19, 0xdd, 0x85, + 0x29, 0x47, 0xa9, 0xbe, 0x35, 0xe2, 0x8a, 0xcd, 0x94, 0xe3, 0xb6, 0xea, 0x0d, 0xc1, 0x97, 0x34, 0xae, 0x3a, 0x72, + 0x91, 0x25, 0x34, 0xf4, 0x41, 0xd1, 0x31, 0xb8, 0xb8, 0x48, 0x80, 0xdd, 0xf0, 0xab, 0x8b, 0x26, 0x35, 0x32, 0x7e, + 0x45, 0x50, 0x94, 0x98, 0xf5, 0x6e, 0xf8, 0x38, 0x21, 0x30, 0xd1, 0xc6, 0x7e, 0x46, 0xb5, 0x7e, 0x36, 0x4c, 0xfa, + 0x13, 0x7b, 0xa0, 0x8b, 0x84, 0x40, 0xf5, 0x89, 0x3d, 0x80, 0xed, 0xdf, 0x5b, 0x90, 0xa6, 0xe8, 0x5b, 0xd0, 0xb5, + 0x05, 0xa1, 0xfe, 0x47, 0x10, 0xac, 0x6a, 0xcb, 0x01, 0x72, 0xf3, 0x2d, 0x58, 0x1c, 0x41, 0x0c, 0x59, 0x9d, 0xc5, + 0x21, 0xe6, 0x26, 0xfe, 0x46, 0x23, 0x8c, 0xed, 0x86, 0xa3, 0x61, 0xbe, 0xf0, 0x5c, 0xf7, 0xa0, 0x56, 0x1f, 0x04, + 0xd9, 0x4d, 0xb5, 0x4d, 0x2b, 0xeb, 0x7b, 0xae, 0x1d, 0xbc, 0x70, 0x5a, 0xbd, 0xda, 0x1d, 0xad, 0xc4, 0x92, 0x1c, + 0xa0, 0xf8, 0xeb, 0xec, 0xd9, 0xda, 0xa8, 0x1d, 0x48, 0xb3, 0x6a, 0x32, 0x8f, 0x63, 0xcb, 0xb9, 0xfc, 0x6b, 0x50, + 0xbf, 0xfa, 0x29, 0x92, 0x25, 0xe5, 0x35, 0x19, 0x40, 0x34, 0x64, 0x03, 0x8e, 0xd1, 0x9f, 0xb5, 0x97, 0x9a, 0x41, + 0xc7, 0xc7, 0x34, 0x07, 0x32, 0x5d, 0xb6, 0xf0, 0x29, 0x53, 0x3b, 0xa8, 0x7c, 0x31, 0xad, 0x62, 0x38, 0x1e, 0x77, + 0x95, 0x15, 0x1a, 0xbd, 0xad, 0xd4, 0x02, 0xf6, 0xbf, 0xe1, 0xfa, 0x74, 0x86, 0x10, 0x97, 0x00, 0x6a, 0x40, 0xec, + 0xf4, 0x9d, 0x1d, 0x2e, 0x17, 0xe5, 0xee, 0xca, 0x97, 0xe4, 0xfe, 0x9d, 0xe1, 0xa5, 0x83, 0x3a, 0x34, 0xd9, 0x5f, + 0xf3, 0x75, 0xf7, 0xc8, 0x2e, 0x59, 0x34, 0x2e, 0x77, 0x58, 0xb9, 0xbf, 0xf6, 0xef, 0xae, 0x84, 0x51, 0x20, 0xa9, + 0x40, 0xdc, 0x80, 0x51, 0xf2, 0x38, 0xc2, 0xcd, 0x4f, 0xc7, 0x2d, 0xd8, 0x8b, 0x8a, 0xc1, 0x06, 0x14, 0x11, 0x4c, + 0x36, 0x53, 0x84, 0xe2, 0x10, 0xb9, 0x1a, 0xdd, 0x82, 0x0d, 0x41, 0x88, 0x6e, 0xdc, 0x89, 0x99, 0xb0, 0x29, 0x2c, + 0xda, 0x04, 0x3c, 0x16, 0xe5, 0xbe, 0x52, 0xeb, 0x60, 0xb7, 0xd4, 0x3a, 0xdb, 0x25, 0xb5, 0x26, 0x77, 0xaa, 0xfb, + 0xc4, 0x5f, 0x28, 0x1e, 0x79, 0x82, 0x38, 0x57, 0x1d, 0xf3, 0x4a, 0xa2, 0x6e, 0xf4, 0xbe, 0x12, 0xad, 0x6a, 0xbd, + 0x91, 0x95, 0x20, 0x8a, 0xbf, 0x15, 0x06, 0x45, 0x28, 0xd4, 0x55, 0xd9, 0xf8, 0x55, 0x21, 0x1b, 0x27, 0xae, 0xa6, + 0x70, 0xa4, 0x11, 0xd4, 0xbf, 0xe2, 0xa4, 0x26, 0xb9, 0x83, 0xc2, 0x59, 0xad, 0x18, 0xa9, 0xe2, 0x7e, 0x55, 0x30, + 0x1a, 0x8a, 0x53, 0x9f, 0xe0, 0x32, 0xca, 0xbe, 0x7d, 0xe5, 0xaa, 0x85, 0xf7, 0x55, 0x51, 0x0e, 0x52, 0x77, 0x1c, + 0xb2, 0x2c, 0x56, 0xb7, 0x4d, 0xd9, 0xfd, 0x46, 0x7d, 0xad, 0x6c, 0x12, 0xe9, 0x27, 0x43, 0x00, 0x16, 0x62, 0xfa, + 0x8a, 0x5e, 0x5b, 0xda, 0x40, 0xe0, 0x20, 0x1b, 0xdc, 0xfa, 0x76, 0x4b, 0xe7, 0x29, 0x5f, 0x42, 0xa1, 0x85, 0x57, + 0x65, 0x10, 0x08, 0xdf, 0x9b, 0x75, 0xc3, 0x2d, 0x8f, 0x97, 0x3c, 0xbf, 0xdf, 0x41, 0xbc, 0xa8, 0xb9, 0xaa, 0x22, + 0x1f, 0x4f, 0xa6, 0x4d, 0xe6, 0xb9, 0x58, 0xb5, 0xde, 0x29, 0x09, 0x71, 0xd6, 0xdc, 0x33, 0xa6, 0x2c, 0xa3, 0xe7, + 0x35, 0xba, 0xe2, 0xbb, 0x7c, 0xeb, 0x24, 0xcb, 0x08, 0x63, 0xdb, 0xdb, 0x59, 0xe2, 0x8f, 0x3e, 0x29, 0x43, 0x16, + 0x72, 0x4e, 0x90, 0x01, 0x97, 0x35, 0x05, 0x3d, 0x1f, 0x43, 0x41, 0xb2, 0xae, 0xd3, 0x4a, 0x15, 0xe9, 0x4b, 0xf7, + 0xa9, 0xdb, 0xf6, 0x5f, 0x4d, 0x0e, 0x2b, 0x42, 0xd1, 0x56, 0xa7, 0x2c, 0x32, 0xdf, 0x30, 0x8e, 0x6c, 0xb6, 0x9c, + 0x0f, 0xd7, 0xaa, 0x6c, 0x55, 0x11, 0xb9, 0xd6, 0xc5, 0xac, 0xea, 0x67, 0x27, 0x93, 0x49, 0x59, 0xd0, 0xe8, 0x6a, + 0x87, 0x28, 0x2c, 0x7c, 0xea, 0xba, 0x6e, 0x75, 0xec, 0xdb, 0xc1, 0x6e, 0xa3, 0xdc, 0xf6, 0xa4, 0x71, 0xc4, 0x08, + 0xdb, 0x5d, 0xf0, 0xab, 0x83, 0x23, 0x77, 0x8a, 0x93, 0x5d, 0x32, 0x8b, 0xe8, 0x91, 0x31, 0x44, 0x90, 0xb1, 0x79, + 0xda, 0x1d, 0x31, 0xd4, 0xc1, 0x38, 0xca, 0x81, 0x46, 0xc3, 0x01, 0x7b, 0x0a, 0xa6, 0x22, 0x9e, 0xd8, 0x15, 0xae, + 0x86, 0xf2, 0xf0, 0x9a, 0xf0, 0x5e, 0x7c, 0x04, 0x0f, 0xca, 0xba, 0x2e, 0xd3, 0xc6, 0x69, 0x75, 0xdc, 0x3f, 0x97, + 0xea, 0x69, 0x70, 0x01, 0xae, 0x85, 0x42, 0x9b, 0xe4, 0xb3, 0xf8, 0xff, 0x52, 0xfe, 0xff, 0x6a, 0xb1, 0x2a, 0xdb, + 0x8f, 0x9c, 0x80, 0x44, 0xbb, 0x38, 0x2d, 0x34, 0xea, 0xa6, 0x3d, 0x20, 0xad, 0x0c, 0x26, 0xaa, 0x02, 0x1d, 0x94, + 0xf4, 0xa5, 0x04, 0x20, 0x0d, 0xe2, 0x77, 0xa4, 0x98, 0x61, 0x89, 0x0b, 0x11, 0x62, 0x91, 0xbe, 0x0e, 0xe6, 0x60, + 0xbd, 0x3c, 0x41, 0xfd, 0x41, 0x69, 0x4f, 0x80, 0x36, 0xbe, 0x36, 0xb7, 0xbd, 0xc4, 0xfd, 0x55, 0xbd, 0x96, 0xe8, + 0x18, 0x40, 0xe6, 0xc1, 0x21, 0x44, 0x43, 0x02, 0xad, 0xb2, 0xb9, 0x69, 0x94, 0xf2, 0xad, 0xaa, 0x67, 0x13, 0x03, + 0xc3, 0xee, 0x9a, 0xab, 0x50, 0xdf, 0x42, 0x5b, 0x00, 0x93, 0xe5, 0xdb, 0x0f, 0x9f, 0x6d, 0x58, 0x62, 0x75, 0x3f, + 0x7a, 0xb8, 0xe4, 0xb8, 0x7f, 0x6d, 0xbc, 0x3b, 0x53, 0x3a, 0xff, 0x28, 0x5f, 0xfc, 0x6b, 0xa3, 0x40, 0xef, 0xaa, + 0x24, 0xa1, 0xe3, 0xd6, 0xe2, 0x2d, 0x73, 0xaf, 0xda, 0xf3, 0x20, 0xda, 0xbf, 0xae, 0xbf, 0xda, 0xbb, 0x2e, 0x5c, + 0x18, 0x7b, 0x57, 0x86, 0x1b, 0x87, 0x2c, 0x17, 0xb2, 0xfe, 0x5f, 0x15, 0x81, 0xa2, 0xea, 0x75, 0xac, 0x63, 0x2b, + 0xa2, 0xf2, 0xaf, 0x96, 0x40, 0x7c, 0xee, 0x95, 0xe0, 0x41, 0x13, 0x39, 0xda, 0xf4, 0x63, 0xed, 0x44, 0x3b, 0x6e, + 0x6b, 0x47, 0xae, 0x4e, 0x5c, 0x58, 0x5f, 0xef, 0xb4, 0x0a, 0x6f, 0xc2, 0x43, 0x57, 0x3f, 0x3b, 0x9d, 0x8a, 0x4b, + 0x62, 0x12, 0x84, 0x21, 0xa1, 0x8a, 0x34, 0x4b, 0xe2, 0x4f, 0xac, 0xac, 0x66, 0xa1, 0x32, 0x6e, 0x04, 0xd2, 0x12, + 0x8f, 0x70, 0x76, 0x46, 0xfe, 0xa2, 0x8b, 0x67, 0x43, 0x2d, 0x04, 0x03, 0x4e, 0x2a, 0xc5, 0x4f, 0xc0, 0x1d, 0x3c, + 0xd4, 0xcf, 0x4e, 0x21, 0x84, 0xa1, 0x36, 0xee, 0xeb, 0x3f, 0xb6, 0x8e, 0x35, 0xaf, 0x73, 0x67, 0xb7, 0x47, 0xae, + 0xed, 0x39, 0x87, 0x9a, 0xeb, 0x1c, 0xd9, 0x2d, 0xe7, 0x58, 0x6b, 0x39, 0x1d, 0xf8, 0x77, 0xe4, 0x39, 0xaf, 0x34, + 0x17, 0x9e, 0x34, 0xcf, 0x69, 0xe3, 0xbf, 0x2d, 0xe7, 0xf8, 0xae, 0x4d, 0x37, 0xbd, 0x2f, 0xdd, 0xaa, 0x2a, 0xa3, + 0x00, 0x27, 0x10, 0xfd, 0xe0, 0xec, 0x74, 0x99, 0x32, 0x6d, 0xd5, 0xd7, 0x5f, 0xe9, 0xda, 0x2c, 0x61, 0x93, 0xbe, + 0xfe, 0xd4, 0x57, 0x4a, 0xbd, 0x93, 0xc6, 0xe2, 0xd6, 0x71, 0x63, 0x71, 0xfb, 0xa8, 0xb1, 0xf8, 0xb0, 0x53, 0x2e, + 0x3e, 0x98, 0xd2, 0x2b, 0x25, 0x83, 0xe0, 0xdc, 0xcf, 0x92, 0x60, 0x65, 0x78, 0x1a, 0xa0, 0x6b, 0x1b, 0xfe, 0x39, + 0x6e, 0x99, 0xb2, 0xd5, 0x10, 0x5a, 0x49, 0x68, 0x1c, 0x9f, 0x68, 0xde, 0xd1, 0x5f, 0x5a, 0x47, 0x23, 0xa8, 0x07, + 0xf9, 0x2e, 0xe1, 0xef, 0xae, 0x7d, 0x32, 0x72, 0x35, 0x68, 0xe8, 0xc1, 0x7f, 0xb3, 0x4e, 0x6b, 0x44, 0x0f, 0x2e, + 0xbc, 0xff, 0xe8, 0x1d, 0xa7, 0xae, 0xed, 0xc1, 0x7f, 0xbf, 0x49, 0x95, 0x3b, 0x28, 0xfc, 0xd5, 0x7e, 0x0f, 0x5d, + 0xad, 0x7d, 0x32, 0x6b, 0x39, 0xaf, 0xee, 0x8e, 0x9d, 0x93, 0x99, 0x77, 0xfc, 0x91, 0x9e, 0x42, 0xbb, 0xe5, 0xbc, + 0x82, 0xbf, 0x8f, 0x6d, 0x77, 0x66, 0x7b, 0xce, 0xc9, 0x5d, 0xdb, 0x69, 0x87, 0xf6, 0x91, 0x73, 0x02, 0x7f, 0xbf, + 0x01, 0x78, 0x01, 0xae, 0x3c, 0x41, 0xa9, 0x06, 0x1b, 0xa3, 0x62, 0xbf, 0xa1, 0x7e, 0xa4, 0x75, 0xa8, 0x75, 0x0e, + 0xff, 0x72, 0x72, 0x67, 0x1f, 0xce, 0xbc, 0xd6, 0x9d, 0xbd, 0xf1, 0xe7, 0x47, 0x80, 0xfc, 0xf6, 0x85, 0x03, 0x30, + 0x62, 0x46, 0x92, 0x3f, 0x0d, 0xac, 0xcb, 0x4d, 0x62, 0xf4, 0xf7, 0xbb, 0xc5, 0xe8, 0x3f, 0x2c, 0xf7, 0x11, 0xa3, + 0xbf, 0xff, 0xea, 0x62, 0xf4, 0xcb, 0xaa, 0x15, 0xf7, 0xfb, 0x6a, 0xe4, 0xf4, 0x5f, 0xd6, 0x55, 0x22, 0x39, 0xf0, + 0x8d, 0xeb, 0xab, 0xe5, 0x0d, 0xc4, 0xfe, 0x79, 0x1f, 0xf7, 0x7f, 0x58, 0x96, 0x4c, 0x94, 0x62, 0xc0, 0x00, 0xef, + 0x63, 0xc2, 0x00, 0xbf, 0x2d, 0xfb, 0x60, 0x17, 0xc1, 0x6f, 0xcd, 0x60, 0x6c, 0xcf, 0xfc, 0x70, 0x22, 0x6f, 0x5c, + 0x28, 0xe9, 0x61, 0x31, 0xd8, 0xcc, 0xc3, 0x65, 0x02, 0xca, 0x9a, 0xe5, 0x3c, 0x4a, 0xbb, 0x47, 0x2e, 0xa0, 0xf9, + 0xd6, 0x24, 0xc9, 0x2b, 0x8d, 0x1d, 0x11, 0x2d, 0xe9, 0x96, 0xdb, 0xf4, 0x6f, 0x7c, 0x8f, 0x26, 0x6b, 0xcd, 0xbd, + 0x7b, 0xf5, 0x7e, 0x35, 0xb0, 0x05, 0x11, 0x26, 0x7d, 0x40, 0x6c, 0x34, 0xbd, 0x2f, 0x1b, 0x8e, 0x55, 0x4c, 0x05, + 0x37, 0x8f, 0x14, 0x46, 0x52, 0x6d, 0xef, 0x95, 0x0d, 0xcf, 0x76, 0x4d, 0xb3, 0xe1, 0xf3, 0xa5, 0xe6, 0x5b, 0xac, + 0xde, 0x64, 0xc7, 0x55, 0x50, 0x55, 0xf2, 0x7e, 0x35, 0x02, 0xa4, 0xa0, 0x3d, 0x0b, 0xd3, 0xb8, 0x82, 0xf0, 0x71, + 0x35, 0xbc, 0x8d, 0x5d, 0xe5, 0x5d, 0xa9, 0x4f, 0xd5, 0x9c, 0xee, 0xc5, 0x1a, 0xe9, 0xc1, 0xe0, 0x37, 0x20, 0x6c, + 0xf8, 0x7d, 0x3c, 0x8c, 0x55, 0x38, 0xaf, 0x95, 0x7e, 0x89, 0xd4, 0xce, 0x67, 0xde, 0xba, 0x4e, 0xda, 0x6c, 0x34, + 0xa4, 0xf5, 0xd8, 0x5c, 0xdc, 0xd1, 0xf8, 0x79, 0x32, 0x5b, 0xcd, 0xc9, 0xb4, 0x18, 0x2d, 0x73, 0xb7, 0x75, 0x26, + 0xea, 0x3d, 0x85, 0x4d, 0x6c, 0xf1, 0x07, 0xd5, 0x6b, 0x7d, 0x3d, 0x81, 0x1c, 0xcd, 0x5d, 0x24, 0x22, 0x14, 0x0a, + 0xaa, 0x85, 0x36, 0xb6, 0xbd, 0x2d, 0xe6, 0x1f, 0x6a, 0xc7, 0xbc, 0x13, 0xb4, 0xd5, 0xdd, 0x66, 0x31, 0x22, 0x5d, + 0x1b, 0xd6, 0x25, 0x05, 0xaa, 0xd7, 0x39, 0xb6, 0xbc, 0x23, 0xcb, 0x39, 0xee, 0x98, 0xb9, 0x38, 0x70, 0x6a, 0x97, + 0x25, 0x80, 0x80, 0xc9, 0xae, 0x1c, 0x66, 0x10, 0x05, 0x59, 0xe0, 0x87, 0x39, 0xa0, 0xfa, 0x32, 0xcd, 0xfb, 0xcf, + 0x65, 0x9a, 0xc1, 0x1c, 0x05, 0x49, 0x86, 0xe6, 0xca, 0xf6, 0x90, 0x65, 0xf7, 0x8c, 0x45, 0x1b, 0x54, 0xb9, 0x55, + 0xeb, 0xe7, 0x3f, 0xce, 0x16, 0x34, 0x27, 0x3b, 0x8b, 0x61, 0x16, 0xf1, 0xfd, 0x21, 0x4c, 0x75, 0xf3, 0x81, 0xf5, + 0xd3, 0x26, 0x84, 0xfb, 0xcf, 0xdd, 0x08, 0x37, 0x63, 0xfb, 0x20, 0xdc, 0x7f, 0x7e, 0x75, 0x84, 0xfb, 0x93, 0x8a, + 0x70, 0x4b, 0x9e, 0x2a, 0x85, 0x4c, 0xf4, 0x03, 0x3e, 0x1b, 0x10, 0x72, 0xf8, 0xa5, 0x7e, 0x40, 0xe4, 0xa5, 0xae, + 0xa4, 0x82, 0xfd, 0x58, 0xca, 0x6d, 0x83, 0x2c, 0x3b, 0x86, 0x48, 0xa5, 0x3c, 0x1a, 0x90, 0x26, 0x55, 0x26, 0xfc, + 0x86, 0x3e, 0x2f, 0xa2, 0x2c, 0x74, 0xde, 0x73, 0xb6, 0x04, 0x54, 0x10, 0x3f, 0xc4, 0xc9, 0xdc, 0xc7, 0xf0, 0x70, + 0x3a, 0xe6, 0xc4, 0x83, 0x07, 0x17, 0xbc, 0xa3, 0x46, 0x71, 0x34, 0x96, 0x72, 0x74, 0xd6, 0xbf, 0x26, 0x7a, 0x50, + 0x7f, 0x60, 0x7e, 0xa2, 0x5b, 0xf4, 0x1a, 0x16, 0xf7, 0x45, 0xdb, 0x7d, 0xd1, 0x3a, 0x7c, 0x71, 0xe4, 0xc2, 0xff, + 0x3c, 0xd6, 0xce, 0x2d, 0x5e, 0x71, 0x1e, 0x47, 0x90, 0x96, 0x43, 0xd4, 0xdc, 0x54, 0xed, 0x9e, 0xb1, 0x4f, 0x45, + 0xad, 0xe3, 0xe6, 0x4a, 0x63, 0xff, 0xa1, 0xa8, 0xd3, 0x58, 0x63, 0x16, 0x2f, 0x95, 0x61, 0x35, 0x8c, 0x26, 0x88, + 0x96, 0x20, 0x19, 0x52, 0x6a, 0xa8, 0xaf, 0xf9, 0x74, 0x8b, 0x79, 0xb1, 0x76, 0x7e, 0x53, 0xe4, 0xfe, 0x11, 0x39, + 0x48, 0x76, 0x42, 0x90, 0x0b, 0xd5, 0x5d, 0x8c, 0x1c, 0x8e, 0xd9, 0x6f, 0x34, 0xc8, 0xbc, 0x57, 0x24, 0x78, 0xc7, + 0x05, 0xca, 0x92, 0x65, 0x34, 0xa2, 0x1c, 0xee, 0xfe, 0x30, 0x35, 0x82, 0x03, 0x88, 0x1d, 0x8a, 0x1f, 0x36, 0x71, + 0xd5, 0xfc, 0x33, 0xb7, 0x48, 0x94, 0x90, 0x8a, 0x55, 0xf1, 0x5f, 0x64, 0x56, 0x42, 0xe9, 0x55, 0x71, 0x69, 0xed, + 0xbe, 0xff, 0x42, 0x36, 0x7c, 0x91, 0x59, 0x90, 0xe2, 0x14, 0x96, 0xfb, 0xf9, 0x73, 0xaa, 0x05, 0x49, 0x07, 0x69, + 0x5a, 0xe7, 0xa3, 0x22, 0xf8, 0x98, 0xe6, 0x4f, 0x63, 0x8a, 0x3f, 0xd6, 0x1d, 0x59, 0xf1, 0xcb, 0x97, 0x67, 0x7d, + 0xcf, 0xe4, 0x29, 0x33, 0x4b, 0xf9, 0x9d, 0x2e, 0xf7, 0x53, 0x8d, 0x9b, 0x8d, 0x4e, 0x5b, 0x8b, 0x20, 0x9a, 0x0a, + 0xcd, 0xb4, 0xc4, 0x5e, 0x90, 0x6f, 0x81, 0x54, 0x60, 0xbe, 0x50, 0x51, 0x8b, 0x3a, 0x77, 0x2c, 0x81, 0x74, 0x9f, + 0x7d, 0xbd, 0xed, 0xb8, 0x8e, 0xab, 0xcb, 0x86, 0x93, 0x60, 0xda, 0x5f, 0xc7, 0x99, 0x0f, 0x99, 0x6b, 0xc2, 0x78, + 0x0a, 0x9e, 0x1f, 0x59, 0x90, 0x85, 0x90, 0x06, 0x05, 0x5c, 0x40, 0xe6, 0xc4, 0x35, 0xe6, 0xdc, 0x1e, 0xd7, 0x4f, + 0x3e, 0x61, 0x2a, 0x3c, 0xe1, 0xf4, 0x85, 0xf1, 0x70, 0x7e, 0x84, 0xcb, 0xd0, 0xd0, 0x0d, 0x48, 0xc4, 0xc8, 0x92, + 0xd4, 0x56, 0xed, 0xdb, 0xbb, 0x1a, 0xb4, 0x81, 0x24, 0xe9, 0xd8, 0xc1, 0x24, 0xf1, 0xe7, 0x10, 0x31, 0x7c, 0x9d, + 0x5b, 0x1c, 0xd3, 0xea, 0x1c, 0xd5, 0x6a, 0xde, 0xab, 0x23, 0x4b, 0x6b, 0x79, 0x96, 0xe6, 0x02, 0xba, 0xd5, 0x73, + 0x6b, 0x9d, 0xdf, 0xf4, 0x76, 0xa9, 0xe8, 0x08, 0xbf, 0x3c, 0xa5, 0x79, 0x90, 0x72, 0x8e, 0x0b, 0x3f, 0x33, 0x0a, + 0x6f, 0x68, 0x28, 0xb1, 0xbc, 0x03, 0x12, 0xd3, 0x5f, 0xb1, 0x55, 0x66, 0x62, 0x9a, 0x10, 0x5e, 0x25, 0x30, 0xd7, + 0xe8, 0x9a, 0x16, 0x44, 0x5a, 0xf0, 0xf9, 0xb3, 0x11, 0x80, 0xf9, 0x7d, 0x5f, 0x81, 0x0f, 0x3c, 0x9b, 0x25, 0x80, + 0x05, 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0x2c, 0x7e, 0x70, 0xc5, 0x9e, 0x13, 0xfa, 0xd1, + 0x14, 0x50, 0x9a, 0x1f, 0x4d, 0x6b, 0x06, 0x04, 0xe4, 0x5d, 0x57, 0x29, 0x2d, 0xba, 0x2a, 0x94, 0xfb, 0xe9, 0xf7, + 0x0f, 0x57, 0x94, 0x06, 0x09, 0x52, 0x6e, 0xfb, 0x63, 0x74, 0x05, 0x2b, 0x74, 0x0f, 0x2f, 0xfb, 0xdf, 0x9c, 0xce, + 0x59, 0xe6, 0x93, 0xe0, 0x12, 0x58, 0x3c, 0x20, 0x07, 0xb4, 0x91, 0x48, 0x61, 0x4a, 0x0c, 0xde, 0x98, 0xdd, 0x05, + 0x23, 0xce, 0xa7, 0x59, 0x1a, 0xbf, 0xa7, 0x6c, 0xb4, 0x51, 0xea, 0x7b, 0x16, 0x99, 0xc8, 0x8e, 0x7c, 0x0c, 0x82, + 0xd8, 0x8f, 0x62, 0xfd, 0xec, 0x1b, 0xe9, 0x4d, 0xb4, 0x69, 0x11, 0x20, 0x17, 0xe1, 0x75, 0xc2, 0xc2, 0x7f, 0xf5, + 0xbf, 0x81, 0x8b, 0xfb, 0x9b, 0x1b, 0xdd, 0xec, 0x65, 0x0e, 0xf2, 0x31, 0xdf, 0x34, 0xe4, 0xe4, 0x43, 0x1e, 0x95, + 0x33, 0x9b, 0x6d, 0x85, 0xd9, 0x84, 0xdf, 0xbb, 0x59, 0xd7, 0xb3, 0x53, 0xbc, 0xd0, 0xce, 0x80, 0xbb, 0x58, 0x97, + 0x78, 0x4e, 0xaf, 0x87, 0x0c, 0xea, 0x30, 0xf4, 0x47, 0x9f, 0x04, 0x87, 0xaa, 0x3e, 0xec, 0xc3, 0x8b, 0x4a, 0xca, + 0xae, 0x71, 0x2f, 0xe3, 0x56, 0x5e, 0xe3, 0x97, 0xf1, 0x53, 0xf7, 0xb3, 0x20, 0x93, 0xcc, 0x30, 0x3e, 0xe4, 0xa0, + 0xcd, 0xc1, 0xf1, 0x15, 0xec, 0x0f, 0x30, 0xa8, 0xde, 0xc9, 0x5f, 0x3a, 0x77, 0x9e, 0x3b, 0x6b, 0x79, 0x0e, 0xb0, + 0x39, 0xb3, 0xb6, 0x73, 0x1c, 0xda, 0x6d, 0xe7, 0x18, 0xfe, 0x3e, 0x02, 0xeb, 0x65, 0xb7, 0x9c, 0xc3, 0x8f, 0x5e, + 0x2b, 0xb4, 0x4f, 0x9c, 0x63, 0xf8, 0xbb, 0xa4, 0x56, 0xbf, 0x20, 0xd3, 0x03, 0x0c, 0xcf, 0x37, 0x25, 0x2c, 0xa0, + 0xfc, 0x96, 0x5a, 0x04, 0xab, 0x74, 0xbd, 0x35, 0x68, 0x22, 0x00, 0x65, 0xe8, 0x96, 0x08, 0x51, 0x18, 0xf5, 0x0c, + 0x48, 0x12, 0x8e, 0xe1, 0xed, 0x85, 0x41, 0x46, 0x54, 0x24, 0xbc, 0xdf, 0x7c, 0x8c, 0x78, 0x9b, 0xe6, 0x70, 0xe0, + 0x22, 0x6f, 0x12, 0xa9, 0x2e, 0xfe, 0xb6, 0xc0, 0x10, 0x3b, 0x22, 0x80, 0xb9, 0x82, 0x95, 0x8a, 0xdc, 0x7d, 0xf9, + 0xee, 0x81, 0xa3, 0xdf, 0x28, 0x93, 0xb9, 0x63, 0xbe, 0x6a, 0xdf, 0x5c, 0x9d, 0x21, 0x7b, 0xff, 0xbd, 0xfd, 0x60, + 0xca, 0x54, 0xea, 0x47, 0xc4, 0x1a, 0x1d, 0x07, 0x89, 0x1c, 0x9e, 0x82, 0xa2, 0xbd, 0xe6, 0x38, 0xea, 0x26, 0x24, + 0xd9, 0xb8, 0x00, 0x2a, 0xf9, 0xce, 0x0f, 0x15, 0xd3, 0x0b, 0xa5, 0xe5, 0x13, 0x89, 0xf9, 0x9f, 0x3f, 0x2f, 0x06, + 0x67, 0x57, 0xc6, 0x7d, 0xea, 0x75, 0xe0, 0xda, 0xed, 0xb0, 0xf6, 0x56, 0x2b, 0xa0, 0xdd, 0xc1, 0x6a, 0x8b, 0x60, + 0x96, 0x42, 0xd3, 0x2f, 0x74, 0x8c, 0x1b, 0x4d, 0x91, 0x6a, 0x1a, 0x46, 0x08, 0xf3, 0x5b, 0x61, 0x75, 0x74, 0xb3, + 0x17, 0x09, 0x85, 0x59, 0xb4, 0x25, 0x40, 0x2f, 0xe7, 0xc5, 0x74, 0x00, 0xcd, 0x96, 0x79, 0xec, 0x70, 0x69, 0xfc, + 0x5f, 0x4f, 0x02, 0xdd, 0x8b, 0x40, 0xc3, 0x57, 0x39, 0xad, 0x25, 0x77, 0x13, 0x79, 0xaf, 0xd2, 0x85, 0xca, 0xd2, + 0x73, 0x1d, 0x8a, 0x20, 0xfb, 0x12, 0x26, 0x5c, 0x93, 0xe6, 0x4d, 0xf2, 0xb6, 0x28, 0x0a, 0xac, 0x00, 0x22, 0x54, + 0x1b, 0xc2, 0xd5, 0xc9, 0x7c, 0xfe, 0x7c, 0xe3, 0x25, 0x44, 0xea, 0x64, 0x35, 0xef, 0xa4, 0xae, 0xe2, 0x37, 0x5d, + 0x45, 0x31, 0xb2, 0x5f, 0xc4, 0x1a, 0xc2, 0x2a, 0x8b, 0xf6, 0x1e, 0xfe, 0x1c, 0x32, 0x3f, 0x73, 0xb8, 0x1e, 0xc4, + 0x50, 0x2e, 0x77, 0xcb, 0x63, 0x6d, 0xb0, 0xc7, 0xe2, 0x91, 0xb8, 0x78, 0xa4, 0xbb, 0x67, 0xeb, 0x8f, 0x4b, 0xee, + 0x87, 0x0c, 0x7d, 0x7c, 0x76, 0x8b, 0xe0, 0x29, 0xef, 0x32, 0x9f, 0x22, 0x6c, 0xa8, 0x57, 0x6e, 0x9c, 0xf9, 0x22, + 0xcb, 0x09, 0xd0, 0xe5, 0xbd, 0x46, 0x85, 0xa1, 0xe2, 0xab, 0x7c, 0xf6, 0xee, 0xea, 0x3b, 0x8d, 0xef, 0x7f, 0xd2, + 0x6f, 0x21, 0x23, 0x43, 0x31, 0xf9, 0xfb, 0x14, 0x93, 0x5f, 0xe3, 0x49, 0x2e, 0x20, 0xb2, 0x7d, 0x7e, 0x40, 0x10, + 0xd4, 0x35, 0x16, 0x8d, 0x48, 0xeb, 0x37, 0x5f, 0x86, 0x59, 0xb0, 0xf0, 0x93, 0xec, 0x00, 0x9a, 0xda, 0x80, 0xe4, + 0xf4, 0x4d, 0x1e, 0xcc, 0xa4, 0x38, 0x14, 0x42, 0xb5, 0x2c, 0x12, 0x9a, 0xc3, 0x49, 0x10, 0x4a, 0xc5, 0xa1, 0xf8, + 0x80, 0x3f, 0x1a, 0xb1, 0x45, 0xd6, 0xd7, 0xfd, 0x05, 0xe4, 0x66, 0xc0, 0x68, 0xcb, 0x07, 0xf1, 0x28, 0x63, 0x99, + 0x9d, 0x66, 0x09, 0xf3, 0xe7, 0xba, 0x0c, 0x34, 0x5a, 0xef, 0x2f, 0x5d, 0x0e, 0xe7, 0x41, 0x26, 0x23, 0xf5, 0xd1, + 0x04, 0x41, 0x85, 0x07, 0x43, 0x3c, 0x1b, 0xe4, 0x1c, 0x84, 0x97, 0xf1, 0xb4, 0xb2, 0xa3, 0x0a, 0xca, 0xe5, 0x1c, + 0xe3, 0xc0, 0xf2, 0x78, 0xfc, 0x63, 0xf4, 0xc8, 0xb9, 0xe5, 0x5e, 0xd7, 0x32, 0xa0, 0xa0, 0x7e, 0x76, 0xca, 0xd9, + 0x5b, 0x0d, 0x03, 0x05, 0xe8, 0x1d, 0x17, 0x22, 0xdd, 0x6e, 0xf2, 0xc7, 0x3e, 0xe0, 0x95, 0xe1, 0x6a, 0xa2, 0x9e, + 0x31, 0x0a, 0x39, 0x8d, 0xe5, 0x0a, 0x08, 0xa1, 0x92, 0x8a, 0x77, 0xe6, 0x9d, 0x49, 0x07, 0x20, 0x1c, 0x15, 0xd2, + 0x4a, 0x9f, 0x3f, 0xbf, 0x1e, 0xfc, 0xe7, 0xdf, 0x10, 0x2a, 0x7d, 0xe6, 0x09, 0x2f, 0xe8, 0x6b, 0xb5, 0x16, 0xa7, + 0x3e, 0xad, 0x01, 0xaa, 0xf7, 0xd9, 0x58, 0x84, 0x05, 0x11, 0x5b, 0x2b, 0x1f, 0xdc, 0x88, 0x50, 0x4f, 0x90, 0x0e, + 0xc1, 0x14, 0xbe, 0xda, 0x03, 0x58, 0xde, 0x81, 0x08, 0x11, 0xa0, 0xfd, 0xba, 0xfa, 0xfe, 0x18, 0x42, 0x01, 0xd7, + 0xb2, 0x14, 0x28, 0x03, 0xc4, 0x3d, 0x74, 0x76, 0xea, 0x73, 0xe1, 0x2b, 0x90, 0x1f, 0x69, 0xf7, 0x00, 0xa6, 0x39, + 0x8b, 0xe7, 0xcc, 0x09, 0xe2, 0x83, 0x7b, 0x36, 0xb4, 0xfd, 0x45, 0x40, 0xf2, 0x65, 0x94, 0xbb, 0x69, 0x44, 0xf9, + 0x49, 0x05, 0x2d, 0xd1, 0xd7, 0x79, 0x01, 0xca, 0xb8, 0x00, 0x14, 0xfc, 0xf4, 0xcf, 0xca, 0xd1, 0x03, 0x1d, 0x11, + 0xbf, 0xbe, 0x8c, 0xe5, 0xcf, 0x29, 0x08, 0xa0, 0x88, 0xf7, 0x57, 0x3c, 0xd8, 0xf1, 0x64, 0xa2, 0x46, 0xfc, 0x73, + 0xca, 0xdf, 0x97, 0x50, 0x29, 0xf6, 0x6c, 0xbc, 0xa0, 0x2f, 0xd5, 0x3f, 0x21, 0x7f, 0x42, 0xee, 0x5e, 0x1e, 0x1c, + 0x12, 0xce, 0x73, 0x2d, 0x72, 0xa0, 0x04, 0xc9, 0x53, 0xaa, 0xc4, 0x11, 0x45, 0x35, 0x4e, 0xf5, 0x06, 0xd2, 0xe4, + 0x49, 0xbf, 0x4f, 0x78, 0xac, 0x8a, 0xce, 0x00, 0x4a, 0x0d, 0xb1, 0xfc, 0x61, 0xb2, 0x19, 0x34, 0xb4, 0xc9, 0x83, + 0x0b, 0x1b, 0x55, 0xa7, 0x53, 0x1f, 0xe3, 0x81, 0x2f, 0xf6, 0x57, 0x69, 0x07, 0xc2, 0xce, 0xe2, 0x0b, 0x0b, 0x08, + 0x5c, 0xf4, 0x53, 0xc1, 0xe3, 0xda, 0xb7, 0x84, 0xb2, 0xed, 0xd0, 0x7f, 0x88, 0x15, 0xcd, 0x3a, 0x77, 0xb2, 0xbf, + 0xc4, 0xd2, 0x2b, 0xe1, 0xdc, 0x56, 0x3b, 0x49, 0x32, 0x1e, 0x7a, 0xfd, 0x34, 0xa9, 0x01, 0xcc, 0x77, 0x1d, 0x26, + 0xb5, 0x6e, 0x79, 0x32, 0x88, 0x1d, 0xf3, 0xe2, 0xa0, 0x95, 0x5e, 0xe2, 0xb9, 0xcf, 0x4f, 0x0f, 0x60, 0x7e, 0x10, + 0x18, 0xa0, 0x44, 0x19, 0x05, 0x26, 0x44, 0x1f, 0xf0, 0x53, 0xb2, 0x0e, 0xb8, 0x18, 0x0b, 0xa2, 0x0e, 0x39, 0x47, + 0x19, 0x9a, 0xb4, 0x54, 0xa5, 0x4e, 0xac, 0xb8, 0xcd, 0x54, 0xde, 0xee, 0xfc, 0x01, 0xbf, 0x2d, 0x31, 0x79, 0x40, + 0xde, 0xcb, 0x98, 0xf0, 0xbb, 0xbd, 0xcc, 0x36, 0xb8, 0xe6, 0x6e, 0xaa, 0x42, 0x04, 0xeb, 0x96, 0x0a, 0xc5, 0x3e, + 0xde, 0x56, 0xab, 0x20, 0x8d, 0x64, 0xb5, 0x85, 0x6f, 0xe8, 0x4f, 0x71, 0xc7, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0xbb, + 0xcc, 0xfa, 0x50, 0x55, 0x08, 0xdb, 0xfd, 0xc5, 0x82, 0x2a, 0x9b, 0xbd, 0xd3, 0x03, 0xe2, 0x3b, 0xcf, 0x68, 0x87, + 0x9d, 0x9d, 0x82, 0x75, 0x21, 0x2d, 0xba, 0xbf, 0x58, 0xf0, 0x25, 0xa5, 0x5f, 0xf4, 0xe6, 0x60, 0x96, 0xcd, 0xc3, + 0xb3, 0xff, 0x03, 0x1c, 0x2a, 0x1a, 0x60, 0x9f, 0x5a, 0x03, 0x00}; } // namespace web_server } // namespace esphome From 618102fe8c6d1fcafa51d2a0e025e08a1a14588d Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Sun, 9 Jun 2024 08:34:21 +0200 Subject: [PATCH 1856/2607] fix: arduino media player still sets wrong state. (#6875) --- .../i2s_audio/media_player/i2s_audio_media_player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index ef494fac2e..5140a923b4 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -28,7 +28,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { } } - if (this->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING) { + if (play_state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING) { this->is_announcement_ = true; } From 7b45498de67ccdf10271e61577c66b5e216bc6db Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 Jun 2024 08:15:29 +1200 Subject: [PATCH 1857/2607] [http_request] Add esp-idf and rp2040 support (#3256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement http_request component for esp-idf * Fix ifdefs * Lint * clang * Set else to fail with error message * Use unique_ptr * Fix * Tidy up casting, explicit HttpResponse lifetime (#3265) Co-authored-by: Daniel Cousens * Remove unique_ptr wrapper * Fix * Use reference * Add duration code into new split files * Add config for tx/rx buffer on idf * Fix * Try reserve response data with rx buffer size * Update http_request.h * Move client cleanup to be earlier * Move capture_response to bool on struct and remove global * Fix returns * Change quotes to brackets * Rework http request * Remove http request from old test yamls * Update component tests * Validate md5 length when hardcoded string * Linting * Add duration_ms to container * More lint * const * Remove default arguments and add helper functions for get and post * Add virtual destructor to HttpContainer * Undo const HEADER_KEYS * 🤦 * Update esphome/components/http_request/ota/ota_http_request.cpp Co-authored-by: Keith Burzinski * Update esphome/components/http_request/ota/ota_http_request.cpp Co-authored-by: Keith Burzinski * lint * Move header keys inline * Add missing WatchdogManagers * CAPS * Fix "follow redirects" string in config dump * IDF 5+ fix --------- Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com> Co-authored-by: Daniel Cousens Co-authored-by: Keith Burzinski --- esphome/codegen.py | 1 + esphome/components/http_request/__init__.py | 137 +++++++++++---- .../components/http_request/http_request.cpp | 132 +------------- .../components/http_request/http_request.h | 141 +++++++++------ .../http_request/http_request_arduino.cpp | 161 ++++++++++++++++++ .../http_request/http_request_arduino.h | 40 +++++ .../http_request/http_request_idf.cpp | 155 +++++++++++++++++ .../http_request/http_request_idf.h | 34 ++++ .../components/http_request/ota/__init__.py | 109 ++---------- .../http_request/ota/ota_http_request.cpp | 110 +++++------- .../http_request/ota/ota_http_request.h | 24 +-- .../ota/ota_http_request_arduino.cpp | 134 --------------- .../ota/ota_http_request_arduino.h | 42 ----- .../http_request/ota/ota_http_request_idf.cpp | 86 ---------- .../http_request/ota/ota_http_request_idf.h | 24 --- .../http_request/{ota => }/watchdog.cpp | 19 ++- .../http_request/{ota => }/watchdog.h | 5 +- esphome/cpp_types.py | 1 + tests/components/http_request/common.yaml | 75 ++++++++ .../http_request/common_http_request.yaml | 33 ---- tests/components/http_request/common_ota.yaml | 36 ---- .../http_request/test-nossl.esp8266.yaml | 40 +---- .../http_request/test.esp32-c3-idf.yaml | 2 +- .../http_request/test.esp32-c3.yaml | 3 +- .../http_request/test.esp32-idf.yaml | 2 +- tests/components/http_request/test.esp32.yaml | 3 +- .../components/http_request/test.esp8266.yaml | 3 +- .../components/http_request/test.rp2040.yaml | 2 +- tests/test1.yaml | 29 ---- tests/test3.1.yaml | 24 --- tests/test7.yaml | 23 +-- 31 files changed, 748 insertions(+), 882 deletions(-) create mode 100644 esphome/components/http_request/http_request_arduino.cpp create mode 100644 esphome/components/http_request/http_request_arduino.h create mode 100644 esphome/components/http_request/http_request_idf.cpp create mode 100644 esphome/components/http_request/http_request_idf.h delete mode 100644 esphome/components/http_request/ota/ota_http_request_arduino.cpp delete mode 100644 esphome/components/http_request/ota/ota_http_request_arduino.h delete mode 100644 esphome/components/http_request/ota/ota_http_request_idf.cpp delete mode 100644 esphome/components/http_request/ota/ota_http_request_idf.h rename esphome/components/http_request/{ota => }/watchdog.cpp (79%) rename esphome/components/http_request/{ota => }/watchdog.h (84%) create mode 100644 tests/components/http_request/common.yaml delete mode 100644 tests/components/http_request/common_http_request.yaml delete mode 100644 tests/components/http_request/common_ota.yaml diff --git a/esphome/codegen.py b/esphome/codegen.py index dc17f28a03..b552490129 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -58,6 +58,7 @@ from esphome.cpp_types import ( # noqa bool_, int_, std_ns, + std_shared_ptr, std_string, std_vector, uint8, diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 0c3e249512..37487ec9a7 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -1,9 +1,8 @@ -import urllib.parse as urlparse - import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.const import ( + __version__, CONF_ID, CONF_TIMEOUT, CONF_METHOD, @@ -12,67 +11,91 @@ from esphome.const import ( CONF_ESP8266_DISABLE_SSL_SUPPORT, ) from esphome.core import Lambda, CORE +from esphome.components import esp32 DEPENDENCIES = ["network"] AUTO_LOAD = ["json"] http_request_ns = cg.esphome_ns.namespace("http_request") HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component) +HttpRequestArduino = http_request_ns.class_("HttpRequestArduino", HttpRequestComponent) +HttpRequestIDF = http_request_ns.class_("HttpRequestIDF", HttpRequestComponent) + +HttpContainer = http_request_ns.class_("HttpContainer") + HttpRequestSendAction = http_request_ns.class_( "HttpRequestSendAction", automation.Action ) HttpRequestResponseTrigger = http_request_ns.class_( - "HttpRequestResponseTrigger", automation.Trigger + "HttpRequestResponseTrigger", + automation.Trigger.template( + cg.std_shared_ptr.template(HttpContainer), cg.std_string + ), ) -CONF_HEADERS = "headers" +CONF_HTTP_REQUEST_ID = "http_request_id" + CONF_USERAGENT = "useragent" -CONF_BODY = "body" -CONF_JSON = "json" CONF_VERIFY_SSL = "verify_ssl" -CONF_ON_RESPONSE = "on_response" CONF_FOLLOW_REDIRECTS = "follow_redirects" CONF_REDIRECT_LIMIT = "redirect_limit" +CONF_WATCHDOG_TIMEOUT = "watchdog_timeout" + +CONF_MAX_RESPONSE_BUFFER_SIZE = "max_response_buffer_size" +CONF_ON_RESPONSE = "on_response" +CONF_HEADERS = "headers" +CONF_BODY = "body" +CONF_JSON = "json" +CONF_CAPTURE_RESPONSE = "capture_response" def validate_url(value): - value = cv.string(value) - try: - parsed = list(urlparse.urlparse(value)) - except Exception as err: - raise cv.Invalid("Invalid URL") from err - - if not parsed[0] or not parsed[1]: - raise cv.Invalid("URL must have a URL scheme and host") - - if parsed[0] not in ["http", "https"]: - raise cv.Invalid("Scheme must be http or https") - - if not parsed[2]: - parsed[2] = "/" - - return urlparse.urlunparse(parsed) + value = cv.url(value) + if value.startswith("http://") or value.startswith("https://"): + return value + raise cv.Invalid("URL must start with 'http://' or 'https://'") -def validate_secure_url(config): - url_ = config[CONF_URL] +def validate_ssl_verification(config): + error_message = "" + + if CORE.is_esp32: + if not CORE.using_esp_idf and config[CONF_VERIFY_SSL]: + error_message = "ESPHome supports certificate verification only via ESP-IDF" + + if CORE.is_rp2040 and config[CONF_VERIFY_SSL]: + error_message = "ESPHome does not support certificate verification on RP2040" + if ( - config.get(CONF_VERIFY_SSL) - and not isinstance(url_, Lambda) - and url_.lower().startswith("https:") + CORE.is_esp8266 + and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT] + and config[CONF_VERIFY_SSL] ): + error_message = "ESPHome does not support certificate verification on ESP8266" + + if len(error_message) > 0: raise cv.Invalid( - "Currently ESPHome doesn't support SSL verification. " - "Set 'verify_ssl: false' to make insecure HTTPS requests." + f"{error_message}. Set '{CONF_VERIFY_SSL}: false' to skip certificate validation and allow less secure HTTPS connections." ) + return config +def _declare_request_class(value): + if CORE.using_esp_idf: + return cv.declare_id(HttpRequestIDF)(value) + if CORE.is_esp8266 or CORE.is_esp32 or CORE.is_rp2040: + return cv.declare_id(HttpRequestArduino)(value) + return NotImplementedError + + CONFIG_SCHEMA = cv.All( cv.Schema( { - cv.GenerateID(): cv.declare_id(HttpRequestComponent), - cv.Optional(CONF_USERAGENT, "ESPHome"): cv.string, + cv.GenerateID(): _declare_request_class, + cv.Optional( + CONF_USERAGENT, f"ESPHome/{__version__} (https://esphome.io)" + ): cv.string, cv.Optional(CONF_FOLLOW_REDIRECTS, True): cv.boolean, cv.Optional(CONF_REDIRECT_LIMIT, 3): cv.int_, cv.Optional( @@ -81,12 +104,21 @@ CONFIG_SCHEMA = cv.All( cv.SplitDefault(CONF_ESP8266_DISABLE_SSL_SUPPORT, esp8266=False): cv.All( cv.only_on_esp8266, cv.boolean ), + cv.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, + cv.Optional(CONF_WATCHDOG_TIMEOUT): cv.All( + cv.Any(cv.only_on_esp32, cv.only_on_rp2040), + cv.positive_not_null_time_period, + cv.positive_time_period_milliseconds, + ), } ).extend(cv.COMPONENT_SCHEMA), cv.require_framework_version( esp8266_arduino=cv.Version(2, 5, 1), esp32_arduino=cv.Version(0, 0, 0), + esp_idf=cv.Version(0, 0, 0), + rp2040_arduino=cv.Version(0, 0, 0), ), + validate_ssl_verification, ) @@ -100,11 +132,30 @@ async def to_code(config): if CORE.is_esp8266 and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT]: cg.add_define("USE_HTTP_REQUEST_ESP8266_HTTPS") + if timeout_ms := config.get(CONF_WATCHDOG_TIMEOUT): + cg.add(var.set_watchdog_timeout(timeout_ms)) + if CORE.is_esp32: - cg.add_library("WiFiClientSecure", None) - cg.add_library("HTTPClient", None) + if CORE.using_esp_idf: + esp32.add_idf_sdkconfig_option( + "CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", + config.get(CONF_VERIFY_SSL), + ) + esp32.add_idf_sdkconfig_option( + "CONFIG_ESP_TLS_INSECURE", + not config.get(CONF_VERIFY_SSL), + ) + esp32.add_idf_sdkconfig_option( + "CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY", + not config.get(CONF_VERIFY_SSL), + ) + else: + cg.add_library("WiFiClientSecure", None) + cg.add_library("HTTPClient", None) if CORE.is_esp8266: cg.add_library("ESP8266HTTPClient", None) + if CORE.is_rp2040 and CORE.using_arduino: + cg.add_library("HTTPClient", None) await cg.register_component(var, config) @@ -116,12 +167,16 @@ HTTP_REQUEST_ACTION_SCHEMA = cv.Schema( cv.Optional(CONF_HEADERS): cv.All( cv.Schema({cv.string: cv.templatable(cv.string)}) ), - cv.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, + cv.Optional(CONF_VERIFY_SSL): cv.invalid( + f"{CONF_VERIFY_SSL} has moved to the base component configuration." + ), + cv.Optional(CONF_CAPTURE_RESPONSE, default=False): cv.boolean, cv.Optional(CONF_ON_RESPONSE): automation.validate_automation( {cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(HttpRequestResponseTrigger)} ), + cv.Optional(CONF_MAX_RESPONSE_BUFFER_SIZE, default="1kB"): cv.validate_bytes, } -).add_extra(validate_secure_url) +) HTTP_REQUEST_GET_ACTION_SCHEMA = automation.maybe_conf( CONF_URL, HTTP_REQUEST_ACTION_SCHEMA.extend( @@ -173,6 +228,9 @@ async def http_request_action_to_code(config, action_id, template_arg, args): template_ = await cg.templatable(config[CONF_URL], args, cg.std_string) cg.add(var.set_url(template_)) cg.add(var.set_method(config[CONF_METHOD])) + cg.add(var.set_capture_response(config[CONF_CAPTURE_RESPONSE])) + cg.add(var.set_max_response_buffer_size(config[CONF_MAX_RESPONSE_BUFFER_SIZE])) + if CONF_BODY in config: template_ = await cg.templatable(config[CONF_BODY], args, cg.std_string) cg.add(var.set_body(template_)) @@ -196,7 +254,12 @@ async def http_request_action_to_code(config, action_id, template_arg, args): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_response_trigger(trigger)) await automation.build_automation( - trigger, [(int, "status_code"), (cg.uint32, "duration_ms")], conf + trigger, + [ + (cg.std_shared_ptr.template(HttpContainer), "response"), + (cg.std_string, "body"), + ], + conf, ) return var diff --git a/esphome/components/http_request/http_request.cpp b/esphome/components/http_request/http_request.cpp index 46894a9afd..be8bef006e 100644 --- a/esphome/components/http_request/http_request.cpp +++ b/esphome/components/http_request/http_request.cpp @@ -1,9 +1,8 @@ -#ifdef USE_ARDUINO - #include "http_request.h" -#include "esphome/core/defines.h" + #include "esphome/core/log.h" -#include "esphome/components/network/util.h" + +#include namespace esphome { namespace http_request { @@ -14,131 +13,12 @@ void HttpRequestComponent::dump_config() { ESP_LOGCONFIG(TAG, "HTTP Request:"); ESP_LOGCONFIG(TAG, " Timeout: %ums", this->timeout_); ESP_LOGCONFIG(TAG, " User-Agent: %s", this->useragent_); - ESP_LOGCONFIG(TAG, " Follow Redirects: %d", this->follow_redirects_); + ESP_LOGCONFIG(TAG, " Follow redirects: %s", YESNO(this->follow_redirects_)); ESP_LOGCONFIG(TAG, " Redirect limit: %d", this->redirect_limit_); -} - -void HttpRequestComponent::set_url(std::string url) { - this->url_ = std::move(url); - this->secure_ = this->url_.compare(0, 6, "https:") == 0; - - if (!this->last_url_.empty() && this->url_ != this->last_url_) { - // Close connection if url has been changed - this->client_.setReuse(false); - this->client_.end(); + if (this->watchdog_timeout_ > 0) { + ESP_LOGCONFIG(TAG, " Watchdog Timeout: %" PRIu32 "ms", this->watchdog_timeout_); } - this->client_.setReuse(true); -} - -void HttpRequestComponent::send(const std::vector &response_triggers) { - if (!network::is_connected()) { - this->client_.end(); - this->status_set_warning(); - ESP_LOGW(TAG, "HTTP Request failed; Not connected to network"); - return; - } - - bool begin_status = false; - const String url = this->url_.c_str(); -#if defined(USE_ESP32) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0)) -#if defined(USE_ESP32) || USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0) - if (this->follow_redirects_) { - this->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); - } else { - this->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS); - } -#else - this->client_.setFollowRedirects(this->follow_redirects_); -#endif - this->client_.setRedirectLimit(this->redirect_limit_); -#endif -#if defined(USE_ESP32) - begin_status = this->client_.begin(url); -#elif defined(USE_ESP8266) - begin_status = this->client_.begin(*this->get_wifi_client_(), url); -#endif - - if (!begin_status) { - this->client_.end(); - this->status_set_warning(); - ESP_LOGW(TAG, "HTTP Request failed at the begin phase. Please check the configuration"); - return; - } - - this->client_.setTimeout(this->timeout_); -#if defined(USE_ESP32) - this->client_.setConnectTimeout(this->timeout_); -#endif - if (this->useragent_ != nullptr) { - this->client_.setUserAgent(this->useragent_); - } - for (const auto &header : this->headers_) { - this->client_.addHeader(header.name, header.value, false, true); - } - - uint32_t start_time = millis(); - int http_code = this->client_.sendRequest(this->method_, this->body_.c_str()); - uint32_t duration = millis() - start_time; - for (auto *trigger : response_triggers) - trigger->process(http_code, duration); - - if (http_code < 0) { - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s; Duration: %u ms", this->url_.c_str(), - HTTPClient::errorToString(http_code).c_str(), duration); - this->status_set_warning(); - return; - } - - if (http_code < 200 || http_code >= 300) { - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Code: %d; Duration: %u ms", this->url_.c_str(), http_code, duration); - this->status_set_warning(); - return; - } - - this->status_clear_warning(); - ESP_LOGD(TAG, "HTTP Request completed; URL: %s; Code: %d; Duration: %u ms", this->url_.c_str(), http_code, duration); -} - -#ifdef USE_ESP8266 -std::shared_ptr HttpRequestComponent::get_wifi_client_() { -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS - if (this->secure_) { - if (this->wifi_client_secure_ == nullptr) { - this->wifi_client_secure_ = std::make_shared(); - this->wifi_client_secure_->setInsecure(); - this->wifi_client_secure_->setBufferSizes(512, 512); - } - return this->wifi_client_secure_; - } -#endif - - if (this->wifi_client_ == nullptr) { - this->wifi_client_ = std::make_shared(); - } - return this->wifi_client_; -} -#endif - -void HttpRequestComponent::close() { - this->last_url_ = this->url_; - this->client_.end(); -} - -const char *HttpRequestComponent::get_string() { -#if defined(ESP32) - // The static variable is here because HTTPClient::getString() returns a String on ESP32, - // and we need something to keep a buffer alive. - static String str; -#else - // However on ESP8266, HTTPClient::getString() returns a String& to a member variable. - // Leaving this the default so that any new platform either doesn't copy, or encounters a compilation error. - auto & -#endif - str = this->client_.getString(); - return str.c_str(); } } // namespace http_request } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index b885de18e6..df6bc7dea7 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -1,27 +1,18 @@ #pragma once -#ifdef USE_ARDUINO - -#include "esphome/components/json/json_util.h" -#include "esphome/core/automation.h" -#include "esphome/core/component.h" -#include "esphome/core/defines.h" - #include #include #include #include #include -#ifdef USE_ESP32 -#include -#endif -#ifdef USE_ESP8266 -#include -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS -#include -#endif -#endif +#include "esphome/components/json/json_util.h" +#include "esphome/core/application.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace http_request { @@ -31,9 +22,32 @@ struct Header { const char *value; }; -class HttpRequestResponseTrigger : public Trigger { +class HttpRequestComponent; + +class HttpContainer : public Parented { public: - void process(int32_t status_code, uint32_t duration_ms) { this->trigger(status_code, duration_ms); } + virtual ~HttpContainer() = default; + size_t content_length; + int status_code; + uint32_t duration_ms; + + virtual int read(uint8_t *buf, size_t max_len) = 0; + virtual void end() = 0; + + void set_secure(bool secure) { this->secure_ = secure; } + + size_t get_bytes_read() const { return this->bytes_read_; } + + protected: + size_t bytes_read_{0}; + bool secure_{false}; +}; + +class HttpRequestResponseTrigger : public Trigger, std::string> { + public: + void process(std::shared_ptr container, std::string response_body) { + this->trigger(std::move(container), std::move(response_body)); + } }; class HttpRequestComponent : public Component { @@ -41,37 +55,33 @@ class HttpRequestComponent : public Component { void dump_config() override; float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } - void set_url(std::string url); - void set_method(const char *method) { this->method_ = method; } void set_useragent(const char *useragent) { this->useragent_ = useragent; } void set_timeout(uint16_t timeout) { this->timeout_ = timeout; } + void set_watchdog_timeout(uint32_t watchdog_timeout) { this->watchdog_timeout_ = watchdog_timeout; } + uint32_t get_watchdog_timeout() const { return this->watchdog_timeout_; } void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; } void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; } - void set_body(const std::string &body) { this->body_ = body; } - void set_headers(std::list

headers) { this->headers_ = std::move(headers); } - void send(const std::vector &response_triggers); - void close(); - const char *get_string(); + + std::shared_ptr get(std::string url) { return this->start(std::move(url), "GET", "", {}); } + std::shared_ptr get(std::string url, std::list
headers) { + return this->start(std::move(url), "GET", "", std::move(headers)); + } + std::shared_ptr post(std::string url, std::string body) { + return this->start(std::move(url), "POST", std::move(body), {}); + } + std::shared_ptr post(std::string url, std::string body, std::list
headers) { + return this->start(std::move(url), "POST", std::move(body), std::move(headers)); + } + + virtual std::shared_ptr start(std::string url, std::string method, std::string body, + std::list
headers) = 0; protected: - HTTPClient client_{}; - std::string url_; - std::string last_url_; - const char *method_; const char *useragent_{nullptr}; - bool secure_; bool follow_redirects_; uint16_t redirect_limit_; uint16_t timeout_{5000}; - std::string body_; - std::list
headers_; -#ifdef USE_ESP8266 - std::shared_ptr wifi_client_; -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS - std::shared_ptr wifi_client_secure_; -#endif - std::shared_ptr get_wifi_client_(); -#endif + uint32_t watchdog_timeout_{0}; }; template class HttpRequestSendAction : public Action { @@ -80,6 +90,7 @@ template class HttpRequestSendAction : public Action { TEMPLATABLE_VALUE(std::string, url) TEMPLATABLE_VALUE(const char *, method) TEMPLATABLE_VALUE(std::string, body) + TEMPLATABLE_VALUE(bool, capture_response) void add_header(const char *key, TemplatableValue value) { this->headers_.insert({key, value}); } @@ -89,19 +100,22 @@ template class HttpRequestSendAction : public Action { void register_response_trigger(HttpRequestResponseTrigger *trigger) { this->response_triggers_.push_back(trigger); } + void set_max_response_buffer_size(size_t max_response_buffer_size) { + this->max_response_buffer_size_ = max_response_buffer_size; + } + void play(Ts... x) override { - this->parent_->set_url(this->url_.value(x...)); - this->parent_->set_method(this->method_.value(x...)); + std::string body; if (this->body_.has_value()) { - this->parent_->set_body(this->body_.value(x...)); + body = this->body_.value(x...); } if (!this->json_.empty()) { auto f = std::bind(&HttpRequestSendAction::encode_json_, this, x..., std::placeholders::_1); - this->parent_->set_body(json::build_json(f)); + body = json::build_json(f); } if (this->json_func_ != nullptr) { auto f = std::bind(&HttpRequestSendAction::encode_json_func_, this, x..., std::placeholders::_1); - this->parent_->set_body(json::build_json(f)); + body = json::build_json(f); } std::list
headers; for (const auto &item : this->headers_) { @@ -111,10 +125,37 @@ template class HttpRequestSendAction : public Action { header.value = val.value(x...); headers.push_back(header); } - this->parent_->set_headers(headers); - this->parent_->send(this->response_triggers_); - this->parent_->close(); - this->parent_->set_body(""); + + auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, headers); + + if (container == nullptr) { + return; + } + + size_t content_length = container->content_length; + size_t max_length = std::min(content_length, this->max_response_buffer_size_); + + std::string response_body; + if (this->capture_response_.value(x...)) { + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + uint8_t *buf = allocator.allocate(max_length); + if (buf != nullptr) { + size_t read_index = 0; + while (container->get_bytes_read() < max_length) { + int read = container->read(buf + read_index, std::min(max_length - read_index, 512)); + App.feed_wdt(); + yield(); + read_index += read; + } + response_body.reserve(read_index); + response_body.assign((char *) buf, read_index); + } + } + + for (auto *trigger : this->response_triggers_) { + trigger->process(container, response_body); + } + container->end(); } protected: @@ -130,9 +171,9 @@ template class HttpRequestSendAction : public Action { std::map> json_{}; std::function json_func_{nullptr}; std::vector response_triggers_; + + size_t max_response_buffer_size_{SIZE_MAX}; }; } // namespace http_request } // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp new file mode 100644 index 0000000000..248a85a439 --- /dev/null +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -0,0 +1,161 @@ +#include "http_request_arduino.h" + +#ifdef USE_ARDUINO + +#include "esphome/components/network/util.h" +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" + +#include "watchdog.h" + +namespace esphome { +namespace http_request { + +static const char *const TAG = "http_request.arduino"; + +std::shared_ptr HttpRequestArduino::start(std::string url, std::string method, std::string body, + std::list
headers) { + if (!network::is_connected()) { + this->status_momentary_error("failed", 1000); + ESP_LOGW(TAG, "HTTP Request failed; Not connected to network"); + return nullptr; + } + + std::shared_ptr container = std::make_shared(); + container->set_parent(this); + + const uint32_t start = millis(); + + bool secure = url.find("https:") != std::string::npos; + container->set_secure(secure); + + watchdog::WatchdogManager wdm(this->get_watchdog_timeout()); + +#if defined(USE_ESP8266) + std::unique_ptr stream_ptr; +#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS + if (secure) { + ESP_LOGV(TAG, "ESP8266 HTTPS connection with WiFiClientSecure"); + stream_ptr = std::make_unique(); + WiFiClientSecure *secure_client = static_cast(stream_ptr.get()); + secure_client->setBufferSizes(512, 512); + secure_client->setInsecure(); + } else { + stream_ptr = std::make_unique(); + } +#else + ESP_LOGV(TAG, "ESP8266 HTTP connection with WiFiClient"); + if (secure) { + ESP_LOGE(TAG, "Can't use HTTPS connection with esp8266_disable_ssl_support"); + return nullptr; + } + stream_ptr = std::make_unique(); +#endif // USE_HTTP_REQUEST_ESP8266_HTTPS + +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 1, 0) // && USE_ARDUINO_VERSION_CODE < VERSION_CODE(?, ?, ?) + if (!secure) { + ESP_LOGW(TAG, "Using HTTP on Arduino version >= 3.1 is **very** slow. Consider setting framework version to 3.0.2 " + "in your YAML, or use HTTPS"); + } +#endif // USE_ARDUINO_VERSION_CODE + + container->client_.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + bool status = container->client_.begin(*stream_ptr, url.c_str()); + +#elif defined(USE_RP2040) + if (secure) { + container->client_.setInsecure(); + } + bool status = container->client_.begin(url.c_str()); +#elif defined(USE_ESP32) + bool status = container->client_.begin(url.c_str()); +#endif + + App.feed_wdt(); + + if (!status) { + ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url.c_str()); + container->end(); + this->status_momentary_error("failed", 1000); + return nullptr; + } + + container->client_.setReuse(true); + container->client_.setTimeout(this->timeout_); +#if defined(USE_ESP32) + container->client_.setConnectTimeout(this->timeout_); +#endif + + if (this->useragent_ != nullptr) { + container->client_.setUserAgent(this->useragent_); + } + for (const auto &header : headers) { + container->client_.addHeader(header.name, header.value, false, true); + } + + // returned needed headers must be collected before the requests + static const char *header_keys[] = {"Content-Length", "Content-Type"}; + static const size_t HEADER_COUNT = sizeof(header_keys) / sizeof(header_keys[0]); + container->client_.collectHeaders(header_keys, HEADER_COUNT); + + container->status_code = container->client_.sendRequest(method.c_str(), body.c_str()); + if (container->status_code < 0) { + ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url.c_str(), + HTTPClient::errorToString(container->status_code).c_str()); + this->status_momentary_error("failed", 1000); + container->end(); + return nullptr; + } + + if (container->status_code < 200 || container->status_code >= 300) { + ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); + this->status_momentary_error("failed", 1000); + container->end(); + return nullptr; + } + + int content_length = container->client_.getSize(); + ESP_LOGD(TAG, "Content-Length: %d", content_length); + container->content_length = (size_t) content_length; + container->duration_ms = millis() - start; + + return container; +} + +int HttpContainerArduino::read(uint8_t *buf, size_t max_len) { + const uint32_t start = millis(); + watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout()); + + WiFiClient *stream_ptr = this->client_.getStreamPtr(); + if (stream_ptr == nullptr) { + ESP_LOGE(TAG, "Stream pointer vanished!"); + return -1; + } + + int available_data = stream_ptr->available(); + int bufsize = std::min(max_len, std::min(this->content_length - this->bytes_read_, (size_t) available_data)); + + if (bufsize == 0) { + this->duration_ms += (millis() - start); + return 0; + } + + App.feed_wdt(); + int read_len = stream_ptr->readBytes(buf, bufsize); + this->bytes_read_ += read_len; + + this->duration_ms += (millis() - start); + + return read_len; +} + +void HttpContainerArduino::end() { + watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout()); + this->client_.end(); +} + +} // namespace http_request +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/http_request/http_request_arduino.h b/esphome/components/http_request/http_request_arduino.h new file mode 100644 index 0000000000..dfdf4a35e2 --- /dev/null +++ b/esphome/components/http_request/http_request_arduino.h @@ -0,0 +1,40 @@ +#pragma once + +#include "http_request.h" + +#ifdef USE_ARDUINO + +#if defined(USE_ESP32) || defined(USE_RP2040) +#include +#endif +#ifdef USE_ESP8266 +#include +#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS +#include +#endif +#endif + +namespace esphome { +namespace http_request { + +class HttpRequestArduino; +class HttpContainerArduino : public HttpContainer { + public: + int read(uint8_t *buf, size_t max_len) override; + void end() override; + + protected: + friend class HttpRequestArduino; + HTTPClient client_{}; +}; + +class HttpRequestArduino : public HttpRequestComponent { + public: + std::shared_ptr start(std::string url, std::string method, std::string body, + std::list
headers) override; +}; + +} // namespace http_request +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp new file mode 100644 index 0000000000..138e0438f4 --- /dev/null +++ b/esphome/components/http_request/http_request_idf.cpp @@ -0,0 +1,155 @@ +#include "http_request_idf.h" + +#ifdef USE_ESP_IDF + +#include "esphome/components/network/util.h" +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" + +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE +#include "esp_crt_bundle.h" +#endif + +#include "watchdog.h" + +namespace esphome { +namespace http_request { + +static const char *const TAG = "http_request.idf"; + +std::shared_ptr HttpRequestIDF::start(std::string url, std::string method, std::string body, + std::list
headers) { + if (!network::is_connected()) { + this->status_momentary_error("failed", 1000); + ESP_LOGE(TAG, "HTTP Request failed; Not connected to network"); + return nullptr; + } + + esp_http_client_method_t method_idf; + if (method == "GET") { + method_idf = HTTP_METHOD_GET; + } else if (method == "POST") { + method_idf = HTTP_METHOD_POST; + } else if (method == "PUT") { + method_idf = HTTP_METHOD_PUT; + } else if (method == "DELETE") { + method_idf = HTTP_METHOD_DELETE; + } else if (method == "PATCH") { + method_idf = HTTP_METHOD_PATCH; + } else { + this->status_momentary_error("failed", 1000); + ESP_LOGE(TAG, "HTTP Request failed; Unsupported method"); + return nullptr; + } + + bool secure = url.find("https:") != std::string::npos; + + esp_http_client_config_t config = {}; + + config.url = url.c_str(); + config.method = method_idf; + config.timeout_ms = this->timeout_; + config.disable_auto_redirect = !this->follow_redirects_; + config.max_redirection_count = this->redirect_limit_; +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE + if (secure) { + config.crt_bundle_attach = esp_crt_bundle_attach; + } +#endif + + if (this->useragent_ != nullptr) { + config.user_agent = this->useragent_; + } + + const uint32_t start = millis(); + watchdog::WatchdogManager wdm(this->get_watchdog_timeout()); + + esp_http_client_handle_t client = esp_http_client_init(&config); + + std::shared_ptr container = std::make_shared(client); + container->set_parent(this); + + container->set_secure(secure); + + for (const auto &header : headers) { + esp_http_client_set_header(client, header.name, header.value); + } + + int body_len = body.length(); + + esp_err_t err = esp_http_client_open(client, body_len); + if (err != ESP_OK) { + this->status_momentary_error("failed", 1000); + ESP_LOGE(TAG, "HTTP Request failed: %s", esp_err_to_name(err)); + esp_http_client_cleanup(client); + return nullptr; + } + + if (body_len > 0) { + int write_left = body_len; + int write_index = 0; + const char *buf = body.c_str(); + while (body_len > 0) { + int written = esp_http_client_write(client, buf + write_index, write_left); + if (written < 0) { + err = ESP_FAIL; + break; + } + write_left -= written; + write_index += written; + } + } + + if (err != ESP_OK) { + this->status_momentary_error("failed", 1000); + ESP_LOGE(TAG, "HTTP Request failed: %s", esp_err_to_name(err)); + esp_http_client_cleanup(client); + return nullptr; + } + + container->content_length = esp_http_client_fetch_headers(client); + const auto status_code = esp_http_client_get_status_code(client); + container->status_code = status_code; + + if (status_code < 200 || status_code >= 300) { + ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), status_code); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; + } + container->duration_ms = millis() - start; + return container; +} + +int HttpContainerIDF::read(uint8_t *buf, size_t max_len) { + const uint32_t start = millis(); + watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout()); + + int bufsize = std::min(max_len, this->content_length - this->bytes_read_); + + if (bufsize == 0) { + this->duration_ms += (millis() - start); + return 0; + } + + App.feed_wdt(); + int read_len = esp_http_client_read(this->client_, (char *) buf, bufsize); + this->bytes_read_ += read_len; + + this->duration_ms += (millis() - start); + + return read_len; +} + +void HttpContainerIDF::end() { + watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout()); + + esp_http_client_close(this->client_); + esp_http_client_cleanup(this->client_); +} + +} // namespace http_request +} // namespace esphome + +#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/http_request_idf.h b/esphome/components/http_request/http_request_idf.h new file mode 100644 index 0000000000..79f850a636 --- /dev/null +++ b/esphome/components/http_request/http_request_idf.h @@ -0,0 +1,34 @@ +#pragma once + +#include "http_request.h" + +#ifdef USE_ESP_IDF + +#include +#include +#include +#include + +namespace esphome { +namespace http_request { + +class HttpContainerIDF : public HttpContainer { + public: + HttpContainerIDF(esp_http_client_handle_t client) : client_(client) {} + int read(uint8_t *buf, size_t max_len) override; + void end() override; + + protected: + esp_http_client_handle_t client_; +}; + +class HttpRequestIDF : public HttpRequestComponent { + public: + std::shared_ptr start(std::string url, std::string method, std::string body, + std::list
headers) override; +}; + +} // namespace http_request +} // namespace esphome + +#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/ota/__init__.py b/esphome/components/http_request/ota/__init__.py index 6a56fac83a..0ef1fc2348 100644 --- a/esphome/components/http_request/ota/__init__.py +++ b/esphome/components/http_request/ota/__init__.py @@ -2,92 +2,35 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.const import ( - CONF_ESP8266_DISABLE_SSL_SUPPORT, CONF_ID, CONF_PASSWORD, - CONF_TIMEOUT, CONF_URL, CONF_USERNAME, ) -from esphome.components import esp32 from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent -from esphome.core import CORE, coroutine_with_priority -from .. import http_request_ns +from esphome.core import coroutine_with_priority +from .. import CONF_HTTP_REQUEST_ID, http_request_ns, HttpRequestComponent CODEOWNERS = ["@oarcher"] AUTO_LOAD = ["md5"] -DEPENDENCIES = ["network"] +DEPENDENCIES = ["network", "http_request"] CONF_MD5 = "md5" CONF_MD5_URL = "md5_url" -CONF_VERIFY_SSL = "verify_ssl" -CONF_WATCHDOG_TIMEOUT = "watchdog_timeout" OtaHttpRequestComponent = http_request_ns.class_( "OtaHttpRequestComponent", OTAComponent ) -OtaHttpRequestComponentArduino = http_request_ns.class_( - "OtaHttpRequestComponentArduino", OtaHttpRequestComponent -) -OtaHttpRequestComponentIDF = http_request_ns.class_( - "OtaHttpRequestComponentIDF", OtaHttpRequestComponent -) OtaHttpRequestComponentFlashAction = http_request_ns.class_( "OtaHttpRequestComponentFlashAction", automation.Action ) - -def validate_ssl_verification(config): - error_message = "" - - if CORE.is_esp32: - if not CORE.using_esp_idf and config[CONF_VERIFY_SSL]: - error_message = "ESPHome supports certificate verification only via ESP-IDF" - - if CORE.is_rp2040 and config[CONF_VERIFY_SSL]: - error_message = "ESPHome does not support certificate verification in Arduino" - - if ( - CORE.is_esp8266 - and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT] - and config[CONF_VERIFY_SSL] - ): - error_message = "ESPHome does not support certificate verification in Arduino" - - if len(error_message) > 0: - raise cv.Invalid( - f"{error_message}. Set '{CONF_VERIFY_SSL}: false' to skip certificate validation and allow less secure HTTPS connections." - ) - - return config - - -def _declare_request_class(value): - if CORE.using_esp_idf: - return cv.declare_id(OtaHttpRequestComponentIDF)(value) - - if CORE.is_esp8266 or CORE.is_esp32 or CORE.is_rp2040: - return cv.declare_id(OtaHttpRequestComponentArduino)(value) - return NotImplementedError - - CONFIG_SCHEMA = cv.All( cv.Schema( { - cv.GenerateID(): _declare_request_class, - cv.SplitDefault(CONF_ESP8266_DISABLE_SSL_SUPPORT, esp8266=False): cv.All( - cv.only_on_esp8266, cv.boolean - ), - cv.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, - cv.Optional( - CONF_TIMEOUT, default="5min" - ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_WATCHDOG_TIMEOUT): cv.All( - cv.Any(cv.only_on_esp32, cv.only_on_rp2040), - cv.positive_not_null_time_period, - cv.positive_time_period_milliseconds, - ), + cv.GenerateID(): cv.declare_id(OtaHttpRequestComponent), + cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent), } ) .extend(BASE_OTA_SCHEMA) @@ -98,7 +41,6 @@ CONFIG_SCHEMA = cv.All( esp_idf=cv.Version(0, 0, 0), rp2040_arduino=cv.Version(0, 0, 0), ), - validate_ssl_verification, ) @@ -106,41 +48,8 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await ota_to_code(var, config) - - cg.add(var.set_timeout(config[CONF_TIMEOUT])) - - if timeout_ms := config.get(CONF_WATCHDOG_TIMEOUT): - cg.add_define( - "USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT", - timeout_ms, - ) - - if CORE.is_esp8266 and not config[CONF_ESP8266_DISABLE_SSL_SUPPORT]: - cg.add_define("USE_HTTP_REQUEST_ESP8266_HTTPS") - - if CORE.is_esp32: - if CORE.using_esp_idf: - esp32.add_idf_sdkconfig_option( - "CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", - config.get(CONF_VERIFY_SSL), - ) - esp32.add_idf_sdkconfig_option( - "CONFIG_ESP_TLS_INSECURE", - not config.get(CONF_VERIFY_SSL), - ) - esp32.add_idf_sdkconfig_option( - "CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY", - not config.get(CONF_VERIFY_SSL), - ) - else: - cg.add_library("WiFiClientSecure", None) - cg.add_library("HTTPClient", None) - if CORE.is_esp8266: - cg.add_library("ESP8266HTTPClient", None) - if CORE.is_rp2040 and CORE.using_arduino: - cg.add_library("HTTPClient", None) - await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_HTTP_REQUEST_ID]) OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA = cv.All( @@ -148,7 +57,9 @@ OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA = cv.All( { cv.GenerateID(): cv.use_id(OtaHttpRequestComponent), cv.Optional(CONF_MD5_URL): cv.templatable(cv.url), - cv.Optional(CONF_MD5): cv.templatable(cv.string), + cv.Optional(CONF_MD5): cv.templatable( + cv.All(cv.string, cv.Length(min=32, max=32)) + ), cv.Optional(CONF_PASSWORD): cv.templatable(cv.string), cv.Optional(CONF_USERNAME): cv.templatable(cv.string), cv.Required(CONF_URL): cv.templatable(cv.url), @@ -159,7 +70,7 @@ OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA = cv.All( @automation.register_action( - "ota_http_request.flash", + "ota.http_request.flash", OtaHttpRequestComponentFlashAction, OTA_HTTP_REQUEST_FLASH_ACTION_SCHEMA, ) diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index cf0816c858..a41f552baf 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -1,16 +1,16 @@ #include "ota_http_request.h" -#include "watchdog.h" +#include "../watchdog.h" #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" #include "esphome/components/md5/md5.h" +#include "esphome/components/ota/ota_backend.h" #include "esphome/components/ota/ota_backend_arduino_esp32.h" #include "esphome/components/ota/ota_backend_arduino_esp8266.h" #include "esphome/components/ota/ota_backend_arduino_rp2040.h" #include "esphome/components/ota/ota_backend_esp_idf.h" -#include "esphome/components/ota/ota_backend.h" namespace esphome { namespace http_request { @@ -21,25 +21,7 @@ void OtaHttpRequestComponent::setup() { #endif } -void OtaHttpRequestComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Over-The-Air updates via HTTP request:"); - ESP_LOGCONFIG(TAG, " Timeout: %llus", this->timeout_ / 1000); -#ifdef USE_ESP8266 -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS - ESP_LOGCONFIG(TAG, " ESP8266 SSL support: No"); -#else - ESP_LOGCONFIG(TAG, " ESP8266 SSL support: Yes"); -#endif -#endif -#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE - ESP_LOGCONFIG(TAG, " TLS server verification: Yes"); -#else - ESP_LOGCONFIG(TAG, " TLS server verification: No"); -#endif -#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT - ESP_LOGCONFIG(TAG, " Watchdog timeout: %ds", USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT / 1000); -#endif -}; +void OtaHttpRequestComponent::dump_config() { ESP_LOGCONFIG(TAG, "Over-The-Air updates via HTTP request"); }; void OtaHttpRequestComponent::set_md5_url(const std::string &url) { if (!this->validate_url_(url)) { @@ -58,20 +40,6 @@ void OtaHttpRequestComponent::set_url(const std::string &url) { this->url_ = url; } -bool OtaHttpRequestComponent::check_status() { - // status can be -1, or HTTP status code - if (this->status_ < 100) { - ESP_LOGE(TAG, "HTTP server did not respond (error %d)", this->status_); - return false; - } - if (this->status_ >= 310) { - ESP_LOGE(TAG, "HTTP error %d", this->status_); - return false; - } - ESP_LOGV(TAG, "HTTP status %d", this->status_); - return true; -} - void OtaHttpRequestComponent::flash() { if (this->url_.empty()) { ESP_LOGE(TAG, "URL not set; cannot start update"); @@ -104,17 +72,18 @@ void OtaHttpRequestComponent::flash() { } } -void OtaHttpRequestComponent::cleanup_(std::unique_ptr backend) { +void OtaHttpRequestComponent::cleanup_(std::unique_ptr backend, + const std::shared_ptr &container) { if (this->update_started_) { ESP_LOGV(TAG, "Aborting OTA backend"); backend->abort(); } ESP_LOGV(TAG, "Aborting HTTP connection"); - this->http_end(); + container->end(); }; uint8_t OtaHttpRequestComponent::do_ota_() { - uint8_t buf[this->http_recv_buffer_ + 1]; + uint8_t buf[OtaHttpRequestComponent::HTTP_RECV_BUFFER + 1]; uint32_t last_progress = 0; uint32_t update_start_time = millis(); md5::MD5Digest md5_receive; @@ -132,9 +101,10 @@ uint8_t OtaHttpRequestComponent::do_ota_() { } ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str()); ESP_LOGI(TAG, "Connecting to: %s", this->url_.c_str()); - this->http_init(url_with_auth); - if (!this->check_status()) { - this->http_end(); + + auto container = this->parent_->get(url_with_auth); + + if (container == nullptr) { return OTA_CONNECTION_ERROR; } @@ -144,18 +114,18 @@ uint8_t OtaHttpRequestComponent::do_ota_() { ESP_LOGV(TAG, "OTA backend begin"); auto backend = ota::make_ota_backend(); - auto error_code = backend->begin(this->body_length_); + auto error_code = backend->begin(container->content_length); if (error_code != ota::OTA_RESPONSE_OK) { ESP_LOGW(TAG, "backend->begin error: %d", error_code); - this->cleanup_(std::move(backend)); + this->cleanup_(std::move(backend), container); return error_code; } - this->bytes_read_ = 0; - while (this->bytes_read_ < this->body_length_) { + while (container->get_bytes_read() < container->content_length) { // read a maximum of chunk_size bytes into buf. (real read size returned) - int bufsize = this->http_read(buf, this->http_recv_buffer_); - ESP_LOGVV(TAG, "bytes_read_ = %u, body_length_ = %u, bufsize = %i", this->bytes_read_, this->body_length_, bufsize); + int bufsize = container->read(buf, OtaHttpRequestComponent::HTTP_RECV_BUFFER); + ESP_LOGVV(TAG, "bytes_read_ = %u, body_length_ = %u, bufsize = %i", container->get_bytes_read(), + container->content_length, bufsize); // feed watchdog and give other tasks a chance to run App.feed_wdt(); @@ -163,9 +133,9 @@ uint8_t OtaHttpRequestComponent::do_ota_() { if (bufsize < 0) { ESP_LOGE(TAG, "Stream closed"); - this->cleanup_(std::move(backend)); + this->cleanup_(std::move(backend), container); return OTA_CONNECTION_ERROR; - } else if (bufsize > 0 && bufsize <= this->http_recv_buffer_) { + } else if (bufsize > 0 && bufsize <= OtaHttpRequestComponent::HTTP_RECV_BUFFER) { // add read bytes to MD5 md5_receive.add(buf, bufsize); @@ -176,16 +146,16 @@ uint8_t OtaHttpRequestComponent::do_ota_() { // error code explanation available at // https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code, - this->bytes_read_ - bufsize, this->body_length_); - this->cleanup_(std::move(backend)); + container->get_bytes_read() - bufsize, container->content_length); + this->cleanup_(std::move(backend), container); return error_code; } } uint32_t now = millis(); - if ((now - last_progress > 1000) or (this->bytes_read_ == this->body_length_)) { + if ((now - last_progress > 1000) or (container->get_bytes_read() == container->content_length)) { last_progress = now; - float percentage = this->bytes_read_ * 100.0f / this->body_length_; + float percentage = container->get_bytes_read() * 100.0f / container->content_length; ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); #ifdef USE_OTA_STATE_CALLBACK this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0); @@ -201,13 +171,13 @@ uint8_t OtaHttpRequestComponent::do_ota_() { this->md5_computed_ = md5_receive_str.get(); if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) { ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str()); - this->cleanup_(std::move(backend)); + this->cleanup_(std::move(backend), container); return ota::OTA_RESPONSE_ERROR_MD5_MISMATCH; } else { backend->set_update_md5(md5_receive_str.get()); } - this->http_end(); + container->end(); // feed watchdog and give other tasks a chance to run App.feed_wdt(); @@ -217,7 +187,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { error_code = backend->end(); if (error_code != ota::OTA_RESPONSE_OK) { ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); - this->cleanup_(std::move(backend)); + this->cleanup_(std::move(backend), container); return error_code; } @@ -256,28 +226,32 @@ bool OtaHttpRequestComponent::http_get_md5_() { ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str()); ESP_LOGI(TAG, "Connecting to: %s", this->md5_url_.c_str()); - this->http_init(url_with_auth); - if (!this->check_status()) { - this->http_end(); + auto container = this->parent_->get(url_with_auth); + if (container == nullptr) { + ESP_LOGE(TAG, "Failed to connect to MD5 URL"); return false; } - int length = this->body_length_; - if (length < 0) { - this->http_end(); + size_t length = container->content_length; + if (length == 0) { + container->end(); return false; } if (length < MD5_SIZE) { - ESP_LOGE(TAG, "MD5 file must be %u bytes; %u bytes reported by HTTP server. Aborting", MD5_SIZE, - this->body_length_); - this->http_end(); + ESP_LOGE(TAG, "MD5 file must be %u bytes; %u bytes reported by HTTP server. Aborting", MD5_SIZE, length); + container->end(); return false; } - this->bytes_read_ = 0; this->md5_expected_.resize(MD5_SIZE); - auto read_len = this->http_read((uint8_t *) this->md5_expected_.data(), MD5_SIZE); - this->http_end(); + int read_len = 0; + while (container->get_bytes_read() < MD5_SIZE) { + read_len = container->read((uint8_t *) this->md5_expected_.data(), MD5_SIZE); + App.feed_wdt(); + yield(); + } + container->end(); + ESP_LOGV(TAG, "Read len: %u, MD5 expected: %u", read_len, MD5_SIZE); return read_len == MD5_SIZE; } diff --git a/esphome/components/http_request/ota/ota_http_request.h b/esphome/components/http_request/ota/ota_http_request.h index 9fbdf2ec25..91c7085517 100644 --- a/esphome/components/http_request/ota/ota_http_request.h +++ b/esphome/components/http_request/ota/ota_http_request.h @@ -1,13 +1,16 @@ #pragma once +#include "esphome/components/ota/ota_backend.h" #include "esphome/core/component.h" #include "esphome/core/defines.h" -#include "esphome/components/ota/ota_backend.h" +#include "esphome/core/helpers.h" #include #include #include +#include "../http_request.h" + namespace esphome { namespace http_request { @@ -20,7 +23,7 @@ enum OtaHttpRequestError : uint8_t { OTA_CONNECTION_ERROR = 0x12, }; -class OtaHttpRequestComponent : public ota::OTAComponent { +class OtaHttpRequestComponent : public ota::OTAComponent, public Parented { public: void setup() override; void dump_config() override; @@ -29,27 +32,19 @@ class OtaHttpRequestComponent : public ota::OTAComponent { void set_md5_url(const std::string &md5_url); void set_md5(const std::string &md5) { this->md5_expected_ = md5; } void set_password(const std::string &password) { this->password_ = password; } - void set_timeout(const uint64_t timeout) { this->timeout_ = timeout; } void set_url(const std::string &url); void set_username(const std::string &username) { this->username_ = username; } std::string md5_computed() { return this->md5_computed_; } std::string md5_expected() { return this->md5_expected_; } - bool check_status(); - void flash(); - virtual void http_init(const std::string &url){}; - virtual int http_read(uint8_t *buf, size_t len) { return 0; }; - virtual void http_end(){}; - protected: - void cleanup_(std::unique_ptr backend); + void cleanup_(std::unique_ptr backend, const std::shared_ptr &container); uint8_t do_ota_(); std::string get_url_with_auth_(const std::string &url); bool http_get_md5_(); - bool secure_() { return this->url_.find("https:") != std::string::npos; }; bool validate_url_(const std::string &url); std::string md5_computed_{}; @@ -58,14 +53,9 @@ class OtaHttpRequestComponent : public ota::OTAComponent { std::string password_{}; std::string username_{}; std::string url_{}; - size_t body_length_ = 0; - size_t bytes_read_ = 0; int status_ = -1; - uint64_t timeout_ = 0; bool update_started_ = false; - const uint16_t http_recv_buffer_ = 256; // the firmware GET chunk size - const uint16_t max_http_recv_buffer_ = 512; // internal max http buffer size must be > HTTP_RECV_BUFFER_ (TLS - // overhead) and must be a power of two from 512 to 4096 + static const uint16_t HTTP_RECV_BUFFER = 256; // the firmware GET chunk size }; } // namespace http_request diff --git a/esphome/components/http_request/ota/ota_http_request_arduino.cpp b/esphome/components/http_request/ota/ota_http_request_arduino.cpp deleted file mode 100644 index d1dc638d5e..0000000000 --- a/esphome/components/http_request/ota/ota_http_request_arduino.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "ota_http_request.h" -#include "watchdog.h" - -#ifdef USE_ARDUINO -#include "ota_http_request_arduino.h" -#include "esphome/core/defines.h" -#include "esphome/core/log.h" -#include "esphome/core/application.h" -#include "esphome/components/network/util.h" -#include "esphome/components/md5/md5.h" - -namespace esphome { -namespace http_request { - -struct Header { - const char *name; - const char *value; -}; - -void OtaHttpRequestComponentArduino::http_init(const std::string &url) { - const char *header_keys[] = {"Content-Length", "Content-Type"}; - const size_t header_count = sizeof(header_keys) / sizeof(header_keys[0]); - watchdog::WatchdogManager wdts; - -#ifdef USE_ESP8266 - if (this->stream_ptr_ == nullptr && this->set_stream_ptr_()) { - ESP_LOGE(TAG, "Unable to set client"); - return; - } -#endif // USE_ESP8266 - -#ifdef USE_RP2040 - this->client_.setInsecure(); -#endif - - App.feed_wdt(); - -#if defined(USE_ESP32) || defined(USE_RP2040) - this->status_ = this->client_.begin(url.c_str()); -#endif -#ifdef USE_ESP8266 - this->client_.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - this->status_ = this->client_.begin(*this->stream_ptr_, url.c_str()); -#endif - - if (!this->status_) { - this->client_.end(); - return; - } - - this->client_.setReuse(true); - - // returned needed headers must be collected before the requests - this->client_.collectHeaders(header_keys, header_count); - - // HTTP GET - this->status_ = this->client_.GET(); - - this->body_length_ = (size_t) this->client_.getSize(); - -#if defined(USE_ESP32) || defined(USE_RP2040) - if (this->stream_ptr_ == nullptr) { - this->set_stream_ptr_(); - } -#endif -} - -int OtaHttpRequestComponentArduino::http_read(uint8_t *buf, const size_t max_len) { -#ifdef USE_ESP8266 -#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 1, 0) // && USE_ARDUINO_VERSION_CODE < VERSION_CODE(?, ?, ?) - if (!this->secure_()) { - ESP_LOGW(TAG, "Using HTTP on Arduino version >= 3.1 is **very** slow. Consider setting framework version to 3.0.2 " - "in your YAML, or use HTTPS"); - } -#endif // USE_ARDUINO_VERSION_CODE -#endif // USE_ESP8266 - - watchdog::WatchdogManager wdts; - - // Since arduino8266 >= 3.1 using this->stream_ptr_ is broken (https://github.com/esp8266/Arduino/issues/9035) - WiFiClient *stream_ptr = this->client_.getStreamPtr(); - if (stream_ptr == nullptr) { - ESP_LOGE(TAG, "Stream pointer vanished!"); - return -1; - } - - int available_data = stream_ptr->available(); - int bufsize = std::min((int) max_len, available_data); - if (bufsize > 0) { - stream_ptr->readBytes(buf, bufsize); - this->bytes_read_ += bufsize; - buf[bufsize] = '\0'; // not fed to ota - } - - return bufsize; -} - -void OtaHttpRequestComponentArduino::http_end() { - watchdog::WatchdogManager wdts; - this->client_.end(); -} - -int OtaHttpRequestComponentArduino::set_stream_ptr_() { -#ifdef USE_ESP8266 -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS - if (this->secure_()) { - ESP_LOGV(TAG, "ESP8266 HTTPS connection with WiFiClientSecure"); - this->stream_ptr_ = std::make_unique(); - WiFiClientSecure *secure_client = static_cast(this->stream_ptr_.get()); - secure_client->setBufferSizes(this->max_http_recv_buffer_, 512); - secure_client->setInsecure(); - } else { - this->stream_ptr_ = std::make_unique(); - } -#else - ESP_LOGV(TAG, "ESP8266 HTTP connection with WiFiClient"); - if (this->secure_()) { - ESP_LOGE(TAG, "Can't use HTTPS connection with esp8266_disable_ssl_support"); - return -1; - } - this->stream_ptr_ = std::make_unique(); -#endif // USE_HTTP_REQUEST_ESP8266_HTTPS -#endif // USE_ESP8266 - -#if defined(USE_ESP32) || defined(USE_RP2040) - this->stream_ptr_ = std::unique_ptr(this->client_.getStreamPtr()); -#endif - return 0; -} - -} // namespace http_request -} // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/http_request/ota/ota_http_request_arduino.h b/esphome/components/http_request/ota/ota_http_request_arduino.h deleted file mode 100644 index 02bc046520..0000000000 --- a/esphome/components/http_request/ota/ota_http_request_arduino.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "ota_http_request.h" - -#ifdef USE_ARDUINO -#include "esphome/core/automation.h" -#include "esphome/core/component.h" -#include "esphome/core/defines.h" - -#include -#include -#include - -#if defined(USE_ESP32) || defined(USE_RP2040) -#include -#endif -#ifdef USE_ESP8266 -#include -#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS -#include -#endif -#endif - -namespace esphome { -namespace http_request { - -class OtaHttpRequestComponentArduino : public OtaHttpRequestComponent { - public: - void http_init(const std::string &url) override; - int http_read(uint8_t *buf, size_t len) override; - void http_end() override; - - protected: - int set_stream_ptr_(); - HTTPClient client_{}; - std::unique_ptr stream_ptr_; -}; - -} // namespace http_request -} // namespace esphome - -#endif // USE_ARDUINO diff --git a/esphome/components/http_request/ota/ota_http_request_idf.cpp b/esphome/components/http_request/ota/ota_http_request_idf.cpp deleted file mode 100644 index 9fa565d9bb..0000000000 --- a/esphome/components/http_request/ota/ota_http_request_idf.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "ota_http_request_idf.h" -#include "watchdog.h" - -#ifdef USE_ESP_IDF -#include "esphome/core/application.h" -#include "esphome/core/defines.h" -#include "esphome/core/log.h" -#include "esphome/components/md5/md5.h" -#include "esphome/components/network/util.h" - -#include "esp_event.h" -#include "esp_http_client.h" -#include "esp_idf_version.h" -#include "esp_log.h" -#include "esp_netif.h" -#include "esp_system.h" -#include "esp_task_wdt.h" -#include "esp_tls.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "nvs_flash.h" - -#include -#include -#include -#include -#include -#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE -#include "esp_crt_bundle.h" -#endif - -namespace esphome { -namespace http_request { - -void OtaHttpRequestComponentIDF::http_init(const std::string &url) { - App.feed_wdt(); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" - esp_http_client_config_t config = {nullptr}; - config.url = url.c_str(); - config.method = HTTP_METHOD_GET; - config.timeout_ms = (int) this->timeout_; - config.buffer_size = this->max_http_recv_buffer_; - config.auth_type = HTTP_AUTH_TYPE_BASIC; - config.max_authorization_retries = -1; -#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE - if (this->secure_()) { - config.crt_bundle_attach = esp_crt_bundle_attach; - } -#endif -#pragma GCC diagnostic pop - - watchdog::WatchdogManager wdts; - this->client_ = esp_http_client_init(&config); - if ((this->status_ = esp_http_client_open(this->client_, 0)) == ESP_OK) { - this->body_length_ = esp_http_client_fetch_headers(this->client_); - this->status_ = esp_http_client_get_status_code(this->client_); - } -} - -int OtaHttpRequestComponentIDF::http_read(uint8_t *buf, const size_t max_len) { - watchdog::WatchdogManager wdts; - int bufsize = std::min(max_len, this->body_length_ - this->bytes_read_); - - App.feed_wdt(); - int read_len = esp_http_client_read(this->client_, (char *) buf, bufsize); - if (read_len > 0) { - this->bytes_read_ += bufsize; - buf[bufsize] = '\0'; // not fed to ota - } - - return read_len; -} - -void OtaHttpRequestComponentIDF::http_end() { - watchdog::WatchdogManager wdts; - - esp_http_client_close(this->client_); - esp_http_client_cleanup(this->client_); -} - -} // namespace http_request -} // namespace esphome - -#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/ota/ota_http_request_idf.h b/esphome/components/http_request/ota/ota_http_request_idf.h deleted file mode 100644 index 9783b2a3e1..0000000000 --- a/esphome/components/http_request/ota/ota_http_request_idf.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "ota_http_request.h" - -#ifdef USE_ESP_IDF -#include "esp_http_client.h" - -namespace esphome { -namespace http_request { - -class OtaHttpRequestComponentIDF : public OtaHttpRequestComponent { - public: - void http_init(const std::string &url) override; - int http_read(uint8_t *buf, size_t len) override; - void http_end() override; - - protected: - esp_http_client_handle_t client_{}; -}; - -} // namespace http_request -} // namespace esphome - -#endif // USE_ESP_IDF diff --git a/esphome/components/http_request/ota/watchdog.cpp b/esphome/components/http_request/watchdog.cpp similarity index 79% rename from esphome/components/http_request/ota/watchdog.cpp rename to esphome/components/http_request/watchdog.cpp index 663c9afaac..e609feb4dd 100644 --- a/esphome/components/http_request/ota/watchdog.cpp +++ b/esphome/components/http_request/watchdog.cpp @@ -1,7 +1,5 @@ #include "watchdog.h" -#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT - #include "esphome/core/application.h" #include "esphome/core/log.h" @@ -20,14 +18,22 @@ namespace esphome { namespace http_request { namespace watchdog { -static const char *const TAG = "watchdog.http_request.ota"; +static const char *const TAG = "http_request.watchdog"; -WatchdogManager::WatchdogManager() { +WatchdogManager::WatchdogManager(uint32_t timeout_ms) : timeout_ms_(timeout_ms) { + if (timeout_ms == 0) { + return; + } this->saved_timeout_ms_ = this->get_timeout_(); - this->set_timeout_(USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT); + this->set_timeout_(timeout_ms); } -WatchdogManager::~WatchdogManager() { this->set_timeout_(this->saved_timeout_ms_); } +WatchdogManager::~WatchdogManager() { + if (this->timeout_ms_ == 0) { + return; + } + this->set_timeout_(this->saved_timeout_ms_); +} void WatchdogManager::set_timeout_(uint32_t timeout_ms) { ESP_LOGV(TAG, "Adjusting WDT to %" PRIu32 "ms", timeout_ms); @@ -68,4 +74,3 @@ uint32_t WatchdogManager::get_timeout_() { } // namespace watchdog } // namespace http_request } // namespace esphome -#endif diff --git a/esphome/components/http_request/ota/watchdog.h b/esphome/components/http_request/watchdog.h similarity index 84% rename from esphome/components/http_request/ota/watchdog.h rename to esphome/components/http_request/watchdog.h index 0a09dcd6fa..9b54ae6c82 100644 --- a/esphome/components/http_request/ota/watchdog.h +++ b/esphome/components/http_request/watchdog.h @@ -9,9 +9,8 @@ namespace http_request { namespace watchdog { class WatchdogManager { -#ifdef USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT public: - WatchdogManager(); + WatchdogManager(uint32_t timeout_ms); ~WatchdogManager(); private: @@ -19,7 +18,7 @@ class WatchdogManager { void set_timeout_(uint32_t timeout_ms); uint32_t saved_timeout_ms_{0}; -#endif + uint32_t timeout_ms_{0}; }; } // namespace watchdog diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index 0f1b7f236b..bd79d3b2f9 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -8,6 +8,7 @@ double = global_ns.namespace("double") bool_ = global_ns.namespace("bool") int_ = global_ns.namespace("int") std_ns = global_ns.namespace("std") +std_shared_ptr = std_ns.class_("shared_ptr") std_string = std_ns.class_("string") std_vector = std_ns.class_("vector") uint8 = global_ns.namespace("uint8_t") diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml new file mode 100644 index 0000000000..2b6996c0b9 --- /dev/null +++ b/tests/components/http_request/common.yaml @@ -0,0 +1,75 @@ +substitutions: + verify_ssl: "true" + +wifi: + ssid: MySSID + password: password1 + +esphome: + on_boot: + then: + - http_request.get: + url: https://esphome.io + headers: + Content-Type: application/json + on_response: + then: + - logger.log: + format: "Response status: %d, Duration: %u ms" + args: + - response->status_code + - response->duration_ms + - http_request.post: + url: https://esphome.io + headers: + Content-Type: application/json + json: + key: value + - http_request.send: + method: PUT + url: https://esphome.io + headers: + Content-Type: application/json + body: "Some data" + +http_request: + useragent: esphome/tagreader + timeout: 10s + verify_ssl: ${verify_ssl} + +ota: + - platform: http_request + on_begin: + then: + - logger.log: "OTA start" + on_progress: + then: + - logger.log: + format: "OTA progress %0.1f%%" + args: ["x"] + on_end: + then: + - logger.log: "OTA end" + on_error: + then: + - logger.log: + format: "OTA update error %d" + args: ["x"] + on_state_change: + then: + lambda: 'ESP_LOGD("ota", "State %d", state);' + +button: + - platform: template + name: Firmware update + on_press: + then: + - ota.http_request.flash: + md5_url: http://my.ha.net:8123/local/esphome/firmware.md5 + url: http://my.ha.net:8123/local/esphome/firmware.bin + + - ota.http_request.flash: + md5: 0123456789abcdef0123456789abcdef + url: http://my.ha.net:8123/local/esphome/firmware.bin + + - logger.log: "This message should be not displayed (reboot)" diff --git a/tests/components/http_request/common_http_request.yaml b/tests/components/http_request/common_http_request.yaml deleted file mode 100644 index b00768c736..0000000000 --- a/tests/components/http_request/common_http_request.yaml +++ /dev/null @@ -1,33 +0,0 @@ -esphome: - on_boot: - then: - - http_request.get: - url: https://esphome.io - headers: - Content-Type: application/json - verify_ssl: false - on_response: - then: - - logger.log: - format: 'Response status: %d, Duration: %u ms' - args: - - status_code - - duration_ms - - http_request.post: - url: https://esphome.io - headers: - Content-Type: application/json - json: - key: value - verify_ssl: false - - http_request.send: - method: PUT - url: https://esphome.io - headers: - Content-Type: application/json - body: "Some data" - verify_ssl: false - -http_request: - useragent: esphome/tagreader - timeout: 10s diff --git a/tests/components/http_request/common_ota.yaml b/tests/components/http_request/common_ota.yaml deleted file mode 100644 index 10e7d54c3f..0000000000 --- a/tests/components/http_request/common_ota.yaml +++ /dev/null @@ -1,36 +0,0 @@ -wifi: - ssid: MySSID - password: password1 - -ota: - - platform: http_request - verify_ssl: ${verify_ssl} - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: 'ESP_LOGD("ota", "State %d", state);' - -button: - - platform: template - name: Firmware update - on_press: - then: - - ota_http_request.flash: - md5_url: http://my.ha.net:8123/local/esphome/firmware.md5 - url: http://my.ha.net:8123/local/esphome/firmware.bin - - logger.log: "This message should be not displayed (reboot)" diff --git a/tests/components/http_request/test-nossl.esp8266.yaml b/tests/components/http_request/test-nossl.esp8266.yaml index 65116d5550..9fc4706c89 100644 --- a/tests/components/http_request/test-nossl.esp8266.yaml +++ b/tests/components/http_request/test-nossl.esp8266.yaml @@ -1,38 +1,4 @@ -<<: !include common_http_request.yaml +<<: !include common.yaml -wifi: - ssid: MySSID - password: password1 - -ota: - - platform: http_request - esp8266_disable_ssl_support: true - on_begin: - then: - - logger.log: "OTA start" - on_progress: - then: - - logger.log: - format: "OTA progress %0.1f%%" - args: ["x"] - on_end: - then: - - logger.log: "OTA end" - on_error: - then: - - logger.log: - format: "OTA update error %d" - args: ["x"] - on_state_change: - then: - lambda: 'ESP_LOGD("ota", "State %d", state);' - -button: - - platform: template - name: Firmware update - on_press: - then: - - ota_http_request.flash: - md5_url: http://my.ha.net:8123/local/esphome/firmware.md5 - url: http://my.ha.net:8123/local/esphome/firmware.bin - - logger.log: "This message should be not displayed (reboot)" +http_request: + esp8266_disable_ssl_support: true diff --git a/tests/components/http_request/test.esp32-c3-idf.yaml b/tests/components/http_request/test.esp32-c3-idf.yaml index da629e83a9..ee2f5aa59b 100644 --- a/tests/components/http_request/test.esp32-c3-idf.yaml +++ b/tests/components/http_request/test.esp32-c3-idf.yaml @@ -1,4 +1,4 @@ substitutions: verify_ssl: "true" -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/components/http_request/test.esp32-c3.yaml b/tests/components/http_request/test.esp32-c3.yaml index 1f597bb500..c1937b5a10 100644 --- a/tests/components/http_request/test.esp32-c3.yaml +++ b/tests/components/http_request/test.esp32-c3.yaml @@ -1,5 +1,4 @@ substitutions: verify_ssl: "false" -<<: !include common_http_request.yaml -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/components/http_request/test.esp32-idf.yaml b/tests/components/http_request/test.esp32-idf.yaml index da629e83a9..ee2f5aa59b 100644 --- a/tests/components/http_request/test.esp32-idf.yaml +++ b/tests/components/http_request/test.esp32-idf.yaml @@ -1,4 +1,4 @@ substitutions: verify_ssl: "true" -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/components/http_request/test.esp32.yaml b/tests/components/http_request/test.esp32.yaml index 1f597bb500..c1937b5a10 100644 --- a/tests/components/http_request/test.esp32.yaml +++ b/tests/components/http_request/test.esp32.yaml @@ -1,5 +1,4 @@ substitutions: verify_ssl: "false" -<<: !include common_http_request.yaml -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/components/http_request/test.esp8266.yaml b/tests/components/http_request/test.esp8266.yaml index 1f597bb500..c1937b5a10 100644 --- a/tests/components/http_request/test.esp8266.yaml +++ b/tests/components/http_request/test.esp8266.yaml @@ -1,5 +1,4 @@ substitutions: verify_ssl: "false" -<<: !include common_http_request.yaml -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/components/http_request/test.rp2040.yaml b/tests/components/http_request/test.rp2040.yaml index 077e4d82da..c1937b5a10 100644 --- a/tests/components/http_request/test.rp2040.yaml +++ b/tests/components/http_request/test.rp2040.yaml @@ -1,4 +1,4 @@ substitutions: verify_ssl: "false" -<<: !include common_ota.yaml +<<: !include common.yaml diff --git a/tests/test1.yaml b/tests/test1.yaml index c49ff307e5..2dacfda536 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -25,31 +25,6 @@ esphome: then: - lambda: >- ESP_LOGV("main", "ON LOOP!"); - - http_request.get: - url: https://esphome.io - headers: - Content-Type: application/json - verify_ssl: false - - http_request.post: - url: https://esphome.io - verify_ssl: false - json: - key: !lambda |- - return id(${textname}_text).state; - greeting: Hello World - - http_request.send: - method: PUT - url: https://esphome.io - headers: - Content-Type: application/json - body: Some data - verify_ssl: false - on_response: - then: - - logger.log: - format: "Response status: %d" - args: - - status_code build_path: build/test1 packages: @@ -84,10 +59,6 @@ network: mdns: disabled: false -http_request: - useragent: esphome/device - timeout: 10s - mqtt: broker: "192.168.178.84" port: 1883 diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 018a4d94f3..c3b078fe67 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -447,26 +447,6 @@ switch: switches: - id: custom_switch name: Custom Switch - on_turn_on: - - http_request.get: - url: https://esphome.io - headers: - Content-Type: application/json - verify_ssl: false - - http_request.post: - url: https://esphome.io - verify_ssl: false - json: - key: !lambda |- - return id(custom_text_sensor).state; - greeting: Hello World - - http_request.send: - method: PUT - url: https://esphome.io - headers: - Content-Type: application/json - body: Some data - verify_ssl: false - platform: template name: open_vent id: open_vent @@ -722,10 +702,6 @@ display: lambda: |- it.printdigit("hello"); -http_request: - useragent: esphome/device - timeout: 10s - button: - platform: output id: output_button diff --git a/tests/test7.yaml b/tests/test7.yaml index b22fbfbcb4..ac193eae4e 100644 --- a/tests/test7.yaml +++ b/tests/test7.yaml @@ -1,7 +1,7 @@ # Tests for ESP32-C3 boards which use toolchain-riscv32-esp --- wifi: - ssid: 'ssid' + ssid: "ssid" network: enable_ipv6: true @@ -12,31 +12,12 @@ esp32: type: arduino esphome: - name: 'on-response-test' - on_boot: - then: - - http_request.send: - method: PUT - url: https://esphome.io - headers: - Content-Type: application/json - body: Some data - verify_ssl: false - on_response: - then: - - logger.log: - format: "Response status: %d" - args: - - status_code + name: test7 logger: debug: -http_request: - useragent: esphome/tagreader - timeout: 10s - sensor: - platform: adc id: adc_sensor_p4 From 6de79d6cfbdf42b5fdc9b1f880b86210900dab5a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:22:41 +1200 Subject: [PATCH 1858/2607] [i2s_speaker] A few fixes (#6872) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 40 +++++++++++++++---- .../i2s_audio/speaker/i2s_audio_speaker.h | 2 +- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 546c2c98f7..6b07ecb1b6 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -38,15 +38,22 @@ void I2SAudioSpeaker::start() { ESP_LOGE(TAG, "Cannot start audio, speaker failed to setup"); return; } + if (this->task_created_) { + ESP_LOGW(TAG, "Called start while task has been already created."); + return; + } this->state_ = speaker::STATE_STARTING; } void I2SAudioSpeaker::start_() { + if (this->task_created_) { + return; + } if (!this->parent_->try_lock()) { return; // Waiting for another i2s component to return lock } - this->state_ = speaker::STATE_RUNNING; xTaskCreate(I2SAudioSpeaker::player_task, "speaker_task", 8192, (void *) this, 1, &this->player_task_handle_); + this->task_created_ = true; } void I2SAudioSpeaker::player_task(void *params) { @@ -131,7 +138,16 @@ void I2SAudioSpeaker::player_task(void *params) { (10 / portTICK_PERIOD_MS)); if (err != ESP_OK) { event = {.type = TaskEventType::WARNING, .err = err}; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); + if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { + ESP_LOGW(TAG, "Failed to send WARNING event"); + } + continue; + } + if (bytes_written != sizeof(sample)) { + event = {.type = TaskEventType::WARNING, .err = ESP_FAIL}; + if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { + ESP_LOGW(TAG, "Failed to send WARNING event"); + } continue; } remaining--; @@ -139,18 +155,25 @@ void I2SAudioSpeaker::player_task(void *params) { } event.type = TaskEventType::PLAYING; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); + event.err = current; + if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { + ESP_LOGW(TAG, "Failed to send PLAYING event"); + } + } + + event.type = TaskEventType::STOPPING; + if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { + ESP_LOGW(TAG, "Failed to send STOPPING event"); } i2s_zero_dma_buffer(this_speaker->parent_->get_port()); - event.type = TaskEventType::STOPPING; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); - i2s_driver_uninstall(this_speaker->parent_->get_port()); event.type = TaskEventType::STOPPED; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); + if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { + ESP_LOGW(TAG, "Failed to send STOPPED event"); + } while (true) { delay(10); @@ -181,6 +204,7 @@ void I2SAudioSpeaker::watch_() { break; case TaskEventType::STARTED: ESP_LOGD(TAG, "Started I2S Audio Speaker"); + this->state_ = speaker::STATE_RUNNING; break; case TaskEventType::STOPPING: ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); @@ -191,6 +215,7 @@ void I2SAudioSpeaker::watch_() { case TaskEventType::STOPPED: this->state_ = speaker::STATE_STOPPED; vTaskDelete(this->player_task_handle_); + this->task_created_ = false; this->player_task_handle_ = nullptr; this->parent_->unlock(); xQueueReset(this->buffer_queue_); @@ -208,7 +233,6 @@ void I2SAudioSpeaker::loop() { switch (this->state_) { case speaker::STATE_STARTING: this->start_(); - break; case speaker::STATE_RUNNING: case speaker::STATE_STOPPING: this->watch_(); diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 20c36a69d3..1800feaeec 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -60,7 +60,6 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud protected: void start_(); - // void stop_(); void watch_(); static void player_task(void *params); @@ -70,6 +69,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud QueueHandle_t event_queue_; uint8_t dout_pin_{0}; + bool task_created_{false}; #if SOC_I2S_SUPPORTS_DAC i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE}; From dceab6ce29493e67caaa8cdadf8cf7f4df063635 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:22:55 +1200 Subject: [PATCH 1859/2607] [voice_assistant] Write less data to speaker each loop (#6877) --- esphome/components/voice_assistant/voice_assistant.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index e4fd2f2e9d..1fa8236cf4 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -428,14 +428,15 @@ void VoiceAssistant::loop() { #ifdef USE_SPEAKER void VoiceAssistant::write_speaker_() { if (this->speaker_buffer_size_ > 0) { - size_t written = this->speaker_->play(this->speaker_buffer_, this->speaker_buffer_size_); + size_t write_chunk = std::min(this->speaker_buffer_size_, 4 * 1024); + size_t written = this->speaker_->play(this->speaker_buffer_, write_chunk); if (written > 0) { memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); this->speaker_buffer_size_ -= written; this->speaker_buffer_index_ -= written; this->set_timeout("speaker-timeout", 5000, [this]() { this->speaker_->stop(); }); } else { - ESP_LOGD(TAG, "Speaker buffer full, trying again next loop"); + ESP_LOGV(TAG, "Speaker buffer full, trying again next loop"); } } } @@ -798,7 +799,7 @@ void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { this->speaker_buffer_index_ += msg.data.length(); this->speaker_buffer_size_ += msg.data.length(); this->speaker_bytes_received_ += msg.data.length(); - ESP_LOGD(TAG, "Received audio: %d bytes from API", msg.data.length()); + ESP_LOGV(TAG, "Received audio: %" PRId32 " bytes from API", msg.data.length()); } else { ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); } From 51a8a7e875fff4d9687f743a4fc8c02a6f201e9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:17:18 +1200 Subject: [PATCH 1860/2607] Bump docker/build-push-action from 5.3.0 to 5.4.0 in /.github/actions/build-image (#6883) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index d36bd65bb6..d792ab5f4c 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v5.3.0 + uses: docker/build-push-action@v5.4.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v5.3.0 + uses: docker/build-push-action@v5.4.0 with: context: . file: ./docker/Dockerfile From 95e45dc12c9e313cbb5787978b3e067f581c76c9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:40:56 +1200 Subject: [PATCH 1861/2607] Allow parse_json to return a boolean result (#6884) * Allow parse_json to return a boolean result * Remove pass variable --- esphome/components/json/json_util.cpp | 17 ++++++++--------- esphome/components/json/json_util.h | 4 ++-- esphome/components/mqtt/mqtt_client.cpp | 5 ++++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index bef494b64d..89ec13fe5b 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -62,7 +62,7 @@ std::string build_json(const json_build_t &f) { } } -void parse_json(const std::string &data, const json_parse_t &f) { +bool parse_json(const std::string &data, const json_parse_t &f) { // Here we are allocating 1.5 times the data size, // with the heap size minus 2kb to be safe if less than that // as we can not have a true dynamic sized document. @@ -76,14 +76,13 @@ void parse_json(const std::string &data, const json_parse_t &f) { #elif defined(USE_LIBRETINY) const size_t free_heap = lt_heap_get_free(); #endif - bool pass = false; size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5)); - do { + while (true) { DynamicJsonDocument json_document(request_size); if (json_document.capacity() == 0) { ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, free heap: %u", request_size, free_heap); - return; + return false; } DeserializationError err = deserializeJson(json_document, data); json_document.shrinkToFit(); @@ -91,21 +90,21 @@ void parse_json(const std::string &data, const json_parse_t &f) { JsonObject root = json_document.as(); if (err == DeserializationError::Ok) { - pass = true; - f(root); + return f(root); } else if (err == DeserializationError::NoMemory) { if (request_size * 2 >= free_heap) { ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller"); - return; + return false; } ESP_LOGV(TAG, "Increasing memory allocation."); request_size *= 2; continue; } else { ESP_LOGE(TAG, "JSON parse error: %s", err.c_str()); - return; + return false; } - } while (!pass); + }; + return false; } } // namespace json diff --git a/esphome/components/json/json_util.h b/esphome/components/json/json_util.h index 2299a4cfed..72d31c8afe 100644 --- a/esphome/components/json/json_util.h +++ b/esphome/components/json/json_util.h @@ -14,7 +14,7 @@ namespace esphome { namespace json { /// Callback function typedef for parsing JsonObjects. -using json_parse_t = std::function; +using json_parse_t = std::function; /// Callback function typedef for building JsonObjects. using json_build_t = std::function; @@ -23,7 +23,7 @@ using json_build_t = std::function; std::string build_json(const json_build_t &f); /// Parse a JSON string and run the provided json parse function if it's valid. -void parse_json(const std::string &data, const json_parse_t &f); +bool parse_json(const std::string &data, const json_parse_t &f); } // namespace json } // namespace esphome diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index abcbb414d9..d70b9cbd30 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -410,7 +410,10 @@ void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t ca void MQTTClientComponent::subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos) { auto f = [callback](const std::string &topic, const std::string &payload) { - json::parse_json(payload, [topic, callback](JsonObject root) { callback(topic, root); }); + json::parse_json(payload, [topic, callback](JsonObject root) -> bool { + callback(topic, root); + return true; + }); }; MQTTSubscription subscription{ .topic = topic, From 7dc07c5632a14986c7050639897eca8a7768d100 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Tue, 11 Jun 2024 11:33:42 +1200 Subject: [PATCH 1862/2607] Update webserver local assets to 20240610-230854 (#6886) --- .../components/web_server/server_index_v2.h | 1246 +++++++++-------- .../components/web_server/server_index_v3.h | 728 +++++----- 2 files changed, 994 insertions(+), 980 deletions(-) diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index 7417f37015..c942cda592 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -10,625 +10,633 @@ namespace esphome { namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xd9, 0x92, 0xdb, 0x46, 0xb6, 0xe0, 0xf3, - 0xdc, 0xaf, 0x40, 0xa5, 0xab, 0x4b, 0xc8, 0x66, 0x12, 0x45, 0xb2, 0xb4, 0x19, 0xac, 0x24, 0xbb, 0x54, 0x92, 0x5b, - 0x76, 0x6b, 0xb1, 0x55, 0x92, 0xdd, 0x36, 0xcd, 0xae, 0x42, 0x11, 0x49, 0x32, 0x2d, 0x10, 0x49, 0x03, 0xc9, 0x5a, - 0x4c, 0xe2, 0xc6, 0x7c, 0xc0, 0x44, 0x4c, 0xc4, 0x3c, 0xcd, 0xcb, 0xc4, 0xdc, 0x87, 0xf9, 0x88, 0x79, 0xbe, 0x9f, - 0x72, 0x7f, 0x60, 0xe6, 0x13, 0x26, 0x4e, 0x2e, 0x40, 0x82, 0x4b, 0xa9, 0xbc, 0xdc, 0x1b, 0x13, 0x0a, 0x49, 0x44, - 0xae, 0x27, 0x4f, 0x9e, 0x3c, 0x7b, 0x02, 0xc7, 0x7b, 0xb1, 0x18, 0xc9, 0xdb, 0x39, 0xf3, 0xa6, 0x72, 0x96, 0xf4, - 0x8e, 0xcd, 0xbf, 0x2c, 0x8a, 0x7b, 0xc7, 0x09, 0x4f, 0x3f, 0x7a, 0x19, 0x4b, 0x28, 0x1f, 0x89, 0xd4, 0x9b, 0x66, - 0x6c, 0x4c, 0xe3, 0x48, 0x46, 0x21, 0x9f, 0x45, 0x13, 0xe6, 0x1d, 0xf6, 0x8e, 0x67, 0x4c, 0x46, 0xde, 0x68, 0x1a, - 0x65, 0x39, 0x93, 0xf4, 0xc3, 0xfb, 0x2f, 0x9a, 0x4f, 0x7b, 0xc7, 0xf9, 0x28, 0xe3, 0x73, 0xe9, 0xc1, 0x90, 0x74, - 0x26, 0xe2, 0x45, 0xc2, 0x7a, 0x87, 0x87, 0xd7, 0xd7, 0xd7, 0xc1, 0x4f, 0xf9, 0x3f, 0x8d, 0x44, 0x9a, 0x4b, 0xef, - 0x15, 0xbd, 0xe6, 0x69, 0x2c, 0xae, 0x09, 0x93, 0xf4, 0x55, 0x70, 0x36, 0x8d, 0x62, 0x71, 0xfd, 0x4e, 0x08, 0x79, - 0x70, 0xe0, 0xeb, 0xc7, 0xdb, 0xd3, 0xb3, 0x33, 0x4a, 0xe9, 0x95, 0xe0, 0xb1, 0xd7, 0x5a, 0xad, 0xaa, 0xc2, 0x20, - 0x8d, 0x24, 0xbf, 0x62, 0xba, 0x0b, 0x3e, 0x38, 0x40, 0x51, 0x2c, 0xe6, 0x92, 0xc5, 0x67, 0xf2, 0x36, 0x61, 0x67, - 0x53, 0xc6, 0x64, 0x8e, 0x78, 0xea, 0x3d, 0x17, 0xa3, 0xc5, 0x8c, 0xa5, 0x32, 0x98, 0x67, 0x42, 0x0a, 0x80, 0xe4, - 0xe0, 0x00, 0x65, 0x6c, 0x9e, 0x44, 0x23, 0x06, 0xf5, 0xa7, 0x67, 0x67, 0x55, 0x8f, 0xaa, 0x11, 0xe1, 0x92, 0x9e, - 0xdd, 0xce, 0x2e, 0x45, 0xe2, 0x63, 0x92, 0x48, 0x9a, 0xb2, 0x6b, 0xef, 0x3b, 0x16, 0x7d, 0x7c, 0x1d, 0xcd, 0xbb, - 0xa3, 0x24, 0xca, 0x73, 0xef, 0x52, 0x2e, 0xd5, 0x12, 0xb2, 0xc5, 0x48, 0x8a, 0xcc, 0x97, 0x84, 0x11, 0x8e, 0x97, - 0x7c, 0xec, 0xcb, 0x29, 0xcf, 0x83, 0xf3, 0xfd, 0x51, 0x9e, 0xbf, 0x63, 0xf9, 0x22, 0x91, 0xfb, 0x74, 0xaf, 0x45, - 0xf8, 0x1e, 0xa5, 0x5c, 0x62, 0x39, 0xcd, 0xc4, 0xb5, 0xf7, 0x22, 0xcb, 0x44, 0xe6, 0xa3, 0xd3, 0xb3, 0x33, 0xdd, - 0xc2, 0xe3, 0xb9, 0x97, 0x0a, 0xe9, 0x95, 0xe3, 0x45, 0x97, 0x09, 0x0b, 0xbc, 0x0f, 0x39, 0xf3, 0x2e, 0x16, 0x69, - 0x1e, 0x8d, 0xd9, 0xe9, 0xd9, 0xd9, 0x85, 0x27, 0x32, 0xef, 0x62, 0x94, 0xe7, 0x17, 0x1e, 0x4f, 0x73, 0xc9, 0xa2, - 0x38, 0x40, 0xb8, 0xab, 0x26, 0x1b, 0xe5, 0xf9, 0x7b, 0x76, 0x23, 0xa9, 0x24, 0xea, 0x51, 0x52, 0x56, 0x4c, 0x98, - 0xf4, 0xf2, 0x72, 0x5d, 0x3e, 0x5e, 0x26, 0x4c, 0x7a, 0x92, 0xaa, 0x7a, 0xd1, 0xd5, 0xb8, 0x67, 0xfa, 0x51, 0x76, - 0xf9, 0xd8, 0x67, 0xf2, 0xe0, 0x40, 0x96, 0x78, 0xc6, 0x7a, 0x69, 0x1e, 0xa7, 0x6c, 0xcf, 0x96, 0x1d, 0x1c, 0xb0, - 0x20, 0x61, 0xe9, 0x44, 0x4e, 0x29, 0xa5, 0xed, 0x2e, 0x3f, 0x38, 0xf0, 0x25, 0x4d, 0x64, 0x30, 0x61, 0xd2, 0x67, - 0x18, 0x93, 0xaa, 0xf7, 0xc1, 0x81, 0xaf, 0x91, 0x20, 0xa8, 0x46, 0x5c, 0x0d, 0xc7, 0x38, 0x30, 0xd8, 0x3f, 0xbb, - 0x4d, 0x47, 0xbe, 0x0b, 0x3f, 0x26, 0xfc, 0xe0, 0x20, 0x91, 0x41, 0x0e, 0x23, 0x12, 0x89, 0x71, 0x91, 0x31, 0xb9, - 0xc8, 0x52, 0x4f, 0x16, 0x52, 0x9c, 0xc9, 0x8c, 0xa7, 0x13, 0x1f, 0x2f, 0x6d, 0x99, 0xd3, 0xb1, 0x28, 0x34, 0xb8, - 0x5f, 0x4b, 0x9a, 0xd1, 0x1e, 0xcc, 0x78, 0x29, 0x7d, 0xd8, 0x45, 0x31, 0xf6, 0x32, 0x4a, 0x51, 0xae, 0xfa, 0xa2, - 0x7e, 0x16, 0x66, 0x0d, 0x84, 0x88, 0x86, 0x92, 0x70, 0x89, 0xc9, 0x47, 0xea, 0x67, 0x24, 0x08, 0x02, 0x89, 0x69, - 0x6f, 0x69, 0xb1, 0x92, 0x39, 0xeb, 0xec, 0x67, 0x83, 0xd6, 0x30, 0x94, 0x41, 0xc6, 0xe2, 0xc5, 0x88, 0xf9, 0x3e, - 0x27, 0x39, 0x49, 0x31, 0xed, 0xf1, 0x86, 0x2f, 0x68, 0x0f, 0xb6, 0x5b, 0xd4, 0xf7, 0x9a, 0xd2, 0xbd, 0x16, 0x36, - 0x30, 0x0a, 0x0b, 0x20, 0x60, 0xd8, 0xc0, 0x23, 0x28, 0x45, 0xe9, 0x62, 0x76, 0xc9, 0x32, 0x54, 0x36, 0xeb, 0xd6, - 0xc8, 0x62, 0x91, 0x33, 0x6f, 0x94, 0xe7, 0xde, 0x78, 0x91, 0x8e, 0x24, 0x17, 0xa9, 0x87, 0x1a, 0xa2, 0x81, 0x34, - 0x39, 0x94, 0xd4, 0x80, 0x70, 0x81, 0xfd, 0x1c, 0x37, 0xb2, 0x41, 0xda, 0x68, 0x0f, 0x09, 0x40, 0x89, 0xbb, 0x66, - 0x3c, 0x83, 0x00, 0x46, 0x32, 0x58, 0x63, 0x41, 0x3e, 0x48, 0x58, 0xa5, 0x5a, 0x22, 0x93, 0xfd, 0x2c, 0xd8, 0x3c, - 0x28, 0x54, 0x06, 0xb3, 0x68, 0xee, 0x33, 0xda, 0x63, 0x8a, 0xb8, 0xa2, 0x74, 0x04, 0xb0, 0xd6, 0xf6, 0xad, 0xcf, - 0x42, 0x16, 0x54, 0x24, 0x85, 0x43, 0x19, 0x8c, 0x45, 0xf6, 0x22, 0x1a, 0x4d, 0xa1, 0x5f, 0x49, 0x30, 0xb1, 0x3d, - 0x6f, 0xa3, 0x8c, 0x45, 0x92, 0xbd, 0x48, 0x18, 0x3c, 0xf9, 0x48, 0xf5, 0x44, 0x98, 0xe4, 0xf4, 0x55, 0x90, 0x70, - 0xf9, 0x46, 0xa4, 0x23, 0xd6, 0xcd, 0x1d, 0xea, 0xe2, 0xb0, 0xef, 0x27, 0x52, 0x66, 0xfc, 0x72, 0x21, 0x99, 0x8f, - 0x52, 0x68, 0x81, 0x48, 0x8e, 0x09, 0x0f, 0x24, 0xbb, 0x91, 0xa7, 0x22, 0x95, 0x2c, 0x95, 0x94, 0x59, 0xa4, 0x92, - 0x2c, 0x88, 0xe6, 0x73, 0x96, 0xc6, 0xa7, 0x53, 0x9e, 0xc4, 0x3e, 0xc7, 0x05, 0x2e, 0x48, 0x24, 0x29, 0xac, 0x91, - 0xf6, 0xb2, 0x10, 0xfe, 0xd9, 0xbd, 0x1a, 0x5f, 0xd2, 0x9e, 0x3a, 0x14, 0x8c, 0x22, 0xd4, 0x1d, 0x8b, 0xcc, 0x37, - 0x2b, 0xf0, 0xc4, 0xd8, 0x93, 0x30, 0xc7, 0xbb, 0x45, 0xc2, 0x72, 0xcc, 0x1a, 0x94, 0x97, 0xdb, 0x68, 0x10, 0xfc, - 0x35, 0x50, 0x7c, 0x81, 0xfd, 0x0c, 0x87, 0x59, 0xf7, 0x2a, 0xca, 0xbc, 0x2f, 0xcc, 0x89, 0xfa, 0xc9, 0x72, 0xb3, - 0xa9, 0xa4, 0x3f, 0x05, 0x32, 0x5b, 0xe4, 0x92, 0xc5, 0xef, 0x6f, 0xe7, 0x2c, 0x27, 0xef, 0x25, 0x9d, 0xca, 0xfe, - 0x54, 0x06, 0x6c, 0x36, 0x97, 0xb7, 0x67, 0x8a, 0x31, 0x86, 0x08, 0x91, 0x11, 0xb4, 0xcc, 0x58, 0x34, 0x02, 0x66, - 0x66, 0xb0, 0xf5, 0xb5, 0x48, 0x6e, 0xc7, 0x3c, 0x49, 0xce, 0x16, 0xf3, 0xb9, 0xc8, 0x24, 0xf9, 0x2b, 0x5d, 0x4a, - 0x51, 0xa1, 0x06, 0xf6, 0x72, 0x99, 0x5f, 0x73, 0x39, 0x9a, 0xfa, 0x12, 0x2f, 0x47, 0x51, 0xce, 0xbc, 0x67, 0x42, - 0x24, 0x2c, 0x4a, 0xc3, 0x8c, 0x66, 0xfd, 0xf7, 0x32, 0x4c, 0x17, 0x49, 0xd2, 0xbd, 0xcc, 0x58, 0xf4, 0xb1, 0xab, - 0xaa, 0xdf, 0x5e, 0xfe, 0xc4, 0x46, 0x32, 0x54, 0xbf, 0x4f, 0xb2, 0x2c, 0xba, 0x85, 0x86, 0x94, 0x42, 0xb3, 0x7e, - 0x16, 0x7e, 0x75, 0xf6, 0xf6, 0x4d, 0xa0, 0x0f, 0x09, 0x1f, 0xdf, 0xfa, 0x59, 0x79, 0xf0, 0xb2, 0x82, 0x8c, 0x33, - 0x31, 0x5b, 0x9b, 0x5a, 0x63, 0x2d, 0xeb, 0xee, 0x00, 0x81, 0xd1, 0x6c, 0x4f, 0x0f, 0xed, 0x42, 0xf0, 0x46, 0xd1, - 0x3c, 0x54, 0x52, 0x33, 0x2f, 0xfc, 0x13, 0xea, 0x62, 0x3f, 0xc3, 0x77, 0x43, 0x2b, 0xb3, 0xdb, 0x25, 0xa3, 0x0a, - 0xce, 0x39, 0x48, 0x18, 0x80, 0x71, 0x14, 0xc9, 0xd1, 0x74, 0xc9, 0xd4, 0x60, 0x85, 0x85, 0x98, 0x15, 0x05, 0xb9, - 0x2e, 0xe9, 0x5d, 0xee, 0x51, 0x9a, 0x29, 0x46, 0x45, 0xe5, 0x6a, 0x95, 0x51, 0x9a, 0x61, 0xf2, 0x1d, 0x5d, 0x46, - 0x76, 0x3d, 0xe1, 0x5e, 0x8b, 0xc0, 0xb9, 0x0c, 0x35, 0x77, 0x21, 0x23, 0x91, 0x5e, 0xb1, 0x4c, 0xb2, 0x2c, 0xfc, - 0x2b, 0xc9, 0xd8, 0x38, 0x01, 0x28, 0xf6, 0xda, 0x64, 0x1a, 0xe5, 0xa7, 0xd3, 0x28, 0x9d, 0xb0, 0x38, 0xbc, 0x96, - 0x05, 0xf9, 0x3b, 0x45, 0x63, 0x9e, 0x46, 0x09, 0xff, 0x85, 0xc5, 0xc8, 0x48, 0x83, 0x13, 0x8f, 0xdd, 0x48, 0x96, - 0xc6, 0xb9, 0xf7, 0xf2, 0xfd, 0xeb, 0x57, 0x66, 0x1f, 0x6b, 0x02, 0x02, 0x2f, 0xf3, 0xc5, 0x9c, 0x65, 0x3e, 0x26, - 0x46, 0x40, 0xbc, 0xe0, 0x8a, 0x39, 0xbe, 0x8e, 0xe6, 0xba, 0x84, 0xe7, 0x1f, 0xe6, 0x71, 0x24, 0xd9, 0xd7, 0x2c, - 0x8d, 0x79, 0x3a, 0xa1, 0x7b, 0x6d, 0x5d, 0x3e, 0x8d, 0x4c, 0x45, 0x5c, 0x16, 0x9d, 0xef, 0xbf, 0x48, 0xd4, 0xba, - 0xcb, 0xc7, 0x85, 0x8f, 0x8b, 0x5c, 0x46, 0x92, 0x8f, 0xbc, 0x28, 0x8e, 0xbf, 0x4c, 0xb9, 0xe4, 0x0a, 0xc0, 0x0c, - 0xb6, 0x07, 0x48, 0x94, 0x69, 0x51, 0x61, 0x01, 0xf7, 0x31, 0xf1, 0x7d, 0x23, 0x00, 0xa6, 0xd8, 0xec, 0xd7, 0xc1, - 0x41, 0xc5, 0xee, 0xfb, 0x2c, 0xd4, 0x95, 0x74, 0x30, 0xc4, 0xc1, 0x7c, 0x91, 0xc3, 0x46, 0xdb, 0x29, 0x40, 0xba, - 0x88, 0xcb, 0x9c, 0x65, 0x57, 0x2c, 0x2e, 0x89, 0x23, 0xf7, 0xf1, 0x72, 0x6d, 0x0e, 0x73, 0x2c, 0x24, 0x1d, 0x0c, - 0xbb, 0x2e, 0xdf, 0x66, 0x86, 0xce, 0x33, 0x31, 0x67, 0x99, 0xe4, 0x2c, 0x2f, 0x59, 0x89, 0x0f, 0x52, 0xb4, 0x64, - 0x27, 0x39, 0xb5, 0xeb, 0x9b, 0xfb, 0x9c, 0x30, 0x5c, 0x63, 0x18, 0x56, 0xd0, 0xbe, 0xb8, 0x52, 0x12, 0x23, 0x27, - 0x1c, 0x13, 0xa9, 0x21, 0xcd, 0x31, 0x2e, 0x30, 0x91, 0x16, 0x5c, 0xcd, 0x8a, 0xcc, 0x6c, 0xb7, 0x20, 0xaa, 0xe9, - 0x77, 0x4a, 0x54, 0x03, 0x43, 0x8b, 0x24, 0x3b, 0x38, 0xf0, 0x59, 0x50, 0x12, 0x05, 0xdd, 0x6b, 0x9b, 0x3d, 0x72, - 0x90, 0xb5, 0x03, 0x6c, 0x98, 0x58, 0x12, 0x86, 0xc9, 0x1e, 0x0b, 0x52, 0x71, 0x32, 0x1a, 0xb1, 0x3c, 0x17, 0xd9, - 0xc1, 0xc1, 0x9e, 0x6a, 0x5f, 0x6a, 0x13, 0xb0, 0x87, 0x6f, 0xaf, 0xd3, 0x0a, 0x02, 0x5c, 0x49, 0x58, 0x23, 0x17, - 0x24, 0xc8, 0x29, 0xa5, 0x70, 0xa0, 0xbe, 0x55, 0x3c, 0x42, 0x74, 0x7e, 0x8e, 0x1a, 0x92, 0x18, 0x34, 0x4c, 0x98, - 0x9d, 0xfa, 0xf6, 0x39, 0xd3, 0xaa, 0x95, 0x52, 0x3c, 0x36, 0x30, 0xa3, 0xcf, 0x4f, 0x10, 0xb3, 0x31, 0x4f, 0x9d, - 0x65, 0xd7, 0x40, 0x22, 0x92, 0xe4, 0xb8, 0x70, 0x36, 0x74, 0xeb, 0xd0, 0x4a, 0xa7, 0xd1, 0x3b, 0xb7, 0x9c, 0x28, - 0x3d, 0xc2, 0xd9, 0xc6, 0x01, 0x1b, 0x16, 0x44, 0xa1, 0xde, 0xae, 0x26, 0x55, 0x80, 0x0e, 0xe4, 0xb0, 0x6b, 0xea, - 0x69, 0xae, 0x31, 0x97, 0xb1, 0x9f, 0x17, 0x2c, 0x97, 0x9a, 0x8e, 0x7d, 0x49, 0x52, 0xc2, 0x71, 0x01, 0xc7, 0x6d, - 0xcc, 0x27, 0x8b, 0x0c, 0xd4, 0x1d, 0x38, 0x8a, 0x2c, 0x5d, 0xcc, 0x98, 0x7d, 0xda, 0x06, 0xdb, 0xdb, 0x39, 0x08, - 0xc4, 0x1c, 0x68, 0xfa, 0x6e, 0x72, 0x02, 0x58, 0x25, 0x5e, 0xad, 0xbe, 0xb3, 0x83, 0x54, 0x5b, 0x59, 0xaa, 0x68, - 0x6b, 0x7b, 0xf2, 0x77, 0x6c, 0xe4, 0xf1, 0x5e, 0x5b, 0x43, 0xff, 0xf7, 0x21, 0xdd, 0x6b, 0x95, 0x14, 0x6c, 0x70, - 0xaa, 0x81, 0xd1, 0x28, 0x7c, 0xab, 0x07, 0xc2, 0x4a, 0xba, 0xd7, 0x88, 0x25, 0x98, 0x6e, 0xd0, 0xe9, 0x94, 0x0e, - 0x40, 0xcf, 0x08, 0xa6, 0xc3, 0x5d, 0xc4, 0x64, 0xb9, 0x81, 0x2f, 0x37, 0xeb, 0x2a, 0xa6, 0x71, 0x55, 0x67, 0x1a, - 0x6b, 0x8b, 0x40, 0xf3, 0xb2, 0x0b, 0x2a, 0x69, 0xcc, 0x1c, 0xf3, 0xaa, 0x8a, 0x70, 0x05, 0x4c, 0xb5, 0x24, 0x67, - 0x88, 0x37, 0xd1, 0x8c, 0xe5, 0x3e, 0xc3, 0x64, 0x57, 0x03, 0x4d, 0x9c, 0xd0, 0x64, 0xe8, 0x88, 0xcd, 0x1c, 0xc4, - 0x26, 0xc7, 0x5a, 0x2b, 0xab, 0x1f, 0xb7, 0x9c, 0xb0, 0x41, 0x3e, 0xac, 0x94, 0x39, 0x67, 0xf1, 0x4a, 0x1e, 0x1b, - 0xea, 0xb6, 0xf8, 0xd3, 0x65, 0x1a, 0x69, 0x4a, 0x69, 0xc8, 0x31, 0xd9, 0x6b, 0xad, 0xef, 0xa3, 0x6d, 0x55, 0xad, - 0x71, 0x30, 0x84, 0x7d, 0x50, 0xe2, 0x22, 0xe0, 0xb9, 0xfa, 0xbf, 0x76, 0xce, 0x00, 0x6d, 0x67, 0x40, 0x16, 0xc1, - 0x38, 0x89, 0xa4, 0xdf, 0x3e, 0x6c, 0x81, 0x26, 0x7a, 0xc5, 0x40, 0x9a, 0x60, 0xbc, 0xb9, 0x14, 0x16, 0x2c, 0xd2, - 0x7c, 0xca, 0xc7, 0xd2, 0x8f, 0xa4, 0x62, 0x28, 0x2c, 0xc9, 0x99, 0x27, 0x6b, 0xfa, 0xb0, 0x62, 0x36, 0x11, 0x90, - 0x5a, 0xa9, 0x7c, 0x31, 0x0b, 0xa9, 0x62, 0x5a, 0xc0, 0x1b, 0x2a, 0x5d, 0xba, 0xe2, 0x31, 0xb6, 0x35, 0x07, 0x7d, - 0xb1, 0xdd, 0xd7, 0x23, 0x86, 0x86, 0x15, 0x70, 0x47, 0x65, 0xe5, 0xa1, 0xcb, 0x1f, 0x4c, 0xa1, 0x0c, 0xa4, 0x78, - 0x25, 0xae, 0x59, 0x76, 0x1a, 0x01, 0xf0, 0xa1, 0xee, 0x5e, 0x68, 0x31, 0xa0, 0xb8, 0xbd, 0xec, 0x5a, 0x7a, 0x39, - 0x57, 0x0b, 0xff, 0x3a, 0x13, 0x33, 0x9e, 0x33, 0xd0, 0xd4, 0x34, 0xfe, 0x53, 0x38, 0x65, 0xea, 0x38, 0x82, 0xa8, - 0x61, 0x25, 0x7d, 0x9d, 0xbc, 0xaa, 0xd3, 0xd7, 0xf9, 0xfe, 0x8b, 0x89, 0x65, 0x7f, 0xf5, 0x43, 0x8c, 0x89, 0x6f, - 0xec, 0x09, 0x47, 0xca, 0x05, 0x53, 0x6c, 0xc4, 0xfb, 0x6a, 0x25, 0x1d, 0xb3, 0xad, 0xa6, 0x2b, 0x32, 0x7d, 0x6c, - 0x70, 0x11, 0xc5, 0x31, 0x68, 0x75, 0x99, 0x48, 0x12, 0x47, 0x50, 0x11, 0xde, 0x2d, 0x45, 0xd3, 0xf9, 0xfe, 0x8b, - 0xb3, 0xbb, 0xa4, 0x13, 0xd4, 0xbb, 0x02, 0xca, 0x02, 0x9a, 0xc6, 0x2c, 0x03, 0x33, 0xd2, 0xd9, 0x2d, 0x23, 0x63, - 0x4f, 0x45, 0x9a, 0xb2, 0x91, 0x64, 0x31, 0x58, 0x29, 0x9c, 0xca, 0x60, 0x2a, 0x72, 0x59, 0x16, 0x56, 0xd0, 0x73, - 0x07, 0x7a, 0x1e, 0x8c, 0xa2, 0x24, 0xf1, 0xb5, 0x45, 0x32, 0x13, 0x57, 0x6c, 0x0b, 0xd4, 0xdd, 0x1a, 0xc8, 0xe5, - 0x30, 0xcc, 0x19, 0x86, 0x05, 0xf9, 0x3c, 0xe1, 0x23, 0x56, 0x0a, 0xae, 0xb3, 0x80, 0xa7, 0x31, 0xbb, 0x01, 0x3e, - 0x82, 0x7b, 0xbd, 0x5e, 0x8b, 0xb4, 0x71, 0xa1, 0x11, 0xbe, 0xdc, 0x40, 0xec, 0x1d, 0x22, 0x13, 0x88, 0x8c, 0xf6, - 0x96, 0xdb, 0xf8, 0x01, 0xc3, 0x8e, 0x9c, 0xe4, 0xd6, 0xb2, 0xd2, 0xbc, 0x19, 0x93, 0x98, 0x25, 0x4c, 0x32, 0xcb, - 0xcb, 0x41, 0x7f, 0xd6, 0x47, 0xf7, 0x5d, 0x89, 0xbf, 0x92, 0x9c, 0xec, 0x29, 0xb3, 0x7b, 0x9e, 0x97, 0x96, 0x7a, - 0xb5, 0x3d, 0x15, 0xb6, 0xfb, 0x52, 0x6f, 0x4f, 0x24, 0x65, 0x34, 0x9a, 0x6a, 0x13, 0xdd, 0xdf, 0x58, 0x52, 0x35, - 0x86, 0xe1, 0xeb, 0xe5, 0x21, 0xfa, 0x60, 0xc1, 0xdc, 0x86, 0x82, 0x33, 0xc3, 0x14, 0x18, 0x58, 0x7d, 0x7a, 0xdb, - 0x4e, 0xa3, 0x24, 0xb9, 0x8c, 0x46, 0x1f, 0xeb, 0xd4, 0x5f, 0x91, 0x01, 0x5d, 0xe7, 0xc6, 0x4e, 0x95, 0xc3, 0xb2, - 0xdc, 0x75, 0x5b, 0x2e, 0x5d, 0x3b, 0x28, 0xfe, 0x5e, 0xab, 0x22, 0xfb, 0xfa, 0x46, 0xef, 0xa4, 0x76, 0x05, 0x11, - 0x37, 0x2b, 0xf3, 0x81, 0x0b, 0x7c, 0x92, 0xe2, 0x2c, 0x3f, 0x30, 0x74, 0x07, 0xb6, 0x46, 0xb1, 0x06, 0x88, 0xc4, - 0xcb, 0x22, 0xe6, 0xf9, 0x6e, 0x0c, 0xfc, 0x21, 0x50, 0x3e, 0x77, 0x66, 0xb8, 0x2f, 0xa0, 0x25, 0x8f, 0x33, 0x2a, - 0x73, 0x09, 0x99, 0xd1, 0x26, 0x2c, 0xa3, 0xf9, 0x1b, 0x68, 0x2e, 0x8a, 0xde, 0xdf, 0xea, 0x2a, 0xd0, 0xc9, 0x00, - 0x8a, 0xbc, 0xeb, 0x2a, 0x13, 0x35, 0x0a, 0x30, 0x3c, 0x95, 0x2b, 0x91, 0x9b, 0xd6, 0x8c, 0x47, 0xa3, 0xae, 0x6b, - 0xfb, 0xdb, 0xb0, 0x5c, 0x41, 0x7d, 0xdf, 0xcf, 0xc1, 0x7e, 0xb3, 0x7a, 0x7d, 0xb5, 0x88, 0x7c, 0x63, 0x11, 0x79, - 0xe0, 0x18, 0x59, 0xb8, 0xa2, 0x65, 0xa7, 0x7b, 0xf8, 0x57, 0xec, 0x36, 0x02, 0x65, 0x35, 0x00, 0xfe, 0x8c, 0x4b, - 0x76, 0x9b, 0x50, 0x49, 0x84, 0x31, 0x70, 0x0c, 0xa5, 0x01, 0xc3, 0xa8, 0xba, 0xa4, 0x58, 0x1f, 0x8d, 0x9a, 0xb1, - 0x9b, 0x12, 0x81, 0xd7, 0x34, 0xfb, 0xa2, 0x30, 0x38, 0x62, 0xd8, 0xec, 0x4d, 0x4d, 0x25, 0x76, 0xb0, 0x42, 0x52, - 0x6a, 0xd4, 0x60, 0xad, 0xf5, 0xac, 0xe3, 0xa6, 0x1c, 0x17, 0x0e, 0x6a, 0x85, 0x9a, 0x9a, 0x3e, 0x69, 0x15, 0xab, - 0x14, 0x93, 0xa9, 0xd5, 0x48, 0x45, 0xb5, 0x6e, 0x4a, 0x91, 0xf5, 0x46, 0xa0, 0xfe, 0xb2, 0x66, 0x12, 0x86, 0x4e, - 0xb3, 0x22, 0x04, 0x96, 0x2a, 0xb6, 0xa1, 0x7b, 0x1b, 0xcd, 0xd4, 0xc6, 0x71, 0x10, 0x2e, 0x5c, 0x84, 0x3b, 0x98, - 0x4d, 0x35, 0xe7, 0x4a, 0x87, 0x74, 0x5a, 0xef, 0xeb, 0x33, 0x22, 0xf4, 0x3e, 0x6c, 0x20, 0x71, 0x5d, 0xf1, 0x54, - 0x24, 0x08, 0x06, 0x6c, 0x0e, 0xca, 0x9d, 0x2b, 0x1f, 0x7c, 0x80, 0x9d, 0xaf, 0x56, 0x1b, 0x44, 0xb7, 0x55, 0xff, - 0xc4, 0x41, 0x65, 0x14, 0xae, 0x56, 0xd7, 0x12, 0xfb, 0x46, 0xf3, 0x25, 0x0c, 0xf7, 0x2d, 0xc7, 0x3d, 0x79, 0x05, - 0xad, 0x94, 0x22, 0x5a, 0x95, 0x94, 0x26, 0x43, 0x9d, 0x66, 0xeb, 0xfb, 0x24, 0x1d, 0xb6, 0x7d, 0xba, 0xc1, 0xbd, - 0x54, 0xa1, 0x11, 0xd3, 0xd5, 0x92, 0x4f, 0xcd, 0xd0, 0x1c, 0x63, 0x1c, 0xe6, 0xca, 0x8a, 0xd9, 0xdb, 0x66, 0x58, - 0x1e, 0x1c, 0xe4, 0xce, 0x40, 0xe7, 0x25, 0x9b, 0xf8, 0xc9, 0x07, 0x91, 0x9c, 0xdf, 0xa6, 0x4a, 0x77, 0xf9, 0xc9, - 0x0a, 0xa1, 0x0d, 0xb3, 0xb4, 0xd5, 0x05, 0x6b, 0x3c, 0xba, 0x8e, 0xb8, 0xf4, 0xca, 0x51, 0xb4, 0x35, 0xee, 0x33, - 0xbc, 0x34, 0xaa, 0x46, 0x90, 0x31, 0x50, 0x1e, 0x81, 0x27, 0x58, 0x15, 0x5a, 0xd3, 0xfd, 0x68, 0xca, 0xc0, 0x11, - 0x6c, 0xb5, 0x88, 0xd2, 0x2e, 0xdc, 0x33, 0x52, 0xc4, 0x0c, 0xbc, 0x1d, 0xf6, 0x62, 0xbd, 0x7b, 0xcd, 0x0e, 0x98, - 0xb3, 0x6c, 0x2c, 0xb2, 0x99, 0xad, 0x2b, 0xd6, 0x9e, 0x0d, 0x67, 0xe4, 0x63, 0x7f, 0xeb, 0xd8, 0x46, 0xfd, 0xef, - 0xae, 0x19, 0xdd, 0x95, 0xb9, 0x5e, 0x13, 0xa5, 0xa5, 0xf4, 0xd5, 0xfe, 0x40, 0x4b, 0x99, 0xb9, 0x6b, 0xde, 0x1b, - 0x67, 0x6a, 0x57, 0x3b, 0x4c, 0xf6, 0xda, 0xdd, 0xd2, 0xe6, 0xb3, 0xd4, 0xd0, 0xd5, 0x8e, 0x0d, 0x23, 0x52, 0xc5, - 0x22, 0x89, 0x0d, 0xb0, 0x1c, 0x13, 0x66, 0xe8, 0xe8, 0x9a, 0x27, 0x49, 0x55, 0xfa, 0x6b, 0xf8, 0x7a, 0x6e, 0xf8, - 0x7a, 0x6a, 0xf9, 0x3a, 0x70, 0x0a, 0xe0, 0xeb, 0x7a, 0xb8, 0xaa, 0x7b, 0xba, 0x71, 0x3a, 0x53, 0xcd, 0xd1, 0x73, - 0x65, 0x47, 0xc3, 0x7c, 0x0b, 0x0b, 0x01, 0x2e, 0x35, 0xaf, 0x8f, 0xbe, 0x71, 0xc2, 0x80, 0x01, 0xa8, 0x5d, 0x98, - 0xcc, 0x75, 0x51, 0x7c, 0xf4, 0x31, 0xc9, 0x0b, 0x56, 0x52, 0xf6, 0xc9, 0x0b, 0x70, 0xd2, 0x39, 0xcb, 0x01, 0x21, - 0xa6, 0x8a, 0x7f, 0x95, 0x12, 0x65, 0x57, 0xc7, 0xcd, 0xea, 0x72, 0xbb, 0x3a, 0xe0, 0xf4, 0xd5, 0xea, 0xe2, 0xbb, - 0x79, 0xbd, 0x5a, 0x1e, 0x2f, 0x97, 0x57, 0xed, 0xf7, 0x6a, 0xe5, 0xaf, 0x95, 0x80, 0xff, 0xde, 0x98, 0x28, 0x59, - 0x39, 0x3a, 0xf0, 0x00, 0x17, 0x33, 0x50, 0x50, 0xe8, 0x45, 0x97, 0x22, 0xee, 0xd5, 0xa7, 0x1c, 0x3c, 0xca, 0x4d, - 0xaf, 0xfb, 0x9f, 0x8a, 0xd9, 0x1c, 0xb4, 0xb1, 0x35, 0x92, 0x9e, 0x30, 0x33, 0x61, 0x55, 0x5f, 0x6c, 0x29, 0xab, - 0xf5, 0x51, 0xe7, 0xb1, 0x46, 0x4d, 0xa5, 0xbd, 0xbc, 0xd7, 0x2a, 0x16, 0x65, 0x51, 0xc9, 0x38, 0xb6, 0x39, 0x55, - 0x4e, 0xd7, 0x5d, 0x32, 0xb6, 0xe2, 0xad, 0xcf, 0x35, 0x1f, 0xe6, 0xc0, 0xeb, 0x1c, 0xf6, 0x63, 0xc9, 0xdd, 0xdd, - 0xff, 0xa2, 0x42, 0xce, 0xb2, 0x58, 0x43, 0xdf, 0xb2, 0x28, 0x4e, 0xb4, 0x91, 0x4d, 0x4e, 0x76, 0x5b, 0xc3, 0x55, - 0x9d, 0x31, 0x16, 0x07, 0x43, 0x72, 0xb2, 0xa9, 0x3a, 0xd2, 0xe5, 0x4c, 0xc4, 0x2c, 0x44, 0x62, 0xce, 0x52, 0x54, - 0x80, 0x57, 0xd5, 0xec, 0xfd, 0x48, 0xfa, 0xcb, 0x77, 0x75, 0xf7, 0x6a, 0x78, 0x52, 0x80, 0xf7, 0xeb, 0x8b, 0x4d, - 0xc7, 0xeb, 0xb7, 0x2c, 0xcb, 0x95, 0x22, 0x5a, 0xea, 0xb4, 0x5f, 0x54, 0x62, 0xe9, 0x8b, 0x70, 0x67, 0xfb, 0xca, - 0x04, 0x41, 0xed, 0xe0, 0x71, 0x70, 0x84, 0xb0, 0x72, 0x0b, 0x7f, 0x65, 0x0e, 0xfc, 0x73, 0xeb, 0x16, 0x7e, 0x41, - 0x9f, 0xd7, 0xbd, 0xc2, 0xb1, 0xa4, 0x2f, 0xfa, 0x2f, 0xac, 0xc5, 0x2c, 0x12, 0x3e, 0xba, 0xf5, 0x51, 0xc2, 0x65, - 0x13, 0x42, 0x6f, 0x88, 0x2c, 0x75, 0x05, 0xb8, 0x14, 0x95, 0x3b, 0xbb, 0xb0, 0xb6, 0x1e, 0x91, 0x92, 0xa2, 0xfd, - 0x84, 0xcb, 0x7d, 0x44, 0x66, 0xf4, 0x02, 0x7e, 0xec, 0x2f, 0xfd, 0xd7, 0x91, 0x9c, 0x06, 0x59, 0x94, 0xc6, 0x62, - 0xe6, 0xe3, 0x06, 0x42, 0x38, 0xc8, 0x95, 0xbd, 0xf1, 0x39, 0x2e, 0xf6, 0x2f, 0xc8, 0x8d, 0xa4, 0xa8, 0x8f, 0x1a, - 0x33, 0xf2, 0x52, 0xd2, 0x8b, 0xe3, 0xfd, 0xe5, 0x8d, 0x2c, 0x7a, 0x17, 0xe4, 0xa6, 0xf4, 0xd8, 0x93, 0xaf, 0xa9, - 0x8f, 0x69, 0xef, 0xc6, 0x40, 0x73, 0x2a, 0x66, 0xda, 0x73, 0x8f, 0x30, 0xf9, 0x00, 0x71, 0x95, 0xac, 0xe2, 0x36, - 0x26, 0xb4, 0xb2, 0x47, 0x91, 0x50, 0x2e, 0x02, 0x74, 0x70, 0xe0, 0x94, 0x95, 0xaa, 0x02, 0x39, 0x91, 0xb4, 0x66, - 0x90, 0x93, 0x37, 0x2a, 0x42, 0x73, 0x22, 0xfd, 0x0c, 0xdb, 0x61, 0x7c, 0xeb, 0x87, 0x36, 0x47, 0x33, 0x1b, 0x68, - 0x0f, 0x43, 0xc0, 0x25, 0xcb, 0x22, 0x29, 0xb2, 0x21, 0x76, 0xd5, 0x0f, 0xf2, 0x37, 0x7a, 0x31, 0xf0, 0xfe, 0xd3, - 0x3f, 0xfd, 0x38, 0xfe, 0x31, 0x1b, 0x5e, 0x90, 0xb7, 0xf4, 0xf0, 0xd8, 0xef, 0x87, 0xfe, 0x5e, 0xb3, 0xb9, 0xfa, - 0xf1, 0x70, 0xf0, 0x8f, 0xa8, 0xf9, 0xcb, 0x49, 0xf3, 0x87, 0x21, 0x5e, 0xf9, 0x3f, 0x1e, 0xf6, 0x07, 0xe6, 0x69, - 0xf0, 0x8f, 0xde, 0x8f, 0xf9, 0xf0, 0xcf, 0xba, 0x70, 0x1f, 0xe3, 0xc3, 0x09, 0x59, 0x48, 0x7a, 0xd8, 0x6c, 0xf6, - 0x0e, 0x27, 0x64, 0x2e, 0xe9, 0x21, 0xfc, 0x7f, 0x49, 0xdf, 0xb1, 0xc9, 0x8b, 0x9b, 0xb9, 0x7f, 0xd1, 0x5b, 0xed, - 0x2f, 0xff, 0x56, 0xc0, 0xa8, 0x83, 0x7f, 0xfc, 0xf8, 0x63, 0x8e, 0x1e, 0xf4, 0xe8, 0xe1, 0xb0, 0x81, 0x7d, 0x28, - 0xfd, 0x33, 0x55, 0xff, 0xfa, 0xfd, 0x70, 0xf0, 0x0f, 0x03, 0x05, 0x7a, 0xf0, 0xe3, 0xc5, 0x71, 0x8f, 0x0e, 0x57, - 0x3e, 0x5a, 0x3d, 0xc0, 0x2b, 0x8c, 0x57, 0xfb, 0xf8, 0x82, 0xa0, 0x09, 0xc2, 0x64, 0x22, 0xe9, 0xe1, 0x83, 0xc3, - 0x09, 0xb9, 0x92, 0xf4, 0x10, 0x1d, 0x4e, 0xc8, 0x0b, 0x49, 0x0f, 0xff, 0xe1, 0xf7, 0x43, 0xed, 0x61, 0x5b, 0x29, - 0xf7, 0xc6, 0x0a, 0x82, 0x1b, 0x51, 0xc6, 0xa2, 0x95, 0xe4, 0x32, 0x61, 0x78, 0xff, 0x90, 0x93, 0x33, 0x85, 0x26, - 0x5f, 0x82, 0x13, 0x06, 0x6c, 0x3b, 0x7f, 0x79, 0x0e, 0x9b, 0x0d, 0x34, 0xb3, 0x1f, 0x66, 0x44, 0xfb, 0x01, 0xf2, - 0x50, 0x92, 0xab, 0x28, 0x59, 0xb0, 0x3c, 0x64, 0x05, 0x26, 0x23, 0x7a, 0x26, 0xfd, 0x36, 0x26, 0xef, 0x24, 0xfc, - 0xe8, 0x60, 0x72, 0x66, 0x02, 0x98, 0x70, 0x90, 0x35, 0x51, 0xa5, 0x42, 0x6b, 0x2c, 0x08, 0x93, 0xf9, 0x96, 0x4a, - 0x39, 0x05, 0xef, 0x02, 0x26, 0xe3, 0x5a, 0xb8, 0x93, 0x5c, 0x53, 0x4b, 0x12, 0xef, 0x33, 0xc6, 0xbe, 0x8b, 0x92, - 0x8f, 0x2c, 0xf3, 0x6f, 0x48, 0xbb, 0xf3, 0x39, 0x51, 0x2e, 0xe8, 0xbd, 0x36, 0xee, 0x96, 0xb1, 0xaa, 0x53, 0xa9, - 0x63, 0x04, 0x20, 0x64, 0xeb, 0xbe, 0x18, 0xd8, 0xf1, 0xbd, 0x6c, 0xc3, 0x61, 0x95, 0x45, 0xd7, 0x08, 0xd7, 0xe3, - 0xa2, 0x3c, 0xbd, 0x8a, 0x12, 0x1e, 0x7b, 0x92, 0xcd, 0xe6, 0x49, 0x24, 0x99, 0x67, 0xd6, 0xeb, 0x45, 0x30, 0x10, - 0x2a, 0x55, 0x86, 0xd8, 0x31, 0x38, 0x63, 0x1b, 0x70, 0x82, 0xb3, 0xe2, 0x43, 0x74, 0xca, 0xa8, 0x1d, 0xaf, 0xab, - 0xe0, 0xd7, 0x7a, 0x7c, 0xaf, 0xd9, 0x06, 0x47, 0xd8, 0x50, 0x89, 0xe7, 0x9c, 0xa4, 0x14, 0x84, 0x68, 0xa7, 0x8f, - 0x8e, 0xf3, 0xab, 0x49, 0x0f, 0x41, 0x6c, 0x46, 0xd0, 0xb7, 0xca, 0x2f, 0x04, 0x0d, 0xa6, 0xb4, 0xd5, 0x9d, 0x1e, - 0xb3, 0xee, 0xb4, 0xd1, 0xb0, 0x3a, 0x74, 0x42, 0xb3, 0xc1, 0x54, 0x77, 0x8f, 0x48, 0x4c, 0x16, 0xb4, 0xd9, 0x26, - 0x13, 0xda, 0x52, 0x5d, 0xba, 0x93, 0xe3, 0xc4, 0x4c, 0x73, 0x70, 0xe0, 0x8b, 0x20, 0x89, 0x72, 0xf9, 0x25, 0x18, - 0xfb, 0x74, 0x42, 0x62, 0x2a, 0x02, 0x76, 0xc3, 0x46, 0x7e, 0x82, 0x49, 0x6c, 0x38, 0x0d, 0xee, 0xe2, 0x09, 0x75, - 0x9a, 0x81, 0x11, 0x41, 0xdf, 0xf6, 0xe3, 0x41, 0x7b, 0x48, 0x29, 0x45, 0x7b, 0xcd, 0x26, 0xea, 0x0b, 0xba, 0x90, - 0x21, 0x94, 0x38, 0xaa, 0x32, 0x9d, 0x43, 0x51, 0xc7, 0x29, 0xf2, 0x5f, 0xc8, 0x40, 0xb2, 0x5c, 0xfa, 0x50, 0x0c, - 0xe6, 0x7f, 0x6e, 0x09, 0x1b, 0x1d, 0x1f, 0xa2, 0x06, 0x94, 0x2a, 0xe2, 0xc4, 0x44, 0xd0, 0x4b, 0x1c, 0xc6, 0x83, - 0xa3, 0xa1, 0xcb, 0xff, 0x55, 0x21, 0x4c, 0x7e, 0xd9, 0x8f, 0x07, 0x2d, 0x35, 0x79, 0x0f, 0xf5, 0x7d, 0x41, 0x73, - 0xad, 0xa0, 0xf5, 0xf3, 0xf0, 0xad, 0x5a, 0x2a, 0x0e, 0x0d, 0x70, 0x66, 0xde, 0x05, 0x6d, 0x76, 0x42, 0x7f, 0xe1, - 0x2e, 0xa2, 0x09, 0x93, 0x19, 0x2c, 0x90, 0x88, 0x42, 0x7b, 0x22, 0x28, 0xcc, 0x58, 0x75, 0xbb, 0x0c, 0xcd, 0xf3, - 0x03, 0xf4, 0xa0, 0x7f, 0x25, 0xc3, 0x89, 0xd4, 0xd3, 0x5f, 0xc9, 0xd5, 0x0a, 0xfe, 0x9f, 0xc8, 0xbe, 0xa0, 0x97, - 0xaa, 0x68, 0x61, 0x8a, 0xe6, 0x50, 0xf4, 0x36, 0x04, 0x50, 0x49, 0x5e, 0x2a, 0x59, 0x7a, 0x4f, 0xae, 0xa8, 0x82, - 0xfd, 0xe0, 0x20, 0x1b, 0x4c, 0x1b, 0xed, 0x21, 0xf8, 0xf7, 0x33, 0x99, 0x7f, 0xc7, 0xe5, 0xd4, 0x47, 0x87, 0x3d, - 0x84, 0xfb, 0xc8, 0x83, 0xad, 0xed, 0xa6, 0x0d, 0xaa, 0x31, 0x9c, 0x34, 0x5e, 0xca, 0x70, 0xd1, 0xa3, 0xad, 0xbe, - 0xcf, 0x8d, 0x3f, 0x0f, 0x93, 0xc4, 0x30, 0xce, 0x16, 0x59, 0xe0, 0x86, 0x94, 0x0d, 0xfb, 0xbc, 0xc0, 0x8d, 0x59, - 0xe3, 0x0a, 0x87, 0x49, 0x63, 0xd6, 0xf0, 0x17, 0x94, 0xd2, 0x66, 0xa7, 0xec, 0x66, 0xa5, 0xdf, 0x14, 0x87, 0x57, - 0xd6, 0xd9, 0x39, 0x50, 0xc7, 0x21, 0x6d, 0xf8, 0xd9, 0x80, 0x0d, 0x57, 0x2b, 0x74, 0xdc, 0xef, 0x21, 0xdc, 0xf0, - 0x2d, 0xa1, 0x1d, 0x5a, 0x4a, 0xc3, 0x98, 0xf0, 0x61, 0x61, 0x42, 0x49, 0xef, 0x6b, 0x61, 0xa3, 0x65, 0x75, 0xd8, - 0x1d, 0x1e, 0xc0, 0x8a, 0xd2, 0x8e, 0xd1, 0xfa, 0xea, 0x1c, 0x96, 0x69, 0x89, 0x39, 0xa5, 0x2d, 0x22, 0xa8, 0xf5, - 0x5d, 0x4f, 0xa9, 0xac, 0x08, 0x3e, 0xa1, 0x55, 0x73, 0x32, 0x88, 0x48, 0x3c, 0xa4, 0xaf, 0xb5, 0x3d, 0xd2, 0xb5, - 0x7e, 0x71, 0x96, 0xd0, 0xf7, 0x6b, 0xd1, 0xdb, 0x08, 0x62, 0x2b, 0xd7, 0xc1, 0x68, 0x91, 0x65, 0x2c, 0x95, 0x6f, - 0x44, 0x6c, 0xd4, 0x34, 0x96, 0x80, 0xa5, 0x04, 0x61, 0x59, 0x02, 0x3a, 0x5a, 0xc7, 0x9e, 0x8c, 0xc5, 0x46, 0xf5, - 0x84, 0x2e, 0xb4, 0xfa, 0xa4, 0x82, 0xb5, 0xdd, 0x89, 0xb1, 0x8b, 0x7d, 0x4c, 0x16, 0x26, 0x8a, 0xeb, 0x07, 0x41, - 0x30, 0x09, 0x46, 0x50, 0x0d, 0x13, 0xe4, 0xb8, 0x50, 0xe7, 0xc8, 0xcf, 0xe9, 0x75, 0x90, 0xb2, 0x1b, 0x35, 0xab, - 0x8f, 0x2b, 0xc9, 0x6c, 0x8f, 0xd7, 0xf1, 0xb4, 0xab, 0xd8, 0x4d, 0x1e, 0xa4, 0x22, 0x66, 0x80, 0x1e, 0x88, 0xdb, - 0x9b, 0xa2, 0x69, 0x94, 0xbb, 0xf1, 0xa9, 0x0a, 0xbe, 0x81, 0xeb, 0xbc, 0x9e, 0x80, 0xc7, 0x57, 0xe9, 0x5a, 0x65, - 0x63, 0xed, 0x06, 0xc7, 0x98, 0x8f, 0xfd, 0x49, 0x00, 0x71, 0x3d, 0x45, 0x42, 0x12, 0x4c, 0xb9, 0x89, 0x4b, 0x54, - 0xb3, 0x72, 0xcc, 0x2b, 0x1a, 0x0f, 0x44, 0xa3, 0xa1, 0xbc, 0xd0, 0x0b, 0x4d, 0x12, 0x13, 0x4c, 0xae, 0xca, 0xb3, - 0x65, 0xdb, 0xbd, 0x95, 0xb4, 0x3e, 0x95, 0x7f, 0x55, 0x77, 0xe7, 0x36, 0xa4, 0xc4, 0xca, 0x53, 0x28, 0xfd, 0x19, - 0x26, 0xcf, 0xe8, 0xa1, 0x3f, 0x08, 0xfa, 0x7f, 0x19, 0xe2, 0xbe, 0x1f, 0xfc, 0x19, 0x1f, 0x6a, 0xce, 0x71, 0x85, - 0xbb, 0x89, 0x9e, 0x63, 0xa9, 0xe2, 0x97, 0x6d, 0xa2, 0x3c, 0x89, 0x61, 0x4a, 0xd2, 0x68, 0xc6, 0xc2, 0x67, 0x70, - 0xc8, 0x2d, 0xe1, 0xbc, 0x95, 0x04, 0x28, 0x29, 0x7c, 0x66, 0x78, 0x49, 0x80, 0xfa, 0xaf, 0x64, 0xf9, 0xd4, 0x47, - 0xfd, 0xe7, 0xd5, 0xd3, 0x5f, 0x50, 0xff, 0x17, 0x19, 0xfe, 0x5c, 0x18, 0x6f, 0x77, 0x6d, 0x8e, 0xc7, 0x76, 0x8e, - 0x42, 0x6f, 0x8d, 0x83, 0xbb, 0x05, 0xde, 0x74, 0x74, 0x4c, 0x70, 0xc1, 0xc7, 0x25, 0x33, 0xca, 0x03, 0x19, 0x4d, - 0x00, 0xa9, 0xce, 0x1e, 0xe4, 0x6e, 0x5c, 0xbf, 0x5a, 0x31, 0x90, 0x8a, 0xa5, 0x57, 0x40, 0xe6, 0xa4, 0xd7, 0xc2, - 0xcb, 0x5a, 0x5b, 0xa5, 0x33, 0xd5, 0xe3, 0xe8, 0x25, 0x9f, 0xbe, 0xa2, 0xad, 0xee, 0xd5, 0xf1, 0xa4, 0x7b, 0xd5, - 0x68, 0xe0, 0xdc, 0x92, 0xd6, 0x62, 0x70, 0x35, 0x24, 0x5f, 0x83, 0x53, 0xcf, 0xa5, 0x25, 0x52, 0x5b, 0x5e, 0xc7, - 0x2c, 0xaf, 0xd1, 0x48, 0x0b, 0xdc, 0x75, 0xba, 0x4e, 0x74, 0xd7, 0xa2, 0xd0, 0x38, 0x59, 0x27, 0xb5, 0xa7, 0x58, - 0x95, 0x40, 0x32, 0x14, 0xa5, 0xf4, 0x46, 0xe2, 0xad, 0xa3, 0xc2, 0x98, 0xd0, 0x5d, 0x9d, 0x59, 0x60, 0x9f, 0x5a, - 0x4a, 0xf8, 0x80, 0x05, 0xe8, 0x5a, 0x7a, 0x82, 0x67, 0x64, 0xd1, 0x68, 0x2b, 0x32, 0x6f, 0xb6, 0xbb, 0xf5, 0xb1, - 0x9e, 0x54, 0x63, 0x91, 0x45, 0x83, 0xce, 0x4a, 0x2c, 0x15, 0x69, 0xa3, 0x51, 0xd4, 0x83, 0x9d, 0xf6, 0xe4, 0xd6, - 0x02, 0x10, 0x37, 0xeb, 0x49, 0x19, 0x56, 0xc2, 0x56, 0x32, 0x95, 0x07, 0x3c, 0x4d, 0x59, 0x06, 0x52, 0x94, 0x4a, - 0xc2, 0x8b, 0xa2, 0x92, 0xec, 0x20, 0x46, 0x09, 0xa3, 0x19, 0x70, 0x1e, 0x65, 0x77, 0x91, 0x94, 0x08, 0x32, 0x55, - 0x7c, 0x83, 0x52, 0x7a, 0x66, 0xd3, 0x59, 0xa4, 0xe2, 0x41, 0x09, 0xe5, 0x8e, 0x4c, 0xca, 0x29, 0x0b, 0xce, 0xf7, - 0x4f, 0xc5, 0x9d, 0x36, 0xd9, 0x80, 0x0f, 0x43, 0xd5, 0x2c, 0x31, 0x9c, 0x2b, 0xa2, 0x1f, 0x7c, 0x89, 0xcb, 0xe8, - 0x48, 0xa0, 0x18, 0xe0, 0x73, 0x9e, 0x31, 0xa5, 0x83, 0xef, 0x5b, 0xbb, 0x2f, 0xa9, 0x2b, 0x90, 0x89, 0xeb, 0xbd, - 0x01, 0x44, 0x46, 0xe0, 0xdc, 0x49, 0xe9, 0x46, 0xb3, 0xf3, 0xfd, 0x93, 0xb7, 0xdb, 0x6c, 0xe0, 0xd5, 0xca, 0x58, - 0xbf, 0x4a, 0xb7, 0x21, 0x51, 0x05, 0x69, 0x62, 0x7e, 0x84, 0x7e, 0xa2, 0x54, 0xa4, 0xc8, 0xcf, 0x80, 0x8a, 0xce, - 0xf7, 0x4f, 0xde, 0xfb, 0x99, 0xf2, 0x2d, 0x61, 0xe2, 0x2e, 0xdb, 0x17, 0xd4, 0x9f, 0x52, 0x86, 0xf5, 0xda, 0x4b, - 0xd6, 0x25, 0x1c, 0x01, 0x1e, 0x4e, 0x55, 0x25, 0x58, 0x10, 0x03, 0x3e, 0xa4, 0x89, 0xc1, 0x00, 0x4d, 0x30, 0x49, - 0x6a, 0x76, 0x19, 0x85, 0x0d, 0x50, 0x73, 0x9d, 0xc1, 0x4e, 0x04, 0x5a, 0xf5, 0xc3, 0x24, 0x51, 0xb3, 0xca, 0x42, - 0x0b, 0x8f, 0x67, 0x1b, 0x59, 0x69, 0x95, 0x39, 0xfa, 0x2d, 0xd8, 0x4e, 0xf6, 0xe1, 0x0d, 0xb5, 0x96, 0x84, 0x29, - 0x78, 0x6e, 0xd3, 0xc7, 0xce, 0xf7, 0x4f, 0x5e, 0x9b, 0x0c, 0xb2, 0x79, 0x64, 0xf9, 0xfd, 0x86, 0x89, 0x79, 0xf2, - 0x3a, 0xa8, 0x6a, 0x55, 0xe3, 0xf3, 0xfd, 0x93, 0x0f, 0xdb, 0x9a, 0x41, 0x79, 0xb1, 0xa8, 0x6c, 0x7c, 0x05, 0xdf, - 0x92, 0x25, 0xe1, 0xd2, 0x08, 0x87, 0x90, 0x17, 0x44, 0x09, 0xa4, 0x30, 0x2f, 0x4a, 0xd7, 0xc8, 0x73, 0x92, 0x52, - 0x15, 0x06, 0xaa, 0xef, 0x9a, 0x51, 0xf3, 0xb8, 0x48, 0xcf, 0x46, 0x62, 0xce, 0x76, 0xc4, 0x86, 0x6e, 0x70, 0xc0, - 0x67, 0x90, 0x3a, 0xa3, 0x40, 0xe7, 0x64, 0xaf, 0x85, 0xbb, 0x75, 0xf1, 0x95, 0x2a, 0x22, 0x15, 0x35, 0xd9, 0x42, - 0xa6, 0xb4, 0x45, 0x12, 0xda, 0x22, 0x11, 0xcd, 0x07, 0x2d, 0x2d, 0x20, 0xba, 0x51, 0x39, 0xae, 0x16, 0x33, 0x90, - 0x15, 0x66, 0x4e, 0xab, 0x16, 0xc0, 0x71, 0x37, 0x52, 0xbe, 0x47, 0x25, 0xd3, 0x63, 0x45, 0x16, 0x6f, 0x7c, 0x41, - 0x84, 0x1a, 0xf8, 0x8c, 0x5f, 0x26, 0x90, 0x58, 0x02, 0xab, 0x22, 0x12, 0x87, 0x65, 0xd3, 0xb6, 0x69, 0x1a, 0x05, - 0x6a, 0x9f, 0x04, 0x89, 0x02, 0xe0, 0xdc, 0x24, 0x32, 0x79, 0x38, 0xf9, 0x66, 0x97, 0xc7, 0x07, 0x07, 0xbe, 0xee, - 0xf4, 0xa5, 0xf4, 0x85, 0xad, 0xaf, 0x22, 0x77, 0xdf, 0x6a, 0x5e, 0x11, 0x63, 0x05, 0x7f, 0xa3, 0x91, 0x0c, 0x0b, - 0x08, 0x43, 0xfb, 0x51, 0x1d, 0x83, 0x16, 0x78, 0xa5, 0xeb, 0xd5, 0x97, 0xdf, 0x68, 0x94, 0x51, 0xda, 0x3a, 0xb6, - 0x6e, 0x48, 0x5a, 0x5c, 0xf9, 0x65, 0xea, 0x4f, 0x6b, 0x23, 0x5f, 0xca, 0x82, 0x80, 0xb9, 0x4b, 0xb3, 0xdc, 0x2e, - 0xc6, 0x39, 0x12, 0x1c, 0xda, 0x7d, 0x69, 0xb2, 0x16, 0x88, 0xca, 0xae, 0x32, 0x8d, 0x2c, 0x3b, 0xeb, 0xe0, 0xd0, - 0x36, 0x82, 0xa8, 0x14, 0x34, 0x6a, 0x14, 0x86, 0xbc, 0xdf, 0x6c, 0xe6, 0x5c, 0x92, 0x1c, 0x1b, 0x27, 0x97, 0x82, - 0x42, 0x21, 0xab, 0x53, 0x22, 0xe5, 0x25, 0x9d, 0xef, 0x26, 0xf9, 0x13, 0x87, 0xe4, 0x9f, 0x51, 0xe6, 0x90, 0xbf, - 0x76, 0x71, 0x04, 0xc2, 0x38, 0x17, 0x72, 0x5b, 0x75, 0x3a, 0xa7, 0xe0, 0x44, 0xab, 0x63, 0xb4, 0x16, 0x56, 0xdc, - 0xc1, 0x50, 0xdc, 0x13, 0xa2, 0xdc, 0x90, 0xc4, 0xc6, 0x80, 0xfd, 0x2a, 0xa8, 0x06, 0x53, 0x6f, 0xf3, 0xe9, 0xb9, - 0x1c, 0xf0, 0xe4, 0xc3, 0xdd, 0xf1, 0xd0, 0xd3, 0xf9, 0xe6, 0xc9, 0x75, 0x72, 0x3f, 0x61, 0xd5, 0xce, 0xc1, 0xad, - 0x67, 0x82, 0xc2, 0xfc, 0x65, 0x1c, 0xbb, 0xce, 0x7c, 0xd6, 0x0e, 0xa1, 0x95, 0x7f, 0x00, 0x6d, 0xbb, 0xad, 0x5a, - 0x30, 0x67, 0x58, 0xe0, 0x47, 0x3a, 0x03, 0x35, 0xca, 0x76, 0xb0, 0x8f, 0x13, 0xd5, 0x80, 0xa5, 0xf1, 0xf6, 0xea, - 0x67, 0x85, 0x21, 0x13, 0x0d, 0x1a, 0x5e, 0x02, 0xff, 0xd3, 0x24, 0x0f, 0x74, 0xa3, 0xe4, 0x02, 0x20, 0x68, 0xae, - 0xf0, 0x54, 0x21, 0x0c, 0xa1, 0xca, 0xfb, 0xfe, 0x72, 0x8f, 0xd2, 0x79, 0xe5, 0x7d, 0x7c, 0x57, 0xa5, 0x5e, 0x01, - 0x59, 0xe0, 0x10, 0xcc, 0xc7, 0xb2, 0x40, 0x87, 0x2f, 0xcf, 0x6c, 0x73, 0x65, 0x42, 0x06, 0x95, 0xc6, 0xed, 0x84, - 0x36, 0x95, 0x5b, 0x4e, 0xd7, 0x5b, 0x34, 0xac, 0xd5, 0xee, 0x43, 0xed, 0x1b, 0xa9, 0x60, 0x84, 0xe7, 0xf7, 0xaa, - 0xb5, 0x1d, 0xb7, 0xf8, 0xb8, 0x9e, 0xbf, 0xb2, 0xb6, 0x29, 0x01, 0x4f, 0x73, 0x96, 0xc9, 0x67, 0x6c, 0x2c, 0x32, - 0x88, 0x59, 0x94, 0x38, 0xc1, 0xc5, 0xbe, 0xe3, 0xb7, 0x53, 0xeb, 0x73, 0x02, 0x05, 0x6b, 0x0b, 0x54, 0xbf, 0x3e, - 0xaa, 0xa0, 0xf5, 0xf9, 0x7a, 0xaf, 0xf9, 0xc1, 0xc1, 0x87, 0x0a, 0x4d, 0x06, 0x4a, 0x05, 0x85, 0xc3, 0xb4, 0xb4, - 0x4a, 0x63, 0x22, 0xb9, 0xfb, 0x7e, 0xe9, 0x04, 0xb0, 0x0c, 0xc3, 0xe5, 0x3d, 0x2f, 0xa9, 0x2c, 0x26, 0xeb, 0x2c, - 0xde, 0x38, 0x27, 0xb8, 0x6b, 0xb8, 0x00, 0x87, 0x07, 0x53, 0x5b, 0x7b, 0x8b, 0xf2, 0x2a, 0x19, 0xb6, 0x84, 0xe1, - 0x14, 0x90, 0xe5, 0x2b, 0x33, 0xc4, 0xa1, 0xc0, 0xad, 0x66, 0xc9, 0x29, 0xe8, 0x95, 0x53, 0x92, 0x07, 0x53, 0x48, - 0x7f, 0xad, 0x1d, 0x59, 0x8c, 0x89, 0x4e, 0xcc, 0x71, 0x52, 0x09, 0x4e, 0x5e, 0x6e, 0x73, 0x29, 0x5b, 0xa2, 0x66, - 0x4a, 0xea, 0xa8, 0x16, 0xb8, 0xec, 0x10, 0x5c, 0xf9, 0xdc, 0x28, 0x6e, 0x36, 0x6e, 0x06, 0x0c, 0xf8, 0x99, 0xf4, - 0x75, 0x30, 0x0a, 0x64, 0x86, 0x08, 0x16, 0x7e, 0x6d, 0xea, 0xae, 0x50, 0xdd, 0x88, 0x41, 0xdc, 0xd4, 0x45, 0x93, - 0x50, 0x71, 0xbd, 0xd3, 0x8a, 0x97, 0x8e, 0x75, 0x06, 0xb5, 0xb4, 0x5c, 0xb0, 0x4a, 0x24, 0x71, 0x96, 0x3f, 0xd6, - 0x49, 0xd1, 0x65, 0x23, 0xc2, 0x14, 0x18, 0xef, 0xd5, 0x1e, 0xb0, 0x02, 0xfe, 0x5f, 0x9e, 0x48, 0x67, 0x47, 0xad, - 0x13, 0x5b, 0xcd, 0xe9, 0x48, 0xfd, 0x77, 0x90, 0xea, 0xb2, 0x7e, 0xe6, 0x5f, 0x2a, 0x59, 0xc8, 0x49, 0x5e, 0x63, - 0xec, 0xa9, 0x62, 0xec, 0x18, 0xf4, 0x34, 0x9b, 0xf8, 0xdd, 0x37, 0x19, 0x2f, 0xdc, 0x48, 0x39, 0x43, 0x62, 0x5f, - 0x97, 0xd1, 0x72, 0xe7, 0xf7, 0xda, 0x6e, 0x84, 0x9c, 0x42, 0x16, 0x10, 0x31, 0x9c, 0x3d, 0xc5, 0x24, 0x6f, 0x34, - 0xba, 0xf9, 0x31, 0xab, 0x9c, 0x24, 0x15, 0x8c, 0x1c, 0x02, 0xba, 0x40, 0xf0, 0x35, 0x19, 0x0a, 0x21, 0x7f, 0x9b, - 0x99, 0x9d, 0x83, 0xaf, 0xfd, 0xe4, 0x9d, 0xef, 0x72, 0x35, 0xb7, 0x6d, 0x19, 0x34, 0x85, 0xf5, 0xf8, 0x55, 0xc0, - 0xe5, 0xeb, 0xbb, 0x13, 0x3c, 0x00, 0xee, 0xbd, 0x36, 0x81, 0x54, 0x34, 0xdc, 0x95, 0x9a, 0x25, 0x94, 0xa7, 0xaf, - 0x8b, 0xab, 0xac, 0x44, 0x77, 0xb2, 0xae, 0xac, 0x8c, 0x59, 0x49, 0xf3, 0xa2, 0xc8, 0x59, 0x15, 0xde, 0x5f, 0x4b, - 0xbf, 0x54, 0xc2, 0x65, 0xd3, 0xdb, 0x7e, 0x3a, 0xa7, 0x92, 0x38, 0x84, 0xfa, 0xf5, 0xae, 0xd8, 0x47, 0x05, 0x26, - 0x9c, 0x6b, 0x23, 0x14, 0x7f, 0xde, 0x26, 0x14, 0x49, 0x6a, 0x8e, 0xbc, 0x12, 0x88, 0xed, 0x7b, 0x08, 0x44, 0xe3, - 0x66, 0xb7, 0x32, 0x11, 0xd4, 0x91, 0x9a, 0x4c, 0xac, 0x6f, 0x29, 0x4d, 0x09, 0x37, 0xbb, 0xd1, 0xeb, 0xac, 0x56, - 0x7c, 0xd0, 0x02, 0x37, 0x12, 0x42, 0xf0, 0xb3, 0xad, 0x7f, 0x3a, 0x9c, 0x58, 0xbb, 0x81, 0x7d, 0x5e, 0x9a, 0x2c, - 0x38, 0x80, 0x04, 0x67, 0x5f, 0x25, 0x65, 0x29, 0x9a, 0x36, 0x14, 0x64, 0x08, 0x9c, 0xf2, 0x32, 0xcc, 0x04, 0x10, - 0x2b, 0x59, 0x61, 0x0c, 0x48, 0x7f, 0x6b, 0xee, 0x9f, 0x35, 0x2f, 0x3f, 0xad, 0x89, 0xd6, 0xe4, 0x8a, 0x56, 0x1f, - 0x6a, 0xf9, 0x06, 0x06, 0x02, 0xa3, 0x1f, 0xee, 0x29, 0x13, 0xb4, 0x12, 0xe5, 0xd8, 0x95, 0x43, 0xa4, 0x05, 0x4e, - 0xb4, 0xbd, 0x0f, 0x3a, 0xc2, 0xbb, 0x45, 0x9a, 0x10, 0xe1, 0xd0, 0xf5, 0x4b, 0x2a, 0x6b, 0xac, 0x64, 0x4a, 0x8d, - 0xa5, 0x44, 0x22, 0x45, 0xa6, 0x92, 0xa6, 0x83, 0xd6, 0x10, 0x14, 0xd0, 0x6e, 0x72, 0x9c, 0x56, 0x26, 0x70, 0xd2, - 0x68, 0xe0, 0xc8, 0xce, 0x3a, 0x1d, 0xf0, 0x46, 0x32, 0x24, 0x8c, 0x24, 0xda, 0x30, 0x39, 0x3b, 0x38, 0xf0, 0xa3, - 0x6a, 0xde, 0x41, 0x32, 0xc4, 0x44, 0xac, 0x56, 0xbe, 0x02, 0x2b, 0xc2, 0xab, 0x55, 0xe4, 0x82, 0xa5, 0xaa, 0xa1, - 0xdb, 0xbc, 0x2f, 0xe9, 0x5c, 0x09, 0xc0, 0x39, 0x40, 0xd8, 0xa0, 0x7e, 0x64, 0xdc, 0x7b, 0x11, 0xb8, 0xa3, 0x1a, - 0xe9, 0x20, 0x69, 0xb4, 0x87, 0x0e, 0xe3, 0x1a, 0x24, 0x43, 0x1a, 0x15, 0xe2, 0xe0, 0x60, 0x2f, 0x37, 0x22, 0xf2, - 0x27, 0x10, 0x65, 0x3f, 0x29, 0xc9, 0xa2, 0x07, 0x74, 0x77, 0x63, 0xdd, 0x19, 0x50, 0x52, 0x94, 0xd9, 0x56, 0xdb, - 0xae, 0x96, 0x05, 0x51, 0x36, 0x22, 0x26, 0x18, 0xdc, 0x07, 0xcb, 0xbe, 0x24, 0xf3, 0x57, 0xb2, 0xcc, 0xb1, 0xfe, - 0x79, 0x6b, 0x66, 0x75, 0x10, 0x04, 0x51, 0x36, 0x51, 0xb1, 0x0c, 0x1b, 0x86, 0x55, 0xc4, 0x7f, 0x64, 0xc0, 0x74, - 0x26, 0x1e, 0x94, 0x73, 0x0d, 0xa9, 0x06, 0xdf, 0xaa, 0x36, 0xf6, 0x2e, 0xc9, 0x4f, 0x5b, 0xbd, 0x0c, 0x1a, 0x92, - 0xe7, 0xbf, 0x15, 0x92, 0x87, 0x06, 0x12, 0x4d, 0x1e, 0x6b, 0x38, 0xdb, 0x81, 0x8b, 0x9f, 0xe4, 0x1a, 0xce, 0x76, - 0xe3, 0xd6, 0x62, 0xea, 0x97, 0x5d, 0xf0, 0x39, 0xbc, 0x41, 0x03, 0x5a, 0x15, 0x38, 0x50, 0x3e, 0x5a, 0xd7, 0xbd, - 0x34, 0x2b, 0x05, 0x61, 0x2a, 0xa9, 0xcf, 0xeb, 0x07, 0xa0, 0xd2, 0x46, 0x1d, 0xc3, 0x97, 0x87, 0x73, 0xec, 0xb8, - 0x04, 0xea, 0xa9, 0x2b, 0x40, 0x4e, 0xc6, 0xdb, 0x3e, 0x3f, 0x38, 0x00, 0xdb, 0x00, 0x94, 0xb8, 0x60, 0x14, 0xcd, - 0xe5, 0x22, 0x03, 0x55, 0x2a, 0xb7, 0xbf, 0xa1, 0x18, 0x6e, 0x81, 0xa8, 0x32, 0xf8, 0x01, 0x05, 0xf3, 0x28, 0xcf, - 0xf9, 0x95, 0x2e, 0x33, 0xbf, 0x89, 0xa0, 0x96, 0x94, 0x73, 0xad, 0x13, 0xa6, 0xb8, 0x9b, 0x1a, 0x3a, 0xad, 0xa3, - 0xed, 0xc5, 0x15, 0x4b, 0xe5, 0x2b, 0x9e, 0x4b, 0x96, 0xc2, 0xf2, 0x2b, 0x8a, 0x83, 0x15, 0xe5, 0x18, 0x0e, 0x6c, - 0xad, 0x57, 0x14, 0xc7, 0x77, 0x76, 0x91, 0x75, 0x1d, 0x68, 0x1a, 0xa5, 0x71, 0xa2, 0x27, 0x71, 0xf3, 0x19, 0x6d, - 0x0e, 0x67, 0xd9, 0xd2, 0xcd, 0xa7, 0xa9, 0x94, 0x0d, 0xc5, 0xdd, 0x7d, 0x4e, 0xad, 0x24, 0xb0, 0xd2, 0xf3, 0x4e, - 0xad, 0x05, 0x22, 0xde, 0x3b, 0x36, 0xc1, 0x5d, 0x09, 0x91, 0x0e, 0x47, 0x0d, 0xea, 0x70, 0x5a, 0xba, 0xf9, 0x72, - 0xeb, 0x95, 0xb6, 0x6d, 0xc2, 0x41, 0xd1, 0xc9, 0xe3, 0xdd, 0x96, 0xd5, 0x6b, 0x2b, 0x39, 0xac, 0xb4, 0xe0, 0xf7, - 0x65, 0xcc, 0x78, 0x69, 0xc9, 0x0b, 0xdb, 0xa3, 0xb8, 0x2f, 0xe9, 0x73, 0xb8, 0x33, 0xf4, 0x52, 0xce, 0x92, 0xb5, - 0xab, 0x31, 0xdd, 0xfd, 0x52, 0xfb, 0xdf, 0x97, 0xfe, 0x7b, 0xf2, 0x06, 0x02, 0xbb, 0x5f, 0x55, 0xcd, 0x37, 0x03, - 0xba, 0x5f, 0x55, 0x08, 0xfa, 0x2a, 0xdc, 0x68, 0xe7, 0x04, 0x72, 0x3b, 0xc1, 0xd3, 0xa0, 0x85, 0xac, 0xb6, 0xf4, - 0xb3, 0x0e, 0x23, 0xe9, 0x4c, 0x4b, 0x75, 0x1e, 0x48, 0x95, 0xa7, 0x06, 0xf9, 0x72, 0x75, 0x0b, 0x89, 0x99, 0x0c, - 0x43, 0xad, 0xc3, 0xef, 0xda, 0x1e, 0x23, 0x63, 0x52, 0x6d, 0x67, 0x7c, 0x1d, 0x65, 0x72, 0x1f, 0x4e, 0x99, 0xd8, - 0xb8, 0x87, 0x37, 0xa5, 0xe0, 0x41, 0xbb, 0xdf, 0x14, 0x8e, 0xb1, 0x9d, 0xeb, 0x7b, 0x40, 0xee, 0xf8, 0x54, 0x58, - 0xdd, 0xad, 0x6e, 0x65, 0x7c, 0x0d, 0xf6, 0x3f, 0x26, 0x53, 0x7b, 0x39, 0x8e, 0x19, 0x0e, 0xcc, 0xc2, 0x65, 0x51, - 0x3a, 0x05, 0x84, 0x56, 0xde, 0x32, 0x4c, 0x44, 0xa1, 0x02, 0xdc, 0x3f, 0x90, 0x6f, 0x0c, 0x4b, 0x1c, 0x97, 0x1c, - 0xe7, 0xe4, 0xbe, 0x1c, 0x51, 0x83, 0x5f, 0xc6, 0xef, 0x81, 0x8e, 0x15, 0x85, 0x16, 0x96, 0x8a, 0x9e, 0x0b, 0xb3, - 0x90, 0x9d, 0x69, 0xa9, 0x84, 0x95, 0x29, 0x35, 0x6a, 0x9a, 0x2d, 0x79, 0x9c, 0xd6, 0xca, 0x96, 0xe5, 0xa9, 0xaa, - 0xcd, 0x8b, 0x77, 0x60, 0xb1, 0x0a, 0x2d, 0xae, 0x56, 0x7e, 0x1d, 0xd5, 0x94, 0x3b, 0x91, 0x0c, 0x4c, 0xb8, 0x93, - 0x51, 0x51, 0xd3, 0xac, 0x75, 0x1f, 0x1f, 0xaf, 0x27, 0x14, 0x59, 0xdd, 0xbc, 0x06, 0x87, 0xeb, 0x42, 0xd0, 0xdd, - 0x5d, 0x9f, 0x02, 0xd1, 0xab, 0x2b, 0x27, 0x72, 0x30, 0xf4, 0x73, 0x99, 0x2a, 0x5b, 0xe5, 0xb4, 0x6e, 0xc1, 0x2f, - 0xbe, 0x23, 0x59, 0xd6, 0xa0, 0x6e, 0xb3, 0xde, 0x49, 0x36, 0x7a, 0x2e, 0x76, 0x25, 0x1b, 0xd5, 0xb4, 0xdd, 0xbd, - 0x16, 0xbe, 0x3b, 0x2d, 0x55, 0xcf, 0xb5, 0xbd, 0xc9, 0x6f, 0x98, 0xae, 0x0d, 0xb4, 0xa9, 0xd1, 0x6c, 0xb9, 0xca, - 0x59, 0x51, 0x8c, 0xcb, 0xcb, 0x04, 0x2a, 0x77, 0x67, 0xac, 0xe9, 0xdf, 0x58, 0x8d, 0xea, 0x3a, 0xae, 0xff, 0x03, - 0x9d, 0x24, 0xe2, 0x32, 0x4a, 0xde, 0xc3, 0x7c, 0x55, 0xe5, 0xcb, 0xdb, 0x38, 0x8b, 0x24, 0x33, 0xdc, 0xa5, 0x82, - 0xe1, 0x07, 0x07, 0x86, 0x1f, 0x34, 0x9f, 0xae, 0xfa, 0x93, 0xe5, 0xab, 0x72, 0x80, 0x70, 0x5c, 0x58, 0x96, 0x71, - 0x2e, 0xb7, 0xcf, 0xb1, 0xce, 0xc2, 0xce, 0x4b, 0x16, 0x76, 0x2e, 0xfd, 0xf5, 0xa1, 0x7c, 0xff, 0x9b, 0xed, 0xa3, - 0x6c, 0x72, 0xb6, 0x6f, 0xaa, 0x83, 0xff, 0x4d, 0x78, 0x67, 0x1f, 0x87, 0xcb, 0x1d, 0x05, 0x47, 0x2a, 0x5d, 0x45, - 0x83, 0xfc, 0x0e, 0xd2, 0x0e, 0x24, 0xed, 0x39, 0x77, 0x0e, 0x2a, 0x39, 0x65, 0x13, 0x81, 0xfc, 0xd1, 0x22, 0x97, - 0x62, 0x66, 0xc6, 0xcc, 0xcd, 0x35, 0x23, 0x55, 0x09, 0xae, 0x68, 0x15, 0x6d, 0x0f, 0xeb, 0x17, 0xb9, 0x96, 0x1f, - 0x79, 0x1a, 0x87, 0x39, 0x31, 0x52, 0x24, 0x0f, 0xd3, 0x82, 0xda, 0x64, 0xe3, 0xcd, 0x3a, 0x32, 0xe6, 0x29, 0xcf, - 0xa7, 0x2c, 0xf3, 0x05, 0x5e, 0xee, 0x9a, 0x4c, 0x40, 0x40, 0x46, 0x4f, 0x46, 0xbe, 0xad, 0x2e, 0xfc, 0x05, 0x30, - 0x1a, 0xf8, 0x81, 0x66, 0x4c, 0x4e, 0x45, 0x0c, 0x89, 0x29, 0x41, 0x5c, 0xde, 0x68, 0x3a, 0x38, 0xd8, 0xf3, 0x91, - 0x72, 0x4b, 0xc0, 0xd5, 0x6f, 0xb7, 0x06, 0xf7, 0x97, 0x70, 0x3d, 0xa7, 0x9a, 0x9a, 0xe1, 0x25, 0x5b, 0xbf, 0xc9, - 0x22, 0x83, 0x8f, 0xec, 0x96, 0x64, 0xb8, 0x28, 0x42, 0x0d, 0x35, 0x1a, 0x73, 0x96, 0xc4, 0x88, 0x7c, 0x64, 0xb7, - 0x61, 0x79, 0x5b, 0x5c, 0x5d, 0x6e, 0x56, 0x1b, 0x88, 0xc4, 0x75, 0x8a, 0x48, 0x35, 0x49, 0xb8, 0x2c, 0x88, 0xc8, - 0xf8, 0x04, 0x88, 0xf3, 0x6f, 0xec, 0x36, 0xd4, 0xe3, 0x71, 0xe7, 0xb2, 0x1e, 0x5e, 0x5a, 0xd4, 0x07, 0x4e, 0xb1, - 0xbb, 0x0d, 0xc6, 0xa0, 0x18, 0xa8, 0xbe, 0x43, 0x5a, 0x6b, 0x57, 0x99, 0x87, 0x18, 0x17, 0xf7, 0x5d, 0x0a, 0xf9, - 0xc2, 0x15, 0x6d, 0xb2, 0x96, 0xfa, 0xba, 0xd6, 0x89, 0x41, 0x87, 0x2a, 0xd7, 0xe3, 0xdc, 0xcf, 0xec, 0xa9, 0x33, - 0x77, 0x10, 0x1c, 0x47, 0xd8, 0x17, 0xd2, 0x0c, 0x1a, 0x7e, 0xab, 0x53, 0x42, 0xaa, 0x48, 0xd2, 0xeb, 0xaa, 0x9f, - 0x77, 0xee, 0x03, 0xde, 0x21, 0xa5, 0x25, 0x52, 0xd7, 0x31, 0x0b, 0x9b, 0x2e, 0xfa, 0x9d, 0xa4, 0xfe, 0xd2, 0x2e, - 0x21, 0xcc, 0x5c, 0x2c, 0xca, 0x02, 0xa8, 0xd0, 0xd0, 0x97, 0xce, 0x00, 0xe4, 0x63, 0x9f, 0x6f, 0x48, 0xcd, 0x54, - 0x49, 0xcd, 0xc0, 0xc1, 0xf8, 0x0e, 0x29, 0xc9, 0x14, 0x32, 0x94, 0x12, 0xa9, 0x84, 0x9e, 0xd9, 0x5c, 0x43, 0x42, - 0xee, 0x86, 0x96, 0xd7, 0xe7, 0xf4, 0x9e, 0xa7, 0x35, 0xb0, 0x7c, 0x35, 0x0e, 0x2e, 0x42, 0x58, 0x12, 0xd3, 0x0d, - 0x0a, 0xeb, 0xce, 0xc9, 0x6c, 0x7e, 0xab, 0x2f, 0x02, 0xbb, 0x2c, 0x6a, 0x51, 0xe2, 0x4f, 0xf1, 0x32, 0xf3, 0xa7, - 0x24, 0x85, 0x7c, 0x44, 0x51, 0x94, 0xf0, 0x33, 0x77, 0x37, 0x6a, 0xd9, 0xca, 0xdb, 0xaf, 0xf8, 0x81, 0x32, 0x2f, - 0x21, 0x47, 0x93, 0x64, 0x96, 0xa7, 0x64, 0xbe, 0xba, 0x6b, 0xe7, 0x6c, 0xdb, 0x57, 0x26, 0x45, 0xc7, 0x00, 0xf6, - 0x9d, 0xf4, 0x97, 0xce, 0x2a, 0xdc, 0xbb, 0xdc, 0xe6, 0xca, 0x9f, 0x09, 0xf6, 0x55, 0x49, 0xa4, 0x7e, 0x4e, 0xd7, - 0x24, 0xce, 0xdd, 0xb9, 0x96, 0x3f, 0x2f, 0x58, 0x76, 0x7b, 0xc6, 0x20, 0xd7, 0x59, 0xc0, 0x5d, 0xdf, 0x6a, 0x1b, - 0xaa, 0x3c, 0xf5, 0x7e, 0xaa, 0x94, 0x95, 0xa2, 0x7e, 0x09, 0x70, 0xfd, 0x8a, 0x60, 0xa1, 0xa2, 0x8d, 0x8e, 0x23, - 0x46, 0x9f, 0x16, 0xb6, 0xf3, 0xf2, 0x24, 0xeb, 0x72, 0xf0, 0xaf, 0x55, 0x98, 0x36, 0xc1, 0x02, 0x22, 0xdc, 0x0b, - 0xa9, 0x83, 0x7c, 0xb8, 0xee, 0x95, 0x81, 0x22, 0x08, 0xdf, 0xa5, 0xbb, 0x97, 0xba, 0x2d, 0x6b, 0x76, 0xf7, 0x52, - 0x6b, 0x41, 0x3f, 0x95, 0xf2, 0x43, 0xcc, 0x3c, 0xe5, 0xe5, 0x65, 0x5e, 0x14, 0xb8, 0x00, 0xf0, 0xbe, 0xef, 0xfa, - 0xfe, 0xf7, 0x26, 0x69, 0x30, 0x80, 0x58, 0xec, 0x59, 0x22, 0x2c, 0x13, 0xaf, 0xe6, 0xff, 0x7e, 0x63, 0xfe, 0xef, - 0x9d, 0x2b, 0xa7, 0x60, 0x1a, 0x4d, 0x52, 0x16, 0x5b, 0xd6, 0x89, 0x35, 0x01, 0x2a, 0xbd, 0x2d, 0x97, 0xf4, 0xe3, - 0x45, 0x08, 0x1a, 0xd7, 0x72, 0x2c, 0x52, 0xd9, 0x1c, 0x47, 0x33, 0x9e, 0xdc, 0x86, 0x0b, 0xde, 0x9c, 0x89, 0x54, - 0xe4, 0xf3, 0x68, 0xc4, 0x48, 0x7e, 0x9b, 0x4b, 0x36, 0x6b, 0x2e, 0x38, 0x79, 0xc9, 0x92, 0x2b, 0x26, 0xf9, 0x28, - 0x22, 0xe8, 0x24, 0xe3, 0x51, 0xe2, 0xbd, 0x89, 0xb2, 0x4c, 0x5c, 0x23, 0xf2, 0x4e, 0x5c, 0x0a, 0x29, 0xc8, 0xdb, - 0x9b, 0xdb, 0x09, 0x4b, 0xc9, 0x87, 0xcb, 0x45, 0x2a, 0x17, 0x24, 0x8f, 0xd2, 0xbc, 0x99, 0xb3, 0x8c, 0x8f, 0xbb, - 0x23, 0x91, 0x88, 0xac, 0x09, 0x29, 0xdb, 0x33, 0x16, 0x26, 0x7c, 0x32, 0x95, 0x5e, 0x1c, 0x65, 0x1f, 0xbb, 0xcd, - 0xe6, 0x3c, 0xe3, 0xb3, 0x28, 0xbb, 0x6d, 0xaa, 0x16, 0xe1, 0x67, 0xad, 0xa3, 0xe8, 0xf3, 0xf1, 0xc3, 0xae, 0xcc, - 0xa2, 0x34, 0xe7, 0xb0, 0x4d, 0x61, 0x94, 0x24, 0xde, 0xd1, 0xa3, 0xd6, 0x2c, 0xdf, 0xd3, 0x81, 0xbc, 0x28, 0x95, - 0xc5, 0x05, 0xf9, 0x08, 0x70, 0x07, 0x97, 0x32, 0x25, 0x97, 0x0b, 0x29, 0x45, 0xba, 0x1c, 0x2d, 0xb2, 0x5c, 0x64, - 0xe1, 0x5c, 0xf0, 0x54, 0xb2, 0xac, 0x7b, 0x29, 0xb2, 0x98, 0x65, 0xcd, 0x2c, 0x8a, 0xf9, 0x22, 0x0f, 0x1f, 0xce, - 0x6f, 0xba, 0xa0, 0x59, 0x4c, 0x32, 0xb1, 0x48, 0x63, 0x33, 0x17, 0x4f, 0xa7, 0x2c, 0xe3, 0xd2, 0xad, 0x50, 0xaf, - 0x30, 0x09, 0x13, 0x9e, 0xb2, 0x28, 0x6b, 0x4e, 0xa0, 0x33, 0x98, 0x45, 0xad, 0x98, 0x4d, 0x48, 0x36, 0xb9, 0x8c, - 0xfc, 0x76, 0xe7, 0x09, 0xb1, 0x7f, 0x83, 0x47, 0xd8, 0x6b, 0x6d, 0x2f, 0x6e, 0xb7, 0x5a, 0x7f, 0xc2, 0xdd, 0xb5, - 0x59, 0x14, 0x40, 0x61, 0x7b, 0x7e, 0xe3, 0xe5, 0x02, 0x72, 0xda, 0xb6, 0xf5, 0xec, 0xce, 0xa3, 0x18, 0x12, 0x82, - 0xc3, 0xce, 0xfc, 0xa6, 0x80, 0xd5, 0x85, 0x3a, 0xc9, 0xd4, 0x2c, 0xd2, 0x3c, 0x2d, 0x7f, 0x2b, 0xc4, 0x4f, 0xb7, - 0x43, 0xdc, 0xb1, 0x10, 0x57, 0x58, 0x6f, 0xc6, 0x8b, 0x4c, 0xc5, 0x56, 0xc3, 0x76, 0xae, 0x01, 0x99, 0x8a, 0x2b, - 0x96, 0x59, 0x38, 0xd4, 0xc3, 0x6f, 0x06, 0xa3, 0xb3, 0x1d, 0x8c, 0xa7, 0x9f, 0x02, 0x23, 0x4b, 0xe3, 0x65, 0x7d, - 0x5f, 0xdb, 0x19, 0x9b, 0x75, 0xa7, 0x0c, 0xe8, 0x29, 0xec, 0xc0, 0xef, 0x6b, 0x1e, 0xcb, 0xa9, 0xfe, 0xa9, 0xc8, - 0xf9, 0x5a, 0xd7, 0x3d, 0x6a, 0xb5, 0xf4, 0x73, 0xce, 0x7f, 0x61, 0x61, 0x3b, 0x80, 0x06, 0xc5, 0x05, 0xf9, 0x5b, - 0x79, 0x99, 0xb7, 0xce, 0x3d, 0xc9, 0x0f, 0xee, 0x2d, 0x5f, 0x27, 0x49, 0xb1, 0xba, 0x11, 0x4d, 0x32, 0x2b, 0x2b, - 0xb5, 0xf0, 0x01, 0xb7, 0x9d, 0x3a, 0x4f, 0x94, 0xf7, 0xca, 0x5b, 0x9c, 0xbc, 0xff, 0x83, 0xce, 0xbb, 0x08, 0x21, - 0xd2, 0xe1, 0x24, 0x1b, 0x8a, 0x6e, 0xda, 0xa3, 0xad, 0x6e, 0xda, 0x6c, 0x62, 0x5f, 0xd0, 0x6c, 0x90, 0x9a, 0xf4, - 0x3c, 0x9f, 0xf7, 0x85, 0x32, 0xb6, 0x73, 0x1c, 0x0a, 0xb8, 0x6a, 0xba, 0x5a, 0x55, 0x61, 0x00, 0xae, 0xae, 0x6b, - 0xfc, 0x4d, 0x9a, 0x06, 0x24, 0x77, 0x38, 0x79, 0x6a, 0x5f, 0xec, 0x92, 0x59, 0x5e, 0x91, 0x88, 0x91, 0xc2, 0x5c, - 0x30, 0x8f, 0xe4, 0x14, 0xbc, 0x14, 0xa5, 0xf8, 0xa9, 0x92, 0x98, 0xd0, 0x21, 0xc2, 0xfd, 0xac, 0xcc, 0x70, 0x83, - 0x4c, 0xbe, 0xac, 0x80, 0x51, 0xbe, 0x91, 0x14, 0x46, 0x24, 0xbf, 0x50, 0x6d, 0xd3, 0x59, 0x8b, 0x6e, 0x7c, 0x5f, - 0x8b, 0x8e, 0xa5, 0x92, 0xab, 0xdc, 0x6d, 0x1b, 0x71, 0x98, 0x46, 0xf9, 0xf9, 0x48, 0xdf, 0x95, 0xcc, 0xab, 0x9b, - 0x01, 0x91, 0x82, 0x5e, 0x1b, 0x69, 0x2c, 0x53, 0xf6, 0xe8, 0xf7, 0x72, 0xa7, 0x7d, 0x92, 0xdd, 0x65, 0x9f, 0x94, - 0x0b, 0xcf, 0xc5, 0x22, 0x1b, 0x41, 0x38, 0xd2, 0x48, 0xbd, 0x4d, 0xc7, 0x0d, 0x52, 0x2a, 0x06, 0x22, 0xd2, 0xc9, - 0x04, 0x95, 0x84, 0xbb, 0x2f, 0x95, 0x60, 0x2a, 0xe4, 0xa5, 0xef, 0x6b, 0x18, 0x11, 0x67, 0x97, 0x04, 0x32, 0x3b, - 0x56, 0x49, 0x8d, 0x7e, 0x4a, 0x7b, 0x69, 0xb0, 0x48, 0xf9, 0xcf, 0x0b, 0x76, 0xce, 0x41, 0xd7, 0xe4, 0x01, 0x8f, - 0x55, 0xac, 0x09, 0x64, 0x5f, 0xb3, 0x0d, 0xc1, 0x0b, 0x1e, 0xeb, 0x8d, 0x49, 0x55, 0xa5, 0xc9, 0x6d, 0x42, 0x4d, - 0x04, 0xfe, 0x62, 0xd0, 0x0e, 0x38, 0x89, 0xc5, 0x2c, 0xe2, 0x69, 0xa8, 0x5c, 0xbe, 0xe5, 0x60, 0x21, 0xb4, 0x26, - 0x3c, 0x0e, 0x53, 0xb3, 0x3d, 0x6d, 0x1c, 0xfc, 0x24, 0x78, 0xaa, 0xba, 0x16, 0x5d, 0xa1, 0x10, 0xaa, 0xd1, 0x47, - 0x2d, 0x82, 0x4f, 0xb4, 0x5c, 0x13, 0x98, 0xb8, 0xd5, 0xe5, 0xb5, 0xf3, 0xda, 0x0e, 0xb4, 0xd6, 0x36, 0x4a, 0x1b, - 0x01, 0x62, 0xbd, 0x34, 0x17, 0x99, 0xf4, 0xfd, 0x29, 0x49, 0x30, 0xed, 0x4d, 0x95, 0xb3, 0xeb, 0x38, 0x51, 0xff, - 0xf5, 0x9b, 0xed, 0xb0, 0x5d, 0x9a, 0xef, 0xb5, 0xdb, 0xc0, 0x3a, 0x39, 0xca, 0xdc, 0x28, 0x55, 0xcb, 0x28, 0x7f, - 0xeb, 0xa5, 0x56, 0xcf, 0xe5, 0x72, 0x89, 0x39, 0x6e, 0x5a, 0x54, 0xf9, 0x35, 0x20, 0x54, 0xb0, 0x68, 0xc7, 0x54, - 0xb8, 0xa8, 0xd6, 0x5d, 0xaa, 0x92, 0x17, 0x5a, 0x44, 0x9f, 0xef, 0x2f, 0x33, 0x33, 0x63, 0x71, 0xc1, 0xad, 0x93, - 0xa9, 0x4e, 0x72, 0x85, 0xc1, 0x88, 0xa3, 0x87, 0x6e, 0x6b, 0xa6, 0x61, 0xb9, 0xa5, 0xd9, 0x56, 0xba, 0x0d, 0xf4, - 0x23, 0xcb, 0x68, 0x15, 0xee, 0xda, 0x18, 0x00, 0x72, 0xf5, 0xb6, 0x01, 0x06, 0x66, 0x6b, 0x2e, 0xed, 0x12, 0x40, - 0x1b, 0x1b, 0x33, 0xb8, 0x48, 0x73, 0xb1, 0xbf, 0xfc, 0x46, 0x16, 0x87, 0x4e, 0x53, 0xf5, 0x9b, 0xc7, 0xf0, 0x3f, - 0x48, 0xc0, 0xa5, 0x56, 0x4a, 0x43, 0xf4, 0xf5, 0xdb, 0xb3, 0xf7, 0x88, 0x5c, 0x8a, 0xf8, 0x36, 0x44, 0x32, 0x5b, - 0x30, 0x54, 0xe0, 0x40, 0x4e, 0x59, 0x5a, 0xbe, 0x8c, 0x47, 0x24, 0x2c, 0x48, 0xc4, 0x44, 0x5f, 0xca, 0x5c, 0x37, - 0x92, 0x47, 0x17, 0xc7, 0xea, 0x25, 0x53, 0xbd, 0x63, 0xa9, 0x5f, 0xef, 0x25, 0x33, 0xf8, 0xd9, 0x83, 0x10, 0xca, - 0xf1, 0xa1, 0x9c, 0xaa, 0x87, 0x33, 0x38, 0x30, 0xea, 0x69, 0x7f, 0xb9, 0x41, 0x4c, 0x7d, 0x18, 0x62, 0xda, 0xd3, - 0x4b, 0xc8, 0x55, 0xab, 0x8b, 0x70, 0x74, 0x71, 0x51, 0x1c, 0x1f, 0xc2, 0x58, 0x87, 0x76, 0x5c, 0x80, 0xd0, 0xf6, - 0x2f, 0x09, 0x0c, 0x5e, 0x36, 0x94, 0xd1, 0x1e, 0x0c, 0x01, 0xf3, 0xc6, 0x3d, 0x58, 0x24, 0x10, 0x18, 0xf4, 0x8e, - 0xcb, 0x12, 0x75, 0x62, 0x75, 0xd1, 0x2e, 0x08, 0x74, 0xc3, 0x8a, 0xee, 0xb5, 0x37, 0xb5, 0xda, 0x5f, 0x0b, 0x52, - 0xec, 0x42, 0x77, 0x81, 0xe1, 0x7f, 0x05, 0xd9, 0xf1, 0xa1, 0xc6, 0xc3, 0x85, 0xfb, 0x6a, 0x13, 0xfd, 0xda, 0x81, - 0x12, 0x5b, 0x83, 0x5c, 0x92, 0x8f, 0x92, 0x7c, 0xbc, 0x50, 0x4d, 0xad, 0x30, 0x02, 0x2d, 0x09, 0x84, 0x76, 0xcb, - 0x6a, 0x1d, 0x23, 0x91, 0x24, 0xd1, 0x3c, 0x67, 0xa1, 0xfd, 0x61, 0xe4, 0x12, 0x88, 0xb7, 0x4d, 0x45, 0xc0, 0xa4, - 0xd7, 0x9c, 0x82, 0xba, 0xb0, 0xa9, 0xa5, 0x5c, 0x45, 0x99, 0xdf, 0x6c, 0x8e, 0x9a, 0x97, 0x13, 0x5c, 0xc8, 0xe9, - 0xd2, 0x95, 0x6a, 0x8f, 0x5b, 0xad, 0x2e, 0xe4, 0x42, 0x36, 0xa3, 0x84, 0x4f, 0xd2, 0x30, 0x61, 0x63, 0x59, 0x48, - 0xb8, 0xa5, 0xb6, 0xb4, 0x6a, 0x44, 0xd0, 0x79, 0x94, 0xb1, 0x99, 0x17, 0xc0, 0xbf, 0x77, 0x4f, 0x5c, 0xc8, 0x38, - 0x4c, 0xe5, 0xb4, 0xa9, 0xb2, 0x6e, 0xe1, 0xce, 0x80, 0x9c, 0xd6, 0x9e, 0x97, 0xce, 0x44, 0x23, 0x06, 0x2a, 0x56, - 0x21, 0x33, 0x4f, 0x4e, 0x89, 0xcc, 0xdc, 0x76, 0x29, 0x5e, 0x6e, 0xac, 0x60, 0x53, 0xd2, 0x1f, 0xe1, 0x22, 0x57, - 0x8a, 0xf1, 0x66, 0x63, 0xab, 0x2e, 0xd5, 0x9f, 0x36, 0xd0, 0xe7, 0x28, 0x76, 0x85, 0x76, 0x2c, 0x2f, 0x75, 0x8f, - 0xfb, 0x20, 0xb3, 0xa6, 0x72, 0x12, 0xb7, 0x07, 0x2e, 0x78, 0x3a, 0x5f, 0xc8, 0x81, 0x72, 0x6a, 0x67, 0x70, 0x41, - 0x62, 0x48, 0x9c, 0x12, 0xc0, 0xc1, 0x70, 0xa9, 0x81, 0x19, 0x45, 0xc9, 0xc8, 0x07, 0x88, 0xbc, 0xa6, 0xf7, 0x34, - 0x63, 0x33, 0xdc, 0x9d, 0xf1, 0xb4, 0xa9, 0xeb, 0x1e, 0x39, 0x6a, 0x49, 0xf0, 0x04, 0x9e, 0x8a, 0x40, 0x8d, 0x46, - 0x54, 0xee, 0xea, 0x16, 0x5c, 0x5e, 0x0c, 0x8b, 0xa2, 0x9b, 0x49, 0x7f, 0xf0, 0xda, 0xc7, 0x43, 0xf2, 0x8b, 0xf3, - 0x72, 0x16, 0x64, 0x8f, 0x0a, 0x22, 0x1d, 0xbc, 0xa3, 0x89, 0x7b, 0x16, 0x54, 0xb3, 0x5f, 0x28, 0x34, 0x7c, 0xe7, - 0x23, 0x96, 0xcf, 0x9b, 0x9a, 0x77, 0x35, 0x15, 0xc9, 0x22, 0xe8, 0x8a, 0x8d, 0xa7, 0xf6, 0x7b, 0xb9, 0x54, 0x6c, - 0xc9, 0x5c, 0xd2, 0xd0, 0xce, 0x84, 0x61, 0x79, 0xa9, 0xc7, 0x3c, 0xbb, 0xd7, 0x78, 0x70, 0x8d, 0x9f, 0x5c, 0x9c, - 0xd4, 0x79, 0x1c, 0xf0, 0xa5, 0xf2, 0x05, 0x76, 0x51, 0x92, 0xc0, 0x84, 0x17, 0x56, 0x7d, 0x71, 0x5f, 0xfa, 0x31, - 0x90, 0x43, 0x1f, 0x17, 0xe6, 0x9c, 0x3e, 0x53, 0x2a, 0xa5, 0xf3, 0xd6, 0xbc, 0x3d, 0x69, 0x83, 0x45, 0x5a, 0xfa, - 0x72, 0x08, 0x77, 0xd7, 0xf2, 0xa2, 0xbb, 0x15, 0xef, 0xd2, 0x0a, 0xa9, 0xa7, 0x16, 0x44, 0x51, 0x96, 0xc6, 0xc8, - 0xfb, 0xcb, 0x28, 0xe1, 0xa3, 0x8f, 0x14, 0xed, 0x2f, 0x7d, 0xbc, 0x79, 0xed, 0x51, 0x71, 0x05, 0xcb, 0xb0, 0x71, - 0xdd, 0x91, 0x9e, 0x06, 0x0e, 0x2f, 0xd6, 0x6f, 0xc5, 0x41, 0xbd, 0xfd, 0x25, 0x30, 0x1e, 0x3d, 0x4f, 0xef, 0xa2, - 0x38, 0xaf, 0xde, 0x75, 0x55, 0x41, 0x01, 0x68, 0xd6, 0xe5, 0x9e, 0x22, 0x2a, 0x8a, 0x3e, 0x49, 0x69, 0xc8, 0xd3, - 0x4c, 0x0d, 0xe0, 0x94, 0x86, 0xbf, 0x21, 0xef, 0x2f, 0x65, 0x19, 0x2b, 0x3d, 0x1a, 0x2a, 0x25, 0x83, 0x22, 0x98, - 0x0b, 0xcc, 0xd8, 0x20, 0x66, 0x32, 0xe2, 0x89, 0xee, 0xd2, 0xb5, 0x06, 0xf8, 0xda, 0x8a, 0x56, 0xab, 0xbc, 0xbe, - 0x16, 0x5e, 0xc7, 0xa0, 0x5a, 0xd9, 0xf1, 0x61, 0x05, 0xb7, 0x5a, 0x99, 0x3a, 0x93, 0x6e, 0x68, 0xb0, 0x5a, 0xa1, - 0xae, 0xf3, 0xfe, 0x32, 0x52, 0xd7, 0x86, 0x00, 0x40, 0x61, 0x00, 0x84, 0xa0, 0xb5, 0xbe, 0x16, 0xe3, 0x27, 0x54, - 0x04, 0x32, 0xca, 0x26, 0x4c, 0xae, 0x21, 0x36, 0xd1, 0x39, 0xaa, 0x5d, 0x1b, 0xa0, 0xde, 0x80, 0x36, 0xaa, 0x43, - 0x7b, 0x01, 0x48, 0xef, 0xef, 0x2f, 0x79, 0x41, 0xf7, 0x97, 0x2c, 0x1d, 0x89, 0x98, 0x7d, 0x78, 0xf7, 0x25, 0x5c, - 0x72, 0x14, 0x29, 0x18, 0x16, 0x53, 0x0c, 0x82, 0x53, 0x6d, 0x8e, 0x16, 0x21, 0x42, 0x89, 0x10, 0xcd, 0x09, 0x3c, - 0x35, 0x97, 0x02, 0xb1, 0x40, 0x5e, 0x5f, 0x43, 0xce, 0x62, 0x0d, 0x33, 0x4d, 0x55, 0x2f, 0x51, 0x1c, 0x1f, 0xea, - 0xd6, 0x5a, 0x04, 0xe8, 0x46, 0x80, 0x04, 0x75, 0x4e, 0x2b, 0x1c, 0x40, 0x5e, 0xb3, 0x8b, 0x87, 0x98, 0x5f, 0x95, - 0xc4, 0xa6, 0x2e, 0x50, 0xf5, 0x8e, 0x93, 0xe8, 0x92, 0x25, 0xbd, 0xfd, 0x65, 0xba, 0x5a, 0xb5, 0x8a, 0xe3, 0x43, - 0xfd, 0xe8, 0x1d, 0x2b, 0xbe, 0xa1, 0x5f, 0x78, 0xa9, 0xb6, 0x18, 0x6e, 0x25, 0x42, 0xb6, 0xa7, 0x4d, 0x73, 0x0a, - 0xcd, 0x00, 0x05, 0xf2, 0x54, 0x82, 0x85, 0x6a, 0x54, 0x2a, 0x44, 0x05, 0xf2, 0x78, 0xbc, 0x59, 0x96, 0x4b, 0x36, - 0x87, 0xd2, 0xe9, 0x6a, 0xd5, 0x2e, 0x90, 0x37, 0xe3, 0x29, 0x3c, 0xa5, 0xab, 0x95, 0xba, 0xf0, 0x37, 0xe3, 0xa9, - 0xdf, 0x02, 0xb2, 0x45, 0xde, 0x2c, 0xba, 0x51, 0x0b, 0xb6, 0x35, 0xd1, 0x8d, 0xdf, 0x36, 0x55, 0x41, 0x89, 0x9f, - 0x1c, 0x28, 0xae, 0xda, 0xd1, 0xc4, 0xec, 0x68, 0x4c, 0x16, 0xfa, 0x2a, 0x13, 0xf5, 0x63, 0x9a, 0x6c, 0xdf, 0xd1, - 0xd8, 0xee, 0xe8, 0x62, 0xc7, 0x8e, 0x2e, 0xee, 0xd8, 0xd1, 0xc8, 0xec, 0x9e, 0x57, 0xe2, 0x4e, 0xac, 0x56, 0xed, - 0x56, 0x85, 0xbd, 0xe3, 0xc3, 0x98, 0x5f, 0xc1, 0x6e, 0x80, 0x9a, 0x27, 0xf9, 0x8c, 0x6d, 0x27, 0xca, 0x3a, 0x8a, - 0xd9, 0xaf, 0xc2, 0x64, 0x85, 0x85, 0xb4, 0x8e, 0x05, 0x97, 0xae, 0xcb, 0x98, 0xdb, 0x1f, 0x49, 0xd9, 0x1c, 0xf0, - 0x90, 0x03, 0x1e, 0xa6, 0xf6, 0x05, 0x98, 0x3e, 0x7a, 0x8f, 0x08, 0xf2, 0x90, 0x25, 0xeb, 0x8b, 0xe2, 0x1c, 0x64, - 0x84, 0x5a, 0xdf, 0xbd, 0x68, 0x11, 0x5a, 0xa3, 0xde, 0x6e, 0x9a, 0x83, 0xf0, 0xf8, 0xb5, 0xc8, 0x62, 0x14, 0xea, - 0xa6, 0xbf, 0x0a, 0x55, 0x33, 0x9e, 0x9a, 0x64, 0xab, 0x9d, 0xb4, 0x56, 0xd5, 0xbb, 0x14, 0xd7, 0x79, 0xf4, 0x48, - 0xb7, 0x98, 0x47, 0x52, 0xb2, 0x2c, 0x35, 0x94, 0x8b, 0xd0, 0xff, 0x17, 0x54, 0xb8, 0x85, 0xaf, 0x44, 0x76, 0x03, - 0x2c, 0x01, 0x1a, 0x85, 0xdd, 0xf0, 0x7c, 0x2d, 0x9e, 0xf6, 0x2a, 0x0d, 0xf6, 0x16, 0xbb, 0x46, 0x83, 0x2e, 0x02, - 0x1b, 0x66, 0x31, 0x63, 0xf1, 0xb9, 0x62, 0xd0, 0xfd, 0xd1, 0x85, 0x51, 0x58, 0xd7, 0xc4, 0x5d, 0xd5, 0x81, 0xa0, - 0x1f, 0x17, 0x9d, 0x27, 0x0f, 0x4f, 0x11, 0xd1, 0x3c, 0x5e, 0x8c, 0xc7, 0x08, 0x17, 0xde, 0xfd, 0xba, 0xb5, 0x1f, - 0xfe, 0xb8, 0xf8, 0xe2, 0x45, 0xeb, 0x8b, 0xb2, 0x73, 0x0a, 0x44, 0x64, 0xe2, 0xfb, 0x56, 0x54, 0x39, 0xf0, 0xda, - 0x15, 0x8d, 0xa3, 0x74, 0xf7, 0x72, 0x06, 0xee, 0x72, 0xf2, 0x39, 0x63, 0x31, 0x10, 0x27, 0xd9, 0x28, 0x3d, 0x4f, - 0xd8, 0x15, 0xb3, 0x6f, 0x1e, 0xdc, 0x32, 0xd9, 0x96, 0x1e, 0x23, 0xb1, 0x48, 0xa5, 0x49, 0x74, 0x30, 0xac, 0xd6, - 0x59, 0xd2, 0x85, 0x5a, 0x83, 0x6b, 0x23, 0xdc, 0x6a, 0x39, 0x57, 0x97, 0x5e, 0xc5, 0x05, 0x41, 0x0e, 0x00, 0x3b, - 0x21, 0xeb, 0xef, 0x28, 0x0f, 0x5b, 0xa4, 0xb5, 0x0b, 0x36, 0xd2, 0xc6, 0x21, 0x42, 0x43, 0x8b, 0x27, 0xe5, 0xab, - 0xac, 0xbd, 0x30, 0x62, 0x27, 0xbe, 0x3e, 0x89, 0x81, 0xcb, 0x0c, 0x06, 0x4b, 0x59, 0x9e, 0xef, 0x44, 0x40, 0xb9, - 0x89, 0x04, 0x55, 0xad, 0xd1, 0x8e, 0x51, 0x48, 0x8b, 0xc0, 0x09, 0x53, 0x00, 0x97, 0x11, 0x53, 0xd3, 0x8a, 0x8d, - 0xc7, 0x6c, 0x54, 0xba, 0x7a, 0x21, 0xf6, 0x35, 0xe6, 0x89, 0x84, 0x10, 0x90, 0x8a, 0xcd, 0xa0, 0x37, 0x22, 0x65, - 0x08, 0xdb, 0x6c, 0x4e, 0x03, 0xbf, 0x91, 0xff, 0xdb, 0xe1, 0xd1, 0x23, 0xd6, 0x61, 0x31, 0xb3, 0xac, 0x56, 0xd6, - 0xcd, 0x53, 0x2b, 0xaf, 0x23, 0x52, 0x28, 0x3f, 0xce, 0xae, 0x03, 0x74, 0xbf, 0x63, 0xb2, 0x6c, 0x7f, 0xf1, 0xa8, - 0xdd, 0x2a, 0x10, 0x41, 0x30, 0xdc, 0x7d, 0x4f, 0x89, 0xea, 0x75, 0x04, 0xbd, 0x16, 0xe9, 0xaf, 0xe9, 0xd7, 0x69, - 0x7f, 0xde, 0x46, 0x44, 0xbf, 0x48, 0x00, 0x17, 0x25, 0x33, 0x18, 0x81, 0xf3, 0xf3, 0x77, 0x2f, 0xa5, 0x3e, 0xf8, - 0xfd, 0xe0, 0x79, 0xdc, 0x6e, 0x21, 0x82, 0x72, 0x29, 0xe6, 0xbf, 0x62, 0x09, 0x47, 0x88, 0xa0, 0x51, 0x22, 0x72, - 0xe6, 0xae, 0x41, 0xab, 0xb3, 0xbf, 0x7f, 0x11, 0x1a, 0xa2, 0x79, 0xc6, 0xf2, 0xdc, 0x73, 0xc7, 0x37, 0xa4, 0xf4, - 0x09, 0x86, 0xb9, 0x95, 0xe2, 0x72, 0x26, 0x15, 0x5e, 0xf4, 0x1d, 0x7f, 0x97, 0xaa, 0x74, 0xd9, 0x06, 0xb1, 0x29, - 0x11, 0x50, 0x32, 0x36, 0xad, 0x5d, 0x7d, 0x72, 0xe6, 0x2d, 0x47, 0x4f, 0x4f, 0xac, 0x63, 0xc2, 0x9b, 0x13, 0xd4, - 0x4a, 0x66, 0x3c, 0x3d, 0xdf, 0x52, 0x1a, 0xdd, 0x6c, 0x29, 0x05, 0x95, 0xad, 0x84, 0xce, 0xbc, 0x7e, 0xe6, 0xd3, - 0x58, 0xaf, 0x14, 0x1f, 0x17, 0xc4, 0x58, 0xf9, 0x2d, 0x3f, 0x01, 0xa9, 0xb3, 0x0d, 0x6a, 0x84, 0xdf, 0x3e, 0x1d, - 0x94, 0xfc, 0x9a, 0xe9, 0xca, 0x51, 0x7e, 0xdf, 0x0a, 0xa1, 0xb4, 0x09, 0xfe, 0xeb, 0xe4, 0x57, 0xad, 0x95, 0xdd, - 0x7c, 0x9a, 0xe0, 0x1c, 0xad, 0xea, 0x77, 0x6c, 0xbd, 0xb9, 0xc7, 0xbe, 0xbe, 0xf7, 0x5b, 0x8a, 0x8d, 0xe2, 0x53, - 0xee, 0xff, 0x28, 0xe1, 0xb3, 0x8a, 0x04, 0x36, 0xc1, 0x54, 0x1a, 0x0f, 0x24, 0x33, 0xb9, 0x83, 0x68, 0xd5, 0xe7, - 0x1c, 0xae, 0x68, 0xc2, 0x7b, 0x30, 0x16, 0x19, 0x3b, 0x4f, 0xc4, 0xf5, 0xfa, 0x7b, 0xbd, 0x76, 0x37, 0x9e, 0xf2, - 0xc9, 0xd4, 0xb9, 0x77, 0xc5, 0x68, 0xb9, 0x09, 0x77, 0x4e, 0x50, 0xfc, 0xeb, 0xbf, 0x04, 0xc1, 0xbf, 0xfe, 0xcb, - 0x27, 0x9b, 0xc2, 0xf0, 0xc5, 0x05, 0x91, 0xd5, 0xb0, 0xbb, 0x4f, 0xd7, 0xf6, 0x99, 0xea, 0x38, 0xdf, 0xde, 0x66, - 0x63, 0x13, 0xa0, 0x7e, 0x63, 0x0b, 0x36, 0x0a, 0xf5, 0xe9, 0xf3, 0x7e, 0x0b, 0x60, 0xb0, 0xae, 0x4f, 0x42, 0x06, - 0x8d, 0x7e, 0x17, 0x68, 0x17, 0x38, 0xbc, 0xd7, 0x8e, 0xfc, 0x76, 0x0c, 0x7f, 0x6a, 0x0d, 0xbf, 0x13, 0x7c, 0xe3, - 0x9f, 0x18, 0x5d, 0x5c, 0x94, 0x09, 0x76, 0x6e, 0x57, 0xb8, 0xc0, 0xdf, 0xdf, 0x28, 0x31, 0x8a, 0x47, 0xd8, 0xc2, - 0x3d, 0x75, 0x3d, 0x90, 0x8e, 0x2e, 0x5e, 0xc3, 0x5b, 0x7b, 0x8e, 0x2f, 0x33, 0xeb, 0xe0, 0xbd, 0x43, 0x38, 0xc0, - 0x10, 0xf5, 0x55, 0xa9, 0x41, 0x37, 0x24, 0x03, 0x94, 0x82, 0xb9, 0x01, 0x60, 0x92, 0xd1, 0x85, 0xb1, 0x36, 0x4f, - 0xb5, 0x1b, 0x26, 0x5c, 0x27, 0x6d, 0xe3, 0x9e, 0xa9, 0x21, 0x9d, 0x78, 0xef, 0x15, 0xbe, 0x54, 0x63, 0x56, 0x59, - 0xf7, 0xca, 0xd5, 0x05, 0x76, 0xc4, 0x45, 0xa1, 0xc2, 0xf4, 0x7f, 0xdd, 0x15, 0x49, 0xfc, 0xfb, 0xa7, 0x23, 0x89, - 0xe2, 0x5e, 0x91, 0xc4, 0xbf, 0xff, 0xe1, 0x91, 0xc4, 0xbf, 0xba, 0x91, 0x44, 0xd8, 0xc4, 0x2f, 0xef, 0x15, 0xed, - 0xb3, 0x91, 0x18, 0x71, 0x9d, 0xd3, 0xb6, 0x51, 0xa3, 0x13, 0x31, 0x81, 0x50, 0xdf, 0xbf, 0x7f, 0xe4, 0x2e, 0x11, - 0x13, 0x37, 0x6e, 0x07, 0x6f, 0x6d, 0x85, 0x40, 0x5d, 0xd7, 0x46, 0xd8, 0x4c, 0xac, 0xac, 0x55, 0xde, 0x48, 0x69, - 0x3e, 0xb4, 0x6f, 0x50, 0x40, 0x61, 0xf9, 0x16, 0xa4, 0x16, 0xe9, 0xd8, 0x68, 0x5a, 0xa8, 0x02, 0x71, 0x65, 0xc7, - 0x4e, 0xc3, 0x5e, 0xb7, 0x70, 0x47, 0xe8, 0xda, 0xb7, 0xbc, 0xe8, 0xdb, 0xf7, 0x4b, 0xf4, 0xe3, 0x4d, 0xfb, 0xd9, - 0xa0, 0xdd, 0x3d, 0x6a, 0xcf, 0x50, 0x88, 0x40, 0x44, 0xaa, 0x82, 0x56, 0xf7, 0xe8, 0x08, 0x0a, 0xae, 0x9d, 0x82, - 0x0e, 0x14, 0x70, 0xa7, 0xe0, 0x11, 0x14, 0x8c, 0x9c, 0x82, 0xc7, 0x50, 0x10, 0x3b, 0x05, 0x4f, 0xa0, 0xe0, 0x0a, - 0x15, 0x03, 0x5e, 0x82, 0xfb, 0x04, 0x0f, 0x89, 0xb6, 0x5c, 0x6c, 0xd9, 0x13, 0xd2, 0x86, 0x10, 0x5e, 0x34, 0x51, - 0x99, 0x47, 0xe0, 0x10, 0x0c, 0x05, 0xb9, 0x9e, 0xb2, 0x34, 0x84, 0x20, 0xea, 0x73, 0x25, 0x63, 0x02, 0x29, 0xde, - 0xf3, 0x19, 0xb3, 0xdf, 0xcb, 0xb0, 0x78, 0xf0, 0x10, 0x1e, 0xb4, 0x86, 0x45, 0xb7, 0xdc, 0x39, 0x1d, 0xfb, 0x33, - 0x59, 0x28, 0x7a, 0x2f, 0xab, 0x3a, 0x3d, 0x5d, 0xb3, 0xdc, 0xf3, 0x1d, 0x31, 0x24, 0xc7, 0x17, 0x31, 0x4e, 0xc4, - 0x75, 0xf3, 0x06, 0xf5, 0xb6, 0xc7, 0x95, 0x00, 0xa2, 0x32, 0xae, 0xa4, 0xd6, 0x54, 0x3e, 0xbd, 0x8f, 0x26, 0xe5, - 0xef, 0xd7, 0x2c, 0xcf, 0xa3, 0x89, 0x69, 0xb9, 0x3b, 0x8e, 0xa4, 0x40, 0x74, 0x63, 0x48, 0x16, 0x08, 0x88, 0x05, - 0xc1, 0x66, 0x81, 0x2d, 0x6f, 0x42, 0x43, 0x80, 0x9d, 0x7a, 0x54, 0x49, 0x4d, 0x5f, 0x2f, 0x92, 0xd1, 0xa4, 0x2a, - 0x38, 0x9e, 0x67, 0x4c, 0x95, 0x6a, 0x0c, 0x17, 0xc7, 0x87, 0x50, 0xa0, 0xab, 0x77, 0x44, 0x8f, 0xac, 0xe3, 0x60, - 0x77, 0x0c, 0xc9, 0xb3, 0xd1, 0x23, 0x37, 0xdf, 0xa6, 0x4c, 0xb6, 0xd9, 0x8c, 0x59, 0x7c, 0xd6, 0x1e, 0xc1, 0x1f, - 0x13, 0x11, 0xf9, 0x6c, 0x3c, 0x1e, 0xdf, 0x19, 0x4d, 0xfa, 0x2c, 0x1e, 0xb3, 0x0e, 0x7b, 0xd4, 0x85, 0x5c, 0x8c, - 0xa6, 0x89, 0x41, 0xb4, 0x0b, 0x85, 0xbb, 0xe5, 0xfd, 0x1a, 0x43, 0xb8, 0x42, 0x4e, 0x97, 0xf7, 0x8f, 0x2c, 0x15, - 0xf3, 0x8c, 0x2d, 0x67, 0x51, 0x36, 0xe1, 0x69, 0xd8, 0x2a, 0x82, 0x2b, 0x13, 0x8a, 0xf9, 0xec, 0xe9, 0xd3, 0xa7, - 0x45, 0x10, 0xdb, 0xa7, 0x56, 0x1c, 0x17, 0xc1, 0x68, 0x59, 0x2e, 0xa3, 0xd5, 0x1a, 0x8f, 0x8b, 0x80, 0xdb, 0x82, - 0xa3, 0xce, 0x28, 0x3e, 0xea, 0x14, 0xc1, 0xb5, 0xd3, 0xa2, 0x08, 0x98, 0x79, 0xca, 0x58, 0x5c, 0x4b, 0xe8, 0x78, - 0xd2, 0x6a, 0x15, 0x81, 0x26, 0xb4, 0x25, 0x98, 0x63, 0xfa, 0x67, 0x18, 0x2d, 0xa4, 0x00, 0x96, 0xdc, 0x15, 0xd2, - 0x1f, 0x9c, 0x9b, 0x97, 0x65, 0xe8, 0x0f, 0x4b, 0x14, 0x78, 0x48, 0xbe, 0x74, 0x83, 0x26, 0x40, 0xcc, 0x2a, 0x58, - 0x22, 0x6c, 0x4c, 0xa5, 0x56, 0x0d, 0x94, 0xa5, 0xaa, 0xbf, 0xa4, 0xa2, 0x8a, 0xa5, 0x00, 0xff, 0x81, 0x96, 0xfa, - 0xad, 0x6e, 0x92, 0xed, 0xe0, 0xfa, 0x8c, 0x7d, 0x92, 0xeb, 0xdf, 0xde, 0x87, 0xe9, 0x33, 0xf6, 0x47, 0x33, 0x7d, - 0xf3, 0xea, 0x53, 0xcd, 0xf4, 0x35, 0x5b, 0x9b, 0x49, 0x8a, 0x46, 0x53, 0x36, 0xfa, 0x78, 0x29, 0x6e, 0x9a, 0x70, - 0x24, 0x32, 0xa4, 0xf8, 0xe9, 0xfe, 0x6f, 0x4d, 0xfe, 0xb0, 0x83, 0x39, 0xdf, 0xa5, 0x50, 0x62, 0xf3, 0x6d, 0x4a, - 0xd1, 0x5b, 0x6b, 0xd3, 0xe9, 0x92, 0xf1, 0x98, 0xa2, 0xb7, 0xe3, 0x31, 0xb2, 0x57, 0xfe, 0x22, 0xc9, 0x54, 0xab, - 0x37, 0xb5, 0x12, 0xd5, 0xea, 0x8b, 0x2f, 0xdc, 0x32, 0xb7, 0xc0, 0x84, 0x5c, 0xdc, 0xf0, 0x8a, 0xa9, 0x89, 0x79, - 0x0e, 0x47, 0x0d, 0x3e, 0x97, 0x51, 0x7f, 0xe7, 0x60, 0x56, 0x7b, 0x3d, 0x74, 0x09, 0xf0, 0x96, 0x77, 0x5a, 0xaf, - 0xdf, 0x77, 0x9f, 0x30, 0x9b, 0x7e, 0xf7, 0xec, 0xf6, 0xcb, 0xd8, 0x9f, 0x49, 0x5c, 0xf0, 0xfc, 0x6d, 0xba, 0x76, - 0x97, 0x45, 0xc3, 0x48, 0xa9, 0xbb, 0xac, 0x42, 0x8a, 0xc9, 0x24, 0x81, 0x0f, 0x96, 0x2c, 0x6b, 0xef, 0x41, 0xd5, - 0xdd, 0xfb, 0xb5, 0xf5, 0x86, 0x6e, 0x47, 0xf3, 0xd6, 0x50, 0xf5, 0xfd, 0x24, 0x9d, 0x03, 0x7d, 0x65, 0x3e, 0xa4, - 0xa3, 0xcc, 0xc1, 0xa5, 0xe1, 0xff, 0x4b, 0x9d, 0x39, 0x2b, 0x21, 0x6b, 0x44, 0x0f, 0x1c, 0x17, 0x85, 0xb9, 0x73, - 0x10, 0xf3, 0x7c, 0x0e, 0xef, 0xe7, 0xd4, 0x3d, 0xd9, 0xa7, 0x58, 0x78, 0x7e, 0xed, 0xc4, 0x35, 0x6a, 0xdb, 0x55, - 0xd8, 0xc0, 0x86, 0x76, 0x14, 0xcf, 0x64, 0x81, 0x8c, 0xbf, 0xd9, 0x22, 0x11, 0x79, 0x1a, 0x9f, 0x3a, 0xe2, 0xe2, - 0xac, 0x10, 0x9c, 0xbe, 0xe5, 0x86, 0xd8, 0x2a, 0x5b, 0x50, 0xb8, 0x71, 0x3b, 0x55, 0xa3, 0xb1, 0xa5, 0xa2, 0x04, - 0xf9, 0x3c, 0x4a, 0x35, 0x1b, 0xa5, 0x48, 0xf3, 0x83, 0xfd, 0x65, 0xb5, 0xf3, 0x05, 0xb2, 0x60, 0x6b, 0xe2, 0xed, - 0x1d, 0x1f, 0x42, 0x87, 0x9e, 0x57, 0x03, 0x3d, 0xdd, 0x08, 0x2e, 0x7c, 0x22, 0xcc, 0x7f, 0x11, 0xe4, 0xd7, 0x24, - 0xc8, 0xaf, 0xbd, 0x3f, 0x2f, 0x9b, 0xd7, 0xec, 0xf2, 0x23, 0x97, 0x4d, 0x19, 0xcd, 0x9b, 0xa0, 0xf0, 0x2b, 0xa7, - 0xa0, 0x61, 0xcf, 0x2a, 0x59, 0x4d, 0xdf, 0xd8, 0xef, 0x2e, 0x72, 0xc8, 0x06, 0x50, 0x6a, 0x6b, 0x98, 0x8a, 0x94, - 0x75, 0xeb, 0x49, 0x89, 0x6e, 0x70, 0xd9, 0x62, 0x6b, 0xb8, 0x14, 0x90, 0x3d, 0x20, 0x6f, 0xc3, 0x96, 0x61, 0xeb, - 0x2d, 0x1b, 0x39, 0x6e, 0x6d, 0x6d, 0x1f, 0x1a, 0xe4, 0x36, 0x94, 0xf4, 0xca, 0x36, 0x23, 0xe8, 0xbb, 0x22, 0xe0, - 0x9f, 0x4a, 0xd1, 0x03, 0x57, 0xa2, 0xfd, 0xeb, 0xe4, 0x36, 0xae, 0x17, 0xab, 0x14, 0xbd, 0xfb, 0x40, 0x16, 0x46, - 0x63, 0xc9, 0x32, 0x72, 0x9f, 0x96, 0x97, 0xea, 0x36, 0xcd, 0x12, 0xc4, 0x4c, 0xd8, 0x7e, 0x3a, 0xbf, 0xb9, 0xff, - 0xf0, 0x77, 0x2f, 0xbf, 0x30, 0x38, 0xb2, 0x6f, 0x97, 0x41, 0xa8, 0x0b, 0x07, 0x21, 0x89, 0x6e, 0x43, 0x9e, 0x2a, - 0x99, 0x77, 0x09, 0xfe, 0xc0, 0xee, 0x5c, 0x98, 0x5c, 0xd3, 0x8c, 0x25, 0xea, 0x53, 0x72, 0x66, 0x2b, 0x8e, 0x1e, - 0xcf, 0x6f, 0xec, 0x6e, 0xb4, 0xd7, 0x72, 0x48, 0xff, 0xd0, 0x54, 0xd1, 0xdd, 0xb9, 0xa9, 0xf5, 0x74, 0xc7, 0x47, - 0xf3, 0x9b, 0xae, 0x16, 0xb4, 0xcd, 0x4c, 0x43, 0xd5, 0x9a, 0xdf, 0xb8, 0xc9, 0xb2, 0xd5, 0x40, 0x5e, 0x70, 0x94, - 0x7b, 0x2c, 0xca, 0x59, 0x17, 0xde, 0x9f, 0xcd, 0x47, 0x51, 0x62, 0x84, 0xf9, 0x8c, 0xc7, 0x71, 0xc2, 0xba, 0x56, - 0x5e, 0x7b, 0xed, 0xc7, 0x90, 0x6b, 0xea, 0x6e, 0x59, 0x7d, 0x57, 0x1c, 0xe4, 0x95, 0x78, 0x8a, 0x2e, 0x73, 0x91, - 0xc0, 0xc7, 0x2b, 0xb6, 0xa2, 0xd3, 0x24, 0x61, 0xb6, 0x2a, 0xe4, 0xa9, 0xdf, 0xf5, 0xb5, 0x3c, 0x6a, 0xfd, 0xa9, - 0xab, 0x36, 0xbc, 0xd5, 0x95, 0x62, 0x1e, 0x36, 0x8f, 0xea, 0x0b, 0x81, 0xaa, 0x72, 0x09, 0x64, 0xcb, 0xb2, 0x08, - 0x48, 0x2b, 0xcd, 0xa7, 0xbd, 0xa0, 0x6d, 0xca, 0xd4, 0x00, 0xf0, 0xa2, 0xe7, 0xb2, 0xa8, 0xa8, 0x2f, 0xe6, 0xdf, - 0xe7, 0xb4, 0x7c, 0xbe, 0xfd, 0xb4, 0x7c, 0x6e, 0x4f, 0xcb, 0xdd, 0x14, 0xfb, 0xd9, 0xb8, 0x0d, 0x7f, 0xba, 0xd5, - 0x82, 0xc2, 0x96, 0x77, 0x34, 0xbf, 0xf1, 0x40, 0x4f, 0x6b, 0x76, 0xe6, 0x37, 0x3a, 0x55, 0x18, 0x62, 0x16, 0x2d, - 0x48, 0x9e, 0x25, 0x2d, 0x0f, 0x0a, 0xe1, 0x6f, 0xab, 0x56, 0xd5, 0x7e, 0x08, 0x75, 0xd0, 0xeb, 0xd1, 0x66, 0x5d, - 0xe7, 0xee, 0x43, 0x1b, 0xa6, 0x42, 0xfa, 0xa1, 0xe5, 0xc6, 0x38, 0x90, 0xd1, 0xe5, 0x25, 0x8b, 0xc3, 0xb1, 0x18, - 0x2d, 0xf2, 0x7f, 0x36, 0xf0, 0x1b, 0x24, 0xde, 0x79, 0xa4, 0xd7, 0xc6, 0xb1, 0x5d, 0x75, 0xe2, 0xb2, 0x1d, 0x61, - 0x59, 0xee, 0x53, 0x98, 0x8f, 0xa2, 0x84, 0xf9, 0x9d, 0xe0, 0xe1, 0x96, 0x43, 0xf0, 0x1f, 0xb2, 0x37, 0x5b, 0x17, - 0xf3, 0x7b, 0x91, 0x71, 0x27, 0x12, 0x7e, 0x15, 0x0e, 0xdc, 0x3d, 0x6c, 0x3d, 0xdd, 0x0e, 0xee, 0xc0, 0xce, 0x34, - 0xb4, 0x42, 0xc1, 0xc8, 0x9d, 0x98, 0x8d, 0xa3, 0x45, 0x22, 0xef, 0x1e, 0x75, 0x17, 0x65, 0x6c, 0x8c, 0x7a, 0x07, - 0x43, 0xaf, 0xda, 0xde, 0x93, 0x4b, 0x7f, 0xf6, 0xf9, 0x43, 0xf8, 0xa3, 0xf3, 0x9e, 0x6e, 0x2b, 0x5d, 0x5d, 0xdb, - 0xaa, 0xa0, 0xab, 0xef, 0xd7, 0x94, 0x71, 0x2d, 0xc2, 0x95, 0x3e, 0x7e, 0xdf, 0xd6, 0xa0, 0x55, 0xde, 0xab, 0xb9, - 0xd1, 0xb2, 0x7e, 0x55, 0xeb, 0x5f, 0x37, 0xf8, 0x3d, 0xdb, 0x8e, 0xb4, 0xe6, 0x5a, 0x6f, 0x6b, 0xbe, 0xa5, 0xb7, - 0xd1, 0xd8, 0x62, 0x5c, 0xb5, 0xdf, 0xa7, 0xb7, 0xa5, 0x89, 0xa2, 0xa3, 0x90, 0x60, 0xa5, 0xec, 0x6b, 0x2b, 0x85, - 0x33, 0xfa, 0x00, 0xde, 0x64, 0xeb, 0xdd, 0xcc, 0x92, 0x34, 0xa7, 0x68, 0x2a, 0xe5, 0x3c, 0xd4, 0x1f, 0x5f, 0xbd, - 0x3e, 0x0a, 0x44, 0x36, 0x39, 0xec, 0xb4, 0x5a, 0x2d, 0x78, 0x03, 0x29, 0xf2, 0xae, 0x38, 0xbb, 0x7e, 0x26, 0x6e, - 0x28, 0x7a, 0xe2, 0x3d, 0xf5, 0x9e, 0x1c, 0x79, 0x8f, 0x1e, 0x23, 0x4f, 0xb1, 0x73, 0x8a, 0x9e, 0x1c, 0x21, 0x4f, - 0xb3, 0x73, 0x8a, 0x1e, 0x3d, 0x46, 0xbd, 0xe3, 0x89, 0x55, 0xc9, 0xe0, 0x0a, 0xa3, 0xd6, 0x77, 0x72, 0x99, 0x89, - 0x8f, 0xac, 0x7e, 0x70, 0x75, 0x99, 0xc9, 0x8c, 0xeb, 0xd8, 0x47, 0x38, 0xbd, 0xa3, 0x68, 0x1e, 0x2a, 0xa2, 0x70, - 0x0b, 0xc1, 0x2d, 0xa3, 0x4b, 0xd5, 0x14, 0xa0, 0x66, 0x5e, 0xa2, 0xde, 0x31, 0x64, 0xb1, 0x7b, 0x31, 0x45, 0xaf, - 0x3b, 0x4f, 0xbc, 0xf6, 0xe3, 0xab, 0xe6, 0xc3, 0x51, 0xab, 0xd9, 0xf6, 0xda, 0xcd, 0x4e, 0xf0, 0xc4, 0xeb, 0xe8, - 0x7f, 0xbd, 0x96, 0x77, 0xe4, 0xb5, 0x83, 0x27, 0xde, 0x91, 0xd7, 0x09, 0x9e, 0x5c, 0x3d, 0xd4, 0xc9, 0x0c, 0x11, - 0x3a, 0xec, 0x1d, 0xc3, 0x87, 0x34, 0x6f, 0x28, 0xfa, 0x1c, 0xe9, 0xcf, 0xd5, 0xa2, 0xcf, 0xdc, 0xd2, 0xf6, 0xd3, - 0xad, 0xc5, 0x9d, 0x27, 0x5b, 0x8b, 0x8f, 0x1e, 0x6f, 0x2d, 0x7e, 0xf8, 0xa8, 0x5e, 0x7c, 0x38, 0xd1, 0x55, 0xe5, - 0x29, 0xa7, 0x68, 0x16, 0xc9, 0x8c, 0xdf, 0xf8, 0x6d, 0xaf, 0xe5, 0xb5, 0xbc, 0x26, 0xfc, 0xf7, 0xa4, 0x83, 0xcb, - 0x5e, 0x97, 0xd0, 0xab, 0x5c, 0xe5, 0x93, 0xa7, 0x5e, 0xfb, 0xf1, 0xcb, 0xce, 0xe3, 0x11, 0xb4, 0x53, 0x0b, 0x6d, - 0x7b, 0xed, 0xab, 0xa3, 0xa7, 0xa3, 0x96, 0x07, 0x1d, 0xdb, 0xf0, 0x67, 0xfa, 0xa8, 0x33, 0xd2, 0x0f, 0x2d, 0xa8, - 0xff, 0xb6, 0xfd, 0x24, 0x6f, 0x35, 0xdb, 0xf0, 0xe7, 0x97, 0x52, 0x23, 0x06, 0x7d, 0xdc, 0x1d, 0xf7, 0x61, 0xcb, - 0x3b, 0x7a, 0x3a, 0xed, 0x04, 0x9f, 0x5f, 0x3d, 0x09, 0x9e, 0x4e, 0xdb, 0x4f, 0xbe, 0xd5, 0x4f, 0x49, 0xb3, 0x13, - 0x7c, 0x0e, 0x7f, 0xbf, 0x3d, 0x6a, 0x4d, 0x9b, 0xed, 0xe0, 0xe9, 0xd5, 0x51, 0x70, 0x94, 0x34, 0x1f, 0x07, 0x4f, - 0xe1, 0x6f, 0x35, 0xdc, 0x54, 0xcc, 0x18, 0xf2, 0x60, 0xbf, 0xd7, 0xcc, 0x2d, 0x77, 0x8e, 0xce, 0x43, 0xef, 0xd1, - 0xc3, 0x97, 0x4f, 0xaf, 0x9a, 0x0f, 0xa7, 0xed, 0xce, 0x55, 0x73, 0xe7, 0xcf, 0x6f, 0x01, 0xf1, 0x66, 0xe0, 0x88, - 0xc1, 0x75, 0x22, 0x8b, 0x38, 0xf5, 0x36, 0xdc, 0x07, 0x24, 0xdf, 0x65, 0x5e, 0x67, 0x9f, 0x36, 0xaf, 0x53, 0x76, - 0x1f, 0xfb, 0x3a, 0xfb, 0xc3, 0xed, 0xeb, 0x9c, 0xad, 0x39, 0x55, 0x6f, 0xe5, 0x86, 0x19, 0xbd, 0x6e, 0x7b, 0xbd, - 0x93, 0xfe, 0x80, 0xc3, 0x57, 0x97, 0x8a, 0xee, 0x2d, 0xbc, 0x70, 0xdb, 0xf5, 0x36, 0x08, 0x38, 0xc8, 0xb7, 0x52, - 0x9f, 0x64, 0xb1, 0x0b, 0x21, 0xc9, 0xa7, 0x11, 0xf2, 0xed, 0x7d, 0xf0, 0x91, 0xfc, 0xe1, 0xf8, 0x10, 0x2e, 0x3e, - 0x6a, 0x7e, 0x5e, 0x65, 0xcf, 0x2a, 0x7b, 0xf4, 0x4c, 0x3d, 0xfb, 0x70, 0xe3, 0xa4, 0x81, 0x0e, 0x19, 0x14, 0xe5, - 0x48, 0xc7, 0x15, 0x5e, 0xfe, 0x1a, 0x97, 0xb4, 0xbe, 0x5e, 0x46, 0x91, 0x31, 0xfe, 0xe7, 0xf0, 0x65, 0x05, 0xfb, - 0x70, 0xa5, 0x2f, 0x3c, 0x53, 0xd4, 0x09, 0x5a, 0x41, 0xab, 0x74, 0x1c, 0xc0, 0x95, 0x42, 0xba, 0x14, 0x32, 0x82, - 0x8f, 0x7b, 0x26, 0x62, 0xa2, 0x3e, 0x03, 0x0a, 0x2f, 0x5f, 0x57, 0x1f, 0x64, 0xd5, 0xef, 0xbd, 0x0f, 0x11, 0x32, - 0x2f, 0x22, 0x80, 0x2b, 0x6b, 0xdf, 0xc0, 0xb5, 0x3e, 0xeb, 0xb1, 0x9e, 0x81, 0x4d, 0xfd, 0x9a, 0xc5, 0x3c, 0xf2, - 0x91, 0x3f, 0xcf, 0xd8, 0x98, 0x65, 0x79, 0xb3, 0x76, 0xd7, 0x4d, 0x5d, 0x73, 0xc3, 0xc8, 0x7e, 0x46, 0x32, 0x83, - 0x97, 0x09, 0xd3, 0x81, 0xf1, 0x6a, 0x21, 0xa3, 0xe6, 0xa3, 0x82, 0xd8, 0x92, 0x0c, 0x38, 0x7a, 0xa5, 0x1a, 0x20, - 0xad, 0x1b, 0xb4, 0x83, 0xce, 0x23, 0xac, 0x79, 0x09, 0xbc, 0xa4, 0xf5, 0x7b, 0xbf, 0x79, 0xd4, 0xfa, 0x13, 0x76, - 0xba, 0x95, 0x03, 0x0d, 0x8d, 0x53, 0x27, 0xab, 0x3e, 0xbf, 0x5b, 0xbf, 0x88, 0x88, 0x34, 0x45, 0x7c, 0xa6, 0xd7, - 0x0e, 0xaf, 0x7b, 0x35, 0xf1, 0x43, 0x7d, 0x9d, 0x7e, 0xcc, 0x27, 0xbe, 0xfb, 0x71, 0x55, 0xfd, 0x12, 0x58, 0xf5, - 0x4d, 0x66, 0x5c, 0x54, 0x4d, 0x32, 0xbc, 0x54, 0xbe, 0x78, 0x9e, 0x7a, 0xd9, 0x6a, 0xe5, 0x67, 0xe0, 0x88, 0xa5, - 0x0e, 0x4e, 0xe1, 0x19, 0xd7, 0x90, 0x9c, 0x91, 0x12, 0x20, 0x85, 0x60, 0x9a, 0xe9, 0xff, 0xab, 0x62, 0xfb, 0xc3, - 0xb8, 0x57, 0x82, 0x24, 0x4a, 0x27, 0x40, 0x85, 0x51, 0x3a, 0xd9, 0x70, 0xde, 0xe8, 0x70, 0xc2, 0x5a, 0x69, 0x35, - 0x54, 0xe5, 0xa4, 0xc9, 0x9f, 0xdd, 0xbe, 0x37, 0x6f, 0x8b, 0x42, 0xe0, 0x03, 0x55, 0xbe, 0xef, 0xea, 0xcd, 0xb6, - 0x0d, 0xfa, 0x40, 0x7f, 0xae, 0x5c, 0x65, 0xc3, 0x81, 0xf4, 0x83, 0x2b, 0x86, 0x9e, 0xb1, 0x79, 0x28, 0xd2, 0xb2, - 0x2f, 0x66, 0x57, 0x7c, 0x64, 0x44, 0x18, 0xf1, 0xcc, 0x35, 0xeb, 0xa6, 0xda, 0x1a, 0xda, 0x26, 0xda, 0xea, 0x1f, - 0x45, 0x2a, 0xdf, 0x99, 0xa6, 0x02, 0xf5, 0x1e, 0x94, 0xdf, 0x8a, 0xdc, 0xb5, 0x09, 0xf0, 0x0d, 0xf5, 0x41, 0xc6, - 0x92, 0x7f, 0xa6, 0x0f, 0xe0, 0x2b, 0xea, 0x0f, 0x86, 0xf0, 0x01, 0xef, 0x40, 0x89, 0x82, 0x07, 0xd5, 0xc7, 0xd4, - 0x81, 0x0f, 0x36, 0x6e, 0x66, 0x09, 0xb9, 0xaf, 0xf8, 0x36, 0xa2, 0xba, 0xf3, 0xa8, 0x12, 0xd5, 0x9d, 0x47, 0xae, - 0xf4, 0x6c, 0x7b, 0xed, 0x4e, 0xf0, 0xc8, 0x11, 0x00, 0x57, 0x4d, 0xf8, 0xbf, 0x26, 0x02, 0x1e, 0x06, 0x8f, 0x4a, - 0x19, 0xf0, 0xaa, 0xdd, 0x09, 0x8e, 0xb4, 0xb8, 0xe9, 0x04, 0x8f, 0x7e, 0x50, 0x0c, 0x5a, 0x33, 0xe7, 0xfa, 0x81, - 0xd8, 0x12, 0xaa, 0xd1, 0x19, 0x7d, 0x88, 0xf8, 0xe5, 0x17, 0xe9, 0xcc, 0xf9, 0x34, 0x2e, 0xa1, 0xe7, 0x51, 0x06, - 0x9f, 0x05, 0xa9, 0x9f, 0xdd, 0x5a, 0x1d, 0xa9, 0xf1, 0x8b, 0x2d, 0x53, 0xc0, 0x09, 0x47, 0xc4, 0xbd, 0xa7, 0x0c, - 0x97, 0x7c, 0xd5, 0x4b, 0x94, 0xed, 0xbb, 0xe4, 0x76, 0x93, 0xb6, 0x6e, 0x68, 0xdf, 0x57, 0xa7, 0x98, 0x05, 0x57, - 0x2f, 0xac, 0x57, 0x93, 0x7c, 0x19, 0x17, 0xeb, 0xf3, 0x43, 0x62, 0x61, 0x26, 0x9c, 0xab, 0xda, 0xac, 0x4a, 0x87, - 0x8f, 0x39, 0x5c, 0xae, 0x2f, 0x0a, 0x0b, 0x7a, 0xcd, 0x19, 0x58, 0x61, 0x49, 0xf1, 0x0b, 0x96, 0xf7, 0x11, 0x14, - 0xa1, 0x10, 0x29, 0x47, 0x12, 0x2a, 0x3f, 0x8d, 0x52, 0x12, 0x76, 0x55, 0x40, 0xd4, 0x95, 0x16, 0x38, 0xb5, 0x80, - 0x1f, 0x84, 0x0f, 0x0e, 0x76, 0x9e, 0x17, 0xa5, 0x8d, 0xc1, 0x5a, 0xab, 0x4f, 0x2a, 0xb8, 0xac, 0x08, 0xb9, 0x88, - 0x2e, 0xc7, 0x55, 0x28, 0xc4, 0x06, 0x4f, 0x97, 0x2c, 0x92, 0x41, 0x94, 0xea, 0x14, 0x05, 0x87, 0x61, 0x91, 0x36, - 0x3b, 0xc2, 0x85, 0x90, 0x91, 0xf3, 0xcd, 0x54, 0x73, 0xce, 0x85, 0x8c, 0xec, 0xc5, 0xc3, 0x54, 0xd6, 0x32, 0xf3, - 0xa7, 0x9d, 0xde, 0xdb, 0xf7, 0x27, 0x9e, 0x3e, 0x9e, 0xc7, 0x87, 0xd3, 0x4e, 0xef, 0x58, 0x59, 0xe6, 0xfa, 0xda, - 0x12, 0xd5, 0xd7, 0x96, 0x3c, 0x73, 0x85, 0x0d, 0xe2, 0x35, 0xc5, 0xa1, 0x5e, 0x36, 0xf2, 0x58, 0x3a, 0xd2, 0x3e, - 0xc5, 0xd9, 0x22, 0x91, 0x1c, 0x5e, 0x08, 0x7c, 0x08, 0x5d, 0x9b, 0xb0, 0x61, 0x65, 0x96, 0xab, 0xd5, 0x70, 0x64, - 0x6a, 0x3d, 0x90, 0x63, 0x9e, 0x30, 0x9b, 0xd7, 0x6a, 0x86, 0x2a, 0xf3, 0xb0, 0x37, 0x5b, 0xe7, 0x8b, 0xcb, 0x19, - 0x97, 0xc8, 0x66, 0x8b, 0x7f, 0x30, 0x1d, 0x8e, 0xd5, 0x54, 0xbd, 0x8b, 0xc2, 0xb8, 0x48, 0xed, 0xc7, 0x4f, 0xd6, - 0x3e, 0x37, 0xaf, 0x57, 0x6f, 0x24, 0x04, 0xdc, 0x3f, 0x9a, 0x1e, 0xf5, 0x4a, 0xa7, 0xa4, 0x5b, 0x57, 0x1c, 0x1f, - 0x4e, 0x8f, 0x7a, 0x17, 0xe1, 0xdc, 0x8c, 0xf7, 0x4a, 0x6c, 0x7c, 0xba, 0xbe, 0xe4, 0x98, 0x7d, 0x95, 0x68, 0xaf, - 0x6f, 0x74, 0x1a, 0x80, 0x47, 0x22, 0x41, 0xbd, 0x63, 0xa3, 0x0c, 0x78, 0x2a, 0xe8, 0x8a, 0x1e, 0xb5, 0x6c, 0xee, - 0x7e, 0x22, 0x94, 0xb6, 0xa4, 0xbb, 0x38, 0x93, 0xd4, 0xfc, 0xba, 0xd3, 0x76, 0xef, 0x38, 0x32, 0x6a, 0x26, 0x30, - 0x8f, 0x3c, 0x3c, 0x84, 0xce, 0xa0, 0xcb, 0x05, 0x5c, 0x1c, 0x5e, 0xb3, 0xcb, 0x66, 0x34, 0xe7, 0x95, 0x13, 0x15, - 0x94, 0x8e, 0x72, 0x4a, 0x51, 0xcd, 0x04, 0x3f, 0xa3, 0xb5, 0x45, 0x2a, 0x16, 0x5e, 0x18, 0x0f, 0xad, 0xd2, 0xd5, - 0x59, 0x24, 0x91, 0xa7, 0x39, 0xbc, 0xf5, 0xe4, 0x1a, 0xd9, 0x5b, 0xa0, 0xde, 0xbf, 0xfd, 0x8f, 0xff, 0x65, 0x9c, - 0xb3, 0xc7, 0x87, 0xd3, 0xb6, 0x1d, 0x6b, 0x0d, 0xd1, 0xc5, 0x31, 0x5c, 0x77, 0xab, 0xa2, 0x89, 0xec, 0xa6, 0x39, - 0xc9, 0x78, 0xdc, 0x9c, 0x46, 0xc9, 0x18, 0xf5, 0x76, 0x23, 0xc8, 0xbd, 0xe7, 0x62, 0xa0, 0xae, 0x17, 0x01, 0x09, - 0xfe, 0xa6, 0x9b, 0x1a, 0x36, 0xe1, 0x5f, 0x9d, 0x56, 0xf7, 0xde, 0x46, 0x75, 0xa0, 0x6a, 0x77, 0x37, 0x32, 0xf3, - 0x8d, 0x24, 0xc3, 0xd4, 0xb2, 0xda, 0x95, 0x8d, 0x02, 0x79, 0x65, 0x34, 0xe4, 0xff, 0xfe, 0xcf, 0xff, 0xf2, 0xdf, - 0xec, 0x23, 0x04, 0x39, 0xfe, 0xed, 0xbf, 0xff, 0xe7, 0xff, 0xf3, 0xbf, 0xff, 0x2b, 0xa4, 0xf9, 0x9b, 0x40, 0x88, - 0xe2, 0x13, 0x5e, 0x15, 0x05, 0xd1, 0x0c, 0xc3, 0x83, 0x4c, 0xb8, 0x19, 0xcf, 0x25, 0x1f, 0xd5, 0x2f, 0x71, 0x9c, - 0xa9, 0x09, 0xd5, 0x61, 0x33, 0xd0, 0xa9, 0x43, 0x5b, 0x54, 0x34, 0x52, 0x43, 0xb9, 0xa2, 0xc5, 0xe2, 0xf8, 0x10, - 0xf0, 0x7d, 0xbf, 0x7b, 0x6f, 0x41, 0xb9, 0x1d, 0x4b, 0xeb, 0xfa, 0x83, 0x92, 0xa2, 0x2a, 0xf7, 0xc0, 0x29, 0xbf, - 0x84, 0xc7, 0xb0, 0xe3, 0x14, 0xab, 0xdd, 0xab, 0xf5, 0xe9, 0xfe, 0xb4, 0xc8, 0x25, 0x1f, 0x03, 0xca, 0xb5, 0x83, - 0x51, 0xc5, 0x3f, 0x9b, 0xa0, 0xfe, 0x25, 0xb7, 0x85, 0x1a, 0x45, 0xdb, 0x8c, 0x0f, 0x9f, 0xfe, 0xa9, 0xf8, 0xcb, - 0x0c, 0x94, 0x2c, 0xcf, 0x9f, 0x45, 0x37, 0xc6, 0x92, 0x7c, 0xdc, 0x6a, 0xcd, 0x6f, 0xf0, 0xb2, 0x9a, 0x81, 0xec, - 0x9a, 0x4c, 0x39, 0x25, 0xdd, 0x01, 0x55, 0xe0, 0xb4, 0xf4, 0x7f, 0xb6, 0x3c, 0x70, 0xa2, 0x7a, 0xad, 0xa2, 0xf8, - 0xf3, 0x52, 0xb9, 0xe0, 0xf8, 0x2f, 0x10, 0xe0, 0x34, 0xde, 0xca, 0x4b, 0xe1, 0x2e, 0x6e, 0xe9, 0xf4, 0xea, 0xe8, - 0x5e, 0xd3, 0xf6, 0xe6, 0x75, 0x2e, 0x37, 0x40, 0xeb, 0x86, 0x56, 0x1f, 0x42, 0xb0, 0x74, 0xda, 0x26, 0xd3, 0xce, - 0xb2, 0x1c, 0x5e, 0x4a, 0x31, 0x73, 0x23, 0xb2, 0x2c, 0x62, 0x23, 0x36, 0xb6, 0x5e, 0x5e, 0x53, 0xaf, 0xa3, 0xad, - 0xc5, 0xf4, 0x68, 0xcb, 0x5c, 0x06, 0x24, 0x15, 0x89, 0xf5, 0x5a, 0xc5, 0x67, 0x70, 0x02, 0x97, 0xe3, 0x44, 0x44, - 0x32, 0x54, 0x04, 0xdb, 0x75, 0xe3, 0xba, 0x11, 0xb0, 0x19, 0xb1, 0x74, 0xe0, 0xe9, 0xea, 0xa6, 0xe0, 0x6f, 0xad, - 0x5f, 0xba, 0x2b, 0x02, 0xd5, 0xdd, 0x1d, 0x4a, 0xbb, 0x6b, 0xbe, 0x35, 0xe1, 0xd2, 0x97, 0x35, 0x3f, 0x87, 0x91, - 0x31, 0x1d, 0xbc, 0xbd, 0x5e, 0x8b, 0x6a, 0x5d, 0xfb, 0x95, 0xf4, 0x91, 0x02, 0x13, 0xad, 0xb7, 0x52, 0x85, 0xd0, - 0xea, 0x25, 0xfd, 0xb6, 0xb4, 0x82, 0xa2, 0xf9, 0x5c, 0x35, 0xc4, 0xdd, 0xe3, 0x43, 0xad, 0xbc, 0x02, 0xf7, 0x50, - 0xb9, 0x00, 0x3a, 0xf4, 0x6e, 0x1a, 0x99, 0xa3, 0xa0, 0x7f, 0x99, 0xa0, 0x3c, 0x7c, 0x3c, 0xab, 0xf7, 0xff, 0x00, - 0x08, 0x50, 0x84, 0x3d, 0xcd, 0x86, 0x00, 0x00}; + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xdb, 0x72, 0xdb, 0xc6, 0xb6, 0xe0, 0xf3, + 0xe4, 0x2b, 0x20, 0x44, 0x5b, 0x41, 0x6f, 0x36, 0x21, 0x92, 0xba, 0x58, 0x06, 0xd5, 0xe4, 0x96, 0x65, 0x67, 0x3b, + 0x3b, 0xbe, 0xc5, 0xb2, 0x93, 0x9d, 0x30, 0xdc, 0x12, 0x44, 0x34, 0xc9, 0xb6, 0x41, 0x34, 0x03, 0x34, 0x29, 0x29, + 0x24, 0x4e, 0xcd, 0x07, 0x4c, 0xd5, 0x54, 0xcd, 0xd3, 0xbc, 0x4c, 0xcd, 0x79, 0x98, 0x8f, 0x98, 0xe7, 0xf3, 0x29, + 0xe7, 0x07, 0x66, 0x3e, 0x61, 0x6a, 0xf5, 0x05, 0x68, 0xf0, 0x22, 0xcb, 0x49, 0xce, 0x39, 0x53, 0xa9, 0x58, 0x44, + 0x5f, 0x57, 0xaf, 0x5e, 0xbd, 0xee, 0x0d, 0x9c, 0xee, 0x44, 0x7c, 0x20, 0xee, 0xa6, 0xd4, 0x19, 0x8b, 0x49, 0xdc, + 0x39, 0xd5, 0xff, 0xd2, 0x30, 0xea, 0x9c, 0xc6, 0x2c, 0xf9, 0xe8, 0xa4, 0x34, 0x26, 0x6c, 0xc0, 0x13, 0x67, 0x9c, + 0xd2, 0x21, 0x89, 0x42, 0x11, 0x06, 0x6c, 0x12, 0x8e, 0xa8, 0xb3, 0xdf, 0x39, 0x9d, 0x50, 0x11, 0x3a, 0x83, 0x71, + 0x98, 0x66, 0x54, 0x90, 0xf7, 0xef, 0xbe, 0xae, 0x9f, 0x74, 0x4e, 0xb3, 0x41, 0xca, 0xa6, 0xc2, 0x81, 0x21, 0xc9, + 0x84, 0x47, 0xb3, 0x98, 0x76, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0xfc, 0x0f, 0xd9, 0x17, 0x03, 0x9e, 0x64, 0xc2, 0x79, + 0x41, 0x6e, 0x58, 0x12, 0xf1, 0x1b, 0x4c, 0x05, 0x79, 0xe1, 0x5f, 0x8c, 0xc3, 0x88, 0xdf, 0xbc, 0xe5, 0x5c, 0xec, + 0xed, 0x79, 0xea, 0xf1, 0xee, 0xfc, 0xe2, 0x82, 0x10, 0x32, 0xe7, 0x2c, 0x72, 0x1a, 0xcb, 0x65, 0x59, 0xe8, 0x27, + 0xa1, 0x60, 0x73, 0xaa, 0xba, 0xa0, 0xbd, 0x3d, 0x37, 0x8c, 0xf8, 0x54, 0xd0, 0xe8, 0x42, 0xdc, 0xc5, 0xf4, 0x62, + 0x4c, 0xa9, 0xc8, 0x5c, 0x96, 0x38, 0x4f, 0xf9, 0x60, 0x36, 0xa1, 0x89, 0xf0, 0xa7, 0x29, 0x17, 0x1c, 0x20, 0xd9, + 0xdb, 0x73, 0x53, 0x3a, 0x8d, 0xc3, 0x01, 0x85, 0xfa, 0xf3, 0x8b, 0x8b, 0xb2, 0x47, 0xd9, 0x08, 0x33, 0x41, 0x2e, + 0xee, 0x26, 0xd7, 0x3c, 0xf6, 0x10, 0x8e, 0x05, 0x49, 0xe8, 0x8d, 0xf3, 0x03, 0x0d, 0x3f, 0xbe, 0x0c, 0xa7, 0xed, + 0x41, 0x1c, 0x66, 0x99, 0x73, 0x2d, 0x16, 0x72, 0x09, 0xe9, 0x6c, 0x20, 0x78, 0xea, 0x09, 0x4c, 0x31, 0x43, 0x0b, + 0x36, 0xf4, 0xc4, 0x98, 0x65, 0xfe, 0xe5, 0xee, 0x20, 0xcb, 0xde, 0xd2, 0x6c, 0x16, 0x8b, 0x5d, 0xb2, 0xd3, 0xc0, + 0x6c, 0x87, 0x10, 0x26, 0x90, 0x18, 0xa7, 0xfc, 0xc6, 0x79, 0x96, 0xa6, 0x3c, 0xf5, 0xdc, 0xf3, 0x8b, 0x0b, 0xd5, + 0xc2, 0x61, 0x99, 0x93, 0x70, 0xe1, 0x14, 0xe3, 0x85, 0xd7, 0x31, 0xf5, 0x9d, 0xf7, 0x19, 0x75, 0xae, 0x66, 0x49, + 0x16, 0x0e, 0xe9, 0xf9, 0xc5, 0xc5, 0x95, 0xc3, 0x53, 0xe7, 0x6a, 0x90, 0x65, 0x57, 0x0e, 0x4b, 0x32, 0x41, 0xc3, + 0xc8, 0x77, 0x51, 0x5b, 0x4e, 0x36, 0xc8, 0xb2, 0x77, 0xf4, 0x56, 0x10, 0x81, 0xe5, 0xa3, 0x20, 0x34, 0x1f, 0x51, + 0xe1, 0x64, 0xc5, 0xba, 0x3c, 0xb4, 0x88, 0xa9, 0x70, 0x04, 0x91, 0xf5, 0xbc, 0xad, 0x70, 0x4f, 0xd5, 0xa3, 0x68, + 0xb3, 0xa1, 0x47, 0xc5, 0xde, 0x9e, 0x28, 0xf0, 0x8c, 0xd4, 0xd2, 0x1c, 0x46, 0xe8, 0x8e, 0x29, 0xdb, 0xdb, 0xa3, + 0x7e, 0x4c, 0x93, 0x91, 0x18, 0x13, 0x42, 0x9a, 0x6d, 0xb6, 0xb7, 0xe7, 0x09, 0x12, 0x0b, 0x7f, 0x44, 0x85, 0x47, + 0x11, 0xc2, 0x65, 0xef, 0xbd, 0x3d, 0x4f, 0x21, 0x81, 0x13, 0x85, 0xb8, 0x0a, 0x8e, 0x91, 0xaf, 0xb1, 0x7f, 0x71, + 0x97, 0x0c, 0x3c, 0x1b, 0x7e, 0x84, 0xd9, 0xde, 0x5e, 0x2c, 0xfc, 0x0c, 0x46, 0xc4, 0x02, 0xa1, 0x3c, 0xa5, 0x62, + 0x96, 0x26, 0x8e, 0xc8, 0x05, 0xbf, 0x10, 0x29, 0x4b, 0x46, 0x1e, 0x5a, 0x98, 0x32, 0xab, 0x63, 0x9e, 0x2b, 0x70, + 0xdf, 0x08, 0x92, 0x92, 0x0e, 0xcc, 0x78, 0x2d, 0x3c, 0xd8, 0x45, 0x3e, 0x74, 0x52, 0x42, 0xdc, 0x4c, 0xf6, 0x75, + 0xbb, 0x69, 0x90, 0xd6, 0x5c, 0x17, 0x2b, 0x28, 0x31, 0x13, 0x08, 0x7f, 0x24, 0x5e, 0x8a, 0x7d, 0xdf, 0x17, 0x88, + 0x74, 0x16, 0x06, 0x2b, 0xa9, 0xb5, 0xce, 0x6e, 0xda, 0x6b, 0xf4, 0x03, 0xe1, 0xa7, 0x34, 0x9a, 0x0d, 0xa8, 0xe7, + 0x31, 0x9c, 0xe1, 0x04, 0x91, 0x0e, 0xab, 0x79, 0x9c, 0x74, 0x60, 0xbb, 0x79, 0x75, 0xaf, 0x09, 0xd9, 0x69, 0x20, + 0x0d, 0x23, 0x37, 0x00, 0x02, 0x86, 0x35, 0x3c, 0x9c, 0x10, 0x37, 0x99, 0x4d, 0xae, 0x69, 0xea, 0x16, 0xcd, 0xda, + 0x15, 0xb2, 0x98, 0x65, 0xd4, 0x19, 0x64, 0x99, 0x33, 0x9c, 0x25, 0x03, 0xc1, 0x78, 0xe2, 0xb8, 0x35, 0x5e, 0x73, + 0x15, 0x39, 0x14, 0xd4, 0xe0, 0xa2, 0x1c, 0x79, 0x19, 0xaa, 0xa5, 0xbd, 0xa4, 0xd6, 0xec, 0x63, 0x80, 0x12, 0xb5, + 0xf5, 0x78, 0x1a, 0x01, 0x14, 0xa7, 0xb0, 0xc6, 0x1c, 0xbf, 0x17, 0xb0, 0x4a, 0xb9, 0x44, 0x2a, 0xba, 0xa9, 0xbf, + 0x7e, 0x50, 0x88, 0xf0, 0x27, 0xe1, 0xd4, 0xa3, 0xa4, 0x43, 0x25, 0x71, 0x85, 0xc9, 0x00, 0x60, 0xad, 0xec, 0x5b, + 0x97, 0x06, 0xd4, 0x2f, 0x49, 0x0a, 0x05, 0xc2, 0x1f, 0xf2, 0xf4, 0x59, 0x38, 0x18, 0x43, 0xbf, 0x82, 0x60, 0x22, + 0x73, 0xde, 0x06, 0x29, 0x0d, 0x05, 0x7d, 0x16, 0x53, 0x78, 0xf2, 0x5c, 0xd9, 0xd3, 0x45, 0x38, 0x23, 0x2f, 0xfc, + 0x98, 0x89, 0x57, 0x3c, 0x19, 0xd0, 0x76, 0x66, 0x51, 0x17, 0x83, 0x7d, 0x3f, 0x13, 0x22, 0x65, 0xd7, 0x33, 0x41, + 0x3d, 0x37, 0x81, 0x16, 0x2e, 0xce, 0x10, 0x66, 0xbe, 0xa0, 0xb7, 0xe2, 0x9c, 0x27, 0x82, 0x26, 0x82, 0x50, 0x83, + 0x54, 0x9c, 0xfa, 0xe1, 0x74, 0x4a, 0x93, 0xe8, 0x7c, 0xcc, 0xe2, 0xc8, 0x63, 0x28, 0x47, 0x39, 0x0e, 0x05, 0x81, + 0x35, 0x92, 0x4e, 0x1a, 0xc0, 0x3f, 0xdb, 0x57, 0xe3, 0x09, 0xd2, 0x91, 0x87, 0x82, 0x12, 0xd7, 0x6d, 0x0f, 0x79, + 0xea, 0xe9, 0x15, 0x38, 0x7c, 0xe8, 0x08, 0x98, 0xe3, 0xed, 0x2c, 0xa6, 0x19, 0xa2, 0x35, 0xc2, 0x8a, 0x6d, 0xd4, + 0x08, 0x7e, 0x03, 0x14, 0x9f, 0x23, 0x2f, 0x45, 0x41, 0xda, 0x9e, 0x87, 0xa9, 0xf3, 0xb5, 0x3e, 0x51, 0x4f, 0x0d, + 0x37, 0x1b, 0x0b, 0xf2, 0xd4, 0x17, 0xe9, 0x2c, 0x13, 0x34, 0x7a, 0x77, 0x37, 0xa5, 0x19, 0x7e, 0x27, 0xc8, 0x58, + 0x74, 0xc7, 0xc2, 0xa7, 0x93, 0xa9, 0xb8, 0xbb, 0x90, 0x8c, 0x31, 0x70, 0x5d, 0x3c, 0x80, 0x96, 0x29, 0x0d, 0x07, + 0xc0, 0xcc, 0x34, 0xb6, 0xde, 0xf0, 0xf8, 0x6e, 0xc8, 0xe2, 0xf8, 0x62, 0x36, 0x9d, 0xf2, 0x54, 0xe0, 0xbf, 0x92, + 0x85, 0xe0, 0x25, 0x6a, 0x60, 0x2f, 0x17, 0xd9, 0x0d, 0x13, 0x83, 0xb1, 0x27, 0xd0, 0x62, 0x10, 0x66, 0xd4, 0x79, + 0xc2, 0x79, 0x4c, 0xc3, 0x24, 0x48, 0x49, 0xda, 0x7d, 0x27, 0x82, 0x64, 0x16, 0xc7, 0xed, 0xeb, 0x94, 0x86, 0x1f, + 0xdb, 0xb2, 0xfa, 0xf5, 0xf5, 0x07, 0x3a, 0x10, 0x81, 0xfc, 0x7d, 0x96, 0xa6, 0xe1, 0x1d, 0x34, 0x24, 0x04, 0x9a, + 0x75, 0xd3, 0xe0, 0x6f, 0x17, 0xaf, 0x5f, 0xf9, 0xea, 0x90, 0xb0, 0xe1, 0x9d, 0x97, 0x16, 0x07, 0x2f, 0xcd, 0xf1, + 0x30, 0xe5, 0x93, 0x95, 0xa9, 0x15, 0xd6, 0xd2, 0xf6, 0x16, 0x10, 0x28, 0x49, 0x77, 0xd4, 0xd0, 0x36, 0x04, 0xaf, + 0x24, 0xcd, 0x43, 0x25, 0xd1, 0xf3, 0xc2, 0x3f, 0x81, 0x2a, 0xf6, 0x52, 0x74, 0x3f, 0xb4, 0x22, 0xbd, 0x5b, 0x50, + 0x22, 0xe1, 0x9c, 0x82, 0x84, 0x01, 0x18, 0x07, 0xa1, 0x18, 0x8c, 0x17, 0x54, 0x0e, 0x96, 0x1b, 0x88, 0x69, 0x9e, + 0xe3, 0x9b, 0x82, 0xde, 0xc5, 0x0e, 0x21, 0xa9, 0x64, 0x54, 0x44, 0x2c, 0x97, 0x29, 0x21, 0x29, 0xc2, 0x3f, 0x90, + 0x45, 0x68, 0xd6, 0x13, 0xec, 0x34, 0x30, 0x9c, 0xcb, 0x40, 0x71, 0x17, 0x3c, 0xe0, 0xc9, 0x9c, 0xa6, 0x82, 0xa6, + 0xc1, 0x5f, 0x71, 0x4a, 0x87, 0x31, 0x40, 0xb1, 0xd3, 0xc4, 0xe3, 0x30, 0x3b, 0x1f, 0x87, 0xc9, 0x88, 0x46, 0xc1, + 0x8d, 0xc8, 0xf1, 0xdf, 0x89, 0x3b, 0x64, 0x49, 0x18, 0xb3, 0x5f, 0x69, 0xe4, 0x6a, 0x69, 0x70, 0xeb, 0xd0, 0x5b, + 0x41, 0x93, 0x28, 0x73, 0x9e, 0xbf, 0x7b, 0xf9, 0x42, 0xef, 0x63, 0x45, 0x40, 0xa0, 0x45, 0x36, 0x9b, 0xd2, 0xd4, + 0x43, 0x58, 0x0b, 0x88, 0x67, 0x4c, 0x32, 0xc7, 0x97, 0xe1, 0x54, 0x95, 0xb0, 0xec, 0xfd, 0x34, 0x0a, 0x05, 0x7d, + 0x43, 0x93, 0x88, 0x25, 0x23, 0xb2, 0xd3, 0x54, 0xe5, 0xe3, 0x50, 0x57, 0x44, 0x45, 0xd1, 0xe5, 0xee, 0xb3, 0x58, + 0xae, 0xbb, 0x78, 0x9c, 0x79, 0x28, 0xcf, 0x44, 0x28, 0xd8, 0xc0, 0x09, 0xa3, 0xe8, 0x9b, 0x84, 0x09, 0x26, 0x01, + 0x4c, 0x61, 0x7b, 0x80, 0x44, 0xa9, 0x12, 0x15, 0x06, 0x70, 0x0f, 0x61, 0xcf, 0xd3, 0x02, 0x60, 0x8c, 0xf4, 0x7e, + 0xed, 0xed, 0x95, 0xec, 0xbe, 0x4b, 0x03, 0x55, 0x49, 0x7a, 0x7d, 0xe4, 0x4f, 0x67, 0x19, 0x6c, 0xb4, 0x99, 0x02, + 0xa4, 0x0b, 0xbf, 0xce, 0x68, 0x3a, 0xa7, 0x51, 0x41, 0x1c, 0x99, 0x87, 0x16, 0x2b, 0x73, 0xe8, 0x63, 0x21, 0x48, + 0xaf, 0xdf, 0xb6, 0xf9, 0x36, 0xd5, 0x74, 0x9e, 0xf2, 0x29, 0x4d, 0x05, 0xa3, 0x59, 0xc1, 0x4a, 0x3c, 0x90, 0xa2, + 0x05, 0x3b, 0xc9, 0x88, 0x59, 0xdf, 0xd4, 0x63, 0x98, 0xa2, 0x0a, 0xc3, 0x30, 0x82, 0xf6, 0xd9, 0x5c, 0x4a, 0x8c, + 0x0c, 0x33, 0x84, 0x85, 0x82, 0x34, 0x43, 0x28, 0x47, 0x58, 0x18, 0x70, 0x15, 0x2b, 0xd2, 0xb3, 0xdd, 0x81, 0xa8, + 0x26, 0x3f, 0x48, 0x51, 0x0d, 0x0c, 0x2d, 0x14, 0x74, 0x6f, 0xcf, 0xa3, 0x7e, 0x41, 0x14, 0x64, 0xa7, 0xa9, 0xf7, + 0xc8, 0x42, 0xd6, 0x16, 0xb0, 0x61, 0x62, 0x81, 0x29, 0xc2, 0x3b, 0xd4, 0x4f, 0xf8, 0xd9, 0x60, 0x40, 0xb3, 0x8c, + 0xa7, 0x7b, 0x7b, 0x3b, 0xb2, 0x7d, 0xa1, 0x4d, 0xc0, 0x1e, 0xbe, 0xbe, 0x49, 0x4a, 0x08, 0x50, 0x29, 0x61, 0xb5, + 0x5c, 0x10, 0x20, 0xa7, 0xa4, 0xc2, 0xe1, 0x76, 0x8d, 0xe2, 0x11, 0xb8, 0x97, 0x97, 0x6e, 0x4d, 0x60, 0x8d, 0x86, + 0x11, 0x35, 0x53, 0xdf, 0x3d, 0xa5, 0x4a, 0xb5, 0x92, 0x8a, 0xc7, 0x1a, 0x66, 0xd4, 0xf9, 0xf1, 0x23, 0x3a, 0x64, + 0x89, 0xb5, 0xec, 0x0a, 0x48, 0x58, 0xe0, 0x0c, 0xe5, 0xd6, 0x86, 0x6e, 0x1c, 0x5a, 0xea, 0x34, 0x6a, 0xe7, 0x16, + 0x23, 0xa9, 0x47, 0x58, 0xdb, 0xd8, 0xa3, 0xfd, 0x1c, 0x4b, 0xd4, 0x9b, 0xd5, 0x24, 0x12, 0xd0, 0x9e, 0xe8, 0xb7, + 0x75, 0x3d, 0xc9, 0x14, 0xe6, 0x52, 0xfa, 0xcb, 0x8c, 0x66, 0x42, 0xd1, 0xb1, 0x27, 0x70, 0x82, 0x19, 0xca, 0xe1, + 0xb8, 0x0d, 0xd9, 0x68, 0x96, 0x82, 0xba, 0x03, 0x47, 0x91, 0x26, 0xb3, 0x09, 0x35, 0x4f, 0x9b, 0x60, 0x7b, 0x3d, + 0x05, 0x81, 0x98, 0x01, 0x4d, 0xdf, 0x4f, 0x4e, 0x00, 0xab, 0x40, 0xcb, 0xe5, 0x0f, 0x66, 0x90, 0x72, 0x2b, 0x0b, + 0x15, 0x6d, 0x65, 0x4f, 0xfe, 0x8e, 0xb4, 0x3c, 0xde, 0x69, 0x2a, 0xe8, 0xff, 0xde, 0x27, 0x3b, 0x8d, 0x82, 0x82, + 0x35, 0x4e, 0x15, 0x30, 0x0a, 0x85, 0xaf, 0xd5, 0x40, 0x48, 0x4a, 0xf7, 0x0a, 0xb1, 0xf8, 0xe3, 0x35, 0x3a, 0x1d, + 0x93, 0x1e, 0xe8, 0x19, 0xfe, 0xb8, 0xbf, 0x8d, 0x98, 0x0c, 0x37, 0xf0, 0xc4, 0x7a, 0x5d, 0xc9, 0x34, 0xe6, 0x55, + 0xa6, 0xb1, 0xb2, 0x08, 0x77, 0x5a, 0x74, 0x71, 0x0b, 0x1a, 0xd3, 0xc7, 0xbc, 0xac, 0xc2, 0x4c, 0x02, 0x53, 0x2e, + 0xc9, 0x1a, 0xe2, 0x55, 0x38, 0xa1, 0x99, 0x47, 0x11, 0xde, 0xd6, 0x40, 0x11, 0x27, 0x34, 0xe9, 0x5b, 0x62, 0x33, + 0x03, 0xb1, 0xc9, 0x90, 0xd2, 0xca, 0xaa, 0xc7, 0x2d, 0xc3, 0xb4, 0x97, 0xf5, 0x4b, 0x65, 0xce, 0x5a, 0xbc, 0x94, + 0xc7, 0x9a, 0xba, 0x0d, 0xfe, 0x54, 0x99, 0x42, 0x9a, 0x54, 0x1a, 0x32, 0x84, 0x77, 0x1a, 0xab, 0xfb, 0x68, 0x5a, + 0x95, 0x6b, 0xec, 0xf5, 0x61, 0x1f, 0xa4, 0xb8, 0xf0, 0x59, 0x26, 0xff, 0x56, 0xce, 0x19, 0xa0, 0xed, 0x02, 0xc8, + 0xc2, 0x1f, 0xc6, 0xa1, 0xf0, 0x9a, 0xfb, 0x0d, 0xd0, 0x44, 0xe7, 0x14, 0xa4, 0x09, 0x42, 0xeb, 0x4b, 0xa1, 0xfe, + 0x2c, 0xc9, 0xc6, 0x6c, 0x28, 0xbc, 0x50, 0x48, 0x86, 0x42, 0xe3, 0x8c, 0x3a, 0xa2, 0xa2, 0x0f, 0x4b, 0x66, 0x13, + 0x02, 0xa9, 0x15, 0xca, 0x17, 0x35, 0x90, 0x4a, 0xa6, 0x05, 0xbc, 0xa1, 0xd4, 0xa5, 0x4b, 0x1e, 0x63, 0x5a, 0x33, + 0xd0, 0x17, 0x9b, 0x5d, 0x35, 0x62, 0xa0, 0x59, 0x01, 0xb3, 0x54, 0x56, 0x16, 0xd8, 0xfc, 0x41, 0x17, 0x0a, 0x5f, + 0xf0, 0x17, 0xfc, 0x86, 0xa6, 0xe7, 0x21, 0x00, 0x1f, 0xa8, 0xee, 0xb9, 0x12, 0x03, 0x92, 0xdb, 0x8b, 0xb6, 0xa1, + 0x97, 0x4b, 0xb9, 0xf0, 0x37, 0x29, 0x9f, 0xb0, 0x8c, 0x82, 0xa6, 0xa6, 0xf0, 0x9f, 0xc0, 0x29, 0x93, 0xc7, 0x11, + 0x44, 0x0d, 0x2d, 0xe8, 0xeb, 0xec, 0x45, 0x95, 0xbe, 0x2e, 0x77, 0x9f, 0x8d, 0x0c, 0xfb, 0xab, 0x1e, 0x62, 0x84, + 0x3d, 0x6d, 0x4f, 0x58, 0x52, 0xce, 0x1f, 0x23, 0x2d, 0xde, 0x97, 0x4b, 0x61, 0x99, 0x6d, 0x15, 0x5d, 0x91, 0xaa, + 0x63, 0x83, 0xf2, 0x30, 0x8a, 0x40, 0xab, 0x4b, 0x79, 0x1c, 0x5b, 0x82, 0x0a, 0xb3, 0x76, 0x21, 0x9a, 0x2e, 0x77, + 0x9f, 0x5d, 0xdc, 0x27, 0x9d, 0xa0, 0xde, 0x16, 0x50, 0x06, 0xd0, 0x24, 0xa2, 0x29, 0x98, 0x91, 0xd6, 0x6e, 0x69, + 0x19, 0x7b, 0xce, 0x93, 0x84, 0x0e, 0x04, 0x8d, 0xc0, 0x4a, 0x61, 0x44, 0xf8, 0x63, 0x9e, 0x89, 0xa2, 0xb0, 0x84, + 0x9e, 0x59, 0xd0, 0x33, 0x7f, 0x10, 0xc6, 0xb1, 0xa7, 0x2c, 0x92, 0x09, 0x9f, 0xd3, 0x0d, 0x50, 0xb7, 0x2b, 0x20, + 0x17, 0xc3, 0x50, 0x6b, 0x18, 0xea, 0x67, 0xd3, 0x98, 0x0d, 0x68, 0x21, 0xb8, 0x2e, 0x7c, 0x96, 0x44, 0xf4, 0x16, + 0xf8, 0x08, 0xea, 0x74, 0x3a, 0x0d, 0xdc, 0x44, 0xb9, 0x42, 0xf8, 0x62, 0x0d, 0xb1, 0xf7, 0x88, 0x4c, 0x20, 0x32, + 0xd2, 0x59, 0x6c, 0xe2, 0x07, 0x14, 0x59, 0x72, 0x92, 0x19, 0xcb, 0x4a, 0xf1, 0x66, 0x84, 0x23, 0x1a, 0x53, 0x41, + 0x0d, 0x2f, 0x07, 0xfd, 0x59, 0x1d, 0xdd, 0xb7, 0x05, 0xfe, 0x0a, 0x72, 0x32, 0xa7, 0xcc, 0xec, 0x79, 0x56, 0x58, + 0xea, 0xe5, 0xf6, 0x94, 0xd8, 0xee, 0x0a, 0xb5, 0x3d, 0xa1, 0x10, 0xe1, 0x60, 0xac, 0x4c, 0x74, 0x6f, 0x6d, 0x49, + 0xe5, 0x18, 0x9a, 0xaf, 0x17, 0x87, 0xe8, 0xbd, 0x01, 0x73, 0x13, 0x0a, 0x2e, 0x34, 0x53, 0xa0, 0x60, 0xf5, 0xa9, + 0x6d, 0x3b, 0x0f, 0xe3, 0xf8, 0x3a, 0x1c, 0x7c, 0xac, 0x52, 0x7f, 0x49, 0x06, 0x64, 0x95, 0x1b, 0x5b, 0x55, 0x16, + 0xcb, 0xb2, 0xd7, 0x6d, 0xb8, 0x74, 0xe5, 0xa0, 0x78, 0x3b, 0x8d, 0x92, 0xec, 0xab, 0x1b, 0xbd, 0x95, 0xda, 0x25, + 0x44, 0x4c, 0xaf, 0xcc, 0x03, 0x2e, 0xf0, 0x49, 0x8a, 0x33, 0xfc, 0x40, 0xd3, 0x1d, 0xd8, 0x1a, 0xf9, 0x0a, 0x20, + 0x02, 0x2d, 0xf2, 0x88, 0x65, 0xdb, 0x31, 0xf0, 0x87, 0x40, 0xf9, 0xd4, 0x9a, 0xe1, 0xa1, 0x80, 0x16, 0x3c, 0x4e, + 0xab, 0xcc, 0x05, 0x64, 0x5a, 0x9b, 0x30, 0x8c, 0xe6, 0x5b, 0xd0, 0x5c, 0x24, 0xbd, 0xbf, 0x56, 0x55, 0xa0, 0x93, + 0x01, 0x14, 0x59, 0xdb, 0x56, 0x26, 0x2a, 0x14, 0xa0, 0x79, 0x2a, 0x93, 0x22, 0x37, 0xa9, 0x18, 0x8f, 0x5a, 0x5d, + 0x57, 0xf6, 0xb7, 0x66, 0xb9, 0x9c, 0x78, 0x9e, 0x97, 0x81, 0xfd, 0x66, 0xf4, 0xfa, 0x72, 0x11, 0xd9, 0xda, 0x22, + 0x32, 0xdf, 0x32, 0xb2, 0x50, 0x49, 0xcb, 0x56, 0xf7, 0xe0, 0xaf, 0xc8, 0x6e, 0x04, 0xca, 0xaa, 0x0f, 0xfc, 0x19, + 0x15, 0xec, 0x36, 0x26, 0x02, 0x73, 0x6d, 0xe0, 0x68, 0x4a, 0x03, 0x86, 0x51, 0x76, 0x49, 0x90, 0x3a, 0x1a, 0x15, + 0x63, 0x37, 0xc1, 0x1c, 0xad, 0x68, 0xf6, 0x79, 0xae, 0x71, 0x44, 0x91, 0xde, 0x9b, 0x8a, 0x4a, 0x6c, 0x61, 0x05, + 0x27, 0x44, 0xab, 0xc1, 0x4a, 0xeb, 0x59, 0xc5, 0x4d, 0x31, 0x2e, 0x1c, 0xd4, 0x12, 0x35, 0x15, 0x7d, 0xd2, 0x28, + 0x56, 0x09, 0xc2, 0x63, 0xa3, 0x91, 0xf2, 0x72, 0xdd, 0x84, 0xb8, 0xc6, 0x1b, 0xe1, 0x76, 0x17, 0x15, 0x93, 0x30, + 0xb0, 0x9a, 0xe5, 0x01, 0xb0, 0x54, 0xbe, 0x09, 0xdd, 0x9b, 0x68, 0xa6, 0x32, 0x8e, 0x85, 0x70, 0x6e, 0x23, 0xdc, + 0xc2, 0x6c, 0xa2, 0x38, 0x57, 0xd2, 0x27, 0xe3, 0x6a, 0x5f, 0x8f, 0x62, 0xae, 0xf6, 0x61, 0x0d, 0x89, 0xab, 0x8a, + 0xa7, 0x24, 0x41, 0x30, 0x60, 0x33, 0x50, 0xee, 0x6c, 0xf9, 0xe0, 0x01, 0xec, 0x6c, 0xb9, 0x5c, 0x23, 0xba, 0x8d, + 0xfa, 0x27, 0xf2, 0x4b, 0xa3, 0x70, 0xb9, 0xbc, 0x11, 0xc8, 0xd3, 0x9a, 0x2f, 0xa6, 0xa8, 0x6b, 0x38, 0xee, 0xd9, + 0x0b, 0x68, 0x25, 0x15, 0xd1, 0xb2, 0xa4, 0x30, 0x19, 0xaa, 0x34, 0x5b, 0xdd, 0x27, 0x61, 0xb1, 0xed, 0xf3, 0x35, + 0xee, 0x25, 0x0b, 0xb5, 0x98, 0x2e, 0x97, 0x7c, 0xae, 0x87, 0x66, 0x08, 0xa1, 0x20, 0x93, 0x56, 0xcc, 0xce, 0x26, + 0xc3, 0x72, 0x6f, 0x2f, 0xb3, 0x06, 0xba, 0x2c, 0xd8, 0xc4, 0x07, 0x0f, 0x44, 0x72, 0x76, 0x97, 0x48, 0xdd, 0xe5, + 0x83, 0x11, 0x42, 0x6b, 0x66, 0x69, 0xa3, 0x0d, 0xd6, 0x78, 0x78, 0x13, 0x32, 0xe1, 0x14, 0xa3, 0x28, 0x6b, 0xdc, + 0xa3, 0x68, 0xa1, 0x55, 0x0d, 0x3f, 0xa5, 0xa0, 0x3c, 0x02, 0x4f, 0x30, 0x2a, 0xb4, 0xa2, 0xfb, 0xc1, 0x98, 0x82, + 0x23, 0xd8, 0x68, 0x11, 0x85, 0x5d, 0xb8, 0xa3, 0xa5, 0x88, 0x1e, 0x78, 0x33, 0xec, 0xf9, 0x6a, 0xf7, 0x8a, 0x1d, + 0x30, 0xa5, 0xe9, 0x90, 0xa7, 0x13, 0x53, 0x97, 0xaf, 0x3c, 0x6b, 0xce, 0xc8, 0x86, 0xde, 0xc6, 0xb1, 0xb5, 0xfa, + 0xdf, 0x5e, 0x31, 0xba, 0x4b, 0x73, 0xbd, 0x22, 0x4a, 0x0b, 0xe9, 0xab, 0xfc, 0x81, 0x86, 0x32, 0x33, 0xdb, 0xbc, + 0xd7, 0xce, 0xd4, 0xb6, 0x72, 0x98, 0xec, 0x34, 0xdb, 0x85, 0xcd, 0x67, 0xa8, 0xa1, 0xad, 0x1c, 0x1b, 0x5a, 0xa4, + 0xf2, 0x59, 0x1c, 0x69, 0x60, 0x19, 0xc2, 0x54, 0xd3, 0xd1, 0x0d, 0x8b, 0xe3, 0xb2, 0xf4, 0x73, 0xf8, 0x7a, 0xa6, + 0xf9, 0x7a, 0x62, 0xf8, 0x3a, 0x70, 0x0a, 0xe0, 0xeb, 0x6a, 0xb8, 0xb2, 0x7b, 0xb2, 0x76, 0x3a, 0x13, 0xc5, 0xd1, + 0x33, 0x69, 0x47, 0xc3, 0x7c, 0x33, 0x03, 0x01, 0x2a, 0x34, 0xaf, 0x8f, 0x9e, 0x76, 0xc2, 0x80, 0x01, 0xa8, 0x5c, + 0x98, 0xd4, 0x76, 0x51, 0x7c, 0xf4, 0x10, 0xce, 0x72, 0x5a, 0x50, 0xf6, 0xd9, 0x33, 0x70, 0xd2, 0x59, 0xcb, 0x01, + 0x21, 0x26, 0x8b, 0x3f, 0x4b, 0x89, 0x32, 0xab, 0x63, 0x7a, 0x75, 0x99, 0x59, 0x1d, 0x70, 0xfa, 0x72, 0x75, 0xd1, + 0xfd, 0xbc, 0x5e, 0x2e, 0x8f, 0x15, 0xcb, 0x2b, 0xf7, 0x7b, 0xb9, 0xf4, 0x56, 0x4a, 0xc0, 0x7f, 0xaf, 0x4d, 0x94, + 0xb4, 0x18, 0x1d, 0x78, 0x80, 0x8d, 0x19, 0x28, 0xc8, 0xd5, 0xa2, 0x0b, 0x11, 0xf7, 0xe2, 0x53, 0x0e, 0x1e, 0xe9, + 0xa6, 0x57, 0xfd, 0xcf, 0xf9, 0x64, 0x0a, 0xda, 0xd8, 0x0a, 0x49, 0x8f, 0xa8, 0x9e, 0xb0, 0xac, 0xcf, 0x37, 0x94, + 0x55, 0xfa, 0xc8, 0xf3, 0x58, 0xa1, 0xa6, 0xc2, 0x5e, 0xde, 0x69, 0xe4, 0xb3, 0xa2, 0xa8, 0x60, 0x1c, 0x9b, 0x9c, + 0x2a, 0xe7, 0xab, 0x2e, 0x19, 0x53, 0xf1, 0xda, 0x63, 0x8a, 0x0f, 0x33, 0xe0, 0x75, 0x16, 0xfb, 0x31, 0xe4, 0x6e, + 0xef, 0x7f, 0x5e, 0x22, 0x67, 0x91, 0xaf, 0xa0, 0x6f, 0x91, 0xe7, 0xb7, 0xca, 0xc8, 0xc6, 0xb7, 0xdb, 0xad, 0xe1, + 0xb2, 0x4e, 0x1b, 0x8b, 0xbd, 0x3e, 0xbe, 0x5d, 0x57, 0x1d, 0xc9, 0x62, 0xc2, 0x23, 0x1a, 0xb8, 0x7c, 0x4a, 0x13, + 0x37, 0x07, 0xaf, 0xaa, 0xde, 0xfb, 0x81, 0xf0, 0x16, 0x6f, 0xab, 0xee, 0xd5, 0xe0, 0x36, 0x07, 0xef, 0xd7, 0xd7, + 0xeb, 0x8e, 0xd7, 0xef, 0x69, 0x9a, 0x49, 0x45, 0xb4, 0xd0, 0x69, 0xbf, 0x2e, 0xc5, 0xd2, 0xd7, 0xc1, 0xd6, 0xf6, + 0xa5, 0x09, 0xe2, 0x36, 0xfd, 0x63, 0xff, 0xc0, 0x45, 0xd2, 0x2d, 0xfc, 0x93, 0x3e, 0xf0, 0x1f, 0x8c, 0x5b, 0xf8, + 0x19, 0xf9, 0x50, 0xf5, 0x0a, 0x47, 0x82, 0x3c, 0xeb, 0x3e, 0x33, 0x16, 0x33, 0x8f, 0xd9, 0xe0, 0xce, 0x73, 0x63, + 0x26, 0xea, 0x10, 0x7a, 0x73, 0xf1, 0x42, 0x55, 0x80, 0x4b, 0x51, 0xba, 0xb3, 0x73, 0x63, 0xeb, 0x61, 0x21, 0x88, + 0xbb, 0x1b, 0x33, 0xb1, 0xeb, 0xe2, 0x09, 0xb9, 0x82, 0x1f, 0xbb, 0x0b, 0xef, 0x65, 0x28, 0xc6, 0x7e, 0x1a, 0x26, + 0x11, 0x9f, 0x78, 0xa8, 0xe6, 0xba, 0xc8, 0xcf, 0xa4, 0xbd, 0xf1, 0x18, 0xe5, 0xbb, 0x57, 0xf8, 0x4c, 0x10, 0xb7, + 0xeb, 0xd6, 0x26, 0xf8, 0x95, 0x20, 0x57, 0xa7, 0xbb, 0x8b, 0x33, 0x91, 0x77, 0xae, 0xf0, 0x59, 0xe1, 0xb1, 0xc7, + 0x6f, 0x88, 0x87, 0x48, 0xe7, 0x4c, 0x43, 0x73, 0xce, 0x27, 0xca, 0x73, 0xef, 0x22, 0xfc, 0x1e, 0xe2, 0x2a, 0x69, + 0xc9, 0x6d, 0x74, 0x68, 0x65, 0x87, 0xb8, 0x5c, 0xba, 0x08, 0xdc, 0xbd, 0x3d, 0xab, 0xac, 0x50, 0x15, 0xf0, 0xad, + 0x20, 0x15, 0x83, 0x1c, 0xbf, 0x95, 0x11, 0x9a, 0x5b, 0xe1, 0xa5, 0xc8, 0x0c, 0xe3, 0x19, 0x3f, 0xb4, 0x3e, 0x9a, + 0x69, 0x4f, 0x79, 0x18, 0x7c, 0x26, 0x68, 0x1a, 0x0a, 0x9e, 0xf6, 0x91, 0xad, 0x7e, 0xe0, 0xbf, 0x91, 0xab, 0x9e, + 0xf3, 0x9f, 0xbe, 0xf8, 0x79, 0xf8, 0x73, 0xda, 0xbf, 0xc2, 0xaf, 0xc9, 0xfe, 0xa9, 0xd7, 0x0d, 0xbc, 0x9d, 0x7a, + 0x7d, 0xf9, 0xf3, 0x7e, 0xef, 0x1f, 0x61, 0xfd, 0xd7, 0xb3, 0xfa, 0x4f, 0x7d, 0xb4, 0xf4, 0x7e, 0xde, 0xef, 0xf6, + 0xf4, 0x53, 0xef, 0x1f, 0x9d, 0x9f, 0xb3, 0xfe, 0x9f, 0x55, 0xe1, 0x2e, 0x42, 0xfb, 0x23, 0x3c, 0x13, 0x64, 0xbf, + 0x5e, 0xef, 0xec, 0x8f, 0xf0, 0x54, 0x90, 0x7d, 0xf8, 0x7b, 0x4d, 0xde, 0xd2, 0xd1, 0xb3, 0xdb, 0xa9, 0x77, 0xd5, + 0x59, 0xee, 0x2e, 0xfe, 0x96, 0xc3, 0xa8, 0xbd, 0x7f, 0xfc, 0xfc, 0x73, 0xe6, 0x7e, 0xd5, 0x21, 0xfb, 0xfd, 0x1a, + 0xf2, 0xa0, 0xf4, 0xcf, 0x44, 0xfe, 0xeb, 0x75, 0x83, 0xde, 0x3f, 0x34, 0x14, 0xee, 0x57, 0x3f, 0x5f, 0x9d, 0x76, + 0x48, 0x7f, 0xe9, 0xb9, 0xcb, 0xaf, 0xd0, 0x12, 0xa1, 0xe5, 0x2e, 0xba, 0xc2, 0xee, 0xc8, 0x45, 0x78, 0x24, 0xc8, + 0xfe, 0x57, 0xfb, 0x23, 0x3c, 0x17, 0x64, 0xdf, 0xdd, 0x1f, 0xe1, 0x67, 0x82, 0xec, 0xff, 0xc3, 0xeb, 0x06, 0xca, + 0xc3, 0xb6, 0x94, 0xee, 0x8d, 0x25, 0x04, 0x37, 0xc2, 0x94, 0x86, 0x4b, 0xc1, 0x44, 0x4c, 0xd1, 0xee, 0x3e, 0xc3, + 0x17, 0x12, 0x4d, 0x9e, 0x00, 0x27, 0x0c, 0xd8, 0x76, 0xde, 0xe2, 0x12, 0x36, 0x1b, 0x68, 0x66, 0x37, 0x48, 0xb1, + 0xf2, 0x03, 0x64, 0x81, 0xc0, 0xf3, 0x30, 0x9e, 0xd1, 0x2c, 0xa0, 0x39, 0xc2, 0x03, 0x72, 0x21, 0xbc, 0x26, 0xc2, + 0xcf, 0x05, 0xfc, 0x68, 0x21, 0x7c, 0xa1, 0x03, 0x98, 0x70, 0x90, 0x15, 0x51, 0x25, 0x5c, 0x69, 0x2c, 0x2e, 0xc2, + 0xd3, 0x0d, 0x95, 0x62, 0x0c, 0xde, 0x05, 0x84, 0x87, 0x95, 0x70, 0x27, 0xbe, 0x21, 0x86, 0x24, 0xde, 0xa5, 0x94, + 0xfe, 0x10, 0xc6, 0x1f, 0x69, 0xea, 0x9d, 0xe1, 0x66, 0xeb, 0x31, 0x96, 0x2e, 0xe8, 0x9d, 0x26, 0x6a, 0x17, 0xb1, + 0xaa, 0x73, 0xa1, 0x62, 0x04, 0x20, 0x64, 0xab, 0xbe, 0x18, 0xd8, 0xf1, 0x9d, 0x74, 0xcd, 0x61, 0x95, 0x86, 0x37, + 0x2e, 0xaa, 0xc6, 0x45, 0x59, 0x32, 0x0f, 0x63, 0x16, 0x39, 0x82, 0x4e, 0xa6, 0x71, 0x28, 0xa8, 0xa3, 0xd7, 0xeb, + 0x84, 0x30, 0x90, 0x5b, 0xa8, 0x0c, 0x91, 0x65, 0x70, 0x46, 0x26, 0xe0, 0x04, 0x67, 0xc5, 0x83, 0xe8, 0x94, 0x56, + 0x3b, 0x5e, 0x96, 0xc1, 0xaf, 0xd5, 0xf8, 0x5e, 0xbd, 0x09, 0x8e, 0xb0, 0xbe, 0x14, 0xcf, 0x19, 0x4e, 0x08, 0x08, + 0xd1, 0x56, 0xd7, 0x3d, 0xcd, 0xe6, 0xa3, 0x8e, 0x0b, 0xb1, 0x19, 0x4e, 0x5e, 0x4b, 0xbf, 0x10, 0x34, 0x18, 0x93, + 0x46, 0x7b, 0x7c, 0x4a, 0xdb, 0xe3, 0x5a, 0xcd, 0xe8, 0xd0, 0x31, 0x49, 0x7b, 0x63, 0xd5, 0x3d, 0xc4, 0x11, 0x9e, + 0x91, 0x7a, 0x13, 0x8f, 0x48, 0x43, 0x76, 0x69, 0x8f, 0x4e, 0x63, 0x3d, 0xcd, 0xde, 0x9e, 0xc7, 0xfd, 0x38, 0xcc, + 0xc4, 0x37, 0x60, 0xec, 0x93, 0x11, 0x8e, 0x08, 0xf7, 0xe9, 0x2d, 0x1d, 0x78, 0x31, 0xc2, 0x91, 0xe6, 0x34, 0xa8, + 0x8d, 0x46, 0xc4, 0x6a, 0x06, 0x46, 0x04, 0x79, 0xdd, 0x8d, 0x7a, 0xcd, 0x3e, 0x21, 0xc4, 0xdd, 0xa9, 0xd7, 0xdd, + 0x2e, 0x27, 0x33, 0x11, 0x40, 0x89, 0xa5, 0x2a, 0x93, 0x29, 0x14, 0xb5, 0xac, 0x22, 0xef, 0x99, 0xf0, 0x05, 0xcd, + 0x84, 0x07, 0xc5, 0x60, 0xfe, 0x67, 0x86, 0xb0, 0xdd, 0xd3, 0x7d, 0xb7, 0x06, 0xa5, 0x92, 0x38, 0x11, 0xe6, 0xe4, + 0x1a, 0x05, 0x51, 0xef, 0xa0, 0x6f, 0xf3, 0x7f, 0x59, 0x08, 0x93, 0x5f, 0x77, 0xa3, 0x5e, 0x43, 0x4e, 0xde, 0x71, + 0xbb, 0x1e, 0x27, 0x99, 0x52, 0xd0, 0xba, 0x59, 0xf0, 0x5a, 0x2e, 0x15, 0x05, 0x1a, 0x38, 0x3d, 0xef, 0x8c, 0xd4, + 0x5b, 0x81, 0x37, 0xb3, 0x17, 0x51, 0x87, 0xc9, 0x34, 0x16, 0x70, 0x48, 0xa0, 0x3d, 0xe6, 0x04, 0x66, 0x2c, 0xbb, + 0x5d, 0x07, 0xfa, 0xf9, 0x2b, 0xf7, 0xab, 0xee, 0x5c, 0x04, 0x23, 0xa1, 0xa6, 0x9f, 0x8b, 0xe5, 0x12, 0xfe, 0x8e, + 0x44, 0x97, 0x93, 0x6b, 0x59, 0x34, 0xd3, 0x45, 0x53, 0x28, 0x7a, 0x1d, 0x00, 0xa8, 0x38, 0x2b, 0x94, 0x2c, 0xb5, + 0x27, 0x73, 0x22, 0x61, 0xdf, 0xdb, 0x4b, 0x7b, 0xe3, 0x5a, 0xb3, 0x0f, 0xfe, 0xfd, 0x54, 0x64, 0x3f, 0x30, 0x31, + 0xf6, 0xdc, 0xfd, 0x8e, 0x8b, 0xba, 0xae, 0x03, 0x5b, 0xdb, 0x4e, 0x6a, 0x44, 0x61, 0x38, 0xae, 0xbd, 0x12, 0xc1, + 0xac, 0x43, 0x1a, 0x5d, 0x8f, 0x69, 0x7f, 0x1e, 0xc2, 0xb1, 0x66, 0x9c, 0x0d, 0x3c, 0x43, 0x35, 0x21, 0x6a, 0xe6, + 0x79, 0x86, 0x6a, 0x93, 0xda, 0x1c, 0x05, 0x71, 0x6d, 0x52, 0xf3, 0x66, 0x84, 0x90, 0x7a, 0xab, 0xe8, 0x66, 0xa4, + 0xdf, 0x18, 0x05, 0x73, 0xe3, 0xec, 0xec, 0xc9, 0xe3, 0x90, 0xd4, 0xbc, 0xb4, 0x47, 0xfb, 0xcb, 0xa5, 0x7b, 0xda, + 0xed, 0xb8, 0xa8, 0xe6, 0x19, 0x42, 0xdb, 0x37, 0x94, 0x86, 0x10, 0x66, 0xfd, 0x5c, 0x87, 0x92, 0xde, 0x55, 0xc2, + 0x46, 0x8b, 0xf2, 0xb0, 0x5b, 0x3c, 0x80, 0xe6, 0x85, 0x1d, 0xa3, 0xf4, 0xd5, 0x29, 0x2c, 0xd3, 0x10, 0x73, 0x42, + 0x1a, 0x98, 0x13, 0xe3, 0xbb, 0x1e, 0x13, 0x51, 0x12, 0x7c, 0x4c, 0xca, 0xe6, 0xb8, 0x17, 0xe2, 0xa8, 0x4f, 0x5e, + 0x2a, 0x7b, 0xa4, 0x6d, 0xfc, 0xe2, 0x34, 0x26, 0xef, 0x56, 0xa2, 0xb7, 0x21, 0xc4, 0x56, 0x6e, 0xfc, 0xc1, 0x2c, + 0x4d, 0x69, 0x22, 0x5e, 0xf1, 0x48, 0xab, 0x69, 0x34, 0x06, 0x4b, 0x09, 0xc2, 0xb2, 0x18, 0x74, 0xb4, 0x96, 0x39, + 0x19, 0xb3, 0xb5, 0xea, 0x11, 0x99, 0x29, 0xf5, 0x49, 0x06, 0x6b, 0xdb, 0x23, 0x6d, 0x17, 0x7b, 0x08, 0xcf, 0x74, + 0x14, 0xd7, 0xf3, 0x7d, 0x7f, 0xe4, 0x0f, 0xa0, 0x1a, 0x26, 0xc8, 0x50, 0x2e, 0xcf, 0x91, 0x97, 0x91, 0x1b, 0x3f, + 0xa1, 0xb7, 0x72, 0x56, 0x0f, 0x95, 0x92, 0xd9, 0x1c, 0xaf, 0xd3, 0x71, 0x5b, 0xb2, 0x9b, 0xcc, 0x4f, 0x78, 0x44, + 0x01, 0x3d, 0x10, 0xb7, 0xd7, 0x45, 0xe3, 0x30, 0xb3, 0xe3, 0x53, 0x25, 0x7c, 0x3d, 0xdb, 0x79, 0x3d, 0x02, 0x8f, + 0xaf, 0xd4, 0xb5, 0x8a, 0xc6, 0xca, 0x0d, 0x8e, 0x10, 0x1b, 0x7a, 0x23, 0x1f, 0xe2, 0x7a, 0x92, 0x84, 0x04, 0x98, + 0x72, 0x23, 0x9b, 0xa8, 0x26, 0xc5, 0x98, 0x73, 0x12, 0xf5, 0x78, 0xad, 0x26, 0xbd, 0xd0, 0x33, 0x45, 0x12, 0x23, + 0x84, 0xe7, 0xc5, 0xd9, 0x32, 0xed, 0x5e, 0x0b, 0x52, 0x9d, 0xca, 0x9b, 0x57, 0xdd, 0xb9, 0x35, 0x21, 0x90, 0xf4, + 0x14, 0x0a, 0x6f, 0x82, 0xf0, 0x13, 0xb2, 0xef, 0xf5, 0xfc, 0xee, 0x5f, 0xfa, 0xa8, 0xeb, 0xf9, 0x7f, 0x46, 0xfb, + 0x8a, 0x73, 0xcc, 0x51, 0x3b, 0x56, 0x73, 0x2c, 0x64, 0xfc, 0xb2, 0x89, 0xa5, 0x27, 0x31, 0x48, 0x70, 0x12, 0x4e, + 0x68, 0xf0, 0x04, 0x0e, 0xb9, 0x21, 0x9c, 0xd7, 0x02, 0x03, 0x25, 0x05, 0x4f, 0x34, 0x2f, 0xf1, 0xdd, 0xee, 0x0b, + 0x51, 0x3c, 0x75, 0xdd, 0xee, 0x87, 0xf2, 0xe9, 0x2f, 0x6e, 0xf7, 0x1b, 0x11, 0xfc, 0x9a, 0x6b, 0x6f, 0x77, 0x65, + 0x8e, 0x63, 0x33, 0x47, 0xae, 0xb6, 0xc6, 0xc2, 0xdd, 0x0c, 0xad, 0x3b, 0x3a, 0x46, 0x28, 0x67, 0xc3, 0x82, 0x19, + 0x65, 0xbe, 0x08, 0x47, 0x80, 0x54, 0x6b, 0x0f, 0x32, 0x3b, 0xae, 0x5f, 0xae, 0x18, 0x48, 0xc5, 0xd0, 0x2b, 0x20, + 0x73, 0xd4, 0x69, 0xa0, 0x45, 0xa5, 0xad, 0xd4, 0x99, 0xaa, 0x71, 0xf4, 0x82, 0x4f, 0xcf, 0x49, 0xa3, 0x3d, 0x3f, + 0x1d, 0xb5, 0xe7, 0xb5, 0x1a, 0xca, 0x0c, 0x69, 0xcd, 0x7a, 0xf3, 0x3e, 0x7e, 0x03, 0x4e, 0x3d, 0x9b, 0x96, 0x70, + 0x65, 0x79, 0x2d, 0xbd, 0xbc, 0x5a, 0x2d, 0xc9, 0x51, 0xdb, 0xea, 0x3a, 0x52, 0x5d, 0xf3, 0x5c, 0xe1, 0x64, 0x95, + 0xd4, 0x4e, 0x90, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0x99, 0x40, 0x1b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, + 0xc0, 0x3e, 0x95, 0x94, 0xf0, 0x00, 0x0b, 0xd0, 0xb5, 0xf0, 0x04, 0x4f, 0xf0, 0xac, 0xd6, 0x94, 0x64, 0x5e, 0x6f, + 0xb6, 0xab, 0x63, 0x3d, 0x2a, 0xc7, 0xc2, 0xb3, 0x1a, 0x99, 0x14, 0x58, 0xca, 0x93, 0x5a, 0x2d, 0xaf, 0x06, 0x3b, + 0xcd, 0xc9, 0xad, 0x04, 0x20, 0xce, 0x56, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, + 0xa4, 0x28, 0x11, 0x98, 0xe5, 0x79, 0x29, 0xd9, 0x41, 0x8c, 0x62, 0x4a, 0x52, 0xe0, 0x3c, 0xd2, 0xee, 0xc2, 0x09, + 0xe6, 0x78, 0x2c, 0xf9, 0x06, 0x21, 0xe4, 0xc2, 0xa4, 0xb3, 0x08, 0xc9, 0x83, 0x62, 0xc2, 0x2c, 0x99, 0x94, 0x11, + 0xea, 0x5f, 0xee, 0x9e, 0xf3, 0x7b, 0x6d, 0xb2, 0x1e, 0xeb, 0x07, 0xb2, 0x59, 0xac, 0x39, 0x57, 0x48, 0xde, 0x7b, + 0x02, 0x15, 0xd1, 0x11, 0x5f, 0x32, 0xc0, 0xa7, 0x2c, 0xa5, 0x52, 0x07, 0xdf, 0x35, 0x76, 0x5f, 0x5c, 0x55, 0x20, + 0x63, 0xdb, 0x7b, 0x03, 0x88, 0x0c, 0xc1, 0xb9, 0x93, 0x90, 0xb5, 0x66, 0x97, 0xbb, 0x67, 0xaf, 0x37, 0xd9, 0xc0, + 0xcb, 0xa5, 0xb6, 0x7e, 0xa5, 0x6e, 0x83, 0xc3, 0x12, 0xd2, 0x58, 0xff, 0x08, 0xbc, 0x58, 0xaa, 0x48, 0xa1, 0x97, + 0x02, 0x15, 0x5d, 0xee, 0x9e, 0xbd, 0xf3, 0x52, 0xe9, 0x5b, 0x42, 0xd8, 0x5e, 0xb6, 0xc7, 0x89, 0x37, 0x26, 0x14, + 0xa9, 0xb5, 0x17, 0xac, 0x8b, 0x5b, 0x02, 0x3c, 0x18, 0xcb, 0x4a, 0xb0, 0x20, 0x7a, 0xac, 0x4f, 0x62, 0x8d, 0x01, + 0x12, 0x23, 0x1c, 0x57, 0xec, 0x32, 0x02, 0x1b, 0x20, 0xe7, 0xba, 0x80, 0x9d, 0xf0, 0x95, 0xea, 0x87, 0x70, 0x2c, + 0x67, 0x15, 0xb9, 0x12, 0x1e, 0x4f, 0xd6, 0xb2, 0xd2, 0x4a, 0x73, 0xf4, 0x7b, 0xb0, 0x9d, 0xcc, 0xc3, 0x2b, 0x62, + 0x2c, 0x09, 0x5d, 0xf0, 0xd4, 0xa4, 0x8f, 0x5d, 0xee, 0x9e, 0xbd, 0xd4, 0x19, 0x64, 0xd3, 0xd0, 0xf0, 0xfb, 0x35, + 0x13, 0xf3, 0xec, 0xa5, 0x5f, 0xd6, 0xca, 0xc6, 0x97, 0xbb, 0x67, 0xef, 0x37, 0x35, 0x83, 0xf2, 0x7c, 0x56, 0xda, + 0xf8, 0x12, 0xbe, 0x05, 0x8d, 0x83, 0x85, 0x16, 0x0e, 0x01, 0xcb, 0xb1, 0x14, 0x48, 0x41, 0x96, 0x17, 0xae, 0x91, + 0xa7, 0x38, 0x21, 0x32, 0x0c, 0x54, 0xdd, 0x35, 0xad, 0xe6, 0x31, 0x9e, 0x5c, 0x0c, 0xf8, 0x94, 0x6e, 0x89, 0x0d, + 0x9d, 0x21, 0x9f, 0x4d, 0x20, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x4e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, + 0x2b, 0xb2, 0x05, 0x8f, 0x49, 0x03, 0xc7, 0xa4, 0x81, 0x43, 0x92, 0xf5, 0x1a, 0x4a, 0x40, 0xb4, 0xc3, 0x62, 0x5c, + 0x25, 0x66, 0x20, 0x2b, 0x4c, 0x9f, 0x56, 0x25, 0x80, 0xa3, 0x76, 0x28, 0x7d, 0x8f, 0x52, 0xa6, 0x47, 0x92, 0x2c, + 0xde, 0x7a, 0x1c, 0x73, 0x39, 0xf0, 0x05, 0xbb, 0x8e, 0x21, 0xb1, 0x04, 0x56, 0x85, 0x05, 0x0a, 0x8a, 0xa6, 0x4d, + 0xdd, 0x34, 0xf4, 0xe5, 0x3e, 0x71, 0x1c, 0xfa, 0xc0, 0xb9, 0x71, 0xa8, 0xf3, 0x70, 0xb2, 0xf5, 0x2e, 0xc7, 0x7b, + 0x7b, 0x9e, 0xea, 0xf4, 0x8b, 0xf0, 0xb8, 0xa9, 0x2f, 0x23, 0x77, 0xdf, 0x2b, 0x5e, 0x11, 0x21, 0x09, 0x7f, 0xad, + 0x16, 0xf7, 0x73, 0x08, 0x43, 0x7b, 0x61, 0x15, 0x83, 0x06, 0x78, 0xa9, 0xeb, 0x55, 0x97, 0x5f, 0xab, 0x15, 0x51, + 0xda, 0x2a, 0xb6, 0xce, 0x70, 0x92, 0xcf, 0xbd, 0x22, 0xf5, 0xa7, 0xb1, 0x96, 0x2f, 0x65, 0x40, 0x40, 0xcc, 0xa6, + 0x59, 0x66, 0x16, 0x63, 0x1d, 0x09, 0x06, 0xed, 0xbe, 0xd1, 0x59, 0x0b, 0x58, 0x66, 0x57, 0xe9, 0x46, 0x86, 0x9d, + 0xb5, 0x50, 0x60, 0x1a, 0x41, 0x54, 0x0a, 0x1a, 0xd5, 0x72, 0x4d, 0xde, 0x6f, 0xd7, 0x73, 0x2e, 0x71, 0x86, 0xb4, + 0x93, 0x4b, 0x42, 0x21, 0x91, 0xd5, 0x2a, 0x90, 0xf2, 0x9c, 0x4c, 0xb7, 0x93, 0xfc, 0x99, 0x45, 0xf2, 0x4f, 0x08, + 0xb5, 0xc8, 0x5f, 0xb9, 0x38, 0x7c, 0xae, 0x9d, 0x0b, 0x99, 0xa9, 0x3a, 0x9f, 0x12, 0x70, 0xa2, 0x55, 0x31, 0x5a, + 0x09, 0x2b, 0x6e, 0x61, 0x28, 0xf6, 0x09, 0x91, 0x6e, 0x48, 0x6c, 0x62, 0xc0, 0x5e, 0x19, 0x54, 0x83, 0xa9, 0x37, + 0xf9, 0xf4, 0x6c, 0x0e, 0x78, 0xf6, 0xfe, 0xfe, 0x78, 0xe8, 0xf9, 0x74, 0xfd, 0xe4, 0x5a, 0xb9, 0x9f, 0xb0, 0x6a, + 0xeb, 0xe0, 0x56, 0x33, 0x41, 0x61, 0xfe, 0x22, 0x8e, 0x5d, 0x65, 0x3e, 0x2b, 0x87, 0xd0, 0xc8, 0x3f, 0x80, 0xb6, + 0xd9, 0x94, 0x2d, 0xa8, 0x35, 0x2c, 0xf0, 0x23, 0x95, 0x81, 0x1a, 0xa6, 0x5b, 0xd8, 0xc7, 0x99, 0x6c, 0x40, 0x93, + 0x68, 0x73, 0xf5, 0x93, 0x5c, 0x93, 0x89, 0x02, 0x0d, 0x2d, 0x80, 0xff, 0x29, 0x92, 0x07, 0xba, 0x91, 0x72, 0x01, + 0x10, 0x34, 0x95, 0x78, 0x2a, 0x11, 0xe6, 0xba, 0xa5, 0xf7, 0xfd, 0xf9, 0x0e, 0x21, 0xd3, 0xd2, 0xfb, 0xf8, 0xb6, + 0x4c, 0xbd, 0x02, 0xb2, 0x40, 0x01, 0x98, 0x8f, 0x45, 0x81, 0x0a, 0x5f, 0x5e, 0x98, 0xe6, 0xd2, 0x84, 0xf4, 0x4b, + 0x8d, 0xdb, 0x0a, 0x6d, 0x4a, 0xb7, 0x9c, 0xaa, 0x37, 0x68, 0x58, 0xa9, 0xdd, 0x85, 0xda, 0xb7, 0x42, 0xc2, 0x08, + 0xcf, 0xef, 0x64, 0x6b, 0x33, 0x6e, 0xfe, 0x71, 0x35, 0x7f, 0x65, 0x65, 0x53, 0x7c, 0x96, 0x64, 0x34, 0x15, 0x4f, + 0xe8, 0x90, 0xa7, 0x10, 0xb3, 0x28, 0x70, 0x82, 0xf2, 0x5d, 0xcb, 0x6f, 0x27, 0xd7, 0x67, 0x05, 0x0a, 0x56, 0x16, + 0x28, 0x7f, 0x7d, 0x94, 0x41, 0xeb, 0xcb, 0xd5, 0x5e, 0xd3, 0xbd, 0xbd, 0xf7, 0x25, 0x9a, 0x34, 0x94, 0x12, 0x0a, + 0x8b, 0x69, 0x29, 0x95, 0x46, 0x47, 0x72, 0x77, 0xbd, 0xc2, 0x09, 0x60, 0x18, 0x86, 0xcd, 0x7b, 0x9e, 0x13, 0x91, + 0x8f, 0x56, 0x59, 0xbc, 0x76, 0x4e, 0x30, 0xdb, 0x70, 0x01, 0x0e, 0x0f, 0xa6, 0xb6, 0xf2, 0x16, 0x65, 0x65, 0x32, + 0x6c, 0x01, 0xc3, 0x39, 0x20, 0xcb, 0x93, 0x66, 0x88, 0x45, 0x81, 0x1b, 0xcd, 0x92, 0x73, 0xd0, 0x2b, 0xc7, 0x38, + 0xf3, 0xc7, 0x90, 0xfe, 0x5a, 0x39, 0xb2, 0x08, 0x61, 0x95, 0x98, 0x63, 0xa5, 0x12, 0x9c, 0x3d, 0xdf, 0xe4, 0x52, + 0x36, 0x44, 0x4d, 0xa5, 0xd4, 0x91, 0x2d, 0x50, 0xd1, 0xc1, 0x9f, 0x7b, 0x4c, 0x2b, 0x6e, 0x26, 0x6e, 0x06, 0x0c, + 0xf8, 0x89, 0xf0, 0x54, 0x30, 0x0a, 0x64, 0x06, 0xf7, 0x67, 0x5e, 0x65, 0xea, 0x36, 0x97, 0xdd, 0xb0, 0x46, 0xdc, + 0xd8, 0x46, 0x13, 0x97, 0x71, 0xbd, 0xf3, 0x92, 0x97, 0x0e, 0x55, 0x06, 0xb5, 0x30, 0x5c, 0xb0, 0x4c, 0x24, 0xb1, + 0x96, 0x3f, 0x54, 0x49, 0xd1, 0x45, 0x23, 0x4c, 0x25, 0x18, 0xef, 0xe4, 0x1e, 0xd0, 0x1c, 0xfe, 0x2e, 0x6e, 0x85, + 0xb5, 0xa3, 0xc6, 0x89, 0x2d, 0xe7, 0xb4, 0xa4, 0xfe, 0x5b, 0x48, 0x75, 0x59, 0x3d, 0xf3, 0xcf, 0xa5, 0x2c, 0x64, + 0x38, 0xab, 0x30, 0xf6, 0x44, 0x32, 0x76, 0x04, 0x7a, 0x9a, 0x49, 0xfc, 0xee, 0xea, 0x8c, 0x17, 0xa6, 0xa5, 0x9c, + 0x26, 0xb1, 0x37, 0x45, 0xb4, 0xdc, 0xfa, 0xbd, 0xb2, 0x1b, 0x01, 0x23, 0x90, 0x05, 0x84, 0x35, 0x67, 0x4f, 0x10, + 0xce, 0x6a, 0xb5, 0x76, 0x76, 0x4a, 0x4b, 0x27, 0x49, 0x09, 0x23, 0x83, 0x80, 0x2e, 0x10, 0x7c, 0x45, 0x86, 0x42, + 0xc8, 0xdf, 0x64, 0x66, 0x67, 0xe0, 0x6b, 0x3f, 0x7b, 0xeb, 0xd9, 0x5c, 0xcd, 0x6e, 0x5b, 0x04, 0x4d, 0x61, 0x3d, + 0x5e, 0x19, 0x70, 0x79, 0x73, 0x7f, 0x82, 0x07, 0xc0, 0xbd, 0xd3, 0xc4, 0x90, 0x8a, 0x86, 0xda, 0x42, 0xb1, 0x84, + 0xe2, 0xf4, 0xb5, 0x51, 0x99, 0x95, 0x68, 0x4f, 0xd6, 0x16, 0xa5, 0x31, 0x2b, 0x48, 0x96, 0xe7, 0x19, 0x2d, 0xc3, + 0xfb, 0x2b, 0xe9, 0x97, 0x52, 0xb8, 0xac, 0x7b, 0xdb, 0xcf, 0xa7, 0x44, 0x60, 0x8b, 0x50, 0xdf, 0x6c, 0x8b, 0x7d, + 0x94, 0x60, 0xc2, 0xb9, 0xd6, 0x42, 0xf1, 0xd7, 0x4d, 0x42, 0x11, 0x27, 0xfa, 0xc8, 0x4b, 0x81, 0xd8, 0x7c, 0x80, + 0x40, 0xd4, 0x6e, 0x76, 0x23, 0x13, 0x41, 0x1d, 0xa9, 0xc8, 0xc4, 0xea, 0x96, 0x92, 0x04, 0x33, 0xbd, 0x1b, 0x9d, + 0xd6, 0x72, 0xc9, 0x7a, 0x0d, 0x70, 0x23, 0xb9, 0x2e, 0xfc, 0x6c, 0xaa, 0x9f, 0x16, 0x27, 0x56, 0x6e, 0x60, 0x8f, + 0x15, 0x26, 0x0b, 0xf2, 0x21, 0xc1, 0xd9, 0x93, 0x49, 0x59, 0x92, 0xa6, 0x35, 0x05, 0x69, 0x02, 0x27, 0xac, 0x08, + 0x33, 0x01, 0xc4, 0x52, 0x56, 0x68, 0x03, 0xd2, 0xdb, 0x98, 0xfb, 0x67, 0xcc, 0xcb, 0x4f, 0x6b, 0xa2, 0x15, 0xb9, + 0xa2, 0xd4, 0x87, 0x4a, 0xbe, 0x81, 0x86, 0x40, 0xeb, 0x87, 0x3b, 0xd2, 0x04, 0x2d, 0x45, 0x39, 0xb2, 0xe5, 0x10, + 0x6e, 0x80, 0x13, 0x6d, 0xe7, 0xbd, 0x8a, 0xf0, 0x6e, 0x90, 0x26, 0x98, 0x5b, 0x74, 0xfd, 0x9c, 0x88, 0x0a, 0x2b, + 0x19, 0x13, 0x6d, 0x29, 0xe1, 0x50, 0x92, 0xa9, 0x20, 0x49, 0xaf, 0xd1, 0x07, 0x05, 0xb4, 0x1d, 0x9f, 0x26, 0xa5, + 0x09, 0x1c, 0xd7, 0x6a, 0x28, 0x34, 0xb3, 0x8e, 0x7b, 0xac, 0x16, 0xf7, 0x31, 0xc5, 0xb1, 0x32, 0x4c, 0x2e, 0xf6, + 0xf6, 0xbc, 0xb0, 0x9c, 0xb7, 0x17, 0xf7, 0x11, 0xe6, 0xcb, 0xa5, 0x27, 0xc1, 0x0a, 0xd1, 0x72, 0x19, 0xda, 0x60, + 0xc9, 0x6a, 0xe8, 0x36, 0xed, 0x0a, 0x32, 0x95, 0x02, 0x70, 0x0a, 0x10, 0xd6, 0x88, 0x17, 0x6a, 0xf7, 0x5e, 0x08, + 0xee, 0xa8, 0x5a, 0xd2, 0x8b, 0x6b, 0xcd, 0xbe, 0xc5, 0xb8, 0x7a, 0x71, 0x9f, 0x84, 0x39, 0xdf, 0xdb, 0xdb, 0xc9, + 0xb4, 0x88, 0xfc, 0x00, 0xa2, 0xec, 0x83, 0x94, 0x2c, 0x6a, 0x40, 0x7b, 0x37, 0x56, 0x9d, 0x01, 0x05, 0x45, 0xe9, + 0x6d, 0x35, 0xed, 0x2a, 0x59, 0x10, 0x45, 0x23, 0xac, 0x83, 0xc1, 0x5d, 0xb0, 0xec, 0x0b, 0x32, 0x7f, 0x21, 0x8a, + 0x1c, 0xeb, 0x5f, 0x37, 0x66, 0x56, 0xfb, 0xbe, 0x1f, 0xa6, 0x23, 0x19, 0xcb, 0x30, 0x61, 0x58, 0x49, 0xfc, 0x07, + 0x1a, 0x4c, 0x6b, 0xe2, 0x5e, 0x31, 0x57, 0x9f, 0x28, 0xf0, 0x8d, 0x6a, 0x63, 0xee, 0x92, 0x3c, 0xdd, 0xe8, 0x65, + 0x50, 0x90, 0x7c, 0xf8, 0xad, 0x90, 0x1c, 0x6a, 0x48, 0x14, 0x79, 0xac, 0xe0, 0x6c, 0x0b, 0x2e, 0x9e, 0x8a, 0x15, + 0x9c, 0x6d, 0xc7, 0xad, 0xc1, 0xd4, 0x37, 0xdb, 0xe0, 0xb3, 0x78, 0x83, 0x02, 0xb4, 0x2c, 0xb0, 0xa0, 0x3c, 0x5a, + 0xd5, 0xbd, 0x14, 0x2b, 0x05, 0x61, 0x2a, 0x88, 0xc7, 0xaa, 0x07, 0xa0, 0xd4, 0x46, 0x2d, 0xc3, 0x97, 0x05, 0x53, + 0x64, 0xb9, 0x04, 0xaa, 0xa9, 0x2b, 0x40, 0x4e, 0xda, 0xdb, 0x3e, 0xdd, 0xdb, 0x03, 0xdb, 0x00, 0x94, 0x38, 0x7f, + 0x10, 0x4e, 0xc5, 0x2c, 0x05, 0x55, 0x2a, 0x33, 0xbf, 0xa1, 0x18, 0x6e, 0x81, 0xc8, 0x32, 0xf8, 0x01, 0x05, 0xd3, + 0x30, 0xcb, 0xd8, 0x5c, 0x95, 0xe9, 0xdf, 0x98, 0x13, 0x43, 0xca, 0x99, 0xd2, 0x09, 0x13, 0xd4, 0x4e, 0x34, 0x9d, + 0x56, 0xd1, 0xf6, 0x6c, 0x4e, 0x13, 0xf1, 0x82, 0x65, 0x82, 0x26, 0xb0, 0xfc, 0x92, 0xe2, 0x60, 0x45, 0x19, 0x82, + 0x03, 0x5b, 0xe9, 0x15, 0x46, 0xd1, 0xbd, 0x5d, 0x44, 0x55, 0x07, 0x1a, 0x87, 0x49, 0x14, 0xab, 0x49, 0xec, 0x7c, + 0x46, 0x93, 0xc3, 0x59, 0xb4, 0xb4, 0xf3, 0x69, 0x4a, 0x65, 0x43, 0x72, 0x77, 0x8f, 0x11, 0x23, 0x09, 0x8c, 0xf4, + 0xbc, 0x57, 0x6b, 0x81, 0x88, 0xf7, 0x96, 0x4d, 0xb0, 0x57, 0x82, 0x85, 0xc5, 0x51, 0xfd, 0x2a, 0x9c, 0x86, 0x6e, + 0x7e, 0xd9, 0x78, 0xa5, 0x6d, 0x93, 0x70, 0x90, 0x74, 0x72, 0xbc, 0xdd, 0xb2, 0x7a, 0x69, 0x24, 0x87, 0x91, 0x16, + 0xec, 0xa1, 0x8c, 0x19, 0x2d, 0x0c, 0x79, 0x21, 0x73, 0x14, 0x77, 0x05, 0xf9, 0x00, 0x77, 0x86, 0x9e, 0x8b, 0x49, + 0xbc, 0x72, 0x35, 0xa6, 0xbd, 0x5b, 0x68, 0xff, 0xbb, 0xc2, 0x7b, 0x87, 0xdf, 0x42, 0x60, 0xf7, 0xa7, 0xb2, 0xf9, + 0x7a, 0x40, 0xf7, 0xa7, 0x12, 0x41, 0x3f, 0x05, 0x6b, 0xed, 0xac, 0x40, 0x6e, 0xcb, 0x3f, 0xf1, 0x1b, 0xae, 0xd1, + 0x96, 0x7e, 0x55, 0x61, 0x24, 0x95, 0x69, 0x29, 0xcf, 0x03, 0x2e, 0xf3, 0xd4, 0x20, 0x5f, 0xae, 0x6a, 0x21, 0x51, + 0x9d, 0x61, 0xa8, 0x74, 0xf8, 0x6d, 0xdb, 0xa3, 0x65, 0x4c, 0xa2, 0xec, 0x8c, 0x37, 0x61, 0x2a, 0x76, 0xe1, 0x94, + 0xf1, 0xb5, 0x7b, 0x78, 0x63, 0x02, 0x1e, 0xb4, 0x87, 0x4d, 0x61, 0x19, 0xdb, 0x99, 0xba, 0x07, 0x64, 0x8f, 0x4f, + 0xb8, 0xd1, 0xdd, 0xaa, 0x56, 0xc6, 0x1b, 0xb0, 0xff, 0x11, 0x1e, 0x9b, 0xcb, 0x71, 0x54, 0x73, 0x60, 0x1a, 0x2c, + 0xf2, 0xc2, 0x29, 0xc0, 0x95, 0xf2, 0x96, 0x22, 0xcc, 0x73, 0x19, 0xe0, 0xfe, 0x16, 0x7f, 0xa7, 0x59, 0xe2, 0xb0, + 0xe0, 0x38, 0xb7, 0x0f, 0xe5, 0x88, 0x0a, 0xfc, 0x22, 0x7e, 0x0f, 0x74, 0x2c, 0x29, 0x34, 0x37, 0x54, 0xf4, 0x94, + 0xeb, 0x85, 0x6c, 0x4d, 0x4b, 0xc5, 0xb4, 0x48, 0xa9, 0x91, 0xd3, 0x6c, 0xc8, 0xe3, 0x34, 0x56, 0xb6, 0x28, 0x4e, + 0x55, 0x65, 0x5e, 0xb4, 0x05, 0x8b, 0x65, 0x68, 0x71, 0xb9, 0xf4, 0xaa, 0xa8, 0x26, 0xcc, 0x8a, 0x64, 0x20, 0xcc, + 0xac, 0x8c, 0x8a, 0x8a, 0x66, 0xad, 0xfa, 0x78, 0x68, 0x35, 0xa1, 0xc8, 0xe8, 0xe6, 0x15, 0x38, 0x6c, 0x17, 0x82, + 0xea, 0x6e, 0xfb, 0x14, 0xb0, 0x5a, 0x5d, 0x31, 0x91, 0x85, 0xa1, 0x5f, 0x8b, 0x54, 0xd9, 0x32, 0xa7, 0x75, 0x03, + 0x7e, 0xd1, 0x3d, 0xc9, 0xb2, 0x1a, 0x75, 0xeb, 0xf5, 0x56, 0xb2, 0xd1, 0x53, 0xbe, 0x2d, 0xd9, 0xa8, 0xa2, 0xed, + 0xee, 0x34, 0xd0, 0xfd, 0x69, 0xa9, 0x6a, 0xae, 0xcd, 0x4d, 0x7e, 0xc3, 0x74, 0x4d, 0xa0, 0x4d, 0x85, 0x66, 0xc3, + 0x55, 0x2e, 0xf2, 0x7c, 0x58, 0x5c, 0x26, 0x90, 0xb9, 0x3b, 0x43, 0x45, 0xff, 0xda, 0x6a, 0x94, 0xd7, 0x71, 0xbd, + 0x6f, 0xc9, 0x28, 0xe6, 0xd7, 0x61, 0xfc, 0x0e, 0xe6, 0x2b, 0x2b, 0x9f, 0xdf, 0x45, 0x69, 0x28, 0xa8, 0xe6, 0x2e, + 0x25, 0x0c, 0xdf, 0x5a, 0x30, 0x7c, 0xab, 0xf8, 0x74, 0xd9, 0x1f, 0x2f, 0x5e, 0x14, 0x03, 0x04, 0xc3, 0xdc, 0xb0, + 0x8c, 0x4b, 0xb1, 0x79, 0x8e, 0x55, 0x16, 0x76, 0x59, 0xb0, 0xb0, 0x4b, 0xe1, 0xad, 0x0e, 0xe5, 0x79, 0xdf, 0x6d, + 0x1e, 0x65, 0x9d, 0xb3, 0x7d, 0x57, 0x1e, 0xfc, 0xef, 0x82, 0x7b, 0xfb, 0x58, 0x5c, 0xee, 0xc0, 0x3f, 0x90, 0xe9, + 0x2a, 0x0a, 0xe4, 0xe7, 0x90, 0x76, 0x20, 0x48, 0xc7, 0xba, 0x73, 0x50, 0xca, 0x29, 0x93, 0x08, 0xe4, 0x0d, 0x66, + 0x99, 0xe0, 0x13, 0x3d, 0x66, 0xa6, 0xaf, 0x19, 0xc9, 0x4a, 0x70, 0x45, 0xcb, 0x68, 0x7b, 0x50, 0xbd, 0xc8, 0xb5, + 0xf8, 0xc8, 0x92, 0x28, 0xc8, 0xb0, 0x96, 0x22, 0x59, 0x90, 0xe4, 0xc4, 0x24, 0x1b, 0xaf, 0xd7, 0xe1, 0x21, 0x4b, + 0x58, 0x36, 0xa6, 0xa9, 0xc7, 0xd1, 0x62, 0xdb, 0x64, 0x1c, 0x02, 0x32, 0x6a, 0x32, 0xfc, 0x7d, 0x79, 0xe1, 0xcf, + 0x87, 0xd1, 0xc0, 0x0f, 0x34, 0xa1, 0x62, 0xcc, 0x23, 0x48, 0x4c, 0xf1, 0xa3, 0xe2, 0x46, 0xd3, 0xde, 0xde, 0x8e, + 0xe7, 0x4a, 0xb7, 0x04, 0x5c, 0xfd, 0xb6, 0x6b, 0x50, 0x77, 0x01, 0xd7, 0x73, 0xca, 0xa9, 0x29, 0x5a, 0xd0, 0xd5, + 0x9b, 0x2c, 0xc2, 0xff, 0x48, 0xef, 0x70, 0x8a, 0xf2, 0x3c, 0x50, 0x50, 0xbb, 0x43, 0x46, 0xe3, 0xc8, 0xc5, 0x1f, + 0xe9, 0x5d, 0x50, 0xdc, 0x16, 0x97, 0x97, 0x9b, 0xe5, 0x06, 0xba, 0xfc, 0x26, 0x71, 0x71, 0x39, 0x49, 0xb0, 0xc8, + 0x31, 0x4f, 0xd9, 0x08, 0x88, 0xf3, 0x5b, 0x7a, 0x17, 0xa8, 0xf1, 0x98, 0x75, 0x59, 0x0f, 0x2d, 0x0c, 0xea, 0x7d, + 0xab, 0xd8, 0xde, 0x06, 0x6d, 0x50, 0xf4, 0x64, 0xdf, 0x3e, 0xa9, 0xb4, 0x2b, 0xcd, 0x43, 0x84, 0xf2, 0x87, 0x2e, + 0x05, 0x7f, 0x6d, 0x8b, 0x36, 0x51, 0x49, 0x7d, 0x5d, 0xe9, 0x44, 0xa1, 0x43, 0x99, 0xeb, 0x71, 0xe9, 0xa5, 0xe6, + 0xd4, 0xe9, 0x3b, 0x08, 0x96, 0x23, 0xec, 0x6b, 0xa1, 0x07, 0x0d, 0xbe, 0x57, 0x29, 0x21, 0x65, 0x24, 0xe9, 0x65, + 0xd9, 0xcf, 0xb9, 0xf4, 0x00, 0xef, 0x90, 0xd2, 0x12, 0xca, 0xeb, 0x98, 0xb9, 0x49, 0x17, 0xfd, 0x41, 0x10, 0x6f, + 0x61, 0x96, 0x10, 0xa4, 0x36, 0x16, 0x45, 0x0e, 0x54, 0xa8, 0xe9, 0x4b, 0x65, 0x00, 0xb2, 0xa1, 0xc7, 0xd6, 0xa4, + 0x66, 0x22, 0xa5, 0xa6, 0x6f, 0x61, 0x7c, 0x8b, 0x94, 0xa4, 0x12, 0x19, 0x52, 0x89, 0x94, 0x42, 0x4f, 0x6f, 0xae, + 0x26, 0x21, 0x7b, 0x43, 0x8b, 0xeb, 0x73, 0x6a, 0xcf, 0x93, 0x0a, 0x58, 0x9e, 0x1c, 0x07, 0xe5, 0x01, 0x2c, 0x89, + 0xaa, 0x06, 0xb9, 0x71, 0xe7, 0xa4, 0x26, 0xbf, 0xd5, 0xe3, 0xbe, 0x59, 0x16, 0x31, 0x28, 0xf1, 0xc6, 0x68, 0x91, + 0x7a, 0x63, 0x9c, 0x40, 0x3e, 0x22, 0xcf, 0x0b, 0xf8, 0xa9, 0xbd, 0x1b, 0x95, 0x6c, 0xe5, 0xcd, 0x57, 0xfc, 0x40, + 0x99, 0x17, 0x90, 0xa3, 0x89, 0x53, 0xc3, 0x53, 0x52, 0x4f, 0xde, 0xb5, 0xb3, 0xb6, 0xed, 0x27, 0x9d, 0xa2, 0xa3, + 0x01, 0xfb, 0x41, 0x78, 0x0b, 0x6b, 0x15, 0xf6, 0x5d, 0x6e, 0x7d, 0xe5, 0x4f, 0x07, 0xfb, 0xca, 0x24, 0x52, 0x2f, + 0x23, 0x2b, 0x12, 0xe7, 0xfe, 0x5c, 0xcb, 0x5f, 0x66, 0x34, 0xbd, 0xbb, 0xa0, 0x90, 0xeb, 0xcc, 0xe1, 0xae, 0x6f, + 0xb9, 0x0d, 0x65, 0x9e, 0x7a, 0x37, 0x91, 0xca, 0x4a, 0x5e, 0xbd, 0x04, 0xb8, 0x7a, 0x45, 0x30, 0x97, 0xd1, 0x46, + 0xcb, 0x11, 0xa3, 0x4e, 0x0b, 0xdd, 0x7a, 0x79, 0x92, 0xb6, 0x19, 0xf8, 0xd7, 0x4a, 0x4c, 0xeb, 0x60, 0x01, 0xe6, + 0xf6, 0x85, 0xd4, 0x5e, 0xd6, 0x5f, 0xf5, 0xca, 0x40, 0x11, 0x84, 0xef, 0x92, 0xed, 0x4b, 0xdd, 0x94, 0x35, 0xbb, + 0x7d, 0xa9, 0x95, 0xa0, 0x9f, 0x4c, 0xf9, 0xc1, 0x7a, 0x9e, 0xe2, 0xf2, 0x32, 0xcb, 0x73, 0x94, 0x03, 0x78, 0x3f, + 0xb6, 0x3d, 0xef, 0x47, 0x9d, 0x34, 0xe8, 0x43, 0x2c, 0xf6, 0x22, 0xe6, 0x86, 0x89, 0x97, 0xf3, 0xff, 0xb8, 0x36, + 0xff, 0x8f, 0xd6, 0x95, 0x53, 0x30, 0x8d, 0x46, 0x09, 0x8d, 0x0c, 0xeb, 0x44, 0x8a, 0x00, 0xa5, 0xde, 0x96, 0x09, + 0xf2, 0xf1, 0x2a, 0x00, 0x8d, 0x6b, 0x31, 0xe4, 0x89, 0xa8, 0x0f, 0xc3, 0x09, 0x8b, 0xef, 0x82, 0x19, 0xab, 0x4f, + 0x78, 0xc2, 0xb3, 0x69, 0x38, 0xa0, 0x38, 0xbb, 0xcb, 0x04, 0x9d, 0xd4, 0x67, 0x0c, 0x3f, 0xa7, 0xf1, 0x9c, 0x0a, + 0x36, 0x08, 0xb1, 0x7b, 0x96, 0xb2, 0x30, 0x76, 0x5e, 0x85, 0x69, 0xca, 0x6f, 0x5c, 0xfc, 0x96, 0x5f, 0x73, 0xc1, + 0xf1, 0xeb, 0xdb, 0xbb, 0x11, 0x4d, 0xf0, 0xfb, 0xeb, 0x59, 0x22, 0x66, 0x38, 0x0b, 0x93, 0xac, 0x9e, 0xd1, 0x94, + 0x0d, 0xdb, 0x03, 0x1e, 0xf3, 0xb4, 0x0e, 0x29, 0xdb, 0x13, 0x1a, 0xc4, 0x6c, 0x34, 0x16, 0x4e, 0x14, 0xa6, 0x1f, + 0xdb, 0xf5, 0xfa, 0x34, 0x65, 0x93, 0x30, 0xbd, 0xab, 0xcb, 0x16, 0xc1, 0x97, 0x8d, 0x83, 0xf0, 0xf1, 0xf0, 0xb0, + 0x2d, 0xd2, 0x30, 0xc9, 0x18, 0x6c, 0x53, 0x10, 0xc6, 0xb1, 0x73, 0x70, 0xd4, 0x98, 0x64, 0x3b, 0x2a, 0x90, 0x17, + 0x26, 0x22, 0xbf, 0xc2, 0x1f, 0x01, 0x6e, 0xff, 0x5a, 0x24, 0xf8, 0x7a, 0x26, 0x04, 0x4f, 0x16, 0x83, 0x59, 0x9a, + 0xf1, 0x34, 0x98, 0x72, 0x96, 0x08, 0x9a, 0xb6, 0xaf, 0x79, 0x1a, 0xd1, 0xb4, 0x9e, 0x86, 0x11, 0x9b, 0x65, 0xc1, + 0xe1, 0xf4, 0xb6, 0x0d, 0x9a, 0xc5, 0x28, 0xe5, 0xb3, 0x24, 0xd2, 0x73, 0xb1, 0x64, 0x4c, 0x53, 0x26, 0xec, 0x0a, + 0xf9, 0x0a, 0x93, 0x20, 0x66, 0x09, 0x0d, 0xd3, 0xfa, 0x08, 0x3a, 0x83, 0x59, 0xd4, 0x88, 0xe8, 0x08, 0xa7, 0xa3, + 0xeb, 0xd0, 0x6b, 0xb6, 0x1e, 0x61, 0xf3, 0xbf, 0x7f, 0x84, 0x9c, 0xc6, 0xe6, 0xe2, 0x66, 0xa3, 0xf1, 0x27, 0xd4, + 0x5e, 0x99, 0x45, 0x02, 0x14, 0x34, 0xa7, 0xb7, 0x4e, 0xc6, 0x21, 0xa7, 0x6d, 0x53, 0xcf, 0xf6, 0x34, 0x8c, 0x20, + 0x21, 0x38, 0x68, 0x4d, 0x6f, 0x73, 0x58, 0x5d, 0xa0, 0x92, 0x4c, 0xf5, 0x22, 0xf5, 0xd3, 0xe2, 0xb7, 0x42, 0x7c, + 0xb2, 0x19, 0xe2, 0x96, 0x81, 0xb8, 0xc4, 0x7a, 0x3d, 0x9a, 0xa5, 0x32, 0xb6, 0x1a, 0x34, 0x33, 0x05, 0xc8, 0x98, + 0xcf, 0x69, 0x6a, 0xe0, 0x90, 0x0f, 0xbf, 0x19, 0x8c, 0xd6, 0x66, 0x30, 0x4e, 0x3e, 0x05, 0x46, 0x9a, 0x44, 0x8b, + 0xea, 0xbe, 0x36, 0x53, 0x3a, 0x69, 0x8f, 0x29, 0xd0, 0x53, 0xd0, 0x82, 0xdf, 0x37, 0x2c, 0x12, 0x63, 0xf5, 0x53, + 0x92, 0xf3, 0x8d, 0xaa, 0x3b, 0x6a, 0x34, 0xd4, 0x73, 0xc6, 0x7e, 0xa5, 0x41, 0xd3, 0x87, 0x06, 0xf9, 0x15, 0xfe, + 0x5b, 0x71, 0x99, 0xb7, 0xca, 0x3d, 0xf1, 0xb7, 0xf6, 0x2d, 0x5f, 0x2b, 0x49, 0xb1, 0xbc, 0x11, 0x8d, 0x53, 0x23, + 0x2b, 0x95, 0xf0, 0x01, 0xb7, 0x9d, 0x3c, 0x4f, 0x84, 0x75, 0x8a, 0x5b, 0x9c, 0xac, 0xfb, 0xad, 0xca, 0xbb, 0x08, + 0x20, 0xd2, 0x61, 0x25, 0x1b, 0xf2, 0x76, 0xd2, 0x21, 0x8d, 0x76, 0x52, 0xaf, 0x23, 0x8f, 0x93, 0xb4, 0x97, 0xe8, + 0xf4, 0x3c, 0x8f, 0x75, 0xb9, 0x34, 0xb6, 0x33, 0x14, 0x70, 0xb8, 0x6a, 0xba, 0x5c, 0x96, 0x61, 0x00, 0x26, 0xaf, + 0x6b, 0xfc, 0x4d, 0xe8, 0x06, 0x38, 0xb3, 0x38, 0x79, 0x62, 0x5e, 0xec, 0x92, 0x1a, 0x5e, 0x11, 0xf3, 0x81, 0xc4, + 0x9c, 0x3f, 0x0d, 0xc5, 0x18, 0xbc, 0x14, 0x85, 0xf8, 0x29, 0x93, 0x98, 0xdc, 0x7d, 0x17, 0x75, 0xd3, 0x22, 0xc3, + 0x0d, 0x32, 0xf9, 0xd2, 0x1c, 0x46, 0xf9, 0x4e, 0x10, 0x18, 0x11, 0x7f, 0x43, 0x94, 0x4d, 0x67, 0x2c, 0xba, 0xe1, + 0x43, 0x2d, 0x3a, 0x9a, 0x08, 0x26, 0x73, 0xb7, 0x4d, 0xc4, 0x61, 0x1c, 0x66, 0x97, 0x03, 0x75, 0x57, 0x32, 0x2b, + 0x6f, 0x06, 0x84, 0x12, 0x7a, 0x65, 0xa4, 0xd1, 0x54, 0xda, 0xa3, 0x3f, 0x8a, 0xad, 0xf6, 0x49, 0x7a, 0x9f, 0x7d, + 0x52, 0x2c, 0x3c, 0xe3, 0xb3, 0x74, 0x00, 0xe1, 0x48, 0x2d, 0xf5, 0xd6, 0x1d, 0x37, 0xae, 0x54, 0x31, 0x5c, 0x2c, + 0xac, 0x4c, 0x50, 0x81, 0x99, 0xfd, 0x52, 0x09, 0x2a, 0x43, 0x5e, 0xea, 0xbe, 0x86, 0x16, 0x71, 0x66, 0x49, 0x20, + 0xb3, 0x23, 0x99, 0xd4, 0xe8, 0x25, 0xa4, 0x93, 0xf8, 0xb3, 0x84, 0xfd, 0x32, 0xa3, 0x97, 0x0c, 0x74, 0x4d, 0xe6, + 0xb3, 0x48, 0xc6, 0x9a, 0x40, 0xf6, 0xd5, 0x9b, 0x10, 0xbc, 0x60, 0x91, 0xda, 0x98, 0x44, 0x56, 0xea, 0xdc, 0x26, + 0xb7, 0xee, 0x82, 0xbf, 0x18, 0xb4, 0x03, 0x86, 0x23, 0x3e, 0x09, 0x59, 0x12, 0x48, 0x97, 0x6f, 0x31, 0x58, 0x00, + 0xad, 0x31, 0x8b, 0x82, 0x44, 0x6f, 0x4f, 0x13, 0xf9, 0x1f, 0x38, 0x4b, 0x64, 0xd7, 0xbc, 0xcd, 0x25, 0x42, 0x15, + 0xfa, 0x88, 0x41, 0xf0, 0x99, 0x92, 0x6b, 0x1c, 0x61, 0xbb, 0xba, 0xb8, 0x76, 0x5e, 0xd9, 0x81, 0xc6, 0xca, 0x46, + 0x29, 0x23, 0x80, 0xaf, 0x96, 0x66, 0x3c, 0x15, 0x9e, 0x37, 0xc6, 0x31, 0x22, 0x9d, 0xb1, 0x74, 0x76, 0x9d, 0xc6, + 0xf2, 0x4f, 0xb7, 0xde, 0x0c, 0x9a, 0x85, 0xf9, 0x5e, 0xb9, 0x0d, 0xac, 0x92, 0xa3, 0xf4, 0x8d, 0x52, 0xb9, 0x8c, + 0xe2, 0xb7, 0x5a, 0x6a, 0xf9, 0x5c, 0x2c, 0x17, 0xeb, 0xe3, 0xa6, 0x44, 0x95, 0x57, 0x01, 0x42, 0x06, 0x8b, 0xb6, + 0x4c, 0x85, 0xf2, 0x72, 0xdd, 0x85, 0x2a, 0x79, 0xa5, 0x44, 0xf4, 0xe5, 0xee, 0x22, 0xd5, 0x33, 0xe6, 0x57, 0xcc, + 0x38, 0x99, 0xaa, 0x24, 0x97, 0x6b, 0x8c, 0x58, 0x7a, 0xe8, 0xa6, 0x66, 0x0a, 0x96, 0x3b, 0x92, 0x6e, 0xa4, 0x5b, + 0x5f, 0x3d, 0xd2, 0x94, 0x94, 0xe1, 0xae, 0xb5, 0x01, 0x20, 0x57, 0x6f, 0x13, 0x60, 0x60, 0xb6, 0x66, 0xc2, 0x2c, + 0x01, 0xb4, 0xb1, 0x21, 0x85, 0x8b, 0x34, 0x57, 0xbb, 0x8b, 0xef, 0x44, 0xbe, 0x6f, 0x35, 0x95, 0xbf, 0x59, 0x04, + 0x7f, 0x41, 0x02, 0x2e, 0x94, 0x52, 0x1a, 0xb8, 0x6f, 0x5e, 0x5f, 0xbc, 0x73, 0xf1, 0x35, 0x8f, 0xee, 0x02, 0x57, + 0xa4, 0x33, 0xea, 0xe6, 0xc8, 0x17, 0x63, 0x9a, 0x14, 0x2f, 0xe3, 0xe1, 0x31, 0xf5, 0x63, 0x3e, 0x52, 0x97, 0x32, + 0x57, 0x8d, 0xe4, 0xc1, 0xd5, 0xa9, 0x7c, 0xc9, 0x54, 0xe7, 0x54, 0xa8, 0xd7, 0x7b, 0x89, 0x14, 0x7e, 0x76, 0x20, + 0x84, 0x72, 0xba, 0x2f, 0xc6, 0xf2, 0xe1, 0x02, 0x0e, 0x8c, 0x7c, 0xda, 0x5d, 0xac, 0x11, 0x53, 0x17, 0x86, 0x18, + 0x77, 0xd4, 0x12, 0x32, 0xd9, 0xea, 0x2a, 0x18, 0x5c, 0x5d, 0xe5, 0xa7, 0xfb, 0x30, 0xd6, 0xbe, 0x19, 0x17, 0x20, + 0x34, 0xfd, 0x0b, 0x02, 0x83, 0x97, 0x0d, 0xa5, 0xa4, 0x03, 0x43, 0xc0, 0xbc, 0x51, 0x07, 0x16, 0x09, 0x04, 0x06, + 0xbd, 0xa3, 0xa2, 0x44, 0x9e, 0x58, 0x55, 0xb4, 0x0d, 0x02, 0xd5, 0xb0, 0xa4, 0x7b, 0xe5, 0x4d, 0x2d, 0xf7, 0xd7, + 0x80, 0x14, 0xd9, 0xd0, 0x5d, 0x21, 0xf8, 0x2b, 0x21, 0x3b, 0xdd, 0x57, 0x78, 0xb8, 0xb2, 0x5f, 0x6d, 0xa2, 0x5e, + 0x3b, 0x50, 0x60, 0xab, 0x97, 0x09, 0xfc, 0x51, 0xe0, 0x8f, 0x57, 0xb2, 0xa9, 0x11, 0x46, 0xa0, 0x25, 0x81, 0xd0, + 0x6e, 0x18, 0xad, 0x63, 0xc0, 0xe3, 0x38, 0x9c, 0x66, 0x34, 0x30, 0x3f, 0xb4, 0x5c, 0x02, 0xf1, 0xb6, 0xae, 0x08, + 0xe8, 0xf4, 0x9a, 0x73, 0x50, 0x17, 0xd6, 0xb5, 0x94, 0x79, 0x98, 0x7a, 0xf5, 0xfa, 0xa0, 0x7e, 0x3d, 0x42, 0xb9, + 0x18, 0x2f, 0x6c, 0xa9, 0x76, 0xdc, 0x68, 0xb4, 0x21, 0x17, 0xb2, 0x1e, 0xc6, 0x6c, 0x94, 0x04, 0x31, 0x1d, 0x8a, + 0x5c, 0xc0, 0x2d, 0xb5, 0x85, 0x51, 0x23, 0xfc, 0xd6, 0x51, 0x4a, 0x27, 0x8e, 0x0f, 0xff, 0xde, 0x3f, 0x71, 0x2e, + 0xa2, 0x20, 0x11, 0xe3, 0xba, 0xcc, 0xba, 0x85, 0x3b, 0x03, 0x62, 0x5c, 0x79, 0x5e, 0x58, 0x13, 0x0d, 0x28, 0xa8, + 0x58, 0xb9, 0x48, 0x1d, 0x31, 0xc6, 0x22, 0xb5, 0xdb, 0x25, 0x68, 0xb1, 0xb6, 0x82, 0x75, 0x49, 0x7f, 0x80, 0xf2, + 0x4c, 0x2a, 0xc6, 0xeb, 0x8d, 0x8d, 0xba, 0x54, 0x7d, 0x5a, 0x43, 0x9f, 0xa5, 0xd8, 0xe5, 0xca, 0xb1, 0xbc, 0x50, + 0x3d, 0x1e, 0x82, 0xcc, 0x8a, 0xca, 0x89, 0xed, 0x1e, 0x28, 0x67, 0xc9, 0x74, 0x26, 0x7a, 0xd2, 0xa9, 0x9d, 0xc2, + 0x05, 0x89, 0x3e, 0xb6, 0x4a, 0x00, 0x07, 0xfd, 0x85, 0x02, 0x66, 0x10, 0xc6, 0x03, 0x0f, 0x20, 0x72, 0xea, 0xce, + 0x49, 0x4a, 0x27, 0xa8, 0x3d, 0x61, 0x49, 0x5d, 0xd5, 0x1d, 0x59, 0x6a, 0x89, 0xff, 0x08, 0x9e, 0x72, 0x5f, 0x8e, + 0x86, 0x65, 0xee, 0xea, 0x06, 0x5c, 0x5e, 0xf5, 0xf3, 0xbc, 0x9d, 0x0a, 0xaf, 0xf7, 0xd2, 0x43, 0x7d, 0xfc, 0x8d, + 0xf5, 0x72, 0x16, 0xd7, 0x1c, 0x15, 0x17, 0xb7, 0xd0, 0x96, 0x26, 0xf6, 0x59, 0x90, 0xcd, 0xbe, 0x21, 0xd0, 0xf0, + 0xb9, 0xe7, 0xd2, 0x6c, 0x5a, 0x57, 0xbc, 0xab, 0x2e, 0x49, 0xd6, 0x85, 0xae, 0x48, 0x7b, 0x6a, 0x7f, 0x14, 0x0b, + 0xc9, 0x96, 0xf4, 0x25, 0x0d, 0xe5, 0x4c, 0xe8, 0x17, 0x97, 0x7a, 0xf4, 0xb3, 0x7d, 0x8d, 0x07, 0x55, 0xf8, 0xc9, + 0xd5, 0x59, 0x95, 0xc7, 0x01, 0x5f, 0x2a, 0x5e, 0x60, 0x17, 0xc6, 0x31, 0x4c, 0x78, 0x65, 0xd4, 0x17, 0xfb, 0xa5, + 0x1f, 0x3d, 0xd1, 0xf7, 0x50, 0xae, 0xcf, 0xe9, 0x13, 0xa9, 0x52, 0x5a, 0x6f, 0xcd, 0xdb, 0x11, 0x26, 0x58, 0xa4, + 0xa4, 0x2f, 0x83, 0x70, 0x77, 0x25, 0x2f, 0xba, 0x5d, 0xf2, 0x2e, 0xa5, 0x90, 0x3a, 0x72, 0x41, 0xc4, 0x4d, 0x93, + 0xc8, 0x75, 0xfe, 0x32, 0x88, 0xd9, 0xe0, 0x23, 0x71, 0x77, 0x17, 0x1e, 0x5a, 0xbf, 0xf6, 0x28, 0xb9, 0x82, 0x61, + 0xd8, 0xa8, 0xea, 0x48, 0x4f, 0x7c, 0x8b, 0x17, 0xab, 0xb7, 0xe2, 0xb8, 0x9d, 0xdd, 0x05, 0x30, 0x1e, 0x35, 0x4f, + 0xe7, 0x2a, 0xbf, 0x2c, 0xdf, 0x75, 0x55, 0x42, 0x01, 0x68, 0x56, 0xe5, 0x8e, 0x24, 0x2a, 0xe2, 0x7e, 0x92, 0xd2, + 0x5c, 0x47, 0x31, 0x35, 0x80, 0x53, 0x68, 0xfe, 0xe6, 0x3a, 0x7f, 0x29, 0xca, 0x68, 0xe1, 0xd1, 0x90, 0x29, 0x19, + 0xc4, 0x85, 0xb9, 0xc0, 0x8c, 0xf5, 0x23, 0x2a, 0x42, 0x16, 0xab, 0x2e, 0x6d, 0x63, 0x80, 0xaf, 0xac, 0x68, 0xb9, + 0xcc, 0xaa, 0x6b, 0x61, 0x55, 0x0c, 0xca, 0x95, 0x9d, 0xee, 0x97, 0x70, 0xcb, 0x95, 0xc9, 0x33, 0x69, 0x87, 0x06, + 0xcb, 0x15, 0xaa, 0x3a, 0xe7, 0x2f, 0x03, 0x79, 0x6d, 0x08, 0x00, 0xe4, 0x1a, 0x40, 0x08, 0x5a, 0xab, 0x6b, 0x31, + 0x5e, 0x4c, 0xb8, 0x2f, 0xc2, 0x74, 0x44, 0xc5, 0x0a, 0x62, 0x63, 0x95, 0xa3, 0xda, 0x36, 0x01, 0xea, 0x35, 0x68, + 0xc3, 0x2a, 0xb4, 0x57, 0x80, 0xf4, 0xee, 0xee, 0x82, 0xe5, 0x64, 0x77, 0x41, 0x93, 0x01, 0x8f, 0xe8, 0xfb, 0xb7, + 0xdf, 0xc0, 0x25, 0x47, 0x9e, 0x80, 0x61, 0x31, 0x46, 0x20, 0x38, 0xe5, 0xe6, 0x28, 0x11, 0xc2, 0xa5, 0x08, 0x51, + 0x9c, 0xc0, 0x91, 0x73, 0x49, 0x10, 0x73, 0xd7, 0xe9, 0x2a, 0xc8, 0x69, 0xa4, 0x60, 0x26, 0x89, 0xec, 0xc5, 0xf3, + 0xd3, 0x7d, 0xd5, 0x5a, 0x89, 0x00, 0xd5, 0x08, 0x90, 0x20, 0xcf, 0x69, 0x89, 0x03, 0xc8, 0x6b, 0xb6, 0xf1, 0x10, + 0xb1, 0x79, 0x41, 0x6c, 0xf2, 0x02, 0x55, 0xe7, 0x34, 0x0e, 0xaf, 0x69, 0xdc, 0xd9, 0x5d, 0x24, 0xcb, 0x65, 0x23, + 0x3f, 0xdd, 0x57, 0x8f, 0xce, 0xa9, 0xe4, 0x1b, 0xea, 0x85, 0x97, 0x72, 0x8b, 0xe1, 0x56, 0x22, 0x64, 0x7b, 0x9a, + 0x34, 0xa7, 0x40, 0x0f, 0x90, 0xbb, 0x8e, 0x4c, 0xb0, 0x90, 0x8d, 0x0a, 0x85, 0x28, 0x77, 0x1d, 0x16, 0xad, 0x97, + 0x65, 0x82, 0x4e, 0xa1, 0x74, 0xbc, 0x5c, 0x36, 0x73, 0xd7, 0x99, 0xb0, 0x04, 0x9e, 0x92, 0xe5, 0x52, 0x5e, 0xf8, + 0x9b, 0xb0, 0xc4, 0x6b, 0x00, 0xd9, 0xba, 0xce, 0x24, 0xbc, 0x95, 0x0b, 0x36, 0x35, 0xe1, 0xad, 0xd7, 0xd4, 0x55, + 0x7e, 0x81, 0x9f, 0x0c, 0x28, 0xae, 0xdc, 0xd1, 0x58, 0xef, 0x68, 0x84, 0x67, 0xea, 0x2a, 0x13, 0xf1, 0x22, 0x12, + 0x6f, 0xde, 0xd1, 0xc8, 0xec, 0xe8, 0x6c, 0xcb, 0x8e, 0xce, 0xee, 0xd9, 0xd1, 0x50, 0xef, 0x9e, 0x53, 0xe0, 0x8e, + 0x2f, 0x97, 0xcd, 0x46, 0x89, 0xbd, 0xd3, 0xfd, 0x88, 0xcd, 0x61, 0x37, 0x40, 0xcd, 0x13, 0x6c, 0x42, 0x37, 0x13, + 0x65, 0x15, 0xc5, 0xf4, 0xb3, 0x30, 0x59, 0x62, 0x21, 0xa9, 0x62, 0xc1, 0xa6, 0xeb, 0x22, 0xe6, 0xf6, 0x47, 0x52, + 0x36, 0x03, 0x3c, 0x64, 0x80, 0x87, 0xb1, 0x79, 0x01, 0xa6, 0xe7, 0xbe, 0x73, 0xb1, 0xeb, 0xb8, 0x86, 0xac, 0xaf, + 0xf2, 0x4b, 0x90, 0x11, 0x72, 0x7d, 0x0f, 0xa2, 0x45, 0x68, 0xed, 0x76, 0xb6, 0xd3, 0x1c, 0x84, 0xc7, 0x6f, 0x78, + 0x1a, 0xb9, 0x81, 0x6a, 0xfa, 0x59, 0xa8, 0x9a, 0xb0, 0x44, 0x27, 0x5b, 0x6d, 0xa5, 0xb5, 0xb2, 0xde, 0xa6, 0xb8, + 0xd6, 0xd1, 0x91, 0x6a, 0x31, 0x0d, 0x85, 0xa0, 0x69, 0xa2, 0x29, 0xd7, 0x75, 0xff, 0xbf, 0xa0, 0xc2, 0x0d, 0x7c, + 0x25, 0x34, 0x1b, 0x60, 0x08, 0x50, 0x2b, 0xec, 0x9a, 0xe7, 0x2b, 0xf1, 0xb4, 0x53, 0x6a, 0xb0, 0x77, 0xc8, 0x36, + 0x1a, 0x54, 0x11, 0xd8, 0x30, 0xb3, 0x09, 0x8d, 0x2e, 0x25, 0x83, 0xee, 0x0e, 0xae, 0xb4, 0xc2, 0xba, 0x22, 0xee, + 0xca, 0x0e, 0xd8, 0xfd, 0x79, 0xd6, 0x7a, 0x74, 0x78, 0xee, 0x62, 0xc5, 0xe3, 0xf9, 0x70, 0xe8, 0xa2, 0xdc, 0x79, + 0x58, 0xb7, 0xe6, 0xe1, 0xcf, 0xb3, 0xaf, 0x9f, 0x35, 0xbe, 0x2e, 0x3a, 0x27, 0x40, 0x44, 0x3a, 0xbe, 0x6f, 0x44, + 0x95, 0x05, 0xaf, 0x59, 0xd1, 0x30, 0x4c, 0xb6, 0x2f, 0xa7, 0x67, 0x2f, 0x27, 0x9b, 0x52, 0x1a, 0x01, 0x71, 0xe2, + 0xb5, 0xd2, 0xcb, 0x98, 0xce, 0xa9, 0x79, 0xf3, 0xe0, 0x86, 0xc9, 0x36, 0xf4, 0x18, 0xf0, 0x59, 0x22, 0x74, 0xa2, + 0x83, 0x66, 0xb5, 0xd6, 0x92, 0xae, 0xe4, 0x1a, 0x6c, 0x1b, 0xe1, 0x4e, 0xc9, 0xb9, 0xaa, 0xf4, 0xca, 0xaf, 0xb0, + 0x6b, 0x01, 0xb0, 0x15, 0xb2, 0xee, 0x96, 0xf2, 0xa0, 0x81, 0x1b, 0xdb, 0x60, 0xc3, 0x4d, 0x14, 0xb8, 0x6e, 0xdf, + 0xe0, 0x49, 0xfa, 0x2a, 0x2b, 0x2f, 0x8c, 0xd8, 0x8a, 0xaf, 0x4f, 0x62, 0xe0, 0x3a, 0x85, 0xc1, 0x12, 0x9a, 0x65, + 0x5b, 0x11, 0x50, 0x6c, 0x22, 0x76, 0xcb, 0xd6, 0xee, 0x96, 0x51, 0x70, 0x03, 0xc3, 0x09, 0x93, 0x00, 0x17, 0x11, + 0x53, 0xdd, 0x8a, 0x0e, 0x87, 0x74, 0x50, 0xb8, 0x7a, 0x21, 0xf6, 0x35, 0x64, 0xb1, 0x80, 0x10, 0x90, 0x8c, 0xcd, + 0xb8, 0xaf, 0x78, 0x42, 0x5d, 0x64, 0xb2, 0x39, 0x35, 0xfc, 0x5a, 0xfe, 0x6f, 0x86, 0x47, 0x8d, 0x58, 0x85, 0x45, + 0xcf, 0xb2, 0x5c, 0x1a, 0x37, 0x4f, 0xa5, 0xbc, 0x8a, 0x48, 0x2e, 0xfd, 0x38, 0xdb, 0x0e, 0xd0, 0xc3, 0x8e, 0xc9, + 0xa2, 0xf9, 0xf5, 0x51, 0xb3, 0x91, 0xbb, 0xd8, 0x85, 0xe1, 0x1e, 0x7a, 0x4a, 0x64, 0xaf, 0x03, 0xe8, 0x35, 0x4b, + 0x3e, 0xa7, 0x5f, 0xab, 0xf9, 0xb8, 0xe9, 0x62, 0xf5, 0x22, 0x01, 0x94, 0x17, 0xcc, 0x60, 0x00, 0xce, 0xcf, 0xdf, + 0xbd, 0x94, 0xea, 0xe0, 0x0f, 0x83, 0xe7, 0xb8, 0xd9, 0x70, 0xb1, 0x9b, 0x09, 0x3e, 0xfd, 0x8c, 0x25, 0x1c, 0xb8, + 0xd8, 0x1d, 0xc4, 0x3c, 0xa3, 0xf6, 0x1a, 0x94, 0x3a, 0xfb, 0xfb, 0x17, 0xa1, 0x20, 0x9a, 0xa6, 0x34, 0xcb, 0x1c, + 0x7b, 0x7c, 0x4d, 0x4a, 0x9f, 0x60, 0x98, 0x1b, 0x29, 0x2e, 0xa3, 0x42, 0xe2, 0x45, 0xdd, 0xf1, 0xb7, 0xa9, 0x4a, + 0x95, 0xad, 0x11, 0x9b, 0x14, 0x01, 0x05, 0x63, 0x53, 0xda, 0xd5, 0x27, 0x67, 0xde, 0x70, 0xf4, 0xd4, 0xc4, 0x2a, + 0x26, 0xbc, 0x3e, 0x41, 0xa5, 0x64, 0xc2, 0x92, 0xcb, 0x0d, 0xa5, 0xe1, 0xed, 0x86, 0x52, 0x50, 0xd9, 0x0a, 0xe8, + 0xf4, 0xeb, 0x67, 0x3e, 0x8d, 0xf5, 0x52, 0xf1, 0xb1, 0x41, 0x8c, 0xa4, 0xdf, 0xf2, 0x13, 0x90, 0x5a, 0xdb, 0x20, + 0x47, 0xf8, 0xed, 0xd3, 0x41, 0xc9, 0xe7, 0x4c, 0x57, 0x8c, 0xf2, 0xfb, 0x56, 0x08, 0xa5, 0x75, 0xf0, 0x5f, 0xc7, + 0x9f, 0xb5, 0x56, 0x7a, 0xfb, 0x69, 0x82, 0xb3, 0xb4, 0xaa, 0xdf, 0xb1, 0xf5, 0xfa, 0x1e, 0xfb, 0xea, 0xde, 0x6f, + 0x28, 0xd6, 0x8a, 0x4f, 0xb1, 0xff, 0x83, 0x98, 0x4d, 0x4a, 0x12, 0x58, 0x07, 0x53, 0x6a, 0x3c, 0x90, 0xcc, 0x64, + 0x0f, 0xa2, 0x54, 0x9f, 0x4b, 0xb8, 0xa2, 0x09, 0xef, 0xc1, 0x98, 0xa5, 0xf4, 0x32, 0xe6, 0x37, 0xab, 0xef, 0xf5, + 0xda, 0xde, 0x78, 0xcc, 0x46, 0x63, 0xeb, 0xde, 0x15, 0x25, 0xc5, 0x26, 0xdc, 0x3b, 0x41, 0xfe, 0x2f, 0xff, 0xec, + 0xfb, 0xff, 0xf2, 0xcf, 0x9f, 0x6c, 0x0a, 0xc3, 0xe7, 0x57, 0x58, 0x94, 0xc3, 0x6e, 0x3f, 0x5d, 0x9b, 0x67, 0xaa, + 0xe2, 0x7c, 0x73, 0x9b, 0xb5, 0x4d, 0x80, 0xfa, 0xb5, 0x2d, 0x58, 0x2b, 0x54, 0xa7, 0xcf, 0xf9, 0x2d, 0x80, 0xc1, + 0xba, 0x3e, 0x09, 0x19, 0x34, 0xfa, 0x5d, 0xa0, 0x5d, 0xa1, 0xe0, 0x41, 0x3b, 0xf2, 0xdb, 0x31, 0xfc, 0xa9, 0x35, + 0xfc, 0x4e, 0xf0, 0xb5, 0x7f, 0x62, 0x70, 0x75, 0x55, 0x24, 0xd8, 0xd9, 0x5d, 0xe1, 0x02, 0x7f, 0x77, 0xad, 0x44, + 0x2b, 0x1e, 0x41, 0x03, 0x75, 0xe4, 0xf5, 0x40, 0x32, 0xb8, 0x7a, 0x09, 0x6f, 0xed, 0x39, 0xbd, 0x4e, 0x8d, 0x83, + 0xf7, 0x1e, 0xe1, 0x00, 0x43, 0x54, 0x57, 0x25, 0x07, 0x5d, 0x93, 0x0c, 0x50, 0x0a, 0xe6, 0x06, 0x80, 0x89, 0x07, + 0x57, 0xda, 0xda, 0x3c, 0x57, 0x6e, 0x98, 0x60, 0x95, 0xb4, 0xb5, 0x7b, 0xa6, 0x82, 0x74, 0xec, 0xbc, 0x93, 0xf8, + 0x92, 0x8d, 0x69, 0x69, 0xdd, 0x4b, 0x57, 0x17, 0xd8, 0x11, 0x57, 0xb9, 0x0c, 0xd3, 0xff, 0x75, 0x5b, 0x24, 0xf1, + 0xef, 0x9f, 0x8e, 0x24, 0xf2, 0x07, 0x45, 0x12, 0xff, 0xfe, 0x87, 0x47, 0x12, 0xff, 0x6a, 0x47, 0x12, 0x61, 0x13, + 0x7f, 0x79, 0x50, 0xb4, 0xcf, 0x44, 0x62, 0xf8, 0x4d, 0x46, 0x9a, 0x5a, 0x8d, 0x8e, 0xf9, 0x08, 0x42, 0x7d, 0xff, + 0xf6, 0x91, 0xbb, 0x98, 0x8f, 0xec, 0xb8, 0x1d, 0xbc, 0xb5, 0x15, 0x02, 0x75, 0x6d, 0x13, 0x61, 0xd3, 0xb1, 0xb2, + 0x46, 0x71, 0x23, 0xa5, 0x7e, 0x68, 0xde, 0xa0, 0xe0, 0x06, 0xc5, 0x5b, 0x90, 0x1a, 0xb8, 0x65, 0xa2, 0x69, 0x81, + 0x0c, 0xc4, 0x15, 0x1d, 0x5b, 0x35, 0x73, 0xdd, 0xc2, 0x1e, 0xa1, 0x6d, 0xde, 0xf2, 0xa2, 0x6e, 0xdf, 0x2f, 0xdc, + 0x9f, 0x6f, 0x9b, 0x4f, 0x7a, 0xcd, 0xf6, 0x41, 0x73, 0xe2, 0x06, 0x2e, 0x88, 0x48, 0x59, 0xd0, 0x68, 0x1f, 0x1c, + 0x40, 0xc1, 0x8d, 0x55, 0xd0, 0x82, 0x02, 0x66, 0x15, 0x1c, 0x41, 0xc1, 0xc0, 0x2a, 0x38, 0x86, 0x82, 0xc8, 0x2a, + 0x78, 0x04, 0x05, 0x73, 0x37, 0xef, 0xb1, 0x02, 0xdc, 0x47, 0xa8, 0x8f, 0x95, 0xe5, 0x62, 0xca, 0x1e, 0xe1, 0x26, + 0x84, 0xf0, 0xc2, 0x91, 0xcc, 0x3c, 0x02, 0x87, 0x60, 0xc0, 0xf1, 0xcd, 0x98, 0x26, 0x01, 0x04, 0x51, 0x9f, 0x4a, + 0x19, 0xe3, 0x0b, 0xfe, 0x8e, 0x4d, 0xa8, 0xf9, 0x5e, 0x86, 0xc1, 0x83, 0xe3, 0xa2, 0x5e, 0xa3, 0x9f, 0xb7, 0x8b, + 0x9d, 0x53, 0xb1, 0x3f, 0x9d, 0x85, 0xa2, 0xf6, 0xb2, 0xac, 0x53, 0xd3, 0xd5, 0x8b, 0x3d, 0xdf, 0x12, 0x43, 0xb2, + 0x7c, 0x11, 0xc3, 0x98, 0xdf, 0xd4, 0x6f, 0xdd, 0xce, 0xe6, 0xb8, 0x12, 0x40, 0x54, 0xc4, 0x95, 0xe4, 0x9a, 0x8a, + 0xa7, 0x77, 0xe1, 0xa8, 0xf8, 0xfd, 0x92, 0x66, 0x59, 0x38, 0xd2, 0x2d, 0xb7, 0xc7, 0x91, 0x24, 0x88, 0x76, 0x0c, + 0xc9, 0x00, 0x01, 0xb1, 0x20, 0xd8, 0x2c, 0xb0, 0xe5, 0x75, 0x68, 0x08, 0xb0, 0x53, 0x8d, 0x2a, 0xc9, 0xe9, 0xab, + 0x45, 0x22, 0x1c, 0x95, 0x05, 0xa7, 0xd3, 0x94, 0xca, 0x52, 0x85, 0xe1, 0xfc, 0x74, 0x1f, 0x0a, 0x54, 0xf5, 0x96, + 0xe8, 0x91, 0x71, 0x1c, 0x6c, 0x8f, 0x21, 0x39, 0x26, 0x7a, 0x64, 0xe7, 0xdb, 0x14, 0xc9, 0x36, 0xeb, 0x31, 0x8b, + 0x2f, 0x9b, 0x03, 0xf8, 0x4f, 0x47, 0x44, 0xbe, 0x1c, 0x0e, 0x87, 0xf7, 0x46, 0x93, 0xbe, 0x8c, 0x86, 0xb4, 0x45, + 0x8f, 0xda, 0x90, 0x8b, 0x51, 0xd7, 0x31, 0x88, 0x66, 0x2e, 0x71, 0xb7, 0x78, 0x58, 0x63, 0x08, 0x57, 0x88, 0xf1, + 0xe2, 0xe1, 0x91, 0xa5, 0x7c, 0x9a, 0xd2, 0xc5, 0x24, 0x4c, 0x47, 0x2c, 0x09, 0x1a, 0xb9, 0x3f, 0xd7, 0xa1, 0x98, + 0x2f, 0x4f, 0x4e, 0x4e, 0x72, 0x3f, 0x32, 0x4f, 0x8d, 0x28, 0xca, 0xfd, 0xc1, 0xa2, 0x58, 0x46, 0xa3, 0x31, 0x1c, + 0xe6, 0x3e, 0x33, 0x05, 0x07, 0xad, 0x41, 0x74, 0xd0, 0xca, 0xfd, 0x1b, 0xab, 0x45, 0xee, 0x53, 0xfd, 0x94, 0xd2, + 0xa8, 0x92, 0xd0, 0xf1, 0xa8, 0xd1, 0xc8, 0x7d, 0x45, 0x68, 0x0b, 0x30, 0xc7, 0xd4, 0xcf, 0x20, 0x9c, 0x09, 0x0e, + 0x2c, 0xb9, 0xcd, 0x85, 0xd7, 0xbb, 0xd4, 0x2f, 0xcb, 0x50, 0x1f, 0x96, 0xc8, 0x51, 0x1f, 0xff, 0x62, 0x07, 0x4d, + 0x80, 0x98, 0x65, 0xb0, 0x84, 0x9b, 0x98, 0x4a, 0xa5, 0x1a, 0x28, 0x4b, 0x56, 0xff, 0x42, 0x78, 0x19, 0x4b, 0x01, + 0xfe, 0x03, 0x2d, 0xd5, 0x5b, 0xdd, 0x04, 0xdd, 0xc2, 0xf5, 0x29, 0xfd, 0x24, 0xd7, 0xbf, 0x7b, 0x08, 0xd3, 0xa7, + 0xf4, 0x8f, 0x66, 0xfa, 0xfa, 0xd5, 0xa7, 0x8a, 0xe9, 0x2b, 0xb6, 0x36, 0x11, 0xc4, 0x1d, 0x8c, 0xe9, 0xe0, 0xe3, + 0x35, 0xbf, 0xad, 0xc3, 0x91, 0x48, 0x5d, 0xc9, 0x4f, 0x77, 0x7f, 0x6b, 0xf2, 0x87, 0x19, 0xcc, 0xfa, 0x2e, 0x85, + 0x14, 0x9b, 0xaf, 0x13, 0xe2, 0xbe, 0x36, 0x36, 0x9d, 0x2a, 0x19, 0x0e, 0x89, 0xfb, 0x7a, 0x38, 0x74, 0xcd, 0x95, + 0xbf, 0x50, 0x50, 0xd9, 0xea, 0x55, 0xa5, 0x44, 0xb6, 0xfa, 0xfa, 0x6b, 0xbb, 0xcc, 0x2e, 0xd0, 0x21, 0x17, 0x3b, + 0xbc, 0xa2, 0x6b, 0x22, 0x96, 0xc1, 0x51, 0x83, 0xcf, 0x65, 0x54, 0xdf, 0x39, 0x98, 0x56, 0x5e, 0x0f, 0x5d, 0x00, + 0xbc, 0xe1, 0x9d, 0xd6, 0xab, 0xf7, 0xdd, 0x47, 0xd4, 0xa4, 0xdf, 0x3d, 0xb9, 0xfb, 0x26, 0xf2, 0x26, 0x02, 0xe5, + 0x2c, 0x7b, 0x9d, 0xac, 0xdc, 0x65, 0x51, 0x30, 0x12, 0x62, 0x2f, 0x2b, 0x17, 0x7c, 0x34, 0x8a, 0xe1, 0x83, 0x25, + 0x8b, 0xca, 0x7b, 0x50, 0x55, 0xf7, 0x6e, 0x65, 0xbd, 0x81, 0xdd, 0x51, 0xbf, 0x35, 0x54, 0x7e, 0x3f, 0x49, 0xe5, + 0x40, 0xcf, 0xf5, 0x87, 0x74, 0xa4, 0x39, 0xb8, 0xd0, 0xfc, 0x7f, 0xa1, 0x32, 0x67, 0x05, 0x64, 0x8d, 0xa8, 0x81, + 0xa3, 0x3c, 0xd7, 0x77, 0x0e, 0x22, 0x96, 0x4d, 0xe1, 0xfd, 0x9c, 0xaa, 0x27, 0xfd, 0x14, 0x0b, 0xcf, 0x6e, 0xac, + 0xb8, 0x46, 0x65, 0xbb, 0x72, 0x13, 0xd8, 0x50, 0x8e, 0xe2, 0x89, 0xc8, 0x5d, 0xed, 0x6f, 0x36, 0x48, 0x74, 0x1d, + 0x85, 0x4f, 0x15, 0x71, 0xb1, 0x56, 0x08, 0x4e, 0xdf, 0x62, 0x43, 0x4c, 0x95, 0x29, 0xc8, 0xed, 0xb8, 0x9d, 0xac, + 0x51, 0xd8, 0x92, 0x51, 0x82, 0x6c, 0x1a, 0x26, 0x8a, 0x8d, 0x12, 0x57, 0xf1, 0x83, 0xdd, 0x45, 0xb9, 0xf3, 0xb9, + 0x6b, 0xc0, 0x56, 0xc4, 0xdb, 0x39, 0xdd, 0x87, 0x0e, 0x1d, 0xa7, 0x02, 0x7a, 0xb2, 0x16, 0x5c, 0xf8, 0x44, 0x98, + 0xff, 0xca, 0xcf, 0x6e, 0xb0, 0x9f, 0xdd, 0x38, 0x7f, 0x5e, 0xd4, 0x6f, 0xe8, 0xf5, 0x47, 0x26, 0xea, 0x22, 0x9c, + 0xd6, 0x41, 0xe1, 0x97, 0x4e, 0x41, 0xcd, 0x9e, 0x65, 0xb2, 0x9a, 0xba, 0xb1, 0xdf, 0x9e, 0x65, 0x90, 0x0d, 0x20, + 0xd5, 0xd6, 0x20, 0xe1, 0x09, 0x6d, 0x57, 0x93, 0x12, 0xed, 0xe0, 0xb2, 0xc1, 0x56, 0x7f, 0xc1, 0x21, 0x7b, 0x40, + 0xdc, 0x05, 0x0d, 0xcd, 0xd6, 0x1b, 0x26, 0x72, 0xdc, 0xd8, 0xd8, 0x3e, 0xd0, 0xc8, 0xad, 0x49, 0xe9, 0x95, 0xae, + 0x47, 0xd0, 0xb7, 0x45, 0xc0, 0x3f, 0x95, 0xa2, 0x07, 0xae, 0x44, 0xf3, 0xbf, 0x95, 0xdb, 0xb8, 0x5a, 0x2c, 0x53, + 0xf4, 0x1e, 0x02, 0x59, 0x10, 0x0e, 0x05, 0x4d, 0xf1, 0x43, 0x5a, 0x5e, 0xcb, 0xdb, 0x34, 0x0b, 0x10, 0x33, 0x41, + 0xf3, 0x64, 0x7a, 0xfb, 0xf0, 0xe1, 0xef, 0x5f, 0x7e, 0xae, 0x71, 0x64, 0xde, 0x2e, 0xe3, 0xba, 0x6d, 0x38, 0x08, + 0x71, 0x78, 0x17, 0xb0, 0x44, 0xca, 0xbc, 0x6b, 0xf0, 0x07, 0xb6, 0xa7, 0x5c, 0xe7, 0x9a, 0xa6, 0x34, 0x96, 0x9f, + 0x92, 0xd3, 0x5b, 0x71, 0x70, 0x3c, 0xbd, 0x35, 0xbb, 0xd1, 0x5c, 0xc9, 0x21, 0xfd, 0x43, 0x53, 0x45, 0xb7, 0xe7, + 0xa6, 0x56, 0xd3, 0x1d, 0x8f, 0xa6, 0xb7, 0x6d, 0x25, 0x68, 0xeb, 0xa9, 0x82, 0xaa, 0x31, 0xbd, 0xb5, 0x93, 0x65, + 0xcb, 0x81, 0x1c, 0xff, 0x20, 0x73, 0x68, 0x98, 0xd1, 0x36, 0xbc, 0x3f, 0x9b, 0x0d, 0xc2, 0x58, 0x0b, 0xf3, 0x09, + 0x8b, 0xa2, 0x98, 0xb6, 0x8d, 0xbc, 0x76, 0x9a, 0xc7, 0x90, 0x6b, 0x6a, 0x6f, 0x59, 0x75, 0x57, 0x2c, 0xe4, 0x15, + 0x78, 0x0a, 0xaf, 0x33, 0x1e, 0xc3, 0xc7, 0x2b, 0x36, 0xa2, 0x53, 0x27, 0x61, 0x36, 0x4a, 0xe4, 0xc9, 0xdf, 0xd5, + 0xb5, 0x1c, 0x35, 0xfe, 0xd4, 0x96, 0x1b, 0xde, 0x68, 0x0b, 0x3e, 0x0d, 0xea, 0x07, 0xd5, 0x85, 0x40, 0x55, 0xb1, + 0x04, 0xbc, 0x61, 0x59, 0x18, 0xa4, 0x95, 0xe2, 0xd3, 0x8e, 0xdf, 0xd4, 0x65, 0x72, 0x00, 0x78, 0xd1, 0x73, 0x51, + 0x94, 0x57, 0x17, 0xf3, 0x6f, 0x73, 0x5a, 0x1e, 0x6f, 0x3e, 0x2d, 0x8f, 0xcd, 0x69, 0xb9, 0x9f, 0x62, 0xbf, 0x1c, + 0x36, 0xe1, 0xbf, 0x76, 0xb9, 0xa0, 0xa0, 0xe1, 0x1c, 0x4c, 0x6f, 0x1d, 0xd0, 0xd3, 0xea, 0xad, 0xe9, 0xad, 0x4a, + 0x15, 0x86, 0x98, 0x45, 0x03, 0x92, 0x67, 0x71, 0xc3, 0x81, 0x42, 0xf8, 0xbf, 0x51, 0xa9, 0x6a, 0x1e, 0x42, 0x1d, + 0xf4, 0x3a, 0x5a, 0xaf, 0x6b, 0xdd, 0x7f, 0x68, 0x83, 0x84, 0x0b, 0x2f, 0x30, 0xdc, 0x18, 0xf9, 0x22, 0xbc, 0xbe, + 0xa6, 0x51, 0x30, 0xe4, 0x83, 0x59, 0xf6, 0x4f, 0x1a, 0x7e, 0x8d, 0xc4, 0x7b, 0x8f, 0xf4, 0xca, 0x38, 0xa6, 0xab, + 0x4a, 0x5c, 0x36, 0x23, 0x2c, 0x8a, 0x7d, 0x0a, 0xb2, 0x41, 0x18, 0x53, 0xaf, 0xe5, 0x1f, 0x6e, 0x38, 0x04, 0xff, + 0x2e, 0x7b, 0xb3, 0x71, 0x31, 0xbf, 0x17, 0x19, 0xf7, 0x22, 0xe1, 0xb3, 0x70, 0x60, 0xef, 0x61, 0xe3, 0x64, 0x33, + 0xb8, 0x3d, 0x33, 0x53, 0xdf, 0x08, 0x05, 0x2d, 0x77, 0x22, 0x3a, 0x0c, 0x67, 0xb1, 0xb8, 0x7f, 0xd4, 0x6d, 0x94, + 0xb1, 0x36, 0xea, 0x3d, 0x0c, 0xbd, 0x6c, 0xfb, 0x40, 0x2e, 0xfd, 0xe5, 0xe3, 0x43, 0xf8, 0x4f, 0xe5, 0x3d, 0xdd, + 0x95, 0xba, 0xba, 0xb2, 0x55, 0x41, 0x57, 0xdf, 0xad, 0x28, 0xe3, 0x4a, 0x84, 0x4b, 0x7d, 0xfc, 0xa1, 0xad, 0x41, + 0xab, 0x7c, 0x50, 0x73, 0xad, 0x65, 0x7d, 0x56, 0xeb, 0xcf, 0x1b, 0xfc, 0x81, 0x6d, 0x07, 0x4a, 0x73, 0xad, 0xb6, + 0xd5, 0xdf, 0xd2, 0x5b, 0x6b, 0x6c, 0x30, 0x2e, 0xdb, 0xef, 0x92, 0xbb, 0xc2, 0x44, 0x51, 0x51, 0x48, 0xb0, 0x52, + 0x76, 0x95, 0x95, 0xc2, 0x28, 0xb9, 0x3a, 0xed, 0xde, 0x4e, 0x62, 0x67, 0xae, 0x6e, 0xfd, 0x11, 0xb7, 0xe9, 0x37, + 0x5c, 0x47, 0xc6, 0xbf, 0xe1, 0xed, 0xe3, 0xae, 0xfc, 0x46, 0xab, 0xdb, 0x05, 0x4d, 0x6b, 0x3e, 0x92, 0x9a, 0xdd, + 0x8b, 0xf0, 0x8e, 0xa6, 0x97, 0x2d, 0xd7, 0x01, 0xef, 0x4a, 0x5d, 0xa5, 0x0a, 0xc8, 0x32, 0xa7, 0xe5, 0x3a, 0xb7, + 0x93, 0x38, 0xc9, 0x88, 0x3b, 0x16, 0x62, 0x1a, 0xa8, 0x8f, 0xb8, 0xde, 0x1c, 0xf8, 0x3c, 0x1d, 0xed, 0xb7, 0x1a, + 0x8d, 0x06, 0xbc, 0xc9, 0xd4, 0x75, 0xe6, 0x8c, 0xde, 0x3c, 0xe1, 0xb7, 0xc4, 0x6d, 0x38, 0x0d, 0xa7, 0xd9, 0x3a, + 0x71, 0x9a, 0xad, 0x43, 0xff, 0xf8, 0xc4, 0xed, 0x7c, 0xe1, 0x38, 0xa7, 0x11, 0x1d, 0x66, 0xf0, 0xc3, 0x71, 0x4e, + 0xa5, 0xe2, 0xa5, 0x7e, 0x3b, 0x8e, 0x3f, 0x88, 0xb3, 0x7a, 0xd3, 0x59, 0xe8, 0x47, 0xc7, 0x81, 0xbb, 0x91, 0x81, + 0xf3, 0xe5, 0xb0, 0x35, 0x3c, 0x1c, 0x3e, 0x6e, 0xeb, 0xe2, 0xfc, 0x8b, 0x4a, 0x73, 0xac, 0xfe, 0xb6, 0xac, 0x6e, + 0x99, 0x48, 0xf9, 0x47, 0xaa, 0x73, 0xf1, 0x1c, 0x10, 0x3d, 0x1b, 0xbb, 0xb6, 0xd6, 0x67, 0x6a, 0x9e, 0x5c, 0x0f, + 0x86, 0xad, 0xb2, 0xb9, 0x84, 0x71, 0xbf, 0x00, 0xf2, 0x74, 0xdf, 0x80, 0x7e, 0x6a, 0xa3, 0xa9, 0x59, 0xdf, 0x84, + 0xa8, 0xa6, 0xab, 0xd7, 0x38, 0x32, 0xeb, 0x3b, 0x85, 0x54, 0x7c, 0xa3, 0xab, 0x4a, 0x08, 0x5c, 0x27, 0x22, 0xee, + 0xcb, 0x66, 0xeb, 0x04, 0x37, 0x9b, 0xc7, 0xfe, 0xf1, 0xc9, 0xa0, 0x81, 0x0f, 0xfd, 0xc3, 0xfa, 0x81, 0x7f, 0x8c, + 0x4f, 0xea, 0x27, 0xf8, 0xe4, 0xf9, 0xc9, 0xa0, 0x7e, 0xe8, 0x1f, 0xe2, 0x46, 0xfd, 0x04, 0x0a, 0xeb, 0x27, 0xf5, + 0x93, 0x79, 0xfd, 0xf0, 0x64, 0xd0, 0x90, 0xa5, 0x2d, 0xff, 0xe8, 0xa8, 0xde, 0x6c, 0xf8, 0x47, 0x47, 0xf8, 0xc8, + 0x3f, 0x3e, 0xae, 0x37, 0x0f, 0xfc, 0xe3, 0xe3, 0x17, 0x47, 0x27, 0xfe, 0x01, 0xd4, 0x1d, 0x1c, 0x0c, 0x0e, 0xfc, + 0x66, 0xb3, 0x0e, 0xff, 0xe0, 0x13, 0xbf, 0xa5, 0x7e, 0x34, 0x9b, 0xfe, 0x41, 0x13, 0x37, 0xe2, 0xa3, 0x96, 0x7f, + 0xfc, 0x18, 0xcb, 0x7f, 0x65, 0x33, 0x2c, 0xff, 0x81, 0x61, 0xf0, 0x63, 0xbf, 0x75, 0xac, 0x7e, 0xc9, 0x01, 0xe7, + 0x87, 0x27, 0x3f, 0xb9, 0xfb, 0x5b, 0xd7, 0xd0, 0x54, 0x6b, 0x38, 0x39, 0xf2, 0x0f, 0x0e, 0xf0, 0x61, 0xd3, 0x3f, + 0x39, 0x18, 0xd7, 0x0f, 0x5b, 0xfe, 0xf1, 0xa3, 0x41, 0xbd, 0xe9, 0x3f, 0x7a, 0x84, 0x1b, 0xf5, 0x03, 0xbf, 0x85, + 0x9b, 0xfe, 0xe1, 0x81, 0xfc, 0x71, 0xe0, 0xb7, 0xe6, 0x8f, 0x1e, 0xfb, 0xc7, 0x47, 0xe3, 0x63, 0xff, 0xf0, 0xfb, + 0xc3, 0x13, 0xbf, 0x75, 0x30, 0x3e, 0x38, 0xf6, 0x5b, 0x8f, 0xe6, 0xc7, 0xfe, 0xe1, 0xb8, 0xde, 0x3a, 0xbe, 0xb7, + 0x67, 0xb3, 0xe5, 0x03, 0x8e, 0x64, 0x35, 0x54, 0x60, 0x5d, 0x01, 0xff, 0x8f, 0x65, 0xdf, 0x7f, 0xc7, 0x61, 0xb2, + 0xf5, 0xae, 0x8f, 0xfd, 0x93, 0x47, 0x03, 0xd5, 0x1c, 0x0a, 0xea, 0xa6, 0x05, 0x74, 0x99, 0xd7, 0xd5, 0xb4, 0x72, + 0xb8, 0xba, 0x19, 0xc8, 0xfc, 0xaf, 0x27, 0x9b, 0xd7, 0x61, 0x62, 0x35, 0xef, 0x7f, 0xe8, 0x38, 0xc5, 0x96, 0x9f, + 0xee, 0x8f, 0x14, 0xe9, 0x8f, 0x3a, 0x5f, 0xa8, 0xd7, 0x14, 0x7f, 0x71, 0x85, 0xb3, 0x6d, 0x8e, 0x8f, 0xf4, 0xd3, + 0x8e, 0x8f, 0x84, 0x3e, 0xc4, 0xf3, 0x91, 0xfe, 0xe1, 0x9e, 0x8f, 0x8c, 0xae, 0xb8, 0xbb, 0xef, 0xc4, 0x9a, 0x83, + 0x63, 0xd5, 0x2a, 0x7e, 0x2e, 0xbc, 0x1e, 0x83, 0xef, 0x61, 0xe5, 0xed, 0x3b, 0x78, 0x15, 0xba, 0xed, 0x07, 0xe2, + 0xc0, 0x62, 0xef, 0x84, 0xe2, 0xb1, 0x7c, 0x1b, 0x42, 0xe2, 0x4f, 0x23, 0xe4, 0xfb, 0x87, 0xe0, 0x23, 0xfe, 0xc3, + 0xf1, 0xc1, 0x6d, 0x7c, 0x54, 0x3c, 0xf0, 0xd2, 0xd3, 0x20, 0x3d, 0x05, 0x17, 0xf2, 0xd9, 0x83, 0xbb, 0x40, 0x35, + 0x77, 0x9f, 0x42, 0x51, 0xe6, 0xaa, 0x88, 0xcf, 0xab, 0xcf, 0x09, 0x16, 0xa8, 0x8b, 0x7f, 0xc4, 0xd5, 0x6e, 0x99, + 0xa9, 0x94, 0x3a, 0xfa, 0xa1, 0x10, 0x4a, 0x2d, 0xbf, 0xe1, 0x37, 0x0a, 0x97, 0x0e, 0x5c, 0xf6, 0x24, 0x0b, 0x2e, + 0x42, 0xf8, 0xec, 0x6a, 0xcc, 0x47, 0xf2, 0x03, 0xad, 0xf0, 0x5a, 0x7c, 0xf9, 0xa9, 0x5c, 0xf5, 0x45, 0x82, 0xc0, + 0x75, 0xf5, 0x2b, 0x22, 0xe0, 0x32, 0xe1, 0x77, 0x70, 0xe1, 0xd2, 0xc4, 0x12, 0x26, 0xe0, 0xed, 0x78, 0x49, 0x23, + 0x16, 0x7a, 0xae, 0x37, 0x4d, 0xe9, 0x90, 0xa6, 0x59, 0xbd, 0x72, 0x0b, 0x51, 0x5e, 0x40, 0x44, 0xae, 0xf9, 0xc0, + 0x67, 0x0a, 0xaf, 0x79, 0x26, 0x3d, 0xed, 0x6f, 0x74, 0xb5, 0x01, 0xe6, 0xe6, 0xd8, 0x94, 0xa4, 0x20, 0x6b, 0x4b, + 0xa5, 0xcd, 0x55, 0x5a, 0x5b, 0xd3, 0x6f, 0x1d, 0x21, 0x47, 0x16, 0xc3, 0xeb, 0x73, 0x7f, 0xf4, 0xea, 0x07, 0x8d, + 0x3f, 0x21, 0xab, 0x5b, 0x31, 0x50, 0x5f, 0xbb, 0xdb, 0xd2, 0xf2, 0xc3, 0xc8, 0xd5, 0x2b, 0xa2, 0xae, 0xa2, 0x88, + 0x2f, 0xd5, 0xda, 0xe1, 0x45, 0xbc, 0x3a, 0xb2, 0xab, 0x5e, 0x74, 0x30, 0x64, 0x23, 0xcf, 0xfe, 0xec, 0xad, 0x7a, + 0x3d, 0xaf, 0xfc, 0x5a, 0x36, 0xca, 0xcb, 0x26, 0x29, 0x5a, 0xc8, 0x28, 0x09, 0x4b, 0x9c, 0x74, 0xb9, 0xf4, 0x52, + 0x70, 0x91, 0x13, 0x0b, 0xa7, 0xf0, 0x8c, 0x2a, 0x48, 0x4e, 0x71, 0x01, 0x90, 0x44, 0x30, 0x49, 0xd5, 0xdf, 0xb2, + 0xd8, 0xfc, 0xd0, 0x8e, 0x2f, 0x3f, 0x0e, 0x93, 0x11, 0x50, 0x61, 0x98, 0x8c, 0xd6, 0xdc, 0x6a, 0x2a, 0xd0, 0xb3, + 0x52, 0x5a, 0x0e, 0x55, 0xba, 0xcf, 0xb2, 0x27, 0x77, 0xef, 0xf4, 0x7b, 0xbc, 0x5c, 0xf0, 0x4e, 0xcb, 0xa8, 0x44, + 0xf9, 0xce, 0xe1, 0x1a, 0xf9, 0x4a, 0x7d, 0x48, 0x5e, 0xca, 0x54, 0xd0, 0x27, 0xe0, 0xf2, 0xa7, 0xa3, 0xad, 0x51, + 0xe2, 0x4a, 0xe9, 0x4e, 0x22, 0x3a, 0x67, 0x03, 0x2d, 0xea, 0xb1, 0xa3, 0x2f, 0xc0, 0xd7, 0xe5, 0xd6, 0x90, 0x26, + 0x56, 0xfe, 0x98, 0x41, 0x28, 0x33, 0xd1, 0x49, 0xc2, 0xdd, 0xce, 0x57, 0xc5, 0x57, 0x3c, 0xb7, 0x6d, 0x02, 0x7c, + 0xdd, 0xbe, 0x97, 0xd2, 0xf8, 0x9f, 0xc8, 0x57, 0xf0, 0x7d, 0xfb, 0xaf, 0xfa, 0xf0, 0x69, 0x75, 0x5f, 0x7e, 0xe5, + 0xfe, 0xab, 0xf2, 0x33, 0xf7, 0xc0, 0x08, 0x6b, 0xb7, 0x93, 0x18, 0x4b, 0x8d, 0xe9, 0x01, 0x0a, 0x91, 0x02, 0xd7, + 0x6d, 0x1d, 0xb9, 0x8e, 0xb2, 0x89, 0xe5, 0xef, 0x8e, 0x12, 0xa7, 0x52, 0x09, 0x70, 0x9a, 0x2d, 0xff, 0x68, 0xdc, + 0xf2, 0x1f, 0xcf, 0x1f, 0xf9, 0x27, 0xe3, 0xe6, 0xa3, 0x79, 0x1d, 0xfe, 0xb6, 0xfc, 0xc7, 0x71, 0xbd, 0xe5, 0x3f, + 0x86, 0xff, 0xbf, 0x3f, 0xf4, 0x8f, 0xc6, 0xf5, 0xa6, 0x7f, 0x32, 0x3f, 0xf0, 0x0f, 0x5e, 0x34, 0x5b, 0xfe, 0x81, + 0xd3, 0x74, 0x54, 0x3f, 0x60, 0xd7, 0x8a, 0x3b, 0x7f, 0xb5, 0x72, 0x20, 0x36, 0x04, 0xd1, 0x54, 0xae, 0xa5, 0x8b, + 0xbd, 0xe2, 0x5b, 0x81, 0xfa, 0x7c, 0x6a, 0x67, 0xdd, 0xd3, 0x30, 0x85, 0x0f, 0xb6, 0x54, 0xcf, 0x6e, 0xa5, 0x0e, + 0x57, 0xf8, 0xc5, 0x86, 0x29, 0xe0, 0x84, 0xbb, 0xd8, 0xbe, 0x41, 0x0e, 0xd7, 0xaf, 0xe5, 0xeb, 0xad, 0xcd, 0x5b, + 0xfe, 0xb6, 0x93, 0xb6, 0x6a, 0x68, 0xde, 0x24, 0x28, 0x99, 0x05, 0x93, 0x9f, 0x12, 0x90, 0x93, 0x7c, 0x13, 0xe5, + 0xab, 0xf3, 0x43, 0xca, 0x67, 0xca, 0xad, 0x4b, 0xf4, 0xb4, 0xbc, 0xa8, 0x10, 0x31, 0x78, 0xed, 0x41, 0x9e, 0x1b, + 0xd0, 0x2b, 0x6e, 0xda, 0x12, 0x4b, 0x92, 0x5f, 0xd0, 0xac, 0xeb, 0x42, 0x91, 0x1b, 0xb8, 0xd2, 0xc5, 0xe7, 0x16, + 0x1f, 0xad, 0x29, 0x08, 0xbb, 0x2c, 0xc0, 0xf2, 0xb2, 0x11, 0x9c, 0x5a, 0xc0, 0x8f, 0x8b, 0xf6, 0xf6, 0xb6, 0x9e, + 0x17, 0xa9, 0x40, 0xc2, 0x5a, 0xcb, 0x8f, 0x5d, 0xd8, 0xac, 0xc8, 0xb5, 0x11, 0x5d, 0x8c, 0x2b, 0x51, 0x88, 0x34, + 0x9e, 0xae, 0x69, 0x28, 0xfc, 0x30, 0x51, 0xc9, 0x23, 0x16, 0xc3, 0xc2, 0x4d, 0x7a, 0x80, 0x72, 0x2e, 0x42, 0xeb, + 0x6b, 0xb6, 0xfa, 0x9c, 0x73, 0x11, 0x9a, 0x2b, 0xa1, 0x89, 0xa8, 0xdc, 0x99, 0x18, 0xb7, 0x3a, 0xaf, 0xdf, 0x9d, + 0x39, 0xea, 0x78, 0x9e, 0xee, 0x8f, 0x5b, 0x9d, 0x53, 0xe9, 0x33, 0x51, 0x17, 0xca, 0x88, 0xba, 0x50, 0xe6, 0xe8, + 0xcb, 0x85, 0x10, 0x49, 0xcb, 0xf7, 0xd5, 0xb2, 0xa5, 0xcd, 0xa0, 0xbc, 0xbd, 0x93, 0x59, 0x2c, 0x18, 0xbc, 0xaa, + 0x79, 0x1f, 0xba, 0xd6, 0x61, 0xc3, 0x8a, 0xfc, 0x63, 0xad, 0x1d, 0x5e, 0x8b, 0xc4, 0xf8, 0x86, 0x87, 0x2c, 0xa6, + 0x26, 0xe3, 0x58, 0x0f, 0x55, 0x64, 0xc8, 0xaf, 0xb7, 0xce, 0x66, 0xd7, 0x13, 0x26, 0x5c, 0x93, 0xc7, 0xff, 0x5e, + 0x77, 0x38, 0x95, 0x53, 0x75, 0xae, 0x72, 0xed, 0xbc, 0x36, 0x9f, 0xa5, 0xa9, 0x6e, 0xa9, 0x5e, 0xbd, 0x96, 0x10, + 0x70, 0x33, 0x6c, 0x7c, 0xd0, 0x29, 0xdc, 0xc5, 0x76, 0x5d, 0x7e, 0xba, 0x3f, 0x3e, 0xe8, 0x5c, 0x05, 0x53, 0x3d, + 0xde, 0x0b, 0x3e, 0xda, 0x3c, 0x56, 0xcc, 0x47, 0x5d, 0x79, 0x05, 0x42, 0xdd, 0xb5, 0x35, 0xca, 0x2f, 0x8f, 0xdd, + 0xce, 0xa9, 0x56, 0x06, 0x1c, 0x19, 0x0e, 0x77, 0x8f, 0x1a, 0xe6, 0x56, 0x45, 0xcc, 0x47, 0x70, 0x20, 0x55, 0x17, + 0x6b, 0x92, 0x8a, 0xc7, 0x7d, 0xdc, 0xec, 0x9c, 0x86, 0x8e, 0xe4, 0x2d, 0x92, 0x79, 0x64, 0xc1, 0x3e, 0x74, 0x1e, + 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xf5, 0x70, 0xca, 0x4a, 0xf7, 0x36, 0x28, 0x1d, 0xc5, 0x94, 0xbc, + 0x9c, 0x09, 0x7e, 0x86, 0x2b, 0x8b, 0x94, 0x2c, 0x3c, 0xd7, 0xbe, 0x73, 0xb0, 0x55, 0x80, 0x84, 0x5c, 0x47, 0x71, + 0x78, 0xe3, 0x63, 0xd7, 0xb2, 0x37, 0x77, 0x3b, 0xff, 0xfa, 0x3f, 0xfe, 0x97, 0x76, 0x9b, 0x9f, 0xee, 0x8f, 0x9b, + 0x66, 0xac, 0x15, 0x44, 0xe7, 0xa7, 0x70, 0x11, 0xb1, 0x8c, 0xf3, 0xd2, 0xdb, 0xfa, 0x28, 0x65, 0x51, 0x7d, 0x1c, + 0xc6, 0x43, 0xb7, 0xb3, 0x1d, 0x41, 0xf6, 0x0d, 0x24, 0x0d, 0x75, 0xb5, 0x08, 0x48, 0xf0, 0x37, 0xdd, 0xa1, 0x31, + 0x57, 0x31, 0xe4, 0x69, 0xb5, 0x6f, 0xd4, 0x94, 0x07, 0xaa, 0x72, 0xab, 0x26, 0xd5, 0x5f, 0xaf, 0xd2, 0x4c, 0x2d, + 0xad, 0x5c, 0xa6, 0xc9, 0x5d, 0xa7, 0x88, 0x53, 0xfd, 0xdf, 0xff, 0xf9, 0x5f, 0xfe, 0x9b, 0x79, 0x84, 0xf0, 0xd3, + 0xbf, 0xfe, 0xf7, 0xff, 0xfc, 0x7f, 0xfe, 0xf7, 0x7f, 0x85, 0x0b, 0x18, 0x3a, 0x44, 0x25, 0xf9, 0x84, 0x53, 0xc6, + 0xa7, 0x14, 0xc3, 0x70, 0x20, 0x47, 0x71, 0xc2, 0x32, 0xc1, 0x06, 0xd5, 0xeb, 0x35, 0x17, 0x72, 0x42, 0x79, 0xd8, + 0x34, 0x74, 0xf2, 0xd0, 0xe6, 0x25, 0x8d, 0x54, 0x50, 0x2e, 0x69, 0x31, 0x3f, 0xdd, 0x07, 0x7c, 0x3f, 0xec, 0x46, + 0xa2, 0x5f, 0x6c, 0xc7, 0xc2, 0x38, 0x65, 0xa1, 0x24, 0x2f, 0xcb, 0x1d, 0x08, 0x97, 0x2c, 0xe0, 0x31, 0x68, 0x59, + 0xc5, 0x72, 0xf7, 0x2a, 0x7d, 0xda, 0x1f, 0x66, 0x99, 0x60, 0x43, 0x40, 0xb9, 0x72, 0xfd, 0xca, 0xc8, 0x74, 0x1d, + 0xd4, 0xbf, 0xf8, 0x2e, 0x97, 0xa3, 0x28, 0xdb, 0xfa, 0xf0, 0xe4, 0x4f, 0xf9, 0x5f, 0x26, 0xa0, 0x64, 0x39, 0xde, + 0x24, 0xbc, 0xd5, 0x16, 0xf7, 0x71, 0xa3, 0x31, 0xbd, 0x45, 0x8b, 0x72, 0x06, 0xbc, 0x6d, 0x32, 0xe9, 0x2e, 0xb6, + 0x07, 0x94, 0x21, 0xed, 0xc2, 0x33, 0xdd, 0x70, 0xc0, 0xbd, 0xed, 0x34, 0xf2, 0xfc, 0xcf, 0x0b, 0xe9, 0x1c, 0x65, + 0xbf, 0x42, 0xe8, 0x59, 0xfb, 0x91, 0xaf, 0xb9, 0xbd, 0xb8, 0x85, 0xd5, 0xab, 0xa5, 0x7a, 0x8d, 0x9b, 0xeb, 0x17, + 0xed, 0xec, 0xd0, 0xb9, 0x1d, 0xf4, 0x3e, 0x84, 0x30, 0xf6, 0xb8, 0x89, 0xc7, 0xad, 0x45, 0x31, 0xbc, 0x10, 0x7c, + 0x62, 0xc7, 0xca, 0x69, 0x48, 0x07, 0x74, 0x68, 0xfc, 0xef, 0xba, 0x5e, 0xc5, 0xc1, 0xf3, 0xf1, 0xc1, 0x86, 0xb9, + 0x34, 0x48, 0x32, 0x46, 0xee, 0x34, 0xf2, 0x2f, 0xe1, 0x04, 0x2e, 0x86, 0x31, 0x0f, 0x45, 0x20, 0x09, 0xb6, 0x6d, + 0x47, 0xdc, 0x43, 0x60, 0x33, 0x7c, 0x61, 0xc1, 0xd3, 0x56, 0x4d, 0xc1, 0x13, 0x5e, 0xbd, 0x0e, 0x99, 0xfb, 0xb2, + 0xbb, 0x3d, 0x94, 0x72, 0xa4, 0x7d, 0xaf, 0x03, 0xd9, 0xaf, 0x2a, 0x1e, 0x28, 0x2d, 0x63, 0x5a, 0x68, 0x73, 0xbd, + 0x12, 0xd5, 0xaa, 0xf6, 0x27, 0xe1, 0xb9, 0x12, 0x4c, 0x77, 0xb5, 0x95, 0x2c, 0x84, 0x56, 0xaf, 0xc8, 0xf7, 0x85, + 0x15, 0x14, 0x4e, 0xa7, 0xb2, 0x21, 0x6a, 0x9f, 0xee, 0x2b, 0xe5, 0x15, 0xb8, 0x87, 0xcc, 0xd2, 0x50, 0x49, 0x11, + 0xba, 0x91, 0x3e, 0x0a, 0xea, 0x97, 0x4e, 0x97, 0x80, 0xcf, 0x9a, 0x75, 0xfe, 0x1f, 0xd6, 0xb2, 0x30, 0xa4, 0x67, + 0x88, 0x00, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index f649a9385e..bde1ce1fb5 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -3632,367 +3632,373 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, - 0xdc, 0xd3, 0x2f, 0xb7, 0x8d, 0x1b, 0xff, 0x7f, 0x9f, 0x82, 0x61, 0xd2, 0x1c, 0x99, 0x90, 0x34, 0x29, 0x59, 0xb6, - 0x23, 0x59, 0xf6, 0xdd, 0x25, 0xb9, 0xa9, 0x3b, 0xbe, 0xcb, 0x4d, 0xe2, 0x66, 0xda, 0xf3, 0x79, 0x2c, 0x4a, 0x82, - 0x24, 0x36, 0x14, 0xa9, 0x21, 0x29, 0x5b, 0x3e, 0x85, 0x7d, 0x96, 0x3e, 0x4b, 0x9f, 0xec, 0x37, 0xbb, 0x0b, 0x80, - 0xe0, 0x87, 0x3e, 0x7c, 0xc9, 0xb5, 0xbf, 0xb9, 0xba, 0x11, 0x41, 0x00, 0x04, 0x16, 0xc0, 0x62, 0xbf, 0xd7, 0x9f, - 0x72, 0xd9, 0x8b, 0x65, 0xb0, 0xfd, 0x3e, 0xf7, 0xf9, 0x33, 0x73, 0x70, 0x4b, 0x02, 0xc1, 0xe7, 0x64, 0xf1, 0x74, - 0x1a, 0x32, 0x43, 0x17, 0xc9, 0x43, 0x74, 0x4b, 0x7e, 0xe6, 0xfc, 0x89, 0x2b, 0x22, 0x76, 0x9a, 0xf9, 0xa6, 0xa3, - 0x25, 0x66, 0xcc, 0x64, 0x48, 0x3b, 0xa2, 0x5c, 0x51, 0x36, 0x7b, 0x87, 0xea, 0x0d, 0xbe, 0x2e, 0xc5, 0xd1, 0xb5, - 0xc7, 0xf1, 0x72, 0x18, 0x32, 0x1b, 0xb7, 0x3b, 0x7c, 0x72, 0x3d, 0x5c, 0x0e, 0x87, 0x90, 0xa5, 0xe5, 0x89, 0x6b, - 0x41, 0xdc, 0x99, 0x38, 0x45, 0x7e, 0x30, 0x37, 0x7b, 0x30, 0x29, 0x27, 0xab, 0x0e, 0x1f, 0x6c, 0x45, 0x40, 0xd4, - 0x43, 0x1f, 0xc8, 0x80, 0xf7, 0x6b, 0x38, 0xb5, 0x7d, 0xfd, 0x03, 0xec, 0xbe, 0x54, 0xef, 0x35, 0x1d, 0xfd, 0xfe, - 0xb5, 0xfe, 0x01, 0x61, 0x8c, 0xd9, 0x8b, 0x5f, 0xd3, 0xee, 0xd5, 0x2d, 0x9d, 0x94, 0xde, 0x4b, 0xcc, 0x63, 0x00, - 0x42, 0xdf, 0x37, 0x81, 0x3f, 0x8d, 0xe2, 0x34, 0x0b, 0x46, 0xfa, 0x4d, 0xef, 0x22, 0x30, 0xae, 0xe7, 0x99, 0x61, - 0xde, 0x58, 0xa3, 0x4c, 0x4d, 0x81, 0x22, 0x10, 0x26, 0x66, 0x40, 0xd9, 0x54, 0x49, 0x3d, 0x41, 0x5b, 0x2b, 0x0a, - 0xd4, 0x8c, 0x95, 0x46, 0x59, 0x1f, 0xea, 0x55, 0xf2, 0xa9, 0x60, 0x62, 0x28, 0x1d, 0x5b, 0x9a, 0x3d, 0xe2, 0x54, - 0x5e, 0x2f, 0xd7, 0x78, 0x95, 0x67, 0xc5, 0x6d, 0x89, 0x31, 0x80, 0x85, 0xe3, 0x0c, 0x3d, 0x3f, 0x51, 0x8d, 0x3e, - 0x4b, 0xf7, 0xee, 0xe0, 0xbb, 0x32, 0x5d, 0x00, 0xf7, 0x37, 0x58, 0x5c, 0x44, 0x71, 0xa6, 0x41, 0x60, 0x1b, 0xf8, - 0xe2, 0xa0, 0x6a, 0x24, 0xc6, 0x7b, 0x35, 0xcc, 0x9c, 0x23, 0x83, 0xef, 0xf1, 0xf2, 0x33, 0x78, 0x78, 0xb3, 0x52, - 0x04, 0x0b, 0x62, 0x16, 0x22, 0x58, 0xc0, 0x2c, 0xbe, 0x8c, 0xef, 0xab, 0x7a, 0x90, 0xd7, 0x83, 0xdd, 0x77, 0xaf, - 0x21, 0xc8, 0x64, 0x91, 0xd5, 0xcf, 0xe0, 0x89, 0x49, 0x05, 0xa1, 0x53, 0x39, 0x53, 0x68, 0xf8, 0x21, 0x68, 0x98, - 0x0c, 0xec, 0xc4, 0xf0, 0x2e, 0x00, 0x94, 0xc4, 0xaf, 0xe9, 0x41, 0x7e, 0x2b, 0x52, 0x27, 0x8b, 0xc4, 0xc5, 0xca, - 0xe5, 0x0c, 0xd8, 0x35, 0x5a, 0x2c, 0x33, 0x0c, 0xb5, 0x0b, 0x03, 0x60, 0xb9, 0xae, 0x61, 0xe8, 0x4e, 0xc0, 0xd2, - 0x05, 0x99, 0x98, 0xeb, 0x5a, 0x30, 0xae, 0x97, 0x71, 0xa2, 0x17, 0x90, 0x17, 0xe2, 0x77, 0x14, 0x54, 0xc1, 0x63, - 0xc2, 0xa7, 0x31, 0xb2, 0x8a, 0x38, 0xf5, 0xc6, 0x08, 0x15, 0x3a, 0x0d, 0x98, 0x61, 0x44, 0xfd, 0xf4, 0x8c, 0xb0, - 0x71, 0xb2, 0x10, 0x7e, 0xb3, 0x34, 0xcd, 0xc1, 0xb3, 0x75, 0x94, 0x9f, 0x3f, 0x5b, 0xa7, 0x79, 0xff, 0xd9, 0xda, - 0x97, 0xb6, 0x02, 0xfa, 0x95, 0x4e, 0x86, 0x02, 0x03, 0x04, 0xc3, 0x20, 0xbf, 0x2d, 0x3c, 0x77, 0x8a, 0xf9, 0xc2, - 0x2e, 0xa3, 0x72, 0x0d, 0x55, 0xf7, 0x7d, 0xae, 0xa0, 0x5f, 0x24, 0xc1, 0xdc, 0x4f, 0x1e, 0x48, 0x9f, 0x6f, 0xa9, - 0x4a, 0x7f, 0x53, 0xd7, 0x08, 0xd1, 0x13, 0x00, 0x08, 0xe7, 0xeb, 0xda, 0xb7, 0xb2, 0x8c, 0xf1, 0xd9, 0x4a, 0xa5, - 0x26, 0x7c, 0xeb, 0x56, 0x7f, 0xc9, 0x9c, 0x31, 0xcb, 0xfc, 0x20, 0xa4, 0x26, 0x3d, 0x91, 0xad, 0xbe, 0x36, 0xbd, - 0xb4, 0x3c, 0xbd, 0xa8, 0xbc, 0x7f, 0x70, 0x32, 0x74, 0x05, 0xd0, 0xb8, 0x71, 0x66, 0x98, 0xc5, 0xaa, 0x79, 0x45, - 0xe9, 0xdd, 0x7f, 0x75, 0x39, 0x18, 0x2c, 0x47, 0x04, 0xcb, 0xc1, 0xa2, 0x51, 0x3c, 0x66, 0x7f, 0x7b, 0x7f, 0x21, - 0xd3, 0x66, 0x81, 0x04, 0x68, 0xc0, 0x37, 0x66, 0x8a, 0xf4, 0x43, 0x82, 0xb4, 0x03, 0x25, 0xb8, 0xd2, 0xe4, 0x16, - 0x4a, 0x72, 0x5d, 0x3b, 0xa7, 0xb1, 0xb3, 0x31, 0x8d, 0xba, 0x1f, 0x63, 0xab, 0x24, 0x3f, 0x3d, 0xa0, 0xda, 0x74, - 0xdb, 0x51, 0x25, 0x00, 0x43, 0x02, 0x33, 0x2c, 0xa0, 0x00, 0x19, 0x3e, 0xfb, 0x5e, 0xc1, 0x50, 0x38, 0x73, 0x94, - 0xb3, 0x7b, 0xe7, 0x65, 0x52, 0x05, 0x5b, 0xe9, 0x67, 0xa7, 0x98, 0xb3, 0x0b, 0xee, 0x6b, 0x88, 0xf2, 0x71, 0x7a, - 0x40, 0x8f, 0x5a, 0xe5, 0x44, 0x14, 0x9d, 0x08, 0xd6, 0xae, 0xcb, 0x3b, 0x78, 0xd4, 0x51, 0x81, 0x14, 0xf1, 0x50, - 0xea, 0xe7, 0xba, 0x36, 0xe7, 0xa4, 0x11, 0x0f, 0x27, 0x04, 0xb1, 0x06, 0x5c, 0x38, 0xbb, 0xba, 0x36, 0xf7, 0x57, - 0x38, 0x73, 0xf1, 0xc6, 0x5f, 0x19, 0x1e, 0x7f, 0x55, 0x9c, 0xb5, 0xb4, 0x7c, 0xd6, 0x46, 0x7c, 0x71, 0xc1, 0x91, - 0x40, 0x72, 0xd6, 0x33, 0x54, 0xd0, 0x36, 0x2c, 0xee, 0x4c, 0x2c, 0xee, 0x78, 0xc3, 0xe2, 0x8e, 0xb7, 0x2c, 0x6e, - 0xc8, 0x17, 0x52, 0x93, 0xa0, 0x4b, 0xd0, 0x39, 0x4c, 0x02, 0x8f, 0x13, 0x1a, 0x5d, 0x7e, 0xce, 0x10, 0x4e, 0x76, - 0x1a, 0x82, 0x71, 0xd4, 0x06, 0x58, 0x35, 0xc1, 0x45, 0x01, 0x44, 0x7d, 0xe2, 0xf2, 0xd4, 0x89, 0x79, 0x43, 0x0e, - 0x4e, 0x23, 0xac, 0xce, 0x17, 0x76, 0x29, 0xe5, 0x17, 0x37, 0x66, 0x1b, 0x66, 0x3a, 0xdb, 0x32, 0xd3, 0x51, 0xe9, - 0xe8, 0xf2, 0x69, 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0x0c, 0x46, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x1c, - 0xab, 0xec, 0xa8, 0x85, 0x9f, 0xa6, 0xf7, 0x71, 0x02, 0x1a, 0x17, 0xe8, 0xe6, 0x71, 0x5b, 0x6a, 0x1e, 0x44, 0x3c, - 0x98, 0xcb, 0xc6, 0xcd, 0x54, 0xbc, 0x57, 0xb7, 0x54, 0xab, 0xd3, 0xa1, 0x1a, 0x0b, 0x3f, 0xcb, 0x58, 0x82, 0x40, - 0xf7, 0x21, 0xea, 0xf7, 0xff, 0x93, 0x6d, 0xd6, 0x80, 0x43, 0x42, 0x05, 0xab, 0x23, 0x86, 0x5e, 0x00, 0x6d, 0x95, - 0x88, 0x8b, 0x58, 0x09, 0x0c, 0x97, 0x48, 0xc0, 0xff, 0x84, 0xc7, 0xd5, 0x48, 0x14, 0xd7, 0x25, 0xef, 0xc8, 0x74, - 0x16, 0xfe, 0xf8, 0x03, 0x28, 0xf6, 0x8c, 0x96, 0x05, 0x46, 0xba, 0x6a, 0x18, 0xb8, 0x84, 0x88, 0xbd, 0x51, 0x81, - 0x24, 0x11, 0x4b, 0x72, 0x13, 0x28, 0xf0, 0x9e, 0xf4, 0xed, 0xc9, 0xcd, 0xba, 0x95, 0x1f, 0x4c, 0x03, 0xb3, 0x86, - 0x35, 0x01, 0xb5, 0x85, 0xfd, 0x33, 0xc9, 0x73, 0x85, 0x96, 0x77, 0x64, 0x82, 0xe4, 0xf7, 0x1a, 0xf2, 0x99, 0xba, - 0x82, 0xa1, 0x1d, 0x24, 0x70, 0x6b, 0x5d, 0xbb, 0x37, 0xf9, 0xf3, 0x29, 0xfe, 0xf2, 0x6e, 0xf2, 0xe7, 0x43, 0xfc, - 0xd5, 0xba, 0xc1, 0xcc, 0x75, 0x0d, 0x8c, 0xbc, 0x32, 0x67, 0xfd, 0xac, 0xb4, 0x9f, 0xc8, 0xfe, 0xec, 0x11, 0xdb, - 0x86, 0x2f, 0xf0, 0xd3, 0x67, 0xeb, 0x14, 0x3c, 0x2e, 0xd5, 0x39, 0x44, 0x4e, 0x62, 0xe6, 0x8d, 0xe5, 0xd3, 0x0d, - 0xe5, 0x43, 0xf3, 0xbf, 0x7c, 0xf1, 0xe3, 0x2e, 0x89, 0x8b, 0x3b, 0xa5, 0x2c, 0x86, 0xb8, 0x1d, 0x06, 0x91, 0x9f, - 0x3c, 0xdc, 0x12, 0x7b, 0x61, 0x08, 0xda, 0x5d, 0x8a, 0x57, 0x88, 0xbc, 0x2c, 0xab, 0xbb, 0x32, 0x45, 0xc0, 0xfb, - 0xc0, 0x2f, 0xfa, 0xfe, 0xdf, 0x13, 0x85, 0x6c, 0x2b, 0x31, 0xa0, 0x7c, 0x41, 0x4a, 0x1f, 0xba, 0x7d, 0xb6, 0x36, - 0x58, 0xbd, 0x9b, 0xca, 0x6c, 0x2b, 0x74, 0x21, 0x2c, 0x0f, 0x32, 0xb3, 0xf3, 0x71, 0xd0, 0x45, 0x7d, 0xd6, 0x30, - 0x5e, 0xd9, 0xcf, 0xd6, 0xd9, 0xb9, 0x3e, 0xf7, 0x93, 0x4f, 0x6c, 0x6c, 0x8f, 0x82, 0x64, 0x14, 0x32, 0xbd, 0xab, - 0x0f, 0x43, 0x3f, 0xfa, 0xc4, 0x1f, 0xed, 0x78, 0x99, 0xa1, 0x86, 0x7a, 0x27, 0xef, 0x2b, 0x60, 0x42, 0x22, 0x3b, - 0x24, 0x56, 0x1b, 0xa0, 0xa0, 0xbd, 0x96, 0x02, 0xaf, 0x82, 0x50, 0x2c, 0x6a, 0x59, 0x60, 0x60, 0x09, 0x4a, 0x73, - 0xf0, 0x58, 0xb5, 0x74, 0x5c, 0x2f, 0xdd, 0x52, 0xa7, 0x4a, 0xc2, 0x4a, 0x99, 0x72, 0xf1, 0x16, 0x7b, 0xf8, 0xfd, - 0x9f, 0xa3, 0x64, 0xd8, 0xfb, 0x7f, 0x4e, 0xf6, 0xf2, 0x65, 0x33, 0x84, 0x52, 0x9b, 0x3c, 0x25, 0x1e, 0xf1, 0x71, - 0x4e, 0x60, 0x6e, 0xfe, 0xb4, 0xda, 0xd8, 0x4f, 0xd3, 0xe5, 0x9c, 0x8d, 0x49, 0x33, 0x78, 0x5e, 0x0c, 0xaa, 0xcc, - 0x59, 0xa8, 0x03, 0xfb, 0x75, 0xd9, 0x3a, 0x3e, 0x7c, 0x0d, 0x16, 0x0b, 0x40, 0x50, 0xc6, 0x93, 0x89, 0x5e, 0xf0, - 0xf8, 0x3b, 0x9a, 0x79, 0x87, 0xbf, 0x2e, 0x7f, 0x78, 0xeb, 0xfe, 0x20, 0x1b, 0x47, 0x40, 0x18, 0x0b, 0xf5, 0x2b, - 0xa7, 0x8b, 0x95, 0xf1, 0x8a, 0x19, 0x4d, 0xfc, 0x68, 0xf3, 0x74, 0xae, 0x4b, 0x5b, 0x7c, 0xc1, 0xd8, 0x18, 0x08, - 0x6e, 0xab, 0x56, 0x7a, 0x1b, 0xb2, 0x3b, 0x26, 0x55, 0xbb, 0xf5, 0x8f, 0x35, 0xb4, 0xc0, 0xd8, 0x73, 0x5c, 0x65, - 0xcc, 0xa9, 0x3a, 0x65, 0x4a, 0x03, 0x9c, 0x03, 0x9f, 0xb9, 0x7a, 0xc4, 0x2a, 0x47, 0x6a, 0x60, 0xe9, 0xca, 0x00, - 0x36, 0x8e, 0xec, 0x7c, 0x43, 0x79, 0x17, 0x13, 0x4f, 0x37, 0x8f, 0xcd, 0xf2, 0xcc, 0x2e, 0xc4, 0xea, 0xe6, 0x70, - 0x0a, 0xe1, 0xe4, 0x19, 0x85, 0x38, 0x64, 0x13, 0xc4, 0x9a, 0x84, 0x64, 0x3a, 0x49, 0x5f, 0x84, 0xb5, 0x23, 0x9a, - 0xfd, 0x0a, 0x39, 0x54, 0xe3, 0xda, 0x68, 0xe5, 0x99, 0x0f, 0x31, 0xa1, 0x6b, 0xc4, 0xd2, 0x74, 0x23, 0xc0, 0xe4, - 0xa2, 0x5b, 0x7a, 0x51, 0xbb, 0x0c, 0x8f, 0xa2, 0xdc, 0x72, 0x2d, 0x20, 0x09, 0x70, 0x82, 0xd5, 0x6f, 0xe1, 0xf5, - 0x72, 0x3b, 0xe7, 0xf6, 0x2a, 0xc9, 0x74, 0xa8, 0x73, 0x5b, 0x82, 0x4d, 0xef, 0xef, 0x75, 0x3e, 0xa8, 0xd2, 0x35, - 0xdd, 0x38, 0x34, 0xa3, 0x84, 0x7a, 0x6b, 0xe2, 0x22, 0xec, 0x40, 0x8c, 0xa9, 0x82, 0x5f, 0xd9, 0x64, 0xc2, 0x46, - 0x59, 0x6a, 0x0a, 0xe1, 0x91, 0x8c, 0x1e, 0x0b, 0x5e, 0x43, 0x4f, 0xfa, 0xfa, 0x4f, 0xe0, 0x43, 0x2f, 0x82, 0x2c, - 0xf1, 0x01, 0x09, 0x9e, 0xa9, 0x19, 0x4c, 0xd4, 0x63, 0x19, 0x44, 0xfc, 0x2b, 0x90, 0x1c, 0xbc, 0xa1, 0x1c, 0x87, - 0xc6, 0xef, 0x9f, 0x62, 0x5f, 0xc4, 0xd2, 0xaa, 0x65, 0x3b, 0x2a, 0xda, 0x76, 0x7c, 0xd7, 0xde, 0x0f, 0x1d, 0xcf, - 0xcd, 0x75, 0x0b, 0x7c, 0xb7, 0x3e, 0xed, 0x7b, 0xe8, 0xb1, 0x55, 0x1b, 0x5a, 0x2d, 0xa3, 0xc7, 0xb4, 0x6b, 0x79, - 0xaf, 0x3c, 0xdd, 0x22, 0x93, 0x39, 0x05, 0xb7, 0x8d, 0xe2, 0x3b, 0x96, 0x7c, 0xf1, 0x54, 0xca, 0x9d, 0xef, 0x37, - 0x9e, 0x23, 0xcf, 0x05, 0x24, 0x9c, 0xc5, 0x8b, 0x47, 0x4c, 0xa1, 0xad, 0x5b, 0xfa, 0x28, 0x8c, 0x53, 0xa6, 0xce, - 0x81, 0x84, 0x20, 0x5f, 0x38, 0x89, 0x9f, 0xdf, 0xbf, 0xfd, 0xf0, 0x41, 0xb7, 0x30, 0x13, 0x68, 0xaa, 0xf6, 0xce, - 0x37, 0xd4, 0x0e, 0xec, 0xdf, 0xb8, 0xef, 0xe8, 0x86, 0x21, 0xa6, 0xb6, 0xbc, 0xe7, 0xa8, 0xac, 0xb6, 0xe5, 0xf8, - 0xcd, 0xc3, 0xbf, 0x4c, 0x9c, 0xe8, 0x5e, 0xf3, 0x6a, 0xc0, 0x0d, 0xdb, 0xaf, 0xb7, 0x52, 0xc9, 0x3c, 0x88, 0x6e, - 0x1b, 0x4a, 0xfd, 0x55, 0x43, 0x29, 0xb0, 0x72, 0x35, 0x5c, 0xb5, 0x8c, 0xe7, 0x0a, 0x69, 0x00, 0x89, 0x9c, 0x77, - 0x81, 0x4b, 0xe1, 0xa7, 0xbe, 0x60, 0xd0, 0x3c, 0x92, 0x7b, 0x75, 0xd4, 0x0d, 0xc5, 0x9c, 0x09, 0x92, 0xb0, 0x1d, - 0x85, 0x60, 0xf0, 0xc7, 0x54, 0xad, 0x5c, 0x99, 0x6c, 0x94, 0xe6, 0xba, 0x4a, 0x27, 0x44, 0xde, 0xde, 0x66, 0x6c, - 0xbe, 0x60, 0x89, 0x9f, 0x2d, 0x13, 0x76, 0x1b, 0xc6, 0xf7, 0x4f, 0x0a, 0x73, 0xfa, 0x1d, 0x95, 0x67, 0xc1, 0x74, - 0x26, 0x6b, 0x9f, 0x1b, 0xac, 0x2f, 0x17, 0x70, 0xeb, 0x07, 0xf2, 0xff, 0xfc, 0xdb, 0x71, 0xfe, 0xf3, 0xef, 0x9d, - 0x55, 0xa1, 0xfb, 0x7c, 0x60, 0x65, 0xfd, 0x3d, 0xf6, 0x45, 0xf3, 0x97, 0xca, 0x30, 0x6f, 0xae, 0x53, 0x5b, 0x04, - 0x78, 0x5f, 0x5b, 0x82, 0x5a, 0x61, 0x79, 0xdf, 0x3c, 0x6a, 0x60, 0x30, 0xaf, 0x9d, 0x23, 0x83, 0x4a, 0x5f, 0x34, - 0xb4, 0x81, 0xd9, 0xdd, 0x6b, 0x45, 0x7e, 0x3f, 0x84, 0x77, 0xcd, 0xe1, 0x0b, 0x87, 0xcf, 0xe5, 0x92, 0xaf, 0x07, - 0x03, 0x99, 0x5b, 0x4e, 0x6d, 0x0a, 0x26, 0xfe, 0xe7, 0xb5, 0x12, 0x7e, 0x79, 0x76, 0x5d, 0x93, 0x7c, 0xef, 0xfb, - 0xaf, 0x07, 0x68, 0x8c, 0x76, 0x3a, 0x4c, 0x0a, 0x62, 0x65, 0x23, 0x6a, 0x23, 0x63, 0xf2, 0x5a, 0xa7, 0x35, 0xbc, - 0x06, 0xa5, 0x98, 0x70, 0x2c, 0x1f, 0x98, 0xd6, 0xeb, 0x01, 0x17, 0x2c, 0x71, 0xfb, 0xd7, 0x6e, 0x75, 0x6b, 0x73, - 0xb1, 0x6c, 0x09, 0xe8, 0x96, 0x46, 0xfa, 0x1f, 0xac, 0xcc, 0x0a, 0x39, 0x1e, 0x0a, 0xf8, 0x41, 0xa2, 0x30, 0xc8, - 0x31, 0xdf, 0xc9, 0xbb, 0x4d, 0x36, 0x62, 0x3f, 0xef, 0xb6, 0x11, 0xbb, 0xda, 0xcb, 0x46, 0xec, 0xe7, 0xaf, 0x6e, - 0x23, 0xf6, 0x4e, 0xb5, 0x11, 0x83, 0x45, 0x7c, 0xcb, 0xf6, 0x32, 0xdc, 0x12, 0x56, 0x1b, 0xf1, 0x7d, 0xda, 0xf7, - 0x38, 0x49, 0x9b, 0x8e, 0x66, 0x0c, 0x64, 0x04, 0x7c, 0x55, 0xc2, 0x78, 0x0a, 0x46, 0x5c, 0x7f, 0xbc, 0xb9, 0x55, - 0x18, 0x4f, 0x55, 0x63, 0xab, 0x88, 0x47, 0x7c, 0x2d, 0xa2, 0x38, 0x91, 0x81, 0x93, 0x6b, 0x89, 0x98, 0x4f, 0xf6, - 0xa1, 0xa9, 0x64, 0xb5, 0x96, 0xd6, 0x6b, 0x2d, 0x61, 0x02, 0xd5, 0x45, 0xeb, 0x29, 0xd9, 0xb0, 0xf5, 0x52, 0xc4, - 0xb6, 0x50, 0x7b, 0x90, 0x56, 0xc2, 0x14, 0x27, 0x62, 0xad, 0xff, 0xba, 0xf2, 0xbe, 0xbf, 0xf6, 0x7a, 0x6d, 0x0f, - 0x9c, 0xb3, 0x81, 0xc3, 0xc4, 0x02, 0xb7, 0xd7, 0x6e, 0x43, 0xc1, 0xbd, 0x52, 0xd0, 0x82, 0x82, 0x40, 0x29, 0xe8, - 0x40, 0xc1, 0x48, 0x29, 0x38, 0x82, 0x82, 0xb1, 0x52, 0x70, 0x0c, 0x05, 0x77, 0x7a, 0x7e, 0x1d, 0xc9, 0xe1, 0x1e, - 0x9b, 0x37, 0x16, 0x31, 0x15, 0xa2, 0xec, 0xd8, 0xf2, 0xc0, 0x6a, 0xca, 0x9f, 0x76, 0x63, 0x8b, 0xa4, 0x8b, 0xdd, - 0xc4, 0xba, 0x9f, 0x31, 0x0a, 0x14, 0xfd, 0x06, 0xef, 0x1c, 0x27, 0x8b, 0xc1, 0x6e, 0x5a, 0x04, 0x60, 0x10, 0x70, - 0xd0, 0x74, 0x13, 0x04, 0x46, 0x3d, 0xb9, 0x72, 0x22, 0x88, 0x85, 0xb2, 0x96, 0xc5, 0x3b, 0xfa, 0x9c, 0x2d, 0xb7, - 0x40, 0x61, 0x71, 0x62, 0xa8, 0x52, 0xc9, 0xaf, 0x61, 0x77, 0xf0, 0x86, 0x0d, 0x97, 0x53, 0xed, 0x32, 0x9e, 0xee, - 0x34, 0x21, 0x50, 0x5f, 0xc1, 0x28, 0x75, 0x52, 0xbf, 0xd8, 0x62, 0x5b, 0xf2, 0x6f, 0xd1, 0x63, 0x5e, 0xae, 0x9f, - 0xc1, 0xd8, 0xb4, 0x8c, 0x0c, 0x58, 0xe0, 0x3b, 0x00, 0x23, 0x45, 0x87, 0x7f, 0x09, 0x70, 0x56, 0x9e, 0xaf, 0x7c, - 0x65, 0x3c, 0x67, 0x3f, 0xb2, 0x34, 0xf5, 0xa7, 0xa2, 0x7e, 0x7d, 0x9c, 0x60, 0xb4, 0x23, 0xf9, 0x2f, 0x04, 0x20, - 0x48, 0xf2, 0x82, 0x9a, 0x6d, 0x46, 0x12, 0xdf, 0x6b, 0x60, 0xfd, 0x03, 0x1b, 0xaa, 0xb0, 0x53, 0x08, 0x1c, 0x58, - 0xc2, 0xb2, 0x45, 0x01, 0x1c, 0xfe, 0x3b, 0x16, 0x56, 0x0b, 0x33, 0x7f, 0x5a, 0x2d, 0xa2, 0x7d, 0x90, 0xab, 0x63, - 0x93, 0x0a, 0xfd, 0x52, 0xe1, 0x97, 0x68, 0xa8, 0xc3, 0x78, 0xfa, 0x87, 0xaa, 0xa7, 0xb7, 0x98, 0x15, 0x7c, 0x88, - 0xac, 0x20, 0x1b, 0x38, 0x08, 0x63, 0xcd, 0x01, 0x10, 0x76, 0xa3, 0x6c, 0x66, 0xa3, 0x6b, 0x99, 0xd1, 0x8a, 0x4c, - 0xcb, 0xc1, 0xb5, 0x5d, 0x57, 0x1d, 0x6a, 0xbb, 0xc9, 0x74, 0xe8, 0x1b, 0x5e, 0xeb, 0xd8, 0x12, 0x7f, 0x8e, 0xdb, - 0x31, 0x73, 0xec, 0x41, 0x1b, 0x07, 0x77, 0xeb, 0x49, 0x1c, 0x65, 0xf6, 0xc4, 0x9f, 0x07, 0xe1, 0x43, 0x77, 0x1e, - 0x47, 0x71, 0xba, 0xf0, 0x47, 0xac, 0x57, 0x30, 0xd4, 0x3d, 0x0c, 0xd5, 0xc0, 0xbd, 0x05, 0x3d, 0xa7, 0x95, 0xb0, - 0x39, 0xb5, 0x96, 0x91, 0x18, 0x26, 0x21, 0x5b, 0xe5, 0xfc, 0xf3, 0xa5, 0xca, 0x54, 0x15, 0xb7, 0x1c, 0xb5, 0x00, - 0x8a, 0x94, 0x87, 0x79, 0x80, 0xe0, 0x46, 0xbd, 0x85, 0x3f, 0xc6, 0xc8, 0x84, 0x4e, 0xab, 0x93, 0xb0, 0xb9, 0xe6, - 0x74, 0x36, 0x76, 0x9e, 0xc4, 0xf7, 0x67, 0x30, 0x5a, 0x6c, 0x6c, 0xa7, 0x2c, 0x9c, 0xe0, 0x1b, 0x1b, 0x3d, 0x4b, - 0x44, 0x3f, 0x36, 0x32, 0xe2, 0xd0, 0x1b, 0x9b, 0xf7, 0xe0, 0x75, 0xb7, 0xa5, 0xb9, 0xbd, 0x79, 0x10, 0xd9, 0x34, - 0x9d, 0x63, 0x77, 0xa1, 0xf4, 0xa5, 0xc2, 0xcf, 0x5c, 0x63, 0x75, 0x4f, 0x73, 0x7b, 0xc0, 0xac, 0x4d, 0xc2, 0xf8, - 0xbe, 0x3b, 0x0b, 0xc6, 0x63, 0x16, 0xf5, 0x70, 0xcc, 0xb2, 0x90, 0x85, 0x61, 0xb0, 0x48, 0x83, 0xb4, 0x37, 0xf7, - 0x57, 0xbc, 0xd7, 0xc3, 0x4d, 0xbd, 0xb6, 0x79, 0xaf, 0xed, 0xbd, 0x7b, 0x55, 0xba, 0x01, 0x2f, 0x16, 0xea, 0x87, - 0x0f, 0xad, 0xa3, 0xb9, 0x95, 0x79, 0xee, 0xdd, 0xeb, 0x22, 0x61, 0xeb, 0xb9, 0x9f, 0x4c, 0x83, 0xa8, 0xeb, 0xe6, - 0xce, 0xdd, 0x9a, 0x36, 0xc6, 0xd3, 0x93, 0x93, 0x93, 0xdc, 0x19, 0x8b, 0x27, 0x77, 0x3c, 0xce, 0x9d, 0x91, 0x78, - 0x9a, 0x4c, 0x5c, 0x77, 0x32, 0xc9, 0x9d, 0x40, 0x14, 0xb4, 0x5b, 0xa3, 0x71, 0xbb, 0x95, 0x3b, 0xf7, 0x4a, 0x8d, - 0xdc, 0x61, 0xfc, 0x29, 0x61, 0xe3, 0x1e, 0x6e, 0x24, 0x32, 0x2b, 0xed, 0x1e, 0xbb, 0x6e, 0x8e, 0x18, 0xe0, 0xba, - 0x84, 0x9b, 0x50, 0xd6, 0x73, 0xb3, 0xde, 0xbb, 0xa6, 0x56, 0x7c, 0x6e, 0x34, 0x6a, 0xac, 0x37, 0xf6, 0x93, 0x4f, - 0x37, 0x9a, 0x32, 0x0b, 0xdf, 0xa7, 0x6a, 0x6b, 0x01, 0x06, 0x7b, 0xd5, 0x85, 0x90, 0x5d, 0xbd, 0x61, 0x9c, 0xc0, - 0x99, 0x4d, 0xfc, 0x71, 0xb0, 0x4c, 0xbb, 0x5e, 0x6b, 0xb1, 0x12, 0x45, 0x7c, 0xaf, 0x17, 0x05, 0x78, 0xf6, 0xba, - 0x69, 0x1c, 0x06, 0x63, 0x51, 0xb4, 0xe9, 0x2c, 0x79, 0x2d, 0xb3, 0x87, 0x0e, 0xeb, 0x01, 0x86, 0x5d, 0xf0, 0xc3, - 0x50, 0x73, 0xda, 0xa9, 0xc6, 0xfc, 0x14, 0xe5, 0xcb, 0x9a, 0x9b, 0x12, 0x5c, 0xd0, 0x39, 0xdd, 0x3b, 0x5c, 0xac, - 0xe4, 0x9e, 0xf7, 0x8e, 0x16, 0xab, 0xfc, 0xdb, 0x39, 0x1b, 0x07, 0xbe, 0x66, 0x14, 0xbb, 0xc9, 0x73, 0x41, 0x06, - 0x6d, 0xae, 0x37, 0x6c, 0x53, 0x71, 0x2c, 0x20, 0xb4, 0xe1, 0x93, 0x60, 0xbe, 0x88, 0x93, 0xcc, 0x8f, 0xb2, 0x3c, - 0x1f, 0xdc, 0xe4, 0x79, 0xef, 0x2a, 0x30, 0xae, 0xff, 0x61, 0xd0, 0x3d, 0x4d, 0x3a, 0x9b, 0xdc, 0xbc, 0xb1, 0xde, - 0x32, 0xd5, 0x66, 0x04, 0xae, 0x31, 0xb4, 0x17, 0x51, 0x2b, 0xd3, 0x2d, 0x59, 0xaf, 0x4c, 0x40, 0x96, 0xd5, 0xc9, - 0x06, 0xa5, 0x5c, 0x05, 0x6f, 0x20, 0xa8, 0xf0, 0x96, 0xf5, 0xaf, 0x14, 0xfb, 0x13, 0x20, 0x56, 0xb0, 0x32, 0xf9, - 0x15, 0x3c, 0xdb, 0x44, 0x33, 0x7e, 0xb7, 0x9b, 0x66, 0xfc, 0x25, 0xdb, 0x87, 0x66, 0xfc, 0xee, 0xab, 0xd3, 0x8c, - 0xcf, 0xea, 0x7e, 0x05, 0x17, 0x71, 0x5f, 0x97, 0x1a, 0x06, 0xb8, 0x9a, 0x12, 0x8a, 0xd8, 0x73, 0xf1, 0xbb, 0xdd, - 0x00, 0x44, 0x6f, 0x94, 0x83, 0x8e, 0x6e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0xfa, 0x7f, 0x4f, 0xd4, 0xe7, 0xc9, 0xa4, - 0xff, 0x26, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0xbe, 0x28, 0x45, 0x57, 0xa0, 0x37, 0xc2, 0x0a, 0x13, 0xf3, 0x4f, 0x80, - 0x73, 0x36, 0x59, 0x1d, 0x8f, 0xa5, 0xf5, 0x59, 0xaf, 0x3c, 0x04, 0x43, 0x9a, 0x7c, 0x0a, 0x17, 0x9c, 0x9a, 0x28, - 0x71, 0xca, 0x32, 0xee, 0x33, 0xfb, 0xfd, 0xc3, 0xc5, 0xd8, 0xb8, 0x88, 0xcd, 0x3c, 0x48, 0xdf, 0x55, 0x1d, 0x60, - 0xb8, 0xee, 0xa7, 0xaf, 0x4e, 0x27, 0xe7, 0x16, 0x64, 0x6a, 0x82, 0x69, 0x78, 0x4d, 0xcd, 0xcf, 0x4b, 0x33, 0xed, - 0xaa, 0x0d, 0x79, 0xa2, 0xab, 0xda, 0x65, 0xcc, 0xbd, 0x0f, 0xd6, 0x9c, 0x02, 0xc4, 0xdc, 0x5d, 0xe8, 0x37, 0x3c, - 0xa6, 0xe6, 0xc1, 0x38, 0xcf, 0xcd, 0x9e, 0x00, 0x84, 0x72, 0xd1, 0xb2, 0x5d, 0x44, 0x5c, 0x7a, 0x2f, 0x6d, 0x1a, - 0xb8, 0x86, 0x90, 0xd4, 0x7f, 0x17, 0xa0, 0x50, 0xe7, 0xca, 0x42, 0x0e, 0x33, 0x5d, 0x23, 0xf0, 0x91, 0xa1, 0x85, - 0x32, 0x21, 0xd0, 0x00, 0x4b, 0xf8, 0x8b, 0x57, 0xa2, 0xa0, 0x6e, 0xc3, 0x49, 0xc0, 0x41, 0x8b, 0x00, 0xf0, 0xf2, - 0x17, 0x72, 0x6d, 0x42, 0x3b, 0xbc, 0x0e, 0x3e, 0xe4, 0xba, 0xa4, 0xfd, 0x70, 0xfb, 0x9d, 0x9d, 0x1e, 0x40, 0x83, - 0xb3, 0x8a, 0xe1, 0xc0, 0x0e, 0x0b, 0x45, 0x20, 0x25, 0xd2, 0x7b, 0xcb, 0x49, 0xef, 0xb5, 0x17, 0x6b, 0x11, 0x21, - 0x23, 0xf3, 0x17, 0x36, 0xb0, 0xf8, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x82, 0x71, 0xf4, 0x96, 0x29, 0xe0, 0x46, 0x64, - 0x54, 0x11, 0xff, 0xf4, 0x46, 0xcb, 0x24, 0x8d, 0x93, 0xee, 0x22, 0x0e, 0xa2, 0x8c, 0x25, 0x39, 0x82, 0xea, 0x1a, - 0xe1, 0x23, 0xc0, 0x73, 0xb3, 0x8e, 0x17, 0xfe, 0x28, 0xc8, 0x1e, 0xba, 0x2e, 0x27, 0x29, 0xdc, 0x1e, 0xa7, 0x0e, - 0xdc, 0xc6, 0xfa, 0x5d, 0x0e, 0xcd, 0x97, 0x48, 0xf8, 0x25, 0x75, 0x72, 0x46, 0xdd, 0xe6, 0x3d, 0xe5, 0x2d, 0xc5, - 0x08, 0x01, 0xf2, 0xc3, 0x4f, 0xec, 0x29, 0x60, 0x79, 0x58, 0x6a, 0x77, 0xcc, 0xa6, 0x16, 0x62, 0x6d, 0x90, 0xcb, - 0x8b, 0x3f, 0xa7, 0x63, 0x6a, 0x6e, 0x73, 0x31, 0x50, 0x3c, 0xe6, 0x3e, 0x23, 0xeb, 0xfa, 0x90, 0x51, 0xcb, 0xda, - 0xa7, 0xe6, 0x90, 0x4d, 0xe2, 0x84, 0x51, 0x3c, 0x59, 0xef, 0x64, 0xb1, 0xda, 0xbf, 0xfb, 0xed, 0xd3, 0x6f, 0xee, - 0x27, 0x8a, 0x33, 0x43, 0x74, 0x66, 0xee, 0xe8, 0xad, 0x7e, 0x9f, 0x01, 0x69, 0x48, 0x90, 0x1f, 0x51, 0xe8, 0xae, - 0xae, 0xae, 0xf7, 0x1a, 0xc3, 0x76, 0x2d, 0x62, 0x7e, 0xe7, 0x25, 0x2c, 0xf4, 0xb3, 0xe0, 0x4e, 0xd0, 0x8c, 0xed, - 0xa3, 0xc5, 0x4a, 0xac, 0x31, 0x5e, 0x78, 0x8f, 0x58, 0xa4, 0xca, 0x50, 0xc4, 0x22, 0x55, 0x8b, 0x71, 0x91, 0x7a, - 0xb5, 0xd9, 0x88, 0x48, 0x16, 0x95, 0x9b, 0xbe, 0xb3, 0x58, 0xa9, 0x57, 0x74, 0xd1, 0x4c, 0xde, 0xd4, 0xd5, 0x10, - 0x64, 0xf3, 0x60, 0x3c, 0x0e, 0x59, 0x5e, 0x5a, 0xe8, 0xf2, 0x5a, 0x2a, 0xc0, 0x91, 0x70, 0xf0, 0x87, 0x69, 0x1c, - 0x2e, 0x33, 0xd6, 0x0c, 0x2e, 0x02, 0x4e, 0xcb, 0x2d, 0x80, 0x83, 0xbf, 0xcb, 0x63, 0xed, 0x00, 0xb9, 0x0d, 0xdb, - 0xc4, 0xed, 0x41, 0xc4, 0x61, 0xbb, 0x5d, 0x1e, 0x3a, 0xbc, 0x92, 0x83, 0xb6, 0x1a, 0x26, 0x62, 0xc1, 0xb5, 0x44, - 0xd8, 0x5b, 0x73, 0x3c, 0x5e, 0x26, 0xa3, 0xae, 0xca, 0xa2, 0xbc, 0x3c, 0x99, 0x3f, 0xe6, 0x8c, 0xbd, 0x6a, 0x3e, - 0x63, 0xaf, 0xc4, 0x19, 0xdb, 0xbe, 0x33, 0x9f, 0x4e, 0x3c, 0xf8, 0xaf, 0x57, 0x4c, 0xa8, 0xeb, 0x6a, 0xed, 0xc5, - 0x4a, 0xf3, 0x16, 0x2b, 0xcd, 0x6e, 0x2d, 0x56, 0x1a, 0x76, 0x8d, 0xf6, 0x20, 0x96, 0xd3, 0x32, 0x2d, 0x57, 0x83, - 0x42, 0xf8, 0x73, 0x4b, 0xaf, 0xbc, 0x43, 0x78, 0x07, 0xad, 0x3a, 0xf5, 0x77, 0xad, 0xed, 0x47, 0x9d, 0xce, 0x92, - 0x40, 0xda, 0xa6, 0x93, 0xf9, 0xc3, 0x21, 0x1b, 0x77, 0x27, 0xf1, 0x68, 0x99, 0xfe, 0x8b, 0x8f, 0x9f, 0x03, 0x71, - 0x2b, 0x22, 0xa8, 0xf4, 0x23, 0x9a, 0x82, 0xa2, 0xe4, 0x8e, 0x89, 0x1e, 0xd6, 0x72, 0x9d, 0xba, 0x14, 0x1e, 0xb9, - 0xe5, 0x1c, 0x36, 0x6c, 0xf2, 0x66, 0x40, 0xff, 0x61, 0xab, 0xb4, 0x19, 0xc5, 0x7c, 0x01, 0x58, 0xb6, 0x82, 0xe3, - 0xf1, 0xd0, 0xe0, 0xab, 0xe9, 0x9e, 0x34, 0x0f, 0xf7, 0x5a, 0x7c, 0xe9, 0x46, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0x8e, - 0x29, 0xdb, 0x7b, 0xdd, 0xb4, 0x47, 0x6a, 0xbd, 0x6e, 0xb9, 0x10, 0x8a, 0xba, 0x7b, 0x62, 0xf9, 0xa7, 0xaf, 0x0e, - 0xe1, 0x3f, 0xa2, 0xea, 0x7f, 0xc9, 0x9a, 0x08, 0xf5, 0x8b, 0xb2, 0x25, 0x38, 0x91, 0x4a, 0x48, 0x88, 0xef, 0x5f, - 0x7f, 0x32, 0x79, 0x5c, 0x83, 0xbd, 0x6b, 0x93, 0x29, 0x55, 0xb5, 0xf6, 0xf7, 0x71, 0x0c, 0xa9, 0x3b, 0xeb, 0xd5, - 0x05, 0x78, 0xc8, 0xd8, 0x3d, 0xeb, 0x43, 0x23, 0xc1, 0x47, 0x90, 0x16, 0x5f, 0xc7, 0x36, 0xc4, 0x4a, 0xbc, 0xdd, - 0xc4, 0x4a, 0xbc, 0xd9, 0xcd, 0x4a, 0xfc, 0x75, 0x2f, 0x56, 0xe2, 0xcd, 0x57, 0x67, 0x25, 0xde, 0xd6, 0x59, 0x89, - 0xab, 0x58, 0xd8, 0xcf, 0x5a, 0x17, 0x4b, 0xfe, 0xf3, 0x23, 0x29, 0xe5, 0x2e, 0xe3, 0x7e, 0xc7, 0xa5, 0x90, 0xc7, - 0x57, 0xbf, 0x9b, 0xb1, 0xc0, 0x8d, 0xf8, 0x1e, 0xcd, 0xc9, 0x0a, 0xd6, 0x82, 0x63, 0x76, 0xfc, 0x8e, 0x52, 0x1c, - 0xc6, 0xd1, 0xf4, 0x67, 0x50, 0xca, 0x82, 0x38, 0x30, 0x51, 0x5e, 0x04, 0xe9, 0xcf, 0xf1, 0x62, 0xb9, 0xb8, 0x80, - 0xbe, 0x3e, 0x06, 0x69, 0x30, 0x0c, 0x99, 0xf4, 0x44, 0x26, 0xf3, 0x37, 0x2e, 0x13, 0x07, 0x8b, 0x53, 0xf1, 0xd3, - 0x5f, 0x89, 0x9f, 0x68, 0x93, 0xca, 0x7f, 0x93, 0x5d, 0x9d, 0xde, 0xcc, 0x88, 0x08, 0x25, 0xa0, 0x32, 0xe8, 0xc7, - 0x33, 0x23, 0x57, 0xb1, 0xd9, 0x30, 0x4b, 0x61, 0xef, 0xb0, 0xb1, 0x1f, 0x56, 0x63, 0x6a, 0x96, 0xa6, 0x25, 0x43, - 0x70, 0xd5, 0xc5, 0xf0, 0xf3, 0x78, 0x99, 0xb2, 0x71, 0x7c, 0x1f, 0xe9, 0x56, 0x24, 0x9d, 0x0c, 0x40, 0xc3, 0x29, - 0xdb, 0x60, 0xf2, 0xc8, 0x0f, 0x48, 0x28, 0xc7, 0x89, 0xa1, 0x43, 0xee, 0xd2, 0xe5, 0xc2, 0x26, 0x55, 0xb3, 0x8d, - 0x53, 0xd4, 0x65, 0x96, 0xa3, 0x27, 0x86, 0x11, 0xf7, 0x1f, 0xd7, 0x52, 0x98, 0x6a, 0xc4, 0x0e, 0x97, 0x0a, 0xa7, - 0x46, 0x24, 0x84, 0x8b, 0x22, 0x0e, 0x46, 0xc3, 0xc2, 0xf1, 0x37, 0xe4, 0xba, 0x5a, 0xbc, 0x85, 0x28, 0x22, 0xf9, - 0x92, 0xaf, 0x07, 0x8f, 0x0a, 0x41, 0x8f, 0xaf, 0x15, 0x30, 0xbe, 0xbb, 0x63, 0x49, 0xe8, 0x3f, 0x18, 0x66, 0x1e, - 0x47, 0x3f, 0x02, 0x00, 0xde, 0xc4, 0xf7, 0x91, 0x5a, 0x01, 0x93, 0xb5, 0x34, 0xec, 0xa5, 0xc6, 0xf8, 0x25, 0xe0, - 0xb8, 0xa2, 0x8c, 0x00, 0xd2, 0xe4, 0x4e, 0xd9, 0xdf, 0x2d, 0xfa, 0xf7, 0x1f, 0x66, 0x6e, 0x5d, 0xc6, 0xf2, 0x43, - 0x7f, 0x5b, 0xec, 0xf1, 0x99, 0xe7, 0xcf, 0x9f, 0x6c, 0x9e, 0x76, 0x39, 0x3d, 0x7b, 0x43, 0x6b, 0x73, 0xe3, 0x29, - 0x80, 0x51, 0x5c, 0xc5, 0xcb, 0xd1, 0x0c, 0x0d, 0x5d, 0xbf, 0xde, 0x7c, 0x33, 0xe8, 0x13, 0xb3, 0x94, 0xca, 0xa9, - 0x57, 0x8a, 0x0a, 0x28, 0xe0, 0xf7, 0xdf, 0x42, 0x00, 0xce, 0xff, 0x21, 0x18, 0xea, 0xbb, 0x86, 0x73, 0xf1, 0xc1, - 0xe3, 0x36, 0x6f, 0x0f, 0x92, 0x69, 0xf2, 0xd0, 0x16, 0x42, 0xb9, 0xd6, 0x8c, 0x64, 0xf2, 0x2a, 0xd0, 0xd4, 0x30, - 0x72, 0x9b, 0x22, 0xe4, 0x89, 0xaf, 0x30, 0x87, 0xd8, 0x74, 0xee, 0x68, 0x60, 0x31, 0x8e, 0xad, 0x2a, 0x48, 0x86, - 0x9b, 0x3c, 0x30, 0x44, 0x5f, 0xd5, 0x77, 0xf3, 0x20, 0xb2, 0x30, 0x0a, 0x7c, 0xfd, 0x8d, 0xbf, 0x82, 0x38, 0xc8, - 0x80, 0xdc, 0xaa, 0xaf, 0xa0, 0xd0, 0x52, 0xfd, 0xe6, 0x20, 0xd5, 0x93, 0xde, 0x08, 0x09, 0xa1, 0xc5, 0x1b, 0xfc, - 0x49, 0xd3, 0x34, 0x4d, 0xb2, 0x11, 0x9a, 0xe4, 0x23, 0xb0, 0x1c, 0xd9, 0x01, 0xd0, 0x96, 0xe4, 0x8b, 0x15, 0x95, - 0x00, 0x67, 0x80, 0x3a, 0x59, 0x51, 0xc0, 0x43, 0xfd, 0x75, 0x5c, 0x51, 0x20, 0x18, 0x7a, 0x08, 0xd3, 0xe6, 0x27, - 0x10, 0x11, 0xb8, 0xab, 0x21, 0xc3, 0x8e, 0x6f, 0xb9, 0x24, 0x58, 0x73, 0xe9, 0x71, 0xd0, 0x63, 0xcd, 0x31, 0xe1, - 0x22, 0x05, 0x0b, 0x82, 0xd6, 0xa1, 0x12, 0xe2, 0xd9, 0x62, 0x0d, 0xb8, 0x11, 0xf9, 0xa2, 0x55, 0x36, 0x67, 0xd1, - 0x52, 0xc7, 0x9c, 0x50, 0x18, 0xa3, 0x0f, 0xea, 0xbc, 0x21, 0x62, 0x0b, 0xb0, 0x4d, 0x73, 0xcb, 0x19, 0xdd, 0x85, - 0x29, 0x47, 0xa9, 0xbe, 0x35, 0xe2, 0x8a, 0xcd, 0x94, 0xe3, 0xb6, 0xea, 0x0d, 0xc1, 0x97, 0x34, 0xae, 0x3a, 0x72, - 0x91, 0x25, 0x34, 0xf4, 0x41, 0xd1, 0x31, 0xb8, 0xb8, 0x48, 0x80, 0xdd, 0xf0, 0xab, 0x8b, 0x26, 0x35, 0x32, 0x7e, - 0x45, 0x50, 0x94, 0x98, 0xf5, 0x6e, 0xf8, 0x38, 0x21, 0x30, 0xd1, 0xc6, 0x7e, 0x46, 0xb5, 0x7e, 0x36, 0x4c, 0xfa, - 0x13, 0x7b, 0xa0, 0x8b, 0x84, 0x40, 0xf5, 0x89, 0x3d, 0x80, 0xed, 0xdf, 0x5b, 0x90, 0xa6, 0xe8, 0x5b, 0xd0, 0xb5, - 0x05, 0xa1, 0xfe, 0x47, 0x10, 0xac, 0x6a, 0xcb, 0x01, 0x72, 0xf3, 0x2d, 0x58, 0x1c, 0x41, 0x0c, 0x59, 0x9d, 0xc5, - 0x21, 0xe6, 0x26, 0xfe, 0x46, 0x23, 0x8c, 0xed, 0x86, 0xa3, 0x61, 0xbe, 0xf0, 0x5c, 0xf7, 0xa0, 0x56, 0x1f, 0x04, - 0xd9, 0x4d, 0xb5, 0x4d, 0x2b, 0xeb, 0x7b, 0xae, 0x1d, 0xbc, 0x70, 0x5a, 0xbd, 0xda, 0x1d, 0xad, 0xc4, 0x92, 0x1c, - 0xa0, 0xf8, 0xeb, 0xec, 0xd9, 0xda, 0xa8, 0x1d, 0x48, 0xb3, 0x6a, 0x32, 0x8f, 0x63, 0xcb, 0xb9, 0xfc, 0x6b, 0x50, - 0xbf, 0xfa, 0x29, 0x92, 0x25, 0xe5, 0x35, 0x19, 0x40, 0x34, 0x64, 0x03, 0x8e, 0xd1, 0x9f, 0xb5, 0x97, 0x9a, 0x41, - 0xc7, 0xc7, 0x34, 0x07, 0x32, 0x5d, 0xb6, 0xf0, 0x29, 0x53, 0x3b, 0xa8, 0x7c, 0x31, 0xad, 0x62, 0x38, 0x1e, 0x77, - 0x95, 0x15, 0x1a, 0xbd, 0xad, 0xd4, 0x02, 0xf6, 0xbf, 0xe1, 0xfa, 0x74, 0x86, 0x10, 0x97, 0x00, 0x6a, 0x40, 0xec, - 0xf4, 0x9d, 0x1d, 0x2e, 0x17, 0xe5, 0xee, 0xca, 0x97, 0xe4, 0xfe, 0x9d, 0xe1, 0xa5, 0x83, 0x3a, 0x34, 0xd9, 0x5f, - 0xf3, 0x75, 0xf7, 0xc8, 0x2e, 0x59, 0x34, 0x2e, 0x77, 0x58, 0xb9, 0xbf, 0xf6, 0xef, 0xae, 0x84, 0x51, 0x20, 0xa9, - 0x40, 0xdc, 0x80, 0x51, 0xf2, 0x38, 0xc2, 0xcd, 0x4f, 0xc7, 0x2d, 0xd8, 0x8b, 0x8a, 0xc1, 0x06, 0x14, 0x11, 0x4c, - 0x36, 0x53, 0x84, 0xe2, 0x10, 0xb9, 0x1a, 0xdd, 0x82, 0x0d, 0x41, 0x88, 0x6e, 0xdc, 0x89, 0x99, 0xb0, 0x29, 0x2c, - 0xda, 0x04, 0x3c, 0x16, 0xe5, 0xbe, 0x52, 0xeb, 0x60, 0xb7, 0xd4, 0x3a, 0xdb, 0x25, 0xb5, 0x26, 0x77, 0xaa, 0xfb, - 0xc4, 0x5f, 0x28, 0x1e, 0x79, 0x82, 0x38, 0x57, 0x1d, 0xf3, 0x4a, 0xa2, 0x6e, 0xf4, 0xbe, 0x12, 0xad, 0x6a, 0xbd, - 0x91, 0x95, 0x20, 0x8a, 0xbf, 0x15, 0x06, 0x45, 0x28, 0xd4, 0x55, 0xd9, 0xf8, 0x55, 0x21, 0x1b, 0x27, 0xae, 0xa6, - 0x70, 0xa4, 0x11, 0xd4, 0xbf, 0xe2, 0xa4, 0x26, 0xb9, 0x83, 0xc2, 0x59, 0xad, 0x18, 0xa9, 0xe2, 0x7e, 0x55, 0x30, - 0x1a, 0x8a, 0x53, 0x9f, 0xe0, 0x32, 0xca, 0xbe, 0x7d, 0xe5, 0xaa, 0x85, 0xf7, 0x55, 0x51, 0x0e, 0x52, 0x77, 0x1c, - 0xb2, 0x2c, 0x56, 0xb7, 0x4d, 0xd9, 0xfd, 0x46, 0x7d, 0xad, 0x6c, 0x12, 0xe9, 0x27, 0x43, 0x00, 0x16, 0x62, 0xfa, - 0x8a, 0x5e, 0x5b, 0xda, 0x40, 0xe0, 0x20, 0x1b, 0xdc, 0xfa, 0x76, 0x4b, 0xe7, 0x29, 0x5f, 0x42, 0xa1, 0x85, 0x57, - 0x65, 0x10, 0x08, 0xdf, 0x9b, 0x75, 0xc3, 0x2d, 0x8f, 0x97, 0x3c, 0xbf, 0xdf, 0x41, 0xbc, 0xa8, 0xb9, 0xaa, 0x22, - 0x1f, 0x4f, 0xa6, 0x4d, 0xe6, 0xb9, 0x58, 0xb5, 0xde, 0x29, 0x09, 0x71, 0xd6, 0xdc, 0x33, 0xa6, 0x2c, 0xa3, 0xe7, - 0x35, 0xba, 0xe2, 0xbb, 0x7c, 0xeb, 0x24, 0xcb, 0x08, 0x63, 0xdb, 0xdb, 0x59, 0xe2, 0x8f, 0x3e, 0x29, 0x43, 0x16, - 0x72, 0x4e, 0x90, 0x01, 0x97, 0x35, 0x05, 0x3d, 0x1f, 0x43, 0x41, 0xb2, 0xae, 0xd3, 0x4a, 0x15, 0xe9, 0x4b, 0xf7, - 0xa9, 0xdb, 0xf6, 0x5f, 0x4d, 0x0e, 0x2b, 0x42, 0xd1, 0x56, 0xa7, 0x2c, 0x32, 0xdf, 0x30, 0x8e, 0x6c, 0xb6, 0x9c, - 0x0f, 0xd7, 0xaa, 0x6c, 0x55, 0x11, 0xb9, 0xd6, 0xc5, 0xac, 0xea, 0x67, 0x27, 0x93, 0x49, 0x59, 0xd0, 0xe8, 0x6a, - 0x87, 0x28, 0x2c, 0x7c, 0xea, 0xba, 0x6e, 0x75, 0xec, 0xdb, 0xc1, 0x6e, 0xa3, 0xdc, 0xf6, 0xa4, 0x71, 0xc4, 0x08, - 0xdb, 0x5d, 0xf0, 0xab, 0x83, 0x23, 0x77, 0x8a, 0x93, 0x5d, 0x32, 0x8b, 0xe8, 0x91, 0x31, 0x44, 0x90, 0xb1, 0x79, - 0xda, 0x1d, 0x31, 0xd4, 0xc1, 0x38, 0xca, 0x81, 0x46, 0xc3, 0x01, 0x7b, 0x0a, 0xa6, 0x22, 0x9e, 0xd8, 0x15, 0xae, - 0x86, 0xf2, 0xf0, 0x9a, 0xf0, 0x5e, 0x7c, 0x04, 0x0f, 0xca, 0xba, 0x2e, 0xd3, 0xc6, 0x69, 0x75, 0xdc, 0x3f, 0x97, - 0xea, 0x69, 0x70, 0x01, 0xae, 0x85, 0x42, 0x9b, 0xe4, 0xb3, 0xf8, 0xff, 0x52, 0xfe, 0xff, 0x6a, 0xb1, 0x2a, 0xdb, - 0x8f, 0x9c, 0x80, 0x44, 0xbb, 0x38, 0x2d, 0x34, 0xea, 0xa6, 0x3d, 0x20, 0xad, 0x0c, 0x26, 0xaa, 0x02, 0x1d, 0x94, - 0xf4, 0xa5, 0x04, 0x20, 0x0d, 0xe2, 0x77, 0xa4, 0x98, 0x61, 0x89, 0x0b, 0x11, 0x62, 0x91, 0xbe, 0x0e, 0xe6, 0x60, - 0xbd, 0x3c, 0x41, 0xfd, 0x41, 0x69, 0x4f, 0x80, 0x36, 0xbe, 0x36, 0xb7, 0xbd, 0xc4, 0xfd, 0x55, 0xbd, 0x96, 0xe8, - 0x18, 0x40, 0xe6, 0xc1, 0x21, 0x44, 0x43, 0x02, 0xad, 0xb2, 0xb9, 0x69, 0x94, 0xf2, 0xad, 0xaa, 0x67, 0x13, 0x03, - 0xc3, 0xee, 0x9a, 0xab, 0x50, 0xdf, 0x42, 0x5b, 0x00, 0x93, 0xe5, 0xdb, 0x0f, 0x9f, 0x6d, 0x58, 0x62, 0x75, 0x3f, - 0x7a, 0xb8, 0xe4, 0xb8, 0x7f, 0x6d, 0xbc, 0x3b, 0x53, 0x3a, 0xff, 0x28, 0x5f, 0xfc, 0x6b, 0xa3, 0x40, 0xef, 0xaa, - 0x24, 0xa1, 0xe3, 0xd6, 0xe2, 0x2d, 0x73, 0xaf, 0xda, 0xf3, 0x20, 0xda, 0xbf, 0xae, 0xbf, 0xda, 0xbb, 0x2e, 0x5c, - 0x18, 0x7b, 0x57, 0x86, 0x1b, 0x87, 0x2c, 0x17, 0xb2, 0xfe, 0x5f, 0x15, 0x81, 0xa2, 0xea, 0x75, 0xac, 0x63, 0x2b, - 0xa2, 0xf2, 0xaf, 0x96, 0x40, 0x7c, 0xee, 0x95, 0xe0, 0x41, 0x13, 0x39, 0xda, 0xf4, 0x63, 0xed, 0x44, 0x3b, 0x6e, - 0x6b, 0x47, 0xae, 0x4e, 0x5c, 0x58, 0x5f, 0xef, 0xb4, 0x0a, 0x6f, 0xc2, 0x43, 0x57, 0x3f, 0x3b, 0x9d, 0x8a, 0x4b, - 0x62, 0x12, 0x84, 0x21, 0xa1, 0x8a, 0x34, 0x4b, 0xe2, 0x4f, 0xac, 0xac, 0x66, 0xa1, 0x32, 0x6e, 0x04, 0xd2, 0x12, - 0x8f, 0x70, 0x76, 0x46, 0xfe, 0xa2, 0x8b, 0x67, 0x43, 0x2d, 0x04, 0x03, 0x4e, 0x2a, 0xc5, 0x4f, 0xc0, 0x1d, 0x3c, - 0xd4, 0xcf, 0x4e, 0x21, 0x84, 0xa1, 0x36, 0xee, 0xeb, 0x3f, 0xb6, 0x8e, 0x35, 0xaf, 0x73, 0x67, 0xb7, 0x47, 0xae, - 0xed, 0x39, 0x87, 0x9a, 0xeb, 0x1c, 0xd9, 0x2d, 0xe7, 0x58, 0x6b, 0x39, 0x1d, 0xf8, 0x77, 0xe4, 0x39, 0xaf, 0x34, - 0x17, 0x9e, 0x34, 0xcf, 0x69, 0xe3, 0xbf, 0x2d, 0xe7, 0xf8, 0xae, 0x4d, 0x37, 0xbd, 0x2f, 0xdd, 0xaa, 0x2a, 0xa3, - 0x00, 0x27, 0x10, 0xfd, 0xe0, 0xec, 0x74, 0x99, 0x32, 0x6d, 0xd5, 0xd7, 0x5f, 0xe9, 0xda, 0x2c, 0x61, 0x93, 0xbe, - 0xfe, 0xd4, 0x57, 0x4a, 0xbd, 0x93, 0xc6, 0xe2, 0xd6, 0x71, 0x63, 0x71, 0xfb, 0xa8, 0xb1, 0xf8, 0xb0, 0x53, 0x2e, - 0x3e, 0x98, 0xd2, 0x2b, 0x25, 0x83, 0xe0, 0xdc, 0xcf, 0x92, 0x60, 0x65, 0x78, 0x1a, 0xa0, 0x6b, 0x1b, 0xfe, 0x39, - 0x6e, 0x99, 0xb2, 0xd5, 0x10, 0x5a, 0x49, 0x68, 0x1c, 0x9f, 0x68, 0xde, 0xd1, 0x5f, 0x5a, 0x47, 0x23, 0xa8, 0x07, - 0xf9, 0x2e, 0xe1, 0xef, 0xae, 0x7d, 0x32, 0x72, 0x35, 0x68, 0xe8, 0xc1, 0x7f, 0xb3, 0x4e, 0x6b, 0x44, 0x0f, 0x2e, - 0xbc, 0xff, 0xe8, 0x1d, 0xa7, 0xae, 0xed, 0xc1, 0x7f, 0xbf, 0x49, 0x95, 0x3b, 0x28, 0xfc, 0xd5, 0x7e, 0x0f, 0x5d, - 0xad, 0x7d, 0x32, 0x6b, 0x39, 0xaf, 0xee, 0x8e, 0x9d, 0x93, 0x99, 0x77, 0xfc, 0x91, 0x9e, 0x42, 0xbb, 0xe5, 0xbc, - 0x82, 0xbf, 0x8f, 0x6d, 0x77, 0x66, 0x7b, 0xce, 0xc9, 0x5d, 0xdb, 0x69, 0x87, 0xf6, 0x91, 0x73, 0x02, 0x7f, 0xbf, - 0x01, 0x78, 0x01, 0xae, 0x3c, 0x41, 0xa9, 0x06, 0x1b, 0xa3, 0x62, 0xbf, 0xa1, 0x7e, 0xa4, 0x75, 0xa8, 0x75, 0x0e, - 0xff, 0x72, 0x72, 0x67, 0x1f, 0xce, 0xbc, 0xd6, 0x9d, 0xbd, 0xf1, 0xe7, 0x47, 0x80, 0xfc, 0xf6, 0x85, 0x03, 0x30, - 0x62, 0x46, 0x92, 0x3f, 0x0d, 0xac, 0xcb, 0x4d, 0x62, 0xf4, 0xf7, 0xbb, 0xc5, 0xe8, 0x3f, 0x2c, 0xf7, 0x11, 0xa3, - 0xbf, 0xff, 0xea, 0x62, 0xf4, 0xcb, 0xaa, 0x15, 0xf7, 0xfb, 0x6a, 0xe4, 0xf4, 0x5f, 0xd6, 0x55, 0x22, 0x39, 0xf0, - 0x8d, 0xeb, 0xab, 0xe5, 0x0d, 0xc4, 0xfe, 0x79, 0x1f, 0xf7, 0x7f, 0x58, 0x96, 0x4c, 0x94, 0x62, 0xc0, 0x00, 0xef, - 0x63, 0xc2, 0x00, 0xbf, 0x2d, 0xfb, 0x60, 0x17, 0xc1, 0x6f, 0xcd, 0x60, 0x6c, 0xcf, 0xfc, 0x70, 0x22, 0x6f, 0x5c, - 0x28, 0xe9, 0x61, 0x31, 0xd8, 0xcc, 0xc3, 0x65, 0x02, 0xca, 0x9a, 0xe5, 0x3c, 0x4a, 0xbb, 0x47, 0x2e, 0xa0, 0xf9, - 0xd6, 0x24, 0xc9, 0x2b, 0x8d, 0x1d, 0x11, 0x2d, 0xe9, 0x96, 0xdb, 0xf4, 0x6f, 0x7c, 0x8f, 0x26, 0x6b, 0xcd, 0xbd, - 0x7b, 0xf5, 0x7e, 0x35, 0xb0, 0x05, 0x11, 0x26, 0x7d, 0x40, 0x6c, 0x34, 0xbd, 0x2f, 0x1b, 0x8e, 0x55, 0x4c, 0x05, - 0x37, 0x8f, 0x14, 0x46, 0x52, 0x6d, 0xef, 0x95, 0x0d, 0xcf, 0x76, 0x4d, 0xb3, 0xe1, 0xf3, 0xa5, 0xe6, 0x5b, 0xac, - 0xde, 0x64, 0xc7, 0x55, 0x50, 0x55, 0xf2, 0x7e, 0x35, 0x02, 0xa4, 0xa0, 0x3d, 0x0b, 0xd3, 0xb8, 0x82, 0xf0, 0x71, - 0x35, 0xbc, 0x8d, 0x5d, 0xe5, 0x5d, 0xa9, 0x4f, 0xd5, 0x9c, 0xee, 0xc5, 0x1a, 0xe9, 0xc1, 0xe0, 0x37, 0x20, 0x6c, - 0xf8, 0x7d, 0x3c, 0x8c, 0x55, 0x38, 0xaf, 0x95, 0x7e, 0x89, 0xd4, 0xce, 0x67, 0xde, 0xba, 0x4e, 0xda, 0x6c, 0x34, - 0xa4, 0xf5, 0xd8, 0x5c, 0xdc, 0xd1, 0xf8, 0x79, 0x32, 0x5b, 0xcd, 0xc9, 0xb4, 0x18, 0x2d, 0x73, 0xb7, 0x75, 0x26, - 0xea, 0x3d, 0x85, 0x4d, 0x6c, 0xf1, 0x07, 0xd5, 0x6b, 0x7d, 0x3d, 0x81, 0x1c, 0xcd, 0x5d, 0x24, 0x22, 0x14, 0x0a, - 0xaa, 0x85, 0x36, 0xb6, 0xbd, 0x2d, 0xe6, 0x1f, 0x6a, 0xc7, 0xbc, 0x13, 0xb4, 0xd5, 0xdd, 0x66, 0x31, 0x22, 0x5d, - 0x1b, 0xd6, 0x25, 0x05, 0xaa, 0xd7, 0x39, 0xb6, 0xbc, 0x23, 0xcb, 0x39, 0xee, 0x98, 0xb9, 0x38, 0x70, 0x6a, 0x97, - 0x25, 0x80, 0x80, 0xc9, 0xae, 0x1c, 0x66, 0x10, 0x05, 0x59, 0xe0, 0x87, 0x39, 0xa0, 0xfa, 0x32, 0xcd, 0xfb, 0xcf, - 0x65, 0x9a, 0xc1, 0x1c, 0x05, 0x49, 0x86, 0xe6, 0xca, 0xf6, 0x90, 0x65, 0xf7, 0x8c, 0x45, 0x1b, 0x54, 0xb9, 0x55, - 0xeb, 0xe7, 0x3f, 0xce, 0x16, 0x34, 0x27, 0x3b, 0x8b, 0x61, 0x16, 0xf1, 0xfd, 0x21, 0x4c, 0x75, 0xf3, 0x81, 0xf5, - 0xd3, 0x26, 0x84, 0xfb, 0xcf, 0xdd, 0x08, 0x37, 0x63, 0xfb, 0x20, 0xdc, 0x7f, 0x7e, 0x75, 0x84, 0xfb, 0x93, 0x8a, - 0x70, 0x4b, 0x9e, 0x2a, 0x85, 0x4c, 0xf4, 0x03, 0x3e, 0x1b, 0x10, 0x72, 0xf8, 0xa5, 0x7e, 0x40, 0xe4, 0xa5, 0xae, - 0xa4, 0x82, 0xfd, 0x58, 0xca, 0x6d, 0x83, 0x2c, 0x3b, 0x86, 0x48, 0xa5, 0x3c, 0x1a, 0x90, 0x26, 0x55, 0x26, 0xfc, - 0x86, 0x3e, 0x2f, 0xa2, 0x2c, 0x74, 0xde, 0x73, 0xb6, 0x04, 0x54, 0x10, 0x3f, 0xc4, 0xc9, 0xdc, 0xc7, 0xf0, 0x70, - 0x3a, 0xe6, 0xc4, 0x83, 0x07, 0x17, 0xbc, 0xa3, 0x46, 0x71, 0x34, 0x96, 0x72, 0x74, 0xd6, 0xbf, 0x26, 0x7a, 0x50, - 0x7f, 0x60, 0x7e, 0xa2, 0x5b, 0xf4, 0x1a, 0x16, 0xf7, 0x45, 0xdb, 0x7d, 0xd1, 0x3a, 0x7c, 0x71, 0xe4, 0xc2, 0xff, - 0x3c, 0xd6, 0xce, 0x2d, 0x5e, 0x71, 0x1e, 0x47, 0x90, 0x96, 0x43, 0xd4, 0xdc, 0x54, 0xed, 0x9e, 0xb1, 0x4f, 0x45, - 0xad, 0xe3, 0xe6, 0x4a, 0x63, 0xff, 0xa1, 0xa8, 0xd3, 0x58, 0x63, 0x16, 0x2f, 0x95, 0x61, 0x35, 0x8c, 0x26, 0x88, - 0x96, 0x20, 0x19, 0x52, 0x6a, 0xa8, 0xaf, 0xf9, 0x74, 0x8b, 0x79, 0xb1, 0x76, 0x7e, 0x53, 0xe4, 0xfe, 0x11, 0x39, - 0x48, 0x76, 0x42, 0x90, 0x0b, 0xd5, 0x5d, 0x8c, 0x1c, 0x8e, 0xd9, 0x6f, 0x34, 0xc8, 0xbc, 0x57, 0x24, 0x78, 0xc7, - 0x05, 0xca, 0x92, 0x65, 0x34, 0xa2, 0x1c, 0xee, 0xfe, 0x30, 0x35, 0x82, 0x03, 0x88, 0x1d, 0x8a, 0x1f, 0x36, 0x71, - 0xd5, 0xfc, 0x33, 0xb7, 0x48, 0x94, 0x90, 0x8a, 0x55, 0xf1, 0x5f, 0x64, 0x56, 0x42, 0xe9, 0x55, 0x71, 0x69, 0xed, - 0xbe, 0xff, 0x42, 0x36, 0x7c, 0x91, 0x59, 0x90, 0xe2, 0x14, 0x96, 0xfb, 0xf9, 0x73, 0xaa, 0x05, 0x49, 0x07, 0x69, - 0x5a, 0xe7, 0xa3, 0x22, 0xf8, 0x98, 0xe6, 0x4f, 0x63, 0x8a, 0x3f, 0xd6, 0x1d, 0x59, 0xf1, 0xcb, 0x97, 0x67, 0x7d, - 0xcf, 0xe4, 0x29, 0x33, 0x4b, 0xf9, 0x9d, 0x2e, 0xf7, 0x53, 0x8d, 0x9b, 0x8d, 0x4e, 0x5b, 0x8b, 0x20, 0x9a, 0x0a, - 0xcd, 0xb4, 0xc4, 0x5e, 0x90, 0x6f, 0x81, 0x54, 0x60, 0xbe, 0x50, 0x51, 0x8b, 0x3a, 0x77, 0x2c, 0x81, 0x74, 0x9f, - 0x7d, 0xbd, 0xed, 0xb8, 0x8e, 0xab, 0xcb, 0x86, 0x93, 0x60, 0xda, 0x5f, 0xc7, 0x99, 0x0f, 0x99, 0x6b, 0xc2, 0x78, - 0x0a, 0x9e, 0x1f, 0x59, 0x90, 0x85, 0x90, 0x06, 0x05, 0x5c, 0x40, 0xe6, 0xc4, 0x35, 0xe6, 0xdc, 0x1e, 0xd7, 0x4f, - 0x3e, 0x61, 0x2a, 0x3c, 0xe1, 0xf4, 0x85, 0xf1, 0x70, 0x7e, 0x84, 0xcb, 0xd0, 0xd0, 0x0d, 0x48, 0xc4, 0xc8, 0x92, - 0xd4, 0x56, 0xed, 0xdb, 0xbb, 0x1a, 0xb4, 0x81, 0x24, 0xe9, 0xd8, 0xc1, 0x24, 0xf1, 0xe7, 0x10, 0x31, 0x7c, 0x9d, - 0x5b, 0x1c, 0xd3, 0xea, 0x1c, 0xd5, 0x6a, 0xde, 0xab, 0x23, 0x4b, 0x6b, 0x79, 0x96, 0xe6, 0x02, 0xba, 0xd5, 0x73, - 0x6b, 0x9d, 0xdf, 0xf4, 0x76, 0xa9, 0xe8, 0x08, 0xbf, 0x3c, 0xa5, 0x79, 0x90, 0x72, 0x8e, 0x0b, 0x3f, 0x33, 0x0a, - 0x6f, 0x68, 0x28, 0xb1, 0xbc, 0x03, 0x12, 0xd3, 0x5f, 0xb1, 0x55, 0x66, 0x62, 0x9a, 0x10, 0x5e, 0x25, 0x30, 0xd7, - 0xe8, 0x9a, 0x16, 0x44, 0x5a, 0xf0, 0xf9, 0xb3, 0x11, 0x80, 0xf9, 0x7d, 0x5f, 0x81, 0x0f, 0x3c, 0x9b, 0x25, 0x80, - 0x05, 0x85, 0x62, 0x09, 0x81, 0x05, 0xbe, 0x31, 0xf0, 0x6f, 0x51, 0x2c, 0x7e, 0x70, 0xc5, 0x9e, 0x13, 0xfa, 0xd1, - 0x14, 0x50, 0x9a, 0x1f, 0x4d, 0x6b, 0x06, 0x04, 0xe4, 0x5d, 0x57, 0x29, 0x2d, 0xba, 0x2a, 0x94, 0xfb, 0xe9, 0xf7, - 0x0f, 0x57, 0x94, 0x06, 0x09, 0x52, 0x6e, 0xfb, 0x63, 0x74, 0x05, 0x2b, 0x74, 0x0f, 0x2f, 0xfb, 0xdf, 0x9c, 0xce, - 0x59, 0xe6, 0x93, 0xe0, 0x12, 0x58, 0x3c, 0x20, 0x07, 0xb4, 0x91, 0x48, 0x61, 0x4a, 0x0c, 0xde, 0x98, 0xdd, 0x05, - 0x23, 0xce, 0xa7, 0x59, 0x1a, 0xbf, 0xa7, 0x6c, 0xb4, 0x51, 0xea, 0x7b, 0x16, 0x99, 0xc8, 0x8e, 0x7c, 0x0c, 0x82, - 0xd8, 0x8f, 0x62, 0xfd, 0xec, 0x1b, 0xe9, 0x4d, 0xb4, 0x69, 0x11, 0x20, 0x17, 0xe1, 0x75, 0xc2, 0xc2, 0x7f, 0xf5, - 0xbf, 0x81, 0x8b, 0xfb, 0x9b, 0x1b, 0xdd, 0xec, 0x65, 0x0e, 0xf2, 0x31, 0xdf, 0x34, 0xe4, 0xe4, 0x43, 0x1e, 0x95, - 0x33, 0x9b, 0x6d, 0x85, 0xd9, 0x84, 0xdf, 0xbb, 0x59, 0xd7, 0xb3, 0x53, 0xbc, 0xd0, 0xce, 0x80, 0xbb, 0x58, 0x97, - 0x78, 0x4e, 0xaf, 0x87, 0x0c, 0xea, 0x30, 0xf4, 0x47, 0x9f, 0x04, 0x87, 0xaa, 0x3e, 0xec, 0xc3, 0x8b, 0x4a, 0xca, - 0xae, 0x71, 0x2f, 0xe3, 0x56, 0x5e, 0xe3, 0x97, 0xf1, 0x53, 0xf7, 0xb3, 0x20, 0x93, 0xcc, 0x30, 0x3e, 0xe4, 0xa0, - 0xcd, 0xc1, 0xf1, 0x15, 0xec, 0x0f, 0x30, 0xa8, 0xde, 0xc9, 0x5f, 0x3a, 0x77, 0x9e, 0x3b, 0x6b, 0x79, 0x0e, 0xb0, - 0x39, 0xb3, 0xb6, 0x73, 0x1c, 0xda, 0x6d, 0xe7, 0x18, 0xfe, 0x3e, 0x02, 0xeb, 0x65, 0xb7, 0x9c, 0xc3, 0x8f, 0x5e, - 0x2b, 0xb4, 0x4f, 0x9c, 0x63, 0xf8, 0xbb, 0xa4, 0x56, 0xbf, 0x20, 0xd3, 0x03, 0x0c, 0xcf, 0x37, 0x25, 0x2c, 0xa0, - 0xfc, 0x96, 0x5a, 0x04, 0xab, 0x74, 0xbd, 0x35, 0x68, 0x22, 0x00, 0x65, 0xe8, 0x96, 0x08, 0x51, 0x18, 0xf5, 0x0c, - 0x48, 0x12, 0x8e, 0xe1, 0xed, 0x85, 0x41, 0x46, 0x54, 0x24, 0xbc, 0xdf, 0x7c, 0x8c, 0x78, 0x9b, 0xe6, 0x70, 0xe0, - 0x22, 0x6f, 0x12, 0xa9, 0x2e, 0xfe, 0xb6, 0xc0, 0x10, 0x3b, 0x22, 0x80, 0xb9, 0x82, 0x95, 0x8a, 0xdc, 0x7d, 0xf9, - 0xee, 0x81, 0xa3, 0xdf, 0x28, 0x93, 0xb9, 0x63, 0xbe, 0x6a, 0xdf, 0x5c, 0x9d, 0x21, 0x7b, 0xff, 0xbd, 0xfd, 0x60, - 0xca, 0x54, 0xea, 0x47, 0xc4, 0x1a, 0x1d, 0x07, 0x89, 0x1c, 0x9e, 0x82, 0xa2, 0xbd, 0xe6, 0x38, 0xea, 0x26, 0x24, - 0xd9, 0xb8, 0x00, 0x2a, 0xf9, 0xce, 0x0f, 0x15, 0xd3, 0x0b, 0xa5, 0xe5, 0x13, 0x89, 0xf9, 0x9f, 0x3f, 0x2f, 0x06, - 0x67, 0x57, 0xc6, 0x7d, 0xea, 0x75, 0xe0, 0xda, 0xed, 0xb0, 0xf6, 0x56, 0x2b, 0xa0, 0xdd, 0xc1, 0x6a, 0x8b, 0x60, - 0x96, 0x42, 0xd3, 0x2f, 0x74, 0x8c, 0x1b, 0x4d, 0x91, 0x6a, 0x1a, 0x46, 0x08, 0xf3, 0x5b, 0x61, 0x75, 0x74, 0xb3, - 0x17, 0x09, 0x85, 0x59, 0xb4, 0x25, 0x40, 0x2f, 0xe7, 0xc5, 0x74, 0x00, 0xcd, 0x96, 0x79, 0xec, 0x70, 0x69, 0xfc, - 0x5f, 0x4f, 0x02, 0xdd, 0x8b, 0x40, 0xc3, 0x57, 0x39, 0xad, 0x25, 0x77, 0x13, 0x79, 0xaf, 0xd2, 0x85, 0xca, 0xd2, - 0x73, 0x1d, 0x8a, 0x20, 0xfb, 0x12, 0x26, 0x5c, 0x93, 0xe6, 0x4d, 0xf2, 0xb6, 0x28, 0x0a, 0xac, 0x00, 0x22, 0x54, - 0x1b, 0xc2, 0xd5, 0xc9, 0x7c, 0xfe, 0x7c, 0xe3, 0x25, 0x44, 0xea, 0x64, 0x35, 0xef, 0xa4, 0xae, 0xe2, 0x37, 0x5d, - 0x45, 0x31, 0xb2, 0x5f, 0xc4, 0x1a, 0xc2, 0x2a, 0x8b, 0xf6, 0x1e, 0xfe, 0x1c, 0x32, 0x3f, 0x73, 0xb8, 0x1e, 0xc4, - 0x50, 0x2e, 0x77, 0xcb, 0x63, 0x6d, 0xb0, 0xc7, 0xe2, 0x91, 0xb8, 0x78, 0xa4, 0xbb, 0x67, 0xeb, 0x8f, 0x4b, 0xee, - 0x87, 0x0c, 0x7d, 0x7c, 0x76, 0x8b, 0xe0, 0x29, 0xef, 0x32, 0x9f, 0x22, 0x6c, 0xa8, 0x57, 0x6e, 0x9c, 0xf9, 0x22, - 0xcb, 0x09, 0xd0, 0xe5, 0xbd, 0x46, 0x85, 0xa1, 0xe2, 0xab, 0x7c, 0xf6, 0xee, 0xea, 0x3b, 0x8d, 0xef, 0x7f, 0xd2, - 0x6f, 0x21, 0x23, 0x43, 0x31, 0xf9, 0xfb, 0x14, 0x93, 0x5f, 0xe3, 0x49, 0x2e, 0x20, 0xb2, 0x7d, 0x7e, 0x40, 0x10, - 0xd4, 0x35, 0x16, 0x8d, 0x48, 0xeb, 0x37, 0x5f, 0x86, 0x59, 0xb0, 0xf0, 0x93, 0xec, 0x00, 0x9a, 0xda, 0x80, 0xe4, - 0xf4, 0x4d, 0x1e, 0xcc, 0xa4, 0x38, 0x14, 0x42, 0xb5, 0x2c, 0x12, 0x9a, 0xc3, 0x49, 0x10, 0x4a, 0xc5, 0xa1, 0xf8, - 0x80, 0x3f, 0x1a, 0xb1, 0x45, 0xd6, 0xd7, 0xfd, 0x05, 0xe4, 0x66, 0xc0, 0x68, 0xcb, 0x07, 0xf1, 0x28, 0x63, 0x99, - 0x9d, 0x66, 0x09, 0xf3, 0xe7, 0xba, 0x0c, 0x34, 0x5a, 0xef, 0x2f, 0x5d, 0x0e, 0xe7, 0x41, 0x26, 0x23, 0xf5, 0xd1, - 0x04, 0x41, 0x85, 0x07, 0x43, 0x3c, 0x1b, 0xe4, 0x1c, 0x84, 0x97, 0xf1, 0xb4, 0xb2, 0xa3, 0x0a, 0xca, 0xe5, 0x1c, - 0xe3, 0xc0, 0xf2, 0x78, 0xfc, 0x63, 0xf4, 0xc8, 0xb9, 0xe5, 0x5e, 0xd7, 0x32, 0xa0, 0xa0, 0x7e, 0x76, 0xca, 0xd9, - 0x5b, 0x0d, 0x03, 0x05, 0xe8, 0x1d, 0x17, 0x22, 0xdd, 0x6e, 0xf2, 0xc7, 0x3e, 0xe0, 0x95, 0xe1, 0x6a, 0xa2, 0x9e, - 0x31, 0x0a, 0x39, 0x8d, 0xe5, 0x0a, 0x08, 0xa1, 0x92, 0x8a, 0x77, 0xe6, 0x9d, 0x49, 0x07, 0x20, 0x1c, 0x15, 0xd2, - 0x4a, 0x9f, 0x3f, 0xbf, 0x1e, 0xfc, 0xe7, 0xdf, 0x10, 0x2a, 0x7d, 0xe6, 0x09, 0x2f, 0xe8, 0x6b, 0xb5, 0x16, 0xa7, - 0x3e, 0xad, 0x01, 0xaa, 0xf7, 0xd9, 0x58, 0x84, 0x05, 0x11, 0x5b, 0x2b, 0x1f, 0xdc, 0x88, 0x50, 0x4f, 0x90, 0x0e, - 0xc1, 0x14, 0xbe, 0xda, 0x03, 0x58, 0xde, 0x81, 0x08, 0x11, 0xa0, 0xfd, 0xba, 0xfa, 0xfe, 0x18, 0x42, 0x01, 0xd7, - 0xb2, 0x14, 0x28, 0x03, 0xc4, 0x3d, 0x74, 0x76, 0xea, 0x73, 0xe1, 0x2b, 0x90, 0x1f, 0x69, 0xf7, 0x00, 0xa6, 0x39, - 0x8b, 0xe7, 0xcc, 0x09, 0xe2, 0x83, 0x7b, 0x36, 0xb4, 0xfd, 0x45, 0x40, 0xf2, 0x65, 0x94, 0xbb, 0x69, 0x44, 0xf9, - 0x49, 0x05, 0x2d, 0xd1, 0xd7, 0x79, 0x01, 0xca, 0xb8, 0x00, 0x14, 0xfc, 0xf4, 0xcf, 0xca, 0xd1, 0x03, 0x1d, 0x11, - 0xbf, 0xbe, 0x8c, 0xe5, 0xcf, 0x29, 0x08, 0xa0, 0x88, 0xf7, 0x57, 0x3c, 0xd8, 0xf1, 0x64, 0xa2, 0x46, 0xfc, 0x73, - 0xca, 0xdf, 0x97, 0x50, 0x29, 0xf6, 0x6c, 0xbc, 0xa0, 0x2f, 0xd5, 0x3f, 0x21, 0x7f, 0x42, 0xee, 0x5e, 0x1e, 0x1c, - 0x12, 0xce, 0x73, 0x2d, 0x72, 0xa0, 0x04, 0xc9, 0x53, 0xaa, 0xc4, 0x11, 0x45, 0x35, 0x4e, 0xf5, 0x06, 0xd2, 0xe4, - 0x49, 0xbf, 0x4f, 0x78, 0xac, 0x8a, 0xce, 0x00, 0x4a, 0x0d, 0xb1, 0xfc, 0x61, 0xb2, 0x19, 0x34, 0xb4, 0xc9, 0x83, - 0x0b, 0x1b, 0x55, 0xa7, 0x53, 0x1f, 0xe3, 0x81, 0x2f, 0xf6, 0x57, 0x69, 0x07, 0xc2, 0xce, 0xe2, 0x0b, 0x0b, 0x08, - 0x5c, 0xf4, 0x53, 0xc1, 0xe3, 0xda, 0xb7, 0x84, 0xb2, 0xed, 0xd0, 0x7f, 0x88, 0x15, 0xcd, 0x3a, 0x77, 0xb2, 0xbf, - 0xc4, 0xd2, 0x2b, 0xe1, 0xdc, 0x56, 0x3b, 0x49, 0x32, 0x1e, 0x7a, 0xfd, 0x34, 0xa9, 0x01, 0xcc, 0x77, 0x1d, 0x26, - 0xb5, 0x6e, 0x79, 0x32, 0x88, 0x1d, 0xf3, 0xe2, 0xa0, 0x95, 0x5e, 0xe2, 0xb9, 0xcf, 0x4f, 0x0f, 0x60, 0x7e, 0x10, - 0x18, 0xa0, 0x44, 0x19, 0x05, 0x26, 0x44, 0x1f, 0xf0, 0x53, 0xb2, 0x0e, 0xb8, 0x18, 0x0b, 0xa2, 0x0e, 0x39, 0x47, - 0x19, 0x9a, 0xb4, 0x54, 0xa5, 0x4e, 0xac, 0xb8, 0xcd, 0x54, 0xde, 0xee, 0xfc, 0x01, 0xbf, 0x2d, 0x31, 0x79, 0x40, - 0xde, 0xcb, 0x98, 0xf0, 0xbb, 0xbd, 0xcc, 0x36, 0xb8, 0xe6, 0x6e, 0xaa, 0x42, 0x04, 0xeb, 0x96, 0x0a, 0xc5, 0x3e, - 0xde, 0x56, 0xab, 0x20, 0x8d, 0x64, 0xb5, 0x85, 0x6f, 0xe8, 0x4f, 0x71, 0xc7, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0xbb, - 0xcc, 0xfa, 0x50, 0x55, 0x08, 0xdb, 0xfd, 0xc5, 0x82, 0x2a, 0x9b, 0xbd, 0xd3, 0x03, 0xe2, 0x3b, 0xcf, 0x68, 0x87, - 0x9d, 0x9d, 0x82, 0x75, 0x21, 0x2d, 0xba, 0xbf, 0x58, 0xf0, 0x25, 0xa5, 0x5f, 0xf4, 0xe6, 0x60, 0x96, 0xcd, 0xc3, - 0xb3, 0xff, 0x03, 0x1c, 0x2a, 0x1a, 0x60, 0x9f, 0x5a, 0x03, 0x00}; + 0xdc, 0x93, 0x2e, 0xb7, 0x6d, 0x24, 0xfd, 0x3f, 0x4f, 0x01, 0xc3, 0x5e, 0x87, 0xb0, 0x01, 0x08, 0x00, 0x45, 0x89, + 0x26, 0x45, 0x69, 0x13, 0x1f, 0xb5, 0x4e, 0x29, 0x71, 0xca, 0x56, 0x5c, 0xbb, 0x51, 0x54, 0x22, 0x48, 0x0e, 0x49, + 0xac, 0x41, 0x80, 0x05, 0x80, 0x3a, 0x42, 0x63, 0x9f, 0x65, 0x9f, 0x65, 0x9f, 0xec, 0xab, 0xee, 0x9e, 0x19, 0x0c, + 0x0e, 0x1e, 0x8a, 0x9d, 0xdd, 0xaf, 0x12, 0xdb, 0xc4, 0xdc, 0xd3, 0x33, 0xd3, 0xd3, 0xd3, 0xa7, 0x3f, 0xe3, 0xbc, + 0x17, 0xb3, 0xc5, 0xf6, 0xeb, 0xee, 0xf3, 0x67, 0x66, 0xe3, 0x96, 0x04, 0x82, 0xcf, 0xce, 0xe2, 0xd9, 0x2c, 0x64, + 0x2d, 0x5d, 0x04, 0x0f, 0xd1, 0x4d, 0xd9, 0xcd, 0xd9, 0x23, 0x47, 0x78, 0xec, 0x34, 0xf2, 0x4d, 0x47, 0x4b, 0xcc, + 0x98, 0x49, 0x97, 0x76, 0x44, 0xb9, 0x22, 0x6f, 0xf6, 0x06, 0xc5, 0x1b, 0x7c, 0x5d, 0x8a, 0xa3, 0x6b, 0x4d, 0xe2, + 0xd5, 0x28, 0x64, 0x16, 0x6e, 0x77, 0xe8, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x10, 0xa5, 0xe5, 0x91, 0x63, 0x82, 0xdf, + 0x99, 0x38, 0xc5, 0xf7, 0x60, 0x6e, 0xf4, 0x61, 0x52, 0x76, 0x56, 0x1d, 0x3e, 0xe8, 0x8a, 0x00, 0xab, 0x87, 0x3a, + 0xc8, 0xe0, 0xed, 0xd7, 0x70, 0x6a, 0x07, 0xfa, 0x07, 0xd8, 0x7d, 0xa9, 0xde, 0x6f, 0x3a, 0xfa, 0x83, 0x4b, 0xfd, + 0x03, 0xc2, 0x18, 0xa3, 0x17, 0xbf, 0xa4, 0xdd, 0xab, 0x9b, 0x3a, 0x09, 0xbd, 0x57, 0x18, 0xc7, 0x00, 0x98, 0xbe, + 0xaf, 0x02, 0x7f, 0x16, 0xc5, 0x69, 0x16, 0x8c, 0xf5, 0xab, 0xfe, 0xdb, 0xa0, 0x75, 0xb9, 0xc8, 0x5a, 0xc6, 0x95, + 0x39, 0xce, 0xd4, 0x10, 0x28, 0x02, 0x61, 0x62, 0x04, 0x94, 0x4d, 0x85, 0xd4, 0x13, 0xb4, 0xb5, 0xa0, 0x40, 0xcd, + 0x58, 0x68, 0x9c, 0x0d, 0xa0, 0x5c, 0x25, 0x9e, 0x0a, 0x06, 0x86, 0xd2, 0xb1, 0xa6, 0xd1, 0xa7, 0x97, 0xca, 0xcb, + 0xd5, 0x1a, 0xaf, 0xf2, 0xac, 0xb8, 0x2d, 0xd1, 0x07, 0xb0, 0x30, 0x9c, 0xa1, 0xef, 0x47, 0xaa, 0xd2, 0x67, 0xe9, + 0xde, 0x1d, 0x7e, 0x57, 0xa6, 0x0b, 0xe0, 0xfe, 0x06, 0x8d, 0x8b, 0x28, 0xce, 0x34, 0x70, 0x6c, 0x03, 0x3d, 0x0e, + 0xab, 0x4a, 0x62, 0xbc, 0xd5, 0x96, 0x91, 0x73, 0x64, 0xf0, 0x3d, 0x5e, 0x7e, 0x2d, 0xee, 0xde, 0xac, 0xe4, 0xc1, + 0x82, 0x1e, 0x0b, 0x11, 0x2c, 0x60, 0x16, 0x9f, 0xc7, 0xb7, 0x55, 0x39, 0xc8, 0xcb, 0xe1, 0xee, 0xbb, 0xb7, 0x25, + 0xc8, 0x64, 0x11, 0xd5, 0xaf, 0xc5, 0x03, 0x93, 0x0a, 0x42, 0xa7, 0x72, 0xa6, 0x50, 0xf1, 0x43, 0xd0, 0x30, 0x19, + 0xe8, 0x89, 0xe1, 0x5d, 0x00, 0x28, 0x89, 0x5f, 0xd3, 0xc3, 0xfc, 0x5a, 0x84, 0x4e, 0x16, 0x81, 0x8b, 0x95, 0xcb, + 0x19, 0xb0, 0x6b, 0xb4, 0x5c, 0x65, 0xe8, 0x6a, 0x17, 0x06, 0xc0, 0x72, 0x5d, 0x43, 0xd7, 0x9d, 0x80, 0xa5, 0x0b, + 0x32, 0x31, 0xd7, 0xb5, 0x60, 0x52, 0x4f, 0xe3, 0x44, 0x2f, 0x20, 0x2f, 0xc4, 0xef, 0xc8, 0xa8, 0x82, 0xcf, 0x84, + 0x4f, 0x63, 0x6c, 0x16, 0x7e, 0xea, 0x5b, 0x63, 0x14, 0xe8, 0x34, 0x60, 0x86, 0x31, 0xb5, 0xd3, 0x6f, 0x85, 0x8d, + 0x93, 0x05, 0xf7, 0x9b, 0xa5, 0x69, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, 0xd6, 0xbe, + 0xd4, 0x15, 0xd0, 0x2f, 0x74, 0x52, 0x14, 0x18, 0x22, 0x18, 0x86, 0xf9, 0x75, 0x61, 0xb9, 0x53, 0xcc, 0x17, 0x76, + 0x19, 0xa5, 0x6b, 0x28, 0xba, 0x1f, 0x70, 0x01, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xf2, 0x7c, 0x53, 0x15, + 0xfa, 0x1b, 0xba, 0x46, 0x88, 0x9e, 0x00, 0x40, 0x38, 0x5f, 0xd7, 0xfe, 0x2a, 0xd3, 0x18, 0x9f, 0xad, 0x14, 0x6a, + 0x42, 0x5f, 0xd7, 0xfa, 0x73, 0x66, 0x4f, 0x58, 0xe6, 0x07, 0x21, 0x55, 0xe9, 0x8b, 0x68, 0xf5, 0xb5, 0xe9, 0xa5, + 0xe5, 0xe9, 0x45, 0xe5, 0xfd, 0x83, 0x93, 0xa1, 0x2b, 0x80, 0xc6, 0x8d, 0x33, 0xc3, 0x28, 0x56, 0xcd, 0x2b, 0x4a, + 0x79, 0xff, 0xd5, 0xe5, 0x60, 0xb0, 0x1c, 0x11, 0x2c, 0x07, 0x8b, 0xc6, 0xf1, 0x84, 0xfd, 0xf2, 0xfe, 0xad, 0x0c, + 0x9b, 0x05, 0x1c, 0xa0, 0x21, 0xdf, 0x98, 0x29, 0xd2, 0x0f, 0x09, 0xd2, 0x0e, 0x14, 0xe0, 0x4a, 0x93, 0x5b, 0x28, + 0xc9, 0x75, 0xed, 0x8c, 0xc6, 0xce, 0x26, 0x34, 0xea, 0x41, 0x8c, 0xb5, 0x92, 0xfc, 0xe4, 0x80, 0x4a, 0xd3, 0x6d, + 0x47, 0x85, 0x00, 0x0c, 0x09, 0xcc, 0xb0, 0x80, 0x02, 0x44, 0xf8, 0x1c, 0xb8, 0xc5, 0x83, 0xc2, 0x5e, 0x20, 0x9f, + 0xdd, 0x3d, 0x2b, 0x93, 0x2a, 0x58, 0x4b, 0x3f, 0x3d, 0xc1, 0x98, 0x5d, 0x70, 0x5f, 0x83, 0x97, 0x8f, 0x93, 0x03, + 0xfa, 0xd4, 0x2a, 0x27, 0xa2, 0x68, 0x44, 0x3c, 0xed, 0x7a, 0xbc, 0x81, 0x07, 0x1d, 0x15, 0x08, 0x11, 0x0f, 0xa9, + 0x7e, 0xae, 0x6b, 0x0b, 0x4e, 0x1a, 0x71, 0x77, 0x42, 0xe0, 0x6b, 0xc0, 0x81, 0xb3, 0xab, 0x6b, 0x0b, 0xff, 0x0e, + 0x67, 0x2e, 0x72, 0xfc, 0xbb, 0x96, 0xcb, 0xb3, 0x8a, 0xb3, 0x96, 0x96, 0xcf, 0xda, 0x98, 0x2f, 0x2e, 0x18, 0x12, + 0xc8, 0x97, 0xf5, 0x1c, 0x05, 0xb4, 0x0d, 0x8b, 0x3b, 0x17, 0x8b, 0x3b, 0xd9, 0xb0, 0xb8, 0x93, 0x2d, 0x8b, 0x1b, + 0xf2, 0x85, 0xd4, 0x24, 0xe8, 0x12, 0x34, 0x0e, 0x93, 0xc0, 0xe3, 0x84, 0x46, 0x8f, 0x9f, 0x33, 0x84, 0x93, 0x95, + 0x86, 0xa0, 0x1c, 0xb5, 0x01, 0x56, 0x4d, 0x70, 0x51, 0x00, 0x51, 0x9f, 0xb8, 0x3c, 0x75, 0x62, 0xde, 0x10, 0x83, + 0xb3, 0x15, 0x56, 0xe7, 0x0b, 0xbb, 0x94, 0xe2, 0x8b, 0xb7, 0xe6, 0x1b, 0x66, 0x3a, 0xdf, 0x32, 0xd3, 0x71, 0xe9, + 0xe8, 0xf2, 0x69, 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0x14, 0x46, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x1c, + 0xab, 0xec, 0xa8, 0xa5, 0x9f, 0xa6, 0xb7, 0x71, 0x02, 0x12, 0x17, 0x68, 0xe6, 0x61, 0x5b, 0x6a, 0x11, 0x44, 0xdc, + 0x99, 0xcb, 0xc6, 0xcd, 0x54, 0xe4, 0xab, 0x5b, 0xca, 0xeb, 0x74, 0xa8, 0xc4, 0xd2, 0xcf, 0x32, 0x96, 0x20, 0xd0, + 0x7d, 0xf0, 0xfa, 0xfd, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0x50, 0xc1, 0xea, 0x88, 0xa1, 0x97, 0x40, 0x5b, 0x25, + 0xe2, 0x22, 0x56, 0x1c, 0xc3, 0x25, 0x12, 0xf0, 0x3f, 0xe1, 0x71, 0x6d, 0x25, 0x8a, 0xe9, 0x92, 0x7b, 0x64, 0xd8, + 0x4b, 0x7f, 0xf2, 0x01, 0x04, 0x7b, 0x2d, 0xcf, 0x04, 0x25, 0x5d, 0xd5, 0x0d, 0x5c, 0x42, 0xc4, 0xde, 0xb8, 0x40, + 0x92, 0x88, 0x25, 0xb9, 0x0a, 0x14, 0x58, 0x4f, 0xfa, 0xd6, 0xf4, 0x6a, 0xed, 0xe5, 0x07, 0xb3, 0xc0, 0xa8, 0x61, + 0x4d, 0x40, 0x6d, 0xe1, 0xe0, 0x54, 0xbe, 0xb9, 0x42, 0xd3, 0x3d, 0x32, 0x80, 0xf3, 0x7b, 0x09, 0xf1, 0x4c, 0x1d, + 0xf1, 0xa0, 0x1d, 0x26, 0x70, 0x6b, 0x5d, 0x3a, 0x57, 0xf9, 0xd3, 0x19, 0xfe, 0x72, 0xaf, 0xf2, 0xa7, 0x23, 0xfc, + 0xe5, 0x5d, 0x61, 0xe4, 0xba, 0x86, 0x87, 0xbc, 0x32, 0x67, 0xfd, 0xb4, 0xb4, 0x9f, 0x48, 0xff, 0xec, 0x01, 0xdb, + 0x86, 0x2f, 0xf0, 0xe3, 0x27, 0xeb, 0x14, 0x2c, 0x2e, 0xd5, 0x39, 0x44, 0x76, 0x62, 0xe4, 0x8d, 0xe9, 0xb3, 0x0d, + 0xe9, 0x23, 0xe3, 0xbf, 0x7c, 0xf1, 0xe3, 0x2e, 0x89, 0x8b, 0x3b, 0xa5, 0xcc, 0x86, 0xb8, 0x1e, 0x05, 0x91, 0x9f, + 0xdc, 0x5f, 0xd3, 0xf3, 0xa2, 0x25, 0x68, 0x77, 0xc9, 0x5e, 0x21, 0xf2, 0xb2, 0x2c, 0xee, 0xca, 0x14, 0x06, 0xef, + 0x3d, 0xbf, 0xe8, 0x07, 0x7f, 0x4f, 0x14, 0xb2, 0xad, 0xf4, 0x00, 0xe5, 0x0b, 0x52, 0xea, 0xe8, 0xfa, 0xc9, 0xba, + 0xc5, 0xea, 0xcd, 0x54, 0x66, 0x5b, 0xa1, 0x0b, 0x61, 0x79, 0xf0, 0x31, 0xbb, 0x98, 0x04, 0x3d, 0x94, 0x67, 0x8d, + 0xe2, 0x3b, 0xeb, 0xc9, 0x3a, 0x3b, 0xd3, 0x17, 0x7e, 0xf2, 0x89, 0x4d, 0xac, 0x71, 0x90, 0x8c, 0x43, 0xa6, 0xf7, + 0xf4, 0x51, 0xe8, 0x47, 0x9f, 0xf8, 0xa7, 0x15, 0xaf, 0x32, 0x94, 0x50, 0xef, 0x7c, 0xfb, 0x0a, 0x98, 0x10, 0xcb, + 0x0e, 0x89, 0xd5, 0x06, 0x28, 0x68, 0x2f, 0x25, 0xc3, 0xab, 0x20, 0x14, 0x8b, 0x52, 0x26, 0x28, 0x58, 0x82, 0xd0, + 0x1c, 0x2c, 0x56, 0x4d, 0x1d, 0xd7, 0x4b, 0x37, 0xd5, 0xa9, 0x12, 0xb3, 0x52, 0x86, 0x5c, 0xbc, 0xc6, 0x16, 0xfe, + 0x78, 0x77, 0x14, 0x0c, 0x7b, 0xff, 0xee, 0x64, 0x2b, 0x5f, 0x36, 0x43, 0x48, 0xb5, 0xc8, 0x52, 0xe2, 0x01, 0x9d, + 0x73, 0x02, 0x73, 0x73, 0xd7, 0x6a, 0x65, 0x3f, 0x4d, 0x57, 0x0b, 0x36, 0x21, 0xc9, 0xe0, 0x59, 0x31, 0xa8, 0xf2, + 0xcb, 0x42, 0x1d, 0xd8, 0x6f, 0x2b, 0xef, 0xf8, 0xf0, 0x25, 0x68, 0x2c, 0x00, 0x41, 0x19, 0x4f, 0xa7, 0x7a, 0xf1, + 0xc6, 0xdf, 0x51, 0xcd, 0x3d, 0xfc, 0x6d, 0xf5, 0xe6, 0xb5, 0xf3, 0x46, 0x56, 0x8e, 0x80, 0x30, 0x16, 0xe2, 0x57, + 0x4e, 0x17, 0x2b, 0xe3, 0x15, 0x33, 0x9a, 0xfa, 0xd1, 0xe6, 0xe9, 0x5c, 0x96, 0xb6, 0xf8, 0x92, 0xb1, 0x09, 0x10, + 0xdc, 0x66, 0x2d, 0xf5, 0x3a, 0x64, 0x37, 0x4c, 0x8a, 0x76, 0xeb, 0x9d, 0x35, 0xd4, 0x40, 0xdf, 0x73, 0x5c, 0x64, + 0xcc, 0xa9, 0x3a, 0x65, 0x4a, 0x43, 0x9c, 0x03, 0x9f, 0xb9, 0x7a, 0xc4, 0x2a, 0x47, 0x6a, 0x68, 0xea, 0xca, 0x00, + 0x36, 0x8e, 0xec, 0x6c, 0x43, 0x7a, 0x0f, 0x03, 0x4f, 0x37, 0x8f, 0xcd, 0x74, 0x8d, 0x1e, 0xf8, 0xea, 0xe6, 0x70, + 0x0a, 0xe1, 0xe4, 0xb5, 0x0a, 0x76, 0xc8, 0x26, 0x88, 0x35, 0x31, 0xc9, 0x74, 0xe2, 0xbe, 0x08, 0x6d, 0x47, 0x54, + 0xfb, 0x15, 0x7c, 0xa8, 0xc6, 0xb5, 0xd1, 0xca, 0x33, 0x1f, 0x61, 0x40, 0xd7, 0x88, 0xa5, 0xe9, 0x46, 0x80, 0xc9, + 0x45, 0x37, 0xf5, 0xa2, 0x74, 0x19, 0x1e, 0x45, 0xba, 0xe9, 0x98, 0x40, 0x12, 0xe0, 0x04, 0xab, 0x7d, 0xe1, 0xf5, + 0x72, 0xbd, 0xe0, 0xfa, 0x2a, 0xc9, 0x6c, 0xa4, 0x73, 0x5d, 0x82, 0x4d, 0xf9, 0xb7, 0x3a, 0x1f, 0x54, 0xe9, 0x9a, + 0x6e, 0x1c, 0x5a, 0xab, 0x84, 0x7a, 0x6b, 0xec, 0x22, 0x6c, 0x40, 0x8c, 0xa9, 0x82, 0x5f, 0xd9, 0x74, 0xca, 0xc6, + 0x59, 0x6a, 0x08, 0xe6, 0x91, 0xf4, 0x1e, 0x0b, 0x56, 0x43, 0x8f, 0x06, 0xfa, 0x4f, 0x60, 0x43, 0x2f, 0x9c, 0x2c, + 0xf1, 0x01, 0x89, 0x37, 0x53, 0x33, 0x98, 0xa8, 0xc5, 0x32, 0x88, 0x78, 0x2f, 0x10, 0x1c, 0xbc, 0x21, 0x1d, 0x87, + 0xc6, 0xef, 0x9f, 0x62, 0x5f, 0xc4, 0x52, 0xab, 0x65, 0x3b, 0x2a, 0xda, 0x76, 0x7c, 0xd7, 0xee, 0x9b, 0x8e, 0xeb, + 0xe4, 0xba, 0x09, 0xb6, 0x5b, 0x9f, 0xf6, 0x3d, 0xf4, 0x58, 0xab, 0x0d, 0xb5, 0x56, 0xd1, 0x43, 0xea, 0x79, 0xee, + 0x0b, 0x57, 0x37, 0x49, 0x65, 0x4e, 0xc1, 0x6d, 0xe3, 0xf8, 0x86, 0x25, 0x5f, 0x3c, 0x95, 0x72, 0xe3, 0xfb, 0x8d, + 0xe7, 0xc8, 0x75, 0x00, 0x09, 0x67, 0xf1, 0xf2, 0x01, 0x53, 0x68, 0xeb, 0xa6, 0x3e, 0x0e, 0xe3, 0x94, 0xa9, 0x73, + 0x20, 0x26, 0xc8, 0x17, 0x4e, 0xe2, 0xe7, 0xf7, 0xaf, 0x3f, 0x7c, 0xd0, 0x4d, 0x8c, 0x04, 0x9a, 0xaa, 0xad, 0xf3, + 0x0d, 0xb5, 0x03, 0xfb, 0x37, 0xee, 0x3b, 0xba, 0x61, 0xe8, 0x51, 0x5b, 0xde, 0x73, 0x94, 0x56, 0xdb, 0x72, 0xfc, + 0xe6, 0xe1, 0x3d, 0xd3, 0x4b, 0x74, 0xaf, 0x79, 0x35, 0xe0, 0x86, 0xed, 0xd7, 0x5b, 0x29, 0x65, 0x11, 0x44, 0xd7, + 0x0d, 0xa9, 0xfe, 0x5d, 0x43, 0x2a, 0x3c, 0xe5, 0x6a, 0xb8, 0x6a, 0x15, 0x2f, 0x14, 0xd2, 0x00, 0x02, 0x39, 0xef, + 0x02, 0x97, 0xf2, 0x9e, 0xfa, 0x82, 0x41, 0x73, 0x4f, 0xee, 0xd5, 0x51, 0x37, 0x24, 0xf3, 0x47, 0x90, 0x84, 0xed, + 0x38, 0x04, 0x85, 0x3f, 0xa6, 0x4a, 0xe5, 0xca, 0x64, 0xa3, 0x54, 0xd7, 0x55, 0x1a, 0x21, 0xf2, 0xf6, 0x3a, 0x63, + 0x8b, 0x25, 0x4b, 0xfc, 0x6c, 0x95, 0xb0, 0xeb, 0x30, 0xbe, 0x7d, 0x54, 0xa8, 0xd3, 0xef, 0x28, 0x3c, 0x0f, 0x66, + 0x73, 0x59, 0xfa, 0xac, 0xc5, 0x06, 0x72, 0x01, 0xb7, 0x76, 0x90, 0xff, 0xe7, 0xdf, 0xb6, 0xfd, 0x9f, 0x7f, 0xef, + 0x2c, 0x0a, 0xcd, 0xe7, 0x43, 0x33, 0x1b, 0xec, 0xb1, 0x2f, 0x9a, 0x7b, 0x2a, 0xc3, 0xbc, 0xb9, 0x4c, 0x6d, 0x11, + 0x20, 0xbf, 0xb6, 0x04, 0xb5, 0xc4, 0xf2, 0xbe, 0x79, 0xd0, 0xc0, 0x60, 0x5e, 0x3b, 0x47, 0x06, 0x85, 0xbe, 0x68, + 0x68, 0x43, 0xa3, 0xb7, 0xd7, 0x8a, 0xfc, 0x71, 0x08, 0xef, 0x9a, 0xc3, 0x17, 0x0e, 0x9f, 0xf3, 0x25, 0x5f, 0x0e, + 0x87, 0x32, 0xb6, 0x9c, 0x5a, 0x15, 0x54, 0xfc, 0xcf, 0x6a, 0x29, 0xfc, 0xf2, 0xec, 0x39, 0x06, 0xd9, 0xde, 0x0f, + 0x5e, 0x0e, 0x51, 0x19, 0xed, 0x64, 0x94, 0x14, 0xc4, 0xca, 0x46, 0xd4, 0x46, 0xca, 0xe4, 0xb5, 0x46, 0x6b, 0x78, + 0x0d, 0x52, 0x31, 0xe0, 0x58, 0x3e, 0x34, 0xcc, 0x97, 0x43, 0xce, 0x58, 0xe2, 0xfa, 0xaf, 0xbd, 0xea, 0xd6, 0xe6, + 0x6c, 0xd9, 0x12, 0xd0, 0x4d, 0x8d, 0xe4, 0x3f, 0x58, 0x98, 0x15, 0x7c, 0x3c, 0x64, 0xf0, 0x03, 0x47, 0x61, 0x98, + 0x63, 0xbc, 0x93, 0x77, 0x9b, 0x74, 0xc4, 0x7e, 0xde, 0xad, 0x23, 0x76, 0xb1, 0x97, 0x8e, 0xd8, 0xcf, 0x5f, 0x5d, + 0x47, 0xec, 0x9d, 0xaa, 0x23, 0x06, 0x8b, 0xf8, 0x9a, 0xed, 0xa5, 0xb8, 0x25, 0xb4, 0x36, 0xe2, 0xdb, 0x74, 0xe0, + 0x72, 0x92, 0x36, 0x1d, 0xcf, 0x19, 0xf0, 0x08, 0xf8, 0xaa, 0x84, 0xf1, 0x0c, 0x94, 0xb8, 0xfe, 0x7c, 0x75, 0xab, + 0x30, 0x9e, 0xa9, 0xca, 0x56, 0x11, 0xf7, 0xf8, 0x5a, 0x78, 0x71, 0x22, 0x05, 0x27, 0xc7, 0x14, 0x3e, 0x9f, 0xac, + 0x43, 0x43, 0x89, 0x6a, 0x2d, 0xb5, 0xd7, 0x3c, 0xa1, 0x02, 0xd5, 0x43, 0xed, 0x29, 0x59, 0xd1, 0x7b, 0x2e, 0x7c, + 0x5b, 0xa8, 0x2d, 0x48, 0x2d, 0x61, 0xf2, 0x13, 0xb1, 0xd6, 0x7f, 0xbb, 0x73, 0xbf, 0xbf, 0x74, 0xfb, 0x6d, 0x17, + 0x8c, 0xb3, 0xe1, 0x85, 0x89, 0x09, 0x4e, 0xbf, 0xdd, 0x86, 0x84, 0x5b, 0x25, 0xc1, 0x83, 0x84, 0x40, 0x49, 0xe8, + 0x40, 0xc2, 0x58, 0x49, 0x38, 0x82, 0x84, 0x89, 0x92, 0x70, 0x0c, 0x09, 0x37, 0x7a, 0x7e, 0x19, 0xc9, 0xe1, 0x1e, + 0x1b, 0x57, 0x26, 0x3d, 0x2a, 0x44, 0xda, 0xb1, 0xe9, 0x82, 0xd6, 0x94, 0x3f, 0xeb, 0xc5, 0x26, 0x71, 0x17, 0x7b, + 0x89, 0x79, 0x3b, 0x67, 0xe4, 0x28, 0xfa, 0x15, 0xde, 0x39, 0x76, 0x16, 0x83, 0xde, 0xb4, 0x70, 0xc0, 0x20, 0xe0, + 0xa0, 0xe9, 0x06, 0x30, 0x8c, 0xfa, 0x72, 0xe5, 0x84, 0x13, 0x0b, 0x65, 0x2d, 0x8b, 0x3c, 0xea, 0xce, 0x92, 0x5b, + 0xa0, 0xd0, 0x38, 0x69, 0xa9, 0x5c, 0xc9, 0xaf, 0xa1, 0x77, 0xf0, 0x8a, 0x8d, 0x56, 0x33, 0xed, 0x3c, 0x9e, 0xed, + 0x54, 0x21, 0x50, 0xb3, 0x60, 0x94, 0x3a, 0x89, 0x5f, 0x2c, 0xb1, 0x2d, 0x79, 0x5f, 0xf4, 0x99, 0x97, 0xcb, 0x67, + 0x30, 0x36, 0x2d, 0x23, 0x05, 0x16, 0xe8, 0x07, 0x60, 0xa4, 0xc8, 0xf0, 0xcf, 0x01, 0xce, 0xca, 0xf7, 0x85, 0xaf, + 0x8c, 0xe7, 0xf4, 0x47, 0x96, 0xa6, 0xfe, 0x4c, 0x94, 0xaf, 0x8f, 0x13, 0x94, 0x76, 0xe4, 0xfb, 0x0b, 0x01, 0x08, + 0x9c, 0xbc, 0xa0, 0xa6, 0x9b, 0x91, 0xc4, 0xb7, 0x1a, 0x68, 0xff, 0xc0, 0x86, 0x2a, 0xf4, 0x14, 0x02, 0x1b, 0x96, + 0xb0, 0xac, 0x51, 0x00, 0x87, 0xff, 0x86, 0x85, 0xd5, 0xc4, 0xcc, 0x9f, 0x55, 0x93, 0x68, 0x1f, 0xe4, 0xea, 0xd8, + 0xa4, 0x40, 0xbf, 0x94, 0xf8, 0x25, 0x12, 0xea, 0x30, 0x9e, 0xfd, 0xa9, 0xe2, 0xe9, 0x2d, 0x6a, 0x05, 0x1f, 0x22, + 0x33, 0xc8, 0x86, 0x36, 0xc2, 0x58, 0xb3, 0x01, 0x84, 0xbd, 0x28, 0x9b, 0x5b, 0x68, 0x5a, 0xd6, 0xf2, 0x22, 0xc3, + 0xb4, 0x71, 0x6d, 0xd7, 0x55, 0x83, 0xda, 0x5e, 0x32, 0x1b, 0xf9, 0x2d, 0xd7, 0x3b, 0x36, 0xc5, 0x1f, 0xdb, 0xe9, + 0x18, 0x39, 0xb6, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, 0xbe, 0xb7, 0x88, + 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x1e, 0xd4, 0x7d, 0x74, 0xd5, 0xc0, 0xad, 0x05, 0x5d, 0xdb, 0x4b, 0xd8, + 0x82, 0x6a, 0x4b, 0x4f, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xbc, 0xfb, 0x52, 0x61, 0x2a, 0x8a, 0x5b, 0x8e, 0x6a, 0x00, + 0x45, 0xca, 0xdd, 0x3c, 0x80, 0x73, 0xa3, 0xfe, 0xd2, 0x9f, 0xa0, 0x67, 0x42, 0xdb, 0xeb, 0x24, 0x6c, 0xa1, 0xd9, + 0x9d, 0x8d, 0x8d, 0x27, 0xf1, 0xed, 0x29, 0x8c, 0x16, 0x2b, 0x5b, 0x29, 0x0b, 0xa7, 0x98, 0x63, 0xa1, 0x65, 0x89, + 0x68, 0xc7, 0xc2, 0x87, 0x38, 0xb4, 0xc6, 0x16, 0x7d, 0xc8, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, 0x91, 0x45, 0xd3, + 0x39, 0x76, 0x96, 0x4a, 0x5b, 0x2a, 0xfc, 0x8c, 0x35, 0x16, 0x77, 0x35, 0xa7, 0x0f, 0x8f, 0xb5, 0x69, 0x18, 0xdf, + 0xf6, 0xe6, 0xc1, 0x64, 0xc2, 0xa2, 0x3e, 0x8e, 0x59, 0x26, 0xb2, 0x30, 0x0c, 0x96, 0x69, 0x90, 0xf6, 0x17, 0xfe, + 0x1d, 0x6f, 0xf5, 0x70, 0x53, 0xab, 0x6d, 0xde, 0x6a, 0x7b, 0xef, 0x56, 0x95, 0x66, 0xc0, 0x8a, 0x85, 0xda, 0xe1, + 0x43, 0xeb, 0x68, 0x4e, 0x65, 0x9e, 0x7b, 0xb7, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, 0x39, 0xb9, + 0x7d, 0xb3, 0xa6, 0x8d, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x7c, 0x39, 0x93, 0x49, 0x6e, 0x8f, 0xc5, 0xd7, + 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0x22, 0xa1, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, 0x12, 0xb9, + 0xcd, 0xf8, 0x57, 0xc2, 0x26, 0x7d, 0xdc, 0x48, 0xa4, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x31, 0xc0, 0x65, 0x09, + 0x37, 0x21, 0xaf, 0xe7, 0x6a, 0xbd, 0x77, 0x49, 0xad, 0xe8, 0x6e, 0x3c, 0x6e, 0x2c, 0x37, 0xf1, 0x93, 0x4f, 0x57, + 0x9a, 0x32, 0x0b, 0xdf, 0xa7, 0x62, 0x6b, 0x01, 0x06, 0xeb, 0xae, 0x07, 0x2e, 0xbb, 0xfa, 0xa3, 0x38, 0x81, 0x33, + 0x9b, 0xf8, 0x93, 0x60, 0x95, 0xf6, 0x5c, 0x6f, 0x79, 0x27, 0x92, 0xf8, 0x5e, 0x2f, 0x12, 0xf0, 0xec, 0xf5, 0xd2, + 0x38, 0x0c, 0x26, 0x22, 0x69, 0xd3, 0x59, 0x72, 0x3d, 0xa3, 0x8f, 0x06, 0xeb, 0x01, 0xba, 0x5d, 0xf0, 0xc3, 0x50, + 0xb3, 0xdb, 0xa9, 0xc6, 0xfc, 0x14, 0xf9, 0xcb, 0x9a, 0x93, 0x12, 0x5c, 0xd0, 0x38, 0xdd, 0x3d, 0x5c, 0xde, 0xc9, + 0x3d, 0xef, 0x1e, 0x2d, 0xef, 0xf2, 0xbf, 0x2e, 0xd8, 0x24, 0xf0, 0xb5, 0x56, 0xb1, 0x9b, 0x5c, 0x07, 0x78, 0xd0, + 0xc6, 0x7a, 0xc3, 0x36, 0x15, 0xc7, 0x02, 0x5c, 0x1b, 0x3e, 0x0a, 0x16, 0xcb, 0x38, 0xc9, 0xfc, 0x28, 0xcb, 0xf3, + 0xe1, 0x55, 0x9e, 0xf7, 0x2f, 0x82, 0xd6, 0xe5, 0x3f, 0x5a, 0x74, 0x4f, 0x93, 0xcc, 0x26, 0x37, 0xae, 0xcc, 0xd7, + 0x4c, 0xd5, 0x19, 0x81, 0x6b, 0x0c, 0xf5, 0x45, 0xd4, 0xc2, 0x74, 0x4b, 0xd6, 0x0b, 0x13, 0x90, 0x65, 0x71, 0xd2, + 0x41, 0x29, 0x17, 0xc1, 0x1b, 0x08, 0x0a, 0xbc, 0x66, 0x83, 0x0b, 0x45, 0xff, 0x04, 0x88, 0x15, 0x2c, 0x4c, 0x76, + 0x05, 0x4f, 0x36, 0xd1, 0x8c, 0xdf, 0xed, 0xa6, 0x19, 0x7f, 0xcd, 0xf6, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, + 0x93, 0xba, 0x5d, 0xc1, 0xdb, 0x78, 0xa0, 0x4b, 0x09, 0x03, 0x5c, 0x4d, 0x09, 0x79, 0xec, 0x79, 0xfb, 0x87, 0xcd, + 0x00, 0x44, 0x6b, 0x14, 0x83, 0x8e, 0x6e, 0x6e, 0xe0, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xef, 0xe9, 0x74, + 0xf0, 0x2a, 0x56, 0x12, 0xe4, 0x17, 0x57, 0xbe, 0x28, 0x79, 0x57, 0xa0, 0x1c, 0xa1, 0x85, 0x89, 0xf1, 0x27, 0xc0, + 0x38, 0x9b, 0xb4, 0x8e, 0x27, 0x52, 0xfb, 0xac, 0x5f, 0x1e, 0x42, 0x4b, 0xaa, 0x7c, 0x0a, 0x13, 0x9c, 0x1a, 0x2b, + 0x71, 0xc6, 0x32, 0x6e, 0x33, 0xfb, 0xfd, 0xfd, 0xdb, 0x49, 0xeb, 0x6d, 0x6c, 0xe4, 0x41, 0xfa, 0xae, 0x6a, 0x00, + 0xc3, 0x65, 0x3f, 0x03, 0x75, 0x3a, 0x39, 0xd7, 0x20, 0x53, 0x03, 0x4c, 0x43, 0x36, 0x55, 0x3f, 0x2b, 0xcd, 0xb4, + 0xa7, 0x56, 0xe4, 0x81, 0xae, 0x6a, 0x97, 0x31, 0xb7, 0x3e, 0x58, 0x73, 0x0a, 0x10, 0x63, 0x77, 0xa1, 0xdd, 0xf0, + 0x84, 0xaa, 0x07, 0x93, 0x3c, 0x37, 0xfa, 0x02, 0x10, 0xca, 0x45, 0xcb, 0x76, 0x11, 0x71, 0xe9, 0xad, 0xd4, 0x69, + 0xe0, 0x12, 0x42, 0x12, 0xff, 0xbd, 0x05, 0x81, 0x3a, 0x17, 0x16, 0x72, 0x98, 0xe9, 0x1a, 0x81, 0x8f, 0x14, 0x2d, + 0x94, 0x09, 0x81, 0x04, 0x58, 0xc2, 0x5f, 0x64, 0x89, 0x84, 0xba, 0x0e, 0x27, 0x01, 0x07, 0x35, 0x02, 0xc0, 0xca, + 0x5f, 0xf0, 0xb5, 0x09, 0xed, 0xf0, 0x32, 0xf8, 0x91, 0xeb, 0x92, 0xf6, 0xc3, 0xed, 0x77, 0x7a, 0x72, 0x00, 0x15, + 0x4e, 0x2b, 0x8a, 0x03, 0x3b, 0x34, 0x14, 0x81, 0x94, 0x48, 0x6f, 0x4d, 0x3b, 0xbd, 0xd5, 0x9e, 0xad, 0x85, 0x87, + 0x8c, 0xcc, 0x5f, 0x5a, 0xf0, 0xc4, 0x47, 0xdc, 0xcb, 0x31, 0x9e, 0xe2, 0x8c, 0xa3, 0xbf, 0x4a, 0x01, 0x37, 0xe2, + 0x43, 0x15, 0xf1, 0x4f, 0x7f, 0xbc, 0x4a, 0xd2, 0x38, 0xe9, 0x2d, 0xe3, 0x20, 0xca, 0x58, 0x92, 0x23, 0xa8, 0x2e, + 0x11, 0x3e, 0x02, 0x3c, 0x57, 0xeb, 0x78, 0xe9, 0x8f, 0x83, 0xec, 0xbe, 0xe7, 0x70, 0x92, 0xc2, 0xe9, 0x73, 0xea, + 0xc0, 0x69, 0x2c, 0xdf, 0xe3, 0xd0, 0x7c, 0x8e, 0x84, 0x5f, 0x52, 0x27, 0x67, 0xd4, 0x6d, 0xde, 0x57, 0x72, 0xc9, + 0x47, 0x08, 0x90, 0x1f, 0x7e, 0x62, 0xcd, 0x00, 0xcb, 0xc3, 0x52, 0x3b, 0x13, 0x36, 0x33, 0x11, 0x6b, 0x03, 0x5f, + 0x5e, 0xfc, 0xb1, 0x3b, 0x86, 0xe6, 0x34, 0x27, 0x03, 0xc5, 0x63, 0xec, 0x33, 0xb2, 0x9e, 0x0f, 0x11, 0xb5, 0xcc, + 0x7d, 0x4a, 0x8e, 0xd8, 0x34, 0x4e, 0x18, 0xf9, 0x93, 0x75, 0xbb, 0xcb, 0xbb, 0xfd, 0x9b, 0xdf, 0x3e, 0xfd, 0xe6, + 0x76, 0xa2, 0x38, 0x6b, 0x89, 0xc6, 0x8c, 0x1d, 0xad, 0xd5, 0xef, 0x33, 0x20, 0x0d, 0x09, 0xf2, 0x63, 0x72, 0xdd, + 0xd5, 0xd3, 0xf5, 0x7e, 0xa3, 0xdb, 0xae, 0x65, 0xcc, 0xef, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, 0x9a, 0xb1, + 0x7d, 0xb4, 0xbc, 0x13, 0x6b, 0x8c, 0x17, 0xde, 0x03, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, 0xd5, 0x64, 0x5c, 0xa4, + 0x7e, 0x6d, 0x36, 0xc2, 0x93, 0x45, 0xe5, 0xa6, 0xef, 0x2c, 0xef, 0xd4, 0x2b, 0xba, 0xa8, 0x26, 0x6f, 0xea, 0xaa, + 0x0b, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x2d, 0x74, 0x79, 0x2d, 0x15, 0xe0, 0x48, 0x38, 0xf8, 0xa3, 0x34, + 0x0e, 0x57, 0x19, 0x6b, 0x06, 0x17, 0x01, 0xc7, 0x73, 0x0a, 0xe0, 0xe0, 0xef, 0xf2, 0x58, 0x3b, 0x40, 0x6e, 0xc3, + 0x36, 0x71, 0xfa, 0xe0, 0x71, 0xd8, 0x6a, 0x97, 0x87, 0x0e, 0x59, 0x72, 0xd0, 0x66, 0xc3, 0x44, 0x4c, 0xb8, 0x96, + 0x08, 0x7b, 0x6b, 0xb6, 0xcb, 0xd3, 0xa4, 0xd7, 0x55, 0x99, 0x94, 0x97, 0x27, 0xf3, 0xe7, 0x9c, 0xb1, 0x17, 0xcd, + 0x67, 0xec, 0x85, 0x38, 0x63, 0xdb, 0x77, 0xe6, 0xe3, 0xa9, 0x0b, 0xff, 0xf5, 0x8b, 0x09, 0xf5, 0x1c, 0xad, 0xbd, + 0xbc, 0xd3, 0xdc, 0xe5, 0x9d, 0x66, 0x79, 0xcb, 0x3b, 0x0d, 0x9b, 0x46, 0x7d, 0x10, 0xd3, 0xf6, 0x0c, 0xd3, 0xd1, + 0x20, 0x11, 0xfe, 0x38, 0xa5, 0x2c, 0xf7, 0x10, 0xf2, 0xa0, 0x56, 0xa7, 0x9e, 0xe7, 0x6d, 0x3f, 0xea, 0x74, 0x96, + 0x04, 0xd2, 0x36, 0xec, 0xcc, 0x1f, 0x8d, 0xd8, 0xa4, 0x37, 0x8d, 0xc7, 0xab, 0xf4, 0x5f, 0x7c, 0xfc, 0x1c, 0x88, + 0x5b, 0x11, 0x41, 0xa5, 0x1d, 0x51, 0x15, 0x04, 0x25, 0x37, 0x4c, 0xb4, 0xb0, 0x96, 0xeb, 0xd4, 0x23, 0xf7, 0xc8, + 0x9e, 0x7d, 0xd8, 0xb0, 0xc9, 0x9b, 0x01, 0xfd, 0xa7, 0xad, 0xd2, 0x66, 0x14, 0xf3, 0x05, 0x60, 0xd9, 0x0a, 0x8e, + 0x87, 0x43, 0x83, 0xaf, 0xa6, 0xd3, 0x6d, 0x1e, 0xee, 0xa5, 0xe8, 0xe9, 0x4a, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0x86, + 0x29, 0xdb, 0x5b, 0xdd, 0xb4, 0x47, 0x6a, 0xad, 0x6e, 0xb9, 0x10, 0x8a, 0xb2, 0x7b, 0x62, 0xf9, 0xc7, 0x2f, 0x0e, + 0xe1, 0x3f, 0xa2, 0xea, 0x7f, 0xcd, 0x9a, 0x08, 0xf5, 0xb7, 0x65, 0x4d, 0x70, 0x22, 0x95, 0x90, 0x10, 0xdf, 0xbf, + 0xfc, 0x74, 0xfa, 0xb0, 0x0a, 0x7b, 0x97, 0x26, 0x55, 0xaa, 0x6a, 0xe9, 0xef, 0xe3, 0x18, 0x42, 0x77, 0xd6, 0x8b, + 0x0b, 0xf0, 0x90, 0xb2, 0x7b, 0x36, 0x80, 0x4a, 0xe2, 0x1d, 0x41, 0x52, 0x7c, 0x1d, 0xeb, 0xd0, 0x53, 0xe2, 0xf5, + 0xa6, 0xa7, 0xc4, 0xab, 0xdd, 0x4f, 0x89, 0x1f, 0xf6, 0x7a, 0x4a, 0xbc, 0xfa, 0xea, 0x4f, 0x89, 0xd7, 0xf5, 0xa7, + 0xc4, 0x45, 0x2c, 0xf4, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x09, 0xe5, 0xce, 0xe3, 0x41, 0xc7, 0x21, 0x97, + 0xc7, 0x17, 0x7f, 0xf8, 0x61, 0x81, 0x1b, 0xf1, 0x3d, 0xaa, 0x93, 0x15, 0x4f, 0x0b, 0x8e, 0xd9, 0xb1, 0x1f, 0x25, + 0x39, 0x8c, 0xa3, 0xd9, 0xcf, 0x20, 0x94, 0x05, 0x76, 0x60, 0xa2, 0x64, 0x04, 0xe9, 0xcf, 0xf1, 0x72, 0xb5, 0x7c, + 0x0b, 0x6d, 0x7d, 0x0c, 0xd2, 0x60, 0x14, 0x32, 0x69, 0x89, 0x4c, 0xea, 0x6f, 0x9c, 0x27, 0x0e, 0x1a, 0xa7, 0xe2, + 0xa7, 0x7f, 0x27, 0x7e, 0xa2, 0x4e, 0x2a, 0xff, 0x4d, 0x7a, 0x75, 0x7a, 0xf3, 0x43, 0x44, 0x08, 0x01, 0x95, 0x41, + 0x3f, 0xfc, 0x31, 0x72, 0x11, 0x1b, 0x0d, 0xb3, 0x14, 0xfa, 0x0e, 0x1b, 0xdb, 0x61, 0xb5, 0x47, 0xcd, 0xca, 0x30, + 0xa5, 0x0b, 0xae, 0x3a, 0x1b, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x91, 0x01, 0x48, + 0x38, 0x65, 0x1d, 0x0c, 0x1e, 0xf9, 0x01, 0x09, 0xe5, 0x38, 0x69, 0xe9, 0x10, 0xbb, 0x74, 0xb5, 0xb4, 0x48, 0xd4, + 0x6c, 0xe1, 0x14, 0x75, 0x19, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0x56, 0x53, 0xa8, 0x6a, 0xc4, 0x36, 0xe7, + 0x0a, 0xa7, 0xad, 0x48, 0x30, 0x17, 0x85, 0x1f, 0x8c, 0x86, 0x85, 0xe3, 0x39, 0x64, 0xba, 0x5a, 0xe4, 0x82, 0x17, + 0x91, 0x7c, 0xc5, 0xd7, 0x83, 0x7b, 0x85, 0xa0, 0xcf, 0x97, 0x0a, 0x18, 0xdf, 0xdd, 0xb0, 0x24, 0xf4, 0xef, 0x5b, + 0x46, 0x1e, 0x47, 0x3f, 0x02, 0x00, 0x5e, 0xc5, 0xb7, 0x91, 0x5a, 0x00, 0x83, 0xb5, 0x34, 0xec, 0xa5, 0x46, 0xff, + 0x25, 0x60, 0xb8, 0xa2, 0x8c, 0x00, 0xc2, 0xe4, 0xce, 0xd8, 0xdf, 0x4d, 0xfa, 0xf7, 0x1f, 0x46, 0x6e, 0x9e, 0xc7, + 0xb2, 0xa3, 0x5f, 0x96, 0x7b, 0x74, 0xf3, 0xf4, 0xe9, 0xa3, 0xcd, 0xd3, 0x2e, 0x87, 0x67, 0x6f, 0xa8, 0x6d, 0x6c, + 0x3c, 0x05, 0x30, 0x8a, 0x8b, 0x78, 0x35, 0x9e, 0xa3, 0xa2, 0xeb, 0xd7, 0x9b, 0x6f, 0x06, 0x6d, 0x62, 0x94, 0x52, + 0x39, 0xf5, 0x4a, 0x52, 0x01, 0x05, 0xec, 0xff, 0x35, 0x38, 0xe0, 0xfc, 0x1f, 0x82, 0xa1, 0xbe, 0x6b, 0xf8, 0x2b, + 0x3e, 0x78, 0xd8, 0xe6, 0xed, 0x43, 0x30, 0x4d, 0xee, 0xda, 0x42, 0x08, 0xd7, 0x9a, 0x91, 0x4c, 0x5e, 0x05, 0x9a, + 0xea, 0x46, 0x6e, 0x93, 0x87, 0x3c, 0xd1, 0x0b, 0xb3, 0xe9, 0x99, 0xce, 0x0d, 0x0d, 0x4c, 0xc6, 0xb1, 0x55, 0x05, + 0xc9, 0x70, 0x95, 0x07, 0x86, 0xe8, 0xab, 0x9a, 0xb7, 0x08, 0x22, 0x13, 0xbd, 0xc0, 0xd7, 0x73, 0xfc, 0x3b, 0xf0, + 0x83, 0x0c, 0xc8, 0xad, 0x9a, 0x05, 0x89, 0xa6, 0x6a, 0x37, 0x07, 0xa1, 0x9e, 0xf4, 0x46, 0x48, 0x08, 0x29, 0xde, + 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0xf9, 0x8c, 0xd0, 0xe4, 0x3b, 0x02, 0xd3, 0xf1, 0x39, 0x00, 0xd2, 0x92, 0x7c, 0x79, + 0x47, 0x29, 0xf0, 0x32, 0x40, 0x99, 0xac, 0x48, 0xe0, 0xae, 0xfe, 0x3a, 0x8e, 0x48, 0x10, 0x0f, 0x7a, 0x70, 0xd3, + 0xe6, 0x27, 0xe0, 0x11, 0xb8, 0xa7, 0xe1, 0x83, 0x1d, 0x73, 0x39, 0x27, 0x58, 0x73, 0xe8, 0x73, 0xd8, 0x67, 0xcd, + 0x3e, 0xe1, 0x22, 0x05, 0x0b, 0x82, 0xd4, 0xa1, 0xe2, 0xe2, 0xd9, 0x64, 0x0d, 0xb8, 0x11, 0xdf, 0x45, 0x77, 0xd9, + 0x82, 0x45, 0x2b, 0x1d, 0x63, 0x42, 0xa1, 0x8f, 0x3e, 0x28, 0xf3, 0x8a, 0x88, 0x2d, 0xc0, 0x36, 0xcd, 0x35, 0xe7, + 0x74, 0x17, 0xa6, 0x1c, 0xa5, 0xfa, 0xe6, 0x98, 0x0b, 0x36, 0x53, 0x8e, 0xdb, 0xaa, 0x37, 0x04, 0x5f, 0xd2, 0xb8, + 0x6a, 0xc8, 0x45, 0x9a, 0xd0, 0xd0, 0x06, 0x79, 0xc7, 0xe0, 0xec, 0x22, 0x01, 0xf6, 0x96, 0x5f, 0x5d, 0x34, 0x29, + 0x91, 0xf1, 0x2b, 0x8c, 0xa2, 0xc4, 0xa8, 0x37, 0xc3, 0xc7, 0x09, 0x8e, 0x89, 0x36, 0xb6, 0x33, 0xae, 0xb5, 0xb3, + 0x61, 0xd2, 0x9f, 0xd8, 0x3d, 0x5d, 0x24, 0x04, 0xaa, 0x4f, 0xec, 0x1e, 0x74, 0xff, 0x5e, 0x03, 0x37, 0x45, 0xdf, + 0x82, 0xae, 0x4d, 0x70, 0xf5, 0x3f, 0x06, 0x67, 0x55, 0x5b, 0x0e, 0x90, 0x93, 0x6f, 0xc1, 0xe2, 0x08, 0x62, 0x88, + 0xea, 0x2c, 0x0e, 0x31, 0x57, 0xf1, 0x6f, 0x35, 0xc2, 0xd8, 0x6a, 0x38, 0x1a, 0xc6, 0x33, 0xd7, 0x71, 0x0e, 0x6a, + 0xe5, 0x81, 0x91, 0xdd, 0x54, 0xda, 0x30, 0xb3, 0x81, 0xeb, 0x58, 0xc1, 0x33, 0xdb, 0xeb, 0xd7, 0xee, 0x68, 0xc5, + 0x97, 0xe4, 0x10, 0xd9, 0x5f, 0xa7, 0x4f, 0xd6, 0xad, 0xda, 0x81, 0x34, 0xaa, 0x2a, 0xf3, 0x38, 0xb6, 0x9c, 0xf3, + 0xbf, 0x86, 0xf5, 0xab, 0x9f, 0x3c, 0x59, 0x52, 0x5c, 0x93, 0x21, 0x78, 0x43, 0x6e, 0xc1, 0x31, 0xfa, 0x8b, 0xf6, + 0x5c, 0x6b, 0xd1, 0xf1, 0x31, 0x8c, 0xa1, 0x0c, 0x97, 0x2d, 0x6c, 0xca, 0xd4, 0x06, 0x2a, 0x3d, 0xa6, 0x55, 0x0c, + 0xc7, 0xfd, 0xae, 0xb2, 0x42, 0xa2, 0xb7, 0x95, 0x5a, 0xc0, 0xf6, 0x37, 0x5c, 0x9f, 0xf6, 0x08, 0xfc, 0x12, 0x40, + 0x09, 0xf0, 0x9d, 0xbe, 0xb3, 0xc1, 0xd5, 0xb2, 0xdc, 0x5c, 0xf9, 0x92, 0xdc, 0xbf, 0x31, 0xbc, 0x74, 0x50, 0x86, + 0x26, 0xdb, 0x6b, 0xbe, 0xee, 0x1e, 0xd8, 0x24, 0x8b, 0x26, 0xe5, 0x06, 0x2b, 0xf7, 0xd7, 0xfe, 0xcd, 0x95, 0x30, + 0x0a, 0x04, 0x15, 0x88, 0x1b, 0x30, 0x4a, 0x1e, 0x47, 0xb8, 0xf9, 0xe9, 0xb8, 0x05, 0x7b, 0x51, 0x31, 0x58, 0x81, + 0x3c, 0x82, 0xc9, 0x6a, 0x0a, 0x53, 0x1c, 0x3c, 0x57, 0xa3, 0x59, 0x70, 0x4b, 0x10, 0xa2, 0x1b, 0x77, 0x62, 0x26, + 0x74, 0x0a, 0x8b, 0x3a, 0x01, 0xf7, 0x45, 0xb9, 0x2f, 0xd7, 0x3a, 0xd8, 0xcd, 0xb5, 0xce, 0x76, 0x71, 0xad, 0xc9, + 0x9c, 0xea, 0x36, 0xf1, 0x97, 0x8a, 0x45, 0x9e, 0x20, 0xce, 0x55, 0xc3, 0xbc, 0x12, 0xab, 0x1b, 0xad, 0xaf, 0x44, + 0xad, 0x5a, 0x6b, 0xa4, 0x25, 0x88, 0xec, 0x6f, 0xe5, 0x81, 0x22, 0x04, 0xea, 0x2a, 0x6f, 0xfc, 0xa2, 0xe0, 0x8d, + 0xd3, 0xab, 0xa6, 0x30, 0xa4, 0x11, 0xd4, 0xbf, 0x62, 0xa4, 0x26, 0x5f, 0x07, 0x85, 0xb1, 0x5a, 0x31, 0x52, 0xc5, + 0xfc, 0xaa, 0x78, 0x68, 0x28, 0x46, 0x7d, 0xe2, 0x95, 0x51, 0xb6, 0xed, 0x2b, 0x17, 0x2d, 0xac, 0xaf, 0x8a, 0x74, + 0xe0, 0xba, 0xe3, 0x90, 0x65, 0xb2, 0xba, 0x6d, 0xca, 0xe6, 0x37, 0x6a, 0xb6, 0xb2, 0x49, 0xa4, 0x9d, 0x0c, 0x01, + 0x58, 0xb0, 0xe9, 0x2b, 0x72, 0x6d, 0xa9, 0x03, 0x81, 0x83, 0x6c, 0x30, 0xeb, 0xdb, 0xcd, 0x9d, 0xa7, 0x78, 0x09, + 0x85, 0x14, 0x5e, 0xe5, 0x41, 0x20, 0x7c, 0xaf, 0xd6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xfc, 0x7e, 0x07, 0xf6, 0xa2, + 0xe6, 0xa8, 0x82, 0x7c, 0x3c, 0x99, 0x16, 0xa9, 0xe7, 0x62, 0xd1, 0x7a, 0xa3, 0xc4, 0xc4, 0x59, 0x73, 0xcb, 0x98, + 0x32, 0x8f, 0x9e, 0x97, 0xe8, 0x89, 0x7e, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0xfa, 0xb6, 0xb7, 0xb2, 0xc4, 0x1f, 0x7f, + 0x52, 0x86, 0x2c, 0xf8, 0x9c, 0xc0, 0x03, 0x2e, 0x4b, 0x0a, 0xfa, 0x3e, 0xba, 0x82, 0x64, 0x3d, 0xdb, 0x4b, 0x15, + 0xee, 0x4b, 0xef, 0xb1, 0xd3, 0xf6, 0x5f, 0x4c, 0x0f, 0x2b, 0x4c, 0x51, 0xaf, 0x53, 0x66, 0x99, 0x6f, 0x18, 0x47, + 0x36, 0x5f, 0x2d, 0x46, 0x6b, 0x95, 0xb7, 0xaa, 0xb0, 0x5c, 0xeb, 0x6c, 0x56, 0xb5, 0xdb, 0xe9, 0x74, 0x5a, 0x66, + 0x34, 0x3a, 0xda, 0x21, 0x32, 0x0b, 0x1f, 0x3b, 0x8e, 0x53, 0x1d, 0xfb, 0x76, 0xb0, 0x5b, 0xc8, 0xb7, 0xed, 0x36, + 0x8e, 0x18, 0x61, 0xbb, 0x0b, 0x7e, 0x75, 0x70, 0xe4, 0x76, 0x71, 0xb2, 0x4b, 0x6a, 0x11, 0x7d, 0x52, 0x86, 0x08, + 0x32, 0xb6, 0x48, 0x7b, 0x63, 0x86, 0x32, 0x18, 0x5b, 0x39, 0xd0, 0xa8, 0x38, 0x60, 0xcd, 0x40, 0x55, 0xc4, 0x15, + 0xbb, 0xc2, 0xd1, 0x90, 0x1f, 0x5e, 0x63, 0xde, 0x8b, 0x4e, 0xf0, 0xa0, 0xac, 0xeb, 0x3c, 0x6d, 0x9c, 0x56, 0xc7, + 0xf9, 0x4b, 0xa9, 0x9c, 0x06, 0x17, 0xe0, 0x5a, 0x08, 0xb4, 0x89, 0x3f, 0x8b, 0x7f, 0x4b, 0xfe, 0xff, 0x8b, 0xe5, + 0x5d, 0x59, 0x7f, 0xa4, 0x0b, 0x1c, 0xed, 0xe2, 0xb4, 0xd0, 0xa8, 0x9b, 0xf6, 0x80, 0xd4, 0x32, 0x98, 0xaa, 0x02, + 0x74, 0x10, 0xd2, 0x97, 0x02, 0x80, 0x34, 0xb0, 0xdf, 0x91, 0x62, 0x86, 0x25, 0x2e, 0x58, 0x88, 0x45, 0xf8, 0x3a, + 0x98, 0x83, 0xf9, 0xbc, 0x8b, 0xf2, 0x83, 0xd2, 0x9e, 0x00, 0x69, 0x7c, 0x6d, 0x6e, 0x7b, 0xb1, 0xfb, 0xab, 0x72, + 0x2d, 0xd1, 0x30, 0x80, 0xcc, 0x85, 0x43, 0x88, 0x8a, 0x04, 0x5a, 0x65, 0x73, 0xd3, 0x28, 0x65, 0xae, 0x2a, 0x67, + 0x13, 0x03, 0xc3, 0xe6, 0x9a, 0x8b, 0x50, 0xdb, 0x42, 0x5a, 0x00, 0x93, 0xe5, 0xdb, 0x0f, 0xbf, 0x2d, 0x58, 0x62, + 0x75, 0x3f, 0xba, 0xb8, 0xe4, 0xb8, 0x7f, 0x2d, 0xbc, 0x3b, 0x53, 0x3a, 0xff, 0xc8, 0x5f, 0xfc, 0xa1, 0x91, 0xa1, + 0x77, 0x51, 0xe2, 0xd0, 0x71, 0x6d, 0x71, 0xcf, 0xd8, 0xab, 0xf4, 0x22, 0x88, 0xf6, 0x2f, 0xeb, 0xdf, 0xed, 0x5d, + 0x16, 0x2e, 0x8c, 0xbd, 0x0b, 0xc3, 0x8d, 0x43, 0x9a, 0x0b, 0xd9, 0xe0, 0x07, 0x85, 0xa1, 0xa8, 0x5a, 0x1d, 0xeb, + 0x58, 0x8b, 0xa8, 0xfc, 0x8b, 0xd5, 0x60, 0x78, 0x72, 0x76, 0xb7, 0x08, 0xb5, 0x1b, 0x96, 0x40, 0x68, 0x9f, 0x81, + 0xee, 0xda, 0x8e, 0xae, 0xa1, 0x0d, 0x6d, 0x10, 0xcd, 0x06, 0xfa, 0x2f, 0x17, 0x6f, 0xac, 0xae, 0x7e, 0x06, 0x22, + 0xda, 0x9b, 0x19, 0x5e, 0x7b, 0xe7, 0xfe, 0x3d, 0x4b, 0xae, 0x3d, 0x5d, 0xc3, 0x08, 0x3e, 0x74, 0xe1, 0x61, 0x9a, + 0xe6, 0xe9, 0x7b, 0x04, 0x8a, 0xd0, 0x44, 0xac, 0x37, 0x1d, 0x50, 0x8e, 0xeb, 0x75, 0x35, 0xd7, 0x3b, 0xb4, 0x8f, + 0xba, 0xfa, 0xe9, 0x37, 0x9a, 0x76, 0x32, 0x61, 0xd3, 0xf4, 0x14, 0x9f, 0x68, 0x27, 0x78, 0x47, 0xd0, 0x6f, 0x4d, + 0xb3, 0xc7, 0x61, 0x6a, 0xb9, 0xda, 0x9a, 0x7f, 0x6a, 0xda, 0x34, 0x08, 0xc3, 0x9e, 0xf6, 0x78, 0xea, 0x4d, 0x0f, + 0xa7, 0x2f, 0xfa, 0x3c, 0x39, 0xff, 0xa6, 0x54, 0xdc, 0xa4, 0x7f, 0x3d, 0xa5, 0x5a, 0x9a, 0x25, 0xf1, 0x27, 0xc6, + 0xd5, 0x4e, 0x34, 0xf9, 0x78, 0xac, 0x56, 0xf5, 0xea, 0x3d, 0xb9, 0xdd, 0xd1, 0x78, 0xea, 0x15, 0xc5, 0x71, 0x8c, + 0x07, 0x72, 0x90, 0x27, 0x07, 0x62, 0xe8, 0x27, 0x2a, 0x98, 0x5c, 0xab, 0x09, 0x50, 0xae, 0xce, 0xe7, 0x38, 0x13, + 0xf3, 0x3b, 0x01, 0x3f, 0x8c, 0xd2, 0x5c, 0x17, 0x46, 0xa0, 0x6b, 0x93, 0x81, 0xfe, 0xa3, 0xeb, 0x75, 0x4d, 0xd7, + 0x3d, 0xb2, 0x8f, 0xba, 0x63, 0xc7, 0x3c, 0xb4, 0x0f, 0xad, 0xb6, 0x7d, 0x64, 0x76, 0xad, 0xae, 0xd9, 0xfd, 0x5b, + 0x77, 0x6c, 0x1d, 0xda, 0x87, 0xa6, 0x63, 0x75, 0x21, 0xd1, 0xea, 0x5a, 0xdd, 0x1b, 0xeb, 0xb0, 0x3b, 0x76, 0x30, + 0xd5, 0xb3, 0x3b, 0x1d, 0xcb, 0x75, 0xec, 0x4e, 0xc7, 0xec, 0xd8, 0x47, 0x47, 0x96, 0xdb, 0xb6, 0x8f, 0x8e, 0xce, + 0x3b, 0x5d, 0xbb, 0x0d, 0x79, 0xed, 0xf6, 0xb8, 0x6d, 0xbb, 0xae, 0x05, 0x7f, 0x99, 0x5d, 0xdb, 0xa3, 0x1f, 0xae, + 0x6b, 0xb7, 0x5d, 0xd3, 0x09, 0x3b, 0x9e, 0x7d, 0xf4, 0xc2, 0xc4, 0xbf, 0xb1, 0x98, 0x89, 0x7f, 0x41, 0x33, 0xe6, + 0x0b, 0xdb, 0x3b, 0xa2, 0x5f, 0xd8, 0xe0, 0xcd, 0x61, 0xf7, 0x57, 0xfd, 0x60, 0xe3, 0x1c, 0x5c, 0x9a, 0x43, 0xb7, + 0x63, 0xb7, 0xdb, 0xe6, 0xa1, 0x6b, 0x77, 0xdb, 0x73, 0xeb, 0xd0, 0xb3, 0x8f, 0x8e, 0xc7, 0x96, 0x6b, 0x1f, 0x1f, + 0x9b, 0x8e, 0xd5, 0xb6, 0x3d, 0xd3, 0xb5, 0x0f, 0xdb, 0xf8, 0xa3, 0x6d, 0x7b, 0x37, 0xc7, 0x2f, 0xec, 0xa3, 0xce, + 0xfc, 0xc8, 0x3e, 0xfc, 0x78, 0xd8, 0xb5, 0xbd, 0xf6, 0xbc, 0x7d, 0x64, 0x7b, 0xc7, 0x37, 0x47, 0xf6, 0xe1, 0xdc, + 0xf2, 0x8e, 0xb6, 0xd6, 0x74, 0x3d, 0x1b, 0x60, 0x84, 0xd9, 0x90, 0x61, 0xf2, 0x0c, 0xf8, 0x33, 0xc7, 0xba, 0xff, + 0xc5, 0x66, 0xd2, 0x7a, 0xd5, 0x17, 0x76, 0xf7, 0x78, 0x4c, 0xc5, 0x21, 0xc1, 0x12, 0x25, 0xa0, 0xca, 0x8d, 0x45, + 0xdd, 0x62, 0x73, 0x96, 0x68, 0x48, 0xfc, 0xe1, 0x9d, 0xdd, 0x58, 0xd0, 0x31, 0xf5, 0xfb, 0x3f, 0x6d, 0x47, 0x2e, + 0x39, 0x44, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x41, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x41, 0xc5, 0xfb, 0xdd, 0x82, 0x8a, + 0x37, 0xab, 0x7d, 0x04, 0x15, 0xef, 0xbf, 0xba, 0xa0, 0xe2, 0xbc, 0xaa, 0x27, 0xff, 0xbe, 0xea, 0x9b, 0xfe, 0xd7, + 0x75, 0xf5, 0x19, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x78, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, 0x4a, 0x4a, + 0x60, 0x31, 0xe0, 0xd8, 0xf7, 0x31, 0xe1, 0xd8, 0xdf, 0x57, 0x03, 0xd0, 0x3c, 0xe1, 0x74, 0x49, 0x30, 0xb1, 0xe6, + 0x7e, 0x38, 0x95, 0x34, 0x0d, 0xa4, 0xf4, 0x31, 0x19, 0xac, 0x12, 0xe0, 0xba, 0x06, 0x71, 0xd8, 0x6a, 0x11, 0xa5, + 0xbd, 0x23, 0x07, 0x2e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xca, 0xb6, 0xf0, 0x47, 0x75, 0xcd, 0xad, 0x26, 0x36, 0xe6, + 0xa3, 0x52, 0x60, 0x73, 0xeb, 0x6e, 0xbd, 0x5d, 0x0d, 0xb4, 0x6d, 0x84, 0xd2, 0x24, 0x90, 0x73, 0x4d, 0xf9, 0x65, + 0xd5, 0xbc, 0x8a, 0x32, 0xe6, 0xe6, 0x91, 0xc2, 0x48, 0xaa, 0xf5, 0xdd, 0xb2, 0x6a, 0xdf, 0xae, 0x69, 0x36, 0x74, + 0x5f, 0xaa, 0xbe, 0x45, 0xaf, 0x50, 0x36, 0x5c, 0x05, 0x55, 0x25, 0xb2, 0x5a, 0x23, 0x40, 0x0a, 0xea, 0xbe, 0x50, + 0x3e, 0x2c, 0x48, 0x4b, 0x47, 0x43, 0x7a, 0xc7, 0x51, 0xf2, 0x4a, 0x6d, 0xaa, 0x0a, 0x8b, 0xcf, 0xd6, 0x48, 0x71, + 0x07, 0xbf, 0x03, 0xe9, 0xc8, 0x29, 0x9e, 0x51, 0xac, 0xc2, 0x79, 0xad, 0xb4, 0x4b, 0x8f, 0x99, 0x7c, 0xee, 0xae, + 0xeb, 0xc4, 0xe3, 0x46, 0x55, 0x65, 0x97, 0x2d, 0x04, 0x15, 0x84, 0xdd, 0x93, 0x62, 0x70, 0x4e, 0xca, 0xdb, 0xa8, + 0xfb, 0xbc, 0xad, 0x31, 0x51, 0xee, 0x31, 0x6c, 0x62, 0x93, 0x7f, 0xa8, 0x7e, 0x01, 0xd6, 0x53, 0x88, 0x82, 0xdd, + 0x43, 0x32, 0x4d, 0xa1, 0x51, 0x3d, 0xd4, 0x62, 0xee, 0x6f, 0x51, 0xb0, 0x51, 0x1b, 0xe6, 0x8d, 0xa0, 0x36, 0xf4, + 0x36, 0x9d, 0x1c, 0x69, 0x3c, 0xb2, 0x2e, 0x89, 0xa8, 0xdd, 0xce, 0xb1, 0xe9, 0x1e, 0x99, 0xf6, 0x71, 0xc7, 0xc8, + 0xc5, 0x81, 0x53, 0x9b, 0x2c, 0x01, 0x04, 0x94, 0xa2, 0xe5, 0x30, 0x83, 0x28, 0xc8, 0x02, 0x3f, 0xcc, 0x81, 0x3e, + 0x2e, 0xbf, 0x2a, 0xfe, 0xb9, 0x4a, 0x33, 0x98, 0xa3, 0x20, 0x7a, 0x51, 0x21, 0xdc, 0x1a, 0xb1, 0xec, 0x96, 0xb1, + 0x68, 0x83, 0xb0, 0xbc, 0xaa, 0x5f, 0xfe, 0xe7, 0x69, 0xdb, 0xe6, 0xa4, 0xc9, 0x32, 0xca, 0x22, 0xbe, 0x3f, 0x84, + 0x32, 0x74, 0x3e, 0x34, 0x7f, 0xda, 0x84, 0x70, 0xff, 0xb9, 0x1b, 0xe1, 0x66, 0x6c, 0x1f, 0x84, 0xfb, 0xcf, 0xaf, + 0x8e, 0x70, 0x7f, 0x52, 0x11, 0x6e, 0xc9, 0x16, 0xa8, 0xe0, 0x3a, 0x7f, 0xc0, 0xef, 0x16, 0x38, 0x75, 0x7e, 0xae, + 0x1f, 0x10, 0x01, 0xaf, 0x2b, 0xc1, 0x76, 0x3f, 0x96, 0xa2, 0x07, 0x21, 0x53, 0x04, 0x9d, 0xd0, 0x52, 0xa4, 0x12, + 0x08, 0x44, 0x2b, 0x43, 0xaa, 0x43, 0x9b, 0x6f, 0xa3, 0x2c, 0xb4, 0xdf, 0xf3, 0x87, 0x1f, 0x08, 0x79, 0xde, 0xc4, + 0xc9, 0xc2, 0x47, 0x07, 0x7c, 0x3a, 0x46, 0x1d, 0x84, 0x0f, 0x07, 0xec, 0xcf, 0xc6, 0x71, 0x34, 0x91, 0x92, 0x0a, + 0x36, 0xb8, 0x24, 0x8a, 0x5b, 0xbf, 0x67, 0x7e, 0xa2, 0x9b, 0x94, 0x0d, 0x8b, 0xfb, 0xac, 0xed, 0x3c, 0xf3, 0x0e, + 0x9f, 0x1d, 0x39, 0xf0, 0xbf, 0xcb, 0xda, 0xb9, 0xc9, 0x0b, 0x2e, 0xe2, 0x08, 0x02, 0x9f, 0x88, 0x92, 0x9b, 0x8a, + 0xdd, 0x32, 0xf6, 0xa9, 0x28, 0x75, 0xdc, 0x5c, 0x68, 0xe2, 0xdf, 0x17, 0x65, 0x1a, 0x4b, 0xcc, 0xe3, 0x95, 0x32, + 0xac, 0x86, 0xd1, 0x04, 0xd1, 0x0a, 0x78, 0x6f, 0x4a, 0x09, 0x35, 0x9b, 0x4f, 0xb7, 0x98, 0x17, 0x6b, 0xe7, 0x57, + 0x45, 0x74, 0x25, 0x11, 0xe5, 0x65, 0x27, 0x04, 0xb9, 0xd8, 0xc2, 0x41, 0xdf, 0xec, 0x18, 0x5f, 0x48, 0x83, 0xd8, + 0x86, 0x62, 0x81, 0x7c, 0x5a, 0xa0, 0x2c, 0x59, 0x45, 0xe3, 0x16, 0xfe, 0xf4, 0x47, 0x69, 0x2b, 0x38, 0x00, 0xef, + 0xac, 0xd8, 0xb1, 0x81, 0xab, 0xe6, 0x9f, 0x3a, 0x45, 0x28, 0x8a, 0x54, 0xac, 0x8a, 0xff, 0x2c, 0x33, 0x13, 0x0a, + 0x60, 0x8b, 0x4b, 0x6b, 0x0d, 0xfc, 0x67, 0xb2, 0xe2, 0xb3, 0xcc, 0x84, 0x20, 0xb2, 0xb0, 0xdc, 0x4f, 0x9f, 0x52, + 0x29, 0x08, 0xeb, 0x48, 0xd3, 0x3a, 0x1b, 0x17, 0xee, 0xdd, 0x34, 0x7f, 0x16, 0x93, 0x87, 0xb7, 0xde, 0xd8, 0x8c, + 0x9f, 0x3f, 0x3f, 0x1d, 0xb8, 0x06, 0x0f, 0x4a, 0x5a, 0x8a, 0xa0, 0x75, 0xbe, 0x9f, 0xf2, 0x81, 0xd1, 0x68, 0x16, + 0xb7, 0x84, 0x37, 0x93, 0x23, 0x54, 0x94, 0x39, 0xf6, 0x82, 0x88, 0x16, 0x24, 0x64, 0xf4, 0x85, 0x12, 0x80, 0x28, + 0x23, 0x5f, 0x5d, 0x6d, 0xdb, 0xb1, 0x1d, 0x5d, 0x56, 0x9c, 0x06, 0xb3, 0xc1, 0x3a, 0xce, 0x7c, 0x88, 0x0d, 0x14, + 0xc6, 0x33, 0xb0, 0xad, 0xc9, 0x82, 0x2c, 0x84, 0x40, 0x33, 0x60, 0x64, 0xb3, 0xa0, 0x77, 0x79, 0xce, 0x35, 0x9e, + 0xfd, 0xe4, 0x13, 0x06, 0x1b, 0x14, 0x66, 0x75, 0xe8, 0x71, 0xe8, 0x47, 0xb8, 0x0c, 0x5b, 0x7a, 0x0b, 0x42, 0x5d, + 0xb2, 0x24, 0xb5, 0x54, 0x0b, 0x82, 0x9e, 0x06, 0x75, 0x20, 0x0c, 0x3d, 0x36, 0x30, 0x4d, 0xfc, 0x05, 0xf8, 0x64, + 0x5f, 0xe7, 0x26, 0xc7, 0xb4, 0x3a, 0x47, 0xb5, 0x9a, 0xfb, 0xe2, 0xc8, 0xd4, 0x3c, 0xd7, 0xd4, 0x1c, 0x40, 0xb7, + 0x7a, 0x6e, 0xae, 0xf3, 0xab, 0xfe, 0x2e, 0x21, 0x28, 0xe1, 0x97, 0xc7, 0x34, 0x0f, 0x12, 0x7f, 0x72, 0xf6, 0x72, + 0x46, 0x0e, 0x24, 0x5b, 0x8a, 0xb7, 0xf4, 0x80, 0x04, 0x21, 0x17, 0xec, 0x2e, 0x33, 0x30, 0x10, 0x0b, 0x2f, 0x12, + 0x18, 0x6b, 0x34, 0xfe, 0x0b, 0x22, 0x2d, 0xf8, 0xfc, 0xb9, 0x15, 0x80, 0x81, 0xc3, 0x40, 0x81, 0x0f, 0x7c, 0x1b, + 0x25, 0x80, 0x05, 0x85, 0xe8, 0x0e, 0x81, 0x05, 0xd6, 0x47, 0xf0, 0x6f, 0x91, 0x2c, 0x7e, 0x70, 0xd1, 0xa9, 0x1d, + 0xfa, 0xd1, 0x0c, 0x50, 0x9a, 0x1f, 0xcd, 0x6a, 0x2a, 0x1a, 0x64, 0xbf, 0x58, 0x49, 0x2d, 0x9a, 0x2a, 0xd4, 0x27, + 0xd2, 0xef, 0xef, 0x2f, 0x28, 0xd0, 0x14, 0x04, 0x35, 0xf7, 0x27, 0x68, 0x6c, 0x57, 0x48, 0x77, 0x9e, 0x0f, 0xbe, + 0x3d, 0x59, 0xb0, 0xcc, 0x27, 0xd6, 0x30, 0x3c, 0x7e, 0x81, 0x1c, 0xd0, 0xc6, 0x22, 0x48, 0x2c, 0x05, 0x93, 0x9f, + 0xb0, 0x9b, 0x60, 0xcc, 0xdf, 0xa5, 0xa6, 0xc6, 0xef, 0x29, 0x0b, 0xb5, 0xc0, 0x06, 0xae, 0x49, 0x4a, 0xc8, 0x63, + 0x1f, 0xdd, 0x4c, 0x0e, 0xa2, 0x58, 0x3f, 0xfd, 0x56, 0xda, 0x6b, 0x6d, 0x5a, 0x04, 0x88, 0xf6, 0x78, 0x99, 0xb0, + 0xf0, 0x5f, 0x83, 0x6f, 0xe1, 0xe2, 0xfe, 0xf6, 0x4a, 0x37, 0xfa, 0x99, 0x3d, 0x4f, 0xd8, 0x74, 0xf0, 0x6d, 0x43, + 0xd4, 0x43, 0x7c, 0xde, 0xd3, 0x58, 0xf4, 0xb6, 0x57, 0x38, 0x07, 0x6a, 0xef, 0xf5, 0xa8, 0x3f, 0xe5, 0xaf, 0x75, + 0x78, 0x01, 0xae, 0x4b, 0x6f, 0x6c, 0xb7, 0x8f, 0xef, 0xe7, 0x51, 0xe8, 0x8f, 0x3f, 0xf5, 0x29, 0xa7, 0xf4, 0x61, + 0xc1, 0x6d, 0x3d, 0xf6, 0x97, 0x3d, 0xbc, 0x5e, 0xd5, 0x44, 0x30, 0xd7, 0xa4, 0x54, 0x49, 0xd9, 0x35, 0xee, 0x65, + 0xdc, 0xca, 0x6b, 0xec, 0x19, 0xbb, 0xba, 0x9d, 0x07, 0x19, 0x13, 0x5d, 0xe1, 0x47, 0x9e, 0x8b, 0x87, 0x3a, 0x3d, + 0x51, 0xf1, 0x61, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, 0x74, 0xbb, + 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, 0x3f, 0xba, + 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xb5, 0xe0, 0x01, 0x44, 0xef, 0x9d, 0x6f, 0x4b, 0x58, 0x40, 0xf9, + 0x2d, 0xe5, 0x34, 0x66, 0xe9, 0x7a, 0x6b, 0x90, 0xf5, 0x00, 0xca, 0xd0, 0x4d, 0xe1, 0x04, 0x32, 0xea, 0xb7, 0x20, + 0x0c, 0x3b, 0x06, 0x10, 0x10, 0x2a, 0x2f, 0xc2, 0x2e, 0x55, 0xb8, 0xd2, 0x6f, 0x3c, 0x46, 0xbc, 0x4e, 0xb3, 0xc3, + 0x75, 0x11, 0x99, 0x8a, 0x84, 0x43, 0xbf, 0x2c, 0xd1, 0x89, 0x91, 0x70, 0x11, 0xaf, 0x60, 0xa5, 0x22, 0x3a, 0x62, + 0xbe, 0x7b, 0xe0, 0x68, 0x99, 0xcb, 0x64, 0x74, 0x9e, 0xaf, 0xda, 0x36, 0x17, 0x18, 0xc9, 0xd6, 0xff, 0x68, 0x3b, + 0x18, 0x94, 0x96, 0xda, 0x11, 0xde, 0x5c, 0x27, 0x41, 0x22, 0x87, 0xa7, 0xa0, 0x68, 0xb7, 0xd9, 0x53, 0xbd, 0x01, + 0x61, 0x4c, 0xde, 0x02, 0x95, 0x7c, 0xe3, 0x87, 0x8a, 0x72, 0x8b, 0x52, 0xf3, 0x91, 0xc4, 0xfc, 0x4f, 0x9f, 0x16, + 0x83, 0xb3, 0x2a, 0xe3, 0x3e, 0x71, 0x3b, 0x70, 0xed, 0x76, 0x58, 0x7b, 0xab, 0x9e, 0xd5, 0x6e, 0x77, 0xc0, 0x85, + 0xbb, 0x50, 0xa1, 0x4b, 0x21, 0xa4, 0xb8, 0x1b, 0x95, 0xbd, 0x6a, 0x32, 0x5c, 0x70, 0xa4, 0x5c, 0x79, 0xea, 0xe8, + 0x46, 0x3f, 0x12, 0x22, 0xc9, 0x68, 0x8b, 0x0b, 0x64, 0xfe, 0x16, 0xd3, 0x01, 0x34, 0x5b, 0xe6, 0xb1, 0xc3, 0x68, + 0xf4, 0x7f, 0x3d, 0x09, 0x34, 0xe0, 0x02, 0x19, 0x6a, 0xe5, 0xb4, 0x96, 0x0c, 0x7a, 0xe4, 0xbd, 0x4a, 0x17, 0x2a, + 0x4b, 0xcf, 0x74, 0x48, 0x82, 0xf8, 0x56, 0x18, 0xd2, 0x4e, 0x2a, 0x90, 0xc9, 0xdb, 0xa2, 0x48, 0x30, 0x03, 0xf0, + 0x01, 0xde, 0x12, 0xc6, 0x64, 0xc6, 0xd3, 0xa7, 0x1b, 0x2f, 0x21, 0x12, 0xd8, 0xab, 0x91, 0x3d, 0x75, 0x15, 0xbf, + 0xe9, 0x2a, 0x8a, 0x91, 0xed, 0x22, 0xd6, 0x10, 0x7a, 0x6f, 0xb4, 0xf7, 0xf0, 0xe7, 0x88, 0xf9, 0x99, 0xcd, 0x25, + 0x4d, 0x2d, 0xe5, 0x72, 0x37, 0x5d, 0xd6, 0x06, 0x8d, 0x37, 0xee, 0xeb, 0x8c, 0xfb, 0x12, 0x7c, 0xb2, 0xfe, 0xb8, + 0xe2, 0x96, 0xde, 0xd0, 0xc6, 0x67, 0xa7, 0x70, 0x4f, 0xf3, 0x2e, 0xf3, 0xc9, 0x87, 0x89, 0x7a, 0xe5, 0xc6, 0x99, + 0x2f, 0xe2, 0xc8, 0x00, 0x5d, 0xde, 0x6f, 0x14, 0xc9, 0x2a, 0xd6, 0xe0, 0xa7, 0xef, 0x2e, 0xbe, 0xd3, 0xf8, 0xfe, + 0x27, 0x09, 0x22, 0x3e, 0x64, 0x28, 0xea, 0xc1, 0x80, 0xa2, 0x1e, 0x68, 0x3c, 0x8c, 0x08, 0xc4, 0x0e, 0xc8, 0x0f, + 0x08, 0x82, 0xc8, 0x80, 0x26, 0xb9, 0xea, 0x62, 0x15, 0x66, 0xc1, 0xd2, 0x4f, 0xb2, 0x03, 0xa8, 0x6a, 0x01, 0x92, + 0xd3, 0x37, 0xd9, 0x88, 0x93, 0x68, 0x56, 0xb8, 0xd8, 0xcb, 0x22, 0x21, 0x9b, 0x9d, 0x06, 0xa1, 0x14, 0xcd, 0x8a, + 0x0e, 0xfc, 0xf1, 0x98, 0x2d, 0xb3, 0x81, 0xee, 0x2f, 0x21, 0xfa, 0x05, 0xfa, 0xb3, 0x3e, 0x88, 0xc7, 0x19, 0xcb, + 0xac, 0x34, 0x4b, 0x98, 0xbf, 0xd0, 0xa5, 0x2b, 0xd7, 0x7a, 0x7b, 0xe9, 0x6a, 0xb4, 0x08, 0x32, 0xe9, 0x0b, 0x91, + 0x26, 0x08, 0x42, 0x52, 0x18, 0xe2, 0xe9, 0x30, 0xe7, 0x20, 0x3c, 0x8f, 0x67, 0x95, 0x1d, 0x55, 0x50, 0x2e, 0x67, + 0xe8, 0x69, 0x97, 0x47, 0x3c, 0x98, 0xa0, 0xcd, 0xd3, 0x35, 0xb7, 0x6b, 0x97, 0x2e, 0x1b, 0xf5, 0xd3, 0x13, 0xfe, + 0xbc, 0xd5, 0xd0, 0x15, 0x83, 0xde, 0x71, 0xc0, 0x97, 0xf0, 0x26, 0x8b, 0xf7, 0x03, 0x5e, 0x18, 0xae, 0x26, 0x6a, + 0x19, 0xfd, 0xbc, 0xd3, 0x58, 0x2e, 0x80, 0x10, 0x2a, 0x09, 0xd1, 0xe7, 0xee, 0xa9, 0x34, 0xb1, 0xc2, 0x51, 0x21, + 0xad, 0xf4, 0xf9, 0xf3, 0xcb, 0xe1, 0x7f, 0xfe, 0x0d, 0xce, 0xe8, 0xe7, 0xae, 0xb0, 0x33, 0xbf, 0x54, 0x4b, 0x71, + 0xea, 0xd3, 0x1c, 0xa2, 0x02, 0x05, 0x9b, 0x08, 0xc7, 0x2b, 0x62, 0x6b, 0xe5, 0xc3, 0x2b, 0xe1, 0x4c, 0x0b, 0x02, + 0x4e, 0x18, 0xc2, 0x1a, 0x7e, 0x08, 0xcb, 0x3b, 0x14, 0x4e, 0x18, 0xb4, 0xdf, 0xee, 0xbe, 0x3f, 0x06, 0x67, 0xcb, + 0xb5, 0x38, 0x10, 0xca, 0x00, 0x71, 0x0f, 0x9d, 0x9e, 0xf8, 0x1a, 0x12, 0x2d, 0x48, 0x7e, 0xa4, 0xbd, 0x03, 0x98, + 0xe6, 0x3c, 0x5e, 0x30, 0x3b, 0x88, 0x0f, 0x6e, 0xd9, 0xc8, 0xf2, 0x97, 0x01, 0xc9, 0xea, 0x91, 0xef, 0xa6, 0x11, + 0xe5, 0x27, 0x45, 0xe0, 0x44, 0x5f, 0xe7, 0x05, 0x28, 0xe3, 0x02, 0x50, 0xf0, 0xd3, 0x3f, 0x2d, 0xfb, 0x67, 0xb4, + 0x45, 0x84, 0x80, 0x32, 0x96, 0x3f, 0x23, 0x37, 0x8b, 0xc2, 0xa3, 0x62, 0xf1, 0x61, 0xc5, 0xd3, 0xa9, 0xea, 0x53, + 0xd1, 0x2e, 0xf7, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0x49, 0x3d, 0xd5, 0xbb, 0x90, 0x3f, 0x21, 0x3a, 0x32, 0x77, + 0xbf, 0x09, 0xe7, 0xb9, 0xe6, 0x9b, 0x51, 0x82, 0xe4, 0x31, 0x15, 0xe2, 0x88, 0xa2, 0xea, 0x09, 0x7c, 0x03, 0x69, + 0xf2, 0x68, 0x30, 0x20, 0x3c, 0x56, 0x45, 0x67, 0x00, 0xa5, 0x86, 0x68, 0x09, 0x30, 0xd9, 0x0c, 0x2a, 0x5a, 0x64, + 0x23, 0x87, 0x95, 0xaa, 0xd3, 0xa9, 0x8f, 0xf1, 0xc0, 0x17, 0xfb, 0xab, 0xb4, 0x03, 0x61, 0x67, 0xf1, 0x85, 0x05, + 0x04, 0x2e, 0xda, 0xa9, 0xe0, 0x71, 0xed, 0xaf, 0x84, 0xb2, 0xad, 0xd0, 0xbf, 0x8f, 0x15, 0xdd, 0x05, 0xee, 0xc6, + 0xe0, 0x1c, 0x53, 0x2f, 0x84, 0xf9, 0x60, 0xed, 0x24, 0x49, 0x8f, 0xf3, 0xf5, 0xd3, 0xa4, 0xba, 0x88, 0xdf, 0x75, + 0x98, 0xd4, 0xb2, 0xe5, 0xc9, 0x20, 0x76, 0xcc, 0x8b, 0x83, 0x56, 0xca, 0xc4, 0x73, 0x9f, 0x9f, 0x1c, 0xc0, 0xfc, + 0xc0, 0xf5, 0x42, 0x89, 0x32, 0x0a, 0x0c, 0xf0, 0xef, 0xe0, 0xa7, 0xa4, 0x7f, 0xf1, 0x76, 0x22, 0x88, 0x3a, 0x7c, + 0x39, 0x4a, 0xe7, 0xaf, 0xa5, 0x22, 0x75, 0x62, 0xc5, 0x69, 0xa6, 0xf2, 0x76, 0x47, 0x68, 0xf8, 0x7d, 0x85, 0xe1, + 0x19, 0xf2, 0x7e, 0xc6, 0x84, 0x65, 0xf3, 0x79, 0xb6, 0xc1, 0xf8, 0x79, 0x53, 0x11, 0x22, 0x58, 0xb7, 0x14, 0x28, + 0xf6, 0xf1, 0xb6, 0x52, 0x05, 0x69, 0x24, 0x8b, 0x2d, 0xfd, 0x96, 0xfe, 0x18, 0x77, 0x7c, 0xad, 0x34, 0xa6, 0x42, + 0xb9, 0xf3, 0x6c, 0x00, 0x45, 0x05, 0xb3, 0xdd, 0x5f, 0x2e, 0xa9, 0xb0, 0xd1, 0x3f, 0x39, 0xa0, 0x77, 0xe7, 0x29, + 0xed, 0xb0, 0xd3, 0x13, 0xd0, 0xdf, 0xa4, 0x45, 0xf7, 0x97, 0x4b, 0xbe, 0xa4, 0xf4, 0x8b, 0x72, 0x0e, 0xe6, 0xd9, + 0x22, 0x3c, 0xfd, 0x3f, 0x1d, 0xdb, 0x6f, 0x83, 0x01, 0x5c, 0x03, 0x00}; } // namespace web_server } // namespace esphome From 3cd2fb08431f170d5c853cfaf87476ae0997e24a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 09:57:36 +1200 Subject: [PATCH 1863/2607] [core] Update Entities (#6885) --- CODEOWNERS | 2 + esphome/components/api/api.proto | 44 +++ esphome/components/api/api_connection.cpp | 45 +++ esphome/components/api/api_connection.h | 6 + esphome/components/api/api_pb2.cpp | 256 ++++++++++++++++++ esphome/components/api/api_pb2.h | 55 ++++ esphome/components/api/api_pb2_service.cpp | 42 +++ esphome/components/api/api_pb2_service.h | 15 + esphome/components/api/api_server.cpp | 7 + esphome/components/api/api_server.h | 3 + esphome/components/api/list_entities.cpp | 3 + esphome/components/api/list_entities.h | 3 + esphome/components/api/subscribe_state.cpp | 3 + esphome/components/api/subscribe_state.h | 3 + .../http_request/ota/ota_http_request.cpp | 2 + .../http_request/ota/ota_http_request.h | 1 - .../http_request/update/__init__.py | 44 +++ .../update/http_request_update.cpp | 157 +++++++++++ .../http_request/update/http_request_update.h | 37 +++ esphome/components/mqtt/__init__.py | 1 + esphome/components/mqtt/mqtt_const.h | 2 + esphome/components/mqtt/mqtt_update.cpp | 62 +++++ esphome/components/mqtt/mqtt_update.h | 41 +++ esphome/components/update/__init__.py | 108 ++++++++ esphome/components/update/update_entity.cpp | 12 + esphome/components/update/update_entity.h | 51 ++++ .../components/web_server/list_entities.cpp | 9 + esphome/components/web_server/list_entities.h | 3 + esphome/components/web_server/web_server.cpp | 71 +++++ esphome/components/web_server/web_server.h | 12 +- esphome/const.py | 1 + esphome/core/application.h | 20 ++ esphome/core/component_iterator.cpp | 15 + esphome/core/component_iterator.h | 6 + esphome/core/controller.cpp | 6 + esphome/core/controller.h | 6 + esphome/core/defines.h | 1 + tests/components/http_request/common.yaml | 6 + tests/components/mqtt/common-update.yaml | 13 + tests/components/mqtt/test.esp32-c3-idf.yaml | 1 + tests/components/mqtt/test.esp32-c3.yaml | 4 + tests/components/mqtt/test.esp32-idf.yaml | 1 + tests/components/mqtt/test.esp32.yaml | 4 + tests/components/mqtt/test.esp8266.yaml | 4 + tests/components/update/common.yaml | 1 + tests/components/update/test.esp32-ard.yaml | 1 + tests/components/update/test.esp32-idf.yaml | 1 + tests/components/update/test.esp8266.yaml | 1 + tests/components/update/test.rp2040.yaml | 1 + 49 files changed, 1191 insertions(+), 2 deletions(-) create mode 100644 esphome/components/http_request/update/__init__.py create mode 100644 esphome/components/http_request/update/http_request_update.cpp create mode 100644 esphome/components/http_request/update/http_request_update.h create mode 100644 esphome/components/mqtt/mqtt_update.cpp create mode 100644 esphome/components/mqtt/mqtt_update.h create mode 100644 esphome/components/update/__init__.py create mode 100644 esphome/components/update/update_entity.cpp create mode 100644 esphome/components/update/update_entity.h create mode 100644 tests/components/mqtt/common-update.yaml create mode 100644 tests/components/update/common.yaml create mode 100644 tests/components/update/test.esp32-ard.yaml create mode 100644 tests/components/update/test.esp32-idf.yaml create mode 100644 tests/components/update/test.esp8266.yaml create mode 100644 tests/components/update/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 90574ca9ba..bbb39c26ad 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -172,6 +172,7 @@ esphome/components/host/time/* @clydebarrow esphome/components/hrxl_maxsonar_wr/* @netmikey esphome/components/hte501/* @Stock-M esphome/components/http_request/ota/* @oarcher +esphome/components/http_request/update/* @jesserockz esphome/components/htu31d/* @betterengineering esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hyt271/* @Philippe12 @@ -410,6 +411,7 @@ esphome/components/uart/button/* @ssieb esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ise/* @pvizeli esphome/components/ultrasonic/* @OttoWinter +esphome/components/update/* @jesserockz esphome/components/uponor_smatrix/* @kroimon esphome/components/valve/* @esphome/core esphome/components/vbus/* @ssieb diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 0becec2348..812a1d74ae 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -48,6 +48,7 @@ service APIConnection { rpc date_command (DateCommandRequest) returns (void) {} rpc time_command (TimeCommandRequest) returns (void) {} rpc datetime_command (DateTimeCommandRequest) returns (void) {} + rpc update_command (UpdateCommandRequest) returns (void) {} rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {} @@ -1837,3 +1838,46 @@ message DateTimeCommandRequest { fixed32 key = 1; fixed32 epoch_seconds = 2; } + +// ==================== UPDATE ==================== +message ListEntitiesUpdateResponse { + option (id) = 116; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_UPDATE"; + + string object_id = 1; + fixed32 key = 2; + string name = 3; + string unique_id = 4; + + string icon = 5; + bool disabled_by_default = 6; + EntityCategory entity_category = 7; + string device_class = 8; +} +message UpdateStateResponse { + option (id) = 117; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_UPDATE"; + option (no_delay) = true; + + fixed32 key = 1; + bool missing_state = 2; + bool in_progress = 3; + bool has_progress = 4; + float progress = 5; + string current_version = 6; + string latest_version = 7; + string title = 8; + string release_summary = 9; + string release_url = 10; +} +message UpdateCommandRequest { + option (id) = 118; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_UPDATE"; + option (no_delay) = true; + + fixed32 key = 1; + bool install = 2; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 253f04aa39..2e73a8336e 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1287,6 +1287,51 @@ bool APIConnection::send_event_info(event::Event *event) { } #endif +#ifdef USE_UPDATE +bool APIConnection::send_update_state(update::UpdateEntity *update) { + if (!this->state_subscription_) + return false; + + UpdateStateResponse resp{}; + resp.key = update->get_object_id_hash(); + resp.missing_state = !update->has_state(); + if (update->has_state()) { + resp.in_progress = update->state == update::UpdateState::UPDATE_STATE_INSTALLING; + if (update->update_info.has_progress) { + resp.has_progress = true; + resp.progress = update->update_info.progress; + } + resp.current_version = update->update_info.current_version; + resp.latest_version = update->update_info.latest_version; + resp.title = update->update_info.title; + resp.release_summary = update->update_info.summary; + resp.release_url = update->update_info.release_url; + } + + return this->send_update_state_response(resp); +} +bool APIConnection::send_update_info(update::UpdateEntity *update) { + ListEntitiesUpdateResponse msg; + msg.key = update->get_object_id_hash(); + msg.object_id = update->get_object_id(); + if (update->has_own_name()) + msg.name = update->get_name(); + msg.unique_id = get_default_unique_id("update", update); + msg.icon = update->get_icon(); + msg.disabled_by_default = update->is_disabled_by_default(); + msg.entity_category = static_cast(update->get_entity_category()); + msg.device_class = update->get_device_class(); + return this->send_list_entities_update_response(msg); +} +void APIConnection::update_command(const UpdateCommandRequest &msg) { + update::UpdateEntity *update = App.get_update_by_key(msg.key); + if (update == nullptr) + return; + + update->perform(); +} +#endif + bool APIConnection::send_log_message(int level, const char *tag, const char *line) { if (this->log_subscription_ < level) return false; diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 293da17fa4..714e806470 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -164,6 +164,12 @@ class APIConnection : public APIServerConnection { bool send_event_info(event::Event *event); #endif +#ifdef USE_UPDATE + bool send_update_state(update::UpdateEntity *update); + bool send_update_info(update::UpdateEntity *update); + void update_command(const UpdateCommandRequest &msg) override; +#endif + void on_disconnect_response(const DisconnectResponse &value) override; void on_ping_response(const PingResponse &value) override { // we initiated ping diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 9db6482c49..e6e905c6d1 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -8376,6 +8376,262 @@ void DateTimeCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool ListEntitiesUpdateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 6: { + this->disabled_by_default = value.as_bool(); + return true; + } + case 7: { + this->entity_category = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ListEntitiesUpdateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->object_id = value.as_string(); + return true; + } + case 3: { + this->name = value.as_string(); + return true; + } + case 4: { + this->unique_id = value.as_string(); + return true; + } + case 5: { + this->icon = value.as_string(); + return true; + } + case 8: { + this->device_class = value.as_string(); + return true; + } + default: + return false; + } +} +bool ListEntitiesUpdateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 2: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->object_id); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name); + buffer.encode_string(4, this->unique_id); + buffer.encode_string(5, this->icon); + buffer.encode_bool(6, this->disabled_by_default); + buffer.encode_enum(7, this->entity_category); + buffer.encode_string(8, this->device_class); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void ListEntitiesUpdateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesUpdateResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +bool UpdateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->missing_state = value.as_bool(); + return true; + } + case 3: { + this->in_progress = value.as_bool(); + return true; + } + case 4: { + this->has_progress = value.as_bool(); + return true; + } + default: + return false; + } +} +bool UpdateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 6: { + this->current_version = value.as_string(); + return true; + } + case 7: { + this->latest_version = value.as_string(); + return true; + } + case 8: { + this->title = value.as_string(); + return true; + } + case 9: { + this->release_summary = value.as_string(); + return true; + } + case 10: { + this->release_url = value.as_string(); + return true; + } + default: + return false; + } +} +bool UpdateStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + case 5: { + this->progress = value.as_float(); + return true; + } + default: + return false; + } +} +void UpdateStateResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_bool(2, this->missing_state); + buffer.encode_bool(3, this->in_progress); + buffer.encode_bool(4, this->has_progress); + buffer.encode_float(5, this->progress); + buffer.encode_string(6, this->current_version); + buffer.encode_string(7, this->latest_version); + buffer.encode_string(8, this->title); + buffer.encode_string(9, this->release_summary); + buffer.encode_string(10, this->release_url); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void UpdateStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("UpdateStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" in_progress: "); + out.append(YESNO(this->in_progress)); + out.append("\n"); + + out.append(" has_progress: "); + out.append(YESNO(this->has_progress)); + out.append("\n"); + + out.append(" progress: "); + sprintf(buffer, "%g", this->progress); + out.append(buffer); + out.append("\n"); + + out.append(" current_version: "); + out.append("'").append(this->current_version).append("'"); + out.append("\n"); + + out.append(" latest_version: "); + out.append("'").append(this->latest_version).append("'"); + out.append("\n"); + + out.append(" title: "); + out.append("'").append(this->title).append("'"); + out.append("\n"); + + out.append(" release_summary: "); + out.append("'").append(this->release_summary).append("'"); + out.append("\n"); + + out.append(" release_url: "); + out.append("'").append(this->release_url).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->install = value.as_bool(); + return true; + } + default: + return false; + } +} +bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { + switch (field_id) { + case 1: { + this->key = value.as_fixed32(); + return true; + } + default: + return false; + } +} +void UpdateCommandRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_bool(2, this->install); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void UpdateCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("UpdateCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" install: "); + out.append(YESNO(this->install)); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 54cbd20559..ef051eecf1 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -2130,6 +2130,61 @@ class DateTimeCommandRequest : public ProtoMessage { protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; }; +class ListEntitiesUpdateResponse : public ProtoMessage { + public: + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool disabled_by_default{false}; + enums::EntityCategory entity_category{}; + std::string device_class{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class UpdateStateResponse : public ProtoMessage { + public: + uint32_t key{0}; + bool missing_state{false}; + bool in_progress{false}; + bool has_progress{false}; + float progress{0.0f}; + std::string current_version{}; + std::string latest_version{}; + std::string title{}; + std::string release_summary{}; + std::string release_url{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class UpdateCommandRequest : public ProtoMessage { + public: + uint32_t key{0}; + bool install{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 7c95bb03ad..269a755e9e 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -611,6 +611,24 @@ bool APIServerConnectionBase::send_date_time_state_response(const DateTimeStateR #endif #ifdef USE_DATETIME_DATETIME #endif +#ifdef USE_UPDATE +bool APIServerConnectionBase::send_list_entities_update_response(const ListEntitiesUpdateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_list_entities_update_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 116); +} +#endif +#ifdef USE_UPDATE +bool APIServerConnectionBase::send_update_state_response(const UpdateStateResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_update_state_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 117); +} +#endif +#ifdef USE_UPDATE +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -1106,6 +1124,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str()); #endif this->on_voice_assistant_timer_event_response(msg); +#endif + break; + } + case 118: { +#ifdef USE_UPDATE + UpdateCommandRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); +#endif + this->on_update_command_request(msg); #endif break; } @@ -1434,6 +1463,19 @@ void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequ this->datetime_command(msg); } #endif +#ifdef USE_UPDATE +void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->update_command(msg); +} +#endif #ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &msg) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 2f8a2b3def..83bfc2ed98 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -306,6 +306,15 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_DATETIME_DATETIME virtual void on_date_time_command_request(const DateTimeCommandRequest &value){}; +#endif +#ifdef USE_UPDATE + bool send_list_entities_update_response(const ListEntitiesUpdateResponse &msg); +#endif +#ifdef USE_UPDATE + bool send_update_state_response(const UpdateStateResponse &msg); +#endif +#ifdef USE_UPDATE + virtual void on_update_command_request(const UpdateCommandRequest &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -373,6 +382,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_DATETIME virtual void datetime_command(const DateTimeCommandRequest &msg) = 0; #endif +#ifdef USE_UPDATE + virtual void update_command(const UpdateCommandRequest &msg) = 0; +#endif #ifdef USE_BLUETOOTH_PROXY virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; #endif @@ -471,6 +483,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_DATETIME_DATETIME void on_date_time_command_request(const DateTimeCommandRequest &msg) override; #endif +#ifdef USE_UPDATE + void on_update_command_request(const UpdateCommandRequest &msg) override; +#endif #ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 0725547771..a61ae89243 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -334,6 +334,13 @@ void APIServer::on_event(event::Event *obj, const std::string &event_type) { } #endif +#ifdef USE_UPDATE +void APIServer::on_update(update::UpdateEntity *obj) { + for (auto &c : this->clients_) + c->send_update_state(obj); +} +#endif + float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } void APIServer::set_port(uint16_t port) { this->port_ = port; } APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 2e1fbdf67c..43bc8a7348 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -102,6 +102,9 @@ class APIServer : public Component, public Controller { #ifdef USE_EVENT void on_event(event::Event *obj, const std::string &event_type) override; #endif +#ifdef USE_UPDATE + void on_update(update::UpdateEntity *obj) override; +#endif bool is_connected() const; diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index a7dbf9a6e7..5fa360d170 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -98,6 +98,9 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont #ifdef USE_EVENT bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); } #endif +#ifdef USE_UPDATE +bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_info(update); } +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index c1fd8b82c4..a37586de0f 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -75,6 +75,9 @@ class ListEntitiesIterator : public ComponentIterator { #endif #ifdef USE_EVENT bool on_event(event::Event *event) override; +#endif +#ifdef USE_UPDATE + bool on_update(update::UpdateEntity *update) override; #endif bool on_end() override; diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 005ab0e6da..5861b1f465 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -77,6 +77,9 @@ bool InitialStateIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont return this->client_->send_alarm_control_panel_state(a_alarm_control_panel); } #endif +#ifdef USE_UPDATE +bool InitialStateIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_state(update); } +#endif InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {} } // namespace api diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index 8c725e422e..67c4346210 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -72,6 +72,9 @@ class InitialStateIterator : public ComponentIterator { #endif #ifdef USE_EVENT bool on_event(event::Event *event) override { return true; }; +#endif +#ifdef USE_UPDATE + bool on_update(update::UpdateEntity *update) override; #endif protected: APIConnection *client_; diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index a41f552baf..dcc783ea47 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -15,6 +15,8 @@ namespace esphome { namespace http_request { +static const char *const TAG = "http_request.ota"; + void OtaHttpRequestComponent::setup() { #ifdef USE_OTA_STATE_CALLBACK ota::register_ota_platform(this); diff --git a/esphome/components/http_request/ota/ota_http_request.h b/esphome/components/http_request/ota/ota_http_request.h index 91c7085517..6a86b4ab43 100644 --- a/esphome/components/http_request/ota/ota_http_request.h +++ b/esphome/components/http_request/ota/ota_http_request.h @@ -14,7 +14,6 @@ namespace esphome { namespace http_request { -static const char *const TAG = "http_request.ota"; static const uint8_t MD5_SIZE = 32; enum OtaHttpRequestError : uint8_t { diff --git a/esphome/components/http_request/update/__init__.py b/esphome/components/http_request/update/__init__.py new file mode 100644 index 0000000000..356afa1432 --- /dev/null +++ b/esphome/components/http_request/update/__init__.py @@ -0,0 +1,44 @@ +import esphome.config_validation as cv +import esphome.codegen as cg + +from esphome.components import update +from esphome.const import ( + CONF_SOURCE, +) + +from .. import http_request_ns, CONF_HTTP_REQUEST_ID, HttpRequestComponent +from ..ota import OtaHttpRequestComponent + + +AUTO_LOAD = ["json"] +CODEOWNERS = ["@jesserockz"] +DEPENDENCIES = ["ota.http_request"] + +HttpRequestUpdate = http_request_ns.class_( + "HttpRequestUpdate", update.UpdateEntity, cg.PollingComponent +) + +CONF_OTA_ID = "ota_id" + +CONFIG_SCHEMA = update.UPDATE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(HttpRequestUpdate), + cv.GenerateID(CONF_OTA_ID): cv.use_id(OtaHttpRequestComponent), + cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent), + cv.Required(CONF_SOURCE): cv.url, + } +).extend(cv.polling_component_schema("6h")) + + +async def to_code(config): + var = await update.new_update(config) + ota_parent = await cg.get_variable(config[CONF_OTA_ID]) + cg.add(var.set_ota_parent(ota_parent)) + request_parent = await cg.get_variable(config[CONF_HTTP_REQUEST_ID]) + cg.add(var.set_request_parent(request_parent)) + + cg.add(var.set_source_url(config[CONF_SOURCE])) + + cg.add_define("USE_OTA_STATE_CALLBACK") + + await cg.register_component(var, config) diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp new file mode 100644 index 0000000000..98129e59dc --- /dev/null +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -0,0 +1,157 @@ +#include "http_request_update.h" + +#include "esphome/core/application.h" +#include "esphome/core/version.h" + +#include "esphome/components/json/json_util.h" +#include "esphome/components/network/util.h" + +namespace esphome { +namespace http_request { + +static const char *const TAG = "http_request.update"; + +static const size_t MAX_READ_SIZE = 256; + +void HttpRequestUpdate::setup() { + this->ota_parent_->add_on_state_callback([this](ota::OTAState state, float progress, uint8_t err) { + if (state == ota::OTAState::OTA_IN_PROGRESS) { + this->state_ = update::UPDATE_STATE_INSTALLING; + this->update_info_.has_progress = true; + this->update_info_.progress = progress; + this->publish_state(); + } else if (state == ota::OTAState::OTA_ABORT || state == ota::OTAState::OTA_ERROR) { + this->state_ = update::UPDATE_STATE_AVAILABLE; + this->status_set_error("Failed to install firmware"); + this->publish_state(); + } + }); +} + +void HttpRequestUpdate::update() { + auto container = this->request_parent_->get(this->source_url_); + + if (container == nullptr) { + std::string msg = str_sprintf("Failed to fetch manifest from %s", this->source_url_.c_str()); + this->status_set_error(msg.c_str()); + return; + } + + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + uint8_t *data = allocator.allocate(container->content_length); + if (data == nullptr) { + std::string msg = str_sprintf("Failed to allocate %d bytes for manifest", container->content_length); + this->status_set_error(msg.c_str()); + container->end(); + return; + } + + size_t read_index = 0; + while (container->get_bytes_read() < container->content_length) { + int read_bytes = container->read(data + read_index, MAX_READ_SIZE); + + App.feed_wdt(); + yield(); + + read_index += read_bytes; + } + + std::string response((char *) data, read_index); + allocator.deallocate(data, container->content_length); + + container->end(); + + bool valid = json::parse_json(response, [this](JsonObject root) -> bool { + if (!root.containsKey("name") || !root.containsKey("version") || !root.containsKey("builds")) { + ESP_LOGE(TAG, "Manifest does not contain required fields"); + return false; + } + this->update_info_.title = root["name"].as(); + this->update_info_.latest_version = root["version"].as(); + + for (auto build : root["builds"].as()) { + if (!build.containsKey("chipFamily")) { + ESP_LOGE(TAG, "Manifest does not contain required fields"); + return false; + } + if (build["chipFamily"] == ESPHOME_VARIANT) { + if (!build.containsKey("ota")) { + ESP_LOGE(TAG, "Manifest does not contain required fields"); + return false; + } + auto ota = build["ota"]; + if (!ota.containsKey("path") || !ota.containsKey("md5")) { + ESP_LOGE(TAG, "Manifest does not contain required fields"); + return false; + } + this->update_info_.firmware_url = ota["path"].as(); + this->update_info_.md5 = ota["md5"].as(); + + if (ota.containsKey("summary")) + this->update_info_.summary = ota["summary"].as(); + if (ota.containsKey("release_url")) + this->update_info_.release_url = ota["release_url"].as(); + + return true; + } + } + return false; + }); + + if (!valid) { + std::string msg = str_sprintf("Failed to parse JSON from %s", this->source_url_.c_str()); + this->status_set_error(msg.c_str()); + return; + } + + // Merge source_url_ and this->update_info_.firmware_url + if (this->update_info_.firmware_url.find("http") == std::string::npos) { + std::string path = this->update_info_.firmware_url; + if (path[0] == '/') { + std::string domain = this->source_url_.substr(0, this->source_url_.find('/', 8)); + this->update_info_.firmware_url = domain + path; + } else { + std::string domain = this->source_url_.substr(0, this->source_url_.rfind('/') + 1); + this->update_info_.firmware_url = domain + path; + } + } + + std::string current_version = this->current_version_; + if (current_version.empty()) { +#ifdef ESPHOME_PROJECT_VERSION + current_version = ESPHOME_PROJECT_VERSION; +#else + current_version = ESPHOME_VERSION; +#endif + } + this->update_info_.current_version = current_version; + + if (this->update_info_.latest_version.empty()) { + this->state_ = update::UPDATE_STATE_NO_UPDATE; + } else if (this->update_info_.latest_version != this->current_version_) { + this->state_ = update::UPDATE_STATE_AVAILABLE; + } + + this->update_info_.has_progress = false; + this->update_info_.progress = 0.0f; + + this->status_clear_error(); + this->publish_state(); +} + +void HttpRequestUpdate::perform() { + if (this->state_ != update::UPDATE_STATE_AVAILABLE) { + return; + } + + this->state_ = update::UPDATE_STATE_INSTALLING; + this->publish_state(); + + this->ota_parent_->set_md5(this->update_info.md5); + this->ota_parent_->set_url(this->update_info.firmware_url); + // Flash in the next loop + this->defer([this]() { this->ota_parent_->flash(); }); +} + +} // namespace http_request +} // namespace esphome diff --git a/esphome/components/http_request/update/http_request_update.h b/esphome/components/http_request/update/http_request_update.h new file mode 100644 index 0000000000..1337822ecc --- /dev/null +++ b/esphome/components/http_request/update/http_request_update.h @@ -0,0 +1,37 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include "esphome/components/http_request/http_request.h" +#include "esphome/components/http_request/ota/ota_http_request.h" +#include "esphome/components/update/update_entity.h" + +namespace esphome { +namespace http_request { + +class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent { + public: + void setup() override; + void update() override; + + void perform() override; + + void set_source_url(const std::string &source_url) { this->source_url_ = source_url; } + + void set_request_parent(HttpRequestComponent *request_parent) { this->request_parent_ = request_parent; } + void set_ota_parent(OtaHttpRequestComponent *ota_parent) { this->ota_parent_ = ota_parent; } + + void set_current_version(const std::string ¤t_version) { this->current_version_ = current_version; } + + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + + protected: + HttpRequestComponent *request_parent_; + OtaHttpRequestComponent *ota_parent_; + std::string source_url_; + std::string current_version_{""}; +}; + +} // namespace http_request +} // namespace esphome diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 31cbb2cf97..96a02cb60e 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -126,6 +126,7 @@ MQTTSelectComponent = mqtt_ns.class_("MQTTSelectComponent", MQTTComponent) MQTTButtonComponent = mqtt_ns.class_("MQTTButtonComponent", MQTTComponent) MQTTLockComponent = mqtt_ns.class_("MQTTLockComponent", MQTTComponent) MQTTEventComponent = mqtt_ns.class_("MQTTEventComponent", MQTTComponent) +MQTTUpdateComponent = mqtt_ns.class_("MQTTUpdateComponent", MQTTComponent) MQTTValveComponent = mqtt_ns.class_("MQTTValveComponent", MQTTComponent) MQTTDiscoveryUniqueIdGenerator = mqtt_ns.enum("MQTTDiscoveryUniqueIdGenerator") diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index 66872680bb..0e063c66d2 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -137,6 +137,7 @@ constexpr const char *const MQTT_PAYLOAD_CLOSE = "pl_cls"; constexpr const char *const MQTT_PAYLOAD_DISARM = "pl_disarm"; constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "pl_hi_spd"; constexpr const char *const MQTT_PAYLOAD_HOME = "pl_home"; +constexpr const char *const MQTT_PAYLOAD_INSTALL = "pl_inst"; constexpr const char *const MQTT_PAYLOAD_LOCATE = "pl_loc"; constexpr const char *const MQTT_PAYLOAD_LOCK = "pl_lock"; constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "pl_lo_spd"; @@ -396,6 +397,7 @@ constexpr const char *const MQTT_PAYLOAD_CLOSE = "payload_close"; constexpr const char *const MQTT_PAYLOAD_DISARM = "payload_disarm"; constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "payload_high_speed"; constexpr const char *const MQTT_PAYLOAD_HOME = "payload_home"; +constexpr const char *const MQTT_PAYLOAD_INSTALL = "payload_install"; constexpr const char *const MQTT_PAYLOAD_LOCATE = "payload_locate"; constexpr const char *const MQTT_PAYLOAD_LOCK = "payload_lock"; constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "payload_low_speed"; diff --git a/esphome/components/mqtt/mqtt_update.cpp b/esphome/components/mqtt/mqtt_update.cpp new file mode 100644 index 0000000000..2ed8faf074 --- /dev/null +++ b/esphome/components/mqtt/mqtt_update.cpp @@ -0,0 +1,62 @@ +#include "mqtt_update.h" +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_UPDATE + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.update"; + +using namespace esphome::update; + +MQTTUpdateComponent::MQTTUpdateComponent(UpdateEntity *update) : update_(update) {} + +void MQTTUpdateComponent::setup() { + this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &payload) { + if (payload == "INSTALL") { + this->update_->perform(); + } else { + ESP_LOGW(TAG, "'%s': Received unknown update payload: %s", this->friendly_name().c_str(), payload.c_str()); + this->status_momentary_warning("state", 5000); + } + }); + + this->update_->add_on_state_callback([this]() { this->defer("send", [this]() { this->publish_state(); }); }); +} + +bool MQTTUpdateComponent::publish_state() { + return this->publish_json(this->get_state_topic_(), [this](JsonObject root) { + root["installed_version"] = this->update_->update_info.current_version; + root["latest_version"] = this->update_->update_info.latest_version; + root["title"] = this->update_->update_info.title; + if (!this->update_->update_info.summary.empty()) + root["release_summary"] = this->update_->update_info.summary; + if (!this->update_->update_info.release_url.empty()) + root["release_url"] = this->update_->update_info.release_url; + }); +} + +void MQTTUpdateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + root["schema"] = "json"; + root[MQTT_PAYLOAD_INSTALL] = "INSTALL"; +} + +bool MQTTUpdateComponent::send_initial_state() { return this->publish_state(); } + +void MQTTUpdateComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Update '%s': ", this->update_->get_name().c_str()); + LOG_MQTT_COMPONENT(true, true); +} + +std::string MQTTUpdateComponent::component_type() const { return "update"; } +const EntityBase *MQTTUpdateComponent::get_entity() const { return this->update_; } + +} // namespace mqtt +} // namespace esphome + +#endif // USE_UPDATE +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_update.h b/esphome/components/mqtt/mqtt_update.h new file mode 100644 index 0000000000..6fe04c4ea7 --- /dev/null +++ b/esphome/components/mqtt/mqtt_update.h @@ -0,0 +1,41 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_MQTT +#ifdef USE_UPDATE + +#include "esphome/components/update/update_entity.h" +#include "mqtt_component.h" + +namespace esphome { +namespace mqtt { + +class MQTTUpdateComponent : public mqtt::MQTTComponent { + public: + explicit MQTTUpdateComponent(update::UpdateEntity *update); + + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + void setup() override; + void dump_config() override; + + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + bool send_initial_state() override; + + bool publish_state(); + + protected: + /// "update" component type. + std::string component_type() const override; + const EntityBase *get_entity() const override; + + update::UpdateEntity *update_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif // USE_UPDATE +#endif // USE_MQTT diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py new file mode 100644 index 0000000000..ae3d5062ab --- /dev/null +++ b/esphome/components/update/__init__.py @@ -0,0 +1,108 @@ +from esphome import automation +from esphome.components import mqtt, web_server +import esphome.config_validation as cv +import esphome.codegen as cg +from esphome.const import ( + CONF_DEVICE_CLASS, + CONF_ID, + CONF_MQTT_ID, + CONF_WEB_SERVER_ID, + DEVICE_CLASS_FIRMWARE, +) +from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_helpers import setup_entity + +CODEOWNERS = ["@jesserockz"] +IS_PLATFORM_COMPONENT = True + +update_ns = cg.esphome_ns.namespace("update") +UpdateEntity = update_ns.class_("UpdateEntity", cg.EntityBase) + +UpdateInfo = update_ns.struct("UpdateInfo") + +PerformAction = update_ns.class_("PerformAction", automation.Action) +IsAvailableCondition = update_ns.class_("IsAvailableCondition", automation.Condition) + +DEVICE_CLASSES = [ + DEVICE_CLASS_FIRMWARE, +] + +CONF_ON_UPDATE_AVAILABLE = "on_update_available" + +UPDATE_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTUpdateComponent), + cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), + cv.Optional(CONF_ON_UPDATE_AVAILABLE): automation.validate_automation( + single=True + ), + } + ) +) + + +async def setup_update_core_(var, config): + await setup_entity(var, config) + + if device_class_config := config.get(CONF_DEVICE_CLASS): + cg.add(var.set_device_class(device_class_config)) + + if on_update_available := config.get(CONF_ON_UPDATE_AVAILABLE): + await automation.build_automation( + var.get_update_available_trigger(), + [(UpdateInfo.operator("ref").operator("const"), "x")], + on_update_available, + ) + + if mqtt_id_config := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id_config, var) + await mqtt.register_mqtt_component(mqtt_, config) + + if web_server_id_config := config.get(CONF_WEB_SERVER_ID): + web_server_ = cg.get_variable(web_server_id_config) + web_server.add_entity_to_sorting_list(web_server_, var, config) + + +async def register_update(var, config): + if not CORE.has_id(config[CONF_ID]): + var = cg.Pvariable(config[CONF_ID], var) + cg.add(cg.App.register_update(var)) + await setup_update_core_(var, config) + + +async def new_update(config): + var = cg.new_Pvariable(config[CONF_ID]) + await register_update(var, config) + return var + + +@coroutine_with_priority(100.0) +async def to_code(config): + cg.add_define("USE_UPDATE") + cg.add_global(update_ns.using) + + +UPDATE_AUTOMATION_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(UpdateEntity), + } +) + + +@automation.register_action("update.perform", PerformAction, UPDATE_AUTOMATION_SCHEMA) +async def update_perform_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, paren, paren) + + +@automation.register_condition( + "update.is_available", IsAvailableCondition, UPDATE_AUTOMATION_SCHEMA +) +async def update_is_available_condition_to_code( + config, condition_id, template_arg, args +): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, paren, paren) diff --git a/esphome/components/update/update_entity.cpp b/esphome/components/update/update_entity.cpp new file mode 100644 index 0000000000..501cb6635f --- /dev/null +++ b/esphome/components/update/update_entity.cpp @@ -0,0 +1,12 @@ +#include "update_entity.h" + +namespace esphome { +namespace update { + +void UpdateEntity::publish_state() { + this->has_state_ = true; + this->state_callback_.call(); +} + +} // namespace update +} // namespace esphome diff --git a/esphome/components/update/update_entity.h b/esphome/components/update/update_entity.h new file mode 100644 index 0000000000..5984c8e35b --- /dev/null +++ b/esphome/components/update/update_entity.h @@ -0,0 +1,51 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/entity_base.h" + +namespace esphome { +namespace update { + +struct UpdateInfo { + std::string latest_version; + std::string current_version; + std::string title; + std::string summary; + std::string release_url; + std::string firmware_url; + std::string md5; + bool has_progress{false}; + float progress; +}; + +enum UpdateState : uint8_t { + UPDATE_STATE_UNKNOWN, + UPDATE_STATE_NO_UPDATE, + UPDATE_STATE_AVAILABLE, + UPDATE_STATE_INSTALLING, +}; + +class UpdateEntity : public EntityBase, public EntityBase_DeviceClass { + public: + bool has_state() const { return this->has_state_; } + + void publish_state(); + + virtual void perform() = 0; + + const UpdateInfo &update_info = update_info_; + const UpdateState &state = state_; + + void add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } + + protected: + UpdateState state_{UPDATE_STATE_UNKNOWN}; + UpdateInfo update_info_; + bool has_state_{false}; + + CallbackManager state_callback_{}; +}; + +} // namespace update +} // namespace esphome diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 42af72e872..332f358352 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -177,5 +177,14 @@ bool ListEntitiesIterator::on_event(event::Event *event) { } #endif +#ifdef USE_UPDATE +bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { + if (this->web_server_->events_.count() == 0) + return true; + this->web_server_->events_.send(this->web_server_->update_json(update, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index 47d427d9b5..5ff6ec0412 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -68,6 +68,9 @@ class ListEntitiesIterator : public ComponentIterator { #ifdef USE_EVENT bool on_event(event::Event *event) override; #endif +#ifdef USE_UPDATE + bool on_update(update::UpdateEntity *update) override; +#endif protected: WebServer *web_server_; diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 5bb36f9600..9a1641e86f 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1501,6 +1501,65 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty } #endif +#ifdef USE_UPDATE +void WebServer::on_update(update::UpdateEntity *obj) { + if (this->events_.count() == 0) + return; + this->events_.send(this->update_json(obj, DETAIL_STATE).c_str(), "state"); +} +void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (update::UpdateEntity *obj : App.get_updates()) { + if (obj->get_object_id() != match.id) + continue; + + if (request->method() == HTTP_GET && match.method.empty()) { + std::string data = this->update_json(obj, DETAIL_STATE); + request->send(200, "application/json", data.c_str()); + return; + } + + if (match.method != "install") { + request->send(404); + return; + } + + this->schedule_([obj]() mutable { obj->perform(); }); + request->send(200); + return; + } + request->send(404); +} +std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_config) { + return json::build_json([this, obj, start_config](JsonObject root) { + set_json_id(root, obj, "update-" + obj->get_object_id(), start_config); + root["value"] = obj->update_info.latest_version; + switch (obj->state) { + case update::UPDATE_STATE_NO_UPDATE: + root["state"] = "NO UPDATE"; + break; + case update::UPDATE_STATE_AVAILABLE: + root["state"] = "UPDATE AVAILABLE"; + break; + case update::UPDATE_STATE_INSTALLING: + root["state"] = "INSTALLING"; + break; + default: + root["state"] = "UNKNOWN"; + break; + } + if (start_config == DETAIL_ALL) { + root["current_version"] = obj->update_info.current_version; + root["title"] = obj->update_info.title; + root["summary"] = obj->update_info.summary; + root["release_url"] = obj->update_info.release_url; + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + } + } + }); +} +#endif + bool WebServer::canHandle(AsyncWebServerRequest *request) { if (request->url() == "/") return true; @@ -1620,6 +1679,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_UPDATE + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update") + return true; +#endif + return false; } void WebServer::handleRequest(AsyncWebServerRequest *request) { @@ -1777,6 +1841,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { return; } #endif + +#ifdef USE_UPDATE + if (match.domain == "update") { + this->handle_update_request(request, match); + return; + } +#endif } bool WebServer::isRequestHandlerTrivial() { return false; } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 0fb40e2c33..5b98806af1 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -7,8 +7,8 @@ #include "esphome/core/controller.h" #include "esphome/core/entity_base.h" -#include #include +#include #ifdef USE_ESP32 #include #include @@ -319,6 +319,16 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config); #endif +#ifdef USE_UPDATE + void on_update(update::UpdateEntity *obj) override; + + /// Handle a update request under '/update/'. + void handle_update_request(AsyncWebServerRequest *request, const UrlMatch &match); + + /// Dump the update state with its value as a JSON string. + std::string update_json(update::UpdateEntity *obj, JsonDetail start_config); +#endif + /// Override the web handler's canHandle method. bool canHandle(AsyncWebServerRequest *request) override; /// Override the web handler's handleRequest method. diff --git a/esphome/const.py b/esphome/const.py index dcb353ab1c..cbd932e3cc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1083,6 +1083,7 @@ DEVICE_CLASS_DURATION = "duration" DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_ENERGY = "energy" DEVICE_CLASS_ENERGY_STORAGE = "energy_storage" +DEVICE_CLASS_FIRMWARE = "firmware" DEVICE_CLASS_FREQUENCY = "frequency" DEVICE_CLASS_GARAGE = "garage" DEVICE_CLASS_GARAGE_DOOR = "garage_door" diff --git a/esphome/core/application.h b/esphome/core/application.h index c4c745b687..2697357456 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -69,6 +69,9 @@ #ifdef USE_EVENT #include "esphome/components/event/event.h" #endif +#ifdef USE_UPDATE +#include "esphome/components/update/update_entity.h" +#endif namespace esphome { @@ -178,6 +181,10 @@ class Application { void register_event(event::Event *event) { this->events_.push_back(event); } #endif +#ifdef USE_UPDATE + void register_update(update::UpdateEntity *update) { this->updates_.push_back(update); } +#endif + /// Register the component in this Application instance. template C *register_component(C *c) { static_assert(std::is_base_of::value, "Only Component subclasses can be registered"); @@ -421,6 +428,16 @@ class Application { } #endif +#ifdef USE_UPDATE + const std::vector &get_updates() { return this->updates_; } + update::UpdateEntity *get_update_by_key(uint32_t key, bool include_internal = false) { + for (auto *obj : this->updates_) + if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) + return obj; + return nullptr; + } +#endif + Scheduler scheduler; protected: @@ -495,6 +512,9 @@ class Application { #ifdef USE_ALARM_CONTROL_PANEL std::vector alarm_control_panels_{}; #endif +#ifdef USE_UPDATE + std::vector updates_{}; +#endif std::string name_; std::string friendly_name_; diff --git a/esphome/core/component_iterator.cpp b/esphome/core/component_iterator.cpp index 9b02bf527b..da593340c1 100644 --- a/esphome/core/component_iterator.cpp +++ b/esphome/core/component_iterator.cpp @@ -351,6 +351,21 @@ void ComponentIterator::advance() { } } break; +#endif +#ifdef USE_UPDATE + case IteratorState::UPDATE: + if (this->at_ >= App.get_updates().size()) { + advance_platform = true; + } else { + auto *update = App.get_updates()[this->at_]; + if (update->is_internal() && !this->include_internal_) { + success = true; + break; + } else { + success = this->on_update(update); + } + } + break; #endif case IteratorState::MAX: if (this->on_end()) { diff --git a/esphome/core/component_iterator.h b/esphome/core/component_iterator.h index 2b847bc088..9e187f6c57 100644 --- a/esphome/core/component_iterator.h +++ b/esphome/core/component_iterator.h @@ -86,6 +86,9 @@ class ComponentIterator { #endif #ifdef USE_EVENT virtual bool on_event(event::Event *event) = 0; +#endif +#ifdef USE_UPDATE + virtual bool on_update(update::UpdateEntity *update) = 0; #endif virtual bool on_end(); @@ -158,6 +161,9 @@ class ComponentIterator { #endif #ifdef USE_EVENT EVENT, +#endif +#ifdef USE_UPDATE + UPDATE, #endif MAX, } state_{IteratorState::NONE}; diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index 0957329500..d6d98a4316 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -121,6 +121,12 @@ void Controller::setup_controller(bool include_internal) { obj->add_on_event_callback([this, obj](const std::string &event_type) { this->on_event(obj, event_type); }); } #endif +#ifdef USE_UPDATE + for (auto *obj : App.get_updates()) { + if (include_internal || !obj->is_internal()) + obj->add_on_state_callback([this, obj]() { this->on_update(obj); }); + } +#endif } } // namespace esphome diff --git a/esphome/core/controller.h b/esphome/core/controller.h index e1bf93193a..39e0b2ba26 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -61,6 +61,9 @@ #ifdef USE_EVENT #include "esphome/components/event/event.h" #endif +#ifdef USE_UPDATE +#include "esphome/components/update/update_entity.h" +#endif namespace esphome { @@ -124,6 +127,9 @@ class Controller { #ifdef USE_EVENT virtual void on_event(event::Event *obj, const std::string &event_type){}; #endif +#ifdef USE_UPDATE + virtual void on_update(update::UpdateEntity *obj){}; +#endif }; } // namespace esphome diff --git a/esphome/core/defines.h b/esphome/core/defines.h index affcd78089..1e6f3517db 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -59,6 +59,7 @@ #define USE_TIME #define USE_TOUCHSCREEN #define USE_UART_DEBUGGER +#define USE_UPDATE #define USE_VALVE #define USE_WIFI #define USE_WIFI_AP diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml index 2b6996c0b9..83b334ca2d 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common.yaml @@ -73,3 +73,9 @@ button: url: http://my.ha.net:8123/local/esphome/firmware.bin - logger.log: "This message should be not displayed (reboot)" + +update: + - platform: http_request + name: OTA Update + id: ota_update + source: http://my.ha.net:8123/local/esphome/manifest.json diff --git a/tests/components/mqtt/common-update.yaml b/tests/components/mqtt/common-update.yaml new file mode 100644 index 0000000000..25f57cfef2 --- /dev/null +++ b/tests/components/mqtt/common-update.yaml @@ -0,0 +1,13 @@ +substitutions: + verify_ssl: "true" + +http_request: + verify_ssl: ${verify_ssl} + +ota: + - platform: http_request + +update: + - platform: http_request + name: "OTA Update" + source: https://example.com/ota.json diff --git a/tests/components/mqtt/test.esp32-c3-idf.yaml b/tests/components/mqtt/test.esp32-c3-idf.yaml index 25cb37a0b4..d19609b55e 100644 --- a/tests/components/mqtt/test.esp32-c3-idf.yaml +++ b/tests/components/mqtt/test.esp32-c3-idf.yaml @@ -1,2 +1,3 @@ packages: common: !include common.yaml + update: !include common-update.yaml diff --git a/tests/components/mqtt/test.esp32-c3.yaml b/tests/components/mqtt/test.esp32-c3.yaml index 25cb37a0b4..4c70fb37d9 100644 --- a/tests/components/mqtt/test.esp32-c3.yaml +++ b/tests/components/mqtt/test.esp32-c3.yaml @@ -1,2 +1,6 @@ +substitutions: + verify_ssl: "false" + packages: common: !include common.yaml + update: !include common-update.yaml diff --git a/tests/components/mqtt/test.esp32-idf.yaml b/tests/components/mqtt/test.esp32-idf.yaml index 25cb37a0b4..d19609b55e 100644 --- a/tests/components/mqtt/test.esp32-idf.yaml +++ b/tests/components/mqtt/test.esp32-idf.yaml @@ -1,2 +1,3 @@ packages: common: !include common.yaml + update: !include common-update.yaml diff --git a/tests/components/mqtt/test.esp32.yaml b/tests/components/mqtt/test.esp32.yaml index 25cb37a0b4..4c70fb37d9 100644 --- a/tests/components/mqtt/test.esp32.yaml +++ b/tests/components/mqtt/test.esp32.yaml @@ -1,2 +1,6 @@ +substitutions: + verify_ssl: "false" + packages: common: !include common.yaml + update: !include common-update.yaml diff --git a/tests/components/mqtt/test.esp8266.yaml b/tests/components/mqtt/test.esp8266.yaml index 25cb37a0b4..4c70fb37d9 100644 --- a/tests/components/mqtt/test.esp8266.yaml +++ b/tests/components/mqtt/test.esp8266.yaml @@ -1,2 +1,6 @@ +substitutions: + verify_ssl: "false" + packages: common: !include common.yaml + update: !include common-update.yaml diff --git a/tests/components/update/common.yaml b/tests/components/update/common.yaml new file mode 100644 index 0000000000..91b8669505 --- /dev/null +++ b/tests/components/update/common.yaml @@ -0,0 +1 @@ +update: diff --git a/tests/components/update/test.esp32-ard.yaml b/tests/components/update/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/update/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/update/test.esp32-idf.yaml b/tests/components/update/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/update/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/update/test.esp8266.yaml b/tests/components/update/test.esp8266.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/update/test.esp8266.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/update/test.rp2040.yaml b/tests/components/update/test.rp2040.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/update/test.rp2040.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 1f8449ec0e56d7fe7f0cca999f7d87843403d76b Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 11 Jun 2024 15:38:26 -0700 Subject: [PATCH 1864/2607] [Dockerfile] Sync platformio version with requirements.txt (#6888) --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 36be700f55..fcb5a5e7ae 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -81,7 +81,8 @@ RUN \ fi; \ pip3 install \ --break-system-packages --no-cache-dir \ - platformio==6.1.13 \ + # Keep platformio version in sync with requirements.txt + platformio==6.1.15 \ # Change some platformio settings && platformio settings set enable_telemetry No \ && platformio settings set check_platformio_interval 1000000 \ From 3a97244b8346bc4e1ca5eebcdccbfbde10f66a32 Mon Sep 17 00:00:00 2001 From: Anton Sergunov Date: Wed, 12 Jun 2024 04:42:20 +0600 Subject: [PATCH 1865/2607] [Deep sleep] Compilation error with IDF >= 5.* (#6879) --- esphome/components/deep_sleep/deep_sleep_component.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h index be56b529ba..7a640b9ea5 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.h +++ b/esphome/components/deep_sleep/deep_sleep_component.h @@ -34,10 +34,12 @@ enum WakeupPinMode { WAKEUP_PIN_MODE_INVERT_WAKEUP, }; +#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) struct Ext1Wakeup { uint64_t mask; esp_sleep_ext1_wakeup_mode_t wakeup_mode; }; +#endif struct WakeupCauseToRunDuration { // Run duration if woken up by timer or any other reason besides those below. @@ -114,7 +116,11 @@ class DeepSleepComponent : public Component { #ifdef USE_ESP32 InternalGPIOPin *wakeup_pin_; WakeupPinMode wakeup_pin_mode_{WAKEUP_PIN_MODE_IGNORE}; + +#if !defined(USE_ESP32_VARIANT_ESP32C3) optional ext1_wakeup_; +#endif + optional touch_wakeup_; optional wakeup_cause_to_run_duration_; #endif From c723fd1f8077b1d113b1d166c6bd43c35bc648a8 Mon Sep 17 00:00:00 2001 From: Landon Rohatensky Date: Tue, 11 Jun 2024 15:56:27 -0700 Subject: [PATCH 1866/2607] [animation] Allow loading external url at build time (#6876) --- esphome/components/animation/__init__.py | 53 ++++++++++++++++++++++-- esphome/components/image/__init__.py | 6 +-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index a7a955bead..dbfc82c891 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -3,7 +3,13 @@ import logging from esphome import automation, core from esphome.components import font import esphome.components.image as espImage -from esphome.components.image import CONF_USE_TRANSPARENCY +from esphome.components.image import ( + CONF_USE_TRANSPARENCY, + LOCAL_SCHEMA, + WEB_SCHEMA, + SOURCE_WEB, + SOURCE_LOCAL, +) import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( @@ -13,6 +19,9 @@ from esphome.const import ( CONF_REPEAT, CONF_RESIZE, CONF_TYPE, + CONF_SOURCE, + CONF_PATH, + CONF_URL, ) from esphome.core import CORE, HexInt @@ -43,6 +52,40 @@ SetFrameAction = animation_ns.class_( "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_) ) +TYPED_FILE_SCHEMA = cv.typed_schema( + { + SOURCE_LOCAL: LOCAL_SCHEMA, + SOURCE_WEB: WEB_SCHEMA, + }, + key=CONF_SOURCE, +) + + +def _file_schema(value): + if isinstance(value, str): + return validate_file_shorthand(value) + return TYPED_FILE_SCHEMA(value) + + +FILE_SCHEMA = cv.Schema(_file_schema) + + +def validate_file_shorthand(value): + value = cv.string_strict(value) + if value.startswith("http://") or value.startswith("https://"): + return FILE_SCHEMA( + { + CONF_SOURCE: SOURCE_WEB, + CONF_URL: value, + } + ) + return FILE_SCHEMA( + { + CONF_SOURCE: SOURCE_LOCAL, + CONF_PATH: value, + } + ) + def validate_cross_dependencies(config): """ @@ -67,7 +110,7 @@ ANIMATION_SCHEMA = cv.Schema( cv.All( { cv.Required(CONF_ID): cv.declare_id(Animation_), - cv.Required(CONF_FILE): cv.file_, + cv.Required(CONF_FILE): FILE_SCHEMA, cv.Optional(CONF_RESIZE): cv.dimensions, cv.Optional(CONF_TYPE, default="BINARY"): cv.enum( espImage.IMAGE_TYPE, upper=True @@ -124,7 +167,11 @@ async def animation_action_to_code(config, action_id, template_arg, args): async def to_code(config): from PIL import Image - path = CORE.relative_config_path(config[CONF_FILE]) + conf_file = config[CONF_FILE] + if conf_file[CONF_SOURCE] == SOURCE_LOCAL: + path = CORE.relative_config_path(conf_file[CONF_PATH]) + elif conf_file[CONF_SOURCE] == SOURCE_WEB: + path = espImage.compute_local_image_path(conf_file).as_posix() try: image = Image.open(path) except Exception as e: diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 73dc73aa45..b23ed3445a 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -68,7 +68,7 @@ def _compute_local_icon_path(value: dict) -> Path: return base_dir / f"{value[CONF_ICON]}.svg" -def _compute_local_image_path(value: dict) -> Path: +def compute_local_image_path(value: dict) -> Path: url = value[CONF_URL] h = hashlib.new("sha256") h.update(url.encode()) @@ -117,7 +117,7 @@ def download_mdi(value): def download_image(value): url = value[CONF_URL] - path = _compute_local_image_path(value) + path = compute_local_image_path(value) download_content(url, path) @@ -295,7 +295,7 @@ async def to_code(config): path = _compute_local_icon_path(conf_file).as_posix() elif conf_file[CONF_SOURCE] == SOURCE_WEB: - path = _compute_local_image_path(conf_file).as_posix() + path = compute_local_image_path(conf_file).as_posix() try: with open(path, "rb") as f: From a64106e48c47098999b7a52a683765cc18224ddd Mon Sep 17 00:00:00 2001 From: Peter Ericson Date: Wed, 12 Jun 2024 01:51:04 +0200 Subject: [PATCH 1867/2607] [waveshare_epaper] Add support for 13.3in-k (#6443) --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.cpp | 83 +++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 24 ++++++ 3 files changed, 111 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 9ad948e915..4d3965449f 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -94,6 +94,9 @@ WaveshareEPaper2P13InV2 = waveshare_epaper_ns.class_( WaveshareEPaper2P13InV3 = waveshare_epaper_ns.class_( "WaveshareEPaper2P13InV3", WaveshareEPaper ) +WaveshareEPaper13P3InK = waveshare_epaper_ns.class_( + "WaveshareEPaper13P3InK", WaveshareEPaper +) GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper) WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel") @@ -133,6 +136,7 @@ MODELS = { "2.13in-ttgo-dke": ("c", WaveshareEPaper2P13InDKE), "2.13inv3": ("c", WaveshareEPaper2P13InV3), "1.54in-m5coreink-m09": ("c", GDEW0154M09), + "13.3in-k": ("b", WaveshareEPaper13P3InK), } RESET_PIN_REQUIRED_MODELS = ("2.13inv2", "2.13in-ttgo-b74") diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 5428f4ec80..24df428e6f 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -2963,5 +2963,88 @@ void WaveshareEPaper2P13InDKE::set_full_update_every(uint32_t full_update_every) this->full_update_every_ = full_update_every; } +// ======================================================== +// 13.3in (K version) +// Datasheet/Specification/Reference: +// - https://files.waveshare.com/wiki/13.3inch-e-Paper-HAT-(K)/13.3-inch-e-Paper-(K)-user-manual.pdf +// - https://github.com/waveshareteam/e-Paper/tree/master/Arduino/epd13in3k +// ======================================================== + +// using default wait_until_idle_() function +void WaveshareEPaper13P3InK::initialize() { + this->wait_until_idle_(); + this->command(0x12); // SWRESET + this->wait_until_idle_(); + + this->command(0x0c); // set soft start + this->data(0xae); + this->data(0xc7); + this->data(0xc3); + this->data(0xc0); + this->data(0x80); + + this->command(0x01); // driver output control + this->data((get_height_internal() - 1) % 256); // Y + this->data((get_height_internal() - 1) / 256); // Y + this->data(0x00); + + this->command(0x11); // data entry mode + this->data(0x03); + + // SET WINDOWS + // XRAM_START_AND_END_POSITION + this->command(0x44); + this->data(0 & 0xFF); + this->data((0 >> 8) & 0x03); + this->data((get_width_internal() - 1) & 0xFF); + this->data(((get_width_internal() - 1) >> 8) & 0x03); + // YRAM_START_AND_END_POSITION + this->command(0x45); + this->data(0 & 0xFF); + this->data((0 >> 8) & 0x03); + this->data((get_height_internal() - 1) & 0xFF); + this->data(((get_height_internal() - 1) >> 8) & 0x03); + + this->command(0x3C); // Border setting + this->data(0x01); + + this->command(0x18); // use the internal temperature sensor + this->data(0x80); + + // SET CURSOR + // XRAM_ADDRESS + this->command(0x4E); + this->data(0 & 0xFF); + this->data((0 >> 8) & 0x03); + // YRAM_ADDRESS + this->command(0x4F); + this->data(0 & 0xFF); + this->data((0 >> 8) & 0x03); +} +void HOT WaveshareEPaper13P3InK::display() { + // do single full update + this->command(0x24); + this->start_data_(); + this->write_array(this->buffer_, this->get_buffer_length_()); + this->end_data_(); + + // COMMAND DISPLAY REFRESH + this->command(0x22); + this->data(0xF7); + this->command(0x20); +} + +int WaveshareEPaper13P3InK::get_width_internal() { return 960; } +int WaveshareEPaper13P3InK::get_height_internal() { return 680; } +uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; } +void WaveshareEPaper13P3InK::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper", this); + ESP_LOGCONFIG(TAG, " Model: 13.3inK"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + } // namespace waveshare_epaper } // namespace esphome diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 4a5844ae88..7572982a20 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -163,6 +163,7 @@ enum WaveshareEPaperTypeBModel { WAVESHARE_EPAPER_7_5_IN, WAVESHARE_EPAPER_7_5_INV2, WAVESHARE_EPAPER_7_5_IN_B_V2, + WAVESHARE_EPAPER_13_3_IN_K, }; class WaveshareEPaper2P7In : public WaveshareEPaper { @@ -769,5 +770,28 @@ class WaveshareEPaper2P13InV3 : public WaveshareEPaper { bool is_busy_{false}; void write_lut_(const uint8_t *lut); }; + +class WaveshareEPaper13P3InK : public WaveshareEPaper { + public: + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + // COMMAND DEEP SLEEP + this->command(0x10); + this->data(0x01); + } + + protected: + int get_width_internal() override; + + int get_height_internal() override; + + uint32_t idle_timeout_() override; +}; + } // namespace waveshare_epaper } // namespace esphome From 562700bd2c4014d8caf224cdeb45ae3969dcc7a4 Mon Sep 17 00:00:00 2001 From: Daniel D'Abate Date: Wed, 12 Jun 2024 02:04:25 +0200 Subject: [PATCH 1868/2607] Climate IR LG - Support fan only mode and all "on" commands (#3712) --- .../climate_ir_lg/climate_ir_lg.cpp | 187 ++++++++++-------- .../components/climate_ir_lg/climate_ir_lg.h | 2 +- 2 files changed, 102 insertions(+), 87 deletions(-) diff --git a/esphome/components/climate_ir_lg/climate_ir_lg.cpp b/esphome/components/climate_ir_lg/climate_ir_lg.cpp index d2199c1cbe..c65f24ebc0 100644 --- a/esphome/components/climate_ir_lg/climate_ir_lg.cpp +++ b/esphome/components/climate_ir_lg/climate_ir_lg.cpp @@ -6,18 +6,24 @@ namespace climate_ir_lg { static const char *const TAG = "climate.climate_ir_lg"; -const uint32_t COMMAND_ON = 0x00000; -const uint32_t COMMAND_ON_AI = 0x03000; -const uint32_t COMMAND_COOL = 0x08000; -const uint32_t COMMAND_HEAT = 0x0C000; +// Commands +const uint32_t COMMAND_MASK = 0xFF000; const uint32_t COMMAND_OFF = 0xC0000; const uint32_t COMMAND_SWING = 0x10000; -// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore. -const uint32_t COMMAND_AUTO = 0x0B000; -const uint32_t COMMAND_DRY_FAN = 0x09000; -const uint32_t COMMAND_MASK = 0xFF000; +const uint32_t COMMAND_ON_COOL = 0x00000; +const uint32_t COMMAND_ON_DRY = 0x01000; +const uint32_t COMMAND_ON_FAN_ONLY = 0x02000; +const uint32_t COMMAND_ON_AI = 0x03000; +const uint32_t COMMAND_ON_HEAT = 0x04000; +const uint32_t COMMAND_COOL = 0x08000; +const uint32_t COMMAND_DRY = 0x09000; +const uint32_t COMMAND_FAN_ONLY = 0x0A000; +const uint32_t COMMAND_AI = 0x0B000; +const uint32_t COMMAND_HEAT = 0x0C000; + +// Fan speed const uint32_t FAN_MASK = 0xF0; const uint32_t FAN_AUTO = 0x50; const uint32_t FAN_MIN = 0x00; @@ -35,69 +41,67 @@ void LgIrClimate::transmit_state() { uint32_t remote_state = 0x8800000; // ESP_LOGD(TAG, "climate_lg_ir mode_before_ code: 0x%02X", modeBefore_); + + // Set command if (send_swing_cmd_) { send_swing_cmd_ = false; remote_state |= COMMAND_SWING; } else { - if (mode_before_ == climate::CLIMATE_MODE_OFF && this->mode == climate::CLIMATE_MODE_HEAT_COOL) { - remote_state |= COMMAND_ON_AI; - } else if (mode_before_ == climate::CLIMATE_MODE_OFF && this->mode != climate::CLIMATE_MODE_OFF) { - remote_state |= COMMAND_ON; - this->mode = climate::CLIMATE_MODE_COOL; - } else { - switch (this->mode) { - case climate::CLIMATE_MODE_COOL: - remote_state |= COMMAND_COOL; - break; - case climate::CLIMATE_MODE_HEAT: - remote_state |= COMMAND_HEAT; - break; - case climate::CLIMATE_MODE_HEAT_COOL: - remote_state |= COMMAND_AUTO; - break; - case climate::CLIMATE_MODE_DRY: - remote_state |= COMMAND_DRY_FAN; - break; - case climate::CLIMATE_MODE_OFF: - default: - remote_state |= COMMAND_OFF; - break; - } - } - mode_before_ = this->mode; - - ESP_LOGD(TAG, "climate_lg_ir mode code: 0x%02X", this->mode); - - if (this->mode == climate::CLIMATE_MODE_OFF) { - remote_state |= FAN_AUTO; - } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY || - this->mode == climate::CLIMATE_MODE_HEAT) { - switch (this->fan_mode.value()) { - case climate::CLIMATE_FAN_HIGH: - remote_state |= FAN_MAX; - break; - case climate::CLIMATE_FAN_MEDIUM: - remote_state |= FAN_MED; - break; - case climate::CLIMATE_FAN_LOW: - remote_state |= FAN_MIN; - break; - case climate::CLIMATE_FAN_AUTO: - default: - remote_state |= FAN_AUTO; - break; - } - } - - if (this->mode == climate::CLIMATE_MODE_HEAT_COOL) { - this->fan_mode = climate::CLIMATE_FAN_AUTO; - // remote_state |= FAN_MODE_AUTO_DRY; - } - if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) { - auto temp = (uint8_t) roundf(clamp(this->target_temperature, TEMP_MIN, TEMP_MAX)); - remote_state |= ((temp - 15) << TEMP_SHIFT); + bool climate_is_off = (mode_before_ == climate::CLIMATE_MODE_OFF); + switch (this->mode) { + case climate::CLIMATE_MODE_COOL: + remote_state |= climate_is_off ? COMMAND_ON_COOL : COMMAND_COOL; + break; + case climate::CLIMATE_MODE_DRY: + remote_state |= climate_is_off ? COMMAND_ON_DRY : COMMAND_DRY; + break; + case climate::CLIMATE_MODE_FAN_ONLY: + remote_state |= climate_is_off ? COMMAND_ON_FAN_ONLY : COMMAND_FAN_ONLY; + break; + case climate::CLIMATE_MODE_HEAT_COOL: + remote_state |= climate_is_off ? COMMAND_ON_AI : COMMAND_AI; + break; + case climate::CLIMATE_MODE_HEAT: + remote_state |= climate_is_off ? COMMAND_ON_HEAT : COMMAND_HEAT; + break; + case climate::CLIMATE_MODE_OFF: + default: + remote_state |= COMMAND_OFF; + break; } } + + mode_before_ = this->mode; + + ESP_LOGD(TAG, "climate_lg_ir mode code: 0x%02X", this->mode); + + // Set fan speed + if (this->mode == climate::CLIMATE_MODE_OFF) { + remote_state |= FAN_AUTO; + } else { + switch (this->fan_mode.value()) { + case climate::CLIMATE_FAN_HIGH: + remote_state |= FAN_MAX; + break; + case climate::CLIMATE_FAN_MEDIUM: + remote_state |= FAN_MED; + break; + case climate::CLIMATE_FAN_LOW: + remote_state |= FAN_MIN; + break; + case climate::CLIMATE_FAN_AUTO: + default: + remote_state |= FAN_AUTO; + break; + } + } + + // Set temperature + if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) { + auto temp = (uint8_t) roundf(clamp(this->target_temperature, TEMP_MIN, TEMP_MAX)); + remote_state |= ((temp - 15) << TEMP_SHIFT); + } + transmit_(remote_state); this->publish_state(); } @@ -125,37 +129,42 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { if ((remote_state & 0xFF00000) != 0x8800000) return false; - if ((remote_state & COMMAND_MASK) == COMMAND_ON) { - this->mode = climate::CLIMATE_MODE_COOL; - } else if ((remote_state & COMMAND_MASK) == COMMAND_ON_AI) { - this->mode = climate::CLIMATE_MODE_HEAT_COOL; - } - + // Get command if ((remote_state & COMMAND_MASK) == COMMAND_OFF) { this->mode = climate::CLIMATE_MODE_OFF; } else if ((remote_state & COMMAND_MASK) == COMMAND_SWING) { this->swing_mode = this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; } else { - if ((remote_state & COMMAND_MASK) == COMMAND_AUTO) { - this->mode = climate::CLIMATE_MODE_HEAT_COOL; - } else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN) { - this->mode = climate::CLIMATE_MODE_DRY; - } else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) { - this->mode = climate::CLIMATE_MODE_HEAT; - } else { - this->mode = climate::CLIMATE_MODE_COOL; + switch (remote_state & COMMAND_MASK) { + case COMMAND_DRY: + case COMMAND_ON_DRY: + this->mode = climate::CLIMATE_MODE_DRY; + break; + case COMMAND_FAN_ONLY: + case COMMAND_ON_FAN_ONLY: + this->mode = climate::CLIMATE_MODE_FAN_ONLY; + break; + case COMMAND_AI: + case COMMAND_ON_AI: + this->mode = climate::CLIMATE_MODE_HEAT_COOL; + break; + case COMMAND_HEAT: + case COMMAND_ON_HEAT: + this->mode = climate::CLIMATE_MODE_HEAT; + break; + case COMMAND_COOL: + case COMMAND_ON_COOL: + default: + this->mode = climate::CLIMATE_MODE_COOL; + break; } - // Temperature - if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) - this->target_temperature = ((remote_state & TEMP_MASK) >> TEMP_SHIFT) + 15; - - // Fan Speed + // Get fan speed if (this->mode == climate::CLIMATE_MODE_HEAT_COOL) { this->fan_mode = climate::CLIMATE_FAN_AUTO; - } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT || - this->mode == climate::CLIMATE_MODE_DRY) { + } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY || + this->mode == climate::CLIMATE_MODE_FAN_ONLY || this->mode == climate::CLIMATE_MODE_HEAT) { if ((remote_state & FAN_MASK) == FAN_AUTO) { this->fan_mode = climate::CLIMATE_FAN_AUTO; } else if ((remote_state & FAN_MASK) == FAN_MIN) { @@ -166,11 +175,17 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { this->fan_mode = climate::CLIMATE_FAN_HIGH; } } + + // Get temperature + if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) { + this->target_temperature = ((remote_state & TEMP_MASK) >> TEMP_SHIFT) + 15; + } } this->publish_state(); return true; } + void LgIrClimate::transmit_(uint32_t value) { calc_checksum_(value); ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02" PRIX32, value); diff --git a/esphome/components/climate_ir_lg/climate_ir_lg.h b/esphome/components/climate_ir_lg/climate_ir_lg.h index 34f50744ef..7ee041b86f 100644 --- a/esphome/components/climate_ir_lg/climate_ir_lg.h +++ b/esphome/components/climate_ir_lg/climate_ir_lg.h @@ -14,7 +14,7 @@ const uint8_t TEMP_MAX = 30; // Celsius class LgIrClimate : public climate_ir::ClimateIR { public: LgIrClimate() - : climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, false, + : climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, true, {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH}, {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {} From 7b60543afd02960058e2cff58c70acebf68acc57 Mon Sep 17 00:00:00 2001 From: NMartin354 Date: Tue, 11 Jun 2024 19:38:20 -0500 Subject: [PATCH 1869/2607] [safe_mode] Allow user-defined interval for successful boot (#6882) Co-authored-by: Keith Burzinski --- esphome/components/safe_mode/__init__.py | 8 +++++++- esphome/components/safe_mode/safe_mode.cpp | 8 ++++++-- esphome/components/safe_mode/safe_mode.h | 13 +++++++------ tests/components/safe_mode/common.yaml | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index 92b285e279..881937890d 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -16,6 +16,7 @@ from esphome import automation CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] +CONF_BOOT_IS_GOOD_AFTER = "boot_is_good_after" CONF_ON_SAFE_MODE = "on_safe_mode" safe_mode_ns = cg.esphome_ns.namespace("safe_mode") @@ -34,6 +35,9 @@ CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(SafeModeComponent), + cv.Optional( + CONF_BOOT_IS_GOOD_AFTER, default="1min" + ): cv.positive_time_period_milliseconds, cv.Optional(CONF_DISABLED, default=False): cv.boolean, cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, cv.Optional( @@ -63,7 +67,9 @@ async def to_code(config): await automation.build_automation(trigger, [], conf) condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] + config[CONF_NUM_ATTEMPTS], + config[CONF_REBOOT_TIMEOUT], + config[CONF_BOOT_IS_GOOD_AFTER], ) cg.add(RawExpression(f"if ({condition}) return")) CORE.data[CONF_SAFE_MODE] = {} diff --git a/esphome/components/safe_mode/safe_mode.cpp b/esphome/components/safe_mode/safe_mode.cpp index 6934dcb9d9..aa1a4b6822 100644 --- a/esphome/components/safe_mode/safe_mode.cpp +++ b/esphome/components/safe_mode/safe_mode.cpp @@ -16,6 +16,8 @@ static const char *const TAG = "safe_mode"; void SafeModeComponent::dump_config() { ESP_LOGCONFIG(TAG, "Safe Mode:"); + ESP_LOGCONFIG(TAG, " Boot considered successful after %" PRIu32 " seconds", + this->safe_mode_boot_is_good_after_ / 1000); // because milliseconds ESP_LOGCONFIG(TAG, " Invoke after %u boot attempts", this->safe_mode_num_attempts_); ESP_LOGCONFIG(TAG, " Remain in safe mode for %" PRIu32 " seconds", this->safe_mode_enable_time_ / 1000); // because milliseconds @@ -34,7 +36,7 @@ void SafeModeComponent::dump_config() { float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } void SafeModeComponent::loop() { - if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) { + if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_boot_is_good_after_) { // successful boot, reset counter ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter"); this->clean_rtc(); @@ -60,9 +62,11 @@ bool SafeModeComponent::get_safe_mode_pending() { return this->read_rtc_() == SafeModeComponent::ENTER_SAFE_MODE_MAGIC; } -bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { +bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, + uint32_t boot_is_good_after) { this->safe_mode_start_time_ = millis(); this->safe_mode_enable_time_ = enable_time; + this->safe_mode_boot_is_good_after_ = boot_is_good_after; this->safe_mode_num_attempts_ = num_attempts; this->rtc_ = global_preferences->make_preference(233825507UL, false); this->safe_mode_rtc_value_ = this->read_rtc_(); diff --git a/esphome/components/safe_mode/safe_mode.h b/esphome/components/safe_mode/safe_mode.h index 0ec3c29529..37e2c3a3d6 100644 --- a/esphome/components/safe_mode/safe_mode.h +++ b/esphome/components/safe_mode/safe_mode.h @@ -11,7 +11,7 @@ namespace safe_mode { /// SafeModeComponent provides a safe way to recover from repeated boot failures class SafeModeComponent : public Component { public: - bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time); + bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, uint32_t boot_is_good_after); /// Set to true if the next startup will enter safe mode void set_safe_mode_pending(const bool &pending); @@ -33,11 +33,12 @@ class SafeModeComponent : public Component { void write_rtc_(uint32_t val); uint32_t read_rtc_(); - bool boot_successful_{false}; ///< set to true after boot is considered successful - uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled - uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for - uint32_t safe_mode_rtc_value_; - uint8_t safe_mode_num_attempts_; + bool boot_successful_{false}; ///< set to true after boot is considered successful + uint32_t safe_mode_boot_is_good_after_{60000}; ///< The amount of time after which the boot is considered successful + uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for + uint32_t safe_mode_rtc_value_{0}; + uint32_t safe_mode_start_time_{0}; ///< stores when safe mode was enabled + uint8_t safe_mode_num_attempts_{0}; ESPPreferenceObject rtc_; CallbackManager safe_mode_callback_{}; diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml index ce8bf2f0cf..c24f49e6b6 100644 --- a/tests/components/safe_mode/common.yaml +++ b/tests/components/safe_mode/common.yaml @@ -3,6 +3,7 @@ wifi: password: password1 safe_mode: + boot_is_good_after: 2min num_attempts: 3 reboot_timeout: 2min on_safe_mode: From 13fabf1cd8eae9fe783a9a83b5d4665b66c5b180 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 11 Jun 2024 18:05:44 -0700 Subject: [PATCH 1870/2607] change to new 1-wire platform (#6860) Co-authored-by: Samuel Sieb Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 3 + esphome/components/dallas/__init__.py | 24 +- .../components/dallas/dallas_component.cpp | 287 ------------------ esphome/components/dallas/dallas_component.h | 79 ----- esphome/components/dallas/esp_one_wire.cpp | 252 --------------- esphome/components/dallas/esp_one_wire.h | 68 ----- esphome/components/dallas/sensor.py | 51 +--- esphome/components/dallas_temp/__init__.py | 1 + .../components/dallas_temp/dallas_temp.cpp | 172 +++++++++++ esphome/components/dallas_temp/dallas_temp.h | 32 ++ esphome/components/dallas_temp/sensor.py | 43 +++ esphome/components/gpio/one_wire/__init__.py | 25 ++ .../gpio/one_wire/gpio_one_wire.cpp | 199 ++++++++++++ .../components/gpio/one_wire/gpio_one_wire.h | 41 +++ esphome/components/one_wire/__init__.py | 40 +++ esphome/components/one_wire/one_wire.cpp | 40 +++ esphome/components/one_wire/one_wire.h | 44 +++ esphome/components/one_wire/one_wire_bus.cpp | 88 ++++++ esphome/components/one_wire/one_wire_bus.h | 61 ++++ script/ci-custom.py | 3 +- .../{dallas => dallas_temp}/common.yaml | 10 +- .../test.esp32-c3-idf.yaml | 0 .../test.esp32-c3.yaml | 0 .../test.esp32-idf.yaml | 0 .../{dallas => dallas_temp}/test.esp32.yaml | 0 .../{dallas => dallas_temp}/test.esp8266.yaml | 0 .../{dallas => dallas_temp}/test.rp2040.yaml | 0 tests/test1.yaml | 12 - 28 files changed, 802 insertions(+), 773 deletions(-) delete mode 100644 esphome/components/dallas/dallas_component.cpp delete mode 100644 esphome/components/dallas/dallas_component.h delete mode 100644 esphome/components/dallas/esp_one_wire.cpp delete mode 100644 esphome/components/dallas/esp_one_wire.h create mode 100644 esphome/components/dallas_temp/__init__.py create mode 100644 esphome/components/dallas_temp/dallas_temp.cpp create mode 100644 esphome/components/dallas_temp/dallas_temp.h create mode 100644 esphome/components/dallas_temp/sensor.py create mode 100644 esphome/components/gpio/one_wire/__init__.py create mode 100644 esphome/components/gpio/one_wire/gpio_one_wire.cpp create mode 100644 esphome/components/gpio/one_wire/gpio_one_wire.h create mode 100644 esphome/components/one_wire/__init__.py create mode 100644 esphome/components/one_wire/one_wire.cpp create mode 100644 esphome/components/one_wire/one_wire.h create mode 100644 esphome/components/one_wire/one_wire_bus.cpp create mode 100644 esphome/components/one_wire/one_wire_bus.h rename tests/components/{dallas => dallas_temp}/common.yaml (55%) rename tests/components/{dallas => dallas_temp}/test.esp32-c3-idf.yaml (100%) rename tests/components/{dallas => dallas_temp}/test.esp32-c3.yaml (100%) rename tests/components/{dallas => dallas_temp}/test.esp32-idf.yaml (100%) rename tests/components/{dallas => dallas_temp}/test.esp32.yaml (100%) rename tests/components/{dallas => dallas_temp}/test.esp8266.yaml (100%) rename tests/components/{dallas => dallas_temp}/test.rp2040.yaml (100%) diff --git a/CODEOWNERS b/CODEOWNERS index bbb39c26ad..75ea4fe523 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -94,6 +94,7 @@ esphome/components/current_based/* @djwmarcx esphome/components/dac7678/* @NickB1 esphome/components/daikin_arc/* @MagicBear esphome/components/daikin_brc/* @hagak +esphome/components/dallas_temp/* @ssieb esphome/components/daly_bms/* @s1lvi0 esphome/components/dashboard_import/* @esphome/core esphome/components/datetime/* @jesserockz @rfdarter @@ -144,6 +145,7 @@ esphome/components/gdk101/* @Szewcson esphome/components/globals/* @esphome/core esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core +esphome/components/gpio/one_wire/* @ssieb esphome/components/gps/* @coogle esphome/components/graph/* @synco esphome/components/graphical_display_menu/* @MrMDavidson @@ -270,6 +272,7 @@ esphome/components/nextion/text_sensor/* @senexcrenshaw esphome/components/nfc/* @jesserockz @kbx81 esphome/components/noblex/* @AGalfra esphome/components/number/* @esphome/core +esphome/components/one_wire/* @ssieb esphome/components/ota/* @esphome/core esphome/components/output/* @esphome/core esphome/components/pca6416a/* @Mat931 diff --git a/esphome/components/dallas/__init__.py b/esphome/components/dallas/__init__.py index 0f71399a7c..6c2a9d830e 100644 --- a/esphome/components/dallas/__init__.py +++ b/esphome/components/dallas/__init__.py @@ -1,25 +1,7 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome import pins -from esphome.const import CONF_ID, CONF_PIN MULTI_CONF = True -AUTO_LOAD = ["sensor"] -dallas_ns = cg.esphome_ns.namespace("dallas") -DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent) - -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(DallasComponent), - cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, - } -).extend(cv.polling_component_schema("60s")) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - - pin = await cg.gpio_pin_expression(config[CONF_PIN]) - cg.add(var.set_pin(pin)) +CONFIG_SCHEMA = cv.invalid( + 'The "dallas" component has been replaced by the "one_wire" component.\nhttps://esphome.io/components/one_wire' +) diff --git a/esphome/components/dallas/dallas_component.cpp b/esphome/components/dallas/dallas_component.cpp deleted file mode 100644 index a51bc369a1..0000000000 --- a/esphome/components/dallas/dallas_component.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "dallas_component.h" -#include "esphome/core/log.h" - -namespace esphome { -namespace dallas { - -static const char *const TAG = "dallas.sensor"; - -static const uint8_t DALLAS_MODEL_DS18S20 = 0x10; -static const uint8_t DALLAS_MODEL_DS1822 = 0x22; -static const uint8_t DALLAS_MODEL_DS18B20 = 0x28; -static const uint8_t DALLAS_MODEL_DS1825 = 0x3B; -static const uint8_t DALLAS_MODEL_DS28EA00 = 0x42; -static const uint8_t DALLAS_COMMAND_START_CONVERSION = 0x44; -static const uint8_t DALLAS_COMMAND_READ_SCRATCH_PAD = 0xBE; -static const uint8_t DALLAS_COMMAND_WRITE_SCRATCH_PAD = 0x4E; - -uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion() const { - switch (this->resolution_) { - case 9: - return 94; - case 10: - return 188; - case 11: - return 375; - default: - return 750; - } -} - -void DallasComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); - - pin_->setup(); - - // clear bus with 480µs high, otherwise initial reset in search_vec() fails - pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - delayMicroseconds(480); - - one_wire_ = new ESPOneWire(pin_); // NOLINT(cppcoreguidelines-owning-memory) - - std::vector raw_sensors; - raw_sensors = this->one_wire_->search_vec(); - - for (auto &address : raw_sensors) { - auto *address8 = reinterpret_cast(&address); - if (crc8(address8, 7) != address8[7]) { - ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str()); - continue; - } - if (address8[0] != DALLAS_MODEL_DS18S20 && address8[0] != DALLAS_MODEL_DS1822 && - address8[0] != DALLAS_MODEL_DS18B20 && address8[0] != DALLAS_MODEL_DS1825 && - address8[0] != DALLAS_MODEL_DS28EA00) { - ESP_LOGW(TAG, "Unknown device type 0x%02X.", address8[0]); - continue; - } - this->found_sensors_.push_back(address); - } - - for (auto *sensor : this->sensors_) { - if (sensor->get_index().has_value()) { - if (*sensor->get_index() >= this->found_sensors_.size()) { - this->status_set_error("Sensor configured by index but not found"); - continue; - } - sensor->set_address(this->found_sensors_[*sensor->get_index()]); - } - - if (!sensor->setup_sensor()) { - this->status_set_error(); - } - } -} -void DallasComponent::dump_config() { - ESP_LOGCONFIG(TAG, "DallasComponent:"); - LOG_PIN(" Pin: ", this->pin_); - LOG_UPDATE_INTERVAL(this); - - if (this->found_sensors_.empty()) { - ESP_LOGW(TAG, " Found no sensors!"); - } else { - ESP_LOGD(TAG, " Found sensors:"); - for (auto &address : this->found_sensors_) { - ESP_LOGD(TAG, " 0x%s", format_hex(address).c_str()); - } - } - - for (auto *sensor : this->sensors_) { - LOG_SENSOR(" ", "Device", sensor); - if (sensor->get_index().has_value()) { - ESP_LOGCONFIG(TAG, " Index %u", *sensor->get_index()); - if (*sensor->get_index() >= this->found_sensors_.size()) { - ESP_LOGE(TAG, "Couldn't find sensor by index - not connected. Proceeding without it."); - continue; - } - } - ESP_LOGCONFIG(TAG, " Address: %s", sensor->get_address_name().c_str()); - ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution()); - } -} - -void DallasComponent::register_sensor(DallasTemperatureSensor *sensor) { this->sensors_.push_back(sensor); } -void DallasComponent::update() { - this->status_clear_warning(); - - bool result; - { - InterruptLock lock; - result = this->one_wire_->reset(); - } - if (!result) { - if (!this->found_sensors_.empty()) { - // Only log error if at the start sensors were found (and thus are disconnected during uptime) - ESP_LOGE(TAG, "Requesting conversion failed"); - this->status_set_warning(); - } - - for (auto *sensor : this->sensors_) { - sensor->publish_state(NAN); - } - return; - } - - { - InterruptLock lock; - this->one_wire_->skip(); - this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); - } - - for (auto *sensor : this->sensors_) { - if (sensor->get_address() == 0) { - ESP_LOGV(TAG, "'%s' - Indexed sensor not found at startup, skipping update", sensor->get_name().c_str()); - sensor->publish_state(NAN); - continue; - } - - this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { - bool res = sensor->read_scratch_pad(); - - if (!res) { - ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str()); - sensor->publish_state(NAN); - this->status_set_warning(); - return; - } - if (!sensor->check_scratch_pad()) { - sensor->publish_state(NAN); - this->status_set_warning(); - return; - } - - float tempc = sensor->get_temp_c(); - ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", sensor->get_name().c_str(), tempc); - sensor->publish_state(tempc); - }); - } -} - -void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; } -uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; } -void DallasTemperatureSensor::set_resolution(uint8_t resolution) { this->resolution_ = resolution; } -optional DallasTemperatureSensor::get_index() const { return this->index_; } -void DallasTemperatureSensor::set_index(uint8_t index) { this->index_ = index; } -uint8_t *DallasTemperatureSensor::get_address8() { return reinterpret_cast(&this->address_); } -uint64_t DallasTemperatureSensor::get_address() { return this->address_; } - -const std::string &DallasTemperatureSensor::get_address_name() { - if (this->address_name_.empty()) { - this->address_name_ = std::string("0x") + format_hex(this->address_); - } - - return this->address_name_; -} -bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { - auto *wire = this->parent_->one_wire_; - - { - InterruptLock lock; - - if (!wire->reset()) { - return false; - } - - wire->select(this->address_); - wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD); - - for (unsigned char &i : this->scratch_pad_) { - i = wire->read8(); - } - } - - return true; -} -bool DallasTemperatureSensor::setup_sensor() { - bool r = this->read_scratch_pad(); - - if (!r) { - ESP_LOGE(TAG, "Reading scratchpad failed: reset"); - return false; - } - if (!this->check_scratch_pad()) - return false; - - if (this->scratch_pad_[4] == this->resolution_) - return false; - - if (this->get_address8()[0] == DALLAS_MODEL_DS18S20) { - // DS18S20 doesn't support resolution. - ESP_LOGW(TAG, "DS18S20 doesn't support setting resolution."); - return false; - } - - switch (this->resolution_) { - case 12: - this->scratch_pad_[4] = 0x7F; - break; - case 11: - this->scratch_pad_[4] = 0x5F; - break; - case 10: - this->scratch_pad_[4] = 0x3F; - break; - case 9: - default: - this->scratch_pad_[4] = 0x1F; - break; - } - - auto *wire = this->parent_->one_wire_; - { - InterruptLock lock; - if (wire->reset()) { - wire->select(this->address_); - wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); - wire->write8(this->scratch_pad_[2]); // high alarm temp - wire->write8(this->scratch_pad_[3]); // low alarm temp - wire->write8(this->scratch_pad_[4]); // resolution - wire->reset(); - - // write value to EEPROM - wire->select(this->address_); - wire->write8(0x48); - } - } - - delay(20); // allow it to finish operation - wire->reset(); - return true; -} -bool DallasTemperatureSensor::check_scratch_pad() { - bool chksum_validity = (crc8(this->scratch_pad_, 8) == this->scratch_pad_[8]); - bool config_validity = false; - - switch (this->get_address8()[0]) { - case DALLAS_MODEL_DS18B20: - config_validity = ((this->scratch_pad_[4] & 0x9F) == 0x1F); - break; - default: - config_validity = ((this->scratch_pad_[4] & 0x10) == 0x10); - } - -#ifdef ESPHOME_LOG_LEVEL_VERY_VERBOSE - ESP_LOGVV(TAG, "Scratch pad: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X (%02X)", this->scratch_pad_[0], - this->scratch_pad_[1], this->scratch_pad_[2], this->scratch_pad_[3], this->scratch_pad_[4], - this->scratch_pad_[5], this->scratch_pad_[6], this->scratch_pad_[7], this->scratch_pad_[8], - crc8(this->scratch_pad_, 8)); -#endif - if (!chksum_validity) { - ESP_LOGW(TAG, "'%s' - Scratch pad checksum invalid!", this->get_name().c_str()); - } else if (!config_validity) { - ESP_LOGW(TAG, "'%s' - Scratch pad config register invalid!", this->get_name().c_str()); - } - return chksum_validity && config_validity; -} -float DallasTemperatureSensor::get_temp_c() { - int16_t temp = (int16_t(this->scratch_pad_[1]) << 11) | (int16_t(this->scratch_pad_[0]) << 3); - if (this->get_address8()[0] == DALLAS_MODEL_DS18S20) { - int diff = (this->scratch_pad_[7] - this->scratch_pad_[6]) << 7; - temp = ((temp & 0xFFF0) << 3) - 16 + (diff / this->scratch_pad_[7]); - } - - return temp / 128.0f; -} -std::string DallasTemperatureSensor::unique_id() { return "dallas-" + str_lower_case(format_hex(this->address_)); } - -} // namespace dallas -} // namespace esphome diff --git a/esphome/components/dallas/dallas_component.h b/esphome/components/dallas/dallas_component.h deleted file mode 100644 index 10bde7338b..0000000000 --- a/esphome/components/dallas/dallas_component.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" -#include "esphome/components/sensor/sensor.h" -#include "esp_one_wire.h" - -#include - -namespace esphome { -namespace dallas { - -class DallasTemperatureSensor; - -class DallasComponent : public PollingComponent { - public: - void set_pin(InternalGPIOPin *pin) { pin_ = pin; } - void register_sensor(DallasTemperatureSensor *sensor); - - void setup() override; - void dump_config() override; - float get_setup_priority() const override { return setup_priority::DATA; } - - void update() override; - - protected: - friend DallasTemperatureSensor; - - InternalGPIOPin *pin_; - ESPOneWire *one_wire_; - std::vector sensors_; - std::vector found_sensors_; -}; - -/// Internal class that helps us create multiple sensors for one Dallas hub. -class DallasTemperatureSensor : public sensor::Sensor { - public: - void set_parent(DallasComponent *parent) { parent_ = parent; } - /// Helper to get a pointer to the address as uint8_t. - uint8_t *get_address8(); - uint64_t get_address(); - /// Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29". - const std::string &get_address_name(); - - /// Set the 64-bit unsigned address for this sensor. - void set_address(uint64_t address); - /// Get the index of this sensor. (0 if using address.) - optional get_index() const; - /// Set the index of this sensor. If using index, address will be set after setup. - void set_index(uint8_t index); - /// Get the set resolution for this sensor. - uint8_t get_resolution() const; - /// Set the resolution for this sensor. - void set_resolution(uint8_t resolution); - /// Get the number of milliseconds we have to wait for the conversion phase. - uint16_t millis_to_wait_for_conversion() const; - - bool setup_sensor(); - bool read_scratch_pad(); - - bool check_scratch_pad(); - - float get_temp_c(); - - std::string unique_id() override; - - protected: - DallasComponent *parent_; - uint64_t address_; - optional index_; - - uint8_t resolution_; - std::string address_name_; - uint8_t scratch_pad_[9] = { - 0, - }; -}; - -} // namespace dallas -} // namespace esphome diff --git a/esphome/components/dallas/esp_one_wire.cpp b/esphome/components/dallas/esp_one_wire.cpp deleted file mode 100644 index 32ddf07fb6..0000000000 --- a/esphome/components/dallas/esp_one_wire.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "esp_one_wire.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" - -namespace esphome { -namespace dallas { - -static const char *const TAG = "dallas.one_wire"; - -const uint8_t ONE_WIRE_ROM_SELECT = 0x55; -const int ONE_WIRE_ROM_SEARCH = 0xF0; - -ESPOneWire::ESPOneWire(InternalGPIOPin *pin) { pin_ = pin->to_isr(); } - -bool HOT IRAM_ATTR ESPOneWire::reset() { - // See reset here: - // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html - // Wait for communication to clear (delay G) - pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - uint8_t retries = 125; - do { - if (--retries == 0) - return false; - delayMicroseconds(2); - } while (!pin_.digital_read()); - - // Send 480µs LOW TX reset pulse (drive bus low, delay H) - pin_.pin_mode(gpio::FLAG_OUTPUT); - pin_.digital_write(false); - delayMicroseconds(480); - - // Release the bus, delay I - pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - delayMicroseconds(70); - - // sample bus, 0=device(s) present, 1=no device present - bool r = !pin_.digital_read(); - // delay J - delayMicroseconds(410); - return r; -} - -void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) { - // drive bus low - pin_.pin_mode(gpio::FLAG_OUTPUT); - pin_.digital_write(false); - - // from datasheet: - // write 0 low time: t_low0: min=60µs, max=120µs - // write 1 low time: t_low1: min=1µs, max=15µs - // time slot: t_slot: min=60µs, max=120µs - // recovery time: t_rec: min=1µs - // ds18b20 appears to read the bus after roughly 14µs - uint32_t delay0 = bit ? 6 : 60; - uint32_t delay1 = bit ? 54 : 5; - - // delay A/C - delayMicroseconds(delay0); - // release bus - pin_.digital_write(true); - // delay B/D - delayMicroseconds(delay1); -} - -bool HOT IRAM_ATTR ESPOneWire::read_bit() { - // drive bus low - pin_.pin_mode(gpio::FLAG_OUTPUT); - pin_.digital_write(false); - - // note: for reading we'll need very accurate timing, as the - // timing for the digital_read() is tight; according to the datasheet, - // we should read at the end of 16µs starting from the bus low - // typically, the ds18b20 pulls the line high after 11µs for a logical 1 - // and 29µs for a logical 0 - - uint32_t start = micros(); - // datasheet says >1µs - delayMicroseconds(3); - - // release bus, delay E - pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - - // Unfortunately some frameworks have different characteristics than others - // esp32 arduino appears to pull the bus low only after the digital_write(false), - // whereas on esp-idf it already happens during the pin_mode(OUTPUT) - // manually correct for this with these constants. - -#ifdef USE_ESP32 - uint32_t timing_constant = 12; -#else - uint32_t timing_constant = 14; -#endif - - // measure from start value directly, to get best accurate timing no matter - // how long pin_mode/delayMicroseconds took - while (micros() - start < timing_constant) - ; - - // sample bus to read bit from peer - bool r = pin_.digital_read(); - - // read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked - uint32_t now = micros(); - if (now - start < 60) - delayMicroseconds(60 - (now - start)); - - return r; -} - -void IRAM_ATTR ESPOneWire::write8(uint8_t val) { - for (uint8_t i = 0; i < 8; i++) { - this->write_bit(bool((1u << i) & val)); - } -} - -void IRAM_ATTR ESPOneWire::write64(uint64_t val) { - for (uint8_t i = 0; i < 64; i++) { - this->write_bit(bool((1ULL << i) & val)); - } -} - -uint8_t IRAM_ATTR ESPOneWire::read8() { - uint8_t ret = 0; - for (uint8_t i = 0; i < 8; i++) { - ret |= (uint8_t(this->read_bit()) << i); - } - return ret; -} -uint64_t IRAM_ATTR ESPOneWire::read64() { - uint64_t ret = 0; - for (uint8_t i = 0; i < 8; i++) { - ret |= (uint64_t(this->read_bit()) << i); - } - return ret; -} -void IRAM_ATTR ESPOneWire::select(uint64_t address) { - this->write8(ONE_WIRE_ROM_SELECT); - this->write64(address); -} -void IRAM_ATTR ESPOneWire::reset_search() { - this->last_discrepancy_ = 0; - this->last_device_flag_ = false; - this->rom_number_ = 0; -} -uint64_t IRAM_ATTR ESPOneWire::search() { - if (this->last_device_flag_) { - return 0u; - } - - { - InterruptLock lock; - if (!this->reset()) { - // Reset failed or no devices present - this->reset_search(); - return 0u; - } - } - - uint8_t id_bit_number = 1; - uint8_t last_zero = 0; - uint8_t rom_byte_number = 0; - bool search_result = false; - uint8_t rom_byte_mask = 1; - - { - InterruptLock lock; - // Initiate search - this->write8(ONE_WIRE_ROM_SEARCH); - do { - // read bit - bool id_bit = this->read_bit(); - // read its complement - bool cmp_id_bit = this->read_bit(); - - if (id_bit && cmp_id_bit) { - // No devices participating in search - break; - } - - bool branch; - - if (id_bit != cmp_id_bit) { - // only chose one branch, the other one doesn't have any devices. - branch = id_bit; - } else { - // there are devices with both 0s and 1s at this bit - if (id_bit_number < this->last_discrepancy_) { - branch = (this->rom_number8_()[rom_byte_number] & rom_byte_mask) > 0; - } else { - branch = id_bit_number == this->last_discrepancy_; - } - - if (!branch) { - last_zero = id_bit_number; - } - } - - if (branch) { - // set bit - this->rom_number8_()[rom_byte_number] |= rom_byte_mask; - } else { - // clear bit - this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask; - } - - // choose/announce branch - this->write_bit(branch); - id_bit_number++; - rom_byte_mask <<= 1; - if (rom_byte_mask == 0u) { - // go to next byte - rom_byte_number++; - rom_byte_mask = 1; - } - } while (rom_byte_number < 8); // loop through all bytes - } - - if (id_bit_number >= 65) { - this->last_discrepancy_ = last_zero; - if (this->last_discrepancy_ == 0) { - // we're at root and have no choices left, so this was the last one. - this->last_device_flag_ = true; - } - search_result = true; - } - - search_result = search_result && (this->rom_number8_()[0] != 0); - if (!search_result) { - this->reset_search(); - return 0u; - } - - return this->rom_number_; -} -std::vector ESPOneWire::search_vec() { - std::vector res; - - this->reset_search(); - uint64_t address; - while ((address = this->search()) != 0u) - res.push_back(address); - - return res; -} -void IRAM_ATTR ESPOneWire::skip() { - this->write8(0xCC); // skip ROM -} - -uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast(&this->rom_number_); } - -} // namespace dallas -} // namespace esphome diff --git a/esphome/components/dallas/esp_one_wire.h b/esphome/components/dallas/esp_one_wire.h deleted file mode 100644 index 7544a6fe98..0000000000 --- a/esphome/components/dallas/esp_one_wire.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "esphome/core/hal.h" -#include - -namespace esphome { -namespace dallas { - -extern const uint8_t ONE_WIRE_ROM_SELECT; -extern const int ONE_WIRE_ROM_SEARCH; - -class ESPOneWire { - public: - explicit ESPOneWire(InternalGPIOPin *pin); - - /** Reset the bus, should be done before all write operations. - * - * Takes approximately 1ms. - * - * @return Whether the operation was successful. - */ - bool reset(); - - /// Write a single bit to the bus, takes about 70µs. - void write_bit(bool bit); - - /// Read a single bit from the bus, takes about 70µs - bool read_bit(); - - /// Write a word to the bus. LSB first. - void write8(uint8_t val); - - /// Write a 64 bit unsigned integer to the bus. LSB first. - void write64(uint64_t val); - - /// Write a command to the bus that addresses all devices by skipping the ROM. - void skip(); - - /// Read an 8 bit word from the bus. - uint8_t read8(); - - /// Read an 64-bit unsigned integer from the bus. - uint64_t read64(); - - /// Select a specific address on the bus for the following command. - void select(uint64_t address); - - /// Reset the device search. - void reset_search(); - - /// Search for a 1-Wire device on the bus. Returns 0 if all devices have been found. - uint64_t search(); - - /// Helper that wraps search in a std::vector. - std::vector search_vec(); - - protected: - /// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer. - inline uint8_t *rom_number8_(); - - ISRInternalGPIOPin pin_; - uint8_t last_discrepancy_{0}; - bool last_device_flag_{false}; - uint64_t rom_number_{0}; -}; - -} // namespace dallas -} // namespace esphome diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py index c6ebda62c8..69f8fc3b9e 100644 --- a/esphome/components/dallas/sensor.py +++ b/esphome/components/dallas/sensor.py @@ -1,50 +1,5 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor -from esphome.const import ( - CONF_ADDRESS, - CONF_DALLAS_ID, - CONF_INDEX, - CONF_RESOLUTION, - DEVICE_CLASS_TEMPERATURE, - STATE_CLASS_MEASUREMENT, - UNIT_CELSIUS, + +CONFIG_SCHEMA = cv.invalid( + 'The "dallas" sensor is now "dallas_temp"\nhttps://esphome.io/components/sensor/dallas_temp' ) -from . import DallasComponent, dallas_ns - -DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sensor) - -CONFIG_SCHEMA = cv.All( - sensor.sensor_schema( - DallasTemperatureSensor, - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=1, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent), - cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, - cv.Optional(CONF_INDEX): cv.positive_int, - cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12), - } - ), - cv.has_exactly_one_key(CONF_ADDRESS, CONF_INDEX), -) - - -async def to_code(config): - hub = await cg.get_variable(config[CONF_DALLAS_ID]) - var = await sensor.new_sensor(config) - - if CONF_ADDRESS in config: - cg.add(var.set_address(config[CONF_ADDRESS])) - else: - cg.add(var.set_index(config[CONF_INDEX])) - - if CONF_RESOLUTION in config: - cg.add(var.set_resolution(config[CONF_RESOLUTION])) - - cg.add(var.set_parent(hub)) - - cg.add(hub.register_sensor(var)) diff --git a/esphome/components/dallas_temp/__init__.py b/esphome/components/dallas_temp/__init__.py new file mode 100644 index 0000000000..3f73044ca8 --- /dev/null +++ b/esphome/components/dallas_temp/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@ssieb"] diff --git a/esphome/components/dallas_temp/dallas_temp.cpp b/esphome/components/dallas_temp/dallas_temp.cpp new file mode 100644 index 0000000000..fe7c9a95ea --- /dev/null +++ b/esphome/components/dallas_temp/dallas_temp.cpp @@ -0,0 +1,172 @@ +#include "dallas_temp.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace dallas_temp { + +static const char *const TAG = "dallas.temp.sensor"; + +static const uint8_t DALLAS_MODEL_DS18S20 = 0x10; +static const uint8_t DALLAS_COMMAND_START_CONVERSION = 0x44; +static const uint8_t DALLAS_COMMAND_READ_SCRATCH_PAD = 0xBE; +static const uint8_t DALLAS_COMMAND_WRITE_SCRATCH_PAD = 0x4E; +static const uint8_t DALLAS_COMMAND_COPY_SCRATCH_PAD = 0x48; + +uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion_() const { + switch (this->resolution_) { + case 9: + return 94; + case 10: + return 188; + case 11: + return 375; + default: + return 750; + } +} + +void DallasTemperatureSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Dallas Temperature Sensor:"); + if (this->address_ == 0) { + ESP_LOGW(TAG, " Unable to select an address"); + return; + } + LOG_ONE_WIRE_DEVICE(this); + ESP_LOGCONFIG(TAG, " Resolution: %u bits", this->resolution_); + LOG_UPDATE_INTERVAL(this); +} + +void DallasTemperatureSensor::update() { + if (this->address_ == 0) + return; + + this->status_clear_warning(); + + this->send_command_(DALLAS_COMMAND_START_CONVERSION); + + this->set_timeout(this->get_address_name(), this->millis_to_wait_for_conversion_(), [this] { + if (!this->read_scratch_pad_() || !this->check_scratch_pad_()) { + this->publish_state(NAN); + return; + } + + float tempc = this->get_temp_c_(); + ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", this->get_name().c_str(), tempc); + this->publish_state(tempc); + }); +} + +void IRAM_ATTR DallasTemperatureSensor::read_scratch_pad_int_() { + for (uint8_t &i : this->scratch_pad_) { + i = this->bus_->read8(); + } +} + +bool DallasTemperatureSensor::read_scratch_pad_() { + bool success; + { + InterruptLock lock; + success = this->send_command_(DALLAS_COMMAND_READ_SCRATCH_PAD); + if (success) + this->read_scratch_pad_int_(); + } + if (!success) { + ESP_LOGW(TAG, "'%s' - reading scratch pad failed bus reset", this->get_name().c_str()); + this->status_set_warning("bus reset failed"); + } + return success; +} + +void DallasTemperatureSensor::setup() { + ESP_LOGCONFIG(TAG, "setting up Dallas temperature sensor..."); + if (!this->check_address_()) + return; + if (!this->read_scratch_pad_()) + return; + if (!this->check_scratch_pad_()) + return; + + if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) { + // DS18S20 doesn't support resolution. + ESP_LOGW(TAG, "DS18S20 doesn't support setting resolution."); + return; + } + + uint8_t res; + switch (this->resolution_) { + case 12: + res = 0x7F; + break; + case 11: + res = 0x5F; + break; + case 10: + res = 0x3F; + break; + case 9: + default: + res = 0x1F; + break; + } + + if (this->scratch_pad_[4] == res) + return; + this->scratch_pad_[4] = res; + + { + InterruptLock lock; + if (this->send_command_(DALLAS_COMMAND_WRITE_SCRATCH_PAD)) { + this->bus_->write8(this->scratch_pad_[2]); // high alarm temp + this->bus_->write8(this->scratch_pad_[3]); // low alarm temp + this->bus_->write8(this->scratch_pad_[4]); // resolution + } + + // write value to EEPROM + this->send_command_(DALLAS_COMMAND_COPY_SCRATCH_PAD); + } +} + +bool DallasTemperatureSensor::check_scratch_pad_() { + bool chksum_validity = (crc8(this->scratch_pad_, 8) == this->scratch_pad_[8]); + +#ifdef ESPHOME_LOG_LEVEL_VERY_VERBOSE + ESP_LOGVV(TAG, "Scratch pad: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X (%02X)", this->scratch_pad_[0], + this->scratch_pad_[1], this->scratch_pad_[2], this->scratch_pad_[3], this->scratch_pad_[4], + this->scratch_pad_[5], this->scratch_pad_[6], this->scratch_pad_[7], this->scratch_pad_[8], + crc8(this->scratch_pad_, 8)); +#endif + if (!chksum_validity) { + ESP_LOGW(TAG, "'%s' - Scratch pad checksum invalid!", this->get_name().c_str()); + this->status_set_warning("scratch pad checksum invalid"); + } + return chksum_validity; +} + +float DallasTemperatureSensor::get_temp_c_() { + int16_t temp = (this->scratch_pad_[1] << 8) | this->scratch_pad_[0]; + if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) { + if (this->scratch_pad_[7] != 0x10) + ESP_LOGE(TAG, "unexpected COUNT_PER_C value: %u", this->scratch_pad_[7]); + temp = ((temp & 0xfff7) << 3) + (0x10 - this->scratch_pad_[6]) - 4; + } else { + switch (this->resolution_) { + case 9: + temp &= 0xfff8; + break; + case 10: + temp &= 0xfffc; + break; + case 11: + temp &= 0xfffe; + break; + case 12: + default: + break; + } + } + + return temp / 16.0f; +} + +} // namespace dallas_temp +} // namespace esphome diff --git a/esphome/components/dallas_temp/dallas_temp.h b/esphome/components/dallas_temp/dallas_temp.h new file mode 100644 index 0000000000..604c9d0cd7 --- /dev/null +++ b/esphome/components/dallas_temp/dallas_temp.h @@ -0,0 +1,32 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/one_wire/one_wire.h" + +namespace esphome { +namespace dallas_temp { + +class DallasTemperatureSensor : public PollingComponent, public sensor::Sensor, public one_wire::OneWireDevice { + public: + void setup() override; + void update() override; + void dump_config() override; + + /// Set the resolution for this sensor. + void set_resolution(uint8_t resolution) { this->resolution_ = resolution; } + + protected: + uint8_t resolution_; + uint8_t scratch_pad_[9] = {0}; + + /// Get the number of milliseconds we have to wait for the conversion phase. + uint16_t millis_to_wait_for_conversion_() const; + bool read_scratch_pad_(); + void read_scratch_pad_int_(); + bool check_scratch_pad_(); + float get_temp_c_(); +}; + +} // namespace dallas_temp +} // namespace esphome diff --git a/esphome/components/dallas_temp/sensor.py b/esphome/components/dallas_temp/sensor.py new file mode 100644 index 0000000000..ab14a9afd5 --- /dev/null +++ b/esphome/components/dallas_temp/sensor.py @@ -0,0 +1,43 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import one_wire, sensor +from esphome.const import ( + CONF_RESOLUTION, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) + +dallas_temp_ns = cg.esphome_ns.namespace("dallas_temp") + +DallasTemperatureSensor = dallas_temp_ns.class_( + "DallasTemperatureSensor", + cg.PollingComponent, + sensor.Sensor, + one_wire.OneWireDevice, +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + DallasTemperatureSensor, + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend( + { + cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12), + } + ) + .extend(one_wire.one_wire_device_schema()) + .extend(cv.polling_component_schema("60s")) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await one_wire.register_one_wire_device(var, config) + + cg.add(var.set_resolution(config[CONF_RESOLUTION])) diff --git a/esphome/components/gpio/one_wire/__init__.py b/esphome/components/gpio/one_wire/__init__.py new file mode 100644 index 0000000000..2166e92083 --- /dev/null +++ b/esphome/components/gpio/one_wire/__init__.py @@ -0,0 +1,25 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.const import CONF_ID, CONF_PIN +from esphome.components.one_wire import OneWireBus +from .. import gpio_ns + +CODEOWNERS = ["@ssieb"] + +GPIOOneWireBus = gpio_ns.class_("GPIOOneWireBus", OneWireBus, cg.Component) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(GPIOOneWireBus), + cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + pin = await cg.gpio_pin_expression(config[CONF_PIN]) + cg.add(var.set_pin(pin)) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp new file mode 100644 index 0000000000..f47e8d58e3 --- /dev/null +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -0,0 +1,199 @@ +#include "gpio_one_wire.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace gpio { + +static const char *const TAG = "gpio.one_wire"; + +void GPIOOneWireBus::setup() { + ESP_LOGCONFIG(TAG, "Setting up 1-wire bus..."); + this->search(); +} + +void GPIOOneWireBus::dump_config() { + ESP_LOGCONFIG(TAG, "GPIO 1-wire bus:"); + LOG_PIN(" Pin: ", this->t_pin_); + this->dump_devices_(TAG); +} + +bool HOT IRAM_ATTR GPIOOneWireBus::reset() { + // See reset here: + // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html + // Wait for communication to clear (delay G) + pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + uint8_t retries = 125; + do { + if (--retries == 0) + return false; + delayMicroseconds(2); + } while (!pin_.digital_read()); + + bool r; + + // Send 480µs LOW TX reset pulse (drive bus low, delay H) + pin_.pin_mode(gpio::FLAG_OUTPUT); + pin_.digital_write(false); + delayMicroseconds(480); + + // Release the bus, delay I + pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + delayMicroseconds(70); + + // sample bus, 0=device(s) present, 1=no device present + r = !pin_.digital_read(); + // delay J + delayMicroseconds(410); + return r; +} + +void HOT IRAM_ATTR GPIOOneWireBus::write_bit_(bool bit) { + // drive bus low + pin_.pin_mode(gpio::FLAG_OUTPUT); + pin_.digital_write(false); + + // from datasheet: + // write 0 low time: t_low0: min=60µs, max=120µs + // write 1 low time: t_low1: min=1µs, max=15µs + // time slot: t_slot: min=60µs, max=120µs + // recovery time: t_rec: min=1µs + // ds18b20 appears to read the bus after roughly 14µs + uint32_t delay0 = bit ? 6 : 60; + uint32_t delay1 = bit ? 54 : 5; + + // delay A/C + delayMicroseconds(delay0); + // release bus + pin_.digital_write(true); + // delay B/D + delayMicroseconds(delay1); +} + +bool HOT IRAM_ATTR GPIOOneWireBus::read_bit_() { + // drive bus low + pin_.pin_mode(gpio::FLAG_OUTPUT); + pin_.digital_write(false); + + // note: for reading we'll need very accurate timing, as the + // timing for the digital_read() is tight; according to the datasheet, + // we should read at the end of 16µs starting from the bus low + // typically, the ds18b20 pulls the line high after 11µs for a logical 1 + // and 29µs for a logical 0 + + uint32_t start = micros(); + // datasheet says >1µs + delayMicroseconds(2); + + // release bus, delay E + pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + + // measure from start value directly, to get best accurate timing no matter + // how long pin_mode/delayMicroseconds took + delayMicroseconds(12 - (micros() - start)); + + // sample bus to read bit from peer + bool r = pin_.digital_read(); + + // read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked + uint32_t now = micros(); + if (now - start < 60) + delayMicroseconds(60 - (now - start)); + + return r; +} + +void IRAM_ATTR GPIOOneWireBus::write8(uint8_t val) { + for (uint8_t i = 0; i < 8; i++) { + this->write_bit_(bool((1u << i) & val)); + } +} + +void IRAM_ATTR GPIOOneWireBus::write64(uint64_t val) { + for (uint8_t i = 0; i < 64; i++) { + this->write_bit_(bool((1ULL << i) & val)); + } +} + +uint8_t IRAM_ATTR GPIOOneWireBus::read8() { + uint8_t ret = 0; + for (uint8_t i = 0; i < 8; i++) { + ret |= (uint8_t(this->read_bit_()) << i); + } + return ret; +} + +uint64_t IRAM_ATTR GPIOOneWireBus::read64() { + uint64_t ret = 0; + for (uint8_t i = 0; i < 8; i++) { + ret |= (uint64_t(this->read_bit_()) << i); + } + return ret; +} + +void GPIOOneWireBus::reset_search() { + this->last_discrepancy_ = 0; + this->last_device_flag_ = false; + this->address_ = 0; +} + +uint64_t IRAM_ATTR GPIOOneWireBus::search_int() { + if (this->last_device_flag_) + return 0u; + + uint8_t last_zero = 0; + uint64_t bit_mask = 1; + uint64_t address = this->address_; + + // Initiate search + for (int bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) { + // read bit + bool id_bit = this->read_bit_(); + // read its complement + bool cmp_id_bit = this->read_bit_(); + + if (id_bit && cmp_id_bit) { + // No devices participating in search + return 0; + } + + bool branch; + + if (id_bit != cmp_id_bit) { + // only chose one branch, the other one doesn't have any devices. + branch = id_bit; + } else { + // there are devices with both 0s and 1s at this bit + if (bit_number < this->last_discrepancy_) { + branch = (address & bit_mask) > 0; + } else { + branch = bit_number == this->last_discrepancy_; + } + + if (!branch) { + last_zero = bit_number; + } + } + + if (branch) { + address |= bit_mask; + } else { + address &= ~bit_mask; + } + + // choose/announce branch + this->write_bit_(branch); + } + + this->last_discrepancy_ = last_zero; + if (this->last_discrepancy_ == 0) { + // we're at root and have no choices left, so this was the last one. + this->last_device_flag_ = true; + } + + this->address_ = address; + return address; +} + +} // namespace gpio +} // namespace esphome diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.h b/esphome/components/gpio/one_wire/gpio_one_wire.h new file mode 100644 index 0000000000..fe949baec3 --- /dev/null +++ b/esphome/components/gpio/one_wire/gpio_one_wire.h @@ -0,0 +1,41 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/one_wire/one_wire.h" + +namespace esphome { +namespace gpio { + +class GPIOOneWireBus : public one_wire::OneWireBus, public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::BUS; } + + void set_pin(InternalGPIOPin *pin) { + this->t_pin_ = pin; + this->pin_ = pin->to_isr(); + } + + bool reset() override; + void write8(uint8_t val) override; + void write64(uint64_t val) override; + uint8_t read8() override; + uint64_t read64() override; + + protected: + InternalGPIOPin *t_pin_; + ISRInternalGPIOPin pin_; + uint8_t last_discrepancy_{0}; + bool last_device_flag_{false}; + uint64_t address_; + + void reset_search() override; + uint64_t search_int() override; + void write_bit_(bool bit); + bool read_bit_(); +}; + +} // namespace gpio +} // namespace esphome diff --git a/esphome/components/one_wire/__init__.py b/esphome/components/one_wire/__init__.py new file mode 100644 index 0000000000..99a1ccd1eb --- /dev/null +++ b/esphome/components/one_wire/__init__.py @@ -0,0 +1,40 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ADDRESS + +CODEOWNERS = ["@ssieb"] + +IS_PLATFORM_COMPONENT = True + +CONF_ONE_WIRE_ID = "one_wire_id" + +one_wire_ns = cg.esphome_ns.namespace("one_wire") +OneWireBus = one_wire_ns.class_("OneWireBus") +OneWireDevice = one_wire_ns.class_("OneWireDevice") + + +def one_wire_device_schema(): + """Create a schema for a 1-wire device. + + :return: The 1-wire device schema, `extend` this in your config schema. + """ + schema = cv.Schema( + { + cv.GenerateID(CONF_ONE_WIRE_ID): cv.use_id(OneWireBus), + cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, + } + ) + return schema + + +async def register_one_wire_device(var, config): + """Register an 1-wire device with the given config. + + Sets the 1-wire bus to use and the 1-wire address. + + This is a coroutine, you need to await it with a 'yield' expression! + """ + parent = await cg.get_variable(config[CONF_ONE_WIRE_ID]) + cg.add(var.set_one_wire_bus(parent)) + if (address := config.get(CONF_ADDRESS)) is not None: + cg.add(var.set_address(address)) diff --git a/esphome/components/one_wire/one_wire.cpp b/esphome/components/one_wire/one_wire.cpp new file mode 100644 index 0000000000..131bc4fbfe --- /dev/null +++ b/esphome/components/one_wire/one_wire.cpp @@ -0,0 +1,40 @@ +#include "one_wire.h" + +namespace esphome { +namespace one_wire { + +static const char *const TAG = "one_wire"; + +const std::string &OneWireDevice::get_address_name() { + if (this->address_name_.empty()) + this->address_name_ = std::string("0x") + format_hex(this->address_); + return this->address_name_; +} + +std::string OneWireDevice::unique_id() { return "dallas-" + str_lower_case(format_hex(this->address_)); } + +bool OneWireDevice::send_command_(uint8_t cmd) { + if (!this->bus_->select(this->address_)) + return false; + this->bus_->write8(cmd); + return true; +} + +bool OneWireDevice::check_address_() { + if (this->address_ != 0) + return true; + auto devices = this->bus_->get_devices(); + if (devices.empty()) { + ESP_LOGE(TAG, "No devices, can't auto-select address"); + return false; + } + if (devices.size() > 1) { + ESP_LOGE(TAG, "More than one device, can't auto-select address"); + return false; + } + this->address_ = devices[0]; + return true; +} + +} // namespace one_wire +} // namespace esphome diff --git a/esphome/components/one_wire/one_wire.h b/esphome/components/one_wire/one_wire.h new file mode 100644 index 0000000000..bf10e4f82e --- /dev/null +++ b/esphome/components/one_wire/one_wire.h @@ -0,0 +1,44 @@ +#pragma once + +#include "one_wire_bus.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace one_wire { + +#define LOG_ONE_WIRE_DEVICE(this) \ + ESP_LOGCONFIG(TAG, " Address: %s (%s)", this->get_address_name().c_str(), \ + LOG_STR_ARG(this->bus_->get_model_str(this->address_ & 0xff))); + +class OneWireDevice { + public: + /// @brief store the address of the device + /// @param address of the device + void set_address(uint64_t address) { this->address_ = address; } + + /// @brief store the pointer to the OneWireBus to use + /// @param bus pointer to the OneWireBus object + void set_one_wire_bus(OneWireBus *bus) { this->bus_ = bus; } + + /// Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29". + const std::string &get_address_name(); + + std::string unique_id(); + + protected: + uint64_t address_{0}; + OneWireBus *bus_{nullptr}; ///< pointer to OneWireBus instance + std::string address_name_; + + /// @brief find an address if necessary + /// should be called from setup + bool check_address_(); + + /// @brief send command on the bus + /// @param cmd command to send + bool send_command_(uint8_t cmd); +}; + +} // namespace one_wire +} // namespace esphome diff --git a/esphome/components/one_wire/one_wire_bus.cpp b/esphome/components/one_wire/one_wire_bus.cpp new file mode 100644 index 0000000000..a8d29428d3 --- /dev/null +++ b/esphome/components/one_wire/one_wire_bus.cpp @@ -0,0 +1,88 @@ +#include "one_wire_bus.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace one_wire { + +static const char *const TAG = "one_wire"; + +static const uint8_t DALLAS_MODEL_DS18S20 = 0x10; +static const uint8_t DALLAS_MODEL_DS1822 = 0x22; +static const uint8_t DALLAS_MODEL_DS18B20 = 0x28; +static const uint8_t DALLAS_MODEL_DS1825 = 0x3B; +static const uint8_t DALLAS_MODEL_DS28EA00 = 0x42; + +const uint8_t ONE_WIRE_ROM_SELECT = 0x55; +const uint8_t ONE_WIRE_ROM_SEARCH = 0xF0; + +const std::vector &OneWireBus::get_devices() { return this->devices_; } + +bool IRAM_ATTR OneWireBus::select(uint64_t address) { + if (!this->reset()) + return false; + this->write8(ONE_WIRE_ROM_SELECT); + this->write64(address); + return true; +} + +void OneWireBus::search() { + this->devices_.clear(); + + this->reset_search(); + uint64_t address; + while (true) { + { + InterruptLock lock; + if (!this->reset()) { + // Reset failed or no devices present + return; + } + + this->write8(ONE_WIRE_ROM_SEARCH); + address = this->search_int(); + } + if (address == 0) + break; + auto *address8 = reinterpret_cast(&address); + if (crc8(address8, 7) != address8[7]) { + ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str()); + } else { + this->devices_.push_back(address); + } + } +} + +void OneWireBus::skip() { + this->write8(0xCC); // skip ROM +} + +const LogString *OneWireBus::get_model_str(uint8_t model) { + switch (model) { + case DALLAS_MODEL_DS18S20: + return LOG_STR("DS18S20"); + case DALLAS_MODEL_DS1822: + return LOG_STR("DS1822"); + case DALLAS_MODEL_DS18B20: + return LOG_STR("DS18B20"); + case DALLAS_MODEL_DS1825: + return LOG_STR("DS1825"); + case DALLAS_MODEL_DS28EA00: + return LOG_STR("DS28EA00"); + default: + return LOG_STR("Unknown"); + } +} + +void OneWireBus::dump_devices_(const char *tag) { + if (this->devices_.empty()) { + ESP_LOGW(tag, " Found no devices!"); + } else { + ESP_LOGCONFIG(tag, " Found devices:"); + for (auto &address : this->devices_) { + ESP_LOGCONFIG(tag, " 0x%s (%s)", format_hex(address).c_str(), LOG_STR_ARG(get_model_str(address & 0xff))); + } + } +} + +} // namespace one_wire +} // namespace esphome diff --git a/esphome/components/one_wire/one_wire_bus.h b/esphome/components/one_wire/one_wire_bus.h new file mode 100644 index 0000000000..6818b17499 --- /dev/null +++ b/esphome/components/one_wire/one_wire_bus.h @@ -0,0 +1,61 @@ +#pragma once + +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace one_wire { + +class OneWireBus { + public: + /** Reset the bus, should be done before all write operations. + * + * Takes approximately 1ms. + * + * @return Whether the operation was successful. + */ + virtual bool reset() = 0; + + /// Write a word to the bus. LSB first. + virtual void write8(uint8_t val) = 0; + + /// Write a 64 bit unsigned integer to the bus. LSB first. + virtual void write64(uint64_t val) = 0; + + /// Write a command to the bus that addresses all devices by skipping the ROM. + void skip(); + + /// Read an 8 bit word from the bus. + virtual uint8_t read8() = 0; + + /// Read an 64-bit unsigned integer from the bus. + virtual uint64_t read64() = 0; + + /// Select a specific address on the bus for the following command. + bool select(uint64_t address); + + /// Return the list of found devices. + const std::vector &get_devices(); + + /// Search for 1-Wire devices on the bus. + void search(); + + /// Get the description string for this model. + const LogString *get_model_str(uint8_t model); + + protected: + std::vector devices_; + + /// log the found devices + void dump_devices_(const char *tag); + + /// Reset the device search. + virtual void reset_search() = 0; + + /// Search for a 1-Wire device on the bus. Returns 0 if all devices have been found. + virtual uint64_t search_int() = 0; +}; + +} // namespace one_wire +} // namespace esphome diff --git a/script/ci-custom.py b/script/ci-custom.py index e2ee81f742..9a97d3e4a8 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -630,7 +630,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/lock/lock.h", "esphome/components/mqtt/mqtt_component.h", "esphome/components/number/number.h", - "esphome/components/text/text.h", + "esphome/components/one_wire/one_wire.h", "esphome/components/output/binary_output.h", "esphome/components/output/float_output.h", "esphome/components/nextion/nextion_base.h", @@ -638,6 +638,7 @@ def lint_trailing_whitespace(fname, match): "esphome/components/sensor/sensor.h", "esphome/components/stepper/stepper.h", "esphome/components/switch/switch.h", + "esphome/components/text/text.h", "esphome/components/text_sensor/text_sensor.h", "esphome/components/valve/valve.h", "esphome/core/component.h", diff --git a/tests/components/dallas/common.yaml b/tests/components/dallas_temp/common.yaml similarity index 55% rename from tests/components/dallas/common.yaml rename to tests/components/dallas_temp/common.yaml index 7975977107..2f846ca278 100644 --- a/tests/components/dallas/common.yaml +++ b/tests/components/dallas_temp/common.yaml @@ -1,11 +1,11 @@ -dallas: - pin: 4 +one_wire: + - platform: gpio + pin: 4 sensor: - - platform: dallas + - platform: dallas_temp address: 0x1C0000031EDD2A28 name: Dallas Temperature resolution: 9 - - platform: dallas - index: 1 + - platform: dallas_temp name: Dallas Temperature diff --git a/tests/components/dallas/test.esp32-c3-idf.yaml b/tests/components/dallas_temp/test.esp32-c3-idf.yaml similarity index 100% rename from tests/components/dallas/test.esp32-c3-idf.yaml rename to tests/components/dallas_temp/test.esp32-c3-idf.yaml diff --git a/tests/components/dallas/test.esp32-c3.yaml b/tests/components/dallas_temp/test.esp32-c3.yaml similarity index 100% rename from tests/components/dallas/test.esp32-c3.yaml rename to tests/components/dallas_temp/test.esp32-c3.yaml diff --git a/tests/components/dallas/test.esp32-idf.yaml b/tests/components/dallas_temp/test.esp32-idf.yaml similarity index 100% rename from tests/components/dallas/test.esp32-idf.yaml rename to tests/components/dallas_temp/test.esp32-idf.yaml diff --git a/tests/components/dallas/test.esp32.yaml b/tests/components/dallas_temp/test.esp32.yaml similarity index 100% rename from tests/components/dallas/test.esp32.yaml rename to tests/components/dallas_temp/test.esp32.yaml diff --git a/tests/components/dallas/test.esp8266.yaml b/tests/components/dallas_temp/test.esp8266.yaml similarity index 100% rename from tests/components/dallas/test.esp8266.yaml rename to tests/components/dallas_temp/test.esp8266.yaml diff --git a/tests/components/dallas/test.rp2040.yaml b/tests/components/dallas_temp/test.rp2040.yaml similarity index 100% rename from tests/components/dallas/test.rp2040.yaml rename to tests/components/dallas_temp/test.rp2040.yaml diff --git a/tests/test1.yaml b/tests/test1.yaml index 2dacfda536..79cb1bba2b 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -315,11 +315,6 @@ as5600: slow_filter: 8x fast_filter: lsb6 -dallas: - pin: - allow_other_uses: true - number: GPIO23 - as3935_spi: cs_pin: ignore_strapping_warning: true @@ -714,13 +709,6 @@ sensor: update_interval: 15s iir_filter: 16x i2c_id: i2c_bus - - platform: dallas - address: 0x1C0000031EDD2A28 - name: Living Room Temperature - resolution: 9 - - platform: dallas - index: 1 - name: Living Room Temperature 2 - platform: dht pin: allow_other_uses: true From e2784d077dea978ba449759be6449f8d9fdde47e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:09:20 +1000 Subject: [PATCH 1871/2607] [he60r] Don't publish state unless it has changed. [BUGFIX] (#6869) --- esphome/components/he60r/he60r.cpp | 46 ++++++++++++++---------------- esphome/components/he60r/he60r.h | 7 ++--- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/esphome/components/he60r/he60r.cpp b/esphome/components/he60r/he60r.cpp index 05f3f528a5..83e895543d 100644 --- a/esphome/components/he60r/he60r.cpp +++ b/esphome/components/he60r/he60r.cpp @@ -56,7 +56,7 @@ void HE60rCover::endstop_reached_(CoverOperation operation) { this->position = new_position; this->current_operation = COVER_OPERATION_IDLE; if (this->last_command_ == operation) { - float dur = (now - this->start_dir_time_) / 1e3f; + float dur = (float) (now - this->start_dir_time_) / 1e3f; ESP_LOGD(TAG, "'%s' - %s endstop reached. Took %.1fs.", this->name_.c_str(), operation == COVER_OPERATION_OPENING ? "Open" : "Close", dur); } @@ -69,7 +69,6 @@ void HE60rCover::set_current_operation_(cover::CoverOperation operation) { this->current_operation = operation; if (operation != COVER_OPERATION_IDLE) this->last_recompute_time_ = millis(); - this->publish_state(); } } @@ -129,7 +128,7 @@ void HE60rCover::update_() { if (this->toggles_needed_ != 0) { if ((this->counter_++ & 0x3) == 0) { this->toggles_needed_--; - ESP_LOGD(TAG, "Writing byte 0x30, still needed=%" PRIu32, this->toggles_needed_); + ESP_LOGD(TAG, "Writing byte 0x30, still needed=%u", this->toggles_needed_); this->write_byte(TOGGLE_BYTE); } else { this->write_byte(QUERY_BYTE); @@ -235,31 +234,28 @@ void HE60rCover::recompute_position_() { return; const uint32_t now = millis(); - float dir; - float action_dur; - - switch (this->current_operation) { - case COVER_OPERATION_OPENING: - dir = 1.0f; - action_dur = this->open_duration_; - break; - case COVER_OPERATION_CLOSING: - dir = -1.0f; - action_dur = this->close_duration_; - break; - default: - return; - } - if (now > this->last_recompute_time_) { - auto diff = now - last_recompute_time_; - auto delta = dir * diff / action_dur; + auto diff = (unsigned) (now - last_recompute_time_); + float delta; + switch (this->current_operation) { + case COVER_OPERATION_OPENING: + delta = (float) diff / (float) this->open_duration_; + break; + case COVER_OPERATION_CLOSING: + delta = -(float) diff / (float) this->close_duration_; + break; + default: + return; + } + // make sure our guesstimate never reaches full open or close. - this->position = clamp(delta + this->position, COVER_CLOSED + 0.01f, COVER_OPEN - 0.01f); - ESP_LOGD(TAG, "Recompute %dms, dir=%f, action_dur=%f, delta=%f, pos=%f", (int) diff, dir, action_dur, delta, - this->position); + auto new_position = clamp(delta + this->position, COVER_CLOSED + 0.01f, COVER_OPEN - 0.01f); + ESP_LOGD(TAG, "Recompute %ums, dir=%u, delta=%f, pos=%f", diff, this->current_operation, delta, new_position); this->last_recompute_time_ = now; - this->publish_state(); + if (this->position != new_position) { + this->position = new_position; + this->publish_state(); + } } } diff --git a/esphome/components/he60r/he60r.h b/esphome/components/he60r/he60r.h index 624b61fc65..e41e2203c1 100644 --- a/esphome/components/he60r/he60r.h +++ b/esphome/components/he60r/he60r.h @@ -25,15 +25,14 @@ class HE60rCover : public cover::Cover, public Component, public uart::UARTDevic void control(const cover::CoverCall &call) override; bool is_at_target_() const; void start_direction_(cover::CoverOperation dir); - void update_operation_(cover::CoverOperation dir); void endstop_reached_(cover::CoverOperation operation); void recompute_position_(); void set_current_operation_(cover::CoverOperation operation); void process_rx_(uint8_t data); - uint32_t open_duration_{0}; - uint32_t close_duration_{0}; - uint32_t toggles_needed_{0}; + unsigned open_duration_{0}; + unsigned close_duration_{0}; + unsigned toggles_needed_{0}; cover::CoverOperation next_direction_{cover::COVER_OPERATION_IDLE}; cover::CoverOperation last_command_{cover::COVER_OPERATION_IDLE}; uint32_t last_recompute_time_{0}; From 699d00e21850c813e3f995c7d4fec0411cd58ef7 Mon Sep 17 00:00:00 2001 From: guillempages Date: Wed, 12 Jun 2024 03:11:00 +0200 Subject: [PATCH 1872/2607] [image] Make PIL import local (#6864) --- esphome/components/image/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index b23ed3445a..c275136427 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -9,8 +9,6 @@ import re import requests from magic import Magic -from PIL import Image - from esphome import core from esphome.components import font from esphome import external_files @@ -267,6 +265,9 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) def load_svg_image(file: bytes, resize: tuple[int, int]): + # Local import only to allow "validate_pillow_installed" to run *before* importing it + from PIL import Image + # This import is only needed in case of SVG images; adding it # to the top would force configurations not using SVG to also have it # installed for no reason. @@ -286,6 +287,9 @@ def load_svg_image(file: bytes, resize: tuple[int, int]): async def to_code(config): + # Local import only to allow "validate_pillow_installed" to run *before* importing it + from PIL import Image + conf_file = config[CONF_FILE] if conf_file[CONF_SOURCE] == SOURCE_LOCAL: From 7b9fb57bb22a86a15ae4f637b886ef3e415c75f4 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:15:57 +1000 Subject: [PATCH 1873/2607] [config] Retain path information in validated configuration (#6785) --- esphome/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index 2b231fc402..afb7207edb 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -23,7 +23,7 @@ from esphome.const import ( CONF_EXTERNAL_COMPONENTS, TARGET_PLATFORMS, ) -from esphome.core import CORE, EsphomeError +from esphome.core import CORE, EsphomeError, DocumentRange from esphome.helpers import indent from esphome.util import safe_print, OrderedDict @@ -184,7 +184,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): def get_deepest_document_range_for_path( self, path: ConfigPath, get_key: bool = False - ) -> ESPHomeDataBase | None: + ) -> DocumentRange | None: data = self doc_range = None for index, path_item in enumerate(path): @@ -1123,4 +1123,4 @@ def read_config(command_line_substitutions): safe_print("") return None - return OrderedDict(res) + return res From 4bf7c9708852758237b8da13c77c5bd568b7cdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Wed, 12 Jun 2024 03:19:18 +0200 Subject: [PATCH 1874/2607] WebSocket overrides check_origin for reverse proxy configuration (#6845) --- esphome/dashboard/web_server.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 9ee2312781..33c83ffb1a 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -17,6 +17,7 @@ import time from collections.abc import Iterable from pathlib import Path from typing import TYPE_CHECKING, Any, Callable, TypeVar +from urllib.parse import urlparse import tornado import tornado.concurrent @@ -166,6 +167,18 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): # use Popen() with a reading thread instead self._use_popen = os.name == "nt" + def check_origin(self, origin): + if "ESPHOME_TRUSTED_DOMAINS" not in os.environ: + return super().check_origin(origin) + trusted_domains = [ + s.strip() for s in os.environ["ESPHOME_TRUSTED_DOMAINS"].split(",") + ] + url = urlparse(origin) + if url.hostname in trusted_domains: + return True + _LOGGER.info("check_origin %s, domain is not trusted", origin) + return False + def open(self, *args: str, **kwargs: str) -> None: """Handle new WebSocket connection.""" # Ensure messages from the subprocess are sent immediately From 7c843437a70f825d71e2198bf17fd8e5d1d48db5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:26:43 +1000 Subject: [PATCH 1875/2607] [config] Early termination of validation steps on error (#6837) --- esphome/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config.py b/esphome/config.py index afb7207edb..925a31fed0 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -139,7 +139,7 @@ class Config(OrderedDict, fv.FinalValidateConfig): ) def run_validation_steps(self): - while self._validation_tasks: + while self._validation_tasks and not self.errors: task = heapq.heappop(self._validation_tasks) task.step.run(self) From e2c1af199c4b6504350fb0a133ea450a470165b1 Mon Sep 17 00:00:00 2001 From: Tudor Sandu Date: Tue, 11 Jun 2024 18:39:01 -0700 Subject: [PATCH 1876/2607] Fix media_player.volume_set when media player is not started (#6859) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../media_player/i2s_audio_media_player.cpp | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 5140a923b4..34ed5b02a0 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -37,38 +37,14 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->set_volume_(volume); this->unmute_(); } - if (this->i2s_state_ != I2S_STATE_RUNNING) { - return; - } if (call.get_command().has_value()) { switch (call.get_command().value()) { - case media_player::MEDIA_PLAYER_COMMAND_PLAY: - if (!this->audio_->isRunning()) - this->audio_->pauseResume(); - this->state = play_state; - break; - case media_player::MEDIA_PLAYER_COMMAND_PAUSE: - if (this->audio_->isRunning()) - this->audio_->pauseResume(); - this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; - break; - case media_player::MEDIA_PLAYER_COMMAND_STOP: - this->stop(); - break; case media_player::MEDIA_PLAYER_COMMAND_MUTE: this->mute_(); break; case media_player::MEDIA_PLAYER_COMMAND_UNMUTE: this->unmute_(); break; - case media_player::MEDIA_PLAYER_COMMAND_TOGGLE: - this->audio_->pauseResume(); - if (this->audio_->isRunning()) { - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; - } else { - this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; - } - break; case media_player::MEDIA_PLAYER_COMMAND_VOLUME_UP: { float new_volume = this->volume + 0.1f; if (new_volume > 1.0f) @@ -85,6 +61,36 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->unmute_(); break; } + default: + break; + } + if (this->i2s_state_ != I2S_STATE_RUNNING) { + return; + } + switch (call.get_command().value()) { + case media_player::MEDIA_PLAYER_COMMAND_PLAY: + if (!this->audio_->isRunning()) + this->audio_->pauseResume(); + this->state = play_state; + break; + case media_player::MEDIA_PLAYER_COMMAND_PAUSE: + if (this->audio_->isRunning()) + this->audio_->pauseResume(); + this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; + break; + case media_player::MEDIA_PLAYER_COMMAND_STOP: + this->stop(); + break; + case media_player::MEDIA_PLAYER_COMMAND_TOGGLE: + this->audio_->pauseResume(); + if (this->audio_->isRunning()) { + this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + } else { + this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; + } + break; + default: + break; } } this->publish_state(); From bc408ad08cc8ba8e8ce90f2cabb7b647377e75e9 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:42:01 +1000 Subject: [PATCH 1877/2607] [display] SDL2 display driver for host platform (#6825) --- .github/workflows/ci.yml | 2 +- CODEOWNERS | 1 + esphome/components/sdl/__init__.py | 1 + esphome/components/sdl/display.py | 72 ++++++++++++++ esphome/components/sdl/sdl_esphome.cpp | 96 +++++++++++++++++++ esphome/components/sdl/sdl_esphome.h | 54 +++++++++++ .../components/sdl/touchscreen/__init__.py | 22 +++++ .../sdl/touchscreen/sdl_touchscreen.h | 26 +++++ tests/components/sdl/common.yaml | 12 +++ tests/components/sdl/test.host.yaml | 1 + 10 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 esphome/components/sdl/__init__.py create mode 100644 esphome/components/sdl/display.py create mode 100644 esphome/components/sdl/sdl_esphome.cpp create mode 100644 esphome/components/sdl/sdl_esphome.h create mode 100644 esphome/components/sdl/touchscreen/__init__.py create mode 100644 esphome/components/sdl/touchscreen/sdl_touchscreen.h create mode 100644 tests/components/sdl/common.yaml create mode 100644 tests/components/sdl/test.host.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b3c80cb35..5a1887c33c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -455,7 +455,7 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install libsodium - run: sudo apt-get install libsodium-dev + run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.6 diff --git a/CODEOWNERS b/CODEOWNERS index 75ea4fe523..5c14d30371 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -320,6 +320,7 @@ esphome/components/rtttl/* @glmnet esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti esphome/components/scd4x/* @martgras @sjtrny esphome/components/script/* @esphome/core +esphome/components/sdl/* @clydebarrow esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdp3x/* @Azimath esphome/components/seeed_mr24hpc1/* @limengdu diff --git a/esphome/components/sdl/__init__.py b/esphome/components/sdl/__init__.py new file mode 100644 index 0000000000..c58ce8a01e --- /dev/null +++ b/esphome/components/sdl/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@clydebarrow"] diff --git a/esphome/components/sdl/display.py b/esphome/components/sdl/display.py new file mode 100644 index 0000000000..18dc570f88 --- /dev/null +++ b/esphome/components/sdl/display.py @@ -0,0 +1,72 @@ +import subprocess + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import display +from esphome.const import ( + CONF_ID, + CONF_DIMENSIONS, + CONF_WIDTH, + CONF_HEIGHT, + CONF_LAMBDA, + PLATFORM_HOST, +) + +sdl_ns = cg.esphome_ns.namespace("sdl") +Sdl = sdl_ns.class_("Sdl", display.Display, cg.Component) + + +CONF_SDL_OPTIONS = "sdl_options" +CONF_SDL_ID = "sdl_id" + + +def get_sdl_options(value): + if value != "": + return value + try: + return subprocess.check_output(["sdl2-config", "--cflags", "--libs"]).decode() + except Exception as e: + raise cv.Invalid("Unable to run sdl2-config - have you installed sdl2?") from e + + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(Sdl), + cv.Optional(CONF_SDL_OPTIONS, default=""): get_sdl_options, + cv.Required(CONF_DIMENSIONS): cv.Any( + cv.dimensions, + cv.Schema( + { + cv.Required(CONF_WIDTH): cv.int_, + cv.Required(CONF_HEIGHT): cv.int_, + } + ), + ), + } + ) + ), + cv.only_on(PLATFORM_HOST), +) + + +async def to_code(config): + for option in config[CONF_SDL_OPTIONS].split(): + cg.add_build_flag(option) + cg.add_build_flag("-DSDL_BYTEORDER=4321") + var = cg.new_Pvariable(config[CONF_ID]) + await display.register_display(var, config) + + dimensions = config[CONF_DIMENSIONS] + if isinstance(dimensions, dict): + cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) + else: + (width, height) = dimensions + cg.add(var.set_dimensions(width, height)) + + if lamb := config.get(CONF_LAMBDA): + lambda_ = await cg.process_lambda( + lamb, [(display.DisplayRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/sdl/sdl_esphome.cpp b/esphome/components/sdl/sdl_esphome.cpp new file mode 100644 index 0000000000..5e17ca5650 --- /dev/null +++ b/esphome/components/sdl/sdl_esphome.cpp @@ -0,0 +1,96 @@ +#ifdef USE_HOST +#include "sdl_esphome.h" +#include "esphome/components/display/display_color_utils.h" + +namespace esphome { +namespace sdl { + +void Sdl::setup() { + ESP_LOGD(TAG, "Starting setup"); + SDL_Init(SDL_INIT_VIDEO); + this->window_ = SDL_CreateWindow(App.get_name().c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + this->width_, this->height_, 0); + this->renderer_ = SDL_CreateRenderer(this->window_, -1, SDL_RENDERER_SOFTWARE); + this->texture_ = + SDL_CreateTexture(this->renderer_, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STATIC, this->width_, this->height_); + SDL_SetTextureBlendMode(this->texture_, SDL_BLENDMODE_BLEND); + ESP_LOGD(TAG, "Setup Complete"); +} +void Sdl::update() { + this->do_update_(); + if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) + return; + SDL_Rect rect{this->x_low_, this->y_low_, this->x_high_ + 1 - this->x_low_, this->y_high_ + 1 - this->y_low_}; + this->x_low_ = this->width_; + this->y_low_ = this->height_; + this->x_high_ = 0; + this->y_high_ = 0; + SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect); + SDL_RenderPresent(this->renderer_); +} + +void Sdl::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { + SDL_Rect rect{x_start, y_start, w, h}; + if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || big_endian) { + display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, + x_pad); + } else { + auto stride = x_offset + w + x_pad; + auto data = ptr + (stride * y_offset + x_offset) * 2; + SDL_UpdateTexture(this->texture_, &rect, data, stride * 2); + } + SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect); + SDL_RenderPresent(this->renderer_); +} + +void Sdl::draw_pixel_at(int x, int y, Color color) { + SDL_Rect rect{x, y, 1, 1}; + auto data = (display::ColorUtil::color_to_565(color, display::COLOR_ORDER_RGB)); + SDL_UpdateTexture(this->texture_, &rect, &data, 2); + if (x < this->x_low_) + this->x_low_ = x; + if (y < this->y_low_) + this->y_low_ = y; + if (x > this->x_high_) + this->x_high_ = x; + if (y > this->y_high_) + this->y_high_ = y; +} + +void Sdl::loop() { + SDL_Event e; + if (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + exit(0); + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + if (e.button.button == 1) { + this->mouse_x = e.button.x; + this->mouse_y = e.button.y; + this->mouse_down = e.button.state != 0; + } + break; + + case SDL_MOUSEMOTION: + if (e.motion.state & 1) { + this->mouse_x = e.button.x; + this->mouse_y = e.button.y; + this->mouse_down = true; + } else { + this->mouse_down = false; + } + break; + + default: + ESP_LOGV(TAG, "Event %d", e.type); + break; + } + } +} + +} // namespace sdl +} // namespace esphome +#endif diff --git a/esphome/components/sdl/sdl_esphome.h b/esphome/components/sdl/sdl_esphome.h new file mode 100644 index 0000000000..e4b2d9dd9f --- /dev/null +++ b/esphome/components/sdl/sdl_esphome.h @@ -0,0 +1,54 @@ +#pragma once + +#ifdef USE_HOST +#include "esphome/core/component.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/components/display/display.h" +#define SDL_MAIN_HANDLED +#include "SDL.h" + +namespace esphome { +namespace sdl { + +constexpr static const char *const TAG = "sdl"; + +class Sdl : public display::Display { + public: + display::DisplayType get_display_type() override { return display::DISPLAY_TYPE_COLOR; } + void update() override; + void loop() override; + void setup() override; + void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; + void draw_pixel_at(int x, int y, Color color) override; + void set_dimensions(uint16_t width, uint16_t height) { + this->width_ = width; + this->height_ = height; + } + int get_width() override { return this->width_; } + int get_height() override { return this->height_; } + float get_setup_priority() const override { return setup_priority::HARDWARE; } + void dump_config() override { LOG_DISPLAY("", "SDL", this); } + + int mouse_x{}; + int mouse_y{}; + bool mouse_down{}; + + protected: + int get_width_internal() override { return this->width_; } + int get_height_internal() override { return this->height_; } + int width_{}; + int height_{}; + SDL_Renderer *renderer_{}; + SDL_Window *window_{}; + SDL_Texture *texture_{}; + uint16_t x_low_{0}; + uint16_t y_low_{0}; + uint16_t x_high_{0}; + uint16_t y_high_{0}; +}; +} // namespace sdl +} // namespace esphome + +#endif diff --git a/esphome/components/sdl/touchscreen/__init__.py b/esphome/components/sdl/touchscreen/__init__.py new file mode 100644 index 0000000000..d6c0ed1c03 --- /dev/null +++ b/esphome/components/sdl/touchscreen/__init__.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID + +from esphome.components import touchscreen +from ..display import Sdl, sdl_ns, CONF_SDL_ID + +SdlTouchscreen = sdl_ns.class_("SdlTouchscreen", touchscreen.Touchscreen) + + +CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(SdlTouchscreen), + cv.GenerateID(CONF_SDL_ID): cv.use_id(Sdl), + } +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_parented(var, config[CONF_SDL_ID]) + await touchscreen.register_touchscreen(var, config) diff --git a/esphome/components/sdl/touchscreen/sdl_touchscreen.h b/esphome/components/sdl/touchscreen/sdl_touchscreen.h new file mode 100644 index 0000000000..a1f0fb15e3 --- /dev/null +++ b/esphome/components/sdl/touchscreen/sdl_touchscreen.h @@ -0,0 +1,26 @@ +#pragma once + +#ifdef USE_HOST +#include "../sdl_esphome.h" +#include "esphome/components/touchscreen/touchscreen.h" + +namespace esphome { +namespace sdl { + +class SdlTouchscreen : public touchscreen::Touchscreen, public Parented { + public: + void setup() override { + this->x_raw_max_ = this->display_->get_width(); + this->y_raw_max_ = this->display_->get_height(); + } + + void update_touches() override { + if (this->parent_->mouse_down) { + add_raw_touch_position_(0, this->parent_->mouse_x, this->parent_->mouse_y); + } + } +}; + +} // namespace sdl +} // namespace esphome +#endif diff --git a/tests/components/sdl/common.yaml b/tests/components/sdl/common.yaml new file mode 100644 index 0000000000..0192f054b5 --- /dev/null +++ b/tests/components/sdl/common.yaml @@ -0,0 +1,12 @@ +host: + mac_address: "62:23:45:AF:B3:DD" + +display: + - platform: sdl + id: sdl_display + update_interval: 1s + auto_clear_enabled: false + show_test_card: true + dimensions: + width: 450 + height: 600 diff --git a/tests/components/sdl/test.host.yaml b/tests/components/sdl/test.host.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sdl/test.host.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From f25c2963037a7d165e11eac1a874c9da2674e7c6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:47:52 +1000 Subject: [PATCH 1878/2607] [ili9xxx] Implement st7735 support (#6838) --- esphome/components/ili9xxx/display.py | 2 + esphome/components/ili9xxx/ili9xxx_defines.h | 2 + .../components/ili9xxx/ili9xxx_display.cpp | 18 +++++-- esphome/components/ili9xxx/ili9xxx_display.h | 10 +++- esphome/components/ili9xxx/ili9xxx_init.h | 51 +++++++++++++++++++ 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index f0ac5ba9ef..483f2b886c 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -69,6 +69,7 @@ MODELS = { "ILI9486": ili9xxx_ns.class_("ILI9XXXILI9486", ILI9XXXDisplay), "ILI9488": ili9xxx_ns.class_("ILI9XXXILI9488", ILI9XXXDisplay), "ILI9488_A": ili9xxx_ns.class_("ILI9XXXILI9488A", ILI9XXXDisplay), + "ST7735": ili9xxx_ns.class_("ILI9XXXST7735", ILI9XXXDisplay), "ST7796": ili9xxx_ns.class_("ILI9XXXST7796", ILI9XXXDisplay), "ST7789V": ili9xxx_ns.class_("ILI9XXXST7789V", ILI9XXXDisplay), "S3BOX": ili9xxx_ns.class_("ILI9XXXS3Box", ILI9XXXDisplay), @@ -134,6 +135,7 @@ def _validate(config): "ILI9341", "ILI9342", "ST7789V", + "ST7735", ]: raise cv.Invalid("Selected model can't run on ESP8266.") diff --git a/esphome/components/ili9xxx/ili9xxx_defines.h b/esphome/components/ili9xxx/ili9xxx_defines.h index 29483ee15e..744013db3d 100644 --- a/esphome/components/ili9xxx/ili9xxx_defines.h +++ b/esphome/components/ili9xxx/ili9xxx_defines.h @@ -70,6 +70,7 @@ static const uint8_t ILI9XXX_PWCTR2 = 0xC1; static const uint8_t ILI9XXX_PWCTR3 = 0xC2; static const uint8_t ILI9XXX_PWCTR4 = 0xC3; static const uint8_t ILI9XXX_PWCTR5 = 0xC4; +static const uint8_t ILI9XXX_PWCTR6 = 0xF6; static const uint8_t ILI9XXX_VMCTR1 = 0xC5; static const uint8_t ILI9XXX_IFCTR = 0xC6; static const uint8_t ILI9XXX_VMCTR2 = 0xC7; @@ -91,6 +92,7 @@ static const uint8_t ILI9XXX_GMCTRN1 = 0xE1; static const uint8_t ILI9XXX_CSCON = 0xF0; static const uint8_t ILI9XXX_ADJCTL3 = 0xF7; +static const uint8_t ILI9XXX_DELAY = 0xFF; // followed by one byte of delay time in ms } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 463e3dd851..21d46ea825 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -411,11 +411,19 @@ void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { uint8_t cmd, x, num_args; while ((cmd = *addr++) != 0) { x = *addr++; - num_args = x & 0x7F; - this->send_command(cmd, addr, num_args); - addr += num_args; - if (x & 0x80) - delay(150); // NOLINT + if (cmd == ILI9XXX_DELAY) { + ESP_LOGD(TAG, "Delay %dms", x); + delay(x); + } else { + num_args = x & 0x7F; + ESP_LOGD(TAG, "Command %02X, length %d, bits %02X", cmd, num_args, *addr); + this->send_command(cmd, addr, num_args); + addr += num_args; + if (x & 0x80) { + ESP_LOGD(TAG, "Delay 150ms"); + delay(150); // NOLINT + } + } } } diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 4446686e7b..7a320dac7b 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -35,7 +35,6 @@ class ILI9XXXDisplay : public display::DisplayBuffer, while ((cmd = *addr++) != 0) { num_args = *addr++ & 0x7F; bits = *addr; - esph_log_d(TAG, "Command %02X, length %d, bits %02X", cmd, num_args, bits); switch (cmd) { case ILI9XXX_MADCTL: { this->swap_xy_ = (bits & MADCTL_MV) != 0; @@ -51,6 +50,9 @@ class ILI9XXXDisplay : public display::DisplayBuffer, break; } + case ILI9XXX_DELAY: + continue; // no args to skip + default: break; } @@ -269,5 +271,11 @@ class ILI9XXXGC9A01A : public ILI9XXXDisplay { ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {} }; +//----------- ILI9XXX_24_TFT display -------------- +class ILI9XXXST7735 : public ILI9XXXDisplay { + public: + ILI9XXXST7735() : ILI9XXXDisplay(INITCMD_ST7735, 128, 160, false) {} +}; + } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index ea90f83f30..260bde4c80 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -370,6 +370,57 @@ static const uint8_t PROGMEM INITCMD_GC9A01A[] = { 0x00 // End of list }; +static const uint8_t PROGMEM INITCMD_ST7735[] = { + ILI9XXX_SWRESET, 0, // Soft reset, then delay 10ms + ILI9XXX_DELAY, 10, + ILI9XXX_SLPOUT , 0, // Exit Sleep, delay + ILI9XXX_DELAY, 10, + ILI9XXX_PIXFMT , 1, 0x05, + ILI9XXX_FRMCTR1, 3, // 4: Frame rate control, 3 args + delay: + 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) + ILI9XXX_FRMCTR2, 3, // 4: Framerate ctrl - idle mode, 3 args: + 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) + ILI9XXX_FRMCTR3, 6, // 5: Framerate - partial mode, 6 args: + 0x01, 0x2C, 0x2D, // Dot inversion mode + 0x01, 0x2C, 0x2D, // Line inversion mode + + ILI9XXX_INVCTR, 1, // 7: Display inversion control, 1 arg: + 0x7, // Line inversion + ILI9XXX_PWCTR1, 3, // 7: Power control, 3 args, no delay: + 0xA2, + 0x02, // -4.6V + 0x84, // AUTO mode + ILI9XXX_PWCTR2, 1, // 8: Power control, 1 arg, no delay: + 0xC5, // VGH25=2.4C VGSEL=-10 VGH=3 * AVDD + ILI9XXX_PWCTR3, 2, // 9: Power control, 2 args, no delay: + 0x0A, // Opamp current small + 0x00, // Boost frequency + ILI9XXX_PWCTR4, 2, // 10: Power control, 2 args, no delay: + 0x8A, // BCLK/2, + 0x2A, // opamp current small & medium low + ILI9XXX_PWCTR5, 2, // 11: Power control, 2 args, no delay: + 0x8A, 0xEE, + + ILI9XXX_VMCTR1, 1, // 11: Power control, 2 args + delay: + 0x0E, + ILI9XXX_GMCTRP1, 16, // 13: Gamma Adjustments (pos. polarity), 16 args + delay: + 0x02, 0x1c, 0x07, 0x12, // (Not entirely necessary, but provides + 0x37, 0x32, 0x29, 0x2d, // accurate colors) + 0x29, 0x25, 0x2B, 0x39, + 0x00, 0x01, 0x03, 0x10, + ILI9XXX_GMCTRN1, 16, // 14: Gamma Adjustments (neg. polarity), 16 args + delay: + 0x03, 0x1d, 0x07, 0x06, // (Not entirely necessary, but provides + 0x2E, 0x2C, 0x29, 0x2D, // accurate colors) + 0x2E, 0x2E, 0x37, 0x3F, + 0x00, 0x00, 0x02, 0x10, + ILI9XXX_MADCTL , 1, 0x00, // Memory Access Control, BGR + ILI9XXX_NORON , 0, + ILI9XXX_DELAY, 10, + ILI9XXX_DISPON , 0, // Display on + ILI9XXX_DELAY, 10, + 00, // endo of list +}; + // clang-format on } // namespace ili9xxx } // namespace esphome From f9f98fa6c6d2d120efd39721133a7b44c5fd4ee3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:16:43 +1200 Subject: [PATCH 1879/2607] Bump version to 2024.6.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cbd932e3cc..0117e8a238 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0-dev" +__version__ = "2024.6.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From bd7e8fbf86b086d2b1211173d2b20efc0efafb7e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:16:43 +1200 Subject: [PATCH 1880/2607] Bump version to 2024.7.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cbd932e3cc..dff14d7cf0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0-dev" +__version__ = "2024.7.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b401b5eca83b69fc5027deb154cbb2571cfde9c7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:36:57 +1200 Subject: [PATCH 1881/2607] [CI] Update device class sync script for update entities (#6895) --- script/sync-device_class.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/sync-device_class.py b/script/sync-device_class.py index 12e1bb6a9f..121c89b8f9 100755 --- a/script/sync-device_class.py +++ b/script/sync-device_class.py @@ -10,6 +10,7 @@ from homeassistant.components.event import EventDeviceClass from homeassistant.components.number import NumberDeviceClass from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.switch import SwitchDeviceClass +from homeassistant.components.update import UpdateDeviceClass from homeassistant.components.valve import ValveDeviceClass # pylint: enable=import-error @@ -27,6 +28,7 @@ DOMAINS = { "number": NumberDeviceClass, "sensor": SensorDeviceClass, "switch": SwitchDeviceClass, + "update": UpdateDeviceClass, "valve": ValveDeviceClass, } From 2044c7e4d4506b840dd2978d2fce5e455d304627 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:58:56 +1200 Subject: [PATCH 1882/2607] [CI] Fix for sdl (#6892) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a1887c33c..b49237db26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -454,7 +454,7 @@ jobs: matrix: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - - name: Install libsodium + - name: Install dependencies run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub @@ -508,8 +508,8 @@ jobs: - name: List components run: echo ${{ matrix.components }} - - name: Install libsodium - run: sudo apt-get install libsodium-dev + - name: Install dependencies + run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.6 From df52bc3493c9834e2fc327e433c0368c58733c51 Mon Sep 17 00:00:00 2001 From: Oliver Hihn <43825356+oliverhihn@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:09:26 +0200 Subject: [PATCH 1883/2607] Add step_delay option to X9C component (#6890) --- esphome/components/x9c/output.py | 3 +++ esphome/components/x9c/x9c.cpp | 5 +++-- esphome/components/x9c/x9c.h | 2 ++ esphome/const.py | 1 + tests/components/x9c/test.esp32-c3-idf.yaml | 1 + tests/components/x9c/test.esp32-c3.yaml | 1 + tests/components/x9c/test.esp32-idf.yaml | 1 + tests/components/x9c/test.esp32.yaml | 1 + tests/components/x9c/test.esp8266.yaml | 1 + tests/components/x9c/test.rp2040.yaml | 1 + 10 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/x9c/output.py b/esphome/components/x9c/output.py index 44e9d729b3..56820efdfa 100644 --- a/esphome/components/x9c/output.py +++ b/esphome/components/x9c/output.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_INC_PIN, CONF_UD_PIN, CONF_INITIAL_VALUE, + CONF_STEP_DELAY, ) CODEOWNERS = ["@EtienneMD"] @@ -26,6 +27,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_VALUE, default=1.0): cv.float_range( min=0.01, max=1.0 ), + cv.Optional(CONF_STEP_DELAY, default=1): cv.int_range(min=1, max=100), } ) ) @@ -44,3 +46,4 @@ async def to_code(config): cg.add(var.set_ud_pin(ud_pin)) cg.add(var.set_initial_value(config[CONF_INITIAL_VALUE])) + cg.add(var.set_step_delay(config[CONF_STEP_DELAY])) diff --git a/esphome/components/x9c/x9c.cpp b/esphome/components/x9c/x9c.cpp index 32a1375f02..4e7a94266e 100644 --- a/esphome/components/x9c/x9c.cpp +++ b/esphome/components/x9c/x9c.cpp @@ -22,9 +22,9 @@ void X9cOutput::trim_value(int change_amount) { for (int i = 0; i < abs(change_amount); i++) { // Move wiper this->inc_pin_->digital_write(true); - delayMicroseconds(1); + delayMicroseconds(this->step_delay_); this->inc_pin_->digital_write(false); - delayMicroseconds(1); + delayMicroseconds(this->step_delay_); } delayMicroseconds(100); // Let value settle @@ -69,6 +69,7 @@ void X9cOutput::dump_config() { LOG_PIN(" Increment Pin: ", this->inc_pin_); LOG_PIN(" Up/Down Pin: ", this->ud_pin_); ESP_LOGCONFIG(TAG, " Initial Value: %f", this->initial_value_); + ESP_LOGCONFIG(TAG, " Step Delay: %d", this->step_delay_); LOG_FLOAT_OUTPUT(this); } diff --git a/esphome/components/x9c/x9c.h b/esphome/components/x9c/x9c.h index 924460c841..e7cc29a6cc 100644 --- a/esphome/components/x9c/x9c.h +++ b/esphome/components/x9c/x9c.h @@ -13,6 +13,7 @@ class X9cOutput : public output::FloatOutput, public Component { void set_inc_pin(InternalGPIOPin *pin) { inc_pin_ = pin; } void set_ud_pin(InternalGPIOPin *pin) { ud_pin_ = pin; } void set_initial_value(float initial_value) { initial_value_ = initial_value; } + void set_step_delay(int step_delay) { step_delay_ = step_delay; } void setup() override; void dump_config() override; @@ -26,6 +27,7 @@ class X9cOutput : public output::FloatOutput, public Component { InternalGPIOPin *ud_pin_; float initial_value_; float pot_value_; + int step_delay_; }; } // namespace x9c diff --git a/esphome/const.py b/esphome/const.py index dff14d7cf0..9c4e451029 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -784,6 +784,7 @@ CONF_STATIC_IP = "static_ip" CONF_STATUS = "status" CONF_STB_PIN = "stb_pin" CONF_STEP = "step" +CONF_STEP_DELAY = "step_delay" CONF_STEP_MODE = "step_mode" CONF_STEP_PIN = "step_pin" CONF_STOP = "stop" diff --git a/tests/components/x9c/test.esp32-c3-idf.yaml b/tests/components/x9c/test.esp32-c3-idf.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.esp32-c3-idf.yaml +++ b/tests/components/x9c/test.esp32-c3-idf.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32-c3.yaml b/tests/components/x9c/test.esp32-c3.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.esp32-c3.yaml +++ b/tests/components/x9c/test.esp32-c3.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32-idf.yaml b/tests/components/x9c/test.esp32-idf.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp32-idf.yaml +++ b/tests/components/x9c/test.esp32-idf.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32.yaml b/tests/components/x9c/test.esp32.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp32.yaml +++ b/tests/components/x9c/test.esp32.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp8266.yaml b/tests/components/x9c/test.esp8266.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp8266.yaml +++ b/tests/components/x9c/test.esp8266.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.rp2040.yaml b/tests/components/x9c/test.rp2040.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.rp2040.yaml +++ b/tests/components/x9c/test.rp2040.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 From 1a242f94db4923b099496497ba6e98b5f72e745d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:20:46 +1200 Subject: [PATCH 1884/2607] [host] Execute host program when using run command (#6897) --- esphome/__main__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/esphome/__main__.py b/esphome/__main__.py index f3c4ff3e23..5ff1a28ec7 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -488,6 +488,15 @@ def command_run(args, config): if exit_code != 0: return exit_code _LOGGER.info("Successfully compiled program.") + if CORE.is_host: + from esphome.platformio_api import get_idedata + + idedata = get_idedata(config) + if idedata is None: + return 1 + program_path = idedata.raw["prog_path"] + return run_external_process(program_path) + port = choose_upload_log_host( default=args.device, check_default=None, From 68dbf35b096be83e46e3fc7e82ae3100d2866ac2 Mon Sep 17 00:00:00 2001 From: Oliver Hihn <43825356+oliverhihn@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:14:03 +0200 Subject: [PATCH 1885/2607] X9C step delay with units (#6898) --- esphome/components/x9c/output.py | 8 +++++++- tests/components/x9c/test.esp32-c3-idf.yaml | 2 +- tests/components/x9c/test.esp32-c3.yaml | 2 +- tests/components/x9c/test.esp32-idf.yaml | 2 +- tests/components/x9c/test.esp32.yaml | 2 +- tests/components/x9c/test.esp8266.yaml | 2 +- tests/components/x9c/test.rp2040.yaml | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/esphome/components/x9c/output.py b/esphome/components/x9c/output.py index 56820efdfa..4497994982 100644 --- a/esphome/components/x9c/output.py +++ b/esphome/components/x9c/output.py @@ -27,7 +27,13 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_VALUE, default=1.0): cv.float_range( min=0.01, max=1.0 ), - cv.Optional(CONF_STEP_DELAY, default=1): cv.int_range(min=1, max=100), + cv.Optional(CONF_STEP_DELAY, default="1us"): cv.All( + cv.positive_time_period_microseconds, + cv.Range( + min=cv.TimePeriod(microseconds=1), + max=cv.TimePeriod(microseconds=100), + ), + ), } ) ) diff --git a/tests/components/x9c/test.esp32-c3-idf.yaml b/tests/components/x9c/test.esp32-c3-idf.yaml index 1234581329..972c743fcd 100644 --- a/tests/components/x9c/test.esp32-c3-idf.yaml +++ b/tests/components/x9c/test.esp32-c3-idf.yaml @@ -5,4 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 - step_delay: 50 + step_delay: 50us diff --git a/tests/components/x9c/test.esp32-c3.yaml b/tests/components/x9c/test.esp32-c3.yaml index 1234581329..972c743fcd 100644 --- a/tests/components/x9c/test.esp32-c3.yaml +++ b/tests/components/x9c/test.esp32-c3.yaml @@ -5,4 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 - step_delay: 50 + step_delay: 50us diff --git a/tests/components/x9c/test.esp32-idf.yaml b/tests/components/x9c/test.esp32-idf.yaml index 5f1468e94b..f587b69b4f 100644 --- a/tests/components/x9c/test.esp32-idf.yaml +++ b/tests/components/x9c/test.esp32-idf.yaml @@ -5,4 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 - step_delay: 50 + step_delay: 50us diff --git a/tests/components/x9c/test.esp32.yaml b/tests/components/x9c/test.esp32.yaml index 5f1468e94b..f587b69b4f 100644 --- a/tests/components/x9c/test.esp32.yaml +++ b/tests/components/x9c/test.esp32.yaml @@ -5,4 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 - step_delay: 50 + step_delay: 50us diff --git a/tests/components/x9c/test.esp8266.yaml b/tests/components/x9c/test.esp8266.yaml index 5f1468e94b..f587b69b4f 100644 --- a/tests/components/x9c/test.esp8266.yaml +++ b/tests/components/x9c/test.esp8266.yaml @@ -5,4 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 - step_delay: 50 + step_delay: 50us diff --git a/tests/components/x9c/test.rp2040.yaml b/tests/components/x9c/test.rp2040.yaml index 1234581329..972c743fcd 100644 --- a/tests/components/x9c/test.rp2040.yaml +++ b/tests/components/x9c/test.rp2040.yaml @@ -5,4 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 - step_delay: 50 + step_delay: 50us From 8453d9a70da397baac09a1b3a158b6d88f27e2ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 09:27:15 +1200 Subject: [PATCH 1886/2607] Bump actions/checkout from 4.1.6 to 4.1.7 (#6900) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 32 +++++++++++------------ .github/workflows/release.yml | 8 +++--- .github/workflows/sync-device-classes.yml | 4 +-- .github/workflows/yaml-lint.yml | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 1628464061..ee08a0246d 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index dd5c051cfb..421a885f74 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -40,7 +40,7 @@ jobs: arch: [amd64, armv7, aarch64] build_type: ["ha-addon", "docker", "lint"] steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Set up Python uses: actions/setup-python@v5.1.0 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b49237db26..3c10e5dac7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Generate cache-key id: cache-key run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT @@ -66,7 +66,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -87,7 +87,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -108,7 +108,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -129,7 +129,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -150,7 +150,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -199,7 +199,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -229,7 +229,7 @@ jobs: - common steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -254,7 +254,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Find all YAML test files id: set-matrix run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT @@ -271,7 +271,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -303,7 +303,7 @@ jobs: file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -358,7 +358,7 @@ jobs: steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -410,7 +410,7 @@ jobs: count: ${{ steps.list-components.outputs.count }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 with: # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. fetch-depth: 500 @@ -458,7 +458,7 @@ jobs: run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: @@ -484,7 +484,7 @@ jobs: matrix: ${{ steps.split.outputs.components }} steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Split components into 20 groups id: split run: | @@ -512,7 +512,7 @@ jobs: run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Restore Python uses: ./.github/actions/restore-python with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 563d485b6a..9c07335104 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: tag: ${{ steps.tag.outputs.tag }} branch_build: ${{ steps.tag.outputs.branch_build }} steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Get tag id: tag # yamllint disable rule:line-length @@ -51,7 +51,7 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -83,7 +83,7 @@ jobs: - linux/arm/v7 - linux/arm64 steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Set up Python uses: actions/setup-python@v5.1.0 with: @@ -174,7 +174,7 @@ jobs: - ghcr - dockerhub steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Download digests uses: actions/download-artifact@v4.1.7 diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index e65e851f3c..45f6b27127 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -13,10 +13,10 @@ jobs: if: github.repository == 'esphome/esphome' steps: - name: Checkout - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Checkout Home Assistant - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 with: repository: home-assistant/core path: lib/home-assistant diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index f009643629..1c0b5f58ad 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from GitHub - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Run yamllint uses: frenck/action-yamllint@v1.5.0 with: From c4c46c206fd5d8edfab0a2769821db0beaae5908 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:12:36 +1200 Subject: [PATCH 1887/2607] Bump esphome-dashboard to 20240613.0 (#6901) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05e46ca31e..a7b08f8a14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240429.1 +esphome-dashboard==20240613.0 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 From fdefc825bb473fedc4fb2b8001ba6ce3f4fe2c7f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:58:56 +1200 Subject: [PATCH 1888/2607] [CI] Fix for sdl (#6892) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a1887c33c..b49237db26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -454,7 +454,7 @@ jobs: matrix: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - - name: Install libsodium + - name: Install dependencies run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub @@ -508,8 +508,8 @@ jobs: - name: List components run: echo ${{ matrix.components }} - - name: Install libsodium - run: sudo apt-get install libsodium-dev + - name: Install dependencies + run: sudo apt-get install libsodium-dev libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.6 From be486e0ca65bad647289c3a4cfd4d09a09b02e64 Mon Sep 17 00:00:00 2001 From: Oliver Hihn <43825356+oliverhihn@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:09:26 +0200 Subject: [PATCH 1889/2607] Add step_delay option to X9C component (#6890) --- esphome/components/x9c/output.py | 3 +++ esphome/components/x9c/x9c.cpp | 5 +++-- esphome/components/x9c/x9c.h | 2 ++ esphome/const.py | 1 + tests/components/x9c/test.esp32-c3-idf.yaml | 1 + tests/components/x9c/test.esp32-c3.yaml | 1 + tests/components/x9c/test.esp32-idf.yaml | 1 + tests/components/x9c/test.esp32.yaml | 1 + tests/components/x9c/test.esp8266.yaml | 1 + tests/components/x9c/test.rp2040.yaml | 1 + 10 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/x9c/output.py b/esphome/components/x9c/output.py index 44e9d729b3..56820efdfa 100644 --- a/esphome/components/x9c/output.py +++ b/esphome/components/x9c/output.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_INC_PIN, CONF_UD_PIN, CONF_INITIAL_VALUE, + CONF_STEP_DELAY, ) CODEOWNERS = ["@EtienneMD"] @@ -26,6 +27,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_VALUE, default=1.0): cv.float_range( min=0.01, max=1.0 ), + cv.Optional(CONF_STEP_DELAY, default=1): cv.int_range(min=1, max=100), } ) ) @@ -44,3 +46,4 @@ async def to_code(config): cg.add(var.set_ud_pin(ud_pin)) cg.add(var.set_initial_value(config[CONF_INITIAL_VALUE])) + cg.add(var.set_step_delay(config[CONF_STEP_DELAY])) diff --git a/esphome/components/x9c/x9c.cpp b/esphome/components/x9c/x9c.cpp index 32a1375f02..4e7a94266e 100644 --- a/esphome/components/x9c/x9c.cpp +++ b/esphome/components/x9c/x9c.cpp @@ -22,9 +22,9 @@ void X9cOutput::trim_value(int change_amount) { for (int i = 0; i < abs(change_amount); i++) { // Move wiper this->inc_pin_->digital_write(true); - delayMicroseconds(1); + delayMicroseconds(this->step_delay_); this->inc_pin_->digital_write(false); - delayMicroseconds(1); + delayMicroseconds(this->step_delay_); } delayMicroseconds(100); // Let value settle @@ -69,6 +69,7 @@ void X9cOutput::dump_config() { LOG_PIN(" Increment Pin: ", this->inc_pin_); LOG_PIN(" Up/Down Pin: ", this->ud_pin_); ESP_LOGCONFIG(TAG, " Initial Value: %f", this->initial_value_); + ESP_LOGCONFIG(TAG, " Step Delay: %d", this->step_delay_); LOG_FLOAT_OUTPUT(this); } diff --git a/esphome/components/x9c/x9c.h b/esphome/components/x9c/x9c.h index 924460c841..e7cc29a6cc 100644 --- a/esphome/components/x9c/x9c.h +++ b/esphome/components/x9c/x9c.h @@ -13,6 +13,7 @@ class X9cOutput : public output::FloatOutput, public Component { void set_inc_pin(InternalGPIOPin *pin) { inc_pin_ = pin; } void set_ud_pin(InternalGPIOPin *pin) { ud_pin_ = pin; } void set_initial_value(float initial_value) { initial_value_ = initial_value; } + void set_step_delay(int step_delay) { step_delay_ = step_delay; } void setup() override; void dump_config() override; @@ -26,6 +27,7 @@ class X9cOutput : public output::FloatOutput, public Component { InternalGPIOPin *ud_pin_; float initial_value_; float pot_value_; + int step_delay_; }; } // namespace x9c diff --git a/esphome/const.py b/esphome/const.py index 0117e8a238..4d0223fa22 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -784,6 +784,7 @@ CONF_STATIC_IP = "static_ip" CONF_STATUS = "status" CONF_STB_PIN = "stb_pin" CONF_STEP = "step" +CONF_STEP_DELAY = "step_delay" CONF_STEP_MODE = "step_mode" CONF_STEP_PIN = "step_pin" CONF_STOP = "stop" diff --git a/tests/components/x9c/test.esp32-c3-idf.yaml b/tests/components/x9c/test.esp32-c3-idf.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.esp32-c3-idf.yaml +++ b/tests/components/x9c/test.esp32-c3-idf.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32-c3.yaml b/tests/components/x9c/test.esp32-c3.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.esp32-c3.yaml +++ b/tests/components/x9c/test.esp32-c3.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32-idf.yaml b/tests/components/x9c/test.esp32-idf.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp32-idf.yaml +++ b/tests/components/x9c/test.esp32-idf.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp32.yaml b/tests/components/x9c/test.esp32.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp32.yaml +++ b/tests/components/x9c/test.esp32.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.esp8266.yaml b/tests/components/x9c/test.esp8266.yaml index 28b18f7a92..5f1468e94b 100644 --- a/tests/components/x9c/test.esp8266.yaml +++ b/tests/components/x9c/test.esp8266.yaml @@ -5,3 +5,4 @@ output: inc_pin: 14 ud_pin: 15 initial_value: 0.5 + step_delay: 50 diff --git a/tests/components/x9c/test.rp2040.yaml b/tests/components/x9c/test.rp2040.yaml index a0480aa68f..1234581329 100644 --- a/tests/components/x9c/test.rp2040.yaml +++ b/tests/components/x9c/test.rp2040.yaml @@ -5,3 +5,4 @@ output: inc_pin: 4 ud_pin: 5 initial_value: 0.5 + step_delay: 50 From 91e72fe121acf4d0994bfd084f05e149ce2de92b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:20:46 +1200 Subject: [PATCH 1890/2607] [host] Execute host program when using run command (#6897) --- esphome/__main__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/esphome/__main__.py b/esphome/__main__.py index f3c4ff3e23..5ff1a28ec7 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -488,6 +488,15 @@ def command_run(args, config): if exit_code != 0: return exit_code _LOGGER.info("Successfully compiled program.") + if CORE.is_host: + from esphome.platformio_api import get_idedata + + idedata = get_idedata(config) + if idedata is None: + return 1 + program_path = idedata.raw["prog_path"] + return run_external_process(program_path) + port = choose_upload_log_host( default=args.device, check_default=None, From 73cb3ec852a3bbdca1430578d4bc3cba114eb115 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:12:36 +1200 Subject: [PATCH 1891/2607] Bump esphome-dashboard to 20240613.0 (#6901) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05e46ca31e..a7b08f8a14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240429.1 +esphome-dashboard==20240613.0 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 From 3db71b98ae4278fa5f54112e7eb885794c258d6b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:31:08 +1200 Subject: [PATCH 1892/2607] Bump version to 2024.6.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4d0223fa22..e2dc5c259a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0b1" +__version__ = "2024.6.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b29e1acab81ddc3bfef041c1cdba0048be2b8c86 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Thu, 13 Jun 2024 19:24:36 +1200 Subject: [PATCH 1893/2607] Synchronise Device Classes from Home Assistant (#6904) --- esphome/components/update/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ae3d5062ab..ea1cf778b6 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, ) from esphome.core import CORE, coroutine_with_priority @@ -24,6 +25,7 @@ PerformAction = update_ns.class_("PerformAction", automation.Action) IsAvailableCondition = update_ns.class_("IsAvailableCondition", automation.Condition) DEVICE_CLASSES = [ + DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, ] From 761aae6f892edc3d447e4478e4d20c3d124a66a1 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 13 Jun 2024 05:15:38 -0500 Subject: [PATCH 1894/2607] [CI] Allow clang-tidy to see IDF components (#6903) * Allow clang-tidy to see IDF components * Remove camera, add tflite-micro --- .github/workflows/ci.yml | 7 +++++++ esphome/idf_component.yml | 9 +++++++++ script/clang-tidy | 6 ++++-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 esphome/idf_component.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c10e5dac7..df7a9178e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -387,6 +387,13 @@ jobs: echo "::add-matcher::.github/workflows/matchers/gcc.json" echo "::add-matcher::.github/workflows/matchers/clang-tidy.json" + - name: Run 'pio run --list-targets -e esp32-idf-tidy' + if: matrix.name == 'Run script/clang-tidy for ESP32 IDF' + run: | + . venv/bin/activate + mkdir -p .temp + pio run --list-targets -e esp32-idf-tidy + - name: Run clang-tidy run: | . venv/bin/activate diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml new file mode 100644 index 0000000000..ba1a6312e2 --- /dev/null +++ b/esphome/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + esp-tflite-micro: + git: https://github.com/espressif/esp-tflite-micro.git + mdns: + git: https://github.com/espressif/esp-protocols.git + version: mdns-v1.2.5 + path: components/mdns + rules: + - if: "idf_version >=5.0" diff --git a/script/clang-tidy b/script/clang-tidy index 84b02306d5..bd919825fd 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -101,8 +101,10 @@ def clang_options(idedata): # add library include directories using -isystem to suppress their errors for directory in sorted(set(idedata["includes"]["build"])): # skip our own directories, we add those later - if not directory.startswith(f"{root_path}/") or directory.startswith( - f"{root_path}/.pio/" + if ( + not directory.startswith(f"{root_path}/") + or directory.startswith(f"{root_path}/.pio/") + or directory.startswith(f"{root_path}/managed_components/") ): cmd.extend(["-isystem", directory]) From 5adadeaa07939f593a761cd2a044db8f8d4385d3 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 13 Jun 2024 05:42:08 -0500 Subject: [PATCH 1895/2607] [esp32_camera] Use newer library version (for #6802) (#6809) --- esphome/components/esp32_camera/__init__.py | 9 ++++++--- esphome/idf_component.yml | 3 +++ platformio.ini | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index 462900d401..4187429412 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -17,7 +17,7 @@ from esphome.const import ( CONF_VSYNC_PIN, ) from esphome.core import CORE -from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.components.esp32 import add_idf_component from esphome.cpp_helpers import setup_entity DEPENDENCIES = ["esp32"] @@ -290,8 +290,11 @@ async def to_code(config): cg.add_define("USE_ESP32_CAMERA") if CORE.using_esp_idf: - cg.add_library("espressif/esp32-camera", "1.0.0") - add_idf_sdkconfig_option("CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC", True) + add_idf_component( + name="esp32-camera", + repo="https://github.com/espressif/esp32-camera.git", + ref="v2.0.9", + ) for conf in config.get(CONF_ON_STREAM_START, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml index ba1a6312e2..c031b2192f 100644 --- a/esphome/idf_component.yml +++ b/esphome/idf_component.yml @@ -1,6 +1,9 @@ dependencies: esp-tflite-micro: git: https://github.com/espressif/esp-tflite-micro.git + esp32_camera: + git: https://github.com/espressif/esp32-camera.git + version: v2.0.9 mdns: git: https://github.com/espressif/esp-protocols.git version: mdns-v1.2.5 diff --git a/platformio.ini b/platformio.ini index 6b34b2f05d..ee82dee243 100644 --- a/platformio.ini +++ b/platformio.ini @@ -142,7 +142,6 @@ platform_packages = framework = espidf lib_deps = ${common:idf.lib_deps} - espressif/esp32-camera@1.0.0 ; esp32_camera droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:idf.build_flags} From 2fc43fa9c71e7f1a5785efffee787033366ca188 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 13 Jun 2024 19:38:35 -0500 Subject: [PATCH 1896/2607] [micro_wake_word] Pin to esp-tflite-micro v1.3.1 (#6906) --- esphome/components/micro_wake_word/__init__.py | 1 + esphome/idf_component.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index def2808e54..35ee3cfedc 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -312,6 +312,7 @@ async def to_code(config): esp32.add_idf_component( name="esp-tflite-micro", repo="https://github.com/espressif/esp-tflite-micro", + ref="v1.3.1", ) cg.add_build_flag("-DTF_LITE_STATIC_MEMORY") diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml index c031b2192f..5f4701b5a3 100644 --- a/esphome/idf_component.yml +++ b/esphome/idf_component.yml @@ -1,6 +1,7 @@ dependencies: esp-tflite-micro: git: https://github.com/espressif/esp-tflite-micro.git + version: v1.3.1 esp32_camera: git: https://github.com/espressif/esp32-camera.git version: v2.0.9 From 290816be11016699c9413d2c62fb92149f201bb4 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Sun, 16 Jun 2024 09:50:00 +0200 Subject: [PATCH 1897/2607] VEML7700 Fix GCC build warnings (#6881) --- esphome/components/veml7700/veml7700.cpp | 2 +- esphome/components/veml7700/veml7700.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/veml7700/veml7700.cpp b/esphome/components/veml7700/veml7700.cpp index 68550811a1..a8c1411c68 100644 --- a/esphome/components/veml7700/veml7700.cpp +++ b/esphome/components/veml7700/veml7700.cpp @@ -243,7 +243,7 @@ ErrorCode VEML7700Component::configure_() { } PSMRegister psm{0}; - psm.PSM = PSM::PSM_MODE_1; + psm.PSM = PSMMode::PSM_MODE_1; psm.PSM_EN = false; ESP_LOGV(TAG, "Setting PSM to 0x%04X", psm.raw); err = this->write_register((uint8_t) CommandRegisters::PWR_SAVING, psm.raw_bytes, VEML_REG_SIZE); diff --git a/esphome/components/veml7700/veml7700.h b/esphome/components/veml7700/veml7700.h index fe5e1158e3..17fee6b851 100644 --- a/esphome/components/veml7700/veml7700.h +++ b/esphome/components/veml7700/veml7700.h @@ -24,7 +24,7 @@ enum class CommandRegisters : uint8_t { ALS_INT = 0x06 // R: ALS INT trigger event }; -enum Gain : uint8_t { +enum Gain : uint16_t { X_1 = 0, X_2 = 1, X_1_8 = 2, @@ -32,7 +32,7 @@ enum Gain : uint8_t { }; const uint8_t GAINS_COUNT = 4; -enum IntegrationTime : uint8_t { +enum IntegrationTime : uint16_t { INTEGRATION_TIME_25MS = 0b1100, INTEGRATION_TIME_50MS = 0b1000, INTEGRATION_TIME_100MS = 0b0000, @@ -42,14 +42,14 @@ enum IntegrationTime : uint8_t { }; const uint8_t INTEGRATION_TIMES_COUNT = 6; -enum Persistence : uint8_t { +enum Persistence : uint16_t { PERSISTENCE_1 = 0, PERSISTENCE_2 = 1, PERSISTENCE_4 = 2, PERSISTENCE_8 = 3, }; -enum PSM : uint8_t { +enum PSMMode : uint16_t { PSM_MODE_1 = 0, PSM_MODE_2 = 1, PSM_MODE_3 = 2, @@ -92,7 +92,7 @@ union PSMRegister { uint8_t raw_bytes[2]; struct { bool PSM_EN : 1; - uint8_t PSM : 2; + PSMMode PSM : 2; uint16_t reserved : 13; } __attribute__((packed)); }; From d49f2cbec80355694f046088ac0c35ef6483f77a Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 16 Jun 2024 03:02:15 -0500 Subject: [PATCH 1898/2607] IDF 5 fixes for #6802 (#6911) --- esphome/components/ethernet/ethernet_component.cpp | 2 +- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 75bdd29be7..7370cb4b44 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -631,7 +631,7 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi ESPHL_ERROR_CHECK(err, "Writing PHY Register failed"); if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) { - ESP_LOGD(TAG, "Select PHY Register Page 0x%02" PRIX32, 0x0); + ESP_LOGD(TAG, "Select PHY Register Page 0x00"); err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0); ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed"); } diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 1fa8236cf4..8a8a9e92aa 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -799,7 +799,7 @@ void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { this->speaker_buffer_index_ += msg.data.length(); this->speaker_buffer_size_ += msg.data.length(); this->speaker_bytes_received_ += msg.data.length(); - ESP_LOGV(TAG, "Received audio: %" PRId32 " bytes from API", msg.data.length()); + ESP_LOGV(TAG, "Received audio: %u bytes from API", msg.data.length()); } else { ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); } From 253303f3a9f27012660e30b7745ddccd5a713715 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:01:07 +1200 Subject: [PATCH 1899/2607] [ili9xxx] Fix init for GC9A01A (#6913) --- .../components/ili9xxx/ili9xxx_display.cpp | 20 ++++++++++++++++--- esphome/components/ili9xxx/ili9xxx_display.h | 3 ++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 21d46ea825..de03df5d41 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -34,8 +34,8 @@ void ILI9XXXDisplay::setup() { ESP_LOGD(TAG, "Setting up ILI9xxx"); this->setup_pins_(); - this->init_lcd_(this->init_sequence_); - this->init_lcd_(this->extra_init_sequence_.data()); + this->init_lcd(this->init_sequence_); + this->init_lcd(this->extra_init_sequence_.data()); switch (this->pixel_mode_) { case PIXEL_MODE_16: if (this->is_18bitdisplay_) { @@ -405,7 +405,7 @@ void ILI9XXXDisplay::reset_() { } } -void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { +void ILI9XXXDisplay::init_lcd(const uint8_t *addr) { if (addr == nullptr) return; uint8_t cmd, x, num_args; @@ -427,6 +427,20 @@ void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { } } +void ILI9XXXGC9A01A::init_lcd(const uint8_t *addr) { + if (addr == nullptr) + return; + uint8_t cmd, x, num_args; + while ((cmd = *addr++) != 0) { + x = *addr++; + num_args = x & 0x7F; + this->send_command(cmd, addr, num_args); + addr += num_args; + if (x & 0x80) + delay(150); // NOLINT + } +} + // Tell the display controller where we want to draw pixels. void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { x1 += this->offset_x_; diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 7a320dac7b..b60047a8c3 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -109,7 +109,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, virtual void set_madctl(); void display_(); - void init_lcd_(const uint8_t *addr); + virtual void init_lcd(const uint8_t *addr); void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2); void reset_(); @@ -269,6 +269,7 @@ class ILI9XXXS3BoxLite : public ILI9XXXDisplay { class ILI9XXXGC9A01A : public ILI9XXXDisplay { public: ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {} + void init_lcd(const uint8_t *addr) override; }; //----------- ILI9XXX_24_TFT display -------------- From 6b89763ad61f4bd0ab5cb8d6417dd678972b6ed6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:20:04 +1200 Subject: [PATCH 1900/2607] [mqtt] Fix datetime copy pasta (#6914) --- esphome/components/mqtt/mqtt_datetime.cpp | 6 +++--- esphome/components/mqtt/mqtt_datetime.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/mqtt/mqtt_datetime.cpp b/esphome/components/mqtt/mqtt_datetime.cpp index 4fa44aafb8..4ae6d0d416 100644 --- a/esphome/components/mqtt/mqtt_datetime.cpp +++ b/esphome/components/mqtt/mqtt_datetime.cpp @@ -6,12 +6,12 @@ #include "mqtt_const.h" #ifdef USE_MQTT -#ifdef USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME namespace esphome { namespace mqtt { -static const char *const TAG = "mqtt.datetime.time"; +static const char *const TAG = "mqtt.datetime.datetime"; using namespace esphome::datetime; @@ -80,5 +80,5 @@ bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t } // namespace mqtt } // namespace esphome -#endif // USE_DATETIME_TIME +#endif // USE_DATETIME_DATETIME #endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_datetime.h b/esphome/components/mqtt/mqtt_datetime.h index f0d68ad2e1..ba81c06cb3 100644 --- a/esphome/components/mqtt/mqtt_datetime.h +++ b/esphome/components/mqtt/mqtt_datetime.h @@ -3,7 +3,7 @@ #include "esphome/core/defines.h" #ifdef USE_MQTT -#ifdef USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME #include "esphome/components/datetime/datetime_entity.h" #include "mqtt_component.h" @@ -17,7 +17,7 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent { * * @param time The time entity. */ - explicit MQTTDateTimeComponent(datetime::DateTimeEntity *time); + explicit MQTTDateTimeComponent(datetime::DateTimeEntity *datetime); // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -41,5 +41,5 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent { } // namespace mqtt } // namespace esphome -#endif // USE_DATETIME_DATE +#endif // USE_DATETIME_DATETIME #endif // USE_MQTT From eb50f0eafd7e920c7405ae476a6878e3c53ee6ba Mon Sep 17 00:00:00 2001 From: esphomebot Date: Thu, 13 Jun 2024 19:24:36 +1200 Subject: [PATCH 1901/2607] Synchronise Device Classes from Home Assistant (#6904) --- esphome/components/update/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ae3d5062ab..ea1cf778b6 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, ) from esphome.core import CORE, coroutine_with_priority @@ -24,6 +25,7 @@ PerformAction = update_ns.class_("PerformAction", automation.Action) IsAvailableCondition = update_ns.class_("IsAvailableCondition", automation.Condition) DEVICE_CLASSES = [ + DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, ] From 1e66241b2696c80f222dd853db76bd10acb48ac4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:01:07 +1200 Subject: [PATCH 1902/2607] [ili9xxx] Fix init for GC9A01A (#6913) --- .../components/ili9xxx/ili9xxx_display.cpp | 20 ++++++++++++++++--- esphome/components/ili9xxx/ili9xxx_display.h | 3 ++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 21d46ea825..de03df5d41 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -34,8 +34,8 @@ void ILI9XXXDisplay::setup() { ESP_LOGD(TAG, "Setting up ILI9xxx"); this->setup_pins_(); - this->init_lcd_(this->init_sequence_); - this->init_lcd_(this->extra_init_sequence_.data()); + this->init_lcd(this->init_sequence_); + this->init_lcd(this->extra_init_sequence_.data()); switch (this->pixel_mode_) { case PIXEL_MODE_16: if (this->is_18bitdisplay_) { @@ -405,7 +405,7 @@ void ILI9XXXDisplay::reset_() { } } -void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { +void ILI9XXXDisplay::init_lcd(const uint8_t *addr) { if (addr == nullptr) return; uint8_t cmd, x, num_args; @@ -427,6 +427,20 @@ void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { } } +void ILI9XXXGC9A01A::init_lcd(const uint8_t *addr) { + if (addr == nullptr) + return; + uint8_t cmd, x, num_args; + while ((cmd = *addr++) != 0) { + x = *addr++; + num_args = x & 0x7F; + this->send_command(cmd, addr, num_args); + addr += num_args; + if (x & 0x80) + delay(150); // NOLINT + } +} + // Tell the display controller where we want to draw pixels. void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { x1 += this->offset_x_; diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 7a320dac7b..b60047a8c3 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -109,7 +109,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, virtual void set_madctl(); void display_(); - void init_lcd_(const uint8_t *addr); + virtual void init_lcd(const uint8_t *addr); void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2); void reset_(); @@ -269,6 +269,7 @@ class ILI9XXXS3BoxLite : public ILI9XXXDisplay { class ILI9XXXGC9A01A : public ILI9XXXDisplay { public: ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {} + void init_lcd(const uint8_t *addr) override; }; //----------- ILI9XXX_24_TFT display -------------- From 65638bf61420b2278b5043fc98f713475be2b749 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:20:04 +1200 Subject: [PATCH 1903/2607] [mqtt] Fix datetime copy pasta (#6914) --- esphome/components/mqtt/mqtt_datetime.cpp | 6 +++--- esphome/components/mqtt/mqtt_datetime.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/mqtt/mqtt_datetime.cpp b/esphome/components/mqtt/mqtt_datetime.cpp index 4fa44aafb8..4ae6d0d416 100644 --- a/esphome/components/mqtt/mqtt_datetime.cpp +++ b/esphome/components/mqtt/mqtt_datetime.cpp @@ -6,12 +6,12 @@ #include "mqtt_const.h" #ifdef USE_MQTT -#ifdef USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME namespace esphome { namespace mqtt { -static const char *const TAG = "mqtt.datetime.time"; +static const char *const TAG = "mqtt.datetime.datetime"; using namespace esphome::datetime; @@ -80,5 +80,5 @@ bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t } // namespace mqtt } // namespace esphome -#endif // USE_DATETIME_TIME +#endif // USE_DATETIME_DATETIME #endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_datetime.h b/esphome/components/mqtt/mqtt_datetime.h index f0d68ad2e1..ba81c06cb3 100644 --- a/esphome/components/mqtt/mqtt_datetime.h +++ b/esphome/components/mqtt/mqtt_datetime.h @@ -3,7 +3,7 @@ #include "esphome/core/defines.h" #ifdef USE_MQTT -#ifdef USE_DATETIME_TIME +#ifdef USE_DATETIME_DATETIME #include "esphome/components/datetime/datetime_entity.h" #include "mqtt_component.h" @@ -17,7 +17,7 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent { * * @param time The time entity. */ - explicit MQTTDateTimeComponent(datetime::DateTimeEntity *time); + explicit MQTTDateTimeComponent(datetime::DateTimeEntity *datetime); // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -41,5 +41,5 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent { } // namespace mqtt } // namespace esphome -#endif // USE_DATETIME_DATE +#endif // USE_DATETIME_DATETIME #endif // USE_MQTT From 25a3db1637d82fbc36a45c0e1d68f0bee7748718 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 Jun 2024 15:35:53 +1200 Subject: [PATCH 1904/2607] Bump version to 2024.6.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e2dc5c259a..a0fe325282 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0b2" +__version__ = "2024.6.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 51c5d1714cb8ee434b1c64d50280e328a11f4abf Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Mon, 17 Jun 2024 07:48:56 +0200 Subject: [PATCH 1905/2607] fix(dallas): make recovery time for 1-bit equal to that of 0-bit (#6763) --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index f47e8d58e3..34c2cf3c29 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -60,7 +60,7 @@ void HOT IRAM_ATTR GPIOOneWireBus::write_bit_(bool bit) { // recovery time: t_rec: min=1µs // ds18b20 appears to read the bus after roughly 14µs uint32_t delay0 = bit ? 6 : 60; - uint32_t delay1 = bit ? 54 : 5; + uint32_t delay1 = bit ? 59 : 5; // delay A/C delayMicroseconds(delay0); From 015cd42a2ed8197e189cc851aea0207bb0fd2b6e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:06:25 -0500 Subject: [PATCH 1906/2607] [CI-ethernet] Add/fix/organize/clean up ethernet component tests (#6916) --- ...{lan8720.esp32-idf.yaml => common-dp83848.yaml} | 2 +- .../{lan8720.esp32.yaml => common-ip101.yaml} | 2 +- tests/components/ethernet/common-jl1101.yaml | 12 ++++++++++++ tests/components/ethernet/common-ksz8081.yaml | 12 ++++++++++++ tests/components/ethernet/common-ksz8081rna.yaml | 12 ++++++++++++ .../ethernet/{common.yaml => common-lan8720.yaml} | 0 tests/components/ethernet/common-rtl8201.yaml | 12 ++++++++++++ .../{w5500.esp32.yaml => common-w5500.yaml} | 12 ++++++------ .../ethernet/test-dp83848.esp32-idf.yaml | 1 + tests/components/ethernet/test-dp83848.esp32.yaml | 1 + .../components/ethernet/test-ip101.esp32-idf.yaml | 1 + tests/components/ethernet/test-ip101.esp32.yaml | 1 + .../components/ethernet/test-jl1101.esp32-idf.yaml | 1 + tests/components/ethernet/test-jl1101.esp32.yaml | 1 + .../ethernet/test-ksz8081.esp32-idf.yaml | 1 + tests/components/ethernet/test-ksz8081.esp32.yaml | 1 + .../ethernet/test-ksz8081rna.esp32-idf.yaml | 1 + .../components/ethernet/test-ksz8081rna.esp32.yaml | 1 + .../ethernet/test-lan8720.esp32-idf.yaml | 1 + tests/components/ethernet/test-lan8720.esp32.yaml | 1 + .../ethernet/test-rtl8201.esp32-idf.yaml | 1 + tests/components/ethernet/test-rtl8201.esp32.yaml | 1 + .../components/ethernet/test-w5500.esp32-idf.yaml | 1 + tests/components/ethernet/test-w5500.esp32.yaml | 1 + tests/components/ethernet/test.esp32-idf.yaml | 1 - tests/components/ethernet/test.esp32.yaml | 1 - tests/components/ethernet/w5500.esp32-idf.yaml | 14 -------------- 27 files changed, 72 insertions(+), 24 deletions(-) rename tests/components/ethernet/{lan8720.esp32-idf.yaml => common-dp83848.yaml} (92%) rename tests/components/ethernet/{lan8720.esp32.yaml => common-ip101.yaml} (92%) create mode 100644 tests/components/ethernet/common-jl1101.yaml create mode 100644 tests/components/ethernet/common-ksz8081.yaml create mode 100644 tests/components/ethernet/common-ksz8081rna.yaml rename tests/components/ethernet/{common.yaml => common-lan8720.yaml} (100%) create mode 100644 tests/components/ethernet/common-rtl8201.yaml rename tests/components/ethernet/{w5500.esp32.yaml => common-w5500.yaml} (57%) create mode 100644 tests/components/ethernet/test-dp83848.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-dp83848.esp32.yaml create mode 100644 tests/components/ethernet/test-ip101.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-ip101.esp32.yaml create mode 100644 tests/components/ethernet/test-jl1101.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-jl1101.esp32.yaml create mode 100644 tests/components/ethernet/test-ksz8081.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-ksz8081.esp32.yaml create mode 100644 tests/components/ethernet/test-ksz8081rna.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-ksz8081rna.esp32.yaml create mode 100644 tests/components/ethernet/test-lan8720.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-lan8720.esp32.yaml create mode 100644 tests/components/ethernet/test-rtl8201.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-rtl8201.esp32.yaml create mode 100644 tests/components/ethernet/test-w5500.esp32-idf.yaml create mode 100644 tests/components/ethernet/test-w5500.esp32.yaml delete mode 100644 tests/components/ethernet/test.esp32-idf.yaml delete mode 100644 tests/components/ethernet/test.esp32.yaml delete mode 100644 tests/components/ethernet/w5500.esp32-idf.yaml diff --git a/tests/components/ethernet/lan8720.esp32-idf.yaml b/tests/components/ethernet/common-dp83848.yaml similarity index 92% rename from tests/components/ethernet/lan8720.esp32-idf.yaml rename to tests/components/ethernet/common-dp83848.yaml index b9ed9cb036..5b6ed3e8d0 100644 --- a/tests/components/ethernet/lan8720.esp32-idf.yaml +++ b/tests/components/ethernet/common-dp83848.yaml @@ -1,5 +1,5 @@ ethernet: - type: LAN8720 + type: DP83848 mdc_pin: 23 mdio_pin: 25 clk_mode: GPIO0_IN diff --git a/tests/components/ethernet/lan8720.esp32.yaml b/tests/components/ethernet/common-ip101.yaml similarity index 92% rename from tests/components/ethernet/lan8720.esp32.yaml rename to tests/components/ethernet/common-ip101.yaml index b9ed9cb036..5ca369cce1 100644 --- a/tests/components/ethernet/lan8720.esp32.yaml +++ b/tests/components/ethernet/common-ip101.yaml @@ -1,5 +1,5 @@ ethernet: - type: LAN8720 + type: IP101 mdc_pin: 23 mdio_pin: 25 clk_mode: GPIO0_IN diff --git a/tests/components/ethernet/common-jl1101.yaml b/tests/components/ethernet/common-jl1101.yaml new file mode 100644 index 0000000000..639542d807 --- /dev/null +++ b/tests/components/ethernet/common-jl1101.yaml @@ -0,0 +1,12 @@ +ethernet: + type: JL1101 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/common-ksz8081.yaml b/tests/components/ethernet/common-ksz8081.yaml new file mode 100644 index 0000000000..167606a1eb --- /dev/null +++ b/tests/components/ethernet/common-ksz8081.yaml @@ -0,0 +1,12 @@ +ethernet: + type: KSZ8081 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/common-ksz8081rna.yaml b/tests/components/ethernet/common-ksz8081rna.yaml new file mode 100644 index 0000000000..f506906b1b --- /dev/null +++ b/tests/components/ethernet/common-ksz8081rna.yaml @@ -0,0 +1,12 @@ +ethernet: + type: KSZ8081RNA + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/common.yaml b/tests/components/ethernet/common-lan8720.yaml similarity index 100% rename from tests/components/ethernet/common.yaml rename to tests/components/ethernet/common-lan8720.yaml diff --git a/tests/components/ethernet/common-rtl8201.yaml b/tests/components/ethernet/common-rtl8201.yaml new file mode 100644 index 0000000000..43842e7c9f --- /dev/null +++ b/tests/components/ethernet/common-rtl8201.yaml @@ -0,0 +1,12 @@ +ethernet: + type: RTL8201 + mdc_pin: 23 + mdio_pin: 25 + clk_mode: GPIO0_IN + phy_addr: 0 + power_pin: 26 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local diff --git a/tests/components/ethernet/w5500.esp32.yaml b/tests/components/ethernet/common-w5500.yaml similarity index 57% rename from tests/components/ethernet/w5500.esp32.yaml rename to tests/components/ethernet/common-w5500.yaml index 6fdccb36e3..76661a75c3 100644 --- a/tests/components/ethernet/w5500.esp32.yaml +++ b/tests/components/ethernet/common-w5500.yaml @@ -1,11 +1,11 @@ ethernet: type: W5500 - clk_pin: GPIO19 - mosi_pin: GPIO21 - miso_pin: GPIO23 - cs_pin: GPIO18 - interrupt_pin: GPIO36 - reset_pin: GPIO22 + clk_pin: 19 + mosi_pin: 21 + miso_pin: 23 + cs_pin: 18 + interrupt_pin: 36 + reset_pin: 22 clock_speed: 10Mhz manual_ip: static_ip: 192.168.178.56 diff --git a/tests/components/ethernet/test-dp83848.esp32-idf.yaml b/tests/components/ethernet/test-dp83848.esp32-idf.yaml new file mode 100644 index 0000000000..906bfba17c --- /dev/null +++ b/tests/components/ethernet/test-dp83848.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-dp83848.yaml diff --git a/tests/components/ethernet/test-dp83848.esp32.yaml b/tests/components/ethernet/test-dp83848.esp32.yaml new file mode 100644 index 0000000000..906bfba17c --- /dev/null +++ b/tests/components/ethernet/test-dp83848.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-dp83848.yaml diff --git a/tests/components/ethernet/test-ip101.esp32-idf.yaml b/tests/components/ethernet/test-ip101.esp32-idf.yaml new file mode 100644 index 0000000000..e52329d7ea --- /dev/null +++ b/tests/components/ethernet/test-ip101.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-ip101.yaml diff --git a/tests/components/ethernet/test-ip101.esp32.yaml b/tests/components/ethernet/test-ip101.esp32.yaml new file mode 100644 index 0000000000..e52329d7ea --- /dev/null +++ b/tests/components/ethernet/test-ip101.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-ip101.yaml diff --git a/tests/components/ethernet/test-jl1101.esp32-idf.yaml b/tests/components/ethernet/test-jl1101.esp32-idf.yaml new file mode 100644 index 0000000000..95d8cd1f21 --- /dev/null +++ b/tests/components/ethernet/test-jl1101.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-jl1101.yaml diff --git a/tests/components/ethernet/test-jl1101.esp32.yaml b/tests/components/ethernet/test-jl1101.esp32.yaml new file mode 100644 index 0000000000..95d8cd1f21 --- /dev/null +++ b/tests/components/ethernet/test-jl1101.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-jl1101.yaml diff --git a/tests/components/ethernet/test-ksz8081.esp32-idf.yaml b/tests/components/ethernet/test-ksz8081.esp32-idf.yaml new file mode 100644 index 0000000000..8f3c750c77 --- /dev/null +++ b/tests/components/ethernet/test-ksz8081.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-ksz8081.yaml diff --git a/tests/components/ethernet/test-ksz8081.esp32.yaml b/tests/components/ethernet/test-ksz8081.esp32.yaml new file mode 100644 index 0000000000..8f3c750c77 --- /dev/null +++ b/tests/components/ethernet/test-ksz8081.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-ksz8081.yaml diff --git a/tests/components/ethernet/test-ksz8081rna.esp32-idf.yaml b/tests/components/ethernet/test-ksz8081rna.esp32-idf.yaml new file mode 100644 index 0000000000..a48e591996 --- /dev/null +++ b/tests/components/ethernet/test-ksz8081rna.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-ksz8081rna.yaml diff --git a/tests/components/ethernet/test-ksz8081rna.esp32.yaml b/tests/components/ethernet/test-ksz8081rna.esp32.yaml new file mode 100644 index 0000000000..a48e591996 --- /dev/null +++ b/tests/components/ethernet/test-ksz8081rna.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-ksz8081rna.yaml diff --git a/tests/components/ethernet/test-lan8720.esp32-idf.yaml b/tests/components/ethernet/test-lan8720.esp32-idf.yaml new file mode 100644 index 0000000000..3df9ac874a --- /dev/null +++ b/tests/components/ethernet/test-lan8720.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-lan8720.yaml diff --git a/tests/components/ethernet/test-lan8720.esp32.yaml b/tests/components/ethernet/test-lan8720.esp32.yaml new file mode 100644 index 0000000000..3df9ac874a --- /dev/null +++ b/tests/components/ethernet/test-lan8720.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-lan8720.yaml diff --git a/tests/components/ethernet/test-rtl8201.esp32-idf.yaml b/tests/components/ethernet/test-rtl8201.esp32-idf.yaml new file mode 100644 index 0000000000..e69f88dc94 --- /dev/null +++ b/tests/components/ethernet/test-rtl8201.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-rtl8201.yaml diff --git a/tests/components/ethernet/test-rtl8201.esp32.yaml b/tests/components/ethernet/test-rtl8201.esp32.yaml new file mode 100644 index 0000000000..e69f88dc94 --- /dev/null +++ b/tests/components/ethernet/test-rtl8201.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-rtl8201.yaml diff --git a/tests/components/ethernet/test-w5500.esp32-idf.yaml b/tests/components/ethernet/test-w5500.esp32-idf.yaml new file mode 100644 index 0000000000..36f1b5365f --- /dev/null +++ b/tests/components/ethernet/test-w5500.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-w5500.yaml diff --git a/tests/components/ethernet/test-w5500.esp32.yaml b/tests/components/ethernet/test-w5500.esp32.yaml new file mode 100644 index 0000000000..36f1b5365f --- /dev/null +++ b/tests/components/ethernet/test-w5500.esp32.yaml @@ -0,0 +1 @@ +<<: !include common-w5500.yaml diff --git a/tests/components/ethernet/test.esp32-idf.yaml b/tests/components/ethernet/test.esp32-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/ethernet/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/ethernet/test.esp32.yaml b/tests/components/ethernet/test.esp32.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/ethernet/test.esp32.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/ethernet/w5500.esp32-idf.yaml b/tests/components/ethernet/w5500.esp32-idf.yaml deleted file mode 100644 index 6fdccb36e3..0000000000 --- a/tests/components/ethernet/w5500.esp32-idf.yaml +++ /dev/null @@ -1,14 +0,0 @@ -ethernet: - type: W5500 - clk_pin: GPIO19 - mosi_pin: GPIO21 - miso_pin: GPIO23 - cs_pin: GPIO18 - interrupt_pin: GPIO36 - reset_pin: GPIO22 - clock_speed: 10Mhz - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local From 67d8c7c69164c48debffff6868c2dc9282ffc37b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:14:19 -0500 Subject: [PATCH 1907/2607] [CI-a01nyub] Consolidate test files (#6917) --- tests/components/a01nyub/common.yaml | 11 +++++++++++ tests/components/a01nyub/test.esp32-c3-idf.yaml | 16 ++++------------ tests/components/a01nyub/test.esp32-c3.yaml | 16 ++++------------ tests/components/a01nyub/test.esp32-idf.yaml | 16 ++++------------ tests/components/a01nyub/test.esp32.yaml | 16 ++++------------ tests/components/a01nyub/test.esp8266.yaml | 16 ++++------------ tests/components/a01nyub/test.rp2040.yaml | 16 ++++------------ 7 files changed, 35 insertions(+), 72 deletions(-) create mode 100644 tests/components/a01nyub/common.yaml diff --git a/tests/components/a01nyub/common.yaml b/tests/components/a01nyub/common.yaml new file mode 100644 index 0000000000..0717acfff7 --- /dev/null +++ b/tests/components/a01nyub/common.yaml @@ -0,0 +1,11 @@ +uart: + - id: uart_a01nyub + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + baud_rate: 9600 + +sensor: + - platform: a01nyub + id: a01nyub_sensor + name: a01nyub Distance + uart_id: uart_a01nyub diff --git a/tests/components/a01nyub/test.esp32-c3-idf.yaml b/tests/components/a01nyub/test.esp32-c3-idf.yaml index 3132f77136..b516342f3b 100644 --- a/tests/components/a01nyub/test.esp32-c3-idf.yaml +++ b/tests/components/a01nyub/test.esp32-c3-idf.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 4 - rx_pin: - number: 5 - baud_rate: 9600 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml diff --git a/tests/components/a01nyub/test.esp32-c3.yaml b/tests/components/a01nyub/test.esp32-c3.yaml index 3132f77136..b516342f3b 100644 --- a/tests/components/a01nyub/test.esp32-c3.yaml +++ b/tests/components/a01nyub/test.esp32-c3.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 4 - rx_pin: - number: 5 - baud_rate: 9600 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml diff --git a/tests/components/a01nyub/test.esp32-idf.yaml b/tests/components/a01nyub/test.esp32-idf.yaml index 79fc9c5fbf..f486544afa 100644 --- a/tests/components/a01nyub/test.esp32-idf.yaml +++ b/tests/components/a01nyub/test.esp32-idf.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 17 - rx_pin: - number: 16 - baud_rate: 9600 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml diff --git a/tests/components/a01nyub/test.esp32.yaml b/tests/components/a01nyub/test.esp32.yaml index 79fc9c5fbf..f486544afa 100644 --- a/tests/components/a01nyub/test.esp32.yaml +++ b/tests/components/a01nyub/test.esp32.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 17 - rx_pin: - number: 16 - baud_rate: 9600 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml diff --git a/tests/components/a01nyub/test.esp8266.yaml b/tests/components/a01nyub/test.esp8266.yaml index 3132f77136..b516342f3b 100644 --- a/tests/components/a01nyub/test.esp8266.yaml +++ b/tests/components/a01nyub/test.esp8266.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 4 - rx_pin: - number: 5 - baud_rate: 9600 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml diff --git a/tests/components/a01nyub/test.rp2040.yaml b/tests/components/a01nyub/test.rp2040.yaml index 3132f77136..b516342f3b 100644 --- a/tests/components/a01nyub/test.rp2040.yaml +++ b/tests/components/a01nyub/test.rp2040.yaml @@ -1,13 +1,5 @@ -uart: - - id: uart_a01nyub - tx_pin: - number: 4 - rx_pin: - number: 5 - baud_rate: 9600 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -sensor: - - platform: a01nyub - id: a01nyub_sensor - name: a01nyub Distance - uart_id: uart_a01nyub +<<: !include common.yaml From d604c8ae644ee91c714c1ae887b7fcbf400a759b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:18:04 -0500 Subject: [PATCH 1908/2607] [CI-api] Test fix for IDF 5+ (#6918) --- tests/components/api/common.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml index 3c56811b95..e0b900f92d 100644 --- a/tests/components/api/common.yaml +++ b/tests/components/api/common.yaml @@ -50,12 +50,12 @@ api: then: - logger.log: # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" + format: "Bool: %s (%u), Int: %ld (%u), Float: %f (%u), String: %s (%u)" # yamllint enable rule:line-length args: - YESNO(bool_arr[0]) - bool_arr.size() - - int_arr[0] + - (long) int_arr[0] - int_arr.size() - float_arr[0] - float_arr.size() From 41f810f8285c7f94d0f629e30828848d13cb734b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:21:15 -0500 Subject: [PATCH 1909/2607] [CI-http_request] Test fix for IDF 5+ (#6919) --- tests/components/http_request/common.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml index 83b334ca2d..589b7fb4b4 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common.yaml @@ -15,10 +15,10 @@ esphome: on_response: then: - logger.log: - format: "Response status: %d, Duration: %u ms" + format: "Response status: %d, Duration: %lu ms" args: - response->status_code - - response->duration_ms + - (long) response->duration_ms - http_request.post: url: https://esphome.io headers: From c30913ccdeebb4627a864132e8cd37c5264e88a5 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:23:24 -0500 Subject: [PATCH 1910/2607] [CI-wireguard] Test file consolidation (#6920) --- tests/components/wireguard/common.yaml | 59 ++++++++++++++++++ tests/components/wireguard/test.bk72xx.yaml | 60 +----------------- .../wireguard/test.esp32-c3-idf.yaml | 61 +------------------ tests/components/wireguard/test.esp32-c3.yaml | 61 +------------------ .../components/wireguard/test.esp32-idf.yaml | 60 +----------------- tests/components/wireguard/test.esp32.yaml | 60 +----------------- tests/components/wireguard/test.esp8266.yaml | 60 +----------------- 7 files changed, 65 insertions(+), 356 deletions(-) create mode 100644 tests/components/wireguard/common.yaml diff --git a/tests/components/wireguard/common.yaml b/tests/components/wireguard/common.yaml new file mode 100644 index 0000000000..cd7ab1075e --- /dev/null +++ b/tests/components/wireguard/common.yaml @@ -0,0 +1,59 @@ +wifi: + ssid: "MySSID1" + password: "password1" + +time: + - platform: sntp + +wireguard: + address: 172.16.34.100 + netmask: 255.255.255.0 + # NEVER use the following keys for your VPN -- they are now public! + private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= + peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= + peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= + peer_endpoint: wg.server.example + peer_persistent_keepalive: 25s + peer_allowed_ips: + - 172.16.34.0/24 + - 192.168.4.0/24 + +binary_sensor: + - platform: wireguard + status: + name: 'WireGuard Status' + enabled: + name: 'WireGuard Enabled' + +sensor: + - platform: wireguard + latest_handshake: + name: 'WireGuard Latest Handshake' + +text_sensor: + - platform: wireguard + address: + name: 'WireGuard Address' + +button: + - platform: template + name: 'Toggle WireGuard' + entity_category: config + on_press: + - if: + condition: wireguard.enabled + then: + - wireguard.disable: + else: + - wireguard.enable: + + - platform: template + name: 'Log WireGuard status' + entity_category: config + on_press: + - if: + condition: wireguard.peer_online + then: + - logger.log: 'wireguard remote peer is online' + else: + - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wireguard/test.bk72xx.yaml b/tests/components/wireguard/test.bk72xx.yaml index 85325139a9..dade44d145 100644 --- a/tests/components/wireguard/test.bk72xx.yaml +++ b/tests/components/wireguard/test.bk72xx.yaml @@ -1,59 +1 @@ -wifi: - ssid: "MySSID1" - password: "password1" - -time: - - platform: sntp - -wireguard: - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' +<<: !include common.yaml diff --git a/tests/components/wireguard/test.esp32-c3-idf.yaml b/tests/components/wireguard/test.esp32-c3-idf.yaml index 37d1727842..dade44d145 100644 --- a/tests/components/wireguard/test.esp32-c3-idf.yaml +++ b/tests/components/wireguard/test.esp32-c3-idf.yaml @@ -1,60 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - -wireguard: - id: vpn - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' +<<: !include common.yaml diff --git a/tests/components/wireguard/test.esp32-c3.yaml b/tests/components/wireguard/test.esp32-c3.yaml index 37d1727842..dade44d145 100644 --- a/tests/components/wireguard/test.esp32-c3.yaml +++ b/tests/components/wireguard/test.esp32-c3.yaml @@ -1,60 +1 @@ -wifi: - ssid: MySSID - password: password1 - -time: - - platform: sntp - -wireguard: - id: vpn - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' +<<: !include common.yaml diff --git a/tests/components/wireguard/test.esp32-idf.yaml b/tests/components/wireguard/test.esp32-idf.yaml index 9ea7f00bdb..2798f8e566 100644 --- a/tests/components/wireguard/test.esp32-idf.yaml +++ b/tests/components/wireguard/test.esp32-idf.yaml @@ -1,62 +1,4 @@ -wifi: - ssid: "MySSID1" - password: "password1" +<<: !include common.yaml network: enable_ipv6: true - -time: - - platform: sntp - -wireguard: - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wireguard/test.esp32.yaml b/tests/components/wireguard/test.esp32.yaml index 9ea7f00bdb..2798f8e566 100644 --- a/tests/components/wireguard/test.esp32.yaml +++ b/tests/components/wireguard/test.esp32.yaml @@ -1,62 +1,4 @@ -wifi: - ssid: "MySSID1" - password: "password1" +<<: !include common.yaml network: enable_ipv6: true - -time: - - platform: sntp - -wireguard: - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' diff --git a/tests/components/wireguard/test.esp8266.yaml b/tests/components/wireguard/test.esp8266.yaml index 9ea7f00bdb..2798f8e566 100644 --- a/tests/components/wireguard/test.esp8266.yaml +++ b/tests/components/wireguard/test.esp8266.yaml @@ -1,62 +1,4 @@ -wifi: - ssid: "MySSID1" - password: "password1" +<<: !include common.yaml network: enable_ipv6: true - -time: - - platform: sntp - -wireguard: - address: 172.16.34.100 - netmask: 255.255.255.0 - # NEVER use the following keys for your vpn, they are now public! - private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8= - peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc= - peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60= - peer_endpoint: wg.server.example - peer_persistent_keepalive: 25s - peer_allowed_ips: - - 172.16.34.0/24 - - 192.168.4.0/24 - -binary_sensor: - - platform: wireguard - status: - name: 'WireGuard Status' - enabled: - name: 'WireGuard Enabled' - -sensor: - - platform: wireguard - latest_handshake: - name: 'WireGuard Latest Handshake' - -text_sensor: - - platform: wireguard - address: - name: 'WireGuard Address' - -button: - - platform: template - name: 'Toggle WireGuard' - entity_category: config - on_press: - - if: - condition: wireguard.enabled - then: - - wireguard.disable: - else: - - wireguard.enable: - - - platform: template - name: 'Log WireGuard status' - entity_category: config - on_press: - - if: - condition: wireguard.peer_online - then: - - logger.log: 'wireguard remote peer is online' - else: - - logger.log: 'wireguard remote peer is offline' From a59c9b4f771f6d6a65af6caa33b0c0edae6af087 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 02:30:54 -0500 Subject: [PATCH 1911/2607] [CI-esp32_hall] Remove IDF test (#6921) --- tests/components/esp32_hall/common.yaml | 3 --- tests/components/esp32_hall/test.esp32-idf.yaml | 1 - tests/components/esp32_hall/test.esp32.yaml | 4 +++- 3 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 tests/components/esp32_hall/common.yaml delete mode 100644 tests/components/esp32_hall/test.esp32-idf.yaml diff --git a/tests/components/esp32_hall/common.yaml b/tests/components/esp32_hall/common.yaml deleted file mode 100644 index f8429f5aa0..0000000000 --- a/tests/components/esp32_hall/common.yaml +++ /dev/null @@ -1,3 +0,0 @@ -sensor: - - platform: esp32_hall - name: ESP32 Hall Sensor diff --git a/tests/components/esp32_hall/test.esp32-idf.yaml b/tests/components/esp32_hall/test.esp32-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/esp32_hall/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/esp32_hall/test.esp32.yaml b/tests/components/esp32_hall/test.esp32.yaml index dade44d145..f8429f5aa0 100644 --- a/tests/components/esp32_hall/test.esp32.yaml +++ b/tests/components/esp32_hall/test.esp32.yaml @@ -1 +1,3 @@ -<<: !include common.yaml +sensor: + - platform: esp32_hall + name: ESP32 Hall Sensor From f6848fe24d58ac7bcb1bc79e210a41a2f09bf571 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 17 Jun 2024 16:32:11 -0500 Subject: [PATCH 1912/2607] [CI] Introduce testing for IDF 5 (and other arbitrary framework versions) (#6802) * Initial changes to support testing of additional framework versions * Rename Arduino test files --- script/test_build_components | 25 ++++++++++--------- .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...esp32.yaml => test-dp83848.esp32-ard.yaml} | 0 ...1.esp32.yaml => test-ip101.esp32-ard.yaml} | 0 ....esp32.yaml => test-jl1101.esp32-ard.yaml} | 0 ...esp32.yaml => test-ksz8081.esp32-ard.yaml} | 0 ...32.yaml => test-ksz8081rna.esp32-ard.yaml} | 0 ...esp32.yaml => test-lan8720.esp32-ard.yaml} | 0 ...esp32.yaml => test-rtl8201.esp32-ard.yaml} | 0 ...0.esp32.yaml => test-w5500.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...p8266.yaml => test-nossl.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-s2-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...{test.bk72xx.yaml => test.bk72xx-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-s3.yaml => test.esp32-s3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...t.esp32-s2.yaml => test.esp32-s2-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...test.esp32-c3.yaml => test.esp32-ard.yaml} | 0 ...test.esp32.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 .../{test.esp32.yaml => test.esp32-ard.yaml} | 0 ...t.esp32-c3.yaml => test.esp32-c3-ard.yaml} | 0 ...est.esp8266.yaml => test.esp8266-ard.yaml} | 0 ...{test.rp2040.yaml => test.rp2040-ard.yaml} | 0 ... => build_components_base.bk72xx-ard.yaml} | 0 ...build_components_base.esp32-c3-idf-50.yaml | 19 ++++++++++++++ .../build_components_base.esp32-idf-50.yaml | 19 ++++++++++++++ ...build_components_base.esp32-s2-idf-50.yaml | 20 +++++++++++++++ .../build_components_base.esp32-s2-idf.yaml | 2 +- ...build_components_base.esp32-s3-idf-50.yaml | 20 +++++++++++++++ .../build_components_base.esp32-s3-idf.yaml | 2 +- ...=> build_components_base.esp8266-ard.yaml} | 2 +- ... => build_components_base.rp2040-ard.yaml} | 2 +- 1689 files changed, 95 insertions(+), 16 deletions(-) rename tests/components/a01nyub/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/a01nyub/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/a01nyub/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/a01nyub/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/a02yyuw/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/a02yyuw/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/a02yyuw/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/a02yyuw/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/a4988/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/a4988/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/a4988/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/a4988/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/absolute_humidity/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/absolute_humidity/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/absolute_humidity/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/absolute_humidity/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ac_dimmer/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ac_dimmer/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ac_dimmer/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ac_dimmer/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/adc/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/adc/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/adc/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/adc/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/adc/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/adc/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/adc128s102/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/adc128s102/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/adc128s102/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/adc128s102/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/addressable_light/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/addressable_light/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ade7880/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ade7880/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ade7880/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ade7880/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ade7953_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ade7953_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ade7953_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ade7953_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ade7953_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ade7953_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ade7953_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ade7953_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ads1115/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ads1115/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ads1115/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ads1115/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ags10/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ags10/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ags10/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/aht10/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/aht10/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/aht10/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/aht10/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/airthings_wave_mini/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/airthings_wave_mini/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/airthings_wave_plus/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/airthings_wave_plus/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/alarm_control_panel/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/alarm_control_panel/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/alarm_control_panel/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/alarm_control_panel/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/alpha3/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/alpha3/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/am2315c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/am2315c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/am2315c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/am2315c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/am2320/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/am2320/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/am2320/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/am2320/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/am43/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/am43/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/analog_threshold/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/analog_threshold/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/analog_threshold/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/analog_threshold/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/animation/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/animation/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/animation/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/animation/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/anova/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/anova/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/apds9960/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/apds9960/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/apds9960/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/apds9960/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/api/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/api/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/api/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/api/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/as3935_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/as3935_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/as3935_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/as3935_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/as3935_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/as3935_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/as3935_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/as3935_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/as5600/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/as5600/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/as5600/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/as5600/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/as7341/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/as7341/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/as7341/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/as7341/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/at581x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/at581x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/at581x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/at581x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/atc_mithermometer/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/atc_mithermometer/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/atm90e26/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/atm90e26/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/atm90e26/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/atm90e26/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/atm90e32/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/atm90e32/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/atm90e32/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/atm90e32/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/b_parasite/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/b_parasite/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ballu/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ballu/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bang_bang/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bang_bang/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bang_bang/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bang_bang/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bedjet/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bedjet/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/beken_spi_led_strip/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/bh1750/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bh1750/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bh1750/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bh1750/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/binary_sensor_map/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/binary_sensor_map/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/binary_sensor_map/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/binary_sensor_map/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bl0939/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bl0939/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bl0939/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bl0939/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bl0940/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bl0940/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bl0940/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bl0940/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bl0942/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bl0942/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bl0942/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bl0942/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ble_client/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ble_client/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ble_presence/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ble_presence/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ble_rssi/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ble_rssi/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ble_scanner/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ble_scanner/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bme280_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bme280_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bme280_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bme280_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bme280_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bme280_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bme280_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bme280_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bme680/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bme680/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bme680/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bme680/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bme680_bsec/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bme680_bsec/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmi160/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmi160/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmi160/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmi160/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bmp085/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmp085/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmp085/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmp085/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bmp280/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmp280/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmp280/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmp280/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bmp3xx_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmp3xx_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmp3xx_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmp3xx_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bmp3xx_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmp3xx_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmp3xx_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmp3xx_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bmp581/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bmp581/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bmp581/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bmp581/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bp1658cj/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bp1658cj/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bp1658cj/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bp1658cj/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/bp5758d/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/bp5758d/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/bp5758d/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/bp5758d/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/button/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/button/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/button/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/button/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/canbus/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/canbus/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cap1188/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cap1188/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cap1188/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cap1188/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/captive_portal/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/captive_portal/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/captive_portal/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ccs811/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ccs811/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ccs811/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ccs811/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cd74hc4067/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cd74hc4067/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cd74hc4067/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cd74hc4067/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/climate_ir_lg/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/climate_ir_lg/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/climate_ir_lg/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/color/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/color/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/color/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/color/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/color_temperature/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/color_temperature/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/color_temperature/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/color_temperature/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/combination/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/combination/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/combination/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/combination/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/coolix/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/coolix/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/coolix/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/copy/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/copy/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/copy/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/copy/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cs5460a/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cs5460a/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cs5460a/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cs5460a/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cse7761/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cse7761/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cse7761/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cse7761/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cse7766/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cse7766/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cse7766/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cse7766/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cst226/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cst816/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ct_clamp/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ct_clamp/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ct_clamp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ct_clamp/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/current_based/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/current_based/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/current_based/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/current_based/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/cwww/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/cwww/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/cwww/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/cwww/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/dac7678/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dac7678/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dac7678/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dac7678/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/daikin/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/daikin/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/daikin_arc/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/daikin_arc/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/daikin_brc/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/daikin_brc/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/daikin_brc/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dallas_temp/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dallas_temp/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dallas_temp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dallas_temp/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/daly_bms/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/daly_bms/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/daly_bms/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/daly_bms/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/debug/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/debug/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/debug/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/debug/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/deep_sleep/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/deep_sleep/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/deep_sleep/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/delonghi/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/delonghi/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/delonghi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dfplayer/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dfplayer/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dfplayer/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dfplayer/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/dfrobot_sen0395/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dfrobot_sen0395/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dfrobot_sen0395/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dfrobot_sen0395/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/dht/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dht/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dht/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dht/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/dht12/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dht12/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dht12/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dht12/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/display/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dps310/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dps310/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dps310/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dps310/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ds1307/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ds1307/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ds1307/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ds1307/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/dsmr/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/dsmr/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/dsmr/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/dsmr/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/duty_cycle/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/duty_cycle/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/duty_cycle/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/duty_cycle/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/duty_time/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/duty_time/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/duty_time/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/duty_time/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/e131/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/e131/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/e131/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/e131/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ee895/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ee895/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ee895/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ee895/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ektf2232/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ektf2232/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ektf2232/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ektf2232/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/emc2101/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/emc2101/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/emc2101/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/emc2101/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/emmeti/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/emmeti/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/endstop/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/endstop/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/endstop/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/endstop/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ens160_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ens160_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ens160_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ens160_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ens160_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ens160_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ens160_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ens160_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ens210/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ens210/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ens210/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ens210/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/esp32_ble/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_ble/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_ble_beacon/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_ble_beacon/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_ble_client/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_ble_client/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_ble_server/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_ble_server/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_ble_tracker/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_ble_tracker/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_camera/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_camera_web_server/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_can/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_can/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_dac/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_hall/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_improv/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_improv/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_rmt_led_strip/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp32_rmt_led_strip/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/esp32_touch/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/esp8266_pwm/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ethernet/{test-dp83848.esp32.yaml => test-dp83848.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-ip101.esp32.yaml => test-ip101.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-jl1101.esp32.yaml => test-jl1101.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-ksz8081.esp32.yaml => test-ksz8081.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-ksz8081rna.esp32.yaml => test-ksz8081rna.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-lan8720.esp32.yaml => test-lan8720.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-rtl8201.esp32.yaml => test-rtl8201.esp32-ard.yaml} (100%) rename tests/components/ethernet/{test-w5500.esp32.yaml => test-w5500.esp32-ard.yaml} (100%) rename tests/components/ethernet_info/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/event/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/event/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/event/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/event/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/exposure_notifications/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/exposure_notifications/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/external_components/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/external_components/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/external_components/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/external_components/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ezo/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ezo/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ezo/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ezo/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ezo_pmp/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ezo_pmp/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ezo_pmp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ezo_pmp/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/factory_reset/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/factory_reset/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/factory_reset/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/factory_reset/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/fastled_clockless/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/fastled_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/feedback/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/feedback/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/feedback/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/feedback/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/fingerprint_grow/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/fingerprint_grow/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/fingerprint_grow/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/fingerprint_grow/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/font/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/font/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/font/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/font/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/fs3000/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/fs3000/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/fs3000/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/fs3000/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ft5x06/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ft5x06/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ft5x06/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ft5x06/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ft63x6/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ft63x6/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ft63x6/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ft63x6/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/fujitsu_general/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/fujitsu_general/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/fujitsu_general/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gcja5/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gcja5/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gcja5/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gcja5/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gdk101/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gdk101/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gdk101/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/globals/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/globals/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/globals/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/globals/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gp8403/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gp8403/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gp8403/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gp8403/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gpio/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gpio/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gpio/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gpio/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gps/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gps/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gps/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gps/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/graph/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/graph/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/graph/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/graph/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/graphical_display_menu/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/graphical_display_menu/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/graphical_display_menu/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/graphical_display_menu/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gree/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gree/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gree/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/grove_tb6612fng/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/grove_tb6612fng/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/grove_tb6612fng/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/grove_tb6612fng/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/growatt_solar/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/growatt_solar/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/growatt_solar/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/growatt_solar/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/gt911/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/gt911/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/gt911/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/gt911/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/haier/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/haier/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/haier/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/haier/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/havells_solar/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/havells_solar/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/havells_solar/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/havells_solar/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hbridge/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hbridge/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hbridge/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hbridge/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hdc1080/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hdc1080/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hdc1080/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hdc1080/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/he60r/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/he60r/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/he60r/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/he60r/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/heatpumpir/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/heatpumpir/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hitachi_ac344/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hitachi_ac344/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hitachi_ac344/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hitachi_ac424/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hitachi_ac424/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hitachi_ac424/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hlw8012/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hlw8012/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hlw8012/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hlw8012/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hm3301/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hm3301/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hm3301/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hm3301/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hmc5883l/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hmc5883l/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hmc5883l/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hmc5883l/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/homeassistant/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/homeassistant/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/homeassistant/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/homeassistant/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/homeassistant/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/honeywell_hih_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/honeywell_hih_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/honeywell_hih_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/honeywell_hih_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/honeywellabp/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/honeywellabp/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/honeywellabp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/honeywellabp/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/honeywellabp2_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/honeywellabp2_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/honeywellabp2_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/honeywellabp2_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hrxl_maxsonar_wr/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hrxl_maxsonar_wr/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hrxl_maxsonar_wr/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hrxl_maxsonar_wr/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hte501/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hte501/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hte501/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hte501/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/http_request/{test-nossl.esp8266.yaml => test-nossl.esp8266-ard.yaml} (100%) rename tests/components/http_request/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/http_request/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/http_request/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/http_request/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/htu21d/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/htu21d/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/htu21d/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/htu21d/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/htu31d/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/htu31d/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hx711/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hx711/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hx711/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hx711/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hydreon_rgxx/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hydreon_rgxx/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hydreon_rgxx/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hydreon_rgxx/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/hyt271/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/hyt271/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/hyt271/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/hyt271/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/i2s_audio/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/i2s_audio/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/iaqcore/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/iaqcore/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/iaqcore/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/iaqcore/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ili9xxx/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ili9xxx/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ili9xxx/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ili9xxx/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/image/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/image/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/image/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/image/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/improv_serial/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/improv_serial/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/improv_serial/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/improv_serial/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina219/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina219/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina219/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina219/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina226/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina226/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina226/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina226/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina260/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina260/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina260/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina260/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina2xx_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina2xx_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina2xx_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina2xx_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina2xx_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina2xx_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina2xx_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina2xx_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ina3221/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ina3221/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ina3221/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ina3221/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/inkbird_ibsth1_mini/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/inkbird_ibsth1_mini/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/inkplate6/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/integration/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/integration/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/integration/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/integration/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/integration/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/integration/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/internal_temperature/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/internal_temperature/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/internal_temperature/{test.esp32-s2.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/internal_temperature/{test.esp32.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/internal_temperature/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/internal_temperature/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/interval/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/interval/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/interval/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/interval/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/jsn_sr04t/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/jsn_sr04t/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/jsn_sr04t/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/jsn_sr04t/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/kamstrup_kmp/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/kamstrup_kmp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/key_collector/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/key_collector/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/key_collector/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/key_collector/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/kmeteriso/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/kmeteriso/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/kmeteriso/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/kmeteriso/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/kuntze/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/kuntze/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/kuntze/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/kuntze/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/lcd_gpio/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/lcd_gpio/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/lcd_gpio/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lcd_gpio/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/lcd_menu/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/lcd_menu/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/lcd_menu/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lcd_menu/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/lcd_pcf8574/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/lcd_pcf8574/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/lcd_pcf8574/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lcd_pcf8574/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ld2410/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ld2410/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ld2410/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ld2410/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ld2420/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ld2420/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ld2420/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ld2420/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ledc/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ledc/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/light/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/light/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/light/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/light/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/lightwaverf/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lilygo_t5_47/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/lilygo_t5_47/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/lilygo_t5_47/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lilygo_t5_47/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/lock/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/lock/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/lock/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/lock/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/logger/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/logger/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/logger/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/logger/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ltr390/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ltr390/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ltr390/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ltr390/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ltr_als_ps/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ltr_als_ps/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ltr_als_ps/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ltr_als_ps/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/matrix_keypad/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/matrix_keypad/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/matrix_keypad/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/matrix_keypad/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max31855/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max31855/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max31855/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max31855/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max31856/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max31856/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max31856/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max31856/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max31865/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max31865/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max31865/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max31865/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max44009/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max44009/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max44009/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max44009/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max6675/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max6675/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max6675/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max6675/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max6956/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max6956/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max6956/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max6956/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max7219/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max7219/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max7219/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max7219/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max7219digit/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max7219digit/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max7219digit/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max7219digit/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/max9611/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/max9611/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/max9611/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/max9611/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp23008/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp23008/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp23008/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp23008/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp23016/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp23016/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp23016/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp23016/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp23017/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp23017/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp23017/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp23017/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp23s08/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp23s08/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp23s08/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp23s08/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp23s17/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp23s17/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp23s17/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp23s17/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp2515/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp2515/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp2515/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp2515/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp3008/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp3008/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp3008/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp3008/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp3204/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp3204/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp3204/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp3204/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp4725/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp4725/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp4725/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp4725/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp4728/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp4728/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp4728/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp4728/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp47a1/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp47a1/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp47a1/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp47a1/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp9600/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp9600/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp9600/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp9600/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mcp9808/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mcp9808/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mcp9808/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mcp9808/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mdns/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mdns/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mdns/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mdns/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/media_player/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mhz19/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mhz19/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mhz19/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mhz19/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/micronova/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/micronova/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/micronova/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/micronova/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/microphone/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/microphone/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mics_4514/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mics_4514/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mics_4514/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mics_4514/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/midea/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/midea/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/midea/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/midea_ir/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/midea_ir/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/midea_ir/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mitsubishi/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mitsubishi/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mitsubishi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mlx90393/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mlx90393/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mlx90393/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mlx90393/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mlx90614/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mlx90614/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mlx90614/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mlx90614/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mmc5603/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mmc5603/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mmc5603/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mmc5603/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mmc5983/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mmc5983/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mmc5983/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mmc5983/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/modbus/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/modbus/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/modbus/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/modbus/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/modbus_controller/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/modbus_controller/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/modbus_controller/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/modbus_controller/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/monochromatic/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/monochromatic/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/monochromatic/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/monochromatic/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mopeka_ble/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mopeka_ble/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mopeka_pro_check/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mopeka_pro_check/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mopeka_std_check/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mopeka_std_check/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mpl3115a2/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mpl3115a2/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mpl3115a2/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mpl3115a2/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mpr121/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mpr121/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mpr121/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mpr121/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mpu6050/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mpu6050/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mpu6050/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mpu6050/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mpu6886/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mpu6886/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mpu6886/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mpu6886/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/mqtt/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/mqtt/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mqtt/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mqtt/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/mqtt_subscribe/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/mqtt_subscribe/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/mqtt_subscribe/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ms5611/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ms5611/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ms5611/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ms5611/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/my9231/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/my9231/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/my9231/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/my9231/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/neopixelbus/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/neopixelbus/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/neopixelbus/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/network/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/network/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/network/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/network/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/nextion/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/nextion/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/nextion/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/nextion/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/noblex/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/noblex/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/noblex/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ntc/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ntc/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ntc/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/ntc/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/ntc/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ntc/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ota/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ota/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ota/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ota/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/output/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/output/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/output/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/output/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/partition/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/partition/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pca6416a/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pca6416a/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pca6416a/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pca6416a/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pca9554/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pca9554/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pca9554/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pca9554/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pca9685/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pca9685/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pca9685/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pca9685/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pcd8544/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pcd8544/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pcd8544/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pcd8544/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pcf85063/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pcf85063/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pcf85063/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pcf85063/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pcf8563/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pcf8563/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pcf8563/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pcf8563/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pcf8574/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pcf8574/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pcf8574/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pcf8574/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pid/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pid/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pid/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pid/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pipsolar/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pipsolar/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pipsolar/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pipsolar/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pm1006/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pm1006/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pm1006/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pm1006/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pmsa003i/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pmsa003i/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pmsa003i/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pmsa003i/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pmsx003/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pmsx003/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pmsx003/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pmsx003/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pmwcs3/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pmwcs3/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pmwcs3/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pmwcs3/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pn532_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pn532_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pn532_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pn532_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pn532_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pn532_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pn532_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pn532_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pn7150_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pn7150_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pn7150_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pn7150_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pn7160_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pn7160_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pn7160_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pn7160_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pn7160_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pn7160_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pn7160_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pn7160_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/power_supply/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/power_supply/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/power_supply/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/power_supply/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/prometheus/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/prometheus/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/prometheus/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/psram/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/psram/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pulse_counter/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pulse_counter/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pulse_counter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pulse_counter/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pulse_meter/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pulse_meter/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pulse_meter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pulse_meter/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pulse_width/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pulse_width/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pulse_width/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pulse_width/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pvvx_mithermometer/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pvvx_mithermometer/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pylontech/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pylontech/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pylontech/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pylontech/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pzem004t/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pzem004t/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pzem004t/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pzem004t/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pzemac/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pzemac/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pzemac/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pzemac/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/pzemdc/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/pzemdc/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/pzemdc/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/pzemdc/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/qmc5883l/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/qmc5883l/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/qmc5883l/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/qmc5883l/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/qmp6988/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/qmp6988/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/qmp6988/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/qmp6988/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/qr_code/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/qr_code/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/qr_code/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/qr_code/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/qwiic_pir/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/qwiic_pir/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/qwiic_pir/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/qwiic_pir/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/radon_eye_ble/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/radon_eye_ble/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/radon_eye_rd200/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/radon_eye_rd200/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rc522_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rc522_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rc522_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rc522_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rc522_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rc522_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rc522_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rc522_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rdm6300/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rdm6300/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rdm6300/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rdm6300/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/remote_receiver/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/remote_receiver/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/remote_receiver/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/remote_transmitter/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/remote_transmitter/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/remote_transmitter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/resistance/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/resistance/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/resistance/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/resistance/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/resistance/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/resistance/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/restart/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/restart/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/restart/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/restart/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rf_bridge/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rf_bridge/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rf_bridge/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rf_bridge/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rgb/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rgb/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rgb/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rgb/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rgbct/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rgbct/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rgbct/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rgbct/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rgbw/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rgbw/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rgbw/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rgbw/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rgbww/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rgbww/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rgbww/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rgbww/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rotary_encoder/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rotary_encoder/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rotary_encoder/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rotary_encoder/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rp2040_pio_led_strip/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rp2040_pwm/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/rtttl/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/rtttl/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/rtttl/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/rtttl/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ruuvi_ble/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ruuvi_ble/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ruuvitag/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ruuvitag/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/safe_mode/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/safe_mode/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/safe_mode/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/safe_mode/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/scd30/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/scd30/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/scd30/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/scd30/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/scd4x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/scd4x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/scd4x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/scd4x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/script/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/script/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/script/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/script/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/script/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sdm_meter/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sdm_meter/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sdm_meter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sdm_meter/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sdp3x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sdp3x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sdp3x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sdp3x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sds011/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sds011/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sds011/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sds011/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/seeed_mr24hpc1/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/selec_meter/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/selec_meter/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/selec_meter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/selec_meter/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sen0321/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sen0321/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sen0321/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sen0321/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sen21231/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sen21231/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sen21231/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sen21231/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sen5x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sen5x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sen5x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sen5x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/senseair/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/senseair/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/senseair/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/senseair/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/servo/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/servo/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/servo/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/servo/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sfa30/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sfa30/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sfa30/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sfa30/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sgp30/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sgp30/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sgp30/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sgp30/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sgp4x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sgp4x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sgp4x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sgp4x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/shelly_dimmer/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sht3xd/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sht3xd/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sht3xd/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sht3xd/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sht4x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sht4x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sht4x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sht4x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/shtcx/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/shtcx/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/shtcx/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/shtcx/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/shutdown/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/shutdown/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/shutdown/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/shutdown/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sigma_delta_output/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sigma_delta_output/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sigma_delta_output/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sigma_delta_output/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sim800l/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sim800l/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sim800l/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sim800l/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/slow_pwm/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/slow_pwm/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/slow_pwm/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/slow_pwm/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sm16716/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sm16716/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sm16716/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sm16716/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sm2135/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sm2135/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sm2135/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sm2135/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sm2235/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sm2235/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sm2235/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sm2235/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sm2335/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sm2335/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sm2335/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sm2335/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sm300d2/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sm300d2/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sm300d2/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sm300d2/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sml/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sml/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sml/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sml/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/smt100/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/smt100/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/smt100/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/smt100/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sn74hc165/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sn74hc165/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sn74hc165/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sn74hc165/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sn74hc595/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sn74hc595/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sn74hc595/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sn74hc595/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sntp/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/sntp/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sntp/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sntp/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sntp/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sonoff_d1/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sonoff_d1/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/speaker/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/speaker/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/speed/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/speed/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/speed/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/speed/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/spi_device/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/spi_device/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/spi_device/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/spi_device/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/spi_led_strip/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/spi_led_strip/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/spi_led_strip/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/spi_led_strip/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sprinkler/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sprinkler/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sprinkler/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sprinkler/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sps30/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sps30/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sps30/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sps30/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1306_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1306_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1306_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1306_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1306_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1306_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1306_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1306_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1322_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1322_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1322_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1322_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1325_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1325_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1325_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1325_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1327_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1327_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1327_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1327_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1327_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1327_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1327_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1327_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1331_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1331_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1331_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1331_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ssd1351_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ssd1351_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ssd1351_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ssd1351_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/st7567_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/st7567_i2c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/st7567_i2c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/st7567_i2c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/st7567_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/st7567_spi/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/st7567_spi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/st7567_spi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/st7735/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/st7735/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/st7735/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/st7735/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/st7789v/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/st7789v/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/st7789v/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/st7789v/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/st7920/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/st7920/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/st7920/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/st7920/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/status/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/status/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/status/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/status/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/status_led/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/status_led/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/status_led/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/status_led/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/stepper/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/stepper/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/stepper/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/stepper/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sts3x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sts3x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sts3x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sts3x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sun/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sun/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sun/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sun/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sun_gtil2/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sun_gtil2/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sun_gtil2/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sun_gtil2/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/sx1509/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/sx1509/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/sx1509/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/sx1509/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/t6615/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/t6615/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/t6615/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/t6615/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tca9548a/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tca9548a/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tca9548a/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tca9548a/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tcl112/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tcl112/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tcl112/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tcs34725/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tcs34725/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tcs34725/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tcs34725/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tee501/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tee501/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tee501/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tee501/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/teleinfo/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/teleinfo/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/teleinfo/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/teleinfo/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/template/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/template/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/template/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/template/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/template/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/thermostat/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/thermostat/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/thermostat/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/thermostat/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/time/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/time/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/time/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/time/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/time_based/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/time_based/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/time_based/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/time_based/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tlc59208f/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tlc59208f/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tlc59208f/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tlc59208f/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tlc5947/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tlc5947/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tlc5947/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tlc5947/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tlc5971/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tlc5971/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tlc5971/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/tlc5971/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tlc5971/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tm1621/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tm1621/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tm1621/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tm1621/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tm1637/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tm1637/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tm1637/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tm1637/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tm1638/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tm1638/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tm1638/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tm1638/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tm1651/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tm1651/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tm1651/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tm1651/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tmp102/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tmp102/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tmp102/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tmp102/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tmp1075/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tmp1075/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tmp1075/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tmp1075/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tmp117/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tmp117/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tmp117/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tmp117/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tof10120/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tof10120/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tof10120/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tof10120/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/toshiba/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/toshiba/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/toshiba/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/total_daily_energy/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/total_daily_energy/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/total_daily_energy/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/total_daily_energy/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tsl2561/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tsl2561/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tsl2561/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tsl2561/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tsl2591/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tsl2591/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tsl2591/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tsl2591/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tt21100/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tt21100/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tt21100/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/tt21100/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tt21100/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ttp229_bsf/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ttp229_bsf/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ttp229_bsf/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ttp229_bsf/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ttp229_lsf/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ttp229_lsf/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ttp229_lsf/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ttp229_lsf/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tuya/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tuya/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tuya/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tuya/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/tx20/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/tx20/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/tx20/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/tx20/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/uart/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/uart/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/uart/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/uart/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ufire_ec/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ufire_ec/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ufire_ec/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ufire_ec/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ufire_ise/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ufire_ise/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ufire_ise/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ufire_ise/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/uln2003/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/uln2003/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/uln2003/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/uln2003/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/ultrasonic/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/ultrasonic/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/ultrasonic/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/ultrasonic/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/update/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/update/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/uponor_smatrix/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/uponor_smatrix/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/uponor_smatrix/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/uponor_smatrix/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/uptime/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/uptime/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/uptime/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/uptime/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/vbus/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/vbus/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/vbus/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/vbus/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/veml3235/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/veml3235/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/veml3235/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/veml3235/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/veml7700/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/veml7700/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/veml7700/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/veml7700/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/version/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/version/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/version/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/version/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/vl53l0x/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/vl53l0x/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/vl53l0x/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/vl53l0x/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/voice_assistant/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/voice_assistant/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wake_on_lan/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wake_on_lan/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wake_on_lan/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wake_on_lan/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/waveshare_epaper/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/waveshare_epaper/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/waveshare_epaper/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/waveshare_epaper/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/web_server/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/web_server/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/web_server/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/whirlpool/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/whirlpool/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/whirlpool/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/whynter/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/whynter/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/whynter/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wiegand/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wiegand/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wiegand/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wiegand/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/wifi/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wifi/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wifi/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wifi/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/wifi_info/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wifi_info/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wifi_info/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wifi_info/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/wifi_signal/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wifi_signal/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wifi_signal/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wifi_signal/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/wireguard/{test.bk72xx.yaml => test.bk72xx-ard.yaml} (100%) rename tests/components/wireguard/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wireguard/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wireguard/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wk2132_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2132_i2c/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2132_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2132_spi/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2168_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2168_i2c/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2168_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2168_spi/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2204_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2204_i2c/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2204_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2204_spi/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2212_i2c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2212_i2c/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wk2212_spi/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wk2212_spi/{test.esp32-s3.yaml => test.esp32-s3-ard.yaml} (100%) rename tests/components/wl_134/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wl_134/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wl_134/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/wl_134/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/wled/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/wled/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/wled/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/x9c/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/x9c/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/x9c/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/x9c/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/xgzp68xx/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xgzp68xx/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xgzp68xx/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/xgzp68xx/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/xiaomi_ble/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_ble/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_cgd1/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_cgd1/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_cgdk2/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_cgdk2/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_cgg1/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_cgg1/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_cgpr1/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_cgpr1/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_gcls002/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_gcls002/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_hhccjcy01/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_hhccjcy01/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_hhccpot002/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_hhccpot002/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_jqjcy01ym/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_jqjcy01ym/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_lywsd02/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_lywsd02/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_lywsd03mmc/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_lywsd03mmc/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_lywsdcgq/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_lywsdcgq/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_mhoc303/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_mhoc303/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_mhoc401/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_mhoc401/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_miscale copy/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_miscale copy/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_miscale/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_miscale/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_mjyd02yla/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_mjyd02yla/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_mue4094rt/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_mue4094rt/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_rtcgq02lm/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_rtcgq02lm/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xiaomi_wx08zm/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xiaomi_wx08zm/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xl9535/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xl9535/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xl9535/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/xl9535/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/xpt2046/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/xpt2046/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/xpt2046/{test.esp32-s2.yaml => test.esp32-s2-ard.yaml} (100%) rename tests/components/xpt2046/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/xpt2046/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/yashima/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/yashima/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/yashima/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/zhlt01/{test.esp32-c3.yaml => test.esp32-ard.yaml} (100%) rename tests/components/zhlt01/{test.esp32.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/zhlt01/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/zio_ultrasonic/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/zio_ultrasonic/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/zio_ultrasonic/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/zio_ultrasonic/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/components/zyaura/{test.esp32.yaml => test.esp32-ard.yaml} (100%) rename tests/components/zyaura/{test.esp32-c3.yaml => test.esp32-c3-ard.yaml} (100%) rename tests/components/zyaura/{test.esp8266.yaml => test.esp8266-ard.yaml} (100%) rename tests/components/zyaura/{test.rp2040.yaml => test.rp2040-ard.yaml} (100%) rename tests/test_build_components/{build_components_base.bk72xx.yaml => build_components_base.bk72xx-ard.yaml} (100%) create mode 100644 tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml create mode 100644 tests/test_build_components/build_components_base.esp32-idf-50.yaml create mode 100644 tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml create mode 100644 tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml rename tests/test_build_components/{build_components_base.esp8266.yaml => build_components_base.esp8266-ard.yaml} (87%) rename tests/test_build_components/{build_components_base.rp2040.yaml => build_components_base.rp2040-ard.yaml} (92%) diff --git a/script/test_build_components b/script/test_build_components index f82dd5c3b6..9bbb694dcc 100755 --- a/script/test_build_components +++ b/script/test_build_components @@ -24,8 +24,8 @@ fi start_esphome() { # create dynamic yaml file in `build` folder. - # `./tests/test_build_components/build/[target_component].[test_name].[target_platform].yaml` - component_test_file="./tests/test_build_components/build/$target_component.$test_name.$target_platform.yaml" + # `./tests/test_build_components/build/[target_component].[test_name].[target_platform_with_version].yaml` + component_test_file="./tests/test_build_components/build/$target_component.$test_name.$target_platform_with_version.yaml" cp $target_platform_file $component_test_file if [[ "$OSTYPE" == "darwin"* ]]; then @@ -36,7 +36,7 @@ start_esphome() { fi # Start esphome process - echo "> [$target_component] [$test_name] [$target_platform]" + echo "> [$target_component] [$test_name] [$target_platform_with_version]" set -x # TODO: Validate escape of Command line substitution value python -m esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file @@ -76,16 +76,17 @@ for f in ./tests/components/$target_component/*.*.yaml; do # 2. `./tests/test_build_components/build_components_base.[target_platform]-ard.yaml` target_platform_file="./tests/test_build_components/build_components_base.$target_platform.yaml" if ! [ -f "$target_platform_file" ]; then - # Try find arduino test framework as platform. - target_platform_ard="$target_platform-ard" - target_platform_file="./tests/test_build_components/build_components_base.$target_platform_ard.yaml" - if ! [ -f "$target_platform_file" ]; then - echo "No base test file [./tests/test_build_components/build_components_base.$target_platform.yaml, ./tests/build_components_base.$target_platform_ard.yaml] for component test [$f] found." - exit 1 - fi - target_platform=$target_platform_ard + echo "No base test file [./tests/test_build_components/build_components_base.$target_platform.yaml] for component test [$f] found." + exit 1 fi - start_esphome + for target_platform_file in ./tests/test_build_components/build_components_base.$target_platform*.yaml; do + # trim off "./tests/test_build_components/build_components_base." prefix + target_platform_with_version=${target_platform_file:52} + # ...now remove suffix starting with "." leaving just the test target hardware and software platform (possibly with version) + # For example: "esp32-s3-idf-50" + target_platform_with_version=${target_platform_with_version%.*} + start_esphome + done fi done diff --git a/tests/components/a01nyub/test.esp32.yaml b/tests/components/a01nyub/test.esp32-ard.yaml similarity index 100% rename from tests/components/a01nyub/test.esp32.yaml rename to tests/components/a01nyub/test.esp32-ard.yaml diff --git a/tests/components/a01nyub/test.esp32-c3.yaml b/tests/components/a01nyub/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/a01nyub/test.esp32-c3.yaml rename to tests/components/a01nyub/test.esp32-c3-ard.yaml diff --git a/tests/components/a01nyub/test.esp8266.yaml b/tests/components/a01nyub/test.esp8266-ard.yaml similarity index 100% rename from tests/components/a01nyub/test.esp8266.yaml rename to tests/components/a01nyub/test.esp8266-ard.yaml diff --git a/tests/components/a01nyub/test.rp2040.yaml b/tests/components/a01nyub/test.rp2040-ard.yaml similarity index 100% rename from tests/components/a01nyub/test.rp2040.yaml rename to tests/components/a01nyub/test.rp2040-ard.yaml diff --git a/tests/components/a02yyuw/test.esp32.yaml b/tests/components/a02yyuw/test.esp32-ard.yaml similarity index 100% rename from tests/components/a02yyuw/test.esp32.yaml rename to tests/components/a02yyuw/test.esp32-ard.yaml diff --git a/tests/components/a02yyuw/test.esp32-c3.yaml b/tests/components/a02yyuw/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/a02yyuw/test.esp32-c3.yaml rename to tests/components/a02yyuw/test.esp32-c3-ard.yaml diff --git a/tests/components/a02yyuw/test.esp8266.yaml b/tests/components/a02yyuw/test.esp8266-ard.yaml similarity index 100% rename from tests/components/a02yyuw/test.esp8266.yaml rename to tests/components/a02yyuw/test.esp8266-ard.yaml diff --git a/tests/components/a02yyuw/test.rp2040.yaml b/tests/components/a02yyuw/test.rp2040-ard.yaml similarity index 100% rename from tests/components/a02yyuw/test.rp2040.yaml rename to tests/components/a02yyuw/test.rp2040-ard.yaml diff --git a/tests/components/a4988/test.esp32.yaml b/tests/components/a4988/test.esp32-ard.yaml similarity index 100% rename from tests/components/a4988/test.esp32.yaml rename to tests/components/a4988/test.esp32-ard.yaml diff --git a/tests/components/a4988/test.esp32-c3.yaml b/tests/components/a4988/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/a4988/test.esp32-c3.yaml rename to tests/components/a4988/test.esp32-c3-ard.yaml diff --git a/tests/components/a4988/test.esp8266.yaml b/tests/components/a4988/test.esp8266-ard.yaml similarity index 100% rename from tests/components/a4988/test.esp8266.yaml rename to tests/components/a4988/test.esp8266-ard.yaml diff --git a/tests/components/a4988/test.rp2040.yaml b/tests/components/a4988/test.rp2040-ard.yaml similarity index 100% rename from tests/components/a4988/test.rp2040.yaml rename to tests/components/a4988/test.rp2040-ard.yaml diff --git a/tests/components/absolute_humidity/test.esp32-c3.yaml b/tests/components/absolute_humidity/test.esp32-ard.yaml similarity index 100% rename from tests/components/absolute_humidity/test.esp32-c3.yaml rename to tests/components/absolute_humidity/test.esp32-ard.yaml diff --git a/tests/components/absolute_humidity/test.esp32.yaml b/tests/components/absolute_humidity/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/absolute_humidity/test.esp32.yaml rename to tests/components/absolute_humidity/test.esp32-c3-ard.yaml diff --git a/tests/components/absolute_humidity/test.esp8266.yaml b/tests/components/absolute_humidity/test.esp8266-ard.yaml similarity index 100% rename from tests/components/absolute_humidity/test.esp8266.yaml rename to tests/components/absolute_humidity/test.esp8266-ard.yaml diff --git a/tests/components/absolute_humidity/test.rp2040.yaml b/tests/components/absolute_humidity/test.rp2040-ard.yaml similarity index 100% rename from tests/components/absolute_humidity/test.rp2040.yaml rename to tests/components/absolute_humidity/test.rp2040-ard.yaml diff --git a/tests/components/ac_dimmer/test.esp32.yaml b/tests/components/ac_dimmer/test.esp32-ard.yaml similarity index 100% rename from tests/components/ac_dimmer/test.esp32.yaml rename to tests/components/ac_dimmer/test.esp32-ard.yaml diff --git a/tests/components/ac_dimmer/test.esp32-c3.yaml b/tests/components/ac_dimmer/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ac_dimmer/test.esp32-c3.yaml rename to tests/components/ac_dimmer/test.esp32-c3-ard.yaml diff --git a/tests/components/ac_dimmer/test.esp8266.yaml b/tests/components/ac_dimmer/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ac_dimmer/test.esp8266.yaml rename to tests/components/ac_dimmer/test.esp8266-ard.yaml diff --git a/tests/components/ac_dimmer/test.rp2040.yaml b/tests/components/ac_dimmer/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ac_dimmer/test.rp2040.yaml rename to tests/components/ac_dimmer/test.rp2040-ard.yaml diff --git a/tests/components/adc/test.esp32.yaml b/tests/components/adc/test.esp32-ard.yaml similarity index 100% rename from tests/components/adc/test.esp32.yaml rename to tests/components/adc/test.esp32-ard.yaml diff --git a/tests/components/adc/test.esp32-c3.yaml b/tests/components/adc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/adc/test.esp32-c3.yaml rename to tests/components/adc/test.esp32-c3-ard.yaml diff --git a/tests/components/adc/test.esp32-s2.yaml b/tests/components/adc/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/adc/test.esp32-s2.yaml rename to tests/components/adc/test.esp32-s2-ard.yaml diff --git a/tests/components/adc/test.esp32-s3.yaml b/tests/components/adc/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/adc/test.esp32-s3.yaml rename to tests/components/adc/test.esp32-s3-ard.yaml diff --git a/tests/components/adc/test.esp8266.yaml b/tests/components/adc/test.esp8266-ard.yaml similarity index 100% rename from tests/components/adc/test.esp8266.yaml rename to tests/components/adc/test.esp8266-ard.yaml diff --git a/tests/components/adc/test.rp2040.yaml b/tests/components/adc/test.rp2040-ard.yaml similarity index 100% rename from tests/components/adc/test.rp2040.yaml rename to tests/components/adc/test.rp2040-ard.yaml diff --git a/tests/components/adc128s102/test.esp32.yaml b/tests/components/adc128s102/test.esp32-ard.yaml similarity index 100% rename from tests/components/adc128s102/test.esp32.yaml rename to tests/components/adc128s102/test.esp32-ard.yaml diff --git a/tests/components/adc128s102/test.esp32-c3.yaml b/tests/components/adc128s102/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/adc128s102/test.esp32-c3.yaml rename to tests/components/adc128s102/test.esp32-c3-ard.yaml diff --git a/tests/components/adc128s102/test.esp8266.yaml b/tests/components/adc128s102/test.esp8266-ard.yaml similarity index 100% rename from tests/components/adc128s102/test.esp8266.yaml rename to tests/components/adc128s102/test.esp8266-ard.yaml diff --git a/tests/components/adc128s102/test.rp2040.yaml b/tests/components/adc128s102/test.rp2040-ard.yaml similarity index 100% rename from tests/components/adc128s102/test.rp2040.yaml rename to tests/components/adc128s102/test.rp2040-ard.yaml diff --git a/tests/components/addressable_light/test.esp32.yaml b/tests/components/addressable_light/test.esp32-ard.yaml similarity index 100% rename from tests/components/addressable_light/test.esp32.yaml rename to tests/components/addressable_light/test.esp32-ard.yaml diff --git a/tests/components/addressable_light/test.esp32-c3.yaml b/tests/components/addressable_light/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/addressable_light/test.esp32-c3.yaml rename to tests/components/addressable_light/test.esp32-c3-ard.yaml diff --git a/tests/components/ade7880/test.esp32.yaml b/tests/components/ade7880/test.esp32-ard.yaml similarity index 100% rename from tests/components/ade7880/test.esp32.yaml rename to tests/components/ade7880/test.esp32-ard.yaml diff --git a/tests/components/ade7880/test.esp32-c3.yaml b/tests/components/ade7880/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ade7880/test.esp32-c3.yaml rename to tests/components/ade7880/test.esp32-c3-ard.yaml diff --git a/tests/components/ade7880/test.esp8266.yaml b/tests/components/ade7880/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ade7880/test.esp8266.yaml rename to tests/components/ade7880/test.esp8266-ard.yaml diff --git a/tests/components/ade7880/test.rp2040.yaml b/tests/components/ade7880/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ade7880/test.rp2040.yaml rename to tests/components/ade7880/test.rp2040-ard.yaml diff --git a/tests/components/ade7953_i2c/test.esp32.yaml b/tests/components/ade7953_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/ade7953_i2c/test.esp32.yaml rename to tests/components/ade7953_i2c/test.esp32-ard.yaml diff --git a/tests/components/ade7953_i2c/test.esp32-c3.yaml b/tests/components/ade7953_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ade7953_i2c/test.esp32-c3.yaml rename to tests/components/ade7953_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/ade7953_i2c/test.esp8266.yaml b/tests/components/ade7953_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ade7953_i2c/test.esp8266.yaml rename to tests/components/ade7953_i2c/test.esp8266-ard.yaml diff --git a/tests/components/ade7953_i2c/test.rp2040.yaml b/tests/components/ade7953_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ade7953_i2c/test.rp2040.yaml rename to tests/components/ade7953_i2c/test.rp2040-ard.yaml diff --git a/tests/components/ade7953_spi/test.esp32.yaml b/tests/components/ade7953_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ade7953_spi/test.esp32.yaml rename to tests/components/ade7953_spi/test.esp32-ard.yaml diff --git a/tests/components/ade7953_spi/test.esp32-c3.yaml b/tests/components/ade7953_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ade7953_spi/test.esp32-c3.yaml rename to tests/components/ade7953_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ade7953_spi/test.esp8266.yaml b/tests/components/ade7953_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ade7953_spi/test.esp8266.yaml rename to tests/components/ade7953_spi/test.esp8266-ard.yaml diff --git a/tests/components/ade7953_spi/test.rp2040.yaml b/tests/components/ade7953_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ade7953_spi/test.rp2040.yaml rename to tests/components/ade7953_spi/test.rp2040-ard.yaml diff --git a/tests/components/ads1115/test.esp32.yaml b/tests/components/ads1115/test.esp32-ard.yaml similarity index 100% rename from tests/components/ads1115/test.esp32.yaml rename to tests/components/ads1115/test.esp32-ard.yaml diff --git a/tests/components/ads1115/test.esp32-c3.yaml b/tests/components/ads1115/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ads1115/test.esp32-c3.yaml rename to tests/components/ads1115/test.esp32-c3-ard.yaml diff --git a/tests/components/ads1115/test.esp8266.yaml b/tests/components/ads1115/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ads1115/test.esp8266.yaml rename to tests/components/ads1115/test.esp8266-ard.yaml diff --git a/tests/components/ads1115/test.rp2040.yaml b/tests/components/ads1115/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ads1115/test.rp2040.yaml rename to tests/components/ads1115/test.rp2040-ard.yaml diff --git a/tests/components/ags10/test.esp32.yaml b/tests/components/ags10/test.esp32-ard.yaml similarity index 100% rename from tests/components/ags10/test.esp32.yaml rename to tests/components/ags10/test.esp32-ard.yaml diff --git a/tests/components/ags10/test.esp32-c3.yaml b/tests/components/ags10/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ags10/test.esp32-c3.yaml rename to tests/components/ags10/test.esp32-c3-ard.yaml diff --git a/tests/components/ags10/test.esp8266.yaml b/tests/components/ags10/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ags10/test.esp8266.yaml rename to tests/components/ags10/test.esp8266-ard.yaml diff --git a/tests/components/aht10/test.esp32.yaml b/tests/components/aht10/test.esp32-ard.yaml similarity index 100% rename from tests/components/aht10/test.esp32.yaml rename to tests/components/aht10/test.esp32-ard.yaml diff --git a/tests/components/aht10/test.esp32-c3.yaml b/tests/components/aht10/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/aht10/test.esp32-c3.yaml rename to tests/components/aht10/test.esp32-c3-ard.yaml diff --git a/tests/components/aht10/test.esp8266.yaml b/tests/components/aht10/test.esp8266-ard.yaml similarity index 100% rename from tests/components/aht10/test.esp8266.yaml rename to tests/components/aht10/test.esp8266-ard.yaml diff --git a/tests/components/aht10/test.rp2040.yaml b/tests/components/aht10/test.rp2040-ard.yaml similarity index 100% rename from tests/components/aht10/test.rp2040.yaml rename to tests/components/aht10/test.rp2040-ard.yaml diff --git a/tests/components/airthings_wave_mini/test.esp32-c3.yaml b/tests/components/airthings_wave_mini/test.esp32-ard.yaml similarity index 100% rename from tests/components/airthings_wave_mini/test.esp32-c3.yaml rename to tests/components/airthings_wave_mini/test.esp32-ard.yaml diff --git a/tests/components/airthings_wave_mini/test.esp32.yaml b/tests/components/airthings_wave_mini/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/airthings_wave_mini/test.esp32.yaml rename to tests/components/airthings_wave_mini/test.esp32-c3-ard.yaml diff --git a/tests/components/airthings_wave_plus/test.esp32-c3.yaml b/tests/components/airthings_wave_plus/test.esp32-ard.yaml similarity index 100% rename from tests/components/airthings_wave_plus/test.esp32-c3.yaml rename to tests/components/airthings_wave_plus/test.esp32-ard.yaml diff --git a/tests/components/airthings_wave_plus/test.esp32.yaml b/tests/components/airthings_wave_plus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/airthings_wave_plus/test.esp32.yaml rename to tests/components/airthings_wave_plus/test.esp32-c3-ard.yaml diff --git a/tests/components/alarm_control_panel/test.esp32-c3.yaml b/tests/components/alarm_control_panel/test.esp32-ard.yaml similarity index 100% rename from tests/components/alarm_control_panel/test.esp32-c3.yaml rename to tests/components/alarm_control_panel/test.esp32-ard.yaml diff --git a/tests/components/alarm_control_panel/test.esp32.yaml b/tests/components/alarm_control_panel/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/alarm_control_panel/test.esp32.yaml rename to tests/components/alarm_control_panel/test.esp32-c3-ard.yaml diff --git a/tests/components/alarm_control_panel/test.esp8266.yaml b/tests/components/alarm_control_panel/test.esp8266-ard.yaml similarity index 100% rename from tests/components/alarm_control_panel/test.esp8266.yaml rename to tests/components/alarm_control_panel/test.esp8266-ard.yaml diff --git a/tests/components/alarm_control_panel/test.rp2040.yaml b/tests/components/alarm_control_panel/test.rp2040-ard.yaml similarity index 100% rename from tests/components/alarm_control_panel/test.rp2040.yaml rename to tests/components/alarm_control_panel/test.rp2040-ard.yaml diff --git a/tests/components/alpha3/test.esp32-c3.yaml b/tests/components/alpha3/test.esp32-ard.yaml similarity index 100% rename from tests/components/alpha3/test.esp32-c3.yaml rename to tests/components/alpha3/test.esp32-ard.yaml diff --git a/tests/components/alpha3/test.esp32.yaml b/tests/components/alpha3/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/alpha3/test.esp32.yaml rename to tests/components/alpha3/test.esp32-c3-ard.yaml diff --git a/tests/components/am2315c/test.esp32.yaml b/tests/components/am2315c/test.esp32-ard.yaml similarity index 100% rename from tests/components/am2315c/test.esp32.yaml rename to tests/components/am2315c/test.esp32-ard.yaml diff --git a/tests/components/am2315c/test.esp32-c3.yaml b/tests/components/am2315c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/am2315c/test.esp32-c3.yaml rename to tests/components/am2315c/test.esp32-c3-ard.yaml diff --git a/tests/components/am2315c/test.esp8266.yaml b/tests/components/am2315c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/am2315c/test.esp8266.yaml rename to tests/components/am2315c/test.esp8266-ard.yaml diff --git a/tests/components/am2315c/test.rp2040.yaml b/tests/components/am2315c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/am2315c/test.rp2040.yaml rename to tests/components/am2315c/test.rp2040-ard.yaml diff --git a/tests/components/am2320/test.esp32.yaml b/tests/components/am2320/test.esp32-ard.yaml similarity index 100% rename from tests/components/am2320/test.esp32.yaml rename to tests/components/am2320/test.esp32-ard.yaml diff --git a/tests/components/am2320/test.esp32-c3.yaml b/tests/components/am2320/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/am2320/test.esp32-c3.yaml rename to tests/components/am2320/test.esp32-c3-ard.yaml diff --git a/tests/components/am2320/test.esp8266.yaml b/tests/components/am2320/test.esp8266-ard.yaml similarity index 100% rename from tests/components/am2320/test.esp8266.yaml rename to tests/components/am2320/test.esp8266-ard.yaml diff --git a/tests/components/am2320/test.rp2040.yaml b/tests/components/am2320/test.rp2040-ard.yaml similarity index 100% rename from tests/components/am2320/test.rp2040.yaml rename to tests/components/am2320/test.rp2040-ard.yaml diff --git a/tests/components/am43/test.esp32-c3.yaml b/tests/components/am43/test.esp32-ard.yaml similarity index 100% rename from tests/components/am43/test.esp32-c3.yaml rename to tests/components/am43/test.esp32-ard.yaml diff --git a/tests/components/am43/test.esp32.yaml b/tests/components/am43/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/am43/test.esp32.yaml rename to tests/components/am43/test.esp32-c3-ard.yaml diff --git a/tests/components/analog_threshold/test.esp32-c3.yaml b/tests/components/analog_threshold/test.esp32-ard.yaml similarity index 100% rename from tests/components/analog_threshold/test.esp32-c3.yaml rename to tests/components/analog_threshold/test.esp32-ard.yaml diff --git a/tests/components/analog_threshold/test.esp32.yaml b/tests/components/analog_threshold/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/analog_threshold/test.esp32.yaml rename to tests/components/analog_threshold/test.esp32-c3-ard.yaml diff --git a/tests/components/analog_threshold/test.esp8266.yaml b/tests/components/analog_threshold/test.esp8266-ard.yaml similarity index 100% rename from tests/components/analog_threshold/test.esp8266.yaml rename to tests/components/analog_threshold/test.esp8266-ard.yaml diff --git a/tests/components/analog_threshold/test.rp2040.yaml b/tests/components/analog_threshold/test.rp2040-ard.yaml similarity index 100% rename from tests/components/analog_threshold/test.rp2040.yaml rename to tests/components/analog_threshold/test.rp2040-ard.yaml diff --git a/tests/components/animation/test.esp32.yaml b/tests/components/animation/test.esp32-ard.yaml similarity index 100% rename from tests/components/animation/test.esp32.yaml rename to tests/components/animation/test.esp32-ard.yaml diff --git a/tests/components/animation/test.esp32-c3.yaml b/tests/components/animation/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/animation/test.esp32-c3.yaml rename to tests/components/animation/test.esp32-c3-ard.yaml diff --git a/tests/components/animation/test.esp8266.yaml b/tests/components/animation/test.esp8266-ard.yaml similarity index 100% rename from tests/components/animation/test.esp8266.yaml rename to tests/components/animation/test.esp8266-ard.yaml diff --git a/tests/components/animation/test.rp2040.yaml b/tests/components/animation/test.rp2040-ard.yaml similarity index 100% rename from tests/components/animation/test.rp2040.yaml rename to tests/components/animation/test.rp2040-ard.yaml diff --git a/tests/components/anova/test.esp32-c3.yaml b/tests/components/anova/test.esp32-ard.yaml similarity index 100% rename from tests/components/anova/test.esp32-c3.yaml rename to tests/components/anova/test.esp32-ard.yaml diff --git a/tests/components/anova/test.esp32.yaml b/tests/components/anova/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/anova/test.esp32.yaml rename to tests/components/anova/test.esp32-c3-ard.yaml diff --git a/tests/components/apds9960/test.esp32.yaml b/tests/components/apds9960/test.esp32-ard.yaml similarity index 100% rename from tests/components/apds9960/test.esp32.yaml rename to tests/components/apds9960/test.esp32-ard.yaml diff --git a/tests/components/apds9960/test.esp32-c3.yaml b/tests/components/apds9960/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/apds9960/test.esp32-c3.yaml rename to tests/components/apds9960/test.esp32-c3-ard.yaml diff --git a/tests/components/apds9960/test.esp8266.yaml b/tests/components/apds9960/test.esp8266-ard.yaml similarity index 100% rename from tests/components/apds9960/test.esp8266.yaml rename to tests/components/apds9960/test.esp8266-ard.yaml diff --git a/tests/components/apds9960/test.rp2040.yaml b/tests/components/apds9960/test.rp2040-ard.yaml similarity index 100% rename from tests/components/apds9960/test.rp2040.yaml rename to tests/components/apds9960/test.rp2040-ard.yaml diff --git a/tests/components/api/test.esp32-c3.yaml b/tests/components/api/test.esp32-ard.yaml similarity index 100% rename from tests/components/api/test.esp32-c3.yaml rename to tests/components/api/test.esp32-ard.yaml diff --git a/tests/components/api/test.esp32.yaml b/tests/components/api/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/api/test.esp32.yaml rename to tests/components/api/test.esp32-c3-ard.yaml diff --git a/tests/components/api/test.esp8266.yaml b/tests/components/api/test.esp8266-ard.yaml similarity index 100% rename from tests/components/api/test.esp8266.yaml rename to tests/components/api/test.esp8266-ard.yaml diff --git a/tests/components/api/test.rp2040.yaml b/tests/components/api/test.rp2040-ard.yaml similarity index 100% rename from tests/components/api/test.rp2040.yaml rename to tests/components/api/test.rp2040-ard.yaml diff --git a/tests/components/as3935_i2c/test.esp32.yaml b/tests/components/as3935_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/as3935_i2c/test.esp32.yaml rename to tests/components/as3935_i2c/test.esp32-ard.yaml diff --git a/tests/components/as3935_i2c/test.esp32-c3.yaml b/tests/components/as3935_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/as3935_i2c/test.esp32-c3.yaml rename to tests/components/as3935_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/as3935_i2c/test.esp8266.yaml b/tests/components/as3935_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/as3935_i2c/test.esp8266.yaml rename to tests/components/as3935_i2c/test.esp8266-ard.yaml diff --git a/tests/components/as3935_i2c/test.rp2040.yaml b/tests/components/as3935_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/as3935_i2c/test.rp2040.yaml rename to tests/components/as3935_i2c/test.rp2040-ard.yaml diff --git a/tests/components/as3935_spi/test.esp32.yaml b/tests/components/as3935_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/as3935_spi/test.esp32.yaml rename to tests/components/as3935_spi/test.esp32-ard.yaml diff --git a/tests/components/as3935_spi/test.esp32-c3.yaml b/tests/components/as3935_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/as3935_spi/test.esp32-c3.yaml rename to tests/components/as3935_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/as3935_spi/test.esp8266.yaml b/tests/components/as3935_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/as3935_spi/test.esp8266.yaml rename to tests/components/as3935_spi/test.esp8266-ard.yaml diff --git a/tests/components/as3935_spi/test.rp2040.yaml b/tests/components/as3935_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/as3935_spi/test.rp2040.yaml rename to tests/components/as3935_spi/test.rp2040-ard.yaml diff --git a/tests/components/as5600/test.esp32.yaml b/tests/components/as5600/test.esp32-ard.yaml similarity index 100% rename from tests/components/as5600/test.esp32.yaml rename to tests/components/as5600/test.esp32-ard.yaml diff --git a/tests/components/as5600/test.esp32-c3.yaml b/tests/components/as5600/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/as5600/test.esp32-c3.yaml rename to tests/components/as5600/test.esp32-c3-ard.yaml diff --git a/tests/components/as5600/test.esp8266.yaml b/tests/components/as5600/test.esp8266-ard.yaml similarity index 100% rename from tests/components/as5600/test.esp8266.yaml rename to tests/components/as5600/test.esp8266-ard.yaml diff --git a/tests/components/as5600/test.rp2040.yaml b/tests/components/as5600/test.rp2040-ard.yaml similarity index 100% rename from tests/components/as5600/test.rp2040.yaml rename to tests/components/as5600/test.rp2040-ard.yaml diff --git a/tests/components/as7341/test.esp32.yaml b/tests/components/as7341/test.esp32-ard.yaml similarity index 100% rename from tests/components/as7341/test.esp32.yaml rename to tests/components/as7341/test.esp32-ard.yaml diff --git a/tests/components/as7341/test.esp32-c3.yaml b/tests/components/as7341/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/as7341/test.esp32-c3.yaml rename to tests/components/as7341/test.esp32-c3-ard.yaml diff --git a/tests/components/as7341/test.esp8266.yaml b/tests/components/as7341/test.esp8266-ard.yaml similarity index 100% rename from tests/components/as7341/test.esp8266.yaml rename to tests/components/as7341/test.esp8266-ard.yaml diff --git a/tests/components/as7341/test.rp2040.yaml b/tests/components/as7341/test.rp2040-ard.yaml similarity index 100% rename from tests/components/as7341/test.rp2040.yaml rename to tests/components/as7341/test.rp2040-ard.yaml diff --git a/tests/components/at581x/test.esp32.yaml b/tests/components/at581x/test.esp32-ard.yaml similarity index 100% rename from tests/components/at581x/test.esp32.yaml rename to tests/components/at581x/test.esp32-ard.yaml diff --git a/tests/components/at581x/test.esp32-c3.yaml b/tests/components/at581x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/at581x/test.esp32-c3.yaml rename to tests/components/at581x/test.esp32-c3-ard.yaml diff --git a/tests/components/at581x/test.esp8266.yaml b/tests/components/at581x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/at581x/test.esp8266.yaml rename to tests/components/at581x/test.esp8266-ard.yaml diff --git a/tests/components/at581x/test.rp2040.yaml b/tests/components/at581x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/at581x/test.rp2040.yaml rename to tests/components/at581x/test.rp2040-ard.yaml diff --git a/tests/components/atc_mithermometer/test.esp32-c3.yaml b/tests/components/atc_mithermometer/test.esp32-ard.yaml similarity index 100% rename from tests/components/atc_mithermometer/test.esp32-c3.yaml rename to tests/components/atc_mithermometer/test.esp32-ard.yaml diff --git a/tests/components/atc_mithermometer/test.esp32.yaml b/tests/components/atc_mithermometer/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/atc_mithermometer/test.esp32.yaml rename to tests/components/atc_mithermometer/test.esp32-c3-ard.yaml diff --git a/tests/components/atm90e26/test.esp32.yaml b/tests/components/atm90e26/test.esp32-ard.yaml similarity index 100% rename from tests/components/atm90e26/test.esp32.yaml rename to tests/components/atm90e26/test.esp32-ard.yaml diff --git a/tests/components/atm90e26/test.esp32-c3.yaml b/tests/components/atm90e26/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/atm90e26/test.esp32-c3.yaml rename to tests/components/atm90e26/test.esp32-c3-ard.yaml diff --git a/tests/components/atm90e26/test.esp8266.yaml b/tests/components/atm90e26/test.esp8266-ard.yaml similarity index 100% rename from tests/components/atm90e26/test.esp8266.yaml rename to tests/components/atm90e26/test.esp8266-ard.yaml diff --git a/tests/components/atm90e26/test.rp2040.yaml b/tests/components/atm90e26/test.rp2040-ard.yaml similarity index 100% rename from tests/components/atm90e26/test.rp2040.yaml rename to tests/components/atm90e26/test.rp2040-ard.yaml diff --git a/tests/components/atm90e32/test.esp32.yaml b/tests/components/atm90e32/test.esp32-ard.yaml similarity index 100% rename from tests/components/atm90e32/test.esp32.yaml rename to tests/components/atm90e32/test.esp32-ard.yaml diff --git a/tests/components/atm90e32/test.esp32-c3.yaml b/tests/components/atm90e32/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/atm90e32/test.esp32-c3.yaml rename to tests/components/atm90e32/test.esp32-c3-ard.yaml diff --git a/tests/components/atm90e32/test.esp8266.yaml b/tests/components/atm90e32/test.esp8266-ard.yaml similarity index 100% rename from tests/components/atm90e32/test.esp8266.yaml rename to tests/components/atm90e32/test.esp8266-ard.yaml diff --git a/tests/components/atm90e32/test.rp2040.yaml b/tests/components/atm90e32/test.rp2040-ard.yaml similarity index 100% rename from tests/components/atm90e32/test.rp2040.yaml rename to tests/components/atm90e32/test.rp2040-ard.yaml diff --git a/tests/components/b_parasite/test.esp32-c3.yaml b/tests/components/b_parasite/test.esp32-ard.yaml similarity index 100% rename from tests/components/b_parasite/test.esp32-c3.yaml rename to tests/components/b_parasite/test.esp32-ard.yaml diff --git a/tests/components/b_parasite/test.esp32.yaml b/tests/components/b_parasite/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/b_parasite/test.esp32.yaml rename to tests/components/b_parasite/test.esp32-c3-ard.yaml diff --git a/tests/components/ballu/test.esp32.yaml b/tests/components/ballu/test.esp32-ard.yaml similarity index 100% rename from tests/components/ballu/test.esp32.yaml rename to tests/components/ballu/test.esp32-ard.yaml diff --git a/tests/components/ballu/test.esp8266.yaml b/tests/components/ballu/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ballu/test.esp8266.yaml rename to tests/components/ballu/test.esp8266-ard.yaml diff --git a/tests/components/bang_bang/test.esp32-c3.yaml b/tests/components/bang_bang/test.esp32-ard.yaml similarity index 100% rename from tests/components/bang_bang/test.esp32-c3.yaml rename to tests/components/bang_bang/test.esp32-ard.yaml diff --git a/tests/components/bang_bang/test.esp32.yaml b/tests/components/bang_bang/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bang_bang/test.esp32.yaml rename to tests/components/bang_bang/test.esp32-c3-ard.yaml diff --git a/tests/components/bang_bang/test.esp8266.yaml b/tests/components/bang_bang/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bang_bang/test.esp8266.yaml rename to tests/components/bang_bang/test.esp8266-ard.yaml diff --git a/tests/components/bang_bang/test.rp2040.yaml b/tests/components/bang_bang/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bang_bang/test.rp2040.yaml rename to tests/components/bang_bang/test.rp2040-ard.yaml diff --git a/tests/components/bedjet/test.esp32-c3.yaml b/tests/components/bedjet/test.esp32-ard.yaml similarity index 100% rename from tests/components/bedjet/test.esp32-c3.yaml rename to tests/components/bedjet/test.esp32-ard.yaml diff --git a/tests/components/bedjet/test.esp32.yaml b/tests/components/bedjet/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bedjet/test.esp32.yaml rename to tests/components/bedjet/test.esp32-c3-ard.yaml diff --git a/tests/components/beken_spi_led_strip/test.bk72xx.yaml b/tests/components/beken_spi_led_strip/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/beken_spi_led_strip/test.bk72xx.yaml rename to tests/components/beken_spi_led_strip/test.bk72xx-ard.yaml diff --git a/tests/components/bh1750/test.esp32.yaml b/tests/components/bh1750/test.esp32-ard.yaml similarity index 100% rename from tests/components/bh1750/test.esp32.yaml rename to tests/components/bh1750/test.esp32-ard.yaml diff --git a/tests/components/bh1750/test.esp32-c3.yaml b/tests/components/bh1750/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bh1750/test.esp32-c3.yaml rename to tests/components/bh1750/test.esp32-c3-ard.yaml diff --git a/tests/components/bh1750/test.esp8266.yaml b/tests/components/bh1750/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bh1750/test.esp8266.yaml rename to tests/components/bh1750/test.esp8266-ard.yaml diff --git a/tests/components/bh1750/test.rp2040.yaml b/tests/components/bh1750/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bh1750/test.rp2040.yaml rename to tests/components/bh1750/test.rp2040-ard.yaml diff --git a/tests/components/binary_sensor_map/test.esp32-c3.yaml b/tests/components/binary_sensor_map/test.esp32-ard.yaml similarity index 100% rename from tests/components/binary_sensor_map/test.esp32-c3.yaml rename to tests/components/binary_sensor_map/test.esp32-ard.yaml diff --git a/tests/components/binary_sensor_map/test.esp32.yaml b/tests/components/binary_sensor_map/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/binary_sensor_map/test.esp32.yaml rename to tests/components/binary_sensor_map/test.esp32-c3-ard.yaml diff --git a/tests/components/binary_sensor_map/test.esp8266.yaml b/tests/components/binary_sensor_map/test.esp8266-ard.yaml similarity index 100% rename from tests/components/binary_sensor_map/test.esp8266.yaml rename to tests/components/binary_sensor_map/test.esp8266-ard.yaml diff --git a/tests/components/binary_sensor_map/test.rp2040.yaml b/tests/components/binary_sensor_map/test.rp2040-ard.yaml similarity index 100% rename from tests/components/binary_sensor_map/test.rp2040.yaml rename to tests/components/binary_sensor_map/test.rp2040-ard.yaml diff --git a/tests/components/bl0939/test.esp32.yaml b/tests/components/bl0939/test.esp32-ard.yaml similarity index 100% rename from tests/components/bl0939/test.esp32.yaml rename to tests/components/bl0939/test.esp32-ard.yaml diff --git a/tests/components/bl0939/test.esp32-c3.yaml b/tests/components/bl0939/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bl0939/test.esp32-c3.yaml rename to tests/components/bl0939/test.esp32-c3-ard.yaml diff --git a/tests/components/bl0939/test.esp8266.yaml b/tests/components/bl0939/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bl0939/test.esp8266.yaml rename to tests/components/bl0939/test.esp8266-ard.yaml diff --git a/tests/components/bl0939/test.rp2040.yaml b/tests/components/bl0939/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bl0939/test.rp2040.yaml rename to tests/components/bl0939/test.rp2040-ard.yaml diff --git a/tests/components/bl0940/test.esp32.yaml b/tests/components/bl0940/test.esp32-ard.yaml similarity index 100% rename from tests/components/bl0940/test.esp32.yaml rename to tests/components/bl0940/test.esp32-ard.yaml diff --git a/tests/components/bl0940/test.esp32-c3.yaml b/tests/components/bl0940/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bl0940/test.esp32-c3.yaml rename to tests/components/bl0940/test.esp32-c3-ard.yaml diff --git a/tests/components/bl0940/test.esp8266.yaml b/tests/components/bl0940/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bl0940/test.esp8266.yaml rename to tests/components/bl0940/test.esp8266-ard.yaml diff --git a/tests/components/bl0940/test.rp2040.yaml b/tests/components/bl0940/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bl0940/test.rp2040.yaml rename to tests/components/bl0940/test.rp2040-ard.yaml diff --git a/tests/components/bl0942/test.esp32.yaml b/tests/components/bl0942/test.esp32-ard.yaml similarity index 100% rename from tests/components/bl0942/test.esp32.yaml rename to tests/components/bl0942/test.esp32-ard.yaml diff --git a/tests/components/bl0942/test.esp32-c3.yaml b/tests/components/bl0942/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bl0942/test.esp32-c3.yaml rename to tests/components/bl0942/test.esp32-c3-ard.yaml diff --git a/tests/components/bl0942/test.esp8266.yaml b/tests/components/bl0942/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bl0942/test.esp8266.yaml rename to tests/components/bl0942/test.esp8266-ard.yaml diff --git a/tests/components/bl0942/test.rp2040.yaml b/tests/components/bl0942/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bl0942/test.rp2040.yaml rename to tests/components/bl0942/test.rp2040-ard.yaml diff --git a/tests/components/ble_client/test.esp32-c3.yaml b/tests/components/ble_client/test.esp32-ard.yaml similarity index 100% rename from tests/components/ble_client/test.esp32-c3.yaml rename to tests/components/ble_client/test.esp32-ard.yaml diff --git a/tests/components/ble_client/test.esp32.yaml b/tests/components/ble_client/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ble_client/test.esp32.yaml rename to tests/components/ble_client/test.esp32-c3-ard.yaml diff --git a/tests/components/ble_presence/test.esp32-c3.yaml b/tests/components/ble_presence/test.esp32-ard.yaml similarity index 100% rename from tests/components/ble_presence/test.esp32-c3.yaml rename to tests/components/ble_presence/test.esp32-ard.yaml diff --git a/tests/components/ble_presence/test.esp32.yaml b/tests/components/ble_presence/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ble_presence/test.esp32.yaml rename to tests/components/ble_presence/test.esp32-c3-ard.yaml diff --git a/tests/components/ble_rssi/test.esp32-c3.yaml b/tests/components/ble_rssi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ble_rssi/test.esp32-c3.yaml rename to tests/components/ble_rssi/test.esp32-ard.yaml diff --git a/tests/components/ble_rssi/test.esp32.yaml b/tests/components/ble_rssi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ble_rssi/test.esp32.yaml rename to tests/components/ble_rssi/test.esp32-c3-ard.yaml diff --git a/tests/components/ble_scanner/test.esp32-c3.yaml b/tests/components/ble_scanner/test.esp32-ard.yaml similarity index 100% rename from tests/components/ble_scanner/test.esp32-c3.yaml rename to tests/components/ble_scanner/test.esp32-ard.yaml diff --git a/tests/components/ble_scanner/test.esp32.yaml b/tests/components/ble_scanner/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ble_scanner/test.esp32.yaml rename to tests/components/ble_scanner/test.esp32-c3-ard.yaml diff --git a/tests/components/bme280_i2c/test.esp32.yaml b/tests/components/bme280_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/bme280_i2c/test.esp32.yaml rename to tests/components/bme280_i2c/test.esp32-ard.yaml diff --git a/tests/components/bme280_i2c/test.esp32-c3.yaml b/tests/components/bme280_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bme280_i2c/test.esp32-c3.yaml rename to tests/components/bme280_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/bme280_i2c/test.esp8266.yaml b/tests/components/bme280_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bme280_i2c/test.esp8266.yaml rename to tests/components/bme280_i2c/test.esp8266-ard.yaml diff --git a/tests/components/bme280_i2c/test.rp2040.yaml b/tests/components/bme280_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bme280_i2c/test.rp2040.yaml rename to tests/components/bme280_i2c/test.rp2040-ard.yaml diff --git a/tests/components/bme280_spi/test.esp32.yaml b/tests/components/bme280_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/bme280_spi/test.esp32.yaml rename to tests/components/bme280_spi/test.esp32-ard.yaml diff --git a/tests/components/bme280_spi/test.esp32-c3.yaml b/tests/components/bme280_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bme280_spi/test.esp32-c3.yaml rename to tests/components/bme280_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/bme280_spi/test.esp8266.yaml b/tests/components/bme280_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bme280_spi/test.esp8266.yaml rename to tests/components/bme280_spi/test.esp8266-ard.yaml diff --git a/tests/components/bme280_spi/test.rp2040.yaml b/tests/components/bme280_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bme280_spi/test.rp2040.yaml rename to tests/components/bme280_spi/test.rp2040-ard.yaml diff --git a/tests/components/bme680/test.esp32.yaml b/tests/components/bme680/test.esp32-ard.yaml similarity index 100% rename from tests/components/bme680/test.esp32.yaml rename to tests/components/bme680/test.esp32-ard.yaml diff --git a/tests/components/bme680/test.esp32-c3.yaml b/tests/components/bme680/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bme680/test.esp32-c3.yaml rename to tests/components/bme680/test.esp32-c3-ard.yaml diff --git a/tests/components/bme680/test.esp8266.yaml b/tests/components/bme680/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bme680/test.esp8266.yaml rename to tests/components/bme680/test.esp8266-ard.yaml diff --git a/tests/components/bme680/test.rp2040.yaml b/tests/components/bme680/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bme680/test.rp2040.yaml rename to tests/components/bme680/test.rp2040-ard.yaml diff --git a/tests/components/bme680_bsec/test.esp32.yaml b/tests/components/bme680_bsec/test.esp32-ard.yaml similarity index 100% rename from tests/components/bme680_bsec/test.esp32.yaml rename to tests/components/bme680_bsec/test.esp32-ard.yaml diff --git a/tests/components/bme680_bsec/test.esp8266.yaml b/tests/components/bme680_bsec/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bme680_bsec/test.esp8266.yaml rename to tests/components/bme680_bsec/test.esp8266-ard.yaml diff --git a/tests/components/bmi160/test.esp32.yaml b/tests/components/bmi160/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmi160/test.esp32.yaml rename to tests/components/bmi160/test.esp32-ard.yaml diff --git a/tests/components/bmi160/test.esp32-c3.yaml b/tests/components/bmi160/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmi160/test.esp32-c3.yaml rename to tests/components/bmi160/test.esp32-c3-ard.yaml diff --git a/tests/components/bmi160/test.esp8266.yaml b/tests/components/bmi160/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmi160/test.esp8266.yaml rename to tests/components/bmi160/test.esp8266-ard.yaml diff --git a/tests/components/bmi160/test.rp2040.yaml b/tests/components/bmi160/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmi160/test.rp2040.yaml rename to tests/components/bmi160/test.rp2040-ard.yaml diff --git a/tests/components/bmp085/test.esp32.yaml b/tests/components/bmp085/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmp085/test.esp32.yaml rename to tests/components/bmp085/test.esp32-ard.yaml diff --git a/tests/components/bmp085/test.esp32-c3.yaml b/tests/components/bmp085/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmp085/test.esp32-c3.yaml rename to tests/components/bmp085/test.esp32-c3-ard.yaml diff --git a/tests/components/bmp085/test.esp8266.yaml b/tests/components/bmp085/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmp085/test.esp8266.yaml rename to tests/components/bmp085/test.esp8266-ard.yaml diff --git a/tests/components/bmp085/test.rp2040.yaml b/tests/components/bmp085/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmp085/test.rp2040.yaml rename to tests/components/bmp085/test.rp2040-ard.yaml diff --git a/tests/components/bmp280/test.esp32.yaml b/tests/components/bmp280/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmp280/test.esp32.yaml rename to tests/components/bmp280/test.esp32-ard.yaml diff --git a/tests/components/bmp280/test.esp32-c3.yaml b/tests/components/bmp280/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmp280/test.esp32-c3.yaml rename to tests/components/bmp280/test.esp32-c3-ard.yaml diff --git a/tests/components/bmp280/test.esp8266.yaml b/tests/components/bmp280/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmp280/test.esp8266.yaml rename to tests/components/bmp280/test.esp8266-ard.yaml diff --git a/tests/components/bmp280/test.rp2040.yaml b/tests/components/bmp280/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmp280/test.rp2040.yaml rename to tests/components/bmp280/test.rp2040-ard.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp32.yaml b/tests/components/bmp3xx_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmp3xx_i2c/test.esp32.yaml rename to tests/components/bmp3xx_i2c/test.esp32-ard.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp32-c3.yaml b/tests/components/bmp3xx_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmp3xx_i2c/test.esp32-c3.yaml rename to tests/components/bmp3xx_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/bmp3xx_i2c/test.esp8266.yaml b/tests/components/bmp3xx_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmp3xx_i2c/test.esp8266.yaml rename to tests/components/bmp3xx_i2c/test.esp8266-ard.yaml diff --git a/tests/components/bmp3xx_i2c/test.rp2040.yaml b/tests/components/bmp3xx_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmp3xx_i2c/test.rp2040.yaml rename to tests/components/bmp3xx_i2c/test.rp2040-ard.yaml diff --git a/tests/components/bmp3xx_spi/test.esp32.yaml b/tests/components/bmp3xx_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmp3xx_spi/test.esp32.yaml rename to tests/components/bmp3xx_spi/test.esp32-ard.yaml diff --git a/tests/components/bmp3xx_spi/test.esp32-c3.yaml b/tests/components/bmp3xx_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmp3xx_spi/test.esp32-c3.yaml rename to tests/components/bmp3xx_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/bmp3xx_spi/test.esp8266.yaml b/tests/components/bmp3xx_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmp3xx_spi/test.esp8266.yaml rename to tests/components/bmp3xx_spi/test.esp8266-ard.yaml diff --git a/tests/components/bmp3xx_spi/test.rp2040.yaml b/tests/components/bmp3xx_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmp3xx_spi/test.rp2040.yaml rename to tests/components/bmp3xx_spi/test.rp2040-ard.yaml diff --git a/tests/components/bmp581/test.esp32.yaml b/tests/components/bmp581/test.esp32-ard.yaml similarity index 100% rename from tests/components/bmp581/test.esp32.yaml rename to tests/components/bmp581/test.esp32-ard.yaml diff --git a/tests/components/bmp581/test.esp32-c3.yaml b/tests/components/bmp581/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bmp581/test.esp32-c3.yaml rename to tests/components/bmp581/test.esp32-c3-ard.yaml diff --git a/tests/components/bmp581/test.esp8266.yaml b/tests/components/bmp581/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bmp581/test.esp8266.yaml rename to tests/components/bmp581/test.esp8266-ard.yaml diff --git a/tests/components/bmp581/test.rp2040.yaml b/tests/components/bmp581/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bmp581/test.rp2040.yaml rename to tests/components/bmp581/test.rp2040-ard.yaml diff --git a/tests/components/bp1658cj/test.esp32.yaml b/tests/components/bp1658cj/test.esp32-ard.yaml similarity index 100% rename from tests/components/bp1658cj/test.esp32.yaml rename to tests/components/bp1658cj/test.esp32-ard.yaml diff --git a/tests/components/bp1658cj/test.esp32-c3.yaml b/tests/components/bp1658cj/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bp1658cj/test.esp32-c3.yaml rename to tests/components/bp1658cj/test.esp32-c3-ard.yaml diff --git a/tests/components/bp1658cj/test.esp8266.yaml b/tests/components/bp1658cj/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bp1658cj/test.esp8266.yaml rename to tests/components/bp1658cj/test.esp8266-ard.yaml diff --git a/tests/components/bp1658cj/test.rp2040.yaml b/tests/components/bp1658cj/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bp1658cj/test.rp2040.yaml rename to tests/components/bp1658cj/test.rp2040-ard.yaml diff --git a/tests/components/bp5758d/test.esp32.yaml b/tests/components/bp5758d/test.esp32-ard.yaml similarity index 100% rename from tests/components/bp5758d/test.esp32.yaml rename to tests/components/bp5758d/test.esp32-ard.yaml diff --git a/tests/components/bp5758d/test.esp32-c3.yaml b/tests/components/bp5758d/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/bp5758d/test.esp32-c3.yaml rename to tests/components/bp5758d/test.esp32-c3-ard.yaml diff --git a/tests/components/bp5758d/test.esp8266.yaml b/tests/components/bp5758d/test.esp8266-ard.yaml similarity index 100% rename from tests/components/bp5758d/test.esp8266.yaml rename to tests/components/bp5758d/test.esp8266-ard.yaml diff --git a/tests/components/bp5758d/test.rp2040.yaml b/tests/components/bp5758d/test.rp2040-ard.yaml similarity index 100% rename from tests/components/bp5758d/test.rp2040.yaml rename to tests/components/bp5758d/test.rp2040-ard.yaml diff --git a/tests/components/button/test.esp32-c3.yaml b/tests/components/button/test.esp32-ard.yaml similarity index 100% rename from tests/components/button/test.esp32-c3.yaml rename to tests/components/button/test.esp32-ard.yaml diff --git a/tests/components/button/test.esp32.yaml b/tests/components/button/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/button/test.esp32.yaml rename to tests/components/button/test.esp32-c3-ard.yaml diff --git a/tests/components/button/test.esp8266.yaml b/tests/components/button/test.esp8266-ard.yaml similarity index 100% rename from tests/components/button/test.esp8266.yaml rename to tests/components/button/test.esp8266-ard.yaml diff --git a/tests/components/button/test.rp2040.yaml b/tests/components/button/test.rp2040-ard.yaml similarity index 100% rename from tests/components/button/test.rp2040.yaml rename to tests/components/button/test.rp2040-ard.yaml diff --git a/tests/components/canbus/test.esp32-c3.yaml b/tests/components/canbus/test.esp32-ard.yaml similarity index 100% rename from tests/components/canbus/test.esp32-c3.yaml rename to tests/components/canbus/test.esp32-ard.yaml diff --git a/tests/components/canbus/test.esp32.yaml b/tests/components/canbus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/canbus/test.esp32.yaml rename to tests/components/canbus/test.esp32-c3-ard.yaml diff --git a/tests/components/cap1188/test.esp32.yaml b/tests/components/cap1188/test.esp32-ard.yaml similarity index 100% rename from tests/components/cap1188/test.esp32.yaml rename to tests/components/cap1188/test.esp32-ard.yaml diff --git a/tests/components/cap1188/test.esp32-c3.yaml b/tests/components/cap1188/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cap1188/test.esp32-c3.yaml rename to tests/components/cap1188/test.esp32-c3-ard.yaml diff --git a/tests/components/cap1188/test.esp8266.yaml b/tests/components/cap1188/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cap1188/test.esp8266.yaml rename to tests/components/cap1188/test.esp8266-ard.yaml diff --git a/tests/components/cap1188/test.rp2040.yaml b/tests/components/cap1188/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cap1188/test.rp2040.yaml rename to tests/components/cap1188/test.rp2040-ard.yaml diff --git a/tests/components/captive_portal/test.esp32-c3.yaml b/tests/components/captive_portal/test.esp32-ard.yaml similarity index 100% rename from tests/components/captive_portal/test.esp32-c3.yaml rename to tests/components/captive_portal/test.esp32-ard.yaml diff --git a/tests/components/captive_portal/test.esp32.yaml b/tests/components/captive_portal/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/captive_portal/test.esp32.yaml rename to tests/components/captive_portal/test.esp32-c3-ard.yaml diff --git a/tests/components/captive_portal/test.esp8266.yaml b/tests/components/captive_portal/test.esp8266-ard.yaml similarity index 100% rename from tests/components/captive_portal/test.esp8266.yaml rename to tests/components/captive_portal/test.esp8266-ard.yaml diff --git a/tests/components/ccs811/test.esp32.yaml b/tests/components/ccs811/test.esp32-ard.yaml similarity index 100% rename from tests/components/ccs811/test.esp32.yaml rename to tests/components/ccs811/test.esp32-ard.yaml diff --git a/tests/components/ccs811/test.esp32-c3.yaml b/tests/components/ccs811/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ccs811/test.esp32-c3.yaml rename to tests/components/ccs811/test.esp32-c3-ard.yaml diff --git a/tests/components/ccs811/test.esp8266.yaml b/tests/components/ccs811/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ccs811/test.esp8266.yaml rename to tests/components/ccs811/test.esp8266-ard.yaml diff --git a/tests/components/ccs811/test.rp2040.yaml b/tests/components/ccs811/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ccs811/test.rp2040.yaml rename to tests/components/ccs811/test.rp2040-ard.yaml diff --git a/tests/components/cd74hc4067/test.esp32.yaml b/tests/components/cd74hc4067/test.esp32-ard.yaml similarity index 100% rename from tests/components/cd74hc4067/test.esp32.yaml rename to tests/components/cd74hc4067/test.esp32-ard.yaml diff --git a/tests/components/cd74hc4067/test.esp32-c3.yaml b/tests/components/cd74hc4067/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cd74hc4067/test.esp32-c3.yaml rename to tests/components/cd74hc4067/test.esp32-c3-ard.yaml diff --git a/tests/components/cd74hc4067/test.esp8266.yaml b/tests/components/cd74hc4067/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cd74hc4067/test.esp8266.yaml rename to tests/components/cd74hc4067/test.esp8266-ard.yaml diff --git a/tests/components/cd74hc4067/test.rp2040.yaml b/tests/components/cd74hc4067/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cd74hc4067/test.rp2040.yaml rename to tests/components/cd74hc4067/test.rp2040-ard.yaml diff --git a/tests/components/climate_ir_lg/test.esp32-c3.yaml b/tests/components/climate_ir_lg/test.esp32-ard.yaml similarity index 100% rename from tests/components/climate_ir_lg/test.esp32-c3.yaml rename to tests/components/climate_ir_lg/test.esp32-ard.yaml diff --git a/tests/components/climate_ir_lg/test.esp32.yaml b/tests/components/climate_ir_lg/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/climate_ir_lg/test.esp32.yaml rename to tests/components/climate_ir_lg/test.esp32-c3-ard.yaml diff --git a/tests/components/climate_ir_lg/test.esp8266.yaml b/tests/components/climate_ir_lg/test.esp8266-ard.yaml similarity index 100% rename from tests/components/climate_ir_lg/test.esp8266.yaml rename to tests/components/climate_ir_lg/test.esp8266-ard.yaml diff --git a/tests/components/color/test.esp32-c3.yaml b/tests/components/color/test.esp32-ard.yaml similarity index 100% rename from tests/components/color/test.esp32-c3.yaml rename to tests/components/color/test.esp32-ard.yaml diff --git a/tests/components/color/test.esp32.yaml b/tests/components/color/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/color/test.esp32.yaml rename to tests/components/color/test.esp32-c3-ard.yaml diff --git a/tests/components/color/test.esp8266.yaml b/tests/components/color/test.esp8266-ard.yaml similarity index 100% rename from tests/components/color/test.esp8266.yaml rename to tests/components/color/test.esp8266-ard.yaml diff --git a/tests/components/color/test.rp2040.yaml b/tests/components/color/test.rp2040-ard.yaml similarity index 100% rename from tests/components/color/test.rp2040.yaml rename to tests/components/color/test.rp2040-ard.yaml diff --git a/tests/components/color_temperature/test.esp32.yaml b/tests/components/color_temperature/test.esp32-ard.yaml similarity index 100% rename from tests/components/color_temperature/test.esp32.yaml rename to tests/components/color_temperature/test.esp32-ard.yaml diff --git a/tests/components/color_temperature/test.esp32-c3.yaml b/tests/components/color_temperature/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/color_temperature/test.esp32-c3.yaml rename to tests/components/color_temperature/test.esp32-c3-ard.yaml diff --git a/tests/components/color_temperature/test.esp8266.yaml b/tests/components/color_temperature/test.esp8266-ard.yaml similarity index 100% rename from tests/components/color_temperature/test.esp8266.yaml rename to tests/components/color_temperature/test.esp8266-ard.yaml diff --git a/tests/components/color_temperature/test.rp2040.yaml b/tests/components/color_temperature/test.rp2040-ard.yaml similarity index 100% rename from tests/components/color_temperature/test.rp2040.yaml rename to tests/components/color_temperature/test.rp2040-ard.yaml diff --git a/tests/components/combination/test.esp32-c3.yaml b/tests/components/combination/test.esp32-ard.yaml similarity index 100% rename from tests/components/combination/test.esp32-c3.yaml rename to tests/components/combination/test.esp32-ard.yaml diff --git a/tests/components/combination/test.esp32.yaml b/tests/components/combination/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/combination/test.esp32.yaml rename to tests/components/combination/test.esp32-c3-ard.yaml diff --git a/tests/components/combination/test.esp8266.yaml b/tests/components/combination/test.esp8266-ard.yaml similarity index 100% rename from tests/components/combination/test.esp8266.yaml rename to tests/components/combination/test.esp8266-ard.yaml diff --git a/tests/components/combination/test.rp2040.yaml b/tests/components/combination/test.rp2040-ard.yaml similarity index 100% rename from tests/components/combination/test.rp2040.yaml rename to tests/components/combination/test.rp2040-ard.yaml diff --git a/tests/components/coolix/test.esp32-c3.yaml b/tests/components/coolix/test.esp32-ard.yaml similarity index 100% rename from tests/components/coolix/test.esp32-c3.yaml rename to tests/components/coolix/test.esp32-ard.yaml diff --git a/tests/components/coolix/test.esp32.yaml b/tests/components/coolix/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/coolix/test.esp32.yaml rename to tests/components/coolix/test.esp32-c3-ard.yaml diff --git a/tests/components/coolix/test.esp8266.yaml b/tests/components/coolix/test.esp8266-ard.yaml similarity index 100% rename from tests/components/coolix/test.esp8266.yaml rename to tests/components/coolix/test.esp8266-ard.yaml diff --git a/tests/components/copy/test.esp32.yaml b/tests/components/copy/test.esp32-ard.yaml similarity index 100% rename from tests/components/copy/test.esp32.yaml rename to tests/components/copy/test.esp32-ard.yaml diff --git a/tests/components/copy/test.esp32-c3.yaml b/tests/components/copy/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/copy/test.esp32-c3.yaml rename to tests/components/copy/test.esp32-c3-ard.yaml diff --git a/tests/components/copy/test.esp8266.yaml b/tests/components/copy/test.esp8266-ard.yaml similarity index 100% rename from tests/components/copy/test.esp8266.yaml rename to tests/components/copy/test.esp8266-ard.yaml diff --git a/tests/components/copy/test.rp2040.yaml b/tests/components/copy/test.rp2040-ard.yaml similarity index 100% rename from tests/components/copy/test.rp2040.yaml rename to tests/components/copy/test.rp2040-ard.yaml diff --git a/tests/components/cs5460a/test.esp32.yaml b/tests/components/cs5460a/test.esp32-ard.yaml similarity index 100% rename from tests/components/cs5460a/test.esp32.yaml rename to tests/components/cs5460a/test.esp32-ard.yaml diff --git a/tests/components/cs5460a/test.esp32-c3.yaml b/tests/components/cs5460a/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cs5460a/test.esp32-c3.yaml rename to tests/components/cs5460a/test.esp32-c3-ard.yaml diff --git a/tests/components/cs5460a/test.esp8266.yaml b/tests/components/cs5460a/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cs5460a/test.esp8266.yaml rename to tests/components/cs5460a/test.esp8266-ard.yaml diff --git a/tests/components/cs5460a/test.rp2040.yaml b/tests/components/cs5460a/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cs5460a/test.rp2040.yaml rename to tests/components/cs5460a/test.rp2040-ard.yaml diff --git a/tests/components/cse7761/test.esp32.yaml b/tests/components/cse7761/test.esp32-ard.yaml similarity index 100% rename from tests/components/cse7761/test.esp32.yaml rename to tests/components/cse7761/test.esp32-ard.yaml diff --git a/tests/components/cse7761/test.esp32-c3.yaml b/tests/components/cse7761/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cse7761/test.esp32-c3.yaml rename to tests/components/cse7761/test.esp32-c3-ard.yaml diff --git a/tests/components/cse7761/test.esp8266.yaml b/tests/components/cse7761/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cse7761/test.esp8266.yaml rename to tests/components/cse7761/test.esp8266-ard.yaml diff --git a/tests/components/cse7761/test.rp2040.yaml b/tests/components/cse7761/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cse7761/test.rp2040.yaml rename to tests/components/cse7761/test.rp2040-ard.yaml diff --git a/tests/components/cse7766/test.esp32.yaml b/tests/components/cse7766/test.esp32-ard.yaml similarity index 100% rename from tests/components/cse7766/test.esp32.yaml rename to tests/components/cse7766/test.esp32-ard.yaml diff --git a/tests/components/cse7766/test.esp32-c3.yaml b/tests/components/cse7766/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cse7766/test.esp32-c3.yaml rename to tests/components/cse7766/test.esp32-c3-ard.yaml diff --git a/tests/components/cse7766/test.esp8266.yaml b/tests/components/cse7766/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cse7766/test.esp8266.yaml rename to tests/components/cse7766/test.esp8266-ard.yaml diff --git a/tests/components/cse7766/test.rp2040.yaml b/tests/components/cse7766/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cse7766/test.rp2040.yaml rename to tests/components/cse7766/test.rp2040-ard.yaml diff --git a/tests/components/cst226/test.esp32-c3.yaml b/tests/components/cst226/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cst226/test.esp32-c3.yaml rename to tests/components/cst226/test.esp32-c3-ard.yaml diff --git a/tests/components/cst816/test.esp32.yaml b/tests/components/cst816/test.esp32-ard.yaml similarity index 100% rename from tests/components/cst816/test.esp32.yaml rename to tests/components/cst816/test.esp32-ard.yaml diff --git a/tests/components/ct_clamp/test.esp32.yaml b/tests/components/ct_clamp/test.esp32-ard.yaml similarity index 100% rename from tests/components/ct_clamp/test.esp32.yaml rename to tests/components/ct_clamp/test.esp32-ard.yaml diff --git a/tests/components/ct_clamp/test.esp32-c3.yaml b/tests/components/ct_clamp/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ct_clamp/test.esp32-c3.yaml rename to tests/components/ct_clamp/test.esp32-c3-ard.yaml diff --git a/tests/components/ct_clamp/test.esp8266.yaml b/tests/components/ct_clamp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ct_clamp/test.esp8266.yaml rename to tests/components/ct_clamp/test.esp8266-ard.yaml diff --git a/tests/components/ct_clamp/test.rp2040.yaml b/tests/components/ct_clamp/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ct_clamp/test.rp2040.yaml rename to tests/components/ct_clamp/test.rp2040-ard.yaml diff --git a/tests/components/current_based/test.esp32.yaml b/tests/components/current_based/test.esp32-ard.yaml similarity index 100% rename from tests/components/current_based/test.esp32.yaml rename to tests/components/current_based/test.esp32-ard.yaml diff --git a/tests/components/current_based/test.esp32-c3.yaml b/tests/components/current_based/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/current_based/test.esp32-c3.yaml rename to tests/components/current_based/test.esp32-c3-ard.yaml diff --git a/tests/components/current_based/test.esp8266.yaml b/tests/components/current_based/test.esp8266-ard.yaml similarity index 100% rename from tests/components/current_based/test.esp8266.yaml rename to tests/components/current_based/test.esp8266-ard.yaml diff --git a/tests/components/current_based/test.rp2040.yaml b/tests/components/current_based/test.rp2040-ard.yaml similarity index 100% rename from tests/components/current_based/test.rp2040.yaml rename to tests/components/current_based/test.rp2040-ard.yaml diff --git a/tests/components/cwww/test.esp32.yaml b/tests/components/cwww/test.esp32-ard.yaml similarity index 100% rename from tests/components/cwww/test.esp32.yaml rename to tests/components/cwww/test.esp32-ard.yaml diff --git a/tests/components/cwww/test.esp32-c3.yaml b/tests/components/cwww/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/cwww/test.esp32-c3.yaml rename to tests/components/cwww/test.esp32-c3-ard.yaml diff --git a/tests/components/cwww/test.esp8266.yaml b/tests/components/cwww/test.esp8266-ard.yaml similarity index 100% rename from tests/components/cwww/test.esp8266.yaml rename to tests/components/cwww/test.esp8266-ard.yaml diff --git a/tests/components/cwww/test.rp2040.yaml b/tests/components/cwww/test.rp2040-ard.yaml similarity index 100% rename from tests/components/cwww/test.rp2040.yaml rename to tests/components/cwww/test.rp2040-ard.yaml diff --git a/tests/components/dac7678/test.esp32.yaml b/tests/components/dac7678/test.esp32-ard.yaml similarity index 100% rename from tests/components/dac7678/test.esp32.yaml rename to tests/components/dac7678/test.esp32-ard.yaml diff --git a/tests/components/dac7678/test.esp32-c3.yaml b/tests/components/dac7678/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dac7678/test.esp32-c3.yaml rename to tests/components/dac7678/test.esp32-c3-ard.yaml diff --git a/tests/components/dac7678/test.esp8266.yaml b/tests/components/dac7678/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dac7678/test.esp8266.yaml rename to tests/components/dac7678/test.esp8266-ard.yaml diff --git a/tests/components/dac7678/test.rp2040.yaml b/tests/components/dac7678/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dac7678/test.rp2040.yaml rename to tests/components/dac7678/test.rp2040-ard.yaml diff --git a/tests/components/daikin/test.esp32.yaml b/tests/components/daikin/test.esp32-ard.yaml similarity index 100% rename from tests/components/daikin/test.esp32.yaml rename to tests/components/daikin/test.esp32-ard.yaml diff --git a/tests/components/daikin/test.esp8266.yaml b/tests/components/daikin/test.esp8266-ard.yaml similarity index 100% rename from tests/components/daikin/test.esp8266.yaml rename to tests/components/daikin/test.esp8266-ard.yaml diff --git a/tests/components/daikin_arc/test.esp32.yaml b/tests/components/daikin_arc/test.esp32-ard.yaml similarity index 100% rename from tests/components/daikin_arc/test.esp32.yaml rename to tests/components/daikin_arc/test.esp32-ard.yaml diff --git a/tests/components/daikin_arc/test.esp8266.yaml b/tests/components/daikin_arc/test.esp8266-ard.yaml similarity index 100% rename from tests/components/daikin_arc/test.esp8266.yaml rename to tests/components/daikin_arc/test.esp8266-ard.yaml diff --git a/tests/components/daikin_brc/test.esp32-c3.yaml b/tests/components/daikin_brc/test.esp32-ard.yaml similarity index 100% rename from tests/components/daikin_brc/test.esp32-c3.yaml rename to tests/components/daikin_brc/test.esp32-ard.yaml diff --git a/tests/components/daikin_brc/test.esp32.yaml b/tests/components/daikin_brc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/daikin_brc/test.esp32.yaml rename to tests/components/daikin_brc/test.esp32-c3-ard.yaml diff --git a/tests/components/daikin_brc/test.esp8266.yaml b/tests/components/daikin_brc/test.esp8266-ard.yaml similarity index 100% rename from tests/components/daikin_brc/test.esp8266.yaml rename to tests/components/daikin_brc/test.esp8266-ard.yaml diff --git a/tests/components/dallas_temp/test.esp32-c3.yaml b/tests/components/dallas_temp/test.esp32-ard.yaml similarity index 100% rename from tests/components/dallas_temp/test.esp32-c3.yaml rename to tests/components/dallas_temp/test.esp32-ard.yaml diff --git a/tests/components/dallas_temp/test.esp32.yaml b/tests/components/dallas_temp/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dallas_temp/test.esp32.yaml rename to tests/components/dallas_temp/test.esp32-c3-ard.yaml diff --git a/tests/components/dallas_temp/test.esp8266.yaml b/tests/components/dallas_temp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dallas_temp/test.esp8266.yaml rename to tests/components/dallas_temp/test.esp8266-ard.yaml diff --git a/tests/components/dallas_temp/test.rp2040.yaml b/tests/components/dallas_temp/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dallas_temp/test.rp2040.yaml rename to tests/components/dallas_temp/test.rp2040-ard.yaml diff --git a/tests/components/daly_bms/test.esp32.yaml b/tests/components/daly_bms/test.esp32-ard.yaml similarity index 100% rename from tests/components/daly_bms/test.esp32.yaml rename to tests/components/daly_bms/test.esp32-ard.yaml diff --git a/tests/components/daly_bms/test.esp32-c3.yaml b/tests/components/daly_bms/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/daly_bms/test.esp32-c3.yaml rename to tests/components/daly_bms/test.esp32-c3-ard.yaml diff --git a/tests/components/daly_bms/test.esp8266.yaml b/tests/components/daly_bms/test.esp8266-ard.yaml similarity index 100% rename from tests/components/daly_bms/test.esp8266.yaml rename to tests/components/daly_bms/test.esp8266-ard.yaml diff --git a/tests/components/daly_bms/test.rp2040.yaml b/tests/components/daly_bms/test.rp2040-ard.yaml similarity index 100% rename from tests/components/daly_bms/test.rp2040.yaml rename to tests/components/daly_bms/test.rp2040-ard.yaml diff --git a/tests/components/debug/test.esp32-c3.yaml b/tests/components/debug/test.esp32-ard.yaml similarity index 100% rename from tests/components/debug/test.esp32-c3.yaml rename to tests/components/debug/test.esp32-ard.yaml diff --git a/tests/components/debug/test.esp32.yaml b/tests/components/debug/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/debug/test.esp32.yaml rename to tests/components/debug/test.esp32-c3-ard.yaml diff --git a/tests/components/debug/test.esp8266.yaml b/tests/components/debug/test.esp8266-ard.yaml similarity index 100% rename from tests/components/debug/test.esp8266.yaml rename to tests/components/debug/test.esp8266-ard.yaml diff --git a/tests/components/debug/test.rp2040.yaml b/tests/components/debug/test.rp2040-ard.yaml similarity index 100% rename from tests/components/debug/test.rp2040.yaml rename to tests/components/debug/test.rp2040-ard.yaml diff --git a/tests/components/deep_sleep/test.esp32-c3.yaml b/tests/components/deep_sleep/test.esp32-ard.yaml similarity index 100% rename from tests/components/deep_sleep/test.esp32-c3.yaml rename to tests/components/deep_sleep/test.esp32-ard.yaml diff --git a/tests/components/deep_sleep/test.esp32.yaml b/tests/components/deep_sleep/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/deep_sleep/test.esp32.yaml rename to tests/components/deep_sleep/test.esp32-c3-ard.yaml diff --git a/tests/components/deep_sleep/test.esp8266.yaml b/tests/components/deep_sleep/test.esp8266-ard.yaml similarity index 100% rename from tests/components/deep_sleep/test.esp8266.yaml rename to tests/components/deep_sleep/test.esp8266-ard.yaml diff --git a/tests/components/delonghi/test.esp32-c3.yaml b/tests/components/delonghi/test.esp32-ard.yaml similarity index 100% rename from tests/components/delonghi/test.esp32-c3.yaml rename to tests/components/delonghi/test.esp32-ard.yaml diff --git a/tests/components/delonghi/test.esp32.yaml b/tests/components/delonghi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/delonghi/test.esp32.yaml rename to tests/components/delonghi/test.esp32-c3-ard.yaml diff --git a/tests/components/delonghi/test.esp8266.yaml b/tests/components/delonghi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/delonghi/test.esp8266.yaml rename to tests/components/delonghi/test.esp8266-ard.yaml diff --git a/tests/components/dfplayer/test.esp32.yaml b/tests/components/dfplayer/test.esp32-ard.yaml similarity index 100% rename from tests/components/dfplayer/test.esp32.yaml rename to tests/components/dfplayer/test.esp32-ard.yaml diff --git a/tests/components/dfplayer/test.esp32-c3.yaml b/tests/components/dfplayer/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dfplayer/test.esp32-c3.yaml rename to tests/components/dfplayer/test.esp32-c3-ard.yaml diff --git a/tests/components/dfplayer/test.esp8266.yaml b/tests/components/dfplayer/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dfplayer/test.esp8266.yaml rename to tests/components/dfplayer/test.esp8266-ard.yaml diff --git a/tests/components/dfplayer/test.rp2040.yaml b/tests/components/dfplayer/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dfplayer/test.rp2040.yaml rename to tests/components/dfplayer/test.rp2040-ard.yaml diff --git a/tests/components/dfrobot_sen0395/test.esp32.yaml b/tests/components/dfrobot_sen0395/test.esp32-ard.yaml similarity index 100% rename from tests/components/dfrobot_sen0395/test.esp32.yaml rename to tests/components/dfrobot_sen0395/test.esp32-ard.yaml diff --git a/tests/components/dfrobot_sen0395/test.esp32-c3.yaml b/tests/components/dfrobot_sen0395/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dfrobot_sen0395/test.esp32-c3.yaml rename to tests/components/dfrobot_sen0395/test.esp32-c3-ard.yaml diff --git a/tests/components/dfrobot_sen0395/test.esp8266.yaml b/tests/components/dfrobot_sen0395/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dfrobot_sen0395/test.esp8266.yaml rename to tests/components/dfrobot_sen0395/test.esp8266-ard.yaml diff --git a/tests/components/dfrobot_sen0395/test.rp2040.yaml b/tests/components/dfrobot_sen0395/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dfrobot_sen0395/test.rp2040.yaml rename to tests/components/dfrobot_sen0395/test.rp2040-ard.yaml diff --git a/tests/components/dht/test.esp32-c3.yaml b/tests/components/dht/test.esp32-ard.yaml similarity index 100% rename from tests/components/dht/test.esp32-c3.yaml rename to tests/components/dht/test.esp32-ard.yaml diff --git a/tests/components/dht/test.esp32.yaml b/tests/components/dht/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dht/test.esp32.yaml rename to tests/components/dht/test.esp32-c3-ard.yaml diff --git a/tests/components/dht/test.esp8266.yaml b/tests/components/dht/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dht/test.esp8266.yaml rename to tests/components/dht/test.esp8266-ard.yaml diff --git a/tests/components/dht/test.rp2040.yaml b/tests/components/dht/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dht/test.rp2040.yaml rename to tests/components/dht/test.rp2040-ard.yaml diff --git a/tests/components/dht12/test.esp32.yaml b/tests/components/dht12/test.esp32-ard.yaml similarity index 100% rename from tests/components/dht12/test.esp32.yaml rename to tests/components/dht12/test.esp32-ard.yaml diff --git a/tests/components/dht12/test.esp32-c3.yaml b/tests/components/dht12/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dht12/test.esp32-c3.yaml rename to tests/components/dht12/test.esp32-c3-ard.yaml diff --git a/tests/components/dht12/test.esp8266.yaml b/tests/components/dht12/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dht12/test.esp8266.yaml rename to tests/components/dht12/test.esp8266-ard.yaml diff --git a/tests/components/dht12/test.rp2040.yaml b/tests/components/dht12/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dht12/test.rp2040.yaml rename to tests/components/dht12/test.rp2040-ard.yaml diff --git a/tests/components/display/test.esp32.yaml b/tests/components/display/test.esp32-ard.yaml similarity index 100% rename from tests/components/display/test.esp32.yaml rename to tests/components/display/test.esp32-ard.yaml diff --git a/tests/components/dps310/test.esp32.yaml b/tests/components/dps310/test.esp32-ard.yaml similarity index 100% rename from tests/components/dps310/test.esp32.yaml rename to tests/components/dps310/test.esp32-ard.yaml diff --git a/tests/components/dps310/test.esp32-c3.yaml b/tests/components/dps310/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dps310/test.esp32-c3.yaml rename to tests/components/dps310/test.esp32-c3-ard.yaml diff --git a/tests/components/dps310/test.esp8266.yaml b/tests/components/dps310/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dps310/test.esp8266.yaml rename to tests/components/dps310/test.esp8266-ard.yaml diff --git a/tests/components/dps310/test.rp2040.yaml b/tests/components/dps310/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dps310/test.rp2040.yaml rename to tests/components/dps310/test.rp2040-ard.yaml diff --git a/tests/components/ds1307/test.esp32.yaml b/tests/components/ds1307/test.esp32-ard.yaml similarity index 100% rename from tests/components/ds1307/test.esp32.yaml rename to tests/components/ds1307/test.esp32-ard.yaml diff --git a/tests/components/ds1307/test.esp32-c3.yaml b/tests/components/ds1307/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ds1307/test.esp32-c3.yaml rename to tests/components/ds1307/test.esp32-c3-ard.yaml diff --git a/tests/components/ds1307/test.esp8266.yaml b/tests/components/ds1307/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ds1307/test.esp8266.yaml rename to tests/components/ds1307/test.esp8266-ard.yaml diff --git a/tests/components/ds1307/test.rp2040.yaml b/tests/components/ds1307/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ds1307/test.rp2040.yaml rename to tests/components/ds1307/test.rp2040-ard.yaml diff --git a/tests/components/dsmr/test.esp32.yaml b/tests/components/dsmr/test.esp32-ard.yaml similarity index 100% rename from tests/components/dsmr/test.esp32.yaml rename to tests/components/dsmr/test.esp32-ard.yaml diff --git a/tests/components/dsmr/test.esp32-c3.yaml b/tests/components/dsmr/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/dsmr/test.esp32-c3.yaml rename to tests/components/dsmr/test.esp32-c3-ard.yaml diff --git a/tests/components/dsmr/test.esp8266.yaml b/tests/components/dsmr/test.esp8266-ard.yaml similarity index 100% rename from tests/components/dsmr/test.esp8266.yaml rename to tests/components/dsmr/test.esp8266-ard.yaml diff --git a/tests/components/dsmr/test.rp2040.yaml b/tests/components/dsmr/test.rp2040-ard.yaml similarity index 100% rename from tests/components/dsmr/test.rp2040.yaml rename to tests/components/dsmr/test.rp2040-ard.yaml diff --git a/tests/components/duty_cycle/test.esp32-c3.yaml b/tests/components/duty_cycle/test.esp32-ard.yaml similarity index 100% rename from tests/components/duty_cycle/test.esp32-c3.yaml rename to tests/components/duty_cycle/test.esp32-ard.yaml diff --git a/tests/components/duty_cycle/test.esp32.yaml b/tests/components/duty_cycle/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/duty_cycle/test.esp32.yaml rename to tests/components/duty_cycle/test.esp32-c3-ard.yaml diff --git a/tests/components/duty_cycle/test.esp8266.yaml b/tests/components/duty_cycle/test.esp8266-ard.yaml similarity index 100% rename from tests/components/duty_cycle/test.esp8266.yaml rename to tests/components/duty_cycle/test.esp8266-ard.yaml diff --git a/tests/components/duty_cycle/test.rp2040.yaml b/tests/components/duty_cycle/test.rp2040-ard.yaml similarity index 100% rename from tests/components/duty_cycle/test.rp2040.yaml rename to tests/components/duty_cycle/test.rp2040-ard.yaml diff --git a/tests/components/duty_time/test.esp32-c3.yaml b/tests/components/duty_time/test.esp32-ard.yaml similarity index 100% rename from tests/components/duty_time/test.esp32-c3.yaml rename to tests/components/duty_time/test.esp32-ard.yaml diff --git a/tests/components/duty_time/test.esp32.yaml b/tests/components/duty_time/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/duty_time/test.esp32.yaml rename to tests/components/duty_time/test.esp32-c3-ard.yaml diff --git a/tests/components/duty_time/test.esp8266.yaml b/tests/components/duty_time/test.esp8266-ard.yaml similarity index 100% rename from tests/components/duty_time/test.esp8266.yaml rename to tests/components/duty_time/test.esp8266-ard.yaml diff --git a/tests/components/duty_time/test.rp2040.yaml b/tests/components/duty_time/test.rp2040-ard.yaml similarity index 100% rename from tests/components/duty_time/test.rp2040.yaml rename to tests/components/duty_time/test.rp2040-ard.yaml diff --git a/tests/components/e131/test.esp32-c3.yaml b/tests/components/e131/test.esp32-ard.yaml similarity index 100% rename from tests/components/e131/test.esp32-c3.yaml rename to tests/components/e131/test.esp32-ard.yaml diff --git a/tests/components/e131/test.esp32.yaml b/tests/components/e131/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/e131/test.esp32.yaml rename to tests/components/e131/test.esp32-c3-ard.yaml diff --git a/tests/components/e131/test.esp8266.yaml b/tests/components/e131/test.esp8266-ard.yaml similarity index 100% rename from tests/components/e131/test.esp8266.yaml rename to tests/components/e131/test.esp8266-ard.yaml diff --git a/tests/components/e131/test.rp2040.yaml b/tests/components/e131/test.rp2040-ard.yaml similarity index 100% rename from tests/components/e131/test.rp2040.yaml rename to tests/components/e131/test.rp2040-ard.yaml diff --git a/tests/components/ee895/test.esp32.yaml b/tests/components/ee895/test.esp32-ard.yaml similarity index 100% rename from tests/components/ee895/test.esp32.yaml rename to tests/components/ee895/test.esp32-ard.yaml diff --git a/tests/components/ee895/test.esp32-c3.yaml b/tests/components/ee895/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ee895/test.esp32-c3.yaml rename to tests/components/ee895/test.esp32-c3-ard.yaml diff --git a/tests/components/ee895/test.esp8266.yaml b/tests/components/ee895/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ee895/test.esp8266.yaml rename to tests/components/ee895/test.esp8266-ard.yaml diff --git a/tests/components/ee895/test.rp2040.yaml b/tests/components/ee895/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ee895/test.rp2040.yaml rename to tests/components/ee895/test.rp2040-ard.yaml diff --git a/tests/components/ektf2232/test.esp32.yaml b/tests/components/ektf2232/test.esp32-ard.yaml similarity index 100% rename from tests/components/ektf2232/test.esp32.yaml rename to tests/components/ektf2232/test.esp32-ard.yaml diff --git a/tests/components/ektf2232/test.esp32-c3.yaml b/tests/components/ektf2232/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ektf2232/test.esp32-c3.yaml rename to tests/components/ektf2232/test.esp32-c3-ard.yaml diff --git a/tests/components/ektf2232/test.esp8266.yaml b/tests/components/ektf2232/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ektf2232/test.esp8266.yaml rename to tests/components/ektf2232/test.esp8266-ard.yaml diff --git a/tests/components/ektf2232/test.rp2040.yaml b/tests/components/ektf2232/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ektf2232/test.rp2040.yaml rename to tests/components/ektf2232/test.rp2040-ard.yaml diff --git a/tests/components/emc2101/test.esp32.yaml b/tests/components/emc2101/test.esp32-ard.yaml similarity index 100% rename from tests/components/emc2101/test.esp32.yaml rename to tests/components/emc2101/test.esp32-ard.yaml diff --git a/tests/components/emc2101/test.esp32-c3.yaml b/tests/components/emc2101/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/emc2101/test.esp32-c3.yaml rename to tests/components/emc2101/test.esp32-c3-ard.yaml diff --git a/tests/components/emc2101/test.esp8266.yaml b/tests/components/emc2101/test.esp8266-ard.yaml similarity index 100% rename from tests/components/emc2101/test.esp8266.yaml rename to tests/components/emc2101/test.esp8266-ard.yaml diff --git a/tests/components/emc2101/test.rp2040.yaml b/tests/components/emc2101/test.rp2040-ard.yaml similarity index 100% rename from tests/components/emc2101/test.rp2040.yaml rename to tests/components/emc2101/test.rp2040-ard.yaml diff --git a/tests/components/emmeti/test.esp32.yaml b/tests/components/emmeti/test.esp32-ard.yaml similarity index 100% rename from tests/components/emmeti/test.esp32.yaml rename to tests/components/emmeti/test.esp32-ard.yaml diff --git a/tests/components/emmeti/test.esp8266.yaml b/tests/components/emmeti/test.esp8266-ard.yaml similarity index 100% rename from tests/components/emmeti/test.esp8266.yaml rename to tests/components/emmeti/test.esp8266-ard.yaml diff --git a/tests/components/endstop/test.esp32-c3.yaml b/tests/components/endstop/test.esp32-ard.yaml similarity index 100% rename from tests/components/endstop/test.esp32-c3.yaml rename to tests/components/endstop/test.esp32-ard.yaml diff --git a/tests/components/endstop/test.esp32.yaml b/tests/components/endstop/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/endstop/test.esp32.yaml rename to tests/components/endstop/test.esp32-c3-ard.yaml diff --git a/tests/components/endstop/test.esp8266.yaml b/tests/components/endstop/test.esp8266-ard.yaml similarity index 100% rename from tests/components/endstop/test.esp8266.yaml rename to tests/components/endstop/test.esp8266-ard.yaml diff --git a/tests/components/endstop/test.rp2040.yaml b/tests/components/endstop/test.rp2040-ard.yaml similarity index 100% rename from tests/components/endstop/test.rp2040.yaml rename to tests/components/endstop/test.rp2040-ard.yaml diff --git a/tests/components/ens160_i2c/test.esp32.yaml b/tests/components/ens160_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/ens160_i2c/test.esp32.yaml rename to tests/components/ens160_i2c/test.esp32-ard.yaml diff --git a/tests/components/ens160_i2c/test.esp32-c3.yaml b/tests/components/ens160_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ens160_i2c/test.esp32-c3.yaml rename to tests/components/ens160_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/ens160_i2c/test.esp8266.yaml b/tests/components/ens160_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ens160_i2c/test.esp8266.yaml rename to tests/components/ens160_i2c/test.esp8266-ard.yaml diff --git a/tests/components/ens160_i2c/test.rp2040.yaml b/tests/components/ens160_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ens160_i2c/test.rp2040.yaml rename to tests/components/ens160_i2c/test.rp2040-ard.yaml diff --git a/tests/components/ens160_spi/test.esp32.yaml b/tests/components/ens160_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ens160_spi/test.esp32.yaml rename to tests/components/ens160_spi/test.esp32-ard.yaml diff --git a/tests/components/ens160_spi/test.esp32-c3.yaml b/tests/components/ens160_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ens160_spi/test.esp32-c3.yaml rename to tests/components/ens160_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ens160_spi/test.esp8266.yaml b/tests/components/ens160_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ens160_spi/test.esp8266.yaml rename to tests/components/ens160_spi/test.esp8266-ard.yaml diff --git a/tests/components/ens160_spi/test.rp2040.yaml b/tests/components/ens160_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ens160_spi/test.rp2040.yaml rename to tests/components/ens160_spi/test.rp2040-ard.yaml diff --git a/tests/components/ens210/test.esp32.yaml b/tests/components/ens210/test.esp32-ard.yaml similarity index 100% rename from tests/components/ens210/test.esp32.yaml rename to tests/components/ens210/test.esp32-ard.yaml diff --git a/tests/components/ens210/test.esp32-c3.yaml b/tests/components/ens210/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ens210/test.esp32-c3.yaml rename to tests/components/ens210/test.esp32-c3-ard.yaml diff --git a/tests/components/ens210/test.esp8266.yaml b/tests/components/ens210/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ens210/test.esp8266.yaml rename to tests/components/ens210/test.esp8266-ard.yaml diff --git a/tests/components/ens210/test.rp2040.yaml b/tests/components/ens210/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ens210/test.rp2040.yaml rename to tests/components/ens210/test.rp2040-ard.yaml diff --git a/tests/components/esp32_ble/test.esp32-c3.yaml b/tests/components/esp32_ble/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_ble/test.esp32-c3.yaml rename to tests/components/esp32_ble/test.esp32-ard.yaml diff --git a/tests/components/esp32_ble/test.esp32.yaml b/tests/components/esp32_ble/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_ble/test.esp32.yaml rename to tests/components/esp32_ble/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_ble_beacon/test.esp32-c3.yaml b/tests/components/esp32_ble_beacon/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_ble_beacon/test.esp32-c3.yaml rename to tests/components/esp32_ble_beacon/test.esp32-ard.yaml diff --git a/tests/components/esp32_ble_beacon/test.esp32.yaml b/tests/components/esp32_ble_beacon/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_ble_beacon/test.esp32.yaml rename to tests/components/esp32_ble_beacon/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_ble_client/test.esp32-c3.yaml b/tests/components/esp32_ble_client/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_ble_client/test.esp32-c3.yaml rename to tests/components/esp32_ble_client/test.esp32-ard.yaml diff --git a/tests/components/esp32_ble_client/test.esp32.yaml b/tests/components/esp32_ble_client/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_ble_client/test.esp32.yaml rename to tests/components/esp32_ble_client/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_ble_server/test.esp32-c3.yaml b/tests/components/esp32_ble_server/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_ble_server/test.esp32-c3.yaml rename to tests/components/esp32_ble_server/test.esp32-ard.yaml diff --git a/tests/components/esp32_ble_server/test.esp32.yaml b/tests/components/esp32_ble_server/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_ble_server/test.esp32.yaml rename to tests/components/esp32_ble_server/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_ble_tracker/test.esp32-c3.yaml b/tests/components/esp32_ble_tracker/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_ble_tracker/test.esp32-c3.yaml rename to tests/components/esp32_ble_tracker/test.esp32-ard.yaml diff --git a/tests/components/esp32_ble_tracker/test.esp32.yaml b/tests/components/esp32_ble_tracker/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_ble_tracker/test.esp32.yaml rename to tests/components/esp32_ble_tracker/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_camera/test.esp32.yaml b/tests/components/esp32_camera/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_camera/test.esp32.yaml rename to tests/components/esp32_camera/test.esp32-ard.yaml diff --git a/tests/components/esp32_camera_web_server/test.esp32.yaml b/tests/components/esp32_camera_web_server/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_camera_web_server/test.esp32.yaml rename to tests/components/esp32_camera_web_server/test.esp32-ard.yaml diff --git a/tests/components/esp32_can/test.esp32.yaml b/tests/components/esp32_can/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_can/test.esp32.yaml rename to tests/components/esp32_can/test.esp32-ard.yaml diff --git a/tests/components/esp32_can/test.esp32-c3.yaml b/tests/components/esp32_can/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_can/test.esp32-c3.yaml rename to tests/components/esp32_can/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_dac/test.esp32.yaml b/tests/components/esp32_dac/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_dac/test.esp32.yaml rename to tests/components/esp32_dac/test.esp32-ard.yaml diff --git a/tests/components/esp32_hall/test.esp32.yaml b/tests/components/esp32_hall/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_hall/test.esp32.yaml rename to tests/components/esp32_hall/test.esp32-ard.yaml diff --git a/tests/components/esp32_improv/test.esp32-c3.yaml b/tests/components/esp32_improv/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_improv/test.esp32-c3.yaml rename to tests/components/esp32_improv/test.esp32-ard.yaml diff --git a/tests/components/esp32_improv/test.esp32.yaml b/tests/components/esp32_improv/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_improv/test.esp32.yaml rename to tests/components/esp32_improv/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_rmt_led_strip/test.esp32.yaml rename to tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/esp32_rmt_led_strip/test.esp32-c3.yaml rename to tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml diff --git a/tests/components/esp32_touch/test.esp32.yaml b/tests/components/esp32_touch/test.esp32-ard.yaml similarity index 100% rename from tests/components/esp32_touch/test.esp32.yaml rename to tests/components/esp32_touch/test.esp32-ard.yaml diff --git a/tests/components/esp8266_pwm/test.esp8266.yaml b/tests/components/esp8266_pwm/test.esp8266-ard.yaml similarity index 100% rename from tests/components/esp8266_pwm/test.esp8266.yaml rename to tests/components/esp8266_pwm/test.esp8266-ard.yaml diff --git a/tests/components/ethernet/test-dp83848.esp32.yaml b/tests/components/ethernet/test-dp83848.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-dp83848.esp32.yaml rename to tests/components/ethernet/test-dp83848.esp32-ard.yaml diff --git a/tests/components/ethernet/test-ip101.esp32.yaml b/tests/components/ethernet/test-ip101.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-ip101.esp32.yaml rename to tests/components/ethernet/test-ip101.esp32-ard.yaml diff --git a/tests/components/ethernet/test-jl1101.esp32.yaml b/tests/components/ethernet/test-jl1101.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-jl1101.esp32.yaml rename to tests/components/ethernet/test-jl1101.esp32-ard.yaml diff --git a/tests/components/ethernet/test-ksz8081.esp32.yaml b/tests/components/ethernet/test-ksz8081.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-ksz8081.esp32.yaml rename to tests/components/ethernet/test-ksz8081.esp32-ard.yaml diff --git a/tests/components/ethernet/test-ksz8081rna.esp32.yaml b/tests/components/ethernet/test-ksz8081rna.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-ksz8081rna.esp32.yaml rename to tests/components/ethernet/test-ksz8081rna.esp32-ard.yaml diff --git a/tests/components/ethernet/test-lan8720.esp32.yaml b/tests/components/ethernet/test-lan8720.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-lan8720.esp32.yaml rename to tests/components/ethernet/test-lan8720.esp32-ard.yaml diff --git a/tests/components/ethernet/test-rtl8201.esp32.yaml b/tests/components/ethernet/test-rtl8201.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-rtl8201.esp32.yaml rename to tests/components/ethernet/test-rtl8201.esp32-ard.yaml diff --git a/tests/components/ethernet/test-w5500.esp32.yaml b/tests/components/ethernet/test-w5500.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet/test-w5500.esp32.yaml rename to tests/components/ethernet/test-w5500.esp32-ard.yaml diff --git a/tests/components/ethernet_info/test.esp32.yaml b/tests/components/ethernet_info/test.esp32-ard.yaml similarity index 100% rename from tests/components/ethernet_info/test.esp32.yaml rename to tests/components/ethernet_info/test.esp32-ard.yaml diff --git a/tests/components/event/test.esp32-c3.yaml b/tests/components/event/test.esp32-ard.yaml similarity index 100% rename from tests/components/event/test.esp32-c3.yaml rename to tests/components/event/test.esp32-ard.yaml diff --git a/tests/components/event/test.esp32.yaml b/tests/components/event/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/event/test.esp32.yaml rename to tests/components/event/test.esp32-c3-ard.yaml diff --git a/tests/components/event/test.esp8266.yaml b/tests/components/event/test.esp8266-ard.yaml similarity index 100% rename from tests/components/event/test.esp8266.yaml rename to tests/components/event/test.esp8266-ard.yaml diff --git a/tests/components/event/test.rp2040.yaml b/tests/components/event/test.rp2040-ard.yaml similarity index 100% rename from tests/components/event/test.rp2040.yaml rename to tests/components/event/test.rp2040-ard.yaml diff --git a/tests/components/exposure_notifications/test.esp32-c3.yaml b/tests/components/exposure_notifications/test.esp32-ard.yaml similarity index 100% rename from tests/components/exposure_notifications/test.esp32-c3.yaml rename to tests/components/exposure_notifications/test.esp32-ard.yaml diff --git a/tests/components/exposure_notifications/test.esp32.yaml b/tests/components/exposure_notifications/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/exposure_notifications/test.esp32.yaml rename to tests/components/exposure_notifications/test.esp32-c3-ard.yaml diff --git a/tests/components/external_components/test.esp32-c3.yaml b/tests/components/external_components/test.esp32-ard.yaml similarity index 100% rename from tests/components/external_components/test.esp32-c3.yaml rename to tests/components/external_components/test.esp32-ard.yaml diff --git a/tests/components/external_components/test.esp32.yaml b/tests/components/external_components/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/external_components/test.esp32.yaml rename to tests/components/external_components/test.esp32-c3-ard.yaml diff --git a/tests/components/external_components/test.esp8266.yaml b/tests/components/external_components/test.esp8266-ard.yaml similarity index 100% rename from tests/components/external_components/test.esp8266.yaml rename to tests/components/external_components/test.esp8266-ard.yaml diff --git a/tests/components/external_components/test.rp2040.yaml b/tests/components/external_components/test.rp2040-ard.yaml similarity index 100% rename from tests/components/external_components/test.rp2040.yaml rename to tests/components/external_components/test.rp2040-ard.yaml diff --git a/tests/components/ezo/test.esp32.yaml b/tests/components/ezo/test.esp32-ard.yaml similarity index 100% rename from tests/components/ezo/test.esp32.yaml rename to tests/components/ezo/test.esp32-ard.yaml diff --git a/tests/components/ezo/test.esp32-c3.yaml b/tests/components/ezo/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ezo/test.esp32-c3.yaml rename to tests/components/ezo/test.esp32-c3-ard.yaml diff --git a/tests/components/ezo/test.esp8266.yaml b/tests/components/ezo/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ezo/test.esp8266.yaml rename to tests/components/ezo/test.esp8266-ard.yaml diff --git a/tests/components/ezo/test.rp2040.yaml b/tests/components/ezo/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ezo/test.rp2040.yaml rename to tests/components/ezo/test.rp2040-ard.yaml diff --git a/tests/components/ezo_pmp/test.esp32.yaml b/tests/components/ezo_pmp/test.esp32-ard.yaml similarity index 100% rename from tests/components/ezo_pmp/test.esp32.yaml rename to tests/components/ezo_pmp/test.esp32-ard.yaml diff --git a/tests/components/ezo_pmp/test.esp32-c3.yaml b/tests/components/ezo_pmp/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ezo_pmp/test.esp32-c3.yaml rename to tests/components/ezo_pmp/test.esp32-c3-ard.yaml diff --git a/tests/components/ezo_pmp/test.esp8266.yaml b/tests/components/ezo_pmp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ezo_pmp/test.esp8266.yaml rename to tests/components/ezo_pmp/test.esp8266-ard.yaml diff --git a/tests/components/ezo_pmp/test.rp2040.yaml b/tests/components/ezo_pmp/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ezo_pmp/test.rp2040.yaml rename to tests/components/ezo_pmp/test.rp2040-ard.yaml diff --git a/tests/components/factory_reset/test.esp32-c3.yaml b/tests/components/factory_reset/test.esp32-ard.yaml similarity index 100% rename from tests/components/factory_reset/test.esp32-c3.yaml rename to tests/components/factory_reset/test.esp32-ard.yaml diff --git a/tests/components/factory_reset/test.esp32.yaml b/tests/components/factory_reset/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/factory_reset/test.esp32.yaml rename to tests/components/factory_reset/test.esp32-c3-ard.yaml diff --git a/tests/components/factory_reset/test.esp8266.yaml b/tests/components/factory_reset/test.esp8266-ard.yaml similarity index 100% rename from tests/components/factory_reset/test.esp8266.yaml rename to tests/components/factory_reset/test.esp8266-ard.yaml diff --git a/tests/components/factory_reset/test.rp2040.yaml b/tests/components/factory_reset/test.rp2040-ard.yaml similarity index 100% rename from tests/components/factory_reset/test.rp2040.yaml rename to tests/components/factory_reset/test.rp2040-ard.yaml diff --git a/tests/components/fastled_clockless/test.esp32.yaml b/tests/components/fastled_clockless/test.esp32-ard.yaml similarity index 100% rename from tests/components/fastled_clockless/test.esp32.yaml rename to tests/components/fastled_clockless/test.esp32-ard.yaml diff --git a/tests/components/fastled_spi/test.esp32.yaml b/tests/components/fastled_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/fastled_spi/test.esp32.yaml rename to tests/components/fastled_spi/test.esp32-ard.yaml diff --git a/tests/components/feedback/test.esp32-c3.yaml b/tests/components/feedback/test.esp32-ard.yaml similarity index 100% rename from tests/components/feedback/test.esp32-c3.yaml rename to tests/components/feedback/test.esp32-ard.yaml diff --git a/tests/components/feedback/test.esp32.yaml b/tests/components/feedback/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/feedback/test.esp32.yaml rename to tests/components/feedback/test.esp32-c3-ard.yaml diff --git a/tests/components/feedback/test.esp8266.yaml b/tests/components/feedback/test.esp8266-ard.yaml similarity index 100% rename from tests/components/feedback/test.esp8266.yaml rename to tests/components/feedback/test.esp8266-ard.yaml diff --git a/tests/components/feedback/test.rp2040.yaml b/tests/components/feedback/test.rp2040-ard.yaml similarity index 100% rename from tests/components/feedback/test.rp2040.yaml rename to tests/components/feedback/test.rp2040-ard.yaml diff --git a/tests/components/fingerprint_grow/test.esp32.yaml b/tests/components/fingerprint_grow/test.esp32-ard.yaml similarity index 100% rename from tests/components/fingerprint_grow/test.esp32.yaml rename to tests/components/fingerprint_grow/test.esp32-ard.yaml diff --git a/tests/components/fingerprint_grow/test.esp32-c3.yaml b/tests/components/fingerprint_grow/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/fingerprint_grow/test.esp32-c3.yaml rename to tests/components/fingerprint_grow/test.esp32-c3-ard.yaml diff --git a/tests/components/fingerprint_grow/test.esp8266.yaml b/tests/components/fingerprint_grow/test.esp8266-ard.yaml similarity index 100% rename from tests/components/fingerprint_grow/test.esp8266.yaml rename to tests/components/fingerprint_grow/test.esp8266-ard.yaml diff --git a/tests/components/fingerprint_grow/test.rp2040.yaml b/tests/components/fingerprint_grow/test.rp2040-ard.yaml similarity index 100% rename from tests/components/fingerprint_grow/test.rp2040.yaml rename to tests/components/fingerprint_grow/test.rp2040-ard.yaml diff --git a/tests/components/font/test.esp32.yaml b/tests/components/font/test.esp32-ard.yaml similarity index 100% rename from tests/components/font/test.esp32.yaml rename to tests/components/font/test.esp32-ard.yaml diff --git a/tests/components/font/test.esp32-c3.yaml b/tests/components/font/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/font/test.esp32-c3.yaml rename to tests/components/font/test.esp32-c3-ard.yaml diff --git a/tests/components/font/test.esp8266.yaml b/tests/components/font/test.esp8266-ard.yaml similarity index 100% rename from tests/components/font/test.esp8266.yaml rename to tests/components/font/test.esp8266-ard.yaml diff --git a/tests/components/font/test.rp2040.yaml b/tests/components/font/test.rp2040-ard.yaml similarity index 100% rename from tests/components/font/test.rp2040.yaml rename to tests/components/font/test.rp2040-ard.yaml diff --git a/tests/components/fs3000/test.esp32.yaml b/tests/components/fs3000/test.esp32-ard.yaml similarity index 100% rename from tests/components/fs3000/test.esp32.yaml rename to tests/components/fs3000/test.esp32-ard.yaml diff --git a/tests/components/fs3000/test.esp32-c3.yaml b/tests/components/fs3000/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/fs3000/test.esp32-c3.yaml rename to tests/components/fs3000/test.esp32-c3-ard.yaml diff --git a/tests/components/fs3000/test.esp8266.yaml b/tests/components/fs3000/test.esp8266-ard.yaml similarity index 100% rename from tests/components/fs3000/test.esp8266.yaml rename to tests/components/fs3000/test.esp8266-ard.yaml diff --git a/tests/components/fs3000/test.rp2040.yaml b/tests/components/fs3000/test.rp2040-ard.yaml similarity index 100% rename from tests/components/fs3000/test.rp2040.yaml rename to tests/components/fs3000/test.rp2040-ard.yaml diff --git a/tests/components/ft5x06/test.esp32.yaml b/tests/components/ft5x06/test.esp32-ard.yaml similarity index 100% rename from tests/components/ft5x06/test.esp32.yaml rename to tests/components/ft5x06/test.esp32-ard.yaml diff --git a/tests/components/ft5x06/test.esp32-c3.yaml b/tests/components/ft5x06/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ft5x06/test.esp32-c3.yaml rename to tests/components/ft5x06/test.esp32-c3-ard.yaml diff --git a/tests/components/ft5x06/test.esp8266.yaml b/tests/components/ft5x06/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ft5x06/test.esp8266.yaml rename to tests/components/ft5x06/test.esp8266-ard.yaml diff --git a/tests/components/ft5x06/test.rp2040.yaml b/tests/components/ft5x06/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ft5x06/test.rp2040.yaml rename to tests/components/ft5x06/test.rp2040-ard.yaml diff --git a/tests/components/ft63x6/test.esp32.yaml b/tests/components/ft63x6/test.esp32-ard.yaml similarity index 100% rename from tests/components/ft63x6/test.esp32.yaml rename to tests/components/ft63x6/test.esp32-ard.yaml diff --git a/tests/components/ft63x6/test.esp32-c3.yaml b/tests/components/ft63x6/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ft63x6/test.esp32-c3.yaml rename to tests/components/ft63x6/test.esp32-c3-ard.yaml diff --git a/tests/components/ft63x6/test.esp8266.yaml b/tests/components/ft63x6/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ft63x6/test.esp8266.yaml rename to tests/components/ft63x6/test.esp8266-ard.yaml diff --git a/tests/components/ft63x6/test.rp2040.yaml b/tests/components/ft63x6/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ft63x6/test.rp2040.yaml rename to tests/components/ft63x6/test.rp2040-ard.yaml diff --git a/tests/components/fujitsu_general/test.esp32-c3.yaml b/tests/components/fujitsu_general/test.esp32-ard.yaml similarity index 100% rename from tests/components/fujitsu_general/test.esp32-c3.yaml rename to tests/components/fujitsu_general/test.esp32-ard.yaml diff --git a/tests/components/fujitsu_general/test.esp32.yaml b/tests/components/fujitsu_general/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/fujitsu_general/test.esp32.yaml rename to tests/components/fujitsu_general/test.esp32-c3-ard.yaml diff --git a/tests/components/fujitsu_general/test.esp8266.yaml b/tests/components/fujitsu_general/test.esp8266-ard.yaml similarity index 100% rename from tests/components/fujitsu_general/test.esp8266.yaml rename to tests/components/fujitsu_general/test.esp8266-ard.yaml diff --git a/tests/components/gcja5/test.esp32.yaml b/tests/components/gcja5/test.esp32-ard.yaml similarity index 100% rename from tests/components/gcja5/test.esp32.yaml rename to tests/components/gcja5/test.esp32-ard.yaml diff --git a/tests/components/gcja5/test.esp32-c3.yaml b/tests/components/gcja5/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gcja5/test.esp32-c3.yaml rename to tests/components/gcja5/test.esp32-c3-ard.yaml diff --git a/tests/components/gcja5/test.esp8266.yaml b/tests/components/gcja5/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gcja5/test.esp8266.yaml rename to tests/components/gcja5/test.esp8266-ard.yaml diff --git a/tests/components/gcja5/test.rp2040.yaml b/tests/components/gcja5/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gcja5/test.rp2040.yaml rename to tests/components/gcja5/test.rp2040-ard.yaml diff --git a/tests/components/gdk101/test.esp32.yaml b/tests/components/gdk101/test.esp32-ard.yaml similarity index 100% rename from tests/components/gdk101/test.esp32.yaml rename to tests/components/gdk101/test.esp32-ard.yaml diff --git a/tests/components/gdk101/test.esp8266.yaml b/tests/components/gdk101/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gdk101/test.esp8266.yaml rename to tests/components/gdk101/test.esp8266-ard.yaml diff --git a/tests/components/gdk101/test.rp2040.yaml b/tests/components/gdk101/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gdk101/test.rp2040.yaml rename to tests/components/gdk101/test.rp2040-ard.yaml diff --git a/tests/components/globals/test.esp32-c3.yaml b/tests/components/globals/test.esp32-ard.yaml similarity index 100% rename from tests/components/globals/test.esp32-c3.yaml rename to tests/components/globals/test.esp32-ard.yaml diff --git a/tests/components/globals/test.esp32.yaml b/tests/components/globals/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/globals/test.esp32.yaml rename to tests/components/globals/test.esp32-c3-ard.yaml diff --git a/tests/components/globals/test.esp8266.yaml b/tests/components/globals/test.esp8266-ard.yaml similarity index 100% rename from tests/components/globals/test.esp8266.yaml rename to tests/components/globals/test.esp8266-ard.yaml diff --git a/tests/components/globals/test.rp2040.yaml b/tests/components/globals/test.rp2040-ard.yaml similarity index 100% rename from tests/components/globals/test.rp2040.yaml rename to tests/components/globals/test.rp2040-ard.yaml diff --git a/tests/components/gp8403/test.esp32.yaml b/tests/components/gp8403/test.esp32-ard.yaml similarity index 100% rename from tests/components/gp8403/test.esp32.yaml rename to tests/components/gp8403/test.esp32-ard.yaml diff --git a/tests/components/gp8403/test.esp32-c3.yaml b/tests/components/gp8403/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gp8403/test.esp32-c3.yaml rename to tests/components/gp8403/test.esp32-c3-ard.yaml diff --git a/tests/components/gp8403/test.esp8266.yaml b/tests/components/gp8403/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gp8403/test.esp8266.yaml rename to tests/components/gp8403/test.esp8266-ard.yaml diff --git a/tests/components/gp8403/test.rp2040.yaml b/tests/components/gp8403/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gp8403/test.rp2040.yaml rename to tests/components/gp8403/test.rp2040-ard.yaml diff --git a/tests/components/gpio/test.esp32.yaml b/tests/components/gpio/test.esp32-ard.yaml similarity index 100% rename from tests/components/gpio/test.esp32.yaml rename to tests/components/gpio/test.esp32-ard.yaml diff --git a/tests/components/gpio/test.esp32-c3.yaml b/tests/components/gpio/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gpio/test.esp32-c3.yaml rename to tests/components/gpio/test.esp32-c3-ard.yaml diff --git a/tests/components/gpio/test.esp8266.yaml b/tests/components/gpio/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gpio/test.esp8266.yaml rename to tests/components/gpio/test.esp8266-ard.yaml diff --git a/tests/components/gpio/test.rp2040.yaml b/tests/components/gpio/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gpio/test.rp2040.yaml rename to tests/components/gpio/test.rp2040-ard.yaml diff --git a/tests/components/gps/test.esp32.yaml b/tests/components/gps/test.esp32-ard.yaml similarity index 100% rename from tests/components/gps/test.esp32.yaml rename to tests/components/gps/test.esp32-ard.yaml diff --git a/tests/components/gps/test.esp32-c3.yaml b/tests/components/gps/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gps/test.esp32-c3.yaml rename to tests/components/gps/test.esp32-c3-ard.yaml diff --git a/tests/components/gps/test.esp8266.yaml b/tests/components/gps/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gps/test.esp8266.yaml rename to tests/components/gps/test.esp8266-ard.yaml diff --git a/tests/components/gps/test.rp2040.yaml b/tests/components/gps/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gps/test.rp2040.yaml rename to tests/components/gps/test.rp2040-ard.yaml diff --git a/tests/components/graph/test.esp32.yaml b/tests/components/graph/test.esp32-ard.yaml similarity index 100% rename from tests/components/graph/test.esp32.yaml rename to tests/components/graph/test.esp32-ard.yaml diff --git a/tests/components/graph/test.esp32-c3.yaml b/tests/components/graph/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/graph/test.esp32-c3.yaml rename to tests/components/graph/test.esp32-c3-ard.yaml diff --git a/tests/components/graph/test.esp8266.yaml b/tests/components/graph/test.esp8266-ard.yaml similarity index 100% rename from tests/components/graph/test.esp8266.yaml rename to tests/components/graph/test.esp8266-ard.yaml diff --git a/tests/components/graph/test.rp2040.yaml b/tests/components/graph/test.rp2040-ard.yaml similarity index 100% rename from tests/components/graph/test.rp2040.yaml rename to tests/components/graph/test.rp2040-ard.yaml diff --git a/tests/components/graphical_display_menu/test.esp32.yaml b/tests/components/graphical_display_menu/test.esp32-ard.yaml similarity index 100% rename from tests/components/graphical_display_menu/test.esp32.yaml rename to tests/components/graphical_display_menu/test.esp32-ard.yaml diff --git a/tests/components/graphical_display_menu/test.esp32-c3.yaml b/tests/components/graphical_display_menu/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/graphical_display_menu/test.esp32-c3.yaml rename to tests/components/graphical_display_menu/test.esp32-c3-ard.yaml diff --git a/tests/components/graphical_display_menu/test.esp8266.yaml b/tests/components/graphical_display_menu/test.esp8266-ard.yaml similarity index 100% rename from tests/components/graphical_display_menu/test.esp8266.yaml rename to tests/components/graphical_display_menu/test.esp8266-ard.yaml diff --git a/tests/components/graphical_display_menu/test.rp2040.yaml b/tests/components/graphical_display_menu/test.rp2040-ard.yaml similarity index 100% rename from tests/components/graphical_display_menu/test.rp2040.yaml rename to tests/components/graphical_display_menu/test.rp2040-ard.yaml diff --git a/tests/components/gree/test.esp32-c3.yaml b/tests/components/gree/test.esp32-ard.yaml similarity index 100% rename from tests/components/gree/test.esp32-c3.yaml rename to tests/components/gree/test.esp32-ard.yaml diff --git a/tests/components/gree/test.esp32.yaml b/tests/components/gree/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gree/test.esp32.yaml rename to tests/components/gree/test.esp32-c3-ard.yaml diff --git a/tests/components/gree/test.esp8266.yaml b/tests/components/gree/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gree/test.esp8266.yaml rename to tests/components/gree/test.esp8266-ard.yaml diff --git a/tests/components/grove_tb6612fng/test.esp32.yaml b/tests/components/grove_tb6612fng/test.esp32-ard.yaml similarity index 100% rename from tests/components/grove_tb6612fng/test.esp32.yaml rename to tests/components/grove_tb6612fng/test.esp32-ard.yaml diff --git a/tests/components/grove_tb6612fng/test.esp32-c3.yaml b/tests/components/grove_tb6612fng/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/grove_tb6612fng/test.esp32-c3.yaml rename to tests/components/grove_tb6612fng/test.esp32-c3-ard.yaml diff --git a/tests/components/grove_tb6612fng/test.esp8266.yaml b/tests/components/grove_tb6612fng/test.esp8266-ard.yaml similarity index 100% rename from tests/components/grove_tb6612fng/test.esp8266.yaml rename to tests/components/grove_tb6612fng/test.esp8266-ard.yaml diff --git a/tests/components/grove_tb6612fng/test.rp2040.yaml b/tests/components/grove_tb6612fng/test.rp2040-ard.yaml similarity index 100% rename from tests/components/grove_tb6612fng/test.rp2040.yaml rename to tests/components/grove_tb6612fng/test.rp2040-ard.yaml diff --git a/tests/components/growatt_solar/test.esp32.yaml b/tests/components/growatt_solar/test.esp32-ard.yaml similarity index 100% rename from tests/components/growatt_solar/test.esp32.yaml rename to tests/components/growatt_solar/test.esp32-ard.yaml diff --git a/tests/components/growatt_solar/test.esp32-c3.yaml b/tests/components/growatt_solar/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/growatt_solar/test.esp32-c3.yaml rename to tests/components/growatt_solar/test.esp32-c3-ard.yaml diff --git a/tests/components/growatt_solar/test.esp8266.yaml b/tests/components/growatt_solar/test.esp8266-ard.yaml similarity index 100% rename from tests/components/growatt_solar/test.esp8266.yaml rename to tests/components/growatt_solar/test.esp8266-ard.yaml diff --git a/tests/components/growatt_solar/test.rp2040.yaml b/tests/components/growatt_solar/test.rp2040-ard.yaml similarity index 100% rename from tests/components/growatt_solar/test.rp2040.yaml rename to tests/components/growatt_solar/test.rp2040-ard.yaml diff --git a/tests/components/gt911/test.esp32.yaml b/tests/components/gt911/test.esp32-ard.yaml similarity index 100% rename from tests/components/gt911/test.esp32.yaml rename to tests/components/gt911/test.esp32-ard.yaml diff --git a/tests/components/gt911/test.esp32-c3.yaml b/tests/components/gt911/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/gt911/test.esp32-c3.yaml rename to tests/components/gt911/test.esp32-c3-ard.yaml diff --git a/tests/components/gt911/test.esp8266.yaml b/tests/components/gt911/test.esp8266-ard.yaml similarity index 100% rename from tests/components/gt911/test.esp8266.yaml rename to tests/components/gt911/test.esp8266-ard.yaml diff --git a/tests/components/gt911/test.rp2040.yaml b/tests/components/gt911/test.rp2040-ard.yaml similarity index 100% rename from tests/components/gt911/test.rp2040.yaml rename to tests/components/gt911/test.rp2040-ard.yaml diff --git a/tests/components/haier/test.esp32.yaml b/tests/components/haier/test.esp32-ard.yaml similarity index 100% rename from tests/components/haier/test.esp32.yaml rename to tests/components/haier/test.esp32-ard.yaml diff --git a/tests/components/haier/test.esp32-c3.yaml b/tests/components/haier/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/haier/test.esp32-c3.yaml rename to tests/components/haier/test.esp32-c3-ard.yaml diff --git a/tests/components/haier/test.esp8266.yaml b/tests/components/haier/test.esp8266-ard.yaml similarity index 100% rename from tests/components/haier/test.esp8266.yaml rename to tests/components/haier/test.esp8266-ard.yaml diff --git a/tests/components/haier/test.rp2040.yaml b/tests/components/haier/test.rp2040-ard.yaml similarity index 100% rename from tests/components/haier/test.rp2040.yaml rename to tests/components/haier/test.rp2040-ard.yaml diff --git a/tests/components/havells_solar/test.esp32.yaml b/tests/components/havells_solar/test.esp32-ard.yaml similarity index 100% rename from tests/components/havells_solar/test.esp32.yaml rename to tests/components/havells_solar/test.esp32-ard.yaml diff --git a/tests/components/havells_solar/test.esp32-c3.yaml b/tests/components/havells_solar/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/havells_solar/test.esp32-c3.yaml rename to tests/components/havells_solar/test.esp32-c3-ard.yaml diff --git a/tests/components/havells_solar/test.esp8266.yaml b/tests/components/havells_solar/test.esp8266-ard.yaml similarity index 100% rename from tests/components/havells_solar/test.esp8266.yaml rename to tests/components/havells_solar/test.esp8266-ard.yaml diff --git a/tests/components/havells_solar/test.rp2040.yaml b/tests/components/havells_solar/test.rp2040-ard.yaml similarity index 100% rename from tests/components/havells_solar/test.rp2040.yaml rename to tests/components/havells_solar/test.rp2040-ard.yaml diff --git a/tests/components/hbridge/test.esp32.yaml b/tests/components/hbridge/test.esp32-ard.yaml similarity index 100% rename from tests/components/hbridge/test.esp32.yaml rename to tests/components/hbridge/test.esp32-ard.yaml diff --git a/tests/components/hbridge/test.esp32-c3.yaml b/tests/components/hbridge/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hbridge/test.esp32-c3.yaml rename to tests/components/hbridge/test.esp32-c3-ard.yaml diff --git a/tests/components/hbridge/test.esp8266.yaml b/tests/components/hbridge/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hbridge/test.esp8266.yaml rename to tests/components/hbridge/test.esp8266-ard.yaml diff --git a/tests/components/hbridge/test.rp2040.yaml b/tests/components/hbridge/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hbridge/test.rp2040.yaml rename to tests/components/hbridge/test.rp2040-ard.yaml diff --git a/tests/components/hdc1080/test.esp32.yaml b/tests/components/hdc1080/test.esp32-ard.yaml similarity index 100% rename from tests/components/hdc1080/test.esp32.yaml rename to tests/components/hdc1080/test.esp32-ard.yaml diff --git a/tests/components/hdc1080/test.esp32-c3.yaml b/tests/components/hdc1080/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hdc1080/test.esp32-c3.yaml rename to tests/components/hdc1080/test.esp32-c3-ard.yaml diff --git a/tests/components/hdc1080/test.esp8266.yaml b/tests/components/hdc1080/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hdc1080/test.esp8266.yaml rename to tests/components/hdc1080/test.esp8266-ard.yaml diff --git a/tests/components/hdc1080/test.rp2040.yaml b/tests/components/hdc1080/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hdc1080/test.rp2040.yaml rename to tests/components/hdc1080/test.rp2040-ard.yaml diff --git a/tests/components/he60r/test.esp32.yaml b/tests/components/he60r/test.esp32-ard.yaml similarity index 100% rename from tests/components/he60r/test.esp32.yaml rename to tests/components/he60r/test.esp32-ard.yaml diff --git a/tests/components/he60r/test.esp32-c3.yaml b/tests/components/he60r/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/he60r/test.esp32-c3.yaml rename to tests/components/he60r/test.esp32-c3-ard.yaml diff --git a/tests/components/he60r/test.esp8266.yaml b/tests/components/he60r/test.esp8266-ard.yaml similarity index 100% rename from tests/components/he60r/test.esp8266.yaml rename to tests/components/he60r/test.esp8266-ard.yaml diff --git a/tests/components/he60r/test.rp2040.yaml b/tests/components/he60r/test.rp2040-ard.yaml similarity index 100% rename from tests/components/he60r/test.rp2040.yaml rename to tests/components/he60r/test.rp2040-ard.yaml diff --git a/tests/components/heatpumpir/test.esp32.yaml b/tests/components/heatpumpir/test.esp32-ard.yaml similarity index 100% rename from tests/components/heatpumpir/test.esp32.yaml rename to tests/components/heatpumpir/test.esp32-ard.yaml diff --git a/tests/components/heatpumpir/test.esp8266.yaml b/tests/components/heatpumpir/test.esp8266-ard.yaml similarity index 100% rename from tests/components/heatpumpir/test.esp8266.yaml rename to tests/components/heatpumpir/test.esp8266-ard.yaml diff --git a/tests/components/hitachi_ac344/test.esp32-c3.yaml b/tests/components/hitachi_ac344/test.esp32-ard.yaml similarity index 100% rename from tests/components/hitachi_ac344/test.esp32-c3.yaml rename to tests/components/hitachi_ac344/test.esp32-ard.yaml diff --git a/tests/components/hitachi_ac344/test.esp32.yaml b/tests/components/hitachi_ac344/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hitachi_ac344/test.esp32.yaml rename to tests/components/hitachi_ac344/test.esp32-c3-ard.yaml diff --git a/tests/components/hitachi_ac344/test.esp8266.yaml b/tests/components/hitachi_ac344/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hitachi_ac344/test.esp8266.yaml rename to tests/components/hitachi_ac344/test.esp8266-ard.yaml diff --git a/tests/components/hitachi_ac424/test.esp32-c3.yaml b/tests/components/hitachi_ac424/test.esp32-ard.yaml similarity index 100% rename from tests/components/hitachi_ac424/test.esp32-c3.yaml rename to tests/components/hitachi_ac424/test.esp32-ard.yaml diff --git a/tests/components/hitachi_ac424/test.esp32.yaml b/tests/components/hitachi_ac424/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hitachi_ac424/test.esp32.yaml rename to tests/components/hitachi_ac424/test.esp32-c3-ard.yaml diff --git a/tests/components/hitachi_ac424/test.esp8266.yaml b/tests/components/hitachi_ac424/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hitachi_ac424/test.esp8266.yaml rename to tests/components/hitachi_ac424/test.esp8266-ard.yaml diff --git a/tests/components/hlw8012/test.esp32.yaml b/tests/components/hlw8012/test.esp32-ard.yaml similarity index 100% rename from tests/components/hlw8012/test.esp32.yaml rename to tests/components/hlw8012/test.esp32-ard.yaml diff --git a/tests/components/hlw8012/test.esp32-c3.yaml b/tests/components/hlw8012/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hlw8012/test.esp32-c3.yaml rename to tests/components/hlw8012/test.esp32-c3-ard.yaml diff --git a/tests/components/hlw8012/test.esp8266.yaml b/tests/components/hlw8012/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hlw8012/test.esp8266.yaml rename to tests/components/hlw8012/test.esp8266-ard.yaml diff --git a/tests/components/hlw8012/test.rp2040.yaml b/tests/components/hlw8012/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hlw8012/test.rp2040.yaml rename to tests/components/hlw8012/test.rp2040-ard.yaml diff --git a/tests/components/hm3301/test.esp32.yaml b/tests/components/hm3301/test.esp32-ard.yaml similarity index 100% rename from tests/components/hm3301/test.esp32.yaml rename to tests/components/hm3301/test.esp32-ard.yaml diff --git a/tests/components/hm3301/test.esp32-c3.yaml b/tests/components/hm3301/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hm3301/test.esp32-c3.yaml rename to tests/components/hm3301/test.esp32-c3-ard.yaml diff --git a/tests/components/hm3301/test.esp8266.yaml b/tests/components/hm3301/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hm3301/test.esp8266.yaml rename to tests/components/hm3301/test.esp8266-ard.yaml diff --git a/tests/components/hm3301/test.rp2040.yaml b/tests/components/hm3301/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hm3301/test.rp2040.yaml rename to tests/components/hm3301/test.rp2040-ard.yaml diff --git a/tests/components/hmc5883l/test.esp32.yaml b/tests/components/hmc5883l/test.esp32-ard.yaml similarity index 100% rename from tests/components/hmc5883l/test.esp32.yaml rename to tests/components/hmc5883l/test.esp32-ard.yaml diff --git a/tests/components/hmc5883l/test.esp32-c3.yaml b/tests/components/hmc5883l/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hmc5883l/test.esp32-c3.yaml rename to tests/components/hmc5883l/test.esp32-c3-ard.yaml diff --git a/tests/components/hmc5883l/test.esp8266.yaml b/tests/components/hmc5883l/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hmc5883l/test.esp8266.yaml rename to tests/components/hmc5883l/test.esp8266-ard.yaml diff --git a/tests/components/hmc5883l/test.rp2040.yaml b/tests/components/hmc5883l/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hmc5883l/test.rp2040.yaml rename to tests/components/hmc5883l/test.rp2040-ard.yaml diff --git a/tests/components/homeassistant/test.bk72xx.yaml b/tests/components/homeassistant/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/homeassistant/test.bk72xx.yaml rename to tests/components/homeassistant/test.bk72xx-ard.yaml diff --git a/tests/components/homeassistant/test.esp32-c3.yaml b/tests/components/homeassistant/test.esp32-ard.yaml similarity index 100% rename from tests/components/homeassistant/test.esp32-c3.yaml rename to tests/components/homeassistant/test.esp32-ard.yaml diff --git a/tests/components/homeassistant/test.esp32.yaml b/tests/components/homeassistant/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/homeassistant/test.esp32.yaml rename to tests/components/homeassistant/test.esp32-c3-ard.yaml diff --git a/tests/components/homeassistant/test.esp8266.yaml b/tests/components/homeassistant/test.esp8266-ard.yaml similarity index 100% rename from tests/components/homeassistant/test.esp8266.yaml rename to tests/components/homeassistant/test.esp8266-ard.yaml diff --git a/tests/components/homeassistant/test.rp2040.yaml b/tests/components/homeassistant/test.rp2040-ard.yaml similarity index 100% rename from tests/components/homeassistant/test.rp2040.yaml rename to tests/components/homeassistant/test.rp2040-ard.yaml diff --git a/tests/components/honeywell_hih_i2c/test.esp32.yaml b/tests/components/honeywell_hih_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/honeywell_hih_i2c/test.esp32.yaml rename to tests/components/honeywell_hih_i2c/test.esp32-ard.yaml diff --git a/tests/components/honeywell_hih_i2c/test.esp32-c3.yaml b/tests/components/honeywell_hih_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/honeywell_hih_i2c/test.esp32-c3.yaml rename to tests/components/honeywell_hih_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/honeywell_hih_i2c/test.esp8266.yaml b/tests/components/honeywell_hih_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/honeywell_hih_i2c/test.esp8266.yaml rename to tests/components/honeywell_hih_i2c/test.esp8266-ard.yaml diff --git a/tests/components/honeywell_hih_i2c/test.rp2040.yaml b/tests/components/honeywell_hih_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/honeywell_hih_i2c/test.rp2040.yaml rename to tests/components/honeywell_hih_i2c/test.rp2040-ard.yaml diff --git a/tests/components/honeywellabp/test.esp32.yaml b/tests/components/honeywellabp/test.esp32-ard.yaml similarity index 100% rename from tests/components/honeywellabp/test.esp32.yaml rename to tests/components/honeywellabp/test.esp32-ard.yaml diff --git a/tests/components/honeywellabp/test.esp32-c3.yaml b/tests/components/honeywellabp/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/honeywellabp/test.esp32-c3.yaml rename to tests/components/honeywellabp/test.esp32-c3-ard.yaml diff --git a/tests/components/honeywellabp/test.esp8266.yaml b/tests/components/honeywellabp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/honeywellabp/test.esp8266.yaml rename to tests/components/honeywellabp/test.esp8266-ard.yaml diff --git a/tests/components/honeywellabp/test.rp2040.yaml b/tests/components/honeywellabp/test.rp2040-ard.yaml similarity index 100% rename from tests/components/honeywellabp/test.rp2040.yaml rename to tests/components/honeywellabp/test.rp2040-ard.yaml diff --git a/tests/components/honeywellabp2_i2c/test.esp32.yaml b/tests/components/honeywellabp2_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/honeywellabp2_i2c/test.esp32.yaml rename to tests/components/honeywellabp2_i2c/test.esp32-ard.yaml diff --git a/tests/components/honeywellabp2_i2c/test.esp32-c3.yaml b/tests/components/honeywellabp2_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/honeywellabp2_i2c/test.esp32-c3.yaml rename to tests/components/honeywellabp2_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/honeywellabp2_i2c/test.esp8266.yaml b/tests/components/honeywellabp2_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/honeywellabp2_i2c/test.esp8266.yaml rename to tests/components/honeywellabp2_i2c/test.esp8266-ard.yaml diff --git a/tests/components/honeywellabp2_i2c/test.rp2040.yaml b/tests/components/honeywellabp2_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/honeywellabp2_i2c/test.rp2040.yaml rename to tests/components/honeywellabp2_i2c/test.rp2040-ard.yaml diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32-ard.yaml similarity index 100% rename from tests/components/hrxl_maxsonar_wr/test.esp32.yaml rename to tests/components/hrxl_maxsonar_wr/test.esp32-ard.yaml diff --git a/tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml b/tests/components/hrxl_maxsonar_wr/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hrxl_maxsonar_wr/test.esp32-c3.yaml rename to tests/components/hrxl_maxsonar_wr/test.esp32-c3-ard.yaml diff --git a/tests/components/hrxl_maxsonar_wr/test.esp8266.yaml b/tests/components/hrxl_maxsonar_wr/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hrxl_maxsonar_wr/test.esp8266.yaml rename to tests/components/hrxl_maxsonar_wr/test.esp8266-ard.yaml diff --git a/tests/components/hrxl_maxsonar_wr/test.rp2040.yaml b/tests/components/hrxl_maxsonar_wr/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hrxl_maxsonar_wr/test.rp2040.yaml rename to tests/components/hrxl_maxsonar_wr/test.rp2040-ard.yaml diff --git a/tests/components/hte501/test.esp32.yaml b/tests/components/hte501/test.esp32-ard.yaml similarity index 100% rename from tests/components/hte501/test.esp32.yaml rename to tests/components/hte501/test.esp32-ard.yaml diff --git a/tests/components/hte501/test.esp32-c3.yaml b/tests/components/hte501/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hte501/test.esp32-c3.yaml rename to tests/components/hte501/test.esp32-c3-ard.yaml diff --git a/tests/components/hte501/test.esp8266.yaml b/tests/components/hte501/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hte501/test.esp8266.yaml rename to tests/components/hte501/test.esp8266-ard.yaml diff --git a/tests/components/hte501/test.rp2040.yaml b/tests/components/hte501/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hte501/test.rp2040.yaml rename to tests/components/hte501/test.rp2040-ard.yaml diff --git a/tests/components/http_request/test-nossl.esp8266.yaml b/tests/components/http_request/test-nossl.esp8266-ard.yaml similarity index 100% rename from tests/components/http_request/test-nossl.esp8266.yaml rename to tests/components/http_request/test-nossl.esp8266-ard.yaml diff --git a/tests/components/http_request/test.esp32-c3.yaml b/tests/components/http_request/test.esp32-ard.yaml similarity index 100% rename from tests/components/http_request/test.esp32-c3.yaml rename to tests/components/http_request/test.esp32-ard.yaml diff --git a/tests/components/http_request/test.esp32.yaml b/tests/components/http_request/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/http_request/test.esp32.yaml rename to tests/components/http_request/test.esp32-c3-ard.yaml diff --git a/tests/components/http_request/test.esp8266.yaml b/tests/components/http_request/test.esp8266-ard.yaml similarity index 100% rename from tests/components/http_request/test.esp8266.yaml rename to tests/components/http_request/test.esp8266-ard.yaml diff --git a/tests/components/http_request/test.rp2040.yaml b/tests/components/http_request/test.rp2040-ard.yaml similarity index 100% rename from tests/components/http_request/test.rp2040.yaml rename to tests/components/http_request/test.rp2040-ard.yaml diff --git a/tests/components/htu21d/test.esp32.yaml b/tests/components/htu21d/test.esp32-ard.yaml similarity index 100% rename from tests/components/htu21d/test.esp32.yaml rename to tests/components/htu21d/test.esp32-ard.yaml diff --git a/tests/components/htu21d/test.esp32-c3.yaml b/tests/components/htu21d/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/htu21d/test.esp32-c3.yaml rename to tests/components/htu21d/test.esp32-c3-ard.yaml diff --git a/tests/components/htu21d/test.esp8266.yaml b/tests/components/htu21d/test.esp8266-ard.yaml similarity index 100% rename from tests/components/htu21d/test.esp8266.yaml rename to tests/components/htu21d/test.esp8266-ard.yaml diff --git a/tests/components/htu21d/test.rp2040.yaml b/tests/components/htu21d/test.rp2040-ard.yaml similarity index 100% rename from tests/components/htu21d/test.rp2040.yaml rename to tests/components/htu21d/test.rp2040-ard.yaml diff --git a/tests/components/htu31d/test.esp32.yaml b/tests/components/htu31d/test.esp32-ard.yaml similarity index 100% rename from tests/components/htu31d/test.esp32.yaml rename to tests/components/htu31d/test.esp32-ard.yaml diff --git a/tests/components/htu31d/test.esp8266.yaml b/tests/components/htu31d/test.esp8266-ard.yaml similarity index 100% rename from tests/components/htu31d/test.esp8266.yaml rename to tests/components/htu31d/test.esp8266-ard.yaml diff --git a/tests/components/hx711/test.esp32.yaml b/tests/components/hx711/test.esp32-ard.yaml similarity index 100% rename from tests/components/hx711/test.esp32.yaml rename to tests/components/hx711/test.esp32-ard.yaml diff --git a/tests/components/hx711/test.esp32-c3.yaml b/tests/components/hx711/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hx711/test.esp32-c3.yaml rename to tests/components/hx711/test.esp32-c3-ard.yaml diff --git a/tests/components/hx711/test.esp8266.yaml b/tests/components/hx711/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hx711/test.esp8266.yaml rename to tests/components/hx711/test.esp8266-ard.yaml diff --git a/tests/components/hx711/test.rp2040.yaml b/tests/components/hx711/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hx711/test.rp2040.yaml rename to tests/components/hx711/test.rp2040-ard.yaml diff --git a/tests/components/hydreon_rgxx/test.esp32.yaml b/tests/components/hydreon_rgxx/test.esp32-ard.yaml similarity index 100% rename from tests/components/hydreon_rgxx/test.esp32.yaml rename to tests/components/hydreon_rgxx/test.esp32-ard.yaml diff --git a/tests/components/hydreon_rgxx/test.esp32-c3.yaml b/tests/components/hydreon_rgxx/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hydreon_rgxx/test.esp32-c3.yaml rename to tests/components/hydreon_rgxx/test.esp32-c3-ard.yaml diff --git a/tests/components/hydreon_rgxx/test.esp8266.yaml b/tests/components/hydreon_rgxx/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hydreon_rgxx/test.esp8266.yaml rename to tests/components/hydreon_rgxx/test.esp8266-ard.yaml diff --git a/tests/components/hydreon_rgxx/test.rp2040.yaml b/tests/components/hydreon_rgxx/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hydreon_rgxx/test.rp2040.yaml rename to tests/components/hydreon_rgxx/test.rp2040-ard.yaml diff --git a/tests/components/hyt271/test.esp32.yaml b/tests/components/hyt271/test.esp32-ard.yaml similarity index 100% rename from tests/components/hyt271/test.esp32.yaml rename to tests/components/hyt271/test.esp32-ard.yaml diff --git a/tests/components/hyt271/test.esp32-c3.yaml b/tests/components/hyt271/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/hyt271/test.esp32-c3.yaml rename to tests/components/hyt271/test.esp32-c3-ard.yaml diff --git a/tests/components/hyt271/test.esp8266.yaml b/tests/components/hyt271/test.esp8266-ard.yaml similarity index 100% rename from tests/components/hyt271/test.esp8266.yaml rename to tests/components/hyt271/test.esp8266-ard.yaml diff --git a/tests/components/hyt271/test.rp2040.yaml b/tests/components/hyt271/test.rp2040-ard.yaml similarity index 100% rename from tests/components/hyt271/test.rp2040.yaml rename to tests/components/hyt271/test.rp2040-ard.yaml diff --git a/tests/components/i2c/test.esp32.yaml b/tests/components/i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/i2c/test.esp32.yaml rename to tests/components/i2c/test.esp32-ard.yaml diff --git a/tests/components/i2c/test.esp32-c3.yaml b/tests/components/i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/i2c/test.esp32-c3.yaml rename to tests/components/i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/i2c/test.esp8266.yaml b/tests/components/i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/i2c/test.esp8266.yaml rename to tests/components/i2c/test.esp8266-ard.yaml diff --git a/tests/components/i2c/test.rp2040.yaml b/tests/components/i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/i2c/test.rp2040.yaml rename to tests/components/i2c/test.rp2040-ard.yaml diff --git a/tests/components/i2s_audio/test.esp32.yaml b/tests/components/i2s_audio/test.esp32-ard.yaml similarity index 100% rename from tests/components/i2s_audio/test.esp32.yaml rename to tests/components/i2s_audio/test.esp32-ard.yaml diff --git a/tests/components/i2s_audio/test.esp32-c3.yaml b/tests/components/i2s_audio/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/i2s_audio/test.esp32-c3.yaml rename to tests/components/i2s_audio/test.esp32-c3-ard.yaml diff --git a/tests/components/iaqcore/test.esp32.yaml b/tests/components/iaqcore/test.esp32-ard.yaml similarity index 100% rename from tests/components/iaqcore/test.esp32.yaml rename to tests/components/iaqcore/test.esp32-ard.yaml diff --git a/tests/components/iaqcore/test.esp32-c3.yaml b/tests/components/iaqcore/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/iaqcore/test.esp32-c3.yaml rename to tests/components/iaqcore/test.esp32-c3-ard.yaml diff --git a/tests/components/iaqcore/test.esp8266.yaml b/tests/components/iaqcore/test.esp8266-ard.yaml similarity index 100% rename from tests/components/iaqcore/test.esp8266.yaml rename to tests/components/iaqcore/test.esp8266-ard.yaml diff --git a/tests/components/iaqcore/test.rp2040.yaml b/tests/components/iaqcore/test.rp2040-ard.yaml similarity index 100% rename from tests/components/iaqcore/test.rp2040.yaml rename to tests/components/iaqcore/test.rp2040-ard.yaml diff --git a/tests/components/ili9xxx/test.esp32.yaml b/tests/components/ili9xxx/test.esp32-ard.yaml similarity index 100% rename from tests/components/ili9xxx/test.esp32.yaml rename to tests/components/ili9xxx/test.esp32-ard.yaml diff --git a/tests/components/ili9xxx/test.esp32-c3.yaml b/tests/components/ili9xxx/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ili9xxx/test.esp32-c3.yaml rename to tests/components/ili9xxx/test.esp32-c3-ard.yaml diff --git a/tests/components/ili9xxx/test.esp8266.yaml b/tests/components/ili9xxx/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ili9xxx/test.esp8266.yaml rename to tests/components/ili9xxx/test.esp8266-ard.yaml diff --git a/tests/components/ili9xxx/test.rp2040.yaml b/tests/components/ili9xxx/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ili9xxx/test.rp2040.yaml rename to tests/components/ili9xxx/test.rp2040-ard.yaml diff --git a/tests/components/image/test.esp32.yaml b/tests/components/image/test.esp32-ard.yaml similarity index 100% rename from tests/components/image/test.esp32.yaml rename to tests/components/image/test.esp32-ard.yaml diff --git a/tests/components/image/test.esp32-c3.yaml b/tests/components/image/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/image/test.esp32-c3.yaml rename to tests/components/image/test.esp32-c3-ard.yaml diff --git a/tests/components/image/test.esp8266.yaml b/tests/components/image/test.esp8266-ard.yaml similarity index 100% rename from tests/components/image/test.esp8266.yaml rename to tests/components/image/test.esp8266-ard.yaml diff --git a/tests/components/image/test.rp2040.yaml b/tests/components/image/test.rp2040-ard.yaml similarity index 100% rename from tests/components/image/test.rp2040.yaml rename to tests/components/image/test.rp2040-ard.yaml diff --git a/tests/components/improv_serial/test.esp32-c3.yaml b/tests/components/improv_serial/test.esp32-ard.yaml similarity index 100% rename from tests/components/improv_serial/test.esp32-c3.yaml rename to tests/components/improv_serial/test.esp32-ard.yaml diff --git a/tests/components/improv_serial/test.esp32.yaml b/tests/components/improv_serial/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/improv_serial/test.esp32.yaml rename to tests/components/improv_serial/test.esp32-c3-ard.yaml diff --git a/tests/components/improv_serial/test.esp8266.yaml b/tests/components/improv_serial/test.esp8266-ard.yaml similarity index 100% rename from tests/components/improv_serial/test.esp8266.yaml rename to tests/components/improv_serial/test.esp8266-ard.yaml diff --git a/tests/components/improv_serial/test.rp2040.yaml b/tests/components/improv_serial/test.rp2040-ard.yaml similarity index 100% rename from tests/components/improv_serial/test.rp2040.yaml rename to tests/components/improv_serial/test.rp2040-ard.yaml diff --git a/tests/components/ina219/test.esp32.yaml b/tests/components/ina219/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina219/test.esp32.yaml rename to tests/components/ina219/test.esp32-ard.yaml diff --git a/tests/components/ina219/test.esp32-c3.yaml b/tests/components/ina219/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina219/test.esp32-c3.yaml rename to tests/components/ina219/test.esp32-c3-ard.yaml diff --git a/tests/components/ina219/test.esp8266.yaml b/tests/components/ina219/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina219/test.esp8266.yaml rename to tests/components/ina219/test.esp8266-ard.yaml diff --git a/tests/components/ina219/test.rp2040.yaml b/tests/components/ina219/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina219/test.rp2040.yaml rename to tests/components/ina219/test.rp2040-ard.yaml diff --git a/tests/components/ina226/test.esp32.yaml b/tests/components/ina226/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina226/test.esp32.yaml rename to tests/components/ina226/test.esp32-ard.yaml diff --git a/tests/components/ina226/test.esp32-c3.yaml b/tests/components/ina226/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina226/test.esp32-c3.yaml rename to tests/components/ina226/test.esp32-c3-ard.yaml diff --git a/tests/components/ina226/test.esp8266.yaml b/tests/components/ina226/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina226/test.esp8266.yaml rename to tests/components/ina226/test.esp8266-ard.yaml diff --git a/tests/components/ina226/test.rp2040.yaml b/tests/components/ina226/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina226/test.rp2040.yaml rename to tests/components/ina226/test.rp2040-ard.yaml diff --git a/tests/components/ina260/test.esp32.yaml b/tests/components/ina260/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina260/test.esp32.yaml rename to tests/components/ina260/test.esp32-ard.yaml diff --git a/tests/components/ina260/test.esp32-c3.yaml b/tests/components/ina260/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina260/test.esp32-c3.yaml rename to tests/components/ina260/test.esp32-c3-ard.yaml diff --git a/tests/components/ina260/test.esp8266.yaml b/tests/components/ina260/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina260/test.esp8266.yaml rename to tests/components/ina260/test.esp8266-ard.yaml diff --git a/tests/components/ina260/test.rp2040.yaml b/tests/components/ina260/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina260/test.rp2040.yaml rename to tests/components/ina260/test.rp2040-ard.yaml diff --git a/tests/components/ina2xx_i2c/test.esp32.yaml b/tests/components/ina2xx_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina2xx_i2c/test.esp32.yaml rename to tests/components/ina2xx_i2c/test.esp32-ard.yaml diff --git a/tests/components/ina2xx_i2c/test.esp32-c3.yaml b/tests/components/ina2xx_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina2xx_i2c/test.esp32-c3.yaml rename to tests/components/ina2xx_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/ina2xx_i2c/test.esp8266.yaml b/tests/components/ina2xx_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina2xx_i2c/test.esp8266.yaml rename to tests/components/ina2xx_i2c/test.esp8266-ard.yaml diff --git a/tests/components/ina2xx_i2c/test.rp2040.yaml b/tests/components/ina2xx_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina2xx_i2c/test.rp2040.yaml rename to tests/components/ina2xx_i2c/test.rp2040-ard.yaml diff --git a/tests/components/ina2xx_spi/test.esp32.yaml b/tests/components/ina2xx_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina2xx_spi/test.esp32.yaml rename to tests/components/ina2xx_spi/test.esp32-ard.yaml diff --git a/tests/components/ina2xx_spi/test.esp32-c3.yaml b/tests/components/ina2xx_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina2xx_spi/test.esp32-c3.yaml rename to tests/components/ina2xx_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ina2xx_spi/test.esp8266.yaml b/tests/components/ina2xx_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina2xx_spi/test.esp8266.yaml rename to tests/components/ina2xx_spi/test.esp8266-ard.yaml diff --git a/tests/components/ina2xx_spi/test.rp2040.yaml b/tests/components/ina2xx_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina2xx_spi/test.rp2040.yaml rename to tests/components/ina2xx_spi/test.rp2040-ard.yaml diff --git a/tests/components/ina3221/test.esp32.yaml b/tests/components/ina3221/test.esp32-ard.yaml similarity index 100% rename from tests/components/ina3221/test.esp32.yaml rename to tests/components/ina3221/test.esp32-ard.yaml diff --git a/tests/components/ina3221/test.esp32-c3.yaml b/tests/components/ina3221/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ina3221/test.esp32-c3.yaml rename to tests/components/ina3221/test.esp32-c3-ard.yaml diff --git a/tests/components/ina3221/test.esp8266.yaml b/tests/components/ina3221/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ina3221/test.esp8266.yaml rename to tests/components/ina3221/test.esp8266-ard.yaml diff --git a/tests/components/ina3221/test.rp2040.yaml b/tests/components/ina3221/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ina3221/test.rp2040.yaml rename to tests/components/ina3221/test.rp2040-ard.yaml diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-ard.yaml similarity index 100% rename from tests/components/inkbird_ibsth1_mini/test.esp32-c3.yaml rename to tests/components/inkbird_ibsth1_mini/test.esp32-ard.yaml diff --git a/tests/components/inkbird_ibsth1_mini/test.esp32.yaml b/tests/components/inkbird_ibsth1_mini/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/inkbird_ibsth1_mini/test.esp32.yaml rename to tests/components/inkbird_ibsth1_mini/test.esp32-c3-ard.yaml diff --git a/tests/components/inkplate6/test.esp32.yaml b/tests/components/inkplate6/test.esp32-ard.yaml similarity index 100% rename from tests/components/inkplate6/test.esp32.yaml rename to tests/components/inkplate6/test.esp32-ard.yaml diff --git a/tests/components/integration/test.esp32.yaml b/tests/components/integration/test.esp32-ard.yaml similarity index 100% rename from tests/components/integration/test.esp32.yaml rename to tests/components/integration/test.esp32-ard.yaml diff --git a/tests/components/integration/test.esp32-c3.yaml b/tests/components/integration/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/integration/test.esp32-c3.yaml rename to tests/components/integration/test.esp32-c3-ard.yaml diff --git a/tests/components/integration/test.esp32-s2.yaml b/tests/components/integration/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/integration/test.esp32-s2.yaml rename to tests/components/integration/test.esp32-s2-ard.yaml diff --git a/tests/components/integration/test.esp32-s3.yaml b/tests/components/integration/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/integration/test.esp32-s3.yaml rename to tests/components/integration/test.esp32-s3-ard.yaml diff --git a/tests/components/integration/test.esp8266.yaml b/tests/components/integration/test.esp8266-ard.yaml similarity index 100% rename from tests/components/integration/test.esp8266.yaml rename to tests/components/integration/test.esp8266-ard.yaml diff --git a/tests/components/integration/test.rp2040.yaml b/tests/components/integration/test.rp2040-ard.yaml similarity index 100% rename from tests/components/integration/test.rp2040.yaml rename to tests/components/integration/test.rp2040-ard.yaml diff --git a/tests/components/internal_temperature/test.bk72xx.yaml b/tests/components/internal_temperature/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.bk72xx.yaml rename to tests/components/internal_temperature/test.bk72xx-ard.yaml diff --git a/tests/components/internal_temperature/test.esp32-c3.yaml b/tests/components/internal_temperature/test.esp32-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.esp32-c3.yaml rename to tests/components/internal_temperature/test.esp32-ard.yaml diff --git a/tests/components/internal_temperature/test.esp32-s2.yaml b/tests/components/internal_temperature/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.esp32-s2.yaml rename to tests/components/internal_temperature/test.esp32-c3-ard.yaml diff --git a/tests/components/internal_temperature/test.esp32.yaml b/tests/components/internal_temperature/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.esp32.yaml rename to tests/components/internal_temperature/test.esp32-s2-ard.yaml diff --git a/tests/components/internal_temperature/test.esp32-s3.yaml b/tests/components/internal_temperature/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.esp32-s3.yaml rename to tests/components/internal_temperature/test.esp32-s3-ard.yaml diff --git a/tests/components/internal_temperature/test.rp2040.yaml b/tests/components/internal_temperature/test.rp2040-ard.yaml similarity index 100% rename from tests/components/internal_temperature/test.rp2040.yaml rename to tests/components/internal_temperature/test.rp2040-ard.yaml diff --git a/tests/components/interval/test.esp32-c3.yaml b/tests/components/interval/test.esp32-ard.yaml similarity index 100% rename from tests/components/interval/test.esp32-c3.yaml rename to tests/components/interval/test.esp32-ard.yaml diff --git a/tests/components/interval/test.esp32.yaml b/tests/components/interval/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/interval/test.esp32.yaml rename to tests/components/interval/test.esp32-c3-ard.yaml diff --git a/tests/components/interval/test.esp8266.yaml b/tests/components/interval/test.esp8266-ard.yaml similarity index 100% rename from tests/components/interval/test.esp8266.yaml rename to tests/components/interval/test.esp8266-ard.yaml diff --git a/tests/components/interval/test.rp2040.yaml b/tests/components/interval/test.rp2040-ard.yaml similarity index 100% rename from tests/components/interval/test.rp2040.yaml rename to tests/components/interval/test.rp2040-ard.yaml diff --git a/tests/components/jsn_sr04t/test.esp32.yaml b/tests/components/jsn_sr04t/test.esp32-ard.yaml similarity index 100% rename from tests/components/jsn_sr04t/test.esp32.yaml rename to tests/components/jsn_sr04t/test.esp32-ard.yaml diff --git a/tests/components/jsn_sr04t/test.esp32-c3.yaml b/tests/components/jsn_sr04t/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/jsn_sr04t/test.esp32-c3.yaml rename to tests/components/jsn_sr04t/test.esp32-c3-ard.yaml diff --git a/tests/components/jsn_sr04t/test.esp8266.yaml b/tests/components/jsn_sr04t/test.esp8266-ard.yaml similarity index 100% rename from tests/components/jsn_sr04t/test.esp8266.yaml rename to tests/components/jsn_sr04t/test.esp8266-ard.yaml diff --git a/tests/components/jsn_sr04t/test.rp2040.yaml b/tests/components/jsn_sr04t/test.rp2040-ard.yaml similarity index 100% rename from tests/components/jsn_sr04t/test.rp2040.yaml rename to tests/components/jsn_sr04t/test.rp2040-ard.yaml diff --git a/tests/components/kamstrup_kmp/test.esp32.yaml b/tests/components/kamstrup_kmp/test.esp32-ard.yaml similarity index 100% rename from tests/components/kamstrup_kmp/test.esp32.yaml rename to tests/components/kamstrup_kmp/test.esp32-ard.yaml diff --git a/tests/components/kamstrup_kmp/test.esp8266.yaml b/tests/components/kamstrup_kmp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/kamstrup_kmp/test.esp8266.yaml rename to tests/components/kamstrup_kmp/test.esp8266-ard.yaml diff --git a/tests/components/key_collector/test.esp32.yaml b/tests/components/key_collector/test.esp32-ard.yaml similarity index 100% rename from tests/components/key_collector/test.esp32.yaml rename to tests/components/key_collector/test.esp32-ard.yaml diff --git a/tests/components/key_collector/test.esp32-c3.yaml b/tests/components/key_collector/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/key_collector/test.esp32-c3.yaml rename to tests/components/key_collector/test.esp32-c3-ard.yaml diff --git a/tests/components/key_collector/test.esp8266.yaml b/tests/components/key_collector/test.esp8266-ard.yaml similarity index 100% rename from tests/components/key_collector/test.esp8266.yaml rename to tests/components/key_collector/test.esp8266-ard.yaml diff --git a/tests/components/key_collector/test.rp2040.yaml b/tests/components/key_collector/test.rp2040-ard.yaml similarity index 100% rename from tests/components/key_collector/test.rp2040.yaml rename to tests/components/key_collector/test.rp2040-ard.yaml diff --git a/tests/components/kmeteriso/test.esp32.yaml b/tests/components/kmeteriso/test.esp32-ard.yaml similarity index 100% rename from tests/components/kmeteriso/test.esp32.yaml rename to tests/components/kmeteriso/test.esp32-ard.yaml diff --git a/tests/components/kmeteriso/test.esp32-c3.yaml b/tests/components/kmeteriso/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/kmeteriso/test.esp32-c3.yaml rename to tests/components/kmeteriso/test.esp32-c3-ard.yaml diff --git a/tests/components/kmeteriso/test.esp8266.yaml b/tests/components/kmeteriso/test.esp8266-ard.yaml similarity index 100% rename from tests/components/kmeteriso/test.esp8266.yaml rename to tests/components/kmeteriso/test.esp8266-ard.yaml diff --git a/tests/components/kmeteriso/test.rp2040.yaml b/tests/components/kmeteriso/test.rp2040-ard.yaml similarity index 100% rename from tests/components/kmeteriso/test.rp2040.yaml rename to tests/components/kmeteriso/test.rp2040-ard.yaml diff --git a/tests/components/kuntze/test.esp32.yaml b/tests/components/kuntze/test.esp32-ard.yaml similarity index 100% rename from tests/components/kuntze/test.esp32.yaml rename to tests/components/kuntze/test.esp32-ard.yaml diff --git a/tests/components/kuntze/test.esp32-c3.yaml b/tests/components/kuntze/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/kuntze/test.esp32-c3.yaml rename to tests/components/kuntze/test.esp32-c3-ard.yaml diff --git a/tests/components/kuntze/test.esp8266.yaml b/tests/components/kuntze/test.esp8266-ard.yaml similarity index 100% rename from tests/components/kuntze/test.esp8266.yaml rename to tests/components/kuntze/test.esp8266-ard.yaml diff --git a/tests/components/kuntze/test.rp2040.yaml b/tests/components/kuntze/test.rp2040-ard.yaml similarity index 100% rename from tests/components/kuntze/test.rp2040.yaml rename to tests/components/kuntze/test.rp2040-ard.yaml diff --git a/tests/components/lcd_gpio/test.esp32.yaml b/tests/components/lcd_gpio/test.esp32-ard.yaml similarity index 100% rename from tests/components/lcd_gpio/test.esp32.yaml rename to tests/components/lcd_gpio/test.esp32-ard.yaml diff --git a/tests/components/lcd_gpio/test.esp32-c3.yaml b/tests/components/lcd_gpio/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/lcd_gpio/test.esp32-c3.yaml rename to tests/components/lcd_gpio/test.esp32-c3-ard.yaml diff --git a/tests/components/lcd_gpio/test.esp8266.yaml b/tests/components/lcd_gpio/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lcd_gpio/test.esp8266.yaml rename to tests/components/lcd_gpio/test.esp8266-ard.yaml diff --git a/tests/components/lcd_gpio/test.rp2040.yaml b/tests/components/lcd_gpio/test.rp2040-ard.yaml similarity index 100% rename from tests/components/lcd_gpio/test.rp2040.yaml rename to tests/components/lcd_gpio/test.rp2040-ard.yaml diff --git a/tests/components/lcd_menu/test.esp32.yaml b/tests/components/lcd_menu/test.esp32-ard.yaml similarity index 100% rename from tests/components/lcd_menu/test.esp32.yaml rename to tests/components/lcd_menu/test.esp32-ard.yaml diff --git a/tests/components/lcd_menu/test.esp32-c3.yaml b/tests/components/lcd_menu/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/lcd_menu/test.esp32-c3.yaml rename to tests/components/lcd_menu/test.esp32-c3-ard.yaml diff --git a/tests/components/lcd_menu/test.esp8266.yaml b/tests/components/lcd_menu/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lcd_menu/test.esp8266.yaml rename to tests/components/lcd_menu/test.esp8266-ard.yaml diff --git a/tests/components/lcd_menu/test.rp2040.yaml b/tests/components/lcd_menu/test.rp2040-ard.yaml similarity index 100% rename from tests/components/lcd_menu/test.rp2040.yaml rename to tests/components/lcd_menu/test.rp2040-ard.yaml diff --git a/tests/components/lcd_pcf8574/test.esp32.yaml b/tests/components/lcd_pcf8574/test.esp32-ard.yaml similarity index 100% rename from tests/components/lcd_pcf8574/test.esp32.yaml rename to tests/components/lcd_pcf8574/test.esp32-ard.yaml diff --git a/tests/components/lcd_pcf8574/test.esp32-c3.yaml b/tests/components/lcd_pcf8574/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/lcd_pcf8574/test.esp32-c3.yaml rename to tests/components/lcd_pcf8574/test.esp32-c3-ard.yaml diff --git a/tests/components/lcd_pcf8574/test.esp8266.yaml b/tests/components/lcd_pcf8574/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lcd_pcf8574/test.esp8266.yaml rename to tests/components/lcd_pcf8574/test.esp8266-ard.yaml diff --git a/tests/components/lcd_pcf8574/test.rp2040.yaml b/tests/components/lcd_pcf8574/test.rp2040-ard.yaml similarity index 100% rename from tests/components/lcd_pcf8574/test.rp2040.yaml rename to tests/components/lcd_pcf8574/test.rp2040-ard.yaml diff --git a/tests/components/ld2410/test.esp32.yaml b/tests/components/ld2410/test.esp32-ard.yaml similarity index 100% rename from tests/components/ld2410/test.esp32.yaml rename to tests/components/ld2410/test.esp32-ard.yaml diff --git a/tests/components/ld2410/test.esp32-c3.yaml b/tests/components/ld2410/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ld2410/test.esp32-c3.yaml rename to tests/components/ld2410/test.esp32-c3-ard.yaml diff --git a/tests/components/ld2410/test.esp8266.yaml b/tests/components/ld2410/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ld2410/test.esp8266.yaml rename to tests/components/ld2410/test.esp8266-ard.yaml diff --git a/tests/components/ld2410/test.rp2040.yaml b/tests/components/ld2410/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ld2410/test.rp2040.yaml rename to tests/components/ld2410/test.rp2040-ard.yaml diff --git a/tests/components/ld2420/test.esp32.yaml b/tests/components/ld2420/test.esp32-ard.yaml similarity index 100% rename from tests/components/ld2420/test.esp32.yaml rename to tests/components/ld2420/test.esp32-ard.yaml diff --git a/tests/components/ld2420/test.esp32-c3.yaml b/tests/components/ld2420/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ld2420/test.esp32-c3.yaml rename to tests/components/ld2420/test.esp32-c3-ard.yaml diff --git a/tests/components/ld2420/test.esp8266.yaml b/tests/components/ld2420/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ld2420/test.esp8266.yaml rename to tests/components/ld2420/test.esp8266-ard.yaml diff --git a/tests/components/ld2420/test.rp2040.yaml b/tests/components/ld2420/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ld2420/test.rp2040.yaml rename to tests/components/ld2420/test.rp2040-ard.yaml diff --git a/tests/components/ledc/test.esp32-c3.yaml b/tests/components/ledc/test.esp32-ard.yaml similarity index 100% rename from tests/components/ledc/test.esp32-c3.yaml rename to tests/components/ledc/test.esp32-ard.yaml diff --git a/tests/components/ledc/test.esp32.yaml b/tests/components/ledc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ledc/test.esp32.yaml rename to tests/components/ledc/test.esp32-c3-ard.yaml diff --git a/tests/components/light/test.esp32.yaml b/tests/components/light/test.esp32-ard.yaml similarity index 100% rename from tests/components/light/test.esp32.yaml rename to tests/components/light/test.esp32-ard.yaml diff --git a/tests/components/light/test.esp32-c3.yaml b/tests/components/light/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/light/test.esp32-c3.yaml rename to tests/components/light/test.esp32-c3-ard.yaml diff --git a/tests/components/light/test.esp8266.yaml b/tests/components/light/test.esp8266-ard.yaml similarity index 100% rename from tests/components/light/test.esp8266.yaml rename to tests/components/light/test.esp8266-ard.yaml diff --git a/tests/components/light/test.rp2040.yaml b/tests/components/light/test.rp2040-ard.yaml similarity index 100% rename from tests/components/light/test.rp2040.yaml rename to tests/components/light/test.rp2040-ard.yaml diff --git a/tests/components/lightwaverf/test.esp8266.yaml b/tests/components/lightwaverf/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lightwaverf/test.esp8266.yaml rename to tests/components/lightwaverf/test.esp8266-ard.yaml diff --git a/tests/components/lilygo_t5_47/test.esp32.yaml b/tests/components/lilygo_t5_47/test.esp32-ard.yaml similarity index 100% rename from tests/components/lilygo_t5_47/test.esp32.yaml rename to tests/components/lilygo_t5_47/test.esp32-ard.yaml diff --git a/tests/components/lilygo_t5_47/test.esp32-c3.yaml b/tests/components/lilygo_t5_47/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/lilygo_t5_47/test.esp32-c3.yaml rename to tests/components/lilygo_t5_47/test.esp32-c3-ard.yaml diff --git a/tests/components/lilygo_t5_47/test.esp8266.yaml b/tests/components/lilygo_t5_47/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lilygo_t5_47/test.esp8266.yaml rename to tests/components/lilygo_t5_47/test.esp8266-ard.yaml diff --git a/tests/components/lilygo_t5_47/test.rp2040.yaml b/tests/components/lilygo_t5_47/test.rp2040-ard.yaml similarity index 100% rename from tests/components/lilygo_t5_47/test.rp2040.yaml rename to tests/components/lilygo_t5_47/test.rp2040-ard.yaml diff --git a/tests/components/lock/test.esp32-c3.yaml b/tests/components/lock/test.esp32-ard.yaml similarity index 100% rename from tests/components/lock/test.esp32-c3.yaml rename to tests/components/lock/test.esp32-ard.yaml diff --git a/tests/components/lock/test.esp32.yaml b/tests/components/lock/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/lock/test.esp32.yaml rename to tests/components/lock/test.esp32-c3-ard.yaml diff --git a/tests/components/lock/test.esp8266.yaml b/tests/components/lock/test.esp8266-ard.yaml similarity index 100% rename from tests/components/lock/test.esp8266.yaml rename to tests/components/lock/test.esp8266-ard.yaml diff --git a/tests/components/lock/test.rp2040.yaml b/tests/components/lock/test.rp2040-ard.yaml similarity index 100% rename from tests/components/lock/test.rp2040.yaml rename to tests/components/lock/test.rp2040-ard.yaml diff --git a/tests/components/logger/test.esp32-c3.yaml b/tests/components/logger/test.esp32-ard.yaml similarity index 100% rename from tests/components/logger/test.esp32-c3.yaml rename to tests/components/logger/test.esp32-ard.yaml diff --git a/tests/components/logger/test.esp32.yaml b/tests/components/logger/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/logger/test.esp32.yaml rename to tests/components/logger/test.esp32-c3-ard.yaml diff --git a/tests/components/logger/test.esp8266.yaml b/tests/components/logger/test.esp8266-ard.yaml similarity index 100% rename from tests/components/logger/test.esp8266.yaml rename to tests/components/logger/test.esp8266-ard.yaml diff --git a/tests/components/logger/test.rp2040.yaml b/tests/components/logger/test.rp2040-ard.yaml similarity index 100% rename from tests/components/logger/test.rp2040.yaml rename to tests/components/logger/test.rp2040-ard.yaml diff --git a/tests/components/ltr390/test.esp32.yaml b/tests/components/ltr390/test.esp32-ard.yaml similarity index 100% rename from tests/components/ltr390/test.esp32.yaml rename to tests/components/ltr390/test.esp32-ard.yaml diff --git a/tests/components/ltr390/test.esp32-c3.yaml b/tests/components/ltr390/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ltr390/test.esp32-c3.yaml rename to tests/components/ltr390/test.esp32-c3-ard.yaml diff --git a/tests/components/ltr390/test.esp8266.yaml b/tests/components/ltr390/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ltr390/test.esp8266.yaml rename to tests/components/ltr390/test.esp8266-ard.yaml diff --git a/tests/components/ltr390/test.rp2040.yaml b/tests/components/ltr390/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ltr390/test.rp2040.yaml rename to tests/components/ltr390/test.rp2040-ard.yaml diff --git a/tests/components/ltr_als_ps/test.esp32.yaml b/tests/components/ltr_als_ps/test.esp32-ard.yaml similarity index 100% rename from tests/components/ltr_als_ps/test.esp32.yaml rename to tests/components/ltr_als_ps/test.esp32-ard.yaml diff --git a/tests/components/ltr_als_ps/test.esp32-c3.yaml b/tests/components/ltr_als_ps/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ltr_als_ps/test.esp32-c3.yaml rename to tests/components/ltr_als_ps/test.esp32-c3-ard.yaml diff --git a/tests/components/ltr_als_ps/test.esp8266.yaml b/tests/components/ltr_als_ps/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ltr_als_ps/test.esp8266.yaml rename to tests/components/ltr_als_ps/test.esp8266-ard.yaml diff --git a/tests/components/ltr_als_ps/test.rp2040.yaml b/tests/components/ltr_als_ps/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ltr_als_ps/test.rp2040.yaml rename to tests/components/ltr_als_ps/test.rp2040-ard.yaml diff --git a/tests/components/matrix_keypad/test.esp32.yaml b/tests/components/matrix_keypad/test.esp32-ard.yaml similarity index 100% rename from tests/components/matrix_keypad/test.esp32.yaml rename to tests/components/matrix_keypad/test.esp32-ard.yaml diff --git a/tests/components/matrix_keypad/test.esp32-c3.yaml b/tests/components/matrix_keypad/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/matrix_keypad/test.esp32-c3.yaml rename to tests/components/matrix_keypad/test.esp32-c3-ard.yaml diff --git a/tests/components/matrix_keypad/test.esp8266.yaml b/tests/components/matrix_keypad/test.esp8266-ard.yaml similarity index 100% rename from tests/components/matrix_keypad/test.esp8266.yaml rename to tests/components/matrix_keypad/test.esp8266-ard.yaml diff --git a/tests/components/matrix_keypad/test.rp2040.yaml b/tests/components/matrix_keypad/test.rp2040-ard.yaml similarity index 100% rename from tests/components/matrix_keypad/test.rp2040.yaml rename to tests/components/matrix_keypad/test.rp2040-ard.yaml diff --git a/tests/components/max31855/test.esp32.yaml b/tests/components/max31855/test.esp32-ard.yaml similarity index 100% rename from tests/components/max31855/test.esp32.yaml rename to tests/components/max31855/test.esp32-ard.yaml diff --git a/tests/components/max31855/test.esp32-c3.yaml b/tests/components/max31855/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max31855/test.esp32-c3.yaml rename to tests/components/max31855/test.esp32-c3-ard.yaml diff --git a/tests/components/max31855/test.esp8266.yaml b/tests/components/max31855/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max31855/test.esp8266.yaml rename to tests/components/max31855/test.esp8266-ard.yaml diff --git a/tests/components/max31855/test.rp2040.yaml b/tests/components/max31855/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max31855/test.rp2040.yaml rename to tests/components/max31855/test.rp2040-ard.yaml diff --git a/tests/components/max31856/test.esp32.yaml b/tests/components/max31856/test.esp32-ard.yaml similarity index 100% rename from tests/components/max31856/test.esp32.yaml rename to tests/components/max31856/test.esp32-ard.yaml diff --git a/tests/components/max31856/test.esp32-c3.yaml b/tests/components/max31856/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max31856/test.esp32-c3.yaml rename to tests/components/max31856/test.esp32-c3-ard.yaml diff --git a/tests/components/max31856/test.esp8266.yaml b/tests/components/max31856/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max31856/test.esp8266.yaml rename to tests/components/max31856/test.esp8266-ard.yaml diff --git a/tests/components/max31856/test.rp2040.yaml b/tests/components/max31856/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max31856/test.rp2040.yaml rename to tests/components/max31856/test.rp2040-ard.yaml diff --git a/tests/components/max31865/test.esp32.yaml b/tests/components/max31865/test.esp32-ard.yaml similarity index 100% rename from tests/components/max31865/test.esp32.yaml rename to tests/components/max31865/test.esp32-ard.yaml diff --git a/tests/components/max31865/test.esp32-c3.yaml b/tests/components/max31865/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max31865/test.esp32-c3.yaml rename to tests/components/max31865/test.esp32-c3-ard.yaml diff --git a/tests/components/max31865/test.esp8266.yaml b/tests/components/max31865/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max31865/test.esp8266.yaml rename to tests/components/max31865/test.esp8266-ard.yaml diff --git a/tests/components/max31865/test.rp2040.yaml b/tests/components/max31865/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max31865/test.rp2040.yaml rename to tests/components/max31865/test.rp2040-ard.yaml diff --git a/tests/components/max44009/test.esp32.yaml b/tests/components/max44009/test.esp32-ard.yaml similarity index 100% rename from tests/components/max44009/test.esp32.yaml rename to tests/components/max44009/test.esp32-ard.yaml diff --git a/tests/components/max44009/test.esp32-c3.yaml b/tests/components/max44009/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max44009/test.esp32-c3.yaml rename to tests/components/max44009/test.esp32-c3-ard.yaml diff --git a/tests/components/max44009/test.esp8266.yaml b/tests/components/max44009/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max44009/test.esp8266.yaml rename to tests/components/max44009/test.esp8266-ard.yaml diff --git a/tests/components/max44009/test.rp2040.yaml b/tests/components/max44009/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max44009/test.rp2040.yaml rename to tests/components/max44009/test.rp2040-ard.yaml diff --git a/tests/components/max6675/test.esp32.yaml b/tests/components/max6675/test.esp32-ard.yaml similarity index 100% rename from tests/components/max6675/test.esp32.yaml rename to tests/components/max6675/test.esp32-ard.yaml diff --git a/tests/components/max6675/test.esp32-c3.yaml b/tests/components/max6675/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max6675/test.esp32-c3.yaml rename to tests/components/max6675/test.esp32-c3-ard.yaml diff --git a/tests/components/max6675/test.esp8266.yaml b/tests/components/max6675/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max6675/test.esp8266.yaml rename to tests/components/max6675/test.esp8266-ard.yaml diff --git a/tests/components/max6675/test.rp2040.yaml b/tests/components/max6675/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max6675/test.rp2040.yaml rename to tests/components/max6675/test.rp2040-ard.yaml diff --git a/tests/components/max6956/test.esp32.yaml b/tests/components/max6956/test.esp32-ard.yaml similarity index 100% rename from tests/components/max6956/test.esp32.yaml rename to tests/components/max6956/test.esp32-ard.yaml diff --git a/tests/components/max6956/test.esp32-c3.yaml b/tests/components/max6956/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max6956/test.esp32-c3.yaml rename to tests/components/max6956/test.esp32-c3-ard.yaml diff --git a/tests/components/max6956/test.esp8266.yaml b/tests/components/max6956/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max6956/test.esp8266.yaml rename to tests/components/max6956/test.esp8266-ard.yaml diff --git a/tests/components/max6956/test.rp2040.yaml b/tests/components/max6956/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max6956/test.rp2040.yaml rename to tests/components/max6956/test.rp2040-ard.yaml diff --git a/tests/components/max7219/test.esp32.yaml b/tests/components/max7219/test.esp32-ard.yaml similarity index 100% rename from tests/components/max7219/test.esp32.yaml rename to tests/components/max7219/test.esp32-ard.yaml diff --git a/tests/components/max7219/test.esp32-c3.yaml b/tests/components/max7219/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max7219/test.esp32-c3.yaml rename to tests/components/max7219/test.esp32-c3-ard.yaml diff --git a/tests/components/max7219/test.esp8266.yaml b/tests/components/max7219/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max7219/test.esp8266.yaml rename to tests/components/max7219/test.esp8266-ard.yaml diff --git a/tests/components/max7219/test.rp2040.yaml b/tests/components/max7219/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max7219/test.rp2040.yaml rename to tests/components/max7219/test.rp2040-ard.yaml diff --git a/tests/components/max7219digit/test.esp32.yaml b/tests/components/max7219digit/test.esp32-ard.yaml similarity index 100% rename from tests/components/max7219digit/test.esp32.yaml rename to tests/components/max7219digit/test.esp32-ard.yaml diff --git a/tests/components/max7219digit/test.esp32-c3.yaml b/tests/components/max7219digit/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max7219digit/test.esp32-c3.yaml rename to tests/components/max7219digit/test.esp32-c3-ard.yaml diff --git a/tests/components/max7219digit/test.esp8266.yaml b/tests/components/max7219digit/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max7219digit/test.esp8266.yaml rename to tests/components/max7219digit/test.esp8266-ard.yaml diff --git a/tests/components/max7219digit/test.rp2040.yaml b/tests/components/max7219digit/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max7219digit/test.rp2040.yaml rename to tests/components/max7219digit/test.rp2040-ard.yaml diff --git a/tests/components/max9611/test.esp32.yaml b/tests/components/max9611/test.esp32-ard.yaml similarity index 100% rename from tests/components/max9611/test.esp32.yaml rename to tests/components/max9611/test.esp32-ard.yaml diff --git a/tests/components/max9611/test.esp32-c3.yaml b/tests/components/max9611/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/max9611/test.esp32-c3.yaml rename to tests/components/max9611/test.esp32-c3-ard.yaml diff --git a/tests/components/max9611/test.esp8266.yaml b/tests/components/max9611/test.esp8266-ard.yaml similarity index 100% rename from tests/components/max9611/test.esp8266.yaml rename to tests/components/max9611/test.esp8266-ard.yaml diff --git a/tests/components/max9611/test.rp2040.yaml b/tests/components/max9611/test.rp2040-ard.yaml similarity index 100% rename from tests/components/max9611/test.rp2040.yaml rename to tests/components/max9611/test.rp2040-ard.yaml diff --git a/tests/components/mcp23008/test.esp32.yaml b/tests/components/mcp23008/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp23008/test.esp32.yaml rename to tests/components/mcp23008/test.esp32-ard.yaml diff --git a/tests/components/mcp23008/test.esp32-c3.yaml b/tests/components/mcp23008/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp23008/test.esp32-c3.yaml rename to tests/components/mcp23008/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp23008/test.esp8266.yaml b/tests/components/mcp23008/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp23008/test.esp8266.yaml rename to tests/components/mcp23008/test.esp8266-ard.yaml diff --git a/tests/components/mcp23008/test.rp2040.yaml b/tests/components/mcp23008/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp23008/test.rp2040.yaml rename to tests/components/mcp23008/test.rp2040-ard.yaml diff --git a/tests/components/mcp23016/test.esp32.yaml b/tests/components/mcp23016/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp23016/test.esp32.yaml rename to tests/components/mcp23016/test.esp32-ard.yaml diff --git a/tests/components/mcp23016/test.esp32-c3.yaml b/tests/components/mcp23016/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp23016/test.esp32-c3.yaml rename to tests/components/mcp23016/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp23016/test.esp8266.yaml b/tests/components/mcp23016/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp23016/test.esp8266.yaml rename to tests/components/mcp23016/test.esp8266-ard.yaml diff --git a/tests/components/mcp23016/test.rp2040.yaml b/tests/components/mcp23016/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp23016/test.rp2040.yaml rename to tests/components/mcp23016/test.rp2040-ard.yaml diff --git a/tests/components/mcp23017/test.esp32.yaml b/tests/components/mcp23017/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp23017/test.esp32.yaml rename to tests/components/mcp23017/test.esp32-ard.yaml diff --git a/tests/components/mcp23017/test.esp32-c3.yaml b/tests/components/mcp23017/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp23017/test.esp32-c3.yaml rename to tests/components/mcp23017/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp23017/test.esp8266.yaml b/tests/components/mcp23017/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp23017/test.esp8266.yaml rename to tests/components/mcp23017/test.esp8266-ard.yaml diff --git a/tests/components/mcp23017/test.rp2040.yaml b/tests/components/mcp23017/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp23017/test.rp2040.yaml rename to tests/components/mcp23017/test.rp2040-ard.yaml diff --git a/tests/components/mcp23s08/test.esp32.yaml b/tests/components/mcp23s08/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp23s08/test.esp32.yaml rename to tests/components/mcp23s08/test.esp32-ard.yaml diff --git a/tests/components/mcp23s08/test.esp32-c3.yaml b/tests/components/mcp23s08/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp23s08/test.esp32-c3.yaml rename to tests/components/mcp23s08/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp23s08/test.esp8266.yaml b/tests/components/mcp23s08/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp23s08/test.esp8266.yaml rename to tests/components/mcp23s08/test.esp8266-ard.yaml diff --git a/tests/components/mcp23s08/test.rp2040.yaml b/tests/components/mcp23s08/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp23s08/test.rp2040.yaml rename to tests/components/mcp23s08/test.rp2040-ard.yaml diff --git a/tests/components/mcp23s17/test.esp32.yaml b/tests/components/mcp23s17/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp23s17/test.esp32.yaml rename to tests/components/mcp23s17/test.esp32-ard.yaml diff --git a/tests/components/mcp23s17/test.esp32-c3.yaml b/tests/components/mcp23s17/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp23s17/test.esp32-c3.yaml rename to tests/components/mcp23s17/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp23s17/test.esp8266.yaml b/tests/components/mcp23s17/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp23s17/test.esp8266.yaml rename to tests/components/mcp23s17/test.esp8266-ard.yaml diff --git a/tests/components/mcp23s17/test.rp2040.yaml b/tests/components/mcp23s17/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp23s17/test.rp2040.yaml rename to tests/components/mcp23s17/test.rp2040-ard.yaml diff --git a/tests/components/mcp2515/test.esp32.yaml b/tests/components/mcp2515/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp2515/test.esp32.yaml rename to tests/components/mcp2515/test.esp32-ard.yaml diff --git a/tests/components/mcp2515/test.esp32-c3.yaml b/tests/components/mcp2515/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp2515/test.esp32-c3.yaml rename to tests/components/mcp2515/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp2515/test.esp8266.yaml b/tests/components/mcp2515/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp2515/test.esp8266.yaml rename to tests/components/mcp2515/test.esp8266-ard.yaml diff --git a/tests/components/mcp2515/test.rp2040.yaml b/tests/components/mcp2515/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp2515/test.rp2040.yaml rename to tests/components/mcp2515/test.rp2040-ard.yaml diff --git a/tests/components/mcp3008/test.esp32.yaml b/tests/components/mcp3008/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp3008/test.esp32.yaml rename to tests/components/mcp3008/test.esp32-ard.yaml diff --git a/tests/components/mcp3008/test.esp32-c3.yaml b/tests/components/mcp3008/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp3008/test.esp32-c3.yaml rename to tests/components/mcp3008/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp3008/test.esp8266.yaml b/tests/components/mcp3008/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp3008/test.esp8266.yaml rename to tests/components/mcp3008/test.esp8266-ard.yaml diff --git a/tests/components/mcp3008/test.rp2040.yaml b/tests/components/mcp3008/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp3008/test.rp2040.yaml rename to tests/components/mcp3008/test.rp2040-ard.yaml diff --git a/tests/components/mcp3204/test.esp32.yaml b/tests/components/mcp3204/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp3204/test.esp32.yaml rename to tests/components/mcp3204/test.esp32-ard.yaml diff --git a/tests/components/mcp3204/test.esp32-c3.yaml b/tests/components/mcp3204/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp3204/test.esp32-c3.yaml rename to tests/components/mcp3204/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp3204/test.esp8266.yaml b/tests/components/mcp3204/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp3204/test.esp8266.yaml rename to tests/components/mcp3204/test.esp8266-ard.yaml diff --git a/tests/components/mcp3204/test.rp2040.yaml b/tests/components/mcp3204/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp3204/test.rp2040.yaml rename to tests/components/mcp3204/test.rp2040-ard.yaml diff --git a/tests/components/mcp4725/test.esp32.yaml b/tests/components/mcp4725/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp4725/test.esp32.yaml rename to tests/components/mcp4725/test.esp32-ard.yaml diff --git a/tests/components/mcp4725/test.esp32-c3.yaml b/tests/components/mcp4725/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp4725/test.esp32-c3.yaml rename to tests/components/mcp4725/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp4725/test.esp8266.yaml b/tests/components/mcp4725/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp4725/test.esp8266.yaml rename to tests/components/mcp4725/test.esp8266-ard.yaml diff --git a/tests/components/mcp4725/test.rp2040.yaml b/tests/components/mcp4725/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp4725/test.rp2040.yaml rename to tests/components/mcp4725/test.rp2040-ard.yaml diff --git a/tests/components/mcp4728/test.esp32.yaml b/tests/components/mcp4728/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp4728/test.esp32.yaml rename to tests/components/mcp4728/test.esp32-ard.yaml diff --git a/tests/components/mcp4728/test.esp32-c3.yaml b/tests/components/mcp4728/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp4728/test.esp32-c3.yaml rename to tests/components/mcp4728/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp4728/test.esp8266.yaml b/tests/components/mcp4728/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp4728/test.esp8266.yaml rename to tests/components/mcp4728/test.esp8266-ard.yaml diff --git a/tests/components/mcp4728/test.rp2040.yaml b/tests/components/mcp4728/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp4728/test.rp2040.yaml rename to tests/components/mcp4728/test.rp2040-ard.yaml diff --git a/tests/components/mcp47a1/test.esp32.yaml b/tests/components/mcp47a1/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp47a1/test.esp32.yaml rename to tests/components/mcp47a1/test.esp32-ard.yaml diff --git a/tests/components/mcp47a1/test.esp32-c3.yaml b/tests/components/mcp47a1/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp47a1/test.esp32-c3.yaml rename to tests/components/mcp47a1/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp47a1/test.esp8266.yaml b/tests/components/mcp47a1/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp47a1/test.esp8266.yaml rename to tests/components/mcp47a1/test.esp8266-ard.yaml diff --git a/tests/components/mcp47a1/test.rp2040.yaml b/tests/components/mcp47a1/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp47a1/test.rp2040.yaml rename to tests/components/mcp47a1/test.rp2040-ard.yaml diff --git a/tests/components/mcp9600/test.esp32.yaml b/tests/components/mcp9600/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp9600/test.esp32.yaml rename to tests/components/mcp9600/test.esp32-ard.yaml diff --git a/tests/components/mcp9600/test.esp32-c3.yaml b/tests/components/mcp9600/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp9600/test.esp32-c3.yaml rename to tests/components/mcp9600/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp9600/test.esp8266.yaml b/tests/components/mcp9600/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp9600/test.esp8266.yaml rename to tests/components/mcp9600/test.esp8266-ard.yaml diff --git a/tests/components/mcp9600/test.rp2040.yaml b/tests/components/mcp9600/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp9600/test.rp2040.yaml rename to tests/components/mcp9600/test.rp2040-ard.yaml diff --git a/tests/components/mcp9808/test.esp32.yaml b/tests/components/mcp9808/test.esp32-ard.yaml similarity index 100% rename from tests/components/mcp9808/test.esp32.yaml rename to tests/components/mcp9808/test.esp32-ard.yaml diff --git a/tests/components/mcp9808/test.esp32-c3.yaml b/tests/components/mcp9808/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mcp9808/test.esp32-c3.yaml rename to tests/components/mcp9808/test.esp32-c3-ard.yaml diff --git a/tests/components/mcp9808/test.esp8266.yaml b/tests/components/mcp9808/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mcp9808/test.esp8266.yaml rename to tests/components/mcp9808/test.esp8266-ard.yaml diff --git a/tests/components/mcp9808/test.rp2040.yaml b/tests/components/mcp9808/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mcp9808/test.rp2040.yaml rename to tests/components/mcp9808/test.rp2040-ard.yaml diff --git a/tests/components/mdns/test.esp32-c3.yaml b/tests/components/mdns/test.esp32-ard.yaml similarity index 100% rename from tests/components/mdns/test.esp32-c3.yaml rename to tests/components/mdns/test.esp32-ard.yaml diff --git a/tests/components/mdns/test.esp32.yaml b/tests/components/mdns/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mdns/test.esp32.yaml rename to tests/components/mdns/test.esp32-c3-ard.yaml diff --git a/tests/components/mdns/test.esp8266.yaml b/tests/components/mdns/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mdns/test.esp8266.yaml rename to tests/components/mdns/test.esp8266-ard.yaml diff --git a/tests/components/mdns/test.rp2040.yaml b/tests/components/mdns/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mdns/test.rp2040.yaml rename to tests/components/mdns/test.rp2040-ard.yaml diff --git a/tests/components/media_player/test.esp32.yaml b/tests/components/media_player/test.esp32-ard.yaml similarity index 100% rename from tests/components/media_player/test.esp32.yaml rename to tests/components/media_player/test.esp32-ard.yaml diff --git a/tests/components/mhz19/test.esp32.yaml b/tests/components/mhz19/test.esp32-ard.yaml similarity index 100% rename from tests/components/mhz19/test.esp32.yaml rename to tests/components/mhz19/test.esp32-ard.yaml diff --git a/tests/components/mhz19/test.esp32-c3.yaml b/tests/components/mhz19/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mhz19/test.esp32-c3.yaml rename to tests/components/mhz19/test.esp32-c3-ard.yaml diff --git a/tests/components/mhz19/test.esp8266.yaml b/tests/components/mhz19/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mhz19/test.esp8266.yaml rename to tests/components/mhz19/test.esp8266-ard.yaml diff --git a/tests/components/mhz19/test.rp2040.yaml b/tests/components/mhz19/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mhz19/test.rp2040.yaml rename to tests/components/mhz19/test.rp2040-ard.yaml diff --git a/tests/components/micronova/test.esp32.yaml b/tests/components/micronova/test.esp32-ard.yaml similarity index 100% rename from tests/components/micronova/test.esp32.yaml rename to tests/components/micronova/test.esp32-ard.yaml diff --git a/tests/components/micronova/test.esp32-c3.yaml b/tests/components/micronova/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/micronova/test.esp32-c3.yaml rename to tests/components/micronova/test.esp32-c3-ard.yaml diff --git a/tests/components/micronova/test.esp8266.yaml b/tests/components/micronova/test.esp8266-ard.yaml similarity index 100% rename from tests/components/micronova/test.esp8266.yaml rename to tests/components/micronova/test.esp8266-ard.yaml diff --git a/tests/components/micronova/test.rp2040.yaml b/tests/components/micronova/test.rp2040-ard.yaml similarity index 100% rename from tests/components/micronova/test.rp2040.yaml rename to tests/components/micronova/test.rp2040-ard.yaml diff --git a/tests/components/microphone/test.esp32.yaml b/tests/components/microphone/test.esp32-ard.yaml similarity index 100% rename from tests/components/microphone/test.esp32.yaml rename to tests/components/microphone/test.esp32-ard.yaml diff --git a/tests/components/microphone/test.esp32-c3.yaml b/tests/components/microphone/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/microphone/test.esp32-c3.yaml rename to tests/components/microphone/test.esp32-c3-ard.yaml diff --git a/tests/components/mics_4514/test.esp32.yaml b/tests/components/mics_4514/test.esp32-ard.yaml similarity index 100% rename from tests/components/mics_4514/test.esp32.yaml rename to tests/components/mics_4514/test.esp32-ard.yaml diff --git a/tests/components/mics_4514/test.esp32-c3.yaml b/tests/components/mics_4514/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mics_4514/test.esp32-c3.yaml rename to tests/components/mics_4514/test.esp32-c3-ard.yaml diff --git a/tests/components/mics_4514/test.esp8266.yaml b/tests/components/mics_4514/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mics_4514/test.esp8266.yaml rename to tests/components/mics_4514/test.esp8266-ard.yaml diff --git a/tests/components/mics_4514/test.rp2040.yaml b/tests/components/mics_4514/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mics_4514/test.rp2040.yaml rename to tests/components/mics_4514/test.rp2040-ard.yaml diff --git a/tests/components/midea/test.esp32.yaml b/tests/components/midea/test.esp32-ard.yaml similarity index 100% rename from tests/components/midea/test.esp32.yaml rename to tests/components/midea/test.esp32-ard.yaml diff --git a/tests/components/midea/test.esp32-c3.yaml b/tests/components/midea/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/midea/test.esp32-c3.yaml rename to tests/components/midea/test.esp32-c3-ard.yaml diff --git a/tests/components/midea/test.esp8266.yaml b/tests/components/midea/test.esp8266-ard.yaml similarity index 100% rename from tests/components/midea/test.esp8266.yaml rename to tests/components/midea/test.esp8266-ard.yaml diff --git a/tests/components/midea_ir/test.esp32-c3.yaml b/tests/components/midea_ir/test.esp32-ard.yaml similarity index 100% rename from tests/components/midea_ir/test.esp32-c3.yaml rename to tests/components/midea_ir/test.esp32-ard.yaml diff --git a/tests/components/midea_ir/test.esp32.yaml b/tests/components/midea_ir/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/midea_ir/test.esp32.yaml rename to tests/components/midea_ir/test.esp32-c3-ard.yaml diff --git a/tests/components/midea_ir/test.esp8266.yaml b/tests/components/midea_ir/test.esp8266-ard.yaml similarity index 100% rename from tests/components/midea_ir/test.esp8266.yaml rename to tests/components/midea_ir/test.esp8266-ard.yaml diff --git a/tests/components/mitsubishi/test.esp32-c3.yaml b/tests/components/mitsubishi/test.esp32-ard.yaml similarity index 100% rename from tests/components/mitsubishi/test.esp32-c3.yaml rename to tests/components/mitsubishi/test.esp32-ard.yaml diff --git a/tests/components/mitsubishi/test.esp32.yaml b/tests/components/mitsubishi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mitsubishi/test.esp32.yaml rename to tests/components/mitsubishi/test.esp32-c3-ard.yaml diff --git a/tests/components/mitsubishi/test.esp8266.yaml b/tests/components/mitsubishi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mitsubishi/test.esp8266.yaml rename to tests/components/mitsubishi/test.esp8266-ard.yaml diff --git a/tests/components/mlx90393/test.esp32.yaml b/tests/components/mlx90393/test.esp32-ard.yaml similarity index 100% rename from tests/components/mlx90393/test.esp32.yaml rename to tests/components/mlx90393/test.esp32-ard.yaml diff --git a/tests/components/mlx90393/test.esp32-c3.yaml b/tests/components/mlx90393/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mlx90393/test.esp32-c3.yaml rename to tests/components/mlx90393/test.esp32-c3-ard.yaml diff --git a/tests/components/mlx90393/test.esp8266.yaml b/tests/components/mlx90393/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mlx90393/test.esp8266.yaml rename to tests/components/mlx90393/test.esp8266-ard.yaml diff --git a/tests/components/mlx90393/test.rp2040.yaml b/tests/components/mlx90393/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mlx90393/test.rp2040.yaml rename to tests/components/mlx90393/test.rp2040-ard.yaml diff --git a/tests/components/mlx90614/test.esp32.yaml b/tests/components/mlx90614/test.esp32-ard.yaml similarity index 100% rename from tests/components/mlx90614/test.esp32.yaml rename to tests/components/mlx90614/test.esp32-ard.yaml diff --git a/tests/components/mlx90614/test.esp32-c3.yaml b/tests/components/mlx90614/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mlx90614/test.esp32-c3.yaml rename to tests/components/mlx90614/test.esp32-c3-ard.yaml diff --git a/tests/components/mlx90614/test.esp8266.yaml b/tests/components/mlx90614/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mlx90614/test.esp8266.yaml rename to tests/components/mlx90614/test.esp8266-ard.yaml diff --git a/tests/components/mlx90614/test.rp2040.yaml b/tests/components/mlx90614/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mlx90614/test.rp2040.yaml rename to tests/components/mlx90614/test.rp2040-ard.yaml diff --git a/tests/components/mmc5603/test.esp32.yaml b/tests/components/mmc5603/test.esp32-ard.yaml similarity index 100% rename from tests/components/mmc5603/test.esp32.yaml rename to tests/components/mmc5603/test.esp32-ard.yaml diff --git a/tests/components/mmc5603/test.esp32-c3.yaml b/tests/components/mmc5603/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mmc5603/test.esp32-c3.yaml rename to tests/components/mmc5603/test.esp32-c3-ard.yaml diff --git a/tests/components/mmc5603/test.esp8266.yaml b/tests/components/mmc5603/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mmc5603/test.esp8266.yaml rename to tests/components/mmc5603/test.esp8266-ard.yaml diff --git a/tests/components/mmc5603/test.rp2040.yaml b/tests/components/mmc5603/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mmc5603/test.rp2040.yaml rename to tests/components/mmc5603/test.rp2040-ard.yaml diff --git a/tests/components/mmc5983/test.esp32.yaml b/tests/components/mmc5983/test.esp32-ard.yaml similarity index 100% rename from tests/components/mmc5983/test.esp32.yaml rename to tests/components/mmc5983/test.esp32-ard.yaml diff --git a/tests/components/mmc5983/test.esp32-c3.yaml b/tests/components/mmc5983/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mmc5983/test.esp32-c3.yaml rename to tests/components/mmc5983/test.esp32-c3-ard.yaml diff --git a/tests/components/mmc5983/test.esp8266.yaml b/tests/components/mmc5983/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mmc5983/test.esp8266.yaml rename to tests/components/mmc5983/test.esp8266-ard.yaml diff --git a/tests/components/mmc5983/test.rp2040.yaml b/tests/components/mmc5983/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mmc5983/test.rp2040.yaml rename to tests/components/mmc5983/test.rp2040-ard.yaml diff --git a/tests/components/modbus/test.esp32.yaml b/tests/components/modbus/test.esp32-ard.yaml similarity index 100% rename from tests/components/modbus/test.esp32.yaml rename to tests/components/modbus/test.esp32-ard.yaml diff --git a/tests/components/modbus/test.esp32-c3.yaml b/tests/components/modbus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/modbus/test.esp32-c3.yaml rename to tests/components/modbus/test.esp32-c3-ard.yaml diff --git a/tests/components/modbus/test.esp8266.yaml b/tests/components/modbus/test.esp8266-ard.yaml similarity index 100% rename from tests/components/modbus/test.esp8266.yaml rename to tests/components/modbus/test.esp8266-ard.yaml diff --git a/tests/components/modbus/test.rp2040.yaml b/tests/components/modbus/test.rp2040-ard.yaml similarity index 100% rename from tests/components/modbus/test.rp2040.yaml rename to tests/components/modbus/test.rp2040-ard.yaml diff --git a/tests/components/modbus_controller/test.esp32.yaml b/tests/components/modbus_controller/test.esp32-ard.yaml similarity index 100% rename from tests/components/modbus_controller/test.esp32.yaml rename to tests/components/modbus_controller/test.esp32-ard.yaml diff --git a/tests/components/modbus_controller/test.esp32-c3.yaml b/tests/components/modbus_controller/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/modbus_controller/test.esp32-c3.yaml rename to tests/components/modbus_controller/test.esp32-c3-ard.yaml diff --git a/tests/components/modbus_controller/test.esp8266.yaml b/tests/components/modbus_controller/test.esp8266-ard.yaml similarity index 100% rename from tests/components/modbus_controller/test.esp8266.yaml rename to tests/components/modbus_controller/test.esp8266-ard.yaml diff --git a/tests/components/modbus_controller/test.rp2040.yaml b/tests/components/modbus_controller/test.rp2040-ard.yaml similarity index 100% rename from tests/components/modbus_controller/test.rp2040.yaml rename to tests/components/modbus_controller/test.rp2040-ard.yaml diff --git a/tests/components/monochromatic/test.esp32-c3.yaml b/tests/components/monochromatic/test.esp32-ard.yaml similarity index 100% rename from tests/components/monochromatic/test.esp32-c3.yaml rename to tests/components/monochromatic/test.esp32-ard.yaml diff --git a/tests/components/monochromatic/test.esp32.yaml b/tests/components/monochromatic/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/monochromatic/test.esp32.yaml rename to tests/components/monochromatic/test.esp32-c3-ard.yaml diff --git a/tests/components/monochromatic/test.esp8266.yaml b/tests/components/monochromatic/test.esp8266-ard.yaml similarity index 100% rename from tests/components/monochromatic/test.esp8266.yaml rename to tests/components/monochromatic/test.esp8266-ard.yaml diff --git a/tests/components/monochromatic/test.rp2040.yaml b/tests/components/monochromatic/test.rp2040-ard.yaml similarity index 100% rename from tests/components/monochromatic/test.rp2040.yaml rename to tests/components/monochromatic/test.rp2040-ard.yaml diff --git a/tests/components/mopeka_ble/test.esp32-c3.yaml b/tests/components/mopeka_ble/test.esp32-ard.yaml similarity index 100% rename from tests/components/mopeka_ble/test.esp32-c3.yaml rename to tests/components/mopeka_ble/test.esp32-ard.yaml diff --git a/tests/components/mopeka_ble/test.esp32.yaml b/tests/components/mopeka_ble/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mopeka_ble/test.esp32.yaml rename to tests/components/mopeka_ble/test.esp32-c3-ard.yaml diff --git a/tests/components/mopeka_pro_check/test.esp32-c3.yaml b/tests/components/mopeka_pro_check/test.esp32-ard.yaml similarity index 100% rename from tests/components/mopeka_pro_check/test.esp32-c3.yaml rename to tests/components/mopeka_pro_check/test.esp32-ard.yaml diff --git a/tests/components/mopeka_pro_check/test.esp32.yaml b/tests/components/mopeka_pro_check/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mopeka_pro_check/test.esp32.yaml rename to tests/components/mopeka_pro_check/test.esp32-c3-ard.yaml diff --git a/tests/components/mopeka_std_check/test.esp32-c3.yaml b/tests/components/mopeka_std_check/test.esp32-ard.yaml similarity index 100% rename from tests/components/mopeka_std_check/test.esp32-c3.yaml rename to tests/components/mopeka_std_check/test.esp32-ard.yaml diff --git a/tests/components/mopeka_std_check/test.esp32.yaml b/tests/components/mopeka_std_check/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mopeka_std_check/test.esp32.yaml rename to tests/components/mopeka_std_check/test.esp32-c3-ard.yaml diff --git a/tests/components/mpl3115a2/test.esp32.yaml b/tests/components/mpl3115a2/test.esp32-ard.yaml similarity index 100% rename from tests/components/mpl3115a2/test.esp32.yaml rename to tests/components/mpl3115a2/test.esp32-ard.yaml diff --git a/tests/components/mpl3115a2/test.esp32-c3.yaml b/tests/components/mpl3115a2/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mpl3115a2/test.esp32-c3.yaml rename to tests/components/mpl3115a2/test.esp32-c3-ard.yaml diff --git a/tests/components/mpl3115a2/test.esp8266.yaml b/tests/components/mpl3115a2/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mpl3115a2/test.esp8266.yaml rename to tests/components/mpl3115a2/test.esp8266-ard.yaml diff --git a/tests/components/mpl3115a2/test.rp2040.yaml b/tests/components/mpl3115a2/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mpl3115a2/test.rp2040.yaml rename to tests/components/mpl3115a2/test.rp2040-ard.yaml diff --git a/tests/components/mpr121/test.esp32.yaml b/tests/components/mpr121/test.esp32-ard.yaml similarity index 100% rename from tests/components/mpr121/test.esp32.yaml rename to tests/components/mpr121/test.esp32-ard.yaml diff --git a/tests/components/mpr121/test.esp32-c3.yaml b/tests/components/mpr121/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mpr121/test.esp32-c3.yaml rename to tests/components/mpr121/test.esp32-c3-ard.yaml diff --git a/tests/components/mpr121/test.esp8266.yaml b/tests/components/mpr121/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mpr121/test.esp8266.yaml rename to tests/components/mpr121/test.esp8266-ard.yaml diff --git a/tests/components/mpr121/test.rp2040.yaml b/tests/components/mpr121/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mpr121/test.rp2040.yaml rename to tests/components/mpr121/test.rp2040-ard.yaml diff --git a/tests/components/mpu6050/test.esp32.yaml b/tests/components/mpu6050/test.esp32-ard.yaml similarity index 100% rename from tests/components/mpu6050/test.esp32.yaml rename to tests/components/mpu6050/test.esp32-ard.yaml diff --git a/tests/components/mpu6050/test.esp32-c3.yaml b/tests/components/mpu6050/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mpu6050/test.esp32-c3.yaml rename to tests/components/mpu6050/test.esp32-c3-ard.yaml diff --git a/tests/components/mpu6050/test.esp8266.yaml b/tests/components/mpu6050/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mpu6050/test.esp8266.yaml rename to tests/components/mpu6050/test.esp8266-ard.yaml diff --git a/tests/components/mpu6050/test.rp2040.yaml b/tests/components/mpu6050/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mpu6050/test.rp2040.yaml rename to tests/components/mpu6050/test.rp2040-ard.yaml diff --git a/tests/components/mpu6886/test.esp32.yaml b/tests/components/mpu6886/test.esp32-ard.yaml similarity index 100% rename from tests/components/mpu6886/test.esp32.yaml rename to tests/components/mpu6886/test.esp32-ard.yaml diff --git a/tests/components/mpu6886/test.esp32-c3.yaml b/tests/components/mpu6886/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mpu6886/test.esp32-c3.yaml rename to tests/components/mpu6886/test.esp32-c3-ard.yaml diff --git a/tests/components/mpu6886/test.esp8266.yaml b/tests/components/mpu6886/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mpu6886/test.esp8266.yaml rename to tests/components/mpu6886/test.esp8266-ard.yaml diff --git a/tests/components/mpu6886/test.rp2040.yaml b/tests/components/mpu6886/test.rp2040-ard.yaml similarity index 100% rename from tests/components/mpu6886/test.rp2040.yaml rename to tests/components/mpu6886/test.rp2040-ard.yaml diff --git a/tests/components/mqtt/test.bk72xx.yaml b/tests/components/mqtt/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/mqtt/test.bk72xx.yaml rename to tests/components/mqtt/test.bk72xx-ard.yaml diff --git a/tests/components/mqtt/test.esp32-c3.yaml b/tests/components/mqtt/test.esp32-ard.yaml similarity index 100% rename from tests/components/mqtt/test.esp32-c3.yaml rename to tests/components/mqtt/test.esp32-ard.yaml diff --git a/tests/components/mqtt/test.esp32.yaml b/tests/components/mqtt/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mqtt/test.esp32.yaml rename to tests/components/mqtt/test.esp32-c3-ard.yaml diff --git a/tests/components/mqtt/test.esp8266.yaml b/tests/components/mqtt/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mqtt/test.esp8266.yaml rename to tests/components/mqtt/test.esp8266-ard.yaml diff --git a/tests/components/mqtt_subscribe/test.esp32-c3.yaml b/tests/components/mqtt_subscribe/test.esp32-ard.yaml similarity index 100% rename from tests/components/mqtt_subscribe/test.esp32-c3.yaml rename to tests/components/mqtt_subscribe/test.esp32-ard.yaml diff --git a/tests/components/mqtt_subscribe/test.esp32.yaml b/tests/components/mqtt_subscribe/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/mqtt_subscribe/test.esp32.yaml rename to tests/components/mqtt_subscribe/test.esp32-c3-ard.yaml diff --git a/tests/components/mqtt_subscribe/test.esp8266.yaml b/tests/components/mqtt_subscribe/test.esp8266-ard.yaml similarity index 100% rename from tests/components/mqtt_subscribe/test.esp8266.yaml rename to tests/components/mqtt_subscribe/test.esp8266-ard.yaml diff --git a/tests/components/ms5611/test.esp32.yaml b/tests/components/ms5611/test.esp32-ard.yaml similarity index 100% rename from tests/components/ms5611/test.esp32.yaml rename to tests/components/ms5611/test.esp32-ard.yaml diff --git a/tests/components/ms5611/test.esp32-c3.yaml b/tests/components/ms5611/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ms5611/test.esp32-c3.yaml rename to tests/components/ms5611/test.esp32-c3-ard.yaml diff --git a/tests/components/ms5611/test.esp8266.yaml b/tests/components/ms5611/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ms5611/test.esp8266.yaml rename to tests/components/ms5611/test.esp8266-ard.yaml diff --git a/tests/components/ms5611/test.rp2040.yaml b/tests/components/ms5611/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ms5611/test.rp2040.yaml rename to tests/components/ms5611/test.rp2040-ard.yaml diff --git a/tests/components/my9231/test.esp32-c3.yaml b/tests/components/my9231/test.esp32-ard.yaml similarity index 100% rename from tests/components/my9231/test.esp32-c3.yaml rename to tests/components/my9231/test.esp32-ard.yaml diff --git a/tests/components/my9231/test.esp32.yaml b/tests/components/my9231/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/my9231/test.esp32.yaml rename to tests/components/my9231/test.esp32-c3-ard.yaml diff --git a/tests/components/my9231/test.esp8266.yaml b/tests/components/my9231/test.esp8266-ard.yaml similarity index 100% rename from tests/components/my9231/test.esp8266.yaml rename to tests/components/my9231/test.esp8266-ard.yaml diff --git a/tests/components/my9231/test.rp2040.yaml b/tests/components/my9231/test.rp2040-ard.yaml similarity index 100% rename from tests/components/my9231/test.rp2040.yaml rename to tests/components/my9231/test.rp2040-ard.yaml diff --git a/tests/components/neopixelbus/test.esp32.yaml b/tests/components/neopixelbus/test.esp32-ard.yaml similarity index 100% rename from tests/components/neopixelbus/test.esp32.yaml rename to tests/components/neopixelbus/test.esp32-ard.yaml diff --git a/tests/components/neopixelbus/test.esp32-c3.yaml b/tests/components/neopixelbus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/neopixelbus/test.esp32-c3.yaml rename to tests/components/neopixelbus/test.esp32-c3-ard.yaml diff --git a/tests/components/neopixelbus/test.esp8266.yaml b/tests/components/neopixelbus/test.esp8266-ard.yaml similarity index 100% rename from tests/components/neopixelbus/test.esp8266.yaml rename to tests/components/neopixelbus/test.esp8266-ard.yaml diff --git a/tests/components/network/test.esp32-c3.yaml b/tests/components/network/test.esp32-ard.yaml similarity index 100% rename from tests/components/network/test.esp32-c3.yaml rename to tests/components/network/test.esp32-ard.yaml diff --git a/tests/components/network/test.esp32.yaml b/tests/components/network/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/network/test.esp32.yaml rename to tests/components/network/test.esp32-c3-ard.yaml diff --git a/tests/components/network/test.esp8266.yaml b/tests/components/network/test.esp8266-ard.yaml similarity index 100% rename from tests/components/network/test.esp8266.yaml rename to tests/components/network/test.esp8266-ard.yaml diff --git a/tests/components/network/test.rp2040.yaml b/tests/components/network/test.rp2040-ard.yaml similarity index 100% rename from tests/components/network/test.rp2040.yaml rename to tests/components/network/test.rp2040-ard.yaml diff --git a/tests/components/nextion/test.esp32.yaml b/tests/components/nextion/test.esp32-ard.yaml similarity index 100% rename from tests/components/nextion/test.esp32.yaml rename to tests/components/nextion/test.esp32-ard.yaml diff --git a/tests/components/nextion/test.esp32-c3.yaml b/tests/components/nextion/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/nextion/test.esp32-c3.yaml rename to tests/components/nextion/test.esp32-c3-ard.yaml diff --git a/tests/components/nextion/test.esp8266.yaml b/tests/components/nextion/test.esp8266-ard.yaml similarity index 100% rename from tests/components/nextion/test.esp8266.yaml rename to tests/components/nextion/test.esp8266-ard.yaml diff --git a/tests/components/nextion/test.rp2040.yaml b/tests/components/nextion/test.rp2040-ard.yaml similarity index 100% rename from tests/components/nextion/test.rp2040.yaml rename to tests/components/nextion/test.rp2040-ard.yaml diff --git a/tests/components/noblex/test.esp32-c3.yaml b/tests/components/noblex/test.esp32-ard.yaml similarity index 100% rename from tests/components/noblex/test.esp32-c3.yaml rename to tests/components/noblex/test.esp32-ard.yaml diff --git a/tests/components/noblex/test.esp32.yaml b/tests/components/noblex/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/noblex/test.esp32.yaml rename to tests/components/noblex/test.esp32-c3-ard.yaml diff --git a/tests/components/noblex/test.esp8266.yaml b/tests/components/noblex/test.esp8266-ard.yaml similarity index 100% rename from tests/components/noblex/test.esp8266.yaml rename to tests/components/noblex/test.esp8266-ard.yaml diff --git a/tests/components/ntc/test.esp32.yaml b/tests/components/ntc/test.esp32-ard.yaml similarity index 100% rename from tests/components/ntc/test.esp32.yaml rename to tests/components/ntc/test.esp32-ard.yaml diff --git a/tests/components/ntc/test.esp32-c3.yaml b/tests/components/ntc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ntc/test.esp32-c3.yaml rename to tests/components/ntc/test.esp32-c3-ard.yaml diff --git a/tests/components/ntc/test.esp32-s2.yaml b/tests/components/ntc/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/ntc/test.esp32-s2.yaml rename to tests/components/ntc/test.esp32-s2-ard.yaml diff --git a/tests/components/ntc/test.esp32-s3.yaml b/tests/components/ntc/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/ntc/test.esp32-s3.yaml rename to tests/components/ntc/test.esp32-s3-ard.yaml diff --git a/tests/components/ntc/test.esp8266.yaml b/tests/components/ntc/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ntc/test.esp8266.yaml rename to tests/components/ntc/test.esp8266-ard.yaml diff --git a/tests/components/ntc/test.rp2040.yaml b/tests/components/ntc/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ntc/test.rp2040.yaml rename to tests/components/ntc/test.rp2040-ard.yaml diff --git a/tests/components/ota/test.esp32-c3.yaml b/tests/components/ota/test.esp32-ard.yaml similarity index 100% rename from tests/components/ota/test.esp32-c3.yaml rename to tests/components/ota/test.esp32-ard.yaml diff --git a/tests/components/ota/test.esp32.yaml b/tests/components/ota/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ota/test.esp32.yaml rename to tests/components/ota/test.esp32-c3-ard.yaml diff --git a/tests/components/ota/test.esp8266.yaml b/tests/components/ota/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ota/test.esp8266.yaml rename to tests/components/ota/test.esp8266-ard.yaml diff --git a/tests/components/ota/test.rp2040.yaml b/tests/components/ota/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ota/test.rp2040.yaml rename to tests/components/ota/test.rp2040-ard.yaml diff --git a/tests/components/output/test.esp32.yaml b/tests/components/output/test.esp32-ard.yaml similarity index 100% rename from tests/components/output/test.esp32.yaml rename to tests/components/output/test.esp32-ard.yaml diff --git a/tests/components/output/test.esp32-c3.yaml b/tests/components/output/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/output/test.esp32-c3.yaml rename to tests/components/output/test.esp32-c3-ard.yaml diff --git a/tests/components/output/test.esp8266.yaml b/tests/components/output/test.esp8266-ard.yaml similarity index 100% rename from tests/components/output/test.esp8266.yaml rename to tests/components/output/test.esp8266-ard.yaml diff --git a/tests/components/output/test.rp2040.yaml b/tests/components/output/test.rp2040-ard.yaml similarity index 100% rename from tests/components/output/test.rp2040.yaml rename to tests/components/output/test.rp2040-ard.yaml diff --git a/tests/components/partition/test.esp32.yaml b/tests/components/partition/test.esp32-ard.yaml similarity index 100% rename from tests/components/partition/test.esp32.yaml rename to tests/components/partition/test.esp32-ard.yaml diff --git a/tests/components/partition/test.esp32-c3.yaml b/tests/components/partition/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/partition/test.esp32-c3.yaml rename to tests/components/partition/test.esp32-c3-ard.yaml diff --git a/tests/components/pca6416a/test.esp32.yaml b/tests/components/pca6416a/test.esp32-ard.yaml similarity index 100% rename from tests/components/pca6416a/test.esp32.yaml rename to tests/components/pca6416a/test.esp32-ard.yaml diff --git a/tests/components/pca6416a/test.esp32-c3.yaml b/tests/components/pca6416a/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pca6416a/test.esp32-c3.yaml rename to tests/components/pca6416a/test.esp32-c3-ard.yaml diff --git a/tests/components/pca6416a/test.esp8266.yaml b/tests/components/pca6416a/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pca6416a/test.esp8266.yaml rename to tests/components/pca6416a/test.esp8266-ard.yaml diff --git a/tests/components/pca6416a/test.rp2040.yaml b/tests/components/pca6416a/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pca6416a/test.rp2040.yaml rename to tests/components/pca6416a/test.rp2040-ard.yaml diff --git a/tests/components/pca9554/test.esp32.yaml b/tests/components/pca9554/test.esp32-ard.yaml similarity index 100% rename from tests/components/pca9554/test.esp32.yaml rename to tests/components/pca9554/test.esp32-ard.yaml diff --git a/tests/components/pca9554/test.esp32-c3.yaml b/tests/components/pca9554/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pca9554/test.esp32-c3.yaml rename to tests/components/pca9554/test.esp32-c3-ard.yaml diff --git a/tests/components/pca9554/test.esp8266.yaml b/tests/components/pca9554/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pca9554/test.esp8266.yaml rename to tests/components/pca9554/test.esp8266-ard.yaml diff --git a/tests/components/pca9554/test.rp2040.yaml b/tests/components/pca9554/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pca9554/test.rp2040.yaml rename to tests/components/pca9554/test.rp2040-ard.yaml diff --git a/tests/components/pca9685/test.esp32.yaml b/tests/components/pca9685/test.esp32-ard.yaml similarity index 100% rename from tests/components/pca9685/test.esp32.yaml rename to tests/components/pca9685/test.esp32-ard.yaml diff --git a/tests/components/pca9685/test.esp32-c3.yaml b/tests/components/pca9685/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pca9685/test.esp32-c3.yaml rename to tests/components/pca9685/test.esp32-c3-ard.yaml diff --git a/tests/components/pca9685/test.esp8266.yaml b/tests/components/pca9685/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pca9685/test.esp8266.yaml rename to tests/components/pca9685/test.esp8266-ard.yaml diff --git a/tests/components/pca9685/test.rp2040.yaml b/tests/components/pca9685/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pca9685/test.rp2040.yaml rename to tests/components/pca9685/test.rp2040-ard.yaml diff --git a/tests/components/pcd8544/test.esp32.yaml b/tests/components/pcd8544/test.esp32-ard.yaml similarity index 100% rename from tests/components/pcd8544/test.esp32.yaml rename to tests/components/pcd8544/test.esp32-ard.yaml diff --git a/tests/components/pcd8544/test.esp32-c3.yaml b/tests/components/pcd8544/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pcd8544/test.esp32-c3.yaml rename to tests/components/pcd8544/test.esp32-c3-ard.yaml diff --git a/tests/components/pcd8544/test.esp8266.yaml b/tests/components/pcd8544/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pcd8544/test.esp8266.yaml rename to tests/components/pcd8544/test.esp8266-ard.yaml diff --git a/tests/components/pcd8544/test.rp2040.yaml b/tests/components/pcd8544/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pcd8544/test.rp2040.yaml rename to tests/components/pcd8544/test.rp2040-ard.yaml diff --git a/tests/components/pcf85063/test.esp32.yaml b/tests/components/pcf85063/test.esp32-ard.yaml similarity index 100% rename from tests/components/pcf85063/test.esp32.yaml rename to tests/components/pcf85063/test.esp32-ard.yaml diff --git a/tests/components/pcf85063/test.esp32-c3.yaml b/tests/components/pcf85063/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pcf85063/test.esp32-c3.yaml rename to tests/components/pcf85063/test.esp32-c3-ard.yaml diff --git a/tests/components/pcf85063/test.esp8266.yaml b/tests/components/pcf85063/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pcf85063/test.esp8266.yaml rename to tests/components/pcf85063/test.esp8266-ard.yaml diff --git a/tests/components/pcf85063/test.rp2040.yaml b/tests/components/pcf85063/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pcf85063/test.rp2040.yaml rename to tests/components/pcf85063/test.rp2040-ard.yaml diff --git a/tests/components/pcf8563/test.esp32.yaml b/tests/components/pcf8563/test.esp32-ard.yaml similarity index 100% rename from tests/components/pcf8563/test.esp32.yaml rename to tests/components/pcf8563/test.esp32-ard.yaml diff --git a/tests/components/pcf8563/test.esp32-c3.yaml b/tests/components/pcf8563/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pcf8563/test.esp32-c3.yaml rename to tests/components/pcf8563/test.esp32-c3-ard.yaml diff --git a/tests/components/pcf8563/test.esp8266.yaml b/tests/components/pcf8563/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pcf8563/test.esp8266.yaml rename to tests/components/pcf8563/test.esp8266-ard.yaml diff --git a/tests/components/pcf8563/test.rp2040.yaml b/tests/components/pcf8563/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pcf8563/test.rp2040.yaml rename to tests/components/pcf8563/test.rp2040-ard.yaml diff --git a/tests/components/pcf8574/test.esp32.yaml b/tests/components/pcf8574/test.esp32-ard.yaml similarity index 100% rename from tests/components/pcf8574/test.esp32.yaml rename to tests/components/pcf8574/test.esp32-ard.yaml diff --git a/tests/components/pcf8574/test.esp32-c3.yaml b/tests/components/pcf8574/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pcf8574/test.esp32-c3.yaml rename to tests/components/pcf8574/test.esp32-c3-ard.yaml diff --git a/tests/components/pcf8574/test.esp8266.yaml b/tests/components/pcf8574/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pcf8574/test.esp8266.yaml rename to tests/components/pcf8574/test.esp8266-ard.yaml diff --git a/tests/components/pcf8574/test.rp2040.yaml b/tests/components/pcf8574/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pcf8574/test.rp2040.yaml rename to tests/components/pcf8574/test.rp2040-ard.yaml diff --git a/tests/components/pid/test.esp32-c3.yaml b/tests/components/pid/test.esp32-ard.yaml similarity index 100% rename from tests/components/pid/test.esp32-c3.yaml rename to tests/components/pid/test.esp32-ard.yaml diff --git a/tests/components/pid/test.esp32.yaml b/tests/components/pid/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pid/test.esp32.yaml rename to tests/components/pid/test.esp32-c3-ard.yaml diff --git a/tests/components/pid/test.esp8266.yaml b/tests/components/pid/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pid/test.esp8266.yaml rename to tests/components/pid/test.esp8266-ard.yaml diff --git a/tests/components/pid/test.rp2040.yaml b/tests/components/pid/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pid/test.rp2040.yaml rename to tests/components/pid/test.rp2040-ard.yaml diff --git a/tests/components/pipsolar/test.esp32.yaml b/tests/components/pipsolar/test.esp32-ard.yaml similarity index 100% rename from tests/components/pipsolar/test.esp32.yaml rename to tests/components/pipsolar/test.esp32-ard.yaml diff --git a/tests/components/pipsolar/test.esp32-c3.yaml b/tests/components/pipsolar/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pipsolar/test.esp32-c3.yaml rename to tests/components/pipsolar/test.esp32-c3-ard.yaml diff --git a/tests/components/pipsolar/test.esp8266.yaml b/tests/components/pipsolar/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pipsolar/test.esp8266.yaml rename to tests/components/pipsolar/test.esp8266-ard.yaml diff --git a/tests/components/pipsolar/test.rp2040.yaml b/tests/components/pipsolar/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pipsolar/test.rp2040.yaml rename to tests/components/pipsolar/test.rp2040-ard.yaml diff --git a/tests/components/pm1006/test.esp32.yaml b/tests/components/pm1006/test.esp32-ard.yaml similarity index 100% rename from tests/components/pm1006/test.esp32.yaml rename to tests/components/pm1006/test.esp32-ard.yaml diff --git a/tests/components/pm1006/test.esp32-c3.yaml b/tests/components/pm1006/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pm1006/test.esp32-c3.yaml rename to tests/components/pm1006/test.esp32-c3-ard.yaml diff --git a/tests/components/pm1006/test.esp8266.yaml b/tests/components/pm1006/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pm1006/test.esp8266.yaml rename to tests/components/pm1006/test.esp8266-ard.yaml diff --git a/tests/components/pm1006/test.rp2040.yaml b/tests/components/pm1006/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pm1006/test.rp2040.yaml rename to tests/components/pm1006/test.rp2040-ard.yaml diff --git a/tests/components/pmsa003i/test.esp32.yaml b/tests/components/pmsa003i/test.esp32-ard.yaml similarity index 100% rename from tests/components/pmsa003i/test.esp32.yaml rename to tests/components/pmsa003i/test.esp32-ard.yaml diff --git a/tests/components/pmsa003i/test.esp32-c3.yaml b/tests/components/pmsa003i/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pmsa003i/test.esp32-c3.yaml rename to tests/components/pmsa003i/test.esp32-c3-ard.yaml diff --git a/tests/components/pmsa003i/test.esp8266.yaml b/tests/components/pmsa003i/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pmsa003i/test.esp8266.yaml rename to tests/components/pmsa003i/test.esp8266-ard.yaml diff --git a/tests/components/pmsa003i/test.rp2040.yaml b/tests/components/pmsa003i/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pmsa003i/test.rp2040.yaml rename to tests/components/pmsa003i/test.rp2040-ard.yaml diff --git a/tests/components/pmsx003/test.esp32.yaml b/tests/components/pmsx003/test.esp32-ard.yaml similarity index 100% rename from tests/components/pmsx003/test.esp32.yaml rename to tests/components/pmsx003/test.esp32-ard.yaml diff --git a/tests/components/pmsx003/test.esp32-c3.yaml b/tests/components/pmsx003/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pmsx003/test.esp32-c3.yaml rename to tests/components/pmsx003/test.esp32-c3-ard.yaml diff --git a/tests/components/pmsx003/test.esp8266.yaml b/tests/components/pmsx003/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pmsx003/test.esp8266.yaml rename to tests/components/pmsx003/test.esp8266-ard.yaml diff --git a/tests/components/pmsx003/test.rp2040.yaml b/tests/components/pmsx003/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pmsx003/test.rp2040.yaml rename to tests/components/pmsx003/test.rp2040-ard.yaml diff --git a/tests/components/pmwcs3/test.esp32.yaml b/tests/components/pmwcs3/test.esp32-ard.yaml similarity index 100% rename from tests/components/pmwcs3/test.esp32.yaml rename to tests/components/pmwcs3/test.esp32-ard.yaml diff --git a/tests/components/pmwcs3/test.esp32-c3.yaml b/tests/components/pmwcs3/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pmwcs3/test.esp32-c3.yaml rename to tests/components/pmwcs3/test.esp32-c3-ard.yaml diff --git a/tests/components/pmwcs3/test.esp8266.yaml b/tests/components/pmwcs3/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pmwcs3/test.esp8266.yaml rename to tests/components/pmwcs3/test.esp8266-ard.yaml diff --git a/tests/components/pmwcs3/test.rp2040.yaml b/tests/components/pmwcs3/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pmwcs3/test.rp2040.yaml rename to tests/components/pmwcs3/test.rp2040-ard.yaml diff --git a/tests/components/pn532_i2c/test.esp32.yaml b/tests/components/pn532_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/pn532_i2c/test.esp32.yaml rename to tests/components/pn532_i2c/test.esp32-ard.yaml diff --git a/tests/components/pn532_i2c/test.esp32-c3.yaml b/tests/components/pn532_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pn532_i2c/test.esp32-c3.yaml rename to tests/components/pn532_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/pn532_i2c/test.esp8266.yaml b/tests/components/pn532_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pn532_i2c/test.esp8266.yaml rename to tests/components/pn532_i2c/test.esp8266-ard.yaml diff --git a/tests/components/pn532_i2c/test.rp2040.yaml b/tests/components/pn532_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pn532_i2c/test.rp2040.yaml rename to tests/components/pn532_i2c/test.rp2040-ard.yaml diff --git a/tests/components/pn532_spi/test.esp32.yaml b/tests/components/pn532_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/pn532_spi/test.esp32.yaml rename to tests/components/pn532_spi/test.esp32-ard.yaml diff --git a/tests/components/pn532_spi/test.esp32-c3.yaml b/tests/components/pn532_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pn532_spi/test.esp32-c3.yaml rename to tests/components/pn532_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/pn532_spi/test.esp8266.yaml b/tests/components/pn532_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pn532_spi/test.esp8266.yaml rename to tests/components/pn532_spi/test.esp8266-ard.yaml diff --git a/tests/components/pn532_spi/test.rp2040.yaml b/tests/components/pn532_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pn532_spi/test.rp2040.yaml rename to tests/components/pn532_spi/test.rp2040-ard.yaml diff --git a/tests/components/pn7150_i2c/test.esp32.yaml b/tests/components/pn7150_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/pn7150_i2c/test.esp32.yaml rename to tests/components/pn7150_i2c/test.esp32-ard.yaml diff --git a/tests/components/pn7150_i2c/test.esp32-c3.yaml b/tests/components/pn7150_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pn7150_i2c/test.esp32-c3.yaml rename to tests/components/pn7150_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/pn7150_i2c/test.esp8266.yaml b/tests/components/pn7150_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pn7150_i2c/test.esp8266.yaml rename to tests/components/pn7150_i2c/test.esp8266-ard.yaml diff --git a/tests/components/pn7150_i2c/test.rp2040.yaml b/tests/components/pn7150_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pn7150_i2c/test.rp2040.yaml rename to tests/components/pn7150_i2c/test.rp2040-ard.yaml diff --git a/tests/components/pn7160_i2c/test.esp32.yaml b/tests/components/pn7160_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/pn7160_i2c/test.esp32.yaml rename to tests/components/pn7160_i2c/test.esp32-ard.yaml diff --git a/tests/components/pn7160_i2c/test.esp32-c3.yaml b/tests/components/pn7160_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pn7160_i2c/test.esp32-c3.yaml rename to tests/components/pn7160_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/pn7160_i2c/test.esp8266.yaml b/tests/components/pn7160_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pn7160_i2c/test.esp8266.yaml rename to tests/components/pn7160_i2c/test.esp8266-ard.yaml diff --git a/tests/components/pn7160_i2c/test.rp2040.yaml b/tests/components/pn7160_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pn7160_i2c/test.rp2040.yaml rename to tests/components/pn7160_i2c/test.rp2040-ard.yaml diff --git a/tests/components/pn7160_spi/test.esp32.yaml b/tests/components/pn7160_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/pn7160_spi/test.esp32.yaml rename to tests/components/pn7160_spi/test.esp32-ard.yaml diff --git a/tests/components/pn7160_spi/test.esp32-c3.yaml b/tests/components/pn7160_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pn7160_spi/test.esp32-c3.yaml rename to tests/components/pn7160_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/pn7160_spi/test.esp8266.yaml b/tests/components/pn7160_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pn7160_spi/test.esp8266.yaml rename to tests/components/pn7160_spi/test.esp8266-ard.yaml diff --git a/tests/components/pn7160_spi/test.rp2040.yaml b/tests/components/pn7160_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pn7160_spi/test.rp2040.yaml rename to tests/components/pn7160_spi/test.rp2040-ard.yaml diff --git a/tests/components/power_supply/test.esp32-c3.yaml b/tests/components/power_supply/test.esp32-ard.yaml similarity index 100% rename from tests/components/power_supply/test.esp32-c3.yaml rename to tests/components/power_supply/test.esp32-ard.yaml diff --git a/tests/components/power_supply/test.esp32.yaml b/tests/components/power_supply/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/power_supply/test.esp32.yaml rename to tests/components/power_supply/test.esp32-c3-ard.yaml diff --git a/tests/components/power_supply/test.esp8266.yaml b/tests/components/power_supply/test.esp8266-ard.yaml similarity index 100% rename from tests/components/power_supply/test.esp8266.yaml rename to tests/components/power_supply/test.esp8266-ard.yaml diff --git a/tests/components/power_supply/test.rp2040.yaml b/tests/components/power_supply/test.rp2040-ard.yaml similarity index 100% rename from tests/components/power_supply/test.rp2040.yaml rename to tests/components/power_supply/test.rp2040-ard.yaml diff --git a/tests/components/prometheus/test.esp32-c3.yaml b/tests/components/prometheus/test.esp32-ard.yaml similarity index 100% rename from tests/components/prometheus/test.esp32-c3.yaml rename to tests/components/prometheus/test.esp32-ard.yaml diff --git a/tests/components/prometheus/test.esp32.yaml b/tests/components/prometheus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/prometheus/test.esp32.yaml rename to tests/components/prometheus/test.esp32-c3-ard.yaml diff --git a/tests/components/prometheus/test.esp8266.yaml b/tests/components/prometheus/test.esp8266-ard.yaml similarity index 100% rename from tests/components/prometheus/test.esp8266.yaml rename to tests/components/prometheus/test.esp8266-ard.yaml diff --git a/tests/components/psram/test.esp32-c3.yaml b/tests/components/psram/test.esp32-ard.yaml similarity index 100% rename from tests/components/psram/test.esp32-c3.yaml rename to tests/components/psram/test.esp32-ard.yaml diff --git a/tests/components/psram/test.esp32.yaml b/tests/components/psram/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/psram/test.esp32.yaml rename to tests/components/psram/test.esp32-c3-ard.yaml diff --git a/tests/components/pulse_counter/test.esp32-c3.yaml b/tests/components/pulse_counter/test.esp32-ard.yaml similarity index 100% rename from tests/components/pulse_counter/test.esp32-c3.yaml rename to tests/components/pulse_counter/test.esp32-ard.yaml diff --git a/tests/components/pulse_counter/test.esp32.yaml b/tests/components/pulse_counter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pulse_counter/test.esp32.yaml rename to tests/components/pulse_counter/test.esp32-c3-ard.yaml diff --git a/tests/components/pulse_counter/test.esp8266.yaml b/tests/components/pulse_counter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pulse_counter/test.esp8266.yaml rename to tests/components/pulse_counter/test.esp8266-ard.yaml diff --git a/tests/components/pulse_counter/test.rp2040.yaml b/tests/components/pulse_counter/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pulse_counter/test.rp2040.yaml rename to tests/components/pulse_counter/test.rp2040-ard.yaml diff --git a/tests/components/pulse_meter/test.esp32-c3.yaml b/tests/components/pulse_meter/test.esp32-ard.yaml similarity index 100% rename from tests/components/pulse_meter/test.esp32-c3.yaml rename to tests/components/pulse_meter/test.esp32-ard.yaml diff --git a/tests/components/pulse_meter/test.esp32.yaml b/tests/components/pulse_meter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pulse_meter/test.esp32.yaml rename to tests/components/pulse_meter/test.esp32-c3-ard.yaml diff --git a/tests/components/pulse_meter/test.esp8266.yaml b/tests/components/pulse_meter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pulse_meter/test.esp8266.yaml rename to tests/components/pulse_meter/test.esp8266-ard.yaml diff --git a/tests/components/pulse_meter/test.rp2040.yaml b/tests/components/pulse_meter/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pulse_meter/test.rp2040.yaml rename to tests/components/pulse_meter/test.rp2040-ard.yaml diff --git a/tests/components/pulse_width/test.esp32-c3.yaml b/tests/components/pulse_width/test.esp32-ard.yaml similarity index 100% rename from tests/components/pulse_width/test.esp32-c3.yaml rename to tests/components/pulse_width/test.esp32-ard.yaml diff --git a/tests/components/pulse_width/test.esp32.yaml b/tests/components/pulse_width/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pulse_width/test.esp32.yaml rename to tests/components/pulse_width/test.esp32-c3-ard.yaml diff --git a/tests/components/pulse_width/test.esp8266.yaml b/tests/components/pulse_width/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pulse_width/test.esp8266.yaml rename to tests/components/pulse_width/test.esp8266-ard.yaml diff --git a/tests/components/pulse_width/test.rp2040.yaml b/tests/components/pulse_width/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pulse_width/test.rp2040.yaml rename to tests/components/pulse_width/test.rp2040-ard.yaml diff --git a/tests/components/pvvx_mithermometer/test.esp32-c3.yaml b/tests/components/pvvx_mithermometer/test.esp32-ard.yaml similarity index 100% rename from tests/components/pvvx_mithermometer/test.esp32-c3.yaml rename to tests/components/pvvx_mithermometer/test.esp32-ard.yaml diff --git a/tests/components/pvvx_mithermometer/test.esp32.yaml b/tests/components/pvvx_mithermometer/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pvvx_mithermometer/test.esp32.yaml rename to tests/components/pvvx_mithermometer/test.esp32-c3-ard.yaml diff --git a/tests/components/pylontech/test.esp32.yaml b/tests/components/pylontech/test.esp32-ard.yaml similarity index 100% rename from tests/components/pylontech/test.esp32.yaml rename to tests/components/pylontech/test.esp32-ard.yaml diff --git a/tests/components/pylontech/test.esp32-c3.yaml b/tests/components/pylontech/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pylontech/test.esp32-c3.yaml rename to tests/components/pylontech/test.esp32-c3-ard.yaml diff --git a/tests/components/pylontech/test.esp8266.yaml b/tests/components/pylontech/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pylontech/test.esp8266.yaml rename to tests/components/pylontech/test.esp8266-ard.yaml diff --git a/tests/components/pylontech/test.rp2040.yaml b/tests/components/pylontech/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pylontech/test.rp2040.yaml rename to tests/components/pylontech/test.rp2040-ard.yaml diff --git a/tests/components/pzem004t/test.esp32.yaml b/tests/components/pzem004t/test.esp32-ard.yaml similarity index 100% rename from tests/components/pzem004t/test.esp32.yaml rename to tests/components/pzem004t/test.esp32-ard.yaml diff --git a/tests/components/pzem004t/test.esp32-c3.yaml b/tests/components/pzem004t/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pzem004t/test.esp32-c3.yaml rename to tests/components/pzem004t/test.esp32-c3-ard.yaml diff --git a/tests/components/pzem004t/test.esp8266.yaml b/tests/components/pzem004t/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pzem004t/test.esp8266.yaml rename to tests/components/pzem004t/test.esp8266-ard.yaml diff --git a/tests/components/pzem004t/test.rp2040.yaml b/tests/components/pzem004t/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pzem004t/test.rp2040.yaml rename to tests/components/pzem004t/test.rp2040-ard.yaml diff --git a/tests/components/pzemac/test.esp32.yaml b/tests/components/pzemac/test.esp32-ard.yaml similarity index 100% rename from tests/components/pzemac/test.esp32.yaml rename to tests/components/pzemac/test.esp32-ard.yaml diff --git a/tests/components/pzemac/test.esp32-c3.yaml b/tests/components/pzemac/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pzemac/test.esp32-c3.yaml rename to tests/components/pzemac/test.esp32-c3-ard.yaml diff --git a/tests/components/pzemac/test.esp8266.yaml b/tests/components/pzemac/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pzemac/test.esp8266.yaml rename to tests/components/pzemac/test.esp8266-ard.yaml diff --git a/tests/components/pzemac/test.rp2040.yaml b/tests/components/pzemac/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pzemac/test.rp2040.yaml rename to tests/components/pzemac/test.rp2040-ard.yaml diff --git a/tests/components/pzemdc/test.esp32.yaml b/tests/components/pzemdc/test.esp32-ard.yaml similarity index 100% rename from tests/components/pzemdc/test.esp32.yaml rename to tests/components/pzemdc/test.esp32-ard.yaml diff --git a/tests/components/pzemdc/test.esp32-c3.yaml b/tests/components/pzemdc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/pzemdc/test.esp32-c3.yaml rename to tests/components/pzemdc/test.esp32-c3-ard.yaml diff --git a/tests/components/pzemdc/test.esp8266.yaml b/tests/components/pzemdc/test.esp8266-ard.yaml similarity index 100% rename from tests/components/pzemdc/test.esp8266.yaml rename to tests/components/pzemdc/test.esp8266-ard.yaml diff --git a/tests/components/pzemdc/test.rp2040.yaml b/tests/components/pzemdc/test.rp2040-ard.yaml similarity index 100% rename from tests/components/pzemdc/test.rp2040.yaml rename to tests/components/pzemdc/test.rp2040-ard.yaml diff --git a/tests/components/qmc5883l/test.esp32.yaml b/tests/components/qmc5883l/test.esp32-ard.yaml similarity index 100% rename from tests/components/qmc5883l/test.esp32.yaml rename to tests/components/qmc5883l/test.esp32-ard.yaml diff --git a/tests/components/qmc5883l/test.esp32-c3.yaml b/tests/components/qmc5883l/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/qmc5883l/test.esp32-c3.yaml rename to tests/components/qmc5883l/test.esp32-c3-ard.yaml diff --git a/tests/components/qmc5883l/test.esp8266.yaml b/tests/components/qmc5883l/test.esp8266-ard.yaml similarity index 100% rename from tests/components/qmc5883l/test.esp8266.yaml rename to tests/components/qmc5883l/test.esp8266-ard.yaml diff --git a/tests/components/qmc5883l/test.rp2040.yaml b/tests/components/qmc5883l/test.rp2040-ard.yaml similarity index 100% rename from tests/components/qmc5883l/test.rp2040.yaml rename to tests/components/qmc5883l/test.rp2040-ard.yaml diff --git a/tests/components/qmp6988/test.esp32.yaml b/tests/components/qmp6988/test.esp32-ard.yaml similarity index 100% rename from tests/components/qmp6988/test.esp32.yaml rename to tests/components/qmp6988/test.esp32-ard.yaml diff --git a/tests/components/qmp6988/test.esp32-c3.yaml b/tests/components/qmp6988/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/qmp6988/test.esp32-c3.yaml rename to tests/components/qmp6988/test.esp32-c3-ard.yaml diff --git a/tests/components/qmp6988/test.esp8266.yaml b/tests/components/qmp6988/test.esp8266-ard.yaml similarity index 100% rename from tests/components/qmp6988/test.esp8266.yaml rename to tests/components/qmp6988/test.esp8266-ard.yaml diff --git a/tests/components/qmp6988/test.rp2040.yaml b/tests/components/qmp6988/test.rp2040-ard.yaml similarity index 100% rename from tests/components/qmp6988/test.rp2040.yaml rename to tests/components/qmp6988/test.rp2040-ard.yaml diff --git a/tests/components/qr_code/test.esp32.yaml b/tests/components/qr_code/test.esp32-ard.yaml similarity index 100% rename from tests/components/qr_code/test.esp32.yaml rename to tests/components/qr_code/test.esp32-ard.yaml diff --git a/tests/components/qr_code/test.esp32-c3.yaml b/tests/components/qr_code/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/qr_code/test.esp32-c3.yaml rename to tests/components/qr_code/test.esp32-c3-ard.yaml diff --git a/tests/components/qr_code/test.esp8266.yaml b/tests/components/qr_code/test.esp8266-ard.yaml similarity index 100% rename from tests/components/qr_code/test.esp8266.yaml rename to tests/components/qr_code/test.esp8266-ard.yaml diff --git a/tests/components/qr_code/test.rp2040.yaml b/tests/components/qr_code/test.rp2040-ard.yaml similarity index 100% rename from tests/components/qr_code/test.rp2040.yaml rename to tests/components/qr_code/test.rp2040-ard.yaml diff --git a/tests/components/qwiic_pir/test.esp32.yaml b/tests/components/qwiic_pir/test.esp32-ard.yaml similarity index 100% rename from tests/components/qwiic_pir/test.esp32.yaml rename to tests/components/qwiic_pir/test.esp32-ard.yaml diff --git a/tests/components/qwiic_pir/test.esp32-c3.yaml b/tests/components/qwiic_pir/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/qwiic_pir/test.esp32-c3.yaml rename to tests/components/qwiic_pir/test.esp32-c3-ard.yaml diff --git a/tests/components/qwiic_pir/test.esp8266.yaml b/tests/components/qwiic_pir/test.esp8266-ard.yaml similarity index 100% rename from tests/components/qwiic_pir/test.esp8266.yaml rename to tests/components/qwiic_pir/test.esp8266-ard.yaml diff --git a/tests/components/qwiic_pir/test.rp2040.yaml b/tests/components/qwiic_pir/test.rp2040-ard.yaml similarity index 100% rename from tests/components/qwiic_pir/test.rp2040.yaml rename to tests/components/qwiic_pir/test.rp2040-ard.yaml diff --git a/tests/components/radon_eye_ble/test.esp32-c3.yaml b/tests/components/radon_eye_ble/test.esp32-ard.yaml similarity index 100% rename from tests/components/radon_eye_ble/test.esp32-c3.yaml rename to tests/components/radon_eye_ble/test.esp32-ard.yaml diff --git a/tests/components/radon_eye_ble/test.esp32.yaml b/tests/components/radon_eye_ble/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/radon_eye_ble/test.esp32.yaml rename to tests/components/radon_eye_ble/test.esp32-c3-ard.yaml diff --git a/tests/components/radon_eye_rd200/test.esp32-c3.yaml b/tests/components/radon_eye_rd200/test.esp32-ard.yaml similarity index 100% rename from tests/components/radon_eye_rd200/test.esp32-c3.yaml rename to tests/components/radon_eye_rd200/test.esp32-ard.yaml diff --git a/tests/components/radon_eye_rd200/test.esp32.yaml b/tests/components/radon_eye_rd200/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/radon_eye_rd200/test.esp32.yaml rename to tests/components/radon_eye_rd200/test.esp32-c3-ard.yaml diff --git a/tests/components/rc522_i2c/test.esp32.yaml b/tests/components/rc522_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/rc522_i2c/test.esp32.yaml rename to tests/components/rc522_i2c/test.esp32-ard.yaml diff --git a/tests/components/rc522_i2c/test.esp32-c3.yaml b/tests/components/rc522_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rc522_i2c/test.esp32-c3.yaml rename to tests/components/rc522_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/rc522_i2c/test.esp8266.yaml b/tests/components/rc522_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rc522_i2c/test.esp8266.yaml rename to tests/components/rc522_i2c/test.esp8266-ard.yaml diff --git a/tests/components/rc522_i2c/test.rp2040.yaml b/tests/components/rc522_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rc522_i2c/test.rp2040.yaml rename to tests/components/rc522_i2c/test.rp2040-ard.yaml diff --git a/tests/components/rc522_spi/test.esp32.yaml b/tests/components/rc522_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/rc522_spi/test.esp32.yaml rename to tests/components/rc522_spi/test.esp32-ard.yaml diff --git a/tests/components/rc522_spi/test.esp32-c3.yaml b/tests/components/rc522_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rc522_spi/test.esp32-c3.yaml rename to tests/components/rc522_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/rc522_spi/test.esp8266.yaml b/tests/components/rc522_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rc522_spi/test.esp8266.yaml rename to tests/components/rc522_spi/test.esp8266-ard.yaml diff --git a/tests/components/rc522_spi/test.rp2040.yaml b/tests/components/rc522_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rc522_spi/test.rp2040.yaml rename to tests/components/rc522_spi/test.rp2040-ard.yaml diff --git a/tests/components/rdm6300/test.esp32.yaml b/tests/components/rdm6300/test.esp32-ard.yaml similarity index 100% rename from tests/components/rdm6300/test.esp32.yaml rename to tests/components/rdm6300/test.esp32-ard.yaml diff --git a/tests/components/rdm6300/test.esp32-c3.yaml b/tests/components/rdm6300/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rdm6300/test.esp32-c3.yaml rename to tests/components/rdm6300/test.esp32-c3-ard.yaml diff --git a/tests/components/rdm6300/test.esp8266.yaml b/tests/components/rdm6300/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rdm6300/test.esp8266.yaml rename to tests/components/rdm6300/test.esp8266-ard.yaml diff --git a/tests/components/rdm6300/test.rp2040.yaml b/tests/components/rdm6300/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rdm6300/test.rp2040.yaml rename to tests/components/rdm6300/test.rp2040-ard.yaml diff --git a/tests/components/remote_receiver/test.esp32-c3.yaml b/tests/components/remote_receiver/test.esp32-ard.yaml similarity index 100% rename from tests/components/remote_receiver/test.esp32-c3.yaml rename to tests/components/remote_receiver/test.esp32-ard.yaml diff --git a/tests/components/remote_receiver/test.esp32.yaml b/tests/components/remote_receiver/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/remote_receiver/test.esp32.yaml rename to tests/components/remote_receiver/test.esp32-c3-ard.yaml diff --git a/tests/components/remote_receiver/test.esp8266.yaml b/tests/components/remote_receiver/test.esp8266-ard.yaml similarity index 100% rename from tests/components/remote_receiver/test.esp8266.yaml rename to tests/components/remote_receiver/test.esp8266-ard.yaml diff --git a/tests/components/remote_transmitter/test.esp32.yaml b/tests/components/remote_transmitter/test.esp32-ard.yaml similarity index 100% rename from tests/components/remote_transmitter/test.esp32.yaml rename to tests/components/remote_transmitter/test.esp32-ard.yaml diff --git a/tests/components/remote_transmitter/test.esp32-c3.yaml b/tests/components/remote_transmitter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/remote_transmitter/test.esp32-c3.yaml rename to tests/components/remote_transmitter/test.esp32-c3-ard.yaml diff --git a/tests/components/remote_transmitter/test.esp8266.yaml b/tests/components/remote_transmitter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/remote_transmitter/test.esp8266.yaml rename to tests/components/remote_transmitter/test.esp8266-ard.yaml diff --git a/tests/components/resistance/test.esp32.yaml b/tests/components/resistance/test.esp32-ard.yaml similarity index 100% rename from tests/components/resistance/test.esp32.yaml rename to tests/components/resistance/test.esp32-ard.yaml diff --git a/tests/components/resistance/test.esp32-c3.yaml b/tests/components/resistance/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/resistance/test.esp32-c3.yaml rename to tests/components/resistance/test.esp32-c3-ard.yaml diff --git a/tests/components/resistance/test.esp32-s2.yaml b/tests/components/resistance/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/resistance/test.esp32-s2.yaml rename to tests/components/resistance/test.esp32-s2-ard.yaml diff --git a/tests/components/resistance/test.esp32-s3.yaml b/tests/components/resistance/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/resistance/test.esp32-s3.yaml rename to tests/components/resistance/test.esp32-s3-ard.yaml diff --git a/tests/components/resistance/test.esp8266.yaml b/tests/components/resistance/test.esp8266-ard.yaml similarity index 100% rename from tests/components/resistance/test.esp8266.yaml rename to tests/components/resistance/test.esp8266-ard.yaml diff --git a/tests/components/resistance/test.rp2040.yaml b/tests/components/resistance/test.rp2040-ard.yaml similarity index 100% rename from tests/components/resistance/test.rp2040.yaml rename to tests/components/resistance/test.rp2040-ard.yaml diff --git a/tests/components/restart/test.esp32-c3.yaml b/tests/components/restart/test.esp32-ard.yaml similarity index 100% rename from tests/components/restart/test.esp32-c3.yaml rename to tests/components/restart/test.esp32-ard.yaml diff --git a/tests/components/restart/test.esp32.yaml b/tests/components/restart/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/restart/test.esp32.yaml rename to tests/components/restart/test.esp32-c3-ard.yaml diff --git a/tests/components/restart/test.esp8266.yaml b/tests/components/restart/test.esp8266-ard.yaml similarity index 100% rename from tests/components/restart/test.esp8266.yaml rename to tests/components/restart/test.esp8266-ard.yaml diff --git a/tests/components/restart/test.rp2040.yaml b/tests/components/restart/test.rp2040-ard.yaml similarity index 100% rename from tests/components/restart/test.rp2040.yaml rename to tests/components/restart/test.rp2040-ard.yaml diff --git a/tests/components/rf_bridge/test.esp32.yaml b/tests/components/rf_bridge/test.esp32-ard.yaml similarity index 100% rename from tests/components/rf_bridge/test.esp32.yaml rename to tests/components/rf_bridge/test.esp32-ard.yaml diff --git a/tests/components/rf_bridge/test.esp32-c3.yaml b/tests/components/rf_bridge/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rf_bridge/test.esp32-c3.yaml rename to tests/components/rf_bridge/test.esp32-c3-ard.yaml diff --git a/tests/components/rf_bridge/test.esp8266.yaml b/tests/components/rf_bridge/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rf_bridge/test.esp8266.yaml rename to tests/components/rf_bridge/test.esp8266-ard.yaml diff --git a/tests/components/rf_bridge/test.rp2040.yaml b/tests/components/rf_bridge/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rf_bridge/test.rp2040.yaml rename to tests/components/rf_bridge/test.rp2040-ard.yaml diff --git a/tests/components/rgb/test.esp32.yaml b/tests/components/rgb/test.esp32-ard.yaml similarity index 100% rename from tests/components/rgb/test.esp32.yaml rename to tests/components/rgb/test.esp32-ard.yaml diff --git a/tests/components/rgb/test.esp32-c3.yaml b/tests/components/rgb/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rgb/test.esp32-c3.yaml rename to tests/components/rgb/test.esp32-c3-ard.yaml diff --git a/tests/components/rgb/test.esp8266.yaml b/tests/components/rgb/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rgb/test.esp8266.yaml rename to tests/components/rgb/test.esp8266-ard.yaml diff --git a/tests/components/rgb/test.rp2040.yaml b/tests/components/rgb/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rgb/test.rp2040.yaml rename to tests/components/rgb/test.rp2040-ard.yaml diff --git a/tests/components/rgbct/test.esp32.yaml b/tests/components/rgbct/test.esp32-ard.yaml similarity index 100% rename from tests/components/rgbct/test.esp32.yaml rename to tests/components/rgbct/test.esp32-ard.yaml diff --git a/tests/components/rgbct/test.esp32-c3.yaml b/tests/components/rgbct/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rgbct/test.esp32-c3.yaml rename to tests/components/rgbct/test.esp32-c3-ard.yaml diff --git a/tests/components/rgbct/test.esp8266.yaml b/tests/components/rgbct/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rgbct/test.esp8266.yaml rename to tests/components/rgbct/test.esp8266-ard.yaml diff --git a/tests/components/rgbct/test.rp2040.yaml b/tests/components/rgbct/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rgbct/test.rp2040.yaml rename to tests/components/rgbct/test.rp2040-ard.yaml diff --git a/tests/components/rgbw/test.esp32.yaml b/tests/components/rgbw/test.esp32-ard.yaml similarity index 100% rename from tests/components/rgbw/test.esp32.yaml rename to tests/components/rgbw/test.esp32-ard.yaml diff --git a/tests/components/rgbw/test.esp32-c3.yaml b/tests/components/rgbw/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rgbw/test.esp32-c3.yaml rename to tests/components/rgbw/test.esp32-c3-ard.yaml diff --git a/tests/components/rgbw/test.esp8266.yaml b/tests/components/rgbw/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rgbw/test.esp8266.yaml rename to tests/components/rgbw/test.esp8266-ard.yaml diff --git a/tests/components/rgbw/test.rp2040.yaml b/tests/components/rgbw/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rgbw/test.rp2040.yaml rename to tests/components/rgbw/test.rp2040-ard.yaml diff --git a/tests/components/rgbww/test.esp32.yaml b/tests/components/rgbww/test.esp32-ard.yaml similarity index 100% rename from tests/components/rgbww/test.esp32.yaml rename to tests/components/rgbww/test.esp32-ard.yaml diff --git a/tests/components/rgbww/test.esp32-c3.yaml b/tests/components/rgbww/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rgbww/test.esp32-c3.yaml rename to tests/components/rgbww/test.esp32-c3-ard.yaml diff --git a/tests/components/rgbww/test.esp8266.yaml b/tests/components/rgbww/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rgbww/test.esp8266.yaml rename to tests/components/rgbww/test.esp8266-ard.yaml diff --git a/tests/components/rgbww/test.rp2040.yaml b/tests/components/rgbww/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rgbww/test.rp2040.yaml rename to tests/components/rgbww/test.rp2040-ard.yaml diff --git a/tests/components/rotary_encoder/test.esp32.yaml b/tests/components/rotary_encoder/test.esp32-ard.yaml similarity index 100% rename from tests/components/rotary_encoder/test.esp32.yaml rename to tests/components/rotary_encoder/test.esp32-ard.yaml diff --git a/tests/components/rotary_encoder/test.esp32-c3.yaml b/tests/components/rotary_encoder/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rotary_encoder/test.esp32-c3.yaml rename to tests/components/rotary_encoder/test.esp32-c3-ard.yaml diff --git a/tests/components/rotary_encoder/test.esp8266.yaml b/tests/components/rotary_encoder/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rotary_encoder/test.esp8266.yaml rename to tests/components/rotary_encoder/test.esp8266-ard.yaml diff --git a/tests/components/rotary_encoder/test.rp2040.yaml b/tests/components/rotary_encoder/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rotary_encoder/test.rp2040.yaml rename to tests/components/rotary_encoder/test.rp2040-ard.yaml diff --git a/tests/components/rp2040_pio_led_strip/test.rp2040.yaml b/tests/components/rp2040_pio_led_strip/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rp2040_pio_led_strip/test.rp2040.yaml rename to tests/components/rp2040_pio_led_strip/test.rp2040-ard.yaml diff --git a/tests/components/rp2040_pwm/test.rp2040.yaml b/tests/components/rp2040_pwm/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rp2040_pwm/test.rp2040.yaml rename to tests/components/rp2040_pwm/test.rp2040-ard.yaml diff --git a/tests/components/rtttl/test.esp32.yaml b/tests/components/rtttl/test.esp32-ard.yaml similarity index 100% rename from tests/components/rtttl/test.esp32.yaml rename to tests/components/rtttl/test.esp32-ard.yaml diff --git a/tests/components/rtttl/test.esp32-c3.yaml b/tests/components/rtttl/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/rtttl/test.esp32-c3.yaml rename to tests/components/rtttl/test.esp32-c3-ard.yaml diff --git a/tests/components/rtttl/test.esp8266.yaml b/tests/components/rtttl/test.esp8266-ard.yaml similarity index 100% rename from tests/components/rtttl/test.esp8266.yaml rename to tests/components/rtttl/test.esp8266-ard.yaml diff --git a/tests/components/rtttl/test.rp2040.yaml b/tests/components/rtttl/test.rp2040-ard.yaml similarity index 100% rename from tests/components/rtttl/test.rp2040.yaml rename to tests/components/rtttl/test.rp2040-ard.yaml diff --git a/tests/components/ruuvi_ble/test.esp32-c3.yaml b/tests/components/ruuvi_ble/test.esp32-ard.yaml similarity index 100% rename from tests/components/ruuvi_ble/test.esp32-c3.yaml rename to tests/components/ruuvi_ble/test.esp32-ard.yaml diff --git a/tests/components/ruuvi_ble/test.esp32.yaml b/tests/components/ruuvi_ble/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ruuvi_ble/test.esp32.yaml rename to tests/components/ruuvi_ble/test.esp32-c3-ard.yaml diff --git a/tests/components/ruuvitag/test.esp32-c3.yaml b/tests/components/ruuvitag/test.esp32-ard.yaml similarity index 100% rename from tests/components/ruuvitag/test.esp32-c3.yaml rename to tests/components/ruuvitag/test.esp32-ard.yaml diff --git a/tests/components/ruuvitag/test.esp32.yaml b/tests/components/ruuvitag/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ruuvitag/test.esp32.yaml rename to tests/components/ruuvitag/test.esp32-c3-ard.yaml diff --git a/tests/components/safe_mode/test.esp32-c3.yaml b/tests/components/safe_mode/test.esp32-ard.yaml similarity index 100% rename from tests/components/safe_mode/test.esp32-c3.yaml rename to tests/components/safe_mode/test.esp32-ard.yaml diff --git a/tests/components/safe_mode/test.esp32.yaml b/tests/components/safe_mode/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/safe_mode/test.esp32.yaml rename to tests/components/safe_mode/test.esp32-c3-ard.yaml diff --git a/tests/components/safe_mode/test.esp8266.yaml b/tests/components/safe_mode/test.esp8266-ard.yaml similarity index 100% rename from tests/components/safe_mode/test.esp8266.yaml rename to tests/components/safe_mode/test.esp8266-ard.yaml diff --git a/tests/components/safe_mode/test.rp2040.yaml b/tests/components/safe_mode/test.rp2040-ard.yaml similarity index 100% rename from tests/components/safe_mode/test.rp2040.yaml rename to tests/components/safe_mode/test.rp2040-ard.yaml diff --git a/tests/components/scd30/test.esp32.yaml b/tests/components/scd30/test.esp32-ard.yaml similarity index 100% rename from tests/components/scd30/test.esp32.yaml rename to tests/components/scd30/test.esp32-ard.yaml diff --git a/tests/components/scd30/test.esp32-c3.yaml b/tests/components/scd30/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/scd30/test.esp32-c3.yaml rename to tests/components/scd30/test.esp32-c3-ard.yaml diff --git a/tests/components/scd30/test.esp8266.yaml b/tests/components/scd30/test.esp8266-ard.yaml similarity index 100% rename from tests/components/scd30/test.esp8266.yaml rename to tests/components/scd30/test.esp8266-ard.yaml diff --git a/tests/components/scd30/test.rp2040.yaml b/tests/components/scd30/test.rp2040-ard.yaml similarity index 100% rename from tests/components/scd30/test.rp2040.yaml rename to tests/components/scd30/test.rp2040-ard.yaml diff --git a/tests/components/scd4x/test.esp32.yaml b/tests/components/scd4x/test.esp32-ard.yaml similarity index 100% rename from tests/components/scd4x/test.esp32.yaml rename to tests/components/scd4x/test.esp32-ard.yaml diff --git a/tests/components/scd4x/test.esp32-c3.yaml b/tests/components/scd4x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/scd4x/test.esp32-c3.yaml rename to tests/components/scd4x/test.esp32-c3-ard.yaml diff --git a/tests/components/scd4x/test.esp8266.yaml b/tests/components/scd4x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/scd4x/test.esp8266.yaml rename to tests/components/scd4x/test.esp8266-ard.yaml diff --git a/tests/components/scd4x/test.rp2040.yaml b/tests/components/scd4x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/scd4x/test.rp2040.yaml rename to tests/components/scd4x/test.rp2040-ard.yaml diff --git a/tests/components/script/test.bk72xx.yaml b/tests/components/script/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/script/test.bk72xx.yaml rename to tests/components/script/test.bk72xx-ard.yaml diff --git a/tests/components/script/test.esp32-c3.yaml b/tests/components/script/test.esp32-ard.yaml similarity index 100% rename from tests/components/script/test.esp32-c3.yaml rename to tests/components/script/test.esp32-ard.yaml diff --git a/tests/components/script/test.esp32.yaml b/tests/components/script/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/script/test.esp32.yaml rename to tests/components/script/test.esp32-c3-ard.yaml diff --git a/tests/components/script/test.esp8266.yaml b/tests/components/script/test.esp8266-ard.yaml similarity index 100% rename from tests/components/script/test.esp8266.yaml rename to tests/components/script/test.esp8266-ard.yaml diff --git a/tests/components/script/test.rp2040.yaml b/tests/components/script/test.rp2040-ard.yaml similarity index 100% rename from tests/components/script/test.rp2040.yaml rename to tests/components/script/test.rp2040-ard.yaml diff --git a/tests/components/sdm_meter/test.esp32.yaml b/tests/components/sdm_meter/test.esp32-ard.yaml similarity index 100% rename from tests/components/sdm_meter/test.esp32.yaml rename to tests/components/sdm_meter/test.esp32-ard.yaml diff --git a/tests/components/sdm_meter/test.esp32-c3.yaml b/tests/components/sdm_meter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sdm_meter/test.esp32-c3.yaml rename to tests/components/sdm_meter/test.esp32-c3-ard.yaml diff --git a/tests/components/sdm_meter/test.esp8266.yaml b/tests/components/sdm_meter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sdm_meter/test.esp8266.yaml rename to tests/components/sdm_meter/test.esp8266-ard.yaml diff --git a/tests/components/sdm_meter/test.rp2040.yaml b/tests/components/sdm_meter/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sdm_meter/test.rp2040.yaml rename to tests/components/sdm_meter/test.rp2040-ard.yaml diff --git a/tests/components/sdp3x/test.esp32.yaml b/tests/components/sdp3x/test.esp32-ard.yaml similarity index 100% rename from tests/components/sdp3x/test.esp32.yaml rename to tests/components/sdp3x/test.esp32-ard.yaml diff --git a/tests/components/sdp3x/test.esp32-c3.yaml b/tests/components/sdp3x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sdp3x/test.esp32-c3.yaml rename to tests/components/sdp3x/test.esp32-c3-ard.yaml diff --git a/tests/components/sdp3x/test.esp8266.yaml b/tests/components/sdp3x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sdp3x/test.esp8266.yaml rename to tests/components/sdp3x/test.esp8266-ard.yaml diff --git a/tests/components/sdp3x/test.rp2040.yaml b/tests/components/sdp3x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sdp3x/test.rp2040.yaml rename to tests/components/sdp3x/test.rp2040-ard.yaml diff --git a/tests/components/sds011/test.esp32.yaml b/tests/components/sds011/test.esp32-ard.yaml similarity index 100% rename from tests/components/sds011/test.esp32.yaml rename to tests/components/sds011/test.esp32-ard.yaml diff --git a/tests/components/sds011/test.esp32-c3.yaml b/tests/components/sds011/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sds011/test.esp32-c3.yaml rename to tests/components/sds011/test.esp32-c3-ard.yaml diff --git a/tests/components/sds011/test.esp8266.yaml b/tests/components/sds011/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sds011/test.esp8266.yaml rename to tests/components/sds011/test.esp8266-ard.yaml diff --git a/tests/components/sds011/test.rp2040.yaml b/tests/components/sds011/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sds011/test.rp2040.yaml rename to tests/components/sds011/test.rp2040-ard.yaml diff --git a/tests/components/seeed_mr24hpc1/test.esp32-c3.yaml b/tests/components/seeed_mr24hpc1/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/seeed_mr24hpc1/test.esp32-c3.yaml rename to tests/components/seeed_mr24hpc1/test.esp32-c3-ard.yaml diff --git a/tests/components/selec_meter/test.esp32.yaml b/tests/components/selec_meter/test.esp32-ard.yaml similarity index 100% rename from tests/components/selec_meter/test.esp32.yaml rename to tests/components/selec_meter/test.esp32-ard.yaml diff --git a/tests/components/selec_meter/test.esp32-c3.yaml b/tests/components/selec_meter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/selec_meter/test.esp32-c3.yaml rename to tests/components/selec_meter/test.esp32-c3-ard.yaml diff --git a/tests/components/selec_meter/test.esp8266.yaml b/tests/components/selec_meter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/selec_meter/test.esp8266.yaml rename to tests/components/selec_meter/test.esp8266-ard.yaml diff --git a/tests/components/selec_meter/test.rp2040.yaml b/tests/components/selec_meter/test.rp2040-ard.yaml similarity index 100% rename from tests/components/selec_meter/test.rp2040.yaml rename to tests/components/selec_meter/test.rp2040-ard.yaml diff --git a/tests/components/sen0321/test.esp32.yaml b/tests/components/sen0321/test.esp32-ard.yaml similarity index 100% rename from tests/components/sen0321/test.esp32.yaml rename to tests/components/sen0321/test.esp32-ard.yaml diff --git a/tests/components/sen0321/test.esp32-c3.yaml b/tests/components/sen0321/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sen0321/test.esp32-c3.yaml rename to tests/components/sen0321/test.esp32-c3-ard.yaml diff --git a/tests/components/sen0321/test.esp8266.yaml b/tests/components/sen0321/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sen0321/test.esp8266.yaml rename to tests/components/sen0321/test.esp8266-ard.yaml diff --git a/tests/components/sen0321/test.rp2040.yaml b/tests/components/sen0321/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sen0321/test.rp2040.yaml rename to tests/components/sen0321/test.rp2040-ard.yaml diff --git a/tests/components/sen21231/test.esp32.yaml b/tests/components/sen21231/test.esp32-ard.yaml similarity index 100% rename from tests/components/sen21231/test.esp32.yaml rename to tests/components/sen21231/test.esp32-ard.yaml diff --git a/tests/components/sen21231/test.esp32-c3.yaml b/tests/components/sen21231/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sen21231/test.esp32-c3.yaml rename to tests/components/sen21231/test.esp32-c3-ard.yaml diff --git a/tests/components/sen21231/test.esp8266.yaml b/tests/components/sen21231/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sen21231/test.esp8266.yaml rename to tests/components/sen21231/test.esp8266-ard.yaml diff --git a/tests/components/sen21231/test.rp2040.yaml b/tests/components/sen21231/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sen21231/test.rp2040.yaml rename to tests/components/sen21231/test.rp2040-ard.yaml diff --git a/tests/components/sen5x/test.esp32.yaml b/tests/components/sen5x/test.esp32-ard.yaml similarity index 100% rename from tests/components/sen5x/test.esp32.yaml rename to tests/components/sen5x/test.esp32-ard.yaml diff --git a/tests/components/sen5x/test.esp32-c3.yaml b/tests/components/sen5x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sen5x/test.esp32-c3.yaml rename to tests/components/sen5x/test.esp32-c3-ard.yaml diff --git a/tests/components/sen5x/test.esp8266.yaml b/tests/components/sen5x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sen5x/test.esp8266.yaml rename to tests/components/sen5x/test.esp8266-ard.yaml diff --git a/tests/components/sen5x/test.rp2040.yaml b/tests/components/sen5x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sen5x/test.rp2040.yaml rename to tests/components/sen5x/test.rp2040-ard.yaml diff --git a/tests/components/senseair/test.esp32.yaml b/tests/components/senseair/test.esp32-ard.yaml similarity index 100% rename from tests/components/senseair/test.esp32.yaml rename to tests/components/senseair/test.esp32-ard.yaml diff --git a/tests/components/senseair/test.esp32-c3.yaml b/tests/components/senseair/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/senseair/test.esp32-c3.yaml rename to tests/components/senseair/test.esp32-c3-ard.yaml diff --git a/tests/components/senseair/test.esp8266.yaml b/tests/components/senseair/test.esp8266-ard.yaml similarity index 100% rename from tests/components/senseair/test.esp8266.yaml rename to tests/components/senseair/test.esp8266-ard.yaml diff --git a/tests/components/senseair/test.rp2040.yaml b/tests/components/senseair/test.rp2040-ard.yaml similarity index 100% rename from tests/components/senseair/test.rp2040.yaml rename to tests/components/senseair/test.rp2040-ard.yaml diff --git a/tests/components/servo/test.esp32.yaml b/tests/components/servo/test.esp32-ard.yaml similarity index 100% rename from tests/components/servo/test.esp32.yaml rename to tests/components/servo/test.esp32-ard.yaml diff --git a/tests/components/servo/test.esp32-c3.yaml b/tests/components/servo/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/servo/test.esp32-c3.yaml rename to tests/components/servo/test.esp32-c3-ard.yaml diff --git a/tests/components/servo/test.esp8266.yaml b/tests/components/servo/test.esp8266-ard.yaml similarity index 100% rename from tests/components/servo/test.esp8266.yaml rename to tests/components/servo/test.esp8266-ard.yaml diff --git a/tests/components/servo/test.rp2040.yaml b/tests/components/servo/test.rp2040-ard.yaml similarity index 100% rename from tests/components/servo/test.rp2040.yaml rename to tests/components/servo/test.rp2040-ard.yaml diff --git a/tests/components/sfa30/test.esp32.yaml b/tests/components/sfa30/test.esp32-ard.yaml similarity index 100% rename from tests/components/sfa30/test.esp32.yaml rename to tests/components/sfa30/test.esp32-ard.yaml diff --git a/tests/components/sfa30/test.esp32-c3.yaml b/tests/components/sfa30/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sfa30/test.esp32-c3.yaml rename to tests/components/sfa30/test.esp32-c3-ard.yaml diff --git a/tests/components/sfa30/test.esp8266.yaml b/tests/components/sfa30/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sfa30/test.esp8266.yaml rename to tests/components/sfa30/test.esp8266-ard.yaml diff --git a/tests/components/sfa30/test.rp2040.yaml b/tests/components/sfa30/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sfa30/test.rp2040.yaml rename to tests/components/sfa30/test.rp2040-ard.yaml diff --git a/tests/components/sgp30/test.esp32.yaml b/tests/components/sgp30/test.esp32-ard.yaml similarity index 100% rename from tests/components/sgp30/test.esp32.yaml rename to tests/components/sgp30/test.esp32-ard.yaml diff --git a/tests/components/sgp30/test.esp32-c3.yaml b/tests/components/sgp30/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sgp30/test.esp32-c3.yaml rename to tests/components/sgp30/test.esp32-c3-ard.yaml diff --git a/tests/components/sgp30/test.esp8266.yaml b/tests/components/sgp30/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sgp30/test.esp8266.yaml rename to tests/components/sgp30/test.esp8266-ard.yaml diff --git a/tests/components/sgp30/test.rp2040.yaml b/tests/components/sgp30/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sgp30/test.rp2040.yaml rename to tests/components/sgp30/test.rp2040-ard.yaml diff --git a/tests/components/sgp4x/test.esp32.yaml b/tests/components/sgp4x/test.esp32-ard.yaml similarity index 100% rename from tests/components/sgp4x/test.esp32.yaml rename to tests/components/sgp4x/test.esp32-ard.yaml diff --git a/tests/components/sgp4x/test.esp32-c3.yaml b/tests/components/sgp4x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sgp4x/test.esp32-c3.yaml rename to tests/components/sgp4x/test.esp32-c3-ard.yaml diff --git a/tests/components/sgp4x/test.esp8266.yaml b/tests/components/sgp4x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sgp4x/test.esp8266.yaml rename to tests/components/sgp4x/test.esp8266-ard.yaml diff --git a/tests/components/sgp4x/test.rp2040.yaml b/tests/components/sgp4x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sgp4x/test.rp2040.yaml rename to tests/components/sgp4x/test.rp2040-ard.yaml diff --git a/tests/components/shelly_dimmer/test.esp8266.yaml b/tests/components/shelly_dimmer/test.esp8266-ard.yaml similarity index 100% rename from tests/components/shelly_dimmer/test.esp8266.yaml rename to tests/components/shelly_dimmer/test.esp8266-ard.yaml diff --git a/tests/components/sht3xd/test.esp32.yaml b/tests/components/sht3xd/test.esp32-ard.yaml similarity index 100% rename from tests/components/sht3xd/test.esp32.yaml rename to tests/components/sht3xd/test.esp32-ard.yaml diff --git a/tests/components/sht3xd/test.esp32-c3.yaml b/tests/components/sht3xd/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sht3xd/test.esp32-c3.yaml rename to tests/components/sht3xd/test.esp32-c3-ard.yaml diff --git a/tests/components/sht3xd/test.esp8266.yaml b/tests/components/sht3xd/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sht3xd/test.esp8266.yaml rename to tests/components/sht3xd/test.esp8266-ard.yaml diff --git a/tests/components/sht3xd/test.rp2040.yaml b/tests/components/sht3xd/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sht3xd/test.rp2040.yaml rename to tests/components/sht3xd/test.rp2040-ard.yaml diff --git a/tests/components/sht4x/test.esp32.yaml b/tests/components/sht4x/test.esp32-ard.yaml similarity index 100% rename from tests/components/sht4x/test.esp32.yaml rename to tests/components/sht4x/test.esp32-ard.yaml diff --git a/tests/components/sht4x/test.esp32-c3.yaml b/tests/components/sht4x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sht4x/test.esp32-c3.yaml rename to tests/components/sht4x/test.esp32-c3-ard.yaml diff --git a/tests/components/sht4x/test.esp8266.yaml b/tests/components/sht4x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sht4x/test.esp8266.yaml rename to tests/components/sht4x/test.esp8266-ard.yaml diff --git a/tests/components/sht4x/test.rp2040.yaml b/tests/components/sht4x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sht4x/test.rp2040.yaml rename to tests/components/sht4x/test.rp2040-ard.yaml diff --git a/tests/components/shtcx/test.esp32.yaml b/tests/components/shtcx/test.esp32-ard.yaml similarity index 100% rename from tests/components/shtcx/test.esp32.yaml rename to tests/components/shtcx/test.esp32-ard.yaml diff --git a/tests/components/shtcx/test.esp32-c3.yaml b/tests/components/shtcx/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/shtcx/test.esp32-c3.yaml rename to tests/components/shtcx/test.esp32-c3-ard.yaml diff --git a/tests/components/shtcx/test.esp8266.yaml b/tests/components/shtcx/test.esp8266-ard.yaml similarity index 100% rename from tests/components/shtcx/test.esp8266.yaml rename to tests/components/shtcx/test.esp8266-ard.yaml diff --git a/tests/components/shtcx/test.rp2040.yaml b/tests/components/shtcx/test.rp2040-ard.yaml similarity index 100% rename from tests/components/shtcx/test.rp2040.yaml rename to tests/components/shtcx/test.rp2040-ard.yaml diff --git a/tests/components/shutdown/test.esp32-c3.yaml b/tests/components/shutdown/test.esp32-ard.yaml similarity index 100% rename from tests/components/shutdown/test.esp32-c3.yaml rename to tests/components/shutdown/test.esp32-ard.yaml diff --git a/tests/components/shutdown/test.esp32.yaml b/tests/components/shutdown/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/shutdown/test.esp32.yaml rename to tests/components/shutdown/test.esp32-c3-ard.yaml diff --git a/tests/components/shutdown/test.esp8266.yaml b/tests/components/shutdown/test.esp8266-ard.yaml similarity index 100% rename from tests/components/shutdown/test.esp8266.yaml rename to tests/components/shutdown/test.esp8266-ard.yaml diff --git a/tests/components/shutdown/test.rp2040.yaml b/tests/components/shutdown/test.rp2040-ard.yaml similarity index 100% rename from tests/components/shutdown/test.rp2040.yaml rename to tests/components/shutdown/test.rp2040-ard.yaml diff --git a/tests/components/sigma_delta_output/test.esp32-c3.yaml b/tests/components/sigma_delta_output/test.esp32-ard.yaml similarity index 100% rename from tests/components/sigma_delta_output/test.esp32-c3.yaml rename to tests/components/sigma_delta_output/test.esp32-ard.yaml diff --git a/tests/components/sigma_delta_output/test.esp32.yaml b/tests/components/sigma_delta_output/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sigma_delta_output/test.esp32.yaml rename to tests/components/sigma_delta_output/test.esp32-c3-ard.yaml diff --git a/tests/components/sigma_delta_output/test.esp8266.yaml b/tests/components/sigma_delta_output/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sigma_delta_output/test.esp8266.yaml rename to tests/components/sigma_delta_output/test.esp8266-ard.yaml diff --git a/tests/components/sigma_delta_output/test.rp2040.yaml b/tests/components/sigma_delta_output/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sigma_delta_output/test.rp2040.yaml rename to tests/components/sigma_delta_output/test.rp2040-ard.yaml diff --git a/tests/components/sim800l/test.esp32.yaml b/tests/components/sim800l/test.esp32-ard.yaml similarity index 100% rename from tests/components/sim800l/test.esp32.yaml rename to tests/components/sim800l/test.esp32-ard.yaml diff --git a/tests/components/sim800l/test.esp32-c3.yaml b/tests/components/sim800l/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sim800l/test.esp32-c3.yaml rename to tests/components/sim800l/test.esp32-c3-ard.yaml diff --git a/tests/components/sim800l/test.esp8266.yaml b/tests/components/sim800l/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sim800l/test.esp8266.yaml rename to tests/components/sim800l/test.esp8266-ard.yaml diff --git a/tests/components/sim800l/test.rp2040.yaml b/tests/components/sim800l/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sim800l/test.rp2040.yaml rename to tests/components/sim800l/test.rp2040-ard.yaml diff --git a/tests/components/slow_pwm/test.esp32-c3.yaml b/tests/components/slow_pwm/test.esp32-ard.yaml similarity index 100% rename from tests/components/slow_pwm/test.esp32-c3.yaml rename to tests/components/slow_pwm/test.esp32-ard.yaml diff --git a/tests/components/slow_pwm/test.esp32.yaml b/tests/components/slow_pwm/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/slow_pwm/test.esp32.yaml rename to tests/components/slow_pwm/test.esp32-c3-ard.yaml diff --git a/tests/components/slow_pwm/test.esp8266.yaml b/tests/components/slow_pwm/test.esp8266-ard.yaml similarity index 100% rename from tests/components/slow_pwm/test.esp8266.yaml rename to tests/components/slow_pwm/test.esp8266-ard.yaml diff --git a/tests/components/slow_pwm/test.rp2040.yaml b/tests/components/slow_pwm/test.rp2040-ard.yaml similarity index 100% rename from tests/components/slow_pwm/test.rp2040.yaml rename to tests/components/slow_pwm/test.rp2040-ard.yaml diff --git a/tests/components/sm16716/test.esp32-c3.yaml b/tests/components/sm16716/test.esp32-ard.yaml similarity index 100% rename from tests/components/sm16716/test.esp32-c3.yaml rename to tests/components/sm16716/test.esp32-ard.yaml diff --git a/tests/components/sm16716/test.esp32.yaml b/tests/components/sm16716/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sm16716/test.esp32.yaml rename to tests/components/sm16716/test.esp32-c3-ard.yaml diff --git a/tests/components/sm16716/test.esp8266.yaml b/tests/components/sm16716/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sm16716/test.esp8266.yaml rename to tests/components/sm16716/test.esp8266-ard.yaml diff --git a/tests/components/sm16716/test.rp2040.yaml b/tests/components/sm16716/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sm16716/test.rp2040.yaml rename to tests/components/sm16716/test.rp2040-ard.yaml diff --git a/tests/components/sm2135/test.esp32-c3.yaml b/tests/components/sm2135/test.esp32-ard.yaml similarity index 100% rename from tests/components/sm2135/test.esp32-c3.yaml rename to tests/components/sm2135/test.esp32-ard.yaml diff --git a/tests/components/sm2135/test.esp32.yaml b/tests/components/sm2135/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sm2135/test.esp32.yaml rename to tests/components/sm2135/test.esp32-c3-ard.yaml diff --git a/tests/components/sm2135/test.esp8266.yaml b/tests/components/sm2135/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sm2135/test.esp8266.yaml rename to tests/components/sm2135/test.esp8266-ard.yaml diff --git a/tests/components/sm2135/test.rp2040.yaml b/tests/components/sm2135/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sm2135/test.rp2040.yaml rename to tests/components/sm2135/test.rp2040-ard.yaml diff --git a/tests/components/sm2235/test.esp32-c3.yaml b/tests/components/sm2235/test.esp32-ard.yaml similarity index 100% rename from tests/components/sm2235/test.esp32-c3.yaml rename to tests/components/sm2235/test.esp32-ard.yaml diff --git a/tests/components/sm2235/test.esp32.yaml b/tests/components/sm2235/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sm2235/test.esp32.yaml rename to tests/components/sm2235/test.esp32-c3-ard.yaml diff --git a/tests/components/sm2235/test.esp8266.yaml b/tests/components/sm2235/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sm2235/test.esp8266.yaml rename to tests/components/sm2235/test.esp8266-ard.yaml diff --git a/tests/components/sm2235/test.rp2040.yaml b/tests/components/sm2235/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sm2235/test.rp2040.yaml rename to tests/components/sm2235/test.rp2040-ard.yaml diff --git a/tests/components/sm2335/test.esp32-c3.yaml b/tests/components/sm2335/test.esp32-ard.yaml similarity index 100% rename from tests/components/sm2335/test.esp32-c3.yaml rename to tests/components/sm2335/test.esp32-ard.yaml diff --git a/tests/components/sm2335/test.esp32.yaml b/tests/components/sm2335/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sm2335/test.esp32.yaml rename to tests/components/sm2335/test.esp32-c3-ard.yaml diff --git a/tests/components/sm2335/test.esp8266.yaml b/tests/components/sm2335/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sm2335/test.esp8266.yaml rename to tests/components/sm2335/test.esp8266-ard.yaml diff --git a/tests/components/sm2335/test.rp2040.yaml b/tests/components/sm2335/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sm2335/test.rp2040.yaml rename to tests/components/sm2335/test.rp2040-ard.yaml diff --git a/tests/components/sm300d2/test.esp32.yaml b/tests/components/sm300d2/test.esp32-ard.yaml similarity index 100% rename from tests/components/sm300d2/test.esp32.yaml rename to tests/components/sm300d2/test.esp32-ard.yaml diff --git a/tests/components/sm300d2/test.esp32-c3.yaml b/tests/components/sm300d2/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sm300d2/test.esp32-c3.yaml rename to tests/components/sm300d2/test.esp32-c3-ard.yaml diff --git a/tests/components/sm300d2/test.esp8266.yaml b/tests/components/sm300d2/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sm300d2/test.esp8266.yaml rename to tests/components/sm300d2/test.esp8266-ard.yaml diff --git a/tests/components/sm300d2/test.rp2040.yaml b/tests/components/sm300d2/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sm300d2/test.rp2040.yaml rename to tests/components/sm300d2/test.rp2040-ard.yaml diff --git a/tests/components/sml/test.esp32.yaml b/tests/components/sml/test.esp32-ard.yaml similarity index 100% rename from tests/components/sml/test.esp32.yaml rename to tests/components/sml/test.esp32-ard.yaml diff --git a/tests/components/sml/test.esp32-c3.yaml b/tests/components/sml/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sml/test.esp32-c3.yaml rename to tests/components/sml/test.esp32-c3-ard.yaml diff --git a/tests/components/sml/test.esp8266.yaml b/tests/components/sml/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sml/test.esp8266.yaml rename to tests/components/sml/test.esp8266-ard.yaml diff --git a/tests/components/sml/test.rp2040.yaml b/tests/components/sml/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sml/test.rp2040.yaml rename to tests/components/sml/test.rp2040-ard.yaml diff --git a/tests/components/smt100/test.esp32.yaml b/tests/components/smt100/test.esp32-ard.yaml similarity index 100% rename from tests/components/smt100/test.esp32.yaml rename to tests/components/smt100/test.esp32-ard.yaml diff --git a/tests/components/smt100/test.esp32-c3.yaml b/tests/components/smt100/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/smt100/test.esp32-c3.yaml rename to tests/components/smt100/test.esp32-c3-ard.yaml diff --git a/tests/components/smt100/test.esp8266.yaml b/tests/components/smt100/test.esp8266-ard.yaml similarity index 100% rename from tests/components/smt100/test.esp8266.yaml rename to tests/components/smt100/test.esp8266-ard.yaml diff --git a/tests/components/smt100/test.rp2040.yaml b/tests/components/smt100/test.rp2040-ard.yaml similarity index 100% rename from tests/components/smt100/test.rp2040.yaml rename to tests/components/smt100/test.rp2040-ard.yaml diff --git a/tests/components/sn74hc165/test.esp32.yaml b/tests/components/sn74hc165/test.esp32-ard.yaml similarity index 100% rename from tests/components/sn74hc165/test.esp32.yaml rename to tests/components/sn74hc165/test.esp32-ard.yaml diff --git a/tests/components/sn74hc165/test.esp32-c3.yaml b/tests/components/sn74hc165/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sn74hc165/test.esp32-c3.yaml rename to tests/components/sn74hc165/test.esp32-c3-ard.yaml diff --git a/tests/components/sn74hc165/test.esp8266.yaml b/tests/components/sn74hc165/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sn74hc165/test.esp8266.yaml rename to tests/components/sn74hc165/test.esp8266-ard.yaml diff --git a/tests/components/sn74hc165/test.rp2040.yaml b/tests/components/sn74hc165/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sn74hc165/test.rp2040.yaml rename to tests/components/sn74hc165/test.rp2040-ard.yaml diff --git a/tests/components/sn74hc595/test.esp32.yaml b/tests/components/sn74hc595/test.esp32-ard.yaml similarity index 100% rename from tests/components/sn74hc595/test.esp32.yaml rename to tests/components/sn74hc595/test.esp32-ard.yaml diff --git a/tests/components/sn74hc595/test.esp32-c3.yaml b/tests/components/sn74hc595/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sn74hc595/test.esp32-c3.yaml rename to tests/components/sn74hc595/test.esp32-c3-ard.yaml diff --git a/tests/components/sn74hc595/test.esp8266.yaml b/tests/components/sn74hc595/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sn74hc595/test.esp8266.yaml rename to tests/components/sn74hc595/test.esp8266-ard.yaml diff --git a/tests/components/sn74hc595/test.rp2040.yaml b/tests/components/sn74hc595/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sn74hc595/test.rp2040.yaml rename to tests/components/sn74hc595/test.rp2040-ard.yaml diff --git a/tests/components/sntp/test.bk72xx.yaml b/tests/components/sntp/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/sntp/test.bk72xx.yaml rename to tests/components/sntp/test.bk72xx-ard.yaml diff --git a/tests/components/sntp/test.esp32-c3.yaml b/tests/components/sntp/test.esp32-ard.yaml similarity index 100% rename from tests/components/sntp/test.esp32-c3.yaml rename to tests/components/sntp/test.esp32-ard.yaml diff --git a/tests/components/sntp/test.esp32.yaml b/tests/components/sntp/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sntp/test.esp32.yaml rename to tests/components/sntp/test.esp32-c3-ard.yaml diff --git a/tests/components/sntp/test.esp8266.yaml b/tests/components/sntp/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sntp/test.esp8266.yaml rename to tests/components/sntp/test.esp8266-ard.yaml diff --git a/tests/components/sntp/test.rp2040.yaml b/tests/components/sntp/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sntp/test.rp2040.yaml rename to tests/components/sntp/test.rp2040-ard.yaml diff --git a/tests/components/sonoff_d1/test.esp32.yaml b/tests/components/sonoff_d1/test.esp32-ard.yaml similarity index 100% rename from tests/components/sonoff_d1/test.esp32.yaml rename to tests/components/sonoff_d1/test.esp32-ard.yaml diff --git a/tests/components/sonoff_d1/test.esp8266.yaml b/tests/components/sonoff_d1/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sonoff_d1/test.esp8266.yaml rename to tests/components/sonoff_d1/test.esp8266-ard.yaml diff --git a/tests/components/speaker/test.esp32.yaml b/tests/components/speaker/test.esp32-ard.yaml similarity index 100% rename from tests/components/speaker/test.esp32.yaml rename to tests/components/speaker/test.esp32-ard.yaml diff --git a/tests/components/speaker/test.esp32-c3.yaml b/tests/components/speaker/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/speaker/test.esp32-c3.yaml rename to tests/components/speaker/test.esp32-c3-ard.yaml diff --git a/tests/components/speed/test.esp32.yaml b/tests/components/speed/test.esp32-ard.yaml similarity index 100% rename from tests/components/speed/test.esp32.yaml rename to tests/components/speed/test.esp32-ard.yaml diff --git a/tests/components/speed/test.esp32-c3.yaml b/tests/components/speed/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/speed/test.esp32-c3.yaml rename to tests/components/speed/test.esp32-c3-ard.yaml diff --git a/tests/components/speed/test.esp8266.yaml b/tests/components/speed/test.esp8266-ard.yaml similarity index 100% rename from tests/components/speed/test.esp8266.yaml rename to tests/components/speed/test.esp8266-ard.yaml diff --git a/tests/components/speed/test.rp2040.yaml b/tests/components/speed/test.rp2040-ard.yaml similarity index 100% rename from tests/components/speed/test.rp2040.yaml rename to tests/components/speed/test.rp2040-ard.yaml diff --git a/tests/components/spi/test.esp32.yaml b/tests/components/spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/spi/test.esp32.yaml rename to tests/components/spi/test.esp32-ard.yaml diff --git a/tests/components/spi/test.esp32-c3.yaml b/tests/components/spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/spi/test.esp32-c3.yaml rename to tests/components/spi/test.esp32-c3-ard.yaml diff --git a/tests/components/spi/test.esp8266.yaml b/tests/components/spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/spi/test.esp8266.yaml rename to tests/components/spi/test.esp8266-ard.yaml diff --git a/tests/components/spi/test.rp2040.yaml b/tests/components/spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/spi/test.rp2040.yaml rename to tests/components/spi/test.rp2040-ard.yaml diff --git a/tests/components/spi_device/test.esp32.yaml b/tests/components/spi_device/test.esp32-ard.yaml similarity index 100% rename from tests/components/spi_device/test.esp32.yaml rename to tests/components/spi_device/test.esp32-ard.yaml diff --git a/tests/components/spi_device/test.esp32-c3.yaml b/tests/components/spi_device/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/spi_device/test.esp32-c3.yaml rename to tests/components/spi_device/test.esp32-c3-ard.yaml diff --git a/tests/components/spi_device/test.esp8266.yaml b/tests/components/spi_device/test.esp8266-ard.yaml similarity index 100% rename from tests/components/spi_device/test.esp8266.yaml rename to tests/components/spi_device/test.esp8266-ard.yaml diff --git a/tests/components/spi_device/test.rp2040.yaml b/tests/components/spi_device/test.rp2040-ard.yaml similarity index 100% rename from tests/components/spi_device/test.rp2040.yaml rename to tests/components/spi_device/test.rp2040-ard.yaml diff --git a/tests/components/spi_led_strip/test.esp32.yaml b/tests/components/spi_led_strip/test.esp32-ard.yaml similarity index 100% rename from tests/components/spi_led_strip/test.esp32.yaml rename to tests/components/spi_led_strip/test.esp32-ard.yaml diff --git a/tests/components/spi_led_strip/test.esp32-c3.yaml b/tests/components/spi_led_strip/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/spi_led_strip/test.esp32-c3.yaml rename to tests/components/spi_led_strip/test.esp32-c3-ard.yaml diff --git a/tests/components/spi_led_strip/test.esp8266.yaml b/tests/components/spi_led_strip/test.esp8266-ard.yaml similarity index 100% rename from tests/components/spi_led_strip/test.esp8266.yaml rename to tests/components/spi_led_strip/test.esp8266-ard.yaml diff --git a/tests/components/spi_led_strip/test.rp2040.yaml b/tests/components/spi_led_strip/test.rp2040-ard.yaml similarity index 100% rename from tests/components/spi_led_strip/test.rp2040.yaml rename to tests/components/spi_led_strip/test.rp2040-ard.yaml diff --git a/tests/components/sprinkler/test.esp32-c3.yaml b/tests/components/sprinkler/test.esp32-ard.yaml similarity index 100% rename from tests/components/sprinkler/test.esp32-c3.yaml rename to tests/components/sprinkler/test.esp32-ard.yaml diff --git a/tests/components/sprinkler/test.esp32.yaml b/tests/components/sprinkler/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sprinkler/test.esp32.yaml rename to tests/components/sprinkler/test.esp32-c3-ard.yaml diff --git a/tests/components/sprinkler/test.esp8266.yaml b/tests/components/sprinkler/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sprinkler/test.esp8266.yaml rename to tests/components/sprinkler/test.esp8266-ard.yaml diff --git a/tests/components/sprinkler/test.rp2040.yaml b/tests/components/sprinkler/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sprinkler/test.rp2040.yaml rename to tests/components/sprinkler/test.rp2040-ard.yaml diff --git a/tests/components/sps30/test.esp32.yaml b/tests/components/sps30/test.esp32-ard.yaml similarity index 100% rename from tests/components/sps30/test.esp32.yaml rename to tests/components/sps30/test.esp32-ard.yaml diff --git a/tests/components/sps30/test.esp32-c3.yaml b/tests/components/sps30/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sps30/test.esp32-c3.yaml rename to tests/components/sps30/test.esp32-c3-ard.yaml diff --git a/tests/components/sps30/test.esp8266.yaml b/tests/components/sps30/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sps30/test.esp8266.yaml rename to tests/components/sps30/test.esp8266-ard.yaml diff --git a/tests/components/sps30/test.rp2040.yaml b/tests/components/sps30/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sps30/test.rp2040.yaml rename to tests/components/sps30/test.rp2040-ard.yaml diff --git a/tests/components/ssd1306_i2c/test.esp32.yaml b/tests/components/ssd1306_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1306_i2c/test.esp32.yaml rename to tests/components/ssd1306_i2c/test.esp32-ard.yaml diff --git a/tests/components/ssd1306_i2c/test.esp32-c3.yaml b/tests/components/ssd1306_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1306_i2c/test.esp32-c3.yaml rename to tests/components/ssd1306_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1306_i2c/test.esp8266.yaml b/tests/components/ssd1306_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1306_i2c/test.esp8266.yaml rename to tests/components/ssd1306_i2c/test.esp8266-ard.yaml diff --git a/tests/components/ssd1306_i2c/test.rp2040.yaml b/tests/components/ssd1306_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1306_i2c/test.rp2040.yaml rename to tests/components/ssd1306_i2c/test.rp2040-ard.yaml diff --git a/tests/components/ssd1306_spi/test.esp32.yaml b/tests/components/ssd1306_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1306_spi/test.esp32.yaml rename to tests/components/ssd1306_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1306_spi/test.esp32-c3.yaml b/tests/components/ssd1306_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1306_spi/test.esp32-c3.yaml rename to tests/components/ssd1306_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1306_spi/test.esp8266.yaml b/tests/components/ssd1306_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1306_spi/test.esp8266.yaml rename to tests/components/ssd1306_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1306_spi/test.rp2040.yaml b/tests/components/ssd1306_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1306_spi/test.rp2040.yaml rename to tests/components/ssd1306_spi/test.rp2040-ard.yaml diff --git a/tests/components/ssd1322_spi/test.esp32.yaml b/tests/components/ssd1322_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1322_spi/test.esp32.yaml rename to tests/components/ssd1322_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1322_spi/test.esp32-c3.yaml b/tests/components/ssd1322_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1322_spi/test.esp32-c3.yaml rename to tests/components/ssd1322_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1322_spi/test.esp8266.yaml b/tests/components/ssd1322_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1322_spi/test.esp8266.yaml rename to tests/components/ssd1322_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1322_spi/test.rp2040.yaml b/tests/components/ssd1322_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1322_spi/test.rp2040.yaml rename to tests/components/ssd1322_spi/test.rp2040-ard.yaml diff --git a/tests/components/ssd1325_spi/test.esp32.yaml b/tests/components/ssd1325_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1325_spi/test.esp32.yaml rename to tests/components/ssd1325_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1325_spi/test.esp32-c3.yaml b/tests/components/ssd1325_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1325_spi/test.esp32-c3.yaml rename to tests/components/ssd1325_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1325_spi/test.esp8266.yaml b/tests/components/ssd1325_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1325_spi/test.esp8266.yaml rename to tests/components/ssd1325_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1325_spi/test.rp2040.yaml b/tests/components/ssd1325_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1325_spi/test.rp2040.yaml rename to tests/components/ssd1325_spi/test.rp2040-ard.yaml diff --git a/tests/components/ssd1327_i2c/test.esp32.yaml b/tests/components/ssd1327_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1327_i2c/test.esp32.yaml rename to tests/components/ssd1327_i2c/test.esp32-ard.yaml diff --git a/tests/components/ssd1327_i2c/test.esp32-c3.yaml b/tests/components/ssd1327_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1327_i2c/test.esp32-c3.yaml rename to tests/components/ssd1327_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1327_i2c/test.esp8266.yaml b/tests/components/ssd1327_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1327_i2c/test.esp8266.yaml rename to tests/components/ssd1327_i2c/test.esp8266-ard.yaml diff --git a/tests/components/ssd1327_i2c/test.rp2040.yaml b/tests/components/ssd1327_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1327_i2c/test.rp2040.yaml rename to tests/components/ssd1327_i2c/test.rp2040-ard.yaml diff --git a/tests/components/ssd1327_spi/test.esp32.yaml b/tests/components/ssd1327_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1327_spi/test.esp32.yaml rename to tests/components/ssd1327_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1327_spi/test.esp32-c3.yaml b/tests/components/ssd1327_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1327_spi/test.esp32-c3.yaml rename to tests/components/ssd1327_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1327_spi/test.esp8266.yaml b/tests/components/ssd1327_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1327_spi/test.esp8266.yaml rename to tests/components/ssd1327_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1327_spi/test.rp2040.yaml b/tests/components/ssd1327_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1327_spi/test.rp2040.yaml rename to tests/components/ssd1327_spi/test.rp2040-ard.yaml diff --git a/tests/components/ssd1331_spi/test.esp32.yaml b/tests/components/ssd1331_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1331_spi/test.esp32.yaml rename to tests/components/ssd1331_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1331_spi/test.esp32-c3.yaml b/tests/components/ssd1331_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1331_spi/test.esp32-c3.yaml rename to tests/components/ssd1331_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1331_spi/test.esp8266.yaml b/tests/components/ssd1331_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1331_spi/test.esp8266.yaml rename to tests/components/ssd1331_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1331_spi/test.rp2040.yaml b/tests/components/ssd1331_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1331_spi/test.rp2040.yaml rename to tests/components/ssd1331_spi/test.rp2040-ard.yaml diff --git a/tests/components/ssd1351_spi/test.esp32.yaml b/tests/components/ssd1351_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/ssd1351_spi/test.esp32.yaml rename to tests/components/ssd1351_spi/test.esp32-ard.yaml diff --git a/tests/components/ssd1351_spi/test.esp32-c3.yaml b/tests/components/ssd1351_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ssd1351_spi/test.esp32-c3.yaml rename to tests/components/ssd1351_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/ssd1351_spi/test.esp8266.yaml b/tests/components/ssd1351_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ssd1351_spi/test.esp8266.yaml rename to tests/components/ssd1351_spi/test.esp8266-ard.yaml diff --git a/tests/components/ssd1351_spi/test.rp2040.yaml b/tests/components/ssd1351_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ssd1351_spi/test.rp2040.yaml rename to tests/components/ssd1351_spi/test.rp2040-ard.yaml diff --git a/tests/components/st7567_i2c/test.esp32.yaml b/tests/components/st7567_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/st7567_i2c/test.esp32.yaml rename to tests/components/st7567_i2c/test.esp32-ard.yaml diff --git a/tests/components/st7567_i2c/test.esp32-c3.yaml b/tests/components/st7567_i2c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/st7567_i2c/test.esp32-c3.yaml rename to tests/components/st7567_i2c/test.esp32-c3-ard.yaml diff --git a/tests/components/st7567_i2c/test.esp8266.yaml b/tests/components/st7567_i2c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/st7567_i2c/test.esp8266.yaml rename to tests/components/st7567_i2c/test.esp8266-ard.yaml diff --git a/tests/components/st7567_i2c/test.rp2040.yaml b/tests/components/st7567_i2c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/st7567_i2c/test.rp2040.yaml rename to tests/components/st7567_i2c/test.rp2040-ard.yaml diff --git a/tests/components/st7567_spi/test.esp32.yaml b/tests/components/st7567_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/st7567_spi/test.esp32.yaml rename to tests/components/st7567_spi/test.esp32-ard.yaml diff --git a/tests/components/st7567_spi/test.esp32-c3.yaml b/tests/components/st7567_spi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/st7567_spi/test.esp32-c3.yaml rename to tests/components/st7567_spi/test.esp32-c3-ard.yaml diff --git a/tests/components/st7567_spi/test.esp8266.yaml b/tests/components/st7567_spi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/st7567_spi/test.esp8266.yaml rename to tests/components/st7567_spi/test.esp8266-ard.yaml diff --git a/tests/components/st7567_spi/test.rp2040.yaml b/tests/components/st7567_spi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/st7567_spi/test.rp2040.yaml rename to tests/components/st7567_spi/test.rp2040-ard.yaml diff --git a/tests/components/st7735/test.esp32.yaml b/tests/components/st7735/test.esp32-ard.yaml similarity index 100% rename from tests/components/st7735/test.esp32.yaml rename to tests/components/st7735/test.esp32-ard.yaml diff --git a/tests/components/st7735/test.esp32-c3.yaml b/tests/components/st7735/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/st7735/test.esp32-c3.yaml rename to tests/components/st7735/test.esp32-c3-ard.yaml diff --git a/tests/components/st7735/test.esp8266.yaml b/tests/components/st7735/test.esp8266-ard.yaml similarity index 100% rename from tests/components/st7735/test.esp8266.yaml rename to tests/components/st7735/test.esp8266-ard.yaml diff --git a/tests/components/st7735/test.rp2040.yaml b/tests/components/st7735/test.rp2040-ard.yaml similarity index 100% rename from tests/components/st7735/test.rp2040.yaml rename to tests/components/st7735/test.rp2040-ard.yaml diff --git a/tests/components/st7789v/test.esp32.yaml b/tests/components/st7789v/test.esp32-ard.yaml similarity index 100% rename from tests/components/st7789v/test.esp32.yaml rename to tests/components/st7789v/test.esp32-ard.yaml diff --git a/tests/components/st7789v/test.esp32-c3.yaml b/tests/components/st7789v/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/st7789v/test.esp32-c3.yaml rename to tests/components/st7789v/test.esp32-c3-ard.yaml diff --git a/tests/components/st7789v/test.esp8266.yaml b/tests/components/st7789v/test.esp8266-ard.yaml similarity index 100% rename from tests/components/st7789v/test.esp8266.yaml rename to tests/components/st7789v/test.esp8266-ard.yaml diff --git a/tests/components/st7789v/test.rp2040.yaml b/tests/components/st7789v/test.rp2040-ard.yaml similarity index 100% rename from tests/components/st7789v/test.rp2040.yaml rename to tests/components/st7789v/test.rp2040-ard.yaml diff --git a/tests/components/st7920/test.esp32.yaml b/tests/components/st7920/test.esp32-ard.yaml similarity index 100% rename from tests/components/st7920/test.esp32.yaml rename to tests/components/st7920/test.esp32-ard.yaml diff --git a/tests/components/st7920/test.esp32-c3.yaml b/tests/components/st7920/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/st7920/test.esp32-c3.yaml rename to tests/components/st7920/test.esp32-c3-ard.yaml diff --git a/tests/components/st7920/test.esp8266.yaml b/tests/components/st7920/test.esp8266-ard.yaml similarity index 100% rename from tests/components/st7920/test.esp8266.yaml rename to tests/components/st7920/test.esp8266-ard.yaml diff --git a/tests/components/st7920/test.rp2040.yaml b/tests/components/st7920/test.rp2040-ard.yaml similarity index 100% rename from tests/components/st7920/test.rp2040.yaml rename to tests/components/st7920/test.rp2040-ard.yaml diff --git a/tests/components/status/test.esp32-c3.yaml b/tests/components/status/test.esp32-ard.yaml similarity index 100% rename from tests/components/status/test.esp32-c3.yaml rename to tests/components/status/test.esp32-ard.yaml diff --git a/tests/components/status/test.esp32.yaml b/tests/components/status/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/status/test.esp32.yaml rename to tests/components/status/test.esp32-c3-ard.yaml diff --git a/tests/components/status/test.esp8266.yaml b/tests/components/status/test.esp8266-ard.yaml similarity index 100% rename from tests/components/status/test.esp8266.yaml rename to tests/components/status/test.esp8266-ard.yaml diff --git a/tests/components/status/test.rp2040.yaml b/tests/components/status/test.rp2040-ard.yaml similarity index 100% rename from tests/components/status/test.rp2040.yaml rename to tests/components/status/test.rp2040-ard.yaml diff --git a/tests/components/status_led/test.esp32-c3.yaml b/tests/components/status_led/test.esp32-ard.yaml similarity index 100% rename from tests/components/status_led/test.esp32-c3.yaml rename to tests/components/status_led/test.esp32-ard.yaml diff --git a/tests/components/status_led/test.esp32.yaml b/tests/components/status_led/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/status_led/test.esp32.yaml rename to tests/components/status_led/test.esp32-c3-ard.yaml diff --git a/tests/components/status_led/test.esp8266.yaml b/tests/components/status_led/test.esp8266-ard.yaml similarity index 100% rename from tests/components/status_led/test.esp8266.yaml rename to tests/components/status_led/test.esp8266-ard.yaml diff --git a/tests/components/status_led/test.rp2040.yaml b/tests/components/status_led/test.rp2040-ard.yaml similarity index 100% rename from tests/components/status_led/test.rp2040.yaml rename to tests/components/status_led/test.rp2040-ard.yaml diff --git a/tests/components/stepper/test.esp32-c3.yaml b/tests/components/stepper/test.esp32-ard.yaml similarity index 100% rename from tests/components/stepper/test.esp32-c3.yaml rename to tests/components/stepper/test.esp32-ard.yaml diff --git a/tests/components/stepper/test.esp32.yaml b/tests/components/stepper/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/stepper/test.esp32.yaml rename to tests/components/stepper/test.esp32-c3-ard.yaml diff --git a/tests/components/stepper/test.esp8266.yaml b/tests/components/stepper/test.esp8266-ard.yaml similarity index 100% rename from tests/components/stepper/test.esp8266.yaml rename to tests/components/stepper/test.esp8266-ard.yaml diff --git a/tests/components/stepper/test.rp2040.yaml b/tests/components/stepper/test.rp2040-ard.yaml similarity index 100% rename from tests/components/stepper/test.rp2040.yaml rename to tests/components/stepper/test.rp2040-ard.yaml diff --git a/tests/components/sts3x/test.esp32.yaml b/tests/components/sts3x/test.esp32-ard.yaml similarity index 100% rename from tests/components/sts3x/test.esp32.yaml rename to tests/components/sts3x/test.esp32-ard.yaml diff --git a/tests/components/sts3x/test.esp32-c3.yaml b/tests/components/sts3x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sts3x/test.esp32-c3.yaml rename to tests/components/sts3x/test.esp32-c3-ard.yaml diff --git a/tests/components/sts3x/test.esp8266.yaml b/tests/components/sts3x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sts3x/test.esp8266.yaml rename to tests/components/sts3x/test.esp8266-ard.yaml diff --git a/tests/components/sts3x/test.rp2040.yaml b/tests/components/sts3x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sts3x/test.rp2040.yaml rename to tests/components/sts3x/test.rp2040-ard.yaml diff --git a/tests/components/sun/test.esp32-c3.yaml b/tests/components/sun/test.esp32-ard.yaml similarity index 100% rename from tests/components/sun/test.esp32-c3.yaml rename to tests/components/sun/test.esp32-ard.yaml diff --git a/tests/components/sun/test.esp32.yaml b/tests/components/sun/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sun/test.esp32.yaml rename to tests/components/sun/test.esp32-c3-ard.yaml diff --git a/tests/components/sun/test.esp8266.yaml b/tests/components/sun/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sun/test.esp8266.yaml rename to tests/components/sun/test.esp8266-ard.yaml diff --git a/tests/components/sun/test.rp2040.yaml b/tests/components/sun/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sun/test.rp2040.yaml rename to tests/components/sun/test.rp2040-ard.yaml diff --git a/tests/components/sun_gtil2/test.esp32.yaml b/tests/components/sun_gtil2/test.esp32-ard.yaml similarity index 100% rename from tests/components/sun_gtil2/test.esp32.yaml rename to tests/components/sun_gtil2/test.esp32-ard.yaml diff --git a/tests/components/sun_gtil2/test.esp32-c3.yaml b/tests/components/sun_gtil2/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sun_gtil2/test.esp32-c3.yaml rename to tests/components/sun_gtil2/test.esp32-c3-ard.yaml diff --git a/tests/components/sun_gtil2/test.esp8266.yaml b/tests/components/sun_gtil2/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sun_gtil2/test.esp8266.yaml rename to tests/components/sun_gtil2/test.esp8266-ard.yaml diff --git a/tests/components/sun_gtil2/test.rp2040.yaml b/tests/components/sun_gtil2/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sun_gtil2/test.rp2040.yaml rename to tests/components/sun_gtil2/test.rp2040-ard.yaml diff --git a/tests/components/sx1509/test.esp32.yaml b/tests/components/sx1509/test.esp32-ard.yaml similarity index 100% rename from tests/components/sx1509/test.esp32.yaml rename to tests/components/sx1509/test.esp32-ard.yaml diff --git a/tests/components/sx1509/test.esp32-c3.yaml b/tests/components/sx1509/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/sx1509/test.esp32-c3.yaml rename to tests/components/sx1509/test.esp32-c3-ard.yaml diff --git a/tests/components/sx1509/test.esp8266.yaml b/tests/components/sx1509/test.esp8266-ard.yaml similarity index 100% rename from tests/components/sx1509/test.esp8266.yaml rename to tests/components/sx1509/test.esp8266-ard.yaml diff --git a/tests/components/sx1509/test.rp2040.yaml b/tests/components/sx1509/test.rp2040-ard.yaml similarity index 100% rename from tests/components/sx1509/test.rp2040.yaml rename to tests/components/sx1509/test.rp2040-ard.yaml diff --git a/tests/components/t6615/test.esp32.yaml b/tests/components/t6615/test.esp32-ard.yaml similarity index 100% rename from tests/components/t6615/test.esp32.yaml rename to tests/components/t6615/test.esp32-ard.yaml diff --git a/tests/components/t6615/test.esp32-c3.yaml b/tests/components/t6615/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/t6615/test.esp32-c3.yaml rename to tests/components/t6615/test.esp32-c3-ard.yaml diff --git a/tests/components/t6615/test.esp8266.yaml b/tests/components/t6615/test.esp8266-ard.yaml similarity index 100% rename from tests/components/t6615/test.esp8266.yaml rename to tests/components/t6615/test.esp8266-ard.yaml diff --git a/tests/components/t6615/test.rp2040.yaml b/tests/components/t6615/test.rp2040-ard.yaml similarity index 100% rename from tests/components/t6615/test.rp2040.yaml rename to tests/components/t6615/test.rp2040-ard.yaml diff --git a/tests/components/tca9548a/test.esp32.yaml b/tests/components/tca9548a/test.esp32-ard.yaml similarity index 100% rename from tests/components/tca9548a/test.esp32.yaml rename to tests/components/tca9548a/test.esp32-ard.yaml diff --git a/tests/components/tca9548a/test.esp32-c3.yaml b/tests/components/tca9548a/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tca9548a/test.esp32-c3.yaml rename to tests/components/tca9548a/test.esp32-c3-ard.yaml diff --git a/tests/components/tca9548a/test.esp8266.yaml b/tests/components/tca9548a/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tca9548a/test.esp8266.yaml rename to tests/components/tca9548a/test.esp8266-ard.yaml diff --git a/tests/components/tca9548a/test.rp2040.yaml b/tests/components/tca9548a/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tca9548a/test.rp2040.yaml rename to tests/components/tca9548a/test.rp2040-ard.yaml diff --git a/tests/components/tcl112/test.esp32-c3.yaml b/tests/components/tcl112/test.esp32-ard.yaml similarity index 100% rename from tests/components/tcl112/test.esp32-c3.yaml rename to tests/components/tcl112/test.esp32-ard.yaml diff --git a/tests/components/tcl112/test.esp32.yaml b/tests/components/tcl112/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tcl112/test.esp32.yaml rename to tests/components/tcl112/test.esp32-c3-ard.yaml diff --git a/tests/components/tcl112/test.esp8266.yaml b/tests/components/tcl112/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tcl112/test.esp8266.yaml rename to tests/components/tcl112/test.esp8266-ard.yaml diff --git a/tests/components/tcs34725/test.esp32.yaml b/tests/components/tcs34725/test.esp32-ard.yaml similarity index 100% rename from tests/components/tcs34725/test.esp32.yaml rename to tests/components/tcs34725/test.esp32-ard.yaml diff --git a/tests/components/tcs34725/test.esp32-c3.yaml b/tests/components/tcs34725/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tcs34725/test.esp32-c3.yaml rename to tests/components/tcs34725/test.esp32-c3-ard.yaml diff --git a/tests/components/tcs34725/test.esp8266.yaml b/tests/components/tcs34725/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tcs34725/test.esp8266.yaml rename to tests/components/tcs34725/test.esp8266-ard.yaml diff --git a/tests/components/tcs34725/test.rp2040.yaml b/tests/components/tcs34725/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tcs34725/test.rp2040.yaml rename to tests/components/tcs34725/test.rp2040-ard.yaml diff --git a/tests/components/tee501/test.esp32.yaml b/tests/components/tee501/test.esp32-ard.yaml similarity index 100% rename from tests/components/tee501/test.esp32.yaml rename to tests/components/tee501/test.esp32-ard.yaml diff --git a/tests/components/tee501/test.esp32-c3.yaml b/tests/components/tee501/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tee501/test.esp32-c3.yaml rename to tests/components/tee501/test.esp32-c3-ard.yaml diff --git a/tests/components/tee501/test.esp8266.yaml b/tests/components/tee501/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tee501/test.esp8266.yaml rename to tests/components/tee501/test.esp8266-ard.yaml diff --git a/tests/components/tee501/test.rp2040.yaml b/tests/components/tee501/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tee501/test.rp2040.yaml rename to tests/components/tee501/test.rp2040-ard.yaml diff --git a/tests/components/teleinfo/test.esp32.yaml b/tests/components/teleinfo/test.esp32-ard.yaml similarity index 100% rename from tests/components/teleinfo/test.esp32.yaml rename to tests/components/teleinfo/test.esp32-ard.yaml diff --git a/tests/components/teleinfo/test.esp32-c3.yaml b/tests/components/teleinfo/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/teleinfo/test.esp32-c3.yaml rename to tests/components/teleinfo/test.esp32-c3-ard.yaml diff --git a/tests/components/teleinfo/test.esp8266.yaml b/tests/components/teleinfo/test.esp8266-ard.yaml similarity index 100% rename from tests/components/teleinfo/test.esp8266.yaml rename to tests/components/teleinfo/test.esp8266-ard.yaml diff --git a/tests/components/teleinfo/test.rp2040.yaml b/tests/components/teleinfo/test.rp2040-ard.yaml similarity index 100% rename from tests/components/teleinfo/test.rp2040.yaml rename to tests/components/teleinfo/test.rp2040-ard.yaml diff --git a/tests/components/template/test.bk72xx.yaml b/tests/components/template/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/template/test.bk72xx.yaml rename to tests/components/template/test.bk72xx-ard.yaml diff --git a/tests/components/template/test.esp32-c3.yaml b/tests/components/template/test.esp32-ard.yaml similarity index 100% rename from tests/components/template/test.esp32-c3.yaml rename to tests/components/template/test.esp32-ard.yaml diff --git a/tests/components/template/test.esp32.yaml b/tests/components/template/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/template/test.esp32.yaml rename to tests/components/template/test.esp32-c3-ard.yaml diff --git a/tests/components/template/test.esp8266.yaml b/tests/components/template/test.esp8266-ard.yaml similarity index 100% rename from tests/components/template/test.esp8266.yaml rename to tests/components/template/test.esp8266-ard.yaml diff --git a/tests/components/template/test.rp2040.yaml b/tests/components/template/test.rp2040-ard.yaml similarity index 100% rename from tests/components/template/test.rp2040.yaml rename to tests/components/template/test.rp2040-ard.yaml diff --git a/tests/components/thermostat/test.esp32-c3.yaml b/tests/components/thermostat/test.esp32-ard.yaml similarity index 100% rename from tests/components/thermostat/test.esp32-c3.yaml rename to tests/components/thermostat/test.esp32-ard.yaml diff --git a/tests/components/thermostat/test.esp32.yaml b/tests/components/thermostat/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/thermostat/test.esp32.yaml rename to tests/components/thermostat/test.esp32-c3-ard.yaml diff --git a/tests/components/thermostat/test.esp8266.yaml b/tests/components/thermostat/test.esp8266-ard.yaml similarity index 100% rename from tests/components/thermostat/test.esp8266.yaml rename to tests/components/thermostat/test.esp8266-ard.yaml diff --git a/tests/components/thermostat/test.rp2040.yaml b/tests/components/thermostat/test.rp2040-ard.yaml similarity index 100% rename from tests/components/thermostat/test.rp2040.yaml rename to tests/components/thermostat/test.rp2040-ard.yaml diff --git a/tests/components/time/test.esp32-c3.yaml b/tests/components/time/test.esp32-ard.yaml similarity index 100% rename from tests/components/time/test.esp32-c3.yaml rename to tests/components/time/test.esp32-ard.yaml diff --git a/tests/components/time/test.esp32.yaml b/tests/components/time/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/time/test.esp32.yaml rename to tests/components/time/test.esp32-c3-ard.yaml diff --git a/tests/components/time/test.esp8266.yaml b/tests/components/time/test.esp8266-ard.yaml similarity index 100% rename from tests/components/time/test.esp8266.yaml rename to tests/components/time/test.esp8266-ard.yaml diff --git a/tests/components/time/test.rp2040.yaml b/tests/components/time/test.rp2040-ard.yaml similarity index 100% rename from tests/components/time/test.rp2040.yaml rename to tests/components/time/test.rp2040-ard.yaml diff --git a/tests/components/time_based/test.esp32-c3.yaml b/tests/components/time_based/test.esp32-ard.yaml similarity index 100% rename from tests/components/time_based/test.esp32-c3.yaml rename to tests/components/time_based/test.esp32-ard.yaml diff --git a/tests/components/time_based/test.esp32.yaml b/tests/components/time_based/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/time_based/test.esp32.yaml rename to tests/components/time_based/test.esp32-c3-ard.yaml diff --git a/tests/components/time_based/test.esp8266.yaml b/tests/components/time_based/test.esp8266-ard.yaml similarity index 100% rename from tests/components/time_based/test.esp8266.yaml rename to tests/components/time_based/test.esp8266-ard.yaml diff --git a/tests/components/time_based/test.rp2040.yaml b/tests/components/time_based/test.rp2040-ard.yaml similarity index 100% rename from tests/components/time_based/test.rp2040.yaml rename to tests/components/time_based/test.rp2040-ard.yaml diff --git a/tests/components/tlc59208f/test.esp32.yaml b/tests/components/tlc59208f/test.esp32-ard.yaml similarity index 100% rename from tests/components/tlc59208f/test.esp32.yaml rename to tests/components/tlc59208f/test.esp32-ard.yaml diff --git a/tests/components/tlc59208f/test.esp32-c3.yaml b/tests/components/tlc59208f/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tlc59208f/test.esp32-c3.yaml rename to tests/components/tlc59208f/test.esp32-c3-ard.yaml diff --git a/tests/components/tlc59208f/test.esp8266.yaml b/tests/components/tlc59208f/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tlc59208f/test.esp8266.yaml rename to tests/components/tlc59208f/test.esp8266-ard.yaml diff --git a/tests/components/tlc59208f/test.rp2040.yaml b/tests/components/tlc59208f/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tlc59208f/test.rp2040.yaml rename to tests/components/tlc59208f/test.rp2040-ard.yaml diff --git a/tests/components/tlc5947/test.esp32.yaml b/tests/components/tlc5947/test.esp32-ard.yaml similarity index 100% rename from tests/components/tlc5947/test.esp32.yaml rename to tests/components/tlc5947/test.esp32-ard.yaml diff --git a/tests/components/tlc5947/test.esp32-c3.yaml b/tests/components/tlc5947/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tlc5947/test.esp32-c3.yaml rename to tests/components/tlc5947/test.esp32-c3-ard.yaml diff --git a/tests/components/tlc5947/test.esp8266.yaml b/tests/components/tlc5947/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tlc5947/test.esp8266.yaml rename to tests/components/tlc5947/test.esp8266-ard.yaml diff --git a/tests/components/tlc5947/test.rp2040.yaml b/tests/components/tlc5947/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tlc5947/test.rp2040.yaml rename to tests/components/tlc5947/test.rp2040-ard.yaml diff --git a/tests/components/tlc5971/test.esp32.yaml b/tests/components/tlc5971/test.esp32-ard.yaml similarity index 100% rename from tests/components/tlc5971/test.esp32.yaml rename to tests/components/tlc5971/test.esp32-ard.yaml diff --git a/tests/components/tlc5971/test.esp32-c3.yaml b/tests/components/tlc5971/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tlc5971/test.esp32-c3.yaml rename to tests/components/tlc5971/test.esp32-c3-ard.yaml diff --git a/tests/components/tlc5971/test.esp32-s2.yaml b/tests/components/tlc5971/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/tlc5971/test.esp32-s2.yaml rename to tests/components/tlc5971/test.esp32-s2-ard.yaml diff --git a/tests/components/tlc5971/test.esp8266.yaml b/tests/components/tlc5971/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tlc5971/test.esp8266.yaml rename to tests/components/tlc5971/test.esp8266-ard.yaml diff --git a/tests/components/tlc5971/test.rp2040.yaml b/tests/components/tlc5971/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tlc5971/test.rp2040.yaml rename to tests/components/tlc5971/test.rp2040-ard.yaml diff --git a/tests/components/tm1621/test.esp32.yaml b/tests/components/tm1621/test.esp32-ard.yaml similarity index 100% rename from tests/components/tm1621/test.esp32.yaml rename to tests/components/tm1621/test.esp32-ard.yaml diff --git a/tests/components/tm1621/test.esp32-c3.yaml b/tests/components/tm1621/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tm1621/test.esp32-c3.yaml rename to tests/components/tm1621/test.esp32-c3-ard.yaml diff --git a/tests/components/tm1621/test.esp8266.yaml b/tests/components/tm1621/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tm1621/test.esp8266.yaml rename to tests/components/tm1621/test.esp8266-ard.yaml diff --git a/tests/components/tm1621/test.rp2040.yaml b/tests/components/tm1621/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tm1621/test.rp2040.yaml rename to tests/components/tm1621/test.rp2040-ard.yaml diff --git a/tests/components/tm1637/test.esp32.yaml b/tests/components/tm1637/test.esp32-ard.yaml similarity index 100% rename from tests/components/tm1637/test.esp32.yaml rename to tests/components/tm1637/test.esp32-ard.yaml diff --git a/tests/components/tm1637/test.esp32-c3.yaml b/tests/components/tm1637/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tm1637/test.esp32-c3.yaml rename to tests/components/tm1637/test.esp32-c3-ard.yaml diff --git a/tests/components/tm1637/test.esp8266.yaml b/tests/components/tm1637/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tm1637/test.esp8266.yaml rename to tests/components/tm1637/test.esp8266-ard.yaml diff --git a/tests/components/tm1637/test.rp2040.yaml b/tests/components/tm1637/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tm1637/test.rp2040.yaml rename to tests/components/tm1637/test.rp2040-ard.yaml diff --git a/tests/components/tm1638/test.esp32-c3.yaml b/tests/components/tm1638/test.esp32-ard.yaml similarity index 100% rename from tests/components/tm1638/test.esp32-c3.yaml rename to tests/components/tm1638/test.esp32-ard.yaml diff --git a/tests/components/tm1638/test.esp32.yaml b/tests/components/tm1638/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tm1638/test.esp32.yaml rename to tests/components/tm1638/test.esp32-c3-ard.yaml diff --git a/tests/components/tm1638/test.esp8266.yaml b/tests/components/tm1638/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tm1638/test.esp8266.yaml rename to tests/components/tm1638/test.esp8266-ard.yaml diff --git a/tests/components/tm1638/test.rp2040.yaml b/tests/components/tm1638/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tm1638/test.rp2040.yaml rename to tests/components/tm1638/test.rp2040-ard.yaml diff --git a/tests/components/tm1651/test.esp32-c3.yaml b/tests/components/tm1651/test.esp32-ard.yaml similarity index 100% rename from tests/components/tm1651/test.esp32-c3.yaml rename to tests/components/tm1651/test.esp32-ard.yaml diff --git a/tests/components/tm1651/test.esp32.yaml b/tests/components/tm1651/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tm1651/test.esp32.yaml rename to tests/components/tm1651/test.esp32-c3-ard.yaml diff --git a/tests/components/tm1651/test.esp8266.yaml b/tests/components/tm1651/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tm1651/test.esp8266.yaml rename to tests/components/tm1651/test.esp8266-ard.yaml diff --git a/tests/components/tm1651/test.rp2040.yaml b/tests/components/tm1651/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tm1651/test.rp2040.yaml rename to tests/components/tm1651/test.rp2040-ard.yaml diff --git a/tests/components/tmp102/test.esp32.yaml b/tests/components/tmp102/test.esp32-ard.yaml similarity index 100% rename from tests/components/tmp102/test.esp32.yaml rename to tests/components/tmp102/test.esp32-ard.yaml diff --git a/tests/components/tmp102/test.esp32-c3.yaml b/tests/components/tmp102/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tmp102/test.esp32-c3.yaml rename to tests/components/tmp102/test.esp32-c3-ard.yaml diff --git a/tests/components/tmp102/test.esp8266.yaml b/tests/components/tmp102/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tmp102/test.esp8266.yaml rename to tests/components/tmp102/test.esp8266-ard.yaml diff --git a/tests/components/tmp102/test.rp2040.yaml b/tests/components/tmp102/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tmp102/test.rp2040.yaml rename to tests/components/tmp102/test.rp2040-ard.yaml diff --git a/tests/components/tmp1075/test.esp32.yaml b/tests/components/tmp1075/test.esp32-ard.yaml similarity index 100% rename from tests/components/tmp1075/test.esp32.yaml rename to tests/components/tmp1075/test.esp32-ard.yaml diff --git a/tests/components/tmp1075/test.esp32-c3.yaml b/tests/components/tmp1075/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tmp1075/test.esp32-c3.yaml rename to tests/components/tmp1075/test.esp32-c3-ard.yaml diff --git a/tests/components/tmp1075/test.esp8266.yaml b/tests/components/tmp1075/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tmp1075/test.esp8266.yaml rename to tests/components/tmp1075/test.esp8266-ard.yaml diff --git a/tests/components/tmp1075/test.rp2040.yaml b/tests/components/tmp1075/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tmp1075/test.rp2040.yaml rename to tests/components/tmp1075/test.rp2040-ard.yaml diff --git a/tests/components/tmp117/test.esp32.yaml b/tests/components/tmp117/test.esp32-ard.yaml similarity index 100% rename from tests/components/tmp117/test.esp32.yaml rename to tests/components/tmp117/test.esp32-ard.yaml diff --git a/tests/components/tmp117/test.esp32-c3.yaml b/tests/components/tmp117/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tmp117/test.esp32-c3.yaml rename to tests/components/tmp117/test.esp32-c3-ard.yaml diff --git a/tests/components/tmp117/test.esp8266.yaml b/tests/components/tmp117/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tmp117/test.esp8266.yaml rename to tests/components/tmp117/test.esp8266-ard.yaml diff --git a/tests/components/tmp117/test.rp2040.yaml b/tests/components/tmp117/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tmp117/test.rp2040.yaml rename to tests/components/tmp117/test.rp2040-ard.yaml diff --git a/tests/components/tof10120/test.esp32.yaml b/tests/components/tof10120/test.esp32-ard.yaml similarity index 100% rename from tests/components/tof10120/test.esp32.yaml rename to tests/components/tof10120/test.esp32-ard.yaml diff --git a/tests/components/tof10120/test.esp32-c3.yaml b/tests/components/tof10120/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tof10120/test.esp32-c3.yaml rename to tests/components/tof10120/test.esp32-c3-ard.yaml diff --git a/tests/components/tof10120/test.esp8266.yaml b/tests/components/tof10120/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tof10120/test.esp8266.yaml rename to tests/components/tof10120/test.esp8266-ard.yaml diff --git a/tests/components/tof10120/test.rp2040.yaml b/tests/components/tof10120/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tof10120/test.rp2040.yaml rename to tests/components/tof10120/test.rp2040-ard.yaml diff --git a/tests/components/toshiba/test.esp32-c3.yaml b/tests/components/toshiba/test.esp32-ard.yaml similarity index 100% rename from tests/components/toshiba/test.esp32-c3.yaml rename to tests/components/toshiba/test.esp32-ard.yaml diff --git a/tests/components/toshiba/test.esp32.yaml b/tests/components/toshiba/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/toshiba/test.esp32.yaml rename to tests/components/toshiba/test.esp32-c3-ard.yaml diff --git a/tests/components/toshiba/test.esp8266.yaml b/tests/components/toshiba/test.esp8266-ard.yaml similarity index 100% rename from tests/components/toshiba/test.esp8266.yaml rename to tests/components/toshiba/test.esp8266-ard.yaml diff --git a/tests/components/total_daily_energy/test.esp32.yaml b/tests/components/total_daily_energy/test.esp32-ard.yaml similarity index 100% rename from tests/components/total_daily_energy/test.esp32.yaml rename to tests/components/total_daily_energy/test.esp32-ard.yaml diff --git a/tests/components/total_daily_energy/test.esp32-c3.yaml b/tests/components/total_daily_energy/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/total_daily_energy/test.esp32-c3.yaml rename to tests/components/total_daily_energy/test.esp32-c3-ard.yaml diff --git a/tests/components/total_daily_energy/test.esp8266.yaml b/tests/components/total_daily_energy/test.esp8266-ard.yaml similarity index 100% rename from tests/components/total_daily_energy/test.esp8266.yaml rename to tests/components/total_daily_energy/test.esp8266-ard.yaml diff --git a/tests/components/total_daily_energy/test.rp2040.yaml b/tests/components/total_daily_energy/test.rp2040-ard.yaml similarity index 100% rename from tests/components/total_daily_energy/test.rp2040.yaml rename to tests/components/total_daily_energy/test.rp2040-ard.yaml diff --git a/tests/components/tsl2561/test.esp32.yaml b/tests/components/tsl2561/test.esp32-ard.yaml similarity index 100% rename from tests/components/tsl2561/test.esp32.yaml rename to tests/components/tsl2561/test.esp32-ard.yaml diff --git a/tests/components/tsl2561/test.esp32-c3.yaml b/tests/components/tsl2561/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tsl2561/test.esp32-c3.yaml rename to tests/components/tsl2561/test.esp32-c3-ard.yaml diff --git a/tests/components/tsl2561/test.esp8266.yaml b/tests/components/tsl2561/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tsl2561/test.esp8266.yaml rename to tests/components/tsl2561/test.esp8266-ard.yaml diff --git a/tests/components/tsl2561/test.rp2040.yaml b/tests/components/tsl2561/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tsl2561/test.rp2040.yaml rename to tests/components/tsl2561/test.rp2040-ard.yaml diff --git a/tests/components/tsl2591/test.esp32.yaml b/tests/components/tsl2591/test.esp32-ard.yaml similarity index 100% rename from tests/components/tsl2591/test.esp32.yaml rename to tests/components/tsl2591/test.esp32-ard.yaml diff --git a/tests/components/tsl2591/test.esp32-c3.yaml b/tests/components/tsl2591/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tsl2591/test.esp32-c3.yaml rename to tests/components/tsl2591/test.esp32-c3-ard.yaml diff --git a/tests/components/tsl2591/test.esp8266.yaml b/tests/components/tsl2591/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tsl2591/test.esp8266.yaml rename to tests/components/tsl2591/test.esp8266-ard.yaml diff --git a/tests/components/tsl2591/test.rp2040.yaml b/tests/components/tsl2591/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tsl2591/test.rp2040.yaml rename to tests/components/tsl2591/test.rp2040-ard.yaml diff --git a/tests/components/tt21100/test.esp32.yaml b/tests/components/tt21100/test.esp32-ard.yaml similarity index 100% rename from tests/components/tt21100/test.esp32.yaml rename to tests/components/tt21100/test.esp32-ard.yaml diff --git a/tests/components/tt21100/test.esp32-c3.yaml b/tests/components/tt21100/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tt21100/test.esp32-c3.yaml rename to tests/components/tt21100/test.esp32-c3-ard.yaml diff --git a/tests/components/tt21100/test.esp32-s2.yaml b/tests/components/tt21100/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/tt21100/test.esp32-s2.yaml rename to tests/components/tt21100/test.esp32-s2-ard.yaml diff --git a/tests/components/tt21100/test.esp8266.yaml b/tests/components/tt21100/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tt21100/test.esp8266.yaml rename to tests/components/tt21100/test.esp8266-ard.yaml diff --git a/tests/components/tt21100/test.rp2040.yaml b/tests/components/tt21100/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tt21100/test.rp2040.yaml rename to tests/components/tt21100/test.rp2040-ard.yaml diff --git a/tests/components/ttp229_bsf/test.esp32.yaml b/tests/components/ttp229_bsf/test.esp32-ard.yaml similarity index 100% rename from tests/components/ttp229_bsf/test.esp32.yaml rename to tests/components/ttp229_bsf/test.esp32-ard.yaml diff --git a/tests/components/ttp229_bsf/test.esp32-c3.yaml b/tests/components/ttp229_bsf/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ttp229_bsf/test.esp32-c3.yaml rename to tests/components/ttp229_bsf/test.esp32-c3-ard.yaml diff --git a/tests/components/ttp229_bsf/test.esp8266.yaml b/tests/components/ttp229_bsf/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ttp229_bsf/test.esp8266.yaml rename to tests/components/ttp229_bsf/test.esp8266-ard.yaml diff --git a/tests/components/ttp229_bsf/test.rp2040.yaml b/tests/components/ttp229_bsf/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ttp229_bsf/test.rp2040.yaml rename to tests/components/ttp229_bsf/test.rp2040-ard.yaml diff --git a/tests/components/ttp229_lsf/test.esp32.yaml b/tests/components/ttp229_lsf/test.esp32-ard.yaml similarity index 100% rename from tests/components/ttp229_lsf/test.esp32.yaml rename to tests/components/ttp229_lsf/test.esp32-ard.yaml diff --git a/tests/components/ttp229_lsf/test.esp32-c3.yaml b/tests/components/ttp229_lsf/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ttp229_lsf/test.esp32-c3.yaml rename to tests/components/ttp229_lsf/test.esp32-c3-ard.yaml diff --git a/tests/components/ttp229_lsf/test.esp8266.yaml b/tests/components/ttp229_lsf/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ttp229_lsf/test.esp8266.yaml rename to tests/components/ttp229_lsf/test.esp8266-ard.yaml diff --git a/tests/components/ttp229_lsf/test.rp2040.yaml b/tests/components/ttp229_lsf/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ttp229_lsf/test.rp2040.yaml rename to tests/components/ttp229_lsf/test.rp2040-ard.yaml diff --git a/tests/components/tuya/test.esp32.yaml b/tests/components/tuya/test.esp32-ard.yaml similarity index 100% rename from tests/components/tuya/test.esp32.yaml rename to tests/components/tuya/test.esp32-ard.yaml diff --git a/tests/components/tuya/test.esp32-c3.yaml b/tests/components/tuya/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tuya/test.esp32-c3.yaml rename to tests/components/tuya/test.esp32-c3-ard.yaml diff --git a/tests/components/tuya/test.esp8266.yaml b/tests/components/tuya/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tuya/test.esp8266.yaml rename to tests/components/tuya/test.esp8266-ard.yaml diff --git a/tests/components/tuya/test.rp2040.yaml b/tests/components/tuya/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tuya/test.rp2040.yaml rename to tests/components/tuya/test.rp2040-ard.yaml diff --git a/tests/components/tx20/test.esp32-c3.yaml b/tests/components/tx20/test.esp32-ard.yaml similarity index 100% rename from tests/components/tx20/test.esp32-c3.yaml rename to tests/components/tx20/test.esp32-ard.yaml diff --git a/tests/components/tx20/test.esp32.yaml b/tests/components/tx20/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/tx20/test.esp32.yaml rename to tests/components/tx20/test.esp32-c3-ard.yaml diff --git a/tests/components/tx20/test.esp8266.yaml b/tests/components/tx20/test.esp8266-ard.yaml similarity index 100% rename from tests/components/tx20/test.esp8266.yaml rename to tests/components/tx20/test.esp8266-ard.yaml diff --git a/tests/components/tx20/test.rp2040.yaml b/tests/components/tx20/test.rp2040-ard.yaml similarity index 100% rename from tests/components/tx20/test.rp2040.yaml rename to tests/components/tx20/test.rp2040-ard.yaml diff --git a/tests/components/uart/test.esp32.yaml b/tests/components/uart/test.esp32-ard.yaml similarity index 100% rename from tests/components/uart/test.esp32.yaml rename to tests/components/uart/test.esp32-ard.yaml diff --git a/tests/components/uart/test.esp32-c3.yaml b/tests/components/uart/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/uart/test.esp32-c3.yaml rename to tests/components/uart/test.esp32-c3-ard.yaml diff --git a/tests/components/uart/test.esp8266.yaml b/tests/components/uart/test.esp8266-ard.yaml similarity index 100% rename from tests/components/uart/test.esp8266.yaml rename to tests/components/uart/test.esp8266-ard.yaml diff --git a/tests/components/uart/test.rp2040.yaml b/tests/components/uart/test.rp2040-ard.yaml similarity index 100% rename from tests/components/uart/test.rp2040.yaml rename to tests/components/uart/test.rp2040-ard.yaml diff --git a/tests/components/ufire_ec/test.esp32.yaml b/tests/components/ufire_ec/test.esp32-ard.yaml similarity index 100% rename from tests/components/ufire_ec/test.esp32.yaml rename to tests/components/ufire_ec/test.esp32-ard.yaml diff --git a/tests/components/ufire_ec/test.esp32-c3.yaml b/tests/components/ufire_ec/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ufire_ec/test.esp32-c3.yaml rename to tests/components/ufire_ec/test.esp32-c3-ard.yaml diff --git a/tests/components/ufire_ec/test.esp8266.yaml b/tests/components/ufire_ec/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ufire_ec/test.esp8266.yaml rename to tests/components/ufire_ec/test.esp8266-ard.yaml diff --git a/tests/components/ufire_ec/test.rp2040.yaml b/tests/components/ufire_ec/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ufire_ec/test.rp2040.yaml rename to tests/components/ufire_ec/test.rp2040-ard.yaml diff --git a/tests/components/ufire_ise/test.esp32.yaml b/tests/components/ufire_ise/test.esp32-ard.yaml similarity index 100% rename from tests/components/ufire_ise/test.esp32.yaml rename to tests/components/ufire_ise/test.esp32-ard.yaml diff --git a/tests/components/ufire_ise/test.esp32-c3.yaml b/tests/components/ufire_ise/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ufire_ise/test.esp32-c3.yaml rename to tests/components/ufire_ise/test.esp32-c3-ard.yaml diff --git a/tests/components/ufire_ise/test.esp8266.yaml b/tests/components/ufire_ise/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ufire_ise/test.esp8266.yaml rename to tests/components/ufire_ise/test.esp8266-ard.yaml diff --git a/tests/components/ufire_ise/test.rp2040.yaml b/tests/components/ufire_ise/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ufire_ise/test.rp2040.yaml rename to tests/components/ufire_ise/test.rp2040-ard.yaml diff --git a/tests/components/uln2003/test.esp32.yaml b/tests/components/uln2003/test.esp32-ard.yaml similarity index 100% rename from tests/components/uln2003/test.esp32.yaml rename to tests/components/uln2003/test.esp32-ard.yaml diff --git a/tests/components/uln2003/test.esp32-c3.yaml b/tests/components/uln2003/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/uln2003/test.esp32-c3.yaml rename to tests/components/uln2003/test.esp32-c3-ard.yaml diff --git a/tests/components/uln2003/test.esp8266.yaml b/tests/components/uln2003/test.esp8266-ard.yaml similarity index 100% rename from tests/components/uln2003/test.esp8266.yaml rename to tests/components/uln2003/test.esp8266-ard.yaml diff --git a/tests/components/uln2003/test.rp2040.yaml b/tests/components/uln2003/test.rp2040-ard.yaml similarity index 100% rename from tests/components/uln2003/test.rp2040.yaml rename to tests/components/uln2003/test.rp2040-ard.yaml diff --git a/tests/components/ultrasonic/test.esp32-c3.yaml b/tests/components/ultrasonic/test.esp32-ard.yaml similarity index 100% rename from tests/components/ultrasonic/test.esp32-c3.yaml rename to tests/components/ultrasonic/test.esp32-ard.yaml diff --git a/tests/components/ultrasonic/test.esp32.yaml b/tests/components/ultrasonic/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/ultrasonic/test.esp32.yaml rename to tests/components/ultrasonic/test.esp32-c3-ard.yaml diff --git a/tests/components/ultrasonic/test.esp8266.yaml b/tests/components/ultrasonic/test.esp8266-ard.yaml similarity index 100% rename from tests/components/ultrasonic/test.esp8266.yaml rename to tests/components/ultrasonic/test.esp8266-ard.yaml diff --git a/tests/components/ultrasonic/test.rp2040.yaml b/tests/components/ultrasonic/test.rp2040-ard.yaml similarity index 100% rename from tests/components/ultrasonic/test.rp2040.yaml rename to tests/components/ultrasonic/test.rp2040-ard.yaml diff --git a/tests/components/update/test.esp8266.yaml b/tests/components/update/test.esp8266-ard.yaml similarity index 100% rename from tests/components/update/test.esp8266.yaml rename to tests/components/update/test.esp8266-ard.yaml diff --git a/tests/components/update/test.rp2040.yaml b/tests/components/update/test.rp2040-ard.yaml similarity index 100% rename from tests/components/update/test.rp2040.yaml rename to tests/components/update/test.rp2040-ard.yaml diff --git a/tests/components/uponor_smatrix/test.esp32.yaml b/tests/components/uponor_smatrix/test.esp32-ard.yaml similarity index 100% rename from tests/components/uponor_smatrix/test.esp32.yaml rename to tests/components/uponor_smatrix/test.esp32-ard.yaml diff --git a/tests/components/uponor_smatrix/test.esp32-c3.yaml b/tests/components/uponor_smatrix/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/uponor_smatrix/test.esp32-c3.yaml rename to tests/components/uponor_smatrix/test.esp32-c3-ard.yaml diff --git a/tests/components/uponor_smatrix/test.esp8266.yaml b/tests/components/uponor_smatrix/test.esp8266-ard.yaml similarity index 100% rename from tests/components/uponor_smatrix/test.esp8266.yaml rename to tests/components/uponor_smatrix/test.esp8266-ard.yaml diff --git a/tests/components/uponor_smatrix/test.rp2040.yaml b/tests/components/uponor_smatrix/test.rp2040-ard.yaml similarity index 100% rename from tests/components/uponor_smatrix/test.rp2040.yaml rename to tests/components/uponor_smatrix/test.rp2040-ard.yaml diff --git a/tests/components/uptime/test.esp32-c3.yaml b/tests/components/uptime/test.esp32-ard.yaml similarity index 100% rename from tests/components/uptime/test.esp32-c3.yaml rename to tests/components/uptime/test.esp32-ard.yaml diff --git a/tests/components/uptime/test.esp32.yaml b/tests/components/uptime/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/uptime/test.esp32.yaml rename to tests/components/uptime/test.esp32-c3-ard.yaml diff --git a/tests/components/uptime/test.esp8266.yaml b/tests/components/uptime/test.esp8266-ard.yaml similarity index 100% rename from tests/components/uptime/test.esp8266.yaml rename to tests/components/uptime/test.esp8266-ard.yaml diff --git a/tests/components/uptime/test.rp2040.yaml b/tests/components/uptime/test.rp2040-ard.yaml similarity index 100% rename from tests/components/uptime/test.rp2040.yaml rename to tests/components/uptime/test.rp2040-ard.yaml diff --git a/tests/components/vbus/test.esp32.yaml b/tests/components/vbus/test.esp32-ard.yaml similarity index 100% rename from tests/components/vbus/test.esp32.yaml rename to tests/components/vbus/test.esp32-ard.yaml diff --git a/tests/components/vbus/test.esp32-c3.yaml b/tests/components/vbus/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/vbus/test.esp32-c3.yaml rename to tests/components/vbus/test.esp32-c3-ard.yaml diff --git a/tests/components/vbus/test.esp8266.yaml b/tests/components/vbus/test.esp8266-ard.yaml similarity index 100% rename from tests/components/vbus/test.esp8266.yaml rename to tests/components/vbus/test.esp8266-ard.yaml diff --git a/tests/components/vbus/test.rp2040.yaml b/tests/components/vbus/test.rp2040-ard.yaml similarity index 100% rename from tests/components/vbus/test.rp2040.yaml rename to tests/components/vbus/test.rp2040-ard.yaml diff --git a/tests/components/veml3235/test.esp32.yaml b/tests/components/veml3235/test.esp32-ard.yaml similarity index 100% rename from tests/components/veml3235/test.esp32.yaml rename to tests/components/veml3235/test.esp32-ard.yaml diff --git a/tests/components/veml3235/test.esp32-c3.yaml b/tests/components/veml3235/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/veml3235/test.esp32-c3.yaml rename to tests/components/veml3235/test.esp32-c3-ard.yaml diff --git a/tests/components/veml3235/test.esp8266.yaml b/tests/components/veml3235/test.esp8266-ard.yaml similarity index 100% rename from tests/components/veml3235/test.esp8266.yaml rename to tests/components/veml3235/test.esp8266-ard.yaml diff --git a/tests/components/veml3235/test.rp2040.yaml b/tests/components/veml3235/test.rp2040-ard.yaml similarity index 100% rename from tests/components/veml3235/test.rp2040.yaml rename to tests/components/veml3235/test.rp2040-ard.yaml diff --git a/tests/components/veml7700/test.esp32.yaml b/tests/components/veml7700/test.esp32-ard.yaml similarity index 100% rename from tests/components/veml7700/test.esp32.yaml rename to tests/components/veml7700/test.esp32-ard.yaml diff --git a/tests/components/veml7700/test.esp32-c3.yaml b/tests/components/veml7700/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/veml7700/test.esp32-c3.yaml rename to tests/components/veml7700/test.esp32-c3-ard.yaml diff --git a/tests/components/veml7700/test.esp8266.yaml b/tests/components/veml7700/test.esp8266-ard.yaml similarity index 100% rename from tests/components/veml7700/test.esp8266.yaml rename to tests/components/veml7700/test.esp8266-ard.yaml diff --git a/tests/components/veml7700/test.rp2040.yaml b/tests/components/veml7700/test.rp2040-ard.yaml similarity index 100% rename from tests/components/veml7700/test.rp2040.yaml rename to tests/components/veml7700/test.rp2040-ard.yaml diff --git a/tests/components/version/test.esp32-c3.yaml b/tests/components/version/test.esp32-ard.yaml similarity index 100% rename from tests/components/version/test.esp32-c3.yaml rename to tests/components/version/test.esp32-ard.yaml diff --git a/tests/components/version/test.esp32.yaml b/tests/components/version/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/version/test.esp32.yaml rename to tests/components/version/test.esp32-c3-ard.yaml diff --git a/tests/components/version/test.esp8266.yaml b/tests/components/version/test.esp8266-ard.yaml similarity index 100% rename from tests/components/version/test.esp8266.yaml rename to tests/components/version/test.esp8266-ard.yaml diff --git a/tests/components/version/test.rp2040.yaml b/tests/components/version/test.rp2040-ard.yaml similarity index 100% rename from tests/components/version/test.rp2040.yaml rename to tests/components/version/test.rp2040-ard.yaml diff --git a/tests/components/vl53l0x/test.esp32.yaml b/tests/components/vl53l0x/test.esp32-ard.yaml similarity index 100% rename from tests/components/vl53l0x/test.esp32.yaml rename to tests/components/vl53l0x/test.esp32-ard.yaml diff --git a/tests/components/vl53l0x/test.esp32-c3.yaml b/tests/components/vl53l0x/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/vl53l0x/test.esp32-c3.yaml rename to tests/components/vl53l0x/test.esp32-c3-ard.yaml diff --git a/tests/components/vl53l0x/test.esp8266.yaml b/tests/components/vl53l0x/test.esp8266-ard.yaml similarity index 100% rename from tests/components/vl53l0x/test.esp8266.yaml rename to tests/components/vl53l0x/test.esp8266-ard.yaml diff --git a/tests/components/vl53l0x/test.rp2040.yaml b/tests/components/vl53l0x/test.rp2040-ard.yaml similarity index 100% rename from tests/components/vl53l0x/test.rp2040.yaml rename to tests/components/vl53l0x/test.rp2040-ard.yaml diff --git a/tests/components/voice_assistant/test.esp32.yaml b/tests/components/voice_assistant/test.esp32-ard.yaml similarity index 100% rename from tests/components/voice_assistant/test.esp32.yaml rename to tests/components/voice_assistant/test.esp32-ard.yaml diff --git a/tests/components/voice_assistant/test.esp32-c3.yaml b/tests/components/voice_assistant/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/voice_assistant/test.esp32-c3.yaml rename to tests/components/voice_assistant/test.esp32-c3-ard.yaml diff --git a/tests/components/wake_on_lan/test.esp32-c3.yaml b/tests/components/wake_on_lan/test.esp32-ard.yaml similarity index 100% rename from tests/components/wake_on_lan/test.esp32-c3.yaml rename to tests/components/wake_on_lan/test.esp32-ard.yaml diff --git a/tests/components/wake_on_lan/test.esp32.yaml b/tests/components/wake_on_lan/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wake_on_lan/test.esp32.yaml rename to tests/components/wake_on_lan/test.esp32-c3-ard.yaml diff --git a/tests/components/wake_on_lan/test.esp8266.yaml b/tests/components/wake_on_lan/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wake_on_lan/test.esp8266.yaml rename to tests/components/wake_on_lan/test.esp8266-ard.yaml diff --git a/tests/components/wake_on_lan/test.rp2040.yaml b/tests/components/wake_on_lan/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wake_on_lan/test.rp2040.yaml rename to tests/components/wake_on_lan/test.rp2040-ard.yaml diff --git a/tests/components/waveshare_epaper/test.esp32.yaml b/tests/components/waveshare_epaper/test.esp32-ard.yaml similarity index 100% rename from tests/components/waveshare_epaper/test.esp32.yaml rename to tests/components/waveshare_epaper/test.esp32-ard.yaml diff --git a/tests/components/waveshare_epaper/test.esp32-c3.yaml b/tests/components/waveshare_epaper/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/waveshare_epaper/test.esp32-c3.yaml rename to tests/components/waveshare_epaper/test.esp32-c3-ard.yaml diff --git a/tests/components/waveshare_epaper/test.esp8266.yaml b/tests/components/waveshare_epaper/test.esp8266-ard.yaml similarity index 100% rename from tests/components/waveshare_epaper/test.esp8266.yaml rename to tests/components/waveshare_epaper/test.esp8266-ard.yaml diff --git a/tests/components/waveshare_epaper/test.rp2040.yaml b/tests/components/waveshare_epaper/test.rp2040-ard.yaml similarity index 100% rename from tests/components/waveshare_epaper/test.rp2040.yaml rename to tests/components/waveshare_epaper/test.rp2040-ard.yaml diff --git a/tests/components/web_server/test.esp32-c3.yaml b/tests/components/web_server/test.esp32-ard.yaml similarity index 100% rename from tests/components/web_server/test.esp32-c3.yaml rename to tests/components/web_server/test.esp32-ard.yaml diff --git a/tests/components/web_server/test.esp32.yaml b/tests/components/web_server/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/web_server/test.esp32.yaml rename to tests/components/web_server/test.esp32-c3-ard.yaml diff --git a/tests/components/web_server/test.esp8266.yaml b/tests/components/web_server/test.esp8266-ard.yaml similarity index 100% rename from tests/components/web_server/test.esp8266.yaml rename to tests/components/web_server/test.esp8266-ard.yaml diff --git a/tests/components/whirlpool/test.esp32-c3.yaml b/tests/components/whirlpool/test.esp32-ard.yaml similarity index 100% rename from tests/components/whirlpool/test.esp32-c3.yaml rename to tests/components/whirlpool/test.esp32-ard.yaml diff --git a/tests/components/whirlpool/test.esp32.yaml b/tests/components/whirlpool/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/whirlpool/test.esp32.yaml rename to tests/components/whirlpool/test.esp32-c3-ard.yaml diff --git a/tests/components/whirlpool/test.esp8266.yaml b/tests/components/whirlpool/test.esp8266-ard.yaml similarity index 100% rename from tests/components/whirlpool/test.esp8266.yaml rename to tests/components/whirlpool/test.esp8266-ard.yaml diff --git a/tests/components/whynter/test.esp32-c3.yaml b/tests/components/whynter/test.esp32-ard.yaml similarity index 100% rename from tests/components/whynter/test.esp32-c3.yaml rename to tests/components/whynter/test.esp32-ard.yaml diff --git a/tests/components/whynter/test.esp32.yaml b/tests/components/whynter/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/whynter/test.esp32.yaml rename to tests/components/whynter/test.esp32-c3-ard.yaml diff --git a/tests/components/whynter/test.esp8266.yaml b/tests/components/whynter/test.esp8266-ard.yaml similarity index 100% rename from tests/components/whynter/test.esp8266.yaml rename to tests/components/whynter/test.esp8266-ard.yaml diff --git a/tests/components/wiegand/test.esp32-c3.yaml b/tests/components/wiegand/test.esp32-ard.yaml similarity index 100% rename from tests/components/wiegand/test.esp32-c3.yaml rename to tests/components/wiegand/test.esp32-ard.yaml diff --git a/tests/components/wiegand/test.esp32.yaml b/tests/components/wiegand/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wiegand/test.esp32.yaml rename to tests/components/wiegand/test.esp32-c3-ard.yaml diff --git a/tests/components/wiegand/test.esp8266.yaml b/tests/components/wiegand/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wiegand/test.esp8266.yaml rename to tests/components/wiegand/test.esp8266-ard.yaml diff --git a/tests/components/wiegand/test.rp2040.yaml b/tests/components/wiegand/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wiegand/test.rp2040.yaml rename to tests/components/wiegand/test.rp2040-ard.yaml diff --git a/tests/components/wifi/test.esp32-c3.yaml b/tests/components/wifi/test.esp32-ard.yaml similarity index 100% rename from tests/components/wifi/test.esp32-c3.yaml rename to tests/components/wifi/test.esp32-ard.yaml diff --git a/tests/components/wifi/test.esp32.yaml b/tests/components/wifi/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wifi/test.esp32.yaml rename to tests/components/wifi/test.esp32-c3-ard.yaml diff --git a/tests/components/wifi/test.esp8266.yaml b/tests/components/wifi/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wifi/test.esp8266.yaml rename to tests/components/wifi/test.esp8266-ard.yaml diff --git a/tests/components/wifi/test.rp2040.yaml b/tests/components/wifi/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wifi/test.rp2040.yaml rename to tests/components/wifi/test.rp2040-ard.yaml diff --git a/tests/components/wifi_info/test.esp32-c3.yaml b/tests/components/wifi_info/test.esp32-ard.yaml similarity index 100% rename from tests/components/wifi_info/test.esp32-c3.yaml rename to tests/components/wifi_info/test.esp32-ard.yaml diff --git a/tests/components/wifi_info/test.esp32.yaml b/tests/components/wifi_info/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wifi_info/test.esp32.yaml rename to tests/components/wifi_info/test.esp32-c3-ard.yaml diff --git a/tests/components/wifi_info/test.esp8266.yaml b/tests/components/wifi_info/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wifi_info/test.esp8266.yaml rename to tests/components/wifi_info/test.esp8266-ard.yaml diff --git a/tests/components/wifi_info/test.rp2040.yaml b/tests/components/wifi_info/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wifi_info/test.rp2040.yaml rename to tests/components/wifi_info/test.rp2040-ard.yaml diff --git a/tests/components/wifi_signal/test.esp32-c3.yaml b/tests/components/wifi_signal/test.esp32-ard.yaml similarity index 100% rename from tests/components/wifi_signal/test.esp32-c3.yaml rename to tests/components/wifi_signal/test.esp32-ard.yaml diff --git a/tests/components/wifi_signal/test.esp32.yaml b/tests/components/wifi_signal/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wifi_signal/test.esp32.yaml rename to tests/components/wifi_signal/test.esp32-c3-ard.yaml diff --git a/tests/components/wifi_signal/test.esp8266.yaml b/tests/components/wifi_signal/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wifi_signal/test.esp8266.yaml rename to tests/components/wifi_signal/test.esp8266-ard.yaml diff --git a/tests/components/wifi_signal/test.rp2040.yaml b/tests/components/wifi_signal/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wifi_signal/test.rp2040.yaml rename to tests/components/wifi_signal/test.rp2040-ard.yaml diff --git a/tests/components/wireguard/test.bk72xx.yaml b/tests/components/wireguard/test.bk72xx-ard.yaml similarity index 100% rename from tests/components/wireguard/test.bk72xx.yaml rename to tests/components/wireguard/test.bk72xx-ard.yaml diff --git a/tests/components/wireguard/test.esp32.yaml b/tests/components/wireguard/test.esp32-ard.yaml similarity index 100% rename from tests/components/wireguard/test.esp32.yaml rename to tests/components/wireguard/test.esp32-ard.yaml diff --git a/tests/components/wireguard/test.esp32-c3.yaml b/tests/components/wireguard/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wireguard/test.esp32-c3.yaml rename to tests/components/wireguard/test.esp32-c3-ard.yaml diff --git a/tests/components/wireguard/test.esp8266.yaml b/tests/components/wireguard/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wireguard/test.esp8266.yaml rename to tests/components/wireguard/test.esp8266-ard.yaml diff --git a/tests/components/wk2132_i2c/test.esp32.yaml b/tests/components/wk2132_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2132_i2c/test.esp32.yaml rename to tests/components/wk2132_i2c/test.esp32-ard.yaml diff --git a/tests/components/wk2132_i2c/test.esp32-s3.yaml b/tests/components/wk2132_i2c/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2132_i2c/test.esp32-s3.yaml rename to tests/components/wk2132_i2c/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2132_spi/test.esp32.yaml b/tests/components/wk2132_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2132_spi/test.esp32.yaml rename to tests/components/wk2132_spi/test.esp32-ard.yaml diff --git a/tests/components/wk2132_spi/test.esp32-s3.yaml b/tests/components/wk2132_spi/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2132_spi/test.esp32-s3.yaml rename to tests/components/wk2132_spi/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2168_i2c/test.esp32.yaml b/tests/components/wk2168_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2168_i2c/test.esp32.yaml rename to tests/components/wk2168_i2c/test.esp32-ard.yaml diff --git a/tests/components/wk2168_i2c/test.esp32-s3.yaml b/tests/components/wk2168_i2c/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2168_i2c/test.esp32-s3.yaml rename to tests/components/wk2168_i2c/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2168_spi/test.esp32.yaml b/tests/components/wk2168_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2168_spi/test.esp32.yaml rename to tests/components/wk2168_spi/test.esp32-ard.yaml diff --git a/tests/components/wk2168_spi/test.esp32-s3.yaml b/tests/components/wk2168_spi/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2168_spi/test.esp32-s3.yaml rename to tests/components/wk2168_spi/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2204_i2c/test.esp32.yaml b/tests/components/wk2204_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2204_i2c/test.esp32.yaml rename to tests/components/wk2204_i2c/test.esp32-ard.yaml diff --git a/tests/components/wk2204_i2c/test.esp32-s3.yaml b/tests/components/wk2204_i2c/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2204_i2c/test.esp32-s3.yaml rename to tests/components/wk2204_i2c/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2204_spi/test.esp32.yaml b/tests/components/wk2204_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2204_spi/test.esp32.yaml rename to tests/components/wk2204_spi/test.esp32-ard.yaml diff --git a/tests/components/wk2204_spi/test.esp32-s3.yaml b/tests/components/wk2204_spi/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2204_spi/test.esp32-s3.yaml rename to tests/components/wk2204_spi/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2212_i2c/test.esp32.yaml b/tests/components/wk2212_i2c/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2212_i2c/test.esp32.yaml rename to tests/components/wk2212_i2c/test.esp32-ard.yaml diff --git a/tests/components/wk2212_i2c/test.esp32-s3.yaml b/tests/components/wk2212_i2c/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2212_i2c/test.esp32-s3.yaml rename to tests/components/wk2212_i2c/test.esp32-s3-ard.yaml diff --git a/tests/components/wk2212_spi/test.esp32.yaml b/tests/components/wk2212_spi/test.esp32-ard.yaml similarity index 100% rename from tests/components/wk2212_spi/test.esp32.yaml rename to tests/components/wk2212_spi/test.esp32-ard.yaml diff --git a/tests/components/wk2212_spi/test.esp32-s3.yaml b/tests/components/wk2212_spi/test.esp32-s3-ard.yaml similarity index 100% rename from tests/components/wk2212_spi/test.esp32-s3.yaml rename to tests/components/wk2212_spi/test.esp32-s3-ard.yaml diff --git a/tests/components/wl_134/test.esp32.yaml b/tests/components/wl_134/test.esp32-ard.yaml similarity index 100% rename from tests/components/wl_134/test.esp32.yaml rename to tests/components/wl_134/test.esp32-ard.yaml diff --git a/tests/components/wl_134/test.esp32-c3.yaml b/tests/components/wl_134/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wl_134/test.esp32-c3.yaml rename to tests/components/wl_134/test.esp32-c3-ard.yaml diff --git a/tests/components/wl_134/test.esp8266.yaml b/tests/components/wl_134/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wl_134/test.esp8266.yaml rename to tests/components/wl_134/test.esp8266-ard.yaml diff --git a/tests/components/wl_134/test.rp2040.yaml b/tests/components/wl_134/test.rp2040-ard.yaml similarity index 100% rename from tests/components/wl_134/test.rp2040.yaml rename to tests/components/wl_134/test.rp2040-ard.yaml diff --git a/tests/components/wled/test.esp32-c3.yaml b/tests/components/wled/test.esp32-ard.yaml similarity index 100% rename from tests/components/wled/test.esp32-c3.yaml rename to tests/components/wled/test.esp32-ard.yaml diff --git a/tests/components/wled/test.esp32.yaml b/tests/components/wled/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/wled/test.esp32.yaml rename to tests/components/wled/test.esp32-c3-ard.yaml diff --git a/tests/components/wled/test.esp8266.yaml b/tests/components/wled/test.esp8266-ard.yaml similarity index 100% rename from tests/components/wled/test.esp8266.yaml rename to tests/components/wled/test.esp8266-ard.yaml diff --git a/tests/components/x9c/test.esp32.yaml b/tests/components/x9c/test.esp32-ard.yaml similarity index 100% rename from tests/components/x9c/test.esp32.yaml rename to tests/components/x9c/test.esp32-ard.yaml diff --git a/tests/components/x9c/test.esp32-c3.yaml b/tests/components/x9c/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/x9c/test.esp32-c3.yaml rename to tests/components/x9c/test.esp32-c3-ard.yaml diff --git a/tests/components/x9c/test.esp8266.yaml b/tests/components/x9c/test.esp8266-ard.yaml similarity index 100% rename from tests/components/x9c/test.esp8266.yaml rename to tests/components/x9c/test.esp8266-ard.yaml diff --git a/tests/components/x9c/test.rp2040.yaml b/tests/components/x9c/test.rp2040-ard.yaml similarity index 100% rename from tests/components/x9c/test.rp2040.yaml rename to tests/components/x9c/test.rp2040-ard.yaml diff --git a/tests/components/xgzp68xx/test.esp32.yaml b/tests/components/xgzp68xx/test.esp32-ard.yaml similarity index 100% rename from tests/components/xgzp68xx/test.esp32.yaml rename to tests/components/xgzp68xx/test.esp32-ard.yaml diff --git a/tests/components/xgzp68xx/test.esp32-c3.yaml b/tests/components/xgzp68xx/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xgzp68xx/test.esp32-c3.yaml rename to tests/components/xgzp68xx/test.esp32-c3-ard.yaml diff --git a/tests/components/xgzp68xx/test.esp8266.yaml b/tests/components/xgzp68xx/test.esp8266-ard.yaml similarity index 100% rename from tests/components/xgzp68xx/test.esp8266.yaml rename to tests/components/xgzp68xx/test.esp8266-ard.yaml diff --git a/tests/components/xgzp68xx/test.rp2040.yaml b/tests/components/xgzp68xx/test.rp2040-ard.yaml similarity index 100% rename from tests/components/xgzp68xx/test.rp2040.yaml rename to tests/components/xgzp68xx/test.rp2040-ard.yaml diff --git a/tests/components/xiaomi_ble/test.esp32-c3.yaml b/tests/components/xiaomi_ble/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_ble/test.esp32-c3.yaml rename to tests/components/xiaomi_ble/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_ble/test.esp32.yaml b/tests/components/xiaomi_ble/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_ble/test.esp32.yaml rename to tests/components/xiaomi_ble/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_cgd1/test.esp32-c3.yaml b/tests/components/xiaomi_cgd1/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgd1/test.esp32-c3.yaml rename to tests/components/xiaomi_cgd1/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_cgd1/test.esp32.yaml b/tests/components/xiaomi_cgd1/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgd1/test.esp32.yaml rename to tests/components/xiaomi_cgd1/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_cgdk2/test.esp32-c3.yaml b/tests/components/xiaomi_cgdk2/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgdk2/test.esp32-c3.yaml rename to tests/components/xiaomi_cgdk2/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_cgdk2/test.esp32.yaml b/tests/components/xiaomi_cgdk2/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgdk2/test.esp32.yaml rename to tests/components/xiaomi_cgdk2/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_cgg1/test.esp32-c3.yaml b/tests/components/xiaomi_cgg1/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgg1/test.esp32-c3.yaml rename to tests/components/xiaomi_cgg1/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_cgg1/test.esp32.yaml b/tests/components/xiaomi_cgg1/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgg1/test.esp32.yaml rename to tests/components/xiaomi_cgg1/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_cgpr1/test.esp32-c3.yaml b/tests/components/xiaomi_cgpr1/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgpr1/test.esp32-c3.yaml rename to tests/components/xiaomi_cgpr1/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_cgpr1/test.esp32.yaml b/tests/components/xiaomi_cgpr1/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_cgpr1/test.esp32.yaml rename to tests/components/xiaomi_cgpr1/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_gcls002/test.esp32-c3.yaml b/tests/components/xiaomi_gcls002/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_gcls002/test.esp32-c3.yaml rename to tests/components/xiaomi_gcls002/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_gcls002/test.esp32.yaml b/tests/components/xiaomi_gcls002/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_gcls002/test.esp32.yaml rename to tests/components/xiaomi_gcls002/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_hhccjcy01/test.esp32-c3.yaml rename to tests/components/xiaomi_hhccjcy01/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_hhccjcy01/test.esp32.yaml b/tests/components/xiaomi_hhccjcy01/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_hhccjcy01/test.esp32.yaml rename to tests/components/xiaomi_hhccjcy01/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_hhccpot002/test.esp32-c3.yaml rename to tests/components/xiaomi_hhccpot002/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_hhccpot002/test.esp32.yaml b/tests/components/xiaomi_hhccpot002/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_hhccpot002/test.esp32.yaml rename to tests/components/xiaomi_hhccpot002/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_jqjcy01ym/test.esp32-c3.yaml rename to tests/components/xiaomi_jqjcy01ym/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_jqjcy01ym/test.esp32.yaml b/tests/components/xiaomi_jqjcy01ym/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_jqjcy01ym/test.esp32.yaml rename to tests/components/xiaomi_jqjcy01ym/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_lywsd02/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd02/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsd02/test.esp32-c3.yaml rename to tests/components/xiaomi_lywsd02/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_lywsd02/test.esp32.yaml b/tests/components/xiaomi_lywsd02/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsd02/test.esp32.yaml rename to tests/components/xiaomi_lywsd02/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsd03mmc/test.esp32-c3.yaml rename to tests/components/xiaomi_lywsd03mmc/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_lywsd03mmc/test.esp32.yaml b/tests/components/xiaomi_lywsd03mmc/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsd03mmc/test.esp32.yaml rename to tests/components/xiaomi_lywsd03mmc/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsdcgq/test.esp32-c3.yaml rename to tests/components/xiaomi_lywsdcgq/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_lywsdcgq/test.esp32.yaml b/tests/components/xiaomi_lywsdcgq/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_lywsdcgq/test.esp32.yaml rename to tests/components/xiaomi_lywsdcgq/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_mhoc303/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc303/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_mhoc303/test.esp32-c3.yaml rename to tests/components/xiaomi_mhoc303/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_mhoc303/test.esp32.yaml b/tests/components/xiaomi_mhoc303/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_mhoc303/test.esp32.yaml rename to tests/components/xiaomi_mhoc303/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_mhoc401/test.esp32-c3.yaml b/tests/components/xiaomi_mhoc401/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_mhoc401/test.esp32-c3.yaml rename to tests/components/xiaomi_mhoc401/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_mhoc401/test.esp32.yaml b/tests/components/xiaomi_mhoc401/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_mhoc401/test.esp32.yaml rename to tests/components/xiaomi_mhoc401/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_miscale copy/test.esp32-c3.yaml b/tests/components/xiaomi_miscale copy/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_miscale copy/test.esp32-c3.yaml rename to tests/components/xiaomi_miscale copy/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_miscale copy/test.esp32.yaml b/tests/components/xiaomi_miscale copy/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_miscale copy/test.esp32.yaml rename to tests/components/xiaomi_miscale copy/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_miscale/test.esp32-c3.yaml b/tests/components/xiaomi_miscale/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_miscale/test.esp32-c3.yaml rename to tests/components/xiaomi_miscale/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_miscale/test.esp32.yaml b/tests/components/xiaomi_miscale/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_miscale/test.esp32.yaml rename to tests/components/xiaomi_miscale/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_mjyd02yla/test.esp32-c3.yaml rename to tests/components/xiaomi_mjyd02yla/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_mjyd02yla/test.esp32.yaml b/tests/components/xiaomi_mjyd02yla/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_mjyd02yla/test.esp32.yaml rename to tests/components/xiaomi_mjyd02yla/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_mue4094rt/test.esp32-c3.yaml rename to tests/components/xiaomi_mue4094rt/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_mue4094rt/test.esp32.yaml b/tests/components/xiaomi_mue4094rt/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_mue4094rt/test.esp32.yaml rename to tests/components/xiaomi_mue4094rt/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_rtcgq02lm/test.esp32-c3.yaml rename to tests/components/xiaomi_rtcgq02lm/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_rtcgq02lm/test.esp32.yaml b/tests/components/xiaomi_rtcgq02lm/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_rtcgq02lm/test.esp32.yaml rename to tests/components/xiaomi_rtcgq02lm/test.esp32-c3-ard.yaml diff --git a/tests/components/xiaomi_wx08zm/test.esp32-c3.yaml b/tests/components/xiaomi_wx08zm/test.esp32-ard.yaml similarity index 100% rename from tests/components/xiaomi_wx08zm/test.esp32-c3.yaml rename to tests/components/xiaomi_wx08zm/test.esp32-ard.yaml diff --git a/tests/components/xiaomi_wx08zm/test.esp32.yaml b/tests/components/xiaomi_wx08zm/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xiaomi_wx08zm/test.esp32.yaml rename to tests/components/xiaomi_wx08zm/test.esp32-c3-ard.yaml diff --git a/tests/components/xl9535/test.esp32.yaml b/tests/components/xl9535/test.esp32-ard.yaml similarity index 100% rename from tests/components/xl9535/test.esp32.yaml rename to tests/components/xl9535/test.esp32-ard.yaml diff --git a/tests/components/xl9535/test.esp32-c3.yaml b/tests/components/xl9535/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xl9535/test.esp32-c3.yaml rename to tests/components/xl9535/test.esp32-c3-ard.yaml diff --git a/tests/components/xl9535/test.esp8266.yaml b/tests/components/xl9535/test.esp8266-ard.yaml similarity index 100% rename from tests/components/xl9535/test.esp8266.yaml rename to tests/components/xl9535/test.esp8266-ard.yaml diff --git a/tests/components/xl9535/test.rp2040.yaml b/tests/components/xl9535/test.rp2040-ard.yaml similarity index 100% rename from tests/components/xl9535/test.rp2040.yaml rename to tests/components/xl9535/test.rp2040-ard.yaml diff --git a/tests/components/xpt2046/test.esp32.yaml b/tests/components/xpt2046/test.esp32-ard.yaml similarity index 100% rename from tests/components/xpt2046/test.esp32.yaml rename to tests/components/xpt2046/test.esp32-ard.yaml diff --git a/tests/components/xpt2046/test.esp32-c3.yaml b/tests/components/xpt2046/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/xpt2046/test.esp32-c3.yaml rename to tests/components/xpt2046/test.esp32-c3-ard.yaml diff --git a/tests/components/xpt2046/test.esp32-s2.yaml b/tests/components/xpt2046/test.esp32-s2-ard.yaml similarity index 100% rename from tests/components/xpt2046/test.esp32-s2.yaml rename to tests/components/xpt2046/test.esp32-s2-ard.yaml diff --git a/tests/components/xpt2046/test.esp8266.yaml b/tests/components/xpt2046/test.esp8266-ard.yaml similarity index 100% rename from tests/components/xpt2046/test.esp8266.yaml rename to tests/components/xpt2046/test.esp8266-ard.yaml diff --git a/tests/components/xpt2046/test.rp2040.yaml b/tests/components/xpt2046/test.rp2040-ard.yaml similarity index 100% rename from tests/components/xpt2046/test.rp2040.yaml rename to tests/components/xpt2046/test.rp2040-ard.yaml diff --git a/tests/components/yashima/test.esp32-c3.yaml b/tests/components/yashima/test.esp32-ard.yaml similarity index 100% rename from tests/components/yashima/test.esp32-c3.yaml rename to tests/components/yashima/test.esp32-ard.yaml diff --git a/tests/components/yashima/test.esp32.yaml b/tests/components/yashima/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/yashima/test.esp32.yaml rename to tests/components/yashima/test.esp32-c3-ard.yaml diff --git a/tests/components/yashima/test.esp8266.yaml b/tests/components/yashima/test.esp8266-ard.yaml similarity index 100% rename from tests/components/yashima/test.esp8266.yaml rename to tests/components/yashima/test.esp8266-ard.yaml diff --git a/tests/components/zhlt01/test.esp32-c3.yaml b/tests/components/zhlt01/test.esp32-ard.yaml similarity index 100% rename from tests/components/zhlt01/test.esp32-c3.yaml rename to tests/components/zhlt01/test.esp32-ard.yaml diff --git a/tests/components/zhlt01/test.esp32.yaml b/tests/components/zhlt01/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/zhlt01/test.esp32.yaml rename to tests/components/zhlt01/test.esp32-c3-ard.yaml diff --git a/tests/components/zhlt01/test.esp8266.yaml b/tests/components/zhlt01/test.esp8266-ard.yaml similarity index 100% rename from tests/components/zhlt01/test.esp8266.yaml rename to tests/components/zhlt01/test.esp8266-ard.yaml diff --git a/tests/components/zio_ultrasonic/test.esp32.yaml b/tests/components/zio_ultrasonic/test.esp32-ard.yaml similarity index 100% rename from tests/components/zio_ultrasonic/test.esp32.yaml rename to tests/components/zio_ultrasonic/test.esp32-ard.yaml diff --git a/tests/components/zio_ultrasonic/test.esp32-c3.yaml b/tests/components/zio_ultrasonic/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/zio_ultrasonic/test.esp32-c3.yaml rename to tests/components/zio_ultrasonic/test.esp32-c3-ard.yaml diff --git a/tests/components/zio_ultrasonic/test.esp8266.yaml b/tests/components/zio_ultrasonic/test.esp8266-ard.yaml similarity index 100% rename from tests/components/zio_ultrasonic/test.esp8266.yaml rename to tests/components/zio_ultrasonic/test.esp8266-ard.yaml diff --git a/tests/components/zio_ultrasonic/test.rp2040.yaml b/tests/components/zio_ultrasonic/test.rp2040-ard.yaml similarity index 100% rename from tests/components/zio_ultrasonic/test.rp2040.yaml rename to tests/components/zio_ultrasonic/test.rp2040-ard.yaml diff --git a/tests/components/zyaura/test.esp32.yaml b/tests/components/zyaura/test.esp32-ard.yaml similarity index 100% rename from tests/components/zyaura/test.esp32.yaml rename to tests/components/zyaura/test.esp32-ard.yaml diff --git a/tests/components/zyaura/test.esp32-c3.yaml b/tests/components/zyaura/test.esp32-c3-ard.yaml similarity index 100% rename from tests/components/zyaura/test.esp32-c3.yaml rename to tests/components/zyaura/test.esp32-c3-ard.yaml diff --git a/tests/components/zyaura/test.esp8266.yaml b/tests/components/zyaura/test.esp8266-ard.yaml similarity index 100% rename from tests/components/zyaura/test.esp8266.yaml rename to tests/components/zyaura/test.esp8266-ard.yaml diff --git a/tests/components/zyaura/test.rp2040.yaml b/tests/components/zyaura/test.rp2040-ard.yaml similarity index 100% rename from tests/components/zyaura/test.rp2040.yaml rename to tests/components/zyaura/test.rp2040-ard.yaml diff --git a/tests/test_build_components/build_components_base.bk72xx.yaml b/tests/test_build_components/build_components_base.bk72xx-ard.yaml similarity index 100% rename from tests/test_build_components/build_components_base.bk72xx.yaml rename to tests/test_build_components/build_components_base.bk72xx-ard.yaml diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml new file mode 100644 index 0000000000..08d4d8679c --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml @@ -0,0 +1,19 @@ +esphome: + name: componenttestesp32c3idf50 + friendly_name: $component_name + +esp32: + board: lolin_c3_mini + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file diff --git a/tests/test_build_components/build_components_base.esp32-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-idf-50.yaml new file mode 100644 index 0000000000..c9f2c1e943 --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-idf-50.yaml @@ -0,0 +1,19 @@ +esphome: + name: componenttestesp32idf50 + friendly_name: $component_name + +esp32: + board: nodemcu-32s + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml new file mode 100644 index 0000000000..351f5fb019 --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml @@ -0,0 +1,20 @@ +esphome: + name: componenttestesp32s2idf50 + friendly_name: $component_name + +esp32: + board: esp32-s2-saola-1 + variant: ESP32S2 + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml index 62f0f4f7bc..484906e8df 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s2ard + name: componenttestesp32s2idf friendly_name: $component_name esp32: diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml new file mode 100644 index 0000000000..c05378903f --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml @@ -0,0 +1,20 @@ +esphome: + name: componenttestesp32s3idf50 + friendly_name: $component_name + +esp32: + board: esp32s3box + variant: ESP32S3 + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml index b1d08fcdf8..ee209000e9 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s3ard + name: componenttestesp32s3idf friendly_name: $component_name esp32: diff --git a/tests/test_build_components/build_components_base.esp8266.yaml b/tests/test_build_components/build_components_base.esp8266-ard.yaml similarity index 87% rename from tests/test_build_components/build_components_base.esp8266.yaml rename to tests/test_build_components/build_components_base.esp8266-ard.yaml index ecf9acd2ba..e4d6607c86 100644 --- a/tests/test_build_components/build_components_base.esp8266.yaml +++ b/tests/test_build_components/build_components_base.esp8266-ard.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp8266 + name: componenttestesp8266ard friendly_name: $component_name esp8266: diff --git a/tests/test_build_components/build_components_base.rp2040.yaml b/tests/test_build_components/build_components_base.rp2040-ard.yaml similarity index 92% rename from tests/test_build_components/build_components_base.rp2040.yaml rename to tests/test_build_components/build_components_base.rp2040-ard.yaml index 335642374b..6c6a27e0a7 100644 --- a/tests/test_build_components/build_components_base.rp2040.yaml +++ b/tests/test_build_components/build_components_base.rp2040-ard.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestrp2040 + name: componenttestrp2040ard friendly_name: $component_name rp2040: From a78b2d0128bd3a3c54fdb092d8180497cd03a8a8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:07:43 +1200 Subject: [PATCH 1913/2607] [wifi] Fix some access point bugs related to esp-idf 4.4.7 (#6928) * Set dhcp server range to only 10 IPs * Change log level to errors to make it clearer * We want to stop the dhcp server, not client --- .../wifi/wifi_component_esp32_arduino.cpp | 12 ++++++------ .../components/wifi/wifi_component_esp8266.cpp | 14 +++++++------- .../components/wifi/wifi_component_esp_idf.cpp | 16 ++++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index ef7a624cd5..fc954a2333 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -694,15 +694,15 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.netmask = network::IPAddress(255, 255, 255, 0); } - err = esp_netif_dhcpc_stop(s_ap_netif); + err = esp_netif_dhcps_stop(s_ap_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "esp_netif_dhcps_stop failed: %s", esp_err_to_name(err)); return false; } err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); + ESP_LOGE(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -712,20 +712,20 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 838250972b..997457e2d2 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -716,12 +716,12 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { if (wifi_softap_dhcps_status() == DHCP_STARTED) { if (!wifi_softap_dhcps_stop()) { - ESP_LOGV(TAG, "Stopping DHCP server failed!"); + ESP_LOGW(TAG, "Stopping DHCP server failed!"); } } if (!wifi_set_ip_info(SOFTAP_IF, &info)) { - ESP_LOGV(TAG, "Setting SoftAP info failed!"); + ESP_LOGE(TAG, "Setting SoftAP info failed!"); return false; } @@ -735,17 +735,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); if (!wifi_softap_set_dhcps_lease(&lease)) { - ESP_LOGV(TAG, "Setting SoftAP DHCP lease failed!"); + ESP_LOGE(TAG, "Setting SoftAP DHCP lease failed!"); return false; } // lease time 1440 minutes (=24 hours) if (!wifi_softap_set_dhcps_lease_time(1440)) { - ESP_LOGV(TAG, "Setting SoftAP DHCP lease time failed!"); + ESP_LOGE(TAG, "Setting SoftAP DHCP lease time failed!"); return false; } @@ -755,13 +755,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { uint8_t mode = 1; // bit0, 1 enables router information from ESP8266 SoftAP DHCP server. if (!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) { - ESP_LOGV(TAG, "wifi_softap_set_dhcps_offer_option failed!"); + ESP_LOGE(TAG, "wifi_softap_set_dhcps_offer_option failed!"); return false; } #endif if (!wifi_softap_dhcps_start()) { - ESP_LOGV(TAG, "Starting SoftAP DHCPS failed!"); + ESP_LOGE(TAG, "Starting SoftAP DHCPS failed!"); return false; } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index bc575e6a2d..c21486fee4 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -823,15 +823,15 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.netmask = network::IPAddress(255, 255, 255, 0); } - err = esp_netif_dhcpc_stop(s_ap_netif); + err = esp_netif_dhcps_stop(s_ap_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "esp_netif_dhcps_stop failed: %s", esp_err_to_name(err)); return false; } err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); + ESP_LOGE(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -841,20 +841,20 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } @@ -887,12 +887,12 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_set_config failed! %d", err); + ESP_LOGE(TAG, "esp_wifi_set_config failed! %d", err); return false; } if (!this->wifi_ap_ip_config_(ap.get_manual_ip())) { - ESP_LOGV(TAG, "wifi_ap_ip_config_ failed!"); + ESP_LOGE(TAG, "wifi_ap_ip_config_ failed!"); return false; } From 4c313bc1982c2eabc3ccfe54b84008323c8fc5ad Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:12:55 +1200 Subject: [PATCH 1914/2607] Rename legacy/modern to ota/factory (#6922) * Rename legacy/modern to ota/factory * Add modern/legacy in brackets --- esphome/components/esp32/__init__.py | 14 +++++------ esphome/components/esp32/post_build.py.script | 13 ++++++++++- .../components/esp8266/post_build.py.script | 10 +++++++- esphome/components/rp2040/__init__.py | 18 +++++++++++++-- .../components/rp2040/post_build.py.script | 23 +++++++++++++++++++ 5 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 esphome/components/rp2040/post_build.py.script diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 8f46567266..1effea708f 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -96,16 +96,16 @@ def get_board(core_obj=None): def get_download_types(storage_json): return [ { - "title": "Modern format", + "title": "Factory format (Previously Modern)", "description": "For use with ESPHome Web and other tools.", - "file": "firmware-factory.bin", - "download": f"{storage_json.name}-factory.bin", + "file": "firmware.factory.bin", + "download": f"{storage_json.name}.factory.bin", }, { - "title": "Legacy format", - "description": "For use with ESPHome Flasher.", - "file": "firmware.bin", - "download": f"{storage_json.name}.bin", + "title": "OTA format (Previously Legacy)", + "description": "For OTA updating a device.", + "file": "firmware.ota.bin", + "download": f"{storage_json.name}.ota.bin", }, ] diff --git a/esphome/components/esp32/post_build.py.script b/esphome/components/esp32/post_build.py.script index c941bdb386..c181cf30b1 100644 --- a/esphome/components/esp32/post_build.py.script +++ b/esphome/components/esp32/post_build.py.script @@ -17,17 +17,19 @@ from SCons.Script import ARGUMENTS # Copy over the default sdkconfig. from os import path + if path.exists("./sdkconfig.defaults"): os.makedirs(".temp", exist_ok=True) shutil.copy("./sdkconfig.defaults", "./.temp/sdkconfig-esp32-idf") + def esp32_create_combined_bin(source, target, env): verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0"))) if verbose: print("Generating combined binary for serial flashing") app_offset = 0x10000 - new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin") sections = env.subst(env.get("FLASH_EXTRA_IMAGES")) firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") chip = env.get("BOARD_MCU") @@ -62,5 +64,14 @@ def esp32_create_combined_bin(source, target, env): else: subprocess.run(["esptool.py", *cmd]) + +def esp32_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") + + shutil.copyfile(firmware_name, new_file_name) + + # pylint: disable=E0602 env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_copy_ota_bin) # noqa diff --git a/esphome/components/esp8266/post_build.py.script b/esphome/components/esp8266/post_build.py.script index 4dab1cbd27..0a854d7599 100644 --- a/esphome/components/esp8266/post_build.py.script +++ b/esphome/components/esp8266/post_build.py.script @@ -6,10 +6,18 @@ Import("env") # noqa def esp8266_copy_factory_bin(source, target, env): firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") - new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin") + + shutil.copyfile(firmware_name, new_file_name) + + +def esp8266_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") shutil.copyfile(firmware_name, new_file_name) # pylint: disable=E0602 env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp8266_copy_factory_bin) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp8266_copy_ota_bin) # noqa diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index ace455add7..f5c3b8bda2 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -47,10 +47,16 @@ def set_core_data(config): def get_download_types(storage_json): return [ { - "title": "UF2 format", + "title": "UF2 factory format", "description": "For copying to RP2040 over USB.", "file": "firmware.uf2", - "download": f"{storage_json.name}.uf2", + "download": f"{storage_json.name}.factory.uf2", + }, + { + "title": "OTA format", + "description": "For OTA updating a device.", + "file": "firmware.ota.bin", + "download": f"{storage_json.name}.ota.bin", }, ] @@ -160,6 +166,8 @@ async def to_code(config): cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "RP2040") + cg.add_platformio_option("extra_scripts", ["post:post_build.py"]) + conf = config[CONF_FRAMEWORK] cg.add_platformio_option("framework", "arduino") cg.add_build_flag("-DUSE_ARDUINO") @@ -225,4 +233,10 @@ def generate_pio_files() -> bool: # Called by writer.py def copy_files() -> bool: + dir = os.path.dirname(__file__) + post_build_file = os.path.join(dir, "post_build.py.script") + copy_file_if_changed( + post_build_file, + CORE.relative_build_path("post_build.py"), + ) return generate_pio_files() diff --git a/esphome/components/rp2040/post_build.py.script b/esphome/components/rp2040/post_build.py.script new file mode 100644 index 0000000000..7dcd7e52a6 --- /dev/null +++ b/esphome/components/rp2040/post_build.py.script @@ -0,0 +1,23 @@ +import shutil + +# pylint: disable=E0602 +Import("env") # noqa + + +def rp2040_copy_factory_uf2(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.uf2") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.uf2") + + shutil.copyfile(firmware_name, new_file_name) + + +def rp2040_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") + + shutil.copyfile(firmware_name, new_file_name) + + +# pylint: disable=E0602 +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", rp2040_copy_factory_uf2) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", rp2040_copy_ota_bin) # noqa From 7d642147c154ad4c825f23c726ac73bcf4210f8a Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Tue, 18 Jun 2024 05:22:50 +0300 Subject: [PATCH 1915/2607] uart: allow setting the UART id in final_validate_device_schema (#6923) --- esphome/components/uart/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index 088227afe5..b036288078 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -258,6 +258,7 @@ KEY_UART_DEVICES = "uart_devices" def final_validate_device_schema( name: str, *, + uart_bus: str = CONF_UART_ID, baud_rate: Optional[int] = None, require_tx: bool = False, require_rx: bool = False, @@ -268,7 +269,7 @@ def final_validate_device_schema( def validate_baud_rate(value): if value != baud_rate: raise cv.Invalid( - f"Component {name} requires baud rate {baud_rate} for the uart bus" + f"Component {name} requires baud rate {baud_rate} for the uart referenced by {uart_bus}" ) return value @@ -287,21 +288,21 @@ def final_validate_device_schema( def validate_data_bits(value): if value != data_bits: raise cv.Invalid( - f"Component {name} requires {data_bits} data bits for the uart bus" + f"Component {name} requires {data_bits} data bits for the uart referenced by {uart_bus}" ) return value def validate_parity(value): if value != parity: raise cv.Invalid( - f"Component {name} requires parity {parity} for the uart bus" + f"Component {name} requires parity {parity} for the uart referenced by {uart_bus}" ) return value def validate_stop_bits(value): if value != stop_bits: raise cv.Invalid( - f"Component {name} requires {stop_bits} stop bits for the uart bus" + f"Component {name} requires {stop_bits} stop bits for the uart referenced by {uart_bus}" ) return value @@ -316,14 +317,14 @@ def final_validate_device_schema( hub_schema[ cv.Required( CONF_TX_PIN, - msg=f"Component {name} requires this uart bus to declare a tx_pin", + msg=f"Component {name} requires uart referenced by {uart_bus} to declare a tx_pin", ) ] = validate_pin(CONF_TX_PIN, device) if require_rx and uart_id_type_str in NATIVE_UART_CLASSES: hub_schema[ cv.Required( CONF_RX_PIN, - msg=f"Component {name} requires this uart bus to declare a rx_pin", + msg=f"Component {name} requires uart referenced by {uart_bus} to declare a rx_pin", ) ] = validate_pin(CONF_RX_PIN, device) if baud_rate is not None: @@ -337,7 +338,7 @@ def final_validate_device_schema( return cv.Schema(hub_schema, extra=cv.ALLOW_EXTRA)(hub_config) return cv.Schema( - {cv.Required(CONF_UART_ID): fv.id_declaration_match_schema(validate_hub)}, + {cv.Required(uart_bus): fv.id_declaration_match_schema(validate_hub)}, extra=cv.ALLOW_EXTRA, ) From 5dec62bf1e464baca86d9e8cda94ca4ada2e0913 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Mon, 17 Jun 2024 07:48:56 +0200 Subject: [PATCH 1916/2607] fix(dallas): make recovery time for 1-bit equal to that of 0-bit (#6763) --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index f47e8d58e3..34c2cf3c29 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -60,7 +60,7 @@ void HOT IRAM_ATTR GPIOOneWireBus::write_bit_(bool bit) { // recovery time: t_rec: min=1µs // ds18b20 appears to read the bus after roughly 14µs uint32_t delay0 = bit ? 6 : 60; - uint32_t delay1 = bit ? 54 : 5; + uint32_t delay1 = bit ? 59 : 5; // delay A/C delayMicroseconds(delay0); From d27e7b3b70310a7970ee44213bb3680a554bd5b1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:07:43 +1200 Subject: [PATCH 1917/2607] [wifi] Fix some access point bugs related to esp-idf 4.4.7 (#6928) * Set dhcp server range to only 10 IPs * Change log level to errors to make it clearer * We want to stop the dhcp server, not client --- .../wifi/wifi_component_esp32_arduino.cpp | 12 ++++++------ .../components/wifi/wifi_component_esp8266.cpp | 14 +++++++------- .../components/wifi/wifi_component_esp_idf.cpp | 16 ++++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index ef7a624cd5..fc954a2333 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -694,15 +694,15 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.netmask = network::IPAddress(255, 255, 255, 0); } - err = esp_netif_dhcpc_stop(s_ap_netif); + err = esp_netif_dhcps_stop(s_ap_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "esp_netif_dhcps_stop failed: %s", esp_err_to_name(err)); return false; } err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); + ESP_LOGE(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -712,20 +712,20 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 838250972b..997457e2d2 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -716,12 +716,12 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { if (wifi_softap_dhcps_status() == DHCP_STARTED) { if (!wifi_softap_dhcps_stop()) { - ESP_LOGV(TAG, "Stopping DHCP server failed!"); + ESP_LOGW(TAG, "Stopping DHCP server failed!"); } } if (!wifi_set_ip_info(SOFTAP_IF, &info)) { - ESP_LOGV(TAG, "Setting SoftAP info failed!"); + ESP_LOGE(TAG, "Setting SoftAP info failed!"); return false; } @@ -735,17 +735,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); if (!wifi_softap_set_dhcps_lease(&lease)) { - ESP_LOGV(TAG, "Setting SoftAP DHCP lease failed!"); + ESP_LOGE(TAG, "Setting SoftAP DHCP lease failed!"); return false; } // lease time 1440 minutes (=24 hours) if (!wifi_softap_set_dhcps_lease_time(1440)) { - ESP_LOGV(TAG, "Setting SoftAP DHCP lease time failed!"); + ESP_LOGE(TAG, "Setting SoftAP DHCP lease time failed!"); return false; } @@ -755,13 +755,13 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { uint8_t mode = 1; // bit0, 1 enables router information from ESP8266 SoftAP DHCP server. if (!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) { - ESP_LOGV(TAG, "wifi_softap_set_dhcps_offer_option failed!"); + ESP_LOGE(TAG, "wifi_softap_set_dhcps_offer_option failed!"); return false; } #endif if (!wifi_softap_dhcps_start()) { - ESP_LOGV(TAG, "Starting SoftAP DHCPS failed!"); + ESP_LOGE(TAG, "Starting SoftAP DHCPS failed!"); return false; } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index bc575e6a2d..c21486fee4 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -823,15 +823,15 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.netmask = network::IPAddress(255, 255, 255, 0); } - err = esp_netif_dhcpc_stop(s_ap_netif); + err = esp_netif_dhcps_stop(s_ap_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "esp_netif_dhcps_stop failed: %s", esp_err_to_name(err)); return false; } err = esp_netif_set_ip_info(s_ap_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); + ESP_LOGE(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -841,20 +841,20 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address += 99; lease.start_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str()); - start_address += 100; + start_address += 10; lease.end_ip = start_address; ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } err = esp_netif_dhcps_start(s_ap_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); + ESP_LOGE(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } @@ -887,12 +887,12 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf); if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_set_config failed! %d", err); + ESP_LOGE(TAG, "esp_wifi_set_config failed! %d", err); return false; } if (!this->wifi_ap_ip_config_(ap.get_manual_ip())) { - ESP_LOGV(TAG, "wifi_ap_ip_config_ failed!"); + ESP_LOGE(TAG, "wifi_ap_ip_config_ failed!"); return false; } From 43b5c2deb747114eae8367f7fbfba34296c24146 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:12:55 +1200 Subject: [PATCH 1918/2607] Rename legacy/modern to ota/factory (#6922) * Rename legacy/modern to ota/factory * Add modern/legacy in brackets --- esphome/components/esp32/__init__.py | 14 +++++------ esphome/components/esp32/post_build.py.script | 13 ++++++++++- .../components/esp8266/post_build.py.script | 10 +++++++- esphome/components/rp2040/__init__.py | 18 +++++++++++++-- .../components/rp2040/post_build.py.script | 23 +++++++++++++++++++ 5 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 esphome/components/rp2040/post_build.py.script diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 8f46567266..1effea708f 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -96,16 +96,16 @@ def get_board(core_obj=None): def get_download_types(storage_json): return [ { - "title": "Modern format", + "title": "Factory format (Previously Modern)", "description": "For use with ESPHome Web and other tools.", - "file": "firmware-factory.bin", - "download": f"{storage_json.name}-factory.bin", + "file": "firmware.factory.bin", + "download": f"{storage_json.name}.factory.bin", }, { - "title": "Legacy format", - "description": "For use with ESPHome Flasher.", - "file": "firmware.bin", - "download": f"{storage_json.name}.bin", + "title": "OTA format (Previously Legacy)", + "description": "For OTA updating a device.", + "file": "firmware.ota.bin", + "download": f"{storage_json.name}.ota.bin", }, ] diff --git a/esphome/components/esp32/post_build.py.script b/esphome/components/esp32/post_build.py.script index c941bdb386..c181cf30b1 100644 --- a/esphome/components/esp32/post_build.py.script +++ b/esphome/components/esp32/post_build.py.script @@ -17,17 +17,19 @@ from SCons.Script import ARGUMENTS # Copy over the default sdkconfig. from os import path + if path.exists("./sdkconfig.defaults"): os.makedirs(".temp", exist_ok=True) shutil.copy("./sdkconfig.defaults", "./.temp/sdkconfig-esp32-idf") + def esp32_create_combined_bin(source, target, env): verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0"))) if verbose: print("Generating combined binary for serial flashing") app_offset = 0x10000 - new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin") sections = env.subst(env.get("FLASH_EXTRA_IMAGES")) firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") chip = env.get("BOARD_MCU") @@ -62,5 +64,14 @@ def esp32_create_combined_bin(source, target, env): else: subprocess.run(["esptool.py", *cmd]) + +def esp32_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") + + shutil.copyfile(firmware_name, new_file_name) + + # pylint: disable=E0602 env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_copy_ota_bin) # noqa diff --git a/esphome/components/esp8266/post_build.py.script b/esphome/components/esp8266/post_build.py.script index 4dab1cbd27..0a854d7599 100644 --- a/esphome/components/esp8266/post_build.py.script +++ b/esphome/components/esp8266/post_build.py.script @@ -6,10 +6,18 @@ Import("env") # noqa def esp8266_copy_factory_bin(source, target, env): firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") - new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin") + + shutil.copyfile(firmware_name, new_file_name) + + +def esp8266_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") shutil.copyfile(firmware_name, new_file_name) # pylint: disable=E0602 env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp8266_copy_factory_bin) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp8266_copy_ota_bin) # noqa diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index ace455add7..f5c3b8bda2 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -47,10 +47,16 @@ def set_core_data(config): def get_download_types(storage_json): return [ { - "title": "UF2 format", + "title": "UF2 factory format", "description": "For copying to RP2040 over USB.", "file": "firmware.uf2", - "download": f"{storage_json.name}.uf2", + "download": f"{storage_json.name}.factory.uf2", + }, + { + "title": "OTA format", + "description": "For OTA updating a device.", + "file": "firmware.ota.bin", + "download": f"{storage_json.name}.ota.bin", }, ] @@ -160,6 +166,8 @@ async def to_code(config): cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "RP2040") + cg.add_platformio_option("extra_scripts", ["post:post_build.py"]) + conf = config[CONF_FRAMEWORK] cg.add_platformio_option("framework", "arduino") cg.add_build_flag("-DUSE_ARDUINO") @@ -225,4 +233,10 @@ def generate_pio_files() -> bool: # Called by writer.py def copy_files() -> bool: + dir = os.path.dirname(__file__) + post_build_file = os.path.join(dir, "post_build.py.script") + copy_file_if_changed( + post_build_file, + CORE.relative_build_path("post_build.py"), + ) return generate_pio_files() diff --git a/esphome/components/rp2040/post_build.py.script b/esphome/components/rp2040/post_build.py.script new file mode 100644 index 0000000000..7dcd7e52a6 --- /dev/null +++ b/esphome/components/rp2040/post_build.py.script @@ -0,0 +1,23 @@ +import shutil + +# pylint: disable=E0602 +Import("env") # noqa + + +def rp2040_copy_factory_uf2(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.uf2") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.uf2") + + shutil.copyfile(firmware_name, new_file_name) + + +def rp2040_copy_ota_bin(source, target, env): + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") + new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.ota.bin") + + shutil.copyfile(firmware_name, new_file_name) + + +# pylint: disable=E0602 +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", rp2040_copy_factory_uf2) # noqa +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", rp2040_copy_ota_bin) # noqa From ff07637dfdfb5364076966fba12dc1de949e8748 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:26:24 +1200 Subject: [PATCH 1919/2607] Bump version to 2024.6.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index a0fe325282..eea437bcdc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0b3" +__version__ = "2024.6.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 65a79acfb972876bfd54d777393bd553cdfde8e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:44:20 +1200 Subject: [PATCH 1920/2607] Bump pypa/gh-action-pypi-publish from 1.8.14 to 1.9.0 (#6926) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c07335104..a1942e8cac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.8.14 + uses: pypa/gh-action-pypi-publish@v1.9.0 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From c18056bdda129136f05b52388e738ceec8242e62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 19:16:10 +1200 Subject: [PATCH 1921/2607] Bump docker/build-push-action from 5.4.0 to 6.0.0 in /.github/actions/build-image (#6927) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index d792ab5f4c..c685e80bec 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.0.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.0.0 with: context: . file: ./docker/Dockerfile From 65b05af0143a11a5d0e290f7025a275808cbd143 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 07:38:31 +1200 Subject: [PATCH 1922/2607] Bump peter-evans/create-pull-request from 6.0.5 to 6.1.0 (#6935) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 45f6b27127..89a3627c64 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.5 + uses: peter-evans/create-pull-request@v6.1.0 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From ed6462fa00b2162d541a433076c01d67fb3c8e84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 07:38:50 +1200 Subject: [PATCH 1923/2607] Bump docker/build-push-action from 6.0.0 to 6.0.1 in /.github/actions/build-image (#6934) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index c685e80bec..53cd836573 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile From 896cdab22dfde5fbd64f3d0506d0d0d3990ef28b Mon Sep 17 00:00:00 2001 From: Manuel Kasper Date: Tue, 18 Jun 2024 21:53:01 +0200 Subject: [PATCH 1924/2607] Fix garbled graphics on LILYGO T4-S3 display (#6910) --- esphome/components/qspi_amoled/display.py | 20 +++++++++++++++---- .../components/qspi_amoled/qspi_amoled.cpp | 13 ++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/esphome/components/qspi_amoled/display.py b/esphome/components/qspi_amoled/display.py index 84bf9553cb..77d1e3d095 100644 --- a/esphome/components/qspi_amoled/display.py +++ b/esphome/components/qspi_amoled/display.py @@ -42,6 +42,14 @@ COLOR_ORDERS = { } DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + +def validate_dimension(value): + value = cv.positive_int(value) + if value % 2 != 0: + raise cv.Invalid("Width/height/offset must be divisible by 2") + return value + + CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( cv.Schema( @@ -52,10 +60,14 @@ CONFIG_SCHEMA = cv.All( cv.dimensions, cv.Schema( { - cv.Required(CONF_WIDTH): cv.int_, - cv.Required(CONF_HEIGHT): cv.int_, - cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, - cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, + cv.Required(CONF_WIDTH): validate_dimension, + cv.Required(CONF_HEIGHT): validate_dimension, + cv.Optional( + CONF_OFFSET_HEIGHT, default=0 + ): validate_dimension, + cv.Optional( + CONF_OFFSET_WIDTH, default=0 + ): validate_dimension, } ), ), diff --git a/esphome/components/qspi_amoled/qspi_amoled.cpp b/esphome/components/qspi_amoled/qspi_amoled.cpp index 697989e861..36e9b03252 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.cpp +++ b/esphome/components/qspi_amoled/qspi_amoled.cpp @@ -26,6 +26,19 @@ void QspiAmoLed::setup() { void QspiAmoLed::update() { this->do_update_(); + // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet) + if (this->x_low_ % 2 == 1) { + this->x_low_--; + } + if (this->x_high_ % 2 == 0) { + this->x_high_++; + } + if (this->y_low_ % 2 == 1) { + this->y_low_--; + } + if (this->y_high_ % 2 == 0) { + this->y_high_++; + } int w = this->x_high_ - this->x_low_ + 1; int h = this->y_high_ - this->y_low_ + 1; this->draw_pixels_at(this->x_low_, this->y_low_, w, h, this->buffer_, this->color_mode_, display::COLOR_BITNESS_565, From 310f850ee4a7dd7ed5084bd307122c0cbb2d4991 Mon Sep 17 00:00:00 2001 From: peter--s Date: Wed, 19 Jun 2024 03:28:03 +0200 Subject: [PATCH 1925/2607] Update cover.h for open() and close() compiler warnings (#6936) --- esphome/components/cover/cover.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index 89598a9636..8b6f5b8a72 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -129,13 +129,13 @@ class Cover : public EntityBase, public EntityBase_DeviceClass { * * This is a legacy method and may be removed later, please use `.make_call()` instead. */ - ESPDEPRECATED("open() is deprecated, use make_call().set_command_open() instead.", "2021.9") + ESPDEPRECATED("open() is deprecated, use make_call().set_command_open().perform() instead.", "2021.9") void open(); /** Close the cover. * * This is a legacy method and may be removed later, please use `.make_call()` instead. */ - ESPDEPRECATED("close() is deprecated, use make_call().set_command_close() instead.", "2021.9") + ESPDEPRECATED("close() is deprecated, use make_call().set_command_close().perform() instead.", "2021.9") void close(); /** Stop the cover. * From 8567877f07d2900a067c6b0fc57e5b0e07685f1d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:09:16 +1200 Subject: [PATCH 1926/2607] [network] Default ipv6 to false to always set the flags (#6937) * [network] Default ipv6 to false to always set the flags * Separate tests for ipv6 disabled and enabled * Forgot other platforms wouldnt have the variable in config --- esphome/components/network/__init__.py | 26 +++++++++++-------- tests/components/network/common.yaml | 5 +++- .../network/test-ipv6.esp32-ard.yaml | 4 +++ .../network/test-ipv6.esp32-c3-ard.yaml | 4 +++ .../network/test-ipv6.esp32-c3-idf.yaml | 4 +++ .../network/test-ipv6.esp32-idf.yaml | 4 +++ .../network/test-ipv6.esp8266-ard.yaml | 4 +++ .../network/test-ipv6.rp2040-ard.yaml | 4 +++ tests/components/network/test.host.yaml | 1 + 9 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 tests/components/network/test-ipv6.esp32-ard.yaml create mode 100644 tests/components/network/test-ipv6.esp32-c3-ard.yaml create mode 100644 tests/components/network/test-ipv6.esp32-c3-idf.yaml create mode 100644 tests/components/network/test-ipv6.esp32-idf.yaml create mode 100644 tests/components/network/test-ipv6.esp8266-ard.yaml create mode 100644 tests/components/network/test-ipv6.rp2040-ard.yaml create mode 100644 tests/components/network/test.host.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 36144ff0a4..9ef75e0fb9 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -19,7 +19,12 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.SplitDefault(CONF_ENABLE_IPV6): cv.All( + cv.SplitDefault( + CONF_ENABLE_IPV6, + esp8266=False, + esp32=False, + rp2040=False, + ): cv.All( cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, @@ -28,18 +33,17 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): - if CONF_ENABLE_IPV6 in config: - cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) - cg.add_define( - "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] - ) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: + cg.add_define("USE_NETWORK_IPV6", enable_ipv6) + if enable_ipv6: + cg.add_define( + "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] ) + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", enable_ipv6) + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", enable_ipv6) else: - if config[CONF_ENABLE_IPV6]: + if enable_ipv6: cg.add_build_flag("-DCONFIG_LWIP_IPV6") cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") if CORE.is_rp2040: diff --git a/tests/components/network/common.yaml b/tests/components/network/common.yaml index 147afd1e81..dca00cbeb6 100644 --- a/tests/components/network/common.yaml +++ b/tests/components/network/common.yaml @@ -1,6 +1,9 @@ +substitutions: + network_enable_ipv6: "false" + wifi: ssid: MySSID password: password1 network: - enable_ipv6: true + enable_ipv6: ${network_enable_ipv6} diff --git a/tests/components/network/test-ipv6.esp32-ard.yaml b/tests/components/network/test-ipv6.esp32-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-ard.yaml b/tests/components/network/test-ipv6.esp32-c3-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-idf.yaml b/tests/components/network/test-ipv6.esp32-c3-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-idf.yaml b/tests/components/network/test-ipv6.esp32-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp8266-ard.yaml b/tests/components/network/test-ipv6.esp8266-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp8266-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.rp2040-ard.yaml b/tests/components/network/test-ipv6.rp2040-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.rp2040-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test.host.yaml b/tests/components/network/test.host.yaml new file mode 100644 index 0000000000..61889b0361 --- /dev/null +++ b/tests/components/network/test.host.yaml @@ -0,0 +1 @@ +network: From fd7a212562089d1e2ce55b4f698cd20343de8094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:44:20 +1200 Subject: [PATCH 1927/2607] Bump pypa/gh-action-pypi-publish from 1.8.14 to 1.9.0 (#6926) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 563d485b6a..62031e925a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.8.14 + uses: pypa/gh-action-pypi-publish@v1.9.0 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From acf69bb56f53b636932e224fc466ef8cab65ef0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 19:16:10 +1200 Subject: [PATCH 1928/2607] Bump docker/build-push-action from 5.4.0 to 6.0.0 in /.github/actions/build-image (#6927) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index d792ab5f4c..c685e80bec 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.0.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.0.0 with: context: . file: ./docker/Dockerfile From c17090c1e556aebeb0186f0042824f9611266896 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 07:38:50 +1200 Subject: [PATCH 1929/2607] Bump docker/build-push-action from 6.0.0 to 6.0.1 in /.github/actions/build-image (#6934) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index c685e80bec..53cd836573 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile From 6682451ee0c53a30d577d67574f827ec82952b17 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:09:16 +1200 Subject: [PATCH 1930/2607] [network] Default ipv6 to false to always set the flags (#6937) * [network] Default ipv6 to false to always set the flags * Separate tests for ipv6 disabled and enabled * Forgot other platforms wouldnt have the variable in config --- esphome/components/network/__init__.py | 26 +++++++++++-------- tests/components/network/common.yaml | 5 +++- .../network/test-ipv6.esp32-ard.yaml | 4 +++ .../network/test-ipv6.esp32-c3-ard.yaml | 4 +++ .../network/test-ipv6.esp32-c3-idf.yaml | 4 +++ .../network/test-ipv6.esp32-idf.yaml | 4 +++ .../network/test-ipv6.esp8266-ard.yaml | 4 +++ .../network/test-ipv6.rp2040-ard.yaml | 4 +++ tests/components/network/test.host.yaml | 1 + 9 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 tests/components/network/test-ipv6.esp32-ard.yaml create mode 100644 tests/components/network/test-ipv6.esp32-c3-ard.yaml create mode 100644 tests/components/network/test-ipv6.esp32-c3-idf.yaml create mode 100644 tests/components/network/test-ipv6.esp32-idf.yaml create mode 100644 tests/components/network/test-ipv6.esp8266-ard.yaml create mode 100644 tests/components/network/test-ipv6.rp2040-ard.yaml create mode 100644 tests/components/network/test.host.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 36144ff0a4..9ef75e0fb9 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -19,7 +19,12 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.SplitDefault(CONF_ENABLE_IPV6): cv.All( + cv.SplitDefault( + CONF_ENABLE_IPV6, + esp8266=False, + esp32=False, + rp2040=False, + ): cv.All( cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, @@ -28,18 +33,17 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): - if CONF_ENABLE_IPV6 in config: - cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) - cg.add_define( - "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] - ) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: + cg.add_define("USE_NETWORK_IPV6", enable_ipv6) + if enable_ipv6: + cg.add_define( + "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] ) + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", enable_ipv6) + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", enable_ipv6) else: - if config[CONF_ENABLE_IPV6]: + if enable_ipv6: cg.add_build_flag("-DCONFIG_LWIP_IPV6") cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") if CORE.is_rp2040: diff --git a/tests/components/network/common.yaml b/tests/components/network/common.yaml index 147afd1e81..dca00cbeb6 100644 --- a/tests/components/network/common.yaml +++ b/tests/components/network/common.yaml @@ -1,6 +1,9 @@ +substitutions: + network_enable_ipv6: "false" + wifi: ssid: MySSID password: password1 network: - enable_ipv6: true + enable_ipv6: ${network_enable_ipv6} diff --git a/tests/components/network/test-ipv6.esp32-ard.yaml b/tests/components/network/test-ipv6.esp32-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-ard.yaml b/tests/components/network/test-ipv6.esp32-c3-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-idf.yaml b/tests/components/network/test-ipv6.esp32-c3-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-idf.yaml b/tests/components/network/test-ipv6.esp32-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp8266-ard.yaml b/tests/components/network/test-ipv6.esp8266-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp8266-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.rp2040-ard.yaml b/tests/components/network/test-ipv6.rp2040-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.rp2040-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test.host.yaml b/tests/components/network/test.host.yaml new file mode 100644 index 0000000000..61889b0361 --- /dev/null +++ b/tests/components/network/test.host.yaml @@ -0,0 +1 @@ +network: From 8bac82f80497b7e25639abc94102c125082e59cf Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:37:43 +1200 Subject: [PATCH 1931/2607] Bump version to 2024.6.0b5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index eea437bcdc..3aba12b9dd 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0b4" +__version__ = "2024.6.0b5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From ff803aa108214331d292fc90574ac06e84b82409 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:37:33 +1200 Subject: [PATCH 1932/2607] Rename test files --- .../{test-ipv6.esp8266-ard.yaml => test-ipv6.esp8266.yaml} | 0 .../network/{test-ipv6.rp2040-ard.yaml => test-ipv6.rp2040.yaml} | 0 tests/components/network/{test.esp32.yaml => test.esp32-ard.yaml} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/components/network/{test-ipv6.esp8266-ard.yaml => test-ipv6.esp8266.yaml} (100%) rename tests/components/network/{test-ipv6.rp2040-ard.yaml => test-ipv6.rp2040.yaml} (100%) rename tests/components/network/{test.esp32.yaml => test.esp32-ard.yaml} (100%) diff --git a/tests/components/network/test-ipv6.esp8266-ard.yaml b/tests/components/network/test-ipv6.esp8266.yaml similarity index 100% rename from tests/components/network/test-ipv6.esp8266-ard.yaml rename to tests/components/network/test-ipv6.esp8266.yaml diff --git a/tests/components/network/test-ipv6.rp2040-ard.yaml b/tests/components/network/test-ipv6.rp2040.yaml similarity index 100% rename from tests/components/network/test-ipv6.rp2040-ard.yaml rename to tests/components/network/test-ipv6.rp2040.yaml diff --git a/tests/components/network/test.esp32.yaml b/tests/components/network/test.esp32-ard.yaml similarity index 100% rename from tests/components/network/test.esp32.yaml rename to tests/components/network/test.esp32-ard.yaml From a6d1aa91de821726d114c46c30a0c9cb36c147ff Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:52:47 +1200 Subject: [PATCH 1933/2607] Bump version to 2024.6.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 3aba12b9dd..0f5caa7f9d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0b5" +__version__ = "2024.6.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 80e5e1995653a3b51193b456d9861ec7f7f81c24 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:59:37 -0500 Subject: [PATCH 1934/2607] debug_libretiny - Fix typo (#6942) --- esphome/components/debug/debug_libretiny.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp index c3418cf96c..b5e2a5b310 100644 --- a/esphome/components/debug/debug_libretiny.cpp +++ b/esphome/components/debug/debug_libretiny.cpp @@ -12,7 +12,7 @@ std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_na uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } void DebugComponent::get_device_info_(std::string &device_info) { - str::string reset_reason = get_reset_reason_(); + std::string reset_reason = get_reset_reason_(); ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); From 775e03cfd95d6532292e7665f82b5301924795b9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 20 Jun 2024 14:12:38 +1200 Subject: [PATCH 1935/2607] Bump esphome-dashboard to 20240620.0 (#6944) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7b08f8a14..0cbe5e7265 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240613.0 +esphome-dashboard==20240620.0 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 From 96f1a146a66e5266d4417e7afb0db2781e243048 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 19 Jun 2024 21:32:29 -0500 Subject: [PATCH 1936/2607] [CI] Add debug component test for LibreTiny (#6945) --- tests/components/debug/test.bk72xx-ard.yaml | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/components/debug/test.bk72xx-ard.yaml diff --git a/tests/components/debug/test.bk72xx-ard.yaml b/tests/components/debug/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/debug/test.bk72xx-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From ad8cf698973ea821ec1a8e4ec7ad74caa691b6cb Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:59:37 -0500 Subject: [PATCH 1937/2607] debug_libretiny - Fix typo (#6942) --- esphome/components/debug/debug_libretiny.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp index c3418cf96c..b5e2a5b310 100644 --- a/esphome/components/debug/debug_libretiny.cpp +++ b/esphome/components/debug/debug_libretiny.cpp @@ -12,7 +12,7 @@ std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_na uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } void DebugComponent::get_device_info_(std::string &device_info) { - str::string reset_reason = get_reset_reason_(); + std::string reset_reason = get_reset_reason_(); ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); From c868dae44a141ca3e0cbbf76a5c92b6bba7f5bbe Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 20 Jun 2024 14:12:38 +1200 Subject: [PATCH 1938/2607] Bump esphome-dashboard to 20240620.0 (#6944) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7b08f8a14..0cbe5e7265 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240613.0 +esphome-dashboard==20240620.0 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 From a7a9eb6f71677e8b1ec29cfcea86569452d16d57 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:59:27 +1200 Subject: [PATCH 1939/2607] Bump version to 2024.6.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 0f5caa7f9d..3b3bdd1a17 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.0" +__version__ = "2024.6.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6f074d369205ad91523bfc7eedaba34093dce423 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 21 Jun 2024 12:49:26 +1200 Subject: [PATCH 1940/2607] [dooya] Flip bit timings (#6947) --- esphome/components/remote_base/dooya_protocol.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/remote_base/dooya_protocol.cpp b/esphome/components/remote_base/dooya_protocol.cpp index d979bca8c5..04c5fef8f3 100644 --- a/esphome/components/remote_base/dooya_protocol.cpp +++ b/esphome/components/remote_base/dooya_protocol.cpp @@ -8,10 +8,10 @@ static const char *const TAG = "remote.dooya"; static const uint32_t HEADER_HIGH_US = 5000; static const uint32_t HEADER_LOW_US = 1500; -static const uint32_t BIT_ZERO_HIGH_US = 750; -static const uint32_t BIT_ZERO_LOW_US = 350; -static const uint32_t BIT_ONE_HIGH_US = 350; -static const uint32_t BIT_ONE_LOW_US = 750; +static const uint32_t BIT_ZERO_HIGH_US = 350; +static const uint32_t BIT_ZERO_LOW_US = 750; +static const uint32_t BIT_ONE_HIGH_US = 750; +static const uint32_t BIT_ONE_LOW_US = 350; void DooyaProtocol::encode(RemoteTransmitData *dst, const DooyaData &data) { dst->set_carrier_frequency(0); From 8045b889d39c7675ba69afa0d38e7fd7b952d93c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:09:00 +1200 Subject: [PATCH 1941/2607] [core] Fix package merging with lists of primitives (#6952) --- esphome/config_helpers.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index b5e0b26143..54242bc259 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -58,17 +58,21 @@ def merge_config(full_old, full_new): ids = { v_id: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, str) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, str) } extend_ids = { v_id.value: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, Extend) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, Extend) } ids_to_delete = [] for v in new: - if new_id := v.get(CONF_ID): + if isinstance(v, dict) and (new_id := v.get(CONF_ID)): if isinstance(new_id, Extend): new_id = new_id.value if new_id in ids: From e7556271e72f85e09d1381bee68e43bde8843387 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:59:52 +1200 Subject: [PATCH 1942/2607] [update] Set entity_category to config & Publish state to logs (#6954) --- esphome/components/update/__init__.py | 5 ++++ esphome/components/update/update_entity.cpp | 26 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ea1cf778b6..20a9373a06 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -4,11 +4,13 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( CONF_DEVICE_CLASS, + CONF_ENTITY_CATEGORY, CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, + ENTITY_CATEGORY_CONFIG, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -41,6 +43,9 @@ UPDATE_SCHEMA = ( cv.Optional(CONF_ON_UPDATE_AVAILABLE): automation.validate_automation( single=True ), + cv.Optional( + CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG + ): cv.entity_category, } ) ) diff --git a/esphome/components/update/update_entity.cpp b/esphome/components/update/update_entity.cpp index 501cb6635f..ed9a0480d8 100644 --- a/esphome/components/update/update_entity.cpp +++ b/esphome/components/update/update_entity.cpp @@ -1,9 +1,35 @@ #include "update_entity.h" +#include "esphome/core/log.h" + namespace esphome { namespace update { +static const char *const TAG = "update"; + void UpdateEntity::publish_state() { + ESP_LOGD(TAG, "'%s' - Publishing:", this->name_.c_str()); + ESP_LOGD(TAG, " Current Version: %s", this->update_info_.current_version.c_str()); + + if (!this->update_info_.md5.empty()) { + ESP_LOGD(TAG, " Latest Version: %s", this->update_info_.latest_version.c_str()); + } + if (!this->update_info_.firmware_url.empty()) { + ESP_LOGD(TAG, " Firmware URL: %s", this->update_info_.firmware_url.c_str()); + } + + ESP_LOGD(TAG, " Title: %s", this->update_info_.title.c_str()); + if (!this->update_info_.summary.empty()) { + ESP_LOGD(TAG, " Summary: %s", this->update_info_.summary.c_str()); + } + if (!this->update_info_.release_url.empty()) { + ESP_LOGD(TAG, " Release URL: %s", this->update_info_.release_url.c_str()); + } + + if (this->update_info_.has_progress) { + ESP_LOGD(TAG, " Progress: %.0f%%", this->update_info_.progress); + } + this->has_state_ = true; this->state_callback_.call(); } From 6c11f0bd5152b32579b3f86802365f2e308e9ca4 Mon Sep 17 00:00:00 2001 From: Manuel Kasper Date: Fri, 21 Jun 2024 16:46:06 +0200 Subject: [PATCH 1943/2607] [qspi_amoled] Fix display remaining blank after update() before setup completion (#6958) --- esphome/components/qspi_amoled/qspi_amoled.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/qspi_amoled/qspi_amoled.cpp b/esphome/components/qspi_amoled/qspi_amoled.cpp index 36e9b03252..b1f651025a 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.cpp +++ b/esphome/components/qspi_amoled/qspi_amoled.cpp @@ -25,6 +25,9 @@ void QspiAmoLed::setup() { } void QspiAmoLed::update() { + if (!this->setup_complete_) { + return; + } this->do_update_(); // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet) if (this->x_low_ % 2 == 1) { From 67bd5db6d6eb6c23e44b430200fefa9a371e2491 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Fri, 21 Jun 2024 17:18:43 -0400 Subject: [PATCH 1944/2607] Fix infinite loop in http_request for ESP-IDF. (#6963) --- esphome/components/http_request/http_request_idf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 138e0438f4..d6fac7a133 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -90,7 +90,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin int write_left = body_len; int write_index = 0; const char *buf = body.c_str(); - while (body_len > 0) { + while (write_left > 0) { int written = esp_http_client_write(client, buf + write_index, write_left); if (written < 0) { err = ESP_FAIL; From 0a9703bff998a5196e15a3aefa35257b7d651c98 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Fri, 21 Jun 2024 17:28:11 -0400 Subject: [PATCH 1945/2607] ESP-IDF 4.x expects seconds for esp_task_wdt_init(), not milliseconds. (#6964) --- esphome/components/http_request/watchdog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/http_request/watchdog.cpp b/esphome/components/http_request/watchdog.cpp index e609feb4dd..a8519c59ed 100644 --- a/esphome/components/http_request/watchdog.cpp +++ b/esphome/components/http_request/watchdog.cpp @@ -46,7 +46,7 @@ void WatchdogManager::set_timeout_(uint32_t timeout_ms) { }; esp_task_wdt_reconfigure(&wdt_config); #else - esp_task_wdt_init(timeout_ms, true); + esp_task_wdt_init(timeout_ms / 1000, true); #endif // ESP_IDF_VERSION_MAJOR #endif // USE_ESP32 From 9c5507ab4680ce4df996910807100cc72f911e1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 12:50:21 +0200 Subject: [PATCH 1946/2607] Bump docker/build-push-action from 6.0.1 to 6.1.0 in /.github/actions/build-image (#6962) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 53cd836573..27d2ffc533 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.0.1 + uses: docker/build-push-action@v6.1.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.0.1 + uses: docker/build-push-action@v6.1.0 with: context: . file: ./docker/Dockerfile From 2aacf14e960d005aee29e7a259f47b90ae1d3970 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sat, 22 Jun 2024 04:57:27 -0700 Subject: [PATCH 1947/2607] Onewire (#6967) * retry scan * setup pin and log retries * fix retries * remove retries --------- Co-authored-by: Samuel Sieb --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index 34c2cf3c29..b4e69e975a 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -9,6 +9,10 @@ static const char *const TAG = "gpio.one_wire"; void GPIOOneWireBus::setup() { ESP_LOGCONFIG(TAG, "Setting up 1-wire bus..."); + this->t_pin_->setup(); + // clear bus with 480µs high, otherwise initial reset in search might fail + this->t_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + delayMicroseconds(480); this->search(); } From 18690d51f51c0d8a145c8ca71a234a496a06b3d9 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Sun, 23 Jun 2024 01:27:47 +1200 Subject: [PATCH 1948/2607] Synchronise Device Classes from Home Assistant (#6966) --- esphome/components/number/__init__.py | 2 ++ esphome/components/sensor/__init__.py | 2 ++ esphome/const.py | 1 + 3 files changed, 5 insertions(+) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 303535c138..d9c16fd7a9 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -26,6 +26,7 @@ from esphome.const import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CONDUCTIVITY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, @@ -82,6 +83,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_BATTERY, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CONDUCTIVITY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 6077f5dc1f..262e69d75b 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -43,6 +43,7 @@ from esphome.const import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CONDUCTIVITY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, @@ -103,6 +104,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_BATTERY, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CONDUCTIVITY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, diff --git a/esphome/const.py b/esphome/const.py index 9c4e451029..a13a0af8eb 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1070,6 +1070,7 @@ DEVICE_CLASS_BUTTON = "button" DEVICE_CLASS_CARBON_DIOXIDE = "carbon_dioxide" DEVICE_CLASS_CARBON_MONOXIDE = "carbon_monoxide" DEVICE_CLASS_COLD = "cold" +DEVICE_CLASS_CONDUCTIVITY = "conductivity" DEVICE_CLASS_CONNECTIVITY = "connectivity" DEVICE_CLASS_CURRENT = "current" DEVICE_CLASS_CURTAIN = "curtain" From 1e05bcaa614040617ef94340a54ca3f22871c4ac Mon Sep 17 00:00:00 2001 From: Manuel Kasper Date: Sat, 22 Jun 2024 17:10:22 +0200 Subject: [PATCH 1949/2607] [qspi_amoled] Fix clear/fill with rotation (#6960) --- esphome/components/qspi_amoled/qspi_amoled.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/qspi_amoled/qspi_amoled.h b/esphome/components/qspi_amoled/qspi_amoled.h index 28d243f548..c766b4e685 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.h +++ b/esphome/components/qspi_amoled/qspi_amoled.h @@ -65,13 +65,10 @@ class QspiAmoLed : public display::DisplayBuffer, void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_enable_pin(GPIOPin *enable_pin) { this->enable_pin_ = enable_pin; } - void set_width(uint16_t width) { this->width_ = width; } void set_dimensions(uint16_t width, uint16_t height) { this->width_ = width; this->height_ = height; } - int get_width() override { return this->width_; } - int get_height() override { return this->height_; } void set_invert_colors(bool invert_colors) { this->invert_colors_ = invert_colors; this->reset_params_(); From 17204baac0168b6a6dd2f6ad87968cd83717f7de Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 23 Jun 2024 15:22:08 -0700 Subject: [PATCH 1950/2607] allow template parameters (#6972) --- esphome/components/script/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py index 483357f85b..16b1d4c54e 100644 --- a/esphome/components/script/__init__.py +++ b/esphome/components/script/__init__.py @@ -88,7 +88,7 @@ def validate_parameter_name(value): raise cv.Invalid(f"Script's parameter name cannot be {CONF_ID}") -ALLOWED_PARAM_TYPE_CHARSET = set("abcdefghijklmnopqrstuvwxyz0123456789_:*&[]") +ALLOWED_PARAM_TYPE_CHARSET = set("abcdefghijklmnopqrstuvwxyz0123456789_:*&[]<>") def validate_parameter_type(value): From 0f49b58e0a727284c055246188a4ce9fee687eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 24 Jun 2024 06:32:20 +0200 Subject: [PATCH 1951/2607] [http_request] memory leak fix (#6973) --- esphome/components/http_request/http_request.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index df6bc7dea7..6281adddb6 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -149,6 +149,7 @@ template class HttpRequestSendAction : public Action { } response_body.reserve(read_index); response_body.assign((char *) buf, read_index); + allocator.deallocate(buf, max_length); } } From 7ee1406f64a04807bf1737cbd407f978744004ab Mon Sep 17 00:00:00 2001 From: Brian Kaufman Date: Sun, 23 Jun 2024 21:54:30 -0700 Subject: [PATCH 1952/2607] Await cg.get_variable in Update component (#6974) --- esphome/components/update/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index 20a9373a06..45bf082fa4 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -69,7 +69,7 @@ async def setup_update_core_(var, config): await mqtt.register_mqtt_component(mqtt_, config) if web_server_id_config := config.get(CONF_WEB_SERVER_ID): - web_server_ = cg.get_variable(web_server_id_config) + web_server_ = await cg.get_variable(web_server_id_config) web_server.add_entity_to_sorting_list(web_server_, var, config) From f7af51b92c9d3fee019f2ff5abda5880cf18061e Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 24 Jun 2024 10:22:07 +0400 Subject: [PATCH 1953/2607] [haier] climate ID auto generation (#6949) --- esphome/components/haier/binary_sensor/__init__.py | 8 ++++---- esphome/components/haier/button/__init__.py | 2 +- esphome/components/haier/climate.py | 11 +++-------- esphome/components/haier/sensor/__init__.py | 10 +++++----- esphome/components/haier/text_sensor/__init__.py | 8 ++++---- tests/components/haier/test.esp32-c3-ard.yaml | 4 ---- tests/components/haier/test.esp32-c3-idf.yaml | 4 ---- tests/components/haier/test.esp32-idf.yaml | 4 ---- tests/components/haier/test.esp8266-ard.yaml | 4 ---- tests/components/haier/test.rp2040-ard.yaml | 4 ---- 10 files changed, 17 insertions(+), 42 deletions(-) diff --git a/esphome/components/haier/binary_sensor/__init__.py b/esphome/components/haier/binary_sensor/__init__.py index 8e9d5ec578..3a4935b22d 100644 --- a/esphome/components/haier/binary_sensor/__init__.py +++ b/esphome/components/haier/binary_sensor/__init__.py @@ -56,7 +56,7 @@ SENSOR_TYPES = { CONFIG_SCHEMA = cv.Schema( { - cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate), } ).extend({cv.Optional(type): schema for type, schema in SENSOR_TYPES.items()}) @@ -64,8 +64,8 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): paren = await cg.get_variable(config[CONF_HAIER_ID]) - for type, _ in SENSOR_TYPES.items(): - if conf := config.get(type): + for type_ in SENSOR_TYPES: + if conf := config.get(type_): sens = await binary_sensor.new_binary_sensor(conf) - binary_sensor_type = getattr(BinarySensorTypeEnum, type.upper()) + binary_sensor_type = getattr(BinarySensorTypeEnum, type_.upper()) cg.add(paren.set_sub_binary_sensor(binary_sensor_type, sens)) diff --git a/esphome/components/haier/button/__init__.py b/esphome/components/haier/button/__init__.py index efe6180aaf..745ad95fb6 100644 --- a/esphome/components/haier/button/__init__.py +++ b/esphome/components/haier/button/__init__.py @@ -21,7 +21,7 @@ ICON_SPRAY_BOTTLE = "mdi:spray-bottle" CONFIG_SCHEMA = cv.Schema( { - cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate), cv.Optional(CONF_SELF_CLEANING): button.button_schema( SelfCleaningButton, icon=ICON_SPRAY_BOTTLE, diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index 1562708a4f..3dcb35708c 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -183,7 +183,6 @@ BASE_CONFIG_SCHEMA = ( cv.Optional( CONF_SUPPORTED_SWING_MODES, default=[ - "OFF", "VERTICAL", "HORIZONTAL", "BOTH", @@ -211,7 +210,7 @@ CONFIG_SCHEMA = cv.All( ): cv.boolean, cv.Optional( CONF_SUPPORTED_PRESETS, - default=list(["BOOST", "COMFORT"]), # No AWAY by default + default=["BOOST", "COMFORT"], # No AWAY by default ): cv.ensure_list( cv.enum(SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS, upper=True) ), @@ -231,7 +230,7 @@ CONFIG_SCHEMA = cv.All( ): cv.int_range(min=PROTOCOL_CONTROL_PACKET_SIZE, max=50), cv.Optional( CONF_SUPPORTED_PRESETS, - default=list(["BOOST", "ECO", "SLEEP"]), # No AWAY by default + default=["BOOST", "ECO", "SLEEP"], # No AWAY by default ): cv.ensure_list( cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True) ), @@ -427,11 +426,7 @@ def _final_validate(config): "No logger component found, logging for Haier protocol is disabled" ) cg.add_build_flag("-DHAIER_LOG_LEVEL=0") - if ( - (CONF_WIFI_SIGNAL in config) - and (config[CONF_WIFI_SIGNAL]) - and CONF_WIFI not in full_config - ): + if config.get(CONF_WIFI_SIGNAL) and CONF_WIFI not in full_config: raise cv.Invalid( f"No WiFi configured, if you want to use haier climate without WiFi add {CONF_WIFI_SIGNAL}: false to climate configuration" ) diff --git a/esphome/components/haier/sensor/__init__.py b/esphome/components/haier/sensor/__init__.py index b2717631e0..23c1d6f008 100644 --- a/esphome/components/haier/sensor/__init__.py +++ b/esphome/components/haier/sensor/__init__.py @@ -137,16 +137,16 @@ SENSOR_TYPES = { CONFIG_SCHEMA = cv.Schema( { - cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate), } -).extend({cv.Optional(type): schema for type, schema in SENSOR_TYPES.items()}) +).extend({cv.Optional(type_): schema for type_, schema in SENSOR_TYPES.items()}) async def to_code(config): paren = await cg.get_variable(config[CONF_HAIER_ID]) - for type, _ in SENSOR_TYPES.items(): - if conf := config.get(type): + for type_ in SENSOR_TYPES: + if conf := config.get(type_): sens = await sensor.new_sensor(conf) - sensor_type = getattr(SensorTypeEnum, type.upper()) + sensor_type = getattr(SensorTypeEnum, type_.upper()) cg.add(paren.set_sub_sensor(sensor_type, sens)) diff --git a/esphome/components/haier/text_sensor/__init__.py b/esphome/components/haier/text_sensor/__init__.py index 528b70d83e..d28c5a8c0e 100644 --- a/esphome/components/haier/text_sensor/__init__.py +++ b/esphome/components/haier/text_sensor/__init__.py @@ -39,7 +39,7 @@ TEXT_SENSOR_TYPES = { CONFIG_SCHEMA = cv.Schema( { - cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate), + cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate), } ).extend({cv.Optional(type): schema for type, schema in TEXT_SENSOR_TYPES.items()}) @@ -47,8 +47,8 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): paren = await cg.get_variable(config[CONF_HAIER_ID]) - for type, _ in TEXT_SENSOR_TYPES.items(): - if conf := config.get(type): + for type_ in TEXT_SENSOR_TYPES: + if conf := config.get(type_): sens = await text_sensor.new_text_sensor(conf) - text_sensor_type = getattr(TextSensorTypeEnum, type.upper()) + text_sensor_type = getattr(TextSensorTypeEnum, type_.upper()) cg.add(paren.set_sub_text_sensor(text_sensor_type, sens)) diff --git a/tests/components/haier/test.esp32-c3-ard.yaml b/tests/components/haier/test.esp32-c3-ard.yaml index fed573bd1d..0053220669 100644 --- a/tests/components/haier/test.esp32-c3-ard.yaml +++ b/tests/components/haier/test.esp32-c3-ard.yaml @@ -54,7 +54,6 @@ climate: sensor: - platform: haier - haier_id: haier_ac outdoor_temperature: name: Haier outdoor temperature humidity: @@ -80,7 +79,6 @@ sensor: binary_sensor: - platform: haier - haier_id: haier_ac compressor_status: name: Haier Outdoor Compressor Status defrost_status: @@ -96,7 +94,6 @@ binary_sensor: button: - platform: haier - haier_id: haier_ac self_cleaning: name: Haier start self cleaning steri_cleaning: @@ -104,7 +101,6 @@ button: text_sensor: - platform: haier - haier_id: haier_ac appliance_name: name: Haier appliance name cleaning_status: diff --git a/tests/components/haier/test.esp32-c3-idf.yaml b/tests/components/haier/test.esp32-c3-idf.yaml index fed573bd1d..0053220669 100644 --- a/tests/components/haier/test.esp32-c3-idf.yaml +++ b/tests/components/haier/test.esp32-c3-idf.yaml @@ -54,7 +54,6 @@ climate: sensor: - platform: haier - haier_id: haier_ac outdoor_temperature: name: Haier outdoor temperature humidity: @@ -80,7 +79,6 @@ sensor: binary_sensor: - platform: haier - haier_id: haier_ac compressor_status: name: Haier Outdoor Compressor Status defrost_status: @@ -96,7 +94,6 @@ binary_sensor: button: - platform: haier - haier_id: haier_ac self_cleaning: name: Haier start self cleaning steri_cleaning: @@ -104,7 +101,6 @@ button: text_sensor: - platform: haier - haier_id: haier_ac appliance_name: name: Haier appliance name cleaning_status: diff --git a/tests/components/haier/test.esp32-idf.yaml b/tests/components/haier/test.esp32-idf.yaml index efff532d25..54e384f3ce 100644 --- a/tests/components/haier/test.esp32-idf.yaml +++ b/tests/components/haier/test.esp32-idf.yaml @@ -54,7 +54,6 @@ climate: sensor: - platform: haier - haier_id: haier_ac outdoor_temperature: name: Haier outdoor temperature humidity: @@ -80,7 +79,6 @@ sensor: binary_sensor: - platform: haier - haier_id: haier_ac compressor_status: name: Haier Outdoor Compressor Status defrost_status: @@ -96,7 +94,6 @@ binary_sensor: button: - platform: haier - haier_id: haier_ac self_cleaning: name: Haier start self cleaning steri_cleaning: @@ -104,7 +101,6 @@ button: text_sensor: - platform: haier - haier_id: haier_ac appliance_name: name: Haier appliance name cleaning_status: diff --git a/tests/components/haier/test.esp8266-ard.yaml b/tests/components/haier/test.esp8266-ard.yaml index fed573bd1d..0053220669 100644 --- a/tests/components/haier/test.esp8266-ard.yaml +++ b/tests/components/haier/test.esp8266-ard.yaml @@ -54,7 +54,6 @@ climate: sensor: - platform: haier - haier_id: haier_ac outdoor_temperature: name: Haier outdoor temperature humidity: @@ -80,7 +79,6 @@ sensor: binary_sensor: - platform: haier - haier_id: haier_ac compressor_status: name: Haier Outdoor Compressor Status defrost_status: @@ -96,7 +94,6 @@ binary_sensor: button: - platform: haier - haier_id: haier_ac self_cleaning: name: Haier start self cleaning steri_cleaning: @@ -104,7 +101,6 @@ button: text_sensor: - platform: haier - haier_id: haier_ac appliance_name: name: Haier appliance name cleaning_status: diff --git a/tests/components/haier/test.rp2040-ard.yaml b/tests/components/haier/test.rp2040-ard.yaml index fed573bd1d..0053220669 100644 --- a/tests/components/haier/test.rp2040-ard.yaml +++ b/tests/components/haier/test.rp2040-ard.yaml @@ -54,7 +54,6 @@ climate: sensor: - platform: haier - haier_id: haier_ac outdoor_temperature: name: Haier outdoor temperature humidity: @@ -80,7 +79,6 @@ sensor: binary_sensor: - platform: haier - haier_id: haier_ac compressor_status: name: Haier Outdoor Compressor Status defrost_status: @@ -96,7 +94,6 @@ binary_sensor: button: - platform: haier - haier_id: haier_ac self_cleaning: name: Haier start self cleaning steri_cleaning: @@ -104,7 +101,6 @@ button: text_sensor: - platform: haier - haier_id: haier_ac appliance_name: name: Haier appliance name cleaning_status: From b1868123db2107a84ad093a6776e4f096829ba1a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 24 Jun 2024 04:21:28 -0700 Subject: [PATCH 1954/2607] fix potential hang (#6976) Co-authored-by: Samuel Sieb --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index b4e69e975a..36eaf2160a 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -94,13 +94,15 @@ bool HOT IRAM_ATTR GPIOOneWireBus::read_bit_() { // measure from start value directly, to get best accurate timing no matter // how long pin_mode/delayMicroseconds took - delayMicroseconds(12 - (micros() - start)); + uint32_t now = micros(); + if (now - start < 12) + delayMicroseconds(12 - (now - start)); // sample bus to read bit from peer bool r = pin_.digital_read(); // read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked - uint32_t now = micros(); + now = micros(); if (now - start < 60) delayMicroseconds(60 - (now - start)); From 78450da6f33366735aeb8da0521c2791160ac12d Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Tue, 25 Jun 2024 00:04:58 +0400 Subject: [PATCH 1955/2607] [midea] fix fan speed compatibility with some models (#6978) --- esphome/components/midea/climate.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/midea/climate.py b/esphome/components/midea/climate.py index 83540a061a..e5612796a3 100644 --- a/esphome/components/midea/climate.py +++ b/esphome/components/midea/climate.py @@ -293,4 +293,4 @@ async def to_code(config): if CONF_HUMIDITY_SETPOINT in config: sens = await sensor.new_sensor(config[CONF_HUMIDITY_SETPOINT]) cg.add(var.set_humidity_setpoint_sensor(sens)) - cg.add_library("dudanov/MideaUART", "1.1.8") + cg.add_library("dudanov/MideaUART", "1.1.9") diff --git a/platformio.ini b/platformio.ini index ee82dee243..e106114ff6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -64,7 +64,7 @@ lib_deps = freekode/TM1651@1.0.1 ; tm1651 glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr - dudanov/MideaUART@1.1.8 ; midea + dudanov/MideaUART@1.1.9 ; midea tonia/HeatpumpIR@1.0.23 ; heatpumpir build_flags = ${common.build_flags} From a21dab334c48da775189085d7206fe88ecdaa3a5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:09:00 +1200 Subject: [PATCH 1956/2607] [core] Fix package merging with lists of primitives (#6952) --- esphome/config_helpers.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index b5e0b26143..54242bc259 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -58,17 +58,21 @@ def merge_config(full_old, full_new): ids = { v_id: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, str) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, str) } extend_ids = { v_id.value: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, Extend) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, Extend) } ids_to_delete = [] for v in new: - if new_id := v.get(CONF_ID): + if isinstance(v, dict) and (new_id := v.get(CONF_ID)): if isinstance(new_id, Extend): new_id = new_id.value if new_id in ids: From 7dbc20b776c56c6cce910e25fe6f12871e9d9b47 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:59:52 +1200 Subject: [PATCH 1957/2607] [update] Set entity_category to config & Publish state to logs (#6954) --- esphome/components/update/__init__.py | 5 ++++ esphome/components/update/update_entity.cpp | 26 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ea1cf778b6..20a9373a06 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -4,11 +4,13 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( CONF_DEVICE_CLASS, + CONF_ENTITY_CATEGORY, CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, + ENTITY_CATEGORY_CONFIG, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -41,6 +43,9 @@ UPDATE_SCHEMA = ( cv.Optional(CONF_ON_UPDATE_AVAILABLE): automation.validate_automation( single=True ), + cv.Optional( + CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG + ): cv.entity_category, } ) ) diff --git a/esphome/components/update/update_entity.cpp b/esphome/components/update/update_entity.cpp index 501cb6635f..ed9a0480d8 100644 --- a/esphome/components/update/update_entity.cpp +++ b/esphome/components/update/update_entity.cpp @@ -1,9 +1,35 @@ #include "update_entity.h" +#include "esphome/core/log.h" + namespace esphome { namespace update { +static const char *const TAG = "update"; + void UpdateEntity::publish_state() { + ESP_LOGD(TAG, "'%s' - Publishing:", this->name_.c_str()); + ESP_LOGD(TAG, " Current Version: %s", this->update_info_.current_version.c_str()); + + if (!this->update_info_.md5.empty()) { + ESP_LOGD(TAG, " Latest Version: %s", this->update_info_.latest_version.c_str()); + } + if (!this->update_info_.firmware_url.empty()) { + ESP_LOGD(TAG, " Firmware URL: %s", this->update_info_.firmware_url.c_str()); + } + + ESP_LOGD(TAG, " Title: %s", this->update_info_.title.c_str()); + if (!this->update_info_.summary.empty()) { + ESP_LOGD(TAG, " Summary: %s", this->update_info_.summary.c_str()); + } + if (!this->update_info_.release_url.empty()) { + ESP_LOGD(TAG, " Release URL: %s", this->update_info_.release_url.c_str()); + } + + if (this->update_info_.has_progress) { + ESP_LOGD(TAG, " Progress: %.0f%%", this->update_info_.progress); + } + this->has_state_ = true; this->state_callback_.call(); } From ae2962259ec004777ecfb96cd409bba85b56e0d4 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Fri, 21 Jun 2024 17:18:43 -0400 Subject: [PATCH 1958/2607] Fix infinite loop in http_request for ESP-IDF. (#6963) --- esphome/components/http_request/http_request_idf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 138e0438f4..d6fac7a133 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -90,7 +90,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin int write_left = body_len; int write_index = 0; const char *buf = body.c_str(); - while (body_len > 0) { + while (write_left > 0) { int written = esp_http_client_write(client, buf + write_index, write_left); if (written < 0) { err = ESP_FAIL; From 96d63de292eba3fa4c6c820faf1b482e0fff205e Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Fri, 21 Jun 2024 17:28:11 -0400 Subject: [PATCH 1959/2607] ESP-IDF 4.x expects seconds for esp_task_wdt_init(), not milliseconds. (#6964) --- esphome/components/http_request/watchdog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/http_request/watchdog.cpp b/esphome/components/http_request/watchdog.cpp index e609feb4dd..a8519c59ed 100644 --- a/esphome/components/http_request/watchdog.cpp +++ b/esphome/components/http_request/watchdog.cpp @@ -46,7 +46,7 @@ void WatchdogManager::set_timeout_(uint32_t timeout_ms) { }; esp_task_wdt_reconfigure(&wdt_config); #else - esp_task_wdt_init(timeout_ms, true); + esp_task_wdt_init(timeout_ms / 1000, true); #endif // ESP_IDF_VERSION_MAJOR #endif // USE_ESP32 From 0d3cf5cb7809e13de16c5edb75c0437705efa4ce Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sat, 22 Jun 2024 04:57:27 -0700 Subject: [PATCH 1960/2607] Onewire (#6967) * retry scan * setup pin and log retries * fix retries * remove retries --------- Co-authored-by: Samuel Sieb --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index 34c2cf3c29..b4e69e975a 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -9,6 +9,10 @@ static const char *const TAG = "gpio.one_wire"; void GPIOOneWireBus::setup() { ESP_LOGCONFIG(TAG, "Setting up 1-wire bus..."); + this->t_pin_->setup(); + // clear bus with 480µs high, otherwise initial reset in search might fail + this->t_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + delayMicroseconds(480); this->search(); } From e39961f7f1c329ae70422ded669b548c43226d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Mon, 24 Jun 2024 06:32:20 +0200 Subject: [PATCH 1961/2607] [http_request] memory leak fix (#6973) --- esphome/components/http_request/http_request.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index df6bc7dea7..6281adddb6 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -149,6 +149,7 @@ template class HttpRequestSendAction : public Action { } response_body.reserve(read_index); response_body.assign((char *) buf, read_index); + allocator.deallocate(buf, max_length); } } From 5bd5b777a6ff949f539b9e58ed537b223e40020e Mon Sep 17 00:00:00 2001 From: Brian Kaufman Date: Sun, 23 Jun 2024 21:54:30 -0700 Subject: [PATCH 1962/2607] Await cg.get_variable in Update component (#6974) --- esphome/components/update/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index 20a9373a06..45bf082fa4 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -69,7 +69,7 @@ async def setup_update_core_(var, config): await mqtt.register_mqtt_component(mqtt_, config) if web_server_id_config := config.get(CONF_WEB_SERVER_ID): - web_server_ = cg.get_variable(web_server_id_config) + web_server_ = await cg.get_variable(web_server_id_config) web_server.add_entity_to_sorting_list(web_server_, var, config) From c5aae8ee254f3e16ed204912457637ba62743818 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 24 Jun 2024 04:21:28 -0700 Subject: [PATCH 1963/2607] fix potential hang (#6976) Co-authored-by: Samuel Sieb --- esphome/components/gpio/one_wire/gpio_one_wire.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index b4e69e975a..36eaf2160a 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -94,13 +94,15 @@ bool HOT IRAM_ATTR GPIOOneWireBus::read_bit_() { // measure from start value directly, to get best accurate timing no matter // how long pin_mode/delayMicroseconds took - delayMicroseconds(12 - (micros() - start)); + uint32_t now = micros(); + if (now - start < 12) + delayMicroseconds(12 - (now - start)); // sample bus to read bit from peer bool r = pin_.digital_read(); // read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked - uint32_t now = micros(); + now = micros(); if (now - start < 60) delayMicroseconds(60 - (now - start)); From a6e1ef2dd144dff244800fa00624285c8bd6e70e Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Tue, 25 Jun 2024 00:04:58 +0400 Subject: [PATCH 1964/2607] [midea] fix fan speed compatibility with some models (#6978) --- esphome/components/midea/climate.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/midea/climate.py b/esphome/components/midea/climate.py index 83540a061a..e5612796a3 100644 --- a/esphome/components/midea/climate.py +++ b/esphome/components/midea/climate.py @@ -293,4 +293,4 @@ async def to_code(config): if CONF_HUMIDITY_SETPOINT in config: sens = await sensor.new_sensor(config[CONF_HUMIDITY_SETPOINT]) cg.add(var.set_humidity_setpoint_sensor(sens)) - cg.add_library("dudanov/MideaUART", "1.1.8") + cg.add_library("dudanov/MideaUART", "1.1.9") diff --git a/platformio.ini b/platformio.ini index 6b34b2f05d..14e9ea9fc6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -64,7 +64,7 @@ lib_deps = freekode/TM1651@1.0.1 ; tm1651 glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr - dudanov/MideaUART@1.1.8 ; midea + dudanov/MideaUART@1.1.9 ; midea tonia/HeatpumpIR@1.0.23 ; heatpumpir build_flags = ${common.build_flags} From 09a947beaa45b45f71dbfb3aac06de2b138abebf Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:57:38 +1200 Subject: [PATCH 1965/2607] Bump version to 2024.6.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 3b3bdd1a17..cde917ca98 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.1" +__version__ = "2024.6.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 11b8e2e1af4af190f407cdd0922f778899e19412 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 25 Jun 2024 16:43:30 +1200 Subject: [PATCH 1966/2607] [core] Add script to extract actions, conditions, and pin_providers (#6929) --- script/extract_automations.py | 25 +++++++++++++++++++++++ script/list-components.py | 38 ++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 18 deletions(-) create mode 100755 script/extract_automations.py diff --git a/script/extract_automations.py b/script/extract_automations.py new file mode 100755 index 0000000000..943eb7110a --- /dev/null +++ b/script/extract_automations.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import json + +from helpers import git_ls_files + +from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY +from esphome.pins import PIN_SCHEMA_REGISTRY + +list_components = __import__("list-components") + + +if __name__ == "__main__": + files = git_ls_files() + files = filter(list_components.filter_component_files, files) + + components = list_components.get_components(files, True) + + dump = { + "actions": sorted(list(ACTION_REGISTRY.keys())), + "conditions": sorted(list(CONDITION_REGISTRY.keys())), + "pin_providers": sorted(list(PIN_SCHEMA_REGISTRY.keys())), + } + + print(json.dumps(dump, indent=2)) diff --git a/script/list-components.py b/script/list-components.py index 5b5fa5811f..4eccdbf96c 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -50,6 +50,7 @@ def create_components_graph(): {KEY_TARGET_FRAMEWORK: "arduino", KEY_TARGET_PLATFORM: None}, {KEY_TARGET_FRAMEWORK: "esp-idf", KEY_TARGET_PLATFORM: None}, {KEY_TARGET_FRAMEWORK: None, KEY_TARGET_PLATFORM: PLATFORM_ESP32}, + {KEY_TARGET_FRAMEWORK: None, KEY_TARGET_PLATFORM: PLATFORM_ESP8266}, ] CORE.data[KEY_CORE] = TARGET_CONFIGURATIONS[0] @@ -119,6 +120,23 @@ def find_children_of_component(components_graph, component_name, depth=0): return list(set(children)) +def get_components(files: list[str], get_dependencies: bool = False): + components = extract_component_names_array_from_files_array(files) + + if get_dependencies: + components_graph = create_components_graph() + + all_components = components.copy() + for c in components: + all_components.extend(find_children_of_component(components_graph, c)) + # Remove duplicate values + all_changed_components = list(set(all_components)) + + return sorted(all_changed_components) + + return sorted(components) + + def main(): parser = argparse.ArgumentParser() parser.add_argument( @@ -142,24 +160,8 @@ def main(): changed = changed_files() files = [f for f in files if f in changed] - components = extract_component_names_array_from_files_array(files) - - if args.changed: - components_graph = create_components_graph() - - all_changed_components = components.copy() - for c in components: - all_changed_components.extend( - find_children_of_component(components_graph, c) - ) - # Remove duplicate values - all_changed_components = list(set(all_changed_components)) - - for c in sorted(all_changed_components): - print(c) - else: - for c in sorted(components): - print(c) + for c in get_components(files, args.changed): + print(c) if __name__ == "__main__": From 8a25bedaf9323c6e1f62a9324b46344d9292ed24 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:42:55 +1200 Subject: [PATCH 1967/2607] [external_files] Move common ``download_content`` function to ``external_files.py`` (#6982) --- esphome/components/font/__init__.py | 30 ++------------------------- esphome/components/image/__init__.py | 31 ++-------------------------- esphome/external_files.py | 26 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 57 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index b3a5beb199..7e4674ffda 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -17,7 +17,6 @@ from esphome.helpers import ( cpp_string_escape, ) from esphome.const import ( - __version__, CONF_FAMILY, CONF_FILE, CONF_GLYPHS, @@ -185,31 +184,6 @@ def get_font_path(value, type) -> Path: return None -def download_content(url: str, path: Path) -> None: - if not external_files.has_remote_file_changed(url, path): - _LOGGER.debug("Remote file has not changed %s", url) - return - - _LOGGER.debug( - "Remote file has changed, downloading from %s to %s", - url, - path, - ) - - try: - req = requests.get( - url, - timeout=external_files.NETWORK_TIMEOUT, - headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, - ) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise cv.Invalid(f"Could not download from {url}: {e}") - - path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(req.content) - - def download_gfont(value): name = ( f"{value[CONF_FAMILY]}:ital,wght@{int(value[CONF_ITALIC])},{value[CONF_WEIGHT]}" @@ -236,7 +210,7 @@ def download_gfont(value): ttf_url = match.group(1) _LOGGER.debug("download_gfont: ttf_url=%s", ttf_url) - download_content(ttf_url, path) + external_files.download_content(ttf_url, path) return value @@ -244,7 +218,7 @@ def download_web_font(value): url = value[CONF_URL] path = get_font_path(value, TYPE_WEB) - download_content(url, path) + external_files.download_content(url, path) _LOGGER.debug("download_web_font: path=%s", path) return value diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index c275136427..e5a205f1e0 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -6,7 +6,6 @@ import hashlib import io from pathlib import Path import re -import requests from magic import Magic from esphome import core @@ -15,7 +14,6 @@ from esphome import external_files import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( - __version__, CONF_DITHER, CONF_FILE, CONF_ICON, @@ -75,31 +73,6 @@ def compute_local_image_path(value: dict) -> Path: return base_dir / key -def download_content(url: str, path: Path) -> None: - if not external_files.has_remote_file_changed(url, path): - _LOGGER.debug("Remote file has not changed %s", url) - return - - _LOGGER.debug( - "Remote file has changed, downloading from %s to %s", - url, - path, - ) - - try: - req = requests.get( - url, - timeout=IMAGE_DOWNLOAD_TIMEOUT, - headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, - ) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise cv.Invalid(f"Could not download from {url}: {e}") - - path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(req.content) - - def download_mdi(value): validate_cairosvg_installed(value) @@ -108,7 +81,7 @@ def download_mdi(value): url = f"https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg/{mdi_id}.svg" - download_content(url, path) + external_files.download_content(url, path, IMAGE_DOWNLOAD_TIMEOUT) return value @@ -117,7 +90,7 @@ def download_image(value): url = value[CONF_URL] path = compute_local_image_path(value) - download_content(url, path) + external_files.download_content(url, path, IMAGE_DOWNLOAD_TIMEOUT) return value diff --git a/esphome/external_files.py b/esphome/external_files.py index a1422d02b1..f8eb1dcabe 100644 --- a/esphome/external_files.py +++ b/esphome/external_files.py @@ -7,6 +7,7 @@ from datetime import datetime import requests import esphome.config_validation as cv from esphome.core import CORE, TimePeriodSeconds +from esphome.const import __version__ _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@landonr"] @@ -75,3 +76,28 @@ def compute_local_file_dir(domain: str) -> Path: base_directory.mkdir(parents=True, exist_ok=True) return base_directory + + +def download_content(url: str, path: Path, timeout=NETWORK_TIMEOUT) -> None: + if not has_remote_file_changed(url, path): + _LOGGER.debug("Remote file has not changed %s", url) + return + + _LOGGER.debug( + "Remote file has changed, downloading from %s to %s", + url, + path, + ) + + try: + req = requests.get( + url, + timeout=timeout, + headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, + ) + req.raise_for_status() + except requests.exceptions.RequestException as e: + raise cv.Invalid(f"Could not download from {url}: {e}") + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(req.content) From c9a0daf4b6435533bf14594c0b579f829719aa15 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Tue, 25 Jun 2024 10:05:37 +0200 Subject: [PATCH 1968/2607] Do not build mDNS when mDNS is disabled via yaml (#6979) --- esphome/components/mdns/__init__.py | 6 +++--- esphome/components/mdns/mdns_component.cpp | 4 +++- esphome/components/mdns/mdns_component.h | 4 +++- esphome/components/mdns/mdns_esp32.cpp | 3 ++- esphome/components/mdns/mdns_esp8266.cpp | 3 ++- esphome/components/mdns/mdns_host.cpp | 3 ++- esphome/components/mdns/mdns_libretiny.cpp | 3 ++- esphome/components/mdns/mdns_rp2040.cpp | 3 ++- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 82cf087fdc..fb90986314 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -74,6 +74,9 @@ def mdns_service( @coroutine_with_priority(55.0) async def to_code(config): + if config[CONF_DISABLED] is True: + return + if CORE.using_arduino: if CORE.is_esp32: cg.add_library("ESPmDNS", None) @@ -92,9 +95,6 @@ async def to_code(config): path="components/mdns", ) - if config[CONF_DISABLED]: - return - cg.add_define("USE_MDNS") var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index e2e562670b..2fc09330cd 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -1,5 +1,6 @@ -#include "mdns_component.h" #include "esphome/core/defines.h" +#ifdef USE_MDNS +#include "mdns_component.h" #include "esphome/core/version.h" #include "esphome/core/application.h" #include "esphome/core/log.h" @@ -125,3 +126,4 @@ void MDNSComponent::dump_config() { } // namespace mdns } // namespace esphome +#endif diff --git a/esphome/components/mdns/mdns_component.h b/esphome/components/mdns/mdns_component.h index b2cb10db62..dfb5b72292 100644 --- a/esphome/components/mdns/mdns_component.h +++ b/esphome/components/mdns/mdns_component.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_MDNS #include #include #include "esphome/core/component.h" @@ -46,3 +47,4 @@ class MDNSComponent : public Component { } // namespace mdns } // namespace esphome +#endif diff --git a/esphome/components/mdns/mdns_esp32.cpp b/esphome/components/mdns/mdns_esp32.cpp index 6081c96637..8006eb27f1 100644 --- a/esphome/components/mdns/mdns_esp32.cpp +++ b/esphome/components/mdns/mdns_esp32.cpp @@ -1,4 +1,5 @@ -#ifdef USE_ESP32 +#include "esphome/core/defines.h" +#if defined(USE_ESP32) && defined(USE_MDNS) #include #include diff --git a/esphome/components/mdns/mdns_esp8266.cpp b/esphome/components/mdns/mdns_esp8266.cpp index 5ff1b86341..7b6e7ec448 100644 --- a/esphome/components/mdns/mdns_esp8266.cpp +++ b/esphome/components/mdns/mdns_esp8266.cpp @@ -1,4 +1,5 @@ -#if defined(USE_ESP8266) && defined(USE_ARDUINO) +#include "esphome/core/defines.h" +#if defined(USE_ESP8266) && defined(USE_ARDUINO) && defined(USE_MDNS) #include #include "esphome/components/network/ip_address.h" diff --git a/esphome/components/mdns/mdns_host.cpp b/esphome/components/mdns/mdns_host.cpp index 3f89146f02..78767ed136 100644 --- a/esphome/components/mdns/mdns_host.cpp +++ b/esphome/components/mdns/mdns_host.cpp @@ -1,4 +1,5 @@ -#ifdef USE_HOST +#include "esphome/core/defines.h" +#if defined(USE_HOST) && defined(USE_MDNS) #include "esphome/components/network/ip_address.h" #include "esphome/components/network/util.h" diff --git a/esphome/components/mdns/mdns_libretiny.cpp b/esphome/components/mdns/mdns_libretiny.cpp index ccb79c88b9..c9a9a289dd 100644 --- a/esphome/components/mdns/mdns_libretiny.cpp +++ b/esphome/components/mdns/mdns_libretiny.cpp @@ -1,4 +1,5 @@ -#ifdef USE_LIBRETINY +#include "esphome/core/defines.h" +#if defined(USE_LIBRETINY) && defined(USE_MDNS) #include "esphome/components/network/ip_address.h" #include "esphome/components/network/util.h" diff --git a/esphome/components/mdns/mdns_rp2040.cpp b/esphome/components/mdns/mdns_rp2040.cpp index 56afd6f5e1..89e668ee59 100644 --- a/esphome/components/mdns/mdns_rp2040.cpp +++ b/esphome/components/mdns/mdns_rp2040.cpp @@ -1,4 +1,5 @@ -#ifdef USE_RP2040 +#include "esphome/core/defines.h" +#if defined(USE_RP2040) && defined(USE_MDNS) #include "esphome/components/network/ip_address.h" #include "esphome/components/network/util.h" From 481cf7384ae081e2cabe568cba31a6a6dde68754 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:07:19 +1200 Subject: [PATCH 1969/2607] [safe_mode] Set safe mode core data in disabled cases (#6983) --- esphome/components/safe_mode/__init__.py | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index 881937890d..185c0e70b1 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -56,21 +56,20 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(50.0) async def to_code(config): - if config[CONF_DISABLED]: - return + if not config[CONF_DISABLED]: + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) + for conf in config.get(CONF_ON_SAFE_MODE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) - for conf in config.get(CONF_ON_SAFE_MODE, []): - trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - await automation.build_automation(trigger, [], conf) + condition = var.should_enter_safe_mode( + config[CONF_NUM_ATTEMPTS], + config[CONF_REBOOT_TIMEOUT], + config[CONF_BOOT_IS_GOOD_AFTER], + ) + cg.add(RawExpression(f"if ({condition}) return")) - condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], - config[CONF_REBOOT_TIMEOUT], - config[CONF_BOOT_IS_GOOD_AFTER], - ) - cg.add(RawExpression(f"if ({condition}) return")) CORE.data[CONF_SAFE_MODE] = {} CORE.data[CONF_SAFE_MODE][KEY_PAST_SAFE_MODE] = True From fb9844463b53d3aee6fd5e67bd5f71a7568c6a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 25 Jun 2024 11:08:57 +0200 Subject: [PATCH 1970/2607] Bump HeatpumpIR and IRremoteESP8266 (#6948) --- esphome/components/heatpumpir/climate.py | 10 ++++++++-- esphome/components/heatpumpir/heatpumpir.cpp | 6 ++++++ esphome/components/heatpumpir/heatpumpir.h | 6 ++++++ platformio.ini | 6 +++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index 8af4ca590f..b86d405b7e 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -34,6 +34,7 @@ PROTOCOLS = { "greeyan": Protocol.PROTOCOL_GREEYAN, "greeyac": Protocol.PROTOCOL_GREEYAC, "greeyt": Protocol.PROTOCOL_GREEYT, + "greeyap": Protocol.PROTOCOL_GREEYAP, "hisense_aud": Protocol.PROTOCOL_HISENSE_AUD, "hitachi": Protocol.PROTOCOL_HITACHI, "hyundai": Protocol.PROTOCOL_HYUNDAI, @@ -61,6 +62,11 @@ PROTOCOLS = { "toshiba_daiseikai": Protocol.PROTOCOL_TOSHIBA_DAISEIKAI, "toshiba": Protocol.PROTOCOL_TOSHIBA, "zhlt01": Protocol.PROTOCOL_ZHLT01, + "nibe": Protocol.PROTOCOL_NIBE, + "carrier_qlima_1": Protocol.PROTOCOL_QLIMA_1, + "carrier_qlima_2": Protocol.PROTOCOL_QLIMA_2, + "samsung_aqv12msan": Protocol.PROTOCOL_SAMSUNG_AQV12MSAN, + "zhjg01": Protocol.PROTOCOL_ZHJG01, } CONF_HORIZONTAL_DEFAULT = "horizontal_default" @@ -116,7 +122,7 @@ def to_code(config): cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE])) cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) - cg.add_library("tonia/HeatpumpIR", "1.0.23") + cg.add_library("tonia/HeatpumpIR", "1.0.26") if CORE.is_esp8266 or CORE.is_esp32: - cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.4") + cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.6") diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index 5e7237b63c..22a5779c8d 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -28,6 +28,7 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_GREEYAN, []() { return new GreeYANHeatpumpIR(); }}, // NOLINT {PROTOCOL_GREEYAC, []() { return new GreeYACHeatpumpIR(); }}, // NOLINT {PROTOCOL_GREEYT, []() { return new GreeYTHeatpumpIR(); }}, // NOLINT + {PROTOCOL_GREEYAP, []() { return new GreeYAPHeatpumpIR(); }}, // NOLINT {PROTOCOL_HISENSE_AUD, []() { return new HisenseHeatpumpIR(); }}, // NOLINT {PROTOCOL_HITACHI, []() { return new HitachiHeatpumpIR(); }}, // NOLINT {PROTOCOL_HYUNDAI, []() { return new HyundaiHeatpumpIR(); }}, // NOLINT @@ -55,6 +56,11 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_TOSHIBA_DAISEIKAI, []() { return new ToshibaDaiseikaiHeatpumpIR(); }}, // NOLINT {PROTOCOL_TOSHIBA, []() { return new ToshibaHeatpumpIR(); }}, // NOLINT {PROTOCOL_ZHLT01, []() { return new ZHLT01HeatpumpIR(); }}, // NOLINT + {PROTOCOL_NIBE, []() { return new NibeHeatpumpIR(); }}, // NOLINT + {PROTOCOL_QLIMA_1, []() { return new Qlima1HeatpumpIR(); }}, // NOLINT + {PROTOCOL_QLIMA_2, []() { return new Qlima2HeatpumpIR(); }}, // NOLINT + {PROTOCOL_SAMSUNG_AQV12MSAN, []() { return new SamsungAQV12MSANHeatpumpIR(); }}, // NOLINT + {PROTOCOL_ZHJG01, []() { return new ZHJG01HeatpumpIR(); }}, // NOLINT }; void HeatpumpIRClimate::setup() { diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index e8b03b4c26..0e6ea2218f 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -28,6 +28,7 @@ enum Protocol { PROTOCOL_GREEYAN, PROTOCOL_GREEYAC, PROTOCOL_GREEYT, + PROTOCOL_GREEYAP, PROTOCOL_HISENSE_AUD, PROTOCOL_HITACHI, PROTOCOL_HYUNDAI, @@ -55,6 +56,11 @@ enum Protocol { PROTOCOL_TOSHIBA_DAISEIKAI, PROTOCOL_TOSHIBA, PROTOCOL_ZHLT01, + PROTOCOL_NIBE, + PROTOCOL_QLIMA_1, + PROTOCOL_QLIMA_2, + PROTOCOL_SAMSUNG_AQV12MSAN, + PROTOCOL_ZHJG01, }; // Simple enum to represent horizontal directios diff --git a/platformio.ini b/platformio.ini index e106114ff6..e2e66bf672 100644 --- a/platformio.ini +++ b/platformio.ini @@ -65,7 +65,7 @@ lib_deps = glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr dudanov/MideaUART@1.1.9 ; midea - tonia/HeatpumpIR@1.0.23 ; heatpumpir + tonia/HeatpumpIR@1.0.26 ; heatpumpir build_flags = ${common.build_flags} -DUSE_ARDUINO @@ -93,7 +93,7 @@ lib_deps = ESP8266HTTPClient ; http_request (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) - crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir + crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:arduino.build_flags} @@ -123,7 +123,7 @@ lib_deps = ESPmDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio - crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir + crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.1 ; wireguard build_flags = ${common:arduino.build_flags} From d8a5c1ea0c440ff488a2b6c1cd84f8440ab81e51 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 25 Jun 2024 15:57:15 -0500 Subject: [PATCH 1971/2607] [ota-esphome] Validate for multiple esphome ota instances (#6984) --- esphome/components/esphome/ota/__init__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index c5903974c2..88e729f230 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,10 +1,14 @@ import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent from esphome.const import ( + CONF_ESPHOME, CONF_ID, CONF_NUM_ATTEMPTS, + CONF_OTA, CONF_PASSWORD, + CONF_PLATFORM, CONF_PORT, CONF_REBOOT_TIMEOUT, CONF_SAFE_MODE, @@ -21,6 +25,19 @@ esphome = cg.esphome_ns.namespace("esphome") ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) +def ota_esphome_final_validate(config): + fconf = fv.full_config.get()[CONF_OTA] + used_ports = [] + for ota_conf in fconf: + if ota_conf.get(CONF_PLATFORM) == CONF_ESPHOME: + if (plat_port := ota_conf.get(CONF_PORT)) not in used_ports: + used_ports.append(plat_port) + else: + raise cv.Invalid( + f"Only one instance of the {CONF_ESPHOME} {CONF_OTA} {CONF_PLATFORM} is allowed per port. Note that this error may result from OTA specified in packages" + ) + + CONFIG_SCHEMA = ( cv.Schema( { @@ -50,6 +67,8 @@ CONFIG_SCHEMA = ( .extend(cv.COMPONENT_SCHEMA) ) +FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate + @coroutine_with_priority(52.0) async def to_code(config): From 0179358f9cbb212d30627999a2f7233ff18e12ea Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 25 Jun 2024 19:50:54 -0400 Subject: [PATCH 1972/2607] Improve 'body' handling in http_request on_response triggers (#6968) --- esphome/codegen.py | 1 + esphome/components/http_request/__init__.py | 2 +- .../components/http_request/http_request.h | 19 ++++++++++++++----- esphome/cpp_types.py | 1 + 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/esphome/codegen.py b/esphome/codegen.py index b552490129..6b000b53a1 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -60,6 +60,7 @@ from esphome.cpp_types import ( # noqa std_ns, std_shared_ptr, std_string, + std_string_ref, std_vector, uint8, uint16, diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 37487ec9a7..ade7024bed 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -257,7 +257,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args): trigger, [ (cg.std_shared_ptr.template(HttpContainer), "response"), - (cg.std_string, "body"), + (cg.std_string_ref, "body"), ], conf, ) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 6281adddb6..82b7392648 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -43,10 +43,10 @@ class HttpContainer : public Parented { bool secure_{false}; }; -class HttpRequestResponseTrigger : public Trigger, std::string> { +class HttpRequestResponseTrigger : public Trigger, std::string &> { public: - void process(std::shared_ptr container, std::string response_body) { - this->trigger(std::move(container), std::move(response_body)); + void process(std::shared_ptr container, std::string &response_body) { + this->trigger(std::move(container), response_body); } }; @@ -153,8 +153,17 @@ template class HttpRequestSendAction : public Action { } } - for (auto *trigger : this->response_triggers_) { - trigger->process(container, response_body); + if (this->response_triggers_.size() == 1) { + // if there is only one trigger, no need to copy the response body + this->response_triggers_[0]->process(container, response_body); + } else { + for (auto *trigger : this->response_triggers_) { + // with multiple triggers, pass a copy of the response body to each + // one so that modifications made in one trigger are not visible to + // the others + auto response_body_copy = std::string(response_body); + trigger->process(container, response_body_copy); + } } container->end(); } diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index bd79d3b2f9..dab993f87f 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -10,6 +10,7 @@ int_ = global_ns.namespace("int") std_ns = global_ns.namespace("std") std_shared_ptr = std_ns.class_("shared_ptr") std_string = std_ns.class_("string") +std_string_ref = std_ns.namespace("string &") std_vector = std_ns.class_("vector") uint8 = global_ns.namespace("uint8_t") uint16 = global_ns.namespace("uint16_t") From bc26de2d68283d0d743a1e5a08921abfa6c00820 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 25 Jun 2024 16:54:02 -0700 Subject: [PATCH 1973/2607] [ds1307] Initialize uninitialized struct members (#6985) --- esphome/components/ds1307/ds1307.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/esphome/components/ds1307/ds1307.cpp b/esphome/components/ds1307/ds1307.cpp index 472ccc7a9a..9df8a1d373 100644 --- a/esphome/components/ds1307/ds1307.cpp +++ b/esphome/components/ds1307/ds1307.cpp @@ -37,14 +37,18 @@ void DS1307Component::read_time() { ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); return; } - ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), - .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), - .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), - .day_of_week = uint8_t(ds1307_.reg.weekday), - .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), - .day_of_year = 1, // ignored by recalc_timestamp_utc(false) - .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), - .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)}; + ESPTime rtc_time{ + .second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), + .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), + .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), + .day_of_week = uint8_t(ds1307_.reg.weekday), + .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), + .day_of_year = 1, // ignored by recalc_timestamp_utc(false) + .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), + .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000), + .is_dst = false, // not used + .timestamp = 0 // overwritten by recalc_timestamp_utc(false) + }; rtc_time.recalc_timestamp_utc(false); if (!rtc_time.is_valid()) { ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); From cc4f1c667ed15f1962c6bacaa7b30c0a7f329b43 Mon Sep 17 00:00:00 2001 From: Petapton <14984292+Petapton@users.noreply.github.com> Date: Wed, 26 Jun 2024 02:08:16 +0200 Subject: [PATCH 1974/2607] Fix float encoding in modbus server (#6986) --- esphome/components/modbus_controller/modbus_controller.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 9f73988b03..29d3137603 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -116,7 +116,8 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %0.1f.", server_register->address, static_cast(server_register->value_type), server_register->register_count, value); - number_to_payload(sixteen_bit_response, value, server_register->value_type); + std::vector payload = float_to_payload(value, server_register->value_type); + sixteen_bit_response.insert(sixteen_bit_response.end(), payload.cbegin(), payload.cend()); current_address += server_register->register_count; found = true; break; From 91766afb64e804db97cc03f8ba6174e13968f742 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 26 Jun 2024 00:27:07 -0700 Subject: [PATCH 1975/2607] [dallas_temp] fix ds18s20 temp calc (#6988) --- .../components/dallas_temp/dallas_temp.cpp | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/esphome/components/dallas_temp/dallas_temp.cpp b/esphome/components/dallas_temp/dallas_temp.cpp index fe7c9a95ea..ae567d6a76 100644 --- a/esphome/components/dallas_temp/dallas_temp.cpp +++ b/esphome/components/dallas_temp/dallas_temp.cpp @@ -145,24 +145,21 @@ bool DallasTemperatureSensor::check_scratch_pad_() { float DallasTemperatureSensor::get_temp_c_() { int16_t temp = (this->scratch_pad_[1] << 8) | this->scratch_pad_[0]; if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) { - if (this->scratch_pad_[7] != 0x10) - ESP_LOGE(TAG, "unexpected COUNT_PER_C value: %u", this->scratch_pad_[7]); - temp = ((temp & 0xfff7) << 3) + (0x10 - this->scratch_pad_[6]) - 4; - } else { - switch (this->resolution_) { - case 9: - temp &= 0xfff8; - break; - case 10: - temp &= 0xfffc; - break; - case 11: - temp &= 0xfffe; - break; - case 12: - default: - break; - } + return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25; + } + switch (this->resolution_) { + case 9: + temp &= 0xfff8; + break; + case 10: + temp &= 0xfffc; + break; + case 11: + temp &= 0xfffe; + break; + case 12: + default: + break; } return temp / 16.0f; From 01bcf5fb97643d73a96fbf7119ea48a768f85b73 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Wed, 26 Jun 2024 14:38:11 +0400 Subject: [PATCH 1976/2607] [modbus-text-sensor] fix potential buffer overflow (#6993) --- .../modbus_controller/text_sensor/modbus_textsensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp index 359c6e2f50..da5c0fba37 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp @@ -15,7 +15,7 @@ void ModbusTextSensor::parse_and_publish(const std::vector &data) { std::ostringstream output; uint8_t items_left = this->response_bytes; uint8_t index = this->offset; - char buffer[4]; + char buffer[5]; while ((items_left > 0) && index < data.size()) { uint8_t b = data[index]; switch (this->encode_) { From 7be071a0e91771019fce9be8704e6dffc1d6e0af Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:07:19 +1200 Subject: [PATCH 1977/2607] [safe_mode] Set safe mode core data in disabled cases (#6983) --- esphome/components/safe_mode/__init__.py | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index 881937890d..185c0e70b1 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -56,21 +56,20 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(50.0) async def to_code(config): - if config[CONF_DISABLED]: - return + if not config[CONF_DISABLED]: + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) + for conf in config.get(CONF_ON_SAFE_MODE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) - for conf in config.get(CONF_ON_SAFE_MODE, []): - trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - await automation.build_automation(trigger, [], conf) + condition = var.should_enter_safe_mode( + config[CONF_NUM_ATTEMPTS], + config[CONF_REBOOT_TIMEOUT], + config[CONF_BOOT_IS_GOOD_AFTER], + ) + cg.add(RawExpression(f"if ({condition}) return")) - condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], - config[CONF_REBOOT_TIMEOUT], - config[CONF_BOOT_IS_GOOD_AFTER], - ) - cg.add(RawExpression(f"if ({condition}) return")) CORE.data[CONF_SAFE_MODE] = {} CORE.data[CONF_SAFE_MODE][KEY_PAST_SAFE_MODE] = True From d8a6d8594a246fd038c6051f157c7ce2eaf8b0eb Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 25 Jun 2024 15:57:15 -0500 Subject: [PATCH 1978/2607] [ota-esphome] Validate for multiple esphome ota instances (#6984) --- esphome/components/esphome/ota/__init__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index c5903974c2..88e729f230 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,10 +1,14 @@ import esphome.codegen as cg import esphome.config_validation as cv +import esphome.final_validate as fv from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent from esphome.const import ( + CONF_ESPHOME, CONF_ID, CONF_NUM_ATTEMPTS, + CONF_OTA, CONF_PASSWORD, + CONF_PLATFORM, CONF_PORT, CONF_REBOOT_TIMEOUT, CONF_SAFE_MODE, @@ -21,6 +25,19 @@ esphome = cg.esphome_ns.namespace("esphome") ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) +def ota_esphome_final_validate(config): + fconf = fv.full_config.get()[CONF_OTA] + used_ports = [] + for ota_conf in fconf: + if ota_conf.get(CONF_PLATFORM) == CONF_ESPHOME: + if (plat_port := ota_conf.get(CONF_PORT)) not in used_ports: + used_ports.append(plat_port) + else: + raise cv.Invalid( + f"Only one instance of the {CONF_ESPHOME} {CONF_OTA} {CONF_PLATFORM} is allowed per port. Note that this error may result from OTA specified in packages" + ) + + CONFIG_SCHEMA = ( cv.Schema( { @@ -50,6 +67,8 @@ CONFIG_SCHEMA = ( .extend(cv.COMPONENT_SCHEMA) ) +FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate + @coroutine_with_priority(52.0) async def to_code(config): From 1579dfeb80a7b49d6cc4cfeb4f52074c026621b3 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 25 Jun 2024 19:50:54 -0400 Subject: [PATCH 1979/2607] Improve 'body' handling in http_request on_response triggers (#6968) --- esphome/codegen.py | 1 + esphome/components/http_request/__init__.py | 2 +- .../components/http_request/http_request.h | 19 ++++++++++++++----- esphome/cpp_types.py | 1 + 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/esphome/codegen.py b/esphome/codegen.py index b552490129..6b000b53a1 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -60,6 +60,7 @@ from esphome.cpp_types import ( # noqa std_ns, std_shared_ptr, std_string, + std_string_ref, std_vector, uint8, uint16, diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 37487ec9a7..ade7024bed 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -257,7 +257,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args): trigger, [ (cg.std_shared_ptr.template(HttpContainer), "response"), - (cg.std_string, "body"), + (cg.std_string_ref, "body"), ], conf, ) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 6281adddb6..82b7392648 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -43,10 +43,10 @@ class HttpContainer : public Parented { bool secure_{false}; }; -class HttpRequestResponseTrigger : public Trigger, std::string> { +class HttpRequestResponseTrigger : public Trigger, std::string &> { public: - void process(std::shared_ptr container, std::string response_body) { - this->trigger(std::move(container), std::move(response_body)); + void process(std::shared_ptr container, std::string &response_body) { + this->trigger(std::move(container), response_body); } }; @@ -153,8 +153,17 @@ template class HttpRequestSendAction : public Action { } } - for (auto *trigger : this->response_triggers_) { - trigger->process(container, response_body); + if (this->response_triggers_.size() == 1) { + // if there is only one trigger, no need to copy the response body + this->response_triggers_[0]->process(container, response_body); + } else { + for (auto *trigger : this->response_triggers_) { + // with multiple triggers, pass a copy of the response body to each + // one so that modifications made in one trigger are not visible to + // the others + auto response_body_copy = std::string(response_body); + trigger->process(container, response_body_copy); + } } container->end(); } diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index bd79d3b2f9..dab993f87f 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -10,6 +10,7 @@ int_ = global_ns.namespace("int") std_ns = global_ns.namespace("std") std_shared_ptr = std_ns.class_("shared_ptr") std_string = std_ns.class_("string") +std_string_ref = std_ns.namespace("string &") std_vector = std_ns.class_("vector") uint8 = global_ns.namespace("uint8_t") uint16 = global_ns.namespace("uint16_t") From 169fb79c977aa451655fa1840b738dfee9bfca13 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 25 Jun 2024 16:54:02 -0700 Subject: [PATCH 1980/2607] [ds1307] Initialize uninitialized struct members (#6985) --- esphome/components/ds1307/ds1307.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/esphome/components/ds1307/ds1307.cpp b/esphome/components/ds1307/ds1307.cpp index 472ccc7a9a..9df8a1d373 100644 --- a/esphome/components/ds1307/ds1307.cpp +++ b/esphome/components/ds1307/ds1307.cpp @@ -37,14 +37,18 @@ void DS1307Component::read_time() { ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); return; } - ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), - .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), - .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), - .day_of_week = uint8_t(ds1307_.reg.weekday), - .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), - .day_of_year = 1, // ignored by recalc_timestamp_utc(false) - .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), - .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)}; + ESPTime rtc_time{ + .second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), + .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), + .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), + .day_of_week = uint8_t(ds1307_.reg.weekday), + .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), + .day_of_year = 1, // ignored by recalc_timestamp_utc(false) + .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), + .year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000), + .is_dst = false, // not used + .timestamp = 0 // overwritten by recalc_timestamp_utc(false) + }; rtc_time.recalc_timestamp_utc(false); if (!rtc_time.is_valid()) { ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); From bbd7c9cf861d199c7e671aa175c3d225a3bea14f Mon Sep 17 00:00:00 2001 From: Petapton <14984292+Petapton@users.noreply.github.com> Date: Wed, 26 Jun 2024 02:08:16 +0200 Subject: [PATCH 1981/2607] Fix float encoding in modbus server (#6986) --- esphome/components/modbus_controller/modbus_controller.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 9f73988b03..29d3137603 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -116,7 +116,8 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %0.1f.", server_register->address, static_cast(server_register->value_type), server_register->register_count, value); - number_to_payload(sixteen_bit_response, value, server_register->value_type); + std::vector payload = float_to_payload(value, server_register->value_type); + sixteen_bit_response.insert(sixteen_bit_response.end(), payload.cbegin(), payload.cend()); current_address += server_register->register_count; found = true; break; From c747d7d45d15469c111635045e2c95437bedccc1 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 26 Jun 2024 00:27:07 -0700 Subject: [PATCH 1982/2607] [dallas_temp] fix ds18s20 temp calc (#6988) --- .../components/dallas_temp/dallas_temp.cpp | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/esphome/components/dallas_temp/dallas_temp.cpp b/esphome/components/dallas_temp/dallas_temp.cpp index fe7c9a95ea..ae567d6a76 100644 --- a/esphome/components/dallas_temp/dallas_temp.cpp +++ b/esphome/components/dallas_temp/dallas_temp.cpp @@ -145,24 +145,21 @@ bool DallasTemperatureSensor::check_scratch_pad_() { float DallasTemperatureSensor::get_temp_c_() { int16_t temp = (this->scratch_pad_[1] << 8) | this->scratch_pad_[0]; if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) { - if (this->scratch_pad_[7] != 0x10) - ESP_LOGE(TAG, "unexpected COUNT_PER_C value: %u", this->scratch_pad_[7]); - temp = ((temp & 0xfff7) << 3) + (0x10 - this->scratch_pad_[6]) - 4; - } else { - switch (this->resolution_) { - case 9: - temp &= 0xfff8; - break; - case 10: - temp &= 0xfffc; - break; - case 11: - temp &= 0xfffe; - break; - case 12: - default: - break; - } + return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25; + } + switch (this->resolution_) { + case 9: + temp &= 0xfff8; + break; + case 10: + temp &= 0xfffc; + break; + case 11: + temp &= 0xfffe; + break; + case 12: + default: + break; } return temp / 16.0f; From 9c2af6318ced3de3927db404172fe358fd0afa7d Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Wed, 26 Jun 2024 14:38:11 +0400 Subject: [PATCH 1983/2607] [modbus-text-sensor] fix potential buffer overflow (#6993) --- .../modbus_controller/text_sensor/modbus_textsensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp index 359c6e2f50..da5c0fba37 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp @@ -15,7 +15,7 @@ void ModbusTextSensor::parse_and_publish(const std::vector &data) { std::ostringstream output; uint8_t items_left = this->response_bytes; uint8_t index = this->offset; - char buffer[4]; + char buffer[5]; while ((items_left > 0) && index < data.size()) { uint8_t b = data[index]; switch (this->encode_) { From 86791422f02a5401c2fff948bba4eb1b0d82ac85 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:41:48 +1200 Subject: [PATCH 1984/2607] Bump version to 2024.6.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index cde917ca98..2434609191 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.2" +__version__ = "2024.6.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7174cf35dd9dc3e9e48ab84466dfcd69f2cb2f03 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 17:53:29 -0500 Subject: [PATCH 1985/2607] [CI] Add more mdns and safe_mode tests (#6990) --- tests/components/mdns/{common.yaml => common-enabled.yaml} | 0 tests/components/mdns/test-disabled.esp32-idf.yaml | 6 ++++++ tests/components/mdns/test-enabled.esp32-ard.yaml | 1 + tests/components/mdns/test-enabled.esp32-c3-ard.yaml | 1 + tests/components/mdns/test-enabled.esp32-c3-idf.yaml | 1 + tests/components/mdns/test-enabled.esp32-idf.yaml | 1 + tests/components/mdns/test-enabled.esp8266-ard.yaml | 1 + tests/components/mdns/test-enabled.rp2040-ard.yaml | 1 + tests/components/mdns/test.esp32-ard.yaml | 1 - tests/components/mdns/test.esp32-c3-ard.yaml | 1 - tests/components/mdns/test.esp32-c3-idf.yaml | 1 - tests/components/mdns/test.esp32-idf.yaml | 1 - tests/components/mdns/test.esp8266-ard.yaml | 1 - tests/components/mdns/test.rp2040-ard.yaml | 1 - .../safe_mode/{common.yaml => common-enabled.yaml} | 0 tests/components/safe_mode/test-disabled.esp32-idf.yaml | 6 ++++++ tests/components/safe_mode/test-enabled.esp32-ard.yaml | 1 + tests/components/safe_mode/test-enabled.esp32-c3-ard.yaml | 1 + tests/components/safe_mode/test-enabled.esp32-c3-idf.yaml | 1 + tests/components/safe_mode/test-enabled.esp32-idf.yaml | 1 + tests/components/safe_mode/test-enabled.esp8266-ard.yaml | 1 + tests/components/safe_mode/test-enabled.rp2040-ard.yaml | 1 + tests/components/safe_mode/test.esp32-ard.yaml | 1 - tests/components/safe_mode/test.esp32-c3-ard.yaml | 1 - tests/components/safe_mode/test.esp32-c3-idf.yaml | 1 - tests/components/safe_mode/test.esp32-idf.yaml | 1 - tests/components/safe_mode/test.esp8266-ard.yaml | 1 - tests/components/safe_mode/test.rp2040-ard.yaml | 1 - 28 files changed, 24 insertions(+), 12 deletions(-) rename tests/components/mdns/{common.yaml => common-enabled.yaml} (100%) create mode 100644 tests/components/mdns/test-disabled.esp32-idf.yaml create mode 100644 tests/components/mdns/test-enabled.esp32-ard.yaml create mode 100644 tests/components/mdns/test-enabled.esp32-c3-ard.yaml create mode 100644 tests/components/mdns/test-enabled.esp32-c3-idf.yaml create mode 100644 tests/components/mdns/test-enabled.esp32-idf.yaml create mode 100644 tests/components/mdns/test-enabled.esp8266-ard.yaml create mode 100644 tests/components/mdns/test-enabled.rp2040-ard.yaml delete mode 100644 tests/components/mdns/test.esp32-ard.yaml delete mode 100644 tests/components/mdns/test.esp32-c3-ard.yaml delete mode 100644 tests/components/mdns/test.esp32-c3-idf.yaml delete mode 100644 tests/components/mdns/test.esp32-idf.yaml delete mode 100644 tests/components/mdns/test.esp8266-ard.yaml delete mode 100644 tests/components/mdns/test.rp2040-ard.yaml rename tests/components/safe_mode/{common.yaml => common-enabled.yaml} (100%) create mode 100644 tests/components/safe_mode/test-disabled.esp32-idf.yaml create mode 100644 tests/components/safe_mode/test-enabled.esp32-ard.yaml create mode 100644 tests/components/safe_mode/test-enabled.esp32-c3-ard.yaml create mode 100644 tests/components/safe_mode/test-enabled.esp32-c3-idf.yaml create mode 100644 tests/components/safe_mode/test-enabled.esp32-idf.yaml create mode 100644 tests/components/safe_mode/test-enabled.esp8266-ard.yaml create mode 100644 tests/components/safe_mode/test-enabled.rp2040-ard.yaml delete mode 100644 tests/components/safe_mode/test.esp32-ard.yaml delete mode 100644 tests/components/safe_mode/test.esp32-c3-ard.yaml delete mode 100644 tests/components/safe_mode/test.esp32-c3-idf.yaml delete mode 100644 tests/components/safe_mode/test.esp32-idf.yaml delete mode 100644 tests/components/safe_mode/test.esp8266-ard.yaml delete mode 100644 tests/components/safe_mode/test.rp2040-ard.yaml diff --git a/tests/components/mdns/common.yaml b/tests/components/mdns/common-enabled.yaml similarity index 100% rename from tests/components/mdns/common.yaml rename to tests/components/mdns/common-enabled.yaml diff --git a/tests/components/mdns/test-disabled.esp32-idf.yaml b/tests/components/mdns/test-disabled.esp32-idf.yaml new file mode 100644 index 0000000000..07c70bf248 --- /dev/null +++ b/tests/components/mdns/test-disabled.esp32-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +mdns: + disabled: true diff --git a/tests/components/mdns/test-enabled.esp32-ard.yaml b/tests/components/mdns/test-enabled.esp32-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test-enabled.esp32-c3-ard.yaml b/tests/components/mdns/test-enabled.esp32-c3-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test-enabled.esp32-c3-idf.yaml b/tests/components/mdns/test-enabled.esp32-c3-idf.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test-enabled.esp32-idf.yaml b/tests/components/mdns/test-enabled.esp32-idf.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test-enabled.esp8266-ard.yaml b/tests/components/mdns/test-enabled.esp8266-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test-enabled.rp2040-ard.yaml b/tests/components/mdns/test-enabled.rp2040-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/mdns/test-enabled.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/mdns/test.esp32-ard.yaml b/tests/components/mdns/test.esp32-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.esp32-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32-c3-ard.yaml b/tests/components/mdns/test.esp32-c3-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.esp32-c3-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32-c3-idf.yaml b/tests/components/mdns/test.esp32-c3-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.esp32-c3-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/mdns/test.esp32-idf.yaml b/tests/components/mdns/test.esp32-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/mdns/test.esp8266-ard.yaml b/tests/components/mdns/test.esp8266-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.esp8266-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/mdns/test.rp2040-ard.yaml b/tests/components/mdns/test.rp2040-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/mdns/test.rp2040-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common-enabled.yaml similarity index 100% rename from tests/components/safe_mode/common.yaml rename to tests/components/safe_mode/common-enabled.yaml diff --git a/tests/components/safe_mode/test-disabled.esp32-idf.yaml b/tests/components/safe_mode/test-disabled.esp32-idf.yaml new file mode 100644 index 0000000000..291f5a2c7c --- /dev/null +++ b/tests/components/safe_mode/test-disabled.esp32-idf.yaml @@ -0,0 +1,6 @@ +wifi: + ssid: MySSID + password: password1 + +safe_mode: + disabled: true diff --git a/tests/components/safe_mode/test-enabled.esp32-ard.yaml b/tests/components/safe_mode/test-enabled.esp32-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test-enabled.esp32-c3-ard.yaml b/tests/components/safe_mode/test-enabled.esp32-c3-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test-enabled.esp32-c3-idf.yaml b/tests/components/safe_mode/test-enabled.esp32-c3-idf.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test-enabled.esp32-idf.yaml b/tests/components/safe_mode/test-enabled.esp32-idf.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test-enabled.esp8266-ard.yaml b/tests/components/safe_mode/test-enabled.esp8266-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test-enabled.rp2040-ard.yaml b/tests/components/safe_mode/test-enabled.rp2040-ard.yaml new file mode 100644 index 0000000000..97fd63d70e --- /dev/null +++ b/tests/components/safe_mode/test-enabled.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-enabled.yaml diff --git a/tests/components/safe_mode/test.esp32-ard.yaml b/tests/components/safe_mode/test.esp32-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.esp32-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32-c3-ard.yaml b/tests/components/safe_mode/test.esp32-c3-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.esp32-c3-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32-c3-idf.yaml b/tests/components/safe_mode/test.esp32-c3-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.esp32-c3-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp32-idf.yaml b/tests/components/safe_mode/test.esp32-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/test.esp8266-ard.yaml b/tests/components/safe_mode/test.esp8266-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.esp8266-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/safe_mode/test.rp2040-ard.yaml b/tests/components/safe_mode/test.rp2040-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/safe_mode/test.rp2040-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml From 300d48a55e14f9d6170069364d4eaf9b0217a7d5 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 17:54:17 -0500 Subject: [PATCH 1986/2607] [CI] Remove old test yamls (#6991) --- .github/workflows/ci.yml | 67 ---------------------------------------- 1 file changed, 67 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df7a9178e1..45fe336d77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -248,72 +248,6 @@ jobs: run: script/ci-suggest-changes if: always() - compile-tests-list: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - name: Check out code from GitHub - uses: actions/checkout@v4.1.7 - - name: Find all YAML test files - id: set-matrix - run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT - - validate-tests: - name: Validate YAML test ${{ matrix.file }} - runs-on: ubuntu-latest - needs: - - common - - compile-tests-list - strategy: - fail-fast: false - matrix: - file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} - steps: - - name: Check out code from GitHub - uses: actions/checkout@v4.1.7 - - name: Restore Python - uses: ./.github/actions/restore-python - with: - python-version: ${{ env.DEFAULT_PYTHON }} - cache-key: ${{ needs.common.outputs.cache-key }} - - name: Run esphome config ${{ matrix.file }} - run: | - . venv/bin/activate - esphome config ${{ matrix.file }} - - compile-tests: - name: Run YAML test ${{ matrix.file }} - runs-on: ubuntu-latest - needs: - - common - - black - - ci-custom - - clang-format - - flake8 - - pylint - - pytest - - pyupgrade - - compile-tests-list - - validate-tests - strategy: - fail-fast: false - max-parallel: 2 - matrix: - file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} - steps: - - name: Check out code from GitHub - uses: actions/checkout@v4.1.7 - - name: Restore Python - uses: ./.github/actions/restore-python - with: - python-version: ${{ env.DEFAULT_PYTHON }} - cache-key: ${{ needs.common.outputs.cache-key }} - - name: Run esphome compile ${{ matrix.file }} - run: | - . venv/bin/activate - esphome compile ${{ matrix.file }} - clang-tidy: name: ${{ matrix.name }} runs-on: ubuntu-latest @@ -550,7 +484,6 @@ jobs: - pylint - pytest - pyupgrade - - compile-tests - clang-tidy - list-components - test-build-components From 855d154439906ea0b150eb57ae7fa866bf52ca3d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 17:55:05 -0500 Subject: [PATCH 1987/2607] [CI] Update tests to run against IDF 5.1 (#6992) --- ...f-50.yaml => build_components_base.esp32-c3-idf-51.yaml} | 6 +++--- ...-idf-50.yaml => build_components_base.esp32-idf-51.yaml} | 6 +++--- ...f-50.yaml => build_components_base.esp32-s2-idf-51.yaml} | 6 +++--- ...f-50.yaml => build_components_base.esp32-s3-idf-51.yaml} | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) rename tests/test_build_components/{build_components_base.esp32-c3-idf-50.yaml => build_components_base.esp32-c3-idf-51.yaml} (76%) rename tests/test_build_components/{build_components_base.esp32-idf-50.yaml => build_components_base.esp32-idf-51.yaml} (77%) rename tests/test_build_components/{build_components_base.esp32-s2-idf-50.yaml => build_components_base.esp32-s2-idf-51.yaml} (78%) rename tests/test_build_components/{build_components_base.esp32-s3-idf-50.yaml => build_components_base.esp32-s3-idf-51.yaml} (77%) diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml similarity index 76% rename from tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml index 08d4d8679c..73d2c8fa19 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32c3idf50 + name: componenttestesp32c3idf51 friendly_name: $component_name esp32: board: lolin_c3_mini framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.6.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-idf-51.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-idf-51.yaml index c9f2c1e943..6c8eb3c193 100644 --- a/tests/test_build_components/build_components_base.esp32-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-idf-51.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32idf50 + name: componenttestesp32idf51 friendly_name: $component_name esp32: board: nodemcu-32s framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.6.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml similarity index 78% rename from tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml index 351f5fb019..8894efb6b8 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s2idf50 + name: componenttestesp32s2idf51 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S2 framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.6.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml index c05378903f..efeffa5a0f 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s3idf50 + name: componenttestesp32s3idf51 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S3 framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.6.0 logger: level: VERY_VERBOSE From 192718fee626852690acd575efae60dc06453df6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 10:55:42 +1200 Subject: [PATCH 1988/2607] Bump docker/build-push-action from 6.1.0 to 6.2.0 in /.github/actions/build-image (#6999) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 27d2ffc533..b038a285ef 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.1.0 + uses: docker/build-push-action@v6.2.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.1.0 + uses: docker/build-push-action@v6.2.0 with: context: . file: ./docker/Dockerfile From 10504c4d68b9808b86d51763f3b92ee0a41b96db Mon Sep 17 00:00:00 2001 From: Christiaan de Ridder Date: Thu, 27 Jun 2024 01:03:55 +0200 Subject: [PATCH 1989/2607] Tuya invalid command 0x22 (#6980) --- esphome/components/tuya/tuya.cpp | 10 ++++++++-- esphome/components/tuya/tuya.h | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 402953bb3b..1443d10254 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -223,13 +223,19 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff break; case TuyaCommandType::DATAPOINT_DELIVER: break; - case TuyaCommandType::DATAPOINT_REPORT: + case TuyaCommandType::DATAPOINT_REPORT_ASYNC: + case TuyaCommandType::DATAPOINT_REPORT_SYNC: if (this->init_state_ == TuyaInitState::INIT_DATAPOINT) { this->init_state_ = TuyaInitState::INIT_DONE; this->set_timeout("datapoint_dump", 1000, [this] { this->dump_config(); }); this->initialized_callback_.call(); } this->handle_datapoints_(buffer, len); + + if (command_type == TuyaCommandType::DATAPOINT_REPORT_SYNC) { + this->send_command_( + TuyaCommand{.cmd = TuyaCommandType::DATAPOINT_REPORT_ACK, .payload = std::vector{0x01}}); + } break; case TuyaCommandType::DATAPOINT_QUERY: break; @@ -423,7 +429,7 @@ void Tuya::send_raw_command_(TuyaCommand command) { break; case TuyaCommandType::DATAPOINT_DELIVER: case TuyaCommandType::DATAPOINT_QUERY: - this->expected_response_ = TuyaCommandType::DATAPOINT_REPORT; + this->expected_response_ = TuyaCommandType::DATAPOINT_REPORT_ASYNC; break; default: break; diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index 6db417d474..76431ddfe4 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -53,10 +53,12 @@ enum class TuyaCommandType : uint8_t { WIFI_RESET = 0x04, WIFI_SELECT = 0x05, DATAPOINT_DELIVER = 0x06, - DATAPOINT_REPORT = 0x07, + DATAPOINT_REPORT_ASYNC = 0x07, DATAPOINT_QUERY = 0x08, WIFI_TEST = 0x0E, LOCAL_TIME_QUERY = 0x1C, + DATAPOINT_REPORT_SYNC = 0x22, + DATAPOINT_REPORT_ACK = 0x23, WIFI_RSSI = 0x24, VACUUM_MAP_UPLOAD = 0x28, GET_NETWORK_STATUS = 0x2B, From cd7894ae8f235df2d601e03b20a725b61b5a2921 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 20:07:07 -0500 Subject: [PATCH 1990/2607] [ota-esphome] Merge configurations by port (#7001) --- esphome/components/esphome/ota/__init__.py | 65 +++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index 88e729f230..a852d8d001 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,7 +1,10 @@ +import logging + import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent +from esphome.config_helpers import merge_config from esphome.const import ( CONF_ESPHOME, CONF_ID, @@ -16,6 +19,8 @@ from esphome.const import ( ) from esphome.core import coroutine_with_priority +_LOGGER = logging.getLogger(__name__) + CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["md5", "socket"] @@ -26,16 +31,62 @@ ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) def ota_esphome_final_validate(config): - fconf = fv.full_config.get()[CONF_OTA] - used_ports = [] - for ota_conf in fconf: + full_conf = fv.full_config.get() + full_ota_conf = full_conf[CONF_OTA] + new_ota_conf = [] + merged_ota_esphome_configs_by_port = {} + ports_with_merged_configs = [] + for ota_conf in full_ota_conf: if ota_conf.get(CONF_PLATFORM) == CONF_ESPHOME: - if (plat_port := ota_conf.get(CONF_PORT)) not in used_ports: - used_ports.append(plat_port) + if ( + conf_port := ota_conf.get(CONF_PORT) + ) not in merged_ota_esphome_configs_by_port: + merged_ota_esphome_configs_by_port[conf_port] = ota_conf else: - raise cv.Invalid( - f"Only one instance of the {CONF_ESPHOME} {CONF_OTA} {CONF_PLATFORM} is allowed per port. Note that this error may result from OTA specified in packages" + if merged_ota_esphome_configs_by_port[conf_port][ + CONF_VERSION + ] != ota_conf.get(CONF_VERSION): + raise cv.Invalid( + f"Found multiple configurations but {CONF_VERSION} is inconsistent" + ) + if ( + merged_ota_esphome_configs_by_port[conf_port][CONF_ID].is_manual + and ota_conf.get(CONF_ID).is_manual + ): + raise cv.Invalid( + f"Found multiple configurations but {CONF_ID} is inconsistent" + ) + if ( + CONF_PASSWORD in merged_ota_esphome_configs_by_port[conf_port] + and CONF_PASSWORD in ota_conf + and merged_ota_esphome_configs_by_port[conf_port][CONF_PASSWORD] + != ota_conf.get(CONF_PASSWORD) + ): + raise cv.Invalid( + f"Found multiple configurations but {CONF_PASSWORD} is inconsistent" + ) + + ports_with_merged_configs.append(conf_port) + merged_ota_esphome_configs_by_port[conf_port] = merge_config( + merged_ota_esphome_configs_by_port[conf_port], ota_conf ) + else: + new_ota_conf.append(ota_conf) + + for port_conf in merged_ota_esphome_configs_by_port.values(): + new_ota_conf.append(port_conf) + + full_conf[CONF_OTA] = new_ota_conf + fv.full_config.set(full_conf) + + if len(ports_with_merged_configs) > 0: + _LOGGER.warning( + "Found and merged multiple configurations for %s %s %s port(s) %s", + CONF_OTA, + CONF_PLATFORM, + CONF_ESPHOME, + ports_with_merged_configs, + ) CONFIG_SCHEMA = ( From bfdf63055fa1113be5b2ee664e464f7763cab808 Mon Sep 17 00:00:00 2001 From: Simone Rossetto Date: Thu, 27 Jun 2024 03:42:16 +0200 Subject: [PATCH 1991/2607] Allow wireguard to bind to PPP interface (#6989) Co-authored-by: Tim Lunn --- esphome/components/wireguard/__init__.py | 2 +- platformio.ini | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 5d5f620b51..16d0d0226e 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -132,7 +132,7 @@ async def to_code(config): # the '+1' modifier is relative to the device's own address that will # be automatically added to the provided list. cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}") - cg.add_library("droscy/esp_wireguard", "0.4.1") + cg.add_library("droscy/esp_wireguard", "0.4.2") await cg.register_component(var, config) diff --git a/platformio.ini b/platformio.ini index e2e66bf672..aa73437222 100644 --- a/platformio.ini +++ b/platformio.ini @@ -94,7 +94,7 @@ lib_deps = ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir - droscy/esp_wireguard@0.4.1 ; wireguard + droscy/esp_wireguard@0.4.2 ; wireguard build_flags = ${common:arduino.build_flags} -Wno-nonnull-compare @@ -124,7 +124,7 @@ lib_deps = DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir - droscy/esp_wireguard@0.4.1 ; wireguard + droscy/esp_wireguard@0.4.2 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_ESP32 @@ -142,7 +142,7 @@ platform_packages = framework = espidf lib_deps = ${common:idf.lib_deps} - droscy/esp_wireguard@0.4.1 ; wireguard + droscy/esp_wireguard@0.4.2 ; wireguard build_flags = ${common:idf.build_flags} -Wno-nonnull-compare @@ -174,7 +174,7 @@ extends = common:arduino platform = libretiny framework = arduino lib_deps = - droscy/esp_wireguard@0.4.1 ; wireguard + droscy/esp_wireguard@0.4.2 ; wireguard build_flags = ${common:arduino.build_flags} -DUSE_LIBRETINY From decf50ed492a06aeba7ce1735a0ab324bc4dad73 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Thu, 27 Jun 2024 03:48:01 +0200 Subject: [PATCH 1992/2607] Fix LEDC 100% is not 100% duty with ESP32 IDF (#6997) --- esphome/components/ledc/ledc_output.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 1040ac25b6..90e11fe4ad 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -115,12 +115,15 @@ void LEDCOutput::write_state(float state) { const uint32_t max_duty = (uint32_t(1) << this->bit_depth_) - 1; const float duty_rounded = roundf(state * max_duty); auto duty = static_cast(duty_rounded); - #ifdef USE_ARDUINO ESP_LOGV(TAG, "Setting duty: %u on channel %u", duty, this->channel_); ledcWrite(this->channel_, duty); #endif #ifdef USE_ESP_IDF + // ensure that 100% on is not 99.975% on + if ((duty == max_duty) && (max_duty != 1)) { + duty = max_duty + 1; + } auto speed_mode = get_speed_mode(channel_); auto chan_num = static_cast(channel_ % 8); int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); From 9a26cdb3364fa40957a05309d16b007f96f29c0f Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 27 Jun 2024 05:50:25 +0400 Subject: [PATCH 1993/2607] [modbus_text_sensor] new default ANSI encoding type (#6975) --- esphome/components/modbus_controller/text_sensor/__init__.py | 3 ++- .../modbus_controller/text_sensor/modbus_textsensor.cpp | 5 ++++- .../modbus_controller/text_sensor/modbus_textsensor.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/components/modbus_controller/text_sensor/__init__.py b/esphome/components/modbus_controller/text_sensor/__init__.py index 763336e104..81d6453c6f 100644 --- a/esphome/components/modbus_controller/text_sensor/__init__.py +++ b/esphome/components/modbus_controller/text_sensor/__init__.py @@ -37,6 +37,7 @@ RAW_ENCODING = { "NONE": RawEncoding.NONE, "HEXBYTES": RawEncoding.HEXBYTES, "COMMA": RawEncoding.COMMA, + "ANSI": RawEncoding.ANSI, } CONFIG_SCHEMA = cv.All( @@ -49,7 +50,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE), cv.Optional(CONF_REGISTER_COUNT, default=0): cv.positive_int, cv.Optional(CONF_RESPONSE_SIZE, default=2): cv.positive_int, - cv.Optional(CONF_RAW_ENCODE, default="NONE"): cv.enum(RAW_ENCODING), + cv.Optional(CONF_RAW_ENCODE, default="ANSI"): cv.enum(RAW_ENCODING), } ), validate_modbus_register, diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp index da5c0fba37..acdcacc083 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp @@ -27,8 +27,11 @@ void ModbusTextSensor::parse_and_publish(const std::vector &data) { sprintf(buffer, index != this->offset ? ",%d" : "%d", b); output << buffer; break; + case RawEncoding::ANSI: + if (b < 0x20) + break; + // FALLTHROUGH // Anything else no encoding - case RawEncoding::NONE: default: output << (char) b; break; diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h index 9cc0db05a5..d6eb5fd230 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h @@ -9,7 +9,7 @@ namespace esphome { namespace modbus_controller { -enum class RawEncoding { NONE = 0, HEXBYTES = 1, COMMA = 2 }; +enum class RawEncoding { NONE = 0, HEXBYTES = 1, COMMA = 2, ANSI = 3 }; class ModbusTextSensor : public Component, public text_sensor::TextSensor, public SensorItem { public: From e23153d090061c93a314a4de7bfb0c58ff05a006 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 21:34:39 -0500 Subject: [PATCH 1994/2607] [CI] Remove old test yaml files (#7002) --- tests/test1.1.yaml | 232 --- tests/test1.yaml | 4427 ------------------------------------------- tests/test11.5.yaml | 809 -------- tests/test2.yaml | 879 --------- tests/test3.1.yaml | 734 ------- tests/test3.yaml | 1432 -------------- tests/test4.yaml | 998 ---------- tests/test5.yaml | 747 -------- tests/test6.yaml | 77 - tests/test7.yaml | 27 - tests/test8.1.yaml | 78 - tests/test8.2.yaml | 75 - tests/test8.yaml | 125 -- tests/test9.1.yaml | 29 - tests/test9.yaml | 35 - 15 files changed, 10704 deletions(-) delete mode 100644 tests/test1.1.yaml delete mode 100644 tests/test1.yaml delete mode 100644 tests/test11.5.yaml delete mode 100644 tests/test2.yaml delete mode 100644 tests/test3.1.yaml delete mode 100644 tests/test3.yaml delete mode 100644 tests/test4.yaml delete mode 100644 tests/test5.yaml delete mode 100644 tests/test6.yaml delete mode 100644 tests/test7.yaml delete mode 100644 tests/test8.1.yaml delete mode 100644 tests/test8.2.yaml delete mode 100644 tests/test8.yaml delete mode 100644 tests/test9.1.yaml delete mode 100644 tests/test9.yaml diff --git a/tests/test1.1.yaml b/tests/test1.1.yaml deleted file mode 100644 index c71aa6e0ef..0000000000 --- a/tests/test1.1.yaml +++ /dev/null @@ -1,232 +0,0 @@ ---- -substitutions: - devicename: test1_1 - sensorname: my - textname: template - roomname: fastled_room - -esphome: - name: test1-1 - name_add_mac_suffix: true - platform: ESP32 - board: nodemcu-32s - platformio_options: - board_build.partitions: huge_app.csv - on_loop: - then: - - light.addressable_set: - id: addr1 - range_from: 0 - range_to: 100 - red: 100% - green: !lambda "return 255;" - blue: 0% - white: 100% - -wled: - -wifi: - networks: - - ssid: "MySSID" - password: "password1" - -uart: - - id: adalight_uart - tx_pin: GPIO25 - rx_pin: GPIO26 - baud_rate: 115200 - rx_buffer_size: 1024 - -adalight: - -network: - -e131: - -power_supply: - - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - enable_on_boot: true - pin: - number: 13 - inverted: true - -i2c: - sda: 21 - scl: - number: 22 - allow_other_uses: true - scan: true - frequency: 100kHz - setup_priority: -100 - id: i2c_bus - -pca9685: - frequency: 500 - address: 0x0 - i2c_id: i2c_bus - -output: - - platform: pca9685 - id: pca_0 - channel: 0 - - platform: pca9685 - id: pca_1 - channel: 1 - - platform: pca9685 - id: pca_2 - channel: 2 - -light: - - platform: rgb - name: Living Room Lights - id: ${roomname}_lights - red: pca_0 - green: pca_1 - blue: pca_2 - - platform: fastled_clockless - id: addr1 - chipset: WS2811 - pin: - allow_other_uses: true - number: GPIO23 - num_leds: 60 - rgb_order: BRG - max_refresh_rate: 20ms - power_supply: atx_power_supply - color_correct: [75%, 100%, 50%] - name: FastLED WS2811 Light - effects: - - addressable_color_wipe: - - addressable_color_wipe: - name: Color Wipe Effect With Custom Values - colors: - - red: 100% - green: 100% - blue: 100% - num_leds: 1 - - red: 0% - green: 0% - blue: 0% - num_leds: 1 - add_led_interval: 100ms - reverse: false - - addressable_scan: - - addressable_scan: - name: Scan Effect With Custom Values - move_interval: 100ms - - addressable_twinkle: - - addressable_twinkle: - name: Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 4ms - - addressable_random_twinkle: - - addressable_random_twinkle: - name: Random Twinkle Effect With Custom Values - twinkle_probability: 5% - progress_interval: 32ms - - addressable_fireworks: - - addressable_fireworks: - name: Fireworks Effect With Custom Values - update_interval: 32ms - spark_probability: 10% - use_random_color: false - fade_out_rate: 120 - - addressable_flicker: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - - addressable_lambda: - name: Test For Custom Lambda Effect - lambda: |- - if (initial_run) { - it[0] = current_color; - } - - - wled: - port: 11111 - - - adalight: - uart_id: adalight_uart - - - e131: - universe: 1 - - - automation: - name: Custom Effect - sequence: - - light.addressable_set: - id: addr1 - red: 100% - green: 100% - blue: 0% - - delay: 100ms - - light.addressable_set: - id: addr1 - red: 0% - green: 100% - blue: 0% - - - platform: fastled_spi - id: addr2 - chipset: WS2801 - data_pin: - allow_other_uses: true - number: GPIO23 - clock_pin: - number: GPIO22 - allow_other_uses: true - data_rate: 2MHz - num_leds: 60 - rgb_order: BRG - name: FastLED SPI Light - - platform: neopixelbus - id: addr3 - name: Neopixelbus Light - gamma_correct: 2.8 - color_correct: [0.0, 0.0, 0.0, 0.0] - default_transition_length: 10s - power_supply: atx_power_supply - effects: - - addressable_flicker: - name: Flicker Effect With Custom Values - update_interval: 16ms - intensity: 5% - type: GRBW - variant: SK6812 - method: ESP32_I2S_0 - num_leds: 60 - pin: - allow_other_uses: true - number: GPIO23 - - platform: partition - name: Partition Light - segments: - - id: addr1 - from: 0 - to: 0 - - id: addr2 - from: 1 - to: 10 - - id: addr2 - from: 20 - to: 25 - - single_light_id: ${roomname}_lights - -canbus: - - platform: esp32_can - id: esp32_internal_can - rx_pin: GPIO04 - tx_pin: GPIO05 - can_id: 4 - bit_rate: 50kbps - -button: - - platform: template - name: Canbus Actions - on_press: - - canbus.send: "abc" - - canbus.send: [0, 1, 2] - - canbus.send: !lambda return {0, 1, 2}; diff --git a/tests/test1.yaml b/tests/test1.yaml deleted file mode 100644 index 79cb1bba2b..0000000000 --- a/tests/test1.yaml +++ /dev/null @@ -1,4427 +0,0 @@ ---- -substitutions: - devicename: test1 - sensorname: my - textname: template - roomname: living_room - -esphome: - name: test1 - name_add_mac_suffix: true - platform: ESP32 - board: nodemcu-32s - platformio_options: - board_build.partitions: huge_app.csv - on_boot: - priority: 150.0 - then: - - lambda: >- - ESP_LOGD("main", "ON BOOT!"); - on_shutdown: - then: - - lambda: >- - ESP_LOGD("main", "ON SHUTDOWN!"); - on_loop: - then: - - lambda: >- - ESP_LOGV("main", "ON LOOP!"); - build_path: build/test1 - -packages: - wifi: !include test_packages/test_packages_package_wifi.yaml - pkg_test: !include test_packages/test_packages_package1.yaml - -wifi: - networks: - - ssid: "MySSID" - password: "password1" - - ssid: "MySSID2" - password: "" - channel: 14 - bssid: "A1:63:95:47:D3:1D" - manual_ip: - static_ip: 192.168.178.230 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - dns1: 1.1.1.1 - dns2: 1.2.2.1 - domain: .local - reboot_timeout: 120s - power_save_mode: light - on_connect: - - light.turn_on: ${roomname}_lights - on_disconnect: - - light.turn_off: ${roomname}_lights - -network: - enable_ipv6: true - -mdns: - disabled: false - -mqtt: - broker: "192.168.178.84" - port: 1883 - username: "debug" - password: "debug" - client_id: someclient - use_abbreviations: false - discovery: true - discovery_retain: false - discovery_prefix: discovery - discovery_unique_id_generator: legacy - topic_prefix: helloworld - log_topic: - topic: helloworld/hi - level: INFO - birth_message: - will_message: - shutdown_message: - topic: topic/to/send/to - payload: hi - qos: 2 - retain: true - keepalive: 60s - reboot_timeout: 60s - on_message: - - topic: my/custom/topic - qos: 0 - then: - - lambda: >- - ESP_LOGD("main", "Got message %s", x.c_str()); - - topic: livingroom/ota_mode - then: - - deep_sleep.prevent - - deep_sleep.allow - - topic: livingroom/ota_mode - then: - - deep_sleep.enter: - on_json_message: - topic: the/topic - then: - - if: - condition: - - wifi.connected: - - mqtt.connected: - - light.is_on: kitchen - - light.is_off: kitchen - - fan.is_on: fan_speed - - fan.is_off: fan_speed - then: - - lambda: |- - int data = x["my_data"]; - ESP_LOGD("main", "The data is: %d", data); - - light.turn_on: - id: ${roomname}_lights - brightness: !lambda |- - float brightness = 1.0; - if (x.containsKey("brightness")) - brightness = x["brightness"]; - return brightness; - effect: !lambda |- - const char *effect = "None"; - if (x.containsKey("effect")) - effect = x["effect"]; - return effect; - - light.control: - id: ${roomname}_lights - # yamllint disable-line rule:line-length - brightness: !lambda "return id(${roomname}_lights).current_values.get_brightness() + 0.5;" - - light.dim_relative: - id: ${roomname}_lights - relative_brightness: 5% - - uart.write: - id: uart_0 - data: Hello World - - uart.write: - id: uart_0 - data: [0x00, 0x20, 0x30] - - uart.write: - id: uart_0 - data: !lambda |- - return {}; - - bluetooth_password.set: - id: my_ld2410 - password: abcdef - on_connect: - - light.turn_on: ${roomname}_lights - - mqtt.publish: - topic: some/topic - payload: Hello - on_disconnect: - - light.turn_off: ${roomname}_lights - -i2c: - sda: - allow_other_uses: true - number: 21 - scl: - allow_other_uses: true - number: 22 - scan: true - frequency: 100kHz - setup_priority: -100 - id: i2c_bus - -spi: - id: spi_bus - clk_pin: - allow_other_uses: true - number: GPIO21 - mosi_pin: - allow_other_uses: true - number: GPIO22 - miso_pin: - allow_other_uses: true - number: GPIO23 - -uart: - - tx_pin: - allow_other_uses: true - number: GPIO22 - inverted: true - rx_pin: - allow_other_uses: true - number: GPIO23 - inverted: true - baud_rate: 115200 - id: uart_0 - parity: NONE - data_bits: 8 - stop_bits: 1 - rx_buffer_size: 512 - debug: - dummy_receiver: true - direction: both - after: - bytes: 50 - timeout: 500ms - delimiter: "\r\n" - sequence: - - lambda: UARTDebug::log_hex(direction, bytes, ':'); - - lambda: UARTDebug::log_string(direction, bytes); - - lambda: UARTDebug::log_int(direction, bytes, ','); - - lambda: UARTDebug::log_binary(direction, bytes, ';'); - - id: ld2410_uart - tx_pin: - allow_other_uses: true - number: 18 - rx_pin: - allow_other_uses: true - number: 23 - baud_rate: 256000 - parity: NONE - stop_bits: 1 - - id: dfrobot_mmwave_uart - tx_pin: - allow_other_uses: true - number: 14 - rx_pin: - allow_other_uses: true - number: 27 - baud_rate: 115200 - - id: ld2420_uart - tx_pin: - allow_other_uses: true - number: 17 - rx_pin: - allow_other_uses: true - number: 16 - baud_rate: 115200 - parity: NONE - stop_bits: 1 - - id: gcja5_uart - rx_pin: GPIO10 - parity: EVEN - baud_rate: 9600 - -safe_mode: - num_attempts: 3 - reboot_timeout: 2min - -ota: - - platform: esphome - password: "superlongpasswordthatnoonewillknow" - port: 3286 - on_state_change: - then: - lambda: >- - ESP_LOGD("ota", "State %d", state); - on_begin: - then: - logger.log: OTA begin - on_progress: - then: - lambda: >- - ESP_LOGD("ota", "Got progress %f", x); - on_end: - then: - logger.log: OTA end - on_error: - then: - lambda: >- - ESP_LOGD("ota", "Got error code %d", x); - -logger: - baud_rate: 0 - level: VERBOSE - logs: - mqtt.component: DEBUG - mqtt.client: ERROR - -web_server: - port: 8080 - version: 2 - -power_supply: - id: atx_power_supply - enable_time: 20ms - keep_on_time: 10s - pin: - number: 13 - allow_other_uses: true - inverted: true - -deep_sleep: - run_duration: 20s - sleep_duration: 50s - wakeup_pin: - allow_other_uses: true - number: GPIO2 - ignore_strapping_warning: true - wakeup_pin_mode: INVERT_WAKEUP - -ads1115: - address: 0x48 - i2c_id: i2c_bus - -ads1118: - spi_id: spi_bus - cs_pin: - allow_other_uses: true - number: GPIO12 - -as5600: - i2c_id: i2c_bus - dir_pin: - number: 27 - allow_other_uses: true - direction: clockwise - start_position: 90deg - range: 180deg - watchdog: true - power_mode: low1 - hysteresis: lsb1 - slow_filter: 8x - fast_filter: lsb6 - -as3935_spi: - cs_pin: - ignore_strapping_warning: true - allow_other_uses: true - number: GPIO12 - irq_pin: - allow_other_uses: true - number: GPIO13 - -esp32_ble: - io_capability: keyboard_only - -esp32_ble_tracker: - -ble_client: - - mac_address: AA:BB:CC:DD:EE:FF - id: ble_foo - auto_connect: true - - mac_address: 11:22:33:44:55:66 - id: ble_blah - auto_connect: false - on_connect: - then: - - switch.turn_on: ble1_status - on_disconnect: - then: - - switch.turn_on: ble1_status - on_passkey_request: - then: - - ble_client.passkey_reply: - id: ble_blah - passkey: 123456 - on_passkey_notification: - then: - - logger.log: "Passkey notification received" - on_numeric_comparison_request: - then: - - ble_client.numeric_comparison_reply: - id: ble_blah - accept: true - - mac_address: C4:4F:33:11:22:33 - id: my_bedjet_ble_client - -bedjet: - - ble_client_id: my_bedjet_ble_client - id: my_bedjet_client - time_id: sntp_time -mcp23s08: - - id: mcp23s08_hub - cs_pin: - ignore_strapping_warning: true - number: GPIO12 - allow_other_uses: true - deviceaddress: 0 - -mcp23s17: - - id: mcp23s17_hub - cs_pin: - ignore_strapping_warning: true - number: GPIO12 - allow_other_uses: true - deviceaddress: 1 - -micronova: - enable_rx_pin: - allow_other_uses: true - number: 4 - uart_id: uart_0 - -dfrobot_sen0395: - - id: mmwave - uart_id: dfrobot_mmwave_uart - -sensor: - - platform: xgzp68xx - i2c_id: i2c_bus - temperature: - name: Pressure Temperature - pressure: - name: Differential pressure - k_value: 4096 - - - platform: pmwcs3 - i2c_id: i2c_bus - e25: - name: pmwcs3_e25 - ec: - name: pmwcs3_ec - temperature: - name: pmwcs3_temperature - vwc: - name: pmwcs3_vwc - - platform: gcja5 - pm_1_0: - name: "Particulate Matter <1.0µm Concentration" - pm_2_5: - name: "Particulate Matter <2.5µm Concentration" - pm_10_0: - name: "Particulate Matter <10.0µm Concentration" - pmc_0_5: - name: "PMC 0.5" - pmc_1_0: - name: "PMC 1.0" - pmc_2_5: - name: "PMC 2.5" - pmc_5_0: - name: "PMC 5.0" - pmc_10_0: - name: "PMC 10.0" - uart_id: gcja5_uart - - platform: internal_temperature - name: Internal Temperature - - platform: ble_client - type: characteristic - ble_client_id: ble_foo - name: Green iTag btn - service_uuid: ffe0 - characteristic_uuid: ffe1 - descriptor_uuid: ffe2 - notify: true - update_interval: never - lambda: |- - ESP_LOGD("main", "Length of data is %i", x.size()); - return x[0]; - on_notify: - then: - - lambda: |- - ESP_LOGD("green_btn", "Button was pressed, val%f", x); - - platform: ble_client - type: rssi - ble_client_id: ble_foo - name: Green iTag RSSI - update_interval: 15s - - platform: adc - pin: A0 - name: Living Room Brightness - update_interval: "1:01" - attenuation: 2.5db - unit_of_measurement: "°C" - icon: "mdi:water-percent" - accuracy_decimals: 5 - expire_after: 120s - setup_priority: -100 - force_update: true - filters: - - offset: 2.0 - - multiply: 1.2 - - calibrate_linear: - datapoints: - - 0.0 -> 0.0 - - 40.0 -> 45.0 - - 100.0 -> 102.5 - - clamp: - min_value: -100 - max_value: 100 - - filter_out: 42.0 - - filter_out: nan - - median: - window_size: 5 - send_every: 5 - send_first_at: 3 - - min: - window_size: 5 - send_every: 5 - send_first_at: 3 - - max: - window_size: 5 - send_every: 5 - send_first_at: 3 - - sliding_window_moving_average: - window_size: 15 - send_every: 15 - send_first_at: 15 - - exponential_moving_average: - alpha: 0.1 - send_every: 15 - send_first_at: 15 - - throttle_average: 60s - - throttle: 1s - - heartbeat: 5s - - debounce: 0.1s - - delta: 5.0 - - delta: 1% - - or: - - throttle: 1s - - delta: 5.0 - - lambda: return x * (9.0/5.0) + 32.0; - on_value: - then: - # yamllint disable rule:line-length - - lambda: |- - ESP_LOGD("main", "Got value %f", x); - id(${sensorname}_sensor).publish_state(42.0); - ESP_LOGI("main", "Value of my sensor: %f", id(${sensorname}_sensor).state); - ESP_LOGI("main", "Raw Value of my sensor: %f", id(${sensorname}_sensor).state); - # yamllint enable rule:line-length - on_value_range: - above: 5 - below: 10 - then: - - lambda: >- - ESP_LOGD("main", "Got value range %f", x); - - wait_until: wifi.connected - - wait_until: - condition: - binary_sensor.is_on: binary_sensor1 - timeout: 1s - on_raw_value: - - lambda: >- - ESP_LOGD("main", "Got raw value %f", x); - - logger.log: - level: DEBUG - format: Got raw value %f - args: ["x"] - - logger.log: Got raw value NAN - - mqtt.publish: - topic: some/topic - payload: Hello - qos: 2 - retain: true - - platform: esp32_hall - name: ESP32 Hall Sensor - - platform: ads1115 - multiplexer: A0_A1 - gain: 1.024 - id: ${sensorname}_sensor - filters: - state_topic: hi/me - retain: false - availability: - - platform: ads1118 - name: ads1118 adc - multiplexer: A0_A1 - gain: 1.024 - type: adc - - platform: ads1118 - name: ads1118 temperature - type: temperature - - platform: as5600 - name: AS5600 Position - raw_position: - name: AS5600 Raw Position - gain: - name: AS5600 Gain - magnitude: - name: AS5600 Magnitude - status: - name: AS5600 Status - - platform: as7341 - update_interval: 15s - gain: X8 - atime: 120 - astep: 99 - f1: - name: F1 - f2: - name: F2 - f3: - name: F3 - f4: - name: F4 - f5: - name: F5 - f6: - name: F6 - f7: - name: F7 - f8: - name: F8 - clear: - name: Clear - nir: - name: NIR - i2c_id: i2c_bus - - platform: atm90e26 - cs_pin: - allow_other_uses: true - number: 5 - voltage: - name: Line Voltage - current: - name: CT Amps - power: - name: Active Watts - power_factor: - name: Power Factor - frequency: - name: Line Frequency - line_frequency: 50Hz - meter_constant: 1000 - pl_const: 1429876 - gain_pga: 1X - gain_metering: 7481 - gain_voltage: 26400 - gain_ct: 31251 - - platform: atm90e32 - cs_pin: - allow_other_uses: true - number: 5 - phase_a: - voltage: - name: EMON Line Voltage A - current: - name: EMON CT1 Current - power: - name: EMON Active Power CT1 - reactive_power: - name: EMON Reactive Power CT1 - power_factor: - name: EMON Power Factor CT1 - gain_voltage: 7305 - gain_ct: 27961 - phase_b: - current: - name: EMON CT2 Current - power: - name: EMON Active Power CT2 - reactive_power: - name: EMON Reactive Power CT2 - power_factor: - name: EMON Power Factor CT2 - gain_voltage: 7305 - gain_ct: 27961 - phase_c: - current: - name: EMON CT3 Current - power: - name: EMON Active Power CT3 - reactive_power: - name: EMON Reactive Power CT3 - power_factor: - name: EMON Power Factor CT3 - gain_voltage: 7305 - gain_ct: 27961 - frequency: - name: EMON Line Frequency - chip_temperature: - name: EMON Chip Temp A - line_frequency: 60Hz - current_phases: 3 - gain_pga: 2X - - platform: bh1750 - name: Living Room Brightness 3 - internal: true - address: 0x23 - update_interval: 30s - qos: 2 - retain: false - availability: - state_topic: livingroom/custom_state_topic - i2c_id: i2c_bus - - platform: max44009 - name: Outside Brightness 1 - internal: true - address: 0x4A - update_interval: 30s - mode: low_power - i2c_id: i2c_bus - - platform: bme680 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - humidity: - name: Outside Humidity - gas_resistance: - name: Outside Gas Sensor - address: 0x77 - heater: - temperature: 320 - duration: 150ms - update_interval: 15s - i2c_id: i2c_bus - - platform: bmp085 - temperature: - name: Outside Temperature - pressure: - name: Outside Pressure - filters: - - lambda: >- - return x / powf(1.0 - (x / 44330.0), 5.255); - update_interval: 15s - i2c_id: i2c_bus - - platform: bmp280 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - address: 0x77 - update_interval: 15s - iir_filter: 16x - i2c_id: i2c_bus - - platform: dht - pin: - allow_other_uses: true - number: GPIO26 - temperature: - id: dht_temperature - name: Living Room Temperature 3 - humidity: - id: dht_humidity - name: Living Room Humidity 3 - model: AM2302 - update_interval: 15s - - platform: dht12 - temperature: - name: Living Room Temperature 4 - humidity: - name: Living Room Humidity 4 - update_interval: 15s - i2c_id: i2c_bus - - platform: duty_cycle - pin: - allow_other_uses: true - number: GPIO25 - name: Duty Cycle Sensor - - platform: ee895 - co2: - name: Office CO2 1 - temperature: - name: Office Temperature 1 - pressure: - name: Office Pressure 1 - address: 0x5F - i2c_id: i2c_bus - - platform: esp32_hall - name: ESP32 Hall Sensor - update_interval: 15s - - platform: ens210 - temperature: - name: Living Room Temperature 5 - humidity: - name: Living Room Humidity 5 - update_interval: 15s - i2c_id: i2c_bus - - platform: hdc1080 - temperature: - name: Living Room Temperature 6 - humidity: - name: Living Room Humidity 5 - update_interval: 15s - i2c_id: i2c_bus - - platform: hlw8012 - sel_pin: - allow_other_uses: true - number: 5 - cf_pin: - allow_other_uses: true - number: 14 - cf1_pin: - allow_other_uses: true - number: 13 - current: - name: HLW8012 Current - voltage: - name: HLW8012 Voltage - power: - name: HLW8012 Power - id: hlw8012_power - energy: - name: HLW8012 Energy - id: hlw8012_energy - update_interval: 15s - current_resistor: 0.001 ohm - voltage_divider: 2351 - change_mode_every: "never" - initial_mode: VOLTAGE - model: hlw8012 - - platform: total_daily_energy - power_id: hlw8012_power - name: HLW8012 Total Daily Energy - - platform: integration - sensor: hlw8012_power - name: Integration Sensor - time_unit: s - - platform: integration - sensor: hlw8012_power - name: Integration Sensor lazy - time_unit: s - - platform: hmc5883l - address: 0x68 - field_strength_x: - name: HMC5883L Field Strength X - field_strength_y: - name: HMC5883L Field Strength Y - field_strength_z: - name: HMC5883L Field Strength Z - heading: - name: HMC5883L Heading - range: 130uT - oversampling: 8x - update_interval: 15s - i2c_id: i2c_bus - - platform: honeywell_hih_i2c - temperature: - name: Living Room Temperature 7 - humidity: - name: Living Room Humidity 7 - update_interval: 15s - i2c_id: i2c_bus - - platform: honeywellabp - pressure: - name: Honeywell pressure - min_pressure: 0 - max_pressure: 15 - temperature: - name: Honeywell temperature - cs_pin: - allow_other_uses: true - number: GPIO5 - - platform: honeywellabp2_i2c - pressure: - name: Honeywell2 pressure - min_pressure: 0 - max_pressure: 16000 - transfer_function: A - temperature: - name: Honeywell temperature - i2c_id: i2c_bus - address: 0x28 - - platform: hte501 - temperature: - name: Office Temperature 2 - humidity: - name: Office Humidity 1 - address: 0x40 - i2c_id: i2c_bus - - platform: qmc5883l - address: 0x0D - field_strength_x: - name: QMC5883L Field Strength X - field_strength_y: - name: QMC5883L Field Strength Y - field_strength_z: - name: QMC5883L Field Strength Z - heading: - name: QMC5883L Heading - range: 800uT - oversampling: 256x - update_interval: 15s - i2c_id: i2c_bus - - platform: hx711 - name: HX711 Value - dout_pin: - allow_other_uses: true - number: GPIO23 - clk_pin: - allow_other_uses: true - number: GPIO25 - gain: 128 - update_interval: 15s - - platform: ina219 - address: 0x40 - shunt_resistance: 0.1 ohm - current: - name: INA219 Current - power: - name: INA219 Power - bus_voltage: - name: INA219 Bus Voltage - shunt_voltage: - name: INA219 Shunt Voltage - max_voltage: 32.0V - max_current: 3.2A - update_interval: 15s - i2c_id: i2c_bus - - platform: ina226 - address: 0x40 - shunt_resistance: 0.1 ohm - current: - name: INA226 Current - power: - name: INA226 Power - bus_voltage: - name: INA226 Bus Voltage - shunt_voltage: - name: INA226 Shunt Voltage - max_current: 3.2A - update_interval: 15s - i2c_id: i2c_bus - - platform: ina3221 - address: 0x40 - channel_1: - shunt_resistance: 0.1 ohm - current: - name: INA3221 Channel 1 Current - power: - name: INA3221 Channel 1 Power - bus_voltage: - name: INA3221 Channel 1 Bus Voltage - shunt_voltage: - name: INA3221 Channel 1 Shunt Voltage - update_interval: 15s - i2c_id: i2c_bus - - platform: kmeteriso - temperature: - name: Outside Temperature - internal_temperature: - name: Internal Ttemperature - update_interval: 15s - i2c_id: i2c_bus - - platform: combination - type: kalman - name: Kalman-filtered temperature - process_std_dev: 0.00139 - sources: - - source: scd30_temperature - error: !lambda |- - return 0.4 + std::abs(x - 25) * 0.023; - - source: scd4x_temperature - error: 1.5 - - platform: combination - type: linear - name: Linearly combined temperatures - sources: - - source: scd30_temperature - coeffecient: !lambda |- - return 0.4 + std::abs(x - 25) * 0.023; - - source: scd4x_temperature - coeffecient: 1.5 - - platform: combination - type: max - name: Max of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: mean - name: Mean of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: median - name: Median of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: min - name: Min of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: most_recently_updated - name: Most recently updated of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: range - name: Range of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: combination - type: sum - name: Sum of combined temperatures - sources: - - source: scd30_temperature - - source: scd4x_temperature - - platform: htu21d - temperature: - name: Living Room Temperature 6 - humidity: - name: Living Room Humidity 6 - heater: - name: Living Room Heater 6 - update_interval: 15s - i2c_id: i2c_bus - - platform: max6675 - name: Living Room Temperature - cs_pin: - allow_other_uses: true - number: GPIO23 - update_interval: 15s - - platform: max31855 - name: Den Temperature - cs_pin: - allow_other_uses: true - number: GPIO23 - update_interval: 15s - reference_temperature: - name: MAX31855 Internal Temperature - - platform: max31856 - name: BBQ Temperature - cs_pin: - allow_other_uses: true - number: GPIO17 - update_interval: 15s - mains_filter: 50Hz - - platform: max31865 - name: Water Tank Temperature - cs_pin: - allow_other_uses: true - number: GPIO23 - update_interval: 15s - reference_resistance: 430 Ω - rtd_nominal_resistance: 100 Ω - - platform: mhz19 - uart_id: uart_0 - co2: - name: MH-Z19 CO2 Value - temperature: - name: MH-Z19 Temperature - update_interval: 15s - automatic_baseline_calibration: false - - platform: mpu6050 - address: 0x68 - accel_x: - name: MPU6050 Accel X - accel_y: - name: MPU6050 Accel Y - accel_z: - name: MPU6050 Accel z - gyro_x: - name: MPU6050 Gyro X - gyro_y: - name: MPU6050 Gyro Y - gyro_z: - name: MPU6050 Gyro z - temperature: - name: MPU6050 Temperature - i2c_id: i2c_bus - - platform: mpu6886 - address: 0x68 - accel_x: - name: MPU6886 Accel X - accel_y: - name: MPU6886 Accel Y - accel_z: - name: MPU6886 Accel z - gyro_x: - name: MPU6886 Gyro X - gyro_y: - name: MPU6886 Gyro Y - gyro_z: - name: MPU6886 Gyro z - temperature: - name: MPU6886 Temperature - i2c_id: i2c_bus - - platform: bmi160 - address: 0x68 - acceleration_x: - name: BMI160 Accel X - acceleration_y: - name: BMI160 Accel Y - acceleration_z: - name: BMI160 Accel z - gyroscope_x: - name: BMI160 Gyro X - gyroscope_y: - name: BMI160 Gyro Y - gyroscope_z: - name: BMI160 Gyro z - temperature: - name: BMI160 Temperature - i2c_id: i2c_bus - - platform: mmc5603 - address: 0x30 - field_strength_x: - name: HMC5883L Field Strength X - field_strength_y: - name: HMC5883L Field Strength Y - field_strength_z: - name: HMC5883L Field Strength Z - i2c_id: i2c_bus - - platform: dps310 - temperature: - name: DPS310 Temperature - pressure: - name: DPS310 Pressure - address: 0x77 - update_interval: 15s - i2c_id: i2c_bus - - platform: ms5611 - temperature: - name: Outside Temperature - pressure: - name: Outside Pressure - address: 0x77 - update_interval: 15s - i2c_id: i2c_bus - - platform: pmsa003i - pm_1_0: - name: PMSA003i PM1.0 - pm_2_5: - name: PMSA003i PM2.5 - pm_10_0: - name: PMSA003i PM10.0 - pmc_0_3: - name: PMSA003i PMC <0.3µm - pmc_0_5: - name: PMSA003i PMC <0.5µm - pmc_1_0: - name: PMSA003i PMC <1µm - pmc_2_5: - name: PMSA003i PMC <2.5µm - pmc_5_0: - name: PMSA003i PMC <5µm - pmc_10_0: - name: PMSA003i PMC <10µm - address: 0x12 - standard_units: true - i2c_id: i2c_bus - - platform: pulse_counter - name: Pulse Counter - pin: - ignore_strapping_warning: true - number: GPIO12 - allow_other_uses: true - count_mode: - rising_edge: INCREMENT - falling_edge: DECREMENT - internal_filter: 13us - update_interval: 15s - - platform: pulse_meter - name: Pulse Meter - id: pulse_meter_sensor - pin: - ignore_strapping_warning: true - number: GPIO12 - allow_other_uses: true - internal_filter: 100ms - timeout: 2 min - on_value: - - pulse_meter.set_total_pulses: - id: pulse_meter_sensor - value: 12345 - total: - name: Pulse Meter Total - - platform: qmp6988 - temperature: - name: Living Temperature QMP - oversampling: 32x - pressure: - name: Living Pressure QMP - oversampling: 2x - address: 0x70 - update_interval: 30s - iir_filter: 16x - i2c_id: i2c_bus - - platform: rotary_encoder - name: Rotary Encoder - id: rotary_encoder1 - pin_a: - allow_other_uses: true - number: GPIO23 - pin_b: - allow_other_uses: true - number: GPIO25 - pin_reset: - allow_other_uses: true - number: GPIO25 - filters: - - or: - - debounce: 0.1s - - delta: 10 - resolution: 4 - min_value: -10 - max_value: 30 - on_value: - - sensor.rotary_encoder.set_value: - id: rotary_encoder1 - value: 10 - - sensor.rotary_encoder.set_value: - id: rotary_encoder1 - value: !lambda "return -1;" - on_clockwise: - - logger.log: Clockwise - - display_menu.down: test_lcd_menu - - display_menu.down: test_graphical_display_menu - on_anticlockwise: - - logger.log: Anticlockwise - - display_menu.up: test_lcd_menu - - display_menu.up: test_graphical_display_menu - - platform: pulse_width - name: Pulse Width - pin: - allow_other_uses: true - number: GPIO12 - - platform: sm300d2 - uart_id: uart_0 - co2: - name: SM300D2 CO2 Value - formaldehyde: - name: SM300D2 Formaldehyde Value - tvoc: - name: SM300D2 TVOC Value - pm_2_5: - name: SM300D2 PM2.5 Value - pm_10_0: - name: SM300D2 PM10 Value - temperature: - name: SM300D2 Temperature Value - humidity: - name: SM300D2 Humidity Value - update_interval: 60s - - platform: sht3xd - temperature: - name: Living Room Temperature 8 - humidity: - name: Living Room Humidity 8 - address: 0x44 - i2c_id: i2c_bus - update_interval: 15s - - platform: sts3x - name: Living Room Temperature 9 - address: 0x4A - i2c_id: i2c_bus - - platform: scd30 - co2: - name: Living Room CO2 9 - temperature: - id: scd30_temperature - name: Living Room Temperature 9 - humidity: - name: Living Room Humidity 9 - address: 0x61 - update_interval: 15s - automatic_self_calibration: true - altitude_compensation: 10m - ambient_pressure_compensation: 961mBar - temperature_offset: 4.2C - i2c_id: i2c_bus - - platform: scd4x - id: scd40 - co2: - name: SCD4X CO2 - temperature: - id: scd4x_temperature - name: SCD4X Temperature - humidity: - name: SCD4X Humidity - update_interval: 15s - automatic_self_calibration: true - altitude_compensation: 10m - ambient_pressure_compensation: 961mBar - temperature_offset: 4.2C - i2c_id: i2c_bus - - platform: sfa30 - formaldehyde: - name: "SFA30 formaldehyde" - temperature: - name: "SFA30 temperature" - humidity: - name: "SFA30 humidity" - i2c_id: i2c_bus - address: 0x5D - update_interval: 30s - - platform: sen0321 - name: Workshop Ozone Sensor - id: sen0321_ozone - update_interval: 10s - i2c_id: i2c_bus - - platform: sgp30 - eco2: - name: Workshop eCO2 - accuracy_decimals: 1 - tvoc: - name: Workshop TVOC - accuracy_decimals: 1 - address: 0x58 - update_interval: 5s - i2c_id: i2c_bus - - platform: sps30 - pm_1_0: - name: Workshop PM <1µm Weight concentration - id: workshop_PM_1_0 - pm_2_5: - name: Workshop PM <2.5µm Weight concentration - id: workshop_PM_2_5 - pm_4_0: - name: Workshop PM <4µm Weight concentration - id: workshop_PM_4_0 - pm_10_0: - name: Workshop PM <10µm Weight concentration - id: workshop_PM_10_0 - pmc_0_5: - name: Workshop PM <0.5µm Number concentration - id: workshop_PMC_0_5 - pmc_1_0: - name: Workshop PM <1µm Number concentration - id: workshop_PMC_1_0 - pmc_2_5: - name: Workshop PM <2.5µm Number concentration - id: workshop_PMC_2_5 - pmc_4_0: - name: Workshop PM <4µm Number concentration - id: workshop_PMC_4_0 - pmc_10_0: - name: Workshop PM <10µm Number concentration - id: workshop_PMC_10_0 - address: 0x69 - update_interval: 10s - i2c_id: i2c_bus - - platform: sht4x - temperature: - name: SHT4X Temperature - humidity: - name: SHT4X Humidity - address: 0x44 - update_interval: 15s - i2c_id: i2c_bus - - platform: shtcx - temperature: - name: Living Room Temperature 10 - humidity: - name: Living Room Humidity 10 - address: 0x70 - update_interval: 15s - i2c_id: i2c_bus - - platform: template - name: Template Sensor - state_class: measurement - id: template_sensor - lambda: |- - if (id(ultrasonic_sensor1).state > 1) { - return 42.0; - } else { - return {}; - } - update_interval: 15s - on_value: - - sensor.template.publish: - id: template_sensor - state: 43.0 - - sensor.template.publish: - id: template_sensor - state: !lambda "return NAN;" - - platform: tsl2561 - name: TSL2561 Ambient Light - address: 0x39 - update_interval: 15s - is_cs_package: true - integration_time: 402ms - gain: 16x - i2c_id: i2c_bus - - platform: tsl2591 - id: this_little_light_of_mine - address: 0x29 - update_interval: 15s - integration_time: 600ms - gain: high - visible: - name: tsl2591 visible - id: tsl2591_vis - unit_of_measurement: pH - infrared: - name: tsl2591 infrared - id: tsl2591_ir - full_spectrum: - name: tsl2591 full_spectrum - id: tsl2591_fs - calculated_lux: - name: tsl2591 calculated_lux - id: tsl2591_cl - i2c_id: i2c_bus - - platform: veml3235 - id: veml3235_sensor - name: VEML3235 Light Sensor - i2c_id: i2c_bus - auto_gain: true - auto_gain_threshold_high: 90% - auto_gain_threshold_low: 15% - digital_gain: 1X - gain: 1X - integration_time: 50ms - - platform: tee501 - name: Office Temperature 3 - address: 0x48 - i2c_id: i2c_bus - - platform: ultrasonic - trigger_pin: - allow_other_uses: true - number: GPIO25 - echo_pin: - number: GPIO23 - allow_other_uses: true - inverted: true - name: Ultrasonic Sensor - timeout: 5.5m - id: ultrasonic_sensor1 - - platform: uptime - name: Uptime Sensor - - id: !extend ${devicename}_uptime_pcg - unit_of_measurement: s - - platform: wifi_signal - name: WiFi Signal Sensor - update_interval: 15s - - platform: mqtt_subscribe - name: MQTT Subscribe Sensor 1 - topic: mqtt/topic - id: the_sensor - qos: 2 - on_value: - - mqtt.publish_json: - topic: the/topic - payload: |- - root["key"] = id(the_sensor).state; - root["greeting"] = "Hello World"; - - platform: sds011 - uart_id: uart_0 - pm_2_5: - name: SDS011 PM2.5 - pm_10_0: - name: SDS011 PM10.0 - update_interval: 5min - rx_only: false - - platform: ccs811 - eco2: - name: CCS811 eCO2 - tvoc: - name: CCS811 TVOC - update_interval: 30s - baseline: 0x4242 - i2c_id: i2c_bus - - platform: tx20 - wind_speed: - name: Windspeed - wind_direction_degrees: - name: Winddirection Degrees - pin: - number: GPIO04 - mode: INPUT - allow_other_uses: true - - platform: zyaura - clock_pin: - allow_other_uses: true - number: GPIO5 - data_pin: - allow_other_uses: true - number: GPIO4 - co2: - name: ZyAura CO2 - temperature: - name: ZyAura Temperature - humidity: - name: ZyAura Humidity - - platform: as3935 - lightning_energy: - name: Lightning Energy - distance: - name: Distance Storm - - platform: tmp117 - name: TMP117 Temperature - update_interval: 5s - i2c_id: i2c_bus - - platform: hm3301 - pm_1_0: - name: PM1.0 - pm_2_5: - name: PM2.5 - pm_10_0: - name: PM10.0 - aqi: - name: AQI - calculation_type: CAQI - i2c_id: i2c_bus - - platform: teleinfo - tag_name: HCHC - name: hchc - unit_of_measurement: Wh - icon: mdi:flash - teleinfo_id: myteleinfo - - platform: mcp9808 - name: MCP9808 Temperature - update_interval: 15s - i2c_id: i2c_bus - - platform: ezo - id: ph_ezo - address: 99 - unit_of_measurement: pH - i2c_id: i2c_bus - - platform: sdp3x - name: HVAC Filter Pressure drop - id: filter_pressure - update_interval: 5s - accuracy_decimals: 3 - i2c_id: i2c_bus - - platform: cs5460a - id: cs5460a1 - current: - name: Socket current - voltage: - name: Mains voltage - power: - name: Socket power - on_value: - then: - cs5460a.restart: cs5460a1 - samples: 1600 - pga_gain: 10X - current_gain: 0.01 - voltage_gain: 0.000573 - current_hpf: true - voltage_hpf: true - phase_offset: 20 - pulse_energy: 0.01 kWh - cs_pin: - mcp23xxx: mcp23017_hub - number: 14 - - platform: max9611 - i2c_id: i2c_bus - shunt_resistance: 0.2 ohm - gain: 1X - voltage: - name: Max9611 Voltage - current: - name: Max9611 Current - power: - name: Max9611 Watts - temperature: - name: Max9611 Temp - update_interval: 1s - - platform: mlx90614 - i2c_id: i2c_bus - ambient: - name: Ambient - object: - name: Object - emissivity: 1.0 - - platform: mpl3115a2 - i2c_id: i2c_bus - temperature: - name: "MPL3115A2 Temperature" - pressure: - name: "MPL3115A2 Pressure" - update_interval: 10s - - platform: alpha3 - ble_client_id: ble_foo - flow: - name: "Radiator Pump Flow" - head: - name: "Radiator Pump Head" - power: - name: "Radiator Pump Power" - speed: - name: "Radiator Pump Speed" - - platform: ld2410 - light: - name: light - moving_distance: - name: "Moving distance (cm)" - still_distance: - name: "Still Distance (cm)" - moving_energy: - name: "Move Energy (%)" - still_energy: - name: "Still Energy (%)" - detection_distance: - name: "Distance Detection (cm)" - g0: - move_energy: - name: g0 move energy - still_energy: - name: g0 still energy - g1: - move_energy: - name: g1 move energy - still_energy: - name: g1 still energy - g2: - move_energy: - name: g2 move energy - still_energy: - name: g2 still energy - g3: - move_energy: - name: g3 move energy - still_energy: - name: g3 still energy - g4: - move_energy: - name: g4 move energy - still_energy: - name: g4 still energy - g5: - move_energy: - name: g5 move energy - still_energy: - name: g5 still energy - g6: - move_energy: - name: g6 move energy - still_energy: - name: g6 still energy - g7: - move_energy: - name: g7 move energy - still_energy: - name: g7 still energy - g8: - move_energy: - name: g8 move energy - still_energy: - name: g8 still energy - - - platform: ld2420 - moving_distance: - name: "Moving distance (cm)" - - platform: sen21231 - name: "Person Sensor" - i2c_id: i2c_bus - - platform: fs3000 - name: "Air Velocity" - model: 1005 - update_interval: 60s - i2c_id: i2c_bus - - platform: absolute_humidity - name: DHT Absolute Humidity - temperature: dht_temperature - humidity: dht_humidity - - platform: hyt271 - i2c_id: i2c_bus - temperature: - name: "Temperature hyt271" - id: temp_etuve - humidity: - name: "Humidity hyt271" - - platform: iaqcore - i2c_id: i2c_bus - co2: - name: "iAQ Core CO2 Sensor" - tvoc: - name: "iAQ Core TVOC Sensor" - - platform: tmp1075 - name: "Temperature TMP1075" - update_interval: 10s - i2c_id: i2c_bus - conversion_rate: 27.5ms - alert: - limit_low: 50 - limit_high: 75 - fault_count: 1 - polarity: active_high - function: comparator - - platform: zio_ultrasonic - name: "Distance" - update_interval: 60s - i2c_id: i2c_bus - - platform: bmp581 - i2c_id: i2c_bus - temperature: - name: "BMP581 Temperature" - iir_filter: 2x - pressure: - name: "BMP581 Pressure" - oversampling: 128x - - platform: debug - free: - name: "Heap Free" - block: - name: "Heap Max Block" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" - - platform: mmc5983 - i2c_id: i2c_bus - field_strength_x: - name: "Magnet X" - id: magnet_x - field_strength_y: - name: "Magnet Y" - id: magnet_y - field_strength_z: - name: "Magnet Z" - id: magnet_z - - platform: micronova - room_temperature: - name: Room Temperature - fumes_temperature: - name: Fumes Temperature - water_temperature: - name: Water temperature - water_pressure: - name: Water pressure - stove_power: - name: Stove Power - fan_speed: - fan_rpm_offset: 240 - name: Fan RPM - memory_address_sensor: - memory_location: 0x20 - memory_address: 0x7d - name: Adres sensor - - platform: ade7880 - i2c_id: i2c_bus - irq0_pin: - number: GPIO13 - allow_other_uses: true - irq1_pin: - number: GPIO5 - allow_other_uses: true - reset_pin: - number: GPIO16 - allow_other_uses: true - frequency: 60Hz - phase_a: - name: Channel A - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3116628 - voltage_gain: -757178 - power_gain: -1344457 - phase_angle: 188 - phase_b: - name: Channel B - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3133655 - voltage_gain: -755235 - power_gain: -1345638 - phase_angle: 188 - phase_c: - name: Channel C - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3111158 - voltage_gain: -743813 - power_gain: -1351437 - phase_angle: 180 - neutral: - name: Neutral - current: Current - calibration: - current_gain: 3189 - -psram: - -esp32_touch: - setup_mode: false - iir_filter: 10ms - sleep_duration: 27ms - measurement_duration: 8ms - low_voltage_reference: 0.5V - high_voltage_reference: 2.7V - voltage_attenuation: 1.5V - -binary_sensor: - - platform: gpio - name: "MCP23S08 Pin #1" - pin: - mcp23xxx: mcp23s08_hub - # Use pin number 1 - number: 1 - # One of INPUT or INPUT_PULLUP - mode: INPUT_PULLUP - inverted: false - - platform: gpio - name: "MCP23S17 Pin #1" - pin: - mcp23xxx: mcp23s17_hub - # Use pin number 1 - number: 1 - allow_other_uses: true - # One of INPUT or INPUT_PULLUP - mode: INPUT_PULLUP - inverted: false - - platform: gpio - name: "MCP23S17 Pin #1 with interrupt" - pin: - mcp23xxx: mcp23s17_hub - # Use pin number 1 - allow_other_uses: true - number: 1 - # One of INPUT or INPUT_PULLUP - mode: INPUT_PULLUP - inverted: false - interrupt: FALLING - - platform: gpio - pin: - allow_other_uses: true - number: GPIO9 - name: Living Room Window - device_class: window - filters: - - invert: - - delayed_on_off: 40ms - - delayed_on_off: - time_on: 10s - time_off: !lambda "return 1000;" - - delayed_on: 40ms - - delayed_off: 40ms - - delayed_on_off: !lambda "return 10;" - - delayed_on: !lambda "return 1000;" - - delayed_off: !lambda "return 0;" - - settle: 40ms - - settle: !lambda "return 10;" - on_press: - then: - - lambda: >- - ESP_LOGD("main", "Pressed"); - on_release: - then: - - lambda: >- - ESP_LOGD("main", "Released"); - on_click: - - min_length: 50ms - max_length: 350ms - then: - - lambda: >- - ESP_LOGD("main", "Clicked"); - - then: - - lambda: >- - ESP_LOGD("main", "Clicked"); - on_double_click: - - min_length: 50ms - max_length: 350ms - then: - - lambda: >- - ESP_LOGD("main", "Double Clicked"); - - then: - - lambda: >- - ESP_LOGD("main", "Double Clicked"); - on_multi_click: - - timing: - - ON for at most 1s - - OFF for at most 1s - - ON for at most 1s - - OFF for at least 0.2s - then: - - logger.log: - format: Multi Clicked TWO - level: warn - - timing: - - OFF for 1s to 2s - - ON for 1s to 2s - - OFF for at least 0.5s - then: - - logger.log: - format: Multi Clicked LONG SINGLE - level: warn - - timing: - - ON for at most 1s - - OFF for at least 0.5s - then: - - logger.log: - format: Multi Clicked SINGLE - level: warn - id: binary_sensor1 - - platform: gpio - pin: - number: GPIO9 - allow_other_uses: true - mode: INPUT_PULLUP - name: Living Room Window 2 - - platform: gpio - pin: - number: GPIO9 - allow_other_uses: true - mode: INPUT_OUTPUT_OPEN_DRAIN - name: Living Room Button - - platform: status - name: Living Room Status - - platform: esp32_touch - name: ESP32 Touch Pad GPIO27 - pin: GPIO27 - threshold: 1000 - id: btn_left - on_press: - - if: - condition: - display_menu.is_active: test_lcd_menu - then: - - display_menu.enter: test_lcd_menu - else: - - display_menu.left: test_lcd_menu - - display_menu.right: test_lcd_menu - - display_menu.show: test_lcd_menu - - if: - condition: - display_menu.is_active: test_graphical_display_menu - then: - - display_menu.enter: test_graphical_display_menu - else: - - display_menu.left: test_graphical_display_menu - - display_menu.right: test_graphical_display_menu - - display_menu.show: test_graphical_display_menu - - platform: template - name: Garage Door Open - id: garage_door - lambda: |- - if (isnan(id(${sensorname}_sensor).state)) { - // isnan checks if the ultrasonic sensor echo - // has timed out, resulting in a NaN (not a number) state - // in that case, return {} to indicate that we don't know. - return {}; - } else if (id(${sensorname}_sensor).state > 30) { - // Garage Door is open. - return true; - } else { - // Garage Door is closed. - return false; - } - on_press: - - binary_sensor.template.publish: - id: garage_door - state: false - - output.ledc.set_frequency: - id: gpio_19 - frequency: 500.0Hz - - output.ledc.set_frequency: - id: gpio_19 - frequency: !lambda "return 500.0;" - - platform: pn532 - pn532_id: pn532_bs - uid: 74-10-37-94 - name: PN532 NFC Tag - - platform: rdm6300 - uid: 7616525 - name: RDM6300 NFC Tag - - platform: gpio - name: PCF binary sensor - pin: - pcf8574: pcf8574_hub - number: 1 - mode: INPUT - inverted: true - - platform: gpio - name: PCA9554 binary sensor - pin: - pca9554: pca9554_hub - number: 1 - mode: INPUT - inverted: true - - platform: gpio - name: PCA6416A binary sensor - pin: - pca6416a: pca6416a_hub - number: 15 - mode: INPUT - inverted: true - - platform: gpio - name: MCP21 binary sensor - pin: - mcp23xxx: mcp23017_hub - number: 1 - allow_other_uses: true - mode: INPUT - inverted: true - - platform: gpio - name: MCP22 binary sensor - pin: - mcp23xxx: mcp23008_hub - number: 7 - mode: INPUT_PULLUP - inverted: false - - platform: gpio - name: MCP23 binary sensor - pin: - mcp23016: mcp23016_hub - number: 7 - mode: INPUT - inverted: false - - platform: gpio - name: Speed Fan Cycle binary sensor" - pin: - number: 18 - allow_other_uses: true - mode: - input: true - pulldown: true - on_press: - - fan.cycle_speed: - id: fan_speed - off_speed_cycle: false - - logger.log: "Cycle speed clicked" - - platform: remote_receiver - name: Raw Remote Receiver Test - raw: - code: - [ - 5685, - -4252, - 1711, - -2265, - 1712, - -2265, - 1711, - -2264, - 1712, - -2266, - 3700, - -2263, - 1712, - -4254, - 1711, - -4249, - 1715, - -2266, - 1710, - -2267, - 1709, - -2265, - 3704, - -4250, - 1712, - -4254, - 3700, - -2260, - 1714, - -2265, - 1712, - -2262, - 1714, - -2267, - 1709, - ] - - platform: remote_receiver - name: Coolix Test 1 - coolix: 0xB21F98 - - platform: remote_receiver - name: Coolix Test 2 - coolix: - first: 0xB2E003 - - platform: remote_receiver - name: Coolix Test 3 - coolix: - first: 0xB2E003 - second: 0xB21F98 - - platform: as3935 - name: Storm Alert - - platform: analog_threshold - name: Analog Trheshold 1 - sensor_id: template_sensor - threshold: - upper: 110 - lower: 90 - filters: - - delayed_on: 0s - - delayed_off: 10s - - platform: analog_threshold - name: Analog Trheshold 2 - sensor_id: template_sensor - threshold: 100 - filters: - - invert: - - platform: template - id: open_endstop_sensor - - platform: template - id: open_sensor - - platform: template - id: open_obstacle_sensor - - - platform: template - id: close_endstop_sensor - - platform: template - id: close_sensor - - platform: template - id: close_obstacle_sensor - - platform: ld2410 - has_target: - name: presence - has_moving_target: - name: movement - has_still_target: - name: still - out_pin_presence_status: - name: out pin presence status - - platform: qwiic_pir - i2c_id: i2c_bus - name: "Qwiic PIR Motion Sensor" - - platform: dfrobot_sen0395 - id: mmwave_detected_uart - dfrobot_sen0395_id: mmwave - - platform: nfc - nfcc_id: nfcc_pn7160_i2c - ndef_contains: pulse - name: MFC Tag 1 - - platform: nfc - nfcc_id: nfcc_pn7160_i2c - tag_id: pulse - name: MFC Tag 2 - - platform: nfc - nfcc_id: nfcc_pn7160_i2c - uid: 59-FC-AB-15 - name: MFC Tag 3 - -pca9685: - frequency: 500 - address: 0x0 - i2c_id: i2c_bus - -tlc59208f: - - address: 0x20 - id: tlc59208f_1 - i2c_id: i2c_bus - - address: 0x22 - id: tlc59208f_2 - i2c_id: i2c_bus - - address: 0x24 - id: tlc59208f_3 - i2c_id: i2c_bus - -my9231: - data_pin: - allow_other_uses: true - number: GPIO12 - clock_pin: - allow_other_uses: true - number: GPIO14 - num_channels: 6 - num_chips: 2 - bit_depth: 16 - -sm2235: - data_pin: - allow_other_uses: true - number: GPIO4 - clock_pin: - allow_other_uses: true - number: GPIO5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -sm2335: - data_pin: - allow_other_uses: true - number: GPIO4 - clock_pin: - allow_other_uses: true - number: GPIO5 - max_power_color_channels: 9 - max_power_white_channels: 9 - -bp1658cj: - data_pin: - allow_other_uses: true - number: GPIO3 - clock_pin: - allow_other_uses: true - number: GPIO5 - max_power_color_channels: 4 - max_power_white_channels: 6 - -bp5758d: - data_pin: - allow_other_uses: true - number: GPIO3 - clock_pin: - allow_other_uses: true - number: GPIO5 - -output: - - platform: gpio - pin: - allow_other_uses: true - number: GPIO26 - id: gpio_26 - power_supply: atx_power_supply - inverted: false - - platform: ledc - pin: - allow_other_uses: true - number: 19 - id: gpio_19 - frequency: 1500Hz - channel: 14 - max_power: 0.5 - - platform: pca9685 - id: pca_0 - channel: 0 - - platform: pca9685 - id: pca_1 - channel: 1 - - platform: pca9685 - id: pca_2 - channel: 2 - - platform: pca9685 - id: pca_3 - channel: 3 - - platform: pca9685 - id: pca_4 - channel: 4 - - platform: pca9685 - id: pca_5 - channel: 5 - - platform: pca9685 - id: pca_6 - channel: 6 - - platform: pca9685 - id: pca_7 - channel: 7 - - platform: tlc59208f - id: tlc_0 - channel: 0 - tlc59208f_id: tlc59208f_1 - - platform: tlc59208f - id: tlc_1 - channel: 1 - tlc59208f_id: tlc59208f_1 - - platform: tlc59208f - id: tlc_2 - channel: 2 - tlc59208f_id: tlc59208f_1 - - platform: tlc59208f - id: tlc_3 - channel: 0 - tlc59208f_id: tlc59208f_2 - - platform: tlc59208f - id: tlc_4 - channel: 1 - tlc59208f_id: tlc59208f_2 - - platform: tlc59208f - id: tlc_5 - channel: 2 - tlc59208f_id: tlc59208f_2 - - platform: tlc59208f - id: tlc_6 - channel: 0 - tlc59208f_id: tlc59208f_3 - - platform: tlc59208f - id: tlc_7 - channel: 1 - tlc59208f_id: tlc59208f_3 - - platform: tlc59208f - id: tlc_8 - channel: 2 - tlc59208f_id: tlc59208f_3 - - platform: gpio - id: id2 - pin: - pcf8574: pcf8574_hub - number: 0 - # allow_other_uses: true - mode: OUTPUT - inverted: false - - platform: gpio - id: id26 - pin: - pca9554: pca9554_hub - number: 0 - # allow_other_uses: true - mode: OUTPUT - inverted: false - - platform: gpio - id: id22 - pin: - mcp23xxx: mcp23017_hub - number: 0 - mode: OUTPUT - inverted: false - - platform: gpio - id: id23 - pin: - mcp23xxx: mcp23008_hub - number: 0 - mode: OUTPUT - inverted: false - - platform: gpio - id: id25 - pin: - mcp23016: mcp23016_hub - number: 0 - mode: OUTPUT - inverted: false - - platform: my9231 - id: my_0 - channel: 0 - - platform: my9231 - id: my_1 - channel: 1 - - platform: my9231 - id: my_2 - channel: 2 - - platform: my9231 - id: my_3 - channel: 3 - - platform: my9231 - id: my_4 - channel: 4 - - platform: my9231 - id: my_5 - channel: 5 - - platform: sm2235 - id: sm2235_red - channel: 1 - - platform: sm2235 - id: sm2235_green - channel: 0 - - platform: sm2235 - id: sm2235_blue - channel: 2 - - platform: sm2235 - id: sm2235_coldwhite - channel: 4 - - platform: sm2235 - id: sm2235_warmwhite - channel: 3 - - platform: sm2335 - id: sm2335_red - channel: 1 - - platform: sm2335 - id: sm2335_green - channel: 0 - - platform: sm2335 - id: sm2335_blue - channel: 2 - - platform: sm2335 - id: sm2335_coldwhite - channel: 4 - - platform: sm2335 - id: sm2335_warmwhite - channel: 3 - - platform: slow_pwm - id: id24 - pin: - allow_other_uses: true - number: GPIO26 - period: 15s - - platform: ac_dimmer - id: dimmer1 - gate_pin: - allow_other_uses: true - number: GPIO5 - zero_cross_pin: - allow_other_uses: true - number: GPIO26 - - platform: esp32_dac - pin: - allow_other_uses: true - number: GPIO25 - id: dac_output - - platform: mcp4725 - id: mcp4725_dac_output - i2c_id: i2c_bus - - platform: mcp4728 - id: mcp4728_dac_output_a - channel: A - vref: vdd - power_down: normal - - platform: mcp4728 - id: mcp4728_dac_output_b - channel: B - vref: internal - gain: X1 - power_down: gnd_1k - - platform: mcp4728 - id: mcp4728_dac_output_c - channel: C - vref: vdd - power_down: gnd_100k - - platform: mcp4728 - id: mcp4728_dac_output_d - channel: D - vref: internal - gain: X2 - power_down: gnd_500k - - platform: bp1658cj - id: bp1658cj_red - channel: 1 - - platform: bp1658cj - id: bp1658cj_green - channel: 2 - - platform: bp1658cj - id: bp1658cj_blue - channel: 0 - - platform: bp1658cj - id: bp1658cj_coldwhite - channel: 3 - - platform: bp1658cj - id: bp1658cj_warmwhite - channel: 4 - - platform: bp5758d - id: bp5758d_red - channel: 2 - current: 10 - - platform: bp5758d - id: bp5758d_green - channel: 3 - current: 10 - - platform: bp5758d - id: bp5758d_blue - channel: 1 - current: 10 - - platform: bp5758d - id: bp5758d_coldwhite - channel: 5 - current: 10 - - platform: bp5758d - id: bp5758d_warmwhite - channel: 4 - current: 10 - - platform: x9c - id: test_x9c - cs_pin: - allow_other_uses: true - number: GPIO25 - inc_pin: - allow_other_uses: true - number: GPIO26 - ud_pin: - allow_other_uses: true - number: GPIO27 - initial_value: 0.5 - -light: - - platform: binary - name: Desk Lamp - output: gpio_26 - effects: - - strobe: - - strobe: - name: My Strobe - colors: - - state: true - duration: 250ms - - state: false - duration: 250ms - on_turn_on: - - switch.template.publish: - id: livingroom_lights - state: true - on_turn_off: - - switch.template.publish: - id: livingroom_lights - state: true - - platform: monochromatic - name: Kitchen Lights - id: kitchen - output: gpio_19 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - - platform: rgb - name: Living Room Lights - id: ${roomname}_lights - red: pca_0 - green: pca_1 - blue: pca_2 - - platform: rgbw - name: Living Room Lights 2 - red: pca_3 - green: pca_4 - blue: pca_5 - white: pca_6 - color_interlock: true - - platform: rgbww - name: Living Room Lights 2 - red: pca_3 - green: pca_4 - blue: pca_5 - cold_white: pca_6 - warm_white: pca_6 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - name: Living Room Lights 2 - red: pca_3 - green: pca_4 - blue: pca_5 - color_temperature: pca_6 - white_brightness: pca_6 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - name: Living Room Lights 2 - cold_white: pca_6 - warm_white: pca_6 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - name: Living Room Lights 2 - color_temperature: pca_6 - brightness: pca_6 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - -remote_transmitter: - - pin: - allow_other_uses: true - number: 32 - carrier_duty_percent: 100% - -climate: - - platform: tcl112 - name: TCL112 Climate With Sensor - supports_heat: true - supports_cool: true - sensor: ${sensorname}_sensor - - platform: tcl112 - name: TCL112 Climate - action_state_topic: action/state/topic - away_command_topic: away/command/topic - away_state_topic: away/state/topic - current_temperature_state_topic: current/temperature/state/topic - fan_mode_command_topic: fan_mode/mode/command/topic - fan_mode_state_topic: fan_mode/mode/state/topic - mode_command_topic: mode/command/topic - mode_state_topic: mode/state/topic - swing_mode_command_topic: swing_mode/command/topic - swing_mode_state_topic: swing_mode/state/topic - target_temperature_command_topic: target/temperature/command/topic - target_temperature_high_command_topic: target/temperature/high/command/topic - target_temperature_high_state_topic: target/temperature/high/state/topic - target_temperature_low_command_topic: target/temperature/low/command/topic - target_temperature_low_state_topic: target/temperature/low/state/topic - target_temperature_state_topic: target/temperature/state/topic - - platform: coolix - name: Coolix Climate With Sensor - supports_heat: true - supports_cool: true - sensor: ${sensorname}_sensor - - platform: coolix - name: Coolix Climate - - platform: fujitsu_general - name: Fujitsu General Climate - - platform: daikin - name: Daikin Climate - - platform: daikin_brc - name: Daikin BRC Climate - use_fahrenheit: true - - platform: delonghi - name: Delonghi Climate - - platform: yashima - name: Yashima Climate - - platform: mitsubishi - name: Mitsubishi - supports_dry: "true" - supports_fan_only: "true" - horizontal_default: "left" - vertical_default: "down" - - platform: whirlpool - name: Whirlpool Climate - - platform: climate_ir_lg - name: LG Climate - - platform: toshiba - name: Toshiba Climate - - platform: hitachi_ac344 - name: Hitachi Climate - - platform: heatpumpir - protocol: mitsubishi_heavy_zm - horizontal_default: left - vertical_default: up - name: HeatpumpIR Climate - min_temperature: 18 - max_temperature: 30 - - platform: heatpumpir - protocol: greeyt - horizontal_default: left - vertical_default: up - name: HeatpumpIR Climate - min_temperature: 18 - max_temperature: 30 - - platform: midea_ir - name: Midea IR - use_fahrenheit: true - - platform: midea - on_control: - - logger.log: Control message received! - - lambda: |- - x.set_mode(CLIMATE_MODE_FAN_ONLY); - on_state: - - logger.log: State changed! - - lambda: |- - if (x.mode == CLIMATE_MODE_FAN_ONLY) - id(binary_sensor1).publish_state(true); - id: midea_unit - uart_id: uart_0 - name: Midea Climate - transmitter_id: - period: 1s - num_attempts: 5 - timeout: 2s - beeper: false - autoconf: true - visual: - min_temperature: 17 °C - max_temperature: 30 °C - temperature_step: 0.5 °C - supported_modes: - - FAN_ONLY - - HEAT_COOL - - COOL - - HEAT - - DRY - custom_fan_modes: - - SILENT - - TURBO - supported_presets: - - ECO - - BOOST - - SLEEP - custom_presets: - - FREEZE_PROTECTION - supported_swing_modes: - - VERTICAL - - HORIZONTAL - - BOTH - outdoor_temperature: - name: Temp - power_usage: - name: Power - humidity_setpoint: - name: Humidity - - platform: anova - name: Anova cooker - ble_client_id: ble_blah - unit_of_measurement: c - icon: mdi:stove - - platform: bedjet - name: My Bedjet - bedjet_id: my_bedjet_client - heat_mode: extended - - platform: whynter - name: Whynter - - platform: noblex - name: AC Living - id: noblex_ac - sensor: ${sensorname}_sensor - receiver_id: rcvr - - platform: gree - name: GREE - model: generic - - platform: zhlt01 - name: ZH/LT-01 Climate - -script: - - id: climate_custom - then: - - climate.control: - id: midea_unit - custom_preset: FREEZE_PROTECTION - custom_fan_mode: SILENT - - id: climate_preset - then: - - climate.control: - id: midea_unit - preset: SLEEP - -switch: - - platform: template - name: MIDEA_AC_BEEPER_CONTROL - optimistic: true - turn_on_action: - midea_ac.beeper_on: - turn_off_action: - midea_ac.beeper_off: - - platform: template - name: MIDEA_RAW - turn_on_action: - - remote_transmitter.transmit_coolix: - first: 0xB21F98 - - remote_transmitter.transmit_coolix: - first: 0xB21F98 - second: 0xB21F98 - - remote_transmitter.transmit_coolix: - first: !lambda "return 0xB21F98;" - second: !lambda "return 0xB21F98;" - - remote_transmitter.transmit_midea: - code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF] - - remote_transmitter.transmit_midea: - code: !lambda "return {0xA2, 0x08, 0xFF, 0xFF, 0xFF};" - - platform: gpio - name: "MCP23S08 Pin #0" - pin: - mcp23xxx: mcp23s08_hub - # Use pin number 0 - number: 0 - mode: OUTPUT - inverted: false - - platform: gpio - name: "MCP23S17 Pin #0" - pin: - mcp23xxx: mcp23s17_hub - # Use pin number 0 - number: 1 - allow_other_uses: true - mode: OUTPUT - inverted: false - - platform: gpio - pin: - allow_other_uses: true - number: GPIO25 - name: Living Room Dehumidifier - icon: "mdi:restart" - inverted: true - command_topic: custom_command_topic - command_retain: true - restore_mode: ALWAYS_OFF - - platform: template - name: JVC Off - id: living_room_lights_on - turn_on_action: - remote_transmitter.transmit_jvc: - data: 0x10EF - - platform: template - name: MagiQuest - turn_on_action: - remote_transmitter.transmit_magiquest: - wand_id: 0x01234567 - - platform: template - name: NEC - id: living_room_lights_off - turn_on_action: - remote_transmitter.transmit_nec: - address: 0x4242 - command: 0x8484 - - platform: template - name: LG - turn_on_action: - remote_transmitter.transmit_lg: - data: 4294967295 - nbits: 28 - - platform: template - name: Samsung - turn_on_action: - remote_transmitter.transmit_samsung: - data: 0xABCDEF - - platform: template - name: Samsung36 - turn_on_action: - remote_transmitter.transmit_samsung36: - address: 0x0400 - command: 0x000E00FF - - platform: template - name: ToshibaAC - turn_on_action: - - remote_transmitter.transmit_toshiba_ac: - rc_code_1: 0xB24DBF4050AF - rc_code_2: 0xD5660001003C - - platform: template - name: Sony - turn_on_action: - remote_transmitter.transmit_sony: - data: 0xABCDEF - nbits: 12 - - platform: template - name: Panasonic - turn_on_action: - remote_transmitter.transmit_panasonic: - address: 0x4004 - command: 0x1000BCD - - platform: template - name: Pioneer - turn_on_action: - - remote_transmitter.transmit_pioneer: - rc_code_1: 0xA556 - rc_code_2: 0xA506 - repeat: - times: 2 - - platform: template - name: RC Switch Raw - turn_on_action: - remote_transmitter.transmit_rc_switch_raw: - code: "00101001100111110101xxxx" - protocol: 1 - - platform: template - name: RC Switch Type A - turn_on_action: - remote_transmitter.transmit_rc_switch_type_a: - group: "11001" - device: "01000" - state: true - protocol: - pulse_length: 175 - sync: [1, 31] - zero: [1, 3] - one: [3, 1] - inverted: false - - platform: template - name: RC Switch Type B - turn_on_action: - remote_transmitter.transmit_rc_switch_type_b: - address: 4 - channel: 2 - state: true - - platform: template - name: RC Switch Type C - turn_on_action: - remote_transmitter.transmit_rc_switch_type_c: - family: "a" - group: 1 - device: 2 - state: true - - platform: template - name: RC Switch Type D - turn_on_action: - remote_transmitter.transmit_rc_switch_type_d: - group: "a" - device: 2 - state: true - - platform: template - name: RC5 - turn_on_action: - remote_transmitter.transmit_rc5: - address: 0x00 - command: 0x0B - - platform: template - name: RC5 - turn_on_action: - remote_transmitter.transmit_raw: - code: [1000, -1000] - - platform: template - name: AEHA - id: eaha_hitachi_climate_power_on - turn_on_action: - remote_transmitter.transmit_aeha: - address: 0x8008 - carrier_frequency: 36700Hz - data: - [ - 0x00, - 0x02, - 0xFD, - 0xFF, - 0x00, - 0x33, - 0xCC, - 0x49, - 0xB6, - 0xC8, - 0x37, - 0x16, - 0xE9, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0xCA, - 0x35, - 0x8F, - 0x70, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0x00, - 0xFF, - 0x00, - 0xFF, - ] - - platform: template - name: Haier - turn_on_action: - remote_transmitter.transmit_haier: - code: - [ - 0xA6, - 0xDA, - 0x00, - 0x00, - 0x40, - 0x40, - 0x00, - 0x80, - 0x00, - 0x00, - 0x00, - 0x00, - 0x05, - ] - - platform: template - name: Living Room Lights - id: livingroom_lights - optimistic: true - assumed_state: true - turn_on_action: - - switch.turn_on: living_room_lights_on - - output.set_level: - id: gpio_19 - level: 50% - - output.set_level: - id: gpio_19 - level: !lambda "return 0.5;" - - output.set_level: - id: dac_output - level: 50% - - output.set_level: - id: dac_output - level: !lambda "return 0.5;" - - output.set_level: - id: mcp4725_dac_output - level: !lambda "return 0.5;" - - output.set_level: - id: mcp4728_dac_output_a - level: !lambda "return 0.5;" - turn_off_action: - - switch.turn_on: living_room_lights_off - on_turn_on: - - switch.template.publish: - id: livingroom_lights - state: true - - platform: restart - name: Living Room Restart - - platform: safe_mode - name: Living Room Restart (Safe Mode) - - platform: factory_reset - name: Living Room Restart (Factory Default Settings) - - platform: shutdown - name: Living Room Shutdown - - platform: output - name: Generic Output - output: pca_6 - - platform: template - name: Template Switch - id: my_switch - lambda: |- - if (id(binary_sensor1).state) { - return true; - } else { - return {}; - } - id(my_switch).publish_state(false); - id(my_switch).publish_state(true); - if (id(my_switch).state) { - // Switch is ON, do something here - id(my_switch).turn_off(); - id(my_switch).turn_on(); - } else { - // Switch is OFF, do something else here - } - optimistic: true - assumed_state: false - on_turn_off: - - switch.template.publish: - id: my_switch - state: !lambda "return false;" - - platform: uart - uart_id: uart_0 - name: UART String Output - data: DataToSend - - platform: uart - uart_id: uart_0 - name: UART Bytes Output - data: [0xDE, 0xAD, 0xBE, 0xEF] - - platform: uart - uart_id: uart_0 - name: UART Recurring Output - data: [0xDE, 0xAD, 0xBE, 0xEF] - send_every: 1s - - platform: uart - uart_id: uart_0 - name: "UART On/Off" - data: - turn_on: "TurnOn\r\n" - turn_off: "TurnOff\r\n" - - platform: template - assumed_state: true - name: Stepper Switch - turn_on_action: - - stepper.set_target: - id: my_stepper - target: !lambda |- - static int32_t i = 0; - i += 1000; - if (i > 5000) { - i = -5000; - } - return i; - - stepper.report_position: - id: my_stepper - position: 0 - - - platform: gpio - name: "SN74HC595 Pin #0" - pin: - sn74hc595: sn74hc595_hub_2 - # Use pin number 0 - number: 0 - inverted: false - - platform: template - id: ble1_status - optimistic: true - - platform: template - id: outlet_switch - optimistic: true - device_class: outlet - - platform: ld2410 - engineering_mode: - name: "control ld2410 engineering mode" - bluetooth: - name: "control ld2410 bluetooth" - - platform: micronova - stove: - name: Stove on/off - -fan: - - platform: binary - output: gpio_26 - name: Living Room Fan 1 - oscillation_output: gpio_19 - direction_output: gpio_26 - - platform: speed - id: fan_speed - icon: mdi:weather-windy - output: pca_6 - speed_count: 10 - name: Living Room Fan 2 - oscillation_output: gpio_19 - direction_output: gpio_26 - oscillation_state_topic: oscillation/state/topic - oscillation_command_topic: oscillation/command/topic - speed_level_state_topic: speed_level/state/topic - speed_level_command_topic: speed_level/command/topic - speed_state_topic: speed/state/topic - speed_command_topic: speed/command/topic - on_speed_set: - then: - - logger.log: Fan speed was changed! - - platform: speed - id: fan_speed_presets - icon: mdi:weather-windy - output: pca_6 - speed_count: 10 - name: Speed Fan w/ Presets - oscillation_output: gpio_19 - direction_output: gpio_26 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! - - platform: hbridge - id: fan_hbridge_presets - icon: mdi:weather-windy - speed_count: 4 - name: H-bridge Fan w/ Presets - pin_a: pca_6 - pin_b: pca_7 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! - - platform: bedjet - name: My Bedjet fan - bedjet_id: my_bedjet_client - - platform: copy - source_id: fan_speed - name: Fan Speed Copy - -interval: - - interval: 10s - then: - - display.page.show: !lambda |- - if (true) return id(page1); else return id(page2); - - display.page.show_next: display1 - - display.page.show_previous: display1 - - interval: 2s - then: - # yamllint disable rule:line-length - - lambda: |- - static uint16_t btn_left_state = id(btn_left)->get_value(); - - ESP_LOGD("adaptive touch", "___ Touch Pad '%s' (T%u): val: %u state: %u tres:%u", id(btn_left)->get_name().c_str(), id(btn_left)->get_touch_pad(), id(btn_left)->get_value(), btn_left_state, id(btn_left)->get_threshold()); - - btn_left_state = ((uint32_t) id(btn_left)->get_value() + 63 * (uint32_t)btn_left_state) >> 6; - - id(btn_left)->set_threshold(btn_left_state * 0.9); - # yamllint enable rule:line-length - - if: - condition: - display.is_displaying_page: - id: display1 - page_id: page1 - then: - - logger.log: Seeing page 1 - - interval: 60min - then: - - ble_client.connect: ble_blah - - ble_client.ble_write: - id: ble_blah - service_uuid: EBE0CCB0-7A0A-4B0C-8A1A-6FF2997DA3A6 - characteristic_uuid: EBE0CCB7-7A0A-4B0C-8A1A-6FF2997DA3A6 - value: !lambda |- - return {1, 0}; - - ble_client.disconnect: ble_blah - -color: - - id: kbx_red - red: 100% - green_int: 123 - blue: 2% - - id: kbx_blue - red: 0% - green: 1% - blue: 100% - - id: kbx_green - hex: "3DEC55" - -display: - - platform: lcd_gpio - id: my_lcd_gpio - dimensions: 18x4 - data_pins: - - allow_other_uses: true - number: GPIO19 - - allow_other_uses: true - number: GPIO21 - - allow_other_uses: true - number: GPIO22 - - allow_other_uses: true - number: GPIO23 - enable_pin: - allow_other_uses: true - number: GPIO23 - rs_pin: - allow_other_uses: true - number: GPIO25 - lambda: |- - it.print("Hello World!"); - - platform: lcd_pcf8574 - dimensions: 18x4 - address: 0x3F - user_characters: - - position: 0 - data: - - 0b00000 - - 0b01010 - - 0b00000 - - 0b00100 - - 0b00100 - - 0b10001 - - 0b01110 - - 0b00000 - lambda: |- - it.print("Hello World!"); - i2c_id: i2c_bus - - platform: max7219 - cs_pin: - allow_other_uses: true - number: GPIO23 - num_chips: 1 - lambda: |- - it.print("01234567"); - - platform: tm1637 - clk_pin: - allow_other_uses: true - number: GPIO23 - dio_pin: - allow_other_uses: true - number: GPIO25 - intensity: 3 - lambda: |- - it.print("1234"); - - platform: tm1637 - clk_pin: - mcp23xxx: mcp23017_hub - number: 1 - allow_other_uses: true - dio_pin: - mcp23xxx: mcp23017_hub - number: 2 - intensity: 3 - inverted: true - length: 4 - lambda: |- - it.print("1234"); - - platform: pcd8544 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - contrast: 60 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1306_i2c - model: SSD1306_128X64 - reset_pin: - allow_other_uses: true - number: GPIO23 - address: 0x3C - id: display1 - contrast: 60% - pages: - - id: page1 - lambda: |- - it.qr_code(0, 0, id(homepage_qr)); - it.rectangle(0, 0, it.get_width(), it.get_height()); - - id: page2 - lambda: |- - // Nothing - on_page_change: - from: page1 - to: page2 - then: - lambda: |- - ESP_LOGD("display", "1 -> 2"); - i2c_id: i2c_bus - - platform: ssd1306_spi - model: SSD1306 128x64 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1322_spi - model: SSD1322 256x64 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1325_spi - model: SSD1325 128x64 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1327_i2c - model: SSD1327 128X128 - reset_pin: - allow_other_uses: true - number: GPIO23 - address: 0x3D - id: display1327 - brightness: 60% - pages: - - id: page13271 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - id: page13272 - lambda: |- - // Nothing - i2c_id: i2c_bus - - platform: ssd1327_spi - model: SSD1327 128x128 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1331_spi - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ssd1351_spi - model: SSD1351 128x128 - cs_pin: - allow_other_uses: true - number: GPIO23 - dc_pin: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: st7789v - model: TTGO TDisplay 135x240 - cs_pin: - allow_other_uses: true - number: GPIO5 - dc_pin: - allow_other_uses: true - number: GPIO16 - reset_pin: - allow_other_uses: true - number: GPIO23 - backlight_pin: false - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: st7920 - width: 128 - height: 64 - cs_pin: - allow_other_uses: true - number: GPIO23 - inverted: true - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: st7567_i2c - id: st7735_display_i2c - address: 0x3F - i2c_id: i2c_bus - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: st7567_spi - id: st7735_display_spi - cs_pin: - allow_other_uses: true - number: GPIO5 - dc_pin: - allow_other_uses: true - number: GPIO16 - reset_pin: - allow_other_uses: true - number: GPIO23 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: st7735 - id: st7735_display - model: INITR_BLACKTAB - cs_pin: - allow_other_uses: true - number: GPIO5 - dc_pin: - allow_other_uses: true - number: GPIO16 - reset_pin: - allow_other_uses: true - number: GPIO23 - rotation: 0 - device_width: 128 - device_height: 160 - col_start: 0 - row_start: 0 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ili9xxx - invert_colors: true - dimensions: 320x240 - transform: - swap_xy: true - mirror_x: true - mirror_y: false - model: TFT 2.4 - cs_pin: - allow_other_uses: true - number: GPIO5 - dc_pin: - allow_other_uses: true - number: GPIO4 - color_palette: GRAYSCALE - reset_pin: - allow_other_uses: true - number: GPIO22 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ili9xxx - dimensions: - width: 320 - height: 240 - offset_width: 20 - offset_height: 10 - model: TFT 2.4 - cs_pin: - allow_other_uses: true - number: GPIO5 - dc_pin: - allow_other_uses: true - number: GPIO4 - reset_pin: - allow_other_uses: true - number: GPIO22 - auto_clear_enabled: false - rotation: 90 - lambda: |- - if (!id(glob_bool_processed)) { - it.fill(Color::WHITE); - id(glob_bool_processed) = true; - } - - platform: pvvx_mithermometer - ble_client_id: ble_foo - time_id: sntp_time - disconnect_delay: 3s - update_interval: 10min - validity_period: 20min - lambda: |- - it.print_bignum(188.8); - it.print_unit(pvvx_mithermometer::UNIT_DEG_E); - it.print_smallnum(88); - it.print_percent(true); - it.print_happy(true); - it.print_sad(true); - it.print_bracket(true); - it.print_battery(true); - - platform: tm1621 - id: tm1621_display - cs_pin: - allow_other_uses: true - number: GPIO17 - data_pin: - allow_other_uses: true - number: GPIO5 - read_pin: - allow_other_uses: true - number: GPIO23 - write_pin: - allow_other_uses: true - number: GPIO18 - lambda: |- - it.printf(0, "%.1f", id(dht_temperature).state); - it.display_celsius(true); - it.printf(1, "%.1f", id(dht_humidity).state); - it.display_humidity(true); - -tm1651: - id: tm1651_battery - clk_pin: - allow_other_uses: true - number: GPIO23 - dio_pin: - allow_other_uses: true - number: GPIO23 - -remote_receiver: - id: rcvr - pin: - allow_other_uses: true - number: GPIO32 - dump: all - on_coolix: - then: - delay: !lambda "return x.first + x.second;" - on_rc_switch: - then: - delay: !lambda "return uint32_t(x.code) + x.protocol;" - -status_led: - pin: - allow_other_uses: true - number: GPIO2 - ignore_strapping_warning: true - -pn532_spi: - id: pn532_bs - cs_pin: - allow_other_uses: true - number: GPIO23 - update_interval: 1s - on_tag: - - lambda: |- - ESP_LOGD("main", "Found tag %s", x.c_str()); - - mqtt.publish: - topic: the/topic - payload: !lambda "return x;" - on_tag_removed: - - lambda: |- - ESP_LOGD("main", "Removed tag %s", x.c_str()); - - mqtt.publish: - topic: the/topic - payload: !lambda "return x;" - -pn532_i2c: - i2c_id: i2c_bus - -pn7150_i2c: - id: nfcc_pn7150_i2c - i2c_id: i2c_bus - irq_pin: - allow_other_uses: true - number: GPIO32 - ven_pin: - allow_other_uses: true - number: GPIO16 - -pn7160_i2c: - id: nfcc_pn7160_i2c - i2c_id: i2c_bus - dwl_req_pin: - allow_other_uses: true - number: GPIO17 - irq_pin: - allow_other_uses: true - number: GPIO35 - ven_pin: - allow_other_uses: true - number: GPIO16 - wkup_req_pin: - allow_other_uses: true - number: GPIO21 - emulation_message: https://www.home-assistant.io/tag/pulse_ce - tag_ttl: 1000ms - -pn7160_spi: - id: nfcc_pn7160_spi - cs_pin: - number: GPIO15 - dwl_req_pin: - allow_other_uses: true - number: GPIO17 - irq_pin: - allow_other_uses: true - number: GPIO35 - ven_pin: - allow_other_uses: true - number: GPIO16 - wkup_req_pin: - allow_other_uses: true - number: GPIO21 - emulation_message: https://www.home-assistant.io/tag/pulse_ce - tag_ttl: 1000ms - -rdm6300: - uart_id: uart_0 - -rc522_spi: - cs_pin: - allow_other_uses: true - number: GPIO23 - update_interval: 1s - on_tag: - - lambda: |- - ESP_LOGD("main", "Found tag %s", x.c_str()); - -rc522_i2c: - - update_interval: 1s - on_tag: - - lambda: |- - ESP_LOGD("main", "Found tag %s", x.c_str()); - i2c_id: i2c_bus - - - update_interval: 1s - on_tag: - - lambda: |- - ESP_LOGD("main", "Found tag %s", x.c_str()); - i2c_id: i2c_bus - -mcp4728: - - id: mcp4728_dac - store_in_eeprom: false - address: 0x60 - i2c_id: i2c_bus - -gps: - uart_id: uart_0 - -time: - - platform: sntp - id: sntp_time - servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 192.168.178.1 - on_time: - cron: "/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI" - then: - - lambda: 'ESP_LOGD("main", "time");' - - platform: gps - on_time_sync: - then: - ds1307.write_time: - id: ds1307_time - - platform: ds1307 - id: ds1307_time - update_interval: never - i2c_id: i2c_bus - on_time: - - seconds: 0 - then: ds1307.read_time - - at: "16:00:00" - then: - - if: - condition: - or: - - binary_sensor.is_on: close_sensor - - binary_sensor.is_on: open_sensor - then: - logger.log: "close_sensor or open_sensor is on" - - if: - condition: - and: - - binary_sensor.is_on: close_sensor - - binary_sensor.is_on: open_sensor - then: - logger.log: "close_sensor and open_sensor are both on" - - if: - condition: - xor: - - binary_sensor.is_on: close_sensor - - binary_sensor.is_on: open_sensor - then: - logger.log: "close_sensor or open_sensor is exclusively on" - - if: - condition: - not: - - binary_sensor.is_on: close_sensor - then: - logger.log: "close_sensor is not on" -cover: - - platform: template - name: Template Cover - id: template_cover - lambda: |- - if (id(binary_sensor1).state) { - return COVER_OPEN; - } else { - return {}; - } - optimistic: true - open_action: - - cover.template.publish: - id: template_cover - state: CLOSED - assumed_state: false - has_position: true - position_state_topic: position/state/topic - position_command_topic: position/command/topic - tilt_lambda: !lambda "return 0.5;" - tilt_state_topic: tilt/state/topic - tilt_command_topic: tilt/command/topic - on_open: - then: - - lambda: 'ESP_LOGD("cover", "open");' - on_closed: - then: - - lambda: 'ESP_LOGD("cover", "closed");' - - platform: am43 - name: Test AM43 - id: am43_test - ble_client_id: ble_foo - icon: mdi:blinds - - platform: feedback - name: Feedback Cover - id: gate - device_class: gate - - infer_endstop_from_movement: false - has_built_in_endstop: false - max_duration: 30s - direction_change_wait_time: 300ms - acceleration_wait_time: 150ms - obstacle_rollback: 10% - - open_duration: 22.1s - open_endstop: open_endstop_sensor - open_sensor: open_sensor - open_obstacle_sensor: open_obstacle_sensor - - close_duration: 22.4s - close_endstop: close_endstop_sensor - close_sensor: close_sensor - close_obstacle_sensor: close_obstacle_sensor - - open_action: - - logger.log: Open Action - - close_action: - - logger.log: Close Action - - stop_action: - - logger.log: Stop Action - -debug: - -tca9548a: - - address: 0x70 - id: multiplex0 - channels: - - bus_id: multiplex0_chan0 - channel: 0 - i2c_id: i2c_bus - - address: 0x71 - id: multiplex1 - i2c_id: multiplex0_chan0 - -pcf8574: - - id: pcf8574_hub - address: 0x21 - pcf8575: false - i2c_id: i2c_bus - -pca9554: - - id: pca9554_hub - pin_count: 8 - address: 0x3F - i2c_id: i2c_bus - -pca6416a: - - id: pca6416a_hub - address: 0x21 - i2c_id: i2c_bus - -mcp23017: - - id: mcp23017_hub - open_drain_interrupt: true - i2c_id: i2c_bus - -mcp23008: - - id: mcp23008_hub - address: 0x22 - open_drain_interrupt: true - i2c_id: i2c_bus - -mcp23016: - - id: mcp23016_hub - address: 0x23 - i2c_id: i2c_bus - -stepper: - - platform: a4988 - id: my_stepper - step_pin: - allow_other_uses: true - number: GPIO23 - dir_pin: - allow_other_uses: true - number: GPIO25 - sleep_pin: - allow_other_uses: true - number: GPIO25 - max_speed: 250 steps/s - acceleration: 100 steps/s^2 - deceleration: 200 steps/s^2 - -globals: - - id: glob_int - type: int - restore_value: true - initial_value: "0" - - id: glob_float - type: float - restore_value: true - initial_value: "0.0f" - - id: glob_bool - type: bool - restore_value: false - initial_value: "true" - - id: glob_string - type: std::string - restore_value: false - # initial_value: "" - - id: glob_bool_processed - type: bool - restore_value: false - initial_value: "false" - -text_sensor: - - platform: ble_client - ble_client_id: ble_foo - name: Sensor Location - service_uuid: "180d" - characteristic_uuid: "2a38" - descriptor_uuid: "2902" - notify: true - update_interval: never - on_notify: - then: - - lambda: |- - ESP_LOGD("green_btn", "Location changed: %s", x.c_str()); - - platform: mqtt_subscribe - name: MQTT Subscribe Text - topic: "the/topic" - qos: 2 - on_value: - - text_sensor.template.publish: - id: ${textname}_text - state: Hello World - - text_sensor.template.publish: - id: ${textname}_text - state: |- - return "Hello World2"; - - globals.set: - id: glob_int - value: "0" - - canbus.send: - canbus_id: mcp2515_can - can_id: 23 - data: [0x10, 0x20, 0x30] - - canbus.send: - canbus_id: mcp2515_can - can_id: 23 - data: !lambda return {0x10, 0x20, 0x30}; - - canbus.send: - canbus_id: esp32_internal_can - can_id: 23 - data: [0x10, 0x20, 0x30] - - canbus.send: - canbus_id: mcp2515_can - can_id: 24 - remote_transmission_request: true - data: [] - - canbus.send: - canbus_id: esp32_internal_can - can_id: 24 - remote_transmission_request: true - data: [] - - platform: template - name: Template Text Sensor - id: ${textname}_text - - platform: template - name: Template Text Sensor Timestamp - id: ${textname}_text_timestamp - device_class: timestamp - - platform: wifi_info - scan_results: - name: Scan Results - ip_address: - name: IP Address - ssid: - name: SSID - bssid: - name: BSSID - mac_address: - name: Mac Address - dns_address: - name: DNS ADdress - - platform: version - name: ESPHome Version No Timestamp - hide_timestamp: true - - platform: teleinfo - tag_name: OPTARIF - name: optarif - teleinfo_id: myteleinfo - - platform: ld2410 - version: - name: "presenece sensor version" - mac_address: - name: "presenece sensor mac address" - -sn74hc595: - - id: sn74hc595_hub - data_pin: - allow_other_uses: true - number: GPIO21 - clock_pin: - allow_other_uses: true - number: GPIO23 - latch_pin: - allow_other_uses: true - number: GPIO22 - oe_pin: - allow_other_uses: true - number: GPIO32 - sr_count: 2 - - id: sn74hc595_hub_2 - latch_pin: - allow_other_uses: true - number: GPIO22 - oe_pin: - allow_other_uses: true - number: GPIO32 - sr_count: 2 - spi_id: spi_bus - type: spi - -rtttl: - output: gpio_19 - -canbus: - - platform: mcp2515 - id: mcp2515_can - cs_pin: - pca9554: pca9554_hub - number: 7 - mode: - output: true - inverted: true - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str()); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - light.toggle: ${roomname}_lights - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - // to be continued... - } - - platform: esp32_can - id: esp32_internal_can - rx_pin: - allow_other_uses: true - number: GPIO04 - tx_pin: - allow_other_uses: true - number: GPIO05 - can_id: 4 - bit_rate: 50kbps - on_frame: - - can_id: 500 - then: - - lambda: |- - std::string b(x.begin(), x.end()); - ESP_LOGD("canid 500", "%s", b.c_str() ); - - can_id: 23 - then: - - if: - condition: - lambda: "return x[0] == 0x11;" - then: - light.toggle: ${roomname}_lights - - can_id: 0b00000000000000000000001000000 - can_id_mask: 0b11111000000000011111111000000 - use_extended_id: true - then: - - lambda: |- - auto pdo_id = can_id >> 14; - switch (pdo_id) - { - case 117: - ESP_LOGD("canbus", "exhaust_fan_duty"); - break; - case 118: - ESP_LOGD("canbus", "supply_fan_duty"); - break; - case 119: - ESP_LOGD("canbus", "supply_fan_flow"); - break; - // to be continued... - } - -teleinfo: - id: myteleinfo - uart_id: uart_0 - update_interval: 60s - historical_mode: true - -number: - - platform: template - id: test_number - state_topic: livingroom/custom_state_topic - command_topic: livingroom/custom_command_topic - min_value: 0 - step: 1 - max_value: 10 - optimistic: true - - platform: ld2410 - light_threshold: - name: light threshold - timeout: - name: timeout - max_move_distance_gate: - name: max move distance gate - max_still_distance_gate: - name: max still distance gate - g0: - move_threshold: - name: g0 move threshold - still_threshold: - name: g0 still threshold - g1: - move_threshold: - name: g1 move threshold - still_threshold: - name: g1 still threshold - g2: - move_threshold: - name: g2 move threshold - still_threshold: - name: g2 still threshold - g3: - move_threshold: - name: g3 move threshold - still_threshold: - name: g3 still threshold - g4: - move_threshold: - name: g4 move threshold - still_threshold: - name: g4 still threshold - g5: - move_threshold: - name: g5 move threshold - still_threshold: - name: g5 still threshold - g6: - move_threshold: - name: g6 move threshold - still_threshold: - name: g6 still threshold - g7: - move_threshold: - name: g7 move threshold - still_threshold: - name: g7 still threshold - g8: - move_threshold: - name: g8 move threshold - still_threshold: - name: g8 still threshold - - platform: micronova - thermostat_temperature: - name: Micronova Thermostaat - step: 1 - power_level: - name: Micronova Power level - -select: - - platform: template - id: test_select - state_topic: livingroom/custom_state_topic - command_topic: livingroom/custom_command_topic - options: - - one - - two - optimistic: true - - platform: copy - source_id: test_select - name: Test Select Copy - - platform: ld2410 - distance_resolution: - name: distance resolution - baud_rate: - name: baud rate - light_function: - name: light function - out_pin_level: - name: out ping level - -qr_code: - - id: homepage_qr - value: https://esphome.io/index.html - -lock: - - platform: template - id: test_lock1 - name: Template Switch - lambda: |- - if (id(binary_sensor1).state) { - return LOCK_STATE_LOCKED; - }else{ - return LOCK_STATE_UNLOCKED; - } - optimistic: true - assumed_state: false - on_unlock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_UNLOCKED;" - on_lock: - - lock.template.publish: - id: test_lock1 - state: !lambda "return LOCK_STATE_LOCKED;" - - platform: output - name: Generic Output Lock - id: test_lock2 - output: pca_6 - - platform: copy - source_id: test_lock2 - name: Generic Output Lock Copy - -button: - - platform: template - name: Start calibration - on_press: - - scd4x.perform_forced_calibration: - value: 419 - id: scd40 - - scd4x.factory_reset: - id: scd40 - - platform: template - name: Midea Display Toggle - on_press: - midea_ac.display_toggle: - - platform: template - name: Midea Swing Step - on_press: - midea_ac.swing_step: - - platform: template - name: Midea Power On - on_press: - midea_ac.power_on: - - platform: template - name: Midea Power Off - on_press: - midea_ac.power_off: - - platform: template - name: Midea Power Inverse - on_press: - midea_ac.power_toggle: - - platform: template - name: Update Mmwave Sensor Settings - on_press: - - dfrobot_sen0395.settings: - id: mmwave - factory_reset: true - detection_segments: - - [0cm, 5m] - - 600cm - - !lambda |- - return 7; - output_latency: - delay_after_detect: 0s - delay_after_disappear: 0s - sensitivity: 6 - - platform: template - name: Reset Mmwave Sensor - on_press: - - dfrobot_sen0395.reset: - - platform: template - name: Poller component suspend test - on_press: - - component.suspend: myteleinfo - - delay: 20s - - component.update: myteleinfo - - delay: 20s - - component.resume: myteleinfo - - delay: 20s - - component.resume: - id: myteleinfo - update_interval: 2s - - delay: 20s - - component.resume: - id: myteleinfo - update_interval: !lambda return 2500; - - platform: ld2410 - factory_reset: - name: "factory reset" - restart: - name: "restart" - query_params: - name: query params - - platform: uart - uart_id: uart_0 - name: UART button - data: "Pressed\r\n" - - platform: micronova - custom_button: - name: Custom Micronova Button - memory_location: 0xA0 - memory_address: 0x7D - memory_data: 0x0F - -ld2410: - id: my_ld2410 - uart_id: ld2410_uart - -ld2420: - id: my_ld2420 - uart_id: ld2420_uart - -lcd_menu: - id: test_lcd_menu - display_id: my_lcd_gpio - mark_back: 0x5e - mark_selected: 0x3e - mark_editing: 0x2a - mark_submenu: 0x7e - active: false - mode: rotary - on_enter: - then: - lambda: 'ESP_LOGI("lcd_menu", "root enter");' - on_leave: - then: - lambda: 'ESP_LOGI("lcd_menu", "root leave");' - items: - - type: back - text: Back - - type: label - - type: menu - text: Submenu 1 - items: - - type: back - text: Back - - type: menu - text: Submenu 21 - items: - - type: back - text: Back - - type: command - text: Show Main - on_value: - then: - - display_menu.show_main: test_lcd_menu - - type: select - text: Enum Item - immediate_edit: true - select: test_select - on_enter: - then: - lambda: 'ESP_LOGI("lcd_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_leave: - then: - lambda: 'ESP_LOGI("lcd_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_value: - then: - lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - - type: number - text: Number - number: test_number - on_enter: - then: - lambda: 'ESP_LOGI("lcd_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_leave: - then: - lambda: 'ESP_LOGI("lcd_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_value: - then: - lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - - type: command - text: Hide - on_value: - then: - - display_menu.hide: test_lcd_menu - - type: switch - text: Switch - switch: my_switch - on_text: Bright - off_text: Dark - immediate_edit: false - on_value: - then: - lambda: 'ESP_LOGI("lcd_menu", "switch value: %s", it->get_value_text().c_str());' - - type: custom - text: !lambda 'return "Custom";' - value_lambda: 'return "Val";' - on_next: - then: - lambda: 'ESP_LOGI("lcd_menu", "custom next: %s", it->get_text().c_str());' - on_prev: - then: - lambda: 'ESP_LOGI("lcd_menu", "custom prev: %s", it->get_text().c_str());' - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 - -graphical_display_menu: - id: test_graphical_display_menu - display: st7735_display - font: roboto - active: false - mode: rotary - on_enter: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "root enter");' - on_leave: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "root leave");' - items: - - type: back - text: "Back" - - type: label - - type: menu - text: "Submenu 1" - items: - - type: back - text: "Back" - - type: menu - text: "Submenu 21" - items: - - type: back - text: "Back" - - type: command - text: "Show Main" - on_value: - then: - - display_menu.show_main: test_graphical_display_menu - - type: select - text: "Enum Item" - immediate_edit: true - select: test_select - on_enter: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "select enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_leave: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "select leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_value: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - - type: number - text: "Number" - number: test_number - on_enter: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "number enter: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_leave: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "number leave: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - on_value: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - - type: command - text: "Hide" - on_value: - then: - - display_menu.hide: test_graphical_display_menu - - type: switch - text: "Switch" - switch: my_switch - on_text: "Bright" - off_text: "Dark" - immediate_edit: false - on_value: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "switch value: %s", it->get_value_text().c_str());' - - type: custom - text: !lambda 'return "Custom";' - value_lambda: 'return "Val";' - on_next: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "custom next: %s", it->get_text().c_str());' - on_prev: - then: - lambda: 'ESP_LOGI("graphical_display_menu", "custom prev: %s", it->get_text().c_str());' - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - binary_sensor1 - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml deleted file mode 100644 index 758f295a6c..0000000000 --- a/tests/test11.5.yaml +++ /dev/null @@ -1,809 +0,0 @@ ---- -# copy of test5.yaml configured to build on IDF 5 -esphome: - name: test11-5 - build_path: build/test11.5 - project: - name: esphome.test11_5_project - version: "1.0.0" - -esp32: - board: nodemcu-32s - framework: - type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 - advanced: - ignore_efuse_mac_crc: true - -wifi: - networks: - - ssid: "MySSID" - password: "password1" - manual_ip: - static_ip: 192.168.1.23 - gateway: 192.168.1.1 - subnet: 255.255.255.0 - -network: - enable_ipv6: true - -api: - -ota: - - platform: esphome - -logger: - -debug: - -psram: - -uart: - - id: uart_1 - tx_pin: 1 - rx_pin: 3 - baud_rate: 9600 - - id: uart_2 - tx_pin: - allow_other_uses: true - number: 17 - rx_pin: - allow_other_uses: true - number: 16 - baud_rate: 19200 - -i2c: - sda: - number: 21 - allow_other_uses: true - frequency: 100khz - -spi: - - id: spi_1 - clk_pin: - allow_other_uses: true - number: 12 - mosi_pin: - allow_other_uses: true - number: 13 - miso_pin: - allow_other_uses: true - number: 14 - - id: spi_2 - clk_pin: - allow_other_uses: true - number: 32 - mosi_pin: 33 - -modbus: - uart_id: uart_1 - flow_control_pin: - allow_other_uses: true - number: 5 - id: mod_bus1 - -modbus_controller: - - id: modbus_controller_test - address: 0x2 - modbus_id: mod_bus1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - idf_send_async: false - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - # yamllint disable rule:line-length - - lambda: |- - ESP_LOGD("Mqtt Test", "testing/sensor/testing_sensor/state=[%s]", x.c_str()); - # yamllint enable rule:line-length - -vbus: - - uart_id: uart_2 - -binary_sensor: - - platform: gpio - pin: GPIO0 - id: io0_button - icon: mdi:gesture-tap-button - - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_binsensortest - register_type: read - address: 0x3200 - bitmask: 0x80 # (bit 8) - lambda: "return x;" - - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - if: - condition: ble.enabled - then: - - ble.disable: - else: - - ble.enable: - - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - - - platform: gpio - id: sn74hc165_pin_0 - pin: - sn74hc165: sn74hc165_hub - number: 0 - - - platform: ezo_pmp - pump_state: - name: "Pump State" - is_paused: - name: "Is Paused" - - - platform: matrix_keypad - keypad_id: keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 - - - platform: vbus - model: deltasol_bs_plus - relay2: - name: Relay 2 On - sensor1_error: - name: Sensor 1 Error - - - platform: vbus - model: custom - command: 0x100 - source: 0x1234 - dest: 0x10 - binary_sensors: - - id: vcustom_b - name: VBus Custom Binary Sensor - lambda: return x[0] & 1; - -tlc5947: - data_pin: - allow_other_uses: true - number: GPIO12 - clock_pin: - allow_other_uses: true - number: GPIO14 - lat_pin: - allow_other_uses: true - number: GPIO15 - -gp8403: - - id: gp8403_5v - voltage: 5V - - id: gp8403_10v - voltage: 10V - -output: - - platform: gpio - pin: GPIO2 - id: built_in_led - - - platform: tlc5947 - id: output_red - channel: 0 - max_power: 0.8 - - - platform: mcp47a1 - id: output_mcp47a1 - - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_output_test - lambda: |- - return x * 1.0 ; - address: 0x9001 - value_type: U_WORD - - - platform: tm1638 - id: Led4 - led: 4 - - - platform: tm1638 - id: Led5 - led: 5 - - - platform: tm1638 - id: Led6 - led: 6 - - - platform: tm1638 - id: Led7 - led: 7 - - - platform: gp8403 - id: gp8403_output_0 - gp8403_id: gp8403_5v - channel: 0 - - platform: gp8403 - gp8403_id: gp8403_10v - id: gp8403_output_1 - channel: 1 - -demo: - -esp32_ble: - enable_on_boot: false - -esp32_ble_server: - manufacturer: ESPHome - model: Test11 - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led - -ezo_pmp: - id: hcl_pump - update_interval: 1s - -number: - - platform: template - name: My template number - id: template_number_id - optimistic: true - max_value: 100 - min_value: 0 - step: 5 - unit_of_measurement: "%" - mode: slider - device_class: humidity - on_value: - - logger.log: - format: Number changed to %f - args: [x] - set_action: - - logger.log: - format: Template Number set to %f - args: [x] - - number.set: - id: template_number_id - value: 50 - - number.to_min: template_number_id - - number.to_min: - id: template_number_id - - number.to_max: template_number_id - - number.to_max: - id: template_number_id - - number.increment: template_number_id - - number.increment: - id: template_number_id - cycle: false - - number.decrement: template_number_id - - number.decrement: - id: template_number_id - cycle: false - - number.operation: - id: template_number_id - operation: Increment - cycle: false - - number.operation: - id: template_number_id - operation: !lambda "return NUMBER_OP_INCREMENT;" - cycle: !lambda "return false;" - - - id: modbus_numbertest - platform: modbus_controller - modbus_controller_id: modbus_controller_test - name: ModbusNumber - address: 0x9002 - value_type: U_WORD - lambda: "return x * 1.0;" - write_lambda: |- - return x * 1.0 ; - multiply: 1.0 - -select: - - platform: template - name: My template select - id: template_select_id - optimistic: true - initial_option: two - restore_value: true - on_value: - - logger.log: - format: Select changed to %s (index %d)" - args: ["x.c_str()", "i"] - set_action: - - logger.log: - format: Template Select set to %s - args: ["x.c_str()"] - - select.set: - id: template_select_id - option: two - - select.first: template_select_id - - select.last: - id: template_select_id - - select.previous: template_select_id - - select.next: - id: template_select_id - cycle: false - - select.operation: - id: template_select_id - operation: Previous - cycle: false - - select.operation: - id: template_select_id - operation: !lambda "return SELECT_OP_PREVIOUS;" - cycle: !lambda "return true;" - - select.set_index: - id: template_select_id - index: 1 - - select.set_index: - id: template_select_id - index: !lambda "return 1 + 1;" - options: - - one - - two - - three - - - platform: modbus_controller - name: Modbus Select Register 1000 - address: 1000 - value_type: U_WORD - optionsmap: - "Zero": 0 - "One": 1 - "Two": 2 - "Three": 3 - -sensor: - - platform: adc - id: adc_sensor_p32 - name: ADC pin 32 - pin: - allow_other_uses: true - number: 32 - attenuation: 11db - update_interval: 1s - - platform: internal_temperature - name: Internal Temperature - - platform: selec_meter - total_active_energy: - name: SelecEM2M Total Active Energy - import_active_energy: - name: SelecEM2M Import Active Energy - export_active_energy: - name: SelecEM2M Export Active Energy - total_reactive_energy: - name: SelecEM2M Total Reactive Energy - import_reactive_energy: - name: SelecEM2M Import Reactive Energy - export_reactive_energy: - name: SelecEM2M Export Reactive Energy - apparent_energy: - name: SelecEM2M Apparent Energy - active_power: - name: SelecEM2M Active Power - reactive_power: - name: SelecEM2M Reactive Power - apparent_power: - name: SelecEM2M Apparent Power - voltage: - name: SelecEM2M Voltage - current: - name: SelecEM2M Current - power_factor: - name: SelecEM2M Power Factor - frequency: - name: SelecEM2M Frequency - maximum_demand_active_power: - name: SelecEM2M Maximum Demand Active Power - disabled_by_default: true - maximum_demand_reactive_power: - name: SelecEM2M Maximum Demand Reactive Power - disabled_by_default: true - maximum_demand_apparent_power: - name: SelecEM2M Maximum Demand Apparent Power - disabled_by_default: true - - - id: modbus_sensortest - platform: modbus_controller - modbus_controller_id: modbus_controller_test - address: 0x331A - register_type: read - value_type: U_WORD - - - platform: t6615 - uart_id: uart_2 - co2: - name: CO2 Sensor - - - platform: sen5x - id: sen54 - temperature: - name: Temperature - accuracy_decimals: 1 - humidity: - name: Humidity - accuracy_decimals: 0 - pm_1_0: - name: PM <1µm Weight concentration - id: pm_1_0 - accuracy_decimals: 1 - pm_2_5: - name: PM <2.5µm Weight concentration - id: pm_2_5 - accuracy_decimals: 1 - pm_4_0: - name: PM <4µm Weight concentration - id: pm_4_0 - accuracy_decimals: 1 - pm_10_0: - name: PM <10µm Weight concentration - id: pm_10_0 - accuracy_decimals: 1 - nox: - name: NOx - voc: - name: VOC - algorithm_tuning: - index_offset: 100 - learning_time_offset_hours: 12 - learning_time_gain_hours: 12 - gating_max_duration_minutes: 180 - std_initial: 50 - gain_factor: 230 - temperature_compensation: - offset: 0 - normalized_offset_slope: 0 - time_constant: 0 - auto_cleaning_interval: 604800s - acceleration_mode: low - store_baseline: true - address: 0x69 - - platform: mcp9600 - thermocouple_type: K - hot_junction: - name: Thermocouple Temperature - cold_junction: - name: Ambient Temperature - - - platform: ezo_pmp - current_volume_dosed: - name: Current Volume Dosed - total_volume_dosed: - name: Total Volume Dosed - absolute_total_volume_dosed: - name: Absolute Total Volume Dosed - pump_voltage: - name: Pump Voltage - last_volume_requested: - name: Last Volume Requested - max_flow_rate: - name: Max Flow Rate - - - platform: vbus - model: deltasol c - temperature_3: - name: Temperature 3 - operating_hours_1: - name: Operating Hours 1 - heat_quantity: - name: Heat Quantity - time: - name: System Time - - - platform: debug - free: - name: "Heap Free" - block: - name: "Heap Max Block" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" - - - platform: vbus - model: custom - command: 0x100 - source: 0x1234 - dest: 0x10 - sensors: - - id: vcustom - name: VBus Custom Sensor - lambda: return x[0] / 10.0; - - - platform: kuntze - ph: - name: Kuntze pH - temperature: - name: Kuntze temperature - - - platform: ade7953_i2c - irq_pin: - allow_other_uses: true - number: 16 - voltage: - name: ADE7953 Voltage - current_a: - name: ADE7953 Current A - current_b: - name: ADE7953 Current B - power_factor_a: - name: "ADE7953 Power Factor A" - power_factor_b: - name: "ADE7953 Power Factor B" - apparent_power_a: - name: "ADE7953 Apparent Power A" - apparent_power_b: - name: "ADE7953 Apparent Power B" - active_power_a: - name: ADE7953 Active Power A - active_power_b: - name: ADE7953 Active Power B - reactive_power_a: - name: "ADE7953 Reactive Power A" - reactive_power_b: - name: "ADE7953 Reactive Power B" - update_interval: 1s - - - platform: ade7953_spi - spi_id: spi_1 - cs_pin: 04 - irq_pin: - allow_other_uses: true - number: 16 - voltage: - name: ADE7953 Voltage - current_a: - name: ADE7953 Current A - current_b: - name: ADE7953 Current B - power_factor_a: - name: "ADE7953 Power Factor A" - power_factor_b: - name: "ADE7953 Power Factor B" - apparent_power_a: - name: "ADE7953 Apparent Power A" - apparent_power_b: - name: "ADE7953 Apparent Power B" - active_power_a: - name: ADE7953 Active Power A - active_power_b: - name: ADE7953 Active Power B - reactive_power_a: - name: "ADE7953 Reactive Power A" - reactive_power_b: - name: "ADE7953 Reactive Power B" - update_interval: 1s - -script: - - id: automation_test - then: - - repeat: - count: 5 - then: - - logger.log: looping! - - - id: zero_repeat_test - then: - - repeat: - count: !lambda "return 0;" - then: - - logger.log: shouldn't see mee! - -switch: - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_switch_test - register_type: coil - address: 2 - bitmask: 1 - - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -display: - - platform: tm1638 - id: primarydisplay - stb_pin: - allow_other_uses: true - number: 5 # TM1638 STB - clk_pin: 18 # TM1638 CLK - dio_pin: 23 # TM1638 DIO - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -time: - - platform: pcf85063 - - platform: pcf8563 - -text_sensor: - - platform: ezo_pmp - dosing_mode: - name: Dosing Mode - calibration_status: - name: Calibration Status - on_value: - - ezo_pmp.dose_volume: - id: hcl_pump - volume: 10 - - ezo_pmp.dose_volume_over_time: - id: hcl_pump - volume: 10 - duration: 2 - - ezo_pmp.dose_with_constant_flow_rate: - id: hcl_pump - volume_per_minute: 10 - duration: 2 - - ezo_pmp.set_calibration_volume: - id: hcl_pump - volume: 10 - - ezo_pmp.find: hcl_pump - - ezo_pmp.dose_continuously: hcl_pump - - ezo_pmp.clear_total_volume_dosed: hcl_pump - - ezo_pmp.clear_calibration: hcl_pump - - ezo_pmp.pause_dosing: hcl_pump - - ezo_pmp.stop_dosing: hcl_pump - - ezo_pmp.arbitrary_command: - id: hcl_pump - command: D,? - -sn74hc165: - id: sn74hc165_hub - data_pin: - allow_other_uses: true - number: GPIO12 - clock_pin: - allow_other_uses: true - number: GPIO14 - load_pin: - number: GPIO27 - clock_inhibit_pin: - number: GPIO26 - sr_count: 4 - -matrix_keypad: - id: keypad - rows: - - pin: - allow_other_uses: true - number: 21 - - pin: 19 - columns: - - pin: - allow_other_uses: true - number: 17 - - pin: - allow_other_uses: true - number: 16 - keys: "1234" - -key_collector: - - id: reader - source_id: keypad - min_length: 4 - max_length: 4 - -light: - - platform: esp32_rmt_led_strip - id: led_strip - pin: - allow_other_uses: true - number: 13 - num_leds: 60 - rmt_channel: 6 - rgb_order: GRB - chipset: ws2812 - - platform: esp32_rmt_led_strip - id: led_strip2 - pin: - allow_other_uses: true - number: 15 - num_leds: 60 - rmt_channel: 2 - rgb_order: RGB - bit0_high: 100us - bit0_low: 100us - bit1_high: 100us - bit1_low: 100us diff --git a/tests/test2.yaml b/tests/test2.yaml deleted file mode 100644 index 92977697c1..0000000000 --- a/tests/test2.yaml +++ /dev/null @@ -1,879 +0,0 @@ ---- -esphome: - name: $devicename - build_path: build/test2 - -esp32: - board: esp32dev - flash_size: 8MB - -globals: - - id: my_global_string - type: std::string - restore_value: true - max_restore_data_length: 70 - initial_value: '"DefaultValue"' - -substitutions: - devicename: test2 - -ethernet: - type: LAN8720 - mdc_pin: - allow_other_uses: true - number: GPIO23 - mdio_pin: - allow_other_uses: true - number: GPIO25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: - allow_other_uses: true - number: GPIO25 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local - -network: - enable_ipv6: true - -mdns: - disabled: true - -api: - -i2c: - sda: - allow_other_uses: true - number: 21 - scl: - allow_other_uses: true - number: 22 - scan: false - -spi: - clk_pin: - allow_other_uses: true - number: GPIO21 - mosi_pin: - allow_other_uses: true - number: GPIO22 - miso_pin: - allow_other_uses: true - number: GPIO23 - -uart: - tx_pin: - allow_other_uses: true - number: GPIO22 - rx_pin: - allow_other_uses: true - number: GPIO23 - baud_rate: 115200 - # Specifically added for testing debug with no after: definition. - debug: - dummy_receiver: false - direction: rx - sequence: - - lambda: UARTDebug::log_hex(direction, bytes, ':'); - -safe_mode: - -ota: - - platform: esphome - port: 3286 - -logger: - level: DEBUG - -debug: - -deep_sleep: - run_duration: - default: 20s - gpio_wakeup_reason: 10s - touch_wakeup_reason: 15s - sleep_duration: 50s - wakeup_pin: - allow_other_uses: true - number: GPIO2 - wakeup_pin_mode: INVERT_WAKEUP - -as3935_i2c: - irq_pin: - allow_other_uses: true - number: GPIO12 - -mcp3008: - - id: mcp3008_hub - cs_pin: - allow_other_uses: true - number: GPIO12 - -output: - - platform: ac_dimmer - id: dimmer1 - gate_pin: GPIO5 - zero_cross_pin: - allow_other_uses: true - number: GPIO12 - -sensor: - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: homeassistant - entity_id: climate.living_room - attribute: temperature - id: ha_hello_world_temperature - - platform: ble_rssi - mac_address: AC:37:43:77:5F:4C - name: BLE Google Home Mini RSSI value - - platform: ble_rssi - service_uuid: 11aa - name: BLE Test Service 16 - - platform: ble_rssi - service_uuid: "11223344" - name: BLE Test Service 32 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 - - platform: ble_rssi - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test iBeacon UUID - - platform: b_parasite - mac_address: F0:CA:F0:CA:01:01 - humidity: - name: b-parasite Air Humidity - temperature: - name: b-parasite Air Temperature - moisture: - name: b-parasite Soil Moisture - battery_voltage: - name: b-parasite Battery Voltage - illuminance: - name: b-parasite Illuminance - - platform: senseair - id: senseair0 - co2: - name: SenseAir CO2 Value - on_value: - then: - - senseair.background_calibration: senseair0 - - senseair.background_calibration_result: senseair0 - - senseair.abc_get_period: senseair0 - - senseair.abc_enable: senseair0 - - senseair.abc_disable: senseair0 - update_interval: 15s - - platform: ruuvitag - mac_address: FF:56:D3:2F:7D:E8 - humidity: - name: RuuviTag Humidity - temperature: - name: RuuviTag Temperature - pressure: - name: RuuviTag Pressure - acceleration_x: - name: RuuviTag Acceleration X - acceleration_y: - name: RuuviTag Acceleration Y - acceleration_z: - name: RuuviTag Acceleration Z - battery_voltage: - name: RuuviTag Battery Voltage - tx_power: - name: RuuviTag TX Power - movement_counter: - name: RuuviTag Movement Counter - measurement_sequence_number: - name: RuuviTag Measurement Sequence Number - - platform: as3935 - lightning_energy: - name: Lightning Energy - distance: - name: Distance Storm - - platform: xiaomi_hhccjcy01 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: Xiaomi HHCCJCY01 Temperature - moisture: - name: Xiaomi HHCCJCY01 Moisture - illuminance: - name: Xiaomi HHCCJCY01 Illuminance - conductivity: - name: Xiaomi HHCCJCY01 Soil Conductivity - battery_level: - name: Xiaomi HHCCJCY01 Battery Level - - platform: xiaomi_hhccjcy10 - mac_address: DD:25:6D:E4:FF:8F - temperature: - name: "Xiaomi HHCCJCY10 Temperature" - moisture: - name: "Xiaomi HHCCJCY10 Moisture" - illuminance: - name: "Xiaomi HHCCJCY10 Illuminance" - conductivity: - name: "Xiaomi HHCCJCY10 Soil Conductivity" - battery_level: - name: "Xiaomi HHCCJCY10 Battery Level" - - platform: xiaomi_lywsdcgq - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi LYWSDCGQ Temperature - humidity: - name: Xiaomi LYWSDCGQ Humidity - battery_level: - name: Xiaomi LYWSDCGQ Battery Level - - platform: xiaomi_lywsd02 - mac_address: 3F:5B:7D:82:58:4E - temperature: - name: Xiaomi LYWSD02 Temperature - humidity: - name: Xiaomi LYWSD02 Humidity - battery_level: - name: Xiaomi LYWSD02 Battery Level - - platform: xiaomi_cgg1 - mac_address: 7A:80:8E:19:36:BA - temperature: - name: Xiaomi CGG1 Temperature - humidity: - name: Xiaomi CGG1 Humidity - battery_level: - name: Xiaomi CGG1 Battery Level - - platform: xiaomi_gcls002 - mac_address: 94:2B:FF:5C:91:61 - temperature: - name: GCLS02 Temperature - moisture: - name: GCLS02 Moisture - conductivity: - name: GCLS02 Soil Conductivity - illuminance: - name: GCLS02 Illuminance - - platform: xiaomi_hhccpot002 - mac_address: 94:2B:FF:5C:91:61 - moisture: - name: HHCCPOT002 Moisture - conductivity: - name: HHCCPOT002 Soil Conductivity - - platform: xiaomi_lywsd03mmc - mac_address: A4:C1:38:4E:16:78 - bindkey: e9efaa6873f9f9c87a5e75a5f814801c - temperature: - name: Xiaomi LYWSD03MMC Temperature - humidity: - name: Xiaomi LYWSD03MMC Humidity - battery_level: - name: Xiaomi LYWSD03MMC Battery Level - - platform: xiaomi_cgd1 - mac_address: A4:C1:38:D1:61:7D - bindkey: c99d2313182473b38001086febf781bd - temperature: - name: Xiaomi CGD1 Temperature - humidity: - name: Xiaomi CGD1 Humidity - battery_level: - name: Xiaomi CGD1 Battery Level - - platform: xiaomi_jqjcy01ym - mac_address: 7A:80:8E:19:36:BA - temperature: - name: JQJCY01YM Temperature - humidity: - name: JQJCY01YM Humidity - formaldehyde: - name: JQJCY01YM Formaldehyde - battery_level: - name: JQJCY01YM Battery Level - - platform: xiaomi_mhoc303 - mac_address: E7:50:59:32:A0:1C - temperature: - name: MHO-C303 Temperature - humidity: - name: MHO-C303 Humidity - battery_level: - name: MHO-C303 Battery Level - - platform: atc_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: ATC Temperature - humidity: - name: ATC Humidity - battery_level: - name: ATC Battery-Level - battery_voltage: - name: ATC Battery-Voltage - - platform: pvvx_mithermometer - mac_address: A4:C1:38:4E:16:78 - temperature: - name: PVVX Temperature - humidity: - name: PVVX Humidity - battery_level: - name: PVVX Battery-Level - battery_voltage: - name: PVVX Battery-Voltage - - platform: inkbird_ibsth1_mini - mac_address: 38:81:D7:0A:9C:11 - temperature: - name: Inkbird IBS-TH1 Temperature - humidity: - name: Inkbird IBS-TH1 Humidity - battery_level: - name: Inkbird IBS-TH1 Battery Level - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - battery_level: - name: Mi Motion Sensor 2 Battery level - - platform: ltr390 - uv: - name: LTR390 UV - uv_index: - name: LTR390 UVI - light: - name: LTR390 Light - ambient_light: - name: LTR390 ALS - gain: X3 - resolution: 18 - window_correction_factor: 1.0 - address: 0x53 - update_interval: 60s - - platform: sgp4x - voc: - name: VOC Index - id: sgp40_voc_index - algorithm_tuning: - index_offset: 100 - learning_time_offset_hours: 12 - learning_time_gain_hours: 12 - gating_max_duration_minutes: 180 - std_initial: 50 - gain_factor: 230 - nox: - name: NOx - algorithm_tuning: - index_offset: 100 - learning_time_offset_hours: 12 - learning_time_gain_hours: 12 - gating_max_duration_minutes: 180 - std_initial: 50 - gain_factor: 230 - update_interval: 5s - - platform: mcp3008 - update_interval: 5s - mcp3008_id: mcp3008_hub - id: freezer_temp_source - reference_voltage: 3.19 - number: 0 - - id: airthingswp - platform: airthings_wave_plus - ble_client_id: airthings01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Plus Temperature - radon: - name: Wave Plus Radon - radon_long_term: - name: Wave Plus Radon Long Term - pressure: - name: Wave Plus Pressure - humidity: - name: Wave Plus Humidity - co2: - name: Wave Plus CO2 - tvoc: - name: Wave Plus VOC - battery_voltage: - name: Wave Plus Battery Voltage - - id: airthingswm - platform: airthings_wave_mini - ble_client_id: airthingsmini01 - update_interval: 5min - battery_update_interval: 12h - temperature: - name: Wave Mini Temperature - humidity: - name: Wave Mini Humidity - pressure: - name: Wave Mini Pressure - tvoc: - name: Wave Mini VOC - battery_voltage: - name: Wave Mini Battery Voltage - - platform: ina260 - address: 0x40 - current: - name: INA260 Current - power: - name: INA260 Power - bus_voltage: - name: INA260 Voltage - update_interval: 60s - - platform: radon_eye_rd200 - ble_client_id: radon_eye_ble_id - update_interval: 10min - radon: - name: RD200 Radon - radon_long_term: - name: RD200 Radon Long Term - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level - - platform: ufire_ec - id: ufire_ec_board - ec: - name: Ufire EC - temperature_sensor: ha_hello_world_temperature - temperature_compensation: 20.0 - temperature_coefficient: 0.019 - - platform: ufire_ise - id: ufire_ise_board - temperature_sensor: ha_hello_world_temperature - ph: - name: Ufire pH - - platform: mics_4514 - update_interval: 60s - nitrogen_dioxide: - name: MICS-4514 NO2 - carbon_monoxide: - name: MICS-4514 CO - methane: - name: MICS-4514 CH4 - hydrogen: - name: MICS-4514 H2 - ethanol: - name: MICS-4514 C2H5OH - ammonia: - name: MICS-4514 NH3 - - platform: mopeka_std_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: Propane test temp - level: - name: Propane test level - distance: - name: Propane test distance - battery_level: - name: Propane test battery level - - platform: duty_time - id: duty_time1 - name: Test Duty Time - restore: true - last_time: - name: Test Last Duty Time Sensor - sensor: ha_hello_world_binary - - platform: duty_time - id: duty_time2 - name: Test Duty Time 2 - restore: false - lambda: "return true;" - -time: - - platform: homeassistant - on_time: - - at: "16:00:00" - then: - - logger.log: It's 16:00 - - if: - condition: - - sensor.duty_time.is_running: duty_time2 - then: - - sensor.duty_time.start: duty_time1 - - if: - condition: - - sensor.duty_time.is_not_running: duty_time1 - then: - - sensor.duty_time.stop: duty_time2 - - sensor.duty_time.reset: duty_time1 - -esp32_touch: - setup_mode: true - -binary_sensor: - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - platform: homeassistant - entity_id: binary_sensor.hello - attribute: world - id: ha_hello_world_binary_attribute - - platform: ble_presence - mac_address: AC:37:43:77:5F:4C - name: ESP32 BLE Tracker Google Home Mini - timeout: 30s - - platform: ble_presence - service_uuid: 11aa - name: BLE Test Service 16 Presence - - platform: ble_presence - service_uuid: "11223344" - name: BLE Test Service 32 Presence - - platform: ble_presence - service_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - name: BLE Test Service 128 Presence - - platform: ble_presence - ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00 - ibeacon_major: 100 - ibeacon_minor: 1 - name: BLE Test iBeacon Presence - - platform: esp32_touch - name: ESP32 Touch Pad GPIO27 - pin: GPIO27 - threshold: 1000 - - platform: as3935 - name: Storm Alert - - platform: xiaomi_mue4094rt - name: MUE4094RT Motion - mac_address: 7A:80:8E:19:36:BA - timeout: 5s - - platform: xiaomi_mjyd02yla - name: MJYD02YL-A Motion - mac_address: 50:EC:50:CD:32:02 - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - idle_time: - name: MJYD02YL-A Idle Time - light: - name: MJYD02YL-A Light Status - battery_level: - name: MJYD02YL-A Battery Level - - platform: xiaomi_wx08zm - name: WX08ZM Activation State - mac_address: 74:a3:4a:b5:07:34 - tablet: - name: WX08ZM Tablet Resource - battery_level: - name: WX08ZM Battery Level - - platform: xiaomi_cgpr1 - name: CGPR1 Motion - mac_address: "12:34:56:12:34:56" - bindkey: 48403ebe2d385db8d0c187f81e62cb64 - battery_level: - name: CGPR1 battery Level - idle_time: - name: CGPR1 Idle Time - illuminance: - name: CGPR1 Illuminance - - platform: xiaomi_rtcgq02lm - id: motion_rtcgq02lm - motion: - name: Mi Motion Sensor 2 - light: - name: Mi Motion Sensor 2 Light - button: - name: Mi Motion Sensor 2 Button - - platform: gpio - id: gpio_set_retry_test - pin: - allow_other_uses: true - number: GPIO9 - on_press: - then: - - lambda: |- - App.scheduler.set_retry(id(gpio_set_retry_test), "set_retry_test", 100, 3, [](const uint8_t remaining) { - return remaining ? RetryResult::RETRY : RetryResult::DONE; // just to reference both symbols - }, 5.0f); - -esp32_ble_tracker: - on_ble_advertise: - - mac_address: - - AA:BB:CC:DD:EE:FF - - FF:EE:DD:CC:BB:AA - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address (%s) exists in list", x.address_str().c_str()); - # yamllint enable rule:line-length - - mac_address: AC:37:43:77:5F:4C - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The device address is %s", x.address_str().c_str()); - # yamllint enable rule:line-length - on_ble_service_data_advertise: - - service_uuid: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of service data is %i", x.size()); - on_ble_manufacturer_data_advertise: - - manufacturer_id: ABCD - then: - - lambda: !lambda |- - ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); - -ble_client: - - mac_address: 01:02:03:04:05:06 - id: airthings01 - - mac_address: 01:02:03:04:05:06 - id: airthingsmini01 - - mac_address: 01:02:03:04:05:06 - id: radon_eye_ble_id - -airthings_ble: - -radon_eye_ble: - -ruuvi_ble: - -xiaomi_ble: - -mopeka_ble: - -bluetooth_proxy: - active: true - -xiaomi_rtcgq02lm: - - id: motion_rtcgq02lm - mac_address: 01:02:03:04:05:06 - bindkey: "48403ebe2d385db8d0c187f81e62cb64" - -status_led: - pin: - allow_other_uses: true - number: GPIO2 - -text_sensor: - - platform: version - name: ESPHome Version - icon: mdi:icon - id: version_sensor - on_value: - - if: - condition: - - api.connected: - then: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The state is %s=%s", x.c_str(), id(version_sensor).state.c_str()); - # yamllint enable rule:line-length - - script.execute: my_script - - script.execute: - id: my_script_with_params - prefix: Running my_script_with_params - param2: 100 - param3: true - - script.execute: - id: my_script_with_params - prefix: Running my_script_with_params using lambda parameters - param2: !lambda return 200; - param3: !lambda return true; - - homeassistant.service: - service: notify.html5 - data: - title: New Humidity - data_template: - message: The humidity is {{ my_variable }}%. - variables: - my_variable: |- - return id(version_sensor).state; - my_variable_str: |- - return "Hello World"; - - homeassistant.service: - service: light.turn_on - data: - entity_id: light.my_light - - homeassistant.tag_scanned: - tag: 1234-abcd - - homeassistant.tag_scanned: 1234-abcd - - deep_sleep.enter: - sleep_duration: 30min - - deep_sleep.enter: - sleep_duration: !lambda "return 30 * 60 * 1000;" - - platform: template - name: Template Text Sensor - lambda: |- - return {"Hello World"}; - filters: - - to_upper: - - to_lower: - - append: xyz - - prepend: abcd - - substitute: - - Hello -> Goodbye - - map: - - red -> green - - lambda: 'return {"1234"};' - - platform: homeassistant - entity_id: sensor.hello_world2 - id: ha_hello_world2 - - platform: homeassistant - entity_id: sensor.hello_world3 - id: ha_hello_world3 - attribute: some_attribute - - platform: ble_scanner - name: Scanner - -script: - - id: my_script - mode: single - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_queued - mode: queued - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_parallel - mode: parallel - max_runs: 2 - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_restart - mode: restart - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - - id: my_script_with_params - parameters: - prefix: string - param2: int - param3: bool - then: - - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());' - -stepper: - - platform: uln2003 - id: my_stepper - pin_a: - allow_other_uses: true - number: GPIO23 - pin_b: GPIO27 - pin_c: - allow_other_uses: true - number: GPIO25 - pin_d: GPIO26 - sleep_when_done: false - step_mode: HALF_STEP - max_speed: 250 steps/s - - # Optional: - acceleration: inf - deceleration: inf - -interval: - interval: 5s - startup_delay: 10s - then: - - logger.log: Interval Run - -display: - - platform: st7789v - model: LILYGO_T-EMBED_170X320 - spi_mode: mode0 - height: 320 - width: 170 - offset_height: 35 - offset_width: 0 - dc_pin: GPIO13 - reset_pin: - allow_other_uses: true - number: GPIO9 - -image: - - id: binary_image - file: pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: pnglogo.png - type: RGB24 - use_transparency: true - - id: rgb565_image - file: pnglogo.png - type: RGB565 - use_transparency: false - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY - -graph: - - id: my_graph - sensor: ha_hello_world_temperature - duration: 1h - width: 100 - height: 100 - -cap1188: - id: cap1188_component - address: 0x29 - touch_threshold: 0x20 - allow_multiple_touches: true - reset_pin: 14 - -switch: - - platform: template - name: Test BLE Write Action - turn_on_action: - - ble_client.ble_write: - id: airthings01 - service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE - characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC - value: [0x01, 0xab, 0xff] - - ble_client.ble_write: - id: airthings01 - service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE - characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC - value: !lambda |- - return {0x13, 0x37}; - -esp32_ble_server: - id: ble - manufacturer_data: [0x72, 0x4, 0x00, 0x23] - -text: - - platform: template - name: My Text - id: my_text - min_length: 0 - max_length: 20 - mode: text - pattern: "[a-z]+" - optimistic: true - restore_value: true - initial_value: "Hello World" - - platform: copy - name: My Text Copy - id: my_text_copy - source_id: my_text - mode: password diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml deleted file mode 100644 index c3b078fe67..0000000000 --- a/tests/test3.1.yaml +++ /dev/null @@ -1,734 +0,0 @@ ---- -esphome: - name: $device_name - comment: $device_comment - build_path: build/test3.1 - includes: - - custom.h - -esp8266: - board: d1_mini - -substitutions: - device_name: test3-1 - device_comment: test3-1 device - min_sub: "0.03" - max_sub: "12.0%" - -api: - -wifi: - ssid: "MySSID" - password: "password1" - -network: - enable_ipv6: true - -web_server: - port: 80 - version: 2 - -i2c: - sda: - allow_other_uses: true - number: 4 - scl: - allow_other_uses: true - number: 5 - scan: false - -spi: - clk_pin: - allow_other_uses: true - number: GPIO12 - mosi_pin: - allow_other_uses: true - number: GPIO13 - miso_pin: - allow_other_uses: true - number: GPIO14 - -ota: - - platform: esphome - version: 2 - -logger: - -debug: - -sensor: - - platform: apds9960 - type: proximity - name: APDS9960 Proximity - - platform: vl53l0x - name: VL53L0x Distance - address: 0x29 - update_interval: 60s - enable_pin: - allow_other_uses: true - number: GPIO13 - timeout: 200us - - platform: apds9960 - type: clear - name: APDS9960 Clear - - platform: apds9960 - type: red - name: APDS9960 Red - - platform: apds9960 - type: green - name: APDS9960 Green - - platform: apds9960 - type: blue - name: APDS9960 Blue - - - platform: aht10 - temperature: - name: Temperature - humidity: - name: Humidity - - platform: am2320 - temperature: - name: Temperature - humidity: - name: Humidity - - platform: adc - pin: VCC - id: my_sensor - filters: - - offset: 5.0 - - multiply: 2.0 - - filter_out: NAN - - sliding_window_moving_average: - - exponential_moving_average: - - quantile: - window_size: 5 - send_every: 5 - send_first_at: 3 - quantile: .8 - - lambda: "return 0;" - - delta: 100 - - throttle: 100ms - - debounce: 500s - - timeout: 10min - - timeout: - timeout: 10min - value: 0 - - calibrate_linear: - method: exact - datapoints: - - -1 -> 3 - - 0.0 -> 1.0 - - 1.0 -> 2.0 - - 2.0 -> 3.0 - - calibrate_polynomial: - degree: 3 - datapoints: - - 0 -> 0 - - 100 -> 200 - - 400 -> 500 - - -50 -> -1000 - - -100 -> -10000 - - platform: cd74hc4067 - id: cd74hc4067_0 - number: 0 - sensor: my_sensor - - platform: resistance - sensor: my_sensor - configuration: DOWNSTREAM - resistor: 10kΩ - reference_voltage: 3.3V - name: Resistance - id: resist - - platform: ntc - sensor: resist - name: NTC Sensor - calibration: - b_constant: 3950 - reference_resistance: 10k - reference_temperature: 25°C - - platform: ntc - sensor: resist - name: NTC Sensor2 - calibration: - - 10.0kOhm -> 25°C - - 27.219kOhm -> 0°C - - 14.674kOhm -> 15°C - - platform: ct_clamp - sensor: my_sensor - name: CT Clamp - sample_duration: 500ms - update_interval: 5s - - - platform: tcs34725 - red_channel: - name: Red Channel - green_channel: - name: Green Channel - blue_channel: - name: Blue Channel - clear_channel: - name: Clear Channel - illuminance: - name: Illuminance - color_temperature: - name: Color Temperature - integration_time: 614ms - gain: 60x - - platform: custom - lambda: |- - auto s = new CustomSensor(); - App.register_component(s); - return {s}; - sensors: - - id: custom_sensor - name: Custom Sensor - - - platform: ade7953_i2c - irq_pin: - allow_other_uses: true - number: GPIO16 - voltage: - name: ADE7953 Voltage - id: ade7953_voltage - current_a: - name: ADE7953 Current A - id: ade7953_current_a - current_b: - name: ADE7953 Current B - id: ade7953_current_b - power_factor_a: - name: "ADE7953 Power Factor A" - power_factor_b: - name: "ADE7953 Power Factor B" - apparent_power_a: - name: "ADE7953 Apparent Power A" - apparent_power_b: - name: "ADE7953 Apparent Power B" - active_power_a: - name: ADE7953 Active Power A - active_power_b: - name: ADE7953 Active Power B - reactive_power_a: - name: "ADE7953 Reactive Power A" - reactive_power_b: - name: "ADE7953 Reactive Power B" - update_interval: 1s - - - platform: ade7953_spi - cs_pin: - allow_other_uses: true - number: GPIO04 - irq_pin: - allow_other_uses: true - number: GPIO16 - voltage: - name: ADE7953 Voltage - current_a: - name: ADE7953 Current A - current_b: - name: ADE7953 Current B - power_factor_a: - name: "ADE7953 Power Factor A" - power_factor_b: - name: "ADE7953 Power Factor B" - apparent_power_a: - name: "ADE7953 Apparent Power A" - apparent_power_b: - name: "ADE7953 Apparent Power B" - active_power_a: - name: ADE7953 Active Power A - active_power_b: - name: ADE7953 Active Power B - reactive_power_a: - name: "ADE7953 Reactive Power A" - reactive_power_b: - name: "ADE7953 Reactive Power B" - update_interval: 1s - - - platform: tmp102 - name: TMP102 Temperature - - platform: hm3301 - pm_1_0: - name: PM1.0 - pm_2_5: - name: PM2.5 - pm_10_0: - name: PM10.0 - aqi: - name: AQI - calculation_type: AQI - - platform: ezo - id: ph_ezo - address: 99 - unit_of_measurement: pH - - platform: tof10120 - name: Distance sensor - update_interval: 5s - - - platform: mlx90393 - oversampling: 1 - filter: 0 - gain: 3X - x_axis: - name: mlxxaxis - y_axis: - name: mlxyaxis - z_axis: - name: mlxzaxis - resolution: 17BIT - temperature: - name: mlxtemp - oversampling: 2 - - - platform: adc128s102 - id: adc128s102_channel_0 - channel: 0 - - - platform: ade7880 - irq0_pin: - number: GPIO13 - allow_other_uses: true - irq1_pin: - number: GPIO5 - allow_other_uses: true - reset_pin: - number: GPIO16 - allow_other_uses: true - frequency: 60Hz - phase_a: - name: Channel A - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3116628 - voltage_gain: -757178 - power_gain: -1344457 - phase_angle: 188 - phase_b: - name: Channel B - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3133655 - voltage_gain: -755235 - power_gain: -1345638 - phase_angle: 188 - phase_c: - name: Channel C - voltage: Voltage - current: Current - active_power: Active Power - power_factor: Power Factor - forward_active_energy: Forward Active Energy - reverse_active_energy: Reverse Active Energy - calibration: - current_gain: 3111158 - voltage_gain: -743813 - power_gain: -1351437 - phase_angle: 180 - neutral: - name: Neutral - current: Current - calibration: - current_gain: 3189 - -apds9960: - address: 0x20 - update_interval: 60s - -binary_sensor: - - platform: apds9960 - direction: up - name: APDS9960 Up - device_class: motion - filters: - - invert - - delayed_on: 20ms - - delayed_off: 20ms - - lambda: "return false;" - on_state: - - logger.log: New state - id: my_binary_sensor - - platform: apds9960 - direction: down - name: APDS9960 Down - - platform: apds9960 - direction: left - name: APDS9960 Left - - platform: apds9960 - direction: right - name: APDS9960 Right - - - platform: ttp229_lsf - channel: 1 - name: TTP229 LSF Test - - platform: ttp229_bsf - channel: 1 - name: TTP229 BSF Test - - platform: custom - lambda: |- - auto s = new CustomBinarySensor(); - App.register_component(s); - return {s}; - binary_sensors: - - id: custom_binary_sensor - name: Custom Binary Sensor - - - platform: template - id: cover_toggle - on_press: - then: - - cover.toggle: time_based_cover - - cover.toggle: endstop_cover - - cover.toggle: current_based_cover - -globals: - - id: my_global_string - type: std::string - initial_value: '""' - -text_sensor: - - platform: custom - lambda: |- - auto s = new CustomTextSensor(); - App.register_component(s); - return {s}; - text_sensors: - - id: custom_text_sensor - name: Custom Text Sensor - -sm2135: - data_pin: - allow_other_uses: true - number: GPIO12 - clock_pin: - allow_other_uses: true - number: GPIO14 - rgb_current: 20mA - cw_current: 60mA - -grove_tb6612fng: - id: test_motor - address: 0x14 - -switch: - - platform: gpio - id: gpio_switch1 - pin: - mcp23xxx: mcp23017_hub - number: 0 - mode: OUTPUT - interlock: &interlock [gpio_switch1, gpio_switch2, gpio_switch3] - - platform: gpio - id: gpio_switch2 - pin: - mcp23xxx: mcp23008_hub - number: 0 - mode: OUTPUT - interlock: *interlock - - platform: gpio - id: gpio_switch3 - pin: - allow_other_uses: true - number: GPIO1 - interlock: *interlock - - platform: custom - lambda: |- - auto s = new CustomSwitch(); - return {s}; - switches: - - id: custom_switch - name: Custom Switch - - platform: template - name: open_vent - id: open_vent - optimistic: true - on_turn_on: - then: - - grove_tb6612fng.run: - channel: 1 - speed: 255 - direction: BACKWARD - id: test_motor - -custom_component: - lambda: |- - auto s = new CustomComponent(); - s->set_update_interval(15000); - return {s}; - -stepper: - - platform: uln2003 - id: my_stepper - pin_a: - allow_other_uses: true - number: GPIO12 - pin_b: - allow_other_uses: true - number: GPIO13 - pin_c: - allow_other_uses: true - number: GPIO14 - pin_d: - allow_other_uses: true - number: GPIO15 - sleep_when_done: false - step_mode: HALF_STEP - max_speed: 250 steps/s - acceleration: inf - deceleration: inf - - platform: a4988 - id: my_stepper2 - step_pin: - allow_other_uses: true - number: GPIO1 - dir_pin: - allow_other_uses: true - number: GPIO2 - max_speed: 0.1 steps/s - acceleration: 10 steps/s^2 - deceleration: 10 steps/s^2 - -interval: - interval: 5s - then: - - logger.log: Interval Run - - stepper.set_target: - id: my_stepper2 - target: 500 - - stepper.set_target: - id: my_stepper - target: !lambda "return 0;" - - stepper.report_position: - id: my_stepper2 - position: 0 - - stepper.report_position: - id: my_stepper - position: !lambda "return 50/100.0;" - -cover: - - platform: endstop - name: Endstop Cover - id: endstop_cover - stop_action: - - switch.turn_on: gpio_switch1 - open_endstop: my_binary_sensor - open_action: - - switch.turn_on: gpio_switch1 - open_duration: 5min - close_endstop: my_binary_sensor - close_action: - - switch.turn_on: gpio_switch2 - - output.set_level: - id: out - level: 50% - - output.esp8266_pwm.set_frequency: - id: out - frequency: 500.0Hz - - output.esp8266_pwm.set_frequency: - id: out - frequency: !lambda "return 500.0;" - - servo.write: - id: my_servo - level: -100% - - servo.write: - id: my_servo - level: !lambda "return -1.0;" - - delay: 2s - - servo.detach: my_servo - close_duration: 4.5min - max_duration: 10min - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - switch.turn_on: gpio_switch1 - open_action: - - switch.turn_on: gpio_switch1 - open_duration: 5min - close_action: - - switch.turn_on: gpio_switch2 - close_duration: 4.5min - - platform: current_based - name: Current Based Cover - id: current_based_cover - open_sensor: ade7953_current_a - open_moving_current_threshold: 0.5 - open_obstacle_current_threshold: 0.8 - open_duration: 12s - open_action: - - switch.turn_on: gpio_switch1 - close_sensor: ade7953_current_b - close_moving_current_threshold: 0.5 - close_obstacle_current_threshold: 0.8 - close_duration: 10s - close_action: - - switch.turn_on: gpio_switch2 - stop_action: - - switch.turn_off: gpio_switch1 - - switch.turn_off: gpio_switch2 - obstacle_rollback: 30% - start_sensing_delay: 0.8s - malfunction_detection: true - malfunction_action: - then: - - logger.log: Malfunction Detected - - platform: template - name: Template Cover with Tilt - tilt_lambda: "return 0.5;" - tilt_action: - - output.set_level: - id: out - level: !lambda "return tilt;" - position_action: - - output.set_level: - id: out - level: !lambda "return pos;" - -output: - - platform: esp8266_pwm - id: out - pin: - number: D3 - frequency: 50Hz - - platform: esp8266_pwm - id: out2 - pin: - allow_other_uses: true - number: D4 - - platform: custom - type: binary - lambda: |- - auto s = new CustomBinaryOutput(); - App.register_component(s); - return {s}; - outputs: - - id: custom_binary - - platform: sigma_delta_output - id: sddac - update_interval: 60s - pin: - allow_other_uses: true - number: D4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - - platform: custom - type: float - lambda: |- - auto s = new CustomFloatOutput(); - App.register_component(s); - return {s}; - outputs: - - id: custom_float - - platform: slow_pwm - pin: - allow_other_uses: true - number: GPIO5 - id: my_slow_pwm - period: 15s - restart_cycle_on_state_change: false - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 - -mcp23017: - id: mcp23017_hub - -mcp23008: - id: mcp23008_hub - -light: - - platform: hbridge - name: Icicle Lights - pin_a: out - pin_b: out2 - -servo: - id: my_servo - output: out - restore: true - min_level: $min_sub - max_level: $max_sub - -ttp229_lsf: - -ttp229_bsf: - sdo_pin: - allow_other_uses: true - number: D2 - scl_pin: - allow_other_uses: true - number: D1 - -display: - - platform: max7219digit - cs_pin: - allow_other_uses: true - number: GPIO15 - num_chips: 4 - rotate_chip: 0 - intensity: 10 - scroll_mode: STOP - id: my_matrix - lambda: |- - it.printdigit("hello"); - -button: - - platform: output - id: output_button - output: out - duration: 100ms - - platform: wake_on_lan - target_mac_address: 12:34:56:78:90:ab - name: wol_test_1 - id: wol_1 - - platform: factory_reset - name: Restart Button (Factory Default Settings) - -cd74hc4067: - pin_s0: - allow_other_uses: true - number: GPIO12 - pin_s1: - allow_other_uses: true - number: GPIO13 - pin_s2: - allow_other_uses: true - number: GPIO14 - pin_s3: - allow_other_uses: true - number: GPIO15 - -adc128s102: - cs_pin: - allow_other_uses: true - number: GPIO12 diff --git a/tests/test3.yaml b/tests/test3.yaml deleted file mode 100644 index d10413b142..0000000000 --- a/tests/test3.yaml +++ /dev/null @@ -1,1432 +0,0 @@ ---- -esphome: - name: $device_name - comment: $device_comment - build_path: build/test3 - on_boot: - - if: - condition: - - api.connected - - wifi.connected - - time.has_time - then: - - logger.log: Have time - -esp8266: - board: d1_mini - early_pin_init: true - -substitutions: - device_name: test3 - device_comment: test3 device - -api: - port: 8000 - password: pwd - reboot_timeout: 0min - encryption: - key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world - variables: - name: string - then: - - logger.log: - format: Hello World %s! - args: - - name.c_str() - - service: empty_service - then: - - logger.log: Service Called - - service: all_types - variables: - bool_: bool - int_: int - float_: float - string_: string - then: - - logger.log: Something happened - - service: array_types - variables: - bool_arr: bool[] - int_arr: int[] - float_arr: float[] - string_arr: string[] - then: - - logger.log: - # yamllint disable rule:line-length - format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" - # yamllint enable rule:line-length - args: - - YESNO(bool_arr[0]) - - bool_arr.size() - - int_arr[0] - - int_arr.size() - - float_arr[0] - - float_arr.size() - - string_arr[0].c_str() - - string_arr.size() - - service: dfplayer_next - then: - - dfplayer.play_next: - - service: dfplayer_previous - then: - - dfplayer.play_previous: - - service: dfplayer_play - variables: - file: int - then: - - dfplayer.play: !lambda "return file;" - - service: dfplayer_play_loop - variables: - file: int - loop_: bool - then: - - dfplayer.play: - file: !lambda "return file;" - loop: !lambda "return loop_;" - - service: dfplayer_play_folder - variables: - folder: int - file: int - then: - - dfplayer.play_folder: - folder: !lambda "return folder;" - file: !lambda "return file;" - - - service: dfplayer_play_loo_folder - variables: - folder: int - then: - - dfplayer.play_folder: - folder: !lambda "return folder;" - loop: true - - - service: dfplayer_set_device - variables: - device: int - then: - - dfplayer.set_device: - device: TF_CARD - - - service: dfplayer_set_volume - variables: - volume: int - then: - - dfplayer.set_volume: !lambda "return volume;" - - service: dfplayer_set_eq - variables: - preset: int - then: - # yamllint disable rule:line-length - - dfplayer.set_eq: !lambda "return static_cast(preset);" - # yamllint enable rule:line-length - - - service: dfplayer_sleep - then: - - dfplayer.sleep - - - service: dfplayer_reset - then: - - dfplayer.reset - - - service: dfplayer_start - then: - - dfplayer.start - - - service: dfplayer_pause - then: - - dfplayer.pause - - - service: dfplayer_stop - then: - - dfplayer.stop - - - service: dfplayer_random - then: - - dfplayer.random - - - service: dfplayer_volume_up - then: - - dfplayer.volume_up - - - service: dfplayer_volume_down - then: - - dfplayer.volume_down - - - service: battery_level_percent - variables: - level_percent: int - then: - - tm1651.set_level_percent: - id: tm1651_battery - level_percent: !lambda "return level_percent;" - - service: battery_level - variables: - level: int - then: - - tm1651.set_level: - id: tm1651_battery - level: !lambda "return level;" - - service: battery_brightness - variables: - brightness: int - then: - - tm1651.set_brightness: - id: tm1651_battery - brightness: !lambda "return brightness;" - - service: battery_turn_on - then: - - tm1651.turn_on: - id: tm1651_battery - - service: battery_turn_on - then: - - tm1651.turn_off: - id: tm1651_battery - - service: pid_set_control_parameters - then: - - climate.pid.set_control_parameters: - id: pid_climate - kp: 1.0 - kd: 1.0 - ki: 1.0 - - service: fingerprint_grow_enroll - variables: - finger_id: int - num_scans: int - then: - - fingerprint_grow.enroll: - finger_id: !lambda "return finger_id;" - num_scans: !lambda "return num_scans;" - - service: fingerprint_grow_cancel_enroll - then: - - fingerprint_grow.cancel_enroll: - - service: fingerprint_grow_delete - variables: - finger_id: int - then: - - fingerprint_grow.delete: - finger_id: !lambda "return finger_id;" - - service: fingerprint_grow_delete_all - then: - - fingerprint_grow.delete_all: - -wifi: - ssid: "MySSID" - password: "password1" - -network: - enable_ipv6: true - -uart: - - id: uart_1 - tx_pin: - number: GPIO1 - inverted: true - allow_other_uses: true - rx_pin: - allow_other_uses: true - number: GPIO3 - baud_rate: 115200 - - id: uart_2 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_3 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 4800 - - id: uart_4 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_5 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_6 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_7 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 38400 - - id: uart_8 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 4800 - parity: NONE - stop_bits: 2 - # Specifically added for testing debug with no options at all. - debug: - - id: uart_9 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_10 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_11 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - - id: uart_12 - tx_pin: - allow_other_uses: true - number: GPIO4 - rx_pin: - allow_other_uses: true - number: GPIO5 - baud_rate: 9600 - -modbus: - uart_id: uart_1 - -vbus: - uart_id: uart_4 - -safe_mode: - num_attempts: 5 - reboot_timeout: 10min - -ota: - - platform: esphome - port: 3286 - -logger: - hardware_uart: UART1 - level: DEBUG - esp8266_store_log_strings_in_flash: true - -debug: - -improv_serial: - next_url: https://esphome.io/?name={{device_name}}&version={{esphome_version}}&ip={{ip_address}} - -deep_sleep: - run_duration: 20s - sleep_duration: 50s - -wled: - -adalight: - -sensor: - - platform: daly_bms - voltage: - name: Battery Voltage - current: - name: Battery Current - battery_level: - name: Battery Level - max_cell_voltage: - name: Max Cell Voltage - max_cell_voltage_number: - name: Max Cell Voltage Number - min_cell_voltage: - name: Min Cell Voltage - min_cell_voltage_number: - name: Min Cell Voltage Number - max_temperature: - name: Max Temperature - max_temperature_probe_number: - name: Max Temperature Probe Number - min_temperature: - name: Min Temperature - min_temperature_probe_number: - name: Min Temperature Probe Number - remaining_capacity: - name: Remaining Capacity - cells_number: - name: Cells Number - temperature_1: - name: Temperature 1 - temperature_2: - name: Temperature 2 - - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - - platform: hydreon_rgxx - model: RG 9 - uart_id: uart_6 - id: hydreon_rg9 - moisture: - name: hydreon_rain - id: hydreon_rain - temperature: - name: hydreon_temperature - disable_led: true - - - platform: hydreon_rgxx - model: RG_15 - uart_id: uart_6 - acc: - name: hydreon_acc - event_acc: - name: hydreon_event_acc - total_acc: - name: hydreon_total_acc - r_int: - name: hydreon_r_int - resolution: low - - - platform: adc - pin: VCC - id: my_sensor - - - platform: binary_sensor_map - name: Binary Sensor Map - type: group - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - - platform: binary_sensor_map - name: Binary Sensor Map - type: sum - channels: - - binary_sensor: bin1 - value: 10.0 - - binary_sensor: bin2 - value: 15.0 - - binary_sensor: bin3 - value: 100.0 - - - platform: binary_sensor_map - name: Binary Sensor Map - type: bayesian - prior: 0.4 - observations: - - binary_sensor: bin1 - prob_given_true: 0.9 - prob_given_false: 0.4 - - binary_sensor: bin2 - prob_given_true: 0.7 - prob_given_false: 0.05 - - binary_sensor: bin3 - prob_given_true: 0.8 - prob_given_false: 0.2 - - - platform: bl0939 - uart_id: uart_8 - voltage: - name: BL0939 Voltage - current_1: - name: BL0939 Current 1 - current_2: - name: BL0939 Current 2 - active_power_1: - name: BL0939 Active Power 1 - active_power_2: - name: BL0939 Active Power 2 - energy_1: - name: BL0939 Energy 1 - energy_2: - name: BL0939 Energy 2 - energy_total: - name: BL0939 Total energy - - platform: bl0940 - uart_id: uart_3 - voltage: - name: BL0940 Voltage - current: - name: BL0940 Current - power: - name: BL0940 Power - energy: - name: BL0940 Energy - internal_temperature: - name: BL0940 Internal temperature - external_temperature: - name: BL0940 External temperature - - platform: bl0942 - uart_id: uart_3 - voltage: - name: BL0942 Voltage - current: - name: BL0942 Current - power: - name: BL0942 Power - energy: - name: BL0942 Energy - frequency: - name: BL0942 Frequency - - platform: pzem004t - uart_id: uart_3 - voltage: - name: PZEM004T Voltage - current: - name: PZEM004T Current - power: - name: PZEM004T Power - - platform: pzemac - id: pzemac1 - voltage: - name: PZEMAC Voltage - current: - name: PZEMAC Current - power: - name: PZEMAC Power - energy: - name: PZEMAC Energy - frequency: - name: PZEMAC Frequency - power_factor: - name: PZEMAC Power Factor - - platform: pzemdc - id: pzemdc1 - voltage: - name: PZEMDC Voltage - current: - name: PZEMDC Current - power: - name: PZEMDC Power - energy: - name: PZEMDC Energy - - platform: pmsx003 - uart_id: uart_9 - type: PMSX003 - pm_1_0: - name: PM 1.0 Concentration - pm_2_5: - name: PM 2.5 Concentration - pm_10_0: - name: PM 10.0 Concentration - pm_1_0_std: - name: PM 1.0 Standard Atmospher Concentration - pm_2_5_std: - name: PM 2.5 Standard Atmospher Concentration - pm_10_0_std: - name: PM 10.0 Standard Atmospher Concentration - pm_0_3um: - name: Particulate Count >0.3um - pm_0_5um: - name: Particulate Count >0.5um - pm_1_0um: - name: Particulate Count >1.0um - pm_2_5um: - name: Particulate Count >2.5um - pm_5_0um: - name: Particulate Count >5.0um - pm_10_0um: - name: Particulate Count >10.0um - update_interval: 30s - - platform: pmsx003 - uart_id: uart_5 - type: PMS5003T - pm_1_0: - name: PM 1.0 Concentration - pm_2_5: - name: PM 2.5 Concentration - pm_10_0: - name: PM 10.0 Concentration - pm_1_0_std: - name: PM 1.0 Standard Atmospher Concentration - pm_2_5_std: - name: PM 2.5 Standard Atmospher Concentration - pm_10_0_std: - name: PM 10.0 Standard Atmospher Concentration - pm_0_3um: - name: Particulate Count >0.3um - pm_0_5um: - name: Particulate Count >0.5um - pm_1_0um: - name: Particulate Count >1.0um - pm_2_5um: - name: Particulate Count >2.5um - temperature: - name: PMS Temperature - humidity: - name: PMS Humidity - - platform: pmsx003 - uart_id: uart_6 - type: PMS5003ST - pm_1_0: - name: PM 1.0 Concentration - pm_2_5: - name: PM 2.5 Concentration - pm_10_0: - name: PM 10.0 Concentration - pm_1_0_std: - name: PM 1.0 Standard Atmospher Concentration - pm_2_5_std: - name: PM 2.5 Standard Atmospher Concentration - pm_10_0_std: - name: PM 10.0 Standard Atmospher Concentration - pm_0_3um: - name: Particulate Count >0.3um - pm_0_5um: - name: Particulate Count >0.5um - pm_1_0um: - name: Particulate Count >1.0um - pm_2_5um: - name: Particulate Count >2.5um - pm_5_0um: - name: Particulate Count >5.0um - pm_10_0um: - name: Particulate Count >10.0um - temperature: - name: PMS Temperature - humidity: - name: PMS Humidity - formaldehyde: - name: PMS Formaldehyde Concentration - - platform: cse7761 - uart_id: uart_7 - voltage: - name: CSE7761 Voltage - current_1: - name: CSE7761 Current 1 - current_2: - name: CSE7761 Current 2 - active_power_1: - name: CSE7761 Active Power 1 - active_power_2: - name: CSE7761 Active Power 2 - - platform: cse7766 - uart_id: uart_3 - voltage: - name: CSE7766 Voltage - current: - name: CSE7766 Current - power: - name: CSE7766 Power - apparent_power: - name: CSE7766 Apparent Power - power_factor: - name: CSE7766 Power Factor - - - platform: fingerprint_grow - fingerprint_count: - name: Fingerprint Count - status: - name: Fingerprint Status - capacity: - name: Fingerprint Capacity - security_level: - name: Fingerprint Security Level - last_finger_id: - name: Fingerprint Last Finger ID - last_confidence: - name: Fingerprint Last Confidence - - platform: sdm_meter - phase_a: - current: - name: Phase A Current - voltage: - name: Phase A Voltage - active_power: - name: Phase A Power - power_factor: - name: Phase A Power Factor - apparent_power: - name: Phase A Apparent Power - reactive_power: - name: Phase A Reactive Power - phase_angle: - name: Phase A Phase Angle - phase_b: - current: - name: Phase B Current - voltage: - name: Phase B Voltage - active_power: - name: Phase B Power - power_factor: - name: Phase B Power Factor - apparent_power: - name: Phase B Apparent Power - reactive_power: - name: Phase B Reactive Power - phase_angle: - name: Phase B Phase Angle - phase_c: - current: - name: Phase C Current - voltage: - name: Phase C Voltage - active_power: - name: Phase C Power - power_factor: - name: Phase C Power Factor - apparent_power: - name: Phase C Apparent Power - reactive_power: - name: Phase C Reactive Power - phase_angle: - name: Phase C Phase Angle - frequency: - name: Frequency - import_active_energy: - name: Import Active Energy - export_active_energy: - name: Export Active Energy - import_reactive_energy: - name: Import Reactive Energy - export_reactive_energy: - name: Export Reactive Energy - - platform: dsmr - energy_delivered_tariff1: - name: dsmr_energy_delivered_tariff1 - - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - - platform: smt100 - uart_id: uart_10 - counts: - name: Counts - dielectric_constant: - name: Dielectric Constant - temperature: - name: Temperature - moisture: - name: Moisture - voltage: - name: Voltage - update_interval: 60s - - - platform: vbus - model: deltasol c - temperature_1: - name: Temperature 1 - - - platform: kuntze - ph: - name: Kuntze pH - temperature: - name: Kuntze temperature - - - platform: haier - haier_id: haier_climate - compressor_current: - name: Haier AC compressor current - compressor_frequency: - name: Haier AC compressor frequency - expansion_valve_open_degree: - name: Haier AC expansion valve open degree - humidity: - name: Haier AC indoor humidity - indoor_coil_temperature: - name: Haier AC indoor coil temperature - outdoor_coil_temperature: - name: Haier AC outdoor coil temperature - outdoor_defrost_temperature: - name: Haier AC outdoor defrost temperature - outdoor_in_air_temperature: - name: Haier AC outdoor in air temperature - outdoor_out_air_temperature: - name: Haier AC outdoor out air temperature - outdoor_temperature: - name: Haier AC outdoor temperature - power: - name: Haier AC power - -time: - - platform: homeassistant - -binary_sensor: - - platform: daly_bms - charging_mos_enabled: - name: Charging MOS - discharging_mos_enabled: - name: Discharging MOS - - - platform: homeassistant - entity_id: binary_sensor.hello_world - id: ha_hello_world_binary - - - platform: fingerprint_grow - name: Fingerprint Enrolling - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Component 2 Touch - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - - - platform: hydreon_rgxx - hydreon_rgxx_id: hydreon_rg9 - too_cold: - name: rg9_toocold - em_sat: - name: rg9_emsat - lens_bad: - name: rg9_lens_bad - - - platform: template - id: pzemac_reset_energy - on_press: - then: - - pzemac.reset_energy: pzemac1 - - platform: template - id: pzemdc_reset_energy - on_press: - then: - - pzemdc.reset_energy: pzemdc1 - - - platform: vbus - model: deltasol_bs_plus - relay1: - name: Relay 1 On - - - platform: gpio - id: bin1 - pin: - allow_other_uses: true - number: 1 - - platform: gpio - id: bin2 - pin: - allow_other_uses: true - number: 2 - - platform: gpio - id: bin3 - pin: - allow_other_uses: true - number: 3 - - - platform: haier - haier_id: haier_climate - compressor_status: - name: Haier AC compressor status - defrost_status: - name: Haier AC defrost status - four_way_valve_status: - name: Haier AC four-way valve status - indoor_electric_heating_status: - name: Haier AC indoor electric heating status - indoor_fan_status: - name: Haier AC indoor fan status - outdoor_fan_status: - name: Haier AC outdoor fan status - -globals: - - id: my_global_string - type: std::string - initial_value: '""' - -remote_receiver: - pin: - allow_other_uses: true - number: GPIO12 - dump: [] - -status_led: - pin: - allow_other_uses: true - number: GPIO2 - -text_sensor: - - platform: daly_bms - status: - name: BMS Status - - platform: version - name: ESPHome Version - icon: mdi:icon - id: version_sensor - on_value: - # yamllint disable rule:line-length - - lambda: !lambda |- - ESP_LOGD("main", "The state is %s=%s", x.c_str(), id(version_sensor).state.c_str()); - # yamllint enable rule:line-length - - script.execute: my_script - - script.wait: my_script - - script.stop: my_script - - homeassistant.service: - service: notify.html5 - data: - title: New Humidity - data_template: - message: The humidity is {{ my_variable }}%. - variables: - my_variable: |- - return id(version_sensor).state; - - platform: template - name: Template Text Sensor - lambda: |- - return {"Hello World"}; - - platform: homeassistant - entity_id: sensor.hello_world2 - id: ha_hello_world2 - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 - - platform: dsmr - identification: - name: dsmr_identification - p1_version: - name: dsmr_p1_version - -script: - - id: my_script - then: - - lambda: 'ESP_LOGD("main", "Hello World!");' - -switch: - - platform: gpio - id: gpio_switch1 - pin: - allow_other_uses: true - number: 1 - - platform: gpio - id: gpio_switch2 - pin: - allow_other_uses: true - number: 2 - - platform: gpio - id: gpio_switch3 - pin: - allow_other_uses: true - number: 3 - - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -climate: - - platform: bang_bang - name: Bang Bang Climate - sensor: ha_hello_world - humidity_sensor: ha_hello_world - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - idle_action: - - switch.turn_on: gpio_switch1 - cool_action: - - switch.turn_on: gpio_switch2 - heat_action: - - switch.turn_on: gpio_switch1 - away_config: - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - - platform: thermostat - name: Thermostat Climate - sensor: ha_hello_world - humidity_sensor: ha_hello_world - preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C - idle_action: - - switch.turn_on: gpio_switch1 - cool_action: - - switch.turn_on: gpio_switch2 - supplemental_cooling_action: - - switch.turn_on: gpio_switch3 - heat_action: - - switch.turn_on: gpio_switch1 - supplemental_heating_action: - - switch.turn_on: gpio_switch3 - dry_action: - - switch.turn_on: gpio_switch2 - fan_only_action: - - switch.turn_on: gpio_switch1 - auto_mode: - - switch.turn_on: gpio_switch2 - off_mode: - - switch.turn_on: gpio_switch1 - heat_mode: - - switch.turn_on: gpio_switch2 - cool_mode: - - switch.turn_on: gpio_switch1 - dry_mode: - - switch.turn_on: gpio_switch2 - fan_only_mode: - - switch.turn_on: gpio_switch1 - fan_mode_auto_action: - - switch.turn_on: gpio_switch2 - fan_mode_on_action: - - switch.turn_on: gpio_switch1 - fan_mode_off_action: - - switch.turn_on: gpio_switch2 - fan_mode_low_action: - - switch.turn_on: gpio_switch1 - fan_mode_medium_action: - - switch.turn_on: gpio_switch2 - fan_mode_high_action: - - switch.turn_on: gpio_switch1 - fan_mode_middle_action: - - switch.turn_on: gpio_switch2 - fan_mode_focus_action: - - switch.turn_on: gpio_switch1 - fan_mode_diffuse_action: - - switch.turn_on: gpio_switch2 - fan_mode_quiet_action: - - switch.turn_on: gpio_switch1 - swing_off_action: - - switch.turn_on: gpio_switch2 - swing_horizontal_action: - - switch.turn_on: gpio_switch1 - swing_vertical_action: - - switch.turn_on: gpio_switch2 - swing_both_action: - - switch.turn_on: gpio_switch1 - startup_delay: true - supplemental_cooling_delta: 2.0 - cool_deadband: 0.5 - cool_overrun: 0.5 - min_cooling_off_time: 300s - min_cooling_run_time: 300s - max_cooling_run_time: 600s - supplemental_heating_delta: 2.0 - heat_deadband: 0.5 - heat_overrun: 0.5 - min_heating_off_time: 300s - min_heating_run_time: 300s - max_heating_run_time: 600s - min_fanning_off_time: 30s - min_fanning_run_time: 30s - min_fan_mode_switching_time: 15s - min_idle_time: 30s - set_point_minimum_differential: 0.5 - fan_only_action_uses_fan_mode_timer: true - fan_only_cooling: true - fan_with_cooling: true - fan_with_heating: true - - platform: pid - id: pid_climate - name: PID Climate Controller - sensor: ha_hello_world - humidity_sensor: ha_hello_world - default_target_temperature: 21°C - heat_output: my_slow_pwm - control_parameters: - kp: 0.0 - ki: 0.0 - kd: 0.0 - max_integral: 0.0 - output_averaging_samples: 1 - derivative_averaging_samples: 1 - deadband_parameters: - threshold_high: 0.4 - threshold_low: -2.0 - kp_multiplier: 0.0 - ki_multiplier: 0.0 - kd_multiplier: 0.0 - deadband_output_averaging_samples: 1 - - platform: haier - id: haier_climate - protocol: hOn - name: Haier AC - uart_id: uart_12 - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - "OFF" - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - "OFF" - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: 'Alarm activated. Code: %d. Message: "%s"' - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: 'Alarm deactivated. Code: %d. Message: "%s"' - args: [code, message] - -sprinkler: - - id: yard_sprinkler_ctrlr - main_switch: Yard Sprinklers - auto_advance_switch: Yard Sprinklers Auto Advance - reverse_switch: Yard Sprinklers Reverse - pump_start_pump_delay: 2s - pump_stop_valve_delay: 4s - pump_switch_off_during_valve_open_delay: true - valve_open_delay: 5s - valves: - - valve_switch: Yard Valve 0 - enable_switch: Enable Yard Valve 0 - pump_switch_id: gpio_switch1 - run_duration: 10s - valve_switch_id: gpio_switch2 - - valve_switch: Yard Valve 1 - enable_switch: Enable Yard Valve 1 - pump_switch_id: gpio_switch1 - run_duration: 10s - valve_switch_id: gpio_switch2 - - valve_switch: Yard Valve 2 - enable_switch: Enable Yard Valve 2 - pump_switch_id: gpio_switch1 - run_duration: 10s - valve_switch_id: gpio_switch2 - - id: garden_sprinkler_ctrlr - main_switch: Garden Sprinklers - auto_advance_switch: Garden Sprinklers Auto Advance - reverse_switch: Garden Sprinklers Reverse - valve_overlap: 5s - valves: - - valve_switch: Garden Valve 0 - enable_switch: Enable Garden Valve 0 - pump_switch_id: gpio_switch1 - run_duration: 10s - valve_switch_id: gpio_switch2 - - valve_switch: Garden Valve 1 - enable_switch: Enable Garden Valve 1 - pump_switch_id: gpio_switch1 - run_duration: 10s - valve_switch_id: gpio_switch2 - -output: - - platform: esp8266_pwm - id: out - pin: - number: D3 - frequency: 50Hz - - platform: esp8266_pwm - id: out2 - pin: - allow_other_uses: true - number: D4 - - platform: slow_pwm - pin: - allow_other_uses: true - number: GPIO5 - id: my_slow_pwm - period: 15s - restart_cycle_on_state_change: false - -e131: - -light: - - platform: neopixelbus - name: Neopixelbus Light - pin: - allow_other_uses: true - number: GPIO1 - type: GRBW - variant: SK6812 - method: ESP8266_UART0 - num_leds: 100 - effects: - - wled: - - adalight: - uart_id: uart_3 - - e131: - universe: 1 - - platform: hbridge - name: Icicle Lights - pin_a: out - pin_b: out2 - - platform: sonoff_d1 - uart_id: uart_2 - use_rm433_remote: false - name: Sonoff D1 Dimmer - id: d1_light - restore_mode: RESTORE_DEFAULT_OFF - - platform: shelly_dimmer - name: "Shelly Dimmer Light" - power: - name: "Shelly Dimmer Power" - voltage: - name: "Shelly Dimmer Voltage" - current: - name: "Shelly Dimmer Current" - max_brightness: 500 - firmware: "51.6" - uart_id: uart_11 - nrst_pin: - number: 5 - allow_other_uses: true - boot0_pin: - number: 4 - allow_other_uses: true - -sim800l: - uart_id: uart_4 - on_sms_received: - - lambda: |- - std::string str; - str = sender; - str = message; - - sim800l.send_sms: - message: hello you - recipient: "+1234" - - sim800l.dial: - recipient: "+1234" - -dfplayer: - uart_id: uart_5 - on_finished_playback: - then: - if: - condition: - not: dfplayer.is_playing - then: - logger.log: Playback finished event -tm1651: - id: tm1651_battery - clk_pin: - allow_other_uses: true - number: D6 - dio_pin: - allow_other_uses: true - number: D5 - -rf_bridge: - uart_id: uart_5 - on_code_received: - - lambda: |- - uint32_t test; - test = data.sync; - test = data.low; - test = data.high; - test = data.code; - - rf_bridge.send_code: - sync: 0x1234 - low: 0x1234 - high: 0x1234 - code: 0x123456 - - rf_bridge.learn - - on_advanced_code_received: - - lambda: |- - uint32_t test; - std::string test_code; - test = data.length; - test = data.protocol; - test_code = data.code; - - rf_bridge.start_advanced_sniffing: - - rf_bridge.stop_advanced_sniffing: - - rf_bridge.send_advanced_code: - length: 0x04 - protocol: 0x01 - code: "ABC123" - - rf_bridge.send_raw: - raw: "AAA5070008001000ABC12355" - -display: - - platform: nextion - uart_id: uart_1 - tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - -fingerprint_grow: - sensing_pin: - allow_other_uses: true - number: 4 - sensor_power_pin: - allow_other_uses: true - number: 5 - inverted: true - idle_period_to_sleep: 5s - password: 0x12FE37DC - new_password: 0xA65B9840 - on_finger_scan_start: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_finger_scan_start - on_finger_scan_invalid: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_finger_scan_invalid - on_finger_scan_matched: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_finger_scan_matched - data: - finger_id: !lambda "return finger_id;" - confidence: !lambda "return confidence;" - on_finger_scan_unmatched: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_finger_scan_unmatched - on_finger_scan_misplaced: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_finger_scan_misplaced - on_enrollment_scan: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_enrollment_scan - data: - finger_id: !lambda "return finger_id;" - scan_num: !lambda "return scan_num;" - on_enrollment_done: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_node_enrollment_done - data: - finger_id: !lambda "return finger_id;" - on_enrollment_failed: - - homeassistant.event: - event: esphome.${device_name}_fingerprint_grow_enrollment_failed - data: - finger_id: !lambda "return finger_id;" - uart_id: uart_6 - -dsmr: - decryption_key: 00112233445566778899aabbccddeeff - uart_id: uart_6 - max_telegram_length: 1000 - request_pin: - allow_other_uses: true - number: D5 - request_interval: 20s - receive_timeout: 100ms - -daly_bms: - update_interval: 20s - uart_id: uart_1 - -qr_code: - - id: homepage_qr - value: https://esphome.io/index.html - -lightwaverf: - read_pin: - number: 13 - write_pin: - allow_other_uses: true - number: 14 - -alarm_control_panel: - - platform: template - id: alarmcontrolpanel1 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_state: - then: - - lambda: !lambda |- - ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); - - platform: template - id: alarmcontrolpanel2 - name: Alarm Panel - codes: - - "1234" - requires_code_to_arm: true - arming_home_time: 1s - arming_night_time: 1s - arming_away_time: 15s - pending_time: 15s - trigger_time: 30s - binary_sensors: - - input: bin1 - bypass_armed_home: true - bypass_armed_night: true - on_disarmed: - then: - - logger.log: "### DISARMED ###" - on_pending: - then: - - logger.log: "### PENDING ###" - on_arming: - then: - - logger.log: "### ARMING ###" - on_armed_home: - then: - - logger.log: "### ARMED HOME ###" - on_armed_night: - then: - - logger.log: "### ARMED NIGHT ###" - on_armed_away: - then: - - logger.log: "### ARMED AWAY ###" - on_triggered: - then: - - logger.log: "### TRIGGERED ###" - on_cleared: - then: - - logger.log: "### CLEARED ###" diff --git a/tests/test4.yaml b/tests/test4.yaml deleted file mode 100644 index c9e8a27317..0000000000 --- a/tests/test4.yaml +++ /dev/null @@ -1,998 +0,0 @@ ---- -esphome: - name: $devicename - platform: ESP32 - board: nodemcu-32s - build_path: build/test4 - -substitutions: - devicename: test-4 - -ethernet: - type: LAN8720 - mdc_pin: - allow_other_uses: true - number: GPIO23 - mdio_pin: - allow_other_uses: true - number: GPIO25 - clk_mode: GPIO0_IN - phy_addr: 0 - power_pin: - allow_other_uses: true - number: GPIO25 - manual_ip: - static_ip: 192.168.178.56 - gateway: 192.168.178.1 - subnet: 255.255.255.0 - domain: .local - -network: - enable_ipv6: true - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - topic_prefix: - -api: - -i2c: - sda: - allow_other_uses: true - number: 21 - scl: - allow_other_uses: true - number: 22 - scan: false - -spi: - - id: spi_id_1 - clk_pin: - allow_other_uses: true - number: GPIO21 - mosi_pin: - allow_other_uses: true - number: GPIO22 - miso_pin: - allow_other_uses: true - number: GPIO23 - interface: hardware - - id: spi_id_2 - clk_pin: - number: GPIO32 - mosi_pin: - number: GPIO33 - interface: hardware - -uart: - - id: uart115200 - tx_pin: - allow_other_uses: true - number: GPIO22 - rx_pin: - allow_other_uses: true - number: GPIO23 - baud_rate: 115200 - - id: uart9600 - tx_pin: - allow_other_uses: true - number: GPIO25 - rx_pin: - allow_other_uses: true - number: GPIO26 - baud_rate: 9600 - - id: uart_a02yyuw - tx_pin: - allow_other_uses: true - number: GPIO22 - rx_pin: - allow_other_uses: true - number: GPIO23 - baud_rate: 9600 - - id: uart_he60r - tx_pin: - number: GPIO18 - allow_other_uses: true - rx_pin: - number: GPIO36 - allow_other_uses: true - baud_rate: 1200 - parity: EVEN - -safe_mode: - -ota: - - platform: esphome - port: 3286 - -logger: - level: DEBUG - -debug: - -web_server: - ota: false - auth: - username: admin - password: admin - include_internal: true - -time: - - platform: sntp - id: sntp_time - -tuya: - time_id: sntp_time - uart_id: uart115200 - status_pin: - number: GPIO5 - inverted: true - allow_other_uses: true - -select: - - platform: tuya - id: tuya_select - enum_datapoint: 42 - options: - 0: Internal - 1: Floor - 2: Both - -pipsolar: - id: inverter0 - uart_id: uart115200 - -pylontech: - - id: pylontech0 - uart_id: uart115200 - - id: pylontech1 - uart_id: uart115200 - -sx1509: - - id: sx1509_hub - address: 0x3E - -mcp3204: - spi_id: spi_id_1 - cs_pin: - allow_other_uses: true - number: GPIO23 - -dac7678: - address: 0x4A - id: dac7678_hub1 - internal_reference: true - -sensor: - - platform: pylontech - pylontech_id: pylontech0 - battery: 1 - voltage: - id: pyl01_voltage - current: - id: pyl01_current - coulomb: - id: pyl01_soc - mos_temperature: - id: pyl01_mos_temperature - - platform: pylontech - pylontech_id: pylontech1 - battery: 1 - voltage: - id: pyl13_voltage - temperature_low: - id: pyl13_temperature_low - temperature_high: - id: pyl13_temperature_high - voltage_low: - id: pyl13_voltage_low - voltage_high: - id: pyl13_voltage_high - - platform: homeassistant - entity_id: sensor.hello_world - id: ha_hello_world - - platform: tuya - id: tuya_sensor - sensor_datapoint: 1 - - platform: pipsolar - pipsolar_id: inverter0 - grid_rating_voltage: - id: inverter0_grid_rating_voltage - name: inverter0_grid_rating_voltage - grid_rating_current: - id: inverter0_grid_rating_current - name: inverter0_grid_rating_current - ac_output_rating_voltage: - id: inverter0_ac_output_rating_voltage - name: inverter0_ac_output_rating_voltage - ac_output_rating_frequency: - id: inverter0_ac_output_rating_frequency - name: inverter0_ac_output_rating_frequency - ac_output_rating_current: - id: inverter0_ac_output_rating_current - name: inverter0_ac_output_rating_current - ac_output_rating_apparent_power: - id: inverter0_ac_output_rating_apparent_power - name: inverter0_ac_output_rating_apparent_power - ac_output_rating_active_power: - id: inverter0_ac_output_rating_active_power - name: inverter0_ac_output_rating_active_power - battery_rating_voltage: - id: inverter0_battery_rating_voltage - name: inverter0_battery_rating_voltage - battery_recharge_voltage: - id: inverter0_battery_recharge_voltage - name: inverter0_battery_recharge_voltage - battery_under_voltage: - id: inverter0_battery_under_voltage - name: inverter0_battery_under_voltage - battery_bulk_voltage: - id: inverter0_battery_bulk_voltage - name: inverter0_battery_bulk_voltage - battery_float_voltage: - id: inverter0_battery_float_voltage - name: inverter0_battery_float_voltage - battery_type: - id: inverter0_battery_type - name: inverter0_battery_type - current_max_ac_charging_current: - id: inverter0_current_max_ac_charging_current - name: inverter0_current_max_ac_charging_current - current_max_charging_current: - id: inverter0_current_max_charging_current - name: inverter0_current_max_charging_current - input_voltage_range: - id: inverter0_input_voltage_range - name: inverter0_input_voltage_range - output_source_priority: - id: inverter0_output_source_priority - name: inverter0_output_source_priority - charger_source_priority: - id: inverter0_charger_source_priority - name: inverter0_charger_source_priority - parallel_max_num: - id: inverter0_parallel_max_num - name: inverter0_parallel_max_num - machine_type: - id: inverter0_machine_type - name: inverter0_machine_type - topology: - id: inverter0_topology - name: inverter0_topology - output_mode: - id: inverter0_output_mode - name: inverter0_output_mode - battery_redischarge_voltage: - id: inverter0_battery_redischarge_voltage - name: inverter0_battery_redischarge_voltage - pv_ok_condition_for_parallel: - id: inverter0_pv_ok_condition_for_parallel - name: inverter0_pv_ok_condition_for_parallel - pv_power_balance: - id: inverter0_pv_power_balance - name: inverter0_pv_power_balance - grid_voltage: - id: inverter0_grid_voltage - name: inverter0_grid_voltage - grid_frequency: - id: inverter0_grid_frequency - name: inverter0_grid_frequency - ac_output_voltage: - id: inverter0_ac_output_voltage - name: inverter0_ac_output_voltage - ac_output_frequency: - id: inverter0_ac_output_frequency - name: inverter0_ac_output_frequency - ac_output_apparent_power: - id: inverter0_ac_output_apparent_power - name: inverter0_ac_output_apparent_power - ac_output_active_power: - id: inverter0_ac_output_active_power - name: inverter0_ac_output_active_power - output_load_percent: - id: inverter0_output_load_percent - name: inverter0_output_load_percent - bus_voltage: - id: inverter0_bus_voltage - name: inverter0_bus_voltage - battery_voltage: - id: inverter0_battery_voltage - name: inverter0_battery_voltage - battery_charging_current: - id: inverter0_battery_charging_current - name: inverter0_battery_charging_current - battery_capacity_percent: - id: inverter0_battery_capacity_percent - name: inverter0_battery_capacity_percent - inverter_heat_sink_temperature: - id: inverter0_inverter_heat_sink_temperature - name: inverter0_inverter_heat_sink_temperature - pv_input_current_for_battery: - id: inverter0_pv_input_current_for_battery - name: inverter0_pv_input_current_for_battery - pv_input_voltage: - id: inverter0_pv_input_voltage - name: inverter0_pv_input_voltage - battery_voltage_scc: - id: inverter0_battery_voltage_scc - name: inverter0_battery_voltage_scc - battery_discharge_current: - id: inverter0_battery_discharge_current - name: inverter0_battery_discharge_current - battery_voltage_offset_for_fans_on: - id: inverter0_battery_voltage_offset_for_fans_on - name: inverter0_battery_voltage_offset_for_fans_on - eeprom_version: - id: inverter0_eeprom_version - name: inverter0_eeprom_version - pv_charging_power: - id: inverter0_pv_charging_power - name: inverter0_pv_charging_power - - platform: hrxl_maxsonar_wr - name: Rainwater Tank Level - uart_id: uart115200 - filters: - - sliding_window_moving_average: - window_size: 12 - send_every: 12 - - or: - - throttle: 20min - - delta: 0.02 - - platform: mcp3204 - name: MCP3204 Pin 1 - number: 1 - id: mcp_sensor - - platform: copy - source_id: mcp_sensor - name: MCP binary sensor copy - - platform: ufire_ec - id: ufire_ec_board - temperature: - name: Ufire Temperature - ec: - name: Ufire EC - temperature_compensation: 20.0 - temperature_coefficient: 0.019 - - platform: ufire_ise - id: ufire_ise_board - temperature: - name: Ufire Temperature - ph: - name: Ufire pH - - platform: a01nyub - id: a01nyub_sensor - name: "a01nyub Distance" - uart_id: uart9600 - state_topic: "esphome/sensor/a01nyub_sensor/state" - - platform: a02yyuw - id: a02yyuw_sensor - name: "a02yyuw Distance" - uart_id: uart_a02yyuw - state_topic: "esphome/sensor/a02yyuw_sensor/state" - -# -# platform sensor.apds9960 requires component apds9960 -# -# - platform: apds9960 -# type: proximity -# name: APDS9960 Proximity -# - platform: apds9960 -# type: clear -# name: APDS9960 Clear -# - platform: apds9960 -# type: red -# name: APDS9960 Red -# - platform: apds9960 -# type: green -# name: APDS9960 Green -# - platform: apds9960 -# type: blue -# name: APDS9960 Blue - -binary_sensor: - - platform: tuya - id: tuya_binary_sensor - sensor_datapoint: 1 - - platform: pipsolar - pipsolar_id: inverter0 - add_sbu_priority_version: - id: inverter0_add_sbu_priority_version - name: inverter0_add_sbu_priority_version - configuration_status: - id: inverter0_configuration_status - name: inverter0_configuration_status - scc_firmware_version: - id: inverter0_scc_firmware_version - name: inverter0_scc_firmware_version - load_status: - id: inverter0_load_status - name: inverter0_load_status - battery_voltage_to_steady_while_charging: - id: inverter0_battery_voltage_to_steady_while_charging - name: inverter0_battery_voltage_to_steady_while_charging - charging_status: - id: inverter0_charging_status - name: inverter0_charging_status - scc_charging_status: - id: inverter0_scc_charging_status - name: inverter0_scc_charging_status - ac_charging_status: - id: inverter0_ac_charging_status - name: inverter0_ac_charging_status - charging_to_floating_mode: - id: inverter0_charging_to_floating_mode - name: inverter0_charging_to_floating_mode - switch_on: - id: inverter0_switch_on - name: inverter0_switch_on - dustproof_installed: - id: inverter0_dustproof_installed - name: inverter0_dustproof_installed - silence_buzzer_open_buzzer: - id: inverter0_silence_buzzer_open_buzzer - name: inverter0_silence_buzzer_open_buzzer - overload_bypass_function: - id: inverter0_overload_bypass_function - name: inverter0_overload_bypass_function - lcd_escape_to_default: - id: inverter0_lcd_escape_to_default - name: inverter0_lcd_escape_to_default - overload_restart_function: - id: inverter0_overload_restart_function - name: inverter0_overload_restart_function - over_temperature_restart_function: - id: inverter0_over_temperature_restart_function - name: inverter0_over_temperature_restart_function - backlight_on: - id: inverter0_backlight_on - name: inverter0_backlight_on - - platform: template - id: ar1 - lambda: "return {};" - filters: - - autorepeat: - - delay: 2s - time_off: 100ms - time_on: 900ms - - delay: 4s - time_off: 100ms - time_on: 400ms - on_state: - then: - - lambda: 'ESP_LOGI("ar1:", "%d", x);' - - platform: touchscreen - touchscreen_id: xpt_touchscreen - id: touch_key0 - x_min: 80 - x_max: 160 - y_min: 106 - y_max: 212 - on_press: - - logger.log: Touched - - - platform: gpio - name: GPIO SX1509 test - pin: - sx1509: sx1509_hub - number: 3 - - - platform: touchscreen - touchscreen_id: lilygo_touchscreen - id: touch_key1 - x_min: 0 - x_max: 100 - y_min: 0 - y_max: 100 - on_press: - - logger.log: Touched - - platform: gt911 - id: touch_key_911 - index: 0 - - - platform: gpio - name: MaxIn Pin 4 - pin: - max6956: max6956_1 - number: 4 - - mode: - input: true - pullup: true - inverted: false - - - platform: gpio - name: XL9535 Pin 0 - pin: - xl9535: xl9535_hub - number: 0 - mode: - input: true - inverted: false - - - platform: gpio - name: XL9535 Pin 17 - pin: - xl9535: xl9535_hub - number: 17 - mode: - input: true - inverted: false - -climate: - - platform: tuya - id: tuya_climate - switch_datapoint: 1 - target_temperature_datapoint: 3 - current_temperature_multiplier: 0.5 - target_temperature_multiplier: 0.5 - reports_fahrenheit: true - -switch: - - platform: tuya - id: tuya_switch - switch_datapoint: 1 - - platform: pipsolar - pipsolar_id: inverter0 - output_source_priority_utility: - name: inverter0_output_source_priority_utility - output_source_priority_solar: - name: inverter0_output_source_priority_solar - output_source_priority_battery: - name: inverter0_output_source_priority_battery - input_voltage_range: - name: inverter0_input_voltage_range - pv_ok_condition_for_parallel: - name: inverter0_pv_ok_condition_for_parallel - pv_power_balance: - name: inverter0_pv_power_balance - - platform: copy - source_id: tuya_switch - name: Tuya Switch Copy - -light: - - platform: fastled_clockless - id: led_matrix_32x8 - name: led_matrix_32x8 - chipset: WS2812B - pin: - allow_other_uses: true - number: GPIO15 - num_leds: 256 - rgb_order: GRB - default_transition_length: 0s - color_correct: [50%, 50%, 50%] - - platform: tuya - id: tuya_light - switch_datapoint: 1 - dimmer_datapoint: 2 - min_value_datapoint: 3 - color_temperature_datapoint: 4 - min_value: 1 - max_value: 100 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - gamma_correct: 1 - -cover: - - platform: tuya - id: tuya_cover - position_datapoint: 2 - - platform: copy - source_id: tuya_cover - name: Tuya Cover copy - - platform: he60r - uart_id: uart_he60r - id: garage_door - name: Garage Door - open_duration: 14s - close_duration: 14s - -display: - - platform: addressable_light - id: led_matrix_32x8_display - addressable_light_id: led_matrix_32x8 - width: 32 - height: 8 - pixel_mapper: |- - if (x % 2 == 0) { - return (x * 8) + y; - } - return (x * 8) + (7 - y); - lambda: |- - Color red = Color(0xFF0000); - Color green = Color(0x00FF00); - Color blue = Color(0x0000FF); - it.rectangle(0, 0, it.get_width(), it.get_height(), red); - it.rectangle(1, 1, it.get_width()-2, it.get_height()-2, green); - it.rectangle(2, 2, it.get_width()-4, it.get_height()-4, blue); - it.rectangle(3, 3, it.get_width()-6, it.get_height()-6, red); - auto touch = id(ft63_touchscreen)->get_touch(); - if (touch) { ESP_LOGD("touch", "%d/%d", touch.value().x, touch.value().y); } - rotation: 0° - update_interval: 16ms - - - platform: inkplate6 - id: inkplate_display - greyscale: false - partial_updating: false - update_interval: 60s - display_data_1_pin: - number: GPIO5 - allow_other_uses: true - display_data_2_pin: - number: GPIO18 - allow_other_uses: true - display_data_3_pin: - number: GPIO19 - allow_other_uses: true - display_data_5_pin: - number: GPIO25 - allow_other_uses: true - display_data_4_pin: - number: GPIO23 - allow_other_uses: true - display_data_6_pin: - number: GPIO26 - allow_other_uses: true - display_data_7_pin: - number: GPIO27 - allow_other_uses: true - ckv_pin: - number: GPIO1 - allow_other_uses: true - sph_pin: - number: GPIO1 - allow_other_uses: true - gmod_pin: - number: GPIO1 - allow_other_uses: true - gpio0_enable_pin: - number: GPIO1 - allow_other_uses: true - oe_pin: - number: GPIO1 - allow_other_uses: true - spv_pin: - number: GPIO1 - allow_other_uses: true - powerup_pin: - number: GPIO1 - allow_other_uses: true - wakeup_pin: - number: GPIO1 - allow_other_uses: true - vcom_pin: - number: GPIO1 - allow_other_uses: true - -number: - - platform: tuya - id: tuya_number - number_datapoint: 102 - min_value: 0 - max_value: 17 - step: 1 - - platform: copy - source_id: tuya_number - name: Tuya Number Copy - -text_sensor: - - platform: pylontech - pylontech_id: pylontech0 - battery: 1 - base_state: - id: pyl0_base_state - voltage_state: - id: pyl0_voltage_state - current_state: - id: pyl0_current_state - temperature_state: - id: pyl0_temperature_state - - platform: pipsolar - pipsolar_id: inverter0 - device_mode: - id: inverter0_device_mode - name: inverter0_device_mode - last_qpigs: - id: inverter0_last_qpigs - name: inverter0_last_qpigs - last_qpiri: - id: inverter0_last_qpiri - name: inverter0_last_qpiri - last_qmod: - id: inverter0_last_qmod - name: inverter0_last_qmod - last_qflag: - id: inverter0_last_qflag - name: inverter0_last_qflag - - platform: copy - source_id: inverter0_device_mode - name: Inverter Text Sensor Copy - - platform: ethernet_info - ip_address: - name: IP Address - -output: - - platform: pipsolar - pipsolar_id: inverter0 - battery_recharge_voltage: - id: inverter0_battery_recharge_voltage_out - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 0 - id: dac7678_1_ch0 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 1 - id: dac7678_1_ch1 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 2 - id: dac7678_1_ch2 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 3 - id: dac7678_1_ch3 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 4 - id: dac7678_1_ch4 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 5 - id: dac7678_1_ch5 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 6 - id: dac7678_1_ch6 - - platform: dac7678 - dac7678_id: dac7678_hub1 - channel: 7 - id: dac7678_1_ch7 -esp32_camera: - name: ESP-32 Camera - data_pins: - - number: GPIO17 - allow_other_uses: true - - number: GPIO35 - allow_other_uses: true - - number: GPIO34 - - number: GPIO5 - allow_other_uses: true - - number: GPIO39 - allow_other_uses: true - - number: GPIO18 - allow_other_uses: true - - number: GPIO36 - allow_other_uses: true - - number: GPIO19 - allow_other_uses: true - vsync_pin: - allow_other_uses: true - number: GPIO22 - href_pin: - allow_other_uses: true - number: GPIO26 - pixel_clock_pin: - allow_other_uses: true - number: GPIO21 - external_clock: - pin: - allow_other_uses: true - number: GPIO27 - frequency: 20MHz - i2c_pins: - sda: - allow_other_uses: true - number: GPIO25 - scl: - allow_other_uses: true - number: GPIO23 - reset_pin: - allow_other_uses: true - number: GPIO15 - power_down_pin: - allow_other_uses: true - number: GPIO1 - resolution: 640x480 - jpeg_quality: 10 - on_image: - then: - - lambda: |- - ESP_LOGD("main", "image len=%d, data=%c", image.length, image.data[0]); - -esp32_camera_web_server: - - port: 8080 - mode: stream - - port: 8081 - mode: snapshot - -external_components: - - source: github://esphome/esphome@dev - refresh: 1d - components: [bh1750] - - source: ../esphome/components - components: [sntp] - -button: - - platform: restart - name: Restart Button - - platform: safe_mode - name: Safe Mode Button - - platform: shutdown - name: Shutdown Button - id: shutdown_btn - - platform: copy - source_id: shutdown_btn - name: Shutdown Button Copy - -touchscreen: - - platform: ektf2232 - interrupt_pin: - allow_other_uses: true - number: GPIO36 - rts_pin: - allow_other_uses: true - number: GPIO5 - display: inkplate_display - on_touch: - - logger.log: - format: Touch at (%d, %d) - args: [touch.x, touch.y] - - - platform: xpt2046 - id: xpt_touchscreen - spi_id: spi_id_2 - cs_pin: - allow_other_uses: true - number: GPIO17 - interrupt_pin: - number: GPIO16 - display: inkplate_display - update_interval: 50ms - threshold: 400 - calibration: - x_min: 3860 - x_max: 280 - y_min: 340 - y_max: 3860 - on_touch: - - logger.log: - format: Touch at (%d, %d) - args: [touch.x, touch.y] - - - platform: lilygo_t5_47 - id: lilygo_touchscreen - interrupt_pin: - allow_other_uses: true - number: GPIO36 - display: inkplate_display - on_touch: - - logger.log: - format: Touch at (%d, %d) - args: [touch.x, touch.y] - - platform: gt911 - interrupt_pin: - number: GPIO3 - display: inkplate_display - - - platform: ft63x6 - id: ft63_touchscreen - interrupt_pin: - allow_other_uses: true - number: GPIO39 - reset_pin: - allow_other_uses: true - number: GPIO5 - display: inkplate_display - on_touch: - - logger.log: - format: Touch at (%d, %d) - args: [touch.x, touch.y] - -i2s_audio: - i2s_lrclk_pin: - allow_other_uses: true - number: GPIO26 - i2s_bclk_pin: - allow_other_uses: true - number: GPIO27 - i2s_mclk_pin: - allow_other_uses: true - number: GPIO25 - -media_player: - - platform: i2s_audio - name: None - dac_type: external - i2s_dout_pin: - allow_other_uses: true - number: GPIO25 - mute_pin: - number: GPIO14 - on_state: - - media_player.play: - - media_player.play_media: http://localhost/media.mp3 - - media_player.play_media: !lambda 'return "http://localhost/media.mp3";' - on_idle: - - media_player.pause: - on_play: - - media_player.stop: - on_pause: - - media_player.toggle: - - wait_until: - media_player.is_idle: - - wait_until: - media_player.is_playing: - - media_player.volume_up: - - media_player.volume_down: - - media_player.volume_set: 50% - -prometheus: - include_internal: true - relabel: - ha_hello_world: - id: hellow_world - name: Hello World - -microphone: - - platform: i2s_audio - id: mic_id_adc - adc_pin: - allow_other_uses: true - number: GPIO35 - adc_type: internal - - - platform: i2s_audio - id: mic_id_external - i2s_din_pin: - allow_other_uses: true - number: GPIO23 - adc_type: external - pdm: false - -speaker: - - platform: i2s_audio - id: speaker_id - dac_type: external - i2s_dout_pin: - allow_other_uses: true - number: GPIO25 - mode: mono - -voice_assistant: - microphone: mic_id_external - speaker: speaker_id - on_listening: - - logger.log: "Voice assistant microphone listening" - on_start: - - logger.log: "Voice assistant started" - on_stt_end: - - logger.log: - format: "Voice assistant STT ended with result %s" - args: [x.c_str()] - on_tts_start: - - logger.log: - format: "Voice assistant TTS started with text %s" - args: [x.c_str()] - on_tts_end: - - logger.log: - format: "Voice assistant TTS ended with url %s" - args: [x.c_str()] - on_end: - - logger.log: "Voice assistant ended" - on_error: - - logger.log: - format: "Voice assistant error - code %s, message: %s" - args: [code.c_str(), message.c_str()] - -max6956: - - id: max6956_1 - address: 0x40 - -xl9535: - - id: xl9535_hub - address: 0x20 diff --git a/tests/test5.yaml b/tests/test5.yaml deleted file mode 100644 index f7a34d5a1b..0000000000 --- a/tests/test5.yaml +++ /dev/null @@ -1,747 +0,0 @@ ---- -esphome: - name: test5 - build_path: build/test5 - project: - name: esphome.test5_project - version: "1.0.0" - -esp32: - board: nodemcu-32s - framework: - type: esp-idf - advanced: - ignore_efuse_mac_crc: true - -wifi: - networks: - - ssid: "MySSID" - password: "password1" - manual_ip: - static_ip: 192.168.1.23 - gateway: 192.168.1.1 - subnet: 255.255.255.0 - -network: - enable_ipv6: true - -api: - -ota: - - platform: esphome - -logger: - -debug: - -psram: - -uart: - - id: uart_1 - tx_pin: 1 - rx_pin: 3 - baud_rate: 9600 - - id: uart_2 - tx_pin: - allow_other_uses: true - number: 17 - inverted: true - rx_pin: - allow_other_uses: true - number: 16 - baud_rate: 19200 - -i2c: - sda: - allow_other_uses: true - number: 21 - scl: - number: 22 - frequency: 100khz - -modbus: - uart_id: uart_1 - flow_control_pin: - allow_other_uses: true - number: 5 - id: mod_bus1 - -modbus_controller: - - id: modbus_controller_test - address: 0x2 - modbus_id: mod_bus1 - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant - idf_send_async: false - log_topic: - on_message: - topic: testing/sensor/testing_sensor/state - qos: 0 - then: - # yamllint disable rule:line-length - - lambda: |- - ESP_LOGD("Mqtt Test", "testing/sensor/testing_sensor/state=[%s]", x.c_str()); - # yamllint enable rule:line-length - -vbus: - - uart_id: uart_2 - -binary_sensor: - - platform: gpio - pin: GPIO0 - id: io0_button - icon: mdi:gesture-tap-button - - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_binsensortest - register_type: read - address: 0x3200 - bitmask: 0x80 # (bit 8) - lambda: "return x;" - - - platform: tm1638 - id: Button0 - key: 0 - filters: - - delayed_on: 10ms - on_press: - then: - - switch.turn_on: Led0 - on_release: - then: - - switch.turn_off: Led0 - - - platform: tm1638 - id: Button1 - key: 1 - on_press: - then: - - switch.turn_on: Led1 - on_release: - then: - - switch.turn_off: Led1 - - - platform: tm1638 - id: Button2 - key: 2 - on_press: - then: - - switch.turn_on: Led2 - on_release: - then: - - switch.turn_off: Led2 - - - platform: tm1638 - id: Button3 - key: 3 - on_press: - then: - - switch.turn_on: Led3 - on_release: - then: - - switch.turn_off: Led3 - - - platform: tm1638 - id: Button4 - key: 4 - on_press: - then: - - output.turn_on: Led4 - on_release: - then: - - output.turn_off: Led4 - - - platform: tm1638 - id: Button5 - key: 5 - on_press: - then: - - output.turn_on: Led5 - on_release: - then: - - output.turn_off: Led5 - - - platform: tm1638 - id: Button6 - key: 6 - on_press: - then: - - output.turn_on: Led6 - on_release: - then: - - output.turn_off: Led6 - - - platform: tm1638 - id: Button7 - key: 7 - on_press: - then: - - output.turn_on: Led7 - on_release: - then: - - output.turn_off: Led7 - - - platform: gpio - id: sn74hc165_pin_0 - pin: - sn74hc165: sn74hc165_hub - number: 0 - - - platform: ezo_pmp - pump_state: - name: "Pump State" - is_paused: - name: "Is Paused" - - - platform: matrix_keypad - keypad_id: keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 - - - platform: vbus - model: deltasol_bs_plus - relay2: - name: Relay 2 On - sensor1_error: - name: Sensor 1 Error - - - platform: vbus - model: custom - command: 0x100 - source: 0x1234 - dest: 0x10 - binary_sensors: - - id: vcustom_b - name: VBus Custom Binary Sensor - lambda: return x[0] & 1; - -tlc5947: - data_pin: - number: GPIO12 - allow_other_uses: true - clock_pin: - allow_other_uses: true - number: GPIO14 - lat_pin: - allow_other_uses: true - number: GPIO15 - -gp8403: - - id: gp8403_5v - voltage: 5V - - id: gp8403_10v - voltage: 10V - -output: - - platform: gpio - pin: GPIO2 - id: built_in_led - - - platform: tlc5947 - id: output_red - channel: 0 - max_power: 0.8 - - - platform: mcp47a1 - id: output_mcp47a1 - - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_output_test - lambda: |- - return x * 1.0 ; - address: 0x9001 - value_type: U_WORD - - - platform: tm1638 - id: Led4 - led: 4 - - - platform: tm1638 - id: Led5 - led: 5 - - - platform: tm1638 - id: Led6 - led: 6 - - - platform: tm1638 - id: Led7 - led: 7 - - - platform: gp8403 - id: gp8403_output_0 - gp8403_id: gp8403_5v - channel: 0 - - platform: gp8403 - gp8403_id: gp8403_10v - id: gp8403_output_1 - channel: 1 - -demo: - -esp32_ble: - -esp32_ble_server: - manufacturer: ESPHome - model: Test5 - -esp32_improv: - authorizer: io0_button - authorized_duration: 1min - status_indicator: built_in_led - -ezo_pmp: - id: hcl_pump - update_interval: 1s - -number: - - platform: template - name: My template number - id: template_number_id - optimistic: true - max_value: 100 - min_value: 0 - step: 5 - unit_of_measurement: "%" - mode: slider - device_class: humidity - on_value: - - logger.log: - format: Number changed to %f - args: [x] - set_action: - - logger.log: - format: Template Number set to %f - args: [x] - - number.set: - id: template_number_id - value: 50 - - number.to_min: template_number_id - - number.to_min: - id: template_number_id - - number.to_max: template_number_id - - number.to_max: - id: template_number_id - - number.increment: template_number_id - - number.increment: - id: template_number_id - cycle: false - - number.decrement: template_number_id - - number.decrement: - id: template_number_id - cycle: false - - number.operation: - id: template_number_id - operation: Increment - cycle: false - - number.operation: - id: template_number_id - operation: !lambda "return NUMBER_OP_INCREMENT;" - cycle: !lambda "return false;" - - - id: modbus_numbertest - platform: modbus_controller - modbus_controller_id: modbus_controller_test - name: ModbusNumber - address: 0x9002 - value_type: U_WORD - lambda: "return x * 1.0;" - write_lambda: |- - return x * 1.0 ; - multiply: 1.0 - -select: - - platform: template - name: My template select - id: template_select_id - optimistic: true - initial_option: two - restore_value: true - on_value: - - logger.log: - format: Select changed to %s (index %d)" - args: ["x.c_str()", "i"] - set_action: - - logger.log: - format: Template Select set to %s - args: ["x.c_str()"] - - select.set: - id: template_select_id - option: two - - select.first: template_select_id - - select.last: - id: template_select_id - - select.previous: template_select_id - - select.next: - id: template_select_id - cycle: false - - select.operation: - id: template_select_id - operation: Previous - cycle: false - - select.operation: - id: template_select_id - operation: !lambda "return SELECT_OP_PREVIOUS;" - cycle: !lambda "return true;" - - select.set_index: - id: template_select_id - index: 1 - - select.set_index: - id: template_select_id - index: !lambda "return 1 + 1;" - options: - - one - - two - - three - - - platform: modbus_controller - name: Modbus Select Register 1000 - address: 1000 - value_type: U_WORD - optionsmap: - "Zero": 0 - "One": 1 - "Two": 2 - "Three": 3 - -sensor: - - platform: adc - id: adc_sensor_p32 - name: ADC pin 32 - pin: 32 - attenuation: 11db - update_interval: 1s - - platform: internal_temperature - name: Internal Temperature - state_topic: - - platform: selec_meter - total_active_energy: - name: SelecEM2M Total Active Energy - import_active_energy: - name: SelecEM2M Import Active Energy - export_active_energy: - name: SelecEM2M Export Active Energy - total_reactive_energy: - name: SelecEM2M Total Reactive Energy - import_reactive_energy: - name: SelecEM2M Import Reactive Energy - export_reactive_energy: - name: SelecEM2M Export Reactive Energy - apparent_energy: - name: SelecEM2M Apparent Energy - active_power: - name: SelecEM2M Active Power - reactive_power: - name: SelecEM2M Reactive Power - apparent_power: - name: SelecEM2M Apparent Power - voltage: - name: SelecEM2M Voltage - current: - name: SelecEM2M Current - power_factor: - name: SelecEM2M Power Factor - frequency: - name: SelecEM2M Frequency - maximum_demand_active_power: - name: SelecEM2M Maximum Demand Active Power - disabled_by_default: true - maximum_demand_reactive_power: - name: SelecEM2M Maximum Demand Reactive Power - disabled_by_default: true - maximum_demand_apparent_power: - name: SelecEM2M Maximum Demand Apparent Power - disabled_by_default: true - - - id: modbus_sensortest - platform: modbus_controller - modbus_controller_id: modbus_controller_test - address: 0x331A - register_type: read - value_type: U_WORD - - - platform: t6615 - uart_id: uart_2 - co2: - name: CO2 Sensor - - - platform: ms8607 - temperature: - name: Temperature - humidity: - name: Humidity - pressure: - name: Pressure - - platform: ms8607 - id: ms8607_more_config - temperature: - name: Indoor Temperature - accuracy_decimals: 1 - pressure: - name: Indoor Pressure - internal: true - humidity: - name: Indoor Humidity - address: 0x41 - i2c_id: - i2c_id: - address: 0x77 - update_interval: 10min - - - platform: sen5x - id: sen54 - temperature: - name: Temperature - accuracy_decimals: 1 - humidity: - name: Humidity - accuracy_decimals: 0 - pm_1_0: - name: PM <1µm Weight concentration - id: pm_1_0 - accuracy_decimals: 1 - pm_2_5: - name: PM <2.5µm Weight concentration - id: pm_2_5 - accuracy_decimals: 1 - pm_4_0: - name: PM <4µm Weight concentration - id: pm_4_0 - accuracy_decimals: 1 - pm_10_0: - name: PM <10µm Weight concentration - id: pm_10_0 - accuracy_decimals: 1 - nox: - name: NOx - voc: - name: VOC - algorithm_tuning: - index_offset: 100 - learning_time_offset_hours: 12 - learning_time_gain_hours: 12 - gating_max_duration_minutes: 180 - std_initial: 50 - gain_factor: 230 - temperature_compensation: - offset: 0 - normalized_offset_slope: 0 - time_constant: 0 - auto_cleaning_interval: 604800s - acceleration_mode: low - store_baseline: true - address: 0x69 - - platform: mcp9600 - thermocouple_type: K - hot_junction: - name: Thermocouple Temperature - cold_junction: - name: Ambient Temperature - - - platform: ezo_pmp - current_volume_dosed: - name: Current Volume Dosed - total_volume_dosed: - name: Total Volume Dosed - absolute_total_volume_dosed: - name: Absolute Total Volume Dosed - pump_voltage: - name: Pump Voltage - last_volume_requested: - name: Last Volume Requested - max_flow_rate: - name: Max Flow Rate - - - platform: vbus - model: deltasol c - temperature_3: - name: Temperature 3 - operating_hours_1: - name: Operating Hours 1 - heat_quantity: - name: Heat Quantity - time: - name: System Time - - - platform: debug - free: - name: "Heap Free" - block: - name: "Heap Max Block" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" - - - platform: vbus - model: custom - command: 0x100 - source: 0x1234 - dest: 0x10 - sensors: - - id: vcustom - name: VBus Custom Sensor - lambda: return x[0] / 10.0; - - - platform: kuntze - ph: - name: Kuntze pH - temperature: - name: Kuntze temperature - -script: - - id: automation_test - then: - - repeat: - count: 5 - then: - - logger.log: looping! - - - id: zero_repeat_test - then: - - repeat: - count: !lambda "return 0;" - then: - - logger.log: shouldn't see mee! - -switch: - - platform: modbus_controller - modbus_controller_id: modbus_controller_test - id: modbus_switch_test - register_type: coil - address: 2 - bitmask: 1 - - - platform: tm1638 - id: Led0 - led: 0 - name: TM1638Led0 - - - platform: tm1638 - id: Led1 - led: 1 - name: TM1638Led1 - - - platform: tm1638 - id: Led2 - led: 2 - name: TM1638Led2 - - - platform: tm1638 - id: Led3 - led: 3 - name: TM1638Led3 - -display: - - platform: tm1638 - id: primarydisplay - stb_pin: - allow_other_uses: true - number: 5 # TM1638 STB - clk_pin: 18 # TM1638 CLK - dio_pin: 23 # TM1638 DIO - update_interval: 5s - intensity: 5 - lambda: |- - it.print("81818181"); - -time: - - platform: pcf85063 - - platform: pcf8563 - -text_sensor: - - platform: ezo_pmp - dosing_mode: - name: Dosing Mode - calibration_status: - name: Calibration Status - on_value: - - ezo_pmp.dose_volume: - id: hcl_pump - volume: 10 - - ezo_pmp.dose_volume_over_time: - id: hcl_pump - volume: 10 - duration: 2 - - ezo_pmp.dose_with_constant_flow_rate: - id: hcl_pump - volume_per_minute: 10 - duration: 2 - - ezo_pmp.set_calibration_volume: - id: hcl_pump - volume: 10 - - ezo_pmp.find: hcl_pump - - ezo_pmp.dose_continuously: hcl_pump - - ezo_pmp.clear_total_volume_dosed: hcl_pump - - ezo_pmp.clear_calibration: hcl_pump - - ezo_pmp.pause_dosing: hcl_pump - - ezo_pmp.stop_dosing: hcl_pump - - ezo_pmp.arbitrary_command: - id: hcl_pump - command: D,? - -sn74hc165: - id: sn74hc165_hub - data_pin: - allow_other_uses: true - number: GPIO12 - clock_pin: - allow_other_uses: true - number: GPIO14 - load_pin: GPIO27 - clock_inhibit_pin: GPIO26 - sr_count: 4 - -matrix_keypad: - id: keypad - rows: - - pin: - allow_other_uses: true - number: 21 - - pin: 19 - columns: - - pin: - allow_other_uses: true - number: 17 - - pin: - allow_other_uses: true - number: 16 - keys: "1234" - has_pulldowns: true - -key_collector: - - id: reader - source_id: keypad - min_length: 4 - max_length: 4 - -light: - - platform: esp32_rmt_led_strip - id: led_strip - pin: 13 - num_leds: 60 - rmt_channel: 6 - rgb_order: GRB - chipset: ws2812 - - platform: esp32_rmt_led_strip - id: led_strip2 - pin: - allow_other_uses: true - number: 15 - num_leds: 60 - rmt_channel: 2 - rgb_order: RGB - bit0_high: 100us - bit0_low: 100us - bit1_high: 100us - bit1_low: 100us diff --git a/tests/test6.yaml b/tests/test6.yaml deleted file mode 100644 index b1103eb126..0000000000 --- a/tests/test6.yaml +++ /dev/null @@ -1,77 +0,0 @@ ---- -esphome: - name: test6 - project: - name: esphome.test6_project - version: "1.0.0" - -rp2040: - board: rpipicow - framework: - # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git - -wifi: - networks: - - ssid: "MySSID" - password: "password1" - -network: - enable_ipv6: true - -api: - -ota: - - platform: esphome - -logger: - -debug: - -binary_sensor: - - platform: gpio - pin: GPIO5 - id: pin_5_button - -output: - - platform: gpio - pin: GPIO4 - id: pin_4 - -switch: - - platform: output - output: pin_4 - id: pin_4_switch - -spi: # Pins are for SPI1 on the RP2040 Pico-W - miso_pin: 8 - clk_pin: 10 - mosi_pin: 11 - id: spi_0 - interface: hardware - -# light: -# - platform: rp2040_pio_led_strip -# id: led_strip -# pin: GPIO13 -# num_leds: 60 -# pio: 0 -# rgb_order: GRB -# chipset: WS2812 -# - platform: rp2040_pio_led_strip -# id: led_strip_custom_timings -# pin: GPIO13 -# num_leds: 60 -# pio: 1 -# rgb_order: GRB -# bit0_high: .1us -# bit0_low: 1.2us -# bit1_high: .69us -# bit1_low: .4us - -sensor: - - platform: internal_temperature - name: Internal Temperature - - platform: adc - pin: VCC - name: VSYS diff --git a/tests/test7.yaml b/tests/test7.yaml deleted file mode 100644 index ac193eae4e..0000000000 --- a/tests/test7.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Tests for ESP32-C3 boards which use toolchain-riscv32-esp ---- -wifi: - ssid: "ssid" - -network: - enable_ipv6: true - -esp32: - board: lolin_c3_mini - framework: - type: arduino - -esphome: - name: test7 - -logger: - -debug: - -sensor: - - platform: adc - id: adc_sensor_p4 - name: ADC pin 4 - pin: 4 - attenuation: 11db - update_interval: 1s diff --git a/tests/test8.1.yaml b/tests/test8.1.yaml deleted file mode 100644 index ab3d0d44aa..0000000000 --- a/tests/test8.1.yaml +++ /dev/null @@ -1,78 +0,0 @@ -# Tests for ESP32-S3 boards - IDf ---- -wifi: - ssid: "ssid" - -network: - enable_ipv6: true - -esp32: - board: esp32s3box - variant: ESP32S3 - framework: - type: esp-idf - -esphome: - name: esp32-s3-test - -logger: - -debug: - -psram: - -spi: - - id: spi_id_1 - type: single - clk_pin: - number: GPIO7 - allow_other_uses: false - mosi_pin: GPIO6 - interface: hardware -spi_device: - id: spidev - data_rate: 2MHz - spi_id: spi_id_1 - mode: 3 - bit_order: lsb_first - -display: - - platform: ili9xxx - id: displ8 - model: ili9342 - cs_pin: GPIO5 - dc_pin: GPIO4 - reset_pin: - number: GPIO48 - allow_other_uses: true - -i2c: - scl: GPIO18 - sda: GPIO8 - -touchscreen: - - platform: tt21100 - display: displ8 - interrupt_pin: - number: GPIO3 - ignore_strapping_warning: true - allow_other_uses: false - reset_pin: - number: GPIO48 - allow_other_uses: true - -binary_sensor: - - platform: tt21100 - name: Home Button - index: 1 - -sensor: - - platform: debug - free: - name: "Heap Free" - block: - name: "Max Block Free" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" diff --git a/tests/test8.2.yaml b/tests/test8.2.yaml deleted file mode 100644 index ae892559e5..0000000000 --- a/tests/test8.2.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Tests for ESP32-C3 boards - IDf ---- -wifi: - ssid: "ssid" - -network: - enable_ipv6: true - -esp32: - board: lolin_c3_mini - variant: ESP32C3 - framework: - type: esp-idf - -esphome: - name: esp32-c3-test - -logger: - -debug: - -psram: - -spi: - - id: spi_id_1 - clk_pin: - number: GPIO7 - allow_other_uses: false - mosi_pin: GPIO6 - interface: any - -spi_device: - id: spidev - data_rate: 2MHz - spi_id: spi_id_1 - mode: 3 - bit_order: lsb_first - -display: - - platform: ili9xxx - id: displ8 - model: ili9342 - cs_pin: GPIO5 - dc_pin: GPIO4 - reset_pin: - number: GPIO21 - -i2c: - scl: GPIO18 - sda: GPIO8 - -touchscreen: - - platform: tt21100 - display: displ8 - interrupt_pin: - number: GPIO3 - allow_other_uses: false - reset_pin: - number: GPIO20 - -binary_sensor: - - platform: tt21100 - name: Home Button - index: 1 - -sensor: - - platform: debug - free: - name: "Heap Free" - block: - name: "Max Block Free" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" diff --git a/tests/test8.yaml b/tests/test8.yaml deleted file mode 100644 index fcc93c6154..0000000000 --- a/tests/test8.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# Tests for ESP32-S3 boards ---- -wifi: - ssid: "ssid" - -network: - enable_ipv6: true - -esp32: - board: esp32s3box - variant: ESP32S3 - framework: - type: arduino - -esphome: - name: esp32-s3-test - -logger: - -debug: - -psram: - -light: - - platform: neopixelbus - type: GRB - variant: WS2812 - pin: GPIO38 - num_leds: 1 - id: neopixel - method: esp32_rmt - name: neopixel-enable - internal: false - restore_mode: ALWAYS_OFF - - platform: spi_led_strip - num_leds: 4 - color_correct: [80%, 60%, 100%] - id: rgb_led - name: "RGB LED" - data_rate: 8MHz - - platform: binary - name: "Red Info Light" - output: board_info_ed - entity_category: diagnostic - restore_mode: ALWAYS_OFF - -spi: - id: spi_id_1 - clk_pin: GPIO7 - mosi_pin: GPIO6 - interface: any - -spi_device: - id: spidev - data_rate: 2MHz - spi_id: spi_id_1 - mode: 3 - bit_order: lsb_first - -font: - - file: "gfonts://Roboto" - id: roboto - size: 20 - -display: - - platform: ili9xxx - id: displ8 - model: ili9342 - cs_pin: GPIO5 - dc_pin: GPIO4 - reset_pin: - number: GPIO48 - allow_other_uses: true - lambda: |- - it.printf(10, 100, id(roboto), Color(0x123456), COLOR_OFF, display::TextAlign::BASELINE, "%f", id(heap_free).state); - -i2c: - scl: GPIO18 - sda: GPIO8 - -output: - - platform: gpio - id: board_info_ed - pin: - # This pin is reserved on the ESP32S3! - number: 26 - ignore_pin_validation_error: true - -touchscreen: - - platform: tt21100 - display: displ8 - interrupt_pin: - number: GPIO3 - ignore_strapping_warning: true - allow_other_uses: false - reset_pin: - number: GPIO48 - allow_other_uses: true - -binary_sensor: - - platform: tt21100 - name: Home Button - index: 1 - -sensor: - - platform: debug - free: - id: heap_free - name: "Heap Free" - block: - name: "Max Block Free" - loop_time: - name: "Loop Time" - psram: - name: "PSRAM Free" - -# Purposely test that `animation:` does auto-load `image:` -# Keep the `image:` undefined. -# image: - -animation: - - id: rgb565_animation - file: pnglogo.png - type: RGB565 - use_transparency: false diff --git a/tests/test9.1.yaml b/tests/test9.1.yaml deleted file mode 100644 index 2d205ef4e6..0000000000 --- a/tests/test9.1.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Tests for rtl87xx boards using LibreTiny ---- -wifi: - ssid: "ssid" - -rtl87xx: - board: generic-rtl8710bn-2mb-788k - -esphome: - name: rtl87xx-test - -logger: - -ota: - - platform: esphome - -captive_portal: - -binary_sensor: - - platform: gpio - name: Home Button - pin: GPIO11 - -sensor: - - platform: adc - id: adc_sensor - name: ADC - pin: PA19 - update_interval: 1s diff --git a/tests/test9.yaml b/tests/test9.yaml deleted file mode 100644 index 5017ccc5ed..0000000000 --- a/tests/test9.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Tests for bk7xx boards using LibreTiny ---- -wifi: - ssid: "ssid" - -bk72xx: - board: cb2s - -esphome: - name: bk72xx-test - -logger: - -ota: - - platform: esphome - -captive_portal: - -binary_sensor: - - platform: gpio - name: Home Button - pin: GPIO24 - -sensor: - - platform: adc - id: adc_sensor - name: ADC - pin: GPIO23 - update_interval: 1s - -mqtt: - broker: test.mosquitto.org - port: 1883 - discovery: true - discovery_prefix: homeassistant From dc4a93f5d0ec268bc1a0de28ac2f9d4c7b96aa6d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:15:02 +1200 Subject: [PATCH 1995/2607] Revert "[CI] Update tests to run against IDF 5.1" (#7003) --- ...f-51.yaml => build_components_base.esp32-c3-idf-50.yaml} | 6 +++--- ...-idf-51.yaml => build_components_base.esp32-idf-50.yaml} | 6 +++--- ...f-51.yaml => build_components_base.esp32-s2-idf-50.yaml} | 6 +++--- ...f-51.yaml => build_components_base.esp32-s3-idf-50.yaml} | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) rename tests/test_build_components/{build_components_base.esp32-c3-idf-51.yaml => build_components_base.esp32-c3-idf-50.yaml} (76%) rename tests/test_build_components/{build_components_base.esp32-idf-51.yaml => build_components_base.esp32-idf-50.yaml} (77%) rename tests/test_build_components/{build_components_base.esp32-s2-idf-51.yaml => build_components_base.esp32-s2-idf-50.yaml} (78%) rename tests/test_build_components/{build_components_base.esp32-s3-idf-51.yaml => build_components_base.esp32-s3-idf-50.yaml} (77%) diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml similarity index 76% rename from tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml rename to tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml index 73d2c8fa19..08d4d8679c 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32c3idf51 + name: componenttestesp32c3idf50 friendly_name: $component_name esp32: board: lolin_c3_mini framework: type: esp-idf - version: 5.1.2 - platform_version: 6.6.0 + version: 5.0.2 + platform_version: 6.3.2 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-idf-50.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-idf-51.yaml rename to tests/test_build_components/build_components_base.esp32-idf-50.yaml index 6c8eb3c193..c9f2c1e943 100644 --- a/tests/test_build_components/build_components_base.esp32-idf-51.yaml +++ b/tests/test_build_components/build_components_base.esp32-idf-50.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32idf51 + name: componenttestesp32idf50 friendly_name: $component_name esp32: board: nodemcu-32s framework: type: esp-idf - version: 5.1.2 - platform_version: 6.6.0 + version: 5.0.2 + platform_version: 6.3.2 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml similarity index 78% rename from tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml rename to tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml index 8894efb6b8..351f5fb019 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s2idf51 + name: componenttestesp32s2idf50 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S2 framework: type: esp-idf - version: 5.1.2 - platform_version: 6.6.0 + version: 5.0.2 + platform_version: 6.3.2 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml rename to tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml index efeffa5a0f..c05378903f 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s3idf51 + name: componenttestesp32s3idf50 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S3 framework: type: esp-idf - version: 5.1.2 - platform_version: 6.6.0 + version: 5.0.2 + platform_version: 6.3.2 logger: level: VERY_VERBOSE From 0e50cac39930770cb9321a06a03403ff938206fd Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 26 Jun 2024 20:07:07 -0500 Subject: [PATCH 1996/2607] [ota-esphome] Merge configurations by port (#7001) --- esphome/components/esphome/ota/__init__.py | 65 +++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index 88e729f230..a852d8d001 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,7 +1,10 @@ +import logging + import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent +from esphome.config_helpers import merge_config from esphome.const import ( CONF_ESPHOME, CONF_ID, @@ -16,6 +19,8 @@ from esphome.const import ( ) from esphome.core import coroutine_with_priority +_LOGGER = logging.getLogger(__name__) + CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["md5", "socket"] @@ -26,16 +31,62 @@ ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) def ota_esphome_final_validate(config): - fconf = fv.full_config.get()[CONF_OTA] - used_ports = [] - for ota_conf in fconf: + full_conf = fv.full_config.get() + full_ota_conf = full_conf[CONF_OTA] + new_ota_conf = [] + merged_ota_esphome_configs_by_port = {} + ports_with_merged_configs = [] + for ota_conf in full_ota_conf: if ota_conf.get(CONF_PLATFORM) == CONF_ESPHOME: - if (plat_port := ota_conf.get(CONF_PORT)) not in used_ports: - used_ports.append(plat_port) + if ( + conf_port := ota_conf.get(CONF_PORT) + ) not in merged_ota_esphome_configs_by_port: + merged_ota_esphome_configs_by_port[conf_port] = ota_conf else: - raise cv.Invalid( - f"Only one instance of the {CONF_ESPHOME} {CONF_OTA} {CONF_PLATFORM} is allowed per port. Note that this error may result from OTA specified in packages" + if merged_ota_esphome_configs_by_port[conf_port][ + CONF_VERSION + ] != ota_conf.get(CONF_VERSION): + raise cv.Invalid( + f"Found multiple configurations but {CONF_VERSION} is inconsistent" + ) + if ( + merged_ota_esphome_configs_by_port[conf_port][CONF_ID].is_manual + and ota_conf.get(CONF_ID).is_manual + ): + raise cv.Invalid( + f"Found multiple configurations but {CONF_ID} is inconsistent" + ) + if ( + CONF_PASSWORD in merged_ota_esphome_configs_by_port[conf_port] + and CONF_PASSWORD in ota_conf + and merged_ota_esphome_configs_by_port[conf_port][CONF_PASSWORD] + != ota_conf.get(CONF_PASSWORD) + ): + raise cv.Invalid( + f"Found multiple configurations but {CONF_PASSWORD} is inconsistent" + ) + + ports_with_merged_configs.append(conf_port) + merged_ota_esphome_configs_by_port[conf_port] = merge_config( + merged_ota_esphome_configs_by_port[conf_port], ota_conf ) + else: + new_ota_conf.append(ota_conf) + + for port_conf in merged_ota_esphome_configs_by_port.values(): + new_ota_conf.append(port_conf) + + full_conf[CONF_OTA] = new_ota_conf + fv.full_config.set(full_conf) + + if len(ports_with_merged_configs) > 0: + _LOGGER.warning( + "Found and merged multiple configurations for %s %s %s port(s) %s", + CONF_OTA, + CONF_PLATFORM, + CONF_ESPHOME, + ports_with_merged_configs, + ) CONFIG_SCHEMA = ( From 3a48b1075700bbc1e7a46b9bfda062b1a4400f2d Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Thu, 27 Jun 2024 03:48:01 +0200 Subject: [PATCH 1997/2607] Fix LEDC 100% is not 100% duty with ESP32 IDF (#6997) --- esphome/components/ledc/ledc_output.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 1040ac25b6..90e11fe4ad 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -115,12 +115,15 @@ void LEDCOutput::write_state(float state) { const uint32_t max_duty = (uint32_t(1) << this->bit_depth_) - 1; const float duty_rounded = roundf(state * max_duty); auto duty = static_cast(duty_rounded); - #ifdef USE_ARDUINO ESP_LOGV(TAG, "Setting duty: %u on channel %u", duty, this->channel_); ledcWrite(this->channel_, duty); #endif #ifdef USE_ESP_IDF + // ensure that 100% on is not 99.975% on + if ((duty == max_duty) && (max_duty != 1)) { + duty = max_duty + 1; + } auto speed_mode = get_speed_mode(channel_); auto chan_num = static_cast(channel_ % 8); int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); From 7904d3b157280387295d57e1dc9f60b253836b56 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:19:13 +1200 Subject: [PATCH 1998/2607] Bump version to 2024.6.4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 2434609191..b26d8d2851 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.3" +__version__ = "2024.6.4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From d0ab2a16a6774d0acf8efe5d475049d9439752ac Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:12:59 +1200 Subject: [PATCH 1999/2607] [mpr121] await register parented (#7014) fixes https://github.com/esphome/issues/issues/5913 --- esphome/components/mpr121/binary_sensor/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/mpr121/binary_sensor/__init__.py b/esphome/components/mpr121/binary_sensor/__init__.py index 292c631c37..dfae92a9af 100644 --- a/esphome/components/mpr121/binary_sensor/__init__.py +++ b/esphome/components/mpr121/binary_sensor/__init__.py @@ -27,7 +27,7 @@ async def to_code(config): var = await binary_sensor.new_binary_sensor(config) hub = await cg.get_variable(config[CONF_MPR121_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) - cg.register_parented(var, hub) + await cg.register_parented(var, hub) if CONF_TOUCH_THRESHOLD in config: cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) From e9cf3623d1e2238b7f92fa8f9eaf6bdd788ad3e1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 08:54:04 +1200 Subject: [PATCH 2000/2607] Bump dockerfile dependencies (#7017) --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index fcb5a5e7ae..eabd118939 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,7 +34,7 @@ RUN \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ git=1:2.39.2-1.1 \ - curl=7.88.1-10+deb12u5 \ + curl=7.88.1-10+deb12u6 \ openssh-client=1:9.2p1-2+deb12u2 \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ @@ -190,8 +190,8 @@ RUN \ clang-format-13=1:13.0.1-11+b2 \ clang-tidy-14=1:14.0.6-12 \ patch=2.7.6-7 \ - software-properties-common=0.99.30-4 \ - nano=7.2-1 \ + software-properties-common=0.99.30-4.1~deb12u1 \ + nano=7.2-1+deb12u1 \ build-essential=12.9 \ python3-dev=3.11.2-1+b1 \ && rm -rf \ From 6294c3b913d1f36b92f3c3845c4101644343e95e Mon Sep 17 00:00:00 2001 From: orland0m Date: Sun, 30 Jun 2024 16:06:59 -0700 Subject: [PATCH 2001/2607] Enable devcontainer linters (#7019) --- .devcontainer/devcontainer.json | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4596b59200..8d9565ad5f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,9 @@ { "name": "ESPHome Dev", "image": "ghcr.io/esphome/esphome-lint:dev", - "postCreateCommand": ["script/devcontainer-post-create"], + "postCreateCommand": [ + "script/devcontainer-post-create" + ], "containerEnv": { "DEVCONTAINER": "1", "PIP_BREAK_SYSTEM_PACKAGES": "1", @@ -27,6 +29,9 @@ "extensions": [ // python "ms-python.python", + "ms-python.pylint", + "ms-python.flake8", + "ms-python.black-formatter", "visualstudioexptteam.vscodeintellicode", // yaml "redhat.vscode-yaml", @@ -38,9 +43,21 @@ "settings": { "python.languageServer": "Pylance", "python.pythonPath": "/usr/bin/python3", - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.formatting.provider": "black", + "pylint.args": [ + "--rcfile=${workspaceFolder}/pyproject.toml" + ], + "flake8.args": [ + "--config=${workspaceFolder}/.flake8" + ], + "black-formatter.args": [ + "--config", + "${workspaceFolder}/pyproject.toml" + ], + "[python]": { + // VS will say "Value is not accepted" before building the devcontainer, but the warning + // should go away after build is completed. + "editor.defaultFormatter": "ms-python.black-formatter" + }, "editor.formatOnPaste": false, "editor.formatOnSave": true, "editor.formatOnType": true, From 715184070d92ac437db85d37c64c30c135725b53 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:17:44 +1200 Subject: [PATCH 2002/2607] [docker] Bump versions inside armv7 block (#7022) --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index eabd118939..b0c800f167 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -46,8 +46,8 @@ RUN \ python3-dev=3.11.2-1+b1 \ zlib1g-dev=1:1.2.13.dfsg-1 \ libjpeg-dev=1:2.1.5-2 \ - libfreetype-dev=2.12.1+dfsg-5 \ - libssl-dev=3.0.11-1~deb12u2 \ + libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ + libssl-dev=3.0.13-1~deb12u1 \ libffi-dev=3.4.4-1 \ libopenjp2-7=2.5.0-2 \ libtiff6=4.5.0-6+deb12u1 \ From b89dea97d9bfbe81f0eb639544e4e186b67c8378 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:51:51 +1200 Subject: [PATCH 2003/2607] [docker] Fix docker build error fall through (#7021) --- docker/Dockerfile | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b0c800f167..16f37274c6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -39,23 +39,27 @@ RUN \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ libmagic1=1:5.44-3 \ - patch=2.7.6-7; \ - if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ - apt-get install -y --no-install-recommends \ - build-essential=12.9 \ - python3-dev=3.11.2-1+b1 \ - zlib1g-dev=1:1.2.13.dfsg-1 \ - libjpeg-dev=1:2.1.5-2 \ - libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.13-1~deb12u1 \ - libffi-dev=3.4.4-1 \ - libopenjp2-7=2.5.0-2 \ - libtiff6=4.5.0-6+deb12u1 \ - cargo=0.66.0+ds1-1 \ - pkg-config=1.8.1-1 \ - gcc-arm-linux-gnueabihf=4:12.2.0-3; \ - fi; \ - rm -rf \ + patch=2.7.6-7 \ + && ( \ + ( \ + [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \ + apt-get install -y --no-install-recommends \ + build-essential=12.9 \ + python3-dev=3.11.2-1+b1 \ + zlib1g-dev=1:1.2.13.dfsg-1 \ + libjpeg-dev=1:2.1.5-2 \ + libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ + libssl-dev=3.0.13-1~deb12u1 \ + libffi-dev=3.4.4-1 \ + libopenjp2-7=2.5.0-2 \ + libtiff6=4.5.0-6+deb12u1 \ + cargo=0.66.0+ds1-1 \ + pkg-config=1.8.1-1 \ + gcc-arm-linux-gnueabihf=4:12.2.0-3 \ + ) \ + || [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \ + ) \ + && rm -rf \ /tmp/* \ /var/{cache,log}/* \ /var/lib/apt/lists/* From 5278ae4b5e620cd6983f2371759c18099878e1fe Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 30 Jun 2024 19:52:05 -0400 Subject: [PATCH 2004/2607] 'uart' and 'improv_serial' need to understand non-UART logger configurations (#6998) --- .../improv_serial/improv_serial_component.cpp | 16 +++++----- .../uart/uart_component_esp32_arduino.cpp | 22 +++++++++++--- .../uart/uart_component_esp_idf.cpp | 24 +++++++++++++-- .../{common.yaml => common-default_uart.yaml} | 0 tests/components/logger/common-usb_cdc.yaml | 8 +++++ .../logger/common-usb_serial_jtag.yaml | 8 +++++ .../logger/test-usb_cdc.esp32-c3-ard.yaml | 1 + .../logger/test-usb_cdc.esp32-s2-ard.yaml | 1 + .../logger/test-usb_cdc.esp32-s2-idf.yaml | 1 + .../logger/test-usb_cdc.esp32-s3-ard.yaml | 1 + .../test-usb_serial_jtag.esp32-c3-idf.yaml | 1 + .../test-usb_serial_jtag.esp32-s3-idf.yaml | 1 + tests/components/logger/test.esp32-ard.yaml | 2 +- .../components/logger/test.esp32-c3-ard.yaml | 2 +- .../components/logger/test.esp32-c3-idf.yaml | 2 +- tests/components/logger/test.esp32-idf.yaml | 2 +- tests/components/logger/test.esp8266-ard.yaml | 2 +- tests/components/logger/test.rp2040-ard.yaml | 2 +- ...st-uart_max_with_usb_cdc.esp32-c3-ard.yaml | 30 +++++++++++++++++++ ...st-uart_max_with_usb_cdc.esp32-s2-ard.yaml | 30 +++++++++++++++++++ ...st-uart_max_with_usb_cdc.esp32-s2-idf.yaml | 30 +++++++++++++++++++ ...st-uart_max_with_usb_cdc.esp32-s3-ard.yaml | 30 +++++++++++++++++++ ...max_with_usb_serial_jtag.esp32-c3-idf.yaml | 30 +++++++++++++++++++ ...max_with_usb_serial_jtag.esp32-s3-idf.yaml | 30 +++++++++++++++++++ 24 files changed, 256 insertions(+), 20 deletions(-) rename tests/components/logger/{common.yaml => common-default_uart.yaml} (100%) create mode 100644 tests/components/logger/common-usb_cdc.yaml create mode 100644 tests/components/logger/common-usb_serial_jtag.yaml create mode 100644 tests/components/logger/test-usb_cdc.esp32-c3-ard.yaml create mode 100644 tests/components/logger/test-usb_cdc.esp32-s2-ard.yaml create mode 100644 tests/components/logger/test-usb_cdc.esp32-s2-idf.yaml create mode 100644 tests/components/logger/test-usb_cdc.esp32-s3-ard.yaml create mode 100644 tests/components/logger/test-usb_serial_jtag.esp32-c3-idf.yaml create mode 100644 tests/components/logger/test-usb_serial_jtag.esp32-s3-idf.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_cdc.esp32-c3-ard.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-ard.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-idf.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_cdc.esp32-s3-ard.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-c3-idf.yaml create mode 100644 tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-s3-idf.yaml diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 2937720496..02ffa9f31c 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -57,7 +57,7 @@ optional ImprovSerialComponent::read_byte_() { } } break; -#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) +#ifdef USE_LOGGER_USB_CDC case logger::UART_SELECTION_USB_CDC: #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) if (esp_usb_console_available_for_read()) { @@ -68,15 +68,15 @@ optional ImprovSerialComponent::read_byte_() { byte = data; } break; -#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) +#endif // USE_LOGGER_USB_CDC +#ifdef USE_LOGGER_USB_SERIAL_JTAG case logger::UART_SELECTION_USB_SERIAL_JTAG: { if (usb_serial_jtag_read_bytes((char *) &data, 1, 0)) { byte = data; } break; } -#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 +#endif // USE_LOGGER_USB_SERIAL_JTAG default: break; } @@ -99,19 +99,19 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 uart_write_bytes(this->uart_num_, data.data(), data.size()); break; -#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) +#ifdef USE_LOGGER_USB_CDC case logger::UART_SELECTION_USB_CDC: { const char *msg = (char *) data.data(); esp_usb_console_write_buf(msg, data.size()); break; } -#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) +#endif // USE_LOGGER_USB_CDC +#ifdef USE_LOGGER_USB_SERIAL_JTAG case logger::UART_SELECTION_USB_SERIAL_JTAG: usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7 break; -#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3 +#endif // USE_LOGGER_USB_SERIAL_JTAG default: break; } diff --git a/esphome/components/uart/uart_component_esp32_arduino.cpp b/esphome/components/uart/uart_component_esp32_arduino.cpp index f77783e20e..793c1d52f4 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.cpp +++ b/esphome/components/uart/uart_component_esp32_arduino.cpp @@ -96,10 +96,24 @@ void ESP32ArduinoUARTComponent::setup() { next_uart_num++; } else { #ifdef USE_LOGGER - // The logger doesn't use this UART component, instead it targets the UARTs - // directly (i.e. Serial/Serial0, Serial1, and Serial2). If the logger is - // enabled, skip the UART that it is configured to use. - if (logger::global_logger->get_baud_rate() > 0 && logger::global_logger->get_uart() == next_uart_num) { + bool logger_uses_hardware_uart = true; + +#ifdef USE_LOGGER_USB_CDC + if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_CDC) { + // this is not a hardware UART, ignore it + logger_uses_hardware_uart = false; + } +#endif // USE_LOGGER_USB_CDC + +#ifdef USE_LOGGER_USB_SERIAL_JTAG + if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_SERIAL_JTAG) { + // this is not a hardware UART, ignore it + logger_uses_hardware_uart = false; + } +#endif // USE_LOGGER_USB_SERIAL_JTAG + + if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 && + logger::global_logger->get_uart() == next_uart_num) { next_uart_num++; } #endif // USE_LOGGER diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index c66753b0c4..6999dfb619 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -60,10 +60,30 @@ uart_config_t IDFUARTComponent::get_config_() { void IDFUARTComponent::setup() { static uint8_t next_uart_num = 0; + #ifdef USE_LOGGER - if (logger::global_logger->get_uart_num() == next_uart_num) + bool logger_uses_hardware_uart = true; + +#ifdef USE_LOGGER_USB_CDC + if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_CDC) { + // this is not a hardware UART, ignore it + logger_uses_hardware_uart = false; + } +#endif // USE_LOGGER_USB_CDC + +#ifdef USE_LOGGER_USB_SERIAL_JTAG + if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_SERIAL_JTAG) { + // this is not a hardware UART, ignore it + logger_uses_hardware_uart = false; + } +#endif // USE_LOGGER_USB_SERIAL_JTAG + + if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 && + logger::global_logger->get_uart_num() == next_uart_num) { next_uart_num++; -#endif + } +#endif // USE_LOGGER + if (next_uart_num >= UART_NUM_MAX) { ESP_LOGW(TAG, "Maximum number of UART components created already."); this->mark_failed(); diff --git a/tests/components/logger/common.yaml b/tests/components/logger/common-default_uart.yaml similarity index 100% rename from tests/components/logger/common.yaml rename to tests/components/logger/common-default_uart.yaml diff --git a/tests/components/logger/common-usb_cdc.yaml b/tests/components/logger/common-usb_cdc.yaml new file mode 100644 index 0000000000..4df320527d --- /dev/null +++ b/tests/components/logger/common-usb_cdc.yaml @@ -0,0 +1,8 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG + hardware_uart: USB_CDC diff --git a/tests/components/logger/common-usb_serial_jtag.yaml b/tests/components/logger/common-usb_serial_jtag.yaml new file mode 100644 index 0000000000..5891c9ea40 --- /dev/null +++ b/tests/components/logger/common-usb_serial_jtag.yaml @@ -0,0 +1,8 @@ +esphome: + on_boot: + then: + - logger.log: Hello world + +logger: + level: DEBUG + hardware_uart: USB_SERIAL_JTAG diff --git a/tests/components/logger/test-usb_cdc.esp32-c3-ard.yaml b/tests/components/logger/test-usb_cdc.esp32-c3-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/logger/test-usb_cdc.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/logger/test-usb_cdc.esp32-s2-ard.yaml b/tests/components/logger/test-usb_cdc.esp32-s2-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/logger/test-usb_cdc.esp32-s2-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/logger/test-usb_cdc.esp32-s2-idf.yaml b/tests/components/logger/test-usb_cdc.esp32-s2-idf.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/logger/test-usb_cdc.esp32-s2-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/logger/test-usb_cdc.esp32-s3-ard.yaml b/tests/components/logger/test-usb_cdc.esp32-s3-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/logger/test-usb_cdc.esp32-s3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/logger/test-usb_serial_jtag.esp32-c3-idf.yaml b/tests/components/logger/test-usb_serial_jtag.esp32-c3-idf.yaml new file mode 100644 index 0000000000..46a927ff10 --- /dev/null +++ b/tests/components/logger/test-usb_serial_jtag.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_serial_jtag.yaml diff --git a/tests/components/logger/test-usb_serial_jtag.esp32-s3-idf.yaml b/tests/components/logger/test-usb_serial_jtag.esp32-s3-idf.yaml new file mode 100644 index 0000000000..46a927ff10 --- /dev/null +++ b/tests/components/logger/test-usb_serial_jtag.esp32-s3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_serial_jtag.yaml diff --git a/tests/components/logger/test.esp32-ard.yaml b/tests/components/logger/test.esp32-ard.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.esp32-ard.yaml +++ b/tests/components/logger/test.esp32-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/logger/test.esp32-c3-ard.yaml b/tests/components/logger/test.esp32-c3-ard.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.esp32-c3-ard.yaml +++ b/tests/components/logger/test.esp32-c3-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/logger/test.esp32-c3-idf.yaml b/tests/components/logger/test.esp32-c3-idf.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.esp32-c3-idf.yaml +++ b/tests/components/logger/test.esp32-c3-idf.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/logger/test.esp32-idf.yaml b/tests/components/logger/test.esp32-idf.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.esp32-idf.yaml +++ b/tests/components/logger/test.esp32-idf.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/logger/test.esp8266-ard.yaml b/tests/components/logger/test.esp8266-ard.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.esp8266-ard.yaml +++ b/tests/components/logger/test.esp8266-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/logger/test.rp2040-ard.yaml b/tests/components/logger/test.rp2040-ard.yaml index dade44d145..3fe04e18a3 100644 --- a/tests/components/logger/test.rp2040-ard.yaml +++ b/tests/components/logger/test.rp2040-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common-default_uart.yaml diff --git a/tests/components/uart/test-uart_max_with_usb_cdc.esp32-c3-ard.yaml b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-c3-ard.yaml new file mode 100644 index 0000000000..2a73826c51 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-c3-ard.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_cdc.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-ard.yaml b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-ard.yaml new file mode 100644 index 0000000000..2a73826c51 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-ard.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_cdc.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-idf.yaml b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-idf.yaml new file mode 100644 index 0000000000..2a73826c51 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s2-idf.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_cdc.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s3-ard.yaml b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s3-ard.yaml new file mode 100644 index 0000000000..2a73826c51 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_cdc.esp32-s3-ard.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_cdc.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-c3-idf.yaml b/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e0a07dde91 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-c3-idf.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_serial_jtag.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 diff --git a/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-s3-idf.yaml b/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-s3-idf.yaml new file mode 100644 index 0000000000..e0a07dde91 --- /dev/null +++ b/tests/components/uart/test-uart_max_with_usb_serial_jtag.esp32-s3-idf.yaml @@ -0,0 +1,30 @@ +<<: !include ../logger/common-usb_serial_jtag.yaml + +esphome: + on_boot: + then: + - uart.write: + id: uart_1 + data: 'Hello World' + - uart.write: + id: uart_1 + data: [0x00, 0x20, 0x42] + +uart: + - id: uart_1 + tx_pin: 4 + rx_pin: 5 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 + + - id: uart_2 + tx_pin: 6 + rx_pin: 7 + baud_rate: 9600 + data_bits: 8 + rx_buffer_size: 512 + parity: EVEN + stop_bits: 2 From 7aaa5ce9c859426964bcca238418c4a75dd0017a Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 1 Jul 2024 01:20:59 -0500 Subject: [PATCH 2005/2607] Move some consts for #4585 (#7023) --- esphome/components/bme680_bsec/__init__.py | 3 +-- esphome/components/bme680_bsec/sensor.py | 12 ++++++------ esphome/components/bme680_bsec/text_sensor.py | 2 +- esphome/components/i2s_audio/microphone/__init__.py | 3 +-- esphome/const.py | 2 ++ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index 62ab50b8f7..743ef6e85d 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, esp32 -from esphome.const import CONF_ID, CONF_TEMPERATURE_OFFSET +from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET CODEOWNERS = ["@trvrnrth"] DEPENDENCIES = ["i2c"] @@ -11,7 +11,6 @@ MULTI_CONF = True CONF_BME680_BSEC_ID = "bme680_bsec_id" CONF_IAQ_MODE = "iaq_mode" CONF_SUPPLY_VOLTAGE = "supply_voltage" -CONF_SAMPLE_RATE = "sample_rate" CONF_STATE_SAVE_INTERVAL = "state_save_interval" bme680_bsec_ns = cg.esphome_ns.namespace("bme680_bsec") diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 43b068b926..aa96998232 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -4,33 +4,33 @@ from esphome.components import sensor from esphome.const import ( CONF_GAS_RESISTANCE, CONF_HUMIDITY, + CONF_IAQ_ACCURACY, CONF_PRESSURE, + CONF_SAMPLE_RATE, CONF_TEMPERATURE, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, - DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + ICON_GAS_CYLINDER, + ICON_GAUGE, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_HECTOPASCAL, UNIT_OHM, UNIT_PARTS_PER_MILLION, UNIT_PERCENT, - ICON_GAS_CYLINDER, - ICON_GAUGE, ) from . import ( BME680BSECComponent, CONF_BME680_BSEC_ID, - CONF_SAMPLE_RATE, SAMPLE_RATE_OPTIONS, ) DEPENDENCIES = ["bme680_bsec"] CONF_IAQ = "iaq" -CONF_IAQ_ACCURACY = "iaq_accuracy" CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" UNIT_IAQ = "IAQ" diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index 3494ba0cac..6b46e501da 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -1,11 +1,11 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor +from esphome.const import CONF_IAQ_ACCURACY from . import BME680BSECComponent, CONF_BME680_BSEC_ID DEPENDENCIES = ["bme680_bsec"] -CONF_IAQ_ACCURACY = "iaq_accuracy" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" TYPES = [CONF_IAQ_ACCURACY] diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index 5ee359dc26..d9c31e8e7b 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -2,7 +2,7 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome import pins -from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER, CONF_SAMPLE_RATE from esphome.components import microphone, esp32 from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin @@ -20,7 +20,6 @@ DEPENDENCIES = ["i2s_audio"] CONF_ADC_PIN = "adc_pin" CONF_ADC_TYPE = "adc_type" CONF_PDM = "pdm" -CONF_SAMPLE_RATE = "sample_rate" CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_USE_APLL = "use_apll" diff --git a/esphome/const.py b/esphome/const.py index a13a0af8eb..543b1d00cc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -355,6 +355,7 @@ CONF_HUMIDITY_SENSOR = "humidity_sensor" CONF_HYSTERESIS = "hysteresis" CONF_I2C = "i2c" CONF_I2C_ID = "i2c_id" +CONF_IAQ_ACCURACY = "iaq_accuracy" CONF_IBEACON_MAJOR = "ibeacon_major" CONF_IBEACON_MINOR = "ibeacon_minor" CONF_IBEACON_UUID = "ibeacon_uuid" @@ -719,6 +720,7 @@ CONF_RX_BUFFER_SIZE = "rx_buffer_size" CONF_RX_ONLY = "rx_only" CONF_RX_PIN = "rx_pin" CONF_SAFE_MODE = "safe_mode" +CONF_SAMPLE_RATE = "sample_rate" CONF_SAMSUNG = "samsung" CONF_SATELLITES = "satellites" CONF_SCAN = "scan" From 582386d3a2cf0812e84f5e245b3f1764b185c88b Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Tue, 2 Jul 2024 03:47:56 +0200 Subject: [PATCH 2006/2607] Make crc8 const-correct (#7027) --- esphome/core/helpers.cpp | 2 +- esphome/core/helpers.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index dee771d4e9..7f040f855f 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -93,7 +93,7 @@ std::string to_string(long double value) { return str_snprintf("%Lf", 32, value) // Mathematics float lerp(float completion, float start, float end) { return start + (end - start) * completion; } -uint8_t crc8(uint8_t *data, uint8_t len) { +uint8_t crc8(const uint8_t *data, uint8_t len) { uint8_t crc = 0; while ((len--) != 0u) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 4af840f77b..b4ad22b083 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -155,7 +155,7 @@ template T remap(U value, U min, U max, T min_out, T max } /// Calculate a CRC-8 checksum of \p data with size \p len. -uint8_t crc8(uint8_t *data, uint8_t len); +uint8_t crc8(const uint8_t *data, uint8_t len); /// Calculate a CRC-16 checksum of \p data with size \p len. uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc = 0xffff, uint16_t reverse_poly = 0xa001, From 83f9664efbc04fa0b66780c23aabc85557aa85f0 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 1 Jul 2024 21:06:33 -0500 Subject: [PATCH 2007/2607] [CI] Run all tests when a base test changes (#7010) --- script/list-components.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/script/list-components.py b/script/list-components.py index 4eccdbf96c..559919bb8a 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -140,7 +140,10 @@ def get_components(files: list[str], get_dependencies: bool = False): def main(): parser = argparse.ArgumentParser() parser.add_argument( - "-c", "--changed", action="store_true", help="Only run on changed files" + "-c", + "--changed", + action="store_true", + help="List all components required for testing based on changes", ) parser.add_argument( "-b", "--branch", help="Branch to compare changed files against" @@ -158,7 +161,9 @@ def main(): changed = changed_files(args.branch) else: changed = changed_files() - files = [f for f in files if f in changed] + # If any base test file(s) changed, there's no need to filter out components + if not any("tests/test_build_components" in file for file in changed): + files = [f for f in files if f in changed] for c in get_components(files, args.changed): print(c) From 5e6c69b9307724f62ff25873d7c687cf239104dc Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 1 Jul 2024 21:07:36 -0500 Subject: [PATCH 2008/2607] [CI] Update tests to run against IDF 5.1 (#7011) --- ...f-50.yaml => build_components_base.esp32-c3-idf-51.yaml} | 6 +++--- ...-idf-50.yaml => build_components_base.esp32-idf-51.yaml} | 6 +++--- ...f-50.yaml => build_components_base.esp32-s2-idf-51.yaml} | 6 +++--- ...f-50.yaml => build_components_base.esp32-s3-idf-51.yaml} | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) rename tests/test_build_components/{build_components_base.esp32-c3-idf-50.yaml => build_components_base.esp32-c3-idf-51.yaml} (76%) rename tests/test_build_components/{build_components_base.esp32-idf-50.yaml => build_components_base.esp32-idf-51.yaml} (77%) rename tests/test_build_components/{build_components_base.esp32-s2-idf-50.yaml => build_components_base.esp32-s2-idf-51.yaml} (78%) rename tests/test_build_components/{build_components_base.esp32-s3-idf-50.yaml => build_components_base.esp32-s3-idf-51.yaml} (77%) diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml similarity index 76% rename from tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml index 08d4d8679c..eb5b23a4ec 100644 --- a/tests/test_build_components/build_components_base.esp32-c3-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32c3idf50 + name: componenttestesp32c3idf51 friendly_name: $component_name esp32: board: lolin_c3_mini framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.5.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-idf-51.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-idf-51.yaml index c9f2c1e943..b5e3dd6d83 100644 --- a/tests/test_build_components/build_components_base.esp32-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-idf-51.yaml @@ -1,13 +1,13 @@ esphome: - name: componenttestesp32idf50 + name: componenttestesp32idf51 friendly_name: $component_name esp32: board: nodemcu-32s framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.5.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml similarity index 78% rename from tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml index 351f5fb019..11b077509e 100644 --- a/tests/test_build_components/build_components_base.esp32-s2-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s2idf50 + name: componenttestesp32s2idf51 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S2 framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.5.0 logger: level: VERY_VERBOSE diff --git a/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml similarity index 77% rename from tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml rename to tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml index c05378903f..4357b3581b 100644 --- a/tests/test_build_components/build_components_base.esp32-s3-idf-50.yaml +++ b/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml @@ -1,5 +1,5 @@ esphome: - name: componenttestesp32s3idf50 + name: componenttestesp32s3idf51 friendly_name: $component_name esp32: @@ -7,8 +7,8 @@ esp32: variant: ESP32S3 framework: type: esp-idf - version: 5.0.2 - platform_version: 6.3.2 + version: 5.1.2 + platform_version: 6.5.0 logger: level: VERY_VERBOSE From d8f0dce08f6e76cddd1ccc784713f14befb4c36f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:29:49 +1200 Subject: [PATCH 2009/2607] [uptime] Add new timestamp type for uptime sensor (#7029) * [uptime] Add new timestamp type for uptime sensor * Remove debug logs --- esphome/components/uptime/sensor.py | 55 +++++++++++++++---- ...e_sensor.cpp => uptime_seconds_sensor.cpp} | 18 +++--- ...ptime_sensor.h => uptime_seconds_sensor.h} | 4 +- .../uptime/uptime_timestamp_sensor.cpp | 39 +++++++++++++ .../uptime/uptime_timestamp_sensor.h | 30 ++++++++++ tests/components/uptime/common.yaml | 12 ++++ 6 files changed, 138 insertions(+), 20 deletions(-) rename esphome/components/uptime/{uptime_sensor.cpp => uptime_seconds_sensor.cpp} (72%) rename esphome/components/uptime/{uptime_sensor.h => uptime_seconds_sensor.h} (82%) create mode 100644 esphome/components/uptime/uptime_timestamp_sensor.cpp create mode 100644 esphome/components/uptime/uptime_timestamp_sensor.h diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py index 07d7d8f2cf..30220751b6 100644 --- a/esphome/components/uptime/sensor.py +++ b/esphome/components/uptime/sensor.py @@ -1,7 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor +from esphome.components import sensor, time from esphome.const import ( + CONF_TIME_ID, + DEVICE_CLASS_TIMESTAMP, ENTITY_CATEGORY_DIAGNOSTIC, STATE_CLASS_TOTAL_INCREASING, UNIT_SECOND, @@ -10,19 +12,50 @@ from esphome.const import ( ) uptime_ns = cg.esphome_ns.namespace("uptime") -UptimeSensor = uptime_ns.class_("UptimeSensor", sensor.Sensor, cg.PollingComponent) +UptimeSecondsSensor = uptime_ns.class_( + "UptimeSecondsSensor", sensor.Sensor, cg.PollingComponent +) +UptimeTimestampSensor = uptime_ns.class_( + "UptimeTimestampSensor", sensor.Sensor, cg.Component +) -CONFIG_SCHEMA = sensor.sensor_schema( - UptimeSensor, - unit_of_measurement=UNIT_SECOND, - icon=ICON_TIMER, - accuracy_decimals=0, - state_class=STATE_CLASS_TOTAL_INCREASING, - device_class=DEVICE_CLASS_DURATION, - entity_category=ENTITY_CATEGORY_DIAGNOSTIC, -).extend(cv.polling_component_schema("60s")) + +CONFIG_SCHEMA = cv.typed_schema( + { + "seconds": sensor.sensor_schema( + UptimeSecondsSensor, + unit_of_measurement=UNIT_SECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_TOTAL_INCREASING, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ).extend(cv.polling_component_schema("60s")), + "timestamp": sensor.sensor_schema( + UptimeTimestampSensor, + icon=ICON_TIMER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TIMESTAMP, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ) + .extend( + cv.Schema( + { + cv.GenerateID(CONF_TIME_ID): cv.All( + cv.requires_component("time"), cv.use_id(time.RealTimeClock) + ), + } + ) + ) + .extend(cv.COMPONENT_SCHEMA), + }, + default_type="seconds", +) async def to_code(config): var = await sensor.new_sensor(config) await cg.register_component(var, config) + if time_id_config := config.get(CONF_TIME_ID): + time_id = await cg.get_variable(time_id_config) + cg.add(var.set_time(time_id)) diff --git a/esphome/components/uptime/uptime_sensor.cpp b/esphome/components/uptime/uptime_seconds_sensor.cpp similarity index 72% rename from esphome/components/uptime/uptime_sensor.cpp rename to esphome/components/uptime/uptime_seconds_sensor.cpp index 40325d2a36..fa6b9d621d 100644 --- a/esphome/components/uptime/uptime_sensor.cpp +++ b/esphome/components/uptime/uptime_seconds_sensor.cpp @@ -1,14 +1,15 @@ -#include "uptime_sensor.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" +#include "uptime_seconds_sensor.h" + #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace uptime { static const char *const TAG = "uptime.sensor"; -void UptimeSensor::update() { +void UptimeSecondsSensor::update() { const uint32_t ms = millis(); const uint64_t ms_mask = (1ULL << 32) - 1ULL; const uint32_t last_ms = this->uptime_ & ms_mask; @@ -26,9 +27,12 @@ void UptimeSensor::update() { const float seconds = float(seconds_int) + (this->uptime_ % 1000ULL) / 1000.0f; this->publish_state(seconds); } -std::string UptimeSensor::unique_id() { return get_mac_address() + "-uptime"; } -float UptimeSensor::get_setup_priority() const { return setup_priority::HARDWARE; } -void UptimeSensor::dump_config() { LOG_SENSOR("", "Uptime Sensor", this); } +std::string UptimeSecondsSensor::unique_id() { return get_mac_address() + "-uptime"; } +float UptimeSecondsSensor::get_setup_priority() const { return setup_priority::HARDWARE; } +void UptimeSecondsSensor::dump_config() { + LOG_SENSOR("", "Uptime Sensor", this); + ESP_LOGCONFIG(TAG, " Type: Seconds"); +} } // namespace uptime } // namespace esphome diff --git a/esphome/components/uptime/uptime_sensor.h b/esphome/components/uptime/uptime_seconds_sensor.h similarity index 82% rename from esphome/components/uptime/uptime_sensor.h rename to esphome/components/uptime/uptime_seconds_sensor.h index dab380d2d9..41b3647822 100644 --- a/esphome/components/uptime/uptime_sensor.h +++ b/esphome/components/uptime/uptime_seconds_sensor.h @@ -1,12 +1,12 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" namespace esphome { namespace uptime { -class UptimeSensor : public sensor::Sensor, public PollingComponent { +class UptimeSecondsSensor : public sensor::Sensor, public PollingComponent { public: void update() override; void dump_config() override; diff --git a/esphome/components/uptime/uptime_timestamp_sensor.cpp b/esphome/components/uptime/uptime_timestamp_sensor.cpp new file mode 100644 index 0000000000..fa8cb2bb61 --- /dev/null +++ b/esphome/components/uptime/uptime_timestamp_sensor.cpp @@ -0,0 +1,39 @@ +#include "uptime_timestamp_sensor.h" + +#ifdef USE_TIME + +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace uptime { + +static const char *const TAG = "uptime.sensor"; + +void UptimeTimestampSensor::setup() { + this->time_->add_on_time_sync_callback([this]() { + if (this->has_state_) + return; // No need to update the timestamp if it's already set + + auto now = this->time_->now(); + const uint32_t ms = millis(); + if (!now.is_valid()) + return; // No need to update the timestamp if the time is not valid + + time_t timestamp = now.timestamp; + uint32_t seconds = ms / 1000; + timestamp -= seconds; + this->publish_state(timestamp); + }); +} +float UptimeTimestampSensor::get_setup_priority() const { return setup_priority::HARDWARE; } +void UptimeTimestampSensor::dump_config() { + LOG_SENSOR("", "Uptime Sensor", this); + ESP_LOGCONFIG(TAG, " Type: Timestamp"); +} + +} // namespace uptime +} // namespace esphome + +#endif // USE_TIME diff --git a/esphome/components/uptime/uptime_timestamp_sensor.h b/esphome/components/uptime/uptime_timestamp_sensor.h new file mode 100644 index 0000000000..f38b5d53b4 --- /dev/null +++ b/esphome/components/uptime/uptime_timestamp_sensor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_TIME + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/time/real_time_clock.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace uptime { + +class UptimeTimestampSensor : public sensor::Sensor, public Component { + public: + void setup() override; + void dump_config() override; + + float get_setup_priority() const override; + + void set_time(time::RealTimeClock *time) { this->time_ = time; } + + protected: + time::RealTimeClock *time_; +}; + +} // namespace uptime +} // namespace esphome + +#endif // USE_TIME diff --git a/tests/components/uptime/common.yaml b/tests/components/uptime/common.yaml index 872a0e7402..f63f80b050 100644 --- a/tests/components/uptime/common.yaml +++ b/tests/components/uptime/common.yaml @@ -1,3 +1,15 @@ +wifi: + ap: + +time: + - platform: sntp + sensor: - platform: uptime name: Uptime Sensor + - platform: uptime + name: Uptime Sensor Seconds + type: seconds + - platform: uptime + name: Uptime Sensor Timestamp + type: timestamp From 3fb9c93a24b3b9683c5987af3ebe88cfa0492e49 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Jul 2024 14:21:41 +1200 Subject: [PATCH 2010/2607] [wifi] Only set default ttls phase 2 on esp-idf (#7033) * [wifi] Only set default ttls phase 2 on esp-idf * Add eap arduino test --- esphome/components/wifi/__init__.py | 4 ++-- tests/components/wifi/test-eap.esp32-ard.yaml | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 tests/components/wifi/test-eap.esp32-ard.yaml diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 3b9e00956f..624bcdabdc 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -114,7 +114,7 @@ EAP_AUTH_SCHEMA = cv.All( cv.Optional(CONF_USERNAME): cv.string_strict, cv.Optional(CONF_PASSWORD): cv.string_strict, cv.Optional(CONF_CERTIFICATE_AUTHORITY): wpa2_eap.validate_certificate, - cv.Optional(CONF_TTLS_PHASE_2): cv.All( + cv.SplitDefault(CONF_TTLS_PHASE_2, esp32_idf="mschapv2"): cv.All( cv.enum(TTLS_PHASE_2), cv.only_with_esp_idf ), cv.Inclusive( @@ -350,7 +350,7 @@ def eap_auth(config): ("ca_cert", ca_cert), ("client_cert", client_cert), ("client_key", key), - ("ttls_phase_2", config.get(CONF_TTLS_PHASE_2, TTLS_PHASE_2["mschapv2"])), + ("ttls_phase_2", config.get(CONF_TTLS_PHASE_2)), ) diff --git a/tests/components/wifi/test-eap.esp32-ard.yaml b/tests/components/wifi/test-eap.esp32-ard.yaml new file mode 100644 index 0000000000..779cd6b49a --- /dev/null +++ b/tests/components/wifi/test-eap.esp32-ard.yaml @@ -0,0 +1,7 @@ +wifi: + networks: + - ssid: MySSID + eap: + username: username + password: password + identity: identity From 12f00a9d3d4e5354bd3c21b414b60cc14e04ee73 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:12:59 +1200 Subject: [PATCH 2011/2607] [mpr121] await register parented (#7014) fixes https://github.com/esphome/issues/issues/5913 --- esphome/components/mpr121/binary_sensor/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/mpr121/binary_sensor/__init__.py b/esphome/components/mpr121/binary_sensor/__init__.py index 292c631c37..dfae92a9af 100644 --- a/esphome/components/mpr121/binary_sensor/__init__.py +++ b/esphome/components/mpr121/binary_sensor/__init__.py @@ -27,7 +27,7 @@ async def to_code(config): var = await binary_sensor.new_binary_sensor(config) hub = await cg.get_variable(config[CONF_MPR121_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) - cg.register_parented(var, hub) + await cg.register_parented(var, hub) if CONF_TOUCH_THRESHOLD in config: cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) From 0914dc719889d25e71bf12a4025c821ed6542504 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 1 Jul 2024 01:20:59 -0500 Subject: [PATCH 2012/2607] Move some consts for #4585 (#7023) --- esphome/components/bme680_bsec/__init__.py | 3 +-- esphome/components/bme680_bsec/sensor.py | 12 ++++++------ esphome/components/bme680_bsec/text_sensor.py | 2 +- esphome/components/i2s_audio/microphone/__init__.py | 3 +-- esphome/const.py | 2 ++ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index 62ab50b8f7..743ef6e85d 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, esp32 -from esphome.const import CONF_ID, CONF_TEMPERATURE_OFFSET +from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET CODEOWNERS = ["@trvrnrth"] DEPENDENCIES = ["i2c"] @@ -11,7 +11,6 @@ MULTI_CONF = True CONF_BME680_BSEC_ID = "bme680_bsec_id" CONF_IAQ_MODE = "iaq_mode" CONF_SUPPLY_VOLTAGE = "supply_voltage" -CONF_SAMPLE_RATE = "sample_rate" CONF_STATE_SAVE_INTERVAL = "state_save_interval" bme680_bsec_ns = cg.esphome_ns.namespace("bme680_bsec") diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 43b068b926..aa96998232 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -4,33 +4,33 @@ from esphome.components import sensor from esphome.const import ( CONF_GAS_RESISTANCE, CONF_HUMIDITY, + CONF_IAQ_ACCURACY, CONF_PRESSURE, + CONF_SAMPLE_RATE, CONF_TEMPERATURE, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, - DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, + ICON_GAS_CYLINDER, + ICON_GAUGE, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_HECTOPASCAL, UNIT_OHM, UNIT_PARTS_PER_MILLION, UNIT_PERCENT, - ICON_GAS_CYLINDER, - ICON_GAUGE, ) from . import ( BME680BSECComponent, CONF_BME680_BSEC_ID, - CONF_SAMPLE_RATE, SAMPLE_RATE_OPTIONS, ) DEPENDENCIES = ["bme680_bsec"] CONF_IAQ = "iaq" -CONF_IAQ_ACCURACY = "iaq_accuracy" CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" UNIT_IAQ = "IAQ" diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index 3494ba0cac..6b46e501da 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -1,11 +1,11 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor +from esphome.const import CONF_IAQ_ACCURACY from . import BME680BSECComponent, CONF_BME680_BSEC_ID DEPENDENCIES = ["bme680_bsec"] -CONF_IAQ_ACCURACY = "iaq_accuracy" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" TYPES = [CONF_IAQ_ACCURACY] diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index 5ee359dc26..d9c31e8e7b 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -2,7 +2,7 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome import pins -from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER, CONF_SAMPLE_RATE from esphome.components import microphone, esp32 from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin @@ -20,7 +20,6 @@ DEPENDENCIES = ["i2s_audio"] CONF_ADC_PIN = "adc_pin" CONF_ADC_TYPE = "adc_type" CONF_PDM = "pdm" -CONF_SAMPLE_RATE = "sample_rate" CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_USE_APLL = "use_apll" diff --git a/esphome/const.py b/esphome/const.py index b26d8d2851..fee9c1796a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -355,6 +355,7 @@ CONF_HUMIDITY_SENSOR = "humidity_sensor" CONF_HYSTERESIS = "hysteresis" CONF_I2C = "i2c" CONF_I2C_ID = "i2c_id" +CONF_IAQ_ACCURACY = "iaq_accuracy" CONF_IBEACON_MAJOR = "ibeacon_major" CONF_IBEACON_MINOR = "ibeacon_minor" CONF_IBEACON_UUID = "ibeacon_uuid" @@ -719,6 +720,7 @@ CONF_RX_BUFFER_SIZE = "rx_buffer_size" CONF_RX_ONLY = "rx_only" CONF_RX_PIN = "rx_pin" CONF_SAFE_MODE = "safe_mode" +CONF_SAMPLE_RATE = "sample_rate" CONF_SAMSUNG = "samsung" CONF_SATELLITES = "satellites" CONF_SCAN = "scan" From 5cb80619ddd362c055e9e418f9da1c4c175687b5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Jul 2024 14:21:41 +1200 Subject: [PATCH 2013/2607] [wifi] Only set default ttls phase 2 on esp-idf (#7033) * [wifi] Only set default ttls phase 2 on esp-idf * Add eap arduino test --- esphome/components/wifi/__init__.py | 4 ++-- tests/components/wifi/test-eap.esp32-ard.yaml | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 tests/components/wifi/test-eap.esp32-ard.yaml diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 3b9e00956f..624bcdabdc 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -114,7 +114,7 @@ EAP_AUTH_SCHEMA = cv.All( cv.Optional(CONF_USERNAME): cv.string_strict, cv.Optional(CONF_PASSWORD): cv.string_strict, cv.Optional(CONF_CERTIFICATE_AUTHORITY): wpa2_eap.validate_certificate, - cv.Optional(CONF_TTLS_PHASE_2): cv.All( + cv.SplitDefault(CONF_TTLS_PHASE_2, esp32_idf="mschapv2"): cv.All( cv.enum(TTLS_PHASE_2), cv.only_with_esp_idf ), cv.Inclusive( @@ -350,7 +350,7 @@ def eap_auth(config): ("ca_cert", ca_cert), ("client_cert", client_cert), ("client_key", key), - ("ttls_phase_2", config.get(CONF_TTLS_PHASE_2, TTLS_PHASE_2["mschapv2"])), + ("ttls_phase_2", config.get(CONF_TTLS_PHASE_2)), ) diff --git a/tests/components/wifi/test-eap.esp32-ard.yaml b/tests/components/wifi/test-eap.esp32-ard.yaml new file mode 100644 index 0000000000..779cd6b49a --- /dev/null +++ b/tests/components/wifi/test-eap.esp32-ard.yaml @@ -0,0 +1,7 @@ +wifi: + networks: + - ssid: MySSID + eap: + username: username + password: password + identity: identity From 995db1d0e11554fed3fa62672df3faa535b7f1ba Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:45:30 +1200 Subject: [PATCH 2014/2607] Bump version to 2024.6.5 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fee9c1796a..5b441faa6c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.4" +__version__ = "2024.6.5" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From ee6f2bfecb1bb728d37f4f4283b05301894eaab9 Mon Sep 17 00:00:00 2001 From: lhy Date: Wed, 3 Jul 2024 17:03:54 +0900 Subject: [PATCH 2015/2607] Fix compile errors on ESP32-C6 with W5500 SPI ethernet (#7030) --- esphome/components/ethernet/ethernet_component.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 7370cb4b44..6b34157b9d 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -65,7 +65,8 @@ void EthernetComponent::setup() { .intr_flags = 0, }; -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32C6) auto host = SPI2_HOST; #else auto host = SPI3_HOST; From 849a98d5b4e93ba61cd323cd224d46774d3566bc Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 08:54:04 +1200 Subject: [PATCH 2016/2607] Bump dockerfile dependencies (#7017) --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index fcb5a5e7ae..eabd118939 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,7 +34,7 @@ RUN \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ git=1:2.39.2-1.1 \ - curl=7.88.1-10+deb12u5 \ + curl=7.88.1-10+deb12u6 \ openssh-client=1:9.2p1-2+deb12u2 \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ @@ -190,8 +190,8 @@ RUN \ clang-format-13=1:13.0.1-11+b2 \ clang-tidy-14=1:14.0.6-12 \ patch=2.7.6-7 \ - software-properties-common=0.99.30-4 \ - nano=7.2-1 \ + software-properties-common=0.99.30-4.1~deb12u1 \ + nano=7.2-1+deb12u1 \ build-essential=12.9 \ python3-dev=3.11.2-1+b1 \ && rm -rf \ From c013c3bf6194ab257c108ef66b27af18939bcf5f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:17:44 +1200 Subject: [PATCH 2017/2607] [docker] Bump versions inside armv7 block (#7022) --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index eabd118939..b0c800f167 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -46,8 +46,8 @@ RUN \ python3-dev=3.11.2-1+b1 \ zlib1g-dev=1:1.2.13.dfsg-1 \ libjpeg-dev=1:2.1.5-2 \ - libfreetype-dev=2.12.1+dfsg-5 \ - libssl-dev=3.0.11-1~deb12u2 \ + libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ + libssl-dev=3.0.13-1~deb12u1 \ libffi-dev=3.4.4-1 \ libopenjp2-7=2.5.0-2 \ libtiff6=4.5.0-6+deb12u1 \ From fc3f806555eb395452c0526b3e9cf1503fdcee51 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:51:51 +1200 Subject: [PATCH 2018/2607] [docker] Fix docker build error fall through (#7021) --- docker/Dockerfile | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b0c800f167..16f37274c6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -39,23 +39,27 @@ RUN \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ libmagic1=1:5.44-3 \ - patch=2.7.6-7; \ - if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ - apt-get install -y --no-install-recommends \ - build-essential=12.9 \ - python3-dev=3.11.2-1+b1 \ - zlib1g-dev=1:1.2.13.dfsg-1 \ - libjpeg-dev=1:2.1.5-2 \ - libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.13-1~deb12u1 \ - libffi-dev=3.4.4-1 \ - libopenjp2-7=2.5.0-2 \ - libtiff6=4.5.0-6+deb12u1 \ - cargo=0.66.0+ds1-1 \ - pkg-config=1.8.1-1 \ - gcc-arm-linux-gnueabihf=4:12.2.0-3; \ - fi; \ - rm -rf \ + patch=2.7.6-7 \ + && ( \ + ( \ + [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \ + apt-get install -y --no-install-recommends \ + build-essential=12.9 \ + python3-dev=3.11.2-1+b1 \ + zlib1g-dev=1:1.2.13.dfsg-1 \ + libjpeg-dev=1:2.1.5-2 \ + libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ + libssl-dev=3.0.13-1~deb12u1 \ + libffi-dev=3.4.4-1 \ + libopenjp2-7=2.5.0-2 \ + libtiff6=4.5.0-6+deb12u1 \ + cargo=0.66.0+ds1-1 \ + pkg-config=1.8.1-1 \ + gcc-arm-linux-gnueabihf=4:12.2.0-3 \ + ) \ + || [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \ + ) \ + && rm -rf \ /tmp/* \ /var/{cache,log}/* \ /var/lib/apt/lists/* From 3727342bce096a38d6f3d20d00aa89e7295c8c89 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 3 Jul 2024 20:14:27 +1200 Subject: [PATCH 2019/2607] Bump version to 2024.6.6 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5b441faa6c..0d79908226 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.6.5" +__version__ = "2024.6.6" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From de19588d10a3350ae2625e490387dbccd6048677 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:22:06 +1200 Subject: [PATCH 2020/2607] Bump docker/setup-buildx-action from 3.3.0 to 3.4.0 (#7043) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 421a885f74..59b58ad82c 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.3.0 + uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU uses: docker/setup-qemu-action@v3.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1942e8cac..70b88bfd71 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,7 +90,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.3.0 + uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.0.0 @@ -184,7 +184,7 @@ jobs: merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.3.0 + uses: docker/setup-buildx-action@v3.4.0 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From 803f3f2e13cc27470113a23708558a1bd7b934b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:31:50 +1200 Subject: [PATCH 2021/2607] Bump docker/build-push-action from 6.2.0 to 6.3.0 in /.github/actions/build-image (#7038) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index b038a285ef..d5baf339aa 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.2.0 + uses: docker/build-push-action@v6.3.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.2.0 + uses: docker/build-push-action@v6.3.0 with: context: . file: ./docker/Dockerfile From 5fa54b0885e3c55f2afb518b2b4fbbad50dd10b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:27:46 +1200 Subject: [PATCH 2022/2607] Bump docker/setup-qemu-action from 3.0.0 to 3.1.0 (#7039) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 59b58ad82c..147efe089e 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -48,7 +48,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.0.0 + uses: docker/setup-qemu-action@v3.1.0 - name: Set TAG run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 70b88bfd71..71a366d535 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,7 +93,7 @@ jobs: uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' - uses: docker/setup-qemu-action@v3.0.0 + uses: docker/setup-qemu-action@v3.1.0 - name: Log in to docker hub uses: docker/login-action@v3.2.0 From b0a3b5e080d457708decc70b35abd0aad7ca3b69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:23:37 +1200 Subject: [PATCH 2023/2607] Bump actions/upload-artifact from 4.3.3 to 4.3.4 (#7047) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71a366d535..83641d8aa5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,7 +141,7 @@ jobs: echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT - name: Upload digests - uses: actions/upload-artifact@v4.3.3 + uses: actions/upload-artifact@v4.3.4 with: name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests From 6ca7b30f7514572dec8019f9335c1ea3ce73db1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:23:47 +1200 Subject: [PATCH 2024/2607] Bump actions/download-artifact from 4.1.7 to 4.1.8 (#7046) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 83641d8aa5..f66c504bda 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -177,7 +177,7 @@ jobs: - uses: actions/checkout@v4.1.7 - name: Download digests - uses: actions/download-artifact@v4.1.7 + uses: actions/download-artifact@v4.1.8 with: pattern: digests-* path: /tmp/digests From dd1e480142ad378e4e93b82fd435da70635de2c4 Mon Sep 17 00:00:00 2001 From: leejoow Date: Sat, 6 Jul 2024 06:57:30 +0200 Subject: [PATCH 2025/2607] Fix display of update state in webinterfae (#7045) Co-authored-by: Leo Schelvis --- .../http_request/update/http_request_update.cpp | 13 ++++++------- .../http_request/update/http_request_update.h | 3 --- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index 98129e59dc..0a14dfd933 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -116,19 +116,18 @@ void HttpRequestUpdate::update() { } } - std::string current_version = this->current_version_; - if (current_version.empty()) { + std::string current_version; #ifdef ESPHOME_PROJECT_VERSION - current_version = ESPHOME_PROJECT_VERSION; + current_version = ESPHOME_PROJECT_VERSION; #else - current_version = ESPHOME_VERSION; + current_version = ESPHOME_VERSION; #endif - } + this->update_info_.current_version = current_version; - if (this->update_info_.latest_version.empty()) { + if (this->update_info_.latest_version.empty() || this->update_info_.latest_version == update_info_.current_version) { this->state_ = update::UPDATE_STATE_NO_UPDATE; - } else if (this->update_info_.latest_version != this->current_version_) { + } else { this->state_ = update::UPDATE_STATE_AVAILABLE; } diff --git a/esphome/components/http_request/update/http_request_update.h b/esphome/components/http_request/update/http_request_update.h index 1337822ecc..a6bc97392b 100644 --- a/esphome/components/http_request/update/http_request_update.h +++ b/esphome/components/http_request/update/http_request_update.h @@ -22,15 +22,12 @@ class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent { void set_request_parent(HttpRequestComponent *request_parent) { this->request_parent_ = request_parent; } void set_ota_parent(OtaHttpRequestComponent *ota_parent) { this->ota_parent_ = ota_parent; } - void set_current_version(const std::string ¤t_version) { this->current_version_ = current_version; } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } protected: HttpRequestComponent *request_parent_; OtaHttpRequestComponent *ota_parent_; std::string source_url_; - std::string current_version_{""}; }; } // namespace http_request From ddaa84683be70cba79a1dcc191eec23f59a4f973 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Sat, 6 Jul 2024 09:00:44 +0200 Subject: [PATCH 2026/2607] Haier component update to support more protocol variations (#7040) Co-authored-by: Pavlo Dudnytskyi --- esphome/components/haier/climate.py | 41 ++++- esphome/components/haier/haier_base.cpp | 4 + esphome/components/haier/haier_base.h | 12 +- esphome/components/haier/hon_climate.cpp | 164 ++++++++++++------ esphome/components/haier/hon_climate.h | 8 +- esphome/components/haier/hon_packet.h | 5 + .../components/haier/smartair2_climate.cpp | 1 + platformio.ini | 2 +- tests/components/haier/common.yaml | 114 ++++++++++++ tests/components/haier/test.esp32-ard.yaml | 116 +------------ tests/components/haier/test.esp32-c3-ard.yaml | 112 +----------- tests/components/haier/test.esp32-c3-idf.yaml | 112 +----------- tests/components/haier/test.esp32-idf.yaml | 112 +----------- tests/components/haier/test.esp8266-ard.yaml | 112 +----------- tests/components/haier/test.rp2040-ard.yaml | 112 +----------- 15 files changed, 316 insertions(+), 711 deletions(-) create mode 100644 tests/components/haier/common.yaml diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index 3dcb35708c..f7423a1356 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -38,6 +38,9 @@ PROTOCOL_MAX_TEMPERATURE = 30.0 PROTOCOL_TARGET_TEMPERATURE_STEP = 1.0 PROTOCOL_CURRENT_TEMPERATURE_STEP = 0.5 PROTOCOL_CONTROL_PACKET_SIZE = 10 +PROTOCOL_MIN_SENSORS_PACKET_SIZE = 18 +PROTOCOL_DEFAULT_SENSORS_PACKET_SIZE = 22 +PROTOCOL_STATUS_MESSAGE_HEADER_SIZE = 0 CODEOWNERS = ["@paveldn"] DEPENDENCIES = ["climate", "uart"] @@ -48,6 +51,9 @@ CONF_CONTROL_PACKET_SIZE = "control_packet_size" CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow" CONF_ON_ALARM_START = "on_alarm_start" CONF_ON_ALARM_END = "on_alarm_end" +CONF_ON_STATUS_MESSAGE = "on_status_message" +CONF_SENSORS_PACKET_SIZE = "sensors_packet_size" +CONF_STATUS_MESSAGE_HEADER_SIZE = "status_message_header_size" CONF_VERTICAL_AIRFLOW = "vertical_airflow" CONF_WIFI_SIGNAL = "wifi_signal" @@ -129,6 +135,11 @@ HaierAlarmEndTrigger = haier_ns.class_( automation.Trigger.template(cg.uint8, cg.const_char_ptr), ) +StatusMessageTrigger = haier_ns.class_( + "StatusMessageTrigger", + automation.Trigger.template(cg.const_char_ptr, cg.size_t), +) + def validate_visual(config): if CONF_VISUAL in config: @@ -193,6 +204,11 @@ BASE_CONFIG_SCHEMA = ( cv.Optional( CONF_ANSWER_TIMEOUT, ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_ON_STATUS_MESSAGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StatusMessageTrigger), + } + ), } ) .extend(uart.UART_DEVICE_SCHEMA) @@ -228,6 +244,14 @@ CONFIG_SCHEMA = cv.All( cv.Optional( CONF_CONTROL_PACKET_SIZE, default=PROTOCOL_CONTROL_PACKET_SIZE ): cv.int_range(min=PROTOCOL_CONTROL_PACKET_SIZE, max=50), + cv.Optional( + CONF_SENSORS_PACKET_SIZE, + default=PROTOCOL_DEFAULT_SENSORS_PACKET_SIZE, + ): cv.int_range(min=PROTOCOL_MIN_SENSORS_PACKET_SIZE, max=50), + cv.Optional( + CONF_STATUS_MESSAGE_HEADER_SIZE, + default=PROTOCOL_STATUS_MESSAGE_HEADER_SIZE, + ): cv.int_range(min=PROTOCOL_STATUS_MESSAGE_HEADER_SIZE), cv.Optional( CONF_SUPPORTED_PRESETS, default=["BOOST", "ECO", "SLEEP"], # No AWAY by default @@ -468,6 +492,16 @@ async def to_code(config): config[CONF_CONTROL_PACKET_SIZE] - PROTOCOL_CONTROL_PACKET_SIZE ) ) + if CONF_SENSORS_PACKET_SIZE in config: + cg.add( + var.set_extra_sensors_packet_bytes_size( + config[CONF_SENSORS_PACKET_SIZE] - PROTOCOL_MIN_SENSORS_PACKET_SIZE + ) + ) + if CONF_STATUS_MESSAGE_HEADER_SIZE in config: + cg.add( + var.set_status_message_header_size(config[CONF_STATUS_MESSAGE_HEADER_SIZE]) + ) for conf in config.get(CONF_ON_ALARM_START, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation( @@ -478,5 +512,10 @@ async def to_code(config): await automation.build_automation( trigger, [(cg.uint8, "code"), (cg.const_char_ptr, "message")], conf ) + for conf in config.get(CONF_ON_STATUS_MESSAGE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation( + trigger, [(cg.const_char_ptr, "data"), (cg.size_t, "data_size")], conf + ) # https://github.com/paveldn/HaierProtocol - cg.add_library("pavlodn/HaierProtocol", "0.9.28") + cg.add_library("pavlodn/HaierProtocol", "0.9.31") diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index 1fca3dfb85..0bd3863160 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -186,6 +186,10 @@ void HaierClimateBase::send_custom_command(const haier_protocol::HaierMessage &m this->action_request_ = PendingAction({ActionRequest::SEND_CUSTOM_COMMAND, message}); } +void HaierClimateBase::add_status_message_callback(std::function &&callback) { + this->status_message_callback_.add(std::move(callback)); +} + haier_protocol::HandlerError HaierClimateBase::answer_preprocess_( haier_protocol::FrameType request_message_type, haier_protocol::FrameType expected_request_message_type, haier_protocol::FrameType answer_message_type, haier_protocol::FrameType expected_answer_message_type, diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index f261a106a2..c0bf878519 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -4,6 +4,7 @@ #include #include "esphome/components/climate/climate.h" #include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" // HaierProtocol #include @@ -56,6 +57,7 @@ class HaierClimateBase : public esphome::Component, void set_answer_timeout(uint32_t timeout); void set_send_wifi(bool send_wifi); void send_custom_command(const haier_protocol::HaierMessage &message); + void add_status_message_callback(std::function &&callback); protected: enum class ProtocolPhases { @@ -140,11 +142,19 @@ class HaierClimateBase : public esphome::Component, esphome::climate::ClimateTraits traits_; HvacSettings current_hvac_settings_; HvacSettings next_hvac_settings_; - std::unique_ptr last_status_message_; + std::unique_ptr last_status_message_{nullptr}; std::chrono::steady_clock::time_point last_request_timestamp_; // For interval between messages std::chrono::steady_clock::time_point last_valid_status_timestamp_; // For protocol timeout std::chrono::steady_clock::time_point last_status_request_; // To request AC status std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level + CallbackManager status_message_callback_{}; +}; + +class StatusMessageTrigger : public Trigger { + public: + explicit StatusMessageTrigger(HaierClimateBase *parent) { + parent->add_status_message_callback([this](const char *data, size_t data_size) { this->trigger(data, data_size); }); + } }; } // namespace haier diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 903f7964da..a1c5098cec 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -18,12 +18,13 @@ constexpr int PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET = -64; constexpr uint8_t CONTROL_MESSAGE_RETRIES = 5; constexpr std::chrono::milliseconds CONTROL_MESSAGE_RETRIES_INTERVAL = std::chrono::milliseconds(500); constexpr size_t ALARM_STATUS_REQUEST_INTERVAL_MS = 600000; +const uint8_t ONE_BUF[] = {0x00, 0x01}; +const uint8_t ZERO_BUF[] = {0x00, 0x00}; HonClimate::HonClimate() : cleaning_status_(CleaningState::NO_CLEANING), got_valid_outdoor_temp_(false), active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} { - last_status_message_ = std::unique_ptr(new uint8_t[sizeof(hon_protocol::HaierPacketControl)]); this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID; this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO; } @@ -169,11 +170,18 @@ haier_protocol::HandlerError HonClimate::status_handler_(haier_protocol::FrameTy this->action_request_.reset(); this->force_send_control_ = false; } else { - if (data_size >= sizeof(hon_protocol::HaierPacketControl) + 2) { - memcpy(this->last_status_message_.get(), data + 2, sizeof(hon_protocol::HaierPacketControl)); + if (!this->last_status_message_) { + this->real_control_packet_size_ = sizeof(hon_protocol::HaierPacketControl) + this->extra_control_packet_bytes_; + this->real_sensors_packet_size_ = sizeof(hon_protocol::HaierPacketSensors) + this->extra_sensors_packet_bytes_; + this->last_status_message_.reset(); + this->last_status_message_ = std::unique_ptr(new uint8_t[this->real_control_packet_size_]); + }; + if (data_size >= this->real_control_packet_size_ + 2) { + memcpy(this->last_status_message_.get(), data + 2 + this->status_message_header_size_, + this->real_control_packet_size_); + this->status_message_callback_.call((const char *) data, data_size); } else { - ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, - sizeof(hon_protocol::HaierPacketControl)); + ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, this->real_control_packet_size_); } switch (this->protocol_phase_) { case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST: @@ -479,8 +487,8 @@ void HonClimate::initialization() { } haier_protocol::HaierMessage HonClimate::get_control_message() { - uint8_t control_out_buffer[sizeof(hon_protocol::HaierPacketControl)]; - memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(hon_protocol::HaierPacketControl)); + uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE]; + memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_); hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; control_out_buffer[4] = 0; // This byte should be cleared before setting values bool has_hvac_settings = false; @@ -636,7 +644,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { out_data->health_mode = this->health_mode_ ? 1 : 0; return haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, - control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); + control_out_buffer, this->real_control_packet_size_); } void HonClimate::process_alarm_message_(const uint8_t *packet, uint8_t size, bool check_new) { @@ -758,15 +766,17 @@ void HonClimate::update_sub_text_sensor_(SubTextSensorType type, const std::stri #endif // USE_TEXT_SENSOR haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { - size_t expected_size = 2 + sizeof(hon_protocol::HaierPacketControl) + sizeof(hon_protocol::HaierPacketSensors) + - this->extra_control_packet_bytes_; - if (size < expected_size) + size_t expected_size = + 2 + this->status_message_header_size_ + this->real_control_packet_size_ + this->real_sensors_packet_size_; + if (size < expected_size) { + ESP_LOGW(TAG, "Unexpected message size %d (expexted >= %d)", size, expected_size); return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; + } uint16_t subtype = (((uint16_t) packet_buffer[0]) << 8) + packet_buffer[1]; - if ((subtype == 0x7D01) && (size >= expected_size + 4 + sizeof(hon_protocol::HaierPacketBigData))) { + if ((subtype == 0x7D01) && (size >= expected_size + sizeof(hon_protocol::HaierPacketBigData))) { // Got BigData packet const hon_protocol::HaierPacketBigData *bd_packet = - (const hon_protocol::HaierPacketBigData *) (&packet_buffer[expected_size + 4]); + (const hon_protocol::HaierPacketBigData *) (&packet_buffer[expected_size]); #ifdef USE_SENSOR this->update_sub_sensor_(SubSensorType::INDOOR_COIL_TEMPERATURE, bd_packet->indoor_coil_temperature / 2.0 - 20); this->update_sub_sensor_(SubSensorType::OUTDOOR_COIL_TEMPERATURE, bd_packet->outdoor_coil_temperature - 64); @@ -795,9 +805,9 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * hon_protocol::HaierPacketControl control; hon_protocol::HaierPacketSensors sensors; } packet; - memcpy(&packet.control, packet_buffer + 2, sizeof(hon_protocol::HaierPacketControl)); - memcpy(&packet.sensors, - packet_buffer + 2 + sizeof(hon_protocol::HaierPacketControl) + this->extra_control_packet_bytes_, + memcpy(&packet.control, packet_buffer + 2 + this->status_message_header_size_, + sizeof(hon_protocol::HaierPacketControl)); + memcpy(&packet.sensors, packet_buffer + 2 + this->status_message_header_size_ + this->real_control_packet_size_, sizeof(hon_protocol::HaierPacketSensors)); if (packet.sensors.error_status != 0) { ESP_LOGW(TAG, "HVAC error, code=0x%02X", packet.sensors.error_status); @@ -996,8 +1006,6 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * } void HonClimate::fill_control_messages_queue_() { - static uint8_t one_buf[] = {0x00, 0x01}; - static uint8_t zero_buf[] = {0x00, 0x00}; if (!this->current_hvac_settings_.valid && !this->force_send_control_) return; this->clear_control_messages_queue_(); @@ -1009,7 +1017,7 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::BEEPER_STATUS, - this->beeper_status_ ? zero_buf : one_buf, 2)); + this->beeper_status_ ? ZERO_BUF : ONE_BUF, 2)); } // Health mode { @@ -1017,7 +1025,7 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::HEALTH_MODE, - this->health_mode_ ? one_buf : zero_buf, 2)); + this->health_mode_ ? ONE_BUF : ZERO_BUF, 2)); } // Climate mode bool new_power = this->mode != CLIMATE_MODE_OFF; @@ -1092,7 +1100,7 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::AC_POWER, - new_power ? one_buf : zero_buf, 2)); + new_power ? ONE_BUF : ZERO_BUF, 2)); } // CLimate preset { @@ -1165,6 +1173,35 @@ void HonClimate::fill_control_messages_queue_() { (uint8_t) hon_protocol::DataParameters::SET_POINT, buffer, 2)); } + // Vertical swing mode + if (climate_control.swing_mode.has_value()) { + uint8_t vertical_swing_buf[] = {0x00, (uint8_t) hon_protocol::VerticalSwingMode::AUTO}; + uint8_t horizontal_swing_buf[] = {0x00, (uint8_t) hon_protocol::HorizontalSwingMode::AUTO}; + switch (climate_control.swing_mode.value()) { + case CLIMATE_SWING_OFF: + horizontal_swing_buf[1] = (uint8_t) this->settings_.last_horizontal_swing; + vertical_swing_buf[1] = (uint8_t) this->settings_.last_vertiacal_swing; + break; + case CLIMATE_SWING_VERTICAL: + horizontal_swing_buf[1] = (uint8_t) this->settings_.last_horizontal_swing; + break; + case CLIMATE_SWING_HORIZONTAL: + vertical_swing_buf[1] = (uint8_t) this->settings_.last_vertiacal_swing; + break; + case CLIMATE_SWING_BOTH: + break; + } + this->control_messages_queue_.push( + haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE, + horizontal_swing_buf, 2)); + this->control_messages_queue_.push( + haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE, + vertical_swing_buf, 2)); + } // Fan mode if (climate_control.fan_mode.has_value()) { switch (climate_control.fan_mode.value()) { @@ -1202,40 +1239,56 @@ void HonClimate::clear_control_messages_queue_() { bool HonClimate::prepare_pending_action() { switch (this->action_request_.value().action) { - case ActionRequest::START_SELF_CLEAN: { - uint8_t control_out_buffer[sizeof(hon_protocol::HaierPacketControl)]; - memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(hon_protocol::HaierPacketControl)); - hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; - out_data->self_cleaning_status = 1; - out_data->steri_clean = 0; - out_data->set_point = 0x06; - out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; - out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; - out_data->ac_power = 1; - out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; - out_data->light_status = 0; - this->action_request_.value().message = haier_protocol::HaierMessage( - haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, - control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); - } - return true; - case ActionRequest::START_STERI_CLEAN: { - uint8_t control_out_buffer[sizeof(hon_protocol::HaierPacketControl)]; - memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(hon_protocol::HaierPacketControl)); - hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; - out_data->self_cleaning_status = 0; - out_data->steri_clean = 1; - out_data->set_point = 0x06; - out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; - out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; - out_data->ac_power = 1; - out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; - out_data->light_status = 0; - this->action_request_.value().message = haier_protocol::HaierMessage( - haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, - control_out_buffer, sizeof(hon_protocol::HaierPacketControl)); - } - return true; + case ActionRequest::START_SELF_CLEAN: + if (this->control_method_ == HonControlMethod::SET_GROUP_PARAMETERS) { + uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE]; + memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_); + hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; + out_data->self_cleaning_status = 1; + out_data->steri_clean = 0; + out_data->set_point = 0x06; + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; + out_data->light_status = 0; + this->action_request_.value().message = haier_protocol::HaierMessage( + haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, + control_out_buffer, this->real_control_packet_size_); + return true; + } else if (this->control_method_ == HonControlMethod::SET_SINGLE_PARAMETER) { + this->action_request_.value().message = + haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::SELF_CLEANING, + ONE_BUF, 2); + return true; + } else { + this->action_request_.reset(); + return false; + } + case ActionRequest::START_STERI_CLEAN: + if (this->control_method_ == HonControlMethod::SET_GROUP_PARAMETERS) { + uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE]; + memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_); + hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer; + out_data->self_cleaning_status = 0; + out_data->steri_clean = 1; + out_data->set_point = 0x06; + out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER; + out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER; + out_data->ac_power = 1; + out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY; + out_data->light_status = 0; + this->action_request_.value().message = haier_protocol::HaierMessage( + haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, + control_out_buffer, this->real_control_packet_size_); + return true; + } else { + // No Steri clean support (yet?) in SET_SINGLE_PARAMETER + this->action_request_.reset(); + return false; + } default: return HaierClimateBase::prepare_pending_action(); } @@ -1251,6 +1304,7 @@ void HonClimate::process_protocol_reset() { #endif // USE_SENSOR this->got_valid_outdoor_temp_ = false; this->hvac_hardware_info_.reset(); + this->last_status_message_.reset(nullptr); } bool HonClimate::should_get_big_data_() { diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index 7b4fcee6b9..64c54186ed 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -104,6 +104,8 @@ class HonClimate : public HaierClimateBase { void start_self_cleaning(); void start_steri_cleaning(); void set_extra_control_packet_bytes_size(size_t size) { this->extra_control_packet_bytes_ = size; }; + void set_extra_sensors_packet_bytes_size(size_t size) { this->extra_sensors_packet_bytes_ = size; }; + void set_status_message_header_size(size_t size) { this->status_message_header_size_ = size; }; void set_control_method(HonControlMethod method) { this->control_method_ = method; }; void add_alarm_start_callback(std::function &&callback); void add_alarm_end_callback(std::function &&callback); @@ -158,7 +160,11 @@ class HonClimate : public HaierClimateBase { esphome::optional pending_horizontal_direction_{}; esphome::optional hvac_hardware_info_{}; uint8_t active_alarms_[8]; - int extra_control_packet_bytes_; + int extra_control_packet_bytes_{0}; + int extra_sensors_packet_bytes_{4}; + int status_message_header_size_{0}; + int real_control_packet_size_{sizeof(hon_protocol::HaierPacketControl)}; + int real_sensors_packet_size_{sizeof(hon_protocol::HaierPacketSensors) + 4}; HonControlMethod control_method_; std::queue control_messages_queue_; CallbackManager alarm_start_callback_{}; diff --git a/esphome/components/haier/hon_packet.h b/esphome/components/haier/hon_packet.h index a03ac2831f..615f93528e 100644 --- a/esphome/components/haier/hon_packet.h +++ b/esphome/components/haier/hon_packet.h @@ -41,15 +41,20 @@ enum class ConditioningMode : uint8_t { enum class DataParameters : uint8_t { AC_POWER = 0x01, SET_POINT = 0x02, + VERTICAL_SWING_MODE = 0x03, AC_MODE = 0x04, FAN_MODE = 0x05, USE_FAHRENHEIT = 0x07, + DISPLAY_STATUS = 0x09, TEN_DEGREE = 0x0A, HEALTH_MODE = 0x0B, + HORIZONTAL_SWING_MODE = 0x0C, + SELF_CLEANING = 0x0D, BEEPER_STATUS = 0x16, LOCK_REMOTE = 0x17, QUIET_MODE = 0x19, FAST_MODE = 0x1A, + SLEEP_MODE = 0x1B, }; enum class SpecialMode : uint8_t { NONE = 0x00, ELDERLY = 0x01, CHILDREN = 0x02, PREGNANT = 0x03 }; diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 00590694d5..028e8a4087 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -37,6 +37,7 @@ haier_protocol::HandlerError Smartair2Climate::status_handler_(haier_protocol::F } else { if (data_size >= sizeof(smartair2_protocol::HaierPacketControl) + 2) { memcpy(this->last_status_message_.get(), data + 2, sizeof(smartair2_protocol::HaierPacketControl)); + this->status_message_callback_.call((const char *) data, data_size); } else { ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, sizeof(smartair2_protocol::HaierPacketControl)); diff --git a/platformio.ini b/platformio.ini index aa73437222..a72bf598c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,7 +39,7 @@ lib_deps = bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 - pavlodn/HaierProtocol@0.9.28 ; haier + pavlodn/HaierProtocol@0.9.31 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library build_flags = diff --git a/tests/components/haier/common.yaml b/tests/components/haier/common.yaml new file mode 100644 index 0000000000..b8a23bac5a --- /dev/null +++ b/tests/components/haier/common.yaml @@ -0,0 +1,114 @@ +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_haier + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + baud_rate: 9600 + +climate: + - platform: haier + id: haier_ac + uart_id: uart_haier + protocol: hOn + name: Haier AC + wifi_signal: true + answer_timeout: 200ms + beeper: true + visual: + min_temperature: 16 °C + max_temperature: 30 °C + temperature_step: + target_temperature: 1 + current_temperature: 0.5 + supported_modes: + - 'OFF' + - HEAT_COOL + - COOL + - HEAT + - DRY + - FAN_ONLY + supported_swing_modes: + - 'OFF' + - VERTICAL + - HORIZONTAL + - BOTH + supported_presets: + - AWAY + - BOOST + - ECO + - SLEEP + on_alarm_start: + then: + - logger.log: + level: DEBUG + format: "Alarm activated. Code: %d. Message: \"%s\"" + args: [code, message] + on_alarm_end: + then: + - logger.log: + level: DEBUG + format: "Alarm deactivated. Code: %d. Message: \"%s\"" + args: [code, message] + +sensor: + - platform: haier + haier_id: haier_ac + outdoor_temperature: + name: Haier outdoor temperature + humidity: + name: Haier Indoor Humidity + compressor_current: + name: Haier Compressor Current + compressor_frequency: + name: Haier Compressor Frequency + expansion_valve_open_degree: + name: Haier Expansion Valve Open Degree + indoor_coil_temperature: + name: Haier Indoor Coil Temperature + outdoor_coil_temperature: + name: Haier Outdoor Coil Temperature + outdoor_defrost_temperature: + name: Haier Outdoor Defrost Temperature + outdoor_in_air_temperature: + name: Haier Outdoor In Air Temperature + outdoor_out_air_temperature: + name: Haier Outdoor Out Air Temperature + power: + name: Haier Power + +binary_sensor: + - platform: haier + haier_id: haier_ac + compressor_status: + name: Haier Outdoor Compressor Status + defrost_status: + name: Haier Defrost Status + four_way_valve_status: + name: Haier Four Way Valve Status + indoor_electric_heating_status: + name: Haier Indoor Electric Heating Status + indoor_fan_status: + name: Haier Indoor Fan Status + outdoor_fan_status: + name: Haier Outdoor Fan Status + +button: + - platform: haier + haier_id: haier_ac + self_cleaning: + name: Haier start self cleaning + steri_cleaning: + name: Haier start 56°C steri-cleaning + +text_sensor: + - platform: haier + haier_id: haier_ac + appliance_name: + name: Haier appliance name + cleaning_status: + name: Haier cleaning status + protocol_version: + name: Haier protocol version diff --git a/tests/components/haier/test.esp32-ard.yaml b/tests/components/haier/test.esp32-ard.yaml index efff532d25..f486544afa 100644 --- a/tests/components/haier/test.esp32-ard.yaml +++ b/tests/components/haier/test.esp32-ard.yaml @@ -1,113 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -uart: - - id: uart_haier - tx_pin: 17 - rx_pin: 16 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - haier_id: haier_ac - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - haier_id: haier_ac - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - haier_id: haier_ac - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - haier_id: haier_ac - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml diff --git a/tests/components/haier/test.esp32-c3-ard.yaml b/tests/components/haier/test.esp32-c3-ard.yaml index 0053220669..b516342f3b 100644 --- a/tests/components/haier/test.esp32-c3-ard.yaml +++ b/tests/components/haier/test.esp32-c3-ard.yaml @@ -1,109 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_haier - tx_pin: 4 - rx_pin: 5 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml diff --git a/tests/components/haier/test.esp32-c3-idf.yaml b/tests/components/haier/test.esp32-c3-idf.yaml index 0053220669..b516342f3b 100644 --- a/tests/components/haier/test.esp32-c3-idf.yaml +++ b/tests/components/haier/test.esp32-c3-idf.yaml @@ -1,109 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_haier - tx_pin: 4 - rx_pin: 5 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml diff --git a/tests/components/haier/test.esp32-idf.yaml b/tests/components/haier/test.esp32-idf.yaml index 54e384f3ce..f486544afa 100644 --- a/tests/components/haier/test.esp32-idf.yaml +++ b/tests/components/haier/test.esp32-idf.yaml @@ -1,109 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -uart: - - id: uart_haier - tx_pin: 17 - rx_pin: 16 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml diff --git a/tests/components/haier/test.esp8266-ard.yaml b/tests/components/haier/test.esp8266-ard.yaml index 0053220669..b516342f3b 100644 --- a/tests/components/haier/test.esp8266-ard.yaml +++ b/tests/components/haier/test.esp8266-ard.yaml @@ -1,109 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_haier - tx_pin: 4 - rx_pin: 5 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml diff --git a/tests/components/haier/test.rp2040-ard.yaml b/tests/components/haier/test.rp2040-ard.yaml index 0053220669..b516342f3b 100644 --- a/tests/components/haier/test.rp2040-ard.yaml +++ b/tests/components/haier/test.rp2040-ard.yaml @@ -1,109 +1,5 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_haier - tx_pin: 4 - rx_pin: 5 - baud_rate: 9600 - -climate: - - platform: haier - id: haier_ac - protocol: hOn - name: Haier AC - wifi_signal: true - answer_timeout: 200ms - beeper: true - visual: - min_temperature: 16 °C - max_temperature: 30 °C - temperature_step: - target_temperature: 1 - current_temperature: 0.5 - supported_modes: - - 'OFF' - - HEAT_COOL - - COOL - - HEAT - - DRY - - FAN_ONLY - supported_swing_modes: - - 'OFF' - - VERTICAL - - HORIZONTAL - - BOTH - supported_presets: - - AWAY - - BOOST - - ECO - - SLEEP - on_alarm_start: - then: - - logger.log: - level: DEBUG - format: "Alarm activated. Code: %d. Message: \"%s\"" - args: [code, message] - on_alarm_end: - then: - - logger.log: - level: DEBUG - format: "Alarm deactivated. Code: %d. Message: \"%s\"" - args: [code, message] - -sensor: - - platform: haier - outdoor_temperature: - name: Haier outdoor temperature - humidity: - name: Haier Indoor Humidity - compressor_current: - name: Haier Compressor Current - compressor_frequency: - name: Haier Compressor Frequency - expansion_valve_open_degree: - name: Haier Expansion Valve Open Degree - indoor_coil_temperature: - name: Haier Indoor Coil Temperature - outdoor_coil_temperature: - name: Haier Outdoor Coil Temperature - outdoor_defrost_temperature: - name: Haier Outdoor Defrost Temperature - outdoor_in_air_temperature: - name: Haier Outdoor In Air Temperature - outdoor_out_air_temperature: - name: Haier Outdoor Out Air Temperature - power: - name: Haier Power - -binary_sensor: - - platform: haier - compressor_status: - name: Haier Outdoor Compressor Status - defrost_status: - name: Haier Defrost Status - four_way_valve_status: - name: Haier Four Way Valve Status - indoor_electric_heating_status: - name: Haier Indoor Electric Heating Status - indoor_fan_status: - name: Haier Indoor Fan Status - outdoor_fan_status: - name: Haier Outdoor Fan Status - -button: - - platform: haier - self_cleaning: - name: Haier start self cleaning - steri_cleaning: - name: Haier start 56°C steri-cleaning - -text_sensor: - - platform: haier - appliance_name: - name: Haier appliance name - cleaning_status: - name: Haier cleaning status - protocol_version: - name: Haier protocol version +<<: !include common.yaml From 4c6a17e304002b741388335db30c06725a6730c6 Mon Sep 17 00:00:00 2001 From: Colm Date: Sat, 6 Jul 2024 08:02:41 +0100 Subject: [PATCH 2027/2607] Don't test for IPv6 addresses when min_ipv6_addr_count is 0 (#7037) --- esphome/components/wifi/wifi_component_esp_idf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index c21486fee4..96fa837767 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -757,7 +757,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { if (s_sta_connected && this->got_ipv4_address_) { -#if USE_NETWORK_IPV6 +#if USE_NETWORK_IPV6 && (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0) if (this->num_ipv6_addresses_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT) { return WiFiSTAConnectStatus::CONNECTED; } From 894d81c57767444425c15e340fec292b3341aacb Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 9 Jul 2024 04:07:54 +0200 Subject: [PATCH 2028/2607] [CI] Allow running specific target test(s) only (#7051) --- script/test_build_components | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/script/test_build_components b/script/test_build_components index 9bbb694dcc..e885294b99 100755 --- a/script/test_build_components +++ b/script/test_build_components @@ -7,12 +7,13 @@ set -e # - `c` - Component folder name to test. Default `*`. esphome_command="compile" target_component="*" -while getopts e:c: flag +while getopts e:c:t: flag do case $flag in e) esphome_command=${OPTARG};; c) target_component=${OPTARG};; - \?) echo "Usage: $0 [-e ] [-c ]" 1>&2; exit 1;; + t) requested_target_platform=${OPTARG};; + \?) echo "Usage: $0 [-e ] [-c ] [-t ]" 1>&2; exit 1;; esac done @@ -23,6 +24,10 @@ if ! [ -d "./tests/test_build_components/build" ]; then fi start_esphome() { + if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform" ]; then + echo "Skiping $target_platform" + return + fi # create dynamic yaml file in `build` folder. # `./tests/test_build_components/build/[target_component].[test_name].[target_platform_with_version].yaml` component_test_file="./tests/test_build_components/build/$target_component.$test_name.$target_platform_with_version.yaml" From ee398441b664722d9af67699035af5fd38b6ab28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 23:21:11 +0200 Subject: [PATCH 2029/2607] Bump actions/setup-python from 5.1.0 to 5.1.1 in /.github/actions/restore-python (#7071) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 4ad9e2eaed..d3fe2a89dc 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -17,7 +17,7 @@ runs: steps: - name: Set up Python ${{ inputs.python-version }} id: python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.1.1 with: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment From 2da939c81c1ec506eb96010a101e6263060f9a1c Mon Sep 17 00:00:00 2001 From: MichD Date: Wed, 10 Jul 2024 23:37:50 +0100 Subject: [PATCH 2030/2607] Fix RC Switch protocol not transmitting correctly via IR (#5411) --- esphome/components/remote_base/rc_switch_protocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/remote_base/rc_switch_protocol.cpp b/esphome/components/remote_base/rc_switch_protocol.cpp index 1f38fdca67..cb8a077975 100644 --- a/esphome/components/remote_base/rc_switch_protocol.cpp +++ b/esphome/components/remote_base/rc_switch_protocol.cpp @@ -54,7 +54,7 @@ void RCSwitchBase::sync(RemoteTransmitData *dst) const { } } void RCSwitchBase::transmit(RemoteTransmitData *dst, uint64_t code, uint8_t len) const { - dst->set_carrier_frequency(0); + dst->set_carrier_frequency(38000); this->sync(dst); for (int16_t i = len - 1; i >= 0; i--) { if (code & ((uint64_t) 1 << i)) { From 2873c6bbaffc22383f870dc5203f4246279c709e Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 10 Jul 2024 21:21:04 -0400 Subject: [PATCH 2031/2607] [micro_wake_word] Version 2 (#7032) --- .../components/micro_wake_word/__init__.py | 262 +++++++-- .../audio_preprocessor_int8_model_data.h | 493 ----------------- .../micro_wake_word/micro_wake_word.cpp | 522 ++++++++---------- .../micro_wake_word/micro_wake_word.h | 190 +++---- .../micro_wake_word/preprocessor_settings.h | 20 + .../micro_wake_word/streaming_model.cpp | 189 +++++++ .../micro_wake_word/streaming_model.h | 84 +++ esphome/core/defines.h | 1 + platformio.ini | 3 +- tests/components/micro_wake_word/common.yaml | 6 +- .../micro_wake_word/test.esp32-idf.yaml | 1 + 11 files changed, 822 insertions(+), 949 deletions(-) delete mode 100644 esphome/components/micro_wake_word/audio_preprocessor_int8_model_data.h create mode 100644 esphome/components/micro_wake_word/preprocessor_settings.h create mode 100644 esphome/components/micro_wake_word/streaming_model.cpp create mode 100644 esphome/components/micro_wake_word/streaming_model.h create mode 100644 tests/components/micro_wake_word/test.esp32-idf.yaml diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 35ee3cfedc..3d3459ccab 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -9,7 +9,7 @@ import requests import esphome.config_validation as cv import esphome.codegen as cg -from esphome.core import CORE, HexInt, EsphomeError +from esphome.core import CORE, HexInt from esphome.components import esp32, microphone from esphome import automation, git, external_files @@ -41,9 +41,15 @@ CODEOWNERS = ["@kahrendt", "@jesserockz"] DEPENDENCIES = ["microphone"] DOMAIN = "micro_wake_word" + +CONF_FEATURE_STEP_SIZE = "feature_step_size" +CONF_MODELS = "models" +CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected" CONF_PROBABILITY_CUTOFF = "probability_cutoff" CONF_SLIDING_WINDOW_AVERAGE_SIZE = "sliding_window_average_size" -CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected" +CONF_SLIDING_WINDOW_SIZE = "sliding_window_size" +CONF_TENSOR_ARENA_SIZE = "tensor_arena_size" +CONF_VAD = "vad" TYPE_HTTP = "http" @@ -98,12 +104,14 @@ GIT_SCHEMA = cv.All( _process_git_source, ) -KEY_WAKE_WORD = "wake_word" + KEY_AUTHOR = "author" -KEY_WEBSITE = "website" -KEY_VERSION = "version" KEY_MICRO = "micro" KEY_MINIMUM_ESPHOME_VERSION = "minimum_esphome_version" +KEY_TRAINED_LANGUAGES = "trained_languages" +KEY_VERSION = "version" +KEY_WAKE_WORD = "wake_word" +KEY_WEBSITE = "website" MANIFEST_SCHEMA_V1 = cv.Schema( { @@ -125,6 +133,29 @@ MANIFEST_SCHEMA_V1 = cv.Schema( } ) +MANIFEST_SCHEMA_V2 = cv.Schema( + { + cv.Required(CONF_TYPE): "micro", + cv.Required(CONF_MODEL): cv.string, + cv.Required(KEY_AUTHOR): cv.string, + cv.Required(KEY_VERSION): cv.All(cv.int_, 2), + cv.Required(KEY_WAKE_WORD): cv.string, + cv.Required(KEY_TRAINED_LANGUAGES): cv.ensure_list(cv.string), + cv.Optional(KEY_WEBSITE): cv.url, + cv.Required(KEY_MICRO): cv.Schema( + { + cv.Required(CONF_FEATURE_STEP_SIZE): cv.int_range(min=0, max=30), + cv.Required(CONF_TENSOR_ARENA_SIZE): cv.int_, + cv.Required(CONF_PROBABILITY_CUTOFF): cv.float_, + cv.Required(CONF_SLIDING_WINDOW_SIZE): cv.positive_int, + cv.Required(KEY_MINIMUM_ESPHOME_VERSION): cv.All( + cv.version_number, cv.validate_esphome_version + ), + } + ), + } +) + def _compute_local_file_path(config: dict) -> Path: url = config[CONF_URL] @@ -135,6 +166,24 @@ def _compute_local_file_path(config: dict) -> Path: return base_dir / key +def _convert_manifest_v1_to_v2(v1_manifest): + v2_manifest = v1_manifest.copy() + + v2_manifest[KEY_VERSION] = 2 + v2_manifest[KEY_MICRO][CONF_SLIDING_WINDOW_SIZE] = v1_manifest[KEY_MICRO][ + CONF_SLIDING_WINDOW_AVERAGE_SIZE + ] + del v2_manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE] + v2_manifest[KEY_MICRO][ + CONF_TENSOR_ARENA_SIZE + ] = 45672 # Original Inception-based V1 manifest models require a minimum of 45672 bytes + v2_manifest[KEY_MICRO][ + CONF_FEATURE_STEP_SIZE + ] = 20 # Original Inception-based V1 manifest models use a 20 ms feature step size + + return v2_manifest + + def _download_file(url: str, path: Path) -> bytes: if not external_files.has_remote_file_changed(url, path): _LOGGER.debug("Remote file has not changed, skipping download") @@ -155,6 +204,24 @@ def _download_file(url: str, path: Path) -> bytes: return req.content +def _validate_manifest_version(manifest_data): + if manifest_version := manifest_data.get(KEY_VERSION): + if manifest_version == 1: + try: + MANIFEST_SCHEMA_V1(manifest_data) + except cv.Invalid as e: + raise cv.Invalid(f"Invalid manifest file: {e}") from e + elif manifest_version == 2: + try: + MANIFEST_SCHEMA_V2(manifest_data) + except cv.Invalid as e: + raise cv.Invalid(f"Invalid manifest file: {e}") from e + else: + raise cv.Invalid("Invalid manifest version") + else: + raise cv.Invalid("Invalid manifest file, missing 'version' key.") + + def _process_http_source(config): url = config[CONF_URL] path = _compute_local_file_path(config) @@ -167,11 +234,6 @@ def _process_http_source(config): if not isinstance(manifest_data, dict): raise cv.Invalid("Manifest file must contain a JSON object") - try: - MANIFEST_SCHEMA_V1(manifest_data) - except cv.Invalid as e: - raise cv.Invalid(f"Invalid manifest file: {e}") from e - model = manifest_data[CONF_MODEL] model_url = urljoin(url, model) @@ -206,7 +268,7 @@ def _validate_source_model_name(value): return MODEL_SOURCE_SCHEMA( { CONF_TYPE: TYPE_HTTP, - CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/{value}.json", + CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/v2/{value}.json", } ) @@ -260,18 +322,55 @@ MODEL_SOURCE_SCHEMA = cv.Any( msg="Not a valid model name, local path, http(s) url, or github shorthand", ) +MODEL_SCHEMA = cv.Schema( + { + cv.Optional(CONF_MODEL): MODEL_SOURCE_SCHEMA, + cv.Optional(CONF_PROBABILITY_CUTOFF): cv.percentage, + cv.Optional(CONF_SLIDING_WINDOW_SIZE): cv.positive_int, + cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), + } +) + +# Provide a default VAD model that could be overridden +VAD_MODEL_SCHEMA = MODEL_SCHEMA.extend( + cv.Schema( + { + cv.Optional( + CONF_MODEL, + default="vad", + ): MODEL_SOURCE_SCHEMA, + } + ) +) + + +def _maybe_empty_vad_schema(value): + # Idea borrowed from uart/__init__.py's ``maybe_empty_debug`` function. Accessed 2 July 2024. + # Loads a default VAD model without any parameters overridden. + if value is None: + value = {} + return VAD_MODEL_SCHEMA(value) + + CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(MicroWakeWord), cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), - cv.Optional(CONF_PROBABILITY_CUTOFF): cv.percentage, - cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int, + cv.Required(CONF_MODELS): cv.ensure_list(MODEL_SCHEMA), cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation( single=True ), - cv.Required(CONF_MODEL): MODEL_SOURCE_SCHEMA, - cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), + cv.Optional(CONF_VAD): _maybe_empty_vad_schema, + cv.Optional(CONF_MODEL): cv.invalid( + f"The {CONF_MODEL} parameter has moved to be a list element under the {CONF_MODELS} parameter." + ), + cv.Optional(CONF_PROBABILITY_CUTOFF): cv.invalid( + f"The {CONF_PROBABILITY_CUTOFF} parameter has moved to be a list element under the {CONF_MODELS} parameter." + ), + cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.invalid( + f"The {CONF_SLIDING_WINDOW_AVERAGE_SIZE} parameter has been renamed to {CONF_SLIDING_WINDOW_SIZE} and moved to be a list element under the {CONF_MODELS} parameter." + ), } ).extend(cv.COMPONENT_SCHEMA), cv.only_with_esp_idf, @@ -282,45 +381,20 @@ def _load_model_data(manifest_path: Path): with open(manifest_path, encoding="utf-8") as f: manifest = json.load(f) - try: - MANIFEST_SCHEMA_V1(manifest) - except cv.Invalid as e: - raise EsphomeError(f"Invalid manifest file: {e}") from e + _validate_manifest_version(manifest) model_path = manifest_path.parent / manifest[CONF_MODEL] with open(model_path, "rb") as f: model = f.read() + if manifest.get(KEY_VERSION) == 1: + manifest = _convert_manifest_v1_to_v2(manifest) + return manifest, model -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - - mic = await cg.get_variable(config[CONF_MICROPHONE]) - cg.add(var.set_microphone(mic)) - - if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED): - await automation.build_automation( - var.get_wake_word_detected_trigger(), - [(cg.std_string, "wake_word")], - on_wake_word_detection_config, - ) - - esp32.add_idf_component( - name="esp-tflite-micro", - repo="https://github.com/espressif/esp-tflite-micro", - ref="v1.3.1", - ) - - cg.add_build_flag("-DTF_LITE_STATIC_MEMORY") - cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON") - cg.add_build_flag("-DESP_NN") - - model_config = config.get(CONF_MODEL) - data = [] +def _model_config_to_manifest_data(model_config): if model_config[CONF_TYPE] == TYPE_GIT: # compute path to model file key = f"{model_config[CONF_URL]}@{model_config.get(CONF_REF)}" @@ -338,23 +412,95 @@ async def to_code(config): else: raise ValueError("Unsupported config type: {model_config[CONF_TYPE]}") - manifest, data = _load_model_data(file) + return _load_model_data(file) - rhs = [HexInt(x) for x in data] - prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) - cg.add(var.set_model_start(prog_arr)) - probability_cutoff = config.get( - CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF] +def _feature_step_size_validate(config): + features_step_size = None + + for model_parameters in config[CONF_MODELS]: + model_config = model_parameters.get(CONF_MODEL) + manifest, _ = _model_config_to_manifest_data(model_config) + + model_step_size = manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE] + + if features_step_size is None: + features_step_size = model_step_size + elif features_step_size != model_step_size: + raise cv.Invalid("Cannot load models with different features step sizes.") + + +FINAL_VALIDATE_SCHEMA = _feature_step_size_validate + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + mic = await cg.get_variable(config[CONF_MICROPHONE]) + cg.add(var.set_microphone(mic)) + + esp32.add_idf_component( + name="esp-tflite-micro", + repo="https://github.com/espressif/esp-tflite-micro", + ref="v1.3.1", ) - cg.add(var.set_probability_cutoff(probability_cutoff)) - sliding_window_average_size = config.get( - CONF_SLIDING_WINDOW_AVERAGE_SIZE, - manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE], - ) - cg.add(var.set_sliding_window_average_size(sliding_window_average_size)) - cg.add(var.set_wake_word(manifest[KEY_WAKE_WORD])) + cg.add_build_flag("-DTF_LITE_STATIC_MEMORY") + cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON") + cg.add_build_flag("-DESP_NN") + + if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED): + await automation.build_automation( + var.get_wake_word_detected_trigger(), + [(cg.std_string, "wake_word")], + on_wake_word_detection_config, + ) + + if vad_model := config.get(CONF_VAD): + cg.add_define("USE_MICRO_WAKE_WORD_VAD") + + # Use the general model loading code for the VAD codegen + config[CONF_MODELS].append(vad_model) + + for model_parameters in config[CONF_MODELS]: + model_config = model_parameters.get(CONF_MODEL) + data = [] + manifest, data = _model_config_to_manifest_data(model_config) + + rhs = [HexInt(x) for x in data] + prog_arr = cg.progmem_array(model_parameters[CONF_RAW_DATA_ID], rhs) + + probability_cutoff = model_parameters.get( + CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF] + ) + sliding_window_size = model_parameters.get( + CONF_SLIDING_WINDOW_SIZE, + manifest[KEY_MICRO][CONF_SLIDING_WINDOW_SIZE], + ) + + if manifest[KEY_WAKE_WORD] == "vad": + cg.add( + var.add_vad_model( + prog_arr, + probability_cutoff, + sliding_window_size, + manifest[KEY_MICRO][CONF_TENSOR_ARENA_SIZE], + ) + ) + else: + cg.add( + var.add_wake_word_model( + prog_arr, + probability_cutoff, + sliding_window_size, + manifest[KEY_WAKE_WORD], + manifest[KEY_MICRO][CONF_TENSOR_ARENA_SIZE], + ) + ) + + cg.add(var.set_features_step_size(manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE])) + cg.add_library("kahrendt/ESPMicroSpeechFeatures", "1.0.0") MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)}) diff --git a/esphome/components/micro_wake_word/audio_preprocessor_int8_model_data.h b/esphome/components/micro_wake_word/audio_preprocessor_int8_model_data.h deleted file mode 100644 index 918e76045f..0000000000 --- a/esphome/components/micro_wake_word/audio_preprocessor_int8_model_data.h +++ /dev/null @@ -1,493 +0,0 @@ -#pragma once - -#ifdef USE_ESP_IDF - -// Converted audio_preprocessor_int8.tflite -// From https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/micro_speech/models accessed -// January 2024 -// -// Copyright 2023 The TensorFlow Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace esphome { -namespace micro_wake_word { - -const unsigned char G_AUDIO_PREPROCESSOR_INT8_TFLITE[] = { - 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, 0x88, 0x00, - 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0xcc, 0x1f, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xeb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x3c, 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, 0x94, 0xff, - 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0xf5, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x2d, 0x00, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, - 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x2c, 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, 0x2e, 0x00, - 0x00, 0x00, 0x9c, 0x0d, 0x00, 0x00, 0x94, 0x0d, 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x48, - 0x09, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00, - 0xec, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x24, 0x07, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00, - 0x00, 0xb0, 0x01, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x60, 0x01, - 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x2c, - 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, - 0x00, 0xdc, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xbc, 0x00, - 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x94, - 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x32, 0x2e, 0x30, 0x00, - 0x00, 0x56, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x38, 0x2e, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xe1, 0xff, 0xff, 0xd8, 0xe1, 0xff, 0xff, 0xdc, - 0xe1, 0xff, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe4, 0xe1, 0xff, 0xff, 0xe8, 0xe1, 0xff, 0xff, 0xec, 0xe1, 0xff, 0xff, - 0xf0, 0xe1, 0xff, 0xff, 0xf4, 0xe1, 0xff, 0xff, 0xf8, 0xe1, 0xff, 0xff, 0xfc, 0xe1, 0xff, 0xff, 0x00, 0xe2, 0xff, - 0xff, 0x04, 0xe2, 0xff, 0xff, 0x08, 0xe2, 0xff, 0xff, 0x0c, 0xe2, 0xff, 0xff, 0x10, 0xe2, 0xff, 0xff, 0x14, 0xe2, - 0xff, 0xff, 0x18, 0xe2, 0xff, 0xff, 0x1c, 0xe2, 0xff, 0xff, 0x20, 0xe2, 0xff, 0xff, 0x24, 0xe2, 0xff, 0xff, 0x28, - 0xe2, 0xff, 0xff, 0x2c, 0xe2, 0xff, 0xff, 0x30, 0xe2, 0xff, 0xff, 0xd2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0xe2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0xff, - 0xff, 0xff, 0x02, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, - 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x22, 0xf8, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x61, 0x05, 0x00, 0x00, 0x00, 0x00, 0x23, 0x0b, 0x41, - 0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x80, 0x05, - 0x00, 0x00, 0x00, 0x00, 0xd1, 0x0c, 0x63, 0x04, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0c, 0x3f, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x81, 0x0c, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0d, 0x77, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x0f, - 0xa9, 0x08, 0x01, 0x02, 0x7f, 0x0b, 0x22, 0x05, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0e, 0xd1, 0x08, 0xdb, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x0d, 0x4a, 0x07, 0xad, 0x01, 0x2c, 0x0c, 0xc6, 0x06, 0x79, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x0c, 0x29, 0x07, 0x23, 0x02, 0x34, 0x0d, 0x5b, 0x08, 0x96, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0x48, - 0x0a, 0xbd, 0x05, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x0c, 0x88, 0x08, 0x43, 0x04, - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0b, 0xd3, 0x07, 0xcb, 0x03, 0xd2, 0x0f, 0xe7, - 0x0b, 0x09, 0x08, 0x39, 0x04, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x0c, 0x14, 0x09, - 0x75, 0x05, 0xe2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x0e, 0xdd, 0x0a, 0x6b, 0x07, 0x03, - 0x04, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0d, 0x09, 0x0a, 0xc9, 0x06, 0x93, 0x03, 0x65, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0d, 0x25, 0x0a, 0x12, 0x07, 0x07, 0x04, 0x05, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x0a, 0x0e, 0x17, 0x0b, 0x2c, 0x08, 0x49, 0x05, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x0f, 0xcb, 0x0c, 0x04, 0x0a, 0x44, 0x07, 0x8b, 0x04, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x0f, 0x87, - 0x0c, 0xe7, 0x09, 0x4e, 0x07, 0xba, 0x04, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x0f, 0x23, 0x0d, 0xa7, 0x0a, - 0x30, 0x08, 0xbe, 0x05, 0x52, 0x03, 0xeb, 0x00, 0x89, 0x0e, 0x2c, 0x0c, 0xd4, 0x09, 0x81, 0x07, 0x33, 0x05, 0xe9, - 0x02, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0e, 0x29, 0x0c, 0xf1, 0x09, 0xbe, 0x07, 0x90, 0x05, 0x65, 0x03, - 0x3f, 0x01, 0x1d, 0x0f, 0xff, 0x0c, 0xe5, 0x0a, 0xcf, 0x08, 0xbc, 0x06, 0xae, 0x04, 0xa3, 0x02, 0x9c, 0x00, 0x99, - 0x0e, 0x99, 0x0c, 0x9d, 0x0a, 0xa4, 0x08, 0xaf, 0x06, 0xbd, 0x04, 0xcf, 0x02, 0xe4, 0x00, 0xfc, 0x0e, 0x17, 0x0d, - 0x36, 0x0b, 0x57, 0x09, 0x7c, 0x07, 0xa4, 0x05, 0xcf, 0x03, 0xfd, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x62, 0x0e, 0x98, 0x0c, 0xd2, 0x0a, 0x0e, 0x09, 0x4d, 0x07, 0x8f, 0x05, 0xd4, 0x03, 0x1b, 0x02, - 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x0e, 0x00, 0x0d, 0x52, 0x0b, 0xa6, 0x09, 0xfd, 0x07, 0x56, 0x06, 0xb1, - 0x04, 0x0f, 0x03, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x0f, 0x37, 0x0e, 0x9e, 0x0c, - 0x08, 0x0b, 0x73, 0x09, 0xe1, 0x07, 0x52, 0x06, 0xc4, 0x04, 0x38, 0x03, 0xaf, 0x01, 0x28, 0x00, 0xa3, 0x0e, 0x1f, - 0x0d, 0x9e, 0x0b, 0x1f, 0x0a, 0xa2, 0x08, 0x27, 0x07, 0xae, 0x05, 0x37, 0x04, 0xc2, 0x02, 0x4e, 0x01, 0x00, 0x00, - 0x00, 0x00, 0xdd, 0x0f, 0x6d, 0x0e, 0xff, 0x0c, 0x93, 0x0b, 0x29, 0x0a, 0xc1, 0x08, 0x5a, 0x07, 0xf5, 0x05, 0x92, - 0x04, 0x30, 0x03, 0xd1, 0x01, 0x73, 0x00, 0x16, 0x0f, 0xbc, 0x0d, 0x62, 0x0c, 0x0b, 0x0b, 0xb5, 0x09, 0x61, 0x08, - 0x0e, 0x07, 0xbd, 0x05, 0x6d, 0x04, 0x1f, 0x03, 0xd3, 0x01, 0x88, 0x00, 0x3e, 0x0f, 0xf6, 0x0d, 0xaf, 0x0c, 0x6a, - 0x0b, 0x27, 0x0a, 0xe4, 0x08, 0xa3, 0x07, 0x64, 0x06, 0x26, 0x05, 0xe9, 0x03, 0xae, 0x02, 0x74, 0x01, 0x3b, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xce, 0x0d, 0x99, 0x0c, 0x66, 0x0b, 0x34, 0x0a, 0x03, - 0x09, 0xd3, 0x07, 0xa5, 0x06, 0x78, 0x05, 0x4c, 0x04, 0x22, 0x03, 0xf8, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa9, 0x0f, 0x83, 0x0e, 0x5f, 0x0d, 0x3b, 0x0c, 0x19, 0x0b, 0xf8, 0x09, 0xd8, 0x08, 0xb9, 0x07, 0x9b, 0x06, 0x7e, - 0x05, 0x63, 0x04, 0x48, 0x03, 0x2f, 0x02, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xfa, 0xff, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x04, 0xbe, 0x0e, 0x00, - 0x00, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x7f, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x2e, 0x03, 0x9c, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x03, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x7e, - 0x03, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x88, 0x09, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x56, 0x07, - 0xfe, 0x0d, 0x80, 0x04, 0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x2e, 0x07, 0x24, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0xfc, 0x02, 0xb5, 0x08, 0x52, 0x0e, 0xd3, 0x03, 0x39, 0x09, 0x86, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xba, 0x03, - 0xd6, 0x08, 0xdc, 0x0d, 0xcb, 0x02, 0xa4, 0x07, 0x69, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0xb7, 0x05, 0x42, - 0x0a, 0xba, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x03, 0x77, 0x07, 0xbc, 0x0b, 0xf1, 0x0f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x04, 0x2c, 0x08, 0x34, 0x0c, 0x2d, 0x00, 0x18, 0x04, 0xf6, - 0x07, 0xc6, 0x0b, 0x89, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0xeb, 0x06, 0x8a, 0x0a, - 0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x22, 0x05, 0x94, 0x08, 0xfc, 0x0b, 0x59, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0xf6, 0x05, 0x36, 0x09, 0x6c, 0x0c, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xbe, 0x02, 0xda, 0x05, 0xed, 0x08, 0xf8, 0x0b, 0xfa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xf5, - 0x01, 0xe8, 0x04, 0xd3, 0x07, 0xb6, 0x0a, 0x92, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, - 0x34, 0x03, 0xfb, 0x05, 0xbb, 0x08, 0x74, 0x0b, 0x27, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x78, 0x03, 0x18, - 0x06, 0xb1, 0x08, 0x45, 0x0b, 0xd2, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0xdc, 0x02, 0x58, 0x05, 0xcf, 0x07, - 0x41, 0x0a, 0xad, 0x0c, 0x14, 0x0f, 0x76, 0x01, 0xd3, 0x03, 0x2b, 0x06, 0x7e, 0x08, 0xcc, 0x0a, 0x16, 0x0d, 0x5a, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x01, 0xd6, 0x03, 0x0e, 0x06, 0x41, 0x08, 0x6f, 0x0a, 0x9a, 0x0c, 0xc0, 0x0e, - 0xe2, 0x00, 0x00, 0x03, 0x1a, 0x05, 0x30, 0x07, 0x43, 0x09, 0x51, 0x0b, 0x5c, 0x0d, 0x63, 0x0f, 0x66, 0x01, 0x66, - 0x03, 0x62, 0x05, 0x5b, 0x07, 0x50, 0x09, 0x42, 0x0b, 0x30, 0x0d, 0x1b, 0x0f, 0x03, 0x01, 0xe8, 0x02, 0xc9, 0x04, - 0xa8, 0x06, 0x83, 0x08, 0x5b, 0x0a, 0x30, 0x0c, 0x02, 0x0e, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x9d, 0x01, 0x67, 0x03, 0x2d, 0x05, 0xf1, 0x06, 0xb2, 0x08, 0x70, 0x0a, 0x2b, 0x0c, 0xe4, 0x0d, 0x9a, 0x0f, - 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0xff, 0x02, 0xad, 0x04, 0x59, 0x06, 0x02, 0x08, 0xa9, 0x09, 0x4e, 0x0b, 0xf0, - 0x0c, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xc8, 0x01, 0x61, 0x03, 0xf7, 0x04, - 0x8c, 0x06, 0x1e, 0x08, 0xad, 0x09, 0x3b, 0x0b, 0xc7, 0x0c, 0x50, 0x0e, 0xd7, 0x0f, 0x5c, 0x01, 0xe0, 0x02, 0x61, - 0x04, 0xe0, 0x05, 0x5d, 0x07, 0xd8, 0x08, 0x51, 0x0a, 0xc8, 0x0b, 0x3d, 0x0d, 0xb1, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x92, 0x01, 0x00, 0x03, 0x6c, 0x04, 0xd6, 0x05, 0x3e, 0x07, 0xa5, 0x08, 0x0a, 0x0a, 0x6d, 0x0b, 0xcf, - 0x0c, 0x2e, 0x0e, 0x8c, 0x0f, 0xe9, 0x00, 0x43, 0x02, 0x9d, 0x03, 0xf4, 0x04, 0x4a, 0x06, 0x9e, 0x07, 0xf1, 0x08, - 0x42, 0x0a, 0x92, 0x0b, 0xe0, 0x0c, 0x2c, 0x0e, 0x77, 0x0f, 0xc1, 0x00, 0x09, 0x02, 0x50, 0x03, 0x95, 0x04, 0xd8, - 0x05, 0x1b, 0x07, 0x5c, 0x08, 0x9b, 0x09, 0xd9, 0x0a, 0x16, 0x0c, 0x51, 0x0d, 0x8b, 0x0e, 0xc4, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x31, 0x02, 0x66, 0x03, 0x99, 0x04, 0xcb, 0x05, 0xfc, 0x06, 0x2c, - 0x08, 0x5a, 0x09, 0x87, 0x0a, 0xb3, 0x0b, 0xdd, 0x0c, 0x07, 0x0e, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, - 0x7c, 0x01, 0xa0, 0x02, 0xc4, 0x03, 0xe6, 0x04, 0x07, 0x06, 0x27, 0x07, 0x46, 0x08, 0x64, 0x09, 0x81, 0x0a, 0x9c, - 0x0b, 0xb7, 0x0c, 0xd0, 0x0d, 0xe8, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, - 0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x24, 0x00, 0x26, 0x00, 0x2a, 0x00, - 0x2e, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x5a, - 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9a, 0x00, 0xa6, 0x00, - 0xb0, 0x00, 0xbc, 0x00, 0xc8, 0x00, 0xd4, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x8a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, - 0x1c, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x30, 0x00, 0x34, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x44, - 0x00, 0x4c, 0x00, 0x50, 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, - 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xc4, 0x00, 0xd0, 0x00, 0xdc, 0x00, 0xe8, - 0x00, 0xf4, 0x00, 0x00, 0x01, 0x0c, 0x01, 0x1c, 0x01, 0x2c, 0x01, 0x00, 0x00, 0xea, 0xfd, 0xff, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, - 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, - 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, - 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4a, 0xfe, 0xff, 0xff, 0x04, - 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x79, 0x7f, 0x76, 0x7f, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x70, 0x7f, 0xf4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0xe9, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x4b, 0x7f, 0xd0, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x7f, 0xa0, 0xff, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x7e, 0x42, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xfd, 0x7d, 0x86, 0xfe, 0x04, 0x00, 0x00, 0x00, 0x87, 0x7c, 0x1d, 0xfd, 0x12, 0x00, 0x00, 0x00, 0xb6, - 0x79, 0x7f, 0xfa, 0x3e, 0x00, 0x00, 0x00, 0x73, 0x74, 0xf9, 0xf5, 0xca, 0x00, 0x00, 0x00, 0x36, 0x6b, 0x33, 0xef, - 0x32, 0x02, 0x00, 0x00, 0x9b, 0x5c, 0x87, 0xe7, 0xce, 0x04, 0x00, 0x00, 0xf0, 0x48, 0xde, 0xe2, 0xa0, 0x07, 0x00, - 0x00, 0x6e, 0x33, 0x8a, 0xe4, 0xa4, 0x08, 0x00, 0x00, 0x9c, 0x20, 0x22, 0xeb, 0x4c, 0x07, 0x00, 0x00, 0x0a, 0x13, - 0x7d, 0xf2, 0x02, 0x05, 0x00, 0x00, 0x89, 0x0a, 0x17, 0xf8, 0x06, 0x03, 0x00, 0x00, 0xa6, 0x05, 0xa0, 0xfb, 0xb4, - 0x01, 0x00, 0x00, 0xfa, 0x02, 0xac, 0xfd, 0xe8, 0x00, 0x00, 0x00, 0x8e, 0x01, 0xc7, 0xfe, 0x7a, 0x00, 0x00, 0x00, - 0xcf, 0x00, 0x5c, 0xff, 0x40, 0x00, 0x00, 0x00, 0x6b, 0x00, 0xab, 0xff, 0x22, 0x00, 0x00, 0x00, 0x38, 0x00, 0xd3, - 0xff, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0xea, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xf3, 0xff, 0x06, 0x00, - 0x00, 0x00, 0x08, 0x00, 0xf8, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0xfd, 0xff, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x82, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, - 0x92, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xff, 0xff, 0xff, 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, 0x06, 0x00, 0x08, 0x00, - 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x13, 0x00, 0x17, 0x00, - 0x1b, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x3c, 0x00, 0x42, 0x00, 0x49, 0x00, 0x51, - 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8d, 0x00, 0x97, 0x00, 0xa1, 0x00, - 0xac, 0x00, 0xb7, 0x00, 0xc2, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xff, 0x00, 0x0c, 0x01, 0x19, - 0x01, 0x27, 0x01, 0x35, 0x01, 0x43, 0x01, 0x52, 0x01, 0x61, 0x01, 0x70, 0x01, 0x7f, 0x01, 0x8f, 0x01, 0x9f, 0x01, - 0xaf, 0x01, 0xc0, 0x01, 0xd1, 0x01, 0xe2, 0x01, 0xf3, 0x01, 0x05, 0x02, 0x17, 0x02, 0x29, 0x02, 0x3c, 0x02, 0x4e, - 0x02, 0x61, 0x02, 0x75, 0x02, 0x88, 0x02, 0x9c, 0x02, 0xb0, 0x02, 0xc4, 0x02, 0xd8, 0x02, 0xed, 0x02, 0x02, 0x03, - 0x17, 0x03, 0x2c, 0x03, 0x41, 0x03, 0x57, 0x03, 0x6d, 0x03, 0x83, 0x03, 0x99, 0x03, 0xb0, 0x03, 0xc7, 0x03, 0xdd, - 0x03, 0xf4, 0x03, 0x0c, 0x04, 0x23, 0x04, 0x3b, 0x04, 0x52, 0x04, 0x6a, 0x04, 0x82, 0x04, 0x9a, 0x04, 0xb3, 0x04, - 0xcb, 0x04, 0xe4, 0x04, 0xfd, 0x04, 0x16, 0x05, 0x2f, 0x05, 0x48, 0x05, 0x61, 0x05, 0x7a, 0x05, 0x94, 0x05, 0xad, - 0x05, 0xc7, 0x05, 0xe1, 0x05, 0xfb, 0x05, 0x15, 0x06, 0x2f, 0x06, 0x49, 0x06, 0x63, 0x06, 0x7e, 0x06, 0x98, 0x06, - 0xb2, 0x06, 0xcd, 0x06, 0xe7, 0x06, 0x02, 0x07, 0x1d, 0x07, 0x37, 0x07, 0x52, 0x07, 0x6d, 0x07, 0x87, 0x07, 0xa2, - 0x07, 0xbd, 0x07, 0xd8, 0x07, 0xf3, 0x07, 0x0d, 0x08, 0x28, 0x08, 0x43, 0x08, 0x5e, 0x08, 0x79, 0x08, 0x93, 0x08, - 0xae, 0x08, 0xc9, 0x08, 0xe3, 0x08, 0xfe, 0x08, 0x19, 0x09, 0x33, 0x09, 0x4e, 0x09, 0x68, 0x09, 0x82, 0x09, 0x9d, - 0x09, 0xb7, 0x09, 0xd1, 0x09, 0xeb, 0x09, 0x05, 0x0a, 0x1f, 0x0a, 0x39, 0x0a, 0x53, 0x0a, 0x6c, 0x0a, 0x86, 0x0a, - 0x9f, 0x0a, 0xb8, 0x0a, 0xd1, 0x0a, 0xea, 0x0a, 0x03, 0x0b, 0x1c, 0x0b, 0x35, 0x0b, 0x4d, 0x0b, 0x66, 0x0b, 0x7e, - 0x0b, 0x96, 0x0b, 0xae, 0x0b, 0xc5, 0x0b, 0xdd, 0x0b, 0xf4, 0x0b, 0x0c, 0x0c, 0x23, 0x0c, 0x39, 0x0c, 0x50, 0x0c, - 0x67, 0x0c, 0x7d, 0x0c, 0x93, 0x0c, 0xa9, 0x0c, 0xbf, 0x0c, 0xd4, 0x0c, 0xe9, 0x0c, 0xfe, 0x0c, 0x13, 0x0d, 0x28, - 0x0d, 0x3c, 0x0d, 0x50, 0x0d, 0x64, 0x0d, 0x78, 0x0d, 0x8b, 0x0d, 0x9f, 0x0d, 0xb2, 0x0d, 0xc4, 0x0d, 0xd7, 0x0d, - 0xe9, 0x0d, 0xfb, 0x0d, 0x0d, 0x0e, 0x1e, 0x0e, 0x2f, 0x0e, 0x40, 0x0e, 0x51, 0x0e, 0x61, 0x0e, 0x71, 0x0e, 0x81, - 0x0e, 0x90, 0x0e, 0x9f, 0x0e, 0xae, 0x0e, 0xbd, 0x0e, 0xcb, 0x0e, 0xd9, 0x0e, 0xe7, 0x0e, 0xf4, 0x0e, 0x01, 0x0f, - 0x0e, 0x0f, 0x1b, 0x0f, 0x27, 0x0f, 0x33, 0x0f, 0x3e, 0x0f, 0x49, 0x0f, 0x54, 0x0f, 0x5f, 0x0f, 0x69, 0x0f, 0x73, - 0x0f, 0x7d, 0x0f, 0x86, 0x0f, 0x8f, 0x0f, 0x98, 0x0f, 0xa0, 0x0f, 0xa8, 0x0f, 0xaf, 0x0f, 0xb7, 0x0f, 0xbe, 0x0f, - 0xc4, 0x0f, 0xcb, 0x0f, 0xd0, 0x0f, 0xd6, 0x0f, 0xdb, 0x0f, 0xe0, 0x0f, 0xe5, 0x0f, 0xe9, 0x0f, 0xed, 0x0f, 0xf0, - 0x0f, 0xf3, 0x0f, 0xf6, 0x0f, 0xf9, 0x0f, 0xfb, 0x0f, 0xfc, 0x0f, 0xfe, 0x0f, 0xff, 0x0f, 0x00, 0x10, 0x00, 0x10, - 0x00, 0x10, 0x00, 0x10, 0xff, 0x0f, 0xfe, 0x0f, 0xfc, 0x0f, 0xfb, 0x0f, 0xf9, 0x0f, 0xf6, 0x0f, 0xf3, 0x0f, 0xf0, - 0x0f, 0xed, 0x0f, 0xe9, 0x0f, 0xe5, 0x0f, 0xe0, 0x0f, 0xdb, 0x0f, 0xd6, 0x0f, 0xd0, 0x0f, 0xcb, 0x0f, 0xc4, 0x0f, - 0xbe, 0x0f, 0xb7, 0x0f, 0xaf, 0x0f, 0xa8, 0x0f, 0xa0, 0x0f, 0x98, 0x0f, 0x8f, 0x0f, 0x86, 0x0f, 0x7d, 0x0f, 0x73, - 0x0f, 0x69, 0x0f, 0x5f, 0x0f, 0x54, 0x0f, 0x49, 0x0f, 0x3e, 0x0f, 0x33, 0x0f, 0x27, 0x0f, 0x1b, 0x0f, 0x0e, 0x0f, - 0x01, 0x0f, 0xf4, 0x0e, 0xe7, 0x0e, 0xd9, 0x0e, 0xcb, 0x0e, 0xbd, 0x0e, 0xae, 0x0e, 0x9f, 0x0e, 0x90, 0x0e, 0x81, - 0x0e, 0x71, 0x0e, 0x61, 0x0e, 0x51, 0x0e, 0x40, 0x0e, 0x2f, 0x0e, 0x1e, 0x0e, 0x0d, 0x0e, 0xfb, 0x0d, 0xe9, 0x0d, - 0xd7, 0x0d, 0xc4, 0x0d, 0xb2, 0x0d, 0x9f, 0x0d, 0x8b, 0x0d, 0x78, 0x0d, 0x64, 0x0d, 0x50, 0x0d, 0x3c, 0x0d, 0x28, - 0x0d, 0x13, 0x0d, 0xfe, 0x0c, 0xe9, 0x0c, 0xd4, 0x0c, 0xbf, 0x0c, 0xa9, 0x0c, 0x93, 0x0c, 0x7d, 0x0c, 0x67, 0x0c, - 0x50, 0x0c, 0x39, 0x0c, 0x23, 0x0c, 0x0c, 0x0c, 0xf4, 0x0b, 0xdd, 0x0b, 0xc5, 0x0b, 0xae, 0x0b, 0x96, 0x0b, 0x7e, - 0x0b, 0x66, 0x0b, 0x4d, 0x0b, 0x35, 0x0b, 0x1c, 0x0b, 0x03, 0x0b, 0xea, 0x0a, 0xd1, 0x0a, 0xb8, 0x0a, 0x9f, 0x0a, - 0x86, 0x0a, 0x6c, 0x0a, 0x53, 0x0a, 0x39, 0x0a, 0x1f, 0x0a, 0x05, 0x0a, 0xeb, 0x09, 0xd1, 0x09, 0xb7, 0x09, 0x9d, - 0x09, 0x82, 0x09, 0x68, 0x09, 0x4e, 0x09, 0x33, 0x09, 0x19, 0x09, 0xfe, 0x08, 0xe3, 0x08, 0xc9, 0x08, 0xae, 0x08, - 0x93, 0x08, 0x79, 0x08, 0x5e, 0x08, 0x43, 0x08, 0x28, 0x08, 0x0d, 0x08, 0xf3, 0x07, 0xd8, 0x07, 0xbd, 0x07, 0xa2, - 0x07, 0x87, 0x07, 0x6d, 0x07, 0x52, 0x07, 0x37, 0x07, 0x1d, 0x07, 0x02, 0x07, 0xe7, 0x06, 0xcd, 0x06, 0xb2, 0x06, - 0x98, 0x06, 0x7e, 0x06, 0x63, 0x06, 0x49, 0x06, 0x2f, 0x06, 0x15, 0x06, 0xfb, 0x05, 0xe1, 0x05, 0xc7, 0x05, 0xad, - 0x05, 0x94, 0x05, 0x7a, 0x05, 0x61, 0x05, 0x48, 0x05, 0x2f, 0x05, 0x16, 0x05, 0xfd, 0x04, 0xe4, 0x04, 0xcb, 0x04, - 0xb3, 0x04, 0x9a, 0x04, 0x82, 0x04, 0x6a, 0x04, 0x52, 0x04, 0x3b, 0x04, 0x23, 0x04, 0x0c, 0x04, 0xf4, 0x03, 0xdd, - 0x03, 0xc7, 0x03, 0xb0, 0x03, 0x99, 0x03, 0x83, 0x03, 0x6d, 0x03, 0x57, 0x03, 0x41, 0x03, 0x2c, 0x03, 0x17, 0x03, - 0x02, 0x03, 0xed, 0x02, 0xd8, 0x02, 0xc4, 0x02, 0xb0, 0x02, 0x9c, 0x02, 0x88, 0x02, 0x75, 0x02, 0x61, 0x02, 0x4e, - 0x02, 0x3c, 0x02, 0x29, 0x02, 0x17, 0x02, 0x05, 0x02, 0xf3, 0x01, 0xe2, 0x01, 0xd1, 0x01, 0xc0, 0x01, 0xaf, 0x01, - 0x9f, 0x01, 0x8f, 0x01, 0x7f, 0x01, 0x70, 0x01, 0x61, 0x01, 0x52, 0x01, 0x43, 0x01, 0x35, 0x01, 0x27, 0x01, 0x19, - 0x01, 0x0c, 0x01, 0xff, 0x00, 0xf2, 0x00, 0xe5, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xac, 0x00, - 0xa1, 0x00, 0x97, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x68, 0x00, 0x60, 0x00, 0x58, 0x00, 0x51, - 0x00, 0x49, 0x00, 0x42, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2a, 0x00, 0x25, 0x00, 0x20, 0x00, 0x1b, 0x00, - 0x17, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xee, 0xff, 0xff, 0x38, 0xee, 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, 0xf4, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, - 0x00, 0xfc, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x00, 0x70, - 0x04, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, - 0x4c, 0x03, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00, - 0x00, 0x48, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x78, 0x00, - 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0xfa, 0xff, 0xff, 0x0c, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0xa6, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, 0x00, - 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x68, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0xff, 0xff, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x98, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, - 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xc8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x25, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0xfd, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, - 0x00, 0xf8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, - 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x84, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x00, 0x02, 0x24, 0x0f, 0x02, 0x01, 0x02, 0x03, 0x40, 0x04, 0x04, 0x04, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xdc, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, - 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x73, 0x6e, - 0x72, 0x5f, 0x73, 0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x0b, 0x01, 0x01, 0x01, 0x06, 0x04, 0x02, 0x24, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x20, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, - 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, - 0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, - 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, - 0x67, 0x00, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, - 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, - 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x73, 0x70, 0x65, 0x63, 0x74, - 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, - 0x73, 0x00, 0x09, 0xa5, 0x88, 0x75, 0x6d, 0x59, 0x4d, 0x3a, 0x31, 0x23, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x29, - 0x3c, 0xd7, 0x03, 0x00, 0x00, 0x33, 0x03, 0x28, 0x00, 0x67, 0x3e, 0x99, 0x01, 0x0a, 0x00, 0x0e, 0x00, 0x05, 0x05, - 0x69, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1b, 0x25, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x10, 0x00, - 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0x2c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x01, 0x0e, 0x01, 0x01, 0x01, 0x28, 0x04, 0x02, 0x24, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0xfe, 0xff, - 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8c, 0xf2, 0xff, 0xff, - 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, - 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0xfe, 0xfe, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0xff, 0xff, 0xff, 0x10, - 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x00, 0x02, 0x17, 0x0e, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x05, 0x00, 0x05, 0x05, - 0x06, 0x25, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, - 0x00, 0x00, 0x00, 0xb8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x66, 0x66, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x00, 0x02, 0x0e, 0x0d, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x02, 0x05, 0x05, 0x06, 0x25, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, - 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, - 0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x07, 0x01, 0x01, 0x01, 0x0c, 0x04, 0x02, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xc4, 0x0a, - 0x00, 0x00, 0x74, 0x0a, 0x00, 0x00, 0x3c, 0x0a, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x88, - 0x09, 0x00, 0x00, 0x40, 0x09, 0x00, 0x00, 0xfc, 0x08, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00, - 0x20, 0x08, 0x00, 0x00, 0xd4, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x3c, 0x07, 0x00, 0x00, 0xf8, 0x06, 0x00, - 0x00, 0xb8, 0x06, 0x00, 0x00, 0x84, 0x06, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0xd8, 0x05, - 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x98, - 0x04, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, - 0x6c, 0x03, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00, - 0x00, 0xe4, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x01, - 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfe, - 0xf5, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x00, 0x44, 0xf5, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3e, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x84, 0xf5, 0xff, 0xff, - 0x0d, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0xc0, - 0xf5, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0xbe, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x04, 0xf6, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x61, - 0x64, 0x64, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x18, 0x00, 0x00, 0x00, 0x38, 0xf6, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, - 0x74, 0x65, 0x44, 0x69, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x10, 0x00, 0x00, 0x00, 0x70, 0xf6, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x28, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0xa0, 0xf6, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x6d, 0x75, 0x6c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8a, 0xf7, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x14, 0x00, 0x00, 0x00, 0xd0, 0xf6, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x32, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xbe, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, - 0x04, 0xf7, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x02, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x00, 0x48, 0xf7, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0x3a, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, - 0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x92, 0xf8, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x34, - 0x00, 0x00, 0x00, 0xd8, 0xf7, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, - 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0xe6, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, 0x1e, 0x00, 0x00, 0x00, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, - 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x32, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x78, 0xf8, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x72, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x00, 0xb8, - 0xf8, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0xa6, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xec, 0xf8, 0xff, 0xff, 0x06, 0x00, - 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xda, - 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x20, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, - 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xec, 0x00, - 0x00, 0x00, 0x16, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xf9, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x43, 0x61, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x4a, 0xfa, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x1c, 0x00, 0x00, 0x00, 0x90, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x5f, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x86, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xf9, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x66, 0x66, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0xbe, - 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x04, 0xfa, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x31, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, 0x44, 0xfa, 0xff, 0xff, - 0x15, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, - 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x42, 0xfb, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, - 0x61, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x76, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1c, 0x00, - 0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x69, - 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, - 0xb6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xfc, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, 0x6f, - 0x6e, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, - 0x2c, 0xfb, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x16, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xfb, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, - 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, - 0x00, 0x8c, 0xfb, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x68, - 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0xfc, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x24, 0x00, 0x00, 0x00, 0xc8, 0xfb, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x2f, 0x79, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc2, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x08, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, - 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x0a, 0xfd, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x50, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, - 0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x52, 0xfd, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, - 0x00, 0x00, 0x00, 0x98, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9a, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0xe0, - 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x33, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x29, 0x00, 0x00, 0x00, 0xe2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x28, 0xfd, 0xff, 0xff, 0x1a, - 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, - 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, - 0x00, 0x2a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x70, 0xfd, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x6a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, - 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0xb0, 0xfd, - 0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, - 0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x24, 0x00, 0x00, 0x00, 0xf0, 0xfd, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, - 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xee, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x34, 0xfe, 0xff, - 0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, - 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, - 0x74, 0x5f, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xa8, - 0xfe, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x96, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xdc, 0xfe, 0xff, 0xff, 0x07, 0x00, - 0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x5f, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xca, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, - 0x73, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x1c, 0x00, - 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0x2c, 0x00, 0x00, 0x00, 0x5c, 0xff, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, - 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, - 0xa4, 0x01, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, - 0x00, 0x10, 0x01, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x50, 0x00, - 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x50, 0xfe, 0xff, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x5c, 0xfe, 0xff, 0xff, - 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x68, 0xfe, 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xfe, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x12, 0x70, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13, - 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, - 0x4c, 0x6f, 0x67, 0x00, 0x98, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x50, 0x43, 0x41, 0x4e, 0x00, 0x00, 0xb8, 0xfe, - 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x23, 0x00, 0x00, 0x00, 0x53, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x70, 0x65, 0x63, - 0x74, 0x72, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xf0, 0xfe, 0xff, - 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1a, 0x00, 0x00, 0x00, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x71, 0x75, 0x61, 0x72, - 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x6c, 0xff, 0xff, 0xff, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x10, 0x00, 0x0f, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x35, 0x7c, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a, - 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x66, 0x66, 0x74, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, - 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x46, 0x66, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x0c, 0x00, - 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00}; - -} // namespace micro_wake_word -} // namespace esphome - -#endif // USE_ESP_IDF diff --git a/esphome/components/micro_wake_word/micro_wake_word.cpp b/esphome/components/micro_wake_word/micro_wake_word.cpp index 5a89708127..b58c7ec434 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.cpp +++ b/esphome/components/micro_wake_word/micro_wake_word.cpp @@ -1,12 +1,5 @@ #include "micro_wake_word.h" - -/** - * This is a workaround until we can figure out a way to get - * the tflite-micro idf component code available in CI - * - * */ -// -#ifndef CLANG_TIDY +#include "streaming_model.h" #ifdef USE_ESP_IDF @@ -14,13 +7,13 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "audio_preprocessor_int8_model_data.h" +#include +#include #include #include #include -#include #include namespace esphome { @@ -29,9 +22,9 @@ namespace micro_wake_word { static const char *const TAG = "micro_wake_word"; static const size_t SAMPLE_RATE_HZ = 16000; // 16 kHz -static const size_t BUFFER_LENGTH = 500; // 0.5 seconds +static const size_t BUFFER_LENGTH = 64; // 0.064 seconds static const size_t BUFFER_SIZE = SAMPLE_RATE_HZ / 1000 * BUFFER_LENGTH; -static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms +static const size_t INPUT_BUFFER_SIZE = 16 * SAMPLE_RATE_HZ / 1000; // 16ms * 16kHz / 1000ms float MicroWakeWord::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } @@ -56,58 +49,56 @@ static const LogString *micro_wake_word_state_to_string(State state) { void MicroWakeWord::dump_config() { ESP_LOGCONFIG(TAG, "microWakeWord:"); - ESP_LOGCONFIG(TAG, " Wake Word: %s", this->get_wake_word().c_str()); - ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_); - ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_average_size_); + ESP_LOGCONFIG(TAG, " models:"); + for (auto &model : this->wake_word_models_) { + model.log_model_config(); + } +#ifdef USE_MICRO_WAKE_WORD_VAD + this->vad_model_->log_model_config(); +#endif } void MicroWakeWord::setup() { ESP_LOGCONFIG(TAG, "Setting up microWakeWord..."); - if (!this->initialize_models()) { - ESP_LOGE(TAG, "Failed to initialize models"); - this->mark_failed(); - return; - } - - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE * sizeof(int16_t)); - if (this->input_buffer_ == nullptr) { - ESP_LOGW(TAG, "Could not allocate input buffer"); - this->mark_failed(); - return; - } - - this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t)); - if (this->ring_buffer_ == nullptr) { - ESP_LOGW(TAG, "Could not allocate ring buffer"); + if (!this->register_streaming_ops_(this->streaming_op_resolver_)) { this->mark_failed(); return; } ESP_LOGCONFIG(TAG, "Micro Wake Word initialized"); + + this->frontend_config_.window.size_ms = FEATURE_DURATION_MS; + this->frontend_config_.window.step_size_ms = this->features_step_size_; + this->frontend_config_.filterbank.num_channels = PREPROCESSOR_FEATURE_SIZE; + this->frontend_config_.filterbank.lower_band_limit = 125.0; + this->frontend_config_.filterbank.upper_band_limit = 7500.0; + this->frontend_config_.noise_reduction.smoothing_bits = 10; + this->frontend_config_.noise_reduction.even_smoothing = 0.025; + this->frontend_config_.noise_reduction.odd_smoothing = 0.06; + this->frontend_config_.noise_reduction.min_signal_remaining = 0.05; + this->frontend_config_.pcan_gain_control.enable_pcan = 1; + this->frontend_config_.pcan_gain_control.strength = 0.95; + this->frontend_config_.pcan_gain_control.offset = 80.0; + this->frontend_config_.pcan_gain_control.gain_bits = 21; + this->frontend_config_.log_scale.enable_log = 1; + this->frontend_config_.log_scale.scale_shift = 6; } -int MicroWakeWord::read_microphone_() { - size_t bytes_read = this->microphone_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t)); - if (bytes_read == 0) { - return 0; - } - - size_t bytes_free = this->ring_buffer_->free(); - - if (bytes_free < bytes_read) { - ESP_LOGW(TAG, - "Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). " - "Resetting the ring buffer. Wake word detection accuracy will be reduced.", - bytes_free, bytes_read); - - this->ring_buffer_->reset(); - } - - return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); +void MicroWakeWord::add_wake_word_model(const uint8_t *model_start, float probability_cutoff, + size_t sliding_window_average_size, const std::string &wake_word, + size_t tensor_arena_size) { + this->wake_word_models_.emplace_back(model_start, probability_cutoff, sliding_window_average_size, wake_word, + tensor_arena_size); } +#ifdef USE_MICRO_WAKE_WORD_VAD +void MicroWakeWord::add_vad_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size, + size_t tensor_arena_size) { + this->vad_model_ = make_unique(model_start, probability_cutoff, sliding_window_size, tensor_arena_size); +} +#endif + void MicroWakeWord::loop() { switch (this->state_) { case State::IDLE: @@ -124,9 +115,12 @@ void MicroWakeWord::loop() { } break; case State::DETECTING_WAKE_WORD: - this->read_microphone_(); - if (this->detect_wake_word_()) { - ESP_LOGD(TAG, "Wake Word Detected"); + while (!this->has_enough_samples_()) { + this->read_microphone_(); + } + this->update_model_probabilities_(); + if (this->detect_wake_words_()) { + ESP_LOGD(TAG, "Wake Word '%s' Detected", (this->detected_wake_word_).c_str()); this->detected_ = true; this->set_state_(State::STOP_MICROPHONE); } @@ -136,13 +130,16 @@ void MicroWakeWord::loop() { this->microphone_->stop(); this->set_state_(State::STOPPING_MICROPHONE); this->high_freq_.stop(); + this->unload_models_(); + this->deallocate_buffers_(); break; case State::STOPPING_MICROPHONE: if (this->microphone_->is_stopped()) { this->set_state_(State::IDLE); if (this->detected_) { + this->wake_word_detected_trigger_->trigger(this->detected_wake_word_); this->detected_ = false; - this->wake_word_detected_trigger_->trigger(this->wake_word_); + this->detected_wake_word_ = ""; } } break; @@ -150,14 +147,34 @@ void MicroWakeWord::loop() { } void MicroWakeWord::start() { + if (!this->is_ready()) { + ESP_LOGW(TAG, "Wake word detection can't start as the component hasn't been setup yet"); + return; + } + if (this->is_failed()) { ESP_LOGW(TAG, "Wake word component is marked as failed. Please check setup logs"); return; } + + if (!this->load_models_() || !this->allocate_buffers_()) { + ESP_LOGE(TAG, "Failed to load the wake word model(s) or allocate buffers"); + this->status_set_error(); + } else { + this->status_clear_error(); + } + + if (this->status_has_error()) { + ESP_LOGW(TAG, "Wake word component has an error. Please check logs"); + return; + } + if (this->state_ != State::IDLE) { ESP_LOGW(TAG, "Wake word is already running"); return; } + + this->reset_states_(); this->set_state_(State::START_MICROPHONE); } @@ -179,289 +196,218 @@ void MicroWakeWord::set_state_(State state) { this->state_ = state; } -bool MicroWakeWord::initialize_models() { - ExternalRAMAllocator arena_allocator(ExternalRAMAllocator::ALLOW_FAILURE); - ExternalRAMAllocator features_allocator(ExternalRAMAllocator::ALLOW_FAILURE); +size_t MicroWakeWord::read_microphone_() { + size_t bytes_read = this->microphone_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t)); + if (bytes_read == 0) { + return 0; + } + + size_t bytes_free = this->ring_buffer_->free(); + + if (bytes_free < bytes_read) { + ESP_LOGW(TAG, + "Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). " + "Resetting the ring buffer. Wake word detection accuracy will be reduced.", + bytes_free, bytes_read); + + this->ring_buffer_->reset(); + } + + return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); +} + +bool MicroWakeWord::allocate_buffers_() { ExternalRAMAllocator audio_samples_allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->streaming_tensor_arena_ = arena_allocator.allocate(STREAMING_MODEL_ARENA_SIZE); - if (this->streaming_tensor_arena_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena."); - return false; + if (this->input_buffer_ == nullptr) { + this->input_buffer_ = audio_samples_allocator.allocate(INPUT_BUFFER_SIZE * sizeof(int16_t)); + if (this->input_buffer_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate input buffer"); + return false; + } } - this->streaming_var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE); - if (this->streaming_var_arena_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the streaming model variable's tensor arena."); - return false; - } - - this->preprocessor_tensor_arena_ = arena_allocator.allocate(PREPROCESSOR_ARENA_SIZE); - if (this->preprocessor_tensor_arena_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the audio preprocessor model's tensor arena."); - return false; - } - - this->new_features_data_ = features_allocator.allocate(PREPROCESSOR_FEATURE_SIZE); - if (this->new_features_data_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the audio features buffer."); - return false; - } - - this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(SAMPLE_DURATION_COUNT); if (this->preprocessor_audio_buffer_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer."); - return false; + this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(this->new_samples_to_get_()); + if (this->preprocessor_audio_buffer_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer."); + return false; + } } - this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE); - if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) { - ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported"); - return false; - } - - this->streaming_model_ = tflite::GetModel(this->model_start_); - if (this->streaming_model_->version() != TFLITE_SCHEMA_VERSION) { - ESP_LOGE(TAG, "Wake word's streaming model's schema is not supported"); - return false; - } - - static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver; - static tflite::MicroMutableOpResolver<17> streaming_op_resolver; - - if (!this->register_preprocessor_ops_(preprocessor_op_resolver)) - return false; - if (!this->register_streaming_ops_(streaming_op_resolver)) - return false; - - tflite::MicroAllocator *ma = - tflite::MicroAllocator::Create(this->streaming_var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE); - this->mrv_ = tflite::MicroResourceVariables::Create(ma, 15); - - static tflite::MicroInterpreter static_preprocessor_interpreter( - this->preprocessor_model_, preprocessor_op_resolver, this->preprocessor_tensor_arena_, PREPROCESSOR_ARENA_SIZE); - - static tflite::MicroInterpreter static_streaming_interpreter(this->streaming_model_, streaming_op_resolver, - this->streaming_tensor_arena_, - STREAMING_MODEL_ARENA_SIZE, this->mrv_); - - this->preprocessor_interperter_ = &static_preprocessor_interpreter; - this->streaming_interpreter_ = &static_streaming_interpreter; - - // Allocate tensors for each models. - if (this->preprocessor_interperter_->AllocateTensors() != kTfLiteOk) { - ESP_LOGE(TAG, "Failed to allocate tensors for the audio preprocessor"); - return false; - } - if (this->streaming_interpreter_->AllocateTensors() != kTfLiteOk) { - ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model"); - return false; - } - - // Verify input tensor matches expected values - TfLiteTensor *input = this->streaming_interpreter_->input(0); - if ((input->dims->size != 3) || (input->dims->data[0] != 1) || (input->dims->data[0] != 1) || - (input->dims->data[1] != 1) || (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) { - ESP_LOGE(TAG, "Wake word detection model tensor input dimensions is not 1x1x%u", input->dims->data[2]); - return false; - } - - if (input->type != kTfLiteInt8) { - ESP_LOGE(TAG, "Wake word detection model tensor input is not int8."); - return false; - } - - // Verify output tensor matches expected values - TfLiteTensor *output = this->streaming_interpreter_->output(0); - if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) { - ESP_LOGE(TAG, "Wake word detection model tensor output dimensions is not 1x1."); - } - - if (output->type != kTfLiteUInt8) { - ESP_LOGE(TAG, "Wake word detection model tensor input is not uint8."); - return false; - } - - this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0); - - return true; -} - -bool MicroWakeWord::update_features_() { - // Retrieve strided audio samples - int16_t *audio_samples = nullptr; - if (!this->stride_audio_samples_(&audio_samples)) { - return false; - } - - // Compute the features for the newest audio samples - if (!this->generate_single_feature_(audio_samples, SAMPLE_DURATION_COUNT, this->new_features_data_)) { - return false; + if (this->ring_buffer_ == nullptr) { + this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t)); + if (this->ring_buffer_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate ring buffer"); + return false; + } } return true; } -float MicroWakeWord::perform_streaming_inference_() { - TfLiteTensor *input = this->streaming_interpreter_->input(0); - - size_t bytes_to_copy = input->bytes; - - memcpy((void *) (tflite::GetTensorData(input)), (const void *) (this->new_features_data_), bytes_to_copy); - - uint32_t prior_invoke = millis(); - - TfLiteStatus invoke_status = this->streaming_interpreter_->Invoke(); - if (invoke_status != kTfLiteOk) { - ESP_LOGW(TAG, "Streaming Interpreter Invoke failed"); - return false; - } - - ESP_LOGV(TAG, "Streaming Inference Latency=%" PRIu32 " ms", (millis() - prior_invoke)); - - TfLiteTensor *output = this->streaming_interpreter_->output(0); - - return static_cast(output->data.uint8[0]) / 255.0; +void MicroWakeWord::deallocate_buffers_() { + ExternalRAMAllocator audio_samples_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + audio_samples_allocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t)); + this->input_buffer_ = nullptr; + audio_samples_allocator.deallocate(this->preprocessor_audio_buffer_, this->new_samples_to_get_()); + this->preprocessor_audio_buffer_ = nullptr; } -bool MicroWakeWord::detect_wake_word_() { - // Preprocess the newest audio samples into features - if (!this->update_features_()) { +bool MicroWakeWord::load_models_() { + // Setup preprocesor feature generator + if (!FrontendPopulateState(&this->frontend_config_, &this->frontend_state_, AUDIO_SAMPLE_FREQUENCY)) { + ESP_LOGD(TAG, "Failed to populate frontend state"); + FrontendFreeStateContents(&this->frontend_state_); return false; } - // Perform inference - float streaming_prob = this->perform_streaming_inference_(); + // Setup streaming models + for (auto &model : this->wake_word_models_) { + if (!model.load_model(this->streaming_op_resolver_)) { + ESP_LOGE(TAG, "Failed to initialize a wake word model."); + return false; + } + } +#ifdef USE_MICRO_WAKE_WORD_VAD + if (!this->vad_model_->load_model(this->streaming_op_resolver_)) { + ESP_LOGE(TAG, "Failed to initialize VAD model."); + return false; + } +#endif - // Add the most recent probability to the sliding window - this->recent_streaming_probabilities_[this->last_n_index_] = streaming_prob; - ++this->last_n_index_; - if (this->last_n_index_ == this->sliding_window_average_size_) - this->last_n_index_ = 0; + return true; +} - float sum = 0.0; - for (auto &prob : this->recent_streaming_probabilities_) { - sum += prob; +void MicroWakeWord::unload_models_() { + FrontendFreeStateContents(&this->frontend_state_); + + for (auto &model : this->wake_word_models_) { + model.unload_model(); + } +#ifdef USE_MICRO_WAKE_WORD_VAD + this->vad_model_->unload_model(); +#endif +} + +void MicroWakeWord::update_model_probabilities_() { + int8_t audio_features[PREPROCESSOR_FEATURE_SIZE]; + + if (!this->generate_features_for_window_(audio_features)) { + return; } - float sliding_window_average = sum / static_cast(this->sliding_window_average_size_); - - // Ensure we have enough samples since the last positive detection + // Increase the counter since the last positive detection this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0); + + for (auto &model : this->wake_word_models_) { + // Perform inference + model.perform_streaming_inference(audio_features); + } +#ifdef USE_MICRO_WAKE_WORD_VAD + this->vad_model_->perform_streaming_inference(audio_features); +#endif +} + +bool MicroWakeWord::detect_wake_words_() { + // Verify we have processed samples since the last positive detection if (this->ignore_windows_ < 0) { return false; } - // Detect the wake word if the sliding window average is above the cutoff - if (sliding_window_average > this->probability_cutoff_) { - this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION; - for (auto &prob : this->recent_streaming_probabilities_) { - prob = 0; - } +#ifdef USE_MICRO_WAKE_WORD_VAD + bool vad_state = this->vad_model_->determine_detected(); +#endif - ESP_LOGD(TAG, "Wake word sliding average probability is %.3f and most recent probability is %.3f", - sliding_window_average, streaming_prob); - return true; + for (auto &model : this->wake_word_models_) { + if (model.determine_detected()) { +#ifdef USE_MICRO_WAKE_WORD_VAD + if (vad_state) { +#endif + this->detected_wake_word_ = model.get_wake_word(); + return true; +#ifdef USE_MICRO_WAKE_WORD_VAD + } else { + ESP_LOGD(TAG, "Wake word model predicts %s, but VAD model doesn't.", model.get_wake_word().c_str()); + } +#endif + } } return false; } -void MicroWakeWord::set_sliding_window_average_size(size_t size) { - this->sliding_window_average_size_ = size; - this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0); +bool MicroWakeWord::has_enough_samples_() { + return this->ring_buffer_->available() >= + (this->features_step_size_ * (AUDIO_SAMPLE_FREQUENCY / 1000)) * sizeof(int16_t); } -bool MicroWakeWord::slice_available_() { - size_t available = this->ring_buffer_->available(); - - return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t)); -} - -bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { - if (!this->slice_available_()) { +bool MicroWakeWord::generate_features_for_window_(int8_t features[PREPROCESSOR_FEATURE_SIZE]) { + // Ensure we have enough new audio samples in the ring buffer for a full window + if (!this->has_enough_samples_()) { return false; } - // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer to the start of the audio buffer - memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), - HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); - - // Copy 640 bytes (320 samples over 20 ms) from the ring buffer into the audio buffer offset 320 bytes (160 samples - // over 10 ms) - size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP), - NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200)); + size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_), + this->new_samples_to_get_() * sizeof(int16_t), pdMS_TO_TICKS(200)); if (bytes_read == 0) { ESP_LOGE(TAG, "Could not read data from Ring Buffer"); - } else if (bytes_read < NEW_SAMPLES_TO_GET * sizeof(int16_t)) { + } else if (bytes_read < this->new_samples_to_get_() * sizeof(int16_t)) { ESP_LOGD(TAG, "Partial Read of Data by Model"); ESP_LOGD(TAG, "Could only read %d bytes when required %d bytes ", bytes_read, - (int) (NEW_SAMPLES_TO_GET * sizeof(int16_t))); + (int) (this->new_samples_to_get_() * sizeof(int16_t))); return false; } - *audio_samples = this->preprocessor_audio_buffer_; - return true; -} + size_t num_samples_read; + struct FrontendOutput frontend_output = FrontendProcessSamples( + &this->frontend_state_, this->preprocessor_audio_buffer_, this->new_samples_to_get_(), &num_samples_read); -bool MicroWakeWord::generate_single_feature_(const int16_t *audio_data, const int audio_data_size, - int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]) { - TfLiteTensor *input = this->preprocessor_interperter_->input(0); - TfLiteTensor *output = this->preprocessor_interperter_->output(0); - std::copy_n(audio_data, audio_data_size, tflite::GetTensorData(input)); - - if (this->preprocessor_interperter_->Invoke() != kTfLiteOk) { - ESP_LOGE(TAG, "Failed to preprocess audio for local wake word."); - return false; + for (size_t i = 0; i < frontend_output.size; ++i) { + // These scaling values are set to match the TFLite audio frontend int8 output. + // 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 = 666; // 666 = 25.6 * 26.0 after rounding + 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; + } + features[i] = value; } - std::memcpy(feature_output, tflite::GetTensorData(output), PREPROCESSOR_FEATURE_SIZE * sizeof(int8_t)); return true; } -bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver) { - if (op_resolver.AddReshape() != kTfLiteOk) - return false; - if (op_resolver.AddCast() != kTfLiteOk) - return false; - if (op_resolver.AddStridedSlice() != kTfLiteOk) - return false; - if (op_resolver.AddConcatenation() != kTfLiteOk) - return false; - if (op_resolver.AddMul() != kTfLiteOk) - return false; - if (op_resolver.AddAdd() != kTfLiteOk) - return false; - if (op_resolver.AddDiv() != kTfLiteOk) - return false; - if (op_resolver.AddMinimum() != kTfLiteOk) - return false; - if (op_resolver.AddMaximum() != kTfLiteOk) - return false; - if (op_resolver.AddWindow() != kTfLiteOk) - return false; - if (op_resolver.AddFftAutoScale() != kTfLiteOk) - return false; - if (op_resolver.AddRfft() != kTfLiteOk) - return false; - if (op_resolver.AddEnergy() != kTfLiteOk) - return false; - if (op_resolver.AddFilterBank() != kTfLiteOk) - return false; - if (op_resolver.AddFilterBankSquareRoot() != kTfLiteOk) - return false; - if (op_resolver.AddFilterBankSpectralSubtraction() != kTfLiteOk) - return false; - if (op_resolver.AddPCAN() != kTfLiteOk) - return false; - if (op_resolver.AddFilterBankLog() != kTfLiteOk) - return false; - - return true; +void MicroWakeWord::reset_states_() { + ESP_LOGD(TAG, "Resetting buffers and probabilities"); + this->ring_buffer_->reset(); + this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION; + for (auto &model : this->wake_word_models_) { + model.reset_probabilities(); + } +#ifdef USE_MICRO_WAKE_WORD_VAD + this->vad_model_->reset_probabilities(); +#endif } -bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver) { +bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver) { if (op_resolver.AddCallOnce() != kTfLiteOk) return false; if (op_resolver.AddVarHandle() != kTfLiteOk) @@ -496,6 +442,12 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> & return false; if (op_resolver.AddMaxPool2D() != kTfLiteOk) return false; + if (op_resolver.AddPad() != kTfLiteOk) + return false; + if (op_resolver.AddPack() != kTfLiteOk) + return false; + if (op_resolver.AddSplitV() != kTfLiteOk) + return false; return true; } @@ -504,5 +456,3 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> & } // namespace esphome #endif // USE_ESP_IDF - -#endif // CLANG_TIDY diff --git a/esphome/components/micro_wake_word/micro_wake_word.h b/esphome/components/micro_wake_word/micro_wake_word.h index 1d7c18d686..0c805b75fc 100644 --- a/esphome/components/micro_wake_word/micro_wake_word.h +++ b/esphome/components/micro_wake_word/micro_wake_word.h @@ -1,21 +1,18 @@ #pragma once -/** - * This is a workaround until we can figure out a way to get - * the tflite-micro idf component code available in CI - * - * */ -// -#ifndef CLANG_TIDY - #ifdef USE_ESP_IDF +#include "preprocessor_settings.h" +#include "streaming_model.h" + #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/ring_buffer.h" #include "esphome/components/microphone/microphone.h" +#include + #include #include #include @@ -23,35 +20,6 @@ namespace esphome { namespace micro_wake_word { -// The following are dictated by the preprocessor model -// -// The number of features the audio preprocessor generates per slice -static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40; -// How frequently the preprocessor generates a new set of features -static const uint8_t FEATURE_STRIDE_MS = 20; -// Duration of each slice used as input into the preprocessor -static const uint8_t FEATURE_DURATION_MS = 30; -// Audio sample frequency in hertz -static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000; -// The number of old audio samples that are saved to be part of the next feature window -static const uint16_t HISTORY_SAMPLES_TO_KEEP = - ((FEATURE_DURATION_MS - FEATURE_STRIDE_MS) * (AUDIO_SAMPLE_FREQUENCY / 1000)); -// The number of new audio samples to receive to be included with the next feature window -static const uint16_t NEW_SAMPLES_TO_GET = (FEATURE_STRIDE_MS * (AUDIO_SAMPLE_FREQUENCY / 1000)); -// The total number of audio samples included in the feature window -static const uint16_t SAMPLE_DURATION_COUNT = FEATURE_DURATION_MS * AUDIO_SAMPLE_FREQUENCY / 1000; -// Number of bytes in memory needed for the preprocessor arena -static const uint32_t PREPROCESSOR_ARENA_SIZE = 9528; - -// The following configure the streaming wake word model -// -// The number of audio slices to process before accepting a positive detection -static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74; - -// Number of bytes in memory needed for the streaming wake word model -static const uint32_t STREAMING_MODEL_ARENA_SIZE = 64000; -static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024; - enum State { IDLE, START_MICROPHONE, @@ -61,6 +29,9 @@ enum State { STOPPING_MICROPHONE, }; +// The number of audio slices to process before accepting a positive detection +static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74; + class MicroWakeWord : public Component { public: void setup() override; @@ -73,28 +44,21 @@ class MicroWakeWord : public Component { bool is_running() const { return this->state_ != State::IDLE; } - bool initialize_models(); - - std::string get_wake_word() { return this->wake_word_; } - - // Increasing either of these will reduce the rate of false acceptances while increasing the false rejection rate - void set_probability_cutoff(float probability_cutoff) { this->probability_cutoff_ = probability_cutoff; } - void set_sliding_window_average_size(size_t size); + void set_features_step_size(uint8_t step_size) { this->features_step_size_ = step_size; } void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; } Trigger *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; } - void set_model_start(const uint8_t *model_start) { this->model_start_ = model_start; } - void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; } + void add_wake_word_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size, + const std::string &wake_word, size_t tensor_arena_size); + +#ifdef USE_MICRO_WAKE_WORD_VAD + void add_vad_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size, + size_t tensor_arena_size); +#endif protected: - void set_state_(State state); - int read_microphone_(); - - const uint8_t *model_start_; - std::string wake_word_; - microphone::Microphone *microphone_{nullptr}; Trigger *wake_word_detected_trigger_ = new Trigger(); State state_{State::IDLE}; @@ -102,85 +66,93 @@ class MicroWakeWord : public Component { std::unique_ptr ring_buffer_; - int16_t *input_buffer_; + std::vector wake_word_models_; - const tflite::Model *preprocessor_model_{nullptr}; - const tflite::Model *streaming_model_{nullptr}; - tflite::MicroInterpreter *streaming_interpreter_{nullptr}; - tflite::MicroInterpreter *preprocessor_interperter_{nullptr}; +#ifdef USE_MICRO_WAKE_WORD_VAD + std::unique_ptr vad_model_; +#endif - std::vector recent_streaming_probabilities_; - size_t last_n_index_{0}; + tflite::MicroMutableOpResolver<20> streaming_op_resolver_; - float probability_cutoff_{0.5}; - size_t sliding_window_average_size_{10}; + // Audio frontend handles generating spectrogram features + struct FrontendConfig frontend_config_; + struct FrontendState frontend_state_; - // When the wake word detection first starts or after the word has been detected once, we ignore this many audio - // feature slices before accepting a positive detection again + // When the wake word detection first starts, we ignore this many audio + // feature slices before accepting a positive detection int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION}; - uint8_t *streaming_var_arena_{nullptr}; - uint8_t *streaming_tensor_arena_{nullptr}; - uint8_t *preprocessor_tensor_arena_{nullptr}; - int8_t *new_features_data_{nullptr}; + uint8_t features_step_size_; - tflite::MicroResourceVariables *mrv_{nullptr}; - - // Stores audio fed into feature generator preprocessor - int16_t *preprocessor_audio_buffer_; + // Stores audio read from the microphone before being added to the ring buffer. + int16_t *input_buffer_{nullptr}; + // Stores audio to be fed into the audio frontend for generating features. + int16_t *preprocessor_audio_buffer_{nullptr}; bool detected_{false}; + std::string detected_wake_word_{""}; - /** Detects if wake word has been said + void set_state_(State state); + + /// @brief Tests if there are enough samples in the ring buffer to generate new features. + /// @return True if enough samples, false otherwise. + bool has_enough_samples_(); + + /** Reads audio from microphone into the ring buffer + * + * Audio data (16000 kHz with int16 samples) is read into the input_buffer_. + * Verifies the ring buffer has enough space for all audio data. If not, it logs + * a warning and resets the ring buffer entirely. + * @return Number of bytes written to the ring buffer + */ + size_t read_microphone_(); + + /// @brief Allocates memory for input_buffer_, preprocessor_audio_buffer_, and ring_buffer_ + /// @return True if successful, false otherwise + bool allocate_buffers_(); + + /// @brief Frees memory allocated for input_buffer_ and preprocessor_audio_buffer_ + void deallocate_buffers_(); + + /// @brief Loads streaming models and prepares the feature generation frontend + /// @return True if successful, false otherwise + bool load_models_(); + + /// @brief Deletes each model's TFLite interpreters and frees tensor arena memory. Frees memory used by the feature + /// generation frontend. + void unload_models_(); + + /** Performs inference with each configured model * * If enough audio samples are available, it will generate one slice of new features. - * If the streaming model predicts the wake word, then the nonstreaming model confirms it. - * @param ring_Buffer Ring buffer containing raw audio samples - * @return True if the wake word is detected, false otherwise + * It then loops through and performs inference with each of the loaded models. */ - bool detect_wake_word_(); + void update_model_probabilities_(); - /// @brief Returns true if there are enough audio samples in the buffer to generate another slice of features - bool slice_available_(); - - /** Shifts previous feature slices over by one and generates a new slice of features + /** Checks every model's recent probabilities to determine if the wake word has been predicted * - * @param ring_buffer ring buffer containing raw audio samples - * @return True if a new slice of features was generated, false otherwise + * Verifies the models have processed enough new samples for accurate predictions. + * Sets detected_wake_word_ to the wake word, if one is detected. + * @return True if a wake word is predicted, false otherwise */ - bool update_features_(); + bool detect_wake_words_(); - /** Generates features from audio samples + /** Generates features for a window of audio samples * - * Adapted from TFLite micro speech example - * @param audio_data Pointer to array with the audio samples - * @param audio_data_size The number of samples to use as input to the preprocessor model - * @param feature_output Array that will store the features + * Reads samples from the ring buffer and feeds them into the preprocessor frontend. + * Adapted from TFLite microspeech frontend. + * @param features int8_t array to store the audio features * @return True if successful, false otherwise. */ - bool generate_single_feature_(const int16_t *audio_data, int audio_data_size, - int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]); + bool generate_features_for_window_(int8_t features[PREPROCESSOR_FEATURE_SIZE]); - /** Performs inference over the most recent feature slice with the streaming model - * - * @return Probability of the wake word between 0.0 and 1.0 - */ - float perform_streaming_inference_(); - - /** Strides the audio samples by keeping the last 10 ms of the previous slice - * - * Adapted from the TFLite micro speech example - * @param ring_buffer Ring buffer containing raw audio samples - * @param audio_samples Pointer to an array that will store the strided audio samples - * @return True if successful, false otherwise - */ - bool stride_audio_samples_(int16_t **audio_samples); - - /// @brief Returns true if successfully registered the preprocessor's TensorFlow operations - bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver); + /// @brief Resets the ring buffer, ignore_windows_, and sliding window probabilities + void reset_states_(); /// @brief Returns true if successfully registered the streaming model's TensorFlow operations - bool register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver); + bool register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver); + + inline uint16_t new_samples_to_get_() { return (this->features_step_size_ * (AUDIO_SAMPLE_FREQUENCY / 1000)); } }; template class StartAction : public Action, public Parented { @@ -202,5 +174,3 @@ template class IsRunningCondition : public Condition, pub } // namespace esphome #endif // USE_ESP_IDF - -#endif // CLANG_TIDY diff --git a/esphome/components/micro_wake_word/preprocessor_settings.h b/esphome/components/micro_wake_word/preprocessor_settings.h new file mode 100644 index 0000000000..03f4fb5230 --- /dev/null +++ b/esphome/components/micro_wake_word/preprocessor_settings.h @@ -0,0 +1,20 @@ +#pragma once + +#ifdef USE_ESP_IDF + +#include + +namespace esphome { +namespace micro_wake_word { + +// The number of features the audio preprocessor generates per slice +static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40; +// Duration of each slice used as input into the preprocessor +static const uint8_t FEATURE_DURATION_MS = 30; +// Audio sample frequency in hertz +static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000; + +} // namespace micro_wake_word +} // namespace esphome + +#endif diff --git a/esphome/components/micro_wake_word/streaming_model.cpp b/esphome/components/micro_wake_word/streaming_model.cpp new file mode 100644 index 0000000000..013fa2ce6e --- /dev/null +++ b/esphome/components/micro_wake_word/streaming_model.cpp @@ -0,0 +1,189 @@ +#ifdef USE_ESP_IDF + +#include "streaming_model.h" + +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +static const char *const TAG = "micro_wake_word"; + +namespace esphome { +namespace micro_wake_word { + +void WakeWordModel::log_model_config() { + ESP_LOGCONFIG(TAG, " - Wake Word: %s", this->wake_word_.c_str()); + ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_); + ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_); +} + +void VADModel::log_model_config() { + ESP_LOGCONFIG(TAG, " - VAD Model"); + ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_); + ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_); +} + +bool StreamingModel::load_model(tflite::MicroMutableOpResolver<20> &op_resolver) { + ExternalRAMAllocator arena_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + + if (this->tensor_arena_ == nullptr) { + this->tensor_arena_ = arena_allocator.allocate(this->tensor_arena_size_); + if (this->tensor_arena_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena."); + return false; + } + } + + if (this->var_arena_ == nullptr) { + this->var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE); + if (this->var_arena_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate the streaming model's variable tensor arena."); + return false; + } + this->ma_ = tflite::MicroAllocator::Create(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE); + this->mrv_ = tflite::MicroResourceVariables::Create(this->ma_, 20); + } + + const tflite::Model *model = tflite::GetModel(this->model_start_); + if (model->version() != TFLITE_SCHEMA_VERSION) { + ESP_LOGE(TAG, "Streaming model's schema is not supported"); + return false; + } + + if (this->interpreter_ == nullptr) { + this->interpreter_ = make_unique( + tflite::GetModel(this->model_start_), op_resolver, this->tensor_arena_, this->tensor_arena_size_, this->mrv_); + if (this->interpreter_->AllocateTensors() != kTfLiteOk) { + ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model"); + return false; + } + + // Verify input tensor matches expected values + // Dimension 3 will represent the first layer stride, so skip it may vary + TfLiteTensor *input = this->interpreter_->input(0); + if ((input->dims->size != 3) || (input->dims->data[0] != 1) || + (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) { + ESP_LOGE(TAG, "Streaming model tensor input dimensions has improper dimensions."); + return false; + } + + if (input->type != kTfLiteInt8) { + ESP_LOGE(TAG, "Streaming model tensor input is not int8."); + return false; + } + + // Verify output tensor matches expected values + TfLiteTensor *output = this->interpreter_->output(0); + if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) { + ESP_LOGE(TAG, "Streaming model tensor output dimension is not 1x1."); + } + + if (output->type != kTfLiteUInt8) { + ESP_LOGE(TAG, "Streaming model tensor output is not uint8."); + return false; + } + } + + return true; +} + +void StreamingModel::unload_model() { + this->interpreter_.reset(); + + ExternalRAMAllocator arena_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + + arena_allocator.deallocate(this->tensor_arena_, this->tensor_arena_size_); + this->tensor_arena_ = nullptr; + arena_allocator.deallocate(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE); + this->var_arena_ = nullptr; +} + +bool StreamingModel::perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]) { + if (this->interpreter_ != nullptr) { + TfLiteTensor *input = this->interpreter_->input(0); + + std::memmove( + (int8_t *) (tflite::GetTensorData(input)) + PREPROCESSOR_FEATURE_SIZE * this->current_stride_step_, + features, PREPROCESSOR_FEATURE_SIZE); + ++this->current_stride_step_; + + uint8_t stride = this->interpreter_->input(0)->dims->data[1]; + + if (this->current_stride_step_ >= stride) { + this->current_stride_step_ = 0; + + TfLiteStatus invoke_status = this->interpreter_->Invoke(); + if (invoke_status != kTfLiteOk) { + ESP_LOGW(TAG, "Streaming interpreter invoke failed"); + return false; + } + + TfLiteTensor *output = this->interpreter_->output(0); + + ++this->last_n_index_; + if (this->last_n_index_ == this->sliding_window_size_) + this->last_n_index_ = 0; + this->recent_streaming_probabilities_[this->last_n_index_] = output->data.uint8[0]; // probability; + } + return true; + } + ESP_LOGE(TAG, "Streaming interpreter is not initialized."); + return false; +} + +void StreamingModel::reset_probabilities() { + for (auto &prob : this->recent_streaming_probabilities_) { + prob = 0; + } +} + +WakeWordModel::WakeWordModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size, + const std::string &wake_word, size_t tensor_arena_size) { + this->model_start_ = model_start; + this->probability_cutoff_ = probability_cutoff; + this->sliding_window_size_ = sliding_window_average_size; + this->recent_streaming_probabilities_.resize(sliding_window_average_size, 0); + this->wake_word_ = wake_word; + this->tensor_arena_size_ = tensor_arena_size; +}; + +bool WakeWordModel::determine_detected() { + int32_t sum = 0; + for (auto &prob : this->recent_streaming_probabilities_) { + sum += prob; + } + + float sliding_window_average = static_cast(sum) / static_cast(255 * this->sliding_window_size_); + + // Detect the wake word if the sliding window average is above the cutoff + if (sliding_window_average > this->probability_cutoff_) { + ESP_LOGD(TAG, "The '%s' model sliding average probability is %.3f and most recent probability is %.3f", + this->wake_word_.c_str(), sliding_window_average, + this->recent_streaming_probabilities_[this->last_n_index_] / (255.0)); + return true; + } + return false; +} + +VADModel::VADModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size, + size_t tensor_arena_size) { + this->model_start_ = model_start; + this->probability_cutoff_ = probability_cutoff; + this->sliding_window_size_ = sliding_window_size; + this->recent_streaming_probabilities_.resize(sliding_window_size, 0); + this->tensor_arena_size_ = tensor_arena_size; +}; + +bool VADModel::determine_detected() { + uint8_t max = 0; + for (auto &prob : this->recent_streaming_probabilities_) { + max = std::max(prob, max); + } + + return max > this->probability_cutoff_; +} + +} // namespace micro_wake_word +} // namespace esphome + +#endif diff --git a/esphome/components/micro_wake_word/streaming_model.h b/esphome/components/micro_wake_word/streaming_model.h new file mode 100644 index 0000000000..0d85579f35 --- /dev/null +++ b/esphome/components/micro_wake_word/streaming_model.h @@ -0,0 +1,84 @@ +#pragma once + +#ifdef USE_ESP_IDF + +#include "preprocessor_settings.h" + +#include +#include +#include + +namespace esphome { +namespace micro_wake_word { + +static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024; + +class StreamingModel { + public: + virtual void log_model_config() = 0; + virtual bool determine_detected() = 0; + + bool perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]); + + /// @brief Sets all recent_streaming_probabilities to 0 + void reset_probabilities(); + + /// @brief Allocates tensor and variable arenas and sets up the model interpreter + /// @param op_resolver MicroMutableOpResolver object that must exist until the model is unloaded + /// @return True if successful, false otherwise + bool load_model(tflite::MicroMutableOpResolver<20> &op_resolver); + + /// @brief Destroys the TFLite interpreter and frees the tensor and variable arenas' memory + void unload_model(); + + protected: + uint8_t current_stride_step_{0}; + + float probability_cutoff_; + size_t sliding_window_size_; + size_t last_n_index_{0}; + size_t tensor_arena_size_; + std::vector recent_streaming_probabilities_; + + const uint8_t *model_start_; + uint8_t *tensor_arena_{nullptr}; + uint8_t *var_arena_{nullptr}; + std::unique_ptr interpreter_; + tflite::MicroResourceVariables *mrv_{nullptr}; + tflite::MicroAllocator *ma_{nullptr}; +}; + +class WakeWordModel final : public StreamingModel { + public: + WakeWordModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size, + const std::string &wake_word, size_t tensor_arena_size); + + void log_model_config() override; + + /// @brief Checks for the wake word by comparing the mean probability in the sliding window with the probability + /// cutoff + /// @return True if wake word is detected, false otherwise + bool determine_detected() override; + + const std::string &get_wake_word() const { return this->wake_word_; } + + protected: + std::string wake_word_; +}; + +class VADModel final : public StreamingModel { + public: + VADModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size, size_t tensor_arena_size); + + void log_model_config() override; + + /// @brief Checks for voice activity by comparing the max probability in the sliding window with the probability + /// cutoff + /// @return True if voice activity is detected, false otherwise + bool determine_detected() override; +}; + +} // namespace micro_wake_word +} // namespace esphome + +#endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1e6f3517db..4831ed2c9e 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -86,6 +86,7 @@ #define USE_ESP32_BLE_SERVER #define USE_ESP32_CAMERA #define USE_IMPROV +#define USE_MICRO_WAKE_WORD_VAD #define USE_MICROPHONE #define USE_PSRAM #define USE_SOCKET_IMPL_BSD_SOCKETS diff --git a/platformio.ini b/platformio.ini index a72bf598c5..f07889526f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -142,7 +142,8 @@ platform_packages = framework = espidf lib_deps = ${common:idf.lib_deps} - droscy/esp_wireguard@0.4.2 ; wireguard + droscy/esp_wireguard@0.4.2 ; wireguard + kahrendt/ESPMicroSpeechFeatures@1.0.0 ; micro_wake_word build_flags = ${common:idf.build_flags} -Wno-nonnull-compare diff --git a/tests/components/micro_wake_word/common.yaml b/tests/components/micro_wake_word/common.yaml index c0f3593cc6..8bd7345307 100644 --- a/tests/components/micro_wake_word/common.yaml +++ b/tests/components/micro_wake_word/common.yaml @@ -10,6 +10,10 @@ microphone: pdm: true micro_wake_word: - model: hey_jarvis on_wake_word_detected: - logger.log: "Wake word detected" + models: + - model: hey_jarvis + probability_cutoff: 0.7 + - model: okay_nabu + sliding_window_size: 5 diff --git a/tests/components/micro_wake_word/test.esp32-idf.yaml b/tests/components/micro_wake_word/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/micro_wake_word/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From aa8c963c50467b194fa5d7ebb25f81a6692d3d19 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Thu, 11 Jul 2024 03:30:55 +0200 Subject: [PATCH 2032/2607] UART component support added for host platform (#6912) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Pavlo Dudnytskyi --- esphome/components/uart/__init__.py | 66 +++- .../components/uart/uart_component_host.cpp | 295 ++++++++++++++++++ esphome/components/uart/uart_component_host.h | 38 +++ tests/components/uart/test.host.yaml | 13 + 4 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 esphome/components/uart/uart_component_host.cpp create mode 100644 esphome/components/uart/uart_component_host.h create mode 100644 tests/components/uart/test.host.yaml diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index b036288078..0738a127e1 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -1,5 +1,5 @@ from typing import Optional - +import re import esphome.codegen as cg import esphome.config_validation as cv import esphome.final_validate as fv @@ -11,6 +11,7 @@ from esphome.const import ( CONF_NUMBER, CONF_RX_PIN, CONF_TX_PIN, + CONF_PORT, CONF_UART_ID, CONF_DATA, CONF_RX_BUFFER_SIZE, @@ -27,6 +28,7 @@ from esphome.const import ( CONF_DUMMY_RECEIVER, CONF_DUMMY_RECEIVER_ID, CONF_LAMBDA, + PLATFORM_HOST, ) from esphome.core import CORE @@ -45,6 +47,7 @@ RP2040UartComponent = uart_ns.class_("RP2040UartComponent", UARTComponent, cg.Co LibreTinyUARTComponent = uart_ns.class_( "LibreTinyUARTComponent", UARTComponent, cg.Component ) +HostUartComponent = uart_ns.class_("HostUartComponent", UARTComponent, cg.Component) NATIVE_UART_CLASSES = ( str(IDFUARTComponent), @@ -54,6 +57,39 @@ NATIVE_UART_CLASSES = ( str(LibreTinyUARTComponent), ) +HOST_BAUD_RATES = [ + 50, + 75, + 110, + 134, + 150, + 200, + 300, + 600, + 1200, + 1800, + 2400, + 4800, + 9600, + 19200, + 38400, + 57600, + 115200, + 230400, + 460800, + 500000, + 576000, + 921600, + 1000000, + 1152000, + 1500000, + 2000000, + 2500000, + 3000000, + 3500000, + 4000000, +] + UARTDevice = uart_ns.class_("UARTDevice") UARTWriteAction = uart_ns.class_("UARTWriteAction", automation.Action) UARTDebugger = uart_ns.class_("UARTDebugger", cg.Component, automation.Action) @@ -95,6 +131,20 @@ def validate_invert_esp32(config): return config +def validate_host_config(config): + if CORE.is_host: + if CONF_TX_PIN in config or CONF_RX_PIN in config: + raise cv.Invalid( + "TX and RX pins are not supported for UART on host platform." + ) + if config[CONF_BAUD_RATE] not in HOST_BAUD_RATES: + raise cv.Invalid( + f"Host platform doesn't support baud rate {config[CONF_BAUD_RATE]}", + path=[CONF_BAUD_RATE], + ) + return config + + def _uart_declare_type(value): if CORE.is_esp8266: return cv.declare_id(ESP8266UartComponent)(value) @@ -107,6 +157,8 @@ def _uart_declare_type(value): return cv.declare_id(RP2040UartComponent)(value) if CORE.is_libretiny: return cv.declare_id(LibreTinyUARTComponent)(value) + if CORE.is_host: + return cv.declare_id(HostUartComponent)(value) raise NotImplementedError @@ -149,6 +201,12 @@ def maybe_empty_debug(value): return DEBUG_SCHEMA(value) +def validate_port(value): + if not re.match(r"^/(?:[^/]+/)[^/]+$", value): + raise cv.Invalid("Port must be a valid device path") + return value + + DEBUG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UARTDebugger), @@ -181,6 +239,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_BAUD_RATE): cv.int_range(min=1), cv.Optional(CONF_TX_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_RX_PIN): validate_rx_pin, + cv.Optional(CONF_PORT): cv.All(validate_port, cv.only_on(PLATFORM_HOST)), cv.Optional(CONF_RX_BUFFER_SIZE, default=256): cv.validate_bytes, cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True), cv.Optional(CONF_DATA_BITS, default=8): cv.int_range(min=5, max=8), @@ -193,8 +252,9 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DEBUG): maybe_empty_debug, } ).extend(cv.COMPONENT_SCHEMA), - cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN), + cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN, CONF_PORT), validate_invert_esp32, + validate_host_config, ) @@ -236,6 +296,8 @@ async def to_code(config): if CONF_RX_PIN in config: rx_pin = await cg.gpio_pin_expression(config[CONF_RX_PIN]) cg.add(var.set_rx_pin(rx_pin)) + if CONF_PORT in config: + cg.add(var.set_name(config[CONF_PORT])) cg.add(var.set_rx_buffer_size(config[CONF_RX_BUFFER_SIZE])) cg.add(var.set_stop_bits(config[CONF_STOP_BITS])) cg.add(var.set_data_bits(config[CONF_DATA_BITS])) diff --git a/esphome/components/uart/uart_component_host.cpp b/esphome/components/uart/uart_component_host.cpp new file mode 100644 index 0000000000..d8d2fd75b8 --- /dev/null +++ b/esphome/components/uart/uart_component_host.cpp @@ -0,0 +1,295 @@ +#ifdef USE_HOST +#include "uart_component_host.h" +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#ifndef __linux__ +#error This HostUartComponent implementation is only for Linux +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_LOGGER +#include "esphome/components/logger/logger.h" +#endif + +namespace { + +speed_t get_baud(int baud) { + switch (baud) { + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return B0; + } +} + +} // namespace + +namespace esphome { +namespace uart { + +static const char *const TAG = "uart.host"; + +HostUartComponent::~HostUartComponent() { + if (this->file_descriptor_ != -1) { + close(this->file_descriptor_); + this->file_descriptor_ = -1; + } +} + +void HostUartComponent::setup() { + ESP_LOGCONFIG(TAG, "Opening UART port..."); + speed_t baud = get_baud(this->baud_rate_); + if (baud == B0) { + ESP_LOGE(TAG, "Unsupported baud rate: %d", this->baud_rate_); + this->mark_failed(); + return; + } + this->file_descriptor_ = ::open(this->port_name_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (this->file_descriptor_ == -1) { + this->update_error_(strerror(errno)); + this->mark_failed(); + return; + } + fcntl(this->file_descriptor_, F_SETFL, 0); + struct termios options; + tcgetattr(this->file_descriptor_, &options); + options.c_cflag &= ~CRTSCTS; + options.c_cflag |= CREAD | CLOCAL; + options.c_lflag &= ~ICANON; + options.c_lflag &= ~ECHO; + options.c_lflag &= ~ECHOE; + options.c_lflag &= ~ECHONL; + options.c_lflag &= ~ISIG; + options.c_iflag &= ~(IXON | IXOFF | IXANY); + options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); + options.c_oflag &= ~OPOST; + options.c_oflag &= ~ONLCR; + // Set data bits + options.c_cflag &= ~CSIZE; // Mask the character size bits + switch (this->data_bits_) { + case 5: + options.c_cflag |= CS5; + break; + case 6: + options.c_cflag |= CS6; + break; + case 7: + options.c_cflag |= CS7; + break; + case 8: + default: + options.c_cflag |= CS8; + break; + } + // Set parity + switch (this->parity_) { + case UART_CONFIG_PARITY_NONE: + options.c_cflag &= ~PARENB; + break; + case UART_CONFIG_PARITY_EVEN: + options.c_cflag |= PARENB; + options.c_cflag &= ~PARODD; + break; + case UART_CONFIG_PARITY_ODD: + options.c_cflag |= PARENB; + options.c_cflag |= PARODD; + break; + }; + // Set stop bits + if (this->stop_bits_ == 2) { + options.c_cflag |= CSTOPB; + } else { + options.c_cflag &= ~CSTOPB; + } + cfsetispeed(&options, baud); + cfsetospeed(&options, baud); + tcsetattr(this->file_descriptor_, TCSANOW, &options); +} + +void HostUartComponent::dump_config() { + ESP_LOGCONFIG(TAG, "UART:"); + ESP_LOGCONFIG(TAG, " Port: %s", this->port_name_.c_str()); + if (this->file_descriptor_ == -1) { + ESP_LOGCONFIG(TAG, " Port status: Not opened"); + if (!this->first_error_.empty()) { + ESP_LOGCONFIG(TAG, " Error: %s", this->first_error_.c_str()); + } + return; + } + ESP_LOGCONFIG(TAG, " Port status: opened"); + ESP_LOGCONFIG(TAG, " Baud Rate: %d", this->baud_rate_); + ESP_LOGCONFIG(TAG, " Data Bits: %d", this->data_bits_); + ESP_LOGCONFIG(TAG, " Parity: %s", + this->parity_ == UART_CONFIG_PARITY_NONE ? "None" + : this->parity_ == UART_CONFIG_PARITY_EVEN ? "Even" + : "Odd"); + ESP_LOGCONFIG(TAG, " Stop Bits: %d", this->stop_bits_); + this->check_logger_conflict(); +} + +void HostUartComponent::write_array(const uint8_t *data, size_t len) { + if (this->file_descriptor_ == -1) { + return; + } + size_t written = ::write(this->file_descriptor_, data, len); + if (written != len) { + this->update_error_(strerror(errno)); + return; + } +#ifdef USE_UART_DEBUGGER + for (size_t i = 0; i < len; i++) { + this->debug_callback_.call(UART_DIRECTION_TX, data[i]); + } +#endif + return; +} + +bool HostUartComponent::peek_byte(uint8_t *data) { + if (this->file_descriptor_ == -1) { + return false; + } + if (!this->has_peek_) { + if (!this->check_read_timeout_()) { + return false; + } + if (::read(this->file_descriptor_, &this->peek_byte_, 1) != 1) { + this->update_error_(strerror(errno)); + return false; + } + this->has_peek_ = true; + } + *data = this->peek_byte_; + return true; +} + +bool HostUartComponent::read_array(uint8_t *data, size_t len) { + if ((this->file_descriptor_ == -1) || (len == 0)) { + return false; + } + if (!this->check_read_timeout_(len)) + return false; + uint8_t *data_ptr = data; + size_t length_to_read = len; + if (this->has_peek_) { + length_to_read--; + *data_ptr = this->peek_byte_; + data_ptr++; + this->has_peek_ = false; + } + if (length_to_read > 0) { + int sz = ::read(this->file_descriptor_, data_ptr, length_to_read); + if (sz == -1) { + this->update_error_(strerror(errno)); + return false; + } + } +#ifdef USE_UART_DEBUGGER + for (size_t i = 0; i < len; i++) { + this->debug_callback_.call(UART_DIRECTION_RX, data[i]); + } +#endif + return true; +} + +int HostUartComponent::available() { + if (this->file_descriptor_ == -1) { + return 0; + } + int available; + int res = ioctl(this->file_descriptor_, FIONREAD, &available); + if (res == -1) { + this->update_error_(strerror(errno)); + return 0; + } + if (this->has_peek_) + available++; + return available; +}; + +void HostUartComponent::flush() { + if (this->file_descriptor_ == -1) { + return; + } + tcflush(this->file_descriptor_, TCIOFLUSH); + ESP_LOGV(TAG, " Flushing..."); +} + +void HostUartComponent::update_error_(const std::string &error) { + if (this->first_error_.empty()) { + this->first_error_ = error; + } + ESP_LOGE(TAG, "Port error: %s", error.c_str()); +} + +} // namespace uart +} // namespace esphome + +#endif // USE_HOST diff --git a/esphome/components/uart/uart_component_host.h b/esphome/components/uart/uart_component_host.h new file mode 100644 index 0000000000..c1f1dd0d2c --- /dev/null +++ b/esphome/components/uart/uart_component_host.h @@ -0,0 +1,38 @@ +#pragma once + +#ifdef USE_HOST + +#include "esphome/core/component.h" +#include "esphome/core/log.h" +#include "uart_component.h" + +namespace esphome { +namespace uart { + +class HostUartComponent : public UARTComponent, public Component { + public: + virtual ~HostUartComponent(); + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::BUS; } + void write_array(const uint8_t *data, size_t len) override; + bool peek_byte(uint8_t *data) override; + bool read_array(uint8_t *data, size_t len) override; + int available() override; + void flush() override; + void set_name(std::string port_name) { port_name_ = port_name; }; + + protected: + void update_error_(const std::string &error); + void check_logger_conflict() override {} + std::string port_name_; + std::string first_error_{""}; + int file_descriptor_ = -1; + bool has_peek_{false}; + uint8_t peek_byte_; +}; + +} // namespace uart +} // namespace esphome + +#endif // USE_HOST diff --git a/tests/components/uart/test.host.yaml b/tests/components/uart/test.host.yaml new file mode 100644 index 0000000000..63f0ade084 --- /dev/null +++ b/tests/components/uart/test.host.yaml @@ -0,0 +1,13 @@ +esphome: + on_boot: + then: + - uart.write: 'Hello World' + - uart.write: [0x00, 0x20, 0x42] + +uart: + - id: uart_uart + port: "/dev/ttyS0" + baud_rate: 9600 + data_bits: 8 + parity: EVEN + stop_bits: 2 From 2f669c99f8954ccc8c960fb527040ae2febe13cf Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 11 Jul 2024 03:32:17 +0200 Subject: [PATCH 2033/2607] Configure ap ip for RP2040 (#7065) --- .../components/wifi/wifi_component_pico_w.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 2bb1af5489..4afcf2d78b 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -141,13 +141,29 @@ bool WiFiComponent::wifi_scan_start_(bool passive) { #ifdef USE_WIFI_AP bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { - // TODO: - return false; + esphome::network::IPAddress ip_address, gateway, subnet, dns; + if (manual_ip.has_value()) { + ip_address = manual_ip->static_ip; + gateway = manual_ip->gateway; + subnet = manual_ip->subnet; + dns = manual_ip->static_ip; + } else { + ip_address = network::IPAddress(192, 168, 4, 1); + gateway = network::IPAddress(192, 168, 4, 1); + subnet = network::IPAddress(255, 255, 255, 0); + dns = network::IPAddress(192, 168, 4, 1); + } + WiFi.config(ip_address, dns, gateway, subnet); + return true; } bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { if (!this->wifi_mode_({}, true)) return false; + if (!this->wifi_ap_ip_config_(ap.get_manual_ip())) { + ESP_LOGV(TAG, "wifi_ap_ip_config_ failed!"); + return false; + } WiFi.beginAP(ap.get_ssid().c_str(), ap.get_password().c_str(), ap.get_channel().value_or(1)); From d1b0e6b5fe11d0e77e20432c11f8f68b421ac841 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:41:48 +1200 Subject: [PATCH 2034/2607] Bump version to 2024.8.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 543b1d00cc..faf6ce19fa 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0-dev" +__version__ = "2024.8.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6417f1f907d0dbbef3f2011905a3cb7c9abf9763 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:41:48 +1200 Subject: [PATCH 2035/2607] Bump version to 2024.7.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 543b1d00cc..d672cc92af 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0-dev" +__version__ = "2024.7.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From fb6c2aef59d5b3ca1463705eba01d0eb3de19535 Mon Sep 17 00:00:00 2001 From: Christian Ferbar <5595808+ferbar@users.noreply.github.com> Date: Thu, 11 Jul 2024 05:58:54 +0200 Subject: [PATCH 2036/2607] helpers.cpp: Fix GLIBCXX_RELEASE check < 8 (#7062) --- esphome/core/helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 7f040f855f..e75b06ccd3 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -78,7 +78,7 @@ static const uint16_t CRC16_1021_BE_LUT_H[] = {0x0000, 0x1231, 0x2462, 0x3653, 0 // STL backports -#if _GLIBCXX_RELEASE < 7 +#if _GLIBCXX_RELEASE < 8 std::string to_string(int value) { return str_snprintf("%d", 32, value); } // NOLINT std::string to_string(long value) { return str_snprintf("%ld", 32, value); } // NOLINT std::string to_string(long long value) { return str_snprintf("%lld", 32, value); } // NOLINT From fa4fbf9d7384e1962e2982ab2ad0db449d33e4c6 Mon Sep 17 00:00:00 2001 From: Z3LIFF Date: Thu, 11 Jul 2024 00:01:14 -0400 Subject: [PATCH 2037/2607] Fix pmsa003i cold boot marked as failed on ESP32 et al (#7064) --- esphome/components/pmsa003i/pmsa003i.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/esphome/components/pmsa003i/pmsa003i.cpp b/esphome/components/pmsa003i/pmsa003i.cpp index ca3d28367a..a9665c6a5a 100644 --- a/esphome/components/pmsa003i/pmsa003i.cpp +++ b/esphome/components/pmsa003i/pmsa003i.cpp @@ -13,6 +13,15 @@ void PMSA003IComponent::setup() { PM25AQIData data; bool successful_read = this->read_data_(&data); + if (!successful_read) { + for (int i = 0; i < 3; i++) { + successful_read = this->read_data_(&data); + if (successful_read) { + break; + } + } + } + if (!successful_read) { this->mark_failed(); return; From dea1e9a1e05ea1b01c3a70d6789d02569498becf Mon Sep 17 00:00:00 2001 From: guillempages Date: Thu, 11 Jul 2024 06:08:51 +0200 Subject: [PATCH 2038/2607] [http_request] Fix follow_redirects on arduino (#7054) --- esphome/components/http_request/http_request_arduino.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index 248a85a439..95b1cdc38e 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -32,6 +32,13 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s watchdog::WatchdogManager wdm(this->get_watchdog_timeout()); + if (this->follow_redirects_) { + container->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); + container->client_.setRedirectLimit(this->redirect_limit_); + } else { + container->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS); + } + #if defined(USE_ESP8266) std::unique_ptr stream_ptr; #ifdef USE_HTTP_REQUEST_ESP8266_HTTPS @@ -59,8 +66,6 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s "in your YAML, or use HTTPS"); } #endif // USE_ARDUINO_VERSION_CODE - - container->client_.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); bool status = container->client_.begin(*stream_ptr, url.c_str()); #elif defined(USE_RP2040) From ee4d5178d6fa54dcc8069b86bfdd63571d8a4f9e Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 11 Jul 2024 06:09:51 +0200 Subject: [PATCH 2039/2607] [ethernet] Fix compile warning for IPv6 (#7048) --- esphome/components/ethernet/ethernet_component.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 6b34157b9d..962a864a29 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -394,7 +394,7 @@ void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_b const esp_netif_ip_info_t *ip_info = &event->ip_info; ESP_LOGV(TAG, "[Ethernet event] ETH Got IP " IPSTR, IP2STR(&ip_info->ip)); global_eth_component->got_ipv4_address_ = true; -#if USE_NETWORK_IPV6 +#if USE_NETWORK_IPV6 && (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0) global_eth_component->connected_ = global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT; #else global_eth_component->connected_ = true; @@ -407,8 +407,12 @@ void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_ ip_event_got_ip6_t *event = (ip_event_got_ip6_t *) event_data; ESP_LOGV(TAG, "[Ethernet event] ETH Got IPv6: " IPV6STR, IPV62STR(event->ip6_info.ip)); global_eth_component->ipv6_count_ += 1; +#if (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0) global_eth_component->connected_ = global_eth_component->got_ipv4_address_ && (global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT); +#else + global_eth_component->connected_ = global_eth_component->got_ipv4_address_; +#endif } #endif /* USE_NETWORK_IPV6 */ From 1b57d8511be329fac18c039d22ac06679e616b8f Mon Sep 17 00:00:00 2001 From: esphomebot Date: Thu, 11 Jul 2024 16:10:18 +1200 Subject: [PATCH 2040/2607] Update webserver local assets to 20240704-081526 (#7041) --- .../components/web_server/server_index_v2.h | 83 +- .../components/web_server/server_index_v3.h | 735 +++++++++--------- 2 files changed, 410 insertions(+), 408 deletions(-) diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index c942cda592..c9932624ba 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -68,7 +68,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe3, 0x9b, 0x82, 0xde, 0xc5, 0x0e, 0x21, 0xa9, 0x64, 0x54, 0x44, 0x2c, 0x97, 0x29, 0x21, 0x29, 0xc2, 0x3f, 0x90, 0x45, 0x68, 0xd6, 0x13, 0xec, 0x34, 0x30, 0x9c, 0xcb, 0x40, 0x71, 0x17, 0x3c, 0xe0, 0xc9, 0x9c, 0xa6, 0x82, 0xa6, 0xc1, 0x5f, 0x71, 0x4a, 0x87, 0x31, 0x40, 0xb1, 0xd3, 0xc4, 0xe3, 0x30, 0x3b, 0x1f, 0x87, 0xc9, 0x88, 0x46, 0xc1, - 0x8d, 0xc8, 0xf1, 0xdf, 0x89, 0x3b, 0x64, 0x49, 0x18, 0xb3, 0x5f, 0x69, 0xe4, 0x6a, 0x69, 0x70, 0xeb, 0xd0, 0x5b, + 0x8d, 0xc8, 0xf1, 0xdf, 0x89, 0x3b, 0x64, 0x49, 0x18, 0xb3, 0x5f, 0x69, 0xe4, 0x6a, 0x69, 0x70, 0xe6, 0xd0, 0x5b, 0x41, 0x93, 0x28, 0x73, 0x9e, 0xbf, 0x7b, 0xf9, 0x42, 0xef, 0x63, 0x45, 0x40, 0xa0, 0x45, 0x36, 0x9b, 0xd2, 0xd4, 0x43, 0x58, 0x0b, 0x88, 0x67, 0x4c, 0x32, 0xc7, 0x97, 0xe1, 0x54, 0x95, 0xb0, 0xec, 0xfd, 0x34, 0x0a, 0x05, 0x7d, 0x43, 0x93, 0x88, 0x25, 0x23, 0xb2, 0xd3, 0x54, 0xe5, 0xe3, 0x50, 0x57, 0x44, 0x45, 0xd1, 0xe5, 0xee, 0xb3, 0x58, @@ -150,19 +150,19 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xa6, 0x57, 0xfd, 0xcf, 0xf9, 0x64, 0x0a, 0xda, 0xd8, 0x0a, 0x49, 0x8f, 0xa8, 0x9e, 0xb0, 0xac, 0xcf, 0x37, 0x94, 0x55, 0xfa, 0xc8, 0xf3, 0x58, 0xa1, 0xa6, 0xc2, 0x5e, 0xde, 0x69, 0xe4, 0xb3, 0xa2, 0xa8, 0x60, 0x1c, 0x9b, 0x9c, 0x2a, 0xe7, 0xab, 0x2e, 0x19, 0x53, 0xf1, 0xda, 0x63, 0x8a, 0x0f, 0x33, 0xe0, 0x75, 0x16, 0xfb, 0x31, 0xe4, 0x6e, - 0xef, 0x7f, 0x5e, 0x22, 0x67, 0x91, 0xaf, 0xa0, 0x6f, 0x91, 0xe7, 0xb7, 0xca, 0xc8, 0xc6, 0xb7, 0xdb, 0xad, 0xe1, - 0xb2, 0x4e, 0x1b, 0x8b, 0xbd, 0x3e, 0xbe, 0x5d, 0x57, 0x1d, 0xc9, 0x62, 0xc2, 0x23, 0x1a, 0xb8, 0x7c, 0x4a, 0x13, - 0x37, 0x07, 0xaf, 0xaa, 0xde, 0xfb, 0x81, 0xf0, 0x16, 0x6f, 0xab, 0xee, 0xd5, 0xe0, 0x36, 0x07, 0xef, 0xd7, 0xd7, + 0xef, 0x7f, 0x5e, 0x22, 0x67, 0x91, 0xaf, 0xa0, 0x6f, 0x91, 0xe7, 0x67, 0xca, 0xc8, 0xc6, 0x67, 0xdb, 0xad, 0xe1, + 0xb2, 0x4e, 0x1b, 0x8b, 0xbd, 0x3e, 0x3e, 0x5b, 0x57, 0x1d, 0xc9, 0x62, 0xc2, 0x23, 0x1a, 0xb8, 0x7c, 0x4a, 0x13, + 0x37, 0x07, 0xaf, 0xaa, 0xde, 0xfb, 0x81, 0xf0, 0x16, 0x6f, 0xab, 0xee, 0xd5, 0xe0, 0x2c, 0x07, 0xef, 0xd7, 0xd7, 0xeb, 0x8e, 0xd7, 0xef, 0x69, 0x9a, 0x49, 0x45, 0xb4, 0xd0, 0x69, 0xbf, 0x2e, 0xc5, 0xd2, 0xd7, 0xc1, 0xd6, 0xf6, 0xa5, 0x09, 0xe2, 0x36, 0xfd, 0x63, 0xff, 0xc0, 0x45, 0xd2, 0x2d, 0xfc, 0x93, 0x3e, 0xf0, 0x1f, 0x8c, 0x5b, 0xf8, 0x19, 0xf9, 0x50, 0xf5, 0x0a, 0x47, 0x82, 0x3c, 0xeb, 0x3e, 0x33, 0x16, 0x33, 0x8f, 0xd9, 0xe0, 0xce, 0x73, 0x63, 0x26, 0xea, 0x10, 0x7a, 0x73, 0xf1, 0x42, 0x55, 0x80, 0x4b, 0x51, 0xba, 0xb3, 0x73, 0x63, 0xeb, 0x61, 0x21, 0x88, 0xbb, 0x1b, 0x33, 0xb1, 0xeb, 0xe2, 0x09, 0xb9, 0x82, 0x1f, 0xbb, 0x0b, 0xef, 0x65, 0x28, 0xc6, 0x7e, 0x1a, 0x26, - 0x11, 0x9f, 0x78, 0xa8, 0xe6, 0xba, 0xc8, 0xcf, 0xa4, 0xbd, 0xf1, 0x18, 0xe5, 0xbb, 0x57, 0xf8, 0x4c, 0x10, 0xb7, - 0xeb, 0xd6, 0x26, 0xf8, 0x95, 0x20, 0x57, 0xa7, 0xbb, 0x8b, 0x33, 0x91, 0x77, 0xae, 0xf0, 0x59, 0xe1, 0xb1, 0xc7, - 0x6f, 0x88, 0x87, 0x48, 0xe7, 0x4c, 0x43, 0x73, 0xce, 0x27, 0xca, 0x73, 0xef, 0x22, 0xfc, 0x1e, 0xe2, 0x2a, 0x69, - 0xc9, 0x6d, 0x74, 0x68, 0x65, 0x87, 0xb8, 0x5c, 0xba, 0x08, 0xdc, 0xbd, 0x3d, 0xab, 0xac, 0x50, 0x15, 0xf0, 0xad, - 0x20, 0x15, 0x83, 0x1c, 0xbf, 0x95, 0x11, 0x9a, 0x5b, 0xe1, 0xa5, 0xc8, 0x0c, 0xe3, 0x19, 0x3f, 0xb4, 0x3e, 0x9a, + 0x11, 0x9f, 0x78, 0xa8, 0xe6, 0xba, 0xc8, 0xcf, 0xa4, 0xbd, 0xf1, 0x18, 0xe5, 0xbb, 0x57, 0xf8, 0x56, 0x10, 0xb7, + 0xeb, 0xd6, 0x26, 0xf8, 0x95, 0x20, 0x57, 0xa7, 0xbb, 0x8b, 0x5b, 0x91, 0x77, 0xae, 0xf0, 0x6d, 0xe1, 0xb1, 0xc7, + 0x6f, 0x88, 0x87, 0x48, 0xe7, 0x56, 0x43, 0x73, 0xce, 0x27, 0xca, 0x73, 0xef, 0x22, 0xfc, 0x1e, 0xe2, 0x2a, 0x69, + 0xc9, 0x6d, 0x74, 0x68, 0x65, 0x87, 0xb8, 0x5c, 0xba, 0x08, 0xdc, 0xbd, 0x3d, 0xab, 0xac, 0x50, 0x15, 0xf0, 0x99, + 0x20, 0x15, 0x83, 0x1c, 0xbf, 0x95, 0x11, 0x9a, 0x33, 0xe1, 0xa5, 0xc8, 0x0c, 0xe3, 0x19, 0x3f, 0xb4, 0x3e, 0x9a, 0x69, 0x4f, 0x79, 0x18, 0x7c, 0x26, 0x68, 0x1a, 0x0a, 0x9e, 0xf6, 0x91, 0xad, 0x7e, 0xe0, 0xbf, 0x91, 0xab, 0x9e, 0xf3, 0x9f, 0xbe, 0xf8, 0x79, 0xf8, 0x73, 0xda, 0xbf, 0xc2, 0xaf, 0xc9, 0xfe, 0xa9, 0xd7, 0x0d, 0xbc, 0x9d, 0x7a, 0x7d, 0xf9, 0xf3, 0x7e, 0xef, 0x1f, 0x61, 0xfd, 0xd7, 0xb3, 0xfa, 0x4f, 0x7d, 0xb4, 0xf4, 0x7e, 0xde, 0xef, 0xf6, @@ -177,7 +177,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xf2, 0x03, 0x64, 0x81, 0xc0, 0xf3, 0x30, 0x9e, 0xd1, 0x2c, 0xa0, 0x39, 0xc2, 0x03, 0x72, 0x21, 0xbc, 0x26, 0xc2, 0xcf, 0x05, 0xfc, 0x68, 0x21, 0x7c, 0xa1, 0x03, 0x98, 0x70, 0x90, 0x15, 0x51, 0x25, 0x5c, 0x69, 0x2c, 0x2e, 0xc2, 0xd3, 0x0d, 0x95, 0x62, 0x0c, 0xde, 0x05, 0x84, 0x87, 0x95, 0x70, 0x27, 0xbe, 0x21, 0x86, 0x24, 0xde, 0xa5, 0x94, - 0xfe, 0x10, 0xc6, 0x1f, 0x69, 0xea, 0x9d, 0xe1, 0x66, 0xeb, 0x31, 0x96, 0x2e, 0xe8, 0x9d, 0x26, 0x6a, 0x17, 0xb1, + 0xfe, 0x10, 0xc6, 0x1f, 0x69, 0xea, 0xdd, 0xe2, 0x66, 0xeb, 0x31, 0x96, 0x2e, 0xe8, 0x9d, 0x26, 0x6a, 0x17, 0xb1, 0xaa, 0x73, 0xa1, 0x62, 0x04, 0x20, 0x64, 0xab, 0xbe, 0x18, 0xd8, 0xf1, 0x9d, 0x74, 0xcd, 0x61, 0x95, 0x86, 0x37, 0x2e, 0xaa, 0xc6, 0x45, 0x59, 0x32, 0x0f, 0x63, 0x16, 0x39, 0x82, 0x4e, 0xa6, 0x71, 0x28, 0xa8, 0xa3, 0xd7, 0xeb, 0x84, 0x30, 0x90, 0x5b, 0xa8, 0x0c, 0x91, 0x65, 0x70, 0x46, 0x26, 0xe0, 0x04, 0x67, 0xc5, 0x83, 0xe8, 0x94, 0x56, @@ -220,10 +220,10 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x73, 0xd4, 0x69, 0xa0, 0x45, 0xa5, 0xad, 0xd4, 0x99, 0xaa, 0x71, 0xf4, 0x82, 0x4f, 0xcf, 0x49, 0xa3, 0x3d, 0x3f, 0x1d, 0xb5, 0xe7, 0xb5, 0x1a, 0xca, 0x0c, 0x69, 0xcd, 0x7a, 0xf3, 0x3e, 0x7e, 0x03, 0x4e, 0x3d, 0x9b, 0x96, 0x70, 0x65, 0x79, 0x2d, 0xbd, 0xbc, 0x5a, 0x2d, 0xc9, 0x51, 0xdb, 0xea, 0x3a, 0x52, 0x5d, 0xf3, 0x5c, 0xe1, 0x64, 0x95, - 0xd4, 0x4e, 0x90, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0x99, 0x40, 0x1b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, + 0xd4, 0x4e, 0x90, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0xad, 0x40, 0x1b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, 0xc0, 0x3e, 0x95, 0x94, 0xf0, 0x00, 0x0b, 0xd0, 0xb5, 0xf0, 0x04, 0x4f, 0xf0, 0xac, 0xd6, 0x94, 0x64, 0x5e, 0x6f, 0xb6, 0xab, 0x63, 0x3d, 0x2a, 0xc7, 0xc2, 0xb3, 0x1a, 0x99, 0x14, 0x58, 0xca, 0x93, 0x5a, 0x2d, 0xaf, 0x06, 0x3b, - 0xcd, 0xc9, 0xad, 0x04, 0x20, 0xce, 0x56, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, + 0xcd, 0xc9, 0xad, 0x04, 0x20, 0x6e, 0x57, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, 0xa4, 0x28, 0x11, 0x98, 0xe5, 0x79, 0x29, 0xd9, 0x41, 0x8c, 0x62, 0x4a, 0x52, 0xe0, 0x3c, 0xd2, 0xee, 0xc2, 0x09, 0xe6, 0x78, 0x2c, 0xf9, 0x06, 0x21, 0xe4, 0xc2, 0xa4, 0xb3, 0x08, 0xc9, 0x83, 0x62, 0xc2, 0x2c, 0x99, 0x94, 0x11, 0xea, 0x5f, 0xee, 0x9e, 0xf3, 0x7b, 0x6d, 0xb2, 0x1e, 0xeb, 0x07, 0xb2, 0x59, 0xac, 0x39, 0x57, 0x48, 0xde, 0x7b, @@ -238,14 +238,14 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x13, 0xf3, 0xec, 0xa5, 0x5f, 0xd6, 0xca, 0xc6, 0x97, 0xbb, 0x67, 0xef, 0x37, 0x35, 0x83, 0xf2, 0x7c, 0x56, 0xda, 0xf8, 0x12, 0xbe, 0x05, 0x8d, 0x83, 0x85, 0x16, 0x0e, 0x01, 0xcb, 0xb1, 0x14, 0x48, 0x41, 0x96, 0x17, 0xae, 0x91, 0xa7, 0x38, 0x21, 0x32, 0x0c, 0x54, 0xdd, 0x35, 0xad, 0xe6, 0x31, 0x9e, 0x5c, 0x0c, 0xf8, 0x94, 0x6e, 0x89, 0x0d, - 0x9d, 0x21, 0x9f, 0x4d, 0x20, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x4e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, + 0xdd, 0x22, 0x9f, 0x4d, 0x20, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x4e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, 0x2b, 0xb2, 0x05, 0x8f, 0x49, 0x03, 0xc7, 0xa4, 0x81, 0x43, 0x92, 0xf5, 0x1a, 0x4a, 0x40, 0xb4, 0xc3, 0x62, 0x5c, 0x25, 0x66, 0x20, 0x2b, 0x4c, 0x9f, 0x56, 0x25, 0x80, 0xa3, 0x76, 0x28, 0x7d, 0x8f, 0x52, 0xa6, 0x47, 0x92, 0x2c, 0xde, 0x7a, 0x1c, 0x73, 0x39, 0xf0, 0x05, 0xbb, 0x8e, 0x21, 0xb1, 0x04, 0x56, 0x85, 0x05, 0x0a, 0x8a, 0xa6, 0x4d, 0xdd, 0x34, 0xf4, 0xe5, 0x3e, 0x71, 0x1c, 0xfa, 0xc0, 0xb9, 0x71, 0xa8, 0xf3, 0x70, 0xb2, 0xf5, 0x2e, 0xc7, 0x7b, 0x7b, 0x9e, 0xea, 0xf4, 0x8b, 0xf0, 0xb8, 0xa9, 0x2f, 0x23, 0x77, 0xdf, 0x2b, 0x5e, 0x11, 0x21, 0x09, 0x7f, 0xad, 0x16, 0xf7, 0x73, 0x08, 0x43, 0x7b, 0x61, 0x15, 0x83, 0x06, 0x78, 0xa9, 0xeb, 0x55, 0x97, 0x5f, 0xab, 0x15, 0x51, - 0xda, 0x2a, 0xb6, 0xce, 0x70, 0x92, 0xcf, 0xbd, 0x22, 0xf5, 0xa7, 0xb1, 0x96, 0x2f, 0x65, 0x40, 0x40, 0xcc, 0xa6, + 0xda, 0x2a, 0xb6, 0x6e, 0x71, 0x92, 0xcf, 0xbd, 0x22, 0xf5, 0xa7, 0xb1, 0x96, 0x2f, 0x65, 0x40, 0x40, 0xcc, 0xa6, 0x59, 0x66, 0x16, 0x63, 0x1d, 0x09, 0x06, 0xed, 0xbe, 0xd1, 0x59, 0x0b, 0x58, 0x66, 0x57, 0xe9, 0x46, 0x86, 0x9d, 0xb5, 0x50, 0x60, 0x1a, 0x41, 0x54, 0x0a, 0x1a, 0xd5, 0x72, 0x4d, 0xde, 0x6f, 0xd7, 0x73, 0x2e, 0x71, 0x86, 0xb4, 0x93, 0x4b, 0x42, 0x21, 0x91, 0xd5, 0x2a, 0x90, 0xf2, 0x9c, 0x4c, 0xb7, 0x93, 0xfc, 0x99, 0x45, 0xf2, 0x4f, 0x08, @@ -268,7 +268,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x36, 0x44, 0x4d, 0xa5, 0xd4, 0x91, 0x2d, 0x50, 0xd1, 0xc1, 0x9f, 0x7b, 0x4c, 0x2b, 0x6e, 0x26, 0x6e, 0x06, 0x0c, 0xf8, 0x89, 0xf0, 0x54, 0x30, 0x0a, 0x64, 0x06, 0xf7, 0x67, 0x5e, 0x65, 0xea, 0x36, 0x97, 0xdd, 0xb0, 0x46, 0xdc, 0xd8, 0x46, 0x13, 0x97, 0x71, 0xbd, 0xf3, 0x92, 0x97, 0x0e, 0x55, 0x06, 0xb5, 0x30, 0x5c, 0xb0, 0x4c, 0x24, 0xb1, - 0x96, 0x3f, 0x54, 0x49, 0xd1, 0x45, 0x23, 0x4c, 0x25, 0x18, 0xef, 0xe4, 0x1e, 0xd0, 0x1c, 0xfe, 0x2e, 0x6e, 0x85, + 0x96, 0x3f, 0x54, 0x49, 0xd1, 0x45, 0x23, 0x4c, 0x25, 0x18, 0xef, 0xe4, 0x1e, 0xd0, 0x1c, 0xfe, 0x2e, 0xce, 0x84, 0xb5, 0xa3, 0xc6, 0x89, 0x2d, 0xe7, 0xb4, 0xa4, 0xfe, 0x5b, 0x48, 0x75, 0x59, 0x3d, 0xf3, 0xcf, 0xa5, 0x2c, 0x64, 0x38, 0xab, 0x30, 0xf6, 0x44, 0x32, 0x76, 0x04, 0x7a, 0x9a, 0x49, 0xfc, 0xee, 0xea, 0x8c, 0x17, 0xa6, 0xa5, 0x9c, 0x26, 0xb1, 0x37, 0x45, 0xb4, 0xdc, 0xfa, 0xbd, 0xb2, 0x1b, 0x01, 0x23, 0x90, 0x05, 0x84, 0x35, 0x67, 0x4f, 0x10, @@ -312,7 +312,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xf1, 0xb5, 0x7b, 0x78, 0x63, 0x02, 0x1e, 0xb4, 0x87, 0x4d, 0x61, 0x19, 0xdb, 0x99, 0xba, 0x07, 0x64, 0x8f, 0x4f, 0xb8, 0xd1, 0xdd, 0xaa, 0x56, 0xc6, 0x1b, 0xb0, 0xff, 0x11, 0x1e, 0x9b, 0xcb, 0x71, 0x54, 0x73, 0x60, 0x1a, 0x2c, 0xf2, 0xc2, 0x29, 0xc0, 0x95, 0xf2, 0x96, 0x22, 0xcc, 0x73, 0x19, 0xe0, 0xfe, 0x16, 0x7f, 0xa7, 0x59, 0xe2, 0xb0, - 0xe0, 0x38, 0xb7, 0x0f, 0xe5, 0x88, 0x0a, 0xfc, 0x22, 0x7e, 0x0f, 0x74, 0x2c, 0x29, 0x34, 0x37, 0x54, 0xf4, 0x94, + 0xe0, 0x38, 0x67, 0x0f, 0xe5, 0x88, 0x0a, 0xfc, 0x22, 0x7e, 0x0f, 0x74, 0x2c, 0x29, 0x34, 0x37, 0x54, 0xf4, 0x94, 0xeb, 0x85, 0x6c, 0x4d, 0x4b, 0xc5, 0xb4, 0x48, 0xa9, 0x91, 0xd3, 0x6c, 0xc8, 0xe3, 0x34, 0x56, 0xb6, 0x28, 0x4e, 0x55, 0x65, 0x5e, 0xb4, 0x05, 0x8b, 0x65, 0x68, 0x71, 0xb9, 0xf4, 0xaa, 0xa8, 0x26, 0xcc, 0x8a, 0x64, 0x20, 0xcc, 0xac, 0x8c, 0x8a, 0x8a, 0x66, 0xad, 0xfa, 0x78, 0x68, 0x35, 0xa1, 0xc8, 0xe8, 0xe6, 0x15, 0x38, 0x6c, 0x17, 0x82, @@ -612,31 +612,32 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xde, 0x0b, 0x3e, 0xda, 0x3c, 0x56, 0xcc, 0x47, 0x5d, 0x79, 0x05, 0x42, 0xdd, 0xb5, 0x35, 0xca, 0x2f, 0x8f, 0xdd, 0xce, 0xa9, 0x56, 0x06, 0x1c, 0x19, 0x0e, 0x77, 0x8f, 0x1a, 0xe6, 0x56, 0x45, 0xcc, 0x47, 0x70, 0x20, 0x55, 0x17, 0x6b, 0x92, 0x8a, 0xc7, 0x7d, 0xdc, 0xec, 0x9c, 0x86, 0x8e, 0xe4, 0x2d, 0x92, 0x79, 0x64, 0xc1, 0x3e, 0x74, 0x1e, - 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xf5, 0x70, 0xca, 0x4a, 0xf7, 0x36, 0x28, 0x1d, 0xc5, 0x94, 0xbc, - 0x9c, 0x09, 0x7e, 0x86, 0x2b, 0x8b, 0x94, 0x2c, 0x3c, 0xd7, 0xbe, 0x73, 0xb0, 0x55, 0x80, 0x84, 0x5c, 0x47, 0x71, - 0x78, 0xe3, 0x63, 0xd7, 0xb2, 0x37, 0x77, 0x3b, 0xff, 0xfa, 0x3f, 0xfe, 0x97, 0x76, 0x9b, 0x9f, 0xee, 0x8f, 0x9b, - 0x66, 0xac, 0x15, 0x44, 0xe7, 0xa7, 0x70, 0x11, 0xb1, 0x8c, 0xf3, 0xd2, 0xdb, 0xfa, 0x28, 0x65, 0x51, 0x7d, 0x1c, - 0xc6, 0x43, 0xb7, 0xb3, 0x1d, 0x41, 0xf6, 0x0d, 0x24, 0x0d, 0x75, 0xb5, 0x08, 0x48, 0xf0, 0x37, 0xdd, 0xa1, 0x31, - 0x57, 0x31, 0xe4, 0x69, 0xb5, 0x6f, 0xd4, 0x94, 0x07, 0xaa, 0x72, 0xab, 0x26, 0xd5, 0x5f, 0xaf, 0xd2, 0x4c, 0x2d, - 0xad, 0x5c, 0xa6, 0xc9, 0x5d, 0xa7, 0x88, 0x53, 0xfd, 0xdf, 0xff, 0xf9, 0x5f, 0xfe, 0x9b, 0x79, 0x84, 0xf0, 0xd3, - 0xbf, 0xfe, 0xf7, 0xff, 0xfc, 0x7f, 0xfe, 0xf7, 0x7f, 0x85, 0x0b, 0x18, 0x3a, 0x44, 0x25, 0xf9, 0x84, 0x53, 0xc6, - 0xa7, 0x14, 0xc3, 0x70, 0x20, 0x47, 0x71, 0xc2, 0x32, 0xc1, 0x06, 0xd5, 0xeb, 0x35, 0x17, 0x72, 0x42, 0x79, 0xd8, - 0x34, 0x74, 0xf2, 0xd0, 0xe6, 0x25, 0x8d, 0x54, 0x50, 0x2e, 0x69, 0x31, 0x3f, 0xdd, 0x07, 0x7c, 0x3f, 0xec, 0x46, - 0xa2, 0x5f, 0x6c, 0xc7, 0xc2, 0x38, 0x65, 0xa1, 0x24, 0x2f, 0xcb, 0x1d, 0x08, 0x97, 0x2c, 0xe0, 0x31, 0x68, 0x59, - 0xc5, 0x72, 0xf7, 0x2a, 0x7d, 0xda, 0x1f, 0x66, 0x99, 0x60, 0x43, 0x40, 0xb9, 0x72, 0xfd, 0xca, 0xc8, 0x74, 0x1d, - 0xd4, 0xbf, 0xf8, 0x2e, 0x97, 0xa3, 0x28, 0xdb, 0xfa, 0xf0, 0xe4, 0x4f, 0xf9, 0x5f, 0x26, 0xa0, 0x64, 0x39, 0xde, - 0x24, 0xbc, 0xd5, 0x16, 0xf7, 0x71, 0xa3, 0x31, 0xbd, 0x45, 0x8b, 0x72, 0x06, 0xbc, 0x6d, 0x32, 0xe9, 0x2e, 0xb6, - 0x07, 0x94, 0x21, 0xed, 0xc2, 0x33, 0xdd, 0x70, 0xc0, 0xbd, 0xed, 0x34, 0xf2, 0xfc, 0xcf, 0x0b, 0xe9, 0x1c, 0x65, - 0xbf, 0x42, 0xe8, 0x59, 0xfb, 0x91, 0xaf, 0xb9, 0xbd, 0xb8, 0x85, 0xd5, 0xab, 0xa5, 0x7a, 0x8d, 0x9b, 0xeb, 0x17, - 0xed, 0xec, 0xd0, 0xb9, 0x1d, 0xf4, 0x3e, 0x84, 0x30, 0xf6, 0xb8, 0x89, 0xc7, 0xad, 0x45, 0x31, 0xbc, 0x10, 0x7c, - 0x62, 0xc7, 0xca, 0x69, 0x48, 0x07, 0x74, 0x68, 0xfc, 0xef, 0xba, 0x5e, 0xc5, 0xc1, 0xf3, 0xf1, 0xc1, 0x86, 0xb9, - 0x34, 0x48, 0x32, 0x46, 0xee, 0x34, 0xf2, 0x2f, 0xe1, 0x04, 0x2e, 0x86, 0x31, 0x0f, 0x45, 0x20, 0x09, 0xb6, 0x6d, - 0x47, 0xdc, 0x43, 0x60, 0x33, 0x7c, 0x61, 0xc1, 0xd3, 0x56, 0x4d, 0xc1, 0x13, 0x5e, 0xbd, 0x0e, 0x99, 0xfb, 0xb2, - 0xbb, 0x3d, 0x94, 0x72, 0xa4, 0x7d, 0xaf, 0x03, 0xd9, 0xaf, 0x2a, 0x1e, 0x28, 0x2d, 0x63, 0x5a, 0x68, 0x73, 0xbd, - 0x12, 0xd5, 0xaa, 0xf6, 0x27, 0xe1, 0xb9, 0x12, 0x4c, 0x77, 0xb5, 0x95, 0x2c, 0x84, 0x56, 0xaf, 0xc8, 0xf7, 0x85, - 0x15, 0x14, 0x4e, 0xa7, 0xb2, 0x21, 0x6a, 0x9f, 0xee, 0x2b, 0xe5, 0x15, 0xb8, 0x87, 0xcc, 0xd2, 0x50, 0x49, 0x11, - 0xba, 0x91, 0x3e, 0x0a, 0xea, 0x97, 0x4e, 0x97, 0x80, 0xcf, 0x9a, 0x75, 0xfe, 0x1f, 0xd6, 0xb2, 0x30, 0xa4, 0x67, - 0x88, 0x00, 0x00}; + 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xf5, 0x70, 0xca, 0x4a, 0xf7, 0x36, 0x28, 0x1d, 0xc5, 0x94, 0xdc, + 0x78, 0xc4, 0xf5, 0x9d, 0xa3, 0x56, 0xe9, 0x6e, 0x3b, 0x04, 0x9b, 0xc7, 0xb8, 0xe6, 0xa4, 0x4f, 0xce, 0x02, 0x8b, + 0x77, 0x4e, 0xf7, 0xc3, 0x15, 0x8c, 0x48, 0x7e, 0x9f, 0x6b, 0x47, 0x3b, 0x18, 0x36, 0x40, 0x6f, 0xae, 0xa3, 0xc4, + 0x81, 0x71, 0xc8, 0x6b, 0x41, 0x9d, 0xbb, 0x9d, 0x7f, 0xfd, 0x1f, 0xff, 0x4b, 0xfb, 0xd8, 0x4f, 0xf7, 0xc7, 0x4d, + 0x33, 0xd6, 0xca, 0xae, 0xe4, 0xa7, 0x70, 0x6b, 0xb1, 0x0c, 0x0a, 0xd3, 0xdb, 0xfa, 0x28, 0x65, 0x51, 0x7d, 0x1c, + 0xc6, 0x43, 0xb7, 0xb3, 0x1d, 0x9b, 0xf6, 0x75, 0x25, 0x0d, 0x75, 0xb5, 0x08, 0xe8, 0xf5, 0x37, 0x5d, 0xb8, 0x31, + 0xf7, 0x36, 0xe4, 0xd1, 0xb6, 0xaf, 0xdf, 0x94, 0xa7, 0xaf, 0x72, 0x05, 0x27, 0xd5, 0x9f, 0xba, 0xd2, 0x1c, 0x30, + 0xad, 0xdc, 0xbc, 0xc9, 0x5d, 0xa7, 0x08, 0x6a, 0xfd, 0xdf, 0xff, 0xf9, 0x5f, 0xfe, 0x9b, 0x79, 0x84, 0x58, 0xd5, + 0xbf, 0xfe, 0xf7, 0xff, 0xfc, 0x7f, 0xfe, 0xf7, 0x7f, 0x85, 0xdb, 0x1a, 0x3a, 0x9e, 0x25, 0x99, 0x8a, 0x53, 0x06, + 0xb3, 0x14, 0x77, 0x71, 0x20, 0xa1, 0x71, 0xc2, 0x32, 0xc1, 0x06, 0xd5, 0xbb, 0x38, 0x17, 0x72, 0x42, 0x79, 0x32, + 0x35, 0x74, 0xf2, 0x84, 0xe7, 0x25, 0x41, 0x55, 0x50, 0x2e, 0x09, 0x37, 0x3f, 0xdd, 0x07, 0x7c, 0x3f, 0xec, 0xfa, + 0xa2, 0x5f, 0x6c, 0xc7, 0xc2, 0x90, 0x09, 0x94, 0xe4, 0x65, 0xb9, 0x03, 0xb1, 0x95, 0x05, 0x3c, 0x06, 0x2d, 0xab, + 0x58, 0xee, 0x5e, 0xa5, 0x4f, 0xfb, 0xc3, 0x2c, 0x13, 0x6c, 0x08, 0x28, 0x57, 0x7e, 0x62, 0x19, 0xc6, 0xae, 0x83, + 0xae, 0x18, 0xdf, 0xe5, 0x72, 0x14, 0x45, 0xa0, 0x87, 0x27, 0x7f, 0xca, 0xff, 0x32, 0x01, 0x8d, 0xcc, 0xf1, 0x26, + 0xe1, 0xad, 0x36, 0xcf, 0x8f, 0x1b, 0x8d, 0xe9, 0x2d, 0x5a, 0x94, 0x33, 0xe0, 0x6d, 0x93, 0x49, 0x3a, 0xb6, 0x07, + 0x94, 0xf1, 0xef, 0xc2, 0x8d, 0xdd, 0x70, 0xc0, 0x17, 0xee, 0x34, 0xf2, 0xfc, 0xcf, 0x0b, 0xe9, 0x49, 0x65, 0xbf, + 0x42, 0x9c, 0x5a, 0x3b, 0x9d, 0xaf, 0xb9, 0xbd, 0xb8, 0x85, 0xd5, 0xab, 0xa5, 0x7a, 0x8d, 0x9b, 0xeb, 0xb7, 0xf2, + 0xec, 0x38, 0xbb, 0x1d, 0x21, 0x3f, 0x84, 0x98, 0xf7, 0xb8, 0x89, 0xc7, 0xad, 0x45, 0x31, 0xbc, 0x10, 0x7c, 0x62, + 0x07, 0xd6, 0x69, 0x48, 0x07, 0x74, 0x68, 0x9c, 0xf5, 0xba, 0x5e, 0x05, 0xcd, 0xf3, 0xf1, 0xc1, 0x86, 0xb9, 0x34, + 0x48, 0x32, 0xa0, 0xee, 0x34, 0xf2, 0x2f, 0xe1, 0x04, 0x2e, 0x86, 0x31, 0x0f, 0x45, 0x20, 0x09, 0xb6, 0x6d, 0x87, + 0xe7, 0x43, 0xe0, 0x49, 0x7c, 0x61, 0xc1, 0xd3, 0x56, 0x4d, 0xc1, 0x6d, 0x5e, 0xbd, 0x3b, 0x99, 0xfb, 0xb2, 0xbb, + 0x3d, 0x94, 0xf2, 0xba, 0x7d, 0xaf, 0xa3, 0xde, 0xaf, 0x2a, 0xee, 0x2a, 0x2d, 0x90, 0x5a, 0x68, 0x73, 0xbd, 0x92, + 0xeb, 0xaa, 0xf6, 0x27, 0xe1, 0xb9, 0x12, 0x4c, 0x77, 0xb5, 0x95, 0x2c, 0x84, 0x56, 0xaf, 0xc8, 0xf7, 0x85, 0xc9, + 0x14, 0x4e, 0xa7, 0xb2, 0x21, 0x6a, 0x9f, 0xee, 0x2b, 0x4d, 0x17, 0xb8, 0x87, 0x4c, 0xe9, 0x50, 0x19, 0x14, 0xba, + 0x91, 0x3e, 0x0a, 0xea, 0x97, 0xce, 0xad, 0x80, 0x6f, 0xa0, 0x75, 0xfe, 0x1f, 0xa2, 0x48, 0xf6, 0xdd, 0x94, 0x88, + 0x00, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index bde1ce1fb5..0c16ea9f37 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -3632,373 +3632,374 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, - 0xdc, 0x93, 0x2e, 0xb7, 0x6d, 0x24, 0xfd, 0x3f, 0x4f, 0x01, 0xc3, 0x5e, 0x87, 0xb0, 0x01, 0x08, 0x00, 0x45, 0x89, - 0x26, 0x45, 0x69, 0x13, 0x1f, 0xb5, 0x4e, 0x29, 0x71, 0xca, 0x56, 0x5c, 0xbb, 0x51, 0x54, 0x22, 0x48, 0x0e, 0x49, - 0xac, 0x41, 0x80, 0x05, 0x80, 0x3a, 0x42, 0x63, 0x9f, 0x65, 0x9f, 0x65, 0x9f, 0xec, 0xab, 0xee, 0x9e, 0x19, 0x0c, - 0x0e, 0x1e, 0x8a, 0x9d, 0xdd, 0xaf, 0x12, 0xdb, 0xc4, 0xdc, 0xd3, 0x33, 0xd3, 0xd3, 0xd3, 0xa7, 0x3f, 0xe3, 0xbc, - 0x17, 0xb3, 0xc5, 0xf6, 0xeb, 0xee, 0xf3, 0x67, 0x66, 0xe3, 0x96, 0x04, 0x82, 0xcf, 0xce, 0xe2, 0xd9, 0x2c, 0x64, - 0x2d, 0x5d, 0x04, 0x0f, 0xd1, 0x4d, 0xd9, 0xcd, 0xd9, 0x23, 0x47, 0x78, 0xec, 0x34, 0xf2, 0x4d, 0x47, 0x4b, 0xcc, - 0x98, 0x49, 0x97, 0x76, 0x44, 0xb9, 0x22, 0x6f, 0xf6, 0x06, 0xc5, 0x1b, 0x7c, 0x5d, 0x8a, 0xa3, 0x6b, 0x4d, 0xe2, - 0xd5, 0x28, 0x64, 0x16, 0x6e, 0x77, 0xe8, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x10, 0xa5, 0xe5, 0x91, 0x63, 0x82, 0xdf, - 0x99, 0x38, 0xc5, 0xf7, 0x60, 0x6e, 0xf4, 0x61, 0x52, 0x76, 0x56, 0x1d, 0x3e, 0xe8, 0x8a, 0x00, 0xab, 0x87, 0x3a, - 0xc8, 0xe0, 0xed, 0xd7, 0x70, 0x6a, 0x07, 0xfa, 0x07, 0xd8, 0x7d, 0xa9, 0xde, 0x6f, 0x3a, 0xfa, 0x83, 0x4b, 0xfd, - 0x03, 0xc2, 0x18, 0xa3, 0x17, 0xbf, 0xa4, 0xdd, 0xab, 0x9b, 0x3a, 0x09, 0xbd, 0x57, 0x18, 0xc7, 0x00, 0x98, 0xbe, - 0xaf, 0x02, 0x7f, 0x16, 0xc5, 0x69, 0x16, 0x8c, 0xf5, 0xab, 0xfe, 0xdb, 0xa0, 0x75, 0xb9, 0xc8, 0x5a, 0xc6, 0x95, - 0x39, 0xce, 0xd4, 0x10, 0x28, 0x02, 0x61, 0x62, 0x04, 0x94, 0x4d, 0x85, 0xd4, 0x13, 0xb4, 0xb5, 0xa0, 0x40, 0xcd, - 0x58, 0x68, 0x9c, 0x0d, 0xa0, 0x5c, 0x25, 0x9e, 0x0a, 0x06, 0x86, 0xd2, 0xb1, 0xa6, 0xd1, 0xa7, 0x97, 0xca, 0xcb, - 0xd5, 0x1a, 0xaf, 0xf2, 0xac, 0xb8, 0x2d, 0xd1, 0x07, 0xb0, 0x30, 0x9c, 0xa1, 0xef, 0x47, 0xaa, 0xd2, 0x67, 0xe9, - 0xde, 0x1d, 0x7e, 0x57, 0xa6, 0x0b, 0xe0, 0xfe, 0x06, 0x8d, 0x8b, 0x28, 0xce, 0x34, 0x70, 0x6c, 0x03, 0x3d, 0x0e, - 0xab, 0x4a, 0x62, 0xbc, 0xd5, 0x96, 0x91, 0x73, 0x64, 0xf0, 0x3d, 0x5e, 0x7e, 0x2d, 0xee, 0xde, 0xac, 0xe4, 0xc1, - 0x82, 0x1e, 0x0b, 0x11, 0x2c, 0x60, 0x16, 0x9f, 0xc7, 0xb7, 0x55, 0x39, 0xc8, 0xcb, 0xe1, 0xee, 0xbb, 0xb7, 0x25, - 0xc8, 0x64, 0x11, 0xd5, 0xaf, 0xc5, 0x03, 0x93, 0x0a, 0x42, 0xa7, 0x72, 0xa6, 0x50, 0xf1, 0x43, 0xd0, 0x30, 0x19, - 0xe8, 0x89, 0xe1, 0x5d, 0x00, 0x28, 0x89, 0x5f, 0xd3, 0xc3, 0xfc, 0x5a, 0x84, 0x4e, 0x16, 0x81, 0x8b, 0x95, 0xcb, - 0x19, 0xb0, 0x6b, 0xb4, 0x5c, 0x65, 0xe8, 0x6a, 0x17, 0x06, 0xc0, 0x72, 0x5d, 0x43, 0xd7, 0x9d, 0x80, 0xa5, 0x0b, - 0x32, 0x31, 0xd7, 0xb5, 0x60, 0x52, 0x4f, 0xe3, 0x44, 0x2f, 0x20, 0x2f, 0xc4, 0xef, 0xc8, 0xa8, 0x82, 0xcf, 0x84, - 0x4f, 0x63, 0x6c, 0x16, 0x7e, 0xea, 0x5b, 0x63, 0x14, 0xe8, 0x34, 0x60, 0x86, 0x31, 0xb5, 0xd3, 0x6f, 0x85, 0x8d, - 0x93, 0x05, 0xf7, 0x9b, 0xa5, 0x69, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, 0xd6, 0xbe, - 0xd4, 0x15, 0xd0, 0x2f, 0x74, 0x52, 0x14, 0x18, 0x22, 0x18, 0x86, 0xf9, 0x75, 0x61, 0xb9, 0x53, 0xcc, 0x17, 0x76, - 0x19, 0xa5, 0x6b, 0x28, 0xba, 0x1f, 0x70, 0x01, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xf2, 0x7c, 0x53, 0x15, - 0xfa, 0x1b, 0xba, 0x46, 0x88, 0x9e, 0x00, 0x40, 0x38, 0x5f, 0xd7, 0xfe, 0x2a, 0xd3, 0x18, 0x9f, 0xad, 0x14, 0x6a, - 0x42, 0x5f, 0xd7, 0xfa, 0x73, 0x66, 0x4f, 0x58, 0xe6, 0x07, 0x21, 0x55, 0xe9, 0x8b, 0x68, 0xf5, 0xb5, 0xe9, 0xa5, - 0xe5, 0xe9, 0x45, 0xe5, 0xfd, 0x83, 0x93, 0xa1, 0x2b, 0x80, 0xc6, 0x8d, 0x33, 0xc3, 0x28, 0x56, 0xcd, 0x2b, 0x4a, - 0x79, 0xff, 0xd5, 0xe5, 0x60, 0xb0, 0x1c, 0x11, 0x2c, 0x07, 0x8b, 0xc6, 0xf1, 0x84, 0xfd, 0xf2, 0xfe, 0xad, 0x0c, - 0x9b, 0x05, 0x1c, 0xa0, 0x21, 0xdf, 0x98, 0x29, 0xd2, 0x0f, 0x09, 0xd2, 0x0e, 0x14, 0xe0, 0x4a, 0x93, 0x5b, 0x28, - 0xc9, 0x75, 0xed, 0x8c, 0xc6, 0xce, 0x26, 0x34, 0xea, 0x41, 0x8c, 0xb5, 0x92, 0xfc, 0xe4, 0x80, 0x4a, 0xd3, 0x6d, - 0x47, 0x85, 0x00, 0x0c, 0x09, 0xcc, 0xb0, 0x80, 0x02, 0x44, 0xf8, 0x1c, 0xb8, 0xc5, 0x83, 0xc2, 0x5e, 0x20, 0x9f, - 0xdd, 0x3d, 0x2b, 0x93, 0x2a, 0x58, 0x4b, 0x3f, 0x3d, 0xc1, 0x98, 0x5d, 0x70, 0x5f, 0x83, 0x97, 0x8f, 0x93, 0x03, - 0xfa, 0xd4, 0x2a, 0x27, 0xa2, 0x68, 0x44, 0x3c, 0xed, 0x7a, 0xbc, 0x81, 0x07, 0x1d, 0x15, 0x08, 0x11, 0x0f, 0xa9, - 0x7e, 0xae, 0x6b, 0x0b, 0x4e, 0x1a, 0x71, 0x77, 0x42, 0xe0, 0x6b, 0xc0, 0x81, 0xb3, 0xab, 0x6b, 0x0b, 0xff, 0x0e, - 0x67, 0x2e, 0x72, 0xfc, 0xbb, 0x96, 0xcb, 0xb3, 0x8a, 0xb3, 0x96, 0x96, 0xcf, 0xda, 0x98, 0x2f, 0x2e, 0x18, 0x12, - 0xc8, 0x97, 0xf5, 0x1c, 0x05, 0xb4, 0x0d, 0x8b, 0x3b, 0x17, 0x8b, 0x3b, 0xd9, 0xb0, 0xb8, 0x93, 0x2d, 0x8b, 0x1b, - 0xf2, 0x85, 0xd4, 0x24, 0xe8, 0x12, 0x34, 0x0e, 0x93, 0xc0, 0xe3, 0x84, 0x46, 0x8f, 0x9f, 0x33, 0x84, 0x93, 0x95, - 0x86, 0xa0, 0x1c, 0xb5, 0x01, 0x56, 0x4d, 0x70, 0x51, 0x00, 0x51, 0x9f, 0xb8, 0x3c, 0x75, 0x62, 0xde, 0x10, 0x83, - 0xb3, 0x15, 0x56, 0xe7, 0x0b, 0xbb, 0x94, 0xe2, 0x8b, 0xb7, 0xe6, 0x1b, 0x66, 0x3a, 0xdf, 0x32, 0xd3, 0x71, 0xe9, - 0xe8, 0xf2, 0x69, 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0x14, 0x46, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x1c, - 0xab, 0xec, 0xa8, 0xa5, 0x9f, 0xa6, 0xb7, 0x71, 0x02, 0x12, 0x17, 0x68, 0xe6, 0x61, 0x5b, 0x6a, 0x11, 0x44, 0xdc, - 0x99, 0xcb, 0xc6, 0xcd, 0x54, 0xe4, 0xab, 0x5b, 0xca, 0xeb, 0x74, 0xa8, 0xc4, 0xd2, 0xcf, 0x32, 0x96, 0x20, 0xd0, - 0x7d, 0xf0, 0xfa, 0xfd, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0x50, 0xc1, 0xea, 0x88, 0xa1, 0x97, 0x40, 0x5b, 0x25, - 0xe2, 0x22, 0x56, 0x1c, 0xc3, 0x25, 0x12, 0xf0, 0x3f, 0xe1, 0x71, 0x6d, 0x25, 0x8a, 0xe9, 0x92, 0x7b, 0x64, 0xd8, - 0x4b, 0x7f, 0xf2, 0x01, 0x04, 0x7b, 0x2d, 0xcf, 0x04, 0x25, 0x5d, 0xd5, 0x0d, 0x5c, 0x42, 0xc4, 0xde, 0xb8, 0x40, - 0x92, 0x88, 0x25, 0xb9, 0x0a, 0x14, 0x58, 0x4f, 0xfa, 0xd6, 0xf4, 0x6a, 0xed, 0xe5, 0x07, 0xb3, 0xc0, 0xa8, 0x61, - 0x4d, 0x40, 0x6d, 0xe1, 0xe0, 0x54, 0xbe, 0xb9, 0x42, 0xd3, 0x3d, 0x32, 0x80, 0xf3, 0x7b, 0x09, 0xf1, 0x4c, 0x1d, - 0xf1, 0xa0, 0x1d, 0x26, 0x70, 0x6b, 0x5d, 0x3a, 0x57, 0xf9, 0xd3, 0x19, 0xfe, 0x72, 0xaf, 0xf2, 0xa7, 0x23, 0xfc, - 0xe5, 0x5d, 0x61, 0xe4, 0xba, 0x86, 0x87, 0xbc, 0x32, 0x67, 0xfd, 0xb4, 0xb4, 0x9f, 0x48, 0xff, 0xec, 0x01, 0xdb, - 0x86, 0x2f, 0xf0, 0xe3, 0x27, 0xeb, 0x14, 0x2c, 0x2e, 0xd5, 0x39, 0x44, 0x76, 0x62, 0xe4, 0x8d, 0xe9, 0xb3, 0x0d, - 0xe9, 0x23, 0xe3, 0xbf, 0x7c, 0xf1, 0xe3, 0x2e, 0x89, 0x8b, 0x3b, 0xa5, 0xcc, 0x86, 0xb8, 0x1e, 0x05, 0x91, 0x9f, - 0xdc, 0x5f, 0xd3, 0xf3, 0xa2, 0x25, 0x68, 0x77, 0xc9, 0x5e, 0x21, 0xf2, 0xb2, 0x2c, 0xee, 0xca, 0x14, 0x06, 0xef, - 0x3d, 0xbf, 0xe8, 0x07, 0x7f, 0x4f, 0x14, 0xb2, 0xad, 0xf4, 0x00, 0xe5, 0x0b, 0x52, 0xea, 0xe8, 0xfa, 0xc9, 0xba, - 0xc5, 0xea, 0xcd, 0x54, 0x66, 0x5b, 0xa1, 0x0b, 0x61, 0x79, 0xf0, 0x31, 0xbb, 0x98, 0x04, 0x3d, 0x94, 0x67, 0x8d, - 0xe2, 0x3b, 0xeb, 0xc9, 0x3a, 0x3b, 0xd3, 0x17, 0x7e, 0xf2, 0x89, 0x4d, 0xac, 0x71, 0x90, 0x8c, 0x43, 0xa6, 0xf7, - 0xf4, 0x51, 0xe8, 0x47, 0x9f, 0xf8, 0xa7, 0x15, 0xaf, 0x32, 0x94, 0x50, 0xef, 0x7c, 0xfb, 0x0a, 0x98, 0x10, 0xcb, - 0x0e, 0x89, 0xd5, 0x06, 0x28, 0x68, 0x2f, 0x25, 0xc3, 0xab, 0x20, 0x14, 0x8b, 0x52, 0x26, 0x28, 0x58, 0x82, 0xd0, - 0x1c, 0x2c, 0x56, 0x4d, 0x1d, 0xd7, 0x4b, 0x37, 0xd5, 0xa9, 0x12, 0xb3, 0x52, 0x86, 0x5c, 0xbc, 0xc6, 0x16, 0xfe, - 0x78, 0x77, 0x14, 0x0c, 0x7b, 0xff, 0xee, 0x64, 0x2b, 0x5f, 0x36, 0x43, 0x48, 0xb5, 0xc8, 0x52, 0xe2, 0x01, 0x9d, - 0x73, 0x02, 0x73, 0x73, 0xd7, 0x6a, 0x65, 0x3f, 0x4d, 0x57, 0x0b, 0x36, 0x21, 0xc9, 0xe0, 0x59, 0x31, 0xa8, 0xf2, - 0xcb, 0x42, 0x1d, 0xd8, 0x6f, 0x2b, 0xef, 0xf8, 0xf0, 0x25, 0x68, 0x2c, 0x00, 0x41, 0x19, 0x4f, 0xa7, 0x7a, 0xf1, - 0xc6, 0xdf, 0x51, 0xcd, 0x3d, 0xfc, 0x6d, 0xf5, 0xe6, 0xb5, 0xf3, 0x46, 0x56, 0x8e, 0x80, 0x30, 0x16, 0xe2, 0x57, - 0x4e, 0x17, 0x2b, 0xe3, 0x15, 0x33, 0x9a, 0xfa, 0xd1, 0xe6, 0xe9, 0x5c, 0x96, 0xb6, 0xf8, 0x92, 0xb1, 0x09, 0x10, - 0xdc, 0x66, 0x2d, 0xf5, 0x3a, 0x64, 0x37, 0x4c, 0x8a, 0x76, 0xeb, 0x9d, 0x35, 0xd4, 0x40, 0xdf, 0x73, 0x5c, 0x64, - 0xcc, 0xa9, 0x3a, 0x65, 0x4a, 0x43, 0x9c, 0x03, 0x9f, 0xb9, 0x7a, 0xc4, 0x2a, 0x47, 0x6a, 0x68, 0xea, 0xca, 0x00, - 0x36, 0x8e, 0xec, 0x6c, 0x43, 0x7a, 0x0f, 0x03, 0x4f, 0x37, 0x8f, 0xcd, 0x74, 0x8d, 0x1e, 0xf8, 0xea, 0xe6, 0x70, - 0x0a, 0xe1, 0xe4, 0xb5, 0x0a, 0x76, 0xc8, 0x26, 0x88, 0x35, 0x31, 0xc9, 0x74, 0xe2, 0xbe, 0x08, 0x6d, 0x47, 0x54, - 0xfb, 0x15, 0x7c, 0xa8, 0xc6, 0xb5, 0xd1, 0xca, 0x33, 0x1f, 0x61, 0x40, 0xd7, 0x88, 0xa5, 0xe9, 0x46, 0x80, 0xc9, - 0x45, 0x37, 0xf5, 0xa2, 0x74, 0x19, 0x1e, 0x45, 0xba, 0xe9, 0x98, 0x40, 0x12, 0xe0, 0x04, 0xab, 0x7d, 0xe1, 0xf5, - 0x72, 0xbd, 0xe0, 0xfa, 0x2a, 0xc9, 0x6c, 0xa4, 0x73, 0x5d, 0x82, 0x4d, 0xf9, 0xb7, 0x3a, 0x1f, 0x54, 0xe9, 0x9a, - 0x6e, 0x1c, 0x5a, 0xab, 0x84, 0x7a, 0x6b, 0xec, 0x22, 0x6c, 0x40, 0x8c, 0xa9, 0x82, 0x5f, 0xd9, 0x74, 0xca, 0xc6, - 0x59, 0x6a, 0x08, 0xe6, 0x91, 0xf4, 0x1e, 0x0b, 0x56, 0x43, 0x8f, 0x06, 0xfa, 0x4f, 0x60, 0x43, 0x2f, 0x9c, 0x2c, - 0xf1, 0x01, 0x89, 0x37, 0x53, 0x33, 0x98, 0xa8, 0xc5, 0x32, 0x88, 0x78, 0x2f, 0x10, 0x1c, 0xbc, 0x21, 0x1d, 0x87, - 0xc6, 0xef, 0x9f, 0x62, 0x5f, 0xc4, 0x52, 0xab, 0x65, 0x3b, 0x2a, 0xda, 0x76, 0x7c, 0xd7, 0xee, 0x9b, 0x8e, 0xeb, - 0xe4, 0xba, 0x09, 0xb6, 0x5b, 0x9f, 0xf6, 0x3d, 0xf4, 0x58, 0xab, 0x0d, 0xb5, 0x56, 0xd1, 0x43, 0xea, 0x79, 0xee, - 0x0b, 0x57, 0x37, 0x49, 0x65, 0x4e, 0xc1, 0x6d, 0xe3, 0xf8, 0x86, 0x25, 0x5f, 0x3c, 0x95, 0x72, 0xe3, 0xfb, 0x8d, - 0xe7, 0xc8, 0x75, 0x00, 0x09, 0x67, 0xf1, 0xf2, 0x01, 0x53, 0x68, 0xeb, 0xa6, 0x3e, 0x0e, 0xe3, 0x94, 0xa9, 0x73, - 0x20, 0x26, 0xc8, 0x17, 0x4e, 0xe2, 0xe7, 0xf7, 0xaf, 0x3f, 0x7c, 0xd0, 0x4d, 0x8c, 0x04, 0x9a, 0xaa, 0xad, 0xf3, - 0x0d, 0xb5, 0x03, 0xfb, 0x37, 0xee, 0x3b, 0xba, 0x61, 0xe8, 0x51, 0x5b, 0xde, 0x73, 0x94, 0x56, 0xdb, 0x72, 0xfc, - 0xe6, 0xe1, 0x3d, 0xd3, 0x4b, 0x74, 0xaf, 0x79, 0x35, 0xe0, 0x86, 0xed, 0xd7, 0x5b, 0x29, 0x65, 0x11, 0x44, 0xd7, - 0x0d, 0xa9, 0xfe, 0x5d, 0x43, 0x2a, 0x3c, 0xe5, 0x6a, 0xb8, 0x6a, 0x15, 0x2f, 0x14, 0xd2, 0x00, 0x02, 0x39, 0xef, - 0x02, 0x97, 0xf2, 0x9e, 0xfa, 0x82, 0x41, 0x73, 0x4f, 0xee, 0xd5, 0x51, 0x37, 0x24, 0xf3, 0x47, 0x90, 0x84, 0xed, - 0x38, 0x04, 0x85, 0x3f, 0xa6, 0x4a, 0xe5, 0xca, 0x64, 0xa3, 0x54, 0xd7, 0x55, 0x1a, 0x21, 0xf2, 0xf6, 0x3a, 0x63, - 0x8b, 0x25, 0x4b, 0xfc, 0x6c, 0x95, 0xb0, 0xeb, 0x30, 0xbe, 0x7d, 0x54, 0xa8, 0xd3, 0xef, 0x28, 0x3c, 0x0f, 0x66, - 0x73, 0x59, 0xfa, 0xac, 0xc5, 0x06, 0x72, 0x01, 0xb7, 0x76, 0x90, 0xff, 0xe7, 0xdf, 0xb6, 0xfd, 0x9f, 0x7f, 0xef, - 0x2c, 0x0a, 0xcd, 0xe7, 0x43, 0x33, 0x1b, 0xec, 0xb1, 0x2f, 0x9a, 0x7b, 0x2a, 0xc3, 0xbc, 0xb9, 0x4c, 0x6d, 0x11, - 0x20, 0xbf, 0xb6, 0x04, 0xb5, 0xc4, 0xf2, 0xbe, 0x79, 0xd0, 0xc0, 0x60, 0x5e, 0x3b, 0x47, 0x06, 0x85, 0xbe, 0x68, - 0x68, 0x43, 0xa3, 0xb7, 0xd7, 0x8a, 0xfc, 0x71, 0x08, 0xef, 0x9a, 0xc3, 0x17, 0x0e, 0x9f, 0xf3, 0x25, 0x5f, 0x0e, - 0x87, 0x32, 0xb6, 0x9c, 0x5a, 0x15, 0x54, 0xfc, 0xcf, 0x6a, 0x29, 0xfc, 0xf2, 0xec, 0x39, 0x06, 0xd9, 0xde, 0x0f, - 0x5e, 0x0e, 0x51, 0x19, 0xed, 0x64, 0x94, 0x14, 0xc4, 0xca, 0x46, 0xd4, 0x46, 0xca, 0xe4, 0xb5, 0x46, 0x6b, 0x78, - 0x0d, 0x52, 0x31, 0xe0, 0x58, 0x3e, 0x34, 0xcc, 0x97, 0x43, 0xce, 0x58, 0xe2, 0xfa, 0xaf, 0xbd, 0xea, 0xd6, 0xe6, - 0x6c, 0xd9, 0x12, 0xd0, 0x4d, 0x8d, 0xe4, 0x3f, 0x58, 0x98, 0x15, 0x7c, 0x3c, 0x64, 0xf0, 0x03, 0x47, 0x61, 0x98, - 0x63, 0xbc, 0x93, 0x77, 0x9b, 0x74, 0xc4, 0x7e, 0xde, 0xad, 0x23, 0x76, 0xb1, 0x97, 0x8e, 0xd8, 0xcf, 0x5f, 0x5d, - 0x47, 0xec, 0x9d, 0xaa, 0x23, 0x06, 0x8b, 0xf8, 0x9a, 0xed, 0xa5, 0xb8, 0x25, 0xb4, 0x36, 0xe2, 0xdb, 0x74, 0xe0, - 0x72, 0x92, 0x36, 0x1d, 0xcf, 0x19, 0xf0, 0x08, 0xf8, 0xaa, 0x84, 0xf1, 0x0c, 0x94, 0xb8, 0xfe, 0x7c, 0x75, 0xab, - 0x30, 0x9e, 0xa9, 0xca, 0x56, 0x11, 0xf7, 0xf8, 0x5a, 0x78, 0x71, 0x22, 0x05, 0x27, 0xc7, 0x14, 0x3e, 0x9f, 0xac, - 0x43, 0x43, 0x89, 0x6a, 0x2d, 0xb5, 0xd7, 0x3c, 0xa1, 0x02, 0xd5, 0x43, 0xed, 0x29, 0x59, 0xd1, 0x7b, 0x2e, 0x7c, - 0x5b, 0xa8, 0x2d, 0x48, 0x2d, 0x61, 0xf2, 0x13, 0xb1, 0xd6, 0x7f, 0xbb, 0x73, 0xbf, 0xbf, 0x74, 0xfb, 0x6d, 0x17, - 0x8c, 0xb3, 0xe1, 0x85, 0x89, 0x09, 0x4e, 0xbf, 0xdd, 0x86, 0x84, 0x5b, 0x25, 0xc1, 0x83, 0x84, 0x40, 0x49, 0xe8, - 0x40, 0xc2, 0x58, 0x49, 0x38, 0x82, 0x84, 0x89, 0x92, 0x70, 0x0c, 0x09, 0x37, 0x7a, 0x7e, 0x19, 0xc9, 0xe1, 0x1e, - 0x1b, 0x57, 0x26, 0x3d, 0x2a, 0x44, 0xda, 0xb1, 0xe9, 0x82, 0xd6, 0x94, 0x3f, 0xeb, 0xc5, 0x26, 0x71, 0x17, 0x7b, - 0x89, 0x79, 0x3b, 0x67, 0xe4, 0x28, 0xfa, 0x15, 0xde, 0x39, 0x76, 0x16, 0x83, 0xde, 0xb4, 0x70, 0xc0, 0x20, 0xe0, - 0xa0, 0xe9, 0x06, 0x30, 0x8c, 0xfa, 0x72, 0xe5, 0x84, 0x13, 0x0b, 0x65, 0x2d, 0x8b, 0x3c, 0xea, 0xce, 0x92, 0x5b, - 0xa0, 0xd0, 0x38, 0x69, 0xa9, 0x5c, 0xc9, 0xaf, 0xa1, 0x77, 0xf0, 0x8a, 0x8d, 0x56, 0x33, 0xed, 0x3c, 0x9e, 0xed, - 0x54, 0x21, 0x50, 0xb3, 0x60, 0x94, 0x3a, 0x89, 0x5f, 0x2c, 0xb1, 0x2d, 0x79, 0x5f, 0xf4, 0x99, 0x97, 0xcb, 0x67, - 0x30, 0x36, 0x2d, 0x23, 0x05, 0x16, 0xe8, 0x07, 0x60, 0xa4, 0xc8, 0xf0, 0xcf, 0x01, 0xce, 0xca, 0xf7, 0x85, 0xaf, - 0x8c, 0xe7, 0xf4, 0x47, 0x96, 0xa6, 0xfe, 0x4c, 0x94, 0xaf, 0x8f, 0x13, 0x94, 0x76, 0xe4, 0xfb, 0x0b, 0x01, 0x08, - 0x9c, 0xbc, 0xa0, 0xa6, 0x9b, 0x91, 0xc4, 0xb7, 0x1a, 0x68, 0xff, 0xc0, 0x86, 0x2a, 0xf4, 0x14, 0x02, 0x1b, 0x96, - 0xb0, 0xac, 0x51, 0x00, 0x87, 0xff, 0x86, 0x85, 0xd5, 0xc4, 0xcc, 0x9f, 0x55, 0x93, 0x68, 0x1f, 0xe4, 0xea, 0xd8, - 0xa4, 0x40, 0xbf, 0x94, 0xf8, 0x25, 0x12, 0xea, 0x30, 0x9e, 0xfd, 0xa9, 0xe2, 0xe9, 0x2d, 0x6a, 0x05, 0x1f, 0x22, - 0x33, 0xc8, 0x86, 0x36, 0xc2, 0x58, 0xb3, 0x01, 0x84, 0xbd, 0x28, 0x9b, 0x5b, 0x68, 0x5a, 0xd6, 0xf2, 0x22, 0xc3, - 0xb4, 0x71, 0x6d, 0xd7, 0x55, 0x83, 0xda, 0x5e, 0x32, 0x1b, 0xf9, 0x2d, 0xd7, 0x3b, 0x36, 0xc5, 0x1f, 0xdb, 0xe9, - 0x18, 0x39, 0xb6, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, 0xbe, 0xb7, 0x88, - 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x1e, 0xd4, 0x7d, 0x74, 0xd5, 0xc0, 0xad, 0x05, 0x5d, 0xdb, 0x4b, 0xd8, - 0x82, 0x6a, 0x4b, 0x4f, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xbc, 0xfb, 0x52, 0x61, 0x2a, 0x8a, 0x5b, 0x8e, 0x6a, 0x00, - 0x45, 0xca, 0xdd, 0x3c, 0x80, 0x73, 0xa3, 0xfe, 0xd2, 0x9f, 0xa0, 0x67, 0x42, 0xdb, 0xeb, 0x24, 0x6c, 0xa1, 0xd9, - 0x9d, 0x8d, 0x8d, 0x27, 0xf1, 0xed, 0x29, 0x8c, 0x16, 0x2b, 0x5b, 0x29, 0x0b, 0xa7, 0x98, 0x63, 0xa1, 0x65, 0x89, - 0x68, 0xc7, 0xc2, 0x87, 0x38, 0xb4, 0xc6, 0x16, 0x7d, 0xc8, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, 0x91, 0x45, 0xd3, - 0x39, 0x76, 0x96, 0x4a, 0x5b, 0x2a, 0xfc, 0x8c, 0x35, 0x16, 0x77, 0x35, 0xa7, 0x0f, 0x8f, 0xb5, 0x69, 0x18, 0xdf, - 0xf6, 0xe6, 0xc1, 0x64, 0xc2, 0xa2, 0x3e, 0x8e, 0x59, 0x26, 0xb2, 0x30, 0x0c, 0x96, 0x69, 0x90, 0xf6, 0x17, 0xfe, - 0x1d, 0x6f, 0xf5, 0x70, 0x53, 0xab, 0x6d, 0xde, 0x6a, 0x7b, 0xef, 0x56, 0x95, 0x66, 0xc0, 0x8a, 0x85, 0xda, 0xe1, - 0x43, 0xeb, 0x68, 0x4e, 0x65, 0x9e, 0x7b, 0xb7, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, 0x39, 0xb9, - 0x7d, 0xb3, 0xa6, 0x8d, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x7c, 0x39, 0x93, 0x49, 0x6e, 0x8f, 0xc5, 0xd7, - 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0x22, 0xa1, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, 0x12, 0xb9, - 0xcd, 0xf8, 0x57, 0xc2, 0x26, 0x7d, 0xdc, 0x48, 0xa4, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x31, 0xc0, 0x65, 0x09, - 0x37, 0x21, 0xaf, 0xe7, 0x6a, 0xbd, 0x77, 0x49, 0xad, 0xe8, 0x6e, 0x3c, 0x6e, 0x2c, 0x37, 0xf1, 0x93, 0x4f, 0x57, - 0x9a, 0x32, 0x0b, 0xdf, 0xa7, 0x62, 0x6b, 0x01, 0x06, 0xeb, 0xae, 0x07, 0x2e, 0xbb, 0xfa, 0xa3, 0x38, 0x81, 0x33, - 0x9b, 0xf8, 0x93, 0x60, 0x95, 0xf6, 0x5c, 0x6f, 0x79, 0x27, 0x92, 0xf8, 0x5e, 0x2f, 0x12, 0xf0, 0xec, 0xf5, 0xd2, - 0x38, 0x0c, 0x26, 0x22, 0x69, 0xd3, 0x59, 0x72, 0x3d, 0xa3, 0x8f, 0x06, 0xeb, 0x01, 0xba, 0x5d, 0xf0, 0xc3, 0x50, - 0xb3, 0xdb, 0xa9, 0xc6, 0xfc, 0x14, 0xf9, 0xcb, 0x9a, 0x93, 0x12, 0x5c, 0xd0, 0x38, 0xdd, 0x3d, 0x5c, 0xde, 0xc9, - 0x3d, 0xef, 0x1e, 0x2d, 0xef, 0xf2, 0xbf, 0x2e, 0xd8, 0x24, 0xf0, 0xb5, 0x56, 0xb1, 0x9b, 0x5c, 0x07, 0x78, 0xd0, - 0xc6, 0x7a, 0xc3, 0x36, 0x15, 0xc7, 0x02, 0x5c, 0x1b, 0x3e, 0x0a, 0x16, 0xcb, 0x38, 0xc9, 0xfc, 0x28, 0xcb, 0xf3, - 0xe1, 0x55, 0x9e, 0xf7, 0x2f, 0x82, 0xd6, 0xe5, 0x3f, 0x5a, 0x74, 0x4f, 0x93, 0xcc, 0x26, 0x37, 0xae, 0xcc, 0xd7, - 0x4c, 0xd5, 0x19, 0x81, 0x6b, 0x0c, 0xf5, 0x45, 0xd4, 0xc2, 0x74, 0x4b, 0xd6, 0x0b, 0x13, 0x90, 0x65, 0x71, 0xd2, - 0x41, 0x29, 0x17, 0xc1, 0x1b, 0x08, 0x0a, 0xbc, 0x66, 0x83, 0x0b, 0x45, 0xff, 0x04, 0x88, 0x15, 0x2c, 0x4c, 0x76, - 0x05, 0x4f, 0x36, 0xd1, 0x8c, 0xdf, 0xed, 0xa6, 0x19, 0x7f, 0xcd, 0xf6, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, - 0x93, 0xba, 0x5d, 0xc1, 0xdb, 0x78, 0xa0, 0x4b, 0x09, 0x03, 0x5c, 0x4d, 0x09, 0x79, 0xec, 0x79, 0xfb, 0x87, 0xcd, - 0x00, 0x44, 0x6b, 0x14, 0x83, 0x8e, 0x6e, 0x6e, 0xe0, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xef, 0xe9, 0x74, - 0xf0, 0x2a, 0x56, 0x12, 0xe4, 0x17, 0x57, 0xbe, 0x28, 0x79, 0x57, 0xa0, 0x1c, 0xa1, 0x85, 0x89, 0xf1, 0x27, 0xc0, - 0x38, 0x9b, 0xb4, 0x8e, 0x27, 0x52, 0xfb, 0xac, 0x5f, 0x1e, 0x42, 0x4b, 0xaa, 0x7c, 0x0a, 0x13, 0x9c, 0x1a, 0x2b, - 0x71, 0xc6, 0x32, 0x6e, 0x33, 0xfb, 0xfd, 0xfd, 0xdb, 0x49, 0xeb, 0x6d, 0x6c, 0xe4, 0x41, 0xfa, 0xae, 0x6a, 0x00, - 0xc3, 0x65, 0x3f, 0x03, 0x75, 0x3a, 0x39, 0xd7, 0x20, 0x53, 0x03, 0x4c, 0x43, 0x36, 0x55, 0x3f, 0x2b, 0xcd, 0xb4, - 0xa7, 0x56, 0xe4, 0x81, 0xae, 0x6a, 0x97, 0x31, 0xb7, 0x3e, 0x58, 0x73, 0x0a, 0x10, 0x63, 0x77, 0xa1, 0xdd, 0xf0, - 0x84, 0xaa, 0x07, 0x93, 0x3c, 0x37, 0xfa, 0x02, 0x10, 0xca, 0x45, 0xcb, 0x76, 0x11, 0x71, 0xe9, 0xad, 0xd4, 0x69, - 0xe0, 0x12, 0x42, 0x12, 0xff, 0xbd, 0x05, 0x81, 0x3a, 0x17, 0x16, 0x72, 0x98, 0xe9, 0x1a, 0x81, 0x8f, 0x14, 0x2d, - 0x94, 0x09, 0x81, 0x04, 0x58, 0xc2, 0x5f, 0x64, 0x89, 0x84, 0xba, 0x0e, 0x27, 0x01, 0x07, 0x35, 0x02, 0xc0, 0xca, - 0x5f, 0xf0, 0xb5, 0x09, 0xed, 0xf0, 0x32, 0xf8, 0x91, 0xeb, 0x92, 0xf6, 0xc3, 0xed, 0x77, 0x7a, 0x72, 0x00, 0x15, - 0x4e, 0x2b, 0x8a, 0x03, 0x3b, 0x34, 0x14, 0x81, 0x94, 0x48, 0x6f, 0x4d, 0x3b, 0xbd, 0xd5, 0x9e, 0xad, 0x85, 0x87, - 0x8c, 0xcc, 0x5f, 0x5a, 0xf0, 0xc4, 0x47, 0xdc, 0xcb, 0x31, 0x9e, 0xe2, 0x8c, 0xa3, 0xbf, 0x4a, 0x01, 0x37, 0xe2, - 0x43, 0x15, 0xf1, 0x4f, 0x7f, 0xbc, 0x4a, 0xd2, 0x38, 0xe9, 0x2d, 0xe3, 0x20, 0xca, 0x58, 0x92, 0x23, 0xa8, 0x2e, - 0x11, 0x3e, 0x02, 0x3c, 0x57, 0xeb, 0x78, 0xe9, 0x8f, 0x83, 0xec, 0xbe, 0xe7, 0x70, 0x92, 0xc2, 0xe9, 0x73, 0xea, - 0xc0, 0x69, 0x2c, 0xdf, 0xe3, 0xd0, 0x7c, 0x8e, 0x84, 0x5f, 0x52, 0x27, 0x67, 0xd4, 0x6d, 0xde, 0x57, 0x72, 0xc9, - 0x47, 0x08, 0x90, 0x1f, 0x7e, 0x62, 0xcd, 0x00, 0xcb, 0xc3, 0x52, 0x3b, 0x13, 0x36, 0x33, 0x11, 0x6b, 0x03, 0x5f, - 0x5e, 0xfc, 0xb1, 0x3b, 0x86, 0xe6, 0x34, 0x27, 0x03, 0xc5, 0x63, 0xec, 0x33, 0xb2, 0x9e, 0x0f, 0x11, 0xb5, 0xcc, - 0x7d, 0x4a, 0x8e, 0xd8, 0x34, 0x4e, 0x18, 0xf9, 0x93, 0x75, 0xbb, 0xcb, 0xbb, 0xfd, 0x9b, 0xdf, 0x3e, 0xfd, 0xe6, - 0x76, 0xa2, 0x38, 0x6b, 0x89, 0xc6, 0x8c, 0x1d, 0xad, 0xd5, 0xef, 0x33, 0x20, 0x0d, 0x09, 0xf2, 0x63, 0x72, 0xdd, - 0xd5, 0xd3, 0xf5, 0x7e, 0xa3, 0xdb, 0xae, 0x65, 0xcc, 0xef, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, 0x9a, 0xb1, - 0x7d, 0xb4, 0xbc, 0x13, 0x6b, 0x8c, 0x17, 0xde, 0x03, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, 0xd5, 0x64, 0x5c, 0xa4, - 0x7e, 0x6d, 0x36, 0xc2, 0x93, 0x45, 0xe5, 0xa6, 0xef, 0x2c, 0xef, 0xd4, 0x2b, 0xba, 0xa8, 0x26, 0x6f, 0xea, 0xaa, - 0x0b, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x2d, 0x74, 0x79, 0x2d, 0x15, 0xe0, 0x48, 0x38, 0xf8, 0xa3, 0x34, - 0x0e, 0x57, 0x19, 0x6b, 0x06, 0x17, 0x01, 0xc7, 0x73, 0x0a, 0xe0, 0xe0, 0xef, 0xf2, 0x58, 0x3b, 0x40, 0x6e, 0xc3, - 0x36, 0x71, 0xfa, 0xe0, 0x71, 0xd8, 0x6a, 0x97, 0x87, 0x0e, 0x59, 0x72, 0xd0, 0x66, 0xc3, 0x44, 0x4c, 0xb8, 0x96, - 0x08, 0x7b, 0x6b, 0xb6, 0xcb, 0xd3, 0xa4, 0xd7, 0x55, 0x99, 0x94, 0x97, 0x27, 0xf3, 0xe7, 0x9c, 0xb1, 0x17, 0xcd, - 0x67, 0xec, 0x85, 0x38, 0x63, 0xdb, 0x77, 0xe6, 0xe3, 0xa9, 0x0b, 0xff, 0xf5, 0x8b, 0x09, 0xf5, 0x1c, 0xad, 0xbd, - 0xbc, 0xd3, 0xdc, 0xe5, 0x9d, 0x66, 0x79, 0xcb, 0x3b, 0x0d, 0x9b, 0x46, 0x7d, 0x10, 0xd3, 0xf6, 0x0c, 0xd3, 0xd1, - 0x20, 0x11, 0xfe, 0x38, 0xa5, 0x2c, 0xf7, 0x10, 0xf2, 0xa0, 0x56, 0xa7, 0x9e, 0xe7, 0x6d, 0x3f, 0xea, 0x74, 0x96, - 0x04, 0xd2, 0x36, 0xec, 0xcc, 0x1f, 0x8d, 0xd8, 0xa4, 0x37, 0x8d, 0xc7, 0xab, 0xf4, 0x5f, 0x7c, 0xfc, 0x1c, 0x88, - 0x5b, 0x11, 0x41, 0xa5, 0x1d, 0x51, 0x15, 0x04, 0x25, 0x37, 0x4c, 0xb4, 0xb0, 0x96, 0xeb, 0xd4, 0x23, 0xf7, 0xc8, - 0x9e, 0x7d, 0xd8, 0xb0, 0xc9, 0x9b, 0x01, 0xfd, 0xa7, 0xad, 0xd2, 0x66, 0x14, 0xf3, 0x05, 0x60, 0xd9, 0x0a, 0x8e, - 0x87, 0x43, 0x83, 0xaf, 0xa6, 0xd3, 0x6d, 0x1e, 0xee, 0xa5, 0xe8, 0xe9, 0x4a, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0x86, - 0x29, 0xdb, 0x5b, 0xdd, 0xb4, 0x47, 0x6a, 0xad, 0x6e, 0xb9, 0x10, 0x8a, 0xb2, 0x7b, 0x62, 0xf9, 0xc7, 0x2f, 0x0e, - 0xe1, 0x3f, 0xa2, 0xea, 0x7f, 0xcd, 0x9a, 0x08, 0xf5, 0xb7, 0x65, 0x4d, 0x70, 0x22, 0x95, 0x90, 0x10, 0xdf, 0xbf, - 0xfc, 0x74, 0xfa, 0xb0, 0x0a, 0x7b, 0x97, 0x26, 0x55, 0xaa, 0x6a, 0xe9, 0xef, 0xe3, 0x18, 0x42, 0x77, 0xd6, 0x8b, - 0x0b, 0xf0, 0x90, 0xb2, 0x7b, 0x36, 0x80, 0x4a, 0xe2, 0x1d, 0x41, 0x52, 0x7c, 0x1d, 0xeb, 0xd0, 0x53, 0xe2, 0xf5, - 0xa6, 0xa7, 0xc4, 0xab, 0xdd, 0x4f, 0x89, 0x1f, 0xf6, 0x7a, 0x4a, 0xbc, 0xfa, 0xea, 0x4f, 0x89, 0xd7, 0xf5, 0xa7, - 0xc4, 0x45, 0x2c, 0xf4, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x09, 0xe5, 0xce, 0xe3, 0x41, 0xc7, 0x21, 0x97, - 0xc7, 0x17, 0x7f, 0xf8, 0x61, 0x81, 0x1b, 0xf1, 0x3d, 0xaa, 0x93, 0x15, 0x4f, 0x0b, 0x8e, 0xd9, 0xb1, 0x1f, 0x25, - 0x39, 0x8c, 0xa3, 0xd9, 0xcf, 0x20, 0x94, 0x05, 0x76, 0x60, 0xa2, 0x64, 0x04, 0xe9, 0xcf, 0xf1, 0x72, 0xb5, 0x7c, - 0x0b, 0x6d, 0x7d, 0x0c, 0xd2, 0x60, 0x14, 0x32, 0x69, 0x89, 0x4c, 0xea, 0x6f, 0x9c, 0x27, 0x0e, 0x1a, 0xa7, 0xe2, - 0xa7, 0x7f, 0x27, 0x7e, 0xa2, 0x4e, 0x2a, 0xff, 0x4d, 0x7a, 0x75, 0x7a, 0xf3, 0x43, 0x44, 0x08, 0x01, 0x95, 0x41, - 0x3f, 0xfc, 0x31, 0x72, 0x11, 0x1b, 0x0d, 0xb3, 0x14, 0xfa, 0x0e, 0x1b, 0xdb, 0x61, 0xb5, 0x47, 0xcd, 0xca, 0x30, - 0xa5, 0x0b, 0xae, 0x3a, 0x1b, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x91, 0x01, 0x48, - 0x38, 0x65, 0x1d, 0x0c, 0x1e, 0xf9, 0x01, 0x09, 0xe5, 0x38, 0x69, 0xe9, 0x10, 0xbb, 0x74, 0xb5, 0xb4, 0x48, 0xd4, - 0x6c, 0xe1, 0x14, 0x75, 0x19, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0x56, 0x53, 0xa8, 0x6a, 0xc4, 0x36, 0xe7, - 0x0a, 0xa7, 0xad, 0x48, 0x30, 0x17, 0x85, 0x1f, 0x8c, 0x86, 0x85, 0xe3, 0x39, 0x64, 0xba, 0x5a, 0xe4, 0x82, 0x17, - 0x91, 0x7c, 0xc5, 0xd7, 0x83, 0x7b, 0x85, 0xa0, 0xcf, 0x97, 0x0a, 0x18, 0xdf, 0xdd, 0xb0, 0x24, 0xf4, 0xef, 0x5b, - 0x46, 0x1e, 0x47, 0x3f, 0x02, 0x00, 0x5e, 0xc5, 0xb7, 0x91, 0x5a, 0x00, 0x83, 0xb5, 0x34, 0xec, 0xa5, 0x46, 0xff, - 0x25, 0x60, 0xb8, 0xa2, 0x8c, 0x00, 0xc2, 0xe4, 0xce, 0xd8, 0xdf, 0x4d, 0xfa, 0xf7, 0x1f, 0x46, 0x6e, 0x9e, 0xc7, - 0xb2, 0xa3, 0x5f, 0x96, 0x7b, 0x74, 0xf3, 0xf4, 0xe9, 0xa3, 0xcd, 0xd3, 0x2e, 0x87, 0x67, 0x6f, 0xa8, 0x6d, 0x6c, - 0x3c, 0x05, 0x30, 0x8a, 0x8b, 0x78, 0x35, 0x9e, 0xa3, 0xa2, 0xeb, 0xd7, 0x9b, 0x6f, 0x06, 0x6d, 0x62, 0x94, 0x52, - 0x39, 0xf5, 0x4a, 0x52, 0x01, 0x05, 0xec, 0xff, 0x35, 0x38, 0xe0, 0xfc, 0x1f, 0x82, 0xa1, 0xbe, 0x6b, 0xf8, 0x2b, - 0x3e, 0x78, 0xd8, 0xe6, 0xed, 0x43, 0x30, 0x4d, 0xee, 0xda, 0x42, 0x08, 0xd7, 0x9a, 0x91, 0x4c, 0x5e, 0x05, 0x9a, - 0xea, 0x46, 0x6e, 0x93, 0x87, 0x3c, 0xd1, 0x0b, 0xb3, 0xe9, 0x99, 0xce, 0x0d, 0x0d, 0x4c, 0xc6, 0xb1, 0x55, 0x05, - 0xc9, 0x70, 0x95, 0x07, 0x86, 0xe8, 0xab, 0x9a, 0xb7, 0x08, 0x22, 0x13, 0xbd, 0xc0, 0xd7, 0x73, 0xfc, 0x3b, 0xf0, - 0x83, 0x0c, 0xc8, 0xad, 0x9a, 0x05, 0x89, 0xa6, 0x6a, 0x37, 0x07, 0xa1, 0x9e, 0xf4, 0x46, 0x48, 0x08, 0x29, 0xde, - 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0xf9, 0x8c, 0xd0, 0xe4, 0x3b, 0x02, 0xd3, 0xf1, 0x39, 0x00, 0xd2, 0x92, 0x7c, 0x79, - 0x47, 0x29, 0xf0, 0x32, 0x40, 0x99, 0xac, 0x48, 0xe0, 0xae, 0xfe, 0x3a, 0x8e, 0x48, 0x10, 0x0f, 0x7a, 0x70, 0xd3, - 0xe6, 0x27, 0xe0, 0x11, 0xb8, 0xa7, 0xe1, 0x83, 0x1d, 0x73, 0x39, 0x27, 0x58, 0x73, 0xe8, 0x73, 0xd8, 0x67, 0xcd, - 0x3e, 0xe1, 0x22, 0x05, 0x0b, 0x82, 0xd4, 0xa1, 0xe2, 0xe2, 0xd9, 0x64, 0x0d, 0xb8, 0x11, 0xdf, 0x45, 0x77, 0xd9, - 0x82, 0x45, 0x2b, 0x1d, 0x63, 0x42, 0xa1, 0x8f, 0x3e, 0x28, 0xf3, 0x8a, 0x88, 0x2d, 0xc0, 0x36, 0xcd, 0x35, 0xe7, - 0x74, 0x17, 0xa6, 0x1c, 0xa5, 0xfa, 0xe6, 0x98, 0x0b, 0x36, 0x53, 0x8e, 0xdb, 0xaa, 0x37, 0x04, 0x5f, 0xd2, 0xb8, - 0x6a, 0xc8, 0x45, 0x9a, 0xd0, 0xd0, 0x06, 0x79, 0xc7, 0xe0, 0xec, 0x22, 0x01, 0xf6, 0x96, 0x5f, 0x5d, 0x34, 0x29, - 0x91, 0xf1, 0x2b, 0x8c, 0xa2, 0xc4, 0xa8, 0x37, 0xc3, 0xc7, 0x09, 0x8e, 0x89, 0x36, 0xb6, 0x33, 0xae, 0xb5, 0xb3, - 0x61, 0xd2, 0x9f, 0xd8, 0x3d, 0x5d, 0x24, 0x04, 0xaa, 0x4f, 0xec, 0x1e, 0x74, 0xff, 0x5e, 0x03, 0x37, 0x45, 0xdf, - 0x82, 0xae, 0x4d, 0x70, 0xf5, 0x3f, 0x06, 0x67, 0x55, 0x5b, 0x0e, 0x90, 0x93, 0x6f, 0xc1, 0xe2, 0x08, 0x62, 0x88, - 0xea, 0x2c, 0x0e, 0x31, 0x57, 0xf1, 0x6f, 0x35, 0xc2, 0xd8, 0x6a, 0x38, 0x1a, 0xc6, 0x33, 0xd7, 0x71, 0x0e, 0x6a, - 0xe5, 0x81, 0x91, 0xdd, 0x54, 0xda, 0x30, 0xb3, 0x81, 0xeb, 0x58, 0xc1, 0x33, 0xdb, 0xeb, 0xd7, 0xee, 0x68, 0xc5, - 0x97, 0xe4, 0x10, 0xd9, 0x5f, 0xa7, 0x4f, 0xd6, 0xad, 0xda, 0x81, 0x34, 0xaa, 0x2a, 0xf3, 0x38, 0xb6, 0x9c, 0xf3, - 0xbf, 0x86, 0xf5, 0xab, 0x9f, 0x3c, 0x59, 0x52, 0x5c, 0x93, 0x21, 0x78, 0x43, 0x6e, 0xc1, 0x31, 0xfa, 0x8b, 0xf6, - 0x5c, 0x6b, 0xd1, 0xf1, 0x31, 0x8c, 0xa1, 0x0c, 0x97, 0x2d, 0x6c, 0xca, 0xd4, 0x06, 0x2a, 0x3d, 0xa6, 0x55, 0x0c, - 0xc7, 0xfd, 0xae, 0xb2, 0x42, 0xa2, 0xb7, 0x95, 0x5a, 0xc0, 0xf6, 0x37, 0x5c, 0x9f, 0xf6, 0x08, 0xfc, 0x12, 0x40, - 0x09, 0xf0, 0x9d, 0xbe, 0xb3, 0xc1, 0xd5, 0xb2, 0xdc, 0x5c, 0xf9, 0x92, 0xdc, 0xbf, 0x31, 0xbc, 0x74, 0x50, 0x86, - 0x26, 0xdb, 0x6b, 0xbe, 0xee, 0x1e, 0xd8, 0x24, 0x8b, 0x26, 0xe5, 0x06, 0x2b, 0xf7, 0xd7, 0xfe, 0xcd, 0x95, 0x30, - 0x0a, 0x04, 0x15, 0x88, 0x1b, 0x30, 0x4a, 0x1e, 0x47, 0xb8, 0xf9, 0xe9, 0xb8, 0x05, 0x7b, 0x51, 0x31, 0x58, 0x81, - 0x3c, 0x82, 0xc9, 0x6a, 0x0a, 0x53, 0x1c, 0x3c, 0x57, 0xa3, 0x59, 0x70, 0x4b, 0x10, 0xa2, 0x1b, 0x77, 0x62, 0x26, - 0x74, 0x0a, 0x8b, 0x3a, 0x01, 0xf7, 0x45, 0xb9, 0x2f, 0xd7, 0x3a, 0xd8, 0xcd, 0xb5, 0xce, 0x76, 0x71, 0xad, 0xc9, - 0x9c, 0xea, 0x36, 0xf1, 0x97, 0x8a, 0x45, 0x9e, 0x20, 0xce, 0x55, 0xc3, 0xbc, 0x12, 0xab, 0x1b, 0xad, 0xaf, 0x44, - 0xad, 0x5a, 0x6b, 0xa4, 0x25, 0x88, 0xec, 0x6f, 0xe5, 0x81, 0x22, 0x04, 0xea, 0x2a, 0x6f, 0xfc, 0xa2, 0xe0, 0x8d, - 0xd3, 0xab, 0xa6, 0x30, 0xa4, 0x11, 0xd4, 0xbf, 0x62, 0xa4, 0x26, 0x5f, 0x07, 0x85, 0xb1, 0x5a, 0x31, 0x52, 0xc5, - 0xfc, 0xaa, 0x78, 0x68, 0x28, 0x46, 0x7d, 0xe2, 0x95, 0x51, 0xb6, 0xed, 0x2b, 0x17, 0x2d, 0xac, 0xaf, 0x8a, 0x74, - 0xe0, 0xba, 0xe3, 0x90, 0x65, 0xb2, 0xba, 0x6d, 0xca, 0xe6, 0x37, 0x6a, 0xb6, 0xb2, 0x49, 0xa4, 0x9d, 0x0c, 0x01, - 0x58, 0xb0, 0xe9, 0x2b, 0x72, 0x6d, 0xa9, 0x03, 0x81, 0x83, 0x6c, 0x30, 0xeb, 0xdb, 0xcd, 0x9d, 0xa7, 0x78, 0x09, - 0x85, 0x14, 0x5e, 0xe5, 0x41, 0x20, 0x7c, 0xaf, 0xd6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xfc, 0x7e, 0x07, 0xf6, 0xa2, - 0xe6, 0xa8, 0x82, 0x7c, 0x3c, 0x99, 0x16, 0xa9, 0xe7, 0x62, 0xd1, 0x7a, 0xa3, 0xc4, 0xc4, 0x59, 0x73, 0xcb, 0x98, - 0x32, 0x8f, 0x9e, 0x97, 0xe8, 0x89, 0x7e, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0xfa, 0xb6, 0xb7, 0xb2, 0xc4, 0x1f, 0x7f, - 0x52, 0x86, 0x2c, 0xf8, 0x9c, 0xc0, 0x03, 0x2e, 0x4b, 0x0a, 0xfa, 0x3e, 0xba, 0x82, 0x64, 0x3d, 0xdb, 0x4b, 0x15, - 0xee, 0x4b, 0xef, 0xb1, 0xd3, 0xf6, 0x5f, 0x4c, 0x0f, 0x2b, 0x4c, 0x51, 0xaf, 0x53, 0x66, 0x99, 0x6f, 0x18, 0x47, - 0x36, 0x5f, 0x2d, 0x46, 0x6b, 0x95, 0xb7, 0xaa, 0xb0, 0x5c, 0xeb, 0x6c, 0x56, 0xb5, 0xdb, 0xe9, 0x74, 0x5a, 0x66, - 0x34, 0x3a, 0xda, 0x21, 0x32, 0x0b, 0x1f, 0x3b, 0x8e, 0x53, 0x1d, 0xfb, 0x76, 0xb0, 0x5b, 0xc8, 0xb7, 0xed, 0x36, - 0x8e, 0x18, 0x61, 0xbb, 0x0b, 0x7e, 0x75, 0x70, 0xe4, 0x76, 0x71, 0xb2, 0x4b, 0x6a, 0x11, 0x7d, 0x52, 0x86, 0x08, - 0x32, 0xb6, 0x48, 0x7b, 0x63, 0x86, 0x32, 0x18, 0x5b, 0x39, 0xd0, 0xa8, 0x38, 0x60, 0xcd, 0x40, 0x55, 0xc4, 0x15, - 0xbb, 0xc2, 0xd1, 0x90, 0x1f, 0x5e, 0x63, 0xde, 0x8b, 0x4e, 0xf0, 0xa0, 0xac, 0xeb, 0x3c, 0x6d, 0x9c, 0x56, 0xc7, - 0xf9, 0x4b, 0xa9, 0x9c, 0x06, 0x17, 0xe0, 0x5a, 0x08, 0xb4, 0x89, 0x3f, 0x8b, 0x7f, 0x4b, 0xfe, 0xff, 0x8b, 0xe5, - 0x5d, 0x59, 0x7f, 0xa4, 0x0b, 0x1c, 0xed, 0xe2, 0xb4, 0xd0, 0xa8, 0x9b, 0xf6, 0x80, 0xd4, 0x32, 0x98, 0xaa, 0x02, - 0x74, 0x10, 0xd2, 0x97, 0x02, 0x80, 0x34, 0xb0, 0xdf, 0x91, 0x62, 0x86, 0x25, 0x2e, 0x58, 0x88, 0x45, 0xf8, 0x3a, - 0x98, 0x83, 0xf9, 0xbc, 0x8b, 0xf2, 0x83, 0xd2, 0x9e, 0x00, 0x69, 0x7c, 0x6d, 0x6e, 0x7b, 0xb1, 0xfb, 0xab, 0x72, - 0x2d, 0xd1, 0x30, 0x80, 0xcc, 0x85, 0x43, 0x88, 0x8a, 0x04, 0x5a, 0x65, 0x73, 0xd3, 0x28, 0x65, 0xae, 0x2a, 0x67, - 0x13, 0x03, 0xc3, 0xe6, 0x9a, 0x8b, 0x50, 0xdb, 0x42, 0x5a, 0x00, 0x93, 0xe5, 0xdb, 0x0f, 0xbf, 0x2d, 0x58, 0x62, - 0x75, 0x3f, 0xba, 0xb8, 0xe4, 0xb8, 0x7f, 0x2d, 0xbc, 0x3b, 0x53, 0x3a, 0xff, 0xc8, 0x5f, 0xfc, 0xa1, 0x91, 0xa1, - 0x77, 0x51, 0xe2, 0xd0, 0x71, 0x6d, 0x71, 0xcf, 0xd8, 0xab, 0xf4, 0x22, 0x88, 0xf6, 0x2f, 0xeb, 0xdf, 0xed, 0x5d, - 0x16, 0x2e, 0x8c, 0xbd, 0x0b, 0xc3, 0x8d, 0x43, 0x9a, 0x0b, 0xd9, 0xe0, 0x07, 0x85, 0xa1, 0xa8, 0x5a, 0x1d, 0xeb, - 0x58, 0x8b, 0xa8, 0xfc, 0x8b, 0xd5, 0x60, 0x78, 0x72, 0x76, 0xb7, 0x08, 0xb5, 0x1b, 0x96, 0x40, 0x68, 0x9f, 0x81, - 0xee, 0xda, 0x8e, 0xae, 0xa1, 0x0d, 0x6d, 0x10, 0xcd, 0x06, 0xfa, 0x2f, 0x17, 0x6f, 0xac, 0xae, 0x7e, 0x06, 0x22, - 0xda, 0x9b, 0x19, 0x5e, 0x7b, 0xe7, 0xfe, 0x3d, 0x4b, 0xae, 0x3d, 0x5d, 0xc3, 0x08, 0x3e, 0x74, 0xe1, 0x61, 0x9a, - 0xe6, 0xe9, 0x7b, 0x04, 0x8a, 0xd0, 0x44, 0xac, 0x37, 0x1d, 0x50, 0x8e, 0xeb, 0x75, 0x35, 0xd7, 0x3b, 0xb4, 0x8f, - 0xba, 0xfa, 0xe9, 0x37, 0x9a, 0x76, 0x32, 0x61, 0xd3, 0xf4, 0x14, 0x9f, 0x68, 0x27, 0x78, 0x47, 0xd0, 0x6f, 0x4d, - 0xb3, 0xc7, 0x61, 0x6a, 0xb9, 0xda, 0x9a, 0x7f, 0x6a, 0xda, 0x34, 0x08, 0xc3, 0x9e, 0xf6, 0x78, 0xea, 0x4d, 0x0f, - 0xa7, 0x2f, 0xfa, 0x3c, 0x39, 0xff, 0xa6, 0x54, 0xdc, 0xa4, 0x7f, 0x3d, 0xa5, 0x5a, 0x9a, 0x25, 0xf1, 0x27, 0xc6, - 0xd5, 0x4e, 0x34, 0xf9, 0x78, 0xac, 0x56, 0xf5, 0xea, 0x3d, 0xb9, 0xdd, 0xd1, 0x78, 0xea, 0x15, 0xc5, 0x71, 0x8c, - 0x07, 0x72, 0x90, 0x27, 0x07, 0x62, 0xe8, 0x27, 0x2a, 0x98, 0x5c, 0xab, 0x09, 0x50, 0xae, 0xce, 0xe7, 0x38, 0x13, - 0xf3, 0x3b, 0x01, 0x3f, 0x8c, 0xd2, 0x5c, 0x17, 0x46, 0xa0, 0x6b, 0x93, 0x81, 0xfe, 0xa3, 0xeb, 0x75, 0x4d, 0xd7, - 0x3d, 0xb2, 0x8f, 0xba, 0x63, 0xc7, 0x3c, 0xb4, 0x0f, 0xad, 0xb6, 0x7d, 0x64, 0x76, 0xad, 0xae, 0xd9, 0xfd, 0x5b, - 0x77, 0x6c, 0x1d, 0xda, 0x87, 0xa6, 0x63, 0x75, 0x21, 0xd1, 0xea, 0x5a, 0xdd, 0x1b, 0xeb, 0xb0, 0x3b, 0x76, 0x30, - 0xd5, 0xb3, 0x3b, 0x1d, 0xcb, 0x75, 0xec, 0x4e, 0xc7, 0xec, 0xd8, 0x47, 0x47, 0x96, 0xdb, 0xb6, 0x8f, 0x8e, 0xce, - 0x3b, 0x5d, 0xbb, 0x0d, 0x79, 0xed, 0xf6, 0xb8, 0x6d, 0xbb, 0xae, 0x05, 0x7f, 0x99, 0x5d, 0xdb, 0xa3, 0x1f, 0xae, - 0x6b, 0xb7, 0x5d, 0xd3, 0x09, 0x3b, 0x9e, 0x7d, 0xf4, 0xc2, 0xc4, 0xbf, 0xb1, 0x98, 0x89, 0x7f, 0x41, 0x33, 0xe6, - 0x0b, 0xdb, 0x3b, 0xa2, 0x5f, 0xd8, 0xe0, 0xcd, 0x61, 0xf7, 0x57, 0xfd, 0x60, 0xe3, 0x1c, 0x5c, 0x9a, 0x43, 0xb7, - 0x63, 0xb7, 0xdb, 0xe6, 0xa1, 0x6b, 0x77, 0xdb, 0x73, 0xeb, 0xd0, 0xb3, 0x8f, 0x8e, 0xc7, 0x96, 0x6b, 0x1f, 0x1f, - 0x9b, 0x8e, 0xd5, 0xb6, 0x3d, 0xd3, 0xb5, 0x0f, 0xdb, 0xf8, 0xa3, 0x6d, 0x7b, 0x37, 0xc7, 0x2f, 0xec, 0xa3, 0xce, - 0xfc, 0xc8, 0x3e, 0xfc, 0x78, 0xd8, 0xb5, 0xbd, 0xf6, 0xbc, 0x7d, 0x64, 0x7b, 0xc7, 0x37, 0x47, 0xf6, 0xe1, 0xdc, - 0xf2, 0x8e, 0xb6, 0xd6, 0x74, 0x3d, 0x1b, 0x60, 0x84, 0xd9, 0x90, 0x61, 0xf2, 0x0c, 0xf8, 0x33, 0xc7, 0xba, 0xff, - 0xc5, 0x66, 0xd2, 0x7a, 0xd5, 0x17, 0x76, 0xf7, 0x78, 0x4c, 0xc5, 0x21, 0xc1, 0x12, 0x25, 0xa0, 0xca, 0x8d, 0x45, - 0xdd, 0x62, 0x73, 0x96, 0x68, 0x48, 0xfc, 0xe1, 0x9d, 0xdd, 0x58, 0xd0, 0x31, 0xf5, 0xfb, 0x3f, 0x6d, 0x47, 0x2e, - 0x39, 0x44, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x41, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x41, 0xc5, 0xfb, 0xdd, 0x82, 0x8a, - 0x37, 0xab, 0x7d, 0x04, 0x15, 0xef, 0xbf, 0xba, 0xa0, 0xe2, 0xbc, 0xaa, 0x27, 0xff, 0xbe, 0xea, 0x9b, 0xfe, 0xd7, - 0x75, 0xf5, 0x19, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x78, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, 0x4a, 0x4a, - 0x60, 0x31, 0xe0, 0xd8, 0xf7, 0x31, 0xe1, 0xd8, 0xdf, 0x57, 0x03, 0xd0, 0x3c, 0xe1, 0x74, 0x49, 0x30, 0xb1, 0xe6, - 0x7e, 0x38, 0x95, 0x34, 0x0d, 0xa4, 0xf4, 0x31, 0x19, 0xac, 0x12, 0xe0, 0xba, 0x06, 0x71, 0xd8, 0x6a, 0x11, 0xa5, - 0xbd, 0x23, 0x07, 0x2e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xca, 0xb6, 0xf0, 0x47, 0x75, 0xcd, 0xad, 0x26, 0x36, 0xe6, - 0xa3, 0x52, 0x60, 0x73, 0xeb, 0x6e, 0xbd, 0x5d, 0x0d, 0xb4, 0x6d, 0x84, 0xd2, 0x24, 0x90, 0x73, 0x4d, 0xf9, 0x65, - 0xd5, 0xbc, 0x8a, 0x32, 0xe6, 0xe6, 0x91, 0xc2, 0x48, 0xaa, 0xf5, 0xdd, 0xb2, 0x6a, 0xdf, 0xae, 0x69, 0x36, 0x74, - 0x5f, 0xaa, 0xbe, 0x45, 0xaf, 0x50, 0x36, 0x5c, 0x05, 0x55, 0x25, 0xb2, 0x5a, 0x23, 0x40, 0x0a, 0xea, 0xbe, 0x50, - 0x3e, 0x2c, 0x48, 0x4b, 0x47, 0x43, 0x7a, 0xc7, 0x51, 0xf2, 0x4a, 0x6d, 0xaa, 0x0a, 0x8b, 0xcf, 0xd6, 0x48, 0x71, - 0x07, 0xbf, 0x03, 0xe9, 0xc8, 0x29, 0x9e, 0x51, 0xac, 0xc2, 0x79, 0xad, 0xb4, 0x4b, 0x8f, 0x99, 0x7c, 0xee, 0xae, - 0xeb, 0xc4, 0xe3, 0x46, 0x55, 0x65, 0x97, 0x2d, 0x04, 0x15, 0x84, 0xdd, 0x93, 0x62, 0x70, 0x4e, 0xca, 0xdb, 0xa8, - 0xfb, 0xbc, 0xad, 0x31, 0x51, 0xee, 0x31, 0x6c, 0x62, 0x93, 0x7f, 0xa8, 0x7e, 0x01, 0xd6, 0x53, 0x88, 0x82, 0xdd, - 0x43, 0x32, 0x4d, 0xa1, 0x51, 0x3d, 0xd4, 0x62, 0xee, 0x6f, 0x51, 0xb0, 0x51, 0x1b, 0xe6, 0x8d, 0xa0, 0x36, 0xf4, - 0x36, 0x9d, 0x1c, 0x69, 0x3c, 0xb2, 0x2e, 0x89, 0xa8, 0xdd, 0xce, 0xb1, 0xe9, 0x1e, 0x99, 0xf6, 0x71, 0xc7, 0xc8, - 0xc5, 0x81, 0x53, 0x9b, 0x2c, 0x01, 0x04, 0x94, 0xa2, 0xe5, 0x30, 0x83, 0x28, 0xc8, 0x02, 0x3f, 0xcc, 0x81, 0x3e, - 0x2e, 0xbf, 0x2a, 0xfe, 0xb9, 0x4a, 0x33, 0x98, 0xa3, 0x20, 0x7a, 0x51, 0x21, 0xdc, 0x1a, 0xb1, 0xec, 0x96, 0xb1, - 0x68, 0x83, 0xb0, 0xbc, 0xaa, 0x5f, 0xfe, 0xe7, 0x69, 0xdb, 0xe6, 0xa4, 0xc9, 0x32, 0xca, 0x22, 0xbe, 0x3f, 0x84, - 0x32, 0x74, 0x3e, 0x34, 0x7f, 0xda, 0x84, 0x70, 0xff, 0xb9, 0x1b, 0xe1, 0x66, 0x6c, 0x1f, 0x84, 0xfb, 0xcf, 0xaf, - 0x8e, 0x70, 0x7f, 0x52, 0x11, 0x6e, 0xc9, 0x16, 0xa8, 0xe0, 0x3a, 0x7f, 0xc0, 0xef, 0x16, 0x38, 0x75, 0x7e, 0xae, - 0x1f, 0x10, 0x01, 0xaf, 0x2b, 0xc1, 0x76, 0x3f, 0x96, 0xa2, 0x07, 0x21, 0x53, 0x04, 0x9d, 0xd0, 0x52, 0xa4, 0x12, - 0x08, 0x44, 0x2b, 0x43, 0xaa, 0x43, 0x9b, 0x6f, 0xa3, 0x2c, 0xb4, 0xdf, 0xf3, 0x87, 0x1f, 0x08, 0x79, 0xde, 0xc4, - 0xc9, 0xc2, 0x47, 0x07, 0x7c, 0x3a, 0x46, 0x1d, 0x84, 0x0f, 0x07, 0xec, 0xcf, 0xc6, 0x71, 0x34, 0x91, 0x92, 0x0a, - 0x36, 0xb8, 0x24, 0x8a, 0x5b, 0xbf, 0x67, 0x7e, 0xa2, 0x9b, 0x94, 0x0d, 0x8b, 0xfb, 0xac, 0xed, 0x3c, 0xf3, 0x0e, - 0x9f, 0x1d, 0x39, 0xf0, 0xbf, 0xcb, 0xda, 0xb9, 0xc9, 0x0b, 0x2e, 0xe2, 0x08, 0x02, 0x9f, 0x88, 0x92, 0x9b, 0x8a, - 0xdd, 0x32, 0xf6, 0xa9, 0x28, 0x75, 0xdc, 0x5c, 0x68, 0xe2, 0xdf, 0x17, 0x65, 0x1a, 0x4b, 0xcc, 0xe3, 0x95, 0x32, - 0xac, 0x86, 0xd1, 0x04, 0xd1, 0x0a, 0x78, 0x6f, 0x4a, 0x09, 0x35, 0x9b, 0x4f, 0xb7, 0x98, 0x17, 0x6b, 0xe7, 0x57, - 0x45, 0x74, 0x25, 0x11, 0xe5, 0x65, 0x27, 0x04, 0xb9, 0xd8, 0xc2, 0x41, 0xdf, 0xec, 0x18, 0x5f, 0x48, 0x83, 0xd8, - 0x86, 0x62, 0x81, 0x7c, 0x5a, 0xa0, 0x2c, 0x59, 0x45, 0xe3, 0x16, 0xfe, 0xf4, 0x47, 0x69, 0x2b, 0x38, 0x00, 0xef, - 0xac, 0xd8, 0xb1, 0x81, 0xab, 0xe6, 0x9f, 0x3a, 0x45, 0x28, 0x8a, 0x54, 0xac, 0x8a, 0xff, 0x2c, 0x33, 0x13, 0x0a, - 0x60, 0x8b, 0x4b, 0x6b, 0x0d, 0xfc, 0x67, 0xb2, 0xe2, 0xb3, 0xcc, 0x84, 0x20, 0xb2, 0xb0, 0xdc, 0x4f, 0x9f, 0x52, - 0x29, 0x08, 0xeb, 0x48, 0xd3, 0x3a, 0x1b, 0x17, 0xee, 0xdd, 0x34, 0x7f, 0x16, 0x93, 0x87, 0xb7, 0xde, 0xd8, 0x8c, - 0x9f, 0x3f, 0x3f, 0x1d, 0xb8, 0x06, 0x0f, 0x4a, 0x5a, 0x8a, 0xa0, 0x75, 0xbe, 0x9f, 0xf2, 0x81, 0xd1, 0x68, 0x16, - 0xb7, 0x84, 0x37, 0x93, 0x23, 0x54, 0x94, 0x39, 0xf6, 0x82, 0x88, 0x16, 0x24, 0x64, 0xf4, 0x85, 0x12, 0x80, 0x28, - 0x23, 0x5f, 0x5d, 0x6d, 0xdb, 0xb1, 0x1d, 0x5d, 0x56, 0x9c, 0x06, 0xb3, 0xc1, 0x3a, 0xce, 0x7c, 0x88, 0x0d, 0x14, - 0xc6, 0x33, 0xb0, 0xad, 0xc9, 0x82, 0x2c, 0x84, 0x40, 0x33, 0x60, 0x64, 0xb3, 0xa0, 0x77, 0x79, 0xce, 0x35, 0x9e, - 0xfd, 0xe4, 0x13, 0x06, 0x1b, 0x14, 0x66, 0x75, 0xe8, 0x71, 0xe8, 0x47, 0xb8, 0x0c, 0x5b, 0x7a, 0x0b, 0x42, 0x5d, - 0xb2, 0x24, 0xb5, 0x54, 0x0b, 0x82, 0x9e, 0x06, 0x75, 0x20, 0x0c, 0x3d, 0x36, 0x30, 0x4d, 0xfc, 0x05, 0xf8, 0x64, - 0x5f, 0xe7, 0x26, 0xc7, 0xb4, 0x3a, 0x47, 0xb5, 0x9a, 0xfb, 0xe2, 0xc8, 0xd4, 0x3c, 0xd7, 0xd4, 0x1c, 0x40, 0xb7, - 0x7a, 0x6e, 0xae, 0xf3, 0xab, 0xfe, 0x2e, 0x21, 0x28, 0xe1, 0x97, 0xc7, 0x34, 0x0f, 0x12, 0x7f, 0x72, 0xf6, 0x72, - 0x46, 0x0e, 0x24, 0x5b, 0x8a, 0xb7, 0xf4, 0x80, 0x04, 0x21, 0x17, 0xec, 0x2e, 0x33, 0x30, 0x10, 0x0b, 0x2f, 0x12, - 0x18, 0x6b, 0x34, 0xfe, 0x0b, 0x22, 0x2d, 0xf8, 0xfc, 0xb9, 0x15, 0x80, 0x81, 0xc3, 0x40, 0x81, 0x0f, 0x7c, 0x1b, - 0x25, 0x80, 0x05, 0x85, 0xe8, 0x0e, 0x81, 0x05, 0xd6, 0x47, 0xf0, 0x6f, 0x91, 0x2c, 0x7e, 0x70, 0xd1, 0xa9, 0x1d, - 0xfa, 0xd1, 0x0c, 0x50, 0x9a, 0x1f, 0xcd, 0x6a, 0x2a, 0x1a, 0x64, 0xbf, 0x58, 0x49, 0x2d, 0x9a, 0x2a, 0xd4, 0x27, - 0xd2, 0xef, 0xef, 0x2f, 0x28, 0xd0, 0x14, 0x04, 0x35, 0xf7, 0x27, 0x68, 0x6c, 0x57, 0x48, 0x77, 0x9e, 0x0f, 0xbe, - 0x3d, 0x59, 0xb0, 0xcc, 0x27, 0xd6, 0x30, 0x3c, 0x7e, 0x81, 0x1c, 0xd0, 0xc6, 0x22, 0x48, 0x2c, 0x05, 0x93, 0x9f, - 0xb0, 0x9b, 0x60, 0xcc, 0xdf, 0xa5, 0xa6, 0xc6, 0xef, 0x29, 0x0b, 0xb5, 0xc0, 0x06, 0xae, 0x49, 0x4a, 0xc8, 0x63, - 0x1f, 0xdd, 0x4c, 0x0e, 0xa2, 0x58, 0x3f, 0xfd, 0x56, 0xda, 0x6b, 0x6d, 0x5a, 0x04, 0x88, 0xf6, 0x78, 0x99, 0xb0, - 0xf0, 0x5f, 0x83, 0x6f, 0xe1, 0xe2, 0xfe, 0xf6, 0x4a, 0x37, 0xfa, 0x99, 0x3d, 0x4f, 0xd8, 0x74, 0xf0, 0x6d, 0x43, - 0xd4, 0x43, 0x7c, 0xde, 0xd3, 0x58, 0xf4, 0xb6, 0x57, 0x38, 0x07, 0x6a, 0xef, 0xf5, 0xa8, 0x3f, 0xe5, 0xaf, 0x75, - 0x78, 0x01, 0xae, 0x4b, 0x6f, 0x6c, 0xb7, 0x8f, 0xef, 0xe7, 0x51, 0xe8, 0x8f, 0x3f, 0xf5, 0x29, 0xa7, 0xf4, 0x61, - 0xc1, 0x6d, 0x3d, 0xf6, 0x97, 0x3d, 0xbc, 0x5e, 0xd5, 0x44, 0x30, 0xd7, 0xa4, 0x54, 0x49, 0xd9, 0x35, 0xee, 0x65, - 0xdc, 0xca, 0x6b, 0xec, 0x19, 0xbb, 0xba, 0x9d, 0x07, 0x19, 0x13, 0x5d, 0xe1, 0x47, 0x9e, 0x8b, 0x87, 0x3a, 0x3d, - 0x51, 0xf1, 0x61, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, 0x74, 0xbb, - 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, 0x3f, 0xba, - 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xb5, 0xe0, 0x01, 0x44, 0xef, 0x9d, 0x6f, 0x4b, 0x58, 0x40, 0xf9, - 0x2d, 0xe5, 0x34, 0x66, 0xe9, 0x7a, 0x6b, 0x90, 0xf5, 0x00, 0xca, 0xd0, 0x4d, 0xe1, 0x04, 0x32, 0xea, 0xb7, 0x20, - 0x0c, 0x3b, 0x06, 0x10, 0x10, 0x2a, 0x2f, 0xc2, 0x2e, 0x55, 0xb8, 0xd2, 0x6f, 0x3c, 0x46, 0xbc, 0x4e, 0xb3, 0xc3, - 0x75, 0x11, 0x99, 0x8a, 0x84, 0x43, 0xbf, 0x2c, 0xd1, 0x89, 0x91, 0x70, 0x11, 0xaf, 0x60, 0xa5, 0x22, 0x3a, 0x62, - 0xbe, 0x7b, 0xe0, 0x68, 0x99, 0xcb, 0x64, 0x74, 0x9e, 0xaf, 0xda, 0x36, 0x17, 0x18, 0xc9, 0xd6, 0xff, 0x68, 0x3b, - 0x18, 0x94, 0x96, 0xda, 0x11, 0xde, 0x5c, 0x27, 0x41, 0x22, 0x87, 0xa7, 0xa0, 0x68, 0xb7, 0xd9, 0x53, 0xbd, 0x01, - 0x61, 0x4c, 0xde, 0x02, 0x95, 0x7c, 0xe3, 0x87, 0x8a, 0x72, 0x8b, 0x52, 0xf3, 0x91, 0xc4, 0xfc, 0x4f, 0x9f, 0x16, - 0x83, 0xb3, 0x2a, 0xe3, 0x3e, 0x71, 0x3b, 0x70, 0xed, 0x76, 0x58, 0x7b, 0xab, 0x9e, 0xd5, 0x6e, 0x77, 0xc0, 0x85, - 0xbb, 0x50, 0xa1, 0x4b, 0x21, 0xa4, 0xb8, 0x1b, 0x95, 0xbd, 0x6a, 0x32, 0x5c, 0x70, 0xa4, 0x5c, 0x79, 0xea, 0xe8, - 0x46, 0x3f, 0x12, 0x22, 0xc9, 0x68, 0x8b, 0x0b, 0x64, 0xfe, 0x16, 0xd3, 0x01, 0x34, 0x5b, 0xe6, 0xb1, 0xc3, 0x68, - 0xf4, 0x7f, 0x3d, 0x09, 0x34, 0xe0, 0x02, 0x19, 0x6a, 0xe5, 0xb4, 0x96, 0x0c, 0x7a, 0xe4, 0xbd, 0x4a, 0x17, 0x2a, - 0x4b, 0xcf, 0x74, 0x48, 0x82, 0xf8, 0x56, 0x18, 0xd2, 0x4e, 0x2a, 0x90, 0xc9, 0xdb, 0xa2, 0x48, 0x30, 0x03, 0xf0, - 0x01, 0xde, 0x12, 0xc6, 0x64, 0xc6, 0xd3, 0xa7, 0x1b, 0x2f, 0x21, 0x12, 0xd8, 0xab, 0x91, 0x3d, 0x75, 0x15, 0xbf, - 0xe9, 0x2a, 0x8a, 0x91, 0xed, 0x22, 0xd6, 0x10, 0x7a, 0x6f, 0xb4, 0xf7, 0xf0, 0xe7, 0x88, 0xf9, 0x99, 0xcd, 0x25, - 0x4d, 0x2d, 0xe5, 0x72, 0x37, 0x5d, 0xd6, 0x06, 0x8d, 0x37, 0xee, 0xeb, 0x8c, 0xfb, 0x12, 0x7c, 0xb2, 0xfe, 0xb8, - 0xe2, 0x96, 0xde, 0xd0, 0xc6, 0x67, 0xa7, 0x70, 0x4f, 0xf3, 0x2e, 0xf3, 0xc9, 0x87, 0x89, 0x7a, 0xe5, 0xc6, 0x99, - 0x2f, 0xe2, 0xc8, 0x00, 0x5d, 0xde, 0x6f, 0x14, 0xc9, 0x2a, 0xd6, 0xe0, 0xa7, 0xef, 0x2e, 0xbe, 0xd3, 0xf8, 0xfe, - 0x27, 0x09, 0x22, 0x3e, 0x64, 0x28, 0xea, 0xc1, 0x80, 0xa2, 0x1e, 0x68, 0x3c, 0x8c, 0x08, 0xc4, 0x0e, 0xc8, 0x0f, - 0x08, 0x82, 0xc8, 0x80, 0x26, 0xb9, 0xea, 0x62, 0x15, 0x66, 0xc1, 0xd2, 0x4f, 0xb2, 0x03, 0xa8, 0x6a, 0x01, 0x92, - 0xd3, 0x37, 0xd9, 0x88, 0x93, 0x68, 0x56, 0xb8, 0xd8, 0xcb, 0x22, 0x21, 0x9b, 0x9d, 0x06, 0xa1, 0x14, 0xcd, 0x8a, - 0x0e, 0xfc, 0xf1, 0x98, 0x2d, 0xb3, 0x81, 0xee, 0x2f, 0x21, 0xfa, 0x05, 0xfa, 0xb3, 0x3e, 0x88, 0xc7, 0x19, 0xcb, - 0xac, 0x34, 0x4b, 0x98, 0xbf, 0xd0, 0xa5, 0x2b, 0xd7, 0x7a, 0x7b, 0xe9, 0x6a, 0xb4, 0x08, 0x32, 0xe9, 0x0b, 0x91, - 0x26, 0x08, 0x42, 0x52, 0x18, 0xe2, 0xe9, 0x30, 0xe7, 0x20, 0x3c, 0x8f, 0x67, 0x95, 0x1d, 0x55, 0x50, 0x2e, 0x67, - 0xe8, 0x69, 0x97, 0x47, 0x3c, 0x98, 0xa0, 0xcd, 0xd3, 0x35, 0xb7, 0x6b, 0x97, 0x2e, 0x1b, 0xf5, 0xd3, 0x13, 0xfe, - 0xbc, 0xd5, 0xd0, 0x15, 0x83, 0xde, 0x71, 0xc0, 0x97, 0xf0, 0x26, 0x8b, 0xf7, 0x03, 0x5e, 0x18, 0xae, 0x26, 0x6a, - 0x19, 0xfd, 0xbc, 0xd3, 0x58, 0x2e, 0x80, 0x10, 0x2a, 0x09, 0xd1, 0xe7, 0xee, 0xa9, 0x34, 0xb1, 0xc2, 0x51, 0x21, - 0xad, 0xf4, 0xf9, 0xf3, 0xcb, 0xe1, 0x7f, 0xfe, 0x0d, 0xce, 0xe8, 0xe7, 0xae, 0xb0, 0x33, 0xbf, 0x54, 0x4b, 0x71, - 0xea, 0xd3, 0x1c, 0xa2, 0x02, 0x05, 0x9b, 0x08, 0xc7, 0x2b, 0x62, 0x6b, 0xe5, 0xc3, 0x2b, 0xe1, 0x4c, 0x0b, 0x02, - 0x4e, 0x18, 0xc2, 0x1a, 0x7e, 0x08, 0xcb, 0x3b, 0x14, 0x4e, 0x18, 0xb4, 0xdf, 0xee, 0xbe, 0x3f, 0x06, 0x67, 0xcb, - 0xb5, 0x38, 0x10, 0xca, 0x00, 0x71, 0x0f, 0x9d, 0x9e, 0xf8, 0x1a, 0x12, 0x2d, 0x48, 0x7e, 0xa4, 0xbd, 0x03, 0x98, - 0xe6, 0x3c, 0x5e, 0x30, 0x3b, 0x88, 0x0f, 0x6e, 0xd9, 0xc8, 0xf2, 0x97, 0x01, 0xc9, 0xea, 0x91, 0xef, 0xa6, 0x11, - 0xe5, 0x27, 0x45, 0xe0, 0x44, 0x5f, 0xe7, 0x05, 0x28, 0xe3, 0x02, 0x50, 0xf0, 0xd3, 0x3f, 0x2d, 0xfb, 0x67, 0xb4, - 0x45, 0x84, 0x80, 0x32, 0x96, 0x3f, 0x23, 0x37, 0x8b, 0xc2, 0xa3, 0x62, 0xf1, 0x61, 0xc5, 0xd3, 0xa9, 0xea, 0x53, - 0xd1, 0x2e, 0xf7, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0x49, 0x3d, 0xd5, 0xbb, 0x90, 0x3f, 0x21, 0x3a, 0x32, 0x77, - 0xbf, 0x09, 0xe7, 0xb9, 0xe6, 0x9b, 0x51, 0x82, 0xe4, 0x31, 0x15, 0xe2, 0x88, 0xa2, 0xea, 0x09, 0x7c, 0x03, 0x69, - 0xf2, 0x68, 0x30, 0x20, 0x3c, 0x56, 0x45, 0x67, 0x00, 0xa5, 0x86, 0x68, 0x09, 0x30, 0xd9, 0x0c, 0x2a, 0x5a, 0x64, - 0x23, 0x87, 0x95, 0xaa, 0xd3, 0xa9, 0x8f, 0xf1, 0xc0, 0x17, 0xfb, 0xab, 0xb4, 0x03, 0x61, 0x67, 0xf1, 0x85, 0x05, - 0x04, 0x2e, 0xda, 0xa9, 0xe0, 0x71, 0xed, 0xaf, 0x84, 0xb2, 0xad, 0xd0, 0xbf, 0x8f, 0x15, 0xdd, 0x05, 0xee, 0xc6, - 0xe0, 0x1c, 0x53, 0x2f, 0x84, 0xf9, 0x60, 0xed, 0x24, 0x49, 0x8f, 0xf3, 0xf5, 0xd3, 0xa4, 0xba, 0x88, 0xdf, 0x75, - 0x98, 0xd4, 0xb2, 0xe5, 0xc9, 0x20, 0x76, 0xcc, 0x8b, 0x83, 0x56, 0xca, 0xc4, 0x73, 0x9f, 0x9f, 0x1c, 0xc0, 0xfc, - 0xc0, 0xf5, 0x42, 0x89, 0x32, 0x0a, 0x0c, 0xf0, 0xef, 0xe0, 0xa7, 0xa4, 0x7f, 0xf1, 0x76, 0x22, 0x88, 0x3a, 0x7c, - 0x39, 0x4a, 0xe7, 0xaf, 0xa5, 0x22, 0x75, 0x62, 0xc5, 0x69, 0xa6, 0xf2, 0x76, 0x47, 0x68, 0xf8, 0x7d, 0x85, 0xe1, - 0x19, 0xf2, 0x7e, 0xc6, 0x84, 0x65, 0xf3, 0x79, 0xb6, 0xc1, 0xf8, 0x79, 0x53, 0x11, 0x22, 0x58, 0xb7, 0x14, 0x28, - 0xf6, 0xf1, 0xb6, 0x52, 0x05, 0x69, 0x24, 0x8b, 0x2d, 0xfd, 0x96, 0xfe, 0x18, 0x77, 0x7c, 0xad, 0x34, 0xa6, 0x42, - 0xb9, 0xf3, 0x6c, 0x00, 0x45, 0x05, 0xb3, 0xdd, 0x5f, 0x2e, 0xa9, 0xb0, 0xd1, 0x3f, 0x39, 0xa0, 0x77, 0xe7, 0x29, - 0xed, 0xb0, 0xd3, 0x13, 0xd0, 0xdf, 0xa4, 0x45, 0xf7, 0x97, 0x4b, 0xbe, 0xa4, 0xf4, 0x8b, 0x72, 0x0e, 0xe6, 0xd9, - 0x22, 0x3c, 0xfd, 0x3f, 0x1d, 0xdb, 0x6f, 0x83, 0x01, 0x5c, 0x03, 0x00}; + 0xdc, 0xb3, 0x37, 0xb7, 0x6d, 0x23, 0xff, 0x7f, 0x3f, 0x05, 0xc3, 0xe4, 0x52, 0x31, 0x21, 0x69, 0x92, 0xb2, 0x6c, + 0x45, 0xb2, 0xec, 0x6b, 0xf3, 0x98, 0x4b, 0xc7, 0x6d, 0x3a, 0x89, 0x9b, 0xb9, 0xab, 0xeb, 0xb1, 0x28, 0x09, 0x92, + 0x78, 0xa1, 0x48, 0x0d, 0x49, 0xf9, 0x51, 0x85, 0xf7, 0x59, 0xee, 0xb3, 0xdc, 0x27, 0xfb, 0xcd, 0xee, 0x02, 0x20, + 0xf8, 0xd0, 0xc3, 0x4d, 0x7a, 0xf7, 0x9b, 0x36, 0x89, 0x08, 0x02, 0x4b, 0x60, 0x01, 0x2c, 0x16, 0xfb, 0xf4, 0x67, + 0x5c, 0xf6, 0x62, 0xb6, 0xd8, 0x7e, 0x9f, 0xfb, 0xfc, 0x99, 0xd9, 0xb8, 0x24, 0x81, 0xe1, 0xb3, 0xb3, 0x78, 0x36, + 0x0b, 0x59, 0x4b, 0x17, 0xc9, 0x43, 0x74, 0x53, 0x7e, 0xe6, 0xec, 0x91, 0x23, 0x22, 0x76, 0x1a, 0xf9, 0xa6, 0xad, + 0x25, 0x46, 0xcc, 0x64, 0x48, 0x3b, 0xe2, 0x5c, 0x51, 0x36, 0x7b, 0x83, 0xea, 0x0d, 0x3e, 0x2f, 0xc5, 0xd6, 0xb5, + 0x26, 0xf1, 0x6a, 0x14, 0x32, 0x0b, 0x97, 0x3b, 0x7c, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x90, 0xa5, 0xe5, 0x91, 0x63, + 0x42, 0xdc, 0x99, 0x38, 0xc5, 0xfb, 0x60, 0x6e, 0xf4, 0x61, 0x50, 0x76, 0x56, 0xed, 0x3e, 0xd8, 0x8a, 0x80, 0xa8, + 0x87, 0x3e, 0x90, 0xc1, 0xdd, 0xaf, 0x61, 0xd7, 0x0e, 0xf4, 0x0f, 0xb0, 0xfa, 0x52, 0xbd, 0xdf, 0xb4, 0xf5, 0x07, + 0x97, 0xfa, 0x07, 0xc4, 0x31, 0x66, 0x2f, 0x7e, 0x49, 0xab, 0x57, 0x37, 0x75, 0x52, 0x7a, 0xaf, 0x30, 0x8f, 0x01, + 0x08, 0x7d, 0x5f, 0x05, 0xfe, 0x2c, 0x8a, 0xd3, 0x2c, 0x18, 0xeb, 0x57, 0xfd, 0xb7, 0x41, 0xeb, 0x72, 0x91, 0xb5, + 0x8c, 0x2b, 0x73, 0x9c, 0xa9, 0x29, 0x50, 0x04, 0xc1, 0xc4, 0x0c, 0x28, 0x9b, 0x2a, 0xa9, 0x3b, 0x68, 0x6b, 0x45, + 0x41, 0x9a, 0xb1, 0xd2, 0x38, 0x1b, 0x40, 0xbd, 0x4a, 0x3e, 0x15, 0x4c, 0x0c, 0xa5, 0x63, 0x4b, 0xa3, 0x4f, 0x37, + 0x95, 0x97, 0xab, 0x35, 0x1e, 0xe5, 0x59, 0x71, 0x5a, 0x62, 0x0c, 0x60, 0xe1, 0x38, 0x43, 0xcf, 0x8f, 0x54, 0xa3, + 0xcf, 0xd2, 0xb9, 0x3b, 0xfc, 0xae, 0xcc, 0x17, 0xc0, 0xf9, 0x0d, 0x16, 0x17, 0x51, 0x9c, 0x69, 0x10, 0xd8, 0x06, + 0xbe, 0x38, 0xac, 0x1a, 0x89, 0x71, 0xa8, 0x2d, 0x23, 0xe7, 0xc4, 0xe0, 0x7b, 0x3c, 0xfc, 0x5a, 0x3c, 0xbc, 0x59, + 0x29, 0x82, 0x05, 0x5d, 0x16, 0x22, 0x98, 0xc0, 0x2c, 0x3e, 0x8f, 0x6f, 0xab, 0x7a, 0x90, 0x97, 0xc3, 0xdd, 0x67, + 0x6f, 0x4b, 0xb0, 0xc9, 0x22, 0xab, 0x5f, 0x8b, 0x27, 0x26, 0x15, 0x8c, 0x4e, 0x65, 0x4f, 0xa1, 0xe1, 0x87, 0xe0, + 0x61, 0x32, 0xb0, 0x13, 0xc3, 0xb3, 0x00, 0x48, 0x12, 0x3f, 0xa6, 0x87, 0xf9, 0xb5, 0x48, 0x9d, 0x2c, 0x12, 0x17, + 0x2b, 0x87, 0x33, 0x50, 0xd7, 0x68, 0xb9, 0xca, 0x30, 0xd4, 0x2e, 0x74, 0x80, 0xe5, 0xba, 0x86, 0xa1, 0x3b, 0x81, + 0x4a, 0x17, 0x6c, 0x62, 0xae, 0x6b, 0xc1, 0xa4, 0x5e, 0xc6, 0x99, 0x5e, 0x20, 0x5e, 0x48, 0xdf, 0x51, 0x50, 0x05, + 0x8f, 0x09, 0x1f, 0xc6, 0xd8, 0x2c, 0xe2, 0xd4, 0xb7, 0xc6, 0xa8, 0xd0, 0x69, 0xa0, 0x0c, 0x63, 0x82, 0xd3, 0x6f, + 0x85, 0x8d, 0x83, 0x85, 0xf0, 0x9b, 0xa5, 0x61, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, + 0xd6, 0xbe, 0xb4, 0x15, 0xd0, 0x2f, 0x74, 0x32, 0x14, 0x18, 0x22, 0x1a, 0x86, 0xf9, 0x75, 0xe1, 0xb9, 0x53, 0x8c, + 0x17, 0x56, 0x19, 0x95, 0x6b, 0xa8, 0xba, 0x1f, 0x70, 0x05, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xfa, 0x7c, + 0x53, 0x55, 0xfa, 0x1b, 0xba, 0x46, 0x84, 0x9e, 0x10, 0x40, 0x34, 0x5f, 0xd7, 0xfe, 0x2a, 0xcb, 0x18, 0x1f, 0xad, + 0x54, 0x6a, 0xc2, 0xb7, 0xae, 0xf5, 0xe7, 0xcc, 0x9e, 0xb0, 0xcc, 0x0f, 0x42, 0x6a, 0xd2, 0x17, 0xd9, 0xea, 0x6b, + 0xc3, 0x4b, 0xcb, 0xc3, 0x8b, 0xca, 0xeb, 0x07, 0x07, 0x43, 0x47, 0x00, 0xf5, 0x1b, 0x47, 0x86, 0x59, 0xac, 0x9a, + 0x67, 0x94, 0xde, 0xfd, 0x57, 0xa7, 0x83, 0xc1, 0x74, 0x44, 0x30, 0x1d, 0x2c, 0x1a, 0xc7, 0x13, 0xf6, 0xcb, 0xfb, + 0xb7, 0x32, 0x6d, 0x16, 0x48, 0x80, 0x86, 0x7c, 0x61, 0xa6, 0xc8, 0x3f, 0x24, 0xc8, 0x3b, 0x50, 0x82, 0x2b, 0x4d, + 0x2e, 0xa1, 0x24, 0xd7, 0xb5, 0x33, 0xea, 0x3b, 0x9b, 0x50, 0xaf, 0x07, 0x31, 0xb6, 0x4a, 0xf2, 0x93, 0x03, 0xaa, + 0x4d, 0xa7, 0x1d, 0x55, 0x02, 0x34, 0x24, 0x30, 0xc2, 0x02, 0x0b, 0x90, 0xe1, 0x73, 0xe0, 0x16, 0x17, 0x0a, 0x7b, + 0x81, 0x72, 0x76, 0xf7, 0xac, 0xcc, 0xaa, 0x60, 0x2b, 0xfd, 0xf4, 0x04, 0x73, 0x76, 0xc1, 0x79, 0x0d, 0x51, 0x3e, + 0x4e, 0x0e, 0xe8, 0x51, 0xab, 0xec, 0x88, 0x02, 0x88, 0xb8, 0xda, 0xf5, 0x38, 0x80, 0x07, 0x6d, 0x15, 0x48, 0x11, + 0x0f, 0xa5, 0x7e, 0xae, 0x6b, 0x0b, 0xce, 0x1a, 0xf1, 0x70, 0x42, 0x10, 0x6b, 0xc0, 0x81, 0xbd, 0xab, 0x6b, 0x0b, + 0xff, 0x0e, 0x47, 0x2e, 0xde, 0xf8, 0x77, 0x2d, 0x97, 0xbf, 0x2a, 0xf6, 0x5a, 0x5a, 0xde, 0x6b, 0x63, 0x3e, 0xb9, + 0xe0, 0x48, 0x20, 0x6f, 0xd6, 0x73, 0x54, 0xd0, 0x36, 0x4c, 0xee, 0x5c, 0x4c, 0xee, 0x64, 0xc3, 0xe4, 0x4e, 0xb6, + 0x4c, 0x6e, 0xc8, 0x27, 0x52, 0x93, 0xa8, 0x4b, 0xd0, 0x39, 0x4c, 0x22, 0x8f, 0x33, 0x1a, 0x3d, 0xbe, 0xcf, 0x10, + 0x4f, 0x56, 0x1a, 0x82, 0x71, 0xd4, 0x06, 0x5c, 0x35, 0xe1, 0x45, 0x41, 0x44, 0x7d, 0xe0, 0x72, 0xd7, 0x89, 0x71, + 0x43, 0x0e, 0xce, 0x56, 0x58, 0x1d, 0x2f, 0xac, 0x52, 0xca, 0x2f, 0xde, 0x9a, 0x6f, 0x18, 0xe9, 0x7c, 0xcb, 0x48, + 0xc7, 0xa5, 0xad, 0xcb, 0x87, 0x4d, 0x9b, 0x50, 0x1d, 0x14, 0xac, 0x41, 0x30, 0x18, 0xc5, 0x25, 0x53, 0x5e, 0x87, + 0x9b, 0x69, 0xac, 0xb2, 0xa2, 0x96, 0x7e, 0x9a, 0xde, 0xc6, 0x09, 0x68, 0x5c, 0x00, 0xcc, 0xc3, 0x96, 0xd4, 0x22, + 0x88, 0x78, 0x30, 0x97, 0x8d, 0x8b, 0xa9, 0x78, 0xaf, 0x2e, 0x29, 0xaf, 0xd3, 0xa1, 0x1a, 0x4b, 0x3f, 0xcb, 0x58, + 0x82, 0x48, 0xf7, 0x21, 0xea, 0xf7, 0xff, 0x93, 0x65, 0xd6, 0x40, 0x43, 0x42, 0x85, 0xaa, 0x23, 0x85, 0x5e, 0x02, + 0x6f, 0x95, 0x88, 0x83, 0x58, 0x09, 0x0c, 0x97, 0x48, 0xc4, 0xff, 0x84, 0xdb, 0xb5, 0x95, 0x28, 0xae, 0x4b, 0xee, + 0x91, 0x61, 0x2f, 0xfd, 0xc9, 0x07, 0x50, 0xec, 0xb5, 0x3c, 0x13, 0x8c, 0x74, 0xd5, 0x30, 0x70, 0x09, 0x31, 0x7b, + 0xe3, 0x82, 0x48, 0x22, 0x95, 0xe4, 0x26, 0x50, 0xe0, 0x3d, 0xe9, 0x5b, 0xd3, 0xab, 0xb5, 0x97, 0x1f, 0xcc, 0x02, + 0xa3, 0x46, 0x35, 0x81, 0xb4, 0x85, 0x83, 0x53, 0x79, 0xe7, 0x0a, 0x4d, 0xf7, 0xc8, 0x00, 0xc9, 0xef, 0x25, 0xe4, + 0x33, 0x75, 0xc4, 0x85, 0x76, 0x98, 0xc0, 0xa9, 0x75, 0xe9, 0x5c, 0xe5, 0x4f, 0x67, 0xf8, 0xcb, 0xbd, 0xca, 0x9f, + 0x8e, 0xf0, 0x97, 0x77, 0x85, 0x99, 0xeb, 0x1a, 0x2e, 0xf2, 0xca, 0x98, 0xf5, 0xd3, 0xd2, 0x7a, 0x22, 0xfb, 0xb3, + 0x07, 0x2c, 0x1b, 0x3e, 0xc1, 0x8f, 0x9f, 0xac, 0x53, 0xf0, 0xb8, 0x54, 0xc7, 0x10, 0xd9, 0x89, 0x91, 0x37, 0x96, + 0xcf, 0x36, 0x94, 0x8f, 0x8c, 0xff, 0xf2, 0xc1, 0x8f, 0xab, 0x24, 0x2e, 0xce, 0x94, 0xb2, 0x18, 0xe2, 0x7a, 0x14, + 0x44, 0x7e, 0x72, 0x7f, 0x4d, 0xd7, 0x8b, 0x96, 0xe0, 0xdd, 0xa5, 0x78, 0x85, 0xd8, 0xcb, 0xb2, 0xba, 0x2b, 0x53, + 0x04, 0xbc, 0xf7, 0xfc, 0xa0, 0x1f, 0xfc, 0x3d, 0x51, 0xd8, 0xb6, 0xd2, 0x05, 0x94, 0x4f, 0x48, 0xe9, 0x43, 0xd7, + 0x4f, 0xd6, 0x2d, 0x56, 0x07, 0x53, 0x19, 0x6d, 0x85, 0x2f, 0x84, 0xe9, 0xc1, 0xcb, 0xec, 0x62, 0x12, 0xf4, 0x50, + 0x9f, 0x35, 0x8a, 0xef, 0xac, 0x27, 0xeb, 0xec, 0x4c, 0x5f, 0xf8, 0xc9, 0x27, 0x36, 0xb1, 0xc6, 0x41, 0x32, 0x0e, + 0x99, 0xde, 0xd3, 0x47, 0xa1, 0x1f, 0x7d, 0xe2, 0x8f, 0x56, 0xbc, 0xca, 0x50, 0x43, 0xbd, 0xf3, 0xee, 0x2b, 0x70, + 0x42, 0x22, 0x3b, 0x64, 0x56, 0x1b, 0xb0, 0xa0, 0xbd, 0x94, 0x02, 0xaf, 0x82, 0x51, 0x2c, 0x6a, 0x99, 0x60, 0x60, + 0x09, 0x4a, 0x73, 0xf0, 0x58, 0x35, 0x75, 0x9c, 0x2f, 0xdd, 0x54, 0x87, 0x4a, 0xc2, 0x4a, 0x99, 0x72, 0xf1, 0x1a, + 0x21, 0xfc, 0xf1, 0xcf, 0x51, 0x32, 0xec, 0xfd, 0x3f, 0x27, 0xa1, 0x7c, 0xd9, 0x08, 0xa1, 0xd4, 0x22, 0x4f, 0x89, + 0x07, 0x7c, 0x9c, 0x33, 0x98, 0x9b, 0x3f, 0xad, 0x36, 0xf6, 0xd3, 0x74, 0xb5, 0x60, 0x13, 0xd2, 0x0c, 0x9e, 0x15, + 0x9d, 0x2a, 0xdf, 0x2c, 0xd4, 0x8e, 0xfd, 0xb6, 0xf2, 0x8e, 0x0f, 0x5f, 0x82, 0xc5, 0x02, 0x30, 0x94, 0xf1, 0x74, + 0xaa, 0x17, 0x77, 0xfc, 0x1d, 0xcd, 0xdc, 0xc3, 0xdf, 0x56, 0x6f, 0x5e, 0x3b, 0x6f, 0x64, 0xe3, 0x08, 0x18, 0x63, + 0xa1, 0x7e, 0xe5, 0x7c, 0xb1, 0xd2, 0x5f, 0x31, 0xa2, 0xa9, 0x1f, 0x6d, 0x1e, 0xce, 0x65, 0x69, 0x89, 0x2f, 0x19, + 0x9b, 0x00, 0xc3, 0x6d, 0xd6, 0x4a, 0xaf, 0x43, 0x76, 0xc3, 0xa4, 0x6a, 0xb7, 0xfe, 0xb1, 0x86, 0x16, 0x18, 0x7b, + 0x8e, 0xab, 0x8c, 0x39, 0x57, 0xa7, 0x0c, 0x69, 0x88, 0x63, 0xe0, 0x23, 0x57, 0xb7, 0x58, 0x65, 0x4b, 0x0d, 0x4d, + 0x5d, 0xe9, 0xc0, 0xc6, 0x9e, 0x9d, 0x6d, 0x28, 0xef, 0x61, 0xe2, 0xe9, 0xe6, 0xbe, 0x99, 0xae, 0xd1, 0x83, 0x58, + 0xdd, 0x1c, 0x4f, 0x21, 0xec, 0xbc, 0x56, 0x21, 0x0e, 0xd9, 0x84, 0xb1, 0x26, 0x21, 0x99, 0x4e, 0xd2, 0x17, 0x61, + 0xed, 0x88, 0x66, 0xbf, 0x42, 0x0e, 0xd5, 0x38, 0x37, 0x5a, 0x79, 0xe4, 0x23, 0x4c, 0xe8, 0x1a, 0xb1, 0x34, 0xdd, + 0x88, 0x30, 0x39, 0xe9, 0xa6, 0x5e, 0xd4, 0x2e, 0xe3, 0xa3, 0x28, 0x37, 0x1d, 0x13, 0x58, 0x02, 0x1c, 0x60, 0xf5, + 0x5b, 0x78, 0xbc, 0x5c, 0x2f, 0xb8, 0xbd, 0x4a, 0x32, 0x1b, 0xe9, 0xdc, 0x96, 0x60, 0xd3, 0xfb, 0x5b, 0x9d, 0x77, + 0xaa, 0x74, 0x4c, 0x37, 0x76, 0xad, 0x55, 0x22, 0xbd, 0x35, 0x71, 0x11, 0x02, 0x10, 0x7d, 0xaa, 0xd0, 0x57, 0x36, + 0x9d, 0xb2, 0x71, 0x96, 0x1a, 0x42, 0x78, 0x24, 0xa3, 0xc7, 0x82, 0xd7, 0xd0, 0xa3, 0x81, 0xfe, 0x13, 0xf8, 0xd0, + 0x8b, 0x20, 0x4b, 0xbc, 0x43, 0xe2, 0xce, 0xd4, 0x8c, 0x26, 0x82, 0x58, 0x46, 0x11, 0xff, 0x0a, 0x24, 0x07, 0x6f, + 0x28, 0xc7, 0xae, 0xf1, 0xf3, 0xa7, 0x58, 0x17, 0xb1, 0xb4, 0x6a, 0xd9, 0x4e, 0x8a, 0xb6, 0x6d, 0xdf, 0xb5, 0xfb, + 0xa6, 0xe3, 0x3a, 0xb9, 0x6e, 0x82, 0xef, 0xd6, 0xa7, 0x7d, 0x37, 0x3d, 0xb6, 0x6a, 0x43, 0xab, 0x55, 0xf4, 0x90, + 0x76, 0x9e, 0xfb, 0xc2, 0xd5, 0x4d, 0x32, 0x99, 0x53, 0x68, 0xdb, 0x38, 0xbe, 0x61, 0xc9, 0x17, 0x0f, 0xa5, 0x0c, + 0x7c, 0xbf, 0xfe, 0x1c, 0xb9, 0x0e, 0x10, 0xe1, 0x2c, 0x5e, 0x3e, 0x60, 0x08, 0x6d, 0xdd, 0xd4, 0xc7, 0x61, 0x9c, + 0x32, 0x75, 0x0c, 0x24, 0x04, 0xf9, 0xc2, 0x41, 0xfc, 0xfc, 0xfe, 0xf5, 0x87, 0x0f, 0xba, 0x89, 0x99, 0x40, 0x53, + 0x15, 0x3a, 0x5f, 0x50, 0x3b, 0xa8, 0x7f, 0xe3, 0xba, 0xa3, 0x13, 0x86, 0x2e, 0xb5, 0xe5, 0x35, 0x47, 0x65, 0xb5, + 0x25, 0xc7, 0x4f, 0x1e, 0xfe, 0x65, 0xba, 0x89, 0xee, 0x35, 0xae, 0x06, 0xda, 0xb0, 0xfd, 0x78, 0x2b, 0x95, 0x2c, + 0x82, 0xe8, 0xba, 0xa1, 0xd4, 0xbf, 0x6b, 0x28, 0x85, 0xab, 0x5c, 0x8d, 0x56, 0xad, 0xe2, 0x85, 0xc2, 0x1a, 0x40, + 0x22, 0xe7, 0x5d, 0xe8, 0x52, 0xee, 0x53, 0x5f, 0xd0, 0x69, 0x1e, 0xc9, 0xbd, 0xda, 0xeb, 0x86, 0x62, 0x7e, 0x09, + 0x92, 0xb8, 0x1d, 0x87, 0x60, 0xf0, 0xc7, 0x54, 0xad, 0x5c, 0x99, 0x6d, 0x94, 0xe6, 0xba, 0x0a, 0x10, 0x62, 0x6f, + 0xaf, 0x33, 0xb6, 0x58, 0xb2, 0xc4, 0xcf, 0x56, 0x09, 0xbb, 0x0e, 0xe3, 0xdb, 0x47, 0x85, 0x39, 0xfd, 0x8e, 0xca, + 0xf3, 0x60, 0x36, 0x97, 0xb5, 0xcf, 0x5a, 0x6c, 0x20, 0x27, 0x70, 0xeb, 0x07, 0xf2, 0xff, 0xfc, 0xdb, 0xb6, 0xff, + 0xf3, 0xef, 0x9d, 0x55, 0x01, 0x7c, 0x3e, 0x34, 0xb3, 0xc1, 0x1e, 0xeb, 0xa2, 0xf9, 0x4b, 0x65, 0x9c, 0x37, 0xd7, + 0xa9, 0x4d, 0x02, 0xbc, 0xaf, 0x4d, 0x41, 0xad, 0xb0, 0xbc, 0x6e, 0x1e, 0xd4, 0x31, 0x18, 0xd7, 0xce, 0x9e, 0x41, + 0xa5, 0x2f, 0xea, 0xda, 0xd0, 0xe8, 0xed, 0x35, 0x23, 0x7f, 0x1c, 0xc3, 0xbb, 0xc6, 0xf0, 0x85, 0xdd, 0xe7, 0x72, + 0xc9, 0x97, 0xc3, 0xa1, 0xcc, 0x2d, 0xa7, 0x36, 0x05, 0x13, 0xff, 0xb3, 0x5a, 0x09, 0x3f, 0x3c, 0x7b, 0x8e, 0x41, + 0xbe, 0xf7, 0x83, 0x97, 0x43, 0x34, 0x46, 0x3b, 0x19, 0x25, 0x05, 0xb3, 0xb2, 0x91, 0xb4, 0x91, 0x31, 0x79, 0x0d, + 0x68, 0x8d, 0xae, 0x41, 0x29, 0x26, 0x1c, 0xcb, 0x87, 0x86, 0xf9, 0x72, 0xc8, 0x05, 0x4b, 0xdc, 0xfe, 0xb5, 0x57, + 0x5d, 0xda, 0x5c, 0x2c, 0x5b, 0x42, 0xba, 0xa9, 0x91, 0xfe, 0x07, 0x2b, 0xb3, 0x42, 0x8e, 0x87, 0x02, 0x7e, 0x90, + 0x28, 0x0c, 0x73, 0xcc, 0x77, 0xf2, 0x6e, 0x93, 0x8d, 0xd8, 0xcf, 0xbb, 0x6d, 0xc4, 0x2e, 0xf6, 0xb2, 0x11, 0xfb, + 0xf9, 0xab, 0xdb, 0x88, 0xbd, 0x53, 0x6d, 0xc4, 0x60, 0x12, 0x5f, 0xb3, 0xbd, 0x0c, 0xb7, 0x84, 0xd5, 0x46, 0x7c, + 0x9b, 0x0e, 0x5c, 0xce, 0xd2, 0xa6, 0xe3, 0x39, 0x03, 0x19, 0x01, 0x9f, 0x95, 0x30, 0x9e, 0x81, 0x11, 0xd7, 0x9f, + 0x6f, 0x6e, 0x15, 0xc6, 0x33, 0xd5, 0xd8, 0x2a, 0xe2, 0x11, 0x5f, 0x8b, 0x28, 0x4e, 0x64, 0xe0, 0xe4, 0x98, 0x22, + 0xe6, 0x93, 0x75, 0x68, 0x28, 0x59, 0xad, 0xa5, 0xf5, 0x9a, 0x27, 0x4c, 0xa0, 0x7a, 0x68, 0x3d, 0x25, 0x1b, 0x7a, + 0xcf, 0x45, 0x6c, 0x0b, 0x15, 0x82, 0xb4, 0x12, 0xa6, 0x38, 0x11, 0x6b, 0xfd, 0xb7, 0x3b, 0xf7, 0xfb, 0x4b, 0xb7, + 0xdf, 0x76, 0xc1, 0x39, 0x1b, 0x6e, 0x98, 0x58, 0xe0, 0xf4, 0xdb, 0x6d, 0x28, 0xb8, 0x55, 0x0a, 0x3c, 0x28, 0x08, + 0x94, 0x82, 0x0e, 0x14, 0x8c, 0x95, 0x82, 0x23, 0x28, 0x98, 0x28, 0x05, 0xc7, 0x50, 0x70, 0xa3, 0xe7, 0x97, 0x91, + 0xec, 0xee, 0xb1, 0x71, 0x65, 0xd2, 0xa5, 0x42, 0x94, 0x1d, 0x9b, 0x2e, 0x58, 0x4d, 0xf9, 0xb3, 0x5e, 0x6c, 0x92, + 0x74, 0xb1, 0x97, 0x98, 0xb7, 0x73, 0x46, 0x81, 0xa2, 0x5f, 0xe1, 0x99, 0x63, 0x67, 0x31, 0xd8, 0x4d, 0x8b, 0x00, + 0x0c, 0x02, 0x0f, 0x9a, 0x6e, 0x80, 0xc0, 0xa8, 0x2f, 0x67, 0x4e, 0x04, 0xb1, 0x50, 0xe6, 0xb2, 0x78, 0x47, 0x9f, + 0xb3, 0xe4, 0x12, 0x28, 0x2c, 0x4e, 0x5a, 0xaa, 0x54, 0xf2, 0x6b, 0xd8, 0x1d, 0xbc, 0x62, 0xa3, 0xd5, 0x4c, 0x3b, + 0x8f, 0x67, 0x3b, 0x4d, 0x08, 0xd4, 0x57, 0xd0, 0x4b, 0x9d, 0xd4, 0x2f, 0x96, 0x58, 0x96, 0xfc, 0x5b, 0xf4, 0x98, + 0x97, 0xeb, 0x67, 0xd0, 0x37, 0x2d, 0x23, 0x03, 0x16, 0xf8, 0x0e, 0xe0, 0x48, 0xd1, 0xe1, 0x9f, 0x03, 0x9e, 0x95, + 0xe7, 0x0b, 0x5f, 0xe9, 0xcf, 0xe9, 0x8f, 0x2c, 0x4d, 0xfd, 0x99, 0xa8, 0x5f, 0xef, 0x27, 0x18, 0xed, 0xc8, 0xfb, + 0x17, 0x22, 0x10, 0x24, 0x79, 0x41, 0xcd, 0x36, 0x23, 0x89, 0x6f, 0x35, 0xb0, 0xfe, 0x81, 0x05, 0x55, 0xd8, 0x29, + 0x04, 0x36, 0x4c, 0x61, 0xd9, 0xa2, 0x00, 0x36, 0xff, 0x0d, 0x0b, 0xab, 0x85, 0x99, 0x3f, 0xab, 0x16, 0xd1, 0x3a, + 0xc8, 0xd5, 0xbe, 0x49, 0x85, 0x7e, 0xa9, 0xf0, 0x4b, 0x34, 0xd4, 0x61, 0x3c, 0xfb, 0x53, 0xd5, 0xd3, 0x5b, 0xcc, + 0x0a, 0x3e, 0x44, 0x66, 0x90, 0x0d, 0x6d, 0xc4, 0xb1, 0x66, 0x03, 0x0a, 0x7b, 0x51, 0x36, 0xb7, 0xd0, 0xb5, 0xac, + 0xe5, 0x45, 0x86, 0x69, 0xe3, 0xdc, 0xae, 0xab, 0x0e, 0xb5, 0xbd, 0x64, 0x36, 0xf2, 0x5b, 0xae, 0x77, 0x6c, 0x8a, + 0x3f, 0xb6, 0xd3, 0x31, 0x72, 0x84, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, + 0xbe, 0xb7, 0x88, 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x2e, 0xd4, 0x7d, 0x0c, 0xd5, 0xc0, 0xbd, 0x05, 0x5d, + 0xdb, 0x4b, 0xd8, 0x82, 0x5a, 0xcb, 0x48, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xfc, 0xf3, 0xa5, 0xca, 0x54, 0x15, 0x97, + 0x1c, 0xb5, 0x00, 0x8e, 0x94, 0x87, 0x79, 0x80, 0xe0, 0x46, 0xfd, 0xa5, 0x3f, 0xc1, 0xc8, 0x84, 0xb6, 0xd7, 0x49, + 0xd8, 0x42, 0xb3, 0x3b, 0x1b, 0x81, 0x27, 0xf1, 0xed, 0x29, 0xf4, 0x16, 0x1b, 0x5b, 0x29, 0x0b, 0xa7, 0xf8, 0xc6, + 0x42, 0xcf, 0x12, 0x01, 0xc7, 0xc2, 0x8b, 0x38, 0x40, 0x63, 0x8b, 0x3e, 0xbc, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, + 0x91, 0x45, 0xc3, 0x39, 0x76, 0x96, 0x0a, 0x2c, 0x15, 0x7f, 0xc6, 0x1a, 0xab, 0xbb, 0x9a, 0xd3, 0x87, 0xcb, 0xda, + 0x34, 0x8c, 0x6f, 0x7b, 0xf3, 0x60, 0x32, 0x61, 0x51, 0x1f, 0xfb, 0x2c, 0x0b, 0x59, 0x18, 0x06, 0xcb, 0x34, 0x48, + 0xfb, 0x0b, 0xff, 0x8e, 0x43, 0x3d, 0xdc, 0x04, 0xb5, 0xcd, 0xa1, 0xb6, 0xf7, 0x86, 0xaa, 0x80, 0x01, 0x2f, 0x16, + 0x82, 0xc3, 0xbb, 0xd6, 0xd1, 0x9c, 0xca, 0x38, 0xf7, 0x86, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, + 0x39, 0xb9, 0x7d, 0xb3, 0xa6, 0x85, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x3c, 0x39, 0x93, 0x49, 0x6e, 0x8f, + 0xc5, 0xd3, 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0xa2, 0xa0, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, + 0x1a, 0xb9, 0xcd, 0xf8, 0x53, 0xc2, 0x26, 0x7d, 0x5c, 0x48, 0x64, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x29, 0xc0, + 0x65, 0x89, 0x36, 0xa1, 0xac, 0xe7, 0x6a, 0xbd, 0x77, 0x4d, 0xad, 0xf8, 0xdc, 0x78, 0xdc, 0x58, 0x6f, 0xe2, 0x27, + 0x9f, 0xae, 0x34, 0x65, 0x14, 0xbe, 0x4f, 0xd5, 0xd6, 0x02, 0x0d, 0xd6, 0x5d, 0x0f, 0x42, 0x76, 0xf5, 0x47, 0x71, + 0x02, 0x7b, 0x36, 0xf1, 0x27, 0xc1, 0x2a, 0xed, 0xb9, 0xde, 0xf2, 0x4e, 0x14, 0xf1, 0xb5, 0x5e, 0x14, 0xe0, 0xde, + 0xeb, 0xa5, 0x71, 0x18, 0x4c, 0x44, 0xd1, 0xa6, 0xbd, 0xe4, 0x7a, 0x46, 0x1f, 0x1d, 0xd6, 0x03, 0x0c, 0xbb, 0xe0, + 0x87, 0xa1, 0x66, 0xb7, 0x53, 0x8d, 0xf9, 0x29, 0xca, 0x97, 0x35, 0x27, 0x25, 0xbc, 0xa0, 0x73, 0xba, 0x7b, 0xb8, + 0xbc, 0x93, 0x6b, 0xde, 0x3d, 0x5a, 0xde, 0xe5, 0x7f, 0x5d, 0xb0, 0x49, 0xe0, 0x6b, 0xad, 0x62, 0x35, 0xb9, 0x0e, + 0xc8, 0xa0, 0x8d, 0xf5, 0x86, 0x65, 0x2a, 0xb6, 0x05, 0x84, 0x36, 0x7c, 0x14, 0x2c, 0x96, 0x71, 0x92, 0xf9, 0x51, + 0x96, 0xe7, 0xc3, 0xab, 0x3c, 0xef, 0x5f, 0x04, 0xad, 0xcb, 0x7f, 0xb4, 0xe8, 0x9c, 0x26, 0x9d, 0x4d, 0x6e, 0x5c, + 0x99, 0xaf, 0x99, 0x6a, 0x33, 0x02, 0xc7, 0x18, 0xda, 0x8b, 0xa8, 0x95, 0xe9, 0x94, 0xac, 0x57, 0x26, 0x24, 0xcb, + 0xea, 0x64, 0x83, 0x52, 0xae, 0x82, 0x27, 0x10, 0x54, 0x78, 0xcd, 0x06, 0x17, 0x8a, 0xfd, 0x09, 0x30, 0x2b, 0x58, + 0x99, 0xfc, 0x0a, 0x9e, 0x6c, 0xe2, 0x19, 0xbf, 0xdb, 0xcd, 0x33, 0xfe, 0x9a, 0xed, 0xc3, 0x33, 0x7e, 0xf7, 0xd5, + 0x79, 0xc6, 0x27, 0x75, 0xbf, 0x82, 0xb7, 0xf1, 0x40, 0x97, 0x1a, 0x06, 0x38, 0x9a, 0x12, 0x8a, 0xd8, 0xf3, 0xf6, + 0x0f, 0xbb, 0x01, 0x08, 0x68, 0x94, 0x83, 0x8e, 0x4e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xe7, + 0xe9, 0x74, 0xf0, 0x2a, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0xbe, 0x28, 0x45, 0x57, 0xa0, 0x37, 0xc2, 0x0a, 0x13, 0xf3, + 0x4f, 0x80, 0x73, 0x36, 0x59, 0x1d, 0x4f, 0xa4, 0xf5, 0x59, 0xbf, 0xdc, 0x85, 0x96, 0x34, 0xf9, 0x14, 0x2e, 0x38, + 0x35, 0x51, 0xe2, 0x8c, 0x65, 0xdc, 0x67, 0xf6, 0xfb, 0xfb, 0xb7, 0x93, 0xd6, 0xdb, 0xd8, 0xc8, 0x83, 0xf4, 0x5d, + 0xd5, 0x01, 0x86, 0xeb, 0x7e, 0x06, 0xea, 0x70, 0x72, 0x6e, 0x41, 0xa6, 0x26, 0x98, 0x86, 0xd7, 0xd4, 0xfc, 0xac, + 0x34, 0xd2, 0x9e, 0xda, 0x90, 0x27, 0xba, 0xaa, 0x1d, 0xc6, 0xdc, 0xfb, 0x60, 0xcd, 0x39, 0x40, 0xcc, 0xdd, 0x85, + 0x7e, 0xc3, 0x13, 0x6a, 0x1e, 0x4c, 0xf2, 0xdc, 0xe8, 0x0b, 0x44, 0x28, 0x07, 0x2d, 0xdb, 0xc5, 0xc4, 0xa5, 0xb7, + 0xd2, 0xa6, 0x81, 0x6b, 0x08, 0x49, 0xfd, 0xf7, 0x16, 0x14, 0xea, 0x5c, 0x59, 0xc8, 0x71, 0xa6, 0x6b, 0x84, 0x3e, + 0x32, 0xb4, 0x50, 0x06, 0x04, 0x1a, 0x60, 0x89, 0x7f, 0xf1, 0x4a, 0x14, 0xd4, 0x6d, 0x38, 0x09, 0x39, 0x68, 0x11, + 0x00, 0x5e, 0xfe, 0x42, 0xae, 0x4d, 0x64, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xbc, 0x1f, 0x2e, 0xbf, 0xd3, 0x93, + 0x03, 0x68, 0x70, 0x5a, 0x31, 0x1c, 0xd8, 0x61, 0xa1, 0x08, 0xac, 0x44, 0x7a, 0x6b, 0xda, 0xe9, 0xad, 0xf6, 0x6c, + 0x2d, 0x22, 0x64, 0x64, 0xfe, 0xd2, 0x82, 0x2b, 0x3e, 0xd2, 0x5e, 0x4e, 0xf1, 0x94, 0x60, 0x1c, 0xfd, 0x55, 0x0a, + 0xb4, 0x11, 0x2f, 0xaa, 0x48, 0x7f, 0xfa, 0xe3, 0x55, 0x92, 0xc6, 0x49, 0x6f, 0x19, 0x07, 0x51, 0xc6, 0x92, 0x1c, + 0x51, 0x75, 0x89, 0xf8, 0x11, 0xe8, 0xb9, 0x5a, 0xc7, 0x4b, 0x7f, 0x1c, 0x64, 0xf7, 0x3d, 0x87, 0xb3, 0x14, 0x4e, + 0x9f, 0x73, 0x07, 0x4e, 0x63, 0xfd, 0x1e, 0xc7, 0xe6, 0x73, 0x64, 0xfc, 0x92, 0x3a, 0x3b, 0xa3, 0x2e, 0xf3, 0xbe, + 0xf2, 0x96, 0x62, 0x84, 0x00, 0xfb, 0xe1, 0x27, 0xd6, 0x0c, 0xa8, 0x3c, 0x4c, 0xb5, 0x33, 0x61, 0x33, 0x13, 0xa9, + 0x36, 0xc8, 0xe5, 0xc5, 0x1f, 0xbb, 0x63, 0x68, 0x4e, 0x73, 0x31, 0x70, 0x3c, 0xc6, 0x3e, 0x3d, 0xeb, 0xf9, 0x90, + 0x51, 0xcb, 0xdc, 0xa7, 0xe6, 0x88, 0x4d, 0xe3, 0x84, 0x51, 0x3c, 0x59, 0xb7, 0xbb, 0xbc, 0xdb, 0x1f, 0xfc, 0xf6, + 0xe1, 0x37, 0xc3, 0x89, 0xe2, 0xac, 0x25, 0x80, 0x19, 0x3b, 0xa0, 0xd5, 0xcf, 0x33, 0x60, 0x0d, 0x09, 0xf3, 0x63, + 0x0a, 0xdd, 0xd5, 0xd3, 0xf5, 0x7e, 0x63, 0xd8, 0xae, 0x65, 0xcc, 0xcf, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, + 0x9e, 0xb1, 0x7d, 0xb4, 0xbc, 0x13, 0x73, 0x8c, 0x07, 0xde, 0x03, 0x26, 0xa9, 0xd2, 0x15, 0x31, 0x49, 0xd5, 0x62, + 0x9c, 0xa4, 0x7e, 0x6d, 0x34, 0x22, 0x92, 0x45, 0xe5, 0xa4, 0xef, 0x2c, 0xef, 0xd4, 0x23, 0xba, 0x68, 0x26, 0x4f, + 0xea, 0x6a, 0x08, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x4d, 0x74, 0x79, 0x2e, 0x15, 0xe4, 0x48, 0x3c, 0xf8, + 0xa3, 0x34, 0x0e, 0x57, 0x19, 0x6b, 0x46, 0x17, 0x21, 0xc7, 0x73, 0x0a, 0xe4, 0xe0, 0xef, 0x72, 0x5f, 0x3b, 0xc0, + 0x6e, 0xc3, 0x32, 0x71, 0xfa, 0x10, 0x71, 0xd8, 0x6a, 0x97, 0xbb, 0x0e, 0xaf, 0x64, 0xa7, 0xcd, 0x86, 0x81, 0x98, + 0x70, 0x2c, 0x11, 0xf5, 0xd6, 0x6c, 0x97, 0x97, 0xc9, 0xa8, 0xab, 0xb2, 0x28, 0x2f, 0x0f, 0xe6, 0xcf, 0xd9, 0x63, + 0x2f, 0x9a, 0xf7, 0xd8, 0x0b, 0xb1, 0xc7, 0xb6, 0xaf, 0xcc, 0xc7, 0x53, 0x17, 0xfe, 0xeb, 0x17, 0x03, 0xea, 0x39, + 0x5a, 0x7b, 0x79, 0xa7, 0xb9, 0xcb, 0x3b, 0xcd, 0xf2, 0x96, 0x77, 0x1a, 0x82, 0x46, 0x7b, 0x10, 0xd3, 0xf6, 0x0c, + 0xd3, 0xd1, 0xa0, 0x10, 0xfe, 0x38, 0xa5, 0x57, 0xee, 0x21, 0xbc, 0x83, 0x56, 0x9d, 0xfa, 0x3b, 0x6f, 0xfb, 0x56, + 0xa7, 0xbd, 0x24, 0x88, 0xb6, 0x61, 0x67, 0xfe, 0x68, 0xc4, 0x26, 0xbd, 0x69, 0x3c, 0x5e, 0xa5, 0xff, 0xe2, 0xfd, + 0xe7, 0x48, 0xdc, 0x4a, 0x08, 0x2a, 0x70, 0x44, 0x53, 0x50, 0x94, 0xdc, 0x30, 0x01, 0x61, 0x2d, 0xe7, 0xa9, 0x47, + 0xe1, 0x91, 0x3d, 0xfb, 0xb0, 0x61, 0x91, 0x37, 0x23, 0xfa, 0x4f, 0x9b, 0xa5, 0xcd, 0x24, 0xe6, 0x0b, 0xd0, 0xb2, + 0x15, 0x1d, 0x0f, 0xc7, 0x06, 0x9f, 0x4d, 0xa7, 0xdb, 0xdc, 0xdd, 0x4b, 0xf1, 0xa5, 0x2b, 0x71, 0xa8, 0xf0, 0x73, + 0x8b, 0x3b, 0xa6, 0x6c, 0x87, 0xba, 0x69, 0x8d, 0xd4, 0xa0, 0x6e, 0x39, 0x10, 0x8a, 0xba, 0x7b, 0x52, 0xf9, 0xc7, + 0x2f, 0x0e, 0xe1, 0x3f, 0xe2, 0xea, 0x7f, 0xcd, 0x9a, 0x18, 0xf5, 0xb7, 0x65, 0x4b, 0x70, 0x62, 0x95, 0x90, 0x11, + 0xdf, 0xbf, 0xfe, 0x74, 0xfa, 0xb0, 0x06, 0x7b, 0xd7, 0x26, 0x53, 0xaa, 0x6a, 0xed, 0xef, 0xe3, 0x18, 0x52, 0x77, + 0xd6, 0xab, 0x0b, 0xf4, 0x90, 0xb1, 0x7b, 0x36, 0x80, 0x46, 0xe2, 0x1e, 0x41, 0x5a, 0x7c, 0x1d, 0xdb, 0xd0, 0x55, + 0xe2, 0xf5, 0xa6, 0xab, 0xc4, 0xab, 0xdd, 0x57, 0x89, 0x1f, 0xf6, 0xba, 0x4a, 0xbc, 0xfa, 0xea, 0x57, 0x89, 0xd7, + 0xf5, 0xab, 0xc4, 0x45, 0x2c, 0xec, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x29, 0xe5, 0xce, 0xe3, 0x41, 0xc7, + 0xa1, 0x90, 0xc7, 0x17, 0x7f, 0xf8, 0x62, 0x81, 0x0b, 0xf1, 0x3d, 0x9a, 0x93, 0x15, 0x57, 0x0b, 0x4e, 0xd9, 0xf1, + 0x3b, 0x4a, 0x71, 0x18, 0x47, 0xb3, 0x9f, 0x41, 0x29, 0x0b, 0xe2, 0xc0, 0x44, 0x79, 0x11, 0xa4, 0x3f, 0xc7, 0xcb, + 0xd5, 0xf2, 0x2d, 0xc0, 0xfa, 0x18, 0xa4, 0xc1, 0x28, 0x64, 0xd2, 0x13, 0x99, 0xcc, 0xdf, 0xb8, 0x4c, 0x1c, 0x2c, + 0x4e, 0xc5, 0x4f, 0xff, 0x4e, 0xfc, 0x44, 0x9b, 0x54, 0xfe, 0x9b, 0xec, 0xea, 0xf4, 0xe6, 0x8b, 0x88, 0x50, 0x02, + 0x2a, 0x9d, 0x7e, 0xf8, 0x65, 0xe4, 0x22, 0x36, 0x1a, 0x46, 0x29, 0xec, 0x1d, 0x36, 0xc2, 0x61, 0xb5, 0x4b, 0xcd, + 0xca, 0x30, 0x65, 0x08, 0xae, 0xba, 0x18, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x93, + 0x01, 0x68, 0x38, 0x65, 0x1b, 0x4c, 0x1e, 0xf9, 0x01, 0x19, 0xe5, 0x38, 0x69, 0xe9, 0x90, 0xbb, 0x74, 0xb5, 0xb4, + 0x48, 0xd5, 0x6c, 0xe1, 0x10, 0x75, 0x99, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0xd6, 0x52, 0x98, 0x6a, 0xc4, + 0x36, 0x97, 0x0a, 0xa7, 0xad, 0x48, 0x08, 0x17, 0x45, 0x1c, 0x8c, 0x86, 0x89, 0xe3, 0x6f, 0xc8, 0x75, 0xb5, 0x78, + 0x0b, 0x51, 0x44, 0xf2, 0x15, 0x9f, 0x0f, 0x1e, 0x15, 0x82, 0x1e, 0x5f, 0x2a, 0x68, 0x7c, 0x77, 0xc3, 0x92, 0xd0, + 0xbf, 0x6f, 0x19, 0x79, 0x1c, 0xfd, 0x08, 0x08, 0x78, 0x15, 0xdf, 0x46, 0x6a, 0x05, 0x4c, 0xd6, 0xd2, 0xb0, 0x96, + 0x1a, 0xe3, 0x97, 0x80, 0xe3, 0x8a, 0xd2, 0x03, 0x48, 0x93, 0x3b, 0x63, 0x7f, 0x37, 0xe9, 0xdf, 0x7f, 0x18, 0xb9, + 0x79, 0x1e, 0xcb, 0x0f, 0xfd, 0xb2, 0xdc, 0xe3, 0x33, 0x4f, 0x9f, 0x3e, 0xda, 0x3c, 0xec, 0x72, 0x7a, 0xf6, 0x86, + 0xd6, 0xc6, 0xc6, 0x5d, 0x00, 0xbd, 0xb8, 0x88, 0x57, 0xe3, 0x39, 0x1a, 0xba, 0x7e, 0xbd, 0xf1, 0x66, 0x00, 0x13, + 0xb3, 0x94, 0xca, 0xa1, 0x57, 0x8a, 0x0a, 0x2c, 0xe0, 0xf7, 0x5f, 0x43, 0x00, 0xce, 0xff, 0x21, 0x1a, 0xea, 0xab, + 0x86, 0xdf, 0xe2, 0x83, 0x87, 0x2d, 0xde, 0x3e, 0x24, 0xd3, 0xe4, 0xa1, 0x2d, 0x84, 0x72, 0xad, 0x99, 0xc8, 0xe4, + 0x55, 0xa4, 0xa9, 0x61, 0xe4, 0x36, 0x45, 0xc8, 0x13, 0x5f, 0x61, 0x36, 0x5d, 0xd3, 0xb9, 0xa3, 0x81, 0xc9, 0x38, + 0xb5, 0xaa, 0x10, 0x19, 0x6e, 0xf2, 0xc0, 0x90, 0x7c, 0x55, 0xdf, 0x2d, 0x82, 0xc8, 0xc4, 0x28, 0xf0, 0xf5, 0x37, + 0xfe, 0x1d, 0xc4, 0x41, 0x06, 0xe2, 0x56, 0x7d, 0x05, 0x85, 0xa6, 0xea, 0x37, 0x07, 0xa9, 0x9e, 0xf4, 0x46, 0x4c, + 0x08, 0x2d, 0xde, 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0x79, 0x8d, 0xd0, 0xe4, 0x3d, 0x02, 0xcb, 0xf1, 0x3a, 0x00, 0xda, + 0x92, 0x7c, 0x79, 0x47, 0x25, 0x70, 0x33, 0x40, 0x9d, 0xac, 0x28, 0xe0, 0xa1, 0xfe, 0x3a, 0x8e, 0x28, 0x10, 0x17, + 0x7a, 0x08, 0xd3, 0xe6, 0x27, 0x10, 0x11, 0xb8, 0xa7, 0xe1, 0x85, 0x1d, 0xdf, 0x72, 0x49, 0xb0, 0xe6, 0xd0, 0xe3, + 0xb0, 0xcf, 0x9a, 0x63, 0xc2, 0x45, 0x0a, 0x15, 0x04, 0xad, 0x43, 0x25, 0xc4, 0xb3, 0xc9, 0x1a, 0x68, 0x23, 0xde, + 0x8b, 0xee, 0xb2, 0x05, 0x8b, 0x56, 0x3a, 0xe6, 0x84, 0xc2, 0x18, 0x7d, 0x50, 0xe7, 0x15, 0x31, 0x5b, 0x40, 0x6d, + 0x9a, 0x5b, 0xce, 0xe9, 0x2c, 0x4c, 0x39, 0x49, 0xf5, 0xcd, 0x31, 0x57, 0x6c, 0xa6, 0x9c, 0xb6, 0x55, 0x4f, 0x08, + 0x3e, 0xa5, 0x71, 0xd5, 0x91, 0x8b, 0x2c, 0xa1, 0x01, 0x06, 0x45, 0xc7, 0xe0, 0xe2, 0x22, 0x81, 0xf6, 0x96, 0x5f, + 0x9d, 0x34, 0xa9, 0x91, 0xf1, 0x2b, 0x82, 0xa2, 0xc4, 0xa8, 0x83, 0xe1, 0xfd, 0x84, 0xc0, 0x44, 0x1b, 0xe1, 0x8c, + 0x6b, 0x70, 0x36, 0x0c, 0xfa, 0x13, 0xbb, 0xa7, 0x83, 0x84, 0x50, 0xf5, 0x89, 0xdd, 0x83, 0xed, 0xdf, 0x6b, 0x90, + 0xa6, 0xe8, 0x5b, 0xc8, 0xb5, 0x09, 0xa1, 0xfe, 0xc7, 0x10, 0xac, 0x6a, 0xcb, 0x06, 0x72, 0xf2, 0x2d, 0x54, 0x1c, + 0x51, 0x0c, 0x59, 0x9d, 0xc5, 0x26, 0xe6, 0x26, 0xfe, 0xad, 0x46, 0x1c, 0x5b, 0x0d, 0x5b, 0xc3, 0x78, 0xe6, 0x3a, + 0xce, 0x41, 0xad, 0x3e, 0x08, 0xb2, 0x9b, 0x6a, 0x1b, 0x66, 0x36, 0x70, 0x1d, 0x2b, 0x78, 0x66, 0x7b, 0xfd, 0xda, + 0x19, 0xad, 0xc4, 0x92, 0x1c, 0xa2, 0xf8, 0xeb, 0xf4, 0xc9, 0xba, 0x55, 0xdb, 0x90, 0x46, 0xd5, 0x64, 0x1e, 0xfb, + 0x96, 0x73, 0xf9, 0xd7, 0xb0, 0x7e, 0xf4, 0x53, 0x24, 0x4b, 0xca, 0x6b, 0x32, 0x84, 0x68, 0xc8, 0x2d, 0xd8, 0x46, + 0x7f, 0xd1, 0x9e, 0x6b, 0x2d, 0xda, 0x3e, 0x86, 0x31, 0x94, 0xe9, 0xb2, 0x85, 0x4f, 0x99, 0x0a, 0xa0, 0xf2, 0xc5, + 0xb4, 0x4a, 0xe1, 0x78, 0xdc, 0x55, 0x56, 0x68, 0xf4, 0xb6, 0x72, 0x0b, 0x08, 0x7f, 0xc3, 0xf1, 0x69, 0x8f, 0x20, + 0x2e, 0x01, 0xd4, 0x80, 0xd8, 0xe9, 0x3b, 0x01, 0xae, 0x96, 0x65, 0x70, 0xe5, 0x43, 0x72, 0x7f, 0x60, 0x78, 0xe8, + 0xa0, 0x0e, 0x4d, 0xc2, 0x6b, 0x3e, 0xee, 0x1e, 0x08, 0x92, 0x45, 0x93, 0x32, 0xc0, 0xca, 0xf9, 0xb5, 0x3f, 0xb8, + 0x12, 0x45, 0x81, 0xa4, 0x02, 0x71, 0x03, 0x45, 0xc9, 0xe3, 0x08, 0x17, 0x3f, 0x6d, 0xb7, 0x60, 0x2f, 0x2e, 0x06, + 0x1b, 0x50, 0x44, 0x30, 0xd9, 0x4c, 0x11, 0x8a, 0x43, 0xe4, 0x6a, 0x74, 0x0b, 0x6e, 0x09, 0x46, 0x74, 0xe3, 0x4a, + 0xcc, 0x84, 0x4d, 0x61, 0xd1, 0x26, 0xe0, 0xb1, 0x28, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, 0xd9, 0x2e, 0xa9, + 0x35, 0xb9, 0x53, 0xdd, 0x26, 0xfe, 0x52, 0xf1, 0xc8, 0x13, 0xcc, 0xb9, 0xea, 0x98, 0x57, 0x12, 0x75, 0xa3, 0xf7, + 0x95, 0x68, 0x55, 0x83, 0x46, 0x56, 0x82, 0x28, 0xfe, 0x56, 0x2e, 0x28, 0x42, 0xa1, 0xae, 0xca, 0xc6, 0x2f, 0x0a, + 0xd9, 0x38, 0xdd, 0x6a, 0x0a, 0x47, 0x1a, 0xc1, 0xfd, 0x2b, 0x4e, 0x6a, 0xf2, 0x76, 0x50, 0x38, 0xab, 0x15, 0x3d, + 0x55, 0xdc, 0xaf, 0x8a, 0x8b, 0x86, 0xe2, 0xd4, 0x27, 0x6e, 0x19, 0x65, 0xdf, 0xbe, 0x72, 0xd5, 0xc2, 0xfb, 0xaa, + 0x28, 0x07, 0xa9, 0x3b, 0x76, 0x59, 0x16, 0xab, 0xcb, 0xa6, 0xec, 0x7e, 0xa3, 0xbe, 0x56, 0x16, 0x89, 0xf4, 0x93, + 0x21, 0x04, 0x0b, 0x31, 0x7d, 0x45, 0xaf, 0x2d, 0x6d, 0x20, 0xb0, 0x93, 0x0d, 0x6e, 0x7d, 0xbb, 0xa5, 0xf3, 0x94, + 0x2f, 0xa1, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0xc4, 0xef, 0xd5, 0xba, 0xe1, 0x94, 0xc7, 0x43, 0x9e, 0x9f, 0xef, 0x20, + 0x5e, 0xd4, 0x1c, 0x55, 0x91, 0x8f, 0x3b, 0xd3, 0x22, 0xf3, 0x5c, 0xac, 0x5a, 0x07, 0x4a, 0x42, 0x9c, 0x35, 0xf7, + 0x8c, 0x29, 0xcb, 0xe8, 0x79, 0x8d, 0x9e, 0xf8, 0x2e, 0x5f, 0x3a, 0xc9, 0x2a, 0xc2, 0xd8, 0xf6, 0x56, 0x96, 0xf8, + 0xe3, 0x4f, 0x4a, 0x97, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0x41, 0xdf, 0xc7, 0x50, 0x90, 0xac, 0x67, 0x7b, + 0xa9, 0x22, 0x7d, 0xe9, 0x3d, 0x76, 0xda, 0xfe, 0x8b, 0xe9, 0x61, 0x45, 0x28, 0xea, 0x75, 0xca, 0x22, 0xf3, 0x0d, + 0xfd, 0xc8, 0xe6, 0xab, 0xc5, 0x68, 0xad, 0xca, 0x56, 0x15, 0x91, 0x6b, 0x5d, 0xcc, 0xaa, 0x7e, 0x76, 0x3a, 0x9d, + 0x96, 0x05, 0x8d, 0x8e, 0x76, 0x88, 0xc2, 0xc2, 0xc7, 0x8e, 0xe3, 0x54, 0xfb, 0xbe, 0x1d, 0xed, 0x16, 0xca, 0x6d, + 0xbb, 0x8d, 0x3d, 0x46, 0xdc, 0xee, 0xc2, 0x5f, 0x1d, 0x1d, 0xb9, 0x5d, 0xec, 0xec, 0x92, 0x59, 0x44, 0x9f, 0x8c, + 0x21, 0x82, 0x8c, 0x2d, 0xd2, 0xde, 0x98, 0xa1, 0x0e, 0xc6, 0x56, 0x36, 0x34, 0x1a, 0x0e, 0x58, 0x33, 0x30, 0x15, + 0x71, 0xc5, 0xaa, 0x70, 0x34, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0xb8, 0x51, 0xd6, 0x75, 0x99, 0x36, 0x0e, + 0xab, 0xe3, 0xfc, 0xa5, 0x54, 0x4f, 0x83, 0x03, 0x70, 0x2d, 0x14, 0xda, 0x24, 0x9f, 0xc5, 0xbf, 0xa5, 0xfc, 0xff, + 0xc5, 0xf2, 0xae, 0x6c, 0x3f, 0xd2, 0x05, 0x89, 0x76, 0xb1, 0x5b, 0xa8, 0xd7, 0x4d, 0x6b, 0x40, 0x5a, 0x19, 0x4c, + 0x55, 0x05, 0x3a, 0x28, 0xe9, 0x4b, 0x09, 0x40, 0x1a, 0xc4, 0xef, 0xc8, 0x31, 0xc3, 0x14, 0x17, 0x22, 0xc4, 0x22, + 0x7d, 0x1d, 0x8c, 0xc1, 0x7c, 0xde, 0x45, 0xfd, 0x41, 0x69, 0x4d, 0x80, 0x36, 0xbe, 0x36, 0xb6, 0xbd, 0xc4, 0xfd, + 0x55, 0xbd, 0x96, 0x00, 0x0c, 0x28, 0x73, 0x61, 0x13, 0xa2, 0x21, 0x81, 0x56, 0x59, 0xdc, 0xd4, 0x4b, 0xf9, 0x56, + 0xd5, 0xb3, 0x89, 0x8e, 0x21, 0xb8, 0xe6, 0x2a, 0x04, 0x5b, 0x68, 0x0b, 0x60, 0xb0, 0x7c, 0xf9, 0xe1, 0xb3, 0x05, + 0x53, 0xac, 0xae, 0x47, 0x17, 0xa7, 0x1c, 0xd7, 0xaf, 0x85, 0x67, 0x67, 0x4a, 0xfb, 0x1f, 0xe5, 0x8b, 0x3f, 0x34, + 0x0a, 0xf4, 0x2e, 0x4a, 0x12, 0x3a, 0x6e, 0x2d, 0xee, 0x19, 0x7b, 0xd5, 0x5e, 0x04, 0xd1, 0xfe, 0x75, 0xfd, 0xbb, + 0xbd, 0xeb, 0xc2, 0x81, 0xb1, 0x77, 0x65, 0x38, 0x71, 0xc8, 0x72, 0x21, 0x1b, 0xfc, 0xa0, 0x08, 0x14, 0x55, 0xaf, + 0x63, 0x1d, 0x5b, 0x11, 0x97, 0x7f, 0xb1, 0x1a, 0x0c, 0x4f, 0xce, 0xee, 0x16, 0xa1, 0x76, 0xc3, 0x12, 0x48, 0xed, + 0x33, 0xd0, 0x5d, 0xdb, 0xd1, 0x35, 0xf4, 0xa1, 0x0d, 0xa2, 0xd9, 0x40, 0xff, 0xe5, 0xe2, 0x8d, 0xd5, 0xd5, 0xcf, + 0x40, 0x45, 0x7b, 0x33, 0xc3, 0x63, 0xef, 0xdc, 0xbf, 0x67, 0xc9, 0xb5, 0xa7, 0x6b, 0x98, 0xc1, 0x87, 0x0e, 0x3c, + 0x2c, 0xd3, 0x3c, 0x7d, 0x8f, 0x44, 0x11, 0x9a, 0xc8, 0xf5, 0xa6, 0x03, 0xc9, 0x71, 0xbd, 0xae, 0xe6, 0x7a, 0x87, + 0xf6, 0x51, 0x57, 0x3f, 0xfd, 0x46, 0xd3, 0x4e, 0x26, 0x6c, 0x9a, 0x9e, 0xe2, 0x15, 0xed, 0x04, 0xcf, 0x08, 0xfa, + 0xad, 0x69, 0xf6, 0x38, 0x4c, 0x2d, 0x57, 0x5b, 0xf3, 0x47, 0x4d, 0x9b, 0x06, 0x61, 0xd8, 0xd3, 0x1e, 0x4f, 0xbd, + 0xe9, 0xe1, 0xf4, 0x45, 0x9f, 0x17, 0xe7, 0xdf, 0x94, 0xaa, 0x9b, 0xf4, 0xaf, 0xa7, 0x34, 0x4b, 0xb3, 0x24, 0xfe, + 0xc4, 0xb8, 0xd9, 0x89, 0x26, 0x2f, 0x8f, 0xd5, 0xa6, 0x5e, 0xfd, 0x4b, 0x6e, 0x77, 0x34, 0x9e, 0x7a, 0x45, 0x75, + 0xec, 0xe3, 0x81, 0xec, 0xe4, 0xc9, 0x81, 0xe8, 0xfa, 0x89, 0x8a, 0x26, 0xd7, 0x6a, 0x42, 0x94, 0xab, 0xf3, 0x31, + 0xce, 0xc4, 0xf8, 0x4e, 0x20, 0x0e, 0xa3, 0x74, 0xd7, 0x85, 0x1e, 0xe8, 0xda, 0x64, 0xa0, 0xff, 0xe8, 0x7a, 0x5d, + 0xd3, 0x75, 0x8f, 0xec, 0xa3, 0xee, 0xd8, 0x31, 0x0f, 0xed, 0x43, 0xab, 0x6d, 0x1f, 0x99, 0x5d, 0xab, 0x6b, 0x76, + 0xff, 0xd6, 0x1d, 0x5b, 0x87, 0xf6, 0xa1, 0xe9, 0x58, 0x5d, 0x28, 0xb4, 0xba, 0x56, 0xf7, 0xc6, 0x3a, 0xec, 0x8e, + 0x1d, 0x2c, 0xf5, 0xec, 0x4e, 0xc7, 0x72, 0x1d, 0xbb, 0xd3, 0x31, 0x3b, 0xf6, 0xd1, 0x91, 0xe5, 0xb6, 0xed, 0xa3, + 0xa3, 0xf3, 0x4e, 0xd7, 0x6e, 0xc3, 0xbb, 0x76, 0x7b, 0xdc, 0xb6, 0x5d, 0xd7, 0x82, 0xbf, 0xcc, 0xae, 0xed, 0xd1, + 0x0f, 0xd7, 0xb5, 0xdb, 0xae, 0xe9, 0x84, 0x1d, 0xcf, 0x3e, 0x7a, 0x61, 0xe2, 0xdf, 0x58, 0xcd, 0xc4, 0xbf, 0x00, + 0x8c, 0xf9, 0xc2, 0xf6, 0x8e, 0xe8, 0x17, 0x02, 0xbc, 0x39, 0xec, 0xfe, 0xaa, 0x1f, 0x6c, 0x1c, 0x83, 0x4b, 0x63, + 0xe8, 0x76, 0xec, 0x76, 0xdb, 0x3c, 0x74, 0xed, 0x6e, 0x7b, 0x6e, 0x1d, 0x7a, 0xf6, 0xd1, 0xf1, 0xd8, 0x72, 0xed, + 0xe3, 0x63, 0xd3, 0xb1, 0xda, 0xb6, 0x67, 0xba, 0xf6, 0x61, 0x1b, 0x7f, 0xb4, 0x6d, 0xef, 0xe6, 0xf8, 0x85, 0x7d, + 0xd4, 0x99, 0x1f, 0xd9, 0x87, 0x1f, 0x0f, 0xbb, 0xb6, 0xd7, 0x9e, 0xb7, 0x8f, 0x6c, 0xef, 0xf8, 0xe6, 0xc8, 0x3e, + 0x9c, 0x5b, 0xde, 0xd1, 0xd6, 0x96, 0xae, 0x67, 0x03, 0x8e, 0xf0, 0x35, 0xbc, 0x30, 0xf9, 0x0b, 0xf8, 0x33, 0xc7, + 0xb6, 0xff, 0x45, 0x30, 0x69, 0xbd, 0xe9, 0x0b, 0xbb, 0x7b, 0x3c, 0xa6, 0xea, 0x50, 0x60, 0x89, 0x1a, 0xd0, 0xe4, + 0xc6, 0xa2, 0xcf, 0x22, 0x38, 0x4b, 0x00, 0x12, 0x7f, 0xf8, 0xc7, 0x6e, 0x2c, 0xf8, 0x30, 0x7d, 0xf7, 0x7f, 0x0a, + 0x47, 0x4e, 0x39, 0x64, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x49, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x45, 0xc5, 0xfb, 0xdd, + 0x8a, 0x8a, 0x37, 0xab, 0x7d, 0x14, 0x15, 0xef, 0xbf, 0xba, 0xa2, 0xe2, 0xbc, 0x6a, 0x27, 0xff, 0xbe, 0x1a, 0x9b, + 0xfe, 0xd7, 0x75, 0xf5, 0x1a, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x44, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, + 0x4a, 0x46, 0x60, 0x31, 0xd0, 0xd8, 0xf7, 0x31, 0xd1, 0xd8, 0xdf, 0x57, 0x03, 0xb0, 0x3c, 0xe1, 0x7c, 0x49, 0x30, + 0xb1, 0xe6, 0x7e, 0x38, 0x95, 0x3c, 0x0d, 0x94, 0xf4, 0xb1, 0x18, 0xbc, 0x12, 0xe0, 0xb8, 0x06, 0x75, 0xd8, 0x6a, + 0x11, 0xa5, 0xbd, 0x23, 0x07, 0x0e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xc6, 0xb6, 0x88, 0x47, 0x75, 0xcd, 0xbd, 0x26, + 0x36, 0xbe, 0x47, 0xa3, 0xc0, 0x66, 0xe8, 0x6e, 0x1d, 0xae, 0x06, 0xd6, 0x36, 0xc2, 0x68, 0x12, 0xd8, 0xb9, 0xa6, + 0xf7, 0x65, 0xd3, 0xbc, 0x8a, 0x31, 0xe6, 0xe6, 0x9e, 0x42, 0x4f, 0xaa, 0xed, 0xdd, 0xb2, 0x69, 0xdf, 0xae, 0x61, + 0x36, 0x7c, 0xbe, 0xd4, 0x7c, 0x8b, 0x5d, 0xa1, 0x04, 0x5c, 0x45, 0x55, 0x25, 0xb3, 0x5a, 0x23, 0x42, 0x0a, 0xee, + 0xbe, 0x30, 0x3e, 0x2c, 0x58, 0x4b, 0x47, 0x43, 0x7e, 0xc7, 0x51, 0xde, 0x95, 0x60, 0xaa, 0x06, 0x8b, 0xcf, 0xd6, + 0xc8, 0x71, 0x07, 0xbf, 0x03, 0xeb, 0xc8, 0x39, 0x9e, 0x51, 0xac, 0xe2, 0x79, 0xad, 0xc0, 0xa5, 0xcb, 0x4c, 0x3e, + 0x77, 0xd7, 0x75, 0xe6, 0x71, 0xa3, 0xa9, 0xb2, 0xcb, 0x16, 0x82, 0x0b, 0xc2, 0xcf, 0x93, 0x61, 0x70, 0x4e, 0xc6, + 0xdb, 0x68, 0xfb, 0xbc, 0x0d, 0x98, 0xa8, 0xf7, 0x18, 0x16, 0xb1, 0xc9, 0x1f, 0xd4, 0xb8, 0x00, 0xeb, 0x29, 0x64, + 0xc1, 0xee, 0x21, 0x9b, 0xa6, 0xf0, 0xa8, 0x1e, 0x5a, 0x31, 0xf7, 0xb7, 0x18, 0xd8, 0xa8, 0x80, 0x39, 0x10, 0xb4, + 0x86, 0xde, 0x66, 0x93, 0x23, 0x9d, 0x47, 0xd6, 0x25, 0x15, 0xb5, 0xdb, 0x39, 0x36, 0xdd, 0x23, 0xd3, 0x3e, 0xee, + 0x18, 0xb9, 0xd8, 0x70, 0x2a, 0xc8, 0x12, 0x42, 0xc0, 0x28, 0x5a, 0x76, 0x33, 0x88, 0x82, 0x2c, 0xf0, 0xc3, 0x1c, + 0xf8, 0xe3, 0xf2, 0xad, 0xe2, 0x9f, 0xab, 0x34, 0x83, 0x31, 0x0a, 0xa6, 0x17, 0x0d, 0xc2, 0xad, 0x11, 0xcb, 0x6e, + 0x19, 0x8b, 0x36, 0x28, 0xcb, 0xab, 0xf6, 0xe5, 0x7f, 0x9e, 0xb5, 0x6d, 0x4e, 0x96, 0x2c, 0xa3, 0x2c, 0xe2, 0xeb, + 0x43, 0x18, 0x43, 0xe7, 0x43, 0xf3, 0xa7, 0x4d, 0x04, 0xf7, 0x9f, 0xbb, 0x09, 0x6e, 0xc6, 0xf6, 0x21, 0xb8, 0xff, + 0xfc, 0xea, 0x04, 0xf7, 0x27, 0x95, 0xe0, 0x96, 0x7c, 0x81, 0x0a, 0xa9, 0xf3, 0x07, 0x7c, 0x6e, 0x41, 0x50, 0xe7, + 0xe7, 0xfa, 0x01, 0x31, 0xf0, 0xba, 0x92, 0x6c, 0xf7, 0x63, 0x29, 0x7b, 0x10, 0x0a, 0x45, 0x30, 0x08, 0x2d, 0x65, + 0x2a, 0x81, 0x44, 0xb4, 0x32, 0xa5, 0x3a, 0xc0, 0x7c, 0x1b, 0x65, 0xa1, 0xfd, 0x9e, 0x5f, 0xfc, 0x40, 0xc9, 0xf3, + 0x26, 0x4e, 0x16, 0x3e, 0x06, 0xe0, 0xd3, 0x31, 0xeb, 0x20, 0x3c, 0x38, 0xe0, 0x7f, 0x36, 0x8e, 0xa3, 0x89, 0xd4, + 0x54, 0xb0, 0xc1, 0x25, 0x71, 0xdc, 0xfa, 0x3d, 0xf3, 0x13, 0xdd, 0xa4, 0xd7, 0x30, 0xb9, 0xcf, 0xda, 0xce, 0x33, + 0xef, 0xf0, 0xd9, 0x91, 0x03, 0xff, 0xbb, 0xac, 0x9d, 0x9b, 0xbc, 0xe2, 0x22, 0x8e, 0x20, 0xf1, 0x89, 0xa8, 0xb9, + 0xa9, 0xda, 0x2d, 0x63, 0x9f, 0x8a, 0x5a, 0xc7, 0xcd, 0x95, 0x26, 0xfe, 0x7d, 0x51, 0xa7, 0xb1, 0xc6, 0x3c, 0x5e, + 0x29, 0xdd, 0x6a, 0xe8, 0x4d, 0x10, 0xad, 0x40, 0xf6, 0xa6, 0xd4, 0x50, 0x5f, 0xf3, 0xe1, 0x16, 0xe3, 0x62, 0xed, + 0xfc, 0xaa, 0xc8, 0xae, 0x24, 0xb2, 0xbc, 0xec, 0xc4, 0x20, 0x57, 0x5b, 0x38, 0x18, 0x9b, 0x1d, 0xf3, 0x0b, 0x69, + 0x90, 0xdb, 0x50, 0x4c, 0x90, 0x4f, 0x13, 0x94, 0x25, 0xab, 0x68, 0xdc, 0xc2, 0x9f, 0xfe, 0x28, 0x6d, 0x05, 0x07, + 0x10, 0x9d, 0x15, 0x3f, 0x6c, 0xe0, 0xac, 0xf9, 0xa7, 0x4e, 0x91, 0x8a, 0x22, 0x15, 0xb3, 0xe2, 0x3f, 0xcb, 0xcc, + 0x84, 0x12, 0xd8, 0xe2, 0xd4, 0x5a, 0x03, 0xff, 0x99, 0x6c, 0xf8, 0x2c, 0x33, 0x21, 0x89, 0x2c, 0x4c, 0xf7, 0xd3, + 0xa7, 0x54, 0x0b, 0xd2, 0x3a, 0xd2, 0xb0, 0xce, 0xc6, 0x45, 0x78, 0x37, 0xcd, 0x9f, 0xc5, 0x14, 0xe1, 0xad, 0x37, + 0x36, 0xe3, 0xe7, 0xcf, 0x4f, 0x07, 0xae, 0xc1, 0x93, 0x92, 0x96, 0x32, 0x68, 0x9d, 0xef, 0x67, 0x7c, 0x60, 0x34, + 0xba, 0xc5, 0x2d, 0xe1, 0xce, 0xe4, 0x08, 0x13, 0x65, 0x4e, 0xbd, 0x20, 0xa3, 0x05, 0x29, 0x19, 0x7d, 0x61, 0x04, + 0x20, 0xea, 0xc8, 0x5b, 0x57, 0xdb, 0x76, 0x6c, 0x47, 0x97, 0x0d, 0xa7, 0xc1, 0x6c, 0xb0, 0x8e, 0x33, 0x1f, 0x72, + 0x03, 0x85, 0xf1, 0x0c, 0x7c, 0x6b, 0xb2, 0x20, 0x0b, 0x21, 0xd1, 0x0c, 0x38, 0xd9, 0x2c, 0xe8, 0x5e, 0x9e, 0x73, + 0x8b, 0x67, 0x3f, 0xf9, 0x84, 0xc9, 0x06, 0x85, 0x5b, 0x1d, 0x46, 0x1c, 0xfa, 0x11, 0x0e, 0xc3, 0x96, 0xde, 0x82, + 0x54, 0x97, 0x2c, 0x49, 0x2d, 0xd5, 0x83, 0xa0, 0xa7, 0x41, 0x1b, 0x48, 0x43, 0x8f, 0x00, 0xa6, 0x89, 0xbf, 0x80, + 0x98, 0xec, 0xeb, 0xdc, 0xe4, 0x94, 0x56, 0xe7, 0xa4, 0x56, 0x73, 0x5f, 0x1c, 0x99, 0x9a, 0xe7, 0x9a, 0x9a, 0x03, + 0xe4, 0x56, 0xcf, 0xcd, 0x75, 0x7e, 0xd5, 0xdf, 0xa5, 0x04, 0x25, 0xfa, 0xf2, 0x98, 0xc6, 0x41, 0xea, 0x4f, 0x2e, + 0x5e, 0xce, 0x28, 0x80, 0x64, 0x4b, 0x89, 0x96, 0x1e, 0x90, 0x22, 0xe4, 0x82, 0xdd, 0x65, 0x06, 0x26, 0x62, 0xe1, + 0x55, 0x02, 0x63, 0x8d, 0xce, 0x7f, 0x41, 0xa4, 0x05, 0x9f, 0x3f, 0xb7, 0x02, 0x70, 0x70, 0x18, 0x28, 0xf8, 0x81, + 0x67, 0xa3, 0x84, 0xb0, 0xa0, 0x50, 0xdd, 0x21, 0xb2, 0xc0, 0xfb, 0x08, 0xfe, 0x2d, 0x8a, 0xc5, 0x0f, 0xae, 0x3a, + 0xb5, 0x43, 0x3f, 0x9a, 0x01, 0x49, 0xf3, 0xa3, 0x59, 0xcd, 0x44, 0x83, 0xfc, 0x17, 0x2b, 0xa5, 0x05, 0xa8, 0xc2, + 0x7c, 0x22, 0xfd, 0xfe, 0xfe, 0x82, 0x12, 0x4d, 0x41, 0x52, 0x73, 0x7f, 0x82, 0xce, 0x76, 0x85, 0x76, 0xe7, 0xf9, + 0xe0, 0xdb, 0x93, 0x05, 0xcb, 0x7c, 0x12, 0x0d, 0xc3, 0xe5, 0x17, 0xd8, 0x01, 0x6d, 0x2c, 0x92, 0xc4, 0x52, 0x32, + 0xf9, 0x09, 0xbb, 0x09, 0xc6, 0xfc, 0x5e, 0x6a, 0x6a, 0xfc, 0x9c, 0xb2, 0xd0, 0x0a, 0x6c, 0xe0, 0x9a, 0x64, 0x84, + 0x3c, 0xf6, 0x31, 0xcc, 0xe4, 0x20, 0x8a, 0xf5, 0xd3, 0x6f, 0xa5, 0xbf, 0xd6, 0xa6, 0x49, 0x80, 0x6c, 0x8f, 0x97, + 0x09, 0x0b, 0xff, 0x35, 0xf8, 0x16, 0x0e, 0xee, 0x6f, 0xaf, 0x74, 0xa3, 0x9f, 0xd9, 0xf3, 0x84, 0x4d, 0x07, 0xdf, + 0x36, 0x64, 0x3d, 0xc4, 0xeb, 0x3d, 0xf5, 0x45, 0x6f, 0x7b, 0x45, 0x70, 0xa0, 0xf6, 0x5e, 0x97, 0xfa, 0x53, 0x7e, + 0x5b, 0x87, 0x1b, 0xe0, 0xba, 0x74, 0xc7, 0x76, 0xfb, 0x78, 0x7f, 0x1e, 0x85, 0xfe, 0xf8, 0x53, 0x9f, 0xde, 0x94, + 0x1e, 0x2c, 0x38, 0xad, 0xc7, 0xfe, 0xb2, 0x87, 0xc7, 0xab, 0x5a, 0x08, 0xee, 0x9a, 0x54, 0x2a, 0x39, 0xbb, 0xc6, + 0xb5, 0x8c, 0x4b, 0x79, 0x8d, 0x5f, 0xc6, 0x4f, 0xdd, 0xce, 0x83, 0x8c, 0x89, 0x4f, 0xe1, 0x43, 0x9e, 0x8b, 0x8b, + 0x3a, 0x5d, 0x51, 0xf1, 0x62, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, + 0x74, 0xbb, 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, + 0x3f, 0xba, 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xad, 0xe0, 0x02, 0x44, 0xf7, 0x9d, 0x6f, 0x4b, 0x54, + 0x40, 0xf9, 0x2d, 0xf5, 0x34, 0x66, 0xe9, 0x78, 0x6b, 0xd0, 0xf5, 0x00, 0xc9, 0xd0, 0x4d, 0x11, 0x04, 0x32, 0xea, + 0xb7, 0x20, 0x0d, 0x3b, 0x26, 0x10, 0x10, 0x26, 0x2f, 0xc2, 0x2f, 0x55, 0x84, 0xd2, 0x6f, 0xdc, 0x46, 0xbc, 0x4d, + 0x73, 0xc0, 0x75, 0x91, 0x99, 0x8a, 0x94, 0x43, 0xbf, 0x2c, 0x31, 0x88, 0x91, 0x08, 0x11, 0xaf, 0x50, 0xa5, 0x22, + 0x3b, 0x62, 0xbe, 0xbb, 0xe3, 0xe8, 0x99, 0xcb, 0x64, 0x76, 0x9e, 0xaf, 0x0a, 0x9b, 0x2b, 0x8c, 0x24, 0xf4, 0x3f, + 0x0a, 0x07, 0x93, 0xd2, 0x12, 0x1c, 0x11, 0xcd, 0x75, 0x12, 0x24, 0xb2, 0x7b, 0x0a, 0x89, 0x76, 0x9b, 0x23, 0xd5, + 0x1b, 0x90, 0xc6, 0xe4, 0x2d, 0x70, 0xc9, 0x37, 0x7e, 0xa8, 0x18, 0xb7, 0x28, 0x2d, 0x1f, 0x49, 0xca, 0xff, 0xf4, + 0x69, 0xd1, 0x39, 0xab, 0xd2, 0xef, 0x13, 0xb7, 0x03, 0xc7, 0x6e, 0x87, 0xb5, 0xb7, 0xda, 0x59, 0xed, 0x0e, 0x07, + 0x5c, 0x84, 0x0b, 0x15, 0xb6, 0x14, 0x42, 0x8b, 0xbb, 0xd1, 0xd8, 0xab, 0xa6, 0xc3, 0x85, 0x40, 0xca, 0x95, 0xab, + 0x8e, 0x6e, 0xf4, 0x23, 0xa1, 0x92, 0x8c, 0xb6, 0x84, 0x40, 0xe6, 0x77, 0x31, 0x1d, 0x50, 0xb3, 0x65, 0x1c, 0x3b, + 0x9c, 0x46, 0xff, 0xd7, 0x83, 0x40, 0x07, 0x2e, 0xd0, 0xa1, 0x56, 0x76, 0x6b, 0xc9, 0xa1, 0x47, 0x9e, 0xab, 0x74, + 0xa0, 0xb2, 0xf4, 0x4c, 0x87, 0x22, 0xc8, 0x6f, 0x85, 0x29, 0xed, 0xa4, 0x01, 0x99, 0x3c, 0x2d, 0x8a, 0x02, 0x33, + 0x80, 0x18, 0xe0, 0x2d, 0xe1, 0x4c, 0x66, 0x3c, 0x7d, 0xba, 0xf1, 0x10, 0x22, 0x85, 0xbd, 0x9a, 0xd9, 0x53, 0x57, + 0xe9, 0x9b, 0xae, 0x92, 0x18, 0x09, 0x17, 0xa9, 0x86, 0xb0, 0x7b, 0xa3, 0xb5, 0x87, 0x3f, 0x47, 0xcc, 0xcf, 0x6c, + 0xae, 0x69, 0x6a, 0x29, 0x87, 0xbb, 0xe9, 0xb2, 0x36, 0x58, 0xbc, 0xf1, 0x58, 0x67, 0x3c, 0x96, 0xe0, 0x93, 0xf5, + 0xc7, 0x15, 0xf7, 0xf4, 0x06, 0x18, 0x9f, 0x9d, 0x22, 0x3c, 0xcd, 0xbb, 0xcc, 0xa7, 0x18, 0x26, 0xea, 0x91, 0x1b, + 0x67, 0xbe, 0xc8, 0x23, 0x03, 0x7c, 0x79, 0xbf, 0x51, 0x25, 0xab, 0x78, 0x83, 0x9f, 0xbe, 0xbb, 0xf8, 0x4e, 0xe3, + 0xeb, 0x9f, 0x34, 0x88, 0x78, 0x91, 0xa1, 0xac, 0x07, 0x03, 0xca, 0x7a, 0xa0, 0xf1, 0x34, 0x22, 0x90, 0x3b, 0x20, + 0x3f, 0x20, 0x0c, 0xa2, 0x00, 0x9a, 0xf4, 0xaa, 0x8b, 0x55, 0x98, 0x05, 0x4b, 0x3f, 0xc9, 0x0e, 0xa0, 0xa9, 0x05, + 0x44, 0x4e, 0xdf, 0xe4, 0x23, 0x4e, 0xaa, 0x59, 0x11, 0x62, 0x2f, 0x8b, 0x84, 0x6e, 0x76, 0x1a, 0x84, 0x52, 0x35, + 0x2b, 0x3e, 0xe0, 0x8f, 0xc7, 0x6c, 0x99, 0x0d, 0x74, 0x7f, 0x09, 0xd9, 0x2f, 0x30, 0x9e, 0xf5, 0x41, 0x3c, 0xce, + 0x58, 0x66, 0xa5, 0x59, 0xc2, 0xfc, 0x85, 0x2e, 0x43, 0xb9, 0xd6, 0xe1, 0xa5, 0xab, 0xd1, 0x22, 0xc8, 0x64, 0x2c, + 0x44, 0x1a, 0x20, 0x28, 0x49, 0xa1, 0x8b, 0xa7, 0xc3, 0x9c, 0xa3, 0xf0, 0x3c, 0x9e, 0x55, 0x56, 0x54, 0xc1, 0xb9, + 0x9c, 0x61, 0xa4, 0x5d, 0x9e, 0xf1, 0x60, 0x82, 0x3e, 0x4f, 0xd7, 0xdc, 0xaf, 0x5d, 0x86, 0x6c, 0xd4, 0x4f, 0x4f, + 0xf8, 0xf5, 0x56, 0xc3, 0x50, 0x0c, 0x7a, 0xc7, 0x81, 0x58, 0xc2, 0x9b, 0x3c, 0xde, 0x0f, 0x78, 0x65, 0x38, 0x9a, + 0x08, 0x32, 0xc6, 0x79, 0xa7, 0xbe, 0x5c, 0x00, 0x23, 0x54, 0x52, 0xa2, 0xcf, 0xdd, 0x53, 0xe9, 0x62, 0x85, 0xbd, + 0x42, 0x5e, 0xe9, 0xf3, 0xe7, 0x97, 0xc3, 0xff, 0xfc, 0x1b, 0x82, 0xd1, 0xcf, 0x5d, 0xe1, 0x67, 0x7e, 0xa9, 0xd6, + 0xe2, 0xdc, 0xa7, 0x39, 0x44, 0x03, 0x0a, 0x36, 0x11, 0x81, 0x57, 0xc4, 0xd2, 0xca, 0x87, 0x57, 0x22, 0x98, 0x16, + 0x24, 0x9c, 0x30, 0x84, 0x37, 0xfc, 0x10, 0xa6, 0x77, 0x28, 0x82, 0x30, 0x68, 0xbf, 0xdd, 0x7d, 0x7f, 0x0c, 0xc1, + 0x96, 0x6b, 0x79, 0x20, 0x94, 0x0e, 0xe2, 0x1a, 0x3a, 0x3d, 0xf1, 0x35, 0x64, 0x5a, 0x90, 0xfd, 0x48, 0x7b, 0x07, + 0x30, 0xcc, 0x79, 0xbc, 0x60, 0x76, 0x10, 0x1f, 0xdc, 0xb2, 0x91, 0xe5, 0x2f, 0x03, 0xd2, 0xd5, 0xa3, 0xdc, 0x4d, + 0x23, 0xce, 0x4f, 0xaa, 0xc0, 0x89, 0xbf, 0xce, 0x0b, 0x54, 0xc6, 0xe5, 0xe8, 0x69, 0x1d, 0xaf, 0x50, 0xdc, 0x81, + 0x4f, 0xb3, 0x82, 0xc7, 0xf8, 0xf4, 0xe4, 0xc0, 0x3f, 0x2d, 0x87, 0x6f, 0xb4, 0x45, 0x02, 0x81, 0xf2, 0x21, 0x70, + 0x46, 0x51, 0x18, 0x45, 0xc0, 0xc5, 0xe2, 0xc1, 0x8a, 0xa7, 0x53, 0x35, 0xe4, 0xa2, 0x5d, 0xee, 0x9e, 0x44, 0x5a, + 0xb1, 0xa4, 0xe3, 0x25, 0x7d, 0xa9, 0xfe, 0x09, 0xf9, 0x13, 0x92, 0x27, 0xf3, 0xe8, 0x9c, 0xb0, 0xdd, 0x6b, 0xa1, + 0x1b, 0x25, 0xc6, 0x1e, 0x53, 0x25, 0x4e, 0x47, 0xaa, 0x81, 0xc2, 0x37, 0x70, 0x2e, 0x8f, 0x06, 0x03, 0x22, 0x73, + 0x55, 0x6a, 0x07, 0x48, 0x6c, 0x48, 0xa6, 0x00, 0x83, 0xcd, 0xa0, 0xa1, 0x45, 0x2e, 0x74, 0xd8, 0xa8, 0x3a, 0x9c, + 0x7a, 0x1f, 0x0f, 0x7c, 0xb1, 0xfc, 0x4a, 0x0b, 0x14, 0x16, 0x1e, 0x9f, 0x77, 0xa0, 0xef, 0x02, 0x4e, 0x85, 0xcc, + 0x6b, 0x7f, 0x25, 0x8a, 0x6e, 0x85, 0xfe, 0x7d, 0xac, 0x98, 0x36, 0xf0, 0x28, 0x07, 0xe7, 0x58, 0x7a, 0x21, 0xbc, + 0x0b, 0x6b, 0x1b, 0x4d, 0x06, 0xa4, 0xaf, 0x6f, 0x36, 0x35, 0x82, 0xfc, 0xae, 0xbd, 0xa6, 0xd6, 0x2d, 0x0f, 0x06, + 0x89, 0x67, 0x5e, 0xec, 0xc3, 0xd2, 0x4b, 0x24, 0x0b, 0xf9, 0xc9, 0x01, 0x8c, 0x0f, 0x22, 0x33, 0x94, 0x18, 0xa7, + 0xc0, 0x80, 0xf0, 0x0f, 0x7e, 0x4a, 0xe6, 0x19, 0x6f, 0x27, 0x82, 0xe7, 0xc3, 0x8b, 0xa5, 0x8c, 0x0d, 0x5b, 0xaa, + 0x52, 0xe7, 0x65, 0x9c, 0x66, 0x26, 0x70, 0x77, 0x02, 0x87, 0xdf, 0x57, 0x98, 0xbd, 0x21, 0xef, 0x67, 0x4c, 0x38, + 0x3e, 0x9f, 0x67, 0x1b, 0x7c, 0xa3, 0x37, 0x55, 0x21, 0x7e, 0x76, 0x4b, 0x85, 0x62, 0x1d, 0x6f, 0xab, 0x55, 0x70, + 0x4e, 0xb2, 0xda, 0xd2, 0x6f, 0xe9, 0x8f, 0x71, 0xc5, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0x3b, 0xcf, 0x06, 0x50, 0x55, + 0xc8, 0xe2, 0xfd, 0xe5, 0x92, 0x2a, 0x1b, 0xfd, 0x93, 0x03, 0xba, 0x96, 0x9e, 0xd2, 0x0a, 0x3b, 0x3d, 0x01, 0xf3, + 0x4e, 0x9a, 0x74, 0x7f, 0xb9, 0xe4, 0x53, 0x4a, 0xbf, 0xe8, 0xcd, 0xc1, 0x3c, 0x5b, 0x84, 0xa7, 0xff, 0x07, 0xc0, + 0xb1, 0x34, 0x8b, 0x20, 0x5c, 0x03, 0x00}; } // namespace web_server } // namespace esphome From 08b8ab837a2b6da234691cbd750625eea9fe38c0 Mon Sep 17 00:00:00 2001 From: Colm Date: Thu, 11 Jul 2024 05:10:58 +0100 Subject: [PATCH 2041/2607] Add braces to if statement to avoid compiler warning. (#7036) --- esphome/components/aht10/aht10.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index 332218b9e9..441c1ac9df 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -93,8 +93,9 @@ void AHT10Component::restart_read_() { void AHT10Component::read_data_() { uint8_t data[6]; - if (this->read_count_ > 1) + if (this->read_count_ > 1) { ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); + } if (this->read(data, 6) != i2c::ERROR_OK) { this->status_set_warning("AHT10 read failed, retrying soon"); this->restart_read_(); @@ -119,8 +120,9 @@ void AHT10Component::read_data_() { return; } } - if (this->read_count_ > 1) + if (this->read_count_ > 1) { ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); + } uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; From 6e624ff7974311bc22058466f0688d554a340b1f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 10 Jul 2024 23:21:24 -0500 Subject: [PATCH 2042/2607] [wifi] Fix EAP for IDF 5.1+, add test (#7061) --- esphome/components/wifi/wifi_component.h | 4 ++ .../wifi/wifi_component_esp_idf.cpp | 48 ++++++++++++++++--- tests/components/wifi/common-eap.yaml | 7 +++ tests/components/wifi/test-eap.esp32-ard.yaml | 8 +--- tests/components/wifi/test-eap.esp32-idf.yaml | 1 + 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 tests/components/wifi/common-eap.yaml create mode 100644 tests/components/wifi/test-eap.esp32-idf.yaml diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 0b077819ae..d79cde0b18 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -20,8 +20,12 @@ #endif #if defined(USE_ESP_IDF) && defined(USE_WIFI_WPA2_EAP) +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) +#include +#else #include #endif +#endif #ifdef USE_ESP8266 #include diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 96fa837767..a8d67ed44d 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -15,8 +15,12 @@ #include #include #ifdef USE_WIFI_WPA2_EAP +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) +#include +#else #include #endif +#endif #ifdef USE_WIFI_AP #include "dhcpserver/dhcpserver.h" @@ -364,48 +368,78 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { if (ap.get_eap().has_value()) { // note: all certificates and keys have to be null terminated. Lengths are appended by +1 to include \0. EAPAuth eap = ap.get_eap().value(); +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length()); +#else err = esp_wifi_sta_wpa2_ent_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length()); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_identity failed! %d", err); + ESP_LOGV(TAG, "set_identity failed %d", err); } int ca_cert_len = strlen(eap.ca_cert); int client_cert_len = strlen(eap.client_cert); int client_key_len = strlen(eap.client_key); if (ca_cert_len) { +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1); +#else err = esp_wifi_sta_wpa2_ent_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_ca_cert failed! %d", err); + ESP_LOGV(TAG, "set_ca_cert failed %d", err); } } // workout what type of EAP this is // validation is not required as the config tool has already validated it if (client_cert_len && client_key_len) { // if we have certs, this must be EAP-TLS +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_certificate_and_key((uint8_t *) eap.client_cert, client_cert_len + 1, + (uint8_t *) eap.client_key, client_key_len + 1, + (uint8_t *) eap.password.c_str(), strlen(eap.password.c_str())); +#else err = esp_wifi_sta_wpa2_ent_set_cert_key((uint8_t *) eap.client_cert, client_cert_len + 1, (uint8_t *) eap.client_key, client_key_len + 1, (uint8_t *) eap.password.c_str(), strlen(eap.password.c_str())); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_cert_key failed! %d", err); + ESP_LOGV(TAG, "set_cert_key failed %d", err); } } else { // in the absence of certs, assume this is username/password based +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_username((uint8_t *) eap.username.c_str(), eap.username.length()); +#else err = esp_wifi_sta_wpa2_ent_set_username((uint8_t *) eap.username.c_str(), eap.username.length()); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_username failed! %d", err); + ESP_LOGV(TAG, "set_username failed %d", err); } +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_password((uint8_t *) eap.password.c_str(), eap.password.length()); +#else err = esp_wifi_sta_wpa2_ent_set_password((uint8_t *) eap.password.c_str(), eap.password.length()); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_password failed! %d", err); + ESP_LOGV(TAG, "set_password failed %d", err); } // set TTLS Phase 2, defaults to MSCHAPV2 +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_eap_client_set_ttls_phase2_method(eap.ttls_phase_2); +#else err = esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(eap.ttls_phase_2); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_ttls_phase2_method failed! %d", err); + ESP_LOGV(TAG, "set_ttls_phase2_method failed %d", err); } } +#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1) + err = esp_wifi_sta_enterprise_enable(); +#else err = esp_wifi_sta_wpa2_ent_enable(); +#endif if (err != ESP_OK) { - ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_enable failed! %d", err); + ESP_LOGV(TAG, "enterprise_enable failed %d", err); } } #endif // USE_WIFI_WPA2_EAP diff --git a/tests/components/wifi/common-eap.yaml b/tests/components/wifi/common-eap.yaml new file mode 100644 index 0000000000..779cd6b49a --- /dev/null +++ b/tests/components/wifi/common-eap.yaml @@ -0,0 +1,7 @@ +wifi: + networks: + - ssid: MySSID + eap: + username: username + password: password + identity: identity diff --git a/tests/components/wifi/test-eap.esp32-ard.yaml b/tests/components/wifi/test-eap.esp32-ard.yaml index 779cd6b49a..9177e5de10 100644 --- a/tests/components/wifi/test-eap.esp32-ard.yaml +++ b/tests/components/wifi/test-eap.esp32-ard.yaml @@ -1,7 +1 @@ -wifi: - networks: - - ssid: MySSID - eap: - username: username - password: password - identity: identity +<<: !include common-eap.yaml diff --git a/tests/components/wifi/test-eap.esp32-idf.yaml b/tests/components/wifi/test-eap.esp32-idf.yaml new file mode 100644 index 0000000000..9177e5de10 --- /dev/null +++ b/tests/components/wifi/test-eap.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-eap.yaml From 5ac875545fe14fa1d818336efb392f48f61b3fc1 Mon Sep 17 00:00:00 2001 From: ttaborda <80131527+ttaborda@users.noreply.github.com> Date: Thu, 11 Jul 2024 05:26:37 +0100 Subject: [PATCH 2043/2607] Update mitsubishi.cpp (#6909) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mitsubishi/mitsubishi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index fd57adc586..a02aabf14d 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -52,6 +52,7 @@ const uint8_t MITSUBISHI_BYTE16 = 0X00; climate::ClimateTraits MitsubishiClimate::traits() { auto traits = climate::ClimateTraits(); + traits.set_supports_current_temperature(this->sensor_ != nullptr); traits.set_supports_action(false); traits.set_visual_min_temperature(MITSUBISHI_TEMP_MIN); traits.set_visual_max_temperature(MITSUBISHI_TEMP_MAX); From 66b36afe90431b89b8e7c26c782be2431f2e7890 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 11 Jul 2024 08:23:29 +0300 Subject: [PATCH 2044/2607] [climate] fix dump output of unsupported features (#7005) --- esphome/components/climate/climate.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 1822707152..bc8d932089 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -574,21 +574,25 @@ void Climate::dump_traits_(const char *tag) { ESP_LOGCONFIG(tag, " - Max temperature: %.1f", traits.get_visual_max_temperature()); ESP_LOGCONFIG(tag, " - Temperature step:"); ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step()); - ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step()); - ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity()); - ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity()); if (traits.get_supports_current_temperature()) { - ESP_LOGCONFIG(tag, " [x] Supports current temperature"); + ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step()); } - if (traits.get_supports_current_humidity()) { - ESP_LOGCONFIG(tag, " [x] Supports current humidity"); + if (traits.get_supports_target_humidity() || traits.get_supports_current_humidity()) { + ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity()); + ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity()); } if (traits.get_supports_two_point_target_temperature()) { ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature"); } + if (traits.get_supports_current_temperature()) { + ESP_LOGCONFIG(tag, " [x] Supports current temperature"); + } if (traits.get_supports_target_humidity()) { ESP_LOGCONFIG(tag, " [x] Supports target humidity"); } + if (traits.get_supports_current_humidity()) { + ESP_LOGCONFIG(tag, " [x] Supports current humidity"); + } if (traits.get_supports_action()) { ESP_LOGCONFIG(tag, " [x] Supports action"); } From d071b05249fc4d4310fda64ed8227896bb3f51d6 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 11 Jul 2024 08:24:36 +0300 Subject: [PATCH 2045/2607] [climate-traits] improved performance (#7006) --- esphome/components/climate/climate_traits.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/climate/climate_traits.h b/esphome/components/climate/climate_traits.h index fd5b025a03..58d7b586d7 100644 --- a/esphome/components/climate/climate_traits.h +++ b/esphome/components/climate/climate_traits.h @@ -73,7 +73,7 @@ class ClimateTraits { ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } - std::set get_supported_modes() const { return supported_modes_; } + const std::set &get_supported_modes() const { return supported_modes_; } void set_supports_action(bool supports_action) { supports_action_ = supports_action; } bool get_supports_action() const { return supports_action_; } @@ -101,7 +101,7 @@ class ClimateTraits { void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } - std::set get_supported_fan_modes() const { return supported_fan_modes_; } + const std::set &get_supported_fan_modes() const { return supported_fan_modes_; } void set_supported_custom_fan_modes(std::set supported_custom_fan_modes) { supported_custom_fan_modes_ = std::move(supported_custom_fan_modes); @@ -140,7 +140,7 @@ class ClimateTraits { } bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); } bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); } - std::set get_supported_swing_modes() const { return supported_swing_modes_; } + const std::set &get_supported_swing_modes() const { return supported_swing_modes_; } float get_visual_min_temperature() const { return visual_min_temperature_; } void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } From d209a2b45acff1e975d7ab68af5b75959624284e Mon Sep 17 00:00:00 2001 From: leejoow Date: Thu, 11 Jul 2024 22:20:58 +0200 Subject: [PATCH 2046/2607] Add default icon to restart button (#7076) Co-authored-by: Leo Schelvis --- esphome/components/restart/button/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/restart/button/__init__.py b/esphome/components/restart/button/__init__.py index 1b2c991261..6aff8cb351 100644 --- a/esphome/components/restart/button/__init__.py +++ b/esphome/components/restart/button/__init__.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_CONFIG, + ICON_RESTART, ) restart_ns = cg.esphome_ns.namespace("restart") @@ -12,6 +13,7 @@ RestartButton = restart_ns.class_("RestartButton", button.Button, cg.Component) CONFIG_SCHEMA = button.button_schema( RestartButton, + icon=ICON_RESTART, device_class=DEVICE_CLASS_RESTART, entity_category=ENTITY_CATEGORY_CONFIG, ).extend(cv.COMPONENT_SCHEMA) From 2e8a2fdbd4677b9075ae9bb572b4d66b8fc67794 Mon Sep 17 00:00:00 2001 From: Tomi Junnila Date: Thu, 11 Jul 2024 23:32:38 +0300 Subject: [PATCH 2047/2607] Add support for the Gree YAC1FB9 in climate_ir (#7056) --- esphome/components/gree/climate.py | 1 + esphome/components/gree/gree.cpp | 14 +++++++++++--- esphome/components/gree/gree.h | 6 +++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/esphome/components/gree/climate.py b/esphome/components/gree/climate.py index 02ce7b12d4..c88a428391 100644 --- a/esphome/components/gree/climate.py +++ b/esphome/components/gree/climate.py @@ -16,6 +16,7 @@ MODELS = { "yan": Model.GREE_YAN, "yaa": Model.GREE_YAA, "yac": Model.GREE_YAC, + "yac1fb9": Model.GREE_YAC1FB9, } CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( diff --git a/esphome/components/gree/gree.cpp b/esphome/components/gree/gree.cpp index 1bbb443fce..cce2a8ffee 100644 --- a/esphome/components/gree/gree.cpp +++ b/esphome/components/gree/gree.cpp @@ -24,7 +24,7 @@ void GreeClimate::transmit_state() { remote_state[4] |= (this->horizontal_swing_() << 4); } - if (this->model_ == GREE_YAA || this->model_ == GREE_YAC) { + if (this->model_ == GREE_YAA || this->model_ == GREE_YAC || this->model_ == GREE_YAC1FB9) { remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN remote_state[3] = 0x50; // bits 4..7 always 0101 remote_state[6] = 0x20; // YAA1FB, FAA1FB1, YB1F2 bits 4..7 always 0010 @@ -53,7 +53,11 @@ void GreeClimate::transmit_state() { data->set_carrier_frequency(GREE_IR_FREQUENCY); data->mark(GREE_HEADER_MARK); - data->space(GREE_HEADER_SPACE); + if (this->model_ == GREE_YAC1FB9) { + data->space(GREE_YAC1FB9_HEADER_SPACE); + } else { + data->space(GREE_HEADER_SPACE); + } for (int i = 0; i < 4; i++) { for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask @@ -71,7 +75,11 @@ void GreeClimate::transmit_state() { data->space(GREE_ZERO_SPACE); data->mark(GREE_BIT_MARK); - data->space(GREE_MESSAGE_SPACE); + if (this->model_ == GREE_YAC1FB9) { + data->space(GREE_YAC1FB9_MESSAGE_SPACE); + } else { + data->space(GREE_MESSAGE_SPACE); + } for (int i = 4; i < 8; i++) { for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask diff --git a/esphome/components/gree/gree.h b/esphome/components/gree/gree.h index e7131a2b89..524a95aebd 100644 --- a/esphome/components/gree/gree.h +++ b/esphome/components/gree/gree.h @@ -41,6 +41,10 @@ const uint32_t GREE_YAC_HEADER_MARK = 6000; const uint32_t GREE_YAC_HEADER_SPACE = 3000; const uint32_t GREE_YAC_BIT_MARK = 650; +// Timing specific to YAC1FB9 +const uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500; +const uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980; + // State Frame size const uint8_t GREE_STATE_FRAME_SIZE = 8; @@ -67,7 +71,7 @@ const uint8_t GREE_HDIR_MRIGHT = 0x05; const uint8_t GREE_HDIR_RIGHT = 0x06; // Model codes -enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC }; +enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9 }; class GreeClimate : public climate_ir::ClimateIR { public: From 99cba0ae7fa0e9897c7f0dfb764a329ba6d431f4 Mon Sep 17 00:00:00 2001 From: Eugen Date: Thu, 11 Jul 2024 23:26:04 +0200 Subject: [PATCH 2048/2607] add ESP32-C6 support to esp32_can (#7063) --- esphome/components/esp32_can/canbus.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/esp32_can/canbus.py b/esphome/components/esp32_can/canbus.py index 74f331f30b..f4ba032009 100644 --- a/esphome/components/esp32_can/canbus.py +++ b/esphome/components/esp32_can/canbus.py @@ -11,6 +11,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, VARIANT_ESP32C3, + VARIANT_ESP32C6, VARIANT_ESP32H2, ) @@ -47,6 +48,7 @@ CAN_SPEEDS_ESP32_S2 = { CAN_SPEEDS_ESP32_S3 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS_ESP32_C3 = {**CAN_SPEEDS_ESP32_S2} +CAN_SPEEDS_ESP32_C6 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS_ESP32_H2 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS = { @@ -54,6 +56,7 @@ CAN_SPEEDS = { VARIANT_ESP32S2: CAN_SPEEDS_ESP32_S2, VARIANT_ESP32S3: CAN_SPEEDS_ESP32_S3, VARIANT_ESP32C3: CAN_SPEEDS_ESP32_C3, + VARIANT_ESP32C6: CAN_SPEEDS_ESP32_C6, VARIANT_ESP32H2: CAN_SPEEDS_ESP32_H2, } From 7f83bcfdd91aba4fed05d0c1918c2899dac1682e Mon Sep 17 00:00:00 2001 From: soeffi Date: Thu, 11 Jul 2024 23:30:45 +0200 Subject: [PATCH 2049/2607] jsn_sr04t component: AJ_SR04M compatibility mode in checksum calculation (#7044) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/jsn_sr04t/jsn_sr04t.cpp | 19 ++++++++++++++++++- esphome/components/jsn_sr04t/jsn_sr04t.h | 8 +++++++- esphome/components/jsn_sr04t/sensor.py | 13 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/esphome/components/jsn_sr04t/jsn_sr04t.cpp b/esphome/components/jsn_sr04t/jsn_sr04t.cpp index b96bf8f762..077d4e58ea 100644 --- a/esphome/components/jsn_sr04t/jsn_sr04t.cpp +++ b/esphome/components/jsn_sr04t/jsn_sr04t.cpp @@ -31,7 +31,16 @@ void Jsnsr04tComponent::loop() { } void Jsnsr04tComponent::check_buffer_() { - uint8_t checksum = this->buffer_[0] + this->buffer_[1] + this->buffer_[2]; + uint8_t checksum = 0; + switch (this->model_) { + case JSN_SR04T: + checksum = this->buffer_[0] + this->buffer_[1] + this->buffer_[2]; + break; + case AJ_SR04M: + checksum = this->buffer_[1] + this->buffer_[2]; + break; + } + if (this->buffer_[3] == checksum) { uint16_t distance = encode_uint16(this->buffer_[1], this->buffer_[2]); if (distance > 250) { @@ -49,6 +58,14 @@ void Jsnsr04tComponent::check_buffer_() { void Jsnsr04tComponent::dump_config() { LOG_SENSOR("", "JST_SR04T Sensor", this); + switch (this->model_) { + case JSN_SR04T: + ESP_LOGCONFIG(TAG, " sensor model: jsn_sr04t"); + break; + case AJ_SR04M: + ESP_LOGCONFIG(TAG, " sensor model: aj_sr04m"); + break; + } LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/jsn_sr04t/jsn_sr04t.h b/esphome/components/jsn_sr04t/jsn_sr04t.h index bd43252be8..2a22ff92ec 100644 --- a/esphome/components/jsn_sr04t/jsn_sr04t.h +++ b/esphome/components/jsn_sr04t/jsn_sr04t.h @@ -9,9 +9,14 @@ namespace esphome { namespace jsn_sr04t { +enum Model { + JSN_SR04T, + AJ_SR04M, +}; + class Jsnsr04tComponent : public sensor::Sensor, public PollingComponent, public uart::UARTDevice { public: - // Nothing really public. + void set_model(Model model) { this->model_ = model; } // ========== INTERNAL METHODS ========== void update() override; @@ -20,6 +25,7 @@ class Jsnsr04tComponent : public sensor::Sensor, public PollingComponent, public protected: void check_buffer_(); + Model model_; std::vector buffer_; }; diff --git a/esphome/components/jsn_sr04t/sensor.py b/esphome/components/jsn_sr04t/sensor.py index 4b062e81e9..682cf06570 100644 --- a/esphome/components/jsn_sr04t/sensor.py +++ b/esphome/components/jsn_sr04t/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, + CONF_MODEL, ) CODEOWNERS = ["@Mafus1"] @@ -14,6 +15,11 @@ jsn_sr04t_ns = cg.esphome_ns.namespace("jsn_sr04t") Jsnsr04tComponent = jsn_sr04t_ns.class_( "Jsnsr04tComponent", sensor.Sensor, cg.PollingComponent, uart.UARTDevice ) +Model = jsn_sr04t_ns.enum("Model") +MODEL = { + "jsn_sr04t": Model.JSN_SR04T, + "aj_sr04m": Model.AJ_SR04M, +} CONFIG_SCHEMA = ( sensor.sensor_schema( @@ -25,6 +31,11 @@ CONFIG_SCHEMA = ( ) .extend(cv.polling_component_schema("60s")) .extend(uart.UART_DEVICE_SCHEMA) + .extend( + { + cv.Optional(CONF_MODEL, default="jsn_sr04t"): cv.enum(MODEL, upper=False), + } + ) ) FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( @@ -42,3 +53,5 @@ async def to_code(config): var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) + + cg.add(var.set_model(config[CONF_MODEL])) From 4a80a09db3c3a871f2825a2b7b7f1621ffab0f8b Mon Sep 17 00:00:00 2001 From: kevdliu <1766838+kevdliu@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:32:31 -0400 Subject: [PATCH 2050/2607] Fix voice assistant crash when no speaker configured (#7075) --- esphome/components/voice_assistant/voice_assistant.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 8a8a9e92aa..e4f388db68 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -684,7 +684,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->defer([this, text]() { this->tts_start_trigger_->trigger(text); #ifdef USE_SPEAKER - this->speaker_->start(); + if (this->speaker_ != nullptr) { + this->speaker_->start(); + } #endif }); break; From 8a3f0e3b93878a24a6cc9cdbe9babb846243c522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jul 2024 23:19:33 +0200 Subject: [PATCH 2051/2607] Bump HeatpumpIR, add protocols, remove IRremoteESP8266 (#6996) --- esphome/components/heatpumpir/climate.py | 11 ++++++----- esphome/components/heatpumpir/heatpumpir.cpp | 5 +++++ esphome/components/heatpumpir/heatpumpir.h | 5 +++++ platformio.ini | 6 +++--- .../heatpumpir/test.bk72xx-ard.yaml | 19 +++++++++++++++++++ 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 tests/components/heatpumpir/test.bk72xx-ard.yaml diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index b86d405b7e..80900d7db9 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -8,7 +8,6 @@ from esphome.const import ( CONF_PROTOCOL, CONF_VISUAL, ) -from esphome.core import CORE CODEOWNERS = ["@rob-deutsch"] @@ -67,6 +66,11 @@ PROTOCOLS = { "carrier_qlima_2": Protocol.PROTOCOL_QLIMA_2, "samsung_aqv12msan": Protocol.PROTOCOL_SAMSUNG_AQV12MSAN, "zhjg01": Protocol.PROTOCOL_ZHJG01, + "airway": Protocol.PROTOCOL_AIRWAY, + "bgh_aud": Protocol.PROTOCOL_BGH_AUD, + "panasonic_altdke": Protocol.PROTOCOL_PANASONIC_ALTDKE, + "vaillantvai8": Protocol.PROTOCOL_VAILLANTVAI8, + "r51m": Protocol.PROTOCOL_R51M, } CONF_HORIZONTAL_DEFAULT = "horizontal_default" @@ -122,7 +126,4 @@ def to_code(config): cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE])) cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) - cg.add_library("tonia/HeatpumpIR", "1.0.26") - - if CORE.is_esp8266 or CORE.is_esp32: - cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.6") + cg.add_library("tonia/HeatpumpIR", "1.0.27") diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index 22a5779c8d..144dcc9bfa 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -61,6 +61,11 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_QLIMA_2, []() { return new Qlima2HeatpumpIR(); }}, // NOLINT {PROTOCOL_SAMSUNG_AQV12MSAN, []() { return new SamsungAQV12MSANHeatpumpIR(); }}, // NOLINT {PROTOCOL_ZHJG01, []() { return new ZHJG01HeatpumpIR(); }}, // NOLINT + {PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT + {PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT + {PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT + {PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT + {PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT }; void HeatpumpIRClimate::setup() { diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index 0e6ea2218f..f6e7ff3cd6 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -61,6 +61,11 @@ enum Protocol { PROTOCOL_QLIMA_2, PROTOCOL_SAMSUNG_AQV12MSAN, PROTOCOL_ZHJG01, + PROTOCOL_AIRWAY, + PROTOCOL_BGH_AUD, + PROTOCOL_PANASONIC_ALTDKE, + PROTOCOL_VAILLANTVAI8, + PROTOCOL_R51M, }; // Simple enum to represent horizontal directios diff --git a/platformio.ini b/platformio.ini index f07889526f..fc7f35b6c3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -65,7 +65,7 @@ lib_deps = glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr dudanov/MideaUART@1.1.9 ; midea - tonia/HeatpumpIR@1.0.26 ; heatpumpir + tonia/HeatpumpIR@1.0.27 ; heatpumpir build_flags = ${common.build_flags} -DUSE_ARDUINO @@ -93,8 +93,8 @@ lib_deps = ESP8266HTTPClient ; http_request (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) - crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.2 ; wireguard + build_flags = ${common:arduino.build_flags} -Wno-nonnull-compare @@ -123,8 +123,8 @@ lib_deps = ESPmDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio - crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.2 ; wireguard + build_flags = ${common:arduino.build_flags} -DUSE_ESP32 diff --git a/tests/components/heatpumpir/test.bk72xx-ard.yaml b/tests/components/heatpumpir/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..90259f1244 --- /dev/null +++ b/tests/components/heatpumpir/test.bk72xx-ard.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 6 + carrier_duty_percent: 50% + +climate: + - platform: heatpumpir + protocol: daikin + horizontal_default: mleft + vertical_default: mup + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 + - platform: heatpumpir + protocol: panasonic_altdke + horizontal_default: mright + vertical_default: mdown + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 From feae794787ca3ad0cc1b20be9496a73117e6844f Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Fri, 12 Jul 2024 21:42:41 +0000 Subject: [PATCH 2052/2607] LTR390 separate ALS and UV gain and resolution (#7026) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 +- esphome/components/ltr390/ltr390.cpp | 73 +++++++++++-------- esphome/components/ltr390/ltr390.h | 14 ++-- esphome/components/ltr390/sensor.py | 40 ++++++++-- tests/components/ltr390/test.esp32-ard.yaml | 18 +++++ tests/components/ltr390/test.esp8266-ard.yaml | 4 +- 6 files changed, 110 insertions(+), 41 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 5c14d30371..210c567f78 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -214,7 +214,7 @@ esphome/components/lightwaverf/* @max246 esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core -esphome/components/ltr390/* @sjtrny +esphome/components/ltr390/* @latonita @sjtrny esphome/components/ltr_als_ps/* @latonita esphome/components/matrix_keypad/* @ssieb esphome/components/max31865/* @DAVe3283 diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 4eb1ff2c46..198d15ebd8 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -19,6 +19,7 @@ static const uint8_t LTR390_MAIN_STATUS = 0x07; static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0}; static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125}; +static const uint8_t RESOLUTION_BITS[6] = {20, 19, 18, 17, 16, 13}; // Request fastest measurement rate - will be slowed by device if conversion rate is slower. static const float RESOLUTION_SETTING[6] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50}; @@ -74,7 +75,7 @@ void LTR390Component::read_als_() { uint32_t als = *val; if (this->light_sensor_ != nullptr) { - float lux = ((0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_])) * this->wfac_; + float lux = ((0.6 * als) / (GAINVALUES[this->gain_als_] * RESOLUTIONVALUE[this->res_als_])) * this->wfac_; this->light_sensor_->publish_state(lux); } @@ -90,7 +91,7 @@ void LTR390Component::read_uvs_() { uint32_t uv = *val; if (this->uvi_sensor_ != nullptr) { - this->uvi_sensor_->publish_state((uv / this->sensitivity_) * this->wfac_); + this->uvi_sensor_->publish_state((uv / this->sensitivity_uv_) * this->wfac_); } if (this->uv_sensor_ != nullptr) { @@ -107,24 +108,38 @@ void LTR390Component::read_mode_(int mode_index) { ctrl[LTR390_CTRL_EN] = true; this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); - // After the sensor integration time do the following - this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, - [this, mode_index]() { - // Read from the sensor - std::get<1>(this->mode_funcs_[mode_index])(); + uint32_t int_time{0}; + // Set gain, resolution and measurement rate + switch (mode) { + case LTR390_MODE_ALS: + this->reg(LTR390_GAIN) = this->gain_als_; + this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_als_]; + int_time = ((uint32_t) RESOLUTIONVALUE[this->res_als_]) * 100; + break; + case LTR390_MODE_UVS: + this->reg(LTR390_GAIN) = this->gain_uv_; + this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_uv_]; + int_time = ((uint32_t) RESOLUTIONVALUE[this->res_uv_]) * 100; + break; + } - // If there are more modes to read then begin the next - // otherwise stop - if (mode_index + 1 < (int) this->mode_funcs_.size()) { - this->read_mode_(mode_index + 1); - } else { - // put sensor in standby - std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); - ctrl[LTR390_CTRL_EN] = false; - this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); - this->reading_ = false; - } - }); + // After the sensor integration time do the following + this->set_timeout(int_time + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, [this, mode_index]() { + // Read from the sensor + std::get<1>(this->mode_funcs_[mode_index])(); + + // If there are more modes to read then begin the next + // otherwise stop + if (mode_index + 1 < (int) this->mode_funcs_.size()) { + this->read_mode_(mode_index + 1); + } else { + // put sensor in standby + std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); + ctrl[LTR390_CTRL_EN] = false; + this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); + this->reading_ = false; + } + }); } void LTR390Component::setup() { @@ -151,16 +166,10 @@ void LTR390Component::setup() { return; } - // Set gain - this->reg(LTR390_GAIN) = gain_; - - // Set resolution and measurement rate - this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_]; - // Set sensitivity by linearly scaling against known value in the datasheet - float gain_scale = GAINVALUES[this->gain_] / GAIN_MAX; - float intg_scale = (RESOLUTIONVALUE[this->res_] * 100) / INTG_MAX; - this->sensitivity_ = SENSITIVITY_MAX * gain_scale * intg_scale; + float gain_scale_uv = GAINVALUES[this->gain_uv_] / GAIN_MAX; + float intg_scale_uv = (RESOLUTIONVALUE[this->res_uv_] * 100) / INTG_MAX; + this->sensitivity_uv_ = SENSITIVITY_MAX * gain_scale_uv * intg_scale_uv; // Set sensor read state this->reading_ = false; @@ -176,7 +185,13 @@ void LTR390Component::setup() { } } -void LTR390Component::dump_config() { LOG_I2C_DEVICE(this); } +void LTR390Component::dump_config() { + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " ALS Gain: X%.0f", GAINVALUES[this->gain_als_]); + ESP_LOGCONFIG(TAG, " ALS Resolution: %u-bit", RESOLUTION_BITS[this->res_als_]); + ESP_LOGCONFIG(TAG, " UV Gain: X%.0f", GAINVALUES[this->gain_uv_]); + ESP_LOGCONFIG(TAG, " UV Resolution: %u-bit", RESOLUTION_BITS[this->res_uv_]); +} void LTR390Component::update() { if (!this->reading_ && !mode_funcs_.empty()) { diff --git a/esphome/components/ltr390/ltr390.h b/esphome/components/ltr390/ltr390.h index bc98518fe9..24afd3c411 100644 --- a/esphome/components/ltr390/ltr390.h +++ b/esphome/components/ltr390/ltr390.h @@ -49,8 +49,10 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice { void dump_config() override; void update() override; - void set_gain_value(LTR390GAIN gain) { this->gain_ = gain; } - void set_res_value(LTR390RESOLUTION res) { this->res_ = res; } + void set_als_gain_value(LTR390GAIN gain) { this->gain_als_ = gain; } + void set_uv_gain_value(LTR390GAIN gain) { this->gain_uv_ = gain; } + void set_als_res_value(LTR390RESOLUTION res) { this->res_als_ = res; } + void set_uv_res_value(LTR390RESOLUTION res) { this->res_uv_ = res; } void set_wfac_value(float wfac) { this->wfac_ = wfac; } void set_light_sensor(sensor::Sensor *light_sensor) { this->light_sensor_ = light_sensor; } @@ -71,9 +73,11 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice { // a list of modes and corresponding read functions std::vector>> mode_funcs_; - LTR390GAIN gain_; - LTR390RESOLUTION res_; - float sensitivity_; + LTR390GAIN gain_als_; + LTR390GAIN gain_uv_; + LTR390RESOLUTION res_als_; + LTR390RESOLUTION res_uv_; + float sensitivity_uv_; float wfac_; sensor::Sensor *light_sensor_{nullptr}; diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py index 8b2676599c..62c3edf8cb 100644 --- a/esphome/components/ltr390/sensor.py +++ b/esphome/components/ltr390/sensor.py @@ -13,7 +13,7 @@ from esphome.const import ( UNIT_LUX, ) -CODEOWNERS = ["@sjtrny"] +CODEOWNERS = ["@sjtrny", "@latonita"] DEPENDENCIES = ["i2c"] ltr390_ns = cg.esphome_ns.namespace("ltr390") @@ -76,8 +76,24 @@ CONFIG_SCHEMA = cv.All( accuracy_decimals=1, device_class=DEVICE_CLASS_EMPTY, ), - cv.Optional(CONF_GAIN, default="X18"): cv.enum(GAIN_OPTIONS), - cv.Optional(CONF_RESOLUTION, default=20): cv.enum(RES_OPTIONS), + cv.Optional(CONF_GAIN, default="X18"): cv.Any( + cv.enum(GAIN_OPTIONS), + cv.Schema( + { + cv.Required(CONF_AMBIENT_LIGHT): cv.enum(GAIN_OPTIONS), + cv.Required(CONF_UV): cv.enum(GAIN_OPTIONS), + } + ), + ), + cv.Optional(CONF_RESOLUTION, default=20): cv.Any( + cv.enum(RES_OPTIONS), + cv.Schema( + { + cv.Required(CONF_AMBIENT_LIGHT): cv.enum(RES_OPTIONS), + cv.Required(CONF_UV): cv.enum(RES_OPTIONS), + } + ), + ), cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range( min=1.0 ), @@ -101,11 +117,25 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - cg.add(var.set_gain_value(config[CONF_GAIN])) - cg.add(var.set_res_value(config[CONF_RESOLUTION])) cg.add(var.set_wfac_value(config[CONF_WINDOW_CORRECTION_FACTOR])) for key, funcName in TYPES.items(): if key in config: sens = await sensor.new_sensor(config[key]) cg.add(getattr(var, funcName)(sens)) + + gain_value = config[CONF_GAIN] + if isinstance(gain_value, dict): + cg.add(var.set_als_gain_value(gain_value[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_gain_value(gain_value[CONF_UV])) + else: + cg.add(var.set_als_gain_value(gain_value)) + cg.add(var.set_uv_gain_value(gain_value)) + + res_value = config[CONF_RESOLUTION] + if isinstance(res_value, dict): + cg.add(var.set_als_res_value(res_value[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_res_value(res_value[CONF_UV])) + else: + cg.add(var.set_als_res_value(res_value)) + cg.add(var.set_uv_res_value(res_value)) diff --git a/tests/components/ltr390/test.esp32-ard.yaml b/tests/components/ltr390/test.esp32-ard.yaml index 9786c7dac3..bdfe349b77 100644 --- a/tests/components/ltr390/test.esp32-ard.yaml +++ b/tests/components/ltr390/test.esp32-ard.yaml @@ -18,3 +18,21 @@ sensor: window_correction_factor: 1.0 address: 0x53 update_interval: 60s + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: + ambient_light: X9 + uv: X3 + resolution: + ambient_light: 18 + uv: 13 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp8266-ard.yaml b/tests/components/ltr390/test.esp8266-ard.yaml index fee0f37ce1..149f46f9c8 100644 --- a/tests/components/ltr390/test.esp8266-ard.yaml +++ b/tests/components/ltr390/test.esp8266-ard.yaml @@ -13,7 +13,9 @@ sensor: name: LTR390 Light ambient_light: name: LTR390 ALS - gain: X3 + gain: + ambient_light: X9 + uv: X3 resolution: 18 window_correction_factor: 1.0 address: 0x53 From d1bfad98906433899d529875f9b0613d5fc6c9c0 Mon Sep 17 00:00:00 2001 From: Christian Ferbar <5595808+ferbar@users.noreply.github.com> Date: Thu, 11 Jul 2024 05:58:54 +0200 Subject: [PATCH 2053/2607] helpers.cpp: Fix GLIBCXX_RELEASE check < 8 (#7062) --- esphome/core/helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 7f040f855f..e75b06ccd3 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -78,7 +78,7 @@ static const uint16_t CRC16_1021_BE_LUT_H[] = {0x0000, 0x1231, 0x2462, 0x3653, 0 // STL backports -#if _GLIBCXX_RELEASE < 7 +#if _GLIBCXX_RELEASE < 8 std::string to_string(int value) { return str_snprintf("%d", 32, value); } // NOLINT std::string to_string(long value) { return str_snprintf("%ld", 32, value); } // NOLINT std::string to_string(long long value) { return str_snprintf("%lld", 32, value); } // NOLINT From 114476d8b15f173aac926ec653c69fccc2dccdc7 Mon Sep 17 00:00:00 2001 From: Z3LIFF Date: Thu, 11 Jul 2024 00:01:14 -0400 Subject: [PATCH 2054/2607] Fix pmsa003i cold boot marked as failed on ESP32 et al (#7064) --- esphome/components/pmsa003i/pmsa003i.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/esphome/components/pmsa003i/pmsa003i.cpp b/esphome/components/pmsa003i/pmsa003i.cpp index ca3d28367a..a9665c6a5a 100644 --- a/esphome/components/pmsa003i/pmsa003i.cpp +++ b/esphome/components/pmsa003i/pmsa003i.cpp @@ -13,6 +13,15 @@ void PMSA003IComponent::setup() { PM25AQIData data; bool successful_read = this->read_data_(&data); + if (!successful_read) { + for (int i = 0; i < 3; i++) { + successful_read = this->read_data_(&data); + if (successful_read) { + break; + } + } + } + if (!successful_read) { this->mark_failed(); return; From 8d28c53fd3e72120fcc8bd13759e67ee4892e91f Mon Sep 17 00:00:00 2001 From: guillempages Date: Thu, 11 Jul 2024 06:08:51 +0200 Subject: [PATCH 2055/2607] [http_request] Fix follow_redirects on arduino (#7054) --- esphome/components/http_request/http_request_arduino.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index 248a85a439..95b1cdc38e 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -32,6 +32,13 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s watchdog::WatchdogManager wdm(this->get_watchdog_timeout()); + if (this->follow_redirects_) { + container->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); + container->client_.setRedirectLimit(this->redirect_limit_); + } else { + container->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS); + } + #if defined(USE_ESP8266) std::unique_ptr stream_ptr; #ifdef USE_HTTP_REQUEST_ESP8266_HTTPS @@ -59,8 +66,6 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s "in your YAML, or use HTTPS"); } #endif // USE_ARDUINO_VERSION_CODE - - container->client_.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); bool status = container->client_.begin(*stream_ptr, url.c_str()); #elif defined(USE_RP2040) From 8a89dac5d541f631e491832965f00a4549eb0210 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Thu, 11 Jul 2024 06:09:51 +0200 Subject: [PATCH 2056/2607] [ethernet] Fix compile warning for IPv6 (#7048) --- esphome/components/ethernet/ethernet_component.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 6b34157b9d..962a864a29 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -394,7 +394,7 @@ void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_b const esp_netif_ip_info_t *ip_info = &event->ip_info; ESP_LOGV(TAG, "[Ethernet event] ETH Got IP " IPSTR, IP2STR(&ip_info->ip)); global_eth_component->got_ipv4_address_ = true; -#if USE_NETWORK_IPV6 +#if USE_NETWORK_IPV6 && (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0) global_eth_component->connected_ = global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT; #else global_eth_component->connected_ = true; @@ -407,8 +407,12 @@ void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_ ip_event_got_ip6_t *event = (ip_event_got_ip6_t *) event_data; ESP_LOGV(TAG, "[Ethernet event] ETH Got IPv6: " IPV6STR, IPV62STR(event->ip6_info.ip)); global_eth_component->ipv6_count_ += 1; +#if (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0) global_eth_component->connected_ = global_eth_component->got_ipv4_address_ && (global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT); +#else + global_eth_component->connected_ = global_eth_component->got_ipv4_address_; +#endif } #endif /* USE_NETWORK_IPV6 */ From bdd0a36aa3ada035ead9eff3a1bc29d2993e4cb5 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Thu, 11 Jul 2024 16:10:18 +1200 Subject: [PATCH 2057/2607] Update webserver local assets to 20240704-081526 (#7041) --- .../components/web_server/server_index_v2.h | 83 +- .../components/web_server/server_index_v3.h | 735 +++++++++--------- 2 files changed, 410 insertions(+), 408 deletions(-) diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index c942cda592..c9932624ba 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -68,7 +68,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe3, 0x9b, 0x82, 0xde, 0xc5, 0x0e, 0x21, 0xa9, 0x64, 0x54, 0x44, 0x2c, 0x97, 0x29, 0x21, 0x29, 0xc2, 0x3f, 0x90, 0x45, 0x68, 0xd6, 0x13, 0xec, 0x34, 0x30, 0x9c, 0xcb, 0x40, 0x71, 0x17, 0x3c, 0xe0, 0xc9, 0x9c, 0xa6, 0x82, 0xa6, 0xc1, 0x5f, 0x71, 0x4a, 0x87, 0x31, 0x40, 0xb1, 0xd3, 0xc4, 0xe3, 0x30, 0x3b, 0x1f, 0x87, 0xc9, 0x88, 0x46, 0xc1, - 0x8d, 0xc8, 0xf1, 0xdf, 0x89, 0x3b, 0x64, 0x49, 0x18, 0xb3, 0x5f, 0x69, 0xe4, 0x6a, 0x69, 0x70, 0xeb, 0xd0, 0x5b, + 0x8d, 0xc8, 0xf1, 0xdf, 0x89, 0x3b, 0x64, 0x49, 0x18, 0xb3, 0x5f, 0x69, 0xe4, 0x6a, 0x69, 0x70, 0xe6, 0xd0, 0x5b, 0x41, 0x93, 0x28, 0x73, 0x9e, 0xbf, 0x7b, 0xf9, 0x42, 0xef, 0x63, 0x45, 0x40, 0xa0, 0x45, 0x36, 0x9b, 0xd2, 0xd4, 0x43, 0x58, 0x0b, 0x88, 0x67, 0x4c, 0x32, 0xc7, 0x97, 0xe1, 0x54, 0x95, 0xb0, 0xec, 0xfd, 0x34, 0x0a, 0x05, 0x7d, 0x43, 0x93, 0x88, 0x25, 0x23, 0xb2, 0xd3, 0x54, 0xe5, 0xe3, 0x50, 0x57, 0x44, 0x45, 0xd1, 0xe5, 0xee, 0xb3, 0x58, @@ -150,19 +150,19 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xa6, 0x57, 0xfd, 0xcf, 0xf9, 0x64, 0x0a, 0xda, 0xd8, 0x0a, 0x49, 0x8f, 0xa8, 0x9e, 0xb0, 0xac, 0xcf, 0x37, 0x94, 0x55, 0xfa, 0xc8, 0xf3, 0x58, 0xa1, 0xa6, 0xc2, 0x5e, 0xde, 0x69, 0xe4, 0xb3, 0xa2, 0xa8, 0x60, 0x1c, 0x9b, 0x9c, 0x2a, 0xe7, 0xab, 0x2e, 0x19, 0x53, 0xf1, 0xda, 0x63, 0x8a, 0x0f, 0x33, 0xe0, 0x75, 0x16, 0xfb, 0x31, 0xe4, 0x6e, - 0xef, 0x7f, 0x5e, 0x22, 0x67, 0x91, 0xaf, 0xa0, 0x6f, 0x91, 0xe7, 0xb7, 0xca, 0xc8, 0xc6, 0xb7, 0xdb, 0xad, 0xe1, - 0xb2, 0x4e, 0x1b, 0x8b, 0xbd, 0x3e, 0xbe, 0x5d, 0x57, 0x1d, 0xc9, 0x62, 0xc2, 0x23, 0x1a, 0xb8, 0x7c, 0x4a, 0x13, - 0x37, 0x07, 0xaf, 0xaa, 0xde, 0xfb, 0x81, 0xf0, 0x16, 0x6f, 0xab, 0xee, 0xd5, 0xe0, 0x36, 0x07, 0xef, 0xd7, 0xd7, + 0xef, 0x7f, 0x5e, 0x22, 0x67, 0x91, 0xaf, 0xa0, 0x6f, 0x91, 0xe7, 0x67, 0xca, 0xc8, 0xc6, 0x67, 0xdb, 0xad, 0xe1, + 0xb2, 0x4e, 0x1b, 0x8b, 0xbd, 0x3e, 0x3e, 0x5b, 0x57, 0x1d, 0xc9, 0x62, 0xc2, 0x23, 0x1a, 0xb8, 0x7c, 0x4a, 0x13, + 0x37, 0x07, 0xaf, 0xaa, 0xde, 0xfb, 0x81, 0xf0, 0x16, 0x6f, 0xab, 0xee, 0xd5, 0xe0, 0x2c, 0x07, 0xef, 0xd7, 0xd7, 0xeb, 0x8e, 0xd7, 0xef, 0x69, 0x9a, 0x49, 0x45, 0xb4, 0xd0, 0x69, 0xbf, 0x2e, 0xc5, 0xd2, 0xd7, 0xc1, 0xd6, 0xf6, 0xa5, 0x09, 0xe2, 0x36, 0xfd, 0x63, 0xff, 0xc0, 0x45, 0xd2, 0x2d, 0xfc, 0x93, 0x3e, 0xf0, 0x1f, 0x8c, 0x5b, 0xf8, 0x19, 0xf9, 0x50, 0xf5, 0x0a, 0x47, 0x82, 0x3c, 0xeb, 0x3e, 0x33, 0x16, 0x33, 0x8f, 0xd9, 0xe0, 0xce, 0x73, 0x63, 0x26, 0xea, 0x10, 0x7a, 0x73, 0xf1, 0x42, 0x55, 0x80, 0x4b, 0x51, 0xba, 0xb3, 0x73, 0x63, 0xeb, 0x61, 0x21, 0x88, 0xbb, 0x1b, 0x33, 0xb1, 0xeb, 0xe2, 0x09, 0xb9, 0x82, 0x1f, 0xbb, 0x0b, 0xef, 0x65, 0x28, 0xc6, 0x7e, 0x1a, 0x26, - 0x11, 0x9f, 0x78, 0xa8, 0xe6, 0xba, 0xc8, 0xcf, 0xa4, 0xbd, 0xf1, 0x18, 0xe5, 0xbb, 0x57, 0xf8, 0x4c, 0x10, 0xb7, - 0xeb, 0xd6, 0x26, 0xf8, 0x95, 0x20, 0x57, 0xa7, 0xbb, 0x8b, 0x33, 0x91, 0x77, 0xae, 0xf0, 0x59, 0xe1, 0xb1, 0xc7, - 0x6f, 0x88, 0x87, 0x48, 0xe7, 0x4c, 0x43, 0x73, 0xce, 0x27, 0xca, 0x73, 0xef, 0x22, 0xfc, 0x1e, 0xe2, 0x2a, 0x69, - 0xc9, 0x6d, 0x74, 0x68, 0x65, 0x87, 0xb8, 0x5c, 0xba, 0x08, 0xdc, 0xbd, 0x3d, 0xab, 0xac, 0x50, 0x15, 0xf0, 0xad, - 0x20, 0x15, 0x83, 0x1c, 0xbf, 0x95, 0x11, 0x9a, 0x5b, 0xe1, 0xa5, 0xc8, 0x0c, 0xe3, 0x19, 0x3f, 0xb4, 0x3e, 0x9a, + 0x11, 0x9f, 0x78, 0xa8, 0xe6, 0xba, 0xc8, 0xcf, 0xa4, 0xbd, 0xf1, 0x18, 0xe5, 0xbb, 0x57, 0xf8, 0x56, 0x10, 0xb7, + 0xeb, 0xd6, 0x26, 0xf8, 0x95, 0x20, 0x57, 0xa7, 0xbb, 0x8b, 0x5b, 0x91, 0x77, 0xae, 0xf0, 0x6d, 0xe1, 0xb1, 0xc7, + 0x6f, 0x88, 0x87, 0x48, 0xe7, 0x56, 0x43, 0x73, 0xce, 0x27, 0xca, 0x73, 0xef, 0x22, 0xfc, 0x1e, 0xe2, 0x2a, 0x69, + 0xc9, 0x6d, 0x74, 0x68, 0x65, 0x87, 0xb8, 0x5c, 0xba, 0x08, 0xdc, 0xbd, 0x3d, 0xab, 0xac, 0x50, 0x15, 0xf0, 0x99, + 0x20, 0x15, 0x83, 0x1c, 0xbf, 0x95, 0x11, 0x9a, 0x33, 0xe1, 0xa5, 0xc8, 0x0c, 0xe3, 0x19, 0x3f, 0xb4, 0x3e, 0x9a, 0x69, 0x4f, 0x79, 0x18, 0x7c, 0x26, 0x68, 0x1a, 0x0a, 0x9e, 0xf6, 0x91, 0xad, 0x7e, 0xe0, 0xbf, 0x91, 0xab, 0x9e, 0xf3, 0x9f, 0xbe, 0xf8, 0x79, 0xf8, 0x73, 0xda, 0xbf, 0xc2, 0xaf, 0xc9, 0xfe, 0xa9, 0xd7, 0x0d, 0xbc, 0x9d, 0x7a, 0x7d, 0xf9, 0xf3, 0x7e, 0xef, 0x1f, 0x61, 0xfd, 0xd7, 0xb3, 0xfa, 0x4f, 0x7d, 0xb4, 0xf4, 0x7e, 0xde, 0xef, 0xf6, @@ -177,7 +177,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xf2, 0x03, 0x64, 0x81, 0xc0, 0xf3, 0x30, 0x9e, 0xd1, 0x2c, 0xa0, 0x39, 0xc2, 0x03, 0x72, 0x21, 0xbc, 0x26, 0xc2, 0xcf, 0x05, 0xfc, 0x68, 0x21, 0x7c, 0xa1, 0x03, 0x98, 0x70, 0x90, 0x15, 0x51, 0x25, 0x5c, 0x69, 0x2c, 0x2e, 0xc2, 0xd3, 0x0d, 0x95, 0x62, 0x0c, 0xde, 0x05, 0x84, 0x87, 0x95, 0x70, 0x27, 0xbe, 0x21, 0x86, 0x24, 0xde, 0xa5, 0x94, - 0xfe, 0x10, 0xc6, 0x1f, 0x69, 0xea, 0x9d, 0xe1, 0x66, 0xeb, 0x31, 0x96, 0x2e, 0xe8, 0x9d, 0x26, 0x6a, 0x17, 0xb1, + 0xfe, 0x10, 0xc6, 0x1f, 0x69, 0xea, 0xdd, 0xe2, 0x66, 0xeb, 0x31, 0x96, 0x2e, 0xe8, 0x9d, 0x26, 0x6a, 0x17, 0xb1, 0xaa, 0x73, 0xa1, 0x62, 0x04, 0x20, 0x64, 0xab, 0xbe, 0x18, 0xd8, 0xf1, 0x9d, 0x74, 0xcd, 0x61, 0x95, 0x86, 0x37, 0x2e, 0xaa, 0xc6, 0x45, 0x59, 0x32, 0x0f, 0x63, 0x16, 0x39, 0x82, 0x4e, 0xa6, 0x71, 0x28, 0xa8, 0xa3, 0xd7, 0xeb, 0x84, 0x30, 0x90, 0x5b, 0xa8, 0x0c, 0x91, 0x65, 0x70, 0x46, 0x26, 0xe0, 0x04, 0x67, 0xc5, 0x83, 0xe8, 0x94, 0x56, @@ -220,10 +220,10 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x73, 0xd4, 0x69, 0xa0, 0x45, 0xa5, 0xad, 0xd4, 0x99, 0xaa, 0x71, 0xf4, 0x82, 0x4f, 0xcf, 0x49, 0xa3, 0x3d, 0x3f, 0x1d, 0xb5, 0xe7, 0xb5, 0x1a, 0xca, 0x0c, 0x69, 0xcd, 0x7a, 0xf3, 0x3e, 0x7e, 0x03, 0x4e, 0x3d, 0x9b, 0x96, 0x70, 0x65, 0x79, 0x2d, 0xbd, 0xbc, 0x5a, 0x2d, 0xc9, 0x51, 0xdb, 0xea, 0x3a, 0x52, 0x5d, 0xf3, 0x5c, 0xe1, 0x64, 0x95, - 0xd4, 0x4e, 0x90, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0x99, 0x40, 0x1b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, + 0xd4, 0x4e, 0x90, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0xad, 0x40, 0x1b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, 0xc0, 0x3e, 0x95, 0x94, 0xf0, 0x00, 0x0b, 0xd0, 0xb5, 0xf0, 0x04, 0x4f, 0xf0, 0xac, 0xd6, 0x94, 0x64, 0x5e, 0x6f, 0xb6, 0xab, 0x63, 0x3d, 0x2a, 0xc7, 0xc2, 0xb3, 0x1a, 0x99, 0x14, 0x58, 0xca, 0x93, 0x5a, 0x2d, 0xaf, 0x06, 0x3b, - 0xcd, 0xc9, 0xad, 0x04, 0x20, 0xce, 0x56, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, + 0xcd, 0xc9, 0xad, 0x04, 0x20, 0x6e, 0x57, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, 0xa4, 0x28, 0x11, 0x98, 0xe5, 0x79, 0x29, 0xd9, 0x41, 0x8c, 0x62, 0x4a, 0x52, 0xe0, 0x3c, 0xd2, 0xee, 0xc2, 0x09, 0xe6, 0x78, 0x2c, 0xf9, 0x06, 0x21, 0xe4, 0xc2, 0xa4, 0xb3, 0x08, 0xc9, 0x83, 0x62, 0xc2, 0x2c, 0x99, 0x94, 0x11, 0xea, 0x5f, 0xee, 0x9e, 0xf3, 0x7b, 0x6d, 0xb2, 0x1e, 0xeb, 0x07, 0xb2, 0x59, 0xac, 0x39, 0x57, 0x48, 0xde, 0x7b, @@ -238,14 +238,14 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x13, 0xf3, 0xec, 0xa5, 0x5f, 0xd6, 0xca, 0xc6, 0x97, 0xbb, 0x67, 0xef, 0x37, 0x35, 0x83, 0xf2, 0x7c, 0x56, 0xda, 0xf8, 0x12, 0xbe, 0x05, 0x8d, 0x83, 0x85, 0x16, 0x0e, 0x01, 0xcb, 0xb1, 0x14, 0x48, 0x41, 0x96, 0x17, 0xae, 0x91, 0xa7, 0x38, 0x21, 0x32, 0x0c, 0x54, 0xdd, 0x35, 0xad, 0xe6, 0x31, 0x9e, 0x5c, 0x0c, 0xf8, 0x94, 0x6e, 0x89, 0x0d, - 0x9d, 0x21, 0x9f, 0x4d, 0x20, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x4e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, + 0xdd, 0x22, 0x9f, 0x4d, 0x20, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x4e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, 0x2b, 0xb2, 0x05, 0x8f, 0x49, 0x03, 0xc7, 0xa4, 0x81, 0x43, 0x92, 0xf5, 0x1a, 0x4a, 0x40, 0xb4, 0xc3, 0x62, 0x5c, 0x25, 0x66, 0x20, 0x2b, 0x4c, 0x9f, 0x56, 0x25, 0x80, 0xa3, 0x76, 0x28, 0x7d, 0x8f, 0x52, 0xa6, 0x47, 0x92, 0x2c, 0xde, 0x7a, 0x1c, 0x73, 0x39, 0xf0, 0x05, 0xbb, 0x8e, 0x21, 0xb1, 0x04, 0x56, 0x85, 0x05, 0x0a, 0x8a, 0xa6, 0x4d, 0xdd, 0x34, 0xf4, 0xe5, 0x3e, 0x71, 0x1c, 0xfa, 0xc0, 0xb9, 0x71, 0xa8, 0xf3, 0x70, 0xb2, 0xf5, 0x2e, 0xc7, 0x7b, 0x7b, 0x9e, 0xea, 0xf4, 0x8b, 0xf0, 0xb8, 0xa9, 0x2f, 0x23, 0x77, 0xdf, 0x2b, 0x5e, 0x11, 0x21, 0x09, 0x7f, 0xad, 0x16, 0xf7, 0x73, 0x08, 0x43, 0x7b, 0x61, 0x15, 0x83, 0x06, 0x78, 0xa9, 0xeb, 0x55, 0x97, 0x5f, 0xab, 0x15, 0x51, - 0xda, 0x2a, 0xb6, 0xce, 0x70, 0x92, 0xcf, 0xbd, 0x22, 0xf5, 0xa7, 0xb1, 0x96, 0x2f, 0x65, 0x40, 0x40, 0xcc, 0xa6, + 0xda, 0x2a, 0xb6, 0x6e, 0x71, 0x92, 0xcf, 0xbd, 0x22, 0xf5, 0xa7, 0xb1, 0x96, 0x2f, 0x65, 0x40, 0x40, 0xcc, 0xa6, 0x59, 0x66, 0x16, 0x63, 0x1d, 0x09, 0x06, 0xed, 0xbe, 0xd1, 0x59, 0x0b, 0x58, 0x66, 0x57, 0xe9, 0x46, 0x86, 0x9d, 0xb5, 0x50, 0x60, 0x1a, 0x41, 0x54, 0x0a, 0x1a, 0xd5, 0x72, 0x4d, 0xde, 0x6f, 0xd7, 0x73, 0x2e, 0x71, 0x86, 0xb4, 0x93, 0x4b, 0x42, 0x21, 0x91, 0xd5, 0x2a, 0x90, 0xf2, 0x9c, 0x4c, 0xb7, 0x93, 0xfc, 0x99, 0x45, 0xf2, 0x4f, 0x08, @@ -268,7 +268,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x36, 0x44, 0x4d, 0xa5, 0xd4, 0x91, 0x2d, 0x50, 0xd1, 0xc1, 0x9f, 0x7b, 0x4c, 0x2b, 0x6e, 0x26, 0x6e, 0x06, 0x0c, 0xf8, 0x89, 0xf0, 0x54, 0x30, 0x0a, 0x64, 0x06, 0xf7, 0x67, 0x5e, 0x65, 0xea, 0x36, 0x97, 0xdd, 0xb0, 0x46, 0xdc, 0xd8, 0x46, 0x13, 0x97, 0x71, 0xbd, 0xf3, 0x92, 0x97, 0x0e, 0x55, 0x06, 0xb5, 0x30, 0x5c, 0xb0, 0x4c, 0x24, 0xb1, - 0x96, 0x3f, 0x54, 0x49, 0xd1, 0x45, 0x23, 0x4c, 0x25, 0x18, 0xef, 0xe4, 0x1e, 0xd0, 0x1c, 0xfe, 0x2e, 0x6e, 0x85, + 0x96, 0x3f, 0x54, 0x49, 0xd1, 0x45, 0x23, 0x4c, 0x25, 0x18, 0xef, 0xe4, 0x1e, 0xd0, 0x1c, 0xfe, 0x2e, 0xce, 0x84, 0xb5, 0xa3, 0xc6, 0x89, 0x2d, 0xe7, 0xb4, 0xa4, 0xfe, 0x5b, 0x48, 0x75, 0x59, 0x3d, 0xf3, 0xcf, 0xa5, 0x2c, 0x64, 0x38, 0xab, 0x30, 0xf6, 0x44, 0x32, 0x76, 0x04, 0x7a, 0x9a, 0x49, 0xfc, 0xee, 0xea, 0x8c, 0x17, 0xa6, 0xa5, 0x9c, 0x26, 0xb1, 0x37, 0x45, 0xb4, 0xdc, 0xfa, 0xbd, 0xb2, 0x1b, 0x01, 0x23, 0x90, 0x05, 0x84, 0x35, 0x67, 0x4f, 0x10, @@ -312,7 +312,7 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xf1, 0xb5, 0x7b, 0x78, 0x63, 0x02, 0x1e, 0xb4, 0x87, 0x4d, 0x61, 0x19, 0xdb, 0x99, 0xba, 0x07, 0x64, 0x8f, 0x4f, 0xb8, 0xd1, 0xdd, 0xaa, 0x56, 0xc6, 0x1b, 0xb0, 0xff, 0x11, 0x1e, 0x9b, 0xcb, 0x71, 0x54, 0x73, 0x60, 0x1a, 0x2c, 0xf2, 0xc2, 0x29, 0xc0, 0x95, 0xf2, 0x96, 0x22, 0xcc, 0x73, 0x19, 0xe0, 0xfe, 0x16, 0x7f, 0xa7, 0x59, 0xe2, 0xb0, - 0xe0, 0x38, 0xb7, 0x0f, 0xe5, 0x88, 0x0a, 0xfc, 0x22, 0x7e, 0x0f, 0x74, 0x2c, 0x29, 0x34, 0x37, 0x54, 0xf4, 0x94, + 0xe0, 0x38, 0x67, 0x0f, 0xe5, 0x88, 0x0a, 0xfc, 0x22, 0x7e, 0x0f, 0x74, 0x2c, 0x29, 0x34, 0x37, 0x54, 0xf4, 0x94, 0xeb, 0x85, 0x6c, 0x4d, 0x4b, 0xc5, 0xb4, 0x48, 0xa9, 0x91, 0xd3, 0x6c, 0xc8, 0xe3, 0x34, 0x56, 0xb6, 0x28, 0x4e, 0x55, 0x65, 0x5e, 0xb4, 0x05, 0x8b, 0x65, 0x68, 0x71, 0xb9, 0xf4, 0xaa, 0xa8, 0x26, 0xcc, 0x8a, 0x64, 0x20, 0xcc, 0xac, 0x8c, 0x8a, 0x8a, 0x66, 0xad, 0xfa, 0x78, 0x68, 0x35, 0xa1, 0xc8, 0xe8, 0xe6, 0x15, 0x38, 0x6c, 0x17, 0x82, @@ -612,31 +612,32 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xde, 0x0b, 0x3e, 0xda, 0x3c, 0x56, 0xcc, 0x47, 0x5d, 0x79, 0x05, 0x42, 0xdd, 0xb5, 0x35, 0xca, 0x2f, 0x8f, 0xdd, 0xce, 0xa9, 0x56, 0x06, 0x1c, 0x19, 0x0e, 0x77, 0x8f, 0x1a, 0xe6, 0x56, 0x45, 0xcc, 0x47, 0x70, 0x20, 0x55, 0x17, 0x6b, 0x92, 0x8a, 0xc7, 0x7d, 0xdc, 0xec, 0x9c, 0x86, 0x8e, 0xe4, 0x2d, 0x92, 0x79, 0x64, 0xc1, 0x3e, 0x74, 0x1e, - 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xf5, 0x70, 0xca, 0x4a, 0xf7, 0x36, 0x28, 0x1d, 0xc5, 0x94, 0xbc, - 0x9c, 0x09, 0x7e, 0x86, 0x2b, 0x8b, 0x94, 0x2c, 0x3c, 0xd7, 0xbe, 0x73, 0xb0, 0x55, 0x80, 0x84, 0x5c, 0x47, 0x71, - 0x78, 0xe3, 0x63, 0xd7, 0xb2, 0x37, 0x77, 0x3b, 0xff, 0xfa, 0x3f, 0xfe, 0x97, 0x76, 0x9b, 0x9f, 0xee, 0x8f, 0x9b, - 0x66, 0xac, 0x15, 0x44, 0xe7, 0xa7, 0x70, 0x11, 0xb1, 0x8c, 0xf3, 0xd2, 0xdb, 0xfa, 0x28, 0x65, 0x51, 0x7d, 0x1c, - 0xc6, 0x43, 0xb7, 0xb3, 0x1d, 0x41, 0xf6, 0x0d, 0x24, 0x0d, 0x75, 0xb5, 0x08, 0x48, 0xf0, 0x37, 0xdd, 0xa1, 0x31, - 0x57, 0x31, 0xe4, 0x69, 0xb5, 0x6f, 0xd4, 0x94, 0x07, 0xaa, 0x72, 0xab, 0x26, 0xd5, 0x5f, 0xaf, 0xd2, 0x4c, 0x2d, - 0xad, 0x5c, 0xa6, 0xc9, 0x5d, 0xa7, 0x88, 0x53, 0xfd, 0xdf, 0xff, 0xf9, 0x5f, 0xfe, 0x9b, 0x79, 0x84, 0xf0, 0xd3, - 0xbf, 0xfe, 0xf7, 0xff, 0xfc, 0x7f, 0xfe, 0xf7, 0x7f, 0x85, 0x0b, 0x18, 0x3a, 0x44, 0x25, 0xf9, 0x84, 0x53, 0xc6, - 0xa7, 0x14, 0xc3, 0x70, 0x20, 0x47, 0x71, 0xc2, 0x32, 0xc1, 0x06, 0xd5, 0xeb, 0x35, 0x17, 0x72, 0x42, 0x79, 0xd8, - 0x34, 0x74, 0xf2, 0xd0, 0xe6, 0x25, 0x8d, 0x54, 0x50, 0x2e, 0x69, 0x31, 0x3f, 0xdd, 0x07, 0x7c, 0x3f, 0xec, 0x46, - 0xa2, 0x5f, 0x6c, 0xc7, 0xc2, 0x38, 0x65, 0xa1, 0x24, 0x2f, 0xcb, 0x1d, 0x08, 0x97, 0x2c, 0xe0, 0x31, 0x68, 0x59, - 0xc5, 0x72, 0xf7, 0x2a, 0x7d, 0xda, 0x1f, 0x66, 0x99, 0x60, 0x43, 0x40, 0xb9, 0x72, 0xfd, 0xca, 0xc8, 0x74, 0x1d, - 0xd4, 0xbf, 0xf8, 0x2e, 0x97, 0xa3, 0x28, 0xdb, 0xfa, 0xf0, 0xe4, 0x4f, 0xf9, 0x5f, 0x26, 0xa0, 0x64, 0x39, 0xde, - 0x24, 0xbc, 0xd5, 0x16, 0xf7, 0x71, 0xa3, 0x31, 0xbd, 0x45, 0x8b, 0x72, 0x06, 0xbc, 0x6d, 0x32, 0xe9, 0x2e, 0xb6, - 0x07, 0x94, 0x21, 0xed, 0xc2, 0x33, 0xdd, 0x70, 0xc0, 0xbd, 0xed, 0x34, 0xf2, 0xfc, 0xcf, 0x0b, 0xe9, 0x1c, 0x65, - 0xbf, 0x42, 0xe8, 0x59, 0xfb, 0x91, 0xaf, 0xb9, 0xbd, 0xb8, 0x85, 0xd5, 0xab, 0xa5, 0x7a, 0x8d, 0x9b, 0xeb, 0x17, - 0xed, 0xec, 0xd0, 0xb9, 0x1d, 0xf4, 0x3e, 0x84, 0x30, 0xf6, 0xb8, 0x89, 0xc7, 0xad, 0x45, 0x31, 0xbc, 0x10, 0x7c, - 0x62, 0xc7, 0xca, 0x69, 0x48, 0x07, 0x74, 0x68, 0xfc, 0xef, 0xba, 0x5e, 0xc5, 0xc1, 0xf3, 0xf1, 0xc1, 0x86, 0xb9, - 0x34, 0x48, 0x32, 0x46, 0xee, 0x34, 0xf2, 0x2f, 0xe1, 0x04, 0x2e, 0x86, 0x31, 0x0f, 0x45, 0x20, 0x09, 0xb6, 0x6d, - 0x47, 0xdc, 0x43, 0x60, 0x33, 0x7c, 0x61, 0xc1, 0xd3, 0x56, 0x4d, 0xc1, 0x13, 0x5e, 0xbd, 0x0e, 0x99, 0xfb, 0xb2, - 0xbb, 0x3d, 0x94, 0x72, 0xa4, 0x7d, 0xaf, 0x03, 0xd9, 0xaf, 0x2a, 0x1e, 0x28, 0x2d, 0x63, 0x5a, 0x68, 0x73, 0xbd, - 0x12, 0xd5, 0xaa, 0xf6, 0x27, 0xe1, 0xb9, 0x12, 0x4c, 0x77, 0xb5, 0x95, 0x2c, 0x84, 0x56, 0xaf, 0xc8, 0xf7, 0x85, - 0x15, 0x14, 0x4e, 0xa7, 0xb2, 0x21, 0x6a, 0x9f, 0xee, 0x2b, 0xe5, 0x15, 0xb8, 0x87, 0xcc, 0xd2, 0x50, 0x49, 0x11, - 0xba, 0x91, 0x3e, 0x0a, 0xea, 0x97, 0x4e, 0x97, 0x80, 0xcf, 0x9a, 0x75, 0xfe, 0x1f, 0xd6, 0xb2, 0x30, 0xa4, 0x67, - 0x88, 0x00, 0x00}; + 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xf5, 0x70, 0xca, 0x4a, 0xf7, 0x36, 0x28, 0x1d, 0xc5, 0x94, 0xdc, + 0x78, 0xc4, 0xf5, 0x9d, 0xa3, 0x56, 0xe9, 0x6e, 0x3b, 0x04, 0x9b, 0xc7, 0xb8, 0xe6, 0xa4, 0x4f, 0xce, 0x02, 0x8b, + 0x77, 0x4e, 0xf7, 0xc3, 0x15, 0x8c, 0x48, 0x7e, 0x9f, 0x6b, 0x47, 0x3b, 0x18, 0x36, 0x40, 0x6f, 0xae, 0xa3, 0xc4, + 0x81, 0x71, 0xc8, 0x6b, 0x41, 0x9d, 0xbb, 0x9d, 0x7f, 0xfd, 0x1f, 0xff, 0x4b, 0xfb, 0xd8, 0x4f, 0xf7, 0xc7, 0x4d, + 0x33, 0xd6, 0xca, 0xae, 0xe4, 0xa7, 0x70, 0x6b, 0xb1, 0x0c, 0x0a, 0xd3, 0xdb, 0xfa, 0x28, 0x65, 0x51, 0x7d, 0x1c, + 0xc6, 0x43, 0xb7, 0xb3, 0x1d, 0x9b, 0xf6, 0x75, 0x25, 0x0d, 0x75, 0xb5, 0x08, 0xe8, 0xf5, 0x37, 0x5d, 0xb8, 0x31, + 0xf7, 0x36, 0xe4, 0xd1, 0xb6, 0xaf, 0xdf, 0x94, 0xa7, 0xaf, 0x72, 0x05, 0x27, 0xd5, 0x9f, 0xba, 0xd2, 0x1c, 0x30, + 0xad, 0xdc, 0xbc, 0xc9, 0x5d, 0xa7, 0x08, 0x6a, 0xfd, 0xdf, 0xff, 0xf9, 0x5f, 0xfe, 0x9b, 0x79, 0x84, 0x58, 0xd5, + 0xbf, 0xfe, 0xf7, 0xff, 0xfc, 0x7f, 0xfe, 0xf7, 0x7f, 0x85, 0xdb, 0x1a, 0x3a, 0x9e, 0x25, 0x99, 0x8a, 0x53, 0x06, + 0xb3, 0x14, 0x77, 0x71, 0x20, 0xa1, 0x71, 0xc2, 0x32, 0xc1, 0x06, 0xd5, 0xbb, 0x38, 0x17, 0x72, 0x42, 0x79, 0x32, + 0x35, 0x74, 0xf2, 0x84, 0xe7, 0x25, 0x41, 0x55, 0x50, 0x2e, 0x09, 0x37, 0x3f, 0xdd, 0x07, 0x7c, 0x3f, 0xec, 0xfa, + 0xa2, 0x5f, 0x6c, 0xc7, 0xc2, 0x90, 0x09, 0x94, 0xe4, 0x65, 0xb9, 0x03, 0xb1, 0x95, 0x05, 0x3c, 0x06, 0x2d, 0xab, + 0x58, 0xee, 0x5e, 0xa5, 0x4f, 0xfb, 0xc3, 0x2c, 0x13, 0x6c, 0x08, 0x28, 0x57, 0x7e, 0x62, 0x19, 0xc6, 0xae, 0x83, + 0xae, 0x18, 0xdf, 0xe5, 0x72, 0x14, 0x45, 0xa0, 0x87, 0x27, 0x7f, 0xca, 0xff, 0x32, 0x01, 0x8d, 0xcc, 0xf1, 0x26, + 0xe1, 0xad, 0x36, 0xcf, 0x8f, 0x1b, 0x8d, 0xe9, 0x2d, 0x5a, 0x94, 0x33, 0xe0, 0x6d, 0x93, 0x49, 0x3a, 0xb6, 0x07, + 0x94, 0xf1, 0xef, 0xc2, 0x8d, 0xdd, 0x70, 0xc0, 0x17, 0xee, 0x34, 0xf2, 0xfc, 0xcf, 0x0b, 0xe9, 0x49, 0x65, 0xbf, + 0x42, 0x9c, 0x5a, 0x3b, 0x9d, 0xaf, 0xb9, 0xbd, 0xb8, 0x85, 0xd5, 0xab, 0xa5, 0x7a, 0x8d, 0x9b, 0xeb, 0xb7, 0xf2, + 0xec, 0x38, 0xbb, 0x1d, 0x21, 0x3f, 0x84, 0x98, 0xf7, 0xb8, 0x89, 0xc7, 0xad, 0x45, 0x31, 0xbc, 0x10, 0x7c, 0x62, + 0x07, 0xd6, 0x69, 0x48, 0x07, 0x74, 0x68, 0x9c, 0xf5, 0xba, 0x5e, 0x05, 0xcd, 0xf3, 0xf1, 0xc1, 0x86, 0xb9, 0x34, + 0x48, 0x32, 0xa0, 0xee, 0x34, 0xf2, 0x2f, 0xe1, 0x04, 0x2e, 0x86, 0x31, 0x0f, 0x45, 0x20, 0x09, 0xb6, 0x6d, 0x87, + 0xe7, 0x43, 0xe0, 0x49, 0x7c, 0x61, 0xc1, 0xd3, 0x56, 0x4d, 0xc1, 0x6d, 0x5e, 0xbd, 0x3b, 0x99, 0xfb, 0xb2, 0xbb, + 0x3d, 0x94, 0xf2, 0xba, 0x7d, 0xaf, 0xa3, 0xde, 0xaf, 0x2a, 0xee, 0x2a, 0x2d, 0x90, 0x5a, 0x68, 0x73, 0xbd, 0x92, + 0xeb, 0xaa, 0xf6, 0x27, 0xe1, 0xb9, 0x12, 0x4c, 0x77, 0xb5, 0x95, 0x2c, 0x84, 0x56, 0xaf, 0xc8, 0xf7, 0x85, 0xc9, + 0x14, 0x4e, 0xa7, 0xb2, 0x21, 0x6a, 0x9f, 0xee, 0x2b, 0x4d, 0x17, 0xb8, 0x87, 0x4c, 0xe9, 0x50, 0x19, 0x14, 0xba, + 0x91, 0x3e, 0x0a, 0xea, 0x97, 0xce, 0xad, 0x80, 0x6f, 0xa0, 0x75, 0xfe, 0x1f, 0xa2, 0x48, 0xf6, 0xdd, 0x94, 0x88, + 0x00, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index bde1ce1fb5..0c16ea9f37 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -3632,373 +3632,374 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, - 0xdc, 0x93, 0x2e, 0xb7, 0x6d, 0x24, 0xfd, 0x3f, 0x4f, 0x01, 0xc3, 0x5e, 0x87, 0xb0, 0x01, 0x08, 0x00, 0x45, 0x89, - 0x26, 0x45, 0x69, 0x13, 0x1f, 0xb5, 0x4e, 0x29, 0x71, 0xca, 0x56, 0x5c, 0xbb, 0x51, 0x54, 0x22, 0x48, 0x0e, 0x49, - 0xac, 0x41, 0x80, 0x05, 0x80, 0x3a, 0x42, 0x63, 0x9f, 0x65, 0x9f, 0x65, 0x9f, 0xec, 0xab, 0xee, 0x9e, 0x19, 0x0c, - 0x0e, 0x1e, 0x8a, 0x9d, 0xdd, 0xaf, 0x12, 0xdb, 0xc4, 0xdc, 0xd3, 0x33, 0xd3, 0xd3, 0xd3, 0xa7, 0x3f, 0xe3, 0xbc, - 0x17, 0xb3, 0xc5, 0xf6, 0xeb, 0xee, 0xf3, 0x67, 0x66, 0xe3, 0x96, 0x04, 0x82, 0xcf, 0xce, 0xe2, 0xd9, 0x2c, 0x64, - 0x2d, 0x5d, 0x04, 0x0f, 0xd1, 0x4d, 0xd9, 0xcd, 0xd9, 0x23, 0x47, 0x78, 0xec, 0x34, 0xf2, 0x4d, 0x47, 0x4b, 0xcc, - 0x98, 0x49, 0x97, 0x76, 0x44, 0xb9, 0x22, 0x6f, 0xf6, 0x06, 0xc5, 0x1b, 0x7c, 0x5d, 0x8a, 0xa3, 0x6b, 0x4d, 0xe2, - 0xd5, 0x28, 0x64, 0x16, 0x6e, 0x77, 0xe8, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x10, 0xa5, 0xe5, 0x91, 0x63, 0x82, 0xdf, - 0x99, 0x38, 0xc5, 0xf7, 0x60, 0x6e, 0xf4, 0x61, 0x52, 0x76, 0x56, 0x1d, 0x3e, 0xe8, 0x8a, 0x00, 0xab, 0x87, 0x3a, - 0xc8, 0xe0, 0xed, 0xd7, 0x70, 0x6a, 0x07, 0xfa, 0x07, 0xd8, 0x7d, 0xa9, 0xde, 0x6f, 0x3a, 0xfa, 0x83, 0x4b, 0xfd, - 0x03, 0xc2, 0x18, 0xa3, 0x17, 0xbf, 0xa4, 0xdd, 0xab, 0x9b, 0x3a, 0x09, 0xbd, 0x57, 0x18, 0xc7, 0x00, 0x98, 0xbe, - 0xaf, 0x02, 0x7f, 0x16, 0xc5, 0x69, 0x16, 0x8c, 0xf5, 0xab, 0xfe, 0xdb, 0xa0, 0x75, 0xb9, 0xc8, 0x5a, 0xc6, 0x95, - 0x39, 0xce, 0xd4, 0x10, 0x28, 0x02, 0x61, 0x62, 0x04, 0x94, 0x4d, 0x85, 0xd4, 0x13, 0xb4, 0xb5, 0xa0, 0x40, 0xcd, - 0x58, 0x68, 0x9c, 0x0d, 0xa0, 0x5c, 0x25, 0x9e, 0x0a, 0x06, 0x86, 0xd2, 0xb1, 0xa6, 0xd1, 0xa7, 0x97, 0xca, 0xcb, - 0xd5, 0x1a, 0xaf, 0xf2, 0xac, 0xb8, 0x2d, 0xd1, 0x07, 0xb0, 0x30, 0x9c, 0xa1, 0xef, 0x47, 0xaa, 0xd2, 0x67, 0xe9, - 0xde, 0x1d, 0x7e, 0x57, 0xa6, 0x0b, 0xe0, 0xfe, 0x06, 0x8d, 0x8b, 0x28, 0xce, 0x34, 0x70, 0x6c, 0x03, 0x3d, 0x0e, - 0xab, 0x4a, 0x62, 0xbc, 0xd5, 0x96, 0x91, 0x73, 0x64, 0xf0, 0x3d, 0x5e, 0x7e, 0x2d, 0xee, 0xde, 0xac, 0xe4, 0xc1, - 0x82, 0x1e, 0x0b, 0x11, 0x2c, 0x60, 0x16, 0x9f, 0xc7, 0xb7, 0x55, 0x39, 0xc8, 0xcb, 0xe1, 0xee, 0xbb, 0xb7, 0x25, - 0xc8, 0x64, 0x11, 0xd5, 0xaf, 0xc5, 0x03, 0x93, 0x0a, 0x42, 0xa7, 0x72, 0xa6, 0x50, 0xf1, 0x43, 0xd0, 0x30, 0x19, - 0xe8, 0x89, 0xe1, 0x5d, 0x00, 0x28, 0x89, 0x5f, 0xd3, 0xc3, 0xfc, 0x5a, 0x84, 0x4e, 0x16, 0x81, 0x8b, 0x95, 0xcb, - 0x19, 0xb0, 0x6b, 0xb4, 0x5c, 0x65, 0xe8, 0x6a, 0x17, 0x06, 0xc0, 0x72, 0x5d, 0x43, 0xd7, 0x9d, 0x80, 0xa5, 0x0b, - 0x32, 0x31, 0xd7, 0xb5, 0x60, 0x52, 0x4f, 0xe3, 0x44, 0x2f, 0x20, 0x2f, 0xc4, 0xef, 0xc8, 0xa8, 0x82, 0xcf, 0x84, - 0x4f, 0x63, 0x6c, 0x16, 0x7e, 0xea, 0x5b, 0x63, 0x14, 0xe8, 0x34, 0x60, 0x86, 0x31, 0xb5, 0xd3, 0x6f, 0x85, 0x8d, - 0x93, 0x05, 0xf7, 0x9b, 0xa5, 0x69, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, 0xd6, 0xbe, - 0xd4, 0x15, 0xd0, 0x2f, 0x74, 0x52, 0x14, 0x18, 0x22, 0x18, 0x86, 0xf9, 0x75, 0x61, 0xb9, 0x53, 0xcc, 0x17, 0x76, - 0x19, 0xa5, 0x6b, 0x28, 0xba, 0x1f, 0x70, 0x01, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xf2, 0x7c, 0x53, 0x15, - 0xfa, 0x1b, 0xba, 0x46, 0x88, 0x9e, 0x00, 0x40, 0x38, 0x5f, 0xd7, 0xfe, 0x2a, 0xd3, 0x18, 0x9f, 0xad, 0x14, 0x6a, - 0x42, 0x5f, 0xd7, 0xfa, 0x73, 0x66, 0x4f, 0x58, 0xe6, 0x07, 0x21, 0x55, 0xe9, 0x8b, 0x68, 0xf5, 0xb5, 0xe9, 0xa5, - 0xe5, 0xe9, 0x45, 0xe5, 0xfd, 0x83, 0x93, 0xa1, 0x2b, 0x80, 0xc6, 0x8d, 0x33, 0xc3, 0x28, 0x56, 0xcd, 0x2b, 0x4a, - 0x79, 0xff, 0xd5, 0xe5, 0x60, 0xb0, 0x1c, 0x11, 0x2c, 0x07, 0x8b, 0xc6, 0xf1, 0x84, 0xfd, 0xf2, 0xfe, 0xad, 0x0c, - 0x9b, 0x05, 0x1c, 0xa0, 0x21, 0xdf, 0x98, 0x29, 0xd2, 0x0f, 0x09, 0xd2, 0x0e, 0x14, 0xe0, 0x4a, 0x93, 0x5b, 0x28, - 0xc9, 0x75, 0xed, 0x8c, 0xc6, 0xce, 0x26, 0x34, 0xea, 0x41, 0x8c, 0xb5, 0x92, 0xfc, 0xe4, 0x80, 0x4a, 0xd3, 0x6d, - 0x47, 0x85, 0x00, 0x0c, 0x09, 0xcc, 0xb0, 0x80, 0x02, 0x44, 0xf8, 0x1c, 0xb8, 0xc5, 0x83, 0xc2, 0x5e, 0x20, 0x9f, - 0xdd, 0x3d, 0x2b, 0x93, 0x2a, 0x58, 0x4b, 0x3f, 0x3d, 0xc1, 0x98, 0x5d, 0x70, 0x5f, 0x83, 0x97, 0x8f, 0x93, 0x03, - 0xfa, 0xd4, 0x2a, 0x27, 0xa2, 0x68, 0x44, 0x3c, 0xed, 0x7a, 0xbc, 0x81, 0x07, 0x1d, 0x15, 0x08, 0x11, 0x0f, 0xa9, - 0x7e, 0xae, 0x6b, 0x0b, 0x4e, 0x1a, 0x71, 0x77, 0x42, 0xe0, 0x6b, 0xc0, 0x81, 0xb3, 0xab, 0x6b, 0x0b, 0xff, 0x0e, - 0x67, 0x2e, 0x72, 0xfc, 0xbb, 0x96, 0xcb, 0xb3, 0x8a, 0xb3, 0x96, 0x96, 0xcf, 0xda, 0x98, 0x2f, 0x2e, 0x18, 0x12, - 0xc8, 0x97, 0xf5, 0x1c, 0x05, 0xb4, 0x0d, 0x8b, 0x3b, 0x17, 0x8b, 0x3b, 0xd9, 0xb0, 0xb8, 0x93, 0x2d, 0x8b, 0x1b, - 0xf2, 0x85, 0xd4, 0x24, 0xe8, 0x12, 0x34, 0x0e, 0x93, 0xc0, 0xe3, 0x84, 0x46, 0x8f, 0x9f, 0x33, 0x84, 0x93, 0x95, - 0x86, 0xa0, 0x1c, 0xb5, 0x01, 0x56, 0x4d, 0x70, 0x51, 0x00, 0x51, 0x9f, 0xb8, 0x3c, 0x75, 0x62, 0xde, 0x10, 0x83, - 0xb3, 0x15, 0x56, 0xe7, 0x0b, 0xbb, 0x94, 0xe2, 0x8b, 0xb7, 0xe6, 0x1b, 0x66, 0x3a, 0xdf, 0x32, 0xd3, 0x71, 0xe9, - 0xe8, 0xf2, 0x69, 0xd3, 0x21, 0x54, 0x27, 0x05, 0x7b, 0x10, 0x14, 0x46, 0x71, 0xcb, 0x94, 0xf7, 0xe1, 0x66, 0x1c, - 0xab, 0xec, 0xa8, 0xa5, 0x9f, 0xa6, 0xb7, 0x71, 0x02, 0x12, 0x17, 0x68, 0xe6, 0x61, 0x5b, 0x6a, 0x11, 0x44, 0xdc, - 0x99, 0xcb, 0xc6, 0xcd, 0x54, 0xe4, 0xab, 0x5b, 0xca, 0xeb, 0x74, 0xa8, 0xc4, 0xd2, 0xcf, 0x32, 0x96, 0x20, 0xd0, - 0x7d, 0xf0, 0xfa, 0xfd, 0xff, 0x64, 0x9b, 0x35, 0xe0, 0x90, 0x50, 0xc1, 0xea, 0x88, 0xa1, 0x97, 0x40, 0x5b, 0x25, - 0xe2, 0x22, 0x56, 0x1c, 0xc3, 0x25, 0x12, 0xf0, 0x3f, 0xe1, 0x71, 0x6d, 0x25, 0x8a, 0xe9, 0x92, 0x7b, 0x64, 0xd8, - 0x4b, 0x7f, 0xf2, 0x01, 0x04, 0x7b, 0x2d, 0xcf, 0x04, 0x25, 0x5d, 0xd5, 0x0d, 0x5c, 0x42, 0xc4, 0xde, 0xb8, 0x40, - 0x92, 0x88, 0x25, 0xb9, 0x0a, 0x14, 0x58, 0x4f, 0xfa, 0xd6, 0xf4, 0x6a, 0xed, 0xe5, 0x07, 0xb3, 0xc0, 0xa8, 0x61, - 0x4d, 0x40, 0x6d, 0xe1, 0xe0, 0x54, 0xbe, 0xb9, 0x42, 0xd3, 0x3d, 0x32, 0x80, 0xf3, 0x7b, 0x09, 0xf1, 0x4c, 0x1d, - 0xf1, 0xa0, 0x1d, 0x26, 0x70, 0x6b, 0x5d, 0x3a, 0x57, 0xf9, 0xd3, 0x19, 0xfe, 0x72, 0xaf, 0xf2, 0xa7, 0x23, 0xfc, - 0xe5, 0x5d, 0x61, 0xe4, 0xba, 0x86, 0x87, 0xbc, 0x32, 0x67, 0xfd, 0xb4, 0xb4, 0x9f, 0x48, 0xff, 0xec, 0x01, 0xdb, - 0x86, 0x2f, 0xf0, 0xe3, 0x27, 0xeb, 0x14, 0x2c, 0x2e, 0xd5, 0x39, 0x44, 0x76, 0x62, 0xe4, 0x8d, 0xe9, 0xb3, 0x0d, - 0xe9, 0x23, 0xe3, 0xbf, 0x7c, 0xf1, 0xe3, 0x2e, 0x89, 0x8b, 0x3b, 0xa5, 0xcc, 0x86, 0xb8, 0x1e, 0x05, 0x91, 0x9f, - 0xdc, 0x5f, 0xd3, 0xf3, 0xa2, 0x25, 0x68, 0x77, 0xc9, 0x5e, 0x21, 0xf2, 0xb2, 0x2c, 0xee, 0xca, 0x14, 0x06, 0xef, - 0x3d, 0xbf, 0xe8, 0x07, 0x7f, 0x4f, 0x14, 0xb2, 0xad, 0xf4, 0x00, 0xe5, 0x0b, 0x52, 0xea, 0xe8, 0xfa, 0xc9, 0xba, - 0xc5, 0xea, 0xcd, 0x54, 0x66, 0x5b, 0xa1, 0x0b, 0x61, 0x79, 0xf0, 0x31, 0xbb, 0x98, 0x04, 0x3d, 0x94, 0x67, 0x8d, - 0xe2, 0x3b, 0xeb, 0xc9, 0x3a, 0x3b, 0xd3, 0x17, 0x7e, 0xf2, 0x89, 0x4d, 0xac, 0x71, 0x90, 0x8c, 0x43, 0xa6, 0xf7, - 0xf4, 0x51, 0xe8, 0x47, 0x9f, 0xf8, 0xa7, 0x15, 0xaf, 0x32, 0x94, 0x50, 0xef, 0x7c, 0xfb, 0x0a, 0x98, 0x10, 0xcb, - 0x0e, 0x89, 0xd5, 0x06, 0x28, 0x68, 0x2f, 0x25, 0xc3, 0xab, 0x20, 0x14, 0x8b, 0x52, 0x26, 0x28, 0x58, 0x82, 0xd0, - 0x1c, 0x2c, 0x56, 0x4d, 0x1d, 0xd7, 0x4b, 0x37, 0xd5, 0xa9, 0x12, 0xb3, 0x52, 0x86, 0x5c, 0xbc, 0xc6, 0x16, 0xfe, - 0x78, 0x77, 0x14, 0x0c, 0x7b, 0xff, 0xee, 0x64, 0x2b, 0x5f, 0x36, 0x43, 0x48, 0xb5, 0xc8, 0x52, 0xe2, 0x01, 0x9d, - 0x73, 0x02, 0x73, 0x73, 0xd7, 0x6a, 0x65, 0x3f, 0x4d, 0x57, 0x0b, 0x36, 0x21, 0xc9, 0xe0, 0x59, 0x31, 0xa8, 0xf2, - 0xcb, 0x42, 0x1d, 0xd8, 0x6f, 0x2b, 0xef, 0xf8, 0xf0, 0x25, 0x68, 0x2c, 0x00, 0x41, 0x19, 0x4f, 0xa7, 0x7a, 0xf1, - 0xc6, 0xdf, 0x51, 0xcd, 0x3d, 0xfc, 0x6d, 0xf5, 0xe6, 0xb5, 0xf3, 0x46, 0x56, 0x8e, 0x80, 0x30, 0x16, 0xe2, 0x57, - 0x4e, 0x17, 0x2b, 0xe3, 0x15, 0x33, 0x9a, 0xfa, 0xd1, 0xe6, 0xe9, 0x5c, 0x96, 0xb6, 0xf8, 0x92, 0xb1, 0x09, 0x10, - 0xdc, 0x66, 0x2d, 0xf5, 0x3a, 0x64, 0x37, 0x4c, 0x8a, 0x76, 0xeb, 0x9d, 0x35, 0xd4, 0x40, 0xdf, 0x73, 0x5c, 0x64, - 0xcc, 0xa9, 0x3a, 0x65, 0x4a, 0x43, 0x9c, 0x03, 0x9f, 0xb9, 0x7a, 0xc4, 0x2a, 0x47, 0x6a, 0x68, 0xea, 0xca, 0x00, - 0x36, 0x8e, 0xec, 0x6c, 0x43, 0x7a, 0x0f, 0x03, 0x4f, 0x37, 0x8f, 0xcd, 0x74, 0x8d, 0x1e, 0xf8, 0xea, 0xe6, 0x70, - 0x0a, 0xe1, 0xe4, 0xb5, 0x0a, 0x76, 0xc8, 0x26, 0x88, 0x35, 0x31, 0xc9, 0x74, 0xe2, 0xbe, 0x08, 0x6d, 0x47, 0x54, - 0xfb, 0x15, 0x7c, 0xa8, 0xc6, 0xb5, 0xd1, 0xca, 0x33, 0x1f, 0x61, 0x40, 0xd7, 0x88, 0xa5, 0xe9, 0x46, 0x80, 0xc9, - 0x45, 0x37, 0xf5, 0xa2, 0x74, 0x19, 0x1e, 0x45, 0xba, 0xe9, 0x98, 0x40, 0x12, 0xe0, 0x04, 0xab, 0x7d, 0xe1, 0xf5, - 0x72, 0xbd, 0xe0, 0xfa, 0x2a, 0xc9, 0x6c, 0xa4, 0x73, 0x5d, 0x82, 0x4d, 0xf9, 0xb7, 0x3a, 0x1f, 0x54, 0xe9, 0x9a, - 0x6e, 0x1c, 0x5a, 0xab, 0x84, 0x7a, 0x6b, 0xec, 0x22, 0x6c, 0x40, 0x8c, 0xa9, 0x82, 0x5f, 0xd9, 0x74, 0xca, 0xc6, - 0x59, 0x6a, 0x08, 0xe6, 0x91, 0xf4, 0x1e, 0x0b, 0x56, 0x43, 0x8f, 0x06, 0xfa, 0x4f, 0x60, 0x43, 0x2f, 0x9c, 0x2c, - 0xf1, 0x01, 0x89, 0x37, 0x53, 0x33, 0x98, 0xa8, 0xc5, 0x32, 0x88, 0x78, 0x2f, 0x10, 0x1c, 0xbc, 0x21, 0x1d, 0x87, - 0xc6, 0xef, 0x9f, 0x62, 0x5f, 0xc4, 0x52, 0xab, 0x65, 0x3b, 0x2a, 0xda, 0x76, 0x7c, 0xd7, 0xee, 0x9b, 0x8e, 0xeb, - 0xe4, 0xba, 0x09, 0xb6, 0x5b, 0x9f, 0xf6, 0x3d, 0xf4, 0x58, 0xab, 0x0d, 0xb5, 0x56, 0xd1, 0x43, 0xea, 0x79, 0xee, - 0x0b, 0x57, 0x37, 0x49, 0x65, 0x4e, 0xc1, 0x6d, 0xe3, 0xf8, 0x86, 0x25, 0x5f, 0x3c, 0x95, 0x72, 0xe3, 0xfb, 0x8d, - 0xe7, 0xc8, 0x75, 0x00, 0x09, 0x67, 0xf1, 0xf2, 0x01, 0x53, 0x68, 0xeb, 0xa6, 0x3e, 0x0e, 0xe3, 0x94, 0xa9, 0x73, - 0x20, 0x26, 0xc8, 0x17, 0x4e, 0xe2, 0xe7, 0xf7, 0xaf, 0x3f, 0x7c, 0xd0, 0x4d, 0x8c, 0x04, 0x9a, 0xaa, 0xad, 0xf3, - 0x0d, 0xb5, 0x03, 0xfb, 0x37, 0xee, 0x3b, 0xba, 0x61, 0xe8, 0x51, 0x5b, 0xde, 0x73, 0x94, 0x56, 0xdb, 0x72, 0xfc, - 0xe6, 0xe1, 0x3d, 0xd3, 0x4b, 0x74, 0xaf, 0x79, 0x35, 0xe0, 0x86, 0xed, 0xd7, 0x5b, 0x29, 0x65, 0x11, 0x44, 0xd7, - 0x0d, 0xa9, 0xfe, 0x5d, 0x43, 0x2a, 0x3c, 0xe5, 0x6a, 0xb8, 0x6a, 0x15, 0x2f, 0x14, 0xd2, 0x00, 0x02, 0x39, 0xef, - 0x02, 0x97, 0xf2, 0x9e, 0xfa, 0x82, 0x41, 0x73, 0x4f, 0xee, 0xd5, 0x51, 0x37, 0x24, 0xf3, 0x47, 0x90, 0x84, 0xed, - 0x38, 0x04, 0x85, 0x3f, 0xa6, 0x4a, 0xe5, 0xca, 0x64, 0xa3, 0x54, 0xd7, 0x55, 0x1a, 0x21, 0xf2, 0xf6, 0x3a, 0x63, - 0x8b, 0x25, 0x4b, 0xfc, 0x6c, 0x95, 0xb0, 0xeb, 0x30, 0xbe, 0x7d, 0x54, 0xa8, 0xd3, 0xef, 0x28, 0x3c, 0x0f, 0x66, - 0x73, 0x59, 0xfa, 0xac, 0xc5, 0x06, 0x72, 0x01, 0xb7, 0x76, 0x90, 0xff, 0xe7, 0xdf, 0xb6, 0xfd, 0x9f, 0x7f, 0xef, - 0x2c, 0x0a, 0xcd, 0xe7, 0x43, 0x33, 0x1b, 0xec, 0xb1, 0x2f, 0x9a, 0x7b, 0x2a, 0xc3, 0xbc, 0xb9, 0x4c, 0x6d, 0x11, - 0x20, 0xbf, 0xb6, 0x04, 0xb5, 0xc4, 0xf2, 0xbe, 0x79, 0xd0, 0xc0, 0x60, 0x5e, 0x3b, 0x47, 0x06, 0x85, 0xbe, 0x68, - 0x68, 0x43, 0xa3, 0xb7, 0xd7, 0x8a, 0xfc, 0x71, 0x08, 0xef, 0x9a, 0xc3, 0x17, 0x0e, 0x9f, 0xf3, 0x25, 0x5f, 0x0e, - 0x87, 0x32, 0xb6, 0x9c, 0x5a, 0x15, 0x54, 0xfc, 0xcf, 0x6a, 0x29, 0xfc, 0xf2, 0xec, 0x39, 0x06, 0xd9, 0xde, 0x0f, - 0x5e, 0x0e, 0x51, 0x19, 0xed, 0x64, 0x94, 0x14, 0xc4, 0xca, 0x46, 0xd4, 0x46, 0xca, 0xe4, 0xb5, 0x46, 0x6b, 0x78, - 0x0d, 0x52, 0x31, 0xe0, 0x58, 0x3e, 0x34, 0xcc, 0x97, 0x43, 0xce, 0x58, 0xe2, 0xfa, 0xaf, 0xbd, 0xea, 0xd6, 0xe6, - 0x6c, 0xd9, 0x12, 0xd0, 0x4d, 0x8d, 0xe4, 0x3f, 0x58, 0x98, 0x15, 0x7c, 0x3c, 0x64, 0xf0, 0x03, 0x47, 0x61, 0x98, - 0x63, 0xbc, 0x93, 0x77, 0x9b, 0x74, 0xc4, 0x7e, 0xde, 0xad, 0x23, 0x76, 0xb1, 0x97, 0x8e, 0xd8, 0xcf, 0x5f, 0x5d, - 0x47, 0xec, 0x9d, 0xaa, 0x23, 0x06, 0x8b, 0xf8, 0x9a, 0xed, 0xa5, 0xb8, 0x25, 0xb4, 0x36, 0xe2, 0xdb, 0x74, 0xe0, - 0x72, 0x92, 0x36, 0x1d, 0xcf, 0x19, 0xf0, 0x08, 0xf8, 0xaa, 0x84, 0xf1, 0x0c, 0x94, 0xb8, 0xfe, 0x7c, 0x75, 0xab, - 0x30, 0x9e, 0xa9, 0xca, 0x56, 0x11, 0xf7, 0xf8, 0x5a, 0x78, 0x71, 0x22, 0x05, 0x27, 0xc7, 0x14, 0x3e, 0x9f, 0xac, - 0x43, 0x43, 0x89, 0x6a, 0x2d, 0xb5, 0xd7, 0x3c, 0xa1, 0x02, 0xd5, 0x43, 0xed, 0x29, 0x59, 0xd1, 0x7b, 0x2e, 0x7c, - 0x5b, 0xa8, 0x2d, 0x48, 0x2d, 0x61, 0xf2, 0x13, 0xb1, 0xd6, 0x7f, 0xbb, 0x73, 0xbf, 0xbf, 0x74, 0xfb, 0x6d, 0x17, - 0x8c, 0xb3, 0xe1, 0x85, 0x89, 0x09, 0x4e, 0xbf, 0xdd, 0x86, 0x84, 0x5b, 0x25, 0xc1, 0x83, 0x84, 0x40, 0x49, 0xe8, - 0x40, 0xc2, 0x58, 0x49, 0x38, 0x82, 0x84, 0x89, 0x92, 0x70, 0x0c, 0x09, 0x37, 0x7a, 0x7e, 0x19, 0xc9, 0xe1, 0x1e, - 0x1b, 0x57, 0x26, 0x3d, 0x2a, 0x44, 0xda, 0xb1, 0xe9, 0x82, 0xd6, 0x94, 0x3f, 0xeb, 0xc5, 0x26, 0x71, 0x17, 0x7b, - 0x89, 0x79, 0x3b, 0x67, 0xe4, 0x28, 0xfa, 0x15, 0xde, 0x39, 0x76, 0x16, 0x83, 0xde, 0xb4, 0x70, 0xc0, 0x20, 0xe0, - 0xa0, 0xe9, 0x06, 0x30, 0x8c, 0xfa, 0x72, 0xe5, 0x84, 0x13, 0x0b, 0x65, 0x2d, 0x8b, 0x3c, 0xea, 0xce, 0x92, 0x5b, - 0xa0, 0xd0, 0x38, 0x69, 0xa9, 0x5c, 0xc9, 0xaf, 0xa1, 0x77, 0xf0, 0x8a, 0x8d, 0x56, 0x33, 0xed, 0x3c, 0x9e, 0xed, - 0x54, 0x21, 0x50, 0xb3, 0x60, 0x94, 0x3a, 0x89, 0x5f, 0x2c, 0xb1, 0x2d, 0x79, 0x5f, 0xf4, 0x99, 0x97, 0xcb, 0x67, - 0x30, 0x36, 0x2d, 0x23, 0x05, 0x16, 0xe8, 0x07, 0x60, 0xa4, 0xc8, 0xf0, 0xcf, 0x01, 0xce, 0xca, 0xf7, 0x85, 0xaf, - 0x8c, 0xe7, 0xf4, 0x47, 0x96, 0xa6, 0xfe, 0x4c, 0x94, 0xaf, 0x8f, 0x13, 0x94, 0x76, 0xe4, 0xfb, 0x0b, 0x01, 0x08, - 0x9c, 0xbc, 0xa0, 0xa6, 0x9b, 0x91, 0xc4, 0xb7, 0x1a, 0x68, 0xff, 0xc0, 0x86, 0x2a, 0xf4, 0x14, 0x02, 0x1b, 0x96, - 0xb0, 0xac, 0x51, 0x00, 0x87, 0xff, 0x86, 0x85, 0xd5, 0xc4, 0xcc, 0x9f, 0x55, 0x93, 0x68, 0x1f, 0xe4, 0xea, 0xd8, - 0xa4, 0x40, 0xbf, 0x94, 0xf8, 0x25, 0x12, 0xea, 0x30, 0x9e, 0xfd, 0xa9, 0xe2, 0xe9, 0x2d, 0x6a, 0x05, 0x1f, 0x22, - 0x33, 0xc8, 0x86, 0x36, 0xc2, 0x58, 0xb3, 0x01, 0x84, 0xbd, 0x28, 0x9b, 0x5b, 0x68, 0x5a, 0xd6, 0xf2, 0x22, 0xc3, - 0xb4, 0x71, 0x6d, 0xd7, 0x55, 0x83, 0xda, 0x5e, 0x32, 0x1b, 0xf9, 0x2d, 0xd7, 0x3b, 0x36, 0xc5, 0x1f, 0xdb, 0xe9, - 0x18, 0x39, 0xb6, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, 0xbe, 0xb7, 0x88, - 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x1e, 0xd4, 0x7d, 0x74, 0xd5, 0xc0, 0xad, 0x05, 0x5d, 0xdb, 0x4b, 0xd8, - 0x82, 0x6a, 0x4b, 0x4f, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xbc, 0xfb, 0x52, 0x61, 0x2a, 0x8a, 0x5b, 0x8e, 0x6a, 0x00, - 0x45, 0xca, 0xdd, 0x3c, 0x80, 0x73, 0xa3, 0xfe, 0xd2, 0x9f, 0xa0, 0x67, 0x42, 0xdb, 0xeb, 0x24, 0x6c, 0xa1, 0xd9, - 0x9d, 0x8d, 0x8d, 0x27, 0xf1, 0xed, 0x29, 0x8c, 0x16, 0x2b, 0x5b, 0x29, 0x0b, 0xa7, 0x98, 0x63, 0xa1, 0x65, 0x89, - 0x68, 0xc7, 0xc2, 0x87, 0x38, 0xb4, 0xc6, 0x16, 0x7d, 0xc8, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, 0x91, 0x45, 0xd3, - 0x39, 0x76, 0x96, 0x4a, 0x5b, 0x2a, 0xfc, 0x8c, 0x35, 0x16, 0x77, 0x35, 0xa7, 0x0f, 0x8f, 0xb5, 0x69, 0x18, 0xdf, - 0xf6, 0xe6, 0xc1, 0x64, 0xc2, 0xa2, 0x3e, 0x8e, 0x59, 0x26, 0xb2, 0x30, 0x0c, 0x96, 0x69, 0x90, 0xf6, 0x17, 0xfe, - 0x1d, 0x6f, 0xf5, 0x70, 0x53, 0xab, 0x6d, 0xde, 0x6a, 0x7b, 0xef, 0x56, 0x95, 0x66, 0xc0, 0x8a, 0x85, 0xda, 0xe1, - 0x43, 0xeb, 0x68, 0x4e, 0x65, 0x9e, 0x7b, 0xb7, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, 0x39, 0xb9, - 0x7d, 0xb3, 0xa6, 0x8d, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x7c, 0x39, 0x93, 0x49, 0x6e, 0x8f, 0xc5, 0xd7, - 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0x22, 0xa1, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, 0x12, 0xb9, - 0xcd, 0xf8, 0x57, 0xc2, 0x26, 0x7d, 0xdc, 0x48, 0xa4, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x31, 0xc0, 0x65, 0x09, - 0x37, 0x21, 0xaf, 0xe7, 0x6a, 0xbd, 0x77, 0x49, 0xad, 0xe8, 0x6e, 0x3c, 0x6e, 0x2c, 0x37, 0xf1, 0x93, 0x4f, 0x57, - 0x9a, 0x32, 0x0b, 0xdf, 0xa7, 0x62, 0x6b, 0x01, 0x06, 0xeb, 0xae, 0x07, 0x2e, 0xbb, 0xfa, 0xa3, 0x38, 0x81, 0x33, - 0x9b, 0xf8, 0x93, 0x60, 0x95, 0xf6, 0x5c, 0x6f, 0x79, 0x27, 0x92, 0xf8, 0x5e, 0x2f, 0x12, 0xf0, 0xec, 0xf5, 0xd2, - 0x38, 0x0c, 0x26, 0x22, 0x69, 0xd3, 0x59, 0x72, 0x3d, 0xa3, 0x8f, 0x06, 0xeb, 0x01, 0xba, 0x5d, 0xf0, 0xc3, 0x50, - 0xb3, 0xdb, 0xa9, 0xc6, 0xfc, 0x14, 0xf9, 0xcb, 0x9a, 0x93, 0x12, 0x5c, 0xd0, 0x38, 0xdd, 0x3d, 0x5c, 0xde, 0xc9, - 0x3d, 0xef, 0x1e, 0x2d, 0xef, 0xf2, 0xbf, 0x2e, 0xd8, 0x24, 0xf0, 0xb5, 0x56, 0xb1, 0x9b, 0x5c, 0x07, 0x78, 0xd0, - 0xc6, 0x7a, 0xc3, 0x36, 0x15, 0xc7, 0x02, 0x5c, 0x1b, 0x3e, 0x0a, 0x16, 0xcb, 0x38, 0xc9, 0xfc, 0x28, 0xcb, 0xf3, - 0xe1, 0x55, 0x9e, 0xf7, 0x2f, 0x82, 0xd6, 0xe5, 0x3f, 0x5a, 0x74, 0x4f, 0x93, 0xcc, 0x26, 0x37, 0xae, 0xcc, 0xd7, - 0x4c, 0xd5, 0x19, 0x81, 0x6b, 0x0c, 0xf5, 0x45, 0xd4, 0xc2, 0x74, 0x4b, 0xd6, 0x0b, 0x13, 0x90, 0x65, 0x71, 0xd2, - 0x41, 0x29, 0x17, 0xc1, 0x1b, 0x08, 0x0a, 0xbc, 0x66, 0x83, 0x0b, 0x45, 0xff, 0x04, 0x88, 0x15, 0x2c, 0x4c, 0x76, - 0x05, 0x4f, 0x36, 0xd1, 0x8c, 0xdf, 0xed, 0xa6, 0x19, 0x7f, 0xcd, 0xf6, 0xa1, 0x19, 0xbf, 0xfb, 0xea, 0x34, 0xe3, - 0x93, 0xba, 0x5d, 0xc1, 0xdb, 0x78, 0xa0, 0x4b, 0x09, 0x03, 0x5c, 0x4d, 0x09, 0x79, 0xec, 0x79, 0xfb, 0x87, 0xcd, - 0x00, 0x44, 0x6b, 0x14, 0x83, 0x8e, 0x6e, 0x6e, 0xe0, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xef, 0xe9, 0x74, - 0xf0, 0x2a, 0x56, 0x12, 0xe4, 0x17, 0x57, 0xbe, 0x28, 0x79, 0x57, 0xa0, 0x1c, 0xa1, 0x85, 0x89, 0xf1, 0x27, 0xc0, - 0x38, 0x9b, 0xb4, 0x8e, 0x27, 0x52, 0xfb, 0xac, 0x5f, 0x1e, 0x42, 0x4b, 0xaa, 0x7c, 0x0a, 0x13, 0x9c, 0x1a, 0x2b, - 0x71, 0xc6, 0x32, 0x6e, 0x33, 0xfb, 0xfd, 0xfd, 0xdb, 0x49, 0xeb, 0x6d, 0x6c, 0xe4, 0x41, 0xfa, 0xae, 0x6a, 0x00, - 0xc3, 0x65, 0x3f, 0x03, 0x75, 0x3a, 0x39, 0xd7, 0x20, 0x53, 0x03, 0x4c, 0x43, 0x36, 0x55, 0x3f, 0x2b, 0xcd, 0xb4, - 0xa7, 0x56, 0xe4, 0x81, 0xae, 0x6a, 0x97, 0x31, 0xb7, 0x3e, 0x58, 0x73, 0x0a, 0x10, 0x63, 0x77, 0xa1, 0xdd, 0xf0, - 0x84, 0xaa, 0x07, 0x93, 0x3c, 0x37, 0xfa, 0x02, 0x10, 0xca, 0x45, 0xcb, 0x76, 0x11, 0x71, 0xe9, 0xad, 0xd4, 0x69, - 0xe0, 0x12, 0x42, 0x12, 0xff, 0xbd, 0x05, 0x81, 0x3a, 0x17, 0x16, 0x72, 0x98, 0xe9, 0x1a, 0x81, 0x8f, 0x14, 0x2d, - 0x94, 0x09, 0x81, 0x04, 0x58, 0xc2, 0x5f, 0x64, 0x89, 0x84, 0xba, 0x0e, 0x27, 0x01, 0x07, 0x35, 0x02, 0xc0, 0xca, - 0x5f, 0xf0, 0xb5, 0x09, 0xed, 0xf0, 0x32, 0xf8, 0x91, 0xeb, 0x92, 0xf6, 0xc3, 0xed, 0x77, 0x7a, 0x72, 0x00, 0x15, - 0x4e, 0x2b, 0x8a, 0x03, 0x3b, 0x34, 0x14, 0x81, 0x94, 0x48, 0x6f, 0x4d, 0x3b, 0xbd, 0xd5, 0x9e, 0xad, 0x85, 0x87, - 0x8c, 0xcc, 0x5f, 0x5a, 0xf0, 0xc4, 0x47, 0xdc, 0xcb, 0x31, 0x9e, 0xe2, 0x8c, 0xa3, 0xbf, 0x4a, 0x01, 0x37, 0xe2, - 0x43, 0x15, 0xf1, 0x4f, 0x7f, 0xbc, 0x4a, 0xd2, 0x38, 0xe9, 0x2d, 0xe3, 0x20, 0xca, 0x58, 0x92, 0x23, 0xa8, 0x2e, - 0x11, 0x3e, 0x02, 0x3c, 0x57, 0xeb, 0x78, 0xe9, 0x8f, 0x83, 0xec, 0xbe, 0xe7, 0x70, 0x92, 0xc2, 0xe9, 0x73, 0xea, - 0xc0, 0x69, 0x2c, 0xdf, 0xe3, 0xd0, 0x7c, 0x8e, 0x84, 0x5f, 0x52, 0x27, 0x67, 0xd4, 0x6d, 0xde, 0x57, 0x72, 0xc9, - 0x47, 0x08, 0x90, 0x1f, 0x7e, 0x62, 0xcd, 0x00, 0xcb, 0xc3, 0x52, 0x3b, 0x13, 0x36, 0x33, 0x11, 0x6b, 0x03, 0x5f, - 0x5e, 0xfc, 0xb1, 0x3b, 0x86, 0xe6, 0x34, 0x27, 0x03, 0xc5, 0x63, 0xec, 0x33, 0xb2, 0x9e, 0x0f, 0x11, 0xb5, 0xcc, - 0x7d, 0x4a, 0x8e, 0xd8, 0x34, 0x4e, 0x18, 0xf9, 0x93, 0x75, 0xbb, 0xcb, 0xbb, 0xfd, 0x9b, 0xdf, 0x3e, 0xfd, 0xe6, - 0x76, 0xa2, 0x38, 0x6b, 0x89, 0xc6, 0x8c, 0x1d, 0xad, 0xd5, 0xef, 0x33, 0x20, 0x0d, 0x09, 0xf2, 0x63, 0x72, 0xdd, - 0xd5, 0xd3, 0xf5, 0x7e, 0xa3, 0xdb, 0xae, 0x65, 0xcc, 0xef, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, 0x9a, 0xb1, - 0x7d, 0xb4, 0xbc, 0x13, 0x6b, 0x8c, 0x17, 0xde, 0x03, 0x16, 0xa9, 0x32, 0x14, 0xb1, 0x48, 0xd5, 0x64, 0x5c, 0xa4, - 0x7e, 0x6d, 0x36, 0xc2, 0x93, 0x45, 0xe5, 0xa6, 0xef, 0x2c, 0xef, 0xd4, 0x2b, 0xba, 0xa8, 0x26, 0x6f, 0xea, 0xaa, - 0x0b, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x2d, 0x74, 0x79, 0x2d, 0x15, 0xe0, 0x48, 0x38, 0xf8, 0xa3, 0x34, - 0x0e, 0x57, 0x19, 0x6b, 0x06, 0x17, 0x01, 0xc7, 0x73, 0x0a, 0xe0, 0xe0, 0xef, 0xf2, 0x58, 0x3b, 0x40, 0x6e, 0xc3, - 0x36, 0x71, 0xfa, 0xe0, 0x71, 0xd8, 0x6a, 0x97, 0x87, 0x0e, 0x59, 0x72, 0xd0, 0x66, 0xc3, 0x44, 0x4c, 0xb8, 0x96, - 0x08, 0x7b, 0x6b, 0xb6, 0xcb, 0xd3, 0xa4, 0xd7, 0x55, 0x99, 0x94, 0x97, 0x27, 0xf3, 0xe7, 0x9c, 0xb1, 0x17, 0xcd, - 0x67, 0xec, 0x85, 0x38, 0x63, 0xdb, 0x77, 0xe6, 0xe3, 0xa9, 0x0b, 0xff, 0xf5, 0x8b, 0x09, 0xf5, 0x1c, 0xad, 0xbd, - 0xbc, 0xd3, 0xdc, 0xe5, 0x9d, 0x66, 0x79, 0xcb, 0x3b, 0x0d, 0x9b, 0x46, 0x7d, 0x10, 0xd3, 0xf6, 0x0c, 0xd3, 0xd1, - 0x20, 0x11, 0xfe, 0x38, 0xa5, 0x2c, 0xf7, 0x10, 0xf2, 0xa0, 0x56, 0xa7, 0x9e, 0xe7, 0x6d, 0x3f, 0xea, 0x74, 0x96, - 0x04, 0xd2, 0x36, 0xec, 0xcc, 0x1f, 0x8d, 0xd8, 0xa4, 0x37, 0x8d, 0xc7, 0xab, 0xf4, 0x5f, 0x7c, 0xfc, 0x1c, 0x88, - 0x5b, 0x11, 0x41, 0xa5, 0x1d, 0x51, 0x15, 0x04, 0x25, 0x37, 0x4c, 0xb4, 0xb0, 0x96, 0xeb, 0xd4, 0x23, 0xf7, 0xc8, - 0x9e, 0x7d, 0xd8, 0xb0, 0xc9, 0x9b, 0x01, 0xfd, 0xa7, 0xad, 0xd2, 0x66, 0x14, 0xf3, 0x05, 0x60, 0xd9, 0x0a, 0x8e, - 0x87, 0x43, 0x83, 0xaf, 0xa6, 0xd3, 0x6d, 0x1e, 0xee, 0xa5, 0xe8, 0xe9, 0x4a, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0x86, - 0x29, 0xdb, 0x5b, 0xdd, 0xb4, 0x47, 0x6a, 0xad, 0x6e, 0xb9, 0x10, 0x8a, 0xb2, 0x7b, 0x62, 0xf9, 0xc7, 0x2f, 0x0e, - 0xe1, 0x3f, 0xa2, 0xea, 0x7f, 0xcd, 0x9a, 0x08, 0xf5, 0xb7, 0x65, 0x4d, 0x70, 0x22, 0x95, 0x90, 0x10, 0xdf, 0xbf, - 0xfc, 0x74, 0xfa, 0xb0, 0x0a, 0x7b, 0x97, 0x26, 0x55, 0xaa, 0x6a, 0xe9, 0xef, 0xe3, 0x18, 0x42, 0x77, 0xd6, 0x8b, - 0x0b, 0xf0, 0x90, 0xb2, 0x7b, 0x36, 0x80, 0x4a, 0xe2, 0x1d, 0x41, 0x52, 0x7c, 0x1d, 0xeb, 0xd0, 0x53, 0xe2, 0xf5, - 0xa6, 0xa7, 0xc4, 0xab, 0xdd, 0x4f, 0x89, 0x1f, 0xf6, 0x7a, 0x4a, 0xbc, 0xfa, 0xea, 0x4f, 0x89, 0xd7, 0xf5, 0xa7, - 0xc4, 0x45, 0x2c, 0xf4, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x09, 0xe5, 0xce, 0xe3, 0x41, 0xc7, 0x21, 0x97, - 0xc7, 0x17, 0x7f, 0xf8, 0x61, 0x81, 0x1b, 0xf1, 0x3d, 0xaa, 0x93, 0x15, 0x4f, 0x0b, 0x8e, 0xd9, 0xb1, 0x1f, 0x25, - 0x39, 0x8c, 0xa3, 0xd9, 0xcf, 0x20, 0x94, 0x05, 0x76, 0x60, 0xa2, 0x64, 0x04, 0xe9, 0xcf, 0xf1, 0x72, 0xb5, 0x7c, - 0x0b, 0x6d, 0x7d, 0x0c, 0xd2, 0x60, 0x14, 0x32, 0x69, 0x89, 0x4c, 0xea, 0x6f, 0x9c, 0x27, 0x0e, 0x1a, 0xa7, 0xe2, - 0xa7, 0x7f, 0x27, 0x7e, 0xa2, 0x4e, 0x2a, 0xff, 0x4d, 0x7a, 0x75, 0x7a, 0xf3, 0x43, 0x44, 0x08, 0x01, 0x95, 0x41, - 0x3f, 0xfc, 0x31, 0x72, 0x11, 0x1b, 0x0d, 0xb3, 0x14, 0xfa, 0x0e, 0x1b, 0xdb, 0x61, 0xb5, 0x47, 0xcd, 0xca, 0x30, - 0xa5, 0x0b, 0xae, 0x3a, 0x1b, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x91, 0x01, 0x48, - 0x38, 0x65, 0x1d, 0x0c, 0x1e, 0xf9, 0x01, 0x09, 0xe5, 0x38, 0x69, 0xe9, 0x10, 0xbb, 0x74, 0xb5, 0xb4, 0x48, 0xd4, - 0x6c, 0xe1, 0x14, 0x75, 0x19, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0x56, 0x53, 0xa8, 0x6a, 0xc4, 0x36, 0xe7, - 0x0a, 0xa7, 0xad, 0x48, 0x30, 0x17, 0x85, 0x1f, 0x8c, 0x86, 0x85, 0xe3, 0x39, 0x64, 0xba, 0x5a, 0xe4, 0x82, 0x17, - 0x91, 0x7c, 0xc5, 0xd7, 0x83, 0x7b, 0x85, 0xa0, 0xcf, 0x97, 0x0a, 0x18, 0xdf, 0xdd, 0xb0, 0x24, 0xf4, 0xef, 0x5b, - 0x46, 0x1e, 0x47, 0x3f, 0x02, 0x00, 0x5e, 0xc5, 0xb7, 0x91, 0x5a, 0x00, 0x83, 0xb5, 0x34, 0xec, 0xa5, 0x46, 0xff, - 0x25, 0x60, 0xb8, 0xa2, 0x8c, 0x00, 0xc2, 0xe4, 0xce, 0xd8, 0xdf, 0x4d, 0xfa, 0xf7, 0x1f, 0x46, 0x6e, 0x9e, 0xc7, - 0xb2, 0xa3, 0x5f, 0x96, 0x7b, 0x74, 0xf3, 0xf4, 0xe9, 0xa3, 0xcd, 0xd3, 0x2e, 0x87, 0x67, 0x6f, 0xa8, 0x6d, 0x6c, - 0x3c, 0x05, 0x30, 0x8a, 0x8b, 0x78, 0x35, 0x9e, 0xa3, 0xa2, 0xeb, 0xd7, 0x9b, 0x6f, 0x06, 0x6d, 0x62, 0x94, 0x52, - 0x39, 0xf5, 0x4a, 0x52, 0x01, 0x05, 0xec, 0xff, 0x35, 0x38, 0xe0, 0xfc, 0x1f, 0x82, 0xa1, 0xbe, 0x6b, 0xf8, 0x2b, - 0x3e, 0x78, 0xd8, 0xe6, 0xed, 0x43, 0x30, 0x4d, 0xee, 0xda, 0x42, 0x08, 0xd7, 0x9a, 0x91, 0x4c, 0x5e, 0x05, 0x9a, - 0xea, 0x46, 0x6e, 0x93, 0x87, 0x3c, 0xd1, 0x0b, 0xb3, 0xe9, 0x99, 0xce, 0x0d, 0x0d, 0x4c, 0xc6, 0xb1, 0x55, 0x05, - 0xc9, 0x70, 0x95, 0x07, 0x86, 0xe8, 0xab, 0x9a, 0xb7, 0x08, 0x22, 0x13, 0xbd, 0xc0, 0xd7, 0x73, 0xfc, 0x3b, 0xf0, - 0x83, 0x0c, 0xc8, 0xad, 0x9a, 0x05, 0x89, 0xa6, 0x6a, 0x37, 0x07, 0xa1, 0x9e, 0xf4, 0x46, 0x48, 0x08, 0x29, 0xde, - 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0xf9, 0x8c, 0xd0, 0xe4, 0x3b, 0x02, 0xd3, 0xf1, 0x39, 0x00, 0xd2, 0x92, 0x7c, 0x79, - 0x47, 0x29, 0xf0, 0x32, 0x40, 0x99, 0xac, 0x48, 0xe0, 0xae, 0xfe, 0x3a, 0x8e, 0x48, 0x10, 0x0f, 0x7a, 0x70, 0xd3, - 0xe6, 0x27, 0xe0, 0x11, 0xb8, 0xa7, 0xe1, 0x83, 0x1d, 0x73, 0x39, 0x27, 0x58, 0x73, 0xe8, 0x73, 0xd8, 0x67, 0xcd, - 0x3e, 0xe1, 0x22, 0x05, 0x0b, 0x82, 0xd4, 0xa1, 0xe2, 0xe2, 0xd9, 0x64, 0x0d, 0xb8, 0x11, 0xdf, 0x45, 0x77, 0xd9, - 0x82, 0x45, 0x2b, 0x1d, 0x63, 0x42, 0xa1, 0x8f, 0x3e, 0x28, 0xf3, 0x8a, 0x88, 0x2d, 0xc0, 0x36, 0xcd, 0x35, 0xe7, - 0x74, 0x17, 0xa6, 0x1c, 0xa5, 0xfa, 0xe6, 0x98, 0x0b, 0x36, 0x53, 0x8e, 0xdb, 0xaa, 0x37, 0x04, 0x5f, 0xd2, 0xb8, - 0x6a, 0xc8, 0x45, 0x9a, 0xd0, 0xd0, 0x06, 0x79, 0xc7, 0xe0, 0xec, 0x22, 0x01, 0xf6, 0x96, 0x5f, 0x5d, 0x34, 0x29, - 0x91, 0xf1, 0x2b, 0x8c, 0xa2, 0xc4, 0xa8, 0x37, 0xc3, 0xc7, 0x09, 0x8e, 0x89, 0x36, 0xb6, 0x33, 0xae, 0xb5, 0xb3, - 0x61, 0xd2, 0x9f, 0xd8, 0x3d, 0x5d, 0x24, 0x04, 0xaa, 0x4f, 0xec, 0x1e, 0x74, 0xff, 0x5e, 0x03, 0x37, 0x45, 0xdf, - 0x82, 0xae, 0x4d, 0x70, 0xf5, 0x3f, 0x06, 0x67, 0x55, 0x5b, 0x0e, 0x90, 0x93, 0x6f, 0xc1, 0xe2, 0x08, 0x62, 0x88, - 0xea, 0x2c, 0x0e, 0x31, 0x57, 0xf1, 0x6f, 0x35, 0xc2, 0xd8, 0x6a, 0x38, 0x1a, 0xc6, 0x33, 0xd7, 0x71, 0x0e, 0x6a, - 0xe5, 0x81, 0x91, 0xdd, 0x54, 0xda, 0x30, 0xb3, 0x81, 0xeb, 0x58, 0xc1, 0x33, 0xdb, 0xeb, 0xd7, 0xee, 0x68, 0xc5, - 0x97, 0xe4, 0x10, 0xd9, 0x5f, 0xa7, 0x4f, 0xd6, 0xad, 0xda, 0x81, 0x34, 0xaa, 0x2a, 0xf3, 0x38, 0xb6, 0x9c, 0xf3, - 0xbf, 0x86, 0xf5, 0xab, 0x9f, 0x3c, 0x59, 0x52, 0x5c, 0x93, 0x21, 0x78, 0x43, 0x6e, 0xc1, 0x31, 0xfa, 0x8b, 0xf6, - 0x5c, 0x6b, 0xd1, 0xf1, 0x31, 0x8c, 0xa1, 0x0c, 0x97, 0x2d, 0x6c, 0xca, 0xd4, 0x06, 0x2a, 0x3d, 0xa6, 0x55, 0x0c, - 0xc7, 0xfd, 0xae, 0xb2, 0x42, 0xa2, 0xb7, 0x95, 0x5a, 0xc0, 0xf6, 0x37, 0x5c, 0x9f, 0xf6, 0x08, 0xfc, 0x12, 0x40, - 0x09, 0xf0, 0x9d, 0xbe, 0xb3, 0xc1, 0xd5, 0xb2, 0xdc, 0x5c, 0xf9, 0x92, 0xdc, 0xbf, 0x31, 0xbc, 0x74, 0x50, 0x86, - 0x26, 0xdb, 0x6b, 0xbe, 0xee, 0x1e, 0xd8, 0x24, 0x8b, 0x26, 0xe5, 0x06, 0x2b, 0xf7, 0xd7, 0xfe, 0xcd, 0x95, 0x30, - 0x0a, 0x04, 0x15, 0x88, 0x1b, 0x30, 0x4a, 0x1e, 0x47, 0xb8, 0xf9, 0xe9, 0xb8, 0x05, 0x7b, 0x51, 0x31, 0x58, 0x81, - 0x3c, 0x82, 0xc9, 0x6a, 0x0a, 0x53, 0x1c, 0x3c, 0x57, 0xa3, 0x59, 0x70, 0x4b, 0x10, 0xa2, 0x1b, 0x77, 0x62, 0x26, - 0x74, 0x0a, 0x8b, 0x3a, 0x01, 0xf7, 0x45, 0xb9, 0x2f, 0xd7, 0x3a, 0xd8, 0xcd, 0xb5, 0xce, 0x76, 0x71, 0xad, 0xc9, - 0x9c, 0xea, 0x36, 0xf1, 0x97, 0x8a, 0x45, 0x9e, 0x20, 0xce, 0x55, 0xc3, 0xbc, 0x12, 0xab, 0x1b, 0xad, 0xaf, 0x44, - 0xad, 0x5a, 0x6b, 0xa4, 0x25, 0x88, 0xec, 0x6f, 0xe5, 0x81, 0x22, 0x04, 0xea, 0x2a, 0x6f, 0xfc, 0xa2, 0xe0, 0x8d, - 0xd3, 0xab, 0xa6, 0x30, 0xa4, 0x11, 0xd4, 0xbf, 0x62, 0xa4, 0x26, 0x5f, 0x07, 0x85, 0xb1, 0x5a, 0x31, 0x52, 0xc5, - 0xfc, 0xaa, 0x78, 0x68, 0x28, 0x46, 0x7d, 0xe2, 0x95, 0x51, 0xb6, 0xed, 0x2b, 0x17, 0x2d, 0xac, 0xaf, 0x8a, 0x74, - 0xe0, 0xba, 0xe3, 0x90, 0x65, 0xb2, 0xba, 0x6d, 0xca, 0xe6, 0x37, 0x6a, 0xb6, 0xb2, 0x49, 0xa4, 0x9d, 0x0c, 0x01, - 0x58, 0xb0, 0xe9, 0x2b, 0x72, 0x6d, 0xa9, 0x03, 0x81, 0x83, 0x6c, 0x30, 0xeb, 0xdb, 0xcd, 0x9d, 0xa7, 0x78, 0x09, - 0x85, 0x14, 0x5e, 0xe5, 0x41, 0x20, 0x7c, 0xaf, 0xd6, 0x0d, 0xb7, 0x3c, 0x5e, 0xf2, 0xfc, 0x7e, 0x07, 0xf6, 0xa2, - 0xe6, 0xa8, 0x82, 0x7c, 0x3c, 0x99, 0x16, 0xa9, 0xe7, 0x62, 0xd1, 0x7a, 0xa3, 0xc4, 0xc4, 0x59, 0x73, 0xcb, 0x98, - 0x32, 0x8f, 0x9e, 0x97, 0xe8, 0x89, 0x7e, 0xf9, 0xd6, 0x49, 0x56, 0x11, 0xfa, 0xb6, 0xb7, 0xb2, 0xc4, 0x1f, 0x7f, - 0x52, 0x86, 0x2c, 0xf8, 0x9c, 0xc0, 0x03, 0x2e, 0x4b, 0x0a, 0xfa, 0x3e, 0xba, 0x82, 0x64, 0x3d, 0xdb, 0x4b, 0x15, - 0xee, 0x4b, 0xef, 0xb1, 0xd3, 0xf6, 0x5f, 0x4c, 0x0f, 0x2b, 0x4c, 0x51, 0xaf, 0x53, 0x66, 0x99, 0x6f, 0x18, 0x47, - 0x36, 0x5f, 0x2d, 0x46, 0x6b, 0x95, 0xb7, 0xaa, 0xb0, 0x5c, 0xeb, 0x6c, 0x56, 0xb5, 0xdb, 0xe9, 0x74, 0x5a, 0x66, - 0x34, 0x3a, 0xda, 0x21, 0x32, 0x0b, 0x1f, 0x3b, 0x8e, 0x53, 0x1d, 0xfb, 0x76, 0xb0, 0x5b, 0xc8, 0xb7, 0xed, 0x36, - 0x8e, 0x18, 0x61, 0xbb, 0x0b, 0x7e, 0x75, 0x70, 0xe4, 0x76, 0x71, 0xb2, 0x4b, 0x6a, 0x11, 0x7d, 0x52, 0x86, 0x08, - 0x32, 0xb6, 0x48, 0x7b, 0x63, 0x86, 0x32, 0x18, 0x5b, 0x39, 0xd0, 0xa8, 0x38, 0x60, 0xcd, 0x40, 0x55, 0xc4, 0x15, - 0xbb, 0xc2, 0xd1, 0x90, 0x1f, 0x5e, 0x63, 0xde, 0x8b, 0x4e, 0xf0, 0xa0, 0xac, 0xeb, 0x3c, 0x6d, 0x9c, 0x56, 0xc7, - 0xf9, 0x4b, 0xa9, 0x9c, 0x06, 0x17, 0xe0, 0x5a, 0x08, 0xb4, 0x89, 0x3f, 0x8b, 0x7f, 0x4b, 0xfe, 0xff, 0x8b, 0xe5, - 0x5d, 0x59, 0x7f, 0xa4, 0x0b, 0x1c, 0xed, 0xe2, 0xb4, 0xd0, 0xa8, 0x9b, 0xf6, 0x80, 0xd4, 0x32, 0x98, 0xaa, 0x02, - 0x74, 0x10, 0xd2, 0x97, 0x02, 0x80, 0x34, 0xb0, 0xdf, 0x91, 0x62, 0x86, 0x25, 0x2e, 0x58, 0x88, 0x45, 0xf8, 0x3a, - 0x98, 0x83, 0xf9, 0xbc, 0x8b, 0xf2, 0x83, 0xd2, 0x9e, 0x00, 0x69, 0x7c, 0x6d, 0x6e, 0x7b, 0xb1, 0xfb, 0xab, 0x72, - 0x2d, 0xd1, 0x30, 0x80, 0xcc, 0x85, 0x43, 0x88, 0x8a, 0x04, 0x5a, 0x65, 0x73, 0xd3, 0x28, 0x65, 0xae, 0x2a, 0x67, - 0x13, 0x03, 0xc3, 0xe6, 0x9a, 0x8b, 0x50, 0xdb, 0x42, 0x5a, 0x00, 0x93, 0xe5, 0xdb, 0x0f, 0xbf, 0x2d, 0x58, 0x62, - 0x75, 0x3f, 0xba, 0xb8, 0xe4, 0xb8, 0x7f, 0x2d, 0xbc, 0x3b, 0x53, 0x3a, 0xff, 0xc8, 0x5f, 0xfc, 0xa1, 0x91, 0xa1, - 0x77, 0x51, 0xe2, 0xd0, 0x71, 0x6d, 0x71, 0xcf, 0xd8, 0xab, 0xf4, 0x22, 0x88, 0xf6, 0x2f, 0xeb, 0xdf, 0xed, 0x5d, - 0x16, 0x2e, 0x8c, 0xbd, 0x0b, 0xc3, 0x8d, 0x43, 0x9a, 0x0b, 0xd9, 0xe0, 0x07, 0x85, 0xa1, 0xa8, 0x5a, 0x1d, 0xeb, - 0x58, 0x8b, 0xa8, 0xfc, 0x8b, 0xd5, 0x60, 0x78, 0x72, 0x76, 0xb7, 0x08, 0xb5, 0x1b, 0x96, 0x40, 0x68, 0x9f, 0x81, - 0xee, 0xda, 0x8e, 0xae, 0xa1, 0x0d, 0x6d, 0x10, 0xcd, 0x06, 0xfa, 0x2f, 0x17, 0x6f, 0xac, 0xae, 0x7e, 0x06, 0x22, - 0xda, 0x9b, 0x19, 0x5e, 0x7b, 0xe7, 0xfe, 0x3d, 0x4b, 0xae, 0x3d, 0x5d, 0xc3, 0x08, 0x3e, 0x74, 0xe1, 0x61, 0x9a, - 0xe6, 0xe9, 0x7b, 0x04, 0x8a, 0xd0, 0x44, 0xac, 0x37, 0x1d, 0x50, 0x8e, 0xeb, 0x75, 0x35, 0xd7, 0x3b, 0xb4, 0x8f, - 0xba, 0xfa, 0xe9, 0x37, 0x9a, 0x76, 0x32, 0x61, 0xd3, 0xf4, 0x14, 0x9f, 0x68, 0x27, 0x78, 0x47, 0xd0, 0x6f, 0x4d, - 0xb3, 0xc7, 0x61, 0x6a, 0xb9, 0xda, 0x9a, 0x7f, 0x6a, 0xda, 0x34, 0x08, 0xc3, 0x9e, 0xf6, 0x78, 0xea, 0x4d, 0x0f, - 0xa7, 0x2f, 0xfa, 0x3c, 0x39, 0xff, 0xa6, 0x54, 0xdc, 0xa4, 0x7f, 0x3d, 0xa5, 0x5a, 0x9a, 0x25, 0xf1, 0x27, 0xc6, - 0xd5, 0x4e, 0x34, 0xf9, 0x78, 0xac, 0x56, 0xf5, 0xea, 0x3d, 0xb9, 0xdd, 0xd1, 0x78, 0xea, 0x15, 0xc5, 0x71, 0x8c, - 0x07, 0x72, 0x90, 0x27, 0x07, 0x62, 0xe8, 0x27, 0x2a, 0x98, 0x5c, 0xab, 0x09, 0x50, 0xae, 0xce, 0xe7, 0x38, 0x13, - 0xf3, 0x3b, 0x01, 0x3f, 0x8c, 0xd2, 0x5c, 0x17, 0x46, 0xa0, 0x6b, 0x93, 0x81, 0xfe, 0xa3, 0xeb, 0x75, 0x4d, 0xd7, - 0x3d, 0xb2, 0x8f, 0xba, 0x63, 0xc7, 0x3c, 0xb4, 0x0f, 0xad, 0xb6, 0x7d, 0x64, 0x76, 0xad, 0xae, 0xd9, 0xfd, 0x5b, - 0x77, 0x6c, 0x1d, 0xda, 0x87, 0xa6, 0x63, 0x75, 0x21, 0xd1, 0xea, 0x5a, 0xdd, 0x1b, 0xeb, 0xb0, 0x3b, 0x76, 0x30, - 0xd5, 0xb3, 0x3b, 0x1d, 0xcb, 0x75, 0xec, 0x4e, 0xc7, 0xec, 0xd8, 0x47, 0x47, 0x96, 0xdb, 0xb6, 0x8f, 0x8e, 0xce, - 0x3b, 0x5d, 0xbb, 0x0d, 0x79, 0xed, 0xf6, 0xb8, 0x6d, 0xbb, 0xae, 0x05, 0x7f, 0x99, 0x5d, 0xdb, 0xa3, 0x1f, 0xae, - 0x6b, 0xb7, 0x5d, 0xd3, 0x09, 0x3b, 0x9e, 0x7d, 0xf4, 0xc2, 0xc4, 0xbf, 0xb1, 0x98, 0x89, 0x7f, 0x41, 0x33, 0xe6, - 0x0b, 0xdb, 0x3b, 0xa2, 0x5f, 0xd8, 0xe0, 0xcd, 0x61, 0xf7, 0x57, 0xfd, 0x60, 0xe3, 0x1c, 0x5c, 0x9a, 0x43, 0xb7, - 0x63, 0xb7, 0xdb, 0xe6, 0xa1, 0x6b, 0x77, 0xdb, 0x73, 0xeb, 0xd0, 0xb3, 0x8f, 0x8e, 0xc7, 0x96, 0x6b, 0x1f, 0x1f, - 0x9b, 0x8e, 0xd5, 0xb6, 0x3d, 0xd3, 0xb5, 0x0f, 0xdb, 0xf8, 0xa3, 0x6d, 0x7b, 0x37, 0xc7, 0x2f, 0xec, 0xa3, 0xce, - 0xfc, 0xc8, 0x3e, 0xfc, 0x78, 0xd8, 0xb5, 0xbd, 0xf6, 0xbc, 0x7d, 0x64, 0x7b, 0xc7, 0x37, 0x47, 0xf6, 0xe1, 0xdc, - 0xf2, 0x8e, 0xb6, 0xd6, 0x74, 0x3d, 0x1b, 0x60, 0x84, 0xd9, 0x90, 0x61, 0xf2, 0x0c, 0xf8, 0x33, 0xc7, 0xba, 0xff, - 0xc5, 0x66, 0xd2, 0x7a, 0xd5, 0x17, 0x76, 0xf7, 0x78, 0x4c, 0xc5, 0x21, 0xc1, 0x12, 0x25, 0xa0, 0xca, 0x8d, 0x45, - 0xdd, 0x62, 0x73, 0x96, 0x68, 0x48, 0xfc, 0xe1, 0x9d, 0xdd, 0x58, 0xd0, 0x31, 0xf5, 0xfb, 0x3f, 0x6d, 0x47, 0x2e, - 0x39, 0x44, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x41, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x41, 0xc5, 0xfb, 0xdd, 0x82, 0x8a, - 0x37, 0xab, 0x7d, 0x04, 0x15, 0xef, 0xbf, 0xba, 0xa0, 0xe2, 0xbc, 0xaa, 0x27, 0xff, 0xbe, 0xea, 0x9b, 0xfe, 0xd7, - 0x75, 0xf5, 0x19, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x78, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, 0x4a, 0x4a, - 0x60, 0x31, 0xe0, 0xd8, 0xf7, 0x31, 0xe1, 0xd8, 0xdf, 0x57, 0x03, 0xd0, 0x3c, 0xe1, 0x74, 0x49, 0x30, 0xb1, 0xe6, - 0x7e, 0x38, 0x95, 0x34, 0x0d, 0xa4, 0xf4, 0x31, 0x19, 0xac, 0x12, 0xe0, 0xba, 0x06, 0x71, 0xd8, 0x6a, 0x11, 0xa5, - 0xbd, 0x23, 0x07, 0x2e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xca, 0xb6, 0xf0, 0x47, 0x75, 0xcd, 0xad, 0x26, 0x36, 0xe6, - 0xa3, 0x52, 0x60, 0x73, 0xeb, 0x6e, 0xbd, 0x5d, 0x0d, 0xb4, 0x6d, 0x84, 0xd2, 0x24, 0x90, 0x73, 0x4d, 0xf9, 0x65, - 0xd5, 0xbc, 0x8a, 0x32, 0xe6, 0xe6, 0x91, 0xc2, 0x48, 0xaa, 0xf5, 0xdd, 0xb2, 0x6a, 0xdf, 0xae, 0x69, 0x36, 0x74, - 0x5f, 0xaa, 0xbe, 0x45, 0xaf, 0x50, 0x36, 0x5c, 0x05, 0x55, 0x25, 0xb2, 0x5a, 0x23, 0x40, 0x0a, 0xea, 0xbe, 0x50, - 0x3e, 0x2c, 0x48, 0x4b, 0x47, 0x43, 0x7a, 0xc7, 0x51, 0xf2, 0x4a, 0x6d, 0xaa, 0x0a, 0x8b, 0xcf, 0xd6, 0x48, 0x71, - 0x07, 0xbf, 0x03, 0xe9, 0xc8, 0x29, 0x9e, 0x51, 0xac, 0xc2, 0x79, 0xad, 0xb4, 0x4b, 0x8f, 0x99, 0x7c, 0xee, 0xae, - 0xeb, 0xc4, 0xe3, 0x46, 0x55, 0x65, 0x97, 0x2d, 0x04, 0x15, 0x84, 0xdd, 0x93, 0x62, 0x70, 0x4e, 0xca, 0xdb, 0xa8, - 0xfb, 0xbc, 0xad, 0x31, 0x51, 0xee, 0x31, 0x6c, 0x62, 0x93, 0x7f, 0xa8, 0x7e, 0x01, 0xd6, 0x53, 0x88, 0x82, 0xdd, - 0x43, 0x32, 0x4d, 0xa1, 0x51, 0x3d, 0xd4, 0x62, 0xee, 0x6f, 0x51, 0xb0, 0x51, 0x1b, 0xe6, 0x8d, 0xa0, 0x36, 0xf4, - 0x36, 0x9d, 0x1c, 0x69, 0x3c, 0xb2, 0x2e, 0x89, 0xa8, 0xdd, 0xce, 0xb1, 0xe9, 0x1e, 0x99, 0xf6, 0x71, 0xc7, 0xc8, - 0xc5, 0x81, 0x53, 0x9b, 0x2c, 0x01, 0x04, 0x94, 0xa2, 0xe5, 0x30, 0x83, 0x28, 0xc8, 0x02, 0x3f, 0xcc, 0x81, 0x3e, - 0x2e, 0xbf, 0x2a, 0xfe, 0xb9, 0x4a, 0x33, 0x98, 0xa3, 0x20, 0x7a, 0x51, 0x21, 0xdc, 0x1a, 0xb1, 0xec, 0x96, 0xb1, - 0x68, 0x83, 0xb0, 0xbc, 0xaa, 0x5f, 0xfe, 0xe7, 0x69, 0xdb, 0xe6, 0xa4, 0xc9, 0x32, 0xca, 0x22, 0xbe, 0x3f, 0x84, - 0x32, 0x74, 0x3e, 0x34, 0x7f, 0xda, 0x84, 0x70, 0xff, 0xb9, 0x1b, 0xe1, 0x66, 0x6c, 0x1f, 0x84, 0xfb, 0xcf, 0xaf, - 0x8e, 0x70, 0x7f, 0x52, 0x11, 0x6e, 0xc9, 0x16, 0xa8, 0xe0, 0x3a, 0x7f, 0xc0, 0xef, 0x16, 0x38, 0x75, 0x7e, 0xae, - 0x1f, 0x10, 0x01, 0xaf, 0x2b, 0xc1, 0x76, 0x3f, 0x96, 0xa2, 0x07, 0x21, 0x53, 0x04, 0x9d, 0xd0, 0x52, 0xa4, 0x12, - 0x08, 0x44, 0x2b, 0x43, 0xaa, 0x43, 0x9b, 0x6f, 0xa3, 0x2c, 0xb4, 0xdf, 0xf3, 0x87, 0x1f, 0x08, 0x79, 0xde, 0xc4, - 0xc9, 0xc2, 0x47, 0x07, 0x7c, 0x3a, 0x46, 0x1d, 0x84, 0x0f, 0x07, 0xec, 0xcf, 0xc6, 0x71, 0x34, 0x91, 0x92, 0x0a, - 0x36, 0xb8, 0x24, 0x8a, 0x5b, 0xbf, 0x67, 0x7e, 0xa2, 0x9b, 0x94, 0x0d, 0x8b, 0xfb, 0xac, 0xed, 0x3c, 0xf3, 0x0e, - 0x9f, 0x1d, 0x39, 0xf0, 0xbf, 0xcb, 0xda, 0xb9, 0xc9, 0x0b, 0x2e, 0xe2, 0x08, 0x02, 0x9f, 0x88, 0x92, 0x9b, 0x8a, - 0xdd, 0x32, 0xf6, 0xa9, 0x28, 0x75, 0xdc, 0x5c, 0x68, 0xe2, 0xdf, 0x17, 0x65, 0x1a, 0x4b, 0xcc, 0xe3, 0x95, 0x32, - 0xac, 0x86, 0xd1, 0x04, 0xd1, 0x0a, 0x78, 0x6f, 0x4a, 0x09, 0x35, 0x9b, 0x4f, 0xb7, 0x98, 0x17, 0x6b, 0xe7, 0x57, - 0x45, 0x74, 0x25, 0x11, 0xe5, 0x65, 0x27, 0x04, 0xb9, 0xd8, 0xc2, 0x41, 0xdf, 0xec, 0x18, 0x5f, 0x48, 0x83, 0xd8, - 0x86, 0x62, 0x81, 0x7c, 0x5a, 0xa0, 0x2c, 0x59, 0x45, 0xe3, 0x16, 0xfe, 0xf4, 0x47, 0x69, 0x2b, 0x38, 0x00, 0xef, - 0xac, 0xd8, 0xb1, 0x81, 0xab, 0xe6, 0x9f, 0x3a, 0x45, 0x28, 0x8a, 0x54, 0xac, 0x8a, 0xff, 0x2c, 0x33, 0x13, 0x0a, - 0x60, 0x8b, 0x4b, 0x6b, 0x0d, 0xfc, 0x67, 0xb2, 0xe2, 0xb3, 0xcc, 0x84, 0x20, 0xb2, 0xb0, 0xdc, 0x4f, 0x9f, 0x52, - 0x29, 0x08, 0xeb, 0x48, 0xd3, 0x3a, 0x1b, 0x17, 0xee, 0xdd, 0x34, 0x7f, 0x16, 0x93, 0x87, 0xb7, 0xde, 0xd8, 0x8c, - 0x9f, 0x3f, 0x3f, 0x1d, 0xb8, 0x06, 0x0f, 0x4a, 0x5a, 0x8a, 0xa0, 0x75, 0xbe, 0x9f, 0xf2, 0x81, 0xd1, 0x68, 0x16, - 0xb7, 0x84, 0x37, 0x93, 0x23, 0x54, 0x94, 0x39, 0xf6, 0x82, 0x88, 0x16, 0x24, 0x64, 0xf4, 0x85, 0x12, 0x80, 0x28, - 0x23, 0x5f, 0x5d, 0x6d, 0xdb, 0xb1, 0x1d, 0x5d, 0x56, 0x9c, 0x06, 0xb3, 0xc1, 0x3a, 0xce, 0x7c, 0x88, 0x0d, 0x14, - 0xc6, 0x33, 0xb0, 0xad, 0xc9, 0x82, 0x2c, 0x84, 0x40, 0x33, 0x60, 0x64, 0xb3, 0xa0, 0x77, 0x79, 0xce, 0x35, 0x9e, - 0xfd, 0xe4, 0x13, 0x06, 0x1b, 0x14, 0x66, 0x75, 0xe8, 0x71, 0xe8, 0x47, 0xb8, 0x0c, 0x5b, 0x7a, 0x0b, 0x42, 0x5d, - 0xb2, 0x24, 0xb5, 0x54, 0x0b, 0x82, 0x9e, 0x06, 0x75, 0x20, 0x0c, 0x3d, 0x36, 0x30, 0x4d, 0xfc, 0x05, 0xf8, 0x64, - 0x5f, 0xe7, 0x26, 0xc7, 0xb4, 0x3a, 0x47, 0xb5, 0x9a, 0xfb, 0xe2, 0xc8, 0xd4, 0x3c, 0xd7, 0xd4, 0x1c, 0x40, 0xb7, - 0x7a, 0x6e, 0xae, 0xf3, 0xab, 0xfe, 0x2e, 0x21, 0x28, 0xe1, 0x97, 0xc7, 0x34, 0x0f, 0x12, 0x7f, 0x72, 0xf6, 0x72, - 0x46, 0x0e, 0x24, 0x5b, 0x8a, 0xb7, 0xf4, 0x80, 0x04, 0x21, 0x17, 0xec, 0x2e, 0x33, 0x30, 0x10, 0x0b, 0x2f, 0x12, - 0x18, 0x6b, 0x34, 0xfe, 0x0b, 0x22, 0x2d, 0xf8, 0xfc, 0xb9, 0x15, 0x80, 0x81, 0xc3, 0x40, 0x81, 0x0f, 0x7c, 0x1b, - 0x25, 0x80, 0x05, 0x85, 0xe8, 0x0e, 0x81, 0x05, 0xd6, 0x47, 0xf0, 0x6f, 0x91, 0x2c, 0x7e, 0x70, 0xd1, 0xa9, 0x1d, - 0xfa, 0xd1, 0x0c, 0x50, 0x9a, 0x1f, 0xcd, 0x6a, 0x2a, 0x1a, 0x64, 0xbf, 0x58, 0x49, 0x2d, 0x9a, 0x2a, 0xd4, 0x27, - 0xd2, 0xef, 0xef, 0x2f, 0x28, 0xd0, 0x14, 0x04, 0x35, 0xf7, 0x27, 0x68, 0x6c, 0x57, 0x48, 0x77, 0x9e, 0x0f, 0xbe, - 0x3d, 0x59, 0xb0, 0xcc, 0x27, 0xd6, 0x30, 0x3c, 0x7e, 0x81, 0x1c, 0xd0, 0xc6, 0x22, 0x48, 0x2c, 0x05, 0x93, 0x9f, - 0xb0, 0x9b, 0x60, 0xcc, 0xdf, 0xa5, 0xa6, 0xc6, 0xef, 0x29, 0x0b, 0xb5, 0xc0, 0x06, 0xae, 0x49, 0x4a, 0xc8, 0x63, - 0x1f, 0xdd, 0x4c, 0x0e, 0xa2, 0x58, 0x3f, 0xfd, 0x56, 0xda, 0x6b, 0x6d, 0x5a, 0x04, 0x88, 0xf6, 0x78, 0x99, 0xb0, - 0xf0, 0x5f, 0x83, 0x6f, 0xe1, 0xe2, 0xfe, 0xf6, 0x4a, 0x37, 0xfa, 0x99, 0x3d, 0x4f, 0xd8, 0x74, 0xf0, 0x6d, 0x43, - 0xd4, 0x43, 0x7c, 0xde, 0xd3, 0x58, 0xf4, 0xb6, 0x57, 0x38, 0x07, 0x6a, 0xef, 0xf5, 0xa8, 0x3f, 0xe5, 0xaf, 0x75, - 0x78, 0x01, 0xae, 0x4b, 0x6f, 0x6c, 0xb7, 0x8f, 0xef, 0xe7, 0x51, 0xe8, 0x8f, 0x3f, 0xf5, 0x29, 0xa7, 0xf4, 0x61, - 0xc1, 0x6d, 0x3d, 0xf6, 0x97, 0x3d, 0xbc, 0x5e, 0xd5, 0x44, 0x30, 0xd7, 0xa4, 0x54, 0x49, 0xd9, 0x35, 0xee, 0x65, - 0xdc, 0xca, 0x6b, 0xec, 0x19, 0xbb, 0xba, 0x9d, 0x07, 0x19, 0x13, 0x5d, 0xe1, 0x47, 0x9e, 0x8b, 0x87, 0x3a, 0x3d, - 0x51, 0xf1, 0x61, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, 0x74, 0xbb, - 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, 0x3f, 0xba, - 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xb5, 0xe0, 0x01, 0x44, 0xef, 0x9d, 0x6f, 0x4b, 0x58, 0x40, 0xf9, - 0x2d, 0xe5, 0x34, 0x66, 0xe9, 0x7a, 0x6b, 0x90, 0xf5, 0x00, 0xca, 0xd0, 0x4d, 0xe1, 0x04, 0x32, 0xea, 0xb7, 0x20, - 0x0c, 0x3b, 0x06, 0x10, 0x10, 0x2a, 0x2f, 0xc2, 0x2e, 0x55, 0xb8, 0xd2, 0x6f, 0x3c, 0x46, 0xbc, 0x4e, 0xb3, 0xc3, - 0x75, 0x11, 0x99, 0x8a, 0x84, 0x43, 0xbf, 0x2c, 0xd1, 0x89, 0x91, 0x70, 0x11, 0xaf, 0x60, 0xa5, 0x22, 0x3a, 0x62, - 0xbe, 0x7b, 0xe0, 0x68, 0x99, 0xcb, 0x64, 0x74, 0x9e, 0xaf, 0xda, 0x36, 0x17, 0x18, 0xc9, 0xd6, 0xff, 0x68, 0x3b, - 0x18, 0x94, 0x96, 0xda, 0x11, 0xde, 0x5c, 0x27, 0x41, 0x22, 0x87, 0xa7, 0xa0, 0x68, 0xb7, 0xd9, 0x53, 0xbd, 0x01, - 0x61, 0x4c, 0xde, 0x02, 0x95, 0x7c, 0xe3, 0x87, 0x8a, 0x72, 0x8b, 0x52, 0xf3, 0x91, 0xc4, 0xfc, 0x4f, 0x9f, 0x16, - 0x83, 0xb3, 0x2a, 0xe3, 0x3e, 0x71, 0x3b, 0x70, 0xed, 0x76, 0x58, 0x7b, 0xab, 0x9e, 0xd5, 0x6e, 0x77, 0xc0, 0x85, - 0xbb, 0x50, 0xa1, 0x4b, 0x21, 0xa4, 0xb8, 0x1b, 0x95, 0xbd, 0x6a, 0x32, 0x5c, 0x70, 0xa4, 0x5c, 0x79, 0xea, 0xe8, - 0x46, 0x3f, 0x12, 0x22, 0xc9, 0x68, 0x8b, 0x0b, 0x64, 0xfe, 0x16, 0xd3, 0x01, 0x34, 0x5b, 0xe6, 0xb1, 0xc3, 0x68, - 0xf4, 0x7f, 0x3d, 0x09, 0x34, 0xe0, 0x02, 0x19, 0x6a, 0xe5, 0xb4, 0x96, 0x0c, 0x7a, 0xe4, 0xbd, 0x4a, 0x17, 0x2a, - 0x4b, 0xcf, 0x74, 0x48, 0x82, 0xf8, 0x56, 0x18, 0xd2, 0x4e, 0x2a, 0x90, 0xc9, 0xdb, 0xa2, 0x48, 0x30, 0x03, 0xf0, - 0x01, 0xde, 0x12, 0xc6, 0x64, 0xc6, 0xd3, 0xa7, 0x1b, 0x2f, 0x21, 0x12, 0xd8, 0xab, 0x91, 0x3d, 0x75, 0x15, 0xbf, - 0xe9, 0x2a, 0x8a, 0x91, 0xed, 0x22, 0xd6, 0x10, 0x7a, 0x6f, 0xb4, 0xf7, 0xf0, 0xe7, 0x88, 0xf9, 0x99, 0xcd, 0x25, - 0x4d, 0x2d, 0xe5, 0x72, 0x37, 0x5d, 0xd6, 0x06, 0x8d, 0x37, 0xee, 0xeb, 0x8c, 0xfb, 0x12, 0x7c, 0xb2, 0xfe, 0xb8, - 0xe2, 0x96, 0xde, 0xd0, 0xc6, 0x67, 0xa7, 0x70, 0x4f, 0xf3, 0x2e, 0xf3, 0xc9, 0x87, 0x89, 0x7a, 0xe5, 0xc6, 0x99, - 0x2f, 0xe2, 0xc8, 0x00, 0x5d, 0xde, 0x6f, 0x14, 0xc9, 0x2a, 0xd6, 0xe0, 0xa7, 0xef, 0x2e, 0xbe, 0xd3, 0xf8, 0xfe, - 0x27, 0x09, 0x22, 0x3e, 0x64, 0x28, 0xea, 0xc1, 0x80, 0xa2, 0x1e, 0x68, 0x3c, 0x8c, 0x08, 0xc4, 0x0e, 0xc8, 0x0f, - 0x08, 0x82, 0xc8, 0x80, 0x26, 0xb9, 0xea, 0x62, 0x15, 0x66, 0xc1, 0xd2, 0x4f, 0xb2, 0x03, 0xa8, 0x6a, 0x01, 0x92, - 0xd3, 0x37, 0xd9, 0x88, 0x93, 0x68, 0x56, 0xb8, 0xd8, 0xcb, 0x22, 0x21, 0x9b, 0x9d, 0x06, 0xa1, 0x14, 0xcd, 0x8a, - 0x0e, 0xfc, 0xf1, 0x98, 0x2d, 0xb3, 0x81, 0xee, 0x2f, 0x21, 0xfa, 0x05, 0xfa, 0xb3, 0x3e, 0x88, 0xc7, 0x19, 0xcb, - 0xac, 0x34, 0x4b, 0x98, 0xbf, 0xd0, 0xa5, 0x2b, 0xd7, 0x7a, 0x7b, 0xe9, 0x6a, 0xb4, 0x08, 0x32, 0xe9, 0x0b, 0x91, - 0x26, 0x08, 0x42, 0x52, 0x18, 0xe2, 0xe9, 0x30, 0xe7, 0x20, 0x3c, 0x8f, 0x67, 0x95, 0x1d, 0x55, 0x50, 0x2e, 0x67, - 0xe8, 0x69, 0x97, 0x47, 0x3c, 0x98, 0xa0, 0xcd, 0xd3, 0x35, 0xb7, 0x6b, 0x97, 0x2e, 0x1b, 0xf5, 0xd3, 0x13, 0xfe, - 0xbc, 0xd5, 0xd0, 0x15, 0x83, 0xde, 0x71, 0xc0, 0x97, 0xf0, 0x26, 0x8b, 0xf7, 0x03, 0x5e, 0x18, 0xae, 0x26, 0x6a, - 0x19, 0xfd, 0xbc, 0xd3, 0x58, 0x2e, 0x80, 0x10, 0x2a, 0x09, 0xd1, 0xe7, 0xee, 0xa9, 0x34, 0xb1, 0xc2, 0x51, 0x21, - 0xad, 0xf4, 0xf9, 0xf3, 0xcb, 0xe1, 0x7f, 0xfe, 0x0d, 0xce, 0xe8, 0xe7, 0xae, 0xb0, 0x33, 0xbf, 0x54, 0x4b, 0x71, - 0xea, 0xd3, 0x1c, 0xa2, 0x02, 0x05, 0x9b, 0x08, 0xc7, 0x2b, 0x62, 0x6b, 0xe5, 0xc3, 0x2b, 0xe1, 0x4c, 0x0b, 0x02, - 0x4e, 0x18, 0xc2, 0x1a, 0x7e, 0x08, 0xcb, 0x3b, 0x14, 0x4e, 0x18, 0xb4, 0xdf, 0xee, 0xbe, 0x3f, 0x06, 0x67, 0xcb, - 0xb5, 0x38, 0x10, 0xca, 0x00, 0x71, 0x0f, 0x9d, 0x9e, 0xf8, 0x1a, 0x12, 0x2d, 0x48, 0x7e, 0xa4, 0xbd, 0x03, 0x98, - 0xe6, 0x3c, 0x5e, 0x30, 0x3b, 0x88, 0x0f, 0x6e, 0xd9, 0xc8, 0xf2, 0x97, 0x01, 0xc9, 0xea, 0x91, 0xef, 0xa6, 0x11, - 0xe5, 0x27, 0x45, 0xe0, 0x44, 0x5f, 0xe7, 0x05, 0x28, 0xe3, 0x02, 0x50, 0xf0, 0xd3, 0x3f, 0x2d, 0xfb, 0x67, 0xb4, - 0x45, 0x84, 0x80, 0x32, 0x96, 0x3f, 0x23, 0x37, 0x8b, 0xc2, 0xa3, 0x62, 0xf1, 0x61, 0xc5, 0xd3, 0xa9, 0xea, 0x53, - 0xd1, 0x2e, 0xf7, 0x2f, 0xa1, 0x52, 0xec, 0xd9, 0x78, 0x49, 0x3d, 0xd5, 0xbb, 0x90, 0x3f, 0x21, 0x3a, 0x32, 0x77, - 0xbf, 0x09, 0xe7, 0xb9, 0xe6, 0x9b, 0x51, 0x82, 0xe4, 0x31, 0x15, 0xe2, 0x88, 0xa2, 0xea, 0x09, 0x7c, 0x03, 0x69, - 0xf2, 0x68, 0x30, 0x20, 0x3c, 0x56, 0x45, 0x67, 0x00, 0xa5, 0x86, 0x68, 0x09, 0x30, 0xd9, 0x0c, 0x2a, 0x5a, 0x64, - 0x23, 0x87, 0x95, 0xaa, 0xd3, 0xa9, 0x8f, 0xf1, 0xc0, 0x17, 0xfb, 0xab, 0xb4, 0x03, 0x61, 0x67, 0xf1, 0x85, 0x05, - 0x04, 0x2e, 0xda, 0xa9, 0xe0, 0x71, 0xed, 0xaf, 0x84, 0xb2, 0xad, 0xd0, 0xbf, 0x8f, 0x15, 0xdd, 0x05, 0xee, 0xc6, - 0xe0, 0x1c, 0x53, 0x2f, 0x84, 0xf9, 0x60, 0xed, 0x24, 0x49, 0x8f, 0xf3, 0xf5, 0xd3, 0xa4, 0xba, 0x88, 0xdf, 0x75, - 0x98, 0xd4, 0xb2, 0xe5, 0xc9, 0x20, 0x76, 0xcc, 0x8b, 0x83, 0x56, 0xca, 0xc4, 0x73, 0x9f, 0x9f, 0x1c, 0xc0, 0xfc, - 0xc0, 0xf5, 0x42, 0x89, 0x32, 0x0a, 0x0c, 0xf0, 0xef, 0xe0, 0xa7, 0xa4, 0x7f, 0xf1, 0x76, 0x22, 0x88, 0x3a, 0x7c, - 0x39, 0x4a, 0xe7, 0xaf, 0xa5, 0x22, 0x75, 0x62, 0xc5, 0x69, 0xa6, 0xf2, 0x76, 0x47, 0x68, 0xf8, 0x7d, 0x85, 0xe1, - 0x19, 0xf2, 0x7e, 0xc6, 0x84, 0x65, 0xf3, 0x79, 0xb6, 0xc1, 0xf8, 0x79, 0x53, 0x11, 0x22, 0x58, 0xb7, 0x14, 0x28, - 0xf6, 0xf1, 0xb6, 0x52, 0x05, 0x69, 0x24, 0x8b, 0x2d, 0xfd, 0x96, 0xfe, 0x18, 0x77, 0x7c, 0xad, 0x34, 0xa6, 0x42, - 0xb9, 0xf3, 0x6c, 0x00, 0x45, 0x05, 0xb3, 0xdd, 0x5f, 0x2e, 0xa9, 0xb0, 0xd1, 0x3f, 0x39, 0xa0, 0x77, 0xe7, 0x29, - 0xed, 0xb0, 0xd3, 0x13, 0xd0, 0xdf, 0xa4, 0x45, 0xf7, 0x97, 0x4b, 0xbe, 0xa4, 0xf4, 0x8b, 0x72, 0x0e, 0xe6, 0xd9, - 0x22, 0x3c, 0xfd, 0x3f, 0x1d, 0xdb, 0x6f, 0x83, 0x01, 0x5c, 0x03, 0x00}; + 0xdc, 0xb3, 0x37, 0xb7, 0x6d, 0x23, 0xff, 0x7f, 0x3f, 0x05, 0xc3, 0xe4, 0x52, 0x31, 0x21, 0x69, 0x92, 0xb2, 0x6c, + 0x45, 0xb2, 0xec, 0x6b, 0xf3, 0x98, 0x4b, 0xc7, 0x6d, 0x3a, 0x89, 0x9b, 0xb9, 0xab, 0xeb, 0xb1, 0x28, 0x09, 0x92, + 0x78, 0xa1, 0x48, 0x0d, 0x49, 0xf9, 0x51, 0x85, 0xf7, 0x59, 0xee, 0xb3, 0xdc, 0x27, 0xfb, 0xcd, 0xee, 0x02, 0x20, + 0xf8, 0xd0, 0xc3, 0x4d, 0x7a, 0xf7, 0x9b, 0x36, 0x89, 0x08, 0x02, 0x4b, 0x60, 0x01, 0x2c, 0x16, 0xfb, 0xf4, 0x67, + 0x5c, 0xf6, 0x62, 0xb6, 0xd8, 0x7e, 0x9f, 0xfb, 0xfc, 0x99, 0xd9, 0xb8, 0x24, 0x81, 0xe1, 0xb3, 0xb3, 0x78, 0x36, + 0x0b, 0x59, 0x4b, 0x17, 0xc9, 0x43, 0x74, 0x53, 0x7e, 0xe6, 0xec, 0x91, 0x23, 0x22, 0x76, 0x1a, 0xf9, 0xa6, 0xad, + 0x25, 0x46, 0xcc, 0x64, 0x48, 0x3b, 0xe2, 0x5c, 0x51, 0x36, 0x7b, 0x83, 0xea, 0x0d, 0x3e, 0x2f, 0xc5, 0xd6, 0xb5, + 0x26, 0xf1, 0x6a, 0x14, 0x32, 0x0b, 0x97, 0x3b, 0x7c, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x90, 0xa5, 0xe5, 0x91, 0x63, + 0x42, 0xdc, 0x99, 0x38, 0xc5, 0xfb, 0x60, 0x6e, 0xf4, 0x61, 0x50, 0x76, 0x56, 0xed, 0x3e, 0xd8, 0x8a, 0x80, 0xa8, + 0x87, 0x3e, 0x90, 0xc1, 0xdd, 0xaf, 0x61, 0xd7, 0x0e, 0xf4, 0x0f, 0xb0, 0xfa, 0x52, 0xbd, 0xdf, 0xb4, 0xf5, 0x07, + 0x97, 0xfa, 0x07, 0xc4, 0x31, 0x66, 0x2f, 0x7e, 0x49, 0xab, 0x57, 0x37, 0x75, 0x52, 0x7a, 0xaf, 0x30, 0x8f, 0x01, + 0x08, 0x7d, 0x5f, 0x05, 0xfe, 0x2c, 0x8a, 0xd3, 0x2c, 0x18, 0xeb, 0x57, 0xfd, 0xb7, 0x41, 0xeb, 0x72, 0x91, 0xb5, + 0x8c, 0x2b, 0x73, 0x9c, 0xa9, 0x29, 0x50, 0x04, 0xc1, 0xc4, 0x0c, 0x28, 0x9b, 0x2a, 0xa9, 0x3b, 0x68, 0x6b, 0x45, + 0x41, 0x9a, 0xb1, 0xd2, 0x38, 0x1b, 0x40, 0xbd, 0x4a, 0x3e, 0x15, 0x4c, 0x0c, 0xa5, 0x63, 0x4b, 0xa3, 0x4f, 0x37, + 0x95, 0x97, 0xab, 0x35, 0x1e, 0xe5, 0x59, 0x71, 0x5a, 0x62, 0x0c, 0x60, 0xe1, 0x38, 0x43, 0xcf, 0x8f, 0x54, 0xa3, + 0xcf, 0xd2, 0xb9, 0x3b, 0xfc, 0xae, 0xcc, 0x17, 0xc0, 0xf9, 0x0d, 0x16, 0x17, 0x51, 0x9c, 0x69, 0x10, 0xd8, 0x06, + 0xbe, 0x38, 0xac, 0x1a, 0x89, 0x71, 0xa8, 0x2d, 0x23, 0xe7, 0xc4, 0xe0, 0x7b, 0x3c, 0xfc, 0x5a, 0x3c, 0xbc, 0x59, + 0x29, 0x82, 0x05, 0x5d, 0x16, 0x22, 0x98, 0xc0, 0x2c, 0x3e, 0x8f, 0x6f, 0xab, 0x7a, 0x90, 0x97, 0xc3, 0xdd, 0x67, + 0x6f, 0x4b, 0xb0, 0xc9, 0x22, 0xab, 0x5f, 0x8b, 0x27, 0x26, 0x15, 0x8c, 0x4e, 0x65, 0x4f, 0xa1, 0xe1, 0x87, 0xe0, + 0x61, 0x32, 0xb0, 0x13, 0xc3, 0xb3, 0x00, 0x48, 0x12, 0x3f, 0xa6, 0x87, 0xf9, 0xb5, 0x48, 0x9d, 0x2c, 0x12, 0x17, + 0x2b, 0x87, 0x33, 0x50, 0xd7, 0x68, 0xb9, 0xca, 0x30, 0xd4, 0x2e, 0x74, 0x80, 0xe5, 0xba, 0x86, 0xa1, 0x3b, 0x81, + 0x4a, 0x17, 0x6c, 0x62, 0xae, 0x6b, 0xc1, 0xa4, 0x5e, 0xc6, 0x99, 0x5e, 0x20, 0x5e, 0x48, 0xdf, 0x51, 0x50, 0x05, + 0x8f, 0x09, 0x1f, 0xc6, 0xd8, 0x2c, 0xe2, 0xd4, 0xb7, 0xc6, 0xa8, 0xd0, 0x69, 0xa0, 0x0c, 0x63, 0x82, 0xd3, 0x6f, + 0x85, 0x8d, 0x83, 0x85, 0xf0, 0x9b, 0xa5, 0x61, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, + 0xd6, 0xbe, 0xb4, 0x15, 0xd0, 0x2f, 0x74, 0x32, 0x14, 0x18, 0x22, 0x1a, 0x86, 0xf9, 0x75, 0xe1, 0xb9, 0x53, 0x8c, + 0x17, 0x56, 0x19, 0x95, 0x6b, 0xa8, 0xba, 0x1f, 0x70, 0x05, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xfa, 0x7c, + 0x53, 0x55, 0xfa, 0x1b, 0xba, 0x46, 0x84, 0x9e, 0x10, 0x40, 0x34, 0x5f, 0xd7, 0xfe, 0x2a, 0xcb, 0x18, 0x1f, 0xad, + 0x54, 0x6a, 0xc2, 0xb7, 0xae, 0xf5, 0xe7, 0xcc, 0x9e, 0xb0, 0xcc, 0x0f, 0x42, 0x6a, 0xd2, 0x17, 0xd9, 0xea, 0x6b, + 0xc3, 0x4b, 0xcb, 0xc3, 0x8b, 0xca, 0xeb, 0x07, 0x07, 0x43, 0x47, 0x00, 0xf5, 0x1b, 0x47, 0x86, 0x59, 0xac, 0x9a, + 0x67, 0x94, 0xde, 0xfd, 0x57, 0xa7, 0x83, 0xc1, 0x74, 0x44, 0x30, 0x1d, 0x2c, 0x1a, 0xc7, 0x13, 0xf6, 0xcb, 0xfb, + 0xb7, 0x32, 0x6d, 0x16, 0x48, 0x80, 0x86, 0x7c, 0x61, 0xa6, 0xc8, 0x3f, 0x24, 0xc8, 0x3b, 0x50, 0x82, 0x2b, 0x4d, + 0x2e, 0xa1, 0x24, 0xd7, 0xb5, 0x33, 0xea, 0x3b, 0x9b, 0x50, 0xaf, 0x07, 0x31, 0xb6, 0x4a, 0xf2, 0x93, 0x03, 0xaa, + 0x4d, 0xa7, 0x1d, 0x55, 0x02, 0x34, 0x24, 0x30, 0xc2, 0x02, 0x0b, 0x90, 0xe1, 0x73, 0xe0, 0x16, 0x17, 0x0a, 0x7b, + 0x81, 0x72, 0x76, 0xf7, 0xac, 0xcc, 0xaa, 0x60, 0x2b, 0xfd, 0xf4, 0x04, 0x73, 0x76, 0xc1, 0x79, 0x0d, 0x51, 0x3e, + 0x4e, 0x0e, 0xe8, 0x51, 0xab, 0xec, 0x88, 0x02, 0x88, 0xb8, 0xda, 0xf5, 0x38, 0x80, 0x07, 0x6d, 0x15, 0x48, 0x11, + 0x0f, 0xa5, 0x7e, 0xae, 0x6b, 0x0b, 0xce, 0x1a, 0xf1, 0x70, 0x42, 0x10, 0x6b, 0xc0, 0x81, 0xbd, 0xab, 0x6b, 0x0b, + 0xff, 0x0e, 0x47, 0x2e, 0xde, 0xf8, 0x77, 0x2d, 0x97, 0xbf, 0x2a, 0xf6, 0x5a, 0x5a, 0xde, 0x6b, 0x63, 0x3e, 0xb9, + 0xe0, 0x48, 0x20, 0x6f, 0xd6, 0x73, 0x54, 0xd0, 0x36, 0x4c, 0xee, 0x5c, 0x4c, 0xee, 0x64, 0xc3, 0xe4, 0x4e, 0xb6, + 0x4c, 0x6e, 0xc8, 0x27, 0x52, 0x93, 0xa8, 0x4b, 0xd0, 0x39, 0x4c, 0x22, 0x8f, 0x33, 0x1a, 0x3d, 0xbe, 0xcf, 0x10, + 0x4f, 0x56, 0x1a, 0x82, 0x71, 0xd4, 0x06, 0x5c, 0x35, 0xe1, 0x45, 0x41, 0x44, 0x7d, 0xe0, 0x72, 0xd7, 0x89, 0x71, + 0x43, 0x0e, 0xce, 0x56, 0x58, 0x1d, 0x2f, 0xac, 0x52, 0xca, 0x2f, 0xde, 0x9a, 0x6f, 0x18, 0xe9, 0x7c, 0xcb, 0x48, + 0xc7, 0xa5, 0xad, 0xcb, 0x87, 0x4d, 0x9b, 0x50, 0x1d, 0x14, 0xac, 0x41, 0x30, 0x18, 0xc5, 0x25, 0x53, 0x5e, 0x87, + 0x9b, 0x69, 0xac, 0xb2, 0xa2, 0x96, 0x7e, 0x9a, 0xde, 0xc6, 0x09, 0x68, 0x5c, 0x00, 0xcc, 0xc3, 0x96, 0xd4, 0x22, + 0x88, 0x78, 0x30, 0x97, 0x8d, 0x8b, 0xa9, 0x78, 0xaf, 0x2e, 0x29, 0xaf, 0xd3, 0xa1, 0x1a, 0x4b, 0x3f, 0xcb, 0x58, + 0x82, 0x48, 0xf7, 0x21, 0xea, 0xf7, 0xff, 0x93, 0x65, 0xd6, 0x40, 0x43, 0x42, 0x85, 0xaa, 0x23, 0x85, 0x5e, 0x02, + 0x6f, 0x95, 0x88, 0x83, 0x58, 0x09, 0x0c, 0x97, 0x48, 0xc4, 0xff, 0x84, 0xdb, 0xb5, 0x95, 0x28, 0xae, 0x4b, 0xee, + 0x91, 0x61, 0x2f, 0xfd, 0xc9, 0x07, 0x50, 0xec, 0xb5, 0x3c, 0x13, 0x8c, 0x74, 0xd5, 0x30, 0x70, 0x09, 0x31, 0x7b, + 0xe3, 0x82, 0x48, 0x22, 0x95, 0xe4, 0x26, 0x50, 0xe0, 0x3d, 0xe9, 0x5b, 0xd3, 0xab, 0xb5, 0x97, 0x1f, 0xcc, 0x02, + 0xa3, 0x46, 0x35, 0x81, 0xb4, 0x85, 0x83, 0x53, 0x79, 0xe7, 0x0a, 0x4d, 0xf7, 0xc8, 0x00, 0xc9, 0xef, 0x25, 0xe4, + 0x33, 0x75, 0xc4, 0x85, 0x76, 0x98, 0xc0, 0xa9, 0x75, 0xe9, 0x5c, 0xe5, 0x4f, 0x67, 0xf8, 0xcb, 0xbd, 0xca, 0x9f, + 0x8e, 0xf0, 0x97, 0x77, 0x85, 0x99, 0xeb, 0x1a, 0x2e, 0xf2, 0xca, 0x98, 0xf5, 0xd3, 0xd2, 0x7a, 0x22, 0xfb, 0xb3, + 0x07, 0x2c, 0x1b, 0x3e, 0xc1, 0x8f, 0x9f, 0xac, 0x53, 0xf0, 0xb8, 0x54, 0xc7, 0x10, 0xd9, 0x89, 0x91, 0x37, 0x96, + 0xcf, 0x36, 0x94, 0x8f, 0x8c, 0xff, 0xf2, 0xc1, 0x8f, 0xab, 0x24, 0x2e, 0xce, 0x94, 0xb2, 0x18, 0xe2, 0x7a, 0x14, + 0x44, 0x7e, 0x72, 0x7f, 0x4d, 0xd7, 0x8b, 0x96, 0xe0, 0xdd, 0xa5, 0x78, 0x85, 0xd8, 0xcb, 0xb2, 0xba, 0x2b, 0x53, + 0x04, 0xbc, 0xf7, 0xfc, 0xa0, 0x1f, 0xfc, 0x3d, 0x51, 0xd8, 0xb6, 0xd2, 0x05, 0x94, 0x4f, 0x48, 0xe9, 0x43, 0xd7, + 0x4f, 0xd6, 0x2d, 0x56, 0x07, 0x53, 0x19, 0x6d, 0x85, 0x2f, 0x84, 0xe9, 0xc1, 0xcb, 0xec, 0x62, 0x12, 0xf4, 0x50, + 0x9f, 0x35, 0x8a, 0xef, 0xac, 0x27, 0xeb, 0xec, 0x4c, 0x5f, 0xf8, 0xc9, 0x27, 0x36, 0xb1, 0xc6, 0x41, 0x32, 0x0e, + 0x99, 0xde, 0xd3, 0x47, 0xa1, 0x1f, 0x7d, 0xe2, 0x8f, 0x56, 0xbc, 0xca, 0x50, 0x43, 0xbd, 0xf3, 0xee, 0x2b, 0x70, + 0x42, 0x22, 0x3b, 0x64, 0x56, 0x1b, 0xb0, 0xa0, 0xbd, 0x94, 0x02, 0xaf, 0x82, 0x51, 0x2c, 0x6a, 0x99, 0x60, 0x60, + 0x09, 0x4a, 0x73, 0xf0, 0x58, 0x35, 0x75, 0x9c, 0x2f, 0xdd, 0x54, 0x87, 0x4a, 0xc2, 0x4a, 0x99, 0x72, 0xf1, 0x1a, + 0x21, 0xfc, 0xf1, 0xcf, 0x51, 0x32, 0xec, 0xfd, 0x3f, 0x27, 0xa1, 0x7c, 0xd9, 0x08, 0xa1, 0xd4, 0x22, 0x4f, 0x89, + 0x07, 0x7c, 0x9c, 0x33, 0x98, 0x9b, 0x3f, 0xad, 0x36, 0xf6, 0xd3, 0x74, 0xb5, 0x60, 0x13, 0xd2, 0x0c, 0x9e, 0x15, + 0x9d, 0x2a, 0xdf, 0x2c, 0xd4, 0x8e, 0xfd, 0xb6, 0xf2, 0x8e, 0x0f, 0x5f, 0x82, 0xc5, 0x02, 0x30, 0x94, 0xf1, 0x74, + 0xaa, 0x17, 0x77, 0xfc, 0x1d, 0xcd, 0xdc, 0xc3, 0xdf, 0x56, 0x6f, 0x5e, 0x3b, 0x6f, 0x64, 0xe3, 0x08, 0x18, 0x63, + 0xa1, 0x7e, 0xe5, 0x7c, 0xb1, 0xd2, 0x5f, 0x31, 0xa2, 0xa9, 0x1f, 0x6d, 0x1e, 0xce, 0x65, 0x69, 0x89, 0x2f, 0x19, + 0x9b, 0x00, 0xc3, 0x6d, 0xd6, 0x4a, 0xaf, 0x43, 0x76, 0xc3, 0xa4, 0x6a, 0xb7, 0xfe, 0xb1, 0x86, 0x16, 0x18, 0x7b, + 0x8e, 0xab, 0x8c, 0x39, 0x57, 0xa7, 0x0c, 0x69, 0x88, 0x63, 0xe0, 0x23, 0x57, 0xb7, 0x58, 0x65, 0x4b, 0x0d, 0x4d, + 0x5d, 0xe9, 0xc0, 0xc6, 0x9e, 0x9d, 0x6d, 0x28, 0xef, 0x61, 0xe2, 0xe9, 0xe6, 0xbe, 0x99, 0xae, 0xd1, 0x83, 0x58, + 0xdd, 0x1c, 0x4f, 0x21, 0xec, 0xbc, 0x56, 0x21, 0x0e, 0xd9, 0x84, 0xb1, 0x26, 0x21, 0x99, 0x4e, 0xd2, 0x17, 0x61, + 0xed, 0x88, 0x66, 0xbf, 0x42, 0x0e, 0xd5, 0x38, 0x37, 0x5a, 0x79, 0xe4, 0x23, 0x4c, 0xe8, 0x1a, 0xb1, 0x34, 0xdd, + 0x88, 0x30, 0x39, 0xe9, 0xa6, 0x5e, 0xd4, 0x2e, 0xe3, 0xa3, 0x28, 0x37, 0x1d, 0x13, 0x58, 0x02, 0x1c, 0x60, 0xf5, + 0x5b, 0x78, 0xbc, 0x5c, 0x2f, 0xb8, 0xbd, 0x4a, 0x32, 0x1b, 0xe9, 0xdc, 0x96, 0x60, 0xd3, 0xfb, 0x5b, 0x9d, 0x77, + 0xaa, 0x74, 0x4c, 0x37, 0x76, 0xad, 0x55, 0x22, 0xbd, 0x35, 0x71, 0x11, 0x02, 0x10, 0x7d, 0xaa, 0xd0, 0x57, 0x36, + 0x9d, 0xb2, 0x71, 0x96, 0x1a, 0x42, 0x78, 0x24, 0xa3, 0xc7, 0x82, 0xd7, 0xd0, 0xa3, 0x81, 0xfe, 0x13, 0xf8, 0xd0, + 0x8b, 0x20, 0x4b, 0xbc, 0x43, 0xe2, 0xce, 0xd4, 0x8c, 0x26, 0x82, 0x58, 0x46, 0x11, 0xff, 0x0a, 0x24, 0x07, 0x6f, + 0x28, 0xc7, 0xae, 0xf1, 0xf3, 0xa7, 0x58, 0x17, 0xb1, 0xb4, 0x6a, 0xd9, 0x4e, 0x8a, 0xb6, 0x6d, 0xdf, 0xb5, 0xfb, + 0xa6, 0xe3, 0x3a, 0xb9, 0x6e, 0x82, 0xef, 0xd6, 0xa7, 0x7d, 0x37, 0x3d, 0xb6, 0x6a, 0x43, 0xab, 0x55, 0xf4, 0x90, + 0x76, 0x9e, 0xfb, 0xc2, 0xd5, 0x4d, 0x32, 0x99, 0x53, 0x68, 0xdb, 0x38, 0xbe, 0x61, 0xc9, 0x17, 0x0f, 0xa5, 0x0c, + 0x7c, 0xbf, 0xfe, 0x1c, 0xb9, 0x0e, 0x10, 0xe1, 0x2c, 0x5e, 0x3e, 0x60, 0x08, 0x6d, 0xdd, 0xd4, 0xc7, 0x61, 0x9c, + 0x32, 0x75, 0x0c, 0x24, 0x04, 0xf9, 0xc2, 0x41, 0xfc, 0xfc, 0xfe, 0xf5, 0x87, 0x0f, 0xba, 0x89, 0x99, 0x40, 0x53, + 0x15, 0x3a, 0x5f, 0x50, 0x3b, 0xa8, 0x7f, 0xe3, 0xba, 0xa3, 0x13, 0x86, 0x2e, 0xb5, 0xe5, 0x35, 0x47, 0x65, 0xb5, + 0x25, 0xc7, 0x4f, 0x1e, 0xfe, 0x65, 0xba, 0x89, 0xee, 0x35, 0xae, 0x06, 0xda, 0xb0, 0xfd, 0x78, 0x2b, 0x95, 0x2c, + 0x82, 0xe8, 0xba, 0xa1, 0xd4, 0xbf, 0x6b, 0x28, 0x85, 0xab, 0x5c, 0x8d, 0x56, 0xad, 0xe2, 0x85, 0xc2, 0x1a, 0x40, + 0x22, 0xe7, 0x5d, 0xe8, 0x52, 0xee, 0x53, 0x5f, 0xd0, 0x69, 0x1e, 0xc9, 0xbd, 0xda, 0xeb, 0x86, 0x62, 0x7e, 0x09, + 0x92, 0xb8, 0x1d, 0x87, 0x60, 0xf0, 0xc7, 0x54, 0xad, 0x5c, 0x99, 0x6d, 0x94, 0xe6, 0xba, 0x0a, 0x10, 0x62, 0x6f, + 0xaf, 0x33, 0xb6, 0x58, 0xb2, 0xc4, 0xcf, 0x56, 0x09, 0xbb, 0x0e, 0xe3, 0xdb, 0x47, 0x85, 0x39, 0xfd, 0x8e, 0xca, + 0xf3, 0x60, 0x36, 0x97, 0xb5, 0xcf, 0x5a, 0x6c, 0x20, 0x27, 0x70, 0xeb, 0x07, 0xf2, 0xff, 0xfc, 0xdb, 0xb6, 0xff, + 0xf3, 0xef, 0x9d, 0x55, 0x01, 0x7c, 0x3e, 0x34, 0xb3, 0xc1, 0x1e, 0xeb, 0xa2, 0xf9, 0x4b, 0x65, 0x9c, 0x37, 0xd7, + 0xa9, 0x4d, 0x02, 0xbc, 0xaf, 0x4d, 0x41, 0xad, 0xb0, 0xbc, 0x6e, 0x1e, 0xd4, 0x31, 0x18, 0xd7, 0xce, 0x9e, 0x41, + 0xa5, 0x2f, 0xea, 0xda, 0xd0, 0xe8, 0xed, 0x35, 0x23, 0x7f, 0x1c, 0xc3, 0xbb, 0xc6, 0xf0, 0x85, 0xdd, 0xe7, 0x72, + 0xc9, 0x97, 0xc3, 0xa1, 0xcc, 0x2d, 0xa7, 0x36, 0x05, 0x13, 0xff, 0xb3, 0x5a, 0x09, 0x3f, 0x3c, 0x7b, 0x8e, 0x41, + 0xbe, 0xf7, 0x83, 0x97, 0x43, 0x34, 0x46, 0x3b, 0x19, 0x25, 0x05, 0xb3, 0xb2, 0x91, 0xb4, 0x91, 0x31, 0x79, 0x0d, + 0x68, 0x8d, 0xae, 0x41, 0x29, 0x26, 0x1c, 0xcb, 0x87, 0x86, 0xf9, 0x72, 0xc8, 0x05, 0x4b, 0xdc, 0xfe, 0xb5, 0x57, + 0x5d, 0xda, 0x5c, 0x2c, 0x5b, 0x42, 0xba, 0xa9, 0x91, 0xfe, 0x07, 0x2b, 0xb3, 0x42, 0x8e, 0x87, 0x02, 0x7e, 0x90, + 0x28, 0x0c, 0x73, 0xcc, 0x77, 0xf2, 0x6e, 0x93, 0x8d, 0xd8, 0xcf, 0xbb, 0x6d, 0xc4, 0x2e, 0xf6, 0xb2, 0x11, 0xfb, + 0xf9, 0xab, 0xdb, 0x88, 0xbd, 0x53, 0x6d, 0xc4, 0x60, 0x12, 0x5f, 0xb3, 0xbd, 0x0c, 0xb7, 0x84, 0xd5, 0x46, 0x7c, + 0x9b, 0x0e, 0x5c, 0xce, 0xd2, 0xa6, 0xe3, 0x39, 0x03, 0x19, 0x01, 0x9f, 0x95, 0x30, 0x9e, 0x81, 0x11, 0xd7, 0x9f, + 0x6f, 0x6e, 0x15, 0xc6, 0x33, 0xd5, 0xd8, 0x2a, 0xe2, 0x11, 0x5f, 0x8b, 0x28, 0x4e, 0x64, 0xe0, 0xe4, 0x98, 0x22, + 0xe6, 0x93, 0x75, 0x68, 0x28, 0x59, 0xad, 0xa5, 0xf5, 0x9a, 0x27, 0x4c, 0xa0, 0x7a, 0x68, 0x3d, 0x25, 0x1b, 0x7a, + 0xcf, 0x45, 0x6c, 0x0b, 0x15, 0x82, 0xb4, 0x12, 0xa6, 0x38, 0x11, 0x6b, 0xfd, 0xb7, 0x3b, 0xf7, 0xfb, 0x4b, 0xb7, + 0xdf, 0x76, 0xc1, 0x39, 0x1b, 0x6e, 0x98, 0x58, 0xe0, 0xf4, 0xdb, 0x6d, 0x28, 0xb8, 0x55, 0x0a, 0x3c, 0x28, 0x08, + 0x94, 0x82, 0x0e, 0x14, 0x8c, 0x95, 0x82, 0x23, 0x28, 0x98, 0x28, 0x05, 0xc7, 0x50, 0x70, 0xa3, 0xe7, 0x97, 0x91, + 0xec, 0xee, 0xb1, 0x71, 0x65, 0xd2, 0xa5, 0x42, 0x94, 0x1d, 0x9b, 0x2e, 0x58, 0x4d, 0xf9, 0xb3, 0x5e, 0x6c, 0x92, + 0x74, 0xb1, 0x97, 0x98, 0xb7, 0x73, 0x46, 0x81, 0xa2, 0x5f, 0xe1, 0x99, 0x63, 0x67, 0x31, 0xd8, 0x4d, 0x8b, 0x00, + 0x0c, 0x02, 0x0f, 0x9a, 0x6e, 0x80, 0xc0, 0xa8, 0x2f, 0x67, 0x4e, 0x04, 0xb1, 0x50, 0xe6, 0xb2, 0x78, 0x47, 0x9f, + 0xb3, 0xe4, 0x12, 0x28, 0x2c, 0x4e, 0x5a, 0xaa, 0x54, 0xf2, 0x6b, 0xd8, 0x1d, 0xbc, 0x62, 0xa3, 0xd5, 0x4c, 0x3b, + 0x8f, 0x67, 0x3b, 0x4d, 0x08, 0xd4, 0x57, 0xd0, 0x4b, 0x9d, 0xd4, 0x2f, 0x96, 0x58, 0x96, 0xfc, 0x5b, 0xf4, 0x98, + 0x97, 0xeb, 0x67, 0xd0, 0x37, 0x2d, 0x23, 0x03, 0x16, 0xf8, 0x0e, 0xe0, 0x48, 0xd1, 0xe1, 0x9f, 0x03, 0x9e, 0x95, + 0xe7, 0x0b, 0x5f, 0xe9, 0xcf, 0xe9, 0x8f, 0x2c, 0x4d, 0xfd, 0x99, 0xa8, 0x5f, 0xef, 0x27, 0x18, 0xed, 0xc8, 0xfb, + 0x17, 0x22, 0x10, 0x24, 0x79, 0x41, 0xcd, 0x36, 0x23, 0x89, 0x6f, 0x35, 0xb0, 0xfe, 0x81, 0x05, 0x55, 0xd8, 0x29, + 0x04, 0x36, 0x4c, 0x61, 0xd9, 0xa2, 0x00, 0x36, 0xff, 0x0d, 0x0b, 0xab, 0x85, 0x99, 0x3f, 0xab, 0x16, 0xd1, 0x3a, + 0xc8, 0xd5, 0xbe, 0x49, 0x85, 0x7e, 0xa9, 0xf0, 0x4b, 0x34, 0xd4, 0x61, 0x3c, 0xfb, 0x53, 0xd5, 0xd3, 0x5b, 0xcc, + 0x0a, 0x3e, 0x44, 0x66, 0x90, 0x0d, 0x6d, 0xc4, 0xb1, 0x66, 0x03, 0x0a, 0x7b, 0x51, 0x36, 0xb7, 0xd0, 0xb5, 0xac, + 0xe5, 0x45, 0x86, 0x69, 0xe3, 0xdc, 0xae, 0xab, 0x0e, 0xb5, 0xbd, 0x64, 0x36, 0xf2, 0x5b, 0xae, 0x77, 0x6c, 0x8a, + 0x3f, 0xb6, 0xd3, 0x31, 0x72, 0x84, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, + 0xbe, 0xb7, 0x88, 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x2e, 0xd4, 0x7d, 0x0c, 0xd5, 0xc0, 0xbd, 0x05, 0x5d, + 0xdb, 0x4b, 0xd8, 0x82, 0x5a, 0xcb, 0x48, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xfc, 0xf3, 0xa5, 0xca, 0x54, 0x15, 0x97, + 0x1c, 0xb5, 0x00, 0x8e, 0x94, 0x87, 0x79, 0x80, 0xe0, 0x46, 0xfd, 0xa5, 0x3f, 0xc1, 0xc8, 0x84, 0xb6, 0xd7, 0x49, + 0xd8, 0x42, 0xb3, 0x3b, 0x1b, 0x81, 0x27, 0xf1, 0xed, 0x29, 0xf4, 0x16, 0x1b, 0x5b, 0x29, 0x0b, 0xa7, 0xf8, 0xc6, + 0x42, 0xcf, 0x12, 0x01, 0xc7, 0xc2, 0x8b, 0x38, 0x40, 0x63, 0x8b, 0x3e, 0xbc, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, + 0x91, 0x45, 0xc3, 0x39, 0x76, 0x96, 0x0a, 0x2c, 0x15, 0x7f, 0xc6, 0x1a, 0xab, 0xbb, 0x9a, 0xd3, 0x87, 0xcb, 0xda, + 0x34, 0x8c, 0x6f, 0x7b, 0xf3, 0x60, 0x32, 0x61, 0x51, 0x1f, 0xfb, 0x2c, 0x0b, 0x59, 0x18, 0x06, 0xcb, 0x34, 0x48, + 0xfb, 0x0b, 0xff, 0x8e, 0x43, 0x3d, 0xdc, 0x04, 0xb5, 0xcd, 0xa1, 0xb6, 0xf7, 0x86, 0xaa, 0x80, 0x01, 0x2f, 0x16, + 0x82, 0xc3, 0xbb, 0xd6, 0xd1, 0x9c, 0xca, 0x38, 0xf7, 0x86, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, + 0x39, 0xb9, 0x7d, 0xb3, 0xa6, 0x85, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x3c, 0x39, 0x93, 0x49, 0x6e, 0x8f, + 0xc5, 0xd3, 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0xa2, 0xa0, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, + 0x1a, 0xb9, 0xcd, 0xf8, 0x53, 0xc2, 0x26, 0x7d, 0x5c, 0x48, 0x64, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x29, 0xc0, + 0x65, 0x89, 0x36, 0xa1, 0xac, 0xe7, 0x6a, 0xbd, 0x77, 0x4d, 0xad, 0xf8, 0xdc, 0x78, 0xdc, 0x58, 0x6f, 0xe2, 0x27, + 0x9f, 0xae, 0x34, 0x65, 0x14, 0xbe, 0x4f, 0xd5, 0xd6, 0x02, 0x0d, 0xd6, 0x5d, 0x0f, 0x42, 0x76, 0xf5, 0x47, 0x71, + 0x02, 0x7b, 0x36, 0xf1, 0x27, 0xc1, 0x2a, 0xed, 0xb9, 0xde, 0xf2, 0x4e, 0x14, 0xf1, 0xb5, 0x5e, 0x14, 0xe0, 0xde, + 0xeb, 0xa5, 0x71, 0x18, 0x4c, 0x44, 0xd1, 0xa6, 0xbd, 0xe4, 0x7a, 0x46, 0x1f, 0x1d, 0xd6, 0x03, 0x0c, 0xbb, 0xe0, + 0x87, 0xa1, 0x66, 0xb7, 0x53, 0x8d, 0xf9, 0x29, 0xca, 0x97, 0x35, 0x27, 0x25, 0xbc, 0xa0, 0x73, 0xba, 0x7b, 0xb8, + 0xbc, 0x93, 0x6b, 0xde, 0x3d, 0x5a, 0xde, 0xe5, 0x7f, 0x5d, 0xb0, 0x49, 0xe0, 0x6b, 0xad, 0x62, 0x35, 0xb9, 0x0e, + 0xc8, 0xa0, 0x8d, 0xf5, 0x86, 0x65, 0x2a, 0xb6, 0x05, 0x84, 0x36, 0x7c, 0x14, 0x2c, 0x96, 0x71, 0x92, 0xf9, 0x51, + 0x96, 0xe7, 0xc3, 0xab, 0x3c, 0xef, 0x5f, 0x04, 0xad, 0xcb, 0x7f, 0xb4, 0xe8, 0x9c, 0x26, 0x9d, 0x4d, 0x6e, 0x5c, + 0x99, 0xaf, 0x99, 0x6a, 0x33, 0x02, 0xc7, 0x18, 0xda, 0x8b, 0xa8, 0x95, 0xe9, 0x94, 0xac, 0x57, 0x26, 0x24, 0xcb, + 0xea, 0x64, 0x83, 0x52, 0xae, 0x82, 0x27, 0x10, 0x54, 0x78, 0xcd, 0x06, 0x17, 0x8a, 0xfd, 0x09, 0x30, 0x2b, 0x58, + 0x99, 0xfc, 0x0a, 0x9e, 0x6c, 0xe2, 0x19, 0xbf, 0xdb, 0xcd, 0x33, 0xfe, 0x9a, 0xed, 0xc3, 0x33, 0x7e, 0xf7, 0xd5, + 0x79, 0xc6, 0x27, 0x75, 0xbf, 0x82, 0xb7, 0xf1, 0x40, 0x97, 0x1a, 0x06, 0x38, 0x9a, 0x12, 0x8a, 0xd8, 0xf3, 0xf6, + 0x0f, 0xbb, 0x01, 0x08, 0x68, 0x94, 0x83, 0x8e, 0x4e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xe7, + 0xe9, 0x74, 0xf0, 0x2a, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0xbe, 0x28, 0x45, 0x57, 0xa0, 0x37, 0xc2, 0x0a, 0x13, 0xf3, + 0x4f, 0x80, 0x73, 0x36, 0x59, 0x1d, 0x4f, 0xa4, 0xf5, 0x59, 0xbf, 0xdc, 0x85, 0x96, 0x34, 0xf9, 0x14, 0x2e, 0x38, + 0x35, 0x51, 0xe2, 0x8c, 0x65, 0xdc, 0x67, 0xf6, 0xfb, 0xfb, 0xb7, 0x93, 0xd6, 0xdb, 0xd8, 0xc8, 0x83, 0xf4, 0x5d, + 0xd5, 0x01, 0x86, 0xeb, 0x7e, 0x06, 0xea, 0x70, 0x72, 0x6e, 0x41, 0xa6, 0x26, 0x98, 0x86, 0xd7, 0xd4, 0xfc, 0xac, + 0x34, 0xd2, 0x9e, 0xda, 0x90, 0x27, 0xba, 0xaa, 0x1d, 0xc6, 0xdc, 0xfb, 0x60, 0xcd, 0x39, 0x40, 0xcc, 0xdd, 0x85, + 0x7e, 0xc3, 0x13, 0x6a, 0x1e, 0x4c, 0xf2, 0xdc, 0xe8, 0x0b, 0x44, 0x28, 0x07, 0x2d, 0xdb, 0xc5, 0xc4, 0xa5, 0xb7, + 0xd2, 0xa6, 0x81, 0x6b, 0x08, 0x49, 0xfd, 0xf7, 0x16, 0x14, 0xea, 0x5c, 0x59, 0xc8, 0x71, 0xa6, 0x6b, 0x84, 0x3e, + 0x32, 0xb4, 0x50, 0x06, 0x04, 0x1a, 0x60, 0x89, 0x7f, 0xf1, 0x4a, 0x14, 0xd4, 0x6d, 0x38, 0x09, 0x39, 0x68, 0x11, + 0x00, 0x5e, 0xfe, 0x42, 0xae, 0x4d, 0x64, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xbc, 0x1f, 0x2e, 0xbf, 0xd3, 0x93, + 0x03, 0x68, 0x70, 0x5a, 0x31, 0x1c, 0xd8, 0x61, 0xa1, 0x08, 0xac, 0x44, 0x7a, 0x6b, 0xda, 0xe9, 0xad, 0xf6, 0x6c, + 0x2d, 0x22, 0x64, 0x64, 0xfe, 0xd2, 0x82, 0x2b, 0x3e, 0xd2, 0x5e, 0x4e, 0xf1, 0x94, 0x60, 0x1c, 0xfd, 0x55, 0x0a, + 0xb4, 0x11, 0x2f, 0xaa, 0x48, 0x7f, 0xfa, 0xe3, 0x55, 0x92, 0xc6, 0x49, 0x6f, 0x19, 0x07, 0x51, 0xc6, 0x92, 0x1c, + 0x51, 0x75, 0x89, 0xf8, 0x11, 0xe8, 0xb9, 0x5a, 0xc7, 0x4b, 0x7f, 0x1c, 0x64, 0xf7, 0x3d, 0x87, 0xb3, 0x14, 0x4e, + 0x9f, 0x73, 0x07, 0x4e, 0x63, 0xfd, 0x1e, 0xc7, 0xe6, 0x73, 0x64, 0xfc, 0x92, 0x3a, 0x3b, 0xa3, 0x2e, 0xf3, 0xbe, + 0xf2, 0x96, 0x62, 0x84, 0x00, 0xfb, 0xe1, 0x27, 0xd6, 0x0c, 0xa8, 0x3c, 0x4c, 0xb5, 0x33, 0x61, 0x33, 0x13, 0xa9, + 0x36, 0xc8, 0xe5, 0xc5, 0x1f, 0xbb, 0x63, 0x68, 0x4e, 0x73, 0x31, 0x70, 0x3c, 0xc6, 0x3e, 0x3d, 0xeb, 0xf9, 0x90, + 0x51, 0xcb, 0xdc, 0xa7, 0xe6, 0x88, 0x4d, 0xe3, 0x84, 0x51, 0x3c, 0x59, 0xb7, 0xbb, 0xbc, 0xdb, 0x1f, 0xfc, 0xf6, + 0xe1, 0x37, 0xc3, 0x89, 0xe2, 0xac, 0x25, 0x80, 0x19, 0x3b, 0xa0, 0xd5, 0xcf, 0x33, 0x60, 0x0d, 0x09, 0xf3, 0x63, + 0x0a, 0xdd, 0xd5, 0xd3, 0xf5, 0x7e, 0x63, 0xd8, 0xae, 0x65, 0xcc, 0xcf, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, + 0x9e, 0xb1, 0x7d, 0xb4, 0xbc, 0x13, 0x73, 0x8c, 0x07, 0xde, 0x03, 0x26, 0xa9, 0xd2, 0x15, 0x31, 0x49, 0xd5, 0x62, + 0x9c, 0xa4, 0x7e, 0x6d, 0x34, 0x22, 0x92, 0x45, 0xe5, 0xa4, 0xef, 0x2c, 0xef, 0xd4, 0x23, 0xba, 0x68, 0x26, 0x4f, + 0xea, 0x6a, 0x08, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x4d, 0x74, 0x79, 0x2e, 0x15, 0xe4, 0x48, 0x3c, 0xf8, + 0xa3, 0x34, 0x0e, 0x57, 0x19, 0x6b, 0x46, 0x17, 0x21, 0xc7, 0x73, 0x0a, 0xe4, 0xe0, 0xef, 0x72, 0x5f, 0x3b, 0xc0, + 0x6e, 0xc3, 0x32, 0x71, 0xfa, 0x10, 0x71, 0xd8, 0x6a, 0x97, 0xbb, 0x0e, 0xaf, 0x64, 0xa7, 0xcd, 0x86, 0x81, 0x98, + 0x70, 0x2c, 0x11, 0xf5, 0xd6, 0x6c, 0x97, 0x97, 0xc9, 0xa8, 0xab, 0xb2, 0x28, 0x2f, 0x0f, 0xe6, 0xcf, 0xd9, 0x63, + 0x2f, 0x9a, 0xf7, 0xd8, 0x0b, 0xb1, 0xc7, 0xb6, 0xaf, 0xcc, 0xc7, 0x53, 0x17, 0xfe, 0xeb, 0x17, 0x03, 0xea, 0x39, + 0x5a, 0x7b, 0x79, 0xa7, 0xb9, 0xcb, 0x3b, 0xcd, 0xf2, 0x96, 0x77, 0x1a, 0x82, 0x46, 0x7b, 0x10, 0xd3, 0xf6, 0x0c, + 0xd3, 0xd1, 0xa0, 0x10, 0xfe, 0x38, 0xa5, 0x57, 0xee, 0x21, 0xbc, 0x83, 0x56, 0x9d, 0xfa, 0x3b, 0x6f, 0xfb, 0x56, + 0xa7, 0xbd, 0x24, 0x88, 0xb6, 0x61, 0x67, 0xfe, 0x68, 0xc4, 0x26, 0xbd, 0x69, 0x3c, 0x5e, 0xa5, 0xff, 0xe2, 0xfd, + 0xe7, 0x48, 0xdc, 0x4a, 0x08, 0x2a, 0x70, 0x44, 0x53, 0x50, 0x94, 0xdc, 0x30, 0x01, 0x61, 0x2d, 0xe7, 0xa9, 0x47, + 0xe1, 0x91, 0x3d, 0xfb, 0xb0, 0x61, 0x91, 0x37, 0x23, 0xfa, 0x4f, 0x9b, 0xa5, 0xcd, 0x24, 0xe6, 0x0b, 0xd0, 0xb2, + 0x15, 0x1d, 0x0f, 0xc7, 0x06, 0x9f, 0x4d, 0xa7, 0xdb, 0xdc, 0xdd, 0x4b, 0xf1, 0xa5, 0x2b, 0x71, 0xa8, 0xf0, 0x73, + 0x8b, 0x3b, 0xa6, 0x6c, 0x87, 0xba, 0x69, 0x8d, 0xd4, 0xa0, 0x6e, 0x39, 0x10, 0x8a, 0xba, 0x7b, 0x52, 0xf9, 0xc7, + 0x2f, 0x0e, 0xe1, 0x3f, 0xe2, 0xea, 0x7f, 0xcd, 0x9a, 0x18, 0xf5, 0xb7, 0x65, 0x4b, 0x70, 0x62, 0x95, 0x90, 0x11, + 0xdf, 0xbf, 0xfe, 0x74, 0xfa, 0xb0, 0x06, 0x7b, 0xd7, 0x26, 0x53, 0xaa, 0x6a, 0xed, 0xef, 0xe3, 0x18, 0x52, 0x77, + 0xd6, 0xab, 0x0b, 0xf4, 0x90, 0xb1, 0x7b, 0x36, 0x80, 0x46, 0xe2, 0x1e, 0x41, 0x5a, 0x7c, 0x1d, 0xdb, 0xd0, 0x55, + 0xe2, 0xf5, 0xa6, 0xab, 0xc4, 0xab, 0xdd, 0x57, 0x89, 0x1f, 0xf6, 0xba, 0x4a, 0xbc, 0xfa, 0xea, 0x57, 0x89, 0xd7, + 0xf5, 0xab, 0xc4, 0x45, 0x2c, 0xec, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x29, 0xe5, 0xce, 0xe3, 0x41, 0xc7, + 0xa1, 0x90, 0xc7, 0x17, 0x7f, 0xf8, 0x62, 0x81, 0x0b, 0xf1, 0x3d, 0x9a, 0x93, 0x15, 0x57, 0x0b, 0x4e, 0xd9, 0xf1, + 0x3b, 0x4a, 0x71, 0x18, 0x47, 0xb3, 0x9f, 0x41, 0x29, 0x0b, 0xe2, 0xc0, 0x44, 0x79, 0x11, 0xa4, 0x3f, 0xc7, 0xcb, + 0xd5, 0xf2, 0x2d, 0xc0, 0xfa, 0x18, 0xa4, 0xc1, 0x28, 0x64, 0xd2, 0x13, 0x99, 0xcc, 0xdf, 0xb8, 0x4c, 0x1c, 0x2c, + 0x4e, 0xc5, 0x4f, 0xff, 0x4e, 0xfc, 0x44, 0x9b, 0x54, 0xfe, 0x9b, 0xec, 0xea, 0xf4, 0xe6, 0x8b, 0x88, 0x50, 0x02, + 0x2a, 0x9d, 0x7e, 0xf8, 0x65, 0xe4, 0x22, 0x36, 0x1a, 0x46, 0x29, 0xec, 0x1d, 0x36, 0xc2, 0x61, 0xb5, 0x4b, 0xcd, + 0xca, 0x30, 0x65, 0x08, 0xae, 0xba, 0x18, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x93, + 0x01, 0x68, 0x38, 0x65, 0x1b, 0x4c, 0x1e, 0xf9, 0x01, 0x19, 0xe5, 0x38, 0x69, 0xe9, 0x90, 0xbb, 0x74, 0xb5, 0xb4, + 0x48, 0xd5, 0x6c, 0xe1, 0x10, 0x75, 0x99, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0xd6, 0x52, 0x98, 0x6a, 0xc4, + 0x36, 0x97, 0x0a, 0xa7, 0xad, 0x48, 0x08, 0x17, 0x45, 0x1c, 0x8c, 0x86, 0x89, 0xe3, 0x6f, 0xc8, 0x75, 0xb5, 0x78, + 0x0b, 0x51, 0x44, 0xf2, 0x15, 0x9f, 0x0f, 0x1e, 0x15, 0x82, 0x1e, 0x5f, 0x2a, 0x68, 0x7c, 0x77, 0xc3, 0x92, 0xd0, + 0xbf, 0x6f, 0x19, 0x79, 0x1c, 0xfd, 0x08, 0x08, 0x78, 0x15, 0xdf, 0x46, 0x6a, 0x05, 0x4c, 0xd6, 0xd2, 0xb0, 0x96, + 0x1a, 0xe3, 0x97, 0x80, 0xe3, 0x8a, 0xd2, 0x03, 0x48, 0x93, 0x3b, 0x63, 0x7f, 0x37, 0xe9, 0xdf, 0x7f, 0x18, 0xb9, + 0x79, 0x1e, 0xcb, 0x0f, 0xfd, 0xb2, 0xdc, 0xe3, 0x33, 0x4f, 0x9f, 0x3e, 0xda, 0x3c, 0xec, 0x72, 0x7a, 0xf6, 0x86, + 0xd6, 0xc6, 0xc6, 0x5d, 0x00, 0xbd, 0xb8, 0x88, 0x57, 0xe3, 0x39, 0x1a, 0xba, 0x7e, 0xbd, 0xf1, 0x66, 0x00, 0x13, + 0xb3, 0x94, 0xca, 0xa1, 0x57, 0x8a, 0x0a, 0x2c, 0xe0, 0xf7, 0x5f, 0x43, 0x00, 0xce, 0xff, 0x21, 0x1a, 0xea, 0xab, + 0x86, 0xdf, 0xe2, 0x83, 0x87, 0x2d, 0xde, 0x3e, 0x24, 0xd3, 0xe4, 0xa1, 0x2d, 0x84, 0x72, 0xad, 0x99, 0xc8, 0xe4, + 0x55, 0xa4, 0xa9, 0x61, 0xe4, 0x36, 0x45, 0xc8, 0x13, 0x5f, 0x61, 0x36, 0x5d, 0xd3, 0xb9, 0xa3, 0x81, 0xc9, 0x38, + 0xb5, 0xaa, 0x10, 0x19, 0x6e, 0xf2, 0xc0, 0x90, 0x7c, 0x55, 0xdf, 0x2d, 0x82, 0xc8, 0xc4, 0x28, 0xf0, 0xf5, 0x37, + 0xfe, 0x1d, 0xc4, 0x41, 0x06, 0xe2, 0x56, 0x7d, 0x05, 0x85, 0xa6, 0xea, 0x37, 0x07, 0xa9, 0x9e, 0xf4, 0x46, 0x4c, + 0x08, 0x2d, 0xde, 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0x79, 0x8d, 0xd0, 0xe4, 0x3d, 0x02, 0xcb, 0xf1, 0x3a, 0x00, 0xda, + 0x92, 0x7c, 0x79, 0x47, 0x25, 0x70, 0x33, 0x40, 0x9d, 0xac, 0x28, 0xe0, 0xa1, 0xfe, 0x3a, 0x8e, 0x28, 0x10, 0x17, + 0x7a, 0x08, 0xd3, 0xe6, 0x27, 0x10, 0x11, 0xb8, 0xa7, 0xe1, 0x85, 0x1d, 0xdf, 0x72, 0x49, 0xb0, 0xe6, 0xd0, 0xe3, + 0xb0, 0xcf, 0x9a, 0x63, 0xc2, 0x45, 0x0a, 0x15, 0x04, 0xad, 0x43, 0x25, 0xc4, 0xb3, 0xc9, 0x1a, 0x68, 0x23, 0xde, + 0x8b, 0xee, 0xb2, 0x05, 0x8b, 0x56, 0x3a, 0xe6, 0x84, 0xc2, 0x18, 0x7d, 0x50, 0xe7, 0x15, 0x31, 0x5b, 0x40, 0x6d, + 0x9a, 0x5b, 0xce, 0xe9, 0x2c, 0x4c, 0x39, 0x49, 0xf5, 0xcd, 0x31, 0x57, 0x6c, 0xa6, 0x9c, 0xb6, 0x55, 0x4f, 0x08, + 0x3e, 0xa5, 0x71, 0xd5, 0x91, 0x8b, 0x2c, 0xa1, 0x01, 0x06, 0x45, 0xc7, 0xe0, 0xe2, 0x22, 0x81, 0xf6, 0x96, 0x5f, + 0x9d, 0x34, 0xa9, 0x91, 0xf1, 0x2b, 0x82, 0xa2, 0xc4, 0xa8, 0x83, 0xe1, 0xfd, 0x84, 0xc0, 0x44, 0x1b, 0xe1, 0x8c, + 0x6b, 0x70, 0x36, 0x0c, 0xfa, 0x13, 0xbb, 0xa7, 0x83, 0x84, 0x50, 0xf5, 0x89, 0xdd, 0x83, 0xed, 0xdf, 0x6b, 0x90, + 0xa6, 0xe8, 0x5b, 0xc8, 0xb5, 0x09, 0xa1, 0xfe, 0xc7, 0x10, 0xac, 0x6a, 0xcb, 0x06, 0x72, 0xf2, 0x2d, 0x54, 0x1c, + 0x51, 0x0c, 0x59, 0x9d, 0xc5, 0x26, 0xe6, 0x26, 0xfe, 0xad, 0x46, 0x1c, 0x5b, 0x0d, 0x5b, 0xc3, 0x78, 0xe6, 0x3a, + 0xce, 0x41, 0xad, 0x3e, 0x08, 0xb2, 0x9b, 0x6a, 0x1b, 0x66, 0x36, 0x70, 0x1d, 0x2b, 0x78, 0x66, 0x7b, 0xfd, 0xda, + 0x19, 0xad, 0xc4, 0x92, 0x1c, 0xa2, 0xf8, 0xeb, 0xf4, 0xc9, 0xba, 0x55, 0xdb, 0x90, 0x46, 0xd5, 0x64, 0x1e, 0xfb, + 0x96, 0x73, 0xf9, 0xd7, 0xb0, 0x7e, 0xf4, 0x53, 0x24, 0x4b, 0xca, 0x6b, 0x32, 0x84, 0x68, 0xc8, 0x2d, 0xd8, 0x46, + 0x7f, 0xd1, 0x9e, 0x6b, 0x2d, 0xda, 0x3e, 0x86, 0x31, 0x94, 0xe9, 0xb2, 0x85, 0x4f, 0x99, 0x0a, 0xa0, 0xf2, 0xc5, + 0xb4, 0x4a, 0xe1, 0x78, 0xdc, 0x55, 0x56, 0x68, 0xf4, 0xb6, 0x72, 0x0b, 0x08, 0x7f, 0xc3, 0xf1, 0x69, 0x8f, 0x20, + 0x2e, 0x01, 0xd4, 0x80, 0xd8, 0xe9, 0x3b, 0x01, 0xae, 0x96, 0x65, 0x70, 0xe5, 0x43, 0x72, 0x7f, 0x60, 0x78, 0xe8, + 0xa0, 0x0e, 0x4d, 0xc2, 0x6b, 0x3e, 0xee, 0x1e, 0x08, 0x92, 0x45, 0x93, 0x32, 0xc0, 0xca, 0xf9, 0xb5, 0x3f, 0xb8, + 0x12, 0x45, 0x81, 0xa4, 0x02, 0x71, 0x03, 0x45, 0xc9, 0xe3, 0x08, 0x17, 0x3f, 0x6d, 0xb7, 0x60, 0x2f, 0x2e, 0x06, + 0x1b, 0x50, 0x44, 0x30, 0xd9, 0x4c, 0x11, 0x8a, 0x43, 0xe4, 0x6a, 0x74, 0x0b, 0x6e, 0x09, 0x46, 0x74, 0xe3, 0x4a, + 0xcc, 0x84, 0x4d, 0x61, 0xd1, 0x26, 0xe0, 0xb1, 0x28, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, 0xd9, 0x2e, 0xa9, + 0x35, 0xb9, 0x53, 0xdd, 0x26, 0xfe, 0x52, 0xf1, 0xc8, 0x13, 0xcc, 0xb9, 0xea, 0x98, 0x57, 0x12, 0x75, 0xa3, 0xf7, + 0x95, 0x68, 0x55, 0x83, 0x46, 0x56, 0x82, 0x28, 0xfe, 0x56, 0x2e, 0x28, 0x42, 0xa1, 0xae, 0xca, 0xc6, 0x2f, 0x0a, + 0xd9, 0x38, 0xdd, 0x6a, 0x0a, 0x47, 0x1a, 0xc1, 0xfd, 0x2b, 0x4e, 0x6a, 0xf2, 0x76, 0x50, 0x38, 0xab, 0x15, 0x3d, + 0x55, 0xdc, 0xaf, 0x8a, 0x8b, 0x86, 0xe2, 0xd4, 0x27, 0x6e, 0x19, 0x65, 0xdf, 0xbe, 0x72, 0xd5, 0xc2, 0xfb, 0xaa, + 0x28, 0x07, 0xa9, 0x3b, 0x76, 0x59, 0x16, 0xab, 0xcb, 0xa6, 0xec, 0x7e, 0xa3, 0xbe, 0x56, 0x16, 0x89, 0xf4, 0x93, + 0x21, 0x04, 0x0b, 0x31, 0x7d, 0x45, 0xaf, 0x2d, 0x6d, 0x20, 0xb0, 0x93, 0x0d, 0x6e, 0x7d, 0xbb, 0xa5, 0xf3, 0x94, + 0x2f, 0xa1, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0xc4, 0xef, 0xd5, 0xba, 0xe1, 0x94, 0xc7, 0x43, 0x9e, 0x9f, 0xef, 0x20, + 0x5e, 0xd4, 0x1c, 0x55, 0x91, 0x8f, 0x3b, 0xd3, 0x22, 0xf3, 0x5c, 0xac, 0x5a, 0x07, 0x4a, 0x42, 0x9c, 0x35, 0xf7, + 0x8c, 0x29, 0xcb, 0xe8, 0x79, 0x8d, 0x9e, 0xf8, 0x2e, 0x5f, 0x3a, 0xc9, 0x2a, 0xc2, 0xd8, 0xf6, 0x56, 0x96, 0xf8, + 0xe3, 0x4f, 0x4a, 0x97, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0x41, 0xdf, 0xc7, 0x50, 0x90, 0xac, 0x67, 0x7b, + 0xa9, 0x22, 0x7d, 0xe9, 0x3d, 0x76, 0xda, 0xfe, 0x8b, 0xe9, 0x61, 0x45, 0x28, 0xea, 0x75, 0xca, 0x22, 0xf3, 0x0d, + 0xfd, 0xc8, 0xe6, 0xab, 0xc5, 0x68, 0xad, 0xca, 0x56, 0x15, 0x91, 0x6b, 0x5d, 0xcc, 0xaa, 0x7e, 0x76, 0x3a, 0x9d, + 0x96, 0x05, 0x8d, 0x8e, 0x76, 0x88, 0xc2, 0xc2, 0xc7, 0x8e, 0xe3, 0x54, 0xfb, 0xbe, 0x1d, 0xed, 0x16, 0xca, 0x6d, + 0xbb, 0x8d, 0x3d, 0x46, 0xdc, 0xee, 0xc2, 0x5f, 0x1d, 0x1d, 0xb9, 0x5d, 0xec, 0xec, 0x92, 0x59, 0x44, 0x9f, 0x8c, + 0x21, 0x82, 0x8c, 0x2d, 0xd2, 0xde, 0x98, 0xa1, 0x0e, 0xc6, 0x56, 0x36, 0x34, 0x1a, 0x0e, 0x58, 0x33, 0x30, 0x15, + 0x71, 0xc5, 0xaa, 0x70, 0x34, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0xb8, 0x51, 0xd6, 0x75, 0x99, 0x36, 0x0e, + 0xab, 0xe3, 0xfc, 0xa5, 0x54, 0x4f, 0x83, 0x03, 0x70, 0x2d, 0x14, 0xda, 0x24, 0x9f, 0xc5, 0xbf, 0xa5, 0xfc, 0xff, + 0xc5, 0xf2, 0xae, 0x6c, 0x3f, 0xd2, 0x05, 0x89, 0x76, 0xb1, 0x5b, 0xa8, 0xd7, 0x4d, 0x6b, 0x40, 0x5a, 0x19, 0x4c, + 0x55, 0x05, 0x3a, 0x28, 0xe9, 0x4b, 0x09, 0x40, 0x1a, 0xc4, 0xef, 0xc8, 0x31, 0xc3, 0x14, 0x17, 0x22, 0xc4, 0x22, + 0x7d, 0x1d, 0x8c, 0xc1, 0x7c, 0xde, 0x45, 0xfd, 0x41, 0x69, 0x4d, 0x80, 0x36, 0xbe, 0x36, 0xb6, 0xbd, 0xc4, 0xfd, + 0x55, 0xbd, 0x96, 0x00, 0x0c, 0x28, 0x73, 0x61, 0x13, 0xa2, 0x21, 0x81, 0x56, 0x59, 0xdc, 0xd4, 0x4b, 0xf9, 0x56, + 0xd5, 0xb3, 0x89, 0x8e, 0x21, 0xb8, 0xe6, 0x2a, 0x04, 0x5b, 0x68, 0x0b, 0x60, 0xb0, 0x7c, 0xf9, 0xe1, 0xb3, 0x05, + 0x53, 0xac, 0xae, 0x47, 0x17, 0xa7, 0x1c, 0xd7, 0xaf, 0x85, 0x67, 0x67, 0x4a, 0xfb, 0x1f, 0xe5, 0x8b, 0x3f, 0x34, + 0x0a, 0xf4, 0x2e, 0x4a, 0x12, 0x3a, 0x6e, 0x2d, 0xee, 0x19, 0x7b, 0xd5, 0x5e, 0x04, 0xd1, 0xfe, 0x75, 0xfd, 0xbb, + 0xbd, 0xeb, 0xc2, 0x81, 0xb1, 0x77, 0x65, 0x38, 0x71, 0xc8, 0x72, 0x21, 0x1b, 0xfc, 0xa0, 0x08, 0x14, 0x55, 0xaf, + 0x63, 0x1d, 0x5b, 0x11, 0x97, 0x7f, 0xb1, 0x1a, 0x0c, 0x4f, 0xce, 0xee, 0x16, 0xa1, 0x76, 0xc3, 0x12, 0x48, 0xed, + 0x33, 0xd0, 0x5d, 0xdb, 0xd1, 0x35, 0xf4, 0xa1, 0x0d, 0xa2, 0xd9, 0x40, 0xff, 0xe5, 0xe2, 0x8d, 0xd5, 0xd5, 0xcf, + 0x40, 0x45, 0x7b, 0x33, 0xc3, 0x63, 0xef, 0xdc, 0xbf, 0x67, 0xc9, 0xb5, 0xa7, 0x6b, 0x98, 0xc1, 0x87, 0x0e, 0x3c, + 0x2c, 0xd3, 0x3c, 0x7d, 0x8f, 0x44, 0x11, 0x9a, 0xc8, 0xf5, 0xa6, 0x03, 0xc9, 0x71, 0xbd, 0xae, 0xe6, 0x7a, 0x87, + 0xf6, 0x51, 0x57, 0x3f, 0xfd, 0x46, 0xd3, 0x4e, 0x26, 0x6c, 0x9a, 0x9e, 0xe2, 0x15, 0xed, 0x04, 0xcf, 0x08, 0xfa, + 0xad, 0x69, 0xf6, 0x38, 0x4c, 0x2d, 0x57, 0x5b, 0xf3, 0x47, 0x4d, 0x9b, 0x06, 0x61, 0xd8, 0xd3, 0x1e, 0x4f, 0xbd, + 0xe9, 0xe1, 0xf4, 0x45, 0x9f, 0x17, 0xe7, 0xdf, 0x94, 0xaa, 0x9b, 0xf4, 0xaf, 0xa7, 0x34, 0x4b, 0xb3, 0x24, 0xfe, + 0xc4, 0xb8, 0xd9, 0x89, 0x26, 0x2f, 0x8f, 0xd5, 0xa6, 0x5e, 0xfd, 0x4b, 0x6e, 0x77, 0x34, 0x9e, 0x7a, 0x45, 0x75, + 0xec, 0xe3, 0x81, 0xec, 0xe4, 0xc9, 0x81, 0xe8, 0xfa, 0x89, 0x8a, 0x26, 0xd7, 0x6a, 0x42, 0x94, 0xab, 0xf3, 0x31, + 0xce, 0xc4, 0xf8, 0x4e, 0x20, 0x0e, 0xa3, 0x74, 0xd7, 0x85, 0x1e, 0xe8, 0xda, 0x64, 0xa0, 0xff, 0xe8, 0x7a, 0x5d, + 0xd3, 0x75, 0x8f, 0xec, 0xa3, 0xee, 0xd8, 0x31, 0x0f, 0xed, 0x43, 0xab, 0x6d, 0x1f, 0x99, 0x5d, 0xab, 0x6b, 0x76, + 0xff, 0xd6, 0x1d, 0x5b, 0x87, 0xf6, 0xa1, 0xe9, 0x58, 0x5d, 0x28, 0xb4, 0xba, 0x56, 0xf7, 0xc6, 0x3a, 0xec, 0x8e, + 0x1d, 0x2c, 0xf5, 0xec, 0x4e, 0xc7, 0x72, 0x1d, 0xbb, 0xd3, 0x31, 0x3b, 0xf6, 0xd1, 0x91, 0xe5, 0xb6, 0xed, 0xa3, + 0xa3, 0xf3, 0x4e, 0xd7, 0x6e, 0xc3, 0xbb, 0x76, 0x7b, 0xdc, 0xb6, 0x5d, 0xd7, 0x82, 0xbf, 0xcc, 0xae, 0xed, 0xd1, + 0x0f, 0xd7, 0xb5, 0xdb, 0xae, 0xe9, 0x84, 0x1d, 0xcf, 0x3e, 0x7a, 0x61, 0xe2, 0xdf, 0x58, 0xcd, 0xc4, 0xbf, 0x00, + 0x8c, 0xf9, 0xc2, 0xf6, 0x8e, 0xe8, 0x17, 0x02, 0xbc, 0x39, 0xec, 0xfe, 0xaa, 0x1f, 0x6c, 0x1c, 0x83, 0x4b, 0x63, + 0xe8, 0x76, 0xec, 0x76, 0xdb, 0x3c, 0x74, 0xed, 0x6e, 0x7b, 0x6e, 0x1d, 0x7a, 0xf6, 0xd1, 0xf1, 0xd8, 0x72, 0xed, + 0xe3, 0x63, 0xd3, 0xb1, 0xda, 0xb6, 0x67, 0xba, 0xf6, 0x61, 0x1b, 0x7f, 0xb4, 0x6d, 0xef, 0xe6, 0xf8, 0x85, 0x7d, + 0xd4, 0x99, 0x1f, 0xd9, 0x87, 0x1f, 0x0f, 0xbb, 0xb6, 0xd7, 0x9e, 0xb7, 0x8f, 0x6c, 0xef, 0xf8, 0xe6, 0xc8, 0x3e, + 0x9c, 0x5b, 0xde, 0xd1, 0xd6, 0x96, 0xae, 0x67, 0x03, 0x8e, 0xf0, 0x35, 0xbc, 0x30, 0xf9, 0x0b, 0xf8, 0x33, 0xc7, + 0xb6, 0xff, 0x45, 0x30, 0x69, 0xbd, 0xe9, 0x0b, 0xbb, 0x7b, 0x3c, 0xa6, 0xea, 0x50, 0x60, 0x89, 0x1a, 0xd0, 0xe4, + 0xc6, 0xa2, 0xcf, 0x22, 0x38, 0x4b, 0x00, 0x12, 0x7f, 0xf8, 0xc7, 0x6e, 0x2c, 0xf8, 0x30, 0x7d, 0xf7, 0x7f, 0x0a, + 0x47, 0x4e, 0x39, 0x64, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x49, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x45, 0xc5, 0xfb, 0xdd, + 0x8a, 0x8a, 0x37, 0xab, 0x7d, 0x14, 0x15, 0xef, 0xbf, 0xba, 0xa2, 0xe2, 0xbc, 0x6a, 0x27, 0xff, 0xbe, 0x1a, 0x9b, + 0xfe, 0xd7, 0x75, 0xf5, 0x1a, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x44, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, + 0x4a, 0x46, 0x60, 0x31, 0xd0, 0xd8, 0xf7, 0x31, 0xd1, 0xd8, 0xdf, 0x57, 0x03, 0xb0, 0x3c, 0xe1, 0x7c, 0x49, 0x30, + 0xb1, 0xe6, 0x7e, 0x38, 0x95, 0x3c, 0x0d, 0x94, 0xf4, 0xb1, 0x18, 0xbc, 0x12, 0xe0, 0xb8, 0x06, 0x75, 0xd8, 0x6a, + 0x11, 0xa5, 0xbd, 0x23, 0x07, 0x0e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xc6, 0xb6, 0x88, 0x47, 0x75, 0xcd, 0xbd, 0x26, + 0x36, 0xbe, 0x47, 0xa3, 0xc0, 0x66, 0xe8, 0x6e, 0x1d, 0xae, 0x06, 0xd6, 0x36, 0xc2, 0x68, 0x12, 0xd8, 0xb9, 0xa6, + 0xf7, 0x65, 0xd3, 0xbc, 0x8a, 0x31, 0xe6, 0xe6, 0x9e, 0x42, 0x4f, 0xaa, 0xed, 0xdd, 0xb2, 0x69, 0xdf, 0xae, 0x61, + 0x36, 0x7c, 0xbe, 0xd4, 0x7c, 0x8b, 0x5d, 0xa1, 0x04, 0x5c, 0x45, 0x55, 0x25, 0xb3, 0x5a, 0x23, 0x42, 0x0a, 0xee, + 0xbe, 0x30, 0x3e, 0x2c, 0x58, 0x4b, 0x47, 0x43, 0x7e, 0xc7, 0x51, 0xde, 0x95, 0x60, 0xaa, 0x06, 0x8b, 0xcf, 0xd6, + 0xc8, 0x71, 0x07, 0xbf, 0x03, 0xeb, 0xc8, 0x39, 0x9e, 0x51, 0xac, 0xe2, 0x79, 0xad, 0xc0, 0xa5, 0xcb, 0x4c, 0x3e, + 0x77, 0xd7, 0x75, 0xe6, 0x71, 0xa3, 0xa9, 0xb2, 0xcb, 0x16, 0x82, 0x0b, 0xc2, 0xcf, 0x93, 0x61, 0x70, 0x4e, 0xc6, + 0xdb, 0x68, 0xfb, 0xbc, 0x0d, 0x98, 0xa8, 0xf7, 0x18, 0x16, 0xb1, 0xc9, 0x1f, 0xd4, 0xb8, 0x00, 0xeb, 0x29, 0x64, + 0xc1, 0xee, 0x21, 0x9b, 0xa6, 0xf0, 0xa8, 0x1e, 0x5a, 0x31, 0xf7, 0xb7, 0x18, 0xd8, 0xa8, 0x80, 0x39, 0x10, 0xb4, + 0x86, 0xde, 0x66, 0x93, 0x23, 0x9d, 0x47, 0xd6, 0x25, 0x15, 0xb5, 0xdb, 0x39, 0x36, 0xdd, 0x23, 0xd3, 0x3e, 0xee, + 0x18, 0xb9, 0xd8, 0x70, 0x2a, 0xc8, 0x12, 0x42, 0xc0, 0x28, 0x5a, 0x76, 0x33, 0x88, 0x82, 0x2c, 0xf0, 0xc3, 0x1c, + 0xf8, 0xe3, 0xf2, 0xad, 0xe2, 0x9f, 0xab, 0x34, 0x83, 0x31, 0x0a, 0xa6, 0x17, 0x0d, 0xc2, 0xad, 0x11, 0xcb, 0x6e, + 0x19, 0x8b, 0x36, 0x28, 0xcb, 0xab, 0xf6, 0xe5, 0x7f, 0x9e, 0xb5, 0x6d, 0x4e, 0x96, 0x2c, 0xa3, 0x2c, 0xe2, 0xeb, + 0x43, 0x18, 0x43, 0xe7, 0x43, 0xf3, 0xa7, 0x4d, 0x04, 0xf7, 0x9f, 0xbb, 0x09, 0x6e, 0xc6, 0xf6, 0x21, 0xb8, 0xff, + 0xfc, 0xea, 0x04, 0xf7, 0x27, 0x95, 0xe0, 0x96, 0x7c, 0x81, 0x0a, 0xa9, 0xf3, 0x07, 0x7c, 0x6e, 0x41, 0x50, 0xe7, + 0xe7, 0xfa, 0x01, 0x31, 0xf0, 0xba, 0x92, 0x6c, 0xf7, 0x63, 0x29, 0x7b, 0x10, 0x0a, 0x45, 0x30, 0x08, 0x2d, 0x65, + 0x2a, 0x81, 0x44, 0xb4, 0x32, 0xa5, 0x3a, 0xc0, 0x7c, 0x1b, 0x65, 0xa1, 0xfd, 0x9e, 0x5f, 0xfc, 0x40, 0xc9, 0xf3, + 0x26, 0x4e, 0x16, 0x3e, 0x06, 0xe0, 0xd3, 0x31, 0xeb, 0x20, 0x3c, 0x38, 0xe0, 0x7f, 0x36, 0x8e, 0xa3, 0x89, 0xd4, + 0x54, 0xb0, 0xc1, 0x25, 0x71, 0xdc, 0xfa, 0x3d, 0xf3, 0x13, 0xdd, 0xa4, 0xd7, 0x30, 0xb9, 0xcf, 0xda, 0xce, 0x33, + 0xef, 0xf0, 0xd9, 0x91, 0x03, 0xff, 0xbb, 0xac, 0x9d, 0x9b, 0xbc, 0xe2, 0x22, 0x8e, 0x20, 0xf1, 0x89, 0xa8, 0xb9, + 0xa9, 0xda, 0x2d, 0x63, 0x9f, 0x8a, 0x5a, 0xc7, 0xcd, 0x95, 0x26, 0xfe, 0x7d, 0x51, 0xa7, 0xb1, 0xc6, 0x3c, 0x5e, + 0x29, 0xdd, 0x6a, 0xe8, 0x4d, 0x10, 0xad, 0x40, 0xf6, 0xa6, 0xd4, 0x50, 0x5f, 0xf3, 0xe1, 0x16, 0xe3, 0x62, 0xed, + 0xfc, 0xaa, 0xc8, 0xae, 0x24, 0xb2, 0xbc, 0xec, 0xc4, 0x20, 0x57, 0x5b, 0x38, 0x18, 0x9b, 0x1d, 0xf3, 0x0b, 0x69, + 0x90, 0xdb, 0x50, 0x4c, 0x90, 0x4f, 0x13, 0x94, 0x25, 0xab, 0x68, 0xdc, 0xc2, 0x9f, 0xfe, 0x28, 0x6d, 0x05, 0x07, + 0x10, 0x9d, 0x15, 0x3f, 0x6c, 0xe0, 0xac, 0xf9, 0xa7, 0x4e, 0x91, 0x8a, 0x22, 0x15, 0xb3, 0xe2, 0x3f, 0xcb, 0xcc, + 0x84, 0x12, 0xd8, 0xe2, 0xd4, 0x5a, 0x03, 0xff, 0x99, 0x6c, 0xf8, 0x2c, 0x33, 0x21, 0x89, 0x2c, 0x4c, 0xf7, 0xd3, + 0xa7, 0x54, 0x0b, 0xd2, 0x3a, 0xd2, 0xb0, 0xce, 0xc6, 0x45, 0x78, 0x37, 0xcd, 0x9f, 0xc5, 0x14, 0xe1, 0xad, 0x37, + 0x36, 0xe3, 0xe7, 0xcf, 0x4f, 0x07, 0xae, 0xc1, 0x93, 0x92, 0x96, 0x32, 0x68, 0x9d, 0xef, 0x67, 0x7c, 0x60, 0x34, + 0xba, 0xc5, 0x2d, 0xe1, 0xce, 0xe4, 0x08, 0x13, 0x65, 0x4e, 0xbd, 0x20, 0xa3, 0x05, 0x29, 0x19, 0x7d, 0x61, 0x04, + 0x20, 0xea, 0xc8, 0x5b, 0x57, 0xdb, 0x76, 0x6c, 0x47, 0x97, 0x0d, 0xa7, 0xc1, 0x6c, 0xb0, 0x8e, 0x33, 0x1f, 0x72, + 0x03, 0x85, 0xf1, 0x0c, 0x7c, 0x6b, 0xb2, 0x20, 0x0b, 0x21, 0xd1, 0x0c, 0x38, 0xd9, 0x2c, 0xe8, 0x5e, 0x9e, 0x73, + 0x8b, 0x67, 0x3f, 0xf9, 0x84, 0xc9, 0x06, 0x85, 0x5b, 0x1d, 0x46, 0x1c, 0xfa, 0x11, 0x0e, 0xc3, 0x96, 0xde, 0x82, + 0x54, 0x97, 0x2c, 0x49, 0x2d, 0xd5, 0x83, 0xa0, 0xa7, 0x41, 0x1b, 0x48, 0x43, 0x8f, 0x00, 0xa6, 0x89, 0xbf, 0x80, + 0x98, 0xec, 0xeb, 0xdc, 0xe4, 0x94, 0x56, 0xe7, 0xa4, 0x56, 0x73, 0x5f, 0x1c, 0x99, 0x9a, 0xe7, 0x9a, 0x9a, 0x03, + 0xe4, 0x56, 0xcf, 0xcd, 0x75, 0x7e, 0xd5, 0xdf, 0xa5, 0x04, 0x25, 0xfa, 0xf2, 0x98, 0xc6, 0x41, 0xea, 0x4f, 0x2e, + 0x5e, 0xce, 0x28, 0x80, 0x64, 0x4b, 0x89, 0x96, 0x1e, 0x90, 0x22, 0xe4, 0x82, 0xdd, 0x65, 0x06, 0x26, 0x62, 0xe1, + 0x55, 0x02, 0x63, 0x8d, 0xce, 0x7f, 0x41, 0xa4, 0x05, 0x9f, 0x3f, 0xb7, 0x02, 0x70, 0x70, 0x18, 0x28, 0xf8, 0x81, + 0x67, 0xa3, 0x84, 0xb0, 0xa0, 0x50, 0xdd, 0x21, 0xb2, 0xc0, 0xfb, 0x08, 0xfe, 0x2d, 0x8a, 0xc5, 0x0f, 0xae, 0x3a, + 0xb5, 0x43, 0x3f, 0x9a, 0x01, 0x49, 0xf3, 0xa3, 0x59, 0xcd, 0x44, 0x83, 0xfc, 0x17, 0x2b, 0xa5, 0x05, 0xa8, 0xc2, + 0x7c, 0x22, 0xfd, 0xfe, 0xfe, 0x82, 0x12, 0x4d, 0x41, 0x52, 0x73, 0x7f, 0x82, 0xce, 0x76, 0x85, 0x76, 0xe7, 0xf9, + 0xe0, 0xdb, 0x93, 0x05, 0xcb, 0x7c, 0x12, 0x0d, 0xc3, 0xe5, 0x17, 0xd8, 0x01, 0x6d, 0x2c, 0x92, 0xc4, 0x52, 0x32, + 0xf9, 0x09, 0xbb, 0x09, 0xc6, 0xfc, 0x5e, 0x6a, 0x6a, 0xfc, 0x9c, 0xb2, 0xd0, 0x0a, 0x6c, 0xe0, 0x9a, 0x64, 0x84, + 0x3c, 0xf6, 0x31, 0xcc, 0xe4, 0x20, 0x8a, 0xf5, 0xd3, 0x6f, 0xa5, 0xbf, 0xd6, 0xa6, 0x49, 0x80, 0x6c, 0x8f, 0x97, + 0x09, 0x0b, 0xff, 0x35, 0xf8, 0x16, 0x0e, 0xee, 0x6f, 0xaf, 0x74, 0xa3, 0x9f, 0xd9, 0xf3, 0x84, 0x4d, 0x07, 0xdf, + 0x36, 0x64, 0x3d, 0xc4, 0xeb, 0x3d, 0xf5, 0x45, 0x6f, 0x7b, 0x45, 0x70, 0xa0, 0xf6, 0x5e, 0x97, 0xfa, 0x53, 0x7e, + 0x5b, 0x87, 0x1b, 0xe0, 0xba, 0x74, 0xc7, 0x76, 0xfb, 0x78, 0x7f, 0x1e, 0x85, 0xfe, 0xf8, 0x53, 0x9f, 0xde, 0x94, + 0x1e, 0x2c, 0x38, 0xad, 0xc7, 0xfe, 0xb2, 0x87, 0xc7, 0xab, 0x5a, 0x08, 0xee, 0x9a, 0x54, 0x2a, 0x39, 0xbb, 0xc6, + 0xb5, 0x8c, 0x4b, 0x79, 0x8d, 0x5f, 0xc6, 0x4f, 0xdd, 0xce, 0x83, 0x8c, 0x89, 0x4f, 0xe1, 0x43, 0x9e, 0x8b, 0x8b, + 0x3a, 0x5d, 0x51, 0xf1, 0x62, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, + 0x74, 0xbb, 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, + 0x3f, 0xba, 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xad, 0xe0, 0x02, 0x44, 0xf7, 0x9d, 0x6f, 0x4b, 0x54, + 0x40, 0xf9, 0x2d, 0xf5, 0x34, 0x66, 0xe9, 0x78, 0x6b, 0xd0, 0xf5, 0x00, 0xc9, 0xd0, 0x4d, 0x11, 0x04, 0x32, 0xea, + 0xb7, 0x20, 0x0d, 0x3b, 0x26, 0x10, 0x10, 0x26, 0x2f, 0xc2, 0x2f, 0x55, 0x84, 0xd2, 0x6f, 0xdc, 0x46, 0xbc, 0x4d, + 0x73, 0xc0, 0x75, 0x91, 0x99, 0x8a, 0x94, 0x43, 0xbf, 0x2c, 0x31, 0x88, 0x91, 0x08, 0x11, 0xaf, 0x50, 0xa5, 0x22, + 0x3b, 0x62, 0xbe, 0xbb, 0xe3, 0xe8, 0x99, 0xcb, 0x64, 0x76, 0x9e, 0xaf, 0x0a, 0x9b, 0x2b, 0x8c, 0x24, 0xf4, 0x3f, + 0x0a, 0x07, 0x93, 0xd2, 0x12, 0x1c, 0x11, 0xcd, 0x75, 0x12, 0x24, 0xb2, 0x7b, 0x0a, 0x89, 0x76, 0x9b, 0x23, 0xd5, + 0x1b, 0x90, 0xc6, 0xe4, 0x2d, 0x70, 0xc9, 0x37, 0x7e, 0xa8, 0x18, 0xb7, 0x28, 0x2d, 0x1f, 0x49, 0xca, 0xff, 0xf4, + 0x69, 0xd1, 0x39, 0xab, 0xd2, 0xef, 0x13, 0xb7, 0x03, 0xc7, 0x6e, 0x87, 0xb5, 0xb7, 0xda, 0x59, 0xed, 0x0e, 0x07, + 0x5c, 0x84, 0x0b, 0x15, 0xb6, 0x14, 0x42, 0x8b, 0xbb, 0xd1, 0xd8, 0xab, 0xa6, 0xc3, 0x85, 0x40, 0xca, 0x95, 0xab, + 0x8e, 0x6e, 0xf4, 0x23, 0xa1, 0x92, 0x8c, 0xb6, 0x84, 0x40, 0xe6, 0x77, 0x31, 0x1d, 0x50, 0xb3, 0x65, 0x1c, 0x3b, + 0x9c, 0x46, 0xff, 0xd7, 0x83, 0x40, 0x07, 0x2e, 0xd0, 0xa1, 0x56, 0x76, 0x6b, 0xc9, 0xa1, 0x47, 0x9e, 0xab, 0x74, + 0xa0, 0xb2, 0xf4, 0x4c, 0x87, 0x22, 0xc8, 0x6f, 0x85, 0x29, 0xed, 0xa4, 0x01, 0x99, 0x3c, 0x2d, 0x8a, 0x02, 0x33, + 0x80, 0x18, 0xe0, 0x2d, 0xe1, 0x4c, 0x66, 0x3c, 0x7d, 0xba, 0xf1, 0x10, 0x22, 0x85, 0xbd, 0x9a, 0xd9, 0x53, 0x57, + 0xe9, 0x9b, 0xae, 0x92, 0x18, 0x09, 0x17, 0xa9, 0x86, 0xb0, 0x7b, 0xa3, 0xb5, 0x87, 0x3f, 0x47, 0xcc, 0xcf, 0x6c, + 0xae, 0x69, 0x6a, 0x29, 0x87, 0xbb, 0xe9, 0xb2, 0x36, 0x58, 0xbc, 0xf1, 0x58, 0x67, 0x3c, 0x96, 0xe0, 0x93, 0xf5, + 0xc7, 0x15, 0xf7, 0xf4, 0x06, 0x18, 0x9f, 0x9d, 0x22, 0x3c, 0xcd, 0xbb, 0xcc, 0xa7, 0x18, 0x26, 0xea, 0x91, 0x1b, + 0x67, 0xbe, 0xc8, 0x23, 0x03, 0x7c, 0x79, 0xbf, 0x51, 0x25, 0xab, 0x78, 0x83, 0x9f, 0xbe, 0xbb, 0xf8, 0x4e, 0xe3, + 0xeb, 0x9f, 0x34, 0x88, 0x78, 0x91, 0xa1, 0xac, 0x07, 0x03, 0xca, 0x7a, 0xa0, 0xf1, 0x34, 0x22, 0x90, 0x3b, 0x20, + 0x3f, 0x20, 0x0c, 0xa2, 0x00, 0x9a, 0xf4, 0xaa, 0x8b, 0x55, 0x98, 0x05, 0x4b, 0x3f, 0xc9, 0x0e, 0xa0, 0xa9, 0x05, + 0x44, 0x4e, 0xdf, 0xe4, 0x23, 0x4e, 0xaa, 0x59, 0x11, 0x62, 0x2f, 0x8b, 0x84, 0x6e, 0x76, 0x1a, 0x84, 0x52, 0x35, + 0x2b, 0x3e, 0xe0, 0x8f, 0xc7, 0x6c, 0x99, 0x0d, 0x74, 0x7f, 0x09, 0xd9, 0x2f, 0x30, 0x9e, 0xf5, 0x41, 0x3c, 0xce, + 0x58, 0x66, 0xa5, 0x59, 0xc2, 0xfc, 0x85, 0x2e, 0x43, 0xb9, 0xd6, 0xe1, 0xa5, 0xab, 0xd1, 0x22, 0xc8, 0x64, 0x2c, + 0x44, 0x1a, 0x20, 0x28, 0x49, 0xa1, 0x8b, 0xa7, 0xc3, 0x9c, 0xa3, 0xf0, 0x3c, 0x9e, 0x55, 0x56, 0x54, 0xc1, 0xb9, + 0x9c, 0x61, 0xa4, 0x5d, 0x9e, 0xf1, 0x60, 0x82, 0x3e, 0x4f, 0xd7, 0xdc, 0xaf, 0x5d, 0x86, 0x6c, 0xd4, 0x4f, 0x4f, + 0xf8, 0xf5, 0x56, 0xc3, 0x50, 0x0c, 0x7a, 0xc7, 0x81, 0x58, 0xc2, 0x9b, 0x3c, 0xde, 0x0f, 0x78, 0x65, 0x38, 0x9a, + 0x08, 0x32, 0xc6, 0x79, 0xa7, 0xbe, 0x5c, 0x00, 0x23, 0x54, 0x52, 0xa2, 0xcf, 0xdd, 0x53, 0xe9, 0x62, 0x85, 0xbd, + 0x42, 0x5e, 0xe9, 0xf3, 0xe7, 0x97, 0xc3, 0xff, 0xfc, 0x1b, 0x82, 0xd1, 0xcf, 0x5d, 0xe1, 0x67, 0x7e, 0xa9, 0xd6, + 0xe2, 0xdc, 0xa7, 0x39, 0x44, 0x03, 0x0a, 0x36, 0x11, 0x81, 0x57, 0xc4, 0xd2, 0xca, 0x87, 0x57, 0x22, 0x98, 0x16, + 0x24, 0x9c, 0x30, 0x84, 0x37, 0xfc, 0x10, 0xa6, 0x77, 0x28, 0x82, 0x30, 0x68, 0xbf, 0xdd, 0x7d, 0x7f, 0x0c, 0xc1, + 0x96, 0x6b, 0x79, 0x20, 0x94, 0x0e, 0xe2, 0x1a, 0x3a, 0x3d, 0xf1, 0x35, 0x64, 0x5a, 0x90, 0xfd, 0x48, 0x7b, 0x07, + 0x30, 0xcc, 0x79, 0xbc, 0x60, 0x76, 0x10, 0x1f, 0xdc, 0xb2, 0x91, 0xe5, 0x2f, 0x03, 0xd2, 0xd5, 0xa3, 0xdc, 0x4d, + 0x23, 0xce, 0x4f, 0xaa, 0xc0, 0x89, 0xbf, 0xce, 0x0b, 0x54, 0xc6, 0xe5, 0xe8, 0x69, 0x1d, 0xaf, 0x50, 0xdc, 0x81, + 0x4f, 0xb3, 0x82, 0xc7, 0xf8, 0xf4, 0xe4, 0xc0, 0x3f, 0x2d, 0x87, 0x6f, 0xb4, 0x45, 0x02, 0x81, 0xf2, 0x21, 0x70, + 0x46, 0x51, 0x18, 0x45, 0xc0, 0xc5, 0xe2, 0xc1, 0x8a, 0xa7, 0x53, 0x35, 0xe4, 0xa2, 0x5d, 0xee, 0x9e, 0x44, 0x5a, + 0xb1, 0xa4, 0xe3, 0x25, 0x7d, 0xa9, 0xfe, 0x09, 0xf9, 0x13, 0x92, 0x27, 0xf3, 0xe8, 0x9c, 0xb0, 0xdd, 0x6b, 0xa1, + 0x1b, 0x25, 0xc6, 0x1e, 0x53, 0x25, 0x4e, 0x47, 0xaa, 0x81, 0xc2, 0x37, 0x70, 0x2e, 0x8f, 0x06, 0x03, 0x22, 0x73, + 0x55, 0x6a, 0x07, 0x48, 0x6c, 0x48, 0xa6, 0x00, 0x83, 0xcd, 0xa0, 0xa1, 0x45, 0x2e, 0x74, 0xd8, 0xa8, 0x3a, 0x9c, + 0x7a, 0x1f, 0x0f, 0x7c, 0xb1, 0xfc, 0x4a, 0x0b, 0x14, 0x16, 0x1e, 0x9f, 0x77, 0xa0, 0xef, 0x02, 0x4e, 0x85, 0xcc, + 0x6b, 0x7f, 0x25, 0x8a, 0x6e, 0x85, 0xfe, 0x7d, 0xac, 0x98, 0x36, 0xf0, 0x28, 0x07, 0xe7, 0x58, 0x7a, 0x21, 0xbc, + 0x0b, 0x6b, 0x1b, 0x4d, 0x06, 0xa4, 0xaf, 0x6f, 0x36, 0x35, 0x82, 0xfc, 0xae, 0xbd, 0xa6, 0xd6, 0x2d, 0x0f, 0x06, + 0x89, 0x67, 0x5e, 0xec, 0xc3, 0xd2, 0x4b, 0x24, 0x0b, 0xf9, 0xc9, 0x01, 0x8c, 0x0f, 0x22, 0x33, 0x94, 0x18, 0xa7, + 0xc0, 0x80, 0xf0, 0x0f, 0x7e, 0x4a, 0xe6, 0x19, 0x6f, 0x27, 0x82, 0xe7, 0xc3, 0x8b, 0xa5, 0x8c, 0x0d, 0x5b, 0xaa, + 0x52, 0xe7, 0x65, 0x9c, 0x66, 0x26, 0x70, 0x77, 0x02, 0x87, 0xdf, 0x57, 0x98, 0xbd, 0x21, 0xef, 0x67, 0x4c, 0x38, + 0x3e, 0x9f, 0x67, 0x1b, 0x7c, 0xa3, 0x37, 0x55, 0x21, 0x7e, 0x76, 0x4b, 0x85, 0x62, 0x1d, 0x6f, 0xab, 0x55, 0x70, + 0x4e, 0xb2, 0xda, 0xd2, 0x6f, 0xe9, 0x8f, 0x71, 0xc5, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0x3b, 0xcf, 0x06, 0x50, 0x55, + 0xc8, 0xe2, 0xfd, 0xe5, 0x92, 0x2a, 0x1b, 0xfd, 0x93, 0x03, 0xba, 0x96, 0x9e, 0xd2, 0x0a, 0x3b, 0x3d, 0x01, 0xf3, + 0x4e, 0x9a, 0x74, 0x7f, 0xb9, 0xe4, 0x53, 0x4a, 0xbf, 0xe8, 0xcd, 0xc1, 0x3c, 0x5b, 0x84, 0xa7, 0xff, 0x07, 0xc0, + 0xb1, 0x34, 0x8b, 0x20, 0x5c, 0x03, 0x00}; } // namespace web_server } // namespace esphome From d7f6d4436e1b4e894306ded3489f6ea337dfffbc Mon Sep 17 00:00:00 2001 From: Colm Date: Thu, 11 Jul 2024 05:10:58 +0100 Subject: [PATCH 2058/2607] Add braces to if statement to avoid compiler warning. (#7036) --- esphome/components/aht10/aht10.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index 332218b9e9..441c1ac9df 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -93,8 +93,9 @@ void AHT10Component::restart_read_() { void AHT10Component::read_data_() { uint8_t data[6]; - if (this->read_count_ > 1) + if (this->read_count_ > 1) { ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); + } if (this->read(data, 6) != i2c::ERROR_OK) { this->status_set_warning("AHT10 read failed, retrying soon"); this->restart_read_(); @@ -119,8 +120,9 @@ void AHT10Component::read_data_() { return; } } - if (this->read_count_ > 1) + if (this->read_count_ > 1) { ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); + } uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; From 2d826768b05f33951d1bdd917f62f9db3792c7ce Mon Sep 17 00:00:00 2001 From: ttaborda <80131527+ttaborda@users.noreply.github.com> Date: Thu, 11 Jul 2024 05:26:37 +0100 Subject: [PATCH 2059/2607] Update mitsubishi.cpp (#6909) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mitsubishi/mitsubishi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index fd57adc586..a02aabf14d 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -52,6 +52,7 @@ const uint8_t MITSUBISHI_BYTE16 = 0X00; climate::ClimateTraits MitsubishiClimate::traits() { auto traits = climate::ClimateTraits(); + traits.set_supports_current_temperature(this->sensor_ != nullptr); traits.set_supports_action(false); traits.set_visual_min_temperature(MITSUBISHI_TEMP_MIN); traits.set_visual_max_temperature(MITSUBISHI_TEMP_MAX); From 531f33a158370f59fa246c064d01e28b80610bbc Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 11 Jul 2024 08:23:29 +0300 Subject: [PATCH 2060/2607] [climate] fix dump output of unsupported features (#7005) --- esphome/components/climate/climate.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 1822707152..bc8d932089 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -574,21 +574,25 @@ void Climate::dump_traits_(const char *tag) { ESP_LOGCONFIG(tag, " - Max temperature: %.1f", traits.get_visual_max_temperature()); ESP_LOGCONFIG(tag, " - Temperature step:"); ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step()); - ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step()); - ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity()); - ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity()); if (traits.get_supports_current_temperature()) { - ESP_LOGCONFIG(tag, " [x] Supports current temperature"); + ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step()); } - if (traits.get_supports_current_humidity()) { - ESP_LOGCONFIG(tag, " [x] Supports current humidity"); + if (traits.get_supports_target_humidity() || traits.get_supports_current_humidity()) { + ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity()); + ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity()); } if (traits.get_supports_two_point_target_temperature()) { ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature"); } + if (traits.get_supports_current_temperature()) { + ESP_LOGCONFIG(tag, " [x] Supports current temperature"); + } if (traits.get_supports_target_humidity()) { ESP_LOGCONFIG(tag, " [x] Supports target humidity"); } + if (traits.get_supports_current_humidity()) { + ESP_LOGCONFIG(tag, " [x] Supports current humidity"); + } if (traits.get_supports_action()) { ESP_LOGCONFIG(tag, " [x] Supports action"); } From 91bb38553d9eeec1f5a0347e48f9ffc5a70dadbf Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Thu, 11 Jul 2024 08:24:36 +0300 Subject: [PATCH 2061/2607] [climate-traits] improved performance (#7006) --- esphome/components/climate/climate_traits.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/climate/climate_traits.h b/esphome/components/climate/climate_traits.h index fd5b025a03..58d7b586d7 100644 --- a/esphome/components/climate/climate_traits.h +++ b/esphome/components/climate/climate_traits.h @@ -73,7 +73,7 @@ class ClimateTraits { ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } - std::set get_supported_modes() const { return supported_modes_; } + const std::set &get_supported_modes() const { return supported_modes_; } void set_supports_action(bool supports_action) { supports_action_ = supports_action; } bool get_supports_action() const { return supports_action_; } @@ -101,7 +101,7 @@ class ClimateTraits { void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } - std::set get_supported_fan_modes() const { return supported_fan_modes_; } + const std::set &get_supported_fan_modes() const { return supported_fan_modes_; } void set_supported_custom_fan_modes(std::set supported_custom_fan_modes) { supported_custom_fan_modes_ = std::move(supported_custom_fan_modes); @@ -140,7 +140,7 @@ class ClimateTraits { } bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); } bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); } - std::set get_supported_swing_modes() const { return supported_swing_modes_; } + const std::set &get_supported_swing_modes() const { return supported_swing_modes_; } float get_visual_min_temperature() const { return visual_min_temperature_; } void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } From a34cec217e50e9bbf26ce8494f9bec5abf9951ab Mon Sep 17 00:00:00 2001 From: leejoow Date: Thu, 11 Jul 2024 22:20:58 +0200 Subject: [PATCH 2062/2607] Add default icon to restart button (#7076) Co-authored-by: Leo Schelvis --- esphome/components/restart/button/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/restart/button/__init__.py b/esphome/components/restart/button/__init__.py index 1b2c991261..6aff8cb351 100644 --- a/esphome/components/restart/button/__init__.py +++ b/esphome/components/restart/button/__init__.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_RESTART, ENTITY_CATEGORY_CONFIG, + ICON_RESTART, ) restart_ns = cg.esphome_ns.namespace("restart") @@ -12,6 +13,7 @@ RestartButton = restart_ns.class_("RestartButton", button.Button, cg.Component) CONFIG_SCHEMA = button.button_schema( RestartButton, + icon=ICON_RESTART, device_class=DEVICE_CLASS_RESTART, entity_category=ENTITY_CATEGORY_CONFIG, ).extend(cv.COMPONENT_SCHEMA) From 54b77a1174b0912e028c5d8c1ba56068e30bc84e Mon Sep 17 00:00:00 2001 From: Tomi Junnila Date: Thu, 11 Jul 2024 23:32:38 +0300 Subject: [PATCH 2063/2607] Add support for the Gree YAC1FB9 in climate_ir (#7056) --- esphome/components/gree/climate.py | 1 + esphome/components/gree/gree.cpp | 14 +++++++++++--- esphome/components/gree/gree.h | 6 +++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/esphome/components/gree/climate.py b/esphome/components/gree/climate.py index 02ce7b12d4..c88a428391 100644 --- a/esphome/components/gree/climate.py +++ b/esphome/components/gree/climate.py @@ -16,6 +16,7 @@ MODELS = { "yan": Model.GREE_YAN, "yaa": Model.GREE_YAA, "yac": Model.GREE_YAC, + "yac1fb9": Model.GREE_YAC1FB9, } CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( diff --git a/esphome/components/gree/gree.cpp b/esphome/components/gree/gree.cpp index 1bbb443fce..cce2a8ffee 100644 --- a/esphome/components/gree/gree.cpp +++ b/esphome/components/gree/gree.cpp @@ -24,7 +24,7 @@ void GreeClimate::transmit_state() { remote_state[4] |= (this->horizontal_swing_() << 4); } - if (this->model_ == GREE_YAA || this->model_ == GREE_YAC) { + if (this->model_ == GREE_YAA || this->model_ == GREE_YAC || this->model_ == GREE_YAC1FB9) { remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN remote_state[3] = 0x50; // bits 4..7 always 0101 remote_state[6] = 0x20; // YAA1FB, FAA1FB1, YB1F2 bits 4..7 always 0010 @@ -53,7 +53,11 @@ void GreeClimate::transmit_state() { data->set_carrier_frequency(GREE_IR_FREQUENCY); data->mark(GREE_HEADER_MARK); - data->space(GREE_HEADER_SPACE); + if (this->model_ == GREE_YAC1FB9) { + data->space(GREE_YAC1FB9_HEADER_SPACE); + } else { + data->space(GREE_HEADER_SPACE); + } for (int i = 0; i < 4; i++) { for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask @@ -71,7 +75,11 @@ void GreeClimate::transmit_state() { data->space(GREE_ZERO_SPACE); data->mark(GREE_BIT_MARK); - data->space(GREE_MESSAGE_SPACE); + if (this->model_ == GREE_YAC1FB9) { + data->space(GREE_YAC1FB9_MESSAGE_SPACE); + } else { + data->space(GREE_MESSAGE_SPACE); + } for (int i = 4; i < 8; i++) { for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask diff --git a/esphome/components/gree/gree.h b/esphome/components/gree/gree.h index e7131a2b89..524a95aebd 100644 --- a/esphome/components/gree/gree.h +++ b/esphome/components/gree/gree.h @@ -41,6 +41,10 @@ const uint32_t GREE_YAC_HEADER_MARK = 6000; const uint32_t GREE_YAC_HEADER_SPACE = 3000; const uint32_t GREE_YAC_BIT_MARK = 650; +// Timing specific to YAC1FB9 +const uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500; +const uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980; + // State Frame size const uint8_t GREE_STATE_FRAME_SIZE = 8; @@ -67,7 +71,7 @@ const uint8_t GREE_HDIR_MRIGHT = 0x05; const uint8_t GREE_HDIR_RIGHT = 0x06; // Model codes -enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC }; +enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9 }; class GreeClimate : public climate_ir::ClimateIR { public: From fbab0aceb024175c86b330048c6f45814248ae97 Mon Sep 17 00:00:00 2001 From: Eugen Date: Thu, 11 Jul 2024 23:26:04 +0200 Subject: [PATCH 2064/2607] add ESP32-C6 support to esp32_can (#7063) --- esphome/components/esp32_can/canbus.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/esp32_can/canbus.py b/esphome/components/esp32_can/canbus.py index 74f331f30b..f4ba032009 100644 --- a/esphome/components/esp32_can/canbus.py +++ b/esphome/components/esp32_can/canbus.py @@ -11,6 +11,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, VARIANT_ESP32C3, + VARIANT_ESP32C6, VARIANT_ESP32H2, ) @@ -47,6 +48,7 @@ CAN_SPEEDS_ESP32_S2 = { CAN_SPEEDS_ESP32_S3 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS_ESP32_C3 = {**CAN_SPEEDS_ESP32_S2} +CAN_SPEEDS_ESP32_C6 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS_ESP32_H2 = {**CAN_SPEEDS_ESP32_S2} CAN_SPEEDS = { @@ -54,6 +56,7 @@ CAN_SPEEDS = { VARIANT_ESP32S2: CAN_SPEEDS_ESP32_S2, VARIANT_ESP32S3: CAN_SPEEDS_ESP32_S3, VARIANT_ESP32C3: CAN_SPEEDS_ESP32_C3, + VARIANT_ESP32C6: CAN_SPEEDS_ESP32_C6, VARIANT_ESP32H2: CAN_SPEEDS_ESP32_H2, } From c6c1d3a3ad2e6fefecd6de60584eea1e263734e2 Mon Sep 17 00:00:00 2001 From: kevdliu <1766838+kevdliu@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:32:31 -0400 Subject: [PATCH 2065/2607] Fix voice assistant crash when no speaker configured (#7075) --- esphome/components/voice_assistant/voice_assistant.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 8a8a9e92aa..e4f388db68 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -684,7 +684,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { this->defer([this, text]() { this->tts_start_trigger_->trigger(text); #ifdef USE_SPEAKER - this->speaker_->start(); + if (this->speaker_ != nullptr) { + this->speaker_->start(); + } #endif }); break; From 0c2f9b9dbbfaa14af7b608e6c6223fd6527bda52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jul 2024 23:19:33 +0200 Subject: [PATCH 2066/2607] Bump HeatpumpIR, add protocols, remove IRremoteESP8266 (#6996) --- esphome/components/heatpumpir/climate.py | 11 ++++++----- esphome/components/heatpumpir/heatpumpir.cpp | 5 +++++ esphome/components/heatpumpir/heatpumpir.h | 5 +++++ platformio.ini | 6 +++--- .../heatpumpir/test.bk72xx-ard.yaml | 19 +++++++++++++++++++ 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 tests/components/heatpumpir/test.bk72xx-ard.yaml diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index b86d405b7e..80900d7db9 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -8,7 +8,6 @@ from esphome.const import ( CONF_PROTOCOL, CONF_VISUAL, ) -from esphome.core import CORE CODEOWNERS = ["@rob-deutsch"] @@ -67,6 +66,11 @@ PROTOCOLS = { "carrier_qlima_2": Protocol.PROTOCOL_QLIMA_2, "samsung_aqv12msan": Protocol.PROTOCOL_SAMSUNG_AQV12MSAN, "zhjg01": Protocol.PROTOCOL_ZHJG01, + "airway": Protocol.PROTOCOL_AIRWAY, + "bgh_aud": Protocol.PROTOCOL_BGH_AUD, + "panasonic_altdke": Protocol.PROTOCOL_PANASONIC_ALTDKE, + "vaillantvai8": Protocol.PROTOCOL_VAILLANTVAI8, + "r51m": Protocol.PROTOCOL_R51M, } CONF_HORIZONTAL_DEFAULT = "horizontal_default" @@ -122,7 +126,4 @@ def to_code(config): cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE])) cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) - cg.add_library("tonia/HeatpumpIR", "1.0.26") - - if CORE.is_esp8266 or CORE.is_esp32: - cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.6") + cg.add_library("tonia/HeatpumpIR", "1.0.27") diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index 22a5779c8d..144dcc9bfa 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -61,6 +61,11 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_QLIMA_2, []() { return new Qlima2HeatpumpIR(); }}, // NOLINT {PROTOCOL_SAMSUNG_AQV12MSAN, []() { return new SamsungAQV12MSANHeatpumpIR(); }}, // NOLINT {PROTOCOL_ZHJG01, []() { return new ZHJG01HeatpumpIR(); }}, // NOLINT + {PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT + {PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT + {PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT + {PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT + {PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT }; void HeatpumpIRClimate::setup() { diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index 0e6ea2218f..f6e7ff3cd6 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -61,6 +61,11 @@ enum Protocol { PROTOCOL_QLIMA_2, PROTOCOL_SAMSUNG_AQV12MSAN, PROTOCOL_ZHJG01, + PROTOCOL_AIRWAY, + PROTOCOL_BGH_AUD, + PROTOCOL_PANASONIC_ALTDKE, + PROTOCOL_VAILLANTVAI8, + PROTOCOL_R51M, }; // Simple enum to represent horizontal directios diff --git a/platformio.ini b/platformio.ini index f07889526f..fc7f35b6c3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -65,7 +65,7 @@ lib_deps = glmnet/Dsmr@0.7 ; dsmr rweather/Crypto@0.4.0 ; dsmr dudanov/MideaUART@1.1.9 ; midea - tonia/HeatpumpIR@1.0.26 ; heatpumpir + tonia/HeatpumpIR@1.0.27 ; heatpumpir build_flags = ${common.build_flags} -DUSE_ARDUINO @@ -93,8 +93,8 @@ lib_deps = ESP8266HTTPClient ; http_request (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) - crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.2 ; wireguard + build_flags = ${common:arduino.build_flags} -Wno-nonnull-compare @@ -123,8 +123,8 @@ lib_deps = ESPmDNS ; mdns (Arduino built-in) DNSServer ; captive_portal (Arduino built-in) esphome/ESP32-audioI2S@2.0.7 ; i2s_audio - crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir droscy/esp_wireguard@0.4.2 ; wireguard + build_flags = ${common:arduino.build_flags} -DUSE_ESP32 diff --git a/tests/components/heatpumpir/test.bk72xx-ard.yaml b/tests/components/heatpumpir/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..90259f1244 --- /dev/null +++ b/tests/components/heatpumpir/test.bk72xx-ard.yaml @@ -0,0 +1,19 @@ +remote_transmitter: + pin: 6 + carrier_duty_percent: 50% + +climate: + - platform: heatpumpir + protocol: daikin + horizontal_default: mleft + vertical_default: mup + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 + - platform: heatpumpir + protocol: panasonic_altdke + horizontal_default: mright + vertical_default: mdown + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 From 316a0e1c967ad28f4ec43144cafea512f519d0a4 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Fri, 12 Jul 2024 21:42:41 +0000 Subject: [PATCH 2067/2607] LTR390 separate ALS and UV gain and resolution (#7026) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 +- esphome/components/ltr390/ltr390.cpp | 73 +++++++++++-------- esphome/components/ltr390/ltr390.h | 14 ++-- esphome/components/ltr390/sensor.py | 40 ++++++++-- tests/components/ltr390/test.esp32-ard.yaml | 18 +++++ tests/components/ltr390/test.esp8266-ard.yaml | 4 +- 6 files changed, 110 insertions(+), 41 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 5c14d30371..210c567f78 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -214,7 +214,7 @@ esphome/components/lightwaverf/* @max246 esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core -esphome/components/ltr390/* @sjtrny +esphome/components/ltr390/* @latonita @sjtrny esphome/components/ltr_als_ps/* @latonita esphome/components/matrix_keypad/* @ssieb esphome/components/max31865/* @DAVe3283 diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 4eb1ff2c46..198d15ebd8 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -19,6 +19,7 @@ static const uint8_t LTR390_MAIN_STATUS = 0x07; static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0}; static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125}; +static const uint8_t RESOLUTION_BITS[6] = {20, 19, 18, 17, 16, 13}; // Request fastest measurement rate - will be slowed by device if conversion rate is slower. static const float RESOLUTION_SETTING[6] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50}; @@ -74,7 +75,7 @@ void LTR390Component::read_als_() { uint32_t als = *val; if (this->light_sensor_ != nullptr) { - float lux = ((0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_])) * this->wfac_; + float lux = ((0.6 * als) / (GAINVALUES[this->gain_als_] * RESOLUTIONVALUE[this->res_als_])) * this->wfac_; this->light_sensor_->publish_state(lux); } @@ -90,7 +91,7 @@ void LTR390Component::read_uvs_() { uint32_t uv = *val; if (this->uvi_sensor_ != nullptr) { - this->uvi_sensor_->publish_state((uv / this->sensitivity_) * this->wfac_); + this->uvi_sensor_->publish_state((uv / this->sensitivity_uv_) * this->wfac_); } if (this->uv_sensor_ != nullptr) { @@ -107,24 +108,38 @@ void LTR390Component::read_mode_(int mode_index) { ctrl[LTR390_CTRL_EN] = true; this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); - // After the sensor integration time do the following - this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, - [this, mode_index]() { - // Read from the sensor - std::get<1>(this->mode_funcs_[mode_index])(); + uint32_t int_time{0}; + // Set gain, resolution and measurement rate + switch (mode) { + case LTR390_MODE_ALS: + this->reg(LTR390_GAIN) = this->gain_als_; + this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_als_]; + int_time = ((uint32_t) RESOLUTIONVALUE[this->res_als_]) * 100; + break; + case LTR390_MODE_UVS: + this->reg(LTR390_GAIN) = this->gain_uv_; + this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_uv_]; + int_time = ((uint32_t) RESOLUTIONVALUE[this->res_uv_]) * 100; + break; + } - // If there are more modes to read then begin the next - // otherwise stop - if (mode_index + 1 < (int) this->mode_funcs_.size()) { - this->read_mode_(mode_index + 1); - } else { - // put sensor in standby - std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); - ctrl[LTR390_CTRL_EN] = false; - this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); - this->reading_ = false; - } - }); + // After the sensor integration time do the following + this->set_timeout(int_time + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, [this, mode_index]() { + // Read from the sensor + std::get<1>(this->mode_funcs_[mode_index])(); + + // If there are more modes to read then begin the next + // otherwise stop + if (mode_index + 1 < (int) this->mode_funcs_.size()) { + this->read_mode_(mode_index + 1); + } else { + // put sensor in standby + std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); + ctrl[LTR390_CTRL_EN] = false; + this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); + this->reading_ = false; + } + }); } void LTR390Component::setup() { @@ -151,16 +166,10 @@ void LTR390Component::setup() { return; } - // Set gain - this->reg(LTR390_GAIN) = gain_; - - // Set resolution and measurement rate - this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_]; - // Set sensitivity by linearly scaling against known value in the datasheet - float gain_scale = GAINVALUES[this->gain_] / GAIN_MAX; - float intg_scale = (RESOLUTIONVALUE[this->res_] * 100) / INTG_MAX; - this->sensitivity_ = SENSITIVITY_MAX * gain_scale * intg_scale; + float gain_scale_uv = GAINVALUES[this->gain_uv_] / GAIN_MAX; + float intg_scale_uv = (RESOLUTIONVALUE[this->res_uv_] * 100) / INTG_MAX; + this->sensitivity_uv_ = SENSITIVITY_MAX * gain_scale_uv * intg_scale_uv; // Set sensor read state this->reading_ = false; @@ -176,7 +185,13 @@ void LTR390Component::setup() { } } -void LTR390Component::dump_config() { LOG_I2C_DEVICE(this); } +void LTR390Component::dump_config() { + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " ALS Gain: X%.0f", GAINVALUES[this->gain_als_]); + ESP_LOGCONFIG(TAG, " ALS Resolution: %u-bit", RESOLUTION_BITS[this->res_als_]); + ESP_LOGCONFIG(TAG, " UV Gain: X%.0f", GAINVALUES[this->gain_uv_]); + ESP_LOGCONFIG(TAG, " UV Resolution: %u-bit", RESOLUTION_BITS[this->res_uv_]); +} void LTR390Component::update() { if (!this->reading_ && !mode_funcs_.empty()) { diff --git a/esphome/components/ltr390/ltr390.h b/esphome/components/ltr390/ltr390.h index bc98518fe9..24afd3c411 100644 --- a/esphome/components/ltr390/ltr390.h +++ b/esphome/components/ltr390/ltr390.h @@ -49,8 +49,10 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice { void dump_config() override; void update() override; - void set_gain_value(LTR390GAIN gain) { this->gain_ = gain; } - void set_res_value(LTR390RESOLUTION res) { this->res_ = res; } + void set_als_gain_value(LTR390GAIN gain) { this->gain_als_ = gain; } + void set_uv_gain_value(LTR390GAIN gain) { this->gain_uv_ = gain; } + void set_als_res_value(LTR390RESOLUTION res) { this->res_als_ = res; } + void set_uv_res_value(LTR390RESOLUTION res) { this->res_uv_ = res; } void set_wfac_value(float wfac) { this->wfac_ = wfac; } void set_light_sensor(sensor::Sensor *light_sensor) { this->light_sensor_ = light_sensor; } @@ -71,9 +73,11 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice { // a list of modes and corresponding read functions std::vector>> mode_funcs_; - LTR390GAIN gain_; - LTR390RESOLUTION res_; - float sensitivity_; + LTR390GAIN gain_als_; + LTR390GAIN gain_uv_; + LTR390RESOLUTION res_als_; + LTR390RESOLUTION res_uv_; + float sensitivity_uv_; float wfac_; sensor::Sensor *light_sensor_{nullptr}; diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py index 8b2676599c..62c3edf8cb 100644 --- a/esphome/components/ltr390/sensor.py +++ b/esphome/components/ltr390/sensor.py @@ -13,7 +13,7 @@ from esphome.const import ( UNIT_LUX, ) -CODEOWNERS = ["@sjtrny"] +CODEOWNERS = ["@sjtrny", "@latonita"] DEPENDENCIES = ["i2c"] ltr390_ns = cg.esphome_ns.namespace("ltr390") @@ -76,8 +76,24 @@ CONFIG_SCHEMA = cv.All( accuracy_decimals=1, device_class=DEVICE_CLASS_EMPTY, ), - cv.Optional(CONF_GAIN, default="X18"): cv.enum(GAIN_OPTIONS), - cv.Optional(CONF_RESOLUTION, default=20): cv.enum(RES_OPTIONS), + cv.Optional(CONF_GAIN, default="X18"): cv.Any( + cv.enum(GAIN_OPTIONS), + cv.Schema( + { + cv.Required(CONF_AMBIENT_LIGHT): cv.enum(GAIN_OPTIONS), + cv.Required(CONF_UV): cv.enum(GAIN_OPTIONS), + } + ), + ), + cv.Optional(CONF_RESOLUTION, default=20): cv.Any( + cv.enum(RES_OPTIONS), + cv.Schema( + { + cv.Required(CONF_AMBIENT_LIGHT): cv.enum(RES_OPTIONS), + cv.Required(CONF_UV): cv.enum(RES_OPTIONS), + } + ), + ), cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range( min=1.0 ), @@ -101,11 +117,25 @@ async def to_code(config): await cg.register_component(var, config) await i2c.register_i2c_device(var, config) - cg.add(var.set_gain_value(config[CONF_GAIN])) - cg.add(var.set_res_value(config[CONF_RESOLUTION])) cg.add(var.set_wfac_value(config[CONF_WINDOW_CORRECTION_FACTOR])) for key, funcName in TYPES.items(): if key in config: sens = await sensor.new_sensor(config[key]) cg.add(getattr(var, funcName)(sens)) + + gain_value = config[CONF_GAIN] + if isinstance(gain_value, dict): + cg.add(var.set_als_gain_value(gain_value[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_gain_value(gain_value[CONF_UV])) + else: + cg.add(var.set_als_gain_value(gain_value)) + cg.add(var.set_uv_gain_value(gain_value)) + + res_value = config[CONF_RESOLUTION] + if isinstance(res_value, dict): + cg.add(var.set_als_res_value(res_value[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_res_value(res_value[CONF_UV])) + else: + cg.add(var.set_als_res_value(res_value)) + cg.add(var.set_uv_res_value(res_value)) diff --git a/tests/components/ltr390/test.esp32-ard.yaml b/tests/components/ltr390/test.esp32-ard.yaml index 9786c7dac3..bdfe349b77 100644 --- a/tests/components/ltr390/test.esp32-ard.yaml +++ b/tests/components/ltr390/test.esp32-ard.yaml @@ -18,3 +18,21 @@ sensor: window_correction_factor: 1.0 address: 0x53 update_interval: 60s + - platform: ltr390 + uv: + name: LTR390 UV + uv_index: + name: LTR390 UVI + light: + name: LTR390 Light + ambient_light: + name: LTR390 ALS + gain: + ambient_light: X9 + uv: X3 + resolution: + ambient_light: 18 + uv: 13 + window_correction_factor: 1.0 + address: 0x53 + update_interval: 60s diff --git a/tests/components/ltr390/test.esp8266-ard.yaml b/tests/components/ltr390/test.esp8266-ard.yaml index fee0f37ce1..149f46f9c8 100644 --- a/tests/components/ltr390/test.esp8266-ard.yaml +++ b/tests/components/ltr390/test.esp8266-ard.yaml @@ -13,7 +13,9 @@ sensor: name: LTR390 Light ambient_light: name: LTR390 ALS - gain: X3 + gain: + ambient_light: X9 + uv: X3 resolution: 18 window_correction_factor: 1.0 address: 0x53 From bb92ab01d736d8bffa0a2d90713d12ff2f03d774 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 13 Jul 2024 09:46:08 +1200 Subject: [PATCH 2068/2607] Bump version to 2024.7.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d672cc92af..4776de4d67 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0b1" +__version__ = "2024.7.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 44d609b205c1549ae4c2ab7be31d81b0f67e8755 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 14 Jul 2024 22:05:02 +0200 Subject: [PATCH 2069/2607] [CI] compile entire web_server during tests (#7084) --- tests/components/web_server/common.yaml | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/components/web_server/common.yaml b/tests/components/web_server/common.yaml index 94388726c3..338d9e97d2 100644 --- a/tests/components/web_server/common.yaml +++ b/tests/components/web_server/common.yaml @@ -5,3 +5,38 @@ wifi: web_server: port: 8080 version: 2 + +binary_sensor: +cover: +fan: +light: +sensor: +switch: +button: +text_sensor: +climate: +number: +text: +select: +lock: +valve: +alarm_control_panel: +api: +time: + - platform: homeassistant + id: homeassistant_time +datetime: + - platform: template + id: my_datetime_date + type: date + optimistic: yes + - platform: template + id: my_datetime_time + type: time + optimistic: yes + - platform: template + id: my_datetime + type: datetime + optimistic: yes +event: +update: From 896af84acc967aca74bc3cf832fb4e7da47ad032 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 14 Jul 2024 15:06:10 -0500 Subject: [PATCH 2070/2607] [improv_serial] Fix linker error created in #6998 (#7082) --- esphome/components/improv_serial/improv_serial_component.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 02ffa9f31c..12809e38cb 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -57,7 +57,7 @@ optional ImprovSerialComponent::read_byte_() { } } break; -#ifdef USE_LOGGER_USB_CDC +#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) case logger::UART_SELECTION_USB_CDC: #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) if (esp_usb_console_available_for_read()) { @@ -99,7 +99,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 uart_write_bytes(this->uart_num_, data.data(), data.size()); break; -#ifdef USE_LOGGER_USB_CDC +#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) case logger::UART_SELECTION_USB_CDC: { const char *msg = (char *) data.data(); esp_usb_console_write_buf(msg, data.size()); @@ -109,6 +109,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #ifdef USE_LOGGER_USB_SERIAL_JTAG case logger::UART_SELECTION_USB_SERIAL_JTAG: usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); + delay(10); usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7 break; #endif // USE_LOGGER_USB_SERIAL_JTAG From 07b78fea760e78e5be5c0dbbf506f2fca490cff0 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 14 Jul 2024 15:32:10 -0500 Subject: [PATCH 2071/2607] [CI] Add more ``improv_serial`` tests (#7081) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../improv_serial/{common.yaml => common-uart0.yaml} | 3 +++ tests/components/improv_serial/common-usb_cdc.yaml | 8 ++++++++ .../components/improv_serial/common-usb_serial_jtag.yaml | 8 ++++++++ tests/components/improv_serial/test-uart0.esp32-ard.yaml | 1 + .../components/improv_serial/test-uart0.esp32-c3-ard.yaml | 1 + .../components/improv_serial/test-uart0.esp32-c3-idf.yaml | 1 + tests/components/improv_serial/test-uart0.esp32-idf.yaml | 1 + .../components/improv_serial/test-uart0.esp32-s2-ard.yaml | 1 + .../components/improv_serial/test-uart0.esp32-s2-idf.yaml | 1 + .../components/improv_serial/test-uart0.esp32-s3-ard.yaml | 1 + .../components/improv_serial/test-uart0.esp32-s3-idf.yaml | 1 + .../components/improv_serial/test-uart0.esp8266-ard.yaml | 1 + tests/components/improv_serial/test-uart0.rp2040-ard.yaml | 1 + .../improv_serial/test-usb_cdc.esp32-c3-ard.yaml | 1 + .../improv_serial/test-usb_cdc.esp32-s2-ard.yaml | 1 + .../improv_serial/test-usb_cdc.esp32-s2-idf.yaml | 1 + .../improv_serial/test-usb_cdc.esp32-s3-ard.yaml | 1 + .../components/improv_serial/test-usb_cdc.rp2040-ard.yaml | 1 + .../improv_serial/test-usb_serial_jtag.esp32-c3-idf.yaml | 1 + .../improv_serial/test-usb_serial_jtag.esp32-s3-idf.yaml | 1 + tests/components/improv_serial/test.esp32-ard.yaml | 1 - tests/components/improv_serial/test.esp32-c3-ard.yaml | 1 - tests/components/improv_serial/test.esp32-c3-idf.yaml | 1 - tests/components/improv_serial/test.esp32-idf.yaml | 1 - tests/components/improv_serial/test.esp8266-ard.yaml | 1 - tests/components/improv_serial/test.rp2040-ard.yaml | 1 - 26 files changed, 36 insertions(+), 6 deletions(-) rename tests/components/improv_serial/{common.yaml => common-uart0.yaml} (64%) create mode 100644 tests/components/improv_serial/common-usb_cdc.yaml create mode 100644 tests/components/improv_serial/common-usb_serial_jtag.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-ard.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-c3-ard.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-c3-idf.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-idf.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-s2-ard.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-s2-idf.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-s3-ard.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp32-s3-idf.yaml create mode 100644 tests/components/improv_serial/test-uart0.esp8266-ard.yaml create mode 100644 tests/components/improv_serial/test-uart0.rp2040-ard.yaml create mode 100644 tests/components/improv_serial/test-usb_cdc.esp32-c3-ard.yaml create mode 100644 tests/components/improv_serial/test-usb_cdc.esp32-s2-ard.yaml create mode 100644 tests/components/improv_serial/test-usb_cdc.esp32-s2-idf.yaml create mode 100644 tests/components/improv_serial/test-usb_cdc.esp32-s3-ard.yaml create mode 100644 tests/components/improv_serial/test-usb_cdc.rp2040-ard.yaml create mode 100644 tests/components/improv_serial/test-usb_serial_jtag.esp32-c3-idf.yaml create mode 100644 tests/components/improv_serial/test-usb_serial_jtag.esp32-s3-idf.yaml delete mode 100644 tests/components/improv_serial/test.esp32-ard.yaml delete mode 100644 tests/components/improv_serial/test.esp32-c3-ard.yaml delete mode 100644 tests/components/improv_serial/test.esp32-c3-idf.yaml delete mode 100644 tests/components/improv_serial/test.esp32-idf.yaml delete mode 100644 tests/components/improv_serial/test.esp8266-ard.yaml delete mode 100644 tests/components/improv_serial/test.rp2040-ard.yaml diff --git a/tests/components/improv_serial/common.yaml b/tests/components/improv_serial/common-uart0.yaml similarity index 64% rename from tests/components/improv_serial/common.yaml rename to tests/components/improv_serial/common-uart0.yaml index b36fe5a4a7..7b7730fd46 100644 --- a/tests/components/improv_serial/common.yaml +++ b/tests/components/improv_serial/common-uart0.yaml @@ -2,4 +2,7 @@ wifi: ssid: MySSID password: password1 +logger: + hardware_uart: UART0 + improv_serial: diff --git a/tests/components/improv_serial/common-usb_cdc.yaml b/tests/components/improv_serial/common-usb_cdc.yaml new file mode 100644 index 0000000000..fc72b6aa7e --- /dev/null +++ b/tests/components/improv_serial/common-usb_cdc.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +logger: + hardware_uart: USB_CDC + +improv_serial: diff --git a/tests/components/improv_serial/common-usb_serial_jtag.yaml b/tests/components/improv_serial/common-usb_serial_jtag.yaml new file mode 100644 index 0000000000..0abcc07168 --- /dev/null +++ b/tests/components/improv_serial/common-usb_serial_jtag.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +logger: + hardware_uart: USB_SERIAL_JTAG + +improv_serial: diff --git a/tests/components/improv_serial/test-uart0.esp32-ard.yaml b/tests/components/improv_serial/test-uart0.esp32-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-c3-ard.yaml b/tests/components/improv_serial/test-uart0.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-c3-idf.yaml b/tests/components/improv_serial/test-uart0.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-idf.yaml b/tests/components/improv_serial/test-uart0.esp32-idf.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-s2-ard.yaml b/tests/components/improv_serial/test-uart0.esp32-s2-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-s2-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-s2-idf.yaml b/tests/components/improv_serial/test-uart0.esp32-s2-idf.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-s2-idf.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-s3-ard.yaml b/tests/components/improv_serial/test-uart0.esp32-s3-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-s3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp32-s3-idf.yaml b/tests/components/improv_serial/test-uart0.esp32-s3-idf.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp32-s3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.esp8266-ard.yaml b/tests/components/improv_serial/test-uart0.esp8266-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-uart0.rp2040-ard.yaml b/tests/components/improv_serial/test-uart0.rp2040-ard.yaml new file mode 100644 index 0000000000..ef8c799241 --- /dev/null +++ b/tests/components/improv_serial/test-uart0.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-uart0.yaml diff --git a/tests/components/improv_serial/test-usb_cdc.esp32-c3-ard.yaml b/tests/components/improv_serial/test-usb_cdc.esp32-c3-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/improv_serial/test-usb_cdc.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/improv_serial/test-usb_cdc.esp32-s2-ard.yaml b/tests/components/improv_serial/test-usb_cdc.esp32-s2-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/improv_serial/test-usb_cdc.esp32-s2-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/improv_serial/test-usb_cdc.esp32-s2-idf.yaml b/tests/components/improv_serial/test-usb_cdc.esp32-s2-idf.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/improv_serial/test-usb_cdc.esp32-s2-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/improv_serial/test-usb_cdc.esp32-s3-ard.yaml b/tests/components/improv_serial/test-usb_cdc.esp32-s3-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/improv_serial/test-usb_cdc.esp32-s3-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/improv_serial/test-usb_cdc.rp2040-ard.yaml b/tests/components/improv_serial/test-usb_cdc.rp2040-ard.yaml new file mode 100644 index 0000000000..cfdaec9771 --- /dev/null +++ b/tests/components/improv_serial/test-usb_cdc.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-usb_cdc.yaml diff --git a/tests/components/improv_serial/test-usb_serial_jtag.esp32-c3-idf.yaml b/tests/components/improv_serial/test-usb_serial_jtag.esp32-c3-idf.yaml new file mode 100644 index 0000000000..46a927ff10 --- /dev/null +++ b/tests/components/improv_serial/test-usb_serial_jtag.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_serial_jtag.yaml diff --git a/tests/components/improv_serial/test-usb_serial_jtag.esp32-s3-idf.yaml b/tests/components/improv_serial/test-usb_serial_jtag.esp32-s3-idf.yaml new file mode 100644 index 0000000000..46a927ff10 --- /dev/null +++ b/tests/components/improv_serial/test-usb_serial_jtag.esp32-s3-idf.yaml @@ -0,0 +1 @@ +<<: !include common-usb_serial_jtag.yaml diff --git a/tests/components/improv_serial/test.esp32-ard.yaml b/tests/components/improv_serial/test.esp32-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.esp32-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32-c3-ard.yaml b/tests/components/improv_serial/test.esp32-c3-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.esp32-c3-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32-c3-idf.yaml b/tests/components/improv_serial/test.esp32-c3-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.esp32-c3-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp32-idf.yaml b/tests/components/improv_serial/test.esp32-idf.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/improv_serial/test.esp8266-ard.yaml b/tests/components/improv_serial/test.esp8266-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.esp8266-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml diff --git a/tests/components/improv_serial/test.rp2040-ard.yaml b/tests/components/improv_serial/test.rp2040-ard.yaml deleted file mode 100644 index dade44d145..0000000000 --- a/tests/components/improv_serial/test.rp2040-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -<<: !include common.yaml From f1d19416be8753ff189562f5719b3e96a783414f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:28:41 +1200 Subject: [PATCH 2072/2607] [i2s_audio] Allow config for primary/secondary i2s mode (#7092) --- esphome/components/i2s_audio/__init__.py | 10 ++++++++++ esphome/components/i2s_audio/microphone/__init__.py | 7 +++++++ .../i2s_audio/microphone/i2s_audio_microphone.cpp | 5 ++--- .../i2s_audio/microphone/i2s_audio_microphone.h | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index d72e13630f..05e44696d8 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -25,6 +25,10 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" CONF_I2S_AUDIO = "i2s_audio" CONF_I2S_AUDIO_ID = "i2s_audio_id" +CONF_I2S_MODE = "i2s_mode" +CONF_PRIMARY = "primary" +CONF_SECONDARY = "secondary" + i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component) I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent)) @@ -32,6 +36,12 @@ I2SAudioOut = i2s_audio_ns.class_( "I2SAudioOut", cg.Parented.template(I2SAudioComponent) ) +i2s_mode_t = cg.global_ns.enum("i2s_mode_t") +I2S_MODE_OPTIONS = { + CONF_PRIMARY: i2s_mode_t.I2S_MODE_MASTER, # NOLINT + CONF_SECONDARY: i2s_mode_t.I2S_MODE_SLAVE, # NOLINT +} + # https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h I2S_PORTS = { VARIANT_ESP32: 2, diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index d9c31e8e7b..844f176bea 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -7,6 +7,9 @@ from esphome.components import microphone, esp32 from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin from .. import ( + CONF_I2S_MODE, + CONF_PRIMARY, + I2S_MODE_OPTIONS, i2s_audio_ns, I2SAudioComponent, I2SAudioIn, @@ -68,6 +71,9 @@ BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( _validate_bits, cv.enum(BITS_PER_SAMPLE) ), cv.Optional(CONF_USE_APLL, default=False): cv.boolean, + cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( + I2S_MODE_OPTIONS, lower=True + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -107,6 +113,7 @@ async def to_code(config): cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) cg.add(var.set_pdm(config[CONF_PDM])) + cg.add(var.set_i2s_mode(config[CONF_I2S_MODE])) cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index a672348d85..009fecdf90 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -46,7 +46,7 @@ void I2SAudioMicrophone::start_() { return; // Waiting for another i2s to return lock } i2s_driver_config_t config = { - .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX), + .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_RX), .sample_rate = this->sample_rate_, .bits_per_sample = this->bits_per_sample_, .channel_format = this->channel_, @@ -174,8 +174,7 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t samples_read = bytes_read / sizeof(int32_t); samples.resize(samples_read); for (size_t i = 0; i < samples_read; i++) { - int32_t temp = reinterpret_cast(buf)[i] >> 14; - samples[i] = clamp(temp, INT16_MIN, INT16_MAX); + samples[i] = reinterpret_cast(buf)[i] >> 16; } memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); return samples_read * sizeof(int16_t); diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 68b9a94fbd..07ca0528aa 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -30,6 +30,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub } #endif + void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; } + void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } @@ -46,6 +48,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub bool adc_{false}; #endif bool pdm_{false}; + i2s_mode_t i2s_mode_{}; i2s_channel_fmt_t channel_; uint32_t sample_rate_; i2s_bits_per_sample_t bits_per_sample_; From c910fdf7e52354e8d4945bdeac44cd2000448d4c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:29:45 +1200 Subject: [PATCH 2073/2607] [micro_wake_word] Allow simpler model config (#7094) --- esphome/components/micro_wake_word/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 3d3459ccab..c2faca25f4 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -357,7 +357,9 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(MicroWakeWord), cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), - cv.Required(CONF_MODELS): cv.ensure_list(MODEL_SCHEMA), + cv.Required(CONF_MODELS): cv.ensure_list( + cv.maybe_simple_value(MODEL_SCHEMA, key=CONF_MODEL) + ), cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation( single=True ), From eaf2bb70d9008d040427ec446cf9c4f7e515d524 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 14 Jul 2024 15:06:10 -0500 Subject: [PATCH 2074/2607] [improv_serial] Fix linker error created in #6998 (#7082) --- esphome/components/improv_serial/improv_serial_component.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 02ffa9f31c..12809e38cb 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -57,7 +57,7 @@ optional ImprovSerialComponent::read_byte_() { } } break; -#ifdef USE_LOGGER_USB_CDC +#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) case logger::UART_SELECTION_USB_CDC: #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) if (esp_usb_console_available_for_read()) { @@ -99,7 +99,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 uart_write_bytes(this->uart_num_, data.data(), data.size()); break; -#ifdef USE_LOGGER_USB_CDC +#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) case logger::UART_SELECTION_USB_CDC: { const char *msg = (char *) data.data(); esp_usb_console_write_buf(msg, data.size()); @@ -109,6 +109,7 @@ void ImprovSerialComponent::write_data_(std::vector &data) { #ifdef USE_LOGGER_USB_SERIAL_JTAG case logger::UART_SELECTION_USB_SERIAL_JTAG: usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS); + delay(10); usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7 break; #endif // USE_LOGGER_USB_SERIAL_JTAG From 41baf7066040900571bee2caeb5388578ce70268 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:28:41 +1200 Subject: [PATCH 2075/2607] [i2s_audio] Allow config for primary/secondary i2s mode (#7092) --- esphome/components/i2s_audio/__init__.py | 10 ++++++++++ esphome/components/i2s_audio/microphone/__init__.py | 7 +++++++ .../i2s_audio/microphone/i2s_audio_microphone.cpp | 5 ++--- .../i2s_audio/microphone/i2s_audio_microphone.h | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index d72e13630f..05e44696d8 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -25,6 +25,10 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" CONF_I2S_AUDIO = "i2s_audio" CONF_I2S_AUDIO_ID = "i2s_audio_id" +CONF_I2S_MODE = "i2s_mode" +CONF_PRIMARY = "primary" +CONF_SECONDARY = "secondary" + i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component) I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent)) @@ -32,6 +36,12 @@ I2SAudioOut = i2s_audio_ns.class_( "I2SAudioOut", cg.Parented.template(I2SAudioComponent) ) +i2s_mode_t = cg.global_ns.enum("i2s_mode_t") +I2S_MODE_OPTIONS = { + CONF_PRIMARY: i2s_mode_t.I2S_MODE_MASTER, # NOLINT + CONF_SECONDARY: i2s_mode_t.I2S_MODE_SLAVE, # NOLINT +} + # https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h I2S_PORTS = { VARIANT_ESP32: 2, diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index d9c31e8e7b..844f176bea 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -7,6 +7,9 @@ from esphome.components import microphone, esp32 from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin from .. import ( + CONF_I2S_MODE, + CONF_PRIMARY, + I2S_MODE_OPTIONS, i2s_audio_ns, I2SAudioComponent, I2SAudioIn, @@ -68,6 +71,9 @@ BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( _validate_bits, cv.enum(BITS_PER_SAMPLE) ), cv.Optional(CONF_USE_APLL, default=False): cv.boolean, + cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( + I2S_MODE_OPTIONS, lower=True + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -107,6 +113,7 @@ async def to_code(config): cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) cg.add(var.set_pdm(config[CONF_PDM])) + cg.add(var.set_i2s_mode(config[CONF_I2S_MODE])) cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index a672348d85..009fecdf90 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -46,7 +46,7 @@ void I2SAudioMicrophone::start_() { return; // Waiting for another i2s to return lock } i2s_driver_config_t config = { - .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX), + .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_RX), .sample_rate = this->sample_rate_, .bits_per_sample = this->bits_per_sample_, .channel_format = this->channel_, @@ -174,8 +174,7 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t samples_read = bytes_read / sizeof(int32_t); samples.resize(samples_read); for (size_t i = 0; i < samples_read; i++) { - int32_t temp = reinterpret_cast(buf)[i] >> 14; - samples[i] = clamp(temp, INT16_MIN, INT16_MAX); + samples[i] = reinterpret_cast(buf)[i] >> 16; } memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); return samples_read * sizeof(int16_t); diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 68b9a94fbd..07ca0528aa 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -30,6 +30,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub } #endif + void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; } + void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } @@ -46,6 +48,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub bool adc_{false}; #endif bool pdm_{false}; + i2s_mode_t i2s_mode_{}; i2s_channel_fmt_t channel_; uint32_t sample_rate_; i2s_bits_per_sample_t bits_per_sample_; From 0bbefb5b2a08f0f6b163f4d86c05b025e704b648 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:29:45 +1200 Subject: [PATCH 2076/2607] [micro_wake_word] Allow simpler model config (#7094) --- esphome/components/micro_wake_word/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index 3d3459ccab..c2faca25f4 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -357,7 +357,9 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(MicroWakeWord), cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), - cv.Required(CONF_MODELS): cv.ensure_list(MODEL_SCHEMA), + cv.Required(CONF_MODELS): cv.ensure_list( + cv.maybe_simple_value(MODEL_SCHEMA, key=CONF_MODEL) + ), cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation( single=True ), From 4af8230b4f1b8c420caf53e7270d9f8e31d988c4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:51:13 +1200 Subject: [PATCH 2077/2607] Bump version to 2024.7.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4776de4d67..dacd839eab 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0b2" +__version__ = "2024.7.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 0b3fe73b74b44f0be4f282a4cbe74252ba51453c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:13:02 +1200 Subject: [PATCH 2078/2607] Bump docker/build-push-action from 6.3.0 to 6.4.0 in /.github/actions/build-image (#7089) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index d5baf339aa..ac9a6ae53a 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.3.0 + uses: docker/build-push-action@v6.4.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.3.0 + uses: docker/build-push-action@v6.4.0 with: context: . file: ./docker/Dockerfile From 8980996b1aa84316e71b8ba5dea26c38c7b3f364 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 16 Jul 2024 07:14:33 +0200 Subject: [PATCH 2079/2607] [CI] add web_server v1 test (#7090) --- tests/components/web_server/common.yaml | 4 ---- tests/components/web_server/common_v1.yaml | 5 +++++ tests/components/web_server/common_v2.yaml | 5 +++++ tests/components/web_server/test.esp32-ard.yaml | 2 +- tests/components/web_server/test.esp32-c3-ard.yaml | 2 +- tests/components/web_server/test.esp32-c3-idf.yaml | 2 +- tests/components/web_server/test.esp32-idf.yaml | 2 +- tests/components/web_server/test.esp8266-ard.yaml | 2 +- tests/components/web_server/test_v1.esp32-ard.yaml | 1 + 9 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 tests/components/web_server/common_v1.yaml create mode 100644 tests/components/web_server/common_v2.yaml create mode 100644 tests/components/web_server/test_v1.esp32-ard.yaml diff --git a/tests/components/web_server/common.yaml b/tests/components/web_server/common.yaml index 338d9e97d2..eb768eeb91 100644 --- a/tests/components/web_server/common.yaml +++ b/tests/components/web_server/common.yaml @@ -2,10 +2,6 @@ wifi: ssid: MySSID password: password1 -web_server: - port: 8080 - version: 2 - binary_sensor: cover: fan: diff --git a/tests/components/web_server/common_v1.yaml b/tests/components/web_server/common_v1.yaml new file mode 100644 index 0000000000..bf5aab4ce6 --- /dev/null +++ b/tests/components/web_server/common_v1.yaml @@ -0,0 +1,5 @@ +<<: !include common.yaml + +web_server: + port: 8080 + version: 1 diff --git a/tests/components/web_server/common_v2.yaml b/tests/components/web_server/common_v2.yaml new file mode 100644 index 0000000000..564c43e553 --- /dev/null +++ b/tests/components/web_server/common_v2.yaml @@ -0,0 +1,5 @@ +<<: !include common.yaml + +web_server: + port: 8080 + version: 2 diff --git a/tests/components/web_server/test.esp32-ard.yaml b/tests/components/web_server/test.esp32-ard.yaml index dade44d145..7e6658e20e 100644 --- a/tests/components/web_server/test.esp32-ard.yaml +++ b/tests/components/web_server/test.esp32-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common_v2.yaml diff --git a/tests/components/web_server/test.esp32-c3-ard.yaml b/tests/components/web_server/test.esp32-c3-ard.yaml index dade44d145..7e6658e20e 100644 --- a/tests/components/web_server/test.esp32-c3-ard.yaml +++ b/tests/components/web_server/test.esp32-c3-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common_v2.yaml diff --git a/tests/components/web_server/test.esp32-c3-idf.yaml b/tests/components/web_server/test.esp32-c3-idf.yaml index dade44d145..7e6658e20e 100644 --- a/tests/components/web_server/test.esp32-c3-idf.yaml +++ b/tests/components/web_server/test.esp32-c3-idf.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common_v2.yaml diff --git a/tests/components/web_server/test.esp32-idf.yaml b/tests/components/web_server/test.esp32-idf.yaml index dade44d145..7e6658e20e 100644 --- a/tests/components/web_server/test.esp32-idf.yaml +++ b/tests/components/web_server/test.esp32-idf.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common_v2.yaml diff --git a/tests/components/web_server/test.esp8266-ard.yaml b/tests/components/web_server/test.esp8266-ard.yaml index dade44d145..7e6658e20e 100644 --- a/tests/components/web_server/test.esp8266-ard.yaml +++ b/tests/components/web_server/test.esp8266-ard.yaml @@ -1 +1 @@ -<<: !include common.yaml +<<: !include common_v2.yaml diff --git a/tests/components/web_server/test_v1.esp32-ard.yaml b/tests/components/web_server/test_v1.esp32-ard.yaml new file mode 100644 index 0000000000..389a930284 --- /dev/null +++ b/tests/components/web_server/test_v1.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common_v1.yaml From 659fdefccb851fa9e76d560b7574e5589b890d24 Mon Sep 17 00:00:00 2001 From: NewoPL <27411874+NewoPL@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:28:23 +0200 Subject: [PATCH 2080/2607] [wifi] Hostname may not be set as expected on Arduino platform (#7050) * bug #6014: workaround for not setting hostname on arduino plarform * moving handle initailisation to ESPHOME_EVENT_ID_WIFI_STA_START callback --- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index fc954a2333..71548b7a3e 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -82,8 +82,8 @@ bool WiFiComponent::wifi_mode_(optional sta, optional ap) { // WiFiClass::mode above calls esp_netif_create_default_wifi_sta() and // esp_netif_create_default_wifi_ap(), which creates the interfaces. - if (set_sta) - s_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + // s_sta_netif handle is set during ESPHOME_EVENT_ID_WIFI_STA_START event + #ifdef USE_WIFI_AP if (set_ap) s_ap_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); @@ -495,6 +495,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ case ESPHOME_EVENT_ID_WIFI_STA_START: { ESP_LOGV(TAG, "Event: WiFi STA start"); // apply hostname + s_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); esp_err_t err = esp_netif_set_hostname(s_sta_netif, App.get_name().c_str()); if (err != ERR_OK) { ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err)); From 193db50668d7f343e5ae22bcf6e3a5b1e2309adf Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:18:43 +1200 Subject: [PATCH 2081/2607] [ota] Print Arduino update errors (#7096) --- .../ota/ota_backend_arduino_esp32.cpp | 29 ++++++++++++----- .../ota/ota_backend_arduino_esp8266.cpp | 31 ++++++++++++++----- .../ota/ota_backend_arduino_libretiny.cpp | 29 ++++++++++++----- .../ota/ota_backend_arduino_rp2040.cpp | 29 ++++++++++++----- 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/esphome/components/ota/ota_backend_arduino_esp32.cpp b/esphome/components/ota/ota_backend_arduino_esp32.cpp index 62c6a72388..15dfc98a6c 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp32.cpp @@ -1,14 +1,17 @@ #ifdef USE_ESP32_FRAMEWORK_ARDUINO #include "esphome/core/defines.h" +#include "esphome/core/log.h" -#include "ota_backend_arduino_esp32.h" #include "ota_backend.h" +#include "ota_backend_arduino_esp32.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_esp32"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { @@ -20,6 +23,9 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { uint8_t error = Update.getError(); if (error == UPDATE_ERROR_SIZE) return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -27,16 +33,25 @@ void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5 OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoESP32OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoESP32OTABackend::abort() { Update.abort(); } diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.cpp b/esphome/components/ota/ota_backend_arduino_esp8266.cpp index b317075bd0..42edbf5d2b 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp8266.cpp @@ -1,16 +1,19 @@ #ifdef USE_ARDUINO #ifdef USE_ESP8266 -#include "ota_backend.h" #include "ota_backend_arduino_esp8266.h" +#include "ota_backend.h" -#include "esphome/core/defines.h" #include "esphome/components/esp8266/preferences.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_esp8266"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { @@ -29,6 +32,9 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; if (error == UPDATE_ERROR_SPACE) return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -36,16 +42,25 @@ void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(m OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoESP8266OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoESP8266OTABackend::abort() { diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp index df4e774ebc..6b2cf80684 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.cpp +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -1,14 +1,17 @@ #ifdef USE_LIBRETINY -#include "ota_backend.h" #include "ota_backend_arduino_libretiny.h" +#include "ota_backend.h" #include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_libretiny"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { @@ -20,6 +23,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { uint8_t error = Update.getError(); if (error == UPDATE_ERROR_SIZE) return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -27,16 +33,25 @@ void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5 OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoLibreTinyOTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoLibreTinyOTABackend::abort() { Update.abort(); } diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.cpp b/esphome/components/ota/ota_backend_arduino_rp2040.cpp index 4448b0c95e..ffeab2e93f 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.cpp +++ b/esphome/components/ota/ota_backend_arduino_rp2040.cpp @@ -1,16 +1,19 @@ #ifdef USE_ARDUINO #ifdef USE_RP2040 -#include "ota_backend.h" #include "ota_backend_arduino_rp2040.h" +#include "ota_backend.h" #include "esphome/components/rp2040/preferences.h" #include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_rp2040"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { @@ -29,6 +32,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; if (error == UPDATE_ERROR_SPACE) return OTA_RESPONSE_ERROR_RP2040_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -36,16 +42,25 @@ void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoRP2040OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoRP2040OTABackend::abort() { From 10205e06cb1de3b65e81dfcdc5a20fe890155162 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:06:27 +1000 Subject: [PATCH 2082/2607] Add host uart support for MacOS (#7095) --- esphome/components/uart/uart_component_host.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/uart/uart_component_host.cpp b/esphome/components/uart/uart_component_host.cpp index d8d2fd75b8..40d3e91ab2 100644 --- a/esphome/components/uart/uart_component_host.cpp +++ b/esphome/components/uart/uart_component_host.cpp @@ -5,8 +5,8 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#ifndef __linux__ -#error This HostUartComponent implementation is only for Linux +#if !(defined(__linux__) || defined(__APPLE__)) +#error This HostUartComponent implementation is not supported on this host OS #endif #include @@ -24,6 +24,9 @@ namespace { speed_t get_baud(int baud) { +#ifdef __APPLE__ + return baud; +#else switch (baud) { case 50: return B50; @@ -88,6 +91,7 @@ speed_t get_baud(int baud) { default: return B0; } +#endif } } // namespace From f153a7b0fd20bdf9a6b0772553c99f05021b04b7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:18:43 +1200 Subject: [PATCH 2083/2607] [ota] Print Arduino update errors (#7096) --- .../ota/ota_backend_arduino_esp32.cpp | 29 ++++++++++++----- .../ota/ota_backend_arduino_esp8266.cpp | 31 ++++++++++++++----- .../ota/ota_backend_arduino_libretiny.cpp | 29 ++++++++++++----- .../ota/ota_backend_arduino_rp2040.cpp | 29 ++++++++++++----- 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/esphome/components/ota/ota_backend_arduino_esp32.cpp b/esphome/components/ota/ota_backend_arduino_esp32.cpp index 62c6a72388..15dfc98a6c 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp32.cpp @@ -1,14 +1,17 @@ #ifdef USE_ESP32_FRAMEWORK_ARDUINO #include "esphome/core/defines.h" +#include "esphome/core/log.h" -#include "ota_backend_arduino_esp32.h" #include "ota_backend.h" +#include "ota_backend_arduino_esp32.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_esp32"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { @@ -20,6 +23,9 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { uint8_t error = Update.getError(); if (error == UPDATE_ERROR_SIZE) return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -27,16 +33,25 @@ void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5 OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoESP32OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoESP32OTABackend::abort() { Update.abort(); } diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.cpp b/esphome/components/ota/ota_backend_arduino_esp8266.cpp index b317075bd0..42edbf5d2b 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp8266.cpp @@ -1,16 +1,19 @@ #ifdef USE_ARDUINO #ifdef USE_ESP8266 -#include "ota_backend.h" #include "ota_backend_arduino_esp8266.h" +#include "ota_backend.h" -#include "esphome/core/defines.h" #include "esphome/components/esp8266/preferences.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_esp8266"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { @@ -29,6 +32,9 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; if (error == UPDATE_ERROR_SPACE) return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -36,16 +42,25 @@ void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(m OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoESP8266OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoESP8266OTABackend::abort() { diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp index df4e774ebc..6b2cf80684 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.cpp +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -1,14 +1,17 @@ #ifdef USE_LIBRETINY -#include "ota_backend.h" #include "ota_backend_arduino_libretiny.h" +#include "ota_backend.h" #include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_libretiny"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { @@ -20,6 +23,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { uint8_t error = Update.getError(); if (error == UPDATE_ERROR_SIZE) return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -27,16 +33,25 @@ void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5 OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoLibreTinyOTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoLibreTinyOTABackend::abort() { Update.abort(); } diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.cpp b/esphome/components/ota/ota_backend_arduino_rp2040.cpp index 4448b0c95e..ffeab2e93f 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.cpp +++ b/esphome/components/ota/ota_backend_arduino_rp2040.cpp @@ -1,16 +1,19 @@ #ifdef USE_ARDUINO #ifdef USE_RP2040 -#include "ota_backend.h" #include "ota_backend_arduino_rp2040.h" +#include "ota_backend.h" #include "esphome/components/rp2040/preferences.h" #include "esphome/core/defines.h" +#include "esphome/core/log.h" #include namespace esphome { namespace ota { +static const char *const TAG = "ota.arduino_rp2040"; + std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { @@ -29,6 +32,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; if (error == UPDATE_ERROR_SPACE) return OTA_RESPONSE_ERROR_RP2040_NOT_ENOUGH_SPACE; + + ESP_LOGE(TAG, "Begin error: %d", error); + return OTA_RESPONSE_ERROR_UNKNOWN; } @@ -36,16 +42,25 @@ void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; + if (written == len) { + return OTA_RESPONSE_OK; } - return OTA_RESPONSE_OK; + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "Write error: %d", error); + + return OTA_RESPONSE_ERROR_WRITING_FLASH; } OTAResponseTypes ArduinoRP2040OTABackend::end() { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; + if (Update.end()) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + ESP_LOGE(TAG, "End error: %d", error); + + return OTA_RESPONSE_ERROR_UPDATE_END; } void ArduinoRP2040OTABackend::abort() { From c512d5ebb66346cea81144b207408f19936f006d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:15:19 +1200 Subject: [PATCH 2084/2607] Bump version to 2024.7.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index dacd839eab..b59a2e9517 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0b3" +__version__ = "2024.7.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From e15d0ee150e879e2a6dce7b53ad7d35a2d500624 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:54:44 +1200 Subject: [PATCH 2085/2607] Bump version to 2024.7.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index b59a2e9517..d581f68470 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0b4" +__version__ = "2024.7.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From dd20c5eab0ca2441e7911ae85638a5a8237534cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:33:30 +1200 Subject: [PATCH 2086/2607] Bump docker/build-push-action from 6.4.0 to 6.4.1 in /.github/actions/build-image (#7102) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index ac9a6ae53a..e2febdad1b 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.4.0 + uses: docker/build-push-action@v6.4.1 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.4.0 + uses: docker/build-push-action@v6.4.1 with: context: . file: ./docker/Dockerfile From b32078a5fe8b05f6f3bf4234b24ec8b3a6871d02 Mon Sep 17 00:00:00 2001 From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:04:11 -0700 Subject: [PATCH 2087/2607] Prevent rename from deleting new config (#7104) --- esphome/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 5ff1a28ec7..b13f96daf7 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -695,7 +695,8 @@ def command_rename(args, config): os.remove(new_path) return 1 - os.remove(CORE.config_path) + if CORE.config_path != new_path: + os.remove(CORE.config_path) print(color(Fore.BOLD_GREEN, "SUCCESS")) print() From 0fb89d186964bc31b28b9873d3245981d19ce8df Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:26:21 +1200 Subject: [PATCH 2088/2607] [code-quality] Add some ruff configuration (#7103) --- pyproject.toml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index fe558f695f..cfc279845f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,3 +105,33 @@ disable = [ [tool.pylint.FORMAT] expected-line-ending-format = "LF" + +[tool.ruff] +required-version = ">=0.5.0" + +[tool.ruff.lint] +select = [ + "E", # pycodestyle + "F", # pyflakes/autoflake + "I", # isort + "PL", # pylint + "UP", # pyupgrade +] + +ignore = [ + "E501", # line too long + "PLR0911", # Too many return statements ({returns} > {max_returns}) + "PLR0912", # Too many branches ({branches} > {max_branches}) + "PLR0913", # Too many arguments to function call ({c_args} > {max_args}) + "PLR0915", # Too many statements ({statements} > {max_statements}) + "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable + "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target +] + +[tool.ruff.lint.isort] +force-sort-within-sections = true +known-first-party = [ + "esphome", +] +combine-as-imports = true +split-on-trailing-comma = false From c5b77f45902c7a3497278ecbadc6c4b799927d11 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Fri, 19 Jul 2024 06:35:41 +0200 Subject: [PATCH 2089/2607] [web_server] move v1 code to separate file (#7091) --- esphome/components/web_server/web_server.cpp | 209 ----------------- .../components/web_server/web_server_v1.cpp | 217 ++++++++++++++++++ 2 files changed, 217 insertions(+), 209 deletions(-) create mode 100644 esphome/components/web_server/web_server_v1.cpp diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 9a1641e86f..6fb04f558a 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -46,29 +46,6 @@ static const char *const HEADER_CORS_REQ_PNA = "Access-Control-Request-Private-N static const char *const HEADER_CORS_ALLOW_PNA = "Access-Control-Allow-Private-Network"; #endif -#if USE_WEBSERVER_VERSION == 1 -void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action, - const std::function &action_func = nullptr) { - stream->print("print(klass.c_str()); - if (obj->is_internal()) - stream->print(" internal"); - stream->print("\" id=\""); - stream->print(klass.c_str()); - stream->print("-"); - stream->print(obj->get_object_id().c_str()); - stream->print("\">"); - stream->print(obj->get_name().c_str()); - stream->print(""); - stream->print(action.c_str()); - if (action_func) { - action_func(*stream, obj); - } - stream->print(""); - stream->print(""); -} -#endif - UrlMatch match_url(const std::string &url, bool only_domain = false) { UrlMatch match; match.valid = false; @@ -102,11 +79,6 @@ WebServer::WebServer(web_server_base::WebServerBase *base) #endif } -#if USE_WEBSERVER_VERSION == 1 -void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; } -void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; } -#endif - #ifdef USE_WEBSERVER_CSS_INCLUDE void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; } #endif @@ -181,187 +153,6 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { response->addHeader("Content-Encoding", "gzip"); request->send(response); } -#elif USE_WEBSERVER_VERSION == 1 -void WebServer::handle_index_request(AsyncWebServerRequest *request) { - AsyncResponseStream *stream = request->beginResponseStream("text/html"); - const std::string &title = App.get_name(); - stream->print(F("")); - stream->print(title.c_str()); - stream->print(F("")); -#ifdef USE_WEBSERVER_CSS_INCLUDE - stream->print(F("")); -#endif - if (strlen(this->css_url_) > 0) { - stream->print(F(R"(print(this->css_url_); - stream->print(F("\">")); - } - stream->print(F("")); - stream->print(F("

")); - stream->print(title.c_str()); - stream->print(F("

")); - stream->print(F("

States

")); - -#ifdef USE_SENSOR - for (auto *obj : App.get_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "sensor", ""); - } -#endif - -#ifdef USE_SWITCH - for (auto *obj : App.get_switches()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "switch", ""); - } -#endif - -#ifdef USE_BUTTON - for (auto *obj : App.get_buttons()) - write_row(stream, obj, "button", ""); -#endif - -#ifdef USE_BINARY_SENSOR - for (auto *obj : App.get_binary_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "binary_sensor", ""); - } -#endif - -#ifdef USE_FAN - for (auto *obj : App.get_fans()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "fan", ""); - } -#endif - -#ifdef USE_LIGHT - for (auto *obj : App.get_lights()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "light", ""); - } -#endif - -#ifdef USE_TEXT_SENSOR - for (auto *obj : App.get_text_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "text_sensor", ""); - } -#endif - -#ifdef USE_COVER - for (auto *obj : App.get_covers()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "cover", ""); - } -#endif - -#ifdef USE_NUMBER - for (auto *obj : App.get_numbers()) { - if (this->include_internal_ || !obj->is_internal()) { - write_row(stream, obj, "number", "", [](AsyncResponseStream &stream, EntityBase *obj) { - number::Number *number = (number::Number *) obj; - stream.print(R"(traits.get_min_value()); - stream.print(R"(" max=")"); - stream.print(number->traits.get_max_value()); - stream.print(R"(" step=")"); - stream.print(number->traits.get_step()); - stream.print(R"(" value=")"); - stream.print(number->state); - stream.print(R"("/>)"); - }); - } - } -#endif - -#ifdef USE_TEXT - for (auto *obj : App.get_texts()) { - if (this->include_internal_ || !obj->is_internal()) { - write_row(stream, obj, "text", "", [](AsyncResponseStream &stream, EntityBase *obj) { - text::Text *text = (text::Text *) obj; - auto mode = (int) text->traits.get_mode(); - stream.print(R"(traits.get_min_length()); - stream.print(R"(" maxlength=")"); - stream.print(text->traits.get_max_length()); - stream.print(R"(" pattern=")"); - stream.print(text->traits.get_pattern().c_str()); - stream.print(R"(" value=")"); - stream.print(text->state.c_str()); - stream.print(R"("/>)"); - }); - } - } -#endif - -#ifdef USE_SELECT - for (auto *obj : App.get_selects()) { - if (this->include_internal_ || !obj->is_internal()) { - write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) { - select::Select *select = (select::Select *) obj; - stream.print(""); - }); - } - } -#endif - -#ifdef USE_LOCK - for (auto *obj : App.get_locks()) { - if (this->include_internal_ || !obj->is_internal()) { - write_row(stream, obj, "lock", "", [](AsyncResponseStream &stream, EntityBase *obj) { - lock::Lock *lock = (lock::Lock *) obj; - stream.print(""); - if (lock->traits.get_supports_open()) { - stream.print(""); - } - }); - } - } -#endif - -#ifdef USE_CLIMATE - for (auto *obj : App.get_climates()) { - if (this->include_internal_ || !obj->is_internal()) - write_row(stream, obj, "climate", ""); - } -#endif - - stream->print(F("
NameStateActions

See ESPHome Web API for " - "REST API documentation.

")); - if (this->allow_ota_) { - stream->print( - F("

OTA Update

")); - } - stream->print(F("

Debug Log

"));
-#ifdef USE_WEBSERVER_JS_INCLUDE
-  if (this->js_include_ != nullptr) {
-    stream->print(F(""));
-  }
-#endif
-  if (strlen(this->js_url_) > 0) {
-    stream->print(F(""));
-  }
-  stream->print(F("
")); - request->send(stream); -} #elif USE_WEBSERVER_VERSION >= 2 void WebServer::handle_index_request(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = diff --git a/esphome/components/web_server/web_server_v1.cpp b/esphome/components/web_server/web_server_v1.cpp new file mode 100644 index 0000000000..c9b38a2dc4 --- /dev/null +++ b/esphome/components/web_server/web_server_v1.cpp @@ -0,0 +1,217 @@ +#include "web_server.h" +#include "esphome/core/application.h" + +#if USE_WEBSERVER_VERSION == 1 + +namespace esphome { +namespace web_server { + +void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action, + const std::function &action_func = nullptr) { + stream->print("print(klass.c_str()); + if (obj->is_internal()) + stream->print(" internal"); + stream->print("\" id=\""); + stream->print(klass.c_str()); + stream->print("-"); + stream->print(obj->get_object_id().c_str()); + stream->print("\">"); + stream->print(obj->get_name().c_str()); + stream->print(""); + stream->print(action.c_str()); + if (action_func) { + action_func(*stream, obj); + } + stream->print(""); + stream->print(""); +} + +void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; } + +void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; } + +void WebServer::handle_index_request(AsyncWebServerRequest *request) { + AsyncResponseStream *stream = request->beginResponseStream("text/html"); + const std::string &title = App.get_name(); + stream->print(F("")); + stream->print(title.c_str()); + stream->print(F("")); +#ifdef USE_WEBSERVER_CSS_INCLUDE + stream->print(F("")); +#endif + if (strlen(this->css_url_) > 0) { + stream->print(F(R"(print(this->css_url_); + stream->print(F("\">")); + } + stream->print(F("")); + stream->print(F("

")); + stream->print(title.c_str()); + stream->print(F("

")); + stream->print(F("

States

")); + +#ifdef USE_SENSOR + for (auto *obj : App.get_sensors()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "sensor", ""); + } +#endif + +#ifdef USE_SWITCH + for (auto *obj : App.get_switches()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "switch", ""); + } +#endif + +#ifdef USE_BUTTON + for (auto *obj : App.get_buttons()) + write_row(stream, obj, "button", ""); +#endif + +#ifdef USE_BINARY_SENSOR + for (auto *obj : App.get_binary_sensors()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "binary_sensor", ""); + } +#endif + +#ifdef USE_FAN + for (auto *obj : App.get_fans()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "fan", ""); + } +#endif + +#ifdef USE_LIGHT + for (auto *obj : App.get_lights()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "light", ""); + } +#endif + +#ifdef USE_TEXT_SENSOR + for (auto *obj : App.get_text_sensors()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "text_sensor", ""); + } +#endif + +#ifdef USE_COVER + for (auto *obj : App.get_covers()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "cover", ""); + } +#endif + +#ifdef USE_NUMBER + for (auto *obj : App.get_numbers()) { + if (this->include_internal_ || !obj->is_internal()) { + write_row(stream, obj, "number", "", [](AsyncResponseStream &stream, EntityBase *obj) { + number::Number *number = (number::Number *) obj; + stream.print(R"(traits.get_min_value()); + stream.print(R"(" max=")"); + stream.print(number->traits.get_max_value()); + stream.print(R"(" step=")"); + stream.print(number->traits.get_step()); + stream.print(R"(" value=")"); + stream.print(number->state); + stream.print(R"("/>)"); + }); + } + } +#endif + +#ifdef USE_TEXT + for (auto *obj : App.get_texts()) { + if (this->include_internal_ || !obj->is_internal()) { + write_row(stream, obj, "text", "", [](AsyncResponseStream &stream, EntityBase *obj) { + text::Text *text = (text::Text *) obj; + auto mode = (int) text->traits.get_mode(); + stream.print(R"(traits.get_min_length()); + stream.print(R"(" maxlength=")"); + stream.print(text->traits.get_max_length()); + stream.print(R"(" pattern=")"); + stream.print(text->traits.get_pattern().c_str()); + stream.print(R"(" value=")"); + stream.print(text->state.c_str()); + stream.print(R"("/>)"); + }); + } + } +#endif + +#ifdef USE_SELECT + for (auto *obj : App.get_selects()) { + if (this->include_internal_ || !obj->is_internal()) { + write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) { + select::Select *select = (select::Select *) obj; + stream.print(""); + }); + } + } +#endif + +#ifdef USE_LOCK + for (auto *obj : App.get_locks()) { + if (this->include_internal_ || !obj->is_internal()) { + write_row(stream, obj, "lock", "", [](AsyncResponseStream &stream, EntityBase *obj) { + lock::Lock *lock = (lock::Lock *) obj; + stream.print(""); + if (lock->traits.get_supports_open()) { + stream.print(""); + } + }); + } + } +#endif + +#ifdef USE_CLIMATE + for (auto *obj : App.get_climates()) { + if (this->include_internal_ || !obj->is_internal()) + write_row(stream, obj, "climate", ""); + } +#endif + + stream->print(F("
NameStateActions

See ESPHome Web API for " + "REST API documentation.

")); + if (this->allow_ota_) { + stream->print( + F("

OTA Update

")); + } + stream->print(F("

Debug Log

"));
+#ifdef USE_WEBSERVER_JS_INCLUDE
+  if (this->js_include_ != nullptr) {
+    stream->print(F(""));
+  }
+#endif
+  if (strlen(this->js_url_) > 0) {
+    stream->print(F(""));
+  }
+  stream->print(F("
")); + request->send(stream); +} + +} // namespace web_server +} // namespace esphome +#endif From 32b927de7e319a4a1357a047959d365ccb85e919 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Fri, 19 Jul 2024 15:15:11 -0400 Subject: [PATCH 2090/2607] revert bit shift to match previous behavior (#7109) --- .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 009fecdf90..cb49a744fc 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -174,7 +174,8 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t samples_read = bytes_read / sizeof(int32_t); samples.resize(samples_read); for (size_t i = 0; i < samples_read; i++) { - samples[i] = reinterpret_cast(buf)[i] >> 16; + int32_t temp = reinterpret_cast(buf)[i] >> 14; + samples[i] = clamp(temp, INT16_MIN, INT16_MAX); } memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); return samples_read * sizeof(int16_t); From 43b818f2b1ca949ccc1ec216db9b5682e051541c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 22 Jul 2024 07:54:16 +1200 Subject: [PATCH 2091/2607] [validation] Add ``host`` to ``require_framework_version`` (#7107) --- esphome/config_validation.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 7259e3c062..3ef92ad460 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -829,7 +829,6 @@ def time_of_day(value): def date_time(date: bool, time: bool): - pattern_str = r"^" # Start of string if date: pattern_str += r"\d{4}-\d{1,2}-\d{1,2}" @@ -2031,6 +2030,7 @@ def require_framework_version( esp32_arduino=None, esp8266_arduino=None, rp2040_arduino=None, + host=None, max_version=False, extra_message=None, ): @@ -2065,6 +2065,13 @@ def require_framework_version( msg += f". {extra_message}" raise Invalid(msg) required = rp2040_arduino + elif CORE.is_host and framework == "host": + if host is None: + msg = "This feature is incompatible with host platform" + if extra_message: + msg += f". {extra_message}" + raise Invalid(msg) + required = host else: raise Invalid( f""" From cfb20abb9f0e7fc0b25b4cc792a560b4d91eb748 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 22 Jul 2024 08:09:06 +1200 Subject: [PATCH 2092/2607] [code-quality] Tidy up some duplicate CONFIG_SCHEMA assignments (#7106) --- esphome/components/ade7953/sensor.py | 2 +- esphome/components/bmp3xx/sensor.py | 2 +- esphome/components/ens160/sensor.py | 2 +- esphome/components/kalman_combinator/sensor.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/ade7953/sensor.py b/esphome/components/ade7953/sensor.py index 0caa2ef454..fc79888129 100644 --- a/esphome/components/ade7953/sensor.py +++ b/esphome/components/ade7953/sensor.py @@ -1,5 +1,5 @@ import esphome.config_validation as cv -CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( +CONFIG_SCHEMA = cv.invalid( "The ade7953 sensor component has been renamed to ade7953_i2c." ) diff --git a/esphome/components/bmp3xx/sensor.py b/esphome/components/bmp3xx/sensor.py index 89753768c3..3c7927f1a8 100644 --- a/esphome/components/bmp3xx/sensor.py +++ b/esphome/components/bmp3xx/sensor.py @@ -2,6 +2,6 @@ import esphome.config_validation as cv CODEOWNERS = ["@latonita"] -CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( +CONFIG_SCHEMA = cv.invalid( "The bmp3xx sensor component has been renamed to bmp3xx_i2c." ) diff --git a/esphome/components/ens160/sensor.py b/esphome/components/ens160/sensor.py index f666b530b3..441671fb7b 100644 --- a/esphome/components/ens160/sensor.py +++ b/esphome/components/ens160/sensor.py @@ -2,6 +2,6 @@ import esphome.config_validation as cv CODEOWNERS = ["@latonita"] -CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( +CONFIG_SCHEMA = cv.invalid( "The ens160 sensor component has been renamed to ens160_i2c." ) diff --git a/esphome/components/kalman_combinator/sensor.py b/esphome/components/kalman_combinator/sensor.py index eca1ba7b85..c19a17462d 100644 --- a/esphome/components/kalman_combinator/sensor.py +++ b/esphome/components/kalman_combinator/sensor.py @@ -1,6 +1,6 @@ import esphome.config_validation as cv -CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( +CONFIG_SCHEMA = cv.invalid( "The kalman_combinator sensor has moved.\nPlease use the combination platform instead with type: kalman.\n" "See https://esphome.io/components/sensor/combination.html" ) From fbc830176f612a341b5ace5418ab4f76cd4a578c Mon Sep 17 00:00:00 2001 From: Lucio Tarantino Date: Sun, 21 Jul 2024 23:16:51 +0200 Subject: [PATCH 2093/2607] [heatpumpir] Fix BK72XX Compile error with IRremoteESP8266 (#6955) --- esphome/components/heatpumpir/climate.py | 3 +++ tests/components/heatpumpir/test.bk72xx-ard.yaml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index 80900d7db9..9d31668deb 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_PROTOCOL, CONF_VISUAL, ) +from esphome.core import CORE CODEOWNERS = ["@rob-deutsch"] @@ -127,3 +128,5 @@ def to_code(config): cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) cg.add_library("tonia/HeatpumpIR", "1.0.27") + if CORE.is_libretiny: + CORE.add_platformio_option("lib_ignore", "IRremoteESP8266") diff --git a/tests/components/heatpumpir/test.bk72xx-ard.yaml b/tests/components/heatpumpir/test.bk72xx-ard.yaml index 90259f1244..b616f9157c 100644 --- a/tests/components/heatpumpir/test.bk72xx-ard.yaml +++ b/tests/components/heatpumpir/test.bk72xx-ard.yaml @@ -3,6 +3,13 @@ remote_transmitter: carrier_duty_percent: 50% climate: + - platform: heatpumpir + protocol: mitsubishi_heavy_zm + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 - platform: heatpumpir protocol: daikin horizontal_default: mleft From 368662969ed4c4df267499c720497d195acbed06 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Sun, 21 Jul 2024 23:36:46 +0200 Subject: [PATCH 2094/2607] Move MQTT ip discovery to deticated config option. (#6673) --- esphome/components/mqtt/__init__.py | 8 ++++++++ esphome/components/mqtt/mqtt_client.cpp | 18 +++++++++++++++--- esphome/components/mqtt/mqtt_client.h | 6 +++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 96a02cb60e..f4bd34bfd3 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -61,6 +61,7 @@ def AUTO_LOAD(): return ["json"] +CONF_DISCOVER_IP = "discover_ip" CONF_IDF_SEND_ASYNC = "idf_send_async" CONF_SKIP_CERT_CN_CHECK = "skip_cert_cn_check" @@ -225,6 +226,7 @@ CONFIG_SCHEMA = cv.All( cv.boolean, cv.one_of("CLEAN", upper=True) ), cv.Optional(CONF_DISCOVERY_RETAIN, default=True): cv.boolean, + cv.Optional(CONF_DISCOVER_IP, default=True): cv.boolean, cv.Optional( CONF_DISCOVERY_PREFIX, default="homeassistant" ): cv.publish_topic, @@ -328,8 +330,12 @@ async def to_code(config): discovery_prefix = config[CONF_DISCOVERY_PREFIX] discovery_unique_id_generator = config[CONF_DISCOVERY_UNIQUE_ID_GENERATOR] discovery_object_id_generator = config[CONF_DISCOVERY_OBJECT_ID_GENERATOR] + discover_ip = config[CONF_DISCOVER_IP] if not discovery: + discovery_prefix = "" + + if not discovery and not discover_ip: cg.add(var.disable_discovery()) elif discovery == "CLEAN": cg.add( @@ -338,6 +344,7 @@ async def to_code(config): discovery_unique_id_generator, discovery_object_id_generator, discovery_retain, + discover_ip, True, ) ) @@ -348,6 +355,7 @@ async def to_code(config): discovery_unique_id_generator, discovery_object_id_generator, discovery_retain, + discover_ip, ) ) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index d70b9cbd30..876367aaea 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -66,7 +66,7 @@ void MQTTClientComponent::setup() { } #endif - if (this->is_discovery_enabled()) { + if (this->is_discovery_ip_enabled()) { this->subscribe( "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); @@ -82,7 +82,7 @@ void MQTTClientComponent::setup() { } void MQTTClientComponent::send_device_info_() { - if (!this->is_connected() or !this->is_discovery_enabled()) { + if (!this->is_connected() or !this->is_discovery_ip_enabled()) { return; } std::string topic = "esphome/discover/"; @@ -99,6 +99,9 @@ void MQTTClientComponent::send_device_info_() { } } root["name"] = App.get_name(); + if (!App.get_friendly_name().empty()) { + root["friendly_name"] = App.get_friendly_name(); + } #ifdef USE_API root["port"] = api::global_api_server->get_port(); #endif @@ -130,6 +133,10 @@ void MQTTClientComponent::send_device_info_() { #ifdef USE_DASHBOARD_IMPORT root["package_import_url"] = dashboard_import::get_package_import_url(); #endif + +#ifdef USE_API_NOISE + root["api_encryption"] = "Noise_NNpsk0_25519_ChaChaPoly_SHA256"; +#endif }, 2, this->discovery_info_.retain); } @@ -140,6 +147,9 @@ void MQTTClientComponent::dump_config() { this->ip_.str().c_str()); ESP_LOGCONFIG(TAG, " Username: " LOG_SECRET("'%s'"), this->credentials_.username.c_str()); ESP_LOGCONFIG(TAG, " Client ID: " LOG_SECRET("'%s'"), this->credentials_.client_id.c_str()); + if (this->is_discovery_ip_enabled()) { + ESP_LOGCONFIG(TAG, " Discovery IP enabled"); + } if (!this->discovery_info_.prefix.empty()) { ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str()); ESP_LOGCONFIG(TAG, " Discovery retain: %s", YESNO(this->discovery_info_.retain)); @@ -581,6 +591,7 @@ void MQTTClientComponent::disable_shutdown_message() { this->recalculate_availability_(); } bool MQTTClientComponent::is_discovery_enabled() const { return !this->discovery_info_.prefix.empty(); } +bool MQTTClientComponent::is_discovery_ip_enabled() const { return this->discovery_info_.discover_ip; } const Availability &MQTTClientComponent::get_availability() { return this->availability_; } void MQTTClientComponent::recalculate_availability_() { if (this->birth_message_.topic.empty() || this->birth_message_.topic != this->last_will_.topic) { @@ -606,8 +617,9 @@ void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message) { this->sh void MQTTClientComponent::set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator, MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, - bool clean) { + bool discover_ip, bool clean) { this->discovery_info_.prefix = std::move(prefix); + this->discovery_info_.discover_ip = discover_ip; this->discovery_info_.unique_id_generator = unique_id_generator; this->discovery_info_.object_id_generator = object_id_generator; this->discovery_info_.retain = retain; diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 454316aa87..b0d3bbe66d 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -79,6 +79,7 @@ enum MQTTDiscoveryObjectIdGenerator { struct MQTTDiscoveryInfo { std::string prefix; ///< The Home Assistant discovery prefix. Empty means disabled. bool retain; ///< Whether to retain discovery messages. + bool discover_ip; ///< Enable the Home Assistant device discovery. bool clean; MQTTDiscoveryUniqueIdGenerator unique_id_generator; MQTTDiscoveryObjectIdGenerator object_id_generator; @@ -122,12 +123,14 @@ class MQTTClientComponent : public Component { * @param retain Whether to retain discovery messages. */ void set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator, - MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, bool clean = false); + MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, bool discover_ip, + bool clean = false); /// Get Home Assistant discovery info. const MQTTDiscoveryInfo &get_discovery_info() const; /// Globally disable Home Assistant discovery. void disable_discovery(); bool is_discovery_enabled() const; + bool is_discovery_ip_enabled() const; #if ASYNC_TCP_SSL_ENABLED /** Add a SSL fingerprint to use for TCP SSL connections to the MQTT broker. @@ -290,6 +293,7 @@ class MQTTClientComponent : public Component { MQTTDiscoveryInfo discovery_info_{ .prefix = "homeassistant", .retain = true, + .discover_ip = true, .clean = false, .unique_id_generator = MQTT_LEGACY_UNIQUE_ID_GENERATOR, .object_id_generator = MQTT_NONE_OBJECT_ID_GENERATOR, From 40e79299d55cd61e2f81b9f694e37ac3598c3d56 Mon Sep 17 00:00:00 2001 From: rnauber <7414650+rnauber@users.noreply.github.com> Date: Sun, 21 Jul 2024 23:57:59 +0200 Subject: [PATCH 2095/2607] Feature/m5angle8: Add support for m5angle8 input device (#6799) Co-authored-by: Richard Nauber Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/m5stack_8angle/__init__.py | 33 +++++++++ .../m5stack_8angle/binary_sensor/__init__.py | 30 ++++++++ .../m5stack_8angle_binary_sensor.cpp | 17 +++++ .../m5stack_8angle_binary_sensor.h | 19 +++++ .../m5stack_8angle/light/__init__.py | 31 ++++++++ .../light/m5stack_8angle_light.cpp | 45 +++++++++++ .../light/m5stack_8angle_light.h | 37 ++++++++++ .../m5stack_8angle/m5stack_8angle.cpp | 74 +++++++++++++++++++ .../m5stack_8angle/m5stack_8angle.h | 34 +++++++++ .../m5stack_8angle/sensor/__init__.py | 66 +++++++++++++++++ .../sensor/m5stack_8angle_sensor.cpp | 24 ++++++ .../sensor/m5stack_8angle_sensor.h | 27 +++++++ tests/components/m5stack_8angle/common.yaml | 30 ++++++++ .../m5stack_8angle/test.esp32-ard.yaml | 1 + .../m5stack_8angle/test.esp32-c3-ard.yaml | 1 + .../m5stack_8angle/test.esp32-c3-idf.yaml | 1 + .../m5stack_8angle/test.esp32-idf.yaml | 1 + .../m5stack_8angle/test.esp8266-ard.yaml | 1 + .../m5stack_8angle/test.rp2040-ard.yaml | 1 + 20 files changed, 474 insertions(+) create mode 100644 esphome/components/m5stack_8angle/__init__.py create mode 100644 esphome/components/m5stack_8angle/binary_sensor/__init__.py create mode 100644 esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp create mode 100644 esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h create mode 100644 esphome/components/m5stack_8angle/light/__init__.py create mode 100644 esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp create mode 100644 esphome/components/m5stack_8angle/light/m5stack_8angle_light.h create mode 100644 esphome/components/m5stack_8angle/m5stack_8angle.cpp create mode 100644 esphome/components/m5stack_8angle/m5stack_8angle.h create mode 100644 esphome/components/m5stack_8angle/sensor/__init__.py create mode 100644 esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp create mode 100644 esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h create mode 100644 tests/components/m5stack_8angle/common.yaml create mode 100644 tests/components/m5stack_8angle/test.esp32-ard.yaml create mode 100644 tests/components/m5stack_8angle/test.esp32-c3-ard.yaml create mode 100644 tests/components/m5stack_8angle/test.esp32-c3-idf.yaml create mode 100644 tests/components/m5stack_8angle/test.esp32-idf.yaml create mode 100644 tests/components/m5stack_8angle/test.esp8266-ard.yaml create mode 100644 tests/components/m5stack_8angle/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 210c567f78..ee76a072fc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -216,6 +216,7 @@ esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core esphome/components/ltr390/* @latonita @sjtrny esphome/components/ltr_als_ps/* @latonita +esphome/components/m5stack_8angle/* @rnauber esphome/components/matrix_keypad/* @ssieb esphome/components/max31865/* @DAVe3283 esphome/components/max44009/* @berfenger diff --git a/esphome/components/m5stack_8angle/__init__.py b/esphome/components/m5stack_8angle/__init__.py new file mode 100644 index 0000000000..1aaa86a6fd --- /dev/null +++ b/esphome/components/m5stack_8angle/__init__.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from esphome.const import CONF_ID + + +DEPENDENCIES = ["i2c"] +CODEOWNERS = ["@rnauber"] +MULTI_CONF = True + +CONF_M5STACK_8ANGLE_ID = "m5stack_8angle_id" + +m5stack_8angle_ns = cg.esphome_ns.namespace("m5stack_8angle") +M5Stack8AngleComponent = m5stack_8angle_ns.class_( + "M5Stack8AngleComponent", + i2c.I2CDevice, + cg.Component, +) + +AnalogBits = m5stack_8angle_ns.enum("AnalogBits") + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(M5Stack8AngleComponent), + } +).extend(i2c.i2c_device_schema(0x43)) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/m5stack_8angle/binary_sensor/__init__.py b/esphome/components/m5stack_8angle/binary_sensor/__init__.py new file mode 100644 index 0000000000..a8b2690083 --- /dev/null +++ b/esphome/components/m5stack_8angle/binary_sensor/__init__.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor + +from .. import M5Stack8AngleComponent, m5stack_8angle_ns, CONF_M5STACK_8ANGLE_ID + + +M5Stack8AngleSwitchBinarySensor = m5stack_8angle_ns.class_( + "M5Stack8AngleSwitchBinarySensor", + binary_sensor.BinarySensor, + cg.PollingComponent, +) + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_M5STACK_8ANGLE_ID): cv.use_id(M5Stack8AngleComponent), + } + ) + .extend(binary_sensor.binary_sensor_schema(M5Stack8AngleSwitchBinarySensor)) + .extend(cv.polling_component_schema("10s")) +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_M5STACK_8ANGLE_ID]) + sens = await binary_sensor.new_binary_sensor(config) + cg.add(sens.set_parent(hub)) + await cg.register_component(sens, config) diff --git a/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp b/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp new file mode 100644 index 0000000000..2f68d9f254 --- /dev/null +++ b/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp @@ -0,0 +1,17 @@ +#include "m5stack_8angle_binary_sensor.h" + +namespace esphome { +namespace m5stack_8angle { + +void M5Stack8AngleSwitchBinarySensor::update() { + int8_t out = this->parent_->read_switch(); + if (out == -1) { + this->status_set_warning("Could not read binary sensor state from M5Stack 8Angle."); + return; + } + this->publish_state(out != 0); + this->status_clear_warning(); +} + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h b/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h new file mode 100644 index 0000000000..b8bb601525 --- /dev/null +++ b/esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/core/component.h" + +#include "../m5stack_8angle.h" + +namespace esphome { +namespace m5stack_8angle { + +class M5Stack8AngleSwitchBinarySensor : public binary_sensor::BinarySensor, + public PollingComponent, + public Parented { + public: + void update() override; +}; + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/light/__init__.py b/esphome/components/m5stack_8angle/light/__init__.py new file mode 100644 index 0000000000..07384ecd61 --- /dev/null +++ b/esphome/components/m5stack_8angle/light/__init__.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import light + +from esphome.const import CONF_OUTPUT_ID + +from .. import M5Stack8AngleComponent, m5stack_8angle_ns, CONF_M5STACK_8ANGLE_ID + + +M5Stack8AngleLightsComponent = m5stack_8angle_ns.class_( + "M5Stack8AngleLightOutput", + light.AddressableLight, +) + + +CONFIG_SCHEMA = cv.All( + light.ADDRESSABLE_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_M5STACK_8ANGLE_ID): cv.use_id(M5Stack8AngleComponent), + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(M5Stack8AngleLightsComponent), + } + ) +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_M5STACK_8ANGLE_ID]) + lights = cg.new_Pvariable(config[CONF_OUTPUT_ID]) + await light.register_light(lights, config) + await cg.register_component(lights, config) + cg.add(lights.set_parent(hub)) diff --git a/esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp b/esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp new file mode 100644 index 0000000000..95fd8cb98f --- /dev/null +++ b/esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp @@ -0,0 +1,45 @@ +#include "m5stack_8angle_light.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace m5stack_8angle { + +static const char *const TAG = "m5stack_8angle.light"; + +void M5Stack8AngleLightOutput::setup() { + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->buf_ = allocator.allocate(M5STACK_8ANGLE_NUM_LEDS * M5STACK_8ANGLE_BYTES_PER_LED); + if (this->buf_ == nullptr) { + ESP_LOGE(TAG, "Failed to allocate buffer of size %u", M5STACK_8ANGLE_NUM_LEDS * M5STACK_8ANGLE_BYTES_PER_LED); + this->mark_failed(); + return; + }; + memset(this->buf_, 0xFF, M5STACK_8ANGLE_NUM_LEDS * M5STACK_8ANGLE_BYTES_PER_LED); + + this->effect_data_ = allocator.allocate(M5STACK_8ANGLE_NUM_LEDS); + if (this->effect_data_ == nullptr) { + ESP_LOGE(TAG, "Failed to allocate effect data of size %u", M5STACK_8ANGLE_NUM_LEDS); + this->mark_failed(); + return; + }; + memset(this->effect_data_, 0x00, M5STACK_8ANGLE_NUM_LEDS); +} + +void M5Stack8AngleLightOutput::write_state(light::LightState *state) { + for (int i = 0; i < M5STACK_8ANGLE_NUM_LEDS; + i++) { // write one LED at a time, otherwise the message will be truncated + this->parent_->write_register(M5STACK_8ANGLE_REGISTER_RGB_24B + i * M5STACK_8ANGLE_BYTES_PER_LED, + this->buf_ + i * M5STACK_8ANGLE_BYTES_PER_LED, M5STACK_8ANGLE_BYTES_PER_LED); + } +} + +light::ESPColorView M5Stack8AngleLightOutput::get_view_internal(int32_t index) const { + size_t pos = index * M5STACK_8ANGLE_BYTES_PER_LED; + // red, green, blue, white, effect_data, color_correction + return {this->buf_ + pos, this->buf_ + pos + 1, this->buf_ + pos + 2, + nullptr, this->effect_data_ + index, &this->correction_}; +} + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/light/m5stack_8angle_light.h b/esphome/components/m5stack_8angle/light/m5stack_8angle_light.h new file mode 100644 index 0000000000..204f2c04c7 --- /dev/null +++ b/esphome/components/m5stack_8angle/light/m5stack_8angle_light.h @@ -0,0 +1,37 @@ +#pragma once + +#include "esphome/components/light/addressable_light.h" +#include "esphome/components/light/light_output.h" + +#include "../m5stack_8angle.h" + +namespace esphome { +namespace m5stack_8angle { + +static const uint8_t M5STACK_8ANGLE_NUM_LEDS = 9; +static const uint8_t M5STACK_8ANGLE_BYTES_PER_LED = 4; + +class M5Stack8AngleLightOutput : public light::AddressableLight, public Parented { + public: + void setup() override; + + void write_state(light::LightState *state) override; + + int32_t size() const override { return M5STACK_8ANGLE_NUM_LEDS; } + light::LightTraits get_traits() override { + auto traits = light::LightTraits(); + traits.set_supported_color_modes({light::ColorMode::RGB}); + return traits; + }; + + void clear_effect_data() override { memset(this->effect_data_, 0x00, M5STACK_8ANGLE_NUM_LEDS); }; + + protected: + light::ESPColorView get_view_internal(int32_t index) const override; + + uint8_t *buf_{nullptr}; + uint8_t *effect_data_{nullptr}; +}; + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/m5stack_8angle.cpp b/esphome/components/m5stack_8angle/m5stack_8angle.cpp new file mode 100644 index 0000000000..6a584eddbc --- /dev/null +++ b/esphome/components/m5stack_8angle/m5stack_8angle.cpp @@ -0,0 +1,74 @@ +#include "m5stack_8angle.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace m5stack_8angle { + +static const char *const TAG = "m5stack_8angle"; + +void M5Stack8AngleComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up M5STACK_8ANGLE..."); + i2c::ErrorCode err; + + err = this->read(nullptr, 0); + if (err != i2c::NO_ERROR) { + ESP_LOGE(TAG, "I2C error %02X...", err); + this->mark_failed(); + return; + }; + + err = this->read_register(M5STACK_8ANGLE_REGISTER_FW_VERSION, &this->fw_version_, 1); + if (err != i2c::NO_ERROR) { + ESP_LOGE(TAG, "I2C error %02X...", err); + this->mark_failed(); + return; + }; +} + +void M5Stack8AngleComponent::dump_config() { + ESP_LOGCONFIG(TAG, "M5STACK_8ANGLE:"); + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Firmware version: %d ", this->fw_version_); +} + +float M5Stack8AngleComponent::read_knob_pos(uint8_t channel, AnalogBits bits) { + int32_t raw_pos = this->read_knob_pos_raw(channel, bits); + if (raw_pos == -1) { + return NAN; + } + return (float) raw_pos / ((1 << bits) - 1); +} + +int32_t M5Stack8AngleComponent::read_knob_pos_raw(uint8_t channel, AnalogBits bits) { + uint16_t knob_pos = 0; + i2c::ErrorCode err; + if (bits == BITS_8) { + err = this->read_register(M5STACK_8ANGLE_REGISTER_ANALOG_INPUT_8B + channel, (uint8_t *) &knob_pos, 1); + } else if (bits == BITS_12) { + err = this->read_register(M5STACK_8ANGLE_REGISTER_ANALOG_INPUT_12B + (channel * 2), (uint8_t *) &knob_pos, 2); + } else { + ESP_LOGE(TAG, "Invalid number of bits: %d", bits); + return -1; + } + if (err == i2c::NO_ERROR) { + return knob_pos; + } else { + return -1; + } +} + +int8_t M5Stack8AngleComponent::read_switch() { + uint8_t out; + i2c::ErrorCode err = this->read_register(M5STACK_8ANGLE_REGISTER_DIGITAL_INPUT, (uint8_t *) &out, 1); + if (err == i2c::NO_ERROR) { + return out ? 1 : 0; + } else { + return -1; + } +} + +float M5Stack8AngleComponent::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/m5stack_8angle.h b/esphome/components/m5stack_8angle/m5stack_8angle.h new file mode 100644 index 0000000000..831b1422fd --- /dev/null +++ b/esphome/components/m5stack_8angle/m5stack_8angle.h @@ -0,0 +1,34 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace m5stack_8angle { + +static const uint8_t M5STACK_8ANGLE_REGISTER_ANALOG_INPUT_12B = 0x00; +static const uint8_t M5STACK_8ANGLE_REGISTER_ANALOG_INPUT_8B = 0x10; +static const uint8_t M5STACK_8ANGLE_REGISTER_DIGITAL_INPUT = 0x20; +static const uint8_t M5STACK_8ANGLE_REGISTER_RGB_24B = 0x30; +static const uint8_t M5STACK_8ANGLE_REGISTER_FW_VERSION = 0xFE; + +enum AnalogBits : uint8_t { + BITS_8 = 8, + BITS_12 = 12, +}; + +class M5Stack8AngleComponent : public i2c::I2CDevice, public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + float read_knob_pos(uint8_t channel, AnalogBits bits = AnalogBits::BITS_8); + int32_t read_knob_pos_raw(uint8_t channel, AnalogBits bits = AnalogBits::BITS_8); + int8_t read_switch(); + + protected: + uint8_t fw_version_; +}; + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/sensor/__init__.py b/esphome/components/m5stack_8angle/sensor/__init__.py new file mode 100644 index 0000000000..70744a59e6 --- /dev/null +++ b/esphome/components/m5stack_8angle/sensor/__init__.py @@ -0,0 +1,66 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor + +from esphome.const import ( + CONF_BIT_DEPTH, + CONF_CHANNEL, + CONF_RAW, + ICON_ROTATE_RIGHT, + STATE_CLASS_MEASUREMENT, +) + +from .. import ( + AnalogBits, + M5Stack8AngleComponent, + m5stack_8angle_ns, + CONF_M5STACK_8ANGLE_ID, +) + + +M5Stack8AngleKnobSensor = m5stack_8angle_ns.class_( + "M5Stack8AngleKnobSensor", + sensor.Sensor, + cg.PollingComponent, +) + + +BIT_DEPTHS = { + 8: AnalogBits.BITS_8, + 12: AnalogBits.BITS_12, +} + +_validate_bits = cv.float_with_unit("bits", "bit") + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(M5Stack8AngleKnobSensor), + cv.GenerateID(CONF_M5STACK_8ANGLE_ID): cv.use_id(M5Stack8AngleComponent), + cv.Required(CONF_CHANNEL): cv.int_range(min=1, max=8), + cv.Optional(CONF_BIT_DEPTH, default="8bit"): cv.All( + _validate_bits, cv.enum(BIT_DEPTHS) + ), + cv.Optional(CONF_RAW, default=False): cv.boolean, + } + ) + .extend( + sensor.sensor_schema( + M5Stack8AngleKnobSensor, + accuracy_decimals=2, + icon=ICON_ROTATE_RIGHT, + state_class=STATE_CLASS_MEASUREMENT, + ) + ) + .extend(cv.polling_component_schema("10s")) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_M5STACK_8ANGLE_ID]) + cg.add(var.set_channel(config[CONF_CHANNEL] - 1)) + cg.add(var.set_bit_depth(BIT_DEPTHS[config[CONF_BIT_DEPTH]])) + cg.add(var.set_raw(config[CONF_RAW])) diff --git a/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp b/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp new file mode 100644 index 0000000000..5e034f1dd3 --- /dev/null +++ b/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp @@ -0,0 +1,24 @@ +#include "m5stack_8angle_sensor.h" + +namespace esphome { +namespace m5stack_8angle { + +void M5Stack8AngleKnobSensor::update() { + if (this->parent_ != nullptr) { + int32_t raw_pos = this->parent_->read_knob_pos_raw(this->channel_, this->bits_); + if (raw_pos == -1) { + this->status_set_warning("Could not read knob position from M5Stack 8Angle."); + return; + } + if (this->raw_) { + this->publish_state(raw_pos); + } else { + float knob_pos = (float) raw_pos / ((1 << this->bits_) - 1); + this->publish_state(knob_pos); + } + this->status_clear_warning(); + }; +} + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h b/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h new file mode 100644 index 0000000000..4848f8f80f --- /dev/null +++ b/esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h @@ -0,0 +1,27 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + +#include "../m5stack_8angle.h" + +namespace esphome { +namespace m5stack_8angle { + +class M5Stack8AngleKnobSensor : public sensor::Sensor, + public PollingComponent, + public Parented { + public: + void update() override; + void set_channel(uint8_t channel) { this->channel_ = channel; }; + void set_bit_depth(AnalogBits bits) { this->bits_ = bits; }; + void set_raw(bool raw) { this->raw_ = raw; }; + + protected: + uint8_t channel_; + AnalogBits bits_; + bool raw_; +}; + +} // namespace m5stack_8angle +} // namespace esphome diff --git a/tests/components/m5stack_8angle/common.yaml b/tests/components/m5stack_8angle/common.yaml new file mode 100644 index 0000000000..d7f988ed3a --- /dev/null +++ b/tests/components/m5stack_8angle/common.yaml @@ -0,0 +1,30 @@ +i2c: + sda: 0 + scl: 1 + id: bus_external + +m5stack_8angle: + i2c_id: bus_external + id: m5stack_8angle_base + +light: + - platform: m5stack_8angle + m5stack_8angle_id: m5stack_8angle_base + id: m8_angle_leds + name: Lights + effects: + - addressable_scan: + +sensor: + - platform: m5stack_8angle + m5stack_8angle_id: m5stack_8angle_base + channel: 1 + name: Knob 1 + - platform: m5stack_8angle + m5stack_8angle_id: m5stack_8angle_base + channel: 2 + name: Knob 2 +binary_sensor: + - platform: m5stack_8angle + m5stack_8angle_id: m5stack_8angle_base + name: Switch diff --git a/tests/components/m5stack_8angle/test.esp32-ard.yaml b/tests/components/m5stack_8angle/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/m5stack_8angle/test.esp32-c3-ard.yaml b/tests/components/m5stack_8angle/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/m5stack_8angle/test.esp32-c3-idf.yaml b/tests/components/m5stack_8angle/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/m5stack_8angle/test.esp32-idf.yaml b/tests/components/m5stack_8angle/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/m5stack_8angle/test.esp8266-ard.yaml b/tests/components/m5stack_8angle/test.esp8266-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/m5stack_8angle/test.rp2040-ard.yaml b/tests/components/m5stack_8angle/test.rp2040-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/m5stack_8angle/test.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 1f4829598a62424170fdd3fcc58dcc4bd2224162 Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Mon, 22 Jul 2024 01:29:09 +0200 Subject: [PATCH 2096/2607] [http_request] allow basic auth for idf (#7086) --- esphome/components/http_request/http_request_idf.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index d6fac7a133..68e0639b99 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -52,6 +52,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin config.timeout_ms = this->timeout_; config.disable_auto_redirect = !this->follow_redirects_; config.max_redirection_count = this->redirect_limit_; + config.auth_type = HTTP_AUTH_TYPE_BASIC; #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE if (secure) { config.crt_bundle_attach = esp_crt_bundle_attach; From f322ec8f3d1f70543578f0ec179d0049681c48c8 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 22 Jul 2024 01:33:26 +0200 Subject: [PATCH 2097/2607] use cache to build tests for compoenents (#7059) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45fe336d77..a8e93248bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -468,6 +468,8 @@ jobs: - name: Compile config run: | . venv/bin/activate + mkdir build_cache + export PLATFORMIO_BUILD_CACHE_DIR=$PWD/build_cache for component in ${{ matrix.components }}; do ./script/test_build_components -e compile -c $component done From a464e46d4d5630f6fe18d5bcffe7026739fd8254 Mon Sep 17 00:00:00 2001 From: irgendwienet Date: Mon, 22 Jul 2024 01:42:09 +0200 Subject: [PATCH 2098/2607] Fixes sml parser to process extended length lists with a number of items that is dividable by 16 (#6148) --- esphome/components/sml/sml_parser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index 3b23522b21..c782c0fc5e 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -27,7 +27,7 @@ bool SmlFile::setup_node(SmlNode *node) { uint8_t parse_length = length; if (has_extended_length) { length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f); - parse_length = length - 1; + parse_length = length; this->pos_ += 1; } @@ -37,7 +37,9 @@ bool SmlFile::setup_node(SmlNode *node) { node->type = type & 0x07; node->nodes.clear(); node->value_bytes.clear(); - if (this->buffer_[this->pos_] == 0x00) { // end of message + + // if the list is a has_extended_length list with e.g. 16 elements this is a 0x00 byte but not the end of message + if (!has_extended_length && this->buffer_[this->pos_] == 0x00) { // end of message this->pos_ += 1; } else if (is_list) { // list this->pos_ += 1; From d187340fc4d5781de91c2db3958e7a2fb295d795 Mon Sep 17 00:00:00 2001 From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:04:11 -0700 Subject: [PATCH 2099/2607] Prevent rename from deleting new config (#7104) --- esphome/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 5ff1a28ec7..b13f96daf7 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -695,7 +695,8 @@ def command_rename(args, config): os.remove(new_path) return 1 - os.remove(CORE.config_path) + if CORE.config_path != new_path: + os.remove(CORE.config_path) print(color(Fore.BOLD_GREEN, "SUCCESS")) print() From 74aee1d453f39b84d5783e9b051fe788e5fadb12 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Fri, 19 Jul 2024 15:15:11 -0400 Subject: [PATCH 2100/2607] revert bit shift to match previous behavior (#7109) --- .../components/i2s_audio/microphone/i2s_audio_microphone.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 009fecdf90..cb49a744fc 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -174,7 +174,8 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t samples_read = bytes_read / sizeof(int32_t); samples.resize(samples_read); for (size_t i = 0; i < samples_read; i++) { - samples[i] = reinterpret_cast(buf)[i] >> 16; + int32_t temp = reinterpret_cast(buf)[i] >> 14; + samples[i] = clamp(temp, INT16_MIN, INT16_MAX); } memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); return samples_read * sizeof(int16_t); From 626ed815fb289b7532eb64d210bbff142f6c7666 Mon Sep 17 00:00:00 2001 From: Lucio Tarantino Date: Sun, 21 Jul 2024 23:16:51 +0200 Subject: [PATCH 2101/2607] [heatpumpir] Fix BK72XX Compile error with IRremoteESP8266 (#6955) --- esphome/components/heatpumpir/climate.py | 3 +++ tests/components/heatpumpir/test.bk72xx-ard.yaml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index 80900d7db9..9d31668deb 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_PROTOCOL, CONF_VISUAL, ) +from esphome.core import CORE CODEOWNERS = ["@rob-deutsch"] @@ -127,3 +128,5 @@ def to_code(config): cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE])) cg.add_library("tonia/HeatpumpIR", "1.0.27") + if CORE.is_libretiny: + CORE.add_platformio_option("lib_ignore", "IRremoteESP8266") diff --git a/tests/components/heatpumpir/test.bk72xx-ard.yaml b/tests/components/heatpumpir/test.bk72xx-ard.yaml index 90259f1244..b616f9157c 100644 --- a/tests/components/heatpumpir/test.bk72xx-ard.yaml +++ b/tests/components/heatpumpir/test.bk72xx-ard.yaml @@ -3,6 +3,13 @@ remote_transmitter: carrier_duty_percent: 50% climate: + - platform: heatpumpir + protocol: mitsubishi_heavy_zm + horizontal_default: left + vertical_default: up + name: HeatpumpIR Climate + min_temperature: 18 + max_temperature: 30 - platform: heatpumpir protocol: daikin horizontal_default: mleft From 5bec0a6534028a834df91aad8e6d9c95cc825c5f Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Mon, 22 Jul 2024 01:29:09 +0200 Subject: [PATCH 2102/2607] [http_request] allow basic auth for idf (#7086) --- esphome/components/http_request/http_request_idf.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index d6fac7a133..68e0639b99 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -52,6 +52,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin config.timeout_ms = this->timeout_; config.disable_auto_redirect = !this->follow_redirects_; config.max_redirection_count = this->redirect_limit_; + config.auth_type = HTTP_AUTH_TYPE_BASIC; #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE if (secure) { config.crt_bundle_attach = esp_crt_bundle_attach; From 4690e227b858a7d2a34cd53aa55645fc03b93878 Mon Sep 17 00:00:00 2001 From: irgendwienet Date: Mon, 22 Jul 2024 01:42:09 +0200 Subject: [PATCH 2103/2607] Fixes sml parser to process extended length lists with a number of items that is dividable by 16 (#6148) --- esphome/components/sml/sml_parser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index 3b23522b21..c782c0fc5e 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -27,7 +27,7 @@ bool SmlFile::setup_node(SmlNode *node) { uint8_t parse_length = length; if (has_extended_length) { length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f); - parse_length = length - 1; + parse_length = length; this->pos_ += 1; } @@ -37,7 +37,9 @@ bool SmlFile::setup_node(SmlNode *node) { node->type = type & 0x07; node->nodes.clear(); node->value_bytes.clear(); - if (this->buffer_[this->pos_] == 0x00) { // end of message + + // if the list is a has_extended_length list with e.g. 16 elements this is a 0x00 byte but not the end of message + if (!has_extended_length && this->buffer_[this->pos_] == 0x00) { // end of message this->pos_ += 1; } else if (is_list) { // list this->pos_ += 1; From 41813b0a1ffeada67d4c5abbdaf9e4ac6095be75 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:35:06 +1200 Subject: [PATCH 2104/2607] Bump version to 2024.7.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d581f68470..ff5f7b699d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.0" +__version__ = "2024.7.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 0a7d8836339ffc59c37d3363414a827ff4cf42ec Mon Sep 17 00:00:00 2001 From: leejoow Date: Mon, 22 Jul 2024 03:33:11 +0200 Subject: [PATCH 2105/2607] [modbus_controller] Add on_command_sent trigger (#7078) Co-authored-by: Leo Schelvis --- .../components/modbus_controller/__init__.py | 28 +++++++++++++++++-- .../components/modbus_controller/automation.h | 19 +++++++++++++ esphome/components/modbus_controller/const.py | 1 + .../modbus_controller/modbus_controller.cpp | 8 ++++++ .../modbus_controller/modbus_controller.h | 3 ++ 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 esphome/components/modbus_controller/automation.h diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index b8ab48fcc6..1d0f406783 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -1,8 +1,16 @@ import binascii import esphome.codegen as cg import esphome.config_validation as cv +from esphome import automation from esphome.components import modbus -from esphome.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_LAMBDA, CONF_OFFSET +from esphome.const import ( + CONF_ADDRESS, + CONF_ID, + CONF_NAME, + CONF_LAMBDA, + CONF_OFFSET, + CONF_TRIGGER_ID, +) from esphome.cpp_helpers import logging from .const import ( CONF_BITMASK, @@ -12,6 +20,7 @@ from .const import ( CONF_CUSTOM_COMMAND, CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, + CONF_ON_COMMAND_SENT, CONF_REGISTER_COUNT, CONF_REGISTER_TYPE, CONF_RESPONSE_SIZE, @@ -97,6 +106,10 @@ TYPE_REGISTER_MAP = { "FP32_R": 2, } +ModbusCommandSentTrigger = modbus_controller_ns.class_( + "ModbusCommandSentTrigger", automation.Trigger.template(cg.int_, cg.int_) +) + _LOGGER = logging.getLogger(__name__) ModbusServerRegisterSchema = cv.Schema( @@ -120,13 +133,19 @@ CONFIG_SCHEMA = cv.All( cv.Optional( CONF_SERVER_REGISTERS, ): cv.ensure_list(ModbusServerRegisterSchema), + cv.Optional(CONF_ON_COMMAND_SENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + ModbusCommandSentTrigger + ), + } + ), } ) .extend(cv.polling_component_schema("60s")) .extend(modbus.modbus_device_schema(0x01)) ) - ModbusItemBaseSchema = cv.Schema( { cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController), @@ -254,6 +273,11 @@ async def to_code(config): ) ) await register_modbus_device(var, config) + for conf in config.get(CONF_ON_COMMAND_SENT, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation( + trigger, [(int, "function_code"), (int, "address")], conf + ) async def register_modbus_device(var, config): diff --git a/esphome/components/modbus_controller/automation.h b/esphome/components/modbus_controller/automation.h new file mode 100644 index 0000000000..ad8de4b05d --- /dev/null +++ b/esphome/components/modbus_controller/automation.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/modbus_controller/modbus_controller.h" + +namespace esphome { +namespace modbus_controller { + +class ModbusCommandSentTrigger : public Trigger { + public: + ModbusCommandSentTrigger(ModbusController *a_modbuscontroller) { + a_modbuscontroller->add_on_command_sent_callback( + [this](int function_code, int address) { this->trigger(function_code, address); }); + } +}; + +} // namespace modbus_controller +} // namespace esphome diff --git a/esphome/components/modbus_controller/const.py b/esphome/components/modbus_controller/const.py index 1a23640e17..1f5c39895c 100644 --- a/esphome/components/modbus_controller/const.py +++ b/esphome/components/modbus_controller/const.py @@ -6,6 +6,7 @@ CONF_CUSTOM_COMMAND = "custom_command" CONF_FORCE_NEW_RANGE = "force_new_range" CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id" CONF_MODBUS_FUNCTIONCODE = "modbus_functioncode" +CONF_ON_COMMAND_SENT = "on_command_sent" CONF_RAW_ENCODE = "raw_encode" CONF_REGISTER_COUNT = "register_count" CONF_REGISTER_TYPE = "register_type" diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 29d3137603..378e5c06c0 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -43,7 +43,11 @@ bool ModbusController::send_next_command_() { ESP_LOGV(TAG, "Sending next modbus command to device %d register 0x%02X count %d", this->address_, command->register_address, command->register_count); command->send(); + this->last_command_timestamp_ = millis(); + + this->command_sent_callback_.call((int) command->function_code, command->register_address); + // remove from queue if no handler is defined if (!command->on_data_func) { command_queue_.pop_front(); @@ -659,5 +663,9 @@ int64_t payload_to_number(const std::vector &data, SensorValueType sens return value; } +void ModbusController::add_on_command_sent_callback(std::function &&callback) { + this->command_sent_callback_.add(std::move(callback)); +} + } // namespace modbus_controller } // namespace esphome diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 9b7d59c93f..3bc11da879 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -456,6 +456,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { size_t get_command_queue_length() { return command_queue_.size(); } /// get if the module is offline, didn't respond the last command bool get_module_offline() { return module_offline_; } + /// Set callback for commands + void add_on_command_sent_callback(std::function &&callback); protected: /// parse sensormap_ and create range of sequential addresses @@ -488,6 +490,7 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { bool module_offline_; /// how many updates to skip if module is offline uint16_t offline_skip_updates_; + CallbackManager command_sent_callback_{}; }; /** Convert vector response payload to float. From 8fc42694f69743561ee5d4474d768aeb2be9d35b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:42:25 +1000 Subject: [PATCH 2106/2607] [ili9xxx] Rework delay handling (#7115) --- esphome/components/ili9xxx/ili9xxx_defines.h | 4 ++- .../components/ili9xxx/ili9xxx_display.cpp | 31 ++++++------------- esphome/components/ili9xxx/ili9xxx_display.h | 12 +++---- esphome/components/ili9xxx/ili9xxx_init.h | 8 ++--- 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/esphome/components/ili9xxx/ili9xxx_defines.h b/esphome/components/ili9xxx/ili9xxx_defines.h index 744013db3d..f4c5aad957 100644 --- a/esphome/components/ili9xxx/ili9xxx_defines.h +++ b/esphome/components/ili9xxx/ili9xxx_defines.h @@ -92,7 +92,9 @@ static const uint8_t ILI9XXX_GMCTRN1 = 0xE1; static const uint8_t ILI9XXX_CSCON = 0xF0; static const uint8_t ILI9XXX_ADJCTL3 = 0xF7; -static const uint8_t ILI9XXX_DELAY = 0xFF; // followed by one byte of delay time in ms +static const uint8_t ILI9XXX_DELAY_FLAG = 0xFF; +// special marker for delay - command byte reprents ms, length byte is an impossible value +#define ILI9XXX_DELAY(ms) ((uint8_t) ((ms) | 0x80)), ILI9XXX_DELAY_FLAG } // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index de03df5d41..4f035edbb0 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -34,8 +34,8 @@ void ILI9XXXDisplay::setup() { ESP_LOGD(TAG, "Setting up ILI9xxx"); this->setup_pins_(); - this->init_lcd(this->init_sequence_); - this->init_lcd(this->extra_init_sequence_.data()); + this->init_lcd_(this->init_sequence_); + this->init_lcd_(this->extra_init_sequence_.data()); switch (this->pixel_mode_) { case PIXEL_MODE_16: if (this->is_18bitdisplay_) { @@ -405,42 +405,29 @@ void ILI9XXXDisplay::reset_() { } } -void ILI9XXXDisplay::init_lcd(const uint8_t *addr) { +void ILI9XXXDisplay::init_lcd_(const uint8_t *addr) { if (addr == nullptr) return; uint8_t cmd, x, num_args; while ((cmd = *addr++) != 0) { x = *addr++; - if (cmd == ILI9XXX_DELAY) { - ESP_LOGD(TAG, "Delay %dms", x); - delay(x); + if (x == ILI9XXX_DELAY_FLAG) { + cmd &= 0x7F; + ESP_LOGV(TAG, "Delay %dms", cmd); + delay(cmd); } else { num_args = x & 0x7F; - ESP_LOGD(TAG, "Command %02X, length %d, bits %02X", cmd, num_args, *addr); + ESP_LOGV(TAG, "Command %02X, length %d, bits %02X", cmd, num_args, *addr); this->send_command(cmd, addr, num_args); addr += num_args; if (x & 0x80) { - ESP_LOGD(TAG, "Delay 150ms"); + ESP_LOGV(TAG, "Delay 150ms"); delay(150); // NOLINT } } } } -void ILI9XXXGC9A01A::init_lcd(const uint8_t *addr) { - if (addr == nullptr) - return; - uint8_t cmd, x, num_args; - while ((cmd = *addr++) != 0) { - x = *addr++; - num_args = x & 0x7F; - this->send_command(cmd, addr, num_args); - addr += num_args; - if (x & 0x80) - delay(150); // NOLINT - } -} - // Tell the display controller where we want to draw pixels. void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { x1 += this->offset_x_; diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index b60047a8c3..6121488d15 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -33,7 +33,9 @@ class ILI9XXXDisplay : public display::DisplayBuffer, uint8_t cmd, num_args, bits; const uint8_t *addr = init_sequence; while ((cmd = *addr++) != 0) { - num_args = *addr++ & 0x7F; + num_args = *addr++; + if (num_args == ILI9XXX_DELAY_FLAG) + continue; bits = *addr; switch (cmd) { case ILI9XXX_MADCTL: { @@ -50,13 +52,10 @@ class ILI9XXXDisplay : public display::DisplayBuffer, break; } - case ILI9XXX_DELAY: - continue; // no args to skip - default: break; } - addr += num_args; + addr += (num_args & 0x7F); } } @@ -109,7 +108,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, virtual void set_madctl(); void display_(); - virtual void init_lcd(const uint8_t *addr); + void init_lcd_(const uint8_t *addr); void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2); void reset_(); @@ -269,7 +268,6 @@ class ILI9XXXS3BoxLite : public ILI9XXXDisplay { class ILI9XXXGC9A01A : public ILI9XXXDisplay { public: ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {} - void init_lcd(const uint8_t *addr) override; }; //----------- ILI9XXX_24_TFT display -------------- diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 260bde4c80..5a67812bc1 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -372,9 +372,9 @@ static const uint8_t PROGMEM INITCMD_GC9A01A[] = { static const uint8_t PROGMEM INITCMD_ST7735[] = { ILI9XXX_SWRESET, 0, // Soft reset, then delay 10ms - ILI9XXX_DELAY, 10, + ILI9XXX_DELAY(10), ILI9XXX_SLPOUT , 0, // Exit Sleep, delay - ILI9XXX_DELAY, 10, + ILI9XXX_DELAY(10), ILI9XXX_PIXFMT , 1, 0x05, ILI9XXX_FRMCTR1, 3, // 4: Frame rate control, 3 args + delay: 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) @@ -415,9 +415,9 @@ static const uint8_t PROGMEM INITCMD_ST7735[] = { 0x00, 0x00, 0x02, 0x10, ILI9XXX_MADCTL , 1, 0x00, // Memory Access Control, BGR ILI9XXX_NORON , 0, - ILI9XXX_DELAY, 10, + ILI9XXX_DELAY(10), ILI9XXX_DISPON , 0, // Display on - ILI9XXX_DELAY, 10, + ILI9XXX_DELAY(10), 00, // endo of list }; From 5d5f3276e9ec73f8463554137ee67f02aa4d91e5 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Benecke Date: Mon, 22 Jul 2024 06:20:09 +0200 Subject: [PATCH 2107/2607] Inherit `esp32_ble_beacon` from `esp32_ble` (#6908) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32_ble/__init__.py | 19 ++- esphome/components/esp32_ble/ble.cpp | 10 +- esphome/components/esp32_ble/ble.h | 9 + .../components/esp32_ble/ble_advertising.cpp | 51 +++++- .../components/esp32_ble/ble_advertising.h | 22 ++- .../components/esp32_ble_beacon/__init__.py | 18 +- .../esp32_ble_beacon/esp32_ble_beacon.cpp | 160 +++++------------- .../esp32_ble_beacon/esp32_ble_beacon.h | 36 ++-- .../components/esp32_ble_server/__init__.py | 1 - esphome/components/esp32_improv/__init__.py | 1 - 10 files changed, 176 insertions(+), 151 deletions(-) diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index d88161e3e0..472669a381 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -7,10 +7,10 @@ from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant DEPENDENCIES = ["esp32"] CODEOWNERS = ["@jesserockz", "@Rapsssito"] -CONFLICTS_WITH = ["esp32_ble_beacon"] CONF_BLE_ID = "ble_id" CONF_IO_CAPABILITY = "io_capability" +CONF_ADVERTISING_CYCLE_TIME = "advertising_cycle_time" NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] @@ -34,6 +34,19 @@ IO_CAPABILITY = { "display_yes_no": IoCapability.IO_CAP_IO, } +esp_power_level_t = cg.global_ns.enum("esp_power_level_t") + +TX_POWER_LEVELS = { + -12: esp_power_level_t.ESP_PWR_LVL_N12, + -9: esp_power_level_t.ESP_PWR_LVL_N9, + -6: esp_power_level_t.ESP_PWR_LVL_N6, + -3: esp_power_level_t.ESP_PWR_LVL_N3, + 0: esp_power_level_t.ESP_PWR_LVL_N0, + 3: esp_power_level_t.ESP_PWR_LVL_P3, + 6: esp_power_level_t.ESP_PWR_LVL_P6, + 9: esp_power_level_t.ESP_PWR_LVL_P9, +} + CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32BLE), @@ -41,6 +54,9 @@ CONFIG_SCHEMA = cv.Schema( IO_CAPABILITY, lower=True ), cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, + cv.Optional( + CONF_ADVERTISING_CYCLE_TIME, default="10s" + ): cv.positive_time_period_milliseconds, } ).extend(cv.COMPONENT_SCHEMA) @@ -58,6 +74,7 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY])) + cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME])) await cg.register_component(var, config) if CORE.using_esp_idf: diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index ceb6516a02..5d08b6e973 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -78,6 +78,11 @@ void ESP32BLE::advertising_set_manufacturer_data(const std::vector &dat this->advertising_start(); } +void ESP32BLE::advertising_register_raw_advertisement_callback(std::function &&callback) { + this->advertising_init_(); + this->advertising_->register_raw_advertisement_callback(std::move(callback)); +} + void ESP32BLE::advertising_add_service_uuid(ESPBTUUID uuid) { this->advertising_init_(); this->advertising_->add_service_uuid(uuid); @@ -102,7 +107,7 @@ bool ESP32BLE::ble_pre_setup_() { void ESP32BLE::advertising_init_() { if (this->advertising_ != nullptr) return; - this->advertising_ = new BLEAdvertising(); // NOLINT(cppcoreguidelines-owning-memory) + this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_); // NOLINT(cppcoreguidelines-owning-memory) this->advertising_->set_scan_response(true); this->advertising_->set_min_preferred_interval(0x06); @@ -312,6 +317,9 @@ void ESP32BLE::loop() { delete ble_event; // NOLINT(cppcoreguidelines-owning-memory) ble_event = this->ble_events_.pop(); } + if (this->advertising_ != nullptr) { + this->advertising_->loop(); + } } void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 023960d6e4..7c55583852 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -3,6 +3,8 @@ #include "ble_advertising.h" #include "ble_uuid.h" +#include + #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/defines.h" @@ -76,6 +78,11 @@ class ESP32BLE : public Component { public: void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; } + void set_advertising_cycle_time(uint32_t advertising_cycle_time) { + this->advertising_cycle_time_ = advertising_cycle_time; + } + uint32_t get_advertising_cycle_time() const { return this->advertising_cycle_time_; } + void enable(); void disable(); bool is_active(); @@ -89,6 +96,7 @@ class ESP32BLE : public Component { void advertising_set_manufacturer_data(const std::vector &data); void advertising_add_service_uuid(ESPBTUUID uuid); void advertising_remove_service_uuid(ESPBTUUID uuid); + void advertising_register_raw_advertisement_callback(std::function &&callback); void register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); } void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); } @@ -121,6 +129,7 @@ class ESP32BLE : public Component { Queue ble_events_; BLEAdvertising *advertising_; esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; + uint32_t advertising_cycle_time_; bool enable_on_boot_; }; diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 59d2398829..1d340c76d9 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -10,9 +10,9 @@ namespace esphome { namespace esp32_ble { -static const char *const TAG = "esp32_ble"; +static const char *const TAG = "esp32_ble.advertising"; -BLEAdvertising::BLEAdvertising() { +BLEAdvertising::BLEAdvertising(uint32_t advertising_cycle_time) : advertising_cycle_time_(advertising_cycle_time) { this->advertising_data_.set_scan_rsp = false; this->advertising_data_.include_name = true; this->advertising_data_.include_txpower = true; @@ -64,7 +64,7 @@ void BLEAdvertising::set_manufacturer_data(const std::vector &data) { } } -void BLEAdvertising::start() { +esp_err_t BLEAdvertising::services_advertisement_() { int num_services = this->advertising_uuids_.size(); if (num_services == 0) { this->advertising_data_.service_uuid_len = 0; @@ -87,8 +87,8 @@ void BLEAdvertising::start() { this->advertising_data_.include_txpower = !this->scan_response_; err = esp_ble_gap_config_adv_data(&this->advertising_data_); if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %d", err); - return; + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %s", esp_err_to_name(err)); + return err; } if (this->scan_response_) { @@ -101,8 +101,8 @@ void BLEAdvertising::start() { this->scan_response_data_.flag = 0; err = esp_ble_gap_config_adv_data(&this->scan_response_data_); if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err); - return; + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %s", esp_err_to_name(err)); + return err; } } @@ -113,8 +113,18 @@ void BLEAdvertising::start() { err = esp_ble_gap_start_advertising(&this->advertising_params_); if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err); - return; + ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err)); + return err; + } + + return ESP_OK; +} + +void BLEAdvertising::start() { + if (this->current_adv_index_ == -1) { + this->services_advertisement_(); + } else { + this->raw_advertisements_callbacks_[this->current_adv_index_](true); } } @@ -124,6 +134,29 @@ void BLEAdvertising::stop() { ESP_LOGE(TAG, "esp_ble_gap_stop_advertising failed: %d", err); return; } + if (this->current_adv_index_ != -1) { + this->raw_advertisements_callbacks_[this->current_adv_index_](false); + } +} + +void BLEAdvertising::loop() { + if (this->raw_advertisements_callbacks_.empty()) { + return; + } + const uint32_t now = millis(); + if (now - this->last_advertisement_time_ > this->advertising_cycle_time_) { + this->stop(); + this->current_adv_index_ += 1; + if (this->current_adv_index_ >= this->raw_advertisements_callbacks_.size()) { + this->current_adv_index_ = -1; + } + this->start(); + this->last_advertisement_time_ = now; + } +} + +void BLEAdvertising::register_raw_advertisement_callback(std::function &&callback) { + this->raw_advertisements_callbacks_.push_back(std::move(callback)); } } // namespace esp32_ble diff --git a/esphome/components/esp32_ble/ble_advertising.h b/esphome/components/esp32_ble/ble_advertising.h index 16a7dd1d8e..946e414c1d 100644 --- a/esphome/components/esp32_ble/ble_advertising.h +++ b/esphome/components/esp32_ble/ble_advertising.h @@ -1,20 +1,31 @@ #pragma once +#include +#include #include #ifdef USE_ESP32 +#include #include #include namespace esphome { namespace esp32_ble { +using raw_adv_data_t = struct { + uint8_t *data; + size_t length; + esp_power_level_t power_level; +}; + class ESPBTUUID; class BLEAdvertising { public: - BLEAdvertising(); + BLEAdvertising(uint32_t advertising_cycle_time); + + void loop(); void add_service_uuid(ESPBTUUID uuid); void remove_service_uuid(ESPBTUUID uuid); @@ -22,16 +33,25 @@ class BLEAdvertising { void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } void set_manufacturer_data(const std::vector &data); void set_service_data(const std::vector &data); + void register_raw_advertisement_callback(std::function &&callback); void start(); void stop(); protected: + esp_err_t services_advertisement_(); + bool scan_response_; esp_ble_adv_data_t advertising_data_; esp_ble_adv_data_t scan_response_data_; esp_ble_adv_params_t advertising_params_; std::vector advertising_uuids_; + + std::vector> raw_advertisements_callbacks_; + + const uint32_t advertising_cycle_time_; + uint32_t last_advertisement_time_{0}; + int8_t current_adv_index_{-1}; // -1 means standard scan response }; } // namespace esp32_ble diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index 9aac48cbb2..d063209478 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -1,16 +1,21 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.components.esp32_ble import CONF_BLE_ID from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER from esphome.core import CORE, TimePeriod from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components import esp32_ble +AUTO_LOAD = ["esp32_ble"] DEPENDENCIES = ["esp32"] -CONFLICTS_WITH = ["esp32_ble_tracker"] esp32_ble_beacon_ns = cg.esphome_ns.namespace("esp32_ble_beacon") -ESP32BLEBeacon = esp32_ble_beacon_ns.class_("ESP32BLEBeacon", cg.Component) - +ESP32BLEBeacon = esp32_ble_beacon_ns.class_( + "ESP32BLEBeacon", + cg.Component, + esp32_ble.GAPEventHandler, + cg.Parented.template(esp32_ble.ESP32BLE), +) CONF_MAJOR = "major" CONF_MINOR = "minor" CONF_MIN_INTERVAL = "min_interval" @@ -28,6 +33,7 @@ CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32BLEBeacon), + cv.GenerateID(CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE), cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True), cv.Required(CONF_UUID): cv.uuid, cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t, @@ -48,7 +54,7 @@ CONFIG_SCHEMA = cv.All( min=-128, max=0 ), cv.Optional(CONF_TX_POWER, default="3dBm"): cv.All( - cv.decibel, cv.one_of(-12, -9, -6, -3, 0, 3, 6, 9, int=True) + cv.decibel, cv.enum(esp32_ble.TX_POWER_LEVELS, int=True) ), } ).extend(cv.COMPONENT_SCHEMA), @@ -62,6 +68,10 @@ async def to_code(config): uuid = config[CONF_UUID].hex uuid_arr = [cg.RawExpression(f"0x{uuid[i:i + 2]}") for i in range(0, len(uuid), 2)] var = cg.new_Pvariable(config[CONF_ID], uuid_arr) + + parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) + cg.add(parent.register_gap_event_handler(var)) + await cg.register_component(var, config) cg.add(var.set_major(config[CONF_MAJOR])) cg.add(var.set_minor(config[CONF_MINOR])) diff --git a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp index 589fcc1e82..423fe61592 100644 --- a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +++ b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp @@ -3,14 +3,16 @@ #ifdef USE_ESP32 -#include -#include -#include #include -#include +#include #include +#include +#include +#include #include + #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #ifdef USE_ARDUINO #include @@ -21,20 +23,6 @@ namespace esp32_ble_beacon { static const char *const TAG = "esp32_ble_beacon"; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static esp_ble_adv_params_t ble_adv_params = { - .adv_int_min = 0x20, - .adv_int_max = 0x40, - .adv_type = ADV_TYPE_NONCONN_IND, - .own_addr_type = BLE_ADDR_TYPE_PUBLIC, - .peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, - .channel_map = ADV_CHNL_ALL, - .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, -}; - -#define ENDIAN_CHANGE_U16(x) ((((x) &0xFF00) >> 8) + (((x) &0xFF) << 8)) - static const esp_ble_ibeacon_head_t IBEACON_COMMON_HEAD = { .flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = {0x4C, 0x00}, .beacon_type = {0x02, 0x15}}; @@ -53,117 +41,62 @@ void ESP32BLEBeacon::dump_config() { " UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d" ", TX Power: %ddBm", uuid, this->major_, this->minor_, this->min_interval_, this->max_interval_, this->measured_power_, - this->tx_power_); + (this->tx_power_ * 3) - 12); } +float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; } + void ESP32BLEBeacon::setup() { - ESP_LOGCONFIG(TAG, "Setting up ESP32 BLE beacon..."); - global_esp32_ble_beacon = this; + this->ble_adv_params_ = { + .adv_int_min = static_cast(this->min_interval_ / 0.625f), + .adv_int_max = static_cast(this->max_interval_ / 0.625f), + .adv_type = ADV_TYPE_NONCONN_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + }; - xTaskCreatePinnedToCore(ESP32BLEBeacon::ble_core_task, - "ble_task", // name - 10000, // stack size (in words) - nullptr, // input params - 1, // priority - nullptr, // Handle, not needed - 0 // core - ); + global_ble->advertising_register_raw_advertisement_callback([this](bool advertise) { + this->advertising_ = advertise; + if (advertise) { + this->on_advertise_(); + } + }); } -float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::BLUETOOTH; } -void ESP32BLEBeacon::ble_core_task(void *params) { - ble_setup(); - - while (true) { - delay(1000); // NOLINT - } -} - -void ESP32BLEBeacon::ble_setup() { - ble_adv_params.adv_int_min = static_cast(global_esp32_ble_beacon->min_interval_ / 0.625f); - ble_adv_params.adv_int_max = static_cast(global_esp32_ble_beacon->max_interval_ / 0.625f); - - // Initialize non-volatile storage for the bluetooth controller - esp_err_t err = nvs_flash_init(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); - return; - } - -#ifdef USE_ARDUINO - if (!btStart()) { - ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); - return; - } -#else - if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { - // start bt controller - if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) { - esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - err = esp_bt_controller_init(&cfg); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err)); - return; - } - while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) - ; - } - if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) { - err = esp_bt_controller_enable(ESP_BT_MODE_BLE); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err)); - return; - } - } - if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { - ESP_LOGE(TAG, "esp bt controller enable failed"); - return; - } - } -#endif - - esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); - - err = esp_bluedroid_init(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err); - return; - } - err = esp_bluedroid_enable(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err); - return; - } - err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, - static_cast((global_esp32_ble_beacon->tx_power_ + 12) / 3)); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err)); - return; - } - err = esp_ble_gap_register_callback(ESP32BLEBeacon::gap_event_handler); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err); - return; - } - +void ESP32BLEBeacon::on_advertise_() { esp_ble_ibeacon_t ibeacon_adv_data; memcpy(&ibeacon_adv_data.ibeacon_head, &IBEACON_COMMON_HEAD, sizeof(esp_ble_ibeacon_head_t)); - memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, global_esp32_ble_beacon->uuid_.data(), + memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, this->uuid_.data(), sizeof(ibeacon_adv_data.ibeacon_vendor.proximity_uuid)); - ibeacon_adv_data.ibeacon_vendor.minor = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->minor_); - ibeacon_adv_data.ibeacon_vendor.major = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->major_); - ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast(global_esp32_ble_beacon->measured_power_); + ibeacon_adv_data.ibeacon_vendor.minor = byteswap(this->minor_); + ibeacon_adv_data.ibeacon_vendor.major = byteswap(this->major_); + ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast(this->measured_power_); - esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data)); + ESP_LOGD(TAG, "Setting BLE TX power"); + esp_err_t err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, this->tx_power_); + if (err != ESP_OK) { + ESP_LOGW(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err)); + } + err = esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw failed: %s", esp_err_to_name(err)); + return; + } } void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + if (!this->advertising_) + return; + esp_err_t err; switch (event) { case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: { - err = esp_ble_gap_start_advertising(&ble_adv_params); + err = esp_ble_gap_start_advertising(&this->ble_adv_params_); if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err); + ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err)); } break; } @@ -181,6 +114,7 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap } else { ESP_LOGD(TAG, "BLE stopped advertising successfully"); } + // this->advertising_ = false; break; } default: @@ -188,8 +122,6 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap } } -ESP32BLEBeacon *global_esp32_ble_beacon = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - } // namespace esp32_ble_beacon } // namespace esphome diff --git a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h index 5208b67ea3..e37edf6cde 100644 --- a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h +++ b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h @@ -1,39 +1,39 @@ #pragma once +#include "esphome/components/esp32_ble/ble.h" #include "esphome/core/component.h" #ifdef USE_ESP32 -#include #include +#include namespace esphome { namespace esp32_ble_beacon { -// NOLINTNEXTLINE(modernize-use-using) -typedef struct { +using esp_ble_ibeacon_head_t = struct { uint8_t flags[3]; uint8_t length; uint8_t type; uint8_t company_id[2]; uint8_t beacon_type[2]; -} __attribute__((packed)) esp_ble_ibeacon_head_t; +} __attribute__((packed)); -// NOLINTNEXTLINE(modernize-use-using) -typedef struct { +using esp_ble_ibeacon_vendor_t = struct { uint8_t proximity_uuid[16]; uint16_t major; uint16_t minor; uint8_t measured_power; -} __attribute__((packed)) esp_ble_ibeacon_vendor_t; +} __attribute__((packed)); -// NOLINTNEXTLINE(modernize-use-using) -typedef struct { +using esp_ble_ibeacon_t = struct { esp_ble_ibeacon_head_t ibeacon_head; esp_ble_ibeacon_vendor_t ibeacon_vendor; -} __attribute__((packed)) esp_ble_ibeacon_t; +} __attribute__((packed)); -class ESP32BLEBeacon : public Component { +using namespace esp32_ble; + +class ESP32BLEBeacon : public Component, public GAPEventHandler, public Parented { public: explicit ESP32BLEBeacon(const std::array &uuid) : uuid_(uuid) {} @@ -46,12 +46,11 @@ class ESP32BLEBeacon : public Component { void set_min_interval(uint16_t val) { this->min_interval_ = val; } void set_max_interval(uint16_t val) { this->max_interval_ = val; } void set_measured_power(int8_t val) { this->measured_power_ = val; } - void set_tx_power(int8_t val) { this->tx_power_ = val; } + void set_tx_power(esp_power_level_t val) { this->tx_power_ = val; } + void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; protected: - static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); - static void ble_core_task(void *params); - static void ble_setup(); + void on_advertise_(); std::array uuid_; uint16_t major_{}; @@ -59,12 +58,11 @@ class ESP32BLEBeacon : public Component { uint16_t min_interval_{}; uint16_t max_interval_{}; int8_t measured_power_{}; - int8_t tx_power_{}; + esp_power_level_t tx_power_{}; + esp_ble_adv_params_t ble_adv_params_; + bool advertising_{false}; }; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -extern ESP32BLEBeacon *global_esp32_ble_beacon; - } // namespace esp32_ble_beacon } // namespace esphome diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index f53c9450f4..ce9fdc2cf3 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -7,7 +7,6 @@ from esphome.components.esp32 import add_idf_sdkconfig_option AUTO_LOAD = ["esp32_ble"] CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] -CONFLICTS_WITH = ["esp32_ble_beacon"] DEPENDENCIES = ["esp32"] CONF_MANUFACTURER = "manufacturer" diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index 49d95d89e5..62d9cd376c 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -6,7 +6,6 @@ from esphome.const import CONF_ID AUTO_LOAD = ["esp32_ble_server"] CODEOWNERS = ["@jesserockz"] -CONFLICTS_WITH = ["esp32_ble_beacon"] DEPENDENCIES = ["wifi", "esp32"] CONF_AUTHORIZED_DURATION = "authorized_duration" From f1aa254e4810999d7bb70619ba9c09bb9be5cf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aodren=20Auffr=C3=A9dou-Heinicke?= <54121510+aodrenah@users.noreply.github.com> Date: Sun, 21 Jul 2024 22:29:54 -0700 Subject: [PATCH 2108/2607] APDS9306 Ambient Light Sensor (#6709) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski Co-authored-by: Mat931 <49403702+Mat931@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/apds9306/__init__.py | 4 + esphome/components/apds9306/apds9306.cpp | 151 ++++++++++++++++++ esphome/components/apds9306/apds9306.h | 66 ++++++++ esphome/components/apds9306/sensor.py | 95 +++++++++++ tests/components/apds9306/common.yaml | 12 ++ tests/components/apds9306/test.esp32-ard.yaml | 5 + .../apds9306/test.esp32-c3-ard.yaml | 5 + .../apds9306/test.esp32-c3-idf.yaml | 5 + tests/components/apds9306/test.esp32-idf.yaml | 5 + .../components/apds9306/test.esp8266-ard.yaml | 5 + .../components/apds9306/test.rp2040-ard.yaml | 5 + 12 files changed, 359 insertions(+) create mode 100644 esphome/components/apds9306/__init__.py create mode 100644 esphome/components/apds9306/apds9306.cpp create mode 100644 esphome/components/apds9306/apds9306.h create mode 100644 esphome/components/apds9306/sensor.py create mode 100644 tests/components/apds9306/common.yaml create mode 100644 tests/components/apds9306/test.esp32-ard.yaml create mode 100644 tests/components/apds9306/test.esp32-c3-ard.yaml create mode 100644 tests/components/apds9306/test.esp32-c3-idf.yaml create mode 100644 tests/components/apds9306/test.esp32-idf.yaml create mode 100644 tests/components/apds9306/test.esp8266-ard.yaml create mode 100644 tests/components/apds9306/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index ee76a072fc..c5e144bdfa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -37,6 +37,7 @@ esphome/components/am43/sensor/* @buxtronix esphome/components/analog_threshold/* @ianchi esphome/components/animation/* @syndlex esphome/components/anova/* @buxtronix +esphome/components/apds9306/* @aodrenah esphome/components/api/* @OttoWinter esphome/components/as5600/* @ammmze esphome/components/as5600/sensor/* @ammmze diff --git a/esphome/components/apds9306/__init__.py b/esphome/components/apds9306/__init__.py new file mode 100644 index 0000000000..3dc8fcf5ff --- /dev/null +++ b/esphome/components/apds9306/__init__.py @@ -0,0 +1,4 @@ +# Based on this datasheet: +# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf + +CODEOWNERS = ["@aodrenah"] diff --git a/esphome/components/apds9306/apds9306.cpp b/esphome/components/apds9306/apds9306.cpp new file mode 100644 index 0000000000..7b79b0964c --- /dev/null +++ b/esphome/components/apds9306/apds9306.cpp @@ -0,0 +1,151 @@ +// Based on this datasheet: +// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf + +#include "apds9306.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace apds9306 { + +static const char *const TAG = "apds9306"; + +enum { // APDS9306 registers + APDS9306_MAIN_CTRL = 0x00, + APDS9306_ALS_MEAS_RATE = 0x04, + APDS9306_ALS_GAIN = 0x05, + APDS9306_PART_ID = 0x06, + APDS9306_MAIN_STATUS = 0x07, + APDS9306_CLEAR_DATA_0 = 0x0A, // LSB + APDS9306_CLEAR_DATA_1 = 0x0B, + APDS9306_CLEAR_DATA_2 = 0x0C, // MSB + APDS9306_ALS_DATA_0 = 0x0D, // LSB + APDS9306_ALS_DATA_1 = 0x0E, + APDS9306_ALS_DATA_2 = 0x0F, // MSB + APDS9306_INT_CFG = 0x19, + APDS9306_INT_PERSISTENCE = 0x1A, + APDS9306_ALS_THRES_UP_0 = 0x21, // LSB + APDS9306_ALS_THRES_UP_1 = 0x22, + APDS9306_ALS_THRES_UP_2 = 0x23, // MSB + APDS9306_ALS_THRES_LOW_0 = 0x24, // LSB + APDS9306_ALS_THRES_LOW_1 = 0x25, + APDS9306_ALS_THRES_LOW_2 = 0x26, // MSB + APDS9306_ALS_THRES_VAR = 0x27 +}; + +#define APDS9306_ERROR_CHECK(func, error) \ + if (!(func)) { \ + ESP_LOGE(TAG, error); \ + this->mark_failed(); \ + return; \ + } +#define APDS9306_WARNING_CHECK(func, warning) \ + if (!(func)) { \ + ESP_LOGW(TAG, warning); \ + this->status_set_warning(); \ + return; \ + } +#define APDS9306_WRITE_BYTE(reg, value) \ + ESP_LOGV(TAG, "Writing 0x%02x to 0x%02x", value, reg); \ + if (!this->write_byte(reg, value)) { \ + ESP_LOGE(TAG, "Failed writing 0x%02x to 0x%02x", value, reg); \ + this->mark_failed(); \ + return; \ + } + +void APDS9306::setup() { + ESP_LOGCONFIG(TAG, "Setting up APDS9306..."); + + uint8_t id; + if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + if (id != 0xB1 && id != 0xB3) { // 0xB1 for APDS9306 0xB3 for APDS9306-065 + this->error_code_ = WRONG_ID; + this->mark_failed(); + return; + } + + // ALS resolution and measurement, see datasheet or init.py for options + uint8_t als_meas_rate = ((this->bit_width_ & 0x07) << 4) | (this->measurement_rate_ & 0x07); + APDS9306_WRITE_BYTE(APDS9306_ALS_MEAS_RATE, als_meas_rate); + + // ALS gain, see datasheet or init.py for options + uint8_t als_gain = (this->gain_ & 0x07); + APDS9306_WRITE_BYTE(APDS9306_ALS_GAIN, als_gain); + + // Set to standby mode + APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00); + + // Check for data, clear main status + uint8_t status; + APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed."); + + // Set to active mode + APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02); + + ESP_LOGCONFIG(TAG, "APDS9306 setup complete"); +} + +void APDS9306::dump_config() { + LOG_SENSOR("", "APDS9306", this); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + switch (this->error_code_) { + case COMMUNICATION_FAILED: + ESP_LOGE(TAG, "Communication with APDS9306 failed!"); + break; + case WRONG_ID: + ESP_LOGE(TAG, "APDS9306 has invalid id!"); + break; + default: + ESP_LOGE(TAG, "Setting up APDS9306 registers failed!"); + break; + } + } + + ESP_LOGCONFIG(TAG, " Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]); + ESP_LOGCONFIG(TAG, " Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]); + ESP_LOGCONFIG(TAG, " Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]); + + LOG_UPDATE_INTERVAL(this); +} + +void APDS9306::update() { + // Check for new data + uint8_t status; + APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed."); + + this->status_clear_warning(); + + if (!(status &= 0b00001000)) { // No new data + return; + } + + // Set to standby mode + APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00); + + // Clear MAIN STATUS + APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed."); + + uint8_t als_data[3]; + APDS9306_WARNING_CHECK(this->read_bytes(APDS9306_ALS_DATA_0, als_data, 3), "Reading ALS data has failed."); + + // Set to active mode + APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02); + + uint32_t light_level = 0x00 | encode_uint24(als_data[2], als_data[1], als_data[0]); + + float lux = ((float) light_level / AMBIENT_LIGHT_GAIN_VALUES[this->gain_]) * + (100.0f / MEASUREMENT_RATE_VALUES[this->measurement_rate_]); + + ESP_LOGD(TAG, "Got illuminance=%.1flx from", lux); + this->publish_state(lux); +} + +} // namespace apds9306 +} // namespace esphome diff --git a/esphome/components/apds9306/apds9306.h b/esphome/components/apds9306/apds9306.h new file mode 100644 index 0000000000..44362908c8 --- /dev/null +++ b/esphome/components/apds9306/apds9306.h @@ -0,0 +1,66 @@ +// Based on this datasheet: +// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf + +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace apds9306 { + +enum MeasurementBitWidth : uint8_t { + MEASUREMENT_BIT_WIDTH_20 = 0, + MEASUREMENT_BIT_WIDTH_19 = 1, + MEASUREMENT_BIT_WIDTH_18 = 2, + MEASUREMENT_BIT_WIDTH_17 = 3, + MEASUREMENT_BIT_WIDTH_16 = 4, + MEASUREMENT_BIT_WIDTH_13 = 5, +}; +static const uint8_t MEASUREMENT_BIT_WIDTH_VALUES[] = {20, 19, 18, 17, 16, 13}; + +enum MeasurementRate : uint8_t { + MEASUREMENT_RATE_25 = 0, + MEASUREMENT_RATE_50 = 1, + MEASUREMENT_RATE_100 = 2, + MEASUREMENT_RATE_200 = 3, + MEASUREMENT_RATE_500 = 4, + MEASUREMENT_RATE_1000 = 5, + MEASUREMENT_RATE_2000 = 6, +}; +static const uint16_t MEASUREMENT_RATE_VALUES[] = {25, 50, 100, 200, 500, 1000, 2000}; + +enum AmbientLightGain : uint8_t { + AMBIENT_LIGHT_GAIN_1 = 0, + AMBIENT_LIGHT_GAIN_3 = 1, + AMBIENT_LIGHT_GAIN_6 = 2, + AMBIENT_LIGHT_GAIN_9 = 3, + AMBIENT_LIGHT_GAIN_18 = 4, +}; +static const uint8_t AMBIENT_LIGHT_GAIN_VALUES[] = {1, 3, 6, 9, 18}; + +class APDS9306 : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + float get_setup_priority() const override { return setup_priority::BUS; } + void dump_config() override; + void update() override; + void set_bit_width(MeasurementBitWidth bit_width) { this->bit_width_ = bit_width; } + void set_measurement_rate(MeasurementRate measurement_rate) { this->measurement_rate_ = measurement_rate; } + void set_ambient_light_gain(AmbientLightGain gain) { this->gain_ = gain; } + + protected: + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + WRONG_ID, + } error_code_{NONE}; + + MeasurementBitWidth bit_width_; + MeasurementRate measurement_rate_; + AmbientLightGain gain_; +}; + +} // namespace apds9306 +} // namespace esphome diff --git a/esphome/components/apds9306/sensor.py b/esphome/components/apds9306/sensor.py new file mode 100644 index 0000000000..25b301444f --- /dev/null +++ b/esphome/components/apds9306/sensor.py @@ -0,0 +1,95 @@ +# Based on this datasheet: +# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_GAIN, + DEVICE_CLASS_ILLUMINANCE, + ICON_LIGHTBULB, + STATE_CLASS_MEASUREMENT, + UNIT_LUX, +) + +DEPENDENCIES = ["i2c"] + +CONF_APDS9306_ID = "apds9306_id" +CONF_BIT_WIDTH = "bit_width" +CONF_MEASUREMENT_RATE = "measurement_rate" + +apds9306_ns = cg.esphome_ns.namespace("apds9306") +APDS9306 = apds9306_ns.class_( + "APDS9306", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice +) + +MeasurementBitWidth = apds9306_ns.enum("MeasurementBitWidth") +MeasurementRate = apds9306_ns.enum("MeasurementRate") +AmbientLightGain = apds9306_ns.enum("AmbientLightGain") + +MEASUREMENT_BIT_WIDTHS = { + 20: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_20, + 19: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_19, + 18: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_18, + 17: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_17, + 16: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_16, + 13: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_13, +} + +MEASUREMENT_RATES = { + 25: MeasurementRate.MEASUREMENT_RATE_25, + 50: MeasurementRate.MEASUREMENT_RATE_50, + 100: MeasurementRate.MEASUREMENT_RATE_100, + 200: MeasurementRate.MEASUREMENT_RATE_200, + 500: MeasurementRate.MEASUREMENT_RATE_500, + 1000: MeasurementRate.MEASUREMENT_RATE_1000, + 2000: MeasurementRate.MEASUREMENT_RATE_2000, +} + +AMBIENT_LIGHT_GAINS = { + 1: AmbientLightGain.AMBIENT_LIGHT_GAIN_1, + 3: AmbientLightGain.AMBIENT_LIGHT_GAIN_3, + 6: AmbientLightGain.AMBIENT_LIGHT_GAIN_6, + 9: AmbientLightGain.AMBIENT_LIGHT_GAIN_9, + 18: AmbientLightGain.AMBIENT_LIGHT_GAIN_18, +} + + +def _validate_measurement_rate(value): + value = cv.positive_time_period_milliseconds(value) + return cv.enum(MEASUREMENT_RATES, int=True)(value.total_milliseconds) + + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + APDS9306, + unit_of_measurement=UNIT_LUX, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + icon=ICON_LIGHTBULB, + ) + .extend( + { + cv.Optional(CONF_GAIN, default="1"): cv.enum(AMBIENT_LIGHT_GAINS, int=True), + cv.Optional(CONF_BIT_WIDTH, default="18"): cv.enum( + MEASUREMENT_BIT_WIDTHS, int=True + ), + cv.Optional( + CONF_MEASUREMENT_RATE, default="100ms" + ): _validate_measurement_rate, + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x52)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + cg.add(var.set_bit_width(config[CONF_BIT_WIDTH])) + cg.add(var.set_measurement_rate(config[CONF_MEASUREMENT_RATE])) + cg.add(var.set_ambient_light_gain(config[CONF_GAIN])) diff --git a/tests/components/apds9306/common.yaml b/tests/components/apds9306/common.yaml new file mode 100644 index 0000000000..b3828e62ff --- /dev/null +++ b/tests/components/apds9306/common.yaml @@ -0,0 +1,12 @@ +i2c: + - id: i2c_apds9306 + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: apds9306 + name: "APDS9306 Light Level" + gain: 3 + bit_width: 16 + measurement_rate: 2000ms + update_interval: 60s diff --git a/tests/components/apds9306/test.esp32-ard.yaml b/tests/components/apds9306/test.esp32-ard.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/apds9306/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/apds9306/test.esp32-c3-ard.yaml b/tests/components/apds9306/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/apds9306/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/apds9306/test.esp32-c3-idf.yaml b/tests/components/apds9306/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/apds9306/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/apds9306/test.esp32-idf.yaml b/tests/components/apds9306/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/apds9306/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/apds9306/test.esp8266-ard.yaml b/tests/components/apds9306/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/apds9306/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/apds9306/test.rp2040-ard.yaml b/tests/components/apds9306/test.rp2040-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/apds9306/test.rp2040-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml From dc24eefe08fb44491ef7623e7db551c319c11521 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:01:45 +1200 Subject: [PATCH 2109/2607] Bump docker/build-push-action from 6.4.1 to 6.5.0 in /.github/actions/build-image (#7119) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index e2febdad1b..bd9ceb8072 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.4.1 + uses: docker/build-push-action@v6.5.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.4.1 + uses: docker/build-push-action@v6.5.0 with: context: . file: ./docker/Dockerfile From ae476bb400f14d51c0e569a3807264a7abcd01e1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:51:32 +1200 Subject: [PATCH 2110/2607] [http_request] Change default timeout to 4.5s (#7123) --- esphome/components/http_request/__init__.py | 2 +- esphome/components/http_request/http_request.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index ade7024bed..ef387553fe 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -99,7 +99,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_FOLLOW_REDIRECTS, True): cv.boolean, cv.Optional(CONF_REDIRECT_LIMIT, 3): cv.int_, cv.Optional( - CONF_TIMEOUT, default="5s" + CONF_TIMEOUT, default="4.5s" ): cv.positive_time_period_milliseconds, cv.SplitDefault(CONF_ESP8266_DISABLE_SSL_SUPPORT, esp8266=False): cv.All( cv.only_on_esp8266, cv.boolean diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 82b7392648..c01baf8644 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -80,7 +80,7 @@ class HttpRequestComponent : public Component { const char *useragent_{nullptr}; bool follow_redirects_; uint16_t redirect_limit_; - uint16_t timeout_{5000}; + uint16_t timeout_{4500}; uint32_t watchdog_timeout_{0}; }; From 2b2a83273fdad8c105acf5a7aedd1d63042891ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:20:44 +1200 Subject: [PATCH 2111/2607] Bump docker/setup-qemu-action from 3.1.0 to 3.2.0 (#7120) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 147efe089e..999a2f03d2 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -48,7 +48,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.1.0 + uses: docker/setup-qemu-action@v3.2.0 - name: Set TAG run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f66c504bda..2fdac00589 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,7 +93,7 @@ jobs: uses: docker/setup-buildx-action@v3.4.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' - uses: docker/setup-qemu-action@v3.1.0 + uses: docker/setup-qemu-action@v3.2.0 - name: Log in to docker hub uses: docker/login-action@v3.2.0 From f0d4b5f74051b596752f3df0e3332720ef79f089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:20:54 +1200 Subject: [PATCH 2112/2607] Bump docker/login-action from 3.2.0 to 3.3.0 (#7121) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fdac00589..c1488d8b89 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,12 +96,12 @@ jobs: uses: docker/setup-qemu-action@v3.2.0 - name: Log in to docker hub - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -188,13 +188,13 @@ jobs: - name: Log in to docker hub if: matrix.registry == 'dockerhub' - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry if: matrix.registry == 'ghcr' - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.actor }} From e88e32bf232080d9f7ab0cbb47e22d59557b9860 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:21:03 +1200 Subject: [PATCH 2113/2607] Bump docker/setup-buildx-action from 3.4.0 to 3.5.0 (#7122) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 999a2f03d2..2b4539105b 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.4.0 + uses: docker/setup-buildx-action@v3.5.0 - name: Set up QEMU uses: docker/setup-qemu-action@v3.2.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c1488d8b89..efec556059 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,7 +90,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.4.0 + uses: docker/setup-buildx-action@v3.5.0 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.2.0 @@ -184,7 +184,7 @@ jobs: merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.4.0 + uses: docker/setup-buildx-action@v3.5.0 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From 19a787c2352bca62c3e642ed421a4e2a0185cfaa Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 23 Jul 2024 04:53:31 +0200 Subject: [PATCH 2114/2607] [fan] fix initial FanCall to properly set speed (#7113) Speed settings were ignored for the first FanCall, if no speed has been restored before. This commit changes the behaviour to: set speed to 100%, iff current speed AND new speed are not set. --- esphome/components/fan/fan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/fan/fan.cpp b/esphome/components/fan/fan.cpp index 95e3ae0758..1d560d2fc6 100644 --- a/esphome/components/fan/fan.cpp +++ b/esphome/components/fan/fan.cpp @@ -45,8 +45,8 @@ void FanCall::validate_() { this->speed_ = clamp(*this->speed_, 1, traits.supported_speed_count()); if (this->binary_state_.has_value() && *this->binary_state_) { - // when turning on, if current speed is zero, set speed to 100% - if (traits.supports_speed() && !this->parent_.state && this->parent_.speed == 0) { + // when turning on, if neither current nor new speed available, set speed to 100% + if (traits.supports_speed() && !this->parent_.state && this->parent_.speed == 0 && !this->speed_.has_value()) { this->speed_ = traits.supported_speed_count(); } } From 2cc14055cfa4080dfb3c0612cefa96ee0a76df9b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:12:23 +1000 Subject: [PATCH 2115/2607] Added ruff to pre-commit hooks (#7124) --- .pre-commit-config.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 74acfa1c1d..aeb434167a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,15 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.5.4 + hooks: + # Run the linter. + - id: ruff + args: [--fix] + # Run the formatter. + - id: ruff-format - repo: https://github.com/psf/black-pre-commit-mirror rev: 24.4.2 hooks: From 39de179e213f79f8016a1ae764c87fe77333d5dc Mon Sep 17 00:00:00 2001 From: dentra Date: Wed, 24 Jul 2024 03:12:59 +0300 Subject: [PATCH 2116/2607] [http_request] Fix ESP-IDF follow redirect (#7101) --- esphome/components/http_request/__init__.py | 14 ++-- .../http_request/http_request_idf.cpp | 66 +++++++++++++++---- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index ef387553fe..161486fbb2 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -1,17 +1,17 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg +from esphome.components import esp32 +import esphome.config_validation as cv from esphome.const import ( - __version__, + CONF_ESP8266_DISABLE_SSL_SUPPORT, CONF_ID, - CONF_TIMEOUT, CONF_METHOD, + CONF_TIMEOUT, CONF_TRIGGER_ID, CONF_URL, - CONF_ESP8266_DISABLE_SSL_SUPPORT, + __version__, ) -from esphome.core import Lambda, CORE -from esphome.components import esp32 +from esphome.core import CORE, Lambda DEPENDENCIES = ["network"] AUTO_LOAD = ["json"] diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 68e0639b99..1f03b5f3bf 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -77,7 +77,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin esp_http_client_set_header(client, header.name, header.value); } - int body_len = body.length(); + const int body_len = body.length(); esp_err_t err = esp_http_client_open(client, body_len); if (err != ESP_OK) { @@ -109,18 +109,62 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } - container->content_length = esp_http_client_fetch_headers(client); - const auto status_code = esp_http_client_get_status_code(client); - container->status_code = status_code; + auto is_ok = [](int code) { return code >= HttpStatus_Ok && code < HttpStatus_MultipleChoices; }; - if (status_code < 200 || status_code >= 300) { - ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), status_code); - this->status_momentary_error("failed", 1000); - esp_http_client_cleanup(client); - return nullptr; + container->content_length = esp_http_client_fetch_headers(client); + container->status_code = esp_http_client_get_status_code(client); + if (is_ok(container->status_code)) { + container->duration_ms = millis() - start; + return container; } - container->duration_ms = millis() - start; - return container; + + if (this->follow_redirects_) { + auto is_redirect = [](int code) { + return code == HttpStatus_MovedPermanently || code == HttpStatus_Found || code == HttpStatus_SeeOther || + code == HttpStatus_TemporaryRedirect || code == HttpStatus_PermanentRedirect; + }; + auto num_redirects = this->redirect_limit_; + while (is_redirect(container->status_code) && num_redirects > 0) { + err = esp_http_client_set_redirection(client); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_http_client_set_redirection failed: %s", esp_err_to_name(err)); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; + } +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char url[256]{}; + if (esp_http_client_get_url(client, url, sizeof(url) - 1) == ESP_OK) { + ESP_LOGV(TAG, "redirecting to url: %s", url); + } +#endif + err = esp_http_client_open(client, 0); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_http_client_open failed: %s", esp_err_to_name(err)); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; + } + + container->content_length = esp_http_client_fetch_headers(client); + container->status_code = esp_http_client_get_status_code(client); + if (is_ok(container->status_code)) { + container->duration_ms = millis() - start; + return container; + } + + num_redirects--; + } + + if (num_redirects == 0) { + ESP_LOGW(TAG, "Reach redirect limit count=%d", this->redirect_limit_); + } + } + + ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; } int HttpContainerIDF::read(uint8_t *buf, size_t max_len) { From da10de9ea8c0129394cb98ccd3b79fcdcb78dfb0 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Wed, 24 Jul 2024 13:57:02 +1200 Subject: [PATCH 2117/2607] Update webserver local assets to 20240724-013115 (#7126) --- .../components/web_server/server_index_v3.h | 7218 +++++++++-------- 1 file changed, 3615 insertions(+), 3603 deletions(-) diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 0c16ea9f37..0f3f743a73 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -397,3609 +397,3621 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, - 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x70, 0xe7, 0x99, 0x76, 0x07, 0x69, 0xda, 0xbc, 0x61, - 0xc3, 0xcf, 0x5c, 0x5b, 0x3c, 0x6b, 0xaa, 0x1b, 0xf0, 0x78, 0x31, 0xcb, 0x30, 0x67, 0xc5, 0xd2, 0xd3, 0xf0, 0x56, - 0x8d, 0xea, 0x5c, 0x09, 0x73, 0x7a, 0x68, 0x3a, 0x6c, 0x42, 0xfc, 0x2f, 0x56, 0x94, 0x7b, 0x8c, 0x0b, 0x83, 0x31, - 0x06, 0x40, 0x9b, 0xbb, 0x24, 0x3c, 0x03, 0x4e, 0x5a, 0x2d, 0x7f, 0x3e, 0x34, 0x6d, 0x9d, 0xb4, 0x9d, 0x9c, 0xb2, - 0xd9, 0xae, 0xfd, 0x59, 0x27, 0x46, 0xed, 0xce, 0xfc, 0x76, 0xcf, 0xfc, 0xd3, 0xda, 0x6b, 0x6d, 0x13, 0x9f, 0x6d, - 0x38, 0x1d, 0x23, 0xbf, 0xb2, 0x5a, 0xce, 0xd3, 0x36, 0x9b, 0x75, 0x17, 0x0a, 0x0e, 0x1a, 0x43, 0x1b, 0xcd, 0x01, - 0xb6, 0x36, 0x33, 0x81, 0x75, 0xa4, 0x5c, 0x00, 0x5d, 0xb7, 0x67, 0x1b, 0xf4, 0xa1, 0x24, 0x18, 0x62, 0xef, 0x6c, - 0xb4, 0x3e, 0xac, 0xd6, 0x5e, 0x35, 0x30, 0xf8, 0x67, 0xfd, 0x57, 0xc5, 0x19, 0xbe, 0x60, 0x01, 0x67, 0xce, 0x1b, - 0xc9, 0xe9, 0xaa, 0xe5, 0xb8, 0xf1, 0x91, 0xae, 0x84, 0x04, 0xe3, 0xcb, 0x30, 0xa3, 0xb7, 0xd6, 0xa9, 0x61, 0xc6, - 0x05, 0x98, 0x4c, 0x21, 0xac, 0x03, 0xe3, 0xf2, 0x69, 0xd8, 0xd0, 0x48, 0xc7, 0xd0, 0xf0, 0x61, 0x27, 0x39, 0x3d, - 0x45, 0xb8, 0x85, 0x3b, 0xa7, 0xa7, 0x81, 0x34, 0x30, 0xd6, 0xbb, 0x8a, 0xee, 0x2a, 0xa9, 0x76, 0x94, 0x3c, 0x32, - 0x8d, 0x1e, 0xb5, 0x5b, 0x2d, 0x6c, 0x1c, 0xb7, 0xcb, 0xc2, 0x5c, 0xed, 0x68, 0xb6, 0xdd, 0x6a, 0x41, 0xb3, 0xf0, - 0xc7, 0xcd, 0xeb, 0x17, 0xb2, 0x6c, 0xa5, 0x2d, 0xdc, 0x4e, 0xdb, 0xb8, 0x93, 0x76, 0xf0, 0x71, 0x7a, 0x8c, 0x4f, - 0xd2, 0x13, 0x7c, 0x9a, 0x9e, 0xe2, 0xb3, 0xf4, 0x0c, 0xdf, 0x4f, 0xef, 0xe3, 0xf3, 0xf4, 0x1c, 0x3f, 0x48, 0x1f, - 0xe0, 0x87, 0x69, 0xbb, 0x85, 0x1f, 0xa5, 0xed, 0x36, 0x7e, 0x9c, 0xb6, 0x3b, 0xf8, 0x49, 0xda, 0x3e, 0xc6, 0x4f, - 0xd3, 0xf6, 0x09, 0x7e, 0x96, 0xb6, 0x4f, 0x31, 0x85, 0xdc, 0x21, 0xe4, 0x66, 0x90, 0x3b, 0x82, 0x5c, 0x06, 0xb9, - 0xe3, 0xb4, 0x7d, 0xba, 0xc6, 0xca, 0x06, 0x7b, 0x88, 0x5a, 0xed, 0xce, 0xf1, 0xc9, 0xe9, 0xd9, 0xfd, 0xf3, 0x07, - 0x0f, 0x1f, 0x3d, 0x7e, 0xf2, 0xf4, 0x59, 0x34, 0xc0, 0x43, 0xe3, 0x73, 0xa1, 0x44, 0x9f, 0x1f, 0xb4, 0x4f, 0x07, - 0xf8, 0xda, 0x7f, 0xc6, 0xfc, 0xa0, 0x73, 0xd2, 0x42, 0x97, 0x97, 0x27, 0x83, 0x46, 0x99, 0xfb, 0xde, 0xb8, 0x7a, - 0x54, 0x59, 0x84, 0x90, 0x18, 0x72, 0x10, 0xbe, 0x33, 0xf5, 0xde, 0xb3, 0x98, 0x27, 0x05, 0x3a, 0x38, 0x30, 0x3f, - 0x26, 0xfe, 0xc7, 0xd0, 0xff, 0xa0, 0xc1, 0x22, 0xdd, 0xd2, 0xd8, 0xf9, 0xfa, 0xea, 0xd2, 0xd2, 0xbe, 0x34, 0x62, - 0xd9, 0xe3, 0xce, 0x9c, 0xfc, 0xbf, 0x22, 0x6b, 0x2e, 0x42, 0x4e, 0xac, 0x4a, 0xe6, 0xb4, 0xc7, 0xc8, 0xb2, 0x48, - 0x3b, 0xa7, 0xa7, 0x07, 0xbf, 0xf4, 0x79, 0xbf, 0x3d, 0x18, 0x1c, 0xb6, 0xef, 0xe3, 0x49, 0x99, 0xd0, 0xb1, 0x09, - 0xc3, 0x32, 0xe1, 0xd8, 0x26, 0xd0, 0xd4, 0xd6, 0x86, 0xa4, 0x13, 0x93, 0x04, 0x25, 0xd6, 0xa9, 0x69, 0xfb, 0xbe, - 0x6d, 0xfb, 0x01, 0xd8, 0x31, 0x99, 0xe6, 0x5d, 0xd3, 0x17, 0x17, 0x27, 0x2b, 0xd7, 0x28, 0x9e, 0xa4, 0xae, 0x35, - 0x9f, 0x78, 0x32, 0x18, 0xe0, 0xa1, 0x49, 0x3c, 0xad, 0x12, 0xcf, 0x06, 0x03, 0xd7, 0xd5, 0x03, 0xd3, 0xd5, 0xfd, - 0x2a, 0xeb, 0x7c, 0x30, 0x30, 0x5d, 0x22, 0xe7, 0xb5, 0xae, 0xf4, 0xde, 0x97, 0x52, 0x73, 0xc0, 0x2f, 0x3a, 0xa7, - 0xa7, 0x3d, 0xc0, 0x30, 0x63, 0x8d, 0xea, 0x61, 0x74, 0x13, 0xc0, 0xe8, 0x0e, 0x7e, 0xf7, 0x86, 0x34, 0xbd, 0xa6, - 0x25, 0x90, 0x7a, 0xd1, 0x7f, 0x45, 0x0d, 0x6d, 0x60, 0x6e, 0xfe, 0x4c, 0xec, 0x9f, 0x21, 0x6a, 0x7c, 0xa1, 0x00, - 0x6e, 0xd0, 0x85, 0x78, 0x65, 0xa6, 0xe9, 0xf1, 0x33, 0x05, 0xe7, 0x92, 0xa9, 0xca, 0x69, 0x6f, 0x35, 0xbd, 0x19, - 0xae, 0xa6, 0xea, 0x0b, 0xfa, 0x33, 0xfe, 0x53, 0x1d, 0xc6, 0xfd, 0x66, 0x23, 0x61, 0x7f, 0x8e, 0xc0, 0x8b, 0xa5, - 0x97, 0x8e, 0xd8, 0x04, 0xf5, 0xfa, 0x7f, 0x2a, 0x3c, 0x68, 0x04, 0x19, 0x3f, 0x6c, 0xa7, 0x80, 0x8f, 0xcb, 0x66, - 0x62, 0xfc, 0x03, 0xea, 0xa1, 0xde, 0x9f, 0xea, 0xf0, 0x4f, 0x74, 0xef, 0xa8, 0x9a, 0xcb, 0xef, 0xd2, 0x6d, 0xe1, - 0x2a, 0xf0, 0xcd, 0x61, 0xb9, 0x85, 0x19, 0x6e, 0x37, 0x19, 0x84, 0x09, 0x03, 0x27, 0x68, 0x12, 0xcb, 0x06, 0x3f, - 0x3a, 0x6e, 0xa1, 0x1f, 0xda, 0x1d, 0x10, 0xeb, 0x9b, 0xe2, 0x70, 0x7b, 0xd3, 0x17, 0xcd, 0x63, 0xfc, 0xa0, 0x59, - 0xe0, 0x36, 0xc2, 0xcd, 0xb6, 0xd7, 0xb7, 0xf6, 0x55, 0xdc, 0x42, 0x58, 0xc5, 0xe7, 0xf0, 0xcf, 0x09, 0x1a, 0x54, - 0x1b, 0xf2, 0x8a, 0x6e, 0xf6, 0x0e, 0x1e, 0x9b, 0x24, 0x56, 0x0d, 0x7e, 0x74, 0xd6, 0x42, 0x3f, 0x9c, 0x99, 0x8e, - 0xd8, 0xa1, 0xde, 0xd1, 0x95, 0xc4, 0x27, 0x4d, 0x09, 0x1d, 0xb5, 0xca, 0x7e, 0x44, 0x7c, 0x8a, 0xb0, 0x88, 0x8f, - 0xe1, 0x9f, 0x76, 0xd8, 0xcf, 0xaf, 0x5b, 0xfd, 0x98, 0x79, 0xb7, 0x71, 0x72, 0x6a, 0x1d, 0x40, 0x95, 0xbd, 0x8d, - 0x6d, 0xb0, 0xcb, 0xb6, 0xb9, 0x46, 0x6a, 0x1f, 0xc1, 0x07, 0xc2, 0xfa, 0x90, 0x28, 0xcc, 0x0e, 0xc1, 0x73, 0x14, - 0x0c, 0x26, 0xd4, 0xc5, 0x71, 0x57, 0x35, 0x1a, 0x48, 0xf4, 0xd5, 0xe0, 0x90, 0xb4, 0x9b, 0xba, 0xc9, 0x30, 0xfc, - 0x6e, 0x90, 0x32, 0x1c, 0x99, 0xa8, 0x7a, 0x7d, 0xec, 0x7a, 0xb5, 0x77, 0xce, 0x1e, 0x3b, 0x08, 0x21, 0xaa, 0x17, - 0xeb, 0x26, 0x43, 0x47, 0xa2, 0x11, 0xeb, 0x0b, 0xd6, 0x3b, 0x4b, 0x5b, 0xc8, 0x60, 0xa7, 0xea, 0xc5, 0xac, 0xc9, - 0x21, 0xbd, 0x93, 0xc6, 0xbc, 0xa9, 0xe1, 0xd7, 0x49, 0x30, 0x0b, 0x01, 0x78, 0x57, 0xf9, 0xc1, 0x14, 0x47, 0x9d, - 0xd3, 0x53, 0x2c, 0x08, 0x4f, 0x26, 0xe6, 0x97, 0x22, 0x3c, 0x19, 0x9a, 0x5f, 0x92, 0x94, 0xf0, 0xb2, 0xbd, 0xe3, - 0x82, 0x04, 0xab, 0x6a, 0x52, 0x28, 0x2c, 0x68, 0x81, 0x8e, 0x3a, 0xfe, 0x42, 0x1a, 0x4f, 0xfd, 0x1c, 0x40, 0x00, - 0x2f, 0x8c, 0x2d, 0xa2, 0x6c, 0x16, 0x38, 0x27, 0xf4, 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, - 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, 0xb6, 0x86, 0xa7, 0x70, 0x8b, 0x98, 0x91, 0xec, 0xf0, 0xac, - 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, - 0xa5, 0x8e, 0x68, 0x33, 0x2a, 0x4c, 0x8f, 0xc7, 0x1a, 0x6e, 0xc4, 0x35, 0xf8, 0x99, 0x68, 0xf0, 0x80, 0x49, 0xb9, - 0xbb, 0x8a, 0x42, 0x26, 0x2e, 0xde, 0x38, 0xd4, 0x1a, 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x4d, 0xa3, 0x88, 0x7f, 0x97, - 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, - 0x03, 0x1d, 0x17, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, - 0xad, 0x34, 0xf9, 0x4c, 0xad, 0x95, 0x3f, 0xf7, 0xee, 0xc6, 0x66, 0xe1, 0xac, 0xb3, 0x73, 0xe9, 0xd9, 0xdc, 0x3f, - 0x05, 0x2b, 0x0a, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, - 0xa1, 0xf2, 0x32, 0xf5, 0xa3, 0x84, 0xa4, 0xce, 0x00, 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, - 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x95, 0xe1, 0x5c, 0x01, 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0xeb, - 0x6e, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0xb0, - 0xf4, 0xc0, 0x93, 0x14, 0xac, 0x3c, 0xf0, 0x30, 0x15, 0xe0, 0x89, 0x40, 0x53, 0x16, 0xd8, 0x8f, 0x3f, 0x74, 0xba, - 0x23, 0x73, 0xdf, 0x49, 0x0c, 0x96, 0x76, 0x19, 0x9c, 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, - 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, - 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0x5f, 0x21, 0x6b, 0xdb, 0x38, 0xdc, 0x4d, 0x43, 0x13, 0x82, 0x70, 0x15, - 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0xf0, 0x22, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, - 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, - 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x47, 0x34, 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, - 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, - 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0x26, 0x1c, 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x76, 0xf8, - 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, - 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, - 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, - 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, - 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, - 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, - 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, - 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, - 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, - 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, - 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, - 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, 0x26, 0x8d, 0x12, 0x7d, 0xcc, 0x86, 0xd9, 0x28, 0xc2, 0x66, - 0x30, 0x63, 0xf8, 0xfb, 0x85, 0xbf, 0x63, 0x3a, 0x8d, 0xce, 0x69, 0x67, 0xc8, 0x3a, 0x11, 0x1e, 0xbe, 0xb9, 0x11, - 0x69, 0x44, 0x4f, 0x3b, 0xb4, 0x43, 0x23, 0x3c, 0x5c, 0x14, 0xf9, 0xdd, 0x8d, 0x94, 0x23, 0x00, 0xc2, 0xf0, 0xfc, - 0xfc, 0x7e, 0x84, 0x33, 0xfa, 0xab, 0x86, 0xda, 0xa7, 0xe3, 0x07, 0x8c, 0xb6, 0x22, 0xfc, 0x0b, 0x2d, 0xf4, 0xc7, - 0x85, 0x72, 0x03, 0x6d, 0x41, 0x8a, 0xcc, 0xde, 0x81, 0x82, 0x39, 0x1a, 0x75, 0xce, 0x1e, 0xb4, 0x59, 0x84, 0xb3, - 0xab, 0xd7, 0xd0, 0xdb, 0xfd, 0xf1, 0x69, 0x0b, 0x3e, 0x04, 0x48, 0x6a, 0xac, 0x80, 0x46, 0xce, 0x4e, 0x1e, 0x9c, - 0xb2, 0x91, 0x49, 0x54, 0x3c, 0xff, 0x6c, 0x66, 0x7f, 0x0e, 0xf3, 0xc9, 0x0a, 0x3e, 0x53, 0x52, 0xa4, 0xd1, 0x28, - 0x6b, 0x9f, 0x1c, 0x43, 0xc2, 0x1d, 0x15, 0x1e, 0x38, 0xb7, 0x50, 0xf5, 0x7c, 0x18, 0xe1, 0x5b, 0x9b, 0x7a, 0x3e, - 0x34, 0x1f, 0x93, 0x77, 0xbf, 0x8a, 0x37, 0xa3, 0x34, 0x1a, 0x9e, 0x9f, 0x9f, 0xb5, 0x20, 0xe1, 0x03, 0xbd, 0x4b, - 0x23, 0xfa, 0x00, 0xfe, 0x83, 0xec, 0x8f, 0xcf, 0xa0, 0x43, 0x18, 0xe1, 0xed, 0xe4, 0x63, 0x98, 0xf3, 0x79, 0x4a, - 0x3f, 0xf3, 0x34, 0x1a, 0x8e, 0x86, 0xf7, 0xcf, 0xa0, 0xde, 0x8c, 0x4e, 0x9e, 0x69, 0x0a, 0xed, 0xb6, 0x5a, 0xa6, - 0xe5, 0x77, 0xfc, 0x0b, 0x33, 0xd5, 0x4f, 0x4f, 0xcf, 0x86, 0x1d, 0x18, 0xc1, 0x15, 0xa8, 0x18, 0x60, 0x3c, 0xe7, - 0x99, 0x69, 0xf0, 0x2a, 0x7b, 0x3a, 0x4a, 0xa3, 0x07, 0x0f, 0x8e, 0x3b, 0x59, 0x16, 0xe1, 0xdb, 0x8f, 0x23, 0x5b, - 0xdb, 0xe4, 0x29, 0x80, 0x7d, 0x1a, 0xb1, 0x07, 0x0f, 0xce, 0xee, 0x53, 0xf8, 0x7e, 0x6e, 0xda, 0x3a, 0x1f, 0x0f, - 0xb3, 0x73, 0x68, 0xeb, 0x77, 0x98, 0xce, 0xc9, 0xf9, 0xf1, 0xc8, 0xf4, 0xf5, 0xbb, 0x19, 0x75, 0x67, 0x7c, 0x32, - 0x3e, 0x31, 0x99, 0x66, 0xa8, 0xe5, 0xe7, 0x6f, 0x2c, 0x8d, 0x32, 0x36, 0x6a, 0x47, 0xf8, 0xd6, 0x2d, 0xdc, 0x83, - 0x93, 0x56, 0x6b, 0x74, 0x1c, 0xe1, 0xd1, 0xc3, 0xf9, 0xfc, 0xad, 0x81, 0x60, 0xfb, 0xe4, 0x81, 0xfd, 0x56, 0x9f, - 0xef, 0xa0, 0xe9, 0xa1, 0x01, 0xda, 0x88, 0xcf, 0x4c, 0xcb, 0x67, 0x0f, 0xe0, 0x3f, 0xf3, 0x6d, 0x9a, 0x2e, 0xbf, - 0xe5, 0x68, 0x62, 0x17, 0xa5, 0xcd, 0x1e, 0xb4, 0xa0, 0xc6, 0x98, 0x7f, 0x1c, 0x16, 0x1c, 0xd0, 0x68, 0xd8, 0x81, - 0xff, 0x8b, 0xf0, 0x38, 0xbf, 0x7a, 0xed, 0x70, 0x76, 0x3c, 0xa6, 0xe3, 0x56, 0x84, 0xc7, 0xf2, 0xa3, 0xd2, 0x1f, - 0x1e, 0x8a, 0x34, 0xea, 0x74, 0xce, 0x87, 0xa6, 0xcc, 0xe2, 0x17, 0xc5, 0x0d, 0x1e, 0xb7, 0x4c, 0x2b, 0x13, 0xfa, - 0x56, 0x0d, 0xaf, 0x24, 0xac, 0x24, 0xfc, 0x17, 0xe1, 0x09, 0xe8, 0xa5, 0x5c, 0x2b, 0xe7, 0x76, 0x3b, 0x4c, 0xde, - 0x19, 0xd4, 0x1c, 0xdd, 0x07, 0x78, 0xf9, 0x65, 0x1c, 0x51, 0x7a, 0xda, 0x69, 0x45, 0xd8, 0x8c, 0xfa, 0xbc, 0x05, - 0xff, 0x45, 0xd8, 0x42, 0xce, 0xc0, 0x75, 0xf2, 0xf1, 0xd9, 0xcb, 0x9b, 0x34, 0xa2, 0xa3, 0xf1, 0x18, 0x96, 0xc4, - 0x4c, 0xc6, 0x17, 0x9b, 0x4a, 0xc1, 0xee, 0x7e, 0xbd, 0x71, 0xdb, 0xc5, 0x24, 0x68, 0x07, 0x9d, 0xb3, 0x07, 0xc3, - 0x93, 0x08, 0xbf, 0x1d, 0x71, 0x2a, 0x60, 0x95, 0xb2, 0xd1, 0x69, 0x76, 0x9a, 0x99, 0x84, 0x89, 0x4c, 0xa3, 0x13, - 0x58, 0xf2, 0x4e, 0x84, 0xf9, 0x97, 0xab, 0x3b, 0x8b, 0x6e, 0x50, 0xdb, 0x21, 0xc8, 0xb8, 0xc5, 0xce, 0xce, 0xb3, - 0x08, 0xe7, 0xf4, 0xcb, 0xb3, 0x5f, 0x8b, 0x34, 0x62, 0x67, 0xec, 0x6c, 0x4c, 0xfd, 0xf7, 0x1f, 0x6a, 0x6a, 0x6a, - 0xb4, 0xc6, 0xa7, 0x90, 0x74, 0x23, 0xcc, 0x58, 0xef, 0x67, 0x63, 0x83, 0x21, 0xaf, 0x66, 0x52, 0x64, 0x4f, 0xc7, - 0x63, 0x69, 0xb1, 0x98, 0xc2, 0x26, 0xfc, 0x04, 0xd0, 0xa6, 0xa3, 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x27, 0xbb, 0x4b, - 0xdc, 0x04, 0x3e, 0x59, 0xcc, 0x66, 0x6e, 0xb7, 0x7f, 0xb2, 0x40, 0x81, 0xf9, 0x8e, 0xe9, 0x98, 0x8e, 0x3a, 0x11, - 0xfe, 0x64, 0xe0, 0x32, 0x3a, 0x86, 0xff, 0xa0, 0x00, 0x74, 0xf6, 0xa0, 0xc5, 0xd8, 0x83, 0x96, 0xf9, 0x0a, 0xf3, - 0xdc, 0xcc, 0x87, 0x67, 0x59, 0x3b, 0xc2, 0x9f, 0x1c, 0x3a, 0x8e, 0xc7, 0xb4, 0x05, 0xe8, 0xf8, 0xc9, 0xa1, 0x63, - 0xa7, 0x35, 0xec, 0x50, 0xf3, 0x6d, 0xb1, 0xe6, 0xfc, 0x7e, 0xc6, 0x60, 0x72, 0x9f, 0x2c, 0x42, 0xde, 0xbf, 0x7f, - 0x7e, 0xfe, 0xe0, 0x01, 0x7c, 0x9a, 0xb6, 0xcb, 0x4f, 0xa5, 0x1f, 0xe6, 0x06, 0xc9, 0x5a, 0xd9, 0x09, 0xd0, 0xc9, - 0x4f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, - 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, - 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, - 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, - 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, - 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, - 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, - 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, - 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, - 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, - 0x87, 0x23, 0xfc, 0x6e, 0x04, 0xd7, 0x60, 0x69, 0x34, 0x1e, 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, - 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, - 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, - 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, - 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, - 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, - 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, - 0x21, 0xdc, 0xf3, 0x2d, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, 0x08, 0x6e, 0xfd, 0xe4, 0xcd, 0xaf, 0x85, 0x45, 0x23, - 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, - 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, - 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, - 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, - 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, - 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, - 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, - 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, - 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, - 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, - 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, - 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, - 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, - 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0x3d, 0xe8, 0x13, 0x1a, 0x7b, 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xe1, 0x45, 0x3f, - 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x5c, 0x00, 0x9c, 0x41, 0xbd, 0xf3, 0x99, 0x04, 0x41, 0x52, - 0x90, 0x56, 0x57, 0x5c, 0x78, 0x3f, 0xce, 0xae, 0x80, 0xa0, 0x03, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0xc4, 0x66, 0xb1, - 0xc2, 0xa4, 0x37, 0x6f, 0x37, 0x32, 0xa5, 0xb4, 0x06, 0xf3, 0x94, 0x50, 0x1f, 0x95, 0x1d, 0x2e, 0x69, 0x21, 0x6e, - 0x11, 0xea, 0x4a, 0x62, 0x62, 0x2c, 0xbf, 0x10, 0x3a, 0x56, 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0x5e, - 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0x11, - 0xa3, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, - 0x47, 0x2c, 0x31, 0xb7, 0x06, 0xd6, 0x37, 0x85, 0xf4, 0x41, 0x73, 0xd6, 0xc2, 0x10, 0xc7, 0xdc, 0x73, 0xde, 0x8f, - 0x58, 0x9f, 0xd7, 0xfd, 0x9a, 0xab, 0xe0, 0xc1, 0x07, 0x07, 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, - 0x56, 0x4c, 0xd0, 0x55, 0xf8, 0xf6, 0x93, 0x1e, 0x48, 0x29, 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, - 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, - 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, 0x49, 0x23, 0x9a, 0xed, 0xdb, 0x48, 0x18, 0xba, 0x7f, - 0xdf, 0x08, 0x66, 0x55, 0x78, 0xb6, 0x06, 0x24, 0x75, 0x41, 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, - 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x45, 0xb4, 0x61, 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, - 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, - 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, - 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, - 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, - 0x46, 0x49, 0xf4, 0x97, 0x57, 0xa2, 0x3e, 0xe2, 0x26, 0xfe, 0xcc, 0x05, 0x49, 0x5a, 0xad, 0xe3, 0xf6, 0x71, 0xeb, - 0xbc, 0xc7, 0x0f, 0xdb, 0x9d, 0xe4, 0x41, 0x27, 0x35, 0x8a, 0x88, 0xb9, 0xbc, 0x01, 0x05, 0xcc, 0x51, 0x27, 0x39, - 0x41, 0x87, 0xed, 0xa4, 0x75, 0x7a, 0xda, 0x84, 0x7f, 0xf0, 0x7b, 0x5d, 0x56, 0x3b, 0x69, 0x9d, 0x9c, 0xf6, 0xf8, - 0xd1, 0x46, 0xa5, 0x98, 0x37, 0xa0, 0x20, 0x3a, 0x32, 0x95, 0x30, 0xd4, 0xaf, 0x96, 0xf7, 0xd9, 0x96, 0x9e, 0xe7, - 0xbd, 0x8e, 0x95, 0x55, 0xc5, 0x01, 0x54, 0xfd, 0xd7, 0xc4, 0x00, 0xd1, 0x7f, 0x0d, 0xcb, 0x18, 0xb1, 0xcb, 0x02, - 0x44, 0xed, 0x47, 0x3c, 0x16, 0x0d, 0x76, 0x18, 0xdb, 0x7c, 0x0d, 0x75, 0x9b, 0x10, 0xb7, 0x0d, 0x4f, 0x5c, 0xae, - 0x0a, 0x73, 0x27, 0x08, 0x35, 0x15, 0xe4, 0x0e, 0x5d, 0xae, 0x0c, 0x73, 0x87, 0x08, 0x35, 0x25, 0xe4, 0xd2, 0x94, - 0x27, 0x14, 0x72, 0x74, 0x42, 0x9b, 0x06, 0x92, 0xd5, 0xa2, 0x3c, 0x67, 0x7e, 0xd8, 0x7c, 0x0c, 0xcb, 0x63, 0x08, - 0x8a, 0x13, 0xa4, 0x05, 0xbc, 0xed, 0x51, 0x6a, 0x73, 0x5a, 0xb8, 0x54, 0xe3, 0x40, 0x46, 0x03, 0xfe, 0x39, 0x64, - 0xe6, 0xc1, 0x87, 0x56, 0xef, 0xf8, 0xac, 0x95, 0xb6, 0xc1, 0x49, 0x19, 0x64, 0x6d, 0x61, 0x65, 0x6d, 0xe1, 0x65, - 0x6d, 0xe1, 0x65, 0x6d, 0x10, 0xe0, 0x83, 0xbe, 0xff, 0x91, 0x35, 0xc3, 0x0f, 0x5e, 0x5a, 0x91, 0x58, 0x33, 0x81, - 0x58, 0xaf, 0x56, 0xcb, 0x35, 0xd8, 0xf8, 0x94, 0x35, 0xa4, 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, - 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, 0x3f, 0xa6, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, - 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, - 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0xf0, 0x79, 0xb1, 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x5c, 0x98, - 0x2d, 0xa9, 0x13, 0x6a, 0xbc, 0xa6, 0xcb, 0x31, 0x7f, 0xad, 0xa1, 0x7d, 0x02, 0x6f, 0xb9, 0x3c, 0xd4, 0x71, 0x0b, - 0x8c, 0x26, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, 0x8d, 0x33, 0x86, 0xfe, 0xbc, 0xe1, 0x83, 0x6a, 0x29, - 0x41, 0xf8, 0x82, 0xc1, 0x67, 0x56, 0x39, 0xc5, 0x97, 0xb6, 0x9e, 0xce, 0x50, 0xcb, 0x1e, 0x09, 0x5d, 0x30, 0xd8, - 0xf6, 0xd1, 0x96, 0x7a, 0x82, 0x48, 0x65, 0xdc, 0x05, 0x49, 0x15, 0x2f, 0x18, 0xdc, 0x67, 0xc9, 0x2d, 0x35, 0xce, - 0x24, 0x2f, 0xec, 0x9f, 0xaf, 0x34, 0xf0, 0xb6, 0x2b, 0x26, 0x43, 0xef, 0xa4, 0x7a, 0x6d, 0xa2, 0xea, 0x90, 0xfd, - 0x7d, 0x6b, 0x4b, 0x6d, 0xbe, 0x36, 0x8d, 0xa9, 0x4d, 0xa2, 0xc9, 0x86, 0x1d, 0xea, 0xd7, 0xe8, 0x1f, 0xef, 0x2b, - 0x56, 0x4c, 0x86, 0x28, 0xa0, 0xd9, 0x06, 0xac, 0xaa, 0x02, 0x96, 0x72, 0xf5, 0x4a, 0x17, 0x42, 0xe8, 0xdd, 0x8c, - 0x79, 0x5d, 0x4c, 0x86, 0x3b, 0x1f, 0xfd, 0xb0, 0x3d, 0xf6, 0xde, 0xd2, 0xa0, 0x07, 0xaf, 0xda, 0x9e, 0xb2, 0xdb, - 0xef, 0xd5, 0xb9, 0xd9, 0x59, 0x47, 0xe5, 0xdf, 0xab, 0xf3, 0x74, 0x57, 0x9d, 0x19, 0xbf, 0x8d, 0xfd, 0xde, 0xd1, - 0x81, 0x1a, 0xdb, 0x18, 0xe8, 0x4c, 0x86, 0x10, 0xa5, 0x1d, 0xfe, 0xda, 0x58, 0x2a, 0x5d, 0x4f, 0xc2, 0x61, 0x15, - 0x64, 0x2f, 0x39, 0x4d, 0x19, 0xa6, 0xa4, 0x73, 0x58, 0x98, 0x68, 0x2a, 0x22, 0xa1, 0x4d, 0x95, 0x50, 0x9c, 0x93, - 0x38, 0xa6, 0x87, 0x19, 0xc4, 0x84, 0x69, 0xf7, 0x68, 0x1a, 0xd3, 0x46, 0x86, 0x8e, 0xe2, 0x76, 0x83, 0x1e, 0x66, - 0x08, 0x35, 0xda, 0xa0, 0x33, 0x95, 0xa4, 0xdd, 0xcc, 0x21, 0x4a, 0xa4, 0x21, 0xc5, 0xf9, 0xa1, 0x48, 0x8a, 0x86, - 0x3c, 0x54, 0x49, 0xd1, 0x48, 0x4e, 0xb1, 0x48, 0x26, 0x65, 0xf2, 0xc4, 0x24, 0x4f, 0x6c, 0xf2, 0xb0, 0x4c, 0x1e, - 0x9a, 0xe4, 0xa1, 0x4d, 0xa6, 0xa4, 0x38, 0x14, 0x09, 0x6d, 0xc4, 0xed, 0x66, 0x81, 0x0e, 0x61, 0x04, 0x7e, 0xf4, - 0x44, 0x84, 0xc1, 0xb9, 0xd7, 0xc6, 0xba, 0x65, 0x2e, 0x73, 0x17, 0x2e, 0xb3, 0x02, 0x52, 0xe9, 0x72, 0x04, 0x75, - 0x9e, 0x05, 0x60, 0xc2, 0xda, 0xfe, 0xf1, 0xc1, 0xe0, 0xd6, 0x59, 0x2e, 0x45, 0xe0, 0x52, 0x05, 0x56, 0xe0, 0x9f, - 0x9d, 0x23, 0x09, 0x40, 0x75, 0x4d, 0xf3, 0xf9, 0x94, 0x6e, 0xf9, 0xad, 0x16, 0x93, 0xa1, 0xdb, 0x59, 0x65, 0x33, - 0x8c, 0x16, 0x36, 0xc8, 0x72, 0xdd, 0xc3, 0x10, 0x40, 0xed, 0xbd, 0x1a, 0x13, 0x6a, 0x94, 0xe4, 0xb6, 0xc6, 0xa4, - 0x60, 0x77, 0x2a, 0xa3, 0x39, 0x8b, 0xab, 0x03, 0xb8, 0x1a, 0x26, 0x23, 0x2f, 0xc0, 0x16, 0xbd, 0x38, 0x4c, 0x8e, - 0x1b, 0x3a, 0x99, 0x1c, 0x26, 0xa7, 0x0f, 0x1a, 0x3a, 0x19, 0x1e, 0x26, 0xed, 0x76, 0x85, 0xb3, 0x49, 0x41, 0x74, - 0x32, 0x21, 0x1a, 0x34, 0x86, 0xb6, 0x51, 0x39, 0xa7, 0x60, 0x5c, 0xf5, 0x6f, 0x0c, 0xa3, 0xe1, 0x86, 0x21, 0xd8, - 0xc4, 0xc6, 0x9b, 0xdc, 0x1a, 0x43, 0xd8, 0x4d, 0xe7, 0xf4, 0xb4, 0xa9, 0x93, 0x02, 0x6b, 0xbb, 0x92, 0x4d, 0x9d, - 0x4c, 0xb0, 0xb6, 0xcb, 0xd7, 0xd4, 0xc9, 0xd0, 0x36, 0x65, 0x74, 0x80, 0x4c, 0x04, 0xc0, 0x7a, 0xce, 0x02, 0xc8, - 0x77, 0xbc, 0x7b, 0xc8, 0x1a, 0xb4, 0x86, 0xdf, 0x2b, 0xd7, 0xf4, 0x05, 0x15, 0xd5, 0x60, 0x64, 0xc3, 0xbe, 0x55, - 0xb4, 0x5d, 0x35, 0xc9, 0xfe, 0x75, 0xd9, 0xb2, 0xd9, 0x42, 0xea, 0x7a, 0xc1, 0x87, 0x35, 0x0c, 0x71, 0xa5, 0xdc, - 0xc1, 0xfd, 0x8a, 0x92, 0x18, 0xa2, 0xca, 0x99, 0x53, 0x88, 0x13, 0xaf, 0x47, 0x86, 0x24, 0xde, 0x68, 0xac, 0x51, - 0x1c, 0x9c, 0xb7, 0x4f, 0x43, 0xaa, 0xba, 0x15, 0x6a, 0x8e, 0x90, 0x68, 0x21, 0xac, 0x31, 0xe2, 0x28, 0x0a, 0x58, - 0x10, 0xa7, 0xdd, 0xad, 0x1d, 0x10, 0x07, 0x07, 0x9b, 0xe7, 0x85, 0x0f, 0xfa, 0xbf, 0x15, 0xe8, 0xbf, 0xb2, 0x64, - 0xf3, 0x4f, 0x11, 0x59, 0x1b, 0x57, 0x1e, 0x20, 0x8a, 0x0f, 0xfa, 0x74, 0xdf, 0x50, 0xf8, 0x7e, 0x15, 0xf1, 0xce, - 0xe5, 0x34, 0xcf, 0x4c, 0x86, 0xe9, 0x6b, 0x10, 0x8c, 0xed, 0x4d, 0x38, 0xa1, 0xd2, 0x4a, 0xef, 0x5f, 0x76, 0x1c, - 0x74, 0xe2, 0x9e, 0x4a, 0x09, 0x1b, 0xfd, 0x3b, 0xb4, 0x89, 0xad, 0x60, 0xe3, 0xbc, 0xa1, 0x57, 0xab, 0xda, 0xc3, - 0x38, 0xf6, 0xf9, 0x15, 0x74, 0x70, 0xc0, 0xd5, 0x33, 0x30, 0xe3, 0x65, 0x71, 0x23, 0x3c, 0x7c, 0xff, 0xa9, 0x9d, - 0xd6, 0x7f, 0x9b, 0x73, 0x35, 0x0d, 0x0e, 0xba, 0x87, 0xb5, 0xfc, 0x9d, 0x2b, 0xd1, 0xd3, 0x29, 0x77, 0x6b, 0xfd, - 0x77, 0x65, 0x24, 0xbd, 0xf5, 0x44, 0xd3, 0xc1, 0x01, 0xaf, 0x02, 0x25, 0x45, 0x3f, 0x44, 0xa8, 0x67, 0x64, 0x90, - 0x67, 0xb9, 0xa4, 0x70, 0x23, 0x0a, 0x57, 0x0c, 0x69, 0x83, 0x1f, 0x69, 0xfc, 0x87, 0xfc, 0xff, 0xd4, 0xc8, 0xa1, - 0x4e, 0x1b, 0x3c, 0x10, 0xc0, 0x42, 0x56, 0xa8, 0x0a, 0x51, 0x68, 0x20, 0x1d, 0xda, 0x3c, 0xa3, 0xf2, 0x30, 0xa7, - 0xf3, 0x79, 0x7e, 0x67, 0x5e, 0xa9, 0x0a, 0x38, 0xaa, 0xea, 0xa2, 0xc9, 0xc5, 0x87, 0xc3, 0x05, 0xf0, 0xf4, 0x80, - 0x7b, 0xc8, 0xf8, 0x77, 0x96, 0x97, 0xdb, 0x02, 0x81, 0x64, 0xa6, 0x88, 0x6c, 0xb6, 0xbb, 0xea, 0x12, 0xe4, 0xb2, - 0x66, 0x13, 0x69, 0x17, 0x36, 0x1b, 0x73, 0x90, 0xc9, 0x94, 0xf5, 0xe1, 0xdc, 0xb3, 0x05, 0x41, 0x72, 0x93, 0x46, - 0x64, 0xdb, 0x5d, 0x8a, 0x8f, 0x63, 0x40, 0x23, 0x64, 0x05, 0xbe, 0x50, 0x58, 0xe4, 0xc0, 0x75, 0x16, 0xbe, 0xe3, - 0x6f, 0xb4, 0x54, 0xf4, 0xd5, 0x60, 0x80, 0x0b, 0xf3, 0x30, 0x43, 0x39, 0x9f, 0x42, 0x05, 0x0f, 0xfd, 0x04, 0x22, - 0x0a, 0x5f, 0xad, 0xf6, 0xe1, 0x1d, 0x1d, 0xd7, 0x26, 0x38, 0x7d, 0xba, 0x9f, 0xd5, 0x9b, 0x19, 0x30, 0x0e, 0x46, - 0x5a, 0xe6, 0xa2, 0xd0, 0xc9, 0x9b, 0xec, 0x42, 0x74, 0x1b, 0x0d, 0x66, 0x42, 0x1c, 0x11, 0x88, 0x67, 0x06, 0x1e, - 0x79, 0xf0, 0xc7, 0x46, 0x2d, 0x52, 0xcc, 0xc6, 0x7e, 0x83, 0xa0, 0xd4, 0xb5, 0x84, 0xd5, 0x4a, 0xd9, 0xd8, 0x22, - 0x26, 0xc7, 0x46, 0x19, 0x29, 0xfb, 0x29, 0x83, 0x98, 0x56, 0x66, 0x1c, 0xdc, 0x6d, 0xf5, 0xb7, 0xd5, 0x7e, 0xde, - 0xe3, 0xf6, 0x1a, 0x8f, 0x1b, 0x8f, 0x7d, 0x03, 0xa8, 0xe5, 0xc6, 0x06, 0xb7, 0x16, 0xe6, 0xb1, 0x35, 0x87, 0x65, - 0x9b, 0x10, 0x14, 0xa5, 0x87, 0xba, 0xbd, 0xb9, 0xf5, 0x11, 0xfb, 0x94, 0x99, 0x93, 0x42, 0xba, 0x0f, 0x72, 0xf4, - 0x80, 0x40, 0xe7, 0xf6, 0x67, 0x45, 0x17, 0x2a, 0x99, 0xb8, 0x1c, 0xe3, 0x2f, 0xc1, 0x6d, 0x5e, 0x3f, 0xba, 0xbe, - 0x36, 0x9b, 0xfc, 0xfa, 0x3a, 0xc2, 0xa1, 0x59, 0x77, 0x14, 0xf0, 0x82, 0xd1, 0xa0, 0x0c, 0xea, 0x64, 0x36, 0x7e, - 0xb3, 0x5d, 0x35, 0xf6, 0x9e, 0x56, 0x78, 0x07, 0xcb, 0x63, 0x1a, 0xdf, 0x72, 0x83, 0xec, 0x73, 0x80, 0x37, 0xeb, - 0xf3, 0x41, 0xf7, 0x4d, 0xac, 0xd0, 0xc1, 0xc1, 0x9b, 0x58, 0xa2, 0xde, 0x15, 0x33, 0x77, 0x6e, 0xe0, 0x07, 0xdd, - 0xe7, 0x66, 0xf8, 0x32, 0x40, 0x80, 0x2b, 0xb6, 0x29, 0xd9, 0xbc, 0x35, 0x51, 0x27, 0x52, 0x88, 0x6a, 0x0d, 0xb1, - 0x75, 0x1d, 0x48, 0xa0, 0xd7, 0x37, 0x21, 0xb4, 0xbb, 0x8c, 0x30, 0x60, 0xe1, 0x4b, 0x2f, 0x35, 0x96, 0xcc, 0x58, - 0x31, 0x61, 0xc5, 0x6a, 0xf5, 0x9e, 0x5a, 0xcf, 0xb3, 0x8d, 0x20, 0x89, 0xaa, 0xdb, 0x68, 0x50, 0x33, 0x7e, 0x10, - 0x1f, 0xe8, 0x00, 0xef, 0xbf, 0x89, 0x0b, 0x84, 0xc0, 0xc2, 0x88, 0x8b, 0x85, 0xf7, 0xb2, 0xca, 0x6a, 0xeb, 0x52, - 0xa0, 0xb2, 0x91, 0x9c, 0xb4, 0xf0, 0x94, 0x64, 0xe5, 0x1a, 0x5d, 0x4c, 0xbb, 0x8d, 0x46, 0x8e, 0x64, 0x9c, 0xf5, - 0xf3, 0x01, 0xe6, 0xb8, 0x80, 0xcb, 0xd4, 0xed, 0x75, 0x98, 0xb3, 0x1a, 0xe5, 0x72, 0xf3, 0x5d, 0xda, 0xb1, 0xa6, - 0x8f, 0xe8, 0x3a, 0x00, 0xc6, 0x23, 0x1a, 0x10, 0x89, 0x5d, 0x40, 0x16, 0x16, 0xc8, 0xca, 0x03, 0x59, 0x18, 0x20, - 0x2b, 0xd4, 0x9b, 0x43, 0xb8, 0x20, 0x85, 0xd2, 0x2d, 0x8a, 0x5e, 0x0f, 0x6c, 0xe9, 0x9c, 0x26, 0x30, 0x37, 0xb1, - 0x15, 0xdc, 0x72, 0x80, 0x03, 0x85, 0xf3, 0xc3, 0x53, 0x64, 0x19, 0x45, 0x26, 0xc6, 0x2b, 0xbe, 0x35, 0x7f, 0x92, - 0x5b, 0x7c, 0x67, 0x7f, 0xdc, 0x05, 0xca, 0xa4, 0xe7, 0x35, 0x6d, 0x03, 0x77, 0x11, 0xd1, 0xa2, 0x24, 0x02, 0xb4, - 0x76, 0xe1, 0xfd, 0x44, 0xfd, 0xc5, 0x33, 0x65, 0x03, 0x31, 0x88, 0x06, 0x51, 0x58, 0x04, 0xa4, 0xf3, 0xcf, 0x3f, - 0x23, 0xd4, 0x13, 0x10, 0x47, 0xc7, 0x9d, 0x6c, 0xcd, 0x36, 0x6a, 0x44, 0x49, 0x94, 0xc6, 0x3e, 0x4c, 0x03, 0xec, - 0x8c, 0x28, 0x0a, 0x5e, 0x3b, 0x29, 0x87, 0xf1, 0xa1, 0x36, 0x0c, 0x33, 0xa8, 0x2a, 0xf0, 0xc4, 0xe5, 0x72, 0x33, - 0xcc, 0x8f, 0x81, 0xaa, 0x30, 0x31, 0x56, 0x90, 0x7d, 0x02, 0x8c, 0x11, 0x76, 0x70, 0xc0, 0xfa, 0x62, 0x10, 0xbc, - 0xe9, 0x55, 0x5d, 0x87, 0xeb, 0x70, 0xe1, 0x62, 0x0a, 0x71, 0xd6, 0x57, 0x2b, 0xfb, 0x97, 0x7c, 0x30, 0xd2, 0x0c, - 0x3c, 0xce, 0x16, 0x9c, 0xb1, 0x62, 0xb7, 0x2c, 0x96, 0x68, 0xf9, 0x3b, 0x98, 0xed, 0xb9, 0xa8, 0x79, 0xdc, 0x4d, - 0xb5, 0xed, 0xa1, 0x3e, 0x37, 0x1a, 0x85, 0x20, 0x66, 0x6d, 0x75, 0xa4, 0xe1, 0xb9, 0x0e, 0xf3, 0x6a, 0xb1, 0x67, - 0x33, 0x55, 0x86, 0x10, 0x85, 0x23, 0x25, 0x01, 0xbb, 0x6d, 0x43, 0x27, 0xe1, 0x47, 0x9d, 0x4a, 0x3a, 0x16, 0x12, - 0xa0, 0xc0, 0x91, 0xb9, 0x9c, 0x37, 0x21, 0xe2, 0x19, 0xda, 0x41, 0xe4, 0x02, 0x13, 0x9a, 0xba, 0x6c, 0xe9, 0x62, - 0x39, 0x45, 0x33, 0xb9, 0x50, 0x6c, 0x31, 0x87, 0xf3, 0xbd, 0x4c, 0xcb, 0x72, 0x9e, 0x7d, 0xae, 0xa7, 0x80, 0xfd, - 0xe5, 0xad, 0x9e, 0x31, 0xb1, 0x88, 0xdc, 0x3c, 0xbf, 0x5a, 0x71, 0xff, 0xcd, 0x0b, 0xfc, 0x88, 0x74, 0x0e, 0xbf, - 0xe2, 0x8f, 0x94, 0x3c, 0x6a, 0x7c, 0xc5, 0x13, 0x4e, 0x2c, 0x6f, 0x90, 0xbc, 0x79, 0x7d, 0xf5, 0xe2, 0xdd, 0x8b, - 0xf7, 0x4f, 0xaf, 0x5f, 0xbc, 0x7a, 0xf6, 0xe2, 0xd5, 0x8b, 0x77, 0x1f, 0xf1, 0x3f, 0x94, 0x7c, 0x3d, 0x6a, 0x9f, - 0xb7, 0xf0, 0x07, 0xf2, 0xf5, 0xa8, 0x83, 0x6f, 0x35, 0xf9, 0x7a, 0x74, 0x82, 0x73, 0x45, 0xbe, 0x1e, 0x76, 0x8e, - 0x8e, 0xf1, 0x42, 0xdb, 0x26, 0x73, 0x39, 0x69, 0xb7, 0xf0, 0x3f, 0xee, 0x0b, 0xc4, 0xfb, 0x6a, 0x16, 0x13, 0xb6, - 0x61, 0xfc, 0x60, 0xca, 0xd0, 0xa1, 0x32, 0x86, 0x28, 0x17, 0x01, 0x3a, 0x4d, 0x55, 0x88, 0x4e, 0x36, 0x88, 0x31, - 0xd8, 0x30, 0x02, 0x5a, 0x71, 0xe2, 0xda, 0xe1, 0x47, 0x6d, 0x76, 0x0c, 0xf4, 0x89, 0x97, 0xc2, 0x71, 0xa9, 0xc2, - 0x69, 0x3b, 0x2d, 0xc6, 0x38, 0x97, 0xb2, 0x88, 0x17, 0xc0, 0x08, 0x18, 0xad, 0x05, 0x3f, 0x2a, 0xa3, 0x25, 0x89, - 0x0b, 0xd2, 0xee, 0xb5, 0x53, 0x71, 0x41, 0x3a, 0xbd, 0x0e, 0xfc, 0x39, 0xed, 0x9d, 0xa6, 0xed, 0x16, 0x3a, 0x0c, - 0xc6, 0xf1, 0x47, 0x0d, 0xad, 0xfb, 0x03, 0xec, 0xba, 0x50, 0xff, 0x14, 0xda, 0xab, 0xf4, 0x84, 0x53, 0xc7, 0xb6, - 0xbb, 0xe2, 0x82, 0x19, 0x3d, 0x2c, 0xff, 0x01, 0x50, 0xdb, 0x38, 0x74, 0x94, 0x1b, 0xc7, 0xfd, 0xe2, 0x47, 0x02, - 0xd5, 0x42, 0xb2, 0xc4, 0x6c, 0xd5, 0x42, 0xc0, 0x34, 0x9a, 0x6c, 0x30, 0x07, 0x4a, 0x94, 0x2c, 0xb4, 0x0f, 0x2b, - 0xaf, 0x9a, 0x12, 0x25, 0x73, 0x39, 0x8f, 0x6b, 0xaa, 0x86, 0x5f, 0x03, 0x33, 0xc7, 0x7d, 0xae, 0x5e, 0xd1, 0x57, - 0x71, 0x8d, 0xe7, 0x09, 0x59, 0xbb, 0x70, 0x5b, 0xfc, 0xe2, 0xac, 0x28, 0x6a, 0xe0, 0x2a, 0x01, 0xeb, 0x47, 0xd5, - 0xd4, 0x17, 0xf0, 0x7e, 0x1e, 0x6b, 0xe8, 0x4b, 0x12, 0x50, 0xcf, 0x9f, 0x4a, 0x33, 0xae, 0x52, 0x19, 0xed, 0x15, - 0xd1, 0xc6, 0x2c, 0xc8, 0x2b, 0xa2, 0x2f, 0x94, 0x01, 0x82, 0x24, 0xbc, 0x2f, 0x06, 0x70, 0xe0, 0xdb, 0x01, 0x4a, - 0x43, 0xe7, 0x40, 0xad, 0x54, 0x99, 0x09, 0x99, 0x4f, 0x13, 0x1c, 0x00, 0x34, 0x4f, 0x95, 0x0a, 0xca, 0x7c, 0x62, - 0x89, 0x82, 0xa1, 0xff, 0x16, 0x6e, 0x80, 0xc3, 0xd8, 0xa0, 0x62, 0x90, 0x7d, 0x4f, 0xd4, 0xf3, 0xdb, 0xe7, 0xad, - 0xa3, 0xaf, 0x41, 0xfe, 0x48, 0x79, 0x7b, 0x8f, 0xbf, 0x03, 0x4a, 0x6e, 0xc3, 0x59, 0xb5, 0xb1, 0x8f, 0x44, 0xd6, - 0x0d, 0x01, 0x72, 0xa8, 0xd1, 0x91, 0x79, 0x4a, 0xb0, 0x8b, 0xf4, 0x21, 0x69, 0xb7, 0x20, 0x7c, 0xd8, 0x0e, 0xca, - 0xf7, 0xd3, 0x06, 0x4c, 0x75, 0x72, 0xdb, 0x04, 0x5a, 0x0d, 0xaf, 0x0b, 0xdd, 0x35, 0x79, 0x72, 0x87, 0x55, 0x80, - 0x33, 0xec, 0x90, 0x35, 0xc4, 0xa1, 0x40, 0x2e, 0xec, 0xaa, 0xdd, 0x00, 0x9a, 0x8a, 0x8e, 0x7d, 0xe5, 0xce, 0x1b, - 0x47, 0x5d, 0x34, 0x93, 0xd3, 0xc3, 0xaf, 0x07, 0x07, 0xb1, 0x6c, 0x90, 0x47, 0x08, 0x2f, 0x29, 0x58, 0x31, 0x83, - 0xd7, 0x17, 0xb7, 0x4c, 0x7c, 0xaa, 0x02, 0xea, 0xb8, 0x50, 0xb5, 0x63, 0xad, 0xea, 0xac, 0xdc, 0x0d, 0x7e, 0x4c, - 0x1d, 0xd4, 0x08, 0xd2, 0xec, 0xe8, 0x3a, 0x35, 0x28, 0xd7, 0x5c, 0xb4, 0x60, 0x5b, 0x36, 0x3e, 0x52, 0xf4, 0xc3, - 0xa3, 0xe6, 0xd7, 0x60, 0xc2, 0x35, 0xd3, 0xa4, 0x47, 0x8d, 0x47, 0xe8, 0x87, 0x47, 0x81, 0x93, 0x1d, 0xaf, 0xd8, - 0x13, 0xcf, 0x8d, 0xfc, 0x64, 0xb9, 0xd2, 0x9f, 0x40, 0xb2, 0x2f, 0xc8, 0x4f, 0x80, 0xe5, 0x94, 0xfc, 0x14, 0xcb, - 0x26, 0x04, 0x1f, 0x24, 0x3f, 0xc5, 0x05, 0xfc, 0xc8, 0xc9, 0x4f, 0x31, 0x60, 0x3b, 0x9e, 0x9a, 0x1f, 0x45, 0x09, - 0x0c, 0x70, 0xec, 0x92, 0xd6, 0xbf, 0xab, 0x58, 0xad, 0xc4, 0xc1, 0x81, 0xb4, 0xbf, 0xe8, 0x65, 0x76, 0x70, 0x90, - 0x5f, 0x4c, 0xab, 0xbe, 0x99, 0xde, 0x45, 0x5f, 0x0c, 0x42, 0xe1, 0xc0, 0x34, 0x8d, 0x87, 0x33, 0xfe, 0x14, 0x52, - 0x56, 0xd3, 0x40, 0xf3, 0xb8, 0x73, 0xff, 0xec, 0x1c, 0xc3, 0xbf, 0xf7, 0x83, 0x82, 0x3f, 0x97, 0x7c, 0x17, 0x69, - 0xb3, 0xe6, 0x59, 0x85, 0x6c, 0x97, 0x01, 0x3e, 0x63, 0x86, 0x9a, 0xe2, 0xe0, 0x80, 0x5f, 0x04, 0xb8, 0x8c, 0x19, - 0x6a, 0x04, 0x16, 0x7b, 0x0f, 0x4b, 0x7b, 0x32, 0xc3, 0x35, 0xc1, 0xb3, 0xb2, 0xbc, 0x5f, 0x0c, 0x2e, 0xb4, 0xa3, - 0x26, 0x61, 0xf0, 0x69, 0x45, 0x5a, 0x6e, 0x93, 0x75, 0x45, 0x53, 0x5d, 0xb6, 0xbb, 0x48, 0x12, 0xd5, 0x10, 0x97, - 0x97, 0x6d, 0x0c, 0x2a, 0xf9, 0x9e, 0x22, 0x32, 0x15, 0xc4, 0x3b, 0xc8, 0x2d, 0x73, 0x99, 0x2a, 0x3c, 0xe5, 0xa9, - 0xf0, 0x72, 0xf6, 0x6b, 0x6f, 0x3d, 0x6d, 0x5c, 0x16, 0x4d, 0xcf, 0x0c, 0x8b, 0x9e, 0x2a, 0x5d, 0xed, 0x60, 0x93, - 0xaa, 0x01, 0xbc, 0xda, 0x57, 0x62, 0x1e, 0xb3, 0xfe, 0x65, 0x0c, 0xa2, 0x22, 0xab, 0x46, 0x1b, 0x32, 0xe1, 0x73, - 0x9d, 0x2a, 0x18, 0xa8, 0x29, 0x7c, 0x01, 0x64, 0x2a, 0xab, 0x0c, 0xb3, 0x7d, 0xc3, 0x50, 0x40, 0x40, 0x81, 0x4b, - 0xc2, 0x02, 0x09, 0x1e, 0x6e, 0x3f, 0x02, 0xc2, 0x51, 0x27, 0x17, 0x76, 0x72, 0x17, 0x0a, 0xba, 0x13, 0x83, 0x0b, - 0xdd, 0x45, 0xa2, 0xd1, 0x70, 0xdc, 0xf6, 0xa5, 0x30, 0x83, 0x68, 0xb6, 0x07, 0x97, 0xac, 0x8b, 0x54, 0xb3, 0x59, - 0x1a, 0x40, 0x5e, 0xb6, 0x56, 0x2b, 0x75, 0xe1, 0x1b, 0xe9, 0xf9, 0x73, 0xdc, 0xf0, 0x5d, 0x5e, 0xf0, 0xfc, 0x4d, - 0x92, 0x7e, 0x04, 0x54, 0x15, 0xf8, 0x6c, 0x39, 0x8f, 0x70, 0x64, 0x1e, 0x74, 0x83, 0xbf, 0xe6, 0x21, 0xae, 0x08, - 0x47, 0xee, 0x8d, 0xb7, 0x68, 0x50, 0x0d, 0x96, 0x67, 0x65, 0x78, 0x72, 0x9e, 0x5c, 0x03, 0xe3, 0xa0, 0xff, 0x56, - 0x68, 0x59, 0xfd, 0x4e, 0x72, 0x17, 0xa8, 0x43, 0xf9, 0x67, 0xc7, 0xdc, 0xa8, 0xd6, 0xbb, 0x5d, 0x23, 0x39, 0x8e, - 0x7c, 0x55, 0x08, 0xdf, 0xff, 0x9d, 0x77, 0x0f, 0xdb, 0xee, 0xb9, 0xed, 0x65, 0xd9, 0x03, 0x70, 0xde, 0xeb, 0x35, - 0xc2, 0xbf, 0xc9, 0x9d, 0x6f, 0xef, 0x46, 0xd7, 0x52, 0x3c, 0xa1, 0x9a, 0x46, 0x8d, 0x37, 0xc6, 0xf0, 0xcd, 0xca, - 0x59, 0xdd, 0x6f, 0x8d, 0x83, 0xfd, 0x5b, 0xdd, 0x43, 0xe8, 0x84, 0xda, 0x33, 0x41, 0x56, 0xf6, 0x35, 0x01, 0x33, - 0x64, 0x60, 0xfa, 0xb6, 0x03, 0x1e, 0x7e, 0x8c, 0x14, 0x1c, 0x7a, 0x2d, 0x9f, 0x44, 0x21, 0x26, 0x69, 0xcd, 0x8d, - 0x18, 0x52, 0x6c, 0x1f, 0xc6, 0xe5, 0x74, 0x8d, 0x42, 0xae, 0x7b, 0xac, 0xea, 0xc4, 0xb4, 0xea, 0xc6, 0x48, 0x1d, - 0x6c, 0x93, 0x05, 0x67, 0x55, 0xef, 0x46, 0x42, 0xa9, 0x5e, 0x54, 0x33, 0xaf, 0x62, 0x36, 0xdb, 0xe6, 0x99, 0x61, - 0xfb, 0xee, 0x9a, 0x02, 0x43, 0xde, 0xfd, 0x32, 0x5c, 0xd4, 0x25, 0x1c, 0xbb, 0x71, 0x00, 0x59, 0x49, 0x2e, 0x97, - 0xee, 0x4d, 0x34, 0xde, 0x97, 0x83, 0x75, 0xf9, 0x42, 0x5a, 0x80, 0x07, 0xd5, 0x48, 0x45, 0x16, 0x72, 0x06, 0xfe, - 0x79, 0xc1, 0x9a, 0x7e, 0x88, 0x7f, 0x85, 0x03, 0xbe, 0x42, 0xd2, 0xd4, 0xaa, 0x9f, 0xe0, 0xe5, 0x22, 0x50, 0x78, - 0xdb, 0xba, 0x9f, 0x64, 0xe8, 0x22, 0x5a, 0xd7, 0xa9, 0x58, 0x2f, 0xcc, 0xba, 0x62, 0xa5, 0x2c, 0x1c, 0x1c, 0x77, - 0x31, 0x5a, 0xa7, 0xce, 0x63, 0xd3, 0x3d, 0x77, 0xf4, 0x50, 0xf0, 0x99, 0x71, 0xa4, 0x7b, 0x56, 0x40, 0xfc, 0xaa, - 0x50, 0x9f, 0xf6, 0xb3, 0x0c, 0xdf, 0xf3, 0xed, 0xc3, 0x3d, 0x61, 0xc9, 0x73, 0x96, 0x6f, 0x50, 0xc3, 0x02, 0x29, - 0xa0, 0x50, 0x0a, 0x8b, 0xd5, 0x2a, 0x16, 0x26, 0xaa, 0x81, 0x0b, 0x6a, 0xeb, 0x5e, 0xaf, 0x30, 0xfa, 0x3b, 0xa8, - 0x8b, 0xbd, 0x7a, 0xc4, 0x98, 0xb0, 0xa2, 0xf0, 0xd2, 0x49, 0x65, 0x41, 0x5f, 0xbb, 0xfa, 0x10, 0xd5, 0x94, 0x7b, - 0xb1, 0xd1, 0xf7, 0xbe, 0xe3, 0x33, 0x26, 0x17, 0xf0, 0x6c, 0x10, 0x66, 0x44, 0x31, 0xed, 0xbf, 0x81, 0x82, 0xc0, - 0xdb, 0x33, 0x3c, 0xc4, 0x47, 0xe0, 0xab, 0x3c, 0xad, 0x93, 0x99, 0x7f, 0x8c, 0x22, 0x32, 0xc1, 0x22, 0xa3, 0x5e, - 0x04, 0x5e, 0x43, 0x20, 0x42, 0x11, 0x12, 0x31, 0x31, 0x8a, 0x7a, 0x91, 0x71, 0x52, 0x8a, 0xc0, 0x6a, 0x0c, 0x94, - 0xdc, 0x11, 0x9e, 0xab, 0x8a, 0x88, 0x85, 0x35, 0x75, 0x50, 0x89, 0xa5, 0xc6, 0x4c, 0xfb, 0xa8, 0x53, 0x81, 0xb0, - 0xc8, 0x36, 0x05, 0x65, 0xbd, 0xa1, 0x2e, 0xc0, 0x92, 0x18, 0xd3, 0x5b, 0x9e, 0x5c, 0x03, 0x37, 0xc7, 0x46, 0xae, - 0xe8, 0x92, 0x5f, 0x81, 0x7a, 0x3a, 0x2d, 0xf0, 0xb5, 0x61, 0xd8, 0x46, 0x29, 0x5d, 0x13, 0x8e, 0x33, 0x52, 0x24, - 0xf4, 0x16, 0xa2, 0x3a, 0xcc, 0xb8, 0x48, 0x73, 0x3c, 0xa3, 0xb7, 0xe9, 0x14, 0xcf, 0xb8, 0x78, 0x62, 0x97, 0x3d, - 0x1d, 0x41, 0x92, 0xff, 0x58, 0xac, 0x89, 0x79, 0x94, 0xea, 0x77, 0xc5, 0x8a, 0x47, 0xc0, 0xab, 0xa8, 0x18, 0x75, - 0x47, 0xc6, 0xa6, 0x9c, 0xe9, 0xca, 0x78, 0xfd, 0xb5, 0x8e, 0x29, 0xce, 0x70, 0x8e, 0x92, 0x5c, 0x62, 0xd6, 0x13, - 0xe9, 0x6b, 0x88, 0xe8, 0x9c, 0x61, 0xfb, 0xa0, 0x15, 0xbf, 0x65, 0xf9, 0x33, 0x59, 0xbc, 0x37, 0x5b, 0x3e, 0x47, - 0x50, 0x08, 0x5c, 0x54, 0x44, 0x13, 0x6e, 0xf7, 0x16, 0x3d, 0x59, 0x35, 0x45, 0x6f, 0x6d, 0x53, 0x6e, 0x88, 0x53, - 0x08, 0x85, 0x9b, 0x4c, 0x79, 0xa3, 0x8d, 0x59, 0xaf, 0xf5, 0x9d, 0x46, 0xa7, 0xa8, 0x2c, 0x89, 0x30, 0xac, 0x55, - 0x53, 0xa5, 0x92, 0x88, 0xa6, 0x72, 0x12, 0xde, 0xd2, 0x00, 0x3b, 0x55, 0x38, 0x93, 0x0b, 0xa1, 0x53, 0x19, 0xe0, - 0x0d, 0xad, 0x36, 0xd7, 0xf2, 0xd6, 0x42, 0x4c, 0xe3, 0x3b, 0xfb, 0x83, 0xe1, 0x6b, 0xa3, 0xe2, 0x7f, 0x0b, 0x86, - 0x3d, 0x2a, 0x15, 0x00, 0x3f, 0x30, 0x9c, 0x05, 0xc8, 0x59, 0x7e, 0xf2, 0x16, 0xc0, 0x67, 0x59, 0xc8, 0x3b, 0x48, - 0x65, 0x26, 0xf5, 0x0e, 0x52, 0x19, 0xa4, 0x1a, 0x5f, 0xee, 0x7d, 0x51, 0x29, 0x8b, 0xc2, 0x06, 0x89, 0xc2, 0xa5, - 0x3a, 0x58, 0x12, 0x91, 0x40, 0xbb, 0x46, 0x94, 0x9b, 0x71, 0x01, 0x41, 0xfd, 0xa0, 0x71, 0xfb, 0x4d, 0x6f, 0xe1, - 0xfb, 0xce, 0xe6, 0x33, 0x9f, 0x7f, 0x67, 0xf3, 0x4d, 0x47, 0x1e, 0xe3, 0xeb, 0xb7, 0x9d, 0xc6, 0x32, 0x5e, 0x3a, - 0xac, 0xfd, 0x50, 0x3e, 0xa1, 0xd2, 0x32, 0x4f, 0x55, 0x93, 0x36, 0x9e, 0x04, 0x48, 0xd9, 0xac, 0x78, 0xb8, 0x0e, - 0x6e, 0xb7, 0x0e, 0x63, 0xde, 0x24, 0x6d, 0x84, 0x0e, 0x9d, 0x70, 0x25, 0x62, 0x23, 0x39, 0x1d, 0x3e, 0x3a, 0x82, - 0xbb, 0x97, 0x99, 0xda, 0xf0, 0x95, 0xb2, 0xd5, 0x9a, 0xed, 0xd6, 0x21, 0xdf, 0x59, 0xa5, 0xd1, 0xc6, 0x33, 0x46, - 0x96, 0xe0, 0x5c, 0x46, 0x0b, 0xab, 0x6a, 0x00, 0x27, 0xce, 0x17, 0xe2, 0xb7, 0x05, 0x1d, 0x99, 0xef, 0x43, 0x9b, - 0xf2, 0x7a, 0xa1, 0x7d, 0x52, 0x93, 0xc3, 0x20, 0x3a, 0xc8, 0x95, 0x0c, 0x72, 0x62, 0x7e, 0x44, 0x92, 0x53, 0x74, - 0xd1, 0xee, 0x25, 0xa7, 0x87, 0xfc, 0x90, 0xa7, 0xc0, 0xc3, 0xc6, 0x4d, 0x5f, 0xa1, 0xd9, 0xf6, 0x75, 0x1e, 0x2f, - 0x86, 0x3c, 0x73, 0xcd, 0x57, 0x1d, 0x94, 0xa9, 0x76, 0x8e, 0x90, 0x05, 0x28, 0xe6, 0x7b, 0x09, 0xb2, 0xeb, 0xdd, - 0x1c, 0xf2, 0x14, 0xfa, 0x81, 0x5a, 0x1d, 0x5b, 0xab, 0x1c, 0xdc, 0x6f, 0x0b, 0x40, 0x30, 0xdf, 0x51, 0x6d, 0x2e, - 0x36, 0xbd, 0x19, 0x57, 0x9d, 0x1d, 0xf2, 0x6a, 0x84, 0x61, 0x99, 0xed, 0xfe, 0xfc, 0xd4, 0xaa, 0x2e, 0x0f, 0x03, - 0x88, 0xfc, 0xb6, 0xe0, 0x22, 0xec, 0x34, 0xec, 0xd6, 0xe5, 0x84, 0x9d, 0xd6, 0x67, 0x19, 0x14, 0xd9, 0xee, 0x75, - 0x6b, 0xa6, 0xf5, 0xd9, 0x5e, 0x81, 0x8f, 0x20, 0x4c, 0xca, 0xac, 0x74, 0x06, 0x57, 0xe8, 0x87, 0x1f, 0x90, 0x6b, - 0xfd, 0xf5, 0x42, 0xfb, 0xfc, 0x12, 0x11, 0x20, 0xbb, 0xea, 0xba, 0xac, 0x0e, 0x7d, 0x94, 0x4d, 0x7c, 0x3d, 0xe4, - 0xc1, 0xca, 0x3d, 0xbd, 0x9d, 0xcb, 0xd4, 0xe3, 0x6b, 0xaf, 0x95, 0x6e, 0x21, 0x27, 0x10, 0x0f, 0xd7, 0x5d, 0x58, - 0x16, 0xe4, 0xec, 0xe6, 0x16, 0x4a, 0x86, 0x13, 0xf7, 0xa5, 0x3f, 0x30, 0x7b, 0xdd, 0xc0, 0x2f, 0x92, 0x53, 0x98, - 0xfa, 0x66, 0x0f, 0x87, 0x1d, 0xe8, 0xc3, 0xc0, 0x61, 0xb3, 0x41, 0x9f, 0x59, 0x41, 0xe4, 0x31, 0x2f, 0x2c, 0x9e, - 0x5d, 0x92, 0x76, 0x8f, 0xa7, 0x6e, 0x33, 0x19, 0xd1, 0xa8, 0xdd, 0xe4, 0xc1, 0xcc, 0x00, 0xbf, 0x5c, 0xd9, 0xb0, - 0x88, 0x5f, 0xa7, 0x00, 0x4a, 0xbe, 0x58, 0xb5, 0x3e, 0x15, 0xbc, 0xea, 0x0d, 0xa7, 0x9b, 0xe9, 0x7e, 0xdd, 0xe0, - 0x76, 0xd7, 0xc3, 0x13, 0x9e, 0x40, 0xb1, 0x68, 0xed, 0x27, 0x3e, 0x01, 0x0e, 0x28, 0x69, 0xdd, 0x3f, 0x05, 0x17, - 0xca, 0x12, 0x96, 0xdb, 0xe5, 0x66, 0x5b, 0xe5, 0x2c, 0x1c, 0x6d, 0xc9, 0x80, 0x3b, 0xd8, 0x84, 0x28, 0x74, 0x70, - 0xd8, 0xc1, 0x49, 0xbb, 0xdd, 0x39, 0xc5, 0xc9, 0xc9, 0x29, 0x0c, 0xb4, 0x91, 0x9c, 0x1e, 0xce, 0x94, 0x05, 0x60, - 0x90, 0xb3, 0x76, 0xed, 0x3e, 0x82, 0x70, 0x49, 0xa1, 0x78, 0xcd, 0x0f, 0xe3, 0xb8, 0x9d, 0xdc, 0x6f, 0xb5, 0x4f, - 0xcf, 0x1b, 0x00, 0xa0, 0xa6, 0xfb, 0x70, 0x35, 0x5e, 0x2f, 0x74, 0xbd, 0x4a, 0x89, 0xf0, 0xf5, 0x6a, 0x0d, 0x5f, - 0xad, 0xd1, 0x5e, 0x57, 0x53, 0xf0, 0x55, 0x9d, 0x70, 0x6e, 0x8b, 0x78, 0xa5, 0x4d, 0xb8, 0x2d, 0x62, 0x3b, 0x90, - 0x18, 0xa4, 0xf3, 0xe4, 0xb4, 0x73, 0x8a, 0xec, 0x58, 0xb4, 0xc3, 0x8f, 0x72, 0x9f, 0x6c, 0x15, 0x69, 0x68, 0x40, - 0x92, 0x72, 0x76, 0x72, 0x01, 0x12, 0x35, 0x27, 0x97, 0xed, 0xe6, 0x8c, 0x25, 0x7e, 0x02, 0x26, 0x15, 0x96, 0xb3, - 0x5c, 0x05, 0x97, 0x14, 0x00, 0xe2, 0x02, 0x8c, 0x8b, 0xee, 0x9f, 0xf6, 0xee, 0x27, 0xa7, 0x67, 0x1d, 0x4b, 0xf4, - 0xf8, 0x45, 0xa7, 0x96, 0x66, 0xa6, 0x9e, 0x9c, 0x9a, 0x34, 0xe8, 0x3a, 0xb9, 0x7f, 0x0a, 0x65, 0x5c, 0x4a, 0x58, - 0x0a, 0xc2, 0x3c, 0x54, 0xc5, 0x20, 0xb6, 0x43, 0x5a, 0xcb, 0x3d, 0xab, 0x65, 0x9f, 0x9f, 0x1c, 0xdf, 0x3f, 0x0d, - 0xa1, 0x56, 0xce, 0xc2, 0x2c, 0xb4, 0x9b, 0x88, 0x9f, 0x1d, 0x2c, 0x2d, 0x3a, 0x4c, 0x4e, 0xd3, 0xad, 0x09, 0xda, - 0x4d, 0x73, 0x68, 0x70, 0x20, 0x50, 0x38, 0x3e, 0x15, 0x4e, 0x5f, 0x12, 0xdc, 0x8f, 0x55, 0x86, 0x26, 0xa1, 0xc2, - 0xd9, 0xdf, 0x53, 0x06, 0x2f, 0x39, 0x86, 0x57, 0x95, 0x8f, 0xa9, 0xf8, 0x42, 0xd5, 0x1b, 0x0a, 0xb1, 0x2b, 0xc4, - 0x20, 0x72, 0x91, 0xb5, 0xeb, 0xb9, 0x3f, 0x81, 0x8b, 0x30, 0x13, 0x70, 0xa1, 0xe9, 0x95, 0xa0, 0x15, 0x2f, 0x30, - 0x0c, 0x1d, 0x6a, 0xcd, 0xb0, 0x7a, 0x3c, 0x75, 0x26, 0x05, 0xa1, 0x6e, 0xeb, 0x39, 0xff, 0x5e, 0xb9, 0xa4, 0xbc, - 0xca, 0x4e, 0x4e, 0x51, 0xe2, 0x2e, 0xcb, 0x93, 0x36, 0x4a, 0x02, 0x13, 0x12, 0x77, 0x24, 0x67, 0x19, 0xe9, 0x47, - 0xb7, 0x11, 0x8e, 0xee, 0x22, 0x1c, 0x59, 0x1f, 0xe6, 0x0f, 0xe0, 0x3c, 0x1f, 0xe1, 0xc8, 0xba, 0x32, 0x47, 0x38, - 0xd2, 0x4c, 0x40, 0x48, 0xab, 0x68, 0x80, 0x73, 0x28, 0x6d, 0x3c, 0xab, 0xcb, 0xd2, 0x8f, 0xfd, 0x57, 0xe9, 0x7a, - 0x6d, 0x53, 0x02, 0x29, 0x73, 0x6a, 0x76, 0xa8, 0x7d, 0x92, 0x39, 0xa2, 0x9e, 0x59, 0x8f, 0x30, 0x08, 0x20, 0xf4, - 0xce, 0x3f, 0xe9, 0x56, 0x45, 0xc3, 0x60, 0xc7, 0xb0, 0xd2, 0xe0, 0x67, 0x1e, 0x85, 0x67, 0x58, 0x84, 0xc7, 0xc2, - 0x17, 0x06, 0xb1, 0xc2, 0xff, 0xce, 0xa5, 0x9c, 0xfb, 0xdf, 0x5a, 0x96, 0xbf, 0xe0, 0x21, 0x10, 0x67, 0xd1, 0x02, - 0x96, 0x5b, 0x36, 0xf8, 0xce, 0x90, 0xd5, 0x47, 0x70, 0x3d, 0x76, 0x01, 0xd2, 0x40, 0x22, 0xbc, 0x36, 0x02, 0x95, - 0x97, 0x0f, 0xaf, 0x6d, 0xb0, 0x1e, 0xf3, 0x09, 0xd1, 0xba, 0x20, 0x20, 0xaf, 0x84, 0x0b, 0x8d, 0x49, 0xc1, 0x94, - 0x8a, 0x6c, 0x14, 0xbb, 0x48, 0x0a, 0xff, 0x2c, 0xa1, 0x4f, 0x19, 0x8b, 0xc8, 0x74, 0x58, 0x9f, 0xad, 0x15, 0x87, - 0x73, 0x59, 0xa8, 0xd4, 0xbe, 0x51, 0xe2, 0xc1, 0x58, 0x3d, 0x55, 0x9f, 0xe6, 0xd9, 0x1a, 0xdb, 0x3b, 0xec, 0xb2, - 0x90, 0xbb, 0xd2, 0x0e, 0x4b, 0x65, 0xd9, 0xfa, 0x5b, 0x13, 0x52, 0xb5, 0x19, 0x05, 0x13, 0xad, 0x06, 0x54, 0x85, - 0xb2, 0x80, 0xc2, 0x36, 0x1c, 0x4a, 0xba, 0x2c, 0x4b, 0xa6, 0xcb, 0x72, 0x19, 0x4e, 0x5a, 0xad, 0xf5, 0x1a, 0x17, - 0xcc, 0x84, 0x65, 0xd9, 0x59, 0x02, 0xf2, 0xd5, 0x54, 0xde, 0x04, 0xb9, 0x2a, 0x2d, 0x67, 0x69, 0x96, 0x28, 0x0a, - 0x8c, 0x60, 0xa3, 0x35, 0xfe, 0xc2, 0x15, 0x07, 0x78, 0xba, 0xd9, 0x0d, 0xa5, 0xcc, 0x19, 0x85, 0xe8, 0x5d, 0x41, - 0x93, 0x6b, 0x3c, 0xe5, 0x23, 0xb6, 0xbb, 0x4d, 0x30, 0x63, 0xfe, 0xf7, 0x5a, 0xf4, 0x08, 0x64, 0xd9, 0x3d, 0x83, - 0x3a, 0xb0, 0x88, 0x2b, 0xe8, 0x20, 0x94, 0xc1, 0x47, 0x21, 0x6e, 0xe6, 0xf4, 0x4e, 0x2e, 0x34, 0xc0, 0x65, 0xa1, - 0xe5, 0x1b, 0x17, 0xeb, 0x60, 0xbf, 0x85, 0x7d, 0xd8, 0x83, 0x25, 0x84, 0x0c, 0x68, 0x61, 0x1b, 0x23, 0xa2, 0x85, - 0x87, 0x52, 0x6b, 0x39, 0x4b, 0x5b, 0xd8, 0x04, 0x6c, 0x68, 0xad, 0xcb, 0xa8, 0x5a, 0xd7, 0xe5, 0x63, 0x8e, 0xd5, - 0x26, 0x58, 0x38, 0xe9, 0x50, 0x13, 0x1d, 0xdc, 0x1e, 0x32, 0xc2, 0x1b, 0x3f, 0x5f, 0xbd, 0x7e, 0xe5, 0x62, 0x26, - 0xf3, 0x31, 0xb8, 0x6c, 0x3a, 0xd5, 0xd8, 0xb5, 0x79, 0x05, 0x29, 0xae, 0x14, 0xa5, 0x56, 0x38, 0x85, 0x96, 0x5f, - 0x08, 0x9d, 0x27, 0xf6, 0xf2, 0xe2, 0x99, 0x2c, 0x66, 0xd4, 0xde, 0x18, 0xe1, 0x6b, 0xe5, 0x9e, 0x3d, 0x37, 0x2f, - 0xab, 0x54, 0x93, 0x7c, 0xb7, 0x79, 0x15, 0xb1, 0xc8, 0x8c, 0xfc, 0x0a, 0xda, 0x00, 0x53, 0xb9, 0x7c, 0xb5, 0xb6, - 0x20, 0x2e, 0xf2, 0x7c, 0x40, 0x5e, 0xde, 0x5a, 0xea, 0x12, 0x45, 0x0d, 0x6e, 0xf0, 0x93, 0x15, 0x3c, 0x0b, 0xae, - 0x0b, 0x0d, 0x7b, 0xe4, 0xc4, 0x8b, 0xa8, 0x15, 0xd5, 0x5f, 0x7d, 0x35, 0xaa, 0x04, 0x1f, 0xb5, 0x34, 0xc9, 0x25, - 0x88, 0x1e, 0xe5, 0x03, 0x73, 0x1c, 0x44, 0x13, 0x7f, 0xf7, 0x7c, 0xd9, 0xf6, 0x74, 0x36, 0xaf, 0xd4, 0x89, 0xe5, - 0x95, 0x09, 0x78, 0x38, 0xda, 0x27, 0x5c, 0x10, 0x0e, 0x12, 0x59, 0xa9, 0x3d, 0xf4, 0xb9, 0xa8, 0x1b, 0xe7, 0x17, - 0x6d, 0xd6, 0x3c, 0x59, 0xad, 0xf2, 0xcb, 0x36, 0x6b, 0x9f, 0xda, 0x07, 0xdf, 0x22, 0x95, 0x01, 0xcd, 0xe5, 0x63, - 0x9e, 0x45, 0xa0, 0x9d, 0x1d, 0x67, 0x26, 0x9c, 0x82, 0x0f, 0x51, 0x4c, 0x16, 0xba, 0xea, 0x4b, 0x82, 0x71, 0x29, - 0xb1, 0x7a, 0xfc, 0x02, 0xf5, 0xda, 0xe9, 0xb6, 0xab, 0x74, 0xb3, 0x7d, 0x18, 0x5c, 0xb8, 0x14, 0x08, 0x77, 0x20, - 0xe4, 0x01, 0xe8, 0x77, 0x97, 0x02, 0x4c, 0x83, 0x00, 0x95, 0x15, 0x88, 0xb4, 0x7c, 0xb6, 0x98, 0x3d, 0x2b, 0xa8, - 0x59, 0x86, 0x27, 0x7c, 0xc2, 0xb5, 0x4a, 0x29, 0x48, 0xb7, 0xbb, 0xd2, 0xd7, 0xbb, 0x25, 0xa8, 0xac, 0x16, 0xf9, - 0x35, 0xd1, 0x3c, 0xfb, 0xac, 0xdc, 0xc2, 0x21, 0x6c, 0x56, 0x56, 0xe0, 0x0c, 0xad, 0x71, 0x2e, 0x27, 0xb4, 0xe0, - 0x7a, 0x3a, 0xfb, 0xb7, 0x56, 0x87, 0xf5, 0xf5, 0xc0, 0x5c, 0x58, 0x01, 0x48, 0xa8, 0x18, 0xad, 0x56, 0xfc, 0xe8, - 0xfb, 0xf7, 0x49, 0xde, 0x27, 0xbc, 0x8d, 0x3b, 0xf8, 0x18, 0x9f, 0xe2, 0x76, 0x0b, 0xb7, 0x4f, 0xe1, 0xea, 0x3e, - 0xcb, 0x17, 0x23, 0xa6, 0x62, 0x78, 0xf9, 0x4b, 0x5f, 0x26, 0xe7, 0x87, 0x65, 0xbc, 0x7b, 0x5d, 0x24, 0x0e, 0x5d, - 0x82, 0xb0, 0xeb, 0x2e, 0x5e, 0x5d, 0x14, 0x85, 0xc1, 0xd2, 0xc6, 0xa1, 0xea, 0xa4, 0xd4, 0x2f, 0x5c, 0x1e, 0xf7, - 0xc0, 0x9e, 0xdb, 0xae, 0x6c, 0x13, 0xcc, 0xbe, 0xed, 0xcf, 0xb4, 0xfa, 0xd9, 0xd4, 0x25, 0x62, 0x78, 0xe8, 0x55, - 0xe8, 0x81, 0x2e, 0x49, 0xfb, 0xe0, 0x00, 0xac, 0x8e, 0x82, 0xd9, 0x70, 0x1b, 0xfd, 0x80, 0x37, 0x6b, 0x69, 0x10, - 0xac, 0x00, 0x8c, 0x3b, 0xdf, 0x70, 0xb2, 0xb4, 0xb0, 0xd5, 0x40, 0x85, 0x75, 0x11, 0x46, 0x74, 0x0b, 0x49, 0x85, - 0x11, 0xa2, 0xe1, 0x08, 0x73, 0x91, 0x4e, 0xf6, 0x5b, 0x58, 0x8e, 0xc7, 0x8a, 0x69, 0x38, 0x3a, 0x0a, 0xf6, 0x85, - 0x15, 0xca, 0x9c, 0x22, 0x43, 0x36, 0xe1, 0xe2, 0xa1, 0xfe, 0xc4, 0x0a, 0x69, 0x3e, 0x8d, 0x06, 0x23, 0x8d, 0xcc, - 0x2a, 0x46, 0x38, 0xcb, 0xf9, 0x1c, 0xaa, 0x4e, 0x0a, 0x70, 0xfa, 0x81, 0xbf, 0x7c, 0x94, 0x86, 0x6d, 0x02, 0xf9, - 0xfa, 0x60, 0x83, 0xd9, 0xe0, 0x51, 0x41, 0x6f, 0x5e, 0x8b, 0xc7, 0xb0, 0xa3, 0x1e, 0x16, 0x8c, 0x42, 0x36, 0x24, - 0xbd, 0x83, 0xa6, 0xe0, 0x03, 0xda, 0x7c, 0x69, 0x00, 0x97, 0x9e, 0x9b, 0x0f, 0x5b, 0xd1, 0x47, 0x0d, 0x4c, 0xca, - 0xb6, 0x4c, 0xa6, 0x39, 0xa5, 0xab, 0x4c, 0x1b, 0x97, 0xa9, 0x9c, 0xc2, 0x1a, 0xbb, 0xa8, 0x27, 0xe1, 0x60, 0x46, - 0x54, 0x4d, 0xd3, 0xfe, 0xc0, 0xfc, 0x7d, 0x6d, 0x4b, 0xb6, 0xb0, 0x0b, 0xb5, 0xb3, 0xc6, 0xe6, 0xc9, 0xce, 0xa0, - 0x7c, 0x1b, 0xc3, 0x3d, 0x2c, 0xbc, 0x1b, 0x59, 0x23, 0x9f, 0x27, 0x9e, 0x6c, 0x9e, 0xac, 0xd7, 0x66, 0x20, 0x2a, - 0x05, 0x3d, 0xd0, 0x5b, 0xbf, 0x6d, 0x5a, 0xb0, 0x3d, 0xca, 0xaf, 0xd3, 0x16, 0x9e, 0x71, 0x78, 0x06, 0xd3, 0xb7, - 0x77, 0xa5, 0x0b, 0xf9, 0xd9, 0x81, 0xa4, 0x15, 0xa4, 0xd8, 0xe9, 0x04, 0x9d, 0x1d, 0xe3, 0x60, 0xe4, 0x40, 0xcf, - 0xaf, 0x3e, 0x5b, 0x58, 0xfb, 0xdf, 0x6f, 0xca, 0x82, 0x39, 0x1d, 0xb2, 0xbc, 0x9c, 0x50, 0xe6, 0xcf, 0xcf, 0x37, - 0x3c, 0xa9, 0x50, 0xc1, 0xbd, 0x1f, 0x05, 0x7b, 0xda, 0x86, 0x98, 0x9c, 0xd1, 0xbf, 0xed, 0x0f, 0x1b, 0x11, 0xa8, - 0xd4, 0xb2, 0x65, 0x85, 0x54, 0xea, 0xa1, 0x4d, 0xb3, 0x47, 0x0f, 0x1c, 0x91, 0x2f, 0xa1, 0x0b, 0xe0, 0xf5, 0x47, - 0x85, 0x9c, 0x1b, 0x44, 0x70, 0xbf, 0xdd, 0xb8, 0x8d, 0xaf, 0x00, 0x78, 0x3b, 0xec, 0x55, 0xff, 0xb4, 0x80, 0xfd, - 0x8d, 0xca, 0x92, 0x7e, 0xbc, 0x1d, 0x7b, 0xfc, 0x17, 0x12, 0xe2, 0x95, 0x5b, 0x3c, 0x4c, 0x1c, 0x3a, 0x95, 0xac, - 0x59, 0xf9, 0x73, 0xab, 0x24, 0x60, 0x58, 0xbd, 0x60, 0xc8, 0xc6, 0x6d, 0x15, 0xb7, 0x99, 0xff, 0x41, 0x05, 0x83, - 0x05, 0xdf, 0x1a, 0x49, 0xc5, 0xb2, 0xf8, 0xed, 0x53, 0xe7, 0xbf, 0xea, 0x1c, 0xd7, 0xbe, 0xae, 0xbd, 0x51, 0x39, - 0x34, 0xf1, 0x81, 0x23, 0x74, 0x70, 0xb0, 0x91, 0x41, 0xc7, 0x00, 0x78, 0xe4, 0xd8, 0x2f, 0xbf, 0x7c, 0x9e, 0x1d, - 0x33, 0x9a, 0xc7, 0x22, 0x0a, 0x99, 0x3b, 0xcf, 0xcd, 0xd9, 0x89, 0x3c, 0xa1, 0x6a, 0xea, 0x0b, 0x03, 0x1c, 0x1f, - 0x6d, 0xa5, 0x02, 0xbe, 0x47, 0xeb, 0x1d, 0x13, 0xd8, 0xe0, 0xb7, 0xec, 0xa4, 0x76, 0x15, 0xf4, 0x0b, 0xb4, 0xdc, - 0xc5, 0x54, 0x6e, 0x2c, 0x70, 0xb4, 0x39, 0x91, 0x9d, 0x43, 0xdf, 0xa8, 0x53, 0xb2, 0x1e, 0x4f, 0x76, 0x1b, 0x7d, - 0x49, 0xb1, 0x2b, 0xb9, 0xa2, 0x6d, 0x43, 0x56, 0xbd, 0x53, 0xab, 0x2b, 0x53, 0xa7, 0xea, 0x9a, 0xb7, 0xb2, 0xb4, - 0x29, 0xed, 0x92, 0xec, 0xdd, 0x16, 0x0b, 0xaf, 0xc2, 0x1b, 0x8d, 0xf2, 0x22, 0x14, 0xec, 0xb1, 0xc4, 0xa0, 0xcb, - 0x09, 0x5c, 0x2f, 0xac, 0x56, 0x31, 0xfc, 0xd9, 0x35, 0x86, 0x5d, 0xa6, 0x4b, 0x1f, 0xf8, 0x06, 0xbf, 0x12, 0x84, - 0xca, 0x75, 0x76, 0x90, 0x60, 0xdd, 0xe5, 0x06, 0x0d, 0xc7, 0x89, 0xff, 0x82, 0x87, 0x9a, 0xb5, 0x77, 0x39, 0x98, - 0x64, 0xdf, 0x78, 0xdc, 0xad, 0x64, 0x2d, 0x6b, 0x71, 0xd6, 0x37, 0x24, 0x18, 0x62, 0x37, 0xa5, 0x73, 0xdc, 0x4a, - 0xda, 0x28, 0x72, 0xc5, 0x2a, 0xf4, 0xff, 0x56, 0x91, 0xcc, 0x66, 0xfe, 0xd7, 0xd9, 0xd9, 0x99, 0x4b, 0x71, 0x36, - 0x7f, 0xca, 0x78, 0xc0, 0x99, 0x04, 0xf6, 0x85, 0x67, 0xcc, 0xe8, 0x90, 0xdf, 0xc2, 0x50, 0x88, 0x20, 0x97, 0xc2, - 0xb1, 0x4b, 0xf0, 0xce, 0x20, 0x50, 0x1e, 0x60, 0xff, 0x9e, 0x6c, 0x94, 0xf3, 0x0f, 0x15, 0xf9, 0x40, 0xbe, 0x65, - 0x83, 0xec, 0x8b, 0xf9, 0xec, 0x5b, 0x33, 0x19, 0x88, 0xcd, 0x1f, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, - 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, 0x0f, 0x53, 0xd6, 0x3d, 0x72, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0xc5, - 0xa3, 0x8c, 0x7e, 0x2c, 0x43, 0x4f, 0xee, 0xbd, 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, - 0x69, 0xfe, 0x23, 0xde, 0xab, 0x42, 0x50, 0x82, 0x2b, 0xa4, 0x89, 0xe2, 0x88, 0xcd, 0x83, 0xce, 0x69, 0x24, 0x80, - 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0xa8, 0x85, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0x16, 0xa9, 0x0d, 0xe1, - 0x0d, 0x91, 0xdc, 0xca, 0xd9, 0x98, 0xaf, 0x47, 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, - 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, - 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, 0x93, 0xdb, 0x60, 0xaa, 0x7f, 0x82, 0x1d, 0x08, 0x3d, 0x53, 0x3a, - 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, - 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, - 0xcc, 0x63, 0xd2, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, - 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, 0xde, 0x72, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, - 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, 0xcc, 0xc5, 0xc3, 0xf0, 0xd1, 0x77, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, - 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0x32, 0xdd, 0xd9, 0x0d, 0xa3, 0xb5, 0x79, 0x6e, 0x29, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, - 0x04, 0xd9, 0xda, 0x3c, 0xd8, 0x54, 0x66, 0x0d, 0x59, 0xf9, 0x3a, 0x41, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, - 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, - 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x22, 0xd7, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, - 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, 0x53, 0x70, 0xed, 0x43, 0xe4, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, - 0x18, 0x5d, 0x1b, 0xc8, 0xd7, 0x9b, 0x73, 0x9a, 0xb8, 0xb3, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, - 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, - 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x03, - 0x51, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, - 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, - 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, - 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, - 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0xa7, 0x1a, 0x35, 0x62, 0x9e, - 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, - 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, - 0xaa, 0x16, 0x85, 0x79, 0xba, 0x2d, 0x56, 0x28, 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0x52, 0x9a, 0x04, 0xc3, - 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, - 0x71, 0x38, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, - 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, 0xec, 0x9e, 0xae, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, - 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0xd7, 0xb5, 0xb8, 0x4b, 0x72, 0x0f, 0x64, 0x54, 0x6f, 0x60, 0xd7, 0x2c, 0xc0, - 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, 0x69, 0x9e, 0x52, 0xa2, 0xe6, 0x05, 0x25, 0x78, 0xb8, 0x99, 0xb0, - 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x68, 0x7b, 0xff, 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, - 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, - 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x67, 0x36, 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x0f, 0x6a, - 0x54, 0x0f, 0x9a, 0xfb, 0xe7, 0x9d, 0x8e, 0x3a, 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, - 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x9e, - 0xe0, 0xa8, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, 0xe6, 0xfe, 0x65, 0xcf, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, - 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, - 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, - 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, 0x5e, 0xdd, 0x01, 0x2b, 0x01, 0x1f, 0xfd, 0xd8, 0x24, 0x19, 0x43, - 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, - 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, - 0x20, 0x7e, 0x29, 0x74, 0x62, 0x22, 0x45, 0x5f, 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, - 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0x63, 0xc8, 0xe3, 0x52, - 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x71, 0xba, 0x5f, - 0x40, 0xd4, 0x66, 0x77, 0x2c, 0x81, 0x9e, 0x7d, 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, - 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0xde, 0x53, 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, - 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, - 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, - 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, - 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, 0x6c, 0x28, 0x5b, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, - 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, - 0x6d, 0xcb, 0x21, 0x18, 0x76, 0xa4, 0x0b, 0x6e, 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, - 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, - 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xd0, - 0xe5, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, - 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, - 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, - 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, - 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, - 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, - 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, - 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, - 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, - 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, - 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, - 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, - 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, - 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0xdf, - 0xe6, 0x84, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, - 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, - 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, - 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, - 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, - 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, - 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, 0xa9, 0x3e, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, - 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, - 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, - 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, - 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, - 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, - 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, - 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0xef, 0x6a, 0x01, 0x97, - 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, - 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x0b, 0xb3, 0x9f, - 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, - 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, - 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, - 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, - 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, - 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, - 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, - 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, - 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, 0x9a, 0xce, 0x3c, 0x8a, 0x5c, 0x7b, 0xef, 0x77, 0x53, 0xb4, 0xf5, - 0xaf, 0x0f, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, - 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, - 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, - 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, - 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, - 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, - 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, - 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, - 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, - 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, - 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, - 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, - 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0x3d, 0x45, 0xb7, 0x72, 0xef, 0xf4, - 0xac, 0xcc, 0xeb, 0x4a, 0xab, 0x58, 0x0e, 0x73, 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, - 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, - 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, - 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, - 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, - 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, - 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, 0x89, 0x17, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, - 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, - 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, - 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, - 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, - 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, - 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, - 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, - 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, 0xbd, 0xbb, 0xe1, 0xbb, 0x70, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, - 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0x3c, 0x15, 0x19, - 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, - 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, - 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, 0x67, 0xf7, 0x2e, 0x61, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, - 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, - 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, - 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, - 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, - 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, 0x55, 0x31, 0xdd, 0x0f, 0xdf, 0xd3, 0x0b, 0x3e, 0xbc, 0x43, 0xda, - 0xc6, 0xa3, 0x96, 0x94, 0x50, 0xbb, 0x83, 0xf6, 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, - 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, 0xca, 0x28, 0x18, 0xc2, 0x3e, 0x60, 0x1f, 0x8b, 0x24, 0xa3, 0xd9, - 0x94, 0x81, 0xba, 0xdf, 0x16, 0xad, 0xe6, 0xf6, 0xa4, 0xee, 0x37, 0x64, 0x9c, 0x7d, 0x84, 0x71, 0xf6, 0x51, 0xe0, - 0xc5, 0x22, 0xc9, 0x1f, 0x32, 0xd6, 0x38, 0x56, 0x4d, 0x81, 0x8e, 0x3a, 0xc0, 0x9d, 0x81, 0x03, 0x0f, 0xd8, 0xa2, - 0x1c, 0x1c, 0x50, 0x67, 0x71, 0x4f, 0x1b, 0x99, 0xf7, 0xf6, 0x84, 0xda, 0x45, 0x2c, 0x70, 0xb3, 0x66, 0xa6, 0x05, - 0xad, 0x15, 0xc6, 0x79, 0x3c, 0xe0, 0x6d, 0x9e, 0xd5, 0xe2, 0x27, 0x6c, 0x58, 0x53, 0xd5, 0x6f, 0xa0, 0x39, 0xaa, - 0x05, 0xb9, 0x79, 0x62, 0xbc, 0x55, 0x49, 0x3f, 0x8a, 0x06, 0x96, 0x53, 0x21, 0x86, 0x64, 0xf4, 0x5b, 0x83, 0xe0, - 0x56, 0x7b, 0xb5, 0xe2, 0x1e, 0xf1, 0x45, 0xcd, 0x5b, 0xcd, 0xdc, 0x02, 0xd0, 0x22, 0x8e, 0xca, 0x7b, 0x93, 0x08, - 0xbc, 0x6f, 0xcb, 0x08, 0x69, 0xcb, 0xbe, 0x7d, 0x34, 0xb1, 0x54, 0x6c, 0xbe, 0xa3, 0x93, 0x41, 0x1a, 0xd9, 0x11, - 0x45, 0xf8, 0xba, 0x84, 0x24, 0x5c, 0x25, 0x5d, 0xab, 0x4c, 0xce, 0x99, 0x4a, 0x39, 0xbe, 0x2e, 0xa4, 0xd4, 0x57, - 0xf6, 0x4b, 0xe2, 0xea, 0x4e, 0x46, 0xe0, 0xeb, 0x09, 0xd3, 0xef, 0x68, 0x31, 0x61, 0xe0, 0x57, 0xe4, 0x6f, 0xc7, - 0x52, 0x4a, 0x2e, 0x9f, 0x88, 0xb8, 0x4f, 0x31, 0xbc, 0xf8, 0x39, 0xc0, 0xda, 0x84, 0x40, 0x29, 0x71, 0x11, 0x2e, - 0x88, 0xde, 0x14, 0xf2, 0xf6, 0x2e, 0x2e, 0xb0, 0x73, 0x00, 0x2c, 0x9d, 0x26, 0x01, 0xfe, 0xe5, 0x63, 0x3e, 0x56, - 0x63, 0x4e, 0x8d, 0xae, 0xdf, 0xfd, 0x4e, 0xae, 0x81, 0xde, 0x96, 0x8e, 0x82, 0xfd, 0xd6, 0x00, 0x72, 0xe1, 0x2e, - 0x0c, 0x2e, 0xbe, 0xc2, 0xda, 0xb2, 0x30, 0xde, 0x58, 0x00, 0xbd, 0xbf, 0x33, 0xb0, 0x60, 0xc3, 0x1c, 0x53, 0x78, - 0x2e, 0x75, 0xc2, 0x74, 0x10, 0x15, 0xe4, 0x49, 0xf9, 0x20, 0x66, 0xad, 0xf6, 0x5b, 0x36, 0x86, 0x3b, 0x8c, 0xe4, - 0xdb, 0x85, 0x13, 0x07, 0x1e, 0x90, 0x69, 0x32, 0xdb, 0xec, 0x1b, 0x1f, 0x79, 0xe4, 0xf5, 0x38, 0xde, 0xd5, 0x52, - 0x98, 0x6f, 0x56, 0x74, 0x8d, 0x21, 0x14, 0x45, 0xd8, 0xef, 0x17, 0x15, 0x53, 0x54, 0x19, 0xb4, 0x41, 0xc3, 0xf2, - 0x46, 0xfc, 0x02, 0x67, 0x0c, 0xad, 0x17, 0xb2, 0x77, 0x74, 0xd6, 0xe1, 0xcc, 0x61, 0xc6, 0x94, 0xc0, 0xa8, 0xb4, - 0x2c, 0xe8, 0x04, 0x1c, 0x9d, 0xab, 0x0f, 0xa2, 0xe2, 0xea, 0x58, 0x01, 0x78, 0x92, 0x29, 0xfc, 0x93, 0x6f, 0x82, - 0x75, 0xbf, 0x55, 0x33, 0x4c, 0xfd, 0x45, 0x6f, 0xbb, 0x96, 0x2f, 0x43, 0x1c, 0x69, 0x63, 0x08, 0xad, 0x73, 0x7b, - 0x07, 0x28, 0xe2, 0x82, 0x5e, 0xa4, 0x1a, 0x5f, 0xab, 0xc5, 0xd0, 0xac, 0xaf, 0x71, 0x1d, 0xd3, 0x06, 0x51, 0xac, - 0xbb, 0x26, 0xbe, 0xae, 0xde, 0x1f, 0x55, 0xa9, 0x82, 0x33, 0x48, 0x20, 0xac, 0xca, 0xcb, 0x86, 0x54, 0x92, 0x4b, - 0xd3, 0xa9, 0x34, 0x9d, 0x56, 0x08, 0xe5, 0xd2, 0x93, 0xf2, 0xfe, 0x15, 0x42, 0x18, 0x98, 0x32, 0x3b, 0xb0, 0x4a, - 0x6d, 0x61, 0x15, 0xbc, 0x7a, 0xb1, 0x81, 0x55, 0x12, 0x8e, 0xe7, 0x12, 0x8d, 0x8a, 0x0a, 0x87, 0x0c, 0xe9, 0x0b, - 0xb1, 0x08, 0x12, 0x00, 0x8b, 0xde, 0x65, 0x2e, 0xef, 0x7b, 0x38, 0x14, 0xf6, 0x24, 0x93, 0x70, 0xba, 0x09, 0xcd, - 0xe1, 0x61, 0x5a, 0xd5, 0xf3, 0x08, 0x01, 0x4b, 0xcf, 0x31, 0x3c, 0x48, 0xfc, 0xfd, 0x87, 0x50, 0x9d, 0x05, 0x79, - 0xfa, 0x2f, 0x51, 0x12, 0x1a, 0xfb, 0xcf, 0xf1, 0xd0, 0x21, 0x61, 0x38, 0xf0, 0xcd, 0x11, 0x56, 0x38, 0xb8, 0x55, - 0xc4, 0x67, 0x70, 0x87, 0x8f, 0x75, 0xe8, 0x01, 0x60, 0x09, 0xc5, 0x21, 0xc8, 0x37, 0x50, 0xcc, 0xe0, 0x80, 0x26, - 0xcb, 0xf0, 0x02, 0x17, 0xac, 0x16, 0xca, 0xfb, 0xdb, 0x96, 0x97, 0xd2, 0x6a, 0x97, 0xbc, 0xc6, 0x1c, 0xa8, 0xfc, - 0x0c, 0x2f, 0x7c, 0x85, 0x79, 0x29, 0xd9, 0x7d, 0xe1, 0x6b, 0x07, 0xf4, 0x14, 0x02, 0x46, 0xba, 0xdf, 0x6b, 0xc2, - 0x3d, 0x45, 0x2f, 0x73, 0x71, 0xd8, 0x76, 0xd0, 0xbd, 0xc0, 0x5c, 0x5d, 0x55, 0x59, 0x73, 0x30, 0x85, 0x06, 0x07, - 0x55, 0x38, 0x23, 0x30, 0x57, 0x2f, 0xca, 0x82, 0x73, 0x10, 0xef, 0x7b, 0xc2, 0xe4, 0x94, 0xd1, 0x00, 0x5e, 0x64, - 0xe5, 0xa3, 0x53, 0x3d, 0x0e, 0x2e, 0xe3, 0x86, 0x4d, 0x7c, 0x21, 0x7c, 0x2a, 0xb0, 0x92, 0xd6, 0x38, 0x34, 0xa2, - 0x23, 0x3a, 0x07, 0xb3, 0x0d, 0xa0, 0xe0, 0xee, 0x7c, 0xd8, 0x58, 0xa8, 0xe0, 0x31, 0xd8, 0xda, 0xdb, 0xcd, 0x84, - 0x38, 0x93, 0xa6, 0xe0, 0x6e, 0xdb, 0x20, 0x83, 0x37, 0xbf, 0xfd, 0xb7, 0xc2, 0x22, 0xc1, 0x80, 0x4a, 0x4d, 0x12, - 0x84, 0x27, 0x28, 0x8d, 0x74, 0x2b, 0x37, 0x13, 0x48, 0x27, 0xa2, 0x66, 0xd4, 0xbd, 0x71, 0xbe, 0x3a, 0x6a, 0x20, - 0x2a, 0x6a, 0xa0, 0x02, 0x6a, 0x20, 0xeb, 0xdb, 0xbf, 0x80, 0x85, 0xb0, 0x11, 0xaa, 0x44, 0x10, 0x10, 0x61, 0xae, - 0x0d, 0x1f, 0x50, 0x24, 0x21, 0xe4, 0x0d, 0xa0, 0x62, 0x4a, 0x5e, 0x82, 0xd1, 0x38, 0xbc, 0xde, 0x03, 0xee, 0x97, - 0x96, 0x61, 0xf0, 0x9c, 0x82, 0xc9, 0x7f, 0xeb, 0xf3, 0xa1, 0x7a, 0xb9, 0x3a, 0x08, 0xe1, 0x17, 0x10, 0x2b, 0xc2, - 0xf1, 0x17, 0xbf, 0x00, 0xd9, 0x54, 0x58, 0x1e, 0x1c, 0x48, 0x10, 0xf8, 0x21, 0x8a, 0x70, 0xc0, 0x33, 0xbc, 0xcc, - 0x36, 0x88, 0x9e, 0x9f, 0x95, 0xaa, 0x66, 0x25, 0x83, 0x59, 0x15, 0x9e, 0xc6, 0xd1, 0x35, 0x61, 0x20, 0xb8, 0x50, - 0xbb, 0x6f, 0x10, 0x02, 0x65, 0xcb, 0x8d, 0xa1, 0x4b, 0x4f, 0xc1, 0x7c, 0x34, 0x8e, 0xde, 0x32, 0x78, 0xd2, 0xd6, - 0x98, 0xfc, 0x33, 0x6d, 0x1e, 0xb8, 0x4f, 0xf7, 0xa2, 0x46, 0xe0, 0xa4, 0x4e, 0x51, 0xf2, 0xb7, 0xe4, 0x22, 0x8e, - 0x9a, 0x97, 0x11, 0x6a, 0xc0, 0xbf, 0x0d, 0x8e, 0xba, 0x34, 0xa1, 0xa3, 0x91, 0x0f, 0x7e, 0x93, 0x11, 0xb3, 0xc9, - 0x56, 0x2b, 0x51, 0x11, 0xf4, 0xc4, 0x6e, 0x30, 0x60, 0x25, 0x5e, 0x00, 0xfb, 0x60, 0x39, 0x58, 0xf2, 0x4e, 0xc4, - 0xca, 0x9f, 0x52, 0x18, 0xac, 0x9e, 0x33, 0x84, 0x70, 0x16, 0xc4, 0x6c, 0xfc, 0xcf, 0x67, 0x1a, 0xae, 0x9f, 0x9f, - 0xaf, 0x63, 0x44, 0xa4, 0x0f, 0x22, 0x57, 0x63, 0x47, 0x44, 0x10, 0xb6, 0x4c, 0xf7, 0x5d, 0x99, 0x1f, 0xbc, 0x75, - 0xf5, 0xc0, 0x86, 0x8b, 0x03, 0x03, 0x6a, 0x14, 0x18, 0xad, 0xe0, 0x9c, 0x94, 0x03, 0x07, 0x25, 0x84, 0x66, 0x45, - 0x3c, 0x25, 0x97, 0x10, 0x09, 0x2f, 0x43, 0x5d, 0x30, 0x2c, 0x08, 0x24, 0xa8, 0x29, 0x48, 0x50, 0x99, 0xaf, 0x3d, - 0x82, 0x59, 0xe7, 0x66, 0xb6, 0x53, 0xd4, 0x75, 0x41, 0x7e, 0x7e, 0xd1, 0xf1, 0x08, 0x58, 0xda, 0x83, 0x83, 0x02, - 0x22, 0x88, 0x01, 0x05, 0x2f, 0x25, 0xc0, 0x40, 0x03, 0x5e, 0x6c, 0x68, 0xc0, 0xe7, 0xda, 0x78, 0x1d, 0x18, 0x5b, - 0x9f, 0x32, 0xc8, 0xc5, 0xb3, 0x6a, 0x4f, 0x13, 0x42, 0xf6, 0x5b, 0x3d, 0x9d, 0x6e, 0x47, 0x48, 0xec, 0x7d, 0xd4, - 0x26, 0xd0, 0x98, 0x23, 0xdd, 0xd5, 0xc6, 0xfc, 0x5a, 0xd3, 0x23, 0x56, 0x93, 0x90, 0x2e, 0x48, 0x97, 0xe7, 0xd3, - 0x9e, 0xc1, 0x15, 0xab, 0x34, 0x72, 0x70, 0x01, 0xfa, 0x6c, 0x40, 0x80, 0x02, 0x95, 0xa6, 0x12, 0x45, 0x11, 0x17, - 0x49, 0xc9, 0x86, 0x61, 0x06, 0x61, 0x0a, 0xab, 0x95, 0xa0, 0x1b, 0x6b, 0x00, 0xbc, 0x33, 0xb3, 0x7f, 0x4a, 0x1f, - 0x6c, 0xba, 0xf6, 0xe6, 0x11, 0x40, 0x40, 0xf6, 0xdb, 0x25, 0xbb, 0x2e, 0x36, 0x2a, 0xb3, 0xb0, 0x96, 0xb1, 0x95, - 0xdb, 0xf6, 0x18, 0x7b, 0x27, 0xb6, 0xf9, 0x04, 0x08, 0x51, 0x5b, 0x32, 0x8d, 0x10, 0x21, 0xb1, 0x88, 0x75, 0x6d, - 0xc8, 0x46, 0x1b, 0xda, 0x37, 0x4f, 0xc2, 0x43, 0xec, 0x03, 0x50, 0xbc, 0x39, 0x2e, 0xc1, 0x21, 0xbc, 0xf0, 0x08, - 0x7f, 0x0b, 0x2c, 0x52, 0x81, 0x19, 0x96, 0xab, 0x15, 0xd4, 0xf3, 0x78, 0x9f, 0x6d, 0x06, 0x27, 0x95, 0x1b, 0x63, - 0x97, 0x76, 0xe2, 0x71, 0xd9, 0x84, 0xc4, 0x19, 0xf4, 0xeb, 0x2b, 0xa2, 0xde, 0x7e, 0x3b, 0x7d, 0xe2, 0xdf, 0x2b, - 0x73, 0x3b, 0x10, 0x1b, 0xd6, 0x1b, 0xac, 0x3e, 0x80, 0x96, 0xbf, 0xca, 0xfc, 0x43, 0x65, 0xc1, 0x4d, 0x82, 0xda, - 0x5c, 0xc4, 0x2e, 0xeb, 0x22, 0x46, 0x6a, 0x8b, 0xbb, 0x43, 0x88, 0x7f, 0xb5, 0x15, 0xc5, 0x80, 0x27, 0x15, 0xff, - 0x1c, 0xa3, 0x2e, 0x84, 0xa2, 0xb6, 0x1e, 0x36, 0x40, 0x69, 0x97, 0xeb, 0x4a, 0x8c, 0x0c, 0x09, 0xe4, 0x5b, 0x17, - 0x5e, 0xd0, 0x9c, 0x44, 0x0a, 0xe4, 0xe4, 0x20, 0x2a, 0x69, 0xb6, 0x21, 0xcc, 0x75, 0xb7, 0x70, 0xcc, 0x5c, 0x6d, - 0xd0, 0x22, 0x7e, 0x01, 0xec, 0x0c, 0x37, 0x92, 0xa5, 0x03, 0x9f, 0xaa, 0x81, 0xcf, 0xaf, 0xb9, 0xa1, 0x28, 0x0a, - 0xf5, 0xde, 0xd9, 0x47, 0xe6, 0xe0, 0x77, 0x1a, 0x88, 0x8f, 0xd4, 0xe9, 0x48, 0x36, 0x42, 0xad, 0x39, 0x3b, 0x5e, - 0xb6, 0x19, 0x61, 0x50, 0xd8, 0xe8, 0x7d, 0x15, 0xb2, 0x8a, 0x9d, 0x9d, 0x8a, 0x60, 0x4e, 0x5f, 0x54, 0xe5, 0x9c, - 0xca, 0x2d, 0xa3, 0x5a, 0x6a, 0x1a, 0x20, 0xc2, 0x95, 0x4f, 0x24, 0xef, 0x33, 0x13, 0xfe, 0xc1, 0x60, 0x5c, 0x3d, - 0x52, 0xf8, 0xfb, 0x5d, 0xb1, 0x43, 0xb6, 0xa3, 0xc3, 0x6d, 0x04, 0xcd, 0x0b, 0x15, 0x3c, 0xe0, 0xa8, 0x64, 0x09, - 0x91, 0x22, 0x97, 0xfb, 0xaa, 0x66, 0xca, 0x76, 0x1d, 0x21, 0x84, 0xb4, 0xc7, 0x59, 0x37, 0xb4, 0x7a, 0xe8, 0x91, - 0x2a, 0xca, 0xe1, 0x16, 0xcd, 0x75, 0x01, 0x2a, 0x8c, 0x40, 0xba, 0xfc, 0xcc, 0xee, 0x52, 0x09, 0xd1, 0xcb, 0xd7, - 0x2e, 0x84, 0xb1, 0xb3, 0xb2, 0xc4, 0x85, 0x19, 0xb5, 0x0d, 0xa3, 0xeb, 0x36, 0x86, 0xb3, 0x81, 0x31, 0xd3, 0xa0, - 0xa4, 0x05, 0xa1, 0xae, 0xbb, 0xf4, 0x22, 0x33, 0x81, 0x1e, 0x73, 0x42, 0x1b, 0x0c, 0x4f, 0x89, 0x06, 0xcb, 0xa6, - 0x02, 0x2c, 0xf8, 0x96, 0x45, 0x6a, 0x6d, 0x36, 0x59, 0xfc, 0x51, 0xc7, 0xe6, 0x69, 0xbf, 0xbc, 0x62, 0x9e, 0x0b, - 0x47, 0xdd, 0x9e, 0x67, 0x3e, 0x1e, 0xdd, 0xd3, 0x37, 0x57, 0x2f, 0x5e, 0xbe, 0x7e, 0xb5, 0x5a, 0xb5, 0x59, 0xb3, - 0x7d, 0x82, 0x7f, 0xd2, 0x65, 0x3c, 0xd8, 0x32, 0x0a, 0xd0, 0xc1, 0xc1, 0x3e, 0x37, 0x2e, 0x3c, 0x9f, 0xf9, 0x1c, - 0xe2, 0x06, 0xe9, 0x01, 0xce, 0x8a, 0x32, 0x26, 0xc8, 0x6d, 0xd4, 0x8b, 0xee, 0x22, 0x50, 0x42, 0x55, 0xe4, 0xef, - 0xc3, 0xe6, 0xec, 0xf7, 0x20, 0x30, 0x11, 0xd4, 0x87, 0x08, 0x20, 0x10, 0xaf, 0x14, 0x17, 0x84, 0xf9, 0x04, 0x88, - 0xe2, 0xbd, 0x00, 0xce, 0xd4, 0x44, 0xad, 0x5a, 0xa8, 0xb8, 0x00, 0x92, 0x68, 0xc3, 0x51, 0xd2, 0x23, 0x13, 0xc0, - 0x1b, 0x82, 0x52, 0xda, 0x5f, 0xdd, 0xdc, 0xb9, 0x4b, 0xe5, 0xa8, 0xd7, 0x4a, 0x73, 0x3c, 0x75, 0x9f, 0x53, 0xf8, - 0x9c, 0x76, 0xfd, 0xe9, 0x20, 0x0e, 0x73, 0xbc, 0x20, 0xe2, 0xd0, 0x3f, 0x8b, 0xb8, 0x9c, 0x17, 0xec, 0x0b, 0x97, - 0x0b, 0x95, 0x2e, 0x6f, 0x53, 0x99, 0xdc, 0x36, 0x47, 0x87, 0x71, 0x91, 0xdc, 0x36, 0x55, 0x72, 0x8b, 0xf0, 0x5d, - 0x2a, 0x93, 0x3b, 0x9b, 0x72, 0xd7, 0x54, 0x70, 0xf3, 0x85, 0x05, 0x1c, 0x8a, 0xb6, 0x68, 0x63, 0xb1, 0x59, 0xd4, - 0xa6, 0xb8, 0xa2, 0x01, 0x06, 0xff, 0xbe, 0x63, 0xe3, 0x87, 0xe1, 0x4b, 0x70, 0x69, 0xd2, 0x44, 0x7e, 0x02, 0xe9, - 0xa7, 0x55, 0x19, 0xb8, 0x4f, 0x49, 0xab, 0x3b, 0xbd, 0x10, 0xcd, 0x76, 0xb7, 0xd1, 0x98, 0xc2, 0xde, 0xcd, 0x48, - 0xee, 0x8b, 0x4d, 0x1b, 0x26, 0xbe, 0xce, 0x7e, 0xb6, 0x5a, 0xed, 0xe7, 0xc8, 0x6c, 0xb8, 0x09, 0x8b, 0x75, 0x7f, - 0x3a, 0xc0, 0x2d, 0xfc, 0x3c, 0x43, 0x68, 0xc9, 0xfa, 0xd3, 0x01, 0x61, 0xfd, 0x69, 0xa3, 0x3d, 0xb0, 0x86, 0x76, - 0x66, 0x2b, 0xae, 0x21, 0x84, 0xe6, 0x74, 0x70, 0x64, 0x4a, 0x4a, 0x97, 0x6f, 0xbf, 0x68, 0x15, 0xd0, 0x4f, 0xd5, - 0x82, 0x97, 0x49, 0xdc, 0x81, 0xbe, 0xe8, 0x85, 0x7d, 0xba, 0xb5, 0x20, 0xc7, 0x47, 0x95, 0xab, 0x3d, 0x45, 0xd8, - 0xf4, 0xa4, 0x0e, 0x8b, 0x43, 0xd3, 0x8c, 0xeb, 0x52, 0xba, 0xef, 0x50, 0x33, 0xf2, 0xd1, 0xc1, 0x02, 0x10, 0xa4, - 0x82, 0x47, 0x56, 0xb8, 0x70, 0x4a, 0x21, 0x5c, 0x1c, 0x54, 0xb6, 0x60, 0x92, 0x93, 0x56, 0x37, 0x37, 0x96, 0xfe, - 0xb9, 0x8b, 0x68, 0x4a, 0x31, 0x25, 0x99, 0x2f, 0x99, 0x1b, 0xb0, 0xd0, 0x4d, 0xca, 0x33, 0x05, 0xbd, 0xd2, 0x00, - 0x8f, 0x08, 0xc4, 0x43, 0xea, 0x16, 0xc6, 0xc0, 0x2b, 0x9e, 0x36, 0x8b, 0x3e, 0x1b, 0xa0, 0xa3, 0x63, 0x4c, 0xfb, - 0x7f, 0x65, 0xf3, 0x36, 0x3c, 0x16, 0xf8, 0xd7, 0x80, 0x4c, 0x9b, 0xb2, 0x4c, 0x10, 0x90, 0x30, 0x6a, 0xca, 0x43, - 0xd8, 0x4b, 0x08, 0x67, 0xb6, 0x62, 0xd6, 0x67, 0x83, 0xe6, 0xb4, 0xac, 0xd8, 0xf1, 0x15, 0x1b, 0xb2, 0x4c, 0xb0, - 0x15, 0x1b, 0xae, 0x62, 0xf8, 0x3a, 0x83, 0x01, 0x41, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x28, 0x88, 0xe6, 0x8b, 0x15, - 0xf1, 0x9b, 0xdd, 0xde, 0xe3, 0xb7, 0xc0, 0x02, 0xad, 0xb6, 0xff, 0x77, 0xa1, 0x0c, 0xd8, 0x53, 0x16, 0x26, 0x66, - 0x6e, 0x61, 0x55, 0x74, 0x00, 0x95, 0x12, 0x61, 0x0a, 0x03, 0x99, 0xfd, 0xcc, 0x40, 0x2d, 0xd0, 0x1a, 0xe4, 0x7d, - 0x3d, 0x68, 0x66, 0x70, 0xc4, 0xc0, 0x3b, 0x34, 0x64, 0x6a, 0x8c, 0x09, 0xe3, 0x1c, 0xa6, 0x98, 0x19, 0xf0, 0x4c, - 0xd3, 0xd6, 0x5a, 0x1a, 0x59, 0xae, 0x97, 0xf7, 0xfe, 0xd1, 0xb1, 0xea, 0x17, 0xcd, 0xf6, 0x00, 0xed, 0x13, 0x62, - 0x3f, 0x06, 0xb0, 0xc9, 0x5c, 0x6a, 0xc3, 0x7c, 0x1f, 0x75, 0x52, 0xfb, 0x09, 0x7f, 0x06, 0x6b, 0xb3, 0x03, 0x40, - 0x47, 0x86, 0xcd, 0xfa, 0xcb, 0x9a, 0xca, 0xeb, 0xe3, 0xce, 0x28, 0x95, 0xbb, 0xde, 0x9d, 0x0e, 0x34, 0xc5, 0xa1, - 0xb7, 0x1e, 0x2e, 0x1f, 0xea, 0x21, 0x60, 0xc6, 0x60, 0x6e, 0x99, 0xd1, 0xf7, 0x42, 0x24, 0x17, 0x44, 0x62, 0x69, - 0xb0, 0x86, 0xc1, 0xde, 0x3a, 0x38, 0x30, 0xd5, 0x58, 0x03, 0x9e, 0x27, 0x45, 0x20, 0x18, 0xf8, 0x08, 0xca, 0x80, - 0x26, 0xca, 0xdc, 0x86, 0x93, 0x8f, 0xcc, 0xfd, 0xc2, 0xe5, 0xed, 0x63, 0xe1, 0xb4, 0xad, 0xe6, 0x7a, 0xbc, 0x2c, - 0x70, 0x57, 0xde, 0x4b, 0x5a, 0x05, 0x37, 0xb2, 0x37, 0x79, 0xca, 0xdc, 0xad, 0xfb, 0x52, 0x9d, 0xdd, 0xcd, 0x74, - 0xca, 0x66, 0x3a, 0xdb, 0xcd, 0x84, 0x9a, 0x99, 0x6f, 0x59, 0x45, 0x9a, 0x93, 0x35, 0x51, 0x73, 0x2a, 0x7e, 0xa2, - 0x73, 0xd0, 0x8e, 0x72, 0x7b, 0xaf, 0x0a, 0x27, 0x57, 0x4e, 0x2e, 0xf7, 0x73, 0x43, 0x5c, 0x91, 0xb9, 0x50, 0x87, - 0x00, 0x2f, 0x2f, 0xca, 0xc7, 0x07, 0xb8, 0x14, 0xbf, 0xca, 0x91, 0x8b, 0x72, 0x2a, 0xa4, 0x96, 0x82, 0x45, 0xc8, - 0xa0, 0xaa, 0x8b, 0x81, 0xbd, 0xb4, 0x7b, 0x4f, 0xf4, 0x78, 0xbf, 0x8a, 0x98, 0x37, 0x30, 0xcf, 0x7d, 0x7c, 0x4f, - 0x53, 0xec, 0xd4, 0xc4, 0x19, 0xf9, 0x90, 0xc5, 0x39, 0xc8, 0x66, 0xfd, 0xea, 0xb5, 0xdf, 0x46, 0x1b, 0x17, 0xcd, - 0x58, 0xf4, 0xcc, 0x13, 0x27, 0x3f, 0x14, 0xc6, 0x38, 0xc0, 0x3a, 0xfa, 0x23, 0x4c, 0x2d, 0xd8, 0xb3, 0xc4, 0x53, - 0xe8, 0xe4, 0xd6, 0xa6, 0xdd, 0x85, 0x69, 0x77, 0x26, 0xad, 0x03, 0xe5, 0x80, 0x34, 0xbb, 0x32, 0x9d, 0x3b, 0xff, - 0x7d, 0x07, 0x2f, 0xdd, 0xae, 0x21, 0x12, 0xf7, 0xfc, 0x91, 0x31, 0x86, 0x78, 0x03, 0x36, 0xa2, 0xea, 0xe0, 0xe0, - 0x0f, 0xe7, 0x7d, 0x5b, 0xc9, 0x7d, 0xdf, 0x0a, 0x07, 0xb6, 0xc1, 0x54, 0xba, 0xbc, 0x91, 0xcc, 0x16, 0x60, 0xd7, - 0xb9, 0xff, 0x8d, 0x78, 0xf8, 0x22, 0x64, 0x5a, 0xac, 0xab, 0xf8, 0x2b, 0x39, 0x2a, 0x3d, 0x44, 0x35, 0x44, 0x20, - 0xad, 0xac, 0x4b, 0x43, 0xd3, 0xd1, 0xab, 0x29, 0x1d, 0xc9, 0x9b, 0xb7, 0x52, 0xea, 0x81, 0x7d, 0x91, 0x5b, 0x27, - 0xf0, 0x68, 0x61, 0x8d, 0xa1, 0xb9, 0x2b, 0xbd, 0x93, 0x6c, 0x40, 0xd4, 0xfa, 0xb8, 0x43, 0x49, 0x24, 0x16, 0xd5, - 0x5d, 0x08, 0x87, 0xbb, 0x10, 0xcc, 0xcb, 0xa0, 0x6d, 0x10, 0xbb, 0xdd, 0x05, 0x6d, 0x03, 0xa7, 0x6e, 0x1b, 0xb8, - 0x3d, 0x18, 0x2c, 0xec, 0x7d, 0x78, 0x39, 0x96, 0x63, 0xe1, 0xaf, 0xc9, 0xec, 0x03, 0x40, 0xa0, 0xf6, 0x61, 0xc5, - 0x13, 0x07, 0x82, 0xc4, 0x19, 0x8e, 0xbe, 0xe7, 0xec, 0xc6, 0x5a, 0x0e, 0xcf, 0xe6, 0x0b, 0xcd, 0x46, 0xe6, 0x8e, - 0x1a, 0x54, 0x7c, 0x75, 0x3f, 0xaf, 0x9f, 0xb2, 0x9a, 0x6e, 0xfc, 0x1e, 0x84, 0x91, 0x70, 0xca, 0x0e, 0xa3, 0x90, - 0xb0, 0xc1, 0xac, 0xca, 0x78, 0x6d, 0xbf, 0x41, 0xbc, 0x07, 0x6d, 0xc2, 0x09, 0x16, 0xb5, 0x0b, 0xaa, 0x08, 0xdb, - 0x78, 0x63, 0x41, 0x94, 0x87, 0x37, 0x5b, 0x46, 0xd3, 0xcb, 0x35, 0x04, 0x3a, 0xee, 0x45, 0xcd, 0xa8, 0xc1, 0x52, - 0x17, 0x94, 0xd9, 0x47, 0x18, 0x57, 0x17, 0x27, 0x26, 0x4e, 0x7b, 0xa9, 0x57, 0xff, 0x2d, 0x03, 0x03, 0x7c, 0x01, - 0x5e, 0x62, 0x61, 0x74, 0xd7, 0xbe, 0x6e, 0x40, 0x7d, 0xd9, 0x60, 0x03, 0xb4, 0x5a, 0xb5, 0xca, 0x67, 0xa0, 0xdc, - 0x35, 0x97, 0xb0, 0xd7, 0x5c, 0xc2, 0x5d, 0x73, 0x09, 0x7f, 0xcd, 0x25, 0xcc, 0x35, 0x97, 0xf0, 0xd7, 0x5c, 0x1e, - 0x84, 0x9f, 0x82, 0x38, 0x8e, 0x31, 0x87, 0xb8, 0x8a, 0xda, 0x46, 0xc6, 0x83, 0x0b, 0xcf, 0x7d, 0x96, 0xa8, 0x72, - 0xf9, 0xc3, 0x18, 0x72, 0x5b, 0xb6, 0x12, 0xc6, 0x6d, 0x8a, 0x29, 0x88, 0x9c, 0x7e, 0x70, 0x50, 0xba, 0x3b, 0x83, - 0x8f, 0x7a, 0xca, 0xf1, 0xd2, 0x3a, 0xd1, 0xfe, 0x01, 0x3a, 0x79, 0xf3, 0xeb, 0x63, 0x2a, 0xd7, 0x44, 0x38, 0x93, - 0xfb, 0xfd, 0xb6, 0xa7, 0x14, 0x9f, 0x32, 0x13, 0x9e, 0x9c, 0x27, 0xda, 0x88, 0x20, 0x08, 0x51, 0xa2, 0x70, 0x46, - 0xa4, 0xdd, 0xef, 0xde, 0x15, 0xde, 0xa8, 0xa2, 0xbc, 0x59, 0xc9, 0xe3, 0x1c, 0x9c, 0xd8, 0x8d, 0x15, 0x06, 0xea, - 0x82, 0x0b, 0x41, 0x66, 0x12, 0xfe, 0x68, 0xe6, 0x96, 0x9c, 0x65, 0x65, 0xd2, 0xc7, 0x66, 0x6e, 0x08, 0x58, 0x41, - 0xf6, 0x3d, 0xcc, 0x96, 0xb7, 0x29, 0xc5, 0x77, 0x69, 0x86, 0x87, 0xf2, 0x36, 0x2d, 0x42, 0x5b, 0x10, 0x7f, 0xf1, - 0x37, 0x8e, 0x23, 0x41, 0xc1, 0xdf, 0x27, 0xe2, 0x62, 0x8f, 0x6f, 0x78, 0x01, 0x2e, 0x33, 0x63, 0x51, 0x9d, 0x32, - 0xfc, 0x0d, 0x4b, 0x78, 0x08, 0x4e, 0xa6, 0xb1, 0x22, 0xf7, 0x38, 0xb0, 0x13, 0x92, 0x80, 0xc3, 0xd5, 0xed, 0x15, - 0xff, 0x0a, 0x17, 0x5f, 0xa5, 0xb3, 0x65, 0x73, 0x28, 0x6f, 0x23, 0x5c, 0x90, 0x37, 0xf0, 0xfa, 0xd6, 0xff, 0xcb, - 0xde, 0xdb, 0x36, 0xb7, 0x6d, 0x64, 0xeb, 0xa2, 0x7f, 0x45, 0x62, 0xd9, 0x0c, 0x60, 0x36, 0x29, 0xca, 0xe7, 0xcc, - 0x54, 0x5d, 0x50, 0x6d, 0x96, 0x63, 0xc7, 0x13, 0x67, 0x22, 0xdb, 0x63, 0x79, 0x32, 0xc9, 0xb0, 0x78, 0x19, 0x08, - 0x68, 0x0a, 0x70, 0x40, 0x80, 0x01, 0x40, 0x89, 0x34, 0x89, 0xff, 0x7e, 0x6a, 0xad, 0xd5, 0xaf, 0x20, 0x28, 0x7b, - 0xf6, 0x3e, 0xfb, 0xd3, 0xbd, 0x5f, 0x6c, 0xb1, 0xd1, 0x68, 0xf4, 0x7b, 0xaf, 0x5e, 0x2f, 0xcf, 0xd3, 0x93, 0xb1, - 0xba, 0x3d, 0x70, 0xd6, 0xa5, 0x14, 0x1d, 0x6f, 0x8a, 0xc3, 0xdb, 0xf3, 0xd9, 0x7e, 0x1b, 0x44, 0x6c, 0x17, 0x64, - 0x58, 0xeb, 0xa4, 0xe1, 0x3f, 0xd1, 0xd6, 0xc1, 0x62, 0x84, 0xfd, 0x5f, 0xd6, 0x03, 0x2f, 0x21, 0x35, 0x14, 0xb8, - 0x18, 0x6c, 0x38, 0x5a, 0xdb, 0x65, 0x1a, 0xb8, 0xa9, 0x41, 0xaf, 0xef, 0x29, 0x44, 0x79, 0xc9, 0x68, 0x6e, 0x04, - 0xeb, 0xc6, 0x90, 0x8b, 0xc3, 0x71, 0xb3, 0x1c, 0xf2, 0x92, 0xa6, 0xd3, 0x20, 0x94, 0xee, 0x2c, 0x6b, 0x48, 0xa2, - 0xec, 0x83, 0x50, 0xbb, 0xb6, 0xec, 0xb7, 0x81, 0xed, 0xcb, 0x1f, 0x0d, 0x63, 0xff, 0x62, 0xf9, 0x4c, 0x48, 0x17, - 0xf1, 0x1c, 0x04, 0x51, 0xfb, 0x79, 0x36, 0xdc, 0xf8, 0x17, 0xeb, 0x67, 0x42, 0xf9, 0x8d, 0xe7, 0xb6, 0x1c, 0x52, - 0x67, 0x2d, 0x7c, 0x61, 0x3c, 0x3c, 0xb8, 0x32, 0xb4, 0x1d, 0x0e, 0x42, 0xff, 0x6d, 0xd6, 0x08, 0x6e, 0x6c, 0x68, - 0x9f, 0x2f, 0x7c, 0xd8, 0xda, 0x68, 0xac, 0x29, 0xa6, 0x5b, 0xe8, 0xdf, 0x64, 0xb6, 0xb4, 0xa7, 0x51, 0xc9, 0x8b, - 0x53, 0xd3, 0x88, 0x85, 0x30, 0x60, 0xe8, 0x27, 0xf3, 0x01, 0x54, 0x73, 0xc7, 0x23, 0x90, 0xc9, 0x07, 0x7a, 0xb0, - 0x26, 0xb5, 0xea, 0xaf, 0x61, 0x26, 0xff, 0x8f, 0x54, 0x58, 0x8c, 0xee, 0xb6, 0x61, 0xa6, 0xfe, 0x88, 0xe4, 0x1f, - 0x2c, 0xe7, 0xbb, 0xd4, 0x0b, 0xb5, 0x1f, 0x0b, 0x2b, 0x30, 0x28, 0x51, 0x35, 0xa0, 0x07, 0x22, 0xa8, 0xca, 0x20, - 0xcd, 0xb0, 0x3a, 0x07, 0xfd, 0xee, 0x69, 0xd5, 0x91, 0x1c, 0xd2, 0x5a, 0x0d, 0xa9, 0x60, 0xaa, 0xd4, 0x20, 0x3f, - 0x1c, 0xee, 0x52, 0xa6, 0xcb, 0x80, 0x4b, 0xfa, 0x5d, 0xaa, 0x94, 0xc2, 0x7f, 0x22, 0x00, 0x9d, 0x83, 0x7b, 0x7c, - 0x39, 0x06, 0xd2, 0x0c, 0x0b, 0xbf, 0x35, 0x3b, 0xbe, 0x26, 0xe1, 0x36, 0x09, 0x2e, 0x06, 0x38, 0x47, 0x57, 0x61, - 0x79, 0x97, 0x42, 0x04, 0x55, 0x09, 0xf5, 0xad, 0x4c, 0x83, 0xd2, 0x56, 0x83, 0xb0, 0x26, 0xa1, 0xce, 0x24, 0x1b, - 0x95, 0xb6, 0x1b, 0x85, 0xd9, 0x22, 0xae, 0x67, 0x84, 0x35, 0x67, 0x33, 0xd5, 0xc0, 0xa4, 0xe1, 0xb8, 0x69, 0xb4, - 0x16, 0x15, 0x6a, 0x0a, 0xf3, 0x1a, 0x57, 0x95, 0xaa, 0xee, 0xe6, 0xd4, 0x52, 0x5a, 0xb6, 0x57, 0xdd, 0x24, 0x1b, - 0x72, 0x19, 0xca, 0x30, 0xd8, 0xc8, 0x11, 0x4c, 0x20, 0x49, 0xce, 0xfc, 0x8d, 0xfc, 0x43, 0x6d, 0xba, 0x16, 0x30, - 0xc7, 0x98, 0x65, 0xc3, 0x82, 0x5e, 0x81, 0x7b, 0xa0, 0x95, 0x9e, 0x4f, 0xb3, 0x8b, 0x3c, 0x48, 0x86, 0x85, 0x5e, - 0x36, 0x19, 0xff, 0x53, 0x18, 0x69, 0x32, 0x63, 0x25, 0x8b, 0x6c, 0x57, 0xa7, 0xc4, 0x79, 0x9c, 0xc0, 0xf6, 0x68, - 0x7a, 0xcb, 0xf7, 0x19, 0x44, 0x05, 0x81, 0x82, 0x19, 0xf3, 0x65, 0x17, 0xcf, 0x7d, 0x9f, 0x59, 0xa6, 0xee, 0xc3, - 0xc1, 0x98, 0xb1, 0xfd, 0x7e, 0x3f, 0xef, 0xf7, 0xd5, 0x7c, 0xeb, 0xf7, 0x93, 0x17, 0xe6, 0x6f, 0x0f, 0x18, 0x14, - 0xe4, 0x44, 0x34, 0x15, 0x22, 0xf8, 0x87, 0xe4, 0x19, 0x92, 0xd1, 0x1d, 0xf7, 0xb9, 0xe5, 0x6c, 0x59, 0x1d, 0x81, - 0x60, 0x1e, 0x0e, 0x97, 0x0a, 0xec, 0x5a, 0xa2, 0x48, 0xc8, 0xf2, 0x9f, 0x81, 0xf1, 0xcc, 0x7d, 0x80, 0x25, 0x03, - 0x10, 0xb6, 0xca, 0xd3, 0xf5, 0x9e, 0xaf, 0x82, 0x77, 0x3a, 0xde, 0x35, 0x56, 0x64, 0x20, 0x6e, 0x81, 0x8d, 0x58, - 0x6b, 0x0f, 0xc8, 0x99, 0x02, 0x1c, 0x2f, 0x0e, 0x87, 0x73, 0xf9, 0x4b, 0x37, 0x5b, 0x27, 0x50, 0x29, 0x70, 0x7b, - 0x74, 0x72, 0xf0, 0xdf, 0x81, 0x66, 0x50, 0x0e, 0xf3, 0x7a, 0xfb, 0x3b, 0x73, 0xf2, 0xd3, 0x53, 0xfc, 0x13, 0x1e, - 0xa2, 0xd3, 0x6f, 0xf7, 0xe6, 0x0f, 0x8a, 0xca, 0xc3, 0x41, 0x2d, 0xfe, 0x73, 0xce, 0x2b, 0xf8, 0x85, 0x6f, 0x02, - 0xb3, 0xc9, 0xd4, 0x3b, 0xf9, 0x26, 0xcf, 0x99, 0x7a, 0x8d, 0x57, 0x4c, 0xbe, 0xc3, 0xe1, 0x5c, 0x8c, 0xea, 0xed, - 0xc8, 0x89, 0x76, 0xca, 0x31, 0x0e, 0x06, 0xff, 0x45, 0xb4, 0x4d, 0x08, 0x30, 0xa4, 0x6e, 0x49, 0x33, 0x1b, 0x57, - 0x96, 0x78, 0x96, 0xce, 0x2f, 0x27, 0x75, 0xb9, 0xd3, 0x8a, 0xa7, 0x3d, 0xb0, 0xb8, 0xad, 0xc1, 0x0b, 0xe0, 0xde, - 0x62, 0xeb, 0x4a, 0xc1, 0xe1, 0x02, 0xe2, 0x14, 0x27, 0x20, 0x82, 0xf6, 0xfb, 0x12, 0xef, 0x15, 0xf4, 0x49, 0x3f, - 0x40, 0x30, 0xe4, 0xcf, 0x12, 0x70, 0xd7, 0xeb, 0xd5, 0x18, 0xdf, 0x4b, 0x21, 0xb8, 0x3e, 0xd3, 0x00, 0xb4, 0xe0, - 0x77, 0xf9, 0x58, 0x4e, 0xbf, 0x89, 0xc0, 0xb3, 0x65, 0x6f, 0xa2, 0xdc, 0x6d, 0x78, 0xda, 0x3f, 0x5a, 0x08, 0xc0, - 0x52, 0x3c, 0x53, 0x82, 0x05, 0x39, 0xc5, 0x5c, 0xfc, 0xbf, 0xe0, 0x23, 0xe6, 0x7b, 0xd2, 0x45, 0x6c, 0xbd, 0x7d, - 0x72, 0x61, 0x20, 0x81, 0xa6, 0x03, 0xf0, 0xe3, 0x55, 0x40, 0x57, 0xc6, 0xcf, 0xcf, 0xb2, 0x1e, 0xeb, 0xe3, 0x3f, - 0x05, 0xf7, 0xe9, 0x67, 0x0a, 0x1f, 0x1d, 0x8e, 0xab, 0x74, 0xb4, 0xa3, 0x14, 0x44, 0x47, 0xb7, 0xcf, 0xa7, 0x3c, - 0xfb, 0xa6, 0x02, 0x72, 0xcb, 0x51, 0x7b, 0x2a, 0x00, 0x8b, 0x2d, 0x1d, 0x81, 0x4f, 0xb3, 0x7c, 0x42, 0xbe, 0xd7, - 0x53, 0x71, 0x75, 0xa9, 0xd3, 0xc5, 0x8b, 0xf1, 0x14, 0xfe, 0x07, 0x62, 0x0f, 0xcb, 0x14, 0xd9, 0xb1, 0xeb, 0xe2, - 0x07, 0xf1, 0xb6, 0xb6, 0xa3, 0x3f, 0x76, 0x10, 0xe9, 0xb8, 0x27, 0x17, 0xea, 0x4b, 0x48, 0x25, 0x17, 0xea, 0x06, - 0x62, 0x17, 0x6a, 0xbc, 0xe3, 0x22, 0xd6, 0xfa, 0x75, 0x8d, 0x82, 0x95, 0x80, 0x33, 0xed, 0x1a, 0x0c, 0x36, 0xb0, - 0x6e, 0x59, 0x06, 0x7f, 0xc3, 0x35, 0x4d, 0xe0, 0x86, 0x45, 0xd6, 0x7b, 0x83, 0xad, 0x74, 0x0d, 0x8e, 0x96, 0x89, - 0x73, 0x29, 0xc9, 0xca, 0x16, 0x19, 0x57, 0x8f, 0x42, 0xaa, 0xa6, 0xfb, 0x5b, 0x51, 0x3f, 0x08, 0x91, 0x07, 0xab, - 0x94, 0x45, 0xc5, 0x0a, 0x64, 0xf6, 0xe0, 0x1f, 0x21, 0x23, 0x47, 0x39, 0x70, 0x14, 0xfa, 0x5b, 0x13, 0xe8, 0x3c, - 0x3f, 0x85, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, - 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, - 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, - 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, - 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, - 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, - 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, - 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, - 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, - 0x74, 0xe9, 0x7e, 0x66, 0xc7, 0x5d, 0xe8, 0x0e, 0xb0, 0xf1, 0xb6, 0x41, 0x47, 0xfe, 0xf5, 0x0e, 0x29, 0x75, 0x93, - 0x01, 0xd8, 0x8d, 0x06, 0x38, 0x64, 0xaa, 0x97, 0x22, 0xab, 0x97, 0x32, 0xd5, 0x4b, 0xb2, 0x72, 0x09, 0x16, 0x12, - 0x53, 0xe5, 0x36, 0xb2, 0x72, 0xcb, 0x86, 0xeb, 0xe1, 0x60, 0x6b, 0xc5, 0x65, 0x73, 0x07, 0xf7, 0x85, 0x15, 0x05, - 0xfe, 0xdf, 0xb2, 0x05, 0xbb, 0x97, 0xc7, 0xc0, 0x35, 0x3a, 0x26, 0xc1, 0x05, 0xe2, 0x9e, 0xdd, 0x82, 0x1d, 0x16, - 0xfe, 0x82, 0xeb, 0xe4, 0x98, 0xed, 0xf0, 0x51, 0xe8, 0x15, 0xec, 0xd6, 0x27, 0xa0, 0x5d, 0xb0, 0x35, 0x40, 0x36, - 0xb6, 0xc5, 0x47, 0x77, 0x87, 0xc3, 0xb5, 0xe7, 0xb3, 0x07, 0xfc, 0x71, 0x7e, 0x77, 0x38, 0xec, 0x3c, 0xa3, 0xde, - 0xbb, 0xe1, 0x09, 0x7b, 0xcf, 0x93, 0xc9, 0xcd, 0x15, 0x8f, 0x27, 0x83, 0xc1, 0x8d, 0xbf, 0xe0, 0xf5, 0xec, 0x06, - 0xb4, 0x03, 0xe7, 0x0b, 0xa9, 0x6b, 0xf6, 0x6e, 0x79, 0xe6, 0x2d, 0x70, 0x6c, 0x6e, 0xe1, 0xe8, 0xed, 0xf7, 0xbd, - 0x3b, 0x1e, 0x79, 0xb7, 0xa4, 0x62, 0x5a, 0x71, 0xc5, 0xf1, 0xb6, 0xc5, 0xfd, 0x74, 0xc5, 0x43, 0x78, 0x84, 0x55, - 0x99, 0xde, 0x04, 0xef, 0x7d, 0xb6, 0xd2, 0x2c, 0x70, 0x0f, 0x98, 0x63, 0x4d, 0x76, 0x42, 0x33, 0xf1, 0x57, 0xd8, - 0x3f, 0x37, 0xaa, 0x7f, 0x68, 0xfe, 0x97, 0xba, 0x9f, 0xc0, 0xed, 0x8b, 0x2c, 0x48, 0xec, 0x3d, 0xbf, 0x61, 0xf7, - 0xdc, 0xb0, 0xcd, 0x9e, 0x99, 0xb2, 0x4f, 0x94, 0x1a, 0x3f, 0x52, 0xea, 0xda, 0x32, 0xac, 0x64, 0xee, 0xbe, 0x8c, - 0xc0, 0xe1, 0x80, 0xfc, 0x74, 0x87, 0x38, 0x08, 0xad, 0x9b, 0xac, 0xe6, 0x8a, 0x72, 0x2e, 0xb4, 0x65, 0xe6, 0xe5, - 0xc0, 0x62, 0x96, 0x52, 0x68, 0x2c, 0x00, 0x10, 0x4c, 0x0a, 0xad, 0xbd, 0x97, 0x01, 0xe4, 0x04, 0x0d, 0x7f, 0x6c, - 0xae, 0x8a, 0xb2, 0x96, 0x2d, 0x09, 0x51, 0xb6, 0xeb, 0xe1, 0x25, 0x42, 0xa6, 0xf5, 0xfb, 0xe7, 0x44, 0xb2, 0x36, - 0xa9, 0xae, 0x6a, 0xb4, 0x04, 0x54, 0x64, 0x09, 0x98, 0xf8, 0x95, 0xe6, 0x13, 0x80, 0x27, 0x1d, 0x0f, 0xaa, 0xa7, - 0xbc, 0x66, 0x82, 0xc8, 0x36, 0x2a, 0x7f, 0x52, 0xbc, 0x40, 0x32, 0x82, 0xe2, 0x69, 0xad, 0x32, 0x16, 0x86, 0x79, - 0xa0, 0x80, 0xbc, 0x7b, 0x77, 0xea, 0x5b, 0xfb, 0x63, 0xc7, 0x9e, 0xad, 0x55, 0xa8, 0x85, 0x9a, 0xc2, 0x25, 0x87, - 0xe8, 0x0a, 0x32, 0x50, 0xc8, 0x78, 0xf2, 0x7a, 0x70, 0x39, 0x89, 0xae, 0xb8, 0x40, 0x67, 0x7c, 0x7d, 0xd3, 0x4d, - 0x67, 0xd1, 0xd3, 0x6a, 0x3e, 0x21, 0x25, 0xd9, 0xe1, 0x90, 0x8d, 0xaa, 0xba, 0x58, 0x4f, 0x43, 0xf9, 0xd3, 0x43, - 0xf0, 0xf5, 0x82, 0x7a, 0x4d, 0x56, 0xa9, 0x7e, 0x4a, 0x95, 0xf2, 0xa2, 0xe1, 0xa5, 0xff, 0xb4, 0x92, 0xfb, 0x1e, - 0x90, 0xd6, 0xf2, 0x92, 0xcb, 0xf7, 0x23, 0xc4, 0x18, 0xf1, 0x03, 0xaf, 0xe4, 0x11, 0x0b, 0xd5, 0x14, 0xae, 0x79, - 0x84, 0x20, 0x6f, 0x99, 0x0e, 0xfe, 0xd6, 0x13, 0xa7, 0xfb, 0x13, 0xa5, 0x5d, 0x7c, 0x61, 0x51, 0xf7, 0x64, 0x6d, - 0xdd, 0x80, 0x1c, 0x6c, 0x98, 0x2e, 0x0a, 0xb2, 0x4d, 0x69, 0x04, 0x6d, 0xb4, 0x1c, 0xd8, 0x70, 0x2a, 0xb5, 0xe1, - 0xcc, 0x35, 0x04, 0xf7, 0xf9, 0x79, 0x3a, 0x5a, 0xc0, 0x87, 0x54, 0xb7, 0x97, 0xf8, 0xf9, 0xb0, 0xe1, 0x11, 0x90, - 0xd9, 0x11, 0x9f, 0xd9, 0x44, 0xd2, 0x49, 0x9d, 0x2b, 0x60, 0xb7, 0xb3, 0x6b, 0x90, 0x23, 0x66, 0xee, 0x2b, 0x54, - 0xdf, 0xa2, 0x01, 0x57, 0xc6, 0xda, 0xd7, 0x24, 0x63, 0xe1, 0x55, 0x39, 0x0d, 0x07, 0x00, 0x43, 0x97, 0xd1, 0xd7, - 0x96, 0x9b, 0x2c, 0xfb, 0xb9, 0x80, 0x20, 0x88, 0x92, 0x78, 0x7c, 0xc0, 0xfb, 0xb2, 0x1a, 0x6a, 0x94, 0x7c, 0x2c, - 0x1b, 0xa9, 0xf4, 0x4a, 0xf4, 0x77, 0x63, 0x2e, 0x31, 0xe0, 0x75, 0xd5, 0x16, 0x14, 0xce, 0xf3, 0xc3, 0xe1, 0x3c, - 0x1f, 0x19, 0xcf, 0x32, 0x50, 0xad, 0x4c, 0xeb, 0x20, 0x36, 0xf3, 0xc5, 0xc2, 0x5f, 0xec, 0x9c, 0x44, 0x44, 0x41, - 0x60, 0x47, 0xc2, 0x83, 0x48, 0xfd, 0xaa, 0xf2, 0x74, 0xa7, 0xfa, 0x6c, 0xbf, 0xb0, 0x89, 0xf4, 0x82, 0x92, 0xc9, - 0x27, 0xc1, 0x5e, 0xf5, 0x77, 0x10, 0x36, 0x84, 0x37, 0xaf, 0x7a, 0x9d, 0x65, 0x6a, 0x56, 0x82, 0x84, 0x19, 0x73, - 0x04, 0x8f, 0xc3, 0x4e, 0x63, 0x1b, 0x1e, 0x5b, 0x70, 0x74, 0xde, 0x9a, 0xdd, 0xb1, 0x15, 0xbb, 0x55, 0x75, 0x5a, - 0xf0, 0x70, 0x3a, 0xbc, 0x0c, 0x70, 0xf5, 0xad, 0xcf, 0x39, 0xbf, 0xa3, 0x13, 0x6c, 0x3d, 0xe0, 0xd1, 0x44, 0xcc, - 0xd6, 0x4f, 0x23, 0xb5, 0x78, 0xd6, 0x43, 0xbe, 0xa0, 0xf5, 0x27, 0x66, 0x77, 0x26, 0xf9, 0x6e, 0xc0, 0x17, 0x93, - 0xf5, 0xd3, 0x08, 0x5e, 0x7d, 0x0a, 0x56, 0x8c, 0xcc, 0x99, 0x65, 0xeb, 0xa7, 0x11, 0x8e, 0xd9, 0xdd, 0xd3, 0x88, - 0x46, 0x6d, 0x25, 0xf7, 0xa5, 0xdb, 0x06, 0x84, 0x95, 0x5b, 0x16, 0xc3, 0x6b, 0x20, 0x9e, 0x69, 0x23, 0xe9, 0x5a, - 0x1a, 0x7a, 0x63, 0x1e, 0x4e, 0xe3, 0x60, 0x4d, 0xad, 0x90, 0x67, 0x86, 0x98, 0xc5, 0x4f, 0xa3, 0x39, 0x5b, 0x61, - 0x45, 0x36, 0x3c, 0x1e, 0x5c, 0x4e, 0x36, 0x57, 0x7c, 0x0d, 0xe4, 0x67, 0x93, 0x8d, 0xd9, 0xa2, 0x6e, 0xb9, 0x98, - 0x6d, 0x9e, 0x46, 0xf3, 0xc9, 0x0a, 0x7a, 0xd6, 0x1e, 0x30, 0xef, 0x0d, 0x88, 0x50, 0x12, 0x52, 0x53, 0x6e, 0x7a, - 0x3d, 0xb6, 0x1e, 0x07, 0x77, 0x6c, 0x7d, 0x19, 0xdc, 0xb2, 0xf5, 0x18, 0x88, 0x38, 0xa8, 0xdf, 0xbd, 0x0d, 0x2c, - 0xbe, 0x88, 0xad, 0x2f, 0x4d, 0xda, 0xe6, 0x69, 0xc4, 0xdc, 0xc1, 0x69, 0xe0, 0x82, 0xb5, 0xc9, 0xbc, 0x15, 0x83, - 0x4b, 0xc8, 0xd2, 0x8b, 0xd9, 0x66, 0x78, 0xc9, 0xd6, 0x23, 0x9c, 0xea, 0x89, 0xcf, 0xee, 0xf8, 0x2d, 0x4b, 0xf8, - 0xaa, 0x89, 0xaf, 0x36, 0xa0, 0x11, 0x3d, 0xca, 0xa0, 0xaf, 0xa0, 0x66, 0xe6, 0xbc, 0xb2, 0x30, 0x2a, 0xf7, 0x2d, - 0x38, 0xa0, 0x20, 0x6d, 0x03, 0x04, 0x49, 0x3c, 0xbb, 0x57, 0xe1, 0xfa, 0x46, 0x0a, 0x03, 0x6e, 0x02, 0x33, 0x60, - 0x60, 0xfa, 0x19, 0xfc, 0xb0, 0xd2, 0x25, 0x42, 0x9c, 0xfd, 0x94, 0x92, 0x64, 0x9e, 0x9f, 0x8a, 0x34, 0x77, 0x0b, - 0xd7, 0x29, 0xcc, 0x8a, 0x02, 0xd5, 0x4f, 0x49, 0x69, 0x60, 0xa1, 0x12, 0x99, 0x4a, 0xc1, 0x2f, 0x9b, 0xf3, 0x28, - 0x3b, 0x46, 0xe7, 0x3a, 0xbf, 0x9c, 0x38, 0xa7, 0x93, 0xbe, 0xff, 0xc0, 0x31, 0x6c, 0x21, 0x03, 0x17, 0xfe, 0xd4, - 0x13, 0xc6, 0xa9, 0x15, 0x88, 0xa9, 0xe4, 0xd9, 0x53, 0xf8, 0x4c, 0x68, 0x75, 0x74, 0xe1, 0xfb, 0x41, 0xa1, 0x4d, - 0xd2, 0x2d, 0x48, 0x52, 0xf0, 0x14, 0x3d, 0xe7, 0xbc, 0x0d, 0x54, 0x8a, 0x11, 0x2d, 0x88, 0xb4, 0xb5, 0xcc, 0x1c, - 0xa4, 0x2d, 0xcd, 0x77, 0x4d, 0xfc, 0x1c, 0x16, 0x70, 0x11, 0x2d, 0x6c, 0x0d, 0x8f, 0xaa, 0x58, 0xb9, 0x37, 0x79, - 0x8e, 0x70, 0x46, 0x97, 0x32, 0x01, 0x70, 0xbd, 0x5f, 0x87, 0xb5, 0xc2, 0x2b, 0x6a, 0x16, 0x79, 0x51, 0xd3, 0x27, - 0x5b, 0xe0, 0x3e, 0x16, 0x25, 0x0a, 0x9c, 0xb5, 0x60, 0xc0, 0x56, 0x58, 0xb2, 0x93, 0xc2, 0xa6, 0x68, 0x09, 0xbd, - 0x3d, 0x7e, 0x3a, 0xa8, 0x99, 0x0c, 0xa0, 0x09, 0xa0, 0xf1, 0xf8, 0x17, 0x80, 0x9a, 0xde, 0xd4, 0x62, 0x5d, 0x05, - 0xa5, 0x52, 0x6e, 0xc2, 0xcf, 0xc0, 0x30, 0xc3, 0x0f, 0x85, 0xdc, 0x26, 0x4a, 0xe4, 0xfc, 0x58, 0x94, 0x62, 0x59, - 0x8a, 0x2a, 0x69, 0x37, 0x14, 0x3c, 0x22, 0xdc, 0x06, 0x8d, 0x99, 0xdb, 0x13, 0x5d, 0xb4, 0x22, 0x94, 0x63, 0xb3, - 0x8e, 0x91, 0x46, 0x99, 0x9d, 0xec, 0x3a, 0x59, 0x68, 0xbf, 0xaf, 0x72, 0xc8, 0x3a, 0x60, 0x8d, 0xe4, 0xeb, 0x35, - 0x87, 0x6e, 0x1b, 0xe5, 0xc5, 0x83, 0xe7, 0x2b, 0x38, 0xcd, 0xf1, 0xc4, 0xee, 0x7a, 0xdd, 0x29, 0x12, 0xf1, 0x0a, - 0x27, 0x55, 0x3e, 0x92, 0x85, 0xe3, 0xce, 0x9d, 0xd6, 0x62, 0x55, 0xb9, 0xac, 0xa7, 0x16, 0x47, 0x04, 0x3e, 0x95, - 0x47, 0x7b, 0xa1, 0x6d, 0x51, 0x2c, 0x84, 0xd1, 0xa3, 0x13, 0x7e, 0x52, 0x02, 0xeb, 0xeb, 0x70, 0x58, 0xfa, 0x11, - 0x47, 0xbf, 0xd3, 0x68, 0xb4, 0x20, 0xa4, 0xe1, 0xa9, 0x17, 0x8d, 0x16, 0x75, 0x51, 0x87, 0xd9, 0x8b, 0x5c, 0x0f, - 0x14, 0x86, 0x11, 0xa8, 0x1f, 0x5c, 0x65, 0xf0, 0x59, 0x84, 0xa8, 0x79, 0x60, 0x9a, 0x0d, 0xe1, 0xa8, 0x0b, 0x3c, - 0xb4, 0x82, 0x16, 0x33, 0xf3, 0x51, 0x88, 0xe1, 0x43, 0xba, 0x38, 0x7f, 0x42, 0x56, 0x3e, 0xc0, 0xee, 0xd0, 0x5d, - 0x28, 0xe7, 0x4c, 0xc5, 0x00, 0x3f, 0x0a, 0xc8, 0x47, 0x09, 0xb8, 0x19, 0x20, 0x7b, 0x64, 0x09, 0x20, 0x56, 0x8c, - 0x8e, 0x26, 0x9f, 0xfb, 0x5e, 0xa4, 0xe0, 0x9d, 0x7d, 0x96, 0xab, 0x09, 0x43, 0xe1, 0x13, 0x03, 0xdd, 0xfc, 0xc6, - 0x6f, 0xcf, 0x5b, 0x30, 0xb2, 0x4b, 0x52, 0xbc, 0xd6, 0x0c, 0xf7, 0x1b, 0x70, 0x3b, 0x02, 0xca, 0x9a, 0xea, 0x98, - 0x64, 0x9b, 0x86, 0x48, 0x06, 0xcc, 0x88, 0x11, 0x41, 0x65, 0xb9, 0xf0, 0xbf, 0x7b, 0x59, 0x14, 0x38, 0x80, 0xab, - 0x99, 0x0c, 0x5e, 0xbb, 0x30, 0x2a, 0x00, 0xce, 0x69, 0xe8, 0x94, 0xf6, 0xaa, 0xea, 0x90, 0xac, 0x9a, 0x1f, 0xcc, - 0xe6, 0x4d, 0xc3, 0xc4, 0x88, 0x20, 0xba, 0x08, 0x27, 0x98, 0x5e, 0x91, 0xbe, 0x56, 0x72, 0x3a, 0x5a, 0x75, 0xb4, - 0x96, 0x98, 0x98, 0x2b, 0x8a, 0xbf, 0x06, 0x3c, 0x6e, 0xf0, 0xea, 0x24, 0x4d, 0x27, 0xaa, 0x47, 0x8f, 0x5f, 0xa7, - 0xe9, 0xa4, 0xc4, 0x5d, 0xe1, 0x37, 0xe0, 0xa2, 0xd9, 0xe6, 0x43, 0x3f, 0x7e, 0x41, 0x11, 0x17, 0x35, 0xb8, 0xf2, - 0x4e, 0xf5, 0x95, 0xea, 0x23, 0xa8, 0x85, 0x27, 0x46, 0xd6, 0xc2, 0x93, 0x4b, 0xd6, 0x5a, 0x10, 0xcc, 0x6c, 0x0e, - 0x5c, 0xc8, 0xaf, 0x94, 0x22, 0xde, 0x44, 0x42, 0x2d, 0x06, 0xad, 0xc7, 0xcc, 0x59, 0x35, 0x5a, 0xa8, 0xcc, 0x08, - 0xed, 0xdb, 0x5a, 0x74, 0x7e, 0x23, 0x3f, 0xe5, 0xa9, 0x7d, 0xd9, 0x1e, 0xe7, 0xe3, 0x3d, 0xba, 0xab, 0xce, 0x32, - 0x93, 0x32, 0x3e, 0x99, 0x25, 0x28, 0xdc, 0x25, 0xd8, 0x80, 0x24, 0xfb, 0xb5, 0x0e, 0x90, 0x51, 0x7b, 0xed, 0x77, - 0x9d, 0xe5, 0xab, 0x9b, 0xad, 0xa1, 0xa8, 0xd4, 0x4a, 0x52, 0x1c, 0x64, 0xb8, 0x6e, 0x2b, 0x1f, 0x2e, 0x2e, 0xa0, - 0x67, 0x8c, 0x44, 0xe6, 0xf9, 0x13, 0xf9, 0x12, 0x9c, 0x33, 0xce, 0x0a, 0x81, 0x09, 0x63, 0xf5, 0xae, 0xb5, 0x54, - 0x1a, 0x52, 0x8c, 0x1d, 0x8d, 0xb2, 0xac, 0xb2, 0x74, 0x99, 0xad, 0x25, 0x6c, 0x59, 0x4e, 0x6e, 0x61, 0xcb, 0x4c, - 0x56, 0xf3, 0x7d, 0xc5, 0x1d, 0x94, 0x6f, 0xb6, 0xce, 0xf8, 0x5e, 0x22, 0x7b, 0xb7, 0x81, 0x12, 0x5e, 0x8c, 0xfe, - 0x82, 0xf4, 0xdb, 0x0c, 0xe3, 0x94, 0xdb, 0x4a, 0x5a, 0x80, 0xd3, 0x3f, 0x1c, 0xde, 0x57, 0x18, 0x34, 0x38, 0xc2, - 0x38, 0xb2, 0x7e, 0xff, 0xb6, 0xf2, 0x6a, 0x4c, 0xd4, 0xf1, 0x59, 0xfd, 0x7e, 0x45, 0x0f, 0xa7, 0xd5, 0x68, 0x95, - 0x6e, 0x91, 0x9d, 0xd0, 0xc6, 0xca, 0x0f, 0x6a, 0x05, 0xcc, 0xde, 0xfa, 0x7c, 0x3a, 0x00, 0x1d, 0x0b, 0x90, 0x68, - 0x36, 0x13, 0x89, 0x39, 0xe9, 0x9e, 0x84, 0xc7, 0x07, 0x16, 0x38, 0xc0, 0x54, 0xfc, 0x9f, 0xc2, 0x9b, 0x81, 0x0d, - 0x1a, 0x25, 0xfa, 0x1a, 0x5d, 0xd5, 0xe6, 0x46, 0xc7, 0x4b, 0x4f, 0x21, 0x91, 0x15, 0xac, 0x9a, 0xfb, 0x72, 0x03, - 0xa7, 0x3d, 0xd4, 0x1c, 0x2a, 0x4b, 0xf0, 0xb7, 0x5f, 0xe6, 0x87, 0xc3, 0x3a, 0x83, 0xc2, 0x76, 0x6b, 0xa1, 0xbd, - 0x31, 0x4b, 0x35, 0x54, 0x84, 0x83, 0xce, 0x57, 0x62, 0x56, 0x8f, 0xe8, 0xef, 0xf9, 0xe1, 0xb0, 0x22, 0x30, 0xe0, - 0xb0, 0x94, 0x99, 0x68, 0xa1, 0x58, 0x5a, 0x67, 0x33, 0xaa, 0x03, 0x0f, 0x4c, 0xcc, 0x59, 0xb8, 0x03, 0xd0, 0x26, - 0xb5, 0x0a, 0xf4, 0x2a, 0xa2, 0x9f, 0xb8, 0x5f, 0xdb, 0xaf, 0xd7, 0x23, 0xb3, 0x74, 0xe4, 0xc6, 0x58, 0x00, 0x70, - 0xe0, 0x79, 0x4d, 0xf2, 0x9c, 0x7c, 0x0d, 0xed, 0x9e, 0x5c, 0xc8, 0x9f, 0xa0, 0x6c, 0xe1, 0xb9, 0x6a, 0x5a, 0x59, - 0xac, 0xb8, 0xaa, 0x5e, 0x5d, 0xf0, 0xca, 0x64, 0x5a, 0xa5, 0x95, 0xa8, 0x94, 0x60, 0x40, 0x5d, 0xe2, 0xb5, 0xa6, - 0x19, 0xa5, 0x36, 0xea, 0x4c, 0xd4, 0x80, 0x0d, 0xf6, 0x53, 0xb5, 0xd1, 0xc9, 0xb9, 0x7c, 0x7e, 0x69, 0x1c, 0x3e, - 0xed, 0xea, 0xcd, 0x4c, 0xe5, 0xc0, 0x5f, 0x2b, 0x1f, 0x5a, 0x3d, 0x06, 0x3a, 0x20, 0xa7, 0x3f, 0x86, 0xc5, 0xc4, - 0xee, 0xd0, 0xbc, 0xdd, 0x5d, 0x56, 0x17, 0xe9, 0x9d, 0xa6, 0x64, 0x56, 0x6f, 0xf9, 0xcc, 0xea, 0xd1, 0x01, 0x2f, - 0x1e, 0xeb, 0xbd, 0xc2, 0x4c, 0x22, 0xb8, 0x18, 0xaa, 0x49, 0x64, 0x77, 0xa0, 0x35, 0x8f, 0x2a, 0x26, 0xc0, 0x0f, - 0x4a, 0xad, 0xe9, 0xbd, 0xdd, 0x15, 0xea, 0x94, 0xc2, 0xe3, 0xd6, 0x92, 0x1f, 0x98, 0x3b, 0xed, 0x5a, 0xe7, 0xe3, - 0xf9, 0xa5, 0xef, 0x37, 0xf2, 0x84, 0x36, 0x3b, 0x93, 0xd3, 0x3f, 0x79, 0xab, 0x7f, 0x98, 0xea, 0x5b, 0xe8, 0x4e, - 0xd0, 0x67, 0xe8, 0xaa, 0xea, 0xae, 0xc4, 0x16, 0x86, 0x7a, 0x62, 0x91, 0x17, 0xf2, 0xa4, 0x35, 0x76, 0x1c, 0xec, - 0x0d, 0x70, 0xe2, 0x97, 0x87, 0x83, 0xb8, 0xca, 0x7d, 0x76, 0xde, 0x35, 0xb2, 0x72, 0x00, 0x2b, 0x88, 0x82, 0x71, - 0x6b, 0x3e, 0xb6, 0x41, 0xba, 0xc4, 0xd5, 0xf8, 0xf8, 0x0d, 0xc5, 0x32, 0xd9, 0x44, 0x5c, 0x5c, 0xe4, 0x4f, 0x9f, - 0x03, 0x69, 0x59, 0xbf, 0x1f, 0xbd, 0xb8, 0x9c, 0x3e, 0x1f, 0x46, 0x01, 0x38, 0x76, 0xd9, 0xcb, 0xcb, 0x98, 0xaf, - 0x2e, 0x99, 0x65, 0x0a, 0x8b, 0x7c, 0x33, 0xa0, 0xba, 0x64, 0xb5, 0x74, 0xbd, 0x02, 0x2c, 0x5d, 0x7e, 0xf3, 0x10, - 0xa6, 0x06, 0x34, 0xb2, 0xe6, 0xee, 0x34, 0xd7, 0x02, 0xa5, 0x9e, 0xf7, 0x33, 0x43, 0xbe, 0x2e, 0x83, 0xae, 0x20, - 0xdd, 0xf3, 0x88, 0xf4, 0x72, 0x2f, 0x9d, 0xee, 0xf7, 0xa5, 0x00, 0x4b, 0x7d, 0x29, 0x3e, 0x83, 0xc2, 0xa2, 0xf1, - 0x8d, 0x00, 0x6d, 0x0d, 0xd5, 0xb4, 0x57, 0x8a, 0xaa, 0x17, 0xf4, 0x4a, 0xf1, 0xb9, 0xa7, 0x87, 0xca, 0x7c, 0x59, - 0x3a, 0xfa, 0x9f, 0x50, 0x73, 0xc1, 0x09, 0x31, 0x13, 0x73, 0x00, 0x95, 0xa0, 0x8d, 0x6f, 0x75, 0xb4, 0xf1, 0xa9, - 0x5e, 0xc5, 0x4d, 0x9f, 0xd7, 0xd6, 0x32, 0x27, 0x84, 0x4d, 0xf7, 0x12, 0xa0, 0x22, 0xaf, 0x84, 0x47, 0xb0, 0xfc, - 0xf2, 0x87, 0x3c, 0x5d, 0x21, 0x5a, 0xc7, 0x3d, 0xcb, 0x5c, 0x1a, 0xfb, 0x37, 0x06, 0xd3, 0xd7, 0xb7, 0xdb, 0x22, - 0x3f, 0x35, 0x31, 0x61, 0x3d, 0x56, 0xf4, 0xcd, 0xbb, 0x70, 0x25, 0x50, 0xe0, 0x50, 0x22, 0xb1, 0x4d, 0x15, 0x8a, - 0x78, 0x90, 0xf4, 0xe9, 0xa2, 0xf5, 0x69, 0x80, 0xa9, 0xb5, 0x1c, 0x98, 0x43, 0xb8, 0x8a, 0x0b, 0x1f, 0x3d, 0x7d, - 0x8b, 0x59, 0x38, 0x9f, 0x78, 0x1f, 0xbd, 0x62, 0x64, 0x3e, 0xee, 0xa3, 0x52, 0x49, 0xff, 0x3c, 0x1c, 0x66, 0xd5, - 0xdc, 0x77, 0xe8, 0x23, 0x3d, 0x54, 0xb9, 0xa0, 0xec, 0x8d, 0x31, 0x89, 0x40, 0x69, 0x8c, 0xf7, 0x71, 0x70, 0x9c, - 0xf7, 0x69, 0x00, 0xa9, 0x7d, 0xe2, 0x3d, 0x29, 0x39, 0x3c, 0xe7, 0x98, 0x13, 0x4a, 0x2b, 0xc2, 0x2a, 0xbe, 0xc8, - 0x50, 0xae, 0x3b, 0xa5, 0x60, 0x92, 0x43, 0x82, 0xe1, 0xaf, 0x9a, 0x37, 0xb1, 0x02, 0x61, 0xd7, 0xcc, 0xab, 0xd1, - 0x93, 0x2a, 0x09, 0x4b, 0x01, 0x47, 0x65, 0xe6, 0x19, 0xf6, 0x86, 0x27, 0x86, 0x91, 0x83, 0xe5, 0xfe, 0xa8, 0x4e, - 0x44, 0xee, 0xd1, 0x05, 0x46, 0x65, 0xe1, 0x79, 0x43, 0x57, 0x1a, 0x54, 0x92, 0x1d, 0x7f, 0xc5, 0x35, 0xa0, 0xb6, - 0xc6, 0x88, 0xa1, 0x80, 0x51, 0xf0, 0xda, 0xfe, 0x10, 0xb2, 0x28, 0x5b, 0xbf, 0xc1, 0x31, 0x9f, 0x95, 0xdc, 0xf5, - 0x0e, 0x67, 0xa1, 0x25, 0xe4, 0xc9, 0x1d, 0x83, 0x34, 0x8d, 0xa5, 0x11, 0x70, 0x22, 0x92, 0x6d, 0x2c, 0x85, 0x23, - 0x80, 0x80, 0x40, 0x37, 0x65, 0x86, 0x31, 0x1d, 0x8c, 0x3c, 0x4f, 0x7a, 0xc6, 0x7b, 0x15, 0x9e, 0x42, 0x9a, 0x6c, - 0x5f, 0xcf, 0xdf, 0x1b, 0x41, 0x56, 0x6e, 0x39, 0xc7, 0xc3, 0xe2, 0x1b, 0x67, 0x5f, 0xe5, 0xe4, 0x29, 0x66, 0x19, - 0xe9, 0x9d, 0x62, 0x5e, 0xc0, 0x9f, 0xca, 0x52, 0x9f, 0xa3, 0xf4, 0x96, 0xf9, 0x64, 0x15, 0x49, 0x97, 0xde, 0xa6, - 0xdf, 0x8f, 0x47, 0xea, 0x50, 0xf3, 0xf7, 0xf1, 0x48, 0x9e, 0x61, 0x1b, 0x96, 0xb0, 0xd0, 0x2a, 0x18, 0x03, 0x48, - 0x62, 0x23, 0xa2, 0xc1, 0x68, 0x6f, 0x0e, 0x87, 0xf3, 0x8d, 0x39, 0x4b, 0xf6, 0xe0, 0xfa, 0xca, 0x13, 0xf3, 0x0e, - 0x7c, 0x99, 0xc7, 0x04, 0x11, 0x9b, 0x79, 0x1b, 0x56, 0x83, 0x07, 0x3b, 0xb8, 0x3e, 0x62, 0x8b, 0x62, 0xad, 0x63, - 0xa9, 0xac, 0x83, 0xd3, 0x3a, 0x36, 0xcd, 0x48, 0x29, 0xb2, 0xcf, 0xb1, 0xbf, 0x77, 0x83, 0xab, 0x6b, 0x63, 0x50, - 0x6b, 0xdc, 0x61, 0xee, 0x9c, 0x0a, 0xa8, 0xc7, 0x74, 0x05, 0xd5, 0xb3, 0x9c, 0x7c, 0xf9, 0xad, 0x9d, 0x03, 0x82, - 0x46, 0x20, 0x70, 0xd1, 0x40, 0xab, 0x76, 0x29, 0xe7, 0x5d, 0x40, 0x88, 0x6f, 0x52, 0xd0, 0xa7, 0x33, 0xd8, 0xc4, - 0xe6, 0x13, 0x88, 0x45, 0xd3, 0x7d, 0xae, 0x35, 0xf3, 0xc5, 0x88, 0x76, 0x66, 0xdd, 0x2d, 0x72, 0xab, 0x85, 0x48, - 0x46, 0xcf, 0x36, 0x13, 0x2e, 0x3a, 0x94, 0x33, 0x12, 0x30, 0x41, 0x6b, 0x2b, 0x25, 0x9f, 0xeb, 0x5e, 0x27, 0x68, - 0x0f, 0x24, 0xad, 0xfb, 0x37, 0x8b, 0xce, 0x28, 0x39, 0xb9, 0xde, 0xe4, 0x0c, 0x52, 0xb0, 0x60, 0x7b, 0x99, 0x13, - 0x6e, 0x80, 0x4f, 0x6c, 0x96, 0x9c, 0xa6, 0x41, 0x1e, 0x0b, 0xe3, 0x91, 0xd7, 0xe6, 0x97, 0x05, 0x74, 0x28, 0x59, - 0x34, 0x42, 0x3c, 0xc0, 0xce, 0x21, 0xb9, 0x2a, 0x50, 0x37, 0x0d, 0x74, 0xe5, 0xca, 0x99, 0x62, 0x0a, 0x5c, 0x08, - 0x05, 0x51, 0x3b, 0x3a, 0x89, 0xca, 0x79, 0x9f, 0x54, 0x97, 0xf9, 0xb4, 0x90, 0xa6, 0x81, 0x7c, 0x5a, 0x39, 0xe6, - 0x81, 0x9d, 0x6d, 0x5c, 0x13, 0x18, 0xe8, 0xd4, 0xbe, 0x16, 0xe5, 0x1c, 0xab, 0x88, 0xde, 0xe7, 0x1f, 0x2a, 0x7b, - 0xfa, 0x20, 0xc2, 0x46, 0x05, 0x1a, 0x4b, 0x89, 0xb1, 0x91, 0xe3, 0xdf, 0x12, 0x65, 0x43, 0x86, 0x80, 0x10, 0xd2, - 0x46, 0x4e, 0x3f, 0xac, 0x2f, 0x6f, 0x33, 0xed, 0xff, 0x49, 0xe2, 0xb7, 0xc1, 0x5e, 0x4e, 0xfd, 0xa9, 0x47, 0x3c, - 0x5e, 0x6b, 0xf4, 0x98, 0x92, 0x6e, 0x83, 0x3c, 0x55, 0x9e, 0x82, 0x64, 0xc2, 0x58, 0x42, 0xb0, 0x28, 0x17, 0x3c, - 0xe7, 0x15, 0x97, 0x70, 0x1f, 0xb5, 0xac, 0x88, 0x50, 0x95, 0xc8, 0xe9, 0xf3, 0x15, 0xf0, 0x4c, 0x40, 0xa0, 0x63, - 0x8c, 0x34, 0xaa, 0xe0, 0x4b, 0x60, 0xac, 0x03, 0x65, 0xa7, 0x19, 0x09, 0x2e, 0xbb, 0x37, 0x48, 0x94, 0xfa, 0x9a, - 0x94, 0xa4, 0xd7, 0xa2, 0xc6, 0x2b, 0xb1, 0x8a, 0x48, 0x20, 0x43, 0x0d, 0x11, 0xab, 0xea, 0xa9, 0x7b, 0x55, 0x4c, - 0x06, 0x83, 0xca, 0x97, 0xd3, 0x13, 0x6f, 0x68, 0xa8, 0xbc, 0xeb, 0x8a, 0x76, 0x7a, 0xa2, 0x95, 0xf2, 0x16, 0xd2, - 0x12, 0x34, 0x0d, 0x23, 0xcd, 0xa1, 0xd4, 0x95, 0x74, 0x37, 0x06, 0xf1, 0x25, 0x13, 0x3d, 0xdb, 0xa9, 0x1d, 0xa5, - 0x2d, 0x69, 0x0f, 0x21, 0x3d, 0x77, 0xc9, 0xc7, 0x2c, 0xe4, 0xea, 0x4e, 0x39, 0x29, 0xaf, 0x42, 0x74, 0x72, 0xdf, - 0x63, 0x48, 0x04, 0xfa, 0x9c, 0x63, 0x58, 0x17, 0x0d, 0x75, 0x0e, 0x2b, 0xc4, 0x6c, 0xa1, 0x84, 0xf9, 0x92, 0xf1, - 0x54, 0x32, 0x68, 0x00, 0x64, 0xc0, 0x67, 0x2f, 0x03, 0xcb, 0x5f, 0x41, 0xfc, 0x68, 0xe3, 0xc3, 0xe1, 0xcf, 0x9a, - 0x42, 0x6c, 0xff, 0x84, 0xcd, 0x10, 0x1e, 0xd5, 0x03, 0x9e, 0xf9, 0x26, 0x4e, 0xd0, 0x0a, 0x48, 0xca, 0xec, 0x68, - 0x22, 0x7b, 0xd5, 0x43, 0x38, 0x95, 0x15, 0xa8, 0xa3, 0xac, 0xb3, 0x12, 0x7e, 0x84, 0xa9, 0x6e, 0x25, 0xd6, 0x02, - 0x6d, 0xae, 0x56, 0xac, 0x05, 0x70, 0xe0, 0xe7, 0x10, 0x3c, 0x91, 0xcf, 0xc1, 0xc5, 0xa0, 0x00, 0x9f, 0x03, 0xe0, - 0x45, 0xee, 0xc2, 0x83, 0x79, 0x64, 0x59, 0x8d, 0x30, 0x1c, 0x55, 0xc4, 0xfa, 0x35, 0xdb, 0x91, 0x0f, 0xdc, 0x8e, - 0xf1, 0xb9, 0xf6, 0x58, 0xb2, 0x1c, 0x8c, 0x32, 0xf7, 0x6a, 0x89, 0x9e, 0x37, 0x69, 0xdc, 0x8c, 0x9e, 0xec, 0x6b, - 0xf9, 0xbf, 0xa0, 0x97, 0x41, 0x7f, 0x0b, 0xb7, 0xbc, 0xe6, 0x77, 0x0b, 0x22, 0xcd, 0xf4, 0x0a, 0x22, 0x65, 0xd4, - 0x88, 0x8c, 0x21, 0x6c, 0x52, 0xdd, 0xdc, 0x26, 0xd5, 0x85, 0x80, 0xa7, 0x23, 0x52, 0x5d, 0x0b, 0x69, 0x23, 0x9f, - 0xd6, 0x81, 0x8c, 0x45, 0x7a, 0xf7, 0xc3, 0xdf, 0x5e, 0x7e, 0x7a, 0xfb, 0xcb, 0x0f, 0x8b, 0xb7, 0xef, 0xde, 0xbc, - 0x7d, 0xf7, 0xf6, 0xd3, 0x6f, 0x04, 0xe1, 0x31, 0x15, 0x2a, 0xc3, 0x87, 0xf7, 0x37, 0x6f, 0x9d, 0x0c, 0xb6, 0x37, - 0x43, 0xd6, 0xbe, 0x91, 0x83, 0x21, 0x10, 0xd9, 0x20, 0x64, 0x90, 0x9d, 0xda, 0xf6, 0x67, 0x62, 0x8e, 0xb1, 0x77, - 0x02, 0x93, 0x2d, 0xe0, 0x1c, 0xcb, 0xbc, 0x64, 0x44, 0xae, 0x0a, 0xad, 0x1f, 0xd0, 0x82, 0x6b, 0x70, 0x91, 0x49, - 0xf3, 0xbb, 0x5f, 0x08, 0x62, 0x9f, 0x56, 0x52, 0xee, 0xab, 0x6d, 0xcd, 0xf3, 0xed, 0xfd, 0x5e, 0xc2, 0xf9, 0xcf, - 0xa5, 0x11, 0xb5, 0x00, 0x07, 0xe0, 0x73, 0xf8, 0xe3, 0x4a, 0x5b, 0xd2, 0x64, 0x16, 0xed, 0x67, 0x0c, 0x41, 0x97, - 0x06, 0x1f, 0xc4, 0x1e, 0x79, 0xa9, 0x4f, 0x16, 0x12, 0xb8, 0x23, 0x86, 0x4f, 0x2b, 0x82, 0x5e, 0x31, 0xa2, 0xb8, - 0xe4, 0x0a, 0x95, 0x52, 0xf2, 0x6f, 0x94, 0x5d, 0x54, 0xc8, 0x59, 0xc1, 0xee, 0x15, 0x39, 0x32, 0x7e, 0x10, 0x4c, - 0x7c, 0x39, 0xb8, 0xff, 0x12, 0xef, 0x70, 0xa6, 0x38, 0x92, 0x13, 0xfe, 0x90, 0x61, 0x60, 0x7f, 0x0e, 0x3e, 0xaf, - 0x0e, 0xf3, 0xf2, 0x46, 0x9f, 0x72, 0x4b, 0x3e, 0x9e, 0x2c, 0xaf, 0xc0, 0x60, 0xbf, 0x54, 0xcd, 0x5d, 0xf3, 0x7a, - 0xb6, 0x9c, 0xb3, 0xfd, 0x2c, 0x9a, 0x07, 0x77, 0x6c, 0x96, 0xcd, 0x83, 0x55, 0xc3, 0xd7, 0xec, 0x96, 0xaf, 0xad, - 0xaa, 0xad, 0xed, 0xaa, 0x4d, 0x36, 0xfc, 0x16, 0x24, 0x84, 0x9b, 0xcc, 0x03, 0xde, 0xe3, 0x3b, 0x9f, 0x6d, 0x40, - 0xa2, 0x5d, 0xb1, 0x0d, 0x5c, 0xc4, 0xd6, 0xfc, 0x87, 0xca, 0xdb, 0xb0, 0x92, 0x9d, 0x8f, 0x59, 0x8e, 0xf3, 0xcf, - 0x87, 0x07, 0xb4, 0x17, 0xea, 0x67, 0x97, 0xea, 0xd9, 0x44, 0xd9, 0xcd, 0x36, 0xa3, 0xc5, 0x7d, 0x5a, 0x6d, 0xc2, - 0x0c, 0x3d, 0xcb, 0xe1, 0xa3, 0xad, 0x14, 0xfc, 0xf4, 0x02, 0xbf, 0x64, 0x47, 0x6d, 0xa5, 0x6d, 0xbb, 0x2a, 0xb1, - 0x15, 0xb4, 0x28, 0xb2, 0x5a, 0xe1, 0x81, 0x39, 0x7f, 0x01, 0x0b, 0x18, 0x7b, 0x8e, 0x73, 0x5e, 0xfb, 0x23, 0x64, - 0xbc, 0x77, 0x00, 0xd0, 0x32, 0xc7, 0x01, 0x1e, 0xb1, 0x62, 0x14, 0x0d, 0xde, 0xf9, 0xa5, 0xb2, 0x5a, 0x69, 0x4e, - 0x42, 0xdb, 0x88, 0x55, 0xcb, 0x91, 0xaa, 0x19, 0x91, 0x3e, 0x48, 0xcf, 0xfb, 0x1e, 0x51, 0x0d, 0xf6, 0x64, 0x5e, - 0x07, 0xf6, 0xe9, 0x55, 0x6b, 0x55, 0x77, 0x7e, 0x4f, 0x95, 0x2e, 0x39, 0xb2, 0xe5, 0xa7, 0xcb, 0xf0, 0x41, 0xfd, - 0x29, 0xb9, 0x3e, 0x14, 0x38, 0xc2, 0x63, 0x15, 0x70, 0xbe, 0x5e, 0x89, 0x76, 0x27, 0xc2, 0xae, 0x5c, 0x02, 0x42, - 0x7c, 0x49, 0xd3, 0x1c, 0x8f, 0x23, 0x9a, 0x88, 0xb0, 0x89, 0xd1, 0x5f, 0xd8, 0x7d, 0x28, 0xb1, 0x9c, 0xe7, 0x1a, - 0x94, 0x5c, 0x32, 0x78, 0x4f, 0xda, 0x6b, 0xd0, 0x2c, 0xaf, 0x4a, 0x4d, 0x26, 0x72, 0x50, 0x3e, 0x1c, 0x0a, 0xd8, - 0x4b, 0x8d, 0x9f, 0x26, 0xfc, 0x84, 0xe5, 0xad, 0xbd, 0x35, 0xa5, 0xa8, 0xa4, 0x01, 0x2a, 0xf0, 0x31, 0x83, 0xff, - 0xdd, 0x19, 0x62, 0xc1, 0x14, 0x1d, 0x3f, 0x9c, 0x89, 0xb9, 0xf5, 0xdc, 0x2a, 0xeb, 0x28, 0x5b, 0xa3, 0x9c, 0x80, - 0x7f, 0x4b, 0x75, 0x9c, 0x24, 0xc2, 0xa9, 0xf7, 0x88, 0x8b, 0xba, 0x97, 0x43, 0xd4, 0x0d, 0x7b, 0x5b, 0xe9, 0x60, - 0xcb, 0x69, 0x1a, 0x1c, 0x89, 0x5f, 0xa9, 0xcf, 0xde, 0x67, 0x16, 0x8f, 0x3a, 0xb2, 0x11, 0x25, 0x69, 0x1c, 0x8b, - 0x1c, 0xb6, 0xf7, 0x85, 0xdc, 0xff, 0xfb, 0x7d, 0x08, 0x27, 0xad, 0x82, 0xa4, 0xf4, 0x04, 0x22, 0xc2, 0xd1, 0xe1, - 0x47, 0x84, 0x27, 0x52, 0x55, 0xf8, 0xa4, 0x3e, 0x71, 0x63, 0x76, 0x2f, 0xcc, 0x51, 0xbd, 0x05, 0x18, 0xc6, 0x7a, - 0x6b, 0x11, 0x92, 0x68, 0xa5, 0x19, 0x6d, 0x3d, 0x20, 0x46, 0xbc, 0x5f, 0x5b, 0x64, 0x30, 0xd6, 0x96, 0x44, 0x02, - 0xf8, 0x1d, 0x09, 0x19, 0xda, 0x36, 0x02, 0x33, 0x86, 0xb7, 0xb3, 0xe2, 0xd2, 0x75, 0xd8, 0xe6, 0x1c, 0xbe, 0x90, - 0x85, 0x66, 0x1d, 0x51, 0x9a, 0x20, 0xe4, 0x1f, 0x70, 0xb2, 0x50, 0x18, 0xcd, 0xeb, 0xa3, 0x74, 0x92, 0x58, 0xdf, - 0x77, 0x95, 0x0a, 0x36, 0x9b, 0x1b, 0xd4, 0x97, 0x1d, 0x25, 0xbf, 0x02, 0x27, 0x1d, 0x27, 0x59, 0xe4, 0x20, 0x6a, - 0x51, 0x39, 0x37, 0x49, 0x58, 0xda, 0xd5, 0xa9, 0x36, 0xeb, 0x75, 0x51, 0xd6, 0xd5, 0x6b, 0x11, 0x29, 0x7a, 0x1f, - 0xf5, 0xe8, 0x89, 0x84, 0x54, 0x68, 0x55, 0x6a, 0x97, 0x47, 0xe0, 0xb6, 0xa9, 0x15, 0xdb, 0x72, 0x09, 0x4b, 0xd4, - 0xf8, 0x4f, 0xd0, 0x47, 0xb9, 0x78, 0x90, 0x01, 0x1a, 0x1d, 0x4f, 0xcd, 0x5b, 0x8f, 0xbc, 0x72, 0x94, 0x5f, 0x5a, - 0x6d, 0xd2, 0x2f, 0x80, 0xcc, 0x68, 0xff, 0x68, 0x29, 0x81, 0xcc, 0xc0, 0x4c, 0x5a, 0x1a, 0x12, 0x39, 0x8a, 0x59, - 0x9a, 0xff, 0x81, 0x2b, 0xb6, 0x42, 0xa4, 0x61, 0x35, 0xf7, 0xf8, 0xcb, 0xca, 0xab, 0xe5, 0x5a, 0x66, 0x9a, 0x9b, - 0x25, 0x8e, 0x15, 0x8b, 0x8b, 0x7a, 0x5d, 0x89, 0x2c, 0x10, 0xe2, 0x08, 0xd3, 0x58, 0x4f, 0xbd, 0x51, 0x5a, 0x7d, - 0x40, 0x42, 0x99, 0x1f, 0xb0, 0xb7, 0x63, 0xaf, 0x07, 0x59, 0x88, 0x63, 0xcb, 0xc1, 0x66, 0xeb, 0x7d, 0x2a, 0x53, - 0x11, 0x9f, 0xd5, 0xc5, 0xd9, 0xa6, 0x12, 0x67, 0x75, 0x22, 0xce, 0xbe, 0x83, 0x9c, 0xdf, 0x9d, 0x51, 0xd1, 0x67, - 0x0f, 0x69, 0x9d, 0x14, 0x9b, 0x9a, 0x9e, 0xbc, 0xc1, 0x32, 0xbe, 0x3b, 0x23, 0xae, 0x9a, 0x33, 0x1a, 0xc9, 0x78, - 0x74, 0xf6, 0x21, 0x03, 0x92, 0xd7, 0xb3, 0x74, 0x05, 0x83, 0x77, 0x16, 0xe6, 0xf1, 0x59, 0x29, 0xee, 0xc0, 0xe2, - 0x54, 0x76, 0xbe, 0x07, 0x19, 0x56, 0xe1, 0x1f, 0xe2, 0x0c, 0xa0, 0x5d, 0xcf, 0xd2, 0xfa, 0x2c, 0xad, 0xce, 0xf2, - 0xa2, 0x3e, 0x53, 0x52, 0x38, 0x84, 0xf1, 0xc3, 0x7b, 0xfa, 0xca, 0x2e, 0x6f, 0xb3, 0xb8, 0xcb, 0x22, 0x7f, 0x8a, - 0x5e, 0x45, 0xc4, 0xa4, 0x51, 0x09, 0xaf, 0xdd, 0xdf, 0x36, 0xf7, 0x0f, 0xaf, 0x1b, 0xbb, 0x9f, 0xdd, 0x31, 0xa2, - 0x0b, 0xea, 0xf1, 0x4a, 0x52, 0x2a, 0x28, 0x20, 0x70, 0xa2, 0x59, 0xe3, 0xc1, 0x1d, 0x07, 0xbc, 0x1a, 0xd8, 0x92, - 0xad, 0x7d, 0xfe, 0x22, 0x96, 0x61, 0xda, 0x9b, 0x00, 0xff, 0x2a, 0x7b, 0xd3, 0x75, 0xb0, 0xc4, 0xfb, 0x16, 0xb2, - 0x0d, 0xbd, 0x7d, 0xcd, 0x5f, 0x7a, 0xb9, 0xfa, 0x9b, 0xfd, 0x13, 0x80, 0x30, 0x20, 0x66, 0xd5, 0x47, 0x13, 0xf7, - 0xce, 0xca, 0xb2, 0x73, 0xb2, 0xec, 0x7a, 0xe8, 0xd7, 0x24, 0x46, 0xa5, 0x95, 0xa5, 0x74, 0xb2, 0x94, 0x90, 0x05, - 0x7c, 0x62, 0x34, 0xb5, 0x11, 0x40, 0xd8, 0x8e, 0x52, 0xf9, 0x42, 0xe5, 0x45, 0x14, 0xce, 0x09, 0x9e, 0x27, 0x62, - 0x74, 0x6f, 0x25, 0x03, 0x86, 0x43, 0x08, 0xe6, 0xa0, 0x2d, 0xf6, 0x86, 0x6e, 0x22, 0xfe, 0x7a, 0x53, 0x94, 0x6f, - 0x63, 0xf2, 0x29, 0xd8, 0x9d, 0x7c, 0x5c, 0xc2, 0xe3, 0xf2, 0xe4, 0xe3, 0x10, 0x3d, 0x12, 0x4e, 0x3e, 0x06, 0xdf, - 0x23, 0x39, 0xaf, 0xbb, 0x1e, 0x27, 0xc8, 0x2d, 0xa4, 0xfb, 0xdb, 0x31, 0x09, 0xd0, 0xbc, 0x86, 0xe5, 0xa8, 0xa9, - 0xb8, 0x66, 0x66, 0x8c, 0xe7, 0x8d, 0xde, 0x1f, 0x3b, 0xde, 0x32, 0x85, 0x62, 0x16, 0xf3, 0x1a, 0x7e, 0xcf, 0xaa, - 0x40, 0xdd, 0xf5, 0x36, 0xc9, 0x2d, 0xb3, 0x7a, 0x8e, 0x76, 0xdf, 0xf7, 0x75, 0x22, 0xa8, 0xfd, 0x1d, 0xf6, 0x3c, - 0xb3, 0xde, 0x55, 0x31, 0x70, 0xa9, 0x92, 0x1d, 0x32, 0x55, 0x4d, 0x0f, 0x54, 0x4a, 0x83, 0xa7, 0x97, 0xd6, 0xe5, - 0x4b, 0xa5, 0x8d, 0x3c, 0xd3, 0xfc, 0x06, 0xf0, 0x62, 0xea, 0xb2, 0xd8, 0x7d, 0x75, 0x5f, 0xc1, 0x6d, 0xbc, 0xdf, - 0x5f, 0x56, 0x9e, 0xf9, 0x89, 0x0b, 0xc0, 0xde, 0x54, 0x68, 0x9d, 0x40, 0xa9, 0x61, 0x1d, 0xbe, 0x4a, 0x44, 0xf4, - 0x47, 0xbb, 0x5c, 0x67, 0xae, 0x03, 0x46, 0x14, 0xf1, 0xdb, 0x78, 0xf4, 0x07, 0x28, 0xae, 0x8d, 0x3d, 0x20, 0xac, - 0x43, 0x42, 0x9f, 0x11, 0x80, 0xd4, 0x63, 0x8e, 0x12, 0xd0, 0xac, 0x68, 0xee, 0x98, 0xfc, 0x5c, 0x5f, 0x29, 0xfd, - 0xfd, 0xb2, 0xf2, 0xc8, 0x9c, 0xd2, 0x36, 0xd3, 0x58, 0xad, 0xa9, 0x04, 0xc2, 0x2b, 0x2a, 0x59, 0x85, 0xcf, 0xe6, - 0x8d, 0xe8, 0xf7, 0xe5, 0x11, 0x9e, 0x56, 0x3f, 0x6c, 0x31, 0xbe, 0x15, 0x10, 0x8d, 0x04, 0x40, 0x3f, 0x01, 0xcc, - 0x8b, 0x6c, 0x66, 0xf7, 0x71, 0x40, 0x95, 0x12, 0x4d, 0xe3, 0x6c, 0x9e, 0xdf, 0xd2, 0x9b, 0xb2, 0x83, 0x4e, 0x9d, - 0x2a, 0x70, 0xc1, 0x55, 0xc9, 0x78, 0x65, 0x3d, 0x91, 0xcf, 0x6f, 0x6e, 0x37, 0x69, 0x16, 0xbf, 0x2f, 0xff, 0x89, - 0x63, 0xab, 0xeb, 0xf0, 0xc8, 0xd4, 0xe9, 0xda, 0x79, 0xa4, 0xb5, 0x17, 0x02, 0x22, 0xda, 0x35, 0xd4, 0x7a, 0x61, - 0xa1, 0x47, 0x7a, 0x22, 0x9c, 0x93, 0x44, 0x4d, 0x3b, 0xd0, 0xd2, 0x08, 0x7d, 0x7d, 0xcd, 0xe9, 0x2f, 0x0c, 0xd6, - 0x3e, 0x1f, 0x33, 0x20, 0x2b, 0xd1, 0x8f, 0xd5, 0x43, 0x63, 0x33, 0x87, 0x9e, 0xb5, 0x2a, 0xcf, 0xbc, 0xea, 0x70, - 0x40, 0x7c, 0x18, 0xfd, 0x25, 0xbf, 0xdf, 0x7f, 0x4d, 0xf3, 0x8f, 0x09, 0x35, 0x7e, 0xb6, 0x19, 0xa0, 0x6b, 0xdf, - 0x95, 0x07, 0xa2, 0x9e, 0x6b, 0x95, 0x20, 0xc4, 0x1b, 0xc4, 0x44, 0x33, 0x62, 0x0e, 0x4e, 0x3b, 0xd4, 0xfc, 0x93, - 0xd4, 0x80, 0x10, 0x25, 0x5e, 0xc7, 0x94, 0x05, 0x39, 0x6d, 0xe2, 0x48, 0x3f, 0x0a, 0x27, 0xf2, 0xa3, 0xa8, 0x8a, - 0xec, 0x1e, 0x2e, 0x18, 0x4c, 0xbd, 0xa7, 0xfd, 0x12, 0xfd, 0x96, 0x70, 0xe4, 0x1c, 0xad, 0x0a, 0x41, 0xe4, 0x84, - 0xb0, 0xd6, 0x10, 0x26, 0x88, 0x0d, 0xe2, 0x65, 0xdf, 0x25, 0x19, 0x8e, 0x14, 0x5c, 0xd6, 0xb1, 0x63, 0xcc, 0xd5, - 0x51, 0xf5, 0x1a, 0xc0, 0x78, 0xe5, 0x08, 0x9a, 0x8d, 0x22, 0xbb, 0x84, 0xa8, 0x22, 0xc7, 0x13, 0x50, 0x3b, 0x28, - 0x8d, 0xcd, 0xf4, 0x7c, 0x1c, 0xe4, 0xa3, 0x45, 0x85, 0x3a, 0x27, 0x96, 0xf1, 0x1a, 0x80, 0xb5, 0x73, 0xd5, 0xcf, - 0xb3, 0x1a, 0x3c, 0x69, 0x88, 0xcf, 0xc7, 0x68, 0x7b, 0x65, 0x73, 0x50, 0x6d, 0xa7, 0xb3, 0xf2, 0x8a, 0xe9, 0x72, - 0x60, 0xdc, 0x37, 0xbc, 0xa2, 0x38, 0xc3, 0x8f, 0x1e, 0x6c, 0x71, 0xfe, 0x74, 0x43, 0xed, 0xc7, 0xdc, 0xa8, 0x87, - 0x81, 0xd6, 0x82, 0x37, 0x05, 0xb1, 0xfe, 0x7e, 0xe8, 0xc8, 0xf6, 0x5e, 0x8b, 0x8c, 0x26, 0x9f, 0xfd, 0xfc, 0x43, - 0x99, 0xae, 0x52, 0xb8, 0x2f, 0x39, 0x59, 0x34, 0xf3, 0x10, 0xd8, 0x1b, 0x62, 0xb8, 0x3e, 0x2a, 0x3c, 0xa2, 0xac, - 0xdf, 0x87, 0xdf, 0x57, 0x19, 0x98, 0x62, 0xe0, 0xba, 0x42, 0x30, 0x1e, 0x02, 0x41, 0x3c, 0x4c, 0xa3, 0x93, 0x41, - 0x0d, 0xda, 0xf0, 0x0d, 0x40, 0x66, 0x80, 0x47, 0xe6, 0xd2, 0x23, 0xe0, 0x2e, 0x70, 0xed, 0xc9, 0x78, 0xec, 0x4f, - 0x4c, 0x43, 0xa3, 0xa6, 0x34, 0xd3, 0x73, 0xe3, 0x37, 0x1d, 0xd5, 0x72, 0xed, 0xfc, 0xc7, 0x97, 0xfc, 0x06, 0xbd, - 0xa0, 0xe5, 0xe5, 0x3e, 0x52, 0x97, 0xfb, 0x8c, 0xe2, 0x32, 0x91, 0x1c, 0x16, 0xc4, 0xb2, 0x84, 0x03, 0x8f, 0x51, - 0xc9, 0x62, 0x4b, 0x8f, 0x55, 0xd1, 0xf2, 0x45, 0xb9, 0x41, 0x3a, 0x74, 0x42, 0xb0, 0x44, 0x05, 0xc1, 0x12, 0x18, - 0x17, 0xb1, 0xe6, 0x9b, 0x41, 0xce, 0xe2, 0xd9, 0x66, 0xce, 0x91, 0xb0, 0x2e, 0x39, 0x1c, 0x0a, 0x09, 0x36, 0x93, - 0xcd, 0xd6, 0x73, 0xb6, 0xf6, 0x19, 0x28, 0x01, 0x4a, 0x99, 0x26, 0x28, 0x4d, 0x2b, 0xb6, 0xe2, 0xa6, 0x35, 0x58, - 0xad, 0xa6, 0x6c, 0x55, 0x53, 0x76, 0x4e, 0x53, 0x8e, 0x2a, 0x28, 0x39, 0xa1, 0x14, 0x65, 0x18, 0xc0, 0x88, 0x4d, - 0xa2, 0xab, 0x0c, 0x7d, 0xbc, 0x13, 0x1e, 0x41, 0x15, 0x11, 0xf9, 0x84, 0x21, 0x04, 0x26, 0xa2, 0xb8, 0x50, 0x85, - 0x62, 0x80, 0x8c, 0x48, 0x20, 0x98, 0xa8, 0xd4, 0x29, 0x30, 0x1f, 0x4d, 0x15, 0xc3, 0xa6, 0x3d, 0x51, 0xbe, 0xa5, - 0x8e, 0x7b, 0x94, 0x6d, 0xfe, 0x2e, 0x76, 0x41, 0x88, 0xdc, 0x8d, 0x3b, 0xf5, 0x33, 0xe2, 0xbd, 0xdd, 0x11, 0xc6, - 0x4f, 0x76, 0xdc, 0x22, 0x5c, 0x11, 0x6c, 0xa9, 0xe6, 0x10, 0x8b, 0x79, 0x35, 0x49, 0x50, 0xcb, 0x92, 0xf8, 0x1b, - 0x9e, 0x0c, 0x72, 0xb6, 0x04, 0x0f, 0xda, 0x39, 0xcb, 0x00, 0x7f, 0xc5, 0x6a, 0xd1, 0x6f, 0xb5, 0xb7, 0x04, 0xf9, - 0x69, 0x63, 0x37, 0x0a, 0x13, 0x23, 0x48, 0xd4, 0xed, 0xca, 0x40, 0x7e, 0xf8, 0x80, 0xd3, 0xf1, 0xd8, 0x53, 0xc6, - 0xdc, 0xca, 0xf4, 0x32, 0x9d, 0x2b, 0xf9, 0x46, 0xee, 0xa5, 0x8f, 0xbd, 0x04, 0x3b, 0x07, 0xbc, 0x81, 0xb4, 0x81, - 0x37, 0xb0, 0x5d, 0x78, 0x6d, 0x90, 0x30, 0x23, 0xc0, 0x16, 0xc7, 0xc7, 0x48, 0x09, 0x0c, 0xe1, 0x38, 0x4b, 0x01, - 0x98, 0x46, 0x5f, 0x66, 0x2b, 0xfb, 0x32, 0xab, 0x35, 0x5b, 0x2a, 0xa7, 0x7b, 0xe7, 0xd6, 0xed, 0x7c, 0x22, 0x01, - 0xc0, 0xa4, 0xce, 0x81, 0x38, 0x33, 0xc1, 0x2e, 0x4d, 0x22, 0xcb, 0xc7, 0x30, 0xbf, 0x13, 0x6f, 0xca, 0x62, 0xa5, - 0xba, 0xa2, 0xed, 0x33, 0x93, 0xcf, 0x48, 0x27, 0xa1, 0x02, 0x0a, 0x0a, 0xb9, 0xd6, 0xa7, 0xef, 0xc2, 0x77, 0x41, - 0xa1, 0x81, 0xd9, 0x2a, 0xdc, 0xd3, 0x64, 0x8d, 0xd4, 0x1b, 0x55, 0xbf, 0x4f, 0xae, 0x81, 0x54, 0x67, 0x0e, 0x2d, - 0x7b, 0x52, 0x61, 0x80, 0xd8, 0x51, 0x9f, 0x91, 0x50, 0x07, 0x52, 0x0f, 0x18, 0x42, 0xb4, 0x4d, 0x1f, 0x7f, 0x32, - 0x24, 0xba, 0x00, 0x5b, 0x88, 0x36, 0xf0, 0xe3, 0x4f, 0xb0, 0xcf, 0x82, 0xf0, 0x98, 0xe6, 0xd7, 0x90, 0x74, 0x6c, - 0xe0, 0xb4, 0xfa, 0x14, 0x7c, 0x90, 0xe4, 0x60, 0xa2, 0x0e, 0x5e, 0xee, 0x2f, 0xfd, 0x3e, 0x6c, 0xd9, 0xb9, 0x94, - 0xea, 0x58, 0xa9, 0xb7, 0x6d, 0xed, 0x07, 0xd1, 0x16, 0x1c, 0x59, 0xc4, 0xdf, 0x67, 0x88, 0x08, 0x66, 0x06, 0x11, - 0x76, 0x2d, 0xd4, 0xdd, 0x9e, 0x52, 0xcb, 0xa2, 0xde, 0xf6, 0x94, 0x52, 0xb7, 0x61, 0xf8, 0x6e, 0x82, 0x99, 0xe2, - 0x86, 0xff, 0x91, 0x79, 0xa1, 0xde, 0x78, 0x2c, 0x0a, 0x74, 0xcf, 0xdf, 0x2f, 0x79, 0x35, 0xdb, 0x28, 0x13, 0xe6, - 0x1d, 0x5f, 0xce, 0x42, 0xd9, 0xd5, 0xd2, 0xb8, 0xf3, 0xd9, 0x5b, 0xaa, 0xf9, 0xe0, 0x1f, 0x0e, 0x09, 0xc4, 0x1b, - 0xc5, 0x57, 0x77, 0x8d, 0xdc, 0xba, 0x26, 0x9b, 0xab, 0x12, 0x50, 0xbf, 0xcf, 0xd7, 0xb8, 0xdf, 0x62, 0xfd, 0xbb, - 0xa7, 0x41, 0xc6, 0x6a, 0x86, 0x2b, 0xa6, 0xf0, 0x29, 0x00, 0x0c, 0x0e, 0xa7, 0x82, 0xb4, 0xc0, 0x1b, 0x5e, 0x0e, - 0x2f, 0x27, 0x1b, 0x32, 0xe9, 0x6e, 0x7c, 0xe4, 0xce, 0x02, 0x55, 0xef, 0x37, 0x14, 0x27, 0x0d, 0x12, 0x8d, 0xbd, - 0x06, 0x5f, 0x66, 0x19, 0xe5, 0xa2, 0x89, 0xfb, 0x98, 0x7c, 0xa5, 0x07, 0x30, 0x57, 0xa1, 0x04, 0x88, 0x7e, 0x63, - 0x59, 0x6c, 0x44, 0xdb, 0x62, 0x03, 0x4b, 0xa9, 0x9a, 0xeb, 0xd5, 0xf4, 0xd9, 0x2b, 0xd1, 0xbc, 0x8f, 0x66, 0x9c, - 0xd2, 0x68, 0xc0, 0x71, 0x1a, 0x85, 0xdb, 0xf7, 0xf7, 0xa2, 0x5c, 0x66, 0x60, 0xc9, 0x56, 0xe1, 0x14, 0x97, 0x8d, - 0x3a, 0x23, 0x5e, 0xe6, 0xb1, 0x02, 0xe8, 0x78, 0x4c, 0x00, 0x54, 0x17, 0x04, 0x54, 0x44, 0x4b, 0xe9, 0xad, 0xd0, - 0x62, 0xa1, 0xde, 0x70, 0x94, 0xc2, 0x1f, 0xe9, 0xcf, 0x83, 0x7c, 0x0a, 0x40, 0xec, 0xfa, 0x38, 0x7a, 0x53, 0x94, - 0xf4, 0xa9, 0x62, 0x96, 0xcb, 0xc1, 0x04, 0x76, 0x75, 0x22, 0x43, 0xad, 0x20, 0x6f, 0xd5, 0x95, 0xb7, 0x32, 0x79, - 0x1b, 0xe3, 0x94, 0xfc, 0xc8, 0x4d, 0xc7, 0x1a, 0x31, 0xf0, 0xca, 0xd3, 0x3a, 0x4d, 0x90, 0x26, 0x17, 0xc0, 0x30, - 0xc4, 0xb7, 0x99, 0xf7, 0xd2, 0x73, 0xa4, 0x2a, 0x48, 0x66, 0xbb, 0xcc, 0x53, 0x17, 0x51, 0x7d, 0xe5, 0xd4, 0xd2, - 0x99, 0xd3, 0x8f, 0x00, 0xde, 0x63, 0x6a, 0xd2, 0x90, 0x8f, 0x70, 0x5b, 0x8a, 0xaf, 0xb7, 0xea, 0x1a, 0x2f, 0x8d, - 0xce, 0xdd, 0xcb, 0x97, 0xee, 0x34, 0xe8, 0xa7, 0x20, 0x28, 0xe7, 0xcb, 0x52, 0xc0, 0x9e, 0x32, 0x9b, 0xeb, 0xd5, - 0xaa, 0x15, 0x5a, 0x87, 0xc3, 0x58, 0x3b, 0x0a, 0x69, 0x75, 0x16, 0xb0, 0xd5, 0x48, 0xa7, 0x04, 0x08, 0xc1, 0x71, - 0x1a, 0x76, 0x82, 0x71, 0x97, 0x4e, 0x23, 0xb2, 0x5e, 0x29, 0x49, 0x17, 0x66, 0x90, 0xfc, 0x93, 0xbc, 0x9e, 0x01, - 0x2d, 0x01, 0x1c, 0x8a, 0x58, 0xc2, 0xc3, 0x49, 0x72, 0x05, 0xd0, 0xe9, 0x70, 0x50, 0x69, 0x68, 0xce, 0x6a, 0x96, - 0xcc, 0x27, 0xb1, 0x54, 0x55, 0x1e, 0x0e, 0x9e, 0x72, 0x33, 0xe8, 0xf7, 0xb3, 0x69, 0xa9, 0x5c, 0x00, 0x82, 0x58, - 0x17, 0x06, 0x88, 0x47, 0x5a, 0x78, 0xb2, 0xe8, 0x53, 0x12, 0xbf, 0x9c, 0x25, 0x73, 0x93, 0x0d, 0xef, 0xc0, 0x08, - 0x36, 0xe3, 0xba, 0xa4, 0x4c, 0x7b, 0x54, 0x7e, 0xcf, 0xe8, 0xa9, 0xed, 0x6b, 0xad, 0xb6, 0x88, 0x75, 0x1d, 0x5c, - 0x95, 0xa8, 0xa7, 0xf8, 0xa0, 0x24, 0xc1, 0xfb, 0xb5, 0x73, 0x33, 0x52, 0xbe, 0x16, 0xb9, 0x1f, 0xb4, 0x33, 0xb5, - 0x72, 0xe0, 0x08, 0xe4, 0x58, 0x45, 0x25, 0xaf, 0x77, 0x1d, 0x82, 0x47, 0x77, 0xa5, 0x02, 0xe5, 0xe0, 0x17, 0x20, - 0x46, 0xd7, 0x57, 0x9d, 0x35, 0xd4, 0x4c, 0xa3, 0xca, 0x23, 0xe8, 0xd4, 0x01, 0x3c, 0x29, 0x78, 0xa9, 0xd5, 0x8f, - 0x87, 0x83, 0x67, 0x7e, 0xf0, 0x57, 0x99, 0xbe, 0x85, 0x98, 0x28, 0xa7, 0x1a, 0x21, 0x71, 0xa5, 0x24, 0x11, 0x1f, - 0x2f, 0x5a, 0x56, 0x8c, 0xca, 0xf0, 0x81, 0x57, 0xaa, 0x7c, 0x75, 0xaa, 0xf2, 0x62, 0xa4, 0x6d, 0x09, 0xbc, 0x26, - 0xff, 0x10, 0xb9, 0xe6, 0xad, 0xaf, 0xbb, 0xca, 0xd0, 0x6b, 0x59, 0x81, 0x8e, 0x60, 0x2b, 0x4b, 0xc9, 0x01, 0x9f, - 0x54, 0x77, 0xd5, 0xaa, 0xf5, 0x39, 0x65, 0x1b, 0xe1, 0x26, 0xbf, 0x8e, 0x1d, 0x1c, 0x29, 0xbf, 0xc1, 0x73, 0x01, - 0xec, 0x35, 0x60, 0x6f, 0xce, 0x59, 0xd1, 0x3c, 0x3a, 0xa4, 0x6d, 0x81, 0x46, 0x66, 0x6e, 0xe7, 0xea, 0xbe, 0x2d, - 0x8f, 0xd2, 0x18, 0x22, 0xd3, 0x1e, 0x99, 0x0e, 0x36, 0xa3, 0xfc, 0xb7, 0x94, 0xdf, 0x2a, 0x1c, 0x03, 0xdf, 0x4e, - 0xbd, 0x03, 0xa8, 0x7a, 0xda, 0x20, 0x63, 0xcd, 0x30, 0xb4, 0xb2, 0xcb, 0xa5, 0xd0, 0x12, 0xb4, 0xd4, 0x4d, 0x10, - 0x9c, 0x1f, 0x11, 0xe5, 0x08, 0x40, 0x17, 0x29, 0x60, 0x82, 0x9f, 0xd2, 0x76, 0xf7, 0xfb, 0xeb, 0xd4, 0x23, 0xf7, - 0xae, 0x50, 0xa3, 0x84, 0x12, 0x8c, 0xfd, 0x44, 0x63, 0x06, 0x1d, 0x5d, 0x91, 0x13, 0x9e, 0xb5, 0x3a, 0xac, 0xeb, - 0xa6, 0x0c, 0xca, 0xe2, 0x98, 0x57, 0xd3, 0xd9, 0xef, 0x4f, 0xf6, 0x75, 0x83, 0x2c, 0xe4, 0xbf, 0xb3, 0x1e, 0x92, - 0x41, 0xf7, 0x20, 0x14, 0xa2, 0x37, 0x0f, 0x66, 0xf8, 0x1f, 0xdb, 0xf0, 0xec, 0x1b, 0x6e, 0xd4, 0x09, 0x60, 0x8e, - 0xb8, 0x5e, 0x7a, 0x8a, 0xb6, 0x1e, 0x6e, 0x81, 0x6c, 0x8d, 0x97, 0xb7, 0xf6, 0x1a, 0xc8, 0x29, 0x8e, 0xff, 0x8e, - 0x67, 0x6a, 0x65, 0x83, 0x9f, 0x9e, 0xb2, 0x1d, 0x78, 0x78, 0x11, 0x02, 0x8a, 0x61, 0xd9, 0xf8, 0x3b, 0xcb, 0x71, - 0x46, 0xff, 0xcd, 0x23, 0x86, 0xc1, 0x22, 0xf2, 0xe3, 0xcb, 0x52, 0x88, 0x2f, 0xc2, 0x7b, 0x5b, 0x79, 0x77, 0xe4, - 0x94, 0x79, 0xa7, 0x87, 0xd1, 0x75, 0x49, 0xfa, 0x26, 0xf9, 0xd8, 0x1a, 0xb6, 0xdf, 0xb5, 0xfb, 0xcd, 0x10, 0x41, - 0x08, 0xe5, 0xf8, 0x39, 0xa3, 0x13, 0x1a, 0x1f, 0x56, 0xb3, 0xd3, 0xeb, 0xf7, 0xce, 0xf1, 0x82, 0xad, 0xd1, 0x00, - 0x8f, 0x87, 0x2e, 0xe6, 0x89, 0x1a, 0x3a, 0x5d, 0xd7, 0xce, 0xc1, 0x03, 0x83, 0x2c, 0x4f, 0xbe, 0x61, 0x58, 0x62, - 0x7f, 0x12, 0xf1, 0xa4, 0xad, 0xda, 0xd8, 0x1c, 0xa9, 0x36, 0x6a, 0x06, 0x7e, 0xf0, 0x0a, 0x0a, 0x8c, 0x2e, 0x48, - 0x2b, 0x30, 0x0e, 0x47, 0x00, 0xb2, 0x62, 0x1c, 0x8f, 0x0c, 0x26, 0x30, 0xa4, 0x1b, 0x8a, 0x02, 0xf0, 0xf0, 0x38, - 0x1e, 0x84, 0x0c, 0x20, 0x5d, 0xf0, 0xd0, 0xb0, 0x4d, 0x42, 0xca, 0xcf, 0xf3, 0xbc, 0x56, 0x43, 0xe8, 0x3b, 0x0b, - 0xd5, 0xb1, 0x1f, 0x69, 0xaf, 0x58, 0xd7, 0xaa, 0x74, 0x64, 0xab, 0x03, 0xf4, 0x0d, 0x19, 0xf8, 0xd6, 0xb1, 0x05, - 0x40, 0xb4, 0xc4, 0x6f, 0xa9, 0x57, 0xfb, 0x32, 0x66, 0x85, 0x7a, 0x7d, 0x61, 0xda, 0xf5, 0x5a, 0x5a, 0x14, 0x50, - 0x71, 0xdb, 0xaa, 0xed, 0x91, 0x9c, 0xff, 0xf8, 0xae, 0xa3, 0x1d, 0x9f, 0x9d, 0x1a, 0x5b, 0x42, 0x99, 0x5b, 0x3c, - 0x91, 0xd5, 0xd1, 0x96, 0xea, 0x54, 0x1f, 0x70, 0xa9, 0x49, 0x75, 0x66, 0x60, 0x78, 0x8d, 0x00, 0xe5, 0x16, 0x22, - 0x69, 0x1c, 0xf6, 0xce, 0x27, 0x83, 0x82, 0xb9, 0x45, 0x02, 0x12, 0xd8, 0xc6, 0xd6, 0x2e, 0x9a, 0xeb, 0xd7, 0x6f, - 0xa9, 0x57, 0xb5, 0xa9, 0xea, 0xc1, 0x1b, 0x2f, 0x70, 0xf6, 0x4e, 0x6b, 0x01, 0x01, 0x14, 0xb6, 0x96, 0xe5, 0xe0, - 0xdc, 0xed, 0xaa, 0x96, 0x8a, 0x32, 0xea, 0xf7, 0xcf, 0x7f, 0x4b, 0x51, 0x11, 0x7b, 0xaa, 0x38, 0x65, 0xfd, 0x76, - 0xcb, 0x5c, 0x54, 0x96, 0xbc, 0x41, 0x15, 0xad, 0xd5, 0x51, 0x53, 0xb9, 0x6e, 0xae, 0x5a, 0x32, 0x41, 0x8c, 0xee, - 0xd3, 0xb5, 0xce, 0x9d, 0x7a, 0xef, 0x55, 0x1c, 0x31, 0x10, 0xdc, 0x74, 0x8f, 0x0f, 0x0e, 0x42, 0xa3, 0xa2, 0x5c, - 0x70, 0xa3, 0xb4, 0xaa, 0xa4, 0x14, 0xf2, 0x56, 0x45, 0x73, 0xa6, 0x8f, 0x00, 0x88, 0x00, 0xab, 0x44, 0xfd, 0x1f, - 0xbe, 0x34, 0xc6, 0x83, 0x07, 0xbe, 0x26, 0xd7, 0xb1, 0xf5, 0xfe, 0x69, 0x8d, 0xb4, 0xda, 0x38, 0x26, 0xb5, 0xea, - 0x65, 0xab, 0x78, 0xd9, 0xbd, 0x4e, 0xc5, 0xe0, 0xf9, 0xff, 0xdc, 0x07, 0xa8, 0x11, 0x2d, 0x65, 0x70, 0xeb, 0x6a, - 0x80, 0xc6, 0x87, 0x63, 0xe1, 0x1b, 0x3f, 0x64, 0x9c, 0x0f, 0x66, 0xe8, 0xa8, 0x36, 0x07, 0x07, 0x04, 0x47, 0x75, - 0x8f, 0xc6, 0x84, 0x59, 0x38, 0xf7, 0x20, 0x50, 0x7d, 0xe2, 0x3e, 0xe3, 0xda, 0x0b, 0xda, 0x04, 0x3e, 0x59, 0xd7, - 0x35, 0x45, 0x80, 0x8b, 0xd8, 0x98, 0x88, 0x21, 0x2e, 0x9b, 0x44, 0xea, 0x9b, 0x31, 0x28, 0x00, 0x8a, 0x17, 0x15, - 0xc9, 0xa5, 0x8b, 0x34, 0xaf, 0x44, 0x59, 0xeb, 0x66, 0x54, 0xac, 0x18, 0x02, 0xc0, 0x43, 0x50, 0x5c, 0x55, 0x66, - 0x42, 0x23, 0x36, 0x90, 0xca, 0x52, 0xb0, 0x6a, 0x58, 0xf8, 0x4d, 0xfb, 0x4d, 0x72, 0xd2, 0x3b, 0x1f, 0xb7, 0xce, - 0x1d, 0xfb, 0xde, 0x51, 0x48, 0x69, 0x0f, 0xc5, 0x04, 0x41, 0xf0, 0xd3, 0x3a, 0x9c, 0x3f, 0xe3, 0x2f, 0x08, 0x4c, - 0x45, 0x36, 0x63, 0xc0, 0x41, 0x88, 0xc8, 0x8c, 0xdf, 0x73, 0xf8, 0x82, 0x97, 0x93, 0x70, 0x38, 0xf4, 0x41, 0x1f, - 0xca, 0xb3, 0x59, 0x38, 0x14, 0x73, 0xe9, 0xbd, 0x0e, 0xd6, 0xba, 0x90, 0xd7, 0x93, 0x10, 0xd1, 0x42, 0x43, 0x1f, - 0x9c, 0xd7, 0x5d, 0x73, 0x84, 0x25, 0x00, 0x4d, 0x1c, 0x7d, 0x59, 0xbf, 0x1f, 0x79, 0xda, 0xd0, 0x22, 0xc5, 0x45, - 0xa3, 0xcc, 0x66, 0xb9, 0xec, 0x84, 0x8d, 0x6b, 0xb7, 0x40, 0x28, 0x1e, 0xa6, 0x2d, 0x54, 0xad, 0xa7, 0x7a, 0x3d, - 0x37, 0xed, 0xbe, 0x7b, 0x54, 0xad, 0x72, 0xa4, 0xb3, 0x36, 0x5d, 0xa9, 0xd5, 0x2d, 0xa3, 0x6a, 0x9d, 0xa5, 0x11, - 0x55, 0x6e, 0x92, 0xbb, 0x46, 0x2d, 0xf8, 0x64, 0x43, 0x97, 0x29, 0x3b, 0x5b, 0x83, 0x13, 0x47, 0x9e, 0x4b, 0x6e, - 0xf9, 0xee, 0xbc, 0xa2, 0xbb, 0x53, 0xed, 0x5b, 0x80, 0x7b, 0x33, 0x6c, 0xc8, 0x9c, 0xd7, 0xd8, 0x69, 0x10, 0x26, - 0x81, 0x1f, 0xb1, 0x8f, 0x19, 0xb2, 0xc1, 0x80, 0x8e, 0x42, 0xfa, 0x5f, 0x5b, 0xe6, 0x48, 0xc0, 0xe4, 0xaf, 0xe7, - 0x7e, 0xb3, 0x28, 0x72, 0x58, 0x8c, 0x1f, 0x36, 0x18, 0x69, 0xac, 0xd6, 0x60, 0x58, 0xde, 0x21, 0xf2, 0xa7, 0x76, - 0xc7, 0x34, 0xd5, 0xf1, 0x66, 0xbd, 0xd6, 0xfc, 0xea, 0xe9, 0x53, 0x5d, 0x9f, 0xff, 0xf6, 0xfd, 0x65, 0x58, 0x33, - 0xfb, 0x43, 0x10, 0x4a, 0xbb, 0x77, 0x8b, 0x73, 0x47, 0xa2, 0x77, 0xac, 0x34, 0xb3, 0x4b, 0xbb, 0x64, 0x97, 0xa6, - 0xb4, 0x1b, 0x72, 0xbd, 0xfa, 0x4a, 0x79, 0x63, 0xe7, 0x15, 0xd3, 0xfd, 0x7b, 0xa1, 0x77, 0x94, 0x53, 0x35, 0x81, - 0x88, 0x26, 0xed, 0x48, 0xdc, 0xee, 0x95, 0xe1, 0xf3, 0x49, 0xde, 0x2e, 0xe1, 0xa8, 0x6b, 0x58, 0x6e, 0xbe, 0xfd, - 0xcf, 0xbc, 0xea, 0xac, 0x70, 0xfb, 0xa5, 0x31, 0x6b, 0x7f, 0x0a, 0xe2, 0xaa, 0xfe, 0xf0, 0x9e, 0xd4, 0x4c, 0xc9, - 0xff, 0x55, 0x8f, 0x81, 0xab, 0x9f, 0x4c, 0x3b, 0xba, 0xa7, 0x10, 0x36, 0x98, 0xfd, 0xfc, 0xf8, 0xa1, 0x05, 0xab, - 0xea, 0x02, 0x45, 0x72, 0x00, 0x9d, 0xbb, 0x64, 0x84, 0xf7, 0x3b, 0xc6, 0xb9, 0x7f, 0xf5, 0xbd, 0x9a, 0x1c, 0x21, - 0xa2, 0x5d, 0x84, 0x03, 0x80, 0xb8, 0xd3, 0x54, 0xd6, 0xa1, 0x06, 0xe8, 0x03, 0x02, 0xeb, 0xd0, 0xb7, 0x19, 0xc0, - 0x41, 0x1f, 0x6d, 0x9e, 0x45, 0x20, 0xaf, 0x7b, 0xf7, 0xec, 0x9a, 0xed, 0x7c, 0xfe, 0x62, 0x95, 0x7a, 0xf7, 0xe8, - 0x10, 0x7c, 0x3e, 0xf6, 0xa7, 0x97, 0x81, 0xc1, 0x85, 0x66, 0xd7, 0xcf, 0x04, 0xdb, 0xb1, 0xdd, 0x33, 0x44, 0x2a, - 0xea, 0xce, 0x3f, 0xbc, 0x34, 0xd1, 0xf3, 0xce, 0x0b, 0x77, 0x7c, 0x09, 0xe0, 0x81, 0x2c, 0x06, 0x14, 0x9f, 0xa5, - 0xf7, 0x2f, 0x96, 0x80, 0x9a, 0xfc, 0x96, 0xaf, 0xbd, 0x2f, 0x94, 0xba, 0x80, 0x3f, 0x07, 0x94, 0x3e, 0xc9, 0xb9, - 0x77, 0x37, 0xbc, 0xf5, 0x2f, 0x9e, 0x83, 0xf3, 0xc4, 0x6a, 0xb8, 0x80, 0xbf, 0x0a, 0x3e, 0xf4, 0xee, 0x06, 0x98, - 0x58, 0xf2, 0xa1, 0xb7, 0x1a, 0x40, 0xaa, 0xc2, 0x85, 0xc4, 0xd8, 0x87, 0x5f, 0x83, 0x9c, 0xe1, 0x1f, 0xbf, 0x69, - 0x0c, 0xd6, 0x5f, 0x83, 0x42, 0xa3, 0xb1, 0x96, 0x2a, 0x64, 0x29, 0x16, 0x67, 0x02, 0x6c, 0xc2, 0x71, 0xb7, 0x2f, - 0x56, 0xb5, 0x59, 0x0b, 0xfa, 0xf3, 0x11, 0xdf, 0xa3, 0xb1, 0xba, 0x2a, 0xe7, 0xa2, 0xfc, 0x88, 0xf4, 0xa9, 0x8e, - 0x8f, 0x51, 0xb1, 0xa9, 0xbb, 0xd3, 0xa9, 0x56, 0x1d, 0x69, 0xbf, 0x29, 0xd7, 0x60, 0xc7, 0xeb, 0xe4, 0xc8, 0x52, - 0x78, 0xd6, 0x61, 0xe7, 0xa5, 0x53, 0xa2, 0xc3, 0x30, 0xde, 0x6d, 0xd5, 0x33, 0x86, 0xf2, 0xdc, 0x60, 0x4c, 0x17, - 0x3c, 0xe2, 0x2f, 0x06, 0xb9, 0x0c, 0x8d, 0xf9, 0x80, 0x6c, 0x18, 0xca, 0x87, 0x16, 0x19, 0x12, 0x22, 0xde, 0x43, - 0x25, 0x60, 0xdb, 0x82, 0x32, 0x29, 0xe0, 0x2c, 0x1a, 0xfc, 0x56, 0x7b, 0x39, 0xf0, 0x1e, 0x44, 0x7e, 0x23, 0x5d, - 0xca, 0x25, 0x36, 0x3a, 0x71, 0x2c, 0x0b, 0xed, 0x3c, 0xae, 0xbf, 0x8e, 0x41, 0xfd, 0x5e, 0xe9, 0x37, 0x28, 0x67, - 0x7f, 0x94, 0xac, 0xd3, 0xc6, 0x13, 0xe3, 0x1f, 0xae, 0xf2, 0x4f, 0xd1, 0x52, 0x0f, 0xff, 0x9f, 0x31, 0x85, 0xd2, - 0xbf, 0x4a, 0xcb, 0x68, 0xb3, 0x5a, 0x8a, 0x52, 0xe4, 0x91, 0x38, 0xf9, 0x5a, 0x64, 0xe7, 0xf2, 0x9d, 0x4f, 0xa1, - 0x5f, 0x00, 0x5a, 0xf6, 0x09, 0x32, 0xfa, 0x7b, 0x26, 0xf8, 0xf0, 0x7b, 0xed, 0x5c, 0x9b, 0xf3, 0xf1, 0x24, 0xbf, - 0xb2, 0xf6, 0x6e, 0xc7, 0x8b, 0xc4, 0x28, 0xc6, 0x72, 0x5f, 0x75, 0xb3, 0x72, 0xa2, 0x92, 0x03, 0x23, 0x5d, 0x93, - 0xbd, 0x5c, 0xc9, 0xba, 0x9d, 0x6e, 0x25, 0x10, 0x51, 0x05, 0xde, 0x63, 0x5c, 0xc5, 0x3e, 0x82, 0xe9, 0xba, 0xe3, - 0x32, 0xda, 0xf1, 0x9e, 0xf1, 0xea, 0x44, 0x59, 0xc1, 0xed, 0x46, 0xb4, 0x27, 0x74, 0xf4, 0xd3, 0xa4, 0xb6, 0x2c, - 0x1c, 0x80, 0xdc, 0x25, 0x8c, 0x65, 0x43, 0xb0, 0x62, 0x50, 0xfa, 0x7a, 0x4d, 0xc9, 0xb2, 0x00, 0x8b, 0xce, 0x2e, - 0x23, 0x10, 0xc3, 0xba, 0x69, 0x4e, 0xe8, 0x78, 0xe9, 0xe2, 0xbc, 0xd7, 0x2a, 0x52, 0xf0, 0x8c, 0x16, 0x1d, 0x73, - 0xd3, 0x91, 0x6e, 0x8c, 0xf6, 0xf6, 0x7b, 0x83, 0x90, 0xe2, 0xf9, 0x03, 0x5b, 0xad, 0x8b, 0x8b, 0xc4, 0x2b, 0x64, - 0xa2, 0x05, 0xb1, 0x14, 0x81, 0x19, 0x2f, 0x34, 0x8d, 0x30, 0x41, 0x99, 0x12, 0x2c, 0x5a, 0xa3, 0x43, 0xfb, 0xc3, - 0x12, 0x76, 0x8f, 0x31, 0x02, 0x04, 0xaa, 0x4c, 0x9f, 0xc3, 0xd6, 0x84, 0xd9, 0xd4, 0xc5, 0x06, 0x68, 0xab, 0x18, - 0x1a, 0x84, 0xb5, 0x21, 0xe6, 0x63, 0x9a, 0xdf, 0xfd, 0x0b, 0x8b, 0xb1, 0x3d, 0x81, 0xd8, 0xde, 0xed, 0x9a, 0x84, - 0xe9, 0x5e, 0x8b, 0x1b, 0xeb, 0xe5, 0xf6, 0x94, 0x63, 0x6a, 0xc7, 0xda, 0xa8, 0x1d, 0x6b, 0xa9, 0x77, 0xac, 0xb5, - 0xde, 0xb1, 0xee, 0x1a, 0xfe, 0x21, 0xf3, 0x62, 0x96, 0x80, 0x7e, 0x77, 0xc5, 0x55, 0x83, 0xa0, 0x19, 0x1b, 0x76, - 0x0b, 0xbf, 0x25, 0xd6, 0x6e, 0xe9, 0x5f, 0x2c, 0xd9, 0xc2, 0xf4, 0x81, 0x6e, 0x1d, 0x60, 0x19, 0x51, 0x93, 0xef, - 0x91, 0x77, 0xd3, 0x59, 0x51, 0xb8, 0x3d, 0xb1, 0x85, 0xcf, 0xae, 0xcd, 0x9b, 0xf7, 0xcf, 0x22, 0xc8, 0xbd, 0xe3, - 0xde, 0xfd, 0xf0, 0xda, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, 0xea, 0x88, 0x4f, 0x10, 0xad, 0xec, 0x29, - 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, - 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, - 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, - 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, - 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, - 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, - 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0xbe, 0x3f, 0x2d, 0x94, 0x6b, 0x37, 0x6f, 0xe3, - 0x37, 0xad, 0x96, 0x2c, 0xad, 0xf5, 0x90, 0x97, 0x96, 0x45, 0x04, 0x02, 0x18, 0x8e, 0x94, 0x5d, 0x2c, 0xe1, 0x1e, - 0x61, 0x75, 0x0f, 0x42, 0xc9, 0xbc, 0x70, 0xf1, 0x9c, 0xc5, 0x90, 0x08, 0xb0, 0xdd, 0xa1, 0x62, 0x5b, 0xb8, 0x78, - 0xce, 0x36, 0xbc, 0xe8, 0xf7, 0x33, 0xd5, 0x29, 0x64, 0xdd, 0x59, 0xf2, 0x8d, 0x6a, 0x8e, 0x35, 0xd4, 0x6c, 0x6d, - 0x92, 0xad, 0x71, 0x6e, 0x2b, 0x3e, 0xee, 0xda, 0x8a, 0x8f, 0x95, 0xb5, 0x2e, 0xdd, 0xeb, 0x3d, 0xaa, 0x0b, 0x60, - 0xeb, 0xbf, 0x3d, 0x5e, 0xb9, 0x9e, 0xcf, 0x08, 0xe0, 0x6b, 0xc1, 0xc7, 0x93, 0x05, 0x7a, 0x95, 0x2c, 0xfc, 0xdb, - 0x81, 0x1a, 0x7f, 0xa7, 0x73, 0x17, 0x00, 0x5d, 0x49, 0x79, 0x05, 0xe4, 0x1d, 0xe4, 0x98, 0x5b, 0x76, 0xe5, 0xfd, - 0xc9, 0x77, 0xd8, 0x35, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, - 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x84, 0x20, 0xae, 0xe0, 0x16, 0xe2, 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, - 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, - 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xd7, 0x52, 0xeb, 0x62, 0x0c, 0x3d, 0x40, 0xfc, 0x74, 0x3b, 0xe0, - 0xf7, 0x1d, 0x6b, 0xcb, 0xbb, 0x66, 0x0b, 0xb6, 0x83, 0x4b, 0x50, 0xd3, 0x5e, 0xf6, 0x27, 0x95, 0x0b, 0xda, 0xb1, - 0x4b, 0xe2, 0xe1, 0x8c, 0x59, 0xa5, 0xcc, 0xac, 0x93, 0xea, 0x4a, 0x74, 0xc6, 0x74, 0xd6, 0x7a, 0x3e, 0x57, 0xf3, - 0x49, 0xa1, 0x41, 0xfd, 0xce, 0x89, 0x8f, 0xa8, 0xe8, 0x3c, 0x81, 0xad, 0x65, 0x05, 0xb1, 0xda, 0xe7, 0x60, 0xad, - 0xd5, 0x2e, 0xfd, 0x5e, 0x3e, 0xe0, 0x36, 0xe5, 0xb0, 0x0e, 0x0c, 0x6a, 0x4e, 0xac, 0xa8, 0xc7, 0x6c, 0xc7, 0xb8, - 0xf9, 0xe9, 0xe5, 0x0f, 0x4e, 0x58, 0xb2, 0x62, 0xb5, 0x3f, 0xfd, 0xfe, 0x99, 0xa7, 0xbf, 0x53, 0xfb, 0x17, 0xc2, - 0x0f, 0xc6, 0xff, 0xa9, 0xdd, 0xd7, 0x5a, 0x8c, 0xca, 0x56, 0x39, 0x42, 0xe3, 0x6e, 0x25, 0x4d, 0x96, 0x9f, 0x84, - 0x27, 0xac, 0x05, 0xcf, 0x72, 0xbd, 0x44, 0xb3, 0x02, 0x56, 0x58, 0xcb, 0x24, 0x5c, 0x61, 0xac, 0x96, 0xb6, 0xfa, - 0x16, 0x4d, 0x73, 0x7c, 0x38, 0xd7, 0x06, 0x65, 0xca, 0xd9, 0x19, 0xb1, 0x1a, 0x2e, 0xc3, 0xd2, 0x84, 0x22, 0x64, - 0xf7, 0x76, 0x70, 0x63, 0xa7, 0x2c, 0xa5, 0x0c, 0xe7, 0x18, 0x4c, 0x78, 0x24, 0x46, 0x55, 0xbe, 0xbf, 0x2f, 0x29, - 0x72, 0xda, 0x96, 0x83, 0x2a, 0x84, 0x7d, 0x24, 0x51, 0x02, 0xb7, 0x22, 0x2d, 0x14, 0x29, 0x8b, 0xbf, 0x1d, 0xa0, - 0x0b, 0xbc, 0x80, 0xba, 0x1a, 0x75, 0xfb, 0xc3, 0x11, 0x0f, 0x1f, 0x99, 0xfa, 0xc0, 0x88, 0x25, 0x81, 0xda, 0x5e, - 0x66, 0xe9, 0x1d, 0xa8, 0xf0, 0x7b, 0xb8, 0x9a, 0x88, 0xfd, 0xdc, 0x92, 0xa2, 0x22, 0x1b, 0xe9, 0x0d, 0xad, 0xc1, - 0x23, 0xb4, 0xa6, 0x7c, 0xef, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, - 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0xef, - 0x55, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, 0xac, 0xd2, 0xd7, 0x24, 0x61, 0x4f, 0x0c, - 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, 0xd2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, - 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x57, 0xc4, 0x97, 0x23, 0x3c, 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, - 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, - 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, - 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, - 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, - 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, - 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, - 0x58, 0x1d, 0xf4, 0xfe, 0x32, 0x7e, 0xda, 0x33, 0x32, 0xf2, 0xb8, 0x75, 0x58, 0xfd, 0xaf, 0xbf, 0x42, 0x00, 0x1c, - 0x9e, 0x4d, 0xbd, 0xcb, 0x31, 0x64, 0x95, 0x65, 0x04, 0x92, 0x9f, 0x18, 0x7c, 0xf9, 0x02, 0xa0, 0xea, 0x33, 0x5d, - 0xab, 0xc9, 0x51, 0x7b, 0xcc, 0xa1, 0x2b, 0x06, 0x80, 0x6d, 0x58, 0xa2, 0xaa, 0x16, 0x36, 0x61, 0x71, 0xfb, 0x19, - 0x46, 0x73, 0xd9, 0xf4, 0x82, 0x06, 0xea, 0x11, 0x82, 0x5f, 0x5a, 0x0f, 0xad, 0xb5, 0x4c, 0x39, 0x74, 0x6d, 0x14, - 0x55, 0x36, 0xd4, 0x25, 0xac, 0xd6, 0x22, 0xaa, 0x89, 0x22, 0xe5, 0x92, 0x51, 0x14, 0x4b, 0x15, 0xec, 0x33, 0x71, - 0x07, 0x51, 0xf3, 0xb4, 0xd5, 0x56, 0xc1, 0xfe, 0x0e, 0x10, 0xd6, 0xc2, 0x5a, 0x48, 0x67, 0x50, 0x7b, 0xa7, 0x1f, - 0x29, 0x7f, 0x79, 0x21, 0xb7, 0x73, 0x0b, 0x45, 0xb8, 0x3d, 0x07, 0xe5, 0x4d, 0x5d, 0x95, 0x8a, 0x68, 0xb4, 0x04, - 0x4a, 0x99, 0x13, 0x44, 0x16, 0x20, 0x80, 0xe3, 0x06, 0x02, 0x9f, 0xd7, 0xf8, 0x04, 0x1a, 0x85, 0x40, 0x7e, 0x60, - 0x15, 0xae, 0x3d, 0xa4, 0xa5, 0xd6, 0x88, 0x28, 0x11, 0x3f, 0xba, 0x7a, 0x8e, 0xed, 0xab, 0xa7, 0xb1, 0xb6, 0x94, - 0x26, 0x88, 0x9f, 0x58, 0x6c, 0x21, 0x26, 0x88, 0xea, 0x10, 0x1d, 0xc1, 0x72, 0x42, 0x88, 0xc2, 0x1f, 0x42, 0x3f, - 0x35, 0xf0, 0x97, 0x6c, 0x59, 0xe4, 0x35, 0xc1, 0x62, 0x56, 0x0c, 0xd0, 0xaa, 0x08, 0x3c, 0xd3, 0xd9, 0x52, 0x99, - 0xd3, 0x3c, 0x3a, 0xb2, 0x83, 0xf3, 0xae, 0x83, 0xbd, 0xf4, 0x65, 0xec, 0x64, 0xd9, 0x34, 0x6a, 0x63, 0x43, 0x24, - 0xbc, 0x22, 0x7f, 0x95, 0xa5, 0xc6, 0x39, 0x32, 0x97, 0xeb, 0xbb, 0x2e, 0xee, 0xee, 0x68, 0x9b, 0xb0, 0x0a, 0x11, - 0xea, 0xb6, 0xa1, 0x72, 0x29, 0xcc, 0xc6, 0xa6, 0x69, 0x80, 0x2f, 0x14, 0x95, 0x4a, 0x55, 0x6a, 0x2b, 0x95, 0x9c, - 0xf0, 0xae, 0xaf, 0x6a, 0x91, 0xba, 0x22, 0xd8, 0xc6, 0x0c, 0xf5, 0x50, 0x6e, 0xd4, 0xd8, 0xd7, 0x1d, 0xab, 0xf4, - 0x0e, 0x13, 0xe4, 0x8c, 0xbc, 0xc8, 0xc1, 0x45, 0x49, 0x41, 0xe6, 0x6a, 0x08, 0xf3, 0x47, 0x0d, 0x9f, 0x16, 0x96, - 0x7b, 0x28, 0x01, 0xb3, 0xa3, 0x86, 0x97, 0x11, 0x02, 0x11, 0x97, 0xca, 0xbe, 0x62, 0xe2, 0xf7, 0x14, 0xcc, 0x92, - 0x09, 0xdd, 0x8b, 0x58, 0x18, 0xa1, 0x8d, 0x4f, 0x92, 0x64, 0xea, 0x69, 0x0a, 0x6e, 0xe4, 0x32, 0xcc, 0xd1, 0x08, - 0x2d, 0xf9, 0xc8, 0x81, 0xf4, 0xb5, 0x9c, 0x4a, 0xf0, 0x11, 0x75, 0x0a, 0x38, 0x9e, 0x9f, 0x17, 0xd6, 0x4f, 0x96, - 0x4b, 0xcc, 0x65, 0x6d, 0xfe, 0xcb, 0x8e, 0x8e, 0xc1, 0x2e, 0x4f, 0x13, 0xc7, 0xd5, 0x7f, 0x54, 0x25, 0xc5, 0xc3, - 0xcf, 0x69, 0x0e, 0x28, 0x82, 0x99, 0x3d, 0xc5, 0xf8, 0xd8, 0x67, 0x99, 0x02, 0xfe, 0x76, 0xbd, 0xb5, 0x64, 0x62, - 0x97, 0xb4, 0x9b, 0x2b, 0xe3, 0x97, 0xda, 0xb0, 0xe3, 0xe0, 0xdc, 0x00, 0x14, 0x67, 0x8d, 0x0e, 0xcb, 0x6b, 0xdd, - 0xb6, 0x2a, 0x54, 0xa0, 0xd6, 0xff, 0xd9, 0x2d, 0x4c, 0x79, 0x9b, 0x97, 0xca, 0xdb, 0x3c, 0x34, 0x01, 0x02, 0x91, - 0x19, 0xf2, 0xac, 0xe9, 0x98, 0x24, 0xee, 0x1d, 0x29, 0x69, 0xdf, 0x91, 0xe2, 0x47, 0xef, 0x48, 0xc8, 0xb7, 0x84, - 0x8e, 0xec, 0x4b, 0x4e, 0x4e, 0xa0, 0xcc, 0x60, 0x2f, 0xaf, 0x99, 0xec, 0x1f, 0xd0, 0x5e, 0x38, 0x97, 0xe5, 0x15, - 0xbf, 0x16, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, - 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, 0xf1, 0xf1, 0xd7, 0x1c, 0x45, 0x6c, 0xa5, 0x3c, 0x92, 0x2e, 0x54, - 0x62, 0x78, 0x69, 0xe0, 0x61, 0x76, 0x7c, 0x3c, 0xd9, 0x5d, 0xdd, 0x4f, 0x06, 0x83, 0x9d, 0xea, 0xdb, 0x2d, 0xaf, - 0x67, 0xbb, 0x39, 0x7b, 0xe0, 0xb7, 0xd3, 0x6d, 0xb0, 0x6f, 0x60, 0xdb, 0xdd, 0x5d, 0x89, 0xc3, 0x61, 0xf7, 0x82, - 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, - 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, - 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe5, 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, - 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, - 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xfa, - 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xf5, 0x6c, 0x33, - 0xf7, 0x5f, 0xac, 0xd8, 0x1d, 0x70, 0xa1, 0x28, 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, - 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, - 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, 0xd7, 0xfc, 0xa6, 0x39, 0x76, 0x8c, 0xfd, 0xea, 0x8d, 0x11, 0x40, - 0x99, 0x2d, 0x58, 0x2c, 0x38, 0x28, 0xd5, 0xaa, 0x6d, 0x49, 0xe4, 0x95, 0x0e, 0x54, 0x9b, 0x11, 0xdc, 0x57, 0x0b, - 0x39, 0xf3, 0xcc, 0x40, 0xdf, 0x56, 0x88, 0x16, 0x0e, 0x1b, 0xf0, 0x57, 0xda, 0x3a, 0xc6, 0x30, 0xcd, 0x6a, 0xa6, - 0x6d, 0x51, 0x97, 0xdf, 0xf6, 0x9e, 0xc9, 0x6f, 0x64, 0x60, 0x0b, 0x91, 0x14, 0x8e, 0xe3, 0x8b, 0xe7, 0x27, 0xfc, - 0x57, 0x2d, 0x8f, 0x5a, 0xed, 0x17, 0x4a, 0x7d, 0xfa, 0x8a, 0x8e, 0x68, 0xe2, 0x5e, 0xb4, 0x65, 0x58, 0xa3, 0xac, - 0xa9, 0xa5, 0xc3, 0x30, 0xae, 0x61, 0x5f, 0x1e, 0x38, 0xf4, 0x1d, 0x10, 0x68, 0xab, 0x54, 0x0a, 0xb4, 0x70, 0x0c, - 0xa3, 0x30, 0x0b, 0x29, 0x8f, 0x0b, 0xb3, 0x94, 0xf7, 0x58, 0xa0, 0xc5, 0xad, 0xba, 0xc7, 0xd4, 0x76, 0x0b, 0x22, - 0xac, 0xde, 0x32, 0xce, 0x2f, 0x1b, 0x55, 0xb8, 0x2d, 0x40, 0x51, 0x04, 0x65, 0xb0, 0x27, 0xb9, 0x6d, 0xa1, 0xa4, - 0xd9, 0x28, 0xac, 0xc5, 0x5d, 0x51, 0xee, 0x7a, 0x0d, 0x5b, 0xe0, 0x05, 0x55, 0x3f, 0x21, 0x6c, 0xcb, 0x9e, 0x75, - 0x28, 0x17, 0xe9, 0x7f, 0x64, 0xe9, 0xf9, 0x76, 0x6b, 0xce, 0xff, 0xf4, 0x15, 0x7d, 0x54, 0xfe, 0xe7, 0x97, 0xf4, - 0x93, 0xc1, 0x32, 0x72, 0x4a, 0x7d, 0x1f, 0x8d, 0x6e, 0xd3, 0x9c, 0x30, 0xb6, 0x7c, 0xfd, 0xf4, 0x1b, 0x64, 0x0a, - 0x92, 0x43, 0x29, 0x55, 0x39, 0xd9, 0x43, 0x5f, 0x78, 0xdd, 0x87, 0x99, 0x60, 0x00, 0xc2, 0x6b, 0xb4, 0xa9, 0x26, - 0x4c, 0xe2, 0xd1, 0x15, 0xfc, 0xdf, 0x08, 0x62, 0xd0, 0x3e, 0x51, 0xd4, 0xb1, 0x6d, 0xa4, 0xeb, 0xb6, 0x73, 0x90, - 0xdc, 0xa9, 0x2b, 0x7f, 0x54, 0x4e, 0xfe, 0x13, 0x0d, 0x91, 0x57, 0x5c, 0x21, 0x56, 0x16, 0x5c, 0x62, 0x31, 0x54, - 0xa4, 0x00, 0xd7, 0x10, 0x44, 0xca, 0xa2, 0xa4, 0x70, 0xcb, 0x41, 0x55, 0x04, 0x60, 0x5c, 0xad, 0x8e, 0x3a, 0x11, - 0x3e, 0x6e, 0xad, 0x45, 0x08, 0x56, 0x34, 0x6a, 0x65, 0xad, 0xc0, 0x17, 0xa4, 0x2f, 0x1d, 0x0a, 0x62, 0x7a, 0x14, - 0x52, 0x55, 0x3a, 0x14, 0x48, 0x73, 0xa8, 0xf8, 0xc6, 0x60, 0xa3, 0xa8, 0x48, 0xcf, 0x5f, 0x9a, 0x94, 0x5c, 0x1a, - 0x33, 0x3e, 0x88, 0x32, 0x12, 0x79, 0x1d, 0xde, 0x89, 0x69, 0x81, 0x7c, 0xa3, 0xc7, 0x0f, 0x82, 0x4b, 0x78, 0x37, - 0xe4, 0x5e, 0x01, 0xb6, 0x04, 0xec, 0x00, 0xf7, 0xca, 0x8c, 0x72, 0x9d, 0xd6, 0xf5, 0x5b, 0xeb, 0xa1, 0x18, 0x86, - 0xcf, 0x2c, 0x81, 0xed, 0x68, 0x1d, 0x1d, 0xe9, 0xe1, 0xc3, 0xff, 0xba, 0xaa, 0x39, 0xea, 0x54, 0x2e, 0x67, 0xc7, - 0x13, 0x96, 0x22, 0x66, 0xd0, 0xfd, 0x75, 0xfb, 0x4a, 0x00, 0xdd, 0x2e, 0x8b, 0x79, 0x36, 0xda, 0xc9, 0xbf, 0xa5, - 0x1b, 0x2b, 0x4a, 0x9b, 0x78, 0x97, 0xf5, 0xc6, 0xfe, 0x70, 0xf4, 0x97, 0x67, 0x5f, 0x26, 0x84, 0xaa, 0xb3, 0x61, - 0x6b, 0x1d, 0xe7, 0xf2, 0xbf, 0xfe, 0x3a, 0x26, 0x2b, 0x08, 0x0a, 0xc2, 0xb2, 0x53, 0x4c, 0x54, 0x30, 0x8a, 0x14, - 0x6b, 0x3e, 0x9e, 0xac, 0x51, 0x27, 0xbc, 0xf6, 0x97, 0x5a, 0x27, 0x4c, 0x8c, 0xac, 0x54, 0xfe, 0x9a, 0x55, 0xec, - 0x4e, 0x65, 0x16, 0x90, 0x79, 0x90, 0x4f, 0xd6, 0x46, 0x83, 0xb9, 0xe2, 0xf5, 0x6c, 0x3d, 0x97, 0xca, 0x67, 0x30, - 0xe5, 0x2c, 0x07, 0x27, 0x4b, 0x61, 0xf7, 0x24, 0x50, 0xb4, 0x66, 0xe8, 0xda, 0x9f, 0x62, 0xab, 0x5e, 0xa7, 0x55, - 0x0d, 0xf0, 0x80, 0x10, 0x03, 0x43, 0xed, 0xd5, 0xc2, 0x43, 0x6b, 0x01, 0xac, 0xfd, 0x51, 0xe9, 0x07, 0xe3, 0xc9, - 0x92, 0x2f, 0x90, 0x7f, 0x39, 0x72, 0xd4, 0xee, 0xfd, 0xbe, 0x77, 0x0f, 0x52, 0x70, 0xe4, 0x5a, 0x28, 0x90, 0x08, - 0x68, 0xc1, 0x37, 0xbe, 0xf2, 0xc1, 0xb8, 0x46, 0x6d, 0x35, 0x28, 0xa8, 0x1d, 0xdd, 0xf2, 0xd8, 0xd1, 0x3b, 0xdf, - 0x9f, 0xd0, 0x57, 0x2f, 0xb4, 0x70, 0xfc, 0x95, 0x33, 0x72, 0xcd, 0x56, 0x1d, 0x72, 0x44, 0x33, 0xe9, 0x10, 0x22, - 0x56, 0x6c, 0xcd, 0xae, 0x49, 0xe5, 0xdc, 0x39, 0x64, 0xa7, 0x8f, 0x50, 0xa5, 0xd7, 0x7a, 0x7c, 0x3b, 0x51, 0xba, - 0xdb, 0xe3, 0xdd, 0xe4, 0x5b, 0x36, 0x11, 0x31, 0x18, 0xd0, 0x06, 0xe1, 0x8c, 0xac, 0x43, 0xa4, 0xd2, 0x01, 0x42, - 0xe0, 0x98, 0x80, 0xa6, 0xff, 0xf8, 0x9a, 0x44, 0x01, 0x47, 0xda, 0x08, 0x59, 0xcb, 0x0e, 0x87, 0x1c, 0x34, 0xca, - 0xcd, 0x1f, 0x5e, 0xa1, 0x4e, 0x73, 0x60, 0x9e, 0x2e, 0x61, 0xcf, 0xc1, 0x23, 0xbd, 0x38, 0x3e, 0xd2, 0xff, 0x3b, - 0x9a, 0xa8, 0xf1, 0x7f, 0xae, 0x89, 0x52, 0x5a, 0x24, 0x47, 0xb5, 0xf4, 0x4d, 0xea, 0x28, 0xb8, 0xc8, 0x3b, 0x6a, - 0x21, 0x7b, 0x96, 0x8d, 0x1b, 0xd5, 0xbc, 0xff, 0x5f, 0x2b, 0xf3, 0xff, 0x35, 0xad, 0x0c, 0x53, 0xb2, 0x63, 0xa9, - 0x66, 0x1e, 0x68, 0x15, 0xc3, 0xec, 0x67, 0x92, 0x10, 0x19, 0x2e, 0x0d, 0xf8, 0x51, 0x05, 0xfb, 0x38, 0xad, 0xd6, - 0x59, 0xb8, 0x43, 0x25, 0xea, 0xad, 0xb8, 0x4b, 0xf3, 0x97, 0xf5, 0xbf, 0x45, 0x59, 0xc0, 0xd4, 0xbe, 0x2b, 0xd3, - 0x38, 0x20, 0x0b, 0x7f, 0x16, 0x96, 0x38, 0xb9, 0xb1, 0x8d, 0x3f, 0xcb, 0xf1, 0xb4, 0x5f, 0x75, 0x66, 0x1e, 0x48, - 0xa0, 0x06, 0xe2, 0x8f, 0x9c, 0xcb, 0xca, 0xe2, 0x01, 0xa1, 0x9b, 0x7f, 0x28, 0xcb, 0xa2, 0xf4, 0x7a, 0x9f, 0x92, - 0xb4, 0x3a, 0x5b, 0x89, 0x3a, 0x29, 0x62, 0x05, 0x65, 0x93, 0x02, 0x8c, 0x3e, 0xac, 0x3c, 0x11, 0x07, 0x67, 0x08, - 0xd4, 0x70, 0x56, 0x27, 0x21, 0x00, 0x0d, 0x2b, 0x84, 0xfd, 0x33, 0x68, 0xe1, 0x59, 0x18, 0x87, 0x6b, 0x80, 0xc9, - 0x49, 0xab, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, 0x88, 0x47, 0x3d, 0x45, 0xc9, 0xf2, 0x26, 0x77, 0xe5, 0x5c, 0x7f, - 0xff, 0x07, 0x05, 0xb0, 0x1b, 0x30, 0xdb, 0x16, 0xd8, 0x01, 0x40, 0x82, 0x02, 0xd9, 0x42, 0x9d, 0x46, 0x67, 0x6a, - 0xa9, 0xc0, 0x7b, 0xae, 0x07, 0xf8, 0x9b, 0x1c, 0xb0, 0x8c, 0xeb, 0x42, 0x06, 0x8c, 0x20, 0x80, 0x11, 0x38, 0x28, - 0x01, 0x43, 0x67, 0x88, 0xdb, 0xaa, 0x9c, 0xb5, 0xd0, 0x5c, 0xe9, 0xb6, 0xe4, 0xa6, 0x51, 0xce, 0x56, 0x22, 0x80, - 0xbe, 0xba, 0x29, 0x71, 0xba, 0x5c, 0xb6, 0x92, 0xb0, 0x6f, 0xdf, 0xb7, 0x53, 0x45, 0x1e, 0x1f, 0xa5, 0x21, 0xaf, - 0xc0, 0x93, 0x8c, 0x23, 0x49, 0x94, 0x08, 0xde, 0xe4, 0x8d, 0x19, 0x87, 0x97, 0x6d, 0xca, 0xa9, 0xbd, 0x59, 0x2f, - 0x00, 0xe7, 0x09, 0xda, 0x32, 0xc0, 0x58, 0xc0, 0xe0, 0x5c, 0x88, 0x25, 0x4f, 0x11, 0xfc, 0xd2, 0x89, 0x14, 0xc6, - 0x5d, 0x0e, 0xc3, 0x3c, 0x28, 0x7a, 0x97, 0xd4, 0x1f, 0xfd, 0x3e, 0x6a, 0x93, 0xc1, 0x10, 0x54, 0x02, 0xa8, 0xac, - 0x1b, 0x24, 0x06, 0x56, 0xa5, 0x85, 0xc4, 0x25, 0xc4, 0xcb, 0x7c, 0x35, 0xad, 0xa3, 0xe0, 0x7d, 0x3d, 0x21, 0x84, - 0x13, 0x8c, 0x0f, 0x71, 0x03, 0x04, 0x0c, 0x56, 0x71, 0x81, 0x41, 0xf2, 0x5c, 0xa2, 0xfb, 0xe3, 0xf9, 0x8e, 0x01, - 0xae, 0x9c, 0xf7, 0x54, 0xbb, 0x7a, 0x60, 0x2f, 0x57, 0xe9, 0x92, 0x11, 0xc2, 0x8a, 0xff, 0x8b, 0xc8, 0xfb, 0x76, - 0x98, 0x80, 0xda, 0x46, 0xfe, 0x18, 0x24, 0xe6, 0x32, 0x51, 0x04, 0xf1, 0x28, 0x2b, 0x58, 0x92, 0x06, 0x9b, 0x51, - 0x92, 0x82, 0x46, 0x13, 0x63, 0xc8, 0x54, 0x68, 0x87, 0xa4, 0xd1, 0x6c, 0x4c, 0xf6, 0x31, 0xe4, 0x35, 0x5c, 0x2c, - 0x16, 0x78, 0xdf, 0xcf, 0x42, 0x75, 0xb0, 0x2d, 0xcd, 0x21, 0xe0, 0x24, 0xc1, 0x9e, 0xba, 0x22, 0x25, 0x61, 0x36, - 0xfa, 0x14, 0x72, 0x6e, 0x40, 0xc7, 0x49, 0x63, 0xa8, 0x3e, 0x30, 0x09, 0xaf, 0x22, 0x74, 0x52, 0x56, 0x08, 0x0b, - 0xb8, 0x6f, 0x64, 0x34, 0x5a, 0x49, 0x83, 0xc0, 0xdb, 0x0c, 0x5b, 0x81, 0x4d, 0x68, 0xf8, 0xcb, 0xcc, 0xc3, 0xb4, - 0x9a, 0x95, 0x60, 0xce, 0x37, 0x50, 0x89, 0xf1, 0x64, 0x79, 0xc5, 0x37, 0x2e, 0x56, 0x62, 0x32, 0x5b, 0xce, 0x27, - 0x6b, 0x49, 0x35, 0x97, 0x7b, 0x6b, 0x96, 0xb1, 0x25, 0xec, 0x1f, 0x06, 0x86, 0xd2, 0x81, 0x1d, 0x4d, 0x35, 0x6d, - 0x12, 0x60, 0x32, 0x9d, 0x73, 0x3e, 0xbc, 0x44, 0x34, 0x59, 0x9d, 0xba, 0x93, 0xa9, 0x6a, 0x07, 0xd7, 0xe4, 0x4c, - 0x4e, 0x8f, 0xd4, 0x53, 0xad, 0x7b, 0xc9, 0x47, 0xdb, 0x61, 0x35, 0xda, 0xfa, 0x01, 0xb8, 0x75, 0x0a, 0x3b, 0x7d, - 0x37, 0xac, 0x46, 0x3b, 0x5f, 0xc3, 0xee, 0x92, 0x42, 0xa0, 0xfa, 0xb3, 0xac, 0xc9, 0x5c, 0xbc, 0x2e, 0x1e, 0xbc, - 0x82, 0x3d, 0xf7, 0x07, 0xfa, 0x57, 0xc9, 0x9e, 0xfb, 0x36, 0x93, 0xeb, 0x9f, 0x69, 0xd7, 0x68, 0xcc, 0x74, 0xbc, - 0x76, 0x05, 0x56, 0x68, 0x80, 0xfc, 0x82, 0x1d, 0xed, 0x6d, 0x0e, 0x02, 0x01, 0xba, 0x97, 0xe0, 0x28, 0x0a, 0x88, - 0x9a, 0x56, 0x95, 0x47, 0xa7, 0x7b, 0x7f, 0x8f, 0x6f, 0x94, 0x80, 0x4d, 0x9e, 0x5a, 0xf7, 0x96, 0xb1, 0x7f, 0x38, - 0x40, 0x08, 0xbd, 0x9c, 0x7e, 0xa3, 0x2d, 0xab, 0x47, 0x3b, 0x96, 0xfb, 0x86, 0x51, 0x4f, 0xc1, 0x18, 0x86, 0x2e, - 0xac, 0x62, 0x24, 0xcf, 0x80, 0xac, 0xf1, 0x1b, 0x44, 0x17, 0xb0, 0xe8, 0xf5, 0x5e, 0x1f, 0xd1, 0x20, 0x02, 0x2a, - 0xbd, 0xe6, 0x2f, 0x45, 0x3e, 0x57, 0x85, 0xe8, 0xbd, 0xb7, 0x76, 0xde, 0xcc, 0x48, 0x96, 0x49, 0x23, 0xd5, 0x6e, - 0x65, 0xb1, 0xae, 0xbc, 0xd9, 0x09, 0xe9, 0x62, 0x8e, 0xa1, 0x32, 0x78, 0x1c, 0x80, 0xd2, 0xf3, 0x6f, 0xa1, 0x57, - 0x32, 0x64, 0x9a, 0x25, 0x9a, 0xd9, 0x5d, 0xe3, 0x4f, 0x56, 0xa9, 0x17, 0x23, 0x62, 0x36, 0xb0, 0x85, 0xb8, 0x2d, - 0x2a, 0xdd, 0x16, 0x85, 0xb2, 0x45, 0x91, 0x3e, 0xd4, 0xce, 0x74, 0x67, 0x16, 0x3e, 0xab, 0x4c, 0xfb, 0xde, 0x66, - 0x66, 0x6c, 0x80, 0xb6, 0x8b, 0xf0, 0x0d, 0x74, 0xa0, 0x42, 0xc8, 0x7f, 0x40, 0x44, 0x24, 0x02, 0x76, 0x39, 0x75, - 0x27, 0x36, 0x1d, 0x92, 0x79, 0x88, 0x59, 0xa1, 0x46, 0x79, 0xc9, 0x93, 0xa3, 0x01, 0xa9, 0x08, 0x75, 0xbb, 0xdf, - 0x3f, 0x5f, 0xba, 0xa0, 0xf6, 0x6b, 0x8a, 0x1d, 0xa3, 0x9b, 0x02, 0xce, 0x05, 0x8f, 0xf2, 0x9e, 0x7b, 0xe7, 0x80, - 0xe6, 0xd8, 0x9e, 0x22, 0x6b, 0xc0, 0xe9, 0x6d, 0x17, 0x02, 0x6c, 0x9f, 0x35, 0x5b, 0xfb, 0x93, 0xd5, 0x55, 0x34, - 0xf5, 0x4a, 0x3e, 0xd3, 0x5d, 0x94, 0xb8, 0x5d, 0x14, 0xcb, 0x2e, 0xda, 0x34, 0x10, 0xec, 0xb8, 0xf2, 0x03, 0xe0, - 0x0d, 0x8d, 0xfa, 0xfd, 0xb2, 0xd5, 0xb3, 0x27, 0x5f, 0x3b, 0xee, 0xd9, 0xcc, 0x67, 0xa5, 0xe9, 0xd9, 0x5f, 0x53, - 0xb7, 0x67, 0xe5, 0x64, 0x2f, 0x3a, 0x27, 0xfb, 0x74, 0x36, 0x0f, 0x04, 0x97, 0x3b, 0xf7, 0x79, 0x3e, 0xd5, 0xd3, - 0xae, 0xf2, 0x83, 0xd6, 0x10, 0x99, 0x2f, 0x7c, 0xaa, 0xba, 0xd7, 0x15, 0x2c, 0x60, 0x09, 0xee, 0xd6, 0x4b, 0xf3, - 0x5f, 0xb1, 0xfb, 0x7b, 0x41, 0x2f, 0xcd, 0x7f, 0xa3, 0x3f, 0x29, 0x80, 0x03, 0xd0, 0x98, 0xda, 0x2d, 0xf0, 0x10, - 0x43, 0x05, 0x85, 0xbb, 0x59, 0x39, 0xf7, 0x6a, 0x80, 0xc3, 0x24, 0x7d, 0x43, 0xab, 0x57, 0x5a, 0xec, 0x7a, 0x99, - 0xec, 0x15, 0xe0, 0xa1, 0x0a, 0x79, 0x78, 0x38, 0x44, 0x1d, 0xc3, 0x0e, 0xea, 0x08, 0x18, 0xf6, 0x10, 0x1a, 0x5b, - 0xe0, 0xf9, 0xf8, 0x29, 0xe3, 0x7b, 0x01, 0x6a, 0x23, 0x84, 0xc7, 0xab, 0x45, 0x19, 0x62, 0xcb, 0xde, 0x22, 0x95, - 0xd4, 0xcf, 0x02, 0x51, 0x46, 0xab, 0x80, 0xb6, 0xda, 0x63, 0x96, 0xc6, 0x1b, 0x08, 0x15, 0x4b, 0x7d, 0x0c, 0xa1, - 0x81, 0xc3, 0xef, 0x70, 0x00, 0x09, 0xbe, 0xe4, 0x9a, 0x6c, 0xee, 0x6d, 0x7e, 0x4f, 0xfb, 0xfc, 0xe1, 0x70, 0x7e, - 0x89, 0xa0, 0x74, 0x29, 0x7c, 0xa4, 0x12, 0x51, 0x3d, 0xc5, 0x4d, 0x09, 0xd9, 0x2c, 0x59, 0xe9, 0x07, 0xbf, 0xaa, - 0x5f, 0x00, 0x20, 0x0b, 0x81, 0x36, 0x91, 0xd9, 0x9f, 0xce, 0x54, 0x74, 0x01, 0x70, 0x88, 0x3f, 0x7e, 0x82, 0xe8, - 0x1b, 0x5a, 0xa6, 0xe5, 0xe3, 0x84, 0x87, 0xa0, 0xb5, 0x25, 0x9d, 0x44, 0xac, 0x14, 0xd8, 0x10, 0x09, 0xdf, 0xef, - 0x9f, 0xc7, 0x92, 0x0e, 0x34, 0x6a, 0x75, 0x6f, 0xdc, 0xea, 0x5e, 0xf9, 0xba, 0xee, 0xe4, 0xc6, 0x07, 0x45, 0xfb, - 0x6c, 0xde, 0xa8, 0x7c, 0xdf, 0xd6, 0x39, 0xbb, 0xd3, 0xbd, 0x23, 0xe7, 0xc4, 0xb7, 0xf7, 0x10, 0x8a, 0x1e, 0x9a, - 0x22, 0xcb, 0x92, 0x30, 0xa0, 0xb5, 0x76, 0xed, 0x59, 0x46, 0x07, 0xaf, 0x7d, 0x43, 0x88, 0xc8, 0x53, 0x7c, 0x12, - 0x72, 0x8b, 0xe3, 0x83, 0x02, 0xfd, 0x33, 0xe3, 0xcf, 0x9c, 0xf8, 0x61, 0xab, 0x5f, 0x00, 0xe7, 0xa6, 0x7b, 0xef, - 0x4e, 0xcc, 0x7a, 0x0c, 0xa5, 0x6c, 0xfc, 0xdf, 0xef, 0x13, 0x59, 0xa0, 0xd3, 0x11, 0x0d, 0x03, 0xc1, 0x5d, 0x54, - 0xff, 0xf7, 0x8a, 0xd7, 0x3d, 0x6b, 0x75, 0xbe, 0xfc, 0xd4, 0xe9, 0x49, 0xaf, 0x5e, 0xc6, 0x3d, 0xa0, 0x42, 0x07, - 0x08, 0xe7, 0x75, 0xbf, 0x61, 0xbb, 0x6f, 0x7e, 0x79, 0x77, 0xf4, 0x32, 0xb0, 0x49, 0x91, 0xd8, 0x56, 0xf2, 0x59, - 0x0f, 0x14, 0x7e, 0x3d, 0xd6, 0xab, 0x8b, 0x75, 0x8f, 0xf5, 0x50, 0x0b, 0x88, 0x1e, 0x16, 0xa0, 0xfe, 0xeb, 0xd9, - 0xa7, 0xa1, 0x70, 0x90, 0x8d, 0x53, 0x05, 0x8a, 0x2c, 0xf8, 0x0b, 0x31, 0x5a, 0x17, 0x04, 0x88, 0x6c, 0x09, 0x69, - 0xd5, 0xc9, 0xec, 0x71, 0xa9, 0x25, 0x19, 0x7c, 0x13, 0x90, 0xd9, 0x81, 0x95, 0x13, 0x94, 0x8e, 0x5b, 0x03, 0xae, - 0x6c, 0xf1, 0x68, 0xb7, 0x3f, 0x0d, 0xb2, 0xb3, 0xe6, 0xa4, 0xd1, 0x3e, 0xec, 0xd3, 0x3c, 0x40, 0x20, 0x92, 0xa9, - 0x08, 0x72, 0xcd, 0xbd, 0x25, 0x7d, 0x74, 0x38, 0xe7, 0x85, 0xfc, 0x73, 0x2a, 0x75, 0x88, 0x43, 0x89, 0x35, 0x10, - 0xa8, 0x3c, 0x43, 0x95, 0xc3, 0x06, 0x39, 0xfe, 0xd9, 0x91, 0xcc, 0x24, 0x26, 0x8b, 0xdc, 0xad, 0x99, 0x0a, 0x3f, - 0x10, 0x7c, 0xcc, 0x72, 0x0e, 0x5c, 0x60, 0xb3, 0xb9, 0xaf, 0xa6, 0xb8, 0xb8, 0x02, 0x7f, 0x4c, 0xe1, 0x57, 0x3c, - 0x85, 0x9d, 0x76, 0xbf, 0x2e, 0xaa, 0x14, 0x75, 0x1b, 0x85, 0x45, 0x25, 0x0b, 0xa6, 0x35, 0xa4, 0x89, 0x0e, 0xa3, - 0x3f, 0xc8, 0x19, 0x28, 0x08, 0xf9, 0x65, 0xd3, 0x00, 0x23, 0x95, 0x5c, 0x1e, 0x54, 0x49, 0xe0, 0x05, 0xd8, 0x06, - 0x15, 0x5b, 0x17, 0x10, 0x64, 0x9b, 0x14, 0x65, 0xfa, 0xa5, 0xc8, 0xeb, 0x30, 0x0b, 0xaa, 0x51, 0x5a, 0xfd, 0xa8, - 0x7f, 0x02, 0xf3, 0x36, 0x15, 0xa3, 0x5a, 0xc5, 0xe4, 0x37, 0xfa, 0xfd, 0x62, 0xd0, 0xfa, 0x90, 0xc1, 0x47, 0xaf, - 0x4d, 0x83, 0x3f, 0x3a, 0x0d, 0x76, 0x98, 0x68, 0x04, 0x40, 0x32, 0xa7, 0x96, 0x3c, 0x14, 0xfd, 0x11, 0xe4, 0x58, - 0xa3, 0xca, 0x29, 0x18, 0xac, 0xff, 0x78, 0xb4, 0x03, 0x53, 0x2f, 0x8e, 0xb6, 0x64, 0x07, 0xad, 0x7c, 0x03, 0xdc, - 0xaf, 0x91, 0x2d, 0x66, 0x39, 0x40, 0xb3, 0xd7, 0x88, 0x8c, 0x4f, 0x5e, 0x00, 0x63, 0xb6, 0xce, 0xc2, 0x48, 0xc4, - 0xc1, 0x58, 0x35, 0x66, 0xcc, 0xc0, 0xc0, 0x05, 0xba, 0x96, 0x49, 0x49, 0x1a, 0xd2, 0xc1, 0x80, 0x95, 0xb2, 0x85, - 0x03, 0x5e, 0x34, 0xc7, 0xed, 0x78, 0xd3, 0xa2, 0xf1, 0xc0, 0x76, 0xb1, 0xfd, 0xfd, 0xf7, 0xc5, 0xf6, 0x3a, 0xdc, - 0x92, 0x5e, 0x21, 0x67, 0x09, 0xfd, 0xfc, 0x51, 0xf6, 0x59, 0xc3, 0xc9, 0xa9, 0xd0, 0x0c, 0x2d, 0x45, 0x42, 0x29, - 0xde, 0xe9, 0x49, 0x81, 0xb1, 0x8c, 0x85, 0xbf, 0x07, 0xce, 0xe9, 0x42, 0x11, 0xb9, 0x03, 0xc7, 0xf1, 0x0d, 0x54, - 0x30, 0x6a, 0x38, 0x78, 0x19, 0xc3, 0xb6, 0x28, 0x66, 0x21, 0xe1, 0x14, 0xc2, 0xc5, 0x2a, 0xeb, 0xf7, 0xe5, 0x2f, - 0xea, 0xa2, 0x8b, 0x4c, 0xd6, 0x7d, 0x12, 0x8e, 0xcc, 0x58, 0x4e, 0xbd, 0x90, 0x3c, 0xef, 0x79, 0x32, 0x4d, 0x9e, - 0xe5, 0x41, 0x04, 0x90, 0xcf, 0xe1, 0x7d, 0x98, 0x66, 0x60, 0x95, 0x26, 0xe5, 0x47, 0x28, 0x7d, 0xf1, 0x79, 0xe5, - 0x07, 0x3a, 0x7b, 0x6e, 0x92, 0xe1, 0xcd, 0xaa, 0xf5, 0x26, 0xb5, 0xae, 0x8b, 0x07, 0xfc, 0x8b, 0x33, 0xd8, 0x38, - 0xd7, 0x99, 0xe0, 0xc0, 0x8b, 0xa4, 0xd6, 0x6b, 0xc6, 0x5f, 0x64, 0xb8, 0x2e, 0x55, 0x1b, 0x7d, 0x14, 0xa2, 0x73, - 0xc8, 0x54, 0x80, 0x42, 0x91, 0xf6, 0x0f, 0x4a, 0xad, 0x4c, 0x2a, 0x6d, 0x24, 0x80, 0xee, 0x61, 0xd2, 0x60, 0x8b, - 0xa1, 0x8c, 0xa5, 0x49, 0x94, 0x3b, 0x0d, 0xe2, 0xca, 0xfe, 0x5c, 0x49, 0x1c, 0x5a, 0x16, 0xc9, 0xbf, 0x77, 0x3d, - 0x7d, 0x85, 0xd4, 0x9d, 0x2c, 0x90, 0x19, 0xe3, 0x65, 0x1e, 0x7f, 0x02, 0xc2, 0x6c, 0xd0, 0x46, 0x45, 0x21, 0x84, - 0x6c, 0x10, 0x83, 0xc6, 0xcb, 0x3c, 0xfe, 0x5e, 0xd1, 0x78, 0xc8, 0x47, 0x91, 0xaf, 0xfe, 0x2a, 0xf5, 0x5f, 0xa1, - 0xcf, 0x4c, 0xf0, 0x08, 0xd5, 0x44, 0xff, 0xee, 0xf9, 0xec, 0x1e, 0xd4, 0x86, 0x51, 0x98, 0x99, 0xf2, 0x2b, 0xdf, - 0x14, 0x67, 0xaf, 0xbf, 0xa2, 0xab, 0x6c, 0xeb, 0x7e, 0xf4, 0xf1, 0x88, 0xc0, 0xda, 0x18, 0x5d, 0x71, 0x63, 0x00, - 0x39, 0x4c, 0xde, 0xaf, 0x28, 0x2d, 0x87, 0x34, 0x08, 0x1d, 0x34, 0x04, 0xbd, 0x92, 0xe8, 0x03, 0x89, 0x45, 0x8c, - 0xe1, 0x85, 0x78, 0x46, 0x6a, 0x32, 0xd1, 0x10, 0xaf, 0x88, 0xfd, 0x10, 0x2d, 0x39, 0x35, 0xd1, 0x8d, 0x30, 0xc5, - 0x40, 0x62, 0x67, 0x90, 0x9c, 0x24, 0xb5, 0xf2, 0x8b, 0x67, 0x92, 0xb0, 0xc4, 0xce, 0x43, 0x0c, 0x26, 0xb5, 0x74, - 0xa7, 0x37, 0x55, 0x7a, 0x77, 0xa4, 0xe5, 0xa0, 0x7d, 0x00, 0x76, 0x29, 0xe9, 0xfd, 0x93, 0x42, 0x11, 0x1f, 0xc2, - 0x38, 0x86, 0xf0, 0x2d, 0xa2, 0xba, 0x02, 0xe7, 0x5a, 0x81, 0xc6, 0x6a, 0xe0, 0xa1, 0x99, 0x55, 0xf3, 0x21, 0xa7, - 0x9f, 0x4a, 0xcb, 0x1f, 0x23, 0x1a, 0x1b, 0xad, 0x9b, 0xc3, 0x61, 0x4f, 0xab, 0x5e, 0x3a, 0x07, 0x5d, 0x36, 0x93, - 0x98, 0xb8, 0x81, 0x74, 0xfd, 0xe8, 0x37, 0x13, 0xf6, 0x22, 0x2a, 0xe4, 0x52, 0x08, 0x0a, 0x5a, 0x1d, 0x08, 0x1c, - 0x0a, 0x6f, 0x51, 0xe6, 0x8b, 0x98, 0x36, 0x10, 0x06, 0x9f, 0x1f, 0xc8, 0xcf, 0x37, 0x05, 0xa9, 0xd8, 0xb1, 0xae, - 0xfd, 0xfe, 0xa6, 0xf4, 0x00, 0x4f, 0xce, 0x24, 0x79, 0xda, 0x0c, 0x61, 0x45, 0x00, 0x8d, 0x59, 0x4d, 0x16, 0x27, - 0x5c, 0x99, 0xc3, 0x8f, 0x95, 0x57, 0xb2, 0x94, 0xa9, 0xf3, 0x54, 0x2f, 0x80, 0xa8, 0xe3, 0x0d, 0x5a, 0x91, 0xfa, - 0x15, 0x3a, 0x7b, 0xcd, 0x4a, 0xc8, 0x78, 0x78, 0xce, 0x79, 0x3a, 0x7a, 0x60, 0x09, 0x8f, 0xf0, 0xaf, 0x64, 0xa2, - 0x0f, 0xbf, 0x07, 0x0e, 0x37, 0xe3, 0x84, 0x47, 0x6e, 0xb3, 0xf7, 0x55, 0xb8, 0x82, 0x9b, 0x69, 0x01, 0x48, 0x6e, - 0x41, 0xd2, 0x04, 0x94, 0x90, 0xc8, 0x84, 0xcc, 0x9a, 0x92, 0x9f, 0x5b, 0xda, 0x06, 0x6b, 0x98, 0x74, 0x1e, 0xf0, - 0xa2, 0xd5, 0x47, 0xab, 0x89, 0x76, 0x99, 0xe5, 0xf3, 0x21, 0xce, 0x50, 0xcd, 0x71, 0x77, 0x06, 0x3f, 0x07, 0xbc, - 0x62, 0x55, 0x93, 0x8e, 0x76, 0x03, 0x2e, 0x3c, 0xb9, 0xce, 0xd3, 0xd1, 0x16, 0x7f, 0xc9, 0xfd, 0x01, 0xa0, 0x83, - 0xa9, 0x4b, 0xe0, 0x4f, 0xd5, 0x56, 0x53, 0xa9, 0x5f, 0x5a, 0xfb, 0x75, 0xdd, 0x59, 0xad, 0xdc, 0xb3, 0x2e, 0x43, - 0x7b, 0x64, 0xc8, 0x19, 0x33, 0xe0, 0xcf, 0x19, 0x4b, 0xfe, 0x9c, 0xb1, 0xe2, 0xcf, 0x19, 0x37, 0x46, 0x06, 0x50, - 0x82, 0x7b, 0xc9, 0x5f, 0xec, 0x11, 0x33, 0xc4, 0x6a, 0x50, 0x09, 0xac, 0x2c, 0xe5, 0xdc, 0x47, 0x4e, 0x31, 0xe5, - 0x94, 0xe1, 0xa5, 0xd3, 0x99, 0x3b, 0x90, 0xf3, 0x60, 0xe6, 0x0e, 0x93, 0xb3, 0x3e, 0xc5, 0xb1, 0x34, 0x26, 0x45, - 0x05, 0xe9, 0x9c, 0x0e, 0x37, 0xaf, 0x8e, 0xf3, 0x84, 0x65, 0x7c, 0xdc, 0x3e, 0x53, 0x20, 0xc4, 0x16, 0xcf, 0x90, - 0x48, 0xa9, 0x9a, 0xe5, 0x36, 0x7f, 0x38, 0xd4, 0xa3, 0x07, 0xbd, 0xd3, 0xc3, 0xaf, 0x84, 0xfd, 0x92, 0x79, 0xf6, - 0x09, 0x02, 0x98, 0x24, 0xf2, 0x4c, 0xc2, 0xd1, 0x8f, 0xe5, 0xe8, 0x6f, 0x1a, 0xfe, 0x2e, 0x43, 0x75, 0x77, 0x08, - 0x4c, 0x6c, 0xd9, 0x81, 0x43, 0x70, 0xba, 0xaa, 0x44, 0x02, 0x0e, 0x36, 0x1b, 0x16, 0xe9, 0x3d, 0x1e, 0xe2, 0x7c, - 0x50, 0xf8, 0x08, 0x0d, 0x33, 0x7a, 0xbf, 0xbf, 0x11, 0x5e, 0x25, 0x5b, 0x79, 0x38, 0x24, 0xd6, 0x5d, 0xd8, 0xd1, - 0xc7, 0xd1, 0x1e, 0x25, 0xd4, 0x7e, 0x54, 0xeb, 0x4d, 0xa5, 0x1e, 0xe4, 0x66, 0x17, 0x12, 0x83, 0x8a, 0xa5, 0xfa, - 0xf4, 0x4a, 0xf5, 0xa1, 0x66, 0x9d, 0xdf, 0xd5, 0x71, 0x9f, 0x8a, 0xd1, 0x5a, 0x4e, 0x08, 0x70, 0x1d, 0x24, 0x1a, - 0x1d, 0x00, 0xe3, 0x6c, 0xb3, 0xe5, 0xa5, 0xb6, 0x4e, 0x94, 0x8e, 0xe3, 0x5c, 0x1f, 0xc7, 0x87, 0x83, 0x14, 0x33, - 0x2e, 0x8f, 0xc4, 0x8c, 0xcb, 0x06, 0xe0, 0xcd, 0x3a, 0x0f, 0xea, 0xc3, 0xe1, 0x92, 0x2e, 0x45, 0xa6, 0xb3, 0x8d, - 0xf2, 0xb3, 0x1e, 0x3d, 0x3c, 0x4b, 0xd0, 0xdc, 0x5b, 0x61, 0xef, 0x45, 0xb2, 0x3d, 0x93, 0x75, 0xea, 0x65, 0xe4, - 0xd3, 0x0b, 0xf7, 0xec, 0x92, 0xab, 0x1f, 0x56, 0x5f, 0x4f, 0x7f, 0x15, 0x5e, 0xc4, 0x2a, 0xda, 0xad, 0x4b, 0x26, - 0xec, 0x2d, 0xa5, 0x92, 0x56, 0x79, 0xf9, 0x74, 0xe3, 0x07, 0x98, 0x99, 0xf6, 0xf4, 0x41, 0x36, 0xa2, 0xfa, 0xb3, - 0x12, 0xb5, 0x32, 0x4c, 0x16, 0xce, 0x4b, 0xa6, 0x9e, 0x0c, 0x78, 0xcc, 0x4a, 0x1e, 0xc9, 0x4e, 0x6f, 0x0c, 0x82, - 0x00, 0xd6, 0x39, 0x69, 0xd5, 0x19, 0x47, 0xa3, 0x55, 0xe5, 0xe2, 0x74, 0x95, 0x0b, 0x0c, 0xb7, 0x5b, 0xb3, 0x8d, - 0xaa, 0xb3, 0xdc, 0xd4, 0x2a, 0xe5, 0x3b, 0x80, 0x8f, 0x65, 0x95, 0x0b, 0x3a, 0xa6, 0x4c, 0x9d, 0x37, 0x10, 0x8c, - 0xad, 0x6a, 0x5c, 0x38, 0x35, 0x2e, 0x78, 0x44, 0xed, 0x6e, 0x9a, 0x7a, 0xb4, 0x05, 0x96, 0xd2, 0xd1, 0x8e, 0x97, - 0xa8, 0x52, 0xf8, 0xbb, 0xe0, 0xfb, 0x30, 0x8e, 0xbf, 0x2f, 0xb6, 0xea, 0x40, 0xbc, 0x2d, 0xb6, 0x48, 0xfb, 0x22, - 0xff, 0x42, 0x1c, 0xf0, 0x5a, 0xd7, 0x94, 0xd7, 0xd6, 0x9c, 0x06, 0xb6, 0x86, 0x91, 0x92, 0xc2, 0xb9, 0xf9, 0xf3, - 0x70, 0xa0, 0x95, 0x5d, 0xab, 0xbb, 0x42, 0xad, 0xc7, 0x1c, 0x36, 0xec, 0x45, 0x16, 0xee, 0x44, 0x09, 0x8e, 0x5c, - 0xf2, 0xaf, 0xc3, 0x41, 0xab, 0x2c, 0xd5, 0x91, 0x3e, 0xdb, 0x7f, 0x09, 0xc6, 0x0c, 0x5d, 0x9a, 0x80, 0x65, 0x63, - 0x24, 0xff, 0x6a, 0x9a, 0x79, 0xc3, 0x64, 0xcd, 0x14, 0x8e, 0x43, 0xc3, 0x08, 0x69, 0x40, 0xb7, 0x41, 0x6d, 0x78, - 0x32, 0xdf, 0x54, 0xe5, 0x57, 0x77, 0xa4, 0xda, 0x0f, 0x86, 0x97, 0x13, 0x71, 0x4e, 0x97, 0x24, 0xf5, 0x54, 0x42, - 0x49, 0x08, 0x76, 0xe9, 0x03, 0x39, 0xb1, 0x02, 0xb2, 0x96, 0xb1, 0xfc, 0x56, 0x0f, 0x08, 0xfd, 0xa7, 0xdd, 0x7a, - 0xa1, 0xff, 0x34, 0xcd, 0x16, 0xea, 0xfa, 0xc3, 0xe4, 0xbe, 0xa3, 0xd7, 0x1f, 0x1c, 0xde, 0xa9, 0xab, 0x8a, 0xab, - 0x78, 0x58, 0x1b, 0x26, 0xb9, 0x51, 0x16, 0xee, 0x8a, 0x4d, 0xad, 0x96, 0xa7, 0xe3, 0x30, 0x02, 0x33, 0x82, 0x02, - 0x64, 0x5d, 0xb7, 0x11, 0x31, 0xac, 0xe4, 0x32, 0x21, 0x9f, 0x10, 0x90, 0x45, 0xa9, 0x71, 0x3e, 0x6e, 0x81, 0x4a, - 0x04, 0x83, 0xd3, 0xd0, 0x5a, 0x75, 0x93, 0x1f, 0x55, 0x36, 0x76, 0x07, 0xe4, 0x90, 0x64, 0xb2, 0xb8, 0x1b, 0xdd, - 0x8a, 0x65, 0x51, 0x8a, 0x9f, 0xb1, 0x1e, 0xae, 0xd9, 0xc2, 0x7d, 0x06, 0x84, 0xf6, 0x13, 0xa5, 0xbd, 0x89, 0x34, - 0x41, 0xf7, 0x1d, 0x5b, 0x01, 0xc8, 0x00, 0x8a, 0xba, 0xda, 0xad, 0xcf, 0xf9, 0x39, 0x92, 0x66, 0x38, 0x8c, 0x6e, - 0x9f, 0xde, 0x05, 0x77, 0x83, 0x4b, 0xd4, 0x4a, 0x5f, 0xb2, 0xb8, 0x85, 0x41, 0xb5, 0x37, 0x4b, 0x38, 0xa8, 0x99, - 0xb5, 0x36, 0x02, 0xc1, 0x64, 0x0f, 0x05, 0x15, 0x73, 0x05, 0xfb, 0xa0, 0x60, 0x2d, 0x79, 0x1d, 0x1c, 0x6e, 0xed, - 0xcb, 0x4a, 0x71, 0xf1, 0xfc, 0x22, 0x69, 0x5d, 0x58, 0xca, 0x8b, 0xe7, 0x0d, 0x18, 0x5c, 0x8e, 0xb0, 0xa9, 0x2a, - 0x7f, 0xb2, 0x01, 0xd0, 0xad, 0x90, 0x22, 0x5e, 0x94, 0xc2, 0xb6, 0x95, 0xcf, 0x9c, 0xb0, 0xc1, 0x86, 0x3d, 0xc0, - 0xbd, 0x32, 0x28, 0x19, 0x5c, 0x88, 0x71, 0xbb, 0xd9, 0x05, 0xb8, 0x82, 0xa1, 0x30, 0xb6, 0xe6, 0x6f, 0x32, 0x2f, - 0x52, 0x02, 0x6e, 0x86, 0x28, 0x5f, 0x1b, 0x38, 0x99, 0xf4, 0xe4, 0x5a, 0xb2, 0x18, 0xb0, 0xa0, 0xc1, 0x77, 0xd4, - 0xfa, 0x3b, 0x93, 0x7f, 0xe3, 0xe9, 0xa1, 0x1f, 0x7c, 0xce, 0xbc, 0xa5, 0xcf, 0xde, 0x54, 0x32, 0x5a, 0x93, 0x44, - 0x79, 0xf5, 0x70, 0x09, 0x72, 0xc3, 0x72, 0xf4, 0xc0, 0x96, 0x20, 0x4e, 0x2c, 0x47, 0x09, 0x65, 0x74, 0x85, 0x7b, - 0x95, 0xd9, 0x32, 0x11, 0x48, 0x71, 0x60, 0x29, 0xe5, 0xde, 0x62, 0x1d, 0x2c, 0x71, 0x7f, 0x22, 0xb9, 0x80, 0x92, - 0x07, 0x50, 0xae, 0x14, 0x10, 0xf0, 0xe9, 0x00, 0xca, 0x97, 0xf2, 0x22, 0xfc, 0x89, 0x13, 0x35, 0x58, 0x8e, 0x1e, - 0x1a, 0xf6, 0xa3, 0x17, 0x5a, 0xf6, 0x87, 0x3b, 0xad, 0x69, 0x58, 0xf1, 0x3b, 0x98, 0x16, 0x13, 0xb7, 0x2f, 0x57, - 0x76, 0x55, 0x7c, 0xb6, 0x52, 0x67, 0x37, 0x35, 0x24, 0x61, 0x5f, 0x91, 0x55, 0x80, 0x83, 0x55, 0x11, 0xf7, 0x2c, - 0xcb, 0x7d, 0x18, 0xfd, 0xb9, 0x49, 0x4b, 0x61, 0xa1, 0x4a, 0xfa, 0xfb, 0xa6, 0x14, 0x48, 0x65, 0xa2, 0x13, 0x2d, - 0x04, 0x57, 0x60, 0x10, 0xb8, 0x17, 0x79, 0x0d, 0x80, 0x31, 0xe0, 0x52, 0xa0, 0x2c, 0xdb, 0x12, 0x42, 0xaa, 0xfb, - 0x19, 0xa8, 0xed, 0xc4, 0x7d, 0x1a, 0x91, 0xb5, 0x10, 0x7d, 0x15, 0x8c, 0x99, 0xf3, 0x52, 0xba, 0xc5, 0xa6, 0xab, - 0xcd, 0xea, 0x06, 0x9d, 0x4b, 0x5b, 0x6e, 0x7e, 0xc2, 0x16, 0x6b, 0x05, 0xca, 0x26, 0x24, 0x6d, 0xe7, 0x3c, 0x47, - 0xd9, 0x84, 0x96, 0xf6, 0x9e, 0x7a, 0x54, 0xa8, 0x4e, 0xb6, 0x5e, 0xaa, 0xa6, 0x16, 0x61, 0xb5, 0xb8, 0xa8, 0xfc, - 0x00, 0x74, 0x53, 0x69, 0xf5, 0xb2, 0xae, 0xd1, 0x14, 0x6a, 0xb5, 0x70, 0xdc, 0x68, 0x67, 0xd3, 0x65, 0x7a, 0x87, - 0x38, 0xab, 0xd2, 0x0e, 0xfd, 0x7d, 0xa6, 0x5d, 0x2f, 0x3b, 0xfa, 0xcd, 0xb8, 0xba, 0xc0, 0x85, 0xd8, 0x80, 0xcf, - 0xb9, 0xbf, 0xbc, 0xde, 0xf3, 0xb8, 0xe7, 0x1f, 0x0e, 0xc8, 0x9e, 0xd4, 0xfe, 0x50, 0x7d, 0xec, 0x0a, 0x86, 0x2c, - 0x8c, 0x52, 0x7f, 0x91, 0xf2, 0xde, 0x13, 0x1c, 0xf7, 0xcf, 0x55, 0x8f, 0xfd, 0x98, 0xf1, 0x7d, 0x5d, 0x6c, 0xa2, - 0x84, 0xa2, 0x1a, 0x7a, 0xab, 0x62, 0x53, 0x89, 0xb8, 0x78, 0xc8, 0x7b, 0x0c, 0x93, 0x61, 0x2c, 0x64, 0x2a, 0xfc, - 0x29, 0x53, 0xc1, 0x23, 0x84, 0x12, 0x37, 0xeb, 0x1e, 0x69, 0x37, 0x21, 0x4e, 0xa9, 0x16, 0xa5, 0x4c, 0xc6, 0xbf, - 0xf5, 0x13, 0x28, 0xcf, 0x29, 0x5a, 0xa6, 0x1f, 0x15, 0x2e, 0xd3, 0x37, 0xeb, 0xe3, 0xd2, 0x33, 0x11, 0xea, 0xcc, - 0xc5, 0xa6, 0xd6, 0xe9, 0x18, 0x3b, 0xa5, 0x53, 0x1b, 0xf6, 0xa5, 0x52, 0x5c, 0x56, 0x14, 0xfe, 0x8d, 0x44, 0x56, - 0x3d, 0x23, 0x8e, 0xff, 0x2b, 0x6b, 0x9f, 0x61, 0x15, 0xf8, 0x65, 0x20, 0xef, 0x17, 0x00, 0x1f, 0xd7, 0x75, 0x99, - 0xde, 0x6e, 0x80, 0x36, 0x84, 0x86, 0xbf, 0xe7, 0x23, 0x03, 0xa6, 0xfb, 0x08, 0x67, 0x48, 0x0f, 0x75, 0xce, 0xe9, - 0xac, 0x4c, 0xe7, 0x5c, 0x85, 0xb5, 0x04, 0x7b, 0x39, 0x69, 0x72, 0xb9, 0x2e, 0x41, 0xcd, 0x04, 0x6e, 0x1f, 0xda, - 0x23, 0x42, 0xa8, 0x4d, 0x59, 0x4d, 0x2f, 0xa1, 0xe6, 0x9d, 0x9c, 0x76, 0x34, 0x29, 0xc1, 0x55, 0x43, 0x67, 0xe5, - 0xfa, 0xaf, 0xc3, 0xa1, 0x77, 0x9b, 0x15, 0xd1, 0x1f, 0x3d, 0xf4, 0x77, 0xdc, 0xde, 0xa4, 0x5f, 0x20, 0x5a, 0xc6, - 0xfa, 0x1b, 0x32, 0xa0, 0xe3, 0xc9, 0xf0, 0xb6, 0xd8, 0xf6, 0xd8, 0x17, 0xd4, 0x60, 0xe9, 0xeb, 0xc7, 0x1f, 0x20, - 0xa1, 0xea, 0xda, 0x17, 0x16, 0x4f, 0x98, 0xa7, 0x44, 0xdb, 0xc2, 0x87, 0xb0, 0xd0, 0x2f, 0x10, 0x19, 0x09, 0xe1, - 0xa6, 0xb2, 0x7b, 0x94, 0xb4, 0x0b, 0x7d, 0xe9, 0x6b, 0xd9, 0x57, 0xbe, 0x73, 0x01, 0xb0, 0xb2, 0xcf, 0x6d, 0xb8, - 0x27, 0xfd, 0x29, 0xd5, 0x87, 0xed, 0x6f, 0xc9, 0x02, 0x0a, 0x2d, 0xac, 0xa7, 0x72, 0x76, 0xae, 0x4b, 0x9e, 0x66, - 0xd3, 0xfd, 0x1a, 0xf6, 0xa8, 0x7b, 0xf4, 0x9a, 0x0a, 0xce, 0x2f, 0xcd, 0xe8, 0xfd, 0xd3, 0x50, 0xa8, 0x8e, 0x3a, - 0x77, 0x90, 0x75, 0x69, 0x5d, 0x72, 0x7e, 0xb3, 0x72, 0x47, 0x61, 0x7e, 0x1f, 0x82, 0x67, 0x58, 0xf7, 0xee, 0xe2, - 0xbc, 0xf7, 0x67, 0x6b, 0x8e, 0xfc, 0x98, 0xcd, 0x52, 0xc4, 0x22, 0x99, 0x83, 0xd5, 0x0f, 0xfd, 0x3c, 0xf6, 0xdb, - 0x20, 0x87, 0xe3, 0xa6, 0x01, 0x1d, 0x36, 0x64, 0xd6, 0xbe, 0x44, 0xe0, 0x54, 0x23, 0x48, 0x53, 0x13, 0xd4, 0x2c, - 0x0f, 0x91, 0xd8, 0x2e, 0x65, 0xdb, 0x20, 0xd7, 0x5d, 0x30, 0xcd, 0x91, 0xf6, 0x0c, 0xde, 0x37, 0x69, 0x92, 0x0a, - 0xcd, 0x22, 0x6d, 0x95, 0x8c, 0x7f, 0x47, 0xda, 0x4c, 0xc9, 0x1e, 0x5b, 0x03, 0xef, 0x25, 0x28, 0x27, 0xc3, 0x14, - 0xc3, 0x77, 0x7c, 0xbd, 0xf3, 0x98, 0x7b, 0xce, 0x31, 0xdb, 0xa4, 0xec, 0x08, 0x26, 0xc9, 0xc6, 0x37, 0x14, 0x6f, - 0xf8, 0xfe, 0xb6, 0x12, 0x25, 0x80, 0x5e, 0x16, 0xfc, 0x85, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, - 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, - 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, - 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, - 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, - 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, - 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, - 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, - 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, 0xf3, 0xfd, 0x95, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, - 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, - 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, - 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, - 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, - 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, - 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, - 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, - 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, - 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, - 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, - 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, - 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, - 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, - 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, - 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, - 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, - 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, - 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, - 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, - 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, - 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, - 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, - 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd1, - 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, - 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe1, 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, - 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, - 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, - 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, - 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, - 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, - 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, - 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, - 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, - 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, - 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, - 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, - 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0x7c, 0xa1, 0x56, 0xda, 0x59, 0x99, - 0x78, 0x35, 0xcb, 0xc0, 0x59, 0xe0, 0xa2, 0xf2, 0x59, 0xa6, 0x55, 0x4f, 0x55, 0x82, 0x3e, 0xaf, 0xe4, 0x04, 0x57, - 0x82, 0x93, 0x0d, 0xc8, 0x2f, 0x40, 0x92, 0xa6, 0x94, 0x35, 0xe5, 0x8b, 0x4b, 0xba, 0x21, 0xa3, 0xe7, 0xbc, 0xe7, - 0x45, 0xc3, 0xd0, 0xbf, 0xf0, 0x4a, 0x08, 0xdf, 0xc4, 0x6d, 0x1b, 0xa5, 0xb0, 0xbf, 0x09, 0x2c, 0x3e, 0x61, 0x3f, - 0x78, 0x4b, 0x7f, 0x3a, 0x0e, 0xc2, 0x21, 0x72, 0x43, 0xc5, 0x1c, 0xd8, 0xd3, 0x80, 0xc5, 0x26, 0xbe, 0xda, 0x4c, - 0xe2, 0xc1, 0xc0, 0xd7, 0x19, 0x8b, 0x59, 0x0c, 0x34, 0xc8, 0xf1, 0xe0, 0x72, 0xae, 0x4f, 0x08, 0xfd, 0x30, 0xa2, - 0x72, 0x54, 0xa0, 0x73, 0x10, 0x0d, 0x96, 0x80, 0xa7, 0xde, 0xca, 0x06, 0x49, 0xc6, 0x24, 0x93, 0xb8, 0xd6, 0x24, - 0xd5, 0xe1, 0x84, 0xd6, 0x81, 0x8e, 0xab, 0x0b, 0xe8, 0x7c, 0x5c, 0xf7, 0x3e, 0x5e, 0x0d, 0x17, 0x54, 0xfa, 0x85, - 0x18, 0x78, 0xf5, 0x74, 0x1c, 0x5c, 0xd2, 0xad, 0x70, 0xb1, 0x0a, 0xb7, 0x3f, 0xcb, 0x07, 0x8e, 0x3b, 0x2a, 0x69, - 0x08, 0x0c, 0xde, 0x1e, 0xba, 0x9b, 0x19, 0x1a, 0xea, 0xa4, 0x7d, 0x18, 0x87, 0x72, 0x88, 0x55, 0x2b, 0x2e, 0xa4, - 0x37, 0x82, 0x6f, 0x17, 0x8a, 0xb1, 0x6c, 0xec, 0xd2, 0x50, 0x14, 0xfe, 0x0a, 0x60, 0x87, 0xda, 0x5f, 0xa9, 0xe4, - 0x63, 0x64, 0x54, 0xd3, 0x40, 0xc7, 0x00, 0x2c, 0x59, 0x9a, 0x48, 0xaa, 0x48, 0x23, 0xf1, 0x47, 0x66, 0xac, 0xa3, - 0xa6, 0xeb, 0x0b, 0xa6, 0xaa, 0x45, 0xd2, 0xed, 0x4c, 0x62, 0x39, 0x91, 0xa4, 0xb6, 0xfb, 0x88, 0x18, 0x0c, 0x7c, - 0xb0, 0x11, 0xd3, 0x4c, 0x84, 0x23, 0x1e, 0x95, 0xc8, 0xa2, 0xcb, 0x6f, 0xa3, 0x4c, 0xda, 0xbe, 0xac, 0xc8, 0x16, - 0x04, 0xd3, 0x93, 0xe8, 0x83, 0x24, 0xe5, 0x54, 0x24, 0xd2, 0x8c, 0x10, 0xe0, 0xc7, 0x93, 0xf2, 0x4a, 0x7f, 0x0e, - 0x9a, 0x56, 0x82, 0x97, 0x0c, 0x92, 0x47, 0xe2, 0x67, 0x52, 0x30, 0x8b, 0xb1, 0x6a, 0x30, 0xc0, 0x72, 0xaa, 0x67, - 0x8e, 0x49, 0xfa, 0x6f, 0x9d, 0x4e, 0xd8, 0x2f, 0xbd, 0xdc, 0xd6, 0xf2, 0xa6, 0xb9, 0xf7, 0xd2, 0xab, 0x58, 0xaa, - 0x61, 0x19, 0xf4, 0x5f, 0x13, 0xed, 0x82, 0xad, 0x2d, 0x63, 0xc2, 0xaa, 0x1f, 0x40, 0xda, 0x23, 0x5d, 0x5e, 0x35, - 0xcc, 0x99, 0xe0, 0xd1, 0x85, 0x35, 0x0f, 0xa2, 0x0b, 0xe1, 0x23, 0x97, 0xdd, 0x24, 0xb9, 0x1a, 0x4f, 0xfc, 0x70, - 0x30, 0x50, 0x00, 0xb4, 0xb4, 0x4e, 0x8a, 0x41, 0xf8, 0x4c, 0xc8, 0x81, 0x34, 0x3a, 0xaa, 0x02, 0x2c, 0x96, 0xd9, - 0x55, 0x39, 0xc9, 0x06, 0x03, 0x1f, 0xc4, 0xc6, 0xc4, 0x6e, 0x68, 0x36, 0xf7, 0xd9, 0x89, 0x82, 0xac, 0x36, 0x87, - 0xad, 0x99, 0x6e, 0x81, 0x01, 0xc0, 0x20, 0x22, 0x58, 0xee, 0x73, 0x23, 0x1f, 0x51, 0xa7, 0xa7, 0x30, 0x02, 0x82, - 0x5f, 0x4e, 0x04, 0x22, 0x17, 0x09, 0xd4, 0x03, 0xcc, 0x04, 0x98, 0x51, 0xc5, 0xf0, 0x12, 0xd8, 0xc5, 0x73, 0xf3, - 0x8a, 0x41, 0xff, 0xa2, 0x49, 0x96, 0x68, 0x2a, 0x71, 0x34, 0x46, 0x4e, 0xa5, 0x31, 0x32, 0x20, 0x76, 0x71, 0xfc, - 0x7b, 0x4a, 0x8f, 0x82, 0x94, 0x7d, 0xae, 0x0c, 0x71, 0x38, 0x8a, 0xaf, 0x60, 0xd5, 0x38, 0x1c, 0x6a, 0xf3, 0x7a, - 0x3a, 0xab, 0xe7, 0x03, 0x11, 0xc0, 0x7f, 0x43, 0xc1, 0x7e, 0xd1, 0x54, 0xe4, 0x06, 0xa9, 0xf3, 0x70, 0x48, 0x41, - 0x3e, 0xd5, 0x4d, 0xfe, 0xbe, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, - 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, - 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, - 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, - 0x7f, 0x95, 0xee, 0xcd, 0xa9, 0x0d, 0x72, 0x00, 0xdb, 0xbd, 0x87, 0xdb, 0x31, 0x7a, 0x20, 0x83, 0x37, 0x42, 0xce, - 0x39, 0xbf, 0x9c, 0x5a, 0x33, 0x26, 0x1a, 0x16, 0xac, 0x1c, 0x46, 0x7e, 0x80, 0x8c, 0x97, 0x53, 0x60, 0x65, 0x3f, - 0x2a, 0xe2, 0xd2, 0x1f, 0x46, 0xfe, 0xc5, 0xf3, 0x20, 0xe3, 0x5e, 0x34, 0xec, 0xf8, 0x02, 0xec, 0xd5, 0x17, 0xcf, - 0x59, 0x34, 0xe0, 0xd5, 0x55, 0x3d, 0xcd, 0x82, 0x61, 0xc6, 0xa2, 0xab, 0x62, 0x08, 0x3e, 0xb4, 0x2f, 0xca, 0x41, - 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x47, 0x70, 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, - 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x85, 0xd4, 0x6c, 0x14, 0x68, 0x4e, 0xae, 0xd0, 0x9c, - 0xac, 0x84, 0x5a, 0xf2, 0x49, 0x85, 0x13, 0x76, 0x3e, 0xc9, 0x95, 0xdd, 0x68, 0x8c, 0x81, 0x8b, 0xf6, 0xdc, 0x16, - 0x46, 0x66, 0x3a, 0x4b, 0xd1, 0x80, 0x85, 0x67, 0xe2, 0x94, 0xc6, 0x80, 0xf6, 0xe5, 0xc0, 0xd2, 0x86, 0xfc, 0x28, - 0x67, 0x06, 0xda, 0x86, 0x94, 0x46, 0xcd, 0xc0, 0x9f, 0xa9, 0x09, 0xf3, 0x2b, 0x58, 0x89, 0x20, 0xaa, 0x0b, 0x30, - 0x49, 0x72, 0x32, 0x1a, 0x29, 0x2b, 0x91, 0x9c, 0x03, 0xde, 0x47, 0xf0, 0x64, 0x11, 0xdb, 0xda, 0x9f, 0xd2, 0xff, - 0xea, 0xf0, 0xb9, 0xf4, 0x9f, 0x09, 0x60, 0x21, 0x97, 0x06, 0x91, 0x81, 0xc2, 0x21, 0x35, 0x95, 0x88, 0x13, 0xc7, - 0x33, 0xf0, 0x0d, 0x5c, 0xa0, 0x29, 0xa0, 0x3f, 0xa8, 0x19, 0x45, 0x64, 0xe1, 0xaf, 0x9e, 0xdd, 0xd4, 0x8d, 0x9e, - 0x67, 0xce, 0x6b, 0xd0, 0xcc, 0x40, 0x48, 0x8f, 0x53, 0xf5, 0x36, 0x24, 0x3a, 0x2f, 0x2f, 0xf5, 0xcb, 0x84, 0x48, - 0x56, 0x44, 0x9e, 0xbe, 0xcf, 0xc1, 0x3c, 0xa2, 0x08, 0x1d, 0x5c, 0x99, 0x87, 0xc3, 0xb9, 0xa0, 0xf0, 0x1d, 0xe5, - 0xf9, 0x80, 0xd3, 0x2c, 0x4a, 0x40, 0x1b, 0xc8, 0x72, 0x53, 0xe6, 0x3a, 0x69, 0x99, 0xba, 0xf7, 0x60, 0x25, 0xa8, - 0xd0, 0xcd, 0x29, 0x28, 0x94, 0x91, 0xa0, 0x94, 0x56, 0x83, 0x50, 0xaa, 0xc3, 0x22, 0x88, 0x1c, 0xb2, 0x10, 0x70, - 0x33, 0x15, 0x8d, 0x96, 0x34, 0x3c, 0xc2, 0xb9, 0x81, 0x42, 0x00, 0x12, 0x7b, 0xaa, 0x28, 0xe3, 0x72, 0x08, 0xf8, - 0x28, 0xe1, 0x10, 0x67, 0x4d, 0xda, 0xf2, 0x1c, 0xc4, 0xb1, 0x5c, 0xf2, 0x75, 0x85, 0x60, 0x10, 0xa1, 0xcf, 0x90, - 0x3f, 0x59, 0xce, 0xbf, 0x5b, 0x87, 0x69, 0x47, 0xf8, 0xb0, 0xab, 0x2d, 0xb8, 0x98, 0xdd, 0xce, 0x27, 0x10, 0xdf, - 0x72, 0x3b, 0x3f, 0xc6, 0x10, 0x59, 0xf8, 0x83, 0xbb, 0xa1, 0xe4, 0x8a, 0x42, 0x97, 0xf5, 0x88, 0x14, 0xd9, 0xd3, - 0x35, 0x47, 0x10, 0x1c, 0x68, 0xd5, 0x20, 0x43, 0x23, 0xf1, 0xc5, 0x73, 0xc8, 0x1a, 0xac, 0xf9, 0xe7, 0x8a, 0x9c, - 0xd5, 0xfd, 0xc9, 0x06, 0xaa, 0x49, 0x26, 0x6b, 0x45, 0xe5, 0xfc, 0xf5, 0xaa, 0x2c, 0x4f, 0x56, 0x65, 0xb8, 0x1a, - 0x74, 0x55, 0x65, 0xc9, 0x91, 0xda, 0x00, 0xad, 0xe9, 0x0a, 0x31, 0x14, 0xb2, 0x06, 0x4b, 0xab, 0x2a, 0x6b, 0xea, - 0x13, 0x08, 0xf4, 0x01, 0x96, 0x51, 0xb3, 0x9f, 0x0e, 0xff, 0x15, 0xfc, 0x4b, 0x85, 0x2c, 0xd5, 0x69, 0x9d, 0x89, - 0x5f, 0x83, 0x25, 0xc3, 0x3f, 0x7e, 0x0b, 0xd6, 0x80, 0x25, 0x40, 0x96, 0xbb, 0x8d, 0x8d, 0xd6, 0x2b, 0xaf, 0x10, - 0x5f, 0x6a, 0x7d, 0xd1, 0x6f, 0xdd, 0x26, 0x6a, 0x05, 0x18, 0xa1, 0xd0, 0x22, 0xc0, 0x56, 0x0f, 0xdc, 0x53, 0xf0, - 0x03, 0x31, 0x9c, 0x6b, 0xd2, 0x9a, 0x3a, 0xe1, 0x75, 0x36, 0x8e, 0x44, 0x54, 0x6f, 0xe1, 0xe2, 0x5e, 0x6f, 0x2d, - 0xfe, 0x46, 0x05, 0x02, 0x20, 0x8b, 0x29, 0xd6, 0xce, 0x1b, 0xd2, 0x2b, 0xc3, 0x4e, 0x42, 0xef, 0x0d, 0x3b, 0x81, - 0xbc, 0x38, 0xec, 0x14, 0xba, 0x44, 0xdb, 0x29, 0x52, 0x13, 0x6d, 0x27, 0x2d, 0x56, 0x61, 0x09, 0xc1, 0xaf, 0xda, - 0x5b, 0x47, 0xd9, 0xbe, 0xc8, 0x12, 0xa6, 0x2d, 0x60, 0x94, 0x5b, 0xf5, 0x99, 0x53, 0xc4, 0x4a, 0xd9, 0x3b, 0x9d, - 0x54, 0xb9, 0x8b, 0x7c, 0x6a, 0x35, 0x45, 0x26, 0x7f, 0x7f, 0xdc, 0x22, 0xf9, 0xe4, 0xe7, 0x76, 0xc3, 0x64, 0xfa, - 0xc7, 0xa3, 0x2f, 0xa0, 0x2b, 0xb2, 0xd3, 0x27, 0x10, 0x90, 0xa9, 0xa0, 0x5a, 0xdd, 0x2a, 0xa6, 0x79, 0xbb, 0xca, - 0x6e, 0x2f, 0x94, 0x18, 0x4e, 0x67, 0x27, 0xe1, 0xd1, 0x66, 0xc8, 0xc0, 0x21, 0x08, 0x14, 0x42, 0x45, 0x31, 0x3c, - 0x02, 0xb5, 0x46, 0xf2, 0x01, 0x7e, 0xb4, 0x3b, 0x15, 0x44, 0x6a, 0x37, 0x15, 0x37, 0x4e, 0x6e, 0xba, 0x5e, 0x0a, - 0xd4, 0x3a, 0x25, 0x2b, 0x80, 0x12, 0xa2, 0xfe, 0x24, 0xb6, 0xf5, 0x2b, 0xb8, 0x62, 0xf3, 0x7d, 0xa3, 0xe8, 0xc9, - 0xf5, 0x29, 0xea, 0x56, 0x5c, 0x9d, 0xa6, 0xad, 0xe6, 0xd8, 0x71, 0x86, 0x1c, 0x3c, 0x2b, 0x08, 0xb6, 0xa3, 0x12, - 0xe5, 0x75, 0xbb, 0xe9, 0x98, 0xd8, 0xea, 0x9f, 0x45, 0xb5, 0xb9, 0x83, 0x8a, 0x88, 0xf8, 0x28, 0xbb, 0x79, 0xd2, - 0x7e, 0x07, 0x7b, 0xac, 0xd5, 0x20, 0xb2, 0xcf, 0xe0, 0x2a, 0xd7, 0x69, 0x91, 0xdb, 0x32, 0x38, 0xff, 0xf0, 0x6a, - 0x57, 0x61, 0x93, 0x63, 0x5d, 0x5d, 0xcd, 0x54, 0x27, 0x15, 0x1b, 0x18, 0x6b, 0x5a, 0x4b, 0x35, 0x8f, 0x21, 0xe9, - 0xae, 0x2c, 0xce, 0xaa, 0xa4, 0x9b, 0x9e, 0x1b, 0x67, 0x0a, 0x31, 0x70, 0xb6, 0x1a, 0x2d, 0x67, 0x18, 0xa2, 0xeb, - 0xc3, 0x2c, 0xf1, 0x5b, 0x3d, 0xe5, 0x3e, 0x0f, 0xb7, 0x7e, 0x57, 0x2f, 0x38, 0x99, 0xec, 0x27, 0xc7, 0xb9, 0xdb, - 0x45, 0xda, 0x4f, 0x7c, 0x1b, 0xe6, 0x5f, 0xdf, 0x20, 0xee, 0x44, 0xfd, 0xcf, 0x0a, 0x80, 0x06, 0x37, 0x79, 0x2c, - 0x51, 0xea, 0xf7, 0xaa, 0xfa, 0x41, 0xcd, 0x54, 0x4d, 0x03, 0xc1, 0x9c, 0x4a, 0x01, 0x7f, 0xb8, 0x5d, 0xb8, 0xe2, - 0x11, 0x37, 0x2c, 0x8c, 0x7f, 0x7a, 0x35, 0x3b, 0x15, 0x54, 0x06, 0x6e, 0xc6, 0x7f, 0x7a, 0x82, 0x9d, 0xc2, 0x5a, - 0x01, 0x59, 0xe1, 0x4f, 0x2f, 0x7f, 0xe4, 0xfd, 0x8a, 0xff, 0xe9, 0x55, 0x8f, 0xbc, 0x8f, 0x38, 0x2f, 0x7f, 0x22, - 0xa9, 0x13, 0xa2, 0xba, 0xfc, 0x49, 0x98, 0x62, 0xab, 0x34, 0x7f, 0x4d, 0x0a, 0x9f, 0xe0, 0x33, 0xf0, 0x1d, 0xae, - 0xc2, 0xad, 0xf9, 0x0d, 0x1e, 0x3b, 0x16, 0xdb, 0x2e, 0xf5, 0x05, 0x94, 0x23, 0xb0, 0x88, 0xdc, 0x7e, 0xbb, 0xb2, - 0x5f, 0x2d, 0x8c, 0x32, 0xc6, 0xee, 0x4b, 0x56, 0xa2, 0x74, 0xd6, 0xef, 0x17, 0x52, 0x30, 0xb2, 0x0b, 0x6b, 0xb4, - 0x47, 0xa9, 0x7a, 0xf5, 0x3a, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, - 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, - 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, - 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0x5e, 0xe4, 0x18, 0x5b, 0x91, 0x03, 0x07, 0x32, 0xfc, 0x80, 0xc0, - 0x7b, 0xd9, 0xbf, 0x82, 0xc1, 0x30, 0xc1, 0x8d, 0x8c, 0x3a, 0x39, 0x67, 0x7f, 0x62, 0x60, 0x06, 0xf5, 0xa4, 0x76, - 0x9f, 0xdd, 0xab, 0xc0, 0x5e, 0x38, 0x03, 0xda, 0xbb, 0x31, 0xfa, 0x59, 0x15, 0x6b, 0x27, 0xfd, 0x53, 0xb1, 0x86, - 0x64, 0x3a, 0x2c, 0x8e, 0xb6, 0x69, 0x78, 0x24, 0x4f, 0x8e, 0xe3, 0x4d, 0xff, 0x70, 0x18, 0xe3, 0xc7, 0x51, 0x7e, - 0x6d, 0x01, 0xaf, 0xe2, 0x16, 0xd2, 0x58, 0xa4, 0xe8, 0x1d, 0x88, 0x39, 0x14, 0xbd, 0x64, 0xbf, 0x65, 0xbc, 0x9c, - 0x08, 0x4a, 0x49, 0x62, 0xc3, 0x3b, 0xd2, 0xd3, 0xb4, 0x1e, 0x6d, 0x65, 0xc0, 0x7e, 0x3d, 0xda, 0xd1, 0x5f, 0xa0, - 0x78, 0xb4, 0xf0, 0x97, 0xf4, 0x77, 0x71, 0x37, 0xf7, 0x9c, 0x6f, 0x1a, 0xdf, 0x11, 0x17, 0x28, 0xd6, 0xec, 0xfe, - 0x9a, 0x96, 0xce, 0x3a, 0x10, 0x1c, 0xf0, 0x16, 0xbb, 0x68, 0xdf, 0x6f, 0x5c, 0xa7, 0xa7, 0xfd, 0xb7, 0x6e, 0x8d, - 0xf2, 0xbd, 0x7f, 0x4a, 0x94, 0x83, 0xfd, 0x6b, 0x17, 0xcd, 0xdf, 0x7e, 0xca, 0x90, 0x54, 0x68, 0x6e, 0xb0, 0x9d, - 0x6c, 0x11, 0xd6, 0xc6, 0x38, 0xa8, 0xd8, 0x5d, 0x19, 0x46, 0xc0, 0xa0, 0x8e, 0xfd, 0x8f, 0x3e, 0x9b, 0x36, 0x64, - 0x1f, 0x00, 0x2a, 0x57, 0x21, 0x60, 0x0f, 0xc0, 0x89, 0x46, 0xb8, 0x01, 0x6e, 0x35, 0x5a, 0xd2, 0x41, 0xdd, 0x16, - 0x0c, 0x44, 0x4b, 0xd8, 0xc8, 0xdb, 0xae, 0x4e, 0x5f, 0x11, 0x3e, 0xd4, 0x4e, 0x4a, 0x87, 0xf2, 0x57, 0xcf, 0xd9, - 0xff, 0xec, 0xb0, 0xa6, 0xa6, 0xdc, 0x00, 0x66, 0xce, 0x4a, 0xe4, 0x15, 0x42, 0xa7, 0xc8, 0xef, 0x55, 0x5d, 0x89, - 0xe1, 0xb2, 0x16, 0x65, 0x67, 0x76, 0xeb, 0x44, 0xef, 0x9c, 0x82, 0x5a, 0x2a, 0x1b, 0xe4, 0x24, 0xd5, 0xe6, 0x23, - 0x6b, 0x05, 0x25, 0xea, 0x1a, 0x05, 0x8e, 0x4f, 0xb9, 0x76, 0xff, 0xef, 0x9c, 0x09, 0x6a, 0xb6, 0x51, 0xdd, 0x5f, - 0xeb, 0xa7, 0xaa, 0x26, 0xb1, 0x00, 0x97, 0x93, 0x34, 0xef, 0x78, 0x84, 0xd5, 0x3f, 0x4e, 0x96, 0x22, 0xd0, 0xeb, - 0x88, 0x76, 0x25, 0x20, 0x41, 0x3b, 0x39, 0x0b, 0x15, 0x81, 0x02, 0x7d, 0xfd, 0xfb, 0x4d, 0x9a, 0xc5, 0x72, 0x35, - 0xdb, 0xc3, 0x44, 0x59, 0xac, 0x87, 0x08, 0x72, 0x66, 0xea, 0x60, 0xbf, 0xa7, 0x19, 0xcd, 0xc2, 0x2b, 0x53, 0x82, - 0x4b, 0x71, 0x15, 0x15, 0x39, 0xf8, 0x1c, 0xe2, 0x0b, 0x9f, 0x0a, 0xb9, 0x41, 0x44, 0xd3, 0xef, 0x25, 0xaa, 0x1d, - 0x29, 0x90, 0x43, 0xc9, 0x4f, 0x88, 0xbf, 0x64, 0x6d, 0x8c, 0xfb, 0xa5, 0x53, 0xed, 0x57, 0x0a, 0xc1, 0xfd, 0x67, - 0x5b, 0x6c, 0x54, 0x79, 0xa2, 0x47, 0x9f, 0x62, 0xfd, 0x4f, 0x16, 0x50, 0xaa, 0xfb, 0x36, 0x38, 0x15, 0x8f, 0xc2, - 0x4d, 0x5d, 0xdc, 0x20, 0xb4, 0x40, 0x39, 0xaa, 0x8a, 0x4d, 0x19, 0x11, 0x27, 0xec, 0xa6, 0x2e, 0x7a, 0x9a, 0x03, - 0x9d, 0x3a, 0x2c, 0x4d, 0xe4, 0x89, 0xd0, 0x6e, 0x41, 0xf7, 0x34, 0xc7, 0x4a, 0xbc, 0x94, 0xa5, 0x83, 0xac, 0x13, - 0x69, 0x42, 0xe5, 0xae, 0xae, 0x3a, 0x2a, 0x95, 0xba, 0xe1, 0x4d, 0xaa, 0x19, 0x7f, 0x97, 0xe6, 0x4f, 0x2c, 0xfb, - 0x4d, 0xeb, 0xb7, 0x5a, 0xed, 0x8d, 0xd5, 0xa3, 0x92, 0x35, 0xc7, 0xd9, 0x84, 0xa4, 0xf4, 0x09, 0xdb, 0xcd, 0xa4, - 0x6b, 0x1d, 0x78, 0x12, 0x5c, 0x0e, 0x3d, 0x01, 0x15, 0x83, 0x26, 0xde, 0xee, 0x02, 0xf5, 0x08, 0x3c, 0x03, 0xe5, - 0x13, 0xb5, 0x0e, 0xf8, 0x79, 0xad, 0xe5, 0x29, 0x23, 0x0c, 0xab, 0x9d, 0x45, 0xcb, 0xc1, 0x79, 0xa7, 0x08, 0x5c, - 0xbb, 0x12, 0x78, 0x3e, 0x54, 0xef, 0x85, 0x80, 0xe1, 0xfe, 0xa9, 0x50, 0xd9, 0xec, 0x66, 0x38, 0x8f, 0x1a, 0xa7, - 0x07, 0xda, 0xdb, 0xae, 0xf5, 0x50, 0xef, 0xba, 0x9d, 0xdb, 0x4a, 0xf7, 0x7e, 0xed, 0x64, 0xd2, 0x05, 0xb4, 0x36, - 0x9f, 0x7d, 0x67, 0x57, 0x5a, 0x37, 0x3d, 0x67, 0x0f, 0xb6, 0x6e, 0x89, 0xce, 0x05, 0xd1, 0xe4, 0xf7, 0x03, 0xcf, - 0xda, 0x76, 0xf4, 0xdb, 0xb4, 0x63, 0x9b, 0x7b, 0xa8, 0x7b, 0x05, 0xb5, 0xde, 0xd0, 0xbc, 0x7f, 0xe6, 0xda, 0x76, - 0x7c, 0xf5, 0xeb, 0xba, 0xc3, 0x75, 0xde, 0x04, 0xc7, 0x4d, 0xd7, 0xb6, 0xda, 0xd9, 0xcf, 0xdd, 0xbd, 0xb5, 0x88, - 0xc2, 0x2c, 0xfb, 0xb1, 0x28, 0xfe, 0xa8, 0xf4, 0x1d, 0x81, 0x8e, 0xee, 0xbc, 0xa8, 0xd3, 0xe5, 0xee, 0x03, 0x61, - 0x3c, 0x79, 0xf5, 0x11, 0xd1, 0xad, 0xef, 0x33, 0xf7, 0x2b, 0xc0, 0x8d, 0xe0, 0x0e, 0xa2, 0xbd, 0x5b, 0xea, 0x93, - 0x5a, 0x7d, 0xad, 0xd7, 0xce, 0xd3, 0xf3, 0x9b, 0xce, 0xed, 0x77, 0xdf, 0x1c, 0x6d, 0xbd, 0xc7, 0x85, 0xb5, 0xb2, - 0xf4, 0x54, 0x15, 0xec, 0xcd, 0xf2, 0x54, 0x15, 0x4c, 0x1e, 0x78, 0xcd, 0x7e, 0x41, 0x83, 0x2b, 0x1d, 0x6d, 0xbc, - 0x27, 0x6a, 0xe0, 0x16, 0x85, 0xa5, 0xc3, 0x2f, 0xb9, 0x99, 0xbc, 0xc2, 0xfd, 0xa5, 0x22, 0x17, 0xfb, 0xce, 0x19, - 0xdd, 0x99, 0x59, 0xf7, 0xaa, 0xc2, 0xd5, 0x82, 0x5c, 0x1d, 0xd8, 0x5a, 0x76, 0x71, 0xb8, 0x61, 0x11, 0x05, 0x08, - 0xc4, 0xf4, 0x4a, 0xad, 0xfd, 0x11, 0x0d, 0x42, 0x3e, 0x18, 0xf8, 0x05, 0x06, 0xab, 0x02, 0x85, 0x0f, 0x14, 0xc9, - 0x5f, 0x7b, 0x02, 0x76, 0xf1, 0x0c, 0xd0, 0xad, 0xd8, 0xac, 0x18, 0x21, 0x42, 0x26, 0xcb, 0x59, 0x4d, 0x67, 0x90, - 0x4f, 0x7d, 0xf1, 0x8d, 0xad, 0x3a, 0x9d, 0xb7, 0x35, 0x55, 0x4e, 0x1d, 0x0a, 0xdd, 0xdd, 0xd4, 0x9d, 0x5b, 0x17, - 0x79, 0xea, 0x10, 0x72, 0xa5, 0x62, 0x25, 0xa6, 0xa1, 0xe6, 0x49, 0x9a, 0x51, 0x7f, 0xb1, 0xf7, 0x7b, 0x8d, 0xc2, - 0x29, 0x7f, 0x3a, 0x06, 0x55, 0xb8, 0xaa, 0x21, 0x8e, 0xa5, 0x2a, 0x1e, 0xd9, 0x20, 0xd0, 0xbc, 0xba, 0x55, 0x49, - 0x13, 0x32, 0xb9, 0x11, 0x3e, 0x35, 0x29, 0xe5, 0x69, 0xda, 0xa4, 0x95, 0x22, 0x75, 0xf0, 0x41, 0x9d, 0x6a, 0x3c, - 0x37, 0xab, 0x17, 0x00, 0x66, 0x9c, 0x5f, 0xf1, 0x4b, 0xc5, 0x65, 0xd4, 0x56, 0x66, 0xd2, 0xfe, 0xe4, 0x68, 0x6c, - 0xd4, 0xe5, 0xb4, 0x51, 0x46, 0x58, 0x29, 0xcd, 0x49, 0xb1, 0x1c, 0xcf, 0x3f, 0x60, 0xb0, 0xe6, 0x09, 0xec, 0x60, - 0xa2, 0x52, 0xde, 0x47, 0x40, 0x7c, 0x9d, 0xa4, 0x77, 0x09, 0xa4, 0x48, 0xff, 0xd2, 0x25, 0x77, 0x19, 0x1b, 0x88, - 0x31, 0x2b, 0x66, 0x46, 0xff, 0x83, 0xbb, 0xa4, 0x3f, 0x09, 0x01, 0x70, 0x13, 0x4d, 0xa1, 0x53, 0xe7, 0xc9, 0x45, - 0x1e, 0x2c, 0x2f, 0x3c, 0xb4, 0x62, 0xc4, 0x83, 0xbf, 0xbe, 0x08, 0x11, 0xc4, 0x1c, 0x53, 0x3c, 0xfd, 0xc2, 0xe8, - 0x2f, 0xc1, 0x25, 0x46, 0x10, 0xba, 0x7b, 0xe7, 0x30, 0x84, 0x9b, 0x3d, 0xc8, 0xa0, 0xfe, 0x50, 0x87, 0x44, 0x0d, - 0x7f, 0xac, 0x3c, 0xe8, 0xff, 0x3a, 0x13, 0x96, 0xda, 0x4f, 0x4f, 0x07, 0x50, 0xc1, 0xfb, 0x8a, 0xb7, 0x11, 0xf1, - 0x7d, 0xe2, 0x67, 0xf1, 0x60, 0xf3, 0x6c, 0x03, 0xd6, 0xba, 0x27, 0xb9, 0xb1, 0xae, 0x12, 0x36, 0x10, 0xf0, 0x35, - 0x8a, 0xda, 0xf3, 0xda, 0xed, 0x1e, 0xfc, 0xd5, 0xbf, 0x08, 0x19, 0x30, 0x71, 0xfa, 0x3e, 0x73, 0xb2, 0x46, 0x17, - 0x99, 0x4c, 0x1f, 0x3a, 0xe9, 0x1b, 0x9d, 0xee, 0x3b, 0xe1, 0x1f, 0x15, 0xb3, 0xf8, 0x70, 0x4b, 0x5f, 0x69, 0x52, - 0xdc, 0x01, 0x2b, 0x9b, 0x47, 0x05, 0xa1, 0xce, 0x45, 0xf4, 0x95, 0x29, 0xdf, 0x12, 0x6a, 0xf6, 0x8d, 0x25, 0xa5, - 0x74, 0xaf, 0xa1, 0x37, 0x69, 0xad, 0xdf, 0x46, 0x09, 0xc6, 0x44, 0xc7, 0x93, 0x97, 0xf1, 0x58, 0x79, 0x1f, 0x8f, - 0x1b, 0xa9, 0x90, 0x07, 0x20, 0x02, 0x15, 0xe3, 0x4f, 0x57, 0x9e, 0x9c, 0xf4, 0xc2, 0x78, 0x15, 0x4a, 0x41, 0x61, - 0x40, 0x57, 0x20, 0x05, 0x3c, 0x6a, 0x4f, 0x74, 0x16, 0x76, 0x09, 0xf7, 0xe8, 0x26, 0x60, 0xac, 0xcf, 0x3f, 0x02, - 0x9a, 0xbb, 0x70, 0x87, 0x17, 0x03, 0xd4, 0xa6, 0x5e, 0xdd, 0x7d, 0x5c, 0xab, 0x73, 0x38, 0x04, 0x07, 0xab, 0x41, - 0x04, 0xa7, 0xf3, 0xa9, 0xa3, 0x59, 0x16, 0xa0, 0x72, 0xb2, 0xdc, 0xc8, 0x9b, 0x47, 0x8b, 0x5e, 0xdd, 0xf7, 0x96, - 0x69, 0x59, 0xd5, 0x41, 0xc6, 0xb2, 0xb0, 0x02, 0x5c, 0x1d, 0x5a, 0x3f, 0x08, 0x97, 0x85, 0xf3, 0x07, 0x42, 0x10, - 0xbb, 0x57, 0xdb, 0x92, 0xe7, 0x6a, 0x0e, 0x3f, 0x7b, 0xce, 0xd6, 0x5c, 0xa2, 0x4e, 0x3a, 0x13, 0x01, 0x88, 0x3d, - 0x35, 0xab, 0xe8, 0x1a, 0x48, 0xea, 0x34, 0xab, 0xe8, 0x9a, 0x9a, 0x6d, 0x8c, 0x03, 0xf9, 0x68, 0x95, 0x02, 0xf6, - 0xdd, 0x74, 0x1c, 0xac, 0x9e, 0xc5, 0xf2, 0x3a, 0x74, 0xf7, 0x6c, 0xa3, 0x7c, 0x06, 0x75, 0xab, 0x8d, 0x31, 0xb1, - 0xdd, 0x7c, 0x39, 0xd7, 0x6f, 0x07, 0x4b, 0xdf, 0x0e, 0x9a, 0x73, 0xca, 0xbe, 0xd3, 0x65, 0xaf, 0xec, 0xb2, 0xa9, - 0xe7, 0x8e, 0x8a, 0x56, 0x63, 0x40, 0x6f, 0x60, 0xc1, 0xfa, 0x5c, 0xa4, 0xd9, 0xaa, 0x54, 0x25, 0xe0, 0x85, 0xb1, - 0x62, 0x77, 0x7e, 0x23, 0x33, 0x24, 0x61, 0x1e, 0x67, 0xe2, 0x9a, 0xee, 0xb5, 0x30, 0x39, 0x8e, 0x45, 0x32, 0x25, - 0x74, 0x4a, 0x77, 0xb6, 0xa1, 0x73, 0x15, 0x46, 0x11, 0xad, 0x95, 0x54, 0x1a, 0x09, 0x4c, 0xcd, 0x00, 0x25, 0x73, - 0x05, 0x4e, 0xe9, 0x72, 0xff, 0x3b, 0x12, 0xe3, 0xcc, 0x17, 0x25, 0x33, 0xa0, 0x5b, 0x7e, 0x5d, 0xac, 0x5b, 0x29, - 0x32, 0xc2, 0xbc, 0x39, 0x6e, 0xaf, 0xeb, 0x43, 0x20, 0x57, 0xcb, 0x1e, 0x45, 0xe3, 0xa0, 0xd0, 0xe1, 0x52, 0x25, - 0xc0, 0xbe, 0x48, 0xfc, 0x8c, 0xb0, 0xa5, 0x3d, 0x90, 0xdb, 0xa3, 0x33, 0x61, 0xce, 0x39, 0x29, 0xcb, 0xce, 0xa5, - 0x19, 0x5c, 0x4e, 0x5c, 0x09, 0x2e, 0xd2, 0xdb, 0xf6, 0x34, 0x69, 0x69, 0xfb, 0xd8, 0x70, 0x8e, 0x86, 0xb6, 0x41, - 0x77, 0xec, 0x0f, 0xcd, 0xc5, 0x22, 0xb6, 0x2e, 0x16, 0xc3, 0xce, 0xec, 0x47, 0x8b, 0x05, 0xc8, 0x01, 0xe0, 0xa8, - 0xdb, 0xf0, 0x31, 0x5b, 0x02, 0xa7, 0xd5, 0x34, 0x9b, 0x7a, 0x1b, 0x5e, 0x3d, 0x53, 0x3d, 0xbd, 0xe4, 0xf9, 0x33, - 0x61, 0xc6, 0x62, 0xc3, 0xf3, 0x67, 0xd6, 0x91, 0x53, 0x3d, 0x13, 0x4a, 0xb4, 0x2e, 0xa0, 0x19, 0x78, 0x4d, 0x01, - 0x23, 0x96, 0x4c, 0xa6, 0x54, 0x91, 0xc7, 0xbd, 0xe9, 0x46, 0x0d, 0x5e, 0x50, 0x38, 0x04, 0x52, 0x3a, 0xfd, 0xe2, - 0x39, 0xd3, 0xef, 0x5d, 0x3c, 0xef, 0x90, 0xb5, 0x0d, 0xd3, 0xe5, 0x66, 0x98, 0x0c, 0x4a, 0xff, 0x99, 0x99, 0x18, - 0x17, 0xd6, 0x24, 0x01, 0xc4, 0xbf, 0xb1, 0xdf, 0x21, 0x85, 0x9b, 0xf7, 0x97, 0xc3, 0xf8, 0x91, 0xf7, 0x63, 0x64, - 0x4f, 0xd2, 0x0c, 0xb1, 0x66, 0x52, 0x21, 0x77, 0x5f, 0xad, 0x7f, 0x4c, 0xec, 0x26, 0x7b, 0x60, 0x01, 0x88, 0xad, - 0x69, 0xab, 0x5b, 0xde, 0xef, 0x7b, 0xa6, 0x08, 0xf0, 0x83, 0xf2, 0x8f, 0xee, 0x0c, 0xc9, 0xa0, 0xec, 0xba, 0x21, - 0xc4, 0x83, 0xb2, 0x69, 0xda, 0xeb, 0x6d, 0xef, 0xcc, 0x63, 0x75, 0x9d, 0x76, 0x16, 0x57, 0x8b, 0x0c, 0xd2, 0xea, - 0x43, 0x76, 0x9c, 0xd9, 0x67, 0x47, 0x4b, 0xa5, 0xfb, 0x7d, 0x88, 0x88, 0x3b, 0xca, 0xda, 0x7e, 0xbb, 0x05, 0xd7, - 0x70, 0x34, 0x08, 0x5d, 0xd9, 0xdb, 0x65, 0xb4, 0x71, 0x21, 0x8e, 0x7b, 0xa6, 0xf3, 0x05, 0x5f, 0x1e, 0xa5, 0x9d, - 0x07, 0xa7, 0x7a, 0xa2, 0xcf, 0x4d, 0x77, 0x95, 0xc9, 0xb5, 0x0e, 0xab, 0x31, 0xa8, 0xcd, 0xc2, 0x16, 0xee, 0xc2, - 0x36, 0x3a, 0x68, 0xed, 0xcb, 0x82, 0x7f, 0xca, 0x00, 0x7c, 0xe9, 0xd9, 0xb2, 0xed, 0x35, 0x69, 0xf5, 0x46, 0x46, - 0x21, 0xb6, 0xb4, 0xbd, 0xfa, 0x74, 0x94, 0x8f, 0x9b, 0x13, 0x8a, 0x0b, 0x39, 0xca, 0x8f, 0x5e, 0x43, 0xd4, 0xb5, - 0xae, 0xe3, 0x62, 0xd1, 0xe1, 0xc6, 0x55, 0xb7, 0xdd, 0xb8, 0x7e, 0x40, 0xbc, 0x35, 0xda, 0xa4, 0x50, 0x2b, 0x63, - 0x47, 0xf0, 0xb2, 0x7c, 0x38, 0x64, 0x62, 0x38, 0x94, 0x90, 0xa9, 0x8f, 0xdd, 0x1b, 0x9a, 0xf6, 0xf9, 0x69, 0xeb, - 0x47, 0x2c, 0x35, 0x8e, 0x62, 0xc3, 0x3b, 0x7d, 0xe7, 0xb1, 0x35, 0xae, 0xe4, 0xcb, 0x60, 0xb6, 0x2b, 0xa8, 0xb6, - 0xc6, 0x1b, 0xf6, 0x72, 0xfe, 0x7d, 0x25, 0x95, 0xfc, 0xed, 0xcf, 0x70, 0x0d, 0x6f, 0x6d, 0xe9, 0xa0, 0xa9, 0x66, - 0x39, 0xcb, 0xf5, 0xbd, 0xe0, 0xf8, 0xe3, 0xee, 0x15, 0xc1, 0xe0, 0xf7, 0x74, 0x14, 0xe4, 0x62, 0xa9, 0xd6, 0x80, - 0x82, 0x74, 0x64, 0xc7, 0x54, 0x16, 0x18, 0x06, 0xf0, 0x86, 0x0c, 0x90, 0xc7, 0x14, 0xee, 0x86, 0x0a, 0x2f, 0xfc, - 0xa5, 0x22, 0xbb, 0x04, 0xb6, 0x35, 0xe3, 0x63, 0x86, 0x3b, 0x08, 0xf9, 0x47, 0xb0, 0x3b, 0xb6, 0x62, 0xb7, 0x6c, - 0xc1, 0x90, 0x6c, 0x1c, 0x87, 0x31, 0xe6, 0xe3, 0x49, 0x7c, 0x25, 0x26, 0xf1, 0x80, 0x47, 0xe8, 0x18, 0xb1, 0xe6, - 0xf5, 0x2c, 0x96, 0x03, 0xc8, 0xee, 0xb8, 0xd2, 0x01, 0x21, 0x34, 0x36, 0xb4, 0xe4, 0x4d, 0x61, 0x70, 0xb1, 0x63, - 0x9f, 0x91, 0x48, 0xc6, 0x21, 0x58, 0xb4, 0xaa, 0x81, 0x85, 0x89, 0xdd, 0xf2, 0x62, 0xb6, 0x9a, 0xe3, 0x3f, 0x87, - 0x03, 0x02, 0x60, 0x07, 0xfb, 0x86, 0xdd, 0x45, 0x88, 0xf4, 0xb6, 0xe0, 0x77, 0x96, 0xa7, 0x0b, 0xbb, 0xe7, 0xd7, - 0x7c, 0xcc, 0xce, 0x7f, 0xf0, 0x20, 0x72, 0xf6, 0xfc, 0x23, 0xa0, 0x21, 0xde, 0xf3, 0xdb, 0xd4, 0xab, 0xd8, 0x2d, - 0x51, 0x10, 0xde, 0x82, 0x33, 0xd0, 0x3d, 0x44, 0xc0, 0x5e, 0xf3, 0x05, 0xc6, 0x8a, 0x9d, 0xa5, 0x4b, 0x0f, 0x33, - 0x42, 0xed, 0xe9, 0x7c, 0x59, 0xab, 0x49, 0xb8, 0xb9, 0x5a, 0x4e, 0x06, 0x83, 0x8d, 0xbf, 0xe3, 0x6b, 0xe0, 0x83, - 0x39, 0xff, 0xc1, 0xdb, 0x51, 0xb9, 0xf0, 0x9f, 0xd7, 0x59, 0xf2, 0xce, 0x67, 0xd7, 0x03, 0xbe, 0x00, 0xbc, 0x25, - 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0xbb, 0xd6, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0xbe, - 0x86, 0x08, 0x8c, 0x04, 0x7c, 0x5b, 0xb5, 0x47, 0xfc, 0x96, 0x1b, 0xc0, 0xaf, 0xcc, 0x67, 0x0f, 0x3c, 0xd4, 0x3f, - 0x13, 0x9f, 0xdd, 0xf0, 0xf7, 0xfc, 0x85, 0x27, 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, - 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, - 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, - 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, - 0xde, 0x14, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, - 0x7c, 0x38, 0xd4, 0x2f, 0x84, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, - 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, - 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, 0xaa, 0xda, 0xbf, 0x25, 0x49, 0xb5, 0xab, 0xb4, - 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, - 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, - 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, - 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, - 0x89, 0x17, 0xe3, 0x69, 0x4d, 0x2c, 0xa9, 0x5d, 0x81, 0x31, 0x7a, 0x5c, 0x15, 0xb5, 0x4f, 0xfd, 0x02, 0x42, 0x91, - 0x6a, 0xcd, 0x1c, 0x6b, 0xdc, 0x18, 0x11, 0x77, 0x58, 0xb9, 0x76, 0x6a, 0xaf, 0x03, 0xb0, 0xbc, 0x1a, 0x17, 0x84, - 0x4d, 0x72, 0xec, 0x5c, 0xc0, 0x6a, 0x34, 0xa4, 0xda, 0x0d, 0xb7, 0x5e, 0x76, 0x7e, 0xf3, 0x38, 0xb1, 0xb5, 0x11, - 0x6e, 0x29, 0xa0, 0x8c, 0xf2, 0x1b, 0xcb, 0x09, 0xbb, 0x53, 0xbd, 0x23, 0x55, 0x3b, 0xe2, 0xc4, 0x05, 0x2c, 0x37, - 0x3c, 0xb5, 0xfa, 0x26, 0x06, 0x27, 0x42, 0xd5, 0x4a, 0xc7, 0x6b, 0x3f, 0xe2, 0x7e, 0x75, 0x5f, 0xf7, 0x4a, 0xf0, - 0x93, 0x90, 0xd7, 0x6f, 0x79, 0x07, 0x80, 0x15, 0x1f, 0xf2, 0x62, 0x5a, 0x38, 0x5a, 0x97, 0x41, 0x19, 0x20, 0x42, - 0x33, 0x00, 0x3a, 0xb9, 0x3a, 0x88, 0xd2, 0xc0, 0x15, 0x77, 0x88, 0xf0, 0xd3, 0xe8, 0x59, 0xfe, 0x22, 0x7c, 0x56, - 0x4d, 0xc3, 0x8b, 0x3c, 0x88, 0x2e, 0xaa, 0x20, 0x7a, 0x56, 0x5d, 0x85, 0xcf, 0xf2, 0x69, 0x74, 0x91, 0x07, 0xe1, - 0x45, 0xd5, 0xd8, 0x77, 0xed, 0xee, 0x9e, 0x90, 0xb7, 0x5d, 0xfd, 0x91, 0x73, 0x65, 0x4f, 0x99, 0x9e, 0x9f, 0xd7, - 0x7a, 0xa5, 0x76, 0x9b, 0xeb, 0x35, 0x6a, 0xa6, 0x3e, 0xca, 0xfe, 0x66, 0x1b, 0x0b, 0x8f, 0xe6, 0x10, 0xfa, 0x8c, - 0xb4, 0x98, 0x7b, 0x9c, 0xeb, 0xcd, 0x9e, 0x14, 0x06, 0x46, 0x4c, 0x2a, 0x19, 0x39, 0xbd, 0xc0, 0x45, 0xa8, 0x42, - 0x0c, 0x6b, 0xe9, 0x6a, 0x9f, 0x75, 0xe9, 0x0d, 0xd4, 0x35, 0xc5, 0xbe, 0x86, 0x0c, 0xbc, 0x68, 0x7a, 0x19, 0x8c, - 0x01, 0x39, 0x02, 0xef, 0xf8, 0x6c, 0x09, 0x07, 0xe6, 0x1a, 0xa0, 0x6f, 0x1e, 0xf5, 0x75, 0xb9, 0xe3, 0x6b, 0xd5, - 0x37, 0xd3, 0xf5, 0x48, 0x29, 0x3f, 0x56, 0xfc, 0xee, 0xe2, 0x39, 0xbb, 0xe5, 0x1a, 0x15, 0xe5, 0x17, 0xbd, 0x58, - 0xef, 0x81, 0xab, 0xee, 0x17, 0xb8, 0xcd, 0xe2, 0xb1, 0x2b, 0x0f, 0x58, 0xb6, 0x65, 0x0f, 0xec, 0x86, 0xbd, 0x67, - 0x4f, 0xd8, 0x5b, 0xf6, 0x8e, 0xfd, 0x84, 0xaa, 0x0d, 0x25, 0xe4, 0xf9, 0x0b, 0x7e, 0x2b, 0x4d, 0x8f, 0x12, 0x95, - 0xec, 0xc1, 0x36, 0xd3, 0x0c, 0x37, 0xec, 0x3d, 0x5f, 0x0c, 0x57, 0xec, 0x2d, 0x64, 0x43, 0x99, 0x78, 0xb0, 0x62, - 0x3f, 0x71, 0x05, 0x62, 0xa6, 0xcf, 0xc2, 0xd2, 0x12, 0x15, 0x4d, 0x99, 0x28, 0x43, 0xbf, 0xe5, 0xf8, 0x22, 0xfb, - 0x09, 0x8b, 0x90, 0x9f, 0x19, 0xae, 0xd8, 0x03, 0x5f, 0x0c, 0x56, 0xec, 0xbd, 0x36, 0x10, 0x0d, 0x36, 0x6e, 0x69, - 0x84, 0x64, 0xa5, 0xcb, 0x92, 0xd2, 0xf4, 0xd6, 0xbe, 0x06, 0x6e, 0xd8, 0x0d, 0xd6, 0xee, 0x09, 0x16, 0x8d, 0x02, - 0xff, 0x60, 0xc5, 0xde, 0x71, 0x09, 0xa0, 0xe6, 0x96, 0x27, 0xbd, 0x42, 0x75, 0x81, 0x74, 0x3f, 0x78, 0xc2, 0xe9, - 0x45, 0xf6, 0x0e, 0xcb, 0xa0, 0xaf, 0x0c, 0x57, 0x6c, 0x8b, 0xb5, 0xbb, 0x31, 0x96, 0x2d, 0xab, 0x7a, 0x12, 0x11, - 0x18, 0x05, 0x95, 0xd2, 0xf2, 0x6f, 0xc4, 0xb2, 0xa9, 0x9b, 0x06, 0xb5, 0xa1, 0x3f, 0x1f, 0x8c, 0xfe, 0xe2, 0xeb, - 0x77, 0x3f, 0x78, 0xa5, 0xbe, 0xf6, 0xfe, 0xe2, 0xb8, 0x56, 0x96, 0xe8, 0x5a, 0xf9, 0x2b, 0x2f, 0x67, 0xbf, 0xcc, - 0x27, 0xba, 0x96, 0xb4, 0xc3, 0x90, 0xaf, 0xe9, 0xec, 0x97, 0x0e, 0x67, 0xcb, 0x5f, 0x7d, 0xbf, 0x31, 0x5d, 0xac, - 0x3e, 0xab, 0x7b, 0xf7, 0x61, 0xb0, 0x69, 0x9c, 0x7a, 0xef, 0x4e, 0xd7, 0x1b, 0x9b, 0x59, 0x6b, 0xcf, 0xcc, 0xff, - 0xe1, 0x4a, 0x6f, 0x71, 0xe8, 0x6e, 0xf8, 0x76, 0xb8, 0xb1, 0x47, 0x41, 0x7e, 0x5f, 0x2a, 0x8d, 0xb3, 0x9a, 0xbf, - 0xf4, 0x3a, 0xa5, 0x58, 0x40, 0x34, 0xfa, 0x64, 0x24, 0xa1, 0x4b, 0x66, 0xe2, 0x19, 0xe2, 0x8b, 0x0c, 0x90, 0xb9, - 0x40, 0x34, 0xbb, 0xe7, 0xe3, 0xc9, 0xfd, 0x55, 0x3c, 0xb9, 0x1f, 0xf0, 0x4f, 0xa6, 0x05, 0xed, 0xc5, 0x76, 0xef, - 0xb3, 0x5f, 0x79, 0x61, 0x2f, 0xc7, 0x5f, 0x7c, 0xf6, 0x45, 0xb8, 0x2b, 0xf4, 0x17, 0x9f, 0xbd, 0x13, 0xfc, 0xd7, - 0x91, 0x26, 0xca, 0x60, 0xef, 0x6a, 0xfe, 0xeb, 0x08, 0x19, 0x3f, 0xd8, 0x67, 0xc1, 0xbf, 0x80, 0xef, 0x77, 0x95, - 0xa0, 0x55, 0xfc, 0x73, 0xad, 0x7e, 0xbe, 0x97, 0x71, 0x39, 0xf0, 0x26, 0xb4, 0x82, 0xde, 0xbc, 0xad, 0xe5, 0x4f, - 0xe2, 0xe1, 0x48, 0xd5, 0x53, 0xc3, 0x3f, 0x8b, 0xc5, 0x2c, 0xea, 0xa3, 0x74, 0x2a, 0x6f, 0x72, 0xcd, 0x33, 0x69, - 0x5d, 0xbe, 0x87, 0x50, 0xe0, 0x6b, 0x1b, 0xa2, 0x60, 0xc7, 0x71, 0x23, 0xb8, 0x66, 0xef, 0x84, 0xcf, 0xb2, 0xe9, - 0x96, 0xdf, 0xf0, 0x27, 0xfc, 0x1d, 0xdf, 0x05, 0x0f, 0xfc, 0x3d, 0x7f, 0xcb, 0x7f, 0xe2, 0x3b, 0xb6, 0x94, 0x68, - 0xa7, 0xf5, 0xf6, 0x32, 0xd8, 0xb2, 0x7a, 0x77, 0x19, 0x3c, 0xb0, 0x7a, 0xfb, 0x3c, 0xb8, 0x61, 0xf5, 0xee, 0x79, - 0xf0, 0x9e, 0x6d, 0x2f, 0x83, 0x27, 0x6c, 0x77, 0x19, 0xbc, 0x65, 0xdb, 0xe7, 0xc1, 0x3b, 0xb6, 0x7b, 0x1e, 0xfc, - 0x24, 0x31, 0x1e, 0xde, 0x09, 0xc9, 0x71, 0xf2, 0xae, 0x66, 0x86, 0x4f, 0x37, 0xf8, 0x2c, 0xac, 0x5f, 0x54, 0xc7, - 0xe0, 0x73, 0xcd, 0x74, 0x8b, 0x03, 0x21, 0x98, 0x6e, 0x6f, 0x70, 0x4b, 0x4f, 0x4c, 0xab, 0x82, 0x54, 0xb0, 0xae, - 0x76, 0x06, 0x8b, 0xba, 0x69, 0x9d, 0xc9, 0x8e, 0x5f, 0x62, 0xdc, 0xe1, 0x97, 0xb8, 0x60, 0xcb, 0xa6, 0xd3, 0x49, - 0xe7, 0xf4, 0x49, 0xa0, 0x37, 0x7f, 0xbd, 0xeb, 0x57, 0xd2, 0x77, 0xa6, 0x68, 0x78, 0xae, 0xb4, 0xc6, 0xad, 0x9d, - 0x3e, 0xb4, 0x76, 0x7a, 0x26, 0x55, 0x68, 0x11, 0x8b, 0xca, 0xa2, 0xaa, 0x90, 0x49, 0x3c, 0xc8, 0xb4, 0x3e, 0x2d, - 0x61, 0xa4, 0xc8, 0x04, 0x34, 0xfa, 0x82, 0x8e, 0x81, 0x9c, 0x2c, 0x0a, 0x6c, 0xc9, 0x37, 0x83, 0x84, 0xad, 0x79, - 0x3c, 0x1d, 0x26, 0xc1, 0x92, 0xdd, 0xf1, 0x61, 0xb7, 0x40, 0xb0, 0x52, 0x01, 0x4c, 0xfa, 0xe2, 0xd4, 0xde, 0xd7, - 0x79, 0x6f, 0x95, 0xc6, 0x71, 0x26, 0x50, 0xd9, 0x56, 0xe9, 0x0d, 0x7e, 0xeb, 0xec, 0xe7, 0x6b, 0xb5, 0xbf, 0x83, - 0xa4, 0xf0, 0x2b, 0x30, 0xec, 0x10, 0xe1, 0x1d, 0x54, 0x18, 0x79, 0x96, 0xcc, 0xa2, 0xaf, 0xec, 0x2d, 0x7d, 0x6b, - 0xb6, 0xe9, 0xff, 0xb4, 0x08, 0xda, 0xc7, 0x65, 0xe7, 0x7f, 0x32, 0xaf, 0xfe, 0xd6, 0xf1, 0xea, 0xc6, 0x9f, 0x3c, - 0xf0, 0x4f, 0x18, 0x96, 0x80, 0x89, 0x6c, 0xc7, 0x3f, 0x8d, 0xb6, 0x8d, 0x53, 0x9e, 0xdc, 0xc7, 0xff, 0xaf, 0x14, - 0x68, 0xef, 0xe4, 0x95, 0xbd, 0x23, 0x6e, 0x79, 0xc7, 0x3e, 0xbe, 0xb4, 0x36, 0x44, 0x03, 0x4d, 0xf2, 0x89, 0xbb, - 0xd1, 0xd0, 0xb0, 0x21, 0xfe, 0xc2, 0xab, 0xd9, 0xa7, 0xf9, 0x64, 0xcb, 0x8f, 0xb7, 0xc3, 0x4f, 0x1d, 0xdb, 0xe1, - 0x2f, 0xfe, 0x60, 0xd9, 0x7c, 0xad, 0x57, 0x3b, 0xb7, 0x71, 0xa7, 0xd2, 0x3b, 0x7e, 0xbc, 0x89, 0x0f, 0xff, 0xe3, - 0x4a, 0xef, 0xbe, 0xb9, 0xd2, 0x76, 0x95, 0xbb, 0x3b, 0xdf, 0x74, 0x7c, 0x23, 0x6b, 0x8d, 0x71, 0x66, 0x46, 0xb3, - 0xf8, 0x13, 0xcd, 0xd2, 0x20, 0xb2, 0x14, 0x8a, 0x3f, 0x99, 0x69, 0xa7, 0xee, 0x54, 0x59, 0xdd, 0x2d, 0xdf, 0xe2, - 0x1e, 0x7f, 0xcb, 0xc7, 0x6c, 0x61, 0x3c, 0x35, 0x6f, 0xaf, 0x16, 0x93, 0xc1, 0xe0, 0xd6, 0xdf, 0xdf, 0xf3, 0x70, - 0x76, 0x3b, 0x67, 0xd7, 0xfc, 0x9e, 0x16, 0xd3, 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, - 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, - 0xde, 0xdb, 0x9a, 0x86, 0xb7, 0xfc, 0xa3, 0x77, 0xed, 0x4f, 0xaf, 0x75, 0xcc, 0xcd, 0x44, 0x1d, 0x49, 0x6f, 0x2f, - 0x9e, 0xb3, 0x5f, 0xf9, 0x27, 0x79, 0x9c, 0x7c, 0x11, 0x72, 0xd2, 0xde, 0x20, 0x77, 0x13, 0x9d, 0x12, 0xef, 0xdc, - 0x44, 0xc2, 0x82, 0x40, 0x18, 0x8e, 0x9a, 0x3f, 0x4c, 0xca, 0xa9, 0xb7, 0x03, 0x6e, 0x57, 0x6e, 0xeb, 0x9f, 0x6f, - 0x39, 0xe7, 0x8b, 0xe1, 0xe5, 0xf4, 0x5d, 0xb7, 0x4b, 0x8f, 0x8a, 0x66, 0x53, 0x81, 0x6e, 0xb7, 0x18, 0x7b, 0x75, - 0x32, 0xb3, 0xcc, 0x25, 0x5f, 0x7a, 0x57, 0x9b, 0x99, 0xc7, 0xf4, 0x7e, 0x33, 0xcd, 0x90, 0xc8, 0x17, 0x08, 0x99, - 0x0e, 0x87, 0xbb, 0x73, 0x2c, 0x8f, 0x0f, 0xdf, 0x3e, 0x7b, 0x32, 0x78, 0x82, 0x91, 0x5b, 0x56, 0x34, 0xc8, 0x3b, - 0x3e, 0xcc, 0xea, 0xd6, 0x6d, 0xe3, 0xe2, 0xf9, 0xf0, 0x17, 0xc8, 0x1b, 0x74, 0x3d, 0x34, 0x45, 0xb4, 0xca, 0xef, - 0x28, 0xfa, 0x44, 0xc9, 0x41, 0xc7, 0x13, 0xa8, 0x1d, 0x52, 0xe0, 0xbe, 0x7b, 0xc6, 0x41, 0xbf, 0x81, 0xa5, 0xf6, - 0xfb, 0xe7, 0x9f, 0x88, 0x47, 0x1a, 0xc6, 0xfb, 0xfb, 0x30, 0xfa, 0x23, 0x2e, 0x8b, 0x35, 0x9c, 0xae, 0x03, 0xf8, - 0xdc, 0x33, 0x7d, 0xfb, 0xba, 0xf3, 0x7d, 0x3f, 0xf0, 0xb6, 0xfc, 0x86, 0xbd, 0xe3, 0xde, 0xe5, 0xf0, 0xad, 0xff, - 0xec, 0x09, 0x88, 0x4e, 0x30, 0x2e, 0x9f, 0x31, 0x12, 0xb6, 0xa3, 0x18, 0xb5, 0x0a, 0x3f, 0xd7, 0x10, 0xa2, 0xf5, - 0x09, 0x19, 0xbb, 0x20, 0xfd, 0x83, 0x02, 0xf4, 0x13, 0x02, 0xab, 0x49, 0x6a, 0x14, 0x98, 0xc4, 0xb7, 0x35, 0x24, - 0x90, 0x82, 0x05, 0x42, 0x6f, 0xa0, 0xf8, 0x54, 0xf0, 0x77, 0xc3, 0xcf, 0x24, 0xf9, 0x2d, 0x6a, 0x3e, 0x86, 0xbf, - 0x61, 0x68, 0x26, 0xd5, 0x43, 0x5a, 0x47, 0x89, 0xf7, 0x93, 0xbf, 0x8f, 0xc2, 0x4a, 0xa8, 0x63, 0x21, 0x48, 0xc5, - 0x90, 0x0b, 0x71, 0xf1, 0x7c, 0x72, 0x5b, 0x8a, 0xf0, 0x8f, 0x09, 0x3e, 0x93, 0x0b, 0x4d, 0x3e, 0xa3, 0x27, 0x8d, - 0x7c, 0xff, 0x41, 0xbe, 0x2f, 0x3b, 0x35, 0x58, 0xd4, 0x43, 0x7e, 0x5b, 0xbb, 0xef, 0xcb, 0x29, 0x41, 0x8f, 0xec, - 0x07, 0x34, 0x05, 0x03, 0x35, 0x01, 0x29, 0x43, 0x70, 0x0b, 0x57, 0x7d, 0x4f, 0x15, 0xe4, 0xcb, 0xef, 0x7d, 0x16, - 0x32, 0x5c, 0x65, 0x41, 0x48, 0x72, 0xa9, 0x90, 0xc2, 0xc6, 0x6d, 0x3d, 0xf8, 0xac, 0x31, 0x49, 0x24, 0xe4, 0x94, - 0x80, 0x24, 0x69, 0x6f, 0x20, 0x49, 0xc4, 0xf4, 0x1f, 0xae, 0x93, 0xa6, 0x59, 0x49, 0xe9, 0x86, 0x38, 0x55, 0xaf, - 0x91, 0xe6, 0x2c, 0x78, 0xcf, 0x60, 0xe9, 0x48, 0xb1, 0xe2, 0x9d, 0x31, 0x18, 0xeb, 0x60, 0xa1, 0x3b, 0x59, 0xdc, - 0xaf, 0x92, 0x30, 0x8d, 0x44, 0x95, 0x2f, 0x42, 0xfe, 0xfc, 0x97, 0x12, 0x7f, 0xf4, 0x96, 0x06, 0x22, 0x10, 0xfc, - 0x00, 0xad, 0x07, 0xac, 0xf1, 0xe0, 0x27, 0x56, 0x97, 0x61, 0x5e, 0x65, 0x54, 0xde, 0x6c, 0xc7, 0xb6, 0x73, 0xa6, - 0xaa, 0x16, 0x7c, 0x16, 0x86, 0x16, 0xed, 0x6c, 0xd5, 0x9c, 0xdc, 0xe6, 0x0d, 0xbe, 0x33, 0x49, 0x22, 0xb5, 0x94, - 0x44, 0xda, 0xea, 0xfa, 0x74, 0xe9, 0x75, 0x8b, 0x0a, 0x1a, 0x23, 0x40, 0x2f, 0x49, 0x77, 0x95, 0x4f, 0x28, 0x5e, - 0x59, 0x0d, 0xab, 0xe1, 0xa5, 0x43, 0x11, 0xc6, 0xda, 0x9b, 0x2b, 0x79, 0x76, 0x07, 0xd6, 0x23, 0xb4, 0x76, 0x55, - 0xea, 0x10, 0xb6, 0x9f, 0xe8, 0x3d, 0xa7, 0x52, 0x7f, 0x03, 0xaa, 0xc0, 0xa9, 0xa3, 0xa1, 0x3e, 0x6a, 0xa7, 0x90, - 0xed, 0xdc, 0x5b, 0x12, 0x54, 0xae, 0xe4, 0xa6, 0x4a, 0x8b, 0x52, 0xca, 0x94, 0xaf, 0x65, 0xb6, 0xb2, 0xfb, 0x64, - 0x00, 0xf1, 0x6c, 0x50, 0x20, 0xb9, 0xa8, 0xad, 0xe6, 0x20, 0x7d, 0x34, 0x4b, 0x1c, 0x6b, 0x07, 0x85, 0x97, 0x55, - 0x60, 0xe6, 0x32, 0x97, 0xcb, 0x41, 0xc1, 0x72, 0xbd, 0xd5, 0x4c, 0x33, 0xd5, 0x17, 0xb9, 0xbd, 0xcd, 0x78, 0x99, - 0xfe, 0x9b, 0x25, 0x03, 0x1e, 0x5d, 0x3c, 0xf7, 0x03, 0x48, 0x93, 0xbc, 0x0e, 0x90, 0x04, 0x9b, 0x83, 0x5d, 0xec, - 0x30, 0x6c, 0x15, 0x2b, 0x7b, 0xf2, 0x74, 0xb9, 0x43, 0x53, 0x2e, 0x61, 0x24, 0x27, 0xe6, 0x52, 0xea, 0xfb, 0x92, - 0xea, 0x86, 0x82, 0x93, 0x4d, 0x13, 0x50, 0x0a, 0x68, 0xb7, 0xe0, 0xbf, 0xf0, 0xa9, 0xa1, 0xd3, 0x02, 0x2c, 0xb5, - 0xdd, 0x80, 0xff, 0x42, 0xbf, 0xd8, 0x3e, 0xa2, 0x7e, 0x60, 0x1e, 0xec, 0xcd, 0xda, 0xca, 0x18, 0x10, 0x91, 0xb8, - 0x82, 0x3c, 0x12, 0xfc, 0xa0, 0xd8, 0xd3, 0x65, 0xe2, 0xc0, 0x99, 0xe2, 0x62, 0x29, 0xb5, 0x99, 0x79, 0xed, 0xb7, - 0xd4, 0xc4, 0x9b, 0x28, 0x89, 0x0a, 0xdb, 0x21, 0x8d, 0x5e, 0x52, 0xc6, 0x54, 0xc1, 0x86, 0xe8, 0xbe, 0x6e, 0x82, - 0x29, 0xf0, 0xa6, 0xaa, 0x02, 0x22, 0xd4, 0x5e, 0x64, 0x79, 0x7e, 0xd3, 0x05, 0x56, 0x17, 0x7c, 0x6c, 0x4c, 0xb3, - 0x0b, 0x56, 0x72, 0x35, 0x93, 0x3e, 0xf3, 0x76, 0xa0, 0x85, 0xbc, 0xcb, 0xcb, 0xa2, 0x15, 0xba, 0x1e, 0x44, 0x0b, - 0x7f, 0xaf, 0x39, 0x1e, 0x3d, 0xdb, 0x56, 0x53, 0x9b, 0x7d, 0xad, 0xc5, 0x02, 0x19, 0x88, 0x86, 0xbe, 0x90, 0x33, - 0x0a, 0x77, 0x95, 0xe6, 0x6a, 0xb5, 0xaf, 0xca, 0x20, 0x81, 0x89, 0x20, 0x6b, 0x59, 0x78, 0x8f, 0xee, 0xd5, 0x23, - 0xcd, 0x2b, 0x09, 0x9e, 0xb9, 0xf8, 0x0b, 0x00, 0xa1, 0x3c, 0x49, 0xc8, 0x01, 0x39, 0x80, 0xbf, 0xa5, 0x28, 0x95, - 0x06, 0xf8, 0x67, 0x75, 0x39, 0xb6, 0xf5, 0xfd, 0x9d, 0x56, 0x31, 0xb8, 0xfe, 0x7c, 0xdd, 0xf5, 0xac, 0x1d, 0xe2, - 0x5c, 0xd9, 0xea, 0xb5, 0x65, 0x9a, 0xc7, 0x48, 0x5d, 0x03, 0x70, 0x27, 0xd2, 0x23, 0x10, 0xc9, 0x4c, 0x34, 0xc8, - 0xd9, 0x0b, 0x3e, 0x9e, 0x8a, 0xc7, 0xa4, 0xbd, 0xca, 0xf7, 0xcd, 0x85, 0x3e, 0x18, 0x63, 0xdf, 0x82, 0x06, 0xf1, - 0xd1, 0x6a, 0x6b, 0x05, 0x62, 0xbd, 0x55, 0xea, 0x43, 0x37, 0x46, 0x41, 0x07, 0x8f, 0xb8, 0x91, 0x0b, 0x8e, 0xed, - 0xae, 0xad, 0xa7, 0xf4, 0x15, 0x80, 0xb9, 0x0e, 0x54, 0x32, 0x0c, 0x52, 0xe7, 0x89, 0xc2, 0x24, 0x3f, 0x4f, 0x48, - 0x42, 0x44, 0x75, 0xb6, 0x1c, 0xa5, 0xdc, 0xb4, 0x80, 0xcb, 0x8c, 0x0c, 0x30, 0x9b, 0x34, 0xeb, 0x27, 0x97, 0x2f, - 0x41, 0x2a, 0x0d, 0x11, 0xdc, 0xb0, 0xbd, 0x64, 0x74, 0xeb, 0xa8, 0x1b, 0x54, 0x49, 0xe6, 0xfa, 0xcd, 0xed, 0x2c, - 0x52, 0xe6, 0xcd, 0x47, 0x18, 0x6b, 0xf2, 0x21, 0xac, 0x13, 0xfc, 0x36, 0x40, 0x25, 0x7d, 0x2a, 0xbc, 0x68, 0x04, - 0x10, 0xea, 0x3b, 0x55, 0xc6, 0xa7, 0xc2, 0xcb, 0x46, 0x5b, 0x96, 0x51, 0x0a, 0xd5, 0x05, 0xb3, 0x5b, 0xd3, 0x85, - 0xe8, 0x56, 0xd5, 0x40, 0x1b, 0xb8, 0x76, 0x1d, 0x28, 0xa0, 0xa1, 0xda, 0x95, 0x1b, 0x16, 0x80, 0xd5, 0x4c, 0x04, - 0x86, 0xcb, 0xbf, 0xcf, 0x5f, 0xa9, 0x18, 0x9e, 0x7e, 0x3f, 0xf4, 0xf6, 0xdb, 0x20, 0x1a, 0x6d, 0x2f, 0xd9, 0x2e, - 0x88, 0x46, 0xbb, 0xcb, 0x86, 0xd1, 0xef, 0xe7, 0xf4, 0xfb, 0x79, 0x03, 0x3a, 0x12, 0x61, 0xc2, 0xec, 0xf5, 0x1b, - 0xb5, 0x7c, 0xa5, 0xd6, 0xef, 0xd4, 0xf2, 0xa5, 0x1a, 0xde, 0xda, 0x93, 0x44, 0x10, 0x59, 0xaa, 0x9a, 0x07, 0x49, - 0x91, 0x6a, 0xe9, 0x72, 0x8c, 0x16, 0x23, 0x6a, 0x29, 0x6b, 0x8e, 0x75, 0x22, 0xed, 0x1c, 0x94, 0x0c, 0x70, 0xb4, - 0xb8, 0xaa, 0x31, 0xdd, 0xac, 0x68, 0x09, 0xc4, 0x08, 0x2b, 0xdb, 0x72, 0x71, 0x93, 0xfa, 0xe8, 0x9c, 0x7c, 0xdb, - 0x2a, 0xe5, 0xdb, 0x56, 0xf0, 0xfc, 0x2b, 0x0a, 0xe5, 0x92, 0x6b, 0xd7, 0xb2, 0x69, 0xa1, 0x14, 0xca, 0xb8, 0x06, - 0x5b, 0xfb, 0x26, 0x30, 0x64, 0x3e, 0x52, 0xd4, 0xd8, 0x5e, 0x34, 0xca, 0x21, 0xc8, 0xd6, 0xc1, 0xa8, 0x53, 0x16, - 0x2c, 0xbe, 0xdd, 0x21, 0x03, 0x19, 0xe8, 0xa8, 0x6a, 0xe3, 0xd5, 0xce, 0x4a, 0x7f, 0x58, 0x5e, 0x3c, 0x67, 0x89, - 0x95, 0x4e, 0x7e, 0x53, 0xa1, 0x3f, 0x08, 0xd1, 0x37, 0x65, 0xc3, 0xc1, 0x8b, 0x2e, 0xb6, 0x32, 0x20, 0xde, 0x30, - 0xbd, 0xb7, 0xb1, 0x92, 0xe5, 0xae, 0x29, 0x5f, 0xcc, 0x78, 0xc2, 0x71, 0xf4, 0xe5, 0x6a, 0x11, 0xd6, 0x6a, 0x91, - 0x9d, 0x00, 0x0f, 0xad, 0xd5, 0x52, 0xc8, 0xd5, 0x22, 0x9c, 0x99, 0x2e, 0xd4, 0x4c, 0xcf, 0x40, 0xf3, 0x28, 0xd4, - 0x2c, 0x4f, 0x00, 0x0b, 0x5e, 0x98, 0x19, 0x2e, 0xcc, 0x0c, 0xc7, 0x21, 0x35, 0x4e, 0x0f, 0x7a, 0xaf, 0x73, 0xcf, - 0x2d, 0x77, 0xa3, 0xd3, 0x30, 0x6f, 0x47, 0x1b, 0xcc, 0xf1, 0x41, 0x38, 0x81, 0xf8, 0xc0, 0x12, 0x01, 0x7a, 0x34, - 0xac, 0x8e, 0x1a, 0x2a, 0x47, 0xf1, 0x65, 0x01, 0x48, 0x96, 0x04, 0x20, 0xb9, 0x57, 0xe3, 0x5c, 0x5a, 0x7e, 0x5d, - 0x25, 0x21, 0x47, 0x64, 0xbc, 0x94, 0x76, 0xf7, 0x84, 0x97, 0x23, 0x23, 0x34, 0x4f, 0x16, 0xa9, 0x97, 0xb3, 0x8c, - 0x8d, 0x11, 0xb8, 0x28, 0xf4, 0x9b, 0xaa, 0xdf, 0x4f, 0x4b, 0x2f, 0xa7, 0x76, 0x7e, 0x02, 0x7f, 0xcb, 0x53, 0x67, - 0x91, 0x23, 0xe4, 0xd5, 0xc8, 0x24, 0x2c, 0x2f, 0x95, 0x7a, 0xfa, 0x12, 0x66, 0x50, 0x77, 0x6f, 0x14, 0x80, 0x6b, - 0x91, 0x4b, 0xa7, 0xda, 0x12, 0xae, 0x4c, 0xb9, 0xc1, 0x3e, 0x0f, 0x79, 0x4e, 0x42, 0xa8, 0x44, 0x1e, 0x29, 0xac, - 0xfb, 0xf6, 0xc5, 0xf3, 0x89, 0xeb, 0xc3, 0x62, 0xa3, 0x11, 0x1c, 0x0e, 0x00, 0x73, 0x30, 0xf5, 0xa2, 0x01, 0x2f, - 0xd5, 0x9c, 0xf9, 0xe8, 0xe5, 0x84, 0x8d, 0x01, 0x6a, 0x8a, 0x81, 0x53, 0xd6, 0x33, 0xf9, 0xc8, 0xf8, 0x96, 0xf9, - 0x7e, 0x80, 0xef, 0xd6, 0x85, 0x84, 0x7c, 0x50, 0xa8, 0x04, 0x99, 0x42, 0x25, 0x48, 0x0c, 0x2a, 0x41, 0x6c, 0x50, - 0x09, 0x36, 0x0d, 0x5f, 0x4b, 0xe5, 0x6d, 0x04, 0x1c, 0x11, 0x3e, 0xf4, 0x2c, 0x6c, 0xac, 0x50, 0x3c, 0x1b, 0xb3, - 0x31, 0x2b, 0xd4, 0xce, 0x93, 0xcb, 0xa9, 0xd8, 0x59, 0x8c, 0x75, 0x13, 0x59, 0x26, 0x5e, 0x48, 0xd0, 0x71, 0xce, - 0x85, 0x44, 0x5d, 0xfd, 0xdc, 0x7b, 0x49, 0xc6, 0x92, 0x79, 0x43, 0xa3, 0x06, 0xf3, 0xb2, 0xeb, 0x00, 0xa6, 0x25, - 0xdf, 0x16, 0x34, 0x98, 0x4e, 0x95, 0x47, 0xa4, 0x49, 0x50, 0x3b, 0x97, 0x49, 0x91, 0x13, 0xc2, 0x24, 0xe8, 0x95, - 0xe0, 0x37, 0x12, 0xda, 0xff, 0xab, 0x9e, 0xef, 0x80, 0xc1, 0x44, 0xab, 0xe4, 0x0b, 0x58, 0x2d, 0x73, 0xfe, 0x52, - 0x7a, 0x62, 0x23, 0xfe, 0x62, 0x99, 0xc6, 0xa3, 0x2f, 0x6c, 0x88, 0x78, 0x56, 0x2f, 0xd1, 0xb4, 0x04, 0x75, 0x80, - 0x47, 0xf4, 0xd7, 0xe8, 0x8b, 0xe1, 0x4d, 0xe9, 0x6a, 0xa4, 0xae, 0xd9, 0x39, 0xe7, 0x5f, 0x6a, 0x43, 0x84, 0x8c, - 0x69, 0x53, 0x20, 0x19, 0x10, 0x48, 0x32, 0x10, 0x00, 0x98, 0x9a, 0xce, 0xec, 0x15, 0x40, 0x34, 0x10, 0xc0, 0xe3, - 0xbc, 0xe3, 0xf1, 0x23, 0xfd, 0x55, 0x1c, 0xf7, 0x4e, 0xd3, 0xb0, 0xfd, 0x17, 0xa0, 0x29, 0x86, 0x72, 0x3c, 0xdf, - 0x29, 0x48, 0xf6, 0x28, 0x65, 0xe9, 0xaa, 0x89, 0xec, 0x50, 0xac, 0x4f, 0x73, 0xca, 0x42, 0xda, 0x96, 0x63, 0xb4, - 0xc5, 0xfa, 0x31, 0xf2, 0xde, 0xdc, 0xa8, 0xc8, 0x07, 0x3d, 0xb8, 0xbd, 0xbd, 0x7d, 0xdd, 0x63, 0x36, 0xc9, 0x8a, - 0x45, 0xae, 0x22, 0x4e, 0x9c, 0xd6, 0x21, 0x07, 0x0c, 0xc8, 0x49, 0x08, 0x4c, 0x63, 0x5c, 0x2a, 0xd0, 0x41, 0xc9, - 0x72, 0x5e, 0x03, 0xb5, 0x2c, 0x22, 0x6b, 0x80, 0xa8, 0xa6, 0xf9, 0x57, 0x0d, 0xf9, 0x49, 0xd5, 0x9c, 0x52, 0xa8, - 0x7d, 0xc5, 0xc3, 0xea, 0xf4, 0x89, 0x55, 0x9b, 0x18, 0xeb, 0x5f, 0x6b, 0x4f, 0xd0, 0x56, 0xd2, 0x40, 0x7c, 0xe7, - 0xeb, 0xf4, 0x8e, 0x42, 0x77, 0x9c, 0x99, 0x78, 0xaa, 0x02, 0x63, 0xdf, 0xda, 0x11, 0x14, 0x0e, 0x4d, 0xd7, 0x01, - 0x87, 0x69, 0x74, 0xc2, 0xe2, 0x9f, 0xd2, 0x71, 0xf2, 0xa2, 0x56, 0x88, 0x24, 0xff, 0x10, 0x2e, 0x0c, 0x89, 0x05, - 0x79, 0x49, 0xa8, 0x23, 0x32, 0x62, 0x35, 0x2a, 0xd6, 0x42, 0x45, 0xc5, 0x29, 0x1e, 0x6f, 0x15, 0x14, 0x97, 0xa2, - 0x54, 0x29, 0x15, 0xb9, 0x51, 0x29, 0x20, 0x96, 0x0d, 0xbc, 0x5b, 0xc0, 0x01, 0x10, 0x74, 0x96, 0xbb, 0xb5, 0xed, - 0x6e, 0x23, 0xf3, 0x99, 0x69, 0x9e, 0x56, 0x1f, 0xd4, 0xdf, 0xef, 0x97, 0x18, 0x5b, 0xe3, 0xe9, 0xef, 0xdb, 0xb4, - 0xe0, 0xe6, 0x6f, 0x18, 0xa2, 0x3b, 0x40, 0xc4, 0x2c, 0xed, 0xa1, 0x90, 0x05, 0x13, 0x96, 0xa1, 0x2a, 0x4f, 0x39, - 0xea, 0xe5, 0x93, 0x5b, 0x80, 0x50, 0x43, 0xbf, 0x36, 0x3a, 0xd5, 0x55, 0x09, 0xc2, 0xf7, 0x5d, 0xa1, 0x1e, 0x9b, - 0x03, 0x9e, 0x0c, 0x80, 0xbf, 0x22, 0xaf, 0xf5, 0xd8, 0xfe, 0x41, 0x6f, 0xd4, 0x1b, 0x20, 0x88, 0xce, 0x79, 0xe1, - 0x1f, 0x71, 0xae, 0x53, 0x7f, 0xc6, 0x85, 0x20, 0xbe, 0xf5, 0x24, 0xbc, 0x17, 0x67, 0x69, 0x1c, 0x9c, 0xf5, 0x06, - 0xe6, 0x22, 0x50, 0x9c, 0xa5, 0xf9, 0x19, 0x88, 0xe5, 0x88, 0x89, 0x58, 0xb3, 0x3b, 0x80, 0x09, 0x2c, 0x75, 0x1c, - 0xb2, 0xea, 0xd8, 0x7e, 0xff, 0xcd, 0xc8, 0x90, 0xa5, 0x23, 0x0c, 0x8c, 0xfe, 0x5d, 0x81, 0x00, 0x05, 0xcb, 0xcc, - 0xf6, 0x60, 0xd2, 0xd5, 0x9e, 0xd5, 0xf3, 0x66, 0x93, 0x77, 0xf5, 0x8e, 0xd5, 0xb4, 0x9c, 0x9a, 0x56, 0x59, 0x4d, - 0x9b, 0xe4, 0x50, 0x33, 0xd1, 0xef, 0x6b, 0x50, 0xd4, 0x7c, 0x0e, 0x60, 0x6c, 0x98, 0xfc, 0x66, 0x56, 0xcd, 0xfb, - 0x7d, 0x4f, 0x3e, 0x82, 0x5f, 0xc8, 0x56, 0xe6, 0xd6, 0x58, 0x3e, 0x7d, 0x4d, 0x24, 0x66, 0x06, 0xe6, 0xe8, 0xee, - 0x08, 0xdf, 0xeb, 0x46, 0x78, 0x1d, 0x73, 0x85, 0xcd, 0xc4, 0xf4, 0x0d, 0x0c, 0x9e, 0x27, 0x7c, 0x70, 0x91, 0xa3, - 0xbf, 0x91, 0xc3, 0x4c, 0x61, 0x41, 0xce, 0xfd, 0xc9, 0x1b, 0xc4, 0x4b, 0x46, 0x78, 0x07, 0x9d, 0x4e, 0x78, 0x90, - 0xfd, 0xfe, 0x0a, 0x3a, 0xb3, 0x95, 0x4a, 0xd9, 0xaa, 0xa8, 0x4c, 0xd7, 0x75, 0x51, 0x56, 0xd0, 0xb1, 0xf4, 0xf3, - 0x56, 0xc8, 0xcc, 0xfa, 0x99, 0x05, 0xf7, 0xb4, 0x92, 0x00, 0x53, 0xb6, 0x6d, 0xa2, 0x36, 0xf0, 0xb2, 0x2e, 0x3e, - 0x17, 0x78, 0x74, 0xd6, 0x5e, 0x6f, 0x84, 0xda, 0xe7, 0x7c, 0xb4, 0x2e, 0xd6, 0x1e, 0xf8, 0xc1, 0xcc, 0xd2, 0xb9, - 0x22, 0xce, 0xc8, 0xfd, 0xd1, 0xe7, 0x22, 0xcd, 0x29, 0x0f, 0x70, 0x1f, 0x8a, 0xb9, 0xfd, 0x16, 0x48, 0x3f, 0xf4, - 0x16, 0xc8, 0x3e, 0x3a, 0xe7, 0xe4, 0x0d, 0x20, 0xd2, 0x21, 0x0c, 0x6e, 0x45, 0x82, 0x8e, 0x55, 0xc3, 0x5b, 0x0b, - 0xec, 0xb4, 0x97, 0xc6, 0xbd, 0x34, 0x3f, 0x4b, 0xfb, 0x7d, 0x83, 0x9a, 0x99, 0x22, 0x1c, 0x3c, 0xce, 0xc8, 0x45, - 0xd2, 0x82, 0x2d, 0xa5, 0xfd, 0x57, 0x03, 0x47, 0x10, 0xf2, 0xf7, 0x3f, 0x84, 0xf7, 0x04, 0x20, 0x36, 0x69, 0x03, - 0xae, 0x7a, 0x4c, 0x47, 0x63, 0x4b, 0xa2, 0x56, 0x9d, 0x0d, 0x90, 0x38, 0x55, 0x5a, 0x4f, 0xb9, 0x59, 0x53, 0x18, - 0xa4, 0xca, 0x42, 0xfd, 0xc6, 0x7a, 0x32, 0x59, 0xe5, 0x22, 0x23, 0x8e, 0xca, 0xf4, 0xa5, 0x66, 0x04, 0xd3, 0xa5, - 0x9f, 0x2f, 0x60, 0xc9, 0xc6, 0x1f, 0x71, 0xf2, 0x96, 0x80, 0x63, 0x3b, 0x6b, 0x57, 0xd5, 0x2e, 0xc7, 0xad, 0xdd, - 0x1c, 0xe0, 0x7b, 0xbd, 0xd1, 0x68, 0xa4, 0x9d, 0xe3, 0x04, 0x0c, 0x55, 0x4f, 0x2d, 0x85, 0x1e, 0xab, 0x15, 0xa0, - 0x6e, 0x47, 0x2e, 0xb3, 0x64, 0x30, 0x5f, 0x18, 0xc7, 0xaf, 0xcc, 0x47, 0x1f, 0x2f, 0x95, 0xb5, 0xeb, 0x88, 0xaf, - 0xff, 0x20, 0xab, 0xf5, 0x2d, 0xef, 0xaa, 0x26, 0xe0, 0x8b, 0x2a, 0xa0, 0xf4, 0x1b, 0xde, 0x93, 0xbd, 0x8b, 0xaf, - 0xdd, 0x60, 0x97, 0x7c, 0xcb, 0x5b, 0xd4, 0x79, 0xbe, 0x72, 0x70, 0xa3, 0x4a, 0xb7, 0xf7, 0x92, 0x05, 0xae, 0xbd, - 0xa3, 0xa6, 0xb1, 0x9e, 0xf9, 0xd1, 0xc3, 0x22, 0x64, 0x3b, 0x1f, 0x7b, 0x5f, 0x35, 0x4f, 0xcf, 0x1a, 0x7a, 0x93, - 0x1a, 0xfa, 0xd8, 0x8b, 0xb2, 0x7d, 0x6a, 0x1a, 0xd1, 0x6b, 0xd8, 0xd0, 0xc7, 0xde, 0x92, 0x93, 0x43, 0x22, 0xc0, - 0xa9, 0x31, 0x7f, 0x7c, 0x38, 0x9d, 0xe1, 0xef, 0x18, 0x50, 0x09, 0xc4, 0x7c, 0x7a, 0x4c, 0x3b, 0x0a, 0x30, 0xa3, - 0x4a, 0x6f, 0x9f, 0x1e, 0xd8, 0x8e, 0x97, 0xf5, 0xd0, 0xd2, 0xbb, 0x27, 0x47, 0xb7, 0xe3, 0x55, 0x35, 0xbe, 0x94, - 0x43, 0x9e, 0xe7, 0xb3, 0xd1, 0x68, 0x24, 0x0c, 0x24, 0x77, 0xa5, 0x37, 0xb0, 0x02, 0x69, 0x5b, 0x54, 0x1f, 0xca, - 0xa5, 0xb7, 0x53, 0x87, 0x76, 0xe5, 0x4f, 0xf2, 0xc3, 0xa1, 0x18, 0x99, 0x63, 0x1c, 0xc0, 0x4d, 0x0a, 0x25, 0x47, - 0xc9, 0x5a, 0x82, 0xe8, 0x94, 0xc6, 0x53, 0x59, 0xaf, 0xad, 0x88, 0xbc, 0x1a, 0x71, 0x1e, 0x82, 0x1f, 0x3d, 0x50, - 0x8b, 0xbf, 0xd0, 0x82, 0xd8, 0x63, 0x9f, 0x2a, 0xa5, 0x17, 0xbc, 0x2a, 0x20, 0x44, 0xec, 0xef, 0x06, 0xda, 0x41, - 0x09, 0x0e, 0x25, 0xdc, 0x07, 0x84, 0x85, 0x7e, 0xed, 0xe5, 0x33, 0x19, 0xa3, 0xdc, 0x1b, 0x54, 0x73, 0x06, 0x30, - 0x95, 0x3e, 0x03, 0xbf, 0x4b, 0x80, 0x3a, 0xc5, 0xa7, 0xe8, 0x54, 0x6f, 0x1e, 0x36, 0x5d, 0x9f, 0x96, 0x28, 0x8a, - 0xe8, 0xce, 0xcf, 0xc7, 0x80, 0xd8, 0xd9, 0xb5, 0x19, 0x69, 0xd7, 0x7e, 0x83, 0x06, 0x2b, 0x25, 0x89, 0x76, 0x4e, - 0x09, 0xbb, 0x9d, 0x8f, 0x6c, 0xe9, 0x47, 0x29, 0x10, 0x73, 0xc7, 0x89, 0x44, 0xf6, 0x60, 0x23, 0x27, 0x70, 0x8b, - 0xf6, 0x8e, 0x0e, 0x40, 0xe5, 0x46, 0x41, 0x7e, 0x35, 0x47, 0x72, 0xc7, 0x77, 0xbd, 0xef, 0x06, 0xf5, 0xe0, 0xbb, - 0xde, 0x59, 0x4a, 0x72, 0x47, 0x78, 0xa6, 0xa6, 0x84, 0x88, 0xcf, 0xbe, 0x1b, 0xe4, 0x03, 0x3c, 0x4b, 0xb4, 0x48, - 0x8b, 0x84, 0x6a, 0x75, 0x8d, 0x9b, 0xf0, 0x22, 0x91, 0xdc, 0x43, 0xbb, 0xce, 0x23, 0x62, 0x01, 0xc8, 0x58, 0x7c, - 0x36, 0x6f, 0x28, 0xd4, 0xdd, 0xc4, 0x6c, 0xd1, 0x5d, 0x16, 0xfb, 0xfd, 0x6d, 0x9e, 0xd6, 0x3d, 0x1d, 0x1f, 0x83, - 0x2f, 0x48, 0x35, 0x01, 0x1e, 0xed, 0xaf, 0xcd, 0xf1, 0xea, 0xd5, 0xe6, 0x48, 0x59, 0xa8, 0x12, 0xf5, 0x5b, 0xac, - 0x66, 0x3d, 0x84, 0xe1, 0xce, 0x32, 0x63, 0x6d, 0x2f, 0x78, 0x25, 0x67, 0x55, 0x6c, 0x97, 0xe3, 0x2b, 0x96, 0xda, - 0x4a, 0xa2, 0x72, 0xb4, 0x1e, 0x6b, 0x53, 0x8c, 0xfc, 0x4a, 0x21, 0x51, 0x16, 0x1d, 0x5b, 0x0b, 0x05, 0xc4, 0x0b, - 0xd0, 0x97, 0xec, 0x4c, 0x03, 0xac, 0x37, 0x7a, 0x15, 0x11, 0x5a, 0x3e, 0x52, 0xe1, 0x4d, 0x6e, 0xaa, 0xcc, 0xca, - 0x66, 0xd1, 0xee, 0xa7, 0x8a, 0x57, 0x08, 0x56, 0x6f, 0xd4, 0x1e, 0x05, 0xa8, 0x3d, 0xb4, 0x50, 0x06, 0x90, 0xd2, - 0x34, 0x03, 0x40, 0x06, 0x00, 0x99, 0x2a, 0xe2, 0x33, 0x01, 0x2a, 0x6d, 0x75, 0xa3, 0xc0, 0x89, 0xf4, 0x1a, 0x68, - 0x16, 0x58, 0xe9, 0x23, 0x05, 0x19, 0x2c, 0xb6, 0x08, 0xc0, 0xca, 0x91, 0x33, 0x4c, 0x63, 0xc8, 0x36, 0x9a, 0xb8, - 0x24, 0xcd, 0xef, 0xc3, 0x2c, 0x95, 0x78, 0x12, 0x3f, 0xc8, 0x1a, 0x23, 0x00, 0x90, 0xbe, 0x4f, 0x2f, 0x8a, 0x2c, - 0x26, 0x1c, 0x38, 0xeb, 0xa9, 0x83, 0xa2, 0x26, 0xe7, 0x5a, 0xd3, 0xea, 0x59, 0x6d, 0xf2, 0x90, 0x05, 0x3a, 0x7b, - 0x30, 0x26, 0xb5, 0x7c, 0xcf, 0x23, 0xfb, 0x2b, 0xc7, 0x33, 0xc2, 0x77, 0xdd, 0xc1, 0xa9, 0xff, 0x6e, 0x6a, 0x60, - 0x62, 0x4a, 0x00, 0x36, 0x06, 0x47, 0x13, 0xe2, 0x77, 0x3a, 0x26, 0x53, 0x9b, 0x14, 0x81, 0xc0, 0x43, 0xf0, 0x0a, - 0x9e, 0x1b, 0x2e, 0xb7, 0xdc, 0xd8, 0x59, 0xe4, 0x69, 0x02, 0x70, 0xe2, 0x05, 0xdf, 0x02, 0x1c, 0xa7, 0x5e, 0x15, - 0xb2, 0x67, 0xcf, 0xc5, 0x74, 0x36, 0x0f, 0x1e, 0x12, 0xda, 0xbf, 0x98, 0xf0, 0x9b, 0xee, 0x2a, 0xb9, 0x32, 0xb5, - 0xee, 0x4d, 0x74, 0x95, 0xcb, 0x9d, 0x3e, 0xad, 0x38, 0x86, 0x39, 0x83, 0x55, 0x40, 0xce, 0xd9, 0x90, 0xbf, 0x38, - 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0xfe, 0x22, 0x94, 0xd5, 0x02, 0xb8, 0x47, 0xce, 0x23, 0xf3, 0xcb, 0x57, 0xdb, - 0xa1, 0x9c, 0x53, 0x14, 0xc6, 0x72, 0x6a, 0x5a, 0x52, 0x9c, 0x0e, 0x3d, 0x05, 0x93, 0xa9, 0x2d, 0x7f, 0x6f, 0x13, - 0x97, 0xd9, 0x9b, 0x49, 0x38, 0x5f, 0x47, 0xb6, 0xad, 0x55, 0xf7, 0xd0, 0x0d, 0xc1, 0xa0, 0x8f, 0x11, 0xb4, 0x6c, - 0xae, 0xef, 0xd6, 0x83, 0x81, 0xc2, 0xf6, 0xad, 0xe9, 0xa6, 0x45, 0xa7, 0x38, 0xe0, 0xcc, 0x5a, 0xd7, 0xa8, 0x54, - 0x15, 0x87, 0x5e, 0xf2, 0x6e, 0x59, 0x95, 0x5d, 0x96, 0x5e, 0x08, 0x52, 0xa3, 0xae, 0x22, 0x44, 0x4a, 0xc5, 0x0e, - 0xef, 0xc9, 0xaf, 0x81, 0x89, 0x67, 0x56, 0x8e, 0xd2, 0x78, 0x0e, 0x30, 0x41, 0x0a, 0x7d, 0x53, 0x7e, 0x05, 0xb8, - 0xa1, 0x8b, 0x28, 0xcc, 0xde, 0xc6, 0x55, 0x50, 0x5b, 0x4d, 0xbf, 0x77, 0x70, 0x62, 0xcf, 0xeb, 0x7e, 0x3f, 0x25, - 0x1a, 0x3f, 0x0c, 0xbd, 0xc0, 0xbf, 0xc7, 0xd3, 0x7d, 0x13, 0xa4, 0xe6, 0x95, 0x07, 0x78, 0x45, 0x97, 0x5b, 0x9b, - 0x72, 0x45, 0xe3, 0x62, 0x5e, 0x23, 0x22, 0x7c, 0xea, 0x28, 0xb6, 0xdb, 0xfc, 0x38, 0xb5, 0x31, 0x18, 0x84, 0x70, - 0xdf, 0xca, 0xf8, 0x7d, 0xe2, 0xe5, 0xb3, 0x68, 0x0e, 0x8a, 0xd2, 0x4c, 0x93, 0x84, 0x14, 0xd2, 0x4b, 0x80, 0x3e, - 0x1a, 0x84, 0x5a, 0x5d, 0xf9, 0x47, 0xe2, 0xa5, 0x6a, 0x5a, 0x9b, 0xa7, 0x58, 0xa3, 0x40, 0xcc, 0xa2, 0x79, 0xc3, - 0x32, 0x3a, 0x24, 0xd5, 0xe5, 0xd2, 0x34, 0xe3, 0x0f, 0xab, 0x19, 0xaa, 0x15, 0x47, 0x4d, 0x50, 0xa3, 0x74, 0x03, - 0x17, 0xc0, 0xbf, 0xd3, 0x1d, 0x47, 0x35, 0x8a, 0x14, 0x0d, 0xf8, 0x04, 0x81, 0x61, 0xcd, 0xe6, 0x09, 0x6b, 0x4d, - 0x5d, 0x33, 0xfa, 0x7d, 0x19, 0x27, 0x64, 0x92, 0x90, 0x9c, 0x0f, 0x97, 0xeb, 0x47, 0x52, 0x5d, 0x00, 0xa9, 0x72, - 0xc5, 0x66, 0xbd, 0xde, 0x1c, 0x30, 0x7a, 0x61, 0xfd, 0xc2, 0xc6, 0x15, 0x9c, 0x5f, 0x12, 0xe6, 0xae, 0xfa, 0x11, - 0x66, 0x19, 0x54, 0x01, 0x69, 0x7e, 0x2c, 0x78, 0xf3, 0xdc, 0x05, 0xa2, 0x7e, 0x33, 0x52, 0x17, 0x94, 0x59, 0x3a, - 0xb7, 0x88, 0x40, 0xc0, 0x6b, 0x58, 0x3d, 0x81, 0x64, 0x5f, 0x3e, 0xf6, 0x69, 0x46, 0x81, 0xea, 0x08, 0x40, 0xd9, - 0xac, 0x1f, 0xc2, 0xfe, 0x01, 0xe1, 0x84, 0xfa, 0x9b, 0x37, 0x72, 0xd6, 0x90, 0x3c, 0x90, 0x6a, 0xc2, 0x63, 0x38, - 0x35, 0x16, 0xf8, 0xd2, 0xa2, 0x37, 0x15, 0xbc, 0x26, 0x38, 0xee, 0x05, 0x5a, 0xfb, 0x16, 0x70, 0x84, 0x08, 0x2e, - 0x43, 0x13, 0xa7, 0xbd, 0x5d, 0x2f, 0x40, 0x42, 0x73, 0x0b, 0xe7, 0xfa, 0xda, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, - 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, - 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, 0x2a, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, - 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, - 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xab, 0xc4, 0x33, 0xec, - 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, - 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x2a, 0xcc, 0x41, 0xde, - 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, - 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, - 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, - 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, - 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0x2f, 0xf2, 0xd1, - 0x96, 0xbe, 0x06, 0xdf, 0x3a, 0x1c, 0xf2, 0xd1, 0xce, 0xfc, 0xf4, 0xc9, 0x5a, 0x29, 0x83, 0x8d, 0x14, 0xa3, 0x10, - 0x12, 0xc5, 0x6d, 0x7b, 0x0c, 0x80, 0xff, 0xfd, 0xc3, 0x81, 0x7e, 0xef, 0xe4, 0x6f, 0xb5, 0x5b, 0x5a, 0xf5, 0xfc, - 0xd0, 0x22, 0xcc, 0x78, 0x5d, 0x1b, 0x76, 0xb6, 0xbd, 0x04, 0x94, 0xde, 0x37, 0x0d, 0x6a, 0x8a, 0xe8, 0x27, 0xac, - 0x26, 0x56, 0x71, 0x58, 0x90, 0x12, 0x87, 0x18, 0x8e, 0xd1, 0x0e, 0x3d, 0x4e, 0x17, 0x35, 0x4f, 0xee, 0x3b, 0x64, - 0xdc, 0xfa, 0x3e, 0x20, 0xb9, 0x14, 0xce, 0x3f, 0x78, 0xa1, 0xc1, 0x44, 0x2f, 0xf2, 0xaa, 0xc8, 0xc4, 0x48, 0xd0, - 0x28, 0xbf, 0x25, 0x71, 0xe6, 0x0c, 0x6b, 0x71, 0xa6, 0x10, 0xc2, 0x42, 0x42, 0xe5, 0x2e, 0x4a, 0x4a, 0x0f, 0xce, - 0x9e, 0xec, 0xcb, 0xe6, 0x77, 0xc2, 0x84, 0x18, 0x2d, 0x80, 0x06, 0x67, 0xd7, 0x2e, 0xef, 0x21, 0x2c, 0x73, 0xef, - 0xf7, 0xb7, 0x77, 0x79, 0x01, 0x71, 0x99, 0x67, 0x52, 0xb1, 0x5a, 0x9e, 0x01, 0x4d, 0x9e, 0x88, 0xcf, 0xc2, 0x4a, - 0x4e, 0x83, 0xaa, 0xa3, 0x58, 0xbd, 0x8d, 0xe7, 0x1e, 0xf0, 0x7a, 0xbf, 0x4f, 0x80, 0xc0, 0xdd, 0x67, 0x6f, 0x94, - 0x5b, 0x2a, 0xe9, 0x91, 0xe7, 0x18, 0x22, 0x99, 0x00, 0xaf, 0x33, 0x04, 0x47, 0x0a, 0xab, 0xe7, 0x26, 0xc8, 0x3f, - 0xbe, 0x3e, 0xa1, 0xf8, 0xa2, 0x79, 0x14, 0x35, 0x2c, 0x64, 0x09, 0x1c, 0x0f, 0xc9, 0x2c, 0x9b, 0x23, 0x35, 0x79, - 0xda, 0x9e, 0x22, 0x1d, 0x9d, 0x58, 0xe2, 0xb7, 0x35, 0xa9, 0x5e, 0xa4, 0xc2, 0x2e, 0x69, 0x67, 0x2b, 0x73, 0x2f, - 0x84, 0xa1, 0x4a, 0xb8, 0xf7, 0xba, 0x9e, 0x85, 0x72, 0x53, 0xb4, 0x2a, 0x66, 0x0f, 0x53, 0x62, 0x86, 0x29, 0xd6, - 0x5f, 0xd8, 0xf0, 0x9b, 0xc4, 0x8b, 0xc1, 0x70, 0xbd, 0xe4, 0xe5, 0x6c, 0x63, 0x16, 0xc2, 0xe1, 0xb0, 0x99, 0x14, - 0xb3, 0x25, 0xc4, 0xb6, 0x2e, 0xe7, 0x87, 0x43, 0x57, 0xcb, 0xd6, 0xc2, 0x83, 0x87, 0xaa, 0x85, 0x9b, 0x86, 0xe5, - 0xf0, 0x33, 0x99, 0xc5, 0xd8, 0xbe, 0xc6, 0x67, 0xf6, 0xe7, 0x8b, 0xee, 0x59, 0x82, 0x8c, 0x1b, 0x6b, 0xe0, 0x1a, - 0x9b, 0xb5, 0x3b, 0x5c, 0x8d, 0x80, 0xe4, 0x71, 0x37, 0xfa, 0xbb, 0xb2, 0x93, 0x9c, 0x04, 0x09, 0xa3, 0x15, 0xc2, - 0xef, 0xbe, 0xf1, 0x27, 0x5a, 0xec, 0x41, 0xbb, 0x8d, 0x2d, 0x21, 0xaa, 0x69, 0xcf, 0xe5, 0x4a, 0xb1, 0x34, 0x6f, - 0xa5, 0x0d, 0x99, 0x0f, 0xeb, 0x73, 0xdf, 0xc8, 0x81, 0x82, 0x31, 0xe2, 0xa9, 0x75, 0x10, 0xcd, 0xe6, 0xc0, 0x7d, - 0x81, 0xe6, 0x11, 0x9e, 0x5a, 0x90, 0xa0, 0xcc, 0xda, 0xb0, 0x9f, 0x24, 0x27, 0xcb, 0xe3, 0xf0, 0x2d, 0xfc, 0xcb, - 0x67, 0xd8, 0x24, 0xa6, 0x28, 0x1e, 0x7f, 0xab, 0x14, 0xff, 0x1d, 0x5b, 0x10, 0xc1, 0xda, 0x8d, 0xa8, 0x0d, 0x7f, - 0xc3, 0xbf, 0x85, 0x7d, 0x84, 0xfd, 0x86, 0x26, 0x08, 0x03, 0x58, 0x7f, 0x26, 0x10, 0x17, 0x16, 0x82, 0x04, 0x7f, - 0xab, 0x24, 0xff, 0x9c, 0xf0, 0xd9, 0xa2, 0x04, 0xb2, 0x3a, 0x8c, 0xe2, 0x13, 0x8a, 0x89, 0x42, 0x18, 0x6e, 0x09, - 0xbd, 0xa3, 0xff, 0x46, 0x94, 0x64, 0x93, 0xdc, 0x8a, 0xf5, 0x40, 0x26, 0x49, 0x30, 0xc1, 0xca, 0x0b, 0xe5, 0x4b, - 0xf7, 0x42, 0xa9, 0xb5, 0x16, 0xb4, 0x7e, 0xf9, 0x93, 0xc4, 0x33, 0xa0, 0x7b, 0x20, 0x63, 0xd0, 0x6d, 0x44, 0x35, - 0xc9, 0x31, 0x7d, 0x94, 0xce, 0x33, 0x50, 0x01, 0x9d, 0xad, 0xb3, 0xb0, 0x5e, 0x16, 0xe5, 0xaa, 0x15, 0x1e, 0x2a, - 0x4b, 0x1f, 0xa9, 0xc7, 0x98, 0x17, 0xe6, 0xc9, 0x89, 0x7c, 0xf0, 0x08, 0xd0, 0xf0, 0x28, 0x4f, 0xab, 0x8e, 0xd2, - 0xfa, 0x81, 0x65, 0xc0, 0x08, 0x9c, 0x28, 0x03, 0x1e, 0x61, 0x19, 0x98, 0xa7, 0x5d, 0x86, 0x1a, 0xc4, 0x1a, 0x55, - 0x57, 0x6a, 0x83, 0x39, 0x51, 0x94, 0x7c, 0x8a, 0xa5, 0x15, 0xc6, 0xd0, 0xd4, 0x95, 0x47, 0xd6, 0x4b, 0x4e, 0xd8, - 0x93, 0xdd, 0x40, 0xba, 0x85, 0x8d, 0x02, 0x17, 0x74, 0x2d, 0x4b, 0x94, 0x8b, 0x6e, 0x19, 0x51, 0x26, 0x42, 0xea, - 0x67, 0x0f, 0x67, 0x5a, 0xed, 0x37, 0x76, 0xd2, 0xbe, 0x3d, 0x52, 0xf4, 0x82, 0x81, 0xf8, 0xb4, 0x47, 0x4a, 0x3d, - 0x6b, 0xe4, 0x32, 0xb0, 0xa5, 0x4b, 0x55, 0xcf, 0x7f, 0x83, 0xf2, 0x1d, 0xcc, 0x8c, 0xb3, 0xd9, 0xef, 0x7a, 0x73, - 0x7b, 0xb2, 0xaf, 0x9b, 0xdf, 0x59, 0xaf, 0x07, 0x5b, 0x83, 0x4c, 0x7c, 0xa9, 0xa8, 0xa7, 0xac, 0x42, 0xac, 0xc8, - 0xec, 0x7f, 0x0b, 0xef, 0x77, 0x78, 0x6b, 0x84, 0x66, 0x65, 0x3c, 0xcc, 0x47, 0x4f, 0xf6, 0xa2, 0xf9, 0xbd, 0xb3, - 0x6c, 0x2b, 0x57, 0x25, 0xb3, 0xfd, 0x7e, 0x94, 0x34, 0x67, 0x8f, 0xd7, 0x48, 0xea, 0x00, 0x1f, 0xaf, 0xcf, 0xf0, - 0x91, 0x4a, 0x28, 0xb5, 0xa0, 0xaa, 0x41, 0xeb, 0x63, 0xbf, 0xb7, 0x9e, 0xd3, 0xc7, 0x8f, 0xe5, 0x74, 0x4b, 0x8a, - 0x30, 0x7e, 0x60, 0x30, 0x65, 0x27, 0x4e, 0x5d, 0xf2, 0x66, 0x48, 0xef, 0xba, 0x55, 0x52, 0x97, 0x3d, 0x4a, 0x04, - 0xa1, 0x0e, 0xd6, 0x2f, 0xf6, 0x43, 0x98, 0xd9, 0xa2, 0x3f, 0x6c, 0x56, 0x73, 0x42, 0x41, 0x04, 0x88, 0x56, 0x79, - 0x1f, 0x38, 0x26, 0x09, 0xb3, 0xe6, 0x86, 0x74, 0xeb, 0xcd, 0x95, 0xf6, 0x4a, 0x0a, 0xe8, 0xe7, 0x20, 0x73, 0xfb, - 0xe8, 0x96, 0xab, 0x96, 0x79, 0x2e, 0x6d, 0x39, 0x60, 0xd1, 0x42, 0x74, 0x66, 0xe7, 0xd2, 0xe1, 0xe0, 0x3f, 0xa8, - 0x2b, 0x51, 0x45, 0x04, 0x1d, 0x45, 0x0b, 0x46, 0xab, 0x55, 0xbb, 0x9c, 0x6c, 0x2a, 0x64, 0x4b, 0x22, 0x9c, 0x28, - 0xd9, 0x2b, 0xa1, 0x3e, 0xca, 0xd5, 0x9e, 0x69, 0x88, 0x3f, 0x13, 0xb0, 0x69, 0x83, 0xbf, 0x05, 0xee, 0x65, 0x70, - 0x66, 0xda, 0xa7, 0x61, 0x04, 0x44, 0xe6, 0x10, 0xec, 0xe7, 0x77, 0x3d, 0xa8, 0xe0, 0x41, 0x47, 0xfa, 0xeb, 0x7a, - 0x56, 0xe0, 0x99, 0x7b, 0xe2, 0xf9, 0x9b, 0x13, 0xe9, 0x45, 0x0e, 0x0f, 0x34, 0xf7, 0x61, 0xc6, 0x5f, 0x96, 0x65, - 0xb8, 0x1b, 0x2d, 0xcb, 0x62, 0xe5, 0x45, 0x7a, 0x1f, 0xcf, 0xa4, 0x18, 0x48, 0x74, 0x98, 0x19, 0x5d, 0xc5, 0x3a, - 0xce, 0x61, 0xdc, 0xdb, 0x93, 0xb0, 0x42, 0xfb, 0x67, 0x89, 0xbd, 0x2e, 0x00, 0xc0, 0x21, 0x6b, 0xd0, 0x0a, 0xef, - 0x74, 0x7b, 0xbb, 0xc7, 0x25, 0x25, 0x8a, 0x1b, 0x35, 0x3f, 0xab, 0xa1, 0x65, 0x82, 0x5a, 0x66, 0xdd, 0xc9, 0x64, - 0x8a, 0x24, 0xf0, 0x6d, 0xd8, 0x1b, 0x56, 0xe4, 0xf3, 0x46, 0x6e, 0x0f, 0xef, 0xc2, 0x95, 0x88, 0xb5, 0x05, 0x9d, - 0x74, 0x64, 0x1c, 0xee, 0x85, 0xe6, 0x46, 0xba, 0x7f, 0x52, 0x25, 0x61, 0x29, 0x62, 0xb8, 0x05, 0xb2, 0xbd, 0xda, - 0x56, 0x82, 0x12, 0x48, 0x60, 0x3f, 0x94, 0x62, 0x99, 0x6e, 0x05, 0x80, 0x39, 0xf0, 0x3f, 0x25, 0x0c, 0xa1, 0xbb, - 0xf3, 0x10, 0xaf, 0x1a, 0x79, 0xdf, 0x20, 0x04, 0xfb, 0x6b, 0x90, 0xd3, 0x80, 0x41, 0xa4, 0x18, 0xc9, 0x82, 0x81, - 0x04, 0x20, 0xe7, 0x6b, 0x30, 0xc9, 0x4d, 0x73, 0xcf, 0x0f, 0x72, 0xdd, 0xc1, 0xb4, 0x0f, 0xba, 0x17, 0xd7, 0x9a, - 0xe5, 0xe0, 0x15, 0x13, 0xf1, 0xbf, 0xd7, 0x5e, 0xc9, 0x72, 0x96, 0xf9, 0x8d, 0xb9, 0xe8, 0x64, 0x70, 0xd5, 0x10, - 0x7e, 0x31, 0xcb, 0xe6, 0x3c, 0x9a, 0x65, 0x3a, 0xd4, 0xbf, 0x68, 0x8e, 0x4a, 0x01, 0x0c, 0x75, 0xbc, 0x00, 0x6b, - 0xbc, 0x2b, 0xdd, 0xb4, 0xe2, 0x91, 0xc6, 0x18, 0x05, 0x15, 0x3a, 0x08, 0xfd, 0xbd, 0x06, 0x78, 0x0d, 0x26, 0xb9, - 0x11, 0x2a, 0x1f, 0x5c, 0xd0, 0x0d, 0xdd, 0x72, 0xe5, 0x12, 0xd4, 0xa4, 0x6a, 0xf9, 0xe5, 0x08, 0xf5, 0xae, 0x96, - 0x5c, 0xaa, 0xcd, 0xa7, 0x46, 0x59, 0x23, 0xc8, 0xe4, 0x28, 0xfd, 0x3e, 0xe5, 0xc2, 0xad, 0x8c, 0xc9, 0xfa, 0x70, - 0xf0, 0x0a, 0x6e, 0x6a, 0xfc, 0x3a, 0x27, 0x16, 0x51, 0x7b, 0x48, 0x84, 0xad, 0xdd, 0x0a, 0xdd, 0x7b, 0xdc, 0x28, - 0xcd, 0xa3, 0x6c, 0x13, 0x8b, 0xca, 0xeb, 0x25, 0x60, 0x2d, 0xee, 0x01, 0x19, 0x2a, 0x2d, 0xfd, 0x8a, 0x15, 0x00, - 0x19, 0x20, 0x85, 0x8d, 0x1f, 0x90, 0xf6, 0xea, 0x83, 0x97, 0xfa, 0xfd, 0xbe, 0x31, 0xe5, 0xbf, 0x7f, 0xc8, 0x81, - 0x99, 0x50, 0x94, 0xf5, 0x0e, 0x26, 0x10, 0x5c, 0x3b, 0x49, 0x7b, 0x56, 0xf3, 0x17, 0xeb, 0xda, 0x03, 0x52, 0x2b, - 0xdf, 0x62, 0xae, 0x7a, 0x6d, 0x5f, 0x6c, 0xf6, 0x69, 0x75, 0x63, 0x34, 0x0e, 0x82, 0xa5, 0xd5, 0x5b, 0xad, 0x72, - 0xc8, 0x1b, 0x5e, 0x81, 0x48, 0x65, 0x5d, 0x5d, 0x2b, 0xe7, 0xea, 0x5a, 0x70, 0x24, 0x90, 0x2d, 0x79, 0x0e, 0xff, - 0x85, 0xdc, 0x2b, 0x0f, 0x87, 0xc2, 0xef, 0xf7, 0xd3, 0x19, 0x69, 0x65, 0x81, 0x32, 0x6d, 0x5d, 0x7b, 0xa1, 0x7f, - 0x38, 0xfc, 0x00, 0x5e, 0x23, 0xfe, 0xe1, 0x50, 0xf6, 0xfb, 0x1f, 0xcd, 0x4d, 0xe6, 0x7c, 0xac, 0x94, 0xb2, 0x97, - 0xa8, 0x74, 0x7f, 0x9b, 0xf0, 0xde, 0xff, 0x1e, 0xfd, 0xef, 0xd1, 0x65, 0x4f, 0x05, 0x80, 0x25, 0x7c, 0x86, 0x37, - 0x74, 0xa6, 0x2e, 0xe7, 0x4c, 0xba, 0xbb, 0x2b, 0x3f, 0xf4, 0x9e, 0xc6, 0x87, 0xef, 0xcd, 0x4d, 0x1b, 0x7f, 0xad, - 0x8e, 0x34, 0x09, 0x1d, 0x17, 0xfd, 0xc3, 0xe1, 0x53, 0xa2, 0xf5, 0x69, 0xa9, 0xd2, 0xa7, 0x29, 0xf0, 0x24, 0xc3, - 0x86, 0xeb, 0x16, 0xa6, 0xa3, 0xf9, 0x71, 0xf3, 0x55, 0xf2, 0xe2, 0x2c, 0x85, 0x6b, 0x6f, 0x3e, 0x4b, 0xe7, 0x53, - 0xb0, 0xae, 0x0c, 0xf3, 0x59, 0x3d, 0x0f, 0x20, 0x75, 0x08, 0x69, 0xd6, 0x34, 0xfc, 0x5b, 0xe5, 0x0a, 0xde, 0xda, - 0xe3, 0xdd, 0x60, 0x44, 0xa9, 0x23, 0x7d, 0xd2, 0x86, 0xd0, 0x25, 0x95, 0xfc, 0x47, 0x91, 0xc7, 0x18, 0xb3, 0xf1, - 0x9a, 0xc8, 0x3e, 0x8b, 0xfc, 0x55, 0x01, 0x80, 0x45, 0x80, 0x80, 0x9c, 0xce, 0x1d, 0x49, 0xfc, 0xe7, 0xe4, 0xdb, - 0x3f, 0xa6, 0x4b, 0xfb, 0x50, 0x16, 0x77, 0xa5, 0xa8, 0xaa, 0xa3, 0xd2, 0x76, 0xb6, 0x5c, 0x0f, 0xf4, 0xa1, 0xfd, - 0xbe, 0xa4, 0x0f, 0x4d, 0x31, 0x14, 0x05, 0x6e, 0x8d, 0xbd, 0x69, 0xca, 0x15, 0x4d, 0xf5, 0xc8, 0x58, 0x3f, 0xbf, - 0xdf, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, 0x7e, 0x52, 0x8a, 0x24, 0x70, 0x3e, 0xc3, 0x54, 0xe2, - 0xd3, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, 0xd9, 0x7f, 0x54, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, - 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, 0x44, 0xf0, 0x17, 0xc2, 0x22, 0xf9, 0xf5, 0xc9, 0x91, - 0xa0, 0x31, 0x93, 0xe5, 0xe3, 0x91, 0xfb, 0x85, 0x7d, 0xe5, 0x3a, 0x9e, 0xff, 0xb9, 0x99, 0xff, 0x03, 0x74, 0x86, - 0x2c, 0x5e, 0x70, 0xcb, 0x60, 0x81, 0xb3, 0x5f, 0xba, 0x7a, 0xc0, 0xdf, 0xcc, 0x13, 0x2f, 0x80, 0x83, 0xf9, 0x05, - 0xba, 0x2a, 0xa6, 0xb3, 0x62, 0x00, 0x04, 0xb6, 0x7e, 0x63, 0xcd, 0x89, 0x37, 0x16, 0xcf, 0x95, 0x5c, 0x10, 0xfa, - 0xba, 0x0a, 0xb3, 0x71, 0x55, 0x6c, 0x2a, 0x51, 0x6c, 0xea, 0x1e, 0xa9, 0x65, 0xf3, 0x69, 0x6d, 0x2b, 0x64, 0x7f, - 0x12, 0x2d, 0xda, 0x2e, 0x43, 0x35, 0x19, 0x65, 0xe9, 0x7a, 0x0a, 0xa4, 0x7a, 0x01, 0x9c, 0x45, 0xe6, 0x95, 0x2f, - 0xce, 0x1e, 0xb0, 0x45, 0xe3, 0x29, 0x30, 0xa2, 0xd2, 0x1f, 0x79, 0x63, 0x74, 0x7a, 0xa2, 0xdf, 0xcf, 0xa7, 0x14, - 0xf2, 0xf5, 0x13, 0x60, 0x72, 0xd5, 0x72, 0x01, 0xfa, 0x32, 0xd4, 0x41, 0x25, 0x4a, 0xad, 0x18, 0x46, 0x2c, 0xfc, - 0x24, 0x90, 0xbd, 0x99, 0x82, 0x9a, 0x55, 0x94, 0x84, 0x4a, 0x54, 0x4a, 0xb6, 0x26, 0xa8, 0xa5, 0xf7, 0x45, 0x51, - 0xef, 0x2b, 0x70, 0x94, 0x8c, 0xb4, 0x59, 0x4e, 0x99, 0x71, 0x51, 0xe6, 0xa2, 0x1f, 0xec, 0xdf, 0x95, 0xe7, 0x37, - 0x32, 0x9f, 0xe5, 0xbe, 0xa3, 0x73, 0xda, 0x8e, 0x0b, 0x94, 0xb9, 0xe5, 0xb4, 0xd5, 0x92, 0xc7, 0xe4, 0x3d, 0x0b, - 0xb6, 0xfd, 0x97, 0x09, 0xf2, 0x2a, 0xc2, 0x7c, 0x42, 0x95, 0xcd, 0x3f, 0x20, 0xcc, 0x16, 0x07, 0xf6, 0xd8, 0x85, - 0x89, 0x48, 0x6f, 0xc1, 0x92, 0x18, 0x66, 0xa5, 0x08, 0xe3, 0x1d, 0x78, 0xff, 0x6c, 0x2a, 0x31, 0x3a, 0x43, 0x27, - 0xf7, 0xb3, 0x87, 0xb4, 0x4e, 0xce, 0xde, 0xbe, 0x3e, 0xfb, 0xae, 0x37, 0x28, 0x46, 0x69, 0x3c, 0xe8, 0x7d, 0x77, - 0xb6, 0xda, 0x00, 0x44, 0xa6, 0x38, 0x8b, 0xc9, 0x94, 0x26, 0xe2, 0x33, 0x32, 0x0c, 0x9e, 0xd5, 0x89, 0x38, 0xa3, - 0x89, 0xe9, 0xbe, 0x46, 0x69, 0xf2, 0xed, 0x28, 0xcc, 0xe1, 0xe5, 0x52, 0x6c, 0x2a, 0x11, 0x83, 0x9d, 0x52, 0xcd, - 0xb3, 0xbc, 0x7d, 0x16, 0xe7, 0xa3, 0x0e, 0x59, 0xa5, 0x03, 0x74, 0x7b, 0x22, 0xed, 0xaa, 0x74, 0x05, 0x84, 0x1e, - 0x00, 0x27, 0x5d, 0xf9, 0xf3, 0x70, 0x10, 0x09, 0x84, 0x5a, 0x30, 0x27, 0xd3, 0x88, 0x6e, 0x48, 0xaf, 0xb0, 0xcf, - 0xc0, 0x2c, 0xa4, 0x34, 0x0f, 0x6e, 0xae, 0x16, 0x2d, 0x77, 0xc5, 0xca, 0x51, 0x58, 0xad, 0x45, 0x54, 0x23, 0xd5, - 0x31, 0x38, 0xef, 0x40, 0x04, 0x80, 0x62, 0x04, 0xcf, 0x78, 0xd4, 0xef, 0x47, 0x2a, 0x28, 0x27, 0xa1, 0x5f, 0x14, - 0xfa, 0xa5, 0x31, 0x28, 0x63, 0xfe, 0x2e, 0xd4, 0xc4, 0x00, 0xf5, 0x96, 0x87, 0x8a, 0x23, 0x00, 0x97, 0x73, 0xc4, - 0x8c, 0xf3, 0x1e, 0x77, 0xd1, 0x38, 0x15, 0xef, 0x84, 0xba, 0x0e, 0x96, 0x0a, 0x75, 0xde, 0xd4, 0x47, 0x7a, 0x4e, - 0x9a, 0x04, 0x0d, 0xe2, 0x06, 0x1e, 0xaf, 0x86, 0x80, 0x6a, 0x25, 0xa4, 0xde, 0x42, 0xa7, 0x54, 0x75, 0x08, 0xac, - 0x01, 0x2e, 0x51, 0xd8, 0x56, 0x98, 0x1c, 0xd1, 0xa6, 0x2c, 0x45, 0x7e, 0xc4, 0x06, 0xed, 0x92, 0x91, 0xa9, 0x83, - 0xcb, 0xe5, 0x72, 0x22, 0xea, 0x5f, 0xf3, 0x2d, 0x80, 0xf3, 0x42, 0x7e, 0x6b, 0x37, 0x5b, 0x26, 0xd9, 0xae, 0x2b, - 0xc3, 0x59, 0x52, 0x8a, 0x6a, 0x5d, 0xe4, 0x55, 0x7a, 0x2f, 0x7e, 0xd6, 0x0f, 0x5d, 0x02, 0x29, 0xf4, 0x23, 0xbd, - 0x6e, 0x37, 0x47, 0xaa, 0x71, 0x74, 0x39, 0xb6, 0xa7, 0xd2, 0x4e, 0xf6, 0xaa, 0xc5, 0x9b, 0x2d, 0x73, 0x25, 0x69, - 0x1c, 0x8b, 0xfc, 0x6d, 0x1e, 0xa7, 0x91, 0x95, 0x1c, 0xfe, 0x1f, 0xde, 0xbe, 0x85, 0xbb, 0x6d, 0x1b, 0x5b, 0xf7, - 0xaf, 0x58, 0xbc, 0xa9, 0x4a, 0x44, 0x90, 0x2c, 0x39, 0x49, 0x67, 0x4a, 0x19, 0xd6, 0x71, 0xf3, 0x68, 0xd3, 0x36, - 0x71, 0x1a, 0xa7, 0x9d, 0xce, 0xe8, 0xea, 0xb8, 0x34, 0x09, 0x5b, 0x6c, 0x68, 0x40, 0x25, 0x29, 0x3f, 0x22, 0xf1, - 0xbf, 0xdf, 0xb5, 0x37, 0x9e, 0xa4, 0x68, 0x27, 0x33, 0xf7, 0xdc, 0xbb, 0xb2, 0x56, 0x2c, 0x82, 0x20, 0xde, 0xd8, - 0xd8, 0xd8, 0x8f, 0x6f, 0xeb, 0x00, 0xd5, 0x2e, 0xf2, 0x95, 0x8b, 0x8d, 0xfc, 0x22, 0x2b, 0x31, 0x60, 0x70, 0xa3, - 0x51, 0xad, 0x50, 0x53, 0x26, 0xf0, 0x85, 0x7c, 0x8f, 0x11, 0xb7, 0x59, 0x99, 0x00, 0xc3, 0x8f, 0x89, 0xfa, 0x92, - 0x9e, 0x42, 0x94, 0x07, 0x15, 0x8f, 0xfb, 0x05, 0x47, 0xc4, 0x6b, 0xab, 0x32, 0x07, 0x26, 0x5b, 0xab, 0x20, 0x11, - 0xec, 0x2e, 0x9b, 0xeb, 0x45, 0xb4, 0x50, 0x77, 0xa1, 0x5e, 0xbc, 0xdd, 0xf6, 0x12, 0x45, 0x07, 0x9c, 0xfc, 0x34, - 0x78, 0x15, 0x67, 0x39, 0x4f, 0xf7, 0x2a, 0xb9, 0xa7, 0x36, 0xd4, 0x9e, 0x72, 0xe6, 0x80, 0x9d, 0xf7, 0x75, 0xb5, - 0xa7, 0xd7, 0xf4, 0x9e, 0x6e, 0xe7, 0x1e, 0x5c, 0x30, 0x70, 0xe7, 0x5e, 0x66, 0xd7, 0x5c, 0xec, 0x81, 0x32, 0xd0, - 0x1a, 0x0f, 0xd4, 0xa2, 0x1a, 0xa9, 0x89, 0xd1, 0x81, 0xab, 0x13, 0x7d, 0x30, 0x07, 0xf4, 0x7b, 0x88, 0x15, 0xde, - 0x7a, 0xbb, 0xd2, 0x07, 0x6d, 0x40, 0x7f, 0x5e, 0x9a, 0x3e, 0xe8, 0x68, 0xf1, 0x2a, 0x24, 0x70, 0x63, 0x48, 0x35, - 0x52, 0xab, 0x91, 0x55, 0xa0, 0x78, 0xc3, 0x5b, 0xbc, 0x3b, 0xd7, 0x92, 0x8d, 0xf7, 0x12, 0x81, 0xbd, 0x32, 0x51, - 0xc5, 0x99, 0x38, 0xf6, 0x52, 0x79, 0xad, 0x9d, 0x64, 0x84, 0xf1, 0x2d, 0x2b, 0xa9, 0xbf, 0x43, 0xcc, 0x2d, 0xd2, - 0x1c, 0x06, 0x2f, 0xc3, 0x8a, 0xcc, 0x78, 0xbf, 0x2f, 0x67, 0x32, 0x2a, 0x67, 0x62, 0xbf, 0x8c, 0x14, 0x42, 0xdb, - 0x7d, 0x22, 0xa0, 0x07, 0x25, 0x40, 0xbe, 0x00, 0xa8, 0x7a, 0x48, 0xf8, 0xf3, 0x90, 0xd4, 0xa7, 0x53, 0xe8, 0x53, - 0x68, 0xeb, 0x15, 0xaf, 0xa0, 0xaa, 0x6e, 0x8c, 0x6c, 0xa3, 0x82, 0x16, 0x8f, 0xe5, 0x59, 0x6d, 0x18, 0x9b, 0x53, - 0xeb, 0x5d, 0x6f, 0x36, 0x98, 0xb2, 0xb9, 0x50, 0xab, 0x30, 0x24, 0xd1, 0x4d, 0xe9, 0x85, 0x0f, 0xb1, 0x58, 0x59, - 0xad, 0xcd, 0x6f, 0x62, 0x7f, 0x64, 0x22, 0xc5, 0xfd, 0x6c, 0x89, 0x73, 0x17, 0x8f, 0xe7, 0x55, 0x5f, 0x6b, 0x69, - 0x91, 0x69, 0xf3, 0x9d, 0xbe, 0x0c, 0x69, 0x2a, 0x6a, 0x48, 0xa3, 0xce, 0x0c, 0xba, 0x6f, 0x97, 0x57, 0x54, 0x23, - 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, 0x1e, 0x88, 0xa2, 0x1a, 0x15, 0x6b, 0x21, 0x10, 0x6d, 0x18, 0x72, 0xcc, - 0x2c, 0x21, 0xc9, 0x3e, 0xf1, 0xef, 0x54, 0x70, 0x85, 0x22, 0xbe, 0x31, 0x70, 0xde, 0x95, 0xf5, 0xec, 0xae, 0x23, - 0x3f, 0x27, 0x16, 0x56, 0xfb, 0x0f, 0xcd, 0xa3, 0xd6, 0x38, 0x0b, 0x68, 0x6b, 0x5a, 0xdd, 0x70, 0xb8, 0x47, 0x75, - 0x2c, 0x4a, 0x03, 0x48, 0xec, 0x91, 0xe5, 0xa2, 0x75, 0xcc, 0xa0, 0x01, 0xfd, 0x6d, 0x76, 0xb5, 0xbe, 0x42, 0xd4, - 0xb6, 0x12, 0x59, 0x27, 0xa9, 0xfc, 0x4b, 0xda, 0xa3, 0xae, 0xed, 0xa9, 0xfc, 0x6f, 0xdb, 0x54, 0x39, 0xb4, 0x40, - 0xf2, 0xd8, 0xcd, 0x59, 0xa0, 0x3a, 0x12, 0x44, 0x81, 0xda, 0x7a, 0xc1, 0xd4, 0x3b, 0x65, 0x8a, 0x0e, 0xe4, 0xe7, - 0xc2, 0x9c, 0x61, 0x5f, 0x70, 0xc4, 0x98, 0xa5, 0x12, 0x83, 0xa9, 0x8f, 0x31, 0xaa, 0x69, 0xad, 0x00, 0x5d, 0x3f, - 0xdd, 0xc0, 0x9f, 0xa8, 0xa8, 0xd1, 0x50, 0x6b, 0x24, 0x85, 0xa2, 0x89, 0x0a, 0x3a, 0x96, 0x16, 0x3a, 0x98, 0x42, - 0x27, 0x91, 0xb0, 0x04, 0x34, 0x4c, 0x88, 0x4e, 0x2a, 0xf0, 0xd6, 0x00, 0xce, 0x7c, 0x5c, 0x94, 0xeb, 0x42, 0x1b, - 0xcc, 0xfd, 0x10, 0x5f, 0xf3, 0xd7, 0x2f, 0x9c, 0x51, 0x7d, 0xcb, 0x5a, 0xdf, 0xd3, 0x82, 0xfc, 0x10, 0x72, 0x8a, - 0x0e, 0x4c, 0xec, 0x68, 0x83, 0xc6, 0x18, 0x65, 0xad, 0x43, 0x5d, 0x9c, 0xe8, 0xf8, 0x2b, 0xda, 0x04, 0xef, 0x01, - 0x4f, 0x11, 0x6d, 0x78, 0x28, 0x8c, 0x55, 0x35, 0x3e, 0x95, 0xac, 0xa5, 0x07, 0x2b, 0x78, 0xba, 0x4e, 0x78, 0x08, - 0x7a, 0x24, 0xc2, 0x8e, 0xc2, 0x62, 0x1e, 0x2f, 0xe0, 0x38, 0x29, 0x08, 0xa8, 0x1d, 0xf4, 0x15, 0x7c, 0xbe, 0x40, - 0xf7, 0x57, 0x89, 0x1e, 0x60, 0x68, 0x41, 0xdc, 0x0c, 0x7d, 0x3a, 0xba, 0x8a, 0x57, 0x0d, 0x15, 0x09, 0x9f, 0x17, - 0x60, 0x3b, 0xa4, 0xd4, 0x53, 0xa0, 0x85, 0x4a, 0x94, 0x7e, 0x18, 0xf8, 0x0e, 0x0d, 0x7c, 0xad, 0x75, 0x80, 0x86, - 0x7e, 0xc6, 0x34, 0xb5, 0xce, 0x50, 0xf9, 0xcc, 0xbb, 0x67, 0x46, 0xcb, 0x99, 0x05, 0x63, 0xd0, 0xb7, 0xd1, 0x14, - 0xc5, 0x39, 0xf9, 0x2c, 0x28, 0xe2, 0x34, 0x8b, 0x73, 0xf0, 0xdb, 0x8c, 0x0b, 0xcc, 0x98, 0xc4, 0x15, 0xbf, 0x94, - 0x05, 0x68, 0xbb, 0x73, 0x95, 0x5a, 0xd7, 0x20, 0x20, 0xfb, 0x01, 0xac, 0x5e, 0x1a, 0x3a, 0x2a, 0xe7, 0xdd, 0xa5, - 0x4d, 0x21, 0x62, 0x11, 0x82, 0x4d, 0x33, 0x5d, 0xb2, 0xe3, 0x50, 0x69, 0x73, 0x20, 0xbe, 0x11, 0x1a, 0xf7, 0x4f, - 0xc3, 0xd8, 0x6a, 0x8a, 0xad, 0xdd, 0xdb, 0x76, 0xfb, 0x7b, 0xe9, 0xa5, 0xd3, 0x9c, 0xf4, 0x18, 0xfb, 0xbd, 0x0c, - 0x8b, 0x91, 0xed, 0x08, 0x81, 0x25, 0xe7, 0x7d, 0xea, 0xbf, 0xa2, 0xe5, 0x3c, 0x01, 0xd3, 0x11, 0x1d, 0x21, 0x17, - 0x28, 0x3b, 0x46, 0x71, 0x07, 0x06, 0x57, 0xf4, 0xfb, 0x60, 0x95, 0x61, 0x2e, 0x24, 0x4b, 0x92, 0x32, 0x78, 0x9e, - 0x7a, 0x18, 0xf0, 0x6b, 0xa6, 0xcc, 0x5d, 0x94, 0xf5, 0xe9, 0x92, 0x4c, 0x53, 0x64, 0x20, 0xd6, 0xe1, 0x26, 0x4b, - 0xa3, 0x44, 0x89, 0xc8, 0x96, 0xe8, 0x1f, 0x69, 0x28, 0x96, 0x0e, 0xd7, 0x8b, 0x54, 0x89, 0x50, 0x31, 0x4f, 0xf1, - 0xa4, 0x4e, 0xeb, 0x74, 0x84, 0xf1, 0x26, 0x41, 0x29, 0x57, 0xc3, 0x40, 0x95, 0x54, 0x2f, 0x85, 0x4d, 0xb1, 0xdd, - 0xea, 0x8b, 0x95, 0x98, 0xc7, 0x0b, 0x7c, 0x29, 0x70, 0x14, 0x7f, 0xe2, 0x5e, 0xac, 0x29, 0xb5, 0x3d, 0xa8, 0x1d, - 0x51, 0x42, 0x7f, 0xe2, 0x70, 0x91, 0xf8, 0x4e, 0xea, 0xb8, 0x7f, 0x68, 0x11, 0x72, 0xa6, 0x0e, 0x52, 0xc3, 0x0d, - 0xed, 0x08, 0xff, 0x0d, 0xd7, 0x67, 0x9c, 0xd1, 0x9b, 0x6a, 0x46, 0x8d, 0xdf, 0xeb, 0xe1, 0x19, 0xa3, 0x3e, 0x1b, - 0x38, 0xac, 0x10, 0x85, 0x36, 0xec, 0xa8, 0x54, 0xa2, 0x85, 0xa1, 0x54, 0x7f, 0x09, 0x15, 0x47, 0xdc, 0x99, 0x51, - 0x96, 0x8c, 0x4f, 0xcb, 0x43, 0x31, 0x1d, 0x0c, 0x4a, 0x52, 0x19, 0x0b, 0x3d, 0xb8, 0x1e, 0x78, 0xfe, 0x3d, 0x70, - 0x0b, 0xf1, 0xe0, 0x90, 0xc5, 0x90, 0x1b, 0x70, 0xfc, 0x16, 0x27, 0x57, 0x8d, 0x4a, 0x15, 0xbc, 0x9a, 0xa8, 0x16, - 0xfc, 0x54, 0x86, 0x01, 0xfa, 0x24, 0x05, 0x60, 0x32, 0x98, 0xf2, 0x5b, 0x90, 0x28, 0x9d, 0xa9, 0x1b, 0xd2, 0xaf, - 0xa2, 0xe0, 0x17, 0xbc, 0xe0, 0x22, 0x71, 0x05, 0x58, 0xde, 0xc1, 0xf6, 0x3a, 0xaa, 0xa8, 0x02, 0xe2, 0x35, 0x3d, - 0x8e, 0xb8, 0xf1, 0xfe, 0x33, 0x3d, 0xb6, 0x40, 0xad, 0xd6, 0xb1, 0xc1, 0x67, 0x8e, 0xc1, 0x05, 0x5d, 0x4b, 0x6c, - 0x0d, 0xd5, 0xb0, 0x22, 0x30, 0x70, 0x01, 0x07, 0x61, 0x89, 0xe2, 0xd8, 0x4a, 0x5e, 0x91, 0x86, 0x94, 0xf6, 0x81, - 0xe1, 0x68, 0x93, 0x1c, 0xdf, 0x66, 0xd9, 0x4d, 0xe0, 0x7c, 0xd1, 0x39, 0x69, 0x26, 0x96, 0x0d, 0xde, 0xe7, 0xcd, - 0xf9, 0x75, 0xff, 0x90, 0x50, 0x15, 0xec, 0x86, 0xb7, 0x83, 0xdd, 0x38, 0xe1, 0xd7, 0x5c, 0x2c, 0x74, 0x7c, 0x16, - 0x73, 0xc9, 0xf2, 0x5b, 0xeb, 0xdd, 0x92, 0xa4, 0x56, 0x40, 0xfb, 0x2c, 0x0b, 0x6a, 0x22, 0x00, 0xdd, 0x0f, 0x7f, - 0x81, 0xd0, 0x19, 0xfe, 0xf6, 0x18, 0x5c, 0x91, 0xc2, 0x7b, 0x87, 0x40, 0x58, 0xd3, 0xcd, 0x9d, 0xda, 0x80, 0x2f, - 0xc6, 0xfd, 0x19, 0x53, 0x4f, 0xbf, 0xcd, 0xe4, 0xae, 0xae, 0xdb, 0x23, 0xcb, 0xf0, 0x11, 0xae, 0x14, 0x00, 0xcb, - 0x84, 0xbf, 0x18, 0x5b, 0x52, 0x7d, 0x02, 0x70, 0x6a, 0x3a, 0xa2, 0x4f, 0x10, 0x18, 0x38, 0x25, 0x5a, 0x8c, 0xae, - 0x95, 0x23, 0x9a, 0x41, 0x5a, 0xd3, 0xad, 0x30, 0xde, 0x7a, 0xd0, 0x42, 0xcf, 0x34, 0x9c, 0xf8, 0x0f, 0x9a, 0x79, - 0x55, 0x40, 0x00, 0xad, 0x8c, 0xe0, 0xad, 0xf5, 0xd1, 0x1c, 0x21, 0x3e, 0x61, 0x49, 0x34, 0x61, 0xf1, 0x4c, 0xf1, - 0x63, 0x42, 0x37, 0x4d, 0x6d, 0xd3, 0x07, 0xa4, 0xbf, 0xb8, 0x66, 0xfd, 0x94, 0x65, 0xed, 0xdb, 0x43, 0xc5, 0x8b, - 0x69, 0x33, 0xf8, 0x61, 0xa2, 0x8a, 0xf1, 0xbf, 0xa8, 0x7c, 0xa9, 0x15, 0xc0, 0x30, 0x77, 0xd5, 0xd3, 0xef, 0x37, - 0xb3, 0xe5, 0x40, 0xa8, 0xfc, 0xce, 0x20, 0xe9, 0xd3, 0xf1, 0xfc, 0xc0, 0x26, 0x51, 0x5b, 0xe8, 0xf9, 0xe3, 0x52, - 0x37, 0xa1, 0xf2, 0xda, 0xd4, 0x88, 0x56, 0xc8, 0x50, 0xd9, 0x3a, 0x60, 0x7d, 0xff, 0x10, 0xee, 0x2e, 0x6a, 0x1a, - 0x6a, 0xdd, 0x73, 0xd7, 0xa2, 0xe0, 0xc4, 0x1f, 0x60, 0x2c, 0x2e, 0x24, 0xb5, 0x0e, 0xc2, 0xa4, 0x1f, 0x2d, 0x4e, - 0x72, 0xa3, 0xae, 0x4e, 0xce, 0x14, 0xf3, 0x04, 0x2e, 0xaa, 0x65, 0xdb, 0x5f, 0x51, 0xa9, 0x4b, 0xb9, 0xbd, 0xa2, - 0x34, 0x3d, 0xa4, 0xed, 0x55, 0x9c, 0xb7, 0x05, 0x17, 0xfc, 0x0b, 0x05, 0x17, 0xd6, 0xc1, 0xba, 0xe3, 0x4e, 0xd9, - 0x13, 0x9e, 0x28, 0xd3, 0xda, 0xe0, 0xae, 0x1b, 0x8c, 0x89, 0xb1, 0xdf, 0x5d, 0xf2, 0xe4, 0x23, 0xb2, 0xe0, 0xdf, - 0x65, 0x02, 0x3c, 0x93, 0xdd, 0x2b, 0x95, 0xff, 0x07, 0xff, 0x6a, 0x6b, 0xdf, 0x59, 0xf3, 0x4f, 0xcf, 0x7a, 0xb8, - 0x73, 0x98, 0xfc, 0x00, 0x9d, 0x01, 0xdd, 0x5c, 0xc9, 0x94, 0x03, 0x32, 0x80, 0xb5, 0x48, 0x46, 0x03, 0x3e, 0xb4, - 0xb2, 0x6c, 0xfb, 0x4e, 0xab, 0x0b, 0xc2, 0xbd, 0x04, 0x6e, 0x7a, 0x7f, 0x6d, 0x66, 0xe6, 0x74, 0xad, 0x44, 0xd3, - 0xa5, 0xb1, 0xb5, 0x2c, 0x55, 0xc0, 0xee, 0xf7, 0x9e, 0x64, 0xd3, 0xfc, 0x70, 0x39, 0xcd, 0x2d, 0x75, 0xdb, 0xb8, - 0x65, 0x03, 0x40, 0x88, 0x5d, 0x6b, 0x2b, 0x07, 0x90, 0xdc, 0x1e, 0x84, 0xf0, 0xb5, 0x22, 0xf4, 0x54, 0x89, 0xd0, - 0xa7, 0x69, 0xb3, 0x0f, 0x76, 0x55, 0xad, 0x1b, 0x71, 0x8e, 0x06, 0xa9, 0x66, 0xe4, 0x4f, 0xae, 0x79, 0x71, 0x91, - 0xcb, 0x1b, 0xc0, 0x40, 0x26, 0xb5, 0x51, 0x58, 0x5e, 0x81, 0x3b, 0x3f, 0x3a, 0x8e, 0x33, 0x31, 0xca, 0x31, 0x58, - 0x2b, 0xc2, 0x23, 0xeb, 0xc4, 0x19, 0x80, 0x20, 0xfb, 0x93, 0xa6, 0xe3, 0xb9, 0x16, 0x18, 0xd3, 0x17, 0xb8, 0xab, - 0x9c, 0x1d, 0x6d, 0x72, 0xbb, 0xe8, 0x9b, 0x33, 0xac, 0x3b, 0x52, 0x5a, 0x1b, 0x8b, 0xae, 0x3b, 0x58, 0x6b, 0x06, - 0x6d, 0x11, 0x4a, 0x3e, 0xe4, 0x4e, 0xda, 0x4f, 0x01, 0x0d, 0xce, 0xb2, 0xf4, 0xd6, 0x5a, 0xe5, 0x6f, 0xb4, 0x10, - 0x27, 0x8a, 0xa9, 0x13, 0xdf, 0x44, 0x89, 0x3e, 0x3f, 0x13, 0xe3, 0x06, 0x02, 0xa9, 0x3f, 0x60, 0x50, 0x8d, 0x22, - 0x4c, 0xe0, 0x3a, 0x10, 0xc5, 0xf6, 0x44, 0x6d, 0x2c, 0x47, 0xd0, 0x09, 0x21, 0xde, 0x41, 0x19, 0xc6, 0xea, 0xe2, - 0x40, 0x1b, 0x2c, 0x7d, 0xdd, 0x5a, 0xe7, 0x86, 0x50, 0x18, 0x27, 0x30, 0xc5, 0x20, 0xa9, 0xb3, 0xce, 0x32, 0x41, - 0x95, 0x1d, 0x93, 0xce, 0xfb, 0x00, 0xdd, 0x5d, 0x8b, 0xa6, 0xf8, 0xba, 0x73, 0x07, 0xdd, 0xc7, 0xf5, 0x6b, 0x2d, - 0x72, 0x83, 0x3f, 0x6f, 0x89, 0xb0, 0x08, 0x9c, 0xb5, 0x26, 0x5f, 0x35, 0xc2, 0x81, 0x29, 0xc9, 0x34, 0xec, 0x25, - 0xca, 0xa6, 0x7b, 0xbb, 0xed, 0xf5, 0xee, 0x15, 0x71, 0xf5, 0x18, 0xab, 0xbc, 0x9b, 0xb9, 0xbd, 0x53, 0xad, 0xc5, - 0xee, 0x4d, 0xdb, 0x4f, 0xb1, 0xa3, 0xd6, 0xda, 0xed, 0x86, 0x13, 0x6a, 0xc8, 0xb7, 0xa2, 0x4a, 0xab, 0xd3, 0x8d, - 0x41, 0x3b, 0xc4, 0xb3, 0x16, 0x19, 0xdc, 0x28, 0x5f, 0x38, 0xa1, 0x93, 0x8a, 0xb3, 0xea, 0xd4, 0x05, 0x9b, 0x2b, - 0x5e, 0x2d, 0x65, 0x1a, 0x09, 0x8a, 0x36, 0xe7, 0x51, 0x49, 0x13, 0xb9, 0x16, 0x55, 0x24, 0x6b, 0xd4, 0x8b, 0x5a, - 0x8d, 0x01, 0x02, 0x32, 0x9d, 0x35, 0x3d, 0xa8, 0x82, 0xd9, 0x50, 0x46, 0x72, 0xfa, 0x1e, 0x2c, 0xed, 0x91, 0x63, - 0xad, 0xef, 0xab, 0xb3, 0xc5, 0xb7, 0x7a, 0x42, 0x30, 0x85, 0xd9, 0x03, 0x61, 0xe0, 0x9a, 0xc6, 0x90, 0xd3, 0x2e, - 0x71, 0x59, 0xd3, 0x2d, 0xe1, 0x1e, 0x6e, 0x57, 0xb2, 0x23, 0x37, 0x4f, 0x9a, 0x9b, 0x2b, 0xd8, 0x51, 0x31, 0x1f, - 0x83, 0xf6, 0x4b, 0xaa, 0x6b, 0x97, 0xe6, 0xd6, 0xe3, 0x41, 0x40, 0x83, 0x41, 0x61, 0xf8, 0xd7, 0x89, 0xf1, 0xf0, - 0xa4, 0x01, 0x41, 0x52, 0x2e, 0xc2, 0xb1, 0x6f, 0x44, 0x3f, 0x99, 0xca, 0x43, 0x8e, 0x16, 0xef, 0xd0, 0xea, 0x04, - 0xa2, 0x78, 0x89, 0x50, 0x12, 0xa3, 0x2a, 0x34, 0x22, 0x28, 0x4f, 0xcb, 0x5f, 0xaa, 0xea, 0x10, 0x50, 0x48, 0xfb, - 0x8a, 0x42, 0xd9, 0x26, 0x31, 0x34, 0xc3, 0x2f, 0xe7, 0x93, 0x85, 0x9e, 0x81, 0x81, 0x9c, 0x1f, 0x2c, 0xf4, 0x2c, - 0x0c, 0xe4, 0xfc, 0xc9, 0xa2, 0x76, 0xeb, 0x40, 0x13, 0x10, 0xcf, 0x85, 0xa3, 0x93, 0xd2, 0xaa, 0x6c, 0x01, 0xdd, - 0x3c, 0x44, 0xd0, 0x7f, 0xb2, 0x87, 0xa0, 0x93, 0x0b, 0xed, 0xc8, 0x0d, 0x68, 0x3b, 0x0e, 0x81, 0xbd, 0x62, 0x52, - 0x61, 0x02, 0x10, 0x1d, 0xb2, 0x31, 0x18, 0x62, 0xab, 0x0f, 0x0e, 0xd9, 0x78, 0xea, 0x93, 0x20, 0x60, 0x74, 0x7f, - 0x30, 0x90, 0xe0, 0xb7, 0x78, 0x95, 0x3e, 0xda, 0x08, 0x74, 0xd3, 0x77, 0x77, 0x43, 0xef, 0xe2, 0x0a, 0x4e, 0xd5, - 0xee, 0x9e, 0x84, 0x6e, 0x32, 0xed, 0x00, 0xbd, 0x86, 0xb8, 0x21, 0xbf, 0x32, 0x1a, 0x8d, 0x6c, 0x4a, 0x48, 0x88, - 0xe1, 0x1c, 0x9a, 0x39, 0x2d, 0x97, 0xaf, 0x6e, 0x3d, 0x1b, 0x90, 0x61, 0xa6, 0xb7, 0x4c, 0xd6, 0x0f, 0x50, 0x56, - 0x3d, 0x86, 0x76, 0xe8, 0x3d, 0x72, 0xfc, 0xf0, 0xe0, 0x9b, 0x8c, 0x9f, 0x39, 0x5c, 0x7b, 0x38, 0x17, 0xbe, 0xcb, - 0x9a, 0x91, 0x39, 0x74, 0x9e, 0x7d, 0x1c, 0xef, 0x61, 0x9c, 0x7c, 0x9e, 0x85, 0xf2, 0xc6, 0x6b, 0xfa, 0x1f, 0x95, - 0xde, 0xec, 0x70, 0xc8, 0xe9, 0x0a, 0x56, 0xdc, 0xac, 0x0a, 0x0d, 0x3f, 0x8b, 0xbc, 0x71, 0xc4, 0x6b, 0x12, 0x55, - 0xdd, 0xe7, 0xbd, 0x0d, 0x53, 0xda, 0x31, 0x0e, 0x00, 0x4e, 0xd4, 0xaa, 0x61, 0x57, 0x1a, 0xd7, 0xea, 0x20, 0x86, - 0xa1, 0x84, 0xad, 0x12, 0x47, 0x42, 0xf9, 0x1b, 0x80, 0xb0, 0x18, 0x8a, 0xe3, 0xad, 0x61, 0x7d, 0x80, 0xfd, 0xd0, - 0x05, 0x9a, 0xe6, 0x94, 0x6a, 0x06, 0x00, 0x49, 0xc0, 0x1f, 0x3d, 0xdd, 0x34, 0x54, 0xb6, 0x79, 0x1e, 0x5a, 0x56, - 0x57, 0xf0, 0x40, 0x4f, 0x5d, 0xc9, 0xc0, 0xb8, 0xaa, 0x63, 0x6f, 0x73, 0x7f, 0x7b, 0xb4, 0x8a, 0x7c, 0x67, 0x93, - 0xda, 0x66, 0x55, 0x68, 0xec, 0xe3, 0x09, 0x3d, 0x9d, 0x00, 0xad, 0xd7, 0x96, 0x8a, 0xf6, 0xfb, 0x28, 0x46, 0x8d, - 0x0b, 0x05, 0x56, 0x61, 0x22, 0xc1, 0x21, 0xc2, 0x08, 0xa1, 0xdf, 0x97, 0xe1, 0xc6, 0x17, 0x64, 0x10, 0x0d, 0xd7, - 0xa2, 0xe3, 0x0f, 0x39, 0x5e, 0xb4, 0x2d, 0x55, 0x35, 0x27, 0x4d, 0x5b, 0x02, 0x6f, 0xc2, 0x01, 0xb6, 0xf3, 0x4f, - 0x1b, 0x22, 0x57, 0xe1, 0xa2, 0x84, 0xef, 0x88, 0x6b, 0x41, 0x74, 0x53, 0x9b, 0x7a, 0x1b, 0x76, 0x88, 0x8e, 0xa6, - 0x78, 0x74, 0xc8, 0x3d, 0x77, 0xcf, 0x6d, 0x11, 0xdf, 0x7c, 0x86, 0xdc, 0x35, 0x9d, 0xbd, 0x14, 0x61, 0x50, 0xb7, - 0x6c, 0xa0, 0x58, 0x87, 0x4e, 0x50, 0x80, 0x51, 0x5b, 0x3e, 0x01, 0x1d, 0x1b, 0x0c, 0x2a, 0x82, 0x4f, 0x0a, 0xdb, - 0xa6, 0x41, 0xfe, 0x88, 0x77, 0x43, 0x87, 0xd7, 0x96, 0x3c, 0x10, 0xaf, 0xb0, 0xcf, 0x94, 0x70, 0xff, 0x82, 0x82, - 0xee, 0x28, 0x2f, 0x57, 0x85, 0xab, 0xd2, 0x00, 0x54, 0xd9, 0xf1, 0x5c, 0x6b, 0x4a, 0x5a, 0xc0, 0x4a, 0x49, 0xdd, - 0xf9, 0x4d, 0x44, 0xdc, 0x92, 0xa9, 0x98, 0xad, 0xba, 0x51, 0xe5, 0xa1, 0x44, 0x91, 0x8e, 0x3d, 0xdb, 0x39, 0x58, - 0x03, 0xe0, 0x29, 0x6c, 0x2f, 0xce, 0xb0, 0xa0, 0x8c, 0xcb, 0x96, 0xb9, 0x04, 0x8a, 0xfa, 0x61, 0x9c, 0x97, 0x1d, - 0x5f, 0xee, 0x8e, 0xb6, 0xf7, 0xd0, 0x1b, 0xb1, 0x31, 0x5e, 0x5f, 0x46, 0x4d, 0xbf, 0x78, 0x86, 0x2b, 0x4b, 0x41, - 0x1e, 0x68, 0xaa, 0x47, 0x18, 0x1d, 0x02, 0xd3, 0x94, 0x1f, 0xb1, 0xf1, 0x74, 0x38, 0x34, 0x64, 0xd0, 0x6b, 0x26, - 0xc6, 0xff, 0xfa, 0x02, 0x5a, 0x67, 0x26, 0xae, 0xf1, 0x69, 0xfb, 0x0a, 0x5a, 0xdd, 0xa2, 0x4c, 0xee, 0x0c, 0x0c, - 0x1f, 0x68, 0xc9, 0x14, 0x4c, 0x15, 0xde, 0x10, 0xa9, 0x64, 0x9f, 0x96, 0xd6, 0x61, 0xdf, 0x2e, 0x14, 0x5a, 0x68, - 0xe2, 0x57, 0x19, 0xe2, 0xa7, 0xae, 0x33, 0xff, 0x36, 0xed, 0x53, 0x83, 0x58, 0x58, 0x12, 0xa3, 0x10, 0xbf, 0x38, - 0x55, 0xb6, 0x13, 0x42, 0x05, 0xc4, 0x43, 0xd7, 0xba, 0x71, 0x24, 0x55, 0xec, 0x49, 0xa1, 0xf1, 0xd4, 0x70, 0xdf, - 0x0b, 0x1d, 0xb3, 0x0e, 0xb3, 0xb8, 0xcd, 0x1a, 0x49, 0x8d, 0x71, 0x2a, 0x4c, 0x70, 0x4a, 0xb9, 0x8a, 0x04, 0x46, - 0xc7, 0xb3, 0x85, 0x41, 0x54, 0x49, 0x4c, 0x32, 0xb6, 0x16, 0xc2, 0xc4, 0xae, 0x73, 0x85, 0x69, 0xea, 0x22, 0xf5, - 0x9b, 0x81, 0xc9, 0x82, 0x86, 0xfc, 0x1e, 0x8d, 0xd6, 0x54, 0x4d, 0x01, 0x86, 0x71, 0x94, 0x6a, 0xfc, 0x5b, 0x84, - 0xda, 0x0c, 0x03, 0x00, 0xdb, 0xbc, 0x93, 0x99, 0xa8, 0x5e, 0x0b, 0x84, 0x40, 0x73, 0xf6, 0x53, 0x45, 0xb5, 0x33, - 0x0b, 0x46, 0xd1, 0x6e, 0xaf, 0x7c, 0x3e, 0x70, 0x42, 0x79, 0xac, 0x2e, 0x50, 0xaf, 0x64, 0xf1, 0x46, 0xa6, 0xbc, - 0x15, 0x17, 0x73, 0x4f, 0xb2, 0x0f, 0xf9, 0x08, 0xce, 0x2b, 0x74, 0x2a, 0x37, 0xdb, 0x44, 0x99, 0x25, 0x49, 0xc6, - 0x02, 0x63, 0xf3, 0x12, 0xcc, 0xa4, 0x66, 0xc6, 0xf0, 0x6b, 0x08, 0x2e, 0xb6, 0x73, 0x12, 0x6e, 0xee, 0xe7, 0x81, - 0x21, 0x34, 0xb9, 0x68, 0x89, 0x86, 0xad, 0x1d, 0xaf, 0x27, 0xd7, 0x84, 0xfb, 0xb0, 0x11, 0x6b, 0x32, 0xc6, 0xb8, - 0x36, 0x37, 0xb2, 0x7e, 0xb4, 0xc0, 0x83, 0x31, 0x65, 0xfd, 0x09, 0x64, 0x5a, 0x49, 0x59, 0xe7, 0x0b, 0x23, 0x66, - 0x52, 0x89, 0xde, 0xed, 0x1b, 0x9f, 0xd5, 0x5d, 0x44, 0xfd, 0xd6, 0x7e, 0x4f, 0xea, 0xe1, 0xce, 0x7f, 0x50, 0x58, - 0x83, 0xca, 0x88, 0xcb, 0x88, 0xf2, 0xcc, 0x81, 0x6e, 0x9a, 0x14, 0x71, 0x7a, 0xb6, 0x8a, 0x8b, 0x92, 0xa7, 0x50, - 0xa9, 0xa6, 0x6e, 0x51, 0x6f, 0x02, 0xf6, 0x86, 0x48, 0x92, 0xac, 0xa5, 0xb1, 0x15, 0xbb, 0x34, 0x48, 0xcf, 0xbd, - 0x61, 0x96, 0x5e, 0x55, 0x68, 0x48, 0x4b, 0xbd, 0xb3, 0x50, 0xc9, 0xfc, 0x15, 0xff, 0x19, 0xd4, 0x0a, 0x74, 0xb4, - 0x49, 0x31, 0x9e, 0x03, 0x23, 0xbe, 0x1b, 0xc1, 0xea, 0x01, 0xe2, 0xa2, 0x09, 0x4a, 0xbd, 0x23, 0x76, 0xfc, 0xdc, - 0xe4, 0xe1, 0x5d, 0xc8, 0x39, 0x83, 0x4f, 0x1f, 0x66, 0x89, 0x5a, 0xeb, 0x48, 0x8c, 0xd4, 0x0c, 0xa0, 0xe9, 0xa0, - 0xcc, 0x79, 0x2c, 0x82, 0x59, 0xcf, 0x24, 0x46, 0x3d, 0xae, 0x7f, 0x81, 0x86, 0xda, 0x6f, 0x56, 0x96, 0x67, 0xd5, - 0xdd, 0x97, 0x70, 0x60, 0x53, 0x5b, 0x41, 0x8f, 0xd7, 0x95, 0xbc, 0xbc, 0x54, 0xdd, 0xf6, 0x0b, 0x31, 0x72, 0xba, - 0xc6, 0xb5, 0x74, 0x5e, 0x2d, 0x58, 0xaf, 0x3b, 0xdd, 0x2c, 0xee, 0x66, 0x19, 0x0d, 0x84, 0xb5, 0x9d, 0x4f, 0x34, - 0x7f, 0xd6, 0x6c, 0xbb, 0x8f, 0xb7, 0x20, 0x66, 0x01, 0x00, 0xa4, 0x07, 0x51, 0xb0, 0xcc, 0x52, 0x1e, 0x50, 0x79, - 0x1f, 0x47, 0x59, 0x28, 0xbd, 0x9c, 0x65, 0xfc, 0xb4, 0x69, 0xac, 0x75, 0x56, 0x28, 0x43, 0x6b, 0xa3, 0x3b, 0x5d, - 0x65, 0x88, 0xed, 0x27, 0x71, 0xb6, 0x00, 0xf7, 0xc7, 0x0c, 0x85, 0x86, 0xce, 0x32, 0xd2, 0x44, 0xc3, 0x77, 0xdd, - 0x33, 0xc8, 0x28, 0x4e, 0xd6, 0x79, 0x25, 0xdd, 0xe8, 0xb3, 0x36, 0x12, 0xe6, 0x1e, 0xa2, 0x5f, 0xc5, 0xe0, 0x51, - 0xee, 0xf3, 0xda, 0xe8, 0x64, 0x5a, 0x46, 0xda, 0x9d, 0x9f, 0xd4, 0xcb, 0x2c, 0xd5, 0x3a, 0x6c, 0x9f, 0x61, 0x6f, - 0x8d, 0x49, 0x6f, 0x42, 0x6a, 0x18, 0x89, 0xcf, 0x67, 0xd4, 0x08, 0x01, 0x6d, 0x39, 0xfe, 0x0e, 0x9f, 0x61, 0x68, - 0x0a, 0x2c, 0x55, 0xdc, 0xc2, 0x6e, 0xf8, 0x9a, 0x4f, 0x56, 0x2d, 0x00, 0x11, 0xac, 0x7c, 0xbd, 0x8b, 0x57, 0x42, - 0x7d, 0xa6, 0xcd, 0x00, 0x90, 0x05, 0xa5, 0xdc, 0xf1, 0x53, 0x2a, 0x1d, 0x2c, 0x51, 0xb4, 0xbd, 0x9c, 0xbe, 0xd1, - 0xb1, 0xf1, 0x43, 0x7a, 0x2e, 0x60, 0xbb, 0x90, 0xdf, 0xba, 0x57, 0x2f, 0x51, 0x91, 0xda, 0x36, 0xeb, 0x01, 0xbe, - 0xdc, 0xa0, 0x49, 0x18, 0x41, 0x99, 0x32, 0x05, 0x30, 0xb8, 0xa9, 0x46, 0xc1, 0xa4, 0xd5, 0x48, 0xd8, 0x52, 0x4f, - 0xb2, 0xdc, 0xf4, 0xc1, 0xa9, 0xee, 0x11, 0xf4, 0x68, 0x87, 0x93, 0x96, 0xfd, 0x5a, 0xc1, 0xd1, 0xc9, 0xd5, 0x10, - 0x35, 0xf3, 0x5e, 0xdb, 0x91, 0x21, 0xe5, 0x32, 0x0c, 0x04, 0x53, 0x8e, 0x79, 0x7a, 0x6c, 0x3d, 0x23, 0xa2, 0x07, - 0xce, 0x3e, 0xd3, 0xad, 0xba, 0x92, 0x80, 0xe8, 0xf8, 0xcd, 0xd3, 0xd7, 0x57, 0xf1, 0xa5, 0x41, 0x51, 0x6a, 0x58, - 0xc4, 0x28, 0xd3, 0xbe, 0x4a, 0xc2, 0xe0, 0xfd, 0xfa, 0xfe, 0x67, 0x95, 0xa5, 0xf6, 0x7b, 0xb0, 0xb1, 0xa2, 0xaa, - 0x5f, 0x4b, 0x5e, 0x34, 0x05, 0x58, 0xf7, 0x59, 0xa2, 0x40, 0xee, 0xf7, 0x36, 0xcd, 0x7c, 0x13, 0x35, 0x6e, 0x36, - 0xac, 0x37, 0xae, 0xdb, 0xa5, 0xb6, 0x64, 0x47, 0x56, 0x22, 0x67, 0x16, 0x83, 0x19, 0x3f, 0x2a, 0x0c, 0x4a, 0xc3, - 0x06, 0x55, 0xa9, 0xf8, 0xbd, 0x11, 0xc1, 0xa9, 0x63, 0x55, 0x61, 0x4c, 0x03, 0x66, 0x5b, 0x51, 0x6b, 0x50, 0x07, - 0xa5, 0xb4, 0x35, 0x51, 0xd8, 0x7e, 0x67, 0x05, 0x35, 0xbf, 0xff, 0x69, 0x0c, 0xf9, 0x9a, 0x52, 0x50, 0x49, 0xc0, - 0xce, 0xa0, 0xd1, 0x53, 0x25, 0x0c, 0xa4, 0x20, 0x78, 0x02, 0x94, 0x2f, 0xa2, 0xc6, 0x6a, 0xb7, 0xaf, 0x4e, 0x8d, - 0xd1, 0x16, 0x10, 0x5a, 0x48, 0x8f, 0x2e, 0xfb, 0xb8, 0x8d, 0x75, 0x20, 0xf1, 0xe0, 0x04, 0xdb, 0xb9, 0xba, 0x46, - 0x23, 0xa1, 0xf9, 0x43, 0xa3, 0x01, 0xaf, 0x69, 0x05, 0x0a, 0xf5, 0x1c, 0x47, 0x43, 0x67, 0x87, 0x14, 0x44, 0x6c, - 0xd0, 0xc2, 0xbe, 0x7b, 0x3e, 0x34, 0xfb, 0x7a, 0x9e, 0x2c, 0x48, 0x4d, 0xa5, 0xfb, 0xdc, 0x2d, 0x21, 0x6b, 0xd5, - 0xa1, 0xac, 0x3c, 0xc0, 0xf1, 0x42, 0xc9, 0xfc, 0x1d, 0x26, 0x35, 0x4a, 0x63, 0x42, 0x63, 0xc4, 0x02, 0x96, 0x04, - 0xed, 0xf5, 0x40, 0xfd, 0x32, 0x08, 0x15, 0xce, 0xf4, 0x44, 0xe2, 0x53, 0xca, 0xd5, 0xa7, 0x05, 0xa9, 0xa7, 0x05, - 0x73, 0xa0, 0x97, 0xbe, 0x95, 0x5f, 0xd9, 0xf8, 0x68, 0x77, 0xef, 0x9a, 0x0b, 0xeb, 0x18, 0x82, 0x61, 0x0b, 0xbf, - 0x39, 0x35, 0x05, 0x60, 0xc3, 0x63, 0x5d, 0x96, 0x6f, 0xd4, 0x44, 0x66, 0x71, 0x48, 0x22, 0x90, 0x6c, 0x37, 0x37, - 0xb7, 0x11, 0x6c, 0x7b, 0x0b, 0xb5, 0xa1, 0xfe, 0xf2, 0xb6, 0xfb, 0x3d, 0xc3, 0xcb, 0x3d, 0xb9, 0x77, 0xd3, 0x86, - 0xf2, 0x87, 0xfb, 0x57, 0xc9, 0xff, 0x55, 0x25, 0xf7, 0x5b, 0x65, 0xd6, 0x6d, 0xf1, 0x7e, 0xd7, 0x71, 0xcb, 0x31, - 0x1a, 0x04, 0xd6, 0x14, 0x18, 0x48, 0x4f, 0x1a, 0xd3, 0x44, 0x87, 0x54, 0x66, 0xcc, 0xe0, 0xd1, 0x05, 0x68, 0x0e, - 0xd3, 0x79, 0x1e, 0x03, 0x70, 0x80, 0x7f, 0xe4, 0x11, 0xea, 0x9f, 0xce, 0xf3, 0xe0, 0x2c, 0x18, 0x94, 0x83, 0x40, - 0x7f, 0xe2, 0x9a, 0x13, 0x2c, 0x40, 0xe7, 0x16, 0x33, 0x08, 0x36, 0x69, 0xcd, 0x1c, 0xe2, 0xc3, 0x64, 0x3a, 0x18, - 0xc4, 0x64, 0x03, 0x20, 0x7d, 0xf1, 0xc2, 0x3a, 0x07, 0x15, 0x7a, 0x41, 0xb6, 0xea, 0x2e, 0x9a, 0x15, 0x7b, 0xd5, - 0x4e, 0xf3, 0x7e, 0x3f, 0x9f, 0x97, 0x83, 0xa0, 0x51, 0x61, 0x61, 0xbc, 0xff, 0x68, 0xf3, 0x4b, 0xa3, 0x93, 0x26, - 0x18, 0xa6, 0xf6, 0x18, 0xd5, 0x2b, 0x9e, 0x66, 0xb4, 0x71, 0x3b, 0x56, 0xca, 0x17, 0x10, 0xc5, 0x03, 0x43, 0xd6, - 0xca, 0xbb, 0x73, 0xf0, 0xba, 0xdc, 0x78, 0x73, 0x44, 0x01, 0x76, 0x53, 0x18, 0x27, 0x35, 0x17, 0x5d, 0xd4, 0xc4, - 0x33, 0xd8, 0xe9, 0xea, 0xad, 0x44, 0xab, 0xf1, 0x5e, 0xbc, 0x6b, 0x36, 0xfe, 0x56, 0xee, 0xe9, 0x32, 0xf7, 0x2e, - 0x00, 0x71, 0x76, 0x2f, 0xae, 0xf6, 0xb0, 0xd4, 0xbd, 0x60, 0x60, 0x91, 0x43, 0xda, 0xd5, 0xea, 0xa1, 0x88, 0xd4, - 0x79, 0x0c, 0x06, 0x4c, 0xa6, 0x21, 0x35, 0x99, 0xf6, 0x0a, 0x05, 0x69, 0x63, 0xad, 0x05, 0xb4, 0xe1, 0xb0, 0xd8, - 0xb1, 0x1b, 0x76, 0xa7, 0x5b, 0x87, 0x42, 0x09, 0xa3, 0x57, 0xd7, 0xcd, 0x43, 0xad, 0xe1, 0x89, 0xa0, 0x07, 0xd5, - 0x68, 0x3f, 0x3d, 0x94, 0x27, 0xed, 0xb1, 0x00, 0x17, 0x3d, 0x7c, 0xf9, 0x52, 0xe0, 0x45, 0x7b, 0x07, 0x79, 0xce, - 0x7c, 0xaa, 0x7c, 0x10, 0x1b, 0x6e, 0x19, 0x3e, 0xb4, 0x8f, 0x6f, 0x05, 0x32, 0xa9, 0x3b, 0x9a, 0xda, 0xda, 0x1d, - 0x8d, 0x63, 0x02, 0xfd, 0xa6, 0x1c, 0xa5, 0x4c, 0x4c, 0x2d, 0x4b, 0x76, 0xd4, 0xcb, 0x95, 0x37, 0x54, 0xca, 0x8e, - 0x96, 0x6d, 0xce, 0x2f, 0x6d, 0x24, 0xf4, 0xfb, 0xda, 0x1d, 0x08, 0xdf, 0xa8, 0xf5, 0x86, 0xbc, 0x6c, 0x88, 0x58, - 0x0e, 0x31, 0x03, 0xc7, 0x0b, 0xa9, 0x5c, 0xbb, 0x8b, 0xa6, 0xaa, 0x6e, 0x67, 0x2b, 0x17, 0xb4, 0xc4, 0x5b, 0x29, - 0xb0, 0x8a, 0xd4, 0xe9, 0xf5, 0x54, 0xe2, 0x7d, 0x1f, 0xc5, 0xf6, 0x23, 0x60, 0x1b, 0x1b, 0x47, 0x63, 0xe3, 0x16, - 0xb1, 0xc1, 0x57, 0x51, 0x45, 0x0b, 0x0e, 0x10, 0xdc, 0x6d, 0x49, 0x2d, 0xcd, 0x1c, 0xe2, 0xbe, 0xe2, 0x01, 0xda, - 0x77, 0x71, 0xc4, 0xa9, 0x00, 0xdb, 0xba, 0xd6, 0x39, 0xab, 0xe5, 0x80, 0xcd, 0x44, 0xcf, 0x3f, 0xad, 0x1a, 0x89, - 0x18, 0x56, 0xd9, 0x48, 0x59, 0xa1, 0x3d, 0x28, 0x5d, 0xc2, 0xc5, 0x17, 0xe0, 0x65, 0xfb, 0x7e, 0x65, 0xf7, 0xd9, - 0x12, 0xfb, 0x87, 0x79, 0xd5, 0x04, 0x8f, 0xbc, 0xc6, 0xdb, 0x7b, 0x98, 0xf8, 0x52, 0x29, 0x84, 0x57, 0x29, 0x0d, - 0x25, 0x00, 0x83, 0x24, 0xa8, 0xe1, 0x4a, 0xdb, 0x66, 0x90, 0xca, 0x18, 0x76, 0xb7, 0x7a, 0xab, 0xff, 0xd3, 0x2a, - 0x5c, 0x54, 0xb2, 0x18, 0x93, 0x40, 0xe7, 0x54, 0xcb, 0x4d, 0x4c, 0xc1, 0xb3, 0x5d, 0x72, 0x04, 0x0a, 0x3b, 0x01, - 0xdc, 0x50, 0xc2, 0x7e, 0xc5, 0xdb, 0x50, 0xce, 0x5e, 0x59, 0xc9, 0x93, 0xdb, 0x97, 0x54, 0xd0, 0x84, 0x4c, 0x85, - 0xdd, 0xbf, 0xad, 0x0d, 0xfb, 0x22, 0x94, 0x23, 0x29, 0x70, 0x71, 0xd0, 0x39, 0x80, 0xfd, 0x41, 0x2e, 0x63, 0xf3, - 0x99, 0xf4, 0xfb, 0xea, 0xfd, 0xf3, 0x3c, 0x4b, 0x3e, 0xee, 0xbc, 0x37, 0x3c, 0xcd, 0x92, 0x01, 0x95, 0x88, 0xa9, - 0x75, 0x55, 0x0c, 0x97, 0xda, 0xc5, 0xb8, 0x41, 0x32, 0xe2, 0x7b, 0xa9, 0x43, 0x8c, 0x18, 0x5f, 0x64, 0x87, 0xa4, - 0xe4, 0x74, 0x59, 0x77, 0xf6, 0x5c, 0x8b, 0x66, 0xd0, 0x18, 0x6e, 0xc7, 0x7b, 0x49, 0xaf, 0x00, 0x15, 0x15, 0xba, - 0x67, 0x81, 0x6b, 0x78, 0x73, 0x49, 0x34, 0xb6, 0xf4, 0xb4, 0x25, 0x1a, 0xb8, 0x57, 0x26, 0x24, 0xd5, 0xc6, 0x01, - 0x16, 0xb1, 0xae, 0x3f, 0x86, 0x12, 0x80, 0x5a, 0x0d, 0xd2, 0x2b, 0x7d, 0x45, 0xa8, 0x4a, 0x42, 0x30, 0x3a, 0x91, - 0xf0, 0x32, 0xa0, 0x71, 0x66, 0x12, 0x2d, 0x6c, 0x70, 0x40, 0x5f, 0x54, 0x26, 0xd1, 0xd8, 0x90, 0x07, 0xb4, 0xb2, - 0x69, 0x00, 0x83, 0x0f, 0x92, 0x24, 0xfa, 0x7a, 0x69, 0x92, 0x40, 0x50, 0x82, 0xf2, 0x0d, 0xfa, 0x4b, 0xe9, 0xf9, - 0x58, 0xfe, 0xcb, 0x3b, 0x94, 0x7e, 0x08, 0x25, 0xc8, 0x14, 0x75, 0xc5, 0x34, 0x63, 0x47, 0x59, 0xb7, 0x31, 0x89, - 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x79, 0xbc, 0x62, 0xc7, 0x21, 0xd7, - 0x78, 0xe9, 0xcf, 0xe3, 0x15, 0xce, 0x10, 0xad, 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, - 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x4e, 0x92, 0xf9, 0xf2, - 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, - 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x5a, - 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1b, 0x50, 0x22, 0xa3, 0xb2, - 0xe2, 0xab, 0x15, 0x4f, 0x67, 0xb7, 0x49, 0x94, 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0x59, 0x9f, 0x67, - 0xc9, 0x6b, 0x88, 0x3d, 0xb0, 0x92, 0x0a, 0x8b, 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x76, - 0x9d, 0x44, 0x6f, 0x97, 0x1e, 0x92, 0x9a, 0x99, 0xb2, 0x4d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x1b, 0x6d, 0x01, - 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, - 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x0f, 0x8b, 0x7e, 0x5f, - 0x1e, 0x16, 0xdb, 0x6d, 0x79, 0x14, 0xf7, 0xfb, 0xf2, 0x28, 0x36, 0xfc, 0x83, 0x52, 0x6c, 0x1b, 0x73, 0x83, 0x84, - 0xe6, 0x12, 0xa2, 0x16, 0x8d, 0xe0, 0x0f, 0xcd, 0x72, 0x2e, 0xa2, 0xfc, 0x30, 0xe9, 0xf7, 0x7b, 0xcb, 0x99, 0x18, - 0xe4, 0xc3, 0x24, 0xca, 0x87, 0x89, 0xe7, 0x84, 0xf8, 0x9b, 0xe7, 0x84, 0xa8, 0x68, 0xe0, 0x0a, 0xce, 0x0c, 0x40, - 0x14, 0xf0, 0xe9, 0x1f, 0xd5, 0xb5, 0x14, 0xba, 0x96, 0x58, 0xd5, 0x92, 0xe8, 0x0a, 0x6a, 0x76, 0x5d, 0x84, 0x25, - 0x96, 0x42, 0x97, 0xec, 0xcf, 0x25, 0xf0, 0x44, 0x39, 0xaf, 0x36, 0xc0, 0xc0, 0x46, 0x78, 0xe7, 0x30, 0xe1, 0x24, - 0xd6, 0x35, 0xa0, 0x9d, 0x6e, 0x6a, 0x7a, 0x41, 0x57, 0xf4, 0x12, 0xf9, 0xd9, 0x0b, 0x30, 0x58, 0x3a, 0x64, 0xf9, - 0x74, 0x30, 0xb8, 0x20, 0x2b, 0x56, 0xce, 0xc3, 0x78, 0x10, 0xae, 0x67, 0xf9, 0xf0, 0x22, 0xba, 0x20, 0xe4, 0xab, - 0x62, 0x41, 0x7b, 0xab, 0x51, 0xf9, 0x31, 0x83, 0xe0, 0x7e, 0xe9, 0x2c, 0xcc, 0x4c, 0x9c, 0x8f, 0xd5, 0xe8, 0x96, - 0xae, 0x20, 0x7e, 0x0d, 0xdc, 0x48, 0x48, 0x04, 0x1d, 0xb9, 0xa4, 0x2b, 0xba, 0xa6, 0xd2, 0xcc, 0x30, 0x86, 0xe8, - 0xb6, 0xc7, 0x49, 0x02, 0x8e, 0xc9, 0xae, 0xf8, 0x68, 0xac, 0x0a, 0xef, 0xfa, 0x8e, 0xd0, 0x5e, 0x2f, 0x71, 0x83, - 0xf4, 0x5d, 0x7b, 0x90, 0x80, 0x11, 0x19, 0xa9, 0x81, 0x32, 0x23, 0x23, 0xa9, 0x99, 0x54, 0x1c, 0x92, 0xd8, 0x1f, - 0x12, 0x35, 0x0e, 0x89, 0x3f, 0x0e, 0xb9, 0x1e, 0x07, 0xe4, 0xee, 0x97, 0x6c, 0x4c, 0x53, 0x36, 0xa6, 0x6b, 0x35, - 0x2a, 0xf4, 0x8a, 0x9e, 0x6b, 0xea, 0x78, 0xc6, 0xde, 0xc0, 0x81, 0x3d, 0x08, 0xf3, 0x59, 0x3c, 0x7c, 0x13, 0xbd, - 0x21, 0xe4, 0x2b, 0x49, 0xaf, 0xd5, 0xa5, 0x0c, 0xc2, 0x20, 0x5e, 0x81, 0x73, 0xa9, 0x0b, 0x75, 0x72, 0x65, 0x76, - 0x1c, 0x3e, 0x5d, 0x36, 0x9e, 0xce, 0x21, 0xa2, 0x0f, 0x5a, 0xa9, 0xf4, 0xfb, 0xe1, 0x05, 0x2b, 0xe7, 0x67, 0xe1, - 0x98, 0x00, 0x0e, 0x8f, 0x1e, 0xce, 0x8b, 0xd1, 0x2d, 0xbd, 0x18, 0xdd, 0x11, 0xb0, 0xf0, 0x1a, 0x4f, 0xd7, 0x87, - 0x2c, 0x9e, 0x0e, 0x06, 0x6b, 0xa4, 0xea, 0x2a, 0xf7, 0x9a, 0x2c, 0xe8, 0x05, 0x4e, 0x04, 0x01, 0x86, 0x3e, 0x13, - 0x6b, 0x43, 0xc3, 0xdf, 0x30, 0xf8, 0xf8, 0x8e, 0x5d, 0x8c, 0xee, 0xe8, 0x2d, 0x7b, 0xb3, 0x1d, 0x4f, 0x81, 0x99, - 0x5a, 0xcd, 0xc2, 0xbb, 0xc3, 0xcb, 0xd9, 0x25, 0xbb, 0x8b, 0xee, 0x8e, 0xa0, 0xa1, 0x57, 0xec, 0x0e, 0x01, 0x97, - 0xd2, 0xc7, 0xcb, 0xc1, 0x1b, 0xb2, 0x3f, 0x18, 0xa4, 0x24, 0x0a, 0xaf, 0x43, 0xaf, 0x95, 0x6f, 0xe8, 0x1d, 0xa1, - 0x2b, 0x76, 0x8b, 0xa3, 0x71, 0xc9, 0xf0, 0x83, 0x73, 0x76, 0x57, 0x5f, 0x87, 0xde, 0x6e, 0x4e, 0x44, 0x27, 0x88, - 0x11, 0xfa, 0x1a, 0x38, 0x9a, 0xe5, 0xc2, 0x4c, 0xc0, 0x93, 0xb9, 0xc8, 0x68, 0x51, 0x68, 0x06, 0xe2, 0xac, 0x04, - 0xc4, 0x92, 0xa8, 0xfb, 0xcd, 0x46, 0x67, 0xb0, 0x9c, 0xfb, 0xfd, 0x5e, 0x65, 0xe8, 0x01, 0x22, 0x67, 0x76, 0xd2, - 0x83, 0x9e, 0x4f, 0x0f, 0xf0, 0x13, 0xbd, 0x6a, 0x10, 0x27, 0xf3, 0xbb, 0x65, 0xf4, 0x9b, 0x47, 0x1f, 0x7e, 0xe8, - 0xa6, 0x3c, 0x22, 0xff, 0xf7, 0x29, 0x4f, 0x99, 0x47, 0x6f, 0x2a, 0x0f, 0x04, 0xcf, 0x5b, 0x93, 0x4a, 0x23, 0x51, - 0x8d, 0xce, 0x56, 0x31, 0x68, 0x23, 0x51, 0xdb, 0xa0, 0x9f, 0xd0, 0xc2, 0x0a, 0x22, 0xe4, 0x1c, 0xbc, 0x00, 0x83, - 0x54, 0x08, 0x95, 0xa3, 0x16, 0x25, 0x1a, 0x82, 0xe4, 0xb2, 0xe4, 0x2a, 0x7c, 0x0e, 0xa1, 0xea, 0xf4, 0x71, 0x26, - 0xc2, 0x86, 0x1e, 0x87, 0x3e, 0x00, 0xfc, 0xaf, 0x3b, 0xe4, 0xa2, 0xe4, 0x97, 0x78, 0x36, 0xb7, 0x09, 0x46, 0xc1, - 0x12, 0xd1, 0x0c, 0x6d, 0x83, 0xd8, 0x8f, 0x25, 0xc1, 0x7a, 0x24, 0x8d, 0x47, 0xa5, 0x39, 0x22, 0xfc, 0x28, 0x3e, - 0x8a, 0x9e, 0xc6, 0x86, 0x44, 0x72, 0x24, 0x91, 0x7c, 0x00, 0x84, 0x93, 0xa0, 0xbf, 0xb8, 0x6b, 0xb2, 0x6b, 0x21, - 0x31, 0xe8, 0x4f, 0x4b, 0xa6, 0x65, 0xf7, 0xaa, 0xc7, 0xbe, 0x22, 0xc8, 0x1d, 0xd3, 0x7f, 0x79, 0x7d, 0xf8, 0xe7, - 0x12, 0x67, 0xd0, 0x7a, 0xbe, 0xa8, 0xce, 0xcc, 0xbc, 0xc1, 0x8d, 0xbc, 0x2e, 0x6b, 0xd7, 0xe5, 0x0b, 0xbe, 0xc7, - 0x6f, 0x2b, 0x2e, 0xd2, 0x72, 0xef, 0x97, 0xaa, 0x8d, 0xe7, 0x54, 0xae, 0x57, 0x2e, 0xce, 0x8a, 0x32, 0x4e, 0xf5, - 0xa4, 0x2e, 0xc6, 0x1a, 0xb6, 0xe1, 0xf7, 0x88, 0xba, 0x92, 0x96, 0xa3, 0xa7, 0x94, 0xab, 0x66, 0xca, 0xc5, 0x3a, - 0xcf, 0x7f, 0xde, 0x49, 0xc5, 0x29, 0x6e, 0xa6, 0x20, 0x55, 0x6a, 0xb9, 0x80, 0xea, 0x39, 0x6a, 0xb9, 0x5b, 0x9a, - 0x1d, 0xe0, 0xdc, 0x36, 0xd5, 0xc7, 0xca, 0xec, 0xc2, 0x4b, 0x6e, 0xdc, 0x9f, 0x4c, 0x19, 0x16, 0x8c, 0x42, 0x9b, - 0x55, 0x57, 0xda, 0xbe, 0xd0, 0x3a, 0x0d, 0xc3, 0x95, 0x1f, 0x2f, 0x20, 0x5d, 0xc0, 0x38, 0x5e, 0x94, 0x4c, 0x8c, - 0xdb, 0xa3, 0xb7, 0x82, 0xf8, 0x92, 0xad, 0x40, 0xc0, 0x5c, 0xc3, 0xdb, 0x75, 0x1d, 0x6d, 0xf7, 0xc4, 0x29, 0xa3, - 0x72, 0x15, 0x8b, 0xef, 0xe3, 0x95, 0x81, 0x4c, 0x56, 0xc7, 0x63, 0x63, 0x4c, 0xa7, 0x3f, 0x25, 0xa1, 0x5f, 0x08, - 0x05, 0x9f, 0xf5, 0xd2, 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, - 0xe4, 0xab, 0xa6, 0x80, 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, - 0x9d, 0x1a, 0x53, 0x31, 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, - 0xa8, 0xdf, 0x02, 0x17, 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, - 0xbe, 0x85, 0x07, 0x88, 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, - 0xa9, 0xd2, 0xc4, 0x70, 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, - 0xe8, 0xa6, 0x74, 0xe9, 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, - 0xac, 0x95, 0xf0, 0xa6, 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, - 0x14, 0x0d, 0x1d, 0xd0, 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, - 0x35, 0x2b, 0xe6, 0xf9, 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, - 0x21, 0xc9, 0x26, 0x56, 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, - 0x32, 0x0c, 0xcb, 0xe1, 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x70, 0x3e, 0x09, 0x15, - 0xbb, 0x60, 0xf7, 0x02, 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, - 0x65, 0x16, 0xcf, 0xc7, 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, - 0xbe, 0xc1, 0x2a, 0xf2, 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, - 0xdc, 0x94, 0x33, 0xae, 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, - 0x49, 0xd3, 0x80, 0xee, 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, - 0xad, 0xd0, 0xab, 0x1a, 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, - 0x12, 0x06, 0x3f, 0xa4, 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, - 0x14, 0x62, 0x94, 0x50, 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, - 0x7c, 0x5d, 0x55, 0x81, 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, - 0x48, 0x08, 0x5e, 0xff, 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, - 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, - 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, - 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, - 0x4f, 0xae, 0xd8, 0x51, 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, - 0xf7, 0x1f, 0xcb, 0x5d, 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, - 0x84, 0x2d, 0xe6, 0x70, 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, - 0xb4, 0xcc, 0xaa, 0xf7, 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, - 0x02, 0xd0, 0x64, 0x23, 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, - 0x92, 0xa0, 0x84, 0x66, 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, - 0x07, 0xf6, 0x16, 0x04, 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, - 0x08, 0xf2, 0xd5, 0x18, 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, - 0xe4, 0xd0, 0x3e, 0x4b, 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb7, 0x2d, 0xb2, 0x24, 0xeb, - 0xc7, 0xd2, 0x28, 0x62, 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3e, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, - 0x0e, 0xe2, 0x36, 0x08, 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, - 0x6f, 0xb2, 0xd6, 0xa8, 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, - 0xdb, 0xed, 0x78, 0x2a, 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, - 0xa5, 0xb7, 0x7f, 0xe1, 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, - 0x4e, 0xff, 0x76, 0x6b, 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xb4, 0x81, 0x2b, 0xd5, 0x2a, 0x04, 0xec, 0x42, - 0x49, 0xf6, 0x0f, 0x20, 0x2a, 0x42, 0x33, 0xee, 0x66, 0xd9, 0x90, 0xc8, 0xf8, 0x71, 0x3a, 0xcb, 0x86, 0x60, 0x87, - 0x7b, 0x51, 0x89, 0xcb, 0x51, 0x6b, 0x83, 0xd3, 0xb3, 0x24, 0x84, 0x50, 0x0e, 0x58, 0xd9, 0xad, 0xfa, 0x73, 0xa7, - 0xcc, 0x84, 0xd4, 0x64, 0x75, 0x3b, 0xa5, 0x7b, 0x98, 0xe6, 0x7b, 0x66, 0x04, 0x07, 0xdc, 0xdb, 0x5f, 0xf5, 0xc7, - 0x30, 0xc9, 0x34, 0x39, 0x45, 0xf2, 0x8b, 0xf4, 0x14, 0x92, 0x76, 0xe8, 0xa9, 0x22, 0x80, 0x13, 0x6a, 0x3f, 0x86, - 0xdf, 0x30, 0xee, 0xdf, 0x35, 0x5f, 0xbb, 0xa9, 0x88, 0x9e, 0x52, 0x2c, 0x53, 0x93, 0xd3, 0x24, 0x2b, 0x12, 0x88, - 0xda, 0xa8, 0x9a, 0x11, 0x3d, 0x71, 0x31, 0x1f, 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, - 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xec, 0x29, 0xdd, 0x9b, 0x7c, 0x73, 0x40, 0xf7, 0x0e, 0x9e, 0x3c, 0x23, 0x00, - 0x8b, 0x76, 0x79, 0x1e, 0x1e, 0x3c, 0x7b, 0x46, 0xf7, 0xbe, 0xfd, 0x96, 0xee, 0x4d, 0x9e, 0x1c, 0x34, 0xd2, 0x26, - 0xcf, 0xbe, 0xa5, 0x7b, 0xdf, 0x3c, 0x6d, 0xa4, 0x1d, 0x8c, 0x9f, 0xd1, 0xbd, 0xbf, 0x7f, 0x63, 0xd2, 0xfe, 0x06, - 0xd9, 0xbe, 0x3d, 0xc0, 0xff, 0x4c, 0xda, 0xe4, 0xd9, 0x13, 0xba, 0x37, 0x19, 0x43, 0x25, 0xcf, 0x5c, 0x25, 0xe3, - 0x09, 0x7c, 0xfc, 0x04, 0xfe, 0xfb, 0x1b, 0x09, 0x16, 0xb4, 0x92, 0x2c, 0x17, 0xa8, 0x3f, 0x43, 0x11, 0x27, 0xaa, - 0x26, 0x12, 0x1e, 0x62, 0x66, 0xf5, 0x4d, 0x1c, 0x06, 0xc4, 0xa5, 0x43, 0x41, 0x74, 0x6f, 0x3c, 0x7a, 0x46, 0x02, - 0x1f, 0x9e, 0xee, 0xc6, 0x07, 0x19, 0xcb, 0xc5, 0x3c, 0xfb, 0x2a, 0x37, 0xb1, 0x15, 0x3c, 0x00, 0xab, 0x8f, 0x7e, - 0xae, 0x4a, 0xce, 0xb3, 0xaf, 0x2a, 0xb9, 0x9b, 0xeb, 0xf7, 0x16, 0xa0, 0xbc, 0xbf, 0x6a, 0xd9, 0x4d, 0xa1, 0x42, - 0xa7, 0xb5, 0x46, 0x9f, 0x7d, 0xc4, 0xf4, 0xc1, 0xc0, 0xbb, 0x61, 0xff, 0xb4, 0x53, 0x4e, 0xeb, 0x1b, 0x8d, 0x42, - 0x8d, 0xca, 0x43, 0xc2, 0x8e, 0xa0, 0xe8, 0xc1, 0x00, 0x78, 0x02, 0x0f, 0xf7, 0xed, 0xdf, 0x2c, 0xe3, 0x63, 0x47, - 0x19, 0xbf, 0xa0, 0x0c, 0x01, 0x8d, 0x7a, 0x98, 0xdd, 0xf4, 0xb0, 0xd1, 0xad, 0x5e, 0xb2, 0x54, 0x27, 0x53, 0xd3, - 0x33, 0xd8, 0xd7, 0xba, 0x96, 0x7b, 0x46, 0x14, 0x2d, 0x2f, 0xf6, 0x52, 0x3e, 0xab, 0xd8, 0x4f, 0x4b, 0x54, 0x6f, - 0x45, 0x8d, 0x37, 0x32, 0x9b, 0x55, 0xec, 0x7b, 0xf3, 0x06, 0xb8, 0x19, 0xf6, 0xbb, 0x7a, 0xf2, 0x03, 0x67, 0x70, - 0x69, 0xdb, 0xa3, 0x4c, 0x8c, 0x00, 0x2b, 0x20, 0x03, 0x07, 0x1e, 0x00, 0x1d, 0xf4, 0x47, 0x7b, 0xbb, 0x55, 0x29, - 0xcd, 0x3e, 0x5b, 0x18, 0x40, 0xc3, 0xbc, 0x4d, 0x5c, 0xd9, 0xff, 0x6a, 0xc8, 0x4b, 0x50, 0xb8, 0xd5, 0x2c, 0x6f, - 0xa7, 0x30, 0x84, 0x10, 0xfc, 0x71, 0xc9, 0x00, 0x70, 0x20, 0xc0, 0x60, 0xac, 0x65, 0x40, 0xcd, 0x96, 0x8f, 0x36, - 0x5c, 0xa9, 0x27, 0x81, 0x33, 0xb8, 0x90, 0x45, 0xc2, 0x4f, 0xb4, 0xd8, 0x1f, 0xad, 0x1f, 0x7d, 0xdf, 0x1e, 0x0f, - 0xd6, 0xbe, 0xc7, 0x47, 0xfa, 0xb3, 0xc6, 0x75, 0x60, 0xd3, 0xf2, 0x8d, 0x17, 0xb5, 0x95, 0x78, 0x94, 0xc0, 0x1b, - 0x98, 0x88, 0x14, 0x06, 0xa9, 0x16, 0x38, 0x06, 0xe5, 0x8d, 0x85, 0x58, 0xaa, 0xae, 0x6e, 0xb0, 0x05, 0x91, 0x21, - 0x78, 0xb8, 0xfd, 0x6b, 0xa9, 0x02, 0x47, 0xf5, 0xfb, 0x5c, 0xfa, 0x6e, 0x4f, 0xc6, 0x8e, 0x1c, 0xa7, 0x7e, 0x2a, - 0x1c, 0xfc, 0x37, 0xa9, 0x6b, 0x63, 0xb9, 0x92, 0x32, 0xcb, 0xb2, 0xb0, 0xa3, 0x50, 0xcb, 0x3d, 0x2a, 0x0f, 0x92, - 0x2f, 0xe4, 0x10, 0xc9, 0x02, 0xa3, 0x50, 0x90, 0xe1, 0x84, 0x8a, 0xd1, 0x5a, 0x94, 0xcb, 0xec, 0xa2, 0x0a, 0x37, - 0x4a, 0xa1, 0xcc, 0x29, 0xfa, 0x76, 0x83, 0x03, 0x09, 0x89, 0xb2, 0xf2, 0x6d, 0xfc, 0x36, 0x44, 0xb0, 0x3a, 0xae, - 0x6d, 0xa1, 0xb8, 0xb7, 0x3f, 0x79, 0xda, 0xc5, 0x1f, 0x19, 0x17, 0x50, 0x17, 0x8b, 0x69, 0x38, 0xb1, 0xb1, 0x6f, - 0xdc, 0x17, 0x56, 0xd3, 0x03, 0x50, 0xdf, 0xa5, 0x12, 0x23, 0xa8, 0xaf, 0x8c, 0x7d, 0x6c, 0x8f, 0x31, 0x39, 0x83, - 0x58, 0xc3, 0x2a, 0x67, 0xa6, 0xfa, 0x46, 0xd8, 0x11, 0x00, 0x37, 0x42, 0x6b, 0x14, 0x04, 0x1e, 0xaf, 0x42, 0x3c, - 0x2f, 0x55, 0xf8, 0xd6, 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, - 0x61, 0xb5, 0x95, 0x65, 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, - 0x5c, 0x0a, 0xcb, 0xa0, 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, - 0x44, 0x23, 0xc4, 0xc3, 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, - 0xa3, 0x04, 0x97, 0xa9, 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, - 0x6a, 0x5f, 0x43, 0x31, 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, - 0x4d, 0xd8, 0xb9, 0x91, 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, - 0xdb, 0x22, 0x73, 0x44, 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, - 0xf1, 0x14, 0x11, 0x01, 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, - 0x81, 0x2c, 0x80, 0xbe, 0xfd, 0x9c, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, - 0x04, 0xbb, 0xba, 0x35, 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, - 0x44, 0x02, 0x32, 0xfb, 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, - 0x4b, 0x44, 0x12, 0x85, 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, - 0x17, 0x7f, 0x5a, 0x75, 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, - 0x6d, 0x29, 0xc9, 0x55, 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, - 0xee, 0x0e, 0xbf, 0xc4, 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, - 0x2a, 0xca, 0x07, 0x13, 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, - 0xac, 0x77, 0xd3, 0x5a, 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, - 0x30, 0x20, 0xda, 0xa5, 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, - 0x9e, 0x01, 0x49, 0x26, 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, - 0xfb, 0x7a, 0xc6, 0x7f, 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, - 0x10, 0x43, 0x54, 0x7b, 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, - 0x43, 0xa3, 0xde, 0xc6, 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, - 0x88, 0x64, 0xbf, 0x3d, 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, - 0xb8, 0x2c, 0x22, 0xcb, 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, - 0xbf, 0x5e, 0xc9, 0x02, 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, - 0xe3, 0xce, 0x9e, 0x80, 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, - 0xb7, 0x80, 0x49, 0xc0, 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, - 0xd6, 0xfe, 0xd5, 0x5d, 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, - 0xa4, 0xb0, 0xe5, 0x31, 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, - 0x0d, 0xee, 0x47, 0x15, 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, - 0x72, 0xbc, 0xed, 0x76, 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, - 0x59, 0xef, 0x25, 0x60, 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, - 0x4b, 0xb2, 0x1f, 0xa6, 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, - 0x41, 0x6f, 0xe9, 0x0d, 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, - 0xfb, 0xfd, 0xde, 0x99, 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, - 0x9b, 0xf0, 0x2c, 0x0f, 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, - 0x93, 0x23, 0xd0, 0x9b, 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, - 0xde, 0xb5, 0x27, 0x63, 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, - 0x7f, 0xb3, 0xf0, 0x86, 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, - 0xd2, 0x53, 0x76, 0x45, 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0xa7, 0x38, 0x0c, 0xe3, 0x61, 0x41, - 0xf6, 0x25, 0xbd, 0xdb, 0x9f, 0xf0, 0x27, 0x64, 0x16, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, - 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0x4e, 0xe8, 0x0d, 0x2b, 0xe8, 0x29, 0x8b, 0x49, 0x74, 0x0d, 0xad, 0x38, 0x9f, - 0x15, 0xd1, 0x0d, 0x3d, 0x65, 0x67, 0xb3, 0x38, 0x3a, 0xa5, 0x27, 0x2c, 0x1f, 0x4e, 0x20, 0xef, 0xe9, 0xf0, 0x86, - 0xec, 0x9f, 0x90, 0x28, 0x3c, 0xd1, 0xbf, 0xef, 0xe8, 0x25, 0x0f, 0x4f, 0xa8, 0x57, 0xcd, 0x09, 0x31, 0xd5, 0x37, - 0x6a, 0x3f, 0x21, 0x91, 0x3f, 0x98, 0x27, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, - 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, 0x06, 0x74, 0xf6, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, - 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, 0xd7, 0xc1, 0x6b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0xeb, 0x7e, 0x1f, 0x22, - 0xdd, 0x17, 0x33, 0x13, 0xdb, 0xcd, 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0xd7, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, - 0xbc, 0x19, 0xbc, 0x7e, 0x7c, 0x47, 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x1b, 0x9a, 0x01, 0xe0, 0xd7, 0xeb, - 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, 0x7d, 0x7d, 0x78, 0x32, 0x1d, 0x0c, 0x5e, 0x9b, 0x6d, 0xf2, 0x96, 0xdd, 0x53, - 0x0a, 0xac, 0xbf, 0xb3, 0x7e, 0xff, 0xed, 0x51, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xd6, 0x45, - 0x55, 0x3b, 0xeb, 0xf7, 0xd7, 0xfd, 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9c, 0xaf, 0x27, 0x48, 0x5b, 0xe6, 0x8e, 0x22, - 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, 0xac, 0xda, 0x36, 0xeb, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, - 0xec, 0x9d, 0x6d, 0xb7, 0xa7, 0x8c, 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, - 0xcc, 0xe6, 0x66, 0x69, 0x0f, 0x81, 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0x2f, 0x00, - 0x42, 0x24, 0x59, 0xc8, 0x67, 0x38, 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xbb, - 0x1d, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, 0xd1, 0xdf, 0x9e, 0x3d, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, - 0x61, 0x17, 0x6b, 0xb5, 0x0f, 0x46, 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0xbe, 0x98, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, - 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, 0x18, 0x4c, 0x2e, 0xd2, 0xcf, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, - 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, 0xdb, 0x6e, 0x2b, 0xff, 0x12, 0xf8, 0x16, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, - 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, - 0xba, 0xdc, 0xe3, 0xea, 0x5f, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, - 0x0c, 0xb7, 0x56, 0x22, 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, - 0x86, 0x07, 0xc9, 0xc4, 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, - 0x24, 0xd3, 0xe4, 0x10, 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, - 0x8e, 0x49, 0xad, 0xef, 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, - 0x78, 0x34, 0x7e, 0x46, 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, - 0x9b, 0x57, 0x3a, 0x36, 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, - 0xea, 0x23, 0x08, 0xb3, 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, - 0xa3, 0x52, 0xa6, 0xba, 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, - 0x10, 0xc0, 0xa3, 0x11, 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, - 0xde, 0x83, 0x30, 0x29, 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, - 0x57, 0x10, 0x27, 0x6c, 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, - 0x25, 0xf7, 0x26, 0xe3, 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, - 0x57, 0xdc, 0x1b, 0x17, 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, - 0x76, 0x3f, 0x31, 0x2b, 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xf6, 0xf2, 0xec, 0xf5, - 0xdb, 0x57, 0xaf, 0xdf, 0xbe, 0xfe, 0xf0, 0xcf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, - 0x6a, 0xf1, 0x85, 0xb3, 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, - 0x20, 0xa3, 0x51, 0x21, 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, - 0xdb, 0xd1, 0xd6, 0xac, 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, - 0xc8, 0x75, 0xf0, 0xbe, 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, - 0x13, 0x73, 0x6d, 0x74, 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, - 0xef, 0xee, 0xcd, 0xe8, 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, - 0xc2, 0xfc, 0x0c, 0x1b, 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, - 0xce, 0x17, 0xdf, 0x42, 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, - 0x31, 0x1e, 0x77, 0xf7, 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, - 0xbe, 0x5d, 0x24, 0xce, 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, - 0x35, 0xe7, 0x6d, 0x42, 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, - 0x17, 0x43, 0x9a, 0x72, 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, - 0xd7, 0xd9, 0xe6, 0x33, 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, - 0xc4, 0x40, 0x74, 0x01, 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, - 0x31, 0x8b, 0xad, 0x25, 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x84, 0x1d, 0x7d, - 0xf7, 0xb6, 0x01, 0x10, 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, - 0x2b, 0xb4, 0xec, 0x95, 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, - 0xa6, 0x12, 0xd5, 0x23, 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, - 0xee, 0xff, 0xe6, 0x42, 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, - 0x5d, 0xa6, 0x97, 0x5d, 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, - 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, - 0x7c, 0x89, 0x5f, 0x29, 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, - 0xfe, 0x17, 0x18, 0x0d, 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, - 0xeb, 0x67, 0x35, 0xcc, 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, - 0x29, 0x11, 0x83, 0x41, 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, - 0x1a, 0x5b, 0x92, 0x6c, 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, - 0x32, 0xd3, 0xc2, 0xa2, 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, - 0x4d, 0xac, 0xf1, 0x8b, 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, - 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, - 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, - 0xcc, 0xaf, 0x24, 0x19, 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, - 0xdc, 0x18, 0xd6, 0xf4, 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, - 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, - 0x60, 0x1c, 0xa5, 0x83, 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, - 0x0b, 0x68, 0xda, 0x97, 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, - 0x0b, 0xd7, 0xc2, 0x8b, 0xdd, 0x16, 0x0a, 0x4d, 0xb6, 0x0b, 0xf9, 0xff, 0xe3, 0x86, 0x71, 0xdf, 0x5d, 0xc2, 0x2c, - 0xae, 0xeb, 0x6c, 0xb4, 0x2a, 0x64, 0x25, 0xe1, 0x36, 0xa1, 0x44, 0x61, 0xa3, 0x78, 0xb5, 0xca, 0xb5, 0x8b, 0xd8, - 0xbc, 0xa2, 0x00, 0xee, 0x02, 0x71, 0x8a, 0x81, 0x85, 0x36, 0x06, 0x72, 0x9f, 0x78, 0x21, 0x99, 0x55, 0xfb, 0x98, - 0x7b, 0xe4, 0x9f, 0x21, 0x18, 0xa3, 0x8a, 0xa3, 0xf1, 0x4c, 0x61, 0x5d, 0x7c, 0x4e, 0xde, 0xfb, 0x6f, 0x1c, 0x45, - 0xf6, 0x68, 0x06, 0x3d, 0x41, 0xe4, 0x3c, 0xe2, 0xec, 0xc9, 0xe4, 0x65, 0xe0, 0x7e, 0x06, 0x2b, 0xfd, 0x75, 0xb7, - 0x19, 0x6b, 0xdb, 0xa3, 0x7b, 0x61, 0x84, 0xa2, 0x9f, 0xf0, 0x9d, 0xa9, 0x17, 0x70, 0x09, 0xd5, 0xc0, 0xae, 0x2f, - 0x2f, 0x79, 0x09, 0x20, 0x42, 0x99, 0xe8, 0xf7, 0x7b, 0x7f, 0x1a, 0x68, 0xd2, 0x92, 0x17, 0x6f, 0x32, 0x61, 0x9d, - 0x71, 0xa0, 0xa9, 0x40, 0xfd, 0x3f, 0x56, 0xf6, 0x99, 0x8e, 0xc9, 0xcc, 0x7f, 0x1c, 0x4e, 0x48, 0xd4, 0x7c, 0x4d, - 0x3e, 0x73, 0x9a, 0x7e, 0xe6, 0x8a, 0xf6, 0x1f, 0xc8, 0xcc, 0x0d, 0x87, 0x0c, 0xf5, 0x97, 0x8e, 0x79, 0x32, 0x7a, - 0x9d, 0x98, 0x1d, 0x09, 0x56, 0xcd, 0x20, 0x0a, 0x7b, 0x01, 0x0f, 0xea, 0x5a, 0x16, 0x4f, 0x61, 0xf6, 0x41, 0x8d, - 0x28, 0x0e, 0xd9, 0x78, 0x16, 0xca, 0x70, 0x02, 0xf6, 0xbd, 0x93, 0x31, 0xdc, 0x07, 0x64, 0xf8, 0xb1, 0x0a, 0xb1, - 0x73, 0x90, 0xf6, 0xb1, 0x42, 0xc5, 0x04, 0x40, 0x04, 0x42, 0xde, 0x7e, 0x5f, 0xaa, 0x24, 0x7c, 0x5d, 0x62, 0x4a, - 0xa1, 0x3e, 0xf8, 0x4f, 0xa4, 0xea, 0x8e, 0xe9, 0x57, 0xeb, 0xc7, 0x9f, 0x09, 0xc5, 0xa7, 0xbb, 0x94, 0xf8, 0x16, - 0x82, 0x3b, 0x4b, 0xd0, 0x41, 0x54, 0x68, 0xc6, 0xf6, 0x30, 0xbf, 0x2b, 0xee, 0xe7, 0x77, 0xc5, 0xff, 0x3b, 0x7e, - 0x57, 0x3c, 0xc4, 0x18, 0x56, 0x16, 0x1a, 0x7e, 0x16, 0x8c, 0x83, 0xe8, 0x3f, 0xe7, 0x13, 0xef, 0xe5, 0xa9, 0xaf, - 0x32, 0x31, 0xbd, 0x87, 0x69, 0xf6, 0x09, 0x0a, 0xc2, 0x2a, 0xee, 0xd2, 0x93, 0x75, 0x65, 0x6f, 0xad, 0x64, 0x88, - 0x79, 0x1e, 0x60, 0x8d, 0xc2, 0xca, 0x03, 0xba, 0x47, 0xd5, 0x06, 0x71, 0x22, 0x78, 0x18, 0x33, 0x2b, 0x7d, 0xdf, - 0x6e, 0x8d, 0x0a, 0xf3, 0x41, 0x2e, 0x0a, 0xb2, 0x9b, 0x8f, 0x67, 0xe3, 0x28, 0xc4, 0x06, 0xfc, 0xc7, 0x8c, 0x55, - 0x43, 0x36, 0xdf, 0xc9, 0x48, 0xed, 0x98, 0x3c, 0x4d, 0x76, 0x49, 0xef, 0x80, 0x77, 0xc8, 0xcf, 0xeb, 0x8f, 0x61, - 0x21, 0x0d, 0xbf, 0x25, 0x2f, 0xe3, 0x22, 0xab, 0x96, 0x57, 0x59, 0x82, 0x4c, 0x17, 0xbc, 0xf8, 0x62, 0xa6, 0xcb, - 0xfb, 0x58, 0x1f, 0x30, 0x9e, 0x52, 0xbc, 0x6e, 0x88, 0xd2, 0xd7, 0x2d, 0xcf, 0x0a, 0x75, 0x79, 0x52, 0x31, 0xdb, - 0xb3, 0x12, 0x9c, 0x4e, 0xc1, 0x04, 0x5f, 0xff, 0x74, 0xbd, 0x8f, 0x01, 0x17, 0x14, 0x6a, 0x4e, 0x0b, 0xb9, 0x32, - 0x58, 0x4e, 0x16, 0xba, 0x13, 0x30, 0x43, 0xa5, 0xc0, 0x0b, 0x14, 0xfc, 0x45, 0x03, 0x23, 0xfa, 0xca, 0xfd, 0x26, - 0x03, 0x83, 0x74, 0x69, 0x4e, 0x84, 0xb1, 0xe3, 0x76, 0x8a, 0xb4, 0x15, 0xe5, 0x8c, 0xb3, 0xf7, 0xea, 0x4a, 0x01, - 0x06, 0x78, 0x9b, 0x9b, 0xe8, 0x3c, 0x41, 0xaf, 0x05, 0xa5, 0xf3, 0x06, 0xee, 0x66, 0x19, 0x19, 0xe1, 0xe2, 0xe3, - 0xca, 0x63, 0xc1, 0x3d, 0xfb, 0x85, 0x58, 0x1a, 0xcd, 0x34, 0x18, 0xb3, 0x79, 0xc1, 0x02, 0x85, 0x0a, 0x14, 0x58, - 0xce, 0xb4, 0xa5, 0x69, 0x35, 0xe4, 0xfb, 0x07, 0x68, 0x6d, 0x5a, 0x0d, 0xf8, 0xfe, 0x41, 0x1d, 0x65, 0x87, 0x90, - 0xe5, 0xc8, 0xcf, 0xa0, 0x5e, 0xd7, 0x91, 0x49, 0x31, 0xd9, 0xfd, 0xfa, 0x52, 0x7f, 0x54, 0x37, 0xe0, 0xfa, 0x01, - 0x08, 0x60, 0x03, 0x70, 0x08, 0x54, 0x83, 0xa5, 0x11, 0xc1, 0xa2, 0x4c, 0xa1, 0x7d, 0x0d, 0xbd, 0x37, 0x1a, 0xfe, - 0x0b, 0xdc, 0x45, 0xe4, 0xca, 0xff, 0x04, 0x81, 0xbf, 0xa2, 0x4c, 0x2b, 0x53, 0xfc, 0x4f, 0xb4, 0x7a, 0x85, 0x72, - 0xd6, 0xb4, 0xe6, 0x83, 0x68, 0x4d, 0x84, 0x6a, 0xc6, 0x10, 0xfc, 0x5b, 0x59, 0xa6, 0x2d, 0x55, 0x95, 0xfa, 0xd0, - 0x78, 0xad, 0x15, 0xce, 0xf2, 0x71, 0xe4, 0xbd, 0xc6, 0xd0, 0xb1, 0x89, 0xb3, 0x94, 0x53, 0xa9, 0xb3, 0x4f, 0xfb, - 0x32, 0x72, 0x80, 0xd3, 0x09, 0x1b, 0x4f, 0x93, 0x43, 0x39, 0x4d, 0x1c, 0x64, 0x7e, 0xce, 0x30, 0xb2, 0xaa, 0x01, - 0x61, 0x51, 0x36, 0x94, 0xb6, 0x00, 0x93, 0x9c, 0x10, 0x32, 0xc5, 0x50, 0x14, 0xf9, 0x48, 0xf7, 0xc3, 0x7a, 0xb3, - 0xba, 0x2f, 0xde, 0x69, 0x80, 0xd3, 0x30, 0x81, 0x40, 0xe0, 0x45, 0x7c, 0x93, 0x89, 0x4b, 0xf0, 0x18, 0x1e, 0xc0, - 0x97, 0xe0, 0x26, 0x97, 0xb2, 0xdf, 0xab, 0x30, 0xc7, 0xb5, 0x05, 0x0c, 0x1a, 0xac, 0x1e, 0x44, 0x87, 0x4b, 0x69, - 0xb3, 0xab, 0x00, 0xb1, 0x31, 0x85, 0x58, 0x16, 0x6c, 0x6d, 0xd9, 0xb3, 0xef, 0x55, 0xd3, 0xd0, 0x3a, 0xe1, 0x58, - 0x5c, 0xe6, 0x10, 0x45, 0x65, 0x10, 0x83, 0x3b, 0x92, 0xc7, 0xe7, 0x3d, 0x12, 0xe1, 0x05, 0x01, 0xb7, 0xb2, 0x58, - 0x86, 0x2b, 0xba, 0x1c, 0xdd, 0xd2, 0xf5, 0xe8, 0x86, 0x8e, 0xe9, 0xe4, 0xef, 0x63, 0xb0, 0xc8, 0xd6, 0xa9, 0x77, - 0x74, 0x3d, 0x5a, 0xd2, 0x6f, 0xc7, 0xf4, 0xe0, 0x6f, 0x60, 0xc2, 0x87, 0x87, 0x09, 0xbd, 0x00, 0xc7, 0x2e, 0x52, - 0xa3, 0xa7, 0xa6, 0x6f, 0x70, 0x58, 0x8d, 0xf2, 0x21, 0x1f, 0xe5, 0x94, 0x8f, 0x8a, 0x61, 0x35, 0x02, 0x4f, 0xc7, - 0x6a, 0xc8, 0x47, 0x15, 0xe5, 0xa3, 0xf3, 0x61, 0x35, 0x3a, 0x27, 0xcd, 0xa6, 0xbf, 0xae, 0xf8, 0x55, 0xc9, 0x52, - 0xd8, 0x16, 0xb0, 0x7c, 0x3d, 0xaf, 0xa8, 0xd4, 0x5f, 0xd5, 0xe6, 0x64, 0xb6, 0x9c, 0xbd, 0xbd, 0xee, 0x72, 0x62, - 0xf1, 0xb8, 0x6d, 0x3a, 0x5c, 0x7d, 0x39, 0x51, 0x27, 0xbd, 0x42, 0x7e, 0x18, 0x4f, 0x85, 0x3a, 0x87, 0xc0, 0x4c, - 0x62, 0x16, 0xc6, 0x0c, 0x9b, 0xa9, 0xd3, 0x40, 0x81, 0x93, 0x8d, 0x3c, 0x17, 0xc5, 0x6c, 0x94, 0x53, 0x78, 0x1f, - 0x13, 0x12, 0x09, 0x38, 0xab, 0x8e, 0xaa, 0x51, 0x01, 0x31, 0x47, 0x58, 0x88, 0x8f, 0xd0, 0x2f, 0xf5, 0x91, 0x87, - 0x04, 0x9e, 0x61, 0x5f, 0x8b, 0x41, 0x0c, 0x47, 0xbc, 0xad, 0xac, 0x9a, 0x85, 0x09, 0x54, 0x56, 0x0d, 0x4b, 0x53, - 0x59, 0x41, 0xb3, 0x51, 0xe5, 0x57, 0x56, 0xe1, 0x18, 0x25, 0x84, 0x44, 0xa5, 0xae, 0x0c, 0xd4, 0x27, 0x09, 0x0b, - 0x4b, 0x5d, 0xd9, 0xb9, 0xfa, 0xe8, 0xdc, 0xaf, 0xec, 0x1c, 0x5c, 0x48, 0x07, 0x89, 0x7f, 0x95, 0xca, 0xd3, 0xf6, - 0x75, 0xb0, 0xb1, 0xaa, 0xe8, 0x86, 0xdf, 0x56, 0x45, 0x1c, 0x95, 0xd4, 0xc5, 0x80, 0xc6, 0x85, 0x11, 0x49, 0xaa, - 0xd7, 0x28, 0xf8, 0x43, 0x82, 0xa8, 0x34, 0x06, 0xaf, 0xce, 0xa4, 0x6b, 0xa5, 0x56, 0x54, 0x0c, 0xca, 0x41, 0x01, - 0xf7, 0xa7, 0xbc, 0xb5, 0x90, 0xbe, 0x87, 0x88, 0xca, 0x50, 0xde, 0xe0, 0x1f, 0x18, 0x3c, 0x99, 0xad, 0xd2, 0x30, - 0x19, 0xdd, 0xd1, 0x78, 0xb4, 0x44, 0x38, 0x18, 0xb6, 0x4e, 0x15, 0xde, 0xfa, 0x05, 0xa4, 0xdf, 0xd2, 0x78, 0x74, - 0x43, 0x53, 0x6b, 0x73, 0x6a, 0xa0, 0xae, 0x7a, 0x63, 0x7a, 0x1b, 0xc1, 0xeb, 0xbb, 0x68, 0x49, 0x61, 0x2b, 0x1d, - 0xe7, 0xd9, 0xa5, 0x88, 0x52, 0x8a, 0x08, 0x84, 0x6b, 0x44, 0x0e, 0x5c, 0x6a, 0xb4, 0xc1, 0xf5, 0x00, 0xca, 0xd0, - 0x70, 0x81, 0xcb, 0x41, 0x3c, 0x5a, 0x7a, 0x64, 0x6a, 0xa9, 0x2f, 0xb2, 0x08, 0x1f, 0xed, 0x6c, 0xb4, 0x14, 0xcf, - 0x88, 0x85, 0x71, 0x05, 0x43, 0xa8, 0x0b, 0x2b, 0x4d, 0x41, 0xd2, 0x05, 0x8e, 0xec, 0x85, 0x45, 0x15, 0x6e, 0xc0, - 0xb4, 0xe8, 0x0e, 0xcc, 0xa3, 0x40, 0xe1, 0xe0, 0x12, 0xa4, 0x9f, 0x50, 0xb6, 0x73, 0x94, 0x26, 0x87, 0x37, 0x41, - 0xe9, 0xce, 0x04, 0x21, 0xed, 0xea, 0x26, 0x5b, 0xd2, 0x37, 0xd8, 0xde, 0xa1, 0x53, 0x51, 0x41, 0xf5, 0xb9, 0x05, - 0x93, 0x25, 0x1b, 0x84, 0x2d, 0x61, 0x7a, 0xa6, 0xd7, 0x80, 0x3d, 0xbd, 0x7f, 0xb0, 0x33, 0xdf, 0xc5, 0xec, 0xd3, - 0x7e, 0x19, 0x8d, 0x95, 0x05, 0x6f, 0x6e, 0x89, 0xdd, 0x92, 0x8d, 0xa7, 0xcb, 0xc3, 0x72, 0xba, 0x44, 0x62, 0x67, - 0xe8, 0x16, 0xe3, 0xf3, 0xe5, 0x82, 0x26, 0x78, 0xb6, 0xb1, 0x6a, 0xbe, 0x34, 0x68, 0x29, 0x29, 0xc3, 0xf5, 0xb6, - 0x44, 0xff, 0x7f, 0x75, 0xf1, 0x4b, 0x01, 0x5e, 0x82, 0xb1, 0x00, 0x10, 0xee, 0xc1, 0xb4, 0x20, 0xb5, 0x51, 0x36, - 0x96, 0x69, 0x98, 0xe2, 0x22, 0x30, 0x29, 0xfd, 0x7e, 0x98, 0xb3, 0x94, 0x78, 0xd0, 0xa1, 0xee, 0xd4, 0x4e, 0x7d, - 0x21, 0x08, 0xf0, 0x48, 0xea, 0x1c, 0x9b, 0xfc, 0x7d, 0x3c, 0x0b, 0xd4, 0x40, 0x04, 0x51, 0x76, 0x88, 0x8f, 0x18, - 0xb8, 0x28, 0xd2, 0x71, 0x3b, 0x5d, 0x11, 0x17, 0xbb, 0xc7, 0x2c, 0xc4, 0x49, 0xc2, 0x5c, 0xb3, 0x6c, 0xc8, 0xaa, - 0x08, 0x13, 0x74, 0x61, 0x60, 0x96, 0x37, 0x64, 0xd5, 0xfe, 0x01, 0x44, 0x6a, 0xb5, 0x65, 0xac, 0xba, 0xca, 0xf8, - 0x16, 0x80, 0xac, 0x19, 0x63, 0x07, 0x7f, 0x1b, 0xcf, 0xd4, 0x37, 0x51, 0xc8, 0x8f, 0x0e, 0xfe, 0x06, 0xc9, 0x87, - 0xdf, 0x22, 0x33, 0x07, 0xc9, 0x8d, 0x82, 0x2e, 0x9b, 0xb3, 0xae, 0xa1, 0x34, 0x71, 0xed, 0x95, 0x7a, 0xed, 0x49, - 0xb3, 0xf6, 0x0a, 0x74, 0xa7, 0x36, 0xbc, 0x87, 0xb2, 0x9d, 0x05, 0x13, 0x74, 0x34, 0xbb, 0x03, 0x1d, 0xbc, 0x53, - 0x04, 0xbd, 0x4c, 0x42, 0xe3, 0x11, 0xaa, 0x8c, 0x7a, 0x61, 0x47, 0x76, 0xb3, 0x2e, 0x99, 0x67, 0xc0, 0x1c, 0xdb, - 0x73, 0x48, 0x0c, 0x73, 0x75, 0x50, 0xa7, 0xac, 0x1c, 0xe6, 0x78, 0x00, 0xaf, 0x99, 0x1c, 0x8a, 0x41, 0xae, 0x51, - 0xbe, 0x2f, 0x58, 0x31, 0x2c, 0x07, 0xb9, 0xe6, 0x66, 0xa6, 0xcd, 0xd8, 0xb4, 0x89, 0x0e, 0xcf, 0xbc, 0x62, 0x47, - 0xab, 0x1e, 0xf0, 0xb1, 0xe0, 0xc9, 0xec, 0x7b, 0x3e, 0xbe, 0x01, 0x4e, 0x66, 0x73, 0x1b, 0x2d, 0xe9, 0x5d, 0x94, - 0xd2, 0x9b, 0x68, 0x4d, 0x97, 0xd1, 0x85, 0x31, 0x31, 0x4e, 0x6a, 0x38, 0x07, 0xa0, 0x55, 0x00, 0x89, 0xa7, 0x7e, - 0xbd, 0xe7, 0x49, 0x15, 0x2e, 0x69, 0x0a, 0x6e, 0xc3, 0xbe, 0x7d, 0xe6, 0x95, 0x2f, 0x91, 0xda, 0x20, 0xc6, 0x9a, - 0x35, 0x54, 0xdc, 0x78, 0xeb, 0x3e, 0x12, 0x35, 0xec, 0x5c, 0x17, 0x9b, 0xa8, 0x1a, 0x4e, 0xa6, 0x25, 0x20, 0xb6, - 0x96, 0xc3, 0xa1, 0x3b, 0x42, 0x76, 0x8f, 0x1f, 0x1d, 0xe8, 0xb9, 0x27, 0x2d, 0xb6, 0x6d, 0xcb, 0x1f, 0x18, 0xc2, - 0x94, 0x7e, 0xfe, 0xc8, 0x07, 0xc4, 0x8a, 0x4b, 0x38, 0x1b, 0x81, 0x3a, 0x5a, 0xa1, 0xd3, 0xef, 0x55, 0x58, 0xe8, - 0x03, 0x7c, 0x73, 0x1b, 0x25, 0xf4, 0x2e, 0xca, 0x3d, 0xb2, 0xb6, 0xac, 0x99, 0x9c, 0x9e, 0x65, 0x21, 0x6f, 0x1f, - 0xe8, 0xe5, 0x02, 0x40, 0xb4, 0x06, 0xb1, 0x2f, 0x75, 0x3d, 0x00, 0xa7, 0x21, 0x34, 0x09, 0x8d, 0xe0, 0xaa, 0x82, - 0x30, 0x02, 0xae, 0x24, 0xfc, 0x0d, 0x26, 0x2a, 0xf0, 0x05, 0xb8, 0xc8, 0xa4, 0x69, 0xce, 0x83, 0xda, 0x1f, 0xc9, - 0xd3, 0xa2, 0xed, 0xed, 0x0a, 0xa3, 0x09, 0xc6, 0x9e, 0x68, 0x9f, 0x47, 0xca, 0x51, 0x5c, 0x24, 0x61, 0x36, 0xba, - 0x55, 0xe7, 0x39, 0xcd, 0x46, 0x77, 0xfa, 0x57, 0x45, 0xc7, 0xf4, 0x3b, 0x1d, 0xd0, 0x46, 0x49, 0xdf, 0x3a, 0xce, - 0x06, 0xb4, 0x5e, 0x2c, 0x8d, 0xff, 0xb5, 0x1c, 0xdd, 0x52, 0x39, 0xba, 0xf3, 0x2d, 0xa9, 0x26, 0xd3, 0xe2, 0x50, - 0xa0, 0x21, 0x55, 0xe7, 0xf7, 0x05, 0xf0, 0x73, 0xa5, 0xf1, 0x9d, 0x36, 0xdf, 0x7b, 0xed, 0x3f, 0xef, 0xe4, 0x09, - 0x14, 0x4b, 0x54, 0xb0, 0x6a, 0x04, 0x76, 0xec, 0xeb, 0x3c, 0x2e, 0xcc, 0x28, 0xc5, 0xd4, 0x9a, 0xf4, 0x63, 0xe0, - 0x8a, 0x69, 0xaf, 0x00, 0x57, 0xcb, 0xed, 0x56, 0xc5, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, - 0x36, 0xdc, 0x03, 0x62, 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, - 0x9d, 0xc7, 0x43, 0x9f, 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, - 0x3c, 0xd7, 0x5f, 0x69, 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, - 0x6e, 0x94, 0x79, 0x24, 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, - 0x3d, 0xf2, 0xa0, 0x9c, 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, - 0x12, 0x73, 0x27, 0x51, 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, - 0x13, 0x57, 0xe1, 0x5a, 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, - 0x1a, 0x56, 0x9a, 0x80, 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, - 0xb9, 0xad, 0x74, 0xc6, 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, - 0x02, 0x33, 0x57, 0x72, 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, - 0x5a, 0x62, 0x42, 0xb4, 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, - 0xda, 0x55, 0x20, 0xb4, 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, - 0xb2, 0x69, 0xc8, 0x5c, 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, - 0x2d, 0x3f, 0x82, 0x17, 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, - 0xb9, 0xdd, 0x96, 0x68, 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, - 0x2b, 0xd0, 0xf7, 0xf8, 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, - 0xfc, 0x4a, 0x76, 0xd6, 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, - 0x2d, 0x85, 0x05, 0xc7, 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, - 0xb2, 0x33, 0xd7, 0x07, 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, - 0xe1, 0xce, 0x3c, 0x6a, 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, - 0xf7, 0x7d, 0x58, 0x3d, 0xe6, 0x83, 0x5f, 0x70, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, - 0x53, 0xbe, 0xd0, 0xad, 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, - 0x18, 0xd7, 0xc0, 0x6d, 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, - 0x31, 0xf7, 0xa5, 0x6b, 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, - 0xe7, 0x91, 0xf9, 0x62, 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, - 0x43, 0x2f, 0x03, 0x17, 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, - 0xa8, 0x10, 0xac, 0xeb, 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x63, 0x20, - 0x9c, 0x5b, 0xa2, 0x67, 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, - 0x5f, 0xf0, 0x5a, 0x0a, 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, - 0x8a, 0xde, 0xbf, 0xe6, 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, - 0x4a, 0x50, 0xc9, 0x5a, 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, - 0x7c, 0x8e, 0x7e, 0x98, 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, - 0xc6, 0xf0, 0x60, 0x36, 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, - 0x7d, 0x89, 0x36, 0xaf, 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, - 0xab, 0x96, 0x8a, 0x06, 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, - 0x59, 0xda, 0xa6, 0xe8, 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, - 0x51, 0x6a, 0x37, 0x48, 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, - 0x1d, 0x47, 0x43, 0xbf, 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, - 0x4b, 0x9a, 0xc2, 0x31, 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, - 0x4d, 0x89, 0xd6, 0xac, 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, - 0xe9, 0xb9, 0x6e, 0xe7, 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, - 0xf5, 0x98, 0x15, 0xc3, 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, - 0xb4, 0x0b, 0xa4, 0x6d, 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, - 0xd8, 0x88, 0x7a, 0x7c, 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, - 0x5a, 0xb5, 0xb9, 0xfb, 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, - 0x5a, 0xb0, 0x9c, 0x75, 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, - 0x92, 0x67, 0x9a, 0xfe, 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, - 0x12, 0x57, 0xbe, 0xc2, 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, - 0x6e, 0x92, 0x1b, 0x8e, 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, - 0x28, 0x73, 0x13, 0x73, 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, - 0x3a, 0xd1, 0x5c, 0x86, 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, - 0xdc, 0xcc, 0x52, 0xb3, 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, - 0x2c, 0x0d, 0xd7, 0x28, 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, - 0x90, 0x8d, 0xd2, 0x38, 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, - 0x15, 0xdd, 0x96, 0x98, 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0xc5, 0xd0, 0xde, 0x1d, - 0x81, 0x51, 0xe5, 0x04, 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, - 0x24, 0x10, 0x18, 0x15, 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, - 0xb7, 0x88, 0x8e, 0xe9, 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, - 0x9e, 0xba, 0x14, 0xfd, 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, - 0xb2, 0x2a, 0x07, 0xed, 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, - 0x6f, 0xc4, 0xa8, 0xbd, 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, - 0x9f, 0x39, 0xb2, 0x33, 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, - 0xda, 0xcf, 0x9d, 0xe9, 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, - 0x35, 0xd5, 0xd1, 0x01, 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, - 0x53, 0x5b, 0x55, 0xc1, 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, - 0xa7, 0xa6, 0x3f, 0x68, 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, - 0x57, 0x95, 0x0f, 0xa0, 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, - 0x58, 0x4f, 0xe4, 0x79, 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, - 0x68, 0x2e, 0xa3, 0x09, 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, - 0x15, 0xdf, 0xc9, 0xf4, 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, - 0x73, 0xf0, 0xb4, 0xa6, 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, - 0xf9, 0x47, 0x97, 0x69, 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, - 0xa2, 0x0e, 0xbe, 0x39, 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, - 0x71, 0x7f, 0xfb, 0xfb, 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, - 0x7f, 0xab, 0x6b, 0xfa, 0x2b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, - 0x06, 0x90, 0x4b, 0xab, 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, - 0xe3, 0xac, 0x02, 0x38, 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x07, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, - 0x46, 0x45, 0x06, 0x3a, 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, - 0xc1, 0x44, 0x58, 0x10, 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, - 0x10, 0x44, 0x77, 0x91, 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, - 0x10, 0x14, 0xff, 0x86, 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, - 0x82, 0x06, 0xba, 0xed, 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, - 0xf5, 0x5f, 0x0d, 0xeb, 0xe8, 0xc2, 0x8f, 0xfe, 0x6a, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, - 0x0c, 0xa4, 0x8b, 0xe3, 0x76, 0x9c, 0xcd, 0x7f, 0x9d, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, - 0xd2, 0xce, 0x07, 0x6f, 0x8e, 0x7f, 0x3f, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, - 0x0a, 0xee, 0xae, 0xe6, 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, - 0x40, 0x0e, 0x99, 0x85, 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, - 0x6f, 0xb9, 0x0d, 0xb2, 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, - 0xce, 0xe6, 0xc5, 0xc2, 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, - 0xa6, 0x51, 0x85, 0x6b, 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, - 0x03, 0x3a, 0x98, 0x50, 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x75, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, - 0x54, 0x5e, 0xc9, 0x6b, 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, - 0x93, 0x4b, 0x88, 0xa6, 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, - 0x7c, 0x2e, 0x16, 0x11, 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, - 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, - 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, - 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, - 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, - 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, - 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, - 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, - 0xb3, 0x5c, 0x1d, 0x7a, 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, - 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, 0x42, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, - 0x91, 0x9e, 0x67, 0x9f, 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, - 0x3f, 0x57, 0x1c, 0xaf, 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, - 0x97, 0x3c, 0xac, 0x46, 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, - 0xff, 0x0a, 0x99, 0x8c, 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, - 0x93, 0x66, 0xa1, 0x4c, 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, - 0xf7, 0xd0, 0xe1, 0xff, 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, - 0x7d, 0x33, 0xf1, 0x0b, 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, - 0xc3, 0x76, 0x8b, 0x0b, 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, - 0x67, 0x6a, 0x98, 0x93, 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, - 0xd0, 0x5e, 0xec, 0x67, 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, - 0x1e, 0x83, 0xf7, 0x06, 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, - 0xb7, 0x95, 0xf1, 0xb7, 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, - 0x5a, 0x60, 0xf8, 0xec, 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, - 0xac, 0x01, 0x88, 0xe4, 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, - 0xeb, 0x60, 0xe2, 0x4c, 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, - 0xa9, 0x42, 0xa9, 0x36, 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, - 0x67, 0xf7, 0xb9, 0xed, 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, - 0x15, 0x63, 0x8c, 0xde, 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, - 0xc5, 0xf5, 0xf2, 0x4b, 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, - 0x5d, 0x69, 0x64, 0x20, 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, - 0x6d, 0x09, 0x1d, 0xb2, 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, - 0x0b, 0x67, 0x59, 0x1c, 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, - 0x81, 0xdd, 0xc9, 0xe9, 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, - 0x42, 0x9b, 0xeb, 0xfa, 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, - 0xfa, 0x40, 0x39, 0x96, 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, - 0xb1, 0x00, 0x58, 0xe8, 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, - 0xee, 0x8a, 0x65, 0x58, 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, - 0x6a, 0x0c, 0x20, 0x72, 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, - 0x5e, 0x4f, 0x4a, 0x02, 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, - 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, - 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, - 0xfb, 0xbf, 0x99, 0x2c, 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, - 0x82, 0xc0, 0x70, 0xc3, 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, - 0x1a, 0x33, 0x3a, 0x78, 0x06, 0xa0, 0xb0, 0x10, 0x10, 0x7d, 0x0c, 0x32, 0x5a, 0x01, 0xbf, 0x85, 0xfa, 0xdd, 0x3a, - 0xf1, 0x7d, 0xe8, 0x57, 0x41, 0x2f, 0x62, 0x60, 0x38, 0xa2, 0xc9, 0x7e, 0xc8, 0x07, 0x93, 0x01, 0x68, 0x4b, 0xbc, - 0xdd, 0xd7, 0xd2, 0x8a, 0x9b, 0xd3, 0xa5, 0xd3, 0xfd, 0x93, 0x36, 0x41, 0x12, 0xa9, 0x64, 0xa5, 0x22, 0x06, 0x10, - 0xca, 0x52, 0x6d, 0x93, 0x25, 0x58, 0x56, 0x98, 0x25, 0xcd, 0x0d, 0x4a, 0xe2, 0xee, 0x66, 0xe0, 0x18, 0x35, 0xeb, - 0x38, 0x2c, 0x5b, 0x6e, 0xd4, 0x00, 0x9f, 0x93, 0xb0, 0xc2, 0xde, 0x70, 0x66, 0xd2, 0x3b, 0xd3, 0xe1, 0xea, 0x98, - 0xb3, 0x37, 0x1c, 0xc1, 0x38, 0x12, 0xbc, 0xf1, 0xd0, 0x25, 0xd3, 0x50, 0x91, 0x29, 0xe3, 0x60, 0xda, 0x03, 0xdc, - 0x7b, 0x0e, 0xc6, 0x61, 0x6c, 0x50, 0x59, 0x52, 0x9f, 0x7a, 0x77, 0x21, 0x10, 0xa4, 0xb5, 0x5e, 0xe6, 0x33, 0x3c, - 0x3d, 0x23, 0x94, 0xfd, 0x21, 0x87, 0x2f, 0xc0, 0x8e, 0x82, 0x1c, 0x4d, 0xf8, 0xb3, 0xc7, 0xbb, 0x81, 0xaa, 0xf8, - 0x20, 0xd8, 0x8b, 0x45, 0xba, 0x17, 0x0c, 0x04, 0xfc, 0x2a, 0xf8, 0x5e, 0x25, 0xe5, 0xde, 0x45, 0x5c, 0xec, 0xc5, - 0xab, 0xb8, 0xa8, 0xf6, 0x6e, 0xb2, 0x6a, 0xb9, 0x67, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x7b, 0xc1, - 0xa0, 0x30, 0x53, 0xbb, 0x62, 0x65, 0xe3, 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, - 0xea, 0x9a, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, 0x88, 0xe9, 0x1a, 0xfa, 0x00, 0x3c, 0xf2, 0x9a, 0xc6, 0xb0, 0x04, 0x2e, - 0x06, 0x03, 0xb2, 0x86, 0xc8, 0x05, 0x6b, 0x6a, 0x83, 0x38, 0x84, 0x6b, 0x65, 0xa7, 0xbd, 0x0b, 0xcc, 0xb4, 0xdd, - 0x02, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, 0x1b, 0xea, 0x5f, 0xb0, 0x97, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, - 0xe6, 0xfb, 0x92, 0x1d, 0x0d, 0x54, 0xc4, 0xe1, 0x1d, 0x47, 0x8a, 0x36, 0x2a, 0x97, 0x65, 0x4f, 0x96, 0x0d, 0x5f, - 0x89, 0x2b, 0xee, 0xfc, 0xb8, 0x2a, 0x29, 0xf3, 0x2a, 0x5b, 0x29, 0xf6, 0x6f, 0xc6, 0x35, 0xf7, 0x07, 0xd6, 0x9f, - 0xcd, 0x57, 0x70, 0x6d, 0xf5, 0xde, 0x35, 0xb9, 0x46, 0xe4, 0x2c, 0xa1, 0x5c, 0x52, 0xdb, 0x3c, 0xbc, 0xa5, 0xef, - 0xf3, 0xab, 0x6f, 0x33, 0x9d, 0xc6, 0x67, 0x15, 0x16, 0x2e, 0x44, 0x2b, 0x82, 0x43, 0x43, 0x2e, 0x9a, 0x47, 0x80, - 0xb9, 0xf6, 0xd9, 0x0a, 0x0a, 0x52, 0x9f, 0x55, 0xe8, 0xdd, 0x0a, 0x09, 0xaf, 0x34, 0xbb, 0xf4, 0x30, 0x90, 0x32, - 0x6e, 0x0f, 0x2d, 0x61, 0xd2, 0xf2, 0x22, 0xbc, 0xf7, 0x9a, 0x9b, 0xdc, 0x8b, 0x10, 0xa3, 0x17, 0x79, 0x76, 0x02, - 0xc6, 0xba, 0x4b, 0x76, 0x36, 0x3c, 0xf1, 0x1b, 0x9e, 0xb3, 0x16, 0x8d, 0xa6, 0x4b, 0x96, 0xf4, 0xfb, 0x31, 0x98, - 0x78, 0xa7, 0x2c, 0x87, 0x5f, 0xf9, 0x82, 0xae, 0x19, 0x60, 0x8a, 0xd1, 0x0b, 0x48, 0x48, 0x11, 0x89, 0x64, 0xad, - 0x4e, 0x92, 0xcf, 0x74, 0x17, 0x80, 0xd1, 0x2f, 0x66, 0x69, 0xb4, 0xbc, 0xd7, 0xcc, 0x02, 0xc9, 0x33, 0xf4, 0x5d, - 0x07, 0xdb, 0x1b, 0xfb, 0x20, 0xe5, 0xfc, 0x50, 0x4c, 0x07, 0x03, 0x4e, 0x34, 0xdc, 0x78, 0xa9, 0xc4, 0xb5, 0xba, - 0xc5, 0x1d, 0xc3, 0x58, 0xea, 0xdb, 0x22, 0x06, 0x07, 0xec, 0xa2, 0x95, 0xdd, 0x3e, 0xc0, 0xbe, 0x72, 0xbc, 0x4b, - 0x95, 0xdd, 0xe9, 0x31, 0xd3, 0x5c, 0xb6, 0x9a, 0x74, 0x52, 0x71, 0x3f, 0x91, 0x6f, 0x72, 0x07, 0x5d, 0x2e, 0xc7, - 0x9a, 0xb7, 0x1c, 0x80, 0x8a, 0x7e, 0xa4, 0xa8, 0xee, 0x17, 0x38, 0xc2, 0x3c, 0x58, 0xb7, 0xf9, 0x64, 0xdf, 0x14, - 0x38, 0x44, 0x9e, 0xb4, 0xd1, 0x14, 0xd0, 0xbd, 0x8b, 0xc7, 0x5d, 0xfd, 0xb6, 0x74, 0x17, 0x28, 0xd1, 0x4e, 0xc5, - 0x0d, 0x3f, 0x26, 0xea, 0x74, 0xa6, 0x0d, 0xa1, 0x7f, 0x65, 0xc4, 0xfd, 0xa5, 0x71, 0x15, 0x6f, 0x7a, 0x97, 0xcf, - 0x38, 0xd4, 0xd9, 0x0d, 0xa1, 0x00, 0x5c, 0xb5, 0xa7, 0x53, 0x37, 0x86, 0xf4, 0x4a, 0x89, 0x6e, 0x83, 0x83, 0xdd, - 0xeb, 0x33, 0x8e, 0xa2, 0x1f, 0xa3, 0x46, 0xbe, 0x89, 0xc4, 0x63, 0x39, 0x88, 0x1f, 0x17, 0x74, 0x19, 0x89, 0xc7, - 0xc5, 0x20, 0x7e, 0x2c, 0xeb, 0x7a, 0xf7, 0x5c, 0xb9, 0xbf, 0x8f, 0xc8, 0xb3, 0xee, 0xec, 0xa5, 0x12, 0x36, 0x06, - 0x9e, 0x5d, 0x0b, 0x08, 0xa7, 0xe0, 0x89, 0x6c, 0x2d, 0x7d, 0xe8, 0xdc, 0xee, 0x63, 0xcb, 0x24, 0x41, 0xd0, 0xf3, - 0x36, 0x9b, 0x44, 0xb1, 0xb3, 0xcd, 0xa3, 0x0f, 0xa7, 0x40, 0x42, 0xb7, 0xdb, 0x66, 0x5d, 0xad, 0x01, 0xc5, 0x34, - 0x1c, 0xf3, 0xfd, 0x62, 0x74, 0xe3, 0xbb, 0xeb, 0xef, 0x17, 0xa3, 0x25, 0x19, 0x4e, 0xcc, 0xe4, 0xc7, 0x47, 0xe3, - 0x59, 0x1c, 0x4d, 0xea, 0x8e, 0xd3, 0x42, 0xe3, 0x9f, 0x7a, 0xb7, 0x50, 0x04, 0x4e, 0xc5, 0x08, 0x8e, 0x9c, 0x0a, - 0xe5, 0xa4, 0xd4, 0xc0, 0xf0, 0xdf, 0xab, 0x76, 0xb4, 0x69, 0x6f, 0xe2, 0x2a, 0x59, 0x66, 0xe2, 0x52, 0x87, 0x0f, - 0xd7, 0xd1, 0xc5, 0x6d, 0x40, 0x3b, 0xef, 0x32, 0xed, 0xf8, 0x75, 0xd2, 0xa0, 0x27, 0xae, 0x66, 0x06, 0xdc, 0xba, - 0x1f, 0xa1, 0x19, 0x02, 0xa3, 0xe5, 0xf9, 0x3b, 0xc4, 0xdc, 0xfe, 0x4d, 0xd9, 0xfc, 0x2a, 0xda, 0xe7, 0xc8, 0x48, - 0xd9, 0x26, 0x23, 0x15, 0x18, 0x61, 0x4a, 0x91, 0xc4, 0x55, 0x08, 0x81, 0xec, 0xbf, 0xa4, 0xb8, 0x16, 0x4b, 0xef, - 0x35, 0x08, 0x13, 0x6c, 0x17, 0xb4, 0x5f, 0xdd, 0xce, 0x6d, 0xa5, 0xc5, 0x1e, 0xa9, 0xef, 0x73, 0x67, 0xbb, 0xa2, - 0xc9, 0xdf, 0x97, 0x0d, 0x68, 0x03, 0x88, 0xf2, 0xbe, 0x3e, 0x2a, 0x81, 0x93, 0x11, 0x37, 0x94, 0x18, 0xbd, 0xa0, - 0xab, 0x13, 0xb9, 0x67, 0xa7, 0xe6, 0x4d, 0xc5, 0x4c, 0xc5, 0x95, 0x6f, 0xf6, 0xcc, 0x7f, 0x30, 0x14, 0x54, 0x80, - 0x81, 0xb7, 0x39, 0xe3, 0xd1, 0x81, 0xee, 0xc6, 0xe8, 0xb4, 0x60, 0xb3, 0xa0, 0x2e, 0xeb, 0xa6, 0x8d, 0x07, 0x8d, - 0x38, 0x28, 0x8a, 0x55, 0xa1, 0x46, 0xc2, 0x13, 0x81, 0x80, 0x29, 0xbb, 0xe2, 0x91, 0x11, 0xd4, 0xf4, 0x26, 0x14, - 0x36, 0x14, 0xfc, 0x55, 0xa2, 0x9a, 0xde, 0x84, 0x36, 0x99, 0x38, 0xcd, 0x20, 0x82, 0x19, 0xb1, 0xdd, 0x6f, 0x01, - 0x6d, 0x6e, 0xcd, 0x68, 0x53, 0xd7, 0x56, 0x5b, 0x85, 0x5c, 0x52, 0xa4, 0x2c, 0xff, 0x9d, 0x9a, 0x0a, 0x4a, 0x6a, - 0xb9, 0xe8, 0x4d, 0x9a, 0x2e, 0x7a, 0x3c, 0x33, 0x92, 0x40, 0xe5, 0x96, 0x3b, 0x46, 0x7f, 0x08, 0x0b, 0x3c, 0x62, - 0xe2, 0xc4, 0x82, 0xb9, 0xd5, 0x11, 0xcb, 0xe6, 0x62, 0x31, 0x5a, 0x49, 0x08, 0x1b, 0x7c, 0xc8, 0xb2, 0x79, 0xa9, - 0x1f, 0x42, 0x5f, 0x58, 0x7a, 0x02, 0x76, 0xb1, 0xc1, 0x4a, 0x96, 0x01, 0xf8, 0x5e, 0xd0, 0xcd, 0x4a, 0x96, 0x91, - 0x54, 0xdd, 0x8f, 0x6b, 0x2c, 0x41, 0xa5, 0x15, 0x2a, 0x2d, 0xa9, 0xb1, 0x20, 0xf0, 0x55, 0xd5, 0xe5, 0x43, 0xb2, - 0xab, 0x40, 0x3d, 0x75, 0xd4, 0x80, 0x53, 0xa0, 0xaa, 0xc0, 0x82, 0x24, 0xa8, 0x0c, 0x5d, 0x15, 0x98, 0x56, 0x60, - 0x9a, 0xa9, 0xc2, 0x45, 0x99, 0x1d, 0x4a, 0xb3, 0x5e, 0xf2, 0x59, 0x3c, 0x08, 0x93, 0x61, 0x4c, 0x1e, 0x23, 0xd4, - 0xfe, 0x7e, 0x1e, 0xc5, 0x5a, 0x2e, 0xb9, 0x72, 0x7e, 0xf1, 0x37, 0x9f, 0xb1, 0xd7, 0x3d, 0xc3, 0x60, 0x01, 0xce, - 0xd2, 0xf6, 0x2a, 0x13, 0xef, 0x64, 0x2b, 0x38, 0x0e, 0x66, 0x51, 0x0e, 0xab, 0x9e, 0x1c, 0xd1, 0x5c, 0xe4, 0xda, - 0xbb, 0x08, 0x91, 0x83, 0xcc, 0x1e, 0x03, 0xec, 0x46, 0xf8, 0x3a, 0xb4, 0x36, 0xb7, 0xba, 0x42, 0xfc, 0x8d, 0x12, - 0x89, 0x9f, 0xa5, 0xfc, 0xb8, 0x5e, 0xa9, 0x5c, 0x95, 0xc1, 0x63, 0xd5, 0xcd, 0xe0, 0x99, 0xf6, 0x3d, 0xd6, 0xfe, - 0xad, 0xed, 0xe6, 0x78, 0xef, 0xc1, 0x83, 0xd6, 0xff, 0xd6, 0x93, 0x10, 0xda, 0x2b, 0x27, 0xa9, 0x3b, 0x6a, 0xf4, - 0xcc, 0x64, 0x8d, 0xa8, 0x84, 0xa9, 0xdd, 0xa9, 0x1c, 0x03, 0x35, 0x1d, 0xc0, 0xb5, 0x44, 0x4d, 0xd0, 0x93, 0x82, - 0x8d, 0xe1, 0x88, 0xb3, 0x38, 0x68, 0x87, 0x31, 0x8a, 0x97, 0x73, 0x25, 0x5e, 0xce, 0x8f, 0x18, 0x07, 0x68, 0x2d, - 0x40, 0xaa, 0xd7, 0xb0, 0x9f, 0xb9, 0x82, 0x05, 0x36, 0x77, 0xbe, 0x03, 0x0b, 0x64, 0x88, 0x93, 0xcd, 0x71, 0xb2, - 0xc7, 0xb5, 0x9e, 0x7b, 0x81, 0x8f, 0x93, 0x7a, 0xe1, 0xd5, 0x55, 0xb6, 0xeb, 0x5a, 0xb2, 0x72, 0x5e, 0x0c, 0x26, - 0x10, 0x94, 0xa5, 0x9c, 0x17, 0xc3, 0xc9, 0x82, 0xe6, 0xf0, 0x63, 0xd1, 0x40, 0x87, 0x58, 0x0e, 0x12, 0xb8, 0x74, - 0xf6, 0x18, 0xf0, 0x86, 0x52, 0x8b, 0xbb, 0xb1, 0x8e, 0x1c, 0xeb, 0x28, 0xf6, 0xc3, 0x18, 0x70, 0x65, 0x9d, 0xc0, - 0xfb, 0xfe, 0xeb, 0x63, 0x13, 0x90, 0x55, 0xbb, 0xc2, 0xab, 0x51, 0xee, 0xba, 0xd2, 0xe8, 0x4b, 0x4a, 0x4f, 0x78, - 0xc1, 0x53, 0xc9, 0x76, 0xdb, 0x33, 0x70, 0xb6, 0xc4, 0x43, 0xe2, 0x1d, 0x23, 0x7a, 0x31, 0x6d, 0x64, 0xe6, 0x04, - 0xce, 0x6c, 0x77, 0xd9, 0xc6, 0xfc, 0xd8, 0x01, 0x0e, 0x16, 0x41, 0x48, 0xdc, 0x10, 0x86, 0x89, 0x1d, 0x95, 0x43, - 0x2d, 0x84, 0xeb, 0x5a, 0x78, 0x1d, 0xa7, 0x65, 0x0c, 0x2e, 0xd2, 0xda, 0x36, 0xf1, 0x1e, 0xba, 0xee, 0xf9, 0x31, - 0xb7, 0x3a, 0x46, 0x5b, 0x48, 0xbf, 0x1d, 0x9d, 0xde, 0x73, 0x18, 0x80, 0xa6, 0x07, 0xb3, 0xaa, 0x7d, 0x26, 0x71, - 0x73, 0xda, 0x09, 0x42, 0x22, 0x10, 0x45, 0xe9, 0x8c, 0x30, 0xfd, 0x3b, 0xcd, 0x65, 0x15, 0xad, 0x1e, 0xe4, 0x99, - 0x43, 0x9e, 0x85, 0xde, 0xf6, 0xa0, 0x55, 0x73, 0x37, 0x18, 0x27, 0x6e, 0xb7, 0x77, 0xfe, 0xdf, 0xb2, 0xae, 0xad, - 0xd6, 0x88, 0xc7, 0xed, 0xea, 0x07, 0x8d, 0xbd, 0xda, 0x53, 0x31, 0x60, 0x56, 0xd2, 0x3b, 0xa3, 0x4a, 0x5e, 0x64, - 0xbc, 0xc4, 0x93, 0x6a, 0xd5, 0xf0, 0xf1, 0xbe, 0xc9, 0x46, 0xe6, 0x81, 0x4c, 0x01, 0xf1, 0xfc, 0x26, 0x35, 0xea, - 0xe3, 0x14, 0x25, 0xe0, 0xef, 0x74, 0x7c, 0x23, 0xfa, 0xd1, 0xbe, 0xb8, 0xe4, 0xd5, 0xc9, 0x8d, 0x30, 0x2f, 0x5e, - 0x58, 0x9d, 0x3f, 0x7d, 0x53, 0xf8, 0xd0, 0xe1, 0xa8, 0xbd, 0x83, 0x22, 0x4b, 0x26, 0x8e, 0x26, 0x46, 0xd6, 0x26, - 0x66, 0x1f, 0x15, 0x5c, 0x4c, 0x54, 0xa1, 0x67, 0x9d, 0x3d, 0x61, 0x0a, 0xd0, 0x37, 0x8e, 0x51, 0xc9, 0x18, 0x16, - 0x0c, 0xd4, 0x69, 0x4a, 0x88, 0x1e, 0x8a, 0x19, 0xc6, 0x2b, 0x06, 0x50, 0x98, 0x42, 0x81, 0x28, 0x3a, 0xfb, 0x70, - 0xa0, 0x09, 0xfd, 0xfe, 0x4d, 0xaa, 0x33, 0xd0, 0xb2, 0x9e, 0x4a, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, - 0x2e, 0x69, 0x99, 0xd1, 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, - 0x21, 0xec, 0xff, 0x6a, 0xd0, 0xf5, 0x56, 0xac, 0x35, 0xb4, 0x3b, 0x41, 0x46, 0x68, 0xbe, 0xd0, 0x41, 0xc8, 0x50, - 0x39, 0x09, 0x5d, 0xab, 0x34, 0x5e, 0x81, 0x4b, 0xa6, 0xd9, 0x68, 0x19, 0x97, 0x61, 0x60, 0xbf, 0x0a, 0x2c, 0x26, - 0x07, 0x26, 0x9d, 0xae, 0xcf, 0x9f, 0xcb, 0xab, 0x95, 0x14, 0x5c, 0x54, 0x0a, 0xa2, 0xdf, 0xe0, 0xbe, 0x9b, 0xb8, - 0xea, 0xac, 0x59, 0x2b, 0x7d, 0xe8, 0x5b, 0x9f, 0xb5, 0x71, 0x5f, 0x18, 0x1c, 0x83, 0x9d, 0x8f, 0x88, 0x81, 0x34, - 0xa8, 0x74, 0x8b, 0x43, 0x13, 0xa0, 0x4b, 0x87, 0x14, 0xb2, 0x64, 0x2a, 0x53, 0x25, 0xa8, 0xf8, 0xc6, 0xef, 0xa5, - 0xac, 0x46, 0x7f, 0xad, 0x79, 0x71, 0x77, 0xca, 0x73, 0x8e, 0x63, 0x14, 0x24, 0xb1, 0xb8, 0x8e, 0xcb, 0x80, 0xf8, - 0x96, 0x57, 0xc1, 0x41, 0x6a, 0xc2, 0xc6, 0xec, 0x54, 0x8d, 0x5a, 0x2f, 0x89, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, - 0x13, 0x51, 0x05, 0x7d, 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, - 0x6e, 0x98, 0x08, 0x41, 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, - 0xf1, 0x39, 0x73, 0xa1, 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, - 0xd9, 0x91, 0x76, 0x69, 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, - 0x2a, 0xce, 0xc4, 0x71, 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, - 0x61, 0x30, 0x35, 0x15, 0xf7, 0xd8, 0x19, 0x5c, 0x54, 0x7f, 0x44, 0x4b, 0x89, 0xb1, 0x50, 0x75, 0xf1, 0xf1, 0x79, - 0x29, 0xf3, 0x75, 0x05, 0xda, 0xdd, 0x8b, 0x2a, 0x3a, 0x78, 0xba, 0xba, 0x9d, 0xaa, 0x1b, 0x4c, 0xf4, 0xf4, 0x60, - 0x75, 0xdb, 0xcb, 0xae, 0x56, 0xb2, 0xa8, 0x62, 0x51, 0x4d, 0x15, 0x22, 0x59, 0x12, 0xe7, 0x49, 0x38, 0x19, 0x8f, - 0xbf, 0xda, 0x1b, 0xee, 0x41, 0x06, 0x32, 0xfd, 0x34, 0x54, 0x2e, 0x47, 0xc3, 0xc9, 0x78, 0x3c, 0x95, 0xea, 0x6e, - 0x17, 0x8d, 0x26, 0x35, 0xd6, 0x33, 0x4c, 0xf4, 0xcc, 0x8c, 0xf8, 0xed, 0x2a, 0x16, 0x29, 0xc4, 0xaf, 0xd3, 0xc5, - 0x1f, 0x3c, 0x1d, 0x37, 0xca, 0xb7, 0x9f, 0x3e, 0xab, 0xff, 0xa8, 0x4d, 0x58, 0x6b, 0xd3, 0xee, 0xe7, 0x7f, 0x1c, - 0xaa, 0xf9, 0x3e, 0x3a, 0xdc, 0xd7, 0x3f, 0xfe, 0xa8, 0xeb, 0xe9, 0x9b, 0x22, 0x9c, 0xff, 0x33, 0x54, 0xf3, 0x79, - 0x5c, 0x14, 0xf1, 0x5d, 0x0d, 0x91, 0x3c, 0x85, 0xf3, 0x26, 0xa1, 0xde, 0x36, 0xa0, 0x07, 0x64, 0x7a, 0x21, 0x18, - 0x7c, 0xf3, 0xbe, 0x0a, 0x03, 0x5e, 0xae, 0x86, 0x5c, 0x54, 0x59, 0x75, 0x37, 0xc4, 0x3c, 0x01, 0x7e, 0x6a, 0x78, - 0xb3, 0xe7, 0x85, 0x21, 0x36, 0x17, 0x05, 0xe7, 0x9f, 0x78, 0xa8, 0x8c, 0xa3, 0xc7, 0x68, 0x1c, 0x3d, 0xa6, 0x6a, - 0x30, 0x26, 0xdf, 0x50, 0xdd, 0x99, 0xc9, 0x37, 0x60, 0x82, 0x94, 0xb5, 0xbf, 0x51, 0xc6, 0x89, 0xd1, 0x98, 0x5e, - 0xbf, 0xca, 0xb3, 0x15, 0x30, 0xc1, 0x4b, 0xfd, 0xa3, 0x26, 0xf4, 0x3d, 0x6f, 0x67, 0x1f, 0x8d, 0x46, 0xcf, 0x0b, - 0x3a, 0x1a, 0x8d, 0x3e, 0x66, 0x35, 0xa1, 0x2b, 0xd1, 0xf1, 0xfe, 0x3d, 0xa7, 0xe7, 0x32, 0xbd, 0x8b, 0x82, 0x80, - 0x2e, 0xb3, 0x34, 0xe5, 0x42, 0x95, 0x75, 0x9a, 0xb6, 0xf3, 0xaa, 0x16, 0x22, 0xf0, 0x8f, 0x6e, 0x23, 0x42, 0x10, - 0x11, 0x7a, 0xb2, 0xd3, 0xb3, 0xd1, 0x68, 0x74, 0x9a, 0x9a, 0x6a, 0x1d, 0x43, 0xfe, 0x06, 0xcd, 0x07, 0x9c, 0x5d, - 0x3e, 0x58, 0xdf, 0x98, 0x68, 0x27, 0xfb, 0xff, 0x3d, 0x9c, 0xcd, 0xc7, 0xc3, 0x6f, 0x47, 0x8b, 0xc7, 0xfb, 0x34, - 0x08, 0x7c, 0xd0, 0xea, 0x50, 0x5b, 0x73, 0x4c, 0xcb, 0xc3, 0xf1, 0x94, 0x94, 0x03, 0xf6, 0xd4, 0xfa, 0xd2, 0x7c, - 0xf5, 0x14, 0x90, 0x48, 0x51, 0x84, 0x1a, 0x38, 0xe9, 0x1f, 0x5e, 0x45, 0x5e, 0x0b, 0xc0, 0x47, 0xb3, 0x91, 0x0c, - 0x8c, 0x16, 0x70, 0x1c, 0x41, 0x79, 0xb5, 0x35, 0x8d, 0xe8, 0x31, 0x96, 0x99, 0xa8, 0xa0, 0xe3, 0x69, 0x79, 0x93, - 0x55, 0xc9, 0x12, 0x03, 0x1b, 0xc5, 0x25, 0x0f, 0xbe, 0x0a, 0xa2, 0x92, 0x1d, 0x3c, 0x9b, 0x2a, 0x78, 0x5f, 0x4c, - 0x4a, 0xf9, 0x25, 0x24, 0x7e, 0x3b, 0x46, 0x08, 0x54, 0xa2, 0x3d, 0x16, 0xb1, 0xc6, 0x57, 0xb9, 0x8c, 0xc1, 0x83, - 0xb3, 0xd4, 0x3c, 0x8b, 0x3d, 0x09, 0xac, 0xfd, 0x45, 0xab, 0x39, 0x12, 0x9a, 0x13, 0x4a, 0x26, 0xf7, 0x4b, 0x2a, - 0xbf, 0x9a, 0xa0, 0x57, 0x10, 0xb8, 0x55, 0x47, 0x70, 0xdc, 0x59, 0xcb, 0x06, 0xbd, 0x7c, 0x52, 0xb6, 0x3f, 0xff, - 0xdf, 0x25, 0x5d, 0x0c, 0xf6, 0xdd, 0xd0, 0x9c, 0x68, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x9e, 0x12, 0x6b, - 0x7c, 0xca, 0xd9, 0xd1, 0xc6, 0x74, 0x67, 0x54, 0x15, 0xd9, 0x55, 0x48, 0x74, 0xaf, 0x1c, 0x28, 0x66, 0x10, 0x65, - 0x23, 0x5c, 0x3f, 0x60, 0x2d, 0xe2, 0x75, 0xf2, 0x9a, 0x17, 0x55, 0x96, 0xa8, 0xf7, 0xd7, 0x8d, 0xf7, 0x40, 0x0d, - 0x54, 0x83, 0xde, 0x15, 0x0c, 0xe6, 0xf9, 0xa4, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, - 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, - 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xae, 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, - 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x93, 0x86, 0x10, - 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, 0x9e, 0xe0, 0xa9, 0x1a, 0x06, 0x17, 0x79, 0xb6, 0xd2, 0x49, 0xd5, 0xa8, - 0xa3, 0xf9, 0x50, 0x6a, 0x47, 0x72, 0x40, 0xbd, 0xf4, 0x18, 0xd3, 0x0b, 0x95, 0xae, 0x8a, 0x72, 0x46, 0x28, 0xef, - 0xf4, 0xc4, 0xb8, 0x30, 0x7d, 0x1c, 0x22, 0xbf, 0xbc, 0x2b, 0x54, 0xe8, 0x17, 0xbe, 0x00, 0xf0, 0x2b, 0xb8, 0xdd, - 0xef, 0xc6, 0x77, 0x51, 0xd9, 0xcf, 0x38, 0xdb, 0xff, 0xef, 0x79, 0x3c, 0xfc, 0x34, 0x1e, 0x7e, 0xbb, 0x18, 0x84, - 0x43, 0xfb, 0x93, 0x3c, 0x7e, 0xb4, 0x4f, 0x5f, 0x71, 0xcb, 0x95, 0xc0, 0xc2, 0x6f, 0x04, 0xb7, 0x51, 0x2b, 0x21, - 0x88, 0x02, 0xbc, 0x51, 0xb8, 0xd5, 0x38, 0x01, 0x80, 0xbf, 0xe0, 0xbf, 0x02, 0x34, 0x12, 0x72, 0x17, 0x0d, 0xd0, - 0x0f, 0xa8, 0xdf, 0x47, 0x4f, 0x1a, 0x06, 0x72, 0x20, 0x9e, 0x50, 0x31, 0x50, 0x88, 0x2e, 0x63, 0xa2, 0x60, 0x7f, - 0x6d, 0xf6, 0xed, 0xb6, 0xd7, 0x96, 0xfc, 0xe0, 0x97, 0x7e, 0xa6, 0x89, 0x99, 0x77, 0xb8, 0xa1, 0xac, 0xe4, 0x2a, - 0x44, 0x6c, 0x3c, 0xfd, 0x2b, 0x67, 0x10, 0x6b, 0xf2, 0x3a, 0x03, 0x1f, 0x06, 0xfb, 0xc5, 0x78, 0x06, 0x6c, 0x03, - 0xdc, 0x71, 0x0a, 0x7e, 0x91, 0x81, 0x5b, 0xb3, 0x88, 0xf1, 0x82, 0x6d, 0x97, 0x44, 0xbf, 0xdf, 0xcb, 0xb3, 0x30, - 0xd7, 0x38, 0xcb, 0x79, 0x6d, 0xc4, 0xee, 0xa8, 0x13, 0x06, 0x71, 0xbb, 0x1e, 0x82, 0xa1, 0x1a, 0x82, 0xa2, 0xa3, - 0x2d, 0xae, 0x5e, 0x5b, 0x4f, 0x61, 0x7a, 0xab, 0xea, 0x2b, 0x46, 0x7f, 0xca, 0x4c, 0x60, 0x21, 0xed, 0x9a, 0x63, - 0x5d, 0x73, 0x8c, 0xb4, 0xa7, 0xdf, 0x17, 0x0d, 0xf2, 0xd3, 0x59, 0x78, 0x10, 0xa8, 0x52, 0xe5, 0x4e, 0x59, 0x94, - 0xdb, 0xd2, 0xbc, 0x31, 0xac, 0x69, 0x9e, 0xd9, 0xb8, 0x2e, 0xb3, 0x5e, 0x2f, 0x0c, 0xd1, 0xa1, 0x11, 0x4b, 0xc5, - 0xda, 0x20, 0xbc, 0x8f, 0x49, 0x18, 0x5d, 0x81, 0xac, 0x2e, 0x3c, 0xe3, 0x04, 0xf9, 0x32, 0x30, 0x59, 0x53, 0xd5, - 0x7a, 0x39, 0xe1, 0xb1, 0x91, 0x2f, 0x1b, 0x41, 0x83, 0xbc, 0xa4, 0xa8, 0x37, 0x71, 0x3b, 0xf6, 0x51, 0x0b, 0xa9, - 0x71, 0x53, 0x4f, 0x7b, 0x9a, 0x54, 0xf4, 0x58, 0xaf, 0x52, 0xbf, 0xc0, 0xb2, 0xc0, 0x92, 0x0f, 0x42, 0x7b, 0x9a, - 0x56, 0x60, 0x86, 0x6b, 0x9b, 0xc1, 0xd0, 0x0f, 0x87, 0xb6, 0x08, 0x9d, 0x51, 0xdb, 0x12, 0xc2, 0xb6, 0x0d, 0xc2, - 0xca, 0x7b, 0x22, 0x5f, 0x3d, 0xf5, 0x18, 0xe1, 0x90, 0x9b, 0xcd, 0x2c, 0x1a, 0x18, 0xe6, 0x57, 0xb2, 0xd9, 0x3c, - 0xdd, 0x5c, 0x2f, 0x2a, 0xa6, 0x80, 0xed, 0xb6, 0x12, 0x04, 0xff, 0x7e, 0xcc, 0x66, 0xf8, 0x37, 0xeb, 0xf7, 0x7b, - 0x21, 0xfe, 0xe2, 0x18, 0xbc, 0x67, 0x2e, 0x16, 0xec, 0x23, 0xc8, 0x54, 0x48, 0x84, 0xa9, 0xca, 0xf8, 0x8d, 0x55, - 0x60, 0x01, 0x67, 0x3e, 0x50, 0xb9, 0x30, 0x93, 0xbd, 0xbc, 0xb8, 0x86, 0x1c, 0xb7, 0xc6, 0x29, 0x1b, 0x65, 0x89, - 0x72, 0x5d, 0xc8, 0x46, 0x71, 0x9e, 0xc5, 0x25, 0x2f, 0xb7, 0x5b, 0x7d, 0x38, 0x26, 0x05, 0x07, 0xf6, 0x54, 0x51, - 0xa9, 0x92, 0x75, 0xa4, 0xba, 0xf1, 0x97, 0x61, 0x81, 0xfb, 0x94, 0xcf, 0x0b, 0x43, 0x23, 0xf6, 0xe0, 0xf2, 0xce, - 0xd4, 0xad, 0xb4, 0x17, 0x16, 0xd0, 0xbc, 0x92, 0x90, 0x0d, 0xa6, 0x7a, 0x16, 0xad, 0x31, 0x13, 0xf3, 0x62, 0x01, - 0x61, 0x64, 0x8a, 0x05, 0xd8, 0x4c, 0x71, 0x01, 0x5e, 0x24, 0x31, 0xc0, 0xc4, 0xc5, 0x64, 0x0a, 0xf1, 0xcc, 0x55, - 0x39, 0xf1, 0xc2, 0xdc, 0x2f, 0x13, 0x87, 0x94, 0x01, 0xaf, 0x6a, 0x83, 0x26, 0x66, 0x1b, 0x8e, 0x3a, 0x41, 0x4e, - 0x4c, 0x7e, 0x3f, 0x55, 0x10, 0xe2, 0x4e, 0x1c, 0x09, 0x97, 0x15, 0xdb, 0x85, 0x97, 0x1d, 0x88, 0x31, 0x6a, 0x70, - 0xca, 0xcf, 0x0c, 0x8e, 0xc6, 0xe0, 0xdc, 0x78, 0x27, 0x48, 0x11, 0xc6, 0x64, 0x23, 0xd9, 0x95, 0x0c, 0xc5, 0x3c, - 0x5e, 0x80, 0xb2, 0x2e, 0x5e, 0x80, 0x65, 0x8d, 0x31, 0xc0, 0x04, 0x79, 0x15, 0xf7, 0x42, 0x3f, 0x51, 0x5c, 0x21, - 0xd2, 0xb3, 0x72, 0x7d, 0x54, 0xb4, 0x43, 0x5f, 0xe0, 0xf5, 0x5e, 0x99, 0xe3, 0x66, 0x3d, 0x16, 0x48, 0x6c, 0x08, - 0x18, 0x1b, 0xe9, 0x34, 0xd5, 0x5a, 0xf7, 0xc6, 0xcc, 0x03, 0x9f, 0x66, 0x23, 0x21, 0xab, 0xb3, 0x0b, 0x10, 0xa1, - 0xf8, 0x68, 0xf0, 0xc8, 0x2f, 0xe2, 0xce, 0x32, 0x6f, 0x6d, 0x8b, 0x4a, 0x76, 0xb4, 0x01, 0x90, 0x3e, 0x1d, 0x2d, - 0x4a, 0xc9, 0x29, 0x4a, 0x52, 0xbb, 0x4d, 0x01, 0x2b, 0xc9, 0x5f, 0xc0, 0x10, 0x6c, 0x6c, 0x4f, 0x38, 0x9d, 0x22, - 0xc4, 0x27, 0x9a, 0x22, 0xb2, 0x62, 0x58, 0x52, 0x1c, 0xdb, 0x12, 0x51, 0x3f, 0x6d, 0x59, 0x76, 0x30, 0x4c, 0x54, - 0xdc, 0x17, 0xa9, 0x47, 0x89, 0x82, 0x80, 0xea, 0x21, 0x07, 0x89, 0xad, 0x6d, 0x20, 0x3c, 0x20, 0x8f, 0xe8, 0x8d, - 0xf5, 0xf7, 0x59, 0xe7, 0xd9, 0x85, 0xe6, 0xa8, 0x5c, 0xef, 0x0a, 0x33, 0x46, 0x78, 0x92, 0x19, 0x98, 0x7c, 0xef, - 0x3c, 0x33, 0x6a, 0x8a, 0x9e, 0x87, 0x4f, 0x76, 0x8c, 0x11, 0xe9, 0xee, 0x19, 0x74, 0x13, 0xbc, 0xaa, 0xc3, 0x46, - 0xbb, 0x52, 0x10, 0x12, 0xa6, 0x16, 0x4d, 0xcc, 0x7a, 0xd6, 0x80, 0x7a, 0xbb, 0xed, 0xe9, 0xb9, 0xba, 0x7f, 0xee, - 0xb6, 0xdb, 0x1e, 0x76, 0xeb, 0x45, 0xda, 0x6d, 0x05, 0x5e, 0xa9, 0x0f, 0xda, 0xe3, 0xcf, 0xdd, 0xf8, 0x73, 0x83, - 0xe4, 0x51, 0x3a, 0x9a, 0x69, 0xeb, 0x83, 0x70, 0xb8, 0xe9, 0x5d, 0xa3, 0x49, 0xdf, 0x67, 0xa1, 0xa4, 0x2b, 0xd1, - 0xa8, 0xae, 0x76, 0x26, 0x95, 0x0f, 0xae, 0xff, 0x87, 0x57, 0x01, 0x1e, 0x71, 0x6a, 0x67, 0xdf, 0xdb, 0xa0, 0xa2, - 0xd1, 0x16, 0x8e, 0x14, 0xa1, 0x07, 0x24, 0xe1, 0xbe, 0x96, 0xb5, 0xb8, 0xcd, 0xd3, 0xec, 0x61, 0xfa, 0xf4, 0x3a, - 0xf5, 0xad, 0xee, 0xdd, 0x32, 0xcb, 0xcc, 0x81, 0x57, 0x51, 0x1c, 0xd0, 0xa8, 0x8b, 0xf6, 0x5d, 0x65, 0x65, 0x09, - 0x5e, 0x1e, 0x70, 0x7d, 0x3e, 0xe5, 0x3e, 0xdc, 0xdc, 0x65, 0xd5, 0xdc, 0xa4, 0xa7, 0xd9, 0x3c, 0x5b, 0x6c, 0xb7, - 0x21, 0xfe, 0xed, 0x6a, 0x91, 0xa3, 0xc9, 0x73, 0xd0, 0xe1, 0x61, 0xe4, 0x1e, 0xa6, 0x1b, 0xe7, 0x6d, 0xfe, 0x4f, - 0xa2, 0xe1, 0x24, 0x70, 0x0c, 0xf4, 0x62, 0xf6, 0x08, 0x64, 0x30, 0xc6, 0xa9, 0x5f, 0xcc, 0xf4, 0x9a, 0x81, 0xe8, - 0x5b, 0x22, 0x02, 0x1c, 0x5d, 0x6c, 0x24, 0x1a, 0x59, 0x70, 0x52, 0x13, 0xb0, 0xd8, 0xb4, 0xe5, 0x7d, 0xb0, 0xb4, - 0xad, 0x2a, 0xee, 0xbc, 0x25, 0xcd, 0x71, 0x1d, 0x38, 0xdb, 0x7e, 0x33, 0xc4, 0xa6, 0xec, 0x6a, 0x81, 0xdc, 0x2f, - 0xaf, 0x69, 0x6f, 0x5c, 0x27, 0x30, 0x6b, 0x9b, 0xda, 0x32, 0x7e, 0xb6, 0xf4, 0x9f, 0xf5, 0xe0, 0x2a, 0xe3, 0xa7, - 0xb9, 0xb1, 0x4a, 0xb0, 0xfb, 0xc6, 0xf3, 0x1d, 0x80, 0x70, 0x6c, 0x3e, 0x3d, 0x3e, 0xcd, 0x3c, 0x7a, 0x0c, 0x44, - 0xc7, 0x7c, 0x54, 0xba, 0x8f, 0xec, 0xee, 0xf5, 0x03, 0xe0, 0xcd, 0xab, 0x76, 0x41, 0xf3, 0x72, 0x01, 0x81, 0x44, - 0xbd, 0xf2, 0x0a, 0xcb, 0x67, 0xc6, 0xec, 0x12, 0xc8, 0x50, 0x41, 0xc0, 0x26, 0xa9, 0xeb, 0x5c, 0x88, 0x55, 0x87, - 0x95, 0xf9, 0x48, 0xc2, 0x8e, 0x42, 0x34, 0xe7, 0x0c, 0x66, 0xc1, 0x7f, 0x05, 0x83, 0x72, 0x10, 0x44, 0x41, 0x14, - 0x04, 0x64, 0x50, 0xc0, 0x2f, 0xc4, 0x19, 0x23, 0x18, 0xa3, 0x04, 0x3a, 0xfc, 0x8e, 0x33, 0x9f, 0x11, 0x79, 0xd9, - 0x08, 0x63, 0xe9, 0x06, 0xe0, 0x5c, 0xca, 0x9c, 0xc7, 0xe8, 0x63, 0xf1, 0x8e, 0xb3, 0x8c, 0xd0, 0x77, 0xde, 0xa9, - 0xfc, 0x88, 0x37, 0x82, 0xdb, 0xed, 0x0e, 0xdb, 0x2b, 0x1e, 0x66, 0xb4, 0x37, 0xa6, 0xef, 0x38, 0x89, 0xb2, 0x86, - 0xf3, 0x30, 0x87, 0x9e, 0x55, 0x96, 0xb5, 0xa2, 0x86, 0xdc, 0xa0, 0x58, 0x17, 0x59, 0x26, 0x27, 0xc3, 0x55, 0x73, - 0x2a, 0x70, 0xdd, 0xd9, 0xf5, 0x02, 0x92, 0x32, 0xa1, 0x59, 0x3a, 0x1b, 0xbe, 0xda, 0xb6, 0xec, 0x45, 0xeb, 0x14, - 0xf2, 0x1a, 0xa2, 0xa2, 0x1f, 0x3a, 0x02, 0x6a, 0x68, 0xc5, 0x65, 0x05, 0x2e, 0xbb, 0xa6, 0x3d, 0xdc, 0xb4, 0xc7, - 0x34, 0xe3, 0x03, 0xc4, 0x88, 0xe3, 0xd8, 0x32, 0xb0, 0x9b, 0x70, 0x78, 0x36, 0xce, 0xf7, 0x65, 0x97, 0xde, 0xba, - 0x5a, 0x3c, 0xc2, 0xda, 0xf3, 0x56, 0x48, 0x08, 0x90, 0x96, 0xa6, 0xd2, 0xed, 0x36, 0x08, 0x60, 0x80, 0xfb, 0xfd, - 0x1e, 0x70, 0xad, 0x86, 0x9d, 0x34, 0xb7, 0x66, 0x4b, 0xec, 0x15, 0x85, 0xc7, 0x40, 0x94, 0x9a, 0xff, 0x0c, 0x02, - 0x8a, 0xe7, 0x6e, 0x08, 0xf6, 0x95, 0xec, 0x68, 0x53, 0xf4, 0xfb, 0x2f, 0x0a, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, - 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, - 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x9f, 0x00, 0x16, 0x3c, 0xf3, 0x86, 0xe5, - 0xbd, 0x07, 0x00, 0xd6, 0xeb, 0xe1, 0x42, 0x71, 0x2f, 0x5f, 0x35, 0xd0, 0x27, 0xf1, 0xa5, 0x65, 0xd7, 0x67, 0x5a, - 0x56, 0x32, 0x1a, 0x8d, 0xaa, 0x5a, 0x49, 0x3e, 0x1c, 0x79, 0x69, 0xa1, 0x56, 0xca, 0x38, 0xe5, 0x29, 0x58, 0x7a, - 0x1b, 0x4a, 0x37, 0x5f, 0xd0, 0x15, 0x17, 0xa9, 0xfa, 0xe9, 0xa1, 0x4d, 0x36, 0x88, 0x6b, 0xd6, 0xd4, 0x59, 0xd8, - 0xe1, 0x87, 0x80, 0x8f, 0xf6, 0x61, 0xe6, 0xd2, 0x35, 0x2c, 0x2d, 0x88, 0x23, 0xe3, 0x82, 0x87, 0x2e, 0x0f, 0x60, - 0xfd, 0x99, 0x43, 0x12, 0x3f, 0x85, 0x9f, 0x33, 0x93, 0xd6, 0xf1, 0x19, 0xce, 0x66, 0x54, 0xaa, 0x1b, 0x41, 0xfb, - 0x35, 0x24, 0x12, 0x83, 0x6c, 0xdc, 0x60, 0x28, 0x5a, 0x77, 0x1b, 0xb8, 0xf2, 0x5b, 0x7a, 0xe7, 0xd3, 0x20, 0xc0, - 0xb6, 0xc6, 0x62, 0x00, 0x30, 0x14, 0x7f, 0xa0, 0xaa, 0xc6, 0x5c, 0x51, 0x4c, 0xc3, 0x54, 0xa2, 0xbd, 0xe3, 0xb8, - 0x8e, 0x1a, 0x57, 0x59, 0xc1, 0x4a, 0x6b, 0xcb, 0xeb, 0xde, 0xd2, 0xc2, 0x96, 0x80, 0x6a, 0x30, 0xdc, 0x09, 0xe0, - 0x33, 0x22, 0xd5, 0x81, 0x20, 0xbb, 0x0f, 0x0e, 0x9a, 0xb3, 0x04, 0xcf, 0xc3, 0x10, 0xfe, 0xc0, 0xc2, 0x81, 0x65, - 0xa9, 0xfa, 0xb9, 0x9c, 0xc6, 0x70, 0xee, 0xe6, 0x6a, 0x87, 0xcf, 0x96, 0xa0, 0xc8, 0x53, 0x73, 0x6a, 0x2e, 0x5f, - 0x79, 0x63, 0xbf, 0xc7, 0x04, 0xf3, 0x98, 0xd9, 0x86, 0xdf, 0x7a, 0xba, 0xad, 0x2f, 0xac, 0x1b, 0x38, 0x69, 0x2f, - 0x9c, 0xf6, 0x62, 0xbb, 0x34, 0x10, 0x77, 0x75, 0x43, 0x88, 0xf0, 0x5a, 0x13, 0x8b, 0xac, 0x21, 0xd3, 0xb1, 0xd8, - 0x18, 0xaa, 0x4d, 0xc5, 0x73, 0xad, 0x10, 0x2f, 0xa7, 0xea, 0xc2, 0xd4, 0x4a, 0x65, 0xc2, 0x20, 0xcc, 0x94, 0xb0, - 0xa8, 0x32, 0xf0, 0xd9, 0xaf, 0x90, 0xe2, 0xda, 0x7a, 0xde, 0xe2, 0xf2, 0xcd, 0x4c, 0x9b, 0xed, 0xa7, 0xaf, 0xf2, - 0xf8, 0x72, 0xbb, 0x0d, 0xbb, 0x5f, 0x80, 0xf9, 0x65, 0xa9, 0x34, 0x6a, 0xe0, 0xf4, 0x10, 0xa2, 0x9f, 0xf3, 0x3d, - 0x39, 0x27, 0x8e, 0x93, 0x6b, 0x37, 0x6f, 0xb6, 0x93, 0x62, 0x04, 0x16, 0x70, 0xe2, 0x22, 0x1d, 0x68, 0xa9, 0xe0, - 0xb4, 0x65, 0xbc, 0xb7, 0xe9, 0x1d, 0xa5, 0xc2, 0xab, 0x85, 0x26, 0x21, 0x95, 0xbb, 0x97, 0xd8, 0x51, 0x03, 0xce, - 0x49, 0xdd, 0x41, 0xc0, 0x49, 0x4d, 0x37, 0xd6, 0x2a, 0x4e, 0x4d, 0x82, 0xf7, 0x4a, 0x0f, 0x5d, 0xa2, 0x9d, 0xb8, - 0xdd, 0xb6, 0x2a, 0x5b, 0xa8, 0x8f, 0x7b, 0x39, 0x4b, 0xd4, 0xf1, 0x80, 0x42, 0x17, 0x75, 0x34, 0xe4, 0x0b, 0x52, - 0xe8, 0x95, 0xa3, 0x55, 0xab, 0xbb, 0x92, 0x81, 0x52, 0xad, 0x82, 0xbc, 0x26, 0xd6, 0x5d, 0x2b, 0x6b, 0x2c, 0xae, - 0x9c, 0x90, 0xc2, 0x26, 0x7c, 0x69, 0x29, 0x16, 0x56, 0xb0, 0x37, 0xa6, 0xbe, 0x70, 0x89, 0xd0, 0x76, 0xb7, 0x21, - 0x26, 0x19, 0xac, 0x9b, 0xed, 0xf6, 0x75, 0x11, 0xce, 0xb3, 0x05, 0x95, 0xa3, 0x2c, 0x45, 0x08, 0x31, 0xe3, 0xa1, - 0x6b, 0xbb, 0x60, 0x26, 0x86, 0xba, 0xf6, 0x78, 0x49, 0xa6, 0x58, 0x9b, 0x24, 0x47, 0xf1, 0xb9, 0x2c, 0xd4, 0x5a, - 0x23, 0x04, 0x0f, 0xf7, 0x3f, 0x53, 0x88, 0xe1, 0x66, 0xd6, 0xdd, 0x6f, 0x3b, 0x37, 0xc4, 0x3f, 0x21, 0x90, 0x40, - 0xc9, 0x5e, 0x17, 0xa3, 0xf3, 0x4c, 0xa4, 0xb8, 0x53, 0x55, 0x54, 0x5c, 0xb5, 0x0e, 0x9a, 0x2d, 0xb7, 0xf7, 0x62, - 0x4b, 0x14, 0x20, 0xae, 0xb1, 0xd0, 0x8c, 0x67, 0xe5, 0x2c, 0x45, 0x32, 0x8a, 0x0d, 0x89, 0x4a, 0x2f, 0x2a, 0xba, - 0xcf, 0xd3, 0x98, 0x1e, 0xba, 0x35, 0x08, 0xae, 0x9a, 0x3b, 0x1b, 0x69, 0xbe, 0x20, 0x44, 0x4d, 0x80, 0x84, 0x8d, - 0x6a, 0x4e, 0xad, 0x4b, 0xf1, 0x30, 0xab, 0x7c, 0xa6, 0x0f, 0xe2, 0x4b, 0x01, 0x3c, 0xac, 0xb7, 0xbd, 0xaf, 0x84, - 0xc7, 0xda, 0xe0, 0xdb, 0xed, 0xf6, 0x52, 0xcc, 0x83, 0xc0, 0x63, 0x34, 0xbf, 0x53, 0x12, 0xf3, 0xde, 0x98, 0xc2, - 0x8a, 0xf7, 0x5d, 0xda, 0xba, 0x49, 0xad, 0xb5, 0x40, 0xdd, 0xe1, 0xfa, 0x80, 0xe7, 0x29, 0x71, 0xb4, 0xa3, 0x72, - 0x2a, 0xad, 0xae, 0x1c, 0xbb, 0x22, 0x30, 0x30, 0xf4, 0x0f, 0x29, 0xdb, 0x80, 0x39, 0x1e, 0x58, 0xdb, 0xa0, 0x9f, - 0x92, 0xd2, 0xc2, 0x8c, 0xd1, 0x98, 0x45, 0xae, 0xab, 0xe8, 0x80, 0xeb, 0xe8, 0xed, 0x3c, 0xfa, 0xdb, 0xb3, 0x31, - 0x2d, 0x62, 0x91, 0xca, 0x2b, 0x50, 0x41, 0x80, 0x32, 0x04, 0x0d, 0xff, 0x35, 0x35, 0x00, 0x0d, 0x82, 0x1b, 0x80, - 0x7f, 0x74, 0x3a, 0x0d, 0xda, 0x9a, 0x7c, 0x4c, 0x52, 0x55, 0xe4, 0xac, 0x0d, 0x65, 0xa6, 0x92, 0x43, 0xf2, 0xb8, - 0x04, 0x3c, 0x47, 0x6c, 0x96, 0xb2, 0xb9, 0x50, 0x9b, 0x4d, 0xbd, 0x56, 0xec, 0xc8, 0x6d, 0xa3, 0x68, 0xb3, 0x16, - 0xb5, 0x9d, 0xc4, 0x7c, 0x31, 0xbd, 0xb5, 0xc2, 0xc0, 0xa9, 0x69, 0xcd, 0xcd, 0x0e, 0x74, 0x9a, 0xad, 0xcf, 0xe4, - 0x26, 0x40, 0x1c, 0x60, 0xb8, 0x6e, 0xe7, 0x37, 0x0b, 0x42, 0x6f, 0xd9, 0xad, 0x15, 0xab, 0xde, 0x58, 0xb9, 0x88, - 0x49, 0xbb, 0x19, 0x4c, 0xe0, 0x32, 0xce, 0x0a, 0xfb, 0x42, 0xab, 0x1b, 0x8a, 0x8e, 0xb6, 0x49, 0xfb, 0x79, 0x47, - 0xbb, 0xe1, 0x82, 0x6f, 0xc5, 0x3a, 0xce, 0x0d, 0x69, 0xaa, 0xd0, 0xa3, 0x03, 0xbd, 0x1d, 0x02, 0x9a, 0xb3, 0x31, - 0x5d, 0xd2, 0x14, 0x2f, 0xd0, 0x74, 0x0d, 0x66, 0x29, 0x17, 0xd0, 0xd7, 0x6e, 0x9f, 0xe4, 0x0b, 0xd5, 0x13, 0xe1, - 0x2d, 0x51, 0xf0, 0xe5, 0x48, 0xc1, 0x2b, 0x2b, 0xe7, 0xb1, 0x99, 0x43, 0xc0, 0x63, 0x51, 0x25, 0x7a, 0x27, 0xc5, - 0x25, 0x28, 0x53, 0xe1, 0x08, 0x34, 0x55, 0x23, 0x96, 0x70, 0x80, 0xdb, 0x8b, 0xa7, 0x01, 0xa1, 0x20, 0xd5, 0x5d, - 0xdb, 0x15, 0x79, 0xcb, 0x8e, 0x36, 0xb7, 0x60, 0x16, 0x5b, 0xad, 0xcb, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, - 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, 0x43, 0x36, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, - 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x55, 0x7c, 0x07, 0x9b, - 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, - 0x5e, 0x6d, 0x6d, 0xd6, 0x66, 0xb9, 0x3e, 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, - 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x36, 0xce, - 0xdc, 0xeb, 0x90, 0x6c, 0xfe, 0xc7, 0x06, 0xea, 0x4d, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x3e, 0x61, 0x10, 0x1b, 0x33, - 0x28, 0xd7, 0x49, 0xc2, 0xcb, 0x32, 0x30, 0x4a, 0xad, 0x35, 0x5b, 0x9b, 0xf3, 0xec, 0x11, 0x3b, 0x7a, 0xd4, 0x63, - 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x04, 0x85, - 0x2c, 0xed, 0x7d, 0x6e, 0x4e, 0x64, 0xf5, 0x8d, 0x36, 0xba, 0x88, 0x54, 0x22, 0xc8, 0xc6, 0x6f, 0x10, 0xb0, 0x17, - 0x9a, 0x1d, 0x90, 0xcd, 0x92, 0x9d, 0xd2, 0x33, 0x6b, 0x02, 0x03, 0xaf, 0x4f, 0x54, 0xa2, 0x19, 0x65, 0x45, 0x74, - 0x95, 0x91, 0xcb, 0x5d, 0x48, 0xa2, 0xb3, 0x90, 0xf8, 0xb9, 0x61, 0x69, 0x5d, 0x87, 0x28, 0x66, 0x36, 0x1b, 0x5e, - 0x75, 0xf7, 0x51, 0x63, 0x5b, 0x19, 0x9f, 0xea, 0x5b, 0x9b, 0x46, 0xa6, 0xd0, 0xd7, 0xe1, 0xa4, 0xdf, 0x87, 0xbf, - 0x9a, 0x7e, 0xe0, 0x2d, 0x05, 0x7f, 0xb1, 0x47, 0xa4, 0x4e, 0x58, 0x00, 0x70, 0x84, 0x39, 0xaf, 0x9a, 0x13, 0xf8, - 0x88, 0x1d, 0x6d, 0x1e, 0x85, 0xa7, 0x8d, 0x99, 0xbb, 0x0b, 0xf1, 0x52, 0x95, 0xf4, 0xbc, 0x79, 0x32, 0x03, 0xb1, - 0x0a, 0xcd, 0x7e, 0xbd, 0x65, 0x56, 0x9f, 0x00, 0x44, 0xea, 0xd6, 0x3a, 0x94, 0xe2, 0xc7, 0xa6, 0xcb, 0x64, 0x93, - 0xb2, 0x36, 0x13, 0xa5, 0x54, 0x24, 0xcd, 0x45, 0x00, 0xfd, 0x86, 0xe1, 0xa8, 0x01, 0xde, 0x5b, 0x8f, 0xbd, 0x19, - 0x1a, 0x6f, 0x4c, 0x0d, 0x3d, 0xdb, 0xe8, 0xe5, 0xed, 0x28, 0x84, 0x19, 0x8b, 0xe8, 0xd6, 0x1d, 0x8b, 0xe1, 0x29, - 0x3d, 0x81, 0x0a, 0xdf, 0x84, 0x18, 0x4d, 0x97, 0xd4, 0xf5, 0x74, 0xad, 0xb6, 0xd2, 0x0d, 0xa1, 0x39, 0x46, 0xf1, - 0xf1, 0xda, 0x76, 0x47, 0x8d, 0xd0, 0x9e, 0x50, 0x1e, 0xde, 0xd2, 0x8a, 0xde, 0x58, 0x16, 0xc1, 0xc9, 0x8f, 0xbd, - 0xfc, 0x84, 0x9e, 0x7b, 0x02, 0x93, 0xa2, 0xad, 0x01, 0xfc, 0x01, 0xf5, 0xc3, 0x59, 0x3d, 0xb5, 0x52, 0x0e, 0x4f, - 0xe1, 0x4b, 0x36, 0x20, 0x57, 0xd0, 0x8b, 0x35, 0x66, 0x47, 0x31, 0xe8, 0xa0, 0x76, 0x76, 0x87, 0x37, 0x29, 0x65, - 0x88, 0xd6, 0x77, 0x0e, 0xe2, 0xe9, 0x1f, 0xa0, 0xe9, 0x83, 0xb4, 0x30, 0xa5, 0x6b, 0x14, 0xf0, 0x80, 0xbe, 0xa9, - 0xdf, 0xcf, 0xf1, 0xb9, 0xf6, 0x2c, 0xb1, 0xb0, 0xc7, 0x4b, 0x42, 0x97, 0x5e, 0xdc, 0x28, 0x90, 0x36, 0x3b, 0x56, - 0x01, 0x58, 0x91, 0x04, 0x1a, 0x91, 0x80, 0xa5, 0x8e, 0x27, 0x2e, 0xdb, 0xa0, 0x01, 0x49, 0x54, 0x52, 0xc8, 0x12, - 0x49, 0xe0, 0x87, 0x11, 0x84, 0x28, 0x8a, 0x41, 0xdc, 0xab, 0x97, 0x57, 0x5c, 0x53, 0x03, 0x4e, 0x14, 0xc1, 0x04, - 0xeb, 0x74, 0x0a, 0xc4, 0x56, 0xac, 0x57, 0xe0, 0x79, 0xe9, 0x38, 0x71, 0x64, 0x09, 0xd0, 0x20, 0xcd, 0x97, 0x4e, - 0xbb, 0xe5, 0xed, 0x89, 0x96, 0x2a, 0x36, 0xf7, 0x5e, 0x2c, 0x2c, 0xf7, 0x58, 0xf9, 0xdb, 0x81, 0xf6, 0xc2, 0x6a, - 0x47, 0x44, 0x0d, 0x56, 0x76, 0x6d, 0xbb, 0x36, 0x94, 0x86, 0xea, 0x5e, 0x39, 0x26, 0xa0, 0xa2, 0xab, 0xb8, 0x5a, - 0x46, 0xd9, 0x08, 0xfe, 0x6c, 0xb7, 0xc1, 0x7e, 0x00, 0x16, 0x90, 0xbf, 0xbe, 0xff, 0x39, 0xc2, 0xf0, 0x4c, 0xbf, - 0xbe, 0xff, 0x79, 0xbb, 0x7d, 0x36, 0x1e, 0x1b, 0xae, 0xc0, 0xa9, 0x75, 0x80, 0x3f, 0x30, 0x6c, 0x83, 0x5d, 0xb2, - 0xdb, 0xed, 0x33, 0xe0, 0x20, 0x14, 0xdb, 0x60, 0x76, 0xb1, 0x72, 0xe4, 0x52, 0xac, 0x86, 0xde, 0x91, 0x80, 0x55, - 0xb7, 0xc3, 0x52, 0xec, 0x52, 0x1f, 0x15, 0x82, 0x51, 0x2f, 0xfa, 0x97, 0x9d, 0x02, 0x4b, 0x0a, 0xa6, 0xab, 0xc1, - 0xb2, 0xaa, 0x56, 0x65, 0xb4, 0xbf, 0x1f, 0xaf, 0xb2, 0x51, 0x99, 0xc1, 0x36, 0x2f, 0xaf, 0x2f, 0x01, 0x50, 0x21, - 0xa0, 0x8d, 0x77, 0x6b, 0x91, 0x99, 0x17, 0x0b, 0xba, 0xcc, 0x70, 0x4d, 0x82, 0xd9, 0x41, 0xce, 0xad, 0x6e, 0x72, - 0x4a, 0xec, 0x03, 0xd8, 0x1c, 0x6e, 0xb7, 0x0d, 0x7e, 0xe1, 0x68, 0xf4, 0x6c, 0xb6, 0xcc, 0xb4, 0x41, 0x27, 0x37, - 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, 0xc9, 0xf4, 0x65, 0x06, 0x7c, 0x1e, 0x7b, 0x2b, 0x42, 0x9f, 0xe5, 0x6a, - 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x32, 0x23, 0xbe, 0x4d, - 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x56, 0x78, 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x12, 0x85, 0xa8, - 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x9a, 0x3a, 0x73, 0x19, 0x5f, 0xb8, - 0xf7, 0xd2, 0x97, 0x99, 0xdc, 0x4a, 0x00, 0x45, 0x52, 0xb5, 0xff, 0xf2, 0x19, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, - 0xe8, 0xfd, 0x02, 0x35, 0x39, 0x82, 0x80, 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, - 0x6d, 0x54, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, 0x4f, 0xd7, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, - 0x1b, 0x21, 0xeb, 0x97, 0x66, 0x17, 0x7e, 0x2e, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, - 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, 0x1e, 0x73, 0x82, 0x3f, 0x3d, 0x78, 0x4a, 0xe8, 0xad, 0x9c, 0x96, 0x08, - 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, - 0x6c, 0xd9, 0x6f, 0x4d, 0xd9, 0x92, 0x6c, 0x04, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbc, 0xdf, 0xa0, - 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, - 0x9c, 0x85, 0xed, 0x76, 0x42, 0x7c, 0x09, 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, - 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x20, 0xa0, 0xc7, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x8e, 0xf9, 0x20, 0x18, - 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x57, 0x05, 0x43, 0x58, 0xa1, 0xbf, - 0x52, 0x36, 0xf9, 0xe6, 0xef, 0x6e, 0x7e, 0xcf, 0xb5, 0x98, 0x1d, 0x84, 0xe2, 0xf6, 0x7a, 0x02, 0xc4, 0xaf, 0xe2, - 0x57, 0x60, 0x5d, 0xad, 0x25, 0xde, 0x6e, 0x7a, 0xfe, 0x14, 0xbe, 0x1c, 0xdd, 0x7e, 0x52, 0x9a, 0x4f, 0x20, 0x48, - 0x8d, 0x93, 0x94, 0xbb, 0xef, 0x3e, 0x4a, 0x57, 0x11, 0x8c, 0x16, 0x20, 0xd6, 0xdd, 0x5b, 0xc9, 0x59, 0x53, 0xf8, - 0x8f, 0x75, 0xbe, 0xc7, 0xd8, 0x21, 0xf2, 0x14, 0xa7, 0xbf, 0x01, 0x86, 0x7d, 0xe7, 0xdf, 0xca, 0xac, 0x21, 0xd1, - 0xb9, 0xfa, 0x08, 0xe8, 0xff, 0x58, 0x8f, 0xdf, 0x31, 0x4a, 0xfa, 0x92, 0x38, 0x47, 0xb8, 0x22, 0x5e, 0xa2, 0xa9, - 0x5e, 0x6f, 0x5c, 0xd3, 0x4f, 0x85, 0x79, 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0x9b, 0x68, - 0x08, 0xba, 0x7f, 0xc7, 0xbd, 0xf1, 0x9b, 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, - 0x1b, 0xc6, 0x82, 0xb5, 0x50, 0xe6, 0xab, 0x69, 0x30, 0xdb, 0xd4, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x6d, 0x9c, 0xb0, - 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, - 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x71, 0x05, 0xbb, 0xcc, - 0x57, 0x52, 0xfc, 0xd9, 0x92, 0x64, 0x63, 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, - 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, - 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x63, 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0xa7, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, - 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, 0x53, 0xba, 0x9b, 0xd3, 0xfe, 0xab, 0x82, 0x0c, 0xff, 0x02, 0xef, 0xae, - 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, - 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, 0xe4, 0xad, 0xc6, 0x6c, 0xca, 0xfd, 0x0f, 0x60, 0x44, 0xb5, 0xb4, 0xdd, - 0x0e, 0xf8, 0x72, 0x84, 0x06, 0xdb, 0xa9, 0x1b, 0xec, 0x7e, 0xdf, 0xa4, 0x1d, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, - 0x51, 0xda, 0x2c, 0x95, 0x41, 0x6d, 0x57, 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x92, 0xc6, 0x56, - 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, - 0xed, 0x36, 0x84, 0x08, 0x1c, 0xc5, 0x70, 0x32, 0x0b, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0xa9, 0x98, - 0x67, 0x0b, 0x85, 0xd8, 0xe3, 0xef, 0xa4, 0xdf, 0x0a, 0xc5, 0x29, 0xf7, 0x7e, 0x13, 0x64, 0xf3, 0x7b, 0x8a, 0x31, - 0x07, 0x9d, 0x66, 0x33, 0x03, 0x09, 0xeb, 0x71, 0x45, 0xd4, 0x3a, 0xb2, 0xb3, 0x01, 0xaa, 0x58, 0x34, 0x85, 0x05, - 0x75, 0x8b, 0x27, 0xd6, 0x33, 0x7a, 0x0f, 0x2a, 0x41, 0x54, 0x0b, 0x76, 0x63, 0xb8, 0xd6, 0x3e, 0x89, 0x50, 0x52, - 0x4e, 0x9a, 0xcc, 0x8c, 0x15, 0x0d, 0x16, 0x20, 0x24, 0x8d, 0xcb, 0xea, 0x8d, 0x4c, 0xb3, 0x8b, 0x0c, 0x10, 0x13, - 0x9c, 0xff, 0x9c, 0x6c, 0xbc, 0x79, 0xae, 0xe6, 0xa5, 0x2b, 0x71, 0x66, 0x61, 0x3e, 0xba, 0xde, 0xd2, 0x82, 0x44, - 0x05, 0xd0, 0x28, 0x5f, 0xcb, 0xf3, 0xd3, 0x8e, 0x55, 0xc8, 0xee, 0x87, 0x53, 0x65, 0x3b, 0xc4, 0x8f, 0x58, 0x45, - 0xbc, 0xd3, 0xba, 0x52, 0x22, 0x8d, 0x8e, 0xb6, 0x01, 0x31, 0x6c, 0xd9, 0xb7, 0xa8, 0xe1, 0x83, 0x30, 0x83, 0x4e, - 0xf2, 0x83, 0x9e, 0xd1, 0xb1, 0x35, 0x90, 0xf4, 0xb5, 0x08, 0xbe, 0x46, 0x47, 0x3a, 0x51, 0xa6, 0x91, 0x98, 0x42, - 0xa2, 0x5f, 0x2f, 0xb4, 0xc6, 0x32, 0xca, 0xbe, 0x22, 0xff, 0x7b, 0xdd, 0xbd, 0xdf, 0xc4, 0x76, 0x0b, 0x93, 0xec, - 0x79, 0x5c, 0xc1, 0xa6, 0x46, 0xad, 0x10, 0xce, 0xce, 0x71, 0x85, 0xda, 0xb1, 0x5e, 0x58, 0x02, 0x79, 0x00, 0x5b, - 0x91, 0x06, 0x65, 0x90, 0xec, 0x53, 0x31, 0x17, 0x0b, 0x27, 0xca, 0x91, 0x0a, 0xef, 0x4b, 0x8e, 0x52, 0x0e, 0x57, - 0xb1, 0xb0, 0x60, 0xc8, 0xaf, 0x8e, 0x2e, 0x0a, 0x79, 0x05, 0x92, 0x12, 0xc3, 0x50, 0x59, 0x5e, 0x17, 0x57, 0x6d, - 0x49, 0x68, 0xef, 0x0c, 0x40, 0x58, 0x0a, 0x10, 0xbc, 0x34, 0x6a, 0x88, 0xd9, 0x46, 0xed, 0xae, 0xe8, 0x5e, 0x72, - 0x40, 0x9d, 0xee, 0xda, 0xad, 0x37, 0x65, 0x9b, 0x6d, 0xc5, 0x85, 0x7f, 0x42, 0xe9, 0xc7, 0x7c, 0x50, 0xf8, 0x54, - 0x02, 0x37, 0xbe, 0xda, 0x64, 0xd9, 0xc5, 0x1d, 0x2e, 0xfd, 0xaa, 0x31, 0x7e, 0xfd, 0x7e, 0x4f, 0x2d, 0x84, 0x46, - 0x2a, 0x30, 0xdf, 0x3e, 0x33, 0x55, 0x19, 0x4d, 0xa9, 0xbd, 0x04, 0x57, 0xce, 0x7e, 0x04, 0x15, 0x71, 0x5d, 0x91, - 0xc9, 0xd4, 0x00, 0xed, 0x79, 0x59, 0xe1, 0x56, 0x16, 0xe0, 0xb1, 0x13, 0x90, 0xed, 0x96, 0x87, 0x81, 0x3e, 0x74, - 0x02, 0x7f, 0x4b, 0x9e, 0x22, 0xb3, 0x66, 0x1f, 0x7f, 0xd1, 0x82, 0x7f, 0x6c, 0xc1, 0xcf, 0x28, 0xee, 0xb4, 0x32, - 0xff, 0x56, 0x5a, 0xb7, 0xb8, 0x7f, 0x27, 0xd3, 0x84, 0xa2, 0x32, 0xa1, 0xf6, 0x2b, 0xfd, 0x97, 0x09, 0x96, 0xa4, - 0xb2, 0x7f, 0x90, 0xf0, 0xc1, 0xac, 0xf1, 0xc4, 0x1a, 0x4f, 0x86, 0xd3, 0xad, 0x34, 0x0c, 0x01, 0x0a, 0xfd, 0xbc, - 0xcc, 0x15, 0xd5, 0xcf, 0xbf, 0xac, 0xf9, 0x9a, 0x37, 0x5b, 0x6c, 0x93, 0x1e, 0x68, 0xb0, 0x97, 0x47, 0x53, 0x0a, - 0x27, 0x51, 0xe7, 0x46, 0xa2, 0x2e, 0x6a, 0x96, 0xa1, 0x3a, 0xc1, 0xab, 0x79, 0xaa, 0x87, 0xbd, 0x99, 0x88, 0xd6, - 0x4a, 0xca, 0x12, 0x03, 0xd6, 0x3a, 0xf2, 0x90, 0xdc, 0xad, 0x75, 0xdc, 0x69, 0xa8, 0x4b, 0x53, 0x28, 0x01, 0x56, - 0xb8, 0x00, 0x47, 0xd0, 0xcf, 0x45, 0xc8, 0xe1, 0x9a, 0xaa, 0xf4, 0x0b, 0x9a, 0x92, 0x27, 0x9e, 0xa2, 0x56, 0x2b, - 0xd2, 0xed, 0x47, 0x39, 0x76, 0xc3, 0x37, 0x4e, 0xc8, 0x89, 0x11, 0xfa, 0xbb, 0x63, 0x29, 0x67, 0x68, 0xf1, 0xa0, - 0x4e, 0xb0, 0x5e, 0xde, 0x52, 0xa0, 0x98, 0xa3, 0xcb, 0xaa, 0x6b, 0x5e, 0xa3, 0xed, 0xcb, 0xb2, 0xdf, 0xcf, 0x6d, - 0x3d, 0x29, 0x3b, 0xda, 0x2c, 0xcd, 0x3e, 0x44, 0xc5, 0x14, 0xee, 0xfa, 0x44, 0xf3, 0x57, 0xa1, 0xbe, 0x6a, 0xcb, - 0x9c, 0x8f, 0x38, 0xe2, 0x62, 0xe4, 0xa4, 0xfe, 0x45, 0x4d, 0xbd, 0x12, 0xf7, 0xab, 0x4a, 0xbe, 0x13, 0xc6, 0x8a, - 0xd1, 0x01, 0xf5, 0xa7, 0x4a, 0xe5, 0xfd, 0xb2, 0x00, 0xb8, 0x27, 0xc1, 0x3e, 0x81, 0x7d, 0x85, 0x46, 0xf8, 0x6d, - 0x09, 0xf8, 0x37, 0x8a, 0x1b, 0xb0, 0x0a, 0x0c, 0x30, 0x9a, 0x6c, 0xcf, 0x69, 0x02, 0x07, 0x9c, 0xd0, 0x2a, 0x0a, - 0x2a, 0xcc, 0xd0, 0x50, 0x5b, 0x18, 0x3d, 0x45, 0x19, 0xb7, 0xca, 0xec, 0xdd, 0x18, 0x3b, 0x2d, 0xf0, 0x1a, 0xfe, - 0x7c, 0x5e, 0xe8, 0x61, 0xa3, 0x0e, 0xd2, 0xa3, 0x93, 0x98, 0xfe, 0xb8, 0x85, 0x93, 0x9b, 0x85, 0xb3, 0xac, 0x59, - 0x02, 0xdd, 0x81, 0x0b, 0x62, 0xdc, 0xef, 0xe7, 0x70, 0x64, 0x9a, 0x91, 0x2f, 0x58, 0x4e, 0x63, 0xb6, 0xa4, 0xda, - 0xd3, 0xee, 0xb2, 0x0a, 0x73, 0xba, 0xb4, 0x32, 0xde, 0x94, 0x81, 0xca, 0x68, 0xbb, 0x0d, 0xe1, 0x4f, 0xb7, 0xb5, - 0x4b, 0x3a, 0x5f, 0x42, 0x06, 0xf8, 0x03, 0x12, 0x51, 0xc4, 0xbe, 0xfe, 0xb7, 0x1a, 0xa7, 0xf4, 0x44, 0x69, 0xcd, - 0x12, 0xba, 0x66, 0xba, 0x7e, 0x7a, 0xc1, 0xd6, 0x8d, 0xa5, 0xb0, 0xdd, 0x86, 0xcd, 0x04, 0xa6, 0x39, 0x57, 0x32, - 0xbd, 0x40, 0x9d, 0x14, 0x50, 0xb1, 0xf0, 0x02, 0x97, 0x5f, 0x4a, 0x28, 0x34, 0x77, 0xbe, 0x5c, 0x18, 0x25, 0x26, - 0xb4, 0x4a, 0x7e, 0xf9, 0x50, 0x99, 0xaf, 0x8d, 0x47, 0xdc, 0xbf, 0xd2, 0x30, 0x31, 0x45, 0xa2, 0x42, 0x74, 0xf6, - 0x1b, 0xc8, 0x72, 0x04, 0xe0, 0x58, 0x9e, 0xca, 0x9a, 0xfe, 0x98, 0x42, 0x1c, 0x74, 0x68, 0xd0, 0xbb, 0x42, 0x5e, - 0x65, 0x25, 0x0f, 0xf1, 0x9e, 0xe0, 0x69, 0x46, 0xef, 0x37, 0xf8, 0xd0, 0xd6, 0x1e, 0x3d, 0x41, 0x36, 0x9e, 0x72, - 0xbf, 0xfe, 0x4e, 0x84, 0x73, 0x88, 0x56, 0xb9, 0xa0, 0x5a, 0x5d, 0xed, 0x00, 0xa8, 0x3c, 0xdb, 0xab, 0x47, 0x70, - 0xba, 0xe9, 0xeb, 0x5b, 0x15, 0x3a, 0x73, 0x00, 0x69, 0x0f, 0xc9, 0xba, 0xe6, 0x7a, 0x07, 0xb8, 0x23, 0xb1, 0x5a, - 0x03, 0x8d, 0x75, 0x5b, 0xb3, 0xd3, 0x1e, 0xc5, 0x63, 0x22, 0x33, 0x63, 0x91, 0x62, 0xcc, 0xdd, 0x3a, 0x2d, 0x8a, - 0x36, 0x68, 0x86, 0xb0, 0x7b, 0xd7, 0xe1, 0xeb, 0x56, 0x84, 0xf5, 0xfb, 0x6d, 0x5f, 0x60, 0x34, 0x8c, 0xb9, 0x76, - 0xcf, 0x33, 0x74, 0xc3, 0x06, 0xdb, 0xc8, 0x79, 0x88, 0x7c, 0x98, 0xa9, 0x03, 0x51, 0xd6, 0xd6, 0x80, 0xed, 0x11, - 0xd7, 0x9b, 0x56, 0xf1, 0xf3, 0x2a, 0xe6, 0x6c, 0xcf, 0x1a, 0xa7, 0xb4, 0xbe, 0xc6, 0x35, 0xc7, 0x55, 0x21, 0xa2, - 0xb6, 0x9e, 0xf1, 0x30, 0xec, 0x7c, 0x81, 0x3b, 0xb3, 0xc2, 0xe0, 0x45, 0x58, 0x2a, 0xd9, 0xa9, 0x5c, 0x7f, 0x0e, - 0x5b, 0x1c, 0xa4, 0xf2, 0xa5, 0xd7, 0xdf, 0x7f, 0xf9, 0xe2, 0x0b, 0x74, 0x53, 0x73, 0x7e, 0x04, 0x41, 0x26, 0xd0, - 0x21, 0x4b, 0xa9, 0x1e, 0xbf, 0x2b, 0x80, 0xda, 0xc3, 0x3c, 0x7c, 0x57, 0x30, 0x11, 0x5f, 0x67, 0x97, 0x71, 0x25, - 0x8b, 0xd1, 0x35, 0x17, 0xa9, 0x2c, 0xac, 0xd4, 0x38, 0x38, 0x5e, 0xad, 0x72, 0x1e, 0x80, 0xa9, 0xbc, 0x65, 0x94, - 0x6d, 0x65, 0x99, 0x1e, 0x5c, 0x2d, 0x4f, 0xaf, 0xb4, 0xe8, 0xbc, 0xbc, 0xbe, 0x0c, 0x22, 0xfc, 0x75, 0x6e, 0x7e, - 0x5c, 0xc5, 0xe5, 0xc7, 0x20, 0xb2, 0x36, 0x75, 0xe6, 0x07, 0x4a, 0xe5, 0xc1, 0x7f, 0x0a, 0x64, 0xba, 0xdf, 0x15, - 0x60, 0x99, 0x6d, 0x2b, 0x3e, 0x8c, 0xb1, 0xd6, 0xe1, 0x84, 0xcc, 0x54, 0x89, 0xde, 0xbb, 0x64, 0x5d, 0x80, 0xb5, - 0x9f, 0xc2, 0x32, 0x56, 0xb9, 0x66, 0x58, 0x99, 0xaa, 0xc8, 0xcc, 0xca, 0x9a, 0xed, 0x87, 0xd6, 0x89, 0x66, 0x8e, - 0xde, 0x02, 0xfa, 0x81, 0xec, 0x5f, 0xd2, 0x72, 0xcd, 0x3c, 0x1f, 0x9b, 0xc6, 0xeb, 0x47, 0xfb, 0x97, 0x6e, 0xc1, - 0xde, 0xda, 0x3b, 0x39, 0x0a, 0x13, 0xc1, 0xb3, 0xd6, 0x8c, 0x2f, 0xf2, 0xac, 0x80, 0x95, 0x33, 0x19, 0x8f, 0xa9, - 0xb7, 0xb4, 0x5a, 0x37, 0x47, 0x87, 0xe4, 0x9a, 0x3d, 0xae, 0x1e, 0x73, 0xb2, 0xcf, 0x5b, 0xa6, 0xb6, 0x6d, 0xeb, - 0x38, 0x4f, 0x93, 0xaf, 0x4c, 0xf7, 0xc5, 0xda, 0x46, 0x44, 0x57, 0xce, 0x7d, 0xce, 0x2b, 0xb8, 0xf5, 0x4d, 0x69, - 0xe8, 0xb5, 0x04, 0x20, 0x3a, 0x6d, 0xc0, 0x5f, 0xb0, 0x72, 0x3d, 0xaa, 0x78, 0x59, 0x81, 0x84, 0x05, 0x45, 0x78, - 0x53, 0xec, 0x4d, 0xe1, 0x6e, 0x9c, 0x9e, 0xc3, 0x0e, 0x5c, 0x4c, 0xd1, 0x1d, 0x27, 0x26, 0xb3, 0xd2, 0x68, 0x45, - 0x23, 0xfd, 0xcb, 0xf5, 0x25, 0xd6, 0x7d, 0xd1, 0xca, 0x3c, 0x9b, 0x53, 0x61, 0xb1, 0xbb, 0xca, 0xa5, 0x13, 0xf5, - 0x5b, 0x26, 0x5c, 0xb9, 0x12, 0x04, 0x64, 0x5a, 0xb0, 0x5e, 0x61, 0x76, 0x91, 0x5c, 0x03, 0x21, 0x03, 0xc3, 0xd7, - 0x60, 0x2d, 0x4a, 0x6e, 0xac, 0x60, 0xbd, 0x7b, 0xbe, 0x4e, 0x10, 0x52, 0xf0, 0xc0, 0x4d, 0xd0, 0x0f, 0xad, 0x9b, - 0xb7, 0xa3, 0x44, 0x19, 0xc4, 0xe3, 0xd6, 0x4e, 0x39, 0x48, 0x20, 0x00, 0xf7, 0x54, 0x85, 0xe0, 0x50, 0x20, 0xeb, - 0xe0, 0x6a, 0xc6, 0x11, 0x5c, 0x5d, 0x39, 0x73, 0x71, 0x03, 0xb0, 0xae, 0xfc, 0xb9, 0x6c, 0x70, 0x61, 0x3d, 0xa2, - 0xca, 0x9c, 0x71, 0x8a, 0x41, 0x8c, 0x2c, 0x41, 0x5f, 0x59, 0x4a, 0x7b, 0x09, 0x9a, 0xc6, 0x2b, 0xb6, 0x52, 0x3e, - 0x00, 0xf4, 0x9c, 0xad, 0x94, 0xb1, 0x3f, 0x7e, 0x7d, 0xc6, 0x56, 0x5a, 0x1a, 0x3c, 0xbd, 0x9a, 0x9d, 0xcf, 0xce, - 0x06, 0xec, 0x20, 0x0a, 0xb5, 0x01, 0x43, 0xe0, 0x90, 0xf8, 0x83, 0x41, 0xa8, 0xf1, 0x4e, 0x06, 0x2a, 0x20, 0x16, - 0xf1, 0x78, 0x6c, 0xc4, 0xcd, 0x0a, 0xc7, 0x43, 0x0c, 0x7e, 0xd5, 0x7c, 0x41, 0x02, 0x42, 0x4d, 0x69, 0xe8, 0xf2, - 0x18, 0x0e, 0x27, 0x7b, 0x13, 0x48, 0xc5, 0xcc, 0x4c, 0x15, 0xc6, 0xc6, 0x24, 0x82, 0x78, 0xa7, 0x9d, 0xf5, 0x42, - 0xb9, 0xdd, 0x35, 0x1a, 0xc8, 0x95, 0xc1, 0x17, 0x55, 0x3c, 0xd9, 0x1b, 0x76, 0x55, 0x8c, 0xa3, 0x70, 0x6d, 0x94, - 0x6f, 0x67, 0x87, 0x00, 0x5e, 0x7b, 0x36, 0xf4, 0xe5, 0x12, 0x67, 0xfb, 0x4f, 0xc9, 0xe3, 0xa7, 0x84, 0x9e, 0xb1, - 0xb3, 0xaf, 0x9e, 0xd2, 0x33, 0x45, 0x4e, 0xf6, 0x26, 0xd1, 0x35, 0xb3, 0x98, 0x2f, 0x07, 0xaa, 0x09, 0xf4, 0x72, - 0xb4, 0x16, 0x6a, 0x81, 0x69, 0x87, 0xa6, 0xf0, 0xdb, 0xf1, 0x5e, 0x30, 0xb8, 0x6e, 0x37, 0xfd, 0xba, 0xdd, 0x56, - 0xcf, 0xab, 0x6b, 0xef, 0x20, 0xda, 0x2d, 0x66, 0xf2, 0xf7, 0xf1, 0x9e, 0x9b, 0x03, 0xac, 0xef, 0xe1, 0x31, 0x31, - 0x4d, 0xda, 0x19, 0x15, 0xbf, 0xa6, 0x27, 0xd8, 0x87, 0x66, 0x91, 0x1d, 0x7d, 0x18, 0xfe, 0x5b, 0x9d, 0xa8, 0xcf, - 0xbe, 0x3a, 0x00, 0x72, 0x04, 0x32, 0x50, 0x2c, 0x11, 0xcc, 0x70, 0xa0, 0x29, 0xa0, 0x20, 0xd3, 0xe3, 0x4e, 0xf5, - 0xf0, 0xab, 0x51, 0x53, 0x33, 0x72, 0x0d, 0x53, 0x83, 0x6d, 0xc1, 0x0f, 0x54, 0x37, 0xf4, 0x37, 0x1a, 0xdd, 0x48, - 0x3b, 0x99, 0x99, 0x97, 0xd4, 0xc6, 0x75, 0xbb, 0x86, 0x00, 0xc6, 0x0e, 0x5e, 0x50, 0xb2, 0xaf, 0x0f, 0x2f, 0xf7, - 0x70, 0x15, 0x01, 0x4a, 0x16, 0x0b, 0xbe, 0x1e, 0x5c, 0xea, 0xcd, 0xbd, 0x17, 0x90, 0xc1, 0xd7, 0xc1, 0xd1, 0xd7, - 0x03, 0x39, 0x08, 0x0e, 0xf7, 0x2f, 0x8f, 0x02, 0x67, 0xdc, 0x0f, 0x21, 0x1e, 0x55, 0x45, 0x31, 0x13, 0xa6, 0x8a, - 0xc4, 0xd6, 0x9e, 0xdb, 0x7a, 0x95, 0xf1, 0x19, 0x4d, 0xa7, 0x16, 0xf9, 0x3b, 0x4c, 0x59, 0x6c, 0x7e, 0x07, 0x13, - 0x7e, 0x15, 0x44, 0x2e, 0x08, 0xea, 0x2c, 0x8f, 0x62, 0xba, 0x64, 0xb7, 0x22, 0x4c, 0x69, 0xb2, 0x9f, 0x13, 0x12, - 0x85, 0x4b, 0x05, 0x9e, 0xa7, 0x5e, 0x27, 0x10, 0xc7, 0xd5, 0x7d, 0x7e, 0x2b, 0xc2, 0x25, 0xcd, 0xf7, 0x13, 0xd2, - 0x2a, 0xc2, 0x45, 0x64, 0xd9, 0xd4, 0xf4, 0x82, 0x85, 0x2b, 0x7a, 0x09, 0xcc, 0x94, 0x5c, 0x87, 0x97, 0xc0, 0xe5, - 0xad, 0xe7, 0xab, 0x05, 0xbb, 0x6c, 0x48, 0xdf, 0x0c, 0x5f, 0x7c, 0x61, 0x7d, 0xf2, 0x80, 0x87, 0x74, 0x7e, 0x78, - 0x29, 0xd8, 0x00, 0x5c, 0x67, 0xfc, 0xe6, 0x3b, 0x79, 0xab, 0xe7, 0xa5, 0x3d, 0xc5, 0x38, 0x33, 0xed, 0xc4, 0xa4, - 0x9d, 0x90, 0xfb, 0xf7, 0xed, 0x4d, 0x6c, 0x4e, 0xf6, 0x32, 0x5a, 0x2b, 0x97, 0x55, 0xcb, 0x90, 0x14, 0x6b, 0x86, - 0xfc, 0x3d, 0x4a, 0x4e, 0xad, 0xc0, 0x93, 0x5d, 0xf0, 0x2a, 0x59, 0xfa, 0x07, 0x95, 0xb5, 0x1a, 0xb0, 0xc7, 0x88, - 0x65, 0xa1, 0x70, 0xec, 0xdf, 0x64, 0xac, 0x58, 0xfb, 0x02, 0x8d, 0x18, 0xb9, 0xb7, 0x37, 0x19, 0xf3, 0x62, 0xae, - 0x26, 0x6b, 0x2f, 0x54, 0x9d, 0x97, 0x9e, 0xb7, 0x78, 0x2f, 0xa7, 0xd4, 0x30, 0x12, 0xd1, 0xbd, 0xb1, 0x32, 0xa3, - 0x54, 0x89, 0x5a, 0x83, 0x46, 0x04, 0x1b, 0xbb, 0xe0, 0x97, 0xe0, 0x84, 0xca, 0x3d, 0x75, 0xb6, 0x6f, 0xa7, 0x54, - 0x7a, 0xc0, 0xb2, 0xd4, 0xa8, 0xca, 0xdd, 0x32, 0x93, 0xac, 0x1a, 0x04, 0xa3, 0x3f, 0x4b, 0x29, 0x66, 0x78, 0x67, - 0x64, 0xc1, 0x14, 0xac, 0x04, 0x55, 0x2d, 0xc3, 0x72, 0xc8, 0x51, 0x8b, 0x67, 0x7c, 0x52, 0xa5, 0xfe, 0xd1, 0x11, - 0x24, 0x77, 0xb9, 0x6e, 0x05, 0xc9, 0x7d, 0x3a, 0x7e, 0xaa, 0x07, 0x3a, 0x5d, 0x6b, 0xc7, 0x43, 0x9f, 0xdf, 0x46, - 0x7c, 0x6d, 0xdd, 0x7b, 0xaa, 0xb5, 0x0a, 0x65, 0xa0, 0xc5, 0x8a, 0xca, 0x95, 0x5a, 0xd2, 0xfb, 0x5d, 0x04, 0xc0, - 0x22, 0x36, 0x66, 0xe3, 0x5d, 0xdb, 0xac, 0x10, 0x34, 0xba, 0xec, 0x68, 0x13, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, - 0xd0, 0xf8, 0x88, 0x95, 0xfd, 0x7e, 0x7e, 0x04, 0xf4, 0x54, 0x1b, 0x31, 0x15, 0x70, 0xe4, 0x7f, 0x69, 0x45, 0xa6, - 0x28, 0xb0, 0x59, 0x53, 0x77, 0x6b, 0x2c, 0x23, 0xd1, 0x97, 0x29, 0x5d, 0x9e, 0xf0, 0x0c, 0x98, 0xd6, 0xeb, 0x96, - 0xe3, 0xca, 0xae, 0xe2, 0xc8, 0x53, 0x61, 0x59, 0x71, 0x5e, 0x85, 0xe3, 0xad, 0xc7, 0x37, 0xd8, 0x37, 0x6c, 0xda, - 0x85, 0x3f, 0x84, 0xb0, 0x10, 0xde, 0x64, 0x70, 0x1b, 0xd1, 0x76, 0x12, 0xa8, 0xbc, 0x31, 0xd7, 0x09, 0x65, 0x73, - 0xbb, 0x5e, 0x7b, 0x06, 0xe9, 0xc4, 0x1c, 0x28, 0xd5, 0x08, 0x5a, 0xa3, 0x59, 0x50, 0x35, 0xe2, 0x91, 0xe3, 0xe1, - 0x9d, 0x41, 0xac, 0x96, 0x2f, 0x69, 0x2a, 0x45, 0x03, 0x30, 0x2e, 0x80, 0xcb, 0xd3, 0xaf, 0xef, 0x7f, 0x3e, 0xe5, - 0x71, 0x91, 0x2c, 0xdf, 0xc5, 0x45, 0x7c, 0x55, 0x86, 0x1b, 0x35, 0x46, 0x71, 0x4d, 0xa6, 0x62, 0xc0, 0xa4, 0x59, - 0x49, 0xcd, 0x5d, 0xa9, 0x09, 0x31, 0xd6, 0x99, 0xac, 0xcb, 0x4a, 0x5e, 0x35, 0x2a, 0x5d, 0x17, 0x19, 0x7e, 0xdc, - 0xf2, 0x39, 0xdd, 0x07, 0x20, 0x4f, 0xe3, 0x42, 0x1a, 0x49, 0x5d, 0x88, 0x31, 0x17, 0xf1, 0xba, 0x3e, 0x1e, 0x37, - 0xba, 0x5e, 0xb2, 0x67, 0xe3, 0x27, 0xd3, 0x37, 0x59, 0x98, 0x0d, 0x04, 0x19, 0x55, 0x4b, 0x2e, 0x5a, 0xa6, 0x9c, - 0xca, 0x24, 0x00, 0x7d, 0x3c, 0x7b, 0x8c, 0x1d, 0x8c, 0xc7, 0x64, 0xd3, 0x16, 0x0f, 0xf0, 0x70, 0xb9, 0x0e, 0x0b, - 0x32, 0xd3, 0x75, 0x44, 0x81, 0xe0, 0xb7, 0x55, 0x00, 0x48, 0x8e, 0xb6, 0x2a, 0xc3, 0xa5, 0xb1, 0x67, 0xe3, 0x09, - 0x95, 0xd8, 0xed, 0x90, 0xd4, 0x5e, 0x85, 0x6e, 0xe6, 0xa5, 0xef, 0x51, 0x24, 0x8d, 0xcb, 0xd2, 0x4e, 0xa5, 0x52, - 0xed, 0x99, 0x99, 0xeb, 0x1a, 0xc4, 0x60, 0x08, 0x75, 0xdd, 0xa5, 0x57, 0xf7, 0x6e, 0x73, 0xad, 0xd9, 0x0e, 0x78, - 0xaf, 0x41, 0x33, 0x94, 0xbc, 0xc5, 0xbc, 0x75, 0x45, 0xd4, 0x74, 0xb5, 0x06, 0xb3, 0x62, 0x94, 0x2d, 0x45, 0xe9, - 0x9a, 0x82, 0x52, 0x30, 0xba, 0x58, 0x7b, 0x0b, 0xf7, 0x8d, 0x6c, 0x5c, 0x58, 0x32, 0xbd, 0x5a, 0x94, 0x94, 0x50, - 0xdd, 0x54, 0x8c, 0x94, 0x30, 0x52, 0x1a, 0x9e, 0xca, 0xf7, 0x02, 0x8f, 0xf3, 0x3c, 0x88, 0x5a, 0x5e, 0x60, 0xc7, - 0x15, 0x39, 0x06, 0x47, 0x2f, 0x93, 0xd3, 0x50, 0xe0, 0x1f, 0x33, 0x05, 0x62, 0x3a, 0x54, 0xf7, 0x1b, 0xdc, 0xfc, - 0xff, 0x28, 0x58, 0xe0, 0xf1, 0xad, 0x97, 0xb8, 0x8d, 0xfe, 0x51, 0xf8, 0xb4, 0xf4, 0xb9, 0xf4, 0x5d, 0x5d, 0x3c, - 0x69, 0x6f, 0x36, 0x4a, 0x96, 0x59, 0x9e, 0xbe, 0x95, 0x29, 0x07, 0x91, 0x19, 0x5a, 0x83, 0xb2, 0x23, 0xd1, 0xb8, - 0xe1, 0x81, 0x11, 0x63, 0xe3, 0xc6, 0xf7, 0x63, 0x06, 0xb2, 0x61, 0xb0, 0xfa, 0x66, 0xa9, 0x4c, 0xd6, 0x57, 0x80, - 0x29, 0xa2, 0xe4, 0x27, 0x2f, 0x73, 0x0e, 0x4f, 0xa1, 0xbe, 0x7e, 0x81, 0xdb, 0x5c, 0xe9, 0xfb, 0x9c, 0xff, 0x98, - 0xd1, 0x1f, 0x11, 0xe8, 0x24, 0x5e, 0x81, 0xdc, 0xe3, 0x39, 0xd4, 0x8d, 0x30, 0xb5, 0x1c, 0x83, 0x03, 0x21, 0x1a, - 0x88, 0xa8, 0x58, 0xa0, 0xa0, 0x2e, 0x0c, 0xb0, 0x86, 0xba, 0x60, 0x0e, 0xcf, 0x73, 0x99, 0x7c, 0x9c, 0x1a, 0x9f, - 0xf9, 0x61, 0x8c, 0x31, 0x93, 0x83, 0x41, 0x58, 0xcd, 0x82, 0xe1, 0x78, 0x34, 0x39, 0x78, 0x06, 0xe7, 0x76, 0x30, - 0x0e, 0xc8, 0x20, 0xa8, 0xcb, 0x55, 0x2c, 0x68, 0x79, 0x7d, 0x69, 0xcb, 0xc0, 0x8f, 0xeb, 0x60, 0xf0, 0x8f, 0xc2, - 0x53, 0xbc, 0x83, 0xe6, 0xe4, 0x4c, 0x86, 0x60, 0x63, 0xbf, 0x26, 0x20, 0x29, 0xeb, 0x69, 0x7e, 0x52, 0x1f, 0x6e, - 0x4c, 0x69, 0xff, 0xcc, 0xe1, 0x05, 0x87, 0x1d, 0x12, 0x28, 0x90, 0xc6, 0xd3, 0x6c, 0xf4, 0x5a, 0x29, 0x72, 0xdf, - 0x15, 0x1c, 0xee, 0xcc, 0x3d, 0x67, 0x7a, 0xe4, 0x14, 0x12, 0xcd, 0x2c, 0xe0, 0x46, 0xfe, 0x5a, 0x5c, 0xc7, 0x79, - 0x96, 0xee, 0x35, 0xdf, 0xec, 0x95, 0x77, 0xa2, 0x8a, 0x6f, 0x47, 0x81, 0xb1, 0x26, 0xe4, 0xbe, 0xea, 0x09, 0xd0, - 0x13, 0x60, 0x0b, 0x80, 0x01, 0xf1, 0x8e, 0x99, 0xc9, 0x8c, 0x47, 0xe0, 0x11, 0xd8, 0xf4, 0x81, 0x2c, 0xee, 0x9c, - 0x4b, 0x92, 0xbf, 0x99, 0x4a, 0x7b, 0xd5, 0x2b, 0x77, 0x0a, 0xb2, 0x5e, 0x6d, 0xe5, 0xae, 0x5b, 0x9f, 0x7d, 0xd3, - 0xe1, 0x15, 0x78, 0x2e, 0xc1, 0x2d, 0xb2, 0xdf, 0x6f, 0x0a, 0x2a, 0x85, 0x51, 0x11, 0xef, 0x24, 0xd7, 0xe8, 0xdf, - 0xee, 0x8d, 0x8d, 0x22, 0xb9, 0xe5, 0xc3, 0x03, 0xa8, 0x33, 0x79, 0x57, 0xdc, 0xce, 0x21, 0x6a, 0xeb, 0x6e, 0x3c, - 0xb0, 0xda, 0xa0, 0x5d, 0xd6, 0x1c, 0xc1, 0x85, 0x17, 0x7b, 0x19, 0x8c, 0x05, 0xce, 0xca, 0x48, 0xa9, 0x71, 0x0d, - 0xa9, 0x05, 0x9f, 0xe4, 0xe9, 0x3d, 0x64, 0xa9, 0x27, 0x41, 0x91, 0xe3, 0x59, 0x0c, 0x99, 0xc6, 0xdb, 0xc0, 0xe3, - 0x77, 0x32, 0x04, 0x69, 0xda, 0x76, 0xdb, 0x1c, 0x81, 0xb2, 0x7b, 0x60, 0x4a, 0x52, 0xd7, 0xc6, 0xd4, 0x40, 0x43, - 0xed, 0xa1, 0x46, 0x2a, 0xe2, 0xec, 0xe8, 0x0d, 0xe8, 0x10, 0xc1, 0xf7, 0x3b, 0xcd, 0xca, 0x8e, 0x17, 0x13, 0x82, - 0x27, 0xef, 0xcb, 0xdb, 0xac, 0xac, 0xca, 0xe8, 0x7d, 0x8a, 0x86, 0x50, 0x89, 0x14, 0xd1, 0x2b, 0x88, 0xa7, 0x57, - 0xe2, 0xef, 0x32, 0xfa, 0x39, 0xa5, 0x71, 0x9a, 0x62, 0xfa, 0x8b, 0x02, 0x7e, 0x3e, 0x07, 0x54, 0x47, 0xdc, 0x09, - 0xd1, 0xb9, 0x04, 0x7b, 0x35, 0x88, 0x66, 0x55, 0x71, 0xc0, 0xd0, 0x8c, 0x6e, 0x05, 0x45, 0x8c, 0x36, 0xcc, 0xfe, - 0x43, 0x81, 0x42, 0x21, 0x55, 0xcc, 0x77, 0xc2, 0x3e, 0x44, 0x3f, 0x62, 0x91, 0xc7, 0xef, 0x5e, 0x9b, 0x21, 0x8d, - 0xee, 0x24, 0xd5, 0x5b, 0x1b, 0x8f, 0x2d, 0x0c, 0x5c, 0x16, 0x5d, 0xae, 0xe9, 0x59, 0xbc, 0xca, 0xa2, 0x0d, 0xe0, - 0x4f, 0xbc, 0x7b, 0xfd, 0x5c, 0x59, 0x98, 0xbc, 0xc8, 0x40, 0x71, 0x70, 0xfc, 0xee, 0xf5, 0x1b, 0x99, 0xae, 0x73, - 0x1e, 0x9d, 0x49, 0x24, 0xad, 0xc7, 0xef, 0x5e, 0xff, 0x82, 0xe6, 0x5e, 0x3f, 0x17, 0xf0, 0xfe, 0x15, 0xf0, 0x96, - 0x51, 0xbc, 0x86, 0x3e, 0xa9, 0xdf, 0xc9, 0x1a, 0x3b, 0xe5, 0xd5, 0x5a, 0x46, 0xbf, 0xa6, 0xb5, 0x27, 0xad, 0xfa, - 0x67, 0xe1, 0x53, 0x3b, 0x4f, 0xc0, 0x73, 0x9b, 0x67, 0xe2, 0x63, 0x64, 0x45, 0x3b, 0x41, 0xf4, 0xf5, 0xde, 0xed, - 0x55, 0x2e, 0xca, 0x08, 0x5f, 0x30, 0xb4, 0x0b, 0x8a, 0xf6, 0xf7, 0x6f, 0x6e, 0x6e, 0x46, 0x37, 0x4f, 0x46, 0xb2, - 0xb8, 0xdc, 0x9f, 0x7c, 0xfb, 0xed, 0xb7, 0xfb, 0xf8, 0x36, 0xf8, 0xba, 0xed, 0xf6, 0x5e, 0x11, 0x3e, 0x60, 0x01, - 0x22, 0x54, 0x7f, 0x0d, 0x57, 0x14, 0xd0, 0xc2, 0x0d, 0xbe, 0x0e, 0xbe, 0xd6, 0x87, 0xce, 0xd7, 0x87, 0xe5, 0xf5, - 0xa5, 0x2a, 0xbf, 0xab, 0xe4, 0x83, 0xf1, 0x78, 0xbc, 0x0f, 0x12, 0xa8, 0xaf, 0x07, 0x7c, 0x10, 0x1c, 0x05, 0x83, - 0x0c, 0x2e, 0x34, 0xe5, 0xf5, 0xe5, 0x51, 0xe0, 0x99, 0xe6, 0x36, 0x58, 0x44, 0x07, 0xe2, 0x12, 0xec, 0x5f, 0xd2, - 0xe0, 0xeb, 0x80, 0xb8, 0x94, 0xaf, 0x20, 0xe5, 0xab, 0x83, 0x67, 0x7e, 0xda, 0xff, 0x52, 0x69, 0x4f, 0xfc, 0xb4, - 0x43, 0x4c, 0x7b, 0xf2, 0xdc, 0x4f, 0x3b, 0x52, 0x69, 0x2f, 0xfd, 0xb4, 0xff, 0x5d, 0x0e, 0x20, 0x75, 0xcf, 0xb7, - 0xfe, 0x3b, 0xf7, 0x5a, 0x83, 0xa7, 0x50, 0x94, 0x5d, 0xc5, 0x97, 0x1c, 0x1a, 0x3d, 0xb8, 0xbd, 0xca, 0x69, 0x30, - 0xc0, 0xf6, 0x7a, 0x26, 0x21, 0xde, 0x07, 0x5f, 0xaf, 0x8b, 0x3c, 0x0c, 0xbe, 0x1e, 0x60, 0x21, 0x83, 0xaf, 0x03, - 0xf2, 0xb5, 0x31, 0x90, 0x11, 0x6c, 0x13, 0xb8, 0x50, 0xa4, 0x43, 0x1b, 0x20, 0xcc, 0x97, 0xc6, 0xd5, 0xf4, 0xaf, - 0xa2, 0x3b, 0x1b, 0xde, 0x12, 0x95, 0x9b, 0x6e, 0x50, 0xd3, 0x13, 0xf0, 0x4e, 0x80, 0x46, 0x45, 0xc1, 0x75, 0x5c, - 0x84, 0xc3, 0x61, 0x79, 0x7d, 0x49, 0xc0, 0x2e, 0x73, 0xc5, 0xe3, 0x2a, 0x0a, 0x84, 0x1c, 0xaa, 0x9f, 0x81, 0x8a, - 0x7c, 0x15, 0x20, 0x20, 0x12, 0xfc, 0x17, 0xd4, 0xf4, 0x9d, 0x64, 0x9b, 0x60, 0x78, 0xc3, 0xcf, 0x3f, 0x66, 0xd5, - 0x50, 0x89, 0x16, 0xaf, 0x05, 0x85, 0x1f, 0xf0, 0xd7, 0x55, 0x1d, 0xfd, 0x05, 0x6e, 0xdc, 0x4d, 0x0d, 0xfb, 0x3b, - 0xe9, 0x58, 0xd4, 0x77, 0x72, 0x9e, 0x2d, 0xa6, 0xad, 0x03, 0xfd, 0x44, 0x92, 0x6a, 0x9e, 0x0d, 0x82, 0x61, 0x30, - 0xe0, 0x0b, 0x76, 0x22, 0xe7, 0xdc, 0x33, 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x65, 0x03, 0xf0, 0x4d, 0x41, 0x7e, - 0x64, 0xff, 0xbf, 0xe7, 0x43, 0x14, 0x1e, 0x0e, 0x1e, 0xed, 0x93, 0x59, 0xb0, 0xba, 0x45, 0x8f, 0xce, 0x28, 0xc8, - 0xc4, 0x92, 0x17, 0x59, 0xe5, 0x2d, 0x95, 0xbb, 0x75, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x15, 0x8b, 0x40, 0x9d, - 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb0, 0x37, 0x1c, - 0xee, 0x05, 0x03, 0xa7, 0xce, 0x1d, 0x04, 0x7b, 0xc3, 0xe1, 0x51, 0xe0, 0xee, 0x43, 0xd9, 0xc8, 0xdd, 0x19, 0x69, - 0xc1, 0xfe, 0x59, 0x84, 0x25, 0x05, 0xf1, 0x98, 0xd4, 0xe2, 0x2f, 0x0d, 0x2e, 0x33, 0x00, 0xe8, 0x23, 0x25, 0x01, - 0x33, 0xb0, 0x32, 0x03, 0x08, 0xcd, 0x4d, 0x63, 0x76, 0x06, 0xcc, 0x23, 0x70, 0xcc, 0x23, 0x64, 0x1c, 0x00, 0xb1, - 0x24, 0xc0, 0xb9, 0x0b, 0xa2, 0x58, 0x17, 0xf2, 0x08, 0x40, 0xef, 0xf1, 0x27, 0x31, 0xa5, 0x60, 0x92, 0x8e, 0x55, - 0x08, 0x82, 0x38, 0x3e, 0xbb, 0x16, 0xad, 0xc9, 0x59, 0xa2, 0x83, 0x19, 0x49, 0x80, 0x0d, 0x31, 0xb0, 0x73, 0x70, - 0x3f, 0x07, 0xa5, 0x87, 0xd5, 0x3b, 0x21, 0x17, 0x7c, 0xc7, 0x3d, 0xd9, 0x2c, 0x5c, 0x3d, 0xe1, 0x20, 0xb8, 0xe3, - 0x9a, 0x05, 0x18, 0x55, 0xc5, 0xba, 0xac, 0x78, 0xfa, 0xe1, 0x6e, 0x05, 0xb1, 0xef, 0x70, 0x40, 0xdf, 0xc9, 0x3c, - 0x4b, 0xee, 0x42, 0x67, 0xcf, 0xb5, 0x51, 0xe9, 0x3f, 0x7c, 0x78, 0xf3, 0x73, 0x04, 0x22, 0xc7, 0xda, 0x50, 0xfa, - 0x3b, 0x8e, 0x67, 0x93, 0x1f, 0xe1, 0xc9, 0xdf, 0xd8, 0x77, 0xdc, 0x9e, 0x1e, 0xfd, 0x3e, 0xd4, 0x4d, 0xef, 0xf8, - 0xec, 0x8e, 0x8f, 0x5c, 0x71, 0xa8, 0xae, 0x70, 0x5f, 0xdf, 0xac, 0x7d, 0x23, 0xa4, 0x87, 0xe7, 0x99, 0xf2, 0xc6, - 0xfc, 0x68, 0x07, 0xc3, 0x20, 0x98, 0x6a, 0xa1, 0x24, 0x44, 0xdd, 0x60, 0x4a, 0xc0, 0x10, 0xed, 0xe9, 0x65, 0x35, - 0x45, 0xce, 0x4d, 0x8d, 0x2c, 0xbc, 0x1f, 0x30, 0x2d, 0x74, 0x68, 0xe4, 0x50, 0x7e, 0x70, 0x38, 0x61, 0xcc, 0xc2, - 0x6f, 0x95, 0x30, 0xfd, 0x6a, 0x51, 0x39, 0x07, 0xd1, 0x3d, 0x30, 0xc6, 0x15, 0xbc, 0x80, 0xae, 0xb0, 0xeb, 0xb5, - 0x8a, 0x8a, 0x81, 0xe0, 0x71, 0xc8, 0x01, 0x7a, 0xd8, 0x05, 0x2d, 0x2b, 0x4b, 0x75, 0xab, 0x72, 0x96, 0x2a, 0xea, - 0x32, 0x94, 0x95, 0xb1, 0xc2, 0x7c, 0x2f, 0xd9, 0x0f, 0x05, 0x7a, 0x96, 0x4f, 0x45, 0x17, 0xbc, 0x10, 0x4a, 0xb0, - 0x5c, 0xd7, 0x3b, 0x11, 0x88, 0x3a, 0x3f, 0xf4, 0xae, 0xfa, 0x1a, 0xc7, 0x8e, 0xa7, 0x6f, 0x64, 0xca, 0xb5, 0x09, - 0x85, 0xe6, 0xf3, 0xa5, 0xaf, 0x98, 0x28, 0xd8, 0x0d, 0xf4, 0xab, 0x6d, 0xa3, 0xcf, 0xee, 0xd6, 0x7a, 0x33, 0x28, - 0xd1, 0x31, 0xaf, 0x51, 0x70, 0xad, 0x14, 0x0a, 0x46, 0x7b, 0x1b, 0x7f, 0x86, 0x23, 0xb7, 0xba, 0x3d, 0xf4, 0x7e, - 0xab, 0xe2, 0xcb, 0xb7, 0xe8, 0xdb, 0x69, 0x7f, 0x8e, 0x2a, 0xf9, 0xeb, 0x6a, 0x05, 0x3e, 0x54, 0x10, 0x59, 0xc4, - 0xe2, 0xd2, 0x42, 0x3d, 0xa7, 0xef, 0x8e, 0xdf, 0x82, 0x1f, 0x25, 0xfe, 0xfe, 0xed, 0xfb, 0xa0, 0x26, 0xd3, 0x78, - 0x56, 0x98, 0x0f, 0x6d, 0x0e, 0x08, 0x4d, 0xe2, 0xd2, 0xec, 0xfb, 0x59, 0xdc, 0x64, 0xdf, 0x35, 0x5b, 0x4f, 0x8b, - 0x26, 0x92, 0x94, 0xe1, 0xf6, 0xc1, 0x80, 0x40, 0x1f, 0x20, 0x8a, 0xb3, 0x2f, 0x68, 0x0c, 0x69, 0x3e, 0xb3, 0xef, - 0x47, 0xc4, 0x7b, 0xb9, 0x13, 0x42, 0x8c, 0x2b, 0x2c, 0x1a, 0x3d, 0xe4, 0x33, 0x1e, 0x29, 0xc3, 0xa2, 0xf7, 0x98, - 0x40, 0x9c, 0xe1, 0xb4, 0x7a, 0x8f, 0x98, 0xc7, 0x78, 0x37, 0xd0, 0xb2, 0x87, 0x28, 0xa3, 0x2e, 0x7b, 0xc3, 0xe2, - 0xfb, 0xe3, 0x3a, 0xcc, 0xac, 0xe5, 0xe5, 0x10, 0xfe, 0x06, 0xda, 0x00, 0x9c, 0x72, 0x64, 0xf9, 0x2a, 0xb3, 0xd1, - 0xd5, 0x12, 0xd3, 0x9b, 0x08, 0x62, 0xf1, 0xe8, 0x74, 0x58, 0xbb, 0x3a, 0x55, 0xef, 0x6a, 0xe7, 0x33, 0xd1, 0xab, - 0x40, 0x2b, 0xd7, 0xb6, 0xc7, 0x43, 0xb8, 0x4b, 0x2d, 0xad, 0xb0, 0x11, 0xe5, 0x5c, 0x3c, 0xdd, 0x39, 0x36, 0x27, - 0xa0, 0xc1, 0x95, 0x4c, 0x01, 0x38, 0x4b, 0xab, 0xd1, 0xa8, 0x11, 0xf6, 0x59, 0x39, 0x9f, 0xc3, 0xd6, 0x42, 0x3c, - 0x2d, 0x00, 0xc3, 0x6d, 0x62, 0x50, 0xf2, 0x6e, 0x0c, 0xca, 0xe9, 0x47, 0x05, 0x6f, 0x1d, 0x9c, 0x95, 0xcb, 0x38, - 0x95, 0x37, 0x80, 0xc5, 0x18, 0xf8, 0xa9, 0x58, 0xaa, 0x97, 0x90, 0x2c, 0x79, 0xf2, 0x11, 0xad, 0x36, 0xd2, 0x00, - 0xb8, 0xca, 0xa9, 0xb1, 0xdc, 0x53, 0x20, 0xa1, 0xae, 0x14, 0x95, 0x10, 0x57, 0x55, 0x9c, 0x2c, 0x4f, 0x31, 0x35, - 0xdc, 0x40, 0x2f, 0xa2, 0x40, 0xae, 0xb8, 0x00, 0x92, 0x9e, 0xb3, 0x7f, 0x65, 0x1a, 0x6b, 0xfc, 0xb9, 0x44, 0x01, - 0x93, 0x46, 0x0d, 0xc6, 0x4a, 0xd9, 0x4b, 0x69, 0xa2, 0xbd, 0x05, 0x41, 0xed, 0x5e, 0xfe, 0x05, 0x75, 0x3f, 0x87, - 0x56, 0x84, 0x0d, 0x30, 0x44, 0x79, 0x8e, 0x3b, 0x34, 0xb5, 0x4b, 0xce, 0x03, 0x46, 0x74, 0xde, 0x67, 0xb5, 0xdd, - 0xea, 0xcf, 0x97, 0x80, 0x6d, 0x9a, 0x1a, 0x9f, 0xc2, 0x30, 0x21, 0x26, 0x36, 0xb0, 0x55, 0x56, 0xda, 0x0d, 0x65, - 0xda, 0x49, 0x97, 0xcc, 0x6b, 0xe1, 0x34, 0xef, 0x31, 0xb6, 0x1c, 0xa9, 0xdc, 0xfd, 0x7e, 0x68, 0x7e, 0xb2, 0x9c, - 0x3e, 0xd7, 0x21, 0x9b, 0xbd, 0xf1, 0xa0, 0x39, 0xd1, 0xea, 0xaa, 0x8e, 0x7e, 0x40, 0x07, 0x60, 0xa6, 0x2d, 0x40, - 0xa6, 0x0b, 0x36, 0xed, 0x2b, 0x51, 0x71, 0x49, 0xc2, 0x52, 0x49, 0x60, 0x67, 0x37, 0x25, 0x3b, 0x9b, 0x80, 0x78, - 0x86, 0xbb, 0x9e, 0x16, 0x3b, 0x21, 0x4d, 0x78, 0x8b, 0xbd, 0x04, 0x44, 0x1d, 0xaa, 0xba, 0x84, 0x6c, 0x8c, 0xa1, - 0x8b, 0x7f, 0x51, 0x0a, 0x13, 0xd6, 0x32, 0xa9, 0x4a, 0x4c, 0x10, 0xa4, 0x72, 0xb7, 0x45, 0x60, 0x89, 0x82, 0x1d, - 0xc0, 0xde, 0xbb, 0x51, 0x37, 0xa3, 0xa6, 0xaa, 0x53, 0x2f, 0xc1, 0xc7, 0x69, 0xd6, 0x55, 0x90, 0x59, 0xd8, 0x55, - 0xb1, 0xe6, 0x81, 0x8e, 0x4d, 0xa5, 0x8c, 0x89, 0xbb, 0xb4, 0xc8, 0x10, 0x0f, 0x18, 0x63, 0xe9, 0x42, 0x20, 0xdf, - 0x6c, 0x77, 0xdc, 0xf4, 0x04, 0xa1, 0x9f, 0xb0, 0xa1, 0x04, 0x6e, 0x3a, 0xdb, 0x53, 0xd3, 0xcc, 0x07, 0x44, 0x1c, - 0x06, 0x14, 0x48, 0x36, 0x0e, 0x69, 0x8e, 0xf4, 0x05, 0x49, 0x13, 0x06, 0x86, 0x56, 0x3c, 0x27, 0xc8, 0x8a, 0x42, - 0xcf, 0xd6, 0x55, 0x1b, 0xe7, 0xca, 0x30, 0x47, 0x4b, 0x4e, 0x85, 0xcf, 0x09, 0x32, 0xb1, 0x7b, 0xda, 0x66, 0x26, - 0xc3, 0x51, 0xb2, 0xc0, 0xfc, 0x0a, 0xa2, 0xc4, 0x9d, 0x69, 0x56, 0xe5, 0x60, 0x5c, 0xc0, 0x02, 0xad, 0x7c, 0x0f, - 0xea, 0xc6, 0x1a, 0xda, 0x68, 0x18, 0x62, 0xb7, 0x3f, 0xc1, 0x7e, 0xad, 0x9d, 0xd6, 0x65, 0x8a, 0xe5, 0x65, 0x0a, - 0xd1, 0x5e, 0xc8, 0xfc, 0x46, 0x91, 0xe8, 0x4e, 0x11, 0x86, 0x84, 0x75, 0x94, 0x3d, 0x69, 0x53, 0x03, 0xe8, 0xa9, - 0x17, 0xf0, 0xbc, 0x73, 0x2d, 0xc3, 0x2e, 0xd2, 0xfd, 0x55, 0xc1, 0xa7, 0x74, 0x83, 0x20, 0x45, 0x6f, 0x52, 0x30, - 0xe7, 0xf5, 0x28, 0xa9, 0x37, 0xa7, 0x2d, 0x33, 0xaa, 0x8e, 0x8a, 0x90, 0x72, 0x82, 0xff, 0xe4, 0xa5, 0xd4, 0xc4, - 0x26, 0x4c, 0xf0, 0xc0, 0x87, 0x79, 0x86, 0x0d, 0xbc, 0xdd, 0xbe, 0x4b, 0xc3, 0xa4, 0xcd, 0x36, 0xa4, 0x20, 0xad, - 0x30, 0x71, 0x31, 0xa0, 0xb2, 0xd7, 0xb8, 0x5f, 0xb0, 0x9d, 0x34, 0x05, 0x0f, 0xc2, 0x46, 0x03, 0x13, 0xb7, 0xba, - 0xf8, 0x3a, 0x4c, 0x68, 0xb8, 0xa4, 0xda, 0xd9, 0x49, 0x4b, 0x9a, 0xdb, 0xeb, 0xf2, 0xc2, 0xf6, 0x41, 0xc7, 0x0e, - 0xeb, 0x1a, 0x1e, 0x68, 0x5e, 0xb3, 0x8b, 0x2b, 0xa6, 0x69, 0xa2, 0xb1, 0x1e, 0x52, 0x96, 0x1c, 0xeb, 0x7a, 0xba, - 0xc2, 0xd5, 0x32, 0xd3, 0xc0, 0xee, 0x12, 0x2f, 0xf4, 0x80, 0x87, 0x1d, 0xae, 0x48, 0x74, 0x81, 0xcd, 0x66, 0xab, - 0x9a, 0x4c, 0xf3, 0xfb, 0xb2, 0xe5, 0x26, 0x20, 0x9c, 0xa5, 0xbe, 0xb9, 0x4f, 0x8e, 0x35, 0x6d, 0xf3, 0x93, 0x00, - 0xc7, 0xdb, 0x2b, 0x20, 0xe9, 0x58, 0x82, 0x2e, 0xbe, 0xa5, 0x3f, 0x88, 0xd4, 0x4c, 0x05, 0xbd, 0x77, 0xbe, 0x48, - 0xdd, 0xfc, 0x02, 0x6c, 0xa3, 0x36, 0xc6, 0x34, 0x2b, 0x5b, 0x87, 0x89, 0xb2, 0xb0, 0x46, 0x16, 0x72, 0x09, 0x3e, - 0x98, 0xbb, 0x4d, 0x9d, 0x1e, 0x77, 0x10, 0x61, 0xbf, 0x8b, 0x1e, 0x8f, 0x30, 0x56, 0xac, 0x41, 0x62, 0x58, 0x85, - 0x35, 0x6d, 0x2e, 0x87, 0x28, 0xa7, 0x66, 0xc9, 0x44, 0x4b, 0xea, 0x53, 0x8a, 0x28, 0x05, 0x73, 0xe3, 0x69, 0xd9, - 0x30, 0x25, 0x44, 0xc8, 0x0a, 0xe9, 0x80, 0x6a, 0x2d, 0xb4, 0x54, 0x13, 0xf4, 0x3a, 0xf4, 0xb2, 0xd0, 0x98, 0x82, - 0xe8, 0x23, 0x32, 0xdc, 0x88, 0x23, 0xa3, 0xbb, 0x63, 0x14, 0x13, 0x08, 0x55, 0xed, 0xe5, 0x85, 0xd5, 0xa7, 0x65, - 0x5b, 0x1d, 0xc4, 0x15, 0x22, 0xdf, 0x77, 0x13, 0xd4, 0x18, 0x05, 0x6d, 0x4e, 0x37, 0xfa, 0x6b, 0x11, 0xfa, 0x76, - 0xe1, 0xd8, 0x8d, 0x82, 0x48, 0x88, 0xc0, 0xea, 0x35, 0x15, 0x03, 0xb2, 0xce, 0x63, 0x17, 0xa1, 0x49, 0x77, 0x0b, - 0x51, 0xde, 0xa8, 0xac, 0x3f, 0xae, 0x43, 0xb2, 0xdd, 0x62, 0x59, 0xe0, 0xcb, 0x7e, 0xba, 0xbe, 0x07, 0xf2, 0xfb, - 0xcd, 0xfa, 0xb3, 0x90, 0xdf, 0xaf, 0xb3, 0x2f, 0x81, 0xfc, 0x7e, 0xb3, 0xfe, 0x9f, 0x86, 0xfc, 0x3e, 0x5d, 0x7b, - 0x90, 0xdf, 0x6a, 0x30, 0x7e, 0x2f, 0x58, 0x70, 0xf2, 0x36, 0xa0, 0x2f, 0x24, 0x0b, 0x4e, 0x5e, 0xbd, 0xf2, 0x8d, - 0x40, 0x84, 0x46, 0xae, 0x37, 0xb2, 0x60, 0xc4, 0x6d, 0x81, 0x57, 0xa8, 0x75, 0xf2, 0x81, 0x8a, 0x32, 0x00, 0x5e, - 0x2f, 0xff, 0x91, 0x55, 0xcb, 0x30, 0xd8, 0x0f, 0xc8, 0xcc, 0x41, 0x82, 0x0e, 0x27, 0x70, 0x7b, 0x43, 0x23, 0xcb, - 0xea, 0x8b, 0xe0, 0xc3, 0x47, 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0xa5, 0xce, 0x6c, 0x24, 0x04, 0x3c, 0xce, 0x78, 0x69, - 0x43, 0x44, 0x2c, 0xe3, 0xf2, 0x4c, 0xc7, 0x66, 0x29, 0xed, 0x56, 0x84, 0x88, 0xf3, 0x67, 0x80, 0x53, 0x6f, 0xf7, - 0x66, 0x8c, 0xfd, 0x50, 0x1c, 0xb1, 0x0e, 0x20, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, - 0x06, 0xbd, 0x84, 0xbb, 0x88, 0xe0, 0x49, 0xe5, 0xb1, 0x4d, 0x0a, 0xa8, 0x3c, 0xd3, 0x40, 0xe5, 0x1d, 0xef, 0x69, - 0x68, 0x87, 0x45, 0xfb, 0x00, 0x1b, 0xe9, 0x72, 0x06, 0x46, 0x8b, 0x2f, 0xaf, 0xb9, 0xa8, 0x7e, 0x06, 0x3c, 0x75, - 0xc1, 0x0b, 0xb8, 0x25, 0x20, 0x17, 0xdb, 0x70, 0x42, 0xa0, 0xc2, 0xf7, 0xec, 0x50, 0x51, 0x63, 0x8c, 0x68, 0xa2, - 0xd1, 0x6f, 0xbc, 0x09, 0xa1, 0x77, 0x27, 0xe8, 0x8a, 0x30, 0x12, 0xde, 0x5f, 0x6b, 0x7e, 0x96, 0x81, 0xf9, 0xbc, - 0x00, 0x28, 0x0d, 0x84, 0x43, 0x65, 0x4a, 0x6e, 0x81, 0x09, 0x1b, 0x63, 0xae, 0x94, 0xa5, 0x1e, 0x52, 0x29, 0x55, - 0x70, 0xba, 0x82, 0xa6, 0x12, 0x70, 0xb8, 0x23, 0x09, 0x60, 0xa6, 0xb6, 0x30, 0x88, 0x6e, 0x9b, 0xd2, 0x2c, 0x8d, - 0x9c, 0x22, 0xcd, 0xe1, 0x93, 0x52, 0x05, 0x3a, 0x7d, 0x96, 0xc4, 0x15, 0xbf, 0x94, 0x05, 0x84, 0xc2, 0x6d, 0xa5, - 0x50, 0xa4, 0xdf, 0x67, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0x39, 0x5b, 0x66, 0x65, 0x05, 0xf9, 0xe6, 0xfa, 0xf4, 0x5b, - 0xd4, 0xd3, 0x02, 0xe7, 0x4d, 0x4d, 0x0a, 0x33, 0xf3, 0x78, 0xac, 0x76, 0x3a, 0xa8, 0x57, 0xbd, 0xd7, 0x06, 0xfb, - 0xbd, 0x39, 0xd1, 0xe3, 0xd6, 0x7a, 0xb0, 0x9a, 0xd4, 0x66, 0xaa, 0x82, 0x38, 0x02, 0xea, 0xc0, 0x8e, 0x70, 0x16, - 0x53, 0xba, 0xb6, 0x08, 0x2a, 0x60, 0xed, 0x80, 0x39, 0x32, 0x71, 0x79, 0x76, 0xa3, 0xe4, 0x27, 0x3d, 0x45, 0x61, - 0xd2, 0x28, 0x56, 0xc8, 0x3e, 0x4b, 0x16, 0xae, 0x59, 0x72, 0x4f, 0xae, 0x75, 0x94, 0x34, 0x30, 0xba, 0xe2, 0xf6, - 0x40, 0x1c, 0x26, 0xed, 0x94, 0xed, 0x76, 0x27, 0x13, 0xb0, 0x06, 0xad, 0x24, 0x88, 0xd6, 0xb1, 0x9c, 0x0d, 0x27, - 0x11, 0x40, 0xa8, 0x68, 0xb2, 0xf6, 0xd7, 0x9a, 0x1b, 0x90, 0xf9, 0x50, 0x7b, 0xfa, 0x39, 0x91, 0xbc, 0x1e, 0x59, - 0xcf, 0x38, 0x4e, 0x4f, 0xfb, 0x1c, 0x0c, 0xb3, 0xfc, 0x21, 0x81, 0x48, 0x30, 0x9d, 0xd3, 0xb3, 0x98, 0x6a, 0x33, - 0x61, 0xc3, 0xa3, 0xd0, 0x2f, 0xfb, 0x4e, 0x03, 0xe0, 0x26, 0x3c, 0x1c, 0x3e, 0x1b, 0x93, 0x5a, 0xdb, 0xac, 0xe3, - 0x02, 0xb2, 0xbf, 0xd5, 0x22, 0x73, 0xcf, 0x76, 0xa1, 0xd1, 0xa6, 0xb7, 0x41, 0xbb, 0x46, 0x2a, 0xee, 0xe9, 0x7e, - 0x4d, 0x6a, 0xb7, 0x60, 0xac, 0x04, 0xe9, 0x0f, 0x75, 0x6a, 0x9d, 0x3d, 0xda, 0x64, 0xba, 0xca, 0xfa, 0x8f, 0xcc, - 0xc6, 0x9b, 0x6b, 0x50, 0x80, 0x5a, 0x2f, 0x25, 0x1f, 0xee, 0xad, 0x23, 0x9b, 0x9e, 0x18, 0x96, 0x75, 0x92, 0x91, - 0x91, 0x7a, 0xe4, 0x2a, 0xfc, 0x56, 0x77, 0x16, 0x7e, 0xcb, 0x93, 0xb0, 0xab, 0x61, 0x8a, 0xc3, 0x37, 0x5d, 0x40, - 0x04, 0x4c, 0x90, 0xeb, 0x87, 0x7f, 0x3c, 0xda, 0x34, 0xc9, 0x52, 0xbd, 0xef, 0x7d, 0x86, 0xbf, 0xb3, 0x14, 0xfe, - 0x56, 0xf5, 0x1f, 0x74, 0x73, 0xc5, 0xab, 0xa5, 0x4c, 0xa3, 0xe0, 0xdd, 0xc9, 0xe9, 0x87, 0x40, 0x23, 0xab, 0xe3, - 0xfd, 0xc2, 0x68, 0x94, 0x0d, 0x86, 0x13, 0x68, 0x58, 0x72, 0x79, 0x89, 0xe0, 0x82, 0x1a, 0x9d, 0xfe, 0x74, 0x29, - 0x6f, 0x8e, 0xf3, 0xdc, 0x67, 0x82, 0x0d, 0xe1, 0xd4, 0x7c, 0x61, 0x83, 0xea, 0x84, 0x20, 0xcb, 0x1b, 0x65, 0xe5, - 0x99, 0xd6, 0xbe, 0xa4, 0x67, 0xe7, 0x77, 0x67, 0x5a, 0xc2, 0x63, 0xd1, 0x1d, 0x9f, 0xff, 0x71, 0x98, 0x66, 0xd7, - 0x7b, 0x48, 0xdd, 0x59, 0x00, 0xa6, 0xf1, 0x39, 0x3f, 0x5f, 0x57, 0x95, 0x14, 0xc3, 0x42, 0xde, 0x04, 0x47, 0x87, - 0xea, 0xc1, 0x64, 0x88, 0xd5, 0x63, 0xb0, 0xf7, 0x5f, 0x49, 0x9e, 0x25, 0x1f, 0x59, 0xf0, 0x68, 0x93, 0xb1, 0xa3, - 0x16, 0x0d, 0x1f, 0xd7, 0xc1, 0x11, 0xb4, 0x75, 0xef, 0x38, 0xcf, 0x0f, 0xf7, 0xd5, 0x17, 0x47, 0x87, 0xfb, 0x69, - 0x76, 0x7d, 0xe4, 0x01, 0xed, 0x3b, 0xbb, 0x59, 0x84, 0x34, 0x73, 0xf7, 0x62, 0x70, 0x90, 0x4d, 0x78, 0x68, 0x39, - 0x09, 0x90, 0xc6, 0x98, 0x30, 0x25, 0x28, 0xc1, 0x09, 0x63, 0x38, 0x37, 0xb7, 0xdb, 0xd0, 0x1a, 0xf5, 0x24, 0x1e, - 0xe2, 0x4d, 0x01, 0x9c, 0x06, 0x66, 0xa1, 0x09, 0xa1, 0x49, 0x4d, 0x42, 0x83, 0xcb, 0x13, 0x13, 0x5a, 0xd4, 0x14, - 0x8e, 0x92, 0x37, 0xf1, 0xca, 0x08, 0xb1, 0xb4, 0x50, 0xc0, 0xb4, 0x7e, 0xd6, 0x18, 0xc7, 0xa8, 0x3d, 0xaa, 0x06, - 0x29, 0xab, 0x57, 0xde, 0x37, 0xb0, 0x20, 0xb7, 0x0c, 0x2b, 0x1a, 0xb4, 0x28, 0x04, 0xc8, 0x1d, 0x7d, 0x71, 0x19, - 0xa7, 0xe1, 0xbc, 0xa4, 0x72, 0x41, 0xd8, 0x51, 0xb8, 0x41, 0xb6, 0xb9, 0x54, 0x54, 0x38, 0x92, 0xb5, 0x83, 0xad, - 0x54, 0xb3, 0x73, 0xf4, 0x68, 0x23, 0x10, 0x29, 0xb1, 0x64, 0x47, 0xcd, 0xf9, 0xaa, 0xe2, 0xf3, 0xe1, 0x92, 0x83, - 0x7f, 0x4d, 0xb0, 0xf7, 0x5f, 0xe9, 0x79, 0x6e, 0x27, 0x45, 0xad, 0xc8, 0x65, 0x2c, 0xd2, 0x9c, 0x7f, 0x88, 0xcf, - 0x7f, 0xc0, 0x3c, 0x2f, 0xce, 0xf3, 0xe7, 0x90, 0xa1, 0x0e, 0x8e, 0x1e, 0x6d, 0x92, 0x6a, 0xf4, 0xf2, 0xed, 0x87, - 0xd7, 0x1f, 0xfe, 0x79, 0xf6, 0xfc, 0xf8, 0xc3, 0xcb, 0xef, 0x4f, 0xde, 0xbf, 0x7e, 0x79, 0x3a, 0xb7, 0x0e, 0xad, - 0x0a, 0x27, 0x8d, 0x2c, 0xb6, 0x5b, 0x97, 0xef, 0xd7, 0xb7, 0x2f, 0x5e, 0xbe, 0x7a, 0xfd, 0xf6, 0xe5, 0x8b, 0x5a, - 0xcd, 0x65, 0xbb, 0x21, 0xb0, 0x43, 0xe3, 0x4c, 0xf0, 0x02, 0x8a, 0xd7, 0xd1, 0x1a, 0xb1, 0xd9, 0x1a, 0xde, 0xaf, - 0xd9, 0x74, 0x1d, 0x09, 0x01, 0x16, 0xd9, 0x9e, 0xde, 0x2c, 0xd0, 0x70, 0x69, 0x36, 0x8e, 0xbf, 0xc4, 0xfc, 0xde, - 0xbc, 0xc4, 0xef, 0xde, 0xcb, 0x1b, 0xd3, 0x15, 0x3d, 0x42, 0x0a, 0xb9, 0x6b, 0xf6, 0xfc, 0x8f, 0x43, 0x5f, 0x5a, - 0x86, 0x22, 0x05, 0x55, 0x2e, 0xfc, 0xaa, 0x83, 0x3d, 0x6d, 0xb9, 0x17, 0x40, 0xe0, 0x89, 0xe0, 0xe8, 0x70, 0xdf, - 0xcf, 0x7d, 0xf4, 0x47, 0xf4, 0xb3, 0xd7, 0x39, 0x2c, 0x15, 0xc6, 0xa1, 0x99, 0xb6, 0x73, 0xba, 0x41, 0x68, 0x24, - 0x77, 0xfe, 0xa9, 0x15, 0x64, 0xc8, 0x95, 0x24, 0x91, 0x9d, 0x44, 0x65, 0x91, 0x62, 0x4a, 0xfb, 0x43, 0xff, 0x75, - 0x7d, 0xc6, 0x1b, 0x3e, 0x17, 0xa5, 0x2c, 0x02, 0xe8, 0x47, 0x3b, 0x5e, 0xc4, 0x9e, 0x17, 0x97, 0x05, 0x7b, 0xd4, - 0x49, 0xde, 0x61, 0x44, 0xf6, 0xdb, 0x9f, 0x7a, 0x1d, 0xfb, 0x83, 0xb8, 0x1f, 0x7b, 0xba, 0x33, 0x2d, 0xf2, 0x62, - 0x1b, 0x78, 0x7f, 0x5c, 0x8f, 0xf9, 0x49, 0x46, 0xff, 0x21, 0xe9, 0x65, 0x4c, 0xaf, 0x62, 0x7a, 0x2a, 0x16, 0x75, - 0xe7, 0xec, 0xd8, 0x98, 0x31, 0x94, 0x4f, 0x43, 0x40, 0x9e, 0xd0, 0xf7, 0x01, 0xcd, 0x25, 0x67, 0x23, 0xad, 0x2b, - 0xfb, 0x10, 0x17, 0x97, 0xdc, 0x84, 0x6a, 0x31, 0x6f, 0x2b, 0x3d, 0x2a, 0xc4, 0x1b, 0x16, 0x80, 0x65, 0xe9, 0x69, - 0x93, 0x82, 0x6c, 0x94, 0x54, 0x45, 0xfe, 0x13, 0xbf, 0x03, 0xae, 0xad, 0xac, 0xe4, 0x0a, 0x78, 0xf5, 0xff, 0xd3, - 0xdc, 0xb3, 0x37, 0xb7, 0x6d, 0x23, 0xff, 0x7f, 0x3f, 0x05, 0xc3, 0xe4, 0x52, 0x31, 0x21, 0x69, 0x92, 0xb2, 0x6c, - 0x45, 0xb2, 0xec, 0x6b, 0xf3, 0x98, 0x4b, 0xc7, 0x6d, 0x3a, 0x89, 0x9b, 0xb9, 0xab, 0xeb, 0xb1, 0x28, 0x09, 0x92, - 0x78, 0xa1, 0x48, 0x0d, 0x49, 0xf9, 0x51, 0x85, 0xf7, 0x59, 0xee, 0xb3, 0xdc, 0x27, 0xfb, 0xcd, 0xee, 0x02, 0x20, - 0xf8, 0xd0, 0xc3, 0x4d, 0x7a, 0xf7, 0x9b, 0x36, 0x89, 0x08, 0x02, 0x4b, 0x60, 0x01, 0x2c, 0x16, 0xfb, 0xf4, 0x67, - 0x5c, 0xf6, 0x62, 0xb6, 0xd8, 0x7e, 0x9f, 0xfb, 0xfc, 0x99, 0xd9, 0xb8, 0x24, 0x81, 0xe1, 0xb3, 0xb3, 0x78, 0x36, - 0x0b, 0x59, 0x4b, 0x17, 0xc9, 0x43, 0x74, 0x53, 0x7e, 0xe6, 0xec, 0x91, 0x23, 0x22, 0x76, 0x1a, 0xf9, 0xa6, 0xad, - 0x25, 0x46, 0xcc, 0x64, 0x48, 0x3b, 0xe2, 0x5c, 0x51, 0x36, 0x7b, 0x83, 0xea, 0x0d, 0x3e, 0x2f, 0xc5, 0xd6, 0xb5, - 0x26, 0xf1, 0x6a, 0x14, 0x32, 0x0b, 0x97, 0x3b, 0x7c, 0x72, 0x3d, 0x5a, 0x8d, 0x46, 0x90, 0xa5, 0xe5, 0x91, 0x63, - 0x42, 0xdc, 0x99, 0x38, 0xc5, 0xfb, 0x60, 0x6e, 0xf4, 0x61, 0x50, 0x76, 0x56, 0xed, 0x3e, 0xd8, 0x8a, 0x80, 0xa8, - 0x87, 0x3e, 0x90, 0xc1, 0xdd, 0xaf, 0x61, 0xd7, 0x0e, 0xf4, 0x0f, 0xb0, 0xfa, 0x52, 0xbd, 0xdf, 0xb4, 0xf5, 0x07, - 0x97, 0xfa, 0x07, 0xc4, 0x31, 0x66, 0x2f, 0x7e, 0x49, 0xab, 0x57, 0x37, 0x75, 0x52, 0x7a, 0xaf, 0x30, 0x8f, 0x01, - 0x08, 0x7d, 0x5f, 0x05, 0xfe, 0x2c, 0x8a, 0xd3, 0x2c, 0x18, 0xeb, 0x57, 0xfd, 0xb7, 0x41, 0xeb, 0x72, 0x91, 0xb5, - 0x8c, 0x2b, 0x73, 0x9c, 0xa9, 0x29, 0x50, 0x04, 0xc1, 0xc4, 0x0c, 0x28, 0x9b, 0x2a, 0xa9, 0x3b, 0x68, 0x6b, 0x45, - 0x41, 0x9a, 0xb1, 0xd2, 0x38, 0x1b, 0x40, 0xbd, 0x4a, 0x3e, 0x15, 0x4c, 0x0c, 0xa5, 0x63, 0x4b, 0xa3, 0x4f, 0x37, - 0x95, 0x97, 0xab, 0x35, 0x1e, 0xe5, 0x59, 0x71, 0x5a, 0x62, 0x0c, 0x60, 0xe1, 0x38, 0x43, 0xcf, 0x8f, 0x54, 0xa3, - 0xcf, 0xd2, 0xb9, 0x3b, 0xfc, 0xae, 0xcc, 0x17, 0xc0, 0xf9, 0x0d, 0x16, 0x17, 0x51, 0x9c, 0x69, 0x10, 0xd8, 0x06, - 0xbe, 0x38, 0xac, 0x1a, 0x89, 0x71, 0xa8, 0x2d, 0x23, 0xe7, 0xc4, 0xe0, 0x7b, 0x3c, 0xfc, 0x5a, 0x3c, 0xbc, 0x59, - 0x29, 0x82, 0x05, 0x5d, 0x16, 0x22, 0x98, 0xc0, 0x2c, 0x3e, 0x8f, 0x6f, 0xab, 0x7a, 0x90, 0x97, 0xc3, 0xdd, 0x67, - 0x6f, 0x4b, 0xb0, 0xc9, 0x22, 0xab, 0x5f, 0x8b, 0x27, 0x26, 0x15, 0x8c, 0x4e, 0x65, 0x4f, 0xa1, 0xe1, 0x87, 0xe0, - 0x61, 0x32, 0xb0, 0x13, 0xc3, 0xb3, 0x00, 0x48, 0x12, 0x3f, 0xa6, 0x87, 0xf9, 0xb5, 0x48, 0x9d, 0x2c, 0x12, 0x17, - 0x2b, 0x87, 0x33, 0x50, 0xd7, 0x68, 0xb9, 0xca, 0x30, 0xd4, 0x2e, 0x74, 0x80, 0xe5, 0xba, 0x86, 0xa1, 0x3b, 0x81, - 0x4a, 0x17, 0x6c, 0x62, 0xae, 0x6b, 0xc1, 0xa4, 0x5e, 0xc6, 0x99, 0x5e, 0x20, 0x5e, 0x48, 0xdf, 0x51, 0x50, 0x05, - 0x8f, 0x09, 0x1f, 0xc6, 0xd8, 0x2c, 0xe2, 0xd4, 0xb7, 0xc6, 0xa8, 0xd0, 0x69, 0xa0, 0x0c, 0x63, 0x82, 0xd3, 0x6f, - 0x85, 0x8d, 0x83, 0x85, 0xf0, 0x9b, 0xa5, 0x61, 0x0e, 0x9f, 0xac, 0xa3, 0xfc, 0xec, 0xc9, 0x3a, 0xcd, 0x07, 0x4f, - 0xd6, 0xbe, 0xb4, 0x15, 0xd0, 0x2f, 0x74, 0x32, 0x14, 0x18, 0x22, 0x1a, 0x86, 0xf9, 0x75, 0xe1, 0xb9, 0x53, 0x8c, - 0x17, 0x56, 0x19, 0x95, 0x6b, 0xa8, 0xba, 0x1f, 0x70, 0x05, 0xfd, 0x32, 0x09, 0x16, 0x7e, 0x72, 0x4f, 0xfa, 0x7c, - 0x53, 0x55, 0xfa, 0x1b, 0xba, 0x46, 0x84, 0x9e, 0x10, 0x40, 0x34, 0x5f, 0xd7, 0xfe, 0x2a, 0xcb, 0x18, 0x1f, 0xad, - 0x54, 0x6a, 0xc2, 0xb7, 0xae, 0xf5, 0xe7, 0xcc, 0x9e, 0xb0, 0xcc, 0x0f, 0x42, 0x6a, 0xd2, 0x17, 0xd9, 0xea, 0x6b, - 0xc3, 0x4b, 0xcb, 0xc3, 0x8b, 0xca, 0xeb, 0x07, 0x07, 0x43, 0x47, 0x00, 0xf5, 0x1b, 0x47, 0x86, 0x59, 0xac, 0x9a, - 0x67, 0x94, 0xde, 0xfd, 0x57, 0xa7, 0x83, 0xc1, 0x74, 0x44, 0x30, 0x1d, 0x2c, 0x1a, 0xc7, 0x13, 0xf6, 0xcb, 0xfb, - 0xb7, 0x32, 0x6d, 0x16, 0x48, 0x80, 0x86, 0x7c, 0x61, 0xa6, 0xc8, 0x3f, 0x24, 0xc8, 0x3b, 0x50, 0x82, 0x2b, 0x4d, - 0x2e, 0xa1, 0x24, 0xd7, 0xb5, 0x33, 0xea, 0x3b, 0x9b, 0x50, 0xaf, 0x07, 0x31, 0xb6, 0x4a, 0xf2, 0x93, 0x03, 0xaa, - 0x4d, 0xa7, 0x1d, 0x55, 0x02, 0x34, 0x24, 0x30, 0xc2, 0x02, 0x0b, 0x90, 0xe1, 0x73, 0xe0, 0x16, 0x17, 0x0a, 0x7b, - 0x81, 0x72, 0x76, 0xf7, 0xac, 0xcc, 0xaa, 0x60, 0x2b, 0xfd, 0xf4, 0x04, 0x73, 0x76, 0xc1, 0x79, 0x0d, 0x51, 0x3e, - 0x4e, 0x0e, 0xe8, 0x51, 0xab, 0xec, 0x88, 0x02, 0x88, 0xb8, 0xda, 0xf5, 0x38, 0x80, 0x07, 0x6d, 0x15, 0x48, 0x11, - 0x0f, 0xa5, 0x7e, 0xae, 0x6b, 0x0b, 0xce, 0x1a, 0xf1, 0x70, 0x42, 0x10, 0x6b, 0xc0, 0x81, 0xbd, 0xab, 0x6b, 0x0b, - 0xff, 0x0e, 0x47, 0x2e, 0xde, 0xf8, 0x77, 0x2d, 0x97, 0xbf, 0x2a, 0xf6, 0x5a, 0x5a, 0xde, 0x6b, 0x63, 0x3e, 0xb9, - 0xe0, 0x48, 0x20, 0x6f, 0xd6, 0x73, 0x54, 0xd0, 0x36, 0x4c, 0xee, 0x5c, 0x4c, 0xee, 0x64, 0xc3, 0xe4, 0x4e, 0xb6, - 0x4c, 0x6e, 0xc8, 0x27, 0x52, 0x93, 0xa8, 0x4b, 0xd0, 0x39, 0x4c, 0x22, 0x8f, 0x33, 0x1a, 0x3d, 0xbe, 0xcf, 0x10, - 0x4f, 0x56, 0x1a, 0x82, 0x71, 0xd4, 0x06, 0x5c, 0x35, 0xe1, 0x45, 0x41, 0x44, 0x7d, 0xe0, 0x72, 0xd7, 0x89, 0x71, - 0x43, 0x0e, 0xce, 0x56, 0x58, 0x1d, 0x2f, 0xac, 0x52, 0xca, 0x2f, 0xde, 0x9a, 0x6f, 0x18, 0xe9, 0x7c, 0xcb, 0x48, - 0xc7, 0xa5, 0xad, 0xcb, 0x87, 0x4d, 0x9b, 0x50, 0x1d, 0x14, 0xac, 0x41, 0x30, 0x18, 0xc5, 0x25, 0x53, 0x5e, 0x87, - 0x9b, 0x69, 0xac, 0xb2, 0xa2, 0x96, 0x7e, 0x9a, 0xde, 0xc6, 0x09, 0x68, 0x5c, 0x00, 0xcc, 0xc3, 0x96, 0xd4, 0x22, - 0x88, 0x78, 0x30, 0x97, 0x8d, 0x8b, 0xa9, 0x78, 0xaf, 0x2e, 0x29, 0xaf, 0xd3, 0xa1, 0x1a, 0x4b, 0x3f, 0xcb, 0x58, - 0x82, 0x48, 0xf7, 0x21, 0xea, 0xf7, 0xff, 0x93, 0x65, 0xd6, 0x40, 0x43, 0x42, 0x85, 0xaa, 0x23, 0x85, 0x5e, 0x02, - 0x6f, 0x95, 0x88, 0x83, 0x58, 0x09, 0x0c, 0x97, 0x48, 0xc4, 0xff, 0x84, 0xdb, 0xb5, 0x95, 0x28, 0xae, 0x4b, 0xee, - 0x91, 0x61, 0x2f, 0xfd, 0xc9, 0x07, 0x50, 0xec, 0xb5, 0x3c, 0x13, 0x8c, 0x74, 0xd5, 0x30, 0x70, 0x09, 0x31, 0x7b, - 0xe3, 0x82, 0x48, 0x22, 0x95, 0xe4, 0x26, 0x50, 0xe0, 0x3d, 0xe9, 0x5b, 0xd3, 0xab, 0xb5, 0x97, 0x1f, 0xcc, 0x02, - 0xa3, 0x46, 0x35, 0x81, 0xb4, 0x85, 0x83, 0x53, 0x79, 0xe7, 0x0a, 0x4d, 0xf7, 0xc8, 0x00, 0xc9, 0xef, 0x25, 0xe4, - 0x33, 0x75, 0xc4, 0x85, 0x76, 0x98, 0xc0, 0xa9, 0x75, 0xe9, 0x5c, 0xe5, 0x4f, 0x67, 0xf8, 0xcb, 0xbd, 0xca, 0x9f, - 0x8e, 0xf0, 0x97, 0x77, 0x85, 0x99, 0xeb, 0x1a, 0x2e, 0xf2, 0xca, 0x98, 0xf5, 0xd3, 0xd2, 0x7a, 0x22, 0xfb, 0xb3, - 0x07, 0x2c, 0x1b, 0x3e, 0xc1, 0x8f, 0x9f, 0xac, 0x53, 0xf0, 0xb8, 0x54, 0xc7, 0x10, 0xd9, 0x89, 0x91, 0x37, 0x96, - 0xcf, 0x36, 0x94, 0x8f, 0x8c, 0xff, 0xf2, 0xc1, 0x8f, 0xab, 0x24, 0x2e, 0xce, 0x94, 0xb2, 0x18, 0xe2, 0x7a, 0x14, - 0x44, 0x7e, 0x72, 0x7f, 0x4d, 0xd7, 0x8b, 0x96, 0xe0, 0xdd, 0xa5, 0x78, 0x85, 0xd8, 0xcb, 0xb2, 0xba, 0x2b, 0x53, - 0x04, 0xbc, 0xf7, 0xfc, 0xa0, 0x1f, 0xfc, 0x3d, 0x51, 0xd8, 0xb6, 0xd2, 0x05, 0x94, 0x4f, 0x48, 0xe9, 0x43, 0xd7, - 0x4f, 0xd6, 0x2d, 0x56, 0x07, 0x53, 0x19, 0x6d, 0x85, 0x2f, 0x84, 0xe9, 0xc1, 0xcb, 0xec, 0x62, 0x12, 0xf4, 0x50, - 0x9f, 0x35, 0x8a, 0xef, 0xac, 0x27, 0xeb, 0xec, 0x4c, 0x5f, 0xf8, 0xc9, 0x27, 0x36, 0xb1, 0xc6, 0x41, 0x32, 0x0e, - 0x99, 0xde, 0xd3, 0x47, 0xa1, 0x1f, 0x7d, 0xe2, 0x8f, 0x56, 0xbc, 0xca, 0x50, 0x43, 0xbd, 0xf3, 0xee, 0x2b, 0x70, - 0x42, 0x22, 0x3b, 0x64, 0x56, 0x1b, 0xb0, 0xa0, 0xbd, 0x94, 0x02, 0xaf, 0x82, 0x51, 0x2c, 0x6a, 0x99, 0x60, 0x60, - 0x09, 0x4a, 0x73, 0xf0, 0x58, 0x35, 0x75, 0x9c, 0x2f, 0xdd, 0x54, 0x87, 0x4a, 0xc2, 0x4a, 0x99, 0x72, 0xf1, 0x1a, - 0x21, 0xfc, 0xf1, 0xcf, 0x51, 0x32, 0xec, 0xfd, 0x3f, 0x27, 0xa1, 0x7c, 0xd9, 0x08, 0xa1, 0xd4, 0x22, 0x4f, 0x89, - 0x07, 0x7c, 0x9c, 0x33, 0x98, 0x9b, 0x3f, 0xad, 0x36, 0xf6, 0xd3, 0x74, 0xb5, 0x60, 0x13, 0xd2, 0x0c, 0x9e, 0x15, - 0x9d, 0x2a, 0xdf, 0x2c, 0xd4, 0x8e, 0xfd, 0xb6, 0xf2, 0x8e, 0x0f, 0x5f, 0x82, 0xc5, 0x02, 0x30, 0x94, 0xf1, 0x74, - 0xaa, 0x17, 0x77, 0xfc, 0x1d, 0xcd, 0xdc, 0xc3, 0xdf, 0x56, 0x6f, 0x5e, 0x3b, 0x6f, 0x64, 0xe3, 0x08, 0x18, 0x63, - 0xa1, 0x7e, 0xe5, 0x7c, 0xb1, 0xd2, 0x5f, 0x31, 0xa2, 0xa9, 0x1f, 0x6d, 0x1e, 0xce, 0x65, 0x69, 0x89, 0x2f, 0x19, - 0x9b, 0x00, 0xc3, 0x6d, 0xd6, 0x4a, 0xaf, 0x43, 0x76, 0xc3, 0xa4, 0x6a, 0xb7, 0xfe, 0xb1, 0x86, 0x16, 0x18, 0x7b, - 0x8e, 0xab, 0x8c, 0x39, 0x57, 0xa7, 0x0c, 0x69, 0x88, 0x63, 0xe0, 0x23, 0x57, 0xb7, 0x58, 0x65, 0x4b, 0x0d, 0x4d, - 0x5d, 0xe9, 0xc0, 0xc6, 0x9e, 0x9d, 0x6d, 0x28, 0xef, 0x61, 0xe2, 0xe9, 0xe6, 0xbe, 0x99, 0xae, 0xd1, 0x83, 0x58, - 0xdd, 0x1c, 0x4f, 0x21, 0xec, 0xbc, 0x56, 0x21, 0x0e, 0xd9, 0x84, 0xb1, 0x26, 0x21, 0x99, 0x4e, 0xd2, 0x17, 0x61, - 0xed, 0x88, 0x66, 0xbf, 0x42, 0x0e, 0xd5, 0x38, 0x37, 0x5a, 0x79, 0xe4, 0x23, 0x4c, 0xe8, 0x1a, 0xb1, 0x34, 0xdd, - 0x88, 0x30, 0x39, 0xe9, 0xa6, 0x5e, 0xd4, 0x2e, 0xe3, 0xa3, 0x28, 0x37, 0x1d, 0x13, 0x58, 0x02, 0x1c, 0x60, 0xf5, - 0x5b, 0x78, 0xbc, 0x5c, 0x2f, 0xb8, 0xbd, 0x4a, 0x32, 0x1b, 0xe9, 0xdc, 0x96, 0x60, 0xd3, 0xfb, 0x5b, 0x9d, 0x77, - 0xaa, 0x74, 0x4c, 0x37, 0x76, 0xad, 0x55, 0x22, 0xbd, 0x35, 0x71, 0x11, 0x02, 0x10, 0x7d, 0xaa, 0xd0, 0x57, 0x36, - 0x9d, 0xb2, 0x71, 0x96, 0x1a, 0x42, 0x78, 0x24, 0xa3, 0xc7, 0x82, 0xd7, 0xd0, 0xa3, 0x81, 0xfe, 0x13, 0xf8, 0xd0, - 0x8b, 0x20, 0x4b, 0xbc, 0x43, 0xe2, 0xce, 0xd4, 0x8c, 0x26, 0x82, 0x58, 0x46, 0x11, 0xff, 0x0a, 0x24, 0x07, 0x6f, - 0x28, 0xc7, 0xae, 0xf1, 0xf3, 0xa7, 0x58, 0x17, 0xb1, 0xb4, 0x6a, 0xd9, 0x4e, 0x8a, 0xb6, 0x6d, 0xdf, 0xb5, 0xfb, - 0xa6, 0xe3, 0x3a, 0xb9, 0x6e, 0x82, 0xef, 0xd6, 0xa7, 0x7d, 0x37, 0x3d, 0xb6, 0x6a, 0x43, 0xab, 0x55, 0xf4, 0x90, - 0x76, 0x9e, 0xfb, 0xc2, 0xd5, 0x4d, 0x32, 0x99, 0x53, 0x68, 0xdb, 0x38, 0xbe, 0x61, 0xc9, 0x17, 0x0f, 0xa5, 0x0c, - 0x7c, 0xbf, 0xfe, 0x1c, 0xb9, 0x0e, 0x10, 0xe1, 0x2c, 0x5e, 0x3e, 0x60, 0x08, 0x6d, 0xdd, 0xd4, 0xc7, 0x61, 0x9c, - 0x32, 0x75, 0x0c, 0x24, 0x04, 0xf9, 0xc2, 0x41, 0xfc, 0xfc, 0xfe, 0xf5, 0x87, 0x0f, 0xba, 0x89, 0x99, 0x40, 0x53, - 0x15, 0x3a, 0x5f, 0x50, 0x3b, 0xa8, 0x7f, 0xe3, 0xba, 0xa3, 0x13, 0x86, 0x2e, 0xb5, 0xe5, 0x35, 0x47, 0x65, 0xb5, - 0x25, 0xc7, 0x4f, 0x1e, 0xfe, 0x65, 0xba, 0x89, 0xee, 0x35, 0xae, 0x06, 0xda, 0xb0, 0xfd, 0x78, 0x2b, 0x95, 0x2c, - 0x82, 0xe8, 0xba, 0xa1, 0xd4, 0xbf, 0x6b, 0x28, 0x85, 0xab, 0x5c, 0x8d, 0x56, 0xad, 0xe2, 0x85, 0xc2, 0x1a, 0x40, - 0x22, 0xe7, 0x5d, 0xe8, 0x52, 0xee, 0x53, 0x5f, 0xd0, 0x69, 0x1e, 0xc9, 0xbd, 0xda, 0xeb, 0x86, 0x62, 0x7e, 0x09, - 0x92, 0xb8, 0x1d, 0x87, 0x60, 0xf0, 0xc7, 0x54, 0xad, 0x5c, 0x99, 0x6d, 0x94, 0xe6, 0xba, 0x0a, 0x10, 0x62, 0x6f, - 0xaf, 0x33, 0xb6, 0x58, 0xb2, 0xc4, 0xcf, 0x56, 0x09, 0xbb, 0x0e, 0xe3, 0xdb, 0x47, 0x85, 0x39, 0xfd, 0x8e, 0xca, - 0xf3, 0x60, 0x36, 0x97, 0xb5, 0xcf, 0x5a, 0x6c, 0x20, 0x27, 0x70, 0xeb, 0x07, 0xf2, 0xff, 0xfc, 0xdb, 0xb6, 0xff, - 0xf3, 0xef, 0x9d, 0x55, 0x01, 0x7c, 0x3e, 0x34, 0xb3, 0xc1, 0x1e, 0xeb, 0xa2, 0xf9, 0x4b, 0x65, 0x9c, 0x37, 0xd7, - 0xa9, 0x4d, 0x02, 0xbc, 0xaf, 0x4d, 0x41, 0xad, 0xb0, 0xbc, 0x6e, 0x1e, 0xd4, 0x31, 0x18, 0xd7, 0xce, 0x9e, 0x41, - 0xa5, 0x2f, 0xea, 0xda, 0xd0, 0xe8, 0xed, 0x35, 0x23, 0x7f, 0x1c, 0xc3, 0xbb, 0xc6, 0xf0, 0x85, 0xdd, 0xe7, 0x72, - 0xc9, 0x97, 0xc3, 0xa1, 0xcc, 0x2d, 0xa7, 0x36, 0x05, 0x13, 0xff, 0xb3, 0x5a, 0x09, 0x3f, 0x3c, 0x7b, 0x8e, 0x41, - 0xbe, 0xf7, 0x83, 0x97, 0x43, 0x34, 0x46, 0x3b, 0x19, 0x25, 0x05, 0xb3, 0xb2, 0x91, 0xb4, 0x91, 0x31, 0x79, 0x0d, - 0x68, 0x8d, 0xae, 0x41, 0x29, 0x26, 0x1c, 0xcb, 0x87, 0x86, 0xf9, 0x72, 0xc8, 0x05, 0x4b, 0xdc, 0xfe, 0xb5, 0x57, - 0x5d, 0xda, 0x5c, 0x2c, 0x5b, 0x42, 0xba, 0xa9, 0x91, 0xfe, 0x07, 0x2b, 0xb3, 0x42, 0x8e, 0x87, 0x02, 0x7e, 0x90, - 0x28, 0x0c, 0x73, 0xcc, 0x77, 0xf2, 0x6e, 0x93, 0x8d, 0xd8, 0xcf, 0xbb, 0x6d, 0xc4, 0x2e, 0xf6, 0xb2, 0x11, 0xfb, - 0xf9, 0xab, 0xdb, 0x88, 0xbd, 0x53, 0x6d, 0xc4, 0x60, 0x12, 0x5f, 0xb3, 0xbd, 0x0c, 0xb7, 0x84, 0xd5, 0x46, 0x7c, - 0x9b, 0x0e, 0x5c, 0xce, 0xd2, 0xa6, 0xe3, 0x39, 0x03, 0x19, 0x01, 0x9f, 0x95, 0x30, 0x9e, 0x81, 0x11, 0xd7, 0x9f, - 0x6f, 0x6e, 0x15, 0xc6, 0x33, 0xd5, 0xd8, 0x2a, 0xe2, 0x11, 0x5f, 0x8b, 0x28, 0x4e, 0x64, 0xe0, 0xe4, 0x98, 0x22, - 0xe6, 0x93, 0x75, 0x68, 0x28, 0x59, 0xad, 0xa5, 0xf5, 0x9a, 0x27, 0x4c, 0xa0, 0x7a, 0x68, 0x3d, 0x25, 0x1b, 0x7a, - 0xcf, 0x45, 0x6c, 0x0b, 0x15, 0x82, 0xb4, 0x12, 0xa6, 0x38, 0x11, 0x6b, 0xfd, 0xb7, 0x3b, 0xf7, 0xfb, 0x4b, 0xb7, - 0xdf, 0x76, 0xc1, 0x39, 0x1b, 0x6e, 0x98, 0x58, 0xe0, 0xf4, 0xdb, 0x6d, 0x28, 0xb8, 0x55, 0x0a, 0x3c, 0x28, 0x08, - 0x94, 0x82, 0x0e, 0x14, 0x8c, 0x95, 0x82, 0x23, 0x28, 0x98, 0x28, 0x05, 0xc7, 0x50, 0x70, 0xa3, 0xe7, 0x97, 0x91, - 0xec, 0xee, 0xb1, 0x71, 0x65, 0xd2, 0xa5, 0x42, 0x94, 0x1d, 0x9b, 0x2e, 0x58, 0x4d, 0xf9, 0xb3, 0x5e, 0x6c, 0x92, - 0x74, 0xb1, 0x97, 0x98, 0xb7, 0x73, 0x46, 0x81, 0xa2, 0x5f, 0xe1, 0x99, 0x63, 0x67, 0x31, 0xd8, 0x4d, 0x8b, 0x00, - 0x0c, 0x02, 0x0f, 0x9a, 0x6e, 0x80, 0xc0, 0xa8, 0x2f, 0x67, 0x4e, 0x04, 0xb1, 0x50, 0xe6, 0xb2, 0x78, 0x47, 0x9f, - 0xb3, 0xe4, 0x12, 0x28, 0x2c, 0x4e, 0x5a, 0xaa, 0x54, 0xf2, 0x6b, 0xd8, 0x1d, 0xbc, 0x62, 0xa3, 0xd5, 0x4c, 0x3b, - 0x8f, 0x67, 0x3b, 0x4d, 0x08, 0xd4, 0x57, 0xd0, 0x4b, 0x9d, 0xd4, 0x2f, 0x96, 0x58, 0x96, 0xfc, 0x5b, 0xf4, 0x98, - 0x97, 0xeb, 0x67, 0xd0, 0x37, 0x2d, 0x23, 0x03, 0x16, 0xf8, 0x0e, 0xe0, 0x48, 0xd1, 0xe1, 0x9f, 0x03, 0x9e, 0x95, - 0xe7, 0x0b, 0x5f, 0xe9, 0xcf, 0xe9, 0x8f, 0x2c, 0x4d, 0xfd, 0x99, 0xa8, 0x5f, 0xef, 0x27, 0x18, 0xed, 0xc8, 0xfb, - 0x17, 0x22, 0x10, 0x24, 0x79, 0x41, 0xcd, 0x36, 0x23, 0x89, 0x6f, 0x35, 0xb0, 0xfe, 0x81, 0x05, 0x55, 0xd8, 0x29, - 0x04, 0x36, 0x4c, 0x61, 0xd9, 0xa2, 0x00, 0x36, 0xff, 0x0d, 0x0b, 0xab, 0x85, 0x99, 0x3f, 0xab, 0x16, 0xd1, 0x3a, - 0xc8, 0xd5, 0xbe, 0x49, 0x85, 0x7e, 0xa9, 0xf0, 0x4b, 0x34, 0xd4, 0x61, 0x3c, 0xfb, 0x53, 0xd5, 0xd3, 0x5b, 0xcc, - 0x0a, 0x3e, 0x44, 0x66, 0x90, 0x0d, 0x6d, 0xc4, 0xb1, 0x66, 0x03, 0x0a, 0x7b, 0x51, 0x36, 0xb7, 0xd0, 0xb5, 0xac, - 0xe5, 0x45, 0x86, 0x69, 0xe3, 0xdc, 0xae, 0xab, 0x0e, 0xb5, 0xbd, 0x64, 0x36, 0xf2, 0x5b, 0xae, 0x77, 0x6c, 0x8a, - 0x3f, 0xb6, 0xd3, 0x31, 0x72, 0x84, 0xa0, 0x4d, 0x82, 0x9b, 0xf5, 0x34, 0x8e, 0x32, 0x6b, 0xea, 0x2f, 0x82, 0xf0, - 0xbe, 0xb7, 0x88, 0xa3, 0x38, 0x5d, 0xfa, 0x63, 0xd6, 0x2f, 0x2e, 0xd4, 0x7d, 0x0c, 0xd5, 0xc0, 0xbd, 0x05, 0x5d, - 0xdb, 0x4b, 0xd8, 0x82, 0x5a, 0xcb, 0x48, 0x0c, 0xd3, 0x90, 0xdd, 0xe5, 0xfc, 0xf3, 0xa5, 0xca, 0x54, 0x15, 0x97, - 0x1c, 0xb5, 0x00, 0x8e, 0x94, 0x87, 0x79, 0x80, 0xe0, 0x46, 0xfd, 0xa5, 0x3f, 0xc1, 0xc8, 0x84, 0xb6, 0xd7, 0x49, - 0xd8, 0x42, 0xb3, 0x3b, 0x1b, 0x81, 0x27, 0xf1, 0xed, 0x29, 0xf4, 0x16, 0x1b, 0x5b, 0x29, 0x0b, 0xa7, 0xf8, 0xc6, - 0x42, 0xcf, 0x12, 0x01, 0xc7, 0xc2, 0x8b, 0x38, 0x40, 0x63, 0x8b, 0x3e, 0xbc, 0xee, 0x79, 0x9a, 0xd3, 0x5f, 0x04, - 0x91, 0x45, 0xc3, 0x39, 0x76, 0x96, 0x0a, 0x2c, 0x15, 0x7f, 0xc6, 0x1a, 0xab, 0xbb, 0x9a, 0xd3, 0x87, 0xcb, 0xda, - 0x34, 0x8c, 0x6f, 0x7b, 0xf3, 0x60, 0x32, 0x61, 0x51, 0x1f, 0xfb, 0x2c, 0x0b, 0x59, 0x18, 0x06, 0xcb, 0x34, 0x48, - 0xfb, 0x0b, 0xff, 0x8e, 0x43, 0x3d, 0xdc, 0x04, 0xb5, 0xcd, 0xa1, 0xb6, 0xf7, 0x86, 0xaa, 0x80, 0x01, 0x2f, 0x16, - 0x82, 0xc3, 0xbb, 0xd6, 0xd1, 0x9c, 0xca, 0x38, 0xf7, 0x86, 0xba, 0x4c, 0xd8, 0x7a, 0xe1, 0x27, 0xb3, 0x20, 0xea, - 0x39, 0xb9, 0x7d, 0xb3, 0xa6, 0x85, 0xf1, 0xb8, 0xdb, 0xed, 0xe6, 0xf6, 0x44, 0x3c, 0x39, 0x93, 0x49, 0x6e, 0x8f, - 0xc5, 0xd3, 0x74, 0xea, 0x38, 0xd3, 0x69, 0x6e, 0x07, 0xa2, 0xa0, 0xed, 0x8d, 0x27, 0x6d, 0x2f, 0xb7, 0x6f, 0x95, - 0x1a, 0xb9, 0xcd, 0xf8, 0x53, 0xc2, 0x26, 0x7d, 0x5c, 0x48, 0x64, 0x56, 0xda, 0x3b, 0x76, 0x9c, 0x1c, 0x29, 0xc0, - 0x65, 0x89, 0x36, 0xa1, 0xac, 0xe7, 0x6a, 0xbd, 0x77, 0x4d, 0xad, 0xf8, 0xdc, 0x78, 0xdc, 0x58, 0x6f, 0xe2, 0x27, - 0x9f, 0xae, 0x34, 0x65, 0x14, 0xbe, 0x4f, 0xd5, 0xd6, 0x02, 0x0d, 0xd6, 0x5d, 0x0f, 0x42, 0x76, 0xf5, 0x47, 0x71, - 0x02, 0x7b, 0x36, 0xf1, 0x27, 0xc1, 0x2a, 0xed, 0xb9, 0xde, 0xf2, 0x4e, 0x14, 0xf1, 0xb5, 0x5e, 0x14, 0xe0, 0xde, - 0xeb, 0xa5, 0x71, 0x18, 0x4c, 0x44, 0xd1, 0xa6, 0xbd, 0xe4, 0x7a, 0x46, 0x1f, 0x1d, 0xd6, 0x03, 0x0c, 0xbb, 0xe0, - 0x87, 0xa1, 0x66, 0xb7, 0x53, 0x8d, 0xf9, 0x29, 0xca, 0x97, 0x35, 0x27, 0x25, 0xbc, 0xa0, 0x73, 0xba, 0x7b, 0xb8, - 0xbc, 0x93, 0x6b, 0xde, 0x3d, 0x5a, 0xde, 0xe5, 0x7f, 0x5d, 0xb0, 0x49, 0xe0, 0x6b, 0xad, 0x62, 0x35, 0xb9, 0x0e, - 0xc8, 0xa0, 0x8d, 0xf5, 0x86, 0x65, 0x2a, 0xb6, 0x05, 0x84, 0x36, 0x7c, 0x14, 0x2c, 0x96, 0x71, 0x92, 0xf9, 0x51, - 0x96, 0xe7, 0xc3, 0xab, 0x3c, 0xef, 0x5f, 0x04, 0xad, 0xcb, 0x7f, 0xb4, 0xe8, 0x9c, 0x26, 0x9d, 0x4d, 0x6e, 0x5c, - 0x99, 0xaf, 0x99, 0x6a, 0x33, 0x02, 0xc7, 0x18, 0xda, 0x8b, 0xa8, 0x95, 0xe9, 0x94, 0xac, 0x57, 0x26, 0x24, 0xcb, - 0xea, 0x64, 0x83, 0x52, 0xae, 0x82, 0x27, 0x10, 0x54, 0x78, 0xcd, 0x06, 0x17, 0x8a, 0xfd, 0x09, 0x30, 0x2b, 0x58, - 0x99, 0xfc, 0x0a, 0x9e, 0x6c, 0xe2, 0x19, 0xbf, 0xdb, 0xcd, 0x33, 0xfe, 0x9a, 0xed, 0xc3, 0x33, 0x7e, 0xf7, 0xd5, - 0x79, 0xc6, 0x27, 0x75, 0xbf, 0x82, 0xb7, 0xf1, 0x40, 0x97, 0x1a, 0x06, 0x38, 0x9a, 0x12, 0x8a, 0xd8, 0xf3, 0xf6, - 0x0f, 0xbb, 0x01, 0x08, 0x68, 0x94, 0x83, 0x8e, 0x4e, 0x6e, 0x90, 0xc7, 0xbe, 0x8b, 0x06, 0x7f, 0x4f, 0xd4, 0xe7, - 0xe9, 0x74, 0xf0, 0x2a, 0x56, 0x0a, 0xe4, 0x13, 0x37, 0xbe, 0x28, 0x45, 0x57, 0xa0, 0x37, 0xc2, 0x0a, 0x13, 0xf3, - 0x4f, 0x80, 0x73, 0x36, 0x59, 0x1d, 0x4f, 0xa4, 0xf5, 0x59, 0xbf, 0xdc, 0x85, 0x96, 0x34, 0xf9, 0x14, 0x2e, 0x38, - 0x35, 0x51, 0xe2, 0x8c, 0x65, 0xdc, 0x67, 0xf6, 0xfb, 0xfb, 0xb7, 0x93, 0xd6, 0xdb, 0xd8, 0xc8, 0x83, 0xf4, 0x5d, - 0xd5, 0x01, 0x86, 0xeb, 0x7e, 0x06, 0xea, 0x70, 0x72, 0x6e, 0x41, 0xa6, 0x26, 0x98, 0x86, 0xd7, 0xd4, 0xfc, 0xac, - 0x34, 0xd2, 0x9e, 0xda, 0x90, 0x27, 0xba, 0xaa, 0x1d, 0xc6, 0xdc, 0xfb, 0x60, 0xcd, 0x39, 0x40, 0xcc, 0xdd, 0x85, - 0x7e, 0xc3, 0x13, 0x6a, 0x1e, 0x4c, 0xf2, 0xdc, 0xe8, 0x0b, 0x44, 0x28, 0x07, 0x2d, 0xdb, 0xc5, 0xc4, 0xa5, 0xb7, - 0xd2, 0xa6, 0x81, 0x6b, 0x08, 0x49, 0xfd, 0xf7, 0x16, 0x14, 0xea, 0x5c, 0x59, 0xc8, 0x71, 0xa6, 0x6b, 0x84, 0x3e, - 0x32, 0xb4, 0x50, 0x06, 0x04, 0x1a, 0x60, 0x89, 0x7f, 0xf1, 0x4a, 0x14, 0xd4, 0x6d, 0x38, 0x09, 0x39, 0x68, 0x11, - 0x00, 0x5e, 0xfe, 0x42, 0xae, 0x4d, 0x64, 0x87, 0xd7, 0xc1, 0x87, 0x5c, 0x97, 0xbc, 0x1f, 0x2e, 0xbf, 0xd3, 0x93, - 0x03, 0x68, 0x70, 0x5a, 0x31, 0x1c, 0xd8, 0x61, 0xa1, 0x08, 0xac, 0x44, 0x7a, 0x6b, 0xda, 0xe9, 0xad, 0xf6, 0x6c, - 0x2d, 0x22, 0x64, 0x64, 0xfe, 0xd2, 0x82, 0x2b, 0x3e, 0xd2, 0x5e, 0x4e, 0xf1, 0x94, 0x60, 0x1c, 0xfd, 0x55, 0x0a, - 0xb4, 0x11, 0x2f, 0xaa, 0x48, 0x7f, 0xfa, 0xe3, 0x55, 0x92, 0xc6, 0x49, 0x6f, 0x19, 0x07, 0x51, 0xc6, 0x92, 0x1c, - 0x51, 0x75, 0x89, 0xf8, 0x11, 0xe8, 0xb9, 0x5a, 0xc7, 0x4b, 0x7f, 0x1c, 0x64, 0xf7, 0x3d, 0x87, 0xb3, 0x14, 0x4e, - 0x9f, 0x73, 0x07, 0x4e, 0x63, 0xfd, 0x1e, 0xc7, 0xe6, 0x73, 0x64, 0xfc, 0x92, 0x3a, 0x3b, 0xa3, 0x2e, 0xf3, 0xbe, - 0xf2, 0x96, 0x62, 0x84, 0x00, 0xfb, 0xe1, 0x27, 0xd6, 0x0c, 0xa8, 0x3c, 0x4c, 0xb5, 0x33, 0x61, 0x33, 0x13, 0xa9, - 0x36, 0xc8, 0xe5, 0xc5, 0x1f, 0xbb, 0x63, 0x68, 0x4e, 0x73, 0x31, 0x70, 0x3c, 0xc6, 0x3e, 0x3d, 0xeb, 0xf9, 0x90, - 0x51, 0xcb, 0xdc, 0xa7, 0xe6, 0x88, 0x4d, 0xe3, 0x84, 0x51, 0x3c, 0x59, 0xb7, 0xbb, 0xbc, 0xdb, 0x1f, 0xfc, 0xf6, - 0xe1, 0x37, 0xc3, 0x89, 0xe2, 0xac, 0x25, 0x80, 0x19, 0x3b, 0xa0, 0xd5, 0xcf, 0x33, 0x60, 0x0d, 0x09, 0xf3, 0x63, - 0x0a, 0xdd, 0xd5, 0xd3, 0xf5, 0x7e, 0x63, 0xd8, 0xae, 0x65, 0xcc, 0xcf, 0xbc, 0x84, 0x85, 0x7e, 0x16, 0xdc, 0x08, - 0x9e, 0xb1, 0x7d, 0xb4, 0xbc, 0x13, 0x73, 0x8c, 0x07, 0xde, 0x03, 0x26, 0xa9, 0xd2, 0x15, 0x31, 0x49, 0xd5, 0x62, - 0x9c, 0xa4, 0x7e, 0x6d, 0x34, 0x22, 0x92, 0x45, 0xe5, 0xa4, 0xef, 0x2c, 0xef, 0xd4, 0x23, 0xba, 0x68, 0x26, 0x4f, - 0xea, 0x6a, 0x08, 0xb2, 0x45, 0x30, 0x99, 0x84, 0x2c, 0x2f, 0x4d, 0x74, 0x79, 0x2e, 0x15, 0xe4, 0x48, 0x3c, 0xf8, - 0xa3, 0x34, 0x0e, 0x57, 0x19, 0x6b, 0x46, 0x17, 0x21, 0xc7, 0x73, 0x0a, 0xe4, 0xe0, 0xef, 0x72, 0x5f, 0x3b, 0xc0, - 0x6e, 0xc3, 0x32, 0x71, 0xfa, 0x10, 0x71, 0xd8, 0x6a, 0x97, 0xbb, 0x0e, 0xaf, 0x64, 0xa7, 0xcd, 0x86, 0x81, 0x98, - 0x70, 0x2c, 0x11, 0xf5, 0xd6, 0x6c, 0x97, 0x97, 0xc9, 0xa8, 0xab, 0xb2, 0x28, 0x2f, 0x0f, 0xe6, 0xcf, 0xd9, 0x63, - 0x2f, 0x9a, 0xf7, 0xd8, 0x0b, 0xb1, 0xc7, 0xb6, 0xaf, 0xcc, 0xc7, 0x53, 0x17, 0xfe, 0xeb, 0x17, 0x03, 0xea, 0x39, - 0x5a, 0x7b, 0x79, 0xa7, 0xb9, 0xcb, 0x3b, 0xcd, 0xf2, 0x96, 0x77, 0x1a, 0x82, 0x46, 0x7b, 0x10, 0xd3, 0xf6, 0x0c, - 0xd3, 0xd1, 0xa0, 0x10, 0xfe, 0x38, 0xa5, 0x57, 0xee, 0x21, 0xbc, 0x83, 0x56, 0x9d, 0xfa, 0x3b, 0x6f, 0xfb, 0x56, - 0xa7, 0xbd, 0x24, 0x88, 0xb6, 0x61, 0x67, 0xfe, 0x68, 0xc4, 0x26, 0xbd, 0x69, 0x3c, 0x5e, 0xa5, 0xff, 0xe2, 0xfd, - 0xe7, 0x48, 0xdc, 0x4a, 0x08, 0x2a, 0x70, 0x44, 0x53, 0x50, 0x94, 0xdc, 0x30, 0x01, 0x61, 0x2d, 0xe7, 0xa9, 0x47, - 0xe1, 0x91, 0x3d, 0xfb, 0xb0, 0x61, 0x91, 0x37, 0x23, 0xfa, 0x4f, 0x9b, 0xa5, 0xcd, 0x24, 0xe6, 0x0b, 0xd0, 0xb2, - 0x15, 0x1d, 0x0f, 0xc7, 0x06, 0x9f, 0x4d, 0xa7, 0xdb, 0xdc, 0xdd, 0x4b, 0xf1, 0xa5, 0x2b, 0x71, 0xa8, 0xf0, 0x73, - 0x8b, 0x3b, 0xa6, 0x6c, 0x87, 0xba, 0x69, 0x8d, 0xd4, 0xa0, 0x6e, 0x39, 0x10, 0x8a, 0xba, 0x7b, 0x52, 0xf9, 0xc7, - 0x2f, 0x0e, 0xe1, 0x3f, 0xe2, 0xea, 0x7f, 0xcd, 0x9a, 0x18, 0xf5, 0xb7, 0x65, 0x4b, 0x70, 0x62, 0x95, 0x90, 0x11, - 0xdf, 0xbf, 0xfe, 0x74, 0xfa, 0xb0, 0x06, 0x7b, 0xd7, 0x26, 0x53, 0xaa, 0x6a, 0xed, 0xef, 0xe3, 0x18, 0x52, 0x77, - 0xd6, 0xab, 0x0b, 0xf4, 0x90, 0xb1, 0x7b, 0x36, 0x80, 0x46, 0xe2, 0x1e, 0x41, 0x5a, 0x7c, 0x1d, 0xdb, 0xd0, 0x55, - 0xe2, 0xf5, 0xa6, 0xab, 0xc4, 0xab, 0xdd, 0x57, 0x89, 0x1f, 0xf6, 0xba, 0x4a, 0xbc, 0xfa, 0xea, 0x57, 0x89, 0xd7, - 0xf5, 0xab, 0xc4, 0x45, 0x2c, 0xec, 0x67, 0xcd, 0xb7, 0x2b, 0xfe, 0xf3, 0x23, 0x29, 0xe5, 0xce, 0xe3, 0x41, 0xc7, - 0xa1, 0x90, 0xc7, 0x17, 0x7f, 0xf8, 0x62, 0x81, 0x0b, 0xf1, 0x3d, 0x9a, 0x93, 0x15, 0x57, 0x0b, 0x4e, 0xd9, 0xf1, - 0x3b, 0x4a, 0x71, 0x18, 0x47, 0xb3, 0x9f, 0x41, 0x29, 0x0b, 0xe2, 0xc0, 0x44, 0x79, 0x11, 0xa4, 0x3f, 0xc7, 0xcb, - 0xd5, 0xf2, 0x2d, 0xc0, 0xfa, 0x18, 0xa4, 0xc1, 0x28, 0x64, 0xd2, 0x13, 0x99, 0xcc, 0xdf, 0xb8, 0x4c, 0x1c, 0x2c, - 0x4e, 0xc5, 0x4f, 0xff, 0x4e, 0xfc, 0x44, 0x9b, 0x54, 0xfe, 0x9b, 0xec, 0xea, 0xf4, 0xe6, 0x8b, 0x88, 0x50, 0x02, - 0x2a, 0x9d, 0x7e, 0xf8, 0x65, 0xe4, 0x22, 0x36, 0x1a, 0x46, 0x29, 0xec, 0x1d, 0x36, 0xc2, 0x61, 0xb5, 0x4b, 0xcd, - 0xca, 0x30, 0x65, 0x08, 0xae, 0xba, 0x18, 0x7e, 0x11, 0xaf, 0x52, 0x36, 0x89, 0x6f, 0x23, 0xdd, 0x8c, 0xa4, 0x93, - 0x01, 0x68, 0x38, 0x65, 0x1b, 0x4c, 0x1e, 0xf9, 0x01, 0x19, 0xe5, 0x38, 0x69, 0xe9, 0x90, 0xbb, 0x74, 0xb5, 0xb4, - 0x48, 0xd5, 0x6c, 0xe1, 0x10, 0x75, 0x99, 0xe5, 0xe8, 0x51, 0xab, 0x15, 0x0f, 0x1e, 0xd6, 0x52, 0x98, 0x6a, 0xc4, - 0x36, 0x97, 0x0a, 0xa7, 0xad, 0x48, 0x08, 0x17, 0x45, 0x1c, 0x8c, 0x86, 0x89, 0xe3, 0x6f, 0xc8, 0x75, 0xb5, 0x78, - 0x0b, 0x51, 0x44, 0xf2, 0x15, 0x9f, 0x0f, 0x1e, 0x15, 0x82, 0x1e, 0x5f, 0x2a, 0x68, 0x7c, 0x77, 0xc3, 0x92, 0xd0, - 0xbf, 0x6f, 0x19, 0x79, 0x1c, 0xfd, 0x08, 0x08, 0x78, 0x15, 0xdf, 0x46, 0x6a, 0x05, 0x4c, 0xd6, 0xd2, 0xb0, 0x96, - 0x1a, 0xe3, 0x97, 0x80, 0xe3, 0x8a, 0xd2, 0x03, 0x48, 0x93, 0x3b, 0x63, 0x7f, 0x37, 0xe9, 0xdf, 0x7f, 0x18, 0xb9, - 0x79, 0x1e, 0xcb, 0x0f, 0xfd, 0xb2, 0xdc, 0xe3, 0x33, 0x4f, 0x9f, 0x3e, 0xda, 0x3c, 0xec, 0x72, 0x7a, 0xf6, 0x86, - 0xd6, 0xc6, 0xc6, 0x5d, 0x00, 0xbd, 0xb8, 0x88, 0x57, 0xe3, 0x39, 0x1a, 0xba, 0x7e, 0xbd, 0xf1, 0x66, 0x00, 0x13, - 0xb3, 0x94, 0xca, 0xa1, 0x57, 0x8a, 0x0a, 0x2c, 0xe0, 0xf7, 0x5f, 0x43, 0x00, 0xce, 0xff, 0x21, 0x1a, 0xea, 0xab, - 0x86, 0xdf, 0xe2, 0x83, 0x87, 0x2d, 0xde, 0x3e, 0x24, 0xd3, 0xe4, 0xa1, 0x2d, 0x84, 0x72, 0xad, 0x99, 0xc8, 0xe4, - 0x55, 0xa4, 0xa9, 0x61, 0xe4, 0x36, 0x45, 0xc8, 0x13, 0x5f, 0x61, 0x36, 0x5d, 0xd3, 0xb9, 0xa3, 0x81, 0xc9, 0x38, - 0xb5, 0xaa, 0x10, 0x19, 0x6e, 0xf2, 0xc0, 0x90, 0x7c, 0x55, 0xdf, 0x2d, 0x82, 0xc8, 0xc4, 0x28, 0xf0, 0xf5, 0x37, - 0xfe, 0x1d, 0xc4, 0x41, 0x06, 0xe2, 0x56, 0x7d, 0x05, 0x85, 0xa6, 0xea, 0x37, 0x07, 0xa9, 0x9e, 0xf4, 0x46, 0x4c, - 0x08, 0x2d, 0xde, 0xf0, 0x1b, 0x4d, 0xd3, 0x34, 0x79, 0x8d, 0xd0, 0xe4, 0x3d, 0x02, 0xcb, 0xf1, 0x3a, 0x00, 0xda, - 0x92, 0x7c, 0x79, 0x47, 0x25, 0x70, 0x33, 0x40, 0x9d, 0xac, 0x28, 0xe0, 0xa1, 0xfe, 0x3a, 0x8e, 0x28, 0x10, 0x17, - 0x7a, 0x08, 0xd3, 0xe6, 0x27, 0x10, 0x11, 0xb8, 0xa7, 0xe1, 0x85, 0x1d, 0xdf, 0x72, 0x49, 0xb0, 0xe6, 0xd0, 0xe3, - 0xb0, 0xcf, 0x9a, 0x63, 0xc2, 0x45, 0x0a, 0x15, 0x04, 0xad, 0x43, 0x25, 0xc4, 0xb3, 0xc9, 0x1a, 0x68, 0x23, 0xde, - 0x8b, 0xee, 0xb2, 0x05, 0x8b, 0x56, 0x3a, 0xe6, 0x84, 0xc2, 0x18, 0x7d, 0x50, 0xe7, 0x15, 0x31, 0x5b, 0x40, 0x6d, - 0x9a, 0x5b, 0xce, 0xe9, 0x2c, 0x4c, 0x39, 0x49, 0xf5, 0xcd, 0x31, 0x57, 0x6c, 0xa6, 0x9c, 0xb6, 0x55, 0x4f, 0x08, - 0x3e, 0xa5, 0x71, 0xd5, 0x91, 0x8b, 0x2c, 0xa1, 0x01, 0x06, 0x45, 0xc7, 0xe0, 0xe2, 0x22, 0x81, 0xf6, 0x96, 0x5f, - 0x9d, 0x34, 0xa9, 0x91, 0xf1, 0x2b, 0x82, 0xa2, 0xc4, 0xa8, 0x83, 0xe1, 0xfd, 0x84, 0xc0, 0x44, 0x1b, 0xe1, 0x8c, - 0x6b, 0x70, 0x36, 0x0c, 0xfa, 0x13, 0xbb, 0xa7, 0x83, 0x84, 0x50, 0xf5, 0x89, 0xdd, 0x83, 0xed, 0xdf, 0x6b, 0x90, - 0xa6, 0xe8, 0x5b, 0xc8, 0xb5, 0x09, 0xa1, 0xfe, 0xc7, 0x10, 0xac, 0x6a, 0xcb, 0x06, 0x72, 0xf2, 0x2d, 0x54, 0x1c, - 0x51, 0x0c, 0x59, 0x9d, 0xc5, 0x26, 0xe6, 0x26, 0xfe, 0xad, 0x46, 0x1c, 0x5b, 0x0d, 0x5b, 0xc3, 0x78, 0xe6, 0x3a, - 0xce, 0x41, 0xad, 0x3e, 0x08, 0xb2, 0x9b, 0x6a, 0x1b, 0x66, 0x36, 0x70, 0x1d, 0x2b, 0x78, 0x66, 0x7b, 0xfd, 0xda, - 0x19, 0xad, 0xc4, 0x92, 0x1c, 0xa2, 0xf8, 0xeb, 0xf4, 0xc9, 0xba, 0x55, 0xdb, 0x90, 0x46, 0xd5, 0x64, 0x1e, 0xfb, - 0x96, 0x73, 0xf9, 0xd7, 0xb0, 0x7e, 0xf4, 0x53, 0x24, 0x4b, 0xca, 0x6b, 0x32, 0x84, 0x68, 0xc8, 0x2d, 0xd8, 0x46, - 0x7f, 0xd1, 0x9e, 0x6b, 0x2d, 0xda, 0x3e, 0x86, 0x31, 0x94, 0xe9, 0xb2, 0x85, 0x4f, 0x99, 0x0a, 0xa0, 0xf2, 0xc5, - 0xb4, 0x4a, 0xe1, 0x78, 0xdc, 0x55, 0x56, 0x68, 0xf4, 0xb6, 0x72, 0x0b, 0x08, 0x7f, 0xc3, 0xf1, 0x69, 0x8f, 0x20, - 0x2e, 0x01, 0xd4, 0x80, 0xd8, 0xe9, 0x3b, 0x01, 0xae, 0x96, 0x65, 0x70, 0xe5, 0x43, 0x72, 0x7f, 0x60, 0x78, 0xe8, - 0xa0, 0x0e, 0x4d, 0xc2, 0x6b, 0x3e, 0xee, 0x1e, 0x08, 0x92, 0x45, 0x93, 0x32, 0xc0, 0xca, 0xf9, 0xb5, 0x3f, 0xb8, - 0x12, 0x45, 0x81, 0xa4, 0x02, 0x71, 0x03, 0x45, 0xc9, 0xe3, 0x08, 0x17, 0x3f, 0x6d, 0xb7, 0x60, 0x2f, 0x2e, 0x06, - 0x1b, 0x50, 0x44, 0x30, 0xd9, 0x4c, 0x11, 0x8a, 0x43, 0xe4, 0x6a, 0x74, 0x0b, 0x6e, 0x09, 0x46, 0x74, 0xe3, 0x4a, - 0xcc, 0x84, 0x4d, 0x61, 0xd1, 0x26, 0xe0, 0xb1, 0x28, 0xf7, 0x95, 0x5a, 0x07, 0xbb, 0xa5, 0xd6, 0xd9, 0x2e, 0xa9, - 0x35, 0xb9, 0x53, 0xdd, 0x26, 0xfe, 0x52, 0xf1, 0xc8, 0x13, 0xcc, 0xb9, 0xea, 0x98, 0x57, 0x12, 0x75, 0xa3, 0xf7, - 0x95, 0x68, 0x55, 0x83, 0x46, 0x56, 0x82, 0x28, 0xfe, 0x56, 0x2e, 0x28, 0x42, 0xa1, 0xae, 0xca, 0xc6, 0x2f, 0x0a, - 0xd9, 0x38, 0xdd, 0x6a, 0x0a, 0x47, 0x1a, 0xc1, 0xfd, 0x2b, 0x4e, 0x6a, 0xf2, 0x76, 0x50, 0x38, 0xab, 0x15, 0x3d, - 0x55, 0xdc, 0xaf, 0x8a, 0x8b, 0x86, 0xe2, 0xd4, 0x27, 0x6e, 0x19, 0x65, 0xdf, 0xbe, 0x72, 0xd5, 0xc2, 0xfb, 0xaa, - 0x28, 0x07, 0xa9, 0x3b, 0x76, 0x59, 0x16, 0xab, 0xcb, 0xa6, 0xec, 0x7e, 0xa3, 0xbe, 0x56, 0x16, 0x89, 0xf4, 0x93, - 0x21, 0x04, 0x0b, 0x31, 0x7d, 0x45, 0xaf, 0x2d, 0x6d, 0x20, 0xb0, 0x93, 0x0d, 0x6e, 0x7d, 0xbb, 0xa5, 0xf3, 0x94, - 0x2f, 0xa1, 0xd0, 0xc2, 0xab, 0x32, 0x08, 0xc4, 0xef, 0xd5, 0xba, 0xe1, 0x94, 0xc7, 0x43, 0x9e, 0x9f, 0xef, 0x20, - 0x5e, 0xd4, 0x1c, 0x55, 0x91, 0x8f, 0x3b, 0xd3, 0x22, 0xf3, 0x5c, 0xac, 0x5a, 0x07, 0x4a, 0x42, 0x9c, 0x35, 0xf7, - 0x8c, 0x29, 0xcb, 0xe8, 0x79, 0x8d, 0x9e, 0xf8, 0x2e, 0x5f, 0x3a, 0xc9, 0x2a, 0xc2, 0xd8, 0xf6, 0x56, 0x96, 0xf8, - 0xe3, 0x4f, 0x4a, 0x97, 0x85, 0x9c, 0x13, 0x64, 0xc0, 0x65, 0x4d, 0x41, 0xdf, 0xc7, 0x50, 0x90, 0xac, 0x67, 0x7b, - 0xa9, 0x22, 0x7d, 0xe9, 0x3d, 0x76, 0xda, 0xfe, 0x8b, 0xe9, 0x61, 0x45, 0x28, 0xea, 0x75, 0xca, 0x22, 0xf3, 0x0d, - 0xfd, 0xc8, 0xe6, 0xab, 0xc5, 0x68, 0xad, 0xca, 0x56, 0x15, 0x91, 0x6b, 0x5d, 0xcc, 0xaa, 0x7e, 0x76, 0x3a, 0x9d, - 0x96, 0x05, 0x8d, 0x8e, 0x76, 0x88, 0xc2, 0xc2, 0xc7, 0x8e, 0xe3, 0x54, 0xfb, 0xbe, 0x1d, 0xed, 0x16, 0xca, 0x6d, - 0xbb, 0x8d, 0x3d, 0x46, 0xdc, 0xee, 0xc2, 0x5f, 0x1d, 0x1d, 0xb9, 0x5d, 0xec, 0xec, 0x92, 0x59, 0x44, 0x9f, 0x8c, - 0x21, 0x82, 0x8c, 0x2d, 0xd2, 0xde, 0x98, 0xa1, 0x0e, 0xc6, 0x56, 0x36, 0x34, 0x1a, 0x0e, 0x58, 0x33, 0x30, 0x15, - 0x71, 0xc5, 0xaa, 0x70, 0x34, 0x94, 0x87, 0xd7, 0x84, 0xf7, 0xe2, 0x23, 0xb8, 0x51, 0xd6, 0x75, 0x99, 0x36, 0x0e, - 0xab, 0xe3, 0xfc, 0xa5, 0x54, 0x4f, 0x83, 0x03, 0x70, 0x2d, 0x14, 0xda, 0x24, 0x9f, 0xc5, 0xbf, 0xa5, 0xfc, 0xff, - 0xc5, 0xf2, 0xae, 0x6c, 0x3f, 0xd2, 0x05, 0x89, 0x76, 0xb1, 0x5b, 0xa8, 0xd7, 0x4d, 0x6b, 0x40, 0x5a, 0x19, 0x4c, - 0x55, 0x05, 0x3a, 0x28, 0xe9, 0x4b, 0x09, 0x40, 0x1a, 0xc4, 0xef, 0xc8, 0x31, 0xc3, 0x14, 0x17, 0x22, 0xc4, 0x22, - 0x7d, 0x1d, 0x8c, 0xc1, 0x7c, 0xde, 0x45, 0xfd, 0x41, 0x69, 0x4d, 0x80, 0x36, 0xbe, 0x36, 0xb6, 0xbd, 0xc4, 0xfd, - 0x55, 0xbd, 0x96, 0x00, 0x0c, 0x28, 0x73, 0x61, 0x13, 0xa2, 0x21, 0x81, 0x56, 0x59, 0xdc, 0xd4, 0x4b, 0xf9, 0x56, - 0xd5, 0xb3, 0x89, 0x8e, 0x21, 0xb8, 0xe6, 0x2a, 0x04, 0x5b, 0x68, 0x0b, 0x60, 0xb0, 0x7c, 0xf9, 0xe1, 0xb3, 0x05, - 0x53, 0xac, 0xae, 0x47, 0x17, 0xa7, 0x1c, 0xd7, 0xaf, 0x85, 0x67, 0x67, 0x4a, 0xfb, 0x1f, 0xe5, 0x8b, 0x3f, 0x34, - 0x0a, 0xf4, 0x2e, 0x4a, 0x12, 0x3a, 0x6e, 0x2d, 0xee, 0x19, 0x7b, 0xd5, 0x5e, 0x04, 0xd1, 0xfe, 0x75, 0xfd, 0xbb, - 0xbd, 0xeb, 0xc2, 0x81, 0xb1, 0x77, 0x65, 0x38, 0x71, 0xc8, 0x72, 0x21, 0x1b, 0xfc, 0xa0, 0x08, 0x14, 0x55, 0xaf, - 0x63, 0x1d, 0x5b, 0x11, 0x97, 0x7f, 0xb1, 0x1a, 0x0c, 0x4f, 0xce, 0xee, 0x16, 0xa1, 0x76, 0xc3, 0x12, 0x48, 0xed, - 0x33, 0xd0, 0x5d, 0xdb, 0xd1, 0x35, 0xf4, 0xa1, 0x0d, 0xa2, 0xd9, 0x40, 0xff, 0xe5, 0xe2, 0x8d, 0xd5, 0xd5, 0xcf, - 0x40, 0x45, 0x7b, 0x33, 0xc3, 0x63, 0xef, 0xdc, 0xbf, 0x67, 0xc9, 0xb5, 0xa7, 0x6b, 0x98, 0xc1, 0x87, 0x0e, 0x3c, - 0x2c, 0xd3, 0x3c, 0x7d, 0x8f, 0x44, 0x11, 0x9a, 0xc8, 0xf5, 0xa6, 0x03, 0xc9, 0x71, 0xbd, 0xae, 0xe6, 0x7a, 0x87, - 0xf6, 0x51, 0x57, 0x3f, 0xfd, 0x46, 0xd3, 0x4e, 0x26, 0x6c, 0x9a, 0x9e, 0xe2, 0x15, 0xed, 0x04, 0xcf, 0x08, 0xfa, - 0xad, 0x69, 0xf6, 0x38, 0x4c, 0x2d, 0x57, 0x5b, 0xf3, 0x47, 0x4d, 0x9b, 0x06, 0x61, 0xd8, 0xd3, 0x1e, 0x4f, 0xbd, - 0xe9, 0xe1, 0xf4, 0x45, 0x9f, 0x17, 0xe7, 0xdf, 0x94, 0xaa, 0x9b, 0xf4, 0xaf, 0xa7, 0x34, 0x4b, 0xb3, 0x24, 0xfe, - 0xc4, 0xb8, 0xd9, 0x89, 0x26, 0x2f, 0x8f, 0xd5, 0xa6, 0x5e, 0xfd, 0x4b, 0x6e, 0x77, 0x34, 0x9e, 0x7a, 0x45, 0x75, - 0xec, 0xe3, 0x81, 0xec, 0xe4, 0xc9, 0x81, 0xe8, 0xfa, 0x89, 0x8a, 0x26, 0xd7, 0x6a, 0x42, 0x94, 0xab, 0xf3, 0x31, - 0xce, 0xc4, 0xf8, 0x4e, 0x20, 0x0e, 0xa3, 0x74, 0xd7, 0x85, 0x1e, 0xe8, 0xda, 0x64, 0xa0, 0xff, 0xe8, 0x7a, 0x5d, - 0xd3, 0x75, 0x8f, 0xec, 0xa3, 0xee, 0xd8, 0x31, 0x0f, 0xed, 0x43, 0xab, 0x6d, 0x1f, 0x99, 0x5d, 0xab, 0x6b, 0x76, - 0xff, 0xd6, 0x1d, 0x5b, 0x87, 0xf6, 0xa1, 0xe9, 0x58, 0x5d, 0x28, 0xb4, 0xba, 0x56, 0xf7, 0xc6, 0x3a, 0xec, 0x8e, - 0x1d, 0x2c, 0xf5, 0xec, 0x4e, 0xc7, 0x72, 0x1d, 0xbb, 0xd3, 0x31, 0x3b, 0xf6, 0xd1, 0x91, 0xe5, 0xb6, 0xed, 0xa3, - 0xa3, 0xf3, 0x4e, 0xd7, 0x6e, 0xc3, 0xbb, 0x76, 0x7b, 0xdc, 0xb6, 0x5d, 0xd7, 0x82, 0xbf, 0xcc, 0xae, 0xed, 0xd1, - 0x0f, 0xd7, 0xb5, 0xdb, 0xae, 0xe9, 0x84, 0x1d, 0xcf, 0x3e, 0x7a, 0x61, 0xe2, 0xdf, 0x58, 0xcd, 0xc4, 0xbf, 0x00, - 0x8c, 0xf9, 0xc2, 0xf6, 0x8e, 0xe8, 0x17, 0x02, 0xbc, 0x39, 0xec, 0xfe, 0xaa, 0x1f, 0x6c, 0x1c, 0x83, 0x4b, 0x63, - 0xe8, 0x76, 0xec, 0x76, 0xdb, 0x3c, 0x74, 0xed, 0x6e, 0x7b, 0x6e, 0x1d, 0x7a, 0xf6, 0xd1, 0xf1, 0xd8, 0x72, 0xed, - 0xe3, 0x63, 0xd3, 0xb1, 0xda, 0xb6, 0x67, 0xba, 0xf6, 0x61, 0x1b, 0x7f, 0xb4, 0x6d, 0xef, 0xe6, 0xf8, 0x85, 0x7d, - 0xd4, 0x99, 0x1f, 0xd9, 0x87, 0x1f, 0x0f, 0xbb, 0xb6, 0xd7, 0x9e, 0xb7, 0x8f, 0x6c, 0xef, 0xf8, 0xe6, 0xc8, 0x3e, - 0x9c, 0x5b, 0xde, 0xd1, 0xd6, 0x96, 0xae, 0x67, 0x03, 0x8e, 0xf0, 0x35, 0xbc, 0x30, 0xf9, 0x0b, 0xf8, 0x33, 0xc7, - 0xb6, 0xff, 0x45, 0x30, 0x69, 0xbd, 0xe9, 0x0b, 0xbb, 0x7b, 0x3c, 0xa6, 0xea, 0x50, 0x60, 0x89, 0x1a, 0xd0, 0xe4, - 0xc6, 0xa2, 0xcf, 0x22, 0x38, 0x4b, 0x00, 0x12, 0x7f, 0xf8, 0xc7, 0x6e, 0x2c, 0xf8, 0x30, 0x7d, 0xf7, 0x7f, 0x0a, - 0x47, 0x4e, 0x39, 0x64, 0xae, 0xfc, 0x86, 0xff, 0x43, 0x49, 0x5f, 0x86, 0xe6, 0xf9, 0x26, 0x45, 0xc5, 0xfb, 0xdd, - 0x8a, 0x8a, 0x37, 0xab, 0x7d, 0x14, 0x15, 0xef, 0xbf, 0xba, 0xa2, 0xe2, 0xbc, 0x6a, 0x27, 0xff, 0xbe, 0x1a, 0x9b, - 0xfe, 0xd7, 0x75, 0xf5, 0x1a, 0x12, 0xf8, 0xad, 0xcb, 0x8b, 0xd5, 0x15, 0x44, 0x57, 0x7a, 0x1f, 0x0f, 0xde, 0xac, - 0x4a, 0x46, 0x60, 0x31, 0xd0, 0xd8, 0xf7, 0x31, 0xd1, 0xd8, 0xdf, 0x57, 0x03, 0xb0, 0x3c, 0xe1, 0x7c, 0x49, 0x30, - 0xb1, 0xe6, 0x7e, 0x38, 0x95, 0x3c, 0x0d, 0x94, 0xf4, 0xb1, 0x18, 0xbc, 0x12, 0xe0, 0xb8, 0x06, 0x75, 0xd8, 0x6a, - 0x11, 0xa5, 0xbd, 0x23, 0x07, 0x0e, 0x52, 0x6f, 0x9a, 0xe4, 0x95, 0xc6, 0xb6, 0x88, 0x47, 0x75, 0xcd, 0xbd, 0x26, - 0x36, 0xbe, 0x47, 0xa3, 0xc0, 0x66, 0xe8, 0x6e, 0x1d, 0xae, 0x06, 0xd6, 0x36, 0xc2, 0x68, 0x12, 0xd8, 0xb9, 0xa6, - 0xf7, 0x65, 0xd3, 0xbc, 0x8a, 0x31, 0xe6, 0xe6, 0x9e, 0x42, 0x4f, 0xaa, 0xed, 0xdd, 0xb2, 0x69, 0xdf, 0xae, 0x61, - 0x36, 0x7c, 0xbe, 0xd4, 0x7c, 0x8b, 0x5d, 0xa1, 0x04, 0x5c, 0x45, 0x55, 0x25, 0xb3, 0x5a, 0x23, 0x42, 0x0a, 0xee, - 0xbe, 0x30, 0x3e, 0x2c, 0x58, 0x4b, 0x47, 0x43, 0x7e, 0xc7, 0x51, 0xde, 0x95, 0x60, 0xaa, 0x06, 0x8b, 0xcf, 0xd6, - 0xc8, 0x71, 0x07, 0xbf, 0x03, 0xeb, 0xc8, 0x39, 0x9e, 0x51, 0xac, 0xe2, 0x79, 0xad, 0xc0, 0xa5, 0xcb, 0x4c, 0x3e, - 0x77, 0xd7, 0x75, 0xe6, 0x71, 0xa3, 0xa9, 0xb2, 0xcb, 0x16, 0x82, 0x0b, 0xc2, 0xcf, 0x93, 0x61, 0x70, 0x4e, 0xc6, - 0xdb, 0x68, 0xfb, 0xbc, 0x0d, 0x98, 0xa8, 0xf7, 0x18, 0x16, 0xb1, 0xc9, 0x1f, 0xd4, 0xb8, 0x00, 0xeb, 0x29, 0x64, - 0xc1, 0xee, 0x21, 0x9b, 0xa6, 0xf0, 0xa8, 0x1e, 0x5a, 0x31, 0xf7, 0xb7, 0x18, 0xd8, 0xa8, 0x80, 0x39, 0x10, 0xb4, - 0x86, 0xde, 0x66, 0x93, 0x23, 0x9d, 0x47, 0xd6, 0x25, 0x15, 0xb5, 0xdb, 0x39, 0x36, 0xdd, 0x23, 0xd3, 0x3e, 0xee, - 0x18, 0xb9, 0xd8, 0x70, 0x2a, 0xc8, 0x12, 0x42, 0xc0, 0x28, 0x5a, 0x76, 0x33, 0x88, 0x82, 0x2c, 0xf0, 0xc3, 0x1c, - 0xf8, 0xe3, 0xf2, 0xad, 0xe2, 0x9f, 0xab, 0x34, 0x83, 0x31, 0x0a, 0xa6, 0x17, 0x0d, 0xc2, 0xad, 0x11, 0xcb, 0x6e, - 0x19, 0x8b, 0x36, 0x28, 0xcb, 0xab, 0xf6, 0xe5, 0x7f, 0x9e, 0xb5, 0x6d, 0x4e, 0x96, 0x2c, 0xa3, 0x2c, 0xe2, 0xeb, - 0x43, 0x18, 0x43, 0xe7, 0x43, 0xf3, 0xa7, 0x4d, 0x04, 0xf7, 0x9f, 0xbb, 0x09, 0x6e, 0xc6, 0xf6, 0x21, 0xb8, 0xff, - 0xfc, 0xea, 0x04, 0xf7, 0x27, 0x95, 0xe0, 0x96, 0x7c, 0x81, 0x0a, 0xa9, 0xf3, 0x07, 0x7c, 0x6e, 0x41, 0x50, 0xe7, - 0xe7, 0xfa, 0x01, 0x31, 0xf0, 0xba, 0x92, 0x6c, 0xf7, 0x63, 0x29, 0x7b, 0x10, 0x0a, 0x45, 0x30, 0x08, 0x2d, 0x65, - 0x2a, 0x81, 0x44, 0xb4, 0x32, 0xa5, 0x3a, 0xc0, 0x7c, 0x1b, 0x65, 0xa1, 0xfd, 0x9e, 0x5f, 0xfc, 0x40, 0xc9, 0xf3, - 0x26, 0x4e, 0x16, 0x3e, 0x06, 0xe0, 0xd3, 0x31, 0xeb, 0x20, 0x3c, 0x38, 0xe0, 0x7f, 0x36, 0x8e, 0xa3, 0x89, 0xd4, - 0x54, 0xb0, 0xc1, 0x25, 0x71, 0xdc, 0xfa, 0x3d, 0xf3, 0x13, 0xdd, 0xa4, 0xd7, 0x30, 0xb9, 0xcf, 0xda, 0xce, 0x33, - 0xef, 0xf0, 0xd9, 0x91, 0x03, 0xff, 0xbb, 0xac, 0x9d, 0x9b, 0xbc, 0xe2, 0x22, 0x8e, 0x20, 0xf1, 0x89, 0xa8, 0xb9, - 0xa9, 0xda, 0x2d, 0x63, 0x9f, 0x8a, 0x5a, 0xc7, 0xcd, 0x95, 0x26, 0xfe, 0x7d, 0x51, 0xa7, 0xb1, 0xc6, 0x3c, 0x5e, - 0x29, 0xdd, 0x6a, 0xe8, 0x4d, 0x10, 0xad, 0x40, 0xf6, 0xa6, 0xd4, 0x50, 0x5f, 0xf3, 0xe1, 0x16, 0xe3, 0x62, 0xed, - 0xfc, 0xaa, 0xc8, 0xae, 0x24, 0xb2, 0xbc, 0xec, 0xc4, 0x20, 0x57, 0x5b, 0x38, 0x18, 0x9b, 0x1d, 0xf3, 0x0b, 0x69, - 0x90, 0xdb, 0x50, 0x4c, 0x90, 0x4f, 0x13, 0x94, 0x25, 0xab, 0x68, 0xdc, 0xc2, 0x9f, 0xfe, 0x28, 0x6d, 0x05, 0x07, - 0x10, 0x9d, 0x15, 0x3f, 0x6c, 0xe0, 0xac, 0xf9, 0xa7, 0x4e, 0x91, 0x8a, 0x22, 0x15, 0xb3, 0xe2, 0x3f, 0xcb, 0xcc, - 0x84, 0x12, 0xd8, 0xe2, 0xd4, 0x5a, 0x03, 0xff, 0x99, 0x6c, 0xf8, 0x2c, 0x33, 0x21, 0x89, 0x2c, 0x4c, 0xf7, 0xd3, - 0xa7, 0x54, 0x0b, 0xd2, 0x3a, 0xd2, 0xb0, 0xce, 0xc6, 0x45, 0x78, 0x37, 0xcd, 0x9f, 0xc5, 0x14, 0xe1, 0xad, 0x37, - 0x36, 0xe3, 0xe7, 0xcf, 0x4f, 0x07, 0xae, 0xc1, 0x93, 0x92, 0x96, 0x32, 0x68, 0x9d, 0xef, 0x67, 0x7c, 0x60, 0x34, - 0xba, 0xc5, 0x2d, 0xe1, 0xce, 0xe4, 0x08, 0x13, 0x65, 0x4e, 0xbd, 0x20, 0xa3, 0x05, 0x29, 0x19, 0x7d, 0x61, 0x04, - 0x20, 0xea, 0xc8, 0x5b, 0x57, 0xdb, 0x76, 0x6c, 0x47, 0x97, 0x0d, 0xa7, 0xc1, 0x6c, 0xb0, 0x8e, 0x33, 0x1f, 0x72, - 0x03, 0x85, 0xf1, 0x0c, 0x7c, 0x6b, 0xb2, 0x20, 0x0b, 0x21, 0xd1, 0x0c, 0x38, 0xd9, 0x2c, 0xe8, 0x5e, 0x9e, 0x73, - 0x8b, 0x67, 0x3f, 0xf9, 0x84, 0xc9, 0x06, 0x85, 0x5b, 0x1d, 0x46, 0x1c, 0xfa, 0x11, 0x0e, 0xc3, 0x96, 0xde, 0x82, - 0x54, 0x97, 0x2c, 0x49, 0x2d, 0xd5, 0x83, 0xa0, 0xa7, 0x41, 0x1b, 0x48, 0x43, 0x8f, 0x00, 0xa6, 0x89, 0xbf, 0x80, - 0x98, 0xec, 0xeb, 0xdc, 0xe4, 0x94, 0x56, 0xe7, 0xa4, 0x56, 0x73, 0x5f, 0x1c, 0x99, 0x9a, 0xe7, 0x9a, 0x9a, 0x03, - 0xe4, 0x56, 0xcf, 0xcd, 0x75, 0x7e, 0xd5, 0xdf, 0xa5, 0x04, 0x25, 0xfa, 0xf2, 0x98, 0xc6, 0x41, 0xea, 0x4f, 0x2e, - 0x5e, 0xce, 0x28, 0x80, 0x64, 0x4b, 0x89, 0x96, 0x1e, 0x90, 0x22, 0xe4, 0x82, 0xdd, 0x65, 0x06, 0x26, 0x62, 0xe1, - 0x55, 0x02, 0x63, 0x8d, 0xce, 0x7f, 0x41, 0xa4, 0x05, 0x9f, 0x3f, 0xb7, 0x02, 0x70, 0x70, 0x18, 0x28, 0xf8, 0x81, - 0x67, 0xa3, 0x84, 0xb0, 0xa0, 0x50, 0xdd, 0x21, 0xb2, 0xc0, 0xfb, 0x08, 0xfe, 0x2d, 0x8a, 0xc5, 0x0f, 0xae, 0x3a, - 0xb5, 0x43, 0x3f, 0x9a, 0x01, 0x49, 0xf3, 0xa3, 0x59, 0xcd, 0x44, 0x83, 0xfc, 0x17, 0x2b, 0xa5, 0x05, 0xa8, 0xc2, - 0x7c, 0x22, 0xfd, 0xfe, 0xfe, 0x82, 0x12, 0x4d, 0x41, 0x52, 0x73, 0x7f, 0x82, 0xce, 0x76, 0x85, 0x76, 0xe7, 0xf9, - 0xe0, 0xdb, 0x93, 0x05, 0xcb, 0x7c, 0x12, 0x0d, 0xc3, 0xe5, 0x17, 0xd8, 0x01, 0x6d, 0x2c, 0x92, 0xc4, 0x52, 0x32, - 0xf9, 0x09, 0xbb, 0x09, 0xc6, 0xfc, 0x5e, 0x6a, 0x6a, 0xfc, 0x9c, 0xb2, 0xd0, 0x0a, 0x6c, 0xe0, 0x9a, 0x64, 0x84, - 0x3c, 0xf6, 0x31, 0xcc, 0xe4, 0x20, 0x8a, 0xf5, 0xd3, 0x6f, 0xa5, 0xbf, 0xd6, 0xa6, 0x49, 0x80, 0x6c, 0x8f, 0x97, - 0x09, 0x0b, 0xff, 0x35, 0xf8, 0x16, 0x0e, 0xee, 0x6f, 0xaf, 0x74, 0xa3, 0x9f, 0xd9, 0xf3, 0x84, 0x4d, 0x07, 0xdf, - 0x36, 0x64, 0x3d, 0xc4, 0xeb, 0x3d, 0xf5, 0x45, 0x6f, 0x7b, 0x45, 0x70, 0xa0, 0xf6, 0x5e, 0x97, 0xfa, 0x53, 0x7e, - 0x5b, 0x87, 0x1b, 0xe0, 0xba, 0x74, 0xc7, 0x76, 0xfb, 0x78, 0x7f, 0x1e, 0x85, 0xfe, 0xf8, 0x53, 0x9f, 0xde, 0x94, - 0x1e, 0x2c, 0x38, 0xad, 0xc7, 0xfe, 0xb2, 0x87, 0xc7, 0xab, 0x5a, 0x08, 0xee, 0x9a, 0x54, 0x2a, 0x39, 0xbb, 0xc6, - 0xb5, 0x8c, 0x4b, 0x79, 0x8d, 0x5f, 0xc6, 0x4f, 0xdd, 0xce, 0x83, 0x8c, 0x89, 0x4f, 0xe1, 0x43, 0x9e, 0x8b, 0x8b, - 0x3a, 0x5d, 0x51, 0xf1, 0x62, 0x6d, 0xb7, 0x35, 0xb7, 0xfb, 0xb7, 0xce, 0x8d, 0xeb, 0xcc, 0x3d, 0xd7, 0xee, 0x7e, - 0x74, 0xbb, 0xf3, 0xb6, 0x7d, 0x1c, 0x5a, 0x6d, 0xfb, 0x18, 0xfe, 0x7c, 0x3c, 0xb6, 0xbb, 0x73, 0xcb, 0xb3, 0x0f, - 0x3f, 0xba, 0x5e, 0x68, 0x75, 0xed, 0x63, 0xf8, 0x73, 0x4e, 0xad, 0xe0, 0x02, 0x44, 0xf7, 0x9d, 0x6f, 0x4b, 0x54, - 0x40, 0xf9, 0x2d, 0xf5, 0x34, 0x66, 0xe9, 0x78, 0x6b, 0xd0, 0xf5, 0x00, 0xc9, 0xd0, 0x4d, 0x11, 0x04, 0x32, 0xea, - 0xb7, 0x20, 0x0d, 0x3b, 0x26, 0x10, 0x10, 0x26, 0x2f, 0xc2, 0x2f, 0x55, 0x84, 0xd2, 0x6f, 0xdc, 0x46, 0xbc, 0x4d, - 0x73, 0xc0, 0x75, 0x91, 0x99, 0x8a, 0x94, 0x43, 0xbf, 0x2c, 0x31, 0x88, 0x91, 0x08, 0x11, 0xaf, 0x50, 0xa5, 0x22, - 0x3b, 0x62, 0xbe, 0xbb, 0xe3, 0xe8, 0x99, 0xcb, 0x64, 0x76, 0x9e, 0xaf, 0x0a, 0x9b, 0x2b, 0x8c, 0x24, 0xf4, 0x3f, - 0x0a, 0x07, 0x93, 0xd2, 0x12, 0x1c, 0x11, 0xcd, 0x75, 0x12, 0x24, 0xb2, 0x7b, 0x0a, 0x89, 0x76, 0x9b, 0x23, 0xd5, - 0x1b, 0x90, 0xc6, 0xe4, 0x2d, 0x70, 0xc9, 0x37, 0x7e, 0xa8, 0x18, 0xb7, 0x28, 0x2d, 0x1f, 0x49, 0xca, 0xff, 0xf4, - 0x69, 0xd1, 0x39, 0xab, 0xd2, 0xef, 0x13, 0xb7, 0x03, 0xc7, 0x6e, 0x87, 0xb5, 0xb7, 0xda, 0x59, 0xed, 0x0e, 0x07, - 0x5c, 0x84, 0x0b, 0x15, 0xb6, 0x14, 0x42, 0x8b, 0xbb, 0xd1, 0xd8, 0xab, 0xa6, 0xc3, 0x85, 0x40, 0xca, 0x95, 0xab, - 0x8e, 0x6e, 0xf4, 0x23, 0xa1, 0x92, 0x8c, 0xb6, 0x84, 0x40, 0xe6, 0x77, 0x31, 0x1d, 0x50, 0xb3, 0x65, 0x1c, 0x3b, - 0x9c, 0x46, 0xff, 0xd7, 0x83, 0x40, 0x07, 0x2e, 0xd0, 0xa1, 0x56, 0x76, 0x6b, 0xc9, 0xa1, 0x47, 0x9e, 0xab, 0x74, - 0xa0, 0xb2, 0xf4, 0x4c, 0x87, 0x22, 0xc8, 0x6f, 0x85, 0x29, 0xed, 0xa4, 0x01, 0x99, 0x3c, 0x2d, 0x8a, 0x02, 0x33, - 0x80, 0x18, 0xe0, 0x2d, 0xe1, 0x4c, 0x66, 0x3c, 0x7d, 0xba, 0xf1, 0x10, 0x22, 0x85, 0xbd, 0x9a, 0xd9, 0x53, 0x57, - 0xe9, 0x9b, 0xae, 0x92, 0x18, 0x09, 0x17, 0xa9, 0x86, 0xb0, 0x7b, 0xa3, 0xb5, 0x87, 0x3f, 0x47, 0xcc, 0xcf, 0x6c, - 0xae, 0x69, 0x6a, 0x29, 0x87, 0xbb, 0xe9, 0xb2, 0x36, 0x58, 0xbc, 0xf1, 0x58, 0x67, 0x3c, 0x96, 0xe0, 0x93, 0xf5, - 0xc7, 0x15, 0xf7, 0xf4, 0x06, 0x18, 0x9f, 0x9d, 0x22, 0x3c, 0xcd, 0xbb, 0xcc, 0xa7, 0x18, 0x26, 0xea, 0x91, 0x1b, - 0x67, 0xbe, 0xc8, 0x23, 0x03, 0x7c, 0x79, 0xbf, 0x51, 0x25, 0xab, 0x78, 0x83, 0x9f, 0xbe, 0xbb, 0xf8, 0x4e, 0xe3, - 0xeb, 0x9f, 0x34, 0x88, 0x78, 0x91, 0xa1, 0xac, 0x07, 0x03, 0xca, 0x7a, 0xa0, 0xf1, 0x34, 0x22, 0x90, 0x3b, 0x20, - 0x3f, 0x20, 0x0c, 0xa2, 0x00, 0x9a, 0xf4, 0xaa, 0x8b, 0x55, 0x98, 0x05, 0x4b, 0x3f, 0xc9, 0x0e, 0xa0, 0xa9, 0x05, - 0x44, 0x4e, 0xdf, 0xe4, 0x23, 0x4e, 0xaa, 0x59, 0x11, 0x62, 0x2f, 0x8b, 0x84, 0x6e, 0x76, 0x1a, 0x84, 0x52, 0x35, - 0x2b, 0x3e, 0xe0, 0x8f, 0xc7, 0x6c, 0x99, 0x0d, 0x74, 0x7f, 0x09, 0xd9, 0x2f, 0x30, 0x9e, 0xf5, 0x41, 0x3c, 0xce, - 0x58, 0x66, 0xa5, 0x59, 0xc2, 0xfc, 0x85, 0x2e, 0x43, 0xb9, 0xd6, 0xe1, 0xa5, 0xab, 0xd1, 0x22, 0xc8, 0x64, 0x2c, - 0x44, 0x1a, 0x20, 0x28, 0x49, 0xa1, 0x8b, 0xa7, 0xc3, 0x9c, 0xa3, 0xf0, 0x3c, 0x9e, 0x55, 0x56, 0x54, 0xc1, 0xb9, - 0x9c, 0x61, 0xa4, 0x5d, 0x9e, 0xf1, 0x60, 0x82, 0x3e, 0x4f, 0xd7, 0xdc, 0xaf, 0x5d, 0x86, 0x6c, 0xd4, 0x4f, 0x4f, - 0xf8, 0xf5, 0x56, 0xc3, 0x50, 0x0c, 0x7a, 0xc7, 0x81, 0x58, 0xc2, 0x9b, 0x3c, 0xde, 0x0f, 0x78, 0x65, 0x38, 0x9a, - 0x08, 0x32, 0xc6, 0x79, 0xa7, 0xbe, 0x5c, 0x00, 0x23, 0x54, 0x52, 0xa2, 0xcf, 0xdd, 0x53, 0xe9, 0x62, 0x85, 0xbd, - 0x42, 0x5e, 0xe9, 0xf3, 0xe7, 0x97, 0xc3, 0xff, 0xfc, 0x1b, 0x82, 0xd1, 0xcf, 0x5d, 0xe1, 0x67, 0x7e, 0xa9, 0xd6, - 0xe2, 0xdc, 0xa7, 0x39, 0x44, 0x03, 0x0a, 0x36, 0x11, 0x81, 0x57, 0xc4, 0xd2, 0xca, 0x87, 0x57, 0x22, 0x98, 0x16, - 0x24, 0x9c, 0x30, 0x84, 0x37, 0xfc, 0x10, 0xa6, 0x77, 0x28, 0x82, 0x30, 0x68, 0xbf, 0xdd, 0x7d, 0x7f, 0x0c, 0xc1, - 0x96, 0x6b, 0x79, 0x20, 0x94, 0x0e, 0xe2, 0x1a, 0x3a, 0x3d, 0xf1, 0x35, 0x64, 0x5a, 0x90, 0xfd, 0x48, 0x7b, 0x07, - 0x30, 0xcc, 0x79, 0xbc, 0x60, 0x76, 0x10, 0x1f, 0xdc, 0xb2, 0x91, 0xe5, 0x2f, 0x03, 0xd2, 0xd5, 0xa3, 0xdc, 0x4d, - 0x23, 0xce, 0x4f, 0xaa, 0xc0, 0x89, 0xbf, 0xce, 0x0b, 0x54, 0xc6, 0xe5, 0xe8, 0x69, 0x1d, 0xaf, 0x50, 0xdc, 0x81, - 0x4f, 0xb3, 0x82, 0xc7, 0xf8, 0xf4, 0xe4, 0xc0, 0x3f, 0x2d, 0x87, 0x6f, 0xb4, 0x45, 0x02, 0x81, 0xf2, 0x21, 0x70, - 0x46, 0x51, 0x18, 0x45, 0xc0, 0xc5, 0xe2, 0xc1, 0x8a, 0xa7, 0x53, 0x35, 0xe4, 0xa2, 0x5d, 0xee, 0x9e, 0x44, 0x5a, - 0xb1, 0xa4, 0xe3, 0x25, 0x7d, 0xa9, 0xfe, 0x09, 0xf9, 0x13, 0x92, 0x27, 0xf3, 0xe8, 0x9c, 0xb0, 0xdd, 0x6b, 0xa1, - 0x1b, 0x25, 0xc6, 0x1e, 0x53, 0x25, 0x4e, 0x47, 0xaa, 0x81, 0xc2, 0x37, 0x70, 0x2e, 0x8f, 0x06, 0x03, 0x22, 0x73, - 0x55, 0x6a, 0x07, 0x48, 0x6c, 0x48, 0xa6, 0x00, 0x83, 0xcd, 0xa0, 0xa1, 0x45, 0x2e, 0x74, 0xd8, 0xa8, 0x3a, 0x9c, - 0x7a, 0x1f, 0x0f, 0x7c, 0xb1, 0xfc, 0x4a, 0x0b, 0x14, 0x16, 0x1e, 0x9f, 0x77, 0xa0, 0xef, 0x02, 0x4e, 0x85, 0xcc, - 0x6b, 0x7f, 0x25, 0x8a, 0x6e, 0x85, 0xfe, 0x7d, 0xac, 0x98, 0x36, 0xf0, 0x28, 0x07, 0xe7, 0x58, 0x7a, 0x21, 0xbc, - 0x0b, 0x6b, 0x1b, 0x4d, 0x06, 0xa4, 0xaf, 0x6f, 0x36, 0x35, 0x82, 0xfc, 0xae, 0xbd, 0xa6, 0xd6, 0x2d, 0x0f, 0x06, - 0x89, 0x67, 0x5e, 0xec, 0xc3, 0xd2, 0x4b, 0x24, 0x0b, 0xf9, 0xc9, 0x01, 0x8c, 0x0f, 0x22, 0x33, 0x94, 0x18, 0xa7, - 0xc0, 0x80, 0xf0, 0x0f, 0x7e, 0x4a, 0xe6, 0x19, 0x6f, 0x27, 0x82, 0xe7, 0xc3, 0x8b, 0xa5, 0x8c, 0x0d, 0x5b, 0xaa, - 0x52, 0xe7, 0x65, 0x9c, 0x66, 0x26, 0x70, 0x77, 0x02, 0x87, 0xdf, 0x57, 0x98, 0xbd, 0x21, 0xef, 0x67, 0x4c, 0x38, - 0x3e, 0x9f, 0x67, 0x1b, 0x7c, 0xa3, 0x37, 0x55, 0x21, 0x7e, 0x76, 0x4b, 0x85, 0x62, 0x1d, 0x6f, 0xab, 0x55, 0x70, - 0x4e, 0xb2, 0xda, 0xd2, 0x6f, 0xe9, 0x8f, 0x71, 0xc5, 0xd7, 0x6a, 0x63, 0x29, 0xd4, 0x3b, 0xcf, 0x06, 0x50, 0x55, - 0xc8, 0xe2, 0xfd, 0xe5, 0x92, 0x2a, 0x1b, 0xfd, 0x93, 0x03, 0xba, 0x96, 0x9e, 0xd2, 0x0a, 0x3b, 0x3d, 0x01, 0xf3, - 0x4e, 0x9a, 0x74, 0x7f, 0xb9, 0xe4, 0x53, 0x4a, 0xbf, 0xe8, 0xcd, 0xc1, 0x3c, 0x5b, 0x84, 0xa7, 0xff, 0x07, 0xc0, - 0xb1, 0x34, 0x8b, 0x20, 0x5c, 0x03, 0x00}; + 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x75, 0x92, 0xe5, 0x7c, 0x46, 0x35, 0x33, 0x70, 0x0e, + 0x48, 0x8d, 0x9b, 0x7c, 0xda, 0x6e, 0xcd, 0x6f, 0xf7, 0x5a, 0x7b, 0xf6, 0x4f, 0x55, 0x1a, 0xb6, 0x51, 0x50, 0xd8, + 0x37, 0xc9, 0x85, 0xc1, 0x0f, 0x03, 0x0e, 0xb3, 0x8b, 0xcc, 0xea, 0x99, 0xb5, 0x0b, 0x60, 0x07, 0xb3, 0xab, 0x35, + 0x75, 0xe9, 0xe8, 0x92, 0x6d, 0xf1, 0xb4, 0xf5, 0x43, 0x3d, 0x37, 0xa7, 0x43, 0x96, 0x2f, 0xed, 0x46, 0xf5, 0xc0, + 0x75, 0x5b, 0x35, 0x5c, 0xe6, 0x80, 0x64, 0x18, 0x10, 0x0d, 0xd2, 0xb4, 0x79, 0xc3, 0x86, 0x9f, 0xb9, 0xb6, 0x5b, + 0xa6, 0xa9, 0x6e, 0xc0, 0x79, 0xc7, 0x8c, 0x69, 0xce, 0x8a, 0xa5, 0x3f, 0x8e, 0x5a, 0x35, 0x02, 0x7a, 0x25, 0xcc, + 0x41, 0xa8, 0xe9, 0xb0, 0x09, 0xa1, 0xcc, 0x58, 0xb1, 0xdc, 0x35, 0xb9, 0xcd, 0x0d, 0x1f, 0x1e, 0x67, 0x27, 0xad, + 0x96, 0x3f, 0xea, 0x9a, 0xb6, 0x4e, 0xda, 0x4e, 0x4e, 0xd9, 0x6c, 0x17, 0xa9, 0xa9, 0xd3, 0xd5, 0x76, 0x67, 0x7e, + 0xbb, 0x67, 0xfe, 0x69, 0xed, 0xb5, 0xb6, 0xe9, 0xe8, 0xf6, 0x92, 0x1f, 0x23, 0x8f, 0xa4, 0x5a, 0xce, 0xd3, 0x36, + 0x9b, 0x75, 0x17, 0x0a, 0xce, 0x4c, 0x03, 0x4e, 0x73, 0x16, 0xaf, 0xcd, 0x4c, 0x00, 0x6a, 0x94, 0x0b, 0x38, 0xa2, + 0xec, 0x31, 0x0d, 0x7d, 0x28, 0x09, 0x36, 0xe5, 0x3b, 0x1b, 0xad, 0x0f, 0xab, 0xb5, 0x57, 0x0d, 0x0c, 0xfe, 0x59, + 0xff, 0x55, 0x31, 0xb9, 0x2f, 0x58, 0x20, 0x64, 0xf0, 0x46, 0x72, 0xba, 0x6a, 0x39, 0xc1, 0x62, 0xa4, 0x2b, 0x79, + 0xc7, 0xb8, 0x65, 0xcc, 0xe8, 0xad, 0xf5, 0xcf, 0x98, 0x71, 0x01, 0xd6, 0x5f, 0x08, 0xeb, 0xc0, 0x4e, 0x7e, 0x1a, + 0x36, 0x34, 0xd2, 0x31, 0x34, 0x7c, 0xd8, 0x49, 0x4e, 0x4f, 0x11, 0x6e, 0xe1, 0xce, 0xe9, 0x69, 0x20, 0xd8, 0x8c, + 0xf5, 0xae, 0xa2, 0xbb, 0x4a, 0xaa, 0x1d, 0x25, 0x8f, 0x4c, 0xa3, 0x47, 0xed, 0x56, 0x0b, 0x1b, 0x1f, 0xf4, 0xb2, + 0x30, 0x57, 0x3b, 0x9a, 0x6d, 0xb7, 0x5a, 0xd0, 0x2c, 0xfc, 0x71, 0xf3, 0xfa, 0x85, 0x2c, 0x5b, 0x69, 0x0b, 0xb7, + 0xd3, 0x36, 0xee, 0xa4, 0x1d, 0x7c, 0x9c, 0x1e, 0xe3, 0x93, 0xf4, 0x04, 0x9f, 0xa6, 0xa7, 0xf8, 0x2c, 0x3d, 0xc3, + 0xf7, 0xd3, 0xfb, 0xf8, 0x3c, 0x3d, 0xc7, 0x0f, 0xd2, 0x07, 0xf8, 0x61, 0xda, 0x6e, 0xe1, 0x47, 0x69, 0xbb, 0x8d, + 0x1f, 0xa7, 0xed, 0x0e, 0x7e, 0x92, 0xb6, 0x8f, 0xf1, 0xd3, 0xb4, 0x7d, 0x82, 0x9f, 0xa5, 0xed, 0x53, 0x4c, 0x21, + 0x77, 0x08, 0xb9, 0x19, 0xe4, 0x8e, 0x20, 0x97, 0x41, 0xee, 0x38, 0x6d, 0x9f, 0xae, 0xb1, 0xb2, 0x71, 0x2b, 0xa2, + 0x56, 0xbb, 0x73, 0x7c, 0x72, 0x7a, 0x76, 0xff, 0xfc, 0xc1, 0xc3, 0x47, 0x8f, 0x9f, 0x3c, 0x7d, 0x16, 0x0d, 0xf0, + 0xd0, 0xb8, 0x8f, 0x28, 0xd1, 0xe7, 0x07, 0xed, 0xd3, 0x01, 0xbe, 0xf6, 0x9f, 0x31, 0x3f, 0xe8, 0x9c, 0xb4, 0xd0, + 0xe5, 0xe5, 0xc9, 0xa0, 0x51, 0xe6, 0xbe, 0x37, 0x5e, 0x2b, 0x55, 0x16, 0x21, 0x24, 0x86, 0x1c, 0x84, 0xef, 0x4c, + 0xbd, 0xf7, 0x2c, 0xe6, 0x49, 0x81, 0x0e, 0x0e, 0xcc, 0x8f, 0x89, 0xff, 0x31, 0xf4, 0x3f, 0x68, 0xb0, 0x48, 0xb7, + 0x34, 0x76, 0x6e, 0xcb, 0xba, 0x74, 0x1a, 0x28, 0xed, 0x71, 0xf6, 0xb8, 0xb3, 0x8c, 0xff, 0xaf, 0xc8, 0x5a, 0xbe, + 0x90, 0x13, 0xab, 0x5d, 0x3a, 0xed, 0x31, 0xb2, 0x2c, 0xd2, 0xce, 0xe9, 0xe9, 0xc1, 0x2f, 0x7d, 0xde, 0x6f, 0x0f, + 0x06, 0x87, 0xed, 0xfb, 0x78, 0x52, 0x26, 0x74, 0x6c, 0xc2, 0xb0, 0x4c, 0x38, 0xb6, 0x09, 0x34, 0xb5, 0xb5, 0x21, + 0xe9, 0xc4, 0x24, 0x41, 0x89, 0x75, 0x6a, 0xda, 0xbe, 0x6f, 0xdb, 0x7e, 0x00, 0x26, 0x59, 0xa6, 0x79, 0xd7, 0xf4, + 0xc5, 0xc5, 0xc9, 0xca, 0x35, 0x8a, 0x27, 0xa9, 0x6b, 0xcd, 0x27, 0x9e, 0x0c, 0x06, 0x78, 0x68, 0x12, 0x4f, 0xab, + 0xc4, 0xb3, 0xc1, 0xc0, 0x75, 0xf5, 0xc0, 0x74, 0x75, 0xbf, 0xca, 0x3a, 0x1f, 0x0c, 0x4c, 0x97, 0xc8, 0x39, 0xe0, + 0x2b, 0xbd, 0xf7, 0xa5, 0x54, 0x82, 0xf0, 0x8b, 0xce, 0xe9, 0x69, 0x0f, 0x30, 0xcc, 0x18, 0xd6, 0x7a, 0x18, 0xdd, + 0x04, 0x30, 0xba, 0x83, 0xdf, 0xbd, 0x21, 0x4d, 0xaf, 0x69, 0x09, 0xa4, 0x5e, 0xf4, 0x5f, 0x51, 0x43, 0x1b, 0x98, + 0x9b, 0x3f, 0x13, 0xfb, 0x67, 0x88, 0x1a, 0x5f, 0x28, 0x80, 0x1b, 0xd4, 0x3a, 0x5e, 0x2f, 0x6b, 0x7a, 0xfc, 0x4c, + 0xc1, 0x4f, 0x66, 0xaa, 0x72, 0xda, 0x5b, 0x4d, 0x6f, 0x86, 0xab, 0xa9, 0xfa, 0x82, 0xfe, 0x8c, 0xff, 0x54, 0x87, + 0x71, 0xbf, 0xd9, 0x48, 0xd8, 0x9f, 0x23, 0x70, 0xc8, 0xe9, 0xa5, 0x23, 0x36, 0x41, 0xbd, 0xfe, 0x9f, 0x0a, 0x0f, + 0x1a, 0x41, 0xc6, 0x0f, 0xdb, 0x29, 0xe0, 0xae, 0xb3, 0x99, 0x18, 0xff, 0x80, 0x7a, 0xa8, 0xf7, 0xa7, 0x3a, 0xfc, + 0x13, 0xdd, 0x3b, 0xaa, 0xe6, 0xf2, 0xbb, 0x74, 0x5b, 0xb8, 0x8a, 0xe1, 0x73, 0x58, 0x6e, 0x61, 0x86, 0xdb, 0x4d, + 0x06, 0x11, 0xcf, 0xc0, 0x9f, 0x9b, 0xc4, 0xb2, 0xc1, 0x8f, 0x8e, 0x5b, 0xe8, 0x87, 0x76, 0x07, 0x34, 0x14, 0x4d, + 0x71, 0xb8, 0xbd, 0xe9, 0x8b, 0xe6, 0x31, 0x7e, 0xd0, 0x2c, 0x70, 0x1b, 0xe1, 0x66, 0xdb, 0xab, 0x8e, 0xfb, 0x2a, + 0x6e, 0x21, 0xac, 0xe2, 0x73, 0xf8, 0xe7, 0x04, 0x0d, 0xaa, 0x0d, 0x79, 0x45, 0x37, 0x7b, 0x07, 0xe7, 0x53, 0x12, + 0xab, 0x06, 0x3f, 0x3a, 0x6b, 0xa1, 0x1f, 0xce, 0x4c, 0x47, 0xec, 0x50, 0xef, 0xe8, 0x4a, 0xe2, 0x93, 0xa6, 0x84, + 0x8e, 0x5a, 0x65, 0x3f, 0x22, 0x3e, 0x45, 0x58, 0xc4, 0xc7, 0xf0, 0x4f, 0x3b, 0xec, 0xe7, 0xd7, 0xad, 0x7e, 0xcc, + 0xbc, 0xdb, 0x38, 0x39, 0xb5, 0xbe, 0xac, 0xca, 0x5e, 0x2c, 0x37, 0xd8, 0x65, 0xdb, 0xdc, 0x88, 0xb5, 0x8f, 0xe0, + 0x03, 0x61, 0x7d, 0x48, 0x14, 0x66, 0x87, 0xe0, 0x04, 0x0b, 0xb6, 0x1f, 0xea, 0xe2, 0xb8, 0xab, 0x1a, 0x0d, 0x24, + 0xfa, 0x6a, 0x70, 0x48, 0xda, 0x4d, 0xdd, 0x64, 0x18, 0x7e, 0x37, 0x48, 0x19, 0x59, 0x4d, 0x54, 0xbd, 0x3e, 0x76, + 0xbd, 0xda, 0xeb, 0x73, 0x8f, 0x1d, 0x84, 0x10, 0xd5, 0x8b, 0x75, 0x93, 0xa1, 0x23, 0xd1, 0x88, 0xf5, 0x05, 0xeb, + 0x9d, 0xa5, 0x2d, 0x64, 0xb0, 0x53, 0xf5, 0x62, 0xd6, 0xe4, 0x90, 0xde, 0x49, 0x63, 0xde, 0xd4, 0xf0, 0xeb, 0x24, + 0x98, 0x85, 0x00, 0xbc, 0xab, 0x5c, 0x7a, 0x8a, 0xa3, 0xce, 0xe9, 0x29, 0x16, 0x84, 0x27, 0x13, 0xf3, 0x4b, 0x11, + 0x9e, 0x0c, 0xcd, 0x2f, 0x49, 0x4a, 0x78, 0xd9, 0xde, 0x71, 0x41, 0x82, 0x55, 0x35, 0x29, 0x14, 0x16, 0xb4, 0x40, + 0x47, 0x1d, 0x7f, 0xb7, 0x8e, 0xa7, 0x7e, 0x0e, 0xa0, 0x4b, 0x28, 0x8c, 0x59, 0xa5, 0x6c, 0x16, 0x38, 0x27, 0xf4, + 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, + 0xb6, 0x86, 0xa7, 0x70, 0x21, 0x9a, 0x91, 0xec, 0xf0, 0xac, 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, + 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, 0xa5, 0xba, 0x6b, 0x33, 0xc0, 0x4d, 0x8f, 0xc7, 0x1a, + 0x2e, 0xf7, 0x35, 0xb8, 0xcc, 0x68, 0x70, 0xe6, 0x49, 0xb9, 0xbb, 0x55, 0x43, 0x26, 0xc4, 0xdf, 0x38, 0x54, 0x80, + 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x79, 0xa6, 0x88, 0x7f, 0x97, 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, + 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, 0x03, 0x75, 0x1d, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, + 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, 0xad, 0x34, 0xf9, 0x4c, 0xad, 0xc3, 0x02, 0xf7, 0x9e, + 0xd3, 0x66, 0xe1, 0xac, 0xdf, 0x76, 0xe9, 0xa4, 0xdd, 0x3f, 0x05, 0x83, 0x10, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, + 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, 0xa1, 0xf2, 0x5e, 0xf8, 0xa3, 0x84, 0xa4, 0xce, 0x00, + 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x2b, 0xe3, 0xbc, 0x1a, + 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0x43, 0x75, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, + 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0x30, 0x5a, 0xc1, 0x93, 0x14, 0x0c, 0x56, 0xf0, 0x30, 0x15, + 0xe0, 0x54, 0x41, 0x53, 0x16, 0x98, 0xc2, 0x3f, 0x74, 0x6a, 0x30, 0x73, 0x75, 0x4b, 0x0c, 0x96, 0x76, 0x19, 0x9c, + 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, + 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0xdf, 0x86, + 0x6b, 0xdb, 0x38, 0x5c, 0xb3, 0x43, 0x13, 0x82, 0x70, 0x15, 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0x86, + 0x24, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, + 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x9f, 0x3a, + 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, + 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0xf1, 0x1c, + 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x2e, 0x05, 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, + 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, + 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, + 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, + 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, + 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, + 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, + 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, + 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, + 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, + 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, + 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, + 0x26, 0xcd, 0x7d, 0xc0, 0x98, 0x0d, 0xb3, 0x51, 0x84, 0xcd, 0x60, 0xc6, 0xf0, 0xf7, 0x0b, 0x7f, 0xc7, 0x74, 0x1a, + 0x9d, 0xd3, 0xce, 0x90, 0x75, 0x22, 0x3c, 0x7c, 0x73, 0x23, 0xd2, 0x88, 0x9e, 0x76, 0x68, 0x87, 0x46, 0x78, 0xb8, + 0x28, 0xf2, 0xbb, 0x1b, 0x29, 0x47, 0x00, 0x84, 0xe1, 0xf9, 0xf9, 0xfd, 0x08, 0x67, 0xf4, 0x57, 0x0d, 0xb5, 0x4f, + 0xc7, 0x0f, 0x18, 0x6d, 0x45, 0xf8, 0x17, 0x5a, 0xe8, 0x8f, 0x0b, 0xe5, 0x06, 0xda, 0x82, 0x14, 0x99, 0xbd, 0x03, + 0x5d, 0x79, 0x34, 0xea, 0x9c, 0x3d, 0x68, 0xb3, 0x08, 0x67, 0x57, 0xaf, 0xa1, 0xb7, 0xfb, 0xe3, 0xd3, 0x16, 0x7c, + 0x08, 0x10, 0x3a, 0x59, 0x01, 0x8d, 0x9c, 0x9d, 0x3c, 0x38, 0x65, 0x23, 0x93, 0xa8, 0x78, 0xfe, 0xd9, 0xcc, 0xfe, + 0x1c, 0xe6, 0x93, 0x15, 0x7c, 0xa6, 0xa4, 0x48, 0xa3, 0x51, 0xd6, 0x3e, 0x39, 0x86, 0x84, 0x3b, 0x2a, 0x3c, 0x70, + 0x6e, 0xa1, 0xea, 0xf9, 0x30, 0xc2, 0xb7, 0x36, 0xf5, 0x7c, 0x68, 0x3e, 0x26, 0xef, 0x7e, 0x15, 0x6f, 0x46, 0x69, + 0x34, 0x3c, 0x3f, 0x3f, 0x6b, 0x41, 0xc2, 0x07, 0x7a, 0x97, 0x46, 0xf4, 0x01, 0xfc, 0x07, 0xd9, 0x1f, 0x9f, 0x41, + 0x87, 0x30, 0xc2, 0xdb, 0xc9, 0xc7, 0x30, 0xe7, 0xf3, 0x94, 0x7e, 0xe6, 0x69, 0x34, 0x1c, 0x0d, 0xef, 0x9f, 0x41, + 0xbd, 0x19, 0x9d, 0x3c, 0xd3, 0x14, 0xda, 0x6d, 0xb5, 0x4c, 0xcb, 0xef, 0xf8, 0x17, 0x66, 0xaa, 0x9f, 0x9e, 0x9e, + 0x0d, 0x3b, 0x30, 0x82, 0x2b, 0xd0, 0x96, 0xc0, 0x78, 0xce, 0x33, 0xd3, 0xe0, 0x55, 0xf6, 0x74, 0x94, 0x46, 0x0f, + 0x1e, 0x1c, 0x77, 0xb2, 0x2c, 0xc2, 0xb7, 0x1f, 0x47, 0xb6, 0xb6, 0xc9, 0x53, 0x00, 0xfb, 0x34, 0x62, 0x0f, 0x1e, + 0x9c, 0xdd, 0xa7, 0xf0, 0xfd, 0xdc, 0xb4, 0x75, 0x3e, 0x1e, 0x66, 0xe7, 0xd0, 0xd6, 0xef, 0x30, 0x9d, 0x93, 0xf3, + 0xe3, 0x91, 0xe9, 0xeb, 0x77, 0x33, 0xea, 0xce, 0xf8, 0x64, 0x7c, 0x62, 0x32, 0xcd, 0x50, 0xcb, 0xcf, 0xdf, 0x58, + 0x1a, 0x65, 0x6c, 0xd4, 0x8e, 0xf0, 0xad, 0x5b, 0xb8, 0x07, 0x27, 0xad, 0xd6, 0xe8, 0x38, 0xc2, 0xa3, 0x87, 0xf3, + 0xf9, 0x5b, 0x03, 0xc1, 0xf6, 0xc9, 0x03, 0xfb, 0xad, 0x3e, 0xdf, 0x41, 0xd3, 0x43, 0x03, 0xb4, 0x11, 0x9f, 0x99, + 0x96, 0xcf, 0x1e, 0xc0, 0x7f, 0xe6, 0xdb, 0x34, 0x5d, 0x7e, 0xcb, 0xd1, 0xc4, 0x2e, 0x4a, 0x9b, 0x3d, 0x68, 0x41, + 0x8d, 0x31, 0xff, 0x38, 0x2c, 0x38, 0xa0, 0xd1, 0xb0, 0x03, 0xff, 0x17, 0xe1, 0x71, 0x7e, 0xf5, 0xda, 0xe1, 0xec, + 0x78, 0x4c, 0xc7, 0xad, 0x08, 0x8f, 0xe5, 0x47, 0xa5, 0x3f, 0x3c, 0x14, 0x69, 0xd4, 0xe9, 0x9c, 0x0f, 0x4d, 0x99, + 0xc5, 0x2f, 0x8a, 0x1b, 0x3c, 0x6e, 0x99, 0x56, 0x26, 0xf4, 0xad, 0x1a, 0x5e, 0x49, 0x58, 0x49, 0xf8, 0x2f, 0xc2, + 0x13, 0x50, 0xb1, 0xb9, 0x56, 0xce, 0xed, 0x76, 0x98, 0xbc, 0x33, 0xa8, 0x39, 0xba, 0x0f, 0xf0, 0xf2, 0xcb, 0x38, + 0xa2, 0xf4, 0xb4, 0xd3, 0x8a, 0xb0, 0x19, 0xf5, 0x79, 0x0b, 0xfe, 0x8b, 0xb0, 0x85, 0x9c, 0x81, 0xeb, 0xe4, 0xe3, + 0xb3, 0x97, 0x37, 0x69, 0x44, 0x47, 0xe3, 0x31, 0x2c, 0x89, 0x99, 0x8c, 0x2f, 0x36, 0x95, 0x82, 0xdd, 0xfd, 0x7a, + 0xe3, 0xb6, 0x8b, 0x49, 0xd0, 0x0e, 0x3a, 0x67, 0x0f, 0x86, 0x27, 0x11, 0x7e, 0x3b, 0xe2, 0x54, 0xc0, 0x2a, 0x65, + 0xa3, 0xd3, 0xec, 0x34, 0x33, 0x09, 0x13, 0x99, 0x46, 0x27, 0xb0, 0xe4, 0x9d, 0x08, 0xf3, 0x2f, 0x57, 0x77, 0x16, + 0xdd, 0xa0, 0xb6, 0x43, 0x90, 0x71, 0x8b, 0x9d, 0x9d, 0x67, 0x11, 0xce, 0xe9, 0x97, 0x67, 0xbf, 0x16, 0x69, 0xc4, + 0xce, 0xd8, 0xd9, 0x98, 0xfa, 0xef, 0x3f, 0xd4, 0xd4, 0xd4, 0x68, 0x8d, 0x4f, 0x21, 0xe9, 0x46, 0x98, 0xb1, 0xde, + 0xcf, 0xc6, 0x06, 0x43, 0x5e, 0xcd, 0xa4, 0xc8, 0x9e, 0x8e, 0xc7, 0xd2, 0x62, 0x31, 0x85, 0x4d, 0xf8, 0x09, 0xa0, + 0x4d, 0x47, 0xa3, 0x73, 0x76, 0x16, 0xe1, 0x4f, 0x76, 0x97, 0xb8, 0x09, 0x7c, 0xb2, 0x98, 0xcd, 0xdc, 0x6e, 0xff, + 0x64, 0x81, 0x02, 0xf3, 0x1d, 0xd3, 0x31, 0x1d, 0x75, 0x22, 0xfc, 0xc9, 0xc0, 0x65, 0x74, 0x0c, 0xff, 0x41, 0x01, + 0xe8, 0xec, 0x41, 0x8b, 0xb1, 0x07, 0x2d, 0xf3, 0x15, 0xe6, 0xb9, 0x99, 0x0f, 0xcf, 0xb2, 0x76, 0x84, 0x3f, 0x39, + 0x74, 0x1c, 0x8f, 0x69, 0x0b, 0xd0, 0xf1, 0x93, 0x43, 0xc7, 0x4e, 0x6b, 0xd8, 0xa1, 0xe6, 0xdb, 0x62, 0xcd, 0xf9, + 0xfd, 0x8c, 0xc1, 0xe4, 0x3e, 0x59, 0x84, 0xbc, 0x7f, 0xff, 0xfc, 0xfc, 0xc1, 0x03, 0xf8, 0x34, 0x6d, 0x97, 0x9f, + 0x4a, 0x3f, 0xcc, 0x0d, 0x92, 0xb5, 0xb2, 0x13, 0xa0, 0x93, 0x9f, 0xcc, 0x18, 0xc7, 0xe3, 0x31, 0x6b, 0x45, 0x38, + 0xe7, 0x33, 0x66, 0x31, 0xc1, 0xfe, 0x36, 0x1d, 0x1d, 0x77, 0xb2, 0xd1, 0x71, 0x27, 0xc2, 0xf9, 0xdb, 0x67, 0x66, + 0x36, 0x2d, 0x98, 0xbd, 0xdf, 0x72, 0x1e, 0x6b, 0x66, 0xf4, 0x0d, 0x0c, 0x12, 0x56, 0x1a, 0x2a, 0xbf, 0x0f, 0xe8, + 0xe1, 0xd9, 0x59, 0x36, 0x82, 0x81, 0xbe, 0x87, 0x6e, 0x01, 0x8c, 0xef, 0xed, 0xe6, 0x1b, 0xd2, 0xd3, 0x53, 0x98, + 0xee, 0xfb, 0xf9, 0xa2, 0x98, 0xbf, 0x4a, 0xa3, 0x07, 0xc7, 0xf7, 0x5b, 0xa3, 0x61, 0x84, 0xdf, 0xbb, 0x09, 0x1e, + 0x67, 0xc3, 0xe3, 0xfb, 0xed, 0x08, 0xbf, 0x37, 0xfb, 0xed, 0xfe, 0xf0, 0xec, 0x1c, 0xce, 0x8d, 0xf7, 0x6a, 0x5e, + 0xbc, 0x9d, 0x98, 0x02, 0x63, 0xfa, 0x00, 0x9a, 0xfd, 0xcd, 0xec, 0xc6, 0x51, 0x1b, 0x36, 0xf2, 0x7b, 0xb3, 0xc9, + 0x0c, 0x9e, 0xdc, 0x6f, 0x9f, 0x9e, 0x9f, 0x46, 0x78, 0xc6, 0x47, 0x02, 0x08, 0xbc, 0xd9, 0x28, 0x0f, 0xda, 0x0f, + 0xee, 0xb7, 0x22, 0x3c, 0x7b, 0xab, 0xb3, 0x8f, 0x74, 0x66, 0xa8, 0xf1, 0x18, 0x60, 0x36, 0xe3, 0x4a, 0xdf, 0xbd, + 0x51, 0x8e, 0x1e, 0xb3, 0x76, 0x84, 0x67, 0x32, 0xcb, 0xa8, 0x7a, 0x6b, 0x13, 0x86, 0xa7, 0x11, 0x16, 0xf4, 0x0b, + 0xfd, 0x5b, 0xfa, 0xcd, 0x34, 0x62, 0x74, 0x64, 0xd2, 0x0c, 0x0e, 0x47, 0xf8, 0xdd, 0x08, 0x6e, 0xf4, 0xd2, 0x68, + 0x3c, 0x1a, 0x9f, 0x02, 0x78, 0x80, 0x00, 0x59, 0xec, 0x06, 0x68, 0xc0, 0xd7, 0xe8, 0xd1, 0x30, 0x8d, 0xce, 0x86, + 0xe7, 0xac, 0x73, 0x1c, 0xe1, 0x92, 0x1a, 0xd1, 0x53, 0xc8, 0x37, 0x9f, 0x1f, 0xcd, 0x96, 0x3a, 0xb1, 0x09, 0x06, + 0x40, 0x23, 0x7a, 0xbf, 0x35, 0x3a, 0x8b, 0xf0, 0xfc, 0x35, 0xf3, 0x7b, 0x8c, 0x31, 0x76, 0x0e, 0xb0, 0x84, 0x24, + 0x83, 0x40, 0xe7, 0xe3, 0xe1, 0x83, 0x73, 0xf3, 0x0d, 0x60, 0xa0, 0x63, 0xc6, 0x00, 0x48, 0xf3, 0xd7, 0xac, 0x04, + 0xc4, 0x68, 0x78, 0xbf, 0x05, 0xf4, 0x65, 0x4e, 0xe7, 0xf4, 0x8e, 0xde, 0x3c, 0x9d, 0x9b, 0x39, 0x8d, 0x47, 0xa7, + 0x11, 0x9e, 0x3f, 0xff, 0x65, 0xbe, 0x18, 0x8f, 0xcd, 0x84, 0xe8, 0xf0, 0x41, 0x84, 0xe7, 0xac, 0x58, 0xc0, 0x1a, + 0x9d, 0x9f, 0x1e, 0x8f, 0x23, 0xec, 0xd0, 0x30, 0x6b, 0x65, 0x43, 0xb8, 0xb2, 0x5c, 0xcc, 0xd2, 0x68, 0x34, 0xa2, + 0xad, 0x11, 0x5c, 0x60, 0xca, 0x9b, 0x5f, 0x0b, 0x8b, 0x46, 0xcc, 0xe0, 0x83, 0x5b, 0x43, 0x98, 0x2f, 0xc0, 0xe3, + 0xe3, 0x90, 0x65, 0x19, 0x75, 0x89, 0x67, 0x67, 0xc7, 0xc7, 0x80, 0x7b, 0x76, 0x86, 0x16, 0x41, 0xde, 0xa8, 0xbb, + 0x61, 0x21, 0xe1, 0xe8, 0x02, 0xa2, 0x0a, 0x64, 0xf5, 0xcd, 0xdd, 0x6b, 0x43, 0x57, 0xdb, 0x67, 0x0f, 0x60, 0x01, + 0x14, 0x1d, 0x8d, 0x5e, 0xd9, 0xc3, 0xed, 0x7c, 0x78, 0x72, 0xda, 0x3e, 0x8e, 0xb0, 0xdf, 0x08, 0xf4, 0xbc, 0x75, + 0xbf, 0x03, 0x25, 0xc4, 0xe8, 0xce, 0x96, 0x18, 0x9f, 0xd0, 0x93, 0xb3, 0x56, 0x84, 0xfd, 0xd6, 0x60, 0xe7, 0xc3, + 0xd3, 0xfb, 0xf0, 0xa9, 0xa6, 0x2c, 0xcf, 0x0d, 0x7e, 0x9f, 0x02, 0x5c, 0x14, 0x7f, 0x26, 0x68, 0x1a, 0xd1, 0xd6, + 0x69, 0xa7, 0x33, 0x82, 0xcf, 0xfc, 0x0b, 0x2b, 0xd2, 0x28, 0x6b, 0xc1, 0x7f, 0x11, 0x0e, 0x76, 0x12, 0x1b, 0x46, + 0xd8, 0xe0, 0xdd, 0x19, 0x3d, 0x35, 0x7b, 0xdf, 0xed, 0xaa, 0xd6, 0x79, 0x0b, 0x36, 0xac, 0xdb, 0x54, 0xee, 0x4b, + 0x09, 0x79, 0xe3, 0x48, 0x2c, 0x8d, 0x70, 0x80, 0xa0, 0xe3, 0xfb, 0xe3, 0x08, 0xfb, 0x1d, 0x77, 0x72, 0x76, 0xde, + 0x01, 0x52, 0xa6, 0x81, 0x50, 0x8c, 0x3a, 0xc3, 0x13, 0x20, 0x4d, 0x9a, 0xbd, 0xb6, 0x78, 0x12, 0x61, 0xfd, 0x54, + 0xe9, 0x57, 0x69, 0x34, 0x3a, 0x1f, 0x8e, 0x47, 0xe7, 0x11, 0xd6, 0x72, 0x46, 0xb5, 0x34, 0x14, 0xf0, 0xf8, 0xe4, + 0x7e, 0x84, 0x0d, 0x9a, 0xb7, 0x58, 0x6b, 0xd4, 0x8a, 0xb0, 0x3b, 0x4a, 0x18, 0x3b, 0xef, 0xc0, 0xb4, 0x7e, 0x7e, + 0xae, 0x01, 0x97, 0x47, 0x6c, 0x78, 0x1c, 0xe1, 0x92, 0xde, 0x1b, 0x42, 0x04, 0x5f, 0x6a, 0x26, 0x3f, 0x3b, 0xd6, + 0x03, 0x48, 0x9d, 0xdf, 0xf0, 0xb0, 0x0c, 0x2f, 0x6f, 0x2c, 0x1a, 0x51, 0xb3, 0xc5, 0x83, 0x2b, 0xdd, 0x27, 0x34, + 0xf6, 0x6c, 0x3b, 0x27, 0xcb, 0x35, 0x2e, 0x23, 0xa5, 0x7e, 0x66, 0x77, 0x2a, 0x56, 0xca, 0x70, 0xb2, 0x41, 0x0a, + 0x78, 0x33, 0x38, 0xdf, 0x00, 0xe7, 0xfe, 0x09, 0x82, 0xa4, 0x20, 0xad, 0xae, 0xb8, 0xf0, 0x2e, 0xa9, 0x5d, 0x01, + 0xf1, 0x13, 0x20, 0xbd, 0x20, 0x94, 0x68, 0x08, 0x33, 0x63, 0x85, 0x49, 0x6f, 0xa9, 0x6f, 0x64, 0x4a, 0x69, 0x6d, + 0xff, 0x29, 0xa1, 0x3e, 0xc0, 0x3c, 0xdc, 0x37, 0x43, 0x08, 0x26, 0xd4, 0x95, 0xc4, 0x84, 0x8b, 0x7e, 0x21, 0x74, + 0xac, 0x54, 0xbf, 0x18, 0xe0, 0xf6, 0x19, 0xc2, 0x10, 0x88, 0x81, 0xf4, 0xe5, 0xe5, 0x65, 0xfb, 0xec, 0xc0, 0x08, + 0x7d, 0x97, 0x97, 0xe7, 0xf6, 0x07, 0xfc, 0x3b, 0xa8, 0x82, 0x5f, 0xc3, 0xf8, 0x1e, 0xb1, 0x40, 0xa3, 0x67, 0xf8, + 0xeb, 0x47, 0x6c, 0xb5, 0x8a, 0x1f, 0x31, 0x02, 0x33, 0xc6, 0x8f, 0x58, 0x62, 0x2e, 0x40, 0xac, 0x9b, 0x0d, 0xe9, + 0x83, 0xe6, 0xac, 0x85, 0x21, 0x24, 0xbb, 0xe7, 0xbc, 0x1f, 0xb1, 0x3e, 0xaf, 0xbb, 0x68, 0x57, 0x71, 0x90, 0x0f, + 0x0e, 0x96, 0x45, 0xaa, 0xad, 0x98, 0xa0, 0xad, 0x98, 0xa0, 0xad, 0x98, 0xa0, 0xab, 0x48, 0xf4, 0x27, 0x3d, 0x90, + 0x52, 0x8c, 0xb2, 0xc5, 0xf1, 0xd4, 0xef, 0x40, 0xed, 0x01, 0xda, 0xc9, 0x5e, 0xa5, 0xec, 0x28, 0x75, 0x15, 0x3b, + 0x15, 0x18, 0x3b, 0x13, 0x9d, 0xb6, 0xe3, 0xe8, 0xdf, 0x51, 0x77, 0xbc, 0xac, 0x89, 0x65, 0xef, 0x76, 0x8a, 0x65, + 0xb0, 0x92, 0x46, 0x34, 0xdb, 0xb7, 0x41, 0x3d, 0x74, 0xff, 0xbe, 0x11, 0xcc, 0xaa, 0x48, 0x73, 0x0d, 0x48, 0xea, + 0x82, 0x14, 0x72, 0x6e, 0xa4, 0xb4, 0x02, 0xa5, 0x23, 0x1d, 0x17, 0xa0, 0xa1, 0xf4, 0x0a, 0xca, 0x32, 0x20, 0x6a, + 0xc3, 0x00, 0x44, 0x59, 0x19, 0xcd, 0xca, 0x6a, 0xa7, 0x20, 0xba, 0x80, 0x26, 0xcc, 0x48, 0x2c, 0xd0, 0x80, 0x30, + 0x0d, 0x08, 0x57, 0x19, 0xc4, 0x19, 0x97, 0x7d, 0x62, 0xb2, 0x95, 0xc9, 0x56, 0x65, 0xb6, 0xf4, 0xd9, 0x56, 0x48, + 0x94, 0x26, 0x5b, 0x96, 0xd9, 0x20, 0xb3, 0xe1, 0x49, 0xaa, 0xf0, 0x30, 0x95, 0x56, 0x54, 0xab, 0x64, 0xab, 0xb7, + 0x34, 0xd4, 0xe6, 0x1e, 0x1c, 0xc4, 0xa5, 0x9c, 0x64, 0xd4, 0xc4, 0xf7, 0x96, 0x3c, 0x29, 0x8c, 0x0c, 0xc4, 0x93, + 0x89, 0xfb, 0x3b, 0x5c, 0x6f, 0xca, 0x4a, 0xc5, 0x64, 0xf8, 0x8d, 0x92, 0xe8, 0x2f, 0xaf, 0x44, 0x7d, 0xc4, 0x4d, + 0x28, 0x9d, 0x0b, 0x92, 0xb4, 0x5a, 0xc7, 0xed, 0xe3, 0xd6, 0x79, 0x8f, 0x1f, 0xb6, 0x3b, 0xc9, 0x83, 0x4e, 0x6a, + 0x14, 0x11, 0x73, 0x79, 0x03, 0x0a, 0x98, 0xa3, 0x4e, 0x72, 0x82, 0x0e, 0xdb, 0x49, 0xeb, 0xf4, 0xb4, 0x09, 0xff, + 0xe0, 0xf7, 0xba, 0xac, 0x76, 0xd2, 0x3a, 0x39, 0xed, 0xf1, 0xa3, 0x8d, 0x4a, 0x31, 0x6f, 0x40, 0x41, 0x74, 0x64, + 0x2a, 0x61, 0xa8, 0x5f, 0x2d, 0xef, 0xb3, 0x2d, 0x3d, 0xcf, 0x7b, 0x1d, 0x2b, 0xab, 0x8a, 0x03, 0xa8, 0xfa, 0xaf, + 0x89, 0x01, 0xa2, 0xff, 0x1a, 0x96, 0xe1, 0x6e, 0x97, 0x05, 0x88, 0xda, 0x8f, 0x78, 0x2c, 0x1a, 0xec, 0x30, 0xb6, + 0xf9, 0x1a, 0xea, 0x36, 0x21, 0x04, 0x1d, 0x9e, 0xb8, 0x5c, 0x15, 0xe6, 0x4e, 0x10, 0x6a, 0x2a, 0xc8, 0x1d, 0xba, + 0x5c, 0x19, 0xe6, 0x0e, 0x11, 0x6a, 0x4a, 0xc8, 0xa5, 0x29, 0x4f, 0x28, 0xe4, 0xe8, 0x84, 0x36, 0x0d, 0x24, 0xab, + 0x45, 0x79, 0xce, 0xfc, 0xb0, 0xf9, 0x18, 0x96, 0xc7, 0x10, 0x14, 0x27, 0x48, 0x0b, 0x78, 0xa6, 0xa4, 0xd4, 0xe6, + 0xb4, 0x70, 0xa9, 0xc6, 0x81, 0x8c, 0x06, 0xfc, 0x73, 0xc8, 0xcc, 0xdb, 0x15, 0xad, 0xde, 0xf1, 0x59, 0x2b, 0x6d, + 0x83, 0xbf, 0x35, 0xc8, 0xda, 0xc2, 0xca, 0xda, 0xc2, 0xcb, 0xda, 0xc2, 0xcb, 0xda, 0x20, 0xc0, 0x07, 0x7d, 0xff, + 0x23, 0x6b, 0x36, 0x2c, 0xbc, 0x34, 0x88, 0xb1, 0x16, 0x0f, 0xb1, 0x5e, 0xad, 0x96, 0x6b, 0x30, 0x57, 0x2a, 0x6b, + 0x48, 0x55, 0xa9, 0x3f, 0x97, 0x45, 0xda, 0xc2, 0x93, 0x14, 0xb4, 0xdc, 0x2d, 0x4c, 0xcd, 0xe6, 0xf6, 0x54, 0x61, + 0x33, 0x14, 0x4e, 0xcf, 0xab, 0x93, 0x2f, 0xc9, 0xb1, 0xd1, 0x1e, 0x2f, 0x8b, 0x94, 0x5b, 0x9a, 0xc1, 0x2d, 0xcd, + 0xe0, 0x96, 0x66, 0x40, 0x23, 0xb8, 0x2c, 0x6c, 0xca, 0x26, 0x94, 0xc0, 0x95, 0x40, 0xff, 0x78, 0x00, 0x91, 0x00, + 0x63, 0x4d, 0xcc, 0xa8, 0x37, 0x3a, 0x6f, 0x43, 0xe4, 0x33, 0x5b, 0x52, 0x27, 0xd4, 0x38, 0x80, 0x97, 0x63, 0xfe, + 0x5a, 0x43, 0xfb, 0x04, 0x9e, 0xa5, 0x79, 0xa8, 0xe3, 0x16, 0xd8, 0x7f, 0x44, 0x45, 0xd4, 0x33, 0x64, 0x21, 0x35, + 0x3a, 0x1b, 0x67, 0xd7, 0xfd, 0x79, 0xc3, 0x9d, 0xd6, 0x52, 0x82, 0xf0, 0x31, 0x86, 0xcf, 0xac, 0xf2, 0xef, 0x2f, + 0xcd, 0x56, 0x9d, 0xcd, 0x99, 0x3d, 0x12, 0xba, 0x60, 0x7b, 0xee, 0x03, 0x47, 0xf5, 0x04, 0x91, 0xca, 0x78, 0x3e, + 0x92, 0x2a, 0xf4, 0x31, 0x78, 0x02, 0x93, 0x5b, 0x6a, 0xfc, 0x62, 0x5e, 0xd8, 0x3f, 0x5f, 0x69, 0xe0, 0x38, 0x58, + 0x4c, 0x86, 0xde, 0xdf, 0xf6, 0xda, 0x04, 0x08, 0x22, 0xfb, 0xfb, 0xd6, 0x2c, 0xdc, 0x7c, 0x6d, 0xda, 0x85, 0x9b, + 0x44, 0x93, 0x0d, 0x3b, 0xd4, 0xaf, 0xd1, 0x3f, 0xde, 0xed, 0xad, 0x98, 0x0c, 0x51, 0x40, 0xb3, 0x0d, 0x58, 0x55, + 0x05, 0x2c, 0xe5, 0xea, 0x95, 0xde, 0x90, 0xd0, 0xbb, 0x19, 0xf3, 0xba, 0x98, 0x0c, 0x77, 0xbe, 0x5f, 0x62, 0x7b, + 0xec, 0xbd, 0xa5, 0x41, 0x0f, 0x5e, 0xb5, 0x3d, 0x65, 0xb7, 0xdf, 0xab, 0x73, 0xb3, 0xb3, 0x8e, 0xca, 0xbf, 0x57, + 0xe7, 0xe9, 0xae, 0x3a, 0x33, 0x7e, 0x1b, 0xfb, 0xbd, 0xa3, 0x03, 0x35, 0xb6, 0xb1, 0x35, 0x9a, 0x0c, 0x21, 0xe0, + 0x3c, 0xfc, 0xb5, 0x61, 0x61, 0xba, 0x9e, 0x84, 0xc3, 0x2a, 0xc8, 0x5e, 0x72, 0x9a, 0x32, 0x4c, 0x49, 0xe7, 0xb0, + 0x30, 0x81, 0x61, 0x44, 0x42, 0x9b, 0x2a, 0xa1, 0x38, 0x27, 0x71, 0x4c, 0x0f, 0x33, 0x08, 0x6f, 0xd3, 0xee, 0xd1, + 0x34, 0xa6, 0x8d, 0x0c, 0x1d, 0xc5, 0xed, 0x06, 0x3d, 0xcc, 0x10, 0x6a, 0xb4, 0x41, 0x67, 0x2a, 0x49, 0xbb, 0x99, + 0x43, 0xc0, 0x4b, 0x43, 0x8a, 0xf3, 0x43, 0x91, 0x14, 0x0d, 0x79, 0xa8, 0x92, 0xa2, 0x91, 0x9c, 0x62, 0x91, 0x4c, + 0xca, 0xe4, 0x89, 0x49, 0x9e, 0xd8, 0xe4, 0x61, 0x99, 0x3c, 0x34, 0xc9, 0x43, 0x9b, 0x4c, 0x49, 0x71, 0x28, 0x12, + 0xda, 0x88, 0xdb, 0xcd, 0x02, 0x1d, 0xc2, 0x08, 0xfc, 0xe8, 0x89, 0x08, 0xe3, 0x8c, 0xaf, 0x8d, 0xa1, 0xce, 0x5c, + 0xe6, 0x2e, 0xf2, 0x67, 0x05, 0xa4, 0xd2, 0x7b, 0x0a, 0xea, 0x3c, 0x0b, 0xc0, 0x84, 0xb5, 0xfd, 0xe3, 0xe3, 0xda, + 0xad, 0xb3, 0x5c, 0x8a, 0xc0, 0x3b, 0x0c, 0x0c, 0xda, 0x3f, 0x3b, 0x9f, 0x18, 0x80, 0xea, 0x9a, 0xe6, 0xf3, 0x29, + 0xdd, 0x72, 0xc1, 0x2d, 0x26, 0x43, 0xb7, 0xb3, 0xca, 0x66, 0x18, 0x2d, 0x6c, 0xbc, 0xe8, 0xba, 0xb3, 0x24, 0x80, + 0xda, 0x3b, 0x68, 0x26, 0xd4, 0x28, 0xc9, 0x6d, 0x8d, 0x49, 0xc1, 0xee, 0x54, 0x46, 0x73, 0x16, 0x57, 0x07, 0x70, + 0x35, 0x4c, 0x46, 0x5e, 0x80, 0x59, 0x7d, 0x71, 0x98, 0x1c, 0x37, 0x74, 0x32, 0x39, 0x4c, 0x4e, 0x1f, 0x34, 0x74, + 0x32, 0x3c, 0x4c, 0xda, 0xed, 0x0a, 0x67, 0x93, 0x82, 0xe8, 0x64, 0x42, 0x34, 0x68, 0x0c, 0x6d, 0xa3, 0x72, 0x4e, + 0xc1, 0x4e, 0xec, 0xdf, 0x18, 0x46, 0xc3, 0x0d, 0x43, 0xb0, 0x89, 0x0d, 0x9d, 0xb9, 0x35, 0x86, 0xb0, 0x9b, 0xce, + 0xe9, 0x69, 0x53, 0x27, 0x05, 0xd6, 0x76, 0x25, 0x9b, 0x3a, 0x99, 0x60, 0x6d, 0x97, 0xaf, 0xa9, 0x93, 0xa1, 0x6d, + 0xca, 0xe8, 0x00, 0x99, 0x08, 0x80, 0xf5, 0x9c, 0x05, 0x90, 0xef, 0x78, 0x4f, 0x97, 0x35, 0x68, 0x0d, 0xbf, 0x57, + 0xae, 0xe9, 0x0b, 0x2a, 0xaa, 0xc1, 0x5e, 0x88, 0x7d, 0xab, 0x68, 0xbb, 0x6a, 0x92, 0xfd, 0xeb, 0xb2, 0x65, 0xb3, + 0x85, 0xd4, 0xf5, 0x82, 0x0f, 0x6b, 0x18, 0xe2, 0x4a, 0xb9, 0x83, 0xfb, 0x15, 0x25, 0x31, 0x04, 0xc8, 0x33, 0xa7, + 0x10, 0x27, 0x5e, 0x8f, 0x0c, 0x49, 0xbc, 0xd1, 0x58, 0xa3, 0x38, 0x38, 0x6f, 0x9f, 0x86, 0x54, 0x75, 0x2b, 0x6a, + 0x1e, 0x21, 0xd1, 0x42, 0x58, 0xbb, 0xca, 0x51, 0x14, 0xb0, 0x20, 0x4e, 0xbb, 0x5b, 0x3b, 0x20, 0x0e, 0x0e, 0x36, + 0xcf, 0x0b, 0xff, 0x7e, 0xc1, 0xd6, 0x9b, 0x05, 0x95, 0x51, 0x9e, 0x7f, 0x55, 0xc9, 0x9a, 0xeb, 0xf2, 0x00, 0x51, + 0x7c, 0xfc, 0xaa, 0xfb, 0x86, 0xc2, 0xf7, 0xab, 0xe0, 0x7d, 0x2e, 0xa7, 0x79, 0x66, 0x32, 0x4c, 0x5f, 0x83, 0x60, + 0x6c, 0x6f, 0xc2, 0x09, 0x95, 0x06, 0x87, 0xff, 0xb2, 0xe3, 0xa0, 0x13, 0xf7, 0xea, 0x4b, 0xd8, 0xe8, 0xdf, 0xa1, + 0x79, 0x6f, 0x05, 0x1b, 0xe7, 0xd8, 0xbd, 0x5a, 0xd5, 0xde, 0xf8, 0xb1, 0x2f, 0xc9, 0xa0, 0x83, 0x03, 0xae, 0x9e, + 0x81, 0x45, 0x32, 0x8b, 0x1b, 0xe1, 0xe1, 0xfb, 0x4f, 0xed, 0xb4, 0xfe, 0xdb, 0x9c, 0xab, 0x69, 0x70, 0xd0, 0x3d, + 0xac, 0xe5, 0xef, 0x5c, 0x89, 0x9e, 0x4e, 0xb9, 0x5b, 0xeb, 0xbf, 0x2b, 0x7b, 0xef, 0xad, 0xd7, 0xa6, 0x0e, 0x0e, + 0x78, 0x15, 0xf3, 0x29, 0xfa, 0x21, 0x42, 0x3d, 0x23, 0x83, 0x3c, 0xcb, 0x25, 0x85, 0x1b, 0x51, 0xb8, 0x62, 0x48, + 0x1b, 0xfc, 0x48, 0xe3, 0x3f, 0xe4, 0xff, 0xa7, 0x46, 0x0e, 0x75, 0xda, 0xe0, 0x81, 0x00, 0x16, 0xb2, 0x42, 0x55, + 0xb4, 0x45, 0x03, 0xe9, 0xd0, 0x7c, 0x1b, 0x95, 0x87, 0x39, 0x9d, 0xcf, 0xf3, 0x3b, 0xf3, 0xe0, 0x56, 0xc0, 0x51, + 0x55, 0x17, 0x4d, 0x2e, 0xd4, 0x1d, 0x2e, 0x80, 0xa7, 0x07, 0xdc, 0x43, 0xc6, 0x55, 0xb5, 0xbc, 0xdc, 0x16, 0x08, + 0x24, 0x33, 0x45, 0x64, 0xb3, 0xdd, 0x55, 0x97, 0x20, 0x97, 0x35, 0x9b, 0x48, 0xbb, 0x08, 0xe0, 0x98, 0x83, 0x4c, + 0xa6, 0xac, 0x3b, 0xea, 0x9e, 0x2d, 0x08, 0x92, 0x9b, 0x34, 0x22, 0xdb, 0xee, 0x52, 0x7c, 0x1c, 0x03, 0x1a, 0x21, + 0x2b, 0xf0, 0x85, 0xc2, 0x22, 0x07, 0xae, 0xb3, 0xf0, 0x1d, 0x7f, 0xa3, 0xa5, 0xa2, 0xaf, 0x06, 0x03, 0x5c, 0x98, + 0x37, 0x26, 0xca, 0xf9, 0x14, 0x2a, 0x78, 0xb3, 0x28, 0x10, 0x51, 0xf8, 0x6a, 0xb5, 0x0f, 0x4f, 0x02, 0xb9, 0x36, + 0xc1, 0x7f, 0xd5, 0xfd, 0xac, 0x9e, 0xff, 0x80, 0x71, 0x30, 0xd2, 0x32, 0x17, 0x85, 0x4e, 0xde, 0x64, 0x17, 0xa2, + 0xdb, 0x68, 0x30, 0x13, 0xad, 0x89, 0x40, 0x68, 0x36, 0x70, 0x2e, 0x84, 0x3f, 0x36, 0x00, 0x93, 0x62, 0x36, 0x8c, + 0x1d, 0xc4, 0xd7, 0xae, 0x25, 0xac, 0x56, 0xca, 0x86, 0x49, 0x31, 0x39, 0x36, 0x60, 0x4a, 0xd9, 0x4f, 0x19, 0x8f, + 0xb5, 0x32, 0xe3, 0xe0, 0x6e, 0xab, 0xbf, 0xad, 0xf6, 0xf3, 0x1e, 0xb7, 0xd7, 0x78, 0xdc, 0x04, 0x1f, 0x30, 0x80, + 0x5a, 0x6e, 0x6c, 0x70, 0x6b, 0x2c, 0x1f, 0x5b, 0xcb, 0x5e, 0xb6, 0x09, 0x41, 0x51, 0x3a, 0xdb, 0xdb, 0x9b, 0x5b, + 0x1f, 0x7c, 0x50, 0x99, 0x39, 0x29, 0xa4, 0xfb, 0x20, 0x47, 0x0f, 0x08, 0x74, 0x6e, 0x7f, 0x56, 0x74, 0xa1, 0x92, + 0x89, 0xcb, 0x31, 0xfe, 0x12, 0xdc, 0xe6, 0xf5, 0xa3, 0xeb, 0x6b, 0xb3, 0xc9, 0xaf, 0xaf, 0x23, 0x1c, 0x5a, 0xa8, + 0x47, 0x01, 0x2f, 0x18, 0x0d, 0xca, 0xf8, 0x54, 0x66, 0xe3, 0x37, 0xdb, 0x55, 0x63, 0xef, 0x69, 0x85, 0x77, 0xb0, + 0x3c, 0xa6, 0xf1, 0x2d, 0x8f, 0xce, 0x3e, 0x07, 0x78, 0xb3, 0x3e, 0x1f, 0x74, 0xdf, 0xc4, 0x0a, 0x1d, 0x1c, 0xbc, + 0x89, 0x25, 0xea, 0x5d, 0x31, 0x73, 0xe7, 0x06, 0x2e, 0xdd, 0x7d, 0x6e, 0x86, 0x2f, 0x03, 0x04, 0xb8, 0x62, 0x9b, + 0x92, 0xcd, 0x5b, 0x13, 0x40, 0x23, 0x85, 0x00, 0xdd, 0x10, 0x26, 0xd8, 0x81, 0x04, 0x7a, 0x7d, 0x13, 0x42, 0xbb, + 0xcb, 0x08, 0x03, 0x16, 0xbe, 0x74, 0xb8, 0x63, 0xc9, 0x8c, 0x15, 0x13, 0x56, 0xac, 0x56, 0xef, 0xa9, 0x75, 0xa2, + 0xdb, 0x88, 0xf7, 0xa8, 0xba, 0x8d, 0x06, 0x35, 0xe3, 0x07, 0xf1, 0x81, 0x0e, 0xf0, 0xfe, 0x9b, 0xb8, 0x40, 0x08, + 0x2c, 0x8c, 0xb8, 0x58, 0x78, 0x87, 0xb1, 0xac, 0xb6, 0x2e, 0x05, 0x2a, 0x1b, 0xc9, 0x49, 0x0b, 0x4f, 0x49, 0x56, + 0xae, 0xd1, 0xc5, 0xb4, 0xdb, 0x68, 0xe4, 0x48, 0xc6, 0x59, 0x3f, 0x1f, 0x60, 0x8e, 0x0b, 0xb8, 0x4c, 0xdd, 0x5e, + 0x87, 0x39, 0xab, 0x51, 0x2e, 0x37, 0xdf, 0xa5, 0x1d, 0x6b, 0xfa, 0x88, 0xae, 0x03, 0x60, 0x3c, 0xa2, 0x01, 0x91, + 0xd8, 0x05, 0x64, 0x61, 0x81, 0xac, 0x3c, 0x90, 0x85, 0x01, 0xb2, 0x42, 0xbd, 0x39, 0x44, 0x3e, 0x52, 0x28, 0xdd, + 0xa2, 0xe8, 0xf5, 0x18, 0x9d, 0xce, 0xff, 0x03, 0x73, 0x13, 0x26, 0xc2, 0x2d, 0x07, 0xf8, 0x82, 0x38, 0x97, 0x42, + 0x45, 0x96, 0x51, 0x64, 0xc2, 0xd5, 0xe2, 0x5b, 0xf3, 0x27, 0xb9, 0xc5, 0x77, 0xf6, 0xc7, 0x5d, 0xa0, 0x4c, 0x7a, + 0x5e, 0xd3, 0x36, 0x70, 0x17, 0xdc, 0x2d, 0x4a, 0x22, 0x40, 0x6b, 0x17, 0xa9, 0x50, 0xd4, 0x1f, 0x6f, 0x53, 0x36, + 0xa6, 0x84, 0x68, 0x10, 0x85, 0x45, 0x40, 0x3a, 0xff, 0xfc, 0x33, 0x42, 0x3d, 0x01, 0x21, 0x81, 0xdc, 0xc9, 0xd6, + 0x6c, 0xa3, 0x46, 0x94, 0x44, 0x69, 0xec, 0x23, 0x4e, 0xc0, 0xce, 0x88, 0xa2, 0xe0, 0xe1, 0x96, 0x72, 0x18, 0x1f, + 0x6a, 0xc3, 0x30, 0x83, 0xaa, 0x62, 0x68, 0x5c, 0x2e, 0x37, 0x23, 0x16, 0x19, 0xa8, 0x0a, 0x13, 0x2e, 0x06, 0xd9, + 0xd7, 0xcc, 0x18, 0x61, 0x07, 0x07, 0xac, 0x2f, 0x06, 0xc1, 0xf3, 0x64, 0xd5, 0x75, 0xb8, 0x0e, 0x17, 0x2e, 0xa6, + 0x10, 0x32, 0x7e, 0xb5, 0xb2, 0x7f, 0xc9, 0x07, 0x23, 0xcd, 0xc0, 0x3b, 0x73, 0xc1, 0x19, 0x2b, 0x76, 0xcb, 0x62, + 0x89, 0x96, 0xbf, 0x83, 0xd9, 0x9e, 0x0b, 0x00, 0xc8, 0xdd, 0x54, 0xdb, 0x1e, 0xea, 0x73, 0xa3, 0x51, 0x08, 0xc2, + 0xef, 0x56, 0x47, 0x1a, 0x9e, 0xeb, 0x30, 0xaf, 0x16, 0x46, 0x37, 0x53, 0x65, 0x34, 0x54, 0x38, 0x52, 0x12, 0x30, + 0x41, 0x37, 0x74, 0x12, 0x7e, 0xd4, 0xa9, 0xa4, 0x63, 0x21, 0x01, 0x0a, 0x1c, 0x99, 0xcb, 0x79, 0x13, 0xed, 0x9e, + 0xa1, 0x1d, 0x44, 0x2e, 0x30, 0xa1, 0xa9, 0xcb, 0x96, 0x2e, 0x2c, 0x55, 0x34, 0x93, 0x0b, 0xc5, 0x16, 0x73, 0x38, + 0xdf, 0xcb, 0xb4, 0x2c, 0xe7, 0xd9, 0xe7, 0x7a, 0x0a, 0x58, 0x3b, 0xde, 0xea, 0x19, 0x13, 0x8b, 0xc8, 0xcd, 0xf3, + 0xab, 0x15, 0xf7, 0xdf, 0xbc, 0xc0, 0x8f, 0x48, 0xe7, 0xf0, 0x2b, 0xfe, 0x48, 0xc9, 0xa3, 0xc6, 0x57, 0x3c, 0xe1, + 0xc4, 0xf2, 0x06, 0xc9, 0x9b, 0xd7, 0x57, 0x2f, 0xde, 0xbd, 0x78, 0xff, 0xf4, 0xfa, 0xc5, 0xab, 0x67, 0x2f, 0x5e, + 0xbd, 0x78, 0xf7, 0x11, 0xff, 0x43, 0xc9, 0xd7, 0xa3, 0xf6, 0x79, 0x0b, 0x7f, 0x20, 0x5f, 0x8f, 0x3a, 0xf8, 0x56, + 0x93, 0xaf, 0x47, 0x27, 0x38, 0x57, 0xe4, 0xeb, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0xb4, 0x6d, 0x32, 0x97, 0x93, 0x76, + 0x0b, 0xff, 0xe3, 0xbe, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x1b, 0xc6, 0x0f, 0xa6, 0x0c, 0x1d, 0x2a, 0x63, 0x88, + 0x72, 0x11, 0xa0, 0xd3, 0x54, 0x85, 0xe8, 0x64, 0xe3, 0x31, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, 0xae, 0x1d, 0x7e, + 0xd4, 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd3, 0x62, 0x8c, 0x73, 0x29, 0x8b, 0x78, + 0x01, 0x8c, 0x80, 0xd1, 0x5a, 0xf0, 0xa3, 0x32, 0xf0, 0x93, 0xb8, 0x20, 0xed, 0x5e, 0x3b, 0x15, 0x17, 0xa4, 0xd3, + 0xeb, 0xc0, 0x9f, 0xd3, 0xde, 0x69, 0xda, 0x6e, 0xa1, 0xc3, 0x60, 0x1c, 0x7f, 0xd4, 0xd0, 0xba, 0x3f, 0xc0, 0xae, + 0x0b, 0xf5, 0x4f, 0xa1, 0xbd, 0x4a, 0x4f, 0x38, 0x75, 0x6c, 0xbb, 0x2b, 0x2e, 0x98, 0xd1, 0xc3, 0xf2, 0x1f, 0x00, + 0xb5, 0x8d, 0x6f, 0x4a, 0xb9, 0x71, 0xdc, 0x2f, 0x7e, 0x24, 0x50, 0x2d, 0xba, 0x4c, 0xcc, 0x56, 0x2d, 0x04, 0x4c, + 0xa3, 0xc9, 0x06, 0x73, 0xa0, 0x44, 0xc9, 0x42, 0xfb, 0x08, 0xf9, 0xaa, 0x29, 0x51, 0x32, 0x97, 0xf3, 0xb8, 0xa6, + 0x6a, 0xf8, 0x35, 0x30, 0x73, 0xdc, 0xe7, 0xea, 0x15, 0x7d, 0x15, 0xd7, 0x78, 0x9e, 0x90, 0xb5, 0x0b, 0xb7, 0xc5, + 0x2f, 0xce, 0x8a, 0xa2, 0x06, 0xae, 0x12, 0xb0, 0x7e, 0x54, 0x4d, 0x7d, 0x01, 0x4f, 0x01, 0xb2, 0x86, 0xbe, 0x24, + 0x01, 0xf5, 0xfc, 0xa9, 0x34, 0xe3, 0x2a, 0x95, 0xd1, 0x5e, 0x11, 0x6d, 0xcc, 0x82, 0xbc, 0x22, 0xfa, 0x42, 0x19, + 0x20, 0x48, 0xc2, 0xfb, 0x62, 0x00, 0x07, 0xbe, 0x1d, 0xa0, 0x34, 0x74, 0x0e, 0xd4, 0x4a, 0x95, 0x99, 0x90, 0xf9, + 0x34, 0x71, 0x0e, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xcc, 0x27, 0x96, 0x28, 0x18, 0xfa, 0x6f, 0xe1, 0x06, 0x38, 0x8c, + 0x0d, 0x2a, 0x06, 0xd9, 0xf7, 0x44, 0x3d, 0xbf, 0x7d, 0xde, 0x3a, 0xfa, 0x1a, 0xe4, 0x8f, 0x94, 0xb7, 0xf7, 0xf8, + 0x3b, 0xa0, 0xe4, 0x36, 0x32, 0x57, 0x1b, 0xfb, 0xa0, 0x6a, 0xdd, 0x10, 0x20, 0x87, 0x1a, 0x1d, 0x99, 0x57, 0x11, + 0xbb, 0x48, 0x1f, 0x92, 0x76, 0x0b, 0x22, 0xa1, 0xed, 0xa0, 0x7c, 0x3f, 0x6d, 0xc0, 0x54, 0x27, 0xb7, 0x4d, 0xa0, + 0xd5, 0xf0, 0x50, 0xd2, 0x5d, 0x93, 0x27, 0x77, 0x58, 0x05, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1c, 0x0a, 0xe4, 0x22, + 0xc8, 0xda, 0x0d, 0xa0, 0xa9, 0xe8, 0xd8, 0x07, 0xfb, 0xbc, 0x71, 0xd4, 0x45, 0x33, 0x39, 0x3d, 0xfc, 0x7a, 0x70, + 0x10, 0xcb, 0x06, 0x79, 0x84, 0xf0, 0x92, 0x82, 0x41, 0x36, 0x38, 0xb0, 0x71, 0xcb, 0xc4, 0xa7, 0x2a, 0xa0, 0x8e, + 0x0b, 0x55, 0x3b, 0xd6, 0xaa, 0xce, 0xca, 0xdd, 0xe0, 0xc7, 0xd4, 0x41, 0x8d, 0x20, 0xcd, 0x8e, 0xae, 0x53, 0x83, + 0x72, 0xcd, 0xdb, 0x0c, 0xb6, 0x65, 0xe3, 0x23, 0x45, 0x3f, 0x3c, 0x6a, 0x7e, 0x0d, 0x26, 0x5c, 0x33, 0x4d, 0x7a, + 0xd4, 0x78, 0x84, 0x7e, 0x78, 0x14, 0xf8, 0x0b, 0xf2, 0x8a, 0x3d, 0xf1, 0xdc, 0xc8, 0x4f, 0x96, 0x2b, 0xfd, 0x09, + 0x24, 0xfb, 0x82, 0xfc, 0x04, 0x58, 0x4e, 0xc9, 0x4f, 0xb1, 0x6c, 0x42, 0x1c, 0x45, 0xf2, 0x53, 0x5c, 0xc0, 0x8f, + 0x9c, 0xfc, 0x14, 0x03, 0xb6, 0xe3, 0xa9, 0xf9, 0x51, 0x94, 0xc0, 0x00, 0x1f, 0x35, 0x69, 0x5d, 0xd5, 0x8a, 0xd5, + 0x4a, 0x1c, 0x1c, 0x48, 0xfb, 0x8b, 0x5e, 0x66, 0x07, 0x07, 0xf9, 0xc5, 0xb4, 0xea, 0x9b, 0xe9, 0x5d, 0xf4, 0xc5, + 0x20, 0x14, 0x0e, 0x4c, 0xd3, 0x78, 0x38, 0xe3, 0x4f, 0x21, 0x65, 0x35, 0x0d, 0x34, 0x8f, 0x3b, 0xf7, 0xcf, 0xce, + 0x31, 0xfc, 0x7b, 0x3f, 0x28, 0xf8, 0x73, 0xc9, 0x77, 0x91, 0x36, 0x6b, 0x9e, 0x55, 0xc8, 0x76, 0x19, 0xe0, 0x33, + 0x66, 0xa8, 0x29, 0x0e, 0x0e, 0xf8, 0x45, 0x80, 0xcb, 0x98, 0xa1, 0x46, 0x60, 0xb1, 0xf7, 0xb0, 0xb4, 0x27, 0x33, + 0x5c, 0x13, 0xbc, 0x90, 0xcb, 0xfb, 0xc5, 0xe0, 0x42, 0x3b, 0x6a, 0x12, 0xc6, 0xd1, 0x56, 0xa4, 0xe5, 0x36, 0x59, + 0x57, 0x34, 0xd5, 0x65, 0xbb, 0x8b, 0x24, 0x51, 0x0d, 0x71, 0x79, 0xd9, 0xc6, 0xa0, 0x92, 0xef, 0x29, 0x22, 0x53, + 0x41, 0xbc, 0xaf, 0xdf, 0x32, 0x97, 0xa9, 0xc2, 0x53, 0x9e, 0x0a, 0x2f, 0x67, 0xbf, 0xf6, 0xd6, 0xd3, 0xc6, 0xfb, + 0xd2, 0xf4, 0xcc, 0xb0, 0xe8, 0xa9, 0xd2, 0x6b, 0x10, 0x36, 0xa9, 0x1a, 0xc0, 0x03, 0x84, 0x25, 0xe6, 0x31, 0xeb, + 0x2a, 0xc7, 0x20, 0xc0, 0xb3, 0x6a, 0xb4, 0x21, 0x13, 0x3e, 0xd7, 0xa9, 0x82, 0x81, 0x9a, 0xc2, 0x17, 0x40, 0xa6, + 0xb2, 0xca, 0x30, 0xdb, 0x37, 0x0c, 0x05, 0x04, 0x14, 0xb8, 0x24, 0x2c, 0x90, 0xe0, 0xe1, 0xf6, 0x23, 0x20, 0x1c, + 0x75, 0x72, 0x61, 0x27, 0x77, 0xa1, 0xa0, 0x3b, 0x31, 0xb8, 0xd0, 0x5d, 0x24, 0x1a, 0x0d, 0xc7, 0x6d, 0x5f, 0x0a, + 0x33, 0x88, 0x66, 0x7b, 0x70, 0xc9, 0xba, 0x48, 0x35, 0x9b, 0xa5, 0x01, 0xe4, 0x65, 0x6b, 0xb5, 0x52, 0x17, 0xbe, + 0x91, 0x9e, 0x3f, 0xc7, 0x0d, 0xdf, 0xe5, 0x05, 0xcf, 0xdf, 0x24, 0xe9, 0x47, 0x40, 0x55, 0x81, 0xcf, 0x96, 0xf3, + 0x08, 0x47, 0xe6, 0x6d, 0x3a, 0xf8, 0x6b, 0xde, 0x14, 0x8b, 0x70, 0xe4, 0x9e, 0xab, 0x8b, 0x06, 0xd5, 0x60, 0x79, + 0x56, 0x46, 0x5a, 0xe7, 0xc9, 0x35, 0x30, 0x0e, 0xfa, 0x6f, 0x85, 0x96, 0xd5, 0xef, 0x24, 0x77, 0x31, 0x47, 0x94, + 0x7f, 0x41, 0xcd, 0x8d, 0x6a, 0xbd, 0xdb, 0xcb, 0x93, 0xe3, 0xc8, 0x57, 0x85, 0x97, 0x08, 0xbe, 0xf3, 0x84, 0x63, + 0xdb, 0xbd, 0x1c, 0xbe, 0x2c, 0x7b, 0x00, 0xce, 0x7b, 0xbd, 0x46, 0xf8, 0x37, 0xb9, 0xf3, 0x19, 0xe1, 0xe8, 0x5a, + 0x8a, 0x27, 0x54, 0xd3, 0xa8, 0xf1, 0xc6, 0x18, 0xbe, 0x59, 0x39, 0xab, 0xfb, 0xad, 0x71, 0xb0, 0x7f, 0xab, 0x7b, + 0x88, 0x02, 0x51, 0x7b, 0xf1, 0xc8, 0xca, 0xbe, 0x26, 0xf6, 0x87, 0x0c, 0x4c, 0xdf, 0x76, 0xc0, 0xc3, 0x8f, 0x91, + 0x82, 0x6f, 0xb2, 0xe5, 0x93, 0x28, 0x84, 0x57, 0xad, 0x79, 0x44, 0x43, 0x8a, 0xed, 0xc3, 0x78, 0xcf, 0xae, 0x51, + 0xc8, 0x75, 0x8f, 0x55, 0x9d, 0x98, 0x56, 0xdd, 0x18, 0xa9, 0x83, 0x6d, 0xb2, 0xe0, 0xac, 0xea, 0xdd, 0x48, 0x28, + 0xd5, 0xe3, 0x70, 0xe6, 0x81, 0xcf, 0x66, 0xdb, 0xbc, 0x98, 0x6c, 0x9f, 0x90, 0x53, 0x60, 0xc8, 0xbb, 0x5f, 0x46, + 0xbe, 0xba, 0x84, 0x63, 0x37, 0x0e, 0x20, 0x2b, 0xc9, 0xe5, 0xd2, 0x3d, 0xef, 0xc6, 0xfb, 0x72, 0xb0, 0x2e, 0x1f, + 0x7b, 0x0b, 0xf0, 0xa0, 0x1a, 0xa9, 0xc8, 0x42, 0xce, 0xc0, 0xbf, 0x94, 0x58, 0xd3, 0x0f, 0xf1, 0xaf, 0x70, 0xc0, + 0x57, 0x48, 0x9a, 0x5a, 0xf5, 0x13, 0x3c, 0xc2, 0x04, 0x0a, 0x6f, 0x5b, 0xf7, 0x93, 0x0c, 0xbd, 0x5d, 0xeb, 0x3a, + 0x15, 0xeb, 0x50, 0x5a, 0x57, 0xac, 0x94, 0x85, 0x83, 0xe3, 0x2e, 0x46, 0xeb, 0xd4, 0x39, 0x9f, 0xba, 0x97, 0x9b, + 0x1e, 0x0a, 0x70, 0x7c, 0xe1, 0x52, 0x3c, 0x2b, 0x20, 0x14, 0x57, 0xa8, 0x4f, 0xfb, 0x59, 0x86, 0x4f, 0x13, 0xf7, + 0xe1, 0x9e, 0xb0, 0xe4, 0x39, 0xcb, 0xe7, 0xb4, 0x61, 0x81, 0x14, 0x50, 0x28, 0x85, 0xc5, 0x6a, 0x15, 0x0b, 0x13, + 0xa0, 0xc1, 0xc5, 0xe7, 0x75, 0x0f, 0x71, 0x18, 0xfd, 0x1d, 0xd4, 0xc5, 0x5e, 0x3d, 0x62, 0x4c, 0x58, 0x51, 0x78, + 0xe9, 0xa4, 0xb2, 0xa0, 0xaf, 0x5d, 0x7d, 0x88, 0x6a, 0xca, 0xbd, 0xd8, 0xe8, 0x7b, 0xdf, 0xf1, 0x19, 0x93, 0x0b, + 0x78, 0x01, 0x09, 0x33, 0xa2, 0x98, 0xf6, 0xdf, 0x40, 0x41, 0xe0, 0x19, 0x1d, 0x1e, 0xe2, 0x23, 0xf0, 0x55, 0x9e, + 0xd6, 0xc9, 0xcc, 0xbf, 0xab, 0x11, 0x99, 0xb8, 0x97, 0x51, 0x2f, 0x02, 0x17, 0x21, 0x10, 0xa1, 0x08, 0x89, 0x98, + 0x18, 0x45, 0xbd, 0xc8, 0xf8, 0x5b, 0x45, 0x60, 0x35, 0x06, 0x4a, 0xee, 0x08, 0xcf, 0x55, 0x45, 0xc4, 0xc2, 0x9a, + 0x3a, 0xa8, 0xc4, 0x52, 0x63, 0xa6, 0x7d, 0xd4, 0xa9, 0x40, 0x58, 0x64, 0x9b, 0x82, 0xb2, 0xde, 0x50, 0x17, 0x60, + 0x49, 0x8c, 0xe9, 0x2d, 0x4f, 0xae, 0x81, 0x9b, 0x63, 0x23, 0x57, 0x74, 0xc9, 0xaf, 0x40, 0x3d, 0x9d, 0x16, 0xf8, + 0xda, 0x30, 0x6c, 0xa3, 0x94, 0xae, 0x09, 0xc7, 0x19, 0x29, 0x12, 0x7a, 0x0b, 0x01, 0x2a, 0x66, 0x5c, 0xa4, 0x39, + 0x9e, 0xd1, 0xdb, 0x74, 0x8a, 0x67, 0x5c, 0x3c, 0xb1, 0xcb, 0x9e, 0x8e, 0x20, 0xc9, 0x7f, 0x2c, 0xd6, 0xc4, 0xbc, + 0xaf, 0xf5, 0xbb, 0x62, 0xc5, 0x23, 0xe0, 0x55, 0x54, 0x8c, 0xba, 0x23, 0x63, 0x53, 0xce, 0x74, 0x65, 0xbc, 0xfe, + 0x5a, 0xc7, 0x14, 0x67, 0x38, 0x47, 0x49, 0x2e, 0x31, 0xeb, 0x89, 0xf4, 0x35, 0x04, 0xa7, 0xce, 0xb0, 0x7d, 0x9b, + 0x8b, 0xdf, 0xb2, 0xfc, 0x99, 0x2c, 0xde, 0x9b, 0x2d, 0x9f, 0x23, 0x28, 0x04, 0x2e, 0x2a, 0xa2, 0x09, 0xb7, 0x7b, + 0x8b, 0x9e, 0xac, 0x9a, 0xa2, 0xb7, 0xb6, 0x29, 0x37, 0xc4, 0x29, 0x44, 0xf5, 0x4d, 0xa6, 0xbc, 0xd1, 0xc6, 0xac, + 0xd7, 0xfa, 0x4e, 0xa3, 0x53, 0x54, 0x96, 0x44, 0x18, 0xd6, 0xaa, 0xa9, 0x52, 0x49, 0x44, 0x53, 0x39, 0x09, 0x6f, + 0x69, 0x80, 0x9d, 0x2a, 0x9c, 0xc9, 0x85, 0xd0, 0xa9, 0x0c, 0xf0, 0x86, 0x56, 0x9b, 0x6b, 0x79, 0x6b, 0x21, 0xa6, + 0xf1, 0x9d, 0xfd, 0xc1, 0xf0, 0xb5, 0x51, 0xf1, 0xbf, 0x05, 0xc3, 0x1e, 0x95, 0x0a, 0x80, 0x1f, 0x18, 0xce, 0x02, + 0xe4, 0x2c, 0x3f, 0x79, 0x0b, 0xe0, 0xb3, 0x2c, 0xe4, 0x1d, 0xa4, 0x32, 0x93, 0x7a, 0x07, 0xa9, 0x0c, 0x52, 0x8d, + 0x5b, 0xfa, 0xbe, 0xa8, 0x94, 0x45, 0x61, 0x83, 0x44, 0xe1, 0x52, 0x1d, 0x2c, 0x89, 0x48, 0xa0, 0x5d, 0x23, 0xca, + 0xcd, 0xb8, 0x80, 0xf8, 0x84, 0xd0, 0xb8, 0xfd, 0xa6, 0xb7, 0xf0, 0x7d, 0x67, 0xf3, 0x99, 0xcf, 0xbf, 0xb3, 0xf9, + 0xa6, 0x23, 0x8f, 0xf1, 0xf5, 0xdb, 0x4e, 0x63, 0x19, 0x2f, 0x1d, 0xd6, 0x7e, 0x28, 0x5f, 0x83, 0x69, 0x99, 0x57, + 0xb7, 0x49, 0x1b, 0x4f, 0x02, 0xa4, 0x6c, 0x56, 0x3c, 0x5c, 0x07, 0xb7, 0x5b, 0x87, 0x31, 0x6f, 0x92, 0x36, 0x42, + 0x87, 0x4e, 0xb8, 0x12, 0xb1, 0x91, 0x9c, 0x0e, 0x1f, 0x1d, 0xc1, 0xdd, 0xcb, 0x4c, 0x6d, 0xf8, 0x4a, 0xd9, 0x6a, + 0xcd, 0x76, 0xeb, 0x90, 0xef, 0xac, 0xd2, 0x68, 0xe3, 0x19, 0x23, 0x4b, 0x70, 0x2e, 0xa3, 0x85, 0x55, 0x35, 0x80, + 0x3f, 0xea, 0x0b, 0xf1, 0xdb, 0x82, 0x8e, 0xcc, 0xf7, 0xa1, 0x4d, 0x79, 0xbd, 0xd0, 0x3e, 0xa9, 0xc9, 0x61, 0x10, + 0x1d, 0xe4, 0x4a, 0x06, 0x39, 0x31, 0x3f, 0x22, 0xc9, 0x29, 0xba, 0x68, 0xf7, 0x92, 0xd3, 0x43, 0x7e, 0xc8, 0x53, + 0xe0, 0x61, 0xe3, 0xa6, 0xaf, 0xd0, 0x6c, 0xfb, 0x3a, 0x8f, 0x17, 0x43, 0x9e, 0xb9, 0xe6, 0xab, 0x0e, 0xca, 0x54, + 0x3b, 0x47, 0xc8, 0x02, 0x14, 0xf3, 0xbd, 0x04, 0xd9, 0xf5, 0x6e, 0x0e, 0x79, 0x0a, 0xfd, 0x40, 0xad, 0x8e, 0xad, + 0x55, 0x0e, 0xee, 0xb7, 0x05, 0x20, 0x98, 0xef, 0xa8, 0x36, 0x17, 0x9b, 0xde, 0x8c, 0xab, 0xce, 0x0e, 0x79, 0x35, + 0xc2, 0xb0, 0xcc, 0x76, 0x7f, 0x7e, 0x6a, 0x55, 0x97, 0x87, 0x01, 0x44, 0x7e, 0x5b, 0x70, 0x11, 0x76, 0x1a, 0x76, + 0xeb, 0x72, 0xc2, 0x4e, 0xeb, 0xb3, 0x0c, 0x8a, 0x6c, 0xf7, 0xba, 0x35, 0xd3, 0xfa, 0x6c, 0xaf, 0xc0, 0x47, 0x10, + 0x26, 0x65, 0x56, 0x3a, 0x83, 0x2b, 0xf4, 0xc3, 0x0f, 0xc8, 0xb5, 0xfe, 0x7a, 0xa1, 0x7d, 0x7e, 0x89, 0x08, 0x90, + 0x5d, 0x75, 0x5d, 0x56, 0x87, 0x3e, 0xca, 0x26, 0xbe, 0x1e, 0xf2, 0x60, 0xe5, 0x9e, 0xde, 0xce, 0x65, 0xea, 0xf1, + 0xb5, 0xd7, 0x4a, 0xb7, 0x90, 0x13, 0x88, 0x87, 0xeb, 0x2e, 0x2c, 0x0b, 0x72, 0x76, 0x73, 0x0b, 0x25, 0xc3, 0x89, + 0xfb, 0xd2, 0x1f, 0x98, 0xbd, 0x6e, 0xe0, 0x17, 0xc9, 0x29, 0x4c, 0x7d, 0xb3, 0x87, 0xc3, 0x0e, 0xf4, 0x61, 0xe0, + 0xb0, 0xd9, 0xa0, 0xcf, 0xac, 0x20, 0xf2, 0x98, 0x17, 0x16, 0xcf, 0x2e, 0x49, 0xbb, 0xc7, 0x53, 0xb7, 0x99, 0x8c, + 0x68, 0xd4, 0x6e, 0xf2, 0x60, 0x66, 0x80, 0x5f, 0xae, 0x6c, 0x58, 0xc4, 0xaf, 0x53, 0x00, 0x25, 0x5f, 0xac, 0x5a, + 0x9f, 0x0a, 0x5e, 0xf5, 0x86, 0xd3, 0xcd, 0x74, 0xbf, 0x6e, 0x70, 0xbb, 0xeb, 0xe1, 0x09, 0xaf, 0xb9, 0x58, 0xb4, + 0xf6, 0x13, 0x9f, 0x00, 0x07, 0x94, 0xb4, 0xee, 0x9f, 0x82, 0x0b, 0x65, 0x09, 0xcb, 0xed, 0x72, 0xb3, 0xad, 0x72, + 0x16, 0x8e, 0xb6, 0x64, 0xc0, 0x1d, 0x6c, 0x42, 0x14, 0x3a, 0x38, 0xec, 0xe0, 0xa4, 0xdd, 0xee, 0x9c, 0xe2, 0xe4, + 0xe4, 0x14, 0x06, 0xda, 0x48, 0x4e, 0x0f, 0x67, 0xca, 0x02, 0x30, 0xc8, 0x59, 0xbb, 0x76, 0x1f, 0x41, 0xe4, 0xa7, + 0x50, 0xbc, 0xe6, 0x87, 0x71, 0xdc, 0x4e, 0xee, 0xb7, 0xda, 0xa7, 0xe7, 0x0d, 0x00, 0x50, 0xd3, 0x7d, 0xb8, 0x1a, + 0xaf, 0x17, 0xba, 0x5e, 0xa5, 0x44, 0xf8, 0x7a, 0xb5, 0x86, 0xaf, 0xd6, 0x68, 0xaf, 0xab, 0x29, 0xf8, 0xaa, 0x4e, + 0x38, 0xb7, 0x45, 0xbc, 0xd2, 0x26, 0xdc, 0x16, 0xb1, 0x1d, 0x48, 0x0c, 0xd2, 0x79, 0x72, 0xda, 0x39, 0x45, 0x76, + 0x2c, 0xda, 0xe1, 0x47, 0xb9, 0x4f, 0xb6, 0x8a, 0x34, 0x34, 0x20, 0x49, 0x39, 0x3b, 0xb9, 0x00, 0x89, 0x9a, 0x93, + 0xcb, 0x76, 0x73, 0xc6, 0x12, 0x3f, 0x01, 0x93, 0x0a, 0xcb, 0x59, 0xae, 0x82, 0x4b, 0x0a, 0x00, 0x71, 0x01, 0xc6, + 0x45, 0xf7, 0x4f, 0x7b, 0xf7, 0x93, 0xd3, 0xb3, 0x8e, 0x25, 0x7a, 0xfc, 0xa2, 0x53, 0x4b, 0x33, 0x53, 0x4f, 0x4e, + 0x4d, 0x1a, 0x74, 0x9d, 0xdc, 0x3f, 0x85, 0x32, 0x2e, 0x25, 0x2c, 0x05, 0x11, 0x2b, 0xaa, 0x62, 0x10, 0xa6, 0x22, + 0xad, 0xe5, 0x9e, 0xd5, 0xb2, 0xcf, 0x4f, 0x8e, 0xef, 0x9f, 0x86, 0x50, 0x2b, 0x67, 0x61, 0x16, 0xda, 0x4d, 0xc4, + 0xcf, 0x0e, 0x96, 0x16, 0x1d, 0x26, 0xa7, 0xe9, 0xd6, 0x04, 0xed, 0xa6, 0x39, 0x34, 0x38, 0x10, 0x28, 0x1c, 0x9f, + 0x0a, 0xa7, 0x2f, 0x09, 0xee, 0xc7, 0x2a, 0x43, 0x93, 0x50, 0xe1, 0xec, 0xef, 0x29, 0x83, 0x47, 0x29, 0xc3, 0xab, + 0xca, 0xc7, 0x54, 0x7c, 0xa1, 0xea, 0x0d, 0x85, 0x30, 0x1c, 0x62, 0x10, 0xb9, 0x20, 0xe1, 0xf5, 0xdc, 0x9f, 0xc0, + 0x45, 0x98, 0x09, 0xb8, 0xd0, 0xf4, 0x4a, 0xd0, 0x8a, 0x17, 0x18, 0x86, 0x0e, 0xb5, 0x66, 0x58, 0x3d, 0x9e, 0x3a, + 0x93, 0x82, 0x50, 0xb7, 0xf5, 0x9c, 0x7f, 0xaf, 0x5c, 0x52, 0x5e, 0x65, 0x27, 0xa7, 0x28, 0x71, 0x97, 0xe5, 0x49, + 0x1b, 0x25, 0x81, 0x09, 0x89, 0x3b, 0x92, 0xb3, 0x8c, 0xf4, 0xa3, 0xdb, 0x08, 0x47, 0x77, 0x11, 0x8e, 0xac, 0x0f, + 0xf3, 0x07, 0x70, 0x10, 0x8f, 0x70, 0x64, 0x5d, 0x99, 0x23, 0x1c, 0x69, 0x26, 0x20, 0x3a, 0x57, 0x34, 0xc0, 0x39, + 0x94, 0x36, 0x9e, 0xd5, 0x65, 0xe9, 0xc7, 0xfe, 0xab, 0x74, 0xbd, 0xb6, 0x29, 0x81, 0x94, 0x39, 0x35, 0x3b, 0xd4, + 0xbe, 0x2e, 0x1d, 0x51, 0xcf, 0xac, 0x47, 0x18, 0x04, 0x10, 0x7a, 0xe7, 0x5f, 0xa7, 0xab, 0x02, 0x7b, 0xb0, 0x63, + 0x58, 0x69, 0xf0, 0x33, 0x8f, 0xc2, 0x33, 0x2c, 0xc2, 0x63, 0xe1, 0x0b, 0x83, 0x58, 0xe1, 0x7f, 0xe7, 0x52, 0xce, + 0xfd, 0x6f, 0x2d, 0xcb, 0x5f, 0xf0, 0xa6, 0x89, 0xb3, 0x68, 0x01, 0xcb, 0x2d, 0x1b, 0x47, 0x68, 0xc8, 0xea, 0x23, + 0xb8, 0x1e, 0xbb, 0x58, 0x6f, 0x20, 0x11, 0x5e, 0x1b, 0x81, 0xca, 0xcb, 0x87, 0xd7, 0x36, 0xee, 0x90, 0xf9, 0x84, + 0xc0, 0x63, 0x10, 0x5b, 0x58, 0xc2, 0x85, 0xc6, 0xa4, 0x60, 0x4a, 0x45, 0x36, 0x20, 0x5f, 0x24, 0x85, 0x7f, 0x61, + 0xd1, 0xa7, 0x8c, 0x45, 0x64, 0x3a, 0xac, 0xcf, 0xd6, 0x8a, 0xc3, 0xb9, 0x2c, 0x54, 0x6a, 0x9f, 0x5b, 0xf1, 0x60, + 0x9c, 0x97, 0x6f, 0x19, 0xa6, 0x79, 0xb6, 0xc6, 0xf6, 0x0e, 0xbb, 0x2c, 0xe4, 0xae, 0xb4, 0xc3, 0x52, 0x59, 0xb6, + 0xfe, 0xd6, 0x84, 0x54, 0x6d, 0x46, 0xc1, 0x44, 0xab, 0x01, 0x55, 0x51, 0x39, 0xa0, 0xb0, 0x8d, 0xec, 0x92, 0x2e, + 0xcb, 0x92, 0xe9, 0xb2, 0x5c, 0x86, 0x93, 0x56, 0x6b, 0xbd, 0xc6, 0x05, 0x33, 0x11, 0x66, 0x76, 0x96, 0x80, 0x7c, + 0x35, 0x95, 0x37, 0x41, 0xae, 0x4a, 0xcb, 0x59, 0x9a, 0x25, 0x8a, 0x02, 0x23, 0xd8, 0x68, 0x8d, 0xbf, 0x70, 0xc5, + 0x01, 0x9e, 0x6e, 0x76, 0x43, 0x29, 0x73, 0x46, 0x21, 0x10, 0x59, 0xd0, 0xe4, 0x1a, 0x4f, 0xf9, 0x88, 0xed, 0x6e, + 0x13, 0xcc, 0x98, 0xff, 0xbd, 0x16, 0x3d, 0x02, 0x59, 0x76, 0xcf, 0xa0, 0x0e, 0x2c, 0xe2, 0x0a, 0x3a, 0x08, 0x65, + 0xf0, 0x51, 0x88, 0x9b, 0x39, 0xbd, 0x93, 0x0b, 0x0d, 0x70, 0x59, 0x68, 0xf9, 0xc6, 0xc5, 0x3a, 0xd8, 0x6f, 0x61, + 0x1f, 0xf6, 0x60, 0x09, 0x21, 0x03, 0x5a, 0xd8, 0x86, 0xbb, 0x68, 0xe1, 0xa1, 0xd4, 0x5a, 0xce, 0xd2, 0x16, 0x36, + 0xb1, 0x27, 0x5a, 0xeb, 0x32, 0x40, 0xd8, 0x75, 0xf9, 0x2e, 0x65, 0xb5, 0x09, 0x16, 0x4e, 0x3a, 0xd4, 0x44, 0x07, + 0xb7, 0x87, 0x8c, 0xf0, 0xc6, 0xcf, 0x57, 0xaf, 0x5f, 0xb9, 0xf0, 0xcf, 0x7c, 0x0c, 0x2e, 0x9b, 0x4e, 0x35, 0x76, + 0x6d, 0x1e, 0x74, 0x8a, 0x2b, 0x45, 0xa9, 0x15, 0x4e, 0xa1, 0xe5, 0x17, 0x42, 0xe7, 0x89, 0xbd, 0xbc, 0x78, 0x26, + 0x8b, 0x19, 0xb5, 0x37, 0x46, 0xf8, 0x5a, 0xb9, 0x17, 0xdc, 0xcd, 0x23, 0x31, 0xd5, 0x24, 0xdf, 0x6d, 0x5e, 0x45, + 0x2c, 0x32, 0x23, 0xbf, 0x82, 0x36, 0xc0, 0x54, 0x2e, 0x1f, 0xe0, 0x2d, 0x88, 0x0b, 0xa2, 0x1f, 0x90, 0x97, 0xb7, + 0x96, 0xba, 0x44, 0x51, 0x83, 0x1b, 0xfc, 0x64, 0x05, 0xcf, 0x82, 0xeb, 0x42, 0xc3, 0x1e, 0x39, 0xf1, 0x22, 0x6a, + 0x45, 0xf5, 0x07, 0x6c, 0x8d, 0x2a, 0xc1, 0x07, 0x60, 0x4d, 0x72, 0x09, 0xa2, 0x47, 0xf9, 0x56, 0x1e, 0x07, 0xd1, + 0xc4, 0xdf, 0x3d, 0x5f, 0xb6, 0x3d, 0x9d, 0xcd, 0x2b, 0x75, 0x62, 0x79, 0x65, 0x02, 0x1e, 0x8e, 0xf6, 0x35, 0x1a, + 0x84, 0x83, 0x44, 0x56, 0x6a, 0x0f, 0x7d, 0x2e, 0xea, 0xc6, 0xf9, 0x45, 0x9b, 0x35, 0x4f, 0x56, 0xab, 0xfc, 0xb2, + 0xcd, 0xda, 0xa7, 0xf6, 0xed, 0xba, 0x48, 0x65, 0x40, 0x73, 0xf9, 0x98, 0x67, 0x11, 0x68, 0x67, 0xc7, 0x99, 0x09, + 0xa7, 0xe0, 0xa3, 0x2d, 0x93, 0x85, 0xae, 0xfa, 0x92, 0x60, 0x5c, 0x4a, 0xac, 0x1e, 0xbf, 0x40, 0xbd, 0x76, 0xba, + 0xed, 0x2a, 0xdd, 0x6c, 0x1f, 0x06, 0x17, 0x2e, 0x05, 0xc2, 0x1d, 0x08, 0x79, 0x00, 0xfa, 0xdd, 0xa5, 0x00, 0xd3, + 0x20, 0x40, 0x65, 0x05, 0x22, 0x2d, 0x9f, 0x2d, 0x66, 0xcf, 0x0a, 0x6a, 0x96, 0xe1, 0x09, 0x9f, 0x70, 0xad, 0x52, + 0x0a, 0xd2, 0xed, 0xae, 0xf4, 0xf5, 0x6e, 0x09, 0x2a, 0xab, 0x05, 0xb1, 0x4d, 0x34, 0xcf, 0x3e, 0x2b, 0xb7, 0x70, + 0x08, 0x9b, 0x95, 0x15, 0x38, 0x43, 0x6b, 0x9c, 0xcb, 0x09, 0x2d, 0xb8, 0x9e, 0xce, 0xfe, 0xad, 0xd5, 0x61, 0x7d, + 0x3d, 0x30, 0x17, 0x56, 0x00, 0x12, 0x2a, 0x46, 0xab, 0x15, 0x3f, 0xfa, 0xfe, 0x7d, 0x92, 0xf7, 0x09, 0x6f, 0xe3, + 0x0e, 0x3e, 0xc6, 0xa7, 0xb8, 0xdd, 0xc2, 0xed, 0x53, 0xb8, 0xba, 0xcf, 0xf2, 0xc5, 0x88, 0xa9, 0x18, 0x1e, 0x31, + 0xd3, 0x97, 0xc9, 0xf9, 0x61, 0x19, 0xba, 0x5f, 0x17, 0x89, 0x43, 0x97, 0x20, 0x82, 0xbc, 0x0b, 0xbd, 0x17, 0x45, + 0x61, 0xdc, 0xb7, 0x71, 0xa8, 0x3a, 0x29, 0xf5, 0x0b, 0x97, 0xc7, 0x3d, 0xb0, 0xe7, 0xb6, 0x2b, 0xdb, 0x04, 0xb3, + 0x6f, 0xfb, 0x33, 0xad, 0x7e, 0x36, 0x75, 0x89, 0x18, 0x1e, 0x7a, 0x15, 0x7a, 0xa0, 0x4b, 0xd2, 0x3e, 0x38, 0x00, + 0xab, 0xa3, 0x60, 0x36, 0xdc, 0x46, 0x3f, 0xe0, 0xcd, 0x5a, 0x1a, 0x04, 0x2b, 0x00, 0xe3, 0xce, 0x37, 0x9c, 0x2c, + 0x2d, 0x6c, 0x35, 0x50, 0x61, 0x5d, 0x84, 0xc1, 0xe9, 0x42, 0x52, 0x61, 0x84, 0x68, 0x38, 0xc2, 0x5c, 0xa4, 0x93, + 0xfd, 0x16, 0x96, 0xe3, 0xb1, 0x62, 0x1a, 0x8e, 0x8e, 0x82, 0x7d, 0x61, 0x85, 0x32, 0xa7, 0xc8, 0x90, 0x4d, 0xb8, + 0x78, 0xa8, 0x3f, 0xb1, 0x42, 0x9a, 0x4f, 0xa3, 0xc1, 0x48, 0x23, 0xb3, 0x8a, 0x11, 0xce, 0x72, 0x3e, 0x87, 0xaa, + 0x93, 0x02, 0x9c, 0x7e, 0xe0, 0x2f, 0x1f, 0xa5, 0x61, 0x9b, 0x40, 0xbe, 0x3e, 0xd8, 0x80, 0x2d, 0x78, 0x54, 0xd0, + 0x9b, 0xd7, 0xe2, 0x31, 0xec, 0xa8, 0x87, 0x05, 0xa3, 0x90, 0x0d, 0x49, 0xef, 0xa0, 0x29, 0xf8, 0x80, 0x36, 0x5f, + 0x1a, 0xc0, 0xa5, 0xe7, 0xe6, 0xc3, 0x56, 0xf4, 0x01, 0x10, 0x93, 0xb2, 0x2d, 0x93, 0x69, 0x4e, 0xe9, 0x2a, 0xd3, + 0x86, 0x98, 0x2a, 0xa7, 0xb0, 0xc6, 0x2e, 0xea, 0x49, 0x38, 0x98, 0x11, 0x55, 0xd3, 0xb4, 0x3f, 0x30, 0x7f, 0x5f, + 0xdb, 0x92, 0x2d, 0xec, 0xc2, 0xc9, 0xac, 0xb1, 0x79, 0x7d, 0x34, 0x28, 0xdf, 0xc6, 0x70, 0x0f, 0x0b, 0x4f, 0x60, + 0xd6, 0xc8, 0xe7, 0x89, 0x27, 0x9b, 0x27, 0xeb, 0xb5, 0x19, 0x88, 0x4a, 0x41, 0x0f, 0xf4, 0xd6, 0x6f, 0x9b, 0x16, + 0x6c, 0x8f, 0xf2, 0xeb, 0xb4, 0x85, 0x67, 0x1c, 0x5e, 0xf4, 0xf4, 0xed, 0x5d, 0xe9, 0x42, 0x7e, 0x76, 0x20, 0x69, + 0x05, 0x29, 0x76, 0x3a, 0x41, 0x67, 0xc7, 0x38, 0x18, 0x39, 0xd0, 0xf3, 0xab, 0xcf, 0x16, 0xd6, 0xfe, 0xf7, 0x9b, + 0xb2, 0xa0, 0x09, 0x96, 0x53, 0x4e, 0x28, 0xf3, 0xe7, 0xe7, 0x1b, 0x9e, 0x54, 0xa8, 0xe0, 0x9e, 0xc2, 0x82, 0x3d, + 0x6d, 0xa3, 0x65, 0xce, 0xe8, 0xdf, 0xf6, 0x87, 0x0d, 0xd0, 0x53, 0x6a, 0xd9, 0xb2, 0x42, 0x2a, 0xf5, 0xd0, 0xa6, + 0xd9, 0xa3, 0x07, 0x8e, 0xc8, 0x97, 0xd0, 0x05, 0xf0, 0xfa, 0xa3, 0x42, 0xce, 0x0d, 0x22, 0xb8, 0xdf, 0x6e, 0xdc, + 0xc6, 0x57, 0x00, 0xbc, 0x1d, 0xf6, 0xaa, 0x7f, 0x5a, 0xc0, 0xfe, 0x46, 0x65, 0x49, 0x3f, 0xde, 0x8e, 0x3d, 0xfe, + 0x0b, 0x09, 0xa1, 0xd7, 0x2d, 0x1e, 0x26, 0x0e, 0x9d, 0x4a, 0xd6, 0xac, 0xfc, 0xb9, 0x55, 0x12, 0x30, 0xac, 0x5e, + 0x30, 0x64, 0xe3, 0xb6, 0x8a, 0xdb, 0xcc, 0xff, 0xa0, 0x82, 0xc1, 0x82, 0x6f, 0x8d, 0xa4, 0x62, 0x59, 0xfc, 0xf6, + 0xa9, 0xf3, 0x5f, 0x75, 0x8e, 0x6b, 0x5f, 0xd7, 0x9e, 0xdb, 0x1c, 0x9a, 0x50, 0xc7, 0x11, 0x3a, 0x38, 0xd8, 0xc8, + 0xa0, 0x63, 0x00, 0x3c, 0x72, 0xec, 0x97, 0x5f, 0x3e, 0xcf, 0x8e, 0x19, 0xcd, 0x63, 0x11, 0x85, 0xcc, 0x9d, 0xe7, + 0xe6, 0xec, 0x44, 0x9e, 0x50, 0x35, 0xf5, 0x85, 0x01, 0x8e, 0x8f, 0xb6, 0x52, 0x01, 0xdf, 0xa3, 0xf5, 0x8e, 0x09, + 0x6c, 0xf0, 0x5b, 0x76, 0x52, 0xbb, 0x0a, 0xfa, 0x05, 0x5a, 0xee, 0x62, 0x2a, 0x37, 0x16, 0x38, 0xda, 0x9c, 0xc8, + 0xce, 0xa1, 0x6f, 0xd4, 0x29, 0x59, 0x8f, 0x27, 0xbb, 0x8d, 0xbe, 0xa4, 0xd8, 0x95, 0x5c, 0xd1, 0xb6, 0x21, 0xab, + 0x9e, 0xdc, 0xd5, 0x95, 0xa9, 0x53, 0x75, 0xcd, 0x5b, 0x59, 0xda, 0x94, 0x76, 0x49, 0xf6, 0x6e, 0x8b, 0x85, 0x57, + 0xe1, 0x8d, 0x46, 0x79, 0x11, 0x0a, 0xf6, 0x58, 0x62, 0xd0, 0xe5, 0x04, 0xae, 0x17, 0x56, 0xab, 0x18, 0xfe, 0xec, + 0x1a, 0xc3, 0x2e, 0xd3, 0xa5, 0x0f, 0x7c, 0x83, 0x5f, 0x09, 0xa2, 0xfe, 0x3a, 0x3b, 0x48, 0xb0, 0xee, 0x72, 0x83, + 0x86, 0xe3, 0xc4, 0x7f, 0xc1, 0x9b, 0xd3, 0xda, 0xbb, 0x1c, 0x4c, 0xb2, 0x6f, 0xbc, 0x53, 0x57, 0xb2, 0x96, 0xb5, + 0x90, 0xf1, 0x1b, 0x12, 0x0c, 0xb1, 0x9b, 0xd2, 0x39, 0x6e, 0x25, 0x6d, 0x14, 0xb9, 0x62, 0x15, 0xfa, 0x7f, 0xab, + 0x48, 0x66, 0x33, 0xff, 0xeb, 0xec, 0xec, 0xcc, 0xa5, 0x38, 0x9b, 0x3f, 0x65, 0x3c, 0xe0, 0x4c, 0x02, 0xfb, 0xc2, + 0x33, 0x66, 0x74, 0xc8, 0x6f, 0x61, 0x28, 0x44, 0x90, 0x4b, 0xe1, 0xd8, 0x25, 0x78, 0x32, 0x11, 0x28, 0x0f, 0xb0, + 0x7f, 0x4f, 0x36, 0xca, 0xf9, 0x37, 0x97, 0x7c, 0x4c, 0xe2, 0xb2, 0x41, 0xf6, 0xc5, 0x7c, 0xf6, 0xad, 0x99, 0x0c, + 0x3c, 0x33, 0x10, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, + 0x0f, 0x53, 0xd6, 0xbd, 0xd7, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0x85, 0xd6, 0x8c, 0x7e, 0x2c, 0xa3, 0x68, 0xee, 0xbd, + 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, 0x69, 0xfe, 0x23, 0xde, 0xab, 0xa2, 0x69, 0x82, + 0x2b, 0xa4, 0x09, 0x48, 0x89, 0xcd, 0xdb, 0xd4, 0x69, 0x24, 0x80, 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0x00, + 0x8c, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0xac, 0xaa, 0x8d, 0x46, 0x0e, 0x41, 0xe9, 0xca, 0xd9, 0x98, 0xaf, 0x47, + 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, + 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, + 0x5e, 0xdc, 0x60, 0xaa, 0x7f, 0x4d, 0x1e, 0x08, 0x3d, 0x53, 0x3a, 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, + 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, + 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, 0xcc, 0xbb, 0xd8, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, + 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, + 0x9e, 0xa5, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, + 0xcc, 0xc5, 0xc3, 0xf0, 0xfd, 0x7a, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0xfd, 0xdd, 0xd9, + 0x0d, 0xa3, 0xb5, 0x79, 0x39, 0x2a, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, 0x9a, 0xda, 0xda, 0xbc, 0x3d, 0x55, 0x66, 0x0d, + 0x59, 0xf9, 0xd0, 0x42, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, + 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x82, + 0xf0, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, + 0x53, 0x70, 0xed, 0xa3, 0xfd, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, 0x44, 0x60, 0x1b, 0x93, 0xd8, 0x9b, 0x73, 0x9a, + 0x10, 0xba, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, + 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, + 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x63, 0x6a, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, + 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, + 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, + 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, + 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, + 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0x72, 0x1b, 0x35, 0x62, 0x9e, 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, + 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, + 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, 0xaa, 0x16, 0x85, 0x79, 0x85, 0x2e, 0x56, 0x28, + 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0xe8, 0x9b, 0x04, 0xc3, 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, + 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, 0x9d, 0x3b, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, + 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, + 0xec, 0x5e, 0xe1, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0x87, 0xc2, + 0xb8, 0x4b, 0x72, 0x6f, 0x7d, 0x54, 0xcf, 0x79, 0xd7, 0x2c, 0xc0, 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, + 0x69, 0x5e, 0x85, 0xa2, 0xe6, 0x31, 0x28, 0x78, 0x83, 0x9a, 0xb0, 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x33, 0x7c, 0xff, + 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, + 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x17, 0x43, + 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x6f, 0x83, 0x54, 0x6f, 0xb3, 0xfb, 0x97, 0xaa, 0x8e, 0x3a, + 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, + 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x5e, 0x13, 0xa9, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, + 0xe6, 0xfe, 0x91, 0xd2, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, + 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, + 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, + 0x1e, 0x10, 0x02, 0x2b, 0x01, 0x1f, 0xc8, 0xd9, 0x24, 0x19, 0x43, 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, + 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, + 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, 0x20, 0x7e, 0x29, 0x74, 0x62, 0x82, 0x5e, 0x5f, + 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, + 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0xbb, 0xce, 0xe3, 0x52, 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, + 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x21, 0xc7, 0x5f, 0x40, 0x00, 0x6a, 0x77, 0x2c, 0x81, 0x9e, 0x7d, + 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0x9e, 0x86, + 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, + 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, + 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, + 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, + 0x6c, 0x54, 0x5e, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, + 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, 0x6d, 0xcb, 0x21, 0xae, 0x77, 0xa4, 0x0b, 0x6e, + 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, + 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, + 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xfc, 0xe8, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, + 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, + 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, + 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, + 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, + 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, + 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, + 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, + 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, + 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, + 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, + 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, + 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, + 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, + 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0x9f, 0x19, 0x85, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, + 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, + 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, + 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, + 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, + 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, + 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, + 0x74, 0x3f, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, + 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, + 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, + 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, + 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, + 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, + 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, + 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0x4f, 0x84, 0x01, 0x97, 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, + 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, + 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x63, 0xb9, 0x9f, 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, + 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, + 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, + 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, + 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, + 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, + 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, + 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, + 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, + 0x9a, 0xce, 0xbc, 0xef, 0x5c, 0x7b, 0xba, 0x78, 0x53, 0xb4, 0xf5, 0x0f, 0x29, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, + 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, + 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, + 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, + 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, + 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, + 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, + 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, + 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, + 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, + 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, + 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, + 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, + 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0xbd, 0xaa, 0xb7, 0x72, 0x4f, 0x0e, 0xad, 0xcc, 0x43, 0x51, 0xab, 0x58, 0x0e, 0x73, + 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, + 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, + 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, + 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, + 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, + 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, + 0x54, 0x18, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, + 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, + 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, + 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, + 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, + 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, + 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, + 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, + 0xbd, 0xbb, 0xe1, 0x13, 0x77, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, + 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0xbc, 0x7a, 0x19, 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, + 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, + 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, + 0x67, 0xf7, 0xc4, 0x62, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, + 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, + 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, + 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, + 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, + 0x55, 0x31, 0xdd, 0x0f, 0x9f, 0x06, 0x0c, 0x3e, 0xbc, 0x43, 0xda, 0xc6, 0xfb, 0x9c, 0x94, 0x50, 0xbb, 0x83, 0xf6, + 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, + 0xca, 0x28, 0x18, 0xb0, 0x72, 0x0a, 0xd4, 0xde, 0x49, 0x46, 0xb3, 0x29, 0x03, 0x75, 0xbf, 0x2d, 0x5a, 0xcd, 0xed, + 0x49, 0xdd, 0x6f, 0xc8, 0x38, 0xfb, 0x08, 0xe3, 0xec, 0xa3, 0xc0, 0x8b, 0x45, 0x92, 0x3f, 0x64, 0xac, 0x71, 0xac, + 0x9a, 0x02, 0x1d, 0x75, 0x80, 0x3b, 0x03, 0x07, 0x1e, 0xb0, 0x45, 0x39, 0x38, 0xa0, 0xce, 0xe2, 0x9e, 0x36, 0x32, + 0xef, 0xed, 0x09, 0xb5, 0x8b, 0x58, 0xe0, 0x66, 0xcd, 0x4c, 0x0b, 0x5a, 0x2b, 0x8c, 0xf3, 0x78, 0xc0, 0xdb, 0x3c, + 0xab, 0xc5, 0x4f, 0xd8, 0xb0, 0xa6, 0xaa, 0xdf, 0x40, 0x73, 0x54, 0x0b, 0x72, 0xf3, 0xc4, 0x78, 0xab, 0x92, 0x7e, + 0x14, 0x0d, 0x2c, 0xa7, 0x42, 0x0c, 0xc9, 0xe8, 0xb7, 0x06, 0xc1, 0xad, 0xf6, 0x6a, 0xc5, 0x3d, 0xe2, 0x8b, 0x9a, + 0xb7, 0x9a, 0xb9, 0x05, 0xa0, 0x45, 0x1c, 0x95, 0xf7, 0x26, 0x11, 0x78, 0xdf, 0x96, 0x11, 0xd2, 0x96, 0x7d, 0xfb, + 0xfe, 0x63, 0xa9, 0xd8, 0x7c, 0x47, 0x27, 0x83, 0x34, 0xb2, 0x23, 0x8a, 0xf0, 0x75, 0x09, 0x49, 0xb8, 0x4a, 0xba, + 0x56, 0x99, 0x9c, 0x33, 0x95, 0x72, 0x7c, 0x5d, 0x48, 0xa9, 0xaf, 0xec, 0x97, 0xc4, 0xd5, 0x9d, 0x8c, 0xc0, 0xd7, + 0x13, 0xa6, 0xdf, 0xd1, 0x62, 0xc2, 0xc0, 0xaf, 0xc8, 0xdf, 0x8e, 0xa5, 0x94, 0x5c, 0x3e, 0x11, 0x71, 0x9f, 0x62, + 0x78, 0xbc, 0x74, 0x80, 0xb5, 0x09, 0x81, 0x52, 0xe2, 0x22, 0x5c, 0x10, 0xbd, 0x29, 0xe4, 0xed, 0x5d, 0x5c, 0x60, + 0xe7, 0x00, 0x58, 0x3a, 0x4d, 0x02, 0xfc, 0xcb, 0xc7, 0x7c, 0xac, 0xc6, 0x9c, 0x1a, 0x5d, 0xbf, 0xfb, 0x9d, 0x5c, + 0x03, 0xbd, 0x2d, 0x1d, 0x05, 0xfb, 0xad, 0x01, 0xe4, 0xc2, 0x5d, 0x18, 0x5c, 0x7c, 0x85, 0xb5, 0x65, 0x61, 0xbc, + 0xb1, 0x00, 0x7a, 0x7f, 0x67, 0x60, 0xc1, 0x86, 0x39, 0xa6, 0xf0, 0xf2, 0xeb, 0x84, 0xe9, 0x20, 0x2a, 0xc8, 0x93, + 0xf2, 0x6d, 0xcf, 0x5a, 0xed, 0xb7, 0x6c, 0x0c, 0x77, 0x18, 0xc9, 0xb7, 0x0b, 0x27, 0x0e, 0x3c, 0x20, 0xd3, 0x64, + 0xb6, 0xd9, 0x37, 0x3e, 0xf2, 0xc8, 0xeb, 0x71, 0xbc, 0xab, 0xa5, 0x30, 0xdf, 0xac, 0xe8, 0x1a, 0x43, 0x28, 0x8a, + 0xb0, 0xdf, 0x2f, 0x2a, 0xa6, 0xa8, 0x32, 0x68, 0x83, 0x86, 0xe5, 0x8d, 0xf8, 0x05, 0xce, 0x18, 0x5a, 0x2f, 0x64, + 0xef, 0xe8, 0xac, 0xc3, 0x99, 0xc3, 0x8c, 0x29, 0x81, 0x51, 0x69, 0x59, 0xd0, 0x09, 0x38, 0x3a, 0x57, 0x1f, 0x44, + 0xc5, 0xd5, 0xb1, 0x02, 0xf0, 0x24, 0x53, 0xf8, 0x27, 0xdf, 0x04, 0xeb, 0x7e, 0xab, 0x66, 0x98, 0xfa, 0x8b, 0xde, + 0x76, 0x2d, 0x5f, 0x86, 0x38, 0xd2, 0xc6, 0x10, 0x5a, 0xe7, 0xf6, 0x0e, 0x50, 0xc4, 0x05, 0xbd, 0x48, 0x35, 0xbe, + 0x56, 0x8b, 0xa1, 0x59, 0x5f, 0xe3, 0x3a, 0xa6, 0x0d, 0xa2, 0x58, 0x77, 0x4d, 0x7c, 0x5d, 0x3d, 0xa5, 0xaa, 0x52, + 0x05, 0x67, 0x90, 0x40, 0x58, 0x95, 0x97, 0x0d, 0xa9, 0x24, 0x97, 0xa6, 0x53, 0x69, 0x3a, 0xad, 0x10, 0xca, 0xa5, + 0x27, 0xe5, 0xfd, 0x2b, 0x84, 0x30, 0x30, 0x65, 0x76, 0x60, 0x95, 0xda, 0xc2, 0x2a, 0x78, 0xf5, 0x62, 0x03, 0xab, + 0x24, 0x1c, 0xcf, 0x25, 0x1a, 0x15, 0x15, 0x0e, 0x19, 0xd2, 0x17, 0x62, 0x11, 0x24, 0x00, 0x16, 0xbd, 0xcb, 0x5c, + 0xde, 0xf7, 0x70, 0x28, 0xec, 0x49, 0x26, 0xe1, 0x74, 0x13, 0x9a, 0xc3, 0x1b, 0xbb, 0xaa, 0xe7, 0x11, 0x02, 0x96, + 0x9e, 0x63, 0x78, 0x5b, 0xf9, 0xfb, 0x6f, 0xba, 0x3a, 0x0b, 0xf2, 0xf4, 0x5f, 0xa2, 0x24, 0x34, 0xf6, 0x9f, 0xe3, + 0xa1, 0x43, 0xc2, 0x70, 0xe0, 0x9b, 0x23, 0xac, 0x70, 0x70, 0xab, 0x88, 0xcf, 0xe0, 0x0e, 0x1f, 0xeb, 0xd0, 0x03, + 0xc0, 0x12, 0x8a, 0x43, 0x90, 0x6f, 0xa0, 0x98, 0xc1, 0x01, 0x4d, 0x96, 0xe1, 0x05, 0x2e, 0x58, 0x2d, 0x94, 0xf7, + 0xb7, 0x2d, 0x2f, 0xa5, 0xd5, 0x2e, 0x79, 0x8d, 0x39, 0x50, 0xf9, 0x19, 0x5e, 0xf8, 0x0a, 0xf3, 0xe8, 0xb3, 0xfb, + 0xc2, 0xd7, 0x0e, 0xe8, 0x29, 0x04, 0x8c, 0x74, 0xbf, 0xd7, 0x84, 0x7b, 0x8a, 0x5e, 0xe6, 0xe2, 0xb0, 0xed, 0xa0, + 0x7b, 0x81, 0xb9, 0xba, 0xaa, 0xb2, 0xe6, 0x60, 0x0a, 0x0d, 0x0e, 0xaa, 0x70, 0x46, 0x60, 0xae, 0x5e, 0x94, 0x05, + 0xe7, 0x20, 0xde, 0xf7, 0x84, 0xc9, 0x29, 0xa3, 0x01, 0xbc, 0xc8, 0xca, 0x47, 0xa7, 0x7a, 0x1c, 0x5c, 0xc6, 0x0d, + 0x9b, 0xf8, 0x42, 0xf8, 0x54, 0x60, 0x25, 0xad, 0x71, 0x68, 0x44, 0x47, 0x74, 0x0e, 0x66, 0x1b, 0x40, 0xc1, 0xdd, + 0xf9, 0xb0, 0xb1, 0x50, 0xc1, 0xbb, 0xb6, 0xb5, 0x67, 0xa8, 0x09, 0x71, 0x26, 0x4d, 0xc1, 0xdd, 0xb6, 0x41, 0x06, + 0x6f, 0x7e, 0xfb, 0x6f, 0x85, 0x45, 0x82, 0x01, 0x95, 0x9a, 0x24, 0x08, 0x4f, 0x50, 0x1a, 0xe9, 0x56, 0x6e, 0x26, + 0x90, 0x4e, 0x44, 0xcd, 0xa8, 0x7b, 0xe3, 0x7c, 0x75, 0xd4, 0x40, 0x54, 0xd4, 0x40, 0x05, 0xd4, 0x40, 0xd6, 0xb7, + 0x7f, 0x01, 0x0b, 0x61, 0x23, 0x54, 0x89, 0x20, 0x20, 0xc2, 0x5c, 0x1b, 0x3e, 0xa0, 0x48, 0x42, 0xc8, 0x1b, 0x40, + 0xc5, 0x94, 0xbc, 0x04, 0xa3, 0x71, 0x78, 0xbd, 0x07, 0xdc, 0x2f, 0x2d, 0xc3, 0xe0, 0x39, 0x05, 0x93, 0xff, 0xd6, + 0xe7, 0x43, 0xf5, 0x72, 0x75, 0x10, 0xc2, 0x2f, 0x20, 0x56, 0x84, 0xe3, 0x2f, 0x7e, 0x01, 0xb2, 0xa9, 0xb0, 0x3c, + 0x38, 0x90, 0x20, 0xf0, 0x43, 0x14, 0xe1, 0x80, 0x67, 0x78, 0x99, 0x6d, 0x10, 0x3d, 0x3f, 0x2b, 0x55, 0xcd, 0x4a, + 0x06, 0xb3, 0x2a, 0x3c, 0x8d, 0xa3, 0x6b, 0xc2, 0x40, 0x70, 0xa1, 0x76, 0xdf, 0x20, 0x04, 0xca, 0x96, 0x1b, 0x43, + 0x97, 0x9e, 0x82, 0xf9, 0x68, 0x1c, 0xbd, 0x65, 0xf0, 0x3a, 0xaf, 0x31, 0xf9, 0x67, 0x9a, 0x65, 0xda, 0x30, 0x8f, + 0x8d, 0xc0, 0x49, 0x9d, 0xa2, 0xe4, 0x6f, 0xc9, 0x45, 0x1c, 0x35, 0x2f, 0x23, 0xd4, 0x80, 0x7f, 0x1b, 0x1c, 0x75, + 0x69, 0x42, 0x47, 0x23, 0x1f, 0xfc, 0x26, 0x23, 0x66, 0x93, 0xad, 0x56, 0xa2, 0x22, 0xe8, 0x89, 0xdd, 0x60, 0xc0, + 0x4a, 0xbc, 0x00, 0xf6, 0xc1, 0x72, 0xb0, 0xe4, 0x9d, 0x88, 0x95, 0x3f, 0xa5, 0x30, 0x58, 0x3d, 0x67, 0x08, 0xe1, + 0x2c, 0x88, 0xd9, 0xf8, 0x9f, 0xcf, 0x34, 0x5c, 0x3f, 0x3f, 0x5f, 0xc7, 0x88, 0x48, 0x1f, 0x44, 0xae, 0xc6, 0x8e, + 0x88, 0x20, 0x6c, 0x99, 0xee, 0xbb, 0x32, 0x3f, 0x78, 0xeb, 0xea, 0x81, 0x0d, 0x17, 0x07, 0x06, 0xd4, 0x28, 0x30, + 0x5a, 0xc1, 0x39, 0x29, 0x07, 0x0e, 0x4a, 0x08, 0xcd, 0x8a, 0x78, 0x4a, 0x2e, 0x21, 0x12, 0x5e, 0x86, 0xba, 0x60, + 0x58, 0x10, 0x48, 0x50, 0x53, 0x90, 0xa0, 0x32, 0x5f, 0x7b, 0x04, 0xb3, 0xce, 0xcd, 0x6c, 0xa7, 0xa8, 0xeb, 0x82, + 0xfc, 0xfc, 0xa2, 0xe3, 0x11, 0xb0, 0xb4, 0x07, 0x07, 0x05, 0x44, 0x10, 0x03, 0x0a, 0x5e, 0x4a, 0x80, 0x81, 0x06, + 0xbc, 0xd8, 0xd0, 0x80, 0xcf, 0xb5, 0xf1, 0x3a, 0x30, 0xb6, 0x3e, 0x65, 0x90, 0x8b, 0x67, 0xd5, 0x9e, 0x26, 0x84, + 0xec, 0xb7, 0x7a, 0x3a, 0xdd, 0x8e, 0x90, 0xd8, 0xfb, 0xa8, 0x4d, 0xa0, 0x31, 0x47, 0xba, 0xab, 0x8d, 0xf9, 0xb5, + 0xa6, 0x47, 0xac, 0x26, 0x21, 0x5d, 0x90, 0x2e, 0xcf, 0xa7, 0x3d, 0x83, 0x2b, 0x56, 0x69, 0xe4, 0xe0, 0x02, 0xf4, + 0xd9, 0x80, 0x00, 0x05, 0x2a, 0x4d, 0x25, 0x8a, 0x22, 0x2e, 0x92, 0x92, 0x0d, 0xc3, 0x0c, 0xc2, 0x14, 0x56, 0x2b, + 0x41, 0x37, 0xd6, 0x00, 0x78, 0x67, 0x66, 0xff, 0x94, 0x3e, 0xd8, 0x74, 0xed, 0xcd, 0x23, 0x80, 0x80, 0xec, 0xb7, + 0x4b, 0x76, 0x5d, 0x6c, 0x54, 0x66, 0x61, 0x2d, 0x63, 0x2b, 0xb7, 0xed, 0x31, 0xf6, 0x4e, 0x6c, 0xf3, 0x09, 0x10, + 0xa2, 0xb6, 0x64, 0x1a, 0x21, 0x42, 0x62, 0x11, 0xeb, 0xda, 0x90, 0x8d, 0x36, 0xb4, 0x6f, 0x5e, 0xb7, 0x87, 0xd8, + 0x07, 0xa0, 0x78, 0x73, 0x5c, 0x82, 0x43, 0x78, 0xe1, 0x11, 0xfe, 0x16, 0x58, 0xa4, 0x02, 0x33, 0x2c, 0x57, 0x2b, + 0xa8, 0xe7, 0xf1, 0x3e, 0xdb, 0x0c, 0x4e, 0x2a, 0x37, 0xc6, 0x2e, 0xed, 0xc4, 0xe3, 0xb2, 0x09, 0x89, 0x33, 0xe8, + 0xd7, 0x57, 0x44, 0xbd, 0xfd, 0x76, 0xfa, 0xc4, 0xbf, 0x57, 0xe6, 0x76, 0x20, 0x36, 0xac, 0x37, 0x58, 0x7d, 0x00, + 0x2d, 0x7f, 0x95, 0xf9, 0x87, 0xca, 0x82, 0x9b, 0x04, 0xb5, 0xb9, 0x88, 0x5d, 0xd6, 0x45, 0x8c, 0xd4, 0x16, 0x77, + 0x87, 0x10, 0xff, 0x6a, 0x2b, 0x8a, 0x01, 0x4f, 0x2a, 0xfe, 0x39, 0x46, 0x5d, 0x08, 0x45, 0x6d, 0x3d, 0x6c, 0x80, + 0xd2, 0x2e, 0xd7, 0x95, 0x18, 0x19, 0x12, 0xc8, 0xb7, 0x2e, 0xbc, 0xa0, 0x39, 0x89, 0x14, 0xc8, 0xc9, 0x41, 0x54, + 0xd2, 0x6c, 0x43, 0x98, 0xeb, 0x6e, 0xe1, 0x98, 0xb9, 0xda, 0xa0, 0x45, 0xfc, 0x02, 0xd8, 0x19, 0x6e, 0x24, 0x4b, + 0x07, 0x3e, 0x55, 0x03, 0x9f, 0x5f, 0x73, 0x43, 0x51, 0x14, 0xea, 0xbd, 0xb3, 0x8f, 0xcc, 0xc1, 0xef, 0x34, 0x10, + 0x1f, 0xa9, 0xd3, 0x91, 0x6c, 0x84, 0x5a, 0x73, 0x76, 0xbc, 0x6c, 0x33, 0xc2, 0xa0, 0xb0, 0xd1, 0xfb, 0x2a, 0x64, + 0x15, 0x3b, 0x3b, 0x15, 0xc1, 0x9c, 0xbe, 0xa8, 0xca, 0x39, 0x95, 0x5b, 0x46, 0xb5, 0xd4, 0x34, 0x40, 0x84, 0x2b, + 0x9f, 0x48, 0xde, 0x67, 0x26, 0xfc, 0x83, 0xc1, 0xb8, 0x7a, 0xa4, 0xf0, 0xf7, 0xbb, 0x62, 0x87, 0x6c, 0x47, 0x87, + 0xdb, 0x08, 0x9a, 0x17, 0x2a, 0x78, 0xc0, 0x51, 0xc9, 0x12, 0x22, 0x45, 0x2e, 0xf7, 0x55, 0xcd, 0x94, 0xed, 0x3a, + 0x42, 0x08, 0x69, 0x8f, 0xb3, 0x6e, 0x68, 0xf5, 0xd0, 0x23, 0x55, 0x94, 0xc3, 0x2d, 0x9a, 0xeb, 0x02, 0x54, 0x18, + 0x81, 0x74, 0xf9, 0x99, 0xdd, 0xa5, 0x12, 0xa2, 0x97, 0xaf, 0x5d, 0x08, 0x63, 0x67, 0x65, 0x89, 0x0b, 0x33, 0x6a, + 0x1b, 0x46, 0xd7, 0x6d, 0x0c, 0x67, 0x03, 0x63, 0xa6, 0x41, 0x49, 0x0b, 0x42, 0x5d, 0x77, 0xe9, 0x45, 0x66, 0x02, + 0x3d, 0xe6, 0x84, 0x36, 0x18, 0x9e, 0x12, 0x0d, 0x96, 0x4d, 0x05, 0x58, 0xf0, 0x2d, 0x8b, 0xd4, 0xda, 0x6c, 0xb2, + 0xf8, 0xa3, 0x8e, 0xcd, 0xd3, 0x7e, 0x79, 0xc5, 0x3c, 0x17, 0x8e, 0xba, 0x3d, 0xcf, 0x7c, 0x3c, 0xba, 0xa7, 0x6f, + 0xae, 0x5e, 0xbc, 0x7c, 0xfd, 0x6a, 0xb5, 0x6a, 0xb3, 0x66, 0xfb, 0x04, 0xff, 0xa4, 0xcb, 0x78, 0xb0, 0x65, 0x14, + 0xa0, 0x83, 0x83, 0x7d, 0x6e, 0x5c, 0x78, 0x3e, 0xf3, 0x39, 0xc4, 0x0d, 0xd2, 0x03, 0x9c, 0x15, 0x65, 0x4c, 0x90, + 0xdb, 0xa8, 0x17, 0xdd, 0x45, 0xa0, 0x84, 0xaa, 0xc8, 0xdf, 0x87, 0xcd, 0xd9, 0xef, 0x41, 0x60, 0x22, 0xa8, 0x0f, + 0x11, 0x40, 0x20, 0x5e, 0x29, 0x2e, 0x08, 0xf3, 0x09, 0x10, 0xc5, 0x7b, 0x01, 0x9c, 0xa9, 0x89, 0x5a, 0xb5, 0x50, + 0x71, 0x01, 0x24, 0xd1, 0x86, 0xa3, 0xa4, 0x47, 0x26, 0x80, 0x37, 0x04, 0xa5, 0xb4, 0xbf, 0xba, 0xb9, 0x73, 0x97, + 0xca, 0x51, 0xaf, 0x95, 0xe6, 0x78, 0xea, 0x3e, 0xa7, 0xf0, 0x39, 0xed, 0xfa, 0xd3, 0x41, 0x1c, 0xe6, 0x78, 0x41, + 0xc4, 0xa1, 0x7f, 0x16, 0x71, 0x39, 0x2f, 0xd8, 0x17, 0x2e, 0x17, 0x2a, 0x5d, 0xde, 0xa6, 0x32, 0xb9, 0x6d, 0x8e, + 0x0e, 0xe3, 0x22, 0xb9, 0x6d, 0xaa, 0xe4, 0x16, 0xe1, 0xbb, 0x54, 0x26, 0x77, 0x36, 0xe5, 0xae, 0xa9, 0xe0, 0xe6, + 0x0b, 0x0b, 0x38, 0x14, 0x6d, 0xd1, 0xc6, 0x62, 0xb3, 0xa8, 0x4d, 0x71, 0x45, 0x03, 0x0c, 0xfe, 0x7d, 0xc7, 0xc6, + 0x0f, 0xc3, 0x97, 0xe0, 0xd2, 0xa4, 0x89, 0xfc, 0x04, 0xd2, 0x4f, 0xab, 0x32, 0x70, 0x9f, 0x92, 0x56, 0x77, 0x7a, + 0x21, 0x9a, 0xed, 0x6e, 0xa3, 0x31, 0x85, 0xbd, 0x9b, 0x91, 0xdc, 0x17, 0x9b, 0x36, 0x4c, 0x7c, 0x9d, 0xfd, 0x6c, + 0xb5, 0xda, 0xcf, 0x91, 0xd9, 0x70, 0x13, 0x16, 0xeb, 0xfe, 0x74, 0x80, 0x5b, 0xf8, 0x79, 0x86, 0xd0, 0x92, 0xf5, + 0xa7, 0x03, 0xc2, 0xfa, 0xd3, 0x46, 0x7b, 0x60, 0x0d, 0xed, 0xcc, 0x56, 0x5c, 0x43, 0x08, 0xcd, 0xe9, 0xe0, 0xc8, + 0x94, 0x94, 0x2e, 0xdf, 0x7e, 0xd1, 0x2a, 0xa0, 0x9f, 0xaa, 0x05, 0x2f, 0x93, 0xb8, 0x03, 0x7d, 0xd1, 0x0b, 0xfb, + 0x74, 0x6b, 0x41, 0x8e, 0x8f, 0x2a, 0x57, 0x7b, 0x8a, 0xb0, 0xe9, 0x49, 0x1d, 0x16, 0x87, 0xa6, 0x19, 0xd7, 0xa5, + 0x74, 0xdf, 0xa1, 0x66, 0xe4, 0xa3, 0x83, 0x05, 0x20, 0x48, 0x05, 0x8f, 0xac, 0x70, 0xe1, 0x94, 0x42, 0xb8, 0x38, + 0xa8, 0x6c, 0xc1, 0x24, 0x27, 0xad, 0x6e, 0x6e, 0x2c, 0xfd, 0x73, 0x17, 0xd1, 0x94, 0x62, 0x4a, 0x32, 0x5f, 0x32, + 0x37, 0x60, 0xa1, 0x9b, 0x94, 0x67, 0x0a, 0x7a, 0xa5, 0x01, 0x1e, 0x11, 0x88, 0x87, 0xd4, 0x2d, 0x8c, 0x81, 0x57, + 0x3c, 0x6d, 0x16, 0x7d, 0x36, 0x40, 0x47, 0xc7, 0x98, 0xf6, 0xff, 0xca, 0xe6, 0x6d, 0x78, 0x2c, 0xf0, 0xaf, 0x01, + 0x99, 0x36, 0x65, 0x99, 0x20, 0x20, 0x61, 0xd4, 0x94, 0x87, 0xb0, 0x97, 0x10, 0xce, 0x6c, 0xc5, 0xac, 0xcf, 0x06, + 0xcd, 0x69, 0x59, 0xb1, 0xe3, 0x2b, 0x36, 0x64, 0x99, 0x60, 0x2b, 0x36, 0x5c, 0xc5, 0xf0, 0x75, 0x06, 0x03, 0x82, + 0x10, 0x00, 0x0c, 0x00, 0xa0, 0x51, 0x10, 0xcd, 0x17, 0x2b, 0xe2, 0x37, 0xbb, 0xbd, 0xc7, 0x6f, 0x81, 0x05, 0x5a, + 0x6d, 0xff, 0xef, 0x42, 0x19, 0xb0, 0xa7, 0x2c, 0x4c, 0xcc, 0xdc, 0xc2, 0xaa, 0xe8, 0x00, 0x2a, 0x25, 0xc2, 0x14, + 0x06, 0x32, 0xfb, 0x99, 0x81, 0x5a, 0xa0, 0x35, 0xc8, 0xfb, 0x7a, 0xd0, 0xcc, 0xe0, 0x88, 0x81, 0x77, 0x68, 0xc8, + 0xd4, 0x18, 0x13, 0xc6, 0x39, 0x4c, 0x31, 0x33, 0xe0, 0x99, 0xa6, 0xad, 0xb5, 0x34, 0xb2, 0x5c, 0x2f, 0xef, 0xfd, + 0xa3, 0x63, 0xd5, 0x2f, 0x9a, 0xed, 0x01, 0xda, 0x27, 0xc4, 0x7e, 0x0c, 0x60, 0x93, 0xb9, 0xd4, 0x86, 0xf9, 0x3e, + 0xea, 0xa4, 0xf6, 0x13, 0xfe, 0x0c, 0xd6, 0x66, 0x07, 0x80, 0x8e, 0x0c, 0x9b, 0xf5, 0x97, 0x35, 0x95, 0xd7, 0xc7, + 0x9d, 0x51, 0x2a, 0x77, 0xbd, 0x3b, 0x1d, 0x68, 0x8a, 0x43, 0x6f, 0x3d, 0x5c, 0x3e, 0xd4, 0x43, 0xc0, 0x8c, 0xc1, + 0xdc, 0x32, 0xa3, 0xef, 0x85, 0x48, 0x2e, 0x88, 0xc4, 0xd2, 0x60, 0x0d, 0x83, 0xbd, 0x75, 0x70, 0x60, 0xaa, 0xb1, + 0x06, 0x3c, 0x4f, 0x8a, 0x40, 0x30, 0xf0, 0x11, 0x94, 0x01, 0x4d, 0x94, 0xb9, 0x0d, 0x27, 0x1f, 0x99, 0xfb, 0x85, + 0xcb, 0xdb, 0xc7, 0xc2, 0x69, 0x5b, 0xcd, 0xf5, 0x78, 0x59, 0xe0, 0xae, 0xbc, 0x97, 0xb4, 0x0a, 0x6e, 0x64, 0x6f, + 0xf2, 0x94, 0xb9, 0x5b, 0xf7, 0xa5, 0x3a, 0xbb, 0x9b, 0xe9, 0x94, 0xcd, 0x74, 0xb6, 0x9b, 0x09, 0x35, 0x33, 0xdf, + 0xb2, 0x8a, 0x34, 0x27, 0x6b, 0xa2, 0xe6, 0x54, 0xfc, 0x44, 0xe7, 0xa0, 0x1d, 0xe5, 0xf6, 0x5e, 0x15, 0x4e, 0xae, + 0x9c, 0x5c, 0xee, 0xe7, 0x86, 0xb8, 0x22, 0x73, 0xa1, 0x0e, 0x01, 0x5e, 0x5e, 0x94, 0x8f, 0x0f, 0x70, 0x29, 0x7e, + 0x95, 0x23, 0x17, 0xe5, 0x54, 0x48, 0x2d, 0x05, 0x8b, 0x90, 0x41, 0x55, 0x17, 0x03, 0x7b, 0x69, 0xf7, 0x9e, 0xe8, + 0xf1, 0x7e, 0x15, 0x31, 0x6f, 0x60, 0x9e, 0xfb, 0xf8, 0x9e, 0xa6, 0xd8, 0xa9, 0x89, 0x33, 0xf2, 0x21, 0x8b, 0x73, + 0x90, 0xcd, 0xfa, 0xd5, 0x6b, 0xbf, 0x8d, 0x36, 0x2e, 0x9a, 0xb1, 0xe8, 0x99, 0x27, 0x4e, 0x7e, 0x28, 0x8c, 0x71, + 0x80, 0x75, 0xf4, 0x47, 0x98, 0x5a, 0xb0, 0x67, 0x89, 0xa7, 0xd0, 0xc9, 0xad, 0x4d, 0xbb, 0x0b, 0xd3, 0xee, 0x4c, + 0x5a, 0x07, 0xca, 0x01, 0x69, 0x76, 0x65, 0x3a, 0x77, 0xfe, 0xfb, 0x0e, 0x5e, 0xba, 0x5d, 0x43, 0x24, 0xee, 0xf9, + 0x23, 0x63, 0x0c, 0xf1, 0x06, 0x6c, 0x44, 0xd5, 0xc1, 0xc1, 0x1f, 0xce, 0xfb, 0xb6, 0x92, 0xfb, 0xbe, 0x15, 0x0e, + 0x6c, 0x83, 0xa9, 0x74, 0x79, 0x23, 0x99, 0x2d, 0xc0, 0xae, 0x73, 0xff, 0x1b, 0xf1, 0xf0, 0x45, 0xc8, 0xb4, 0x58, + 0x57, 0xf1, 0x57, 0x72, 0x54, 0x7a, 0x88, 0x6a, 0x88, 0x40, 0x5a, 0x59, 0x97, 0x86, 0xa6, 0xa3, 0x57, 0x53, 0x3a, + 0x92, 0x37, 0x6f, 0xa5, 0xd4, 0x03, 0xfb, 0x22, 0xb7, 0x4e, 0xe0, 0xd1, 0xc2, 0x1a, 0x43, 0x73, 0x57, 0x7a, 0x27, + 0xd9, 0x80, 0xa8, 0xf5, 0x71, 0x87, 0x92, 0x48, 0x2c, 0xaa, 0xbb, 0x10, 0x0e, 0x77, 0x21, 0x98, 0x97, 0x41, 0xdb, + 0x20, 0x76, 0xbb, 0x0b, 0xda, 0x06, 0x4e, 0xdd, 0x36, 0x70, 0x7b, 0x30, 0x58, 0xd8, 0xfb, 0xf0, 0x72, 0x2c, 0xc7, + 0xc2, 0x5f, 0x93, 0xd9, 0x07, 0x80, 0x40, 0xed, 0xc3, 0x8a, 0x27, 0x0e, 0x04, 0x89, 0x33, 0x1c, 0x7d, 0xcf, 0xd9, + 0x8d, 0xb5, 0x1c, 0x9e, 0xcd, 0x17, 0x9a, 0x8d, 0xcc, 0x1d, 0x35, 0xa8, 0xf8, 0xea, 0x7e, 0x5e, 0x3f, 0x65, 0x35, + 0xdd, 0xf8, 0x3d, 0x08, 0x23, 0xe1, 0x94, 0x1d, 0x46, 0x21, 0x61, 0x83, 0x59, 0x95, 0xf1, 0xda, 0x7e, 0x83, 0x78, + 0x0f, 0xda, 0x84, 0x13, 0x2c, 0x6a, 0x17, 0x54, 0x11, 0xb6, 0xf1, 0xc6, 0x82, 0x28, 0x0f, 0x6f, 0xb6, 0x8c, 0xa6, + 0x97, 0x6b, 0x08, 0x74, 0xdc, 0x8b, 0x9a, 0x51, 0x83, 0xa5, 0x2e, 0x28, 0xb3, 0x8f, 0x30, 0xae, 0x2e, 0x4e, 0x4c, + 0x9c, 0xf6, 0x52, 0xaf, 0xfe, 0x5b, 0x06, 0x06, 0xf8, 0x02, 0xbc, 0xc4, 0xc2, 0xe8, 0xae, 0x7d, 0xdd, 0x80, 0xfa, + 0xb2, 0xc1, 0x06, 0x68, 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xb9, 0x6b, 0x2e, 0x61, 0xaf, 0xb9, 0x84, 0xbb, 0xe6, 0x12, + 0xfe, 0x9a, 0x4b, 0x98, 0x6b, 0x2e, 0xe1, 0xaf, 0xb9, 0x3c, 0x08, 0x3f, 0x05, 0x71, 0x1c, 0x63, 0x0e, 0x71, 0x15, + 0xb5, 0x8d, 0x8c, 0x07, 0x17, 0x9e, 0xfb, 0x2c, 0x51, 0xe5, 0xf2, 0x87, 0x31, 0xe4, 0xb6, 0x6c, 0x25, 0x8c, 0xdb, + 0x14, 0x53, 0x10, 0x39, 0xfd, 0xe0, 0xa0, 0x74, 0x77, 0x06, 0x1f, 0xf5, 0x94, 0xe3, 0xa5, 0x75, 0xa2, 0xfd, 0x03, + 0x74, 0xf2, 0xe6, 0xd7, 0xc7, 0x54, 0xae, 0x89, 0x70, 0x26, 0xf7, 0xfb, 0x6d, 0x4f, 0x29, 0x3e, 0x65, 0x26, 0x3c, + 0x39, 0x4f, 0xb4, 0x11, 0x41, 0x10, 0xa2, 0x44, 0xe1, 0x8c, 0x48, 0xbb, 0xdf, 0xbd, 0x2b, 0xbc, 0x51, 0x45, 0x79, + 0xb3, 0x92, 0xc7, 0x39, 0x38, 0xb1, 0x1b, 0x2b, 0x0c, 0xd4, 0x05, 0x17, 0x82, 0xcc, 0x24, 0xfc, 0xd1, 0xcc, 0x2d, + 0x39, 0xcb, 0xca, 0xa4, 0x8f, 0xcd, 0xdc, 0x10, 0xb0, 0x82, 0xec, 0x7b, 0x98, 0x2d, 0x6f, 0x53, 0x8a, 0xef, 0xd2, + 0x0c, 0x0f, 0xe5, 0x6d, 0x5a, 0x84, 0xb6, 0x20, 0xfe, 0xe2, 0xef, 0xff, 0x65, 0xef, 0x5d, 0x9b, 0xdb, 0x36, 0xb2, + 0x76, 0xd1, 0xbf, 0x22, 0xb1, 0x6c, 0x06, 0x30, 0x9b, 0x14, 0xe5, 0xbd, 0x67, 0xaa, 0x0e, 0xa8, 0x16, 0xcb, 0xb1, + 0xe3, 0x89, 0x33, 0xf1, 0x65, 0x2c, 0x4f, 0x26, 0x19, 0x16, 0x0f, 0x03, 0x01, 0x4d, 0x01, 0x0e, 0x08, 0x30, 0x00, + 0x28, 0x91, 0x26, 0xf1, 0xdf, 0x77, 0xad, 0xb5, 0xfa, 0x0a, 0x82, 0xb2, 0xe7, 0x7d, 0xf7, 0xfb, 0xe9, 0x9c, 0x2f, + 0xb6, 0xd8, 0x68, 0x34, 0xfa, 0xde, 0xab, 0xd7, 0xe5, 0x79, 0x96, 0x5e, 0x2f, 0x0f, 0x21, 0xde, 0xa7, 0x97, 0xe6, + 0x67, 0x69, 0x2b, 0x0a, 0x70, 0x1f, 0xa1, 0x47, 0x75, 0x20, 0xd8, 0x09, 0x4f, 0x78, 0x00, 0x27, 0xab, 0x59, 0xc5, + 0x9f, 0xa4, 0x20, 0x4e, 0x14, 0x1c, 0x02, 0xae, 0xb6, 0x37, 0xe9, 0x17, 0x30, 0x7c, 0xe9, 0x60, 0xcb, 0xe1, 0x6d, + 0xb1, 0xed, 0xb1, 0x92, 0x7f, 0x00, 0xf6, 0xad, 0x9e, 0x8c, 0xd5, 0xed, 0x81, 0xb3, 0x2e, 0xa5, 0xe8, 0x78, 0x53, + 0x1c, 0xde, 0x9e, 0xcf, 0xf6, 0xdb, 0x20, 0x62, 0xbb, 0x20, 0xc3, 0x5a, 0x27, 0x0d, 0xff, 0x89, 0xb6, 0x0e, 0x16, + 0x23, 0xec, 0xff, 0xb2, 0x1e, 0x78, 0x09, 0xa9, 0xa1, 0xc0, 0xc5, 0x60, 0xc3, 0xd1, 0xda, 0x2e, 0xd3, 0xc0, 0x4d, + 0x0d, 0x7a, 0x7d, 0x4f, 0x21, 0xca, 0x4b, 0x46, 0x73, 0x23, 0x58, 0x37, 0x86, 0x5c, 0x1c, 0x8e, 0x9b, 0xe5, 0x90, + 0x97, 0x34, 0x9d, 0x06, 0xa1, 0x74, 0x67, 0x59, 0x43, 0x12, 0x65, 0x1f, 0x84, 0xda, 0xb5, 0x65, 0xbf, 0x0d, 0x6c, + 0x5f, 0xfe, 0x68, 0x18, 0xfb, 0x17, 0xcb, 0x67, 0x42, 0xba, 0x88, 0xe7, 0x20, 0x88, 0xda, 0xcf, 0xb3, 0xe1, 0xc6, + 0xbf, 0x58, 0x3f, 0x13, 0xca, 0x6f, 0x3c, 0xb7, 0xe5, 0x90, 0x3a, 0x6b, 0xe1, 0x0b, 0xe3, 0xe1, 0xc1, 0x95, 0xa1, + 0xed, 0x70, 0x10, 0xfa, 0x6f, 0xb3, 0x46, 0x70, 0x63, 0x43, 0xfb, 0x7c, 0xe1, 0xc3, 0xd6, 0x46, 0x63, 0x4d, 0x31, + 0xdd, 0x42, 0xff, 0x26, 0xb3, 0xa5, 0x3d, 0x8d, 0x4a, 0x5e, 0x9c, 0x9a, 0x46, 0x2c, 0x84, 0x01, 0x43, 0x3f, 0x99, + 0x0f, 0xa0, 0x9a, 0x3b, 0x1e, 0x81, 0x4c, 0x3e, 0xd0, 0x83, 0x35, 0xa9, 0x55, 0x7f, 0x0d, 0x33, 0xf9, 0x7f, 0xa4, + 0xc2, 0x62, 0x74, 0xb7, 0x0d, 0x33, 0xf5, 0x47, 0x24, 0xff, 0x60, 0x39, 0xdf, 0xa5, 0x5e, 0xa8, 0xfd, 0x58, 0x58, + 0x81, 0x41, 0x89, 0xaa, 0x01, 0x3d, 0x10, 0x41, 0x55, 0x06, 0x69, 0x86, 0xd5, 0x39, 0xe8, 0x77, 0x4f, 0xab, 0x8e, + 0xe4, 0x90, 0xd6, 0x6a, 0x48, 0x05, 0x53, 0xa5, 0x06, 0xf9, 0xe1, 0x70, 0x97, 0x32, 0x5d, 0x06, 0x5c, 0xd2, 0xef, + 0x52, 0xa5, 0x14, 0xfe, 0x13, 0x01, 0xe8, 0x1c, 0xdc, 0xe3, 0xcb, 0x31, 0x90, 0x66, 0x58, 0xf8, 0xad, 0xd9, 0xf1, + 0x35, 0x09, 0xb7, 0x49, 0x70, 0x31, 0xc0, 0x39, 0xba, 0x0a, 0xcb, 0xbb, 0x14, 0x22, 0xa8, 0x4a, 0xa8, 0x6f, 0x65, + 0x1a, 0x94, 0xb6, 0x1a, 0x84, 0x35, 0x09, 0x75, 0x26, 0xd9, 0xa8, 0xb4, 0xdd, 0x28, 0xcc, 0x16, 0x71, 0x3d, 0x23, + 0xac, 0x39, 0x9b, 0xa9, 0x06, 0x26, 0x0d, 0xc7, 0x4d, 0xa3, 0xb5, 0xa8, 0x50, 0x53, 0x98, 0xd7, 0xb8, 0xaa, 0x54, + 0x75, 0x37, 0xa7, 0x96, 0xd2, 0xb2, 0xbd, 0xea, 0x26, 0xd9, 0x90, 0xcb, 0x50, 0x86, 0xc1, 0x46, 0x8e, 0x60, 0x02, + 0x49, 0x72, 0xe6, 0x6f, 0xe4, 0x1f, 0x6a, 0xd3, 0xb5, 0x80, 0x39, 0xc6, 0x2c, 0x1b, 0x16, 0xf4, 0x0a, 0xdc, 0x03, + 0xad, 0xf4, 0x7c, 0x9a, 0x5d, 0xe4, 0x41, 0x32, 0x2c, 0xf4, 0xb2, 0xc9, 0xf8, 0x9f, 0xc2, 0x48, 0x93, 0x19, 0x2b, + 0x59, 0x64, 0xbb, 0x3a, 0x25, 0xce, 0xe3, 0x04, 0xb6, 0x47, 0xd3, 0x5b, 0xbe, 0xcf, 0x20, 0x2a, 0x08, 0x14, 0xcc, + 0x98, 0x2f, 0xbb, 0x78, 0xee, 0xfb, 0xcc, 0x32, 0x75, 0x1f, 0x0e, 0xc6, 0x8c, 0xed, 0xf7, 0xfb, 0x79, 0xbf, 0xaf, + 0xe6, 0x5b, 0xbf, 0x9f, 0x5c, 0x9b, 0xbf, 0x3d, 0x60, 0x50, 0x90, 0x13, 0xd1, 0x54, 0x88, 0xe0, 0x1f, 0x92, 0x67, + 0x48, 0x46, 0x77, 0xdc, 0xe7, 0x96, 0xb3, 0x65, 0x75, 0x04, 0x82, 0x79, 0x38, 0x5c, 0x2a, 0xb0, 0x6b, 0x89, 0x22, + 0x21, 0xcb, 0x7f, 0x06, 0xc6, 0x33, 0xf7, 0x01, 0x96, 0x0c, 0x40, 0xd8, 0x2a, 0x4f, 0xd7, 0x7b, 0xbe, 0x0a, 0xde, + 0xe9, 0x78, 0xd7, 0x58, 0x91, 0x81, 0xb8, 0x05, 0x36, 0x62, 0xad, 0x3d, 0x20, 0x67, 0x0a, 0x70, 0xbc, 0x38, 0x1c, + 0xce, 0xe5, 0x2f, 0xdd, 0x6c, 0x9d, 0x40, 0xa5, 0xc0, 0xed, 0xd1, 0xc9, 0xc1, 0x7f, 0x07, 0x9a, 0x41, 0x39, 0xcc, + 0xeb, 0xed, 0xef, 0xcc, 0xc9, 0x4f, 0x4f, 0xf1, 0x4f, 0x78, 0x88, 0x4e, 0xbf, 0xdd, 0x9b, 0x3f, 0x28, 0x2a, 0x0f, + 0x07, 0xb5, 0xf8, 0xcf, 0x39, 0xaf, 0xe0, 0x17, 0xbe, 0x09, 0xcc, 0x26, 0x53, 0xef, 0xe4, 0x9b, 0x3c, 0x67, 0xea, + 0x35, 0x5e, 0x31, 0xf9, 0x0e, 0x87, 0x73, 0x31, 0xaa, 0xb7, 0x23, 0x27, 0xda, 0x29, 0xc7, 0x38, 0x18, 0xfc, 0x17, + 0xd1, 0x36, 0x21, 0xc0, 0x90, 0xba, 0x25, 0xcd, 0x6c, 0x5c, 0x59, 0xe2, 0x59, 0x3a, 0xbf, 0x9c, 0xd4, 0xe5, 0x4e, + 0x2b, 0x9e, 0xf6, 0xc0, 0xe2, 0xb6, 0x06, 0x2f, 0x80, 0x7b, 0x8b, 0xad, 0x2b, 0x05, 0x87, 0x0b, 0x88, 0x53, 0x9c, + 0x80, 0x08, 0xda, 0xef, 0x4b, 0xbc, 0x57, 0xd0, 0x27, 0xfd, 0x00, 0xc1, 0x90, 0x3f, 0x4b, 0xc0, 0x5d, 0xaf, 0x57, + 0x63, 0x7c, 0x2f, 0x85, 0xe0, 0xfa, 0x4c, 0x03, 0xd0, 0x82, 0xdf, 0xe5, 0x63, 0x39, 0xfd, 0x26, 0x02, 0xcf, 0x96, + 0xbd, 0x89, 0x72, 0xb7, 0xe1, 0x69, 0xff, 0x68, 0x21, 0x00, 0x4b, 0xf1, 0x4c, 0x09, 0x16, 0xe4, 0x14, 0x73, 0xf1, + 0xff, 0x82, 0x8f, 0x98, 0xef, 0x49, 0x17, 0xb1, 0xf5, 0xf6, 0xc9, 0x85, 0x81, 0x04, 0x9a, 0x0e, 0xc0, 0x8f, 0x57, + 0x01, 0x5d, 0x19, 0x3f, 0x3f, 0xcb, 0x7a, 0xac, 0x8f, 0xff, 0x14, 0xdc, 0xa7, 0x9f, 0x29, 0x7c, 0x74, 0x38, 0xae, + 0xd2, 0xd1, 0x8e, 0x52, 0x10, 0x1d, 0xdd, 0x3e, 0x9f, 0xf2, 0xec, 0x9b, 0x0a, 0xc8, 0x2d, 0x47, 0xed, 0xa9, 0x00, + 0x2c, 0xb6, 0x74, 0x04, 0x3e, 0xcd, 0xf2, 0x09, 0xf9, 0x5e, 0x4f, 0xc5, 0xd5, 0xa5, 0x4e, 0x17, 0xd7, 0xe3, 0x29, + 0xfc, 0x0f, 0xc4, 0x1e, 0x96, 0x29, 0xb2, 0x63, 0xd7, 0xc5, 0x0f, 0xe2, 0x6d, 0x6d, 0x47, 0x7f, 0xec, 0x20, 0xd2, + 0x71, 0x4f, 0x2e, 0xd4, 0x97, 0x90, 0x4a, 0x2e, 0xd4, 0x0d, 0xc4, 0x2e, 0xd4, 0x78, 0xc7, 0x45, 0xac, 0xf5, 0xb7, + 0x35, 0x0a, 0x56, 0x02, 0xce, 0xb4, 0xb7, 0x60, 0xb0, 0x81, 0x75, 0xcb, 0x32, 0xf8, 0x1b, 0xae, 0x69, 0x02, 0x37, + 0x2c, 0xb2, 0xde, 0x1b, 0x6c, 0xa5, 0xb7, 0xe0, 0x68, 0x99, 0x38, 0x97, 0x92, 0xac, 0x6c, 0x91, 0x71, 0xf5, 0x28, + 0xa4, 0x6a, 0xba, 0xbf, 0x15, 0xf5, 0x83, 0x10, 0x79, 0xb0, 0x4a, 0x59, 0x54, 0xac, 0x40, 0x66, 0x0f, 0xfe, 0x11, + 0x32, 0x72, 0x94, 0x03, 0x47, 0xa1, 0xbf, 0x35, 0x81, 0xce, 0xf3, 0x53, 0xa8, 0xf3, 0x48, 0xb0, 0x95, 0x7a, 0x28, + 0xac, 0xbc, 0x80, 0xe8, 0x60, 0x0b, 0x63, 0x95, 0x27, 0xa1, 0x62, 0x53, 0x26, 0xf2, 0x38, 0xa8, 0x25, 0x60, 0xac, + 0x20, 0x98, 0xb3, 0x5c, 0xba, 0x20, 0x55, 0x8d, 0x1e, 0x16, 0x99, 0xfb, 0xa9, 0xa0, 0xfc, 0x4f, 0x55, 0x4e, 0xb8, + 0xbe, 0x0c, 0x01, 0x8e, 0xf6, 0x29, 0x88, 0x12, 0x63, 0xfd, 0xa2, 0xc5, 0x3b, 0x99, 0x39, 0x9b, 0xda, 0x5e, 0x82, + 0x8c, 0xed, 0xf0, 0x2b, 0x84, 0x56, 0x0b, 0x45, 0x16, 0x0d, 0x17, 0x4c, 0xb7, 0xa7, 0xb4, 0xea, 0x1e, 0x36, 0x3c, + 0x2b, 0x3d, 0x54, 0xea, 0xdb, 0x98, 0xc0, 0xb2, 0x4a, 0x19, 0xbe, 0x9d, 0x50, 0x75, 0x62, 0x50, 0xb1, 0x6e, 0xd8, + 0x12, 0x0e, 0xb1, 0x98, 0x34, 0xd6, 0xd9, 0x80, 0x47, 0x2c, 0x81, 0x7f, 0x36, 0x7c, 0xcc, 0x96, 0x3c, 0x9a, 0x6c, + 0xae, 0x96, 0xfd, 0x7e, 0xe9, 0x85, 0x5e, 0x3d, 0xcb, 0x9e, 0x46, 0xf3, 0x59, 0x3e, 0xf7, 0x51, 0x71, 0x31, 0x19, + 0x0c, 0x36, 0x7e, 0x36, 0x1c, 0xb2, 0x64, 0x38, 0x9c, 0x64, 0x4f, 0xe1, 0xb5, 0xa7, 0x3c, 0x52, 0x4b, 0x2a, 0xb9, + 0xca, 0x60, 0x7f, 0x1f, 0xf0, 0xc8, 0x67, 0x9d, 0x9f, 0x96, 0x4d, 0x97, 0xee, 0x67, 0x76, 0xdc, 0x85, 0xee, 0x00, + 0x1b, 0x6f, 0x1b, 0x74, 0xe4, 0x5f, 0xef, 0x90, 0x52, 0x37, 0x19, 0x80, 0xdd, 0x68, 0x80, 0x43, 0xa6, 0x7a, 0x29, + 0xb2, 0x7a, 0x29, 0x53, 0xbd, 0x24, 0x2b, 0x97, 0x60, 0x21, 0x31, 0x55, 0x6e, 0x23, 0x2b, 0xb7, 0x6c, 0xb8, 0x1e, + 0x0e, 0xb6, 0x56, 0x5c, 0x36, 0x77, 0x70, 0x5f, 0x58, 0x51, 0xe0, 0xff, 0x2d, 0x5b, 0xb0, 0x7b, 0x79, 0x0c, 0xbc, + 0x45, 0xc7, 0x24, 0xb8, 0x40, 0xdc, 0xb3, 0x5b, 0xb0, 0xc3, 0xc2, 0x5f, 0x70, 0x9d, 0x1c, 0xb3, 0x1d, 0x3e, 0x0a, + 0xbd, 0x82, 0xdd, 0xfa, 0x04, 0xb4, 0x0b, 0xb6, 0x06, 0xc8, 0xc6, 0xb6, 0xf8, 0xe8, 0xee, 0x70, 0x78, 0xeb, 0xf9, + 0xec, 0x01, 0x7f, 0x9c, 0xdf, 0x1d, 0x0e, 0x3b, 0xcf, 0xa8, 0xf7, 0x6e, 0x78, 0xc2, 0xde, 0xf3, 0x64, 0x72, 0x73, + 0xc5, 0xe3, 0xc9, 0x60, 0x70, 0xe3, 0x2f, 0x78, 0x3d, 0xbb, 0x01, 0xed, 0xc0, 0xf9, 0x42, 0xea, 0x9a, 0xbd, 0x5b, + 0x9e, 0x79, 0x0b, 0x1c, 0x9b, 0x5b, 0x38, 0x7a, 0xfb, 0x7d, 0xef, 0x8e, 0x47, 0xde, 0x2d, 0xa9, 0x98, 0x56, 0x5c, + 0x71, 0xbc, 0x6d, 0x71, 0x3f, 0x5d, 0xf1, 0x10, 0x1e, 0x61, 0x55, 0xa6, 0x37, 0xc1, 0x7b, 0x9f, 0xad, 0x34, 0x0b, + 0xdc, 0x03, 0xe6, 0x58, 0x93, 0x9d, 0xd0, 0x4c, 0xfc, 0x15, 0xf6, 0xcf, 0x8d, 0xea, 0x1f, 0x9a, 0xff, 0xa5, 0xee, + 0x27, 0x70, 0xfb, 0x22, 0x0b, 0x12, 0x7b, 0xcf, 0x6f, 0xd8, 0x3d, 0x37, 0x6c, 0xb3, 0x67, 0xa6, 0xec, 0x13, 0xa5, + 0xc6, 0x8f, 0x94, 0xba, 0xb6, 0x0c, 0x2b, 0x99, 0xbb, 0x2f, 0x23, 0x70, 0x38, 0x20, 0x3f, 0xdd, 0x21, 0x0e, 0x42, + 0xeb, 0x26, 0xab, 0xb9, 0xa2, 0x9c, 0x0b, 0x6d, 0x99, 0x79, 0x39, 0xb0, 0x98, 0xa5, 0x14, 0x1a, 0x0b, 0x00, 0x04, + 0x93, 0x42, 0x6b, 0xef, 0x65, 0x00, 0x39, 0x41, 0xc3, 0x1f, 0x9b, 0xab, 0xa2, 0xac, 0x65, 0x4b, 0x42, 0x94, 0xed, + 0x7a, 0x78, 0x89, 0x90, 0x69, 0xfd, 0xfe, 0x39, 0x91, 0xac, 0x4d, 0xaa, 0xab, 0x1a, 0x2d, 0x01, 0x15, 0x59, 0x02, + 0x26, 0x7e, 0xa5, 0xf9, 0x04, 0xe0, 0x49, 0xc7, 0x83, 0xea, 0x29, 0xaf, 0x99, 0x20, 0xb2, 0x8d, 0xca, 0x9f, 0x14, + 0xd7, 0x48, 0x46, 0x50, 0x3c, 0xad, 0x55, 0xc6, 0xc2, 0x30, 0x0f, 0x14, 0x90, 0x77, 0xef, 0x4e, 0x7d, 0x6b, 0x7f, + 0xec, 0xd8, 0xb3, 0xb5, 0x0a, 0xb5, 0x50, 0x53, 0xb8, 0xe4, 0x10, 0x5d, 0x41, 0x06, 0x0a, 0x19, 0x4f, 0x5e, 0x0f, + 0x2e, 0x27, 0xd1, 0x15, 0x17, 0xe8, 0x8c, 0xaf, 0x6f, 0xba, 0xe9, 0x2c, 0x7a, 0x5a, 0xcd, 0x27, 0xa4, 0x24, 0x3b, + 0x1c, 0xb2, 0x51, 0x55, 0x17, 0xeb, 0x69, 0x28, 0x7f, 0x7a, 0x08, 0xbe, 0x5e, 0x50, 0xaf, 0xc9, 0x2a, 0xd5, 0x4f, + 0xa9, 0x52, 0x5e, 0x34, 0xbc, 0xf4, 0x9f, 0x56, 0x72, 0xdf, 0x03, 0xd2, 0x5a, 0x5e, 0x72, 0xf9, 0x7e, 0x84, 0x18, + 0x23, 0x7e, 0xe0, 0x95, 0x3c, 0x62, 0xa1, 0x9a, 0xc2, 0x35, 0x8f, 0x10, 0xe4, 0x2d, 0xd3, 0xc1, 0xdf, 0x7a, 0xe2, + 0x74, 0x7f, 0xa2, 0xb4, 0x8b, 0x2f, 0x2c, 0xea, 0x9e, 0xac, 0xad, 0x1b, 0x90, 0x83, 0x0d, 0xd3, 0x45, 0x41, 0xb6, + 0x29, 0x8d, 0xa0, 0x8d, 0x96, 0x03, 0x1b, 0x4e, 0xa5, 0x36, 0x9c, 0xb9, 0x86, 0xe0, 0x3e, 0x3f, 0x4f, 0x47, 0x0b, + 0xf8, 0x90, 0xea, 0xf6, 0x12, 0x3f, 0x1f, 0x36, 0x3c, 0x02, 0x32, 0x3b, 0xe2, 0x33, 0x9b, 0x48, 0x3a, 0xa9, 0x73, + 0x05, 0xec, 0x76, 0xf6, 0x16, 0xe4, 0x88, 0x99, 0xfb, 0x0a, 0xd5, 0xb7, 0x68, 0xc0, 0x95, 0xb1, 0xf6, 0x35, 0xc9, + 0x58, 0x78, 0x55, 0x4e, 0xc3, 0x01, 0xc0, 0xd0, 0x65, 0xf4, 0xb5, 0xe5, 0x26, 0xcb, 0x7e, 0x2e, 0x20, 0x08, 0xa2, + 0x24, 0x1e, 0x1f, 0xf0, 0xbe, 0xac, 0x86, 0x1a, 0x25, 0x1f, 0xcb, 0x46, 0x2a, 0xbd, 0x12, 0xfd, 0xdd, 0x98, 0x4b, + 0x0c, 0xf8, 0xb6, 0x6a, 0x0b, 0x0a, 0xe7, 0xf9, 0xe1, 0x70, 0x9e, 0x8f, 0x8c, 0x67, 0x19, 0xa8, 0x56, 0xa6, 0x75, + 0x10, 0x9b, 0xf9, 0x62, 0xe1, 0x2f, 0x76, 0x4e, 0x22, 0xa2, 0x20, 0xb0, 0x23, 0xe1, 0x41, 0xa4, 0x7e, 0x59, 0x79, + 0xba, 0x53, 0x7d, 0xb6, 0x5f, 0xd8, 0x44, 0x7a, 0x41, 0xc9, 0xe4, 0x93, 0x60, 0xaf, 0xfa, 0x3b, 0x08, 0x1b, 0xc2, + 0x9b, 0x57, 0xbd, 0xce, 0x32, 0x35, 0x2b, 0x41, 0xc2, 0x8c, 0x39, 0x82, 0xc7, 0x61, 0xa7, 0xb1, 0x0d, 0x8f, 0x2d, + 0x38, 0x3a, 0x6f, 0xcd, 0xee, 0xd8, 0x8a, 0xdd, 0xaa, 0x3a, 0x2d, 0x78, 0x38, 0x1d, 0x5e, 0x06, 0xb8, 0xfa, 0xd6, + 0xe7, 0x9c, 0xdf, 0xd1, 0x09, 0xb6, 0x1e, 0xf0, 0x68, 0x22, 0x66, 0xeb, 0xa7, 0x91, 0x5a, 0x3c, 0xeb, 0x21, 0x5f, + 0xd0, 0xfa, 0x13, 0xb3, 0x3b, 0x93, 0x7c, 0x37, 0xe0, 0x8b, 0xc9, 0xfa, 0x69, 0x04, 0xaf, 0x3e, 0x05, 0x2b, 0x46, + 0xe6, 0xcc, 0xb2, 0xf5, 0xd3, 0x08, 0xc7, 0xec, 0xee, 0x69, 0x44, 0xa3, 0xb6, 0x92, 0xfb, 0xd2, 0x6d, 0x03, 0xc2, + 0xca, 0x2d, 0x8b, 0xe1, 0x35, 0x10, 0xcf, 0xb4, 0x91, 0x74, 0x2d, 0x0d, 0xbd, 0x31, 0x0f, 0xa7, 0x71, 0xb0, 0xa6, + 0x56, 0xc8, 0x33, 0x43, 0xcc, 0xe2, 0xa7, 0xd1, 0x9c, 0xad, 0xb0, 0x22, 0x1b, 0x1e, 0x0f, 0x2e, 0x27, 0x9b, 0x2b, + 0xbe, 0x06, 0xf2, 0xb3, 0xc9, 0xc6, 0x6c, 0x51, 0xb7, 0x5c, 0xcc, 0x36, 0x4f, 0xa3, 0xf9, 0x64, 0x05, 0x3d, 0x6b, + 0x0f, 0x98, 0xf7, 0x1a, 0x44, 0x28, 0x09, 0xa9, 0x29, 0x37, 0xbd, 0x1e, 0x5b, 0x8f, 0x83, 0x3b, 0xb6, 0xbe, 0x0c, + 0x6e, 0xd9, 0x7a, 0x0c, 0x44, 0x1c, 0xd4, 0xef, 0xde, 0x06, 0x16, 0x5f, 0xc4, 0xd6, 0x97, 0x26, 0x6d, 0xf3, 0x34, + 0x62, 0xee, 0xe0, 0x34, 0x70, 0xc1, 0xda, 0x64, 0xde, 0x8a, 0xc1, 0x25, 0x64, 0xe9, 0xc5, 0x6c, 0x33, 0xbc, 0x64, + 0xeb, 0x11, 0x4e, 0xf5, 0xc4, 0x67, 0x77, 0xfc, 0x96, 0x25, 0x7c, 0xd5, 0xc4, 0x57, 0x1b, 0xd0, 0x88, 0x1e, 0x65, + 0xd0, 0x57, 0x50, 0x33, 0x73, 0x5e, 0x5a, 0x18, 0x95, 0xfb, 0x16, 0x1c, 0x50, 0x90, 0xb6, 0x01, 0x82, 0x24, 0x9e, + 0xdd, 0xcb, 0x70, 0x7d, 0x23, 0x85, 0x01, 0x37, 0x81, 0x19, 0x30, 0x30, 0xfd, 0x0c, 0x7e, 0x58, 0xe9, 0x12, 0x21, + 0xce, 0x7e, 0x4a, 0x49, 0x32, 0xcf, 0x4f, 0x45, 0x9a, 0xbb, 0x85, 0xeb, 0x14, 0x66, 0x45, 0x81, 0xea, 0xa7, 0xa4, + 0x34, 0xb0, 0x50, 0x89, 0x4c, 0xa5, 0xe0, 0x97, 0xcd, 0x79, 0x94, 0x1d, 0xa3, 0x73, 0x9d, 0x5f, 0x4e, 0x9c, 0xd3, + 0x49, 0xdf, 0x7f, 0xe0, 0x18, 0xb6, 0x90, 0x81, 0x0b, 0x7f, 0xea, 0x09, 0xe3, 0xd4, 0x0a, 0xc4, 0x54, 0xf2, 0xec, + 0x29, 0x7c, 0x26, 0xb4, 0x3a, 0xba, 0xf0, 0xfd, 0xa0, 0xd0, 0x26, 0xe9, 0x16, 0x24, 0x29, 0x78, 0x8a, 0x9e, 0x73, + 0xde, 0x06, 0x2a, 0xc5, 0x88, 0x16, 0x44, 0xda, 0x5a, 0x66, 0x0e, 0xd2, 0x96, 0xe6, 0xbb, 0x26, 0x7e, 0x0e, 0x0b, + 0xb8, 0x88, 0x16, 0xb6, 0x86, 0x47, 0x55, 0xac, 0xdc, 0x9b, 0x3c, 0x47, 0x38, 0xa3, 0x4b, 0x99, 0x00, 0xb8, 0xde, + 0xaf, 0xc2, 0x5a, 0xe1, 0x15, 0x35, 0x8b, 0xbc, 0xa8, 0xe9, 0x93, 0x2d, 0x70, 0x1f, 0x8b, 0x12, 0x05, 0xce, 0x5a, + 0x30, 0x60, 0x2b, 0x2c, 0xd9, 0x49, 0x61, 0x53, 0xb4, 0x84, 0xde, 0x1e, 0x3f, 0x1d, 0xd4, 0x4c, 0x06, 0xd0, 0x04, + 0xd0, 0x78, 0xfc, 0x0b, 0x40, 0x4d, 0x6f, 0x6a, 0xb1, 0xae, 0x82, 0x52, 0x29, 0x37, 0xe1, 0x67, 0x60, 0x98, 0xe1, + 0x87, 0x42, 0x6e, 0x13, 0x25, 0x72, 0x7e, 0x2c, 0x4a, 0xb1, 0x2c, 0x45, 0x95, 0xb4, 0x1b, 0x0a, 0x1e, 0x11, 0x6e, + 0x83, 0xc6, 0xcc, 0xed, 0x89, 0x2e, 0x5a, 0x11, 0xca, 0xb1, 0x59, 0xc7, 0x48, 0xa3, 0xcc, 0x4e, 0x76, 0x9d, 0x2c, + 0xb4, 0xdf, 0x57, 0x39, 0x64, 0x1d, 0xb0, 0x46, 0xf2, 0xf5, 0x9a, 0x43, 0xb7, 0x8d, 0xf2, 0xe2, 0xc1, 0xf3, 0x15, + 0x9c, 0xe6, 0x78, 0x62, 0x77, 0xbd, 0xee, 0x14, 0x89, 0x78, 0x85, 0x93, 0x2a, 0x1f, 0xc9, 0xc2, 0x71, 0xe7, 0x4e, + 0x6b, 0xb1, 0xaa, 0x5c, 0xd6, 0x53, 0x8b, 0x23, 0x02, 0x9f, 0xca, 0xa3, 0xbd, 0xd0, 0xb6, 0x28, 0x16, 0xc2, 0xe8, + 0xd1, 0x09, 0x3f, 0x29, 0x81, 0xf5, 0x75, 0x38, 0x2c, 0xfd, 0x88, 0xa3, 0xdf, 0x69, 0x34, 0x5a, 0x10, 0xd2, 0xf0, + 0xd4, 0x8b, 0x46, 0x8b, 0xba, 0xa8, 0xc3, 0xec, 0x3a, 0xd7, 0x03, 0x85, 0x61, 0x04, 0xea, 0x07, 0x57, 0x19, 0x7c, + 0x16, 0x21, 0x6a, 0x1e, 0x98, 0x66, 0x43, 0x38, 0xea, 0x02, 0x0f, 0xad, 0xa0, 0xc5, 0xcc, 0x7c, 0x14, 0x62, 0xf8, + 0x90, 0x2e, 0xce, 0x9f, 0x90, 0x95, 0x0f, 0xb0, 0x3b, 0x74, 0x17, 0xca, 0x39, 0x53, 0x31, 0xc0, 0x8f, 0x02, 0xf2, + 0x51, 0x02, 0x6e, 0x06, 0xc8, 0x1e, 0x59, 0x02, 0x88, 0x15, 0xa3, 0xa3, 0xc9, 0xe7, 0xbe, 0x17, 0x29, 0x78, 0x67, + 0x9f, 0xe5, 0x6a, 0xc2, 0x50, 0xf8, 0xc4, 0x40, 0x37, 0xbf, 0xf1, 0xdb, 0xf3, 0x16, 0x8c, 0xec, 0x92, 0x14, 0xaf, + 0x35, 0xc3, 0xfd, 0x06, 0xdc, 0x8e, 0x80, 0xb2, 0xa6, 0x3a, 0x26, 0xd9, 0xa6, 0x21, 0x92, 0x01, 0x33, 0x62, 0x44, + 0x50, 0x59, 0x2e, 0xfc, 0xef, 0x5e, 0x16, 0x05, 0x0e, 0xe0, 0x6a, 0x26, 0x83, 0xd7, 0x2e, 0x8c, 0x0a, 0x80, 0x73, + 0x1a, 0x3a, 0xa5, 0xbd, 0xaa, 0x3a, 0x24, 0xab, 0xe6, 0x07, 0xb3, 0x79, 0xd3, 0x30, 0x31, 0x22, 0x88, 0x2e, 0xc2, + 0x09, 0xa6, 0x57, 0xa4, 0xaf, 0x95, 0x9c, 0x8e, 0x56, 0x1d, 0xad, 0x25, 0x26, 0xe6, 0x8a, 0xe2, 0xaf, 0x01, 0x8f, + 0x1b, 0xbc, 0x3a, 0x49, 0xd3, 0x89, 0xea, 0xd1, 0xe3, 0xd7, 0x69, 0x3a, 0x29, 0x71, 0x57, 0xf8, 0x0d, 0xb8, 0x68, + 0xb6, 0xf9, 0xd0, 0x8f, 0x5f, 0x50, 0xc4, 0x45, 0x0d, 0xae, 0xbc, 0x53, 0x7d, 0xa5, 0xfa, 0x08, 0x6a, 0xe1, 0x89, + 0x91, 0xb5, 0xf0, 0xe4, 0x92, 0xb5, 0x16, 0x04, 0x33, 0x9b, 0x03, 0x17, 0xf2, 0x2b, 0xa5, 0x88, 0x37, 0x91, 0x50, + 0x8b, 0x41, 0xeb, 0x31, 0x73, 0x56, 0x8d, 0x16, 0x2a, 0x33, 0x42, 0xfb, 0xb6, 0x16, 0x9d, 0xdf, 0xc8, 0x4f, 0x79, + 0x6a, 0x5f, 0xb6, 0xc7, 0xf9, 0x78, 0x8f, 0xee, 0xaa, 0xb3, 0xcc, 0xa4, 0x8c, 0x4f, 0x66, 0x09, 0x0a, 0x77, 0x09, + 0x36, 0x20, 0xc9, 0x7e, 0xad, 0x03, 0x64, 0xd4, 0x5e, 0xfb, 0x5d, 0x67, 0xf9, 0xea, 0x66, 0x6b, 0x28, 0x2a, 0xb5, + 0x92, 0x14, 0x07, 0x19, 0xae, 0xdb, 0xca, 0x87, 0x8b, 0x0b, 0xe8, 0x19, 0x23, 0x91, 0x79, 0xfe, 0x44, 0xbe, 0x04, + 0xe7, 0x8c, 0xb3, 0x42, 0x60, 0xc2, 0x58, 0xbd, 0x6b, 0x2d, 0x95, 0x86, 0x14, 0x63, 0x47, 0xa3, 0x2c, 0xab, 0x2c, + 0x5d, 0x66, 0x6b, 0x09, 0x5b, 0x96, 0x93, 0x5b, 0xd8, 0x32, 0x93, 0xd5, 0x7c, 0x5f, 0x71, 0x07, 0xe5, 0x9b, 0xad, + 0x33, 0xbe, 0x97, 0xc8, 0xde, 0x6d, 0xa0, 0x84, 0xeb, 0xd1, 0x5f, 0x90, 0x7e, 0x9b, 0x61, 0x9c, 0x72, 0x5b, 0x49, + 0x0b, 0x70, 0xfa, 0x87, 0xc3, 0xfb, 0x0a, 0x83, 0x06, 0x47, 0x18, 0x47, 0xd6, 0xef, 0xdf, 0x56, 0x5e, 0x8d, 0x89, + 0x3a, 0x3e, 0xab, 0xdf, 0xaf, 0xe8, 0xe1, 0xb4, 0x1a, 0xad, 0xd2, 0x2d, 0xb2, 0x13, 0xda, 0x58, 0xf9, 0x41, 0xad, + 0x80, 0xd9, 0x5b, 0x9f, 0x4f, 0x07, 0xa0, 0x63, 0x01, 0x12, 0xcd, 0x66, 0x22, 0x31, 0x27, 0xdd, 0x93, 0xf0, 0xf8, + 0xc0, 0x02, 0x07, 0x98, 0x8a, 0xff, 0x53, 0x78, 0x33, 0xb0, 0x41, 0xa3, 0x44, 0x5f, 0xa3, 0xab, 0xda, 0xdc, 0xe8, + 0x78, 0xe9, 0x29, 0x24, 0xb2, 0x82, 0x55, 0x73, 0x5f, 0x6e, 0xe0, 0xb4, 0x87, 0x9a, 0x43, 0x65, 0x09, 0xfe, 0xf6, + 0xcb, 0xfc, 0x70, 0x58, 0x67, 0x50, 0xd8, 0x6e, 0x2d, 0xb4, 0x37, 0x66, 0xa9, 0x86, 0x8a, 0x70, 0xd0, 0xf9, 0x4a, + 0xcc, 0xea, 0x11, 0xfd, 0x3d, 0x3f, 0x1c, 0x56, 0x04, 0x06, 0x1c, 0x96, 0x32, 0x13, 0x2d, 0x14, 0x4b, 0xeb, 0x6c, + 0x46, 0x75, 0xe0, 0x81, 0x89, 0x39, 0x0b, 0x77, 0x00, 0xda, 0xa4, 0x56, 0x81, 0x5e, 0x45, 0xf4, 0x13, 0xf7, 0x6b, + 0xfb, 0xf5, 0x7a, 0x64, 0x96, 0x8e, 0xdc, 0x18, 0x0b, 0x00, 0x0e, 0x3c, 0xaf, 0x49, 0x9e, 0x93, 0xaf, 0xa1, 0xdd, + 0x93, 0x0b, 0xf9, 0x13, 0x94, 0x2d, 0x3c, 0x57, 0x4d, 0x2b, 0x8b, 0x15, 0x57, 0xd5, 0xab, 0x0b, 0x5e, 0x99, 0x4c, + 0xab, 0xb4, 0x12, 0x95, 0x12, 0x0c, 0xa8, 0x4b, 0xbc, 0xd6, 0x34, 0xa3, 0xd4, 0x46, 0x9d, 0x89, 0x1a, 0xb0, 0xc1, + 0x7e, 0xaa, 0x36, 0x3a, 0x39, 0x97, 0xcf, 0x2f, 0x8d, 0xc3, 0xa7, 0x5d, 0xbd, 0x99, 0xa9, 0x1c, 0xf8, 0x6b, 0xe5, + 0x43, 0xab, 0xc7, 0x40, 0x07, 0xe4, 0xf4, 0xc7, 0xb0, 0x98, 0xd8, 0x1d, 0x9a, 0xb7, 0xbb, 0xcb, 0xea, 0x22, 0xbd, + 0xd3, 0x94, 0xcc, 0xea, 0x2d, 0x9f, 0x59, 0x3d, 0x3a, 0xe0, 0xc5, 0x63, 0xbd, 0x57, 0x98, 0x49, 0x04, 0x17, 0x43, + 0x35, 0x89, 0xec, 0x0e, 0xb4, 0xe6, 0x51, 0xc5, 0x04, 0xf8, 0x41, 0xa9, 0x35, 0xbd, 0xb7, 0xbb, 0x42, 0x9d, 0x52, + 0x78, 0xdc, 0x5a, 0xf2, 0x03, 0x73, 0xa7, 0x5d, 0xeb, 0x7c, 0x3c, 0xbf, 0xf4, 0xfd, 0x46, 0x9e, 0xd0, 0x66, 0x67, + 0x72, 0xfa, 0x27, 0x6f, 0xf5, 0x0f, 0x53, 0x7d, 0x0b, 0xdd, 0x09, 0xfa, 0x0c, 0x5d, 0x55, 0xdd, 0x95, 0xd8, 0xc2, + 0x50, 0x4f, 0x2c, 0xf2, 0x42, 0x9e, 0xb4, 0xc6, 0x8e, 0x83, 0xbd, 0x01, 0x4e, 0xfc, 0xf2, 0x70, 0x10, 0x57, 0xb9, + 0xcf, 0xce, 0xbb, 0x46, 0x56, 0x0e, 0x60, 0x05, 0x51, 0x30, 0x6e, 0xcd, 0xc7, 0x36, 0x48, 0x97, 0xb8, 0x1a, 0x1f, + 0xbf, 0xa1, 0x58, 0x26, 0x9b, 0x88, 0x8b, 0x8b, 0xfc, 0xe9, 0x73, 0x20, 0x2d, 0xeb, 0xf7, 0xa3, 0xeb, 0xcb, 0xe9, + 0xf3, 0x61, 0x14, 0x80, 0x63, 0x97, 0xbd, 0xbc, 0x8c, 0xf9, 0xea, 0x92, 0x59, 0xa6, 0xb0, 0xc8, 0x37, 0x03, 0xaa, + 0x4b, 0x56, 0x4b, 0xd7, 0x2b, 0xc0, 0xd2, 0xe5, 0x37, 0x0f, 0x61, 0x6a, 0x40, 0x23, 0x6b, 0xee, 0x4e, 0x73, 0x2d, + 0x50, 0xea, 0x79, 0x3f, 0x33, 0xe4, 0xeb, 0x32, 0xe8, 0x0a, 0xd2, 0x3d, 0x8f, 0x48, 0x2f, 0xf7, 0xd2, 0xe9, 0x7e, + 0x5f, 0x0a, 0xb0, 0xd4, 0x97, 0xe2, 0x33, 0x28, 0x2c, 0x1a, 0xdf, 0x08, 0xd0, 0xd6, 0x50, 0x4d, 0x7b, 0xa5, 0xa8, + 0x7a, 0x41, 0xaf, 0x14, 0x9f, 0x7b, 0x7a, 0xa8, 0xcc, 0x97, 0xa5, 0xa3, 0xff, 0x09, 0x35, 0x17, 0x9c, 0x10, 0x33, + 0x31, 0x07, 0x50, 0x09, 0xda, 0xf8, 0x56, 0x47, 0x1b, 0x9f, 0xea, 0x55, 0xdc, 0xf4, 0x79, 0x6d, 0x2d, 0x73, 0x42, + 0xd8, 0x74, 0x2f, 0x01, 0x2a, 0xf2, 0x4a, 0x78, 0x04, 0xcb, 0x2f, 0x7f, 0xc8, 0xd3, 0x15, 0xa2, 0x75, 0xdc, 0xb3, + 0xcc, 0xa5, 0xb1, 0x7f, 0x6d, 0x30, 0x7d, 0x7d, 0xbb, 0x2d, 0xf2, 0x53, 0x13, 0x13, 0xd6, 0x63, 0x45, 0xdf, 0xbc, + 0x0b, 0x57, 0x02, 0x05, 0x0e, 0x25, 0x12, 0xdb, 0x54, 0xa1, 0x88, 0x07, 0x49, 0x9f, 0x2e, 0x5a, 0x9f, 0x06, 0x98, + 0x5a, 0xcb, 0x81, 0x39, 0x84, 0xab, 0xb8, 0xf0, 0xd1, 0xd3, 0xb7, 0x98, 0x85, 0xf3, 0x89, 0xf7, 0xd1, 0x2b, 0x46, + 0xe6, 0xe3, 0x3e, 0x2a, 0x95, 0xf4, 0xcf, 0xc3, 0x61, 0x56, 0xcd, 0x7d, 0x87, 0x3e, 0xd2, 0x43, 0x95, 0x0b, 0xca, + 0xde, 0x18, 0x93, 0x08, 0x94, 0xc6, 0x78, 0x1f, 0x07, 0xc7, 0x79, 0x9f, 0x06, 0x90, 0xda, 0x27, 0xde, 0x93, 0x92, + 0xc3, 0x73, 0x8e, 0x39, 0xa1, 0xb4, 0x22, 0xac, 0xe2, 0x8b, 0x0c, 0xe5, 0xba, 0x53, 0x0a, 0x26, 0x39, 0x24, 0x18, + 0xfe, 0xaa, 0x79, 0x13, 0x2b, 0x10, 0x76, 0xcd, 0xbc, 0x1a, 0x3d, 0xa9, 0x92, 0xb0, 0x14, 0x70, 0x54, 0x66, 0x9e, + 0x61, 0x6f, 0x78, 0x62, 0x18, 0x39, 0x58, 0xee, 0x8f, 0xea, 0x44, 0xe4, 0x1e, 0x5d, 0x60, 0x54, 0x16, 0x9e, 0x37, + 0x74, 0xa5, 0x41, 0x25, 0xd9, 0xf1, 0x57, 0x5c, 0x03, 0x6a, 0x6b, 0x8c, 0x18, 0x0a, 0x18, 0x05, 0xaf, 0xed, 0x0f, + 0x21, 0x8b, 0xb2, 0xf5, 0x1b, 0x1c, 0xf3, 0x59, 0xc9, 0x5d, 0xef, 0x70, 0x16, 0x5a, 0x42, 0x9e, 0xdc, 0x31, 0x48, + 0xd3, 0x58, 0x1a, 0x01, 0x27, 0x22, 0xd9, 0xc6, 0x52, 0x38, 0x02, 0x08, 0x08, 0x74, 0x53, 0x66, 0x18, 0xd3, 0xc1, + 0xc8, 0xf3, 0xa4, 0x67, 0xbc, 0x57, 0xe1, 0x29, 0xa4, 0xc9, 0xf6, 0xf5, 0xfc, 0xbd, 0x11, 0x64, 0xe5, 0x96, 0x73, + 0x3c, 0x2c, 0xbe, 0x71, 0xf6, 0x55, 0x4e, 0x9e, 0x62, 0x96, 0x91, 0xde, 0x29, 0xe6, 0x05, 0xfc, 0xa9, 0x2c, 0xf5, + 0x39, 0x4a, 0x6f, 0x99, 0x4f, 0x56, 0x91, 0x74, 0xe9, 0x6d, 0xfa, 0xfd, 0x78, 0xa4, 0x0e, 0x35, 0x7f, 0x1f, 0x8f, + 0xe4, 0x19, 0xb6, 0x61, 0x09, 0x0b, 0xad, 0x82, 0x31, 0x80, 0x24, 0x36, 0x22, 0x1a, 0x8c, 0xf6, 0xe6, 0x70, 0x38, + 0xdf, 0x98, 0xb3, 0x64, 0x0f, 0xae, 0xaf, 0x3c, 0x31, 0xef, 0xc0, 0x97, 0x79, 0x4c, 0x10, 0xb1, 0x99, 0xb7, 0x61, + 0x35, 0x78, 0xb0, 0x83, 0xeb, 0x23, 0xb6, 0x28, 0xd6, 0x3a, 0x96, 0xca, 0x3a, 0x38, 0xad, 0x63, 0xd3, 0x8c, 0x94, + 0x22, 0xfb, 0x1c, 0xfb, 0x7b, 0x37, 0xb8, 0xba, 0x36, 0x06, 0xb5, 0xc6, 0x1d, 0xe6, 0xce, 0xa9, 0x80, 0x7a, 0x4c, + 0x57, 0x50, 0x3d, 0xcb, 0xc9, 0x97, 0xdf, 0xda, 0x39, 0x20, 0x68, 0x04, 0x02, 0x17, 0x0d, 0xb4, 0x6a, 0x97, 0x72, + 0xde, 0x05, 0x84, 0xf8, 0x26, 0x05, 0x7d, 0x3a, 0x83, 0x4d, 0x6c, 0x3e, 0x81, 0x58, 0x34, 0xdd, 0xe7, 0x5a, 0x33, + 0x5f, 0x8c, 0x68, 0x67, 0xd6, 0xdd, 0x22, 0xb7, 0x5a, 0x88, 0x64, 0xf4, 0x6c, 0x33, 0xe1, 0xa2, 0x43, 0x39, 0x23, + 0x01, 0x13, 0xb4, 0xb6, 0x52, 0xf2, 0xb9, 0xee, 0x75, 0x82, 0xf6, 0x40, 0xd2, 0xba, 0x7f, 0xb3, 0xe8, 0x8c, 0x92, + 0x93, 0xeb, 0x4d, 0xce, 0x20, 0x05, 0x0b, 0xb6, 0x97, 0x39, 0xe1, 0x06, 0xf8, 0xc4, 0x66, 0xc9, 0x69, 0x1a, 0xe4, + 0xb1, 0x30, 0x1e, 0x79, 0x6d, 0x7e, 0x59, 0x40, 0x87, 0x92, 0x45, 0x23, 0xc4, 0x03, 0xec, 0x1c, 0x92, 0xab, 0x02, + 0x75, 0xd3, 0x40, 0x57, 0xae, 0x9c, 0x29, 0xa6, 0xc0, 0x85, 0x50, 0x10, 0xb5, 0xa3, 0x93, 0xa8, 0x9c, 0xf7, 0x49, + 0x75, 0x99, 0x4f, 0x0b, 0x69, 0x1a, 0xc8, 0xa7, 0x95, 0x63, 0x1e, 0xd8, 0xd9, 0xc6, 0x35, 0x81, 0x81, 0x4e, 0xed, + 0x6b, 0x51, 0xce, 0xb1, 0x8a, 0xe8, 0x7d, 0xfe, 0xa1, 0xb2, 0xa7, 0x0f, 0x22, 0x6c, 0x54, 0xa0, 0xb1, 0x94, 0x18, + 0x1b, 0x39, 0xfe, 0x2d, 0x51, 0x36, 0x64, 0x08, 0x08, 0x21, 0x6d, 0xe4, 0xf4, 0xc3, 0xfa, 0xf2, 0x36, 0xd3, 0xfe, + 0x9f, 0x24, 0x7e, 0x1b, 0xec, 0xe5, 0xd4, 0x9f, 0x7a, 0xc4, 0xe3, 0xb5, 0x46, 0x8f, 0x29, 0xe9, 0x36, 0xc8, 0x53, + 0xe5, 0x29, 0x48, 0x26, 0x8c, 0x25, 0x04, 0x8b, 0x72, 0xc1, 0x73, 0x5e, 0x71, 0x09, 0xf7, 0x51, 0xcb, 0x8a, 0x08, + 0x55, 0x89, 0x9c, 0x3e, 0x5f, 0x01, 0xcf, 0x04, 0x04, 0x3a, 0xc6, 0x48, 0xa3, 0x0a, 0xbe, 0x04, 0xc6, 0x3a, 0x50, + 0x76, 0x9a, 0x91, 0xe0, 0xb2, 0x7b, 0x83, 0x44, 0xa9, 0xaf, 0x48, 0x49, 0xfa, 0x56, 0xd4, 0x78, 0x25, 0x56, 0x11, + 0x09, 0x64, 0xa8, 0x21, 0x62, 0x55, 0x3d, 0x75, 0xaf, 0x8a, 0xc9, 0x60, 0x50, 0xf9, 0x72, 0x7a, 0xe2, 0x0d, 0x0d, + 0x95, 0x77, 0x5d, 0xd1, 0x4e, 0x4f, 0xb4, 0x52, 0xde, 0x42, 0x5a, 0x82, 0xa6, 0x61, 0xa4, 0x39, 0x94, 0xba, 0x92, + 0xee, 0xc6, 0x20, 0xbe, 0x64, 0xa2, 0x67, 0x3b, 0xb5, 0xa3, 0xb4, 0x25, 0xed, 0x21, 0xa4, 0xe7, 0x2e, 0xf9, 0x98, + 0x85, 0x5c, 0xdd, 0x29, 0x27, 0xe5, 0x55, 0x88, 0x4e, 0xee, 0x7b, 0x0c, 0x89, 0x40, 0x9f, 0x73, 0x0c, 0xeb, 0xa2, + 0xa1, 0xce, 0x61, 0x85, 0x98, 0x2d, 0x94, 0x30, 0x5f, 0x32, 0x9e, 0x4a, 0x06, 0x0d, 0x80, 0x0c, 0xf8, 0xec, 0x65, + 0x60, 0xf9, 0x2b, 0x88, 0x1f, 0x6d, 0x7c, 0x38, 0xfc, 0x59, 0x53, 0x88, 0xed, 0x9f, 0xb0, 0x19, 0xc2, 0xa3, 0x7a, + 0xc0, 0x33, 0xdf, 0xc4, 0x09, 0x5a, 0x01, 0x49, 0x99, 0x1d, 0x4d, 0x64, 0xaf, 0x7a, 0x08, 0xa7, 0xb2, 0x02, 0x75, + 0x94, 0x75, 0x56, 0xc2, 0x8f, 0x30, 0xd5, 0xad, 0xc4, 0x5a, 0xa0, 0xcd, 0xd5, 0x8a, 0xb5, 0x00, 0x0e, 0xfc, 0x1c, + 0x82, 0x27, 0xf2, 0x39, 0xb8, 0x18, 0x14, 0xe0, 0x73, 0x00, 0xbc, 0xc8, 0x5d, 0x78, 0x30, 0x8f, 0x2c, 0xab, 0x11, + 0x86, 0xa3, 0x8a, 0x58, 0xbf, 0x66, 0x3b, 0xf2, 0x81, 0xdb, 0x31, 0x3e, 0xd7, 0x1e, 0x4b, 0x96, 0x83, 0x51, 0xe6, + 0x5e, 0x2d, 0xd1, 0xf3, 0x26, 0x8d, 0x9b, 0xd1, 0x93, 0x7d, 0x2d, 0xff, 0x17, 0xf4, 0x32, 0xe8, 0x6f, 0xe1, 0x96, + 0xd7, 0xfc, 0x6e, 0x41, 0xa4, 0x99, 0x5e, 0x41, 0xa4, 0x8c, 0x1a, 0x91, 0x31, 0x84, 0x4d, 0xaa, 0x9b, 0xdb, 0xa4, + 0xba, 0x10, 0xf0, 0x74, 0x44, 0xaa, 0x6b, 0x21, 0x6d, 0xe4, 0xd3, 0x3a, 0x90, 0xb1, 0x48, 0xef, 0x7e, 0xf8, 0xdb, + 0x8b, 0x4f, 0x6f, 0x7e, 0xf9, 0x61, 0xf1, 0xe6, 0xdd, 0xeb, 0x37, 0xef, 0xde, 0x7c, 0xfa, 0x8d, 0x20, 0x3c, 0xa6, + 0x42, 0x65, 0xf8, 0xf0, 0xfe, 0xe6, 0x8d, 0x93, 0xc1, 0xf6, 0x66, 0xc8, 0xda, 0x37, 0x72, 0x30, 0x04, 0x22, 0x1b, + 0x84, 0x0c, 0xb2, 0x53, 0xdb, 0xfe, 0x4c, 0xcc, 0x31, 0xf6, 0x4e, 0x60, 0xb2, 0x05, 0x9c, 0x63, 0x99, 0x97, 0x8c, + 0xc8, 0x55, 0xa1, 0xf5, 0x03, 0x5a, 0xf0, 0x16, 0x5c, 0x64, 0xd2, 0xfc, 0xee, 0x17, 0x82, 0xd8, 0xa7, 0x95, 0x94, + 0xfb, 0x6a, 0x5b, 0xf3, 0x7c, 0x7b, 0xbf, 0x97, 0x70, 0xfe, 0x73, 0x69, 0x44, 0x2d, 0xc0, 0x01, 0xf8, 0x1c, 0xfe, + 0xb8, 0xd2, 0x96, 0x34, 0x99, 0x45, 0xfb, 0x19, 0x43, 0xd0, 0xa5, 0xc1, 0x07, 0xb1, 0x47, 0x5e, 0xea, 0x93, 0x85, + 0x04, 0xee, 0x88, 0xe1, 0xd3, 0x8a, 0xa0, 0x57, 0x8c, 0x28, 0x2e, 0xb9, 0x42, 0xa5, 0x94, 0xfc, 0x1b, 0x65, 0x17, + 0x15, 0x72, 0x56, 0xb0, 0x7b, 0x45, 0x8e, 0x8c, 0x1f, 0x04, 0x13, 0x5f, 0x0e, 0xee, 0xbf, 0xc4, 0x3b, 0x9c, 0x29, + 0x8e, 0xe4, 0x84, 0x3f, 0x64, 0x18, 0xd8, 0x9f, 0x83, 0xcf, 0xab, 0xc3, 0xbc, 0xbc, 0xd1, 0xa7, 0xdc, 0x92, 0x8f, + 0x27, 0xcb, 0x2b, 0x30, 0xd8, 0x2f, 0x55, 0x73, 0xd7, 0xbc, 0x9e, 0x2d, 0xe7, 0x6c, 0x3f, 0x8b, 0xe6, 0xc1, 0x1d, + 0x9b, 0x65, 0xf3, 0x60, 0xd5, 0xf0, 0x35, 0xbb, 0xe5, 0x6b, 0xab, 0x6a, 0x6b, 0xbb, 0x6a, 0x93, 0x0d, 0xbf, 0x05, + 0x09, 0xe1, 0x26, 0xf3, 0x80, 0xf7, 0xf8, 0xce, 0x67, 0x1b, 0x90, 0x68, 0x57, 0x6c, 0x03, 0x17, 0xb1, 0x35, 0xff, + 0xa1, 0xf2, 0x36, 0xac, 0x64, 0xe7, 0x63, 0x96, 0xe3, 0xfc, 0xf3, 0xe1, 0x01, 0xed, 0x85, 0xfa, 0xd9, 0xa5, 0x7a, + 0x36, 0x51, 0x76, 0xb3, 0xcd, 0x68, 0x71, 0x9f, 0x56, 0x9b, 0x30, 0x43, 0xcf, 0x72, 0xf8, 0x68, 0x2b, 0x05, 0x3f, + 0xbd, 0xc0, 0x2f, 0xd9, 0x51, 0x5b, 0x69, 0xdb, 0xae, 0x4a, 0x6c, 0x05, 0x2d, 0x8a, 0xac, 0x56, 0x78, 0x60, 0xce, + 0xaf, 0x61, 0x01, 0x63, 0xcf, 0x71, 0xce, 0x6b, 0x7f, 0x84, 0x8c, 0xf7, 0x0e, 0x00, 0x5a, 0xe6, 0x38, 0xc0, 0x23, + 0x56, 0x8c, 0xa2, 0xc1, 0x3b, 0xbf, 0x54, 0x56, 0x2b, 0xcd, 0x49, 0x68, 0x1b, 0xb1, 0x6a, 0x39, 0x52, 0x35, 0x23, + 0xd2, 0x07, 0xe9, 0x79, 0xdf, 0x23, 0xaa, 0xc1, 0x9e, 0xcc, 0xeb, 0xc0, 0x3e, 0xbd, 0x6c, 0xad, 0xea, 0xce, 0xef, + 0xa9, 0xd2, 0x25, 0x47, 0xb6, 0xfc, 0x74, 0x19, 0x3e, 0xa8, 0x3f, 0x25, 0xd7, 0x87, 0x02, 0x47, 0x78, 0xac, 0x02, + 0xce, 0xd7, 0x2b, 0xd1, 0xee, 0x44, 0xd8, 0x95, 0x4b, 0x40, 0x88, 0x2f, 0x69, 0x9a, 0xe3, 0x71, 0x44, 0x13, 0x11, + 0x36, 0x31, 0xfa, 0x0b, 0xbb, 0x0f, 0x25, 0x96, 0xf3, 0x5c, 0x83, 0x92, 0x4b, 0x06, 0xef, 0x49, 0x7b, 0x0d, 0x9a, + 0xe5, 0x55, 0xa9, 0xc9, 0x44, 0x0e, 0xca, 0x87, 0x43, 0x01, 0x7b, 0xa9, 0xf1, 0xd3, 0x84, 0x9f, 0xb0, 0xbc, 0xb5, + 0xb7, 0xa6, 0x14, 0x95, 0x34, 0x40, 0x05, 0x3e, 0x66, 0xf0, 0xbf, 0x3b, 0x43, 0x2c, 0x98, 0xa2, 0xe3, 0x87, 0x33, + 0x31, 0xb7, 0x9e, 0x5b, 0x65, 0x1d, 0x65, 0x6b, 0x94, 0x13, 0xf0, 0x6f, 0xa9, 0x8e, 0x93, 0x44, 0x38, 0xf5, 0x1e, + 0x71, 0x51, 0xf7, 0x72, 0x88, 0xba, 0x61, 0x6f, 0x2a, 0x1d, 0x6c, 0x39, 0x4d, 0x83, 0x23, 0xf1, 0x2b, 0xf5, 0xd9, + 0xfb, 0xcc, 0xe2, 0x51, 0x47, 0x36, 0xa2, 0x24, 0x8d, 0x63, 0x91, 0xc3, 0xf6, 0xbe, 0x90, 0xfb, 0x7f, 0xbf, 0x0f, + 0xe1, 0xa4, 0x55, 0x90, 0x94, 0x9e, 0x40, 0x44, 0x38, 0x3a, 0xfc, 0x88, 0xf0, 0x44, 0xaa, 0x0a, 0x9f, 0xd4, 0x27, + 0x6e, 0xcc, 0xee, 0x85, 0x39, 0xaa, 0xb7, 0x00, 0xc3, 0x58, 0x6f, 0x2d, 0x42, 0x12, 0xad, 0x34, 0xa3, 0xad, 0x07, + 0xc4, 0x88, 0xf7, 0x6b, 0x8b, 0x0c, 0xc6, 0xda, 0x92, 0x48, 0x00, 0xbf, 0x23, 0x21, 0x43, 0xdb, 0x46, 0x60, 0xc6, + 0xf0, 0x76, 0x56, 0x5c, 0xba, 0x0e, 0xdb, 0x9c, 0xc3, 0x17, 0xb2, 0xd0, 0xac, 0x23, 0x4a, 0x13, 0x84, 0xfc, 0x03, + 0x4e, 0x16, 0x0a, 0xa3, 0x79, 0x75, 0x94, 0x4e, 0x12, 0xeb, 0xfb, 0xae, 0x52, 0xc1, 0x66, 0x73, 0x83, 0xfa, 0xb2, + 0xa3, 0xe4, 0x97, 0xe0, 0xa4, 0xe3, 0x24, 0x8b, 0x1c, 0x44, 0x2d, 0x2a, 0xe7, 0x26, 0x09, 0x4b, 0xbb, 0x3a, 0xd5, + 0x66, 0xbd, 0x2e, 0xca, 0xba, 0x7a, 0x25, 0x22, 0x45, 0xef, 0xa3, 0x1e, 0x3d, 0x91, 0x90, 0x0a, 0xad, 0x4a, 0xed, + 0xf2, 0x08, 0xdc, 0x36, 0xb5, 0x62, 0x5b, 0x2e, 0x61, 0x89, 0x1a, 0xff, 0x09, 0xfa, 0x28, 0x17, 0x0f, 0x32, 0x40, + 0xa3, 0xe3, 0xa9, 0x79, 0xeb, 0x91, 0x57, 0x8e, 0xf2, 0x4b, 0xab, 0x4d, 0xfa, 0x05, 0x90, 0x19, 0xed, 0x1f, 0x2d, + 0x25, 0x90, 0x19, 0x98, 0x49, 0x4b, 0x43, 0x22, 0x47, 0x31, 0x4b, 0xf3, 0x3f, 0x70, 0xc5, 0x56, 0x88, 0x34, 0xac, + 0xe6, 0x1e, 0x7f, 0x51, 0x79, 0xb5, 0x5c, 0xcb, 0x4c, 0x73, 0xb3, 0xc4, 0xb1, 0x62, 0x71, 0x51, 0xaf, 0x2b, 0x91, + 0x05, 0x42, 0x1c, 0x61, 0x1a, 0xeb, 0xa9, 0x37, 0x4a, 0xab, 0x0f, 0x48, 0x28, 0xf3, 0x03, 0xf6, 0x76, 0xec, 0xf5, + 0x20, 0x0b, 0x71, 0x6c, 0x39, 0xd8, 0x6c, 0xbd, 0x4f, 0x65, 0x2a, 0xe2, 0xb3, 0xba, 0x38, 0xdb, 0x54, 0xe2, 0xac, + 0x4e, 0xc4, 0xd9, 0x77, 0x90, 0xf3, 0xbb, 0x33, 0x2a, 0xfa, 0xec, 0x21, 0xad, 0x93, 0x62, 0x53, 0xd3, 0x93, 0xd7, + 0x58, 0xc6, 0x77, 0x67, 0xc4, 0x55, 0x73, 0x46, 0x23, 0x19, 0x8f, 0xce, 0x3e, 0x64, 0x40, 0xf2, 0x7a, 0x96, 0xae, + 0x60, 0xf0, 0xce, 0xc2, 0x3c, 0x3e, 0x2b, 0xc5, 0x1d, 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x2a, 0xfc, 0x43, + 0x9c, 0x01, 0xb4, 0xeb, 0x59, 0x5a, 0x9f, 0xa5, 0xd5, 0x59, 0x5e, 0xd4, 0x67, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, + 0x4f, 0x5f, 0xd9, 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x2a, 0xe1, 0xb5, 0xfb, + 0xdb, 0xe6, 0xfe, 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, 0x46, 0x74, 0x41, 0x3d, 0x5e, 0x49, 0x4a, 0x05, 0x05, 0x04, + 0x4e, 0x34, 0x6b, 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, 0x5b, 0xb2, 0xb5, 0xcf, 0xaf, 0x63, 0x19, 0xa6, 0xbd, 0x09, + 0xf0, 0xaf, 0xb2, 0x37, 0x5d, 0x07, 0x4b, 0xbc, 0x6f, 0x21, 0xdb, 0xd0, 0x9b, 0x57, 0xfc, 0x85, 0x97, 0xab, 0xbf, + 0xd9, 0x3f, 0x01, 0x08, 0x03, 0x62, 0x56, 0x7d, 0x34, 0x71, 0xef, 0xac, 0x2c, 0x3b, 0x27, 0xcb, 0xae, 0x87, 0x7e, + 0x4d, 0x62, 0x54, 0x5a, 0x59, 0x4a, 0x27, 0x4b, 0x09, 0x59, 0xc0, 0x27, 0x46, 0x53, 0x1b, 0x01, 0x84, 0xed, 0x28, + 0x95, 0x2f, 0x54, 0x5e, 0x44, 0xe1, 0x9c, 0xe0, 0x79, 0x22, 0x46, 0xf7, 0x56, 0x32, 0x60, 0x38, 0x84, 0x60, 0x0e, + 0xda, 0x62, 0x6f, 0xe8, 0x26, 0xe2, 0xaf, 0xd7, 0x45, 0xf9, 0x26, 0x26, 0x9f, 0x82, 0xdd, 0xc9, 0xc7, 0x25, 0x3c, + 0x2e, 0x4f, 0x3e, 0x0e, 0xd1, 0x23, 0xe1, 0xe4, 0x63, 0xf0, 0x3d, 0x92, 0xf3, 0xba, 0xeb, 0x71, 0x82, 0xdc, 0x42, + 0xba, 0xbf, 0x1d, 0x93, 0x00, 0xcd, 0x6b, 0x58, 0x8e, 0x9a, 0x8a, 0x6b, 0x66, 0xc6, 0x78, 0xde, 0xe8, 0xfd, 0xb1, + 0xe3, 0x2d, 0x53, 0x28, 0x66, 0x31, 0xaf, 0xe1, 0xf7, 0xac, 0x0a, 0xd4, 0x5d, 0x6f, 0x93, 0xdc, 0x32, 0xab, 0xe7, + 0x68, 0xf7, 0x7d, 0x5f, 0x27, 0x82, 0xda, 0xdf, 0x61, 0xcf, 0x33, 0xeb, 0x5d, 0x15, 0x03, 0x97, 0x2a, 0xd9, 0x21, + 0x53, 0xd5, 0xf4, 0x40, 0xa5, 0x34, 0x78, 0x7a, 0x69, 0x5d, 0xbe, 0x54, 0xda, 0xc8, 0x33, 0xcd, 0x6f, 0x00, 0x2f, + 0xa6, 0x2e, 0x8b, 0xdd, 0x57, 0xf7, 0x15, 0xdc, 0xc6, 0xfb, 0xfd, 0x65, 0xe5, 0x99, 0x9f, 0xb8, 0x00, 0xec, 0x4d, + 0x85, 0xd6, 0x09, 0x94, 0x1a, 0xd6, 0xe1, 0xcb, 0x44, 0x44, 0x7f, 0xb4, 0xcb, 0x75, 0xe6, 0x3a, 0x60, 0x44, 0x11, + 0xbf, 0x8d, 0x47, 0x7f, 0x80, 0xe2, 0xda, 0xd8, 0x03, 0xc2, 0x3a, 0x24, 0xf4, 0x19, 0x01, 0x48, 0x3d, 0xe6, 0x28, + 0x01, 0xcd, 0x8a, 0xe6, 0x8e, 0xc9, 0xcf, 0xf5, 0x95, 0xd2, 0xdf, 0x2f, 0x2b, 0x8f, 0xcc, 0x29, 0x6d, 0x33, 0x8d, + 0xd5, 0x9a, 0x4a, 0x20, 0xbc, 0xa2, 0x92, 0x55, 0xf8, 0x6c, 0xde, 0x88, 0x7e, 0x5f, 0x1e, 0xe1, 0x69, 0xf5, 0xc3, + 0x16, 0xe3, 0x5b, 0x01, 0xd1, 0x48, 0x00, 0xf4, 0x13, 0xc0, 0xbc, 0xc8, 0x66, 0x76, 0x1f, 0x07, 0x54, 0x29, 0xd1, + 0x34, 0xce, 0xe6, 0xf9, 0x2d, 0xbd, 0x29, 0x3b, 0xe8, 0xd4, 0xa9, 0x02, 0x17, 0x5c, 0x95, 0x8c, 0x57, 0xd6, 0x13, + 0xf9, 0xfc, 0xe6, 0x76, 0x93, 0x66, 0xf1, 0xfb, 0xf2, 0x9f, 0x38, 0xb6, 0xba, 0x0e, 0x8f, 0x4c, 0x9d, 0xae, 0x9d, + 0x47, 0x5a, 0x7b, 0x21, 0x20, 0xa2, 0x5d, 0x43, 0xad, 0x17, 0x16, 0x7a, 0xa4, 0x27, 0xc2, 0x39, 0x49, 0xd4, 0xb4, + 0x03, 0x2d, 0x8d, 0xd0, 0xd7, 0xd7, 0x9c, 0xfe, 0xc2, 0x60, 0xed, 0xf3, 0x31, 0x03, 0xb2, 0x12, 0xfd, 0x58, 0x3d, + 0x34, 0x36, 0x73, 0xe8, 0x59, 0xab, 0xf2, 0xcc, 0xab, 0x0e, 0x07, 0xc4, 0x87, 0xd1, 0x5f, 0xf2, 0xfb, 0xfd, 0x57, + 0x34, 0xff, 0x98, 0x50, 0xe3, 0x67, 0x9b, 0x01, 0xba, 0xf6, 0x5d, 0x79, 0x20, 0xea, 0xb9, 0x56, 0x09, 0x42, 0xbc, + 0x41, 0x4c, 0x34, 0x23, 0xe6, 0xe0, 0xb4, 0x43, 0xcd, 0x3f, 0x49, 0x0d, 0x08, 0x51, 0xe2, 0x75, 0x4c, 0x59, 0x90, + 0xd3, 0x26, 0x8e, 0xf4, 0xa3, 0x70, 0x22, 0x3f, 0x8a, 0xaa, 0xc8, 0xee, 0xe1, 0x82, 0xc1, 0xd4, 0x7b, 0xda, 0x2f, + 0xd1, 0x6f, 0x09, 0x47, 0xce, 0xd1, 0xaa, 0x10, 0x44, 0x4e, 0x08, 0x6b, 0x0d, 0x61, 0x82, 0xd8, 0x20, 0x5e, 0xf6, + 0x5d, 0x92, 0xe1, 0x48, 0xc1, 0x65, 0x1d, 0x3b, 0xc6, 0x5c, 0x1d, 0x55, 0xaf, 0x01, 0x8c, 0x57, 0x8e, 0xa0, 0xd9, + 0x28, 0xb2, 0x4b, 0x88, 0x2a, 0x72, 0x3c, 0x01, 0xb5, 0x83, 0xd2, 0xd8, 0x4c, 0xcf, 0xc7, 0x41, 0x3e, 0x5a, 0x54, + 0xa8, 0x73, 0x62, 0x19, 0xaf, 0x01, 0x58, 0x3b, 0x57, 0xfd, 0x3c, 0xab, 0xc1, 0x93, 0x86, 0xf8, 0x7c, 0x8c, 0xb6, + 0x57, 0x36, 0x07, 0xd5, 0x76, 0x3a, 0x2b, 0xaf, 0x98, 0x2e, 0x07, 0xc6, 0x7d, 0xc3, 0x2b, 0x8a, 0x33, 0xfc, 0xe8, + 0xc1, 0x16, 0xe7, 0x4f, 0x37, 0xd4, 0x7e, 0xcc, 0x8d, 0x7a, 0x18, 0x68, 0x2d, 0x78, 0x53, 0x10, 0xeb, 0xef, 0x87, + 0x8e, 0x6c, 0xef, 0xb5, 0xc8, 0x68, 0xf2, 0xd9, 0xcf, 0x3f, 0x94, 0xe9, 0x2a, 0x85, 0xfb, 0x92, 0x93, 0x45, 0x33, + 0x0f, 0x81, 0xbd, 0x21, 0x86, 0xeb, 0xa3, 0xc2, 0x23, 0xca, 0xfa, 0x7d, 0xf8, 0x7d, 0x95, 0x81, 0x29, 0x06, 0xae, + 0x2b, 0x04, 0xe3, 0x21, 0x10, 0xc4, 0xc3, 0x34, 0x3a, 0x19, 0xd4, 0xa0, 0x0d, 0xdf, 0x00, 0x64, 0x06, 0x78, 0x64, + 0x2e, 0x3d, 0x02, 0xee, 0x02, 0xd7, 0x9e, 0x8c, 0xc7, 0xfe, 0xc4, 0x34, 0x34, 0x6a, 0x4a, 0x33, 0x3d, 0x37, 0x7e, + 0xd3, 0x51, 0x2d, 0xd7, 0xce, 0x7f, 0x7c, 0xc9, 0x6f, 0xd0, 0x0b, 0x5a, 0x5e, 0xee, 0x23, 0x75, 0xb9, 0xcf, 0x28, + 0x2e, 0x13, 0xc9, 0x61, 0x41, 0x2c, 0x4b, 0x38, 0xf0, 0x18, 0x95, 0x2c, 0xb6, 0xf4, 0x58, 0x15, 0x2d, 0x5f, 0x94, + 0x1b, 0xa4, 0x43, 0x27, 0x04, 0x4b, 0x54, 0x10, 0x2c, 0x81, 0x71, 0x11, 0x6b, 0xbe, 0x19, 0xe4, 0x2c, 0x9e, 0x6d, + 0xe6, 0x1c, 0x09, 0xeb, 0x92, 0xc3, 0xa1, 0x90, 0x60, 0x33, 0xd9, 0x6c, 0x3d, 0x67, 0x6b, 0x9f, 0x81, 0x12, 0xa0, + 0x94, 0x69, 0x82, 0xd2, 0xb4, 0x62, 0x2b, 0x6e, 0x5a, 0x83, 0xd5, 0x6a, 0xca, 0x56, 0x35, 0x65, 0xe7, 0x34, 0xe5, + 0xa8, 0x82, 0x92, 0x13, 0x4a, 0x51, 0x86, 0x01, 0x8c, 0xd8, 0x24, 0xba, 0xca, 0xd0, 0xc7, 0x3b, 0xe1, 0x11, 0x54, + 0x11, 0x91, 0x4f, 0x18, 0x42, 0x60, 0x22, 0x8a, 0x0b, 0x55, 0x28, 0x06, 0xc8, 0x88, 0x04, 0x82, 0x89, 0x4a, 0x9d, + 0x02, 0xf3, 0xd1, 0x54, 0x31, 0x6c, 0xda, 0x13, 0xe5, 0x5b, 0xea, 0xb8, 0x47, 0xd9, 0xe6, 0xef, 0x62, 0x17, 0x84, + 0xc8, 0xdd, 0xb8, 0x53, 0x3f, 0x23, 0xde, 0xdb, 0x1d, 0x61, 0xfc, 0x64, 0xc7, 0x2d, 0xc2, 0x15, 0xc1, 0x96, 0x6a, + 0x0e, 0xb1, 0x98, 0x57, 0x93, 0x04, 0xb5, 0x2c, 0x89, 0xbf, 0xe1, 0xc9, 0x20, 0x67, 0x4b, 0xf0, 0xa0, 0x9d, 0xb3, + 0x0c, 0xf0, 0x57, 0xac, 0x16, 0xfd, 0x56, 0x7b, 0x4b, 0x90, 0x9f, 0x36, 0x76, 0xa3, 0x30, 0x31, 0x82, 0x44, 0xdd, + 0xae, 0x0c, 0xe4, 0x87, 0x0f, 0x38, 0x1d, 0x8f, 0x3d, 0x65, 0xcc, 0xad, 0x4c, 0x2f, 0xd3, 0xb9, 0x92, 0x6f, 0xe4, + 0x5e, 0xfa, 0xd8, 0x4b, 0xb0, 0x73, 0xc0, 0x1b, 0x48, 0x1b, 0x78, 0x03, 0xdb, 0x85, 0xd7, 0x06, 0x09, 0x33, 0x02, + 0x6c, 0x71, 0x7c, 0x8c, 0x94, 0xc0, 0x10, 0x8e, 0xb3, 0x14, 0x80, 0x69, 0xf4, 0x65, 0xb6, 0xb2, 0x2f, 0xb3, 0x5a, + 0xb3, 0xa5, 0x72, 0xba, 0x77, 0x6e, 0xdd, 0xce, 0x27, 0x12, 0x00, 0x4c, 0xea, 0x1c, 0x88, 0x33, 0x13, 0xec, 0xd2, + 0x24, 0xb2, 0x7c, 0x0c, 0xf3, 0x3b, 0xf1, 0xba, 0x2c, 0x56, 0xaa, 0x2b, 0xda, 0x3e, 0x33, 0xf9, 0x8c, 0x74, 0x12, + 0x2a, 0xa0, 0xa0, 0x90, 0x6b, 0x7d, 0xfa, 0x2e, 0x7c, 0x17, 0x14, 0x1a, 0x98, 0xad, 0xc2, 0x3d, 0x4d, 0xd6, 0x48, + 0xbd, 0x51, 0xf5, 0xfb, 0xe4, 0x1a, 0x48, 0x75, 0xe6, 0xd0, 0xb2, 0x27, 0x15, 0x06, 0x88, 0x1d, 0xf5, 0x19, 0x09, + 0x75, 0x20, 0xf5, 0x80, 0x21, 0x44, 0xdb, 0xf4, 0xf1, 0x27, 0x43, 0xa2, 0x0b, 0xb0, 0x85, 0x68, 0x03, 0x3f, 0xfe, + 0x04, 0xfb, 0x2c, 0x08, 0x8f, 0x69, 0xfe, 0x16, 0x92, 0x8e, 0x0d, 0x9c, 0x56, 0x9f, 0x82, 0x0f, 0x92, 0x1c, 0x4c, + 0xd4, 0xc1, 0xcb, 0xfd, 0xa5, 0xdf, 0x87, 0x2d, 0x3b, 0x97, 0x52, 0x1d, 0x2b, 0xf5, 0xb6, 0xad, 0xfd, 0x20, 0xda, + 0x82, 0x23, 0x8b, 0xf8, 0xfb, 0x0c, 0x11, 0xc1, 0xcc, 0x20, 0xc2, 0xae, 0x85, 0xba, 0xdb, 0x53, 0x6a, 0x59, 0xd4, + 0xdb, 0x9e, 0x52, 0xea, 0x36, 0x0c, 0xdf, 0x4d, 0x30, 0x53, 0xdc, 0xf0, 0x3f, 0x32, 0x2f, 0xd4, 0x1b, 0x8f, 0x45, + 0x81, 0xee, 0xf9, 0xfb, 0x25, 0xaf, 0x66, 0x1b, 0x65, 0xc2, 0xbc, 0xe3, 0xcb, 0x59, 0x28, 0xbb, 0x5a, 0x1a, 0x77, + 0x3e, 0x7b, 0x4b, 0x35, 0x1f, 0xfc, 0xc3, 0x21, 0x81, 0x78, 0xa3, 0xf8, 0xea, 0xae, 0x91, 0x5b, 0xd7, 0x64, 0x73, + 0x55, 0x02, 0xea, 0xf7, 0xf9, 0x1a, 0xf7, 0x5b, 0xac, 0x7f, 0xf7, 0x34, 0xc8, 0x58, 0xcd, 0x70, 0xc5, 0x14, 0x3e, + 0x05, 0x80, 0xc1, 0xe1, 0x54, 0x90, 0x16, 0x78, 0xc3, 0xcb, 0xe1, 0xe5, 0x64, 0x43, 0x26, 0xdd, 0x8d, 0x8f, 0xdc, + 0x59, 0xa0, 0xea, 0xfd, 0x86, 0xe2, 0xa4, 0x41, 0xa2, 0xb1, 0xd7, 0xe0, 0x8b, 0x2c, 0xa3, 0x5c, 0x34, 0x71, 0x1f, + 0x93, 0xaf, 0xf4, 0x00, 0xe6, 0x2a, 0x94, 0x00, 0xd1, 0x6f, 0x2c, 0x8b, 0x8d, 0x68, 0x5b, 0x6c, 0x60, 0x29, 0x55, + 0x73, 0xbd, 0x9a, 0x3e, 0x7b, 0x25, 0x9a, 0xf7, 0xd1, 0x8c, 0x53, 0x1a, 0x0d, 0x38, 0x4e, 0xa3, 0x70, 0xfb, 0xfe, + 0x5e, 0x94, 0xcb, 0x0c, 0x2c, 0xd9, 0x2a, 0x9c, 0xe2, 0xb2, 0x51, 0x67, 0xc4, 0x8b, 0x3c, 0x56, 0x00, 0x1d, 0x8f, + 0x09, 0x80, 0xea, 0x82, 0x80, 0x8a, 0x68, 0x29, 0xbd, 0x15, 0x5a, 0x2c, 0xd4, 0x1b, 0x8e, 0x52, 0xf8, 0x23, 0xfd, + 0x79, 0x90, 0x4f, 0x01, 0x88, 0x5d, 0x1f, 0x47, 0xaf, 0x8b, 0x92, 0x3e, 0x55, 0xcc, 0x72, 0x39, 0x98, 0xc0, 0xae, + 0x4e, 0x64, 0xa8, 0x15, 0xe4, 0xad, 0xba, 0xf2, 0x56, 0x26, 0x6f, 0x63, 0x9c, 0x92, 0x1f, 0xb9, 0xe9, 0x58, 0x23, + 0x06, 0x5e, 0x79, 0x5a, 0xa7, 0x09, 0xd2, 0xe4, 0x02, 0x18, 0x86, 0xf8, 0x36, 0xf3, 0x5e, 0x78, 0x8e, 0x54, 0x05, + 0xc9, 0x6c, 0x97, 0x79, 0xea, 0x22, 0xaa, 0xaf, 0x9c, 0x5a, 0x3a, 0x73, 0xfa, 0x11, 0xc0, 0x7b, 0x4c, 0x4d, 0x1a, + 0xf2, 0x11, 0x6e, 0x4b, 0xf1, 0xf5, 0x56, 0x5d, 0xe3, 0xa5, 0xd1, 0xb9, 0x7b, 0xf9, 0xd2, 0x9d, 0x06, 0xfd, 0x14, + 0x04, 0xe5, 0x7c, 0x51, 0x0a, 0xd8, 0x53, 0x66, 0x73, 0xbd, 0x5a, 0xb5, 0x42, 0xeb, 0x70, 0x18, 0x6b, 0x47, 0x21, + 0xad, 0xce, 0x02, 0xb6, 0x1a, 0xe9, 0x94, 0x00, 0x21, 0x38, 0x4e, 0xc3, 0x4e, 0x30, 0xee, 0xd2, 0x69, 0x44, 0xd6, + 0x2b, 0x25, 0xe9, 0xc2, 0x0c, 0x92, 0x7f, 0x92, 0xd7, 0x33, 0xa0, 0x25, 0x80, 0x43, 0x11, 0x4b, 0x78, 0x38, 0x49, + 0xae, 0x00, 0x3a, 0x1d, 0x0e, 0x2a, 0x0d, 0xcd, 0x59, 0xcd, 0x92, 0xf9, 0x24, 0x96, 0xaa, 0xca, 0xc3, 0xc1, 0x53, + 0x6e, 0x06, 0xfd, 0x7e, 0x36, 0x2d, 0x95, 0x0b, 0x40, 0x10, 0xeb, 0xc2, 0x00, 0xf1, 0x48, 0x0b, 0x4f, 0x16, 0x7d, + 0x4a, 0xe2, 0x97, 0xb3, 0x64, 0x6e, 0xb2, 0xe1, 0x1d, 0x18, 0xc1, 0x66, 0x5c, 0x97, 0x94, 0x69, 0x8f, 0xca, 0xef, + 0x19, 0x3d, 0xb5, 0x7d, 0xad, 0xd5, 0x16, 0xb1, 0xae, 0x83, 0xab, 0x12, 0xf5, 0x14, 0x1f, 0x94, 0x24, 0x78, 0xbf, + 0x72, 0x6e, 0x46, 0xca, 0xd7, 0x22, 0xf7, 0x83, 0x76, 0xa6, 0x56, 0x0e, 0x1c, 0x81, 0x1c, 0xab, 0xa8, 0xe4, 0xf5, + 0xae, 0x43, 0xf0, 0xe8, 0xae, 0x54, 0xa0, 0x1c, 0x7c, 0x0d, 0x62, 0x74, 0x7d, 0xd5, 0x59, 0x43, 0xcd, 0x34, 0xaa, + 0x3c, 0x82, 0x4e, 0x1d, 0xc0, 0x93, 0x82, 0x97, 0x5a, 0xfd, 0x78, 0x38, 0x78, 0xe6, 0x07, 0x7f, 0x99, 0xe9, 0x5b, + 0x88, 0x89, 0x72, 0xaa, 0x11, 0x12, 0x57, 0x4a, 0x12, 0xf1, 0xf1, 0xa2, 0x65, 0xc5, 0xa8, 0x0c, 0x1f, 0x78, 0xa5, + 0xca, 0x57, 0xa7, 0x2a, 0x2f, 0x46, 0xda, 0x96, 0xc0, 0x6b, 0xf2, 0x0f, 0x91, 0x6b, 0xde, 0xfa, 0xba, 0xab, 0x0c, + 0x7d, 0x2b, 0x2b, 0xd0, 0x11, 0x6c, 0x65, 0x29, 0x39, 0xe0, 0x93, 0xea, 0xae, 0x5a, 0xb5, 0x3e, 0xa7, 0x6c, 0x23, + 0xdc, 0xe4, 0xd7, 0xb1, 0x83, 0x23, 0xe5, 0x37, 0x78, 0x2e, 0x80, 0xbd, 0x06, 0xec, 0xcd, 0x39, 0x2b, 0x9a, 0x47, + 0x87, 0xb4, 0x2d, 0xd0, 0xc8, 0xcc, 0xed, 0x5c, 0xdd, 0xb7, 0xe5, 0x51, 0x1a, 0x43, 0x64, 0xda, 0x23, 0xd3, 0xc1, + 0x66, 0x94, 0xff, 0x96, 0xf2, 0x5b, 0x85, 0x63, 0xe0, 0xdb, 0xa9, 0x77, 0x00, 0x55, 0x4f, 0x1b, 0x64, 0xac, 0x19, + 0x86, 0x56, 0x76, 0xb9, 0x14, 0x5a, 0x82, 0x96, 0xba, 0x09, 0x82, 0xf3, 0x23, 0xa2, 0x1c, 0x01, 0xe8, 0x22, 0x05, + 0x4c, 0xf0, 0x53, 0xda, 0xee, 0x7e, 0x7f, 0x9d, 0x7a, 0xe4, 0xde, 0x15, 0x6a, 0x94, 0x50, 0x82, 0xb1, 0x9f, 0x68, + 0xcc, 0xa0, 0xa3, 0x2b, 0x72, 0xc2, 0xb3, 0x56, 0x87, 0x75, 0xdd, 0x94, 0x41, 0x59, 0x1c, 0xf3, 0x6a, 0x3a, 0xfb, + 0xfd, 0xc9, 0xbe, 0x6e, 0x90, 0x85, 0xfc, 0x77, 0xd6, 0x43, 0x32, 0xe8, 0x1e, 0x84, 0x42, 0xf4, 0xe6, 0xc1, 0x0c, + 0xff, 0x63, 0x1b, 0x9e, 0x7d, 0xc3, 0x8d, 0x3a, 0x01, 0xcc, 0x11, 0xd7, 0x4b, 0x4f, 0xd1, 0xd6, 0xc3, 0x2d, 0x90, + 0xad, 0xf1, 0xf2, 0xd6, 0x5e, 0x03, 0x39, 0xc5, 0xf1, 0xdf, 0xf1, 0x4c, 0xad, 0x6c, 0xf0, 0xd3, 0x53, 0xb6, 0x03, + 0x0f, 0x2f, 0x42, 0x40, 0x31, 0x2c, 0x1b, 0x7f, 0x67, 0x39, 0xce, 0xe8, 0xbf, 0x79, 0xc4, 0x30, 0x58, 0x44, 0x7e, + 0x7c, 0x59, 0x0a, 0xf1, 0x45, 0x78, 0x6f, 0x2a, 0xef, 0x8e, 0x9c, 0x32, 0xef, 0xf4, 0x30, 0xba, 0x2e, 0x49, 0xdf, + 0x24, 0x1f, 0x5b, 0xc3, 0xf6, 0xbb, 0x76, 0xbf, 0x19, 0x22, 0x08, 0xa1, 0x1c, 0x3f, 0x67, 0x74, 0x42, 0xe3, 0xc3, + 0x6a, 0x76, 0x7a, 0xfd, 0xde, 0x39, 0x5e, 0xb0, 0x35, 0x1a, 0xe0, 0xf1, 0xd0, 0xc5, 0x3c, 0x51, 0x43, 0xa7, 0xeb, + 0xda, 0x39, 0x78, 0x60, 0x90, 0xe5, 0xc9, 0x37, 0x0c, 0x4b, 0xec, 0x4f, 0x22, 0x9e, 0xb4, 0x55, 0x1b, 0x9b, 0x23, + 0xd5, 0x46, 0xcd, 0xc0, 0x0f, 0x5e, 0x41, 0x81, 0xd1, 0x05, 0x69, 0x05, 0xc6, 0xe1, 0x08, 0x40, 0x56, 0x8c, 0xe3, + 0x91, 0xc1, 0x04, 0x86, 0x74, 0x43, 0x51, 0x00, 0x1e, 0x1e, 0xc7, 0x83, 0x90, 0x01, 0xa4, 0x0b, 0x1e, 0x1a, 0xb6, + 0x49, 0x48, 0xf9, 0x79, 0x9e, 0xd7, 0x6a, 0x08, 0x7d, 0x67, 0xa1, 0x3a, 0xf6, 0x23, 0xed, 0x15, 0xeb, 0x5a, 0x95, + 0x8e, 0x6c, 0x75, 0x80, 0xbe, 0x21, 0x03, 0xdf, 0x3a, 0xb6, 0x00, 0x88, 0x96, 0xf8, 0x2d, 0xf5, 0x6a, 0x5f, 0xc6, + 0xac, 0x50, 0xaf, 0x2f, 0x4c, 0xbb, 0x5e, 0x49, 0x8b, 0x02, 0x2a, 0x6e, 0x5b, 0xb5, 0x3d, 0x92, 0xf3, 0x1f, 0xdf, + 0x75, 0xb4, 0xe3, 0xb3, 0x53, 0x63, 0x4b, 0x28, 0x73, 0x8b, 0x27, 0xb2, 0x3a, 0xda, 0x52, 0x9d, 0xea, 0x03, 0x2e, + 0x35, 0xa9, 0xce, 0x0c, 0x0c, 0xaf, 0x11, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xde, 0xf9, 0x64, 0x50, 0x30, 0xb7, + 0x48, 0x40, 0x02, 0xdb, 0xd8, 0xda, 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xaa, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, + 0xce, 0xde, 0x69, 0x2d, 0x20, 0x80, 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, + 0xf9, 0x6f, 0x29, 0x2a, 0x62, 0x4f, 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, + 0x3a, 0x6a, 0x2a, 0xd7, 0xcd, 0x55, 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xba, 0xd6, 0xb9, 0x53, 0xef, 0xbd, 0x8a, 0x23, + 0x06, 0x82, 0x9b, 0xee, 0xf1, 0xc1, 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, + 0x68, 0xce, 0xf4, 0x11, 0x00, 0x11, 0x60, 0x95, 0xa8, 0xff, 0xc3, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, + 0xb6, 0xde, 0x3f, 0xad, 0x91, 0x56, 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, + 0xff, 0x9f, 0xfb, 0x00, 0x35, 0xa2, 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2c, 0x7c, 0xe3, 0x87, 0x8c, + 0xf3, 0xc1, 0x0c, 0x1d, 0xd5, 0xe6, 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, + 0x4f, 0xdc, 0x67, 0x5c, 0x7b, 0x41, 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, + 0x65, 0x93, 0x48, 0x7d, 0x33, 0x06, 0x05, 0x40, 0x71, 0x5d, 0x91, 0x5c, 0xba, 0x48, 0xf3, 0x4a, 0x94, 0xb5, 0x6e, + 0x46, 0xc5, 0x8a, 0x21, 0x00, 0x3c, 0x04, 0xc5, 0x55, 0x65, 0x26, 0x34, 0x62, 0x03, 0xa9, 0x2c, 0x05, 0xab, 0x86, + 0x85, 0xdf, 0xb4, 0xdf, 0x24, 0x27, 0xbd, 0xf3, 0x71, 0xeb, 0xdc, 0xb1, 0xef, 0x1d, 0x85, 0x94, 0xf6, 0x50, 0x4c, + 0x10, 0x04, 0x3f, 0xad, 0xc3, 0xf9, 0x33, 0x7e, 0x4d, 0x60, 0x2a, 0xb2, 0x19, 0x03, 0x0e, 0x42, 0x44, 0x66, 0xfc, + 0x9e, 0xc3, 0x6b, 0x5e, 0x4e, 0xc2, 0xe1, 0xd0, 0x07, 0x7d, 0x28, 0xcf, 0x66, 0xe1, 0x50, 0xcc, 0xa5, 0xf7, 0x3a, + 0x58, 0xeb, 0x42, 0x5e, 0x4f, 0x42, 0x44, 0x0b, 0x0d, 0x7d, 0x70, 0x5e, 0x77, 0xcd, 0x11, 0x96, 0x00, 0x34, 0x71, + 0xf4, 0x65, 0xfd, 0x7e, 0xe4, 0x69, 0x43, 0x8b, 0x14, 0x17, 0x8d, 0x32, 0x9b, 0xe5, 0xb2, 0x13, 0x36, 0xae, 0xdd, + 0x02, 0xa1, 0x78, 0x98, 0xb6, 0x50, 0xb5, 0x9e, 0xea, 0xf5, 0xdc, 0xb4, 0xfb, 0xee, 0x51, 0xb5, 0xca, 0x91, 0xce, + 0xda, 0x74, 0xa5, 0x56, 0xb7, 0x8c, 0xaa, 0x75, 0x96, 0x46, 0x54, 0xb9, 0x49, 0xee, 0x1a, 0xb5, 0xe0, 0x93, 0x0d, + 0x5d, 0xa6, 0xec, 0x6c, 0x0d, 0x4e, 0x1c, 0x79, 0x2e, 0xb9, 0xe5, 0xbb, 0xf3, 0x8a, 0xee, 0x4e, 0xb5, 0x6f, 0x01, + 0xee, 0xcd, 0xb0, 0x21, 0x73, 0x5e, 0x63, 0xa7, 0x41, 0x98, 0x04, 0x7e, 0xc4, 0x3e, 0x66, 0xc8, 0x06, 0x03, 0x3a, + 0x0a, 0xe9, 0x7f, 0x6d, 0x99, 0x23, 0x01, 0x93, 0xbf, 0x9e, 0xfb, 0xcd, 0xa2, 0xc8, 0x61, 0x31, 0x7e, 0xd8, 0x60, + 0xa4, 0xb1, 0x5a, 0x83, 0x61, 0x79, 0x87, 0xc8, 0x9f, 0xda, 0x1d, 0xd3, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, + 0xa7, 0x4f, 0x75, 0x7d, 0xfe, 0xdb, 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xde, 0x2d, 0xce, 0x1d, + 0x89, 0xde, 0xb1, 0xd2, 0xcc, 0x2e, 0xed, 0x92, 0x5d, 0x9a, 0xd2, 0x6e, 0xc8, 0xf5, 0xea, 0x2b, 0xe5, 0x8d, 0x9d, + 0x57, 0x4c, 0xf7, 0xef, 0x85, 0xde, 0x51, 0x4e, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, + 0x27, 0x79, 0xbb, 0x84, 0xa3, 0xae, 0x61, 0xb9, 0xf9, 0xf6, 0x3f, 0xf3, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, + 0xfd, 0x29, 0x88, 0xab, 0xfa, 0xc3, 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe8, + 0x9e, 0x42, 0xd8, 0x60, 0xf6, 0xf3, 0xe3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x92, 0x11, + 0xde, 0xef, 0x18, 0xe7, 0xfe, 0xd5, 0xf7, 0x6a, 0x72, 0x84, 0x88, 0x76, 0x11, 0x0e, 0x00, 0xe2, 0x4e, 0x53, 0x59, + 0x87, 0x1a, 0xa0, 0x0f, 0x08, 0xac, 0x43, 0xdf, 0x66, 0x00, 0x07, 0x7d, 0xb4, 0x79, 0x16, 0x81, 0xbc, 0xee, 0xdd, + 0xb3, 0xb7, 0x6c, 0xe7, 0xf3, 0xeb, 0x55, 0xea, 0xdd, 0xa3, 0x43, 0xf0, 0xf9, 0xd8, 0x9f, 0x5e, 0x06, 0x06, 0x17, + 0x9a, 0xbd, 0x7d, 0x26, 0xd8, 0x8e, 0xed, 0x9e, 0x21, 0x52, 0x51, 0x77, 0xfe, 0xe1, 0xa5, 0x89, 0x9e, 0x77, 0x5e, + 0xb8, 0xe3, 0x4b, 0x00, 0x0f, 0x64, 0x31, 0xa0, 0xf8, 0x2c, 0xbd, 0x7f, 0xb1, 0x04, 0xd4, 0xe4, 0xb7, 0x7c, 0xed, + 0x7d, 0xa1, 0xd4, 0x05, 0xfc, 0x39, 0xa0, 0xf4, 0x49, 0xce, 0xbd, 0xbb, 0xe1, 0xad, 0x7f, 0xf1, 0x1c, 0x9c, 0x27, + 0x56, 0xc3, 0x05, 0xfc, 0x55, 0xf0, 0xa1, 0x77, 0x37, 0xc0, 0xc4, 0x92, 0x0f, 0xbd, 0xd5, 0x00, 0x52, 0x15, 0x2e, + 0x24, 0xc6, 0x3e, 0xfc, 0x1a, 0xe4, 0x0c, 0xff, 0xf8, 0x4d, 0x63, 0xb0, 0xfe, 0x1a, 0x14, 0x1a, 0x8d, 0xb5, 0x54, + 0x21, 0x4b, 0xb1, 0x38, 0x13, 0x60, 0x13, 0x8e, 0xbb, 0x7d, 0xb1, 0xaa, 0xcd, 0x5a, 0xd0, 0x9f, 0x8f, 0xf8, 0x1e, + 0x8d, 0xd5, 0x55, 0x39, 0x17, 0xe5, 0x47, 0xa4, 0x4f, 0x75, 0x7c, 0x8c, 0x8a, 0x4d, 0xdd, 0x9d, 0x4e, 0xb5, 0xea, + 0x48, 0xfb, 0x4d, 0xb9, 0x06, 0x3b, 0x5e, 0x27, 0x47, 0x96, 0xc2, 0xb3, 0x0e, 0x3b, 0x2f, 0x9d, 0x12, 0x1d, 0x86, + 0xf1, 0x6e, 0xab, 0x9e, 0x31, 0x94, 0xe7, 0x06, 0x63, 0xba, 0xe0, 0x11, 0xbf, 0x1e, 0xe4, 0x32, 0x34, 0xe6, 0x03, + 0xb2, 0x61, 0x28, 0x1f, 0x5a, 0x64, 0x48, 0x88, 0x78, 0x0f, 0x95, 0x80, 0x6d, 0x0b, 0xca, 0xa4, 0x80, 0xb3, 0x68, + 0xf0, 0x5b, 0xed, 0xe5, 0xc0, 0x7b, 0x10, 0xf9, 0x8d, 0x74, 0x29, 0x97, 0xd8, 0xe8, 0xc4, 0xb1, 0x2c, 0xb4, 0xf3, + 0xb8, 0xfe, 0x3a, 0x06, 0xf5, 0x7b, 0xa5, 0xdf, 0xa0, 0x9c, 0xfd, 0x51, 0xb2, 0x4e, 0x1b, 0x4f, 0x8c, 0x7f, 0xb8, + 0xca, 0x3f, 0x45, 0x4b, 0x3d, 0xfc, 0x7f, 0xc6, 0x14, 0x4a, 0xff, 0x32, 0x2d, 0xa3, 0xcd, 0x6a, 0x29, 0x4a, 0x91, + 0x47, 0xe2, 0xe4, 0x6b, 0x91, 0x9d, 0xcb, 0x77, 0x3e, 0x85, 0x7e, 0x01, 0x68, 0xd9, 0x27, 0xc8, 0xe8, 0xef, 0x99, + 0xe0, 0xc3, 0xef, 0xb5, 0x73, 0x6d, 0xce, 0xc7, 0x93, 0xfc, 0xca, 0xda, 0xbb, 0x1d, 0x2f, 0x12, 0xa3, 0x18, 0xcb, + 0x7d, 0xd5, 0xcd, 0xca, 0x89, 0x4a, 0x0e, 0x8c, 0x74, 0x4d, 0xf6, 0x72, 0x25, 0xeb, 0x76, 0xba, 0x95, 0x40, 0x44, + 0x15, 0x78, 0x8f, 0x71, 0x15, 0xfb, 0x08, 0xa6, 0xeb, 0x8e, 0xcb, 0x68, 0xc7, 0x7b, 0xc6, 0xab, 0x13, 0x65, 0x05, + 0xb7, 0x1b, 0xd1, 0x9e, 0xd0, 0xd1, 0x4f, 0x93, 0xda, 0xb2, 0x70, 0x00, 0x72, 0x97, 0x30, 0x96, 0x0d, 0xc1, 0x8a, + 0x41, 0xe9, 0xeb, 0x35, 0x25, 0xcb, 0x02, 0x2c, 0x3a, 0xbb, 0x8c, 0x40, 0x0c, 0xeb, 0xa6, 0x39, 0xa1, 0xe3, 0xa5, + 0x8b, 0xf3, 0x5e, 0xab, 0x48, 0xc1, 0x33, 0x5a, 0x74, 0xcc, 0x4d, 0x47, 0xba, 0x31, 0xda, 0xdb, 0xef, 0x0d, 0x42, + 0x8a, 0xe7, 0x0f, 0x6c, 0xb5, 0x2e, 0x2e, 0x12, 0xaf, 0x90, 0x89, 0x16, 0xc4, 0x52, 0x04, 0x66, 0xbc, 0xd0, 0x34, + 0xc2, 0x04, 0x65, 0x4a, 0xb0, 0x68, 0x8d, 0x0e, 0xed, 0x0f, 0x4b, 0xd8, 0x3d, 0xc6, 0x08, 0x10, 0xa8, 0x32, 0x7d, + 0x0e, 0x5b, 0x13, 0x66, 0x53, 0x17, 0x1b, 0xa0, 0xad, 0x62, 0x68, 0x10, 0xd6, 0x86, 0x98, 0x8f, 0x69, 0x7e, 0xf7, + 0x2f, 0x2c, 0xc6, 0xf6, 0x04, 0x62, 0x7b, 0xb7, 0x6b, 0x12, 0xa6, 0x7b, 0x2d, 0x6e, 0xac, 0x97, 0xdb, 0x53, 0x8e, + 0xa9, 0x1d, 0x6b, 0xa3, 0x76, 0xac, 0xa5, 0xde, 0xb1, 0xd6, 0x7a, 0xc7, 0xba, 0x6b, 0xf8, 0x87, 0xcc, 0x8b, 0x59, + 0x02, 0xfa, 0xdd, 0x15, 0x57, 0x0d, 0x82, 0x66, 0x6c, 0xd8, 0x2d, 0xfc, 0x96, 0x58, 0xbb, 0xa5, 0x7f, 0xb1, 0x64, + 0x0b, 0xd3, 0x07, 0xba, 0x75, 0x80, 0x65, 0x44, 0x4d, 0xbe, 0x47, 0xde, 0x4d, 0x67, 0x45, 0xe1, 0xf6, 0xc4, 0x16, + 0x3e, 0x7b, 0x6b, 0xde, 0xbc, 0x7f, 0x16, 0x41, 0xee, 0x1d, 0xf7, 0xee, 0x87, 0x6f, 0xfd, 0x0b, 0xdd, 0x02, 0x39, + 0x99, 0xe5, 0x0c, 0xa4, 0x8e, 0xf8, 0x04, 0xd1, 0xca, 0x9e, 0xf2, 0x9d, 0x90, 0x3b, 0xdb, 0xfa, 0xd9, 0xbd, 0xbb, + 0xad, 0xdd, 0x3d, 0xbb, 0x67, 0xd5, 0x88, 0x62, 0xc5, 0x69, 0x8a, 0x84, 0x59, 0xb4, 0x01, 0x9e, 0x7a, 0xf9, 0x7e, + 0xc7, 0x8e, 0x39, 0xdc, 0x3d, 0xeb, 0xe8, 0x78, 0x39, 0x07, 0xec, 0xee, 0x3f, 0xda, 0x84, 0x8d, 0x95, 0xae, 0x55, + 0xe8, 0x70, 0xf7, 0x2c, 0xd3, 0x78, 0x0e, 0x47, 0xf2, 0xe9, 0x58, 0x63, 0x83, 0xa0, 0xae, 0xcf, 0x19, 0xd4, 0x8e, + 0xdd, 0xd7, 0x84, 0x5d, 0x76, 0xcc, 0x6b, 0x5d, 0xf3, 0xf6, 0xca, 0x53, 0xb1, 0x21, 0xa0, 0xc3, 0xd7, 0xea, 0x06, + 0xf9, 0x97, 0xc0, 0x29, 0x02, 0x40, 0x0e, 0xc7, 0x4b, 0x1e, 0xfb, 0x3e, 0xcd, 0xd2, 0x7a, 0x87, 0x5a, 0x8b, 0xca, + 0xb2, 0x0c, 0x6b, 0xef, 0x07, 0xad, 0x18, 0x96, 0x9a, 0xfe, 0xe9, 0x38, 0x70, 0x3b, 0xdb, 0xad, 0x8c, 0x5d, 0xc6, + 0xb3, 0xe2, 0xe2, 0xfb, 0xd3, 0x42, 0xb9, 0x76, 0xf3, 0x36, 0x7e, 0xd3, 0x6a, 0xc9, 0xd2, 0x5a, 0x0f, 0x79, 0x69, + 0x59, 0x44, 0x20, 0x80, 0xe1, 0x48, 0xd9, 0xc5, 0x12, 0xee, 0x11, 0x56, 0xf7, 0x20, 0x94, 0xcc, 0x0b, 0x17, 0xcf, + 0x59, 0x0c, 0x89, 0x00, 0xdb, 0x1d, 0x2a, 0xb6, 0x85, 0x8b, 0xe7, 0x6c, 0xc3, 0x8b, 0x7e, 0x3f, 0x53, 0x9d, 0x42, + 0xd6, 0x9d, 0x25, 0xdf, 0xa8, 0xe6, 0x58, 0x43, 0xcd, 0xd6, 0x26, 0xd9, 0x1a, 0xe7, 0xb6, 0xe2, 0xe3, 0xae, 0xad, + 0xf8, 0x58, 0x59, 0xeb, 0xd2, 0xbd, 0xde, 0xa3, 0xba, 0x00, 0xb6, 0xfe, 0xdb, 0xe3, 0x95, 0xeb, 0xf9, 0x8c, 0x00, + 0xbe, 0x16, 0x7c, 0x3c, 0x59, 0xa0, 0x57, 0xc9, 0xc2, 0xbf, 0x1d, 0xa8, 0xf1, 0x77, 0x3a, 0x77, 0x01, 0xd0, 0x95, + 0x94, 0x57, 0x40, 0xde, 0x41, 0x8e, 0xb9, 0x65, 0x57, 0xde, 0x9f, 0x7c, 0x87, 0xbd, 0xe5, 0xf5, 0x6c, 0x31, 0x67, + 0x3b, 0x70, 0x2a, 0x48, 0x06, 0xf6, 0xb2, 0x62, 0xbb, 0x20, 0xb6, 0x13, 0x7e, 0x23, 0x60, 0xca, 0x17, 0x10, 0xc4, + 0x15, 0xdc, 0x42, 0x1c, 0x9e, 0xfc, 0x73, 0x70, 0xdf, 0xda, 0xac, 0xef, 0x99, 0xd5, 0x39, 0xc1, 0x9a, 0x59, 0x3d, + 0x18, 0x2c, 0x9b, 0xc9, 0xaa, 0xdf, 0xf7, 0x76, 0xda, 0xf1, 0xe9, 0x4e, 0xea, 0xc4, 0x4e, 0x6b, 0xb5, 0x16, 0xec, + 0xad, 0xd4, 0xba, 0x18, 0x43, 0x0f, 0x10, 0x3f, 0xdd, 0x0e, 0xf8, 0x7d, 0xc7, 0xda, 0xf2, 0xde, 0xb2, 0x05, 0xdb, + 0xc1, 0x25, 0xa8, 0x69, 0x2f, 0xfb, 0x93, 0xca, 0x05, 0xed, 0xd8, 0x25, 0xf1, 0x70, 0xc6, 0xac, 0x52, 0x66, 0xd6, + 0x49, 0x75, 0x25, 0x3a, 0x63, 0x3a, 0x6b, 0x3d, 0x9f, 0xab, 0xf9, 0xa4, 0xd0, 0xa0, 0x7e, 0xe7, 0xc4, 0x47, 0x54, + 0x74, 0x9e, 0xc0, 0xd6, 0xb2, 0x82, 0x58, 0xed, 0x73, 0xb0, 0xd6, 0x6a, 0x97, 0x7e, 0x2f, 0x1f, 0x70, 0x9b, 0x72, + 0x58, 0x07, 0x06, 0x35, 0x27, 0x56, 0xd4, 0x63, 0xb6, 0x63, 0xdc, 0xfc, 0xf4, 0xf2, 0x07, 0x27, 0x2c, 0x59, 0xb1, + 0xda, 0x9f, 0x7e, 0xff, 0xcc, 0xd3, 0xdf, 0xa9, 0xfd, 0x0b, 0xe1, 0x07, 0xe3, 0xff, 0xd4, 0xee, 0x6b, 0x2d, 0x46, + 0x65, 0xab, 0x1c, 0xa1, 0x71, 0xb7, 0x92, 0x26, 0xcb, 0x4f, 0xc2, 0x13, 0xd6, 0x82, 0x67, 0xb9, 0x5e, 0xa2, 0x59, + 0x01, 0x2b, 0xac, 0x65, 0x12, 0xae, 0x30, 0x56, 0x4b, 0x5b, 0x7d, 0x8b, 0xa6, 0x39, 0x3e, 0x9c, 0x6b, 0x83, 0x32, + 0xe5, 0xec, 0x8c, 0x58, 0x0d, 0x97, 0x61, 0x69, 0x42, 0x11, 0xb2, 0x7b, 0x3b, 0xb8, 0xb1, 0x53, 0x96, 0x52, 0x86, + 0x73, 0x0c, 0x26, 0x3c, 0x12, 0xa3, 0x2a, 0xdf, 0xdf, 0x97, 0x14, 0x39, 0x6d, 0xcb, 0x41, 0x15, 0xc2, 0x3e, 0x92, + 0x28, 0x81, 0x5b, 0x91, 0x16, 0x8a, 0x94, 0xc5, 0xdf, 0x0e, 0xd0, 0x05, 0x5e, 0x40, 0x5d, 0x8d, 0xba, 0xfd, 0xe1, + 0x88, 0x87, 0x8f, 0x4c, 0x7d, 0x60, 0xc4, 0x92, 0x40, 0x6d, 0x2f, 0xb2, 0xf4, 0x0e, 0x54, 0xf8, 0x3d, 0x5c, 0x4d, + 0xc4, 0x7e, 0x6e, 0x49, 0x51, 0x91, 0x8d, 0xf4, 0x86, 0xd6, 0xe0, 0x11, 0x5a, 0x53, 0xbe, 0x77, 0x52, 0x6d, 0xd2, + 0x79, 0x47, 0xc8, 0xb1, 0xfa, 0xd6, 0x12, 0x46, 0xbb, 0xa2, 0x17, 0xf7, 0x8e, 0xde, 0xf3, 0x74, 0xd5, 0x73, 0x7f, + 0xe2, 0x8a, 0x79, 0x72, 0x1b, 0x81, 0xba, 0x15, 0x54, 0xb7, 0xf7, 0x2a, 0xc1, 0x82, 0x25, 0xed, 0x3e, 0x7e, 0x3b, + 0x6b, 0x07, 0xa2, 0x32, 0x56, 0xe9, 0x6b, 0x92, 0xb0, 0x27, 0x06, 0x9d, 0x42, 0x55, 0x6e, 0x77, 0x47, 0x5b, 0xe0, + 0x3a, 0x66, 0x29, 0x7a, 0x61, 0x8b, 0xdc, 0x2d, 0xff, 0xee, 0xb9, 0x22, 0x67, 0xbf, 0x04, 0x04, 0xa7, 0xe6, 0x2b, + 0xe2, 0xcb, 0x11, 0x1e, 0x55, 0xb7, 0xc0, 0x71, 0xfa, 0x0e, 0xe0, 0x1f, 0x0e, 0x97, 0xa0, 0x09, 0x88, 0x05, 0xeb, + 0xa5, 0x71, 0x8f, 0xf5, 0xe2, 0x62, 0x73, 0x97, 0xe4, 0x1b, 0x70, 0x66, 0xa0, 0x54, 0x4b, 0x3f, 0x70, 0xac, 0x16, + 0x50, 0xe1, 0x60, 0x76, 0x52, 0x2f, 0x2c, 0xa3, 0x1e, 0xd3, 0xe7, 0x67, 0xb0, 0x77, 0x84, 0x04, 0xc0, 0xfd, 0xb2, + 0x0f, 0x48, 0xc0, 0x43, 0x67, 0x76, 0x40, 0x38, 0x61, 0x16, 0x55, 0x81, 0x44, 0x72, 0xa4, 0x9f, 0x3d, 0x66, 0x22, + 0xf9, 0x83, 0x59, 0xcf, 0x39, 0x25, 0x7a, 0xac, 0xa7, 0x8e, 0x90, 0x1e, 0xeb, 0x59, 0x47, 0x44, 0x8f, 0xf5, 0xac, + 0xe3, 0xa3, 0xc7, 0x7a, 0xe6, 0xd8, 0xe9, 0x41, 0x60, 0x02, 0x44, 0x1e, 0xb0, 0x1e, 0x4d, 0xa6, 0x9e, 0xe2, 0x1e, + 0x20, 0x1a, 0x04, 0xd6, 0x93, 0xc2, 0x79, 0x0f, 0x90, 0xc7, 0x48, 0xac, 0x0e, 0x7a, 0x7f, 0x19, 0x3f, 0xed, 0x19, + 0x19, 0x79, 0xdc, 0x3a, 0xac, 0xfe, 0xd7, 0x5f, 0x21, 0x00, 0x0e, 0xcf, 0xa6, 0xde, 0xe5, 0x18, 0xb2, 0xca, 0x32, + 0x02, 0xc9, 0x4f, 0x0c, 0xbe, 0x7c, 0x01, 0x50, 0xf5, 0x99, 0xae, 0xd5, 0xe4, 0xa8, 0x3d, 0xe6, 0xd0, 0x15, 0x03, + 0xc0, 0x36, 0x2c, 0x51, 0x55, 0x0b, 0x9b, 0xb0, 0xb8, 0xfd, 0x0c, 0xa3, 0xb9, 0x6c, 0x7a, 0x41, 0x03, 0xf5, 0x08, + 0xc1, 0x2f, 0xad, 0x87, 0xd6, 0x5a, 0xa6, 0x1c, 0xba, 0x36, 0x8a, 0x2a, 0x1b, 0xea, 0x12, 0x56, 0x6b, 0x11, 0xd5, + 0x44, 0x91, 0x72, 0xc9, 0x28, 0x8a, 0xa5, 0x0a, 0xf6, 0x99, 0xb8, 0x83, 0xa8, 0x79, 0xda, 0x6a, 0xab, 0x60, 0x7f, + 0x07, 0x08, 0x6b, 0x61, 0x2d, 0xa4, 0x33, 0xa8, 0xbd, 0xd3, 0x8f, 0x94, 0xbf, 0xbc, 0x90, 0xdb, 0xb9, 0x85, 0x22, + 0xdc, 0x9e, 0x83, 0xf2, 0xa6, 0xae, 0x4a, 0x45, 0x34, 0x5a, 0x02, 0xa5, 0xcc, 0x09, 0x22, 0x0b, 0x10, 0xc0, 0x71, + 0x03, 0x81, 0xcf, 0x6b, 0x7c, 0x02, 0x8d, 0x42, 0x20, 0x3f, 0xb0, 0x0a, 0xd7, 0x1e, 0xd2, 0x52, 0x6b, 0x44, 0x94, + 0x88, 0x1f, 0x5d, 0x3d, 0xc7, 0xf6, 0xd5, 0xd3, 0x58, 0x5b, 0x4a, 0x13, 0xc4, 0x4f, 0x2c, 0xb6, 0x10, 0x13, 0x44, + 0x75, 0x88, 0x8e, 0x60, 0x39, 0x21, 0x44, 0xe1, 0x0f, 0xa1, 0x9f, 0x1a, 0xf8, 0x4b, 0xb6, 0x2c, 0xf2, 0x9a, 0x60, + 0x31, 0x2b, 0x06, 0x68, 0x55, 0x04, 0x9e, 0xe9, 0x6c, 0xa9, 0xcc, 0x69, 0x1e, 0x1d, 0xd9, 0xc1, 0x79, 0xd7, 0xc1, + 0x5e, 0xfa, 0x32, 0x76, 0xb2, 0x6c, 0x1a, 0xb5, 0xb1, 0x21, 0x12, 0x5e, 0x91, 0xbf, 0xcc, 0x52, 0xe3, 0x1c, 0x99, + 0xcb, 0xf5, 0x5d, 0x17, 0x77, 0x77, 0xb4, 0x4d, 0x58, 0x85, 0x08, 0x75, 0xdb, 0x50, 0xb9, 0x14, 0x66, 0x63, 0xd3, + 0x34, 0xc0, 0x17, 0x8a, 0x4a, 0xa5, 0x2a, 0xb5, 0x95, 0x4a, 0x4e, 0x78, 0xd7, 0x57, 0xb5, 0x48, 0x5d, 0x11, 0x6c, + 0x63, 0x86, 0x7a, 0x28, 0x37, 0x6a, 0xec, 0xeb, 0x8e, 0x55, 0x7a, 0x87, 0x09, 0x72, 0x46, 0x5e, 0xe4, 0xe0, 0xa2, + 0xa4, 0x20, 0x73, 0x35, 0x84, 0xf9, 0xa3, 0x86, 0x4f, 0x0b, 0xcb, 0x3d, 0x94, 0x80, 0xd9, 0x51, 0xc3, 0xcb, 0x08, + 0x81, 0x88, 0x4b, 0x65, 0x5f, 0x31, 0xf1, 0x7b, 0x0a, 0x66, 0xc9, 0x84, 0xee, 0x45, 0x2c, 0x8c, 0xd0, 0xc6, 0x27, + 0x49, 0x32, 0xf5, 0x34, 0x05, 0x37, 0x72, 0x19, 0xe6, 0x68, 0x84, 0x96, 0x7c, 0xe4, 0x40, 0xfa, 0x5a, 0x4e, 0x25, + 0xf8, 0x88, 0x3a, 0x05, 0x1c, 0xcf, 0xcf, 0x0b, 0xeb, 0x27, 0xcb, 0x25, 0xe6, 0xb2, 0x36, 0xff, 0x65, 0x47, 0xc7, + 0x60, 0x97, 0xa7, 0x89, 0xe3, 0xea, 0x3f, 0xaa, 0x92, 0xe2, 0xe1, 0xe7, 0x34, 0x07, 0x14, 0xc1, 0xcc, 0x9e, 0x62, + 0x7c, 0xec, 0xb3, 0x4c, 0x01, 0x7f, 0xbb, 0xde, 0x5a, 0x32, 0xb1, 0x4b, 0xda, 0xcd, 0x95, 0xf1, 0x4b, 0x6d, 0xd8, + 0x71, 0x70, 0x6e, 0x00, 0x8a, 0xb3, 0x46, 0x87, 0xe5, 0xb5, 0x6e, 0x5b, 0x15, 0x2a, 0x50, 0xeb, 0xff, 0xec, 0x16, + 0xa6, 0xbc, 0xcd, 0x4b, 0xe5, 0x6d, 0x1e, 0x9a, 0x00, 0x81, 0xc8, 0x0c, 0x79, 0xd6, 0x74, 0x4c, 0x12, 0xf7, 0x8e, + 0x94, 0xb4, 0xef, 0x48, 0xf1, 0xa3, 0x77, 0x24, 0xe4, 0x5b, 0x42, 0x47, 0xf6, 0x25, 0x27, 0x27, 0x50, 0x66, 0xb0, + 0x97, 0xd7, 0x4c, 0xf6, 0x0f, 0x68, 0x2f, 0x9c, 0xcb, 0xf2, 0x8a, 0xbf, 0x15, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, + 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, + 0xf1, 0xf1, 0x6f, 0x39, 0x8a, 0xd8, 0x4a, 0x79, 0x24, 0x5d, 0xa8, 0xc4, 0xf0, 0xd2, 0xc0, 0xc3, 0xec, 0xf8, 0x78, + 0xb2, 0xbb, 0xba, 0x9f, 0x0c, 0x06, 0x3b, 0xd5, 0xb7, 0x5b, 0x5e, 0xcf, 0x76, 0x73, 0xf6, 0xc0, 0x6f, 0xa7, 0xdb, + 0x60, 0xdf, 0xc0, 0xb6, 0xbb, 0xbb, 0x12, 0x87, 0xc3, 0xee, 0x9a, 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, + 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, + 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe1, + 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, + 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, + 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xf8, 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, + 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xdb, 0xd9, 0x66, 0xee, 0x5f, 0xaf, 0xd8, 0x1d, 0x70, 0xa1, 0x28, + 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, + 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, + 0x6f, 0xf9, 0x4d, 0x73, 0xec, 0x18, 0xfb, 0xd5, 0x1b, 0x23, 0x80, 0x32, 0x5b, 0xb0, 0x58, 0x70, 0x50, 0xaa, 0x55, + 0xdb, 0x92, 0xc8, 0x2b, 0x1d, 0xa8, 0x36, 0x23, 0xb8, 0xaf, 0x16, 0x72, 0xe6, 0x99, 0x81, 0xbe, 0xad, 0x10, 0x2d, + 0x1c, 0x36, 0xe0, 0xaf, 0xb4, 0x75, 0x8c, 0x61, 0x9a, 0xd5, 0x4c, 0xdb, 0xa2, 0x2e, 0xbf, 0xed, 0x3d, 0x93, 0xdf, + 0xc8, 0xc0, 0x16, 0x22, 0x29, 0x1c, 0xc7, 0x17, 0xcf, 0x4f, 0xf8, 0xaf, 0x5a, 0x1e, 0xb5, 0xda, 0x2f, 0x94, 0xfa, + 0xf4, 0x25, 0x1d, 0xd1, 0xc4, 0xbd, 0x68, 0xcb, 0xb0, 0x46, 0x59, 0x53, 0x4b, 0x87, 0x61, 0x5c, 0xc3, 0xbe, 0x3c, + 0x70, 0xe8, 0x3b, 0x20, 0xd0, 0x56, 0xa9, 0x14, 0x68, 0xe1, 0x18, 0x46, 0x61, 0x16, 0x52, 0x1e, 0x17, 0x66, 0x29, + 0xef, 0xb1, 0x40, 0x8b, 0x5b, 0x75, 0x8f, 0xa9, 0xed, 0x16, 0x44, 0x58, 0xbd, 0x65, 0x9c, 0x5f, 0x36, 0xaa, 0x70, + 0x5b, 0x80, 0xa2, 0x08, 0xca, 0x60, 0x4f, 0x72, 0xdb, 0x42, 0x49, 0xb3, 0x51, 0x58, 0x8b, 0xbb, 0xa2, 0xdc, 0xf5, + 0x1a, 0xb6, 0xc0, 0x0b, 0xaa, 0x7e, 0x42, 0xd8, 0x96, 0x3d, 0xeb, 0x50, 0x2e, 0xd2, 0xff, 0xc8, 0xd2, 0xf3, 0xed, + 0xd6, 0x9c, 0xff, 0xe9, 0x2b, 0xfa, 0xa8, 0xfc, 0xcf, 0x2f, 0xe9, 0x27, 0x83, 0x65, 0xe4, 0x94, 0xfa, 0x3e, 0x1a, + 0xdd, 0xa6, 0x39, 0x61, 0x6c, 0xf9, 0xfa, 0xe9, 0x37, 0xc8, 0x14, 0x24, 0x87, 0x52, 0xaa, 0x72, 0xb2, 0x87, 0xbe, + 0xf0, 0xba, 0x0f, 0x33, 0xc1, 0x00, 0x84, 0xd7, 0x68, 0x53, 0x4d, 0x98, 0xc4, 0xa3, 0x2b, 0xf8, 0xbf, 0x11, 0xc4, + 0xa0, 0x7d, 0xa2, 0xa8, 0x63, 0xdb, 0x48, 0xd7, 0x6d, 0xe7, 0x20, 0xb9, 0x53, 0x57, 0xfe, 0xa8, 0x9c, 0xfc, 0x27, + 0x1a, 0x22, 0xaf, 0xb8, 0x42, 0xac, 0x2c, 0xb8, 0xc4, 0x62, 0xa8, 0x48, 0x01, 0xae, 0x21, 0x88, 0x94, 0x45, 0x49, + 0xe1, 0x96, 0x83, 0xaa, 0x08, 0xc0, 0xb8, 0x5a, 0x1d, 0x75, 0x22, 0x7c, 0xdc, 0x5a, 0x8b, 0x10, 0xac, 0x68, 0xd4, + 0xca, 0x5a, 0x81, 0x2f, 0x48, 0x5f, 0x3a, 0x14, 0xc4, 0xf4, 0x28, 0xa4, 0xaa, 0x74, 0x28, 0x90, 0xe6, 0x50, 0xf1, + 0x8d, 0xc1, 0x46, 0x51, 0x91, 0x9e, 0xbf, 0x34, 0x29, 0xb9, 0x34, 0x66, 0x7c, 0x10, 0x65, 0x24, 0xf2, 0x3a, 0xbc, + 0x13, 0xd3, 0x02, 0xf9, 0x46, 0x8f, 0x1f, 0x04, 0x97, 0xf0, 0x6e, 0xc8, 0xbd, 0x02, 0x6c, 0x09, 0xd8, 0x01, 0xee, + 0x95, 0x19, 0xe5, 0x3a, 0xad, 0xeb, 0xb7, 0xd6, 0x43, 0x31, 0x0c, 0x9f, 0x59, 0x02, 0xdb, 0xd1, 0x3a, 0x3a, 0xd2, + 0xc3, 0x87, 0xff, 0x75, 0x55, 0x73, 0xd4, 0xa9, 0x5c, 0xce, 0x8e, 0x27, 0x2c, 0x45, 0xcc, 0xa0, 0xfb, 0xeb, 0xf6, + 0xa5, 0x00, 0xba, 0x5d, 0x16, 0xf3, 0x6c, 0xb4, 0x93, 0x7f, 0x4b, 0x37, 0x56, 0x94, 0x36, 0xf1, 0x2e, 0xeb, 0x8d, + 0xfd, 0xe1, 0xe8, 0x2f, 0xcf, 0xbe, 0x4c, 0x08, 0x55, 0x67, 0xc3, 0xd6, 0x3a, 0xce, 0xe5, 0x7f, 0xfd, 0x75, 0x4c, + 0x56, 0x10, 0x14, 0x84, 0x65, 0xa7, 0x98, 0xa8, 0x60, 0x14, 0x29, 0xd6, 0x7c, 0x3c, 0x59, 0xa3, 0x4e, 0x78, 0xed, + 0x2f, 0xb5, 0x4e, 0x98, 0x18, 0x59, 0xa9, 0xfc, 0x35, 0xab, 0xd8, 0x9d, 0xca, 0x2c, 0x20, 0xf3, 0x20, 0x9f, 0xac, + 0x8d, 0x06, 0x73, 0xc5, 0xeb, 0xd9, 0x7a, 0x2e, 0x95, 0xcf, 0x60, 0xca, 0x59, 0x0e, 0x4e, 0x96, 0xc2, 0xee, 0x49, + 0xa0, 0x68, 0xcd, 0xd0, 0xb5, 0x3f, 0xc5, 0x56, 0xbd, 0x4a, 0xab, 0x1a, 0xe0, 0x01, 0x21, 0x06, 0x86, 0xda, 0xab, + 0x85, 0x87, 0xd6, 0x02, 0x58, 0xfb, 0xa3, 0xd2, 0x0f, 0xc6, 0x93, 0x25, 0x5f, 0x20, 0xff, 0x72, 0xe4, 0xa8, 0xdd, + 0xfb, 0x7d, 0xef, 0x1e, 0xa4, 0xe0, 0xc8, 0xb5, 0x50, 0x20, 0x11, 0xd0, 0x82, 0x6f, 0x7c, 0xe5, 0x83, 0xf1, 0x16, + 0xb5, 0xd5, 0xa0, 0xa0, 0x76, 0x74, 0xcb, 0x63, 0x47, 0xef, 0x7c, 0x7f, 0x42, 0x5f, 0xbd, 0xd0, 0xc2, 0xf1, 0x57, + 0xce, 0xc8, 0x35, 0x5b, 0x75, 0xc8, 0x11, 0xcd, 0xa4, 0x43, 0x88, 0x58, 0xb1, 0x35, 0x7b, 0x4b, 0x2a, 0xe7, 0xce, + 0x21, 0x3b, 0x7d, 0x84, 0x2a, 0xbd, 0xd6, 0xe3, 0xdb, 0x89, 0xd2, 0xdd, 0x1e, 0xef, 0x26, 0xdf, 0xb2, 0x89, 0x88, + 0xc1, 0x80, 0x36, 0x08, 0x67, 0x64, 0x1d, 0x22, 0x95, 0x0e, 0x10, 0x02, 0xc7, 0x04, 0x34, 0xfd, 0xc7, 0xd7, 0x24, + 0x0a, 0x38, 0xd2, 0x46, 0xc8, 0x5a, 0x76, 0x38, 0xe4, 0xa0, 0x51, 0x6e, 0xfe, 0xf0, 0x0a, 0x75, 0x9a, 0x03, 0xf3, + 0x74, 0x09, 0x7b, 0x0e, 0x1e, 0xe9, 0xc5, 0xf1, 0x91, 0xfe, 0xdf, 0xd1, 0x44, 0x8d, 0xff, 0x73, 0x4d, 0x94, 0xd2, + 0x22, 0x39, 0xaa, 0xa5, 0x6f, 0x52, 0x47, 0xc1, 0x45, 0xde, 0x51, 0x0b, 0xd9, 0xb3, 0x6c, 0xdc, 0xa8, 0xe6, 0xfd, + 0xff, 0x5a, 0x99, 0xff, 0xaf, 0x69, 0x65, 0x98, 0x92, 0x1d, 0x4b, 0x35, 0xf3, 0x40, 0xab, 0x18, 0x66, 0x3f, 0x93, + 0x84, 0xc8, 0x70, 0x69, 0xc0, 0x8f, 0x2a, 0xd8, 0xc7, 0x69, 0xb5, 0xce, 0xc2, 0x1d, 0x2a, 0x51, 0x6f, 0xc5, 0x5d, + 0x9a, 0xbf, 0xa8, 0xff, 0x2d, 0xca, 0x02, 0xa6, 0xf6, 0x5d, 0x99, 0xc6, 0x01, 0x59, 0xf8, 0xb3, 0xb0, 0xc4, 0xc9, + 0x8d, 0x6d, 0xfc, 0x59, 0x8e, 0xa7, 0xfd, 0xaa, 0x33, 0xf3, 0x40, 0x02, 0x35, 0x10, 0x7f, 0xe4, 0x5c, 0x56, 0x16, + 0x0f, 0x08, 0xdd, 0xfc, 0x43, 0x59, 0x16, 0xa5, 0xd7, 0xfb, 0x94, 0xa4, 0xd5, 0xd9, 0x4a, 0xd4, 0x49, 0x11, 0x2b, + 0x28, 0x9b, 0x14, 0x60, 0xf4, 0x61, 0xe5, 0x89, 0x38, 0x38, 0x43, 0xa0, 0x86, 0xb3, 0x3a, 0x09, 0x01, 0x68, 0x58, + 0x21, 0xec, 0x9f, 0x41, 0x0b, 0xcf, 0xc2, 0x38, 0x5c, 0x03, 0x4c, 0x4e, 0x5a, 0x9d, 0xad, 0xcb, 0xe2, 0x3e, 0x8d, + 0x45, 0x3c, 0xea, 0x29, 0x4a, 0x96, 0xd7, 0xb9, 0x2b, 0xe7, 0xfa, 0xfb, 0x3f, 0x28, 0x80, 0xdd, 0x80, 0xd9, 0xb6, + 0xc0, 0x0e, 0x00, 0x12, 0x14, 0xc8, 0x16, 0xea, 0x34, 0x3a, 0x53, 0x4b, 0x05, 0xde, 0x73, 0x3d, 0xc0, 0x5f, 0xe7, + 0x80, 0x65, 0x5c, 0x17, 0x32, 0x60, 0x04, 0x01, 0x8c, 0xc0, 0x41, 0x09, 0x18, 0x3a, 0x43, 0xdc, 0x56, 0xe5, 0xac, + 0x85, 0xe6, 0x4a, 0xb7, 0x25, 0x37, 0x8d, 0x72, 0xb6, 0x12, 0x01, 0xf4, 0xd5, 0x4d, 0x89, 0xd3, 0xe5, 0xb2, 0x95, + 0x84, 0x7d, 0xfb, 0xbe, 0x9d, 0x2a, 0xf2, 0xf8, 0x28, 0x0d, 0x79, 0x05, 0x9e, 0x64, 0x1c, 0x49, 0xa2, 0x44, 0xf0, + 0x3a, 0x6f, 0xcc, 0x38, 0xbc, 0x68, 0x53, 0x4e, 0xed, 0xcd, 0x7a, 0x01, 0x38, 0x4f, 0xd0, 0x96, 0x01, 0xc6, 0x02, + 0x06, 0xe7, 0x42, 0x2c, 0x79, 0x8a, 0xe0, 0x97, 0x4e, 0xa4, 0x30, 0xee, 0x72, 0x18, 0xe6, 0x41, 0xd1, 0xbb, 0xa4, + 0xfe, 0xe8, 0xf7, 0x51, 0x9b, 0x0c, 0x86, 0xa0, 0x12, 0x40, 0x65, 0xdd, 0x20, 0x31, 0xb0, 0x2a, 0x2d, 0x24, 0x2e, + 0x21, 0x5e, 0xe6, 0xab, 0x69, 0x1d, 0x05, 0xef, 0xeb, 0x09, 0x21, 0x9c, 0x60, 0x7c, 0x88, 0x1b, 0x20, 0x60, 0xb0, + 0x8a, 0x0b, 0x0c, 0x92, 0xe7, 0x12, 0xdd, 0x1f, 0xcf, 0x77, 0x0c, 0x70, 0xe5, 0xbc, 0xa7, 0xda, 0xd5, 0x03, 0x7b, + 0xb9, 0x4a, 0x97, 0x8c, 0x10, 0x56, 0xfc, 0x5f, 0x44, 0xde, 0xb7, 0xc3, 0x04, 0xd4, 0x36, 0xf2, 0xc7, 0x20, 0x31, + 0x97, 0x89, 0x22, 0x88, 0x47, 0x59, 0xc1, 0x92, 0x34, 0xd8, 0x8c, 0x92, 0x14, 0x34, 0x9a, 0x18, 0x43, 0xa6, 0x42, + 0x3b, 0x24, 0x8d, 0x66, 0x63, 0xb2, 0x8f, 0x21, 0xaf, 0xe1, 0x62, 0xb1, 0xc0, 0xfb, 0x7e, 0x16, 0xaa, 0x83, 0x6d, + 0x69, 0x0e, 0x01, 0x27, 0x09, 0xf6, 0xd4, 0x15, 0x29, 0x09, 0xb3, 0xd1, 0xa7, 0x90, 0x73, 0x03, 0x3a, 0x4e, 0x1a, + 0x43, 0xf5, 0x81, 0x49, 0x78, 0x15, 0xa1, 0x93, 0xb2, 0x42, 0x58, 0xc0, 0x7d, 0x23, 0xa3, 0xd1, 0x4a, 0x1a, 0x04, + 0xde, 0x66, 0xd8, 0x0a, 0x6c, 0x42, 0xc3, 0x5f, 0x64, 0x1e, 0xa6, 0xd5, 0xac, 0x04, 0x73, 0xbe, 0x81, 0x4a, 0x8c, + 0x27, 0xcb, 0x2b, 0xbe, 0x71, 0xb1, 0x12, 0x93, 0xd9, 0x72, 0x3e, 0x59, 0x4b, 0xaa, 0xb9, 0xdc, 0x5b, 0xb3, 0x8c, + 0x2d, 0x61, 0xff, 0x30, 0x30, 0x94, 0x0e, 0xec, 0x68, 0xaa, 0x69, 0x93, 0x00, 0x93, 0xe9, 0x9c, 0xf3, 0xe1, 0x25, + 0xa2, 0xc9, 0xea, 0xd4, 0x9d, 0x4c, 0x55, 0x3b, 0xb8, 0x26, 0x67, 0x72, 0x7a, 0xa4, 0x9e, 0x6a, 0xdd, 0x4b, 0x3e, + 0xda, 0x0e, 0xab, 0xd1, 0xd6, 0x0f, 0xc0, 0xad, 0x53, 0xd8, 0xe9, 0xbb, 0x61, 0x35, 0xda, 0xf9, 0x1a, 0x76, 0x97, + 0x14, 0x02, 0xd5, 0x9f, 0x65, 0x4d, 0xe6, 0xe2, 0x75, 0xf1, 0xe0, 0x15, 0xec, 0xb9, 0x3f, 0xd0, 0xbf, 0x4a, 0xf6, + 0xdc, 0xb7, 0x99, 0x5c, 0xff, 0x4c, 0xbb, 0x46, 0x63, 0xa6, 0xe3, 0xb5, 0x2b, 0xb0, 0x42, 0x03, 0xe4, 0x17, 0xec, + 0x68, 0x6f, 0x72, 0x10, 0x08, 0xd0, 0xbd, 0x04, 0x47, 0x51, 0x40, 0xd4, 0xb4, 0xaa, 0x3c, 0x3a, 0xdd, 0xfb, 0x7b, + 0x7c, 0xa3, 0x04, 0x6c, 0xf2, 0xd4, 0xba, 0xb7, 0x8c, 0xfd, 0xc3, 0x01, 0x42, 0xe8, 0xe5, 0xf4, 0x1b, 0x6d, 0x59, + 0x3d, 0xda, 0xb1, 0xdc, 0x37, 0x8c, 0x7a, 0x0a, 0xc6, 0x30, 0x74, 0x61, 0x15, 0x23, 0x79, 0x06, 0x64, 0x8d, 0xdf, + 0x20, 0xba, 0x80, 0x45, 0xaf, 0xf7, 0xea, 0x88, 0x06, 0x11, 0x50, 0xe9, 0x35, 0x7f, 0x29, 0xf2, 0xb9, 0x2a, 0x44, + 0xef, 0xbd, 0xb5, 0xf3, 0x66, 0x46, 0xb2, 0x4c, 0x1a, 0xa9, 0x76, 0x2b, 0x8b, 0x75, 0xe5, 0xcd, 0x4e, 0x48, 0x17, + 0x73, 0x0c, 0x95, 0xc1, 0xe3, 0x00, 0x94, 0x9e, 0x7f, 0x0b, 0xbd, 0x92, 0x21, 0xd3, 0x2c, 0xd1, 0xcc, 0xee, 0x1a, + 0x7f, 0xb2, 0x4a, 0xbd, 0x18, 0x11, 0xb3, 0x81, 0x2d, 0xc4, 0x6d, 0x51, 0xe9, 0xb6, 0x28, 0x94, 0x2d, 0x8a, 0xf4, + 0xa1, 0x76, 0xa6, 0x3b, 0xb3, 0xf0, 0x59, 0x65, 0xda, 0xf7, 0x26, 0x33, 0x63, 0x03, 0xb4, 0x5d, 0x84, 0x6f, 0xa0, + 0x03, 0x15, 0x42, 0xfe, 0x03, 0x22, 0x22, 0x11, 0xb0, 0xcb, 0xa9, 0x3b, 0xb1, 0xe9, 0x90, 0xcc, 0x43, 0xcc, 0x0a, + 0x35, 0xca, 0x4b, 0x9e, 0x1c, 0x0d, 0x48, 0x45, 0xa8, 0xdb, 0xfd, 0xfe, 0xf9, 0xd2, 0x05, 0xb5, 0x5f, 0x53, 0xec, + 0x18, 0xdd, 0x14, 0x70, 0x2e, 0x78, 0x94, 0xf7, 0xdc, 0x3b, 0x07, 0x34, 0xc7, 0xf6, 0x14, 0x59, 0x03, 0x4e, 0x6f, + 0xbb, 0x10, 0x60, 0xfb, 0xac, 0xd9, 0xda, 0x9f, 0xac, 0xae, 0xa2, 0xa9, 0x57, 0xf2, 0x99, 0xee, 0xa2, 0xc4, 0xed, + 0xa2, 0x58, 0x76, 0xd1, 0xa6, 0x81, 0x60, 0xc7, 0x95, 0x1f, 0x00, 0x6f, 0x68, 0xd4, 0xef, 0x97, 0xad, 0x9e, 0x3d, + 0xf9, 0xda, 0x71, 0xcf, 0x66, 0x3e, 0x2b, 0x4d, 0xcf, 0xfe, 0x9a, 0xba, 0x3d, 0x2b, 0x27, 0x7b, 0xd1, 0x39, 0xd9, + 0xa7, 0xb3, 0x79, 0x20, 0xb8, 0xdc, 0xb9, 0xcf, 0xf3, 0xa9, 0x9e, 0x76, 0x95, 0x1f, 0xb4, 0x86, 0xc8, 0x7c, 0xe1, + 0x53, 0xd5, 0xbd, 0xae, 0x60, 0x01, 0x4b, 0x70, 0xb7, 0x5e, 0x9a, 0xff, 0x8a, 0xdd, 0xdf, 0x0b, 0x7a, 0x69, 0xfe, + 0x1b, 0xfd, 0x49, 0x01, 0x1c, 0x80, 0xc6, 0xd4, 0x6e, 0x81, 0x87, 0x18, 0x2a, 0x28, 0xdc, 0xcd, 0xca, 0xb9, 0x57, + 0x03, 0x1c, 0x26, 0xe9, 0x1b, 0x5a, 0xbd, 0xd2, 0x62, 0xd7, 0xcb, 0x64, 0xaf, 0x00, 0x0f, 0x55, 0xc8, 0xc3, 0xc3, + 0x21, 0xea, 0x18, 0x76, 0x50, 0x47, 0xc0, 0xb0, 0x87, 0xd0, 0xd8, 0x02, 0xcf, 0xc7, 0x4f, 0x19, 0xdf, 0x0b, 0x50, + 0x1b, 0x21, 0x3c, 0x5e, 0x2d, 0xca, 0x10, 0x5b, 0xf6, 0x06, 0xa9, 0xa4, 0x7e, 0x16, 0x88, 0x32, 0x5a, 0x05, 0xb4, + 0xd5, 0x1e, 0xb3, 0x34, 0xde, 0x40, 0xa8, 0x58, 0xea, 0x63, 0x08, 0x0d, 0x1c, 0x7e, 0x87, 0x03, 0x48, 0xf0, 0x25, + 0xd7, 0x64, 0x73, 0x6f, 0xf2, 0x7b, 0xda, 0xe7, 0x0f, 0x87, 0xf3, 0x4b, 0x04, 0xa5, 0x4b, 0xe1, 0x23, 0x95, 0x88, + 0xea, 0x29, 0x6e, 0x4a, 0xc8, 0x66, 0xc9, 0x4a, 0x3f, 0xf8, 0x55, 0xfd, 0x02, 0x00, 0x59, 0x08, 0xb4, 0x89, 0xcc, + 0xfe, 0x74, 0xa6, 0xa2, 0x0b, 0x80, 0x43, 0xfc, 0xf1, 0x13, 0x44, 0xdf, 0xd0, 0x32, 0x2d, 0x1f, 0x27, 0x3c, 0x04, + 0xad, 0x2d, 0xe9, 0x24, 0x62, 0xa5, 0xc0, 0x86, 0x48, 0xf8, 0x7e, 0xff, 0x3c, 0x96, 0x74, 0xa0, 0x51, 0xab, 0x7b, + 0xe3, 0x56, 0xf7, 0xca, 0xd7, 0x75, 0x27, 0x37, 0x3e, 0x28, 0xda, 0x67, 0xf3, 0x46, 0xe5, 0xfb, 0xb6, 0xce, 0xd9, + 0x9d, 0xee, 0x1d, 0x39, 0x27, 0xbe, 0xbd, 0x87, 0x50, 0xf4, 0xd0, 0x14, 0x59, 0x96, 0x84, 0x01, 0xad, 0xb5, 0x6b, + 0xcf, 0x32, 0x3a, 0x78, 0xed, 0x1b, 0x42, 0x44, 0x9e, 0xe2, 0x93, 0x90, 0x5b, 0x1c, 0x1f, 0x14, 0xe8, 0x9f, 0x19, + 0x7f, 0xe6, 0xc4, 0x0f, 0x5b, 0xfd, 0x02, 0x38, 0x37, 0xdd, 0x7b, 0x77, 0x62, 0xd6, 0x63, 0x28, 0x65, 0xe3, 0xff, + 0x7e, 0x9f, 0xc8, 0x02, 0x9d, 0x8e, 0x68, 0x18, 0x08, 0xee, 0xa2, 0xfa, 0xbf, 0x57, 0xbc, 0xee, 0x59, 0xab, 0xf3, + 0xe5, 0xa7, 0x4e, 0x4f, 0x7a, 0xf5, 0x32, 0xee, 0x01, 0x15, 0x3a, 0x40, 0x38, 0xaf, 0xfb, 0x0d, 0xdb, 0x7d, 0xf3, + 0xcb, 0xbb, 0xa3, 0x97, 0x81, 0x4d, 0x8a, 0xc4, 0xb6, 0x92, 0xcf, 0x7a, 0xa0, 0xf0, 0xeb, 0xb1, 0x5e, 0x5d, 0xac, + 0x7b, 0xac, 0x87, 0x5a, 0x40, 0xf4, 0xb0, 0x00, 0xf5, 0x5f, 0xcf, 0x3e, 0x0d, 0x85, 0x83, 0x6c, 0x9c, 0x2a, 0x50, + 0x64, 0xc1, 0xaf, 0xc5, 0x68, 0x5d, 0x10, 0x20, 0xb2, 0x25, 0xa4, 0x55, 0x27, 0xb3, 0xc7, 0xa5, 0x96, 0x64, 0xf0, + 0x4d, 0x40, 0x66, 0x07, 0x56, 0x4e, 0x50, 0x3a, 0x6e, 0x0d, 0xb8, 0xb2, 0xc5, 0xa3, 0xdd, 0xfe, 0x34, 0xc8, 0xce, + 0x9a, 0x93, 0x46, 0xfb, 0xb0, 0x4f, 0xf3, 0x00, 0x81, 0x48, 0xa6, 0x22, 0xc8, 0x35, 0xf7, 0x96, 0xf4, 0xd1, 0xe1, + 0x9c, 0x17, 0xf2, 0xcf, 0xa9, 0xd4, 0x21, 0x0e, 0x25, 0xd6, 0x40, 0xa0, 0xf2, 0x0c, 0x55, 0x0e, 0x1b, 0xe4, 0xf8, + 0x67, 0x47, 0x32, 0x93, 0x98, 0x2c, 0x72, 0xb7, 0x66, 0x2a, 0xfc, 0x40, 0xf0, 0x31, 0xcb, 0x39, 0x70, 0x81, 0xcd, + 0xe6, 0xbe, 0x9a, 0xe2, 0xe2, 0x0a, 0xfc, 0x31, 0x85, 0x5f, 0xf1, 0x14, 0x76, 0xda, 0xfd, 0xba, 0xa8, 0x52, 0xd4, + 0x6d, 0x14, 0x16, 0x95, 0x2c, 0x98, 0xd6, 0x90, 0x26, 0x3a, 0x8c, 0xfe, 0x20, 0x67, 0xa0, 0x20, 0xe4, 0x97, 0x4d, + 0x03, 0x8c, 0x54, 0x72, 0x79, 0x50, 0x25, 0x81, 0x17, 0x60, 0x1b, 0x54, 0x6c, 0x5d, 0x40, 0x90, 0x6d, 0x52, 0x94, + 0xe9, 0x97, 0x22, 0xaf, 0xc3, 0x2c, 0xa8, 0x46, 0x69, 0xf5, 0xa3, 0xfe, 0x09, 0xcc, 0xdb, 0x54, 0x8c, 0x6a, 0x15, + 0x93, 0xdf, 0xe8, 0xf7, 0x8b, 0x41, 0xeb, 0x43, 0x06, 0x1f, 0xbd, 0x36, 0x0d, 0xfe, 0xe8, 0x34, 0xd8, 0x61, 0xa2, + 0x11, 0x00, 0xc9, 0x9c, 0x5a, 0xf2, 0x50, 0xf4, 0x47, 0x90, 0x63, 0x8d, 0x2a, 0xa7, 0x60, 0xb0, 0xfe, 0xe3, 0xd1, + 0x0e, 0x4c, 0xbd, 0x38, 0xda, 0x92, 0x1d, 0xb4, 0xf2, 0x0d, 0x70, 0xbf, 0x46, 0xb6, 0x98, 0xe5, 0x00, 0xcd, 0x5e, + 0x23, 0x32, 0x3e, 0x79, 0x01, 0x8c, 0xd9, 0x3a, 0x0b, 0x23, 0x11, 0x07, 0x63, 0xd5, 0x98, 0x31, 0x03, 0x03, 0x17, + 0xe8, 0x5a, 0x26, 0x25, 0x69, 0x48, 0x07, 0x03, 0x56, 0xca, 0x16, 0x0e, 0x78, 0xd1, 0x1c, 0xb7, 0xe3, 0x75, 0x8b, + 0xc6, 0x03, 0xdb, 0xc5, 0xf6, 0xf7, 0xdf, 0x17, 0xdb, 0xb7, 0xe1, 0x96, 0xf4, 0x0a, 0x39, 0x4b, 0xe8, 0xe7, 0x8f, + 0xb2, 0xcf, 0x1a, 0x4e, 0x4e, 0x85, 0x66, 0x68, 0x29, 0x12, 0x4a, 0xf1, 0x4e, 0x4f, 0x0a, 0x8c, 0x65, 0x2c, 0xfc, + 0x3d, 0x70, 0x4e, 0x17, 0x8a, 0xc8, 0x1d, 0x38, 0x8e, 0x6f, 0xa0, 0x82, 0x51, 0xc3, 0xc1, 0xcb, 0x18, 0xb6, 0x45, + 0x31, 0x0b, 0x09, 0xa7, 0x10, 0x2e, 0x56, 0x59, 0xbf, 0x2f, 0x7f, 0x51, 0x17, 0x5d, 0x64, 0xb2, 0xee, 0x93, 0x70, + 0x64, 0xc6, 0x72, 0xea, 0x85, 0xe4, 0x79, 0xcf, 0x93, 0x69, 0xf2, 0x2c, 0x0f, 0x22, 0x80, 0x7c, 0x0e, 0xef, 0xc3, + 0x34, 0x03, 0xab, 0x34, 0x29, 0x3f, 0x42, 0xe9, 0x8b, 0xcf, 0x2b, 0x3f, 0xd0, 0xd9, 0x73, 0x93, 0x0c, 0x6f, 0x56, + 0xad, 0x37, 0xa9, 0x75, 0x5d, 0x3c, 0xe0, 0x5f, 0x9c, 0xc1, 0xc6, 0xb9, 0xce, 0x04, 0x07, 0x5e, 0x24, 0xb5, 0x5e, + 0x33, 0x7e, 0x9d, 0xe1, 0xba, 0x54, 0x6d, 0xf4, 0x51, 0x88, 0xce, 0x21, 0x53, 0x01, 0x0a, 0x45, 0xda, 0x3f, 0x28, + 0xb5, 0x32, 0xa9, 0xb4, 0x91, 0x00, 0xba, 0x87, 0x49, 0x83, 0x2d, 0x86, 0x32, 0x96, 0x26, 0x51, 0xee, 0x34, 0x88, + 0x2b, 0xfb, 0x73, 0x25, 0x71, 0x68, 0x59, 0x24, 0xff, 0xde, 0xf5, 0xf4, 0x15, 0x52, 0x77, 0xb2, 0x40, 0x66, 0x8c, + 0x17, 0x79, 0xfc, 0x09, 0x08, 0xb3, 0x41, 0x1b, 0x15, 0x85, 0x10, 0xb2, 0x41, 0x0c, 0x1a, 0x2f, 0xf2, 0xf8, 0x7b, + 0x45, 0xe3, 0x21, 0x1f, 0x45, 0xbe, 0xfa, 0xab, 0xd4, 0x7f, 0x85, 0x3e, 0x33, 0xc1, 0x23, 0x54, 0x13, 0xfd, 0xbb, + 0xe7, 0xb3, 0x7b, 0x50, 0x1b, 0x46, 0x61, 0x66, 0xca, 0xaf, 0x7c, 0x53, 0x9c, 0xbd, 0xfe, 0x8a, 0xae, 0xb2, 0xad, + 0xfb, 0xd1, 0xc7, 0x23, 0x02, 0x6b, 0x63, 0x74, 0xc5, 0x8d, 0x01, 0xe4, 0x30, 0x79, 0xbf, 0xa2, 0xb4, 0x1c, 0xd2, + 0x20, 0x74, 0xd0, 0x10, 0xf4, 0x4a, 0xa2, 0x0f, 0x24, 0x16, 0x31, 0x86, 0x17, 0xe2, 0x19, 0xa9, 0xc9, 0x44, 0x43, + 0xbc, 0x22, 0xf6, 0x43, 0xb4, 0xe4, 0xd4, 0x44, 0x37, 0xc2, 0x14, 0x03, 0x89, 0x9d, 0x41, 0x72, 0x92, 0xd4, 0xca, + 0x2f, 0x9e, 0x49, 0xc2, 0x12, 0x3b, 0x0f, 0x31, 0x98, 0xd4, 0xd2, 0x9d, 0xde, 0x54, 0xe9, 0xdd, 0x91, 0x96, 0x83, + 0xf6, 0x01, 0xd8, 0xa5, 0xa4, 0xf7, 0x4f, 0x0a, 0x45, 0x7c, 0x08, 0xe3, 0x18, 0xc2, 0xb7, 0x88, 0xea, 0x0a, 0x9c, + 0x6b, 0x05, 0x1a, 0xab, 0x81, 0x87, 0x66, 0x56, 0xcd, 0x87, 0x9c, 0x7e, 0x2a, 0x2d, 0x7f, 0x8c, 0x68, 0x6c, 0xb4, + 0x6e, 0x0e, 0x87, 0x3d, 0xad, 0x7a, 0xe9, 0x1c, 0x74, 0xd9, 0x4c, 0x62, 0xe2, 0x06, 0xd2, 0xf5, 0xa3, 0xdf, 0x4c, + 0xd8, 0x8b, 0xa8, 0x90, 0x4b, 0x21, 0x28, 0x68, 0x75, 0x20, 0x70, 0x28, 0xbc, 0x45, 0x99, 0x2f, 0x62, 0xda, 0x40, + 0x18, 0x7c, 0x7e, 0x20, 0x3f, 0xdf, 0x14, 0xa4, 0x62, 0xc7, 0xba, 0xf6, 0xfb, 0x9b, 0xd2, 0x03, 0x3c, 0x39, 0x93, + 0xe4, 0x69, 0x33, 0x84, 0x15, 0x01, 0x34, 0x66, 0x35, 0x59, 0x9c, 0x70, 0x65, 0x0e, 0x3f, 0x56, 0x5e, 0xc9, 0x52, + 0xa6, 0xce, 0x53, 0xbd, 0x00, 0xa2, 0x8e, 0x37, 0x68, 0x45, 0xea, 0x57, 0xe8, 0xec, 0x35, 0x2b, 0x21, 0xe3, 0xe1, + 0x39, 0xe7, 0xe9, 0xe8, 0x81, 0x25, 0x3c, 0xc2, 0xbf, 0x92, 0x89, 0x3e, 0xfc, 0x1e, 0x38, 0xdc, 0x8c, 0x13, 0x1e, + 0xb9, 0xcd, 0xde, 0x57, 0xe1, 0x0a, 0x6e, 0xa6, 0x05, 0x20, 0xb9, 0x05, 0x49, 0x13, 0x50, 0x42, 0x22, 0x13, 0x32, + 0x6b, 0x4a, 0x7e, 0x6e, 0x69, 0x1b, 0xac, 0x61, 0xd2, 0x79, 0xc0, 0x8b, 0x56, 0x1f, 0xad, 0x26, 0xda, 0x65, 0x96, + 0xcf, 0x87, 0x38, 0x43, 0x35, 0xc7, 0xdd, 0x19, 0xfc, 0x1c, 0xf0, 0x8a, 0x55, 0x4d, 0x3a, 0xda, 0x0d, 0xb8, 0xf0, + 0xe4, 0x3a, 0x4f, 0x47, 0x5b, 0xfc, 0x25, 0xf7, 0x07, 0x80, 0x0e, 0xa6, 0x2e, 0x81, 0x3f, 0x55, 0x5b, 0x4d, 0xa5, + 0x7e, 0x69, 0xed, 0xd7, 0x75, 0x67, 0xb5, 0x72, 0xcf, 0xba, 0x0c, 0xed, 0x91, 0x21, 0x67, 0xcc, 0x80, 0x3f, 0x67, + 0x2c, 0xf9, 0x73, 0xc6, 0x8a, 0x3f, 0x67, 0xdc, 0x18, 0x19, 0x40, 0x09, 0xee, 0x25, 0xbf, 0xde, 0x23, 0x66, 0x88, + 0xd5, 0xa0, 0x12, 0x58, 0x59, 0xca, 0xb9, 0x8f, 0x9c, 0x62, 0xca, 0x29, 0xc3, 0x4b, 0xa7, 0x33, 0x77, 0x20, 0xe7, + 0xc1, 0xcc, 0x1d, 0x26, 0x67, 0x7d, 0x8a, 0x63, 0x69, 0x4c, 0x8a, 0x0a, 0xd2, 0x39, 0x1d, 0x6e, 0x5e, 0x1d, 0xe7, + 0x09, 0xcb, 0xf8, 0xb8, 0x7d, 0xa6, 0x40, 0x88, 0x2d, 0x9e, 0x21, 0x91, 0x52, 0x35, 0xcb, 0x6d, 0xfe, 0x70, 0xa8, + 0x47, 0x0f, 0x7a, 0xa7, 0x87, 0x5f, 0x09, 0xfb, 0x25, 0xf3, 0xec, 0x13, 0x04, 0x30, 0x49, 0xe4, 0x99, 0x84, 0xa3, + 0x1f, 0xcb, 0xd1, 0xdf, 0x34, 0xfc, 0x5d, 0x86, 0xea, 0xee, 0x10, 0x98, 0xd8, 0xb2, 0x03, 0x87, 0xe0, 0x74, 0x55, + 0x89, 0x04, 0x1c, 0x6c, 0x36, 0x2c, 0xd2, 0x7b, 0x3c, 0xc4, 0xf9, 0xa0, 0xf0, 0x11, 0x1a, 0x66, 0xf4, 0x7e, 0x7f, + 0x23, 0xbc, 0x4a, 0xb6, 0xf2, 0x70, 0x48, 0xac, 0xbb, 0xb0, 0xa3, 0x8f, 0xa3, 0x3d, 0x4a, 0xa8, 0xfd, 0xa8, 0xd6, + 0x9b, 0x4a, 0x3d, 0xc8, 0xcd, 0x2e, 0x24, 0x06, 0x15, 0x4b, 0xf5, 0xe9, 0x95, 0xea, 0x43, 0xcd, 0x3a, 0xbf, 0xab, + 0xe3, 0x3e, 0x15, 0xa3, 0xb5, 0x9c, 0x10, 0xe0, 0x3a, 0x48, 0x34, 0x3a, 0x00, 0xc6, 0xd9, 0x66, 0xcb, 0x4b, 0x6d, + 0x9d, 0x28, 0x1d, 0xc7, 0xb9, 0x3e, 0x8e, 0x0f, 0x07, 0x29, 0x66, 0x5c, 0x1e, 0x89, 0x19, 0x97, 0x0d, 0xc0, 0x9b, + 0x75, 0x1e, 0xd4, 0x87, 0xc3, 0x25, 0x5d, 0x8a, 0x4c, 0x67, 0x1b, 0xe5, 0x67, 0x3d, 0x7a, 0x78, 0x96, 0xa0, 0xb9, + 0xb7, 0xc2, 0xde, 0x8b, 0x64, 0x7b, 0x26, 0xeb, 0xd4, 0xcb, 0xc8, 0xa7, 0x17, 0xee, 0xd9, 0x25, 0x57, 0x3f, 0xac, + 0xbe, 0x9e, 0xfe, 0x2a, 0xbc, 0x88, 0x55, 0xb4, 0x5b, 0x97, 0x4c, 0xd8, 0x5b, 0x4a, 0x25, 0xad, 0xf2, 0xf2, 0xe9, + 0xc6, 0x0f, 0x30, 0x33, 0xed, 0xe9, 0x83, 0x6c, 0x44, 0xf5, 0x67, 0x25, 0x6a, 0x65, 0x98, 0x2c, 0x9c, 0x97, 0x4c, + 0x3d, 0x19, 0xf0, 0x98, 0x95, 0x3c, 0x92, 0x9d, 0xde, 0x18, 0x04, 0x01, 0xac, 0x73, 0xd2, 0xaa, 0x33, 0x8e, 0x46, + 0xab, 0xca, 0xc5, 0xe9, 0x2a, 0x17, 0x18, 0x6e, 0xb7, 0x66, 0x1b, 0x55, 0x67, 0xb9, 0xa9, 0x55, 0xca, 0x77, 0x00, + 0x1f, 0xcb, 0x2a, 0x17, 0x74, 0x4c, 0x99, 0x3a, 0x6f, 0x20, 0x18, 0x5b, 0xd5, 0xb8, 0x70, 0x6a, 0x5c, 0xf0, 0x88, + 0xda, 0xdd, 0x34, 0xf5, 0x68, 0x0b, 0x2c, 0xa5, 0xa3, 0x1d, 0x2f, 0x51, 0xa5, 0xf0, 0x77, 0xc1, 0xf7, 0x61, 0x1c, + 0x7f, 0x5f, 0x6c, 0xd5, 0x81, 0x78, 0x5b, 0x6c, 0x91, 0xf6, 0x45, 0xfe, 0x85, 0x38, 0xe0, 0xb5, 0xae, 0x29, 0xaf, + 0xad, 0x39, 0x0d, 0x6c, 0x0d, 0x23, 0x25, 0x85, 0x73, 0xf3, 0xe7, 0xe1, 0x40, 0x2b, 0xbb, 0x56, 0x77, 0x85, 0x5a, + 0x8f, 0x39, 0x6c, 0xd8, 0x8b, 0x2c, 0xdc, 0x89, 0x12, 0x1c, 0xb9, 0xe4, 0x5f, 0x87, 0x83, 0x56, 0x59, 0xaa, 0x23, + 0x7d, 0xb6, 0xff, 0x12, 0x8c, 0x19, 0xba, 0x34, 0x01, 0xcb, 0xc6, 0x48, 0xfe, 0xd5, 0x34, 0xf3, 0x86, 0xc9, 0x9a, + 0x29, 0x1c, 0x87, 0x86, 0x11, 0xd2, 0x80, 0x6e, 0x83, 0xda, 0xf0, 0x64, 0xbe, 0xa9, 0xca, 0xaf, 0xee, 0x48, 0xb5, + 0x1f, 0x0c, 0x2f, 0x27, 0xe2, 0x9c, 0x2e, 0x49, 0xea, 0xa9, 0x84, 0x92, 0x10, 0xec, 0xd2, 0x07, 0x72, 0x62, 0x05, + 0x64, 0x2d, 0x63, 0xf9, 0xad, 0x1e, 0x10, 0xfa, 0x4f, 0xbb, 0xf5, 0x42, 0xff, 0x69, 0x9a, 0x2d, 0xd4, 0xf5, 0x87, + 0xc9, 0x7d, 0x47, 0xaf, 0x3f, 0x38, 0xbc, 0x53, 0x57, 0x15, 0x57, 0xf1, 0xb0, 0x36, 0x4c, 0x72, 0xa3, 0x2c, 0xdc, + 0x15, 0x9b, 0x5a, 0x2d, 0x4f, 0xc7, 0x61, 0x04, 0x66, 0x04, 0x05, 0xc8, 0xba, 0x6e, 0x23, 0x62, 0x58, 0xc9, 0x65, + 0x42, 0x3e, 0x21, 0x20, 0x8b, 0x52, 0xe3, 0x7c, 0xdc, 0x02, 0x95, 0x08, 0x06, 0xa7, 0xa1, 0xb5, 0xea, 0x26, 0x3f, + 0xaa, 0x6c, 0xec, 0x0e, 0xc8, 0x21, 0xc9, 0x64, 0x71, 0x37, 0xba, 0x15, 0xcb, 0xa2, 0x14, 0x3f, 0x63, 0x3d, 0x5c, + 0xb3, 0x85, 0xfb, 0x0c, 0x08, 0xed, 0x27, 0x4a, 0x7b, 0x13, 0x69, 0x82, 0xee, 0x3b, 0xb6, 0x02, 0x90, 0x01, 0x14, + 0x75, 0xb5, 0x5b, 0x9f, 0xf3, 0x73, 0x24, 0xcd, 0x70, 0x18, 0xdd, 0x3e, 0xbd, 0x0b, 0xee, 0x06, 0x97, 0xa8, 0x95, + 0xbe, 0x64, 0x71, 0x0b, 0x83, 0x6a, 0x6f, 0x96, 0x70, 0x50, 0x33, 0x6b, 0x6d, 0x04, 0x82, 0xc9, 0x1e, 0x0a, 0x2a, + 0xe6, 0x0a, 0xf6, 0x41, 0xc1, 0x5a, 0xf2, 0x3a, 0x38, 0xdc, 0xda, 0x97, 0x95, 0xe2, 0xe2, 0xf9, 0x45, 0xd2, 0xba, + 0xb0, 0x94, 0x17, 0xcf, 0x1b, 0x30, 0xb8, 0x1c, 0x61, 0x53, 0x55, 0xfe, 0x64, 0x03, 0xa0, 0x5b, 0x21, 0x45, 0xbc, + 0x28, 0x85, 0x6d, 0x2b, 0x9f, 0x39, 0x61, 0x83, 0x0d, 0x7b, 0x80, 0x7b, 0x65, 0x50, 0x32, 0xb8, 0x10, 0xe3, 0x76, + 0xb3, 0x0b, 0x70, 0x05, 0x43, 0x61, 0x6c, 0xcd, 0x5f, 0x67, 0x5e, 0xa4, 0x04, 0xdc, 0x0c, 0x51, 0xbe, 0x36, 0x70, + 0x32, 0xe9, 0xc9, 0xb5, 0x64, 0x31, 0x60, 0x41, 0x83, 0xef, 0xa8, 0xf5, 0x77, 0x26, 0xff, 0xc6, 0xd3, 0x43, 0x3f, + 0xf8, 0x9c, 0x79, 0x4b, 0x9f, 0xbd, 0xae, 0x64, 0xb4, 0x26, 0x89, 0xf2, 0xea, 0xe1, 0x12, 0xe4, 0x86, 0xe5, 0xe8, + 0x81, 0x2d, 0x41, 0x9c, 0x58, 0x8e, 0x12, 0xca, 0xe8, 0x0a, 0xf7, 0x2a, 0xb3, 0x65, 0x22, 0x90, 0xe2, 0xc0, 0x52, + 0xca, 0xbd, 0xc5, 0x3a, 0x58, 0xe2, 0xfe, 0x44, 0x72, 0x01, 0x25, 0x0f, 0xa0, 0x5c, 0x29, 0x20, 0xe0, 0xd3, 0x01, + 0x94, 0x2f, 0xe5, 0x45, 0xf8, 0x13, 0x27, 0x6a, 0xb0, 0x1c, 0x3d, 0x34, 0xec, 0x47, 0x2f, 0xb4, 0xec, 0x0f, 0x77, + 0x5a, 0xd3, 0xb0, 0xe2, 0x77, 0x30, 0x2d, 0x26, 0x6e, 0x5f, 0xae, 0xec, 0xaa, 0xf8, 0x6c, 0xa5, 0xce, 0x6e, 0x6a, + 0x48, 0xc2, 0xbe, 0x22, 0xab, 0x00, 0x07, 0xab, 0x22, 0xee, 0x59, 0x96, 0xfb, 0x30, 0xfa, 0x73, 0x93, 0x96, 0xc2, + 0x42, 0x95, 0xf4, 0xf7, 0x4d, 0x29, 0x90, 0xca, 0x44, 0x27, 0x5a, 0x08, 0xae, 0xc0, 0x20, 0x70, 0x2f, 0xf2, 0x1a, + 0x00, 0x63, 0xc0, 0xa5, 0x40, 0x59, 0xb6, 0x25, 0x84, 0x54, 0xf7, 0x33, 0x50, 0xdb, 0x89, 0xfb, 0x34, 0x22, 0x6b, + 0x21, 0xfa, 0x2a, 0x18, 0x33, 0xe7, 0xa5, 0x74, 0x8b, 0x4d, 0x57, 0x9b, 0xd5, 0x0d, 0x3a, 0x97, 0xb6, 0xdc, 0xfc, + 0x84, 0x2d, 0xd6, 0x0a, 0x94, 0x4d, 0x48, 0xda, 0xce, 0x79, 0x8e, 0xb2, 0x09, 0x2d, 0xed, 0x3d, 0xf5, 0xa8, 0x50, + 0x9d, 0x6c, 0xbd, 0x54, 0x4d, 0x2d, 0xc2, 0x6a, 0x71, 0x51, 0xf9, 0x01, 0xe8, 0xa6, 0xd2, 0xea, 0x45, 0x5d, 0xa3, + 0x29, 0xd4, 0x6a, 0xe1, 0xb8, 0xd1, 0xce, 0xa6, 0xcb, 0xf4, 0x0e, 0x71, 0x56, 0xa5, 0x1d, 0xfa, 0xfb, 0x4c, 0xbb, + 0x5e, 0x76, 0xf4, 0x9b, 0x71, 0x75, 0x81, 0x0b, 0xb1, 0x01, 0x9f, 0x73, 0x7f, 0x79, 0xbd, 0xe7, 0x71, 0xcf, 0x3f, + 0x1c, 0x90, 0x3d, 0xa9, 0xfd, 0xa1, 0xfa, 0xd8, 0x15, 0x0c, 0x59, 0x18, 0xa5, 0xfe, 0x22, 0xe5, 0xbd, 0x27, 0x38, + 0xee, 0x9f, 0xab, 0x1e, 0xfb, 0x31, 0xe3, 0xfb, 0xba, 0xd8, 0x44, 0x09, 0x45, 0x35, 0xf4, 0x56, 0xc5, 0xa6, 0x12, + 0x71, 0xf1, 0x90, 0xf7, 0x18, 0x26, 0xc3, 0x58, 0xc8, 0x54, 0xf8, 0x53, 0xa6, 0x82, 0x47, 0x08, 0x25, 0x6e, 0xd6, + 0x3d, 0xd2, 0x6e, 0x42, 0x9c, 0x52, 0x2d, 0x4a, 0x99, 0x8c, 0x7f, 0xeb, 0x27, 0x50, 0x9e, 0x53, 0xb4, 0x4c, 0x3f, + 0x2a, 0x5c, 0xa6, 0x6f, 0xd6, 0xc7, 0xa5, 0x67, 0x22, 0xd4, 0x99, 0x8b, 0x4d, 0xad, 0xd3, 0x31, 0x76, 0x4a, 0xa7, + 0x36, 0xec, 0x4b, 0xa5, 0xb8, 0xac, 0x28, 0xfc, 0x1b, 0x89, 0xac, 0x7a, 0x46, 0x1c, 0xff, 0x57, 0xd6, 0x3e, 0xc3, + 0x2a, 0xf0, 0xcb, 0x40, 0xde, 0x2f, 0x00, 0x3e, 0xae, 0xeb, 0x32, 0xbd, 0xdd, 0x00, 0x6d, 0x08, 0x0d, 0x7f, 0xcf, + 0x47, 0x06, 0x4c, 0xf7, 0x11, 0xce, 0x90, 0x1e, 0xea, 0x9c, 0xd3, 0x59, 0x99, 0xce, 0xb9, 0x0a, 0x6b, 0x09, 0xf6, + 0x72, 0xd2, 0xe4, 0x72, 0x5d, 0x82, 0x9a, 0x09, 0xdc, 0x3e, 0xb4, 0x47, 0x84, 0x50, 0x9b, 0xb2, 0x9a, 0x5e, 0x42, + 0xcd, 0x3b, 0x39, 0xed, 0x68, 0x52, 0x82, 0xab, 0x86, 0xce, 0xca, 0xf5, 0x5f, 0x87, 0x43, 0xef, 0x36, 0x2b, 0xa2, + 0x3f, 0x7a, 0xe8, 0xef, 0xb8, 0xbd, 0x49, 0xbf, 0x40, 0xb4, 0x8c, 0xf5, 0x37, 0x64, 0x40, 0xc7, 0x93, 0xe1, 0x6d, + 0xb1, 0xed, 0xb1, 0x2f, 0xa8, 0xc1, 0xd2, 0xd7, 0x8f, 0x3f, 0x40, 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, + 0x89, 0xb6, 0x85, 0x0f, 0x61, 0xa1, 0x5f, 0x20, 0x32, 0x12, 0xc2, 0x4d, 0x65, 0xf7, 0x28, 0x69, 0x17, 0xfa, 0xd2, + 0xd7, 0xb2, 0xaf, 0x7c, 0xe7, 0x02, 0x60, 0x65, 0x9f, 0xdb, 0x70, 0x4f, 0xfa, 0x53, 0xaa, 0x0f, 0xdb, 0xdf, 0x92, + 0x05, 0x14, 0x5a, 0x58, 0x4f, 0xe5, 0xec, 0x5c, 0x97, 0x3c, 0xcd, 0xa6, 0xfb, 0x35, 0xec, 0x51, 0xf7, 0xe8, 0x35, + 0x15, 0x9c, 0x5f, 0x9a, 0xd1, 0xfb, 0xa7, 0xa1, 0x50, 0x1d, 0x75, 0xee, 0x20, 0xeb, 0xd2, 0xba, 0xe4, 0xfc, 0x66, + 0xe5, 0x8e, 0xc2, 0xfc, 0x3e, 0x04, 0xcf, 0xb0, 0xee, 0xdd, 0xc5, 0x79, 0xef, 0xcf, 0xd6, 0x1c, 0xf9, 0x31, 0x9b, + 0xa5, 0x88, 0x45, 0x32, 0x07, 0xab, 0x1f, 0xfa, 0x79, 0xec, 0xb7, 0x41, 0x0e, 0xc7, 0x4d, 0x03, 0x3a, 0x6c, 0xc8, + 0xac, 0x7d, 0x89, 0xc0, 0xa9, 0x46, 0x90, 0xa6, 0x26, 0xa8, 0x59, 0x1e, 0x22, 0xb1, 0x5d, 0xca, 0xb6, 0x41, 0xae, + 0xbb, 0x60, 0x9a, 0x23, 0xed, 0x19, 0xbc, 0x6f, 0xd2, 0x24, 0x15, 0x9a, 0x45, 0xda, 0x2a, 0x19, 0xff, 0x8e, 0xb4, + 0x99, 0x92, 0x3d, 0xb6, 0x06, 0xde, 0x4b, 0x50, 0x4e, 0x86, 0x29, 0x86, 0xef, 0xf8, 0x7a, 0xe7, 0x31, 0xf7, 0x9c, + 0x63, 0xb6, 0x49, 0xd9, 0x11, 0x4c, 0x92, 0x8d, 0x6f, 0x28, 0xde, 0xf0, 0xfd, 0x6d, 0x25, 0x4a, 0x00, 0xbd, 0x2c, + 0xf8, 0xb5, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, + 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, + 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, + 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, + 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x52, 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, + 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, + 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, 0x4b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, + 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, + 0xf3, 0xfd, 0xa5, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, + 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, 0xa5, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, + 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, + 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, + 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, + 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, + 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, + 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, + 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, + 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, + 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, + 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, + 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, + 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, + 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, + 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, + 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, + 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, + 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, + 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, + 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, + 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, + 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, + 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd2, 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, + 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe2, + 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, + 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, + 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, + 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, + 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, + 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, + 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, + 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, + 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, + 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, + 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, + 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, + 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0xbc, 0x56, 0x2b, 0xed, 0xac, 0x4c, 0xbc, 0x9a, 0x65, 0xe0, 0x2c, 0x70, 0x51, 0xf9, + 0x2c, 0xd3, 0xaa, 0xa7, 0x2a, 0x41, 0x9f, 0x57, 0x72, 0x82, 0x2b, 0xc1, 0xc9, 0x06, 0xe4, 0x17, 0x20, 0x49, 0x53, + 0xca, 0x9a, 0xf2, 0xfa, 0x92, 0x6e, 0xc8, 0xe8, 0x39, 0xef, 0x79, 0xd1, 0x30, 0xf4, 0x2f, 0xbc, 0x12, 0xc2, 0x37, + 0x71, 0xdb, 0x46, 0x29, 0xec, 0x6f, 0x02, 0x8b, 0x4f, 0xd8, 0x0f, 0xde, 0xd2, 0x9f, 0x8e, 0x83, 0x70, 0x88, 0xdc, + 0x50, 0x31, 0x07, 0xf6, 0x34, 0x60, 0xb1, 0x89, 0xaf, 0x36, 0x93, 0x78, 0x30, 0xf0, 0x75, 0xc6, 0x62, 0x16, 0x03, + 0x0d, 0x72, 0x3c, 0xb8, 0x9c, 0xeb, 0x13, 0x42, 0x3f, 0x8c, 0xa8, 0x1c, 0x15, 0xe8, 0x1c, 0x44, 0x83, 0x25, 0xe0, + 0xa9, 0xb7, 0xb2, 0x41, 0x92, 0x31, 0xc9, 0x24, 0xae, 0x35, 0x49, 0x75, 0x38, 0xa1, 0x75, 0xa0, 0xe3, 0xea, 0x02, + 0x3a, 0x1f, 0xd7, 0xbd, 0x8f, 0x57, 0xc3, 0x05, 0x95, 0x7e, 0x21, 0x06, 0x5e, 0x3d, 0x1d, 0x07, 0x97, 0x74, 0x2b, + 0x5c, 0xac, 0xc2, 0xed, 0xcf, 0xf2, 0x81, 0xe3, 0x8e, 0x4a, 0x1a, 0x02, 0x83, 0xb7, 0x87, 0xee, 0x66, 0x86, 0x86, + 0x3a, 0x69, 0x1f, 0xc6, 0xa1, 0x1c, 0x62, 0xd5, 0x8a, 0x0b, 0xe9, 0x8d, 0xe0, 0xdb, 0x85, 0x62, 0x2c, 0x1b, 0xbb, + 0x34, 0x14, 0x85, 0xbf, 0x02, 0xd8, 0xa1, 0xf6, 0x57, 0x2a, 0xf9, 0x18, 0x19, 0xd5, 0x34, 0xd0, 0x31, 0x00, 0x4b, + 0x96, 0x26, 0x92, 0x2a, 0xd2, 0x48, 0xfc, 0x91, 0x19, 0xeb, 0xa8, 0xe9, 0xfa, 0x82, 0xa9, 0x6a, 0x91, 0x74, 0x3b, + 0x93, 0x58, 0x4e, 0x24, 0xa9, 0xed, 0x3e, 0x22, 0x06, 0x03, 0x1f, 0x6c, 0xc4, 0x34, 0x13, 0xe1, 0x88, 0x47, 0x25, + 0xb2, 0xe8, 0xf2, 0xdb, 0x28, 0x93, 0xb6, 0x2f, 0x2b, 0xb2, 0x05, 0xc1, 0xf4, 0x24, 0xfa, 0x20, 0x49, 0x39, 0x15, + 0x89, 0x34, 0x23, 0x04, 0xf8, 0xf1, 0xa4, 0xbc, 0xd2, 0x9f, 0x83, 0xa6, 0x95, 0xe0, 0x25, 0x83, 0xe4, 0x91, 0xf8, + 0x99, 0x14, 0xcc, 0x62, 0xac, 0x1a, 0x0c, 0xb0, 0x9c, 0xea, 0x99, 0x63, 0x92, 0xfe, 0x5b, 0xa7, 0x13, 0xf6, 0x0b, + 0x2f, 0xb7, 0xb5, 0xbc, 0x69, 0xee, 0xbd, 0xf0, 0x2a, 0x96, 0x6a, 0x58, 0x06, 0xfd, 0xd7, 0x44, 0xbb, 0x60, 0x6b, + 0xcb, 0x98, 0xb0, 0xea, 0x07, 0x90, 0xf6, 0x48, 0x97, 0x57, 0x0d, 0x73, 0x26, 0x78, 0x74, 0x61, 0xcd, 0x83, 0xe8, + 0x42, 0xf8, 0xc8, 0x65, 0x37, 0x49, 0xae, 0xc6, 0x13, 0x3f, 0x1c, 0x0c, 0x14, 0x00, 0x2d, 0xad, 0x93, 0x62, 0x10, + 0x3e, 0x13, 0x72, 0x20, 0x8d, 0x8e, 0xaa, 0x00, 0x8b, 0x65, 0x76, 0x55, 0x4e, 0xb2, 0xc1, 0xc0, 0x07, 0xb1, 0x31, + 0xb1, 0x1b, 0x9a, 0xcd, 0x7d, 0x76, 0xa2, 0x20, 0xab, 0xcd, 0x61, 0x6b, 0xa6, 0x5b, 0x60, 0x00, 0x30, 0x88, 0x08, + 0x96, 0xfb, 0xdc, 0xc8, 0x47, 0xd4, 0xe9, 0x29, 0x8c, 0x80, 0xe0, 0x97, 0x13, 0x81, 0xc8, 0x45, 0x02, 0xf5, 0x00, + 0x33, 0x01, 0x66, 0x54, 0x31, 0xbc, 0x04, 0x76, 0xf1, 0xdc, 0xbc, 0x62, 0xd0, 0xbf, 0x68, 0x92, 0x25, 0x9a, 0x4a, + 0x1c, 0x8d, 0x91, 0x53, 0x69, 0x8c, 0x0c, 0x88, 0x5d, 0x1c, 0xff, 0x9e, 0xd2, 0xa3, 0x20, 0x65, 0x9f, 0x2b, 0x43, + 0x1c, 0x8e, 0xe2, 0x2b, 0x58, 0x35, 0x0e, 0x87, 0xda, 0xbc, 0x9e, 0xce, 0xea, 0xf9, 0x40, 0x04, 0xf0, 0xdf, 0x50, + 0xb0, 0x5f, 0x34, 0x15, 0xb9, 0x41, 0xea, 0x3c, 0x1c, 0x52, 0x90, 0x4f, 0x75, 0x93, 0xbf, 0xaf, 0xdc, 0xfd, 0x74, + 0x36, 0xb7, 0xe6, 0xe8, 0x45, 0x8d, 0xeb, 0xd6, 0xea, 0x86, 0x42, 0xa2, 0x35, 0x4d, 0x8a, 0xab, 0x6a, 0x52, 0x0c, + 0x78, 0xee, 0x0b, 0xd5, 0xc5, 0xd6, 0x08, 0x16, 0xfe, 0xdc, 0x02, 0x61, 0x32, 0xee, 0xc5, 0x47, 0x0b, 0x39, 0xa5, + 0x5d, 0x5b, 0xed, 0xb6, 0x95, 0x0d, 0x29, 0x9a, 0x0f, 0x2f, 0x61, 0x97, 0x4e, 0x11, 0x6d, 0xbb, 0x24, 0xf8, 0x02, + 0xb4, 0xac, 0x2e, 0x44, 0x1e, 0xd3, 0xaf, 0x90, 0x5f, 0x8a, 0xe1, 0x5f, 0xa5, 0x7b, 0x73, 0x6a, 0x83, 0x1c, 0xc0, + 0x76, 0xef, 0xe1, 0x76, 0x8c, 0x1e, 0xc8, 0xe0, 0x8d, 0x90, 0x73, 0xce, 0x2f, 0xa7, 0xd6, 0x8c, 0x89, 0x86, 0x05, + 0x2b, 0x87, 0x91, 0x1f, 0x20, 0xe3, 0xe5, 0x14, 0x58, 0xd9, 0x8f, 0x8a, 0xb8, 0xf4, 0x87, 0x91, 0x7f, 0xf1, 0x3c, + 0xc8, 0xb8, 0x17, 0x0d, 0x3b, 0xbe, 0x00, 0x7b, 0xf5, 0xc5, 0x73, 0x16, 0x0d, 0x78, 0x75, 0x55, 0x4f, 0xb3, 0x60, + 0x98, 0xb1, 0xe8, 0xaa, 0x18, 0x82, 0x0f, 0xed, 0x75, 0x39, 0x08, 0x7d, 0xdf, 0xec, 0x1c, 0xba, 0x1b, 0x12, 0x79, + 0x84, 0xfd, 0x08, 0x6e, 0xbb, 0x5a, 0x62, 0x06, 0x93, 0xcd, 0x5d, 0xc4, 0x0c, 0xb6, 0xfc, 0xc5, 0x73, 0xc3, 0x25, + 0x54, 0x5d, 0x4b, 0xcd, 0x46, 0x81, 0xe6, 0xe4, 0x0a, 0xcd, 0xc9, 0x4a, 0xa8, 0x25, 0x9f, 0x54, 0x38, 0x61, 0xe7, + 0x93, 0x5c, 0xd9, 0x8d, 0xc6, 0x18, 0xb8, 0x68, 0xcf, 0x6d, 0x61, 0x64, 0xa6, 0xb3, 0x14, 0x0d, 0x58, 0x78, 0x26, + 0x4e, 0x69, 0x0c, 0x68, 0x5f, 0x0e, 0x2c, 0x6d, 0xc8, 0x8f, 0x72, 0x66, 0xa0, 0x6d, 0x48, 0x69, 0xd4, 0x0c, 0xfc, + 0x99, 0x9a, 0x30, 0xbf, 0x82, 0x95, 0x08, 0xa2, 0xba, 0x00, 0x93, 0x24, 0x27, 0xa3, 0x91, 0xb2, 0x12, 0xc9, 0x39, + 0xe0, 0x7d, 0x04, 0x4f, 0x16, 0xb1, 0xad, 0xfd, 0x29, 0xfd, 0xaf, 0x0e, 0x9f, 0x4b, 0xff, 0x99, 0x00, 0x16, 0x72, + 0x69, 0x10, 0x19, 0x28, 0x1c, 0x52, 0x53, 0x89, 0x38, 0x71, 0x3c, 0x03, 0x5f, 0xc3, 0x05, 0x9a, 0x02, 0xfa, 0x83, + 0x9a, 0x51, 0x44, 0x16, 0xfe, 0xea, 0xd9, 0x4d, 0xdd, 0xe8, 0x79, 0xe6, 0xbc, 0x06, 0xcd, 0x0c, 0x84, 0xf4, 0x38, + 0x55, 0x6f, 0x43, 0xa2, 0xf3, 0xf2, 0x52, 0xbf, 0x4c, 0x88, 0x64, 0x45, 0xe4, 0xe9, 0xfb, 0x1c, 0xcc, 0x23, 0x8a, + 0xd0, 0xc1, 0x95, 0x79, 0x38, 0x9c, 0x0b, 0x0a, 0xdf, 0x51, 0x9e, 0x0f, 0x38, 0xcd, 0xa2, 0x04, 0xb4, 0x81, 0x2c, + 0x37, 0x65, 0xae, 0x93, 0x96, 0xa9, 0x7b, 0x0f, 0x56, 0x82, 0x0a, 0xdd, 0x9c, 0x82, 0x42, 0x19, 0x09, 0x4a, 0x69, + 0x35, 0x08, 0xa5, 0x3a, 0x2c, 0x82, 0xc8, 0x21, 0x0b, 0x01, 0x37, 0x53, 0xd1, 0x68, 0x49, 0xc3, 0x23, 0x9c, 0x1b, + 0x28, 0x04, 0x20, 0xb1, 0xa7, 0x8a, 0x32, 0x2e, 0x87, 0x80, 0x8f, 0x12, 0x0e, 0x71, 0xd6, 0xa4, 0x2d, 0xcf, 0x41, + 0x1c, 0xcb, 0x25, 0x5f, 0x57, 0x08, 0x06, 0x11, 0xfa, 0x0c, 0xf9, 0x93, 0xe5, 0xfc, 0xbb, 0x75, 0x98, 0x76, 0x84, + 0x0f, 0xbb, 0xda, 0x82, 0x8b, 0xd9, 0xed, 0x7c, 0x02, 0xf1, 0x2d, 0xb7, 0xf3, 0x63, 0x0c, 0x91, 0x85, 0x3f, 0xb8, + 0x1b, 0x4a, 0xae, 0x28, 0x74, 0x59, 0x8f, 0x48, 0x91, 0x3d, 0x5d, 0x73, 0x04, 0xc1, 0x81, 0x56, 0x0d, 0x32, 0x34, + 0x12, 0x5f, 0x3c, 0x87, 0xac, 0xc1, 0x9a, 0x7f, 0xae, 0xc8, 0x59, 0xdd, 0x9f, 0x6c, 0xa0, 0x9a, 0x64, 0xb2, 0x56, + 0x54, 0xce, 0x5f, 0xaf, 0xca, 0xf2, 0x64, 0x55, 0x86, 0xab, 0x41, 0x57, 0x55, 0x96, 0x1c, 0xa9, 0x0d, 0xd0, 0x9a, + 0xae, 0x10, 0x43, 0x21, 0x6b, 0xb0, 0xb4, 0xaa, 0xb2, 0xa6, 0x3e, 0x81, 0x40, 0x1f, 0x60, 0x19, 0x35, 0xfb, 0xe9, + 0xf0, 0x5f, 0xc1, 0xbf, 0x54, 0xc8, 0x52, 0x9d, 0xd6, 0x99, 0xf8, 0x35, 0x58, 0x32, 0xfc, 0xe3, 0xb7, 0x60, 0x0d, + 0x58, 0x02, 0x64, 0xb9, 0xdb, 0xd8, 0x68, 0xbd, 0xf2, 0x0a, 0xf1, 0xa5, 0xd6, 0x17, 0xfd, 0xd6, 0x6d, 0xa2, 0x56, + 0x80, 0x11, 0x0a, 0x2d, 0x02, 0x6c, 0xf5, 0xc0, 0x3d, 0x05, 0x3f, 0x10, 0xc3, 0xb9, 0x26, 0xad, 0xa9, 0x13, 0x5e, + 0x67, 0xe3, 0x48, 0x44, 0xf5, 0x16, 0x2e, 0xee, 0xf5, 0xd6, 0xe2, 0x6f, 0x54, 0x20, 0x00, 0xb2, 0x98, 0x62, 0xed, + 0xbc, 0x21, 0xbd, 0x32, 0xec, 0x24, 0xf4, 0xde, 0xb0, 0x13, 0xc8, 0x8b, 0xc3, 0x4e, 0xa1, 0x4b, 0xb4, 0x9d, 0x22, + 0x35, 0xd1, 0x76, 0xd2, 0x62, 0x15, 0x96, 0x10, 0xfc, 0xaa, 0xbd, 0x75, 0x94, 0xed, 0x8b, 0x2c, 0x61, 0xda, 0x02, + 0x46, 0xb9, 0x55, 0x9f, 0x39, 0x45, 0xac, 0x94, 0xbd, 0xd3, 0x49, 0x95, 0xbb, 0xc8, 0xa7, 0x56, 0x53, 0x64, 0xf2, + 0xf7, 0xc7, 0x2d, 0x92, 0x4f, 0x7e, 0x6e, 0x37, 0x4c, 0xa6, 0x7f, 0x3c, 0xfa, 0x02, 0xba, 0x22, 0x3b, 0x7d, 0x02, + 0x01, 0x99, 0x0a, 0xaa, 0xd5, 0xad, 0x62, 0x9a, 0xb7, 0xab, 0xec, 0xf6, 0x42, 0x89, 0xe1, 0x74, 0x76, 0x12, 0x1e, + 0x6d, 0x86, 0x0c, 0x1c, 0x82, 0x40, 0x21, 0x54, 0x14, 0xc3, 0x23, 0x50, 0x6b, 0x24, 0x1f, 0xe0, 0x47, 0xbb, 0x53, + 0x41, 0xa4, 0x76, 0x53, 0x71, 0xe3, 0xe4, 0xa6, 0xeb, 0xa5, 0x40, 0xad, 0x53, 0xb2, 0x02, 0x28, 0x21, 0xea, 0x4f, + 0x62, 0x5b, 0xbf, 0x84, 0x2b, 0x36, 0xdf, 0x37, 0x8a, 0x9e, 0x5c, 0x9f, 0xa2, 0x6e, 0xc5, 0xd5, 0x69, 0xda, 0x6a, + 0x8e, 0x1d, 0x67, 0xc8, 0xc1, 0xb3, 0x82, 0x60, 0x3b, 0x2a, 0x51, 0xbe, 0x6d, 0x37, 0x1d, 0x13, 0x5b, 0xfd, 0xb3, + 0xa8, 0x36, 0x77, 0x50, 0x11, 0x11, 0x1f, 0x65, 0x37, 0x4f, 0xda, 0xef, 0x60, 0x8f, 0xb5, 0x1a, 0x44, 0xf6, 0x19, + 0x5c, 0xe5, 0x3a, 0x2d, 0x72, 0x5b, 0x06, 0xe7, 0x1f, 0x5e, 0xed, 0x2a, 0x6c, 0x72, 0xac, 0xab, 0xab, 0x99, 0xea, + 0xa4, 0x62, 0x03, 0x63, 0x4d, 0x6b, 0xa9, 0xe6, 0x31, 0x24, 0xdd, 0x95, 0xc5, 0x59, 0x95, 0x74, 0xd3, 0x73, 0xe3, + 0x4c, 0x21, 0x06, 0xce, 0x56, 0xa3, 0xe5, 0x0c, 0x43, 0x74, 0x7d, 0x98, 0x25, 0x7e, 0xab, 0xa7, 0xdc, 0xe7, 0xe1, + 0xd6, 0xef, 0xea, 0x05, 0x27, 0x93, 0xfd, 0xe4, 0x38, 0x77, 0xbb, 0x48, 0xfb, 0x89, 0x6f, 0xc3, 0xfc, 0xeb, 0x1b, + 0xc4, 0x9d, 0xa8, 0xff, 0x59, 0x01, 0xd0, 0xe0, 0x26, 0x8f, 0x25, 0x4a, 0xfd, 0x5e, 0x55, 0x3f, 0xa8, 0x99, 0xaa, + 0x69, 0x20, 0x98, 0x53, 0x29, 0xe0, 0x0f, 0xb7, 0x0b, 0x57, 0x3c, 0xe2, 0x86, 0x85, 0xf1, 0x4f, 0xaf, 0x66, 0xa7, + 0x82, 0xca, 0xc0, 0xcd, 0xf8, 0x4f, 0x4f, 0xb0, 0x53, 0x58, 0x2b, 0x20, 0x2b, 0xfc, 0xe9, 0xe5, 0x8f, 0xbc, 0x5f, + 0xf1, 0x3f, 0xbd, 0xea, 0x91, 0xf7, 0x11, 0xe7, 0xe5, 0x4f, 0x24, 0x75, 0x42, 0x54, 0x97, 0x3f, 0x09, 0x53, 0x6c, + 0x95, 0xe6, 0xaf, 0x48, 0xe1, 0x13, 0x7c, 0x06, 0xbe, 0xc3, 0x55, 0xb8, 0x35, 0xbf, 0xc1, 0x63, 0xc7, 0x62, 0xdb, + 0xa5, 0xbe, 0x80, 0x72, 0x04, 0x16, 0x91, 0xdb, 0x6f, 0x57, 0xf6, 0xab, 0x85, 0x51, 0xc6, 0xd8, 0x7d, 0xc9, 0x4a, + 0x94, 0xce, 0xfa, 0xfd, 0x42, 0x0a, 0x46, 0x76, 0x61, 0x8d, 0xf6, 0x28, 0x55, 0xaf, 0xbe, 0x0d, 0xeb, 0x28, 0x49, + 0xf3, 0x3b, 0x19, 0x7d, 0x24, 0xc3, 0x8e, 0xf4, 0x95, 0x94, 0x68, 0xaf, 0x55, 0x58, 0x8e, 0x66, 0xbf, 0x2e, 0x39, + 0x50, 0x5e, 0xb7, 0x82, 0xf2, 0x55, 0x13, 0x40, 0xaf, 0x54, 0xfb, 0x0c, 0xb4, 0x82, 0xc2, 0x52, 0x79, 0xb0, 0x12, + 0xe7, 0xa2, 0xcf, 0x8a, 0xc3, 0x41, 0x5d, 0x0c, 0x09, 0x05, 0xaa, 0xc4, 0x49, 0x68, 0xc4, 0x73, 0xb8, 0x10, 0x8a, + 0xeb, 0x1c, 0x63, 0x2b, 0x72, 0xe0, 0x40, 0x86, 0x1f, 0x10, 0x78, 0x2f, 0xfb, 0x57, 0x30, 0x18, 0x26, 0xb8, 0x91, + 0x51, 0x27, 0xe7, 0xec, 0x4f, 0x0c, 0xcc, 0xa0, 0x9e, 0xd4, 0xee, 0xb3, 0x7b, 0x15, 0xd8, 0x0b, 0x67, 0x40, 0x7b, + 0x37, 0x46, 0x3f, 0xab, 0x62, 0xed, 0xa4, 0x7f, 0x2a, 0xd6, 0x90, 0x4c, 0x87, 0xc5, 0xd1, 0x36, 0x0d, 0x8f, 0xe4, + 0xc9, 0x71, 0xbc, 0xe9, 0x1f, 0x0e, 0x63, 0xfc, 0x38, 0xca, 0xaf, 0x2d, 0xe0, 0x55, 0xdc, 0x42, 0x1a, 0x8b, 0x14, + 0xbd, 0x03, 0x31, 0x87, 0xa2, 0x97, 0xec, 0xb7, 0x8c, 0x97, 0x13, 0x41, 0x29, 0x49, 0x6c, 0x78, 0x47, 0x7a, 0x9a, + 0xd6, 0xa3, 0xad, 0x0c, 0xd8, 0xaf, 0x47, 0x3b, 0xfa, 0x0b, 0x14, 0x8f, 0x16, 0xfe, 0x92, 0xfe, 0x2e, 0xee, 0xe6, + 0x9e, 0xf3, 0x4d, 0xe3, 0x3b, 0xe2, 0x02, 0xc5, 0x9a, 0xdd, 0x5f, 0xd3, 0xd2, 0x59, 0x07, 0x82, 0x03, 0xde, 0x62, + 0x17, 0xed, 0xfb, 0x8d, 0xeb, 0xf4, 0xb4, 0xff, 0xd6, 0xad, 0x51, 0xbe, 0xf7, 0x4f, 0x89, 0x72, 0xb0, 0x7f, 0xe5, + 0xa2, 0xf9, 0xdb, 0x4f, 0x19, 0x92, 0x0a, 0xcd, 0x0d, 0xb6, 0x93, 0x2d, 0xc2, 0xda, 0x18, 0x07, 0x15, 0xbb, 0x2b, + 0xc3, 0x08, 0x18, 0xd4, 0xb1, 0xff, 0xd1, 0x67, 0xd3, 0x86, 0xec, 0x03, 0x40, 0xe5, 0x2a, 0x04, 0xec, 0x01, 0x38, + 0xd1, 0x08, 0x37, 0xc0, 0xad, 0x46, 0x4b, 0x3a, 0xa8, 0xdb, 0x82, 0x81, 0x68, 0x09, 0x1b, 0x79, 0xdb, 0xd5, 0xe9, + 0x2b, 0xc2, 0x87, 0xda, 0x49, 0xe9, 0x50, 0xfe, 0xea, 0x39, 0xfb, 0x9f, 0x1d, 0xd6, 0xd4, 0x94, 0x1b, 0xc0, 0xcc, + 0x59, 0x89, 0xbc, 0x42, 0xe8, 0x14, 0xf9, 0xbd, 0xaa, 0x2b, 0x31, 0x5c, 0xd6, 0xa2, 0xec, 0xcc, 0x6e, 0x9d, 0xe8, + 0x9d, 0x53, 0x50, 0x4b, 0x65, 0x83, 0x9c, 0xa4, 0xda, 0x7c, 0x64, 0xad, 0xa0, 0x44, 0x5d, 0xa3, 0xc0, 0xf1, 0x29, + 0xd7, 0xee, 0xff, 0x9d, 0x33, 0x41, 0xcd, 0x36, 0xaa, 0xfb, 0x2b, 0xfd, 0x54, 0xd5, 0x24, 0x16, 0xe0, 0x72, 0x92, + 0xe6, 0x1d, 0x8f, 0xb0, 0xfa, 0xc7, 0xc9, 0x52, 0x04, 0x7a, 0x15, 0xd1, 0xae, 0x04, 0x24, 0x68, 0x27, 0x67, 0xa1, + 0x22, 0x50, 0xa0, 0xaf, 0x7f, 0xbf, 0x49, 0xb3, 0x58, 0xae, 0x66, 0x7b, 0x98, 0x28, 0x8b, 0xf5, 0x10, 0x41, 0xce, + 0x4c, 0x1d, 0xec, 0xf7, 0x34, 0xa3, 0x59, 0x78, 0x65, 0x4a, 0x70, 0x29, 0xae, 0xa2, 0x22, 0x07, 0x9f, 0x43, 0x7c, + 0xe1, 0x53, 0x21, 0x37, 0x88, 0x68, 0xfa, 0xbd, 0x44, 0xb5, 0x23, 0x05, 0x72, 0x28, 0xf9, 0x09, 0xf1, 0x97, 0xac, + 0x8d, 0x71, 0xbf, 0x74, 0xaa, 0xfd, 0x52, 0x21, 0xb8, 0xff, 0x6c, 0x8b, 0x8d, 0x2a, 0x4f, 0xf4, 0xe8, 0x53, 0xac, + 0xff, 0xc9, 0x02, 0x4a, 0x75, 0xdf, 0x06, 0xa7, 0xe2, 0x51, 0xb8, 0xa9, 0x8b, 0x1b, 0x84, 0x16, 0x28, 0x47, 0x55, + 0xb1, 0x29, 0x23, 0xe2, 0x84, 0xdd, 0xd4, 0x45, 0x4f, 0x73, 0xa0, 0x53, 0x87, 0xa5, 0x89, 0x3c, 0x11, 0xda, 0x2d, + 0xe8, 0x9e, 0xe6, 0x58, 0x89, 0x17, 0xb2, 0x74, 0x90, 0x75, 0x22, 0x4d, 0xa8, 0xdc, 0xd5, 0x55, 0x47, 0xa5, 0x52, + 0x37, 0xbc, 0x4e, 0x35, 0xe3, 0xef, 0xd2, 0xfc, 0x89, 0x65, 0xbf, 0x6e, 0xfd, 0x56, 0xab, 0xbd, 0xb1, 0x7a, 0x54, + 0xb2, 0xe6, 0x38, 0x9b, 0x90, 0x94, 0x3e, 0x61, 0xbb, 0x99, 0x74, 0xad, 0x03, 0x4f, 0x82, 0xcb, 0xa1, 0x27, 0xa0, + 0x62, 0xd0, 0xc4, 0xdb, 0x5d, 0xa0, 0x1e, 0x81, 0x67, 0xa0, 0x7c, 0xa2, 0xd6, 0x01, 0x3f, 0xaf, 0xb5, 0x3c, 0x65, + 0x84, 0x61, 0xb5, 0xb3, 0x68, 0x39, 0x38, 0xef, 0x14, 0x81, 0x6b, 0x57, 0x02, 0xcf, 0x87, 0xea, 0xbd, 0x10, 0x30, + 0xdc, 0x3f, 0x15, 0x2a, 0x9b, 0xdd, 0x0c, 0xe7, 0x51, 0xe3, 0xf4, 0x40, 0x7b, 0xdb, 0xb5, 0x1e, 0xea, 0x5d, 0xb7, + 0x73, 0x5b, 0xe9, 0xde, 0xaf, 0x9d, 0x4c, 0xba, 0x80, 0xd6, 0xe6, 0xb3, 0xef, 0xec, 0x4a, 0xeb, 0xa6, 0xe7, 0xec, + 0xc1, 0xd6, 0x2d, 0xd1, 0xb9, 0x20, 0x9a, 0xfc, 0x7e, 0xe0, 0x59, 0xdb, 0x8e, 0x7e, 0x9b, 0x76, 0x6c, 0x73, 0x0f, + 0x75, 0xaf, 0xa0, 0xd6, 0x1b, 0x9a, 0xf7, 0xcf, 0x5c, 0xdb, 0x8e, 0xaf, 0x7e, 0x5d, 0x77, 0xb8, 0xce, 0x9b, 0xe0, + 0xb8, 0xe9, 0xda, 0x56, 0x3b, 0xfb, 0xb9, 0xbb, 0xb7, 0x16, 0x51, 0x98, 0x65, 0x3f, 0x16, 0xc5, 0x1f, 0x95, 0xbe, + 0x23, 0xd0, 0xd1, 0x9d, 0x17, 0x75, 0xba, 0xdc, 0x7d, 0x20, 0x8c, 0x27, 0xaf, 0x3e, 0x22, 0xba, 0xf5, 0x7d, 0xe6, + 0x7e, 0x05, 0xb8, 0x11, 0xdc, 0x41, 0xb4, 0x77, 0x4b, 0x7d, 0x52, 0xab, 0xaf, 0xf5, 0xda, 0x79, 0x7a, 0x7e, 0xd3, + 0xb9, 0xfd, 0xee, 0x9b, 0xa3, 0xad, 0xf7, 0xb8, 0xb0, 0x56, 0x96, 0x9e, 0xaa, 0x82, 0xbd, 0x59, 0x9e, 0xaa, 0x82, + 0xc9, 0x03, 0xaf, 0xd9, 0x2f, 0x68, 0x70, 0xa5, 0xa3, 0x8d, 0xf7, 0x44, 0x0d, 0xdc, 0xa2, 0xb0, 0x74, 0xf8, 0x25, + 0x37, 0x93, 0x97, 0xb8, 0xbf, 0x54, 0xe4, 0x62, 0xdf, 0x39, 0xa3, 0x3b, 0x33, 0xeb, 0x5e, 0x55, 0xb8, 0x5a, 0x90, + 0xab, 0x03, 0x5b, 0xcb, 0x2e, 0x0e, 0x37, 0x2c, 0xa2, 0x00, 0x81, 0x98, 0x5e, 0xa9, 0xb5, 0x3f, 0xa2, 0x41, 0xc8, + 0x07, 0x03, 0xbf, 0xc0, 0x60, 0x55, 0xa0, 0xf0, 0x81, 0x22, 0xf9, 0x2b, 0x4f, 0xc0, 0x2e, 0x9e, 0x01, 0xba, 0x15, + 0x9b, 0x15, 0x23, 0x44, 0xc8, 0x64, 0x39, 0xab, 0xe9, 0x0c, 0xf2, 0xa9, 0x2f, 0xbe, 0xb1, 0x55, 0xa7, 0xf3, 0xb6, + 0xa6, 0xca, 0xa9, 0x43, 0xa1, 0xbb, 0x9b, 0xba, 0x73, 0xeb, 0x22, 0x4f, 0x1d, 0x42, 0xae, 0x54, 0xac, 0xc4, 0x34, + 0xd4, 0x3c, 0x49, 0x33, 0xea, 0x2f, 0xf6, 0x7e, 0xaf, 0x51, 0x38, 0xe5, 0x4f, 0xc7, 0xa0, 0x0a, 0x57, 0x35, 0xc4, + 0xb1, 0x54, 0xc5, 0x23, 0x1b, 0x04, 0x9a, 0x57, 0xb7, 0x2a, 0x69, 0x42, 0x26, 0x37, 0xc2, 0xa7, 0x26, 0xa5, 0x3c, + 0x4d, 0x9b, 0xb4, 0x52, 0xa4, 0x0e, 0x3e, 0xa8, 0x53, 0x8d, 0xe7, 0x66, 0x75, 0x0d, 0x60, 0xc6, 0xf9, 0x15, 0xbf, + 0x54, 0x5c, 0x46, 0x6d, 0x65, 0x26, 0xed, 0x4f, 0x8e, 0xc6, 0x46, 0x5d, 0x4e, 0x1b, 0x65, 0x84, 0x95, 0xd2, 0x9c, + 0x14, 0xcb, 0xf1, 0xfc, 0x03, 0x06, 0x6b, 0x9e, 0xc0, 0x0e, 0x26, 0x2a, 0xe5, 0x7d, 0x04, 0xc4, 0xd7, 0x49, 0x7a, + 0x97, 0x40, 0x8a, 0xf4, 0x2f, 0x5d, 0x72, 0x97, 0xb1, 0x81, 0x18, 0xb3, 0x62, 0x66, 0xf4, 0x3f, 0xb8, 0x4b, 0xfa, + 0x93, 0x10, 0x00, 0x37, 0xd1, 0x14, 0x3a, 0x75, 0x9e, 0x5c, 0xe4, 0xc1, 0xf2, 0xc2, 0x43, 0x2b, 0x46, 0x3c, 0xf8, + 0xeb, 0x75, 0x88, 0x20, 0xe6, 0x98, 0xe2, 0xe9, 0x17, 0x46, 0x7f, 0x09, 0x2e, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, + 0x21, 0xdc, 0xec, 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, 0x6a, 0xf8, 0x63, 0xe5, 0x41, 0xff, 0xd7, 0x99, 0xb0, 0xd4, + 0x7e, 0x7a, 0x3a, 0x80, 0x0a, 0xde, 0x57, 0xbc, 0x8d, 0x88, 0xef, 0x13, 0x3f, 0x8b, 0x07, 0x9b, 0x67, 0x1b, 0xb0, + 0xd6, 0x3d, 0xc9, 0x8d, 0x75, 0x95, 0xb0, 0x81, 0x80, 0xaf, 0x51, 0xd4, 0x9e, 0xd7, 0x6e, 0xf7, 0xe0, 0xaf, 0xfe, + 0x45, 0xc8, 0x80, 0x89, 0xd3, 0xf7, 0x99, 0x93, 0x35, 0xba, 0xc8, 0x64, 0xfa, 0xd0, 0x49, 0xdf, 0xe8, 0x74, 0xdf, + 0x09, 0xff, 0xa8, 0x98, 0xc5, 0x87, 0x5b, 0xfa, 0x4a, 0x93, 0xe2, 0x0e, 0x58, 0xd9, 0x3c, 0x2a, 0x08, 0x75, 0x2e, + 0xa2, 0xaf, 0x4c, 0xf9, 0x96, 0x50, 0xb3, 0x6f, 0x2c, 0x29, 0xa5, 0x7b, 0x0d, 0xbd, 0x4e, 0x6b, 0xfd, 0x36, 0x4a, + 0x30, 0x26, 0x3a, 0x9e, 0xbc, 0x8c, 0xc7, 0xca, 0xfb, 0x78, 0xdc, 0x48, 0x85, 0x3c, 0x00, 0x11, 0xa8, 0x18, 0x7f, + 0xba, 0xf2, 0xe4, 0xa4, 0x17, 0xc6, 0xab, 0x50, 0x0a, 0x0a, 0x03, 0xba, 0x02, 0x29, 0xe0, 0x51, 0x7b, 0xa2, 0xb3, + 0xb0, 0x4b, 0xb8, 0x47, 0x37, 0x01, 0x63, 0x7d, 0xfe, 0x11, 0xd0, 0xdc, 0x85, 0x3b, 0xbc, 0x18, 0xa0, 0x36, 0xf5, + 0xea, 0xee, 0xe3, 0x5a, 0x9d, 0xc3, 0x21, 0x38, 0x58, 0x0d, 0x22, 0x38, 0x9d, 0x4f, 0x1d, 0xcd, 0xb2, 0x00, 0x95, + 0x93, 0xe5, 0x46, 0xde, 0x3c, 0x5a, 0xf4, 0xea, 0xbe, 0xb7, 0x4c, 0xcb, 0xaa, 0x0e, 0x32, 0x96, 0x85, 0x15, 0xe0, + 0xea, 0xd0, 0xfa, 0x41, 0xb8, 0x2c, 0x9c, 0x3f, 0x10, 0x82, 0xd8, 0xbd, 0xda, 0x96, 0x3c, 0x57, 0x73, 0xf8, 0xd9, + 0x73, 0xb6, 0xe6, 0x12, 0x75, 0xd2, 0x99, 0x08, 0x40, 0xec, 0xa9, 0x59, 0x45, 0xd7, 0x40, 0x52, 0xa7, 0x59, 0x45, + 0xd7, 0xd4, 0x6c, 0x63, 0x1c, 0xc8, 0x47, 0xab, 0x14, 0xb0, 0xef, 0xa6, 0xe3, 0x60, 0xf5, 0x2c, 0x96, 0xd7, 0xa1, + 0xbb, 0x67, 0x1b, 0xe5, 0x33, 0xa8, 0x5b, 0x6d, 0x8c, 0x89, 0xed, 0xe6, 0xcb, 0xb9, 0x7e, 0x3b, 0x58, 0xfa, 0x76, + 0xd0, 0x9c, 0x53, 0xf6, 0x9d, 0x2e, 0x7b, 0x65, 0x97, 0x4d, 0x3d, 0x77, 0x54, 0xb4, 0x1a, 0x03, 0x7a, 0x03, 0x0b, + 0xd6, 0xe7, 0x22, 0xcd, 0x56, 0xa5, 0x2a, 0x01, 0x2f, 0x8c, 0x15, 0xbb, 0xf3, 0x1b, 0x99, 0x21, 0x09, 0xf3, 0x38, + 0x13, 0x6f, 0xe9, 0x5e, 0x0b, 0x93, 0xe3, 0x58, 0x24, 0x53, 0x42, 0xa7, 0x74, 0x67, 0x1b, 0x3a, 0x57, 0x61, 0x14, + 0xd1, 0x5a, 0x49, 0xa5, 0x91, 0xc0, 0xd4, 0x0c, 0x50, 0x32, 0x57, 0xe0, 0x94, 0x2e, 0xf7, 0xbf, 0x23, 0x31, 0xce, + 0x7c, 0x51, 0x32, 0x03, 0xba, 0xe5, 0xd7, 0xc5, 0xba, 0x95, 0x22, 0x23, 0xcc, 0x9b, 0xe3, 0xf6, 0xba, 0x3e, 0x04, + 0x72, 0xb5, 0xec, 0x51, 0x34, 0x0e, 0x0a, 0x1d, 0x2e, 0x55, 0x02, 0xec, 0x8b, 0xc4, 0xcf, 0x08, 0x5b, 0xda, 0x03, + 0xb9, 0x3d, 0x3a, 0x13, 0xe6, 0x9c, 0x93, 0xb2, 0xec, 0x5c, 0x9a, 0xc1, 0xe5, 0xc4, 0x95, 0xe0, 0x22, 0xbd, 0x6d, + 0x4f, 0x93, 0x96, 0xb6, 0x8f, 0x0d, 0xe7, 0x68, 0x68, 0x1b, 0x74, 0xc7, 0xfe, 0xd0, 0x5c, 0x2c, 0x62, 0xeb, 0x62, + 0x31, 0xec, 0xcc, 0x7e, 0xb4, 0x58, 0x80, 0x1c, 0x00, 0x8e, 0xba, 0x0d, 0x1f, 0xb3, 0x25, 0x70, 0x5a, 0x4d, 0xb3, + 0xa9, 0xb7, 0xe1, 0xd5, 0x33, 0xd5, 0xd3, 0x4b, 0x9e, 0x3f, 0x13, 0x66, 0x2c, 0x36, 0x3c, 0x7f, 0x66, 0x1d, 0x39, + 0xd5, 0x33, 0xa1, 0x44, 0xeb, 0x02, 0x9a, 0x81, 0xd7, 0x14, 0x30, 0x62, 0xc9, 0x64, 0x4a, 0x15, 0x79, 0xdc, 0x9b, + 0x6e, 0xd4, 0xe0, 0x05, 0x85, 0x43, 0x20, 0xa5, 0xd3, 0x2f, 0x9e, 0x33, 0xfd, 0xde, 0xc5, 0xf3, 0x0e, 0x59, 0xdb, + 0x30, 0x5d, 0x6e, 0x86, 0xc9, 0xa0, 0xf4, 0x9f, 0x99, 0x89, 0x71, 0x61, 0x4d, 0x12, 0x40, 0xfc, 0x1b, 0xfb, 0x1d, + 0x52, 0xb8, 0x79, 0x7f, 0x39, 0x8c, 0x1f, 0x79, 0x3f, 0x46, 0xf6, 0x24, 0xcd, 0x10, 0x6b, 0x26, 0x15, 0x72, 0xf7, + 0xd5, 0xfa, 0xc7, 0xc4, 0x6e, 0xb2, 0x07, 0x16, 0x80, 0xd8, 0x9a, 0xb6, 0xba, 0xe5, 0xfd, 0xbe, 0x67, 0x8a, 0x00, + 0x3f, 0x28, 0xff, 0xe8, 0xce, 0x90, 0x0c, 0xca, 0xae, 0x1b, 0x42, 0x3c, 0x28, 0x9b, 0xa6, 0xbd, 0xde, 0xf6, 0xce, + 0x3c, 0x56, 0xd7, 0x69, 0x67, 0x71, 0xb5, 0xc8, 0x20, 0xad, 0x3e, 0x64, 0xc7, 0x99, 0x7d, 0x76, 0xb4, 0x54, 0xba, + 0xdf, 0x87, 0x88, 0xb8, 0xa3, 0xac, 0xed, 0xb7, 0x5b, 0x70, 0x0d, 0x47, 0x83, 0xd0, 0x95, 0xbd, 0x5d, 0x46, 0x1b, + 0x17, 0xe2, 0xb8, 0x67, 0x3a, 0x5f, 0xf0, 0xe5, 0x51, 0xda, 0x79, 0x70, 0xaa, 0x27, 0xfa, 0xdc, 0x74, 0x57, 0x99, + 0x5c, 0xeb, 0xb0, 0x1a, 0x83, 0xda, 0x2c, 0x6c, 0xe1, 0x2e, 0x6c, 0xa3, 0x83, 0xd6, 0xbe, 0x2c, 0xf8, 0xa7, 0x0c, + 0xc0, 0x97, 0x9e, 0x2d, 0xdb, 0x5e, 0x93, 0x56, 0xaf, 0x65, 0x14, 0x62, 0x4b, 0xdb, 0xab, 0x4f, 0x47, 0xf9, 0xb8, + 0x39, 0xa1, 0xb8, 0x90, 0xa3, 0xfc, 0xe8, 0x35, 0x44, 0x5d, 0xeb, 0x3a, 0x2e, 0x16, 0x1d, 0x6e, 0x5c, 0x75, 0xdb, + 0x8d, 0xeb, 0x07, 0xc4, 0x5b, 0xa3, 0x4d, 0x0a, 0xb5, 0x32, 0x76, 0x04, 0x2f, 0xcb, 0x87, 0x43, 0x26, 0x86, 0x43, + 0x09, 0x99, 0xfa, 0xd8, 0xbd, 0xa1, 0x69, 0x9f, 0x9f, 0xb6, 0x7e, 0xc4, 0x52, 0xe3, 0x28, 0x36, 0xbc, 0xd3, 0x77, + 0x1e, 0x5b, 0xe3, 0x4a, 0xbe, 0x0c, 0x66, 0xbb, 0x82, 0x6a, 0x6b, 0xbc, 0x61, 0x2f, 0xe7, 0xdf, 0x57, 0x52, 0xc9, + 0xdf, 0xfe, 0x0c, 0xd7, 0xf0, 0xd6, 0x96, 0x0e, 0x9a, 0x6a, 0x96, 0xb3, 0x5c, 0xdf, 0x0b, 0x8e, 0x3f, 0xee, 0x5e, + 0x11, 0x0c, 0x7e, 0x4f, 0x47, 0x41, 0x2e, 0x96, 0x6a, 0x0d, 0x28, 0x48, 0x47, 0x76, 0x4c, 0x65, 0x81, 0x61, 0x00, + 0x6f, 0xc8, 0x00, 0x79, 0x4c, 0xe1, 0x6e, 0xa8, 0xf0, 0xc2, 0x5f, 0x2a, 0xb2, 0x4b, 0x60, 0x5b, 0x33, 0x3e, 0x66, + 0xb8, 0x83, 0x90, 0x7f, 0x04, 0xbb, 0x63, 0x2b, 0x76, 0xcb, 0x16, 0x0c, 0xc9, 0xc6, 0x71, 0x18, 0x63, 0x3e, 0x9e, + 0xc4, 0x57, 0x62, 0x12, 0x0f, 0x78, 0x84, 0x8e, 0x11, 0x6b, 0x5e, 0xcf, 0x62, 0x39, 0x80, 0xec, 0x8e, 0x2b, 0x1d, + 0x10, 0x42, 0x63, 0x43, 0x4b, 0x5e, 0x17, 0x06, 0x17, 0x3b, 0xf6, 0x19, 0x89, 0x64, 0x1c, 0x82, 0x45, 0xab, 0x1a, + 0x58, 0x98, 0xd8, 0x2d, 0x2f, 0x66, 0xab, 0x39, 0xfe, 0x73, 0x38, 0x20, 0x00, 0x76, 0xb0, 0x6f, 0xd8, 0x5d, 0x84, + 0x48, 0x6f, 0x0b, 0x7e, 0x67, 0x79, 0xba, 0xb0, 0x7b, 0xfe, 0x96, 0x8f, 0xd9, 0xf9, 0x0f, 0x1e, 0x44, 0xce, 0x9e, + 0x7f, 0x04, 0x34, 0xc4, 0x7b, 0x7e, 0x9b, 0x7a, 0x15, 0xbb, 0x25, 0x0a, 0xc2, 0x5b, 0x70, 0x06, 0xba, 0x87, 0x08, + 0xd8, 0xb7, 0x7c, 0x81, 0xb1, 0x62, 0x67, 0xe9, 0xd2, 0xc3, 0x8c, 0x50, 0x7b, 0x3a, 0x5f, 0xd6, 0x6a, 0x12, 0x6e, + 0xae, 0x96, 0x93, 0xc1, 0x60, 0xe3, 0xef, 0xf8, 0x1a, 0xf8, 0x60, 0xce, 0x7f, 0xf0, 0x76, 0x54, 0x2e, 0xfc, 0xe7, + 0x75, 0x96, 0xbc, 0xf3, 0xd9, 0xdb, 0x01, 0x5f, 0x00, 0xde, 0x12, 0x3a, 0x70, 0xdd, 0xfb, 0x4c, 0xe2, 0xb5, 0xbd, + 0xd5, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0x7e, 0x0b, 0x11, 0x18, 0x09, 0xf8, 0xb6, 0x6a, 0x8f, + 0xf8, 0x2d, 0x37, 0x80, 0x5f, 0x99, 0xcf, 0x1e, 0x78, 0xa8, 0x7f, 0x26, 0x3e, 0xbb, 0xe1, 0xef, 0xf9, 0xb5, 0x27, + 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, + 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, + 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, + 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, 0x5e, 0x17, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, + 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, 0x7c, 0x38, 0xd4, 0xd7, 0x42, 0x8b, 0x04, 0x53, + 0xd0, 0xb8, 0x06, 0x6d, 0x01, 0x82, 0x3e, 0x0f, 0x90, 0xb5, 0xa4, 0x58, 0xf0, 0xed, 0xaf, 0x10, 0x83, 0x57, 0xa6, + 0x77, 0x2e, 0x57, 0x19, 0x09, 0xdb, 0x0b, 0xbf, 0x1c, 0xd6, 0xfe, 0xc4, 0xa9, 0x85, 0xa5, 0xd5, 0x1c, 0xd4, 0xcf, + 0x6c, 0x39, 0x4e, 0x55, 0xed, 0xdf, 0x92, 0xa4, 0xda, 0x55, 0x5a, 0x4e, 0xef, 0xed, 0x9b, 0x2e, 0x13, 0x6c, 0xec, + 0x07, 0x54, 0x1d, 0x59, 0x0d, 0xbb, 0x2f, 0xd4, 0x17, 0x3d, 0x25, 0x13, 0x9a, 0x8f, 0x2a, 0x9a, 0x67, 0xf7, 0x9b, + 0x1d, 0xf5, 0x9f, 0x5e, 0x0e, 0x45, 0x80, 0x64, 0x95, 0x16, 0x4b, 0x91, 0xb3, 0xb1, 0x1f, 0x0f, 0x93, 0x4c, 0x85, + 0x17, 0xa4, 0xa3, 0xbb, 0xdf, 0xb8, 0xbf, 0xe5, 0x06, 0xb2, 0x42, 0xab, 0x36, 0x18, 0x2b, 0x45, 0xcb, 0x60, 0x7d, + 0x35, 0xee, 0xf7, 0xc5, 0xd5, 0x78, 0x2a, 0x82, 0x1a, 0x88, 0x8b, 0xc4, 0xf5, 0x78, 0x5a, 0x13, 0x4b, 0x6a, 0x57, + 0x60, 0x8c, 0x1e, 0x57, 0x45, 0xed, 0x53, 0x5f, 0x43, 0x28, 0x52, 0xad, 0x99, 0x63, 0x8d, 0x1b, 0x23, 0xe2, 0x0e, + 0x2b, 0xd7, 0x4e, 0xed, 0x75, 0x00, 0x96, 0x57, 0xe3, 0x82, 0xb0, 0x49, 0x8e, 0x9d, 0x0b, 0x58, 0x8d, 0x86, 0x54, + 0xbb, 0xe1, 0xd6, 0xcb, 0xce, 0x6f, 0x1e, 0x27, 0xb6, 0x36, 0xc2, 0x2d, 0x05, 0x94, 0x51, 0x7e, 0x63, 0x39, 0x61, + 0x77, 0xaa, 0x77, 0xa4, 0x6a, 0x47, 0x9c, 0xb8, 0x80, 0xe5, 0x86, 0xa7, 0x56, 0xdf, 0xc4, 0xe0, 0x44, 0xa8, 0x5a, + 0xe9, 0x78, 0xed, 0x47, 0xdc, 0xaf, 0xee, 0xeb, 0x5e, 0x09, 0x7e, 0x12, 0xf2, 0xfa, 0x2d, 0xef, 0x00, 0xb0, 0xe2, + 0x43, 0x5e, 0x4c, 0x0b, 0x47, 0xeb, 0x32, 0x28, 0x03, 0x44, 0x68, 0x06, 0x40, 0x27, 0x57, 0x07, 0x51, 0x1a, 0xb8, + 0xe2, 0x0e, 0x11, 0x7e, 0x1a, 0x3d, 0xcb, 0xaf, 0xc3, 0x67, 0xd5, 0x34, 0xbc, 0xc8, 0x83, 0xe8, 0xa2, 0x0a, 0xa2, + 0x67, 0xd5, 0x55, 0xf8, 0x2c, 0x9f, 0x46, 0x17, 0x79, 0x10, 0x5e, 0x54, 0x8d, 0x7d, 0xd7, 0xee, 0xee, 0x09, 0x79, + 0xdb, 0xd5, 0x1f, 0x39, 0x57, 0xf6, 0x94, 0xe9, 0xf9, 0x79, 0xad, 0x57, 0x6a, 0xb7, 0xb9, 0x5e, 0xa3, 0x66, 0xea, + 0xa3, 0xec, 0x6f, 0xb6, 0xb1, 0xf0, 0x68, 0x0e, 0xa1, 0xcf, 0x48, 0x8b, 0xb9, 0xc7, 0xb9, 0xde, 0xec, 0x49, 0x61, + 0x60, 0xc4, 0xa4, 0x92, 0x91, 0xd3, 0x0b, 0x5c, 0x84, 0x2a, 0xc4, 0xb0, 0x96, 0xae, 0xf6, 0x59, 0x97, 0xde, 0x40, + 0x5d, 0x53, 0xec, 0x6b, 0xc8, 0xc0, 0x8b, 0xa6, 0x97, 0xc1, 0x18, 0x90, 0x23, 0xf0, 0x8e, 0xcf, 0x96, 0x70, 0x60, + 0xae, 0x01, 0xfa, 0xe6, 0x51, 0x5f, 0x97, 0x3b, 0xbe, 0x56, 0x7d, 0x33, 0x5d, 0x8f, 0x94, 0xf2, 0x63, 0xc5, 0xef, + 0x2e, 0x9e, 0xb3, 0x5b, 0xae, 0x51, 0x51, 0x7e, 0xd1, 0x8b, 0xf5, 0x1e, 0xb8, 0xea, 0x7e, 0x81, 0xdb, 0x2c, 0x1e, + 0xbb, 0xf2, 0x80, 0x65, 0x5b, 0xf6, 0xc0, 0x6e, 0xd8, 0x7b, 0xf6, 0x84, 0xbd, 0x61, 0xef, 0xd8, 0x4f, 0xa8, 0xda, + 0x50, 0x42, 0x9e, 0xbf, 0xe0, 0xb7, 0xd2, 0xf4, 0x28, 0x51, 0xc9, 0x1e, 0x6c, 0x33, 0xcd, 0x70, 0xc3, 0xde, 0xf3, + 0xc5, 0x70, 0xc5, 0xde, 0x40, 0x36, 0x94, 0x89, 0x07, 0x2b, 0xf6, 0x13, 0x57, 0x20, 0x66, 0xfa, 0x2c, 0x2c, 0x2d, + 0x51, 0xd1, 0x94, 0x89, 0x32, 0xf4, 0x1b, 0x8e, 0x2f, 0xb2, 0x9f, 0xb0, 0x08, 0xf9, 0x99, 0xe1, 0x8a, 0x3d, 0xf0, + 0xc5, 0x60, 0xc5, 0xde, 0x6b, 0x03, 0xd1, 0x60, 0xe3, 0x96, 0x46, 0x48, 0x56, 0xba, 0x2c, 0x29, 0x4d, 0x6f, 0xed, + 0x6b, 0xe0, 0x86, 0xdd, 0x60, 0xed, 0x9e, 0x60, 0xd1, 0x28, 0xf0, 0x0f, 0x56, 0xec, 0x1d, 0x97, 0x00, 0x6a, 0x6e, + 0x79, 0xd2, 0x2b, 0x54, 0x17, 0x48, 0xf7, 0x83, 0x27, 0x9c, 0x5e, 0x64, 0xef, 0xb0, 0x0c, 0xfa, 0xca, 0x70, 0xc5, + 0xb6, 0x58, 0xbb, 0x1b, 0x63, 0xd9, 0xb2, 0xaa, 0x27, 0x11, 0x81, 0x51, 0x50, 0x29, 0x2d, 0xff, 0x46, 0x2c, 0x9b, + 0xba, 0x69, 0x50, 0x1b, 0xfa, 0xf3, 0xc1, 0xe8, 0x2f, 0xbe, 0x7e, 0xf7, 0x83, 0x57, 0xea, 0x6b, 0xef, 0x2f, 0x8e, + 0x6b, 0x65, 0x89, 0xae, 0x95, 0xbf, 0xf2, 0x72, 0xf6, 0xcb, 0x7c, 0xa2, 0x6b, 0x49, 0x3b, 0x0c, 0xf9, 0x9a, 0xce, + 0x7e, 0xe9, 0x70, 0xb6, 0xfc, 0xd5, 0xf7, 0x1b, 0xd3, 0xc5, 0xea, 0xb3, 0xba, 0x77, 0x1f, 0x06, 0x9b, 0xc6, 0xa9, + 0xf7, 0xee, 0x74, 0xbd, 0xb1, 0x99, 0xb5, 0xf6, 0xcc, 0xfc, 0x1f, 0xae, 0xf4, 0x16, 0x87, 0xee, 0x86, 0x6f, 0x87, + 0x1b, 0x7b, 0x14, 0xe4, 0xf7, 0xa5, 0xd2, 0x38, 0xab, 0xf9, 0x0b, 0xaf, 0x53, 0x8a, 0x05, 0x44, 0xa3, 0x4f, 0x46, + 0x12, 0xba, 0x64, 0x26, 0x9e, 0x21, 0xbe, 0xc8, 0x00, 0x99, 0x0b, 0x44, 0xb3, 0x7b, 0x3e, 0x9e, 0xdc, 0x5f, 0xc5, + 0x93, 0xfb, 0x01, 0xff, 0x64, 0x5a, 0xd0, 0x5e, 0x6c, 0xf7, 0x3e, 0xfb, 0x95, 0x17, 0xf6, 0x72, 0xfc, 0xc5, 0x67, + 0x5f, 0x84, 0xbb, 0x42, 0x7f, 0xf1, 0xd9, 0x3b, 0xc1, 0x7f, 0x1d, 0x69, 0xa2, 0x0c, 0xf6, 0xae, 0xe6, 0xbf, 0x8e, + 0x90, 0xf1, 0x83, 0x7d, 0x16, 0xfc, 0x0b, 0xf8, 0x7e, 0x57, 0x09, 0x5a, 0xc5, 0x3f, 0xd7, 0xea, 0xe7, 0x7b, 0x19, + 0x97, 0x03, 0x6f, 0x42, 0x2b, 0xe8, 0xcd, 0xdb, 0x5a, 0xfe, 0x24, 0x1e, 0x8e, 0x54, 0x3d, 0x35, 0xfc, 0xb3, 0x58, + 0xcc, 0xa2, 0x3e, 0x4a, 0xa7, 0xf2, 0x26, 0x6f, 0x79, 0x26, 0xad, 0xcb, 0xf7, 0x10, 0x0a, 0xfc, 0xd6, 0x86, 0x28, + 0xd8, 0x71, 0xdc, 0x08, 0xde, 0xb2, 0x77, 0xc2, 0x67, 0xd9, 0x74, 0xcb, 0x6f, 0xf8, 0x13, 0xfe, 0x8e, 0xef, 0x82, + 0x07, 0xfe, 0x9e, 0xbf, 0xe1, 0x3f, 0xf1, 0x1d, 0x5b, 0x4a, 0xb4, 0xd3, 0x7a, 0x7b, 0x19, 0x6c, 0x59, 0xbd, 0xbb, + 0x0c, 0x1e, 0x58, 0xbd, 0x7d, 0x1e, 0xdc, 0xb0, 0x7a, 0xf7, 0x3c, 0x78, 0xcf, 0xb6, 0x97, 0xc1, 0x13, 0xb6, 0xbb, + 0x0c, 0xde, 0xb0, 0xed, 0xf3, 0xe0, 0x1d, 0xdb, 0x3d, 0x0f, 0x7e, 0x92, 0x18, 0x0f, 0xef, 0x84, 0xe4, 0x38, 0x79, + 0x57, 0x33, 0xc3, 0xa7, 0x1b, 0x7c, 0x16, 0xd6, 0x2f, 0xaa, 0x63, 0xf0, 0xb9, 0x66, 0xba, 0xc5, 0x81, 0x10, 0x4c, + 0xb7, 0x37, 0xb8, 0xa5, 0x27, 0xa6, 0x55, 0x41, 0x2a, 0x58, 0x57, 0x3b, 0x83, 0x45, 0xdd, 0xb4, 0xce, 0x64, 0xc7, + 0x2f, 0x31, 0xee, 0xf0, 0x4b, 0x5c, 0xb0, 0x65, 0xd3, 0xe9, 0xa4, 0x73, 0xfa, 0x24, 0xd0, 0x9b, 0xbf, 0xde, 0xf5, + 0x2b, 0xe9, 0x3b, 0x53, 0x34, 0x3c, 0x57, 0x5a, 0xe3, 0xd6, 0x4e, 0x1f, 0x5a, 0x3b, 0x3d, 0x93, 0x2a, 0xb4, 0x88, + 0x45, 0x65, 0x51, 0x55, 0xc8, 0x24, 0x1e, 0x64, 0x5a, 0x9f, 0x96, 0x30, 0x52, 0x64, 0x02, 0x1a, 0x7d, 0x41, 0xc7, + 0x40, 0x4e, 0x16, 0x05, 0xb6, 0xe4, 0x9b, 0x41, 0xc2, 0xd6, 0x3c, 0x9e, 0x0e, 0x93, 0x60, 0xc9, 0xee, 0xf8, 0xb0, + 0x5b, 0x20, 0x58, 0xa9, 0x00, 0x26, 0x7d, 0x71, 0x6a, 0xef, 0xeb, 0xbc, 0xb7, 0x4a, 0xe3, 0x38, 0x13, 0xa8, 0x6c, + 0xab, 0xf4, 0x06, 0xbf, 0x75, 0xf6, 0xf3, 0xb5, 0xda, 0xdf, 0x41, 0x52, 0xf8, 0x15, 0x18, 0x76, 0x88, 0xf0, 0x0e, + 0x2a, 0x8c, 0x3c, 0x4b, 0x66, 0xd1, 0x57, 0xf6, 0x96, 0xbe, 0x35, 0xdb, 0xf4, 0x7f, 0x5a, 0x04, 0xed, 0xe3, 0xb2, + 0xf3, 0x3f, 0x99, 0x57, 0x7f, 0xeb, 0x78, 0x75, 0xe3, 0x4f, 0x1e, 0xf8, 0x27, 0x0c, 0x4b, 0xc0, 0x44, 0xb6, 0xe3, + 0x9f, 0x46, 0xdb, 0xc6, 0x29, 0x4f, 0xee, 0xe3, 0xff, 0x57, 0x0a, 0xb4, 0x77, 0xf2, 0xca, 0xde, 0x11, 0xb7, 0xbc, + 0x63, 0x1f, 0x5f, 0x5a, 0x1b, 0xa2, 0x81, 0x26, 0xf9, 0xc4, 0xdd, 0x68, 0x68, 0xd8, 0x10, 0x7f, 0xe1, 0xd5, 0xec, + 0xd3, 0x7c, 0xb2, 0xe5, 0xc7, 0xdb, 0xe1, 0xa7, 0x8e, 0xed, 0xf0, 0x17, 0x7f, 0xb0, 0x6c, 0xbe, 0xd6, 0xab, 0x9d, + 0xdb, 0xb8, 0x53, 0xe9, 0x1d, 0x3f, 0xde, 0xc4, 0x87, 0xff, 0x71, 0xa5, 0x77, 0xdf, 0x5c, 0x69, 0xbb, 0xca, 0xdd, + 0x9d, 0x6f, 0x3a, 0xbe, 0x91, 0xb5, 0xc6, 0x38, 0x33, 0xa3, 0x59, 0xfc, 0x89, 0x66, 0x69, 0x10, 0x59, 0x0a, 0xc5, + 0x9f, 0xcc, 0xb4, 0x53, 0x77, 0xaa, 0xac, 0xee, 0x96, 0x6f, 0x71, 0x8f, 0xbf, 0xe5, 0x63, 0xb6, 0x30, 0x9e, 0x9a, + 0xb7, 0x57, 0x8b, 0xc9, 0x60, 0x70, 0xeb, 0xef, 0xef, 0x79, 0x38, 0xbb, 0x9d, 0xb3, 0xb7, 0xfc, 0x9e, 0x16, 0xd3, + 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, + 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, 0xde, 0xdb, 0x9a, 0x86, 0x37, 0xfc, 0xa3, 0xf7, + 0xd6, 0x9f, 0xbe, 0xd5, 0x31, 0x37, 0x13, 0x75, 0x24, 0xbd, 0xb9, 0x78, 0xce, 0x7e, 0xe5, 0x9f, 0xe4, 0x71, 0xf2, + 0x45, 0xc8, 0x49, 0x7b, 0x83, 0xdc, 0x4d, 0x74, 0x4a, 0xbc, 0x73, 0x13, 0x09, 0x0b, 0x02, 0x61, 0x38, 0x6a, 0xfe, + 0x30, 0x29, 0xa7, 0xde, 0x0e, 0xb8, 0x5d, 0xb9, 0xad, 0x7f, 0xbe, 0xe5, 0x9c, 0x2f, 0x86, 0x97, 0xd3, 0x77, 0xdd, + 0x2e, 0x3d, 0x2a, 0x9a, 0x4d, 0x05, 0xba, 0xdd, 0x62, 0xec, 0xd5, 0xc9, 0xcc, 0x32, 0x97, 0x7c, 0xe9, 0x5d, 0x6d, + 0x66, 0x1e, 0xd3, 0xfb, 0xcd, 0x34, 0x43, 0x22, 0x5f, 0x20, 0x64, 0x3a, 0x1c, 0xee, 0xce, 0xb1, 0x3c, 0x3e, 0x7c, + 0xf3, 0xec, 0xc9, 0xe0, 0x09, 0x46, 0x6e, 0x59, 0xd1, 0x20, 0xef, 0xf8, 0x30, 0xab, 0x5b, 0xb7, 0x8d, 0x8b, 0xe7, + 0xc3, 0x5f, 0x20, 0x6f, 0xd0, 0xf5, 0xd0, 0x14, 0xd1, 0x2a, 0xbf, 0xa3, 0xe8, 0x13, 0x25, 0x07, 0x1d, 0x4f, 0xa0, + 0x76, 0x48, 0x81, 0xfb, 0xee, 0x19, 0x07, 0xfd, 0x06, 0x96, 0xda, 0xef, 0x9f, 0x7f, 0x22, 0x1e, 0x69, 0x18, 0xef, + 0xef, 0xc3, 0xe8, 0x8f, 0xb8, 0x2c, 0xd6, 0x70, 0xba, 0x0e, 0xe0, 0x73, 0xcf, 0xf4, 0xed, 0xeb, 0xce, 0xf7, 0xfd, + 0xc0, 0xdb, 0xf2, 0x1b, 0xf6, 0x8e, 0x7b, 0x97, 0xc3, 0x37, 0xfe, 0xb3, 0x27, 0x20, 0x3a, 0xc1, 0xb8, 0x7c, 0xc6, + 0x48, 0xd8, 0x8e, 0x62, 0xd4, 0x2a, 0xfc, 0x5c, 0x43, 0x88, 0xd6, 0x27, 0x64, 0xec, 0x82, 0xf4, 0x0f, 0x0a, 0xd0, + 0x4f, 0x08, 0xac, 0x26, 0xa9, 0x51, 0x60, 0x12, 0xdf, 0xd6, 0x90, 0x40, 0x0a, 0x16, 0x08, 0xbd, 0x81, 0xe2, 0x53, + 0xc1, 0xdf, 0x0d, 0x3f, 0x93, 0xe4, 0xb7, 0xa8, 0xf9, 0x18, 0xfe, 0x86, 0xa1, 0x99, 0x54, 0x0f, 0x69, 0x1d, 0x25, + 0xde, 0x4f, 0xfe, 0x3e, 0x0a, 0x2b, 0xa1, 0x8e, 0x85, 0x20, 0x15, 0x43, 0x2e, 0xc4, 0xc5, 0xf3, 0xc9, 0x6d, 0x29, + 0xc2, 0x3f, 0x26, 0xf8, 0x4c, 0x2e, 0x34, 0xf9, 0x8c, 0x9e, 0x34, 0xf2, 0xfd, 0x07, 0xf9, 0xbe, 0xec, 0xd4, 0x60, + 0x51, 0x0f, 0xf9, 0x6d, 0xed, 0xbe, 0x2f, 0xa7, 0x04, 0x3d, 0xb2, 0x1f, 0xd0, 0x14, 0x0c, 0xd4, 0x04, 0xa4, 0x0c, + 0xc1, 0x2d, 0x5c, 0xf5, 0x3d, 0x55, 0x90, 0x2f, 0xbf, 0xf7, 0x59, 0xc8, 0x70, 0x95, 0x05, 0x21, 0xc9, 0xa5, 0x42, + 0x0a, 0x1b, 0xb7, 0xf5, 0xe0, 0xb3, 0xc6, 0x24, 0x91, 0x90, 0x53, 0x02, 0x92, 0xa4, 0xbd, 0x81, 0x24, 0x11, 0xd3, + 0x7f, 0xb8, 0x4e, 0x9a, 0x66, 0x25, 0xa5, 0x1b, 0xe2, 0x54, 0x7d, 0x8b, 0x34, 0x67, 0xc1, 0x7b, 0x06, 0x4b, 0x47, + 0x8a, 0x15, 0xef, 0x8c, 0xc1, 0x58, 0x07, 0x0b, 0xdd, 0xc9, 0xe2, 0x7e, 0x95, 0x84, 0x69, 0x24, 0xaa, 0x7c, 0x11, + 0xf2, 0xe7, 0xbf, 0x94, 0xf8, 0xa3, 0xb7, 0x34, 0x10, 0x81, 0xe0, 0x07, 0x68, 0x3d, 0x60, 0x8d, 0x07, 0x3f, 0xb1, + 0xba, 0x0c, 0xf3, 0x2a, 0xa3, 0xf2, 0x66, 0x3b, 0xb6, 0x9d, 0x33, 0x55, 0xb5, 0xe0, 0xb3, 0x30, 0xb4, 0x68, 0x67, + 0xab, 0xe6, 0xe4, 0x36, 0x6f, 0xf0, 0x9d, 0x49, 0x12, 0xa9, 0xa5, 0x24, 0xd2, 0x56, 0xd7, 0xa7, 0x4b, 0xaf, 0x5b, + 0x54, 0xd0, 0x18, 0x01, 0x7a, 0x49, 0xba, 0xab, 0x7c, 0x42, 0xf1, 0xca, 0x6a, 0x58, 0x0d, 0x2f, 0x1d, 0x8a, 0x30, + 0xd6, 0xde, 0x5c, 0xc9, 0xb3, 0x3b, 0xb0, 0x1e, 0xa1, 0xb5, 0xab, 0x52, 0x87, 0xb0, 0xfd, 0x44, 0xef, 0x39, 0x95, + 0xfa, 0x1b, 0x50, 0x05, 0x4e, 0x1d, 0x0d, 0xf5, 0x51, 0x3b, 0x85, 0x6c, 0xe7, 0xde, 0x92, 0xa0, 0x72, 0x25, 0x37, + 0x55, 0x5a, 0x94, 0x52, 0xa6, 0x7c, 0x2d, 0xb3, 0x95, 0xdd, 0x27, 0x03, 0x88, 0x67, 0x83, 0x02, 0xc9, 0x45, 0x6d, + 0x35, 0x07, 0xe9, 0xa3, 0x59, 0xe2, 0x58, 0x3b, 0x28, 0xbc, 0xac, 0x02, 0x33, 0x97, 0xb9, 0x5c, 0x0e, 0x0a, 0x96, + 0xeb, 0xad, 0x66, 0x9a, 0xa9, 0xbe, 0xc8, 0xed, 0x6d, 0xc6, 0xcb, 0xf4, 0xdf, 0x2c, 0x19, 0xf0, 0xe8, 0xe2, 0xb9, + 0x1f, 0x40, 0x9a, 0xe4, 0x75, 0x80, 0x24, 0xd8, 0x1c, 0xec, 0x62, 0x87, 0x61, 0xab, 0x58, 0xd9, 0x93, 0xa7, 0xcb, + 0x1d, 0x9a, 0x72, 0x09, 0x23, 0x39, 0x31, 0x97, 0x52, 0xdf, 0x97, 0x54, 0x37, 0x14, 0x9c, 0x6c, 0x9a, 0x80, 0x52, + 0x40, 0xbb, 0x05, 0xff, 0x85, 0x4f, 0x0d, 0x9d, 0x16, 0x60, 0xa9, 0xed, 0x06, 0xfc, 0x17, 0xfa, 0xc5, 0xf6, 0x11, + 0xf5, 0x03, 0xf3, 0x60, 0x6f, 0xd6, 0x56, 0xc6, 0x80, 0x88, 0xc4, 0x15, 0xe4, 0x91, 0xe0, 0x07, 0xc5, 0x9e, 0x2e, + 0x13, 0x07, 0xce, 0x14, 0x17, 0x4b, 0xa9, 0xcd, 0xcc, 0x6b, 0xbf, 0xa5, 0x26, 0xde, 0x44, 0x49, 0x54, 0xd8, 0x0e, + 0x69, 0xf4, 0x92, 0x32, 0xa6, 0x0a, 0x36, 0x44, 0xf7, 0x75, 0x13, 0x4c, 0x81, 0x37, 0x55, 0x15, 0x10, 0xa1, 0xf6, + 0x22, 0xcb, 0xf3, 0x9b, 0x2e, 0xb0, 0xba, 0xe0, 0x63, 0x63, 0x9a, 0x5d, 0xb0, 0x92, 0xab, 0x99, 0xf4, 0x99, 0xb7, + 0x03, 0x2d, 0xe4, 0x5d, 0x5e, 0x16, 0xad, 0xd0, 0xf5, 0x20, 0x5a, 0xf8, 0x7b, 0xcd, 0xf1, 0xe8, 0xd9, 0xb6, 0x9a, + 0xda, 0xec, 0x6b, 0x2d, 0x16, 0xc8, 0x40, 0x34, 0xf4, 0x85, 0x9c, 0x51, 0xb8, 0xab, 0x34, 0x57, 0xab, 0x7d, 0x55, + 0x06, 0x09, 0x4c, 0x04, 0x59, 0xcb, 0xc2, 0x7b, 0x74, 0xaf, 0x1e, 0x69, 0x5e, 0x49, 0xf0, 0xcc, 0xc5, 0x5f, 0x00, + 0x08, 0xe5, 0x49, 0x42, 0x0e, 0xc8, 0x01, 0xfc, 0x2d, 0x45, 0xa9, 0x34, 0xc0, 0x3f, 0xab, 0xcb, 0xb1, 0xad, 0xef, + 0xef, 0xb4, 0x8a, 0xc1, 0xf5, 0xe7, 0xeb, 0xae, 0x67, 0xed, 0x10, 0xe7, 0xca, 0x56, 0xaf, 0x2d, 0xd3, 0x3c, 0x46, + 0xea, 0x1a, 0x80, 0x3b, 0x91, 0x1e, 0x81, 0x48, 0x66, 0xa2, 0x41, 0xce, 0xae, 0xf9, 0x78, 0x2a, 0x1e, 0x93, 0xf6, + 0x2a, 0xdf, 0x37, 0x17, 0xfa, 0x60, 0x8c, 0x7d, 0x0b, 0x1a, 0xc4, 0x47, 0xab, 0xad, 0x15, 0x88, 0xf5, 0x56, 0xa9, + 0x0f, 0xdd, 0x18, 0x05, 0x1d, 0x3c, 0xe2, 0x46, 0x2e, 0x38, 0xb6, 0xbb, 0xb6, 0x9e, 0xd2, 0x57, 0x00, 0xe6, 0x3a, + 0x50, 0xc9, 0x30, 0x48, 0x9d, 0x27, 0x0a, 0x93, 0xfc, 0x3c, 0x21, 0x09, 0x11, 0xd5, 0xd9, 0x72, 0x94, 0x72, 0xd3, + 0x02, 0x2e, 0x33, 0x32, 0xc0, 0x6c, 0xd2, 0xac, 0x9f, 0x5c, 0xbe, 0x04, 0xa9, 0x34, 0x44, 0x70, 0xc3, 0xf6, 0x92, + 0xd1, 0xad, 0xa3, 0x6e, 0x50, 0x25, 0x99, 0xeb, 0x37, 0xb7, 0xb3, 0x48, 0x99, 0x37, 0x1f, 0x61, 0xac, 0xc9, 0x87, + 0xb0, 0x4e, 0xf0, 0xdb, 0x00, 0x95, 0xf4, 0xa9, 0xf0, 0xa2, 0x11, 0x40, 0xa8, 0xef, 0x54, 0x19, 0x9f, 0x0a, 0x2f, + 0x1b, 0x6d, 0x59, 0x46, 0x29, 0x54, 0x17, 0xcc, 0x6e, 0x4d, 0x17, 0xa2, 0x5b, 0x55, 0x03, 0x6d, 0xe0, 0xda, 0x75, + 0xa0, 0x80, 0x86, 0x6a, 0x57, 0x6e, 0x58, 0x00, 0x56, 0x33, 0x11, 0x18, 0x2e, 0xff, 0x3e, 0x7f, 0xa9, 0x62, 0x78, + 0xfa, 0xfd, 0xd0, 0xdb, 0x6f, 0x83, 0x68, 0xb4, 0xbd, 0x64, 0xbb, 0x20, 0x1a, 0xed, 0x2e, 0x1b, 0x46, 0xbf, 0x9f, + 0xd3, 0xef, 0xe7, 0x0d, 0xe8, 0x48, 0x84, 0x09, 0xb3, 0xd7, 0x6f, 0xd4, 0xf2, 0x95, 0x5a, 0xbf, 0x53, 0xcb, 0x97, + 0x6a, 0x78, 0x6b, 0x4f, 0x12, 0x41, 0x64, 0xa9, 0x6a, 0x1e, 0x24, 0x45, 0xaa, 0xa5, 0xcb, 0x31, 0x5a, 0x8c, 0xa8, + 0xa5, 0xac, 0x39, 0xd6, 0x89, 0xb4, 0x73, 0x50, 0x32, 0xc0, 0xd1, 0xe2, 0xaa, 0xc6, 0x74, 0xb3, 0xa2, 0x25, 0x10, + 0x23, 0xac, 0x6c, 0xcb, 0xc5, 0x4d, 0xea, 0xa3, 0x73, 0xf2, 0x6d, 0xab, 0x94, 0x6f, 0x5b, 0xc1, 0xf3, 0xaf, 0x28, + 0x94, 0x4b, 0xae, 0x5d, 0xcb, 0xa6, 0x85, 0x52, 0x28, 0xe3, 0x1a, 0x6c, 0xed, 0x9b, 0xc0, 0x90, 0xf9, 0x48, 0x51, + 0x63, 0x7b, 0xd1, 0x28, 0x87, 0x20, 0x5b, 0x07, 0xa3, 0x4e, 0x59, 0xb0, 0xf8, 0x76, 0x87, 0x0c, 0x64, 0xa0, 0xa3, + 0xaa, 0x8d, 0x57, 0x3b, 0x2b, 0xfd, 0x61, 0x79, 0xf1, 0x9c, 0x25, 0x56, 0x3a, 0xf9, 0x4d, 0x85, 0xfe, 0x20, 0x44, + 0xdf, 0x94, 0x0d, 0x07, 0x2f, 0xba, 0xd8, 0xca, 0x80, 0x78, 0xc3, 0xf4, 0xde, 0xc6, 0x4a, 0x96, 0xbb, 0xa6, 0x7c, + 0x31, 0xe3, 0x09, 0xc7, 0xd1, 0x97, 0xab, 0x45, 0x58, 0xab, 0x45, 0x76, 0x02, 0x3c, 0xb4, 0x56, 0x4b, 0x21, 0x57, + 0x8b, 0x70, 0x66, 0xba, 0x50, 0x33, 0x3d, 0x03, 0xcd, 0xa3, 0x50, 0xb3, 0x3c, 0x01, 0x2c, 0x78, 0x61, 0x66, 0xb8, + 0x30, 0x33, 0x1c, 0x87, 0xd4, 0x38, 0x3d, 0xe8, 0xbd, 0xce, 0x3d, 0xb7, 0xdc, 0x8d, 0x4e, 0xc3, 0xbc, 0x1d, 0x6d, + 0x30, 0xc7, 0x07, 0xe1, 0x04, 0xe2, 0x03, 0x4b, 0x04, 0xe8, 0xd1, 0xb0, 0x3a, 0x6a, 0xa8, 0x1c, 0xc5, 0x97, 0x05, + 0x20, 0x59, 0x12, 0x80, 0xe4, 0x5e, 0x8d, 0x73, 0x69, 0xf9, 0x75, 0x95, 0x84, 0x1c, 0x91, 0xf1, 0x52, 0xda, 0xdd, + 0x13, 0x5e, 0x8e, 0x8c, 0xd0, 0x3c, 0x59, 0xa4, 0x5e, 0xce, 0x32, 0x36, 0x46, 0xe0, 0xa2, 0xd0, 0x6f, 0xaa, 0x7e, + 0x3f, 0x2d, 0xbd, 0x9c, 0xda, 0xf9, 0x09, 0xfc, 0x2d, 0x4f, 0x9d, 0x45, 0x8e, 0x90, 0x57, 0x23, 0x93, 0xb0, 0xbc, + 0x54, 0xea, 0xe9, 0x4b, 0x98, 0x41, 0xdd, 0xbd, 0x51, 0x00, 0xae, 0x45, 0x2e, 0x9d, 0x6a, 0x4b, 0xb8, 0x32, 0xe5, + 0x06, 0xfb, 0x3c, 0xe4, 0x39, 0x09, 0xa1, 0x12, 0x79, 0xa4, 0xb0, 0xee, 0xdb, 0x17, 0xcf, 0x27, 0xae, 0x0f, 0x8b, + 0x8d, 0x46, 0x70, 0x38, 0x00, 0xcc, 0xc1, 0xd4, 0x8b, 0x06, 0xbc, 0x54, 0x73, 0xe6, 0xa3, 0x97, 0x13, 0x36, 0x06, + 0xa8, 0x29, 0x06, 0x4e, 0x59, 0xcf, 0xe4, 0x23, 0xe3, 0x5b, 0xe6, 0xfb, 0x01, 0xbe, 0x5b, 0x17, 0x12, 0xf2, 0x41, + 0xa1, 0x12, 0x64, 0x0a, 0x95, 0x20, 0x31, 0xa8, 0x04, 0xb1, 0x41, 0x25, 0xd8, 0x34, 0x7c, 0x2d, 0x95, 0xb7, 0x11, + 0x70, 0x44, 0xf8, 0xd0, 0xb3, 0xb0, 0xb1, 0x42, 0xf1, 0x6c, 0xcc, 0xc6, 0xac, 0x50, 0x3b, 0x4f, 0x2e, 0xa7, 0x62, + 0x67, 0x31, 0xd6, 0x4d, 0x64, 0x99, 0x78, 0x21, 0x41, 0xc7, 0x39, 0x17, 0x12, 0x75, 0xf5, 0x73, 0xef, 0x25, 0x19, + 0x4b, 0xe6, 0x0d, 0x8d, 0x1a, 0xcc, 0xcb, 0xae, 0x03, 0x98, 0x96, 0x7c, 0x5b, 0xd0, 0x60, 0x3a, 0x55, 0x1e, 0x91, + 0x26, 0x41, 0xed, 0x5c, 0x26, 0x45, 0x4e, 0x08, 0x93, 0xa0, 0x57, 0x82, 0xdf, 0x48, 0x68, 0xff, 0xaf, 0x7a, 0xbe, + 0x03, 0x06, 0x13, 0xad, 0x92, 0x2f, 0x60, 0xb5, 0xcc, 0xf9, 0x0b, 0xe9, 0x89, 0x8d, 0xf8, 0x8b, 0x65, 0x1a, 0x8f, + 0xbe, 0xb0, 0x21, 0xe2, 0x59, 0xbd, 0x40, 0xd3, 0x12, 0xd4, 0x01, 0x1e, 0xd1, 0x5f, 0xa3, 0x2f, 0x86, 0x37, 0xa5, + 0xab, 0x91, 0xba, 0x66, 0xe7, 0x9c, 0x7f, 0xa9, 0x0d, 0x11, 0x32, 0xa6, 0x4d, 0x81, 0x64, 0x40, 0x20, 0xc9, 0x40, + 0x00, 0x60, 0x6a, 0x3a, 0xb3, 0x57, 0x00, 0xd1, 0x40, 0x00, 0x8f, 0xf3, 0x8e, 0xc7, 0x8f, 0xf4, 0x57, 0x71, 0xdc, + 0x3b, 0x4d, 0xc3, 0xf6, 0x5f, 0x80, 0xa6, 0x18, 0xca, 0xf1, 0x7c, 0xa7, 0x20, 0xd9, 0xa3, 0x94, 0xa5, 0xab, 0x26, + 0xb2, 0x43, 0xb1, 0x3e, 0xcd, 0x29, 0x0b, 0x69, 0x5b, 0x8e, 0xd1, 0x16, 0xeb, 0xc7, 0xc8, 0x7b, 0x73, 0xa3, 0x22, + 0x1f, 0xf4, 0xe0, 0xf6, 0xf6, 0xe6, 0x55, 0x8f, 0xd9, 0x24, 0x2b, 0x16, 0xb9, 0x8a, 0x38, 0x71, 0x5a, 0x87, 0x1c, + 0x30, 0x20, 0x27, 0x21, 0x30, 0x8d, 0x71, 0xa9, 0x40, 0x07, 0x25, 0xcb, 0x79, 0x0d, 0xd4, 0xb2, 0x88, 0xac, 0x01, + 0xa2, 0x9a, 0xe6, 0x5f, 0x35, 0xe4, 0x27, 0x55, 0x73, 0x4a, 0xa1, 0xf6, 0x15, 0x0f, 0xab, 0xd3, 0x27, 0x56, 0x6d, + 0x62, 0xac, 0x7f, 0xad, 0x3d, 0x41, 0x5b, 0x49, 0x03, 0xf1, 0x9d, 0xaf, 0xd2, 0x3b, 0x0a, 0xdd, 0x71, 0x66, 0xe2, + 0xa9, 0x0a, 0x8c, 0x7d, 0x6b, 0x47, 0x50, 0x38, 0x34, 0x5d, 0x07, 0x1c, 0xa6, 0xd1, 0x09, 0x8b, 0x7f, 0x4a, 0xc7, + 0xc9, 0x8b, 0x5a, 0x21, 0x92, 0xfc, 0x43, 0xb8, 0x30, 0x24, 0x16, 0xe4, 0x25, 0xa1, 0x8e, 0xc8, 0x88, 0xd5, 0xa8, + 0x58, 0x0b, 0x15, 0x15, 0xa7, 0x78, 0xbc, 0x55, 0x50, 0x5c, 0x8a, 0x52, 0xa5, 0x54, 0xe4, 0x46, 0xa5, 0x80, 0x58, + 0x36, 0xf0, 0x6e, 0x01, 0x07, 0x40, 0xd0, 0x59, 0xee, 0xd6, 0xb6, 0xbb, 0x8d, 0xcc, 0x67, 0xa6, 0x79, 0x5a, 0x7d, + 0x50, 0x7f, 0xbf, 0x5f, 0x62, 0x6c, 0x8d, 0xa7, 0xbf, 0x6f, 0xd3, 0x82, 0x9b, 0xbf, 0x61, 0x88, 0xee, 0x00, 0x11, + 0xb3, 0xb4, 0x87, 0x42, 0x16, 0x4c, 0x58, 0x86, 0xaa, 0x3c, 0xe5, 0xa8, 0x97, 0x4f, 0x6e, 0x01, 0x42, 0x0d, 0xfd, + 0xda, 0xe8, 0x54, 0x57, 0x25, 0x08, 0xdf, 0x77, 0x85, 0x7a, 0x6c, 0x0e, 0x78, 0x32, 0x00, 0xfe, 0x8a, 0xbc, 0xd6, + 0x63, 0xfb, 0x07, 0xbd, 0x51, 0x6f, 0x80, 0x20, 0x3a, 0xe7, 0x85, 0x7f, 0xc4, 0xb9, 0x4e, 0xfd, 0x19, 0x17, 0x82, + 0xf8, 0xd6, 0x93, 0xf0, 0x5e, 0x9c, 0xa5, 0x71, 0x70, 0xd6, 0x1b, 0x98, 0x8b, 0x40, 0x71, 0x96, 0xe6, 0x67, 0x20, + 0x96, 0x23, 0x26, 0x62, 0xcd, 0xee, 0x00, 0x26, 0xb0, 0xd4, 0x71, 0xc8, 0xaa, 0x63, 0xfb, 0xfd, 0xd7, 0x23, 0x43, + 0x96, 0x8e, 0x30, 0x30, 0xfa, 0x77, 0x05, 0x02, 0x14, 0x2c, 0x33, 0xdb, 0x83, 0x49, 0x57, 0x7b, 0x56, 0xcf, 0x9b, + 0x4d, 0xde, 0xd5, 0x3b, 0x56, 0xd3, 0x72, 0x6a, 0x5a, 0x65, 0x35, 0x6d, 0x92, 0x43, 0xcd, 0x44, 0xbf, 0xaf, 0x41, + 0x51, 0xf3, 0x39, 0x80, 0xb1, 0x61, 0xf2, 0xeb, 0x59, 0x35, 0xef, 0xf7, 0x3d, 0xf9, 0x08, 0x7e, 0x21, 0x5b, 0x99, + 0x5b, 0x63, 0xf9, 0xf4, 0x15, 0x91, 0x98, 0x19, 0x98, 0xa3, 0xbb, 0x23, 0x7c, 0xaf, 0x1b, 0xe1, 0x75, 0xcc, 0x15, + 0x36, 0x13, 0xd3, 0xd7, 0x30, 0x78, 0x9e, 0xf0, 0xc1, 0x45, 0x8e, 0xfe, 0x46, 0x0e, 0x33, 0x85, 0x05, 0x39, 0xf7, + 0x27, 0xaf, 0x11, 0x2f, 0x19, 0xe1, 0x1d, 0x74, 0x3a, 0xe1, 0x41, 0xf6, 0xfb, 0x2b, 0xe8, 0xcc, 0x56, 0x2a, 0x65, + 0xab, 0xa2, 0x32, 0x5d, 0xd7, 0x45, 0x59, 0x41, 0xc7, 0xd2, 0xcf, 0x5b, 0x21, 0x33, 0xeb, 0x67, 0x16, 0xdc, 0xd3, + 0x4a, 0x02, 0x4c, 0xd9, 0xb6, 0x89, 0xda, 0xc0, 0xcb, 0xba, 0xf8, 0x5c, 0xe0, 0xd1, 0x59, 0x7b, 0xbd, 0x11, 0x6a, + 0x9f, 0xf3, 0xd1, 0xba, 0x58, 0x7b, 0xe0, 0x07, 0x33, 0x4b, 0xe7, 0x8a, 0x38, 0x23, 0xf7, 0x47, 0x9f, 0x8b, 0x34, + 0xa7, 0x3c, 0xc0, 0x7d, 0x28, 0xe6, 0xf6, 0x5b, 0x20, 0xfd, 0xd0, 0x5b, 0x20, 0xfb, 0xe8, 0x9c, 0x93, 0xd7, 0x80, + 0x48, 0x87, 0x30, 0xb8, 0x15, 0x09, 0x3a, 0x56, 0x0d, 0x6f, 0x2d, 0xb0, 0xd3, 0x5e, 0x1a, 0xf7, 0xd2, 0xfc, 0x2c, + 0xed, 0xf7, 0x0d, 0x6a, 0x66, 0x8a, 0x70, 0xf0, 0x38, 0x23, 0x17, 0x49, 0x0b, 0xb6, 0x94, 0xf6, 0x5f, 0x0d, 0x1c, + 0x41, 0xc8, 0xdf, 0xff, 0x10, 0xde, 0x13, 0x80, 0xd8, 0xa4, 0x0d, 0xb8, 0xea, 0x31, 0x1d, 0x8d, 0x2d, 0x89, 0x5a, + 0x75, 0x36, 0x40, 0xe2, 0x54, 0x69, 0x3d, 0xe5, 0x66, 0x4d, 0x61, 0x90, 0x2a, 0x0b, 0xf5, 0x1b, 0xeb, 0xc9, 0x64, + 0x95, 0x8b, 0x8c, 0x38, 0x2a, 0xd3, 0x97, 0x9a, 0x11, 0x4c, 0x97, 0x7e, 0xbe, 0x80, 0x25, 0x1b, 0x7f, 0xc4, 0xc9, + 0x5b, 0x02, 0x8e, 0xed, 0xac, 0x5d, 0x55, 0xbb, 0x1c, 0xb7, 0x76, 0x73, 0x80, 0xef, 0xf5, 0x46, 0xa3, 0x91, 0x76, + 0x8e, 0x13, 0x30, 0x54, 0x3d, 0xb5, 0x14, 0x7a, 0xac, 0x56, 0x80, 0xba, 0x1d, 0xb9, 0xcc, 0x92, 0xc1, 0x7c, 0x61, + 0x1c, 0xbf, 0x34, 0x1f, 0x7d, 0xbc, 0x54, 0xd6, 0xae, 0x23, 0xbe, 0xfe, 0x83, 0xac, 0xd6, 0xb7, 0xbc, 0xab, 0x9a, + 0x80, 0x2f, 0xaa, 0x80, 0xd2, 0x6f, 0x78, 0x4f, 0xf6, 0x2e, 0xbe, 0x76, 0x83, 0x5d, 0xf2, 0x2d, 0x6f, 0x51, 0xe7, + 0xf9, 0xca, 0xc1, 0x8d, 0x2a, 0xdd, 0xde, 0x4b, 0x16, 0xb8, 0xf6, 0x8e, 0x9a, 0xc6, 0x7a, 0xe6, 0x47, 0x0f, 0x8b, + 0x90, 0xed, 0x7c, 0xec, 0x7d, 0xd5, 0x3c, 0x3d, 0x6b, 0xe8, 0x4d, 0x6a, 0xe8, 0x63, 0x2f, 0xca, 0xf6, 0xa9, 0x69, + 0x44, 0xaf, 0x61, 0x43, 0x1f, 0x7b, 0x4b, 0x4e, 0x0e, 0x89, 0x00, 0xa7, 0xc6, 0xfc, 0xf1, 0xe1, 0x74, 0x86, 0xbf, + 0x63, 0x40, 0x25, 0x10, 0xf3, 0xe9, 0x31, 0xed, 0x28, 0xc0, 0x8c, 0x2a, 0xbd, 0x7d, 0x7a, 0x60, 0x3b, 0x5e, 0xd6, + 0x43, 0x4b, 0xef, 0x9e, 0x1c, 0xdd, 0x8e, 0x57, 0xd5, 0xf8, 0x52, 0x0e, 0x79, 0x9e, 0xcf, 0x46, 0xa3, 0x91, 0x30, + 0x90, 0xdc, 0x95, 0xde, 0xc0, 0x0a, 0xa4, 0x6d, 0x51, 0x7d, 0x28, 0x97, 0xde, 0x4e, 0x1d, 0xda, 0x95, 0x3f, 0xc9, + 0x0f, 0x87, 0x62, 0x64, 0x8e, 0x71, 0x00, 0x37, 0x29, 0x94, 0x1c, 0x25, 0x6b, 0x09, 0xa2, 0x53, 0x1a, 0x4f, 0x65, + 0xbd, 0xb6, 0x22, 0xf2, 0x6a, 0xc4, 0x79, 0x08, 0x7e, 0xf4, 0x40, 0x2d, 0x7e, 0xad, 0x05, 0xb1, 0xc7, 0x3e, 0x55, + 0x4a, 0x2f, 0x78, 0x55, 0x40, 0x88, 0xd8, 0xdf, 0x0d, 0xb4, 0x83, 0x12, 0x1c, 0x4a, 0xb8, 0x0f, 0x08, 0x0b, 0xfd, + 0xca, 0xcb, 0x67, 0x32, 0x46, 0xb9, 0x37, 0xa8, 0xe6, 0x0c, 0x60, 0x2a, 0x7d, 0x06, 0x7e, 0x97, 0x00, 0x75, 0x8a, + 0x4f, 0xd1, 0xa9, 0xde, 0x3c, 0x6c, 0xba, 0x3e, 0x2d, 0x51, 0x14, 0xd1, 0x9d, 0x9f, 0x8f, 0x01, 0xb1, 0xb3, 0x6b, + 0x33, 0xd2, 0xae, 0xfd, 0x06, 0x0d, 0x56, 0x4a, 0x12, 0xed, 0x9c, 0x12, 0x76, 0x3b, 0x1f, 0xd9, 0xd2, 0x8f, 0x52, + 0x20, 0xe6, 0x8e, 0x13, 0x89, 0xec, 0xc1, 0x46, 0x4e, 0xe0, 0x16, 0xed, 0x1d, 0x1d, 0x80, 0xca, 0x8d, 0x82, 0xfc, + 0x6a, 0x8e, 0xe4, 0x8e, 0xef, 0x7a, 0xdf, 0x0d, 0xea, 0xc1, 0x77, 0xbd, 0xb3, 0x94, 0xe4, 0x8e, 0xf0, 0x4c, 0x4d, + 0x09, 0x11, 0x9f, 0x7d, 0x37, 0xc8, 0x07, 0x78, 0x96, 0x68, 0x91, 0x16, 0x09, 0xd5, 0xea, 0x1a, 0x37, 0xe1, 0x45, + 0x22, 0xb9, 0x87, 0x76, 0x9d, 0x47, 0xc4, 0x02, 0x90, 0xb1, 0xf8, 0x6c, 0xde, 0x50, 0xa8, 0xbb, 0x89, 0xd9, 0xa2, + 0xbb, 0x2c, 0xf6, 0xfb, 0x9b, 0x3c, 0xad, 0x7b, 0x3a, 0x3e, 0x06, 0x5f, 0x90, 0x6a, 0x02, 0x3c, 0xda, 0x5f, 0x99, + 0xe3, 0xd5, 0xab, 0xcd, 0x91, 0xb2, 0x50, 0x25, 0xea, 0xb7, 0x58, 0xcd, 0x7a, 0x08, 0xc3, 0x9d, 0x65, 0xc6, 0xda, + 0x5e, 0xf0, 0x4a, 0xce, 0xaa, 0xd8, 0x2e, 0xc7, 0x57, 0x2c, 0xb5, 0x95, 0x44, 0xe5, 0x68, 0x3d, 0xd6, 0xa6, 0x18, + 0xf9, 0x95, 0x42, 0xa2, 0x2c, 0x3a, 0xb6, 0x16, 0x0a, 0x88, 0x17, 0xa0, 0x2f, 0xd9, 0x99, 0x06, 0x58, 0x6f, 0xf4, + 0x2a, 0x22, 0xb4, 0x7c, 0xa4, 0xc2, 0x9b, 0xdc, 0x54, 0x99, 0x95, 0xcd, 0xa2, 0xdd, 0x4f, 0x15, 0xaf, 0x10, 0xac, + 0xde, 0xa8, 0x3d, 0x0a, 0x50, 0x7b, 0x68, 0xa1, 0x0c, 0x20, 0xa5, 0x69, 0x06, 0x80, 0x0c, 0x00, 0x32, 0x55, 0xc4, + 0x67, 0x02, 0x54, 0xda, 0xea, 0x46, 0x81, 0x13, 0xe9, 0x15, 0xd0, 0x2c, 0xb0, 0xd2, 0x47, 0x0a, 0x32, 0x58, 0x6c, + 0x11, 0x80, 0x95, 0x23, 0x67, 0x98, 0xc6, 0x90, 0x6d, 0x34, 0x71, 0x49, 0x9a, 0xdf, 0x87, 0x59, 0x2a, 0xf1, 0x24, + 0x7e, 0x90, 0x35, 0x46, 0x00, 0x20, 0x7d, 0x9f, 0x5e, 0x14, 0x59, 0x4c, 0x38, 0x70, 0xd6, 0x53, 0x07, 0x45, 0x4d, + 0xce, 0xb5, 0xa6, 0xd5, 0xb3, 0xda, 0xe4, 0x21, 0x0b, 0x74, 0xf6, 0x60, 0x4c, 0x6a, 0xf9, 0x9e, 0x47, 0xf6, 0x57, + 0x8e, 0x67, 0x84, 0xef, 0xba, 0x83, 0x53, 0xff, 0xdd, 0xd4, 0xc0, 0xc4, 0x94, 0x00, 0x6c, 0x0c, 0x8e, 0x26, 0xc4, + 0xef, 0x74, 0x4c, 0xa6, 0x36, 0x29, 0x02, 0x81, 0x87, 0xe0, 0x15, 0x3c, 0x37, 0x5c, 0x6e, 0xb9, 0xb1, 0xb3, 0xc8, + 0xd3, 0x04, 0xe0, 0xc4, 0x0b, 0xbe, 0x05, 0x38, 0x4e, 0xbd, 0x2a, 0x64, 0xcf, 0x9e, 0x8b, 0xe9, 0x6c, 0x1e, 0x3c, + 0x24, 0xb4, 0x7f, 0x31, 0xe1, 0x37, 0xdd, 0x55, 0x72, 0x65, 0x6a, 0xdd, 0x9b, 0xe8, 0x2a, 0x97, 0x3b, 0x7d, 0x5a, + 0x71, 0x0c, 0x73, 0x06, 0xab, 0x80, 0x9c, 0xb3, 0x21, 0xbf, 0x3e, 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0x7e, 0x1d, + 0xca, 0x6a, 0x01, 0xdc, 0x23, 0xe7, 0x91, 0xf9, 0xe5, 0xab, 0xed, 0x50, 0xce, 0x29, 0x0a, 0x63, 0x39, 0x35, 0x2d, + 0x29, 0x4e, 0x87, 0x9e, 0x82, 0xc9, 0xd4, 0x96, 0xbf, 0xb7, 0x89, 0xcb, 0xec, 0xcd, 0x24, 0x9c, 0xaf, 0x23, 0xdb, + 0xd6, 0xaa, 0x7b, 0xe8, 0x86, 0x60, 0xd0, 0xc7, 0x08, 0x5a, 0x36, 0xd7, 0x77, 0xeb, 0xc1, 0x40, 0x61, 0xfb, 0xd6, + 0x74, 0xd3, 0xa2, 0x53, 0x1c, 0x70, 0x66, 0xad, 0x6b, 0x54, 0xaa, 0x8a, 0x43, 0x2f, 0x79, 0xb7, 0xac, 0xca, 0x2e, + 0x4b, 0x2f, 0x04, 0xa9, 0x51, 0x57, 0x11, 0x22, 0xa5, 0x62, 0x87, 0xf7, 0xe4, 0xd7, 0xc0, 0xc4, 0x33, 0x2b, 0x47, + 0x69, 0x3c, 0x07, 0x98, 0x20, 0x85, 0xbe, 0x29, 0xbf, 0x02, 0xdc, 0xd0, 0x45, 0x14, 0x66, 0x6f, 0xe2, 0x2a, 0xa8, + 0xad, 0xa6, 0xdf, 0x3b, 0x38, 0xb1, 0xe7, 0x75, 0xbf, 0x9f, 0x12, 0x8d, 0x1f, 0x86, 0x5e, 0xe0, 0xdf, 0xe3, 0xe9, + 0xbe, 0x09, 0x52, 0xf3, 0xca, 0x03, 0xbc, 0xa2, 0xcb, 0xad, 0x4d, 0xb9, 0xa2, 0x71, 0x31, 0xaf, 0x11, 0x11, 0x3e, + 0x75, 0x14, 0xdb, 0x6d, 0x7e, 0x9c, 0xda, 0x18, 0x0c, 0x42, 0xb8, 0x6f, 0x65, 0xfc, 0x3e, 0xf1, 0xf2, 0x59, 0x34, + 0x07, 0x45, 0x69, 0xa6, 0x49, 0x42, 0x0a, 0xe9, 0x25, 0x40, 0x1f, 0x0d, 0x42, 0xad, 0xae, 0xfc, 0x23, 0xf1, 0x52, + 0x35, 0xad, 0xcd, 0x53, 0xac, 0x51, 0x20, 0x66, 0xd1, 0xbc, 0x61, 0x19, 0x1d, 0x92, 0xea, 0x72, 0x69, 0x9a, 0xf1, + 0x87, 0xd5, 0x0c, 0xd5, 0x8a, 0xa3, 0x26, 0xa8, 0x51, 0xba, 0x81, 0x0b, 0xe0, 0xdf, 0xe9, 0x8e, 0xa3, 0x1a, 0x45, + 0x8a, 0x06, 0x7c, 0x82, 0xc0, 0xb0, 0x66, 0xf3, 0x84, 0xb5, 0xa6, 0xae, 0x19, 0xfd, 0xbe, 0x8c, 0x13, 0x32, 0x49, + 0x48, 0xce, 0x87, 0xcb, 0xf5, 0x23, 0xa9, 0x2e, 0x80, 0x54, 0xb9, 0x62, 0xb3, 0x5e, 0x6f, 0x0e, 0x18, 0xbd, 0xb0, + 0x7e, 0x61, 0xe3, 0x0a, 0xce, 0x2f, 0x09, 0x73, 0x57, 0xfd, 0x08, 0xb3, 0x0c, 0xaa, 0x80, 0x34, 0x3f, 0x16, 0xbc, + 0x79, 0xee, 0x02, 0x51, 0xbf, 0x1e, 0xa9, 0x0b, 0xca, 0x2c, 0x9d, 0x5b, 0x44, 0x20, 0xe0, 0x35, 0xac, 0x9e, 0x40, + 0xb2, 0x2f, 0x1f, 0xfb, 0x34, 0xa3, 0x40, 0x75, 0x04, 0xa0, 0x6c, 0xd6, 0x0f, 0x61, 0xff, 0x80, 0x70, 0x42, 0xfd, + 0xcd, 0x1b, 0x39, 0x6b, 0x48, 0x1e, 0x48, 0x35, 0xe1, 0x31, 0x9c, 0x1a, 0x0b, 0x7c, 0x69, 0xd1, 0x9b, 0x0a, 0x5e, + 0x13, 0x1c, 0xf7, 0x02, 0xad, 0x7d, 0x0b, 0x38, 0x42, 0x04, 0x97, 0xa1, 0x89, 0xd3, 0xde, 0xae, 0x17, 0x20, 0xa1, + 0xb9, 0x85, 0x73, 0xfd, 0xd6, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, + 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, + 0x32, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, + 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, + 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xcb, 0xc4, 0x33, 0xec, 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, + 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, + 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x32, 0xcc, 0x41, 0xde, 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, + 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, + 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, + 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, + 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, + 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0xd7, 0xf9, 0x68, 0x4b, 0x5f, 0x83, 0x6f, 0x1d, 0x0e, 0xf9, 0x68, + 0x67, 0x7e, 0xfa, 0x64, 0xad, 0x94, 0xc1, 0x46, 0x8a, 0x51, 0x08, 0x89, 0xe2, 0xb6, 0x3d, 0x06, 0xc0, 0xff, 0xfe, + 0xe1, 0x40, 0xbf, 0x77, 0xf2, 0xb7, 0xda, 0x2d, 0xad, 0x7a, 0x7e, 0x68, 0x11, 0x66, 0xbc, 0xaa, 0x0d, 0x3b, 0xdb, + 0x5e, 0x02, 0x4a, 0xef, 0x9b, 0x06, 0x35, 0x45, 0xf4, 0x13, 0x56, 0x13, 0xab, 0x38, 0x2c, 0x48, 0x89, 0x43, 0x0c, + 0xc7, 0x68, 0x87, 0x1e, 0xa7, 0x8b, 0x9a, 0x27, 0xf7, 0x1d, 0x32, 0x6e, 0x7d, 0x1f, 0x90, 0x5c, 0x0a, 0xe7, 0x1f, + 0xbc, 0xd0, 0x60, 0xa2, 0x17, 0x79, 0x55, 0x64, 0x62, 0x24, 0x68, 0x94, 0xdf, 0x90, 0x38, 0x73, 0x86, 0xb5, 0x38, + 0x53, 0x08, 0x61, 0x21, 0xa1, 0x72, 0x17, 0x25, 0xa5, 0x07, 0x67, 0x4f, 0xf6, 0x65, 0xf3, 0x3b, 0x61, 0x42, 0x8c, + 0x16, 0x40, 0x83, 0xb3, 0x6b, 0x97, 0xf7, 0x10, 0x96, 0xb9, 0xf7, 0xfb, 0x9b, 0xbb, 0xbc, 0x80, 0xb8, 0xcc, 0x33, + 0xa9, 0x58, 0x2d, 0xcf, 0x80, 0x26, 0x4f, 0xc4, 0x67, 0x61, 0x25, 0xa7, 0x41, 0xd5, 0x51, 0xac, 0xde, 0xc6, 0x73, + 0x0f, 0x78, 0xbd, 0xdf, 0x27, 0x40, 0xe0, 0xee, 0xb3, 0xd7, 0xca, 0x2d, 0x95, 0xf4, 0xc8, 0x73, 0x0c, 0x91, 0x4c, + 0x80, 0xd7, 0x19, 0x82, 0x23, 0x85, 0xd5, 0x73, 0x13, 0xe4, 0x1f, 0x5f, 0x9f, 0x50, 0x7c, 0xd1, 0x3c, 0x8a, 0x1a, + 0x16, 0xb2, 0x04, 0x8e, 0x87, 0x64, 0x96, 0xcd, 0x91, 0x9a, 0x3c, 0x6d, 0x4f, 0x91, 0x8e, 0x4e, 0x2c, 0xf1, 0xdb, + 0x9a, 0x54, 0x2f, 0x52, 0x61, 0x97, 0xb4, 0xb3, 0x95, 0xb9, 0x17, 0xc2, 0x50, 0x25, 0xdc, 0x7b, 0x55, 0xcf, 0x42, + 0xb9, 0x29, 0x5a, 0x15, 0xb3, 0x87, 0x29, 0x31, 0xc3, 0x14, 0xeb, 0x2f, 0x6c, 0xf8, 0x4d, 0xe2, 0xc5, 0x60, 0xb8, + 0x5e, 0xf2, 0x72, 0xb6, 0x31, 0x0b, 0xe1, 0x70, 0xd8, 0x4c, 0x8a, 0xd9, 0x12, 0x62, 0x5b, 0x97, 0xf3, 0xc3, 0xa1, + 0xab, 0x65, 0x6b, 0xe1, 0xc1, 0x43, 0xd5, 0xc2, 0x4d, 0xc3, 0x72, 0xf8, 0x99, 0xcc, 0x62, 0x6c, 0x5f, 0xe3, 0x33, + 0xfb, 0xf3, 0x45, 0xf7, 0x2c, 0x41, 0xc6, 0x8d, 0x35, 0x70, 0x8d, 0xcd, 0xda, 0x1d, 0xae, 0x46, 0x40, 0xf2, 0xb8, + 0x1b, 0xfd, 0x5d, 0xd9, 0x49, 0x4e, 0x82, 0x84, 0xd1, 0x0a, 0xe1, 0x77, 0xdf, 0xf8, 0x13, 0x2d, 0xf6, 0xa0, 0xdd, + 0xc6, 0x96, 0x10, 0xd5, 0xb4, 0xe7, 0x72, 0xa5, 0x58, 0x9a, 0xb7, 0xd2, 0x86, 0xcc, 0x87, 0xf5, 0xb9, 0x6f, 0xe4, + 0x40, 0xc1, 0x18, 0xf1, 0xd4, 0x3a, 0x88, 0x66, 0x73, 0xe0, 0xbe, 0x40, 0xf3, 0x08, 0x4f, 0x2d, 0x48, 0x50, 0x66, + 0x6d, 0xd8, 0x4f, 0x92, 0x93, 0xe5, 0x71, 0xf8, 0x16, 0xfe, 0xe5, 0x33, 0x6c, 0x12, 0x53, 0x14, 0x8f, 0xbf, 0x55, + 0x8a, 0xff, 0x8e, 0x2d, 0x88, 0x60, 0xed, 0x46, 0xd4, 0x86, 0xbf, 0xe1, 0xdf, 0xc2, 0x3e, 0xc2, 0x7e, 0x43, 0x13, + 0x84, 0x01, 0xac, 0x3f, 0x13, 0x88, 0x0b, 0x0b, 0x41, 0x82, 0xbf, 0x55, 0x92, 0x7f, 0x4e, 0xf8, 0x6c, 0x51, 0x02, + 0x59, 0x1d, 0x46, 0xf1, 0x09, 0xc5, 0x44, 0x21, 0x0c, 0xb7, 0x84, 0xde, 0xd1, 0x7f, 0x23, 0x4a, 0xb2, 0x49, 0x6e, + 0xc5, 0x7a, 0x20, 0x93, 0x24, 0x98, 0x60, 0xe5, 0x85, 0xf2, 0x85, 0x7b, 0xa1, 0xd4, 0x5a, 0x0b, 0x5a, 0xbf, 0xfc, + 0x49, 0xe2, 0x19, 0xd0, 0x3d, 0x90, 0x31, 0xe8, 0x36, 0xa2, 0x9a, 0xe4, 0x98, 0x3e, 0x4a, 0xe7, 0x19, 0xa8, 0x80, + 0xce, 0xd6, 0x59, 0x58, 0x2f, 0x8b, 0x72, 0xd5, 0x0a, 0x0f, 0x95, 0xa5, 0x8f, 0xd4, 0x63, 0xcc, 0x0b, 0xf3, 0xe4, + 0x44, 0x3e, 0x78, 0x04, 0x68, 0x78, 0x94, 0xa7, 0x55, 0x47, 0x69, 0xfd, 0xc0, 0x32, 0x60, 0x04, 0x4e, 0x94, 0x01, + 0x8f, 0xb0, 0x0c, 0xcc, 0xd3, 0x2e, 0x43, 0x0d, 0x62, 0x8d, 0xaa, 0x2b, 0xb5, 0xc1, 0x9c, 0x28, 0x4a, 0x3e, 0xc5, + 0xd2, 0x0a, 0x63, 0x68, 0xea, 0xca, 0x23, 0xeb, 0x25, 0x27, 0xec, 0xc9, 0x6e, 0x20, 0xdd, 0xc2, 0x46, 0x81, 0x0b, + 0xba, 0x96, 0x25, 0xca, 0x45, 0xb7, 0x8c, 0x28, 0x13, 0x21, 0xf5, 0xb3, 0x87, 0x33, 0xad, 0xf6, 0x1b, 0x3b, 0x69, + 0xdf, 0x1e, 0x29, 0x7a, 0xc1, 0x40, 0x7c, 0xda, 0x23, 0xa5, 0x9e, 0x35, 0x72, 0x19, 0xd8, 0xd2, 0xa5, 0xaa, 0xe7, + 0xbf, 0x41, 0xf9, 0x0e, 0x66, 0xc6, 0xd9, 0xec, 0x77, 0xbd, 0xb9, 0x3d, 0xd9, 0xd7, 0xcd, 0xef, 0xac, 0xd7, 0x83, + 0xad, 0x41, 0x26, 0xbe, 0x50, 0xd4, 0x53, 0x56, 0x21, 0x56, 0x64, 0xf6, 0xbf, 0x85, 0xf7, 0x3b, 0xbc, 0x35, 0x42, + 0xb3, 0x32, 0x1e, 0xe6, 0xa3, 0x27, 0x7b, 0xd1, 0xfc, 0xde, 0x59, 0xb6, 0x95, 0xab, 0x92, 0xd9, 0x7e, 0x3f, 0x4a, + 0x9a, 0xb3, 0xc7, 0x6b, 0x24, 0x75, 0x80, 0x8f, 0xd7, 0x67, 0xf8, 0x48, 0x25, 0x94, 0x5a, 0x50, 0xd5, 0xa0, 0xf5, + 0xb1, 0xdf, 0x5b, 0xcf, 0xe9, 0xe3, 0xc7, 0x72, 0xba, 0x25, 0x45, 0x18, 0x3f, 0x30, 0x98, 0xb2, 0x13, 0xa7, 0x2e, + 0x79, 0x33, 0xa4, 0x77, 0xdd, 0x2a, 0xa9, 0xcb, 0x1e, 0x25, 0x82, 0x50, 0x07, 0xeb, 0x17, 0xfb, 0x21, 0xcc, 0x6c, + 0xd1, 0x1f, 0x36, 0xab, 0x39, 0xa1, 0x20, 0x02, 0x44, 0xab, 0xbc, 0x0f, 0x1c, 0x93, 0x84, 0x59, 0x73, 0x43, 0xba, + 0xf5, 0xe6, 0x4a, 0x7b, 0x25, 0x05, 0xf4, 0x73, 0x90, 0xb9, 0x7d, 0x74, 0xcb, 0x55, 0xcb, 0x3c, 0x97, 0xb6, 0x1c, + 0xb0, 0x68, 0x21, 0x3a, 0xb3, 0x73, 0xe9, 0x70, 0xf0, 0x1f, 0xd4, 0x95, 0xa8, 0x22, 0x82, 0x8e, 0xa2, 0x05, 0xa3, + 0xd5, 0xaa, 0x5d, 0x4e, 0x36, 0x15, 0xb2, 0x25, 0x11, 0x4e, 0x94, 0xec, 0x95, 0x50, 0x1f, 0xe5, 0x6a, 0xcf, 0x34, + 0xc4, 0x9f, 0x09, 0xd8, 0xb4, 0xc1, 0xdf, 0x02, 0xf7, 0x32, 0x38, 0x33, 0xed, 0xd3, 0x30, 0x02, 0x22, 0x73, 0x08, + 0xf6, 0xf3, 0xbb, 0x1e, 0x54, 0xf0, 0xa0, 0x23, 0xfd, 0x55, 0x3d, 0x2b, 0xf0, 0xcc, 0x3d, 0xf1, 0xfc, 0xf5, 0x89, + 0xf4, 0x22, 0x87, 0x07, 0x9a, 0xfb, 0x30, 0xe3, 0x2f, 0xca, 0x32, 0xdc, 0x8d, 0x96, 0x65, 0xb1, 0xf2, 0x22, 0xbd, + 0x8f, 0x67, 0x52, 0x0c, 0x24, 0x3a, 0xcc, 0x8c, 0xae, 0x62, 0x1d, 0xe7, 0x30, 0xee, 0xed, 0x49, 0x58, 0xa1, 0xfd, + 0xb3, 0xc4, 0x5e, 0x17, 0x00, 0xe0, 0x90, 0x35, 0x68, 0x85, 0x77, 0xba, 0xbd, 0xdd, 0xe3, 0x92, 0x12, 0xc5, 0x8d, + 0x9a, 0x9f, 0xd5, 0xd0, 0x32, 0x41, 0x2d, 0xb3, 0xee, 0x64, 0x32, 0x45, 0x12, 0xf8, 0x36, 0xec, 0x35, 0x2b, 0xf2, + 0x79, 0x23, 0xb7, 0x87, 0x77, 0xe1, 0x4a, 0xc4, 0xda, 0x82, 0x4e, 0x3a, 0x32, 0x0e, 0xf7, 0x42, 0x73, 0x23, 0xdd, + 0x3f, 0xa9, 0x92, 0xb0, 0x14, 0x31, 0xdc, 0x02, 0xd9, 0x5e, 0x6d, 0x2b, 0x41, 0x09, 0x24, 0xb0, 0x1f, 0x4a, 0xb1, + 0x4c, 0xb7, 0x02, 0xc0, 0x1c, 0xf8, 0x9f, 0x12, 0x86, 0xd0, 0xdd, 0x79, 0x88, 0x57, 0x8d, 0xbc, 0x6f, 0x10, 0x82, + 0xfd, 0x15, 0xc8, 0x69, 0xc0, 0x20, 0x52, 0x8c, 0x64, 0xc1, 0x40, 0x02, 0x90, 0xf3, 0x35, 0x98, 0xe4, 0xa6, 0xb9, + 0xe7, 0x07, 0xb9, 0xee, 0x60, 0xda, 0x07, 0xdd, 0x8b, 0x6b, 0xcd, 0x72, 0xf0, 0x8a, 0x89, 0xf8, 0xdf, 0x6b, 0xaf, + 0x64, 0x39, 0xcb, 0xfc, 0xc6, 0x5c, 0x74, 0x32, 0xb8, 0x6a, 0x08, 0xbf, 0x98, 0x65, 0x73, 0x1e, 0xcd, 0x32, 0x1d, + 0xea, 0x5f, 0x34, 0x47, 0xa5, 0x00, 0x86, 0x3a, 0x5e, 0x80, 0x35, 0xde, 0x95, 0x6e, 0x5a, 0xf1, 0x48, 0x63, 0x8c, + 0x82, 0x0a, 0x1d, 0x84, 0xfe, 0x5e, 0x03, 0xbc, 0x06, 0x93, 0xdc, 0x08, 0x95, 0x0f, 0x2e, 0xe8, 0x86, 0x6e, 0xb9, + 0x72, 0x09, 0x6a, 0x52, 0xb5, 0xfc, 0x72, 0x84, 0x7a, 0x57, 0x4b, 0x2e, 0xd5, 0xe6, 0x53, 0xa3, 0xac, 0x11, 0x64, + 0x72, 0x94, 0x7e, 0x9f, 0x72, 0xe1, 0x56, 0xc6, 0x64, 0x7d, 0x38, 0x78, 0x05, 0x37, 0x35, 0x7e, 0x95, 0x13, 0x8b, + 0xa8, 0x3d, 0x24, 0xc2, 0xd6, 0x6e, 0x85, 0xee, 0x3d, 0x6e, 0x94, 0xe6, 0x51, 0xb6, 0x89, 0x45, 0xe5, 0xf5, 0x12, + 0xb0, 0x16, 0xf7, 0x80, 0x0c, 0x95, 0x96, 0x7e, 0xc5, 0x0a, 0x80, 0x0c, 0x90, 0xc2, 0xc6, 0x0f, 0x48, 0x7b, 0xf5, + 0xc1, 0x4b, 0xfd, 0x7e, 0xdf, 0x98, 0xf2, 0xdf, 0x3f, 0xe4, 0xc0, 0x4c, 0x28, 0xca, 0x7a, 0x07, 0x13, 0x08, 0xae, + 0x9d, 0xa4, 0x3d, 0xab, 0xf9, 0xf5, 0xba, 0xf6, 0x80, 0xd4, 0xca, 0xb7, 0x98, 0xab, 0x5e, 0xd9, 0x17, 0x9b, 0x7d, + 0x5a, 0xdd, 0x18, 0x8d, 0x83, 0x60, 0x69, 0xf5, 0x46, 0xab, 0x1c, 0xf2, 0x86, 0x57, 0x20, 0x52, 0x59, 0x57, 0xd7, + 0xca, 0xb9, 0xba, 0x16, 0x1c, 0x09, 0x64, 0x4b, 0x9e, 0xc3, 0x7f, 0x21, 0xf7, 0xca, 0xc3, 0xa1, 0xf0, 0xfb, 0xfd, + 0x74, 0x46, 0x5a, 0x59, 0xa0, 0x4c, 0x5b, 0xd7, 0x5e, 0xe8, 0x1f, 0x0e, 0x3f, 0x80, 0xd7, 0x88, 0x7f, 0x38, 0x94, + 0xfd, 0xfe, 0x47, 0x73, 0x93, 0x39, 0x1f, 0x2b, 0xa5, 0xec, 0x25, 0x2a, 0xdd, 0xdf, 0x24, 0xbc, 0xf7, 0xbf, 0x47, + 0xff, 0x7b, 0x74, 0xd9, 0x53, 0x01, 0x60, 0x09, 0x9f, 0xe1, 0x0d, 0x9d, 0xa9, 0xcb, 0x39, 0x93, 0xee, 0xee, 0xca, + 0x0f, 0xbd, 0xa7, 0xf1, 0xe1, 0x7b, 0x73, 0xd3, 0xc6, 0x5f, 0xab, 0x23, 0x4d, 0x42, 0xc7, 0x45, 0xff, 0x70, 0xf8, + 0x94, 0x68, 0x7d, 0x5a, 0xaa, 0xf4, 0x69, 0x0a, 0x3c, 0xc9, 0xb0, 0xe1, 0xba, 0x85, 0xe9, 0x68, 0x7e, 0xdc, 0x7c, + 0x95, 0xbc, 0x38, 0x4b, 0xe1, 0xda, 0x9b, 0xcf, 0xd2, 0xf9, 0x14, 0xac, 0x2b, 0xc3, 0x7c, 0x56, 0xcf, 0x03, 0x48, + 0x1d, 0x42, 0x9a, 0x35, 0x0d, 0xff, 0x56, 0xb9, 0x82, 0xb7, 0xf6, 0x78, 0x37, 0x18, 0x51, 0xea, 0x48, 0x9f, 0xb4, + 0x21, 0x74, 0x49, 0x25, 0xff, 0x51, 0xe4, 0x31, 0xc6, 0x6c, 0xbc, 0x22, 0xb2, 0xcf, 0x22, 0x7f, 0x59, 0x00, 0x60, + 0x11, 0x20, 0x20, 0xa7, 0x73, 0x47, 0x12, 0xff, 0x39, 0xf9, 0xf6, 0x8f, 0xe9, 0xd2, 0x3e, 0x94, 0xc5, 0x5d, 0x29, + 0xaa, 0xea, 0xa8, 0xb4, 0x9d, 0x2d, 0xd7, 0x03, 0x7d, 0x68, 0xbf, 0x2f, 0xe9, 0x43, 0x53, 0x0c, 0x45, 0x81, 0x5b, + 0x63, 0x6f, 0x9a, 0x72, 0x45, 0x53, 0x3d, 0x32, 0xd6, 0xcf, 0xef, 0x77, 0x6f, 0x62, 0x2f, 0xf5, 0x83, 0x14, 0x04, + 0x61, 0x8d, 0x9f, 0x94, 0x22, 0x09, 0x9c, 0xcf, 0x30, 0x95, 0xf8, 0x74, 0x29, 0x55, 0xfe, 0x30, 0xd2, 0x7c, 0x98, + 0x82, 0x5e, 0xf6, 0x1f, 0x15, 0xcc, 0x7f, 0xdd, 0x1e, 0xac, 0x4f, 0xeb, 0x32, 0x8d, 0x2a, 0xa2, 0xca, 0x0b, 0x53, + 0x6d, 0x02, 0x11, 0xfc, 0x5a, 0x58, 0x24, 0xbf, 0x3e, 0x39, 0x12, 0x34, 0x66, 0xb2, 0x7c, 0x3c, 0x72, 0xbf, 0xb0, + 0xaf, 0x5c, 0xc7, 0xf3, 0x3f, 0x37, 0xf3, 0x7f, 0x80, 0xce, 0x90, 0xc5, 0x35, 0xb7, 0x0c, 0x16, 0x38, 0xfb, 0xa5, + 0xab, 0x07, 0xfc, 0xcd, 0x3c, 0x71, 0x0d, 0x1c, 0xcc, 0xd7, 0xe8, 0xaa, 0x98, 0xce, 0x8a, 0x01, 0x10, 0xd8, 0xfa, + 0x8d, 0x35, 0x27, 0x5e, 0x5b, 0x3c, 0x57, 0x72, 0x41, 0xe8, 0xeb, 0x2a, 0xcc, 0xc6, 0x55, 0xb1, 0xa9, 0x44, 0xb1, + 0xa9, 0x7b, 0xa4, 0x96, 0xcd, 0xa7, 0xb5, 0xad, 0x90, 0xfd, 0x49, 0xb4, 0x68, 0xbb, 0x0c, 0xd5, 0x64, 0x94, 0xa5, + 0xeb, 0x29, 0x90, 0xea, 0x05, 0x70, 0x16, 0x99, 0x57, 0xbe, 0x38, 0x7b, 0xc0, 0x16, 0x8d, 0xa7, 0xc0, 0x88, 0x4a, + 0x7f, 0xe4, 0x8d, 0xd1, 0xe9, 0x89, 0x7e, 0x3f, 0x9f, 0x52, 0xc8, 0xd7, 0x4f, 0x80, 0xc9, 0x55, 0xcb, 0x05, 0xe8, + 0xcb, 0x50, 0x07, 0x95, 0x28, 0xb5, 0x62, 0x18, 0xb1, 0xf0, 0x93, 0x40, 0xf6, 0x66, 0x0a, 0x6a, 0x56, 0x51, 0x12, + 0x2a, 0x51, 0x29, 0xd9, 0x9a, 0xa0, 0x96, 0xde, 0x17, 0x45, 0xbd, 0xaf, 0xc0, 0x51, 0x32, 0xd2, 0x66, 0x39, 0x65, + 0xc6, 0x45, 0x99, 0x8b, 0x7e, 0xb0, 0x7f, 0x57, 0x9e, 0xdf, 0xc8, 0x7c, 0x96, 0xfb, 0x8e, 0xce, 0x69, 0x3b, 0x2e, + 0x50, 0xe6, 0x96, 0xd3, 0x56, 0x4b, 0x1e, 0x93, 0xf7, 0x2c, 0xd8, 0xf6, 0x5f, 0x24, 0xc8, 0xab, 0x08, 0xf3, 0x09, + 0x55, 0x36, 0xff, 0x80, 0x30, 0x5b, 0x1c, 0xd8, 0x63, 0x17, 0x26, 0x22, 0xbd, 0x05, 0x4b, 0x62, 0x98, 0x95, 0x22, + 0x8c, 0x77, 0xe0, 0xfd, 0xb3, 0xa9, 0xc4, 0xe8, 0x0c, 0x9d, 0xdc, 0xcf, 0x1e, 0xd2, 0x3a, 0x39, 0x7b, 0xf3, 0xea, + 0xec, 0xbb, 0xde, 0xa0, 0x18, 0xa5, 0xf1, 0xa0, 0xf7, 0xdd, 0xd9, 0x6a, 0x03, 0x10, 0x99, 0xe2, 0x2c, 0x26, 0x53, + 0x9a, 0x88, 0xcf, 0xc8, 0x30, 0x78, 0x56, 0x27, 0xe2, 0x8c, 0x26, 0xa6, 0xfb, 0x1a, 0xa5, 0xc9, 0xb7, 0xa3, 0x30, + 0x87, 0x97, 0x4b, 0xb1, 0xa9, 0x44, 0x0c, 0x76, 0x4a, 0x35, 0xcf, 0xf2, 0xf6, 0x59, 0x9c, 0x8f, 0x3a, 0x64, 0x95, + 0x0e, 0xd0, 0xed, 0x89, 0xb4, 0xab, 0xd2, 0x15, 0x10, 0x7a, 0x00, 0x9c, 0x74, 0xe5, 0xcf, 0xc3, 0x41, 0x24, 0x10, + 0x6a, 0xc1, 0x9c, 0x4c, 0x23, 0xba, 0x21, 0xbd, 0xc4, 0x3e, 0x03, 0xb3, 0x90, 0xd2, 0x3c, 0xb8, 0xb9, 0x5a, 0xb4, + 0xdc, 0x15, 0x2b, 0x47, 0x61, 0xb5, 0x16, 0x51, 0x8d, 0x54, 0xc7, 0xe0, 0xbc, 0x03, 0x11, 0x00, 0x8a, 0x11, 0x3c, + 0xe3, 0x51, 0xbf, 0x1f, 0xa9, 0xa0, 0x9c, 0x84, 0x7e, 0x51, 0xe8, 0x97, 0xc6, 0xa0, 0x8c, 0xf9, 0xbb, 0x50, 0x13, + 0x03, 0xd4, 0x5b, 0x1e, 0x2a, 0x8e, 0x00, 0x5c, 0xce, 0x11, 0x33, 0xce, 0x7b, 0xdc, 0x45, 0xe3, 0x54, 0xbc, 0x13, + 0xea, 0x3a, 0x58, 0x2a, 0xd4, 0x79, 0x53, 0x1f, 0xe9, 0x39, 0x69, 0x12, 0x34, 0x88, 0x1b, 0x78, 0xbc, 0x1a, 0x02, + 0xaa, 0x95, 0x90, 0x7a, 0x0b, 0x9d, 0x52, 0xd5, 0x21, 0xb0, 0x06, 0xb8, 0x44, 0x61, 0x5b, 0x61, 0x72, 0x44, 0x9b, + 0xb2, 0x14, 0xf9, 0x11, 0x1b, 0xb4, 0x4b, 0x46, 0xa6, 0x0e, 0xae, 0xff, 0xc3, 0xdb, 0xb7, 0x70, 0xb7, 0x6d, 0x63, + 0xeb, 0xfe, 0x15, 0x8b, 0x37, 0x55, 0x89, 0x08, 0x92, 0x25, 0x37, 0xe9, 0xb4, 0x94, 0x21, 0x1d, 0x37, 0x8f, 0x36, + 0x9d, 0xe6, 0xd1, 0x38, 0xed, 0x74, 0x46, 0x57, 0xc7, 0xa5, 0x49, 0xd8, 0x62, 0x43, 0x03, 0x2a, 0x49, 0xf9, 0x51, + 0x89, 0xff, 0xfd, 0xae, 0xbd, 0xf1, 0x24, 0x45, 0x3b, 0x99, 0xb9, 0xe7, 0xde, 0x95, 0xb5, 0x62, 0x11, 0x04, 0xf1, + 0xc6, 0xc6, 0xc6, 0x7e, 0x7c, 0xbb, 0x19, 0xcb, 0x49, 0x85, 0xfe, 0x75, 0x75, 0x01, 0x9c, 0x17, 0xc6, 0xb7, 0x6e, + 0x66, 0xcb, 0x75, 0xb4, 0xeb, 0xd2, 0xc5, 0x2c, 0x29, 0x78, 0xb9, 0x96, 0xa2, 0xcc, 0xae, 0xf9, 0x4f, 0xf6, 0x65, + 0x33, 0x80, 0x14, 0xda, 0x91, 0xbe, 0x6e, 0x77, 0x47, 0x8b, 0x71, 0x6c, 0x39, 0xbe, 0xa5, 0xd2, 0x9d, 0x1e, 0x55, + 0x2f, 0x6e, 0xb6, 0xce, 0xb5, 0xca, 0xd2, 0x94, 0x8b, 0x57, 0x22, 0xcd, 0x12, 0x2f, 0x39, 0xd6, 0x01, 0xaa, 0x5d, + 0xe4, 0x2b, 0x17, 0x1b, 0xf9, 0x79, 0x56, 0x62, 0xc0, 0xe0, 0x46, 0xa3, 0x5a, 0xa1, 0xa6, 0x4c, 0xe0, 0x0b, 0xf9, + 0x1e, 0x23, 0x6e, 0xb3, 0x32, 0x01, 0x86, 0x1f, 0x13, 0xf5, 0x25, 0x3d, 0x85, 0x28, 0x0f, 0x2a, 0x1e, 0xf7, 0x73, + 0x8e, 0x88, 0xd7, 0x56, 0x65, 0x0e, 0x4c, 0xb6, 0x56, 0x41, 0x22, 0xd8, 0x5d, 0xb6, 0xd0, 0x8b, 0x68, 0xa9, 0xee, + 0x42, 0xbd, 0x78, 0xb7, 0xeb, 0x25, 0x8a, 0x0e, 0x38, 0xf9, 0x69, 0xf0, 0x32, 0xce, 0x72, 0x9e, 0x1e, 0x54, 0xf2, + 0x40, 0x6d, 0xa8, 0x03, 0xe5, 0xcc, 0x01, 0x3b, 0xef, 0xcb, 0xea, 0x40, 0xaf, 0xe9, 0x03, 0xdd, 0xce, 0x03, 0xb8, + 0x60, 0xe0, 0xce, 0xbd, 0xcc, 0xae, 0xb9, 0x38, 0x00, 0x65, 0xa0, 0x35, 0x1e, 0xa8, 0x45, 0x35, 0x52, 0x13, 0xa3, + 0x03, 0x57, 0x27, 0xfa, 0x60, 0x0e, 0xe8, 0xf7, 0x10, 0x2b, 0xbc, 0xf5, 0x76, 0xad, 0x0f, 0xda, 0x80, 0xfe, 0xb4, + 0x32, 0x7d, 0xd0, 0xd1, 0xe2, 0x55, 0x48, 0xe0, 0xc6, 0x90, 0x6a, 0xa4, 0x56, 0x23, 0xab, 0x40, 0xf1, 0x86, 0xb7, + 0x78, 0xf7, 0xae, 0x25, 0x5b, 0xef, 0x25, 0x02, 0x7b, 0x65, 0xa2, 0x8a, 0x33, 0x71, 0xe2, 0xa5, 0xf2, 0x5a, 0x3b, + 0xc9, 0x08, 0xe3, 0x5b, 0x56, 0x52, 0x7f, 0x87, 0x98, 0x5b, 0xa4, 0x39, 0x0c, 0x5e, 0x84, 0x15, 0x99, 0xf3, 0x7e, + 0x5f, 0xce, 0x65, 0x54, 0xce, 0xc5, 0x61, 0x19, 0x29, 0x84, 0xb6, 0xfb, 0x44, 0x40, 0x0f, 0x4a, 0x80, 0x7c, 0x01, + 0x50, 0xf5, 0x90, 0xf0, 0xe7, 0x21, 0xa9, 0x4f, 0xa7, 0xd0, 0xa7, 0xd0, 0xd6, 0x2b, 0x5e, 0x41, 0x55, 0xdd, 0x18, + 0xd9, 0x46, 0x05, 0x2d, 0x1e, 0xcb, 0xb3, 0xda, 0x30, 0x36, 0xa7, 0xd6, 0xbb, 0xde, 0x6c, 0x30, 0x65, 0x73, 0xa1, + 0x56, 0x61, 0x48, 0xa2, 0x9b, 0xd2, 0x0b, 0x1f, 0x62, 0xb1, 0xb2, 0x5a, 0x9b, 0xdf, 0xc4, 0xfe, 0xc8, 0x44, 0x8a, + 0xfb, 0xd9, 0x12, 0xe7, 0x2e, 0x1e, 0xcf, 0xab, 0xbe, 0xd6, 0xd2, 0x22, 0xd3, 0xe6, 0x3b, 0x7d, 0x19, 0xd2, 0x54, + 0xd4, 0x90, 0x46, 0x9d, 0x19, 0x74, 0xdf, 0x2e, 0xaf, 0xa8, 0x46, 0x98, 0x00, 0xaf, 0x74, 0x06, 0xdd, 0x68, 0x3c, + 0x10, 0x45, 0x35, 0x2a, 0x36, 0x42, 0x20, 0xda, 0x30, 0xe4, 0x98, 0x5b, 0x42, 0x92, 0xfd, 0xc5, 0xbf, 0x53, 0xc1, + 0x15, 0x8a, 0xf8, 0xc6, 0xc0, 0x79, 0x57, 0xd6, 0xb3, 0xbb, 0x8e, 0xfc, 0x9c, 0x58, 0x58, 0xed, 0x3f, 0x34, 0x8f, + 0x5a, 0xe3, 0x2c, 0xa0, 0xad, 0x69, 0x75, 0xc3, 0xe1, 0x1e, 0xd5, 0xb1, 0x28, 0x0d, 0x20, 0xb1, 0x47, 0x96, 0x8b, + 0xd6, 0x31, 0x83, 0x06, 0xf4, 0xb7, 0xd9, 0xd5, 0xe6, 0x0a, 0x51, 0xdb, 0x4a, 0x64, 0x9d, 0xa4, 0xf2, 0x2f, 0x69, + 0x8f, 0xba, 0xb6, 0xa7, 0xf2, 0xbf, 0x6d, 0x53, 0xe5, 0xd0, 0x02, 0xc9, 0x63, 0x37, 0xe7, 0x81, 0xea, 0x48, 0x10, + 0x05, 0x6a, 0xeb, 0x05, 0x53, 0xef, 0x94, 0x29, 0x3a, 0x90, 0x9f, 0x0b, 0x73, 0x86, 0x7d, 0xc6, 0x11, 0x63, 0x96, + 0x4a, 0x0c, 0xa6, 0x3e, 0xc6, 0xa8, 0xa6, 0xb5, 0x02, 0x74, 0xfd, 0x74, 0x0b, 0x7f, 0xa2, 0xa2, 0x46, 0x43, 0xad, + 0x91, 0x14, 0x8a, 0x26, 0x2a, 0xe8, 0x58, 0x5a, 0xe8, 0x60, 0x0a, 0x9d, 0x44, 0xc2, 0x12, 0xd0, 0x30, 0x21, 0x3a, + 0xa9, 0xc0, 0x5b, 0x03, 0x38, 0xf3, 0x71, 0x51, 0x6e, 0x0a, 0x6d, 0x30, 0xf7, 0x43, 0x7c, 0xcd, 0x5f, 0x3d, 0x77, + 0x46, 0xf5, 0x2d, 0x6b, 0x7d, 0x4f, 0x0b, 0xf2, 0x43, 0xc8, 0x29, 0x3a, 0x30, 0xb1, 0xd9, 0x16, 0x8d, 0x31, 0xca, + 0x5a, 0x87, 0xba, 0x78, 0xab, 0xe3, 0xaf, 0x68, 0x13, 0xbc, 0x07, 0x3c, 0x45, 0xb4, 0xe1, 0xa1, 0x30, 0x56, 0xd5, + 0xf8, 0x54, 0xb2, 0x96, 0x1e, 0xac, 0xe0, 0xe9, 0x26, 0xe1, 0x21, 0xe8, 0x91, 0x08, 0x9b, 0x85, 0xc5, 0x22, 0x5e, + 0xc2, 0x71, 0x52, 0x10, 0x50, 0x3b, 0xe8, 0x2b, 0xf8, 0x62, 0x89, 0xee, 0xaf, 0x12, 0x3d, 0xc0, 0xd0, 0x82, 0xb8, + 0x19, 0xfa, 0x74, 0x74, 0x15, 0xaf, 0x1b, 0x2a, 0x12, 0xbe, 0x28, 0xc0, 0x76, 0x48, 0xa9, 0xa7, 0x40, 0x0b, 0x95, + 0x28, 0xfd, 0x30, 0xf0, 0x1d, 0x1a, 0xf8, 0x5a, 0xeb, 0x00, 0x0d, 0xfd, 0x8c, 0x69, 0x6a, 0x9d, 0xa1, 0xf2, 0xb9, + 0x77, 0xcf, 0x8c, 0x56, 0x73, 0x0b, 0xc6, 0xa0, 0x6f, 0xa3, 0x29, 0x8a, 0x73, 0xf2, 0x79, 0x50, 0xc4, 0x69, 0x16, + 0xe7, 0xe0, 0xb7, 0x19, 0x17, 0x98, 0x31, 0x89, 0x2b, 0x7e, 0x29, 0x0b, 0xd0, 0x76, 0xe7, 0x2a, 0xb5, 0xae, 0x41, + 0x40, 0xf6, 0x03, 0x58, 0xbd, 0x34, 0x74, 0x54, 0xce, 0xbb, 0x4b, 0x9b, 0x42, 0xc4, 0x22, 0x04, 0x9b, 0x66, 0xba, + 0x62, 0x27, 0xa1, 0xd2, 0xe6, 0x40, 0x7c, 0x23, 0x34, 0xee, 0x9f, 0x86, 0xb1, 0xd5, 0x14, 0x5b, 0xbb, 0xb7, 0xdd, + 0xee, 0xb7, 0xd2, 0x4b, 0xa7, 0x39, 0xe9, 0x31, 0xf6, 0x5b, 0x19, 0x16, 0x23, 0xdb, 0x11, 0x02, 0x4b, 0xce, 0xfb, + 0xd4, 0x7f, 0x45, 0xcb, 0x45, 0x02, 0xa6, 0x23, 0x3a, 0x42, 0x2e, 0x50, 0x76, 0x8c, 0xe2, 0x0e, 0x0c, 0xae, 0xe8, + 0xf7, 0xc1, 0x2a, 0xc3, 0x5c, 0x48, 0x56, 0x24, 0x65, 0xf0, 0x3c, 0xf5, 0x30, 0xe0, 0x37, 0x4c, 0x99, 0xbb, 0x28, + 0xeb, 0xd3, 0x15, 0x99, 0xa6, 0xc8, 0x40, 0x6c, 0xc2, 0x6d, 0x96, 0x46, 0x89, 0x12, 0x91, 0xad, 0xd0, 0x3f, 0xd2, + 0x50, 0x2c, 0x1d, 0xae, 0x17, 0xa9, 0x12, 0xa1, 0x62, 0x91, 0xe2, 0x49, 0x9d, 0xd6, 0xe9, 0x08, 0xe3, 0x4d, 0x82, + 0x52, 0xae, 0x86, 0x81, 0x2a, 0xa9, 0x5e, 0x0a, 0xdb, 0x62, 0xb7, 0xd3, 0x17, 0x2b, 0xb1, 0x88, 0x97, 0xf8, 0x52, + 0xe0, 0x28, 0xfe, 0x9d, 0x7b, 0xb1, 0xa6, 0xd4, 0xf6, 0xa0, 0x76, 0x44, 0x09, 0xfd, 0x3b, 0x87, 0x8b, 0xc4, 0x77, + 0x52, 0xc7, 0xfd, 0x43, 0x8b, 0x90, 0x33, 0x75, 0x90, 0x1a, 0x6e, 0x68, 0x4f, 0xf8, 0x6f, 0xb8, 0x3e, 0xe3, 0x8c, + 0xde, 0x54, 0x33, 0x6a, 0xfc, 0x5e, 0x0f, 0xcf, 0x18, 0xf5, 0xd9, 0xc0, 0x61, 0x85, 0x28, 0xb4, 0x61, 0xb3, 0x52, + 0x89, 0x16, 0x86, 0x52, 0xfd, 0x25, 0x54, 0xcc, 0xb8, 0x33, 0xa3, 0x2c, 0x19, 0x9f, 0x96, 0xc7, 0x62, 0x3a, 0x18, + 0x94, 0xa4, 0x32, 0x16, 0x7a, 0x70, 0x3d, 0xf0, 0xfc, 0x7b, 0xe0, 0x16, 0xe2, 0xc1, 0x21, 0x8b, 0x21, 0x37, 0xe0, + 0xf8, 0x2d, 0x4e, 0xae, 0x1a, 0x95, 0x2a, 0x78, 0x35, 0x51, 0x2d, 0xf8, 0x7b, 0x19, 0x06, 0xe8, 0x93, 0x14, 0x80, + 0xc9, 0x60, 0xca, 0x6f, 0x41, 0xa2, 0x74, 0xa6, 0x6e, 0x48, 0xbf, 0x88, 0x82, 0x5f, 0xf0, 0x82, 0x8b, 0xc4, 0x15, + 0x60, 0x79, 0x07, 0xdb, 0xeb, 0xa8, 0xa2, 0x0a, 0x88, 0xd7, 0xf4, 0x38, 0xe2, 0xc6, 0xfb, 0xcf, 0xf4, 0xd8, 0x02, + 0xb5, 0x5a, 0xc7, 0x06, 0x9f, 0x39, 0x06, 0x17, 0x74, 0x2d, 0xb1, 0x35, 0x54, 0xc3, 0x8a, 0xc0, 0xc0, 0x05, 0x1c, + 0x84, 0x25, 0x8a, 0x63, 0x2b, 0x79, 0x45, 0x1a, 0x52, 0xda, 0x07, 0x86, 0xa3, 0x4d, 0x72, 0x7c, 0x9b, 0x65, 0x37, + 0x81, 0x8b, 0x65, 0xe7, 0xa4, 0x99, 0x58, 0x36, 0x78, 0x9f, 0x37, 0xe7, 0xd7, 0xfd, 0x43, 0x42, 0x55, 0xb0, 0x1b, + 0xde, 0x0e, 0x76, 0xe3, 0x84, 0x5f, 0x0b, 0xb1, 0xd4, 0xf1, 0x59, 0xcc, 0x25, 0xcb, 0x6f, 0xad, 0x77, 0x4b, 0x92, + 0x5a, 0x01, 0xed, 0xb3, 0x2c, 0xa8, 0x89, 0x00, 0x74, 0x3f, 0xfc, 0x05, 0x42, 0x67, 0xf8, 0xdb, 0x63, 0x70, 0x45, + 0x0a, 0xef, 0x1d, 0x02, 0x61, 0x4d, 0x37, 0xf7, 0x6a, 0x03, 0xbe, 0x18, 0xf7, 0x67, 0x4c, 0x3d, 0xfd, 0x36, 0x93, + 0xfb, 0xba, 0x6e, 0x8f, 0x2c, 0xc3, 0x47, 0xb8, 0x52, 0x00, 0x2c, 0x13, 0xfe, 0x62, 0x6c, 0x49, 0xf5, 0x09, 0xc0, + 0xa9, 0xe9, 0x88, 0x3e, 0x41, 0x60, 0xe0, 0x94, 0x68, 0x31, 0xba, 0x56, 0x8e, 0x68, 0x06, 0x69, 0x4d, 0xb7, 0xc2, + 0x78, 0xeb, 0x41, 0x0b, 0x3d, 0xd3, 0x70, 0xe2, 0x3f, 0x68, 0xe6, 0x55, 0x01, 0x01, 0xb4, 0x32, 0x82, 0xb7, 0xd6, + 0x47, 0x73, 0x84, 0xf8, 0x84, 0x25, 0xd1, 0x84, 0xc5, 0x33, 0xc5, 0x8f, 0x09, 0xdd, 0x36, 0xb5, 0x4d, 0x1f, 0x90, + 0xfe, 0xe2, 0x9a, 0xf5, 0x53, 0x56, 0xb5, 0x6f, 0x0f, 0x15, 0x2f, 0xa7, 0xcd, 0xe0, 0x87, 0x89, 0x2a, 0xc6, 0xff, + 0xa2, 0xf2, 0xa5, 0x56, 0x00, 0xc3, 0xdc, 0x55, 0x4f, 0xbf, 0xdf, 0xcc, 0x96, 0x03, 0xa1, 0xf2, 0x3b, 0x83, 0xa4, + 0x4f, 0xc7, 0xf3, 0x03, 0x9b, 0x44, 0x6d, 0xa1, 0xe7, 0x8f, 0x4b, 0xdd, 0x84, 0xca, 0x6b, 0x53, 0x23, 0x5a, 0x21, + 0x43, 0x65, 0xeb, 0x80, 0xf5, 0xfd, 0x43, 0xb8, 0xbf, 0xa8, 0x69, 0xa8, 0x75, 0xcf, 0x5d, 0x8b, 0x82, 0x13, 0x7f, + 0x80, 0xb1, 0xb8, 0x90, 0xd4, 0x3a, 0x08, 0x93, 0x7e, 0xb4, 0x38, 0xc9, 0x8d, 0xba, 0x3a, 0x39, 0x53, 0xcc, 0x13, + 0xb8, 0xa8, 0x96, 0x6d, 0x7f, 0x45, 0xa5, 0x2e, 0xe5, 0xf6, 0x8a, 0xd2, 0xf4, 0x90, 0xb6, 0x57, 0x71, 0xde, 0x16, + 0x5c, 0xf0, 0xcf, 0x14, 0x5c, 0x58, 0x07, 0xeb, 0x8e, 0x3b, 0x65, 0x4f, 0x78, 0xa2, 0x4c, 0x6b, 0x83, 0xbb, 0x69, + 0x30, 0x26, 0xc6, 0x7e, 0x77, 0xc5, 0x93, 0x8f, 0xc8, 0x82, 0x7f, 0x97, 0x09, 0xf0, 0x4c, 0x76, 0xaf, 0x54, 0xfe, + 0x1f, 0xfc, 0xab, 0xad, 0x7d, 0x67, 0xcd, 0x3f, 0x3d, 0xeb, 0xe1, 0xce, 0x61, 0xf2, 0x03, 0x74, 0x06, 0x74, 0x7b, + 0x25, 0x53, 0x0e, 0xc8, 0x00, 0xd6, 0x22, 0x19, 0x0d, 0xf8, 0xd0, 0xca, 0xb2, 0xed, 0x3b, 0xad, 0x2e, 0x08, 0xf7, + 0x12, 0xb8, 0xe9, 0xfd, 0xb5, 0x99, 0x99, 0xd3, 0xb5, 0x12, 0x4d, 0x97, 0xc6, 0xd6, 0xb2, 0x54, 0x01, 0xbb, 0xdf, + 0x7b, 0x92, 0x4d, 0xf3, 0xe3, 0xd5, 0x34, 0xb7, 0xd4, 0x6d, 0xeb, 0x96, 0x0d, 0x00, 0x21, 0x76, 0xad, 0xad, 0x1c, + 0x40, 0x72, 0x7b, 0x10, 0xc2, 0xd7, 0x8a, 0xd0, 0x53, 0x25, 0x42, 0x9f, 0xa6, 0xcd, 0x3e, 0xd8, 0x55, 0xb5, 0x69, + 0xc4, 0x39, 0x1a, 0xa4, 0x9a, 0x91, 0x7f, 0x7b, 0xcd, 0x8b, 0x8b, 0x5c, 0xde, 0x00, 0x06, 0x32, 0xa9, 0x8d, 0xc2, + 0xf2, 0x0a, 0xdc, 0xf9, 0xd1, 0x71, 0x9c, 0x89, 0x51, 0x8e, 0xc1, 0x5a, 0x11, 0x1e, 0x59, 0x27, 0xce, 0x01, 0x04, + 0xd9, 0x9f, 0x34, 0x1d, 0xcf, 0xb5, 0xc0, 0x98, 0xbe, 0xc0, 0x5d, 0xe5, 0x6c, 0xb6, 0xcd, 0xed, 0xa2, 0x6f, 0xce, + 0xb0, 0xee, 0x48, 0x69, 0x6d, 0x2c, 0xba, 0xee, 0x60, 0xad, 0x19, 0xb4, 0x45, 0x28, 0xf9, 0x90, 0x3b, 0x69, 0xff, + 0x0a, 0x68, 0x70, 0x96, 0xa5, 0xb7, 0xd6, 0x2a, 0x7f, 0xab, 0x85, 0x38, 0x51, 0x4c, 0x9d, 0xf8, 0x26, 0x4a, 0xf4, + 0xf9, 0x99, 0x18, 0x37, 0x10, 0x48, 0xfd, 0x01, 0x83, 0x6a, 0x14, 0x61, 0x02, 0xd7, 0x81, 0x28, 0xb6, 0x27, 0x6a, + 0x63, 0x39, 0x82, 0x4e, 0x08, 0xf1, 0x0e, 0xca, 0x30, 0x56, 0x17, 0x07, 0xda, 0x60, 0xe9, 0xeb, 0xd6, 0x3a, 0x37, + 0x84, 0xc2, 0x38, 0x81, 0x29, 0x06, 0x49, 0x9d, 0x75, 0x96, 0x09, 0xaa, 0xec, 0x98, 0x74, 0xde, 0x07, 0xe8, 0xfe, + 0x5a, 0x34, 0xc5, 0xd7, 0x9d, 0x3b, 0xe8, 0x3e, 0xae, 0x5f, 0x6b, 0x91, 0x1b, 0xfc, 0x79, 0x4b, 0x84, 0x45, 0xe0, + 0xac, 0x35, 0xf9, 0xaa, 0x11, 0x0e, 0x4c, 0x49, 0xa6, 0x61, 0x2f, 0x51, 0x36, 0xdd, 0xbb, 0x5d, 0xaf, 0x77, 0xaf, + 0x88, 0xab, 0xc7, 0x58, 0xe5, 0xdd, 0xcc, 0xed, 0x9d, 0x6a, 0x23, 0xf6, 0x6f, 0xda, 0x7e, 0x8a, 0x1d, 0xb5, 0xd6, + 0x6e, 0x37, 0x9c, 0x50, 0x43, 0xbe, 0x15, 0x55, 0x5a, 0x9d, 0x6e, 0x0c, 0xda, 0x21, 0x9e, 0xb5, 0xc8, 0xe0, 0x46, + 0xf9, 0xdc, 0x09, 0x9d, 0x54, 0x9c, 0x55, 0xa7, 0x2e, 0xd8, 0x5e, 0xf1, 0x6a, 0x25, 0xd3, 0x48, 0x50, 0xb4, 0x39, + 0x8f, 0x4a, 0x9a, 0xc8, 0x8d, 0xa8, 0x22, 0x59, 0xa3, 0x5e, 0xd4, 0x6a, 0x0c, 0x10, 0x90, 0xe9, 0xac, 0xe9, 0x41, + 0x15, 0xcc, 0x87, 0x32, 0x92, 0xd3, 0xf7, 0x60, 0x69, 0x8f, 0x1c, 0x6b, 0x7d, 0x5f, 0x9d, 0x2d, 0xbe, 0xd5, 0x13, + 0x82, 0x29, 0xcc, 0x1e, 0x08, 0x03, 0xd7, 0x34, 0x86, 0x9c, 0x76, 0x89, 0xcb, 0x9a, 0x6e, 0x09, 0xf7, 0x70, 0xbb, + 0x92, 0xcd, 0xdc, 0x3c, 0x69, 0x6e, 0xae, 0x60, 0xb3, 0x62, 0x31, 0x06, 0xed, 0x97, 0x54, 0xd7, 0x2e, 0xcd, 0xad, + 0xc7, 0x83, 0x80, 0x06, 0x83, 0xc2, 0xf0, 0xaf, 0x13, 0xe3, 0xe1, 0x49, 0x03, 0x82, 0xa4, 0x5c, 0x84, 0x63, 0xdf, + 0x88, 0x7e, 0x32, 0x95, 0xc7, 0x1c, 0x2d, 0xde, 0xa1, 0xd5, 0x09, 0x44, 0xf1, 0x12, 0xa1, 0x24, 0x46, 0x55, 0x68, + 0x44, 0x50, 0x9e, 0x96, 0xbf, 0x54, 0xd5, 0x21, 0xa0, 0x90, 0xf6, 0x15, 0x85, 0xb2, 0x4d, 0x62, 0x68, 0x86, 0x5f, + 0x2e, 0x26, 0x4b, 0x3d, 0x03, 0x03, 0xb9, 0x38, 0x5a, 0xea, 0x59, 0x18, 0xc8, 0xc5, 0x57, 0xcb, 0xda, 0xad, 0x03, + 0x4d, 0x40, 0x3c, 0x17, 0x8e, 0x4e, 0x4a, 0xab, 0xb2, 0x05, 0x74, 0xfb, 0x10, 0x41, 0xff, 0xbb, 0x3d, 0x04, 0x9d, + 0x5c, 0x68, 0x4f, 0x6e, 0x40, 0xdb, 0x71, 0x08, 0xec, 0x15, 0x93, 0x0a, 0x13, 0x80, 0xe8, 0x98, 0x8d, 0xc1, 0x10, + 0x5b, 0x7d, 0x70, 0xcc, 0xc6, 0x53, 0x9f, 0x04, 0x01, 0xa3, 0xfb, 0x83, 0x81, 0x04, 0xbf, 0xc5, 0xab, 0xf4, 0x6c, + 0x2b, 0xd0, 0x4d, 0xdf, 0xdd, 0x0d, 0xbd, 0x8b, 0x2b, 0x38, 0x55, 0xbb, 0x7b, 0x12, 0xba, 0xc9, 0xb4, 0x03, 0xf4, + 0x1a, 0xe2, 0x86, 0xfc, 0xca, 0x68, 0x34, 0xb2, 0x29, 0x21, 0x21, 0x86, 0x73, 0x68, 0xe6, 0xb4, 0x5c, 0xbe, 0xba, + 0xf5, 0x6c, 0x41, 0x86, 0x99, 0xde, 0x32, 0x59, 0x3f, 0x40, 0x59, 0xf5, 0x18, 0xda, 0xa1, 0xf7, 0xc8, 0xf1, 0xc3, + 0x83, 0x6f, 0x32, 0x7e, 0xe2, 0x70, 0xed, 0xe1, 0x5c, 0xf8, 0x2e, 0x6b, 0x46, 0xe6, 0xd0, 0x79, 0xf6, 0x71, 0xbc, + 0x87, 0x71, 0xf2, 0x69, 0x16, 0xca, 0x1b, 0xaf, 0xe9, 0x7f, 0x54, 0x7a, 0xb3, 0xc3, 0x21, 0xa7, 0x6b, 0x58, 0x71, + 0xf3, 0x2a, 0x34, 0xfc, 0x2c, 0xf2, 0xc6, 0x11, 0xaf, 0x49, 0x54, 0x75, 0x9f, 0xf7, 0x36, 0x4c, 0x69, 0xc7, 0x38, + 0x00, 0x38, 0x51, 0xab, 0x86, 0x7d, 0x69, 0x5c, 0xab, 0x83, 0x18, 0x86, 0x12, 0xb6, 0x4a, 0x1c, 0x09, 0xe5, 0x6f, + 0x00, 0xc2, 0x62, 0x28, 0x8e, 0xb7, 0x86, 0xf5, 0x01, 0xf6, 0x43, 0x17, 0x68, 0x9a, 0x53, 0xaa, 0x19, 0x00, 0x24, + 0x01, 0x7f, 0xf4, 0x74, 0xd3, 0x50, 0xd9, 0xe6, 0x79, 0x68, 0x59, 0x5d, 0xc1, 0x03, 0x3d, 0x75, 0x25, 0x03, 0xe3, + 0xaa, 0x8e, 0xbd, 0xed, 0xfd, 0xed, 0xd1, 0x2a, 0xf2, 0xbd, 0x4d, 0x6a, 0x9b, 0x55, 0xa1, 0xb1, 0x8f, 0x27, 0xf4, + 0x74, 0x02, 0xb4, 0x5e, 0x5b, 0x2a, 0xda, 0xef, 0xa3, 0x18, 0x35, 0x2e, 0x14, 0x58, 0x85, 0x89, 0x04, 0x87, 0x08, + 0x23, 0x84, 0x7e, 0x5f, 0x86, 0x5b, 0x5f, 0x90, 0x41, 0x34, 0x5c, 0x8b, 0x8e, 0x3f, 0xe4, 0x78, 0xd1, 0xb6, 0x54, + 0xd5, 0x9c, 0x34, 0x6d, 0x09, 0xbc, 0x09, 0x07, 0xd8, 0xce, 0x3f, 0x6d, 0x88, 0x5c, 0x85, 0x8b, 0x12, 0xbe, 0x27, + 0xae, 0x05, 0xd1, 0x4d, 0x6d, 0xea, 0x6d, 0xd8, 0x21, 0x3a, 0x9a, 0xe2, 0xd1, 0x21, 0xf7, 0xdc, 0x3d, 0xb7, 0x45, + 0x7c, 0xf3, 0x09, 0x72, 0xd7, 0x74, 0xf6, 0x52, 0x84, 0x41, 0xdd, 0xb2, 0x81, 0x62, 0x1d, 0x3b, 0x41, 0x01, 0x46, + 0x6d, 0xf9, 0x0b, 0xe8, 0xd8, 0x60, 0x50, 0x11, 0x7c, 0x52, 0xd8, 0x36, 0x0d, 0xf2, 0x47, 0xbc, 0x1b, 0x3a, 0xbc, + 0xb6, 0xe4, 0x81, 0x78, 0x85, 0x7d, 0xa2, 0x84, 0xfb, 0x17, 0x14, 0x74, 0x47, 0x79, 0xb9, 0x2a, 0x5c, 0x95, 0x06, + 0xa0, 0xca, 0x9e, 0xe7, 0x5a, 0x53, 0xd2, 0x02, 0x56, 0x4a, 0xea, 0xce, 0x6f, 0x22, 0xe2, 0x96, 0x4c, 0xc5, 0x6c, + 0xd5, 0x8d, 0x2a, 0x8f, 0x25, 0x8a, 0x74, 0xec, 0xd9, 0xce, 0xc1, 0x1a, 0x00, 0x4f, 0x61, 0x7b, 0x71, 0x86, 0x05, + 0x65, 0x5c, 0xb6, 0xcc, 0x25, 0x50, 0xd4, 0x0f, 0xe3, 0xbc, 0xec, 0xf9, 0x72, 0x77, 0xb4, 0xbd, 0x87, 0xde, 0x88, + 0x8d, 0xf1, 0xfa, 0x3c, 0x6a, 0xfa, 0xd9, 0x33, 0x5c, 0x59, 0x0a, 0xf2, 0x40, 0x53, 0x3d, 0xc2, 0xe8, 0x10, 0x98, + 0xa6, 0x7c, 0xc6, 0xc6, 0xd3, 0xe1, 0xd0, 0x90, 0x41, 0xaf, 0x99, 0x18, 0xff, 0xeb, 0x33, 0x68, 0x9d, 0x99, 0xb8, + 0xc6, 0xa7, 0xed, 0x2b, 0x68, 0x75, 0x8b, 0x32, 0xb9, 0x33, 0x30, 0x7c, 0xa0, 0x25, 0x53, 0x30, 0x55, 0x78, 0x43, + 0xa4, 0x92, 0xfd, 0xb5, 0xb2, 0x0e, 0xfb, 0x76, 0xa1, 0xd0, 0x42, 0x13, 0xbf, 0xca, 0x10, 0x3f, 0x75, 0x9d, 0xf9, + 0xb7, 0x69, 0x9f, 0x1a, 0xc4, 0xc2, 0x92, 0x18, 0x85, 0xf8, 0xc5, 0xa9, 0xb2, 0x9d, 0x10, 0x2a, 0x20, 0x1e, 0xba, + 0xd6, 0x8d, 0x23, 0xa9, 0x62, 0x4f, 0x0a, 0x8d, 0xa7, 0x86, 0xfb, 0x5e, 0xe8, 0x98, 0x75, 0x98, 0xc5, 0x6d, 0xd6, + 0x48, 0x6a, 0x8c, 0x53, 0x61, 0x82, 0x53, 0xca, 0x75, 0x24, 0x30, 0x3a, 0x9e, 0x2d, 0x0c, 0xa2, 0x4a, 0x62, 0x92, + 0xb1, 0xb5, 0x10, 0x26, 0x76, 0x9d, 0x2b, 0x4c, 0x53, 0x17, 0xa9, 0xdf, 0x0c, 0x4c, 0x16, 0x34, 0xe4, 0xf7, 0x68, + 0xb4, 0xa6, 0x6a, 0x0a, 0x30, 0x8c, 0xa3, 0x54, 0xe3, 0xdf, 0x22, 0xd4, 0x66, 0x18, 0x00, 0xd8, 0xe6, 0x9d, 0xcc, + 0x44, 0xf5, 0x4a, 0x20, 0x04, 0x9a, 0xb3, 0x9f, 0x2a, 0xaa, 0xbd, 0x59, 0x30, 0x8a, 0x76, 0x7b, 0xe5, 0xf3, 0x81, + 0x13, 0xca, 0x13, 0x75, 0x81, 0x7a, 0x29, 0x8b, 0xd7, 0x32, 0xe5, 0xad, 0xb8, 0x98, 0x07, 0x92, 0x7d, 0xc8, 0x47, + 0x70, 0x5e, 0xa1, 0x53, 0xb9, 0xd9, 0x26, 0xca, 0x2c, 0x49, 0x32, 0x16, 0x18, 0x9b, 0x97, 0x60, 0x2e, 0x35, 0x33, + 0x86, 0x5f, 0x43, 0x70, 0xb1, 0xbd, 0x93, 0x70, 0x7b, 0x3f, 0x0f, 0x0c, 0xa1, 0xc9, 0x45, 0x4b, 0x34, 0x6c, 0xed, + 0x78, 0x3d, 0xb9, 0x26, 0xdc, 0x87, 0x8d, 0x58, 0x93, 0x31, 0xc6, 0xb5, 0xb9, 0x91, 0xf5, 0xa3, 0x05, 0x1e, 0x8c, + 0x29, 0xeb, 0x4f, 0x20, 0xd3, 0x4a, 0xca, 0xba, 0x58, 0x1a, 0x31, 0x93, 0x4a, 0xf4, 0x6e, 0xdf, 0xf8, 0xac, 0xee, + 0x22, 0xea, 0xb7, 0xf6, 0x7b, 0x52, 0x0f, 0x77, 0xfe, 0x83, 0xc2, 0x1a, 0x54, 0x46, 0x5c, 0x46, 0x94, 0x67, 0x0e, + 0x74, 0xd3, 0xa4, 0x88, 0xd3, 0xb3, 0x75, 0x5c, 0x94, 0x3c, 0x85, 0x4a, 0x35, 0x75, 0x8b, 0x7a, 0x13, 0xb0, 0x37, + 0x44, 0x92, 0x64, 0x2d, 0x8d, 0xad, 0xd8, 0xa5, 0x41, 0x7a, 0xee, 0x0d, 0xb3, 0xf4, 0xb2, 0x42, 0x43, 0x5a, 0xea, + 0x9d, 0x85, 0x4a, 0xe6, 0xaf, 0xf8, 0xcf, 0xa0, 0x56, 0xa0, 0xa3, 0x4d, 0x8a, 0xf1, 0x0c, 0x18, 0xf1, 0xfd, 0x08, + 0x56, 0x0f, 0x10, 0x17, 0x4d, 0x50, 0xea, 0x3d, 0xb1, 0xe3, 0xa7, 0x26, 0x0f, 0xef, 0x42, 0xce, 0x19, 0x7c, 0xfa, + 0x30, 0x4b, 0xd4, 0x5a, 0x47, 0x62, 0xa4, 0x66, 0x00, 0x4d, 0x07, 0x65, 0xce, 0x63, 0x11, 0xcc, 0x7b, 0x26, 0x31, + 0xea, 0x71, 0xfd, 0x0b, 0x34, 0xd4, 0x7e, 0xb3, 0xb2, 0x3c, 0xab, 0xee, 0x3e, 0x87, 0x03, 0x9b, 0xda, 0x0a, 0x7a, + 0xbc, 0xae, 0xe4, 0xe5, 0xa5, 0xea, 0xb6, 0x5f, 0x88, 0x91, 0xd3, 0x35, 0xae, 0xa5, 0x8b, 0x6a, 0xc9, 0x7a, 0xdd, + 0xe9, 0x66, 0x71, 0x37, 0xcb, 0x68, 0x20, 0xac, 0xed, 0x7d, 0xa2, 0xf9, 0xb3, 0x66, 0xdb, 0x7d, 0xbc, 0x05, 0x31, + 0x0f, 0x00, 0x20, 0x3d, 0x88, 0x82, 0x55, 0x96, 0xf2, 0x80, 0xca, 0xfb, 0x38, 0xca, 0x42, 0xe9, 0xe5, 0x2c, 0xe3, + 0xa7, 0x4d, 0x63, 0xad, 0xb3, 0x42, 0x19, 0x5a, 0x1b, 0xdd, 0xe9, 0x3a, 0x43, 0x6c, 0x3f, 0x89, 0xb3, 0x05, 0xb8, + 0x3f, 0x66, 0x28, 0x34, 0x74, 0x96, 0x91, 0x26, 0x1a, 0xbe, 0xeb, 0x9e, 0x41, 0x46, 0x71, 0xb2, 0xce, 0x2b, 0xe9, + 0x56, 0x9f, 0xb5, 0x91, 0x30, 0xf7, 0x10, 0xfd, 0x2a, 0x06, 0x8f, 0x72, 0x9f, 0xd7, 0x46, 0x27, 0xd3, 0x32, 0xd2, + 0xee, 0xfc, 0xa4, 0x5e, 0x65, 0xa9, 0xd6, 0x61, 0xfb, 0x0c, 0x7b, 0x6b, 0x4c, 0x7a, 0x13, 0x52, 0xc3, 0x48, 0x7c, + 0x3a, 0xa3, 0x46, 0x08, 0x68, 0xcb, 0xf1, 0xf7, 0xf8, 0x0c, 0x43, 0x53, 0x60, 0xa9, 0xe2, 0x16, 0x76, 0xc3, 0xd7, + 0x7c, 0xb2, 0x6a, 0x01, 0x88, 0x60, 0xe5, 0xeb, 0x5d, 0xbc, 0x12, 0xea, 0x33, 0x6d, 0x06, 0x80, 0x2c, 0x28, 0xe5, + 0x8e, 0x9f, 0x52, 0xe9, 0x60, 0x89, 0xa2, 0xed, 0xe5, 0xf4, 0x8d, 0x8e, 0x8d, 0x1f, 0xd2, 0x73, 0x01, 0xdb, 0x85, + 0xfc, 0xd6, 0xbd, 0x7a, 0x89, 0x8a, 0xd4, 0xb6, 0x59, 0x0f, 0xf0, 0xe5, 0x06, 0x4d, 0xc2, 0x08, 0xca, 0x94, 0x29, + 0x80, 0xc1, 0x4d, 0x35, 0x0a, 0x26, 0xad, 0x46, 0xc2, 0x96, 0x7a, 0x92, 0xe5, 0xa6, 0x0f, 0x4e, 0x75, 0x8f, 0xa0, + 0x47, 0x3b, 0x9c, 0xb4, 0xec, 0xd7, 0x0a, 0x8e, 0x4e, 0xae, 0x86, 0xa8, 0x99, 0xf7, 0xda, 0x8e, 0x0c, 0x29, 0x97, + 0x61, 0x20, 0x98, 0x72, 0xcc, 0xd3, 0x63, 0xeb, 0x19, 0x11, 0x3d, 0x70, 0xf6, 0x99, 0x6e, 0xd5, 0x95, 0x04, 0x44, + 0xc7, 0xaf, 0x9f, 0xbc, 0xba, 0x8a, 0x2f, 0x0d, 0x8a, 0x52, 0xc3, 0x22, 0x46, 0x99, 0xf6, 0x55, 0x12, 0x06, 0xef, + 0x97, 0xf7, 0x3f, 0xa9, 0x2c, 0xb5, 0xdf, 0x83, 0xad, 0x15, 0x55, 0xfd, 0x52, 0xf2, 0xa2, 0x29, 0xc0, 0xba, 0xcf, + 0x12, 0x05, 0x72, 0xbf, 0xb7, 0x69, 0xe6, 0x9b, 0xa8, 0x71, 0xb3, 0x61, 0xbd, 0x71, 0xdd, 0x2e, 0xb5, 0x25, 0x3b, + 0xb2, 0x12, 0x39, 0xb3, 0x18, 0xcc, 0xf8, 0x51, 0x61, 0x50, 0x1a, 0xb6, 0xa8, 0x4a, 0xc5, 0xef, 0x8d, 0x08, 0x4e, + 0x1d, 0xab, 0x0a, 0x63, 0x1a, 0x30, 0xdb, 0x8a, 0x5a, 0x83, 0x3a, 0x28, 0xa5, 0xad, 0x89, 0xc2, 0xf6, 0x1b, 0x2b, + 0xa8, 0xf9, 0xfd, 0x4f, 0x63, 0xc8, 0xd7, 0x94, 0x82, 0x4a, 0x02, 0x76, 0x06, 0x8d, 0x9e, 0x2a, 0x61, 0x20, 0x05, + 0xc1, 0x13, 0xa0, 0x7c, 0x11, 0x35, 0x56, 0xfb, 0x7d, 0x75, 0x6a, 0x8c, 0xb6, 0x80, 0xd0, 0x42, 0x7a, 0x74, 0xd9, + 0xc7, 0x6d, 0xad, 0x03, 0x89, 0x07, 0x27, 0xd8, 0xce, 0xd5, 0x35, 0x1a, 0x09, 0xcd, 0x1f, 0x1a, 0x0d, 0x78, 0x4d, + 0x2b, 0x50, 0xa8, 0xe7, 0x38, 0x1a, 0x3a, 0x3b, 0xa4, 0x20, 0x62, 0x83, 0x16, 0xf6, 0xdd, 0xf3, 0xa1, 0xd9, 0xd7, + 0x8b, 0x64, 0x49, 0x6a, 0x2a, 0xdd, 0xe7, 0x6e, 0x09, 0x59, 0xab, 0x0e, 0x65, 0xe5, 0x01, 0x8e, 0x17, 0x4a, 0xe6, + 0xef, 0x30, 0xa9, 0x51, 0x1a, 0x13, 0x1a, 0x23, 0x16, 0xb0, 0x24, 0x68, 0xaf, 0x07, 0xea, 0x97, 0x41, 0xa8, 0x70, + 0xa6, 0x27, 0x12, 0x9f, 0x52, 0xae, 0x3e, 0x2d, 0x48, 0x3d, 0x2d, 0x98, 0x03, 0xbd, 0xf4, 0xad, 0xfc, 0xca, 0xc6, + 0x47, 0xfb, 0x7b, 0xd7, 0x5c, 0x58, 0xc7, 0x10, 0x0c, 0x5b, 0xf8, 0xcd, 0xa9, 0x29, 0x00, 0x1b, 0x9e, 0xe8, 0xb2, + 0x7c, 0xa3, 0x26, 0x32, 0x8f, 0x43, 0x12, 0x81, 0x64, 0xbb, 0xb9, 0xb9, 0x8d, 0x60, 0xdb, 0x5b, 0xa8, 0x0d, 0xf5, + 0x97, 0xb7, 0xdd, 0xef, 0x19, 0x5e, 0xee, 0xc9, 0xbd, 0x9b, 0x36, 0x94, 0x3f, 0xdc, 0xbf, 0x4a, 0xfe, 0xaf, 0x2a, + 0xb9, 0xdf, 0x2a, 0xb3, 0x6e, 0x8b, 0xf7, 0xbb, 0x8e, 0x5b, 0x8e, 0xd1, 0x20, 0xb0, 0xa6, 0xc0, 0x40, 0x7a, 0xd2, + 0x98, 0x26, 0x3a, 0xa4, 0x32, 0x63, 0x06, 0x8f, 0x2e, 0x40, 0x73, 0x98, 0xce, 0xf3, 0x18, 0x80, 0x03, 0xfc, 0x23, + 0x8f, 0x50, 0xff, 0x74, 0x5e, 0x04, 0x67, 0xc1, 0xa0, 0x1c, 0x04, 0xfa, 0x13, 0xd7, 0x9c, 0x60, 0x09, 0x3a, 0xb7, + 0x98, 0x41, 0xb0, 0x49, 0x6b, 0xe6, 0x10, 0x1f, 0x27, 0xd3, 0xc1, 0x20, 0x26, 0x5b, 0x00, 0xe9, 0x8b, 0x97, 0xd6, + 0x39, 0xa8, 0xd0, 0x0b, 0xb2, 0x55, 0x77, 0xd1, 0xac, 0xd8, 0xab, 0x76, 0x9a, 0xf7, 0xfb, 0xf9, 0xa2, 0x1c, 0x04, + 0x8d, 0x0a, 0x0b, 0xe3, 0xfd, 0x47, 0x9b, 0x5f, 0x1a, 0x9d, 0x34, 0xc1, 0x30, 0xb5, 0x27, 0xa8, 0x5e, 0xf1, 0x34, + 0xa3, 0x8d, 0xdb, 0xb1, 0x52, 0xbe, 0x80, 0x28, 0x1e, 0x18, 0xb2, 0x56, 0xde, 0xbd, 0x83, 0xd7, 0xe5, 0xc6, 0x9b, + 0x23, 0x0a, 0xb0, 0x9b, 0xc2, 0x38, 0xa9, 0xb9, 0xe8, 0xa2, 0x26, 0x9e, 0xc1, 0x4e, 0x57, 0x6f, 0x25, 0x5a, 0x8d, + 0xf7, 0xe2, 0x7d, 0xb3, 0xf1, 0x37, 0xf2, 0x40, 0x97, 0x79, 0x70, 0x01, 0x88, 0xb3, 0x07, 0x71, 0x75, 0x80, 0xa5, + 0x1e, 0x04, 0x03, 0x8b, 0x1c, 0xd2, 0xae, 0x56, 0x0f, 0x45, 0xa4, 0xce, 0x63, 0x30, 0x60, 0x32, 0x0d, 0xa9, 0xc9, + 0xb4, 0x57, 0x28, 0x48, 0x1b, 0x6b, 0x2d, 0xa0, 0x0d, 0x87, 0xc5, 0x9e, 0xdd, 0xb0, 0x3b, 0xdd, 0x3a, 0x14, 0x4a, + 0x18, 0xbd, 0xba, 0x6e, 0x1e, 0x6a, 0x0d, 0x4f, 0x04, 0x3d, 0xa8, 0x46, 0xfb, 0xe9, 0xa1, 0x3c, 0x69, 0x8f, 0x05, + 0xb8, 0xe8, 0xe1, 0xcb, 0x17, 0x02, 0x2f, 0xda, 0x7b, 0xc8, 0x73, 0xe6, 0x53, 0xe5, 0x83, 0xd8, 0x70, 0xcb, 0xf0, + 0xa1, 0x7d, 0x7c, 0x2b, 0x90, 0x49, 0xdd, 0xd1, 0xd4, 0xd6, 0xee, 0x68, 0x1c, 0x13, 0xe8, 0x37, 0xe5, 0x28, 0x65, + 0x62, 0x6a, 0x59, 0xb1, 0x59, 0x2f, 0x57, 0xde, 0x50, 0x29, 0x9b, 0xad, 0xda, 0x9c, 0x5f, 0xda, 0x48, 0xe8, 0xf7, + 0xb5, 0x3b, 0x10, 0xbe, 0x51, 0xeb, 0x0d, 0x79, 0xd9, 0x10, 0xb1, 0x1c, 0x62, 0x06, 0x8e, 0x17, 0x52, 0xb9, 0x76, + 0x17, 0x4d, 0x55, 0xdd, 0xde, 0x56, 0x2e, 0x68, 0x89, 0xb7, 0x52, 0x60, 0x15, 0xa9, 0xd3, 0xeb, 0xa9, 0xc4, 0xfb, + 0x3e, 0x8a, 0xed, 0x47, 0xc0, 0x36, 0x36, 0x8e, 0xc6, 0xc6, 0x2d, 0x62, 0x8b, 0xaf, 0xa2, 0x8a, 0x16, 0x1c, 0x20, + 0xb8, 0xdb, 0x92, 0x5a, 0x9a, 0x39, 0xc4, 0x7d, 0xc5, 0x03, 0xb4, 0xef, 0xe2, 0x88, 0x53, 0x01, 0xb6, 0x75, 0xad, + 0x73, 0x56, 0xcb, 0x01, 0x9b, 0x89, 0x9e, 0x7f, 0x5a, 0x35, 0x12, 0x31, 0xac, 0xb2, 0x91, 0xb2, 0x42, 0x7b, 0x50, + 0xba, 0x84, 0x8b, 0x2f, 0xc0, 0xcb, 0xf6, 0xfd, 0xca, 0xee, 0xb3, 0x15, 0xf6, 0x0f, 0xf3, 0xaa, 0x09, 0x1e, 0x79, + 0x8d, 0xb7, 0xf7, 0x30, 0xf1, 0xb9, 0x52, 0x08, 0xaf, 0x52, 0x1a, 0x4a, 0x00, 0x06, 0x49, 0x50, 0xc3, 0x95, 0xb6, + 0xcd, 0x20, 0x95, 0x31, 0xec, 0x7e, 0xf5, 0x56, 0xff, 0xa7, 0x55, 0xb8, 0xa8, 0x64, 0x31, 0x26, 0x81, 0xce, 0xa9, + 0x96, 0x9b, 0x98, 0x82, 0x67, 0xfb, 0xe4, 0x08, 0x14, 0x76, 0x02, 0xb8, 0xa1, 0x84, 0xfd, 0x82, 0xb7, 0xa1, 0x9c, + 0xbd, 0xb4, 0x92, 0x27, 0xb7, 0x2f, 0xa9, 0xa0, 0x09, 0x99, 0x0a, 0xbb, 0x7f, 0x5b, 0x1b, 0xf6, 0x79, 0x28, 0x47, + 0x52, 0xe0, 0xe2, 0xa0, 0x0b, 0x00, 0xfb, 0x83, 0x5c, 0xc6, 0xe6, 0x33, 0xe9, 0xf7, 0xd5, 0xfb, 0x67, 0x79, 0x96, + 0x7c, 0xdc, 0x7b, 0x6f, 0x78, 0x9a, 0x15, 0x03, 0x2a, 0x11, 0x53, 0xeb, 0xaa, 0x18, 0xae, 0xb4, 0x8b, 0x71, 0x83, + 0x64, 0xc4, 0xf7, 0x52, 0x87, 0x18, 0x31, 0xbe, 0xc8, 0x1e, 0x49, 0xc9, 0xe9, 0xaa, 0xee, 0xec, 0xb9, 0x16, 0xcd, + 0xa0, 0x31, 0xdc, 0x9e, 0xf7, 0x92, 0x5e, 0x01, 0x2a, 0x2a, 0x74, 0xcf, 0x02, 0xd7, 0xf0, 0xe6, 0x92, 0x68, 0x6c, + 0xe9, 0x69, 0x4b, 0x34, 0x70, 0xaf, 0x4c, 0x48, 0xaa, 0x8d, 0x03, 0x2c, 0x62, 0x5d, 0x7f, 0x0c, 0x25, 0x00, 0xb5, + 0x1a, 0xa4, 0x57, 0xfa, 0x92, 0x50, 0x95, 0x84, 0x60, 0x74, 0x22, 0xe1, 0x65, 0x40, 0xe3, 0xcc, 0x24, 0x5a, 0xd8, + 0xe0, 0x80, 0x3e, 0xaf, 0x4c, 0xa2, 0xb1, 0x21, 0x0f, 0x68, 0x65, 0xd3, 0x00, 0x06, 0x1f, 0x24, 0x49, 0xf4, 0xd5, + 0xca, 0x24, 0x81, 0xa0, 0x04, 0xe5, 0x1b, 0xf4, 0xe7, 0xd2, 0xf3, 0xb1, 0xfc, 0x97, 0x77, 0x28, 0xfd, 0x10, 0x4a, + 0x90, 0x29, 0xea, 0x8a, 0x69, 0xc6, 0x66, 0x59, 0xb7, 0x31, 0x89, 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, + 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x59, 0xbc, 0x66, 0x27, 0x21, 0xd7, 0x78, 0xe9, 0xcf, 0xe2, 0x35, 0xce, 0x10, 0xad, + 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, + 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x5e, 0x92, 0xf9, 0xf2, 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, + 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, + 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x58, 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, + 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1a, 0x50, 0x22, 0xa3, 0xb2, 0xe2, 0xeb, 0x35, 0x4f, 0xe7, 0xb7, 0x49, 0x94, + 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0xd9, 0x9c, 0x67, 0xc9, 0x2b, 0x88, 0x3d, 0xb0, 0x96, 0x0a, 0x8b, + 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x7e, 0x9d, 0x44, 0x6f, 0x56, 0x1e, 0x92, 0x9a, 0x99, + 0xb2, 0x6d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x5b, 0x6d, 0x01, 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, + 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, + 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x8f, 0x8b, 0x7e, 0x5f, 0x1e, 0x17, 0xbb, 0x5d, 0x39, 0x8b, 0xfb, 0x7d, + 0x39, 0x8b, 0x0d, 0xff, 0xa0, 0x14, 0xdb, 0xc6, 0xdc, 0x20, 0xa1, 0xb9, 0x84, 0xa8, 0x45, 0x23, 0xf8, 0x43, 0xb3, + 0x9c, 0x8b, 0x28, 0x3f, 0x4e, 0xfa, 0xfd, 0xde, 0x6a, 0x2e, 0x06, 0xf9, 0x30, 0x89, 0xf2, 0x61, 0xe2, 0x39, 0x21, + 0xfe, 0xea, 0x39, 0x21, 0x2a, 0x1a, 0xb8, 0x86, 0x33, 0x03, 0x10, 0x05, 0x7c, 0xfa, 0x47, 0x75, 0x2d, 0x85, 0xae, + 0x25, 0x56, 0xb5, 0x24, 0xba, 0x82, 0x9a, 0x5d, 0x17, 0x61, 0x89, 0xa5, 0xd0, 0x15, 0xfb, 0x63, 0x05, 0x3c, 0x51, + 0xce, 0xab, 0x2d, 0x30, 0xb0, 0x11, 0xde, 0x39, 0x4c, 0x38, 0x89, 0x4d, 0x0d, 0x68, 0xa7, 0xdb, 0x9a, 0x5e, 0xd0, + 0x35, 0xbd, 0x44, 0x7e, 0xf6, 0x02, 0x0c, 0x96, 0x8e, 0x59, 0x3e, 0x1d, 0x0c, 0x2e, 0xc8, 0x9a, 0x95, 0x8b, 0x30, + 0x1e, 0x84, 0x9b, 0x79, 0x3e, 0xbc, 0x88, 0x2e, 0x08, 0xf9, 0xa2, 0x58, 0xd2, 0xde, 0x7a, 0x54, 0x7e, 0xcc, 0x20, + 0xb8, 0x5f, 0x3a, 0x0f, 0x33, 0x13, 0xe7, 0x63, 0x3d, 0xba, 0xa5, 0x6b, 0x88, 0x5f, 0x03, 0x37, 0x12, 0x12, 0x41, + 0x47, 0x2e, 0xe9, 0x9a, 0x6e, 0xa8, 0x34, 0x33, 0x8c, 0x21, 0xba, 0xed, 0x71, 0x92, 0x80, 0x63, 0xb2, 0x2b, 0x3e, + 0x1a, 0xab, 0xc2, 0xbb, 0xbe, 0x23, 0xb4, 0xd7, 0x4b, 0xdc, 0x20, 0x7d, 0xd7, 0x1e, 0x24, 0x60, 0x44, 0x46, 0x6a, + 0xa0, 0xcc, 0xc8, 0x48, 0x6a, 0x26, 0x15, 0x87, 0x24, 0xf6, 0x87, 0x44, 0x8d, 0x43, 0xe2, 0x8f, 0x43, 0xae, 0xc7, + 0x01, 0xb9, 0xfb, 0x15, 0x1b, 0xd3, 0x94, 0x8d, 0xe9, 0x46, 0x8d, 0x0a, 0xbd, 0xa2, 0xe7, 0x9a, 0x3a, 0x9e, 0xb1, + 0xd7, 0x70, 0x60, 0x0f, 0xc2, 0x7c, 0x1e, 0x0f, 0x5f, 0x47, 0xaf, 0x09, 0xf9, 0x42, 0xd2, 0x6b, 0x75, 0x29, 0x83, + 0x30, 0x88, 0x57, 0xe0, 0x5c, 0xea, 0x42, 0x9d, 0x5c, 0x99, 0x1d, 0x87, 0x4f, 0x97, 0x8d, 0xa7, 0x73, 0x88, 0xe8, + 0x83, 0x56, 0x2a, 0xfd, 0x7e, 0x78, 0xc1, 0xca, 0xc5, 0x59, 0x38, 0x26, 0x80, 0xc3, 0xa3, 0x87, 0xf3, 0x62, 0x74, + 0x4b, 0x2f, 0x46, 0x77, 0x04, 0x2c, 0xbc, 0xc6, 0xd3, 0xcd, 0x31, 0x8b, 0xa7, 0x83, 0xc1, 0x06, 0xa9, 0xba, 0xca, + 0xbd, 0x21, 0x4b, 0x7a, 0x81, 0x13, 0x41, 0x80, 0xa1, 0xcf, 0xc4, 0xc6, 0xd0, 0xf0, 0xd7, 0x0c, 0x3e, 0xbe, 0x63, + 0x17, 0xa3, 0x3b, 0x7a, 0xcb, 0x5e, 0xef, 0xc6, 0x53, 0x60, 0xa6, 0xd6, 0xf3, 0xf0, 0xee, 0xf8, 0x72, 0x7e, 0xc9, + 0xee, 0xa2, 0xbb, 0x19, 0x34, 0xf4, 0x8a, 0xdd, 0x21, 0xe0, 0x52, 0xfa, 0x78, 0x35, 0x78, 0x4d, 0x0e, 0x07, 0x83, + 0x94, 0x44, 0xe1, 0x75, 0xe8, 0xb5, 0xf2, 0x35, 0xbd, 0x23, 0x74, 0xcd, 0x6e, 0x71, 0x34, 0x2e, 0x19, 0x7e, 0x70, + 0xce, 0xee, 0xea, 0xeb, 0xd0, 0xdb, 0xcd, 0x89, 0xe8, 0x04, 0x31, 0x42, 0x5f, 0x03, 0x47, 0xb3, 0x5c, 0x98, 0x09, + 0x78, 0x32, 0x17, 0x19, 0x2d, 0x0a, 0xcd, 0x40, 0x9c, 0x95, 0x80, 0x58, 0x12, 0x75, 0xbf, 0xd9, 0xe8, 0x0c, 0x96, + 0x73, 0xbf, 0xdf, 0xab, 0x0c, 0x3d, 0x40, 0xe4, 0xcc, 0x4e, 0x7a, 0xd0, 0xf3, 0xe9, 0x01, 0x7e, 0xa2, 0x57, 0x0d, + 0xe2, 0x64, 0x7e, 0xb7, 0x8a, 0x7e, 0xf5, 0xe8, 0xc3, 0x0f, 0xdd, 0x94, 0x47, 0xe4, 0xff, 0x3e, 0xe5, 0x29, 0xf3, + 0xe8, 0x75, 0xe5, 0x81, 0xe0, 0x79, 0x6b, 0x52, 0x69, 0x24, 0xaa, 0xd1, 0xd9, 0x3a, 0x06, 0x6d, 0x24, 0x6a, 0x1b, + 0xf4, 0x13, 0x5a, 0x58, 0x41, 0x84, 0x9c, 0xa3, 0xe7, 0x60, 0x90, 0x0a, 0xa1, 0x72, 0xd4, 0xa2, 0x44, 0x43, 0x90, + 0x5c, 0x96, 0x5c, 0x85, 0xcf, 0x21, 0x54, 0x9d, 0x3e, 0xce, 0x44, 0xd8, 0xd0, 0xe3, 0xd0, 0x07, 0x80, 0xff, 0x65, + 0x8f, 0x5c, 0x94, 0xfc, 0x12, 0xcf, 0xe6, 0x36, 0xc1, 0x28, 0x58, 0x22, 0x9a, 0xa1, 0x6d, 0x10, 0xfb, 0xb1, 0x24, + 0x58, 0x8f, 0xa4, 0xf1, 0xa8, 0x34, 0x47, 0x84, 0x1f, 0xc5, 0x47, 0xd1, 0xd3, 0xd8, 0x90, 0x48, 0x8e, 0x24, 0x92, + 0x0f, 0x80, 0x70, 0x12, 0xf4, 0x17, 0x77, 0x4d, 0x76, 0x2d, 0x24, 0x06, 0xfd, 0x69, 0xc5, 0xb4, 0xec, 0x5e, 0xf5, + 0xd8, 0x57, 0x04, 0xb9, 0x63, 0xfa, 0x4f, 0xaf, 0x0f, 0xff, 0x5c, 0xe1, 0x0c, 0x5a, 0xcf, 0x17, 0xd5, 0x99, 0xb9, + 0x37, 0xb8, 0x91, 0xd7, 0x65, 0xed, 0xba, 0x7c, 0xc1, 0x0f, 0xf8, 0x6d, 0xc5, 0x45, 0x5a, 0x1e, 0xfc, 0x5c, 0xb5, + 0xf1, 0x9c, 0xca, 0xcd, 0xda, 0xc5, 0x59, 0x51, 0xc6, 0xa9, 0x9e, 0xd4, 0xc5, 0x58, 0xc3, 0x36, 0xfc, 0x1e, 0x51, + 0x57, 0xd2, 0x72, 0xf4, 0x94, 0x72, 0xdd, 0x4c, 0xb9, 0xd8, 0xe4, 0xf9, 0x4f, 0x7b, 0xa9, 0x38, 0xc5, 0xcd, 0x14, + 0xa4, 0x4a, 0x2d, 0x17, 0x50, 0x3d, 0x47, 0x2d, 0x77, 0x4b, 0xb3, 0x03, 0x9c, 0xdb, 0xa6, 0xfa, 0x58, 0x99, 0x5d, + 0x78, 0xc9, 0x8d, 0xfb, 0x93, 0x29, 0xc3, 0x82, 0x51, 0x68, 0xb3, 0xea, 0x4a, 0xdb, 0x17, 0x5a, 0xa7, 0x61, 0xb8, + 0xf2, 0xe3, 0x05, 0xa4, 0x0b, 0x18, 0xc7, 0x8b, 0x92, 0x89, 0x71, 0x7b, 0xf4, 0x56, 0x10, 0x9f, 0xb3, 0x15, 0x08, + 0x98, 0x6b, 0x78, 0xbb, 0xae, 0xa3, 0xed, 0x9e, 0x38, 0x65, 0x54, 0xae, 0x63, 0xf1, 0x7d, 0xbc, 0x36, 0x90, 0xc9, + 0xea, 0x78, 0x6c, 0x8c, 0xe9, 0xf4, 0xef, 0x49, 0xe8, 0x17, 0x42, 0xc1, 0x67, 0xbd, 0xb4, 0xf2, 0xe4, 0xf6, 0xb0, + 0x8c, 0x6b, 0xf4, 0x4a, 0x5c, 0xeb, 0xbe, 0x19, 0x29, 0xa4, 0x1e, 0xf9, 0xaa, 0x29, 0xa0, 0x37, 0x63, 0xdf, 0x4c, + 0x85, 0x79, 0xbb, 0x67, 0xcc, 0x15, 0x82, 0x95, 0x2a, 0xbb, 0x7d, 0xa7, 0xc6, 0x54, 0xcc, 0x60, 0x8a, 0x6d, 0x67, + 0x31, 0xe9, 0x56, 0xfe, 0x69, 0xe7, 0x7e, 0x95, 0x77, 0xb8, 0x2b, 0xea, 0xb7, 0xc0, 0x85, 0x66, 0x45, 0x59, 0xb5, + 0x65, 0xc3, 0xb6, 0xf1, 0x46, 0x16, 0x8a, 0x0d, 0xb0, 0xec, 0xb9, 0x6f, 0xe1, 0x01, 0xe2, 0x26, 0xdc, 0xb3, 0xcb, + 0x1a, 0x6e, 0x0c, 0x9f, 0x57, 0x92, 0xef, 0x4a, 0x63, 0x2e, 0x7d, 0xaa, 0x34, 0x31, 0x9c, 0x2c, 0x47, 0x5c, 0xa4, + 0xcb, 0x3a, 0xb3, 0x6b, 0xe1, 0x13, 0x5e, 0x86, 0x0b, 0xbe, 0x34, 0xba, 0x29, 0x5d, 0x7a, 0xc1, 0x62, 0xdd, 0xe9, + 0xed, 0x5a, 0x63, 0xa5, 0x44, 0xdc, 0x9a, 0x65, 0x02, 0x65, 0x29, 0x6b, 0x25, 0xbc, 0x29, 0x5a, 0xb6, 0x92, 0x46, + 0xde, 0xb3, 0x00, 0xf7, 0xb1, 0x1f, 0x10, 0x13, 0xd9, 0x04, 0x26, 0x45, 0x43, 0x07, 0xb4, 0xab, 0x2e, 0x7c, 0x33, + 0xea, 0xc1, 0x20, 0xb7, 0x24, 0x11, 0x2b, 0x48, 0xb1, 0x82, 0x4d, 0xcd, 0x8a, 0x45, 0xbe, 0xa4, 0x17, 0x4c, 0x2e, + 0xd2, 0x25, 0x5d, 0x33, 0xb9, 0xd8, 0xe0, 0x4d, 0xe8, 0x02, 0x4e, 0x48, 0xb2, 0x8d, 0x95, 0x02, 0xf6, 0x02, 0x2f, + 0x6f, 0x78, 0xa6, 0x6a, 0x5a, 0x76, 0xa9, 0x38, 0xc0, 0xf8, 0xbc, 0x0c, 0xc3, 0x72, 0x78, 0x01, 0xd6, 0x12, 0x87, + 0xe1, 0x7a, 0xc1, 0x97, 0xea, 0x37, 0x04, 0x9c, 0x4f, 0x42, 0xc5, 0x2e, 0xd8, 0xbd, 0x40, 0xa6, 0x57, 0x0b, 0xbe, + 0x54, 0x23, 0xa1, 0x0b, 0xbe, 0xb2, 0xc6, 0x26, 0xb1, 0x27, 0x68, 0x99, 0xc7, 0x8b, 0xf1, 0x32, 0x8a, 0x6b, 0x58, + 0x86, 0xa7, 0x6a, 0x66, 0x5a, 0xf2, 0x9f, 0x44, 0x6d, 0x68, 0xa2, 0x6f, 0xb0, 0x8a, 0xfc, 0xe1, 0xf1, 0xd1, 0x25, + 0x90, 0xb1, 0xb3, 0x2b, 0x99, 0xf9, 0xd0, 0xf7, 0x91, 0xc1, 0x3d, 0x37, 0xe5, 0x8c, 0xab, 0x20, 0x51, 0x06, 0xee, + 0x5e, 0xcd, 0x92, 0xb1, 0x16, 0xe1, 0xfb, 0x47, 0x45, 0xd1, 0x67, 0xd2, 0x34, 0xa0, 0xfb, 0x48, 0x30, 0x07, 0x7a, + 0xaf, 0xd0, 0xe1, 0xb2, 0xda, 0x66, 0x02, 0xfe, 0x22, 0x41, 0x7e, 0x2b, 0xf4, 0xaa, 0xc6, 0xa0, 0x8a, 0x76, 0x11, + 0x4b, 0xff, 0x3e, 0xe2, 0x47, 0xd9, 0xfc, 0xd3, 0xdc, 0xe3, 0x95, 0x84, 0xc1, 0x0f, 0xa9, 0xd9, 0x24, 0xf3, 0xf6, + 0x8a, 0x7d, 0x0f, 0x1d, 0xf5, 0xa8, 0x35, 0xde, 0x57, 0x2f, 0x38, 0x85, 0x18, 0x25, 0x14, 0x9d, 0x04, 0x03, 0xb8, + 0x5d, 0x42, 0x8a, 0xbb, 0xc1, 0x6e, 0x9b, 0xd7, 0xbc, 0x28, 0x38, 0xdf, 0x54, 0x55, 0xe0, 0x07, 0x34, 0x5c, 0x2c, + 0xf7, 0x43, 0x18, 0x8e, 0x69, 0xeb, 0x1a, 0x06, 0x61, 0xc6, 0x30, 0x12, 0x82, 0xd7, 0xbf, 0xe8, 0x2b, 0x9a, 0xc4, + 0xeb, 0xef, 0xf8, 0x5f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, + 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, + 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, + 0x9d, 0x07, 0x74, 0x7b, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, 0x4f, 0xae, 0xd8, 0xac, 0xea, 0xa1, 0xf6, 0xde, + 0x8c, 0x50, 0xd0, 0xef, 0x63, 0x0a, 0x74, 0x23, 0xa8, 0xbd, 0xab, 0xfb, 0x8f, 0xe5, 0x3e, 0x87, 0xef, 0x38, 0xcb, + 0x2d, 0x60, 0xa9, 0xc8, 0x5a, 0x81, 0x47, 0x01, 0xea, 0x52, 0x19, 0xc2, 0x16, 0x73, 0x38, 0x54, 0x76, 0xab, 0x56, + 0x43, 0x49, 0x8e, 0xcb, 0x11, 0x38, 0x84, 0x6e, 0xca, 0x41, 0x39, 0x5a, 0x65, 0xd5, 0x7b, 0xfc, 0xad, 0x59, 0x87, + 0x24, 0xbb, 0x8f, 0x75, 0xe0, 0x96, 0x75, 0x98, 0x7e, 0x34, 0x48, 0x01, 0x68, 0xb2, 0x11, 0xb8, 0x04, 0xe0, 0xbd, + 0xfd, 0x47, 0x84, 0x5a, 0x99, 0xde, 0xcb, 0x58, 0xa8, 0xef, 0x1b, 0x49, 0x50, 0x42, 0x33, 0xa1, 0x72, 0x2c, 0x05, + 0xef, 0x3c, 0xd2, 0x39, 0xa9, 0x33, 0xf1, 0x1e, 0xc4, 0x69, 0xe1, 0x03, 0x7b, 0x0b, 0x82, 0x73, 0x16, 0xf4, 0x0e, + 0x6f, 0xb3, 0x5a, 0x6a, 0xa3, 0x07, 0x0a, 0xe0, 0x77, 0x83, 0x3b, 0x04, 0xf9, 0x6a, 0x0c, 0xd7, 0x5a, 0xde, 0x84, + 0x7c, 0x58, 0xd0, 0x23, 0x32, 0xb0, 0xcf, 0x62, 0x18, 0xd3, 0x23, 0x72, 0x6c, 0x9f, 0xa5, 0x1b, 0xc0, 0x81, 0xd4, + 0xa3, 0x4a, 0x8f, 0xa0, 0x41, 0xbf, 0xd9, 0x16, 0x59, 0x92, 0xf5, 0x63, 0x69, 0x14, 0x31, 0x50, 0x25, 0x88, 0xa8, + 0xc5, 0x3f, 0x1f, 0xcc, 0x75, 0x87, 0xb9, 0x40, 0x98, 0x83, 0x01, 0x07, 0x71, 0x1b, 0x84, 0xe6, 0x80, 0xd9, 0xde, + 0x46, 0x82, 0xde, 0x59, 0xc3, 0xcc, 0x8e, 0xfe, 0x70, 0x2b, 0xc1, 0x37, 0x59, 0x6b, 0xd4, 0x79, 0x71, 0x08, 0x04, + 0xc1, 0x9b, 0x42, 0x55, 0x7b, 0xd5, 0x03, 0x1b, 0x6f, 0xd5, 0x8f, 0xdd, 0x6e, 0x3c, 0x15, 0xee, 0xda, 0x2f, 0x28, + 0x9c, 0x7c, 0x4a, 0xfe, 0xf5, 0xde, 0x64, 0x70, 0x60, 0x64, 0xf8, 0xd2, 0xdb, 0xbf, 0xf0, 0xb5, 0x96, 0xee, 0x89, + 0x41, 0x49, 0x1e, 0x1f, 0x29, 0xfa, 0x77, 0xaf, 0xac, 0x7c, 0x6a, 0xa7, 0x7f, 0xb7, 0x33, 0xeb, 0xf3, 0x78, 0x34, + 0xd9, 0xed, 0x7a, 0xda, 0xc0, 0x95, 0x6a, 0x15, 0x02, 0x76, 0xa1, 0x24, 0x87, 0x47, 0x10, 0x15, 0xa1, 0x19, 0x77, + 0xb3, 0x6c, 0x48, 0x64, 0xfc, 0x38, 0x9d, 0x65, 0x43, 0xb0, 0xc3, 0xbd, 0xa8, 0xc4, 0xe5, 0xa8, 0xb5, 0xc1, 0xe9, + 0x59, 0x12, 0x42, 0x28, 0x07, 0xac, 0xec, 0x56, 0xfd, 0xb9, 0x53, 0x66, 0x42, 0x6a, 0xb2, 0xba, 0x9d, 0xd2, 0x3d, + 0x4c, 0xf3, 0x03, 0x33, 0x82, 0x03, 0xee, 0xed, 0xaf, 0xfa, 0x63, 0x98, 0x64, 0x9a, 0x9c, 0x22, 0xf9, 0x45, 0x7a, + 0x0a, 0x49, 0x7b, 0xf4, 0x54, 0x11, 0xc0, 0x09, 0xb5, 0x1f, 0xc3, 0x6f, 0x18, 0xf7, 0xef, 0x9a, 0xaf, 0xdd, 0x54, + 0x44, 0x4f, 0x28, 0x96, 0xa9, 0xc9, 0x69, 0x92, 0x15, 0x09, 0x44, 0x6d, 0x54, 0xcd, 0x88, 0xbe, 0x72, 0x31, 0x1f, + 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xf4, 0x09, + 0x3d, 0x98, 0x7c, 0x7d, 0x44, 0x0f, 0x8e, 0xbe, 0x7a, 0x4a, 0x00, 0x16, 0xed, 0xf2, 0x3c, 0x3c, 0x7a, 0xfa, 0x94, + 0x1e, 0x7c, 0xfb, 0x2d, 0x3d, 0x98, 0x7c, 0x75, 0xd4, 0x48, 0x9b, 0x3c, 0xfd, 0x96, 0x1e, 0x7c, 0xfd, 0xa4, 0x91, + 0x76, 0x34, 0x7e, 0x4a, 0x0f, 0xbe, 0xf9, 0xda, 0xa4, 0xfd, 0x0d, 0xb2, 0x7d, 0x7b, 0x84, 0xff, 0x99, 0xb4, 0xc9, + 0xd3, 0xaf, 0xe8, 0xc1, 0x64, 0x0c, 0x95, 0x3c, 0x75, 0x95, 0x8c, 0x27, 0xf0, 0xf1, 0x57, 0xf0, 0xdf, 0xdf, 0x48, + 0xb0, 0xa4, 0x95, 0x64, 0xb9, 0x40, 0xfd, 0x19, 0x8a, 0x38, 0x51, 0x35, 0x91, 0xf0, 0x10, 0x33, 0xab, 0x6f, 0xe2, + 0x30, 0x20, 0x2e, 0x1d, 0x0a, 0xa2, 0x07, 0xe3, 0xd1, 0x53, 0x12, 0xf8, 0xf0, 0x74, 0x37, 0x3e, 0xc8, 0x58, 0x2e, + 0x16, 0xd9, 0x17, 0xb9, 0x89, 0xad, 0xe0, 0x01, 0x58, 0x7d, 0xf4, 0x73, 0x55, 0x72, 0x91, 0x7d, 0x51, 0xc9, 0xfd, + 0x5c, 0xbf, 0xb5, 0x00, 0xe5, 0xfd, 0x55, 0xcb, 0x6e, 0x0a, 0x15, 0x3a, 0xad, 0x35, 0xfa, 0xec, 0x23, 0xa6, 0x0f, + 0x06, 0xde, 0x0d, 0xfb, 0xef, 0x7b, 0xe5, 0xb4, 0xbe, 0xd1, 0x28, 0xd4, 0xa8, 0x3c, 0x24, 0x6c, 0x06, 0x45, 0x0f, + 0x06, 0xc0, 0x13, 0x78, 0xb8, 0x6f, 0xff, 0x66, 0x19, 0x1f, 0x3b, 0xca, 0xf8, 0x19, 0x65, 0x08, 0x68, 0xd4, 0xc3, + 0xec, 0xa6, 0x87, 0x8d, 0x6e, 0xf5, 0x92, 0xa5, 0x3a, 0x99, 0x9a, 0x9e, 0xc1, 0xbe, 0xd6, 0xb5, 0x3c, 0x30, 0xa2, + 0x68, 0x79, 0x71, 0x90, 0xf2, 0x79, 0xc5, 0xfe, 0xbe, 0x42, 0xf5, 0x56, 0xd4, 0x78, 0x23, 0xb3, 0x79, 0xc5, 0xbe, + 0x37, 0x6f, 0x80, 0x9b, 0x61, 0xbf, 0xa9, 0x27, 0x3f, 0x70, 0x06, 0x97, 0xb6, 0x3d, 0xca, 0xc4, 0x08, 0xb0, 0x02, + 0x32, 0x70, 0xe0, 0x01, 0xd0, 0x41, 0x7f, 0xb4, 0x77, 0x3b, 0x95, 0xd2, 0xec, 0xb3, 0x85, 0x01, 0x34, 0xcc, 0xdb, + 0xc4, 0x95, 0xfd, 0xaf, 0x86, 0xbc, 0x04, 0x85, 0x5b, 0xcd, 0xf2, 0xf6, 0x0a, 0x43, 0x08, 0xc1, 0x1f, 0x57, 0x0c, + 0x00, 0x07, 0x02, 0x0c, 0xc6, 0x5a, 0x06, 0xd4, 0x6c, 0xf9, 0x68, 0xcb, 0x95, 0x7a, 0x12, 0x38, 0x83, 0x0b, 0x59, + 0x24, 0xfc, 0xad, 0x16, 0xfb, 0xa3, 0xf5, 0xa3, 0xef, 0xdb, 0xe3, 0xc1, 0xda, 0xf7, 0xf8, 0x48, 0x7f, 0xd6, 0xb8, + 0x0e, 0x6c, 0x5b, 0xbe, 0xf1, 0xa2, 0xb6, 0x12, 0x8f, 0x12, 0x78, 0x03, 0x13, 0x91, 0xc2, 0x20, 0xd5, 0x02, 0xc7, + 0xa0, 0xbc, 0xb1, 0x10, 0x4b, 0xd5, 0xd5, 0x0d, 0xb6, 0x20, 0x32, 0x04, 0x0f, 0xb7, 0x7f, 0xad, 0x54, 0xe0, 0xa8, + 0x7e, 0x9f, 0x4b, 0xdf, 0xed, 0xc9, 0xd8, 0x91, 0xe3, 0xd4, 0x4f, 0x85, 0x83, 0xff, 0x26, 0x75, 0x6d, 0x2c, 0x57, + 0x52, 0x66, 0x59, 0x16, 0x36, 0x0b, 0xb5, 0xdc, 0xa3, 0xf2, 0x20, 0xf9, 0x42, 0x0e, 0x91, 0x2c, 0x30, 0x0a, 0x05, + 0x19, 0x4e, 0xa8, 0x18, 0x6d, 0x44, 0xb9, 0xca, 0x2e, 0xaa, 0x70, 0xab, 0x14, 0xca, 0x9c, 0xa2, 0x6f, 0x37, 0x38, + 0x90, 0x90, 0x28, 0x2b, 0xdf, 0xc4, 0x6f, 0x42, 0x04, 0xab, 0xe3, 0xda, 0x16, 0x8a, 0x7b, 0xfb, 0x93, 0xa7, 0x5d, + 0xfc, 0x91, 0x71, 0x01, 0x75, 0xb1, 0x98, 0x86, 0x13, 0x1b, 0xfb, 0xc6, 0x7d, 0x61, 0x35, 0x3d, 0x00, 0xf5, 0x5d, + 0x2a, 0x31, 0x82, 0xfa, 0xca, 0xd8, 0xc7, 0xf6, 0x18, 0x93, 0x73, 0x88, 0x35, 0xac, 0x72, 0x66, 0xaa, 0x6f, 0x84, + 0xcd, 0x00, 0xb8, 0x11, 0x5a, 0xa3, 0x20, 0xf0, 0x78, 0x15, 0xe2, 0x79, 0xa9, 0xc2, 0xb7, 0x66, 0x84, 0x8e, 0xc1, + 0x9b, 0xca, 0x36, 0x32, 0x93, 0xbe, 0x60, 0xd0, 0x1c, 0xdb, 0x3a, 0x0a, 0xab, 0xad, 0x2c, 0x9b, 0x01, 0xdc, 0x40, + 0x76, 0x6c, 0x2e, 0x9e, 0xf3, 0x6a, 0x91, 0x2d, 0x23, 0x13, 0x14, 0x70, 0x25, 0x2c, 0x83, 0xf6, 0xd7, 0x3d, 0xb2, + 0x1d, 0x87, 0xd0, 0x0d, 0xf7, 0x11, 0x8c, 0xa7, 0xdd, 0x14, 0xac, 0x20, 0x1a, 0x21, 0x1e, 0x66, 0xcc, 0xe2, 0x7b, + 0xa5, 0x29, 0x4f, 0x55, 0x4b, 0x20, 0x70, 0x14, 0x42, 0x5d, 0xec, 0x1b, 0x25, 0xb8, 0x4c, 0x8d, 0x60, 0x06, 0x7b, + 0x76, 0xa4, 0xb6, 0x4b, 0xce, 0xe9, 0x50, 0x4d, 0x69, 0xa9, 0xa7, 0x54, 0xfb, 0x1a, 0x8a, 0x45, 0x89, 0x1e, 0x7a, + 0xe0, 0x7a, 0xa0, 0x1d, 0xf2, 0x4a, 0x3a, 0x31, 0x11, 0x74, 0x5a, 0x6d, 0xc2, 0xce, 0x8d, 0x74, 0xcb, 0x6a, 0xe4, + 0x1d, 0x43, 0xb3, 0x23, 0x5e, 0xf8, 0x81, 0xba, 0x00, 0x22, 0xe4, 0xde, 0x16, 0x99, 0x23, 0x9a, 0x65, 0xe5, 0x4b, + 0x28, 0x8b, 0x23, 0xb6, 0xae, 0x80, 0x6b, 0x29, 0x98, 0x5c, 0xf2, 0x88, 0xa7, 0x88, 0x08, 0x78, 0xa2, 0xb4, 0xeb, + 0x7b, 0x2d, 0x21, 0x34, 0x4b, 0x81, 0xb8, 0xb9, 0x28, 0xce, 0xb5, 0x0d, 0x64, 0x01, 0xf4, 0xed, 0xa7, 0xec, 0xca, + 0x0b, 0x07, 0xbb, 0xbd, 0xca, 0xc4, 0x73, 0x7e, 0x91, 0x09, 0x9e, 0x22, 0xd8, 0xd5, 0xad, 0x79, 0xe0, 0x8e, 0x6d, + 0x03, 0xcb, 0xb7, 0xef, 0x60, 0xc1, 0x94, 0xa1, 0x56, 0x4a, 0x64, 0x22, 0x12, 0x90, 0xd9, 0x67, 0xee, 0x5e, 0x67, + 0xe2, 0x75, 0x7c, 0x0b, 0xde, 0x14, 0x0d, 0x7e, 0x7a, 0x74, 0x8e, 0x5f, 0x22, 0x92, 0x28, 0xc4, 0xb0, 0xc5, 0x88, + 0x58, 0x88, 0x1c, 0x3b, 0x26, 0x94, 0x2b, 0x41, 0x6b, 0x6b, 0x08, 0xbc, 0xf8, 0xd3, 0xaa, 0x7b, 0x57, 0x99, 0x30, + 0xf6, 0x19, 0x57, 0xf1, 0x2d, 0x2b, 0x15, 0x98, 0x05, 0xc6, 0xb9, 0x6f, 0x4b, 0x49, 0xae, 0x32, 0x61, 0x04, 0x24, + 0x57, 0xf1, 0x2d, 0x6d, 0xca, 0x38, 0xb4, 0x15, 0x9d, 0x17, 0xe7, 0x77, 0x7f, 0xf8, 0x25, 0x86, 0x5a, 0x19, 0xf7, + 0xfb, 0x20, 0x31, 0x93, 0xb6, 0x29, 0x73, 0x19, 0x49, 0x8d, 0x16, 0x52, 0x51, 0x3e, 0x98, 0x90, 0xfd, 0x95, 0x6a, + 0x19, 0x51, 0xfb, 0x55, 0x28, 0xe6, 0xe3, 0x68, 0x42, 0xe8, 0xa4, 0x63, 0xbd, 0x9b, 0xd6, 0x42, 0xa6, 0xd1, 0xd3, + 0xc8, 0xf3, 0xe9, 0x2c, 0x58, 0x35, 0x2d, 0x8e, 0x19, 0x9f, 0x16, 0x83, 0x01, 0xd1, 0x2e, 0x85, 0x5b, 0xac, 0x07, + 0x4c, 0x69, 0x5c, 0xbc, 0x35, 0xd3, 0xea, 0x97, 0x52, 0x85, 0xa4, 0xf7, 0x0c, 0x48, 0x32, 0xe9, 0x82, 0xdd, 0x82, + 0x44, 0xd1, 0xf3, 0xbf, 0x53, 0x5b, 0x70, 0xdf, 0x83, 0xb1, 0x19, 0xdd, 0xd7, 0x33, 0xfe, 0x43, 0x6d, 0x0b, 0xa2, + 0x3e, 0x95, 0xac, 0xd7, 0x91, 0xa8, 0x42, 0x2e, 0xc2, 0xcf, 0x8e, 0x86, 0x18, 0xa2, 0xda, 0x63, 0x81, 0xd8, 0x5c, + 0x9d, 0xf3, 0x02, 0xa7, 0x9f, 0xb9, 0xcb, 0x15, 0x6c, 0x0b, 0x5a, 0x19, 0x1a, 0xf5, 0x26, 0x7e, 0x13, 0xd9, 0xcb, + 0x82, 0x2e, 0xf2, 0x39, 0x0a, 0x59, 0xf3, 0x30, 0xac, 0x86, 0xed, 0x41, 0x24, 0x87, 0xed, 0x49, 0x68, 0x34, 0x06, + 0x16, 0xc8, 0x1e, 0x8d, 0xc0, 0x45, 0x68, 0xe5, 0x6f, 0xc7, 0xe0, 0xc2, 0x65, 0x11, 0x59, 0x86, 0x3a, 0x7e, 0x53, + 0xbb, 0x09, 0xaa, 0x57, 0xe8, 0x34, 0x85, 0x55, 0x29, 0x93, 0x7c, 0xf8, 0xf5, 0x52, 0x16, 0x98, 0xc9, 0xeb, 0xb2, + 0x47, 0x5f, 0xdb, 0xed, 0x1d, 0x98, 0x82, 0x75, 0x9f, 0xbc, 0xaf, 0x1f, 0x77, 0xf6, 0x04, 0x8c, 0x62, 0x55, 0x8e, + 0xa6, 0x90, 0x52, 0xfb, 0xa0, 0xd4, 0x1f, 0xc3, 0x95, 0xd0, 0x1c, 0xbb, 0x05, 0x4c, 0x02, 0xf6, 0x19, 0x52, 0x3d, + 0xa6, 0x1d, 0xfb, 0x1c, 0x6d, 0x61, 0x49, 0xc0, 0xe1, 0x1f, 0x65, 0xb2, 0xf6, 0xaf, 0xee, 0x22, 0x6d, 0x86, 0x6c, + 0x59, 0x2c, 0x81, 0xcf, 0x87, 0x5d, 0x1b, 0x95, 0x28, 0x9b, 0x88, 0x24, 0x85, 0x2d, 0x8f, 0x41, 0xda, 0xa3, 0x98, + 0xae, 0x0b, 0x9e, 0x64, 0x28, 0xa5, 0x48, 0xb4, 0x4f, 0x70, 0x0e, 0x6f, 0x70, 0x3f, 0xaa, 0x80, 0xf0, 0x2a, 0xe4, + 0x74, 0x94, 0x52, 0x6d, 0x01, 0xa3, 0xa8, 0x07, 0x88, 0xf2, 0x32, 0x90, 0xe3, 0xed, 0x76, 0x13, 0xba, 0x66, 0xab, + 0xe1, 0x84, 0x22, 0x29, 0xb9, 0xc4, 0x72, 0xaf, 0x40, 0xe7, 0x71, 0xce, 0x7a, 0x2f, 0x00, 0x8b, 0xe0, 0x0c, 0xfe, + 0xc6, 0x84, 0x5e, 0xc3, 0xdf, 0x9c, 0xd0, 0xd7, 0x2c, 0xbc, 0x1a, 0x5e, 0x92, 0xc3, 0x30, 0x1d, 0x4c, 0x94, 0x60, + 0xec, 0x8e, 0xad, 0xca, 0x50, 0x25, 0xae, 0x0f, 0x2f, 0xc8, 0xe3, 0x0b, 0x7a, 0x4b, 0x6f, 0xe8, 0x29, 0x7d, 0x0b, + 0x84, 0xff, 0xee, 0x78, 0xc2, 0x87, 0x93, 0x27, 0xfd, 0x7e, 0xef, 0xbc, 0xdf, 0xef, 0x9d, 0x19, 0x03, 0x0a, 0xbd, + 0x8b, 0x2e, 0x6b, 0xaa, 0x7f, 0x5d, 0xd5, 0xcb, 0xe9, 0x5b, 0xb5, 0x71, 0x13, 0x9e, 0xe5, 0xe1, 0xd5, 0xe1, 0x1d, + 0x19, 0xe2, 0xe3, 0x45, 0x2e, 0x65, 0x11, 0x5e, 0x1e, 0xde, 0x11, 0xfa, 0x76, 0x06, 0x7a, 0x53, 0xac, 0xef, 0xed, + 0xe3, 0x3b, 0x5d, 0x1b, 0xa1, 0x2f, 0xc2, 0x04, 0xb6, 0xc9, 0x2d, 0xb3, 0x77, 0xed, 0xc9, 0x18, 0x62, 0x99, 0xdc, + 0x79, 0xe5, 0xdd, 0x3d, 0xbe, 0x25, 0x87, 0xb7, 0xe0, 0x29, 0x6a, 0xc9, 0xdf, 0x3c, 0xbc, 0x61, 0xad, 0x1a, 0x1e, + 0xdf, 0xd1, 0xd3, 0x56, 0x23, 0x1e, 0xdf, 0x91, 0x28, 0xbc, 0x61, 0x97, 0xf4, 0x94, 0x5d, 0x11, 0x7a, 0xde, 0xef, + 0x9f, 0xf5, 0xfb, 0xb2, 0xdf, 0xff, 0x7b, 0x1c, 0x86, 0xf1, 0xb0, 0x20, 0x87, 0x92, 0xde, 0x1d, 0x4e, 0xf8, 0x57, + 0x64, 0x1e, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0xde, + 0xd2, 0x1b, 0x56, 0xd0, 0x53, 0x16, 0x93, 0xe8, 0x1a, 0x5a, 0x71, 0x3e, 0x2f, 0xa2, 0x1b, 0x7a, 0xca, 0xce, 0xe6, + 0x71, 0x74, 0x4a, 0xdf, 0xb2, 0x7c, 0x38, 0x81, 0xbc, 0xa7, 0xc3, 0x1b, 0x72, 0xf8, 0x96, 0x44, 0xe1, 0x5b, 0xfd, + 0xfb, 0x8e, 0x5e, 0xf2, 0xf0, 0x2d, 0xf5, 0xaa, 0x79, 0x4b, 0x4c, 0xf5, 0x8d, 0xda, 0xdf, 0x92, 0xc8, 0x1f, 0xcc, + 0xb7, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, + 0x06, 0x74, 0xfe, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, + 0xd7, 0xc1, 0x2b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0x9b, 0x7e, 0x1f, 0x22, 0xdd, 0x17, 0x73, 0x13, 0xdb, 0xcd, + 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0x57, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, 0xbc, 0x19, 0xbc, 0x7a, 0x7c, 0x47, + 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x6b, 0x9a, 0x01, 0xe0, 0xd7, 0xab, 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, + 0x7d, 0x75, 0xfc, 0x76, 0x3a, 0x18, 0xbc, 0x32, 0xdb, 0xe4, 0x0d, 0xbb, 0xa7, 0x14, 0x58, 0x7f, 0x67, 0xfd, 0xfe, + 0x9b, 0x59, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xc6, 0x45, 0x55, 0x3b, 0xeb, 0xf7, 0x37, 0xfd, + 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9d, 0xaf, 0x27, 0x48, 0x5b, 0x16, 0x8e, 0x22, 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, + 0xac, 0xda, 0x36, 0xef, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, 0xec, 0x9d, 0xed, 0x76, 0xa7, 0x8c, + 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, 0xcc, 0xe6, 0x76, 0x65, 0x0f, 0x81, + 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0xcf, 0x00, 0x42, 0x24, 0x59, 0xc8, 0xe7, 0x38, + 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xb7, 0x1b, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, + 0xd1, 0xdf, 0x9e, 0x3e, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, 0x61, 0x17, 0x6b, 0x75, 0x08, 0x46, + 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0x3e, 0x9b, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, + 0x18, 0x4c, 0x2e, 0xd2, 0x4f, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, + 0xdb, 0xed, 0x2a, 0xff, 0x12, 0xf8, 0x06, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, + 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, 0xba, 0xdc, 0x93, 0xea, 0x5f, 0xbc, + 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, 0x04, 0xb7, 0x56, 0x22, 0x89, 0x35, + 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0x59, 0xc9, 0xf8, 0xbc, 0x8c, 0x12, 0x1a, 0xc3, 0x83, 0x64, 0x62, 0x2e, 0xa3, + 0x04, 0xed, 0x13, 0x5d, 0x84, 0xc1, 0x3f, 0x01, 0xb3, 0x9f, 0xe6, 0xf0, 0x57, 0x92, 0x69, 0x72, 0x0c, 0x01, 0x21, + 0x8e, 0xc7, 0xf3, 0x38, 0x1c, 0x93, 0x28, 0x99, 0xc1, 0x13, 0xfc, 0x57, 0x84, 0x63, 0x52, 0xeb, 0x3b, 0x8c, 0x54, + 0x97, 0xdb, 0x84, 0x01, 0x5c, 0xd9, 0x78, 0x3e, 0x89, 0xac, 0x74, 0x57, 0x3e, 0x1e, 0x8d, 0x9f, 0x92, 0x69, 0x1c, + 0xca, 0x41, 0x42, 0x28, 0x78, 0xf7, 0x86, 0xe5, 0x30, 0xd1, 0xf0, 0x6c, 0xc0, 0xe6, 0x95, 0x8e, 0xcd, 0x93, 0x70, + 0x02, 0xc2, 0x30, 0x21, 0xc7, 0x7a, 0x0f, 0x52, 0x8a, 0x3e, 0xcf, 0xb1, 0x9f, 0xfa, 0x08, 0xc2, 0xec, 0xa8, 0xa5, + 0xe2, 0x6b, 0x00, 0xba, 0xc4, 0xc1, 0xa1, 0xf6, 0xcc, 0x17, 0xf3, 0xb0, 0xf4, 0xa8, 0x94, 0xa9, 0xee, 0x50, 0x34, + 0x28, 0xbf, 0x69, 0xd0, 0xa1, 0x20, 0x83, 0x09, 0x2d, 0x67, 0x13, 0xfe, 0x15, 0x04, 0xf0, 0x68, 0x44, 0xfc, 0x52, + 0x38, 0x31, 0x10, 0x5e, 0x05, 0x19, 0xa8, 0xb4, 0x56, 0x8d, 0x19, 0xd9, 0x8a, 0x0f, 0x20, 0x4c, 0xca, 0xc1, 0x8d, + 0xdc, 0xe4, 0x29, 0x44, 0x05, 0xdb, 0xe4, 0xd5, 0xc1, 0x25, 0x58, 0xb2, 0xc7, 0x15, 0xc4, 0x09, 0xdb, 0xac, 0x01, + 0x3b, 0xf7, 0xd1, 0xb6, 0xac, 0x0f, 0xd4, 0x77, 0x07, 0xd8, 0x72, 0x78, 0x55, 0xc9, 0x83, 0xc9, 0x78, 0x3c, 0x1e, + 0xfd, 0x0e, 0x47, 0x07, 0x10, 0x5a, 0x12, 0x19, 0x3e, 0x19, 0xa0, 0x71, 0x37, 0x15, 0xf7, 0xc6, 0x85, 0xa2, 0xac, + 0x74, 0x32, 0x21, 0x20, 0x7e, 0x36, 0x7d, 0x83, 0x7d, 0xc5, 0x75, 0xfc, 0x93, 0xfd, 0x4f, 0xcc, 0x8a, 0x56, 0x2b, + 0x75, 0xf4, 0xee, 0xed, 0xe9, 0xab, 0x0f, 0xaf, 0x7e, 0x7d, 0x71, 0xf6, 0xea, 0xcd, 0xcb, 0x57, 0x6f, 0x5e, 0x7d, + 0xf8, 0xe7, 0x03, 0x0c, 0xb6, 0x6f, 0x2b, 0x62, 0xc7, 0xde, 0xbb, 0xc7, 0x78, 0xb5, 0xf8, 0xc2, 0xd9, 0x23, 0x77, + 0x8b, 0x05, 0xd8, 0x04, 0xc3, 0x2d, 0x08, 0xaa, 0x19, 0x8d, 0x4a, 0xdf, 0x13, 0x90, 0xd1, 0xa8, 0x90, 0x8d, 0x87, + 0x15, 0x5b, 0x21, 0x17, 0xef, 0x18, 0x0e, 0x3e, 0xb2, 0xbf, 0x15, 0x67, 0xc2, 0xed, 0x68, 0x6b, 0x56, 0x04, 0x7c, + 0xbe, 0x36, 0xa2, 0xf2, 0xb8, 0x10, 0xb5, 0xb7, 0xed, 0x73, 0x48, 0xa8, 0x47, 0xe4, 0x3a, 0x78, 0xdf, 0x06, 0xd9, + 0xe3, 0x23, 0xef, 0x49, 0x79, 0x86, 0xfa, 0x1c, 0x0d, 0x1f, 0x35, 0x9e, 0xd1, 0x89, 0xb9, 0x36, 0x3a, 0xd4, 0xb3, + 0x02, 0xf6, 0xb7, 0x12, 0x63, 0x43, 0xb4, 0x87, 0x14, 0xb1, 0x3e, 0x9c, 0xee, 0x77, 0xff, 0x66, 0xf4, 0x3d, 0x1c, + 0x3f, 0x4a, 0x35, 0x81, 0xb4, 0x28, 0x50, 0xba, 0x32, 0xe4, 0xb6, 0xe7, 0x61, 0x61, 0x7e, 0x86, 0x0d, 0x02, 0x68, + 0x2f, 0x3b, 0x96, 0x04, 0x9a, 0xc5, 0x6b, 0x5d, 0xff, 0xbc, 0x7c, 0x99, 0x68, 0xe7, 0x8b, 0x6f, 0x21, 0xc4, 0xb0, + 0x7f, 0x45, 0x68, 0x4c, 0xb8, 0x9b, 0x64, 0x77, 0x69, 0x31, 0xf7, 0xaa, 0xab, 0x18, 0x8f, 0xbb, 0x7b, 0xae, 0x14, + 0xcd, 0x5b, 0x17, 0xd8, 0x03, 0x35, 0xaf, 0xe3, 0x25, 0x0b, 0x01, 0x9b, 0xf1, 0xd0, 0x2e, 0x12, 0xe7, 0xf7, 0x4e, + 0x27, 0xe4, 0xf0, 0x68, 0xca, 0x87, 0xac, 0xa4, 0x62, 0xc0, 0xca, 0x7a, 0x8f, 0x9a, 0xf3, 0x36, 0x21, 0x17, 0xfb, + 0x34, 0x5c, 0x0c, 0xf9, 0x43, 0x97, 0xa4, 0x0f, 0xbc, 0xe1, 0x50, 0x6d, 0x9b, 0x8b, 0x21, 0x4d, 0x39, 0xdd, 0xa7, + 0x32, 0x20, 0x44, 0xba, 0x8a, 0x2b, 0x52, 0xeb, 0xa3, 0x2a, 0x75, 0x92, 0x8e, 0xeb, 0x6c, 0xfb, 0x89, 0x4b, 0xb6, + 0xba, 0x5d, 0xfb, 0xd7, 0xea, 0xf6, 0x85, 0x19, 0xc8, 0xdf, 0x1f, 0x88, 0x6a, 0x62, 0x20, 0xba, 0x80, 0x0a, 0xfe, + 0x01, 0x5e, 0x9e, 0x3c, 0xd2, 0x0a, 0xd0, 0xfb, 0xce, 0x8e, 0xae, 0x3d, 0xde, 0x98, 0xc5, 0xd6, 0x12, 0xe7, 0xac, + 0xf2, 0x9d, 0xe5, 0x55, 0xd9, 0x0a, 0x5d, 0x47, 0xb0, 0x9f, 0xc3, 0x8e, 0xbe, 0x7b, 0xdb, 0x00, 0x88, 0x52, 0x58, + 0xb9, 0xb3, 0x5f, 0x78, 0x67, 0xbf, 0xb0, 0x67, 0xbf, 0xdd, 0x04, 0xca, 0x87, 0x15, 0x5a, 0xf6, 0x52, 0x8a, 0xca, + 0x34, 0x79, 0xdc, 0xd4, 0x65, 0x21, 0x2d, 0xe6, 0x87, 0x96, 0x76, 0x3d, 0x19, 0x53, 0x89, 0xea, 0x91, 0x1f, 0xb0, + 0x55, 0x87, 0x25, 0x79, 0xf8, 0x9e, 0xf9, 0x3f, 0x7b, 0x83, 0xbc, 0xef, 0x6e, 0xf7, 0x7f, 0x73, 0xa1, 0x83, 0xdb, + 0x5a, 0x2a, 0x3c, 0x75, 0x75, 0x5c, 0xe0, 0x5d, 0x2d, 0x7d, 0xf8, 0xae, 0xf6, 0x2e, 0xd3, 0xcb, 0xae, 0x02, 0xd4, + 0x20, 0xb1, 0xb9, 0xe2, 0x45, 0x96, 0xd4, 0x56, 0xa1, 0xf1, 0x96, 0x43, 0x68, 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, + 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0xfd, 0x96, 0x87, 0x19, 0x19, 0xf8, 0x12, 0xbf, 0x52, 0xfa, 0xe2, + 0xe2, 0xc3, 0xbd, 0xcc, 0x04, 0xbd, 0x4a, 0x6c, 0x76, 0x29, 0xdb, 0x31, 0x3f, 0xfc, 0x2f, 0x30, 0x1a, 0x84, 0xd7, + 0x96, 0xec, 0x50, 0x74, 0xcc, 0x72, 0x05, 0x47, 0x6d, 0xe9, 0xca, 0x2c, 0x5b, 0xd7, 0xcf, 0x6a, 0x98, 0xe9, 0x33, + 0xe5, 0x2d, 0xc8, 0xbe, 0x90, 0xbb, 0x9f, 0xea, 0x8a, 0x05, 0x99, 0x4d, 0xc6, 0x53, 0x22, 0x06, 0x83, 0x56, 0xf2, + 0x31, 0x26, 0x0f, 0x87, 0x7b, 0xcc, 0xa5, 0xd0, 0xfd, 0xf0, 0xfa, 0x00, 0xf5, 0x35, 0xb6, 0x24, 0xd9, 0x56, 0xec, + 0x4f, 0x30, 0x8b, 0x05, 0xe2, 0xe8, 0xe0, 0x17, 0x17, 0x4b, 0x00, 0x59, 0x86, 0x65, 0xa6, 0x85, 0x45, 0x65, 0xaa, + 0x7c, 0x64, 0x0b, 0x26, 0x8f, 0xc7, 0x73, 0xbf, 0xe7, 0x8e, 0xc1, 0x21, 0x24, 0x9a, 0x58, 0xe3, 0x17, 0x3f, 0x0b, + 0xc6, 0x71, 0x28, 0x67, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, + 0x05, 0x39, 0x2c, 0xe8, 0xca, 0x1f, 0x4b, 0x4c, 0x3f, 0x8c, 0x0f, 0x27, 0x63, 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, + 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x22, 0x87, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, 0xcc, 0xaf, 0x24, 0x19, 0xac, 0x06, + 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xe6, 0x98, 0x4f, 0x89, 0x68, 0xdc, 0x18, 0x36, 0xf4, 0x2a, 0xfe, + 0x43, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0x74, + 0xc6, 0x26, 0xe3, 0x79, 0xca, 0xd2, 0xe3, 0xc9, 0xd3, 0xf9, 0xe4, 0x69, 0x74, 0x34, 0x8e, 0xd2, 0xc1, 0x00, 0x92, + 0x8f, 0xc6, 0xe0, 0x62, 0x07, 0xbf, 0xd9, 0x11, 0x0c, 0xdd, 0x0c, 0x59, 0xc2, 0x02, 0x9a, 0xf6, 0x79, 0x4d, 0xd2, + 0xc3, 0x79, 0xa1, 0x7a, 0x12, 0xdf, 0xd2, 0x8d, 0xe7, 0xe0, 0xe2, 0xb7, 0xf0, 0xc2, 0xb5, 0xf0, 0x62, 0xbf, 0x85, + 0x42, 0x93, 0xed, 0x42, 0xfe, 0xff, 0xb8, 0x61, 0xdc, 0x77, 0x97, 0x30, 0x8b, 0xeb, 0x3a, 0x1b, 0xad, 0x0b, 0x59, + 0x49, 0xb8, 0x4d, 0x28, 0x51, 0xd8, 0x28, 0x5e, 0xaf, 0x73, 0xed, 0x22, 0xb6, 0xa8, 0x28, 0x80, 0xbb, 0x40, 0x9c, + 0x62, 0x60, 0xa1, 0x8d, 0x81, 0xdc, 0x5f, 0xbc, 0x90, 0xcc, 0xaa, 0x7d, 0xcc, 0x3d, 0xf2, 0x8f, 0x10, 0x8c, 0x51, + 0xc5, 0x6c, 0x3c, 0x57, 0x58, 0x17, 0x9f, 0x92, 0xf7, 0xfe, 0x1b, 0x47, 0x91, 0x3d, 0x9a, 0x41, 0x4f, 0x10, 0x39, + 0x8f, 0x38, 0x7b, 0x32, 0x79, 0x19, 0xb8, 0x9f, 0xc1, 0x4a, 0x7f, 0xdd, 0x6d, 0xc6, 0xda, 0xf6, 0xe8, 0x5e, 0x18, + 0xa1, 0xe8, 0x5f, 0xf8, 0xce, 0xd4, 0x0b, 0xb8, 0x84, 0x6a, 0x60, 0x37, 0x97, 0x97, 0xbc, 0x04, 0x10, 0xa1, 0x4c, + 0xf4, 0xfb, 0xbd, 0x3f, 0x0c, 0x34, 0x69, 0xc9, 0x8b, 0xd7, 0x99, 0xb0, 0xce, 0x38, 0xd0, 0x54, 0xa0, 0xfe, 0x1f, + 0x2b, 0xfb, 0x4c, 0xc7, 0x64, 0xee, 0x3f, 0x0e, 0x27, 0x24, 0x6a, 0xbe, 0x26, 0x9f, 0x38, 0x4d, 0x3f, 0x71, 0x45, + 0xfb, 0x0f, 0x64, 0xe6, 0x86, 0x43, 0x86, 0xfa, 0x4b, 0xc7, 0x3c, 0x19, 0xbd, 0x4e, 0xcc, 0x66, 0x82, 0x55, 0x73, + 0x88, 0xc2, 0x5e, 0xc0, 0x83, 0xba, 0x96, 0xc5, 0x53, 0x98, 0x7d, 0x50, 0x23, 0x8a, 0x63, 0x36, 0x9e, 0x87, 0x32, + 0x9c, 0x80, 0x7d, 0xef, 0x64, 0x0c, 0xf7, 0x01, 0x19, 0x7e, 0xac, 0x42, 0xec, 0x1c, 0xa4, 0x7d, 0xac, 0x50, 0x31, + 0x01, 0x10, 0x81, 0x90, 0xb7, 0xdf, 0x97, 0x2a, 0x09, 0x5f, 0x97, 0x98, 0x52, 0xa8, 0x0f, 0xfe, 0x13, 0xa9, 0xba, + 0x63, 0xfa, 0xd5, 0xfa, 0xf1, 0x67, 0x42, 0xf1, 0xe9, 0x2e, 0x25, 0xbe, 0x85, 0xe0, 0xce, 0x12, 0x74, 0x10, 0x15, + 0x9a, 0xb1, 0x3d, 0xcc, 0xef, 0x8a, 0xfb, 0xf9, 0x5d, 0xf1, 0xff, 0x8e, 0xdf, 0x15, 0x0f, 0x31, 0x86, 0x95, 0x85, + 0x86, 0x9f, 0x07, 0xe3, 0x20, 0xfa, 0xcf, 0xf9, 0xc4, 0x7b, 0x79, 0xea, 0xab, 0x4c, 0x4c, 0xef, 0x61, 0x9a, 0x7d, + 0x82, 0x82, 0xb0, 0x8a, 0xfb, 0xf4, 0x64, 0x53, 0xd9, 0x5b, 0x2b, 0x19, 0x62, 0x9e, 0x07, 0x58, 0xa3, 0xb0, 0xf2, + 0x80, 0xee, 0x51, 0xb5, 0x41, 0x9c, 0x08, 0x1e, 0xc6, 0xcc, 0x4a, 0xdf, 0x77, 0x3b, 0xa3, 0xc2, 0x7c, 0x90, 0x8b, + 0x82, 0xec, 0xe6, 0xe3, 0xf9, 0x38, 0x0a, 0xb1, 0x01, 0xff, 0x31, 0x63, 0xd5, 0x90, 0xcd, 0x77, 0x32, 0x52, 0x7b, + 0x26, 0x4f, 0x93, 0x7d, 0xd2, 0x3b, 0xe0, 0x1d, 0xf2, 0xf3, 0xfa, 0x63, 0x58, 0x48, 0xc3, 0x6f, 0xc9, 0xcb, 0xb8, + 0xc8, 0xaa, 0xd5, 0x55, 0x96, 0x20, 0xd3, 0x05, 0x2f, 0x3e, 0x9b, 0xe9, 0xf2, 0x3e, 0xd6, 0x07, 0x8c, 0xa7, 0x14, + 0xaf, 0x1b, 0xa2, 0xf4, 0x4d, 0xcb, 0xb3, 0x42, 0x5d, 0x9e, 0x54, 0xcc, 0xf6, 0xac, 0x04, 0xa7, 0x53, 0x30, 0xc1, + 0xd7, 0x3f, 0x5d, 0xef, 0x63, 0xc0, 0x05, 0x85, 0x9a, 0xd3, 0x42, 0xae, 0x0d, 0x96, 0x93, 0x85, 0xee, 0x04, 0xcc, + 0x50, 0x29, 0xf0, 0x02, 0x05, 0x7f, 0xd1, 0xc0, 0x88, 0xbe, 0x74, 0xbf, 0xc9, 0xc0, 0x20, 0x5d, 0x9a, 0x13, 0x61, + 0xec, 0xb8, 0x9d, 0x22, 0x6d, 0x45, 0x39, 0xe3, 0xec, 0xbd, 0xba, 0x52, 0x80, 0x01, 0xde, 0xf6, 0x26, 0x3a, 0x4f, + 0xd0, 0x6b, 0x41, 0xe9, 0xbc, 0x81, 0xbb, 0x59, 0x45, 0x46, 0xb8, 0xf8, 0xb8, 0xf2, 0x58, 0x70, 0xcf, 0x7e, 0x21, + 0x96, 0x46, 0x33, 0x0d, 0xc6, 0x6c, 0x5e, 0xb0, 0x40, 0xa1, 0x02, 0x05, 0x96, 0x73, 0x6d, 0x69, 0x5a, 0x0d, 0xf9, + 0xe1, 0x11, 0x5a, 0x9b, 0x56, 0x03, 0x7e, 0x78, 0x54, 0x47, 0xd9, 0x31, 0x64, 0x99, 0xf9, 0x19, 0xd4, 0xeb, 0x3a, + 0x32, 0x29, 0x26, 0xbb, 0x5f, 0x5f, 0xea, 0x8f, 0xea, 0x16, 0x5c, 0x3f, 0x00, 0x01, 0x6c, 0x00, 0x0e, 0x81, 0x6a, + 0xb0, 0x34, 0x22, 0x58, 0x94, 0x29, 0xb4, 0xaf, 0xa1, 0xf7, 0x46, 0xc3, 0x7f, 0x81, 0xbb, 0x88, 0x5c, 0xfb, 0x9f, + 0x20, 0xf0, 0x57, 0x94, 0x69, 0x65, 0x8a, 0xff, 0x89, 0x56, 0xaf, 0x50, 0xce, 0x9a, 0xd6, 0x7c, 0x10, 0xad, 0x89, + 0x50, 0xcd, 0x18, 0x82, 0x7f, 0x2b, 0xcb, 0xb4, 0xa5, 0xaa, 0x52, 0x1f, 0x1a, 0xaf, 0xb5, 0xc2, 0x59, 0x3e, 0x8e, + 0xbc, 0xd7, 0x18, 0x3a, 0x36, 0x71, 0x96, 0x72, 0x2a, 0x75, 0xfe, 0xd7, 0xa1, 0x8c, 0x1c, 0xe0, 0x74, 0xc2, 0xc6, + 0xd3, 0xe4, 0x58, 0x4e, 0x13, 0x07, 0x99, 0x9f, 0x33, 0x8c, 0xac, 0x6a, 0x40, 0x58, 0x94, 0x0d, 0xa5, 0x2d, 0xc0, + 0x24, 0x27, 0x84, 0x4c, 0x31, 0x14, 0x45, 0x3e, 0xd2, 0xfd, 0xb0, 0xde, 0xac, 0xee, 0x8b, 0x77, 0x1a, 0xe0, 0x34, + 0x4c, 0x20, 0x10, 0x78, 0x11, 0xdf, 0x64, 0xe2, 0x12, 0x3c, 0x86, 0x07, 0xf0, 0x25, 0xb8, 0xc9, 0xa5, 0xec, 0xb7, + 0x2a, 0xcc, 0x71, 0x6d, 0x01, 0x83, 0x06, 0xab, 0x07, 0xd1, 0xe1, 0x52, 0xda, 0xec, 0x2a, 0x40, 0x6c, 0x4c, 0x21, + 0x96, 0x05, 0xdb, 0x58, 0xf6, 0xec, 0x7b, 0xd5, 0x34, 0xb4, 0x4e, 0x38, 0x11, 0x97, 0x39, 0x44, 0x51, 0x19, 0xc4, + 0xe0, 0x8e, 0xe4, 0xf1, 0x79, 0x8f, 0x44, 0x78, 0x41, 0xc0, 0xad, 0x2c, 0x96, 0xe1, 0x9a, 0xae, 0x46, 0xb7, 0x74, + 0x33, 0xba, 0xa1, 0x63, 0x3a, 0xf9, 0x66, 0x0c, 0x16, 0xd9, 0x3a, 0xf5, 0x8e, 0x6e, 0x46, 0x2b, 0xfa, 0xed, 0x98, + 0x1e, 0xfd, 0x0d, 0x4c, 0xf8, 0xf0, 0x30, 0xa1, 0x17, 0xe0, 0xd8, 0x45, 0x6a, 0xf4, 0xd4, 0xf4, 0x0d, 0x0e, 0xab, + 0x51, 0x3e, 0xe4, 0xa3, 0x9c, 0xf2, 0x51, 0x31, 0xac, 0x46, 0xe0, 0xe9, 0x58, 0x0d, 0xf9, 0xa8, 0xa2, 0x7c, 0x74, + 0x3e, 0xac, 0x46, 0xe7, 0xa4, 0xd9, 0xf4, 0x57, 0x15, 0xbf, 0x2a, 0x59, 0x0a, 0xdb, 0x02, 0x96, 0xaf, 0xe7, 0x15, + 0x95, 0xfa, 0xab, 0xda, 0x9c, 0xcc, 0x96, 0xb3, 0xb7, 0xd7, 0x5d, 0x4e, 0x2c, 0x1e, 0xb7, 0x4d, 0x87, 0xab, 0x2f, + 0x27, 0xea, 0xa4, 0x57, 0xc8, 0x0f, 0xe3, 0xa9, 0x50, 0xe7, 0x10, 0x98, 0x49, 0xcc, 0xc3, 0x98, 0x61, 0x33, 0x75, + 0x1a, 0x28, 0x70, 0xb2, 0x91, 0xe7, 0xa2, 0x98, 0x8d, 0x72, 0x0a, 0xef, 0x63, 0x42, 0x22, 0x01, 0x67, 0xd5, 0xac, + 0x1a, 0x15, 0x10, 0x73, 0x84, 0x85, 0xf8, 0x08, 0xfd, 0x52, 0x1f, 0x79, 0x48, 0xe0, 0x19, 0xf6, 0xb5, 0x18, 0xc4, + 0x70, 0xc4, 0xdb, 0xca, 0xaa, 0x79, 0x98, 0x40, 0x65, 0xd5, 0xb0, 0x34, 0x95, 0x15, 0x34, 0x1b, 0x55, 0x7e, 0x65, + 0x15, 0x8e, 0x51, 0x42, 0x48, 0x54, 0xea, 0xca, 0x40, 0x7d, 0x92, 0xb0, 0xb0, 0xd4, 0x95, 0x9d, 0xab, 0x8f, 0xce, + 0xfd, 0xca, 0xce, 0xc1, 0x85, 0x74, 0x90, 0xf8, 0x57, 0xa9, 0x3c, 0x6d, 0x5f, 0x07, 0x1b, 0xab, 0x8a, 0x6e, 0xf9, + 0x6d, 0x55, 0xc4, 0x51, 0x49, 0x5d, 0x0c, 0x68, 0x5c, 0x18, 0x91, 0xa4, 0x7a, 0x8d, 0x82, 0x3f, 0x24, 0x88, 0x4a, + 0x63, 0xf0, 0xea, 0x4c, 0xba, 0x56, 0x6a, 0x45, 0xc5, 0xa0, 0x1c, 0x14, 0x70, 0x7f, 0xca, 0x5b, 0x0b, 0xe9, 0x7b, + 0x88, 0xa8, 0x0c, 0xe5, 0x0d, 0xfe, 0x81, 0xc1, 0x93, 0xd9, 0x3a, 0x0d, 0x93, 0xd1, 0x1d, 0x8d, 0x47, 0x2b, 0x84, + 0x83, 0x61, 0x9b, 0x54, 0xe1, 0xad, 0x5f, 0x40, 0xfa, 0x2d, 0x8d, 0x47, 0x37, 0x34, 0xb5, 0x36, 0xa7, 0x06, 0xea, + 0xaa, 0x37, 0xa6, 0xb7, 0x11, 0xbc, 0xbe, 0x8b, 0x56, 0x14, 0xb6, 0xd2, 0x49, 0x9e, 0x5d, 0x8a, 0x28, 0xa5, 0x88, + 0x40, 0xb8, 0x41, 0xe4, 0xc0, 0x95, 0x46, 0x1b, 0xdc, 0x0c, 0xa0, 0x0c, 0x0d, 0x17, 0xb8, 0x1a, 0xc4, 0xa3, 0x95, + 0x47, 0xa6, 0x56, 0xfa, 0x22, 0x8b, 0xf0, 0xd1, 0xce, 0x46, 0x4b, 0xf1, 0x8c, 0x58, 0x18, 0x57, 0x30, 0x84, 0xba, + 0xb0, 0xd2, 0x14, 0x24, 0x5d, 0xe0, 0xc8, 0x5e, 0x58, 0x54, 0xe1, 0x16, 0x4c, 0x8b, 0xee, 0xc0, 0x3c, 0x0a, 0x14, + 0x0e, 0x2e, 0x41, 0xfa, 0x09, 0x65, 0x3b, 0x47, 0x69, 0x72, 0x78, 0x13, 0x94, 0xee, 0x4d, 0x10, 0xd2, 0xae, 0x6e, + 0xb2, 0x25, 0x7d, 0x83, 0xed, 0x3d, 0x3a, 0x15, 0x15, 0x54, 0x9f, 0x5b, 0x30, 0x59, 0xb2, 0x41, 0xd8, 0x12, 0xa6, + 0x67, 0x7a, 0x03, 0xd8, 0xd3, 0x87, 0x47, 0x7b, 0xf3, 0x5d, 0xcc, 0xff, 0x3a, 0x2c, 0xa3, 0xb1, 0xb2, 0xe0, 0xcd, + 0x2d, 0xb1, 0x5b, 0xb1, 0xf1, 0x74, 0x75, 0x5c, 0x4e, 0x57, 0x48, 0xec, 0x0c, 0xdd, 0x62, 0x7c, 0xb1, 0x5a, 0xd2, + 0x04, 0xcf, 0x36, 0x56, 0x2d, 0x56, 0x06, 0x2d, 0x25, 0x65, 0xb8, 0xde, 0x56, 0xe8, 0xff, 0xaf, 0x2e, 0x7e, 0x29, + 0xc0, 0x4b, 0x30, 0x16, 0x00, 0xc2, 0x3d, 0x98, 0x16, 0xa4, 0x36, 0xca, 0xc6, 0x2a, 0x0d, 0x53, 0x5c, 0x04, 0x26, + 0xa5, 0xdf, 0x0f, 0x73, 0x96, 0x12, 0x0f, 0x3a, 0xd4, 0x9d, 0xda, 0xa9, 0x2f, 0x04, 0x01, 0x1e, 0x49, 0x9d, 0x63, + 0x93, 0x6f, 0xc6, 0xf3, 0x40, 0x0d, 0x44, 0x10, 0x65, 0xc7, 0xf8, 0x88, 0x81, 0x8b, 0x22, 0x1d, 0xb7, 0xd3, 0x15, + 0x71, 0xb1, 0x7f, 0xcc, 0x42, 0x9c, 0x24, 0xcc, 0x35, 0xcf, 0x86, 0xac, 0x8a, 0x30, 0x41, 0x17, 0x06, 0x66, 0x79, + 0x43, 0x56, 0x1d, 0x1e, 0x41, 0xa4, 0x56, 0x5b, 0xc6, 0xba, 0xab, 0x8c, 0x6f, 0x01, 0xc8, 0x9a, 0x31, 0x76, 0xf4, + 0xb7, 0xf1, 0x5c, 0x7d, 0x13, 0x85, 0x7c, 0x76, 0xf4, 0x37, 0x48, 0x3e, 0xfe, 0x16, 0x99, 0x39, 0x48, 0x6e, 0x14, + 0x74, 0xd9, 0x9c, 0x75, 0x0d, 0xa5, 0x89, 0x6b, 0xaf, 0xd4, 0x6b, 0x4f, 0x9a, 0xb5, 0x57, 0xa0, 0x3b, 0xb5, 0xe1, + 0x3d, 0x94, 0xed, 0x2c, 0x98, 0xa0, 0xa3, 0xd9, 0x1d, 0xe8, 0xe0, 0x9d, 0x22, 0xe8, 0x45, 0x12, 0x1a, 0x8f, 0x50, + 0x65, 0xd4, 0x0b, 0x3b, 0xb2, 0x9b, 0x75, 0xc9, 0x3c, 0x03, 0xe6, 0xd8, 0x9e, 0x43, 0x62, 0x98, 0xab, 0x83, 0x3a, + 0x65, 0xe5, 0x30, 0xc7, 0x03, 0x78, 0xc3, 0xe4, 0x50, 0x0c, 0x72, 0x8d, 0xf2, 0x7d, 0xc1, 0x8a, 0x61, 0x39, 0xc8, + 0x35, 0x37, 0x33, 0x6d, 0xc6, 0xa6, 0x4d, 0x74, 0x78, 0xe6, 0x35, 0x9b, 0xad, 0x7b, 0xc0, 0xc7, 0x82, 0x27, 0xb3, + 0xef, 0xf9, 0xf8, 0x1a, 0x38, 0x99, 0xed, 0x6d, 0xb4, 0xa2, 0x77, 0x51, 0x4a, 0x6f, 0xa2, 0x0d, 0x5d, 0x45, 0x17, + 0xc6, 0xc4, 0x38, 0xa9, 0xe1, 0x1c, 0x80, 0x56, 0x01, 0x24, 0x9e, 0xfa, 0xf5, 0x9e, 0x27, 0x55, 0xb8, 0xa2, 0x29, + 0xb8, 0x0d, 0xfb, 0xf6, 0x99, 0x57, 0xbe, 0x44, 0x6a, 0x8b, 0x18, 0x6b, 0xd6, 0x50, 0x71, 0xeb, 0xad, 0xfb, 0x48, + 0xd4, 0xb0, 0x73, 0x5d, 0x6c, 0xa2, 0x6a, 0x38, 0x99, 0x96, 0x80, 0xd8, 0x5a, 0x0e, 0x87, 0xee, 0x08, 0xd9, 0x3f, + 0x7e, 0x74, 0xa0, 0xe7, 0x9e, 0xb4, 0xd8, 0xb6, 0x2d, 0x7f, 0x60, 0x08, 0x53, 0xfa, 0xe9, 0x23, 0x1f, 0x10, 0x2b, + 0x2e, 0xe1, 0x6c, 0x04, 0xea, 0x68, 0x85, 0x4e, 0xbf, 0x55, 0x61, 0xa1, 0x0f, 0xf0, 0xed, 0x6d, 0x94, 0xd0, 0xbb, + 0x28, 0xf7, 0xc8, 0xda, 0xaa, 0x66, 0x72, 0x7a, 0x96, 0x85, 0xbc, 0x7d, 0xa0, 0x97, 0x4b, 0x00, 0xd1, 0x1a, 0xc4, + 0xbe, 0xd4, 0xf5, 0x08, 0x9c, 0x86, 0xd0, 0x24, 0x34, 0x82, 0xab, 0x0a, 0xc2, 0x08, 0xb8, 0x92, 0xf0, 0x37, 0x98, + 0xa8, 0xc0, 0x17, 0xe0, 0x22, 0x93, 0xa6, 0x39, 0x0f, 0x6a, 0x7f, 0x24, 0x4f, 0x8b, 0xb6, 0xb7, 0x2b, 0x8c, 0x26, + 0x18, 0x7b, 0xa2, 0x7d, 0x1e, 0x29, 0x47, 0x71, 0x91, 0x84, 0xd9, 0xe8, 0x56, 0x9d, 0xe7, 0x34, 0x1b, 0xdd, 0xe9, + 0x5f, 0x15, 0x1d, 0xd3, 0xef, 0x74, 0x40, 0x1b, 0x25, 0x7d, 0xeb, 0x38, 0x1b, 0xd0, 0x7a, 0xb1, 0x34, 0xfe, 0xd7, + 0x72, 0x74, 0x4b, 0xe5, 0xe8, 0xce, 0xb7, 0xa4, 0x9a, 0x4c, 0x8b, 0x63, 0x81, 0x86, 0x54, 0x9d, 0xdf, 0x17, 0xc0, + 0xcf, 0x95, 0xc6, 0x77, 0xda, 0x7c, 0xef, 0xb5, 0xff, 0xbc, 0x93, 0x27, 0x50, 0x2c, 0x51, 0xc1, 0xaa, 0x11, 0xd8, + 0xb1, 0x6f, 0xf2, 0xb8, 0x30, 0xa3, 0x14, 0x53, 0x6b, 0xd2, 0x8f, 0x81, 0x2b, 0xa6, 0xbd, 0x02, 0x5c, 0x2d, 0x77, + 0x3b, 0x15, 0x43, 0x13, 0xf6, 0xec, 0x18, 0xa2, 0x9e, 0x1b, 0xc7, 0x28, 0xd9, 0x70, 0x0f, 0x88, 0xb5, 0xcc, 0x5b, + 0xb9, 0x04, 0x24, 0xf0, 0xd6, 0xc3, 0xa4, 0x00, 0x8c, 0xc1, 0x72, 0x45, 0x74, 0x1e, 0x0f, 0x7d, 0x42, 0xbd, 0xd0, + 0xa8, 0x13, 0xb2, 0xb1, 0x25, 0x70, 0xfc, 0x61, 0x7d, 0x08, 0x04, 0xaf, 0xf2, 0x5c, 0x7f, 0xa5, 0x75, 0xfd, 0xa5, + 0xd2, 0x73, 0xc7, 0x72, 0x5d, 0x3f, 0x6b, 0x53, 0xa3, 0x97, 0x60, 0xe1, 0xbb, 0x55, 0xe6, 0x91, 0xdc, 0x22, 0xa4, + 0x2a, 0xb0, 0x52, 0xb7, 0x90, 0x60, 0xfe, 0x95, 0x9c, 0xad, 0xca, 0x7c, 0xf5, 0xc8, 0x83, 0x72, 0x36, 0x3d, 0xfd, + 0x0d, 0x09, 0xda, 0x5d, 0x47, 0x9a, 0xc7, 0x5b, 0x74, 0xf8, 0xec, 0x5a, 0x4b, 0xcc, 0xbd, 0x44, 0xc5, 0xf3, 0x29, + 0x60, 0xab, 0xe7, 0xd9, 0x95, 0xf2, 0xb1, 0xda, 0xc7, 0xf1, 0x33, 0xe7, 0x4f, 0x5c, 0x85, 0x1b, 0xd1, 0x50, 0x82, + 0x80, 0x37, 0x87, 0xb1, 0x2b, 0x54, 0x01, 0x0d, 0xcd, 0x0d, 0x1c, 0xe7, 0x6a, 0x58, 0x69, 0x02, 0xa6, 0xa5, 0x3c, + 0x3a, 0xc0, 0xa1, 0xc9, 0xa3, 0x76, 0xd3, 0xb0, 0x32, 0x74, 0xad, 0xd1, 0xe7, 0xb6, 0xd2, 0x19, 0x6f, 0x36, 0xfc, + 0xf0, 0x68, 0x50, 0xe1, 0x4f, 0xd2, 0x1c, 0x8d, 0x76, 0x6e, 0xb8, 0xd3, 0x08, 0xcc, 0x5c, 0xc9, 0x35, 0xd9, 0x1f, + 0x25, 0x2f, 0xbf, 0xa7, 0x17, 0x16, 0xd0, 0x9f, 0xff, 0x5c, 0x4c, 0x38, 0x69, 0x89, 0x09, 0xd1, 0xd2, 0x41, 0x8b, + 0x0e, 0xf6, 0x94, 0x57, 0xf6, 0x25, 0x5e, 0x3a, 0xc7, 0xff, 0xbe, 0x1e, 0x6b, 0x5f, 0x81, 0xd0, 0xea, 0xe4, 0x61, + 0x7b, 0xb2, 0x40, 0xd4, 0x80, 0x6a, 0x76, 0x55, 0x8e, 0x32, 0xed, 0xac, 0xc8, 0xb6, 0x21, 0x73, 0xdd, 0xcf, 0xd2, + 0xb0, 0x99, 0xec, 0x58, 0x58, 0x66, 0x18, 0xac, 0x9d, 0x2a, 0xfa, 0x1c, 0xb4, 0xfc, 0x08, 0x9e, 0x37, 0x95, 0x67, + 0x3e, 0x9b, 0x65, 0xc4, 0x0b, 0x74, 0xc1, 0xa9, 0x58, 0x36, 0xa5, 0x63, 0xe5, 0x6e, 0x57, 0xa2, 0xb1, 0x44, 0x19, + 0x05, 0x41, 0x6d, 0x83, 0xb0, 0xeb, 0xd2, 0x3d, 0xe9, 0xd3, 0x3e, 0x3e, 0xad, 0x40, 0xdf, 0xe3, 0xfb, 0x0c, 0x24, + 0xa6, 0x9e, 0xe4, 0xa1, 0x6a, 0x34, 0x47, 0x27, 0xcf, 0xe3, 0x54, 0xe3, 0xf3, 0x2b, 0xd9, 0x59, 0xf3, 0x6e, 0x35, + 0xa6, 0xf8, 0x8f, 0xd4, 0xed, 0x3b, 0x97, 0xa1, 0x89, 0xfe, 0x5a, 0x1e, 0xb4, 0x14, 0x16, 0x1c, 0xb7, 0x8d, 0xbf, + 0x7e, 0x9b, 0x39, 0xc4, 0xb0, 0x74, 0x39, 0xbc, 0x09, 0x1d, 0xba, 0xbb, 0xca, 0xde, 0x5c, 0x1f, 0x51, 0xa7, 0x2e, + 0xd6, 0x6d, 0x40, 0xc9, 0x92, 0x77, 0xeb, 0xf4, 0xc4, 0x4a, 0xdf, 0x1d, 0x86, 0x7b, 0xf3, 0xa8, 0xd9, 0xdd, 0xdd, + 0x6e, 0x42, 0xda, 0xf6, 0xc1, 0x78, 0x5f, 0xc2, 0x42, 0x9c, 0x77, 0xd8, 0xc1, 0xf7, 0x61, 0xf5, 0x98, 0x0f, 0x7e, + 0xc6, 0x71, 0x86, 0xd1, 0xcf, 0x94, 0xa1, 0xcf, 0xcb, 0x42, 0x5e, 0xa9, 0x4e, 0xf9, 0x42, 0xb7, 0x96, 0xa9, 0xf7, + 0x9b, 0xf8, 0x4d, 0x2b, 0x40, 0x8c, 0xd7, 0x15, 0x2b, 0xc5, 0x1b, 0x5a, 0x61, 0x5c, 0x03, 0xb7, 0xc9, 0xa1, 0x96, + 0x6a, 0x81, 0xa8, 0xcb, 0x4f, 0x1e, 0xf3, 0xc8, 0xa8, 0x33, 0xe1, 0xbb, 0xc7, 0xdc, 0x97, 0xae, 0xed, 0x37, 0xf1, + 0x53, 0x4d, 0x3b, 0xdc, 0x1f, 0xe8, 0x8e, 0xd6, 0x3d, 0xdc, 0x3c, 0x9b, 0x9f, 0x47, 0xe6, 0x8b, 0x01, 0x36, 0x6b, + 0x9f, 0x71, 0xd9, 0x33, 0xdc, 0xf7, 0xa6, 0x07, 0x63, 0x01, 0x81, 0xc4, 0x0c, 0xbd, 0x0c, 0x5c, 0xe0, 0x02, 0x77, + 0x85, 0x01, 0x43, 0x5c, 0xd3, 0x92, 0x33, 0x6d, 0x65, 0xeb, 0x23, 0x6f, 0xa3, 0x42, 0xb0, 0xae, 0x3b, 0x6e, 0x92, + 0x1c, 0x82, 0x13, 0xb6, 0xdc, 0xfb, 0xda, 0x6b, 0x67, 0xf8, 0x8f, 0x81, 0x70, 0x6e, 0x89, 0x9e, 0x51, 0xdb, 0x63, + 0xad, 0xee, 0x35, 0xbc, 0xca, 0x5d, 0xe4, 0x59, 0xbf, 0x99, 0x97, 0x86, 0x7d, 0xc1, 0x6b, 0x29, 0x38, 0x34, 0xb6, + 0x5b, 0xe1, 0x16, 0x8b, 0x77, 0xb4, 0x5a, 0x59, 0x6b, 0xab, 0xbd, 0x56, 0x2a, 0x7a, 0xff, 0x9a, 0xe3, 0xc4, 0x59, + 0x0a, 0xdb, 0x0f, 0x1f, 0x2e, 0xd8, 0x35, 0x01, 0x0c, 0x5a, 0x4c, 0x16, 0x28, 0x41, 0x25, 0x6b, 0x55, 0xbb, 0x9d, + 0x12, 0xbf, 0xdc, 0xcf, 0xba, 0xcc, 0x76, 0x1e, 0xbf, 0x6e, 0xd2, 0x3e, 0xf1, 0x39, 0xfa, 0x61, 0x7e, 0x67, 0x9d, + 0x94, 0x9c, 0x61, 0x5c, 0xcb, 0xff, 0xaf, 0xa2, 0x97, 0x45, 0x96, 0x46, 0x5b, 0xc3, 0x83, 0xd9, 0x50, 0x9b, 0x3e, + 0x34, 0x46, 0xe5, 0x96, 0x8d, 0x22, 0xa2, 0xd5, 0x2d, 0x08, 0x66, 0x14, 0xf7, 0x25, 0xda, 0xbc, 0x52, 0x65, 0xe1, + 0x1d, 0x3e, 0xb1, 0xd1, 0x1b, 0xb6, 0x27, 0x84, 0xf2, 0xfd, 0xd3, 0xc2, 0xac, 0x5a, 0x2a, 0x1a, 0x6c, 0x97, 0xf0, + 0x2e, 0x46, 0x95, 0x7e, 0xc2, 0x64, 0xcb, 0x82, 0xa9, 0xfe, 0x7f, 0x5f, 0x64, 0x69, 0x9b, 0xa2, 0x03, 0xd3, 0xd9, + 0xf4, 0xe9, 0xa4, 0x5b, 0x5c, 0x67, 0xc0, 0x22, 0x82, 0x2d, 0x15, 0x8e, 0x47, 0xa9, 0xdd, 0x20, 0x61, 0x22, 0xb8, + 0x89, 0x7a, 0xd9, 0xd1, 0x32, 0x25, 0xab, 0x02, 0x9e, 0x5f, 0xb9, 0xca, 0x74, 0x1c, 0x0d, 0xfd, 0xfe, 0x55, 0x6a, + 0x42, 0xbf, 0x52, 0x2f, 0x55, 0x71, 0x1e, 0x46, 0xd5, 0xa1, 0xc2, 0x18, 0xad, 0x68, 0x0a, 0xc7, 0x60, 0x76, 0x11, + 0xa6, 0x78, 0x39, 0xdb, 0x26, 0xec, 0x33, 0x06, 0x72, 0xa5, 0x0d, 0xea, 0x35, 0x25, 0xda, 0xb0, 0xf6, 0x66, 0x4e, + 0x09, 0xbd, 0x60, 0xa5, 0x7f, 0x17, 0xda, 0x80, 0x40, 0x51, 0x36, 0x53, 0xa6, 0xe7, 0xba, 0x9d, 0x17, 0x34, 0xa1, + 0x05, 0x5d, 0x93, 0x1a, 0xf4, 0xbd, 0x4e, 0xce, 0x8e, 0x4e, 0x76, 0x66, 0xd6, 0x63, 0x56, 0x0c, 0x27, 0xd3, 0x18, + 0xae, 0x69, 0xb1, 0xbb, 0xa6, 0xad, 0x9a, 0x37, 0xae, 0xc6, 0xc6, 0x69, 0xd0, 0x2e, 0x90, 0xb6, 0x69, 0x6e, 0x3f, + 0xf5, 0xb8, 0xfd, 0x4d, 0xcd, 0x56, 0xd3, 0xde, 0x66, 0xb7, 0xeb, 0xa5, 0x60, 0x23, 0xea, 0xf1, 0xf1, 0x1b, 0x25, + 0x5d, 0xb7, 0x5c, 0x7e, 0x0a, 0xcf, 0x1e, 0x5f, 0xbf, 0xf2, 0xc1, 0xe5, 0x68, 0xd5, 0xe6, 0xee, 0x57, 0xfb, 0xc8, + 0x72, 0x9f, 0x35, 0xb4, 0x5c, 0xcf, 0x50, 0x93, 0x3c, 0x1b, 0xed, 0x1d, 0x6a, 0xc1, 0x72, 0xd6, 0x4d, 0x78, 0x62, + 0xb0, 0x63, 0xaf, 0x1a, 0x9b, 0xa3, 0x32, 0x97, 0xac, 0x06, 0x09, 0xf4, 0x49, 0x9e, 0x69, 0xfa, 0x07, 0x19, 0xe6, + 0xa3, 0x5b, 0x9a, 0x03, 0xae, 0x58, 0x65, 0x2f, 0x19, 0xa4, 0xae, 0xda, 0x4b, 0x5c, 0xf9, 0x0a, 0x87, 0x64, 0x8b, + 0x4f, 0x86, 0xa9, 0xfa, 0xe4, 0x92, 0x07, 0xff, 0x6f, 0xab, 0x56, 0xe9, 0xb9, 0x49, 0x6e, 0x38, 0xfe, 0x75, 0xd2, + 0xf6, 0x31, 0x31, 0x48, 0xc0, 0x53, 0xbb, 0x18, 0xaa, 0x51, 0x55, 0xc4, 0xa2, 0xcc, 0x4d, 0xcc, 0xb1, 0x7b, 0xbb, + 0x86, 0x0e, 0xca, 0xe0, 0xd7, 0x0d, 0x9f, 0x98, 0x3b, 0xb0, 0x15, 0xe8, 0xe8, 0x44, 0x73, 0x19, 0x66, 0xe6, 0x32, + 0x4c, 0xbb, 0xb6, 0x0a, 0x0c, 0xaf, 0xda, 0x2a, 0x89, 0x72, 0x35, 0xea, 0x71, 0x33, 0x4b, 0xcd, 0x5e, 0xe4, 0xdd, + 0x6b, 0xd2, 0x93, 0xf8, 0xd3, 0x95, 0x27, 0xaf, 0x87, 0x01, 0x91, 0x9f, 0xb3, 0x34, 0x5c, 0xa3, 0x20, 0x38, 0xb5, + 0xda, 0x81, 0x34, 0x1f, 0x01, 0x32, 0x3f, 0x4e, 0xc3, 0x77, 0x5a, 0x9c, 0x43, 0xb6, 0x4a, 0xe3, 0xc4, 0x56, 0x46, + 0x3d, 0x04, 0x77, 0xde, 0x2b, 0x1e, 0x43, 0xe0, 0xc3, 0x0f, 0xb8, 0x19, 0x54, 0x74, 0x5b, 0x62, 0xa2, 0xb4, 0x79, + 0xd4, 0x2d, 0x1f, 0x35, 0x84, 0x4a, 0x56, 0x86, 0x17, 0x43, 0x7b, 0xf7, 0x04, 0x46, 0x95, 0x13, 0xc8, 0x0c, 0x8b, + 0xc3, 0xa3, 0x61, 0xaa, 0x04, 0x45, 0x43, 0x39, 0x5c, 0xa1, 0x1c, 0x10, 0x93, 0x40, 0x60, 0x54, 0x0c, 0x52, 0x5d, + 0x99, 0x7a, 0x31, 0x48, 0xf5, 0xad, 0x8a, 0xd4, 0x67, 0x59, 0x58, 0x51, 0xdd, 0x22, 0x3a, 0xa6, 0x43, 0x49, 0x57, + 0x66, 0xa7, 0xe6, 0x5a, 0x7a, 0xa1, 0x96, 0xe3, 0x33, 0x9d, 0x06, 0xa3, 0x78, 0xea, 0x52, 0xf4, 0x5b, 0xb5, 0x9f, + 0xfd, 0xb7, 0x98, 0x52, 0x23, 0x36, 0xb5, 0xb7, 0x88, 0x61, 0xd5, 0x7e, 0xc8, 0xaa, 0x1c, 0xb4, 0xbb, 0xa0, 0x6c, + 0xac, 0x8c, 0xf3, 0x7c, 0x23, 0x98, 0x39, 0x68, 0x1b, 0xab, 0xa6, 0x0f, 0xbd, 0x11, 0xa3, 0xf6, 0xc6, 0x54, 0xe3, + 0x9e, 0xc0, 0x4f, 0x1b, 0x34, 0xdd, 0x8b, 0x3c, 0x47, 0x3d, 0xf2, 0xee, 0x7f, 0xe6, 0xc8, 0xce, 0xe4, 0x93, 0x58, + 0x26, 0x75, 0xfb, 0x98, 0x04, 0x0b, 0x55, 0xc7, 0xe8, 0xc2, 0x8d, 0x4c, 0x69, 0x3f, 0xf7, 0xa6, 0x1f, 0xf1, 0x4c, + 0x1e, 0xb6, 0x43, 0xa3, 0xbe, 0x34, 0xac, 0x25, 0x45, 0xd4, 0x17, 0xf4, 0xd6, 0x54, 0x47, 0x47, 0xd4, 0xeb, 0x08, + 0xac, 0xae, 0x68, 0x8b, 0x1a, 0x80, 0xc9, 0xb8, 0xb6, 0xb5, 0xf9, 0x1c, 0x4c, 0x6d, 0x55, 0x05, 0x4f, 0xe9, 0xbe, + 0x50, 0xba, 0x37, 0xa9, 0xeb, 0xd6, 0x10, 0x5b, 0xc0, 0x80, 0xc0, 0x8d, 0x9e, 0x9a, 0xfe, 0xa0, 0x89, 0x0a, 0x40, + 0x83, 0xc6, 0xed, 0x4c, 0xe7, 0x48, 0xf4, 0x3b, 0xb5, 0x69, 0x9b, 0xa9, 0x5e, 0x55, 0x3e, 0x80, 0x8a, 0x3f, 0x4b, + 0x67, 0x17, 0x66, 0xc4, 0x02, 0x18, 0xf7, 0xc0, 0x99, 0xea, 0x9d, 0x64, 0x60, 0x3d, 0x91, 0xe7, 0x59, 0xc9, 0x13, + 0x29, 0x60, 0x46, 0xe4, 0xd5, 0x95, 0x14, 0x30, 0x0c, 0x6a, 0x00, 0xd0, 0xa2, 0xb9, 0x8c, 0x26, 0xfc, 0xab, 0x9a, + 0xde, 0x97, 0x87, 0x7f, 0xa5, 0x73, 0x7d, 0x3d, 0xae, 0xc1, 0x50, 0x79, 0x53, 0xf1, 0xbd, 0x4c, 0x5f, 0xf3, 0x27, + 0x5e, 0xa6, 0x95, 0xdc, 0x14, 0x7b, 0x59, 0xbe, 0xfa, 0x9a, 0x3f, 0xd5, 0x79, 0x8e, 0x9e, 0xd4, 0x34, 0x8d, 0xef, + 0xf6, 0xb2, 0x7c, 0xf3, 0xf5, 0x13, 0x9b, 0xe7, 0xab, 0x71, 0x4d, 0x6f, 0x38, 0xff, 0xe8, 0x32, 0x4d, 0x74, 0x55, + 0xe3, 0x27, 0xdf, 0xd8, 0x5c, 0x4f, 0x6a, 0x7a, 0x25, 0x45, 0xb5, 0xda, 0x2b, 0xea, 0xe8, 0xeb, 0xa3, 0x6f, 0xf8, + 0xd7, 0xa6, 0x7b, 0x47, 0x35, 0xfd, 0x73, 0x13, 0x17, 0x15, 0x2f, 0xf6, 0x8a, 0xfb, 0xdb, 0x37, 0xdf, 0x3c, 0xb1, + 0x19, 0x9f, 0xd4, 0xf4, 0x8e, 0xc7, 0x1d, 0x6d, 0x9f, 0x3c, 0x7d, 0xc2, 0xff, 0x56, 0xd7, 0xf4, 0x17, 0xe6, 0x07, + 0x47, 0x3d, 0xc9, 0x3c, 0x3d, 0x7c, 0x22, 0x9b, 0xa8, 0x01, 0x43, 0x0f, 0x0d, 0x20, 0x97, 0x56, 0x4d, 0x73, 0x8f, + 0x57, 0x2e, 0xb8, 0x7d, 0x9f, 0xc5, 0x69, 0xbc, 0x86, 0x83, 0x60, 0x8b, 0xc6, 0x59, 0x05, 0x70, 0xaa, 0xc0, 0x7b, + 0x46, 0x25, 0xcd, 0x4a, 0xf9, 0x0f, 0xce, 0x3f, 0xc2, 0xa0, 0x21, 0xa4, 0x8d, 0x8a, 0x0c, 0xf4, 0x76, 0xad, 0x23, + 0x1b, 0xa1, 0xff, 0x66, 0x33, 0x0e, 0x8e, 0x0f, 0xa3, 0xd7, 0xef, 0x87, 0x05, 0x13, 0x61, 0x41, 0x08, 0xfd, 0x23, + 0x2c, 0xc0, 0xa1, 0xa4, 0x60, 0x5e, 0x3e, 0xe3, 0x7b, 0xae, 0x8d, 0xc2, 0x42, 0x10, 0xdd, 0x45, 0xf6, 0x01, 0x55, + 0x8f, 0xbe, 0x43, 0x37, 0xc4, 0xcb, 0x0a, 0x0b, 0x86, 0x56, 0x35, 0x30, 0x43, 0x50, 0xfc, 0x6b, 0x1e, 0x4a, 0xf0, + 0x89, 0x07, 0xf8, 0xe8, 0x31, 0x99, 0x73, 0x75, 0xad, 0x7d, 0x7b, 0x11, 0x16, 0x34, 0xd0, 0x6d, 0x87, 0xa0, 0x03, + 0x91, 0xff, 0x02, 0x3c, 0x05, 0x06, 0x3e, 0x2c, 0xec, 0x4a, 0xee, 0xfb, 0xab, 0xff, 0x62, 0x58, 0x47, 0x17, 0x7e, + 0xf4, 0x17, 0xeb, 0xc2, 0x9e, 0x91, 0xa9, 0x3c, 0x2e, 0x87, 0x93, 0xe9, 0x60, 0x20, 0x5d, 0x1c, 0xb7, 0x93, 0x6c, + 0xf1, 0xcb, 0x42, 0x2e, 0x97, 0xa8, 0xfb, 0xc6, 0x79, 0x9d, 0xeb, 0xbf, 0x91, 0x76, 0x3e, 0x78, 0x7d, 0xf2, 0xdb, + 0xd9, 0xe9, 0xc9, 0x4b, 0x70, 0x3e, 0xf8, 0xf0, 0xe2, 0xfb, 0x17, 0xef, 0x55, 0x70, 0x77, 0x35, 0xe7, 0xfd, 0xbe, + 0x93, 0xfa, 0x84, 0x7c, 0x58, 0x91, 0xc3, 0x30, 0x7e, 0x5c, 0x28, 0xa3, 0x07, 0x72, 0xcc, 0x2c, 0x14, 0x32, 0x54, + 0x51, 0xdb, 0xdf, 0xe5, 0x70, 0xe2, 0x81, 0x59, 0xdc, 0x35, 0x44, 0xb8, 0x7e, 0xcb, 0x6d, 0x90, 0x35, 0x39, 0xf3, + 0xfa, 0xc1, 0xc9, 0x54, 0x3a, 0xb6, 0xb0, 0x60, 0x50, 0x36, 0xb4, 0xe9, 0x24, 0x5b, 0x14, 0x4b, 0xdb, 0x2e, 0xb7, + 0x40, 0x46, 0x69, 0x76, 0x71, 0x11, 0x2a, 0xe8, 0xea, 0x19, 0x68, 0x00, 0x4c, 0xa3, 0x0a, 0xd7, 0x22, 0x3e, 0xf7, + 0xcb, 0x8f, 0xc6, 0x5e, 0xf3, 0x6e, 0x51, 0xf7, 0x64, 0x9a, 0x55, 0x35, 0x06, 0x74, 0x30, 0xa1, 0xdc, 0x0d, 0xba, + 0x09, 0x26, 0xa3, 0xda, 0xf2, 0xcb, 0xa2, 0x5a, 0x9a, 0xe6, 0xb8, 0x61, 0xa8, 0xbc, 0x92, 0x37, 0xb2, 0x81, 0xc8, + 0x40, 0x32, 0x0c, 0x7b, 0x34, 0x46, 0x91, 0xfa, 0xc1, 0xbe, 0x77, 0xfc, 0x36, 0x97, 0x10, 0x4d, 0x31, 0x03, 0xe9, + 0xfc, 0x89, 0x50, 0xce, 0xe5, 0x92, 0xf1, 0x85, 0x58, 0xce, 0xc0, 0xed, 0x7c, 0x21, 0x96, 0x11, 0x06, 0xe5, 0xcb, + 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, + 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x5a, 0x54, 0x6d, 0x4f, 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, + 0x39, 0x8d, 0x8f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x11, + 0x2f, 0x69, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, + 0xcf, 0x70, 0x19, 0x15, 0xa1, 0x5b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, + 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x22, 0x5e, 0xb2, 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, + 0xd4, 0x73, 0x58, 0x6a, 0x07, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x2e, 0xa2, 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, + 0x2e, 0x7e, 0xf3, 0xf9, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4d, 0xb4, 0xb3, 0x5c, 0x1d, 0x7a, 0x8b, 0x25, 0x8d, + 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, + 0x40, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, 0x91, 0x9e, 0x67, 0x7f, 0x35, 0x31, 0xd6, + 0x34, 0x35, 0x33, 0xf1, 0x36, 0x14, 0xa2, 0x41, 0x0b, 0xa2, 0x19, 0xbc, 0x7f, 0xae, 0x38, 0x5e, 0x75, 0xe0, 0x07, + 0xbc, 0x73, 0x71, 0xe6, 0xd5, 0xcc, 0x23, 0x72, 0xea, 0xa3, 0x1c, 0xd1, 0x2f, 0x79, 0x58, 0x8d, 0x74, 0x32, 0xc6, + 0x4a, 0xe2, 0xa0, 0xb7, 0xc1, 0x82, 0x39, 0xa1, 0x6b, 0x1e, 0x5a, 0x3e, 0xfe, 0x25, 0x32, 0x19, 0x25, 0x35, 0x56, + 0x74, 0xa5, 0xc5, 0x88, 0xf3, 0x1a, 0x66, 0x69, 0xb2, 0xa2, 0x8b, 0x85, 0x26, 0xcd, 0x42, 0x99, 0x06, 0xf8, 0x04, + 0x5a, 0x8c, 0xdc, 0x43, 0x4d, 0x1b, 0x08, 0x0d, 0xfb, 0x43, 0xc0, 0x47, 0xee, 0xa1, 0xc3, 0xff, 0xcf, 0xb3, 0x0b, + 0x44, 0xda, 0x9b, 0x9b, 0xc8, 0x78, 0xa4, 0x6e, 0xe0, 0xa0, 0x18, 0x1f, 0xfb, 0x66, 0xe2, 0x67, 0xce, 0xe8, 0x43, + 0x52, 0xf9, 0x0e, 0x1f, 0x2c, 0x7f, 0xbc, 0xa9, 0x99, 0x95, 0x11, 0xac, 0x87, 0xdd, 0x0e, 0x17, 0x44, 0xdb, 0x05, + 0x90, 0x7a, 0xc6, 0xab, 0x85, 0x6f, 0xbc, 0x1a, 0xdf, 0x63, 0xbc, 0xea, 0xce, 0xd4, 0x30, 0x27, 0x5b, 0xd4, 0x67, + 0x29, 0x79, 0x7e, 0x8e, 0x32, 0xc1, 0xa6, 0xcb, 0x59, 0x49, 0x55, 0x2a, 0xa1, 0xbd, 0xd8, 0xcf, 0x18, 0xdf, 0x12, + 0x8c, 0xb3, 0xe2, 0x30, 0x12, 0xa8, 0x4a, 0x25, 0x75, 0xd8, 0x2b, 0x40, 0x3d, 0x06, 0xef, 0x0d, 0x86, 0xa8, 0x91, + 0xb1, 0x9b, 0x36, 0x10, 0x1a, 0x1a, 0xeb, 0xd1, 0x9e, 0xb5, 0x1e, 0xdd, 0xed, 0x2a, 0xe3, 0x6f, 0x27, 0x37, 0x45, + 0x82, 0xa8, 0xc2, 0x6a, 0x34, 0x01, 0xde, 0x34, 0xb1, 0xb7, 0x25, 0xa7, 0xb4, 0xc0, 0xf0, 0xd9, 0x7f, 0x84, 0xa5, + 0x53, 0x49, 0x94, 0x64, 0x5e, 0x46, 0x03, 0x77, 0x0e, 0x3e, 0x8f, 0x2b, 0x58, 0x03, 0x10, 0xc9, 0x11, 0x3d, 0x5c, + 0xff, 0x08, 0xa5, 0xcb, 0x2c, 0xc9, 0x5c, 0x42, 0x66, 0x2e, 0xd2, 0x76, 0xd6, 0xc1, 0xc4, 0x99, 0xd4, 0x7a, 0x63, + 0x21, 0x87, 0x06, 0xf9, 0x01, 0x94, 0x21, 0x0e, 0x9f, 0x7c, 0x30, 0xa1, 0x52, 0x85, 0x52, 0x6d, 0x74, 0xb3, 0x1b, + 0x78, 0xe5, 0x43, 0x76, 0xc5, 0xcb, 0x2a, 0xbe, 0x5a, 0x1b, 0x4b, 0x62, 0xce, 0xee, 0x73, 0xdb, 0xa3, 0xc2, 0xbc, + 0x7a, 0xf3, 0xe2, 0xfb, 0x93, 0xc6, 0xab, 0x7d, 0xc4, 0xd1, 0x10, 0x6c, 0x2b, 0xc6, 0x18, 0xbd, 0xc5, 0xa7, 0xc1, + 0x44, 0xb9, 0x46, 0xa0, 0x77, 0x29, 0xe8, 0xb7, 0x3f, 0xd7, 0x13, 0xf0, 0x8a, 0xeb, 0xe5, 0x97, 0x7c, 0x04, 0x2c, + 0x51, 0xa1, 0x67, 0x85, 0xb9, 0x59, 0x99, 0xdf, 0xdb, 0xad, 0xc8, 0x4c, 0xbb, 0xd2, 0xc8, 0x40, 0xbc, 0xda, 0x0e, + 0x63, 0xe1, 0xd2, 0x35, 0xdd, 0x0e, 0x76, 0xb5, 0xf2, 0x2c, 0x91, 0x77, 0xbb, 0x12, 0x3a, 0x64, 0x07, 0xdc, 0x7b, + 0x19, 0xdf, 0xc2, 0xcb, 0xd2, 0xeb, 0x66, 0x33, 0x78, 0x02, 0x98, 0x09, 0x17, 0xce, 0xb2, 0x38, 0x66, 0x3c, 0x09, + 0x55, 0x6c, 0xae, 0x86, 0xc8, 0x5b, 0x11, 0x5a, 0xb3, 0xbf, 0x42, 0x31, 0x02, 0xbb, 0x93, 0xd3, 0x8f, 0xd9, 0x7a, + 0xbe, 0x02, 0xd4, 0xfc, 0xab, 0x4c, 0x00, 0xcd, 0xb5, 0x6b, 0xc1, 0x36, 0x85, 0x36, 0xd7, 0xf5, 0xb3, 0x78, 0x1d, + 0x27, 0xa0, 0xba, 0x01, 0x6f, 0x91, 0x3b, 0x2d, 0xba, 0x32, 0xe8, 0xa2, 0xf4, 0x81, 0x72, 0x2c, 0x29, 0x74, 0xf4, + 0xbd, 0x27, 0xd4, 0xb9, 0x67, 0x00, 0x97, 0x34, 0x6a, 0x9e, 0x6a, 0x29, 0x63, 0x01, 0xb0, 0xd0, 0xc1, 0x5c, 0x91, + 0xad, 0xe8, 0xd6, 0x60, 0x52, 0xc0, 0x5b, 0x03, 0xfc, 0x21, 0xb2, 0x4a, 0xdd, 0x15, 0xcb, 0xb0, 0xf4, 0xec, 0xaf, + 0xfb, 0xfd, 0xd8, 0xb3, 0xbf, 0xbe, 0xd0, 0xb4, 0x2e, 0x6e, 0x37, 0x80, 0xd4, 0x18, 0x40, 0xe4, 0x44, 0x0f, 0x84, + 0x89, 0x28, 0xd6, 0xf4, 0xfd, 0x3b, 0x31, 0x59, 0x14, 0x08, 0xfd, 0x5e, 0xbd, 0x9e, 0x94, 0x04, 0x74, 0x6a, 0x15, + 0x9b, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xc5, 0x52, 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, + 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x62, 0xbc, + 0x44, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, 0xfb, 0xbf, 0x99, 0x2c, 0x09, 0x6a, 0xae, + 0xfc, 0x40, 0x8e, 0x7b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, 0x82, 0xc0, 0x70, 0xc3, 0xcf, 0xf8, 0xf8, + 0x68, 0x49, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xe3, 0xaf, 0x00, 0x35, 0x66, 0x74, 0xf4, 0x14, 0x40, 0x61, + 0x21, 0x20, 0xfa, 0x18, 0x64, 0xb4, 0x02, 0x7e, 0x0b, 0xf5, 0xbb, 0x75, 0xe2, 0xfb, 0xd0, 0xaf, 0x82, 0x5e, 0xc4, + 0xc0, 0x70, 0x44, 0x93, 0xc3, 0x90, 0x0f, 0x26, 0x03, 0xd0, 0x96, 0x78, 0xbb, 0xaf, 0xa5, 0x15, 0x37, 0xa7, 0x4b, + 0xa7, 0xfb, 0x27, 0x6d, 0x82, 0x24, 0x52, 0xc9, 0x4a, 0x45, 0x0c, 0x20, 0x94, 0xa5, 0xda, 0x26, 0x2b, 0xb0, 0xac, + 0x30, 0x4b, 0x9a, 0x1b, 0x94, 0xc4, 0xfd, 0xcd, 0xc0, 0x31, 0x6a, 0xd6, 0x49, 0x58, 0xb6, 0xdc, 0xa8, 0x01, 0x3e, + 0x27, 0x61, 0x85, 0xbd, 0xe1, 0xcc, 0xa5, 0x77, 0xa6, 0xc3, 0xd5, 0x31, 0x67, 0xaf, 0x39, 0x82, 0x71, 0x24, 0x78, + 0xe3, 0xa1, 0x2b, 0xa6, 0xa1, 0x22, 0x53, 0xc6, 0xc1, 0xb4, 0x07, 0xb8, 0xf7, 0x1c, 0x8c, 0xc3, 0xd8, 0xa0, 0xb2, + 0xa4, 0x3e, 0xf5, 0xee, 0x42, 0x20, 0x48, 0x6b, 0xbd, 0xcc, 0xe7, 0x78, 0x7a, 0x46, 0x28, 0xfb, 0x43, 0x0e, 0x5f, + 0x80, 0x1d, 0x05, 0x99, 0x4d, 0xf8, 0xd3, 0xc7, 0xfb, 0x81, 0xaa, 0xf8, 0x20, 0x38, 0x88, 0x45, 0x7a, 0x10, 0x0c, + 0x04, 0xfc, 0x2a, 0xf8, 0x41, 0x25, 0xe5, 0xc1, 0x45, 0x5c, 0x1c, 0xc4, 0xeb, 0xb8, 0xa8, 0x0e, 0x6e, 0xb2, 0x6a, + 0x75, 0x60, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x07, 0xc1, 0xa0, 0x30, 0x53, 0xbb, 0x66, 0x65, 0xe3, + 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, 0xea, 0x86, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, + 0x88, 0xe9, 0x06, 0xfa, 0x00, 0x3c, 0xf2, 0x86, 0xc6, 0xb0, 0x04, 0x2e, 0x06, 0x03, 0xb2, 0x81, 0xc8, 0x05, 0x1b, + 0x6a, 0x83, 0x38, 0x84, 0x1b, 0x65, 0xa7, 0xbd, 0x0f, 0xcc, 0xb4, 0xdb, 0x01, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, + 0x1b, 0xea, 0x5f, 0xb0, 0x57, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, 0xe6, 0xfb, 0x92, 0xcd, 0x06, 0x2a, 0xe2, + 0xf0, 0x9e, 0x23, 0x45, 0x1b, 0x95, 0xcb, 0xb2, 0x27, 0xab, 0x86, 0xaf, 0xc4, 0x15, 0x77, 0x7e, 0x5c, 0x95, 0x94, + 0x79, 0x95, 0xad, 0x15, 0xfb, 0x37, 0xe7, 0x9a, 0xfb, 0x03, 0xeb, 0xcf, 0xe6, 0x2b, 0xb8, 0xb6, 0x7a, 0xef, 0x9a, + 0x5c, 0x23, 0x72, 0x96, 0x50, 0x2e, 0xa9, 0x6d, 0x1e, 0xde, 0xd2, 0xf7, 0xf9, 0xd5, 0xb7, 0x99, 0x4e, 0xe3, 0xb3, + 0x0a, 0x0b, 0x17, 0xa2, 0x15, 0xc1, 0xa1, 0x21, 0x97, 0xcd, 0x23, 0xc0, 0x5c, 0xfb, 0x6c, 0x05, 0x05, 0xa9, 0xcf, + 0x2a, 0xf4, 0x6e, 0x85, 0x84, 0x97, 0x9a, 0x5d, 0x7a, 0x18, 0x48, 0x19, 0xb7, 0x87, 0x96, 0x30, 0x69, 0x79, 0x11, + 0xde, 0x7b, 0xcd, 0x4d, 0xee, 0x79, 0x88, 0xd1, 0x8b, 0x3c, 0x3b, 0x01, 0x63, 0xdd, 0x25, 0x3b, 0x1b, 0x9e, 0xf8, + 0x0d, 0xcf, 0x59, 0x8b, 0x46, 0xd3, 0x15, 0x4b, 0xfa, 0xfd, 0x18, 0x4c, 0xbc, 0x53, 0x96, 0xc3, 0xaf, 0x7c, 0x49, + 0x37, 0x0c, 0x30, 0xc5, 0xe8, 0x05, 0x24, 0xa4, 0x88, 0x44, 0xb2, 0x51, 0x27, 0xc9, 0x27, 0xba, 0x0b, 0xc0, 0xe8, + 0x17, 0xf3, 0x34, 0x5a, 0xdd, 0x6b, 0x66, 0x81, 0xe4, 0x19, 0xfa, 0xae, 0x83, 0xed, 0x8d, 0x7d, 0x90, 0x72, 0x7e, + 0x2c, 0xa6, 0x83, 0x01, 0x27, 0x1a, 0x6e, 0xbc, 0x54, 0xe2, 0x5a, 0xdd, 0xe2, 0x8e, 0x61, 0x2c, 0xf5, 0x6d, 0x11, + 0x83, 0x03, 0x76, 0xd1, 0xca, 0x6e, 0x1f, 0x60, 0x5f, 0x39, 0xde, 0xa5, 0xca, 0xee, 0xf4, 0x98, 0x69, 0x2e, 0x5b, + 0x4d, 0x3a, 0xa9, 0xb8, 0x9f, 0xc8, 0x37, 0xb9, 0x83, 0x2e, 0x97, 0x63, 0xcd, 0x5b, 0x0e, 0x40, 0x45, 0x3f, 0x52, + 0x54, 0xf7, 0x33, 0x1c, 0x61, 0x1e, 0xac, 0xdb, 0x7c, 0x72, 0x68, 0x0a, 0x1c, 0x22, 0x4f, 0xda, 0x68, 0x0a, 0xe8, + 0xde, 0xc5, 0xe3, 0xae, 0x7e, 0x5b, 0xba, 0x0b, 0x94, 0x68, 0xaf, 0xe2, 0x86, 0x1f, 0x13, 0x75, 0x3a, 0xd3, 0x86, + 0xd0, 0xbf, 0x32, 0xe2, 0xfe, 0xd2, 0xb8, 0x8a, 0x37, 0xbd, 0xcb, 0xe7, 0x1c, 0xea, 0xec, 0x86, 0x50, 0x00, 0xae, + 0xda, 0xd3, 0xa9, 0x1b, 0x43, 0x7a, 0xa5, 0x44, 0xb7, 0xc1, 0xc1, 0xee, 0xf5, 0x19, 0x47, 0xd1, 0x8f, 0x51, 0x23, + 0xdf, 0x44, 0xe2, 0xb1, 0x1c, 0xc4, 0x8f, 0x0b, 0xba, 0x8a, 0xc4, 0xe3, 0x62, 0x10, 0x3f, 0x96, 0x75, 0xbd, 0x7f, + 0xae, 0xdc, 0xdf, 0x47, 0xe4, 0x59, 0xf7, 0xf6, 0x52, 0x09, 0x1b, 0x03, 0xcf, 0xae, 0x25, 0x84, 0x53, 0xf0, 0x44, + 0xb6, 0x96, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x65, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, 0xd9, 0xe6, 0xd1, + 0x87, 0x53, 0x20, 0xa1, 0xdb, 0x6d, 0xb3, 0xae, 0xd6, 0x80, 0x62, 0x1a, 0x8e, 0xf9, 0x61, 0x31, 0xba, 0xf1, 0xdd, + 0xf5, 0x0f, 0x8b, 0xd1, 0x8a, 0x0c, 0x27, 0x66, 0xf2, 0xe3, 0xd9, 0x78, 0x1e, 0x47, 0x93, 0xba, 0xe3, 0xb4, 0xd0, + 0xf8, 0xa7, 0xde, 0x2d, 0x14, 0x81, 0x53, 0x31, 0x82, 0x23, 0xa7, 0x42, 0x39, 0x29, 0x35, 0x30, 0xfc, 0x0f, 0xaa, + 0x3d, 0x6d, 0xda, 0xeb, 0xb8, 0x4a, 0x56, 0x99, 0xb8, 0xd4, 0xe1, 0xc3, 0x75, 0x74, 0x71, 0x1b, 0xd0, 0xce, 0xbb, + 0x4c, 0x3b, 0x7e, 0x9d, 0x34, 0xe8, 0x89, 0xab, 0x99, 0x01, 0xb7, 0xee, 0x47, 0x68, 0x86, 0xc0, 0x68, 0x79, 0xfe, + 0x0e, 0x31, 0xb7, 0x7f, 0x55, 0x36, 0xbf, 0x8a, 0xf6, 0x39, 0x32, 0x52, 0xb6, 0xc9, 0x48, 0x05, 0x46, 0x98, 0x52, + 0x24, 0x71, 0x15, 0x42, 0x20, 0xfb, 0xcf, 0x29, 0xae, 0xc5, 0xd2, 0x7b, 0x0d, 0xc2, 0x04, 0xdb, 0x05, 0xed, 0x57, + 0xb7, 0x77, 0x5b, 0x69, 0xb1, 0x47, 0xea, 0xfb, 0xdc, 0xd9, 0xae, 0x68, 0xf2, 0xf7, 0x79, 0x03, 0xda, 0x00, 0xa2, + 0xbc, 0xaf, 0x8f, 0x4a, 0xe0, 0x64, 0xc4, 0x0d, 0x25, 0x46, 0x2f, 0xe8, 0xea, 0x44, 0xee, 0xd9, 0xa9, 0x79, 0x53, + 0x31, 0x57, 0x71, 0xe5, 0x9b, 0x3d, 0xf3, 0x1f, 0x0c, 0x05, 0x15, 0x60, 0xe0, 0x6d, 0xce, 0x78, 0x74, 0xa0, 0xbb, + 0x31, 0x3a, 0x2d, 0xd8, 0x2c, 0xa8, 0xcb, 0xba, 0x69, 0xe3, 0x41, 0x23, 0x0e, 0x8a, 0x62, 0x55, 0xa8, 0x91, 0xf0, + 0x44, 0x20, 0x60, 0xca, 0xae, 0x78, 0x64, 0x04, 0x35, 0xbd, 0x09, 0x85, 0x0d, 0x05, 0x7f, 0x95, 0xa8, 0xa6, 0x37, + 0xa1, 0x4d, 0x26, 0x4e, 0x33, 0x88, 0x60, 0x46, 0x6c, 0xf7, 0x5b, 0x40, 0x9b, 0x5b, 0x33, 0xda, 0xd6, 0xb5, 0xd5, + 0x56, 0x21, 0x97, 0x14, 0x29, 0xcb, 0x7f, 0xa7, 0xa6, 0x82, 0x92, 0x5a, 0x2e, 0x7a, 0x93, 0xa6, 0x8b, 0x1e, 0xcf, + 0x8c, 0x24, 0x50, 0xb9, 0xe5, 0x8e, 0xd1, 0x1f, 0xc2, 0x02, 0x8f, 0x98, 0x38, 0xb1, 0x60, 0x6e, 0x35, 0x63, 0xd9, + 0x42, 0x2c, 0x47, 0x6b, 0x09, 0x61, 0x83, 0x8f, 0x59, 0xb6, 0x28, 0xf5, 0x43, 0xe8, 0x0b, 0x4b, 0xdf, 0x82, 0x5d, + 0x6c, 0xb0, 0x96, 0x65, 0x00, 0xbe, 0x17, 0x74, 0xbb, 0x96, 0x65, 0x24, 0x55, 0xf7, 0xe3, 0x1a, 0x4b, 0x50, 0x69, + 0x85, 0x4a, 0x4b, 0x6a, 0x2c, 0x08, 0x7c, 0x55, 0x75, 0xf9, 0x90, 0xec, 0x2a, 0x50, 0x4f, 0x1d, 0x35, 0xe0, 0x14, + 0xa8, 0x2a, 0xb0, 0x20, 0x09, 0x2a, 0x43, 0x57, 0x05, 0xa6, 0x15, 0x98, 0x66, 0xaa, 0x70, 0x51, 0x66, 0x87, 0xd2, + 0xac, 0x97, 0x7c, 0x1e, 0x0f, 0xc2, 0x64, 0x18, 0x93, 0xc7, 0x08, 0xb5, 0x7f, 0x98, 0x47, 0xb1, 0x96, 0x4b, 0xae, + 0x9d, 0x5f, 0xfc, 0xcd, 0x27, 0xec, 0x75, 0xcf, 0x30, 0x58, 0x80, 0xb3, 0xb4, 0xbd, 0xca, 0xc4, 0x3b, 0xd9, 0x0a, + 0x8e, 0x83, 0x59, 0x94, 0xc3, 0xaa, 0x27, 0x47, 0x34, 0x17, 0xb9, 0xf6, 0x2e, 0x42, 0xe4, 0x20, 0xb3, 0xc7, 0x00, + 0xbb, 0x11, 0xbe, 0x0e, 0xad, 0xcd, 0xad, 0xae, 0x10, 0x7f, 0xa3, 0x44, 0xe2, 0x27, 0x29, 0x3f, 0x6e, 0xd6, 0x2a, + 0x57, 0x65, 0xf0, 0x58, 0x75, 0x33, 0x78, 0xa6, 0x7d, 0x8f, 0xb5, 0x7f, 0x6b, 0xbb, 0x39, 0xde, 0x7b, 0xf0, 0xa0, + 0xf5, 0xbf, 0xf5, 0x24, 0x84, 0xf6, 0xca, 0x49, 0xea, 0x8e, 0x1a, 0x3d, 0x33, 0x59, 0x23, 0x2a, 0x61, 0x6a, 0x77, + 0x2a, 0xc7, 0x40, 0x4d, 0x07, 0x70, 0x2d, 0x51, 0x13, 0xf4, 0xa4, 0x60, 0x63, 0x38, 0xe2, 0x2c, 0x0e, 0xda, 0x71, + 0x8c, 0xe2, 0xe5, 0x5c, 0x89, 0x97, 0xf3, 0x19, 0xe3, 0x00, 0xad, 0x05, 0x48, 0xf5, 0x1a, 0xf6, 0x33, 0x57, 0xb0, + 0xc0, 0xe6, 0xce, 0x77, 0x64, 0x81, 0x0c, 0x71, 0xb2, 0x39, 0x4e, 0xf6, 0xb8, 0xd6, 0x73, 0x2f, 0xf0, 0x71, 0x52, + 0x2f, 0xbd, 0xba, 0xca, 0x76, 0x5d, 0x2b, 0x56, 0x2e, 0x8a, 0xc1, 0x04, 0x82, 0xb2, 0x94, 0x8b, 0x62, 0x38, 0x59, + 0xd2, 0x1c, 0x7e, 0x2c, 0x1b, 0xe8, 0x10, 0xab, 0x41, 0x02, 0x97, 0xce, 0x1e, 0x03, 0xde, 0x50, 0x6a, 0x71, 0x37, + 0xd6, 0x91, 0x63, 0x1d, 0xc5, 0x61, 0x18, 0x03, 0xae, 0xac, 0x13, 0x78, 0xdf, 0x7f, 0x7d, 0x6c, 0x02, 0xb2, 0x6a, + 0x57, 0x78, 0x35, 0xca, 0x5d, 0x57, 0x1a, 0x7d, 0x49, 0xe9, 0x09, 0x2f, 0x78, 0x2a, 0xd9, 0xed, 0x7a, 0x06, 0xce, + 0x96, 0x78, 0x48, 0xbc, 0x63, 0x44, 0x2f, 0xa6, 0x8d, 0xcc, 0x9c, 0xc0, 0x99, 0xed, 0x2e, 0xdb, 0x98, 0x1f, 0x3b, + 0xc0, 0xc1, 0x22, 0x08, 0x89, 0x1b, 0xc2, 0x30, 0xb1, 0x59, 0x39, 0xd4, 0x42, 0xb8, 0xae, 0x85, 0xd7, 0x71, 0x5a, + 0xc6, 0xe0, 0x22, 0xad, 0x6d, 0x13, 0xef, 0xa1, 0xeb, 0x9e, 0x1f, 0x73, 0xab, 0x63, 0xb4, 0x85, 0xf4, 0xdb, 0xd1, + 0xe9, 0x03, 0x87, 0x01, 0x68, 0x7a, 0x30, 0xaf, 0xda, 0x67, 0x12, 0x37, 0xa7, 0x9d, 0x20, 0x24, 0x02, 0x51, 0x94, + 0xce, 0x08, 0xd3, 0xbf, 0xd7, 0x5c, 0x56, 0xd1, 0xea, 0x41, 0x9e, 0x39, 0xe4, 0x59, 0xe8, 0x6d, 0x0f, 0x5a, 0x35, + 0x77, 0x83, 0x71, 0xe2, 0x76, 0x7b, 0xe7, 0xff, 0x2d, 0xeb, 0xda, 0x6a, 0x8d, 0x78, 0xdc, 0xae, 0x7e, 0xd0, 0xd8, + 0xab, 0x3d, 0x15, 0x03, 0x66, 0x2d, 0xbd, 0x33, 0xaa, 0xe4, 0x45, 0xc6, 0x4b, 0x3c, 0xa9, 0xd6, 0x0d, 0x1f, 0xef, + 0x9b, 0x6c, 0x64, 0x1e, 0xc8, 0x14, 0x10, 0xcf, 0x6f, 0x52, 0xa3, 0x3e, 0x4e, 0x51, 0x02, 0xfe, 0x4e, 0xc7, 0x37, + 0xa2, 0x1f, 0xed, 0x8b, 0x4b, 0x5e, 0xbd, 0xbd, 0x11, 0xe6, 0xc5, 0x73, 0xab, 0xf3, 0xa7, 0xaf, 0x0b, 0x1f, 0x3a, + 0x1c, 0xb5, 0x77, 0x50, 0x64, 0xc9, 0xc4, 0x6c, 0x62, 0x64, 0x6d, 0x62, 0xfe, 0x51, 0xc1, 0xc5, 0x44, 0x15, 0x7a, + 0xd6, 0xd9, 0x13, 0xa6, 0x00, 0x7d, 0xe3, 0x18, 0x95, 0x8c, 0x61, 0xc1, 0x40, 0x9d, 0xa6, 0x84, 0xe8, 0xa1, 0x98, + 0x63, 0xbc, 0x62, 0x00, 0x85, 0x29, 0x14, 0x88, 0xa2, 0xb3, 0x0f, 0x07, 0x9a, 0xd0, 0xef, 0xdf, 0xa4, 0x3a, 0x03, + 0x2d, 0xeb, 0xa9, 0x04, 0x51, 0x1d, 0x44, 0x5b, 0xe5, 0x45, 0xf8, 0xe3, 0x8a, 0x96, 0x19, 0x5d, 0x09, 0x9a, 0x0a, + 0x9a, 0x64, 0xf4, 0x82, 0x2b, 0x51, 0xf1, 0x85, 0x60, 0x8a, 0xb6, 0x1b, 0xc2, 0xfe, 0xaf, 0x06, 0x5d, 0x6f, 0xc5, + 0x5a, 0x43, 0xbb, 0x13, 0x64, 0x84, 0x16, 0x4b, 0x1d, 0x84, 0x0c, 0x95, 0x93, 0xd0, 0xb5, 0x4a, 0xe3, 0x15, 0xb8, + 0x64, 0x9a, 0x8d, 0x56, 0x71, 0x19, 0x06, 0xf6, 0xab, 0xc0, 0x62, 0x72, 0x60, 0xd2, 0xe9, 0xe6, 0xfc, 0x99, 0xbc, + 0x5a, 0x4b, 0xc1, 0x45, 0xa5, 0x20, 0xfa, 0x0d, 0xee, 0xbb, 0x89, 0xab, 0xce, 0x9a, 0xb5, 0xd2, 0x87, 0xbe, 0xf5, + 0x59, 0x1b, 0xf7, 0x85, 0xc1, 0x31, 0xd8, 0xfb, 0x88, 0x18, 0x48, 0x83, 0x4a, 0xb7, 0x38, 0x34, 0x01, 0xba, 0x74, + 0x48, 0x21, 0x4b, 0xa6, 0x32, 0x55, 0x82, 0x8a, 0x6f, 0xfc, 0x5e, 0xca, 0x6a, 0xf4, 0xe7, 0x86, 0x17, 0x77, 0xa7, + 0x3c, 0xe7, 0x38, 0x46, 0x41, 0x12, 0x8b, 0xeb, 0xb8, 0x0c, 0x88, 0x6f, 0x79, 0x15, 0x1c, 0xa5, 0x26, 0x6c, 0xcc, + 0x5e, 0xd5, 0xa8, 0xf5, 0x92, 0xe8, 0x2b, 0xa3, 0x7c, 0x63, 0x30, 0x34, 0x11, 0x55, 0xd0, 0xf7, 0x5a, 0xdd, 0xd3, + 0xea, 0x86, 0x05, 0xc4, 0x5f, 0x28, 0xbd, 0x50, 0xeb, 0x75, 0x33, 0xe6, 0x86, 0x89, 0x10, 0x34, 0xfa, 0xaa, 0x5e, + 0xd6, 0x9e, 0x5b, 0x9a, 0x8a, 0x8c, 0x1b, 0x6d, 0x73, 0x7e, 0x09, 0x32, 0x3e, 0x67, 0x2e, 0x34, 0xa9, 0x6b, 0xaa, + 0xa0, 0x0a, 0xa3, 0xed, 0x6d, 0x23, 0x9d, 0xde, 0x81, 0x3b, 0x9b, 0x31, 0x3b, 0xd2, 0x2e, 0x8d, 0x35, 0x2d, 0x78, + 0xb9, 0x96, 0xa2, 0x84, 0x30, 0xce, 0xbd, 0x31, 0xbd, 0x8a, 0x33, 0x51, 0xc5, 0x99, 0x38, 0x29, 0xd7, 0x3c, 0xa9, + 0xde, 0xc3, 0x2d, 0x4e, 0x59, 0xdd, 0xd4, 0x25, 0x5c, 0xe9, 0x92, 0x03, 0x0c, 0xa6, 0xa6, 0xe2, 0x1e, 0x3b, 0x83, + 0x8b, 0xea, 0xf7, 0x68, 0x25, 0x31, 0x16, 0xaa, 0x2e, 0x3e, 0x3e, 0x2f, 0x65, 0xbe, 0xa9, 0x40, 0xbb, 0x7b, 0x51, + 0x45, 0x47, 0x4f, 0xd6, 0xb7, 0x53, 0x75, 0x83, 0x89, 0x9e, 0x1c, 0xad, 0x6f, 0x7b, 0xd9, 0xd5, 0x5a, 0x16, 0x55, + 0x2c, 0xaa, 0xa9, 0x42, 0x24, 0x4b, 0xe2, 0x3c, 0x09, 0x27, 0xe3, 0xf1, 0x17, 0x07, 0xc3, 0x03, 0xc8, 0x40, 0xa6, + 0x7f, 0x0d, 0x95, 0xcb, 0xd1, 0x70, 0x32, 0x1e, 0x4f, 0xa5, 0xba, 0xdb, 0x45, 0xa3, 0x49, 0x8d, 0xf5, 0x0c, 0x13, + 0x3d, 0x33, 0x23, 0x7e, 0xbb, 0x8e, 0x45, 0x0a, 0xf1, 0xeb, 0x74, 0xf1, 0x47, 0x4f, 0xc6, 0x8d, 0xf2, 0xed, 0xa7, + 0x4f, 0xeb, 0xdf, 0x6b, 0x13, 0xd6, 0xda, 0xb4, 0xfb, 0xd9, 0xef, 0xc7, 0x6a, 0xbe, 0x67, 0xc7, 0x87, 0xfa, 0xc7, + 0xef, 0x75, 0x3d, 0x7d, 0x5d, 0x84, 0x8b, 0x7f, 0x86, 0x6a, 0x3e, 0x4f, 0x8a, 0x22, 0xbe, 0xab, 0x21, 0x92, 0xa7, + 0x70, 0xde, 0x24, 0xd4, 0xdb, 0x06, 0xf4, 0x88, 0x4c, 0x2f, 0x04, 0x83, 0x6f, 0xde, 0x57, 0x61, 0xc0, 0xcb, 0xf5, + 0x90, 0x8b, 0x2a, 0xab, 0xee, 0x86, 0x98, 0x27, 0xc0, 0x4f, 0x0d, 0x6f, 0xf6, 0xac, 0x30, 0xc4, 0xe6, 0xa2, 0xe0, + 0xfc, 0x2f, 0x1e, 0x2a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1a, 0x8c, 0xc9, 0xd7, 0x54, 0x77, 0x66, 0xf2, + 0x35, 0x98, 0x20, 0x65, 0xed, 0x6f, 0x94, 0x71, 0x62, 0x34, 0xa6, 0xd7, 0x2f, 0xf3, 0x6c, 0x0d, 0x4c, 0xf0, 0x4a, + 0xff, 0xa8, 0x09, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xb3, 0x82, 0x8e, 0x46, 0xa3, 0x8f, 0x59, 0x4d, 0xe8, + 0x5a, 0x74, 0xbc, 0x7f, 0xcf, 0xe9, 0xb9, 0x4c, 0xef, 0xa2, 0x20, 0xa0, 0xab, 0x2c, 0x4d, 0xb9, 0x50, 0x65, 0x9d, + 0xa6, 0xed, 0xbc, 0xaa, 0x85, 0x08, 0xfc, 0xa3, 0xdb, 0x88, 0x10, 0x44, 0x84, 0xbe, 0xdd, 0xeb, 0xd9, 0x68, 0x34, + 0x3a, 0x4d, 0x4d, 0xb5, 0x8e, 0x21, 0x7f, 0x8d, 0xe6, 0x03, 0xce, 0x2e, 0x1f, 0xac, 0x6f, 0x4c, 0xb4, 0x93, 0xc3, + 0xff, 0x1e, 0xce, 0x17, 0xe3, 0xe1, 0xb7, 0xa3, 0xe5, 0xe3, 0x43, 0x1a, 0x04, 0x3e, 0x68, 0x75, 0xa8, 0xad, 0x39, + 0xa6, 0xe5, 0xf1, 0x78, 0x4a, 0xca, 0x01, 0x7b, 0x62, 0x7d, 0x69, 0xbe, 0x78, 0x02, 0x48, 0xa4, 0x28, 0x42, 0x0d, + 0x9c, 0xf4, 0x0f, 0xaf, 0x22, 0xaf, 0x04, 0xe0, 0xa3, 0xd9, 0x48, 0x06, 0x46, 0x0b, 0x38, 0x8e, 0xa0, 0xbc, 0xda, + 0x9a, 0x46, 0xf4, 0x18, 0xcb, 0x4c, 0x54, 0xd0, 0xf1, 0xb4, 0xbc, 0xc9, 0xaa, 0x64, 0x85, 0x81, 0x8d, 0xe2, 0x92, + 0x07, 0x5f, 0x04, 0x51, 0xc9, 0x8e, 0x9e, 0x4e, 0x15, 0xbc, 0x2f, 0x26, 0xa5, 0xfc, 0x12, 0x12, 0xbf, 0x1d, 0x23, + 0x04, 0x2a, 0xd1, 0x1e, 0x8b, 0x58, 0xe3, 0xcb, 0x5c, 0xc6, 0xe0, 0xc1, 0x59, 0x6a, 0x9e, 0xc5, 0x9e, 0x04, 0xd6, + 0xfe, 0xa2, 0xd5, 0x1c, 0x09, 0xcd, 0x09, 0x25, 0x93, 0x87, 0x25, 0x95, 0x5f, 0x4c, 0xd0, 0x2b, 0x08, 0xdc, 0xaa, + 0x23, 0x38, 0xee, 0xac, 0x65, 0x83, 0x5e, 0x3e, 0x29, 0x3b, 0x5c, 0xfc, 0xef, 0x92, 0x2e, 0x07, 0x87, 0x6e, 0x68, + 0xde, 0x6a, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x96, 0x12, 0x6b, 0x7c, 0xca, 0xd9, 0x6c, 0x6b, 0xba, 0x33, + 0xaa, 0x8a, 0xec, 0x2a, 0x24, 0xba, 0x57, 0x0e, 0x14, 0x33, 0x88, 0xb2, 0x11, 0xae, 0x1f, 0xb0, 0x16, 0xf1, 0x3a, + 0x79, 0xcd, 0x8b, 0x2a, 0x4b, 0xd4, 0xfb, 0xeb, 0xc6, 0x7b, 0xa0, 0x06, 0xaa, 0x41, 0xef, 0x0a, 0x06, 0xf3, 0xfc, + 0xb6, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, + 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xa9, + 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, + 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x9d, 0x86, 0x10, 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, + 0xbe, 0xc5, 0x53, 0x35, 0x0c, 0x2e, 0xf2, 0x6c, 0xad, 0x93, 0xaa, 0x51, 0x47, 0xf3, 0xa1, 0xd4, 0x8e, 0xe4, 0x80, + 0x7a, 0xe9, 0x31, 0xa6, 0x17, 0x2a, 0x5d, 0x15, 0xe5, 0x8c, 0x50, 0xde, 0xe9, 0x89, 0x71, 0x61, 0xfa, 0x38, 0x44, + 0x7e, 0x79, 0x57, 0xa8, 0xd0, 0x2f, 0x7c, 0x09, 0xe0, 0x57, 0x70, 0xbb, 0xdf, 0x8f, 0xef, 0xa2, 0xb2, 0x9f, 0x71, + 0x76, 0xf8, 0xdf, 0x8b, 0x78, 0xf8, 0xd7, 0x78, 0xf8, 0xed, 0x72, 0x10, 0x0e, 0xed, 0x4f, 0xf2, 0xf8, 0xd1, 0x21, + 0x7d, 0xc9, 0x2d, 0x57, 0x02, 0x0b, 0xbf, 0x11, 0xdc, 0x46, 0xad, 0x84, 0x20, 0x0a, 0xf0, 0x46, 0xe1, 0x56, 0xe3, + 0x04, 0x00, 0xfe, 0x82, 0xff, 0x0a, 0xd0, 0x48, 0xc8, 0x5d, 0x34, 0x40, 0x3f, 0xa0, 0x7e, 0xcf, 0xbe, 0x6a, 0x18, + 0xc8, 0x81, 0x78, 0x42, 0xc5, 0x40, 0x21, 0xba, 0x8c, 0x89, 0x82, 0xfd, 0xb5, 0xd9, 0x77, 0xbb, 0x5e, 0x5b, 0xf2, + 0x83, 0x5f, 0xfa, 0x99, 0x26, 0x66, 0xde, 0xe1, 0x86, 0xb2, 0x96, 0xeb, 0x10, 0xb1, 0xf1, 0xf4, 0xaf, 0x9c, 0x41, + 0xac, 0xc9, 0xeb, 0x0c, 0x7c, 0x18, 0xec, 0x17, 0xe3, 0x39, 0xb0, 0x0d, 0x70, 0xc7, 0x29, 0xf8, 0x45, 0x06, 0x6e, + 0xcd, 0x22, 0xc6, 0x0b, 0xb6, 0x5d, 0x12, 0xfd, 0x7e, 0x2f, 0xcf, 0xc2, 0x5c, 0xe3, 0x2c, 0xe7, 0xb5, 0x11, 0xbb, + 0xa3, 0x4e, 0x18, 0xc4, 0xed, 0x7a, 0x08, 0x86, 0x6a, 0x08, 0x8a, 0x8e, 0xb6, 0xb8, 0x7a, 0x6d, 0x3d, 0x85, 0xe9, + 0xad, 0xaa, 0xaf, 0x18, 0xfd, 0x21, 0x33, 0x81, 0x85, 0xb4, 0x6b, 0x8e, 0x75, 0xcd, 0x31, 0xd2, 0x9e, 0x7e, 0x5f, + 0x34, 0xc8, 0x4f, 0x67, 0xe1, 0x41, 0xa0, 0x4a, 0x95, 0x7b, 0x65, 0x51, 0x6e, 0x4b, 0xf3, 0xc6, 0xb0, 0xa6, 0x79, + 0x66, 0xe3, 0xba, 0xcc, 0x7b, 0xbd, 0x30, 0x44, 0x87, 0x46, 0x2c, 0x15, 0x6b, 0x83, 0xf0, 0x3e, 0x26, 0x61, 0x74, + 0x05, 0xb2, 0xba, 0xf0, 0x8c, 0x13, 0xe4, 0xcb, 0xc0, 0x64, 0x4d, 0x55, 0xeb, 0xe5, 0x84, 0xc7, 0x46, 0xbe, 0x6c, + 0x04, 0x0d, 0xf2, 0x92, 0xa2, 0xde, 0xc4, 0xed, 0xd8, 0x47, 0x2d, 0xa4, 0xc6, 0x6d, 0x3d, 0xed, 0x69, 0x52, 0xd1, + 0x63, 0xbd, 0x4a, 0xfd, 0x02, 0xcb, 0x02, 0x4b, 0x3e, 0x08, 0xed, 0x69, 0x5a, 0x81, 0x19, 0xae, 0x6d, 0x06, 0x43, + 0x3f, 0x1c, 0xda, 0x22, 0x74, 0x46, 0x6d, 0x4b, 0x08, 0xdb, 0x36, 0x08, 0x2b, 0xef, 0x89, 0x7c, 0xf1, 0xc4, 0x63, + 0x84, 0x43, 0x6e, 0x36, 0xb3, 0x68, 0x60, 0x98, 0x5f, 0xc9, 0x66, 0xf3, 0x74, 0x73, 0xbd, 0xa8, 0x98, 0x02, 0xb6, + 0xdb, 0x5a, 0x10, 0xfc, 0xfb, 0x31, 0x9b, 0xe3, 0xdf, 0xac, 0xdf, 0xef, 0x85, 0xf8, 0x8b, 0x63, 0xf0, 0x9e, 0x85, + 0x58, 0xb2, 0x8f, 0x20, 0x53, 0x21, 0x11, 0xa6, 0x2a, 0xe3, 0x37, 0x56, 0x81, 0x05, 0x9c, 0xf9, 0x40, 0xe5, 0xc2, + 0x4c, 0xf6, 0xf2, 0xe2, 0x1a, 0x72, 0xd2, 0x1a, 0xa7, 0x6c, 0x94, 0x25, 0xca, 0x75, 0x21, 0x1b, 0xc5, 0x79, 0x16, + 0x97, 0xbc, 0xdc, 0xed, 0xf4, 0xe1, 0x98, 0x14, 0x1c, 0xd8, 0x53, 0x45, 0xa5, 0x4a, 0xd6, 0x91, 0xea, 0xc6, 0x5f, + 0x86, 0x05, 0xee, 0x53, 0xbe, 0x28, 0x0c, 0x8d, 0x38, 0x80, 0xcb, 0x3b, 0x53, 0xb7, 0xd2, 0x5e, 0x58, 0x40, 0xf3, + 0x4a, 0x42, 0xb6, 0x98, 0xea, 0x59, 0xb4, 0xc6, 0x4c, 0x2c, 0x8a, 0x25, 0x84, 0x91, 0x29, 0x96, 0x60, 0x33, 0xc5, + 0x05, 0x78, 0x91, 0xc4, 0x00, 0x13, 0x17, 0x93, 0x29, 0xc4, 0x33, 0x57, 0xe5, 0xc4, 0x4b, 0x73, 0xbf, 0x4c, 0x1c, + 0x52, 0x06, 0xbc, 0xaa, 0x0d, 0x9a, 0x98, 0x6d, 0x38, 0xea, 0x04, 0x39, 0x31, 0xf9, 0xfd, 0x54, 0x41, 0x88, 0x3b, + 0x71, 0x24, 0x5c, 0x56, 0x6c, 0x17, 0x5e, 0x74, 0x20, 0xc6, 0xa8, 0xc1, 0x29, 0x3f, 0x31, 0x38, 0x1a, 0x83, 0x73, + 0xeb, 0x9d, 0x20, 0x45, 0x18, 0x93, 0xad, 0x64, 0x57, 0x32, 0x14, 0x8b, 0x78, 0x09, 0xca, 0xba, 0x78, 0x09, 0x96, + 0x35, 0xc6, 0x00, 0x13, 0xe4, 0x55, 0xdc, 0x0b, 0xfd, 0x44, 0x71, 0x85, 0x48, 0xcf, 0xca, 0xf5, 0x51, 0xd1, 0x0e, + 0x7d, 0x81, 0xd7, 0x7b, 0x65, 0x8e, 0x9b, 0xf5, 0x58, 0x20, 0xb1, 0x21, 0x60, 0x6c, 0xa4, 0xd3, 0x54, 0x6b, 0xdd, + 0x1b, 0x33, 0x0f, 0x7c, 0x9a, 0x8d, 0x84, 0xac, 0xce, 0x2e, 0x40, 0x84, 0xe2, 0xa3, 0xc1, 0x23, 0xbf, 0x88, 0x3b, + 0xcb, 0xbc, 0xb5, 0x2d, 0x2a, 0xd9, 0x6c, 0x0b, 0x20, 0x7d, 0x3a, 0x5a, 0x94, 0x92, 0x53, 0x94, 0xa4, 0x76, 0x9b, + 0x02, 0x56, 0x92, 0xbf, 0x80, 0x21, 0xd8, 0xd8, 0x81, 0x70, 0x3a, 0x45, 0x88, 0x4f, 0x34, 0x45, 0x64, 0xc5, 0xb0, + 0xa4, 0x38, 0xb6, 0x25, 0xa2, 0x7e, 0xda, 0xb2, 0xec, 0x60, 0x98, 0xa8, 0xb8, 0xcf, 0x53, 0x8f, 0x12, 0x05, 0x01, + 0xd5, 0x43, 0x0e, 0x12, 0x5b, 0xdb, 0x40, 0x78, 0x40, 0x1e, 0xd1, 0x1b, 0xeb, 0xef, 0xb3, 0xce, 0xb3, 0x0b, 0xcd, + 0x51, 0xb9, 0xde, 0x15, 0x66, 0x8c, 0xf0, 0x24, 0x33, 0x30, 0xf9, 0xde, 0x79, 0x66, 0xd4, 0x14, 0x3d, 0x0f, 0x9f, + 0xec, 0x04, 0x23, 0xd2, 0xdd, 0x33, 0xe8, 0x26, 0x78, 0x55, 0x87, 0x8d, 0x76, 0xa5, 0x20, 0x24, 0x4c, 0x2d, 0x9a, + 0x98, 0xf5, 0xac, 0x01, 0xf5, 0x6e, 0xd7, 0xd3, 0x73, 0x75, 0xff, 0xdc, 0xed, 0x76, 0x3d, 0xec, 0xd6, 0xf3, 0xb4, + 0xdb, 0x0a, 0xbc, 0x52, 0x1f, 0xb4, 0xc7, 0x9f, 0xbb, 0xf1, 0xe7, 0x06, 0xc9, 0xa3, 0x74, 0x34, 0xd3, 0xd6, 0x07, + 0xe1, 0x70, 0xd3, 0xbb, 0x46, 0x93, 0xbe, 0xcf, 0x42, 0x49, 0xd7, 0xa2, 0x51, 0x5d, 0xed, 0x4c, 0x2a, 0x1f, 0x5c, + 0xff, 0x0f, 0xaf, 0x02, 0x3c, 0xe2, 0xd4, 0xce, 0xbe, 0xb7, 0x41, 0x45, 0xa3, 0x2d, 0x1c, 0x29, 0x42, 0x0f, 0x48, + 0xc2, 0x7d, 0x2d, 0x6b, 0x71, 0x9b, 0xa7, 0xd9, 0xc3, 0xf4, 0xe9, 0x55, 0xea, 0x5b, 0xdd, 0xbb, 0x65, 0x96, 0x99, + 0x03, 0xaf, 0xa2, 0x38, 0xa0, 0x51, 0x17, 0xed, 0xbb, 0xca, 0xca, 0x12, 0xbc, 0x3c, 0xe0, 0xfa, 0x7c, 0xca, 0x7d, + 0xb8, 0xb9, 0xcb, 0xaa, 0xb9, 0x49, 0x4f, 0xb3, 0x45, 0xb6, 0xdc, 0xed, 0x42, 0xfc, 0xdb, 0xd5, 0x22, 0x47, 0x93, + 0x17, 0xa0, 0xc3, 0xc3, 0xc8, 0x3d, 0x4c, 0x37, 0xce, 0xdb, 0xfc, 0x7f, 0x89, 0x86, 0x93, 0xc0, 0x09, 0xd0, 0x8b, + 0xf9, 0x23, 0x90, 0xc1, 0x18, 0xa7, 0x7e, 0x31, 0xd7, 0x6b, 0x06, 0xa2, 0x6f, 0x89, 0x08, 0x70, 0x74, 0xb1, 0x91, + 0x68, 0x64, 0xc1, 0x49, 0x4d, 0xc0, 0x62, 0xd3, 0x96, 0xf7, 0xc1, 0xd2, 0xb6, 0xaa, 0xb8, 0xf3, 0x96, 0x34, 0xc7, + 0x75, 0xe0, 0x6c, 0xfb, 0xcd, 0x10, 0x9b, 0xb2, 0xab, 0x25, 0x72, 0xbf, 0xbc, 0xa6, 0xbd, 0x71, 0x9d, 0xc0, 0xac, + 0x6d, 0x6b, 0xcb, 0xf8, 0xd9, 0xd2, 0x7f, 0xd2, 0x83, 0xab, 0x8c, 0x9f, 0x16, 0xc6, 0x2a, 0xc1, 0xee, 0x1b, 0xcf, + 0x77, 0x00, 0xc2, 0xb1, 0xf9, 0xf4, 0xf8, 0x34, 0xf3, 0xe8, 0x31, 0x10, 0x1d, 0xf3, 0x51, 0xe9, 0x3e, 0xb2, 0xbb, + 0xd7, 0x0f, 0x80, 0xb7, 0xa8, 0xda, 0x05, 0x2d, 0xca, 0x25, 0x04, 0x12, 0xf5, 0xca, 0x2b, 0x2c, 0x9f, 0x19, 0xb3, + 0x4b, 0x20, 0x43, 0x05, 0x01, 0x9b, 0xa4, 0xae, 0x73, 0x21, 0x56, 0x1d, 0x56, 0xe6, 0x23, 0x09, 0x9b, 0x85, 0x68, + 0xce, 0x19, 0xcc, 0x83, 0xff, 0x0a, 0x06, 0xe5, 0x20, 0x88, 0x82, 0x28, 0x08, 0xc8, 0xa0, 0x80, 0x5f, 0x88, 0x33, + 0x46, 0x30, 0x46, 0x09, 0x74, 0xf8, 0x1d, 0x67, 0x3e, 0x23, 0xf2, 0xa2, 0x11, 0xc6, 0xd2, 0x0d, 0xc0, 0xb9, 0x94, + 0x39, 0x8f, 0xd1, 0xc7, 0xe2, 0x1d, 0x67, 0x19, 0xa1, 0xef, 0xbc, 0x53, 0xf9, 0x11, 0x6f, 0x04, 0xb7, 0xdb, 0x1f, + 0xb6, 0x97, 0x3c, 0xcc, 0x68, 0x6f, 0x4c, 0xdf, 0x71, 0x12, 0x65, 0x0d, 0xe7, 0x61, 0x0e, 0x3d, 0xab, 0x2c, 0x6b, + 0x45, 0x0d, 0xb9, 0x41, 0xb1, 0x2e, 0xb2, 0x4c, 0x4e, 0x86, 0xab, 0xe6, 0x54, 0xe0, 0xba, 0xb3, 0xeb, 0x05, 0x24, + 0x65, 0x42, 0xb3, 0x74, 0x36, 0x7c, 0xb5, 0x6d, 0xd9, 0xf3, 0xd6, 0x29, 0xe4, 0x35, 0x44, 0x45, 0x3f, 0x74, 0x04, + 0xd4, 0xd0, 0x8a, 0xcb, 0x0a, 0x5c, 0x76, 0x4d, 0x7b, 0xb8, 0x69, 0x8f, 0x69, 0xc6, 0x07, 0x88, 0x11, 0xc7, 0xb1, + 0x65, 0x60, 0x37, 0xe1, 0xf0, 0x6c, 0x9c, 0xef, 0xcb, 0x3e, 0xbd, 0x75, 0xb5, 0x78, 0x84, 0xb5, 0xe7, 0xad, 0x90, + 0x10, 0x20, 0x2d, 0x4d, 0xa5, 0xbb, 0x5d, 0x10, 0xc0, 0x00, 0xf7, 0xfb, 0x3d, 0xe0, 0x5a, 0x0d, 0x3b, 0x69, 0x6e, + 0xcd, 0x96, 0xd8, 0x2b, 0x0a, 0x8f, 0x81, 0x28, 0x35, 0xff, 0x19, 0x04, 0x14, 0xcf, 0xdd, 0x10, 0xec, 0x2b, 0xd9, + 0x6c, 0x5b, 0xf4, 0xfb, 0xcf, 0x0b, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, + 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, + 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x7f, 0x01, 0x2c, 0x78, 0xe6, 0x0d, 0xcb, 0x7b, 0x0f, 0x00, 0xac, 0xd7, 0xc3, 0x85, + 0xe2, 0x5e, 0xbe, 0x6c, 0xa0, 0x4f, 0xe2, 0x4b, 0xcb, 0xae, 0xcf, 0xb5, 0xac, 0x64, 0x34, 0x1a, 0x55, 0xb5, 0x92, + 0x7c, 0x38, 0xf2, 0xd2, 0x42, 0xad, 0x94, 0x71, 0xca, 0x53, 0xb0, 0xf4, 0x36, 0x94, 0x6e, 0xb1, 0xa4, 0x6b, 0x2e, + 0x52, 0xf5, 0xd3, 0x43, 0x9b, 0x6c, 0x10, 0xd7, 0xac, 0xa9, 0xb3, 0xb0, 0xc3, 0x0f, 0x01, 0x1f, 0xed, 0xc3, 0xdc, + 0xa5, 0x6b, 0x58, 0x5a, 0x10, 0x47, 0xc6, 0x05, 0x0f, 0x5d, 0x1e, 0xc0, 0xfa, 0x33, 0x87, 0x24, 0x7e, 0x0a, 0x3f, + 0xe7, 0x26, 0xad, 0xe3, 0x33, 0x9c, 0xcd, 0xa8, 0x54, 0x37, 0x82, 0xf6, 0x6b, 0x48, 0x24, 0x06, 0xd9, 0xb8, 0xc1, + 0x50, 0xb4, 0xee, 0x36, 0x70, 0xe5, 0xb7, 0xf4, 0xce, 0xa7, 0x41, 0x80, 0x6d, 0x8d, 0xc5, 0x00, 0x60, 0x28, 0xfe, + 0x40, 0x55, 0x8d, 0xb9, 0xa2, 0x98, 0x86, 0xa9, 0x44, 0x7b, 0xc7, 0x71, 0x1d, 0x35, 0xae, 0xb2, 0x82, 0x95, 0xd6, + 0x96, 0xd7, 0xbd, 0xa5, 0x85, 0x2d, 0x01, 0xd5, 0x60, 0xb8, 0x13, 0xc0, 0x67, 0x44, 0xaa, 0x03, 0x41, 0x76, 0x1f, + 0x1c, 0x34, 0x67, 0x09, 0x9e, 0x87, 0x21, 0xfc, 0x81, 0x85, 0x03, 0xcb, 0x52, 0xf5, 0x73, 0x35, 0x8d, 0xe1, 0xdc, + 0xcd, 0xd5, 0x0e, 0x9f, 0xaf, 0x40, 0x91, 0xa7, 0xe6, 0xd4, 0x5c, 0xbe, 0xf2, 0xc6, 0x7e, 0x8f, 0x09, 0xe6, 0x31, + 0xb3, 0x0d, 0xbf, 0xf5, 0x74, 0x5b, 0x5f, 0x58, 0x37, 0x70, 0xd2, 0x5e, 0x38, 0xed, 0xc5, 0x76, 0x65, 0x20, 0xee, + 0xea, 0x86, 0x10, 0xe1, 0x95, 0x26, 0x16, 0x59, 0x43, 0xa6, 0x63, 0xb1, 0x31, 0x54, 0x9b, 0x8a, 0x67, 0x5a, 0x21, + 0x5e, 0x4e, 0xd5, 0x85, 0xa9, 0x95, 0xca, 0x84, 0x41, 0x98, 0x29, 0x61, 0x51, 0x65, 0xe0, 0xb3, 0x5f, 0x21, 0xc5, + 0xb5, 0xf5, 0xbc, 0xc1, 0xe5, 0x9b, 0x99, 0x36, 0xdb, 0x4f, 0x5f, 0xe6, 0xf1, 0xe5, 0x6e, 0x17, 0x76, 0xbf, 0x00, + 0xf3, 0xcb, 0x52, 0x69, 0xd4, 0xc0, 0xe9, 0x21, 0x44, 0x3f, 0xe7, 0x7b, 0x72, 0x4e, 0x1c, 0x27, 0xd7, 0x6e, 0xde, + 0x7c, 0x2f, 0xc5, 0x08, 0x2c, 0xe0, 0xc4, 0x45, 0x3a, 0xd0, 0x52, 0xc1, 0x69, 0xcb, 0x78, 0x6f, 0xd3, 0x3b, 0x4a, + 0x85, 0x57, 0x0b, 0x4d, 0x42, 0x2a, 0x77, 0x2f, 0xb1, 0xa3, 0x06, 0x9c, 0x93, 0xba, 0x83, 0x80, 0x93, 0x9a, 0x6e, + 0xac, 0x55, 0x9c, 0x9a, 0x04, 0xef, 0x95, 0x1e, 0xba, 0x44, 0x3b, 0x71, 0xbb, 0x6d, 0x55, 0xb6, 0x50, 0x1f, 0x0f, + 0x72, 0x96, 0xa8, 0xe3, 0x01, 0x85, 0x2e, 0xea, 0x68, 0xc8, 0x97, 0xa4, 0xd0, 0x2b, 0x47, 0xab, 0x56, 0xf7, 0x25, + 0x03, 0xa5, 0x5a, 0x05, 0x79, 0x4d, 0xac, 0xbb, 0x56, 0xd6, 0x58, 0x5c, 0x39, 0x21, 0x85, 0x4d, 0xf8, 0xdc, 0x52, + 0x2c, 0xac, 0x60, 0x6f, 0x4c, 0x7d, 0xe1, 0x12, 0xa1, 0xed, 0x6e, 0x43, 0x4c, 0x32, 0x58, 0x37, 0xbb, 0xdd, 0xab, + 0x22, 0x5c, 0x64, 0x4b, 0x2a, 0x47, 0x59, 0x8a, 0x10, 0x62, 0xc6, 0x43, 0xd7, 0x76, 0xc1, 0x4c, 0x0c, 0x75, 0xed, + 0xf1, 0x92, 0x4c, 0xb1, 0x36, 0x49, 0x8e, 0xe2, 0x73, 0x59, 0xa8, 0xb5, 0x46, 0x08, 0x1e, 0xee, 0x7f, 0xa4, 0x10, + 0xc3, 0xcd, 0xac, 0xbb, 0x5f, 0xf7, 0x6e, 0x88, 0x7f, 0x40, 0x20, 0x81, 0x92, 0xbd, 0x2a, 0x46, 0xe7, 0x99, 0x48, + 0x71, 0xa7, 0xaa, 0xa8, 0xb8, 0x6a, 0x1d, 0x34, 0x5b, 0x6e, 0xef, 0xc5, 0x96, 0x28, 0x40, 0x5c, 0x63, 0xa1, 0x19, + 0xcf, 0xca, 0x59, 0x8a, 0x64, 0x14, 0x1b, 0x12, 0x95, 0x5e, 0x54, 0x74, 0x9f, 0xa7, 0x31, 0x3d, 0x74, 0x6b, 0x10, + 0x5c, 0x35, 0xf7, 0x36, 0xd2, 0x62, 0x49, 0x88, 0x9a, 0x00, 0x09, 0x1b, 0xd5, 0x9c, 0x5a, 0x97, 0xe2, 0x61, 0x56, + 0xf9, 0x4c, 0x1f, 0xc4, 0x97, 0x02, 0x78, 0x58, 0x6f, 0x7b, 0x5f, 0x09, 0x8f, 0xb5, 0xc1, 0xb7, 0xbb, 0xdd, 0xa5, + 0x58, 0x04, 0x81, 0xc7, 0x68, 0x7e, 0xa7, 0x24, 0xe6, 0xbd, 0x31, 0x85, 0x15, 0xef, 0xbb, 0xb4, 0x75, 0x93, 0x5a, + 0x6b, 0x81, 0xba, 0xc7, 0xf5, 0x01, 0xcf, 0x53, 0xe2, 0x68, 0x47, 0xe5, 0x54, 0x5a, 0x5d, 0x39, 0x76, 0x45, 0x60, + 0x60, 0xe8, 0x1f, 0x52, 0xb6, 0x05, 0x73, 0x3c, 0xb0, 0xb6, 0x41, 0x3f, 0x25, 0xa5, 0x85, 0x19, 0xa3, 0x31, 0x8b, + 0xdc, 0x54, 0xd1, 0x11, 0xd7, 0xd1, 0xdb, 0x79, 0xf4, 0xb7, 0xa7, 0x63, 0x5a, 0xc4, 0x22, 0x95, 0x57, 0xa0, 0x82, + 0x00, 0x65, 0x08, 0x1a, 0xfe, 0x6b, 0x6a, 0x00, 0x1a, 0x04, 0x37, 0x00, 0xff, 0xe8, 0x74, 0x1a, 0xb4, 0x35, 0xf9, + 0x98, 0xa4, 0xaa, 0xc8, 0x79, 0x1b, 0xca, 0x4c, 0x25, 0x87, 0xe4, 0x71, 0x09, 0x78, 0x8e, 0xd8, 0x2c, 0x65, 0x73, + 0xa1, 0x36, 0x9b, 0x7a, 0xad, 0xd8, 0x91, 0xdb, 0x46, 0xd1, 0x66, 0x2d, 0x6a, 0x3b, 0x89, 0xc5, 0x72, 0x7a, 0x6b, + 0x85, 0x81, 0x53, 0xd3, 0x9a, 0x9b, 0x3d, 0xe8, 0x34, 0x5b, 0x9f, 0xc9, 0x4d, 0x80, 0x38, 0xc0, 0x70, 0xdd, 0x2e, + 0x6e, 0x96, 0x84, 0xde, 0xb2, 0x5b, 0x2b, 0x56, 0xbd, 0xb1, 0x72, 0x11, 0x93, 0x76, 0x33, 0x98, 0xc0, 0x65, 0x9c, + 0x15, 0xf6, 0x85, 0x56, 0x37, 0x14, 0x1d, 0x6d, 0x93, 0xf6, 0xf3, 0x8e, 0x76, 0xc3, 0x05, 0xdf, 0x8a, 0x75, 0x9c, + 0x1b, 0xd2, 0x54, 0xa1, 0x47, 0x07, 0x7a, 0x3b, 0x04, 0x34, 0x67, 0x63, 0xba, 0xa2, 0x29, 0x5e, 0xa0, 0xe9, 0x06, + 0xcc, 0x52, 0x2e, 0xa0, 0xaf, 0xdd, 0x3e, 0xc9, 0x17, 0xaa, 0x27, 0xc2, 0x5b, 0xa2, 0xe0, 0xcb, 0x91, 0x82, 0x57, + 0x56, 0xce, 0x63, 0x33, 0x87, 0x80, 0xc7, 0xa2, 0x4a, 0xf4, 0x4e, 0x8a, 0x4b, 0x50, 0xa6, 0xc2, 0x11, 0x68, 0xaa, + 0x46, 0x2c, 0xe1, 0x00, 0xb7, 0x17, 0x4f, 0x03, 0x42, 0x41, 0xaa, 0xbb, 0xb1, 0x2b, 0xf2, 0x96, 0xcd, 0xb6, 0xb7, + 0x60, 0x16, 0x5b, 0x6d, 0xca, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, + 0x43, 0xb6, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, + 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x75, 0x7c, 0x07, 0x9b, 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, + 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, 0x5e, 0x6d, 0x63, 0xd6, 0x66, 0xb9, 0x39, + 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, + 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x35, 0xce, 0xdc, 0xeb, 0x90, 0x6c, 0xff, 0xc7, 0x06, + 0xea, 0x75, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x7e, 0xcb, 0x20, 0x36, 0x66, 0x50, 0x6e, 0x92, 0x84, 0x97, 0x65, 0x60, + 0x94, 0x5a, 0x1b, 0xb6, 0x31, 0xe7, 0xd9, 0x23, 0x36, 0x7b, 0xd4, 0x63, 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, + 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x2d, 0x0a, 0x59, 0xda, 0xfb, 0xdc, 0x9c, 0xc8, 0xea, + 0x1b, 0x6d, 0x74, 0x11, 0xa9, 0x44, 0x90, 0x8d, 0xdf, 0x20, 0x60, 0x2f, 0x34, 0x3b, 0x20, 0xdb, 0x15, 0x3b, 0xa5, + 0x67, 0xd6, 0x04, 0x06, 0x5e, 0xbf, 0x55, 0x89, 0x66, 0x94, 0x15, 0xd1, 0x55, 0x46, 0x2e, 0x77, 0x21, 0x89, 0xce, + 0x42, 0xe2, 0xe7, 0x86, 0xa5, 0x75, 0x1d, 0xa2, 0x98, 0xd9, 0x6c, 0x78, 0xd5, 0xdd, 0x47, 0x8d, 0x6d, 0x65, 0x7c, + 0xaa, 0x6f, 0x6d, 0x1a, 0x99, 0x42, 0x5f, 0x87, 0x93, 0x7e, 0x1f, 0xfe, 0x6a, 0xfa, 0x81, 0xb7, 0x14, 0xfc, 0xc5, + 0x1e, 0x91, 0x3a, 0x61, 0x01, 0xc0, 0x11, 0xe6, 0xbc, 0x6a, 0x4e, 0xe0, 0x23, 0x36, 0xdb, 0x3e, 0x0a, 0x4f, 0x1b, + 0x33, 0x77, 0x17, 0xe2, 0xa5, 0x2a, 0xe9, 0x79, 0xf3, 0x64, 0x06, 0x62, 0x1d, 0x9a, 0xfd, 0x7a, 0xcb, 0xac, 0x3e, + 0x01, 0x88, 0xd4, 0xad, 0x75, 0x28, 0xc5, 0x8f, 0x4d, 0x97, 0xc9, 0x36, 0x65, 0x6d, 0x26, 0x4a, 0xa9, 0x48, 0x9a, + 0x8b, 0x00, 0xfa, 0x0d, 0xc3, 0x51, 0x03, 0xbc, 0xb7, 0x1e, 0x7b, 0x33, 0x34, 0xde, 0x98, 0x1a, 0x7a, 0xb6, 0xd5, + 0xcb, 0xdb, 0x51, 0x08, 0x33, 0x16, 0xd1, 0xad, 0x3b, 0x16, 0xc3, 0x53, 0xfa, 0x16, 0x2a, 0x7c, 0x1d, 0x62, 0x34, + 0x5d, 0x52, 0xd7, 0xd3, 0x8d, 0xda, 0x4a, 0x37, 0x84, 0xe6, 0x18, 0xc5, 0xc7, 0x6b, 0xdb, 0x1d, 0x35, 0x42, 0x7b, + 0x42, 0x79, 0x78, 0x4b, 0x2b, 0x7a, 0x63, 0x59, 0x04, 0x27, 0x3f, 0xf6, 0xf2, 0x13, 0x7a, 0xee, 0x09, 0x4c, 0x8a, + 0xb6, 0x06, 0xf0, 0x07, 0xd4, 0x0f, 0x67, 0xf5, 0xd4, 0x4a, 0x39, 0x3c, 0x85, 0x2f, 0xd9, 0x82, 0x5c, 0x41, 0x2f, + 0xd6, 0x98, 0xcd, 0x62, 0xd0, 0x41, 0xed, 0xed, 0x0e, 0x6f, 0x52, 0xca, 0x10, 0xad, 0xef, 0x1c, 0xc4, 0xd3, 0x3f, + 0x40, 0xd3, 0x07, 0x69, 0x61, 0x4a, 0x37, 0x28, 0xe0, 0x01, 0x7d, 0x53, 0xbf, 0x9f, 0xe3, 0x73, 0xed, 0x59, 0x62, + 0x61, 0x8f, 0x57, 0x84, 0xae, 0xbc, 0xb8, 0x51, 0x20, 0x6d, 0x76, 0xac, 0x02, 0xb0, 0x22, 0x09, 0x34, 0x22, 0x01, + 0x4b, 0x1d, 0x4f, 0x5c, 0xb6, 0x45, 0x03, 0x92, 0xa8, 0xa4, 0x90, 0x25, 0x92, 0xc0, 0x0f, 0x23, 0x08, 0x51, 0x14, + 0x83, 0xb8, 0x57, 0x2f, 0xaf, 0xb8, 0xa6, 0x06, 0x9c, 0x28, 0x82, 0x09, 0xd6, 0xe9, 0x14, 0x88, 0xad, 0xd8, 0xac, + 0xc1, 0xf3, 0xd2, 0x71, 0xe2, 0xc8, 0x12, 0xa0, 0x41, 0x9a, 0x2f, 0x9d, 0x76, 0xcb, 0xdb, 0x13, 0x2d, 0x55, 0x6c, + 0xe1, 0xbd, 0x58, 0x5a, 0xee, 0xb1, 0xf2, 0xb7, 0x03, 0xed, 0x85, 0xd5, 0x9e, 0x88, 0x1a, 0xac, 0xec, 0xda, 0x76, + 0x6d, 0x28, 0x0d, 0xd5, 0xbd, 0x72, 0x4c, 0x40, 0x45, 0xd7, 0x71, 0xb5, 0x8a, 0xb2, 0x11, 0xfc, 0xd9, 0xed, 0x82, + 0xc3, 0x00, 0x2c, 0x20, 0x7f, 0x79, 0xff, 0x53, 0x84, 0xe1, 0x99, 0x7e, 0x79, 0xff, 0xd3, 0x6e, 0xf7, 0x74, 0x3c, + 0x36, 0x5c, 0x81, 0x53, 0xeb, 0x00, 0x7f, 0x60, 0xd8, 0x06, 0xbb, 0x64, 0x77, 0xbb, 0xa7, 0xc0, 0x41, 0x28, 0xb6, + 0xc1, 0xec, 0x62, 0xe5, 0xc8, 0xa5, 0x58, 0x0d, 0xbd, 0x23, 0x01, 0xab, 0x6e, 0x8f, 0xa5, 0xd8, 0xa7, 0x3e, 0x2a, + 0x04, 0xa3, 0x5e, 0xf4, 0x2f, 0x3a, 0x05, 0x96, 0x14, 0x4c, 0x57, 0x83, 0x55, 0x55, 0xad, 0xcb, 0xe8, 0xf0, 0x30, + 0x5e, 0x67, 0xa3, 0x32, 0x83, 0x6d, 0x5e, 0x5e, 0x5f, 0x02, 0xa0, 0x42, 0x40, 0x1b, 0xef, 0x36, 0x22, 0x33, 0x2f, + 0x96, 0x74, 0x95, 0xe1, 0x9a, 0x04, 0xb3, 0x83, 0x9c, 0x5b, 0xdd, 0xe4, 0x94, 0xd8, 0x07, 0xb0, 0x39, 0xdc, 0xed, + 0x1a, 0xfc, 0xc2, 0x6c, 0xf4, 0x74, 0xbe, 0xca, 0xb4, 0x41, 0x27, 0x37, 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, + 0xc9, 0xf4, 0x45, 0x06, 0x7c, 0x1e, 0x7b, 0x23, 0x42, 0x9f, 0xe5, 0x6a, 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, + 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x2a, 0x23, 0xbe, 0x4d, 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x46, 0x78, + 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x02, 0x85, 0xa8, 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, + 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x92, 0x3a, 0x73, 0x19, 0x5f, 0xb8, 0xf7, 0xc2, 0x97, 0x99, 0xdc, 0x4a, 0x00, + 0x45, 0x52, 0xb5, 0xff, 0xfc, 0x09, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, 0xe8, 0xfd, 0x0c, 0x35, 0x39, 0x82, 0x80, + 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, 0x6d, 0x55, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, + 0x4f, 0x37, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, 0x1b, 0x21, 0xeb, 0xe7, 0x66, 0x17, 0x7e, + 0x2a, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, + 0x1e, 0x73, 0x82, 0x3f, 0x39, 0x7a, 0x42, 0xe8, 0xad, 0x9c, 0x96, 0x08, 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, + 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, 0x6c, 0xd9, 0x6f, 0x4c, 0xd9, 0x92, 0x6c, + 0x05, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbd, 0xdf, 0xa0, 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, + 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, 0x9c, 0x87, 0xed, 0x76, 0x42, 0x7c, 0x09, + 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x28, + 0xa0, 0x27, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x4e, 0xf8, 0x20, 0x18, 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, + 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x97, 0x05, 0x43, 0x58, 0xa1, 0x3f, 0x53, 0x36, 0xf9, 0xfa, 0x1b, 0x37, 0xbf, + 0xe7, 0x5a, 0xcc, 0x0e, 0x42, 0x71, 0x7b, 0x3d, 0x01, 0xe2, 0x57, 0xf1, 0x2b, 0xb0, 0xae, 0xd6, 0x12, 0x6f, 0x37, + 0x3d, 0x7f, 0x08, 0x5f, 0x8e, 0x6e, 0x3f, 0x29, 0xcd, 0x27, 0x10, 0xa4, 0xc6, 0x49, 0xca, 0xdd, 0x77, 0x1f, 0xa5, + 0xab, 0x08, 0x46, 0x0b, 0x10, 0xeb, 0xee, 0xad, 0xe4, 0xac, 0x29, 0xfc, 0xc7, 0x3a, 0xdf, 0x63, 0xec, 0x10, 0x79, + 0x8a, 0xd3, 0xdf, 0x00, 0xc3, 0xbe, 0xf3, 0x6f, 0x65, 0xd6, 0x90, 0xe8, 0x5c, 0x7d, 0x04, 0xf4, 0x7f, 0xac, 0xc7, + 0xef, 0x04, 0x25, 0x7d, 0x49, 0x9c, 0x23, 0x5c, 0x11, 0x2f, 0xd1, 0x54, 0xaf, 0x37, 0xae, 0xe9, 0x5f, 0x85, 0x79, + 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0xab, 0x68, 0x08, 0xba, 0x7f, 0xc3, 0xbd, 0xf1, 0xab, + 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, 0x1b, 0xc6, 0x82, 0x8d, 0x50, 0xe6, 0xab, + 0x69, 0x30, 0xdf, 0xd6, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x69, 0x9c, 0xb0, 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, + 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, + 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x49, 0x05, 0xbb, 0xcc, 0x57, 0x52, 0xfc, 0xd1, 0x92, 0x64, 0x63, + 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, + 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x13, + 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0x87, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, + 0x53, 0xba, 0x9b, 0xd3, 0xe1, 0xcb, 0x82, 0x0c, 0xff, 0x04, 0xef, 0xae, 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, + 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, + 0xed, 0x1b, 0x8d, 0xd9, 0x94, 0xfb, 0x1f, 0xc0, 0x88, 0x6a, 0x69, 0xbb, 0x1d, 0xf0, 0xd5, 0x08, 0x0d, 0xb6, 0x53, + 0x37, 0xd8, 0xfd, 0xbe, 0x49, 0x9b, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, 0x53, 0xda, 0xac, 0x94, 0x41, 0x6d, 0x57, + 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x8a, 0xc6, 0x56, 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, + 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, 0xdd, 0x2e, 0x84, 0x08, 0x1c, 0xc5, 0x70, + 0x32, 0x0f, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0x57, 0xb1, 0xc8, 0x96, 0x0a, 0xb1, 0xc7, 0xdf, 0x49, + 0xbf, 0x16, 0x8a, 0x53, 0xee, 0xfd, 0x2a, 0xc8, 0xf6, 0xb7, 0x14, 0x63, 0x0e, 0x3a, 0xcd, 0x66, 0x06, 0x12, 0xd6, + 0x93, 0x8a, 0xa8, 0x75, 0x64, 0x67, 0x03, 0x54, 0xb1, 0x68, 0x0a, 0x0b, 0xea, 0x16, 0x4f, 0xac, 0x67, 0xf4, 0x1e, + 0x54, 0x82, 0xa8, 0x16, 0xec, 0xc6, 0x70, 0xad, 0xfd, 0x25, 0x42, 0x49, 0x39, 0x69, 0x32, 0x33, 0x56, 0x34, 0x58, + 0x80, 0x90, 0x34, 0x2e, 0xab, 0xd7, 0x32, 0xcd, 0x2e, 0x32, 0x40, 0x4c, 0x70, 0xfe, 0x73, 0xb2, 0xf1, 0xe6, 0x99, + 0x9a, 0x97, 0xae, 0xc4, 0xb9, 0x85, 0xf9, 0xe8, 0x7a, 0x4b, 0x0b, 0x12, 0x15, 0x40, 0xa3, 0x7c, 0x2d, 0xcf, 0xdf, + 0xf7, 0xac, 0x42, 0xf6, 0x3f, 0x9c, 0x2a, 0xdb, 0x21, 0x3e, 0x63, 0x15, 0xf1, 0x4e, 0xeb, 0x4a, 0x89, 0x34, 0x3a, + 0xda, 0x06, 0xc4, 0xb0, 0x65, 0xdf, 0xa2, 0x86, 0x0f, 0xc2, 0x0c, 0x3a, 0xc9, 0x0f, 0x7a, 0x46, 0xc7, 0xd6, 0x40, + 0xd2, 0xd7, 0x22, 0xf8, 0x1a, 0x1d, 0xe9, 0x44, 0x99, 0x46, 0x62, 0x0a, 0x89, 0x7e, 0xbd, 0xd0, 0x1a, 0xcb, 0x28, + 0xfb, 0x8a, 0xfc, 0xef, 0x75, 0xf7, 0x7e, 0x15, 0xbb, 0x1d, 0x4c, 0xb2, 0xe7, 0x71, 0x05, 0x9b, 0x1a, 0xb5, 0x42, + 0x38, 0x3b, 0x27, 0x15, 0x6a, 0xc7, 0x7a, 0x61, 0x09, 0xe4, 0x01, 0x6c, 0x45, 0x1a, 0x94, 0x41, 0xb2, 0xbf, 0x8a, + 0x85, 0x58, 0x3a, 0x51, 0x8e, 0x54, 0x78, 0x5f, 0x72, 0x94, 0x72, 0xb8, 0x8a, 0x85, 0x05, 0x43, 0x7e, 0x75, 0x74, + 0x51, 0xc8, 0x2b, 0x90, 0x94, 0x18, 0x86, 0xca, 0xf2, 0xba, 0xb8, 0x6a, 0x4b, 0x42, 0x7b, 0x67, 0x00, 0xc2, 0x52, + 0x80, 0xe0, 0xa5, 0x51, 0x43, 0xcc, 0xb6, 0x6a, 0x77, 0x45, 0xf7, 0x92, 0x03, 0xea, 0x74, 0xd7, 0x6e, 0xbd, 0x29, + 0xdb, 0x6c, 0x2b, 0x2e, 0xfc, 0x03, 0x4a, 0x3f, 0xe1, 0x83, 0xc2, 0xa7, 0x12, 0xb8, 0xf1, 0xd5, 0x26, 0xcb, 0x2e, + 0xee, 0x70, 0xe9, 0x57, 0x8d, 0xf1, 0xeb, 0xf7, 0x7b, 0x6a, 0x21, 0x34, 0x52, 0x81, 0xf9, 0xf6, 0x99, 0xa9, 0xca, + 0x68, 0x4a, 0xed, 0x25, 0xb8, 0x72, 0xf6, 0x23, 0xa8, 0x88, 0xeb, 0x8a, 0x4c, 0xa6, 0x06, 0xe8, 0xc0, 0xcb, 0x0a, + 0xb7, 0xb2, 0x00, 0x8f, 0x9d, 0x80, 0xec, 0x76, 0x3c, 0x0c, 0xf4, 0xa1, 0x13, 0xf8, 0x5b, 0xf2, 0x14, 0x99, 0x35, + 0xfb, 0xf8, 0xb3, 0x16, 0xfc, 0x63, 0x0b, 0x7e, 0x42, 0x71, 0xa7, 0x95, 0xf9, 0xb7, 0xd2, 0xba, 0xc5, 0xfd, 0x7b, + 0x99, 0x26, 0x14, 0x95, 0x09, 0xb5, 0x5f, 0xe9, 0xbf, 0x4c, 0xb0, 0x24, 0x95, 0xfd, 0x83, 0x84, 0x0f, 0xe6, 0x8d, + 0x27, 0xd6, 0x78, 0x32, 0x9c, 0x6e, 0xa5, 0x61, 0x08, 0x50, 0xe8, 0xe7, 0x65, 0xae, 0xa8, 0x7e, 0xfe, 0x79, 0xc3, + 0x37, 0xbc, 0xd9, 0x62, 0x9b, 0xf4, 0x40, 0x83, 0xbd, 0x3c, 0x9a, 0x52, 0x38, 0x89, 0x3a, 0x37, 0x12, 0x75, 0x51, + 0xb3, 0x0c, 0xd5, 0x09, 0x5e, 0xcd, 0x53, 0x3d, 0xec, 0xcd, 0x44, 0xb4, 0x56, 0x52, 0x96, 0x18, 0xb0, 0xd6, 0x91, + 0x87, 0xe4, 0x6e, 0xad, 0xe3, 0x4e, 0x43, 0x5d, 0x9a, 0x42, 0x09, 0xb0, 0xc2, 0x05, 0x38, 0x82, 0x7e, 0x2a, 0x42, + 0x0e, 0xd7, 0x54, 0xa5, 0x5f, 0xd0, 0x94, 0x3c, 0xf1, 0x14, 0xb5, 0x5a, 0x91, 0x6e, 0x3f, 0xca, 0xb1, 0x1b, 0xbe, + 0x71, 0x42, 0x4e, 0x8c, 0xd0, 0xdf, 0x1d, 0x4b, 0x39, 0x43, 0x8b, 0x07, 0x75, 0x82, 0xf5, 0xf2, 0x96, 0x02, 0xc5, + 0x1c, 0x5d, 0x56, 0x5d, 0xf3, 0x0a, 0x6d, 0x5f, 0x56, 0xfd, 0x7e, 0x6e, 0xeb, 0x49, 0xd9, 0x6c, 0xbb, 0x32, 0xfb, + 0x10, 0x15, 0x53, 0xb8, 0xeb, 0x13, 0xcd, 0x5f, 0x85, 0xfa, 0xaa, 0x2d, 0x73, 0x3e, 0xe2, 0x88, 0x8b, 0x91, 0x93, + 0xfa, 0x67, 0x35, 0xf5, 0x4a, 0xdc, 0xaf, 0x2a, 0xf9, 0x4e, 0x18, 0x2b, 0x46, 0x07, 0xd4, 0x9f, 0x2a, 0x95, 0xf7, + 0x8b, 0x02, 0xe0, 0x9e, 0x04, 0xfb, 0x0b, 0xec, 0x2b, 0x34, 0xc2, 0x6f, 0x4b, 0xc0, 0xbf, 0x55, 0xdc, 0x80, 0x55, + 0x60, 0x80, 0xd1, 0x64, 0x7b, 0x4e, 0x13, 0x38, 0xe0, 0x84, 0x56, 0x51, 0x50, 0x61, 0x86, 0x86, 0xda, 0xc2, 0xe8, + 0x29, 0xca, 0xb8, 0x55, 0x66, 0xef, 0xc6, 0xd8, 0x69, 0x81, 0xd7, 0xf0, 0xe7, 0xf3, 0x42, 0x0f, 0x1b, 0x75, 0x90, + 0x1e, 0x9d, 0xc4, 0xf4, 0xc7, 0x2d, 0x9c, 0xdc, 0x2c, 0x9c, 0x55, 0xcd, 0x12, 0xe8, 0x0e, 0x5c, 0x10, 0xe3, 0x7e, + 0x3f, 0x87, 0x23, 0xd3, 0x8c, 0x7c, 0xc1, 0x72, 0x1a, 0xb3, 0x15, 0xd5, 0x9e, 0x76, 0x97, 0x55, 0x98, 0xd3, 0x95, + 0x95, 0xf1, 0xa6, 0x0c, 0x54, 0x46, 0xbb, 0x5d, 0x08, 0x7f, 0xba, 0xad, 0x5d, 0xd2, 0xc5, 0x0a, 0x32, 0xc0, 0x1f, + 0x90, 0x88, 0x22, 0xf6, 0xf5, 0xbf, 0xd5, 0x38, 0xa5, 0x27, 0x4a, 0x6b, 0x96, 0xd0, 0x0d, 0xd3, 0xf5, 0xd3, 0x0b, + 0xb6, 0x69, 0x2c, 0x85, 0xdd, 0x2e, 0x6c, 0x26, 0x30, 0xcd, 0xb9, 0x92, 0xe9, 0x05, 0xea, 0xa4, 0x80, 0x8a, 0x85, + 0x17, 0xb8, 0xfc, 0x52, 0x42, 0xa1, 0xb9, 0x8b, 0xd5, 0xd2, 0x28, 0x31, 0xa1, 0x55, 0xf2, 0xf3, 0x87, 0xca, 0x7c, + 0x6d, 0x3c, 0xe2, 0xfe, 0x95, 0x86, 0x89, 0x29, 0x12, 0x15, 0xa2, 0xf3, 0x5f, 0x41, 0x96, 0x23, 0x00, 0xc7, 0xf2, + 0x54, 0xd6, 0xf4, 0xc7, 0x14, 0xe2, 0xa0, 0x43, 0x83, 0xde, 0x15, 0xf2, 0x2a, 0x2b, 0x79, 0x88, 0xf7, 0x04, 0x4f, + 0x33, 0x7a, 0xbf, 0xc1, 0x87, 0xb6, 0xf6, 0xe8, 0x09, 0xb2, 0xf5, 0x94, 0xfb, 0xf5, 0x77, 0x22, 0x5c, 0x40, 0xb4, + 0xca, 0x25, 0xd5, 0xea, 0x6a, 0x07, 0x40, 0xe5, 0xd9, 0x5e, 0x3d, 0x82, 0xd3, 0x4d, 0x5f, 0xdf, 0xaa, 0xd0, 0x99, + 0x03, 0x48, 0x7b, 0x48, 0xd6, 0x35, 0xd7, 0x3b, 0xc0, 0x1d, 0x89, 0xd5, 0x06, 0x68, 0xac, 0xdb, 0x9a, 0x9d, 0xf6, + 0x28, 0x1e, 0x13, 0x99, 0x19, 0x8b, 0x14, 0x63, 0xee, 0xd6, 0x69, 0x51, 0xb4, 0x45, 0x33, 0x84, 0xfd, 0xbb, 0x0e, + 0xdf, 0xb4, 0x22, 0xac, 0xdf, 0x6f, 0xfb, 0x02, 0xa3, 0x61, 0xcc, 0xb5, 0x7b, 0x9e, 0xa1, 0x1b, 0x36, 0xd8, 0x46, + 0xce, 0x43, 0xe4, 0xc3, 0x4c, 0x1d, 0x88, 0xb2, 0xb6, 0x06, 0x6c, 0x8f, 0xb8, 0xde, 0xb4, 0x8a, 0x9f, 0x57, 0x31, + 0x67, 0x7b, 0xd6, 0x38, 0xa5, 0xf5, 0x35, 0xae, 0x39, 0xae, 0x0a, 0x11, 0xb5, 0xf5, 0x8c, 0x87, 0x61, 0xe7, 0x4b, + 0xdc, 0x99, 0x15, 0x06, 0x2f, 0xc2, 0x52, 0xc9, 0x5e, 0xe5, 0xfa, 0x73, 0xd8, 0xe2, 0x20, 0x95, 0x2f, 0xbd, 0xfe, + 0xfe, 0xcb, 0x17, 0x5f, 0xa0, 0x9b, 0x9a, 0xf3, 0x23, 0x08, 0x32, 0x81, 0x0e, 0x59, 0x4a, 0xf5, 0xf8, 0x5d, 0x01, + 0xd4, 0x1e, 0xe6, 0xe1, 0xbb, 0x82, 0x89, 0xf8, 0x3a, 0xbb, 0x8c, 0x2b, 0x59, 0x8c, 0xae, 0xb9, 0x48, 0x65, 0x61, + 0xa5, 0xc6, 0xc1, 0xc9, 0x7a, 0x9d, 0xf3, 0x00, 0x4c, 0xe5, 0x2d, 0xa3, 0x6c, 0x2b, 0xcb, 0xf4, 0xe0, 0x6a, 0x79, + 0x7a, 0xa5, 0x45, 0xe7, 0xe5, 0xf5, 0x65, 0x10, 0xe1, 0xaf, 0x73, 0xf3, 0xe3, 0x2a, 0x2e, 0x3f, 0x06, 0x91, 0xb5, + 0xa9, 0x33, 0x3f, 0x50, 0x2a, 0x0f, 0xfe, 0x53, 0x20, 0xd3, 0xfd, 0xae, 0x00, 0xcb, 0x6c, 0x5b, 0xf1, 0x71, 0x8c, + 0xb5, 0x0e, 0x27, 0x64, 0xae, 0x4a, 0xf4, 0xde, 0x25, 0x9b, 0x02, 0xac, 0xfd, 0x14, 0x96, 0xb1, 0xca, 0x35, 0xc7, + 0xca, 0x54, 0x45, 0x66, 0x56, 0x36, 0xec, 0x30, 0xb4, 0x4e, 0x34, 0x0b, 0xf4, 0x16, 0xd0, 0x0f, 0xe4, 0xf0, 0x92, + 0x96, 0x1b, 0xe6, 0xf9, 0xd8, 0x34, 0x5e, 0x3f, 0x3a, 0xbc, 0x74, 0x0b, 0xf6, 0xd6, 0xde, 0xc9, 0x51, 0x98, 0x08, + 0x9e, 0xb5, 0x66, 0x7c, 0x91, 0x67, 0x05, 0xac, 0x9c, 0xc9, 0x78, 0x4c, 0xbd, 0xa5, 0xd5, 0xba, 0x39, 0x3a, 0x24, + 0xd7, 0xec, 0x71, 0xf5, 0x98, 0x93, 0x43, 0xde, 0x32, 0xb5, 0x6d, 0x5b, 0xc7, 0x79, 0x9a, 0x7c, 0x65, 0xba, 0x2f, + 0x36, 0x36, 0x22, 0xba, 0x72, 0xee, 0x73, 0x5e, 0xc1, 0xad, 0x6f, 0x4a, 0x43, 0xaf, 0x25, 0x00, 0xd1, 0x69, 0x03, + 0xfe, 0x82, 0x95, 0x9b, 0x51, 0xc5, 0xcb, 0x0a, 0x24, 0x2c, 0x28, 0xc2, 0x9b, 0x62, 0x6f, 0x0a, 0x77, 0xe3, 0xf4, + 0x1c, 0x76, 0xe0, 0x62, 0x8a, 0xee, 0x38, 0x31, 0x99, 0x97, 0x46, 0x2b, 0x1a, 0xe9, 0x5f, 0xae, 0x2f, 0xb1, 0xee, + 0x8b, 0x56, 0xe6, 0xd9, 0x9c, 0x0a, 0x8b, 0xdd, 0x55, 0x2e, 0x9d, 0xa8, 0xdf, 0x32, 0xe1, 0xca, 0x95, 0x20, 0x20, + 0xd3, 0x82, 0xf5, 0x0a, 0xb3, 0x8b, 0xe4, 0x06, 0x08, 0x19, 0x18, 0xbe, 0x06, 0x1b, 0x51, 0x72, 0x63, 0x05, 0xeb, + 0xdd, 0xf3, 0x75, 0x82, 0x90, 0x82, 0x07, 0x6e, 0x82, 0x7e, 0x68, 0xdd, 0xbc, 0x1d, 0x25, 0xca, 0x20, 0x1e, 0xb7, + 0x76, 0xca, 0x41, 0x02, 0x01, 0xb8, 0xa7, 0x2a, 0x04, 0x87, 0x02, 0x59, 0x07, 0x57, 0x33, 0x8e, 0xe0, 0xea, 0xca, + 0x99, 0x8b, 0x1b, 0x80, 0x75, 0xe5, 0xcf, 0x65, 0x83, 0x0b, 0xeb, 0x11, 0x55, 0xe6, 0x8c, 0x53, 0x0c, 0x62, 0x64, + 0x09, 0xfa, 0xda, 0x52, 0xda, 0x4b, 0xd0, 0x34, 0x5e, 0xb1, 0xb5, 0xf2, 0x01, 0xa0, 0xe7, 0x6c, 0xad, 0x8c, 0xfd, + 0xf1, 0xeb, 0x33, 0xb6, 0xd6, 0xd2, 0xe0, 0xe9, 0xd5, 0xfc, 0x7c, 0x7e, 0x36, 0x60, 0x47, 0x51, 0xa8, 0x0d, 0x18, + 0x02, 0x87, 0xc4, 0x1f, 0x0c, 0x42, 0x8d, 0x77, 0x32, 0x50, 0x01, 0xb1, 0x88, 0xc7, 0x63, 0x23, 0x6e, 0x56, 0x38, + 0x1e, 0x62, 0xf0, 0xab, 0xe6, 0x0b, 0x12, 0x10, 0x6a, 0x4a, 0x43, 0x97, 0xc7, 0x70, 0x38, 0x39, 0x98, 0x40, 0x2a, + 0x66, 0x66, 0xaa, 0x30, 0x36, 0x26, 0x11, 0xc4, 0x3b, 0xed, 0xac, 0x17, 0xca, 0xed, 0xae, 0xd1, 0x40, 0xae, 0x0c, + 0x3e, 0xab, 0xe2, 0xc9, 0xc1, 0xb0, 0xab, 0x62, 0x1c, 0x85, 0x6b, 0xa3, 0x7c, 0x3b, 0x3b, 0x06, 0xf0, 0xda, 0xb3, + 0xa1, 0x2f, 0x97, 0x38, 0x3b, 0x7c, 0x42, 0x1e, 0x3f, 0x21, 0xf4, 0x8c, 0x9d, 0x7d, 0xf1, 0x84, 0x9e, 0x29, 0x72, + 0x72, 0x30, 0x89, 0xae, 0x99, 0xc5, 0x7c, 0x39, 0x52, 0x4d, 0xa0, 0x97, 0xa3, 0x8d, 0x50, 0x0b, 0x4c, 0x3b, 0x34, + 0x85, 0xdf, 0x8e, 0x0f, 0x82, 0xc1, 0x75, 0xbb, 0xe9, 0xd7, 0xed, 0xb6, 0x7a, 0x5e, 0x5d, 0x07, 0x47, 0xd1, 0x7e, + 0x31, 0x93, 0x6f, 0xc6, 0x07, 0x6e, 0x0e, 0xb0, 0xbe, 0x87, 0xc7, 0xc4, 0x34, 0x69, 0x6f, 0x54, 0xfc, 0x9a, 0xbe, + 0xc2, 0x3e, 0x34, 0x8b, 0xec, 0xe8, 0xc3, 0xf0, 0xdf, 0xea, 0x44, 0x7d, 0xf6, 0xc5, 0x11, 0x90, 0x23, 0x90, 0x81, + 0x62, 0x89, 0x60, 0x86, 0x03, 0x4d, 0x01, 0x05, 0x99, 0x1e, 0x77, 0xaa, 0x87, 0x5f, 0x8d, 0x9a, 0x9a, 0x91, 0x6b, + 0x98, 0x1a, 0x6c, 0x0b, 0x7e, 0xa0, 0xba, 0xa1, 0xbf, 0xd1, 0xe8, 0x46, 0xda, 0xc9, 0xcc, 0xbc, 0xa4, 0x36, 0xae, + 0xdb, 0x35, 0x04, 0x30, 0x76, 0xf0, 0x82, 0x92, 0x7d, 0x79, 0x7c, 0x79, 0x80, 0xab, 0x08, 0x50, 0xb2, 0x58, 0xf0, + 0xe5, 0xe0, 0x52, 0x6f, 0xee, 0x83, 0x80, 0x0c, 0xbe, 0x0c, 0x66, 0x5f, 0x0e, 0xe4, 0x20, 0x38, 0x3e, 0xbc, 0x9c, + 0x05, 0xce, 0xb8, 0x1f, 0x42, 0x3c, 0xaa, 0x8a, 0x62, 0x26, 0x4c, 0x15, 0x89, 0xad, 0x3d, 0xb7, 0xf5, 0x2a, 0xe3, + 0x33, 0x9a, 0x4e, 0x2d, 0xf2, 0x77, 0x98, 0xb2, 0xd8, 0xfc, 0x0e, 0x26, 0xfc, 0x2a, 0x88, 0x5c, 0x10, 0xd4, 0x79, + 0x1e, 0xc5, 0x74, 0xc5, 0x6e, 0x45, 0x98, 0xd2, 0xe4, 0x30, 0x27, 0x24, 0x0a, 0x57, 0x0a, 0x3c, 0x4f, 0xbd, 0x4e, + 0x20, 0x8e, 0xab, 0xfb, 0xfc, 0x56, 0x84, 0x2b, 0x9a, 0x1f, 0x26, 0xa4, 0x55, 0x84, 0x8b, 0xc8, 0xb2, 0xad, 0xe9, + 0x05, 0x0b, 0xd7, 0xf4, 0x12, 0x98, 0x29, 0xb9, 0x09, 0x2f, 0x81, 0xcb, 0xdb, 0x2c, 0xd6, 0x4b, 0x76, 0xd9, 0x90, + 0xbe, 0x19, 0xbe, 0xf8, 0xc2, 0xfa, 0xe4, 0x01, 0x0f, 0xe9, 0xfc, 0xf0, 0x52, 0xb0, 0x01, 0xb8, 0xce, 0xf8, 0xcd, + 0x77, 0xf2, 0x56, 0xcf, 0x4b, 0x7b, 0x8a, 0x71, 0x66, 0xda, 0x89, 0x49, 0x3b, 0x21, 0xf7, 0xef, 0xdb, 0xdb, 0xd8, + 0x9c, 0xec, 0x65, 0xb4, 0x51, 0x2e, 0xab, 0x96, 0x21, 0x29, 0x36, 0x0c, 0xf9, 0x7b, 0x94, 0x9c, 0x5a, 0x81, 0x27, + 0xbb, 0xe0, 0x55, 0xb2, 0xf2, 0x0f, 0x2a, 0x6b, 0x35, 0x60, 0x8f, 0x11, 0xcb, 0x42, 0xe1, 0xd8, 0xbf, 0xce, 0x58, + 0xb1, 0xf1, 0x05, 0x1a, 0x31, 0x72, 0x6f, 0xaf, 0x33, 0xe6, 0xc5, 0x5c, 0x4d, 0x36, 0x5e, 0xa8, 0x3a, 0x2f, 0x3d, + 0x6f, 0xf1, 0x5e, 0x4e, 0xa9, 0x61, 0x24, 0xa2, 0x07, 0x63, 0x65, 0x46, 0xa9, 0x12, 0xb5, 0x06, 0x8d, 0x08, 0x36, + 0x76, 0xc1, 0x2f, 0xc1, 0x09, 0x95, 0x7b, 0xea, 0x6c, 0xdf, 0x4e, 0xa9, 0xf4, 0x80, 0x65, 0xa9, 0x51, 0x95, 0xbb, + 0x65, 0x26, 0x59, 0x35, 0x08, 0x46, 0x7f, 0x94, 0x52, 0xcc, 0xf1, 0xce, 0xc8, 0x82, 0x29, 0x58, 0x09, 0xaa, 0x5a, + 0x86, 0xe5, 0x90, 0xa3, 0x16, 0xcf, 0xf8, 0xa4, 0x4a, 0xfd, 0xa3, 0x23, 0x48, 0xee, 0x6a, 0xd3, 0x0a, 0x92, 0xfb, + 0x64, 0xfc, 0x44, 0x0f, 0x74, 0xba, 0xd1, 0x8e, 0x87, 0x3e, 0xbf, 0x8d, 0xf8, 0xda, 0xba, 0xf7, 0x54, 0x6b, 0x15, + 0xca, 0x40, 0x8b, 0x15, 0x95, 0x2b, 0xb5, 0xa4, 0xf7, 0xbb, 0x08, 0x80, 0x45, 0x6c, 0xcc, 0xc6, 0xfb, 0xb6, 0x59, + 0x21, 0x68, 0x74, 0xd9, 0x6c, 0x1b, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, 0xd0, 0x78, 0xc6, 0xca, 0x7e, 0x3f, 0x9f, + 0x01, 0x3d, 0xd5, 0x46, 0x4c, 0x05, 0x1c, 0xf9, 0x9f, 0x5b, 0x91, 0x29, 0x0a, 0x6c, 0xd6, 0xd4, 0xdd, 0x1a, 0xcb, + 0x48, 0xf4, 0x65, 0x4a, 0x97, 0x27, 0x3c, 0x03, 0xa6, 0xcd, 0xa6, 0xe5, 0xb8, 0xb2, 0xaf, 0x38, 0xf2, 0x54, 0x58, + 0x56, 0x9c, 0x57, 0xe1, 0x78, 0xeb, 0xf1, 0x0d, 0x0e, 0x0d, 0x9b, 0x76, 0xe1, 0x0f, 0x21, 0x2c, 0x84, 0xd7, 0x19, + 0xdc, 0x46, 0xb4, 0x9d, 0x04, 0x2a, 0x6f, 0xcc, 0x75, 0x42, 0xd9, 0xdc, 0x6e, 0x36, 0x9e, 0x41, 0x3a, 0x31, 0x07, + 0x4a, 0x35, 0x82, 0xd6, 0x68, 0x16, 0x54, 0x8d, 0x78, 0xe4, 0x78, 0x78, 0x67, 0x10, 0xab, 0xe5, 0x4b, 0x9a, 0x4a, + 0xd1, 0x00, 0x8c, 0x0b, 0xe0, 0xf2, 0xf4, 0xcb, 0xfb, 0x9f, 0x4e, 0x79, 0x5c, 0x24, 0xab, 0x77, 0x71, 0x11, 0x5f, + 0x95, 0xe1, 0x56, 0x8d, 0x51, 0x5c, 0x93, 0xa9, 0x18, 0x30, 0x69, 0x56, 0x52, 0x73, 0x57, 0x6a, 0x42, 0x8c, 0x75, + 0x26, 0x9b, 0xb2, 0x92, 0x57, 0x8d, 0x4a, 0x37, 0x45, 0x86, 0x1f, 0xb7, 0x7c, 0x4e, 0x0f, 0x01, 0xc8, 0xd3, 0xb8, + 0x90, 0x46, 0x52, 0x17, 0x62, 0xcc, 0x45, 0xbc, 0xae, 0x8f, 0xc7, 0x8d, 0xae, 0x97, 0xec, 0xe9, 0xf8, 0xab, 0xe9, + 0xeb, 0x2c, 0xcc, 0x06, 0x82, 0x8c, 0xaa, 0x15, 0x17, 0x2d, 0x53, 0x4e, 0x65, 0x12, 0x80, 0x3e, 0x9e, 0x3d, 0xc6, + 0x8e, 0xc6, 0x63, 0xb2, 0x6d, 0x8b, 0x07, 0x78, 0xb8, 0xda, 0x84, 0x05, 0x99, 0xeb, 0x3a, 0xa2, 0x40, 0xf0, 0xdb, + 0x2a, 0x00, 0x24, 0x47, 0x5b, 0x95, 0xe1, 0xd2, 0xd8, 0xd3, 0xf1, 0x84, 0x4a, 0xec, 0x76, 0x48, 0x6a, 0xaf, 0x42, + 0x37, 0xf3, 0xd2, 0xf7, 0x28, 0x92, 0xc6, 0x65, 0x69, 0xaf, 0x52, 0xa9, 0xf6, 0xcc, 0xdc, 0x75, 0x0d, 0x62, 0x30, + 0x84, 0xba, 0xee, 0xd2, 0xab, 0x7b, 0xbf, 0xb9, 0xd6, 0x6c, 0x07, 0xbc, 0xd7, 0xa0, 0x19, 0x4a, 0xde, 0x62, 0xde, + 0xba, 0x22, 0x6a, 0xba, 0xde, 0x80, 0x59, 0x31, 0xca, 0x96, 0xa2, 0x74, 0x43, 0x41, 0x29, 0x18, 0x5d, 0x6c, 0xbc, + 0x85, 0xfb, 0x5a, 0x36, 0x2e, 0x2c, 0x99, 0x5e, 0x2d, 0x4a, 0x4a, 0xa8, 0x6e, 0x2a, 0x46, 0x4a, 0x18, 0x29, 0x0d, + 0x4f, 0xe5, 0x7b, 0x81, 0xc7, 0x79, 0x1e, 0x44, 0x2d, 0x2f, 0xb0, 0x93, 0x8a, 0x9c, 0x80, 0xa3, 0x97, 0xc9, 0x69, + 0x28, 0xf0, 0x8f, 0x99, 0x02, 0x31, 0x1d, 0xaa, 0xfb, 0x0d, 0x6e, 0xfe, 0x7f, 0x14, 0x2c, 0xf0, 0xf8, 0xd6, 0x4b, + 0xdc, 0x46, 0xff, 0x28, 0x7c, 0x5a, 0xfa, 0x4c, 0xfa, 0xae, 0x2e, 0x9e, 0xb4, 0x37, 0x1b, 0x25, 0xab, 0x2c, 0x4f, + 0xdf, 0xc8, 0x94, 0x83, 0xc8, 0x0c, 0xad, 0x41, 0xd9, 0x4c, 0x34, 0x6e, 0x78, 0x60, 0xc4, 0xd8, 0xb8, 0xf1, 0xfd, + 0x98, 0x81, 0x6c, 0x18, 0xac, 0xbe, 0x59, 0x2a, 0x93, 0xcd, 0x15, 0x60, 0x8a, 0x28, 0xf9, 0xc9, 0x8b, 0x9c, 0xc3, + 0x53, 0xa8, 0xaf, 0x5f, 0xe0, 0x36, 0x57, 0xfa, 0x3e, 0xe7, 0x3f, 0x66, 0xf4, 0x47, 0x04, 0x3a, 0x89, 0xd7, 0x20, + 0xf7, 0x78, 0x06, 0x75, 0x23, 0x4c, 0x2d, 0xc7, 0xe0, 0x40, 0x88, 0x06, 0x22, 0x2a, 0x16, 0x28, 0xa8, 0x0b, 0x03, + 0xac, 0xa1, 0x2e, 0x98, 0xc3, 0xf3, 0x5c, 0x26, 0x1f, 0xa7, 0xc6, 0x67, 0x7e, 0x18, 0x63, 0xcc, 0xe4, 0x60, 0x10, + 0x56, 0xf3, 0x60, 0x38, 0x1e, 0x4d, 0x8e, 0x9e, 0xc2, 0xb9, 0x1d, 0x8c, 0x03, 0x32, 0x08, 0xea, 0x72, 0x1d, 0x0b, + 0x5a, 0x5e, 0x5f, 0xda, 0x32, 0xf0, 0xe3, 0x3a, 0x18, 0xfc, 0xa3, 0xf0, 0x14, 0xef, 0xa0, 0x39, 0x39, 0x93, 0x21, + 0xd8, 0xd8, 0x6f, 0x08, 0x48, 0xca, 0x7a, 0x9a, 0x9f, 0xd4, 0x87, 0x1b, 0x53, 0xda, 0x3f, 0x73, 0x78, 0xc1, 0x61, + 0x87, 0x04, 0x0a, 0xa4, 0xf1, 0x34, 0x1b, 0xbd, 0x52, 0x8a, 0xdc, 0x77, 0x05, 0x87, 0x3b, 0x73, 0xcf, 0x99, 0x1e, + 0x39, 0x85, 0x44, 0x33, 0x0b, 0xb8, 0x91, 0xbf, 0x12, 0xd7, 0x71, 0x9e, 0xa5, 0x07, 0xcd, 0x37, 0x07, 0xe5, 0x9d, + 0xa8, 0xe2, 0xdb, 0x51, 0x60, 0xac, 0x09, 0xb9, 0xaf, 0x7a, 0x02, 0xf4, 0x04, 0xd8, 0x02, 0x60, 0x40, 0xbc, 0x67, + 0x66, 0x32, 0xe7, 0x11, 0x78, 0x04, 0x36, 0x7d, 0x20, 0x8b, 0x3b, 0xe7, 0x92, 0xe4, 0x6f, 0xa6, 0xd2, 0x5e, 0xf5, + 0xca, 0xbd, 0x82, 0xac, 0x57, 0x5b, 0xb9, 0xef, 0xd6, 0x67, 0xdf, 0x74, 0x78, 0x05, 0x9e, 0x4b, 0x70, 0x8b, 0xec, + 0xf7, 0x9b, 0x82, 0x4a, 0x61, 0x54, 0xc4, 0x7b, 0xc9, 0x35, 0xfa, 0xb7, 0x7b, 0x63, 0xa3, 0x48, 0x6e, 0xf9, 0xf0, + 0x00, 0xea, 0x4c, 0xde, 0x15, 0xb7, 0x73, 0x88, 0xda, 0xba, 0x1b, 0x0f, 0xac, 0x36, 0x68, 0x97, 0xb5, 0x40, 0x70, + 0xe1, 0xe5, 0x41, 0x06, 0x63, 0x81, 0xb3, 0x32, 0x52, 0x6a, 0x5c, 0x43, 0x6a, 0xc1, 0x27, 0x79, 0x7a, 0x0f, 0x59, + 0xea, 0x49, 0x50, 0xe4, 0x78, 0x16, 0x43, 0xa6, 0xf1, 0x36, 0xf0, 0xf8, 0x9d, 0x0c, 0x41, 0x9a, 0xb6, 0xdb, 0x35, + 0x47, 0xa0, 0xec, 0x1e, 0x98, 0x92, 0xd4, 0xb5, 0x31, 0x35, 0xd0, 0x50, 0x7b, 0xa8, 0x91, 0x8a, 0x38, 0x9b, 0xbd, + 0x06, 0x1d, 0x22, 0xf8, 0x7e, 0xa7, 0x59, 0xd9, 0xf1, 0x62, 0x42, 0xf0, 0xe4, 0x7d, 0x71, 0x9b, 0x95, 0x55, 0x19, + 0xbd, 0x4f, 0xd1, 0x10, 0x2a, 0x91, 0x22, 0x7a, 0x09, 0xf1, 0xf4, 0x4a, 0xfc, 0x5d, 0x46, 0x3f, 0xa5, 0x34, 0x4e, + 0x53, 0x4c, 0x7f, 0x5e, 0xc0, 0xcf, 0x67, 0x80, 0xea, 0x88, 0x3b, 0x21, 0x3a, 0x97, 0x60, 0xaf, 0x06, 0xd1, 0xac, + 0x2a, 0x0e, 0x18, 0x9a, 0xd1, 0xad, 0xa0, 0x88, 0xd1, 0x86, 0xd9, 0x7f, 0x28, 0x50, 0x28, 0xa4, 0x8a, 0xf9, 0x4e, + 0xd8, 0x87, 0xe8, 0x47, 0x2c, 0xf2, 0xe4, 0xdd, 0x2b, 0x33, 0xa4, 0xd1, 0x9d, 0xa4, 0x7a, 0x6b, 0xe3, 0xb1, 0x85, + 0x81, 0xcb, 0xa2, 0xcb, 0x0d, 0x3d, 0x8b, 0xd7, 0x59, 0xb4, 0x05, 0xfc, 0x89, 0x77, 0xaf, 0x9e, 0x29, 0x0b, 0x93, + 0xe7, 0x19, 0x28, 0x0e, 0x4e, 0xde, 0xbd, 0x7a, 0x2d, 0xd3, 0x4d, 0xce, 0xa3, 0x33, 0x89, 0xa4, 0xf5, 0xe4, 0xdd, + 0xab, 0x9f, 0xd1, 0xdc, 0xeb, 0xa7, 0x02, 0xde, 0xbf, 0x04, 0xde, 0x32, 0x8a, 0x37, 0xd0, 0x27, 0xf5, 0x3b, 0xd9, + 0x60, 0xa7, 0xbc, 0x5a, 0xcb, 0xe8, 0x97, 0xb4, 0xf6, 0xa4, 0x55, 0xff, 0x2c, 0x7c, 0x6a, 0xe7, 0x09, 0x78, 0x6e, + 0xf3, 0x4c, 0x7c, 0x8c, 0xac, 0x68, 0x27, 0x88, 0xbe, 0x3c, 0xb8, 0xbd, 0xca, 0x45, 0x19, 0xe1, 0x0b, 0x86, 0x76, + 0x41, 0xd1, 0xe1, 0xe1, 0xcd, 0xcd, 0xcd, 0xe8, 0xe6, 0xab, 0x91, 0x2c, 0x2e, 0x0f, 0x27, 0xdf, 0x7e, 0xfb, 0xed, + 0x21, 0xbe, 0x0d, 0xbe, 0x6c, 0xbb, 0xbd, 0x57, 0x84, 0x0f, 0x58, 0x80, 0x08, 0xd5, 0x5f, 0xc2, 0x15, 0x05, 0xb4, + 0x70, 0x83, 0x2f, 0x83, 0x2f, 0xf5, 0xa1, 0xf3, 0xe5, 0x71, 0x79, 0x7d, 0xa9, 0xca, 0xef, 0x2a, 0xf9, 0x68, 0x3c, + 0x1e, 0x1f, 0x82, 0x04, 0xea, 0xcb, 0x01, 0x1f, 0x04, 0xb3, 0x60, 0x90, 0xc1, 0x85, 0xa6, 0xbc, 0xbe, 0x9c, 0x05, + 0x9e, 0x69, 0x6e, 0x83, 0x45, 0x74, 0x20, 0x2e, 0xc1, 0xe1, 0x25, 0x0d, 0xbe, 0x0c, 0x88, 0x4b, 0xf9, 0x02, 0x52, + 0xbe, 0x38, 0x7a, 0xea, 0xa7, 0xfd, 0x2f, 0x95, 0xf6, 0x95, 0x9f, 0x76, 0x8c, 0x69, 0x5f, 0x3d, 0xf3, 0xd3, 0x66, + 0x2a, 0xed, 0x85, 0x9f, 0xf6, 0xbf, 0xcb, 0x01, 0xa4, 0x1e, 0xf8, 0xd6, 0x7f, 0xe7, 0x5e, 0x6b, 0xf0, 0x14, 0x8a, + 0xb2, 0xab, 0xf8, 0x92, 0x43, 0xa3, 0x07, 0xb7, 0x57, 0x39, 0x0d, 0x06, 0xd8, 0x5e, 0xcf, 0x24, 0xc4, 0xfb, 0xe0, + 0xcb, 0x4d, 0x91, 0x87, 0xc1, 0x97, 0x03, 0x2c, 0x64, 0xf0, 0x65, 0x40, 0xbe, 0x34, 0x06, 0x32, 0x82, 0x6d, 0x03, + 0x17, 0x8a, 0x74, 0x68, 0x03, 0x84, 0xf9, 0xd2, 0xb8, 0x9a, 0xfe, 0x59, 0x74, 0x67, 0xc3, 0x5b, 0xa2, 0x72, 0xd3, + 0x0d, 0x6a, 0xfa, 0x16, 0xbc, 0x13, 0xa0, 0x51, 0x51, 0x70, 0x1d, 0x17, 0xe1, 0x70, 0x58, 0x5e, 0x5f, 0x12, 0xb0, + 0xcb, 0x5c, 0xf3, 0xb8, 0x8a, 0x02, 0x21, 0x87, 0xea, 0x67, 0xa0, 0x22, 0x5f, 0x05, 0x08, 0x88, 0x04, 0xff, 0x05, + 0x35, 0x7d, 0x27, 0xd9, 0x36, 0x18, 0xde, 0xf0, 0xf3, 0x8f, 0x59, 0x35, 0x54, 0xa2, 0xc5, 0x6b, 0x41, 0xe1, 0x07, + 0xfc, 0x75, 0x55, 0x47, 0x7f, 0x82, 0x1b, 0x77, 0x53, 0xc3, 0xfe, 0x4e, 0x3a, 0x16, 0xf5, 0x9d, 0x5c, 0x64, 0xcb, + 0x69, 0xeb, 0x40, 0x7f, 0x2b, 0x49, 0xb5, 0xc8, 0x06, 0xc1, 0x30, 0x18, 0xf0, 0x25, 0x7b, 0x2b, 0x17, 0xdc, 0x33, + 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x67, 0x03, 0xf0, 0x4d, 0x41, 0x7e, 0xe4, 0xf0, 0xbf, 0x17, 0x43, 0x14, 0x1e, + 0x0e, 0x1e, 0x1d, 0x92, 0x79, 0xb0, 0xbe, 0x45, 0x8f, 0xce, 0x28, 0xc8, 0xc4, 0x8a, 0x17, 0x59, 0xe5, 0x2d, 0x95, + 0xbb, 0x4d, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x1d, 0x8b, 0x40, 0x9d, 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, + 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb8, 0x37, 0x1c, 0x1e, 0x04, 0x03, 0xa7, 0xce, 0x1d, 0x04, + 0x07, 0xc3, 0xe1, 0x2c, 0x70, 0xf7, 0xa1, 0x6c, 0xe4, 0xee, 0x8c, 0xb4, 0x60, 0xff, 0x2c, 0xc2, 0x92, 0x82, 0x78, + 0x4c, 0x6a, 0xf1, 0x97, 0x06, 0x97, 0x19, 0x00, 0xf4, 0x91, 0x92, 0x80, 0x19, 0x58, 0x99, 0x01, 0x84, 0xe6, 0xa6, + 0x31, 0x3b, 0x03, 0xe6, 0x11, 0x38, 0xe6, 0x11, 0x32, 0x0e, 0x80, 0x58, 0x12, 0xe0, 0xdc, 0x05, 0x51, 0xac, 0x0b, + 0x79, 0x04, 0xa0, 0xf7, 0xf8, 0x93, 0x98, 0x52, 0x30, 0x49, 0xc7, 0x2a, 0x04, 0x41, 0x1c, 0x9f, 0x5f, 0x8b, 0xd6, + 0xe4, 0xac, 0xd0, 0xc1, 0x8c, 0x24, 0xc0, 0x86, 0x18, 0xd8, 0x39, 0xb8, 0x9f, 0x83, 0xd2, 0xc3, 0xea, 0x9d, 0x90, + 0x0b, 0xbe, 0xe3, 0x9e, 0x6c, 0x16, 0xae, 0x9e, 0x70, 0x10, 0xdc, 0x71, 0xcd, 0x02, 0x8c, 0xaa, 0x62, 0x53, 0x56, + 0x3c, 0xfd, 0x70, 0xb7, 0x86, 0xd8, 0x77, 0x38, 0xa0, 0xef, 0x64, 0x9e, 0x25, 0x77, 0xa1, 0xb3, 0xe7, 0xda, 0xaa, + 0xf4, 0x1f, 0x3e, 0xbc, 0xfe, 0x29, 0x02, 0x91, 0x63, 0x6d, 0x28, 0xfd, 0x1d, 0xc7, 0xb3, 0xc9, 0x8f, 0xf0, 0xe4, + 0x6f, 0xec, 0x3b, 0x6e, 0x4f, 0x8f, 0x7e, 0x1f, 0xea, 0xa6, 0x77, 0x7c, 0x7e, 0xc7, 0x47, 0xae, 0x38, 0x54, 0x57, + 0xb8, 0xaf, 0x6f, 0x36, 0xbe, 0x11, 0xd2, 0xc3, 0xf3, 0x4c, 0x79, 0x63, 0x7e, 0xb4, 0x83, 0x61, 0x10, 0x4c, 0xb5, + 0x50, 0x12, 0xa2, 0x6e, 0x30, 0x25, 0x60, 0x88, 0x0e, 0xf4, 0xb2, 0x9a, 0x22, 0xe7, 0xa6, 0x46, 0x16, 0xde, 0x0f, + 0x98, 0x16, 0x3a, 0x34, 0x72, 0x28, 0x3f, 0x38, 0x9c, 0x30, 0x66, 0xe1, 0xb7, 0x4a, 0x98, 0x7e, 0xb5, 0xa8, 0x9c, + 0x83, 0xe8, 0x01, 0x18, 0xe3, 0x0a, 0x5e, 0x40, 0x57, 0xd8, 0xf5, 0x46, 0x45, 0xc5, 0x40, 0xf0, 0x38, 0xe4, 0x00, + 0x3d, 0xec, 0x82, 0x96, 0x95, 0xa5, 0xba, 0x55, 0x39, 0x4b, 0x15, 0x75, 0x19, 0xca, 0xca, 0x58, 0x61, 0xbe, 0x97, + 0xec, 0x87, 0x02, 0x3d, 0xcb, 0xa7, 0xa2, 0x0b, 0x5e, 0x08, 0x25, 0x58, 0xae, 0xeb, 0x9d, 0x08, 0x44, 0x9d, 0x1f, + 0x7a, 0x57, 0x7d, 0x8d, 0x63, 0xc7, 0xd3, 0xd7, 0x32, 0xe5, 0xda, 0x84, 0x42, 0xf3, 0xf9, 0xd2, 0x57, 0x4c, 0x14, + 0xec, 0x06, 0xfa, 0xd5, 0xb6, 0xd1, 0x67, 0x77, 0x1b, 0xbd, 0x19, 0x94, 0xe8, 0x98, 0xd7, 0x28, 0xb8, 0x56, 0x0a, + 0x05, 0xa3, 0xbd, 0x8d, 0x3f, 0xc1, 0x91, 0x5b, 0xdd, 0x1e, 0x7a, 0xbf, 0x55, 0xf1, 0xe5, 0x1b, 0xf4, 0xed, 0xb4, + 0x3f, 0x47, 0x95, 0xfc, 0x65, 0xbd, 0x06, 0x1f, 0x2a, 0x88, 0x2c, 0x62, 0x71, 0x69, 0xa1, 0x9e, 0xd3, 0x77, 0x27, + 0x6f, 0xc0, 0x8f, 0x12, 0x7f, 0xff, 0xfa, 0x7d, 0x50, 0x93, 0x69, 0x3c, 0x2f, 0xcc, 0x87, 0x36, 0x07, 0x84, 0x26, + 0x71, 0x69, 0xf6, 0xfd, 0x3c, 0x6e, 0xb2, 0xef, 0x9a, 0xad, 0xa7, 0x45, 0x13, 0x49, 0xca, 0x70, 0xfb, 0x60, 0x40, + 0xa0, 0x0f, 0x10, 0xc5, 0xd9, 0x17, 0x34, 0x86, 0x34, 0x9f, 0xd9, 0xf7, 0x23, 0xe2, 0xbd, 0xd8, 0x0b, 0x21, 0xc6, + 0x15, 0x16, 0x8d, 0x1e, 0xf2, 0x39, 0x8f, 0x94, 0x61, 0xd1, 0x7b, 0x4c, 0x20, 0xce, 0x70, 0x5a, 0xbd, 0x47, 0xcc, + 0x63, 0xbc, 0x1b, 0x68, 0xd9, 0x43, 0x94, 0x51, 0x97, 0xbd, 0x61, 0xf1, 0xfd, 0x71, 0x13, 0x66, 0xd6, 0xf2, 0x72, + 0x08, 0x7f, 0x03, 0x6d, 0x00, 0x4e, 0x39, 0xb2, 0x7c, 0x95, 0xd9, 0xe8, 0x6a, 0x89, 0xe9, 0x4d, 0x04, 0xb1, 0x78, + 0x74, 0x3a, 0xac, 0x5d, 0x9d, 0xaa, 0x77, 0xb5, 0xf3, 0x99, 0xe8, 0x55, 0xa0, 0x95, 0x6b, 0xdb, 0xe3, 0x21, 0xdc, + 0xa5, 0x96, 0x56, 0xd8, 0x88, 0x72, 0x2e, 0x9e, 0xee, 0x02, 0x9b, 0x13, 0xd0, 0xe0, 0x4a, 0xa6, 0x00, 0x9c, 0xa5, + 0xd5, 0x68, 0xd4, 0x08, 0xfb, 0xac, 0x9c, 0xcf, 0x61, 0x6b, 0x21, 0x9e, 0x16, 0x80, 0xe1, 0x36, 0x31, 0x28, 0x79, + 0x37, 0x06, 0xe5, 0xf4, 0xa3, 0x82, 0xb7, 0x0e, 0xce, 0xca, 0x55, 0x9c, 0xca, 0x1b, 0xc0, 0x62, 0x0c, 0xfc, 0x54, + 0x2c, 0xd5, 0x4b, 0x48, 0x56, 0x3c, 0xf9, 0x88, 0x56, 0x1b, 0x69, 0x00, 0x5c, 0xe5, 0xd4, 0x58, 0xee, 0x29, 0x90, + 0x50, 0x57, 0x8a, 0x4a, 0x88, 0xab, 0x2a, 0x4e, 0x56, 0xa7, 0x98, 0x1a, 0x6e, 0xa1, 0x17, 0x51, 0x20, 0xd7, 0x5c, + 0x00, 0x49, 0xcf, 0xd9, 0xbf, 0x32, 0x8d, 0x35, 0xfe, 0x4c, 0xa2, 0x80, 0x49, 0xa3, 0x06, 0x63, 0xa5, 0xec, 0x85, + 0x34, 0xd1, 0xde, 0x82, 0xa0, 0x76, 0x2f, 0xff, 0x84, 0xba, 0x9f, 0x41, 0x2b, 0xc2, 0x06, 0x18, 0xa2, 0x3c, 0xc7, + 0x1d, 0x9a, 0xda, 0x25, 0xe7, 0x01, 0x23, 0x3a, 0xef, 0xb3, 0xda, 0x6e, 0xf5, 0x67, 0x2b, 0xc0, 0x36, 0x4d, 0x8d, + 0x4f, 0x61, 0x98, 0x10, 0x13, 0x1b, 0xd8, 0x2a, 0x2b, 0xed, 0x86, 0x32, 0xed, 0xa4, 0x2b, 0xe6, 0xb5, 0x70, 0x9a, + 0xf7, 0x18, 0x5b, 0x8d, 0x54, 0xee, 0x7e, 0x3f, 0x34, 0x3f, 0x59, 0x4e, 0x9f, 0xe9, 0x90, 0xcd, 0xde, 0x78, 0xd0, + 0x9c, 0x68, 0x75, 0x55, 0x47, 0x3f, 0xa0, 0x03, 0x30, 0xd3, 0x16, 0x20, 0xd3, 0x05, 0x9b, 0xf6, 0x95, 0xa8, 0xb8, + 0x24, 0x61, 0xa9, 0x24, 0xb0, 0xb3, 0x9b, 0x92, 0x9d, 0x6d, 0x40, 0x3c, 0xc3, 0x5d, 0x4f, 0x8b, 0x9d, 0x90, 0x26, + 0xbc, 0xc5, 0x41, 0x02, 0xa2, 0x0e, 0x55, 0x5d, 0x42, 0xb6, 0xc6, 0xd0, 0xc5, 0xbf, 0x28, 0x85, 0x09, 0x6b, 0x99, + 0x54, 0x25, 0x26, 0x08, 0x52, 0xb9, 0xdf, 0x22, 0xb0, 0x44, 0xc1, 0x0e, 0x60, 0xef, 0xdd, 0xa8, 0x9b, 0x51, 0x53, + 0xd5, 0xa9, 0x97, 0xe0, 0xe3, 0x34, 0xef, 0x2a, 0xc8, 0x2c, 0xec, 0xaa, 0xd8, 0xf0, 0x40, 0xc7, 0xa6, 0x52, 0xc6, + 0xc4, 0x5d, 0x5a, 0x64, 0x88, 0x07, 0x8c, 0xb1, 0x74, 0x21, 0x90, 0x6f, 0xb6, 0x3f, 0x6e, 0x7a, 0x82, 0xd0, 0x4f, + 0xd8, 0x50, 0x02, 0x37, 0x9d, 0xed, 0xa9, 0x69, 0xe6, 0x03, 0x22, 0x0e, 0x03, 0x0a, 0x24, 0x1b, 0x87, 0x34, 0x47, + 0xfa, 0x82, 0xa4, 0x09, 0x03, 0x43, 0x2b, 0x9e, 0x13, 0x64, 0x45, 0xa1, 0x67, 0xeb, 0xaa, 0x8d, 0x73, 0x65, 0x98, + 0xa3, 0x25, 0xa7, 0xc2, 0xe7, 0x04, 0x99, 0xd8, 0x3d, 0x6d, 0x33, 0x93, 0xe1, 0x28, 0x59, 0x60, 0x7e, 0x05, 0x51, + 0xe2, 0xce, 0x34, 0xab, 0x72, 0x30, 0x2e, 0x60, 0x81, 0x56, 0xbe, 0x07, 0x75, 0x63, 0x0d, 0x6d, 0x35, 0x0c, 0xb1, + 0xdb, 0x9f, 0x60, 0xbf, 0xd6, 0x4e, 0xeb, 0x32, 0xc5, 0xf2, 0x32, 0x85, 0x68, 0x2f, 0x64, 0x7e, 0xa3, 0x48, 0x74, + 0xaf, 0x08, 0x43, 0xc2, 0x3a, 0xca, 0x9e, 0xb4, 0xa9, 0x01, 0xf4, 0xd4, 0x0b, 0x78, 0xde, 0xb9, 0x96, 0x61, 0x17, + 0xe9, 0xfe, 0xaa, 0xe0, 0x53, 0xba, 0x41, 0x90, 0xa2, 0x37, 0x29, 0x98, 0xf3, 0x7a, 0x94, 0xd4, 0x9b, 0xd3, 0x96, + 0x19, 0x55, 0x47, 0x45, 0x48, 0x39, 0xc1, 0x7f, 0xf2, 0x52, 0x6a, 0x62, 0x13, 0x26, 0x78, 0xe0, 0xc3, 0x3c, 0xc3, + 0x06, 0xde, 0xed, 0xde, 0xa5, 0x61, 0xd2, 0x66, 0x1b, 0x52, 0x90, 0x56, 0x98, 0xb8, 0x18, 0x50, 0xd9, 0x2b, 0xdc, + 0x2f, 0xd8, 0x4e, 0x9a, 0x82, 0x07, 0x61, 0xa3, 0x81, 0x89, 0x5b, 0x5d, 0x7c, 0x13, 0x26, 0x34, 0x5c, 0x51, 0xed, + 0xec, 0xa4, 0x25, 0xcd, 0xed, 0x75, 0x79, 0x61, 0xfb, 0xa0, 0x63, 0x87, 0x75, 0x0d, 0x0f, 0x34, 0xaf, 0xd9, 0xc5, + 0x35, 0xd3, 0x34, 0xd1, 0x58, 0x0f, 0x29, 0x4b, 0x8e, 0x4d, 0x3d, 0x5d, 0xe3, 0x6a, 0x99, 0x6b, 0x60, 0x77, 0x89, + 0x17, 0x7a, 0xc0, 0xc3, 0x0e, 0xd7, 0x24, 0xba, 0xc0, 0x66, 0xb3, 0x75, 0x4d, 0xa6, 0xf9, 0x7d, 0xd9, 0x72, 0x13, + 0x10, 0xce, 0x52, 0xdf, 0xdc, 0x27, 0xc7, 0x9a, 0xb6, 0xf9, 0x49, 0x80, 0xe3, 0xed, 0x15, 0x90, 0x74, 0x2c, 0x41, + 0x17, 0xdf, 0xd2, 0x1f, 0x44, 0x6a, 0xa6, 0x82, 0xde, 0x3b, 0x5f, 0xa4, 0x6e, 0x7e, 0x01, 0xb6, 0x51, 0x5b, 0x63, + 0x9a, 0x95, 0x6d, 0xc2, 0x44, 0x59, 0x58, 0x23, 0x0b, 0xb9, 0x02, 0x1f, 0xcc, 0xfd, 0xa6, 0x4e, 0x4f, 0x3a, 0x88, + 0xb0, 0xdf, 0x45, 0x8f, 0x47, 0x18, 0x2b, 0xd6, 0x20, 0x31, 0xac, 0xc2, 0x86, 0x36, 0x97, 0x43, 0x94, 0x53, 0xb3, + 0x64, 0xa2, 0x15, 0xf5, 0x29, 0x45, 0x94, 0x82, 0xb9, 0xf1, 0xb4, 0x6c, 0x98, 0x12, 0x22, 0x64, 0x85, 0x74, 0x40, + 0xb5, 0x16, 0x5a, 0xaa, 0x09, 0x7a, 0x1d, 0x7a, 0x59, 0x68, 0x4c, 0x41, 0xf4, 0x11, 0x19, 0x6e, 0xc4, 0x91, 0xd1, + 0xfd, 0x31, 0x8a, 0x09, 0x84, 0xaa, 0xf6, 0xf2, 0xc2, 0xea, 0xd3, 0xb2, 0xad, 0x0e, 0xe2, 0x0a, 0x91, 0xef, 0xbb, + 0x09, 0x6a, 0x8c, 0x82, 0x36, 0xa7, 0x1b, 0xfd, 0xa5, 0x08, 0x7d, 0xbb, 0x70, 0xec, 0x46, 0x41, 0x24, 0x44, 0x60, + 0xf5, 0x9a, 0x8a, 0x01, 0x59, 0x17, 0xb1, 0x8b, 0xd0, 0xa4, 0xbb, 0x85, 0x28, 0x6f, 0x54, 0xd6, 0x1f, 0x37, 0x21, + 0xd9, 0xed, 0xb0, 0x2c, 0xf0, 0x65, 0x3f, 0xdd, 0xdc, 0x03, 0xf9, 0xfd, 0x7a, 0xf3, 0x49, 0xc8, 0xef, 0x57, 0xd9, + 0xe7, 0x40, 0x7e, 0xbf, 0xde, 0xfc, 0x4f, 0x43, 0x7e, 0x9f, 0x6e, 0x3c, 0xc8, 0x6f, 0x35, 0x18, 0xbf, 0x15, 0x2c, + 0x78, 0xfb, 0x26, 0xa0, 0xcf, 0x25, 0x0b, 0xde, 0xbe, 0x7c, 0xe9, 0x1b, 0x81, 0x08, 0x8d, 0x5c, 0x6f, 0x64, 0xc1, + 0x88, 0xdb, 0x02, 0xaf, 0x50, 0xeb, 0xe4, 0x03, 0x15, 0x65, 0x00, 0xbc, 0x5e, 0xfe, 0x23, 0xab, 0x56, 0x61, 0x70, + 0x18, 0x90, 0xb9, 0x83, 0x04, 0x1d, 0x4e, 0xe0, 0xf6, 0x86, 0x46, 0x96, 0xd5, 0x67, 0xc1, 0x87, 0x8f, 0x46, 0xa3, + 0xb8, 0xb8, 0xc4, 0x4b, 0x9d, 0xd9, 0x48, 0x08, 0x78, 0x9c, 0xf1, 0xd2, 0x86, 0x88, 0x58, 0xc5, 0xe5, 0x99, 0x8e, + 0xcd, 0x52, 0xda, 0xad, 0x08, 0x11, 0xe7, 0xcf, 0x00, 0xa7, 0xde, 0xee, 0xcd, 0x18, 0xfb, 0xa1, 0x38, 0x62, 0x1d, + 0x40, 0xf6, 0xd9, 0x46, 0xbf, 0x3b, 0x8f, 0x4b, 0xfe, 0x2e, 0xae, 0x56, 0x0c, 0x7a, 0x09, 0x77, 0x11, 0xc1, 0x93, + 0xca, 0x63, 0x9b, 0x14, 0x50, 0x79, 0xa6, 0x81, 0xca, 0x3b, 0xde, 0xd3, 0xd0, 0x0e, 0x8b, 0xf6, 0x01, 0x36, 0xd2, + 0xe5, 0x0c, 0x8c, 0x16, 0x5f, 0x5c, 0x73, 0x51, 0xfd, 0x04, 0x78, 0xea, 0x82, 0x17, 0x70, 0x4b, 0x40, 0x2e, 0xb6, + 0xe1, 0x84, 0x40, 0x85, 0xef, 0xd9, 0xa1, 0xa2, 0xc6, 0x18, 0xd1, 0x44, 0xa3, 0xdf, 0x78, 0x13, 0x42, 0xef, 0x4e, + 0xd0, 0x15, 0x61, 0x24, 0xbc, 0x3f, 0x37, 0xfc, 0x2c, 0x03, 0xf3, 0x79, 0x01, 0x50, 0x1a, 0x08, 0x87, 0xca, 0x94, + 0xdc, 0x02, 0x13, 0xb6, 0xc6, 0x5c, 0x29, 0x4b, 0x3d, 0xa4, 0x52, 0xaa, 0xe0, 0x74, 0x05, 0x4d, 0x25, 0xe0, 0x70, + 0x47, 0x12, 0xc0, 0x4c, 0x6d, 0x61, 0x10, 0xdd, 0x36, 0xa5, 0x59, 0x1a, 0x39, 0x45, 0x9a, 0xc3, 0x27, 0xa5, 0x0a, + 0x74, 0xfa, 0x2c, 0x89, 0x2b, 0x7e, 0x29, 0x0b, 0x08, 0x85, 0xdb, 0x4a, 0xa1, 0x48, 0xbf, 0xcf, 0xc4, 0xe6, 0x8a, + 0x17, 0x59, 0x72, 0xb6, 0xca, 0xca, 0x0a, 0xf2, 0x2d, 0xf4, 0xe9, 0xb7, 0xac, 0xa7, 0x05, 0xce, 0x9b, 0x9a, 0x14, + 0x66, 0xe6, 0xf1, 0x44, 0xed, 0x74, 0x50, 0xaf, 0x7a, 0xaf, 0x0d, 0xf6, 0x7b, 0x73, 0xa2, 0xc7, 0xad, 0xf5, 0x60, + 0x35, 0xa9, 0xcd, 0x54, 0x05, 0x71, 0x04, 0xd4, 0x81, 0xcd, 0x70, 0x16, 0x53, 0xba, 0xb1, 0x08, 0x2a, 0x60, 0xed, + 0x80, 0x39, 0x32, 0x71, 0x79, 0x76, 0xa3, 0xe4, 0x27, 0x3d, 0x45, 0x61, 0xd2, 0x28, 0x56, 0xc8, 0x3e, 0x2b, 0x16, + 0x6e, 0x58, 0x72, 0x4f, 0xae, 0x4d, 0x94, 0x34, 0x30, 0xba, 0xe2, 0xf6, 0x40, 0x1c, 0x27, 0xed, 0x94, 0xf9, 0x70, + 0x12, 0xed, 0x65, 0x03, 0xe6, 0xa0, 0x9d, 0x0f, 0xae, 0xaa, 0xab, 0xb9, 0x6a, 0xc5, 0xa8, 0x92, 0x3f, 0xc9, 0x1b, + 0x73, 0xb1, 0x3d, 0x4e, 0x3a, 0x12, 0xa1, 0xdc, 0x49, 0x94, 0x1f, 0xaf, 0xd4, 0x0f, 0x80, 0x5e, 0xd1, 0xe4, 0xf0, + 0xcf, 0x0d, 0x37, 0xe0, 0xf4, 0xa1, 0xf6, 0x10, 0x74, 0xa2, 0x7c, 0x3d, 0x23, 0x9e, 0x51, 0x9d, 0x5e, 0x2e, 0x0b, + 0x30, 0xe8, 0xf2, 0x87, 0x12, 0x22, 0xc8, 0x74, 0x4e, 0xeb, 0x72, 0xaa, 0xcd, 0x8b, 0x0d, 0x6f, 0x43, 0x3f, 0xef, + 0x3b, 0x0d, 0x9c, 0x9b, 0xf0, 0x70, 0xf8, 0x74, 0x4c, 0x6a, 0x6d, 0xeb, 0x8e, 0x0b, 0xcf, 0xfe, 0x56, 0x8b, 0xd3, + 0x3d, 0xdb, 0x05, 0x4a, 0x9b, 0x5e, 0x0a, 0xed, 0x1a, 0xa9, 0xb8, 0xa7, 0xfb, 0x35, 0xa9, 0xdd, 0x42, 0xb3, 0x92, + 0xa7, 0xdf, 0xd5, 0x69, 0x77, 0xf6, 0x68, 0x9b, 0xe9, 0x2a, 0xeb, 0xdf, 0x33, 0x1b, 0xa7, 0xae, 0x41, 0x39, 0x6a, + 0xbd, 0x04, 0x7d, 0x98, 0xb8, 0x8e, 0x6c, 0x7a, 0x3a, 0x59, 0xd6, 0x49, 0x7e, 0x46, 0xea, 0x91, 0xab, 0xb0, 0x5d, + 0xdd, 0x59, 0xf8, 0x2d, 0x4f, 0xc2, 0xae, 0x86, 0xa9, 0x9b, 0x81, 0xe9, 0x02, 0x22, 0x67, 0x82, 0x3e, 0x20, 0xfc, + 0xfd, 0xd1, 0xb6, 0x49, 0xce, 0xea, 0x43, 0xef, 0x33, 0xfc, 0x9d, 0xa5, 0xf0, 0xb7, 0xaa, 0x7f, 0xa7, 0xdb, 0x2b, + 0x5e, 0xad, 0x64, 0x1a, 0x05, 0xef, 0xde, 0x9e, 0x7e, 0x08, 0x34, 0x22, 0x3b, 0xde, 0x4b, 0x8c, 0x26, 0xda, 0x60, + 0x3f, 0x81, 0x66, 0x26, 0x97, 0x97, 0x08, 0x4a, 0xa8, 0x51, 0xed, 0x4f, 0x57, 0xf2, 0xe6, 0x24, 0xcf, 0x7d, 0xe6, + 0xd9, 0x10, 0x5c, 0xcd, 0x4f, 0x36, 0xa8, 0x55, 0x08, 0x32, 0xc0, 0x51, 0x56, 0x9e, 0x69, 0xad, 0x4d, 0x7a, 0x76, + 0x7e, 0x77, 0xa6, 0x25, 0x43, 0x16, 0x15, 0xf2, 0xd9, 0xef, 0xc7, 0x69, 0x76, 0x7d, 0x80, 0xa7, 0x02, 0x0b, 0xc0, + 0xa4, 0x3e, 0xe7, 0xe7, 0x9b, 0xaa, 0x92, 0x62, 0x58, 0xc8, 0x9b, 0x60, 0x76, 0xac, 0x1e, 0x4c, 0x86, 0x58, 0x3d, + 0x06, 0x07, 0xff, 0x95, 0xe4, 0x59, 0xf2, 0x91, 0x05, 0x8f, 0xb6, 0x19, 0x9b, 0xb5, 0x68, 0xff, 0xb8, 0x0e, 0x66, + 0xd0, 0xd6, 0x83, 0x93, 0x3c, 0x3f, 0x3e, 0x54, 0x5f, 0xcc, 0x8e, 0x0f, 0xd3, 0xec, 0x7a, 0xe6, 0x01, 0xf4, 0x3b, + 0x7b, 0x5b, 0x84, 0x42, 0x73, 0xf7, 0x69, 0x70, 0xac, 0x4d, 0x78, 0x68, 0x39, 0x10, 0x90, 0xe2, 0x98, 0xf0, 0x26, + 0x28, 0xf9, 0x09, 0x63, 0x38, 0x6f, 0x77, 0xbb, 0xd0, 0x1a, 0x03, 0x25, 0x1e, 0x52, 0x4e, 0x01, 0x1c, 0x0a, 0x66, + 0xa1, 0x09, 0xa1, 0x49, 0x4d, 0x42, 0x83, 0xe7, 0x13, 0x13, 0x5a, 0xd4, 0x14, 0x8e, 0xa0, 0xd7, 0xf1, 0xda, 0x08, + 0xbf, 0xb4, 0x30, 0xc1, 0xb4, 0x7e, 0xde, 0x18, 0xc7, 0xa8, 0x3d, 0xaa, 0x06, 0x61, 0xab, 0x57, 0xde, 0x37, 0xb0, + 0x20, 0xef, 0x0c, 0x2b, 0x1a, 0xb4, 0xe8, 0x0a, 0xc8, 0x2b, 0x7d, 0x31, 0x1b, 0xa7, 0xe1, 0xa2, 0xa4, 0x72, 0x49, + 0xd8, 0x2c, 0xdc, 0x22, 0xbb, 0x5d, 0x2a, 0xea, 0x1d, 0xc9, 0xda, 0xc1, 0x5d, 0xaa, 0xd9, 0x99, 0x3d, 0xda, 0x0a, + 0x44, 0x58, 0x2c, 0xd9, 0xac, 0x39, 0x5f, 0x55, 0x7c, 0x3e, 0x5c, 0x71, 0xf0, 0xcb, 0x09, 0x0e, 0xfe, 0x2b, 0x3d, + 0xcf, 0xed, 0xa4, 0xa8, 0x15, 0xb9, 0x8a, 0x45, 0x9a, 0xf3, 0x0f, 0xf1, 0xf9, 0x0f, 0x98, 0xe7, 0xf9, 0x79, 0xfe, + 0x0c, 0x32, 0xd4, 0xc1, 0xec, 0xd1, 0x36, 0xa9, 0x46, 0x2f, 0xde, 0x7c, 0x78, 0xf5, 0xe1, 0x9f, 0x67, 0xcf, 0x4e, + 0x3e, 0xbc, 0xf8, 0xfe, 0xed, 0xfb, 0x57, 0x2f, 0x4e, 0x17, 0xd6, 0x11, 0x56, 0xe1, 0xab, 0x91, 0xe5, 0x6e, 0xe7, + 0xf2, 0xfd, 0xf2, 0xe6, 0xf9, 0x8b, 0x97, 0xaf, 0xde, 0xbc, 0x78, 0x5e, 0xab, 0xb9, 0x6c, 0x37, 0x04, 0x76, 0x68, + 0x9c, 0x09, 0x5e, 0x40, 0xf1, 0x3a, 0xca, 0x23, 0x36, 0x5b, 0xc3, 0x02, 0x36, 0x9b, 0xae, 0x23, 0x28, 0xc0, 0x22, + 0x3b, 0xd0, 0x9b, 0x05, 0x1a, 0x2e, 0xcd, 0xc6, 0xf1, 0x97, 0x98, 0xdf, 0x9b, 0x17, 0xf8, 0xdd, 0x7b, 0x79, 0x63, + 0xba, 0xa2, 0x47, 0x48, 0x21, 0x7e, 0xcd, 0x9f, 0xfd, 0x7e, 0xec, 0x4b, 0xd9, 0x50, 0x14, 0xa1, 0xca, 0x85, 0x5f, + 0x75, 0x70, 0xa0, 0x2d, 0xfe, 0x02, 0x08, 0x58, 0x11, 0xcc, 0x8e, 0x0f, 0xfd, 0xdc, 0xb3, 0xdf, 0xa3, 0x9f, 0xbc, + 0xce, 0x61, 0xa9, 0x30, 0x0e, 0xcd, 0xb4, 0xbd, 0x53, 0x11, 0x42, 0x2a, 0xb9, 0x73, 0x53, 0xad, 0x20, 0x43, 0xae, + 0x24, 0x89, 0xec, 0x24, 0x2a, 0x4b, 0x16, 0x53, 0xda, 0xef, 0xfa, 0xaf, 0xeb, 0x33, 0x4a, 0x06, 0xb8, 0x28, 0x65, + 0x11, 0x40, 0x3f, 0xda, 0x71, 0x26, 0x0e, 0xbc, 0x78, 0x2e, 0xd8, 0xa3, 0x4e, 0xf2, 0x0e, 0x23, 0x72, 0xd8, 0xfe, + 0xd4, 0xeb, 0xd8, 0xef, 0xc4, 0xfd, 0xf8, 0x3f, 0xcd, 0x3d, 0xeb, 0x76, 0xdb, 0x36, 0xd2, 0xff, 0xfb, 0x14, 0x0c, + 0x93, 0x4d, 0xc5, 0x84, 0xa4, 0x49, 0xc9, 0xb2, 0x15, 0xc9, 0xb2, 0xdb, 0xe6, 0x72, 0x36, 0xfb, 0xb9, 0x4d, 0x4f, + 0xe2, 0xe6, 0xdb, 0xad, 0xeb, 0x63, 0x51, 0x12, 0x24, 0x71, 0x43, 0x91, 0x3a, 0x24, 0xe5, 0x4b, 0x15, 0xee, 0xb3, + 0xec, 0x23, 0x7c, 0xcf, 0xd0, 0x27, 0xfb, 0xce, 0xcc, 0x00, 0x20, 0x78, 0x93, 0x94, 0x26, 0xed, 0xee, 0x69, 0x93, + 0x88, 0xb8, 0x63, 0x00, 0x0c, 0x06, 0x73, 0xd5, 0xf8, 0x64, 0x4a, 0xe8, 0x45, 0x0e, 0xb0, 0x39, 0x1e, 0xc8, 0xe5, + 0x1b, 0xdf, 0xfc, 0xdf, 0xc8, 0x9c, 0x7b, 0xe6, 0xd2, 0x33, 0xdf, 0x85, 0x57, 0x59, 0xed, 0xea, 0xc8, 0x58, 0x33, + 0x26, 0x1b, 0xb4, 0xc0, 0x63, 0x05, 0x7f, 0x47, 0x70, 0xea, 0xda, 0xb7, 0xb9, 0x8c, 0xed, 0xc2, 0x8b, 0xe7, 0x4c, + 0x84, 0x78, 0x11, 0xb9, 0x29, 0x87, 0x8a, 0xa1, 0x80, 0x05, 0xdc, 0xb9, 0x3c, 0xe0, 0xaa, 0x08, 0xbe, 0x3d, 0x49, + 0xe3, 0xe0, 0x7f, 0xd8, 0x3d, 0x50, 0x7b, 0x49, 0x1a, 0xad, 0x80, 0xc6, 0xf7, 0xe6, 0x9c, 0x67, 0x63, 0xb6, 0xd8, + 0x7e, 0xdd, 0x7d, 0xfc, 0xc8, 0x6c, 0xdc, 0x92, 0x40, 0x28, 0xda, 0x69, 0x34, 0x9f, 0x07, 0xac, 0xa5, 0x8b, 0xa0, + 0x23, 0xba, 0x29, 0xbb, 0x39, 0x7b, 0xe0, 0x08, 0x4f, 0x9f, 0x46, 0xd6, 0x74, 0xb4, 0xc4, 0x8c, 0x99, 0x74, 0x85, + 0x47, 0x14, 0x2f, 0xf2, 0x74, 0x6f, 0x50, 0x2c, 0xc2, 0xd7, 0x25, 0x3f, 0xba, 0xd6, 0x34, 0x5a, 0x8f, 0x03, 0x66, + 0xe1, 0x76, 0x87, 0x2e, 0x37, 0xe3, 0xf5, 0x78, 0x0c, 0xd1, 0x5d, 0x1e, 0x38, 0x26, 0xf8, 0xab, 0x89, 0x12, 0x7c, + 0x47, 0x66, 0xc6, 0x00, 0x26, 0x65, 0xa7, 0xe5, 0xe1, 0x83, 0x8e, 0x09, 0xb0, 0x88, 0xa8, 0x83, 0x14, 0xde, 0x8c, + 0x35, 0xa7, 0x76, 0xa8, 0xbf, 0x83, 0xdd, 0x97, 0xe8, 0x83, 0xba, 0xa3, 0x3f, 0xbc, 0xd4, 0xdf, 0x21, 0x8c, 0x31, + 0xea, 0xf1, 0x73, 0xda, 0xbd, 0xba, 0xa9, 0x93, 0xb0, 0x7c, 0x8d, 0xf1, 0x0f, 0x80, 0x59, 0xfc, 0xc2, 0xf7, 0xe6, + 0x61, 0x94, 0xa4, 0xfe, 0x44, 0xbf, 0x1a, 0xbc, 0xf6, 0x5b, 0x97, 0xcb, 0xb4, 0x65, 0x5c, 0x99, 0x93, 0x54, 0x0d, + 0x9d, 0x22, 0x10, 0x26, 0x46, 0x4e, 0x69, 0x2a, 0xa4, 0x9e, 0xa0, 0xad, 0x05, 0x05, 0x6a, 0xc6, 0x42, 0x93, 0x74, + 0x08, 0xe5, 0x4a, 0x71, 0x58, 0x30, 0xa0, 0x94, 0x8e, 0x35, 0x8d, 0x01, 0xbd, 0x70, 0x9e, 0xaf, 0x37, 0x78, 0x95, + 0xa7, 0xf9, 0x6d, 0x89, 0xbe, 0x83, 0x85, 0xc1, 0x0d, 0x7d, 0x3f, 0x50, 0x95, 0x45, 0x0b, 0xf7, 0xee, 0xe8, 0xdb, + 0x22, 0x5d, 0x00, 0xf7, 0x37, 0x68, 0x6a, 0x84, 0x51, 0xaa, 0x81, 0x43, 0x1c, 0xe8, 0x71, 0x54, 0x56, 0x2e, 0xe3, + 0xad, 0xb6, 0x8c, 0x8c, 0x23, 0x83, 0xef, 0xf0, 0xf2, 0x6b, 0x71, 0xb7, 0x68, 0x05, 0xcf, 0x17, 0xf4, 0xc8, 0x08, + 0x61, 0x01, 0x0b, 0x14, 0xa5, 0x82, 0xfb, 0x77, 0xde, 0xbd, 0x2d, 0x41, 0x5e, 0x8b, 0x68, 0x80, 0x2d, 0x1e, 0xd0, + 0x54, 0x10, 0x3a, 0xa5, 0x33, 0x85, 0x0a, 0x23, 0x82, 0x86, 0x49, 0x41, 0xbf, 0x0c, 0xef, 0x02, 0x40, 0x49, 0xfc, + 0x9a, 0x1e, 0x65, 0xd7, 0x22, 0xe4, 0xb2, 0x08, 0x78, 0xac, 0x5c, 0xce, 0x80, 0x5d, 0xc3, 0xd5, 0x3a, 0x45, 0x17, + 0xbd, 0x30, 0x00, 0x96, 0xe9, 0x1a, 0xba, 0xfc, 0x04, 0x2c, 0x9d, 0x93, 0x89, 0x99, 0xae, 0xf9, 0xd3, 0x6a, 0x1a, + 0x27, 0x7a, 0x01, 0x79, 0x21, 0x7e, 0x47, 0x06, 0x17, 0x7c, 0xc6, 0x7c, 0x1a, 0x13, 0x33, 0xf7, 0x6f, 0xdf, 0x9a, + 0xa0, 0x20, 0xa8, 0x06, 0x33, 0x4c, 0xa8, 0x9d, 0x41, 0x2b, 0xa8, 0x9d, 0x2c, 0xb8, 0xed, 0x2c, 0x4c, 0x73, 0xf4, + 0x68, 0x13, 0x66, 0x67, 0x8f, 0x36, 0x49, 0x36, 0x7c, 0xb4, 0xf1, 0xa4, 0x8e, 0x81, 0x7e, 0xa1, 0x93, 0x82, 0xc1, + 0x08, 0xc1, 0x30, 0xca, 0xae, 0x73, 0x8b, 0x9f, 0x7c, 0xbe, 0xb0, 0xcb, 0x28, 0x5d, 0x43, 0x91, 0xff, 0x90, 0x0b, + 0xf6, 0x57, 0xb1, 0xbf, 0xf4, 0xe2, 0x7b, 0xd2, 0x03, 0x30, 0x55, 0x65, 0x01, 0x43, 0xd7, 0x08, 0xd1, 0x13, 0x00, + 0x08, 0xe7, 0xeb, 0xda, 0x37, 0x32, 0x8d, 0xf1, 0xd9, 0x4a, 0x61, 0x28, 0xf4, 0x75, 0xad, 0x3f, 0x65, 0xf6, 0x94, + 0xa5, 0x9e, 0x1f, 0x50, 0x95, 0x81, 0x88, 0x72, 0x5f, 0x99, 0x5e, 0x52, 0x9c, 0x5e, 0x58, 0xdc, 0x3f, 0x38, 0x19, + 0xba, 0x02, 0x68, 0xdc, 0x38, 0x33, 0x8c, 0x7e, 0x55, 0xbf, 0xa2, 0x94, 0xf7, 0xa7, 0x2e, 0x07, 0x83, 0xe5, 0x08, + 0x61, 0x39, 0x58, 0x38, 0x89, 0xa6, 0xec, 0xa7, 0xb7, 0xaf, 0x65, 0xb8, 0x2d, 0xe0, 0x1c, 0x8d, 0xf8, 0xc6, 0x4c, + 0x90, 0x7e, 0x88, 0x91, 0x76, 0xa0, 0xc0, 0x58, 0x9a, 0xdc, 0x42, 0x71, 0xa6, 0x6b, 0x67, 0x34, 0x76, 0x36, 0xa5, + 0x51, 0x0f, 0x23, 0xac, 0x15, 0x67, 0x27, 0x07, 0x54, 0x9a, 0x6e, 0x3b, 0x2a, 0x04, 0x60, 0x88, 0x61, 0x86, 0x39, + 0x14, 0x20, 0x32, 0xe8, 0xd0, 0xcd, 0x1f, 0x14, 0xf6, 0x12, 0xf9, 0xf3, 0xee, 0x59, 0x91, 0x54, 0xc1, 0x5a, 0xfa, + 0xe9, 0x09, 0xc6, 0xfa, 0x82, 0xfb, 0x1a, 0xbc, 0x83, 0x9c, 0x1c, 0xd0, 0xa7, 0x56, 0x3a, 0x11, 0x79, 0x23, 0xe2, + 0x69, 0xd7, 0xe7, 0x0d, 0x7c, 0xd2, 0x51, 0x81, 0xd0, 0xf2, 0x90, 0xea, 0x65, 0xba, 0xb6, 0xe4, 0xa4, 0x11, 0x77, + 0x43, 0x04, 0x3e, 0x0a, 0x1c, 0x38, 0xbb, 0xba, 0xb6, 0xf4, 0xee, 0x70, 0xe6, 0x22, 0xc7, 0xbb, 0x6b, 0xb9, 0x3c, + 0x2b, 0x3f, 0x6b, 0x49, 0xf1, 0xac, 0x4d, 0xf8, 0xe2, 0x82, 0x01, 0x82, 0x7c, 0x91, 0x2f, 0x50, 0xb0, 0x5b, 0xb3, + 0xb8, 0x0b, 0xb1, 0xb8, 0xd3, 0x86, 0xc5, 0x9d, 0x6e, 0x59, 0xdc, 0x80, 0x2f, 0xa4, 0x26, 0x41, 0x17, 0xa3, 0x51, + 0x99, 0x04, 0x1e, 0x27, 0x34, 0xfa, 0xfc, 0x9c, 0x21, 0x9c, 0xac, 0x24, 0x00, 0xa5, 0xaa, 0x06, 0x58, 0xd5, 0xc1, + 0x45, 0x01, 0x44, 0x75, 0xe2, 0xf2, 0xd4, 0x89, 0x79, 0x43, 0xec, 0xce, 0x56, 0x50, 0x9e, 0x2f, 0xec, 0x52, 0x8a, + 0x4b, 0xde, 0x5a, 0x34, 0xcc, 0x74, 0xb1, 0x65, 0xa6, 0x93, 0xc2, 0xd1, 0xe5, 0xd3, 0xa6, 0x43, 0xa8, 0x4e, 0x0a, + 0xf6, 0x20, 0x28, 0x9a, 0xe2, 0x96, 0x29, 0xee, 0xc3, 0x66, 0x1c, 0xab, 0xec, 0xa8, 0x95, 0x97, 0x24, 0xb7, 0x51, + 0x0c, 0x92, 0x1a, 0x68, 0xe6, 0xd3, 0xb6, 0xd4, 0xd2, 0x0f, 0xb9, 0x13, 0x98, 0xc6, 0xcd, 0x94, 0xe7, 0xab, 0x5b, + 0xaa, 0xdd, 0xed, 0x52, 0x89, 0x95, 0x97, 0xa6, 0x2c, 0x46, 0xa0, 0x7b, 0xe0, 0x2d, 0xfc, 0xbf, 0x64, 0x9b, 0xd5, + 0xe0, 0x90, 0x40, 0xc1, 0xea, 0x88, 0xa1, 0x57, 0x40, 0x5b, 0xc5, 0xe2, 0x22, 0x56, 0x1c, 0xca, 0xc5, 0x12, 0xf0, + 0x3f, 0xe0, 0x71, 0x6d, 0xc5, 0x8a, 0xc9, 0x93, 0x7b, 0x64, 0xd8, 0x2b, 0x6f, 0xfa, 0x0e, 0x04, 0x82, 0xad, 0xb6, + 0x09, 0xca, 0xbd, 0xaa, 0xfb, 0xb8, 0x98, 0x88, 0xbd, 0x49, 0x8e, 0x24, 0x11, 0x4b, 0x72, 0xd5, 0x29, 0xb0, 0xba, + 0xf4, 0xac, 0xd9, 0xd5, 0xa6, 0x9d, 0x1d, 0xcc, 0x7d, 0xa3, 0x82, 0x35, 0x01, 0xb5, 0x05, 0xc3, 0x53, 0xf9, 0xe6, + 0x0a, 0x4c, 0xf7, 0xc8, 0x00, 0x8e, 0xf1, 0x25, 0xc4, 0x41, 0x75, 0xc4, 0x83, 0x76, 0x14, 0xc3, 0xad, 0x75, 0xe9, + 0x5c, 0x65, 0x8f, 0xe7, 0xf8, 0xcb, 0xbd, 0xca, 0x1e, 0x8f, 0xf1, 0x57, 0xfb, 0x0a, 0x23, 0xde, 0xd5, 0x3c, 0xe4, + 0x95, 0x39, 0xeb, 0xa7, 0x85, 0xfd, 0x44, 0x7a, 0x6b, 0x9f, 0xb0, 0x6d, 0xf8, 0x02, 0x3f, 0x7c, 0xb4, 0x49, 0xc0, + 0x52, 0x53, 0x9d, 0x43, 0x68, 0xc7, 0x46, 0x56, 0x9b, 0x3e, 0x6f, 0x48, 0x1f, 0x1b, 0x7f, 0xf2, 0xc5, 0x8f, 0xbb, + 0x24, 0xca, 0xef, 0x94, 0x22, 0x1b, 0xe2, 0x7a, 0xec, 0x87, 0x5e, 0x7c, 0x7f, 0x4d, 0xcf, 0x8b, 0x96, 0xa0, 0xdd, + 0x25, 0x7b, 0x85, 0xc8, 0xcb, 0xa2, 0x98, 0x2c, 0x55, 0x18, 0xc3, 0xf7, 0xfc, 0xa2, 0x1f, 0xfe, 0x3d, 0x56, 0xc8, + 0xb6, 0xc2, 0x03, 0x94, 0x2f, 0x48, 0xa1, 0xa3, 0xeb, 0x47, 0x9b, 0x16, 0xab, 0x36, 0x53, 0x9a, 0x6d, 0x89, 0x2e, + 0x84, 0xe5, 0xc1, 0xc7, 0xec, 0x72, 0xea, 0xf7, 0x51, 0x0e, 0x36, 0x8e, 0xee, 0xac, 0x47, 0x9b, 0xf4, 0x4c, 0x5f, + 0x7a, 0xf1, 0x07, 0x36, 0xb5, 0x26, 0x7e, 0x3c, 0x09, 0x98, 0xde, 0xd7, 0xc7, 0x81, 0x17, 0x7e, 0xe0, 0x9f, 0x56, + 0xb4, 0x4e, 0x51, 0xb2, 0xbd, 0xf3, 0xed, 0x2b, 0x60, 0x42, 0x2c, 0x3b, 0x24, 0x56, 0x6b, 0xa0, 0xa0, 0x3d, 0x97, + 0x0c, 0xaf, 0x9c, 0x50, 0xcc, 0x4b, 0x99, 0xa0, 0x98, 0x09, 0xc2, 0x76, 0xb0, 0x74, 0x35, 0x75, 0x5c, 0x2f, 0xdd, + 0x54, 0xa7, 0x4a, 0xcc, 0x4a, 0x19, 0xaa, 0xf1, 0x1a, 0x5b, 0xf8, 0xfd, 0xdd, 0x51, 0x10, 0xed, 0xfd, 0xbb, 0x93, + 0xad, 0x7c, 0xde, 0x0c, 0x21, 0xd5, 0x22, 0x0b, 0x8b, 0x4f, 0xe8, 0x9c, 0x13, 0x98, 0xcd, 0x5d, 0xab, 0x95, 0xbd, + 0x24, 0x59, 0x2f, 0xd9, 0x94, 0x24, 0x8a, 0x67, 0xf9, 0xa0, 0x8a, 0x2f, 0x0b, 0x75, 0x60, 0xbf, 0xac, 0xdb, 0xc7, + 0x87, 0xcf, 0x41, 0xd3, 0x01, 0x08, 0xca, 0x68, 0x36, 0xd3, 0xf3, 0x37, 0xfe, 0x8e, 0x6a, 0xee, 0xe1, 0x2f, 0xeb, + 0x57, 0x2f, 0x9d, 0x57, 0xb2, 0x72, 0x08, 0x84, 0xb1, 0x10, 0xdb, 0x72, 0xba, 0x58, 0x19, 0xaf, 0x98, 0xd1, 0xcc, + 0x0b, 0x9b, 0xa7, 0x73, 0x59, 0xd8, 0xe2, 0x2b, 0xc6, 0xa6, 0x40, 0x70, 0x9b, 0x95, 0xd4, 0xeb, 0x80, 0xdd, 0x30, + 0x29, 0x12, 0xae, 0x76, 0x56, 0x53, 0x03, 0x7d, 0xd6, 0x71, 0x51, 0x33, 0xa7, 0xea, 0x94, 0x29, 0x8d, 0x70, 0x0e, + 0x7c, 0xe6, 0xea, 0x11, 0x2b, 0x1d, 0xa9, 0x91, 0xa9, 0x2b, 0x03, 0x68, 0x1c, 0xd9, 0x59, 0x43, 0x7a, 0x1f, 0x03, + 0x56, 0xd7, 0x8f, 0xcd, 0x74, 0x8d, 0x3e, 0xf8, 0xf8, 0xe6, 0x70, 0x0a, 0xe0, 0xe4, 0xb5, 0x72, 0x76, 0x48, 0x13, + 0xc4, 0xea, 0x98, 0x64, 0x3a, 0x71, 0x5f, 0x84, 0x96, 0x24, 0xaa, 0x0b, 0x0b, 0x3e, 0x54, 0xed, 0xda, 0x68, 0xc5, + 0x99, 0x8f, 0x31, 0x10, 0x6c, 0xc8, 0x92, 0xa4, 0x11, 0x60, 0x72, 0xd1, 0x4d, 0x3d, 0x2f, 0x5d, 0x84, 0x47, 0x9e, + 0x6e, 0x3a, 0x26, 0x90, 0x04, 0x38, 0xc1, 0x72, 0x5f, 0x78, 0xbd, 0x5c, 0x2f, 0xb9, 0x9e, 0x4b, 0x3c, 0x1f, 0xeb, + 0x5c, 0x07, 0xa1, 0x29, 0xff, 0x56, 0xe7, 0x83, 0x2a, 0x5c, 0xd3, 0xb5, 0x43, 0x6b, 0x15, 0x50, 0x6f, 0x85, 0x5d, + 0x84, 0x0d, 0x88, 0x31, 0x95, 0xf0, 0x2b, 0x9b, 0xcd, 0xd8, 0x24, 0x4d, 0x0c, 0xc1, 0x3c, 0x92, 0x5e, 0x67, 0xc1, + 0xda, 0xe8, 0xc1, 0x50, 0xff, 0x01, 0x6c, 0xef, 0x85, 0x73, 0x26, 0x3e, 0x20, 0xf1, 0x66, 0xaa, 0x07, 0x13, 0xb5, + 0x58, 0x04, 0x11, 0xef, 0x05, 0x82, 0x8a, 0xd7, 0xa4, 0xe3, 0xd0, 0xf8, 0xfd, 0x93, 0xef, 0x8b, 0x48, 0x6a, 0xc3, + 0x6c, 0x47, 0x45, 0xdb, 0x8e, 0xef, 0xc6, 0x7d, 0xd5, 0x75, 0x9d, 0x4c, 0x37, 0xc1, 0xe6, 0xeb, 0xc3, 0xbe, 0x87, + 0x1e, 0x6b, 0x75, 0xa0, 0xd6, 0x3a, 0xfc, 0x94, 0x7a, 0x6d, 0xf7, 0x99, 0xab, 0x9b, 0xa4, 0x6a, 0xa7, 0xe0, 0xb6, + 0x49, 0x74, 0xc3, 0xe2, 0xcf, 0x9e, 0x4a, 0xb1, 0xf1, 0xfd, 0xc6, 0x73, 0xe4, 0x3a, 0x80, 0x84, 0xd3, 0x68, 0xf5, + 0x09, 0x53, 0xe8, 0xe8, 0xa6, 0x3e, 0x09, 0xa2, 0x84, 0xa9, 0x73, 0x20, 0x26, 0xc8, 0x67, 0x4e, 0xe2, 0xc7, 0xb7, + 0x2f, 0xdf, 0xbd, 0xd3, 0x4d, 0x8c, 0x20, 0x9a, 0xa8, 0xad, 0xf3, 0x0d, 0xb5, 0x03, 0xfb, 0xd7, 0xee, 0x3b, 0xba, + 0x61, 0xe8, 0x51, 0x5b, 0xdc, 0x73, 0x94, 0x56, 0xd9, 0x72, 0xfc, 0xe6, 0xe1, 0x3d, 0xd3, 0x4b, 0x74, 0xaf, 0x79, + 0xd5, 0xe0, 0x86, 0xed, 0xd7, 0x5b, 0x21, 0x65, 0xe9, 0x87, 0xd7, 0x35, 0xa9, 0xde, 0x5d, 0x4d, 0x2a, 0x3c, 0xe5, + 0x2a, 0xb8, 0x6a, 0x1d, 0x2d, 0x15, 0xd2, 0x00, 0x02, 0x40, 0xef, 0x02, 0x97, 0xf2, 0x9e, 0xfa, 0x8c, 0x41, 0x73, + 0x0f, 0xf0, 0xe5, 0x51, 0xd7, 0x24, 0xf3, 0x47, 0x90, 0x84, 0xed, 0x24, 0x00, 0x45, 0x41, 0xa6, 0x4a, 0xe5, 0x8a, + 0x64, 0x23, 0x57, 0xf3, 0x1d, 0x96, 0x28, 0x74, 0xaa, 0x46, 0x02, 0x10, 0x8e, 0xdf, 0x57, 0xde, 0x14, 0xb4, 0xef, + 0xac, 0x71, 0x94, 0xa6, 0xd1, 0xb2, 0xef, 0x3a, 0xab, 0x3b, 0x5d, 0x1b, 0x08, 0xc6, 0x03, 0x57, 0x0e, 0xec, 0xff, + 0xf6, 0xef, 0x12, 0xca, 0xa5, 0xf4, 0xeb, 0x94, 0x2d, 0x57, 0x2c, 0xf6, 0xd2, 0x75, 0xcc, 0x32, 0xed, 0xb7, 0xff, + 0x7b, 0x5e, 0x7a, 0x64, 0x0f, 0xd4, 0x3a, 0x44, 0x5e, 0xab, 0x55, 0xae, 0x83, 0xe8, 0xf6, 0x41, 0x6e, 0x06, 0xb0, + 0xa3, 0xf0, 0xc2, 0x9f, 0x2f, 0x64, 0xe9, 0xb3, 0x74, 0xcb, 0xdc, 0xc4, 0xe8, 0x89, 0xe9, 0xae, 0x9d, 0x47, 0xb7, + 0xfd, 0xdf, 0xfe, 0x2d, 0x99, 0x27, 0x3b, 0x77, 0x5d, 0xfd, 0x40, 0x8b, 0x2b, 0x5a, 0x5f, 0xa6, 0xb2, 0xc4, 0x90, + 0x5f, 0x59, 0xe0, 0x4a, 0x22, 0xed, 0xca, 0xaa, 0x84, 0x6b, 0xcb, 0x9c, 0xfe, 0xea, 0xcf, 0x17, 0x9f, 0x3b, 0x29, + 0x00, 0xe8, 0xce, 0x59, 0x41, 0xa1, 0x2f, 0x30, 0xad, 0x51, 0x7f, 0xff, 0x05, 0xfb, 0xcc, 0x79, 0xed, 0x9a, 0xd2, + 0x97, 0x98, 0x0d, 0xe7, 0xa2, 0x3e, 0x1f, 0x8d, 0x64, 0x04, 0x3d, 0xb5, 0x3e, 0x18, 0x32, 0x9c, 0x55, 0x52, 0xf8, + 0x55, 0xdf, 0x77, 0x0c, 0xf2, 0x30, 0xb0, 0x07, 0x40, 0x50, 0x25, 0xaf, 0x06, 0x1c, 0xcd, 0xf8, 0x9a, 0x34, 0xeb, + 0x2b, 0x7d, 0x57, 0x90, 0x35, 0xa4, 0x62, 0xf4, 0x35, 0x29, 0x9a, 0x33, 0xeb, 0x87, 0x73, 0x1b, 0x7b, 0x2b, 0x62, + 0xd8, 0x6b, 0x28, 0x8f, 0x00, 0x06, 0x88, 0x78, 0xd1, 0x62, 0x70, 0x97, 0x37, 0x4d, 0x0a, 0x71, 0x3f, 0xee, 0x56, + 0x88, 0xbb, 0xd8, 0x4b, 0x21, 0xee, 0xc7, 0x2f, 0xae, 0x10, 0xf7, 0x46, 0x55, 0x88, 0x83, 0xb5, 0x7c, 0xc9, 0xf6, + 0xd2, 0x52, 0x13, 0xaa, 0x26, 0xd1, 0x6d, 0x32, 0x74, 0x39, 0x1d, 0x9e, 0x4c, 0x16, 0x0c, 0x18, 0x1b, 0x1c, 0xea, + 0x41, 0x34, 0x07, 0x8d, 0xb5, 0x3f, 0x5e, 0xb7, 0x2c, 0x88, 0xe6, 0xaa, 0x66, 0x59, 0xc8, 0xdd, 0xdb, 0xe6, 0x2e, + 0xab, 0x48, 0x9b, 0xcb, 0x31, 0x85, 0x83, 0x2b, 0xeb, 0xd0, 0x50, 0x42, 0x78, 0x4b, 0x55, 0xbd, 0xb6, 0xd0, 0xf7, + 0xea, 0xa3, 0xaa, 0x98, 0xac, 0xd8, 0x7e, 0x2a, 0x1c, 0x79, 0xa8, 0x2d, 0x48, 0x95, 0x68, 0x72, 0x8a, 0xb1, 0xd1, + 0x7f, 0xb9, 0x73, 0xbf, 0xbb, 0x74, 0x07, 0x1d, 0x17, 0x2c, 0xd1, 0xe1, 0x59, 0x8c, 0x09, 0xce, 0xa0, 0xd3, 0x81, + 0x84, 0x5b, 0x25, 0xa1, 0x0d, 0x09, 0xbe, 0x92, 0xd0, 0x85, 0x84, 0x89, 0x92, 0x70, 0x04, 0x09, 0x53, 0x25, 0xe1, + 0x18, 0x12, 0x6e, 0xf4, 0xec, 0x32, 0x94, 0xc3, 0x3d, 0x36, 0xae, 0x4c, 0x7a, 0x09, 0x89, 0xb4, 0x63, 0xd3, 0x05, + 0x15, 0x31, 0x6f, 0xde, 0x8f, 0x4c, 0x62, 0x89, 0xf6, 0x63, 0xf3, 0x76, 0xc1, 0xc8, 0x2b, 0xf6, 0x0b, 0xbc, 0x28, + 0xed, 0x34, 0x02, 0x25, 0x71, 0xe1, 0x6d, 0x42, 0xc0, 0x41, 0xd3, 0x0d, 0xe0, 0x72, 0x0d, 0xe4, 0xca, 0x09, 0x8f, + 0x1d, 0xca, 0x5a, 0xe6, 0x79, 0xd4, 0x9d, 0x25, 0xb7, 0x40, 0xae, 0x26, 0xd3, 0x52, 0x59, 0xa9, 0x5f, 0x42, 0x59, + 0xe2, 0x05, 0x1b, 0xaf, 0xe7, 0xda, 0x79, 0x34, 0xdf, 0xa9, 0xf7, 0xa0, 0x66, 0xc1, 0x28, 0x75, 0x92, 0x19, 0x59, + 0x62, 0x5b, 0xf2, 0xbe, 0xe8, 0x33, 0x2b, 0x96, 0x4f, 0x61, 0x6c, 0x5a, 0x4a, 0x18, 0x07, 0xfa, 0x01, 0x18, 0x29, + 0x8a, 0x07, 0xe7, 0x00, 0x67, 0xe5, 0xfb, 0xc2, 0x53, 0xc6, 0x73, 0xfa, 0x3d, 0x4b, 0x12, 0x6f, 0x2e, 0xca, 0x57, + 0xc7, 0x09, 0x9a, 0x46, 0xf2, 0xd1, 0x88, 0x00, 0x04, 0xf6, 0xa3, 0x5f, 0x51, 0x28, 0x89, 0xa3, 0x5b, 0x0d, 0x54, + 0x96, 0x60, 0x43, 0xe5, 0xca, 0x15, 0xbe, 0x0d, 0x4b, 0x58, 0x54, 0x83, 0x80, 0xc3, 0x7f, 0xc3, 0x82, 0x72, 0x62, + 0xea, 0xcd, 0xcb, 0x49, 0xb4, 0x0f, 0x32, 0x75, 0x6c, 0x52, 0x0b, 0xa1, 0x90, 0xf8, 0x39, 0x62, 0xf5, 0x20, 0x9a, + 0xff, 0xa1, 0x32, 0xf5, 0x2d, 0xba, 0x10, 0xef, 0x42, 0xd3, 0x4f, 0x47, 0x36, 0xc2, 0x58, 0xb3, 0x01, 0x84, 0xfd, + 0x30, 0x5d, 0x58, 0x68, 0x47, 0xd7, 0x6a, 0x87, 0x86, 0x69, 0xe3, 0xda, 0x6e, 0xca, 0xd6, 0xc3, 0xfd, 0x78, 0x3e, + 0xf6, 0x5a, 0x6e, 0xfb, 0xd8, 0x14, 0x7f, 0x6c, 0xa7, 0x6b, 0x64, 0xd8, 0x82, 0x36, 0xf5, 0x6f, 0x36, 0xb3, 0x28, + 0x4c, 0xad, 0x99, 0xb7, 0xf4, 0x83, 0xfb, 0xfe, 0x32, 0x0a, 0xa3, 0x64, 0xe5, 0x4d, 0xd8, 0x20, 0xe7, 0x02, 0x0c, + 0xd0, 0x2f, 0x05, 0x37, 0x8d, 0x74, 0xed, 0x76, 0xcc, 0x96, 0x54, 0x5b, 0xba, 0x9d, 0x98, 0x05, 0xec, 0x2e, 0xe3, + 0xdd, 0x17, 0x0a, 0x53, 0x51, 0xdc, 0x72, 0x54, 0x03, 0xc8, 0x68, 0xee, 0xd3, 0x02, 0x3c, 0x39, 0x0d, 0x38, 0x2d, + 0xda, 0xb7, 0xdb, 0xdd, 0x98, 0x2d, 0x35, 0xbb, 0xdb, 0xd8, 0x78, 0x1c, 0xdd, 0x9e, 0xc2, 0x68, 0xb1, 0xb2, 0x95, + 0xb0, 0x60, 0x86, 0x39, 0x16, 0x9a, 0xd1, 0x88, 0x76, 0x2c, 0xe4, 0x1e, 0x40, 0x6b, 0x6c, 0x39, 0x80, 0xec, 0x7e, + 0x5b, 0x73, 0x06, 0x4b, 0x3f, 0xb4, 0x68, 0x3a, 0xc7, 0xce, 0x4a, 0x69, 0x4b, 0x85, 0x9f, 0xb1, 0xc1, 0xe2, 0xae, + 0xe6, 0x0c, 0xe0, 0x85, 0x39, 0x0b, 0xa2, 0xdb, 0xfe, 0xc2, 0x9f, 0x4e, 0x59, 0x38, 0xc0, 0x31, 0xcb, 0x44, 0x16, + 0x04, 0xfe, 0x2a, 0xf1, 0x93, 0xc1, 0xd2, 0xbb, 0xe3, 0xad, 0x1e, 0x36, 0xb5, 0xda, 0xe1, 0xad, 0x76, 0xf6, 0x6e, + 0x55, 0x69, 0x06, 0x4c, 0x76, 0xa8, 0x1d, 0x3e, 0xb4, 0xae, 0xe6, 0x94, 0xe6, 0xb9, 0x77, 0xab, 0xab, 0x98, 0x6d, + 0x96, 0x5e, 0x3c, 0xf7, 0xc3, 0xbe, 0x93, 0xd9, 0x37, 0x1b, 0xda, 0x18, 0x0f, 0x7b, 0xbd, 0x5e, 0x66, 0x4f, 0xc5, + 0x97, 0x33, 0x9d, 0x66, 0xf6, 0x44, 0x7c, 0xcd, 0x66, 0x8e, 0x33, 0x9b, 0x65, 0xb6, 0x2f, 0x12, 0x3a, 0xed, 0xc9, + 0xb4, 0xd3, 0xce, 0xec, 0x5b, 0xa5, 0x44, 0x66, 0x33, 0xfe, 0x15, 0xb3, 0xe9, 0x00, 0x37, 0x12, 0xe9, 0xd0, 0xf6, + 0x8f, 0x1d, 0x27, 0x43, 0x0c, 0x70, 0x59, 0xc0, 0x4d, 0xc8, 0xa0, 0xba, 0xda, 0xec, 0x5d, 0x52, 0xcb, 0xbb, 0x9b, + 0x4c, 0x6a, 0xcb, 0x4d, 0xbd, 0xf8, 0xc3, 0x95, 0xa6, 0xcc, 0xc2, 0xf3, 0xa8, 0xd8, 0x46, 0x80, 0xc1, 0xba, 0xeb, + 0x83, 0x7f, 0xb2, 0xc1, 0x38, 0x8a, 0xe1, 0xcc, 0xc6, 0xde, 0xd4, 0x5f, 0x27, 0x7d, 0xb7, 0xbd, 0xba, 0x13, 0x49, + 0x7c, 0xaf, 0xe7, 0x09, 0x78, 0xf6, 0xfa, 0x49, 0x14, 0xf8, 0x53, 0x91, 0xd4, 0x74, 0x96, 0xdc, 0xb6, 0x31, 0x40, + 0xeb, 0x7c, 0x1f, 0x7d, 0x4c, 0x78, 0x41, 0xa0, 0xd9, 0x9d, 0x44, 0x63, 0x5e, 0x82, 0x4c, 0x71, 0xcd, 0x49, 0x08, + 0x2e, 0x68, 0x89, 0xef, 0x1e, 0xae, 0xee, 0xe4, 0x9e, 0x77, 0x8f, 0x56, 0x77, 0xd9, 0x37, 0x4b, 0x36, 0xf5, 0x3d, + 0xad, 0x95, 0xef, 0x26, 0xd7, 0x01, 0xc6, 0xb9, 0xb1, 0x69, 0xd8, 0xa6, 0xe2, 0x58, 0x80, 0x1f, 0xc7, 0x07, 0xfe, + 0x72, 0x15, 0xc5, 0xa9, 0x17, 0xa6, 0x59, 0x36, 0xba, 0xca, 0xb2, 0xc1, 0x85, 0xdf, 0xba, 0xfc, 0x47, 0x8b, 0xee, + 0x69, 0x12, 0x34, 0x65, 0xc6, 0x95, 0xf9, 0x92, 0xa9, 0x8a, 0x2e, 0x70, 0x8d, 0xa1, 0x92, 0x8b, 0x5a, 0x98, 0x6e, + 0xc9, 0x6a, 0x61, 0x02, 0xb2, 0x2c, 0x4e, 0x8a, 0x33, 0xc5, 0x22, 0x78, 0x03, 0x41, 0x81, 0x97, 0x6c, 0x78, 0xa1, + 0x28, 0xcd, 0x00, 0xb1, 0x82, 0x85, 0xc9, 0x88, 0xe2, 0x51, 0x13, 0xcd, 0xf8, 0xed, 0x6e, 0x9a, 0xf1, 0xe7, 0x74, + 0x1f, 0x9a, 0xf1, 0xdb, 0x2f, 0x4e, 0x33, 0x3e, 0xaa, 0x1a, 0x51, 0xbc, 0x8e, 0x86, 0xba, 0x14, 0x8b, 0xc0, 0xd5, + 0x14, 0x93, 0x7b, 0xa2, 0xd7, 0xbf, 0xdb, 0xe6, 0x41, 0xb4, 0x46, 0x01, 0xf7, 0xe8, 0xe6, 0x06, 0x26, 0xf2, 0x9b, + 0x70, 0xf8, 0xf7, 0x58, 0xfd, 0x9e, 0xcd, 0x86, 0x2f, 0x22, 0x25, 0x41, 0x7e, 0x71, 0x8d, 0x91, 0x82, 0x2b, 0x09, + 0xca, 0x11, 0xaa, 0xa3, 0x18, 0x6c, 0x03, 0x2c, 0xd1, 0x49, 0x55, 0x7a, 0x2a, 0x55, 0xe6, 0x06, 0xc5, 0x21, 0xb4, + 0xa4, 0x9e, 0xaa, 0xb0, 0x37, 0xaa, 0xf0, 0x3f, 0xe7, 0x2c, 0xe5, 0x06, 0xc2, 0xdf, 0xdd, 0xbf, 0x9e, 0xb6, 0x5e, + 0x47, 0x46, 0xe6, 0x27, 0x6f, 0xca, 0xd6, 0x3e, 0x5c, 0x60, 0x35, 0x54, 0xa7, 0x93, 0x71, 0xb5, 0x37, 0x35, 0x9a, + 0x36, 0x64, 0x53, 0xf5, 0xb3, 0xc2, 0x4c, 0xfb, 0x6a, 0x45, 0x1e, 0xd5, 0xab, 0x72, 0x19, 0x73, 0x53, 0x8b, 0x0d, + 0xa7, 0x00, 0x31, 0x50, 0x19, 0x1a, 0x49, 0x4f, 0xa9, 0xba, 0x3f, 0xcd, 0x32, 0x63, 0x20, 0x00, 0xa1, 0x5c, 0xb4, + 0x6c, 0x17, 0x11, 0x97, 0xe4, 0xef, 0x31, 0x2e, 0xd6, 0x24, 0x99, 0xe5, 0x6b, 0xd0, 0x02, 0xe0, 0x12, 0x4e, 0x0e, + 0x33, 0x5d, 0x23, 0xf0, 0x91, 0x76, 0x88, 0x32, 0x21, 0x10, 0x5b, 0x4b, 0xf8, 0x8b, 0x2c, 0x91, 0x50, 0x55, 0x3c, + 0x25, 0xe0, 0xa0, 0x1a, 0x03, 0xb8, 0x34, 0x10, 0xcc, 0x1a, 0x42, 0x3b, 0xbc, 0x0c, 0x7e, 0x64, 0xba, 0xa4, 0xfd, + 0x70, 0xfb, 0x9d, 0x9e, 0x1c, 0x40, 0x85, 0xd3, 0x12, 0x23, 0x66, 0x87, 0x5a, 0x25, 0x90, 0x12, 0xc9, 0xad, 0x69, + 0x27, 0xb7, 0xda, 0x93, 0x8d, 0x70, 0x07, 0x92, 0x7a, 0x2b, 0x0b, 0x5e, 0xff, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x3c, + 0x8f, 0x0c, 0xd6, 0x09, 0xe0, 0x46, 0x7c, 0x88, 0x22, 0xfe, 0x19, 0x4c, 0xd6, 0x71, 0x12, 0xc5, 0xfd, 0x55, 0xe4, + 0x87, 0x29, 0x8b, 0x33, 0x04, 0xd5, 0x25, 0xc2, 0x47, 0x80, 0xe7, 0x6a, 0x13, 0xad, 0xbc, 0x89, 0x9f, 0xde, 0xf7, + 0x1d, 0x4e, 0x52, 0x38, 0x03, 0x4e, 0x1d, 0x38, 0xb5, 0xe5, 0xfb, 0x1c, 0x9a, 0x4f, 0x91, 0xf0, 0x8b, 0xab, 0xe4, + 0x8c, 0xba, 0xcd, 0x07, 0x4a, 0x2e, 0x39, 0x44, 0x01, 0xf2, 0xc3, 0x8b, 0xad, 0x39, 0x60, 0x79, 0x58, 0x6a, 0x67, + 0xca, 0xe6, 0x26, 0x62, 0x6d, 0x10, 0x26, 0x88, 0x3f, 0x76, 0xd7, 0xd0, 0x9c, 0xfa, 0x64, 0xa0, 0x78, 0x8c, 0x7d, + 0x46, 0xd6, 0xf7, 0x20, 0x7c, 0x98, 0xb9, 0x4f, 0xc9, 0x31, 0x9b, 0x45, 0x31, 0x23, 0xe7, 0xb9, 0x6e, 0x6f, 0x75, + 0xb7, 0x7f, 0xf3, 0xdb, 0xa7, 0x5f, 0xdf, 0x4e, 0x18, 0xa5, 0x2d, 0xd1, 0x98, 0xb1, 0xa3, 0xb5, 0xea, 0x7d, 0x06, + 0xa4, 0x21, 0x41, 0x7e, 0x42, 0x7e, 0xca, 0xfa, 0xba, 0x3e, 0xa8, 0xf5, 0x51, 0xb6, 0x8a, 0xf8, 0x9d, 0x17, 0xb3, + 0xc0, 0x4b, 0xfd, 0x1b, 0x41, 0x33, 0x76, 0x8e, 0x56, 0x77, 0x62, 0x8d, 0xf1, 0xc2, 0xfb, 0x84, 0x45, 0x2a, 0x0d, + 0x45, 0x2c, 0x52, 0x39, 0x19, 0x17, 0x69, 0x50, 0x99, 0x8d, 0x70, 0xdb, 0x51, 0xba, 0xe9, 0xbb, 0xab, 0x3b, 0xf5, + 0x8a, 0xce, 0xab, 0xc9, 0x9b, 0xba, 0xec, 0x6f, 0x6d, 0xe9, 0x4f, 0xa7, 0x01, 0xcb, 0x0a, 0x0b, 0x5d, 0x5c, 0x4b, + 0x05, 0x38, 0x12, 0x0e, 0xde, 0x38, 0x89, 0x82, 0x75, 0xca, 0xea, 0xc1, 0x45, 0xc0, 0x69, 0x3b, 0x39, 0x70, 0xf0, + 0x77, 0x71, 0xac, 0x5d, 0x20, 0xb7, 0x61, 0x9b, 0x38, 0x03, 0x70, 0xaf, 0x6c, 0x75, 0x8a, 0x43, 0x87, 0x2c, 0x39, + 0x68, 0xb3, 0x66, 0x22, 0x26, 0x5c, 0x4b, 0x84, 0xbd, 0x35, 0xdb, 0xe5, 0x69, 0xd2, 0xc5, 0xac, 0x4c, 0xca, 0x8a, + 0x93, 0xf9, 0x63, 0xce, 0xd8, 0xb3, 0xfa, 0x33, 0xf6, 0x4c, 0x9c, 0xb1, 0xed, 0x3b, 0xf3, 0xe1, 0xcc, 0x85, 0xff, + 0x06, 0xf9, 0x84, 0xfa, 0x8e, 0xd6, 0x59, 0xdd, 0x69, 0xee, 0xea, 0x4e, 0xb3, 0xda, 0xab, 0x3b, 0x0d, 0x9b, 0x46, + 0x25, 0x16, 0xd3, 0x6e, 0x1b, 0xa6, 0xa3, 0x41, 0x22, 0xfc, 0x71, 0x0a, 0x59, 0xee, 0x21, 0xe4, 0x41, 0xad, 0x6e, + 0x35, 0xaf, 0xbd, 0xfd, 0xa8, 0xd3, 0x59, 0x12, 0x48, 0xdb, 0xb0, 0x53, 0x6f, 0x3c, 0x66, 0xd3, 0xfe, 0x2c, 0x9a, + 0xac, 0x93, 0x7f, 0xf1, 0xf1, 0x73, 0x20, 0x6e, 0x45, 0x04, 0xa5, 0x76, 0x44, 0x55, 0x90, 0xee, 0xdc, 0x30, 0xd1, + 0xc2, 0x46, 0xae, 0x53, 0x9f, 0x7c, 0x41, 0xb7, 0xed, 0xc3, 0x9a, 0x4d, 0x5e, 0x0f, 0xe8, 0x3f, 0x6c, 0x95, 0x9a, + 0x51, 0xcc, 0x67, 0x80, 0x65, 0x2b, 0x38, 0x3e, 0x1d, 0x1a, 0x7c, 0x35, 0x9d, 0x5e, 0xfd, 0x70, 0x2f, 0x45, 0x4f, + 0x57, 0xe2, 0x52, 0xe1, 0xf7, 0x16, 0xb7, 0xa6, 0xd9, 0xde, 0x6a, 0xd3, 0x1e, 0xa9, 0xb4, 0xba, 0xe5, 0x42, 0xc8, + 0xcb, 0xee, 0x89, 0xe5, 0x1f, 0x3e, 0x3b, 0x84, 0xff, 0x88, 0xaa, 0xff, 0x39, 0xad, 0x23, 0xd4, 0x5f, 0x17, 0xd5, + 0xd7, 0x89, 0x54, 0x42, 0x42, 0x7c, 0xff, 0xf2, 0xb3, 0xd9, 0xa7, 0x55, 0xd8, 0xbb, 0x34, 0xe9, 0x7f, 0x95, 0x4b, + 0x7f, 0x17, 0x45, 0x10, 0xa7, 0xb4, 0x5a, 0x5c, 0x80, 0x87, 0x34, 0xf4, 0xd3, 0x21, 0x54, 0x12, 0xef, 0x08, 0x52, + 0x3d, 0xd0, 0xb1, 0x0e, 0x3d, 0x25, 0x5e, 0x36, 0x3d, 0x25, 0x5e, 0xec, 0x7e, 0x4a, 0xfc, 0x6d, 0xaf, 0xa7, 0xc4, + 0x8b, 0x2f, 0xfe, 0x94, 0x78, 0x59, 0x7d, 0x4a, 0x5c, 0x44, 0x42, 0xe9, 0xd7, 0x7c, 0xbd, 0xe6, 0x3f, 0xdf, 0x93, + 0x24, 0xf1, 0x3c, 0x1a, 0x76, 0x1d, 0xf2, 0xef, 0x7c, 0xf1, 0xbb, 0x1f, 0x16, 0xb8, 0x11, 0xdf, 0xa2, 0x0e, 0x5c, + 0xfe, 0xb4, 0xe0, 0x98, 0x1d, 0xfb, 0x51, 0x92, 0x83, 0x28, 0x9c, 0xff, 0x08, 0x92, 0x64, 0x60, 0x07, 0xc6, 0x4a, + 0x86, 0x9f, 0xfc, 0x18, 0xad, 0xd6, 0xab, 0xd7, 0xd0, 0xd6, 0x7b, 0x3f, 0xf1, 0xc7, 0x01, 0x93, 0x66, 0xd7, 0xa4, + 0xb3, 0xc7, 0x79, 0xe2, 0xa0, 0x26, 0x2b, 0x7e, 0x7a, 0x77, 0xe2, 0x27, 0x2a, 0xd2, 0xf2, 0xdf, 0xa4, 0x0c, 0xa8, + 0xd7, 0x3f, 0x44, 0xc0, 0x41, 0x51, 0x69, 0xd0, 0x9f, 0xfe, 0x18, 0xb9, 0x88, 0x8c, 0x9a, 0x59, 0x0a, 0x25, 0x8d, + 0xc6, 0x76, 0x58, 0xe5, 0x51, 0xb3, 0x36, 0x4c, 0xe9, 0x6f, 0xac, 0xca, 0x86, 0x5f, 0x46, 0xeb, 0x84, 0x4d, 0xa3, + 0xdb, 0x50, 0x37, 0x43, 0x69, 0x19, 0x01, 0x62, 0x59, 0x59, 0x07, 0x23, 0x65, 0xbe, 0x43, 0x42, 0x39, 0x8a, 0x5b, + 0x3a, 0x04, 0x6a, 0x5d, 0xaf, 0x2c, 0x92, 0x8f, 0x5b, 0x38, 0x45, 0x5d, 0x86, 0x74, 0x7a, 0xd0, 0x6a, 0x45, 0xc3, + 0x4f, 0xab, 0x29, 0xf4, 0x4b, 0x22, 0x9b, 0x73, 0x85, 0x93, 0x56, 0x28, 0x98, 0x8b, 0xc2, 0xe9, 0x47, 0xcd, 0xc2, + 0xf1, 0x1c, 0xb2, 0xb7, 0xcd, 0x73, 0xc1, 0x65, 0x4a, 0xb6, 0xe6, 0xeb, 0xc1, 0x5d, 0x60, 0xd0, 0xe7, 0x73, 0x05, + 0x8c, 0x6f, 0x6e, 0x58, 0x1c, 0x78, 0xf7, 0x2d, 0x23, 0x8b, 0xc2, 0xef, 0x01, 0x00, 0x2f, 0xa2, 0xdb, 0x50, 0x2d, + 0x80, 0x91, 0x69, 0x6a, 0xf6, 0x52, 0xad, 0xb3, 0x16, 0xb0, 0xb6, 0x51, 0x46, 0x00, 0x31, 0x81, 0xe7, 0xec, 0xef, + 0x26, 0xfd, 0xfb, 0x0f, 0x23, 0x33, 0xcf, 0x23, 0xd9, 0xd1, 0x4f, 0xab, 0x3d, 0xba, 0x79, 0xfc, 0xf8, 0x41, 0xf3, + 0xb4, 0x8b, 0xb1, 0xe8, 0x6b, 0x6a, 0x1b, 0x8d, 0xa7, 0x00, 0x46, 0x71, 0x11, 0xad, 0x27, 0x0b, 0xd4, 0xce, 0xfd, + 0x72, 0xf3, 0x4d, 0xa1, 0x4d, 0x0c, 0xc9, 0x2a, 0xa7, 0x5e, 0x4a, 0xca, 0xa1, 0x80, 0xfd, 0xbf, 0x04, 0x6f, 0xa3, + 0xff, 0x41, 0x30, 0x54, 0x77, 0x0d, 0x7f, 0xc5, 0xfb, 0x9f, 0xb6, 0x79, 0x07, 0x10, 0x39, 0x94, 0xfb, 0xf1, 0x10, + 0xc2, 0xb5, 0x7a, 0x24, 0x93, 0x95, 0x81, 0xa6, 0xfa, 0xcc, 0x6b, 0x72, 0x07, 0x28, 0x7a, 0x61, 0x36, 0x3d, 0xd3, + 0xb9, 0x75, 0x84, 0xc9, 0x38, 0xb6, 0x2a, 0x21, 0x19, 0xae, 0xa7, 0xc1, 0x10, 0x7d, 0x95, 0xf3, 0x96, 0x7e, 0x68, + 0xa2, 0xcb, 0xfb, 0x6a, 0x8e, 0x77, 0x07, 0x4e, 0x9f, 0x01, 0xb9, 0x95, 0xb3, 0x20, 0xd1, 0x54, 0x8d, 0xfd, 0x20, + 0xae, 0x95, 0x5e, 0x0b, 0x09, 0x21, 0xc5, 0x1b, 0x7d, 0xa5, 0x69, 0x9a, 0x26, 0x9f, 0x11, 0x9a, 0x7c, 0x47, 0x60, + 0x3a, 0x3e, 0x07, 0x40, 0x5a, 0x92, 0xad, 0xee, 0x28, 0x05, 0x5e, 0x06, 0x28, 0x99, 0x15, 0x09, 0xdc, 0xaf, 0x61, + 0xd7, 0x11, 0x09, 0xe2, 0x41, 0x0f, 0x3e, 0xe9, 0xbc, 0x18, 0xdc, 0x1f, 0xf7, 0x35, 0x7c, 0xb0, 0x63, 0x2e, 0xe7, + 0x04, 0x6b, 0x0e, 0x7d, 0x8e, 0x06, 0xac, 0xde, 0x01, 0x5e, 0xa8, 0x60, 0x41, 0x90, 0x3a, 0x94, 0xfc, 0x59, 0x9b, + 0xac, 0x06, 0x37, 0xe2, 0xbb, 0xe8, 0x2e, 0x5d, 0xb2, 0x70, 0xad, 0x63, 0x00, 0x2c, 0x74, 0x48, 0x08, 0x65, 0x5e, + 0x10, 0xb1, 0x05, 0xd8, 0xa6, 0xbe, 0xe6, 0x82, 0xee, 0xc2, 0x84, 0xa3, 0x54, 0xcf, 0x9c, 0x70, 0xc1, 0x66, 0xc2, + 0x71, 0x5b, 0xf9, 0x86, 0xe0, 0x4b, 0x1a, 0x95, 0xad, 0xcf, 0x48, 0x7d, 0x1b, 0xda, 0x20, 0x57, 0x20, 0x9c, 0x5d, + 0x24, 0xc0, 0xde, 0xf2, 0xca, 0x8b, 0x26, 0x25, 0x32, 0x5e, 0x89, 0x51, 0x14, 0x1b, 0xd5, 0x66, 0xf8, 0x38, 0xc1, + 0x0b, 0x53, 0x63, 0x3b, 0x93, 0x4a, 0x3b, 0x0d, 0x93, 0xfe, 0xc0, 0xee, 0xe9, 0x22, 0x21, 0x50, 0x7d, 0x60, 0xf7, + 0xa0, 0xb0, 0xf8, 0x12, 0xb8, 0x29, 0xfa, 0x16, 0x74, 0x6d, 0x42, 0x5c, 0x83, 0x09, 0x78, 0xe6, 0xda, 0x72, 0x80, + 0x9c, 0x6c, 0x0b, 0x16, 0x47, 0x10, 0x43, 0x08, 0x6b, 0x71, 0x88, 0xb9, 0x5d, 0x42, 0xab, 0x16, 0xc6, 0x56, 0xcd, + 0xd1, 0x30, 0x9e, 0xb8, 0x8e, 0x73, 0x50, 0x29, 0x0f, 0x8c, 0xec, 0xba, 0xd2, 0x86, 0x99, 0x0e, 0x5d, 0xc7, 0xf2, + 0x9f, 0xd8, 0xed, 0x41, 0xe5, 0x8e, 0x56, 0x1c, 0x67, 0x8e, 0x90, 0xfd, 0x75, 0xfa, 0x68, 0xd3, 0xaa, 0x1c, 0x48, + 0xa3, 0xac, 0xe7, 0x8f, 0x63, 0xcb, 0x38, 0xff, 0x6b, 0x54, 0xbd, 0xfa, 0xc9, 0x6d, 0x27, 0x05, 0x71, 0x19, 0x81, + 0xeb, 0xe7, 0x16, 0x1c, 0xa3, 0xbf, 0x68, 0x4f, 0xb5, 0x16, 0x1d, 0x1f, 0xc3, 0x18, 0xc9, 0xd8, 0xe0, 0xc2, 0x10, + 0x4e, 0x6d, 0xa0, 0xd4, 0x63, 0x52, 0xc6, 0x70, 0xdc, 0xc9, 0x2c, 0xcb, 0x25, 0x7a, 0x5b, 0xa9, 0x05, 0x6c, 0xbf, + 0xe1, 0xfa, 0xb4, 0xc7, 0xe0, 0x4c, 0x01, 0x4a, 0x80, 0xa3, 0xf8, 0x9d, 0x0d, 0xae, 0x57, 0xc5, 0xe6, 0x8a, 0x97, + 0xe4, 0xfe, 0x8d, 0xe1, 0xa5, 0x83, 0x32, 0x34, 0xd9, 0x5e, 0xfd, 0x75, 0xf7, 0x89, 0x4d, 0xb2, 0x70, 0x5a, 0x6c, + 0xb0, 0x74, 0x7f, 0xed, 0xdf, 0x5c, 0x01, 0xa3, 0x40, 0x04, 0x85, 0xa8, 0x06, 0xa3, 0x64, 0x51, 0x88, 0x9b, 0x9f, + 0x8e, 0x9b, 0xbf, 0x17, 0x15, 0x83, 0x15, 0xc8, 0xfd, 0x99, 0xac, 0xa6, 0x30, 0xc5, 0xc1, 0x4d, 0x37, 0xda, 0x32, + 0xb7, 0x04, 0x21, 0xda, 0xb8, 0x13, 0x53, 0xa1, 0x08, 0x99, 0xd7, 0xf1, 0xb9, 0xe3, 0xcd, 0x7d, 0xb9, 0xd6, 0xfe, + 0x6e, 0xae, 0x75, 0xba, 0x8b, 0x6b, 0x4d, 0x36, 0x60, 0xa4, 0xbd, 0x23, 0x6d, 0xe1, 0x04, 0x71, 0xae, 0x5a, 0x13, + 0x16, 0x58, 0xdd, 0x68, 0x32, 0x26, 0x6a, 0x55, 0x5a, 0x23, 0xd5, 0x46, 0x64, 0x7f, 0x2b, 0x0f, 0x14, 0x21, 0x50, + 0x57, 0x79, 0xe3, 0x17, 0x39, 0x6f, 0x9c, 0x5e, 0x35, 0xb9, 0xf5, 0x8f, 0xa0, 0xfe, 0x15, 0xcb, 0x3a, 0xf9, 0x3a, + 0xc8, 0x2d, 0xec, 0xf2, 0x91, 0x2a, 0x36, 0x63, 0xf9, 0x43, 0x43, 0xb1, 0x44, 0x14, 0xaf, 0x8c, 0xa2, 0x41, 0x62, + 0xb1, 0x68, 0x6e, 0x32, 0x96, 0xa7, 0x03, 0xd7, 0x1d, 0x87, 0x2c, 0x93, 0xd5, 0x6d, 0x53, 0xb4, 0x19, 0x52, 0xb3, + 0x95, 0x4d, 0x22, 0x8d, 0x7b, 0x08, 0xc0, 0x82, 0x4d, 0x5f, 0x92, 0x6b, 0x4b, 0x1d, 0x08, 0x1c, 0x64, 0x8d, 0x2d, + 0xe2, 0x6e, 0xee, 0x3c, 0x05, 0x87, 0xc8, 0x45, 0xd7, 0x2e, 0xde, 0xee, 0x24, 0x09, 0x56, 0xf9, 0x11, 0x08, 0xeb, + 0x2b, 0x85, 0x83, 0xd0, 0x77, 0x34, 0x67, 0x50, 0x43, 0x00, 0xe0, 0xfd, 0x5f, 0xfe, 0xe6, 0xa4, 0x00, 0x70, 0x22, + 0x35, 0x47, 0x95, 0xf9, 0xe3, 0x21, 0xb6, 0x48, 0xfd, 0x18, 0x8b, 0x56, 0xfb, 0x24, 0x7e, 0xcf, 0x86, 0x5b, 0xfe, + 0x14, 0xd9, 0xf9, 0xbc, 0x44, 0x5f, 0x8c, 0x83, 0xef, 0xb2, 0x78, 0x1d, 0xa2, 0xcf, 0x7f, 0x2b, 0x8d, 0xbd, 0xc9, + 0x87, 0x8d, 0xd2, 0x1f, 0x67, 0x89, 0x02, 0xbb, 0xb8, 0x28, 0x54, 0x18, 0x78, 0xe8, 0x22, 0x93, 0xf5, 0xed, 0x76, + 0xa2, 0x30, 0x6a, 0xfa, 0x0f, 0x9d, 0x8e, 0xf7, 0x6c, 0x76, 0x58, 0xe2, 0x9f, 0xb6, 0xbb, 0x45, 0xee, 0xba, 0x1c, + 0xc7, 0x32, 0xfa, 0x95, 0xdb, 0x48, 0xfe, 0xf9, 0x5d, 0x27, 0xbc, 0xcf, 0xd2, 0x1a, 0x7d, 0xce, 0x10, 0xa0, 0x7e, + 0x41, 0x30, 0xad, 0x8a, 0x69, 0x2a, 0x29, 0x4d, 0xc3, 0x9a, 0xf9, 0x41, 0x60, 0x05, 0x60, 0xa9, 0xb2, 0xf9, 0xac, + 0xe9, 0x61, 0x3b, 0x6b, 0x70, 0xce, 0xfc, 0x19, 0xed, 0x14, 0x77, 0x4a, 0xba, 0x58, 0x2f, 0xc7, 0x1b, 0x95, 0x51, + 0xae, 0xf0, 0xcf, 0xab, 0x3c, 0x73, 0xb5, 0xdb, 0xd9, 0x6c, 0x56, 0xe4, 0x1a, 0x3b, 0xda, 0x21, 0x72, 0x7e, 0x1f, + 0x3a, 0x8e, 0x53, 0x86, 0x6f, 0xd3, 0x41, 0xa1, 0x83, 0x61, 0x21, 0x13, 0xbe, 0xb7, 0x7b, 0x4f, 0xfd, 0x49, 0xa3, + 0xa5, 0xa6, 0x9a, 0xce, 0x23, 0x6d, 0xb5, 0xff, 0x8a, 0xa1, 0x20, 0x6a, 0xd8, 0x75, 0xfc, 0xab, 0x7b, 0x65, 0x4b, + 0x4b, 0xe5, 0x03, 0xfc, 0x69, 0x95, 0x77, 0xec, 0xf5, 0x3d, 0xaa, 0x36, 0x6d, 0xef, 0xcc, 0xce, 0xaf, 0xdd, 0x82, + 0xce, 0xd2, 0x80, 0x34, 0x95, 0xfc, 0x94, 0x2d, 0x93, 0xfe, 0x84, 0xa1, 0x80, 0xd4, 0x56, 0x6e, 0x5b, 0xd4, 0xea, + 0xb1, 0xe6, 0xa0, 0xc7, 0xe5, 0x0a, 0x3c, 0xec, 0x68, 0x28, 0xac, 0xaa, 0x48, 0xd6, 0x44, 0x27, 0x78, 0x8b, 0x6d, + 0xaa, 0x02, 0x27, 0xdc, 0xa6, 0x5d, 0xe7, 0x2f, 0x85, 0x72, 0x1a, 0x50, 0xa7, 0x1b, 0xa1, 0x6d, 0x42, 0xc2, 0x13, + 0xfc, 0x5b, 0x0a, 0xe7, 0x9e, 0xad, 0xee, 0x8a, 0xca, 0x5d, 0x3d, 0x10, 0x37, 0xe5, 0x57, 0x19, 0x8d, 0xba, 0x0e, + 0xf5, 0x49, 0x15, 0xa0, 0x99, 0xaa, 0xdd, 0x02, 0x1a, 0x34, 0x85, 0x50, 0x44, 0x35, 0xb2, 0x31, 0x7c, 0xce, 0xc2, + 0xce, 0xcb, 0xf9, 0xfb, 0x79, 0x20, 0x4d, 0x98, 0x83, 0xf9, 0xb4, 0x87, 0xc2, 0xbd, 0xc2, 0x56, 0x45, 0x55, 0x19, + 0xdc, 0x03, 0xe2, 0x45, 0xaa, 0xad, 0xe3, 0xc0, 0xa2, 0x38, 0x3d, 0x2d, 0x63, 0x53, 0x9d, 0x77, 0x73, 0xf3, 0x6e, + 0x17, 0xe4, 0x1a, 0x55, 0x50, 0xed, 0x25, 0xda, 0x2b, 0xcb, 0xb0, 0xc5, 0x38, 0x61, 0x05, 0xc0, 0x92, 0x42, 0x43, + 0xa5, 0x21, 0xad, 0x84, 0xfb, 0x68, 0xd2, 0x32, 0x57, 0x45, 0xd6, 0x62, 0x9e, 0xd8, 0x5c, 0x7d, 0x11, 0x6a, 0x5b, + 0x48, 0x06, 0x01, 0x76, 0x1c, 0x3b, 0xe1, 0xb7, 0x05, 0x3b, 0x46, 0x45, 0x57, 0x2e, 0xee, 0x20, 0x3c, 0xa5, 0x16, + 0xd2, 0xc9, 0x09, 0x9d, 0x52, 0x94, 0x25, 0xfc, 0xad, 0x96, 0x79, 0x7f, 0x51, 0xe0, 0xc6, 0x73, 0x73, 0x96, 0xb6, + 0xb1, 0x57, 0xe9, 0xa5, 0x1f, 0xee, 0x5f, 0xd6, 0xbb, 0xdb, 0xbb, 0x2c, 0x10, 0x87, 0x7b, 0x17, 0x06, 0xea, 0x92, + 0xb4, 0x94, 0xd2, 0xe1, 0xdf, 0x14, 0xe1, 0x81, 0xea, 0x16, 0x41, 0xc7, 0x5a, 0xf4, 0xa2, 0xbf, 0x58, 0x0f, 0x47, + 0x27, 0x67, 0x77, 0xcb, 0x40, 0xbb, 0x61, 0x31, 0xc4, 0x2c, 0x1b, 0xea, 0xae, 0xed, 0xe8, 0x1a, 0x1a, 0xf9, 0xfb, + 0xe1, 0x7c, 0xa8, 0xff, 0x74, 0xf1, 0xca, 0xea, 0xe9, 0x67, 0xa0, 0x8e, 0x71, 0x33, 0x47, 0x12, 0xf7, 0xdc, 0xbb, + 0x67, 0xf1, 0x75, 0x5b, 0xd7, 0x30, 0x34, 0x19, 0x11, 0xb7, 0x98, 0xa6, 0xb5, 0xf5, 0x3d, 0x22, 0xe0, 0x68, 0x22, + 0x88, 0xa5, 0x0e, 0x88, 0xd5, 0x6d, 0xf7, 0x34, 0xb7, 0x7d, 0x68, 0x1f, 0xf5, 0xf4, 0xd3, 0xaf, 0x34, 0xed, 0x64, + 0xca, 0x66, 0xc9, 0x29, 0xb2, 0x63, 0x4e, 0x90, 0x1e, 0xa4, 0xdf, 0x9a, 0x66, 0x4f, 0x82, 0xc4, 0x72, 0xb5, 0x0d, + 0xff, 0xd4, 0x34, 0x40, 0x46, 0x7d, 0xed, 0xe1, 0xac, 0x3d, 0x3b, 0x9c, 0x3d, 0x1b, 0xf0, 0xe4, 0xec, 0xab, 0x42, + 0x71, 0x93, 0xfe, 0x6d, 0x2b, 0xd5, 0x92, 0x34, 0x8e, 0x3e, 0x30, 0x4e, 0x4b, 0x6a, 0x92, 0x51, 0x54, 0xae, 0xda, + 0xae, 0xf6, 0xe4, 0xf6, 0xc6, 0x93, 0x59, 0x3b, 0x2f, 0x8e, 0x63, 0x3c, 0x90, 0x83, 0x3c, 0x39, 0x10, 0x43, 0x3f, + 0x51, 0xc1, 0xe4, 0x5a, 0x75, 0x80, 0x72, 0x75, 0x3e, 0xc7, 0xb9, 0x98, 0xdf, 0x09, 0x38, 0x98, 0xcd, 0x0d, 0x10, + 0x12, 0xac, 0x36, 0xd4, 0xbf, 0x77, 0xdb, 0x3d, 0xd3, 0x75, 0x8f, 0xec, 0xa3, 0xde, 0xc4, 0x31, 0x0f, 0xed, 0x43, + 0xab, 0x63, 0x1f, 0x99, 0x3d, 0xab, 0x67, 0xf6, 0xfe, 0xda, 0x9b, 0x58, 0x87, 0xf6, 0xa1, 0xe9, 0x58, 0x3d, 0x48, + 0xb4, 0x7a, 0x56, 0xef, 0xc6, 0x3a, 0xec, 0x4d, 0x1c, 0x4c, 0x6d, 0xdb, 0xdd, 0xae, 0xe5, 0x3a, 0x76, 0xb7, 0x6b, + 0x76, 0xed, 0xa3, 0x23, 0xcb, 0xed, 0xd8, 0x47, 0x47, 0xe7, 0xdd, 0x9e, 0xdd, 0x81, 0xbc, 0x4e, 0x67, 0xd2, 0xb1, + 0x5d, 0xd7, 0x82, 0xbf, 0xcc, 0x9e, 0xdd, 0xa6, 0x1f, 0xae, 0x6b, 0x77, 0x5c, 0xd3, 0x09, 0xba, 0x6d, 0xfb, 0xe8, + 0x99, 0x89, 0x7f, 0x63, 0x31, 0x13, 0xff, 0x82, 0x66, 0xcc, 0x67, 0x76, 0xfb, 0x88, 0x7e, 0x61, 0x83, 0x37, 0x87, + 0xbd, 0x9f, 0xf5, 0x83, 0xc6, 0x39, 0xb8, 0x34, 0x87, 0x5e, 0xd7, 0xee, 0x74, 0xcc, 0x43, 0xd7, 0xee, 0x75, 0x16, + 0xd6, 0x61, 0xdb, 0x3e, 0x3a, 0x9e, 0x58, 0xae, 0x7d, 0x7c, 0x6c, 0x3a, 0x56, 0xc7, 0x6e, 0x9b, 0xae, 0x7d, 0xd8, + 0xc1, 0x1f, 0x1d, 0xbb, 0x7d, 0x73, 0xfc, 0xcc, 0x3e, 0xea, 0x2e, 0x8e, 0xec, 0xc3, 0xf7, 0x87, 0x3d, 0xbb, 0xdd, + 0x59, 0x74, 0x8e, 0xec, 0xf6, 0xf1, 0xcd, 0x91, 0x7d, 0xb8, 0xb0, 0xda, 0x47, 0x5b, 0x6b, 0xba, 0x6d, 0x1b, 0x60, + 0x84, 0xd9, 0x90, 0x61, 0xf2, 0x0c, 0xf8, 0xb3, 0xc0, 0xba, 0x7f, 0x62, 0x33, 0x49, 0xb5, 0xea, 0x33, 0xbb, 0x77, + 0x3c, 0xa1, 0xe2, 0x90, 0x60, 0x89, 0x12, 0x50, 0xe5, 0xc6, 0xa2, 0x6e, 0xb1, 0x39, 0x4b, 0x34, 0x24, 0xfe, 0xf0, + 0xce, 0x6e, 0x2c, 0xe8, 0x98, 0xfa, 0xfd, 0x8f, 0xb6, 0x23, 0x97, 0x1c, 0x42, 0xf2, 0x7e, 0xc5, 0xff, 0xa1, 0x68, + 0x56, 0x23, 0xf3, 0xbc, 0x49, 0x28, 0xf9, 0x76, 0xb7, 0x50, 0xf2, 0xd5, 0x7a, 0x1f, 0xa1, 0xe4, 0xdb, 0x2f, 0x2e, + 0x94, 0x3c, 0x2f, 0xdb, 0xc4, 0xbc, 0x2d, 0x07, 0xdd, 0xf8, 0x79, 0x53, 0x66, 0x39, 0xf8, 0x5e, 0xeb, 0xf2, 0x62, + 0x7d, 0x05, 0xee, 0xdf, 0xde, 0x46, 0xc3, 0x57, 0xeb, 0x82, 0xc2, 0x67, 0x04, 0x38, 0xf6, 0x6d, 0x44, 0x38, 0xf6, + 0xd7, 0xf5, 0x10, 0xb4, 0xcc, 0x38, 0x99, 0xe3, 0x4f, 0xad, 0x85, 0x17, 0xcc, 0x24, 0x89, 0x04, 0x29, 0x03, 0x4c, + 0x06, 0xbb, 0x2b, 0xb8, 0x9e, 0xe1, 0x25, 0xb3, 0x5e, 0x86, 0x09, 0x68, 0x04, 0x83, 0x26, 0xc7, 0x2c, 0xce, 0x4a, + 0x95, 0x6d, 0xe1, 0x30, 0xef, 0x9a, 0x5b, 0x40, 0x35, 0xe6, 0xa3, 0x02, 0x70, 0x7d, 0xeb, 0x6e, 0xb5, 0x5d, 0x0d, + 0x34, 0xeb, 0x84, 0x82, 0x34, 0x50, 0xfb, 0x75, 0xf9, 0x45, 0x35, 0xdc, 0x92, 0xe2, 0x75, 0xf3, 0x48, 0x61, 0x24, + 0xe5, 0xfa, 0x6e, 0x51, 0x8d, 0x77, 0xd7, 0x34, 0x6b, 0xba, 0x2f, 0x54, 0xdf, 0xa2, 0x43, 0x2c, 0x1b, 0x2e, 0x83, + 0xaa, 0x14, 0x32, 0xb2, 0x16, 0x20, 0xf9, 0x03, 0x35, 0x57, 0x34, 0xce, 0x29, 0x55, 0x47, 0x43, 0x7a, 0xc7, 0x51, + 0xf2, 0x0a, 0x6d, 0xaa, 0xca, 0xc9, 0x4f, 0x36, 0xf8, 0xae, 0xf0, 0x7f, 0x05, 0x4a, 0x94, 0x53, 0x3c, 0xe3, 0x48, + 0x85, 0xf3, 0x46, 0x69, 0x97, 0xb8, 0x11, 0xd9, 0xc2, 0xdd, 0x54, 0x69, 0xd1, 0x46, 0xb3, 0x04, 0x97, 0x2d, 0x05, + 0x15, 0x84, 0xdd, 0x93, 0x11, 0x40, 0x46, 0x86, 0x1a, 0x68, 0xe7, 0xb0, 0xad, 0x31, 0x51, 0xee, 0x21, 0x6c, 0x62, + 0x93, 0x7f, 0xa8, 0x8e, 0x4b, 0x36, 0xb3, 0x20, 0xf2, 0xd2, 0x3e, 0x92, 0x69, 0x0a, 0xc9, 0xdb, 0x46, 0x8b, 0x85, + 0xc1, 0x16, 0x65, 0x3a, 0xb5, 0x61, 0xde, 0x08, 0x5a, 0x3e, 0x6c, 0xd3, 0xbf, 0x93, 0x86, 0x62, 0x9b, 0x82, 0x3a, + 0x8a, 0xdb, 0x3d, 0x36, 0xdd, 0x23, 0xd3, 0x3e, 0xee, 0x1a, 0x99, 0x38, 0x70, 0x6a, 0x93, 0x05, 0x80, 0x80, 0x01, + 0x84, 0x1c, 0xa6, 0x1f, 0xfa, 0xa9, 0xef, 0x05, 0x19, 0xd0, 0xc3, 0xc5, 0x47, 0xca, 0x3f, 0xd7, 0x49, 0x0a, 0x73, + 0x14, 0x44, 0x2f, 0x1a, 0x7f, 0x58, 0x63, 0x96, 0xde, 0x32, 0x16, 0x36, 0x28, 0xc6, 0x94, 0x6d, 0x49, 0xfe, 0x38, + 0xcd, 0xfa, 0x8c, 0xb4, 0xd6, 0xc6, 0x69, 0xc8, 0xf7, 0x87, 0x30, 0x7c, 0xc8, 0x46, 0xe6, 0x0f, 0x4d, 0x08, 0xf7, + 0x9f, 0xbb, 0x11, 0x6e, 0xca, 0xf6, 0x41, 0xb8, 0xff, 0xfc, 0xe2, 0x08, 0xf7, 0x07, 0x15, 0xe1, 0x16, 0xec, 0xfe, + 0x72, 0x09, 0xd3, 0x3b, 0xfc, 0x6e, 0x81, 0xb7, 0xfa, 0xa7, 0xfa, 0x01, 0x11, 0xf0, 0xba, 0x12, 0x45, 0xfc, 0x7d, + 0x21, 0x2c, 0x1a, 0x32, 0x40, 0xd1, 0x4b, 0x36, 0x85, 0x60, 0x82, 0x08, 0xdb, 0x8e, 0x0c, 0xc3, 0xc4, 0x6e, 0xb5, + 0xd7, 0x61, 0x1a, 0xd8, 0x6f, 0xf9, 0x3b, 0x12, 0x04, 0xba, 0xaf, 0xa2, 0x78, 0xe9, 0xa1, 0x87, 0x50, 0x1d, 0xc3, + 0xa9, 0xc2, 0x87, 0x03, 0xb6, 0xa4, 0x93, 0x28, 0x9c, 0x4a, 0xa9, 0x24, 0x1b, 0x5e, 0x12, 0xc5, 0xad, 0xdf, 0x33, + 0x2f, 0xd6, 0x4d, 0xca, 0x86, 0xc5, 0x7d, 0xd2, 0x71, 0x9e, 0xb4, 0x0f, 0x9f, 0x1c, 0x39, 0xf0, 0xbf, 0xcb, 0x3a, + 0x99, 0xc9, 0x0b, 0x2e, 0xa3, 0x10, 0x22, 0x3a, 0x89, 0x92, 0x4d, 0xc5, 0x6e, 0x19, 0xfb, 0x90, 0x97, 0x3a, 0xae, + 0x2f, 0x34, 0xf5, 0xee, 0xf3, 0x32, 0xb5, 0x25, 0x16, 0xd1, 0x5a, 0x19, 0x56, 0xcd, 0x68, 0xfc, 0x70, 0x0d, 0x7c, + 0x76, 0xa5, 0x84, 0x9a, 0xcd, 0xa7, 0x9b, 0xcf, 0x8b, 0x75, 0xb2, 0xab, 0x3c, 0x6c, 0x9c, 0x08, 0x5f, 0xb5, 0x13, + 0x82, 0x5c, 0x44, 0xe9, 0x60, 0xd0, 0x09, 0x0c, 0x9c, 0xa6, 0x41, 0xd0, 0x56, 0xb1, 0x40, 0x1e, 0x2d, 0x50, 0x1a, + 0xaf, 0xc3, 0x49, 0x0b, 0x7f, 0x7a, 0xe3, 0xa4, 0xe5, 0x1f, 0x80, 0xfb, 0x68, 0xec, 0xd8, 0xc0, 0x55, 0xf3, 0x4e, + 0x9d, 0x3c, 0xc6, 0x4e, 0x22, 0x56, 0xc5, 0x7b, 0x92, 0x9a, 0x31, 0x45, 0xe6, 0xc6, 0xa5, 0xb5, 0x86, 0xde, 0x13, + 0x59, 0xf1, 0x49, 0x6a, 0x42, 0x74, 0x6c, 0x58, 0xee, 0xc7, 0x8f, 0xa9, 0x14, 0xc4, 0xab, 0xa5, 0x69, 0x9d, 0x4d, + 0x72, 0xff, 0x93, 0x9a, 0x37, 0x8f, 0xc8, 0x05, 0x65, 0x7f, 0x62, 0x46, 0x4f, 0x9f, 0x9e, 0x0e, 0x5d, 0x83, 0x47, + 0x5b, 0x2e, 0x84, 0x06, 0x3c, 0xdf, 0x4f, 0xd1, 0xc8, 0xa8, 0x35, 0x81, 0x5d, 0xc1, 0x9b, 0xc9, 0x11, 0xe6, 0x08, + 0x1c, 0x7b, 0x41, 0xa8, 0x1e, 0x52, 0x28, 0xf0, 0x84, 0xc2, 0x8f, 0x28, 0x23, 0x5f, 0x5d, 0x1d, 0xdb, 0xb1, 0x1d, + 0x5d, 0x56, 0x9c, 0xf9, 0xf3, 0xe1, 0x26, 0x4a, 0x3d, 0x08, 0x7a, 0x16, 0x44, 0x73, 0xb0, 0xa3, 0x4b, 0xfd, 0x34, + 0x80, 0x08, 0x5a, 0x60, 0x50, 0xb7, 0xa4, 0x77, 0x79, 0xc6, 0xad, 0x1b, 0xbc, 0xf8, 0x03, 0x46, 0x51, 0x15, 0x26, + 0xb4, 0xe8, 0x12, 0xed, 0x7b, 0xb8, 0x0c, 0x5b, 0x7a, 0x0b, 0x78, 0x03, 0x2c, 0x4e, 0x2c, 0xd5, 0x5a, 0xa8, 0xaf, + 0x41, 0x1d, 0x43, 0xe7, 0x93, 0x98, 0xc5, 0xde, 0x12, 0x82, 0x4d, 0x6c, 0x32, 0x93, 0x63, 0x5a, 0x9d, 0xa3, 0x5a, + 0xcd, 0x7d, 0x76, 0x64, 0x6a, 0x6d, 0xd7, 0xd4, 0x1c, 0x40, 0xb7, 0x7a, 0x66, 0x6e, 0xb2, 0xab, 0xc1, 0x2e, 0x85, + 0x07, 0xc2, 0x2f, 0x0f, 0x69, 0x1e, 0xa4, 0xea, 0xc0, 0x45, 0x49, 0x29, 0x79, 0xb8, 0x6d, 0x29, 0x61, 0x20, 0x7c, + 0x12, 0x7a, 0x5e, 0xb0, 0xbb, 0xd4, 0xc0, 0x08, 0x53, 0xbc, 0x88, 0x6f, 0x6c, 0xd0, 0xd0, 0xd7, 0x0f, 0x35, 0xff, + 0xe3, 0xc7, 0x96, 0x0f, 0xc6, 0x4c, 0x43, 0x05, 0x3e, 0xf0, 0x6d, 0x14, 0x00, 0xe6, 0xe7, 0x62, 0x7a, 0x04, 0x16, + 0x58, 0x1a, 0xc2, 0xbf, 0x79, 0xb2, 0xf8, 0xc1, 0xd5, 0x24, 0xec, 0xc0, 0x0b, 0xe7, 0x80, 0xd2, 0xbc, 0x70, 0x5e, + 0x51, 0xc7, 0x22, 0x5b, 0xe5, 0x52, 0x6a, 0xde, 0x54, 0xae, 0x2a, 0x95, 0x7c, 0x77, 0x7f, 0x41, 0x11, 0xf4, 0x5a, + 0x3a, 0xdc, 0x72, 0x68, 0x58, 0x9b, 0x4b, 0x72, 0x9f, 0x0e, 0xbf, 0x3e, 0x59, 0xb2, 0xd4, 0x23, 0x31, 0x10, 0x3c, + 0x7e, 0x81, 0x1c, 0xd0, 0x26, 0x22, 0xfa, 0x35, 0x5e, 0x0d, 0xc3, 0x29, 0xbb, 0xf1, 0x27, 0xfc, 0x5d, 0x6a, 0x6a, + 0xfc, 0x9e, 0xb2, 0x50, 0xe3, 0x73, 0xe8, 0x9a, 0x64, 0x70, 0x30, 0xf1, 0xd0, 0x0f, 0xee, 0x30, 0x8c, 0xf4, 0xd3, + 0xaf, 0xa5, 0x6d, 0x66, 0xd3, 0x22, 0x40, 0x18, 0xdb, 0xcb, 0x98, 0x05, 0xff, 0x1a, 0x7e, 0x0d, 0x17, 0xf7, 0xd7, + 0x57, 0xba, 0x31, 0x48, 0xed, 0x45, 0xcc, 0x66, 0xc3, 0xaf, 0x6b, 0xc2, 0xb9, 0xe2, 0xf3, 0x9e, 0xc6, 0xa2, 0x77, + 0xda, 0xb9, 0xf7, 0xb2, 0xce, 0x5e, 0x8f, 0xfa, 0x53, 0xfe, 0x5a, 0x87, 0x17, 0xe0, 0xa6, 0xf0, 0xc6, 0x76, 0x07, + 0xf8, 0x7e, 0x1e, 0x07, 0xde, 0xe4, 0xc3, 0x80, 0x72, 0x0a, 0x1f, 0x16, 0xdc, 0xd6, 0x13, 0x6f, 0xd5, 0xc7, 0xeb, + 0x55, 0x4d, 0x04, 0xd3, 0x6c, 0x4a, 0x95, 0x94, 0x5d, 0xed, 0x5e, 0xc6, 0xad, 0xbc, 0xc1, 0x9e, 0xb1, 0xab, 0xdb, + 0x85, 0x9f, 0x32, 0xd1, 0x15, 0x7e, 0x64, 0x99, 0x78, 0xa8, 0xd3, 0x13, 0x15, 0x1f, 0xd6, 0x76, 0x47, 0x73, 0x7b, + 0x7f, 0xed, 0xde, 0xb8, 0xce, 0xa2, 0xed, 0xda, 0xbd, 0xf7, 0x6e, 0x6f, 0xd1, 0xb1, 0x8f, 0x03, 0xab, 0x63, 0x1f, + 0xc3, 0x9f, 0xf7, 0xc7, 0x76, 0x6f, 0x61, 0xb5, 0xed, 0xc3, 0xf7, 0x6e, 0x3b, 0xb0, 0x7a, 0xf6, 0x31, 0xfc, 0x39, + 0xa7, 0x5a, 0xf0, 0x00, 0xa2, 0xf7, 0xce, 0xd7, 0x05, 0x2c, 0xa0, 0xfc, 0x96, 0x32, 0x59, 0xb3, 0x70, 0xbd, 0xd5, + 0xc8, 0x75, 0x01, 0x65, 0xe8, 0xa6, 0xf0, 0x52, 0x1b, 0x0e, 0x5a, 0xe1, 0x90, 0x47, 0x46, 0x11, 0xea, 0x6d, 0xc2, + 0x06, 0x5d, 0xc4, 0x08, 0xa9, 0x3d, 0x46, 0xbc, 0x4e, 0x7d, 0x44, 0x08, 0x11, 0x72, 0x8f, 0x04, 0xc1, 0x3f, 0xad, + 0xd0, 0xcb, 0x9a, 0x88, 0x61, 0xa1, 0x60, 0xa5, 0x3c, 0xec, 0x6b, 0xb6, 0x7b, 0xe0, 0x68, 0x85, 0xcf, 0x64, 0xd8, + 0xb1, 0x2f, 0xda, 0x36, 0x17, 0x0e, 0xcb, 0xd6, 0x7f, 0x6f, 0x3b, 0x18, 0x6d, 0x9b, 0xda, 0x11, 0xee, 0xa6, 0xa7, + 0x7e, 0x2c, 0x87, 0xa7, 0xa0, 0x68, 0xb7, 0x3e, 0x94, 0x86, 0x01, 0xf1, 0x99, 0x5e, 0x03, 0x95, 0x7c, 0xe3, 0x05, + 0x8a, 0x22, 0x9b, 0x52, 0xf3, 0x81, 0xc4, 0xfc, 0x8f, 0x1f, 0xe7, 0x83, 0xb3, 0x4a, 0xe3, 0x3e, 0x71, 0xbb, 0x70, + 0xed, 0x76, 0x59, 0x67, 0xab, 0x4e, 0xe5, 0x6e, 0x7f, 0xe5, 0xb9, 0x3f, 0x63, 0xa1, 0x37, 0x25, 0x34, 0x36, 0x1a, + 0x15, 0x3b, 0x2b, 0xfa, 0x1a, 0xe0, 0xe9, 0xbd, 0xf4, 0xd4, 0xd1, 0x8d, 0x41, 0x28, 0xd4, 0x0f, 0xc2, 0x2d, 0x3e, + 0xda, 0xf9, 0x5b, 0x4c, 0x07, 0xd0, 0x6c, 0x99, 0xc7, 0x0e, 0x03, 0xf1, 0xff, 0xf4, 0x24, 0xd0, 0x58, 0x13, 0xf4, + 0x25, 0x4a, 0xa7, 0xb5, 0x60, 0xbc, 0x27, 0xef, 0x55, 0xba, 0x50, 0x59, 0x72, 0xa6, 0x43, 0x12, 0x04, 0xee, 0xc3, + 0x58, 0x9d, 0x52, 0x59, 0x54, 0xde, 0x16, 0x79, 0x82, 0xe9, 0x43, 0x90, 0x82, 0x96, 0x30, 0x1c, 0x35, 0x1e, 0x3f, + 0x6e, 0xbc, 0x84, 0x48, 0x39, 0x47, 0x0d, 0x59, 0xac, 0xab, 0xf8, 0x4d, 0x57, 0x51, 0x8c, 0x6c, 0x17, 0xb1, 0x86, + 0xd0, 0x71, 0xa5, 0xbd, 0x87, 0x3f, 0xc7, 0xcc, 0x4b, 0x6d, 0x2e, 0x2c, 0x6d, 0x29, 0x97, 0xbb, 0xe9, 0xb2, 0x0e, + 0x68, 0xb7, 0x72, 0x67, 0x8c, 0xdc, 0xd9, 0xe9, 0xa3, 0xcd, 0xfb, 0x35, 0xf7, 0xea, 0x00, 0x6d, 0x7c, 0x74, 0x72, + 0xff, 0x59, 0x6f, 0x52, 0x8f, 0x9c, 0x2c, 0xa9, 0x57, 0x6e, 0x94, 0x7a, 0x22, 0x40, 0x16, 0xd0, 0xe5, 0x83, 0x5a, + 0xf5, 0x0b, 0xc5, 0xf3, 0xc3, 0xe9, 0x9b, 0x8b, 0x6f, 0x35, 0xbe, 0xff, 0x49, 0x5b, 0x00, 0x1f, 0x32, 0x14, 0x96, + 0x65, 0x48, 0x61, 0x59, 0x34, 0x1e, 0x1f, 0x09, 0x82, 0x9b, 0x64, 0x07, 0x04, 0x41, 0x64, 0x40, 0x93, 0x0e, 0xc5, + 0x72, 0x1d, 0xa4, 0xfe, 0xca, 0x8b, 0xd3, 0x03, 0xa8, 0x6a, 0x01, 0x92, 0xd3, 0x9b, 0xfc, 0x41, 0x90, 0x1a, 0x86, + 0xf0, 0x01, 0x9a, 0x86, 0x42, 0x0f, 0x63, 0xe6, 0x07, 0x52, 0x0d, 0x43, 0x74, 0xe0, 0x4d, 0x26, 0x6c, 0x95, 0x0e, + 0x75, 0x6f, 0x05, 0xe1, 0x79, 0xd0, 0xe1, 0xfe, 0x41, 0x34, 0x49, 0x59, 0x6a, 0x25, 0x69, 0xcc, 0xbc, 0xa5, 0x2e, + 0x7d, 0x4d, 0x57, 0xdb, 0x4b, 0xd6, 0xe3, 0xa5, 0x9f, 0x4a, 0x67, 0xad, 0x34, 0x41, 0x50, 0x88, 0x80, 0x21, 0x82, + 0x73, 0x18, 0x02, 0xe1, 0x79, 0x34, 0x2f, 0xed, 0xa8, 0x9c, 0x72, 0x39, 0x43, 0x57, 0xe0, 0x3c, 0x24, 0xcb, 0x14, + 0xed, 0x1b, 0xaf, 0xb9, 0x0f, 0x0b, 0xe9, 0x53, 0x56, 0x3f, 0x3d, 0xe1, 0xcf, 0x5b, 0x0d, 0xdd, 0xae, 0xe8, 0x5d, + 0x07, 0x9c, 0x9d, 0x37, 0x79, 0xb7, 0x38, 0xe0, 0x85, 0xe1, 0x6a, 0xa2, 0x96, 0x31, 0x10, 0x05, 0x8d, 0xe5, 0x02, + 0x08, 0xa1, 0x82, 0xc2, 0xcc, 0xc2, 0x3d, 0x95, 0xe6, 0x94, 0x38, 0x2a, 0xa4, 0x95, 0x3e, 0x7e, 0x7c, 0x3e, 0xfa, + 0xed, 0xdf, 0x10, 0x2d, 0x63, 0xe1, 0x0a, 0x9f, 0x12, 0x97, 0x6a, 0x29, 0x4e, 0x7d, 0x9a, 0x23, 0x54, 0x96, 0x62, + 0x53, 0xe1, 0x98, 0x47, 0x6c, 0xad, 0x6c, 0x74, 0x25, 0xbc, 0xfd, 0x41, 0x44, 0x1c, 0x43, 0x78, 0xbe, 0x18, 0xc1, + 0xf2, 0x8e, 0x84, 0xc3, 0x15, 0xed, 0x97, 0xbb, 0xef, 0x8e, 0xb5, 0xdc, 0x05, 0x4f, 0x9d, 0x46, 0x0f, 0xed, 0xa1, + 0xd3, 0x13, 0x4f, 0x43, 0xa2, 0x05, 0xc9, 0x8f, 0xa4, 0x7f, 0x00, 0xd3, 0x5c, 0x44, 0x4b, 0x66, 0xfb, 0xd1, 0xc1, + 0x2d, 0x1b, 0x5b, 0xde, 0xca, 0x27, 0xbd, 0x1c, 0xe4, 0xbb, 0x69, 0x44, 0xf9, 0x49, 0x75, 0x17, 0xa2, 0xaf, 0xb3, + 0x1c, 0x94, 0x51, 0xd1, 0xbd, 0x63, 0xb7, 0x9d, 0xcb, 0x01, 0xc1, 0x7f, 0x81, 0x02, 0xc7, 0xe8, 0xf4, 0xe4, 0xc0, + 0x3b, 0x2d, 0xfa, 0x97, 0xb5, 0x45, 0x84, 0x93, 0xe2, 0x25, 0x70, 0x46, 0x6e, 0x62, 0x85, 0x47, 0xd8, 0xfc, 0xc3, + 0x8a, 0x66, 0x33, 0xd5, 0x27, 0xac, 0x5d, 0x1c, 0x9e, 0x04, 0x5a, 0xbe, 0xa5, 0xa3, 0x15, 0xf5, 0x54, 0xed, 0x42, + 0xfe, 0x84, 0xa8, 0xf0, 0xdc, 0x7d, 0x30, 0x1c, 0xf7, 0x8a, 0x6f, 0x59, 0x09, 0xb1, 0x87, 0x54, 0x88, 0xe3, 0x91, + 0x72, 0x24, 0x83, 0x06, 0xca, 0xe5, 0xc1, 0x70, 0x48, 0x68, 0xae, 0x8c, 0xed, 0x00, 0x88, 0x35, 0xd1, 0x5e, 0x60, + 0xb2, 0x29, 0x54, 0xb4, 0xc8, 0x5c, 0x16, 0x2b, 0x95, 0xa7, 0x53, 0x1d, 0xe3, 0x81, 0x27, 0xb6, 0x5f, 0x61, 0x83, + 0xc2, 0xc6, 0xe3, 0xeb, 0x0e, 0xf8, 0x5d, 0xb4, 0x53, 0x42, 0xf3, 0xda, 0x37, 0x84, 0xd1, 0xad, 0xc0, 0xbb, 0x8f, + 0x14, 0x35, 0x26, 0xee, 0xd1, 0xe4, 0x1c, 0x53, 0x2f, 0x84, 0x25, 0x71, 0xe5, 0xa0, 0xc9, 0x88, 0x19, 0xd5, 0xc3, + 0xa6, 0x86, 0xb8, 0xd8, 0x75, 0xd6, 0xd4, 0xb2, 0xc5, 0xc9, 0x20, 0xf2, 0xcc, 0xf2, 0x73, 0x58, 0xc8, 0x44, 0xb4, + 0x90, 0x9d, 0x1c, 0xc0, 0xfc, 0xc0, 0x0b, 0x4b, 0x81, 0x70, 0xf2, 0x0d, 0x70, 0xf5, 0xe2, 0x25, 0xa4, 0x8a, 0xf5, + 0x7a, 0x2a, 0x68, 0x3e, 0x7c, 0x58, 0x4a, 0xe7, 0xd5, 0x85, 0x22, 0x55, 0x5a, 0xc6, 0xa9, 0x27, 0x02, 0x77, 0x47, + 0x98, 0xf9, 0x75, 0x8d, 0xe1, 0x65, 0xb2, 0x41, 0xca, 0x84, 0x93, 0x83, 0xf3, 0xb4, 0xc1, 0x0f, 0x42, 0x53, 0x11, + 0xa2, 0x67, 0xb7, 0x14, 0xc8, 0xf7, 0xf1, 0xb6, 0x52, 0x39, 0xe5, 0x24, 0x8b, 0xad, 0xbc, 0x96, 0xfe, 0x10, 0x77, + 0x7c, 0xa5, 0x34, 0xa6, 0x42, 0xb9, 0xf3, 0x74, 0x08, 0x45, 0x05, 0x2f, 0xde, 0x5b, 0xad, 0xa8, 0xb0, 0x31, 0x38, + 0x39, 0xa0, 0x67, 0xe9, 0x29, 0xed, 0xb0, 0xd3, 0x13, 0x50, 0xe5, 0xa6, 0x45, 0xf7, 0x56, 0x2b, 0xbe, 0xa4, 0xf4, + 0x8b, 0x72, 0x0e, 0x16, 0xe9, 0x32, 0x38, 0xfd, 0x7f, 0x8a, 0xa5, 0x7c, 0x2e, 0xc4, 0x61, 0x03, 0x00}; } // namespace web_server } // namespace esphome From 1f3754684adccccc54a4795d8a685d13ba59e352 Mon Sep 17 00:00:00 2001 From: dentra Date: Wed, 24 Jul 2024 06:50:59 +0300 Subject: [PATCH 2118/2607] [http_request] Allow configure buffer size on ESP-IDF (#7125) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/http_request/__init__.py | 11 +++++++++++ esphome/components/http_request/http_request_idf.cpp | 9 +++++++++ esphome/components/http_request/http_request_idf.h | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 161486fbb2..3ca97b9611 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -40,6 +40,8 @@ CONF_VERIFY_SSL = "verify_ssl" CONF_FOLLOW_REDIRECTS = "follow_redirects" CONF_REDIRECT_LIMIT = "redirect_limit" CONF_WATCHDOG_TIMEOUT = "watchdog_timeout" +CONF_BUFFER_SIZE_RX = "buffer_size_rx" +CONF_BUFFER_SIZE_TX = "buffer_size_tx" CONF_MAX_RESPONSE_BUFFER_SIZE = "max_response_buffer_size" CONF_ON_RESPONSE = "on_response" @@ -110,6 +112,12 @@ CONFIG_SCHEMA = cv.All( cv.positive_not_null_time_period, cv.positive_time_period_milliseconds, ), + cv.SplitDefault(CONF_BUFFER_SIZE_RX, esp32_idf=512): cv.All( + cv.uint16_t, cv.only_with_esp_idf + ), + cv.SplitDefault(CONF_BUFFER_SIZE_TX, esp32_idf=512): cv.All( + cv.uint16_t, cv.only_with_esp_idf + ), } ).extend(cv.COMPONENT_SCHEMA), cv.require_framework_version( @@ -137,6 +145,9 @@ async def to_code(config): if CORE.is_esp32: if CORE.using_esp_idf: + cg.add(var.set_buffer_size_rx(config[CONF_BUFFER_SIZE_RX])) + cg.add(var.set_buffer_size_tx(config[CONF_BUFFER_SIZE_TX])) + esp32.add_idf_sdkconfig_option( "CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", config.get(CONF_VERIFY_SSL), diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 1f03b5f3bf..4fe5585723 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -18,6 +18,12 @@ namespace http_request { static const char *const TAG = "http_request.idf"; +void HttpRequestIDF::dump_config() { + HttpRequestComponent::dump_config(); + ESP_LOGCONFIG(TAG, " Buffer Size RX: %u", this->buffer_size_rx_); + ESP_LOGCONFIG(TAG, " Buffer Size TX: %u", this->buffer_size_tx_); +} + std::shared_ptr HttpRequestIDF::start(std::string url, std::string method, std::string body, std::list
headers) { if (!network::is_connected()) { @@ -63,6 +69,9 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin config.user_agent = this->useragent_; } + config.buffer_size = this->buffer_size_rx_; + config.buffer_size_tx = this->buffer_size_tx_; + const uint32_t start = millis(); watchdog::WatchdogManager wdm(this->get_watchdog_timeout()); diff --git a/esphome/components/http_request/http_request_idf.h b/esphome/components/http_request/http_request_idf.h index 79f850a636..431794924b 100644 --- a/esphome/components/http_request/http_request_idf.h +++ b/esphome/components/http_request/http_request_idf.h @@ -24,8 +24,18 @@ class HttpContainerIDF : public HttpContainer { class HttpRequestIDF : public HttpRequestComponent { public: + void dump_config() override; + std::shared_ptr start(std::string url, std::string method, std::string body, std::list
headers) override; + + void set_buffer_size_rx(uint16_t buffer_size_rx) { this->buffer_size_rx_ = buffer_size_rx; } + void set_buffer_size_tx(uint16_t buffer_size_tx) { this->buffer_size_tx_ = buffer_size_tx; } + + protected: + // if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE + uint16_t buffer_size_rx_{}; + uint16_t buffer_size_tx_{}; }; } // namespace http_request From 75635956cd707237f44aab63c652555d635e3428 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 25 Jul 2024 05:30:39 +1000 Subject: [PATCH 2119/2607] Give more info on import errors. (#7128) --- esphome/loader.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/esphome/loader.py b/esphome/loader.py index e0457eb425..9399c4cb31 100644 --- a/esphome/loader.py +++ b/esphome/loader.py @@ -1,17 +1,17 @@ -import logging -from typing import Callable, Optional, Any, ContextManager -from types import ModuleType -import importlib -import importlib.util -import importlib.resources -import importlib.abc -import sys -from pathlib import Path from dataclasses import dataclass +import importlib +import importlib.abc +import importlib.resources +import importlib.util +import logging +from pathlib import Path +import sys +from types import ModuleType +from typing import Any, Callable, ContextManager, Optional from esphome.const import SOURCE_FILE_EXTENSIONS -import esphome.core.config from esphome.core import CORE +import esphome.core.config from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) @@ -175,7 +175,11 @@ def _lookup_module(domain): try: module = importlib.import_module(f"esphome.components.{domain}") except ImportError as e: - if "No module named" not in str(e): + if "No module named" in str(e): + _LOGGER.error( + "Unable to import component %s: %s", domain, str(e), exc_info=False + ) + else: _LOGGER.error("Unable to import component %s:", domain, exc_info=True) return None except Exception: # pylint: disable=broad-except From 6e863305aae0589103fa9dfdf2d36d2ff50858c9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:51:32 +1200 Subject: [PATCH 2120/2607] [http_request] Change default timeout to 4.5s (#7123) --- esphome/components/http_request/__init__.py | 2 +- esphome/components/http_request/http_request.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index ade7024bed..ef387553fe 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -99,7 +99,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_FOLLOW_REDIRECTS, True): cv.boolean, cv.Optional(CONF_REDIRECT_LIMIT, 3): cv.int_, cv.Optional( - CONF_TIMEOUT, default="5s" + CONF_TIMEOUT, default="4.5s" ): cv.positive_time_period_milliseconds, cv.SplitDefault(CONF_ESP8266_DISABLE_SSL_SUPPORT, esp8266=False): cv.All( cv.only_on_esp8266, cv.boolean diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 82b7392648..c01baf8644 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -80,7 +80,7 @@ class HttpRequestComponent : public Component { const char *useragent_{nullptr}; bool follow_redirects_; uint16_t redirect_limit_; - uint16_t timeout_{5000}; + uint16_t timeout_{4500}; uint32_t watchdog_timeout_{0}; }; From 7c24f1ba6dac36d839c5fe34f16d6b52f12264da Mon Sep 17 00:00:00 2001 From: dentra Date: Wed, 24 Jul 2024 03:12:59 +0300 Subject: [PATCH 2121/2607] [http_request] Fix ESP-IDF follow redirect (#7101) --- esphome/components/http_request/__init__.py | 14 ++-- .../http_request/http_request_idf.cpp | 66 +++++++++++++++---- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index ef387553fe..161486fbb2 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -1,17 +1,17 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg +from esphome.components import esp32 +import esphome.config_validation as cv from esphome.const import ( - __version__, + CONF_ESP8266_DISABLE_SSL_SUPPORT, CONF_ID, - CONF_TIMEOUT, CONF_METHOD, + CONF_TIMEOUT, CONF_TRIGGER_ID, CONF_URL, - CONF_ESP8266_DISABLE_SSL_SUPPORT, + __version__, ) -from esphome.core import Lambda, CORE -from esphome.components import esp32 +from esphome.core import CORE, Lambda DEPENDENCIES = ["network"] AUTO_LOAD = ["json"] diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 68e0639b99..1f03b5f3bf 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -77,7 +77,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin esp_http_client_set_header(client, header.name, header.value); } - int body_len = body.length(); + const int body_len = body.length(); esp_err_t err = esp_http_client_open(client, body_len); if (err != ESP_OK) { @@ -109,18 +109,62 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } - container->content_length = esp_http_client_fetch_headers(client); - const auto status_code = esp_http_client_get_status_code(client); - container->status_code = status_code; + auto is_ok = [](int code) { return code >= HttpStatus_Ok && code < HttpStatus_MultipleChoices; }; - if (status_code < 200 || status_code >= 300) { - ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), status_code); - this->status_momentary_error("failed", 1000); - esp_http_client_cleanup(client); - return nullptr; + container->content_length = esp_http_client_fetch_headers(client); + container->status_code = esp_http_client_get_status_code(client); + if (is_ok(container->status_code)) { + container->duration_ms = millis() - start; + return container; } - container->duration_ms = millis() - start; - return container; + + if (this->follow_redirects_) { + auto is_redirect = [](int code) { + return code == HttpStatus_MovedPermanently || code == HttpStatus_Found || code == HttpStatus_SeeOther || + code == HttpStatus_TemporaryRedirect || code == HttpStatus_PermanentRedirect; + }; + auto num_redirects = this->redirect_limit_; + while (is_redirect(container->status_code) && num_redirects > 0) { + err = esp_http_client_set_redirection(client); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_http_client_set_redirection failed: %s", esp_err_to_name(err)); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; + } +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char url[256]{}; + if (esp_http_client_get_url(client, url, sizeof(url) - 1) == ESP_OK) { + ESP_LOGV(TAG, "redirecting to url: %s", url); + } +#endif + err = esp_http_client_open(client, 0); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_http_client_open failed: %s", esp_err_to_name(err)); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; + } + + container->content_length = esp_http_client_fetch_headers(client); + container->status_code = esp_http_client_get_status_code(client); + if (is_ok(container->status_code)) { + container->duration_ms = millis() - start; + return container; + } + + num_redirects--; + } + + if (num_redirects == 0) { + ESP_LOGW(TAG, "Reach redirect limit count=%d", this->redirect_limit_); + } + } + + ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); + this->status_momentary_error("failed", 1000); + esp_http_client_cleanup(client); + return nullptr; } int HttpContainerIDF::read(uint8_t *buf, size_t max_len) { From ad0118dd4a47f1566ee6146d69004957d5555d12 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:13:05 +1200 Subject: [PATCH 2122/2607] Bump version to 2024.7.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index ff5f7b699d..9abfafc4a4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.1" +__version__ = "2024.7.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 23ffc3ddfb1504a0f3f5ad7f3cc2f9ea1d3cddf6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:12:04 +1000 Subject: [PATCH 2123/2607] [lvgl] base implementation (#7116) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/lvgl/__init__.py | 212 ++++++++++ esphome/components/lvgl/defines.py | 487 ++++++++++++++++++++++ esphome/components/lvgl/font.cpp | 76 ++++ esphome/components/lvgl/helpers.py | 70 ++++ esphome/components/lvgl/label.py | 34 ++ esphome/components/lvgl/lv_validation.py | 170 ++++++++ esphome/components/lvgl/lvcode.py | 237 +++++++++++ esphome/components/lvgl/lvgl_esphome.cpp | 129 ++++++ esphome/components/lvgl/lvgl_esphome.h | 119 ++++++ esphome/components/lvgl/lvgl_hal.h | 21 + esphome/components/lvgl/obj.py | 22 + esphome/components/lvgl/schemas.py | 260 ++++++++++++ esphome/components/lvgl/types.py | 64 +++ esphome/components/lvgl/widget.py | 347 +++++++++++++++ esphome/core/defines.h | 3 + platformio.ini | 1 + tests/components/lvgl/common.yaml | 0 tests/components/lvgl/lvgl-package.yaml | 24 ++ tests/components/lvgl/test.esp32-ard.yaml | 30 ++ tests/components/lvgl/test.esp32-idf.yaml | 52 +++ 21 files changed, 2359 insertions(+) create mode 100644 esphome/components/lvgl/__init__.py create mode 100644 esphome/components/lvgl/defines.py create mode 100644 esphome/components/lvgl/font.cpp create mode 100644 esphome/components/lvgl/helpers.py create mode 100644 esphome/components/lvgl/label.py create mode 100644 esphome/components/lvgl/lv_validation.py create mode 100644 esphome/components/lvgl/lvcode.py create mode 100644 esphome/components/lvgl/lvgl_esphome.cpp create mode 100644 esphome/components/lvgl/lvgl_esphome.h create mode 100644 esphome/components/lvgl/lvgl_hal.h create mode 100644 esphome/components/lvgl/obj.py create mode 100644 esphome/components/lvgl/schemas.py create mode 100644 esphome/components/lvgl/types.py create mode 100644 esphome/components/lvgl/widget.py create mode 100644 tests/components/lvgl/common.yaml create mode 100644 tests/components/lvgl/lvgl-package.yaml create mode 100644 tests/components/lvgl/test.esp32-ard.yaml create mode 100644 tests/components/lvgl/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c5e144bdfa..2fc030453f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -217,6 +217,7 @@ esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core esphome/components/ltr390/* @latonita @sjtrny esphome/components/ltr_als_ps/* @latonita +esphome/components/lvgl/* @clydebarrow esphome/components/m5stack_8angle/* @rnauber esphome/components/matrix_keypad/* @ssieb esphome/components/max31865/* @DAVe3283 diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py new file mode 100644 index 0000000000..2f3bd69546 --- /dev/null +++ b/esphome/components/lvgl/__init__.py @@ -0,0 +1,212 @@ +import logging + +import esphome.codegen as cg +from esphome.components.display import Display +import esphome.config_validation as cv +from esphome.const import ( + CONF_AUTO_CLEAR_ENABLED, + CONF_BUFFER_SIZE, + CONF_ID, + CONF_LAMBDA, + CONF_PAGES, +) +from esphome.core import CORE, ID, Lambda +from esphome.cpp_generator import MockObj +from esphome.final_validate import full_config +from esphome.helpers import write_file_if_changed + +from . import defines as df, helpers, lv_validation as lvalid +from .label import label_spec +from .lvcode import ConstantLiteral, LvContext + +# from .menu import menu_spec +from .obj import obj_spec +from .schemas import WIDGET_TYPES, any_widget_schema, obj_schema +from .types import FontEngine, LvglComponent, lv_disp_t_ptr, lv_font_t, lvgl_ns +from .widget import LvScrActType, Widget, add_widgets, set_obj_properties + +DOMAIN = "lvgl" +DEPENDENCIES = ("display",) +AUTO_LOAD = ("key_provider",) +CODEOWNERS = ("@clydebarrow",) +LOGGER = logging.getLogger(__name__) + +for widg in ( + label_spec, + obj_spec, +): + WIDGET_TYPES[widg.name] = widg + +lv_scr_act_spec = LvScrActType() +lv_scr_act = Widget.create( + None, ConstantLiteral("lv_scr_act()"), lv_scr_act_spec, {}, parent=None +) + +WIDGET_SCHEMA = any_widget_schema() + + +async def add_init_lambda(lv_component, init): + if init: + lamb = await cg.process_lambda(Lambda(init), [(lv_disp_t_ptr, "lv_disp")]) + cg.add(lv_component.add_init_lambda(lamb)) + + +lv_defines = {} # Dict of #defines to provide as build flags + + +def add_define(macro, value="1"): + if macro in lv_defines and lv_defines[macro] != value: + LOGGER.error( + "Redefinition of %s - was %s now %s", macro, lv_defines[macro], value + ) + lv_defines[macro] = value + + +def as_macro(macro, value): + if value is None: + return f"#define {macro}" + return f"#define {macro} {value}" + + +LV_CONF_FILENAME = "lv_conf.h" +LV_CONF_H_FORMAT = """\ +#pragma once +{} +""" + + +def generate_lv_conf_h(): + definitions = [as_macro(m, v) for m, v in lv_defines.items()] + definitions.sort() + return LV_CONF_H_FORMAT.format("\n".join(definitions)) + + +def final_validation(config): + global_config = full_config.get() + for display_id in config[df.CONF_DISPLAYS]: + path = global_config.get_path_for_id(display_id)[:-1] + display = global_config.get_config_for_path(path) + if CONF_LAMBDA in display: + raise cv.Invalid("Using lambda: in display config not compatible with LVGL") + if display[CONF_AUTO_CLEAR_ENABLED]: + raise cv.Invalid( + "Using auto_clear_enabled: true in display config not compatible with LVGL" + ) + buffer_frac = config[CONF_BUFFER_SIZE] + if not CORE.is_host and buffer_frac > 0.5 and "psram" not in global_config: + LOGGER.warning("buffer_size: may need to be reduced without PSRAM") + + +async def to_code(config): + cg.add_library("lvgl/lvgl", "8.4.0") + CORE.add_define("USE_LVGL") + # suppress default enabling of extra widgets + add_define("_LV_KCONFIG_PRESENT") + # Always enable - lots of things use it. + add_define("LV_DRAW_COMPLEX", "1") + add_define("LV_TICK_CUSTOM", "1") + add_define("LV_TICK_CUSTOM_INCLUDE", '"esphome/components/lvgl/lvgl_hal.h"') + add_define("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(lv_millis())") + add_define("LV_MEM_CUSTOM", "1") + add_define("LV_MEM_CUSTOM_ALLOC", "lv_custom_mem_alloc") + add_define("LV_MEM_CUSTOM_FREE", "lv_custom_mem_free") + add_define("LV_MEM_CUSTOM_REALLOC", "lv_custom_mem_realloc") + add_define("LV_MEM_CUSTOM_INCLUDE", '"esphome/components/lvgl/lvgl_hal.h"') + + add_define("LV_LOG_LEVEL", f"LV_LOG_LEVEL_{config[df.CONF_LOG_LEVEL]}") + add_define("LV_COLOR_DEPTH", config[df.CONF_COLOR_DEPTH]) + for font in helpers.lv_fonts_used: + add_define(f"LV_FONT_{font.upper()}") + + if config[df.CONF_COLOR_DEPTH] == 16: + add_define( + "LV_COLOR_16_SWAP", + "1" if config[df.CONF_BYTE_ORDER] == "big_endian" else "0", + ) + add_define( + "LV_COLOR_CHROMA_KEY", + await lvalid.lv_color.process(config[df.CONF_TRANSPARENCY_KEY]), + ) + CORE.add_build_flag("-Isrc") + + cg.add_global(lvgl_ns.using) + lv_component = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(lv_component, config) + Widget.create(config[CONF_ID], lv_component, WIDGET_TYPES[df.CONF_OBJ], config) + for display in config[df.CONF_DISPLAYS]: + cg.add(lv_component.add_display(await cg.get_variable(display))) + + frac = config[CONF_BUFFER_SIZE] + if frac >= 0.75: + frac = 1 + elif frac >= 0.375: + frac = 2 + elif frac > 0.19: + frac = 4 + else: + frac = 8 + cg.add(lv_component.set_buffer_frac(int(frac))) + cg.add(lv_component.set_full_refresh(config[df.CONF_FULL_REFRESH])) + + for font in helpers.esphome_fonts_used: + await cg.get_variable(font) + cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font)) + default_font = config[df.CONF_DEFAULT_FONT] + if default_font not in helpers.lv_fonts_used: + add_define( + "LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})" + ) + globfont_id = ID( + df.DEFAULT_ESPHOME_FONT, + True, + type=lv_font_t.operator("ptr").operator("const"), + ) + cg.new_variable(globfont_id, MockObj(default_font)) + add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT) + else: + add_define("LV_FONT_DEFAULT", default_font) + + with LvContext(): + await set_obj_properties(lv_scr_act, config) + await add_widgets(lv_scr_act, config) + Widget.set_completed() + await add_init_lambda(lv_component, LvContext.get_code()) + for comp in helpers.lvgl_components_required: + CORE.add_define(f"USE_LVGL_{comp.upper()}") + for use in helpers.lv_uses: + add_define(f"LV_USE_{use.upper()}") + lv_conf_h_file = CORE.relative_src_path(LV_CONF_FILENAME) + write_file_if_changed(lv_conf_h_file, generate_lv_conf_h()) + CORE.add_build_flag("-DLV_CONF_H=1") + CORE.add_build_flag(f'-DLV_CONF_PATH="{LV_CONF_FILENAME}"') + + +def display_schema(config): + value = cv.ensure_list(cv.use_id(Display))(config) + return value or [cv.use_id(Display)(config)] + + +FINAL_VALIDATE_SCHEMA = final_validation + +CONFIG_SCHEMA = ( + cv.polling_component_schema("1s") + .extend(obj_schema("obj")) + .extend( + { + cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent), + cv.GenerateID(df.CONF_DISPLAYS): display_schema, + cv.Optional(df.CONF_COLOR_DEPTH, default=16): cv.one_of(16), + cv.Optional(df.CONF_DEFAULT_FONT, default="montserrat_14"): lvalid.lv_font, + cv.Optional(df.CONF_FULL_REFRESH, default=False): cv.boolean, + cv.Optional(CONF_BUFFER_SIZE, default="100%"): cv.percentage, + cv.Optional(df.CONF_LOG_LEVEL, default="WARN"): cv.one_of( + *df.LOG_LEVELS, upper=True + ), + cv.Optional(df.CONF_BYTE_ORDER, default="big_endian"): cv.one_of( + "big_endian", "little_endian" + ), + cv.Optional(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA), + cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, + } + ) +).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py new file mode 100644 index 0000000000..50bdac3865 --- /dev/null +++ b/esphome/components/lvgl/defines.py @@ -0,0 +1,487 @@ +""" +This is the base of the import tree for LVGL. It contains constant definitions used elsewhere. +Constants already defined in esphome.const are not duplicated here and must be imported where used. + +""" + +from esphome import codegen as cg, config_validation as cv +from esphome.core import ID, Lambda +from esphome.cpp_types import uint32 +from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor + +from .lvcode import ConstantLiteral + + +class LValidator: + """ + A validator for a particular type used in LVGL. Usable in configs as a validator, also + has `process()` to convert a value during code generation + """ + + def __init__(self, validator, rtype, idtype=None, idexpr=None, retmapper=None): + self.validator = validator + self.rtype = rtype + self.idtype = idtype + self.idexpr = idexpr + self.retmapper = retmapper + + def __call__(self, value): + if isinstance(value, cv.Lambda): + return cv.returning_lambda(value) + if self.idtype is not None and isinstance(value, ID): + return cv.use_id(self.idtype)(value) + return self.validator(value) + + async def process(self, value, args=()): + if value is None: + return None + if isinstance(value, Lambda): + return cg.RawExpression( + f"{await cg.process_lambda(value, args, return_type=self.rtype)}()" + ) + if self.idtype is not None and isinstance(value, ID): + return cg.RawExpression(f"{value}->{self.idexpr}") + if self.retmapper is not None: + return self.retmapper(value) + return cg.safe_exp(value) + + +class LvConstant(LValidator): + """ + Allow one of a list of choices, mapped to upper case, and prepend the choice with the prefix. + It's also permitted to include the prefix in the value + The property `one_of` has the single case validator, and `several_of` allows a list of constants. + """ + + def __init__(self, prefix: str, *choices): + self.prefix = prefix + self.choices = choices + prefixed_choices = [prefix + v for v in choices] + prefixed_validator = cv.one_of(*prefixed_choices, upper=True) + + @schema_extractor("one_of") + def validator(value): + if value == SCHEMA_EXTRACT: + return self.choices + if isinstance(value, str) and value.startswith(self.prefix): + return prefixed_validator(value) + return self.prefix + cv.one_of(*choices, upper=True)(value) + + super().__init__(validator, rtype=uint32) + self.one_of = LValidator(validator, uint32, retmapper=self.mapper) + self.several_of = LValidator( + cv.ensure_list(self.one_of), uint32, retmapper=self.mapper + ) + + def mapper(self, value, args=()): + if isinstance(value, list): + value = "|".join(value) + return ConstantLiteral(value) + + def extend(self, *choices): + """ + Extend an LVCconstant with additional choices. + :param choices: The extra choices + :return: A new LVConstant instance + """ + return LvConstant(self.prefix, *(self.choices + choices)) + + +# Widgets +CONF_LABEL = "label" + +# Parts +CONF_MAIN = "main" +CONF_SCROLLBAR = "scrollbar" +CONF_INDICATOR = "indicator" +CONF_KNOB = "knob" +CONF_SELECTED = "selected" +CONF_ITEMS = "items" +CONF_TICKS = "ticks" +CONF_TICK_STYLE = "tick_style" +CONF_CURSOR = "cursor" +CONF_TEXTAREA_PLACEHOLDER = "textarea_placeholder" + +LV_FONTS = list(f"montserrat_{s}" for s in range(8, 50, 2)) + [ + "dejavu_16_persian_hebrew", + "simsun_16_cjk", + "unscii_8", + "unscii_16", +] + +LV_EVENT = { + "PRESS": "PRESSED", + "SHORT_CLICK": "SHORT_CLICKED", + "LONG_PRESS": "LONG_PRESSED", + "LONG_PRESS_REPEAT": "LONG_PRESSED_REPEAT", + "CLICK": "CLICKED", + "RELEASE": "RELEASED", + "SCROLL_BEGIN": "SCROLL_BEGIN", + "SCROLL_END": "SCROLL_END", + "SCROLL": "SCROLL", + "FOCUS": "FOCUSED", + "DEFOCUS": "DEFOCUSED", + "READY": "READY", + "CANCEL": "CANCEL", +} + +LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT) + + +LV_ANIM = LvConstant( + "LV_SCR_LOAD_ANIM_", + "NONE", + "OVER_LEFT", + "OVER_RIGHT", + "OVER_TOP", + "OVER_BOTTOM", + "MOVE_LEFT", + "MOVE_RIGHT", + "MOVE_TOP", + "MOVE_BOTTOM", + "FADE_IN", + "FADE_OUT", + "OUT_LEFT", + "OUT_RIGHT", + "OUT_TOP", + "OUT_BOTTOM", +) + +LOG_LEVELS = ( + "TRACE", + "INFO", + "WARN", + "ERROR", + "USER", + "NONE", +) + +LV_LONG_MODES = LvConstant( + "LV_LABEL_LONG_", + "WRAP", + "DOT", + "SCROLL", + "SCROLL_CIRCULAR", + "CLIP", +) + +STATES = ( + "default", + "checked", + "focused", + "focus_key", + "edited", + "hovered", + "pressed", + "scrolled", + "disabled", + "user_1", + "user_2", + "user_3", + "user_4", +) + +PARTS = ( + CONF_MAIN, + CONF_SCROLLBAR, + CONF_INDICATOR, + CONF_KNOB, + CONF_SELECTED, + CONF_ITEMS, + CONF_TICKS, + CONF_CURSOR, + CONF_TEXTAREA_PLACEHOLDER, +) + +KEYBOARD_MODES = LvConstant( + "LV_KEYBOARD_MODE_", + "TEXT_LOWER", + "TEXT_UPPER", + "SPECIAL", + "NUMBER", +) +ROLLER_MODES = LvConstant("LV_ROLLER_MODE_", "NORMAL", "INFINITE") +DIRECTIONS = LvConstant("LV_DIR_", "LEFT", "RIGHT", "BOTTOM", "TOP") +TILE_DIRECTIONS = DIRECTIONS.extend("HOR", "VER", "ALL") +CHILD_ALIGNMENTS = LvConstant( + "LV_ALIGN_", + "TOP_LEFT", + "TOP_MID", + "TOP_RIGHT", + "LEFT_MID", + "CENTER", + "RIGHT_MID", + "BOTTOM_LEFT", + "BOTTOM_MID", + "BOTTOM_RIGHT", +) + +SIBLING_ALIGNMENTS = LvConstant( + "LV_ALIGN_", + "OUT_LEFT_TOP", + "OUT_TOP_LEFT", + "OUT_TOP_MID", + "OUT_TOP_RIGHT", + "OUT_RIGHT_TOP", + "OUT_LEFT_MID", + "OUT_RIGHT_MID", + "OUT_LEFT_BOTTOM", + "OUT_BOTTOM_LEFT", + "OUT_BOTTOM_MID", + "OUT_BOTTOM_RIGHT", + "OUT_RIGHT_BOTTOM", +) +ALIGN_ALIGNMENTS = CHILD_ALIGNMENTS.extend(*SIBLING_ALIGNMENTS.choices) + +FLEX_FLOWS = LvConstant( + "LV_FLEX_FLOW_", + "ROW", + "COLUMN", + "ROW_WRAP", + "COLUMN_WRAP", + "ROW_REVERSE", + "COLUMN_REVERSE", + "ROW_WRAP_REVERSE", + "COLUMN_WRAP_REVERSE", +) + +OBJ_FLAGS = ( + "hidden", + "clickable", + "click_focusable", + "checkable", + "scrollable", + "scroll_elastic", + "scroll_momentum", + "scroll_one", + "scroll_chain_hor", + "scroll_chain_ver", + "scroll_chain", + "scroll_on_focus", + "scroll_with_arrow", + "snappable", + "press_lock", + "event_bubble", + "gesture_bubble", + "adv_hittest", + "ignore_layout", + "floating", + "overflow_visible", + "layout_1", + "layout_2", + "widget_1", + "widget_2", + "user_1", + "user_2", + "user_3", + "user_4", +) + +ARC_MODES = LvConstant("LV_ARC_MODE_", "NORMAL", "REVERSE", "SYMMETRICAL") +BAR_MODES = LvConstant("LV_BAR_MODE_", "NORMAL", "SYMMETRICAL", "RANGE") + +BTNMATRIX_CTRLS = ( + "HIDDEN", + "NO_REPEAT", + "DISABLED", + "CHECKABLE", + "CHECKED", + "CLICK_TRIG", + "POPOVER", + "RECOLOR", + "CUSTOM_1", + "CUSTOM_2", +) + +LV_BASE_ALIGNMENTS = ( + "START", + "CENTER", + "END", +) +LV_CELL_ALIGNMENTS = LvConstant( + "LV_GRID_ALIGN_", + *LV_BASE_ALIGNMENTS, +) +LV_GRID_ALIGNMENTS = LV_CELL_ALIGNMENTS.extend( + "STRETCH", + "SPACE_EVENLY", + "SPACE_AROUND", + "SPACE_BETWEEN", +) + +LV_FLEX_ALIGNMENTS = LvConstant( + "LV_FLEX_ALIGN_", + *LV_BASE_ALIGNMENTS, + "SPACE_EVENLY", + "SPACE_AROUND", + "SPACE_BETWEEN", +) + +LV_MENU_MODES = LvConstant( + "LV_MENU_HEADER_", + "TOP_FIXED", + "TOP_UNFIXED", + "BOTTOM_FIXED", +) + +LV_CHART_TYPES = ( + "NONE", + "LINE", + "BAR", + "SCATTER", +) +LV_CHART_AXES = ( + "PRIMARY_Y", + "SECONDARY_Y", + "PRIMARY_X", + "SECONDARY_X", +) + +CONF_ACCEPTED_CHARS = "accepted_chars" +CONF_ADJUSTABLE = "adjustable" +CONF_ALIGN = "align" +CONF_ALIGN_TO = "align_to" +CONF_ANGLE_RANGE = "angle_range" +CONF_ANIMATED = "animated" +CONF_ANIMATION = "animation" +CONF_ANTIALIAS = "antialias" +CONF_ARC_LENGTH = "arc_length" +CONF_AUTO_START = "auto_start" +CONF_BACKGROUND_STYLE = "background_style" +CONF_DECIMAL_PLACES = "decimal_places" +CONF_COLUMN = "column" +CONF_DIGITS = "digits" +CONF_DISP_BG_COLOR = "disp_bg_color" +CONF_DISP_BG_IMAGE = "disp_bg_image" +CONF_BODY = "body" +CONF_BUTTONS = "buttons" +CONF_BYTE_ORDER = "byte_order" +CONF_CHANGE_RATE = "change_rate" +CONF_CLOSE_BUTTON = "close_button" +CONF_COLOR_DEPTH = "color_depth" +CONF_COLOR_END = "color_end" +CONF_COLOR_START = "color_start" +CONF_CONTROL = "control" +CONF_DEFAULT = "default" +CONF_DEFAULT_FONT = "default_font" +CONF_DIR = "dir" +CONF_DISPLAYS = "displays" +CONF_END_ANGLE = "end_angle" +CONF_END_VALUE = "end_value" +CONF_ENTER_BUTTON = "enter_button" +CONF_ENTRIES = "entries" +CONF_FLAGS = "flags" +CONF_FLEX_FLOW = "flex_flow" +CONF_FLEX_ALIGN_MAIN = "flex_align_main" +CONF_FLEX_ALIGN_CROSS = "flex_align_cross" +CONF_FLEX_ALIGN_TRACK = "flex_align_track" +CONF_FLEX_GROW = "flex_grow" +CONF_FULL_REFRESH = "full_refresh" +CONF_GRID_CELL_ROW_POS = "grid_cell_row_pos" +CONF_GRID_CELL_COLUMN_POS = "grid_cell_column_pos" +CONF_GRID_CELL_ROW_SPAN = "grid_cell_row_span" +CONF_GRID_CELL_COLUMN_SPAN = "grid_cell_column_span" +CONF_GRID_CELL_X_ALIGN = "grid_cell_x_align" +CONF_GRID_CELL_Y_ALIGN = "grid_cell_y_align" +CONF_GRID_COLUMN_ALIGN = "grid_column_align" +CONF_GRID_COLUMNS = "grid_columns" +CONF_GRID_ROW_ALIGN = "grid_row_align" +CONF_GRID_ROWS = "grid_rows" +CONF_HEADER_MODE = "header_mode" +CONF_HOME = "home" +CONF_INDICATORS = "indicators" +CONF_KEY_CODE = "key_code" +CONF_LABEL_GAP = "label_gap" +CONF_LAYOUT = "layout" +CONF_LEFT_BUTTON = "left_button" +CONF_LINE_WIDTH = "line_width" +CONF_LOG_LEVEL = "log_level" +CONF_LONG_PRESS_TIME = "long_press_time" +CONF_LONG_PRESS_REPEAT_TIME = "long_press_repeat_time" +CONF_LVGL_ID = "lvgl_id" +CONF_LONG_MODE = "long_mode" +CONF_MAJOR = "major" +CONF_MSGBOXES = "msgboxes" +CONF_OBJ = "obj" +CONF_OFFSET_X = "offset_x" +CONF_OFFSET_Y = "offset_y" +CONF_ONE_LINE = "one_line" +CONF_ON_SELECT = "on_select" +CONF_ONE_CHECKED = "one_checked" +CONF_NEXT = "next" +CONF_PAGE_WRAP = "page_wrap" +CONF_PASSWORD_MODE = "password_mode" +CONF_PIVOT_X = "pivot_x" +CONF_PIVOT_Y = "pivot_y" +CONF_PLACEHOLDER_TEXT = "placeholder_text" +CONF_POINTS = "points" +CONF_PREVIOUS = "previous" +CONF_REPEAT_COUNT = "repeat_count" +CONF_R_MOD = "r_mod" +CONF_RECOLOR = "recolor" +CONF_RIGHT_BUTTON = "right_button" +CONF_ROLLOVER = "rollover" +CONF_ROOT_BACK_BTN = "root_back_btn" +CONF_ROWS = "rows" +CONF_SCALES = "scales" +CONF_SCALE_LINES = "scale_lines" +CONF_SCROLLBAR_MODE = "scrollbar_mode" +CONF_SELECTED_INDEX = "selected_index" +CONF_SHOW_SNOW = "show_snow" +CONF_SPIN_TIME = "spin_time" +CONF_SRC = "src" +CONF_START_ANGLE = "start_angle" +CONF_START_VALUE = "start_value" +CONF_STATES = "states" +CONF_STRIDE = "stride" +CONF_STYLE = "style" +CONF_STYLE_ID = "style_id" +CONF_SKIP = "skip" +CONF_SYMBOL = "symbol" +CONF_TAB_ID = "tab_id" +CONF_TABS = "tabs" +CONF_TEXT = "text" +CONF_TILE = "tile" +CONF_TILE_ID = "tile_id" +CONF_TILES = "tiles" +CONF_TITLE = "title" +CONF_TOP_LAYER = "top_layer" +CONF_TRANSPARENCY_KEY = "transparency_key" +CONF_THEME = "theme" +CONF_VISIBLE_ROW_COUNT = "visible_row_count" +CONF_WIDGET = "widget" +CONF_WIDGETS = "widgets" +CONF_X = "x" +CONF_Y = "y" +CONF_ZOOM = "zoom" + +# Keypad keys + +LV_KEYS = LvConstant( + "LV_KEY_", + "UP", + "DOWN", + "RIGHT", + "LEFT", + "ESC", + "DEL", + "BACKSPACE", + "ENTER", + "NEXT", + "PREV", + "HOME", + "END", +) + + +# list of widgets and the parts allowed +WIDGET_PARTS = { + CONF_LABEL: (CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED), + CONF_OBJ: (CONF_MAIN,), +} + +DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" + + +def join_enums(enums, prefix=""): + return "|".join(f"(int){prefix}{e.upper()}" for e in enums) diff --git a/esphome/components/lvgl/font.cpp b/esphome/components/lvgl/font.cpp new file mode 100644 index 0000000000..9c172f07f5 --- /dev/null +++ b/esphome/components/lvgl/font.cpp @@ -0,0 +1,76 @@ +#include "lvgl_esphome.h" + +#ifdef USE_LVGL_FONT +namespace esphome { +namespace lvgl { + +static const uint8_t *get_glyph_bitmap(const lv_font_t *font, uint32_t unicode_letter) { + auto *fe = (FontEngine *) font->dsc; + const auto *gd = fe->get_glyph_data(unicode_letter); + if (gd == nullptr) + return nullptr; + // esph_log_d(TAG, "Returning bitmap @ %X", (uint32_t)gd->data); + + return gd->data; +} + +static bool get_glyph_dsc_cb(const lv_font_t *font, lv_font_glyph_dsc_t *dsc, uint32_t unicode_letter, uint32_t next) { + auto *fe = (FontEngine *) font->dsc; + const auto *gd = fe->get_glyph_data(unicode_letter); + if (gd == nullptr) + return false; + dsc->adv_w = gd->offset_x + gd->width; + dsc->ofs_x = gd->offset_x; + dsc->ofs_y = fe->height - gd->height - gd->offset_y - fe->baseline; + dsc->box_w = gd->width; + dsc->box_h = gd->height; + dsc->is_placeholder = 0; + dsc->bpp = fe->bpp; + return true; +} + +FontEngine::FontEngine(font::Font *esp_font) : font_(esp_font) { + this->bpp = esp_font->get_bpp(); + this->lv_font_.dsc = this; + this->lv_font_.line_height = this->height = esp_font->get_height(); + this->lv_font_.base_line = this->baseline = this->lv_font_.line_height - esp_font->get_baseline(); + this->lv_font_.get_glyph_dsc = get_glyph_dsc_cb; + this->lv_font_.get_glyph_bitmap = get_glyph_bitmap; + this->lv_font_.subpx = LV_FONT_SUBPX_NONE; + this->lv_font_.underline_position = -1; + this->lv_font_.underline_thickness = 1; +} + +const lv_font_t *FontEngine::get_lv_font() { return &this->lv_font_; } + +const font::GlyphData *FontEngine::get_glyph_data(uint32_t unicode_letter) { + if (unicode_letter == last_letter_) + return this->last_data_; + uint8_t unicode[5]; + memset(unicode, 0, sizeof unicode); + if (unicode_letter > 0xFFFF) { + unicode[0] = 0xF0 + ((unicode_letter >> 18) & 0x7); + unicode[1] = 0x80 + ((unicode_letter >> 12) & 0x3F); + unicode[2] = 0x80 + ((unicode_letter >> 6) & 0x3F); + unicode[3] = 0x80 + (unicode_letter & 0x3F); + } else if (unicode_letter > 0x7FF) { + unicode[0] = 0xE0 + ((unicode_letter >> 12) & 0xF); + unicode[1] = 0x80 + ((unicode_letter >> 6) & 0x3F); + unicode[2] = 0x80 + (unicode_letter & 0x3F); + } else if (unicode_letter > 0x7F) { + unicode[0] = 0xC0 + ((unicode_letter >> 6) & 0x1F); + unicode[1] = 0x80 + (unicode_letter & 0x3F); + } else { + unicode[0] = unicode_letter; + } + int match_length; + int glyph_n = this->font_->match_next_glyph(unicode, &match_length); + if (glyph_n < 0) + return nullptr; + this->last_data_ = this->font_->get_glyphs()[glyph_n].get_glyph_data(); + this->last_letter_ = unicode_letter; + return this->last_data_; +} +} // namespace lvgl +} // namespace esphome +#endif // USES_LVGL_FONT diff --git a/esphome/components/lvgl/helpers.py b/esphome/components/lvgl/helpers.py new file mode 100644 index 0000000000..c8d4948fb1 --- /dev/null +++ b/esphome/components/lvgl/helpers.py @@ -0,0 +1,70 @@ +import re + +from esphome import config_validation as cv +from esphome.config import Config +from esphome.const import CONF_ARGS, CONF_FORMAT +from esphome.core import CORE, ID +from esphome.yaml_util import ESPHomeDataBase + +lv_uses = { + "USER_DATA", + "LOG", + "STYLE", + "FONT_PLACEHOLDER", + "THEME_DEFAULT", +} + + +def add_lv_use(*names): + for name in names: + lv_uses.add(name) + + +lv_fonts_used = set() +esphome_fonts_used = set() +REQUIRED_COMPONENTS = {} +lvgl_components_required = set() + + +def validate_printf(value): + cfmt = r""" + ( # start of capture group 1 + % # literal "%" + (?:[-+0 #]{0,5}) # optional flags + (?:\d+|\*)? # width + (?:\.(?:\d+|\*))? # precision + (?:h|l|ll|w|I|I32|I64)? # size + [cCdiouxXeEfgGaAnpsSZ] # type + ) + """ # noqa + matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) + if len(matches) != len(value[CONF_ARGS]): + raise cv.Invalid( + f"Found {len(matches)} printf-patterns ({', '.join(matches)}), but {len(value[CONF_ARGS])} args were given!" + ) + return value + + +def get_line_marks(value) -> list: + """ + If possible, return a preprocessor directive to identify the line number where the given id was defined. + :param id: The id in question + :return: A list containing zero or more line directives + """ + path = None + if isinstance(value, ESPHomeDataBase): + path = value.esp_range + elif isinstance(value, ID) and isinstance(CORE.config, Config): + path = CORE.config.get_path_for_id(value)[:-1] + path = CORE.config.get_deepest_document_range_for_path(path) + if path is None: + return [] + return [path.start_mark.as_line_directive] + + +def requires_component(comp): + def validator(value): + lvgl_components_required.add(comp) + return cv.requires_component(comp)(value) + + return validator diff --git a/esphome/components/lvgl/label.py b/esphome/components/lvgl/label.py new file mode 100644 index 0000000000..5c4ae6ab0d --- /dev/null +++ b/esphome/components/lvgl/label.py @@ -0,0 +1,34 @@ +import esphome.config_validation as cv + +from .defines import CONF_LABEL, CONF_LONG_MODE, CONF_RECOLOR, CONF_TEXT, LV_LONG_MODES +from .lv_validation import lv_bool, lv_text +from .schemas import TEXT_SCHEMA +from .types import lv_label_t +from .widget import Widget, WidgetType + + +class LabelType(WidgetType): + def __init__(self): + super().__init__( + CONF_LABEL, + TEXT_SCHEMA.extend( + { + cv.Optional(CONF_RECOLOR): lv_bool, + cv.Optional(CONF_LONG_MODE): LV_LONG_MODES.one_of, + } + ), + ) + + @property + def w_type(self): + return lv_label_t + + async def to_code(self, w: Widget, config): + """For a text object, create and set text""" + if value := config.get(CONF_TEXT): + w.set_property(CONF_TEXT, await lv_text.process(value)) + w.set_property(CONF_LONG_MODE, config) + w.set_property(CONF_RECOLOR, config) + + +label_spec = LabelType() diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py new file mode 100644 index 0000000000..1de63c30ce --- /dev/null +++ b/esphome/components/lvgl/lv_validation.py @@ -0,0 +1,170 @@ +import esphome.codegen as cg +from esphome.components.binary_sensor import BinarySensor +from esphome.components.color import ColorStruct +from esphome.components.font import Font +from esphome.components.sensor import Sensor +from esphome.components.text_sensor import TextSensor +import esphome.config_validation as cv +from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT +from esphome.core import HexInt +from esphome.cpp_generator import MockObj +from esphome.helpers import cpp_string_escape +from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor + +from . import types as ty +from .defines import LV_FONTS, LValidator, LvConstant +from .helpers import ( + esphome_fonts_used, + lv_fonts_used, + lvgl_components_required, + requires_component, +) +from .lvcode import ConstantLiteral, lv_expr +from .types import lv_font_t + + +@schema_extractor("one_of") +def color(value): + if value == SCHEMA_EXTRACT: + return ["hex color value", "color ID"] + if isinstance(value, int): + return value + return cv.use_id(ColorStruct)(value) + + +def color_retmapper(value): + if isinstance(value, cv.Lambda): + return cv.returning_lambda(value) + if isinstance(value, int): + hexval = HexInt(value) + return lv_expr.color_hex(hexval) + # Must be an id + lvgl_components_required.add(CONF_COLOR) + return lv_expr.color_from(MockObj(value)) + + +def pixels_or_percent(value): + """A length in one axis - either a number (pixels) or a percentage""" + if value == SCHEMA_EXTRACT: + return ["pixels", "..%"] + if isinstance(value, int): + return str(cv.int_(value)) + # Will throw an exception if not a percentage. + return f"lv_pct({int(cv.percentage(value) * 100)})" + + +def zoom(value): + value = cv.float_range(0.1, 10.0)(value) + return int(value * 256) + + +def angle(value): + """ + Validation for an angle in degrees, converted to an integer representing 0.1deg units + :param value: The input in the range 0..360 + :return: An angle in 1/10 degree units. + """ + return int(cv.float_range(0.0, 360.0)(cv.angle(value)) * 10) + + +@schema_extractor("one_of") +def size(value): + """A size in one axis - one of "size_content", a number (pixels) or a percentage""" + if value == SCHEMA_EXTRACT: + return ["size_content", "pixels", "..%"] + if isinstance(value, str) and value.lower().endswith("px"): + value = cv.int_(value[:-2]) + if isinstance(value, str) and not value.endswith("%"): + if value.upper() == "SIZE_CONTENT": + return "LV_SIZE_CONTENT" + raise cv.Invalid("must be 'size_content', a pixel position or a percentage") + if isinstance(value, int): + return str(cv.int_(value)) + # Will throw an exception if not a percentage. + return f"lv_pct({int(cv.percentage(value) * 100)})" + + +@schema_extractor("one_of") +def opacity(value): + consts = LvConstant("LV_OPA_", "TRANSP", "COVER") + if value == SCHEMA_EXTRACT: + return consts.choices + value = cv.Any(cv.percentage, consts.one_of)(value) + if isinstance(value, float): + return int(value * 255) + return value + + +def stop_value(value): + return cv.int_range(0, 255)(value) + + +lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) +lv_bool = LValidator(cv.boolean, cg.bool_, BinarySensor, "get_state()") + + +def lvms_validator_(value): + if value == "never": + value = "2147483647ms" + return cv.positive_time_period_milliseconds(value) + + +lv_milliseconds = LValidator( + lvms_validator_, + cg.int32, + retmapper=lambda x: x.total_milliseconds, +) + + +class TextValidator(LValidator): + def __init__(self): + super().__init__( + cv.string, + cg.const_char_ptr, + TextSensor, + "get_state().c_str()", + lambda s: cg.safe_exp(f"{s}"), + ) + + def __call__(self, value): + if isinstance(value, dict): + return value + return super().__call__(value) + + async def process(self, value, args=()): + if isinstance(value, dict): + args = [str(x) for x in value[CONF_ARGS]] + arg_expr = cg.RawExpression(",".join(args)) + format_str = cpp_string_escape(value[CONF_FORMAT]) + return f"str_sprintf({format_str}, {arg_expr}).c_str()" + return await super().process(value, args) + + +lv_text = TextValidator() +lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") +lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") + + +class LvFont(LValidator): + def __init__(self): + def lv_builtin_font(value): + fontval = cv.one_of(*LV_FONTS, lower=True)(value) + lv_fonts_used.add(fontval) + return "&lv_font_" + fontval + + def validator(value): + if value == SCHEMA_EXTRACT: + return LV_FONTS + if isinstance(value, str) and value.lower() in LV_FONTS: + return lv_builtin_font(value) + fontval = cv.use_id(Font)(value) + esphome_fonts_used.add(fontval) + return requires_component("font")(f"{fontval}_engine->get_lv_font()") + + super().__init__(validator, lv_font_t) + + async def process(self, value, args=()): + return ConstantLiteral(value) + + +lv_font = LvFont() diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py new file mode 100644 index 0000000000..13b4862b4d --- /dev/null +++ b/esphome/components/lvgl/lvcode.py @@ -0,0 +1,237 @@ +import abc +import logging +from typing import Union + +from esphome import codegen as cg +from esphome.core import ID, Lambda +from esphome.cpp_generator import ( + AssignmentExpression, + CallExpression, + Expression, + LambdaExpression, + Literal, + MockObj, + RawExpression, + RawStatement, + SafeExpType, + Statement, + VariableDeclarationExpression, + statement, +) + +from .helpers import get_line_marks + +_LOGGER = logging.getLogger(__name__) + + +class CodeContext(abc.ABC): + """ + A class providing a context for code generation. Generated code will be added to the + current context. A new context will stack on the current context, and restore it + when done. Used with the `with` statement. + """ + + code_context = None + + @abc.abstractmethod + def add(self, expression: Union[Expression, Statement]): + pass + + @staticmethod + def append(expression: Union[Expression, Statement]): + if CodeContext.code_context is not None: + CodeContext.code_context.add(expression) + return expression + + def __init__(self): + self.previous: Union[CodeContext | None] = None + + def __enter__(self): + self.previous = CodeContext.code_context + CodeContext.code_context = self + + def __exit__(self, *args): + CodeContext.code_context = self.previous + + +class MainContext(CodeContext): + """ + Code generation into the main() function + """ + + def add(self, expression: Union[Expression, Statement]): + return cg.add(expression) + + +class LvContext(CodeContext): + """ + Code generation into the LVGL initialisation code (called in `setup()`) + """ + + lv_init_code: list["Statement"] = [] + + @staticmethod + def lv_add(expression: Union[Expression, Statement]): + if isinstance(expression, Expression): + expression = statement(expression) + if not isinstance(expression, Statement): + raise ValueError( + f"Add '{expression}' must be expression or statement, not {type(expression)}" + ) + LvContext.lv_init_code.append(expression) + _LOGGER.debug("LV Adding: %s", expression) + return expression + + @staticmethod + def get_code(): + code = [] + for exp in LvContext.lv_init_code: + text = str(statement(exp)) + text = text.rstrip() + code.append(text) + return "\n".join(code) + "\n\n" + + def add(self, expression: Union[Expression, Statement]): + return LvContext.lv_add(expression) + + def set_style(self, prop): + return MockObj("lv_set_style_{prop}", "") + + +class LambdaContext(CodeContext): + """ + A context that will accumlate code for use in a lambda. + """ + + def __init__( + self, + parameters: list[tuple[SafeExpType, str]], + return_type: SafeExpType = None, + ): + super().__init__() + self.code_list: list[Statement] = [] + self.parameters = parameters + self.return_type = return_type + + def add(self, expression: Union[Expression, Statement]): + self.code_list.append(expression) + return expression + + async def code(self) -> LambdaExpression: + code_text = [] + for exp in self.code_list: + text = str(statement(exp)) + text = text.rstrip() + code_text.append(text) + return await cg.process_lambda( + Lambda("\n".join(code_text) + "\n\n"), + self.parameters, + return_type=self.return_type, + ) + + +class LocalVariable(MockObj): + """ + Create a local variable and enclose the code using it within a block. + """ + + def __init__(self, name, type, modifier=None, rhs=None): + base = ID(name, True, type) + super().__init__(base, "") + self.modifier = modifier + self.rhs = rhs + + def __enter__(self): + CodeContext.append(RawStatement("{")) + CodeContext.append( + VariableDeclarationExpression(self.base.type, self.modifier, self.base.id) + ) + if self.rhs is not None: + CodeContext.append(AssignmentExpression(None, "", self.base, self.rhs)) + return self.base + + def __exit__(self, *args): + CodeContext.append(RawStatement("}")) + + +class MockLv: + """ + A mock object that can be used to generate LVGL calls. + """ + + def __init__(self, base): + self.base = base + + def __getattr__(self, attr: str) -> "MockLv": + return MockLv(f"{self.base}{attr}") + + def append(self, expression): + CodeContext.append(expression) + + def __call__(self, *args: SafeExpType) -> "MockObj": + call = CallExpression(self.base, *args) + result = MockObj(call, "") + self.append(result) + return result + + def __str__(self): + return str(self.base) + + def __repr__(self): + return f"MockLv<{str(self.base)}>" + + def call(self, prop, *args): + call = CallExpression(RawExpression(f"{self.base}{prop}"), *args) + result = MockObj(call, "") + self.append(result) + return result + + def cond_if(self, expression: Expression): + CodeContext.append(RawExpression(f"if({expression}) {{")) + + def cond_else(self): + CodeContext.append(RawExpression("} else {")) + + def cond_endif(self): + CodeContext.append(RawExpression("}")) + + +class LvExpr(MockLv): + def __getattr__(self, attr: str) -> "MockLv": + return LvExpr(f"{self.base}{attr}") + + def append(self, expression): + pass + + +# Top level mock for generic lv_ calls to be recorded +lv = MockLv("lv_") +# Just generate an expression +lv_expr = LvExpr("lv_") +# Mock for lv_obj_ calls +lv_obj = MockLv("lv_obj_") + + +# equivalent to cg.add() for the lvgl init context +def lv_add(expression: Union[Expression, Statement]): + return CodeContext.append(expression) + + +def add_line_marks(where): + for mark in get_line_marks(where): + lv_add(cg.RawStatement(mark)) + + +def lv_assign(target, expression): + lv_add(RawExpression(f"{target} = {expression}")) + + +class ConstantLiteral(Literal): + __slots__ = ("constant",) + + def __init__(self, constant: str): + super().__init__() + self.constant = constant + + def __str__(self): + return self.constant diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp new file mode 100644 index 0000000000..bdaf8a4f18 --- /dev/null +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -0,0 +1,129 @@ +#include "esphome/core/defines.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include "esphome/core/hal.h" +#include "lvgl_hal.h" +#include "lvgl_esphome.h" + +namespace esphome { +namespace lvgl { +static const char *const TAG = "lvgl"; + +lv_event_code_t lv_custom_event; // NOLINT +void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); } +void LvglComponent::draw_buffer_(const lv_area_t *area, const uint8_t *ptr) { + for (auto *display : this->displays_) { + display->draw_pixels_at(area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area), ptr, + display::COLOR_ORDER_RGB, LV_BITNESS, LV_COLOR_16_SWAP); + } +} + +void LvglComponent::flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { + auto now = millis(); + this->draw_buffer_(area, (const uint8_t *) color_p); + ESP_LOGV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area), + lv_area_get_height(area), (int) (millis() - now)); + lv_disp_flush_ready(disp_drv); +} + +void LvglComponent::setup() { + ESP_LOGCONFIG(TAG, "LVGL Setup starts"); +#if LV_USE_LOG + lv_log_register_print_cb(log_cb); +#endif + lv_init(); + lv_custom_event = static_cast(lv_event_register_id()); + auto *display = this->displays_[0]; + size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_; + auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; + auto *buf = lv_custom_mem_alloc(buf_bytes); + if (buf == nullptr) { + ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); + this->mark_failed(); + this->status_set_error("Memory allocation failure"); + return; + } + lv_disp_draw_buf_init(&this->draw_buf_, buf, nullptr, buffer_pixels); + lv_disp_drv_init(&this->disp_drv_); + this->disp_drv_.draw_buf = &this->draw_buf_; + this->disp_drv_.user_data = this; + this->disp_drv_.full_refresh = this->full_refresh_; + this->disp_drv_.flush_cb = static_flush_cb; + this->disp_drv_.rounder_cb = rounder_cb; + switch (display->get_rotation()) { + case display::DISPLAY_ROTATION_0_DEGREES: + break; + case display::DISPLAY_ROTATION_90_DEGREES: + this->disp_drv_.sw_rotate = true; + this->disp_drv_.rotated = LV_DISP_ROT_90; + break; + case display::DISPLAY_ROTATION_180_DEGREES: + this->disp_drv_.sw_rotate = true; + this->disp_drv_.rotated = LV_DISP_ROT_180; + break; + case display::DISPLAY_ROTATION_270_DEGREES: + this->disp_drv_.sw_rotate = true; + this->disp_drv_.rotated = LV_DISP_ROT_270; + break; + } + display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES); + this->disp_drv_.hor_res = (lv_coord_t) display->get_width(); + this->disp_drv_.ver_res = (lv_coord_t) display->get_height(); + ESP_LOGV(TAG, "sw_rotate = %d, rotated=%d", this->disp_drv_.sw_rotate, this->disp_drv_.rotated); + this->disp_ = lv_disp_drv_register(&this->disp_drv_); + for (const auto &v : this->init_lambdas_) + v(this->disp_); + lv_disp_trig_activity(this->disp_); + ESP_LOGCONFIG(TAG, "LVGL Setup complete"); +} +} // namespace lvgl +} // namespace esphome + +size_t lv_millis(void) { return esphome::millis(); } + +#if defined(USE_HOST) || defined(USE_RP2040) || defined(USE_ESP8266) +void *lv_custom_mem_alloc(size_t size) { + auto *ptr = malloc(size); // NOLINT + if (ptr == nullptr) { + esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); + } + return ptr; +} +void lv_custom_mem_free(void *ptr) { return free(ptr); } // NOLINT +void *lv_custom_mem_realloc(void *ptr, size_t size) { return realloc(ptr, size); } // NOLINT +#else +static unsigned cap_bits = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; // NOLINT + +void *lv_custom_mem_alloc(size_t size) { + void *ptr; + ptr = heap_caps_malloc(size, cap_bits); + if (ptr == nullptr) { + cap_bits = MALLOC_CAP_8BIT; + ptr = heap_caps_malloc(size, cap_bits); + } + if (ptr == nullptr) { + esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); + return nullptr; + } +#ifdef ESPHOME_LOG_HAS_VERBOSE + esphome::ESP_LOGV(esphome::lvgl::TAG, "allocate %zu - > %p", size, ptr); +#endif + return ptr; +} + +void lv_custom_mem_free(void *ptr) { +#ifdef ESPHOME_LOG_HAS_VERBOSE + esphome::ESP_LOGV(esphome::lvgl::TAG, "free %p", ptr); +#endif + if (ptr == nullptr) + return; + heap_caps_free(ptr); +} + +void *lv_custom_mem_realloc(void *ptr, size_t size) { +#ifdef ESPHOME_LOG_HAS_VERBOSE + esphome::ESP_LOGV(esphome::lvgl::TAG, "realloc %p: %zu", ptr, size); +#endif + return heap_caps_realloc(ptr, size, cap_bits); +} +#endif diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h new file mode 100644 index 0000000000..988c22917b --- /dev/null +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -0,0 +1,119 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_LVGL + +// required for clang-tidy +#ifndef LV_CONF_H +#define LV_CONF_SKIP 1 // NOLINT +#endif + +#include "esphome/components/display/display.h" +#include "esphome/components/display/display_color_utils.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include +#include + +#ifdef USE_LVGL_FONT +#include "esphome/components/font/font.h" +#endif +namespace esphome { +namespace lvgl { + +extern lv_event_code_t lv_custom_event; // NOLINT +#ifdef USE_LVGL_COLOR +static lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } +#endif +#if LV_COLOR_DEPTH == 16 +static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; +#elif LV_COLOR_DEPTH == 32 +static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_888; +#else +static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_332; +#endif + +// Parent class for things that wrap an LVGL object +class LvCompound { + public: + virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } + lv_obj_t *obj{}; +}; + +using LvLambdaType = std::function; +using set_value_lambda_t = std::function; +using event_callback_t = void(_lv_event_t *); +using text_lambda_t = std::function; + +#ifdef USE_LVGL_FONT +class FontEngine { + public: + FontEngine(font::Font *esp_font); + const lv_font_t *get_lv_font(); + + const font::GlyphData *get_glyph_data(uint32_t unicode_letter); + uint16_t baseline{}; + uint16_t height{}; + uint8_t bpp{}; + + protected: + font::Font *font_{}; + uint32_t last_letter_{}; + const font::GlyphData *last_data_{}; + lv_font_t lv_font_{}; +}; +#endif // USE_LVGL_FONT + +class LvglComponent : public PollingComponent { + constexpr static const char *const TAG = "lvgl"; + + public: + static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { + reinterpret_cast(disp_drv->user_data)->flush_cb_(disp_drv, area, color_p); + } + + float get_setup_priority() const override { return setup_priority::PROCESSOR; } + static void log_cb(const char *buf) { + esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); + } + static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { + // make sure all coordinates are even + if (area->x1 & 1) + area->x1--; + if (!(area->x2 & 1)) + area->x2++; + if (area->y1 & 1) + area->y1--; + if (!(area->y2 & 1)) + area->y2++; + } + + void loop() override { lv_timer_handler_run_in_period(5); } + void setup() override; + + void update() override {} + + void add_display(display::Display *display) { this->displays_.push_back(display); } + void add_init_lambda(const std::function &lamb) { this->init_lambdas_.push_back(lamb); } + void dump_config() override; + void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; } + void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } + lv_disp_t *get_disp() { return this->disp_; } + + protected: + void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); + void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); + std::vector displays_{}; + lv_disp_draw_buf_t draw_buf_{}; + lv_disp_drv_t disp_drv_{}; + lv_disp_t *disp_{}; + + std::vector> init_lambdas_; + size_t buffer_frac_{1}; + bool full_refresh_{}; +}; + +} // namespace lvgl +} // namespace esphome + +#endif diff --git a/esphome/components/lvgl/lvgl_hal.h b/esphome/components/lvgl/lvgl_hal.h new file mode 100644 index 0000000000..754cc70391 --- /dev/null +++ b/esphome/components/lvgl/lvgl_hal.h @@ -0,0 +1,21 @@ +// +// Created by Clyde Stubbs on 20/9/2023. +// + +#pragma once + +#ifdef __cplusplus +#define EXTERNC extern "C" +#include +namespace esphome { +namespace lvgl {} +} // namespace esphome +#else +#define EXTERNC extern +#include +#endif + +EXTERNC size_t lv_millis(void); +EXTERNC void *lv_custom_mem_alloc(size_t size); +EXTERNC void lv_custom_mem_free(void *ptr); +EXTERNC void *lv_custom_mem_realloc(void *ptr, size_t size); diff --git a/esphome/components/lvgl/obj.py b/esphome/components/lvgl/obj.py new file mode 100644 index 0000000000..fba20bef36 --- /dev/null +++ b/esphome/components/lvgl/obj.py @@ -0,0 +1,22 @@ +from .defines import CONF_OBJ +from .types import lv_obj_t +from .widget import WidgetType + + +class ObjType(WidgetType): + """ + The base LVGL object. All other widgets inherit from this. + """ + + def __init__(self): + super().__init__(CONF_OBJ, schema={}, modify_schema={}) + + @property + def w_type(self): + return lv_obj_t + + async def to_code(self, w, config): + return [] + + +obj_spec = ObjType() diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py new file mode 100644 index 0000000000..4ae5824151 --- /dev/null +++ b/esphome/components/lvgl/schemas.py @@ -0,0 +1,260 @@ +from esphome import config_validation as cv +from esphome.const import CONF_ARGS, CONF_FORMAT, CONF_ID, CONF_STATE, CONF_TYPE +from esphome.schema_extractors import SCHEMA_EXTRACT + +from . import defines as df, lv_validation as lvalid, types as ty +from .defines import WIDGET_PARTS +from .helpers import ( + REQUIRED_COMPONENTS, + add_lv_use, + requires_component, + validate_printf, +) +from .lv_validation import lv_font +from .types import WIDGET_TYPES, get_widget_type + +# A schema for text properties +TEXT_SCHEMA = cv.Schema( + { + cv.Optional(df.CONF_TEXT): cv.Any( + cv.All( + cv.Schema( + { + cv.Required(CONF_FORMAT): cv.string, + cv.Optional(CONF_ARGS, default=list): cv.ensure_list( + cv.lambda_ + ), + }, + ), + validate_printf, + ), + lvalid.lv_text, + ) + } +) + +# All LVGL styles and their validators +STYLE_PROPS = { + "align": df.CHILD_ALIGNMENTS.one_of, + "arc_opa": lvalid.opacity, + "arc_color": lvalid.lv_color, + "arc_rounded": lvalid.lv_bool, + "arc_width": cv.positive_int, + "anim_time": lvalid.lv_milliseconds, + "bg_color": lvalid.lv_color, + "bg_grad_color": lvalid.lv_color, + "bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, + "bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of, + "bg_grad_stop": lvalid.stop_value, + "bg_img_opa": lvalid.opacity, + "bg_img_recolor": lvalid.lv_color, + "bg_img_recolor_opa": lvalid.opacity, + "bg_main_stop": lvalid.stop_value, + "bg_opa": lvalid.opacity, + "border_color": lvalid.lv_color, + "border_opa": lvalid.opacity, + "border_post": lvalid.lv_bool, + "border_side": df.LvConstant( + "LV_BORDER_SIDE_", "NONE", "TOP", "BOTTOM", "LEFT", "RIGHT", "INTERNAL" + ).several_of, + "border_width": cv.positive_int, + "clip_corner": lvalid.lv_bool, + "height": lvalid.size, + "img_recolor": lvalid.lv_color, + "img_recolor_opa": lvalid.opacity, + "line_width": cv.positive_int, + "line_dash_width": cv.positive_int, + "line_dash_gap": cv.positive_int, + "line_rounded": lvalid.lv_bool, + "line_color": lvalid.lv_color, + "opa": lvalid.opacity, + "opa_layered": lvalid.opacity, + "outline_color": lvalid.lv_color, + "outline_opa": lvalid.opacity, + "outline_pad": lvalid.size, + "outline_width": lvalid.size, + "pad_all": lvalid.size, + "pad_bottom": lvalid.size, + "pad_column": lvalid.size, + "pad_left": lvalid.size, + "pad_right": lvalid.size, + "pad_row": lvalid.size, + "pad_top": lvalid.size, + "shadow_color": lvalid.lv_color, + "shadow_ofs_x": cv.int_, + "shadow_ofs_y": cv.int_, + "shadow_opa": lvalid.opacity, + "shadow_spread": cv.int_, + "shadow_width": cv.positive_int, + "text_align": df.LvConstant( + "LV_TEXT_ALIGN_", "LEFT", "CENTER", "RIGHT", "AUTO" + ).one_of, + "text_color": lvalid.lv_color, + "text_decor": df.LvConstant( + "LV_TEXT_DECOR_", "NONE", "UNDERLINE", "STRIKETHROUGH" + ).several_of, + "text_font": lv_font, + "text_letter_space": cv.positive_int, + "text_line_space": cv.positive_int, + "text_opa": lvalid.opacity, + "transform_angle": lvalid.angle, + "transform_height": lvalid.pixels_or_percent, + "transform_pivot_x": lvalid.pixels_or_percent, + "transform_pivot_y": lvalid.pixels_or_percent, + "transform_zoom": lvalid.zoom, + "translate_x": lvalid.pixels_or_percent, + "translate_y": lvalid.pixels_or_percent, + "max_height": lvalid.pixels_or_percent, + "max_width": lvalid.pixels_or_percent, + "min_height": lvalid.pixels_or_percent, + "min_width": lvalid.pixels_or_percent, + "radius": cv.Any(lvalid.size, df.LvConstant("LV_RADIUS_", "CIRCLE").one_of), + "width": lvalid.size, + "x": lvalid.pixels_or_percent, + "y": lvalid.pixels_or_percent, +} + +# Complete object style schema +STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( + { + cv.Optional(df.CONF_SCROLLBAR_MODE): df.LvConstant( + "LV_SCROLLBAR_MODE_", "OFF", "ON", "ACTIVE", "AUTO" + ).one_of, + } +) + +# Object states. Top level properties apply to MAIN +STATE_SCHEMA = cv.Schema( + {cv.Optional(state): STYLE_SCHEMA for state in df.STATES} +).extend(STYLE_SCHEMA) +# Setting object states +SET_STATE_SCHEMA = cv.Schema( + {cv.Optional(state): lvalid.lv_bool for state in df.STATES} +) +# Setting object flags +FLAG_SCHEMA = cv.Schema({cv.Optional(flag): cv.boolean for flag in df.OBJ_FLAGS}) +FLAG_LIST = cv.ensure_list(df.LvConstant("LV_OBJ_FLAG_", *df.OBJ_FLAGS).one_of) + + +def part_schema(widget_type): + """ + Generate a schema for the various parts (e.g. main:, indicator:) of a widget type + :param widget_type: The type of widget to generate for + :return: + """ + parts = WIDGET_PARTS.get(widget_type) + if parts is None: + parts = (df.CONF_MAIN,) + return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend( + STATE_SCHEMA + ) + + +def obj_schema(widget_type: str): + """ + Create a schema for a widget type itself i.e. no allowance for children + :param widget_type: + :return: + """ + return ( + part_schema(widget_type) + .extend(FLAG_SCHEMA) + .extend(ALIGN_TO_SCHEMA) + .extend( + cv.Schema( + { + cv.Optional(CONF_STATE): SET_STATE_SCHEMA, + } + ) + ) + ) + + +ALIGN_TO_SCHEMA = { + cv.Optional(df.CONF_ALIGN_TO): cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(ty.lv_obj_t), + cv.Required(df.CONF_ALIGN): df.ALIGN_ALIGNMENTS.one_of, + cv.Optional(df.CONF_X, default=0): lvalid.pixels_or_percent, + cv.Optional(df.CONF_Y, default=0): lvalid.pixels_or_percent, + } + ) +} + + +# A style schema that can include text +STYLED_TEXT_SCHEMA = cv.maybe_simple_value( + STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT +) + + +ALL_STYLES = { + **STYLE_PROPS, +} + + +def container_validator(schema, widget_type): + """ + Create a validator for a container given the widget type + :param schema: Base schema to extend + :param widget_type: + :return: + """ + + def validator(value): + result = schema + if w_sch := WIDGET_TYPES[widget_type].schema: + result = result.extend(w_sch) + if value and (layout := value.get(df.CONF_LAYOUT)): + if not isinstance(layout, dict): + raise cv.Invalid("Layout value must be a dict") + ltype = layout.get(CONF_TYPE) + add_lv_use(ltype) + if value == SCHEMA_EXTRACT: + return result + return result(value) + + return validator + + +def container_schema(widget_type, extras=None): + """ + Create a schema for a container widget of a given type. All obj properties are available, plus + the extras passed in, plus any defined for the specific widget being specified. + :param widget_type: The widget type, e.g. "img" + :param extras: Additional options to be made available, e.g. layout properties for children + :return: The schema for this type of widget. + """ + lv_type = get_widget_type(widget_type) + schema = obj_schema(widget_type).extend({cv.GenerateID(): cv.declare_id(lv_type)}) + if extras: + schema = schema.extend(extras) + # Delayed evaluation for recursion + return container_validator(schema, widget_type) + + +def widget_schema(widget_type, extras=None): + """ + Create a schema for a given widget type + :param widget_type: The name of the widget + :param extras: + :return: + """ + validator = container_schema(widget_type, extras=extras) + if required := REQUIRED_COMPONENTS.get(widget_type): + validator = cv.All(validator, requires_component(required)) + return cv.Exclusive(widget_type, df.CONF_WIDGETS), validator + + +# All widget schemas must be defined before this is called. + + +def any_widget_schema(extras=None): + """ + Generate schemas for all possible LVGL widgets. This is what implements the ability to have a list of any kind of + widget under the widgets: key. + + :param extras: Additional schema to be applied to each generated one + :return: + """ + return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_PARTS)) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py new file mode 100644 index 0000000000..3c043d266d --- /dev/null +++ b/esphome/components/lvgl/types.py @@ -0,0 +1,64 @@ +from esphome import codegen as cg +from esphome.core import ID + +from .defines import CONF_LABEL, CONF_OBJ, CONF_TEXT + +uint16_t_ptr = cg.uint16.operator("ptr") +lvgl_ns = cg.esphome_ns.namespace("lvgl") +char_ptr = cg.global_ns.namespace("char").operator("ptr") +void_ptr = cg.void.operator("ptr") +LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) +lv_event_code_t = cg.global_ns.namespace("lv_event_code_t") +FontEngine = lvgl_ns.class_("FontEngine") +LvCompound = lvgl_ns.class_("LvCompound") +lv_font_t = cg.global_ns.class_("lv_font_t") +lv_style_t = cg.global_ns.struct("lv_style_t") +lv_pseudo_button_t = lvgl_ns.class_("LvPseudoButton") +lv_obj_base_t = cg.global_ns.class_("lv_obj_t", lv_pseudo_button_t) +lv_obj_t_ptr = lv_obj_base_t.operator("ptr") +lv_disp_t_ptr = cg.global_ns.struct("lv_disp_t").operator("ptr") +lv_color_t = cg.global_ns.struct("lv_color_t") + + +# this will be populated later, in __init__.py to avoid circular imports. +WIDGET_TYPES: dict = {} + + +class LvType(cg.MockObjClass): + def __init__(self, *args, **kwargs): + parens = kwargs.pop("parents", ()) + super().__init__(*args, parents=parens + (lv_obj_base_t,)) + self.args = kwargs.pop("largs", [(lv_obj_t_ptr, "obj")]) + self.value = kwargs.pop("lvalue", lambda w: w.obj) + self.has_on_value = kwargs.pop("has_on_value", False) + self.value_property = None + + def get_arg_type(self): + return self.args[0][0] if len(self.args) else None + + +class LvText(LvType): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + largs=[(cg.std_string, "text")], + lvalue=lambda w: w.get_property("text")[0], + **kwargs, + ) + self.value_property = CONF_TEXT + + +lv_obj_t = LvType("lv_obj_t") +lv_label_t = LvText("lv_label_t") + +LV_TYPES = { + CONF_LABEL: lv_label_t, + CONF_OBJ: lv_obj_t, +} + + +def get_widget_type(typestr: str) -> LvType: + return LV_TYPES[typestr] + + +CUSTOM_EVENT = ID("lv_custom_event", False, type=lv_event_code_t) diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widget.py new file mode 100644 index 0000000000..44f277f1c3 --- /dev/null +++ b/esphome/components/lvgl/widget.py @@ -0,0 +1,347 @@ +import sys +from typing import Any + +from esphome import codegen as cg, config_validation as cv +from esphome.config_validation import Invalid +from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE +from esphome.core import ID, TimePeriod +from esphome.coroutine import FakeAwaitable +from esphome.cpp_generator import MockObjClass + +from .defines import ( + CONF_DEFAULT, + CONF_MAIN, + CONF_SCROLLBAR_MODE, + CONF_WIDGETS, + OBJ_FLAGS, + PARTS, + STATES, + LValidator, + join_enums, +) +from .helpers import add_lv_use +from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj +from .schemas import ALL_STYLES +from .types import WIDGET_TYPES, LvCompound, lv_obj_t + +EVENT_LAMB = "event_lamb__" + + +class WidgetType: + """ + Describes a type of Widget, e.g. "bar" or "line" + """ + + def __init__(self, name, schema=None, modify_schema=None): + """ + :param name: The widget name, e.g. "bar" + :param schema: The config schema for defining a widget + :param modify_schema: A schema to update the widget + """ + self.name = name + self.schema = schema or {} + if modify_schema is None: + self.modify_schema = schema + else: + self.modify_schema = modify_schema + + @property + def animated(self): + return False + + @property + def w_type(self): + """ + Get the type associated with this widget + :return: + """ + return lv_obj_t + + def is_compound(self): + return self.w_type.inherits_from(LvCompound) + + async def to_code(self, w, config: dict): + """ + Generate code for a given widget + :param w: The widget + :param config: Its configuration + :return: Generated code as a list of text lines + """ + raise NotImplementedError(f"No to_code defined for {self.name}") + + def obj_creator(self, parent: MockObjClass, config: dict): + """ + Create an instance of the widget type + :param parent: The parent to which it should be attached + :param config: Its configuration + :return: Generated code as a single text line + """ + return f"lv_{self.name}_create({parent})" + + def get_uses(self): + """ + Get a list of other widgets used by this one + :return: + """ + return () + + +class LvScrActType(WidgetType): + """ + A "widget" representing the active screen. + """ + + def __init__(self): + super().__init__("lv_scr_act()") + + def obj_creator(self, parent: MockObjClass, config: dict): + return [] + + async def to_code(self, w, config: dict): + return [] + + +class Widget: + """ + Represents a Widget. + """ + + widgets_completed = False + + @staticmethod + def set_completed(): + Widget.widgets_completed = True + + def __init__(self, var, wtype: WidgetType, config: dict = None, parent=None): + self.var = var + self.type = wtype + self.config = config + self.scale = 1.0 + self.step = 1.0 + self.range_from = -sys.maxsize + self.range_to = sys.maxsize + self.parent = parent + + @staticmethod + def create(name, var, wtype: WidgetType, config: dict = None, parent=None): + w = Widget(var, wtype, config, parent) + if name is not None: + widget_map[name] = w + return w + + @property + def obj(self): + if self.type.is_compound(): + return f"{self.var}->obj" + return self.var + + def add_state(self, *args): + return lv_obj.add_state(self.obj, *args) + + def clear_state(self, *args): + return lv_obj.clear_state(self.obj, *args) + + def add_flag(self, *args): + return lv_obj.add_flag(self.obj, *args) + + def clear_flag(self, *args): + return lv_obj.clear_flag(self.obj, *args) + + def set_property(self, prop, value, animated: bool = None, ltype=None): + if isinstance(value, dict): + value = value.get(prop) + if value is None: + return + if isinstance(value, TimePeriod): + value = value.total_milliseconds + ltype = ltype or self.__type_base() + if animated is None or self.type.animated is not True: + lv.call(f"{ltype}_set_{prop}", self.obj, value) + else: + lv.call( + f"{ltype}_set_{prop}", + self.obj, + value, + "LV_ANIM_ON" if animated else "LV_ANIM_OFF", + ) + + def get_property(self, prop, ltype=None): + ltype = ltype or self.__type_base() + return f"lv_{ltype}_get_{prop}({self.obj})" + + def set_style(self, prop, value, state): + if value is None: + return [] + return lv.call(f"obj_set_style_{prop}", self.obj, value, state) + + def __type_base(self): + wtype = self.type.w_type + base = str(wtype) + if base.startswith("Lv"): + return f"{wtype}".removeprefix("Lv").removesuffix("Type").lower() + return f"{wtype}".removeprefix("lv_").removesuffix("_t") + + def __str__(self): + return f"({self.var}, {self.type})" + + +# Map of widgets to their config, used for trigger generation +widget_map: dict[Any, Widget] = {} + + +def get_widget_generator(wid): + """ + Used to wait for a widget during code generation. + :param wid: + :return: + """ + while True: + if obj := widget_map.get(wid): + return obj + if Widget.widgets_completed: + raise Invalid( + f"Widget {wid} not found, yet all widgets should be defined by now" + ) + yield + + +async def get_widget(wid: ID) -> Widget: + if obj := widget_map.get(wid): + return obj + return await FakeAwaitable(get_widget_generator(wid)) + + +def collect_props(config): + """ + Collect all properties from a configuration + :param config: + :return: + """ + props = {} + for prop in [*ALL_STYLES, *OBJ_FLAGS, CONF_GROUP]: + if prop in config: + props[prop] = config[prop] + return props + + +def collect_states(config): + """ + Collect prperties for each state of a widget + :param config: + :return: + """ + states = {CONF_DEFAULT: collect_props(config)} + for state in STATES: + if state in config: + states[state] = collect_props(config[state]) + return states + + +def collect_parts(config): + """ + Collect properties and states for all widget parts + :param config: + :return: + """ + parts = {CONF_MAIN: collect_states(config)} + for part in PARTS: + if part in config: + parts[part] = collect_states(config[part]) + return parts + + +async def set_obj_properties(w: Widget, config): + """Generate a list of C++ statements to apply properties to an lv_obj_t""" + parts = collect_parts(config) + for part, states in parts.items(): + for state, props in states.items(): + lv_state = ConstantLiteral( + f"(int)LV_STATE_{state.upper()}|(int)LV_PART_{part.upper()}" + ) + for prop, value in { + k: v for k, v in props.items() if k in ALL_STYLES + }.items(): + if isinstance(ALL_STYLES[prop], LValidator): + value = await ALL_STYLES[prop].process(value) + w.set_style(prop, value, lv_state) + flag_clr = set() + flag_set = set() + props = parts[CONF_MAIN][CONF_DEFAULT] + for prop, value in {k: v for k, v in props.items() if k in OBJ_FLAGS}.items(): + if value: + flag_set.add(prop) + else: + flag_clr.add(prop) + if flag_set: + adds = join_enums(flag_set, "LV_OBJ_FLAG_") + w.add_flag(adds) + if flag_clr: + clrs = join_enums(flag_clr, "LV_OBJ_FLAG_") + w.clear_flag(clrs) + + if states := config.get(CONF_STATE): + adds = set() + clears = set() + lambs = {} + for key, value in states.items(): + if isinstance(value, cv.Lambda): + lambs[key] = value + elif value == "true": + adds.add(key) + else: + clears.add(key) + if adds: + adds = ConstantLiteral(join_enums(adds, "LV_STATE_")) + w.add_state(adds) + if clears: + clears = ConstantLiteral(join_enums(clears, "LV_STATE_")) + w.clear_state(clears) + for key, value in lambs.items(): + lamb = await cg.process_lambda(value, [], return_type=cg.bool_) + state = ConstantLiteral(f"LV_STATE_{key.upper}") + lv.cond_if(lamb) + w.add_state(state) + lv.cond_else() + w.clear_state(state) + lv.cond_endif() + if scrollbar_mode := config.get(CONF_SCROLLBAR_MODE): + lv_obj.set_scrollbar_mode(w.obj, scrollbar_mode) + + +async def add_widgets(parent: Widget, config: dict): + """ + Add all widgets to an object + :param parent: The enclosing obj + :param config: The configuration + :return: + """ + for w in config.get(CONF_WIDGETS) or (): + w_type, w_cnfig = next(iter(w.items())) + await widget_to_code(w_cnfig, w_type, parent.obj) + + +async def widget_to_code(w_cnfig, w_type, parent): + """ + Converts a Widget definition to C code. + :param w_cnfig: The widget configuration + :param w_type: The Widget type + :param parent: The parent to which the widget should be added + :return: + """ + spec: WidgetType = WIDGET_TYPES[w_type] + creator = spec.obj_creator(parent, w_cnfig) + add_lv_use(spec.name) + add_lv_use(*spec.get_uses()) + wid = w_cnfig[CONF_ID] + add_line_marks(wid) + if spec.is_compound(): + var = cg.new_Pvariable(wid) + lv_add(var.set_obj(creator)) + else: + var = cg.Pvariable(wid, cg.nullptr, type_=lv_obj_t) + lv_assign(var, creator) + + widget = Widget.create(wid, var, spec, w_cnfig, parent) + await set_obj_properties(widget, w_cnfig) + await add_widgets(widget, w_cnfig) + await spec.to_code(widget, w_cnfig) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 4831ed2c9e..9d453260ab 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -38,6 +38,9 @@ #define USE_LIGHT #define USE_LOCK #define USE_LOGGER +#define USE_LVGL +#define USE_LVGL_FONT +#define USE_LVGL_IMAGE #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT diff --git a/platformio.ini b/platformio.ini index fc7f35b6c3..baf0a85d73 100644 --- a/platformio.ini +++ b/platformio.ini @@ -42,6 +42,7 @@ lib_deps = pavlodn/HaierProtocol@0.9.31 ; haier ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library + lvgl/lvgl@8.4.0 ; lvgl build_flags = -DESPHOME_LOG_LEVEL=ESPHOME_LOG_LEVEL_VERY_VERBOSE src_filter = diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml new file mode 100644 index 0000000000..856e7c3e9d --- /dev/null +++ b/tests/components/lvgl/lvgl-package.yaml @@ -0,0 +1,24 @@ +color: + - id: light_blue + hex: "3340FF" + +lvgl: + bg_color: light_blue + widgets: + - label: + text: Hello world + text_color: 0xFF8000 + align: center + text_font: montserrat_40 + border_post: true + + - label: + text: "Hello shiny day" + text_color: 0xFFFFFF + align: bottom_mid + text_font: space16 + +font: + - file: "gfonts://Roboto" + id: space16 + bpp: 4 diff --git a/tests/components/lvgl/test.esp32-ard.yaml b/tests/components/lvgl/test.esp32-ard.yaml new file mode 100644 index 0000000000..abfb324ea5 --- /dev/null +++ b/tests/components/lvgl/test.esp32-ard.yaml @@ -0,0 +1,30 @@ +spi: + clk_pin: 14 + mosi_pin: 13 + +i2c: + sda: GPIO18 + scl: GPIO19 + +display: + - platform: ili9xxx + model: st7789v + id: tft_display + dimensions: + width: 240 + height: 320 + transform: + swap_xy: false + mirror_x: true + mirror_y: true + data_rate: 80MHz + cs_pin: GPIO22 + dc_pin: GPIO21 + auto_clear_enabled: false + invert_colors: false + update_interval: never + +packages: + lvgl: !include lvgl-package.yaml + +<<: !include common.yaml diff --git a/tests/components/lvgl/test.esp32-idf.yaml b/tests/components/lvgl/test.esp32-idf.yaml new file mode 100644 index 0000000000..f159431b99 --- /dev/null +++ b/tests/components/lvgl/test.esp32-idf.yaml @@ -0,0 +1,52 @@ +spi: + clk_pin: 14 + mosi_pin: 13 + +i2c: + sda: GPIO18 + scl: GPIO19 + +display: + - platform: ili9xxx + model: st7789v + id: second_display + dimensions: + width: 240 + height: 320 + transform: + swap_xy: false + mirror_x: true + mirror_y: true + data_rate: 80MHz + cs_pin: GPIO20 + dc_pin: GPIO15 + auto_clear_enabled: false + invert_colors: false + update_interval: never + + - platform: ili9xxx + model: st7789v + id: tft_display + dimensions: + width: 240 + height: 320 + transform: + swap_xy: false + mirror_x: true + mirror_y: true + data_rate: 80MHz + cs_pin: GPIO22 + dc_pin: GPIO21 + auto_clear_enabled: false + invert_colors: false + update_interval: never + +packages: + lvgl: !include lvgl-package.yaml + +lvgl: + displays: + - tft_display + - second_display + +<<: !include common.yaml From d3f2434c57034c0cac30c997f80850df59e40028 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 24 Jul 2024 19:45:42 -0500 Subject: [PATCH 2124/2607] Bump aioesphomeapi to 24.6.2 and cryptography to 43.0.0 (#7131) --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0cbe5e7265..3e658de8ad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ async_timeout==4.0.3; python_version <= "3.10" -cryptography==42.0.2 +cryptography==43.0.0 voluptuous==0.14.2 PyYAML==6.0.1 paho-mqtt==1.6.1 @@ -13,7 +13,7 @@ platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240620.0 -aioesphomeapi==24.3.0 +aioesphomeapi==24.6.2 zeroconf==0.132.2 python-magic==0.4.27 ruamel.yaml==0.18.6 # dashboard_import From f61582f82600b26e5747afe5b5f1f5b642a47ee6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:19:33 +1200 Subject: [PATCH 2125/2607] [dependabot] Group docker action bumps into single PR (#7133) --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3b6495653b..bb35f16048 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,6 +13,13 @@ updates: schedule: interval: daily open-pull-requests-limit: 10 + groups: + docker-actions: + applies-to: version-updates + patterns: + - "docker/setup-qemu-action" + - "docker/login-action" + - "docker/setup-buildx-action" - package-ecosystem: github-actions directory: "/.github/actions/build-image" schedule: From 39c0019534f5e6aa67d2e71f69a04d8c3ff28343 Mon Sep 17 00:00:00 2001 From: thevogoncoder <6619878+thevogoncoder@users.noreply.github.com> Date: Thu, 25 Jul 2024 04:06:23 +0200 Subject: [PATCH 2126/2607] Add delay after sending REG_READ_START (#7130) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/pmwcs3/pmwcs3.cpp | 61 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/esphome/components/pmwcs3/pmwcs3.cpp b/esphome/components/pmwcs3/pmwcs3.cpp index 812018b52e..97ce4c9ae0 100644 --- a/esphome/components/pmwcs3/pmwcs3.cpp +++ b/esphome/components/pmwcs3/pmwcs3.cpp @@ -72,43 +72,44 @@ void PMWCS3Component::dump_config() { LOG_SENSOR(" ", "vwc", this->vwc_sensor_); } void PMWCS3Component::read_data_() { - uint8_t data[8]; - float e25, ec, temperature, vwc; - /////// Super important !!!! first activate reading PMWCS3_REG_READ_START (if not, return always the same values) //// - if (!this->write_bytes(PMWCS3_REG_READ_START, nullptr, 0)) { this->status_set_warning(); ESP_LOGVV(TAG, "Failed to write into REG_READ_START register !!!"); return; } - // NOLINT delay(100); - if (!this->read_bytes(PMWCS3_REG_GET_DATA, (uint8_t *) &data, 8)) { - ESP_LOGVV(TAG, "Error reading PMWCS3_REG_GET_DATA registers"); - this->mark_failed(); - return; - } - if (this->e25_sensor_ != nullptr) { - e25 = ((data[1] << 8) | data[0]) / 100.0; - this->e25_sensor_->publish_state(e25); - ESP_LOGVV(TAG, "e25: data[0]=%d, data[1]=%d, result=%f", data[0], data[1], e25); - } - if (this->ec_sensor_ != nullptr) { - ec = ((data[3] << 8) | data[2]) / 10.0; - this->ec_sensor_->publish_state(ec); - ESP_LOGVV(TAG, "ec: data[2]=%d, data[3]=%d, result=%f", data[2], data[3], ec); - } - if (this->temperature_sensor_ != nullptr) { - temperature = ((data[5] << 8) | data[4]) / 100.0; - this->temperature_sensor_->publish_state(temperature); - ESP_LOGVV(TAG, "temp: data[4]=%d, data[5]=%d, result=%f", data[4], data[5], temperature); - } - if (this->vwc_sensor_ != nullptr) { - vwc = ((data[7] << 8) | data[6]) / 10.0; - this->vwc_sensor_->publish_state(vwc); - ESP_LOGVV(TAG, "vwc: data[6]=%d, data[7]=%d, result=%f", data[6], data[7], vwc); - } + // Wait for the sensor to be ready. + // 80ms empirically determined (conservative). + this->set_timeout(80, [this] { + uint8_t data[8]; + float e25, ec, temperature, vwc; + if (!this->read_bytes(PMWCS3_REG_GET_DATA, (uint8_t *) &data, 8)) { + ESP_LOGVV(TAG, "Error reading PMWCS3_REG_GET_DATA registers"); + this->mark_failed(); + return; + } + if (this->e25_sensor_ != nullptr) { + e25 = ((data[1] << 8) | data[0]) / 100.0; + this->e25_sensor_->publish_state(e25); + ESP_LOGVV(TAG, "e25: data[0]=%d, data[1]=%d, result=%f", data[0], data[1], e25); + } + if (this->ec_sensor_ != nullptr) { + ec = ((data[3] << 8) | data[2]) / 10.0; + this->ec_sensor_->publish_state(ec); + ESP_LOGVV(TAG, "ec: data[2]=%d, data[3]=%d, result=%f", data[2], data[3], ec); + } + if (this->temperature_sensor_ != nullptr) { + temperature = ((data[5] << 8) | data[4]) / 100.0; + this->temperature_sensor_->publish_state(temperature); + ESP_LOGVV(TAG, "temp: data[4]=%d, data[5]=%d, result=%f", data[4], data[5], temperature); + } + if (this->vwc_sensor_ != nullptr) { + vwc = ((data[7] << 8) | data[6]) / 10.0; + this->vwc_sensor_->publish_state(vwc); + ESP_LOGVV(TAG, "vwc: data[6]=%d, data[7]=%d, result=%f", data[6], data[7], vwc); + } + }); } } // namespace pmwcs3 From adfec578cfd301ee0295bd1dec6a649ff98fcb8b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:13:09 +1200 Subject: [PATCH 2127/2607] Add ``--version`` handler to cli (#7150) --- esphome/__main__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index b13f96daf7..9e7b7fa15b 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -747,7 +747,14 @@ def parse_args(argv): ) parser = argparse.ArgumentParser( - description=f"ESPHome v{const.__version__}", parents=[options_parser] + description=f"ESPHome {const.__version__}", parents=[options_parser] + ) + + parser.add_argument( + "--version", + action="version", + version=f"Version: {const.__version__}", + help="Print the ESPHome version and exit.", ) mqtt_options = argparse.ArgumentParser(add_help=False) From acf690c87d362b37dc3b8910bcc7ffd4882bc2f2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:05:41 +1200 Subject: [PATCH 2128/2607] [code-quality] Organise ethernet related imports (#7152) --- esphome/components/ethernet/__init__.py | 36 +++++++++---------- .../components/ethernet_info/text_sensor.py | 4 +-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 697436415b..1c6acda724 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -1,6 +1,4 @@ from esphome import pins -import esphome.config_validation as cv -import esphome.final_validate as fv import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant from esphome.components.esp32.const import ( @@ -8,31 +6,33 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, ) +from esphome.components.network import IPAddress +from esphome.components.spi import CONF_INTERFACE_INDEX, get_spi_interface +import esphome.config_validation as cv from esphome.const import ( - CONF_DOMAIN, - CONF_ID, - CONF_VALUE, - CONF_MANUAL_IP, - CONF_STATIC_IP, - CONF_TYPE, - CONF_USE_ADDRESS, - CONF_GATEWAY, - CONF_SUBNET, + CONF_ADDRESS, + CONF_CLK_PIN, + CONF_CS_PIN, CONF_DNS1, CONF_DNS2, - CONF_CLK_PIN, + CONF_DOMAIN, + CONF_GATEWAY, + CONF_ID, + CONF_INTERRUPT_PIN, + CONF_MANUAL_IP, CONF_MISO_PIN, CONF_MOSI_PIN, - CONF_CS_PIN, - CONF_INTERRUPT_PIN, + CONF_PAGE_ID, CONF_RESET_PIN, CONF_SPI, - CONF_PAGE_ID, - CONF_ADDRESS, + CONF_STATIC_IP, + CONF_SUBNET, + CONF_TYPE, + CONF_USE_ADDRESS, + CONF_VALUE, ) from esphome.core import CORE, coroutine_with_priority -from esphome.components.network import IPAddress -from esphome.components.spi import get_spi_interface, CONF_INTERFACE_INDEX +import esphome.final_validate as fv CONFLICTS_WITH = ["wifi"] DEPENDENCIES = ["esp32"] diff --git a/esphome/components/ethernet_info/text_sensor.py b/esphome/components/ethernet_info/text_sensor.py index a545475870..31da516e44 100644 --- a/esphome/components/ethernet_info/text_sensor.py +++ b/esphome/components/ethernet_info/text_sensor.py @@ -1,9 +1,9 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import text_sensor +import esphome.config_validation as cv from esphome.const import ( - CONF_IP_ADDRESS, CONF_DNS_ADDRESS, + CONF_IP_ADDRESS, CONF_MAC_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC, ) From 20c22465335231017b4300827ad3e68ce968bd4f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:06:08 +1200 Subject: [PATCH 2129/2607] [code-quality] Organise wifi related imports (#7153) --- esphome/components/wifi/__init__.py | 31 +++++++++++---------- esphome/components/wifi/wpa2_eap.py | 13 ++++----- esphome/components/wifi_info/text_sensor.py | 6 ++-- esphome/components/wifi_signal/sensor.py | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 624bcdabdc..ea03cc16d1 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -1,15 +1,19 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -import esphome.final_validate as fv from esphome import automation from esphome.automation import Condition +import esphome.codegen as cg +from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant +from esphome.components.network import IPAddress +import esphome.config_validation as cv from esphome.const import ( CONF_AP, CONF_BSSID, + CONF_CERTIFICATE, + CONF_CERTIFICATE_AUTHORITY, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, + CONF_EAP, CONF_ENABLE_BTM, CONF_ENABLE_ON_BOOT, CONF_ENABLE_RRM, @@ -17,29 +21,26 @@ from esphome.const import ( CONF_GATEWAY, CONF_HIDDEN, CONF_ID, + CONF_IDENTITY, + CONF_KEY, CONF_MANUAL_IP, CONF_NETWORKS, + CONF_ON_CONNECT, + CONF_ON_DISCONNECT, CONF_PASSWORD, CONF_POWER_SAVE_MODE, + CONF_PRIORITY, CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, - CONF_USE_ADDRESS, - CONF_PRIORITY, - CONF_IDENTITY, - CONF_CERTIFICATE_AUTHORITY, - CONF_CERTIFICATE, - CONF_KEY, - CONF_USERNAME, - CONF_EAP, CONF_TTLS_PHASE_2, - CONF_ON_CONNECT, - CONF_ON_DISCONNECT, + CONF_USE_ADDRESS, + CONF_USERNAME, ) from esphome.core import CORE, HexInt, coroutine_with_priority -from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const -from esphome.components.network import IPAddress +import esphome.final_validate as fv + from . import wpa2_eap AUTO_LOAD = ["network"] diff --git a/esphome/components/wifi/wpa2_eap.py b/esphome/components/wifi/wpa2_eap.py index 3985dfef18..5d5bd8dca3 100644 --- a/esphome/components/wifi/wpa2_eap.py +++ b/esphome/components/wifi/wpa2_eap.py @@ -7,16 +7,15 @@ so that it doesn't crash if it's not installed. import logging from pathlib import Path -from esphome.core import CORE import esphome.config_validation as cv from esphome.const import ( - CONF_USERNAME, - CONF_IDENTITY, - CONF_PASSWORD, CONF_CERTIFICATE, + CONF_IDENTITY, CONF_KEY, + CONF_PASSWORD, + CONF_USERNAME, ) - +from esphome.core import CORE _LOGGER = logging.getLogger(__name__) @@ -49,8 +48,8 @@ def wrapped_load_pem_x509_certificate(value): def wrapped_load_pem_private_key(value, password): validate_cryptography_installed() - from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.serialization import load_pem_private_key if password: password = password.encode("UTF-8") @@ -91,7 +90,7 @@ def _validate_load_private_key(key, cert_pw): def _check_private_key_cert_match(key, cert): - from cryptography.hazmat.primitives.asymmetric import rsa, ec + from cryptography.hazmat.primitives.asymmetric import ec, rsa def check_match_a(): return key.public_key().public_numbers() == cert.public_key().public_numbers() diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index 75513712dd..4ceb73a695 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -1,13 +1,13 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import text_sensor +import esphome.config_validation as cv from esphome.const import ( CONF_BSSID, + CONF_DNS_ADDRESS, CONF_IP_ADDRESS, + CONF_MAC_ADDRESS, CONF_SCAN_RESULTS, CONF_SSID, - CONF_MAC_ADDRESS, - CONF_DNS_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC, ) diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py index 77fabf272e..99b51adea0 100644 --- a/esphome/components/wifi_signal/sensor.py +++ b/esphome/components/wifi_signal/sensor.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import sensor +import esphome.config_validation as cv from esphome.const import ( DEVICE_CLASS_SIGNAL_STRENGTH, ENTITY_CATEGORY_DIAGNOSTIC, From e64709c37e22148572a182461f98430982e3228f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:07:44 +1200 Subject: [PATCH 2130/2607] [code-quality] Organise core imports (#7149) --- esphome/__main__.py | 12 ++-- esphome/automation.py | 2 +- esphome/codegen.py | 106 ++++++++++++++++---------------- esphome/config.py | 42 ++++++------- esphome/config_validation.py | 42 ++++++------- esphome/core/__init__.py | 19 +++--- esphome/core/config.py | 6 +- esphome/core/entity_helpers.py | 3 +- esphome/coroutine.py | 2 +- esphome/cpp_generator.py | 2 +- esphome/cpp_helpers.py | 8 +-- esphome/dashboard/core.py | 6 +- esphome/dashboard/dashboard.py | 6 +- esphome/dashboard/entries.py | 2 +- esphome/dashboard/util/file.py | 2 +- esphome/dashboard/web_server.py | 6 +- esphome/external_files.py | 10 +-- esphome/final_validate.py | 4 +- esphome/git.py | 10 +-- esphome/helpers.py | 12 ++-- esphome/mqtt.py | 6 +- esphome/pins.py | 12 ++-- esphome/platformio_api.py | 10 +-- esphome/storage_json.py | 3 +- esphome/types.py | 2 +- esphome/util.py | 5 +- esphome/voluptuous_schema.py | 1 + esphome/vscode.py | 9 +-- esphome/wizard.py | 2 +- esphome/writer.py | 16 ++--- esphome/yaml_util.py | 6 +- esphome/zeroconf.py | 2 +- 32 files changed, 190 insertions(+), 186 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 9e7b7fa15b..13f09e15ed 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -1,12 +1,12 @@ # PYTHON_ARGCOMPLETE_OK import argparse +from datetime import datetime import functools import logging import os import re import sys import time -from datetime import datetime import argcomplete @@ -39,14 +39,14 @@ from esphome.const import ( ) from esphome.core import CORE, EsphomeError, coroutine from esphome.helpers import indent, is_ip_address +from esphome.log import Fore, color, setup_log from esphome.util import ( + get_serial_ports, + list_yaml_files, run_external_command, run_external_process, safe_print, - list_yaml_files, - get_serial_ports, ) -from esphome.log import color, setup_log, Fore _LOGGER = logging.getLogger(__name__) @@ -116,6 +116,7 @@ def get_port_type(port): def run_miniterm(config, port): import serial + from esphome import platformio_api if CONF_LOGGER not in config: @@ -596,9 +597,10 @@ def command_update_all(args): def command_idedata(args, config): - from esphome import platformio_api import json + from esphome import platformio_api + logging.disable(logging.INFO) logging.disable(logging.WARNING) diff --git a/esphome/automation.py b/esphome/automation.py index b25ffa5abe..0bd6cf0af0 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -7,10 +7,10 @@ from esphome.const import ( CONF_ELSE, CONF_ID, CONF_THEN, + CONF_TIME, CONF_TIMEOUT, CONF_TRIGGER_ID, CONF_TYPE_ID, - CONF_TIME, CONF_UPDATE_INTERVAL, ) from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor diff --git a/esphome/codegen.py b/esphome/codegen.py index 6b000b53a1..bfa1683ce7 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -8,55 +8,78 @@ # want to break suddenly due to a rename (this file will get backports for features). # pylint: disable=unused-import -from esphome.cpp_generator import ( # noqa +from esphome.cpp_generator import ( # noqa: F401 + ArrayInitializer, Expression, + LineComment, + MockObj, + MockObjClass, + Pvariable, RawExpression, RawStatement, - TemplateArguments, - StructInitializer, - ArrayInitializer, - safe_exp, Statement, - LineComment, - progmem_array, - static_const_array, - statement, - variable, - with_local_variable, - new_variable, - Pvariable, - new_Pvariable, + StructInitializer, + TemplateArguments, add, - add_global, - add_library, add_build_flag, add_define, + add_global, + add_library, add_platformio_option, get_variable, get_variable_with_full_id, - process_lambda, is_template, + new_Pvariable, + new_variable, + process_lambda, + progmem_array, + safe_exp, + statement, + static_const_array, templatable, - MockObj, - MockObjClass, + variable, + with_local_variable, ) -from esphome.cpp_helpers import ( # noqa - gpio_pin_expression, - register_component, +from esphome.cpp_helpers import ( # noqa: F401 build_registry_entry, build_registry_list, extract_registry_entry_config, - register_parented, + gpio_pin_expression, past_safe_mode, + register_component, + register_parented, ) -from esphome.cpp_types import ( # noqa - global_ns, - void, - nullptr, - float_, - double, +from esphome.cpp_types import ( # noqa: F401 + NAN, + App, + Application, + Component, + ComponentPtr, + Controller, + EntityBase, + EntityCategory, + ESPTime, + GPIOPin, + InternalGPIOPin, + JsonObject, + JsonObjectConst, + Parented, + PollingComponent, + arduino_json_ns, bool_, + const_char_ptr, + double, + esphome_ns, + float_, + global_ns, + gpio_Flags, + int16, + int32, + int64, int_, + nullptr, + optional, + size_t, std_ns, std_shared_ptr, std_string, @@ -66,28 +89,5 @@ from esphome.cpp_types import ( # noqa uint16, uint32, uint64, - int16, - int32, - int64, - size_t, - const_char_ptr, - NAN, - esphome_ns, - App, - EntityBase, - Component, - ComponentPtr, - PollingComponent, - Application, - optional, - arduino_json_ns, - JsonObject, - JsonObjectConst, - Controller, - GPIOPin, - InternalGPIOPin, - gpio_Flags, - EntityCategory, - Parented, - ESPTime, + void, ) diff --git a/esphome/config.py b/esphome/config.py index 925a31fed0..a2d0d15477 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -1,40 +1,38 @@ from __future__ import annotations + import abc +from contextlib import contextmanager +import contextvars import functools import heapq import logging import re - -from typing import Union, Any - -from contextlib import contextmanager -import contextvars +from typing import Any, Union import voluptuous as vol -from esphome import core, yaml_util, loader, pins -import esphome.core.config as core_config +from esphome import core, loader, pins, yaml_util +from esphome.config_helpers import Extend, Remove +import esphome.config_validation as cv from esphome.const import ( CONF_ESPHOME, - CONF_ID, - CONF_PLATFORM, - CONF_PACKAGES, - CONF_SUBSTITUTIONS, CONF_EXTERNAL_COMPONENTS, + CONF_ID, + CONF_PACKAGES, + CONF_PLATFORM, + CONF_SUBSTITUTIONS, TARGET_PLATFORMS, ) -from esphome.core import CORE, EsphomeError, DocumentRange -from esphome.helpers import indent -from esphome.util import safe_print, OrderedDict - -from esphome.config_helpers import Extend, Remove -from esphome.loader import get_component, get_platform, ComponentManifest -from esphome.yaml_util import is_secret, ESPHomeDataBase, ESPForceValue -from esphome.voluptuous_schema import ExtraKeysInvalid -from esphome.log import color, Fore +from esphome.core import CORE, DocumentRange, EsphomeError +import esphome.core.config as core_config import esphome.final_validate as fv -import esphome.config_validation as cv -from esphome.types import ConfigType, ConfigFragmentType +from esphome.helpers import indent +from esphome.loader import ComponentManifest, get_component, get_platform +from esphome.log import Fore, color +from esphome.types import ConfigFragmentType, ConfigType +from esphome.util import OrderedDict, safe_print +from esphome.voluptuous_schema import ExtraKeysInvalid +from esphome.yaml_util import ESPForceValue, ESPHomeDataBase, is_secret _LOGGER = logging.getLogger(__name__) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 3ef92ad460..1cd1d6aa31 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1,13 +1,13 @@ """Helpers for config validation using voluptuous.""" +from contextlib import contextmanager from dataclasses import dataclass +from datetime import datetime import logging import os import re -from contextlib import contextmanager -import uuid as uuid_ -from datetime import datetime from string import ascii_letters, digits +import uuid as uuid_ import voluptuous as vol @@ -17,37 +17,37 @@ from esphome.config_helpers import Extend, Remove from esphome.const import ( ALLOWED_NAME_CHARS, CONF_AVAILABILITY, - CONF_COMMAND_TOPIC, CONF_COMMAND_RETAIN, + CONF_COMMAND_TOPIC, + CONF_DAY, CONF_DISABLED_BY_DEFAULT, CONF_DISCOVERY, CONF_ENTITY_CATEGORY, + CONF_HOUR, CONF_ICON, CONF_ID, CONF_INTERNAL, + CONF_MINUTE, + CONF_MONTH, CONF_NAME, + CONF_PASSWORD, + CONF_PATH, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, - CONF_RETAIN, CONF_QOS, + CONF_REF, + CONF_RETAIN, + CONF_SECOND, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, - CONF_YEAR, - CONF_MONTH, - CONF_DAY, - CONF_HOUR, - CONF_MINUTE, - CONF_SECOND, - CONF_VALUE, - CONF_UPDATE_INTERVAL, - CONF_TYPE_ID, CONF_TYPE, - CONF_REF, + CONF_TYPE_ID, + CONF_UPDATE_INTERVAL, CONF_URL, - CONF_PATH, CONF_USERNAME, - CONF_PASSWORD, + CONF_VALUE, + CONF_YEAR, ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_NONE, @@ -71,15 +71,15 @@ from esphome.core import ( TimePeriod, TimePeriodMicroseconds, TimePeriodMilliseconds, + TimePeriodMinutes, TimePeriodNanoseconds, TimePeriodSeconds, - TimePeriodMinutes, ) -from esphome.helpers import list_starts_with, add_class_to_obj +from esphome.helpers import add_class_to_obj, list_starts_with from esphome.schema_extractors import ( SCHEMA_EXTRACT, - schema_extractor_list, schema_extractor, + schema_extractor_list, schema_extractor_registry, schema_extractor_typed, ) @@ -1686,9 +1686,9 @@ class SplitDefault(Optional): if CORE.is_esp32: from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( + VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3, - VARIANT_ESP32C3, ) variant = get_esp32_variant() diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index f25891965a..9d3d14492e 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -7,26 +7,29 @@ from typing import TYPE_CHECKING, Optional, Union from esphome.const import ( CONF_COMMENT, CONF_ESPHOME, - CONF_USE_ADDRESS, CONF_ETHERNET, + CONF_PORT, + CONF_USE_ADDRESS, CONF_WEB_SERVER, CONF_WIFI, - CONF_PORT, KEY_CORE, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, - PLATFORM_BK72XX, - PLATFORM_RTL87XX, - PLATFORM_RP2040, PLATFORM_HOST, + PLATFORM_RP2040, + PLATFORM_RTL87XX, ) -from esphome.coroutine import FakeAwaitable as _FakeAwaitable -from esphome.coroutine import FakeEventLoop as _FakeEventLoop # pylint: disable=unused-import -from esphome.coroutine import coroutine, coroutine_with_priority # noqa +from esphome.coroutine import ( # noqa: F401 + FakeAwaitable as _FakeAwaitable, + FakeEventLoop as _FakeEventLoop, + coroutine, + coroutine_with_priority, +) from esphome.helpers import ensure_unique_string, get_str_env, is_ha_addon from esphome.util import OrderedDict diff --git a/esphome/core/config.py b/esphome/core/config.py index 80b731b905..739a8a1aea 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -3,9 +3,9 @@ import multiprocessing import os import re +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome import automation from esphome.const import ( CONF_ARDUINO_VERSION, CONF_AREA, @@ -16,11 +16,11 @@ from esphome.const import ( CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, CONF_FRAMEWORK, + CONF_FRIENDLY_NAME, CONF_INCLUDES, CONF_LIBRARIES, CONF_MIN_VERSION, CONF_NAME, - CONF_FRIENDLY_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, @@ -34,8 +34,8 @@ from esphome.const import ( CONF_TYPE, CONF_VERSION, KEY_CORE, - TARGET_PLATFORMS, PLATFORM_ESP8266, + TARGET_PLATFORMS, __version__ as ESPHOME_VERSION, ) from esphome.core import CORE, coroutine_with_priority diff --git a/esphome/core/entity_helpers.py b/esphome/core/entity_helpers.py index f921711ec2..7f6a9b48ab 100644 --- a/esphome/core/entity_helpers.py +++ b/esphome/core/entity_helpers.py @@ -1,6 +1,5 @@ -import esphome.final_validate as fv - from esphome.const import CONF_ID +import esphome.final_validate as fv def inherit_property_from(property_to_inherit, parent_id_property, transform=None): diff --git a/esphome/coroutine.py b/esphome/coroutine.py index 5f391dc7ad..30ebb8147e 100644 --- a/esphome/coroutine.py +++ b/esphome/coroutine.py @@ -43,13 +43,13 @@ the last `yield` expression defines what is returned. """ import collections +from collections.abc import Awaitable, Generator, Iterator import functools import heapq import inspect import logging import types from typing import Any, Callable -from collections.abc import Awaitable, Generator, Iterator _LOGGER = logging.getLogger(__name__) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 9a4cb2269a..7a82d5cba1 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -1,8 +1,8 @@ import abc +from collections.abc import Sequence import inspect import math import re -from collections.abc import Sequence from typing import Any, Callable, Optional, Union from esphome.core import ( diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index 825224bb9d..9a775bad33 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -12,15 +12,13 @@ from esphome.const import ( CONF_UPDATE_INTERVAL, KEY_PAST_SAFE_MODE, ) - -from esphome.core import coroutine, ID, CORE +from esphome.core import CORE, ID, coroutine from esphome.coroutine import FakeAwaitable -from esphome.types import ConfigType, ConfigFragmentType from esphome.cpp_generator import add, get_variable from esphome.cpp_types import App +from esphome.helpers import sanitize, snake_case +from esphome.types import ConfigFragmentType, ConfigType from esphome.util import Registry, RegistryEntry -from esphome.helpers import snake_case, sanitize - _LOGGER = logging.getLogger(__name__) diff --git a/esphome/dashboard/core.py b/esphome/dashboard/core.py index 875ff6b91f..eec0777da6 100644 --- a/esphome/dashboard/core.py +++ b/esphome/dashboard/core.py @@ -1,13 +1,13 @@ from __future__ import annotations import asyncio +from collections.abc import Coroutine import contextlib -import logging -import threading from dataclasses import dataclass from functools import partial +import logging +import threading from typing import TYPE_CHECKING, Any, Callable -from collections.abc import Coroutine from ..zeroconf import DiscoveredImport from .dns import DNSCache diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 2be98ab3e4..9de2d39ce2 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -1,14 +1,14 @@ from __future__ import annotations import asyncio +from asyncio import events +from concurrent.futures import ThreadPoolExecutor import logging import os import socket import threading -import traceback -from asyncio import events -from concurrent.futures import ThreadPoolExecutor from time import monotonic +import traceback from typing import Any from esphome.storage_json import EsphomeStorageJSON, esphome_storage_path diff --git a/esphome/dashboard/entries.py b/esphome/dashboard/entries.py index 7a9bff4ec1..cb0d4a3772 100644 --- a/esphome/dashboard/entries.py +++ b/esphome/dashboard/entries.py @@ -1,9 +1,9 @@ from __future__ import annotations import asyncio +from collections import defaultdict import logging import os -from collections import defaultdict from typing import TYPE_CHECKING, Any from esphome import const, util diff --git a/esphome/dashboard/util/file.py b/esphome/dashboard/util/file.py index 661d5f34cf..bb263f9ad7 100644 --- a/esphome/dashboard/util/file.py +++ b/esphome/dashboard/util/file.py @@ -1,7 +1,7 @@ import logging import os -import tempfile from pathlib import Path +import tempfile _LOGGER = logging.getLogger(__name__) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 33c83ffb1a..e4b7b8d342 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -2,6 +2,7 @@ from __future__ import annotations import asyncio import base64 +from collections.abc import Iterable import datetime import functools import gzip @@ -9,13 +10,12 @@ import hashlib import json import logging import os +from pathlib import Path import secrets import shutil import subprocess import threading import time -from collections.abc import Iterable -from pathlib import Path from typing import TYPE_CHECKING, Any, Callable, TypeVar from urllib.parse import urlparse @@ -26,13 +26,13 @@ import tornado.httpserver import tornado.httputil import tornado.ioloop import tornado.iostream +from tornado.log import access_log import tornado.netutil import tornado.process import tornado.queues import tornado.web import tornado.websocket import yaml -from tornado.log import access_log from yaml.nodes import Node from esphome import const, platformio_api, yaml_util diff --git a/esphome/external_files.py b/esphome/external_files.py index f8eb1dcabe..baf62286e4 100644 --- a/esphome/external_files.py +++ b/esphome/external_files.py @@ -1,13 +1,15 @@ from __future__ import annotations -import logging -from pathlib import Path -import os from datetime import datetime +import logging +import os +from pathlib import Path + import requests + import esphome.config_validation as cv -from esphome.core import CORE, TimePeriodSeconds from esphome.const import __version__ +from esphome.core import CORE, TimePeriodSeconds _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@landonr"] diff --git a/esphome/final_validate.py b/esphome/final_validate.py index 5e9d2207b0..cebd2f1cda 100644 --- a/esphome/final_validate.py +++ b/esphome/final_validate.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod -from typing import Any import contextvars +from typing import Any -from esphome.types import ConfigFragmentType, ID, ConfigPathType import esphome.config_validation as cv +from esphome.types import ID, ConfigFragmentType, ConfigPathType class FinalValidateConfig(ABC): diff --git a/esphome/git.py b/esphome/git.py index e41777f425..144c160b20 100644 --- a/esphome/git.py +++ b/esphome/git.py @@ -1,12 +1,12 @@ -import hashlib -import logging -import re -import subprocess -import urllib.parse from dataclasses import dataclass from datetime import datetime +import hashlib +import logging from pathlib import Path +import re +import subprocess from typing import Callable, Optional +import urllib.parse import esphome.config_validation as cv from esphome.core import CORE, TimePeriodSeconds diff --git a/esphome/helpers.py b/esphome/helpers.py index 4c8cb4e2cc..2a7e5cd9b6 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -1,14 +1,13 @@ import codecs from contextlib import suppress - import logging import os -import platform from pathlib import Path -from typing import Union -import tempfile -from urllib.parse import urlparse +import platform import re +import tempfile +from typing import Union +from urllib.parse import urlparse _LOGGER = logging.getLogger(__name__) @@ -129,9 +128,10 @@ def _resolve_with_zeroconf(host): def resolve_ip_address(host): - from esphome.core import EsphomeError import socket + from esphome.core import EsphomeError + errs = [] if host.endswith(".local"): diff --git a/esphome/mqtt.py b/esphome/mqtt.py index 667a20bcf8..d7e14a1d08 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -1,10 +1,10 @@ from datetime import datetime import hashlib +import json import logging import ssl import sys import time -import json import paho.mqtt.client as mqtt @@ -24,9 +24,9 @@ from esphome.const import ( CONF_USERNAME, ) from esphome.core import CORE, EsphomeError -from esphome.log import color, Fore +from esphome.helpers import get_int_env, get_str_env +from esphome.log import Fore, color from esphome.util import safe_print -from esphome.helpers import get_str_env, get_int_env _LOGGER = logging.getLogger(__name__) diff --git a/esphome/pins.py b/esphome/pins.py index 5ccb696738..724cd25d82 100644 --- a/esphome/pins.py +++ b/esphome/pins.py @@ -1,20 +1,20 @@ -import operator from functools import reduce -import esphome.config_validation as cv -from esphome.core import CORE +import operator +import esphome.config_validation as cv from esphome.const import ( + CONF_ALLOW_OTHER_USES, + CONF_IGNORE_STRAPPING_WARNING, CONF_INPUT, + CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_OPEN_DRAIN, CONF_OUTPUT, CONF_PULLDOWN, CONF_PULLUP, - CONF_IGNORE_STRAPPING_WARNING, - CONF_ALLOW_OTHER_USES, - CONF_INVERTED, ) +from esphome.core import CORE class PinRegistry(dict): diff --git a/esphome/platformio_api.py b/esphome/platformio_api.py index c46a3fc767..b81ec4ab37 100644 --- a/esphome/platformio_api.py +++ b/esphome/platformio_api.py @@ -1,12 +1,11 @@ from dataclasses import dataclass import json -from typing import Union -from pathlib import Path - import logging import os +from pathlib import Path import re import subprocess +from typing import Union from esphome.const import CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, KEY_CORE from esphome.core import CORE, EsphomeError @@ -20,9 +19,10 @@ def patch_structhash(): # removed/added. This might have unintended consequences, but this improves compile # times greatly when adding/removing components and a simple clean build solves # all issues - from platformio.run import helpers, cli - from os.path import join, isdir, getmtime from os import makedirs + from os.path import getmtime, isdir, join + + from platformio.run import cli, helpers def patched_clean_build_dir(build_dir, *args): from platformio import fs diff --git a/esphome/storage_json.py b/esphome/storage_json.py index 0a41a4f738..e2e7514904 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -1,10 +1,11 @@ from __future__ import annotations + import binascii import codecs +from datetime import datetime import json import logging import os -from datetime import datetime from esphome import const from esphome.const import CONF_DISABLED, CONF_MDNS diff --git a/esphome/types.py b/esphome/types.py index 27ec61ceff..4e69e3cbd7 100644 --- a/esphome/types.py +++ b/esphome/types.py @@ -2,7 +2,7 @@ from typing import Union -from esphome.core import ID, Lambda, EsphomeCore +from esphome.core import ID, EsphomeCore, Lambda ConfigFragmentType = Union[ str, diff --git a/esphome/util.py b/esphome/util.py index d5a4c60570..32fd90cd25 100644 --- a/esphome/util.py +++ b/esphome/util.py @@ -1,13 +1,12 @@ -from typing import Union - import collections import io import logging import os +from pathlib import Path import re import subprocess import sys -from pathlib import Path +from typing import Union from esphome import const diff --git a/esphome/voluptuous_schema.py b/esphome/voluptuous_schema.py index 9af6cb717c..7f1573b443 100644 --- a/esphome/voluptuous_schema.py +++ b/esphome/voluptuous_schema.py @@ -2,6 +2,7 @@ import difflib import itertools import voluptuous as vol + from esphome.schema_extractors import schema_extractor_extended diff --git a/esphome/vscode.py b/esphome/vscode.py index 8198d2659a..907ed88216 100644 --- a/esphome/vscode.py +++ b/esphome/vscode.py @@ -1,13 +1,14 @@ from __future__ import annotations + +from io import StringIO import json import os -from io import StringIO from typing import Any -from esphome.yaml_util import parse_yaml -from esphome.config import validate_config, _format_vol_invalid, Config -from esphome.core import CORE, DocumentRange +from esphome.config import Config, _format_vol_invalid, validate_config import esphome.config_validation as cv +from esphome.core import CORE, DocumentRange +from esphome.yaml_util import parse_yaml def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None: diff --git a/esphome/wizard.py b/esphome/wizard.py index f8911ae844..319fb31938 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -276,8 +276,8 @@ def wizard(path): from esphome.components.bk72xx import boards as bk72xx_boards from esphome.components.esp32 import boards as esp32_boards from esphome.components.esp8266 import boards as esp8266_boards - from esphome.components.rtl87xx import boards as rtl87xx_boards from esphome.components.rp2040 import boards as rp2040_boards + from esphome.components.rtl87xx import boards as rtl87xx_boards if not path.endswith(".yaml") and not path.endswith(".yml"): safe_print( diff --git a/esphome/writer.py b/esphome/writer.py index 3ad0e60d31..c6111cbe3f 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -1,27 +1,27 @@ import logging import os -import re from pathlib import Path +import re from typing import Union -from esphome.config import iter_components, iter_component_configs +from esphome import loader +from esphome.config import iter_component_configs, iter_components from esphome.const import ( + ENV_NOGITIGNORE, HEADER_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS, __version__, - ENV_NOGITIGNORE, ) from esphome.core import CORE, EsphomeError from esphome.helpers import ( - mkdir_p, - read_file, - write_file_if_changed, - walk_files, copy_file_if_changed, get_bool_env, + mkdir_p, + read_file, + walk_files, + write_file_if_changed, ) from esphome.storage_json import StorageJSON, storage_path -from esphome import loader _LOGGER = logging.getLogger(__name__) diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index 06bfd8b217..d67511dfec 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -3,16 +3,16 @@ from __future__ import annotations import fnmatch import functools import inspect +from io import TextIOWrapper import logging import math import os -import uuid -from io import TextIOWrapper from typing import Any +import uuid import yaml -import yaml.constructor from yaml import SafeLoader as PurePythonLoader +import yaml.constructor try: from yaml import CSafeLoader as FastestAvailableSafeLoader diff --git a/esphome/zeroconf.py b/esphome/zeroconf.py index b67ea41323..b3ee64e259 100644 --- a/esphome/zeroconf.py +++ b/esphome/zeroconf.py @@ -1,8 +1,8 @@ from __future__ import annotations import asyncio -import logging from dataclasses import dataclass +import logging from typing import Callable from zeroconf import IPVersion, ServiceInfo, ServiceStateChange, Zeroconf From b3728697cc3997899bd7cb20fdeb9d8f3b1f06ae Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:13:57 +1200 Subject: [PATCH 2131/2607] Remove deprecated argument parser (#7151) * Remove deprecated argument parser * Add back removed argcomplete line --- esphome/__main__.py | 68 --------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 13f09e15ed..7237a04717 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -957,67 +957,6 @@ def parse_args(argv): # a deprecation warning). arguments = argv[1:] - # On Python 3.9+ we can simply set exit_on_error=False in the constructor - def _raise(x): - raise argparse.ArgumentError(None, x) - - # First, try new-style parsing, but don't exit in case of failure - try: - # duplicate parser so that we can use the original one to raise errors later on - current_parser = argparse.ArgumentParser(add_help=False, parents=[parser]) - current_parser.set_defaults(deprecated_argv_suggestion=None) - current_parser.error = _raise - return current_parser.parse_args(arguments) - except argparse.ArgumentError: - pass - - # Second, try compat parsing and rearrange the command-line if it succeeds - # Disable argparse's built-in help option and add it manually to prevent this - # parser from printing the help messagefor the old format when invoked with -h. - compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False) - compat_parser.add_argument("-h", "--help", action="store_true") - compat_parser.add_argument("configuration", nargs="*") - compat_parser.add_argument( - "command", - choices=[ - "config", - "compile", - "upload", - "logs", - "run", - "clean-mqtt", - "wizard", - "mqtt-fingerprint", - "version", - "clean", - "dashboard", - "vscode", - "update-all", - ], - ) - - try: - compat_parser.error = _raise - result, unparsed = compat_parser.parse_known_args(argv[1:]) - last_option = len(arguments) - len(unparsed) - 1 - len(result.configuration) - unparsed = [ - "--device" if arg in ("--upload-port", "--serial-port") else arg - for arg in unparsed - ] - arguments = ( - arguments[0:last_option] - + [result.command] - + result.configuration - + unparsed - ) - deprecated_argv_suggestion = arguments - except argparse.ArgumentError: - # old-style parsing failed, don't suggest any argument - deprecated_argv_suggestion = None - - # Finally, run the new-style parser again with the possibly swapped arguments, - # and let it error out if the command is unparsable. - parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion) argcomplete.autocomplete(parser) return parser.parse_args(arguments) @@ -1032,13 +971,6 @@ def run_esphome(argv): # Show timestamp for dashboard access logs args.command == "dashboard", ) - if args.deprecated_argv_suggestion is not None and args.command != "vscode": - _LOGGER.warning( - "Calling ESPHome with the configuration before the command is deprecated " - "and will be removed in the future. " - ) - _LOGGER.warning("Please instead use:") - _LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion)) if sys.version_info < (3, 8, 0): _LOGGER.error( From 24515546fd25a265dbb704890a6d7c9285775b17 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:22:30 +1200 Subject: [PATCH 2132/2607] Move ``CONF_ON_ERROR`` to const.py (#7156) --- esphome/components/ota/__init__.py | 12 ++++++--- .../components/voice_assistant/__init__.py | 27 +++++++++---------- esphome/const.py | 1 + 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 4e447bfb2d..d9917a2aae 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -1,10 +1,15 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome import automation +from esphome.const import ( + CONF_ESPHOME, + CONF_ON_ERROR, + CONF_OTA, + CONF_PLATFORM, + CONF_TRIGGER_ID, +) from esphome.core import CORE, coroutine_with_priority -from esphome.const import CONF_ESPHOME, CONF_OTA, CONF_PLATFORM, CONF_TRIGGER_ID - CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["md5", "safe_mode"] @@ -13,7 +18,6 @@ IS_PLATFORM_COMPONENT = True CONF_ON_ABORT = "on_abort" CONF_ON_BEGIN = "on_begin" CONF_ON_END = "on_end" -CONF_ON_ERROR = "on_error" CONF_ON_PROGRESS = "on_progress" CONF_ON_STATE_CHANGE = "on_state_change" diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index c18f0a6850..031edbf27a 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -1,18 +1,18 @@ -import esphome.config_validation as cv -import esphome.codegen as cg - -from esphome.const import ( - CONF_ID, - CONF_MICROPHONE, - CONF_SPEAKER, - CONF_MEDIA_PLAYER, - CONF_ON_CLIENT_CONNECTED, - CONF_ON_CLIENT_DISCONNECTED, - CONF_ON_IDLE, -) from esphome import automation from esphome.automation import register_action, register_condition -from esphome.components import microphone, speaker, media_player +import esphome.codegen as cg +from esphome.components import media_player, microphone, speaker +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_MEDIA_PLAYER, + CONF_MICROPHONE, + CONF_ON_CLIENT_CONNECTED, + CONF_ON_CLIENT_DISCONNECTED, + CONF_ON_ERROR, + CONF_ON_IDLE, + CONF_SPEAKER, +) AUTO_LOAD = ["socket"] DEPENDENCIES = ["api", "microphone"] @@ -20,7 +20,6 @@ DEPENDENCIES = ["api", "microphone"] CODEOWNERS = ["@jesserockz"] CONF_ON_END = "on_end" -CONF_ON_ERROR = "on_error" CONF_ON_INTENT_END = "on_intent_end" CONF_ON_INTENT_START = "on_intent_start" CONF_ON_LISTENING = "on_listening" diff --git a/esphome/const.py b/esphome/const.py index faf6ce19fa..4357963384 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -539,6 +539,7 @@ CONF_ON_DOUBLE_CLICK = "on_double_click" CONF_ON_ENROLLMENT_DONE = "on_enrollment_done" CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed" CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan" +CONF_ON_ERROR = "on_error" CONF_ON_EVENT = "on_event" CONF_ON_FINGER_SCAN_INVALID = "on_finger_scan_invalid" CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched" From 5b6b7c0d15098f7477bae68329fe76a1d8993cf5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:25:53 +1200 Subject: [PATCH 2133/2607] [code-quality] Organise esp32 imports (#7154) --- esphome/components/esp32/__init__.py | 19 ++++++++--------- esphome/components/esp32/boards.py | 2 +- esphome/components/esp32/gpio.py | 25 +++++++++++------------ esphome/components/esp32/gpio_esp32.py | 3 +-- esphome/components/esp32/gpio_esp32_c2.py | 3 +-- esphome/components/esp32/gpio_esp32_c3.py | 6 +----- esphome/components/esp32/gpio_esp32_c6.py | 3 +-- esphome/components/esp32/gpio_esp32_h2.py | 3 +-- esphome/components/esp32/gpio_esp32_s2.py | 3 +-- esphome/components/esp32/gpio_esp32_s3.py | 7 +------ 10 files changed, 29 insertions(+), 45 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 1effea708f..0a5dd46478 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1,11 +1,12 @@ from dataclasses import dataclass -from typing import Union, Optional -from pathlib import Path import logging import os -import esphome.final_validate as fv +from pathlib import Path +from typing import Optional, Union -from esphome.helpers import copy_file_if_changed, write_file_if_changed, mkdir_p +from esphome import git +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_ADVANCED, CONF_BOARD, @@ -15,6 +16,7 @@ from esphome.const import ( CONF_IGNORE_EFUSE_MAC_CRC, CONF_NAME, CONF_PATH, + CONF_PLATFORM_VERSION, CONF_PLATFORMIO_OPTIONS, CONF_REF, CONF_REFRESH, @@ -32,13 +34,12 @@ from esphome.const import ( TYPE_GIT, TYPE_LOCAL, __version__, - CONF_PLATFORM_VERSION, ) from esphome.core import CORE, HexInt, TimePeriod -import esphome.config_validation as cv -import esphome.codegen as cg -from esphome import git +import esphome.final_validate as fv +from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed +from .boards import BOARDS from .const import ( # noqa KEY_BOARD, KEY_COMPONENTS, @@ -54,12 +55,10 @@ from .const import ( # noqa VARIANT_FRIENDLY, VARIANTS, ) -from .boards import BOARDS # force import gpio to register pin schema from .gpio import esp32_pin_to_code # noqa - _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["preferences"] diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index cd85f3da97..60abcd447c 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -1,4 +1,4 @@ -from .const import VARIANT_ESP32, VARIANT_ESP32S2, VARIANT_ESP32C3, VARIANT_ESP32S3 +from .const import VARIANT_ESP32, VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3 ESP32_BASE_PINS = { "TX": 1, diff --git a/esphome/components/esp32/gpio.py b/esphome/components/esp32/gpio.py index 0d9cb5daf0..558ff51af8 100644 --- a/esphome/components/esp32/gpio.py +++ b/esphome/components/esp32/gpio.py @@ -1,22 +1,22 @@ from dataclasses import dataclass -from typing import Any import logging +from typing import Any +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_ID, + CONF_IGNORE_PIN_VALIDATION_ERROR, + CONF_IGNORE_STRAPPING_WARNING, CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_OPEN_DRAIN, CONF_OUTPUT, - CONF_IGNORE_PIN_VALIDATION_ERROR, - CONF_IGNORE_STRAPPING_WARNING, PLATFORM_ESP32, ) -from esphome import pins from esphome.core import CORE -import esphome.config_validation as cv -import esphome.codegen as cg from . import boards from .const import ( @@ -24,22 +24,21 @@ from .const import ( KEY_ESP32, KEY_VARIANT, VARIANT_ESP32, - VARIANT_ESP32C3, - VARIANT_ESP32S2, - VARIANT_ESP32S3, VARIANT_ESP32C2, + VARIANT_ESP32C3, VARIANT_ESP32C6, VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, esp32_ns, ) - from .gpio_esp32 import esp32_validate_gpio_pin, esp32_validate_supports -from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports -from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports -from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports from .gpio_esp32_c2 import esp32_c2_validate_gpio_pin, esp32_c2_validate_supports +from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports from .gpio_esp32_c6 import esp32_c6_validate_gpio_pin, esp32_c6_validate_supports from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports +from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports +from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin) diff --git a/esphome/components/esp32/gpio_esp32.py b/esphome/components/esp32/gpio_esp32.py index d10b266c7a..e4d3b6aaf3 100644 --- a/esphome/components/esp32/gpio_esp32.py +++ b/esphome/components/esp32/gpio_esp32.py @@ -1,5 +1,6 @@ import logging +import esphome.config_validation as cv from esphome.const import ( CONF_INPUT, CONF_MODE, @@ -8,10 +9,8 @@ from esphome.const import ( CONF_PULLDOWN, CONF_PULLUP, ) -import esphome.config_validation as cv from esphome.pins import check_strapping_pin - _ESP_SDIO_PINS = { 6: "Flash Clock", 7: "Flash Data 0", diff --git a/esphome/components/esp32/gpio_esp32_c2.py b/esphome/components/esp32/gpio_esp32_c2.py index 0bee7d82bf..abdcb1b655 100644 --- a/esphome/components/esp32/gpio_esp32_c2.py +++ b/esphome/components/esp32/gpio_esp32_c2.py @@ -1,10 +1,9 @@ import logging +import esphome.config_validation as cv from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.pins import check_strapping_pin -import esphome.config_validation as cv - _ESP32C2_STRAPPING_PINS = {8, 9} _LOGGER = logging.getLogger(__name__) diff --git a/esphome/components/esp32/gpio_esp32_c3.py b/esphome/components/esp32/gpio_esp32_c3.py index 6c70c09f9e..5b9ec0ebd9 100644 --- a/esphome/components/esp32/gpio_esp32_c3.py +++ b/esphome/components/esp32/gpio_esp32_c3.py @@ -1,11 +1,7 @@ import logging -from esphome.const import ( - CONF_INPUT, - CONF_MODE, - CONF_NUMBER, -) import esphome.config_validation as cv +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.pins import check_strapping_pin _ESP32C3_SPI_PSRAM_PINS = { diff --git a/esphome/components/esp32/gpio_esp32_c6.py b/esphome/components/esp32/gpio_esp32_c6.py index a1f777c625..bc735f85c4 100644 --- a/esphome/components/esp32/gpio_esp32_c6.py +++ b/esphome/components/esp32/gpio_esp32_c6.py @@ -1,8 +1,7 @@ import logging -from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER - import esphome.config_validation as cv +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.pins import check_strapping_pin _ESP32C6_SPI_PSRAM_PINS = { diff --git a/esphome/components/esp32/gpio_esp32_h2.py b/esphome/components/esp32/gpio_esp32_h2.py index d18ee8a2a6..7413bf4db5 100644 --- a/esphome/components/esp32/gpio_esp32_h2.py +++ b/esphome/components/esp32/gpio_esp32_h2.py @@ -1,8 +1,7 @@ import logging -from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER - import esphome.config_validation as cv +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER _ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21} diff --git a/esphome/components/esp32/gpio_esp32_s2.py b/esphome/components/esp32/gpio_esp32_s2.py index 82449532ec..331aeb9d94 100644 --- a/esphome/components/esp32/gpio_esp32_s2.py +++ b/esphome/components/esp32/gpio_esp32_s2.py @@ -1,5 +1,6 @@ import logging +import esphome.config_validation as cv from esphome.const import ( CONF_INPUT, CONF_MODE, @@ -8,8 +9,6 @@ from esphome.const import ( CONF_PULLDOWN, CONF_PULLUP, ) - -import esphome.config_validation as cv from esphome.pins import check_strapping_pin _ESP32S2_SPI_PSRAM_PINS = { diff --git a/esphome/components/esp32/gpio_esp32_s3.py b/esphome/components/esp32/gpio_esp32_s3.py index 8dcbf8c7bb..7120504693 100644 --- a/esphome/components/esp32/gpio_esp32_s3.py +++ b/esphome/components/esp32/gpio_esp32_s3.py @@ -1,12 +1,7 @@ import logging -from esphome.const import ( - CONF_INPUT, - CONF_MODE, - CONF_NUMBER, -) - import esphome.config_validation as cv +from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.pins import check_strapping_pin _ESP_32S3_SPI_PSRAM_PINS = { From 341fc659589a592fef60321227209f1014ccf34e Mon Sep 17 00:00:00 2001 From: FreeBear-nc <67865163+FreeBear-nc@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:05:25 +0100 Subject: [PATCH 2134/2607] Add microAmp and milliAmp to defined units (#7157) --- esphome/const.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/const.py b/esphome/const.py index 4357963384..37844e1047 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1033,11 +1033,13 @@ UNIT_KILOWATT_HOURS = "kWh" UNIT_LUX = "lx" UNIT_METER = "m" UNIT_METER_PER_SECOND_SQUARED = "m/s²" +UNIT_MICROAMP = "µA" UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³" UNIT_MICROMETER = "µm" UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" UNIT_MICROTESLA = "µT" +UNIT_MILLIAMP = "mA" UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" UNIT_MILLIMETER = "mm" UNIT_MILLISECOND = "ms" From 25c8676d80cb9a6b75cd6413aa4f9a99f3a662e5 Mon Sep 17 00:00:00 2001 From: RubyBailey <60991881+RubyBailey@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:20:29 -0700 Subject: [PATCH 2135/2607] Fix for Mitsubishi units that only support cooling (#7143) --- esphome/components/mitsubishi/mitsubishi.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index a02aabf14d..449c8fc712 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -110,7 +110,7 @@ void MitsubishiClimate::transmit_state() { // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00 // Byte 16: Constant 0x00 // Byte 17: Checksum: SUM[Byte0...Byte16] - uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x00, + uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; switch (this->mode) { @@ -136,6 +136,12 @@ void MitsubishiClimate::transmit_state() { break; case climate::CLIMATE_MODE_OFF: default: + remote_state[6] = MITSUBISHI_MODE_COOL; + remote_state[8] = MITSUBISHI_MODE_A_COOL; + if (this->supports_heat_) { + remote_state[6] = MITSUBISHI_MODE_HEAT; + remote_state[8] = MITSUBISHI_MODE_A_HEAT; + } remote_state[5] = MITSUBISHI_OFF; break; } From 12e840ee88705b063817e48c7f8a15f817103ad5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:36:09 +1200 Subject: [PATCH 2136/2607] Bump docker/setup-buildx-action from 3.5.0 to 3.6.1 in the docker-actions group (#7159) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 2b4539105b..91c02b0a17 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.5.0 + uses: docker/setup-buildx-action@v3.6.1 - name: Set up QEMU uses: docker/setup-qemu-action@v3.2.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efec556059..d454076c84 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,7 +90,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.5.0 + uses: docker/setup-buildx-action@v3.6.1 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.2.0 @@ -184,7 +184,7 @@ jobs: merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.5.0 + uses: docker/setup-buildx-action@v3.6.1 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From 7c1aa771aaa9c9ea2f2c42a0b981ef8267a9d664 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:41:34 +1000 Subject: [PATCH 2137/2607] LVGL stage 2 (#7129) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/lvgl/__init__.py | 38 +++++--- esphome/components/lvgl/btn.py | 25 +++++ esphome/components/lvgl/defines.py | 9 +- esphome/components/lvgl/helpers.py | 1 - esphome/components/lvgl/label.py | 21 ++-- esphome/components/lvgl/lv_validation.py | 79 ++++++++++++--- esphome/components/lvgl/lvgl_esphome.cpp | 6 ++ esphome/components/lvgl/lvgl_esphome.h | 59 ++++++++++-- esphome/components/lvgl/obj.py | 11 +-- esphome/components/lvgl/schemas.py | 64 +++++++------ esphome/components/lvgl/touchscreens.py | 46 +++++++++ esphome/components/lvgl/types.py | 112 +++++++++++++++++----- esphome/components/lvgl/widget.py | 73 ++------------ esphome/core/defines.h | 1 + tests/components/lvgl/common.yaml | 10 ++ tests/components/lvgl/logo-text.svg | 25 +++++ tests/components/lvgl/lvgl-package.yaml | 102 +++++++++++++++++++- tests/components/lvgl/test.esp32-idf.yaml | 4 +- 18 files changed, 503 insertions(+), 183 deletions(-) create mode 100644 esphome/components/lvgl/btn.py create mode 100644 esphome/components/lvgl/touchscreens.py create mode 100644 tests/components/lvgl/logo-text.svg diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 2f3bd69546..c454a61957 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -16,13 +16,20 @@ from esphome.final_validate import full_config from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid +from .btn import btn_spec from .label import label_spec from .lvcode import ConstantLiteral, LvContext - -# from .menu import menu_spec from .obj import obj_spec -from .schemas import WIDGET_TYPES, any_widget_schema, obj_schema -from .types import FontEngine, LvglComponent, lv_disp_t_ptr, lv_font_t, lvgl_ns +from .schemas import any_widget_schema, obj_schema +from .touchscreens import touchscreen_schema, touchscreens_to_code +from .types import ( + WIDGET_TYPES, + FontEngine, + LvglComponent, + lv_disp_t_ptr, + lv_font_t, + lvgl_ns, +) from .widget import LvScrActType, Widget, add_widgets, set_obj_properties DOMAIN = "lvgl" @@ -31,11 +38,8 @@ AUTO_LOAD = ("key_provider",) CODEOWNERS = ("@clydebarrow",) LOGGER = logging.getLogger(__name__) -for widg in ( - label_spec, - obj_spec, -): - WIDGET_TYPES[widg.name] = widg +for w_type in (label_spec, obj_spec, btn_spec): + WIDGET_TYPES[w_type.name] = w_type lv_scr_act_spec = LvScrActType() lv_scr_act = Widget.create( @@ -93,7 +97,7 @@ def final_validation(config): "Using auto_clear_enabled: true in display config not compatible with LVGL" ) buffer_frac = config[CONF_BUFFER_SIZE] - if not CORE.is_host and buffer_frac > 0.5 and "psram" not in global_config: + if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config: LOGGER.warning("buffer_size: may need to be reduced without PSRAM") @@ -132,7 +136,7 @@ async def to_code(config): cg.add_global(lvgl_ns.using) lv_component = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(lv_component, config) - Widget.create(config[CONF_ID], lv_component, WIDGET_TYPES[df.CONF_OBJ], config) + Widget.create(config[CONF_ID], lv_component, obj_spec, config) for display in config[df.CONF_DISPLAYS]: cg.add(lv_component.add_display(await cg.get_variable(display))) @@ -152,7 +156,7 @@ async def to_code(config): await cg.get_variable(font) cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font)) default_font = config[df.CONF_DEFAULT_FONT] - if default_font not in helpers.lv_fonts_used: + if not lvalid.is_lv_font(default_font): add_define( "LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})" ) @@ -161,12 +165,15 @@ async def to_code(config): True, type=lv_font_t.operator("ptr").operator("const"), ) - cg.new_variable(globfont_id, MockObj(default_font)) + cg.new_variable( + globfont_id, MockObj(await lvalid.lv_font.process(default_font)) + ) add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT) else: - add_define("LV_FONT_DEFAULT", default_font) + add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font)) with LvContext(): + await touchscreens_to_code(lv_component, config) await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) Widget.set_completed() @@ -190,7 +197,7 @@ FINAL_VALIDATE_SCHEMA = final_validation CONFIG_SCHEMA = ( cv.polling_component_schema("1s") - .extend(obj_schema("obj")) + .extend(obj_schema(obj_spec)) .extend( { cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent), @@ -207,6 +214,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA), cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, + cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, } ) ).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) diff --git a/esphome/components/lvgl/btn.py b/esphome/components/lvgl/btn.py new file mode 100644 index 0000000000..4f5f88d9e6 --- /dev/null +++ b/esphome/components/lvgl/btn.py @@ -0,0 +1,25 @@ +from esphome.const import CONF_BUTTON +from esphome.cpp_generator import MockObjClass + +from .defines import CONF_MAIN +from .types import LvBoolean, WidgetType + + +class BtnType(WidgetType): + def __init__(self): + super().__init__(CONF_BUTTON, LvBoolean("lv_btn_t"), (CONF_MAIN,)) + + async def to_code(self, w, config): + return [] + + def obj_creator(self, parent: MockObjClass, config: dict): + """ + LVGL 8 calls buttons `btn` + """ + return f"lv_btn_create({parent})" + + def get_uses(self): + return ("btn",) + + +btn_spec = BtnType() diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 50bdac3865..a2b4ac13fb 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -446,6 +446,7 @@ CONF_TILE_ID = "tile_id" CONF_TILES = "tiles" CONF_TITLE = "title" CONF_TOP_LAYER = "top_layer" +CONF_TOUCHSCREENS = "touchscreens" CONF_TRANSPARENCY_KEY = "transparency_key" CONF_THEME = "theme" CONF_VISIBLE_ROW_COUNT = "visible_row_count" @@ -474,14 +475,8 @@ LV_KEYS = LvConstant( ) -# list of widgets and the parts allowed -WIDGET_PARTS = { - CONF_LABEL: (CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED), - CONF_OBJ: (CONF_MAIN,), -} - DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" def join_enums(enums, prefix=""): - return "|".join(f"(int){prefix}{e.upper()}" for e in enums) + return ConstantLiteral("|".join(f"(int){prefix}{e.upper()}" for e in enums)) diff --git a/esphome/components/lvgl/helpers.py b/esphome/components/lvgl/helpers.py index c8d4948fb1..d67739155c 100644 --- a/esphome/components/lvgl/helpers.py +++ b/esphome/components/lvgl/helpers.py @@ -22,7 +22,6 @@ def add_lv_use(*names): lv_fonts_used = set() esphome_fonts_used = set() -REQUIRED_COMPONENTS = {} lvgl_components_required = set() diff --git a/esphome/components/lvgl/label.py b/esphome/components/lvgl/label.py index 5c4ae6ab0d..0498f39474 100644 --- a/esphome/components/lvgl/label.py +++ b/esphome/components/lvgl/label.py @@ -1,16 +1,27 @@ import esphome.config_validation as cv -from .defines import CONF_LABEL, CONF_LONG_MODE, CONF_RECOLOR, CONF_TEXT, LV_LONG_MODES +from .defines import ( + CONF_LABEL, + CONF_LONG_MODE, + CONF_MAIN, + CONF_RECOLOR, + CONF_SCROLLBAR, + CONF_SELECTED, + CONF_TEXT, + LV_LONG_MODES, +) from .lv_validation import lv_bool, lv_text from .schemas import TEXT_SCHEMA -from .types import lv_label_t -from .widget import Widget, WidgetType +from .types import LvText, WidgetType +from .widget import Widget class LabelType(WidgetType): def __init__(self): super().__init__( CONF_LABEL, + LvText("lv_label_t"), + (CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED), TEXT_SCHEMA.extend( { cv.Optional(CONF_RECOLOR): lv_bool, @@ -19,10 +30,6 @@ class LabelType(WidgetType): ), ) - @property - def w_type(self): - return lv_label_t - async def to_code(self, w: Widget, config): """For a text object, create and set text""" if value := config.get(CONF_TEXT): diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 1de63c30ce..533dc582f0 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -8,6 +8,7 @@ import esphome.config_validation as cv from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT from esphome.core import HexInt from esphome.cpp_generator import MockObj +from esphome.cpp_types import uint32 from esphome.helpers import cpp_string_escape from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -23,6 +24,28 @@ from .lvcode import ConstantLiteral, lv_expr from .types import lv_font_t +def literal_mapper(value, args=()): + if isinstance(value, str): + return ConstantLiteral(value) + return value + + +opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") + + +@schema_extractor("one_of") +def opacity_validator(value): + if value == SCHEMA_EXTRACT: + return opacity_consts.choices + value = cv.Any(cv.percentage, opacity_consts.one_of)(value) + if isinstance(value, float): + return int(value * 255) + return value + + +opacity = LValidator(opacity_validator, uint32, retmapper=literal_mapper) + + @schema_extractor("one_of") def color(value): if value == SCHEMA_EXTRACT: @@ -43,16 +66,24 @@ def color_retmapper(value): return lv_expr.color_from(MockObj(value)) -def pixels_or_percent(value): +lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) + + +def pixels_or_percent_validator(value): """A length in one axis - either a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: return ["pixels", "..%"] if isinstance(value, int): - return str(cv.int_(value)) + return cv.int_(value) # Will throw an exception if not a percentage. return f"lv_pct({int(cv.percentage(value) * 100)})" +pixels_or_percent = LValidator( + pixels_or_percent_validator, uint32, retmapper=literal_mapper +) + + def zoom(value): value = cv.float_range(0.1, 10.0)(value) return int(value * 256) @@ -68,7 +99,7 @@ def angle(value): @schema_extractor("one_of") -def size(value): +def size_validator(value): """A size in one axis - one of "size_content", a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: return ["size_content", "pixels", "..%"] @@ -79,28 +110,42 @@ def size(value): return "LV_SIZE_CONTENT" raise cv.Invalid("must be 'size_content', a pixel position or a percentage") if isinstance(value, int): - return str(cv.int_(value)) + return cv.int_(value) # Will throw an exception if not a percentage. return f"lv_pct({int(cv.percentage(value) * 100)})" +size = LValidator(size_validator, uint32, retmapper=literal_mapper) + +radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") + + @schema_extractor("one_of") -def opacity(value): - consts = LvConstant("LV_OPA_", "TRANSP", "COVER") +def radius_validator(value): if value == SCHEMA_EXTRACT: - return consts.choices - value = cv.Any(cv.percentage, consts.one_of)(value) + return radius_consts.choices + value = cv.Any(size, cv.percentage, radius_consts.one_of)(value) if isinstance(value, float): return int(value * 255) return value +def id_name(value): + if value == SCHEMA_EXTRACT: + return "id" + return cv.validate_id_name(value) + + +radius = LValidator(radius_validator, uint32, retmapper=literal_mapper) + + def stop_value(value): return cv.int_range(0, 255)(value) -lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) -lv_bool = LValidator(cv.boolean, cg.bool_, BinarySensor, "get_state()") +lv_bool = LValidator( + cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal_mapper +) def lvms_validator_(value): @@ -145,26 +190,32 @@ lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") +def is_lv_font(font): + return isinstance(font, str) and font.lower() in LV_FONTS + + class LvFont(LValidator): def __init__(self): def lv_builtin_font(value): fontval = cv.one_of(*LV_FONTS, lower=True)(value) lv_fonts_used.add(fontval) - return "&lv_font_" + fontval + return fontval def validator(value): if value == SCHEMA_EXTRACT: return LV_FONTS - if isinstance(value, str) and value.lower() in LV_FONTS: + if is_lv_font(value): return lv_builtin_font(value) fontval = cv.use_id(Font)(value) esphome_fonts_used.add(fontval) - return requires_component("font")(f"{fontval}_engine->get_lv_font()") + return requires_component("font")(fontval) super().__init__(validator, lv_font_t) async def process(self, value, args=()): - return ConstantLiteral(value) + if is_lv_font(value): + return ConstantLiteral(f"&lv_font_{value}") + return ConstantLiteral(f"{value}_engine->get_lv_font()") lv_font = LvFont() diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index bdaf8a4f18..74a1b0e7af 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -38,7 +38,9 @@ void LvglComponent::setup() { auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; auto *buf = lv_custom_mem_alloc(buf_bytes); if (buf == nullptr) { +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); +#endif this->mark_failed(); this->status_set_error("Memory allocation failure"); return; @@ -85,7 +87,9 @@ size_t lv_millis(void) { return esphome::millis(); } void *lv_custom_mem_alloc(size_t size) { auto *ptr = malloc(size); // NOLINT if (ptr == nullptr) { +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); +#endif } return ptr; } @@ -102,7 +106,9 @@ void *lv_custom_mem_alloc(size_t size) { ptr = heap_caps_malloc(size, cap_bits); } if (ptr == nullptr) { +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); +#endif return nullptr; } #ifdef ESPHOME_LOG_HAS_VERBOSE diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 988c22917b..a884a27042 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -18,23 +18,27 @@ #ifdef USE_LVGL_FONT #include "esphome/components/font/font.h" #endif +#ifdef USE_LVGL_TOUCHSCREEN +#include "esphome/components/touchscreen/touchscreen.h" +#endif // USE_LVGL_TOUCHSCREEN + namespace esphome { namespace lvgl { extern lv_event_code_t lv_custom_event; // NOLINT #ifdef USE_LVGL_COLOR -static lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } -#endif +inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } +#endif // USE_LVGL_COLOR #if LV_COLOR_DEPTH == 16 static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; #elif LV_COLOR_DEPTH == 32 static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_888; -#else +#else // LV_COLOR_DEPTH static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_332; -#endif +#endif // LV_COLOR_DEPTH // Parent class for things that wrap an LVGL object -class LvCompound { +class LvCompound final { public: virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } lv_obj_t *obj{}; @@ -99,6 +103,14 @@ class LvglComponent : public PollingComponent { void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; } void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } lv_disp_t *get_disp() { return this->disp_; } + void set_paused(bool paused, bool show_snow) { + this->paused_ = paused; + if (!paused && lv_scr_act() != nullptr) { + lv_disp_trig_activity(this->disp_); // resets the inactivity time + lv_obj_invalidate(lv_scr_act()); + } + } + bool is_paused() const { return this->paused_; } protected: void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); @@ -107,13 +119,48 @@ class LvglComponent : public PollingComponent { lv_disp_draw_buf_t draw_buf_{}; lv_disp_drv_t disp_drv_{}; lv_disp_t *disp_{}; + bool paused_{}; std::vector> init_lambdas_; size_t buffer_frac_{1}; bool full_refresh_{}; }; +#ifdef USE_LVGL_TOUCHSCREEN +class LVTouchListener : public touchscreen::TouchListener, public Parented { + public: + LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) { + lv_indev_drv_init(&this->drv_); + this->drv_.long_press_repeat_time = long_press_repeat_time; + this->drv_.long_press_time = long_press_time; + this->drv_.type = LV_INDEV_TYPE_POINTER; + this->drv_.user_data = this; + this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { + auto *l = static_cast(d->user_data); + if (l->touch_pressed_) { + data->point.x = l->touch_point_.x; + data->point.y = l->touch_point_.y; + data->state = LV_INDEV_STATE_PRESSED; + } else { + data->state = LV_INDEV_STATE_RELEASED; + } + }; + } + void update(const touchscreen::TouchPoints_t &tpoints) override { + this->touch_pressed_ = !this->parent_->is_paused() && !tpoints.empty(); + if (this->touch_pressed_) + this->touch_point_ = tpoints[0]; + } + void release() override { touch_pressed_ = false; } + lv_indev_drv_t *get_drv() { return &this->drv_; } + + protected: + lv_indev_drv_t drv_{}; + touchscreen::TouchPoint touch_point_{}; + bool touch_pressed_{}; +}; +#endif // USE_LVGL_TOUCHSCREEN } // namespace lvgl } // namespace esphome -#endif +#endif // USE_LVGL diff --git a/esphome/components/lvgl/obj.py b/esphome/components/lvgl/obj.py index fba20bef36..92c4f63d2d 100644 --- a/esphome/components/lvgl/obj.py +++ b/esphome/components/lvgl/obj.py @@ -1,6 +1,5 @@ -from .defines import CONF_OBJ -from .types import lv_obj_t -from .widget import WidgetType +from .defines import CONF_MAIN, CONF_OBJ +from .types import WidgetType, lv_obj_t class ObjType(WidgetType): @@ -9,11 +8,7 @@ class ObjType(WidgetType): """ def __init__(self): - super().__init__(CONF_OBJ, schema={}, modify_schema={}) - - @property - def w_type(self): - return lv_obj_t + super().__init__(CONF_OBJ, lv_obj_t, (CONF_MAIN,), schema={}, modify_schema={}) async def to_code(self, w, config): return [] diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 4ae5824151..9f6d984545 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -3,15 +3,9 @@ from esphome.const import CONF_ARGS, CONF_FORMAT, CONF_ID, CONF_STATE, CONF_TYPE from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid, types as ty -from .defines import WIDGET_PARTS -from .helpers import ( - REQUIRED_COMPONENTS, - add_lv_use, - requires_component, - validate_printf, -) +from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_font -from .types import WIDGET_TYPES, get_widget_type +from .types import WIDGET_TYPES, WidgetType # A schema for text properties TEXT_SCHEMA = cv.Schema( @@ -46,9 +40,9 @@ STYLE_PROPS = { "bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, "bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of, "bg_grad_stop": lvalid.stop_value, - "bg_img_opa": lvalid.opacity, - "bg_img_recolor": lvalid.lv_color, - "bg_img_recolor_opa": lvalid.opacity, + "bg_image_opa": lvalid.opacity, + "bg_image_recolor": lvalid.lv_color, + "bg_image_recolor_opa": lvalid.opacity, "bg_main_stop": lvalid.stop_value, "bg_opa": lvalid.opacity, "border_color": lvalid.lv_color, @@ -60,8 +54,8 @@ STYLE_PROPS = { "border_width": cv.positive_int, "clip_corner": lvalid.lv_bool, "height": lvalid.size, - "img_recolor": lvalid.lv_color, - "img_recolor_opa": lvalid.opacity, + "image_recolor": lvalid.lv_color, + "image_recolor_opa": lvalid.opacity, "line_width": cv.positive_int, "line_dash_width": cv.positive_int, "line_dash_gap": cv.positive_int, @@ -108,12 +102,21 @@ STYLE_PROPS = { "max_width": lvalid.pixels_or_percent, "min_height": lvalid.pixels_or_percent, "min_width": lvalid.pixels_or_percent, - "radius": cv.Any(lvalid.size, df.LvConstant("LV_RADIUS_", "CIRCLE").one_of), + "radius": lvalid.radius, "width": lvalid.size, "x": lvalid.pixels_or_percent, "y": lvalid.pixels_or_percent, } +STYLE_REMAP = { + "bg_image_opa": "bg_img_opa", + "bg_image_recolor": "bg_img_recolor", + "bg_image_recolor_opa": "bg_img_recolor_opa", + "bg_image_src": "bg_img_src", + "image_recolor": "img_recolor", + "image_recolor_opa": "img_recolor_opa", +} + # Complete object style schema STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( { @@ -132,25 +135,23 @@ SET_STATE_SCHEMA = cv.Schema( {cv.Optional(state): lvalid.lv_bool for state in df.STATES} ) # Setting object flags -FLAG_SCHEMA = cv.Schema({cv.Optional(flag): cv.boolean for flag in df.OBJ_FLAGS}) +FLAG_SCHEMA = cv.Schema({cv.Optional(flag): lvalid.lv_bool for flag in df.OBJ_FLAGS}) FLAG_LIST = cv.ensure_list(df.LvConstant("LV_OBJ_FLAG_", *df.OBJ_FLAGS).one_of) -def part_schema(widget_type): +def part_schema(widget_type: WidgetType): """ Generate a schema for the various parts (e.g. main:, indicator:) of a widget type :param widget_type: The type of widget to generate for :return: """ - parts = WIDGET_PARTS.get(widget_type) - if parts is None: - parts = (df.CONF_MAIN,) + parts = widget_type.parts return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend( STATE_SCHEMA ) -def obj_schema(widget_type: str): +def obj_schema(widget_type: WidgetType): """ Create a schema for a widget type itself i.e. no allowance for children :param widget_type: @@ -187,13 +188,12 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value( STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT ) - ALL_STYLES = { **STYLE_PROPS, } -def container_validator(schema, widget_type): +def container_validator(schema, widget_type: WidgetType): """ Create a validator for a container given the widget type :param schema: Base schema to extend @@ -203,13 +203,16 @@ def container_validator(schema, widget_type): def validator(value): result = schema - if w_sch := WIDGET_TYPES[widget_type].schema: + if w_sch := widget_type.schema: result = result.extend(w_sch) if value and (layout := value.get(df.CONF_LAYOUT)): if not isinstance(layout, dict): raise cv.Invalid("Layout value must be a dict") ltype = layout.get(CONF_TYPE) add_lv_use(ltype) + result = result.extend( + {cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema())} + ) if value == SCHEMA_EXTRACT: return result return result(value) @@ -217,7 +220,7 @@ def container_validator(schema, widget_type): return validator -def container_schema(widget_type, extras=None): +def container_schema(widget_type: WidgetType, extras=None): """ Create a schema for a container widget of a given type. All obj properties are available, plus the extras passed in, plus any defined for the specific widget being specified. @@ -225,15 +228,16 @@ def container_schema(widget_type, extras=None): :param extras: Additional options to be made available, e.g. layout properties for children :return: The schema for this type of widget. """ - lv_type = get_widget_type(widget_type) - schema = obj_schema(widget_type).extend({cv.GenerateID(): cv.declare_id(lv_type)}) + schema = obj_schema(widget_type).extend( + {cv.GenerateID(): cv.declare_id(widget_type.w_type)} + ) if extras: schema = schema.extend(extras) # Delayed evaluation for recursion return container_validator(schema, widget_type) -def widget_schema(widget_type, extras=None): +def widget_schema(widget_type: WidgetType, extras=None): """ Create a schema for a given widget type :param widget_type: The name of the widget @@ -241,9 +245,9 @@ def widget_schema(widget_type, extras=None): :return: """ validator = container_schema(widget_type, extras=extras) - if required := REQUIRED_COMPONENTS.get(widget_type): + if required := widget_type.required_component: validator = cv.All(validator, requires_component(required)) - return cv.Exclusive(widget_type, df.CONF_WIDGETS), validator + return cv.Exclusive(widget_type.name, df.CONF_WIDGETS), validator # All widget schemas must be defined before this is called. @@ -257,4 +261,4 @@ def any_widget_schema(extras=None): :param extras: Additional schema to be applied to each generated one :return: """ - return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_PARTS)) + return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_TYPES.values())) diff --git a/esphome/components/lvgl/touchscreens.py b/esphome/components/lvgl/touchscreens.py new file mode 100644 index 0000000000..a0d4a3e4ad --- /dev/null +++ b/esphome/components/lvgl/touchscreens.py @@ -0,0 +1,46 @@ +import esphome.codegen as cg +from esphome.components.touchscreen import CONF_TOUCHSCREEN_ID, Touchscreen +import esphome.config_validation as cv +from esphome.const import CONF_ID +from esphome.core import CORE, TimePeriod + +from .defines import ( + CONF_LONG_PRESS_REPEAT_TIME, + CONF_LONG_PRESS_TIME, + CONF_TOUCHSCREENS, +) +from .helpers import lvgl_components_required +from .lv_validation import lv_milliseconds +from .lvcode import lv +from .types import LVTouchListener + +PRESS_TIME = cv.All(lv_milliseconds, cv.Range(max=TimePeriod(milliseconds=65535))) +CONF_TOUCHSCREEN = "touchscreen" +TOUCHSCREENS_CONFIG = cv.maybe_simple_value( + { + cv.Required(CONF_TOUCHSCREEN_ID): cv.use_id(Touchscreen), + cv.Optional(CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, + cv.Optional(CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, + cv.GenerateID(): cv.declare_id(LVTouchListener), + }, + key=CONF_TOUCHSCREEN_ID, +) + + +def touchscreen_schema(config): + value = cv.ensure_list(TOUCHSCREENS_CONFIG)(config) + if value or CONF_TOUCHSCREEN not in CORE.loaded_integrations: + return value + return [TOUCHSCREENS_CONFIG(config)] + + +async def touchscreens_to_code(var, config): + for tconf in config.get(CONF_TOUCHSCREENS) or (): + lvgl_components_required.add(CONF_TOUCHSCREEN) + touchscreen = await cg.get_variable(tconf[CONF_TOUCHSCREEN_ID]) + lpt = tconf[CONF_LONG_PRESS_TIME].total_milliseconds + lprt = tconf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds + listener = cg.new_Pvariable(tconf[CONF_ID], lpt, lprt) + await cg.register_parented(listener, var) + lv.indev_drv_register(listener.get_drv()) + cg.add(touchscreen.register_listener(listener)) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index 3c043d266d..60291ea54a 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -1,7 +1,22 @@ from esphome import codegen as cg from esphome.core import ID +from esphome.cpp_generator import MockObjClass + +from .defines import CONF_TEXT + + +class LvType(cg.MockObjClass): + def __init__(self, *args, **kwargs): + parens = kwargs.pop("parents", ()) + super().__init__(*args, parents=parens + (lv_obj_base_t,)) + self.args = kwargs.pop("largs", [(lv_obj_t_ptr, "obj")]) + self.value = kwargs.pop("lvalue", lambda w: w.obj) + self.has_on_value = kwargs.pop("has_on_value", False) + self.value_property = None + + def get_arg_type(self): + return self.args[0][0] if len(self.args) else None -from .defines import CONF_LABEL, CONF_OBJ, CONF_TEXT uint16_t_ptr = cg.uint16.operator("ptr") lvgl_ns = cg.esphome_ns.namespace("lvgl") @@ -18,25 +33,15 @@ lv_obj_base_t = cg.global_ns.class_("lv_obj_t", lv_pseudo_button_t) lv_obj_t_ptr = lv_obj_base_t.operator("ptr") lv_disp_t_ptr = cg.global_ns.struct("lv_disp_t").operator("ptr") lv_color_t = cg.global_ns.struct("lv_color_t") +LVTouchListener = lvgl_ns.class_("LVTouchListener") +LVEncoderListener = lvgl_ns.class_("LVEncoderListener") +lv_obj_t = LvType("lv_obj_t") # this will be populated later, in __init__.py to avoid circular imports. WIDGET_TYPES: dict = {} -class LvType(cg.MockObjClass): - def __init__(self, *args, **kwargs): - parens = kwargs.pop("parents", ()) - super().__init__(*args, parents=parens + (lv_obj_base_t,)) - self.args = kwargs.pop("largs", [(lv_obj_t_ptr, "obj")]) - self.value = kwargs.pop("lvalue", lambda w: w.obj) - self.has_on_value = kwargs.pop("has_on_value", False) - self.value_property = None - - def get_arg_type(self): - return self.args[0][0] if len(self.args) else None - - class LvText(LvType): def __init__(self, *args, **kwargs): super().__init__( @@ -48,17 +53,74 @@ class LvText(LvType): self.value_property = CONF_TEXT -lv_obj_t = LvType("lv_obj_t") -lv_label_t = LvText("lv_label_t") - -LV_TYPES = { - CONF_LABEL: lv_label_t, - CONF_OBJ: lv_obj_t, -} - - -def get_widget_type(typestr: str) -> LvType: - return LV_TYPES[typestr] +class LvBoolean(LvType): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + largs=[(cg.bool_, "x")], + lvalue=lambda w: w.is_checked(), + has_on_value=True, + **kwargs, + ) CUSTOM_EVENT = ID("lv_custom_event", False, type=lv_event_code_t) + + +class WidgetType: + """ + Describes a type of Widget, e.g. "bar" or "line" + """ + + def __init__(self, name, w_type, parts, schema=None, modify_schema=None): + """ + :param name: The widget name, e.g. "bar" + :param w_type: The C type of the widget + :param parts: What parts this widget supports + :param schema: The config schema for defining a widget + :param modify_schema: A schema to update the widget + """ + self.name = name + self.w_type = w_type + self.parts = parts + self.schema = schema or {} + if modify_schema is None: + self.modify_schema = schema + else: + self.modify_schema = modify_schema + + @property + def animated(self): + return False + + @property + def required_component(self): + return None + + def is_compound(self): + return self.w_type.inherits_from(LvCompound) + + async def to_code(self, w, config: dict): + """ + Generate code for a given widget + :param w: The widget + :param config: Its configuration + :return: Generated code as a list of text lines + """ + raise NotImplementedError(f"No to_code defined for {self.name}") + + def obj_creator(self, parent: MockObjClass, config: dict): + """ + Create an instance of the widget type + :param parent: The parent to which it should be attached + :param config: Its configuration + :return: Generated code as a single text line + """ + return f"lv_{self.name}_create({parent})" + + def get_uses(self): + """ + Get a list of other widgets used by this one + :return: + """ + return () diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widget.py index 44f277f1c3..4755d8b21d 100644 --- a/esphome/components/lvgl/widget.py +++ b/esphome/components/lvgl/widget.py @@ -21,78 +21,19 @@ from .defines import ( ) from .helpers import add_lv_use from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj -from .schemas import ALL_STYLES -from .types import WIDGET_TYPES, LvCompound, lv_obj_t +from .schemas import ALL_STYLES, STYLE_REMAP +from .types import WIDGET_TYPES, WidgetType, lv_obj_t EVENT_LAMB = "event_lamb__" -class WidgetType: - """ - Describes a type of Widget, e.g. "bar" or "line" - """ - - def __init__(self, name, schema=None, modify_schema=None): - """ - :param name: The widget name, e.g. "bar" - :param schema: The config schema for defining a widget - :param modify_schema: A schema to update the widget - """ - self.name = name - self.schema = schema or {} - if modify_schema is None: - self.modify_schema = schema - else: - self.modify_schema = modify_schema - - @property - def animated(self): - return False - - @property - def w_type(self): - """ - Get the type associated with this widget - :return: - """ - return lv_obj_t - - def is_compound(self): - return self.w_type.inherits_from(LvCompound) - - async def to_code(self, w, config: dict): - """ - Generate code for a given widget - :param w: The widget - :param config: Its configuration - :return: Generated code as a list of text lines - """ - raise NotImplementedError(f"No to_code defined for {self.name}") - - def obj_creator(self, parent: MockObjClass, config: dict): - """ - Create an instance of the widget type - :param parent: The parent to which it should be attached - :param config: Its configuration - :return: Generated code as a single text line - """ - return f"lv_{self.name}_create({parent})" - - def get_uses(self): - """ - Get a list of other widgets used by this one - :return: - """ - return () - - class LvScrActType(WidgetType): """ A "widget" representing the active screen. """ def __init__(self): - super().__init__("lv_scr_act()") + super().__init__("lv_scr_act()", lv_obj_t, ()) def obj_creator(self, parent: MockObjClass, config: dict): return [] @@ -263,7 +204,9 @@ async def set_obj_properties(w: Widget, config): }.items(): if isinstance(ALL_STYLES[prop], LValidator): value = await ALL_STYLES[prop].process(value) - w.set_style(prop, value, lv_state) + # Remapping for backwards compatibility of style names + prop_r = STYLE_REMAP.get(prop, prop) + w.set_style(prop_r, value, lv_state) flag_clr = set() flag_set = set() props = parts[CONF_MAIN][CONF_DEFAULT] @@ -291,10 +234,10 @@ async def set_obj_properties(w: Widget, config): else: clears.add(key) if adds: - adds = ConstantLiteral(join_enums(adds, "LV_STATE_")) + adds = join_enums(adds, "LV_STATE_") w.add_state(adds) if clears: - clears = ConstantLiteral(join_enums(clears, "LV_STATE_")) + clears = join_enums(clears, "LV_STATE_") w.clear_state(clears) for key, value in lambs.items(): lamb = await cg.process_lambda(value, [], return_type=cg.bool_) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 9d453260ab..6ba5b64761 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -41,6 +41,7 @@ #define USE_LVGL #define USE_LVGL_FONT #define USE_LVGL_IMAGE +#define USE_LVGL_TOUCHSCREEN #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index e69de29bb2..8b92f8caa7 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -0,0 +1,10 @@ +touchscreen: + - platform: ft63x6 + id: tft_touch + display: tft_display + update_interval: 50ms + threshold: 1 + calibration: + x_max: 240 + y_max: 320 + diff --git a/tests/components/lvgl/logo-text.svg b/tests/components/lvgl/logo-text.svg new file mode 100644 index 0000000000..4950806a36 --- /dev/null +++ b/tests/components/lvgl/logo-text.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 856e7c3e9d..696c749876 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -1,9 +1,10 @@ -color: - - id: light_blue - hex: "3340FF" - lvgl: + log_level: TRACE bg_color: light_blue + touchscreens: + - touchscreen_id: tft_touch + long_press_repeat_time: 200ms + long_press_time: 500ms widgets: - label: text: Hello world @@ -17,8 +18,101 @@ lvgl: text_color: 0xFFFFFF align: bottom_mid text_font: space16 + - obj: + align: center + arc_opa: COVER + arc_color: 0xFF0000 + arc_rounded: false + arc_width: 3 + anim_time: 1s + bg_color: light_blue + bg_grad_color: light_blue + bg_dither_mode: ordered + bg_grad_dir: hor + bg_grad_stop: 128 + bg_image_opa: transp + bg_image_recolor: light_blue + bg_image_recolor_opa: 50% + bg_main_stop: 0 + bg_opa: 20% + border_color: 0x00FF00 + border_opa: cover + border_post: true + border_side: [bottom, left] + border_width: 4 + clip_corner: false + height: 50% + image_recolor: light_blue + image_recolor_opa: cover + line_width: 10 + line_dash_width: 10 + line_dash_gap: 10 + line_rounded: false + line_color: light_blue + opa: cover + opa_layered: cover + outline_color: light_blue + outline_opa: cover + outline_pad: 10px + outline_width: 10px + pad_all: 10px + pad_bottom: 10px + pad_column: 10px + pad_left: 10px + pad_right: 10px + pad_row: 10px + pad_top: 10px + shadow_color: light_blue + shadow_ofs_x: 5 + shadow_ofs_y: 5 + shadow_opa: cover + shadow_spread: 5 + shadow_width: 10 + text_align: auto + text_color: light_blue + text_decor: [underline, strikethrough] + text_font: montserrat_18 + text_letter_space: 4 + text_line_space: 4 + text_opa: cover + transform_angle: 180 + transform_height: 100 + transform_pivot_x: 50% + transform_pivot_y: 50% + transform_zoom: 0.5 + translate_x: 10 + translate_y: 10 + max_height: 100 + max_width: 200 + min_height: 20% + min_width: 20% + radius: circle + width: 10px + x: 100 + y: 120 + - button: + width: 20% + height: 10% + pressed: + bg_color: light_blue + widgets: + - label: + text: Button font: - file: "gfonts://Roboto" id: space16 bpp: 4 + +image: + - id: cat_img + resize: 256x48 + file: $component_dir/logo-text.svg + - id: dog_img + file: $component_dir/logo-text.svg + resize: 256x48 + type: TRANSPARENT_BINARY + +color: + - id: light_blue + hex: "3340FF" diff --git a/tests/components/lvgl/test.esp32-idf.yaml b/tests/components/lvgl/test.esp32-idf.yaml index f159431b99..eab75b05f3 100644 --- a/tests/components/lvgl/test.esp32-idf.yaml +++ b/tests/components/lvgl/test.esp32-idf.yaml @@ -19,7 +19,9 @@ display: mirror_y: true data_rate: 80MHz cs_pin: GPIO20 - dc_pin: GPIO15 + dc_pin: + number: GPIO15 + ignore_strapping_warning: true auto_clear_enabled: false invert_colors: false update_interval: never From 6e21d79bde02b90e4273b7a92f2caa8604a3d687 Mon Sep 17 00:00:00 2001 From: FreeBear-nc <67865163+FreeBear-nc@users.noreply.github.com> Date: Tue, 30 Jul 2024 02:15:27 +0100 Subject: [PATCH 2138/2607] [pid] Add get_min_integral() and get_max_integral() (#7162) --- esphome/components/pid/pid_climate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/pid/pid_climate.h b/esphome/components/pid/pid_climate.h index 5ae97ee10b..b5275e9775 100644 --- a/esphome/components/pid/pid_climate.h +++ b/esphome/components/pid/pid_climate.h @@ -44,6 +44,8 @@ class PIDClimate : public climate::Climate, public Component { float get_kp() { return controller_.kp_; } float get_ki() { return controller_.ki_; } float get_kd() { return controller_.kd_; } + float get_min_integral() { return controller_.min_integral_; } + float get_max_integral() { return controller_.max_integral_; } float get_proportional_term() const { return controller_.proportional_term_; } float get_integral_term() const { return controller_.integral_term_; } float get_derivative_term() const { return controller_.derivative_term_; } From 83bb7d0266459ebae70d663addabc45a1f112092 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:23:30 +1200 Subject: [PATCH 2139/2607] [code-quality] Organise bluetooth related imports (#7155) --- esphome/components/ble_client/__init__.py | 8 ++++---- esphome/components/ble_client/output/__init__.py | 2 +- esphome/components/ble_client/sensor/__init__.py | 7 ++++--- esphome/components/ble_client/switch/__init__.py | 3 ++- esphome/components/ble_client/text_sensor/__init__.py | 7 ++++--- esphome/components/ble_presence/binary_sensor.py | 6 +++--- esphome/components/ble_rssi/sensor.py | 4 ++-- esphome/components/ble_scanner/text_sensor.py | 2 +- esphome/components/bluetooth_proxy/__init__.py | 6 +++--- esphome/components/esp32_ble/__init__.py | 6 +++--- esphome/components/esp32_ble_beacon/__init__.py | 10 +++++----- esphome/components/esp32_ble_client/__init__.py | 1 - esphome/components/esp32_ble_server/__init__.py | 4 ++-- esphome/components/esp32_ble_tracker/__init__.py | 4 ++-- 14 files changed, 36 insertions(+), 34 deletions(-) diff --git a/esphome/components/ble_client/__init__.py b/esphome/components/ble_client/__init__.py index 34b9868edc..6bf4ff739e 100644 --- a/esphome/components/ble_client/__init__.py +++ b/esphome/components/ble_client/__init__.py @@ -1,7 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv +from esphome import automation from esphome.automation import maybe_simple_id -from esphome.components import esp32_ble_tracker, esp32_ble_client +import esphome.codegen as cg +from esphome.components import esp32_ble_client, esp32_ble_tracker +import esphome.config_validation as cv from esphome.const import ( CONF_CHARACTERISTIC_UUID, CONF_ID, @@ -13,7 +14,6 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_VALUE, ) -from esphome import automation AUTO_LOAD = ["esp32_ble_client"] CODEOWNERS = ["@buxtronix", "@clydebarrow"] diff --git a/esphome/components/ble_client/output/__init__.py b/esphome/components/ble_client/output/__init__.py index fd847d80b8..729885eb8b 100644 --- a/esphome/components/ble_client/output/__init__.py +++ b/esphome/components/ble_client/output/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import ble_client, esp32_ble_tracker, output +import esphome.config_validation as cv from esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID from .. import ble_client_ns diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py index d0b27c30a9..0c48902a90 100644 --- a/esphome/components/ble_client/sensor/__init__.py +++ b/esphome/components/ble_client/sensor/__init__.py @@ -1,17 +1,18 @@ +from esphome import automation import esphome.codegen as cg +from esphome.components import ble_client, esp32_ble_tracker, sensor import esphome.config_validation as cv -from esphome.components import sensor, ble_client, esp32_ble_tracker from esphome.const import ( CONF_CHARACTERISTIC_UUID, CONF_LAMBDA, + CONF_SERVICE_UUID, CONF_TRIGGER_ID, CONF_TYPE, - CONF_SERVICE_UUID, DEVICE_CLASS_SIGNAL_STRENGTH, STATE_CLASS_MEASUREMENT, UNIT_DECIBEL_MILLIWATT, ) -from esphome import automation + from .. import ble_client_ns DEPENDENCIES = ["ble_client"] diff --git a/esphome/components/ble_client/switch/__init__.py b/esphome/components/ble_client/switch/__init__.py index 2304d65c01..70314e8f30 100644 --- a/esphome/components/ble_client/switch/__init__.py +++ b/esphome/components/ble_client/switch/__init__.py @@ -1,7 +1,8 @@ import esphome.codegen as cg +from esphome.components import ble_client, switch import esphome.config_validation as cv -from esphome.components import switch, ble_client from esphome.const import ICON_BLUETOOTH + from .. import ble_client_ns BLEClientSwitch = ble_client_ns.class_( diff --git a/esphome/components/ble_client/text_sensor/__init__.py b/esphome/components/ble_client/text_sensor/__init__.py index 7a93c4e4ae..479af1a57e 100644 --- a/esphome/components/ble_client/text_sensor/__init__.py +++ b/esphome/components/ble_client/text_sensor/__init__.py @@ -1,13 +1,14 @@ +from esphome import automation import esphome.codegen as cg +from esphome.components import ble_client, esp32_ble_tracker, text_sensor import esphome.config_validation as cv -from esphome.components import text_sensor, ble_client, esp32_ble_tracker from esphome.const import ( CONF_CHARACTERISTIC_UUID, CONF_ID, - CONF_TRIGGER_ID, CONF_SERVICE_UUID, + CONF_TRIGGER_ID, ) -from esphome import automation + from .. import ble_client_ns DEPENDENCIES = ["ble_client"] diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index 9c24a91a05..d1fdc80289 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -1,13 +1,13 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import binary_sensor, esp32_ble_tracker +import esphome.config_validation as cv from esphome.const import ( - CONF_MAC_ADDRESS, - CONF_SERVICE_UUID, CONF_IBEACON_MAJOR, CONF_IBEACON_MINOR, CONF_IBEACON_UUID, + CONF_MAC_ADDRESS, CONF_MIN_RSSI, + CONF_SERVICE_UUID, CONF_TIMEOUT, ) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 0543eb0578..e3ba1abfd7 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -1,12 +1,12 @@ import esphome.codegen as cg +from esphome.components import esp32_ble_tracker, sensor import esphome.config_validation as cv -from esphome.components import sensor, esp32_ble_tracker from esphome.const import ( CONF_IBEACON_MAJOR, CONF_IBEACON_MINOR, CONF_IBEACON_UUID, - CONF_SERVICE_UUID, CONF_MAC_ADDRESS, + CONF_SERVICE_UUID, DEVICE_CLASS_SIGNAL_STRENGTH, STATE_CLASS_MEASUREMENT, UNIT_DECIBEL_MILLIWATT, diff --git a/esphome/components/ble_scanner/text_sensor.py b/esphome/components/ble_scanner/text_sensor.py index 743403c6a4..96d71a0399 100644 --- a/esphome/components/ble_scanner/text_sensor.py +++ b/esphome/components/ble_scanner/text_sensor.py @@ -1,6 +1,6 @@ import esphome.codegen as cg +from esphome.components import esp32_ble_tracker, text_sensor import esphome.config_validation as cv -from esphome.components import text_sensor, esp32_ble_tracker DEPENDENCIES = ["esp32_ble_tracker"] diff --git a/esphome/components/bluetooth_proxy/__init__.py b/esphome/components/bluetooth_proxy/__init__.py index bec1579d8e..5a4ba36666 100644 --- a/esphome/components/bluetooth_proxy/__init__.py +++ b/esphome/components/bluetooth_proxy/__init__.py @@ -1,8 +1,8 @@ -from esphome.components import esp32_ble_tracker, esp32_ble_client -import esphome.config_validation as cv import esphome.codegen as cg -from esphome.const import CONF_ACTIVE, CONF_ID +from esphome.components import esp32_ble_client, esp32_ble_tracker from esphome.components.esp32 import add_idf_sdkconfig_option +import esphome.config_validation as cv +from esphome.const import CONF_ACTIVE, CONF_ID AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"] DEPENDENCIES = ["api", "esp32"] diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 472669a381..75cf9d707d 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -1,9 +1,9 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg +from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant +import esphome.config_validation as cv from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID from esphome.core import CORE -from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const DEPENDENCIES = ["esp32"] CODEOWNERS = ["@jesserockz", "@Rapsssito"] diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index d063209478..f97f289a0a 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -1,10 +1,10 @@ import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components.esp32_ble import CONF_BLE_ID -from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER -from esphome.core import CORE, TimePeriod -from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components import esp32_ble +from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.components.esp32_ble import CONF_BLE_ID +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_TX_POWER, CONF_TYPE, CONF_UUID +from esphome.core import CORE, TimePeriod AUTO_LOAD = ["esp32_ble"] DEPENDENCIES = ["esp32"] diff --git a/esphome/components/esp32_ble_client/__init__.py b/esphome/components/esp32_ble_client/__init__.py index 94a5576d0b..25957ed0da 100644 --- a/esphome/components/esp32_ble_client/__init__.py +++ b/esphome/components/esp32_ble_client/__init__.py @@ -1,5 +1,4 @@ import esphome.codegen as cg - from esphome.components import esp32_ble_tracker AUTO_LOAD = ["esp32_ble_tracker"] diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index ce9fdc2cf3..9da7d13999 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -1,9 +1,9 @@ import esphome.codegen as cg +from esphome.components import esp32_ble +from esphome.components.esp32 import add_idf_sdkconfig_option import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODEL -from esphome.components import esp32_ble from esphome.core import CORE -from esphome.components.esp32 import add_idf_sdkconfig_option AUTO_LOAD = ["esp32_ble"] CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 1edeaadbfd..0aa8eadd0a 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -1,10 +1,10 @@ import re -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import esp32_ble from esphome.components.esp32 import add_idf_sdkconfig_option +import esphome.config_validation as cv from esphome.const import ( CONF_ACTIVE, CONF_DURATION, From caa2ea64e35ca883105f1fefeb1aeee5dbf28510 Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Tue, 30 Jul 2024 03:45:19 +0200 Subject: [PATCH 2140/2607] http_request watchdog as a component (#7161) --- CODEOWNERS | 1 + esphome/components/http_request/__init__.py | 2 +- esphome/components/http_request/http_request_arduino.cpp | 4 ++-- esphome/components/http_request/http_request_idf.cpp | 4 ++-- esphome/components/http_request/ota/ota_http_request.cpp | 2 +- esphome/components/watchdog/__init__.py | 1 + esphome/components/{http_request => watchdog}/watchdog.cpp | 2 -- esphome/components/{http_request => watchdog}/watchdog.h | 2 -- 8 files changed, 8 insertions(+), 10 deletions(-) create mode 100644 esphome/components/watchdog/__init__.py rename esphome/components/{http_request => watchdog}/watchdog.cpp (96%) rename esphome/components/{http_request => watchdog}/watchdog.h (88%) diff --git a/CODEOWNERS b/CODEOWNERS index 2fc030453f..d94c34c019 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -427,6 +427,7 @@ esphome/components/veml7700/* @latonita esphome/components/version/* @esphome/core esphome/components/voice_assistant/* @jesserockz esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 +esphome/components/watchdog/* @oarcher esphome/components/waveshare_epaper/* @clydebarrow esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_idf/* @dentra diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 3ca97b9611..0407bbd326 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( from esphome.core import CORE, Lambda DEPENDENCIES = ["network"] -AUTO_LOAD = ["json"] +AUTO_LOAD = ["json", "watchdog"] http_request_ns = cg.esphome_ns.namespace("http_request") HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component) diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index 95b1cdc38e..2148d92ad2 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -3,12 +3,12 @@ #ifdef USE_ARDUINO #include "esphome/components/network/util.h" +#include "esphome/components/watchdog/watchdog.h" + #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" -#include "watchdog.h" - namespace esphome { namespace http_request { diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 4fe5585723..3819f5544e 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -3,6 +3,8 @@ #ifdef USE_ESP_IDF #include "esphome/components/network/util.h" +#include "esphome/components/watchdog/watchdog.h" + #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" @@ -11,8 +13,6 @@ #include "esp_crt_bundle.h" #endif -#include "watchdog.h" - namespace esphome { namespace http_request { diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index dcc783ea47..1553de0bc1 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -1,11 +1,11 @@ #include "ota_http_request.h" -#include "../watchdog.h" #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" #include "esphome/components/md5/md5.h" +#include "esphome/components/watchdog/watchdog.h" #include "esphome/components/ota/ota_backend.h" #include "esphome/components/ota/ota_backend_arduino_esp32.h" #include "esphome/components/ota/ota_backend_arduino_esp8266.h" diff --git a/esphome/components/watchdog/__init__.py b/esphome/components/watchdog/__init__.py new file mode 100644 index 0000000000..6fb87e45a4 --- /dev/null +++ b/esphome/components/watchdog/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@oarcher"] diff --git a/esphome/components/http_request/watchdog.cpp b/esphome/components/watchdog/watchdog.cpp similarity index 96% rename from esphome/components/http_request/watchdog.cpp rename to esphome/components/watchdog/watchdog.cpp index a8519c59ed..3a94a658e8 100644 --- a/esphome/components/http_request/watchdog.cpp +++ b/esphome/components/watchdog/watchdog.cpp @@ -15,7 +15,6 @@ #endif namespace esphome { -namespace http_request { namespace watchdog { static const char *const TAG = "http_request.watchdog"; @@ -72,5 +71,4 @@ uint32_t WatchdogManager::get_timeout_() { } } // namespace watchdog -} // namespace http_request } // namespace esphome diff --git a/esphome/components/http_request/watchdog.h b/esphome/components/watchdog/watchdog.h similarity index 88% rename from esphome/components/http_request/watchdog.h rename to esphome/components/watchdog/watchdog.h index 9b54ae6c82..899ec3fde0 100644 --- a/esphome/components/http_request/watchdog.h +++ b/esphome/components/watchdog/watchdog.h @@ -5,7 +5,6 @@ #include namespace esphome { -namespace http_request { namespace watchdog { class WatchdogManager { @@ -22,5 +21,4 @@ class WatchdogManager { }; } // namespace watchdog -} // namespace http_request } // namespace esphome From d7231fadb1e174fe88f0d293c40265a26cd42ede Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:50:12 +1200 Subject: [PATCH 2141/2607] [touchscreen] Allow binary sensor to have multiple pages in config (#7112) * [touchscreen] Allow binary sensor to have multiple pages in config * Sort imports --- .../touchscreen/binary_sensor/__init__.py | 34 +++++++++++++------ .../touchscreen_binary_sensor.cpp | 5 +-- .../binary_sensor/touchscreen_binary_sensor.h | 6 ++-- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/esphome/components/touchscreen/binary_sensor/__init__.py b/esphome/components/touchscreen/binary_sensor/__init__.py index 800bc4c2a9..45fefbf814 100644 --- a/esphome/components/touchscreen/binary_sensor/__init__.py +++ b/esphome/components/touchscreen/binary_sensor/__init__.py @@ -1,10 +1,9 @@ import esphome.codegen as cg -import esphome.config_validation as cv - from esphome.components import binary_sensor, display -from esphome.const import CONF_PAGE_ID +import esphome.config_validation as cv +from esphome.const import CONF_PAGE_ID, CONF_PAGES -from .. import touchscreen_ns, CONF_TOUCHSCREEN_ID, Touchscreen, TouchListener +from .. import CONF_TOUCHSCREEN_ID, TouchListener, Touchscreen, touchscreen_ns DEPENDENCIES = ["touchscreen"] @@ -22,7 +21,7 @@ CONF_Y_MIN = "y_min" CONF_Y_MAX = "y_max" -def validate_coords(config): +def _validate_coords(config): if ( config[CONF_X_MAX] < config[CONF_X_MIN] or config[CONF_Y_MAX] < config[CONF_Y_MIN] @@ -33,6 +32,15 @@ def validate_coords(config): return config +def _set_pages(config: dict) -> dict: + if CONF_PAGES in config or CONF_PAGE_ID not in config: + return config + + config = config.copy() + config[CONF_PAGES] = [config.pop(CONF_PAGE_ID)] + return config + + CONFIG_SCHEMA = cv.All( binary_sensor.binary_sensor_schema(TouchscreenBinarySensor) .extend( @@ -42,11 +50,17 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_X_MAX): cv.int_range(min=0, max=2000), cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=2000), cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=2000), - cv.Optional(CONF_PAGE_ID): cv.use_id(display.DisplayPage), + cv.Exclusive(CONF_PAGE_ID, group_of_exclusion=CONF_PAGES): cv.use_id( + display.DisplayPage + ), + cv.Exclusive(CONF_PAGES, group_of_exclusion=CONF_PAGES): cv.ensure_list( + cv.use_id(display.DisplayPage) + ), } ) .extend(cv.COMPONENT_SCHEMA), - validate_coords, + _validate_coords, + _set_pages, ) @@ -64,6 +78,6 @@ async def to_code(config): ) ) - if CONF_PAGE_ID in config: - page = await cg.get_variable(config[CONF_PAGE_ID]) - cg.add(var.set_page(page)) + for page_id in config.get(CONF_PAGES, []): + page = await cg.get_variable(page_id) + cg.add(var.add_page(page)) diff --git a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp index 6c26ae3626..6cd12d4d0d 100644 --- a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +++ b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp @@ -11,8 +11,9 @@ void TouchscreenBinarySensor::setup() { void TouchscreenBinarySensor::touch(TouchPoint tp) { bool touched = (tp.x >= this->x_min_ && tp.x <= this->x_max_ && tp.y >= this->y_min_ && tp.y <= this->y_max_); - if (this->page_ != nullptr) { - touched &= this->page_ == this->parent_->get_display()->get_active_page(); + if (!this->pages_.empty()) { + auto *current_page = this->parent_->get_display()->get_active_page(); + touched &= std::find(this->pages_.begin(), this->pages_.end(), current_page) != this->pages_.end(); } if (touched) { this->publish_state(true); diff --git a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h index b56ae562b1..862f41064c 100644 --- a/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +++ b/esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h @@ -6,6 +6,8 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" +#include + namespace esphome { namespace touchscreen { @@ -30,14 +32,14 @@ class TouchscreenBinarySensor : public binary_sensor::BinarySensor, int16_t get_width() { return this->x_max_ - this->x_min_; } int16_t get_height() { return this->y_max_ - this->y_min_; } - void set_page(display::DisplayPage *page) { this->page_ = page; } + void add_page(display::DisplayPage *page) { this->pages_.push_back(page); } void touch(TouchPoint tp) override; void release() override; protected: int16_t x_min_, x_max_, y_min_, y_max_; - display::DisplayPage *page_{nullptr}; + std::vector pages_{}; }; } // namespace touchscreen From dff6884bedd1585b49d7864e52039f0f14e74fa8 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Tue, 30 Jul 2024 16:57:51 -0400 Subject: [PATCH 2142/2607] [micro_wake_word] Fix VAD detection and modify detection computation (#7164) --- esphome/components/micro_wake_word/streaming_model.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/esphome/components/micro_wake_word/streaming_model.cpp b/esphome/components/micro_wake_word/streaming_model.cpp index 013fa2ce6e..d0d2e2df05 100644 --- a/esphome/components/micro_wake_word/streaming_model.cpp +++ b/esphome/components/micro_wake_word/streaming_model.cpp @@ -148,7 +148,7 @@ WakeWordModel::WakeWordModel(const uint8_t *model_start, float probability_cutof }; bool WakeWordModel::determine_detected() { - int32_t sum = 0; + uint32_t sum = 0; for (auto &prob : this->recent_streaming_probabilities_) { sum += prob; } @@ -175,12 +175,14 @@ VADModel::VADModel(const uint8_t *model_start, float probability_cutoff, size_t }; bool VADModel::determine_detected() { - uint8_t max = 0; + uint32_t sum = 0; for (auto &prob : this->recent_streaming_probabilities_) { - max = std::max(prob, max); + sum += prob; } - return max > this->probability_cutoff_; + float sliding_window_average = static_cast(sum) / static_cast(255 * this->sliding_window_size_); + + return sliding_window_average > this->probability_cutoff_; } } // namespace micro_wake_word From dd3dd7a136b9f81a5d3ff7c7296edd031af38f4f Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Tue, 30 Jul 2024 22:30:15 +0100 Subject: [PATCH 2143/2607] fix: Add `pin->setup();` to matrix_keypad.cpp (#7163) --- esphome/components/matrix_keypad/matrix_keypad.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index 902e574846..f62c75c869 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -8,6 +8,7 @@ static const char *const TAG = "matrix_keypad"; void MatrixKeypad::setup() { for (auto *pin : this->rows_) { + pin->setup(); if (!has_diodes_) { pin->pin_mode(gpio::FLAG_INPUT); } else { @@ -15,6 +16,7 @@ void MatrixKeypad::setup() { } } for (auto *pin : this->columns_) { + pin->setup(); if (has_pulldowns_) { pin->pin_mode(gpio::FLAG_INPUT); } else { From 8849443bf6e9f56e5c0f682a25a78a6782007a1e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:08:11 +1200 Subject: [PATCH 2144/2607] [update] Implement ``update.perform`` action and ``update.is_available`` condition (#7165) * [update] Fix unimplemented yaml action/condition * Add/update tests --------- Co-authored-by: Keith Burzinski --- .../update/http_request_update.cpp | 4 +- .../http_request/update/http_request_update.h | 2 +- esphome/components/update/__init__.py | 48 +++++++++++++------ esphome/components/update/automation.h | 23 +++++++++ esphome/components/update/update_entity.h | 4 +- tests/components/update/common.yaml | 27 +++++++++++ tests/components/update/test.esp32-ard.yaml | 3 ++ tests/components/update/test.esp8266-ard.yaml | 3 ++ tests/components/update/test.rp2040-ard.yaml | 3 ++ 9 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 esphome/components/update/automation.h diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index 0a14dfd933..059148e7e5 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -138,8 +138,8 @@ void HttpRequestUpdate::update() { this->publish_state(); } -void HttpRequestUpdate::perform() { - if (this->state_ != update::UPDATE_STATE_AVAILABLE) { +void HttpRequestUpdate::perform(bool force) { + if (this->state_ != update::UPDATE_STATE_AVAILABLE && !force) { return; } diff --git a/esphome/components/http_request/update/http_request_update.h b/esphome/components/http_request/update/http_request_update.h index a6bc97392b..943231a906 100644 --- a/esphome/components/http_request/update/http_request_update.h +++ b/esphome/components/http_request/update/http_request_update.h @@ -15,7 +15,7 @@ class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent { void setup() override; void update() override; - void perform() override; + void perform(bool force) override; void set_source_url(const std::string &source_url) { this->source_url_ = source_url; } diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index 45bf082fa4..ba3b2f20df 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -1,10 +1,11 @@ from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server import esphome.config_validation as cv -import esphome.codegen as cg from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, + CONF_FORCE_UPDATE, CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, @@ -23,8 +24,12 @@ UpdateEntity = update_ns.class_("UpdateEntity", cg.EntityBase) UpdateInfo = update_ns.struct("UpdateInfo") -PerformAction = update_ns.class_("PerformAction", automation.Action) -IsAvailableCondition = update_ns.class_("IsAvailableCondition", automation.Condition) +PerformAction = update_ns.class_( + "PerformAction", automation.Action, cg.Parented.template(UpdateEntity) +) +IsAvailableCondition = update_ns.class_( + "IsAvailableCondition", automation.Condition, cg.Parented.template(UpdateEntity) +) DEVICE_CLASSES = [ DEVICE_CLASS_EMPTY, @@ -92,24 +97,37 @@ async def to_code(config): cg.add_global(update_ns.using) -UPDATE_AUTOMATION_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.use_id(UpdateEntity), - } +@automation.register_action( + "update.perform", + PerformAction, + automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(UpdateEntity), + cv.Optional(CONF_FORCE_UPDATE, default=False): cv.templatable(cv.boolean), + } + ), ) - - -@automation.register_action("update.perform", PerformAction, UPDATE_AUTOMATION_SCHEMA) async def update_perform_action_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, paren, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + + force = await cg.templatable(config[CONF_FORCE_UPDATE], args, cg.bool_) + cg.add(var.set_force(force)) + return var @automation.register_condition( - "update.is_available", IsAvailableCondition, UPDATE_AUTOMATION_SCHEMA + "update.is_available", + IsAvailableCondition, + automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(UpdateEntity), + } + ), ) async def update_is_available_condition_to_code( config, condition_id, template_arg, args ): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(condition_id, paren, paren) + var = cg.new_Pvariable(condition_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/esphome/components/update/automation.h b/esphome/components/update/automation.h new file mode 100644 index 0000000000..df50f86a0c --- /dev/null +++ b/esphome/components/update/automation.h @@ -0,0 +1,23 @@ +#pragma once + +#include "update_entity.h" + +#include "esphome/core/automation.h" + +namespace esphome { +namespace update { + +template class PerformAction : public Action, public Parented { + TEMPLATABLE_VALUE(bool, force) + + public: + void play(Ts... x) override { this->parent_->perform(this->force_.value(x...)); } +}; + +template class IsAvailableCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->state == UPDATE_STATE_AVAILABLE; } +}; + +} // namespace update +} // namespace esphome diff --git a/esphome/components/update/update_entity.h b/esphome/components/update/update_entity.h index 5984c8e35b..568fbe3bb0 100644 --- a/esphome/components/update/update_entity.h +++ b/esphome/components/update/update_entity.h @@ -32,7 +32,9 @@ class UpdateEntity : public EntityBase, public EntityBase_DeviceClass { void publish_state(); - virtual void perform() = 0; + void perform() { this->perform(false); } + + virtual void perform(bool force) = 0; const UpdateInfo &update_info = update_info_; const UpdateState &state = state_; diff --git a/tests/components/update/common.yaml b/tests/components/update/common.yaml index 91b8669505..dcb4f42527 100644 --- a/tests/components/update/common.yaml +++ b/tests/components/update/common.yaml @@ -1 +1,28 @@ +substitutions: + verify_ssl: "true" + +esphome: + on_boot: + then: + - if: + condition: + update.is_available: + then: + - logger.log: "Update available" + - update.perform: + force_update: true + +wifi: + ssid: MySSID + password: password1 + +http_request: + verify_ssl: ${verify_ssl} + +ota: + - platform: http_request + update: + - platform: http_request + name: Firmware Update + source: http://example.com/manifest.json diff --git a/tests/components/update/test.esp32-ard.yaml b/tests/components/update/test.esp32-ard.yaml index dade44d145..c1937b5a10 100644 --- a/tests/components/update/test.esp32-ard.yaml +++ b/tests/components/update/test.esp32-ard.yaml @@ -1 +1,4 @@ +substitutions: + verify_ssl: "false" + <<: !include common.yaml diff --git a/tests/components/update/test.esp8266-ard.yaml b/tests/components/update/test.esp8266-ard.yaml index dade44d145..c1937b5a10 100644 --- a/tests/components/update/test.esp8266-ard.yaml +++ b/tests/components/update/test.esp8266-ard.yaml @@ -1 +1,4 @@ +substitutions: + verify_ssl: "false" + <<: !include common.yaml diff --git a/tests/components/update/test.rp2040-ard.yaml b/tests/components/update/test.rp2040-ard.yaml index dade44d145..c1937b5a10 100644 --- a/tests/components/update/test.rp2040-ard.yaml +++ b/tests/components/update/test.rp2040-ard.yaml @@ -1 +1,4 @@ +substitutions: + verify_ssl: "false" + <<: !include common.yaml From 3920029aff9dd85fd5f0775945b8426c03da471c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 31 Jul 2024 14:31:15 +1000 Subject: [PATCH 2145/2607] [lvgl] PR stage 3 (#7160) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/lvgl/__init__.py | 58 +++++-- esphome/components/lvgl/automation.py | 188 +++++++++++++++++++++ esphome/components/lvgl/btn.py | 6 +- esphome/components/lvgl/defines.py | 30 +++- esphome/components/lvgl/lv_validation.py | 46 ++--- esphome/components/lvgl/lvcode.py | 64 ++++--- esphome/components/lvgl/lvgl_esphome.cpp | 75 +++++++- esphome/components/lvgl/lvgl_esphome.h | 165 ++++++++++++++++-- esphome/components/lvgl/obj.py | 13 +- esphome/components/lvgl/rotary_encoders.py | 62 +++++++ esphome/components/lvgl/schemas.py | 80 ++++++++- esphome/components/lvgl/touchscreens.py | 5 +- esphome/components/lvgl/trigger.py | 61 +++++++ esphome/components/lvgl/types.py | 23 ++- esphome/components/lvgl/widget.py | 58 +++++-- esphome/core/defines.h | 3 + tests/components/lvgl/lvgl-package.yaml | 35 ++++ tests/components/lvgl/test.esp32-idf.yaml | 21 +++ 18 files changed, 895 insertions(+), 98 deletions(-) create mode 100644 esphome/components/lvgl/automation.py create mode 100644 esphome/components/lvgl/rotary_encoders.py create mode 100644 esphome/components/lvgl/trigger.py diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index c454a61957..182d04e038 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -1,5 +1,6 @@ import logging +from esphome.automation import build_automation, register_action, validate_automation import esphome.codegen as cg from esphome.components.display import Display import esphome.config_validation as cv @@ -8,7 +9,11 @@ from esphome.const import ( CONF_BUFFER_SIZE, CONF_ID, CONF_LAMBDA, + CONF_ON_IDLE, CONF_PAGES, + CONF_TIMEOUT, + CONF_TRIGGER_ID, + CONF_TYPE, ) from esphome.core import CORE, ID, Lambda from esphome.cpp_generator import MockObj @@ -16,21 +21,26 @@ from esphome.final_validate import full_config from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid +from .automation import update_to_code from .btn import btn_spec from .label import label_spec -from .lvcode import ConstantLiteral, LvContext +from .lv_validation import lv_images_used +from .lvcode import LvContext from .obj import obj_spec -from .schemas import any_widget_schema, obj_schema +from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code +from .schemas import any_widget_schema, create_modify_schema, obj_schema from .touchscreens import touchscreen_schema, touchscreens_to_code +from .trigger import generate_triggers from .types import ( WIDGET_TYPES, FontEngine, + IdleTrigger, LvglComponent, - lv_disp_t_ptr, + ObjUpdateAction, lv_font_t, lvgl_ns, ) -from .widget import LvScrActType, Widget, add_widgets, set_obj_properties +from .widget import Widget, add_widgets, lv_scr_act, set_obj_properties DOMAIN = "lvgl" DEPENDENCIES = ("display",) @@ -41,17 +51,21 @@ LOGGER = logging.getLogger(__name__) for w_type in (label_spec, obj_spec, btn_spec): WIDGET_TYPES[w_type.name] = w_type -lv_scr_act_spec = LvScrActType() -lv_scr_act = Widget.create( - None, ConstantLiteral("lv_scr_act()"), lv_scr_act_spec, {}, parent=None -) - WIDGET_SCHEMA = any_widget_schema() +for w_type in WIDGET_TYPES.values(): + register_action( + f"lvgl.{w_type.name}.update", + ObjUpdateAction, + create_modify_schema(w_type), + )(update_to_code) + async def add_init_lambda(lv_component, init): if init: - lamb = await cg.process_lambda(Lambda(init), [(lv_disp_t_ptr, "lv_disp")]) + lamb = await cg.process_lambda( + Lambda(init), [(LvglComponent.operator("ptr"), "lv_component")] + ) cg.add(lv_component.add_init_lambda(lamb)) @@ -99,6 +113,13 @@ def final_validation(config): buffer_frac = config[CONF_BUFFER_SIZE] if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config: LOGGER.warning("buffer_size: may need to be reduced without PSRAM") + for image_id in lv_images_used: + path = global_config.get_path_for_id(image_id)[:-1] + image_conf = global_config.get_config_for_path(path) + if image_conf[CONF_TYPE] in ("RGBA", "RGB24"): + raise cv.Invalid( + "Using RGBA or RGB24 in image config not compatible with LVGL", path + ) async def to_code(config): @@ -174,9 +195,15 @@ async def to_code(config): with LvContext(): await touchscreens_to_code(lv_component, config) + await rotary_encoders_to_code(lv_component, config) await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) - Widget.set_completed() + Widget.set_completed() + await generate_triggers(lv_component) + for conf in config.get(CONF_ON_IDLE, ()): + templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) + idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) + await build_automation(idle_trigger, [], conf) await add_init_lambda(lv_component, LvContext.get_code()) for comp in helpers.lvgl_components_required: CORE.add_define(f"USE_LVGL_{comp.upper()}") @@ -212,9 +239,18 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_BYTE_ORDER, default="big_endian"): cv.one_of( "big_endian", "little_endian" ), + cv.Optional(CONF_ON_IDLE): validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(IdleTrigger), + cv.Required(CONF_TIMEOUT): cv.templatable( + cv.positive_time_period_milliseconds + ), + } + ), cv.Optional(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA), cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, + cv.GenerateID(df.CONF_ROTARY_ENCODERS): ROTARY_ENCODER_CONFIG, } ) ).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py new file mode 100644 index 0000000000..4fd0be185e --- /dev/null +++ b/esphome/components/lvgl/automation.py @@ -0,0 +1,188 @@ +from esphome import automation +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome.core import Lambda +from esphome.cpp_generator import RawStatement +from esphome.cpp_types import nullptr + +from .defines import CONF_LVGL_ID, CONF_SHOW_SNOW, literal +from .lv_validation import lv_bool +from .lvcode import ( + LambdaContext, + ReturnStatement, + add_line_marks, + lv, + lv_add, + lv_obj, + lvgl_comp, +) +from .schemas import ACTION_SCHEMA, LVGL_SCHEMA +from .types import ( + LvglAction, + LvglComponent, + LvglComponentPtr, + LvglCondition, + ObjUpdateAction, + lv_obj_t, +) +from .widget import Widget, get_widget, lv_scr_act, set_obj_properties + + +async def action_to_code(action: list, action_id, widget: Widget, template_arg, args): + with LambdaContext() as context: + lv.cond_if(widget.obj == nullptr) + lv_add(RawStatement(" return;")) + lv.cond_endif() + code = context.get_code() + code.extend(action) + action = "\n".join(code) + "\n\n" + lamb = await cg.process_lambda(Lambda(action), args) + var = cg.new_Pvariable(action_id, template_arg, lamb) + return var + + +async def update_to_code(config, action_id, template_arg, args): + if config is not None: + widget = await get_widget(config) + with LambdaContext() as context: + add_line_marks(action_id) + await set_obj_properties(widget, config) + await widget.type.to_code(widget, config) + if ( + widget.type.w_type.value_property is not None + and widget.type.w_type.value_property in config + ): + lv.event_send(widget.obj, literal("LV_EVENT_VALUE_CHANGED"), nullptr) + return await action_to_code( + context.get_code(), action_id, widget, template_arg, args + ) + + +@automation.register_condition( + "lvgl.is_paused", + LvglCondition, + LVGL_SCHEMA, +) +async def lvgl_is_paused(config, condition_id, template_arg, args): + lvgl = config[CONF_LVGL_ID] + with LambdaContext( + [(LvglComponentPtr, "lvgl_comp")], return_type=cg.bool_ + ) as context: + lv_add(ReturnStatement(lvgl_comp.is_paused())) + var = cg.new_Pvariable(condition_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, lvgl) + return var + + +@automation.register_condition( + "lvgl.is_idle", + LvglCondition, + LVGL_SCHEMA.extend( + { + cv.Required(CONF_TIMEOUT): cv.templatable( + cv.positive_time_period_milliseconds + ) + } + ), +) +async def lvgl_is_idle(config, condition_id, template_arg, args): + lvgl = config[CONF_LVGL_ID] + timeout = await cg.templatable(config[CONF_TIMEOUT], [], cg.uint32) + with LambdaContext( + [(LvglComponentPtr, "lvgl_comp")], return_type=cg.bool_ + ) as context: + lv_add(ReturnStatement(lvgl_comp.is_idle(timeout))) + var = cg.new_Pvariable(condition_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, lvgl) + return var + + +@automation.register_action( + "lvgl.widget.redraw", + ObjUpdateAction, + cv.Schema( + { + cv.Optional(CONF_ID): cv.use_id(lv_obj_t), + cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), + } + ), +) +async def obj_invalidate_to_code(config, action_id, template_arg, args): + if CONF_ID in config: + w = await get_widget(config) + else: + w = lv_scr_act + with LambdaContext() as context: + add_line_marks(action_id) + lv_obj.invalidate(w.obj) + return await action_to_code(context.get_code(), action_id, w, template_arg, args) + + +@automation.register_action( + "lvgl.pause", + LvglAction, + { + cv.GenerateID(): cv.use_id(LvglComponent), + cv.Optional(CONF_SHOW_SNOW, default=False): lv_bool, + }, +) +async def pause_action_to_code(config, action_id, template_arg, args): + with LambdaContext([(LvglComponentPtr, "lvgl_comp")]) as context: + add_line_marks(action_id) + lv_add(lvgl_comp.set_paused(True, config[CONF_SHOW_SNOW])) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, config[CONF_ID]) + return var + + +@automation.register_action( + "lvgl.resume", + LvglAction, + { + cv.GenerateID(): cv.use_id(LvglComponent), + }, +) +async def resume_action_to_code(config, action_id, template_arg, args): + with LambdaContext([(LvglComponentPtr, "lvgl_comp")]) as context: + add_line_marks(action_id) + lv_add(lvgl_comp.set_paused(False, False)) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, config[CONF_ID]) + return var + + +@automation.register_action("lvgl.widget.disable", ObjUpdateAction, ACTION_SCHEMA) +async def obj_disable_to_code(config, action_id, template_arg, args): + w = await get_widget(config) + with LambdaContext() as context: + add_line_marks(action_id) + w.add_state("LV_STATE_DISABLED") + return await action_to_code(context.get_code(), action_id, w, template_arg, args) + + +@automation.register_action("lvgl.widget.enable", ObjUpdateAction, ACTION_SCHEMA) +async def obj_enable_to_code(config, action_id, template_arg, args): + w = await get_widget(config) + with LambdaContext() as context: + add_line_marks(action_id) + w.clear_state("LV_STATE_DISABLED") + return await action_to_code(context.get_code(), action_id, w, template_arg, args) + + +@automation.register_action("lvgl.widget.hide", ObjUpdateAction, ACTION_SCHEMA) +async def obj_hide_to_code(config, action_id, template_arg, args): + w = await get_widget(config) + with LambdaContext() as context: + add_line_marks(action_id) + w.add_flag("LV_OBJ_FLAG_HIDDEN") + return await action_to_code(context.get_code(), action_id, w, template_arg, args) + + +@automation.register_action("lvgl.widget.show", ObjUpdateAction, ACTION_SCHEMA) +async def obj_show_to_code(config, action_id, template_arg, args): + w = await get_widget(config) + with LambdaContext() as context: + add_line_marks(action_id) + w.clear_flag("LV_OBJ_FLAG_HIDDEN") + return await action_to_code(context.get_code(), action_id, w, template_arg, args) diff --git a/esphome/components/lvgl/btn.py b/esphome/components/lvgl/btn.py index 4f5f88d9e6..064d886d47 100644 --- a/esphome/components/lvgl/btn.py +++ b/esphome/components/lvgl/btn.py @@ -9,9 +9,6 @@ class BtnType(WidgetType): def __init__(self): super().__init__(CONF_BUTTON, LvBoolean("lv_btn_t"), (CONF_MAIN,)) - async def to_code(self, w, config): - return [] - def obj_creator(self, parent: MockObjClass, config: dict): """ LVGL 8 calls buttons `btn` @@ -21,5 +18,8 @@ class BtnType(WidgetType): def get_uses(self): return ("btn",) + async def to_code(self, w, config): + return [] + btn_spec = BtnType() diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index a2b4ac13fb..9f349e3943 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -4,12 +4,32 @@ Constants already defined in esphome.const are not duplicated here and must be i """ +from typing import Union + from esphome import codegen as cg, config_validation as cv from esphome.core import ID, Lambda +from esphome.cpp_generator import Literal from esphome.cpp_types import uint32 from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor -from .lvcode import ConstantLiteral +from .helpers import requires_component + + +class ConstantLiteral(Literal): + __slots__ = ("constant",) + + def __init__(self, constant: str): + super().__init__() + self.constant = constant + + def __str__(self): + return self.constant + + +def literal(arg: Union[str, ConstantLiteral]): + if isinstance(arg, str): + return ConstantLiteral(arg) + return arg class LValidator: @@ -18,14 +38,19 @@ class LValidator: has `process()` to convert a value during code generation """ - def __init__(self, validator, rtype, idtype=None, idexpr=None, retmapper=None): + def __init__( + self, validator, rtype, idtype=None, idexpr=None, retmapper=None, requires=None + ): self.validator = validator self.rtype = rtype self.idtype = idtype self.idexpr = idexpr self.retmapper = retmapper + self.requires = requires def __call__(self, value): + if self.requires: + value = requires_component(self.requires)(value) if isinstance(value, cv.Lambda): return cv.returning_lambda(value) if self.idtype is not None and isinstance(value, ID): @@ -422,6 +447,7 @@ CONF_RECOLOR = "recolor" CONF_RIGHT_BUTTON = "right_button" CONF_ROLLOVER = "rollover" CONF_ROOT_BACK_BTN = "root_back_btn" +CONF_ROTARY_ENCODERS = "rotary_encoders" CONF_ROWS = "rows" CONF_SCALES = "scales" CONF_SCALE_LINES = "scale_lines" diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 533dc582f0..818bde6aed 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components.binary_sensor import BinarySensor from esphome.components.color import ColorStruct from esphome.components.font import Font +from esphome.components.image import Image_ from esphome.components.sensor import Sensor from esphome.components.text_sensor import TextSensor import esphome.config_validation as cv @@ -13,22 +14,15 @@ from esphome.helpers import cpp_string_escape from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from . import types as ty -from .defines import LV_FONTS, LValidator, LvConstant +from .defines import LV_FONTS, ConstantLiteral, LValidator, LvConstant, literal from .helpers import ( esphome_fonts_used, lv_fonts_used, lvgl_components_required, requires_component, ) -from .lvcode import ConstantLiteral, lv_expr -from .types import lv_font_t - - -def literal_mapper(value, args=()): - if isinstance(value, str): - return ConstantLiteral(value) - return value - +from .lvcode import lv_expr +from .types import lv_font_t, lv_img_t opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") @@ -43,7 +37,7 @@ def opacity_validator(value): return value -opacity = LValidator(opacity_validator, uint32, retmapper=literal_mapper) +opacity = LValidator(opacity_validator, uint32, retmapper=literal) @schema_extractor("one_of") @@ -79,9 +73,7 @@ def pixels_or_percent_validator(value): return f"lv_pct({int(cv.percentage(value) * 100)})" -pixels_or_percent = LValidator( - pixels_or_percent_validator, uint32, retmapper=literal_mapper -) +pixels_or_percent = LValidator(pixels_or_percent_validator, uint32, retmapper=literal) def zoom(value): @@ -115,7 +107,7 @@ def size_validator(value): return f"lv_pct({int(cv.percentage(value) * 100)})" -size = LValidator(size_validator, uint32, retmapper=literal_mapper) +size = LValidator(size_validator, uint32, retmapper=literal) radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") @@ -130,21 +122,37 @@ def radius_validator(value): return value +radius = LValidator(radius_validator, uint32, retmapper=literal) + + def id_name(value): if value == SCHEMA_EXTRACT: return "id" return cv.validate_id_name(value) -radius = LValidator(radius_validator, uint32, retmapper=literal_mapper) - - def stop_value(value): return cv.int_range(0, 255)(value) +lv_images_used = set() + + +def image_validator(value): + value = requires_component("image")(value) + value = cv.use_id(Image_)(value) + lv_images_used.add(value) + return value + + +lv_image = LValidator( + image_validator, + lv_img_t, + retmapper=lambda x: lv_expr.img_from(MockObj(x)), + requires="image", +) lv_bool = LValidator( - cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal_mapper + cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal ) diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 13b4862b4d..3a8a958f2e 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -8,8 +8,8 @@ from esphome.cpp_generator import ( AssignmentExpression, CallExpression, Expression, + ExpressionStatement, LambdaExpression, - Literal, MockObj, RawExpression, RawStatement, @@ -19,7 +19,9 @@ from esphome.cpp_generator import ( statement, ) +from .defines import ConstantLiteral from .helpers import get_line_marks +from .types import lv_group_t _LOGGER = logging.getLogger(__name__) @@ -105,29 +107,40 @@ class LambdaContext(CodeContext): def __init__( self, - parameters: list[tuple[SafeExpType, str]], - return_type: SafeExpType = None, + parameters: list[tuple[SafeExpType, str]] = None, + return_type: SafeExpType = cg.void, + capture: str = "", ): super().__init__() self.code_list: list[Statement] = [] self.parameters = parameters self.return_type = return_type + self.capture = capture def add(self, expression: Union[Expression, Statement]): self.code_list.append(expression) return expression - async def code(self) -> LambdaExpression: + async def get_lambda(self) -> LambdaExpression: + code_text = self.get_code() + return await cg.process_lambda( + Lambda("\n".join(code_text) + "\n\n"), + self.parameters, + capture=self.capture, + return_type=self.return_type, + ) + + def get_code(self): code_text = [] for exp in self.code_list: text = str(statement(exp)) text = text.rstrip() code_text.append(text) - return await cg.process_lambda( - Lambda("\n".join(code_text) + "\n\n"), - self.parameters, - return_type=self.return_type, - ) + return code_text + + def __enter__(self): + super().__enter__() + return self class LocalVariable(MockObj): @@ -187,13 +200,18 @@ class MockLv: return result def cond_if(self, expression: Expression): - CodeContext.append(RawExpression(f"if({expression}) {{")) + CodeContext.append(RawStatement(f"if {expression} {{")) def cond_else(self): - CodeContext.append(RawExpression("} else {")) + CodeContext.append(RawStatement("} else {")) def cond_endif(self): - CodeContext.append(RawExpression("}")) + CodeContext.append(RawStatement("}")) + + +class ReturnStatement(ExpressionStatement): + def __str__(self): + return f"return {self.expression};" class LvExpr(MockLv): @@ -210,6 +228,7 @@ lv = MockLv("lv_") lv_expr = LvExpr("lv_") # Mock for lv_obj_ calls lv_obj = MockLv("lv_obj_") +lvgl_comp = MockObj("lvgl_comp", "->") # equivalent to cg.add() for the lvgl init context @@ -226,12 +245,19 @@ def lv_assign(target, expression): lv_add(RawExpression(f"{target} = {expression}")) -class ConstantLiteral(Literal): - __slots__ = ("constant",) +lv_groups = {} # Widget group names - def __init__(self, constant: str): - super().__init__() - self.constant = constant - def __str__(self): - return self.constant +def add_group(name): + if name is None: + return None + fullname = f"lv_esp_group_{name}" + if name not in lv_groups: + gid = ID(fullname, True, type=lv_group_t.operator("ptr")) + lv_add( + AssignmentExpression( + type_=gid.type, modifier="", name=fullname, rhs=lv_expr.group_create() + ) + ) + lv_groups[name] = ConstantLiteral(fullname) + return lv_groups[name] diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 74a1b0e7af..34f8eaf21f 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -19,13 +19,35 @@ void LvglComponent::draw_buffer_(const lv_area_t *area, const uint8_t *ptr) { } void LvglComponent::flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { - auto now = millis(); - this->draw_buffer_(area, (const uint8_t *) color_p); - ESP_LOGV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area), - lv_area_get_height(area), (int) (millis() - now)); + if (!this->paused_) { + auto now = millis(); + this->draw_buffer_(area, (const uint8_t *) color_p); + ESP_LOGV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area), + lv_area_get_height(area), (int) (millis() - now)); + } lv_disp_flush_ready(disp_drv); } +void LvglComponent::write_random_() { + // length of 2 lines in 32 bit units + // we write 2 lines for the benefit of displays that won't write one line at a time. + size_t line_len = this->disp_drv_.hor_res * LV_COLOR_DEPTH / 8 / 4 * 2; + for (size_t i = 0; i != line_len; i++) { + ((uint32_t *) (this->draw_buf_.buf1))[i] = random_uint32(); + } + lv_area_t area; + area.x1 = 0; + area.x2 = this->disp_drv_.hor_res - 1; + if (this->snow_line_ == this->disp_drv_.ver_res / 2) { + area.y1 = static_cast(random_uint32() % (this->disp_drv_.ver_res / 2) * 2); + } else { + area.y1 = this->snow_line_++ * 2; + } + // write 2 lines + area.y2 = area.y1 + 1; + this->draw_buffer_(&area, (const uint8_t *) this->draw_buf_.buf1); +} + void LvglComponent::setup() { ESP_LOGCONFIG(TAG, "LVGL Setup starts"); #if LV_USE_LOG @@ -74,10 +96,53 @@ void LvglComponent::setup() { ESP_LOGV(TAG, "sw_rotate = %d, rotated=%d", this->disp_drv_.sw_rotate, this->disp_drv_.rotated); this->disp_ = lv_disp_drv_register(&this->disp_drv_); for (const auto &v : this->init_lambdas_) - v(this->disp_); + v(this); lv_disp_trig_activity(this->disp_); ESP_LOGCONFIG(TAG, "LVGL Setup complete"); } + +#ifdef USE_LVGL_IMAGE +lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { + if (img_dsc == nullptr) + img_dsc = new lv_img_dsc_t(); // NOLINT + img_dsc->header.always_zero = 0; + img_dsc->header.reserved = 0; + img_dsc->header.w = src->get_width(); + img_dsc->header.h = src->get_height(); + img_dsc->data = src->get_data_start(); + img_dsc->data_size = image_type_to_width_stride(img_dsc->header.w * img_dsc->header.h, src->get_type()); + switch (src->get_type()) { + case image::IMAGE_TYPE_BINARY: + img_dsc->header.cf = LV_IMG_CF_ALPHA_1BIT; + break; + + case image::IMAGE_TYPE_GRAYSCALE: + img_dsc->header.cf = LV_IMG_CF_ALPHA_8BIT; + break; + + case image::IMAGE_TYPE_RGB24: + img_dsc->header.cf = LV_IMG_CF_RGB888; + break; + + case image::IMAGE_TYPE_RGB565: +#if LV_COLOR_DEPTH == 16 + img_dsc->header.cf = src->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR; +#else + img_dsc->header.cf = LV_IMG_CF_RGB565; +#endif + break; + + case image::IMAGE_TYPE_RGBA: +#if LV_COLOR_DEPTH == 32 + img_dsc->header.cf = LV_IMG_CF_TRUE_COLOR; +#else + img_dsc->header.cf = LV_IMG_CF_RGBA8888; +#endif + break; + } + return img_dsc; +} +#endif } // namespace lvgl } // namespace esphome diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index a884a27042..a0d3d226ce 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -1,23 +1,32 @@ #pragma once #include "esphome/core/defines.h" -#ifdef USE_LVGL + +#ifdef USE_LVGL_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif // USE_LVGL_BINARY_SENSOR +#ifdef USE_LVGL_ROTARY_ENCODER +#include "esphome/components/rotary_encoder/rotary_encoder.h" +#endif // USE_LVGL_ROTARY_ENCODER // required for clang-tidy #ifndef LV_CONF_H #define LV_CONF_SKIP 1 // NOLINT -#endif +#endif // LV_CONF_H #include "esphome/components/display/display.h" #include "esphome/components/display/display_color_utils.h" #include "esphome/core/component.h" -#include "esphome/core/hal.h" #include "esphome/core/log.h" #include +#include #include +#ifdef USE_LVGL_IMAGE +#include "esphome/components/image/image.h" +#endif // USE_LVGL_IMAGE #ifdef USE_LVGL_FONT #include "esphome/components/font/font.h" -#endif +#endif // USE_LVGL_FONT #ifdef USE_LVGL_TOUCHSCREEN #include "esphome/components/touchscreen/touchscreen.h" #endif // USE_LVGL_TOUCHSCREEN @@ -40,7 +49,7 @@ static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BIT // Parent class for things that wrap an LVGL object class LvCompound final { public: - virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } + void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } lv_obj_t *obj{}; }; @@ -49,6 +58,15 @@ using set_value_lambda_t = std::function; using event_callback_t = void(_lv_event_t *); using text_lambda_t = std::function; +template class ObjUpdateAction : public Action { + public: + explicit ObjUpdateAction(std::function &&lamb) : lamb_(std::move(lamb)) {} + + void play(Ts... x) override { this->lamb_(x...); } + + protected: + std::function lamb_; +}; #ifdef USE_LVGL_FONT class FontEngine { public: @@ -67,6 +85,9 @@ class FontEngine { lv_font_t lv_font_{}; }; #endif // USE_LVGL_FONT +#ifdef USE_LVGL_IMAGE +lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc = nullptr); +#endif // USE_LVGL_IMAGE class LvglComponent : public PollingComponent { constexpr static const char *const TAG = "lvgl"; @@ -92,27 +113,54 @@ class LvglComponent : public PollingComponent { area->y2++; } - void loop() override { lv_timer_handler_run_in_period(5); } void setup() override; - void update() override {} + void update() override { + // update indicators + if (this->paused_) { + return; + } + this->idle_callbacks_.call(lv_disp_get_inactive_time(this->disp_)); + } + void loop() override { + if (this->paused_) { + if (this->show_snow_) + this->write_random_(); + } + lv_timer_handler_run_in_period(5); + } + + void add_on_idle_callback(std::function &&callback) { + this->idle_callbacks_.add(std::move(callback)); + } void add_display(display::Display *display) { this->displays_.push_back(display); } - void add_init_lambda(const std::function &lamb) { this->init_lambdas_.push_back(lamb); } + void add_init_lambda(const std::function &lamb) { this->init_lambdas_.push_back(lamb); } void dump_config() override; void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; } + bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; } void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } lv_disp_t *get_disp() { return this->disp_; } void set_paused(bool paused, bool show_snow) { this->paused_ = paused; + this->show_snow_ = show_snow; + this->snow_line_ = 0; if (!paused && lv_scr_act() != nullptr) { lv_disp_trig_activity(this->disp_); // resets the inactivity time lv_obj_invalidate(lv_scr_act()); } } + + void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) { + lv_obj_add_event_cb(obj, callback, event, this); + if (event == LV_EVENT_VALUE_CHANGED) { + lv_obj_add_event_cb(obj, callback, lv_custom_event, this); + } + } bool is_paused() const { return this->paused_; } protected: + void write_random_(); void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); std::vector displays_{}; @@ -120,12 +168,52 @@ class LvglComponent : public PollingComponent { lv_disp_drv_t disp_drv_{}; lv_disp_t *disp_{}; bool paused_{}; + bool show_snow_{}; + lv_coord_t snow_line_{}; - std::vector> init_lambdas_; + std::vector> init_lambdas_; + CallbackManager idle_callbacks_{}; size_t buffer_frac_{1}; bool full_refresh_{}; }; +class IdleTrigger : public Trigger<> { + public: + explicit IdleTrigger(LvglComponent *parent, TemplatableValue timeout) : timeout_(std::move(timeout)) { + parent->add_on_idle_callback([this](uint32_t idle_time) { + if (!this->is_idle_ && idle_time > this->timeout_.value()) { + this->is_idle_ = true; + this->trigger(); + } else if (this->is_idle_ && idle_time < this->timeout_.value()) { + this->is_idle_ = false; + } + }); + } + + protected: + TemplatableValue timeout_; + bool is_idle_{}; +}; + +template class LvglAction : public Action, public Parented { + public: + explicit LvglAction(std::function &&lamb) : action_(std::move(lamb)) {} + void play(Ts... x) override { this->action_(this->parent_); } + + protected: + std::function action_{}; +}; + +template class LvglCondition : public Condition, public Parented { + public: + LvglCondition(std::function &&condition_lambda) + : condition_lambda_(std::move(condition_lambda)) {} + bool check(Ts... x) override { return this->condition_lambda_(this->parent_); } + + protected: + std::function condition_lambda_{}; +}; + #ifdef USE_LVGL_TOUCHSCREEN class LVTouchListener : public touchscreen::TouchListener, public Parented { public: @@ -160,7 +248,62 @@ class LVTouchListener : public touchscreen::TouchListener, public Parented { + public: + LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { + lv_indev_drv_init(&this->drv_); + this->drv_.type = type; + this->drv_.user_data = this; + this->drv_.long_press_time = lpt; + this->drv_.long_press_repeat_time = lprt; + this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { + auto *l = static_cast(d->user_data); + data->state = l->pressed_ ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; + data->key = l->key_; + data->enc_diff = (int16_t) (l->count_ - l->last_count_); + l->last_count_ = l->count_; + data->continue_reading = false; + }; + } + + void set_left_button(binary_sensor::BinarySensor *left_button) { + left_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_LEFT, state); }); + } + void set_right_button(binary_sensor::BinarySensor *right_button) { + right_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_RIGHT, state); }); + } + + void set_enter_button(binary_sensor::BinarySensor *enter_button) { + enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); }); + } + + void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor) { + sensor->register_listener([this](int32_t count) { this->set_count(count); }); + } + + void event(int key, bool pressed) { + if (!this->parent_->is_paused()) { + this->pressed_ = pressed; + this->key_ = key; + } + } + + void set_count(int32_t count) { + if (!this->parent_->is_paused()) + this->count_ = count; + } + + lv_indev_drv_t *get_drv() { return &this->drv_; } + + protected: + lv_indev_drv_t drv_{}; + bool pressed_{}; + int32_t count_{}; + int32_t last_count_{}; + int key_{}; +}; +#endif // USE_LVGL_KEY_LISTENER } // namespace lvgl } // namespace esphome - -#endif // USE_LVGL diff --git a/esphome/components/lvgl/obj.py b/esphome/components/lvgl/obj.py index 92c4f63d2d..40d7e55381 100644 --- a/esphome/components/lvgl/obj.py +++ b/esphome/components/lvgl/obj.py @@ -1,5 +1,9 @@ +from esphome import automation + +from .automation import update_to_code from .defines import CONF_MAIN, CONF_OBJ -from .types import WidgetType, lv_obj_t +from .schemas import create_modify_schema +from .types import ObjUpdateAction, WidgetType, lv_obj_t class ObjType(WidgetType): @@ -15,3 +19,10 @@ class ObjType(WidgetType): obj_spec = ObjType() + + +@automation.register_action( + "lvgl.widget.update", ObjUpdateAction, create_modify_schema(obj_spec) +) +async def obj_update_to_code(config, action_id, template_arg, args): + return await update_to_code(config, action_id, template_arg, args) diff --git a/esphome/components/lvgl/rotary_encoders.py b/esphome/components/lvgl/rotary_encoders.py new file mode 100644 index 0000000000..77dc397c3e --- /dev/null +++ b/esphome/components/lvgl/rotary_encoders.py @@ -0,0 +1,62 @@ +import esphome.codegen as cg +from esphome.components.binary_sensor import BinarySensor +from esphome.components.rotary_encoder.sensor import RotaryEncoderSensor +import esphome.config_validation as cv +from esphome.const import CONF_GROUP, CONF_ID, CONF_SENSOR + +from .defines import ( + CONF_ENTER_BUTTON, + CONF_LEFT_BUTTON, + CONF_LONG_PRESS_REPEAT_TIME, + CONF_LONG_PRESS_TIME, + CONF_RIGHT_BUTTON, + CONF_ROTARY_ENCODERS, +) +from .helpers import lvgl_components_required +from .lvcode import add_group, lv, lv_add, lv_expr +from .schemas import ENCODER_SCHEMA +from .types import lv_indev_type_t + +ROTARY_ENCODER_CONFIG = cv.ensure_list( + ENCODER_SCHEMA.extend( + { + cv.Required(CONF_ENTER_BUTTON): cv.use_id(BinarySensor), + cv.Required(CONF_SENSOR): cv.Any( + cv.use_id(RotaryEncoderSensor), + cv.Schema( + { + cv.Required(CONF_LEFT_BUTTON): cv.use_id(BinarySensor), + cv.Required(CONF_RIGHT_BUTTON): cv.use_id(BinarySensor), + } + ), + ), + } + ) +) + + +async def rotary_encoders_to_code(var, config): + for enc_conf in config.get(CONF_ROTARY_ENCODERS, ()): + lvgl_components_required.add("KEY_LISTENER") + lvgl_components_required.add("ROTARY_ENCODER") + lpt = enc_conf[CONF_LONG_PRESS_TIME].total_milliseconds + lprt = enc_conf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds + listener = cg.new_Pvariable( + enc_conf[CONF_ID], lv_indev_type_t.LV_INDEV_TYPE_ENCODER, lpt, lprt + ) + await cg.register_parented(listener, var) + if sensor_config := enc_conf.get(CONF_SENSOR): + if isinstance(sensor_config, dict): + b_sensor = await cg.get_variable(sensor_config[CONF_LEFT_BUTTON]) + cg.add(listener.set_left_button(b_sensor)) + b_sensor = await cg.get_variable(sensor_config[CONF_RIGHT_BUTTON]) + cg.add(listener.set_right_button(b_sensor)) + else: + sensor_config = await cg.get_variable(sensor_config) + lv_add(listener.set_sensor(sensor_config)) + b_sensor = await cg.get_variable(enc_conf[CONF_ENTER_BUTTON]) + cg.add(listener.set_enter_button(b_sensor)) + if group := add_group(enc_conf.get(CONF_GROUP)): + lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) + else: + lv.indev_drv_register(listener.get_drv()) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 9f6d984545..ebef56a882 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -1,10 +1,21 @@ from esphome import config_validation as cv -from esphome.const import CONF_ARGS, CONF_FORMAT, CONF_ID, CONF_STATE, CONF_TYPE +from esphome.automation import Trigger, validate_automation +from esphome.const import ( + CONF_ARGS, + CONF_FORMAT, + CONF_GROUP, + CONF_ID, + CONF_ON_VALUE, + CONF_STATE, + CONF_TRIGGER_ID, + CONF_TYPE, +) +from esphome.core import TimePeriod from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid, types as ty from .helpers import add_lv_use, requires_component, validate_printf -from .lv_validation import lv_font +from .lv_validation import id_name, lv_font from .types import WIDGET_TYPES, WidgetType # A schema for text properties @@ -27,6 +38,28 @@ TEXT_SCHEMA = cv.Schema( } ) +ACTION_SCHEMA = cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(ty.lv_pseudo_button_t), + }, + key=CONF_ID, +) + +PRESS_TIME = cv.All( + lvalid.lv_milliseconds, cv.Range(max=TimePeriod(milliseconds=65535)) +) + +ENCODER_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.All( + cv.declare_id(ty.LVEncoderListener), requires_component("binary_sensor") + ), + cv.Optional(CONF_GROUP): lvalid.id_name, + cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, + cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, + } +) + # All LVGL styles and their validators STYLE_PROPS = { "align": df.CHILD_ALIGNMENTS.one_of, @@ -43,6 +76,7 @@ STYLE_PROPS = { "bg_image_opa": lvalid.opacity, "bg_image_recolor": lvalid.lv_color, "bg_image_recolor_opa": lvalid.opacity, + "bg_image_src": lvalid.lv_image, "bg_main_stop": lvalid.stop_value, "bg_opa": lvalid.opacity, "border_color": lvalid.lv_color, @@ -151,6 +185,39 @@ def part_schema(widget_type: WidgetType): ) +def automation_schema(typ: ty.LvType): + if typ.has_on_value: + events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,) + else: + events = df.LV_EVENT_TRIGGERS + if isinstance(typ, ty.LvType): + template = Trigger.template(typ.get_arg_type()) + else: + template = Trigger.template() + return { + cv.Optional(event): validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(template), + } + ) + for event in events + } + + +def create_modify_schema(widget_type): + return ( + part_schema(widget_type) + .extend( + { + cv.Required(CONF_ID): cv.use_id(widget_type), + cv.Optional(CONF_STATE): SET_STATE_SCHEMA, + } + ) + .extend(FLAG_SCHEMA) + .extend(widget_type.modify_schema) + ) + + def obj_schema(widget_type: WidgetType): """ Create a schema for a widget type itself i.e. no allowance for children @@ -161,10 +228,12 @@ def obj_schema(widget_type: WidgetType): part_schema(widget_type) .extend(FLAG_SCHEMA) .extend(ALIGN_TO_SCHEMA) + .extend(automation_schema(widget_type.w_type)) .extend( cv.Schema( { cv.Optional(CONF_STATE): SET_STATE_SCHEMA, + cv.Optional(CONF_GROUP): id_name, } ) ) @@ -188,6 +257,13 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value( STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT ) +# For use by platform components +LVGL_SCHEMA = cv.Schema( + { + cv.GenerateID(df.CONF_LVGL_ID): cv.use_id(ty.LvglComponent), + } +) + ALL_STYLES = { **STYLE_PROPS, } diff --git a/esphome/components/lvgl/touchscreens.py b/esphome/components/lvgl/touchscreens.py index a0d4a3e4ad..499b33aa02 100644 --- a/esphome/components/lvgl/touchscreens.py +++ b/esphome/components/lvgl/touchscreens.py @@ -2,7 +2,7 @@ import esphome.codegen as cg from esphome.components.touchscreen import CONF_TOUCHSCREEN_ID, Touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID -from esphome.core import CORE, TimePeriod +from esphome.core import CORE from .defines import ( CONF_LONG_PRESS_REPEAT_TIME, @@ -10,11 +10,10 @@ from .defines import ( CONF_TOUCHSCREENS, ) from .helpers import lvgl_components_required -from .lv_validation import lv_milliseconds from .lvcode import lv +from .schemas import PRESS_TIME from .types import LVTouchListener -PRESS_TIME = cv.All(lv_milliseconds, cv.Range(max=TimePeriod(milliseconds=65535))) CONF_TOUCHSCREEN = "touchscreen" TOUCHSCREENS_CONFIG = cv.maybe_simple_value( { diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py new file mode 100644 index 0000000000..bf92bda5b0 --- /dev/null +++ b/esphome/components/lvgl/trigger.py @@ -0,0 +1,61 @@ +from esphome import automation +import esphome.codegen as cg +from esphome.const import CONF_ID, CONF_ON_VALUE, CONF_TRIGGER_ID + +from .defines import ( + CONF_ALIGN, + CONF_ALIGN_TO, + CONF_X, + CONF_Y, + LV_EVENT, + LV_EVENT_TRIGGERS, + literal, +) +from .lvcode import LambdaContext, add_line_marks, lv, lv_add +from .widget import widget_map + +lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") + + +async def generate_triggers(lv_component): + """ + Generate LVGL triggers for all defined widgets + Must be done after all widgets completed + :param lv_component: The parent component + :return: + """ + + for w in widget_map.values(): + if w.config: + for event, conf in { + event: conf + for event, conf in w.config.items() + if event in LV_EVENT_TRIGGERS + }.items(): + conf = conf[0] + w.add_flag("LV_OBJ_FLAG_CLICKABLE") + event = "LV_EVENT_" + LV_EVENT[event[3:].upper()] + await add_trigger(conf, event, lv_component, w) + for conf in w.config.get(CONF_ON_VALUE, ()): + await add_trigger(conf, "LV_EVENT_VALUE_CHANGED", lv_component, w) + + # Generate align to directives while we're here + if align_to := w.config.get(CONF_ALIGN_TO): + target = widget_map[align_to[CONF_ID]].obj + align = align_to[CONF_ALIGN] + x = align_to[CONF_X] + y = align_to[CONF_Y] + lv.obj_align_to(w.obj, target, align, x, y) + + +async def add_trigger(conf, event, lv_component, w): + tid = conf[CONF_TRIGGER_ID] + add_line_marks(tid) + trigger = cg.new_Pvariable(tid) + args = w.get_args() + value = w.get_value() + await automation.build_automation(trigger, args, conf) + with LambdaContext([(lv_event_t_ptr, "event_data")]) as context: + add_line_marks(tid) + lv_add(trigger.trigger(value)) + lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), literal(event))) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index 60291ea54a..6997207dac 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -1,4 +1,4 @@ -from esphome import codegen as cg +from esphome import automation, codegen as cg from esphome.core import ID from esphome.cpp_generator import MockObjClass @@ -23,8 +23,14 @@ lvgl_ns = cg.esphome_ns.namespace("lvgl") char_ptr = cg.global_ns.namespace("char").operator("ptr") void_ptr = cg.void.operator("ptr") LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) +LvglComponentPtr = LvglComponent.operator("ptr") lv_event_code_t = cg.global_ns.namespace("lv_event_code_t") +lv_indev_type_t = cg.global_ns.enum("lv_indev_type_t") FontEngine = lvgl_ns.class_("FontEngine") +IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template()) +ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action) +LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition) +LvglAction = lvgl_ns.class_("LvglAction", automation.Action) LvCompound = lvgl_ns.class_("LvCompound") lv_font_t = cg.global_ns.class_("lv_font_t") lv_style_t = cg.global_ns.struct("lv_style_t") @@ -33,9 +39,11 @@ lv_obj_base_t = cg.global_ns.class_("lv_obj_t", lv_pseudo_button_t) lv_obj_t_ptr = lv_obj_base_t.operator("ptr") lv_disp_t_ptr = cg.global_ns.struct("lv_disp_t").operator("ptr") lv_color_t = cg.global_ns.struct("lv_color_t") +lv_group_t = cg.global_ns.struct("lv_group_t") LVTouchListener = lvgl_ns.class_("LVTouchListener") LVEncoderListener = lvgl_ns.class_("LVEncoderListener") lv_obj_t = LvType("lv_obj_t") +lv_img_t = LvType("lv_img_t") # this will be populated later, in __init__.py to avoid circular imports. @@ -58,7 +66,7 @@ class LvBoolean(LvType): super().__init__( *args, largs=[(cg.bool_, "x")], - lvalue=lambda w: w.is_checked(), + lvalue=lambda w: w.has_state("LV_STATE_CHECKED"), has_on_value=True, **kwargs, ) @@ -83,11 +91,14 @@ class WidgetType: self.name = name self.w_type = w_type self.parts = parts - self.schema = schema or {} - if modify_schema is None: - self.modify_schema = schema + if schema is None: + self.schema = {} else: - self.modify_schema = modify_schema + self.schema = schema + if modify_schema is None: + self.modify_schema = self.schema + else: + self.modify_schema = self.schema @property def animated(self): diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widget.py index 4755d8b21d..83aed341e7 100644 --- a/esphome/components/lvgl/widget.py +++ b/esphome/components/lvgl/widget.py @@ -4,9 +4,9 @@ from typing import Any from esphome import codegen as cg, config_validation as cv from esphome.config_validation import Invalid from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE -from esphome.core import ID, TimePeriod +from esphome.core import CORE, TimePeriod from esphome.coroutine import FakeAwaitable -from esphome.cpp_generator import MockObjClass +from esphome.cpp_generator import MockObj, MockObjClass, VariableDeclarationExpression from .defines import ( CONF_DEFAULT, @@ -16,13 +16,15 @@ from .defines import ( OBJ_FLAGS, PARTS, STATES, + ConstantLiteral, LValidator, join_enums, + literal, ) from .helpers import add_lv_use -from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj +from .lvcode import add_group, add_line_marks, lv, lv_add, lv_assign, lv_expr, lv_obj from .schemas import ALL_STYLES, STYLE_REMAP -from .types import WIDGET_TYPES, WidgetType, lv_obj_t +from .types import WIDGET_TYPES, LvType, WidgetType, lv_obj_t, lv_obj_t_ptr EVENT_LAMB = "event_lamb__" @@ -76,17 +78,20 @@ class Widget: return f"{self.var}->obj" return self.var - def add_state(self, *args): - return lv_obj.add_state(self.obj, *args) + def add_state(self, state): + return lv_obj.add_state(self.obj, literal(state)) - def clear_state(self, *args): - return lv_obj.clear_state(self.obj, *args) + def clear_state(self, state): + return lv_obj.clear_state(self.obj, literal(state)) - def add_flag(self, *args): - return lv_obj.add_flag(self.obj, *args) + def has_state(self, state): + return lv_expr.obj_get_state(self.obj) & literal(state) != 0 - def clear_flag(self, *args): - return lv_obj.clear_flag(self.obj, *args) + def add_flag(self, flag): + return lv_obj.add_flag(self.obj, literal(flag)) + + def clear_flag(self, flag): + return lv_obj.clear_flag(self.obj, literal(flag)) def set_property(self, prop, value, animated: bool = None, ltype=None): if isinstance(value, dict): @@ -125,6 +130,16 @@ class Widget: def __str__(self): return f"({self.var}, {self.type})" + def get_args(self): + if isinstance(self.type.w_type, LvType): + return self.type.w_type.args + return [(lv_obj_t_ptr, "obj")] + + def get_value(self): + if isinstance(self.type.w_type, LvType): + return self.type.w_type.value(self) + return self.obj + # Map of widgets to their config, used for trigger generation widget_map: dict[Any, Widget] = {} @@ -146,7 +161,8 @@ def get_widget_generator(wid): yield -async def get_widget(wid: ID) -> Widget: +async def get_widget(config: dict, id: str = CONF_ID) -> Widget: + wid = config[id] if obj := widget_map.get(wid): return obj return await FakeAwaitable(get_widget_generator(wid)) @@ -204,9 +220,10 @@ async def set_obj_properties(w: Widget, config): }.items(): if isinstance(ALL_STYLES[prop], LValidator): value = await ALL_STYLES[prop].process(value) - # Remapping for backwards compatibility of style names prop_r = STYLE_REMAP.get(prop, prop) w.set_style(prop_r, value, lv_state) + if group := add_group(config.get(CONF_GROUP)): + lv.group_add_obj(group, w.obj) flag_clr = set() flag_set = set() props = parts[CONF_MAIN][CONF_DEFAULT] @@ -241,7 +258,7 @@ async def set_obj_properties(w: Widget, config): w.clear_state(clears) for key, value in lambs.items(): lamb = await cg.process_lambda(value, [], return_type=cg.bool_) - state = ConstantLiteral(f"LV_STATE_{key.upper}") + state = f"LV_STATE_{key.upper}" lv.cond_if(lamb) w.add_state(state) lv.cond_else() @@ -281,10 +298,19 @@ async def widget_to_code(w_cnfig, w_type, parent): var = cg.new_Pvariable(wid) lv_add(var.set_obj(creator)) else: - var = cg.Pvariable(wid, cg.nullptr, type_=lv_obj_t) + var = MockObj(wid, "->") + decl = VariableDeclarationExpression(lv_obj_t, "*", wid) + CORE.add_global(decl) + CORE.register_variable(wid, var) lv_assign(var, creator) widget = Widget.create(wid, var, spec, w_cnfig, parent) await set_obj_properties(widget, w_cnfig) await add_widgets(widget, w_cnfig) await spec.to_code(widget, w_cnfig) + + +lv_scr_act_spec = LvScrActType() +lv_scr_act = Widget.create( + None, ConstantLiteral("lv_scr_act()"), lv_scr_act_spec, {}, parent=None +) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 6ba5b64761..726db24592 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -39,9 +39,12 @@ #define USE_LOCK #define USE_LOGGER #define USE_LVGL +#define USE_LVGL_BINARY_SENSOR #define USE_LVGL_FONT #define USE_LVGL_IMAGE +#define USE_LVGL_KEY_LISTENER #define USE_LVGL_TOUCHSCREEN +#define USE_LVGL_ROTARY_ENCODER #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 696c749876..fde700e0bd 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -7,6 +7,7 @@ lvgl: long_press_time: 500ms widgets: - label: + id: hello_label text: Hello world text_color: 0xFF8000 align: center @@ -95,9 +96,43 @@ lvgl: height: 10% pressed: bg_color: light_blue + checkable: true + checked: + bg_color: 0x000000 widgets: - label: text: Button + on_click: + lvgl.label.update: + id: hello_label + bg_color: 0x123456 + text: clicked + on_value: + logger.log: + format: "state now %d" + args: [x] + on_short_click: + lvgl.widget.hide: hello_label + on_long_press: + lvgl.widget.show: hello_label + on_cancel: + lvgl.widget.enable: hello_label + on_ready: + lvgl.widget.disable: hello_label + on_defocus: + lvgl.widget.hide: hello_label + on_focus: + logger.log: Button clicked + on_scroll: + logger.log: Button clicked + on_scroll_end: + logger.log: Button clicked + on_scroll_begin: + logger.log: Button clicked + on_release: + logger.log: Button clicked + on_long_press_repeat: + logger.log: Button clicked font: - file: "gfonts://Roboto" diff --git a/tests/components/lvgl/test.esp32-idf.yaml b/tests/components/lvgl/test.esp32-idf.yaml index eab75b05f3..0f740db980 100644 --- a/tests/components/lvgl/test.esp32-idf.yaml +++ b/tests/components/lvgl/test.esp32-idf.yaml @@ -6,6 +6,23 @@ i2c: sda: GPIO18 scl: GPIO19 +sensor: + - platform: rotary_encoder + name: "Rotary Encoder" + id: encoder + pin_a: 2 + pin_b: 1 + internal: true + +binary_sensor: + - platform: gpio + id: pushbutton + name: Pushbutton + pin: + number: 0 + inverted: true + ignore_strapping_warning: true + display: - platform: ili9xxx model: st7789v @@ -50,5 +67,9 @@ lvgl: displays: - tft_display - second_display + rotary_encoders: + sensor: encoder + enter_button: pushbutton + group: general <<: !include common.yaml From dfacf1bbfe3aef5ca6796f92e8a46cb62212e924 Mon Sep 17 00:00:00 2001 From: thevogoncoder <6619878+thevogoncoder@users.noreply.github.com> Date: Thu, 25 Jul 2024 04:06:23 +0200 Subject: [PATCH 2146/2607] Add delay after sending REG_READ_START (#7130) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/pmwcs3/pmwcs3.cpp | 61 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/esphome/components/pmwcs3/pmwcs3.cpp b/esphome/components/pmwcs3/pmwcs3.cpp index 812018b52e..97ce4c9ae0 100644 --- a/esphome/components/pmwcs3/pmwcs3.cpp +++ b/esphome/components/pmwcs3/pmwcs3.cpp @@ -72,43 +72,44 @@ void PMWCS3Component::dump_config() { LOG_SENSOR(" ", "vwc", this->vwc_sensor_); } void PMWCS3Component::read_data_() { - uint8_t data[8]; - float e25, ec, temperature, vwc; - /////// Super important !!!! first activate reading PMWCS3_REG_READ_START (if not, return always the same values) //// - if (!this->write_bytes(PMWCS3_REG_READ_START, nullptr, 0)) { this->status_set_warning(); ESP_LOGVV(TAG, "Failed to write into REG_READ_START register !!!"); return; } - // NOLINT delay(100); - if (!this->read_bytes(PMWCS3_REG_GET_DATA, (uint8_t *) &data, 8)) { - ESP_LOGVV(TAG, "Error reading PMWCS3_REG_GET_DATA registers"); - this->mark_failed(); - return; - } - if (this->e25_sensor_ != nullptr) { - e25 = ((data[1] << 8) | data[0]) / 100.0; - this->e25_sensor_->publish_state(e25); - ESP_LOGVV(TAG, "e25: data[0]=%d, data[1]=%d, result=%f", data[0], data[1], e25); - } - if (this->ec_sensor_ != nullptr) { - ec = ((data[3] << 8) | data[2]) / 10.0; - this->ec_sensor_->publish_state(ec); - ESP_LOGVV(TAG, "ec: data[2]=%d, data[3]=%d, result=%f", data[2], data[3], ec); - } - if (this->temperature_sensor_ != nullptr) { - temperature = ((data[5] << 8) | data[4]) / 100.0; - this->temperature_sensor_->publish_state(temperature); - ESP_LOGVV(TAG, "temp: data[4]=%d, data[5]=%d, result=%f", data[4], data[5], temperature); - } - if (this->vwc_sensor_ != nullptr) { - vwc = ((data[7] << 8) | data[6]) / 10.0; - this->vwc_sensor_->publish_state(vwc); - ESP_LOGVV(TAG, "vwc: data[6]=%d, data[7]=%d, result=%f", data[6], data[7], vwc); - } + // Wait for the sensor to be ready. + // 80ms empirically determined (conservative). + this->set_timeout(80, [this] { + uint8_t data[8]; + float e25, ec, temperature, vwc; + if (!this->read_bytes(PMWCS3_REG_GET_DATA, (uint8_t *) &data, 8)) { + ESP_LOGVV(TAG, "Error reading PMWCS3_REG_GET_DATA registers"); + this->mark_failed(); + return; + } + if (this->e25_sensor_ != nullptr) { + e25 = ((data[1] << 8) | data[0]) / 100.0; + this->e25_sensor_->publish_state(e25); + ESP_LOGVV(TAG, "e25: data[0]=%d, data[1]=%d, result=%f", data[0], data[1], e25); + } + if (this->ec_sensor_ != nullptr) { + ec = ((data[3] << 8) | data[2]) / 10.0; + this->ec_sensor_->publish_state(ec); + ESP_LOGVV(TAG, "ec: data[2]=%d, data[3]=%d, result=%f", data[2], data[3], ec); + } + if (this->temperature_sensor_ != nullptr) { + temperature = ((data[5] << 8) | data[4]) / 100.0; + this->temperature_sensor_->publish_state(temperature); + ESP_LOGVV(TAG, "temp: data[4]=%d, data[5]=%d, result=%f", data[4], data[5], temperature); + } + if (this->vwc_sensor_ != nullptr) { + vwc = ((data[7] << 8) | data[6]) / 10.0; + this->vwc_sensor_->publish_state(vwc); + ESP_LOGVV(TAG, "vwc: data[6]=%d, data[7]=%d, result=%f", data[6], data[7], vwc); + } + }); } } // namespace pmwcs3 From a70f926971264501287ac93b8e39d533461990dc Mon Sep 17 00:00:00 2001 From: RubyBailey <60991881+RubyBailey@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:20:29 -0700 Subject: [PATCH 2147/2607] Fix for Mitsubishi units that only support cooling (#7143) --- esphome/components/mitsubishi/mitsubishi.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index a02aabf14d..449c8fc712 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -110,7 +110,7 @@ void MitsubishiClimate::transmit_state() { // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00 // Byte 16: Constant 0x00 // Byte 17: Checksum: SUM[Byte0...Byte16] - uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x00, + uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; switch (this->mode) { @@ -136,6 +136,12 @@ void MitsubishiClimate::transmit_state() { break; case climate::CLIMATE_MODE_OFF: default: + remote_state[6] = MITSUBISHI_MODE_COOL; + remote_state[8] = MITSUBISHI_MODE_A_COOL; + if (this->supports_heat_) { + remote_state[6] = MITSUBISHI_MODE_HEAT; + remote_state[8] = MITSUBISHI_MODE_A_HEAT; + } remote_state[5] = MITSUBISHI_OFF; break; } From 5ac9d301eaca1d46cc0db942e828a7995289640e Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Tue, 30 Jul 2024 16:57:51 -0400 Subject: [PATCH 2148/2607] [micro_wake_word] Fix VAD detection and modify detection computation (#7164) --- esphome/components/micro_wake_word/streaming_model.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/esphome/components/micro_wake_word/streaming_model.cpp b/esphome/components/micro_wake_word/streaming_model.cpp index 013fa2ce6e..d0d2e2df05 100644 --- a/esphome/components/micro_wake_word/streaming_model.cpp +++ b/esphome/components/micro_wake_word/streaming_model.cpp @@ -148,7 +148,7 @@ WakeWordModel::WakeWordModel(const uint8_t *model_start, float probability_cutof }; bool WakeWordModel::determine_detected() { - int32_t sum = 0; + uint32_t sum = 0; for (auto &prob : this->recent_streaming_probabilities_) { sum += prob; } @@ -175,12 +175,14 @@ VADModel::VADModel(const uint8_t *model_start, float probability_cutoff, size_t }; bool VADModel::determine_detected() { - uint8_t max = 0; + uint32_t sum = 0; for (auto &prob : this->recent_streaming_probabilities_) { - max = std::max(prob, max); + sum += prob; } - return max > this->probability_cutoff_; + float sliding_window_average = static_cast(sum) / static_cast(255 * this->sliding_window_size_); + + return sliding_window_average > this->probability_cutoff_; } } // namespace micro_wake_word From 0af10c58f53466da19d9e065f764124e3bd31810 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 1 Aug 2024 07:51:23 +1200 Subject: [PATCH 2149/2607] Bump version to 2024.7.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 9abfafc4a4..1f63497982 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.7.2" +__version__ = "2024.7.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From cb9906b9215f17903ac004af160cc1537998b5a6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 1 Aug 2024 22:38:36 +1200 Subject: [PATCH 2150/2607] [api] ``homeassistant.action`` replaces ``homeassistant.service`` (#7171) --- esphome/components/api/__init__.py | 130 +++++++++++++-------- esphome/config_validation.py | 10 ++ esphome/const.py | 2 + tests/components/api/common.yaml | 16 +-- tests/components/homeassistant/common.yaml | 8 +- 5 files changed, 103 insertions(+), 63 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index d6b4416af8..38b50d4b9d 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -1,25 +1,27 @@ import base64 -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( + CONF_ACTION, + CONF_ACTIONS, CONF_DATA, CONF_DATA_TEMPLATE, + CONF_EVENT, CONF_ID, CONF_KEY, + CONF_ON_CLIENT_CONNECTED, + CONF_ON_CLIENT_DISCONNECTED, CONF_PASSWORD, CONF_PORT, CONF_REBOOT_TIMEOUT, CONF_SERVICE, - CONF_VARIABLES, CONF_SERVICES, - CONF_TRIGGER_ID, - CONF_EVENT, CONF_TAG, - CONF_ON_CLIENT_CONNECTED, - CONF_ON_CLIENT_DISCONNECTED, + CONF_TRIGGER_ID, + CONF_VARIABLES, ) from esphome.core import coroutine_with_priority @@ -63,40 +65,51 @@ def validate_encryption_key(value): return value -CONFIG_SCHEMA = cv.Schema( +ACTIONS_SCHEMA = automation.validate_automation( { - cv.GenerateID(): cv.declare_id(APIServer), - cv.Optional(CONF_PORT, default=6053): cv.port, - cv.Optional(CONF_PASSWORD, default=""): cv.string_strict, - cv.Optional( - CONF_REBOOT_TIMEOUT, default="15min" - ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_SERVICES): automation.validate_automation( + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger), + cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.valid_name, + cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.valid_name, + cv.Optional(CONF_VARIABLES, default={}): cv.Schema( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger), - cv.Required(CONF_SERVICE): cv.valid_name, - cv.Optional(CONF_VARIABLES, default={}): cv.Schema( - { - cv.validate_id_name: cv.one_of( - *SERVICE_ARG_NATIVE_TYPES, lower=True - ), - } - ), + cv.validate_id_name: cv.one_of(*SERVICE_ARG_NATIVE_TYPES, lower=True), } ), - cv.Optional(CONF_ENCRYPTION): cv.Schema( - { - cv.Required(CONF_KEY): validate_encryption_key, - } - ), - cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( - single=True - ), - cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation( - single=True - ), - } -).extend(cv.COMPONENT_SCHEMA) + }, + cv.All( + cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION), + cv.rename_key(CONF_SERVICE, CONF_ACTION), + ), +) + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(APIServer), + cv.Optional(CONF_PORT, default=6053): cv.port, + cv.Optional(CONF_PASSWORD, default=""): cv.string_strict, + cv.Optional( + CONF_REBOOT_TIMEOUT, default="15min" + ): cv.positive_time_period_milliseconds, + cv.Exclusive( + CONF_SERVICES, group_of_exclusion=CONF_ACTIONS + ): ACTIONS_SCHEMA, + cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA, + cv.Optional(CONF_ENCRYPTION): cv.Schema( + { + cv.Required(CONF_KEY): validate_encryption_key, + } + ), + cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( + single=True + ), + cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation( + single=True + ), + } + ).extend(cv.COMPONENT_SCHEMA), + cv.rename_key(CONF_SERVICES, CONF_ACTIONS), +) @coroutine_with_priority(40.0) @@ -108,7 +121,7 @@ async def to_code(config): cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) - for conf in config.get(CONF_SERVICES, []): + for conf in config.get(CONF_ACTIONS, []): template_args = [] func_args = [] service_arg_names = [] @@ -119,7 +132,7 @@ async def to_code(config): service_arg_names.append(name) templ = cg.TemplateArguments(*template_args) trigger = cg.new_Pvariable( - conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names + conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names ) cg.add(var.register_user_service(trigger)) await automation.build_automation(trigger, func_args, conf) @@ -152,28 +165,43 @@ async def to_code(config): KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)}) -HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.use_id(APIServer), - cv.Required(CONF_SERVICE): cv.templatable(cv.string), - cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA, - cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA, - cv.Optional(CONF_VARIABLES, default={}): cv.Schema( - {cv.string: cv.returning_lambda} - ), - } + +HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.use_id(APIServer), + cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.templatable( + cv.string + ), + cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.templatable( + cv.string + ), + cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA, + cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA, + cv.Optional(CONF_VARIABLES, default={}): cv.Schema( + {cv.string: cv.returning_lambda} + ), + } + ), + cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION), + cv.rename_key(CONF_SERVICE, CONF_ACTION), ) +@automation.register_action( + "homeassistant.action", + HomeAssistantServiceCallAction, + HOMEASSISTANT_ACTION_ACTION_SCHEMA, +) @automation.register_action( "homeassistant.service", HomeAssistantServiceCallAction, - HOMEASSISTANT_SERVICE_ACTION_SCHEMA, + HOMEASSISTANT_ACTION_ACTION_SCHEMA, ) async def homeassistant_service_to_code(config, action_id, template_arg, args): serv = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, serv, False) - templ = await cg.templatable(config[CONF_SERVICE], args, None) + templ = await cg.templatable(config[CONF_ACTION], args, None) cg.add(var.set_service(templ)) for key, value in config[CONF_DATA].items(): templ = await cg.templatable(value, args, None) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 1cd1d6aa31..d93f8aed9a 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -2181,3 +2181,13 @@ SOURCE_SCHEMA = Any( } ), ) + + +def rename_key(old_key, new_key): + def validator(config: dict) -> dict: + config = config.copy() + if old_key in config: + config[new_key] = config.pop(old_key) + return config + + return validator diff --git a/esphome/const.py b/esphome/const.py index 37844e1047..39dd48d3f8 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -37,8 +37,10 @@ CONF_ACCELERATION_Y = "acceleration_y" CONF_ACCELERATION_Z = "acceleration_z" CONF_ACCURACY = "accuracy" CONF_ACCURACY_DECIMALS = "accuracy_decimals" +CONF_ACTION = "action" CONF_ACTION_ID = "action_id" CONF_ACTION_STATE_TOPIC = "action_state_topic" +CONF_ACTIONS = "actions" CONF_ACTIVE = "active" CONF_ACTIVE_POWER = "active_power" CONF_ACTUAL_GAIN = "actual_gain" diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml index e0b900f92d..6c2a333598 100644 --- a/tests/components/api/common.yaml +++ b/tests/components/api/common.yaml @@ -5,8 +5,8 @@ esphome: event: esphome.button_pressed data: message: Button was pressed - - homeassistant.service: - service: notify.html5 + - homeassistant.action: + action: notify.html5 data: message: Button was pressed - homeassistant.tag_scanned: pulse @@ -21,8 +21,8 @@ api: reboot_timeout: 0min encryption: key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU= - services: - - service: hello_world + actions: + - action: hello_world variables: name: string then: @@ -30,10 +30,10 @@ api: format: Hello World %s! args: - name.c_str() - - service: empty_service + - action: empty_action then: - - logger.log: Service Called - - service: all_types + - logger.log: Action Called + - action: all_types variables: bool_: bool int_: int @@ -41,7 +41,7 @@ api: string_: string then: - logger.log: Something happened - - service: array_types + - action: array_types variables: bool_arr: bool[] int_arr: int[] diff --git a/tests/components/homeassistant/common.yaml b/tests/components/homeassistant/common.yaml index ae016a3bea..07a6e8090c 100644 --- a/tests/components/homeassistant/common.yaml +++ b/tests/components/homeassistant/common.yaml @@ -13,12 +13,12 @@ esphome: message: The humidity is {{ my_variable }}%. variables: my_variable: "return id(ha_hello_world_temperature).state;" - - homeassistant.service: - service: notify.html5 + - homeassistant.action: + action: notify.html5 data: message: Button was pressed - - homeassistant.service: - service: notify.html5 + - homeassistant.action: + action: notify.html5 data: title: New Humidity data_template: From a5f18dfe7fda26d0311cfeb2fde42d0bf528f576 Mon Sep 17 00:00:00 2001 From: SimoPk Date: Thu, 1 Aug 2024 12:39:54 +0200 Subject: [PATCH 2151/2607] ade7953_spi wrong size specified in read_array call (#7172) --- esphome/components/ade7953_spi/ade7953_spi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ade7953_spi/ade7953_spi.cpp b/esphome/components/ade7953_spi/ade7953_spi.cpp index cfd5d71d0a..77a2a8adc7 100644 --- a/esphome/components/ade7953_spi/ade7953_spi.cpp +++ b/esphome/components/ade7953_spi/ade7953_spi.cpp @@ -60,7 +60,7 @@ bool AdE7953Spi::ade_read_16(uint16_t reg, uint16_t *value) { this->write_byte16(reg); this->transfer_byte(0x80); uint8_t recv[2]; - this->read_array(recv, 4); + this->read_array(recv, 2); *value = encode_uint16(recv[0], recv[1]); this->disable(); return false; From aedfb32482cf11feaa6373b73cc8ce8a2da50658 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:01:21 +1200 Subject: [PATCH 2152/2607] Bump improv library to 1.2.4 (#7174) --- esphome/components/improv_base/__init__.py | 5 ++--- platformio.ini | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/improv_base/__init__.py b/esphome/components/improv_base/__init__.py index 5c2853a5c6..aa75f4d89c 100644 --- a/esphome/components/improv_base/__init__.py +++ b/esphome/components/improv_base/__init__.py @@ -1,8 +1,7 @@ import re -import esphome.config_validation as cv import esphome.codegen as cg - +import esphome.config_validation as cv from esphome.const import __version__ CODEOWNERS = ["@esphome/core"] @@ -39,4 +38,4 @@ def _process_next_url(url: str): async def setup_improv_core(var, config): if CONF_NEXT_URL in config: cg.add(var.set_next_url(_process_next_url(config[CONF_NEXT_URL]))) - cg.add_library("esphome/Improv", "1.2.3") + cg.add_library("improv/Improv", "1.2.4") diff --git a/platformio.ini b/platformio.ini index baf0a85d73..e4f363d650 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,7 +35,7 @@ build_flags = lib_deps = esphome/noise-c@0.1.4 ; api makuna/NeoPixelBus@2.7.3 ; neopixelbus - esphome/Improv@1.2.3 ; improv_serial / esp32_improv + improv/Improv@1.2.4 ; improv_serial / esp32_improv bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 From 4a7570770b0b36cfc2495ad3795d4ae3c7df66bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ebbinghaus?= Date: Fri, 2 Aug 2024 01:58:59 +0200 Subject: [PATCH 2153/2607] Implement 'round to nearest multiple' filter (#7142) --- esphome/components/sensor/__init__.py | 19 +++++++++++++++++++ esphome/components/sensor/filter.cpp | 8 ++++++++ esphome/components/sensor/filter.h | 9 +++++++++ esphome/config_validation.py | 1 + esphome/const.py | 1 + 5 files changed, 38 insertions(+) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 262e69d75b..3b76466dec 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -17,6 +17,7 @@ from esphome.const import ( CONF_ICON, CONF_ID, CONF_IGNORE_OUT_OF_RANGE, + CONF_MULTIPLE, CONF_ON_RAW_VALUE, CONF_ON_VALUE, CONF_ON_VALUE_RANGE, @@ -249,6 +250,7 @@ CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter) ClampFilter = sensor_ns.class_("ClampFilter", Filter) RoundFilter = sensor_ns.class_("RoundFilter", Filter) +RoundMultipleFilter = sensor_ns.class_("RoundMultipleFilter", Filter) validate_unit_of_measurement = cv.string_strict validate_accuracy_decimals = cv.int_ @@ -734,6 +736,23 @@ async def round_filter_to_code(config, filter_id): ) +@FILTER_REGISTRY.register( + "round_to_multiple_of", + RoundMultipleFilter, + cv.maybe_simple_value( + { + cv.Required(CONF_MULTIPLE): cv.positive_not_null_float, + }, + key=CONF_MULTIPLE, + ), +) +async def round_multiple_filter_to_code(config, filter_id): + return cg.new_Pvariable( + filter_id, + config[CONF_MULTIPLE], + ) + + async def build_filters(config): return await cg.build_registry_list(FILTER_REGISTRY, config) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index eaa909429b..bcf1fc8269 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -472,5 +472,13 @@ optional RoundFilter::new_value(float value) { return value; } +RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {} +optional RoundMultipleFilter::new_value(float value) { + if (std::isfinite(value)) { + return value - remainderf(value, this->multiple_); + } + return value; +} + } // namespace sensor } // namespace esphome diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index c13cb3420a..92b1d8d240 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -431,5 +431,14 @@ class RoundFilter : public Filter { uint8_t precision_; }; +class RoundMultipleFilter : public Filter { + public: + explicit RoundMultipleFilter(float multiple); + optional new_value(float value) override; + + protected: + float multiple_; +}; + } // namespace sensor } // namespace esphome diff --git a/esphome/config_validation.py b/esphome/config_validation.py index d93f8aed9a..6e1d3ba2f9 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -464,6 +464,7 @@ zero_to_one_float = float_range(min=0, max=1) negative_one_to_one_float = float_range(min=-1, max=1) positive_int = int_range(min=0) positive_not_null_int = int_range(min=0, min_included=False) +positive_not_null_float = float_range(min=0, min_included=False) def validate_id_name(value): diff --git a/esphome/const.py b/esphome/const.py index 39dd48d3f8..fcb630badd 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -503,6 +503,7 @@ CONF_MOTION = "motion" CONF_MOVEMENT_COUNTER = "movement_counter" CONF_MQTT = "mqtt" CONF_MQTT_ID = "mqtt_id" +CONF_MULTIPLE = "multiple" CONF_MULTIPLEXER = "multiplexer" CONF_MULTIPLY = "multiply" CONF_NAME = "name" From 61c65811233eb1b678fcfa077d6370e7f07ba091 Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Sat, 3 Aug 2024 01:00:18 +0200 Subject: [PATCH 2154/2607] git ignore managed_components (#7180) --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0c9a878400..79820249ac 100644 --- a/.gitignore +++ b/.gitignore @@ -138,3 +138,5 @@ sdkconfig.* .tests/ /components +/managed_components + From 81ac9391d1af48bc02b4df9886954474c1fd7d01 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:04:06 +1000 Subject: [PATCH 2155/2607] [core] Eliminate nuisance messages from `build_codeowners` (#7185) --- esphome/loader.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/esphome/loader.py b/esphome/loader.py index 9399c4cb31..d808805119 100644 --- a/esphome/loader.py +++ b/esphome/loader.py @@ -1,3 +1,4 @@ +from contextlib import AbstractContextManager from dataclasses import dataclass import importlib import importlib.abc @@ -7,7 +8,7 @@ import logging from pathlib import Path import sys from types import ModuleType -from typing import Any, Callable, ContextManager, Optional +from typing import Any, Callable, Optional from esphome.const import SOURCE_FILE_EXTENSIONS from esphome.core import CORE @@ -22,7 +23,7 @@ class FileResource: package: str resource: str - def path(self) -> ContextManager[Path]: + def path(self) -> AbstractContextManager[Path]: return importlib.resources.as_file( importlib.resources.files(self.package) / self.resource ) @@ -176,7 +177,7 @@ def _lookup_module(domain): module = importlib.import_module(f"esphome.components.{domain}") except ImportError as e: if "No module named" in str(e): - _LOGGER.error( + _LOGGER.info( "Unable to import component %s: %s", domain, str(e), exc_info=False ) else: From 38c25dec93b17ede8999f0cc6f295ba4a730ab6d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:15:19 +1200 Subject: [PATCH 2156/2607] [code-quality] More portable shebangs (#7189) Co-authored-by: Keith Burzinski --- docker/docker_entrypoint.sh | 2 +- script/devcontainer-post-create | 2 +- script/quicklint | 2 +- script/setup | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/docker_entrypoint.sh b/docker/docker_entrypoint.sh index 397b1528c5..1b9224244c 100755 --- a/docker/docker_entrypoint.sh +++ b/docker/docker_entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # If /cache is mounted, use that as PIO's coredir # otherwise use path in /config (so that PIO packages aren't downloaded on each compile) diff --git a/script/devcontainer-post-create b/script/devcontainer-post-create index 272d350519..2d376786ac 100755 --- a/script/devcontainer-post-create +++ b/script/devcontainer-post-create @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # set -x diff --git a/script/quicklint b/script/quicklint index a4fae98195..84e4c97667 100755 --- a/script/quicklint +++ b/script/quicklint @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e diff --git a/script/setup b/script/setup index aeb1b39bc1..824840c392 100755 --- a/script/setup +++ b/script/setup @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Set up ESPHome dev environment set -e From 87944f0c1b5df3019407bc20f0f0c29f8cf13033 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:58:20 +1200 Subject: [PATCH 2157/2607] Add support for doing update entity refresh/check via API. (#7190) --- esphome/components/api/api.proto | 7 +++++- esphome/components/api/api_connection.cpp | 12 +++++++++- esphome/components/api/api_pb2.cpp | 22 +++++++++++++++---- esphome/components/api/api_pb2.h | 7 +++++- .../http_request/update/http_request_update.h | 1 + esphome/components/update/update_entity.h | 2 +- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 812a1d74ae..b62fddf815 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1872,6 +1872,11 @@ message UpdateStateResponse { string release_summary = 9; string release_url = 10; } +enum UpdateCommand { + UPDATE_COMMAND_NONE = 0; + UPDATE_COMMAND_UPDATE = 1; + UPDATE_COMMAND_CHECK = 2; +} message UpdateCommandRequest { option (id) = 118; option (source) = SOURCE_CLIENT; @@ -1879,5 +1884,5 @@ message UpdateCommandRequest { option (no_delay) = true; fixed32 key = 1; - bool install = 2; + UpdateCommand command = 2; } diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 2e73a8336e..81fa4cb339 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1328,7 +1328,17 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { if (update == nullptr) return; - update->perform(); + switch (msg.command) { + case enums::UPDATE_COMMAND_UPDATE: + update->perform(); + break; + case enums::UPDATE_COMMAND_CHECK: + update->check(); + break; + default: + ESP_LOGW(TAG, "Unknown update command: %d", msg.command); + break; + } } #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index e6e905c6d1..a57627a66c 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -567,6 +567,20 @@ template<> const char *proto_enum_to_string(enums::ValveO } } #endif +#ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::UpdateCommand value) { + switch (value) { + case enums::UPDATE_COMMAND_NONE: + return "UPDATE_COMMAND_NONE"; + case enums::UPDATE_COMMAND_UPDATE: + return "UPDATE_COMMAND_UPDATE"; + case enums::UPDATE_COMMAND_CHECK: + return "UPDATE_COMMAND_CHECK"; + default: + return "UNKNOWN"; + } +} +#endif bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -8596,7 +8610,7 @@ void UpdateStateResponse::dump_to(std::string &out) const { bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { - this->install = value.as_bool(); + this->command = value.as_enum(); return true; } default: @@ -8615,7 +8629,7 @@ bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { } void UpdateCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_bool(2, this->install); + buffer.encode_enum(2, this->command); } #ifdef HAS_PROTO_MESSAGE_DUMP void UpdateCommandRequest::dump_to(std::string &out) const { @@ -8626,8 +8640,8 @@ void UpdateCommandRequest::dump_to(std::string &out) const { out.append(buffer); out.append("\n"); - out.append(" install: "); - out.append(YESNO(this->install)); + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); out.append("\n"); out.append("}"); } diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index ef051eecf1..bb5263cffa 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -227,6 +227,11 @@ enum ValveOperation : uint32_t { VALVE_OPERATION_IS_OPENING = 1, VALVE_OPERATION_IS_CLOSING = 2, }; +enum UpdateCommand : uint32_t { + UPDATE_COMMAND_NONE = 0, + UPDATE_COMMAND_UPDATE = 1, + UPDATE_COMMAND_CHECK = 2, +}; } // namespace enums @@ -2175,7 +2180,7 @@ class UpdateStateResponse : public ProtoMessage { class UpdateCommandRequest : public ProtoMessage { public: uint32_t key{0}; - bool install{false}; + enums::UpdateCommand command{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/http_request/update/http_request_update.h b/esphome/components/http_request/update/http_request_update.h index 943231a906..45c7e6a447 100644 --- a/esphome/components/http_request/update/http_request_update.h +++ b/esphome/components/http_request/update/http_request_update.h @@ -16,6 +16,7 @@ class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent { void update() override; void perform(bool force) override; + void check() override { this->update(); } void set_source_url(const std::string &source_url) { this->source_url_ = source_url; } diff --git a/esphome/components/update/update_entity.h b/esphome/components/update/update_entity.h index 568fbe3bb0..cc269e288f 100644 --- a/esphome/components/update/update_entity.h +++ b/esphome/components/update/update_entity.h @@ -33,8 +33,8 @@ class UpdateEntity : public EntityBase, public EntityBase_DeviceClass { void publish_state(); void perform() { this->perform(false); } - virtual void perform(bool force) = 0; + virtual void check() = 0; const UpdateInfo &update_info = update_info_; const UpdateState &state = state_; From d18bb34f87758cff3d1a6d881b1b167d1d6f79a1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:07:05 +1000 Subject: [PATCH 2158/2607] [lvgl] Stage 4 (#7166) --- esphome/components/lvgl/__init__.py | 110 +++++-- esphome/components/lvgl/animimg.py | 117 +++++++ esphome/components/lvgl/arc.py | 78 +++++ esphome/components/lvgl/automation.py | 186 ++++++----- esphome/components/lvgl/btn.py | 11 +- esphome/components/lvgl/checkbox.py | 25 ++ esphome/components/lvgl/defines.py | 64 ++-- esphome/components/lvgl/helpers.py | 20 -- esphome/components/lvgl/img.py | 85 +++++ esphome/components/lvgl/label.py | 9 +- esphome/components/lvgl/led.py | 29 ++ esphome/components/lvgl/line.py | 51 +++ esphome/components/lvgl/lv_bar.py | 53 ++++ esphome/components/lvgl/lv_switch.py | 20 ++ esphome/components/lvgl/lv_validation.py | 60 +++- esphome/components/lvgl/lvcode.py | 236 +++++++++----- esphome/components/lvgl/lvgl_esphome.cpp | 202 ++++++++++++ esphome/components/lvgl/lvgl_esphome.h | 164 ++++------ esphome/components/lvgl/page.py | 113 +++++++ esphome/components/lvgl/rotary_encoders.py | 3 +- esphome/components/lvgl/schemas.py | 105 ++++++- esphome/components/lvgl/slider.py | 63 ++++ esphome/components/lvgl/spinner.py | 43 +++ esphome/components/lvgl/styles.py | 58 ++++ esphome/components/lvgl/trigger.py | 22 +- esphome/components/lvgl/types.py | 92 ++++-- esphome/components/lvgl/widget.py | 219 +++++++++---- tests/components/lvgl/lvgl-package.yaml | 343 +++++++++++++-------- 28 files changed, 2002 insertions(+), 579 deletions(-) create mode 100644 esphome/components/lvgl/animimg.py create mode 100644 esphome/components/lvgl/arc.py create mode 100644 esphome/components/lvgl/checkbox.py create mode 100644 esphome/components/lvgl/img.py create mode 100644 esphome/components/lvgl/led.py create mode 100644 esphome/components/lvgl/line.py create mode 100644 esphome/components/lvgl/lv_bar.py create mode 100644 esphome/components/lvgl/lv_switch.py create mode 100644 esphome/components/lvgl/page.py create mode 100644 esphome/components/lvgl/slider.py create mode 100644 esphome/components/lvgl/spinner.py create mode 100644 esphome/components/lvgl/styles.py diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 182d04e038..c154689199 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -15,44 +15,91 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_TYPE, ) -from esphome.core import CORE, ID, Lambda +from esphome.core import CORE, ID from esphome.cpp_generator import MockObj from esphome.final_validate import full_config from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid -from .automation import update_to_code +from .animimg import animimg_spec +from .arc import arc_spec +from .automation import disp_update, update_to_code from .btn import btn_spec +from .checkbox import checkbox_spec +from .defines import CONF_SKIP +from .img import img_spec from .label import label_spec -from .lv_validation import lv_images_used -from .lvcode import LvContext +from .led import led_spec +from .line import line_spec +from .lv_bar import bar_spec +from .lv_switch import switch_spec +from .lv_validation import lv_bool, lv_images_used +from .lvcode import LvContext, LvglComponent from .obj import obj_spec +from .page import add_pages, page_spec from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code -from .schemas import any_widget_schema, create_modify_schema, obj_schema +from .schemas import ( + DISP_BG_SCHEMA, + FLEX_OBJ_SCHEMA, + GRID_CELL_SCHEMA, + LAYOUT_SCHEMAS, + STYLE_SCHEMA, + WIDGET_TYPES, + any_widget_schema, + container_schema, + create_modify_schema, + grid_alignments, + obj_schema, +) +from .slider import slider_spec +from .spinner import spinner_spec +from .styles import add_top_layer, styles_to_code, theme_to_code from .touchscreens import touchscreen_schema, touchscreens_to_code from .trigger import generate_triggers from .types import ( - WIDGET_TYPES, FontEngine, IdleTrigger, - LvglComponent, ObjUpdateAction, lv_font_t, + lv_style_t, lvgl_ns, ) from .widget import Widget, add_widgets, lv_scr_act, set_obj_properties DOMAIN = "lvgl" -DEPENDENCIES = ("display",) -AUTO_LOAD = ("key_provider",) -CODEOWNERS = ("@clydebarrow",) +DEPENDENCIES = ["display"] +AUTO_LOAD = ["key_provider"] +CODEOWNERS = ["@clydebarrow"] LOGGER = logging.getLogger(__name__) -for w_type in (label_spec, obj_spec, btn_spec): +for w_type in ( + label_spec, + obj_spec, + btn_spec, + bar_spec, + slider_spec, + arc_spec, + line_spec, + spinner_spec, + led_spec, + animimg_spec, + checkbox_spec, + img_spec, + switch_spec, +): WIDGET_TYPES[w_type.name] = w_type WIDGET_SCHEMA = any_widget_schema() +LAYOUT_SCHEMAS[df.TYPE_GRID] = { + cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema(GRID_CELL_SCHEMA)) +} +LAYOUT_SCHEMAS[df.TYPE_FLEX] = { + cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema(FLEX_OBJ_SCHEMA)) +} +LAYOUT_SCHEMAS[df.TYPE_NONE] = { + cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema()) +} for w_type in WIDGET_TYPES.values(): register_action( f"lvgl.{w_type.name}.update", @@ -61,14 +108,6 @@ for w_type in WIDGET_TYPES.values(): )(update_to_code) -async def add_init_lambda(lv_component, init): - if init: - lamb = await cg.process_lambda( - Lambda(init), [(LvglComponent.operator("ptr"), "lv_component")] - ) - cg.add(lv_component.add_init_lambda(lamb)) - - lv_defines = {} # Dict of #defines to provide as build flags @@ -100,6 +139,9 @@ def generate_lv_conf_h(): def final_validation(config): + if pages := config.get(CONF_PAGES): + if all(p[CONF_SKIP] for p in pages): + raise cv.Invalid("At least one page must not be skipped") global_config = full_config.get() for display_id in config[df.CONF_DISPLAYS]: path = global_config.get_path_for_id(display_id)[:-1] @@ -193,18 +235,23 @@ async def to_code(config): else: add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font)) - with LvContext(): + async with LvContext(lv_component): await touchscreens_to_code(lv_component, config) await rotary_encoders_to_code(lv_component, config) + await theme_to_code(config) + await styles_to_code(config) await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) + await add_pages(lv_component, config) + await add_top_layer(config) + await disp_update(f"{lv_component}->get_disp()", config) Widget.set_completed() await generate_triggers(lv_component) for conf in config.get(CONF_ON_IDLE, ()): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) await build_automation(idle_trigger, [], conf) - await add_init_lambda(lv_component, LvContext.get_code()) + for comp in helpers.lvgl_components_required: CORE.add_define(f"USE_LVGL_{comp.upper()}") for use in helpers.lv_uses: @@ -239,6 +286,16 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_BYTE_ORDER, default="big_endian"): cv.one_of( "big_endian", "little_endian" ), + cv.Optional(df.CONF_STYLE_DEFINITIONS): cv.ensure_list( + cv.Schema({cv.Required(CONF_ID): cv.declare_id(lv_style_t)}) + .extend(STYLE_SCHEMA) + .extend( + { + cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, + cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments, + } + ) + ), cv.Optional(CONF_ON_IDLE): validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(IdleTrigger), @@ -247,10 +304,19 @@ CONFIG_SCHEMA = ( ), } ), - cv.Optional(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA), + cv.Exclusive(df.CONF_WIDGETS, CONF_PAGES): cv.ensure_list(WIDGET_SCHEMA), + cv.Exclusive(CONF_PAGES, CONF_PAGES): cv.ensure_list( + container_schema(page_spec) + ), + cv.Optional(df.CONF_PAGE_WRAP, default=True): lv_bool, + cv.Optional(df.CONF_TOP_LAYER): container_schema(obj_spec), cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, + cv.Optional(df.CONF_THEME): cv.Schema( + {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} + ), cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, cv.GenerateID(df.CONF_ROTARY_ENCODERS): ROTARY_ENCODER_CONFIG, } ) + .extend(DISP_BG_SCHEMA) ).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) diff --git a/esphome/components/lvgl/animimg.py b/esphome/components/lvgl/animimg.py new file mode 100644 index 0000000000..20b85b019c --- /dev/null +++ b/esphome/components/lvgl/animimg.py @@ -0,0 +1,117 @@ +from esphome import automation +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_DURATION, CONF_ID + +from ...cpp_generator import MockObj +from .automation import action_to_code +from .defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC +from .helpers import lvgl_components_required +from .img import CONF_IMAGE +from .label import CONF_LABEL +from .lv_validation import lv_image, lv_milliseconds +from .lvcode import lv, lv_expr +from .types import LvType, ObjUpdateAction, void_ptr +from .widget import Widget, WidgetType, get_widgets + +CONF_ANIMIMG = "animimg" +CONF_SRC_LIST_ID = "src_list_id" + + +def lv_repeat_count(value): + if isinstance(value, str) and value.lower() in ("forever", "infinite"): + value = 0xFFFF + return cv.int_range(min=0, max=0xFFFF)(value) + + +ANIMIMG_BASE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_REPEAT_COUNT, default="forever"): lv_repeat_count, + cv.Optional(CONF_AUTO_START, default=True): cv.boolean, + } +) +ANIMIMG_SCHEMA = ANIMIMG_BASE_SCHEMA.extend( + { + cv.Required(CONF_DURATION): lv_milliseconds, + cv.Required(CONF_SRC): cv.ensure_list(lv_image), + cv.GenerateID(CONF_SRC_LIST_ID): cv.declare_id(void_ptr), + } +) + +ANIMIMG_MODIFY_SCHEMA = ANIMIMG_BASE_SCHEMA.extend( + { + cv.Optional(CONF_DURATION): lv_milliseconds, + } +) + +lv_animimg_t = LvType("lv_animimg_t") + + +class AnimimgType(WidgetType): + def __init__(self): + super().__init__( + CONF_ANIMIMG, + lv_animimg_t, + (CONF_MAIN,), + ANIMIMG_SCHEMA, + ANIMIMG_MODIFY_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + lvgl_components_required.add(CONF_IMAGE) + lvgl_components_required.add(CONF_ANIMIMG) + if CONF_SRC in config: + for x in config[CONF_SRC]: + await cg.get_variable(x) + srcs = [lv_expr.img_from(MockObj(x)) for x in config[CONF_SRC]] + src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs) + count = len(config[CONF_SRC]) + lv.animimg_set_src(w.obj, src_id, count) + lv.animimg_set_repeat_count(w.obj, config[CONF_REPEAT_COUNT]) + lv.animimg_set_duration(w.obj, config[CONF_DURATION]) + if config.get(CONF_AUTO_START): + lv.animimg_start(w.obj) + + def get_uses(self): + return CONF_IMAGE, CONF_LABEL + + +animimg_spec = AnimimgType() + + +@automation.register_action( + "lvgl.animimg.start", + ObjUpdateAction, + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(lv_animimg_t), + }, + key=CONF_ID, + ), +) +async def animimg_start(config, action_id, template_arg, args): + widget = await get_widgets(config) + + async def do_start(w: Widget): + lv.animimg_start(w.obj) + + return await action_to_code(widget, do_start, action_id, template_arg, args) + + +@automation.register_action( + "lvgl.animimg.stop", + ObjUpdateAction, + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(lv_animimg_t), + }, + key=CONF_ID, + ), +) +async def animimg_stop(config, action_id, template_arg, args): + widget = await get_widgets(config) + + async def do_stop(w: Widget): + lv.animimg_stop(w.obj) + + return await action_to_code(widget, do_stop, action_id, template_arg, args) diff --git a/esphome/components/lvgl/arc.py b/esphome/components/lvgl/arc.py new file mode 100644 index 0000000000..d036464c7a --- /dev/null +++ b/esphome/components/lvgl/arc.py @@ -0,0 +1,78 @@ +import esphome.config_validation as cv +from esphome.const import ( + CONF_MAX_VALUE, + CONF_MIN_VALUE, + CONF_MODE, + CONF_ROTATION, + CONF_VALUE, +) +from esphome.cpp_types import nullptr + +from .defines import ( + ARC_MODES, + CONF_ADJUSTABLE, + CONF_CHANGE_RATE, + CONF_END_ANGLE, + CONF_INDICATOR, + CONF_KNOB, + CONF_MAIN, + CONF_START_ANGLE, + literal, +) +from .lv_validation import angle, get_start_value, lv_float +from .lvcode import lv, lv_obj +from .types import LvNumber, NumberType +from .widget import Widget + +CONF_ARC = "arc" +ARC_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_MIN_VALUE, default=0): cv.int_, + cv.Optional(CONF_MAX_VALUE, default=100): cv.int_, + cv.Optional(CONF_START_ANGLE, default=135): angle, + cv.Optional(CONF_END_ANGLE, default=45): angle, + cv.Optional(CONF_ROTATION, default=0.0): angle, + cv.Optional(CONF_ADJUSTABLE, default=False): bool, + cv.Optional(CONF_MODE, default="NORMAL"): ARC_MODES.one_of, + cv.Optional(CONF_CHANGE_RATE, default=720): cv.uint16_t, + } +) + +ARC_MODIFY_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + } +) + + +class ArcType(NumberType): + def __init__(self): + super().__init__( + CONF_ARC, + LvNumber("lv_arc_t"), + parts=(CONF_MAIN, CONF_INDICATOR, CONF_KNOB), + schema=ARC_SCHEMA, + modify_schema=ARC_MODIFY_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + if CONF_MIN_VALUE in config: + lv.arc_set_range(w.obj, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE]) + lv.arc_set_bg_angles( + w.obj, config[CONF_START_ANGLE] // 10, config[CONF_END_ANGLE] // 10 + ) + lv.arc_set_rotation(w.obj, config[CONF_ROTATION] // 10) + lv.arc_set_mode(w.obj, literal(config[CONF_MODE])) + lv.arc_set_change_rate(w.obj, config[CONF_CHANGE_RATE]) + + if config.get(CONF_ADJUSTABLE) is False: + lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB")) + w.clear_flag("LV_OBJ_FLAG_CLICKABLE") + + value = await get_start_value(config) + if value is not None: + lv.arc_set_value(w.obj, value) + + +arc_spec = ArcType() diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index 4fd0be185e..ffa25783ad 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -1,15 +1,26 @@ +from collections.abc import Awaitable +from typing import Callable + from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_TIMEOUT -from esphome.core import Lambda -from esphome.cpp_generator import RawStatement from esphome.cpp_types import nullptr -from .defines import CONF_LVGL_ID, CONF_SHOW_SNOW, literal -from .lv_validation import lv_bool +from .defines import ( + CONF_DISP_BG_COLOR, + CONF_DISP_BG_IMAGE, + CONF_LVGL_ID, + CONF_SHOW_SNOW, + literal, +) +from .lv_validation import lv_bool, lv_color, lv_image from .lvcode import ( + LVGL_COMP_ARG, LambdaContext, + LocalVariable, + LvConditional, + LvglComponent, ReturnStatement, add_line_marks, lv, @@ -17,46 +28,46 @@ from .lvcode import ( lv_obj, lvgl_comp, ) -from .schemas import ACTION_SCHEMA, LVGL_SCHEMA +from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA from .types import ( + LV_EVENT, + LV_STATE, LvglAction, - LvglComponent, - LvglComponentPtr, LvglCondition, ObjUpdateAction, + lv_disp_t, lv_obj_t, ) -from .widget import Widget, get_widget, lv_scr_act, set_obj_properties +from .widget import Widget, get_widgets, lv_scr_act, set_obj_properties -async def action_to_code(action: list, action_id, widget: Widget, template_arg, args): - with LambdaContext() as context: - lv.cond_if(widget.obj == nullptr) - lv_add(RawStatement(" return;")) - lv.cond_endif() - code = context.get_code() - code.extend(action) - action = "\n".join(code) + "\n\n" - lamb = await cg.process_lambda(Lambda(action), args) - var = cg.new_Pvariable(action_id, template_arg, lamb) +async def action_to_code( + widgets: list[Widget], + action: Callable[[Widget], Awaitable[None]], + action_id, + template_arg, + args, +): + async with LambdaContext(parameters=args, where=action_id) as context: + for widget in widgets: + with LvConditional(widget.obj != nullptr): + await action(widget) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) return var async def update_to_code(config, action_id, template_arg, args): - if config is not None: - widget = await get_widget(config) - with LambdaContext() as context: - add_line_marks(action_id) - await set_obj_properties(widget, config) - await widget.type.to_code(widget, config) - if ( - widget.type.w_type.value_property is not None - and widget.type.w_type.value_property in config - ): - lv.event_send(widget.obj, literal("LV_EVENT_VALUE_CHANGED"), nullptr) - return await action_to_code( - context.get_code(), action_id, widget, template_arg, args - ) + async def do_update(widget: Widget): + await set_obj_properties(widget, config) + await widget.type.to_code(widget, config) + if ( + widget.type.w_type.value_property is not None + and widget.type.w_type.value_property in config + ): + lv.event_send(widget.obj, LV_EVENT.VALUE_CHANGED, nullptr) + + widgets = await get_widgets(config[CONF_ID]) + return await action_to_code(widgets, do_update, action_id, template_arg, args) @automation.register_condition( @@ -66,9 +77,7 @@ async def update_to_code(config, action_id, template_arg, args): ) async def lvgl_is_paused(config, condition_id, template_arg, args): lvgl = config[CONF_LVGL_ID] - with LambdaContext( - [(LvglComponentPtr, "lvgl_comp")], return_type=cg.bool_ - ) as context: + async with LambdaContext(LVGL_COMP_ARG, return_type=cg.bool_) as context: lv_add(ReturnStatement(lvgl_comp.is_paused())) var = cg.new_Pvariable(condition_id, template_arg, await context.get_lambda()) await cg.register_parented(var, lvgl) @@ -89,15 +98,23 @@ async def lvgl_is_paused(config, condition_id, template_arg, args): async def lvgl_is_idle(config, condition_id, template_arg, args): lvgl = config[CONF_LVGL_ID] timeout = await cg.templatable(config[CONF_TIMEOUT], [], cg.uint32) - with LambdaContext( - [(LvglComponentPtr, "lvgl_comp")], return_type=cg.bool_ - ) as context: + async with LambdaContext(LVGL_COMP_ARG, return_type=cg.bool_) as context: lv_add(ReturnStatement(lvgl_comp.is_idle(timeout))) var = cg.new_Pvariable(condition_id, template_arg, await context.get_lambda()) await cg.register_parented(var, lvgl) return var +async def disp_update(disp, config: dict): + if CONF_DISP_BG_COLOR not in config and CONF_DISP_BG_IMAGE not in config: + return + with LocalVariable("lv_disp_tmp", lv_disp_t, literal(disp)) as disp_temp: + if bg_color := config.get(CONF_DISP_BG_COLOR): + lv.disp_set_bg_color(disp_temp, await lv_color.process(bg_color)) + if bg_image := config.get(CONF_DISP_BG_IMAGE): + lv.disp_set_bg_image(disp_temp, await lv_image.process(bg_image)) + + @automation.register_action( "lvgl.widget.redraw", ObjUpdateAction, @@ -109,14 +126,32 @@ async def lvgl_is_idle(config, condition_id, template_arg, args): ), ) async def obj_invalidate_to_code(config, action_id, template_arg, args): - if CONF_ID in config: - w = await get_widget(config) - else: - w = lv_scr_act - with LambdaContext() as context: - add_line_marks(action_id) - lv_obj.invalidate(w.obj) - return await action_to_code(context.get_code(), action_id, w, template_arg, args) + widgets = await get_widgets(config) or [lv_scr_act] + + async def do_invalidate(widget: Widget): + lv_obj.invalidate(widget.obj) + + return await action_to_code(widgets, do_invalidate, action_id, template_arg, args) + + +@automation.register_action( + "lvgl.update", + LvglAction, + DISP_BG_SCHEMA.extend( + { + cv.GenerateID(): cv.use_id(LvglComponent), + } + ).add_extra(cv.has_at_least_one_key(CONF_DISP_BG_COLOR, CONF_DISP_BG_IMAGE)), +) +async def lvgl_update_to_code(config, action_id, template_arg, args): + widgets = await get_widgets(config) + w = widgets[0] + disp = f"{w.obj}->get_disp()" + async with LambdaContext(parameters=args, where=action_id) as context: + await disp_update(disp, config) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, w.var) + return var @automation.register_action( @@ -128,8 +163,8 @@ async def obj_invalidate_to_code(config, action_id, template_arg, args): }, ) async def pause_action_to_code(config, action_id, template_arg, args): - with LambdaContext([(LvglComponentPtr, "lvgl_comp")]) as context: - add_line_marks(action_id) + async with LambdaContext(LVGL_COMP_ARG) as context: + add_line_marks(where=action_id) lv_add(lvgl_comp.set_paused(True, config[CONF_SHOW_SNOW])) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) await cg.register_parented(var, config[CONF_ID]) @@ -144,45 +179,48 @@ async def pause_action_to_code(config, action_id, template_arg, args): }, ) async def resume_action_to_code(config, action_id, template_arg, args): - with LambdaContext([(LvglComponentPtr, "lvgl_comp")]) as context: - add_line_marks(action_id) + async with LambdaContext(LVGL_COMP_ARG, where=action_id) as context: lv_add(lvgl_comp.set_paused(False, False)) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) await cg.register_parented(var, config[CONF_ID]) return var -@automation.register_action("lvgl.widget.disable", ObjUpdateAction, ACTION_SCHEMA) +@automation.register_action("lvgl.widget.disable", ObjUpdateAction, LIST_ACTION_SCHEMA) async def obj_disable_to_code(config, action_id, template_arg, args): - w = await get_widget(config) - with LambdaContext() as context: - add_line_marks(action_id) - w.add_state("LV_STATE_DISABLED") - return await action_to_code(context.get_code(), action_id, w, template_arg, args) + async def do_disable(widget: Widget): + widget.add_state(LV_STATE.DISABLED) + + return await action_to_code( + await get_widgets(config), do_disable, action_id, template_arg, args + ) -@automation.register_action("lvgl.widget.enable", ObjUpdateAction, ACTION_SCHEMA) +@automation.register_action("lvgl.widget.enable", ObjUpdateAction, LIST_ACTION_SCHEMA) async def obj_enable_to_code(config, action_id, template_arg, args): - w = await get_widget(config) - with LambdaContext() as context: - add_line_marks(action_id) - w.clear_state("LV_STATE_DISABLED") - return await action_to_code(context.get_code(), action_id, w, template_arg, args) + async def do_enable(widget: Widget): + widget.clear_state(LV_STATE.DISABLED) + + return await action_to_code( + await get_widgets(config), do_enable, action_id, template_arg, args + ) -@automation.register_action("lvgl.widget.hide", ObjUpdateAction, ACTION_SCHEMA) +@automation.register_action("lvgl.widget.hide", ObjUpdateAction, LIST_ACTION_SCHEMA) async def obj_hide_to_code(config, action_id, template_arg, args): - w = await get_widget(config) - with LambdaContext() as context: - add_line_marks(action_id) - w.add_flag("LV_OBJ_FLAG_HIDDEN") - return await action_to_code(context.get_code(), action_id, w, template_arg, args) + async def do_hide(widget: Widget): + widget.add_flag("LV_OBJ_FLAG_HIDDEN") + + return await action_to_code( + await get_widgets(config), do_hide, action_id, template_arg, args + ) -@automation.register_action("lvgl.widget.show", ObjUpdateAction, ACTION_SCHEMA) +@automation.register_action("lvgl.widget.show", ObjUpdateAction, LIST_ACTION_SCHEMA) async def obj_show_to_code(config, action_id, template_arg, args): - w = await get_widget(config) - with LambdaContext() as context: - add_line_marks(action_id) - w.clear_flag("LV_OBJ_FLAG_HIDDEN") - return await action_to_code(context.get_code(), action_id, w, template_arg, args) + async def do_show(widget: Widget): + widget.clear_flag("LV_OBJ_FLAG_HIDDEN") + + return await action_to_code( + await get_widgets(config), do_show, action_id, template_arg, args + ) diff --git a/esphome/components/lvgl/btn.py b/esphome/components/lvgl/btn.py index 064d886d47..2a2a53e1e2 100644 --- a/esphome/components/lvgl/btn.py +++ b/esphome/components/lvgl/btn.py @@ -1,19 +1,14 @@ from esphome.const import CONF_BUTTON -from esphome.cpp_generator import MockObjClass from .defines import CONF_MAIN from .types import LvBoolean, WidgetType +lv_btn_t = LvBoolean("lv_btn_t") + class BtnType(WidgetType): def __init__(self): - super().__init__(CONF_BUTTON, LvBoolean("lv_btn_t"), (CONF_MAIN,)) - - def obj_creator(self, parent: MockObjClass, config: dict): - """ - LVGL 8 calls buttons `btn` - """ - return f"lv_btn_create({parent})" + super().__init__(CONF_BUTTON, lv_btn_t, (CONF_MAIN,), lv_name="btn") def get_uses(self): return ("btn",) diff --git a/esphome/components/lvgl/checkbox.py b/esphome/components/lvgl/checkbox.py new file mode 100644 index 0000000000..7418d633cf --- /dev/null +++ b/esphome/components/lvgl/checkbox.py @@ -0,0 +1,25 @@ +from .defines import CONF_INDICATOR, CONF_MAIN, CONF_TEXT +from .lv_validation import lv_text +from .lvcode import lv +from .schemas import TEXT_SCHEMA +from .types import LvBoolean +from .widget import Widget, WidgetType + +CONF_CHECKBOX = "checkbox" + + +class CheckboxType(WidgetType): + def __init__(self): + super().__init__( + CONF_CHECKBOX, + LvBoolean("lv_checkbox_t"), + (CONF_MAIN, CONF_INDICATOR), + TEXT_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + if value := config.get(CONF_TEXT): + lv.checkbox_set_text(w.obj, await lv_text.process(value)) + + +checkbox_spec = CheckboxType() diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 9f349e3943..16ec45ae8a 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -4,31 +4,20 @@ Constants already defined in esphome.const are not duplicated here and must be i """ -from typing import Union - from esphome import codegen as cg, config_validation as cv from esphome.core import ID, Lambda -from esphome.cpp_generator import Literal +from esphome.cpp_generator import MockObj from esphome.cpp_types import uint32 from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from .helpers import requires_component - -class ConstantLiteral(Literal): - __slots__ = ("constant",) - - def __init__(self, constant: str): - super().__init__() - self.constant = constant - - def __str__(self): - return self.constant +lvgl_ns = cg.esphome_ns.namespace("lvgl") -def literal(arg: Union[str, ConstantLiteral]): +def literal(arg): if isinstance(arg, str): - return ConstantLiteral(arg) + return MockObj(arg) return arg @@ -93,15 +82,23 @@ class LvConstant(LValidator): return self.prefix + cv.one_of(*choices, upper=True)(value) super().__init__(validator, rtype=uint32) + self.retmapper = self.mapper self.one_of = LValidator(validator, uint32, retmapper=self.mapper) self.several_of = LValidator( cv.ensure_list(self.one_of), uint32, retmapper=self.mapper ) def mapper(self, value, args=()): - if isinstance(value, list): - value = "|".join(value) - return ConstantLiteral(value) + if not isinstance(value, list): + value = [value] + return literal( + "|".join( + [ + str(v) if str(v).startswith(self.prefix) else self.prefix + str(v) + for v in value + ] + ).upper() + ) def extend(self, *choices): """ @@ -112,9 +109,6 @@ class LvConstant(LValidator): return LvConstant(self.prefix, *(self.choices + choices)) -# Widgets -CONF_LABEL = "label" - # Parts CONF_MAIN = "main" CONF_SCROLLBAR = "scrollbar" @@ -123,10 +117,15 @@ CONF_KNOB = "knob" CONF_SELECTED = "selected" CONF_ITEMS = "items" CONF_TICKS = "ticks" -CONF_TICK_STYLE = "tick_style" CONF_CURSOR = "cursor" CONF_TEXTAREA_PLACEHOLDER = "textarea_placeholder" +# Layout types + +TYPE_FLEX = "flex" +TYPE_GRID = "grid" +TYPE_NONE = "none" + LV_FONTS = list(f"montserrat_{s}" for s in range(8, 50, 2)) + [ "dejavu_16_persian_hebrew", "simsun_16_cjk", @@ -134,7 +133,7 @@ LV_FONTS = list(f"montserrat_{s}" for s in range(8, 50, 2)) + [ "unscii_16", ] -LV_EVENT = { +LV_EVENT_MAP = { "PRESS": "PRESSED", "SHORT_CLICK": "SHORT_CLICKED", "LONG_PRESS": "LONG_PRESSED", @@ -150,7 +149,7 @@ LV_EVENT = { "CANCEL": "CANCEL", } -LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT) +LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP) LV_ANIM = LvConstant( @@ -305,7 +304,8 @@ OBJ_FLAGS = ( ARC_MODES = LvConstant("LV_ARC_MODE_", "NORMAL", "REVERSE", "SYMMETRICAL") BAR_MODES = LvConstant("LV_BAR_MODE_", "NORMAL", "SYMMETRICAL", "RANGE") -BTNMATRIX_CTRLS = ( +BTNMATRIX_CTRLS = LvConstant( + "LV_BTNMATRIX_CTRL_", "HIDDEN", "NO_REPEAT", "DISABLED", @@ -366,7 +366,6 @@ CONF_ACCEPTED_CHARS = "accepted_chars" CONF_ADJUSTABLE = "adjustable" CONF_ALIGN = "align" CONF_ALIGN_TO = "align_to" -CONF_ANGLE_RANGE = "angle_range" CONF_ANIMATED = "animated" CONF_ANIMATION = "animation" CONF_ANTIALIAS = "antialias" @@ -384,8 +383,6 @@ CONF_BYTE_ORDER = "byte_order" CONF_CHANGE_RATE = "change_rate" CONF_CLOSE_BUTTON = "close_button" CONF_COLOR_DEPTH = "color_depth" -CONF_COLOR_END = "color_end" -CONF_COLOR_START = "color_start" CONF_CONTROL = "control" CONF_DEFAULT = "default" CONF_DEFAULT_FONT = "default_font" @@ -414,9 +411,7 @@ CONF_GRID_ROW_ALIGN = "grid_row_align" CONF_GRID_ROWS = "grid_rows" CONF_HEADER_MODE = "header_mode" CONF_HOME = "home" -CONF_INDICATORS = "indicators" CONF_KEY_CODE = "key_code" -CONF_LABEL_GAP = "label_gap" CONF_LAYOUT = "layout" CONF_LEFT_BUTTON = "left_button" CONF_LINE_WIDTH = "line_width" @@ -425,7 +420,6 @@ CONF_LONG_PRESS_TIME = "long_press_time" CONF_LONG_PRESS_REPEAT_TIME = "long_press_repeat_time" CONF_LVGL_ID = "lvgl_id" CONF_LONG_MODE = "long_mode" -CONF_MAJOR = "major" CONF_MSGBOXES = "msgboxes" CONF_OBJ = "obj" CONF_OFFSET_X = "offset_x" @@ -434,6 +428,7 @@ CONF_ONE_LINE = "one_line" CONF_ON_SELECT = "on_select" CONF_ONE_CHECKED = "one_checked" CONF_NEXT = "next" +CONF_PAGE = "page" CONF_PAGE_WRAP = "page_wrap" CONF_PASSWORD_MODE = "password_mode" CONF_PIVOT_X = "pivot_x" @@ -442,14 +437,12 @@ CONF_PLACEHOLDER_TEXT = "placeholder_text" CONF_POINTS = "points" CONF_PREVIOUS = "previous" CONF_REPEAT_COUNT = "repeat_count" -CONF_R_MOD = "r_mod" CONF_RECOLOR = "recolor" CONF_RIGHT_BUTTON = "right_button" CONF_ROLLOVER = "rollover" CONF_ROOT_BACK_BTN = "root_back_btn" CONF_ROTARY_ENCODERS = "rotary_encoders" CONF_ROWS = "rows" -CONF_SCALES = "scales" CONF_SCALE_LINES = "scale_lines" CONF_SCROLLBAR_MODE = "scrollbar_mode" CONF_SELECTED_INDEX = "selected_index" @@ -459,8 +452,9 @@ CONF_SRC = "src" CONF_START_ANGLE = "start_angle" CONF_START_VALUE = "start_value" CONF_STATES = "states" -CONF_STRIDE = "stride" CONF_STYLE = "style" +CONF_STYLES = "styles" +CONF_STYLE_DEFINITIONS = "style_definitions" CONF_STYLE_ID = "style_id" CONF_SKIP = "skip" CONF_SYMBOL = "symbol" @@ -505,4 +499,4 @@ DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" def join_enums(enums, prefix=""): - return ConstantLiteral("|".join(f"(int){prefix}{e.upper()}" for e in enums)) + return literal("|".join(f"(int){prefix}{e.upper()}" for e in enums)) diff --git a/esphome/components/lvgl/helpers.py b/esphome/components/lvgl/helpers.py index d67739155c..e04a0105d5 100644 --- a/esphome/components/lvgl/helpers.py +++ b/esphome/components/lvgl/helpers.py @@ -1,10 +1,7 @@ import re from esphome import config_validation as cv -from esphome.config import Config from esphome.const import CONF_ARGS, CONF_FORMAT -from esphome.core import CORE, ID -from esphome.yaml_util import ESPHomeDataBase lv_uses = { "USER_DATA", @@ -44,23 +41,6 @@ def validate_printf(value): return value -def get_line_marks(value) -> list: - """ - If possible, return a preprocessor directive to identify the line number where the given id was defined. - :param id: The id in question - :return: A list containing zero or more line directives - """ - path = None - if isinstance(value, ESPHomeDataBase): - path = value.esp_range - elif isinstance(value, ID) and isinstance(CORE.config, Config): - path = CORE.config.get_path_for_id(value)[:-1] - path = CORE.config.get_deepest_document_range_for_path(path) - if path is None: - return [] - return [path.start_mark.as_line_directive] - - def requires_component(comp): def validator(value): lvgl_components_required.add(comp) diff --git a/esphome/components/lvgl/img.py b/esphome/components/lvgl/img.py new file mode 100644 index 0000000000..e9682def8c --- /dev/null +++ b/esphome/components/lvgl/img.py @@ -0,0 +1,85 @@ +import esphome.config_validation as cv +from esphome.const import CONF_ANGLE, CONF_MODE + +from .defines import ( + CONF_ANTIALIAS, + CONF_MAIN, + CONF_OFFSET_X, + CONF_OFFSET_Y, + CONF_PIVOT_X, + CONF_PIVOT_Y, + CONF_SRC, + CONF_ZOOM, + LvConstant, +) +from .label import CONF_LABEL +from .lv_validation import angle, lv_bool, lv_image, size, zoom +from .lvcode import lv +from .types import lv_img_t +from .widget import Widget, WidgetType + +CONF_IMAGE = "image" + +BASE_IMG_SCHEMA = cv.Schema( + { + cv.Optional(CONF_PIVOT_X, default="50%"): size, + cv.Optional(CONF_PIVOT_Y, default="50%"): size, + cv.Optional(CONF_ANGLE): angle, + cv.Optional(CONF_ZOOM): zoom, + cv.Optional(CONF_OFFSET_X): size, + cv.Optional(CONF_OFFSET_Y): size, + cv.Optional(CONF_ANTIALIAS): lv_bool, + cv.Optional(CONF_MODE): LvConstant( + "LV_IMG_SIZE_MODE_", "VIRTUAL", "REAL" + ).one_of, + } +) + +IMG_SCHEMA = BASE_IMG_SCHEMA.extend( + { + cv.Required(CONF_SRC): lv_image, + } +) + +IMG_MODIFY_SCHEMA = BASE_IMG_SCHEMA.extend( + { + cv.Optional(CONF_SRC): lv_image, + } +) + + +class ImgType(WidgetType): + def __init__(self): + super().__init__( + CONF_IMAGE, + lv_img_t, + (CONF_MAIN,), + IMG_SCHEMA, + IMG_MODIFY_SCHEMA, + lv_name="img", + ) + + def get_uses(self): + return "img", CONF_LABEL + + async def to_code(self, w: Widget, config): + if src := config.get(CONF_SRC): + lv.img_set_src(w.obj, await lv_image.process(src)) + if cf_angle := config.get(CONF_ANGLE): + pivot_x = config[CONF_PIVOT_X] + pivot_y = config[CONF_PIVOT_Y] + lv.img_set_pivot(w.obj, pivot_x, pivot_y) + lv.img_set_angle(w.obj, cf_angle) + if img_zoom := config.get(CONF_ZOOM): + lv.img_set_zoom(w.obj, img_zoom) + if offset := config.get(CONF_OFFSET_X): + lv.img_set_offset_x(w.obj, offset) + if offset := config.get(CONF_OFFSET_Y): + lv.img_set_offset_y(w.obj, offset) + if CONF_ANTIALIAS in config: + lv.img_set_antialias(w.obj, config[CONF_ANTIALIAS]) + if mode := config.get(CONF_MODE): + lv.img_set_mode(w.obj, mode) + + +img_spec = ImgType() diff --git a/esphome/components/lvgl/label.py b/esphome/components/lvgl/label.py index 0498f39474..6c3e1f4a00 100644 --- a/esphome/components/lvgl/label.py +++ b/esphome/components/lvgl/label.py @@ -1,7 +1,6 @@ import esphome.config_validation as cv from .defines import ( - CONF_LABEL, CONF_LONG_MODE, CONF_MAIN, CONF_RECOLOR, @@ -15,6 +14,8 @@ from .schemas import TEXT_SCHEMA from .types import LvText, WidgetType from .widget import Widget +CONF_LABEL = "label" + class LabelType(WidgetType): def __init__(self): @@ -33,9 +34,9 @@ class LabelType(WidgetType): async def to_code(self, w: Widget, config): """For a text object, create and set text""" if value := config.get(CONF_TEXT): - w.set_property(CONF_TEXT, await lv_text.process(value)) - w.set_property(CONF_LONG_MODE, config) - w.set_property(CONF_RECOLOR, config) + await w.set_property(CONF_TEXT, await lv_text.process(value)) + await w.set_property(CONF_LONG_MODE, config) + await w.set_property(CONF_RECOLOR, config) label_spec = LabelType() diff --git a/esphome/components/lvgl/led.py b/esphome/components/lvgl/led.py new file mode 100644 index 0000000000..f920758efb --- /dev/null +++ b/esphome/components/lvgl/led.py @@ -0,0 +1,29 @@ +import esphome.config_validation as cv +from esphome.const import CONF_BRIGHTNESS, CONF_COLOR, CONF_LED + +from .defines import CONF_MAIN +from .lv_validation import lv_brightness, lv_color +from .lvcode import lv +from .types import LvType +from .widget import Widget, WidgetType + +LED_SCHEMA = cv.Schema( + { + cv.Optional(CONF_COLOR): lv_color, + cv.Optional(CONF_BRIGHTNESS): lv_brightness, + } +) + + +class LedType(WidgetType): + def __init__(self): + super().__init__(CONF_LED, LvType("lv_led_t"), (CONF_MAIN,), LED_SCHEMA) + + async def to_code(self, w: Widget, config): + if color := config.get(CONF_COLOR): + lv.led_set_color(w.obj, await lv_color.process(color)) + if brightness := config.get(CONF_BRIGHTNESS): + lv.led_set_brightness(w.obj, await lv_brightness.process(brightness)) + + +led_spec = LedType() diff --git a/esphome/components/lvgl/line.py b/esphome/components/lvgl/line.py new file mode 100644 index 0000000000..ab50832bbf --- /dev/null +++ b/esphome/components/lvgl/line.py @@ -0,0 +1,51 @@ +import functools + +import esphome.codegen as cg +import esphome.config_validation as cv + +from . import defines as df +from .defines import CONF_MAIN, literal +from .lvcode import lv +from .types import LvType +from .widget import Widget, WidgetType + +CONF_LINE = "line" +CONF_POINTS = "points" +CONF_POINT_LIST_ID = "point_list_id" + +lv_point_t = cg.global_ns.struct("lv_point_t") + + +def point_list(il): + il = cv.string(il) + nl = il.replace(" ", "").split(",") + return [int(n) for n in nl] + + +def cv_point_list(value): + if not isinstance(value, list): + raise cv.Invalid("List of points required") + values = [point_list(v) for v in value] + if not functools.reduce(lambda f, v: f and len(v) == 2, values, True): + raise cv.Invalid("Points must be a list of x,y integer pairs") + return values + + +LINE_SCHEMA = { + cv.Required(df.CONF_POINTS): cv_point_list, + cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t), +} + + +class LineType(WidgetType): + def __init__(self): + super().__init__(CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA) + + async def to_code(self, w: Widget, config): + """For a line object, create and add the points""" + data = literal(config[CONF_POINTS]) + points = cg.static_const_array(config[CONF_POINT_LIST_ID], data) + lv.line_set_points(w.obj, points, len(data)) + + +line_spec = LineType() diff --git a/esphome/components/lvgl/lv_bar.py b/esphome/components/lvgl/lv_bar.py new file mode 100644 index 0000000000..d5dcff0bf0 --- /dev/null +++ b/esphome/components/lvgl/lv_bar.py @@ -0,0 +1,53 @@ +import esphome.config_validation as cv +from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, CONF_VALUE + +from .defines import BAR_MODES, CONF_ANIMATED, CONF_INDICATOR, CONF_MAIN, literal +from .lv_validation import animated, get_start_value, lv_float +from .lvcode import lv +from .types import LvNumber, NumberType +from .widget import Widget + +CONF_BAR = "bar" +BAR_MODIFY_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_ANIMATED, default=True): animated, + } +) + +BAR_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_MIN_VALUE, default=0): cv.int_, + cv.Optional(CONF_MAX_VALUE, default=100): cv.int_, + cv.Optional(CONF_MODE, default="NORMAL"): BAR_MODES.one_of, + cv.Optional(CONF_ANIMATED, default=True): animated, + } +) + + +class BarType(NumberType): + def __init__(self): + super().__init__( + CONF_BAR, + LvNumber("lv_bar_t"), + parts=(CONF_MAIN, CONF_INDICATOR), + schema=BAR_SCHEMA, + modify_schema=BAR_MODIFY_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + var = w.obj + if CONF_MIN_VALUE in config: + lv.bar_set_range(var, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE]) + lv.bar_set_mode(var, literal(config[CONF_MODE])) + value = await get_start_value(config) + if value is not None: + lv.bar_set_value(var, value, literal(config[CONF_ANIMATED])) + + @property + def animated(self): + return True + + +bar_spec = BarType() diff --git a/esphome/components/lvgl/lv_switch.py b/esphome/components/lvgl/lv_switch.py new file mode 100644 index 0000000000..5db2c2ce38 --- /dev/null +++ b/esphome/components/lvgl/lv_switch.py @@ -0,0 +1,20 @@ +from .defines import CONF_INDICATOR, CONF_KNOB, CONF_MAIN +from .types import LvBoolean +from .widget import WidgetType + +CONF_SWITCH = "switch" + + +class SwitchType(WidgetType): + def __init__(self): + super().__init__( + CONF_SWITCH, + LvBoolean("lv_switch_t"), + (CONF_MAIN, CONF_INDICATOR, CONF_KNOB), + ) + + async def to_code(self, w, config): + return [] + + +switch_spec = SwitchType() diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 818bde6aed..b351b84af6 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -1,3 +1,5 @@ +from typing import Union + import esphome.codegen as cg from esphome.components.binary_sensor import BinarySensor from esphome.components.color import ColorStruct @@ -6,7 +8,7 @@ from esphome.components.image import Image_ from esphome.components.sensor import Sensor from esphome.components.text_sensor import TextSensor import esphome.config_validation as cv -from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT +from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_VALUE from esphome.core import HexInt from esphome.cpp_generator import MockObj from esphome.cpp_types import uint32 @@ -14,7 +16,14 @@ from esphome.helpers import cpp_string_escape from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from . import types as ty -from .defines import LV_FONTS, ConstantLiteral, LValidator, LvConstant, literal +from .defines import ( + CONF_END_VALUE, + CONF_START_VALUE, + LV_FONTS, + LValidator, + LvConstant, + literal, +) from .helpers import ( esphome_fonts_used, lv_fonts_used, @@ -60,6 +69,13 @@ def color_retmapper(value): return lv_expr.color_from(MockObj(value)) +def option_string(value): + value = cv.string(value).strip() + if value.find("\n") != -1: + raise cv.Invalid("Options strings must not contain newlines") + return value + + lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) @@ -156,6 +172,12 @@ lv_bool = LValidator( ) +def lv_pct(value: Union[int, float]): + if isinstance(value, float): + value = int(value * 100) + return literal(f"lv_pct({value})") + + def lvms_validator_(value): if value == "never": value = "2147483647ms" @@ -189,13 +211,16 @@ class TextValidator(LValidator): args = [str(x) for x in value[CONF_ARGS]] arg_expr = cg.RawExpression(",".join(args)) format_str = cpp_string_escape(value[CONF_FORMAT]) - return f"str_sprintf({format_str}, {arg_expr}).c_str()" + return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()") return await super().process(value, args) lv_text = TextValidator() lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") +lv_brightness = LValidator( + cv.percentage, cg.float_, Sensor, "get_state()", retmapper=lambda x: int(x * 255) +) def is_lv_font(font): @@ -222,8 +247,33 @@ class LvFont(LValidator): async def process(self, value, args=()): if is_lv_font(value): - return ConstantLiteral(f"&lv_font_{value}") - return ConstantLiteral(f"{value}_engine->get_lv_font()") + return literal(f"&lv_font_{value}") + return literal(f"{value}_engine->get_lv_font()") lv_font = LvFont() + + +def animated(value): + if isinstance(value, bool): + value = "ON" if value else "OFF" + return LvConstant("LV_ANIM_", "OFF", "ON").one_of(value) + + +def key_code(value): + value = cv.Any(cv.All(cv.string_strict, cv.Length(min=1, max=1)), cv.uint8_t)(value) + if isinstance(value, str): + return ord(value[0]) + return value + + +async def get_end_value(config): + return await lv_int.process(config.get(CONF_END_VALUE)) + + +async def get_start_value(config): + if CONF_START_VALUE in config: + value = config[CONF_START_VALUE] + else: + value = config.get(CONF_VALUE) + return await lv_int.process(value) diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 3a8a958f2e..f54a032de2 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -1,9 +1,9 @@ import abc -import logging from typing import Union from esphome import codegen as cg -from esphome.core import ID, Lambda +from esphome.config import Config +from esphome.core import CORE, ID, Lambda from esphome.cpp_generator import ( AssignmentExpression, CallExpression, @@ -18,12 +18,47 @@ from esphome.cpp_generator import ( VariableDeclarationExpression, statement, ) +from esphome.yaml_util import ESPHomeDataBase -from .defines import ConstantLiteral -from .helpers import get_line_marks -from .types import lv_group_t +from .defines import literal, lvgl_ns -_LOGGER = logging.getLogger(__name__) +LVGL_COMP = "lv_component" # used as a lambda argument in lvgl_comp() + +# Argument tuple for use in lambdas +LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) +LVGL_COMP_ARG = [(LvglComponent.operator("ptr"), LVGL_COMP)] +lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") +EVENT_ARG = [(lv_event_t_ptr, "ev")] +CUSTOM_EVENT = literal("lvgl::lv_custom_event") + + +def get_line_marks(value) -> list: + """ + If possible, return a preprocessor directive to identify the line number where the given id was defined. + :param value: The id or other token to get the line number for + :return: A list containing zero or more line directives + """ + path = None + if isinstance(value, ESPHomeDataBase): + path = value.esp_range + elif isinstance(value, ID) and isinstance(CORE.config, Config): + path = CORE.config.get_path_for_id(value)[:-1] + path = CORE.config.get_deepest_document_range_for_path(path) + if path is None: + return [] + return [path.start_mark.as_line_directive] + + +class IndentedStatement(Statement): + def __init__(self, stmt: Statement, indent: int): + self.statement = stmt + self.indent = indent + + def __str__(self): + result = " " * self.indent * 4 + str(self.statement).strip() + if not isinstance(self.statement, RawStatement): + result += ";" + return result class CodeContext(abc.ABC): @@ -39,6 +74,16 @@ class CodeContext(abc.ABC): def add(self, expression: Union[Expression, Statement]): pass + @staticmethod + def start_block(): + CodeContext.append(RawStatement("{")) + CodeContext.code_context.indent() + + @staticmethod + def end_block(): + CodeContext.code_context.detent() + CodeContext.append(RawStatement("}")) + @staticmethod def append(expression: Union[Expression, Statement]): if CodeContext.code_context is not None: @@ -47,14 +92,25 @@ class CodeContext(abc.ABC): def __init__(self): self.previous: Union[CodeContext | None] = None + self.indent_level = 0 - def __enter__(self): + async def __aenter__(self): self.previous = CodeContext.code_context CodeContext.code_context = self + return self - def __exit__(self, *args): + async def __aexit__(self, *args): CodeContext.code_context = self.previous + def indent(self): + self.indent_level += 1 + + def detent(self): + self.indent_level -= 1 + + def indented_statement(self, stmt): + return IndentedStatement(stmt, self.indent_level) + class MainContext(CodeContext): """ @@ -62,42 +118,7 @@ class MainContext(CodeContext): """ def add(self, expression: Union[Expression, Statement]): - return cg.add(expression) - - -class LvContext(CodeContext): - """ - Code generation into the LVGL initialisation code (called in `setup()`) - """ - - lv_init_code: list["Statement"] = [] - - @staticmethod - def lv_add(expression: Union[Expression, Statement]): - if isinstance(expression, Expression): - expression = statement(expression) - if not isinstance(expression, Statement): - raise ValueError( - f"Add '{expression}' must be expression or statement, not {type(expression)}" - ) - LvContext.lv_init_code.append(expression) - _LOGGER.debug("LV Adding: %s", expression) - return expression - - @staticmethod - def get_code(): - code = [] - for exp in LvContext.lv_init_code: - text = str(statement(exp)) - text = text.rstrip() - code.append(text) - return "\n".join(code) + "\n\n" - - def add(self, expression: Union[Expression, Statement]): - return LvContext.lv_add(expression) - - def set_style(self, prop): - return MockObj("lv_set_style_{prop}", "") + return cg.add(self.indented_statement(expression)) class LambdaContext(CodeContext): @@ -110,21 +131,23 @@ class LambdaContext(CodeContext): parameters: list[tuple[SafeExpType, str]] = None, return_type: SafeExpType = cg.void, capture: str = "", + where=None, ): super().__init__() self.code_list: list[Statement] = [] - self.parameters = parameters + self.parameters = parameters or [] self.return_type = return_type self.capture = capture + self.where = where def add(self, expression: Union[Expression, Statement]): - self.code_list.append(expression) + self.code_list.append(self.indented_statement(expression)) return expression async def get_lambda(self) -> LambdaExpression: code_text = self.get_code() return await cg.process_lambda( - Lambda("\n".join(code_text) + "\n\n"), + Lambda("\n".join(code_text) + "\n"), self.parameters, capture=self.capture, return_type=self.return_type, @@ -138,33 +161,59 @@ class LambdaContext(CodeContext): code_text.append(text) return code_text - def __enter__(self): - super().__enter__() + async def __aenter__(self): + await super().__aenter__() + add_line_marks(self.where) return self +class LvContext(LambdaContext): + """ + Code generation into the LVGL initialisation code (called in `setup()`) + """ + + def __init__(self, lv_component, args=None): + self.args = args or LVGL_COMP_ARG + super().__init__(parameters=self.args) + self.lv_component = lv_component + + async def add_init_lambda(self): + cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) + + async def __aexit__(self, exc_type, exc_val, exc_tb): + await super().__aexit__(exc_type, exc_val, exc_tb) + await self.add_init_lambda() + + def add(self, expression: Union[Expression, Statement]): + self.code_list.append(self.indented_statement(expression)) + return expression + + def __call__(self, *args): + return self.add(*args) + + class LocalVariable(MockObj): """ Create a local variable and enclose the code using it within a block. """ - def __init__(self, name, type, modifier=None, rhs=None): - base = ID(name, True, type) + def __init__(self, name, type, rhs=None, modifier="*"): + base = ID(name + "_VAR_", True, type) super().__init__(base, "") self.modifier = modifier self.rhs = rhs def __enter__(self): - CodeContext.append(RawStatement("{")) + CodeContext.start_block() CodeContext.append( VariableDeclarationExpression(self.base.type, self.modifier, self.base.id) ) if self.rhs is not None: CodeContext.append(AssignmentExpression(None, "", self.base, self.rhs)) - return self.base + return MockObj(self.base) def __exit__(self, *args): - CodeContext.append(RawStatement("}")) + CodeContext.end_block() class MockLv: @@ -199,14 +248,27 @@ class MockLv: self.append(result) return result - def cond_if(self, expression: Expression): - CodeContext.append(RawStatement(f"if {expression} {{")) - def cond_else(self): +class LvConditional: + def __init__(self, condition): + self.condition = condition + + def __enter__(self): + if self.condition is not None: + CodeContext.append(RawStatement(f"if ({self.condition}) {{")) + CodeContext.code_context.indent() + return self + + def __exit__(self, *args): + if self.condition is not None: + CodeContext.code_context.detent() + CodeContext.append(RawStatement("}")) + + def else_(self): + assert self.condition is not None + CodeContext.code_context.detent() CodeContext.append(RawStatement("} else {")) - - def cond_endif(self): - CodeContext.append(RawStatement("}")) + CodeContext.code_context.indent() class ReturnStatement(ExpressionStatement): @@ -228,36 +290,56 @@ lv = MockLv("lv_") lv_expr = LvExpr("lv_") # Mock for lv_obj_ calls lv_obj = MockLv("lv_obj_") -lvgl_comp = MockObj("lvgl_comp", "->") +# Operations on the LVGL component +lvgl_comp = MockObj(LVGL_COMP, "->") -# equivalent to cg.add() for the lvgl init context +# equivalent to cg.add() for the current code context def lv_add(expression: Union[Expression, Statement]): return CodeContext.append(expression) def add_line_marks(where): + """ + Add line marks for the current code context + :param where: An object to identify the source of the line marks + :return: + """ for mark in get_line_marks(where): lv_add(cg.RawStatement(mark)) def lv_assign(target, expression): - lv_add(RawExpression(f"{target} = {expression}")) + lv_add(AssignmentExpression("", "", target, expression)) -lv_groups = {} # Widget group names +def lv_Pvariable(type, name): + """ + Create but do not initialise a pointer variable + :param type: Type of the variable target + :param name: name of the variable, or an ID + :return: A MockObj of the variable + """ + if isinstance(name, str): + name = ID(name, True, type) + decl = VariableDeclarationExpression(type, "*", name) + CORE.add_global(decl) + var = MockObj(name, "->") + CORE.register_variable(name, var) + return var -def add_group(name): - if name is None: - return None - fullname = f"lv_esp_group_{name}" - if name not in lv_groups: - gid = ID(fullname, True, type=lv_group_t.operator("ptr")) - lv_add( - AssignmentExpression( - type_=gid.type, modifier="", name=fullname, rhs=lv_expr.group_create() - ) - ) - lv_groups[name] = ConstantLiteral(fullname) - return lv_groups[name] +def lv_variable(type, name): + """ + Create but do not initialise a variable + :param type: Type of the variable target + :param name: name of the variable, or an ID + :return: A MockObj of the variable + """ + if isinstance(name, str): + name = ID(name, True, type) + decl = VariableDeclarationExpression(type, "", name) + CORE.add_global(decl) + var = MockObj(name, ".") + CORE.register_variable(name, var) + return var diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 34f8eaf21f..1221682d28 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -9,8 +9,72 @@ namespace esphome { namespace lvgl { static const char *const TAG = "lvgl"; +#if LV_USE_LOG +static void log_cb(const char *buf) { + esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); +} +#endif // LV_USE_LOG + +static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { + // make sure all coordinates are even + if (area->x1 & 1) + area->x1--; + if (!(area->x2 & 1)) + area->x2++; + if (area->y1 & 1) + area->y1--; + if (!(area->y2 & 1)) + area->y2++; +} + lv_event_code_t lv_custom_event; // NOLINT void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); } +void LvglComponent::set_paused(bool paused, bool show_snow) { + this->paused_ = paused; + this->show_snow_ = show_snow; + this->snow_line_ = 0; + if (!paused && lv_scr_act() != nullptr) { + lv_disp_trig_activity(this->disp_); // resets the inactivity time + lv_obj_invalidate(lv_scr_act()); + } +} +void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) { + lv_obj_add_event_cb(obj, callback, event, this); + if (event == LV_EVENT_VALUE_CHANGED) { + lv_obj_add_event_cb(obj, callback, lv_custom_event, this); + } +} +void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, + lv_event_code_t event2) { + this->add_event_cb(obj, callback, event1); + this->add_event_cb(obj, callback, event2); +} +void LvglComponent::add_page(LvPageType *page) { + this->pages_.push_back(page); + page->setup(this->pages_.size() - 1); +} +void LvglComponent::show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time) { + if (index >= this->pages_.size()) + return; + this->current_page_ = index; + lv_scr_load_anim(this->pages_[this->current_page_]->obj, anim, time, 0, false); +} +void LvglComponent::show_next_page(lv_scr_load_anim_t anim, uint32_t time) { + if (this->pages_.empty() || (this->current_page_ == this->pages_.size() - 1 && !this->page_wrap_)) + return; + do { + this->current_page_ = (this->current_page_ + 1) % this->pages_.size(); + } while (this->pages_[this->current_page_]->skip); // skip empty pages() + this->show_page(this->current_page_, anim, time); +} +void LvglComponent::show_prev_page(lv_scr_load_anim_t anim, uint32_t time) { + if (this->pages_.empty() || (this->current_page_ == 0 && !this->page_wrap_)) + return; + do { + this->current_page_ = (this->current_page_ + this->pages_.size() - 1) % this->pages_.size(); + } while (this->pages_[this->current_page_]->skip); // skip empty pages() + this->show_page(this->current_page_, anim, time); +} void LvglComponent::draw_buffer_(const lv_area_t *area, const uint8_t *ptr) { for (auto *display : this->displays_) { display->draw_pixels_at(area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area), ptr, @@ -27,6 +91,116 @@ void LvglComponent::flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv } lv_disp_flush_ready(disp_drv); } +IdleTrigger::IdleTrigger(LvglComponent *parent, TemplatableValue timeout) : timeout_(std::move(timeout)) { + parent->add_on_idle_callback([this](uint32_t idle_time) { + if (!this->is_idle_ && idle_time > this->timeout_.value()) { + this->is_idle_ = true; + this->trigger(); + } else if (this->is_idle_ && idle_time < this->timeout_.value()) { + this->is_idle_ = false; + } + }); +} + +#ifdef USE_LVGL_TOUCHSCREEN +LVTouchListener::LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) { + lv_indev_drv_init(&this->drv_); + this->drv_.long_press_repeat_time = long_press_repeat_time; + this->drv_.long_press_time = long_press_time; + this->drv_.type = LV_INDEV_TYPE_POINTER; + this->drv_.user_data = this; + this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { + auto *l = static_cast(d->user_data); + if (l->touch_pressed_) { + data->point.x = l->touch_point_.x; + data->point.y = l->touch_point_.y; + data->state = LV_INDEV_STATE_PRESSED; + } else { + data->state = LV_INDEV_STATE_RELEASED; + } + }; +} +void LVTouchListener::update(const touchscreen::TouchPoints_t &tpoints) { + this->touch_pressed_ = !this->parent_->is_paused() && !tpoints.empty(); + if (this->touch_pressed_) + this->touch_point_ = tpoints[0]; +} +#endif // USE_LVGL_TOUCHSCREEN + +#ifdef USE_LVGL_ROTARY_ENCODER +LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { + lv_indev_drv_init(&this->drv_); + this->drv_.type = type; + this->drv_.user_data = this; + this->drv_.long_press_time = lpt; + this->drv_.long_press_repeat_time = lprt; + this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { + auto *l = static_cast(d->user_data); + data->state = l->pressed_ ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; + data->key = l->key_; + data->enc_diff = (int16_t) (l->count_ - l->last_count_); + l->last_count_ = l->count_; + data->continue_reading = false; + }; +} +#endif // USE_LVGL_ROTARY_ENCODER + +#ifdef USE_LVGL_BUTTONMATRIX +void LvBtnmatrixType::set_obj(lv_obj_t *lv_obj) { + LvCompound::set_obj(lv_obj); + lv_obj_add_event_cb( + lv_obj, + [](lv_event_t *event) { + auto *self = static_cast(event->user_data); + if (self->key_callback_.size() == 0) + return; + auto key_idx = lv_btnmatrix_get_selected_btn(self->obj); + if (key_idx == LV_BTNMATRIX_BTN_NONE) + return; + if (self->key_map_.count(key_idx) != 0) { + self->send_key_(self->key_map_[key_idx]); + return; + } + const auto *str = lv_btnmatrix_get_btn_text(self->obj, key_idx); + auto len = strlen(str); + while (len--) + self->send_key_(*str++); + }, + LV_EVENT_PRESSED, this); +} +#endif // USE_LVGL_BUTTONMATRIX + +#ifdef USE_LVGL_KEYBOARD +static const char *const KB_SPECIAL_KEYS[] = { + "abc", "ABC", "1#", + // maybe add other special keys here +}; + +void LvKeyboardType::set_obj(lv_obj_t *lv_obj) { + LvCompound::set_obj(lv_obj); + lv_obj_add_event_cb( + lv_obj, + [](lv_event_t *event) { + auto *self = static_cast(event->user_data); + if (self->key_callback_.size() == 0) + return; + + auto key_idx = lv_btnmatrix_get_selected_btn(self->obj); + if (key_idx == LV_BTNMATRIX_BTN_NONE) + return; + const char *txt = lv_btnmatrix_get_btn_text(self->obj, key_idx); + if (txt == nullptr) + return; + for (const auto *kb_special_key : KB_SPECIAL_KEYS) { + if (strcmp(txt, kb_special_key) == 0) + return; + } + while (*txt != 0) + self->send_key_(*txt++); + }, + LV_EVENT_PRESSED, this); +} +#endif // USE_LVGL_KEYBOARD void LvglComponent::write_random_() { // length of 2 lines in 32 bit units @@ -97,9 +271,24 @@ void LvglComponent::setup() { this->disp_ = lv_disp_drv_register(&this->disp_drv_); for (const auto &v : this->init_lambdas_) v(this); + this->show_page(0, LV_SCR_LOAD_ANIM_NONE, 0); lv_disp_trig_activity(this->disp_); ESP_LOGCONFIG(TAG, "LVGL Setup complete"); } +void LvglComponent::update() { + // update indicators + if (this->paused_) { + return; + } + this->idle_callbacks_.call(lv_disp_get_inactive_time(this->disp_)); +} +void LvglComponent::loop() { + if (this->paused_) { + if (this->show_snow_) + this->write_random_(); + } + lv_timer_handler_run_in_period(5); +} #ifdef USE_LVGL_IMAGE lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { @@ -142,7 +331,20 @@ lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { } return img_dsc; } +#endif // USE_LVGL_IMAGE + +#ifdef USE_LVGL_ANIMIMG +void lv_animimg_stop(lv_obj_t *obj) { + auto *animg = (lv_animimg_t *) obj; + int32_t duration = animg->anim.time; + lv_animimg_set_duration(obj, 0); + lv_animimg_start(obj); + lv_animimg_set_duration(obj, duration); +} #endif +void LvglComponent::static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { + reinterpret_cast(disp_drv->user_data)->flush_cb_(disp_drv, area, color_p); +} } // namespace lvgl } // namespace esphome diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index a0d3d226ce..b92799addd 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -18,7 +18,6 @@ #include "esphome/core/component.h" #include "esphome/core/log.h" #include -#include #include #ifdef USE_LVGL_IMAGE #include "esphome/components/image/image.h" @@ -31,6 +30,10 @@ #include "esphome/components/touchscreen/touchscreen.h" #endif // USE_LVGL_TOUCHSCREEN +#if defined(USE_LVGL_BUTTONMATRIX) || defined(USE_LVGL_KEYBOARD) +#include "esphome/components/key_provider/key_provider.h" +#endif // USE_LVGL_BUTTONMATRIX + namespace esphome { namespace lvgl { @@ -47,12 +50,25 @@ static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BIT #endif // LV_COLOR_DEPTH // Parent class for things that wrap an LVGL object -class LvCompound final { +class LvCompound { public: - void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } + virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } lv_obj_t *obj{}; }; +class LvPageType { + public: + LvPageType(bool skip) : skip(skip) {} + + void setup(size_t index) { + this->index = index; + this->obj = lv_obj_create(nullptr); + } + lv_obj_t *obj{}; + size_t index{}; + bool skip; +}; + using LvLambdaType = std::function; using set_value_lambda_t = std::function; using event_callback_t = void(_lv_event_t *); @@ -89,48 +105,20 @@ class FontEngine { lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc = nullptr); #endif // USE_LVGL_IMAGE +#ifdef USE_LVGL_ANIMIMG +void lv_animimg_stop(lv_obj_t *obj); +#endif // USE_LVGL_ANIMIMG + class LvglComponent : public PollingComponent { constexpr static const char *const TAG = "lvgl"; public: - static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { - reinterpret_cast(disp_drv->user_data)->flush_cb_(disp_drv, area, color_p); - } + static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); float get_setup_priority() const override { return setup_priority::PROCESSOR; } - static void log_cb(const char *buf) { - esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); - } - static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { - // make sure all coordinates are even - if (area->x1 & 1) - area->x1--; - if (!(area->x2 & 1)) - area->x2++; - if (area->y1 & 1) - area->y1--; - if (!(area->y2 & 1)) - area->y2++; - } - void setup() override; - - void update() override { - // update indicators - if (this->paused_) { - return; - } - this->idle_callbacks_.call(lv_disp_get_inactive_time(this->disp_)); - } - - void loop() override { - if (this->paused_) { - if (this->show_snow_) - this->write_random_(); - } - lv_timer_handler_run_in_period(5); - } - + void update() override; + void loop() override; void add_on_idle_callback(std::function &&callback) { this->idle_callbacks_.add(std::move(callback)); } @@ -141,23 +129,15 @@ class LvglComponent : public PollingComponent { bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; } void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } lv_disp_t *get_disp() { return this->disp_; } - void set_paused(bool paused, bool show_snow) { - this->paused_ = paused; - this->show_snow_ = show_snow; - this->snow_line_ = 0; - if (!paused && lv_scr_act() != nullptr) { - lv_disp_trig_activity(this->disp_); // resets the inactivity time - lv_obj_invalidate(lv_scr_act()); - } - } - - void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) { - lv_obj_add_event_cb(obj, callback, event, this); - if (event == LV_EVENT_VALUE_CHANGED) { - lv_obj_add_event_cb(obj, callback, lv_custom_event, this); - } - } + void set_paused(bool paused, bool show_snow); + void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event); + void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2); bool is_paused() const { return this->paused_; } + void add_page(LvPageType *page); + void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time); + void show_next_page(lv_scr_load_anim_t anim, uint32_t time); + void show_prev_page(lv_scr_load_anim_t anim, uint32_t time); + void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; } protected: void write_random_(); @@ -168,8 +148,11 @@ class LvglComponent : public PollingComponent { lv_disp_drv_t disp_drv_{}; lv_disp_t *disp_{}; bool paused_{}; + std::vector pages_{}; + size_t current_page_{0}; bool show_snow_{}; lv_coord_t snow_line_{}; + bool page_wrap_{true}; std::vector> init_lambdas_; CallbackManager idle_callbacks_{}; @@ -179,16 +162,7 @@ class LvglComponent : public PollingComponent { class IdleTrigger : public Trigger<> { public: - explicit IdleTrigger(LvglComponent *parent, TemplatableValue timeout) : timeout_(std::move(timeout)) { - parent->add_on_idle_callback([this](uint32_t idle_time) { - if (!this->is_idle_ && idle_time > this->timeout_.value()) { - this->is_idle_ = true; - this->trigger(); - } else if (this->is_idle_ && idle_time < this->timeout_.value()) { - this->is_idle_ = false; - } - }); - } + explicit IdleTrigger(LvglComponent *parent, TemplatableValue timeout); protected: TemplatableValue timeout_; @@ -217,28 +191,8 @@ template class LvglCondition : public Condition, public P #ifdef USE_LVGL_TOUCHSCREEN class LVTouchListener : public touchscreen::TouchListener, public Parented { public: - LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) { - lv_indev_drv_init(&this->drv_); - this->drv_.long_press_repeat_time = long_press_repeat_time; - this->drv_.long_press_time = long_press_time; - this->drv_.type = LV_INDEV_TYPE_POINTER; - this->drv_.user_data = this; - this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { - auto *l = static_cast(d->user_data); - if (l->touch_pressed_) { - data->point.x = l->touch_point_.x; - data->point.y = l->touch_point_.y; - data->state = LV_INDEV_STATE_PRESSED; - } else { - data->state = LV_INDEV_STATE_RELEASED; - } - }; - } - void update(const touchscreen::TouchPoints_t &tpoints) override { - this->touch_pressed_ = !this->parent_->is_paused() && !tpoints.empty(); - if (this->touch_pressed_) - this->touch_point_ = tpoints[0]; - } + LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time); + void update(const touchscreen::TouchPoints_t &tpoints) override; void release() override { touch_pressed_ = false; } lv_indev_drv_t *get_drv() { return &this->drv_; } @@ -249,24 +203,10 @@ class LVTouchListener : public touchscreen::TouchListener, public Parented { public: - LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { - lv_indev_drv_init(&this->drv_); - this->drv_.type = type; - this->drv_.user_data = this; - this->drv_.long_press_time = lpt; - this->drv_.long_press_repeat_time = lprt; - this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { - auto *l = static_cast(d->user_data); - data->state = l->pressed_ ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; - data->key = l->key_; - data->enc_diff = (int16_t) (l->count_ - l->last_count_); - l->last_count_ = l->count_; - data->continue_reading = false; - }; - } + LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt); void set_left_button(binary_sensor::BinarySensor *left_button) { left_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_LEFT, state); }); @@ -304,6 +244,24 @@ class LVEncoderListener : public Parented { int32_t last_count_{}; int key_{}; }; -#endif // USE_LVGL_KEY_LISTENER +#endif // USE_LVGL_ROTARY_ENCODER +#ifdef USE_LVGL_BUTTONMATRIX +class LvBtnmatrixType : public key_provider::KeyProvider, public LvCompound { + public: + void set_obj(lv_obj_t *lv_obj) override; + uint16_t get_selected() { return lv_btnmatrix_get_selected_btn(this->obj); } + void set_key(size_t idx, uint8_t key) { this->key_map_[idx] = key; } + + protected: + std::map key_map_{}; +}; +#endif // USE_LVGL_BUTTONMATRIX + +#ifdef USE_LVGL_KEYBOARD +class LvKeyboardType : public key_provider::KeyProvider, public LvCompound { + public: + void set_obj(lv_obj_t *lv_obj) override; +}; +#endif // USE_LVGL_KEYBOARD } // namespace lvgl } // namespace esphome diff --git a/esphome/components/lvgl/page.py b/esphome/components/lvgl/page.py new file mode 100644 index 0000000000..4566b7eea4 --- /dev/null +++ b/esphome/components/lvgl/page.py @@ -0,0 +1,113 @@ +from esphome import automation, codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME + +from .defines import ( + CONF_ANIMATION, + CONF_LVGL_ID, + CONF_PAGE, + CONF_PAGE_WRAP, + CONF_SKIP, + LV_ANIM, +) +from .lv_validation import lv_bool, lv_milliseconds +from .lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp +from .schemas import LVGL_SCHEMA +from .types import LvglAction, lv_page_t +from .widget import Widget, WidgetType, add_widgets, set_obj_properties + + +class PageType(WidgetType): + def __init__(self): + super().__init__( + CONF_PAGE, + lv_page_t, + (), + { + cv.Optional(CONF_SKIP, default=False): lv_bool, + }, + ) + + async def to_code(self, w: Widget, config: dict): + return [] + + +SHOW_SCHEMA = LVGL_SCHEMA.extend( + { + cv.Optional(CONF_ANIMATION, default="NONE"): LV_ANIM.one_of, + cv.Optional(CONF_TIME, default="50ms"): lv_milliseconds, + } +) + + +page_spec = PageType() + + +@automation.register_action( + "lvgl.page.next", + LvglAction, + SHOW_SCHEMA, +) +async def page_next_to_code(config, action_id, template_arg, args): + animation = await LV_ANIM.process(config[CONF_ANIMATION]) + time = await lv_milliseconds.process(config[CONF_TIME]) + async with LambdaContext(LVGL_COMP_ARG) as context: + add_line_marks(action_id) + lv_add(lvgl_comp.show_next_page(animation, time)) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, config[CONF_LVGL_ID]) + return var + + +@automation.register_action( + "lvgl.page.previous", + LvglAction, + SHOW_SCHEMA, +) +async def page_previous_to_code(config, action_id, template_arg, args): + animation = await LV_ANIM.process(config[CONF_ANIMATION]) + time = await lv_milliseconds.process(config[CONF_TIME]) + async with LambdaContext(LVGL_COMP_ARG) as context: + add_line_marks(action_id) + lv_add(lvgl_comp.show_prev_page(animation, time)) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, config[CONF_LVGL_ID]) + return var + + +@automation.register_action( + "lvgl.page.show", + LvglAction, + cv.maybe_simple_value( + SHOW_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.use_id(lv_page_t), + } + ), + key=CONF_ID, + ), +) +async def page_show_to_code(config, action_id, template_arg, args): + widget = await cg.get_variable(config[CONF_ID]) + animation = await LV_ANIM.process(config[CONF_ANIMATION]) + time = await lv_milliseconds.process(config[CONF_TIME]) + async with LambdaContext(LVGL_COMP_ARG) as context: + add_line_marks(action_id) + lv_add(lvgl_comp.show_page(widget.index, animation, time)) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + await cg.register_parented(var, config[CONF_LVGL_ID]) + return var + + +async def add_pages(lv_component, config): + lv_add(lv_component.set_page_wrap(config[CONF_PAGE_WRAP])) + for pconf in config.get(CONF_PAGES, ()): + id = pconf[CONF_ID] + skip = pconf[CONF_SKIP] + var = cg.new_Pvariable(id, skip) + page = Widget.create(id, var, page_spec, pconf) + lv_add(lv_component.add_page(var)) + # Set outer config first + await set_obj_properties(page, config) + await set_obj_properties(page, pconf) + await add_widgets(page, pconf) diff --git a/esphome/components/lvgl/rotary_encoders.py b/esphome/components/lvgl/rotary_encoders.py index 77dc397c3e..ede6905a67 100644 --- a/esphome/components/lvgl/rotary_encoders.py +++ b/esphome/components/lvgl/rotary_encoders.py @@ -13,9 +13,10 @@ from .defines import ( CONF_ROTARY_ENCODERS, ) from .helpers import lvgl_components_required -from .lvcode import add_group, lv, lv_add, lv_expr +from .lvcode import lv, lv_add, lv_expr from .schemas import ENCODER_SCHEMA from .types import lv_indev_type_t +from .widget import add_group ROTARY_ENCODER_CONFIG = cv.ensure_list( ENCODER_SCHEMA.extend( diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index ebef56a882..796783890d 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -15,8 +15,12 @@ from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid, types as ty from .helpers import add_lv_use, requires_component, validate_printf -from .lv_validation import id_name, lv_font -from .types import WIDGET_TYPES, WidgetType +from .lv_validation import id_name, lv_color, lv_font, lv_image +from .lvcode import LvglComponent +from .types import WidgetType + +# this will be populated later, in __init__.py to avoid circular imports. +WIDGET_TYPES: dict = {} # A schema for text properties TEXT_SCHEMA = cv.Schema( @@ -38,11 +42,13 @@ TEXT_SCHEMA = cv.Schema( } ) -ACTION_SCHEMA = cv.maybe_simple_value( - { - cv.Required(CONF_ID): cv.use_id(ty.lv_pseudo_button_t), - }, - key=CONF_ID, +LIST_ACTION_SCHEMA = cv.ensure_list( + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(ty.lv_pseudo_button_t), + }, + key=CONF_ID, + ) ) PRESS_TIME = cv.All( @@ -154,6 +160,7 @@ STYLE_REMAP = { # Complete object style schema STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( { + cv.Optional(df.CONF_STYLES): cv.ensure_list(cv.use_id(ty.lv_style_t)), cv.Optional(df.CONF_SCROLLBAR_MODE): df.LvConstant( "LV_SCROLLBAR_MODE_", "OFF", "ON", "ACTIVE", "AUTO" ).one_of, @@ -209,7 +216,14 @@ def create_modify_schema(widget_type): part_schema(widget_type) .extend( { - cv.Required(CONF_ID): cv.use_id(widget_type), + cv.Required(CONF_ID): cv.ensure_list( + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(widget_type), + }, + key=CONF_ID, + ) + ), cv.Optional(CONF_STATE): SET_STATE_SCHEMA, } ) @@ -227,6 +241,7 @@ def obj_schema(widget_type: WidgetType): return ( part_schema(widget_type) .extend(FLAG_SCHEMA) + .extend(LAYOUT_SCHEMA) .extend(ALIGN_TO_SCHEMA) .extend(automation_schema(widget_type.w_type)) .extend( @@ -240,6 +255,8 @@ def obj_schema(widget_type: WidgetType): ) +LAYOUT_SCHEMAS = {} + ALIGN_TO_SCHEMA = { cv.Optional(df.CONF_ALIGN_TO): cv.Schema( { @@ -252,6 +269,65 @@ ALIGN_TO_SCHEMA = { } +def grid_free_space(value): + value = cv.Upper(value) + if value.startswith("FR(") and value.endswith(")"): + value = value.removesuffix(")").removeprefix("FR(") + return f"LV_GRID_FR({cv.positive_int(value)})" + raise cv.Invalid("must be a size in pixels, CONTENT or FR(nn)") + + +grid_spec = cv.Any( + lvalid.size, df.LvConstant("LV_GRID_", "CONTENT").one_of, grid_free_space +) + +cell_alignments = df.LV_CELL_ALIGNMENTS.one_of +grid_alignments = df.LV_GRID_ALIGNMENTS.one_of +flex_alignments = df.LV_FLEX_ALIGNMENTS.one_of + +LAYOUT_SCHEMA = { + cv.Optional(df.CONF_LAYOUT): cv.typed_schema( + { + df.TYPE_GRID: { + cv.Required(df.CONF_GRID_ROWS): [grid_spec], + cv.Required(df.CONF_GRID_COLUMNS): [grid_spec], + cv.Optional(df.CONF_GRID_COLUMN_ALIGN): grid_alignments, + cv.Optional(df.CONF_GRID_ROW_ALIGN): grid_alignments, + }, + df.TYPE_FLEX: { + cv.Optional( + df.CONF_FLEX_FLOW, default="row_wrap" + ): df.FLEX_FLOWS.one_of, + cv.Optional(df.CONF_FLEX_ALIGN_MAIN, default="start"): flex_alignments, + cv.Optional(df.CONF_FLEX_ALIGN_CROSS, default="start"): flex_alignments, + cv.Optional(df.CONF_FLEX_ALIGN_TRACK, default="start"): flex_alignments, + }, + }, + lower=True, + ) +} + +GRID_CELL_SCHEMA = { + cv.Required(df.CONF_GRID_CELL_ROW_POS): cv.positive_int, + cv.Required(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int, + cv.Optional(df.CONF_GRID_CELL_ROW_SPAN, default=1): cv.positive_int, + cv.Optional(df.CONF_GRID_CELL_COLUMN_SPAN, default=1): cv.positive_int, + cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, + cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments, +} + +FLEX_OBJ_SCHEMA = { + cv.Optional(df.CONF_FLEX_GROW): cv.int_, +} + +DISP_BG_SCHEMA = cv.Schema( + { + cv.Optional(df.CONF_DISP_BG_IMAGE): lv_image, + cv.Optional(df.CONF_DISP_BG_COLOR): lv_color, + } +) + + # A style schema that can include text STYLED_TEXT_SCHEMA = cv.maybe_simple_value( STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT @@ -260,13 +336,11 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value( # For use by platform components LVGL_SCHEMA = cv.Schema( { - cv.GenerateID(df.CONF_LVGL_ID): cv.use_id(ty.LvglComponent), + cv.GenerateID(df.CONF_LVGL_ID): cv.use_id(LvglComponent), } ) -ALL_STYLES = { - **STYLE_PROPS, -} +ALL_STYLES = {**STYLE_PROPS, **GRID_CELL_SCHEMA, **FLEX_OBJ_SCHEMA} def container_validator(schema, widget_type: WidgetType): @@ -281,16 +355,17 @@ def container_validator(schema, widget_type: WidgetType): result = schema if w_sch := widget_type.schema: result = result.extend(w_sch) + ltype = df.TYPE_NONE if value and (layout := value.get(df.CONF_LAYOUT)): if not isinstance(layout, dict): raise cv.Invalid("Layout value must be a dict") ltype = layout.get(CONF_TYPE) + if not ltype: + raise (cv.Invalid("Layout schema requires type:")) add_lv_use(ltype) - result = result.extend( - {cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema())} - ) if value == SCHEMA_EXTRACT: return result + result = result.extend(LAYOUT_SCHEMAS[ltype.lower()]) return result(value) return validator diff --git a/esphome/components/lvgl/slider.py b/esphome/components/lvgl/slider.py new file mode 100644 index 0000000000..1886f79b44 --- /dev/null +++ b/esphome/components/lvgl/slider.py @@ -0,0 +1,63 @@ +import esphome.config_validation as cv +from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, CONF_VALUE + +from .defines import ( + BAR_MODES, + CONF_ANIMATED, + CONF_INDICATOR, + CONF_KNOB, + CONF_MAIN, + literal, +) +from .helpers import add_lv_use +from .lv_bar import CONF_BAR +from .lv_validation import animated, get_start_value, lv_float +from .lvcode import lv +from .types import LvNumber, NumberType +from .widget import Widget + +CONF_SLIDER = "slider" +SLIDER_MODIFY_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_ANIMATED, default=True): animated, + } +) + +SLIDER_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_MIN_VALUE, default=0): cv.int_, + cv.Optional(CONF_MAX_VALUE, default=100): cv.int_, + cv.Optional(CONF_MODE, default="NORMAL"): BAR_MODES.one_of, + cv.Optional(CONF_ANIMATED, default=True): animated, + } +) + + +class SliderType(NumberType): + def __init__(self): + super().__init__( + CONF_SLIDER, + LvNumber("lv_slider_t"), + parts=(CONF_MAIN, CONF_INDICATOR, CONF_KNOB), + schema=SLIDER_SCHEMA, + modify_schema=SLIDER_MODIFY_SCHEMA, + ) + + @property + def animated(self): + return True + + async def to_code(self, w: Widget, config): + add_lv_use(CONF_BAR) + if CONF_MIN_VALUE in config: + # not modify case + lv.slider_set_range(w.obj, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE]) + lv.slider_set_mode(w.obj, literal(config[CONF_MODE])) + value = await get_start_value(config) + if value is not None: + lv.slider_set_value(w.obj, value, literal(config[CONF_ANIMATED])) + + +slider_spec = SliderType() diff --git a/esphome/components/lvgl/spinner.py b/esphome/components/lvgl/spinner.py new file mode 100644 index 0000000000..2f798d0fbf --- /dev/null +++ b/esphome/components/lvgl/spinner.py @@ -0,0 +1,43 @@ +import esphome.config_validation as cv +from esphome.cpp_generator import MockObjClass + +from .arc import CONF_ARC +from .defines import CONF_ARC_LENGTH, CONF_INDICATOR, CONF_MAIN, CONF_SPIN_TIME +from .lv_validation import angle +from .lvcode import lv_expr +from .types import LvType +from .widget import Widget, WidgetType + +CONF_SPINNER = "spinner" + +SPINNER_SCHEMA = cv.Schema( + { + cv.Required(CONF_ARC_LENGTH): angle, + cv.Required(CONF_SPIN_TIME): cv.positive_time_period_milliseconds, + } +) + + +class SpinnerType(WidgetType): + def __init__(self): + super().__init__( + CONF_SPINNER, + LvType("lv_spinner_t"), + (CONF_MAIN, CONF_INDICATOR), + SPINNER_SCHEMA, + {}, + ) + + async def to_code(self, w: Widget, config): + return [] + + def get_uses(self): + return (CONF_ARC,) + + def obj_creator(self, parent: MockObjClass, config: dict): + spin_time = config[CONF_SPIN_TIME].total_milliseconds + arc_length = config[CONF_ARC_LENGTH] // 10 + return lv_expr.call("spinner_create", parent, spin_time, arc_length) + + +spinner_spec = SpinnerType() diff --git a/esphome/components/lvgl/styles.py b/esphome/components/lvgl/styles.py new file mode 100644 index 0000000000..7a795bc99d --- /dev/null +++ b/esphome/components/lvgl/styles.py @@ -0,0 +1,58 @@ +import esphome.codegen as cg +from esphome.const import CONF_ID +from esphome.core import ID +from esphome.cpp_generator import MockObj + +from .defines import ( + CONF_STYLE_DEFINITIONS, + CONF_THEME, + CONF_TOP_LAYER, + LValidator, + literal, +) +from .helpers import add_lv_use +from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable +from .obj import obj_spec +from .schemas import ALL_STYLES +from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr +from .widget import Widget, add_widgets, set_obj_properties, theme_widget_map + +TOP_LAYER = literal("lv_disp_get_layer_top(lv_component->get_disp())") + + +async def styles_to_code(config): + """Convert styles to C__ code.""" + for style in config.get(CONF_STYLE_DEFINITIONS, ()): + svar = cg.new_Pvariable(style[CONF_ID]) + lv.style_init(svar) + for prop, validator in ALL_STYLES.items(): + if value := style.get(prop): + if isinstance(validator, LValidator): + value = await validator.process(value) + if isinstance(value, list): + value = "|".join(value) + lv.call(f"style_set_{prop}", svar, literal(value)) + + +async def theme_to_code(config): + if theme := config.get(CONF_THEME): + add_lv_use(CONF_THEME) + for w_name, style in theme.items(): + if not isinstance(style, dict): + continue + + lname = "lv_theme_apply_" + w_name + apply = lv_variable(lv_lambda_t, lname) + theme_widget_map[w_name] = apply + ow = Widget.create("obj", MockObj(ID("obj")), obj_spec) + async with LambdaContext([(lv_obj_t_ptr, "obj")], where=w_name) as context: + await set_obj_properties(ow, style) + lv_assign(apply, await context.get_lambda()) + + +async def add_top_layer(config): + if top_conf := config.get(CONF_TOP_LAYER): + with LocalVariable("top_layer", lv_obj_t, TOP_LAYER) as top_layer_obj: + top_w = Widget(top_layer_obj, obj_spec, top_conf) + await set_obj_properties(top_w, top_conf) + await add_widgets(top_w, top_conf) diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index bf92bda5b0..c640c8abd9 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -7,15 +7,14 @@ from .defines import ( CONF_ALIGN_TO, CONF_X, CONF_Y, - LV_EVENT, + LV_EVENT_MAP, LV_EVENT_TRIGGERS, literal, ) -from .lvcode import LambdaContext, add_line_marks, lv, lv_add +from .lvcode import EVENT_ARG, LambdaContext, LvConditional, lv, lv_add +from .types import LV_EVENT from .widget import widget_map -lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") - async def generate_triggers(lv_component): """ @@ -34,15 +33,15 @@ async def generate_triggers(lv_component): }.items(): conf = conf[0] w.add_flag("LV_OBJ_FLAG_CLICKABLE") - event = "LV_EVENT_" + LV_EVENT[event[3:].upper()] + event = literal("LV_EVENT_" + LV_EVENT_MAP[event[3:].upper()]) await add_trigger(conf, event, lv_component, w) for conf in w.config.get(CONF_ON_VALUE, ()): - await add_trigger(conf, "LV_EVENT_VALUE_CHANGED", lv_component, w) + await add_trigger(conf, LV_EVENT.VALUE_CHANGED, lv_component, w) # Generate align to directives while we're here if align_to := w.config.get(CONF_ALIGN_TO): target = widget_map[align_to[CONF_ID]].obj - align = align_to[CONF_ALIGN] + align = literal(align_to[CONF_ALIGN]) x = align_to[CONF_X] y = align_to[CONF_Y] lv.obj_align_to(w.obj, target, align, x, y) @@ -50,12 +49,11 @@ async def generate_triggers(lv_component): async def add_trigger(conf, event, lv_component, w): tid = conf[CONF_TRIGGER_ID] - add_line_marks(tid) trigger = cg.new_Pvariable(tid) args = w.get_args() value = w.get_value() await automation.build_automation(trigger, args, conf) - with LambdaContext([(lv_event_t_ptr, "event_data")]) as context: - add_line_marks(tid) - lv_add(trigger.trigger(value)) - lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), literal(event))) + async with LambdaContext(EVENT_ARG, where=tid) as context: + with LvConditional(w.is_selected()): + lv_add(trigger.trigger(value)) + lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), event)) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index 6997207dac..b6f65c8c1b 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -1,8 +1,11 @@ -from esphome import automation, codegen as cg -from esphome.core import ID -from esphome.cpp_generator import MockObjClass +import sys -from .defines import CONF_TEXT +from esphome import automation, codegen as cg +from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_VALUE +from esphome.cpp_generator import MockObj, MockObjClass + +from .defines import CONF_TEXT, lvgl_ns +from .lvcode import lv_expr class LvType(cg.MockObjClass): @@ -18,36 +21,48 @@ class LvType(cg.MockObjClass): return self.args[0][0] if len(self.args) else None +class LvNumber(LvType): + def __init__(self, *args): + super().__init__( + *args, + largs=[(cg.float_, "x")], + lvalue=lambda w: w.get_number_value(), + has_on_value=True, + ) + self.value_property = CONF_VALUE + + uint16_t_ptr = cg.uint16.operator("ptr") -lvgl_ns = cg.esphome_ns.namespace("lvgl") char_ptr = cg.global_ns.namespace("char").operator("ptr") void_ptr = cg.void.operator("ptr") -LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) -LvglComponentPtr = LvglComponent.operator("ptr") -lv_event_code_t = cg.global_ns.namespace("lv_event_code_t") +lv_coord_t = cg.global_ns.namespace("lv_coord_t") +lv_event_code_t = cg.global_ns.enum("lv_event_code_t") lv_indev_type_t = cg.global_ns.enum("lv_indev_type_t") FontEngine = lvgl_ns.class_("FontEngine") IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template()) ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action) LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition) LvglAction = lvgl_ns.class_("LvglAction", automation.Action) +lv_lambda_t = lvgl_ns.class_("LvLambdaType") LvCompound = lvgl_ns.class_("LvCompound") lv_font_t = cg.global_ns.class_("lv_font_t") lv_style_t = cg.global_ns.struct("lv_style_t") +# fake parent class for first class widgets and matrix buttons lv_pseudo_button_t = lvgl_ns.class_("LvPseudoButton") lv_obj_base_t = cg.global_ns.class_("lv_obj_t", lv_pseudo_button_t) lv_obj_t_ptr = lv_obj_base_t.operator("ptr") -lv_disp_t_ptr = cg.global_ns.struct("lv_disp_t").operator("ptr") +lv_disp_t = cg.global_ns.struct("lv_disp_t") lv_color_t = cg.global_ns.struct("lv_color_t") lv_group_t = cg.global_ns.struct("lv_group_t") LVTouchListener = lvgl_ns.class_("LVTouchListener") LVEncoderListener = lvgl_ns.class_("LVEncoderListener") lv_obj_t = LvType("lv_obj_t") +lv_page_t = cg.global_ns.class_("LvPageType", LvCompound) lv_img_t = LvType("lv_img_t") - -# this will be populated later, in __init__.py to avoid circular imports. -WIDGET_TYPES: dict = {} +LV_EVENT = MockObj(base="LV_EVENT_", op="") +LV_STATE = MockObj(base="LV_STATE_", op="") +LV_BTNMATRIX_CTRL = MockObj(base="LV_BTNMATRIX_CTRL_", op="") class LvText(LvType): @@ -55,7 +70,8 @@ class LvText(LvType): super().__init__( *args, largs=[(cg.std_string, "text")], - lvalue=lambda w: w.get_property("text")[0], + lvalue=lambda w: w.get_property("text"), + has_on_value=True, **kwargs, ) self.value_property = CONF_TEXT @@ -66,13 +82,21 @@ class LvBoolean(LvType): super().__init__( *args, largs=[(cg.bool_, "x")], - lvalue=lambda w: w.has_state("LV_STATE_CHECKED"), + lvalue=lambda w: w.is_checked(), has_on_value=True, **kwargs, ) -CUSTOM_EVENT = ID("lv_custom_event", False, type=lv_event_code_t) +class LvSelect(LvType): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + largs=[(cg.int_, "x")], + lvalue=lambda w: w.get_property("selected"), + has_on_value=True, + **kwargs, + ) class WidgetType: @@ -80,7 +104,15 @@ class WidgetType: Describes a type of Widget, e.g. "bar" or "line" """ - def __init__(self, name, w_type, parts, schema=None, modify_schema=None): + def __init__( + self, + name: str, + w_type: LvType, + parts: tuple, + schema=None, + modify_schema=None, + lv_name=None, + ): """ :param name: The widget name, e.g. "bar" :param w_type: The C type of the widget @@ -89,6 +121,7 @@ class WidgetType: :param modify_schema: A schema to update the widget """ self.name = name + self.lv_name = lv_name or name self.w_type = w_type self.parts = parts if schema is None: @@ -98,7 +131,8 @@ class WidgetType: if modify_schema is None: self.modify_schema = self.schema else: - self.modify_schema = self.schema + self.modify_schema = modify_schema + self.mock_obj = MockObj(f"lv_{self.lv_name}", "_") @property def animated(self): @@ -118,7 +152,7 @@ class WidgetType: :param config: Its configuration :return: Generated code as a list of text lines """ - raise NotImplementedError(f"No to_code defined for {self.name}") + return [] def obj_creator(self, parent: MockObjClass, config: dict): """ @@ -127,7 +161,7 @@ class WidgetType: :param config: Its configuration :return: Generated code as a single text line """ - return f"lv_{self.name}_create({parent})" + return lv_expr.call(f"{self.lv_name}_create", parent) def get_uses(self): """ @@ -135,3 +169,23 @@ class WidgetType: :return: """ return () + + def get_max(self, config: dict): + return sys.maxsize + + def get_min(self, config: dict): + return -sys.maxsize + + def get_step(self, config: dict): + return 1 + + def get_scale(self, config: dict): + return 1.0 + + +class NumberType(WidgetType): + def get_max(self, config: dict): + return int(config[CONF_MAX_VALUE] or 100) + + def get_min(self, config: dict): + return int(config[CONF_MIN_VALUE] or 0) diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widget.py index 83aed341e7..5734aec7dc 100644 --- a/esphome/components/lvgl/widget.py +++ b/esphome/components/lvgl/widget.py @@ -1,33 +1,63 @@ import sys -from typing import Any +from typing import Any, Union from esphome import codegen as cg, config_validation as cv from esphome.config_validation import Invalid -from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE -from esphome.core import CORE, TimePeriod +from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE +from esphome.core import ID, TimePeriod from esphome.coroutine import FakeAwaitable -from esphome.cpp_generator import MockObj, MockObjClass, VariableDeclarationExpression +from esphome.cpp_generator import AssignmentExpression, CallExpression, MockObj from .defines import ( CONF_DEFAULT, + CONF_FLEX_ALIGN_CROSS, + CONF_FLEX_ALIGN_MAIN, + CONF_FLEX_ALIGN_TRACK, + CONF_FLEX_FLOW, + CONF_GRID_COLUMN_ALIGN, + CONF_GRID_COLUMNS, + CONF_GRID_ROW_ALIGN, + CONF_GRID_ROWS, + CONF_LAYOUT, CONF_MAIN, CONF_SCROLLBAR_MODE, + CONF_STYLES, CONF_WIDGETS, OBJ_FLAGS, PARTS, STATES, - ConstantLiteral, + TYPE_FLEX, + TYPE_GRID, LValidator, join_enums, literal, ) from .helpers import add_lv_use -from .lvcode import add_group, add_line_marks, lv, lv_add, lv_assign, lv_expr, lv_obj -from .schemas import ALL_STYLES, STYLE_REMAP -from .types import WIDGET_TYPES, LvType, WidgetType, lv_obj_t, lv_obj_t_ptr +from .lvcode import ( + LvConditional, + add_line_marks, + lv, + lv_add, + lv_assign, + lv_expr, + lv_obj, + lv_Pvariable, +) +from .schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES +from .types import ( + LV_STATE, + LvType, + WidgetType, + lv_coord_t, + lv_group_t, + lv_obj_t, + lv_obj_t_ptr, +) EVENT_LAMB = "event_lamb__" +theme_widget_map = {} + class LvScrActType(WidgetType): """ @@ -37,9 +67,6 @@ class LvScrActType(WidgetType): def __init__(self): super().__init__("lv_scr_act()", lv_obj_t, ()) - def obj_creator(self, parent: MockObjClass, config: dict): - return [] - async def to_code(self, w, config: dict): return [] @@ -55,7 +82,7 @@ class Widget: def set_completed(): Widget.widgets_completed = True - def __init__(self, var, wtype: WidgetType, config: dict = None, parent=None): + def __init__(self, var, wtype: WidgetType, config: dict = None): self.var = var self.type = wtype self.config = config @@ -63,21 +90,18 @@ class Widget: self.step = 1.0 self.range_from = -sys.maxsize self.range_to = sys.maxsize - self.parent = parent + if wtype.is_compound(): + self.obj = MockObj(f"{self.var}->obj") + else: + self.obj = var @staticmethod - def create(name, var, wtype: WidgetType, config: dict = None, parent=None): - w = Widget(var, wtype, config, parent) + def create(name, var, wtype: WidgetType, config: dict = None): + w = Widget(var, wtype, config) if name is not None: widget_map[name] = w return w - @property - def obj(self): - if self.type.is_compound(): - return f"{self.var}->obj" - return self.var - def add_state(self, state): return lv_obj.add_state(self.obj, literal(state)) @@ -85,7 +109,13 @@ class Widget: return lv_obj.clear_state(self.obj, literal(state)) def has_state(self, state): - return lv_expr.obj_get_state(self.obj) & literal(state) != 0 + return (lv_expr.obj_get_state(self.obj) & literal(state)) != 0 + + def is_pressed(self): + return self.has_state(LV_STATE.PRESSED) + + def is_checked(self): + return self.has_state(LV_STATE.CHECKED) def add_flag(self, flag): return lv_obj.add_flag(self.obj, literal(flag)) @@ -93,32 +123,37 @@ class Widget: def clear_flag(self, flag): return lv_obj.clear_flag(self.obj, literal(flag)) - def set_property(self, prop, value, animated: bool = None, ltype=None): + async def set_property(self, prop, value, animated: bool = None): if isinstance(value, dict): value = value.get(prop) + if isinstance(ALL_STYLES.get(prop), LValidator): + value = await ALL_STYLES[prop].process(value) + else: + value = literal(value) if value is None: return if isinstance(value, TimePeriod): value = value.total_milliseconds - ltype = ltype or self.__type_base() + if isinstance(value, str): + value = literal(value) if animated is None or self.type.animated is not True: - lv.call(f"{ltype}_set_{prop}", self.obj, value) + lv.call(f"{self.type.lv_name}_set_{prop}", self.obj, value) else: lv.call( - f"{ltype}_set_{prop}", + f"{self.type.lv_name}_set_{prop}", self.obj, value, - "LV_ANIM_ON" if animated else "LV_ANIM_OFF", + literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"), ) def get_property(self, prop, ltype=None): ltype = ltype or self.__type_base() - return f"lv_{ltype}_get_{prop}({self.obj})" + return cg.RawExpression(f"lv_{ltype}_get_{prop}({self.obj})") def set_style(self, prop, value, state): if value is None: - return [] - return lv.call(f"obj_set_style_{prop}", self.obj, value, state) + return + lv.call(f"obj_set_style_{prop}", self.obj, value, state) def __type_base(self): wtype = self.type.w_type @@ -140,6 +175,32 @@ class Widget: return self.type.w_type.value(self) return self.obj + def get_number_value(self): + value = self.type.mock_obj.get_value(self.obj) + if self.scale == 1.0: + return value + return value / float(self.scale) + + def is_selected(self): + """ + Overridable property to determine if the widget is selected. Will be None except + for matrix buttons + :return: + """ + return None + + def get_max(self): + return self.type.get_max(self.config) + + def get_min(self): + return self.type.get_min(self.config) + + def get_step(self): + return self.type.get_step(self.config) + + def get_scale(self): + return self.type.get_scale(self.config) + # Map of widgets to their config, used for trigger generation widget_map: dict[Any, Widget] = {} @@ -161,13 +222,20 @@ def get_widget_generator(wid): yield -async def get_widget(config: dict, id: str = CONF_ID) -> Widget: - wid = config[id] +async def get_widget_(wid: Widget): if obj := widget_map.get(wid): return obj return await FakeAwaitable(get_widget_generator(wid)) +async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]: + if not config: + return [] + if not isinstance(config, list): + config = [config] + return [await get_widget_(c[id]) for c in config if id in c] + + def collect_props(config): """ Collect all properties from a configuration @@ -175,7 +243,7 @@ def collect_props(config): :return: """ props = {} - for prop in [*ALL_STYLES, *OBJ_FLAGS, CONF_GROUP]: + for prop in [*ALL_STYLES, *OBJ_FLAGS, CONF_STYLES, CONF_GROUP]: if prop in config: props[prop] = config[prop] return props @@ -209,12 +277,39 @@ def collect_parts(config): async def set_obj_properties(w: Widget, config): """Generate a list of C++ statements to apply properties to an lv_obj_t""" + if layout := config.get(CONF_LAYOUT): + layout_type: str = layout[CONF_TYPE] + lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}")) + if layout_type == TYPE_GRID: + wid = config[CONF_ID] + rows = "{" + ",".join(layout[CONF_GRID_ROWS]) + ", LV_GRID_TEMPLATE_LAST}" + row_id = ID(f"{wid}_row_dsc", is_declaration=True, type=lv_coord_t) + row_array = cg.static_const_array(row_id, cg.RawExpression(rows)) + w.set_style("grid_row_dsc_array", row_array, 0) + columns = ( + "{" + ",".join(layout[CONF_GRID_COLUMNS]) + ", LV_GRID_TEMPLATE_LAST}" + ) + column_id = ID(f"{wid}_column_dsc", is_declaration=True, type=lv_coord_t) + column_array = cg.static_const_array(column_id, cg.RawExpression(columns)) + w.set_style("grid_column_dsc_array", column_array, 0) + w.set_style( + CONF_GRID_COLUMN_ALIGN, literal(layout.get(CONF_GRID_COLUMN_ALIGN)), 0 + ) + w.set_style( + CONF_GRID_ROW_ALIGN, literal(layout.get(CONF_GRID_ROW_ALIGN)), 0 + ) + if layout_type == TYPE_FLEX: + lv_obj.set_flex_flow(w.obj, literal(layout[CONF_FLEX_FLOW])) + main = literal(layout[CONF_FLEX_ALIGN_MAIN]) + cross = literal(layout[CONF_FLEX_ALIGN_CROSS]) + track = literal(layout[CONF_FLEX_ALIGN_TRACK]) + lv_obj.set_flex_align(w.obj, main, cross, track) parts = collect_parts(config) for part, states in parts.items(): for state, props in states.items(): - lv_state = ConstantLiteral( - f"(int)LV_STATE_{state.upper()}|(int)LV_PART_{part.upper()}" - ) + lv_state = join_enums((f"LV_STATE_{state}", f"LV_PART_{part}")) + for style_id in props.get(CONF_STYLES, ()): + lv_obj.add_style(w.obj, MockObj(style_id), lv_state) for prop, value in { k: v for k, v in props.items() if k in ALL_STYLES }.items(): @@ -258,14 +353,12 @@ async def set_obj_properties(w: Widget, config): w.clear_state(clears) for key, value in lambs.items(): lamb = await cg.process_lambda(value, [], return_type=cg.bool_) - state = f"LV_STATE_{key.upper}" - lv.cond_if(lamb) - w.add_state(state) - lv.cond_else() - w.clear_state(state) - lv.cond_endif() - if scrollbar_mode := config.get(CONF_SCROLLBAR_MODE): - lv_obj.set_scrollbar_mode(w.obj, scrollbar_mode) + state = f"LV_STATE_{key.upper()}" + with LvConditional(f"{lamb}()") as cond: + w.add_state(state) + cond.else_() + w.clear_state(state) + await w.set_property(CONF_SCROLLBAR_MODE, config) async def add_widgets(parent: Widget, config: dict): @@ -280,7 +373,7 @@ async def add_widgets(parent: Widget, config: dict): await widget_to_code(w_cnfig, w_type, parent.obj) -async def widget_to_code(w_cnfig, w_type, parent): +async def widget_to_code(w_cnfig, w_type: WidgetType, parent): """ Converts a Widget definition to C code. :param w_cnfig: The widget configuration @@ -298,19 +391,33 @@ async def widget_to_code(w_cnfig, w_type, parent): var = cg.new_Pvariable(wid) lv_add(var.set_obj(creator)) else: - var = MockObj(wid, "->") - decl = VariableDeclarationExpression(lv_obj_t, "*", wid) - CORE.add_global(decl) - CORE.register_variable(wid, var) + var = lv_Pvariable(lv_obj_t, wid) lv_assign(var, creator) - widget = Widget.create(wid, var, spec, w_cnfig, parent) - await set_obj_properties(widget, w_cnfig) - await add_widgets(widget, w_cnfig) - await spec.to_code(widget, w_cnfig) + w = Widget.create(wid, var, spec, w_cnfig) + if theme := theme_widget_map.get(w_type): + lv_add(CallExpression(theme, w.obj)) + await set_obj_properties(w, w_cnfig) + await add_widgets(w, w_cnfig) + await spec.to_code(w, w_cnfig) lv_scr_act_spec = LvScrActType() -lv_scr_act = Widget.create( - None, ConstantLiteral("lv_scr_act()"), lv_scr_act_spec, {}, parent=None -) +lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {}) + +lv_groups = {} # Widget group names + + +def add_group(name): + if name is None: + return None + fullname = f"lv_esp_group_{name}" + if name not in lv_groups: + gid = ID(fullname, True, type=lv_group_t.operator("ptr")) + lv_add( + AssignmentExpression( + type_=gid.type, modifier="", name=fullname, rhs=lv_expr.group_create() + ) + ) + lv_groups[name] = literal(fullname) + return lv_groups[name] diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index fde700e0bd..0cca45d376 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -5,142 +5,229 @@ lvgl: - touchscreen_id: tft_touch long_press_repeat_time: 200ms long_press_time: 500ms - widgets: - - label: - id: hello_label - text: Hello world - text_color: 0xFF8000 - align: center - text_font: montserrat_40 - border_post: true - - - label: - text: "Hello shiny day" - text_color: 0xFFFFFF - align: bottom_mid - text_font: space16 - - obj: - align: center - arc_opa: COVER - arc_color: 0xFF0000 - arc_rounded: false - arc_width: 3 - anim_time: 1s - bg_color: light_blue - bg_grad_color: light_blue - bg_dither_mode: ordered - bg_grad_dir: hor - bg_grad_stop: 128 - bg_image_opa: transp - bg_image_recolor: light_blue - bg_image_recolor_opa: 50% - bg_main_stop: 0 - bg_opa: 20% - border_color: 0x00FF00 - border_opa: cover - border_post: true - border_side: [bottom, left] - border_width: 4 - clip_corner: false - height: 50% - image_recolor: light_blue - image_recolor_opa: cover - line_width: 10 - line_dash_width: 10 - line_dash_gap: 10 - line_rounded: false - line_color: light_blue - opa: cover - opa_layered: cover - outline_color: light_blue - outline_opa: cover - outline_pad: 10px - outline_width: 10px - pad_all: 10px - pad_bottom: 10px - pad_column: 10px - pad_left: 10px - pad_right: 10px - pad_row: 10px - pad_top: 10px - shadow_color: light_blue - shadow_ofs_x: 5 - shadow_ofs_y: 5 - shadow_opa: cover - shadow_spread: 5 - shadow_width: 10 - text_align: auto - text_color: light_blue - text_decor: [underline, strikethrough] - text_font: montserrat_18 - text_letter_space: 4 - text_line_space: 4 - text_opa: cover - transform_angle: 180 - transform_height: 100 - transform_pivot_x: 50% - transform_pivot_y: 50% - transform_zoom: 0.5 - translate_x: 10 - translate_y: 10 - max_height: 100 - max_width: 200 - min_height: 20% - min_width: 20% - radius: circle - width: 10px - x: 100 - y: 120 - - button: - width: 20% - height: 10% - pressed: - bg_color: light_blue - checkable: true - checked: - bg_color: 0x000000 - widgets: - - label: - text: Button - on_click: - lvgl.label.update: + pages: + - id: page1 + skip: true + widgets: + - label: id: hello_label - bg_color: 0x123456 - text: clicked - on_value: - logger.log: - format: "state now %d" - args: [x] - on_short_click: - lvgl.widget.hide: hello_label - on_long_press: - lvgl.widget.show: hello_label - on_cancel: - lvgl.widget.enable: hello_label - on_ready: - lvgl.widget.disable: hello_label - on_defocus: - lvgl.widget.hide: hello_label - on_focus: - logger.log: Button clicked - on_scroll: - logger.log: Button clicked - on_scroll_end: - logger.log: Button clicked - on_scroll_begin: - logger.log: Button clicked - on_release: - logger.log: Button clicked - on_long_press_repeat: - logger.log: Button clicked + text: Hello world + text_color: 0xFF8000 + align: center + text_font: montserrat_40 + border_post: true + - label: + text: "Hello shiny day" + text_color: 0xFFFFFF + align: bottom_mid + text_font: space16 + - obj: + align: center + arc_opa: COVER + arc_color: 0xFF0000 + arc_rounded: false + arc_width: 3 + anim_time: 1s + bg_color: light_blue + bg_grad_color: light_blue + bg_dither_mode: ordered + bg_grad_dir: hor + bg_grad_stop: 128 + bg_image_opa: transp + bg_image_recolor: light_blue + bg_image_recolor_opa: 50% + bg_main_stop: 0 + bg_opa: 20% + border_color: 0x00FF00 + border_opa: cover + border_post: true + border_side: [bottom, left] + border_width: 4 + clip_corner: false + height: 50% + image_recolor: light_blue + image_recolor_opa: cover + line_width: 10 + line_dash_width: 10 + line_dash_gap: 10 + line_rounded: false + line_color: light_blue + opa: cover + opa_layered: cover + outline_color: light_blue + outline_opa: cover + outline_pad: 10px + outline_width: 10px + pad_all: 10px + pad_bottom: 10px + pad_column: 10px + pad_left: 10px + pad_right: 10px + pad_row: 10px + pad_top: 10px + shadow_color: light_blue + shadow_ofs_x: 5 + shadow_ofs_y: 5 + shadow_opa: cover + shadow_spread: 5 + shadow_width: 10 + text_align: auto + text_color: light_blue + text_decor: [underline, strikethrough] + text_font: montserrat_18 + text_letter_space: 4 + text_line_space: 4 + text_opa: cover + transform_angle: 180 + transform_height: 100 + transform_pivot_x: 50% + transform_pivot_y: 50% + transform_zoom: 0.5 + translate_x: 10 + translate_y: 10 + max_height: 100 + max_width: 200 + min_height: 20% + min_width: 20% + radius: circle + width: 10px + x: 100 + y: 120 + - button: + width: 20% + height: 10% + pressed: + bg_color: light_blue + checkable: true + checked: + bg_color: 0x000000 + widgets: + - label: + text: Button + on_click: + lvgl.label.update: + id: hello_label + bg_color: 0x123456 + text: clicked + on_value: + logger.log: + format: "state now %d" + args: [x] + on_short_click: + lvgl.widget.hide: hello_label + on_long_press: + lvgl.widget.show: hello_label + on_cancel: + lvgl.widget.enable: hello_label + on_ready: + lvgl.widget.disable: hello_label + on_defocus: + lvgl.widget.hide: hello_label + on_focus: + logger.log: Button clicked + on_scroll: + logger.log: Button clicked + on_scroll_end: + logger.log: Button clicked + on_scroll_begin: + logger.log: Button clicked + on_release: + logger.log: Button clicked + on_long_press_repeat: + logger.log: Button clicked + - led: + color: 0x00FF00 + brightness: 50% + align: right_mid + - spinner: + arc_length: 120 + spin_time: 2s + align: left_mid + - image: + src: cat_image + align: top_left + y: 50 + + - id: page2 + widgets: + - arc: + align: left_mid + id: lv_arc + adjustable: true + on_value: + then: + - logger.log: + format: "Arc value is %f" + args: [x] + group: general + scroll_on_focus: true + value: 75 + min_value: 1 + max_value: 100 + arc_color: 0xFF0000 + indicator: + arc_color: 0xF000FF + pressed: + arc_color: 0xFFFF00 + focused: + arc_color: 0x808080 + - bar: + id: bar_id + align: top_mid + y: 20 + value: 30 + max_value: 100 + min_value: 10 + mode: range + on_click: + then: + - lvgl.bar.update: + id: bar_id + value: !lambda return (int)((float)rand() / RAND_MAX * 100); + - logger.log: + format: "bar value %f" + args: [x] + - line: + align: center + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 240, 10 + on_click: + lvgl.page.next: + - switch: + align: right_mid + - checkbox: + text: Checkbox + align: bottom_right + - slider: + id: slider_id + align: top_mid + y: 40 + value: 30 + max_value: 100 + min_value: 10 + mode: normal + on_value: + then: + - logger.log: + format: "slider value %f" + args: [x] + on_click: + then: + - lvgl.slider.update: + id: slider_id + value: !lambda return (int)((float)rand() / RAND_MAX * 100); font: - file: "gfonts://Roboto" id: space16 bpp: 4 image: - - id: cat_img + - id: cat_image resize: 256x48 file: $component_dir/logo-text.svg - id: dog_img From e02319dcff75a003b5551866c701dd81803022c8 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Mon, 5 Aug 2024 12:09:54 -0400 Subject: [PATCH 2159/2607] [esp32_improv] Update Improv library to reference new repo/version (#7195) --- esphome/components/esp32_improv/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index 62d9cd376c..705dff0f1b 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -1,9 +1,8 @@ import esphome.codegen as cg +from esphome.components import binary_sensor, esp32_ble_server, output import esphome.config_validation as cv -from esphome.components import binary_sensor, output, esp32_ble_server from esphome.const import CONF_ID - AUTO_LOAD = ["esp32_ble_server"] CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["wifi", "esp32"] @@ -50,7 +49,7 @@ async def to_code(config): cg.add(ble_server.register_service_component(var)) cg.add_define("USE_IMPROV") - cg.add_library("esphome/Improv", "1.2.3") + cg.add_library("improv/Improv", "1.2.4") cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) From f737ca6e286f36e243b5bae1bcb7515b9a4bf857 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Mon, 5 Aug 2024 23:17:02 +0200 Subject: [PATCH 2160/2607] hydreon_rgxx: Fix parsing of data line (#7192) --- esphome/components/hydreon_rgxx/hydreon_rgxx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp index 95702fe9e8..92d7774193 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp @@ -236,7 +236,7 @@ void HydreonRGxxComponent::process_line_() { } bool is_data_line = false; for (int i = 0; i < NUM_SENSORS; i++) { - if (this->sensors_[i] != nullptr && this->buffer_starts_with_(PROTOCOL_NAMES[i])) { + if (this->sensors_[i] != nullptr && this->buffer_.find(PROTOCOL_NAMES[i]) != std::string::npos) { is_data_line = true; break; } From acaec41bb765949f37c04cf34b77e0f73df26272 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 6 Aug 2024 01:40:34 +0200 Subject: [PATCH 2161/2607] Remove outdated version block (#7177) --- esphome/__main__.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 7237a04717..5c197ff486 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -972,13 +972,6 @@ def run_esphome(argv): args.command == "dashboard", ) - if sys.version_info < (3, 8, 0): - _LOGGER.error( - "You're running ESPHome with Python <3.8. ESPHome is no longer compatible " - "with this Python version. Please reinstall ESPHome with Python 3.8+" - ) - return 1 - if args.command in PRE_CONFIG_ACTIONS: try: return PRE_CONFIG_ACTIONS[args.command](args) From 6b141102d62930778552db1f2bdf23bdc20b1d86 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:17:29 +1000 Subject: [PATCH 2162/2607] [lvgl] Stage 5 (#7191) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/lvgl/__init__.py | 25 +- esphome/components/lvgl/animimg.py | 2 +- esphome/components/lvgl/automation.py | 2 +- esphome/components/lvgl/{btn.py => button.py} | 8 +- esphome/components/lvgl/buttonmatrix.py | 277 ++++++++++++++++ esphome/components/lvgl/checkbox.py | 2 +- esphome/components/lvgl/defines.py | 2 +- esphome/components/lvgl/dropdown.py | 76 +++++ esphome/components/lvgl/img.py | 8 +- esphome/components/lvgl/keyboard.py | 49 +++ esphome/components/lvgl/led.py | 4 +- esphome/components/lvgl/lvgl_esphome.cpp | 4 +- esphome/components/lvgl/lvgl_esphome.h | 2 +- esphome/components/lvgl/meter.py | 302 ++++++++++++++++++ esphome/components/lvgl/msgbox.py | 127 ++++++++ esphome/components/lvgl/roller.py | 77 +++++ esphome/components/lvgl/spinbox.py | 178 +++++++++++ esphome/components/lvgl/styles.py | 2 +- esphome/components/lvgl/tabview.py | 114 +++++++ esphome/components/lvgl/textarea.py | 67 ++++ esphome/components/lvgl/tileview.py | 128 ++++++++ esphome/components/lvgl/widget.py | 8 +- esphome/core/defines.h | 3 + tests/components/lvgl/.gitattributes | 2 + tests/components/lvgl/common.yaml | 46 +++ tests/components/lvgl/helvetica.ttf | Bin 0 -> 83644 bytes tests/components/lvgl/lvgl-package.yaml | 228 ++++++++++++- .../lvgl/materialdesignicons-webfont.ttf | Bin 0 -> 1307419 bytes tests/components/lvgl/roboto.ttf | Bin 0 -> 171676 bytes 29 files changed, 1716 insertions(+), 27 deletions(-) rename esphome/components/lvgl/{btn.py => button.py} (58%) create mode 100644 esphome/components/lvgl/buttonmatrix.py create mode 100644 esphome/components/lvgl/dropdown.py create mode 100644 esphome/components/lvgl/keyboard.py create mode 100644 esphome/components/lvgl/meter.py create mode 100644 esphome/components/lvgl/msgbox.py create mode 100644 esphome/components/lvgl/roller.py create mode 100644 esphome/components/lvgl/spinbox.py create mode 100644 esphome/components/lvgl/tabview.py create mode 100644 esphome/components/lvgl/textarea.py create mode 100644 esphome/components/lvgl/tileview.py create mode 100644 tests/components/lvgl/.gitattributes create mode 100644 tests/components/lvgl/helvetica.ttf create mode 100644 tests/components/lvgl/materialdesignicons-webfont.ttf create mode 100644 tests/components/lvgl/roboto.ttf diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index c154689199..a963fca98b 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -24,10 +24,13 @@ from . import defines as df, helpers, lv_validation as lvalid from .animimg import animimg_spec from .arc import arc_spec from .automation import disp_update, update_to_code -from .btn import btn_spec +from .button import button_spec +from .buttonmatrix import buttonmatrix_spec from .checkbox import checkbox_spec from .defines import CONF_SKIP +from .dropdown import dropdown_spec from .img import img_spec +from .keyboard import keyboard_spec from .label import label_spec from .led import led_spec from .line import line_spec @@ -35,8 +38,11 @@ from .lv_bar import bar_spec from .lv_switch import switch_spec from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent +from .meter import meter_spec +from .msgbox import MSGBOX_SCHEMA, msgboxes_to_code from .obj import obj_spec from .page import add_pages, page_spec +from .roller import roller_spec from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code from .schemas import ( DISP_BG_SCHEMA, @@ -52,8 +58,12 @@ from .schemas import ( obj_schema, ) from .slider import slider_spec +from .spinbox import spinbox_spec from .spinner import spinner_spec from .styles import add_top_layer, styles_to_code, theme_to_code +from .tabview import tabview_spec +from .textarea import textarea_spec +from .tileview import tileview_spec from .touchscreens import touchscreen_schema, touchscreens_to_code from .trigger import generate_triggers from .types import ( @@ -75,7 +85,7 @@ LOGGER = logging.getLogger(__name__) for w_type in ( label_spec, obj_spec, - btn_spec, + button_spec, bar_spec, slider_spec, arc_spec, @@ -86,6 +96,15 @@ for w_type in ( checkbox_spec, img_spec, switch_spec, + tabview_spec, + buttonmatrix_spec, + meter_spec, + dropdown_spec, + roller_spec, + textarea_spec, + spinbox_spec, + keyboard_spec, + tileview_spec, ): WIDGET_TYPES[w_type.name] = w_type @@ -244,6 +263,7 @@ async def to_code(config): await add_widgets(lv_scr_act, config) await add_pages(lv_component, config) await add_top_layer(config) + await msgboxes_to_code(config) await disp_update(f"{lv_component}->get_disp()", config) Widget.set_completed() await generate_triggers(lv_component) @@ -308,6 +328,7 @@ CONFIG_SCHEMA = ( cv.Exclusive(CONF_PAGES, CONF_PAGES): cv.ensure_list( container_schema(page_spec) ), + cv.Optional(df.CONF_MSGBOXES): cv.ensure_list(MSGBOX_SCHEMA), cv.Optional(df.CONF_PAGE_WRAP, default=True): lv_bool, cv.Optional(df.CONF_TOP_LAYER): container_schema(obj_spec), cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, diff --git a/esphome/components/lvgl/animimg.py b/esphome/components/lvgl/animimg.py index 20b85b019c..ad84713d7f 100644 --- a/esphome/components/lvgl/animimg.py +++ b/esphome/components/lvgl/animimg.py @@ -2,8 +2,8 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_DURATION, CONF_ID +from esphome.cpp_generator import MockObj -from ...cpp_generator import MockObj from .automation import action_to_code from .defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC from .helpers import lvgl_components_required diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index ffa25783ad..7a862fb58b 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -109,7 +109,7 @@ async def disp_update(disp, config: dict): if CONF_DISP_BG_COLOR not in config and CONF_DISP_BG_IMAGE not in config: return with LocalVariable("lv_disp_tmp", lv_disp_t, literal(disp)) as disp_temp: - if bg_color := config.get(CONF_DISP_BG_COLOR): + if (bg_color := config.get(CONF_DISP_BG_COLOR)) is not None: lv.disp_set_bg_color(disp_temp, await lv_color.process(bg_color)) if bg_image := config.get(CONF_DISP_BG_IMAGE): lv.disp_set_bg_image(disp_temp, await lv_image.process(bg_image)) diff --git a/esphome/components/lvgl/btn.py b/esphome/components/lvgl/button.py similarity index 58% rename from esphome/components/lvgl/btn.py rename to esphome/components/lvgl/button.py index 2a2a53e1e2..96329b3fa9 100644 --- a/esphome/components/lvgl/btn.py +++ b/esphome/components/lvgl/button.py @@ -3,12 +3,12 @@ from esphome.const import CONF_BUTTON from .defines import CONF_MAIN from .types import LvBoolean, WidgetType -lv_btn_t = LvBoolean("lv_btn_t") +lv_button_t = LvBoolean("lv_btn_t") -class BtnType(WidgetType): +class ButtonType(WidgetType): def __init__(self): - super().__init__(CONF_BUTTON, lv_btn_t, (CONF_MAIN,), lv_name="btn") + super().__init__(CONF_BUTTON, lv_button_t, (CONF_MAIN,), lv_name="btn") def get_uses(self): return ("btn",) @@ -17,4 +17,4 @@ class BtnType(WidgetType): return [] -btn_spec = BtnType() +button_spec = ButtonType() diff --git a/esphome/components/lvgl/buttonmatrix.py b/esphome/components/lvgl/buttonmatrix.py new file mode 100644 index 0000000000..75ed43f909 --- /dev/null +++ b/esphome/components/lvgl/buttonmatrix.py @@ -0,0 +1,277 @@ +from esphome import automation +import esphome.codegen as cg +from esphome.components.key_provider import KeyProvider +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_WIDTH +from esphome.cpp_generator import MockObj + +from .automation import action_to_code +from .button import lv_button_t +from .defines import ( + BUTTONMATRIX_CTRLS, + CONF_BUTTONS, + CONF_CONTROL, + CONF_ITEMS, + CONF_KEY_CODE, + CONF_MAIN, + CONF_ONE_CHECKED, + CONF_ROWS, + CONF_SELECTED, + CONF_TEXT, +) +from .helpers import lvgl_components_required +from .lv_validation import key_code, lv_bool +from .lvcode import lv, lv_add, lv_expr +from .schemas import automation_schema +from .types import ( + LV_BTNMATRIX_CTRL, + LV_STATE, + LvBoolean, + LvCompound, + LvType, + ObjUpdateAction, + char_ptr, + lv_pseudo_button_t, +) +from .widget import Widget, WidgetType, get_widgets, widget_map + +CONF_BUTTONMATRIX = "buttonmatrix" +CONF_BUTTON_TEXT_LIST_ID = "button_text_list_id" + +LvButtonMatrixButton = LvBoolean( + str(cg.uint16), + parents=(lv_pseudo_button_t,), +) +BUTTONMATRIX_BUTTON_SCHEMA = cv.Schema( + { + cv.Optional(CONF_TEXT): cv.string, + cv.Optional(CONF_KEY_CODE): key_code, + cv.GenerateID(): cv.declare_id(LvButtonMatrixButton), + cv.Optional(CONF_WIDTH, default=1): cv.positive_int, + cv.Optional(CONF_CONTROL): cv.ensure_list( + cv.Schema( + {cv.Optional(k.lower()): cv.boolean for k in BUTTONMATRIX_CTRLS.choices} + ) + ), + } +).extend(automation_schema(lv_button_t)) + +BUTTONMATRIX_SCHEMA = cv.Schema( + { + cv.Optional(CONF_ONE_CHECKED, default=False): lv_bool, + cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr), + cv.Required(CONF_ROWS): cv.ensure_list( + cv.Schema( + { + cv.Required(CONF_BUTTONS): cv.ensure_list( + BUTTONMATRIX_BUTTON_SCHEMA + ), + } + ) + ), + } +) + + +class ButtonmatrixButtonType(WidgetType): + """ + A pseudo-widget for the matrix buttons + """ + + def __init__(self): + super().__init__("btnmatrix_btn", LvButtonMatrixButton, (), {}, {}) + + async def to_code(self, w, config: dict): + return [] + + +btn_btn_spec = ButtonmatrixButtonType() + + +class MatrixButton(Widget): + """ + Describes a button within a button matrix. + """ + + @staticmethod + def create_button(id, parent, config: dict, index): + w = MatrixButton(id, parent, config, index) + widget_map[id] = w + return w + + def __init__(self, id, parent: Widget, config, index): + super().__init__(id, btn_btn_spec, config) + self.parent = parent + self.index = index + self.obj = parent.obj + + def is_selected(self): + return self.parent.var.get_selected() == MockObj(self.var) + + @staticmethod + def map_ctrls(state): + state = str(state).upper().removeprefix("LV_STATE_") + assert state in BUTTONMATRIX_CTRLS.choices + return getattr(LV_BTNMATRIX_CTRL, state) + + def has_state(self, state): + state = self.map_ctrls(state) + return lv_expr.btnmatrix_has_btn_ctrl(self.obj, self.index, state) + + def add_state(self, state): + state = self.map_ctrls(state) + return lv.btnmatrix_set_btn_ctrl(self.obj, self.index, state) + + def clear_state(self, state): + state = self.map_ctrls(state) + return lv.btnmatrix_clear_btn_ctrl(self.obj, self.index, state) + + def is_pressed(self): + return self.is_selected() & self.parent.has_state(LV_STATE.PRESSED) + + def is_checked(self): + return self.has_state(LV_STATE.CHECKED) + + def get_value(self): + return self.is_checked() + + def check_null(self): + return None + + +async def get_button_data(config, buttonmatrix: Widget): + """ + Process a button matrix button list + :param config: The row list + :param buttonmatrix: The parent variable + :return: text array id, control list, width list + """ + text_list = [] + ctrl_list = [] + width_list = [] + key_list = [] + for row in config: + for button_conf in row.get(CONF_BUTTONS) or (): + bid = button_conf[CONF_ID] + index = len(width_list) + MatrixButton.create_button(bid, buttonmatrix, button_conf, index) + cg.new_variable(bid, index) + text_list.append(button_conf.get(CONF_TEXT) or "") + key_list.append(button_conf.get(CONF_KEY_CODE) or 0) + width_list.append(button_conf[CONF_WIDTH]) + ctrl = ["LV_BTNMATRIX_CTRL_CLICK_TRIG"] + for item in button_conf.get(CONF_CONTROL, ()): + ctrl.extend([k for k, v in item.items() if v]) + ctrl_list.append(await BUTTONMATRIX_CTRLS.process(ctrl)) + text_list.append("\n") + text_list = text_list[:-1] + text_list.append(cg.nullptr) + return text_list, ctrl_list, width_list, key_list + + +lv_buttonmatrix_t = LvType( + "LvButtonMatrixType", + parents=(KeyProvider, LvCompound), + largs=[(cg.uint16, "x")], + lvalue=lambda w: w.var.get_selected(), +) + + +class ButtonMatrixType(WidgetType): + def __init__(self): + super().__init__( + CONF_BUTTONMATRIX, + lv_buttonmatrix_t, + (CONF_MAIN, CONF_ITEMS), + BUTTONMATRIX_SCHEMA, + {}, + lv_name="btnmatrix", + ) + + async def to_code(self, w: Widget, config): + lvgl_components_required.add("BUTTONMATRIX") + if CONF_ROWS not in config: + return [] + text_list, ctrl_list, width_list, key_list = await get_button_data( + config[CONF_ROWS], w + ) + text_id = config[CONF_BUTTON_TEXT_LIST_ID] + text_id = cg.static_const_array(text_id, text_list) + lv.btnmatrix_set_map(w.obj, text_id) + set_btn_data(w.obj, ctrl_list, width_list) + lv.btnmatrix_set_one_checked(w.obj, config[CONF_ONE_CHECKED]) + for index, key in enumerate(key_list): + if key != 0: + lv_add(w.var.set_key(index, key)) + + def get_uses(self): + return ("btnmatrix",) + + +def set_btn_data(obj, ctrl_list, width_list): + for index, ctrl in enumerate(ctrl_list): + lv.btnmatrix_set_btn_ctrl(obj, index, ctrl) + for index, width in enumerate(width_list): + lv.btnmatrix_set_btn_width(obj, index, width) + + +buttonmatrix_spec = ButtonMatrixType() + + +@automation.register_action( + "lvgl.matrix.button.update", + ObjUpdateAction, + cv.Schema( + { + cv.Optional(CONF_WIDTH): cv.positive_int, + cv.Optional(CONF_CONTROL): cv.ensure_list( + cv.Schema( + { + cv.Optional(k.lower()): cv.boolean + for k in BUTTONMATRIX_CTRLS.choices + } + ), + ), + cv.Required(CONF_ID): cv.ensure_list( + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(LvButtonMatrixButton), + }, + key=CONF_ID, + ) + ), + cv.Optional(CONF_SELECTED): lv_bool, + } + ), +) +async def button_update_to_code(config, action_id, template_arg, args): + widgets = await get_widgets(config[CONF_ID]) + assert all(isinstance(w, MatrixButton) for w in widgets) + + async def do_button_update(w: MatrixButton): + if (width := config.get(CONF_WIDTH)) is not None: + lv.btnmatrix_set_btn_width(w.obj, w.index, width) + if config.get(CONF_SELECTED): + lv.btnmatrix_set_selected_btn(w.obj, w.index) + if controls := config.get(CONF_CONTROL): + adds = [] + clrs = [] + for item in controls: + adds.extend( + [f"LV_BTNMATRIX_CTRL_{k.upper()}" for k, v in item.items() if v] + ) + clrs.extend( + [f"LV_BTNMATRIX_CTRL_{k.upper()}" for k, v in item.items() if not v] + ) + if adds: + lv.btnmatrix_set_btn_ctrl( + w.obj, w.index, await BUTTONMATRIX_CTRLS.process(adds) + ) + if clrs: + lv.btnmatrix_clear_btn_ctrl( + w.obj, w.index, await BUTTONMATRIX_CTRLS.process(clrs) + ) + + return await action_to_code( + widgets, do_button_update, action_id, template_arg, args + ) diff --git a/esphome/components/lvgl/checkbox.py b/esphome/components/lvgl/checkbox.py index 7418d633cf..be7b029269 100644 --- a/esphome/components/lvgl/checkbox.py +++ b/esphome/components/lvgl/checkbox.py @@ -18,7 +18,7 @@ class CheckboxType(WidgetType): ) async def to_code(self, w: Widget, config): - if value := config.get(CONF_TEXT): + if (value := config.get(CONF_TEXT)) is not None: lv.checkbox_set_text(w.obj, await lv_text.process(value)) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 16ec45ae8a..ac28f9ed5f 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -304,7 +304,7 @@ OBJ_FLAGS = ( ARC_MODES = LvConstant("LV_ARC_MODE_", "NORMAL", "REVERSE", "SYMMETRICAL") BAR_MODES = LvConstant("LV_BAR_MODE_", "NORMAL", "SYMMETRICAL", "RANGE") -BTNMATRIX_CTRLS = LvConstant( +BUTTONMATRIX_CTRLS = LvConstant( "LV_BTNMATRIX_CTRL_", "HIDDEN", "NO_REPEAT", diff --git a/esphome/components/lvgl/dropdown.py b/esphome/components/lvgl/dropdown.py new file mode 100644 index 0000000000..d7bdebaade --- /dev/null +++ b/esphome/components/lvgl/dropdown.py @@ -0,0 +1,76 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_OPTIONS + +from .defines import ( + CONF_DIR, + CONF_INDICATOR, + CONF_MAIN, + CONF_SELECTED_INDEX, + CONF_SYMBOL, + DIRECTIONS, + literal, +) +from .label import CONF_LABEL +from .lv_validation import lv_int, lv_text, option_string +from .lvcode import LocalVariable, lv, lv_expr +from .schemas import part_schema +from .types import LvSelect, LvType, lv_obj_t +from .widget import Widget, WidgetType, set_obj_properties + +CONF_DROPDOWN = "dropdown" +CONF_DROPDOWN_LIST = "dropdown_list" + +lv_dropdown_t = LvSelect("lv_dropdown_t") +lv_dropdown_list_t = LvType("lv_dropdown_list_t") +dropdown_list_spec = WidgetType(CONF_DROPDOWN_LIST, lv_dropdown_list_t, (CONF_MAIN,)) + +DROPDOWN_BASE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_SYMBOL): lv_text, + cv.Optional(CONF_SELECTED_INDEX): cv.templatable(cv.int_), + cv.Optional(CONF_DIR, default="BOTTOM"): DIRECTIONS.one_of, + cv.Optional(CONF_DROPDOWN_LIST): part_schema(dropdown_list_spec), + } +) + +DROPDOWN_SCHEMA = DROPDOWN_BASE_SCHEMA.extend( + { + cv.Required(CONF_OPTIONS): cv.ensure_list(option_string), + } +) + + +class DropdownType(WidgetType): + def __init__(self): + super().__init__( + CONF_DROPDOWN, + lv_dropdown_t, + (CONF_MAIN, CONF_INDICATOR), + DROPDOWN_SCHEMA, + DROPDOWN_BASE_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + if options := config.get(CONF_OPTIONS): + text = cg.safe_exp("\n".join(options)) + lv.dropdown_set_options(w.obj, text) + if symbol := config.get(CONF_SYMBOL): + lv.dropdown_set_symbol(w.obj, await lv_text.process(symbol)) + if (selected := config.get(CONF_SELECTED_INDEX)) is not None: + value = await lv_int.process(selected) + lv.dropdown_set_selected(w.obj, value) + if dirn := config.get(CONF_DIR): + lv.dropdown_set_dir(w.obj, literal(dirn)) + if dlist := config.get(CONF_DROPDOWN_LIST): + with LocalVariable( + "dropdown_list", lv_obj_t, lv_expr.dropdown_get_list(w.obj) + ) as dlist_obj: + dwid = Widget(dlist_obj, dropdown_list_spec, dlist) + await set_obj_properties(dwid, dlist) + + def get_uses(self): + return (CONF_LABEL,) + + +dropdown_spec = DropdownType() diff --git a/esphome/components/lvgl/img.py b/esphome/components/lvgl/img.py index e9682def8c..dd962fcf31 100644 --- a/esphome/components/lvgl/img.py +++ b/esphome/components/lvgl/img.py @@ -65,16 +65,16 @@ class ImgType(WidgetType): async def to_code(self, w: Widget, config): if src := config.get(CONF_SRC): lv.img_set_src(w.obj, await lv_image.process(src)) - if cf_angle := config.get(CONF_ANGLE): + if (cf_angle := config.get(CONF_ANGLE)) is not None: pivot_x = config[CONF_PIVOT_X] pivot_y = config[CONF_PIVOT_Y] lv.img_set_pivot(w.obj, pivot_x, pivot_y) lv.img_set_angle(w.obj, cf_angle) - if img_zoom := config.get(CONF_ZOOM): + if (img_zoom := config.get(CONF_ZOOM)) is not None: lv.img_set_zoom(w.obj, img_zoom) - if offset := config.get(CONF_OFFSET_X): + if (offset := config.get(CONF_OFFSET_X)) is not None: lv.img_set_offset_x(w.obj, offset) - if offset := config.get(CONF_OFFSET_Y): + if (offset := config.get(CONF_OFFSET_Y)) is not None: lv.img_set_offset_y(w.obj, offset) if CONF_ANTIALIAS in config: lv.img_set_antialias(w.obj, config[CONF_ANTIALIAS]) diff --git a/esphome/components/lvgl/keyboard.py b/esphome/components/lvgl/keyboard.py new file mode 100644 index 0000000000..7ce73d2170 --- /dev/null +++ b/esphome/components/lvgl/keyboard.py @@ -0,0 +1,49 @@ +from esphome.components.key_provider import KeyProvider +import esphome.config_validation as cv +from esphome.const import CONF_MODE +from esphome.cpp_types import std_string + +from .defines import CONF_ITEMS, CONF_MAIN, KEYBOARD_MODES, literal +from .helpers import add_lv_use, lvgl_components_required +from .textarea import CONF_TEXTAREA, lv_textarea_t +from .types import LvCompound, LvType +from .widget import Widget, WidgetType, get_widgets + +CONF_KEYBOARD = "keyboard" + +KEYBOARD_SCHEMA = { + cv.Optional(CONF_MODE, default="TEXT_UPPER"): KEYBOARD_MODES.one_of, + cv.Optional(CONF_TEXTAREA): cv.use_id(lv_textarea_t), +} + +lv_keyboard_t = LvType( + "LvKeyboardType", + parents=(KeyProvider, LvCompound), + largs=[(std_string, "text")], + has_on_value=True, + lvalue=lambda w: literal(f"lv_textarea_get_text({w.obj})"), +) + + +class KeyboardType(WidgetType): + def __init__(self): + super().__init__( + CONF_KEYBOARD, + lv_keyboard_t, + (CONF_MAIN, CONF_ITEMS), + KEYBOARD_SCHEMA, + ) + + def get_uses(self): + return CONF_KEYBOARD, CONF_TEXTAREA + + async def to_code(self, w: Widget, config: dict): + lvgl_components_required.add("KEY_LISTENER") + lvgl_components_required.add(CONF_KEYBOARD) + add_lv_use("btnmatrix") + await w.set_property(CONF_MODE, await KEYBOARD_MODES.process(config[CONF_MODE])) + if ta := await get_widgets(config, CONF_TEXTAREA): + await w.set_property(CONF_TEXTAREA, ta[0].obj) + + +keyboard_spec = KeyboardType() diff --git a/esphome/components/lvgl/led.py b/esphome/components/lvgl/led.py index f920758efb..9b6e819278 100644 --- a/esphome/components/lvgl/led.py +++ b/esphome/components/lvgl/led.py @@ -20,9 +20,9 @@ class LedType(WidgetType): super().__init__(CONF_LED, LvType("lv_led_t"), (CONF_MAIN,), LED_SCHEMA) async def to_code(self, w: Widget, config): - if color := config.get(CONF_COLOR): + if (color := config.get(CONF_COLOR)) is not None: lv.led_set_color(w.obj, await lv_color.process(color)) - if brightness := config.get(CONF_BRIGHTNESS): + if (brightness := config.get(CONF_BRIGHTNESS)) is not None: lv.led_set_brightness(w.obj, await lv_brightness.process(brightness)) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 1221682d28..544643d532 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -146,12 +146,12 @@ LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_ #endif // USE_LVGL_ROTARY_ENCODER #ifdef USE_LVGL_BUTTONMATRIX -void LvBtnmatrixType::set_obj(lv_obj_t *lv_obj) { +void LvButtonMatrixType::set_obj(lv_obj_t *lv_obj) { LvCompound::set_obj(lv_obj); lv_obj_add_event_cb( lv_obj, [](lv_event_t *event) { - auto *self = static_cast(event->user_data); + auto *self = static_cast(event->user_data); if (self->key_callback_.size() == 0) return; auto key_idx = lv_btnmatrix_get_selected_btn(self->obj); diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index b92799addd..71e0fd069f 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -246,7 +246,7 @@ class LVEncoderListener : public Parented { }; #endif // USE_LVGL_ROTARY_ENCODER #ifdef USE_LVGL_BUTTONMATRIX -class LvBtnmatrixType : public key_provider::KeyProvider, public LvCompound { +class LvButtonMatrixType : public key_provider::KeyProvider, public LvCompound { public: void set_obj(lv_obj_t *lv_obj) override; uint16_t get_selected() { return lv_btnmatrix_get_selected_btn(this->obj); } diff --git a/esphome/components/lvgl/meter.py b/esphome/components/lvgl/meter.py new file mode 100644 index 0000000000..1a6bef7c57 --- /dev/null +++ b/esphome/components/lvgl/meter.py @@ -0,0 +1,302 @@ +from esphome import automation +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import ( + CONF_COLOR, + CONF_COUNT, + CONF_ID, + CONF_LENGTH, + CONF_LOCAL, + CONF_RANGE_FROM, + CONF_RANGE_TO, + CONF_ROTATION, + CONF_VALUE, + CONF_WIDTH, +) + +from .arc import CONF_ARC +from .automation import action_to_code +from .defines import ( + CONF_END_VALUE, + CONF_MAIN, + CONF_PIVOT_X, + CONF_PIVOT_Y, + CONF_SRC, + CONF_START_VALUE, + CONF_TICKS, +) +from .helpers import add_lv_use +from .img import CONF_IMAGE +from .line import CONF_LINE +from .lv_validation import ( + angle, + get_end_value, + get_start_value, + lv_bool, + lv_color, + lv_float, + lv_image, + requires_component, + size, +) +from .lvcode import LocalVariable, lv, lv_assign, lv_expr +from .obj import obj_spec +from .types import LvType, ObjUpdateAction +from .widget import Widget, WidgetType, get_widgets + +CONF_ANGLE_RANGE = "angle_range" +CONF_COLOR_END = "color_end" +CONF_COLOR_START = "color_start" +CONF_INDICATORS = "indicators" +CONF_LABEL_GAP = "label_gap" +CONF_MAJOR = "major" +CONF_METER = "meter" +CONF_R_MOD = "r_mod" +CONF_SCALES = "scales" +CONF_STRIDE = "stride" +CONF_TICK_STYLE = "tick_style" + +lv_meter_t = LvType("lv_meter_t") +lv_meter_indicator_t = cg.global_ns.struct("lv_meter_indicator_t") +lv_meter_indicator_t_ptr = lv_meter_indicator_t.operator("ptr") + + +def pixels(value): + """A size in one axis in pixels""" + if isinstance(value, str) and value.lower().endswith("px"): + return cv.int_(value[:-2]) + return cv.int_(value) + + +INDICATOR_LINE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_WIDTH, default=4): size, + cv.Optional(CONF_COLOR, default=0): lv_color, + cv.Optional(CONF_R_MOD, default=0): size, + cv.Optional(CONF_VALUE): lv_float, + } +) +INDICATOR_IMG_SCHEMA = cv.Schema( + { + cv.Required(CONF_SRC): lv_image, + cv.Required(CONF_PIVOT_X): pixels, + cv.Required(CONF_PIVOT_Y): pixels, + cv.Optional(CONF_VALUE): lv_float, + } +) +INDICATOR_ARC_SCHEMA = cv.Schema( + { + cv.Optional(CONF_WIDTH, default=4): size, + cv.Optional(CONF_COLOR, default=0): lv_color, + cv.Optional(CONF_R_MOD, default=0): size, + cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float, + cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float, + cv.Optional(CONF_END_VALUE): lv_float, + } +) +INDICATOR_TICKS_SCHEMA = cv.Schema( + { + cv.Optional(CONF_WIDTH, default=4): size, + cv.Optional(CONF_COLOR_START, default=0): lv_color, + cv.Optional(CONF_COLOR_END): lv_color, + cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float, + cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float, + cv.Optional(CONF_END_VALUE): lv_float, + cv.Optional(CONF_LOCAL, default=False): lv_bool, + } +) +INDICATOR_SCHEMA = cv.Schema( + { + cv.Exclusive(CONF_LINE, CONF_INDICATORS): INDICATOR_LINE_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(lv_meter_indicator_t), + } + ), + cv.Exclusive(CONF_IMAGE, CONF_INDICATORS): cv.All( + INDICATOR_IMG_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(lv_meter_indicator_t), + } + ), + requires_component("image"), + ), + cv.Exclusive(CONF_ARC, CONF_INDICATORS): INDICATOR_ARC_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(lv_meter_indicator_t), + } + ), + cv.Exclusive(CONF_TICK_STYLE, CONF_INDICATORS): INDICATOR_TICKS_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(lv_meter_indicator_t), + } + ), + } +) + +SCALE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_TICKS): cv.Schema( + { + cv.Optional(CONF_COUNT, default=12): cv.positive_int, + cv.Optional(CONF_WIDTH, default=2): size, + cv.Optional(CONF_LENGTH, default=10): size, + cv.Optional(CONF_COLOR, default=0x808080): lv_color, + cv.Optional(CONF_MAJOR): cv.Schema( + { + cv.Optional(CONF_STRIDE, default=3): cv.positive_int, + cv.Optional(CONF_WIDTH, default=5): size, + cv.Optional(CONF_LENGTH, default="15%"): size, + cv.Optional(CONF_COLOR, default=0): lv_color, + cv.Optional(CONF_LABEL_GAP, default=4): size, + } + ), + } + ), + cv.Optional(CONF_RANGE_FROM, default=0.0): cv.float_, + cv.Optional(CONF_RANGE_TO, default=100.0): cv.float_, + cv.Optional(CONF_ANGLE_RANGE, default=270): cv.int_range(0, 360), + cv.Optional(CONF_ROTATION): angle, + cv.Optional(CONF_INDICATORS): cv.ensure_list(INDICATOR_SCHEMA), + } +) + +METER_SCHEMA = {cv.Optional(CONF_SCALES): cv.ensure_list(SCALE_SCHEMA)} + + +class MeterType(WidgetType): + def __init__(self): + super().__init__(CONF_METER, lv_meter_t, (CONF_MAIN,), METER_SCHEMA) + + async def to_code(self, w: Widget, config): + """For a meter object, create and set parameters""" + + var = w.obj + for scale_conf in config.get(CONF_SCALES) or (): + rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2 + if CONF_ROTATION in scale_conf: + rotation = scale_conf[CONF_ROTATION] // 10 + with LocalVariable( + "meter_var", "lv_meter_scale_t", lv_expr.meter_add_scale(var) + ) as meter_var: + lv.meter_set_scale_range( + var, + meter_var, + scale_conf[CONF_RANGE_FROM], + scale_conf[CONF_RANGE_TO], + scale_conf[CONF_ANGLE_RANGE], + rotation, + ) + if ticks := scale_conf.get(CONF_TICKS): + color = await lv_color.process(ticks[CONF_COLOR]) + lv.meter_set_scale_ticks( + var, + meter_var, + ticks[CONF_COUNT], + ticks[CONF_WIDTH], + ticks[CONF_LENGTH], + color, + ) + if CONF_MAJOR in ticks: + major = ticks[CONF_MAJOR] + color = await lv_color.process(major[CONF_COLOR]) + lv.meter_set_scale_major_ticks( + var, + meter_var, + major[CONF_STRIDE], + major[CONF_WIDTH], + major[CONF_LENGTH], + color, + major[CONF_LABEL_GAP], + ) + for indicator in scale_conf.get(CONF_INDICATORS) or (): + (t, v) = next(iter(indicator.items())) + iid = v[CONF_ID] + ivar = cg.new_variable( + iid, cg.nullptr, type_=lv_meter_indicator_t_ptr + ) + # Enable getting the meter to which this belongs. + wid = Widget.create(iid, var, obj_spec, v) + wid.obj = ivar + if t == CONF_LINE: + color = await lv_color.process(v[CONF_COLOR]) + lv_assign( + ivar, + lv_expr.meter_add_needle_line( + var, meter_var, v[CONF_WIDTH], color, v[CONF_R_MOD] + ), + ) + if t == CONF_ARC: + color = await lv_color.process(v[CONF_COLOR]) + lv_assign( + ivar, + lv_expr.meter_add_arc( + var, meter_var, v[CONF_WIDTH], color, v[CONF_R_MOD] + ), + ) + if t == CONF_TICK_STYLE: + color_start = await lv_color.process(v[CONF_COLOR_START]) + color_end = await lv_color.process( + v.get(CONF_COLOR_END) or color_start + ) + lv_assign( + ivar, + lv_expr.meter_add_scale_lines( + var, + meter_var, + color_start, + color_end, + v[CONF_LOCAL], + v[CONF_WIDTH], + ), + ) + if t == CONF_IMAGE: + add_lv_use("img") + lv_assign( + ivar, + lv_expr.meter_add_needle_img( + var, + meter_var, + await lv_image.process(v[CONF_SRC]), + v[CONF_PIVOT_X], + v[CONF_PIVOT_Y], + ), + ) + start_value = await get_start_value(v) + end_value = await get_end_value(v) + set_indicator_values(var, ivar, start_value, end_value) + + +meter_spec = MeterType() + + +@automation.register_action( + "lvgl.indicator.update", + ObjUpdateAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(lv_meter_indicator_t), + cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float, + cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float, + cv.Optional(CONF_END_VALUE): lv_float, + } + ), +) +async def indicator_update_to_code(config, action_id, template_arg, args): + widget = await get_widgets(config) + start_value = await get_start_value(config) + end_value = await get_end_value(config) + + async def set_value(w: Widget): + set_indicator_values(w.var, w.obj, start_value, end_value) + + return await action_to_code(widget, set_value, action_id, template_arg, args) + + +def set_indicator_values(meter, indicator, start_value, end_value): + if start_value is not None: + if end_value is None: + lv.meter_set_indicator_value(meter, indicator, start_value) + else: + lv.meter_set_indicator_start_value(meter, indicator, start_value) + if end_value is not None: + lv.meter_set_indicator_end_value(meter, indicator, end_value) diff --git a/esphome/components/lvgl/msgbox.py b/esphome/components/lvgl/msgbox.py new file mode 100644 index 0000000000..6dd529d77f --- /dev/null +++ b/esphome/components/lvgl/msgbox.py @@ -0,0 +1,127 @@ +from esphome import config_validation as cv +from esphome.const import CONF_BUTTON, CONF_ID +from esphome.core import ID +from esphome.cpp_generator import new_Pvariable, static_const_array +from esphome.cpp_types import nullptr + +from .button import button_spec +from .buttonmatrix import ( + BUTTONMATRIX_BUTTON_SCHEMA, + CONF_BUTTON_TEXT_LIST_ID, + buttonmatrix_spec, + get_button_data, + lv_buttonmatrix_t, + set_btn_data, +) +from .defines import ( + CONF_BODY, + CONF_BUTTONS, + CONF_CLOSE_BUTTON, + CONF_MSGBOXES, + CONF_TEXT, + CONF_TITLE, + TYPE_FLEX, + literal, +) +from .helpers import add_lv_use +from .label import CONF_LABEL +from .lv_validation import lv_bool, lv_pct, lv_text +from .lvcode import ( + EVENT_ARG, + LambdaContext, + LocalVariable, + lv_add, + lv_assign, + lv_expr, + lv_obj, + lv_Pvariable, +) +from .obj import obj_spec +from .schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema +from .styles import TOP_LAYER +from .types import LV_EVENT, char_ptr, lv_obj_t +from .widget import Widget, set_obj_properties + +CONF_MSGBOX = "msgbox" +MSGBOX_SCHEMA = container_schema( + obj_spec, + STYLE_SCHEMA.extend( + { + cv.GenerateID(CONF_ID): cv.declare_id(lv_obj_t), + cv.Required(CONF_TITLE): STYLED_TEXT_SCHEMA, + cv.Optional(CONF_BODY): STYLED_TEXT_SCHEMA, + cv.Optional(CONF_BUTTONS): cv.ensure_list(BUTTONMATRIX_BUTTON_SCHEMA), + cv.Optional(CONF_CLOSE_BUTTON): lv_bool, + cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr), + } + ), +) + + +async def msgbox_to_code(conf): + """ + Construct a message box. This consists of a full-screen translucent background enclosing a centered container + with an optional title, body, close button and a button matrix. And any other widgets the user cares to add + :param conf: The config data + :return: code to add to the init lambda + """ + add_lv_use( + TYPE_FLEX, + CONF_BUTTON, + CONF_LABEL, + CONF_MSGBOX, + *buttonmatrix_spec.get_uses(), + *button_spec.get_uses(), + ) + mbid = conf[CONF_ID] + outer = lv_Pvariable(lv_obj_t, mbid.id) + btnm = new_Pvariable( + ID(f"{mbid.id}_btnm_", is_declaration=True, type=lv_buttonmatrix_t) + ) + msgbox = lv_Pvariable(lv_obj_t, f"{mbid.id}_msgbox") + outer_w = Widget.create(mbid, outer, obj_spec, conf) + btnm_widg = Widget.create(str(btnm), btnm, buttonmatrix_spec, conf) + text_list, ctrl_list, width_list, _ = await get_button_data((conf,), btnm_widg) + text_id = conf[CONF_BUTTON_TEXT_LIST_ID] + text_list = static_const_array(text_id, text_list) + if (text := conf.get(CONF_BODY)) is not None: + text = await lv_text.process(text.get(CONF_TEXT)) + if (title := conf.get(CONF_TITLE)) is not None: + title = await lv_text.process(title.get(CONF_TEXT)) + close_button = conf[CONF_CLOSE_BUTTON] + lv_assign(outer, lv_expr.obj_create(TOP_LAYER)) + lv_obj.set_width(outer, lv_pct(100)) + lv_obj.set_height(outer, lv_pct(100)) + lv_obj.set_style_bg_opa(outer, 128, 0) + lv_obj.set_style_bg_color(outer, literal("lv_color_black()"), 0) + lv_obj.set_style_border_width(outer, 0, 0) + lv_obj.set_style_pad_all(outer, 0, 0) + lv_obj.set_style_radius(outer, 0, 0) + outer_w.add_flag("LV_OBJ_FLAG_HIDDEN") + lv_assign( + msgbox, lv_expr.msgbox_create(outer, title, text, text_list, close_button) + ) + lv_obj.set_style_align(msgbox, literal("LV_ALIGN_CENTER"), 0) + lv_add(btnm.set_obj(lv_expr.msgbox_get_btns(msgbox))) + await set_obj_properties(outer_w, conf) + if close_button: + async with LambdaContext(EVENT_ARG, where=mbid) as context: + outer_w.add_flag("LV_OBJ_FLAG_HIDDEN") + with LocalVariable( + "close_btn_", lv_obj_t, lv_expr.msgbox_get_close_btn(msgbox) + ) as close_btn: + lv_obj.remove_event_cb(close_btn, nullptr) + lv_obj.add_event_cb( + close_btn, + await context.get_lambda(), + LV_EVENT.CLICKED, + nullptr, + ) + + if len(ctrl_list) != 0 or len(width_list) != 0: + set_btn_data(btnm.obj, ctrl_list, width_list) + + +async def msgboxes_to_code(config): + for conf in config.get(CONF_MSGBOXES, ()): + await msgbox_to_code(conf) diff --git a/esphome/components/lvgl/roller.py b/esphome/components/lvgl/roller.py new file mode 100644 index 0000000000..7af3ef3c3d --- /dev/null +++ b/esphome/components/lvgl/roller.py @@ -0,0 +1,77 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_MODE, CONF_OPTIONS + +from .defines import ( + CONF_ANIMATED, + CONF_MAIN, + CONF_SELECTED, + CONF_SELECTED_INDEX, + CONF_VISIBLE_ROW_COUNT, + ROLLER_MODES, + literal, +) +from .label import CONF_LABEL +from .lv_validation import animated, lv_int, option_string +from .lvcode import lv +from .types import LvSelect +from .widget import WidgetType + +CONF_ROLLER = "roller" +lv_roller_t = LvSelect("lv_roller_t") + +ROLLER_BASE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_SELECTED_INDEX): cv.templatable(cv.int_), + cv.Optional(CONF_VISIBLE_ROW_COUNT): lv_int, + } +) + +ROLLER_SCHEMA = ROLLER_BASE_SCHEMA.extend( + { + cv.Required(CONF_OPTIONS): cv.ensure_list(option_string), + cv.Optional(CONF_MODE, default="NORMAL"): ROLLER_MODES.one_of, + } +) + +ROLLER_MODIFY_SCHEMA = ROLLER_BASE_SCHEMA.extend( + { + cv.Optional(CONF_ANIMATED, default=True): animated, + } +) + + +class RollerType(WidgetType): + def __init__(self): + super().__init__( + CONF_ROLLER, + lv_roller_t, + (CONF_MAIN, CONF_SELECTED), + ROLLER_SCHEMA, + ROLLER_MODIFY_SCHEMA, + ) + + async def to_code(self, w, config): + if options := config.get(CONF_OPTIONS): + mode = await ROLLER_MODES.process(config[CONF_MODE]) + text = cg.safe_exp("\n".join(options)) + lv.roller_set_options(w.obj, text, mode) + animopt = literal(config.get(CONF_ANIMATED) or "LV_ANIM_OFF") + if CONF_SELECTED_INDEX in config: + if selected := config[CONF_SELECTED_INDEX]: + value = await lv_int.process(selected) + lv.roller_set_selected(w.obj, value, animopt) + await w.set_property( + CONF_VISIBLE_ROW_COUNT, + await lv_int.process(config.get(CONF_VISIBLE_ROW_COUNT)), + ) + + @property + def animated(self): + return True + + def get_uses(self): + return (CONF_LABEL,) + + +roller_spec = RollerType() diff --git a/esphome/components/lvgl/spinbox.py b/esphome/components/lvgl/spinbox.py new file mode 100644 index 0000000000..62c58c54a3 --- /dev/null +++ b/esphome/components/lvgl/spinbox.py @@ -0,0 +1,178 @@ +from esphome import automation +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_RANGE_FROM, CONF_RANGE_TO, CONF_STEP, CONF_VALUE + +from .automation import action_to_code, update_to_code +from .defines import ( + CONF_CURSOR, + CONF_DECIMAL_PLACES, + CONF_DIGITS, + CONF_MAIN, + CONF_ROLLOVER, + CONF_SCROLLBAR, + CONF_SELECTED, + CONF_TEXTAREA_PLACEHOLDER, +) +from .label import CONF_LABEL +from .lv_validation import lv_bool, lv_float +from .lvcode import lv +from .textarea import CONF_TEXTAREA +from .types import LvNumber, ObjUpdateAction +from .widget import Widget, WidgetType, get_widgets + +CONF_SPINBOX = "spinbox" + +lv_spinbox_t = LvNumber("lv_spinbox_t") + +SPIN_ACTIONS = ( + "INCREMENT", + "DECREMENT", + "STEP_NEXT", + "STEP_PREV", + "CLEAR", +) + + +def validate_spinbox(config): + max_val = 2**31 - 1 + min_val = -1 - max_val + range_from = int(config[CONF_RANGE_FROM]) + range_to = int(config[CONF_RANGE_TO]) + step = int(config[CONF_STEP]) + if ( + range_from > max_val + or range_from < min_val + or range_to > max_val + or range_to < min_val + ): + raise cv.Invalid("Range outside allowed limits") + if step <= 0 or step >= (range_to - range_from) / 2: + raise cv.Invalid("Invalid step value") + if config[CONF_DIGITS] <= config[CONF_DECIMAL_PLACES]: + raise cv.Invalid("Number of digits must exceed number of decimal places") + return config + + +SPINBOX_SCHEMA = cv.Schema( + { + cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_RANGE_FROM, default=0): cv.float_, + cv.Optional(CONF_RANGE_TO, default=100): cv.float_, + cv.Optional(CONF_DIGITS, default=4): cv.int_range(1, 10), + cv.Optional(CONF_STEP, default=1.0): cv.positive_float, + cv.Optional(CONF_DECIMAL_PLACES, default=0): cv.int_range(0, 6), + cv.Optional(CONF_ROLLOVER, default=False): lv_bool, + } +).add_extra(validate_spinbox) + + +SPINBOX_MODIFY_SCHEMA = { + cv.Required(CONF_VALUE): lv_float, +} + + +class SpinboxType(WidgetType): + def __init__(self): + super().__init__( + CONF_SPINBOX, + lv_spinbox_t, + ( + CONF_MAIN, + CONF_SCROLLBAR, + CONF_SELECTED, + CONF_CURSOR, + CONF_TEXTAREA_PLACEHOLDER, + ), + SPINBOX_SCHEMA, + SPINBOX_MODIFY_SCHEMA, + ) + + async def to_code(self, w: Widget, config): + if CONF_DIGITS in config: + digits = config[CONF_DIGITS] + scale = 10 ** config[CONF_DECIMAL_PLACES] + range_from = int(config[CONF_RANGE_FROM]) * scale + range_to = int(config[CONF_RANGE_TO]) * scale + step = int(config[CONF_STEP]) * scale + w.scale = scale + w.step = step + w.range_to = range_to + w.range_from = range_from + lv.spinbox_set_range(w.obj, range_from, range_to) + await w.set_property(CONF_STEP, step) + await w.set_property(CONF_ROLLOVER, config) + lv.spinbox_set_digit_format( + w.obj, digits, digits - config[CONF_DECIMAL_PLACES] + ) + if (value := config.get(CONF_VALUE)) is not None: + lv.spinbox_set_value(w.obj, await lv_float.process(value)) + + def get_scale(self, config): + return 10 ** config[CONF_DECIMAL_PLACES] + + def get_uses(self): + return CONF_TEXTAREA, CONF_LABEL + + def get_max(self, config: dict): + return config[CONF_RANGE_TO] + + def get_min(self, config: dict): + return config[CONF_RANGE_FROM] + + def get_step(self, config: dict): + return config[CONF_STEP] + + +spinbox_spec = SpinboxType() + + +@automation.register_action( + "lvgl.spinbox.increment", + ObjUpdateAction, + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(lv_spinbox_t), + }, + key=CONF_ID, + ), +) +async def spinbox_increment(config, action_id, template_arg, args): + widgets = await get_widgets(config) + + async def do_increment(w: Widget): + lv.spinbox_increment(w.obj) + + return await action_to_code(widgets, do_increment, action_id, template_arg, args) + + +@automation.register_action( + "lvgl.spinbox.decrement", + ObjUpdateAction, + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(lv_spinbox_t), + }, + key=CONF_ID, + ), +) +async def spinbox_decrement(config, action_id, template_arg, args): + widgets = await get_widgets(config) + + async def do_increment(w: Widget): + lv.spinbox_decrement(w.obj) + + return await action_to_code(widgets, do_increment, action_id, template_arg, args) + + +@automation.register_action( + "lvgl.spinbox.update", + ObjUpdateAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(lv_spinbox_t), + cv.Required(CONF_VALUE): lv_float, + } + ), +) +async def spinbox_update_to_code(config, action_id, template_arg, args): + return await update_to_code(config, action_id, template_arg, args) diff --git a/esphome/components/lvgl/styles.py b/esphome/components/lvgl/styles.py index 7a795bc99d..09f1c376d0 100644 --- a/esphome/components/lvgl/styles.py +++ b/esphome/components/lvgl/styles.py @@ -26,7 +26,7 @@ async def styles_to_code(config): svar = cg.new_Pvariable(style[CONF_ID]) lv.style_init(svar) for prop, validator in ALL_STYLES.items(): - if value := style.get(prop): + if (value := style.get(prop)) is not None: if isinstance(validator, LValidator): value = await validator.process(value) if isinstance(value, list): diff --git a/esphome/components/lvgl/tabview.py b/esphome/components/lvgl/tabview.py new file mode 100644 index 0000000000..7b6a864e21 --- /dev/null +++ b/esphome/components/lvgl/tabview.py @@ -0,0 +1,114 @@ +from esphome import automation +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_INDEX, CONF_NAME, CONF_POSITION, CONF_SIZE +from esphome.cpp_generator import MockObjClass + +from . import buttonmatrix_spec +from .automation import action_to_code +from .defines import ( + CONF_ANIMATED, + CONF_MAIN, + CONF_TAB_ID, + CONF_TABS, + DIRECTIONS, + TYPE_FLEX, + literal, +) +from .lv_validation import animated, lv_int, size +from .lvcode import LocalVariable, lv, lv_assign, lv_expr +from .obj import obj_spec +from .schemas import container_schema, part_schema +from .types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr +from .widget import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties + +CONF_TABVIEW = "tabview" +CONF_TAB_STYLE = "tab_style" + +lv_tab_t = LvType("lv_obj_t") + +TABVIEW_SCHEMA = cv.Schema( + { + cv.Required(CONF_TABS): cv.ensure_list( + container_schema( + obj_spec, + { + cv.Required(CONF_NAME): cv.string, + cv.GenerateID(): cv.declare_id(lv_tab_t), + }, + ) + ), + cv.Optional(CONF_TAB_STYLE): part_schema(buttonmatrix_spec), + cv.Optional(CONF_POSITION, default="top"): DIRECTIONS.one_of, + cv.Optional(CONF_SIZE, default="10%"): size, + } +) + + +class TabviewType(WidgetType): + def __init__(self): + super().__init__( + CONF_TABVIEW, + LvType( + "lv_tabview_t", + largs=[(lv_obj_t_ptr, "tab")], + lvalue=lambda w: lv_expr.obj_get_child( + lv_expr.tabview_get_content(w.obj), + lv_expr.tabview_get_tab_act(w.obj), + ), + has_on_value=True, + ), + parts=(CONF_MAIN,), + schema=TABVIEW_SCHEMA, + modify_schema={}, + ) + + def get_uses(self): + return "btnmatrix", TYPE_FLEX + + async def to_code(self, w: Widget, config: dict): + for tab_conf in config[CONF_TABS]: + w_id = tab_conf[CONF_ID] + tab_obj = cg.Pvariable(w_id, cg.nullptr, type_=lv_tab_t) + tab_widget = Widget.create(w_id, tab_obj, obj_spec) + lv_assign(tab_obj, lv_expr.tabview_add_tab(w.obj, tab_conf[CONF_NAME])) + await set_obj_properties(tab_widget, tab_conf) + await add_widgets(tab_widget, tab_conf) + if button_style := config.get(CONF_TAB_STYLE): + with LocalVariable( + "tabview_btnmatrix", lv_obj_t, rhs=lv_expr.tabview_get_tab_btns(w.obj) + ) as btnmatrix_obj: + await set_obj_properties(Widget(btnmatrix_obj, obj_spec), button_style) + + def obj_creator(self, parent: MockObjClass, config: dict): + return lv_expr.call( + "tabview_create", + parent, + literal(config[CONF_POSITION]), + literal(config[CONF_SIZE]), + ) + + +tabview_spec = TabviewType() + + +@automation.register_action( + "lvgl.tabview.select", + ObjUpdateAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(tabview_spec.w_type), + cv.Optional(CONF_ANIMATED, default=False): animated, + cv.Required(CONF_INDEX): lv_int, + }, + ).add_extra(cv.has_at_least_one_key(CONF_INDEX, CONF_TAB_ID)), +) +async def tabview_select(config, action_id, template_arg, args): + widget = await get_widgets(config) + index = config[CONF_INDEX] + + async def do_select(w: Widget): + lv.tabview_set_act(w.obj, index, literal(config[CONF_ANIMATED])) + lv.event_send(w.obj, LV_EVENT.VALUE_CHANGED, cg.nullptr) + + return await action_to_code(widget, do_select, action_id, template_arg, args) diff --git a/esphome/components/lvgl/textarea.py b/esphome/components/lvgl/textarea.py new file mode 100644 index 0000000000..d383e1f098 --- /dev/null +++ b/esphome/components/lvgl/textarea.py @@ -0,0 +1,67 @@ +import esphome.config_validation as cv +from esphome.const import CONF_MAX_LENGTH + +from .defines import ( + CONF_ACCEPTED_CHARS, + CONF_CURSOR, + CONF_MAIN, + CONF_ONE_LINE, + CONF_PASSWORD_MODE, + CONF_PLACEHOLDER_TEXT, + CONF_SCROLLBAR, + CONF_SELECTED, + CONF_TEXT, + CONF_TEXTAREA_PLACEHOLDER, +) +from .lv_validation import lv_bool, lv_int, lv_text +from .schemas import TEXT_SCHEMA +from .types import LvText +from .widget import Widget, WidgetType + +CONF_TEXTAREA = "textarea" + +lv_textarea_t = LvText("lv_textarea_t") + +TEXTAREA_SCHEMA = TEXT_SCHEMA.extend( + { + cv.Optional(CONF_PLACEHOLDER_TEXT): lv_text, + cv.Optional(CONF_ACCEPTED_CHARS): lv_text, + cv.Optional(CONF_ONE_LINE): lv_bool, + cv.Optional(CONF_PASSWORD_MODE): lv_bool, + cv.Optional(CONF_MAX_LENGTH): lv_int, + } +) + + +class TextareaType(WidgetType): + def __init__(self): + super().__init__( + CONF_TEXTAREA, + lv_textarea_t, + ( + CONF_MAIN, + CONF_SCROLLBAR, + CONF_SELECTED, + CONF_CURSOR, + CONF_TEXTAREA_PLACEHOLDER, + ), + TEXTAREA_SCHEMA, + ) + + async def to_code(self, w: Widget, config: dict): + for prop in (CONF_TEXT, CONF_PLACEHOLDER_TEXT, CONF_ACCEPTED_CHARS): + if (value := config.get(prop)) is not None: + await w.set_property(prop, await lv_text.process(value)) + await w.set_property( + CONF_MAX_LENGTH, await lv_int.process(config.get(CONF_MAX_LENGTH)) + ) + await w.set_property( + CONF_PASSWORD_MODE, + await lv_bool.process(config.get(CONF_PASSWORD_MODE)), + ) + await w.set_property( + CONF_ONE_LINE, await lv_bool.process(config.get(CONF_ONE_LINE)) + ) + + +textarea_spec = TextareaType() diff --git a/esphome/components/lvgl/tileview.py b/esphome/components/lvgl/tileview.py new file mode 100644 index 0000000000..aa841fa23e --- /dev/null +++ b/esphome/components/lvgl/tileview.py @@ -0,0 +1,128 @@ +from esphome import automation +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_ON_VALUE, CONF_ROW, CONF_TRIGGER_ID + +from .automation import action_to_code +from .defines import ( + CONF_ANIMATED, + CONF_COLUMN, + CONF_DIR, + CONF_MAIN, + CONF_TILE_ID, + CONF_TILES, + TILE_DIRECTIONS, + literal, +) +from .lv_validation import animated, lv_int +from .lvcode import lv, lv_assign, lv_expr, lv_obj, lv_Pvariable +from .obj import obj_spec +from .schemas import container_schema +from .types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr +from .widget import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties + +CONF_TILEVIEW = "tileview" + +lv_tile_t = LvType("lv_tileview_tile_t") + +lv_tileview_t = LvType( + "lv_tileview_t", + largs=[(lv_obj_t_ptr, "tile")], + lvalue=lambda w: w.get_property("tile_act"), +) + +tile_spec = WidgetType("lv_tileview_tile_t", lv_tile_t, (CONF_MAIN,), {}) + +TILEVIEW_SCHEMA = cv.Schema( + { + cv.Required(CONF_TILES): cv.ensure_list( + container_schema( + obj_spec, + { + cv.Required(CONF_ROW): lv_int, + cv.Required(CONF_COLUMN): lv_int, + cv.GenerateID(): cv.declare_id(lv_tile_t), + cv.Optional(CONF_DIR, default="ALL"): TILE_DIRECTIONS.several_of, + }, + ) + ), + cv.Optional(CONF_ON_VALUE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + automation.Trigger.template(lv_obj_t_ptr) + ) + } + ), + } +) + + +class TileviewType(WidgetType): + def __init__(self): + super().__init__( + CONF_TILEVIEW, + lv_tileview_t, + (CONF_MAIN,), + schema=TILEVIEW_SCHEMA, + modify_schema={}, + ) + + async def to_code(self, w: Widget, config: dict): + for tile_conf in config.get(CONF_TILES) or (): + w_id = tile_conf[CONF_ID] + tile_obj = lv_Pvariable(lv_obj_t, w_id) + tile = Widget.create(w_id, tile_obj, tile_spec, tile_conf) + dirs = tile_conf[CONF_DIR] + if isinstance(dirs, list): + dirs = "|".join(dirs) + lv_assign( + tile_obj, + lv_expr.tileview_add_tile( + w.obj, tile_conf[CONF_COLUMN], tile_conf[CONF_ROW], literal(dirs) + ), + ) + await set_obj_properties(tile, tile_conf) + await add_widgets(tile, tile_conf) + + +tileview_spec = TileviewType() + + +def tile_select_validate(config): + row = CONF_ROW in config + column = CONF_COLUMN in config + tile = CONF_TILE_ID in config + if tile and (row or column) or not tile and not (row and column): + raise cv.Invalid("Specify either a tile id, or both a row and a column") + return config + + +@automation.register_action( + "lvgl.tileview.select", + ObjUpdateAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(lv_tileview_t), + cv.Optional(CONF_ANIMATED, default=False): animated, + cv.Optional(CONF_ROW): lv_int, + cv.Optional(CONF_COLUMN): lv_int, + cv.Optional(CONF_TILE_ID): cv.use_id(lv_tile_t), + }, + ).add_extra(tile_select_validate), +) +async def tileview_select(config, action_id, template_arg, args): + widgets = await get_widgets(config) + + async def do_select(w: Widget): + if tile := config.get(CONF_TILE_ID): + tile = await cg.get_variable(tile) + lv_obj.set_tile(w.obj, tile, literal(config[CONF_ANIMATED])) + else: + row = await lv_int.process(config[CONF_ROW]) + column = await lv_int.process(config[CONF_COLUMN]) + lv_obj.set_tile_id( + widgets[0].obj, column, row, literal(config[CONF_ANIMATED]) + ) + lv.event_send(w.obj, LV_EVENT.VALUE_CHANGED, cg.nullptr) + + return await action_to_code(widgets, do_select, action_id, template_arg, args) diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widget.py index 5734aec7dc..fcaee29085 100644 --- a/esphome/components/lvgl/widget.py +++ b/esphome/components/lvgl/widget.py @@ -282,13 +282,13 @@ async def set_obj_properties(w: Widget, config): lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}")) if layout_type == TYPE_GRID: wid = config[CONF_ID] - rows = "{" + ",".join(layout[CONF_GRID_ROWS]) + ", LV_GRID_TEMPLATE_LAST}" + rows = [str(x) for x in layout[CONF_GRID_ROWS]] + rows = "{" + ",".join(rows) + ", LV_GRID_TEMPLATE_LAST}" row_id = ID(f"{wid}_row_dsc", is_declaration=True, type=lv_coord_t) row_array = cg.static_const_array(row_id, cg.RawExpression(rows)) w.set_style("grid_row_dsc_array", row_array, 0) - columns = ( - "{" + ",".join(layout[CONF_GRID_COLUMNS]) + ", LV_GRID_TEMPLATE_LAST}" - ) + columns = [str(x) for x in layout[CONF_GRID_COLUMNS]] + columns = "{" + ",".join(columns) + ", LV_GRID_TEMPLATE_LAST}" column_id = ID(f"{wid}_column_dsc", is_declaration=True, type=lv_coord_t) column_array = cg.static_const_array(column_id, cg.RawExpression(columns)) w.set_style("grid_column_dsc_array", column_array, 0) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 726db24592..b7bdbb1f9d 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -39,9 +39,12 @@ #define USE_LOCK #define USE_LOGGER #define USE_LVGL +#define USE_LVGL_ANIMIMG #define USE_LVGL_BINARY_SENSOR +#define USE_LVGL_BUTTONMATRIX #define USE_LVGL_FONT #define USE_LVGL_IMAGE +#define USE_LVGL_KEYBOARD #define USE_LVGL_KEY_LISTENER #define USE_LVGL_TOUCHSCREEN #define USE_LVGL_ROTARY_ENCODER diff --git a/tests/components/lvgl/.gitattributes b/tests/components/lvgl/.gitattributes new file mode 100644 index 0000000000..75e7a44254 --- /dev/null +++ b/tests/components/lvgl/.gitattributes @@ -0,0 +1,2 @@ +*.ttf -text + diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 8b92f8caa7..6d0c1967b4 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -8,3 +8,49 @@ touchscreen: x_max: 240 y_max: 320 +font: + - file: "$component_dir/roboto.ttf" + id: roboto20 + size: 20 + extras: + - file: '$component_dir/materialdesignicons-webfont.ttf' + glyphs: [ + "\U000F004B", + "\U0000f0ed", + "\U000F006E", + "\U000F012C", + "\U000F179B", + "\U000F0748", + "\U000F1A1B", + "\U000F02DC", + "\U000F0A02", + "\U000F035F", + "\U000F0156", + "\U000F0C5F", + "\U000f0084", + "\U000f0091", + ] + - file: "$component_dir/helvetica.ttf" + id: helvetica20 + - file: "$component_dir/roboto.ttf" + id: roboto10 + size: 10 + bpp: 4 + extras: + - file: '$component_dir/materialdesignicons-webfont.ttf' + glyphs: [ + "\U000F004B", + "\U0000f0ed", + "\U000F006E", + "\U000F012C", + "\U000F179B", + "\U000F0748", + "\U000F1A1B", + "\U000F02DC", + "\U000F0A02", + "\U000F035F", + "\U000F0156", + "\U000F0C5F", + "\U000f0084", + "\U000f0091", + ] diff --git a/tests/components/lvgl/helvetica.ttf b/tests/components/lvgl/helvetica.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7aec6f3f3cc74a7138ce350def27a2209b44ad89 GIT binary patch literal 83644 zcmd?S2Y4LSy*_--%=S9lyR@rSv9z}3wJcl0vbDA(<3cgUCXxb)gk`V+n_|4l3Yj}864tp4Kc*DPz-_8EACAp&9+A0d(P~xMoF$YH;vl_5BwZ(;T03>_4_4lSGs9R&7vjZ%kcq{@Qh;)5%$=?q#g} zf{RvM(D>reVjMq!`XvYzZ>Dz;J#pwC)YsuHBHE|;7CB3BoAiR!pc4c^6m+aQk!c#19JkpR1?PI^$aU2FmZwUjrJp5%RgvsGCekmrlQfkohalyJW?>Rm;2cmyF_% zBuCYiE6%%UT0Oy+@jrnu`V-;>{jn#M5QAW0Cvc#ZumkOn5+T1=_$-th`KjG0;5&7A zTLUo?6EPDDu@W1xqqUtxA}-=49z54a{3JkvBt*g_LZT!_N=PY*lLRRvNm5QKNF}Kv z6G%0wAt^GEOd^v>Etx{nWGbm6(?~s;PG*n>(nyXYGf5MfMP`#`yxtr#m$Z;p5M~}Z zp3El;$U?G+oIp+_Cy|rMVsZ*uLQW-1$ue>p`37kx9i)?dlblY@Am1Y2CS7=?d&&Le zLGmzpk~~9RB7>x#Y$ZP++sO{Hle|h^A-l+r$!_u!@>B9U*+bqWZ;+pnx5!@d4%tWE zCGXLtDBZax{RJp7t>Q|JGqlQLT)FIl84A9@;&l6d5kUF0>gpL|L_ zBflh{lP}1x$-k3PN+_iQ6{(IIsf{|Qhx%y*H7=t`nxa!^n$DoJ@r)Buzi-lR{`Tk6 zwW#x5!cT;s3LlF@ac?{vFNv4ME8|n*$HiOY>*CKR$`X}jLYbk=S>`VDm4(Yn%2H+X z%eu-|RJ{J5|M-J&Pymk;@XjW**o(ZTJI2-Y$7rjun*NIXh76CZsU9`8QzvQ~0CibS zYv^RubUJNB3!H$OoyGLIeeP#3|^(ysB zb@j-G&l*3Q{#pHJ(>_aoHsQ1QXMsFEj>`!Oz@7jOH{$=}@esbRallCv#-@HG$ z-?rcU;rCrPxUMo>bCebUf&c&eClTXX<66T>`W^aT>o;M6rq$m7TeL&JPd8b25_I=p z1QC0a#bsi%FbhkyMy=7$(UR}09crCgN3%4p-yvM6zoJOVcgQ=!rMhY&gGZmlD)Z%M z&?-Za-hRm0cIco1NdG#r4SHz<wST1TI{X4w`Yyc7kO zJ%<+_cErCYvuNRh`Nz*|Yi*f3C(}H8R@2Pm8XIOzub);oH9e(v@}!BWn(7Hvl@;a5 zvP8VJBo>W?L&1RG=k>T(Gg#=L8iVeB|4X92JX-vh<9m8w#56i zC5gKh#`}`picVjdti*e69UWcTo=C_ff-C0r&FktrzVG<1ZaKc3Q;2pY+g7zsn%I_{ zm&DU5yJcNva{hdNq6^1eg=5rgL0s-#(ysJo`tW9FUcD-qY}*(~v~}Qlt;s|y-oLH2 ztrcG@2XVD*WX)qtCA(Lxz!eP*8hse?+mvc=DmgbXX<{~Rr*o67FT=T!;MnL|Ym~A? zUuzOIT69Ws(UMMlnYS(3n)Om|TNln!mpk4VuO-RmNfWn0(0kfWX-~>sr?$u2rR+>Hcvq1|AdNfQ|pB@z}?XF<<$Ttl=EcGTC0gTCb(aaOVED(0@2 zgDvfH90alTBzrb&&5$#bZE?A4aeE>Xmp9=PC1<+3Iyxe49ZIaWuQkH9AZ4o1 zd=WX8VilIyw!gV`rLuyxgI$?WrL{-(B5fuj7XahLJycEFkLfje9cC%1>B+Ae8Z72GhlCE0f7+^pGDy%lWKhu3OJcB65j zG1@_|ws^a2YFRFuTe>=0+xpu2+RuatG0yMM*q8A$+vDt(o}5bMR@7Ff=hnz+>`i5R zlP1n-CMyUtS!Y8jur1S+XA|afolR7}9pT$Ue0z{@5Af|j`1bF7yN_>w&bM##?OS}i zmv4W@w{P+-3vtfo>iKN)Z-mVG1CCzj=YGn!EQmWB=8tV(7xL{I28DuH^V-LBDZ?QSz8=l~29_QQd@$DwQeT;7(<=aR2_Hxwl@TXtQ&#&X#wS0RK z-y$T(mFM&AYJS&we19e1XSDBO-=y(tyF4u-*L85~SK!HHmVi53;(ZX1w$=!YRZZJ+ z=$=){zU54LGok6)N=m!>`ntE0cz0jCt#3o$M(l1#g8Nr>_sG?4iv zoHQ}5wsrK&Xh%l^I#6jeRU}jG1PZQCF|&Otm$6+~##BTxmeh2}{+4mq@j~r7c8lff zuH%Jc-}klGvG22teczGK1z~&7gkF22H3=V~6Lu^v-`bk&h|6E{{S*2A9em%;_v3Ij zKw<2&_v3`-YE=gv*aYpjYu7F`5iHMkqzbCYNo_q#=59yMpq?z&c0CCGPiDI>!`RNp zvJl$78^^ht#_Gnlxr{lw=Vt0W4c-~T{F&Z`NCV6h=g)UFyE4LpR`+6ZqU$8j$-4QA z+|!XW(DDWKhWU;9HYhu$Gvn=Xxw_>{xu#`#mt4XWy1wF)_{z8(M|;J)`ZjI|c67-4 z%0zq>8WK)GD|;q$&$h7?Mr0d_lhO{}$`g}wyW~m9x$->r-EDHJrK>OA(%G)SH{D96Kuc~KYx=;yU7b~`{!@+YBvSIfrsCuz03G_ z8mnGFyD5mY*Vs+0-t4BrCn&=A*(W<6#7!NAzezYLuo7ha4j{{BBs!U-%8+&8f9yOV zBR^p(mBPH>8gkHp&-)I-ujYhcQB0DY!0zW z_zDXRv9CY{m$Yvsz2S~*hWLlW=_wr^(N$OH5|e3ToiF*j+T}g9^($U~ot_~)M1QKz z7+G=qn|RaP#Q|YH;&eu(HSA3lN((P&D!w4)FKCb{e?fEc1r6*4x9FD|8|hN9v3a<8 zn7)i8q(O)og?qMe4_QpAOj0Dsyxr}1&1I=u_%=&_4or}cQ`B=VFH?t-il~-D%N@G#5!Y=uSri*#5$vn zuO5^MrL)!9*U$ci`xn(%XI(!_#rlE!gKDg^(-YKc{SE3OI-oAPPW|LMbt!$Gt=G}A z>*&D9>*^=845@xHcU00<8zv&pd>m;Lx-<##79=E9Xsmg~#!B(Va?2^+SjQI|%ZNpkhDuF#fGWoX9$&s zbCr!D1dNT1$`pz+12zM}0GTo+ppkWpKNO<1K@_5y&`7zqinNV2^gv~6Wuv_jr|?g= z!GJ#6AFHOJl(c?m*CDEu#-t&+RFX^gDe*YnNp>pnQiFrpu1CMb<;~>oe!WCPZhpC9 z(Bo=@BpdcAMkBx4Xkb?x$=&Sg45E)!r$SD<6nFCiBmf#K-6>YVfyPRSy0m;;$$01K^19Y^IrZH^sfQ*K*|=15?Q#>JAqt<`R$ zBvet^n8xc*VL=xEle7=8j3OPE+Kz6644ItkZEg#vQnIh5J?HkfHE$)8Gq&b7?75rq z;ciHE6tApL7p_dzrtA5Y^=a&-X5k|>cI9BN(T4v>{%fhhXyX?fZ4~U^gq7lA{>V^i zyn>g-D?%0V(%D!;DC?j;f50C|C)1Txl~pe6B6(yq7=6iloT#r)*QHsx3x$>S(`HPc zQSUMs4L&bB=b6qjQ7EZ$2`gV(-D`Tmy11!p?(WmSdHrQS>3-+JYZd(|bFT{T{r0!7 zzG&O(*~ibCby@e7Z6_SpxURx5ah<*MoNbq6(pFV+)pd0}`qN8Sn|J@zxnkX?*6%Nz zX%m9R`fr_a|Bee*ST9olW}4A_#gfK`68iqZC5GeXT-DV)yTm-AqK9Yk=qH9Z^qat{ zA@twWkQww@O{<9oL1`!oipT|}N*1}GG!_M=ifOfN=o0#&LhM_~5BnogLt_d%N_iUF zTr6C&sCj7Uis9fstYdq0FcOVKtHL69eeaM-iA0rHcq_Rq8wp2KB2~w|_#{~5lfhoQg#SXD8qEF>Z#RF)5b~Rwuo?<& zYPNa&TA2rX=4QXgW-gQwQS$II$wNGnI2$V|l!*qrq?OsRC(e@W2C-09UNvn7FPk=_ ze8#k@CamR!vZ|W&G_5R+y{hJE>6)rSSxI6thy|9OoGwXEPRzzyQYcH5rzUGBhL%_es=rqd-vXc`_F_)SMn>DUU}eS{VNA%M~^OG+P8CbzrI?( zjg+I0Zw`%Uyc8?&(%d31#W*kdv;rG#DKe9fF_RKr+^qN)H7hXO8FK{*S70GfCK>Z= zBF@Ib4oEH`R)?9Q%sHK67`m#K_E-B7Bqr^`$&9&{#A>lAI*L>W zurM8^RNHXEMyhRC_z5q&!b<{PEc`?wg%c@~NMYe>O)>bST^aLCVwj1Ae{Et0u9-m+ zGqCWREbJx=Nm;OHH%UHepX}VjjA6dzpe#HAD26)d1tU#X84O9*a5z&{SxKi(pE09K z%&QEK*B=OQrBRtIgKjds_Pu+yd~5z{)u*3q-DE$`?W6RUH=X{$b+7#Aw-$cSGWQhf zKWTH5<(%L3%xYh>$bVdI_1yG=(-$q8JXv?necN8VZN-{pbJg8p%SCJNx?^&c`jbuH zKJ(odpIG;Q%{_C!WlI+a6!rC;sAAU z@9cQ3l}VwMb;VXDyp_=z$u)+)*vJBFS$R;ziaRq6Oz z6*c8ptu#$Z@|tq2R)oK|wNd1?vRa6!tH^F((%=b98l{H zB3gL!&wrtBQeG`e7K;}OKh?hmCA>(Zm9x+q-Xg7>yfsAG$y>u$q?O1;j#z7JsqB<; zM$zhF9tY!5V|qrwm<|}L(#EP8>8crlbQS$K<0n;L+_~bW8&}-&Rezdduw$^Xu1w0Lwxce>6D)WCYJHbuYPR;-QYw;S_*yS-Q&Bd3wkAPQT_x}3>O zXf6EKLs)6fqBodvcF?L53HmqSd3=;F8#EeCUN4~wTE7|^g4?h2iWaMvNM8-%pS?+< zJ^}Vh_!6$9U{%}b%lFZj)wcWSR_#-5WA)CeZ`1YU7l=OdR4j6wt5|Q1rxCSrD!PmH z)}h}0!cwDi5oz8xoYS3wnoGMFU(cwotAmC%rt8xX-Wkbc_S|#MT-zM<=)`kZuO58p zq3E}*Gbf#n=XcUy2#bZgp-1yFRphNPnbLTR=6P#Orl{762>RA$MWMABBxC%IH}0f= zRV~8Z$Zp~dvALOifG3=IgiMV+;lGmFZRnZ^DI(r+cpI9)FEa<1y(8kd?7Q!N@ByLd z*?wR6rv3{&BQLi?ffw-%qZXD5oEM2K6f}cVJI^I#fQXF(h0oADL=}-B7!u)SgC8!( zo53|;?TKD~;hU=M7W$R`i+_A&upu@(Ve|uCmFCN!Vq9Ys=@%}xpGH4(o_>*H`j+>I?cgAMM6VmrB6F*Gy}c%lY-#KydiSzFAK=$HHk8}p58ch&9+(wr!o&CH2m zx8H}`zo&UC{ZiEIkKiVHm?t}!v3oL-f6PNEdKw0gWNyM*^iV`Y(L=$WILq%D^E8N9 z^lV7TFV4nV^ia&UqKAS#bF*aUo=u0ojJPCHH4ed*pazBTFYZ+D669b!xCZ3nu* z^a!4a&WRc($O~Ext%Vwv6?wzTYiN4jI77DWfEJW`A zlClITvi{O=#%v;16Bg!DFiwZ&U`ra3oSx>cn9d!%GMqrnfu;=jbLZNC^`;R z{*unPf6bGBco{@7l8YKdAH4OBhw= zL1rd_D)r<8jVh%Ds!T6ZrIb@8s1?`%04n5=f?Va;&}fm9o0-qIO^zVk^?D*)IFwYX zv346A!54;esi~={*@(@CXifwe$tE3AN+Sq{O*T;G*fHz_U-AOeSh#A^!c|a92?nLT z+mKv-U|5-4D(%Y#z077Imvc(HJnxbY*|`tBsD#|lbQ6U`tkG-CVEk*VWPA{bBQ+-@WXbg&C8mdsJ_*PHuvR zg8Qkf)jx)mXn>xs(YvS{gGG94y3t;scc@5jJEylE^oFp&ft4gXvTtrZ@&-EQ{SGN+ za0QN@}#4Y5Vw*GvpO-F!WE{hTZ|!g zquDOEXFPz<3;zxU*Cira>SjCNv(bxbP>_kvSE37ga;yS4MZ5joR=yv+F9 z!ii(vmI&jv#JJm5;Jz&J8F95@^hr(GjN8Y)-Eg34bWKFRpL%bzDa)`HN zs@Req&7Xp>`A=>pcrlh&+cKP!BtK!owhidk=ZCig9gA*e1j$r%nT9OE zE}90r9boS9xsFV{vNu^-@FXO}Fg#C?tdx)gXu>KLatI!OJgJq%vFB+{#{C|iLzt>% zuXsdhOoQrft``ND1RYpRC?MPvx_5kL%36BQeY*1`(@lH#{6qcY$HSu=`dXgo?R^64 zl2i1X-snGf-KJZHpHu(w-h1i+U}R6B7r*}cA^!$h-mpRGXoqy2z;)ma@D$G0+Qd+3 zld<^8z}v(m8}gn)!Qhy9n>b*HO^`4nQjb}KPOm9Dnsr!kVwa+GD1<4jti_@EiV3&J z4YsOJ_^ojWS@Ev!|1}1bG@S?Vt7B5zRufD0ip`r&~Z8pO!FA@d5>W%C#L5$4S;)0nrVDq38c4?EyTo}$StXq24J zqG2x%Gmb|J z&sW6N&(>_*xMt19dGprX`1I2^-nbbN{(*4S>fGyp{p;(wHI*T6@LLbQ_|7{oKKQLr z^VZC zgg8(5!4rgO6atL`!C(gK&4=x zs}!cy4`+c)WxO{TFSOhddSg~zZ}6P>5&C9!Uf&?fD0)@!q|ye281>WOssdAKG+cTbPa( zQ{#K@QG>cgeM?>S(MRI%iz)@}!lPPU5^`%Kmul@&jNHe13J;HK$9f8RHVXY9G?dl1 zB2&TQTh?C)(?=J?`xdvakTU=w8j}sOp8GB6Eiq6(oTaTS0G4Y9Fg(07hC389V(LY5@RatP&Vx{}NpqTx%2V*y z$>%CW;oNuMMYiJMhoaxI&YXM(e?N+G4w7!6_*WSD%eA*FW_rxUx6?8`rhKNyQhYnE z%?Ctc5{Rj`_M-(eGiGDPWW>TkpNv_T5p`I2YE@^ft9zaQ4` ze@-t0p~#`+=_O<^T0@{3z4RG_9t)?JUI4v7J7b<+qDc>Wfnv<_qV=E_Xr^0uC@2O& zvft9JYWouyD6#knwS5tz86aTdAN21*)5S@@Ml*du(6tLK`|ChNJTD=W6Fjqz>P z>n>T?nlm@X0WHXwkuQU~GxOTTNiCFL3E%;W+j~gSn^_R3mlRv+HtHv_eZx}59Lm^2 zSlIP)s8;bHsh=^sGce_D4?pRy#VxXapQ6)o7fPpRE|iY+e2H`m`bKz!JRJ@V>mD&0 z41r`N!aCmLCPGeymYZ*uWb2=PKJ?{Tmz^|Qly#lwFK(Ta`C|8OedB$bzxexy%F2P& z^X^%7&)((pEvHF33!nl1R378(|}0+*vv!ke-pQ6AgY5 z4anWk8PhBEb63BjX8)ufQ17GXQ_Focwq*So>LWi^2hIC{QjeYM!TC3io{t?S9*PZj^Zn_f#r{>X} z>P_l@eyBctd?4aH=j8`Kqw^ki-!}5VlosKvzdzM+#@%c0ewj%{3}Z%SqR&G@{BGcF zPo#oW1W8#w&m}Rb0Imm249HE07S3~Rt_Y3Ig8{!&FhHsAV$wMvVsHTus1cb1cSBYT zcsznLU}xT8?J&uCtR8FDDcDj2NNM|x9)$Y{5ENwiSa!@=nHrP;z>ugvHE6fm1JM2{ z#i-+j1{5+K3f-R?G+K;)FLtOxC222`15?5uh5L10FO?RyUh!2>2}tZq$*L@s5YSnr zSSstmMpXPd_Jw3+R@9-uqCT&VbndzLj`Tlx z*4e_{!}MpL>vtTOOP^Iw)BSp6ov@Ml*>JY?I#4t~%E%;|)#NEqpy_0i&}(_&0M|4w zIlyUJOG|9pc^CJoe2bdMfTfmw(uleA`R)XWKsq5lPZ|6oh4;qc2EY!&Q(?< z%GlL37YrrgB=_WKfClop$)O>1ftHZFawd}tu>N<^pbG_I()S8w^f%Paht1}-Bw+W+o})0?Qqwww!EdL2z{`h@;_oz3}d!KvksjPare#g#7x11ex zg{xL=f8#fLui9|&HEYfuxqoEz#@nufSwb(#===J$`d^b6ovZPSvA{1Sq(rCjg^}}% zT{d!lDJ}AgmO|4lMs6lVa>Ec)Bq1%+ap(azC=Lrt)EbQ}RpBR(C>GuNVTyd1O!g_U z7&kL9!puyJJc9Hj3LN_sr;`^r9jw5~3P?8YjG>KkBohPYfOpUiV^EgCUXLIDg?2Dn zib;O#8Ik0-7z@FX&R9(H>q34blKe*9_%?ESdYzua7g-!m4YT0%SUgTg6IM&%i-;~1 zOpm{dOy9CHvNNU;zQB* zp7~fk@aNw=_sa?)rv5?wH~Iv62bRt9Kwmxu>0SZpc7WIi zwYDnu3xtcZt@R6-^8Etnk;%)p7VYaBn-weM87+KP+a6*NIlj_L{s*e!NatEpI-_ zGQPC}-rj(>KxDnii)TX+ya9c{Yih#Eq=pAXCacSTJJbu+m*B!)^enB!TR17kvLj|By8i$@ zL*#E7HH%Ts7&Wz6!k6!#9HS-&R^-Sc*q>%OIJ6yI7Z{;{JUq+!ZifSZ77?UFh(U#X zddp5$;LtAFvjnzhi^u1dtag@S(H7`Nq$ z=G;~b7_=uRfH%feW!9{lW@hpLHV@*v`}NZX)gT zVS}B*Cp#hQ>JHr_#t(feUaH^G-mW%d^|Z5$6QkO*pqht#as<_YZOz*kjcQ_^YUmr! z^C0gV&(TH?d{|ioos4Xf0MH3S@6pVNjnTA>(r zn+#ksnb4u%gAT1C2Q-=#BccgK9jZk{ zmV8fXb&)1oZL_a6=q#p@1`x zLl#9Qhi)iX16hyDqg%0?K(E>`z>K?OizHk2DOM|2t5yqBt5&8~k5Hmccdyf35KGbE z1a%>nZYTD{S@i`14-taiVh?OZ=%=J zhCkA8mJCI|7<^CtE2Y2xe52nTOsI9jjaN;v4oslWVMzSxK&Afa=g@;W^-t<&>T6Gh zV^tfQ-J1{nb({SiX1y>BN1p;WM#xT$@{xk|iWa#s!mXE6j&SQ0qY1la)to$fu!)VX zFr3HcT{*vB!#yz+C%DjW^c%Bb=FFIkKIG|xqPyI*hiQ52&2n; zmiLU%U?VQi;Hpb`nLioz73s_%SCDJl^U|(8zYI)CxufO@J zdHcF^&$~vy#){``sHDZ#@j&!U%T~q5A)tx5yZ8l{m)nmZC%T!CQ(8 ztA+VS6p8`w!gTUDrZFKE4py=tyx<8N7G78pd|=SPc#ax$I&`Uz*!>B8$HPak?n zc<PUS7sv)f)0fL4A>KCK!TK$Szyrft^ zO^dtpTD-KVOBlQzIT`_qL@}b(om$HSnI4M@JZ*%~G=lN)AwVqIU(OP-hPY1An|S?= z;0YFl;#HWPCU`g`PrxqJE!*|t1(^hAa*|urFYLjf@ScrJ=4MSXjAH45N2fQ4QcF8V zjCE*AMNhN#0918PzvPw-?!(KnVYdj2yTux^WFn!kDJ<=NKMd*C*d%IVY+^A*Q`)g5 z!j2=+!f_DDM&=DtHy##Au2l6N-*xUuc06!GL89NslX`NM8d`?qDIfYv@7N z_y@c*rsXI?-8B71SNH9=(&TkY=ZQoA6QG2Q0}=ITB=Sgw0NFO^K=2gut; zv{LYES}AmRD{Zj~i=2&qw9-&B293ZM8Sr9;0yhSVus>y7dyH#@v8I7y7xh3{uUGsa z{5h;6QZd0iK;%G`bI>|ixPIMB6?7)y8%2{wMnA~9GHV4{70I1HXN8ZuGVAk3nL~CM zeKaM@2$QC#cXeHQneb^>*Xq?HR?uXb?m5upC3t>|;d}fJz6UVp$HHmlBeZyLA_Yr z@oO4ZfBoxUsrdZWm=Cg4eNz3tx=hB5Kx}rLMM#zXS^Y{K1pS#md;t9DhTaHi90?zQ z;TcVIOmDck-80GVBO+)mDr5FxTz(~r5tI4+iq|W$F-gd;*h%hC&TIGDvo7Y6SnXaf zS07^@hZ2RGp|I0biD?0wo90<@C}(#&7^r6#bVv{(8w=i8%ob#kHDb0Pi`jxP#B9NQ z%r~#7ny`+G*}Skutjufm22IWQU|o~r5*vnOxn?rZ ziJVVqq~+y8{M|qP@m=*dPb}~G3El9}9d|sWUaa5o-j271sW@_<=)Ykj%T_RMzk_qT zmsHUbMr|Z$3Zs#ViHk9(`|!lYnA5E#E|96%PD(&(3vgBudjh>8wY3V;8CfqWXMVU& z8V2r%x^z$t1AbpsK*!K%_@g&g?x z*;rXpqeEYnHWrwdRG zWWz%h)eZE{lsch6IR|^ z&s?psJRsW5(_vI+)8fPJa5A3k!b#)wS`8#7%mWP?Gu!$fwg?bGtf$ ziPLaj@A|vcq<+W0?b^9I;*(AsRKJ>goG<_psnFeC&@Lu>FSCBtpr!7zgMcMn_3*{mp{-(`qgM7{S*(Z%p^?$ za~Kpftb{yln4bwWdgtZP zJ|!IHo_{#RJpV9@aJK=TdRPAx$0U!$Z<3QkN_q-zNK0~hA23w>29jns5OUWMQ;e2K% zPFM~im(HO4h-7B2H&Id;Z6|q(LXSPEIZ?s^NX2n^MqS~`nn`Tr1K7x@!(PoSeAGY% z6m!o+*GqH-o|}{==zYM&1Q(NZ6V^$El$$3M)^t#~#8VOu&Bm(Xn$lpqJUT?LrKJ<` z!ic;g+_QpXO3Le|>H=w9)V}kH%`YBz+)I?aiR95+>WKR3SXxgp!eo{fE$?K4T{M44mO0(daglB#Om1_($z(9iP33G3DsDq2 z%7m;Z9KbP)O0x!LKzAt)h7s_(4GUVcCL}h$U=b)wuAxUrv0C^pVr1sPv7`~pb`-K| zfKWSBr|ucmiIB+Aj=uwc!kat}udNDi5+MJny-Cq{jd`(}@$%=h?qgo8pZC(35n=eS zii=^yoG?~EMk+?s1px$t9R*o%wu?j`;NBRB+0)OuZ6PzYJUUQ3Jbgy|#4qjTXY^U( zv4AhLZjS|HMsw&LK8igDd!07?7g$L&*x+Y?m2ALf+YGa@j!P32Q%IuIO`6?KElotx zaS5xWIky@jj_>QMkQVxb`YZMQ&#&?*`gpEz{h8}GdHhIkK)(=d~q zeiCTsB!A(wBgHsUA|>e1--?0yJdPxVkxVXHk{=PFq2qyh8?XqC2E9Ytv!{7T$D=I} z3(?jfz82Ra$cB@TEIA_Zap8F(Djx*n7)&S}aAICFjQM7f1A4EVb}P$1HY#@Kf*!eY zaeFRfuXIX419vETf`J#z*LM1DGhyKeaZCbN zQmP${%PI}BoGoP})|s&|5{IIkStFo-v;+$)4EeBN2Vhrp_hrmzb~f3QHuA3;6LQH@ z7=5d!5RJYiQFaxk4TxjWt}2Nau8L17;a4F)9A%@&(VL9fF(fS7l@6)UUQ(q)yRuxW zK)b@mn5m)zQ?1Mr${NlWWz|K)l^`4z^YL*7J5gOxh=(fxnOp@3W#QOzM7bAzoGY{O z@#u+b8-G$b*IT@F{!&54_y+g zx7w$Nb$th~iZs}*4Kdw~h&L~cHCXL4q6aZkFml~QUkmPv(R(!RDvnD^Bqig{qgo9WZmy9Js2GKno@UcP` zY_n9DBBHwkBCN-qfTapdatE1^0$Ti%}eI zq}w?d-vF4>%B;Y^_>#kvHE}S$R)l(@foV*OvPVntiJQAA^=Y{1R(XWCt; z2JVu8q(vqWU+CbewQQH!bd>0u%~mG*%t94JA37osJnF(gz{f5O2E$_)f-3+c$mi(_ zpZRH(q+#$cPZU;tF-Odg0}l3!ey|j=Unw9+@=a6HXpsJ`%@i zG@_+pO*LCpjBk&yx{8xI#W{q+g{TvD7wuE9yE&)CN&vU$x9YeBMsTHL@om;oLZvId z2qG=Q+aLM!ae2K#hRVY5xYVHDh=nz%8M$RNs1*%rHeq3fHU}2$P({E~FruiC&C+AA z8>AP5-7sa8DQgr!cD>dj_#U)~(}p6w5iMe4MIf}vcod;ccn%0{H0q0l2Azv!&Qse3 zgFk=dopl#OB|p7(?Z~^ZV<(6gjm!{!dT7H4=0OAM4PHzR^z@JqHF_3NuNYm*Bxm$s zRztl?dDJU<(DIVQoNJPEFESwyinN~FJvWtgqkoH>t+?^h7&C=TIU6sO^$-kZY0SGg zSrdcYorR1Z3t`w*7CQs~Wz80bi=kUACbMKf7bHr7fPxb=&cU%`^eZx`QYAbkv%u$5 z(TFEl7+q~eEr%&|a4f*QfiN>@-V^cxO{lp;^|j)LLqE{XI&`tvckt>LblvUkr+wq# zW7vW!*Qsj+qTf9>%C%_K$40pxo*f<=<;t^I1ESDq!3bsa1|HTY%F~s;#C7yqK%h}aW9Oa! z*nQ`*#$^_*tL|{?O2xc&#pu#}EAoEO0f9CWU}O2XOn7fY@In*;hURk3(4Yo-Oguo} z=HoIa7;OLeig8b)x`u8YPp4v*dW=q5wy!W^dW=rmcu=zi<3aOu(q#l47L87TcNnp7 zIvI^R9jDWPL2nif`dZLrJwwLnF|I<-E|E#CY~ct<^zHH9p!!4_(8udO{+M2?uDR3D za3|_J`h^e>Ki1!fF7ag=w--k!jA2@}5ehUvLSYQk%F&`ZQ=`7Mxj9EMZ!B{=fL9ew z)Bv_+`4m2OH4W2NCsfickEoBSk3T{O=jm@ebhq%z$ZT;nqZt_$bZbY?0Yd8kaCAK% zFWUprIwe06*oW~Cy0z*`HgR7}w*z>~Pw?&eQNZIlA&+9yP`l$eA%9-$5f_#bV3J|n zVYOro0hYzx{LSh-v|9aYe?J}&S3hO>uZ5$Z>t^dtf)1HWztHGeZ2y*G45YPxEZ0&ykA*=8PeOvj}NBI&_McfgB|>ZX58@`iz;!zO9PE zysTX@-~ix8FTjmc*{&{|@R=E!9%H0{O<*^%-8@b!n;CZoL~0Aur0KeXoy2`(CmMLxaj=(jKJfQPD)Y zfjzzfLqxK@4I+D|22>0$7)!GQuZG4%g|q1?4J0s^k8FM6slSv&l9ku5JO66?Q}$1O_UfKQ)KuyYALl)5 za*5p=UZ0&h>-*PVc4p^oXSVotf*9L;`yJ2vN=2i2dbRnq?z7L5m1iCw>5n9Iy6Y{r zhKklu;BxxobwP8`y=*~e_leV6?a>(c^HT69GEKx!D(T4@e-`n)Riq4~_*rzO;d!lj zJnsZr;?mCNqciZPDFYB$j6AED0^2a%w}XwXQN;RY)?I`C6zTnJCKh095(}^7-CmL9rCA%2EN^JBVM|9XaWK9BK^dq~y~$?;v- z5pzE9Nh`QG%)l1eUTc_raX5~|PB_!Rcmn(p_p_6}F|=+R;{la8d-~yM!Av058;%ut z!(?S1BqHZ<%oGb-o3Iv#@K_xIOx(lD0@$-Q(;wA-gWOS3l{=3@T(UDb^l-0->I)|@ZWgt zJ9~b*^B2RZaV zD8NVmD-<9m+B!B05CzDi9gPAUFMI!+P=HJzG3F2Om*RN9{Cq+)(&AguU;pSGl^Q?U z`D;v4)wlNMhwiv-)vW<~-Rt}4RQy_mNb7#SZS6H54()k!{Z){u`DhyzG8M!a+HW7B z^D%}tFH@S%m-0HlvWS!B9wXQH2G%4Y@|p|OeQ92>(Ah~LSO8UVr@aQ*Bcz%zc>^1|$z&`_HenbilQ9V+1GbX$*b$R4 z?-2Y3xok-GjgzsmD3`G)*S%3MWGIRU<%P^qc7%|XMR5T`4j&<7rJ>$vs32pafyL>N zqbP9yQE?VN#$~6XrCJ$q{!wu@*1WnET+@Ko1aMxvH4V?e%{TuJ!c*CaqWB7dx*B|MGr@cbzz}&kMw~0U9`Sxq?{`m0^zeFo8fo4oV z!a``pA06F_CQZh)RxHe?fsxR88RH&qp%s-HU}XB01d(FHDfB`kXsyB9JfkEG>GYjlvv+B`oCX!?oiC|KFC4%3krE#&{ zMO=1qHr70ska|AxhYu4;Fqk%n_tvEi1`iuo$)=OS==jFZ)kDYG%{Yv(|OW+k~6$J@xc+PF>HuO1OJL{m)^l zhBakytS{Nh!a`v6@q-rH+7nDsCAhk*GP38Nc!?4X zO1oGoN4Uo_OzVNaF*}pR>(dlzIeAR+`nabnlJl}&pHI`Ht|7UGyDLC=M#m8KQ6^q7 z@)*Rc=)u&mF%C+34eFRFw=4iahsk_iyLzP~v}+C2f>LvocI{1+#oj^W-hNXR+U?3V`bgd7`+4}C>xzrRI-@T(Ivo_$q#Y$jMuXEhaRWr=P>g9 z^_>^mpP_#`IQXuAt91Ew_iwm=!wsA6RNs2_4sMC4ba-qBtu{yy%f?v$8nlQqB_zT9)@nIYv~`!ALTUh7}PL zW?$TnZky$pe`XjNd}+4=OF|(kC9s4H-v^_}@O`Wo31=A+6mv1c{N?b&Pe_Jy&8X<3 zi1*!q{+yR%puVv#n5Y{qg{~$TxTY}%PK%q6Pjv|iU8t^)R zqt|@K0%niT0O9wse&e)D8#BxW?K_>Fr5DS}P-o{^Yj57v*$FRk|AbqHl#!$$f9K*K zZytG-$<-|&;~Y@Xj8JQfM#Cb;)KSz%MT{w4_3JREiV0-YH8%r0rjtI}!wFWV5sYC? zL9oNHrbr1$=)Ky9bPTYnHp}tJl_fNXnRH`fcsZPg!W~Hyem%~pp z=-l3E-T|}2X$b05Mf744^X2-I8#?hPY~8AxeDH1kjy*&e{Zw5>XX72&*y0zpcPx%Z z^A+EbjYeY*4MJPOG_F3caV5Q^FKS%HbPD?AfTVSM@rn$;idW?LRd_;{T{$9&dN#Hd z7*})}L4PYQ4}V2T?{STLMRxd4ykb5uVDQ$edNyTcn!Vx8ot?dRR40=s&Cp&mbMKA% zN7C~Qi}x^@K#S@q-ZnyY+PjX!O&6jxj+-8jZFOrt%9u*{|M+ImZ8C*5_?T6Go8UVMq#e=8G`Lkj(o zx_0E-LcCAKuT*e)(pg+W@-uc7<-=0soqtL`n5tniGLD?b5{&ee0kg$=1Y@J7ta9l5 z)3lzU3bt?>{Zwn=X$4DIU(|ZjxFrn8)40}~UetO4o+k=vqRO?Nhs6%1WVzx2US;`! z)u^kiL)Q%q6bsBTghXI-EwQ<<%kJu#%IF z`#W#2x~jUWDlm23MreWEt0c5SzVPeVC)7w zR0g-mM#HdTO#_%sC!EpYJSI(20@GpX#!e}?GOpl@;(g27yH0EG=NGS#+2x0oEp8u_ zoK@9H7)=?^h~Rnrh&}J0zA#eOq5U7J$fKpb(b9q<_xOu}iKjH`Z^FtD7<@pK)mcOf zStnLIffjP|#DJ#ced+u(KMdi;#%Uj=><`!c%TBAfeDfX4Dt)na-`l*Uv$Ln`;=az# zZ+_#l?{;?TCOF71sn`~;H+{YmEcb1(tL9?l=uekmJM$AX+HIusO)~mTmFkPp3_D>nDAj9FQO!LR8b49L zq@GVcrEc{j)ZGt#@`E4j-~WRjd;;&~Qnf>u1g(R> zjCN|eu-LaWp{NVBz9n0JQQKTmW7|TW3lq1+- z32UC7)Ny~mY?tgAmpX}-F@4u-i?U}#%XsRf;M?nX&SqSCGM_m)Iz1U0uZ7IEq82ij zMs3hSV{>`ioW-;X_H513kkeL7Px`p-Dds1+3SwS=-sMDs(tqi))6DCBs3j;3u&wzF zIXy*d!(zY3kvTBuSPtwkFP`;z95V;z zK^xl8hCBym{TFgzthXAimrs02z`Ya_Uy_rxo>P*Ui?85_CBCf4dhPn>vtG9U`&ln! zE7>Ibn&mh$>lJ+G;GcKBdXe4oOlPNg&C~bZa?dT-J$i2p*m-2Vs-JfIUObQzl2)X> zUU~b+TG|Vi0weT<&AjC{Y3-Ju`qD&0McE5-Kg1yixgQcP%ANy$2vr=2kO>PK6dTl= z&12F97Bx$|ce4p9kyA*-I+Pj!50($7vQEi??1kdPGvIDOs>THvbin4&8@(711CKID zF@Yct#dw#Z>|`C8MLUX46Qlrn;(^oR(PgIv!e`wZ3Rm3q7}MulQpsE3;Jx%Xw}o?& zpB=;-)*gkLoltPOrjU|+5`6-HRY{(}Uo~A+>3P)bg!Gg#)U0-(p=Ku(P_tm-R0bhv z6bNgEnhoSpv(JzeP_yM$5C547r8bpE%|6=iuS|I+9EO@@vkuAuNe=A8)So;l7Ywkh zK~Vdti&Fg5#bigSfSOGVDYcVvL#-s&j-h62*$w2VU%QZ4@;GNLmnN_d+5u}hTgFhc zveBwV48HcFaoUdP}1PEUe_otFF>0_M~Qf zuxa~_ftsC=DxzkwHvy>G)P%7s2LYMIf59(H)fQ2+DIKW=YL@@>1^3H5fuNRX4&sr) zz-+8Xp=RN`@*fr`WIFgy3!u*q|M_{?0%_s*rt4N;aB+3@726+fnft3(fBA{+1^fC9 zmtS37ebx5+Gnx0czWlLK_#bOgHTjpN+*!JAeMQ5Gf-oQ?j&&jO2Um4uQ z{QubKp9P1$6K#5vCU?dBVW`+o%=3rbxMUq(J z)Qv7908ZxuDZ7`?8?YSa3^Q}@qWyqDdNBB87ohSc_VXyaFz6VWME0{dZ1`XW;?v4{ zs1^nmV4}vb73jdM6C9`4T+)5dJ^jx-(>NtV9V@RDcHT`Vs{8I9X)fop<8Oe3{a!a2 zdA+Z+cL7{b%jzYHIwYFcAyF<^WyM&A=@6pCq28H_4?%q3b!J08VD{1Ht%KT7%m`B9 zVX~pTG30Wv8^^8#;eRqq_)uPSE+b*HUWudok{RNmoY!r}V6O9k9ku}_nAao-OX95a zI_EZ-(M{OYl(9IFHg{+6!v#Evb7Y4_ua4rsz+<5(#uu}6Gu4H3G&&or_NypbKQEhh zwJ>6?KFvCNHG%^1*Szv#=4mcF&Fx?N!r&m&Q6ndISc1KPosERU>~5A9C2LrMvw)p7 zV!+s%Y#3ulHB?y;KT5DBYc>{+k1V%g!jRQjf1pqvK;Po(tQ8PG?f$WHnl&2oIN59< z2%reZ&e}1JFvrtECu!JOPde?Xt7F?dVpdG2#UwpZ-Mf7G8*laWy!Syzr}|b`_s4H_ zfkmDdmmYdb>^%6k*m~#(Or`>msbTQSF_Ex&vwsv4HlIr?AYogNiG)S7emxQvg%}e2 zHAq+#emxQvh5rXg*wtT;gkAIXNZ8e1kAz+Ge-{Z`Y+sIm#fE(>4C@8@5j zK0w!9aH0Aa^#JDDnjjc3i_+C2e;fIbKA^7T?W~?8{toRNCVRLQBE???i4=7L|5XqY z&i^V%w5Sup+zJ^^X&!XgU51bgzbL`{Bi>7Z<~U{wRAE^&6e4Rj$l%Ta267EkwlLH( zb%dS#JG@SXjoDwFbzscCsMx~nMu-r_4?ksn;TV9^UQ^bN9Z|11(7Q?x!;e!6w1T0k z-XCB;j{~Cc(f#~W{GGb$TX)|*rK)=NtR>S#b?sSa(-K;C=5nOXU;5hv)b_NK_T1vq zWe#l+FNP#ELlSm^LdQh5GD#RcbTqOxF9}6tYwHon)^q;}Wb3*ABC@qo8@j`gt=K&_ zvUT+l$X4+G*CSh-h3iLN6kA5F5$-&6&8?z!(V}_BANmWnpvr0LIl^f`Y$nKcn)iYM z|C;wQ_FD-i?!6EhjsnI~j{Q~wM{MStjRe1OgIOGdCj2ss$;oH9*~1#2$|h-0w28J* z5M8hM0T*C2y_ii23&&`BYx@BcaK`vgyD&_l0Y9ULV4USs(7PJ&RibYd^T_ha##{i6 z%@9s|^104$e53QZC(k+l_{#b7D~~_^9Q7P~@A~0aU%%}2SBKa4+BcY{E`3w|<;sRo zZ2C&|mv1heYGU%SQzi5?16Y8Zq`hY`%K}7f9`C4SS-$2sjK(8kS!ecIq(9hC4zQmx z+Ig>vzU#lU=M?B!R-k9`ImsiQ6V7LI%8TPlxg6#^d3u^HVa&-8#;mPKH|OaYmIh1x zrGB#|QlO_J<9A@;^mNqrQ^2J41$uhw{U9VJ_nyHz{#_ugv3|PW$Iy2^)@_Y>+)f*# zqej`&mZ|4(64H{D(_^9kr@bqIkE*)*@4h!{GLxCiWG2fblgwlpNFX63A%rbM2y2iX zgvd_9zOUknD+mZy5fl;EDsJseCIL~g*rH;KwJNpRy0tE?O114*>qcI_|GDqY9;&vs z-`C%-3@`7^dvET$_rANFd(QuyfB(hIO;xxfrjGr7l=D)yMpGf~2V!JwLVe~Wl+&!1 zGs?fhFZJDBO@poL6ADk0}3#OZKp&4wvetELTInAv+y z*+~C}(bcP_mM`ty_ku$9-s}mUp6;TtBiGNKP*RcY9y^lkf`5@$u_rWr@M4nLQzOfb zD0`|B;1mWg-pHfusS3>3sj{b<>Hvxcd#V=V`A{MCG^kGj?~kyjLfYW$soGS|o(k$z zirCHBQ?-neO|0M_le~(Fd+Igk>RVQ8<#;Bir0F=0s3mjAd2O>m`j-IWRZH*`#p-BV{ty zm0)$akW3|j3qaE5>9{NPalbLwPYazqF4hHdD?;?G%?soZW}93P!67UDG*_Bg%w^2o zqbD*bs5F!6P6BKP;omrHCqr4cCs?h^%D0q70-1Y#5h^|$c|pbJ^Tw{g4P{#lW#QG4 z!<7bQ8dgUc$U=sr9y5}5tWGB4hLH;^K_oN9Gv^N+ zGjLPpBN?MJ^IrFruDRLyNbbka4(>PP{NXc(UB#^LRg}qRf1TsH;oh;iKCR&;SM{>T zH~1ZCXFoPxx#{T_nE8#rm5jd?P(2N+)}OsVGHYIc>iI<_*)%>i!i%~YoWhO5=Sn+K z$wv%qc%+?})$!iU+sTMXJK^Jf&;-|LH<9)E1h)?#8hV6ap${fw2^25j5kXv8K^lq= zT_WB*<3N1qOR#Y$0Nee|0D2t{m6w~y5gyTLEB)n_`0zojvLZysZ6-IsKh8{2?%-ZW zMxRPLVC@Lc=P+AOoIZialnSm=e3ZwO3z_BkC|@dtj7og?GyB8;FI4EQ02GZ3*;wnx z3@bh*Ot25#iz_?eAPiqM@a^#TK`eX-?yNF>W|HMf9h)@Gy$=k_pEPmgy!zT5y%(># z&Th1w-d$>QGVRN6eD$b)&lOv4_f$C96!~ptZz-!~S1&FZHF(5`TwimJztU=2TQ=doG_)(=hI__rH97?>*aARWG`r>~d|xxJx%xm9jEGC#)qd>f?37i<$u% z@02b7x3$8%-6bDo%l$)dy0;Q&y@Eg)~PA zJjEzNFZka|YA|UK30%LbelXdA8P4f&D)ewV>EH`{_x}9nd-uK|-xj=f$=qcN*u154 zmt7rfyK4E|B ziQo5n4u0h~774y0eE2V1xy401EqK3^FCgh+pr|8vFCKumR8y)1;3a1jNWyW>eJQCa zigO=L*?a-4L5_oIZb-d|^_P*In`3i}y?jN*f(Jno@oe?(WsC06|<9rj3QpEJ2ZR*&_eu0>{X>Z;^aXG z@2i~2YUB-z7qb@DvS_iqk@b_W)UYe%%Vy4!FJo6~#J%gq%`nN%=-j$q_wai82DWEzFB@ye5iA(MxejQ({%X?O}6%Zcy5dl-dFNe9&Uq8 zkv3S)`;{$F&imEaNWbE1e>K6E-zZVeP5 z0(hNZtHX!iIkFCSW;^N59zu2xeE6L<;-R4)ACLUTkj7*BcB2F)=}ToOr5%O}=!Bu% z!)Sq-3Z@8g@Iy~aKhQ5af5yri_Pq4SH6`V?*}r@^_&m<7oIQ8r&A0w_$2Go+l-Uax zvR_?&=aR7nc~e_{x@b&Z&Q$ID&-`HV+WF)AU*5E=V|8Ffex`lVg8ffE8(6w-{`jix z%{P2+)%}a|GfWGX?VmH}tFt37n^e;;&Ea1(a?Ykfb=C~9I093t`K35rd;d3TPdZf& zjkYJ1H=bqar3@yGX{3n%)Ov{UL7?#T;EaF$4A|y%4vpXt9q@2!q%+i>pdc>BHtDg) z*x1J&)87BmOD_rH**|r?Em^d0k>yQWHnkA#1j^c$5&;!DZ9hM^i z>V>t4K)qJMYL*6JBTz5b%QX3xq4F+h zOg<(*DGy`E5S|KuI|VEb*UGyPdg`z8ZnlP*AaBSMfwtSNISiepif@d>l7J_+I=(0Q zZm8$^Iw7Ee7#a!S97y3{;cp(lIgs~!H*OmN%k%$wpACQ_Nzwoz3YQyVgbI$xX1l$w z9XR^&$IspVi=1s4TNht(%Wa!mw`YsvZ+(Ore*S9L1AC^=d-S$FPqxky;PCx!*V{Tt z`xf&FOGR?E)Ch;v*TXFC6`pFvP9>8x=Rc3W7EO#++fGWD)i` z<}l*M7r6+b{U}Hh?{CYpkP{zZ=_X-Qi1^D@7d}|Z%TEV-9}n~d##wRU%QzhbcHvZL zXznmh45B#h3FS5Pz#2qb0&@a)9;rcA;Fy(LPKAnb+$-;01Cvas+~1oDMMJdeT31W) zX_Gzcu%_2j^HCnkzT-do^s&AP-ZDmSIisa1`OZ(LJTfV$?uKY-L7L%lA zjn3=nl{1EUdRmPs#@;q>2;4qQXenx7=JQn`BV(A41r-Tt}{>EgNCqIx=8e%Y})S7O+7pT$Z`= z9IFQ?&x2{{d?5ifFVez7AXp3&62e14ldi6FLXI3K^nDyMQ4opyX6A9pcuHT0zet~$O1!cG<=(#K=+awC>JIs1rAkMDIXcZ z@@}|i(%`vW6DGd5XT*q|$L3#f!Te*aNZNGynu|wNo8^na7A#-EJ{{52FeGM%DiqeJ zGt^q~1I$oss5fDT${QW5>VAf*qM4^Ey(TD%Q>F)`8iJx?s`8FrSn#ND9Qm*Ae#WY% z-&M!|4qT&{y_k@pmBhW;&6vmjS+9D8VpaIH;Z>g@Ua6HfZp1jZN*X1e(B6*KcxKqM zK7y)_^1BkM8to)tb$ zz3h=kF1z%RN7$H6)240QIBnV{?d|-;rI$S-|8m+UewN1I30-Hw$!g5J`n#;`M~Iaj!!Dy1-7PPB(2QVSiRA2vR7PxC=nW|jQ;N!_ zMdLMvUsoC1wV1bJS=;5|M5-m0?`5OqBYWi|lfazJz#}#oZ}*>Kcpe2UR&64~b3kEu z-iV-^|1iVzeud$AKLsxM`wY)mKE*OTLrTnaihGybcza!XD*I#S+M9klyRmt~%<0nA z;v=_RGj)pQmRT2#nb2U*ylndq7xkIwZx}Os;Z66C8ACOaBK8#bqed#i?9T4+h!)ii zxp`~MR4$kh947qA6-a%~7{E|!0i`b#o(SXsuVuI8@ToRfT1ul@nGiS=DlIE5Ys*pD zodcZR*`0$CO<{L-TLbRX!Tfv<+sbzn3M*f@4H{ltNM?6NO$EXK3mtKZaNC(+sT=Ih znRc6^iHT=--cO4zr8f{8c9`8+rJ;c!r21%u$1k{=V72P;OrLZ9oLMu@t2?i}T=RoL^^+%U+jGg1`9mG%i~(ydxpC(WGsd1ba?IGJ z9uMmEOU;ww^*nyYaHS_j>^a}iZbZ{W1#1&$fq(;Lu-mKHmxtewKUc$MFky#0h2w{^ zg@^eQga`&PYDwW3L_~~JFo;o0ih_E{29m>wEgkqF@Tat;TM*bej308QW8w&9XJr$n zFi2n-1tXMZQZPcKl#0a&2^=G2GJrUcV}w%uDL@HDF+xEn5~7z8!TnUF7ZT#fM?U`` zU`}WCYu0Q!*#6M^SC-Uev;*w3a`)~Nd&KEqy|n0Bu`W~gh<_CSNNu)QzDN2Jektj~ zUzEB9fq^m$N5w=9Z?ndLhL508F;Ve3Mx5+`;W#Knj)KN+#72sCZJk&T4{o?v>8;_( z_{P<&%}De=R)VEFfGc-|5Z?uSy(x&qu5p6`pVkyT<5Fh zCO>th+6KPyYLKG z-TF8h1wkr-Wl_N)Ciki#jXnXXWarSmv zPgh|*{kZn`TsM@*prJ3D&H=zmKBL-@crSZIvQYCGiH6>WS9DDEtI&ZR@b5cSkh|@L z!5kA7))WB2NYJNWP(L_;WbRM&uL!w}c`CJK9Qm}_4n0*^Nu@KYiYTjHXSW&$VT(~V zMHsGhcBce}tJt^(5r!)v+bMzJDpt9rD!!~{=)R2g*pYHeT?dm<1}=ngjus>-uuZo; z@W5@f&6q!b25s`oVsqzxQho65d)nIWxjVSzqSb3IzIe^*i%u^<+wOjK8X3}~!;YeY zwx}w@=&-}x3qw*Pyx{6XrbZs970XXap?9X$sfj|y0sG)j!Fl>_lmuFrDl1f)0bp3E z(K;O3;_$(59Gd!*~M_<;5Hq(|ON4rMu(%U;Bn$W&Rm(!8hNAMgQbVfAlL#Bbor_eBhz!6-uE3a$ zGXmxlSwc_?>TwJVeq*N9YStoTofal<4NWTuya`B4o5Uc|ZUo#I6pIB2qzZRnU?p`r ztwsZkG5upfo!NRCgU9fojyRdy{2ICu?7ZOO!egu0UF`aP{Vuy~>mN;$Zb-c-bpCnebI+}0L*<`ay1InDU8i*> zwCF zR`t#PcfA5FOho1Z`rtcRul#o${LdQ)XQH=UtoD}AcyHMzOya%eI_VSMTSVb8d4Z-@ zGXPRsfpBkvbROmCj^{6na&&Y4GN9Utqr0Ha2+_s=^&H(Mu$<+Q5j6kwSp=j`;OMsH z1L^a3IJvb%DM~Si6g?Ic9lk0j?8Y!0XFBa@?&6}|JI#mmfB981CwEu3l-!ynzrc(j zKZlx`$qFF9c zPDr%mWO;)*N<1N~T|gq^pApOgh#70YHIdgvWUr7zFR zccU99gl=FS=?2c3<6Ut%&USf&*$FvzCFd9ss?{9JuOP>z$gx2vRa%j*qC#jhXq)O^ zkA^TstXc+!b?fWL@t*`%J5eJdb8~)n&(^K?{A>J4#uEXeZ)3lj2} zmz+m;wmY212O+`DXIj{NJ(Nc%f(2yKPe@TfMx9nfb^u%y_%CFwI2JBi6^rYVAIzNF z>~1N}ZOSRENLi3QcY0<^FHe)Bu#YkG!i70Dv#p|6cpojtl7^%h#!oQ94i?2#A_iajGptCxB$aVFnJO-R{tt9f+?1 z)k=nBeYf4}FgodbJi1|v)r|lD7Yj!{SD<&da7-P)V#RpcdJh@Wo3?4n*YPVRD&Kn# ziMEK1j{1M zP*;{KtF71!TxFh%w0MM-^Yu1kElW!bC_P#`diFFI`*aE&eW<6Vr-t9(QQA}L4F#IQ zMjz$fJghic!Sh3>#fL-MQlVf7`izLBOTo)ijd1hO7{Man6Mw)Ykz*-@8VHyghuh)I zbGr+Td^v?+xilw%G!q{JH3=1My~{)_px~#81Z}XAfzpJN1ZO|WK$uGbd%%0vL@lgM>l`a00v&?`PL=Qw*OCq7eZy1{(4l*fL*2JfebxRQ)mQ#E*L-0F zXqKxuLptDz0{znqw~GHm2e=jhw(?^>KsJD9+d95h@XkiO^UUgmc;TK5Fj@UXx|vnq+yAnv_6I;SHJ+a+!kFdQ^7c<%XB3 z&ZyMnV=&Z>k4te^T#Bh?Z!k3>MRRhBDW()P#ja10;%GHRk-zO5Sbj_%Z5A&`s>8Zj zMZU2lr)W*JhVw|UV~?I{vJ7i+l9=`|H&Rq;QZjsP9>X=6VpVd9euICUCmzsjHki+f zETVpc?LCg8JFI?#?OkPrRHA#C!1`hXPdo@gOyG&PflUD8o&;(PK=u5R4j&prLUaTI z0uZlhD1v1!eM_FTfSGhmX9M#y*J-xAD5 zYnXu^eVrJF%k(4>^-He0$9QBsXNtSxQtY;`C#Q(<=-esZ5SL=N<56;o7?0vpq2y%_GkFi?DGGUPur^pMJvi~x5XE{^ zyFSMacBhuw@ls?#-pOGFO4qWa?U=SR+>h&78iyKOqv#JvG zvDH3SfWW4;B@$tIGvT@c3$Wlx2d69;Hd%?3C*Qu~RWQgdk{8Lp{?Q@-!w)jfG27!9 zjvpqPSt6KiWw){g+r>NNOKu`w+28N~YIFOe1CG7G8j1HlbY#F2zmOjz+F9*v;+uVM zKReE@xsjv}&K}2md2P6ti|rcDrg#P7$lt_!Oy6hD*JNr>OKvqx7|T49}HViG|Z7jYS==$$@H3?h+r0)T9Om zcrR?v@iV#;K{^s@((bTZZKz4iz5z&tWO2`c9;r>~QyJkt<%!I`8N5%W1~Pb`f*wg- ze{f4_NU8(P0m2XGfL8lZhe4;;OLj$uCp$vFOY#Tt0G42JM5YN!$(axs^DTnUfw5N-@0o-M|ba15kk#T;0SX$}lxz(^?*UTwd? zf)@6Z=RW)FIeGAc7U|LhyX6gR$L?|Cv`_w(o%zv|A2E5GRB-XNvM{UxW8QUL?`Xb< zDAxUj=assM;1B8|7Hz_h2-Wdf*r8Va=ne`Wzb%3x6APpQF& zz65Iuz}xG}w4OL(E%%lCd?}e!TjbEoYXza8DEexMB4(fhQ00CN9QQQ*w*(~(nh~SM zZ!Gj@6yl?#-`8*Mix0o2Zz0kz?F)TehBe^g?j4G^4xtPBYT(&HE{GJTjzBUsVWl(0 z_R+y|4ZU-%f(U?b41N3%>Aj=M9 zq(l7f^mfx@^mfTP?ug5A;|OoCF(Jnzl5;$4_%Joc{{p>TavqPw<*{j$H`tVr$5F|7 z9NjoNoX2~?@jer4gnv?RcQ5pIc`YTbCYP$WbGE8_yX>&OF1)ANMk&YBF|FfhTscNe z_6A2Jlw)#oIfhM8>-yiLw^MR`e@w0)=ebs9i)`U*TS!=f8#X$e@2=ThuL!R&9<@{W z57ygdo>Om^lc={V?N)Ec>sDuqsoP_5bvqj4#pr|<5jS3h>vqK05lY*ZsFmrSMHIb3 z!g!%s+^EbJ2qvsZqZcT%Mb~?6K0b4%1blqvoT&uR>w3P8OUS_@;PV7TX?J0-$G#NN zhT7Xau2IBzQUr077&9_m7|8{o_o|8Use z8|zF{-3LDdHCBVa568GQ21|Q`8mkmvRBEhxI@Gjz>UtAJMjiRo;1JKkVZ^5<=1iM^ zYBSwAwHb6B6a39Q**2lsjNbqzXXf9D)x%6N=7TmfZllx0>Y?03KcYNBA{Z{**(Ox` zAY7kmuk6z&#mD83z>w2{!N>i^G=HBoeE8%zBdy|is6fl_s0;Y4fx6Sd{{1;TwSOJK zQ^D5-6zYVDj|w-nrKY5S6@((Fu>fcb5P;C>hYz889qyyL z9F7vevnOo`eTnhx88Ub{dG-wP52oCMRAk}|LIzIsPoVFi<{1h>FJcpzoKzQ1Ke0nm zTFQwaF^nj{eZYe=YcZ$Wl9)Xr3|p$Xjpp=tzaf@Py;U4T2U78)7GIWl?K?m31RaQe z%!K_5Z%uFWeRTA#%L_7#YH#?({*DLk{$sC_e9u)1N!PF059>x8xNO6M3$C9x+@TRg z@iRli=$-q=)mk*;rh0lwcMx&NUCncdIOK++(waV-@85mn!x?UUilMSNRUz%_oN|>r z)oGj71dgu$qs-Yk?}A`t)p^@6J^#PcvksQ4I0uyvjgS86h2x@?4loCC_8cyuAn*v+ zlZC|dA`*&D@D+Q5zJw8{IC+I%(xW7-Ge}OcBQC`fSfff3QtXkOVzICI+$kQ3OR+b! z5WN#p>_!VwR#Fz9BF$mpQa{d9RJ9Po*XA)i&K8#`xr9Ux)DPQ)7){17jx%B%`IeFD zRVD`xuvFu7f8$8?KcPtV#Jzxb%Qe57`MZ54{B9XI6;n5g;H(z|^|)%-rr+(=P*x0>!Xzp*KX zSFN1hbWV$4x7T=& zBG@c^E$T4|)LGATIINZ|KBi)NP#B;{pQA(*&y}Fh3FW&49pcf1oR(bfRT#7Z@`|8a zxz?>AgRwaGEP_EGIA*5BnP$m!TAbHf2U!PgO*?t=NLHr9X|+)5%IApHoaM-sa7!9J zopXL_y#fyno=L;2PYX>9z|C9_lS!HwrqIfhV~<`Z4tNW}!lf4u0(pR>xF&TE`C?cxa=`qzxBu3vfHirFjA z$REis$cM!qhkx~}!-rp8zMMuR;H|(aLsIbswbdRK>mn^8)m_-f8!Sxd?R@}oj;@)w zy`rFZfhAwj!O+_)<85qWxF5u%_>bsrlT+-7OYv*9mvMt7T>;*q!%zrF5ONs;O? zT@!vw2LEiM1)+2}A#BhH zerP8*`_E9dGK%9GfwRNlekdZuX#*xs9Dq%(=Kfqd_3Ixe4y2=j6WRQI;^y!dtjz1W zUeYvaW}aLBtFjOz>3`9~C{C=Z|AnNT;ph5ag^l1F>wlH;;y+3M3oTD2d2d2n&h@{( zY5}o(NdHT^pLAj;$Yix8V#BW|ZQFIILjL09)tA*@yIcfU!E@JKQh)6#qAR$+oauiv ziT&pD7WU>7*Uvrs=4HF9Zn@2_ucS$eWg{j5Nt9c8IYl;?^XKa8YuKo)*@Z>dlfm)Ltq7bRcbaSpd z*;?<0?lhq$VI9k{DB51mEdgzBCire=E2Bch)*9uzRa_lXRab{|^4+?L?=~yKcN>yw zoCy0E)EdAwXGOmj`&qzC_o5! z2AV&ofH@VGR2TRqoMCN~?xFmiFj|2GOqrqbVX zC2S(SM04|oCz9DEKy3E=2fAgKKo3*e1+}$syLgYcsz+>zs*+hQ2%H?6z$nSj2nkpv6*fokz{iivZ__(TF7pR*WiG%>n}`N3NiK7K zQ9ds-a`=1XkZd(!#PYYx;kcw6CfDIdadr4DbBHp-cS+mI-*bujRz47SM&7eFHP@Rw zZ+j6LCOU5`qhf)}kjCfjvvSuvLOWXae>t@qAu$9T!>3bprT;@tZTaPI&8f}0Fvkkl zvsZ!nZAy^6(j(dqMfTFDvX?EQ?cni*LgExlT|IbQvD#um_~R28U#h99f-9^ZhFs`) zYby&YX3uWAXn-?ax`1t1@cp|sU?Bvg1!v&Og8X&5^^~MOaEo<&eT+!i(67)0XdS9X3k7a1Nd4A@~mkSY-Fnm*apo2 zTn$2h3g;q=C79O55=`?@Z7RWZ&;sNZgnk<^+gS*;R0#pYJlvNMz+qrM&Rd?>o3o}S(u)$ZX zSaHQyeJ(SD!|bV-o>4f=(9a3e^D&poed_%4n>Yk@PHwVaQ*JVXI?t6CMo=r(2a>PD zn*BH8Yz4(WZ?HH)a`7cwA9|GZP|<~5_h1b=OZWrU8wI=#izE|9Vp71O$AePv04YAy z)2zoH`@@SQPw=wo`ynUcvV9s?wr+KV$z==U%^?~7qd8IPj)$C`yUzJgGan$QO0#fGvDiznB;@6tE?g0HtKqw-94IUZr z@u0CL?Bnt2Kj)Dl9Kag}^bj@Ko1Ven@CJIr=;7CO-oiP~eZqO+YwTI|8j$yzv3x~Q zPS;S&yM(StEo%fzx;JP^sO9wJI!Uvp8CAcX>rl(NJjHRyg_7cj(GJP_RwGsMm-yf?HLj>2y_^&SdU1#TJlGQcy@}GQe*xkbx*q>EttqcwC77glb#X zZkC{wfaGI6ei4O`B1x*H&(1dR|zT0%OsBo&>?+DwR@a^i$PB{j{W70nXbn02cn zBppfBYSM5@vg$R!c@G+dIIysfz(oxlN`zmnOxM@cDnxm;4n6s+!8z@zr=D8S@<0D0 zejq-%Y~wOgm(*qPl2>{t3#RF0?BnK?DPDi*UD-4Fq#&8W{hy>DqK9 zqkyxgrKg3X;|oCpWIg!K22;@;m$jQj(LnLB)DmkEl^OCGO3dR?0+Wh(lz{Q4QEFgM zNKF$J%zH|TIZeY%qBcD}Qs@+oWX35mQfTnMr`zmlS=zE0RS5+yEZh+YG&j>Gb}ZPi zK-|;$3+&GRp5DLWaY8d&A9~-^?&Ca8y2Vg;<8hJ`@i@7L+d;|JK0!?}*2b9X_7r-9 zo`jxM*o__38?l2@pDyEVl;@GR`zzG8eNE>r(#L$(=1-$*>{rot4{w^-vV9O&ww!`w zDXk#6Y}xMYus2O|**=P~cBZ<$m}3(?=XxZU%~RqD+jzNu4j!o@@Bly^scM}2oJ_n)*>BYu9@>-tBv??K`j zD9Fm&D+#Y=2MKP3PA1!JiR#l+!cmliBmM{6rW?v{(vbgie!eRoUVl!Qq!tPJ7|YxB z8jS{L%&Fx6tRZJUyIqq{3tA#Jg8#GKYPYuKYXFdR*wd^uumua@AOt!FtVK$NLqVa> zQOpyCv^HjsVbZ=`C?N-Tn;w`<@>w=J&1nv&(^bM($=qkT)^D!Ghl35PYk}6!*TA#@O&`KtTb-H5F)|D_iX$wB$&@}J~acjwhqSBO3PEX}(aZ4U2TUyBi}Oz4l8 z?>m(@6d{U6%y-r5t`J3=RHA6ad{?dR3Lky3igV4w9=!C_$rS6mP>fC%EQMI!-tNik z>nc_;ui1HsAX+*E_||rhu~#lBCjf<|knqbw7E7^;Z?z1w3~MVUd~4mXG@>&HzIDhj z0+kLK2DE6Me;5Z&wh6;1a$_jXZ{gnwRB9pGr(lK!x6x?=l`1#Uk2t6_*rSIM7Edw! zTYFGWD_mznH8mz;iv~-P)n8-9hrj9uD{!S=t+fW1>W+e&=cYEZ$)uo18JtQ3*-`fD z>m(0511^_pTim~Xots-1O1uC8KtxQ**w!gfASMS#cWFLh0vd*^Q-DB zoCE) zuFT9R-1g=h@+a4Adt>K)_wC$y-{i^CQGhzH-!*kunr7UA+xn1ceDjGXRYx=0A*=6^BJ#NoqKnQKZ?kllDALalFL@rzv|p&`-sJst#5yCux~<& z{gca9*{_n94U&6D*IMBsHs(9l|N9d43k{KF{O_a7c&fj=&i$Hac-!trwT5+kFY$c2 z2aaHyK;EwZ*XJ#2n@G+Z=YRJJ)6~3`vtg7s$~RVe&+vB3^Nm%&2jZH@xM4_lAnK7L z;Z3+ecOKRB@OGP#onaxbN2I6&+x+jf$I+6eb$viJA$%e>OVDND8uu;bGH)&A1W)@- zoF{0vn1*CeP*=7q?6s-jmq_LfV}ss^LmPFw=14{x6?u!oXd|9SJw>7k=W%bGZ)vxY zXkzmig8+%kCHImE=kiz_g2{*RCK0n9huaFLSyY;kPm+h#e6pOle0IBj>n@)$KCq}w zjhl}-YCa)_5*qBEL0a7nVfjUW&0?W6F-?ppbK0`f0H&eX`VX9;wav1iJ=Q zwZMTOK5knvD?EPuL@*y=9s)Thf_e%r&y=6dbp;A$1ak^0xtu~ImlJbd;WVn0L=mn^ zwV5QF+Ce>npxJO#0`Gwys~TeYgcm;)i+;zx%qi-);R1iI zs4tp4ZlWjcFHG`wu9DxE-z&INoBcFP7su_~`->L~?nMNOt&dOM3G`7J;`U#Txc!DO zn@@y-2oWVz>!?CO1o~ON&P<6|-#O*)*G0u+;i!15T?LtF-&Dimb@TKHmr(TS3jc;q z;=q;`1}fpcN& zKzkK~tz%2$&~=)p!tgrE!+V-vvOBc*p_Kn@O#C?eBQg8E2S&g9UPRy9uh}EobS54P z?+?mqI8xFmJA+bEqgv7^JA=Ye@E;dBPoW;`E^;25mgs`3*^}&pi+8hFt`^`u{L>TLOY}`Dc{(R! zd3PZwrE`X$)SuInUGuB33wwBvwg#z28pN4K{`HzaVj&^T=75OePoX2>noYd7)m^{W z+$%jNc!f)qnJS`VO<=JXR60i!D7C^bR?k5v`W%F%uzy*P6kR3qJu96G*s`=*)p9_Z-6qxR$D0X zNT0QKnlV;iaM#UjQu9xHyXBV)bUmEzdjGKU+CA%S{RTETd@s*#S~XQ{zjGPWYVLhV z{%L5z$c<~}u#9&**Do2}e4)6!9>N{0OYD!Dwc-`u!HC(YVyDwFVrtfYwM)EWkCMJY z_|DTe2%jTSO8*+^Y1XX$IYa?9s^qt|7XxbsbMcvg=Z;Ce?S5>j* zWlQI;tIx7a;xbL&6^9SpmODFjVEHWMVujSs8nnlvxrnrysMY%KBi{5=#Jc*kJQo@e z=0tLlU{xD^gRbmXTy(gdO_z<<&p zCca8-;t5t5tyVTEdK~+nQP{{UM`>%Mc5xmO%3F7+V|}!=4jL+sWKFTx z@i%{_`_ekNZANfuVoU4D^{2;|){&m3Ayu(b+N35^ocIQ7q6LgCY;1dq6c$YjWtCqP zXY!Wi5w<1FYu~V}{uI30f+pU?(8BOP=B@riFkQ9*j4hSPsx{S zEbNE!#Qk42X*y!^?NXVv82pQr2pv%$NC&qqnF9_k^C$Q~BDPgJ<=bG)ftOE^5kFOn5zGx}Iw2m@|%c_=_U4b%t*zNLyJ3BADO`gvV-X?BC$&1*J4a#isE-zKssI zJ&vjo&On`(A-skoiXC`iLa&HET^RvV)Da;1bRHSys9kV(uhnyDKb7QGW}3hrk@-cpNGde$kn%)7YX%6tv`6a7Yu~*}th?z0M93ukg?ugeQgV$Pjep z2J>==^ymlpY|Yx%Y6+M?QO-ym#7;cLFq%4+3WC60Xc)s>~b@HMxm9Q6q& zyz)wSWw~bvHh1`%r>Lx4xmJcF&*1X1B2W0*kfGxc%LTt1H*v_saYF}T8xp=Yw6STN za;*tRL+i&iH4Y75>pyT5-VJ^?s;Pg|sDVSUfpbhL!@wcKM=95a<7nXEQNxD}#I<;C zD(+yb*xX7AC050XV*?q*U5#5{#a|hB)v;q&UG?OXSB+n{Zv2FG>n3cIidUZfjd&pO zy!b}q8Oe6+N;(J2aQY?Fre1Q%)M=M|`MCDSUk=GlzR>we@;Qtn?ZO-EZ=AiknR;?O zcXL#Ap(swIB*h6IN>uLV7}93eF2H|?Sl<-pz%VN_`&$AV^Eq-55h$WLP==E*z#~C< zqVjW54pd?;#*YQE8S@c0%)Hf}z_^7`@c)o$>%Z(R|6%McXs<%oYnmp^E0yeaW$ug2 zynQ2ci8AwIR^>8BRb(zvXje7k5znNz5IPeCXyrsOqd&gp35U)EeGnyDLp={d&ao)FW$+KeFe5BCt^;>zwEP^+vmkhn>QV+k+p9&67iYrB* z88Z;6%4()dbfJ*{iY`Qc*WE?E-t({fL&qoX zlL3$?V2>})=HZ(`{FO=d+ z&8Bf1kp?&_moQZjHwd6hY!CvTi_(fXv_ag*VFn6*6nI^K$ZC_cV_LRvAJejPQbU^| zkJcjXS_$5))?w2JxlYVb)*D*ZX3libHLK04v&CO)%dt_6pd+c-DSlUWjv>c-^3@z< zN8wy23(}Id6hm&A@;wF1h9zyT-0=4-bX|~On8V*w;f21WEjuf>3`UbIaOyd-M+4R| zdS0MlK|wIvwY`6#YAFFLJI4vzD-qKj?n6pQ*Gh(Xx0UjbM~_*%?&A;Ft{Xi@{-U;4 z{z6M3j)G~ z>8$}LXw;cAy#}o7@QV=OXQFvjyA8eY0{&(p=Blfx=!j;fRg?f|GcB)75O%`4KReg` zS>Z+;%GT$DAN zWXUYAd}RCfhiiLe&1Cyc+Z&|8C#NiZx#`8PG_w5c_|waWoSe+g-)utQ@k!-l_AoZ% z?iV$hpWi)Be*3EPmB7T%cdMOt_!bHs`Ru(D0;&A71 zLHCJZ6Q|lNMhD89gr=gvy|o1AqUtF0iW6C8Tc3IT9ZgenhuZUc_83%?SMa?t04U0DytC)nlhggn zZy7gk+0E>V57~+W?~`xWmDc;_*A1B_{}i8{a><7mtv$$EIxoCX4pNDWVbw0xuELR4 zXi-WWiTw^#tg4mgvEN~$RNuHhQexF$R9D}w)i4Sj@%nMlih@9)og73&^qs*73Lnxk zjaYH2;uHRQqh$%@kWjPNbdSaAXcI(1s9 zd*-q0(d7#19blS6S7Udwk7T!IPWg!Re!;ut6>P0MSTt?FyU{sfgZ#8KLTZ<9O!Mv9 z(3#t5T6jfIhg^gAw3a=p86b|sx_^Z7o+9J_x3Mv<4@x45GE~XX@2r(hp6xG=+l%!7 z9gNrg$DKCas%fA9UaDCFEedl9H|u^a{SID| zg+PR?NXSi}gxsja+$L5T$&CWMl^hs%dt0D%!rKn{j2?*}l)5DcO|2|cWXi(mV?7lr z1)~a`qV7mx!ZGmBUm{tC1y&h;l&Bme9qF_*@aXhB=m~Ru@W4gE^T*sj`_`ZQ_{JrN zs+Qh$*$@7-YJ1Cy2b$_{Ub^m}=C_;XPq}1J&+BK*UoX~${m~bK@OrT5nx3Z&T~WmgQ?{jQEq>N6T~`p_g!NLZ63+vpW7LeI9BbKH-!{3hv|+ zj=dB#*x4Stlv2uPm{aUXkuTS2w(3w^-uREV6_|BgaP^V297JSU2(tybgnnq-qMRdN zVI|TkuM&q|=fq?LxV29N{93IX!q?I$Y`57kTcNhZKh>5L_BFCJQ*~i>QG>~|dT+zb zii*-wt7tKwr)%t&>&aX+VdQ-IsnWq!MT3lH7P$6D?DWm-A+~?YplZx;DMJh<`73#! z{BGygA6|Ij6pYI3pzyx#25BBd-YQ{MLakIM)JoW1Sre%h9?{KjD#Qf5dJkaJ< zaMC=`=7Bnog?#25ZX=-g&)A7W9jrS!z4pn?jkot6bVIM= zK7ob#d&b^;@}HP_Lr=ZGqHdD1D2iu=0m(e2b6!l?L& z(i0-{QFK&P<|EY^%EY3>A~&D}Q$P_UOsMz6T}i7mr5g0c6e8hPCIP?2j>ZpSWs642 z&}HZ(igOp4AXtZ8&?DdpO&Py9*(U-#p%yC9QYQWb#XwYGsB`wvCn8ExT zYEsMK>}|&efe2k+qVCW3vmx@2SjU;pITC!h@0Fis{pG1=#C>N!m47^ot>4Nrwz5_7 z_qNJsw#qx{&EF*mx|=jFLxN2a)+%ovB09Bu1B;GJDO`_j45aY>5FM5j%z-|o;#4~m zBuxs;s}(2PMXin-g6itp3UpdRpzGi$h9%n!)*0-rku^!pr&dI!X0NfNo$Zk-ntmGOgOw zOe{6hnSlBNm5fjayMUyDfO87VDva_NV~k+u)@uYUtO2KJL#72}`Uv!3R%R8fs9>sN zs?{onnSlO@wv}v;ynLm+oc&C`hs|QMw7Wa|ch-r|imjcub>1p2!tD2+u9e-P?}ynn z5vvfLU6m10R7b=pf`@0fd*6B$+oJFHBA!vMn<(C=U;J;z@aQJSVtBxzCSI@m8Or&c zBb9VN15yd73f)9$kbVuG@PC1-&`k_GRAHX`|A>kaX3ABf4fW&-OQ5Q7VPH|4nZhfq z3z+y=6SbLfq}sQoJ}mw_)Q9ZaZ_a&)Jnz?jF52{~|BKF2++)ElT<&%?A8g-wiJhq1?VCgq!*Z30fUN+6>0090VNd zA^eY0qKL-6XG9iIH1-}=GJswC0 zDmz$Oe3WGgE82WMTx1nUi3E|bCJ`L$mBbL0>F{Cra8y<~>`Gt)P-;nNg{-x?dC#7m zJI9Z#?jL%HLgI^$J}TXMc9C@J&4)K#DBUd$8*=5%XBSbReC?B`Xs)H&-K5s;PZH|3 z_#Aaxa_+jN+T-;bO0~Lc>f@@oLqJ7RC6m+|%+06p1rjoQze%U~1iT}30|F*xR?)z_Re>BDl@NCl5 zn_j4zV;S_RkZQmQK?oLJJ~zBS`=`!Z3<4x(^e}!uUBK`3%jKbh!H_RMB0qv(QA#oY z*cIaK%2%-tLqVPJsQ4>kw`QGChpj=MCrr>z6PnppVYB$4umjr&3FkBq3lnf}8@@O5 zeO=d^xPL6R7qHb}8-c9~TLZRn*ytMVrz!UfZAfE2rNj5@gms2|)*H{t!*+}IS)m!* zeK-zi-Vp-2I$=J(AH;7T(+EN#&L2Qp2Xqe#dvX2%u2Vkgz6to=j^h^mE)U0dNUCit-B;d}+sxk5yqv9FV!>UtMx2`Eb*_G7SZ!ZQYAKMLC<+(YLlVY`MsD_qB( z?Rp#6u@|nx^RJ=v*y!F(v`0DzalJwP-3}aEk&is=Gu5pghMs9+hVT^aQT|JDFFpS+ z`2AvRjo7IEb#xE*({XK*Ae{Y^AjlK7?{&Q^{!OUF`DdyAa1Bsse(eaq_MngEapwj-F-HJb+7JCwcrin@PL-FK?j>u8TQXT@(mMIAKbdmwhhJ9r=Yc?|ncv3KDf0ULjx z^e$sJDv$bp@5VjRO=&aKP7p0geh%dvgS;J5_VO$0{$6$8sa~H=d$e!dD}RdjLhqa2 zab!b&exl}&_B?;MPVYJVzUer+QCoh8zqcJYAKmD^D{U$h&pN5pjeHX4=-DUK?| zJ?e43df!<(#(lTbca-xF*j`839oSN_J%-;Lz%#GI^#j!AWA|tm&*Qs*K0*1TK6y>z zp57VGk3!x*q+{%VN8iyd#-Lx0!u{gw)e2@$F^8}usC`Q4kMA!1XX2l*KZtD~w!3K4+$3CvbSa;dU&{9YY{)O~-;{Th ziRXQia?J1f5@o0HD6%0lu>Rw76L4fdkcMkkXysRR?GAuDX zW*lxjoAN?x$aII;|6}Z>GO)yT*P;#(GDtOLQ^e88~*#|Bmn8a23h@C`$@4tcTuhxMQNw+t;BI;-KrhF=b|4jVe`r;QsLpJ+TY ze8BLBMpTb@dt~~^U84#|O&t{)tsVXBn4&TB$Fw(H-*iXQpT}M_cISEh$EA-e9Cv8k z)8jrK?;byL{Oa+yjz2xVb3(<0857=^sGs*edS|j}a?Rw~lebNo zHRakVKb-RFR5rDA>XfMmrfr^f_q3l)`|J7c^GBZl^XXSlziawWr++!4aK_jf8)gJ% zyw;rBT+@8C`JI^uX1+V~FSA^;8fUGTwQttjvyHR+&c0ywHFE~eX_<5VoWpb8nroQb zckY3CtLNQ1@5l2#n(vrDWPxWv(}INyb}x8v!OIIeTS{6cv}|s9q~-CJPg*)#OIpXb zZfd==^yVShYwY2BbNlPzYdhgQbmzkHj zmd#kUXxREB3DV(TYE;_}fa&%HAud zt-O5Yp_L!6%33vR)z;PLueo&1eQRD=^TwKw)@H07ymsN*-D_`O`_S6cYdhBsUe~m4 z$GThB{dnCk)_t+wyMFBYjqC4R|I_uau77`nbwk~T`5Sg@Xy5S0M%~6IHh#5fz@}xJ z9@+HPg%@A=^k&EA3pT%ek#tejMH??VdeIjbufF*GOPVh^d}-CCt1mrq`T3XMa`|gp zGPnHcO5K&quNr*SjH_O~dg9f$Tw}Rr`85Zw`T4c>Yj50|yLJDz>}@Ny{rEc9b?05T z`?}-Xb=xOw|G|ziJFeUD+D^~TxjXmneD?Z{yY#yb?;c5#5xW9h4SGbD(qL6YqfQgX zRYBZ{6#&Iv?kDbw$WP=+uEhNr6u(#Q(cm8PZl!-(j9oXY$2y#E zL+VUJPcR9OtH&C_COpfJwK#9(IBllUA~QDO1Abn|@Bd0Y#(8+PQ#yLOpJl7ZbiOA) zhV?_($jG;pY2X}#^MK&+V^K(BKT(e*;Y#+RdW_$SlhtD_#+6p}Scmg>@M9pl1(T?x z16u^nALHj!aXw9aK|QAPZ}4LizyA~Un9eKtPowjanV*N_i(r$K{97p?#~D1GRq8RFznC8*KCWPuu2+xg{O$bM$?yN6dQ9gZ=f~MNpC&!8 z9@F{X@Z&sw{~y(3I{yVf&c}I!CRIJgd5xVP_on+b#p*GgucTuGf39YjdQ9iX)3J%y zr)HjdOy^hdV_t8X%hh8#zhl^{)tlEYS+sb4L5~GJ3o7gC`u47?Eg03hX?g4V^}Q#| zTd-{2+LrQyq05&S@Y~iEtZiM_x^`o0OZlkQRzkUt@legb!@|& zwz|f;;e}<5NBT}0II6KuXD9_KX^ubrmX^J(hg$AyeYE9p>&cd9S`F*`+EFc^wTSEe zdS~k`E$yw+hQQF-ev7_UzfiwOe@GwF->AP`zb;^$J?AKN%q_zk9>e&wL|8d|J3fyJ zi-$i3jqGyf;@=;~B;O+R!flNW!9F!*)5~0*83YB#37%>Fp{0*5J-Jj`=Pw@FI&$I2 zMI#T542@i{uyx_Wg^Ly*S{PdRz{2)L3${M6wf+7F?r*mtU;CEtJGk#AX~P^Sf`>0D zoL{hg!S?M7pa*8I?SYXSmoyeGX+*@t#exmt^_K9zEBN1)_#1?0;^cq2Ba;x1oz2dfYH_BMc9h2si1vVQoY?EPA zFR?GP@4$SU5wtus#RK>|VA{<_?YL{NxyC%j-s>6nokx)LhV8g@CQIwTIsdo5+g6*897g}&Zgyj? zPP>tGOZUI0EI%e~#LINslx*Pt)E_fx4ya#cTMOy`|*Ds)puCKvA&oeM)%szZr9iQAN%juf5c~|>#wQnndy24x}JfqXQ1mD=z0dao`J4spz9gv zdIq|lfv#tu>lx^J2D+Ysu4ka@8Tjw^40QcDYS%OW-|d<2`t^1_^IgwC*E7)d4E&$Z zK)nxiy%YSOUze_DtBEW{jbq~hv%s4Ip}&0{{EbIJq!Oj&%%Gj?`7@yuh{eV=d(-y zIiAn|{kiCRM*i2|x2~_p|N8al`un=;>(TWLbUg!I&p_8R(De*-Jp*0OK-V+y&+-g( zz03c;rF%cukl~=->d%qtp8oRexLs}f1kU4U%P%^ zyPkorXQ1mD=z0dao`J4spz9gvdItU@pMn4C|NQV@z3*>dEB+^z{Jc?q`fD;P@H0uf zt?)m8Zs;xFF>~qrv2NO zq3^_L_}Ucpb66X`W<`DV8or)IebpPjrbT__8-6E>`Wa6(sJF9dyi8?!e zcJk6WBymWDix&(d+^3o+G>QeZn$V-=&sLSA&Auk;uQJ2LpOI|uq z_<6|aauRiU{PN6{t{_oY#IHzRx{^d)8NV`l=_(R+5PlGO>8cWSHT-JirK?NS!T7=C zrE3U3EgM}^qOOHsi<#23g&#tVt|L*`#jndu>3R}%2!058>G~3N1N;W$r5j4rq4=TX zr5j1qVfbO>r5j7s;rQX?rJG395%>}0rJG9Bk@%71rJG6A&GDO)mu?|Zx5RHrUb>Y; z9fco7Ub?kJ-3Gr6dFi$ibvyiaVO?Hu}yW)2x zFWpU|?vCdtpF@*9B7`~l>p z2TIg~@CT8X9xPE0!5>0idZEROf2z>qY_R=FI>QVTk$V-owsK?-sAul~v zq8^7oj=c1EiFyM51oF}oCF)7|lgLX?mZ+!TPa!WoRid7TKaITfbcuQf{tWWcGbQR- z__N4M&z7j?;Ljm1Jy)Whhd+Q(rw$V;!5sMp}HAuqjFqF#r;j=c1GiFyP62J+GyCF)K1o5)LV zmZ-PjZy_(eRifU8zm2@~c8Pii{toieJ0ctOCOe~kKi96FMU*^K8Amcy!3I2`UL(7^3o?I>Qnfq$V;D=sL$Y^ zAuoMaqCSUzj=c1FiTVQm1@h7tCF)D~m&i+BmZ-1bUm-7jRieIze~rBKb&2{0{tfcd zHzn#@__xSQ-(hnu-NBED(OFx#VpWr_sFa1=a zeun>yy!3O4`UUR0%$$V&q`i8n?#)*KRbEp91?X-{G8;ab4k>>@pF@x&LdIh#m`G# z+Fzp1ho6tUbbg7t0Db}T(gh{zLimNqOBa@?i{KX_FI`lkE{0!>ymWDix&(d+^3o+G z>QeZn$V-=&sLSA&Auk;uQJ2LpOI|uqqArJDj=XeviMj%Q1@h7rCF)A}mB>q1mZ+=X zS0OJQBvDtzuS#CJnnYb4zdCv8V2Qd0ehu={H6`j=__fGO*OsX3;MXB9U00&6hhLAp zbcjS+9(0f-5k&RKQ!I8kf>YYdH;u|+g1{F6rT5gXu54JQMbYK{tr#JZ6)e< zc;5e^>9)N@-2u=0KQ!HTl&Cx5cOoy{S)%TO--Wz%SBbhCemC;c-6iTC_&vx=_mrr6 z;rAjh-CLrL#*Zd1-AAJCi{F>LbU%r@KYoAm(gP&wf%pT-OAnH$2jdSWFFiz}9*RGd zy!0@MdN}@Y^3o$D>XG;($xDxts7K?ECNDikq8^Jsmb~;hiF!Q#c=FN{BLjT{&e!vGbHMn_%q2%&yuKT4}OD~eB7vnD`FTF&fUW&hzy!0}OdO7}b^3p3L>XrB_$xE-2s8{2! zCNI54qF#%?mb~;jiF!T$dh*g6Bf7Hi>#W{&w=x zJ0$9z_&doXY~<$xEM-s88dcCNF(PqCSg%mb~;iiTXVLdGgX1BX-O0$xFYI zs9)p1CNKR)qJE42mb~;kiTXYMd-BpBB=@|B|R<@MFl)u_95s;k)ri{-t9{)E0aTd1W|X@^AZ#CMXH_L8W*@x94Q$CjuKz9BCiN1~34AD6szJc&9!eth!M2_))- z_zB5NCz7ZW<0mFBokXHeil3CcbTWzB2j7RhbaIK>7vGn>bP9>u58scxbV`Xj6@Du6 z(y1ltH27)AOQ)5n)8VHhFP&bZ&VZkRymUs1Ium{-^3s_l>MZzK$V+FHsI%c`BQKp@ zqRxSzgS>Q3i8>d4F7nd3CF(r*dB{uWm8kvk{mDz`lc@9K=O-^+K%y>)Uy!_XA&I&$ zeqr*`MI`E?_(jP}7n7)q;}<6{T|%NRiC>bubSa6tG=6FF(q$y-0Q>;*(q$#;K>R@R z(&Z%T^7!S+OIMJnE8R|j}^3pXV z>YDg9$xGLgsB7cbCNEt_qOOZym%Ma6i8=&7guHZpiMj!P1M<=hCF)T8Q1a4^BYYweBBFWpC??u*}-ymUW_x<7t@^3nq&>VfzJ$x9ECs0ZT@ zCNDiiq8^Grl)UsXiF!ExaPrb4B9Pia(XS^fZZjI{tL>(laFLnfNowOV5(1XXDQ%FFi-1 zo{K-1y!1SYdOrSq^3n?=>V^0V$xAPis2AfeCNI52qF#!>l)UsZiF!Hya`MtEBi-iyDNy!1YadO!Yt^3n$+>VxWBCb$xA4lBi$fza}sJMxuU;|CYS;JBj)|{(JJ$A0+CJ_#eqjf0C#_<9{YE{Y9ew zivN|o^f!t6JN|d_(my2XpZGt?OaGFnWAJ0h(UwTmZuo9|n@{Oj614@-05mPF615HA zMqb)oqV~Y|ATRAHQQPtDQwlt$V;b|sMFx5AupX)qE3gOj=Xewi8=#*2J+GwCF)H0naE3LmZ-DfXCW`0 zRie&@pN+h9c8NL%eh%`|IVI{`__@eS=a#7R;O8MPomZmv$M+{Molm09kDs5sbODLF zAbvse(uE}I!uW;BOBa!-i{ck0FI`NcE{eBe7$xD}!r~~i= z$V-=%r~~l>$xD}$sLSJ*Cof$=qOOQvk-T&ziMld=W%ANhB|o*Ca1pOQNogUz@yi9f`UweqHj?^(5*L{1Ece^(E>C_zlQQHTdYm$V+#ZsC(e|ATQlhqV9#?i@bDii8>lTn!I!$iMlU-U-HuZB~#F; z%v5%UgwIXOnG&hGN%-8foG&rE0Dl29m0c*|bJKE> z#Oz}H#mrQ8iGV{PoOKc7ue^P0NiEvzzcYF;m&i5hP$Ol1#A_}sKS zEHQfo{|GacJu2aI)AE?a>~Z|#%vAP-gwIXOlM=J1@J}&Q+0zm}H!aUd%$~(R%S>g@ zN%-8fJTEbO0sjIsmAxq8bJOyY#O!7K%gj{viiFQi%c~Nz*YK|~Q`zehJ~u6INX*{E zzsXExZ%O#vw7e}bdk6mxGnKt7;d9gSp2X~Z{QJyQ_JM@YP0NQ8vybo}F;m&c5DdBU|@|DEwYy8*DRQ8R8&rQp>60`5{-!W6! z_YyugEk8)ie#HOCOl3bw_}sMoEHV29{|hsf{VL&e)AF0d?05X{%vAP=gwIXOpAxgb z@O=M|*%wcuOum9kJaJ8S#AokJ(K4nedg( zEa7w0I*Y_?R{X5YR5qK0&rR#>60Ol9*(_}sM4D>3Vj z@6SwS^GW#Jw9YRvTL8ZRGnFkU;d9fvki=|Z{KCvswupq!P3xlK_a?P2hUfc#JYO8Y zIKIx8ka)f%p7(#wn%1Qxo-d7Gn!L`Jk$64;KY+Z>mz8)v5I>N-&X<#TzC3<;@;YBZ z;`xer-v2pkT33>IzA~Qof6kiLRV1Dd!Ve;^^Hn9DuZHLSpR=ZQb&2PL@x1?Y*0io6 z@qA7En&fr9mc;Y5@x1?Y*0io8@qAr8@Bf@Nt?NlVAA%o3UgzseJl_D%`#)z*>xL4~ zhvJ8l*ZD>g&xhf8|L3e}-B{xJaQtxcI^RU%`3U?7@;cvC;`vDYNb)-0Oyc?G_|3`d zd<%)^TjF{D=d5YnO5*t_Jn#RUHLY7qJl_Vt4SAh!EAf0gJn#RUHLcrAJl_G&`#)z* z>y8r7cf#*PUgtYYJl_S+`#)z*>#h>dcf<4k&so#DyTtQ7@OzNg`JNKb_rml3&so#D zx5V?&_|fEbzK_K7eet~ibJn!(C-HoL{Ql&1et^XD1Mvrv*ZDyb&kx2QOkU@QNIX9j ze<*pKA13kqaQxxqb$*1z^CR&`lGpiB63>suA5C88$4ERs7Jn>xogXLh{CNEFEv~OhQ#wT@n@3P`B@Ur&&Hok zUgzgXJU%WXHDyE63=hP-%eiVcSt_$KOw0=MP9ce-Qs5d7VEb@%&-@!{l}Th{W?p@sE<%`C}5#AICpV zUgu9pJbx1ZBzc`bCGq@e{L|!h{*1))XYtRH*ZFf2&!5LXPhRIQNIZWL{~~#vza;Ve zW&F$Jb^eOP^H=e&lGpib63<`9zfNA~Z%90U6aOZ8oxdgV{B8W(Q~ zdlJvz$G=Zr=O0Ks{}BHnd7XbG@%&@_$K-YXiNy0y@t=~{`DYT(KgWMgUguv(JpU5^ zC3&5HCGq@g{MY1l{*A=*Z}H!f*ZFr6&%eiiPhRIgNId@$|08*w|0MDJXZ+9Pb^eRQ z^I!45lGpif63>6f|4v@#e@Hz46aOc9o&P2Ad<=dJIp=MW)OlMs31>~)SQ5`$@GXhw zt$6+eg6C~`1~_Zlx=T1~+ImPhYub8BJa5Oh^WQu0>uT$eINOQuq^D+kNtkQedP|%g z8_)OuGuN~=5@*N3^ZozMj*A}`U$f&$oE;xOK6%YfAYra)n^5BHM0mdcpSh-OVu`bp z;CcUdc2fML_?n$e;%py$AM%==T*6$_)>q=}6nNhMnQPkmNt~S$KP7q1P9@@gkn5o%mCC*NVpN_m{rh46g;zq1SD7sl7@A`)j8#V<-;vx`ZXYuXl*`+1SHEqjCoE?B4z)a09D{*!pejs_xE+=8GX{r}Fc zjb9sIv+GElT^GMDdCjgTVXkQ#B5`(oJm3G%T+_CJ#Muq;8}L4Q$ZK|U33E-`77}N-#Ba$=&2A-e zb`*XTdChJuVXkT0M&j(Y_-&b~+3h6GZjaxdyk>WhFxRy0C~d#GgoBvnNTIYuZkhIC~2I z6lQAnREe{v;ZGy4+0!M=HEm}|oIMkNCNnjAmc-e!@n@6Q>^TzVnznN#&Yp)qkC~c1 zU*hZq_zTEu_Cg7BP1{8hXD`NI%uLN*B60Ro{H5eIdzpl}rtNZxvsd7+V5VlTlsJ18 z{wngCy;{Ot({_!-*=zCFGE=kHNu0eNe?584-XLMFX}eM4>`i$7{GYj|?PiIyx8QFf zui0BA%r$MdNu0eMe>*cZdxyl?JMnjt*X&&q=9;#eqlDgMDlDgNuo22e_A4|fW zrhAK|?sadKc&`oLmUyo_p3r+e@ICN#ucyR&?Reh*xzlv-kZ`Bz-YMZu)4i9(d%f|! znXh|eOT5?M8}hn0j>LQ8;(7n)PSbrniTB3G^Zw7BruzgE?@frGki70qB=O$F_=(Bu z-Xs$5O^WCJpF2(W$t2$EgXjI9J5Be=CEn|c?@M0yrjU5AAHE-X-J4S4y{Yh1k=MPc zCEl9`KMi@^n^xkz>G0E$*S+Z_-kSkG19{z>QR2Os@H3Iuy_qH6n+4DNKX;n$vr4=- z8=m)n?lj$Jmw0au{2b(UZ%&E#=EBcKUiapfcyAs&@BiFsy3Z@|UVnUl^13&l#C!AO z=O?dw3rM`TAbvsey0?(Tdkf=v|L0EAeG!TG7R4`0UiTK0cyDq1;^cL235oZX#4kx+ z_m+})Z)yC}WL&@vjMiTE0!w(~`dmBr< zHyl5lyzXrx@!kmh2=cnOsl7d#6dfcRK!b^1641#CvDr&m^yVXGy$wHvVk#x_6Gmd*|ZMC9iwuNxXMH{(SPf zcY(xv7ve7@uX`6symvAFV)D9oiNt%C;x8qydzVSPcRBuY^1640#CuobuOzQ~S4q5g zHU4Vyx_6Dld)MNxC9iweNxXMG{(ADdcZ0-xH{x$3uX{I1ymvGHX7ajsi^O}k;%_Cd zd$&ovcRT)e^1642#Cvz*?^1Ang#CuQTpCqq)Pf5J@H2!Jw zy7!F4d(YyZC9iwWNxb(w{(17c_kzTGFXCS$uX`^^y!SHxW%9cBio|=b;$J1Nd#_2n z_d5P{^1Ani#Cvbz-z2YlZ%MrOHvVn$y7!L6d+*}kC9iw$Nxb(y{(bVg_kqNFAL2hG zuX`U!y!SEwWAeK9iNt%K;y)#?d!I?X_c{J^^1Anh#Cu=jza+1FUrD_8HU4Yzy7!I5 zd*9-}C9iwmNxb(x{(JJe_k+ZHKjMERuX{g9y!SKyXY#uDi^O}s;(sNtd%sD%_dEV~ z^1Anj#Cw0@|0J(_e@VPI20wJ0IUiZe6aHr`pzJxnXj|n8+n-D)C^L1|`iT5VPPfT9-CXsk=Qv9Ukb#F3>_xj-b zkk`G*CEn|c?@M0yrjU5AAHE-X-J4S4y{Yh1k=MPcCEl9`KMi@^n^xkz>G0E$*S+Z_ z-kSkG19{z>QR2Os@H3Iuy_qH6n*~1$dEJ{;;=S4Mvys=m*(Kha13w3O-J4V5y}9sn zk=MPsCEl9{KM#4`n^)q!{`mgnb#Fe2_vXjXPhR&Hka%xF{DS0lZy|~I7RE13UiTJ} zcyCesqU3dNF^TsU$1hG^_m+@&Z%O=;x-Z!L-U*2b?*Uia3KcyC?&y5x0lJ&E^*;D?acz4ayD+W@}- zdEMJk;=Q5xq2zUMBZ>Eh;fImey^ST_8;&1NUiUVUcy9!LMAEIEt4+o4_3AMaKa%JRd*SyYufDw{ z_Kn7mCa=DIB=+r#-N`MU-+}l8$*b=miG2s-4<@g^LnQVcia(UR z`VN!WcR2oV^6EQ6V&9SYBgw1pD2aVXbpQ<--Y-K$*b=oiG3I2FD9?POCU%(9--GxE$*b=niG2^_A11H9M6`W}^6Gm+V&9Ya zC&{btDT#egia-q--q}Q$*b=piG3gAKPIofPbBtzivN_n`aYA`_c{J^^6L9SV&9keFUhO#D~Wwy z?WbB={c69`g*oV=xTblN~*7C zn}n{WXLpHxJ@7pe`+DLD?Q6%k>C$9F7wqlp2WWK@#B+M-vko-Cd5xjUVRfu?3)-rF?sb(BC&5${G{a7H<`q~KKMT5 z)i=4szP|Xr1S9nea1_SKrJM`)0w{}eaIC=FgA+c{s{F3C=x0J-brSVIXSKl%c`v%|#kXPTb68i??2a;FcauWNN z$1hJ_eJe=pTM@q^dG)O%v2SJk%H-9zip0J__(9~=x2nXx)$ps4SKsOq`v&6&lULsw z68qM~uSs5gYf0=|8^1Pr^{peZZ(aPl`G!zQn!_@Eed<--Z(VhT?~k zSKmew`-b6%kyqcw68nbZhm%*|CKCHb;75>G-=-4#M&d`3SKnq5`!>gKPF{UmNbK7Z zza@F~Z6&d96n+$W^=&P&ZyWqJtHi$D@Vk*$-|iCo_Q3B!UVVE??Ar^!7kTyVEwOJjel&UY?IW>oU;Mu0 z)wiF-zWwq0lULsX68jFsA4pz(2TANZ7=JK%^&KLy?@;`q`I~sp9dG#G5vF}*?vE^m8MGI{l# zBC+pO{Hf&Ccbde$)A6U1SKk>D`_9ClNnU+tN$fite>Qpbog=aDT>QD@)pwr6zVq?t zlULsb68kR1Ur1hk7fI~97=JN&^<5&d?^67w^wdB=zoy5ND@z;}A-whJ`Zp7b6UVS%7?7JC%GkNvhBC+pQ{H^5G zcbmk%+wr%PSKl2H`|iZwNnU+-N$k5De>Zvc-6OH@Ui`h})pwu7zWed_lULsZ68j#+ zKS*AE4@vBM82>PN^*ti7?@|1t#JvP5hhW)%}*l?zi!8lUMgU61(5Uze`@-?@8!wdcH5Q`vd$3%vAS> z61zXbe?(s0A4}~11pf(nb$=?c`!hV>|6}*(_|Ngx{e{HtFY#ZJSNB&EyT8VNOG{3H?jP_!FjL(>O6>j#{}Xw2|17cl7d+qpLvPdbSBc%f;rad_ zyMM?3j<4=NBzFIa|C7AB|B~1}20w{|F^rrH~8uvM?!DY zKCXn`rhPn#-Q(lOXTG{8kk~yTenRr}4p?n&^IFjL)=O6;BtKN)#-_mS8= zIev2T>h3GCdkQ??|8I9cd_R13Pbsl`D*ROB)jhSu?rHGTkXQG#61%6vPe)$e(@W@W z+Gmj1JtKZbW~zH8iQO~fXC|-iStNGPil3Fdx@VKvJv)AO^6H*LLT}SPr^N2L@N+R! z-E&Lqo(De?jiUgB2c)tIi-lly!iQU`d`Tl=;oAw5BwhF)xD?0?!EAPkyrQL z61zv^N0V3gJ`#GH_I)LG?}y)ynd;tOV)p^~1IVlUK#AQ4;SVCO?t>+EAA&!Gyt)sS z(A%^hCb9c){Nc=0_Yo4ikHjBIUfoAY>^>TQG^=d1 z0(o_xD6#t_{7K~1eX_*vQ}CydSNEwBdYkssBzB*UKb@KCK0{*nnfNowtNSd8-Dl&^ zCa>;uBzB*R=l$RA^YG{4tNVP3-5205Ag}HVC3atgzlglLFP7MS3H}oD>b_J$Z_|F6 z#O}-Smorn{S4ix>5`QImbzdd1`)d5v*nKXxA@b^eSYr1h_(#aA`%wwKP5WaKyC26t z&P;VbA+h^O{FCI>{glM+r}0mdSNAg#yPw5BOJ3d2N$73bpO@JE0{#VNs{2KW-7n!^ zBCqb3C3e4pe}%ldUzOPX8vZr%>V929Z`1yU#O^ooZ!%NeZ%OQa8~-+Wb-yFA`&~Tm z|MWKP?@8=_AOAjib$=kCw`u=SV)sXQ-v8-s+CP@q{R#dP^6LInV)tkG&&aF$bBWzw z;J+ZR?k^?uHtkC zcW-=e^6DO2Vt0dY$g6uC3B66nxDtAsj`1Y)HXY+j?4AHW0e7o=LW$iI;U^-m?ujLK zPlBI>yt*fq*gYAZ_kX+l;QQdKdvb~0eer$Ct9uHG-Tm6ltV zZ__c2#O`VF(=t=t(@E@}9zQ*KbQImoMfPKn)f;pZZ+?zts)&x7av-|l(w^Wv+!zr^nO@bi&Z_xuvO7r-w- zUfl~y>|O}Z`#-%+$HEeNn~p^!b}x!wl$q*YOk(%q_{GVqdkKl%OX8O#ukNKJb}x3SCr7(bgU$?du9B}%vAR( z61xZC2a#9zsuH_b!>>kO-K$IN9*iGMUfpX*=xsXIl-Ru%el2FIdu@r`>)_WRukLjv zcCUwDkG#5vNbFu8zdm_&Zy=$!>DW+W_fY&$W~zH5iQU8S!^o?9V~O3v@x#fhdlQM> zBk&{0t9w%ky-mkRiQSvwH)E!{H<#GG1%3fTaf_g46=$g6vl#O|%}Ta#D!HWGT9 zj%_7&Z-?KGnd;tNV)qXC9muPDM~U4#;ddgh?wuue?}Fcjyt;Rl(A#wECb4^W{O-(D z_Z||v_r&i>Ufp|1?A{x{H+glBme{=yejoDc-d93z)3Kk#?)~xmGgI9MNbEike;|2v zA0)B+VEn=4)qRM>?nCj1l2`X(5_+4C!zFeffj@$o>ON9p_fhzx$gBHkiQUKG`QQK2 z+jJZ&vHLhY@Belmk3Sw?-6u%wJ`sN+d3B#8vHN8F$>i02ip1_y@%;Hey-mky5_+4C z(ONCq_gVO}$gBHoiQVVm&mphwb0v14hv)s@?(^~I?u@i&uK_bn2;Z^iTH|MWH;w@K)2I&PQP zeFy#yW~%#6iQRYM?;@}6yCrttgTIHoy6=_PeIK6pf4lF;-;b~E2PAesh<}j0x*w9* z{V@Jv^6Gv>V)vu?N6D-EF$uj*$Kw*apTIxCOm#mgvHL0fQ{>hCw8ZXb@XwG}_p=ha zpTj>#Ufs`2=xsV)kl6hq{zYc0`z49pFXLY(ukKeQcE5^$mAtxNli2+_{&n)|enUcU z)A6Rn?zix7F;m@dOYD9J{|i$Gx_ow(z$*cP_iQS*$KPRv5FC=z>{sI33d3FCNvHK_dPvq78vxMHJ;}?nDzv6#orn-NV*!?^Hck=4~Lt^)z_&>?3 z`!9*zWAMEHS2wTSMd)ohyGg3Mb1VtHO=pXwx;tAX^fsMslIrg4E}^&S>>;tcC%$K5 zcRRivU)>!NyF2j=+uaM_3t!#6C3cUEADg_o8wtHl=Qt92o6d11c8`Z2kNN5zUqWxw zIf2CP3Gov$Q{59u?4B4uF?n@QBC&f?{G{a7J(Yhqs_tf~Q$*X%B3B66{v=Y0g!%xRdbx$v`dj|XrQdp?QX^W*0yukHmTb}xuukY|;@Z#ox}u%qc*SmK^V@QZM__ADx4N7K2O#664S zdH-ie)47DiJxk(w|7S zdGgw`g2X*5;#VZEJu6AvvofCdfA_3{Uj<)#21(e_bgn9K&uVzy|Jl)Wt}b!UU_9^t z>}WdIkho_}{F>yoXDtakn$EQ)?pX)V`@ehE#jlI6J?lx_GXy_`y!NawanA<$4ajTH zh7$J-#q<8}o{jJu;cL$@2|Jq3jV10GjvvlU?b$@)o)P#F(d_Uwd|t zu%qeRQR1GR@H;V6dv=z%XBYe~D)u&o;~qi#VIYQ!|Bk@O)*Pf#!>}WcVmbm8_{4vbbo?|8KXgZIRxaW90 z@Bi#*I!}AXndo{RApGgEsm zk+|nl{H5fz=Q4?VF2`R^UVE;Pu%qd`QsSPg@K-TYd#;wSqv^ax;+|{q*D_Oku9LXu zdOYv{>}Wb~khteY{Eg(b=Ozg|n$DXg?zshj3p2InRtY&?s*#jG~fdF^>Y;+_}rFOt`umn80a8UHeQ?RiDwo>%d&lGmQsB<^_~|2lc?c|+o! zH}P+h*Pgc|?s*&kHhJxNN8+A$@$Zt?p7$i~c_05idF}Z?;+_xjAClLek0kE-82>SO z?fFFFo=@?glGmQkB<}ef|2cW>`9k8JFY#ZJ*PgE=?)e)3HF@p%M&h1t@!yiyp6?{? z`5ym0dF}Z@;+`MzKa$s;pCs=28UHhR?fFIGo?r35lGmQ!B<}eg|2ui@`9tEKKkA-j3Yfq=dJ-zS@yQeq4H@^0aEpbnSZ^&!UI1=}aiyxP~_KYWCN7HM3 ziF+o%^XLEUXnIX3VMo(zB8ht@#!t*l?U_X4o=NeOlGmQeB<|^h??YaDCYP|I>D5=_ zo+Js-1 z#t$a1J!?qZvnGB`^4hbO#64@{*Cww$>qy+QE`D9|+OwX-JwxzA$ZOB~68CI?-+;XK zY$$QhQ2bEx+Ov_wJ;U(B$ZOBW688+p4=1lZn@HR<0zZPh_G~I~&q(}8^4hbR#66qi zHz%(>TS(lqC4Nit+Ow6!J)`iW$ZOBm68CI_--f*QY%6ikcKGecYtQx)_w0b*fxPzY zC~?nD_?^gW&(0F}?1JBgy!PxWanEk}-Nw^4fEj{O#Xg&c>fj z-k|45+k}C$IfiNZfxV{z~%Nf0e}jSL3fHul?6Z++1pTzz5xM|CGf2Pvf5^ul>(R-2W{8S@PQdoW%Xl{!Q}Q|CYr4Z{y!4ul?^x-2X2A zUGm!hp2Yp{o+TXjIgxyW= zu_U#>cZ-DGP48Ao?eEA79%i5WX|1={=!@)lKh-B(9$r zKQZIAei8|*o8FU3Tt69pGG=OhABpQH$Mc8(tZsVum9V<$J%z;e{qX&msr^$*+&>k5 zD)QPtwZ#3?;HM$4{nJX=-SnPL;{NIJy!^Af={}7lS@5$k zQ~PI?xPLbMY~;0nc8UAvz|TQm`{$IfyXifb#Qk&Q`NMy9H@)YPxPM+efB5hI{`mg* z+CQJf{qy7JC$IerNZh|5enIluzmUZJ3*#3iul~)FC}sR()gvxYyUD5_Yc4iAg}$)O58sXKajlkFDGGl(|dV|`&YoPz)bC5 zQNr$~_ev7?uZ&-rncBaK#QlTtgUDP@z;@2gw{p(5GKLkI7y!NjzasLMR4ajT%h7$J=#SbN~{ToTx z-Si$NVRzGeV~P8R(v_ZQHhO z+qP|2+qP}nwsFQ95pTSjF=Kbnv2MH<@!kLQY4&h)jvi^Tn1$-C0m{%#WY zcPH;oU;BGV+~1SDCw=YjC2@am^4|2dzmLTIeaZXM*ZzJI_xC67Pha~7NZdb=d?0=8 zA0%=AVDiEAwSS1j{X@xz(%1fB688@$A5LHUM@Za1l6)k6?H?s^|7h~j^tFGC#QkH* z$I{pSaT52BCm&B=`zJ`;KaqSQeeItlasOoU$@H~$*0oS{%I2TPbZ&FU;AfB z+&`0iCVlOnC2{|3^4avYe~!fcbIIq@*Zz4D_s=JvPha~NNZh}Wd?9`9UnFt=V)DiG zwSS4k{Y%N0(%1fF68A4BUrt~9S4iByl6)n7?O!Ev|7!Bp^tFGD#Qovq;q4J~-z{_J@orVY>|( zO;YmucoO%= zCy!5G`x8jqpO8EueeF*qaerd+#Pqd4iNyU$$&=F8{$vvOCnrx%U;9%?+@F#>C4KEr zC2@ah^3?RTKaIrwY01;l*Zy=8_opXMPha~pNZg;1JR^PW&m?hwX7bGRwLgo*{aMMg z(%1fM68C2(&rV(bZ$dJ^~7C$CRm`x{8y-;lf^eeG`~ zaerg-#`LwniNyU)$(z#G{$>*QHz#jSU;A4~+~1PCC4KF0C2@ai^49dVzm3HGZOPlx z*Zy`A_qQi+Pha~xNZj9%yd!<>?<8@5XY$VUwZDtR{awks(%1fO68Co}?@nL)dq~{h zle{N=?e8UVe{b^M^tHc_#QlBA`_k9`eiHZhC+|;R`v*weKahMNeeEA4asOcQ!SuC% zh{XLv$%oR{{$UdL4<{c^U;9T$+&_|hBz^54C2{{~^3n9Qe~iTaW68(T*Zy%5_m3wZ zPha~dNZdb>d?J1ApCobrWb(=MwSS7l{Zq-O(%1fJ68BFhpH5%UiF^}%?cXeM{}%Es^tFGh#QodIx6#-B?GpFzAm2e>`*%v*zl(eqeeK^Z zasM9jJ@mDIuf+ZP$oJ9L{{0g7A0R(KU;7VA+<%Dt5Pj`GEOGx4@+0)M|ER?M$H{}u8p^tJ!0#QoREuhG~3>k{|hAiqIh`)^9ze~bJUeeJ(3asM6iJM^{x zuEhQK$nVkD{`(U5KOlcVU;7_Q-2aID5q<4{EOGx6@+b7Q|Ea|N&&Z$A*Z$`c_rD;2 zL0|h{O5Fd7{1tuee=TwU8}c{wwg0We{qM-%(bxX>68C=~|3F{+KT6#HiTo3N?f)!s z{}=Kv^tJ!1#QopMztPwJ?-KX_Apb#M`+rK@|BL(=eeM4(asMCkKlHW#uf+ZT$p6u^ z-y*5~HiCrh)<%@nej7=`c55R`YQK#lVY{{eNov21Dq*{|(ImCsMwhVN+87e|$0U!5 zNbQd$aer*`*z~nOMB;uU*I!us9TN9D$({7I-z9Oso7_!b`#s`+`p|mGz4W!;C;X=( z{5e$kUy}H)6&=ebQ1TcCr?jb`!h(~pOHKxeeKUAaerp=%=EQCi^Tm|$+Obe{%jKWXD822 zU;A@N+@F&?Cw=YDC2@al^4#>bKaa%ydCBwA*ZzDG_va_iPha~BNZenLydZt;FC=k) zVe-QCwZDkO{YA-((%1fC689G;FHT?kOGw;blDs5+?Jp&9e`)g4^tHc?#QkN-%hK2W zauWBKCofN5`zuJ?Uy-~beeJI#aerm<%Jj9rip2d@$*a=W{%R8US0}GdU;ArF++UNt zCVlO%C2@ak^4j#ZzmCNHb;;|}*Zz7E_tz({Pha~RNZj9$ydiz&h)jvi^Tn1$-C0m{%#WYcPH;oU;BGV+~1SDCw=YjC2@am z^4|2dzmLTIeaZXM*ZzJI_xC67Pha~7NZdb=d?0=8A0%=AVDiEAwSS1j{X@xz(%1fB z688@$A5LHUM@Za1l6)k6?H?s^|7h~j^tFGC#QkH*$I{pSaT52BCm&B=`zJ`;KaqSQ zeeItlasOoU$@H~$*0oS{%I2TPbZ&FU;AfB+&`0iCVlOnC2{|3^4avYe~!fc zbIIq@*Zz4D_s=JvPha~NNZh}Wd?9`9UnFt=V)DiGwSS4k{Y%N0(%1fF68A4BUrt~9 zS4iByl6)n7?O!Ev|7!Bp^tFGD#Qovq;q4J~-z{-e9f_B%$Eu-!UFlhl64=n}SD#~2d#$0U!LxIY$o zEOPCSEpdMcng6iB{YGx&+V7CK-%0MIul+8G``zSj`r7Z2xZg|erLX-y3EQn>sKot# zazAfse?Y=^>ll={Ka4z#H?=>G#Qkx}mucoO%=Cy!5G`x8jqpO8EueeF*qVY_uq zEOCDlGXL@)_a`M!O0NCMB<@d6o}9k+r;xZmC3#Bv+Mi0|{?z2D>1%%)iTl%%r=_p` z=_G8oj_Db_vaG7|TfB`-@~`^!n(U!J@? zeeJIxaeqbfiuAR=lEnR$$t%;>{wfmpS0%4XU;C>`++Ur%I(_Z0A#s0A@|yIuzm~-P zwaIJK*Zw*Z_tzz_OJDozN!(wbygq&HZy<4hL-L07wZDo{4W<0<4*_-o7YREdtKkx!#9$I~VFwT?3+I-W^BlQ-pfmPE(1$!F7- z<2e%iTF1E(9nT}5$D49IU!vm$Yqzju(?J=1n0Uc$oyh z)^WK+$1BKJ@TMHEl<0UB`6~Kyyjp@^>$pau<8bnD-jw6D5*@E2Uq@e#*Guqg9XCjH zypen(Z_4o|iHBHDTO|0kj$0)<-bTKSH|2P{M8`YGchHyPof7<7$6XQ~?;b50D?=O*uX&(eWYjL-ghNumr!>@rXpnN6C-!rW_xW z==eDKar$z6LV{oGcv7O{Q{<<3Q;ttdbbN;V41GC1E5WaIJSWlddGhnTDaRKiI=)DL zk-i*XlHk`mUY6+i3i%b@l;f)s9bY5AMqiGvOYmzQZ%A}}ll&%c%JD6Uj&GCSrZ2~L zB>1(CcO^Q$M}Cht<@mlt#}CLK(3j(f68u`nM-m-BCi5@zLezcYj( z4{yrxUx|+Yk^iH|u`?3 zt#f<{eywu?iH;MJC*(~zP9)KBV)DfFWfJDay$qUk#<3bW07bY)EUyh4N@N1omN_1R|ycloFadC-`OOThKFUKV%__fZZ zBswll=KEjAWys5r%W+wWj?0mkqc6whB|5G^UV*+GSCr_u5_u*1a$H%0U+Y{&qT{OM zRe4j6t4VZRoxD1IIj$kWuXU~|!LN0$CDCzhGT;CBwa#@UI<8CR`yap7xt>JF^~vkg zm*WN!9XBLzNMDW{N$_i(8%uQDguDrF%5hVPj+>D;qc6wJB|2_F-h#dyx0L9(6?rTA za@<;?<2K}N=*w|iiH_Tmx1%q|?Ik+yK;D7A9Cwu9*E)BS=(sbP?|=MS=PnW*cO~yi zUyi#;bljc1JAFCsA<=P9@}BhNxR*r7y~%w4` zM@w`(hRpXrey#IZiH^sSkE1Wg<0bgD&J!d$o=E2VAHUXll0?Uo$tTm7<0%pyPbHs9 zUyi3qbUdAWI(<2wA<^+n@|pDIc$P%Rv&nq_pWkg;{{~C z|M6>`7fN)zhm(iEw%kf5ujyI8SqA$mrB|6?hzJ)X@1ifqyCwLw&U+*}-b?2DAHUXlpG3#|$@kNj z;{y^MA0+cH|G}?yJ|xlcVe-TD<@kt1$4AMJ(wF075*;5WKTcncPe^oplKdonIX)%9 zuXR2x(eW8F-~afv&Sxb$K1Y6zz8s&I==cKp1^RM)QKI8ZwHV1`??`lfm;5e$Ild>+@qP09^yT=0 zM8^-wAJUiOM-m-BCVxy{j-N<${FMADeK~$6(eZQg=k(?Hg#^FW`K3h1ugHA=*5?E0Ui9J@x9;MclFlayoE=o0)|*BFv=>>5*oU+Wr6QjT3? zOLQDU=KEjAM&|op#}0A_xg0wsI(Cuy3w7)!cazJpN1|gdxtG2i`y@IJB@d-9$9{>9 z1LOhvavYTCIE*}uz8uGq;McmwmEhO9#*^qcK6!lJm*WHy{94z95*;TZPsE#YoLHjc zB;-lx%W+bPj+2omqc6wFB|1()o`Sv{r?aY2cW3y~M1FUN%?Ixa$9guWaX zmFTz_c`^EOTwJ2#667W5%W+AGj!Ti3qA$m#B|0ucUWUFLmzChxx|WmZxIB4z-jw4C z5*=40uSj2xD@k-*nY=Q6Ij$nnaaHoF^yRpkM90<1tJ9a`8WJ7XB(F(dj%!JDT${W$ zeL1cp!LN0#E75U1@_M`}$Mq#TZb06Ez8p7{=(rJiBl>dOSfb-5c`N#I+**QP>)J-5FX?@C{eyGeB1oxD4JIqo6RaZmD|^yRph1i#j`w?xN%$ouf7 z9QT#zxF2~x`f}V~qT>PN1L(`~K#7hAkq@FT$Acw09zs5Zz8nvg=y(|UF#2*lT%zL< zjz^P^=1n;sBhm3#^0D;gc$`GX;Zay(n2<2mGW=*#h3iH_%y z&!aEL^Cdc7K)!&!950mUcoF#``f|KjqT?mxOX$n-Qi+b2kuRe!$IB)7wXQ29I$lY> zk~igel|;v@$yd{t<24c;hm(iXm*ce(9j_x_M_-QDOLV+}d;@(s-YC)WCh|@6<#@A1 z$6Ls^(3j(_68u`%Z4w=CC-X1=#IJSTA<^+p@}2bMc$Y-SyUBOcm*YJW9q%RIOJ9!n zNp!rQd_R3TJ|NNYLGpw2<@k_9$A`%e)0g8T68u`%qY@n-BR|HQa(rB(;}hg3=*#g* ziH=W^pQ10vrzJW*Lw<(79G{iw_#F8;`f_|;qT>tX7wF6JMTw3tkzb-O$CoAewXRnr zI=)JNl{e-1nncIf$*df z|4Ltuze#lboy_n5__eM-Bs%^{=KCMN*7cV}$G^#c)0g8v5*_~~|4Uzv|4GWRJCbtj z9zlX%>mE^3j@=_k@N3;8OUki(6bXK<`+t&h>>gEuU+W%CQjXoDOYm#mV@S%edrS#_ zt$Qpbx$V2uXRr@!LM~sA<=P4@|3(U$EhSbPEDSgz8t5K z=r}ETTKaOFPNL)VC$3@AD(wF065*-&OFHT>MOGtEFlDs5+IW8s9acT0>^yRpWM8{>x z%hH$QauWPn_wo`QS0Jyzn{r%HqT@>BmFUZHWr>cfkXNBE$5kadu0~#sz8qJV=(q-X z4f=9iQ=;QqyX!>FUNHy__gl!Bs#87=J$X6TK5JL9XBNN`#*lIdn1XC z81)NZ6!Kx zN8XM%<+!~>#~sK!(3j(m5*>FU??hjYJ4?oa0TfBaha0TLY#Bp*m$jt5C}JeYhi zeK{T?(eY67q4ec=m_*0J$%oUI;}H@ak0c*SUyesf@N3;iOLRPj%C5pF ziH?_&FQqTX%Oqp`$e))>^u2<71#imtN(rv5`zndPSCg;iP5E9U(RVm`IDPqEE7A8l z@^$p(d%Z;88^|}%m+y@deQzS)L|?u)OZ2^k%=f>(w~}uqm+x&7eQzh@_kUE??dE==*#zE39haC z5sAK!k{{(w`93Dm_i^&$^yT}61lQL6q(tAR$WQU6e4m!+`waOR`tp5NqVIF$=jhA# zd5OL+kYAuL-xnqNzC?bBzI`BmPO?`sl$Unjp#U%qchaBbahO7wk; z{1$J@_ic&3?~vc2FW+}1`o2egkG_20m+1Qe`2+g${ZOLsN92#_%lBgmuC4nMiN2qb zKjlsNekRfPbMoi(<@<#M*Vg@|MBlH-U-71Vzn19x4fz}T^8Hq#?|0{fAskFL{h#zBS^}(XG96Et!E@j`Sy$~!L{{_A}QaV|4DFd zJ)=s>w`Vj-`Sy%1!L{{_At~RUF(tURp0On5+cUNV*VZ#cqHiO&MBff_2f2JZCHi)e zyXeceTcU3dnZJp?z2shU`SwZl9ZDWbU%vekeFw;V|LZ$Q=KEjYVdP=t@*PK_@3`b~ z>C1OK39hYYe2Kmjkoo?{we?IW(RU*9MD*o5u>{xFGl@jsNy(G)rhF%p=sP)ia{BU} zLV|1SnNosl>zPWT@6_a}d0)QMNc5eSJS~0sPA9>&^-M3(cLwqdyeZ!qCHl@po{7GE zXO`gFdS;R6J1cos-jwfb5`AYU&rV;yb4c`^lRPJV`OYQLcW(0B^yNE`MBjPI^U{~^ zd=gw+&-@a77a%XdoAO;yqVGcFh3Lz7VF|9SXAz0Mi;@@RP5CY+(RXn&-~YI_o+Tvu zE=lJ5AJ^8iltka9$xG9h?=lj7mnAPtU%typaBV%yOY~iVyaI2^cSVW5E0I^CFW;3V zxVD~EB>JvOUX?fHyP8Db)yb>Vm+u-9eb*$fNngHeN%UQtyf%ILt|QTRUGlp0<-48) z*VePXMBfd_8}O!lHuB~SaiN0Hs z`TobX^=u{4cWd(2^yRyaMBi=6+tQcsb`o4$&-N01cOdV;oATXJqVG=Ro#@MVX9=#Y zXBUaSyOMY1P5JI7(RX+9?)2rmheY2!$$Qe5?_Lsp_a^U6U%vZD^xc=dFMav$C&9J# z>@U&x0P+F6Dc=Jn`W{3+h`xLemf+fY4w2}4DEUy{l<#2@eGez|{f}$wIYOfEkz~IA zacw>_j>a6yeZ!sB>LV+zLCCsZ<65JdTy5Jdkgs% z-jwgH5`AwY-$q})w@dWBgM0^l`Q9nf_b&2X^yPcEMBjVJ_t2N`y%Jno&wUbo?41M`NE5Wt(JSWljdGhnTDc=_)`o2hhk-mIilHl5UUY6+l3i%b@l<%t& zeP1KLMqj?KOZ0t%{04pbzA4f7E%ICR<@>fo-*?FG(3kJK5?ou)dlG%$C%?~|^8G-f z?}y|M>C5*c39hZ@V~M_>kU!x~`F<+V_cQWm^yT}xMBgvSU(lEDmlA!yB7a3+zF$l9 z{f7JveffSX!L{{#C(-wN^7p(c-ybCU{z(3jzI=a@;M#hAmgxHn`4`@l@2?VleY@?Z4j`?o~jf5`vPm+!w4TwBk7lJf111lQI(f~0(VN0gLr z??@6{Tkpt{^6ec(f@|yjpQLyF!C^R`HmyecU)Dc@-%`c6xpmcD$ali=EV zrC1OM39hYoeu=&dkQd-h`7S8YcOmjZ^yRy-MBhcoi_n+v zq7r=efcga!L{`+CDC_j^3uF1-(@8FE=yjPzI>OH;M#hZm*~3! zc?I5-?}`$AS0b-OU%o3#^j(F#3Vr#mD$#c}@@n+uyShZ*HOOnwm+zVqTwCv25`EVu zug#nCT}Ptty5x1~%Xd8quB~@{iM|_HefK8s&71Pw zN22e(% zOY}X0d<1>@9x1`K^&TbB_h|CbyeZ#fB>EmpK9;_GkCWiqdXJardjk0c-jwf&5`9l1 zpG052Crk7_g?tKq`JO7#_cZcp^yPcHMBg*WXV91LnG#%E?^zOk&nBPEoANzJqVKun zbLq?XJPEF?_k4-I7mzRDP5E9Z(f1m>SKPrjZv<$Hrf-y6v{(wFZ| z5`Awb-%MY=w@CE8m3%9G`Q9ec_jdB_^yPbp1lQJkr$pbo$anFkeD9X%dk^^@`trS3 zf@|x&PonSrP?_&~uA16OfU%pRB zaBaO$O7wk-{1k7>_i2f~&yb&?FW+Y+xVGNsB>Fy2ex5hw`+`K@7s)Tum+wmweP1TO zOkcjQNc4S`{3?C~zF$aiZM|Pg z^!rM-Yl*(!kiVfX-)|+jw%+d~`hHLTo;T(DgGApS$v@JU?@tnae-|qszI~D4 z+WJP2lyBdN5?ou~NRsmH8(D&D>l;Nl;H-zI|g# zaBY2KNy@ixY)Sd{4Uy>E$bA3n+d=Limv5&;-!5_&eff4v^z9+{(3fwoMBhF#e{+3@ zl82JZw_l>~0C|AEdGNCo|3+Nr;_M9HF;|K@|{Ma@3iD; z>C1OI39hYgdWpU>kZ0gc`OYZOcP8>o^yNFVMBiD+v(T6CtP)&X-)s_nXD83joARAQ zqVJsKIg?R_^XFU=yj$Pg65Zz^^Uwd_-TLO0=sq8rfBr}J`N{K>%Y6Zf?hBF^q%Ze{ zB)Tt5UYNez7m?_`D0xx(a$ih>ck5eRqWco$C3sWrOG1r|yj$Pe65ZD!^Uwd_-TKy*=)N9#J^FHAUxIh*+d!iGhU5)-Q|=o{ zbl;e~F@3pjBGG+Q@}~6VzL`Y#&B>e7m-`kHyj$Ov65Y2V^Uwe5zBPGka=C9K(S2L; zw)Ew`okaKT$=lPH`wkMkTi=cn-FG7I#G7*8S)%(c;#pH|0<$j4o z_e;r_(wF;X65TH+Urt}{S4ecfl6)n7xnCvG{c7^n^yPkyMEBw3;q>Kxtwi_h$k)-A z`}GptZy?`5U+yIJ%l#gS?)Q@Kr7!pUB)Z>EzMsC_ACTz&Aerxf-5(-9L@xJ-CAvRCeuTc< zAC>6-82K^!a(`T+`xE3R=*#^{iSAF4pQ11KrzN^SLw<(7+@F=`{v7!^`f`6>qWcTv z7wF6VMG4-m?kl_sQ?mm-`12-9IGr{jd8+&PspFpm;0v@-9ICL zMqloqOLYH&`~`ive<{)ZEAm(L<^Huq_ixDG(3ktS65YQee@9>L-%E7=f&2q~x&J7^ zyY>Af(fw!g&%7!3UnIK!O8%9;+<%kk{yX`1`f~q6qWhoZKk3W;FNyAdlmDhK_kSe1 z|4aUtzTE$llslifMeuGzN05~J&=Do&K6E4r-fif}l5!t9iUjXA^na3aA3CZ8?>2Na zNx2UlU4nNTI))AklqB@{IK5K9fZEnaMNLm-{Rd z-Df4wN?-1?N$_q%XP4+c2YC+Ol>3|#-RC0DMPKf7OLU)yJP&=j&nwY=KJt9@2NRiSApIx8_Z` zZzIutTk^K_<-VOn_wC8s)0g`W65V$s??_+nJ4tlknY=T7x$h#;eOL0X^yR*rMEBjv zyVIBZ9unR6B=1RI?t4k_ZbSE$=)MnmAKsMvz7pN{BkxCF?)yu0KY)AyeYqbf(fuIu zLGK=*#_9iSD9nQar$z9LZbVVKob$^%qF1g&_lj#0F`F;9w|3ISqhvX0G%l#vX?jMssrZ4wTB)We} z{*=DlKa=SGIr($?a{of2`C62qiSA#MzoswuZzOoPq2Ee$|Bn0}Z_539iS9p; zf1oe-A0@i~ME;4s+<%tn{tNjR`f~qOqWf>;-{{NzcZu$QkpG}B_dg}N|3&_bzTE$o z=>89x-~V<0m;5ie-2ao5JD;{i@NWGhNXor`LWyY-JEDfj;WN$_s{ zqe{xXe>4f+t$%b$x%ZDD!MpX3DJl2#co)03y?O}Wn?(S1hpjP&I`lSKEK$urZJ z`z#XOXC=={U+%L>bf29(JAJv&A<=zK@|^VLK9@xIxyf_Wm-{>t-RC9GOJDBuN$_s{ z^GkGJfV=>2%6&nJ?hBC@qA&M_CAu#{UWC5f7nSI~7`kDxF2BPF^YMLvqY+>e&%ehm2- z`f@*3qWf`V{`pw-J`>Etpc~kDENpwG* zd^&x(pCQrxO!ArZ<$jh#_p`}o)0g`>65Y=wpG#lv=Sg%wpL{-jxnCd|@fH5OP~sgI zkuTy+-EpzRJ1!w#LSJ`WD&dCKf0@KPE+_N*KR2}gDp1jFs7t#8W>B$J#AoYN!>IsM8Z97ph@bcfes1xw1G~EH+7M_ z5^w4zca!U;9*H;gl6&dvrap-`4J8kyubcWM-ZVhwZ|+TlxeDe6@x@iK5H%&;MkiKr3Na9TslP9LHnZX|`-ZTq&7W%qrR*5&wMxKqnZkk=fJ#AnPi8swjo|89q(_9j7nwvZ~ecd#V z#GB?N&r4r7%_rfWHZZ@$n-(DR{m(sZU_psDEkx$~-!!sd z-n2M*ar(Mx35ho?N#^%|Z(54H6uE9%TH;O1koo@So;I+o#G95Q^Zm~~ZD4tcH?2Tk zfxd29QNlfKU?qt+txV?opL^QCDiZE#1FK5BX*Kd{ys4X3mw3|}HqIOkX!`BH^Ak zu&KnGHY0Dwo4RRp3HP*tEhOHwC3#EU)J_L6W<8`xXoP5Y4f{hxc+eciOb#G4KvA3$F>9Vp?RHgJ%{n+_%) z%$vID5Q#S(N~oika*LP(*}-~c+)XtzW=@HSn{#t zy6HHHHyuwtp1y86LE=p(l24?sn@*B=)5+wM>FcIbB;3;mPL+7mY2?#*Q#YM1@uoA# zXVBM8XG*;3Eb>|Ob<^1rZ#sv34t?Epu7rEqzsl`|0bZ z2PEF~Ao)T1y6GW_H$6<|`=5K-z#|fGdX)Sqeckk!#G4)`^Zm~~ZQu!sH$6#ylD=+w zO5#mVlb@!qo1T$yPaAkv;!V$ypW{v4^t{BIULf=R&pmD6MTs}PM1G0BZhBebO|Ovo z{^y=H@T$a{UL(IoUpKuj@uoM(Z_w9GZ%VxBE%ICRb<^7tZ+eIP4t?G9uEd+(Bfm#q zH@z?6o;L7-#G5`Of5@A<=_83ZeN6tCzHa(N;!U5DKc%mmK9hLU=VZSBxu*?$A@Qa! z$$bBFPaF73;!R(Z`TpmgHt>zao4zG~OJ6sAC-J85$=}o0O+QGy=|?i(|K9Wy`6qJS z^s~g9ej)!tUpM_K@uuI%ztPuCze~L75Aq-Mb<>{`Z~BY;7k%CIx5S(NA^$^PH~lN| zrvJ$Q(R0&aBz4o^2ommTgCk1nrooXU+|vd}mT*rS97R$$4gOEUJ#BDQN!>I!nuL4W z;OLUNX>be)_q4$=C3Vx_SQ74OgJVnTrokZ+?rDQfQa25DNVumBc1padi_G`GH+7S{ z$#qkY#G87_eE)k>AGwcQHw~3|Q$M+%zHS!$G} z-ZVaWeEPa+0*N_gHuSn zX-e{xys4X}l6ce93CB&O)v4L8OSrx*G)4@ylEyf-~Zgx z24|LVPaB*?;!U%XXXQ=ZG@HbmW+%^1UpLJm@uoS+bJEvMb4j?T4bCm`rg_No@TP8> zSK>|ck>{hYo935rPa9l7;!O*Z7vxRdw2;J`7AEuk&pmB$5s5b~O6L3Dn-(K4My{I{ zmw3|>HbDLSHv+D&d|s zxS7P8HYab+o4RQWi8pOY=KJ59wjysuuA8=&c+)oIZRqQ!Z6)5c9eF$Yx@mifH|;>? z``?>(B=1PBn|6|T)6V3b>FcIlB;K?uc~|C?M~jEzHZt>!aZ$pPl-3}Mc#`y zb<^Gw?rDSjNW5uZ^1i&OoA#4<)BfcB>FcHgB;Ir&`9S)*=^zRBw84WV-gF505Z=^H zhf2KZF!Evab<^PzZ#sf}1by9fq{N$!A|FLxHythEo;G-l#G8&K^ZoBl$B~aC*Gc+;)qTj}ej+a%s}JNb6{y6FxH z_q4$~CEj!w`7YknO?OMY=^pYu^mWs{5^uVXd>?(?bic%#9w0wJUpGA{@ur8!57F06 z4@DAU{E0H$5rwrl-jK{_jmslb^tH@zkCrnkv&)7MS!NVumBzAN#j_sH+@rfzy);!PirKcKIhK9qRVN92#_ z>!yz--t-Ci6Z*R8Q;9cyM*fVxZu(r}O<$0|ps$<0lz7uuw#N?$kqCh?}<$-mRr zO@Bzd=}+>X^mWr;5^wsO{5O5w^pC`w{w4oQUpM_HshfsH!aZ%+2$H&K*ocz4Y1l{- z?rFnDmeftdMv-t&8}>g*-85`e3HP*Nqe<$fVWUg9rwtoJQa247Q^GxM*jSRfY1r5j z?rFn@Nb06xO~O5GScjx;8rCWCrY>?<@_(kzKdiQ~Tf@(sYyMnfg%GVx2qA$h2qAppYL@s9C~@pPT*tamNv z_>8AjiMjt9Pie$y#F3}f3^JZpCtjU=H4QSJ)*|NqZ#-oXGt_uW z5+{ixPm2sPp4KK_n|$PH9fORgOyW%Pk*9SHGM?5W=KgOytxvo@apWn>Ap9gUHZTZ3 ziHr>mGM+Xf-iZ3hQ?^0I)5gTy|M8Q^*u)^?X;WhE|M*E{0($avb4cuVq;r>zV!p0+05ntbFb&mjCHGPW_uc-oeDTWTUt+Zkj$OTao_06Lc-n)Q`@iwDC-I)dk*8vVjHkVb_aYy8+S?%GX&>T!$VZ+^ z3^JbfCFcH*pG3xf1{qKL6LbH^Pa>n#Amix(V($O=Nn{*oknwa7@j>JxPh|!fPX`kp zOg{2-h(X5Fp~Q!hk35wdgr7vlVFnpbhZ7%8P2}kagN&yN;tKMSry~tAo{l0uihShh zXoHNWN@DK+_(^0OW03K5EHU?g{3J4#7-T$E5p(~?Pa@+ugN&!+iH|2Ac{;%$RkR-9*g&A3uqVn+-CaZXv#feB`OaAmiy)V($O=No3q+knwao@$KXzPn`zg zCy{Z7LB`Xa#CK8?dAiFW5rfiHrvfGM;*fx&PxQk@28G#?wQ@-2d^D$avTw76{3J5oG{|^*i02v`#*jX z8DAP?JbgvX{U1Mxj46YRr>}{*|Klf-@r^;o)3?Oj|M8Q^m^KJMiHz?IGM>IC{+^o1 z)Bg-Io@R(=$VZ-jFvxiNk@!dQk*A*wGM;9MXURvNem2N>`h}SLKYkJ!zZzsb%@K3| z$4?^TH-n6)--)^Z<0p~vhe5{EJn=mF$kU$&8Bc!^|3yCX^tVCyNn|V-WIX*t{0}ve zr+*DHp8g~Lk361|GAQztv<$*eB54~Gc}m6%!cQXU7!-L*x(4AVk@O6TJSBaD@RLXe z21TBdp+WdbB;y7}o{}pVgr7t*#h}Pjaz%q8Psx=G!cQWZFevhrOf?8UiR8)#8BePa zbN@GdCD}%cv_cuUGkBq^$aqe)+grvkDo*`%OLzDk{cLg zJZ(t4AvKYwjSMoLvWc_FN1iq|$ava>coXuGr%eqqo^ptD$VZ+wGst+_oOpBck*6&T zGM;jYbIC`Zwlv6i+KPB9@{y;l4Kkkci1Wxtp0+W_c-oej`@iwD9r1R=k*9ovjHm61 zwX-DE6$w!_F3^JZ}BHoF7^Jq$9Q_9W*1kDo-c*dY8Ql6x6sJnc=qH#L!`eGD?5N{CCy zN1paI$avb1ct7%yr~M5wo=S;J$w!_JFvxg1koZ9Ik*9+UGM>ta%g9Hb4mQYmI)wNT z@{y-Q4Kkj}iOb1Ho(?m}csiVz`@ivY1o08Xk*5lSjHe@sk0c*?I?5p9>1g7k$w!_l z4KkjNAwGtDDm9U((+o16YKd#fN1jeM$ap$~_zd!qr!x&Q zp6ZC}$VZ;eGRSy3oA_+&Zu+mKtO{olAT!`N-2UgN&yJ;s)}Or}GRl zp3WyepM2!$0)z0ANH!W|JY7h9AvKYwiwrWJE+)R1eB`OgAmiy0;!DU!o-Q@Wcv?=p zoP6Y|*&yTTGUCg~N1iS>$auPf_zLoorxt^Zrz?s1{U1Mx+1H=!Ik397lWIR1c{2=+r z(?bRsPY)A6Og{3|Ymo8u2=OE2BTtVSWIR1a%>5rfiDaKa#?#}(-2aWICy1XQjyyeS zknz+{+)qC8^pruy)6>LHlaD+-W03JQKs-P`^7O1h#?y1e&ykNjJ#UclG)O#1KJxT} zLB`XI#4nPMJiTO)@ias{L_YHLvO&hvE5zLY@smitY7l-B$zg+xr`L#IqbBn7x!`G01qDAfBKm^7N@e#?xoS zpOKF|eQuEPG)X*3KJxU1LB`XU#9xw+Jbh)5@iav|MLzQMwL!+yH^kqNk34;AknuE4 zJWW3G^qoP*)Az*O|M8PZ{?8!eX@;2lzwz_~@ejn2rymV6o_-?!iG1W~)*$2QXX2m9 zN1lE$$awmd_*e3gr#XX+r{9QwBOiJC-5}%X58^+_N1o;lGM@e<{*!#<=`Vwfr@x8+ zCLeiPFvxiNhxi}zk*9wR!cQXkpFxqQMKTCKiA9z{k*7trLHJ25iWwAnTI3jnpTr{9 zpvcoA&mjCH7WoE6o)!fL;U}>uG$``4C~gpb5{p(aDDt!@#UT777OiMd{k*7r~8)Q7KLcEG(JgrL1{oi;>BTgfZJgsJs@w7Ve>f|F&YZ!#5|Nme7 z>Sa|+Hr;jw@V}K}dBFd+aZ-U#2{#kSdj-I|&rL4Khj}UFmJp6g@k$txRw#loDTQYW z{}a06ptKTw2{aQ6QYyWvebUM)(8hmqa}p-_Pi<@FKhc3Wtpx`7x4Uw_S_Lp~wQ>GU zPV`0phA;kYHPQcvx6)hrzw{~v; z+F?rCxEuzhO&lP<33Z#W(i&wrzkJX}cQWnV$poK>zmWY|q^7yJ1e+p%7YNT-q@g z8evo_pr?R21yj;a)a=v&^U}^mK)f^a7ZWe;kqYx*P}&9EUHYV5dEa$H+N~F6rJ`yW zkao|4R%wrPKx5B*=#+|6phnuO80vtYy_=+c&?*toUos=@i^hJ;+>crN7eb3v%6VxO z^h*bze?Xg5M($w#+o5&RVZ?{ge^`%ncmU-vC>=rL5$!N6Rir=#@Ls{}Bl7|6Bgdqp zI$=UOx?8HG_n1uSSn7|hm6lMqq)V!*k&ep)bdP7p6Via(3FA^V`&ReBv~*%NRKtjL zQVul0oOCj~oZJD#HLcPqDS)R_7Nk?DKaKa(sI6s2?U-~r&(oWMUC-#2&cyebJnPb- zO*%_Z3Dlf50MpXhsZatF(mBjNhq`*^){ja{@wF7Ka~q{)%vy%0hBRPi10K#}m-8m2 z^J{_n3pj7=l`f?3LbNYp&c)e)c2mA|NfKIMPP(*ST8`Fow43Q^CU;pO%uAOSK`W5E zq6W}zDT99LN@}j8=gK~ql&(sH3LtmYAS_5%GwbSh;Jg)2tqm|OT~h$)UNb9QTMk3g zb?ny`Q3>?4jY!uEvY;5Mp&978p+mYc6B?yTe3`(77ceVkwcW}m~S9g{`k8~G4@8aw(`nrg_$laX@Bho!Zz?^$ap;zjr zr@INLy)O^wyKhpuzYw}4F1UK29GKIS4b(lD5AD)JNucMUM(JVd9wzrNJNDMWxbz6x zj|@qVW4}+^j?iL#@X1Q^nNSMNFS8Ifb?M&)B<(m%>9V>kLdeoO!`>R zEPcYfPdNL8{)r@XOP?0Ng7g_)KF@(EX|fo2e$gp?Sr5^ZztvZ%!24H2(iHJjwe)ow z3`pOQ|F%e)7Eu3vAnz+tdf3mq}go1&n$nBpQ-t| zN&1D{FVy}rCjE-$ubj=X>m1MD$p6+Y{az#eLERtKFf7eyK^sg-f8y^?;y>r4zv%m` zOZuCce>cN~w1CFKxb#mx5dWJ8qtbuW{x>8`0hB|JEGrdiU`&=>4O6mWyvO=wIcd-= z%cb5ekmYB|3Q}Z+WwPSr;0K_T=3`|*pE#kXLKo36De7l_xUW^L-%9+I_A9@Ie}%*o2Eg+W>Cra}QU%UUl0 zW^u={)<c}LFmsb6 zG{TguP0`x44yez`gArMq(YJYutStgyW^N`>pF1yW%XV2?Il$bl8)W67xea~WjLO=U z=e8BHwqu9wILj}EZdu%0tR1p}zuS)WvI@{HAl`|&J0}6H#l0{stFQy+W$i-mF7)lX zAZxcW7?xGUtlbM_?GZqitUW7%p5k&~@4e96I}KW3PS!qXmN2WNS=PSnyl*v3$=a_L zsNWyG{dtz=13Mg00Xz@Pf(BrZgQzbrna*Z31e_nOjbOd8e$y z=s%1ZhoOBq`NNreI9f-P!H}$qRA`lTWH!{nxU8cD%s4s|W@S}UTiGk?82XQ?f(cp2 zb^x_YcrHP&isx}?9p3=cvQ8)jcH#bFRrkp{F&Eloom2qqa8kRhlS_c!8fMop@01)_ zr{eF_VrZ3hS}CAWOME)H)8}NJkq1q(&g5Aa06Uyj4qZU)+325LC+i#sDxeK!WYssq zpsb~wFGX+Zw5)Tpp#er@Ekl19=MA|)&v~4k*CFeCb~>Nh3wmWW(%V=o>q4Fv4#>KQ z9WLsZb#W1($^FG@B5oRzbx9^P0KJ!%K&Pzb?6kZdnAgml<|$d1HNw2C%e!S=fsZTb zZApVt=#_OPI#*JE74=sQ!-A}SpRDT(VNTW!yx-6Uy}QjoAUvUTj;rEOjbu0 zFsox!)~)E@iq5TQ+?EaW-ZlXA-Ol^%yx-m@tCPCUQXsyA_zs?TmH<26)gr5lxm{hd z?w*x(PcAgVl&pKHxwjL>WOY}-u&n!d-iPP=GoclxWj%oQ1Cz3P%3(y-gVjL(A$EVL zUDm@{&<69edTRmgM;c&3)}zHRAnUO-=#kY&@8bb*{zN*^|712y$m*{HG@eRAxvZyi zfc!IkvYst~W?9eG!%US}kj?1}0_whSqPK|6VWa55b76c?Sxi4%l^`Ie+Fs2h7X*i@pAuko9*e z49Qxkl=V*&49fa99nktO4aogBCtIyBFWbroVrx>iod;FWB|FA5)+gJk0nWLj*lrPY z%J!)9c>3wkCYw8p9W=`hv!NcwWyk4{56fPmQFaRF+*@q!EB1;5vR6t%8BEDeFh9{H zJGB}HWv`qA)UG@sdzDOR2I{!8*sD&;PGg@m_F64h_Uh=aJ|mld8>*dN0AnyOd(9!) zYcXRjG%^NcCp%^H>zBQ#LH648ufy!jh+aT*-4fu8-&pMR%7Om%3!w!DWoM;95ulTW z<_7G%0efvQEPKN|=!QAj8_}~7H5;LmEyxD6H>PG2o}1FQX)CZ}4$sZVZ_zG0w^a6) z0d&EP?5)ax{8r4`8ttul=GDvIrcw5`oNYTTdpmaHcM?0lPWJX_Z%@q*`7k1TM<_tM zpc>FAn3KH|?>nKf)3EHFJ7h0T1?m^q0J|*4b73V!&q>+4WJ8neU29=M_HNACts9tA z#Gbp;yL$_uy$5G|ra-yu;!L2gct-YKWiTdt?-Cf7y$^N!Ov^5*0%q)6325$@4xKPB zd;fmfr8&?h`vCF>49GqZodd^ZA2cMpjJ>&w*artd|H15jNG8<4tn5SUVN!NEdmmN+ zEwT?U2K0}h_Xz5az(Ykf@H~>bBd25^h2Bxr9!*VUwruVl_OT9B$X=2J>XtCSid+>w zs+e(H9(2h*p57CvI|03F-cKw5YEMGvq;?pSeKPUMy+B_L8a4FRlmJ?%Fq7X;>{FR@ zYPamuieW@{Z6(ahKAqjq$buf(XA0V6*X6*l?6cBjpPdW*ea@lgoMsr3U5{3M8MMe= znlJm@BEZABbF!DAyA1t?dYG1dUXASYsXw3G1;mXhFeCfI9H8eS-Y=?_eQ_NyrwP5L z2B78=YPfgUmyo}d{G~O(zL)a8oZXhwx19Iold_xhpb6NoncmCLyKGAKy{MR9oe#PO_P0F7L3cj9lcKK@8Il?QQ3F4$iAyyHg^NNt4;RZ zWwP&~|K42amfcOhyIJ;q>~J5?`_qA04^aESi0qzhD1{mz|6m%F$>z5W`(bJyM*Csv zdfDp{_ItDn7Gyt`5A4#H18DV)%YM9C_7miv=#~8>^PVKvUjfuT#hj<;eTv-EmCz3p zvY#P-rbqTbG0ez*wng@H1<(Zed%g(h9~7W9I4%1H_Ioi4=zodbUz(FWM9&a9FH`?= zx9nGvP%Zma^4t~d;Q*>+zg7W*vR`kI{RXvfv;uQSs2iD({U-C@MDMM1*>5xR?LOI~ zsX+ZZc`z*dU3A}NxAzKx_xI*yk7dbzpBdZ@?DxlHf6yfR!(Q3rl`tjyBk~_H=i^d9 z>*H?OpX38N6KOCjo4bMi8FN3Q=d(^=pU;y(?IiihHrZdK%Kno0%Pv5d-!AO03ZNRu zeTCjs5iH35dRq23*)T8r+hN($#n3JLyC&J+m&1_k8Tx1HfmuIL`=cNW%Ai^HPY!VY z6B@I;&(6vInf_nM|I#J<*L>jp*GbuP^v{jR{;dKy`)yYC@0|b6-oJDH2YdcO{0AEI z#Pid#|15+a*?-adR|C-hH@Ux=$Nj+mrx^NV|CoiXpy$7N#Z&-|Fs7JQ0v(Fk zY0w2Tip9!dNHHf5Iu&!NcUxgvF^`-_uP>m^pHeKCRV+j&UIg7Rr`QTvfNn}AkV_%A zVuNBUQJ0`UH65CO{L1L85`q4zEikEAS`sRN-qo_97e*9Yo!sgRimg$jSUNkTcPX}J z3edmixMFKn1DYAliY4hwGHVfgEkbkc0-$f5OqfNUHoxRh^0rA1JiXBo4U9h0op+kz5*C=)vyByZ9*x@BW{SnMLVpOq; zEI_Y<-Xrs20Ol1tsuCJuM6si@fxe^L0sYEUsDOSLSL_%xj-mFLX~no}#Fntj5^9$$ zC{|So>~I|Y$HNKqo6{U6&7>x0S${V%M|h^_<;Muh@;$--w6yRA9gM1;uU} z0nTqp!i-`a)ZdE6t?Yd3xMH{UDRz4fR6-k&>qM(_RkLALcV%$4okLN(2VowY!_9Qw_@^|QWfV2Ju#hz+{ImNhh#GV;aY=GW@ ze#M^U`D~A3&!qtR&$TP|JbOJqsn{SrFEIbbR6yq?YF}c;P&Tx}jAAdBDE3O3Vy_As z0q?`S57YZvDU2xgI`8~5lh_+oK+i}Wu+y8=yp;lNioK2I+r5g7GJlk_cRCe&ml^Nn z0J-<*8zUa8hattdU&P)g_dy|$`(RYD5A&cIrW70J$!`#`k4hB#n3|87^)Wkqk_+f^ z*N9E<{4^EV`LitG{qsr1COcqGu`h~&J-+1Z%SOe%;`tRdQ%NX;Va2|#R_vP`;QZT4 z=!QwfrW+LdE(NIhz5wPG`(F)=D>jo2>^w7|*bjm>#eSskr+&p|(VDG;Ud4WPpc>Hl zB^}xU?O%&wRI#~Q7*p)GQkYQe_a4RmNJ0mUC^paYPxSsmn|~$}`R~ZRe*NtjGUEuUnLEgzbbQAZ36OXg}{u}s^qMm3d~x4 zK+YP}tU=EjqjJ(6$b}&}YgWivi?g+Q)*N0Q%O?fqpqz%;k>YY%nWl!&*Q;n||&DPIfn-xiRM(56anuJpZi1*|Z4I z$f*LJo3Yns)NjsnivXzEg1+2Rn3uC<8g#;foUJN>8C#=~$KKoIL5rMiB`1GI&i3tc zc5s0F4qb9~%mj8UNJ5*Oop|zD@9cy=pY_hp=r5j>Q%GDmEN2($cfrT5Ja_Grvm1LA z)d2Oo56ao20vaKTr{wIJ1;x+|oxrT(07?Lzy@>a!h7mb?XG0M*%h@Ld>g1GAQ^F4W z67M@BXTK^yWB)cerPP*^JAm8)-Et1hf-X4+IWQ%stVYhkB|!Zl#lZYS&^j~+&^?qL z%c(6VJ`CT7RRXn#H^PXVBMM%*Z(!?W0>@QcfkiAA{C0 z6LO9%1@=6azs(YQm!Pqv59qJzlyh7T@P2#&49Pj61jgi4SHP5<6Kmw0MBhn`upsB; zVL3I^a!%p>6rQKn$vKVl)2iguMlkbq-cK(BbkE3#898S%x2{3XSpl>IGx%p1&N)eF zl~d0i^+R%&Rs(0}Rzk0wWz;VtUWNw09XRI|$T>d~x?mU< z5gA(YGb4|6JYf}Kd>zH}ntemz^IoDUfh@2bn zal?R|8y#qq)1H)bQ-hqF(Yu-aEd@YtM;372F$^pXQYk}uzgPeDHzSk{h z%mH@zka%2B2WWo8{Es^2e4K71O;sQrxE&#C>qUCv|yQ1b=* ze@Wk$)PB_R?RH_ssczTF(D!VP4Km39#D? z@eiE+Fe&FpdVi_{>Spvy#N;Qfy- zIr9P31O4+8a{lD(FV6mAzrV|1R?Y(Xf2v?g&cA8U0PM+Uzw=+0TnVaRTCP^vGQq?Ug&_u95>hSIv@}mIl3YSEFY&G*%mzyLur|zXtVdw8~9S0rdFYz+JNi z=H;$c3zKp)*eh8I6LJ^T%UzpY*5+*OUb*X(!GPS%9GH^3ZY501<@W-2y7&rbP$FfVs|{tnw$K{E`> z-LVh`o_uM3)u`CPvp8=1{r!o9Fd?nQYJJ%?ak?!{;|q2IJ1_mVyl}?mzD$Za{8OA{pb6&XzJta))V#~tyB)yH_sG3B zDtC;!G0xu40_s2D@A5%4kmEN5_ro@rmOD=UN7*nZ_v1Q1_mdjnIYIpdHJ_6IEFD_q zejWh5lc{pQC<5xfa-d)CRD;~F$$icIZ))X!TMQF&r^}#M?svIB-S-tRCHH^jz;mV) z#^nA$&yRw7xj&)#Q>Wb70%(`}Gx?vX|Czd9ssOLQHp!i1pSf1KzZJr`+~2$8{=xfv zHjK*slO6tKhrfE|{@pBh0iA#IU|8;dZSs_aVR=@qJiAU_ECt%-Icd-#&#i!Qd0q~* z$nzUvLS9e^ee%K@=$04f87IF&3DBQH--=lyRxzNF(IGF%{z>{4 zF?-RRytV7)t%Jro^sK{sCUY~T^frZJ7c!^0wl9EB4&FPF`L% zG{Shdz0HwtKsxyBp`babConBKmiyfA?W|d(_I?6V2iz@V*!Cd$Z%- z)AIH~yTpMWdHZGpy8D#^XZttGD(rTRspjPssYZ*O5`0J0Q(=j zAn%Ytd55;iE9d;Ma(Raf&^}^LUIk}IqJI?o9n~!FX!bg~31;P0QhN;N#}>kvJU(Z= zDhFER9ajdE@{VWT3G7|X%oC|Qaa7((DNqdPpIj@C&snc#Sl%f$@=itjv;ex~)e3l? z&iNUfpUJ*;)$-0Fe^xzo!jwF|r+a5l%R46>sHx8b<}78urOoorb%5Gs`9S|NdK!2( z&~qMpo;N1%eDuyAmv;gCH0HvBybJr~UEC^<&rt7D_FqoT@;Q0U&rR2;#lNqi@D zcecvADJ@<6TySEUi<@3?IF93GBuMzs?-CrT^0Y_d>0Z{)S`G?SY zXk6aI&GLHLr?(9j@`lI_ z(Km$l%N6oorRUWVdBey$t5$y-^KA@u)L4bp+(-u^nc9r zlN{)lH&F`An3$ILX*mqZ`z#mQ{w0OD#;u`;{D@h2C7Ayx)j_Yk*mKzoYqk9Zbvnqg&p5wY)#k{!73ff2RSt zzX#+kFl(V1=H&f@?my`MTMQlY{=?6I)ABVg->QH~`E~(x$&V#rLcYV(sexhnZaz@! zl|Y|-zgd2e1)PPPg)J~6KVAr(fHt3-{tAPDR*C~f@>k3OdiW0QuQVq=Q7k`|+{&fE z`zr17SIvfUh~gpnX~b#$@>fd-^j7bHF<6klMlMu93sAEL8tF;-YX&eXe=T-di@J;& zpf_0pUGf(R+T^dzthIaO^L^USOo3kc>sGnP%4wS>J{LPwx{Webp>NanapUZh}1yH|bDWJPm9`wrJ zIv>!@D+6}frd$5D>GHQjKcD{mM)})QvpqdK(7R(M49hQ=mA?}jJGIK+8U3A`XW~F9gN85Gt=LLd3!KxPv-B5ZgCcHwpTSw$=|z1 z{ywSlOPISay8EHKUx)ntdG619X*Mw9fHC<87Rx^<9VX9Wf=pA|KE?vQIvrqyAC!A5GuUr7$S}81ly! z!;t(X^eriaarsrv@{jA4e*(4D=vNQOKau@U?3aHMH7935kNlb>G{C(4Q<~(TipHrm zFf0Ew@~2J9=eKXac255374pwWfe!g+7Qv+ax^kedZcP4J`SQ;eP{Bx2pB)>it zsHrDjivCjSmR8F@m;AZZ@!9GxqragGrsSVjFaLbbFW}iYEdQb+`4`X2zhqqga`Mge zHIu)rPX6UpFeLwqTfpDzp4;=Tl>EyJJZHoy@zlPySuxy6EewghBatGw1FG!1F!K zzlZo9^7l;2zn9v3nRV}&{O(d<=6%%Phvxlh^7+j5ALy6g(=7i%^dB6O|4^;`hqHm5 zAD))qi`FC5K2ixY@*i!5dHIjk0PlVE@*jsM1oS*f?~?=a`y1syRSq36A^&M+JX0lq z0G($8V5jFZVNm`cGhd+Q#VPsx_UymJj3Lg3(0e%*nDsJsujE6Y{8vkX{$XYf)AL#Z zFo*A){_D(qo%nU~Z=m%Cy>HMnk^=ONw8?*y`ERoGTWQcM|7~Wy-2n6QM;l>M{yUt% z(+Oz4%h`Kqz1J##jNY+I7?b~gK6K0f0Bt^t{SRj3f5?mv$&I7&QM>$)1=N2$BL9ZJk6fparS+q{Qq^xpJDb7Y0w~_@1y>YE%Nz3>i<*^GxBF^fWOJ? zg8ZN9`-S*dJk3!%NBrBQ{NM5M`>gyw*n!Vo|Ibul&R^*NO%10-!EPg9aE^5YiKJ7SDnv1uF#5 zq97$5dKIjg1fDCAU#S|!c{iY*nys8VoB~uK@-WtWRxL7W6CFfZaCAhA{=%T?#g4 z&yA_wBncHjylFY`%wbMW4WO}ED%2|2T+ppx3!Yn4Dag$SX68;R;IlH=a!|omrwsN=IT*dZ7C6zoV`;6R6hozkIK!OjIh&(0GH7NfDa z9LN`D0=pGXD%b^2yOzSJg58D`6cO*93jGT9$bwDly-4om?w4(w8JPyqEXs-P?%1{EA! zt>6%J4`IJUi-5W1jSBc@%fVsv98TR4X;2C5a0KTSrO*y@3XU9Aa1`}NQ*$(Dm1tCU zD>!CI!Leu@+oxa&JMld<;PW#$E)VECp8N@DpD>`H8ola%1t(?!f1?xU6`X|T$^0Eo zo={Lz2Ga^o;q26OsDUvBr?LBK3kqt>0iDxxVNk&tNoY`TCc1Tnz}Z>t3eF~fcBg`K zQh@XNVg-D521_|RHyb7tENfNJ02j0=Xhi?Q5(O6(05uoQDY%%vCTg3|xrF>BQwlC+ z{&F;z)7Q*dbC-h4*!l8wpzjKHxS|QzxurwFm9+}4N`qbnSM$8ON5M6Czh+dywe<5D z8eBV|;JO(FZRFdiZzH~*=k;?6ZfI6;V^TqTje?udiKYQIjrr?26m{QQwrr^N}1rIUvA>xP274)Lj+pge|q=H8UGYTGKufA+(1T-Hn z17r-FWZ`&)tYr_g^2{io4*nzLtkAE*Ly&lbXf0=|m|&vgL(&*uU&2OR}3 zM06{7kr^+}DR_zJ5IRHb@p8R_S5lx~!K*x9tp@ss>tIm9YefoPC;xh*f;Z54gMHpu zP%uJ0zsUw~!Q0FkErw|Y?{q16w?x5v=)X6wV2oYg&x1(?AE5Ukwd3fG4=DJkLczxY z^eXtIQo%$T3@iAwK*49}Py=HMKCe|U$=M`lUo1%-CC!dMB+D0GH^C!dF*%hPLu z359;G!XO>GVOn8W1Y-*Mt{KL=6!KXZuFwGU3RBt@u9%{5r3kcF8dR9bhfam5nF?2? zcI9D(tDvz8&s9r+8EGvFSEGKlDTS-o0DWuFw?@Ch^gLkKHR)MP3Ny%OFh5ECA_ua7 z{zd4lU8Qgx=BzWLFtbx3pON9Z)UMaAaDD36rzVSM)`-Fl3Smeg-zCEhM-^^V0h0=| z(a7exah<|V1k`NWq%bE71{7}ArEv2Ch@Qg=w;vX)I!JIRyfci5lVM1YDyTY>rh3C`&ef(Y<^4&75 zUr@M|=TiO-=N2nmM$Iy68i#$y|GSVJG0w|72edY@aAIZ zR(MN`!j2Rme`}$_+e%k#@G(J$!anBqQS*2f zv?zQcfI^s7_++2L{xabC6uzIT2If883g|qO2DLDzaG)N@J=>u0xh93r4=Wr*`-Oa9 z&WmWiNbaRJg+r;p%$J$@@_@ouc)r3rpPAus5%ep3tw!PNc?#d4?~MtCBhJv7D~VArueh3}^TH6Ii}BTOp%ung!Q&w@H2 z_YpHb>Qwk~5}Fl$g62e^@Kf@ijw<|&S)Yw4{G9X88(=}tbq!Ga4YR+QQur;;Z+V}tSNL53Jqo|igK>p3)e3*eSNLO&!k>l} z^8GOUSug_g3V$g9=KaE6zcTMv@^j@dqwu$S7*qIrkHSBgF`oi$z`p!e8~(}ppZyB| zN&@-6^PpAX0=q6WEBq%N#uffs0(kh3=YQjhs}W`ux9b&m3ZP$cw+u!U_ljUZaX$}w z6c5T_O!2TuaXusCD^w|-5z$E0w{F;t9?YJXcN!v{o5XJS_{FVNUVYDuDXc z(OkU^CKX>JAG#DzPXhI8wkXbLV|=YDm{L50XEFuYIXR*DqC)6VeC-_QP<$OUGqa&n z@pZ|qJE-`2^sLX!tOCV1Ah!YWhU~Oqi{cwGd!v5Ev(d?>c4Kzmgm}|jV8Cr z`1|m=7~i4<$mJHpjN)6iE6(R(d@JIun-tGWfnLS8sZ@O1BrtQ^8pXFmbGvTE^U=-c zxjp&q(b<8z9UaJlC>~b4fZBo%#dm_8nYlO>hzofZ(#!Y7_^wro?^X&kiWdNdm*NLz0`CX0*FnvIZdn>s0Ow`s9?bp+qj4~Gd`89(DFL(&nOFSKDi~3`JRhh( zj5&u8mI%cm4?&I2@?XB5Az7SO#Mt;;7BzoG(owlL$$d_e!IY(V2``mUzG6`j^u z#joM~nhwRU6_mlC;@6>b-Mr#$^tZ9Y4e5&C$oY-TXrEC0CT8B8tN1NwcBCqPE8IqW zd%5DB#W1b-9rcRenFald-_@XaS0>CWemDB}bSZu>xo+n0c^JR1Me+L`K>LAl#e3-M zsa5>Je8nGP?n6_GKg@eCb9&KxBnKuHf3!*Q$C%rf0zHa9PX6&mVEz;IK0)o1Ng&ss z4!l3r4nvAR&7M#9!JOjHQ~>cn8Vo4@EOVaiRs1>LpQHY{dBvZvgAv6C3t?387iwT! z@fYcRk@uG>6(33m>R)D$m&X);B@?O?f0Z3xrDnJU1{HrTU-8%3o$r!yJ|E+6q5U>z zqiDR70#k~=JFNJ7U5byPHP)~A`$a(hg9gPvWX^{JijP+TUis{cf0FrstbGe$lV`dA z^CnHwymi4K+Hp$rujbslkW6cs(FobdlW-WpMloT5dP-~!oxzX3Q#wmXtDS$LWNH2u+D+yQ+oFXY)NmBJ7NfF#5M@Xva1>jx_ zx=}nwagQwm&XQDzxb?_;{dtn&ZNO&WG)WB+U=whHq{cpA4@n6bI7m`*JxNV#Noo!N zpxd&Aq}B`o8g1K1YM)P1hX*)JQfebfouJ#rz;kyefHcyepFTlS55i6Z{pp}ReHTeH zvcNMW^&;%d6(r3n2QHB`8}w(NAt|#7I8M?vpmPoAU%QH=>sA6sN$Oim(j3s8vll>| zx$v8Z_j!mj?h;$ZSCTS69+yKADpuPAINlWm&1ox$t z0Lr!W0!ho@wk$`|jc~hhJ4wrt@8zJg0{0ag0OYOz2uTCakaW`yl2-Nr$ji<1fnC5^ zl3ueEI84$l4J5%HR$7$-4w7{13IOT6wi7r_(rtYt-HtG~UnFUDmZaAOfM-ZrGf2`M zh<68`F_%f}ngGxqLY{`UlC&Ov>$j71C*1EmL(-ezcNd=TI!4llJtVyuVX$tK-kKq4 zBjRklMAF?SNV?|`N%tb}n~<0L5a#~%B)x4jNt;3I0fc|B4M5npBX8MLBt3MLq=$1P zVXl$3;Q5^h|40A;jdyJzX)9=BE|K27o22(3pYK7uNBaQ8*|rpTiKNF6?r{fjkfisn zAZa_&ecuI=-jDF_-vOK@=>y2;2jCC=rL^M^NyAG4(AbIho!bHA>4O^p+;{CI=|k|x zd?I~#5pbBKkAT)k4wAIHiKLItC+TCz&l8mZ(%-X!q>qFClL-4H+&@tcYy?h|w08$d zpG2Hbo+0T|p#NzPaEzpVTSyuyBk40Sl0NGI4wLjb#5uT%B&@BZ&mSP^3#f-LYzC0V z7m?-{k^UisJ+uipMbgtq^XU^LeQ5)5nWQfx&NF*S`pO=XzKV3PwvxVvw7-V*pqG>m zBh1%9|Ley|dKT`_?k4FQGO&xJ9Nu&LNO}(RpW8~(HyePnBz+6%963$W^KgG2`S=cS zbO%Y_MP9$Rl%y9x?-=49J4Vv?@%;UZB>i9;Nk0q#pm)3vK%9RA%^!6Fp!M%~KG6#t zB54$57(GhT$u+l7pxJc4z(EC{faG0c@ZzSm#$kQ)& zkaT7xaG9iEBK$9rk6*1P>DTc4^)n>BG#@xc(r-ZTw;qzt21xoH{9is#()mLq{b!D( zKOpP{(EVeUq(33OKOZ6K;!%?Rim?Bc0YK+c8-O@}+eOmf*OK%PguRR~|9y<4D-M#W zhh(vhWW#2XjfY9bKA3E70CtdUSxa*HQj)E0B-`L-gPSCiECY%M*aW;pvf2wAAlVLD z_9G-a;N~g=c9HDv1P+nxfuH9f$zFu@A{}1_KwADaBnJrCLvpYQI7)KGAaIG~&?*4$ zm55XM49QiXQI#V(44PrQS0i85pdHyta?N&H&6;+_n?|o%U_OMUp$#0(eg$uc@;n zcOu_in@R2ljqW2PrxyW;m%c#qG?Z;R0f;*z1K^Hziac{W$+Hk<7Q)ZEO!92d%^)Aw ztRVT?GGIOM63N$XBDoKFngh&5UgsjMd7Z!+lIJ7-^`MD0iVR*ZFKhx1le`FdUj$k= z;Qa=KUyOK*Hv-7>l0M)F$x9JtDbiiGndBSG0OV_V4A@HY3IdSs3i$W$C3#>KfVekp zA$eslfajax_8NqH&2Ex!K^|^7Px2~+y%l-8^%TjkMcS`L8D9(c+ZF-H&mjB;Hv_1% z+u^sm5;#rr>+rk=wASn*`Ho%ybY749>v4Yr^1c@F-?*0Kbtv!92H+^k>wAF1B;Sc} zcfLgOn?U0((7)?A$r}*%&E>#plHU>oHUkLzmWw36wGDv(TlWEHNZuF$Rse{<@hHi6 zBi`MhdG}V}7|HhpfK>p(--EK;i*)Y=y?YUMlMJi`b^~WgzOM<`1RMq~lYBqY!W<&s zzlY?v0h>3H`~ch@*a0B?gIfU5d3zbK6abyKpC&oG2mpde(i+D5PQ>4Np5za%B6*hs*iQ0?BEUhC zKaBVvhTliF0!U*w{5}fWA4U6oY!}H-GyrEv-qQxa@8c-0m?z)_N+>y!6w1}>2NRF35ReZVD>N4AlC0DcER_cL2a{;UVs1R&h!mI4TK z5PA4~C&^#fNb(nZfdeETLV8c1C;3ajmsbFY|I8thzmg&Ot1*(lCIc5qK8$jFeH+Qo zc9Q%Jq?1GZ+%b}$1I_1l0|@iY^(23bfwYd`{%sjJNb>V*0p$Jp%OrmXVUNQ7=mC5&p$9B%j(s@{bn*$4LH(2f+JJ1HdK#`8kdI&+z`Ujlgk| zf4&B|L^9Si@-L2(d}cj>aKGF^@~=7pr19$*06H%<0XdR?gZRJMMe={Z?Y9wND{!9V zvxxJ%Z6v>32EhO2izJ^L1Wu8B9%Vd_`|lC{4{*PL@?1c9{|K6YM7%!*fK>p}{_{SP zFXH_o^7ofTzyXr~iah)k@BallmpXwg$$#r5`R}0jcZC1PdXg{0{qjMQ{~K<3gwMnM zN&}E1h1LKUND)22E>aBTz$)MbDMt8}l>u8xF%htX6muu=3@Mh~q?E^iOQcv4&w3s@ z7c6Z_k$M17ln;`k$iOz>G%4yL05RCuKK2kgp0C#UMaDo)f zii!`Z`5nM^QUU>BFDXH|2NA9U;VaIN5;{amUNQW)s9ksl$7`yQX0wt&~EeqJAjL%B;cMvI!X8?I{}odDFZx1N;C4< zj4&;rgB6d`<^k~Dfv~BSzy(q|HObwc2cl%QCLGz700Q}b>-VnkL!GHZqQtm|BcOsoT z&y(_|&7|D52tc?E2>0ftq`U=rdCM_UFoP*~A0_3U7_f_!dqMNwJ)~?x+)X(0u9`Df>5(GSUMe-282^=NmX{7V?E>gY}0O0;* zxPSQ=DbH*mYA0Uk%g4PcYk#ZdO;|EFkH>CF?4}d)X=prfqE(0+Dc{u_9 z(I#LIDVWWaleoWln3Pj+JM|1HKi*2pPd1S9Q^fh{K2lC252sI&^0O={Kgato0>EBU z&LFS9ECW`O@+$(ilk)2`q`b5gKpMY6UVd|wl>dPHZx4`i_B1KKTLIwyvIAH{%DFaR z4=LyIeje%mC+`1=bbb%Izek?_fHGVF?F&7m{E>mMe<}wy0H;X#GwA*KB~mUTFMnB2 z%3o22|B3*cfgCB9@P27KDSyNLZ^--KSCR6M0C1j^%LhpL??F=XmB0y7u52R}D>RkP zl8PBiHS__8NHyYaJVI*OTHqq7rcJqj{KzKWzF*m7>HsB1Y&V8i1wvp;yN~$LYz|XsxR9_RYgH(SdfOr9f4L(C^1!z|w z{SeZugkL4%Vop-4@E+bsYV|GvVI#f3F;Z*rUK=1aDw7&Rnst4^VN&bo1II~?uL52o zwP6FPjZFaJCKdtDkeZAE+kwlZHmwKX*SrEi{1*7N>?XC<10apIN&qz4a-_B&CA9-# zQ=pT=bLUC`lmrCPm!8w0Q!Kn0MgFD?V4WTG^y8aB=x!oaD>#pO{C62{^sl>b?zXk^U8ojq|S%? ze9*mq3#kiwNL>i`gu4HB6SJEFNNPSgu9V|&7>}O0J}+DkpYg9 z+P?-kL+Sw1#{8w;w3pPCOG&*MY2SQ+)Yq&8&XRh|c2ZZ#z#dX>MH-mT)Y~e7eWYRs zNgdop>g|K1u0}pqBi+~Gc}*K|oYXsZkotOrfBhv=-_Qqa15T5=whX}ijYxA{1VFr@ zEu^mZ056ex=Vnsh1R8J30vAcWYXyM&h9jiD8R@-c6>x&ox0VA3N!^IB8Hab*cB~NPQd1xY+?9?q=li0fc|xIH?cz0q}qO z3Scj(SZ%4efzR7pdwmdjPr&^X7fIc_fz(e{0*6V(9H)K?`TO*C zQupC`-)T~x+6){ab$eHa{C8YZ$(Ec*~FrTT<1OSA8<|3(IIY{bP*8@jL{n}De53eBg>xlm>o}WES>NgPg z8^~X7FR9PXC-s|Uz&299)dax*$SUA8sozHUZyzP~`IP|Nzq1xNPU=yle-!C__W-Hi zL)aH$0Ky$Z8sE>5`UB+U2Z;Z}PT(M^#}V(}Jf!{z?mxo&za!lfpg9Wn(Nm zNc+VTq@HR3wv+l}y#E+9e}el@;Qv#&o!$x{-Jfj$;P>-30JMIAFuy?E{Ng;RXOR9G zxcw68{c=5UoYY_S00&9^bsvBF0bC^YcWVLM zUq)VEMn2E=0`NZ{0rrskpJf2j{e1v9M(Q8h0HkvP@h)5<^^ZAH|8#`ZKc6M_;$~9+ z5(5zaFYx>8N&tTUwTRS9NcR%x{cS0!e?ONlknBeMUqB=N*Jas8vYVEY-P{WtAiJd!z`Y!9<>$$6-9dI+4}kyK zDD48ykX>E@AdE7f>?*>mn}O40x8vP@k?f8LkOlC68=auGTg!kwWN%wR_V%-6?<8OlK-!q|>|OJLy<~^B z(%!umc!}(3570yQ9>ncAMfPbs$UYskre7fYjDx^wviG9AGXrFwh5M|nWS_kVI7;@+ zDzaaLG_F|#oFF?im-g!rt`F{gh(8xJ=RQOBd5AY}FWKkIz#+07X`-(-tX|nfk0WOn$U=P`ELY$Qz z;1bzy2Hn?y?rScR{gws*v{tPr`>hTjOZL|yKd(g?XeaHrfj;Is`|VrFj=9dh8sSzW z{OdsLbqC14W{~W6lmo}e{(8iH1JYTGyuK0X50#O9eG}R5M3^`20pNBQ%68XTvTp#r zH}{hLEq%ZRvcGj7**7Bo-D}B?dCYzf!ru%3d*QbUxNi-Bc=sdT{m9eX<^vmn9N9Nl z0*JTy2-zQS0LbG5XUP8GCID%^9cjEBdCf+Ey#VMuv=qQI<}~}mtAK+5(s>8MzGEAJ z_*?M21!3Na{Je7!fO>f6DY8G(1MDOFyUKx00MghBdRuXS_g1pMhkz{EA1woR0~g7@ z4QXsUME1ujfz7~6WPcoPj~^%ddshH^$i5x%wr>C~ll^^of4>9RP4*9Tl6?oBcMJlT z$UeLj0Ii)!e36C%LJbq7Fhaz@w`U*BU?+?#b-_Y$BmuL}Gt3xj&g7O$tip_w!W@7yPoCS91SA5%O7T^YFBG#3kb{$hP8{U zrL#30j0W+S?N_V`tD;@{iJ%B0LK$xwSH}Nc313x7#7*JF1B=7qz^u8m0;L5u!9NnDsjnMUViflh!b(WX<-s?$0eE~7Cf(GhK3+>#$@SuDyD ziNsZelS5hb9x`gQpA%W=A$?R&l*cq>n*VkIi7IT$I#kqHKFBQZ2lOi#W;Ej0$c2{oD zQ(4(iS(y}xq@Ei+)%H zq?)c(4W6)}W0s+-vjsgO-sdeNre|=!X`6IxPID7DH*Yo5F@vI&NtZ@l>s< z_f5`;x~!_J&m1w$d-Ju`O--|!n)1KmXWjW1jeQLw(aTaH>ClbM>(1#5Ib?l@HQ58`h6sZoMA1p`bKBi*->(Z($%>lT&&LxvU zOT>#R33(%yUYjI&BuPk-`edj&KT;h^)JOD2LBOOtP?wJR-LhN8-+)zedPB)%$m^7> z$zm&wZzmUpwAv~3z8S)wPU-#KQfw(d#%yVHc*RJ5zcUzg4)pgA;C?tzTiaG!yXy*- zT2BlIomU8Bp&$K^oWb@Q1Zb;y$vrkUxQ+BNcn)==66b>I3Y{Ivao6Wb!e8q48I-mn zA_gKA$@=`$BUzn+3|l3aw<4LW@VX=`PYZ=27J0{;Ksij!gicZCt?A-Y@NY`1Xm1=H zPc?)E3hYPMKzf|6_FKzygAX2^^`ajm&S18xu8Qi!wed>Hw4kD~IbwCy`Kz0*_xMG> zFqkZg-5=`l^MnA`rv602D%tFkQf~D*DrDOW{yLX6(%e|lG~j3sCKBZ~n`%?bt>02A z`zjT59@GcsF^$K+N#pSmO3^I30r~FkjB_{fn4`6E49u`W>pE$@%ha0vSC=b_GDNk? zv~ZUnS1#c%WU$(QXsi%PcZC~&Pfspq!sx5&idFbz8~%&cxN`ogkm-e`QdKKVzqG6AO)EYV(h)6cgN+z{Ff-!@1d2Y3m7aWCWS1%-+_$*Ovu*8vGcRHRH z-gp>%EZPwduQ9jQW$Qwjf6Pno3W@%;Ez>b2#;RM*Yr+jDv$4udvZ}?hE0q67aIFo( zls<0sx!Xw*jGS@vcacq5CbB7it);*`(d|kzyDkd3v{9Si&!aXHj#M^?vWCh?aaK<1 zvd*xLnN%jjOv=_+UhcE_{T5$&IqG>lkEnorIhjYq#|f2F^NKTCBTvaLw8kv4j0tJ^ zwX`Odv&4=uNm?*fVzNY4>wKwDLY*mHY7RH!uO-~l5}v@I3fw6LpJEV{5p{m$`{L&s zAM{gTR(OSIFx@j^346&?I?tJq?xqYs1&tdzSVjs}Z27`ea9}GGOx>z%wCe`|1OtBGeF_ zR1Y;**LjgATm12KtFQ~drBDkxcjmbWvfURt)z(@5z^qpLRCN%F^fs8LO*1w0a(d{~ z=fntB5DnA?DG%%p^13Q&TLfkvpC4rmiw+3yEtoVd^|EJdT~)rE`(hyQR8@ObRr_?lh>tk5fV0p#086of zfkH?GM-wr>(#HD;d8iSbxtHef$Y62N@2eJ=&eICL5eoi*?K|kw9lpX2ed8qzO&9>f@^@#ykqu+O?>&^A)ZX+0PmCzTN7$~Uc zbjlJ<7uKG&^)s>jdo0jiXI5pOHRKKY+;V4~rJ}XQSQchyMVahe23bDI0(9c-O|zRu zGWbFN5npgCsX9xrtr)RD&+n2uW93ZG7!GvA%&Ow$Wb(&@u52=y1u6WDj3oO(u-_Hr zzQp65dH4u;cr7HtYl-}v(G(bY)Yt(@gvYq0FqNRR%+$O6;PPe*9=bZ~~pQ#9n zda94Nh;y!BHt6#Dd~Tn~Bq8^%pky-P?YW@OAF^AmE_;r~Xu&61yQ2V0~hWgHn+kXoAi@0BWeWns# zJY6R{{f24E^&#=ejmxd>kahX$Pu2A*J&R}P#HTL~D+@yTTmHJ-R^hfT_kBuB=VkDl zhwy|M)L#>KmxSN0sI$h2<-aZgX9Z<*c{C#0u3u#P(SSj3R(ON1D-dfFg04^^=oAoj zxhj}PurB07(5(gw+7QfFgW1RDApi_EBVWn<(H zNB`?Wt3%?wt3#{3jeX1JG&Iav*4HQoz^-mirEUh38_4!nbo_hd#t8l}g2v^;gqqZ~ zGK6Ig8pZO8x#6njjQq02*O&D#m@+rpiWzxNGY7&-XsYZe#hgH%E!2k*Usdy9W=nu? zk{k1;39yW3-hQ3!q;w{4NqM;|q1&7B04)xtfGD#5{L0|XA|ALoxE5>tmc_U7r6t%J z^LS#d!RUY5t)ngGuAMP= zMs4Kw>Z%4`Lth}-5^%?Q9gRv^%i{6%Xhe&0J@VXyI&y27!OVnb)T*CHp|*%XpJ)F# zO2*SShN?DU`MXEL?&{|oyHTsPOF~tFaKPycqLri9RJ4W^wCq>mW36$+si~nRDDDs2 z!};$=8~Yl&67LLExvM?S;5E_Cn^OUQYe;0!%%O%k4HXrUh9*SuM6Bc5T%rKgVUA+S zZA{@7edU(-Bga}7^kR;{A9~poJ@MnnW&Zcv0fT$#4LpzGjWy~WiOX}H+wDZ5nU5!m_m9e^Ev1u zxxd+v9>j3W%qdfiQFx&YN?>(x^4#!HE;%HIi?Su_VeHTmK>y*cfq3Nv6Rv>>@5F3^ z37auArrrr2W~CAs?U({)G^=Tp#+R4V4~(Thv6Na)yb}vIl0BIe-bqE$W#630YUQ!( z^e{A{?x@Ak{i5#CV5j1Sf-3P=_8LkFqd|xrkL3?U-e` z%cn8(u*MWxvX1Vwc-Su2D6zUqOz=)D8_31PwHzzx9SMLe2@vbc+L!>VpUBVypBR)6Z_^ZG#>3hZnaJ&wG& zTxMPOU?wxv-`}s($NbOp9M2O~+6uCbH58^e>q*n`8YjoZQQRZLr^e(eLPxP z2pCaNf48wXpv2c@M^nTZ%jX*~5B5ma?zmf3KV~re+86RGM#b!dydQ}y?0RHw+0Fc1 zU0o+RBTbH&Ff?Lv{8GSPZZjz#wNxp-C%oSIier?+H$k$^%r)oF=`YB;-bSpm;hOP6 z*Pcf2C@u)nm^n?wmpVT$hj}rqU%BVhpuviJ0MRay)wKrAUAN`Gq(6$DOcLT@7C_^O zWKLsAUG9*}6>{gg9@QVt^bbM&tzbax8AxgzDZ|Z%H6wUV4*lK_jZzHji6-K@g^cCa zmgvq2d2(WzZh`*9R8)1LOKGjkEnHF)mK33*(CBBA;6f*XWLCaifTci556-j^(zVx{ z^m>Q%)z4zxSzsF=p9NpDG6bG7{rz6q#c>cEk$9;zw_`|mD##|B{}!%Up$#omB)S<3 zd025`s$re!Ow8Aij?I=X^n|WiSSO7wiv)%0{GLpv!W*cQYWib6eVM*#(f%5#F5s=m zWS}4n>6}&!*M&SamSFN(lhqb>)nqc&=?1^QAzhux)VRVntLa%N9&0?Ix&)Wer7%y| z#%MeEt5;j8GAmED>*}e}<80C0BCt$_`Wm@bMKxflLH@;RizHc~{W`{X;7HV9FquWH z>Gnj7A4IfedYRZ?HofHmo84CW8=7e}8x6);9``JR0gp3-H+OfhtkBw<*N!_eJ2#-E zyCGrp(E=Jkuk4Jcc(v@)=V4v+0>=UiOPekA@f2if2-4AR3&vc^?D1PtK7WfyM|n~0 zkFulB!|JnWJvRWB7^rFt^g-i%v%%*!PFuZk^|WcLr@Pz^gCtifOWiTUV5M@S@@}(v zzR{STExW?4t+O4iVb|N%7>#R;hH$H6Hja7m^qF%7{T@j+N^Tc4)*2~eWsODhIUAd5 zo$jwRHZ>jaH~6ugl1SFr;@=L%Z8amB!xwGwP-9+GYGm{|=YseW%3p&yAKGQ!d1H>q z`&wNotQo3Bt1#Eb?P9iwV+hW`rWd$2T+&76aV{Y#Zfn%#Nk&4~85*vM-Wa{6!LZrt zR;1dB=@k(O>;7VYNw}4T)|sx>iu&sU8(S;h>~y}lqV+}VLdE?(S?;!4-#D%x|4w`c z`AX4jo(iVOi6i#x?`i(3m;2)t2`8g2fx!~n1{ga z0_b6L>2}OX`t+kuJZX%)TI|rUIyOB{c)+faPo(N0ax*7~+E(~|sdRms=g@W(I2{$v zsM(@5mf7E(Zs#Btt^xGe5pWNuqCCSFr?M{S)K%^R6I(v}O{2lp(de_84H%TpaGgVl zxXq5@DLci$$J{o&2obWIohnqJN+4`Bj*cl6eZ@^h<*oS~Pm3ahnJ@oYXGjE8#q5%V z!|D_j)eb3C)l-+xiA>v|T@s;6o6};DozN+`%EO-0T%7<%;CUcS=!|KwqI8k{m%7)O zwgx&JUcI&oR_kD61A8$VgR4f#d5(xTN25-wBsnGNy-i(RH+Ob6S4JY~NaRtGygpf3 z?RPtUQJ;v4#_N(j6&{Dbu0p(Kr(1SNl0&ZV;c?UxhR}?^O_epZRsK-9sm!K0oNB11 zCe$RGO=fau1Z;w{Dm6c&`RibuZG}2}ZBeprVLmUlty8LM>W*8 z7&>PeuOQeN&9NklMPaMaya z<#MTZo713{VRn$qOhyR3+|aDbW^r69iE+G;qdJ~7fjGcIqon{y#@ai(i~a%pWXJs# zAH4$!{0^|Zr(r*)o5IwXgV@OFfqS@XyfuDo>|!La;EE08jL7D*UNMm0e~-zWHJhMP z@a4~qn#&@QGOU(0vAfWBj4ZOd5xWjM!)!DW?ZUP$HfZ+ePbRQfz%DSJ`jaQId#q0b z`clhUSjwRDVC90V2@iVwINp+2`y~6te!h+F-!F#y@sP;zb>05)bh!S;=Rh;rDCJ-@ zKYFs5h0%eNCpizr<-WfBD%LkoNKs8LL_WBtvHjVFJ)2ZAmm3}$5?aDBHT2n+J(rYepXPTP^)gktT2XEM!d@wwi+<8NuFN6F(C<-o` zZ(eiC=QMBBx1OJ;G*KM2?9?mfT;iVaQ%{BO5kpt#ZhpF(+h$VOLM4t4Ea-gdsm=vr zD7PT>)KjSi4$>ST-z#m=?M9> zqgwd9aV(^YqG_ zw0@Z`_Rnevj_eZeD)!G8!h?&3weC5*=)hodc+nug4?czd3J1;efabDJ^DOqa5%ESI zQ`mUd2dfw<_Q}ygFGcYSeX|s{FtEi)p--MGbkfOvv#vCWqA!^+q`I)6oYXV4ZkU_Y zm$-j%x>xnh*|0`~pr0O3*a8h+NohO$Py1f(pLg7=`(-J;SL&CXUhe8%sU;*8d*kG8 zIia4=FDKL!RDF}{2%T_J4WXw_tRDxI6cJE@j;^Gyi|gBS`tHyaWGD8#NhwV1v`9?n zPy6)#lJ?f1ql0F@D6p_ncbOC}RR}k^t4yc^@Ub*RtrEwn(^U}3iA+SWc4l%mwXSki zKdHkMf$nA*Pc&U(VCXGk=>Myul=|j)9;T=HPk0!o`AVJTg;(kfSp5|G3F?A16nby*m-Y{#zrUK~tLr9(eo~l&>xvAkFjrr%Pt|%KDTJAgtwC*y z9pY*HSJ(5L{;OhtdrIIFz3A6bXHkeKuq9~ouAVy!VT%GsvcQ+TuP}F-bO~SYc1G}6 zOnj5)gamgm?-U(z;`l4fozO&pEkg&WEgf{iaec!?XHoxZ?i9&?+ApW-cZD=f|6=YG z$*b9vmf9=Mp5tX*t?x~!FO2@lbp@_8siySla~vNp^gmOn^PwZA$M1MeL3Sc5nv}xC z-ii9*@iK}n&z;yQq`^N8L+m}tZ212=o%o!Xr@uDv1A>bpkO@S5swFNdN5fX z4@7Rtpl@Lzb;q_l?wC6?bklg90!k$Gio*NNpPi>9MrU1&?A` zi8TNgnc7Yg_RO&fV*UtMw70tpn*W87UO7Q-cV4$V1(cWio=v(;m%b9hVyYJ3?Ve#Voa*0GP|8g?9 z?w)(b>Xpq698eMxDl_iY)DC`Dcg({21X@y<6n0tsU789)P=7zP0ikMp?Tjz-C91s( z^yGmIJlYf0l@aW=)>T(k<5qO#v~>BB&8o|>*~?}!RI*caf&+#PoD_y6bg-BV(3;~c zd;EHb?&z*7nl_%(_xuvE88zD8c+JM}`(oH0*DZUpx~}mG>GyutQ7Ve4?Qb+UX6m$E z%*L+9w}#&*Dweer_tbN`CX?0i&}eg>F@K>}p3~M*9_VWz$rlXP3%y;_ZKvZ=SRe2& zYlg6PP({6XRNq#~pTp*bG7Qb3x;ni07Aw@Lo?u17Wi!t#lY#*;#P(QCk^Fvr_rlkI zOS!FFw&2h48988;ih0P1>rrpK`9=C-&Qjy;0?UW`xofCD{O)&$`$hlg=;+7*KMy2^ zd6Nm9RvSCG2-Le;;7c&ZC>gFBv6qgW1JpPywMO$fukzNnDqc+dh_IETUwTH``H&i+O9YYu%^-->gb^lOfDlvhLXwtojb2kCbttm#cjQlB7+tmuMgt2bM%#fEktbVKszzu zg^~jIOurX3$J=^SqoDsoTTIl0L^SpM4CMY5QbUDm>Ul40|1^UpJ{+U(bebT-F!Sxg zwqnNTgYLiI=VNm&pD(`?+hph!*xT&SkFbG?7}Z=}DT~Pg@WTYGRt5&3O&ZW1G$-c! z;D`5!Ptz*&KQ=pp9v*8!ZQtqY7wG7DC#5@$P|){jW5WYOQ0T9r?8EPrFHw-I-z}9H zqOgj#R5|>ZB9lzXlCJj9E2yq;$*1b zSskjK7{Yc3R}WaXRzYSlQm!cFJ|AE6`^TPj7cro@42SBh=CIpaX|~plfI(&T4FGVu z(qpEs!ikL;UmzkW&Wbu+@1~ng)gqTEY#UxjOE7e>1!PG9suyv<*zm zpojI>@odiAEv4nvZ%#uW3Uxi26T5b;q8nCMuqzhnZuA3jDt}ApE=wTt*k`c26$)Bf zs-OYyYcp7F4!g0n#_edyzZi^0JEGBV1fzz9*4y6~`TQHB?IK_Zd;H~tx7m%3^7dA% zqpZ^=J{h{p8HvodluJ@&Jp_Q}S~E1iHO=MCGh?Y}G!=^l%gYxS_eHuoVwQ5hx60@@ z^bf|%%Z(0)(NeyZn?>i_y!GeTHEk$GtAWK6Xqc-}K%du+ZO15N@6t~0-Ll8rV^FNO zzs~HltiIii?5I!3Jpms!#lnX~6{JDq6ZiBU_lj`CO8&LrA%=>i6CCx((J6t+sddMXhfbpt4Vr-tv3}xOD&Bk~Uxr=vg7?6)5uF!uoKI&ID?kAI!^lvMp%DPT=Cf$qO?Qj^ErPL!fB5nz*nX|oj{XivqT zc+06k+ndNHafHq`YLn&akrA#Ou3*^)o(pHuZ%#|O3HxMqkkieUDCAS^T(LJ=*r-S6yPC~`gKDVL7C;J$=sqn#X3b$yMHvjPvVG)&W)SO$gtl-lMk*kJUI^DA#qT zyfu8fA>Cz$h+1ogQeD8J22yDi4m!dd3r;W?(ex7{vtVI8XFc|W;<6ubTh>=q5E3Q|2(CkLa{a{HkaWn@}yEH z^^&}J>#Z-E=T2Q%O+Qp97pLFBYpPe52PiRM6jM~t{PP?QRW*KTT63A%j0*lA?HVTD0H-A#$Lr1snb}MQ~$aL z3J-RIs=~6C51m!$R&AnuKbXJBCOa%6P}vUaN74rLrEX>f3Mwp9VjUx}vM=`8QO%@R z6PvVS+~5!;E`f9VI4gxQB5+hEIinTqsddIWT$4UuBHOVZtX^3NunYhYb{otA{#wG@`e!Mf>4 zqps!-*ihg1`chgZIsb6bg;PO#I=qj^B3hJahGyu79ZpVdLK*lhI@D^g6dD~s=Fg!l z)7$XSHa(#oMdaOtnOBu48*Zl{ckn zeWArHl+&o&?$^h~kY;Q>>4vr1I)*=7x!#H-(R~zz{nf$JXhjHas2< zg_E)T;w0|1u~%qOu{j)?7jM1kk@&n&xaKBw8dE6`dcCt=lB zAf54Ogi)}U4=BN0FRfXQV>hKrU`wg1^V=QWt;tkPMMGkGTWwh=)*Ps)N{6q%N4&PB zJ6T`RQZ6jbu|(GsjmD_2sk-v8v$6u`7K-B5h?Z7F_*4eAVaW{WYqn+3seT%q*{kg=WaxU7si?q;W8{=} z;8`aE{S_M`;$RAnFyONeY4?;tOJ7wP;^X(pWOd<)FvirOoBJ9~POHPVL~_lqZ|iul znvdW&Ap|_NL&Uc_{Qii~C$aOa9tsVcW-(3^WKw>-vutjJSbi>%NXk~o9Lav!>cxQ+tK6Sd;2?W5A~U>` z1*M_fuvN(=^TS!iI-ElYSzND)>iV%5-WTKpF~y@5ofzHdRAWbQaBK<{UUZ8Vy;x5V zYduX*hMYvfY?v*x-p!TCXV>wav5s}@nVmS4l)&Uy39HyNqTsBN-o7*;;+* zOTPuQly0U$dIR#~(X^cwuh!LJca4r-58i@33J90H_cUAZ4x&Y4glXtN)4CNdj}A7Q z2mgmbvL$S&gQYMnq@}LP0z*&P>=8LtD(0t~Xh0ra7I{YOJREZgZ?n z2wP&NQPlR-I%8FyfYV;xQxUwjMnCmpHPnPe^pT3Fp)&SH zYgywoqXBfLmB%^^B3w}s7KV;k`Lz17@-pMJ#xiT|w5X_>GsB@aS9s(0YKPq(_f|Bk zju~^XaWL&xr_;ZYKgLnvZV$J~)~e>^a$DHa3`vru?U; ztvd9-)6C`5h0P*-rgAY|SWF+iIq-G3)^~-W*iLa?6X@X=9 z;g!z}vQf9lmYKZGUTln*njda{*!?-Dv+Og>;P~K%$Yvg9-!fZS$P~{uKg`{U#ekQ^ z{g^WOgeDv6S#W+4b_V!Jgm$bLDaFOihK7ba?)R<^-+OO(wfFv2YZ{h)8BX_o{C3Ud z$@{QZSKKD$Wt~nd1o3=IdTH&8cio*ho7@=}Zcth?j`(LoUT?5wd%Mkcbuw?RjIWAU zblx|sBiMnXt;IB1v^8RSw(8oOIvC{H#nt7AvW4I45nj9e!rM?AzUF>!;>qx1Tu-ao!#f*9Uqdu}&3!}3^_t_8 zx3q_?%NjLNB8Pg<73zw$PHbR4MeVb#1cyH@!p1|+$8ruiALHK zUj5|#tMo4uf?2T`s+;sEnvrmYW`Kd#g_2X-kOzPCrg0`xUpA$2G#)I|E2ghnRcaP* zLj$-cHhb}dRa51vRrhg9DCU#PmNh=pxa`N+oW4Q>Fy`Si$5;L$UJ#F>zI5|*R&30o zdD`T-nucg2JwT7pdubPaoc7Zf=`ekpen2mxW{d09(q38VAzt(RwTNdc93w1rk)B0P#&QE#67=Htr8p)5Z|d z(6sukikUi3a;VZm7bpbi*R^y5dNmcQexY8I1A3+1jgOO_Db$}HdZ8|l_3MrKm*l8k zt%%Jj4C-wKiGJ$gtJmdbdM76g^GP^6ID1{YxsP(nD#em0V24z+*$iUkHT* z=6?PrDuh74E<^EB5N2?qG%TS7(T#dawOx8BHP6*9nwbQr>n%J%rz_G$Qke;3VUgY# zg+WvpAR?`Y`2#nEqCBfl^n2BGW3=iv?dlyEAyZHsXiE&O=z=1(>Q|J&{gA0dUPh*eXZVUC6DU6$!b;kvIV@eZ({9~Emyjcxpy#`m%?T~u$j!t7J zTNVc=D1CdSQvAK>4e#P7&@LFd^TwT zEr-R<9rPx;m$LM3jJd0tdh*9V#=f~x>K|j>qS!tquTl$_!i;$ple*ePu*#JyLa*&s z$nu4AIxQ0qWL#6=qWZ0`&?{<9nW=<2#z9aF0dOD_yTirX*BL5Dxx4eYa0v5EN^GB8n|c>t$j=7Fl_T!1w8&c zD*1E!_wQ$s357maI<=__XHXch(!dK8ztuEG-wUvzL?LI{6FIxgA56{Nh+C~I(sjAB-EM+3Cl;hI}PG>m| ztSb5MmSK%8{Y7=z{whKG*V~BOxlFTh#F<}9-K46_4t3+K8rMI!2d-jhBoe_FO~y`# z7y9K+Eb(oqN3D;f{cN8zbP{&Z!&r-;Hb!vTvS0sb71BjGJv{7Awav}Ag*Anctg+FB ztxJyP9C&B=4L#xUvCqA;dTmd*P?sed5JAV&(D?(~X~Sx}Lk#Pja=`~9w)QF8Qo=)bU z(SbU_4-;Li3oKB@>$M*2?5s|us^6i&9t&E0L*+wkI$3`R0yWsL zU9;dF`|+B@XMJUS&Phpsc(|#LA5g^HI}XQ4{Kg7mfUGL^-*Ka6J|4fftrqc)0PG ze8jNE4^cc66}6x>&WQE~D;=#GP)P1V+Lgm-KM9mMksL*-6a1Zge&ru%j1#DtE37Zm zg!NM2(2XqgPr~ts`t|nIPQyb#%X#J8VhySp zp*Y2Hq;)Ya^M1_;hoATd-A(Ig{9GugHYT|Nxl|}+vM|VasBvMr&{?#ZzB4e9|7gZM z+)sF{^H&fA!2E&x66ZXpWeL0oUp3JBJ4|nQuqP6uT$8#hXNpsJmHmSICYPO4;x^~H z^P?|ty)cS($6>h6*p0*SJ3n*$bDR~8-)LO{odPvDf;{2}*&5MYi(cB`D|7^KG=9n^ z!OPIkb>4(J)XM?Of+=_`e*}z}lW=a>#E0+29MwT8!+{65a9biHJhXJSsP$B|R_TYU z4pI=Dkld>pOU%PLRjwN@Kc`*?KE}Bz)(iV_oif;s!x#P7t&qR{IX{+dO##rAt?51t3Y`pv(uX)-b-D6Rw@Smy**p3t9a;+Y21EPHQ!w z=LM;s6Ek5g(1dm5ZIG1Od5!OF*E9jVJFIV-)yLbh699Rq-CNio!#0^WIxeuOosSG4 z0!*Vg8tf?A)A4rRK){y*{n!tIKfXycKY~+-&5^q9`e0I)lR=nlNOmbuU3lw$UiTN7 zvT~EjYHDo2K@i2*+G=i~Sj zHN14|{IJb%&(p9Hm7~g^HxK>MtgRBiX|s1c4VSQ@ z>C@ZVrzIEn*3|Sa##f4}@Kv~~%7V%PWz^%d)zuX7b2Zi1E?<6abxlDdB8IKr4Ucc| zTF2t^y6^|$PvQ&csk}|Wd)U|r!${P2%CJF)U0bgOd+s=b+=Z`>R0eAr8*74Fo`$S_4{Q99Y5r>5_$2Usemau|(%`JCBvYf^8zK$n?Cw0_llV1!;6AkmNq9=a;QP>QKo=HPi$}*VT1{ z{a*g3L*q&?u6~49{}kisSV1P#lHOnSbh#Wj|6Lc4^0&revN67jy3(dpT(sk0ZsVN9 zoMq#Z$p5t?I0VCn-0pGJuP!du(PeR1Jc9KK^uSoB;A?Pk@J}{6z`0Fq8Gkf2<UYcSZok@gcY{@S+r)00*v2J7Am9hs83f7jCO~i%n-IV_36LswU?u@J zBtztElAQ^eOp=|d?2^e2kRMBaUCC~S2?_aaM!o<4Irr*ORc(_@b?fTt>gwKe&-u=G zzQ_OjzNR&H*Wq?+gBp=fj#d}u14L*bHw@KZHlobmUZ?wdn-@t+Pk6I^bv&IOM?!I; zhY<>fnqg~bM`ppl6_}Uu0?|Hnu`yvU_i?Nky#`B=B=?=eMyEFh(e z4ue(muyg|!@*mXOeP{yuZVMgi4J4P!pD8cxwD**QLT!`TM43%W0<9eImJ`{XakGE|%}(u{#U6!Y1M>LTpG&ECfFr?r;QTbPsK zi44B%@5lsFa*ZGo_sh^^3y@Q6z^hB4X@BwHW_1kF2Rxz6D z^Y^_*G^hDob}jVt(?^X&uahv2PG4>6$q897BiXyA!nr5Jmz=di#O027y{SuL&CK zUlp!#rYMlf_;3@NNlyuoidv`@Wx_x$t<+4t$vhG?CTdetTKX-9p`X?bBbh@1DH)s? zH*%hKwVf%Yi~jk!z?6S}-d{|Y1R56bojKzR#L_$X5q}eWgmm&qaJyD3WePyU<5Zju zXncX(!-m$f-CPT;l**&pu#`18ORZQEBFTt>~HLHPN@yGE~*iOt<1S0OI9%# z1oHM#d&Qrr*-I(jlC#j4FJT-VCMW>2jY-?&C=w828J#h_h$t92Av z95nkD<8^b!x!SchJ7&1ypO;@K-9^#33zEzcTN8JZS^67=0ixJtIToxDqX0~(sRU#p zRhVb98;neZ6)CLrHxui<^7-~ z3B3T`NBTirSk?eW-VrqpZEr_1ZD_E)4f;JeTanBg*$Oc=Wibe>3z$S~3>1Bu=R2)^ z_bvcD_Okb8f={F2vRZK1-Rln>GbV5Aeamdaq4)p%L&uYox9!PBSZlUL)8I~gdX*%2 zbUoydQNY$E<>28#+t(C@^aqCEO#H81y9V_BFqPD5@8=hIz)^bS{a%J19hSWtkQhbr zqg46Lm6fFYZ>+2wLYuvvl@)xW{;RR>&jn3d+909O`t&k0g0r}`xw(FDN}Sx?-KaJX z&WH`FWFybXdm;HPa&5lMotW&>cJMBH?bg9t;QG)Tu(7gDVrT$yT&{ON_=DUJs-jiJ z+Xvx&vv|sTQG|suf~`dF0hU0Bq>w?|x!ZH^yzrJ>=fc%s?zUX_={M&(@40GT8>B0J zM8q7S7wYi$zxd+Qk8C3>Mbut=y0-nuM%QWw;_Lt^8p@8jjbsT&@MtqA|(efTr<2J*>Npd zr;qtANw8v_A|-^o4dAlV(M~KqzIZEq$H<#J30EpBB$bf)2Y-O!Z6G|%lHqWA&&;l{ zs|q6N@VQjmH3-bmSMUTZJgW2+mACVZ*yoM|f@FKUg&MU|D#X%~Zl621b?zMM3k-a8 zyp&q631M}DcS_5Ep(8H=P#0=ZF&Yl|3v>)IU3Hzv$G0zKYCb=B%86>G+WW`WLg4mR zTIe4Si)N7Jy&U>_+B)ctLQ2KBy;?D z1}`#9={o1y5KY&5-AJxdtK=dwm_R>~89Q-e4DL!7)+>N2;kOEcQp#8}7TFj2pct$k zHydW9Ug!g#;+SceanNfj8@q{U2KnMM(F9$kN;rB>Sqo3Cch}dMZ}*!>B%-;IKRFl` z{$X~$O{3ye8r6;9`cyiOYS%W}MT=P$EkpcZ9Khk>RRq$wG@GrGSHX!aYai-S=>lt1 zI?`vY=El#ek#Sd{3BY0iD-9Y1dAPSGC8;eGvr;3|hEKNl{ZKlD|H4m0v1*T{?=gE< z03LHfUb(i*nw^b`3+QmvrX#N3fa^-4`a#-At}S8WK% z%8uL_rj;JtA|{cL&mmWnNh4Sj5738Yr-@_10hNwWgd$GIK}s;IMAECN#@^!3o3L+y zo0hPARY-A2NOefRHaizCbS~sad-2KD)e9H!f+u2_GYs=;>Q*Sr8mEqpd|y;L4J5dN zUROa?2$dujdS*_iLjxCKhnNH87P9evsNO z%WB`X+8{bD89-#Q^e0LSu2dSZ71bM9 z6lrK~>|m(e7i%efKBzm-#8!Xql6x)}K}FtTx+TFd)p+94uXyeX2TrHPUUO+S;JYjR z<+b};e@$j#Uz4v2K;|2peA~HtbzM0s)OLq@WM_L|d)St=4C>tz9ciVrR5Jt7R% z3CLf^zL-@#^Wn+UX_SRuT8N?O`eZSk3r+@e>5Z$uKhi-XokN)FSH@DgSUip&jkU($ zn8?983C>8}=Oyul{urKtpZURm&PWo+TS0&jk_KRO6>mda{@^peT{J)bki*{FLDde_ z^7gvD@n?c@4`NI`KDUSaIPCShJ+bYpSKA6YtF}zp;p=Qc!1L-v`Fgjy@r)7hvQP|q zmE~g0-N8|cyO>6=!8AgwVu^g0l-hsigsGEV(_m9sK^STo4l5)+qit=R!m^ znkVXWXd!7?TP(?%8mk@&qf%lbVR{}+bO!KR>=J7_3Zk&%q1uCkVw1qQ-Or*P6z4`{Z8UIT7nZyJ`O$N#X1UTr)v(UC?aQq z8%TI~<9SL^MaZaHN~%3v*eq5DR=~9%UcC^ee^^;NsX3!&07)z zz+T6lu0-HdapAE4J*z0X#_wX8OrG(_Cwt#p8ni9wb-Lf@3lvfJ2V$b%TYs@fu7>~6 zrOf5+n)qKKR{JHek;Xv@T_HyRu*T|^Woris&1Jta&J8CFcj+FrR|Hb1rv8p<&$r{B z^e0@eo_h7>m0N3f<(#TVQKzm6_5p9OYK+>RvzPq7jpSyx`r=B!%Py5Hh3?)C!~&Y5 zRS6KJ(N@+$U<`?iu2=Y(b~$P1q6^vuo-*VwgdB_$QH=y&LANW4?Rcu@@FG8UDvn)j z>5his7?IgZ8Ik2FkQ)H`AzQ7DR9p{u5Lq2J+NpRvwE;=XR&DK(D6tZN|6vK-Zb}Q7 zDav$3Q?d*gP*{Qj;7BFbRnRUSEkUsMGNMcCO|n+j%Z3nr38H^`mm8)>>?-L^hgF-0 zu#vU7q*}!#g^E=XW~7q{ zlaPS0hB_H4e?hX}u3cr;MyU+~dlwZ$%`1fQExMjeqR@M{wzmgcPn*H0u=uY_3mG>j z-Od{4dd=ys9(J(R_Uk@NmEG(2-{dRwpbPm=^g>(qqtaI|@zy)sz>tI%bq?>&sw(`U zL?N1>u(iZL+8rP~8mLohj&&QU>&J7AYO>YLNE>sr2}q!7p%jNy8(1H< zXq%^~eaOvRR&zwDphFK>E?Ec6_H~DE-Md+}4fPLq&pecPrq>y2BqZIT7HpWUY!>wg z!7hfHN|OQB7>)y#HX4HlR%@7I4Ahwb2vgB)(VXp=_ndrCaA1>eUc+*-E?V9|H2|>$ zf5>=+Z!wot5VWv`{pGSBwiP)b;y(eptWuIZhF;JJRp#<*K>ENN{e3jSAonDZ%Y>EU zg_Drgv9T&E3-TmuVuQV?84h=uat@+&7*?9fqO{!7odQ-x@3JvgDY!L<%i#z)ybhO` zag`he-$bldePgv2oA4DJCD)8_;k%FnXKC(2Wz2XDBou@KyjQ*5Sq($h3B{mt`V($< z0t=8o7J^VHbbB_Q^M@lwYJA)k)Oc!88?F+>7b0LdD90>RVZ)vxYGgj6nTsyGC zNL{#cxDa!73&h>Gpv2)iPRCzTZowGwr!=D-q<~cYNIyR8L{=1nWsBhQC6L4s3Vb@o z&2MgPb&$Nmw4l?P-s_{OZ_uBRAQ0UE{QHgjv-XyWn}7FrZ-$C#T5jw%SnD{xdDSj* zJ>`Q{9xhs;c?4V$4aBOLM8q<}mqC%ehsk|mk`cAt)@C)}-QhRTLFfqCYc_cgYSMp! zdwc@Ec^&td!jzMDFhB-?kC`_yXw*}8K_y^dfW;neQ)|sPo$^NC`OYi~`PIbRmNKE< zZ^Bd)@Ls9?_-0eyuJj#oTc#2S?=_b);;dSZmDS}P(5U%rie3(-VD>xZ1HMN3zXGh9 z#C5{@+`=$yONQUVFi<1nU6hu&3)Y^HPsWO6u)mt!r$R)em#|1W2Pebmz}t`KCNc8W zBJpfPBr@L_s)`g1?KX5QEN$u7PAt9NY_7{4Xk2%o5^1e=A)miP@;~&iVxPO>8Rd6F zPF)hWA=P;dCAe0DIcNbisD}j%+dJ!btQ0OSBz`@4t$Zxerw! z*0u?5-SWDBUvqf8pKYVSmGZ`1mxx>qe(Q1C7)#KdnJu7##NYt2WTfRHGocF?ItGtMv8awmWO+5)u-O~ zK*hVXQhTN~QT_r$S7_E+tu+c6ot@5Ft226i=}%z0Afm95qQz!CCS((T_ZRe+ zE`1RTc<=YW4(cRN<9yb@A;D$iQCdm`_~JYk-P88Q-s*izOZQ#vx>oL4Ub?4_f^NMv z*NF$;@Zbqocln-`@5nFu?Yx~->6QL4(Phz~d%rCpaPyt_LjV1PxE*`4Mj2N&)B=G` z4=5bN`*iMU@vGmuGVzSCy*2lqi5Kztz2ClqgSOmz$bVJ;tB56=09Q~pcu1QJlQGLS z$S5TlanX0-ntfwFCu3#$#c*Wt>d~mSgGe%q#y4TFq}6H|Wi?tM+6Ft&;jwc1jpN$P zHOh*_I`CwK!Hhf|x^?Cu zKkP`*bQ+4$D`Pr0i*xvzAse%2<#gCN1`jQnz_A7aFamM{gZ)lSLMq&D6K zB(nn!r=--{U&&uHyus>=t%SPZNc$!3)T%tma4V|Qj(!jxg1Rgp67)DO&sD7E%6C8s zgYkC&tguf8bB}8TR5nx$j22AUAINQ8eV^*9 z4owQu(*m2{*Uo-$V(aSP4fPq;z>SG(d7n9)Ros=gJn# zK7wVM+g6KwOl&3$cCyaN-6QDs9h9!s1K%J|2rW zR-&$z@N~=wWtMxNh|YvpT+tN=k^-%ag#?XO_}>&0_GmCWHJiN^Wj+d#_lc=&Flra7 z*t1O6a?;`WFTPSD7twP;r!TZTAAHW|4Ca#IT%zO)2Ip7mpc7bQVu5&M+&2}dKb_EH zn$`#u>VYZWc*LAP9q?%vWnM;JH74w=v?LzMbvn66)E2c-_#r2^q-Vu{-Yc5s?>NgA z?3`-iy+fyp$)Sr3ez$4;4iy@;${9QF`t%KdrtZ~&m0PxvyiQxN^Ov6-x_V>i_jnNA z3|4tBeq)Qvh5M88S%g=<$*<++cG(t48Q>CzxLtnx;J$O#)H#?sxa(JjPqFTkrHzcp*_|kVi}PiX>TS`$7U<;--`Z6Yh7*>mxdCsd2VjTcCoi9R&sajq~+9 zWx;&?e0fW0n_GTmaK&@bGOltZhOr)`q298x3o<5}S(a42dM~k^#;Q?R0d#y!Pvm(1+F+;=^q znXd-XN8Iqw+<}rFuq-n41nCSg^*OE_lrxYQ zP0eeuaYZXk7qlzZ0+Rl$(vne)C6z*!gTZ>LV$@CbpVy}@I$@$hB^nZyX$%y#w65K^ z+btj32BJb!iTwEdcs`Lr8d;j`%);=W+~25LE)E1Dtn$HV{M&?8)XQch{Qg!BwNKTu zfjOk_btJTa9UectK{oa10omXCn;^{08(k!R6Z(PMnsOogg$R@qMjOBuFz|kN+@Ke1 z3{+sAJ6I?VJU8P9c2vh7yrZdmO2nXbPvweyrF*toEZ28~dv==b^(In7FeAYsH+4uF zx9E$#duV6&DGVwh;>QpqemG6~!%Rr|aF zuOK|PNGYJc#NrMvp$0_RB&KL6HZ13ah@l6}tlT3nFb|W52I->4!B|{YZLP^)F z<@P7Wr>Dm+@cRo1TsS;lO8kU8XL>^O`{Eh5C@d@#ggX=W`LzkR5Q%Iyfe0_O56(Dl zI98^N6#yUP3I*@EN^&cm<}zPkQPu)OA#|2UMsfp7BFDR_5>$^raty+G{c7ZmhiN~@ z9y!hv*WY+7bFM=g1p%a%qbDGHd*<9_oOb^5xtaOwk)sPloF=kIveS1@XLBd7 z!9mn&ZOgS2_a{<5fR%Fs2$e+7H`9i~2M z?;=wBi{Pbk@KTtGVC4iS(e^>GB)HdZjp8_^l=?!hRc=?Fvx<66pPNB9hKb0PZ|Fwx zguN`xq- zYieE+a|tndgX!VS|0rNS_|TV4Ir;um)v)^ZBe~#=v&;+l7neifu24( zw+6ie=LI;)F@)z~^X{Qb;5pSne6v1u+!rl@D&M zWeUvHg22E@JYRg{8((G!wkEd}gh*cywAnccglgck$G{XPk}FG$0S=oaXOcq#|wqyci*Sp+NF9)Ow=-Cj+xW7&fqw|<{Y!0{|QD^_MabF zF{O14_Kx9x2;4k7nQOIjla1R4y-_>i{(ON)3!nGA`k2)(iVvxNElH>B!9FQL9W&t= zuy0CHt1;T&T<|F?<Xp)AAgSZ{$D~mP2+i1871ke zU@l@b0N4R<6{Tfp&gQ)gI3VEJlhI=ATYT&fd_{cb=wB?JU!Hc@#eF&Pp5FiVzkFT@ zw&5M$obYrhPGyWcLwBBbxH&o$X^4Kak70qMS9S?=3C% zHulu$C1ZcRwbhpq(KIYq3vuC-Ra102xcS{XMj!B(hh zoJMCnG~;Nac)?dI&F#`G(1d5NQ*E^n5WR3+RwEvW^_#YK_L=Yiwl( zIi&PDzwp~#A!ub5c{tA zf58rS?i`-e8WS-ok32VeHQ1W*bi5Ynov40B&dIq{IrO?hXG`BHujLzDeH%@^>yR6$ ze(blES;P>TfaSxYA^HH!rpd;dbaGf@U%sudjqdLQ)z;JKhukCk+bR!sM>^x5H+I0n zY~Zh58wyyAb!uzqkhKn=QiFw;U2V-Nj-6l16-8DQ}KmM+f%Tv~5L^kCyARvGWg$*A}dj%e9nM0L&JQB}8lgeaLMLlUG z{zEZg7>Oc2i_X-eZ}`ztGI#%v-k(dFZ#eWQ+H8#>`2bdo{ak1d?T{$r}c4DQlidO;qGZ}>9^p${^5O&vPr}MJI{VMF(?U(Ex zpp4jlMMIRkIcLEV0K6?oyvqRGZh}7O0q-EX2XSCaQ=Q@xK@c?<0CuL9mZqAr!iBuv z_3w&*3m!n5D6GN_1Qw$!D-AGK9d=q%l(!_)rl^&2SFYqrHHoRHEfv>r$>qV@AyBLWqAwY`s{eyjQZy*l@T@$m!5bbpIofkC^z%is}iAu zHG=|XH-4ao-r!;eqJe21hWUY6{$M+NXP-xY#_rIVBp zxdxk`oEcJSFIXG_GlPT#8&XATN|ETG=c*TLJqAibmqZ+H#DBL2{ikYxJzva(pb;h^@=#YUBRHTKOZfGy6R{btJW zBB~_h@n%gptsC~(&X8?uA1`|)Isqi7&R{Zj z&%q{KMViXpt*xDdcNXhb62wuuRJ8Jnl!B}p15LeQ?!nudB+>=_4x|El ziX+Mw4F#)0Wm&S!BJx%#od)y*?MrN|;}5IhpQtyeZjc0Oy}b^kcxp_&F83&IBU#Px zcsgVN4uY#-ed?pIfQsv9j28=Excr6AD9Q`9vx13W@FSPMaJe;rUlE`6H6BmMyiNle zXI$PmeU4}BT0cQzWq;YJzE5D|{7250L9r;K>DhPRfpNC=k@Fup##18x-yUrOVliK1 zqVObNVg5ZzgGAxxAzxu>->+lEvD_^nFe-_tC;m2XKxzveEGJpr7;aEgh3{Oq>4`|lt7+a)B+>4$ zZJfiDG!+UQK7_&{c>0Q5r6K-^jceDgQBdUORT7#d;B^2Ji#b$4R1j|^I9!bKRHun; zfD4GKLA@V#+TU?dBjUq17zIZWk3e0Gwks*!A|4jV6C}K@ZR{X!2Spfu8aITP2fGE| zPHHk0Tr9e@6phKeaN5#FlgN%u{p+d(!wWob3YApVyQhENQvbIbG-$~+RrN`PE4j1} zN%@wr**cUQ7&agVDr>Wu-U#*@Y&jrg{e1Kjaf`XuOjc z6_~V)fAoZ^%pSqNQ_1Ao3%VV3N?`*aEA1gd89(F^Kh**JVUKMQ?fC0(pTuE zW#$2Z)|qqwAp!k+Hint9jM1rk$AS}9+ig8#d@psn2xbYZ z8&7&+ltcD*^JoN=GLt4IasL&_Ago7X8+b+~2n;q0z7KDUn#H>MJN@(#a;Lb6@m*Y5 z?SCz72ohVl?{)XBI2@>iSo6DFd?kHuS6zivFR8a@RGc;9h~q)LUZ;+Vj{GgI5e;j0 zyB>7glR=lGhF4R8-OTblNfjAbm6niTys5$l@tB}dJQ?%C(6iY>)s=%84uF%7M~g{q z5z$p#4jKrzs)H+Oz=3XQn3Ird z0DT&K`9k5u>X^`{rX2o2+~e{fU#=JD3E^pg_fyydF5`dvr0Qf6b8{bsC{+xPaCLpk~hsf-L z!3QPsVQkD1pDJo|ac|re^w{m8$T%!UE?;UTIQ*p=G7_2%f zZ)h%o_eAcJSs8|5q+a)i;+AT=VN?wK&l;1pF_&*5rMc}WjvUleal_{bgbm&2(~WSz z;WOeXJ%~cecDI(A@VUlnlSWvrGu1$9f`*-mRNya7mP?YOA&MqP7*+sI#J^E%w30U{ zb0~R3k`8KPAmhRI@Ze+Ilt@L#n7U>jSA~MhG z*QF?^BbWU8I_s>+MI9RnAK$~hq_YR23}f0=MLM(O08@<9$sp?rVBJFKMN#IBs22<1 znRG}Lk>SbAUkDcko)=LFdL8mO_&RU9)q={~I|p747&boOSPwjMkYz?mT5U)hYaQUW zk+yRe8~84wYeNBQSbD3(x0%a0!6r=4ZEJAV#tI;{DezLR2+G&Afr~-IuHveQd)me{ zU90XwkU`|lwoGPZu?hxJSkH~c5*Onom<~riA0Ct!N8WKR-0Tk|%A^{vo`r$0_$Z$i zVmJ>%yEnfT@cSTF71Vi*o=VdJ%cV@VhMuBtM+GUUkQS;b)*75{?V{OeuiTi=eH~yQ zCEjAmq6fy(3zVv`KR^<#7+jD|Q0<^IhaxhCk%JW4QG7?XgAzd#>&iaT92$d+5~b?P z2p+;hh5#)r#vud~73=eMtY-t{#Z9xbu7x{htFw13xCXml9l(CJ_kE?#+8tniEU}hj z?}6C>$xbj66u+Xr{)$aNR%FQ{eqnI`!<%9y8D4+oCYgQOMW4Dsk$^fHFma*qtvNjl z?b?$UE<9QD`>xx3eo<{-Tkmw%uOUfjz}FW`RsIGlEr2Yd9yT(Aa%QVar?5#vxE5Xi zuVCr;6~Fn`ef!(rel_TR(CK{89qd{=x8e`utat|j)`M`w8(h}~+rA5W^I_NT{Z*$U zs-44c^Q*Ui__hyy=(Z1&uE0Mq7UWef8SE965OlcE5OfZ`fDW`0CJ%~yBLk3D=RP%c z(c0M9+`N4Ga_=8E5RkEhzTK+`H{d8~Hn%7aVrLtB!X{mg8yn3Xe762@FU%LLoeHQ9 zJy#Seg%UE`(v8!Ii+A_F=YR~>xS+2Iag%;E@!Hc#>@a)oRCX9W%<45RmYPK#%tmdIg{eu3KZy6|4h5TuWdAp4O1w6`5!Z z5vu48^gg8*Bt#Omi6ickulz*be&K$X;dIv~Qf1F{@MI}p&wJfrd%kY>XvkjUEsn>h z%L~W}?JN31k%`$%GFqtSSM#Z4FzKxM{E1j7;MH8Uew#Xk@5NzEM3HT+h!`LlEej7m zB+SM#Q!;Ju=(j|)b9&8rd^+4&?W|_2j<+XY>zzujVljyuwV9I$!rVZrUVOmp;hw<?b?|xPyG*n#g9rq%{<=@#^A&trpTj)`0uP zg_^?k>{Sr+5>lKzh%|*b`iAMH>E&rSdo2D(6_}x?(Kk2b_h zH#t&~tw_po)AF&cV}IB>ckUcKg&&F}5)ttxr2m8PwAX4qj>EjJT0c3@G+Y(30u!0R z)~`Ifby`yHNUkUEz(T$!1M9Jtwh_~B7PjLhOjT?bfKY;E^9VUR&O%)!u&O$w7bV&$ z!4BwhiU<;&UN+s2hkVnwE{UCHr?WE>BJu%zs-tM3lC67xuS9L+VysocP?}K6$DscM zL)at^t_cj`p+^Bcri{+^EA^_|Z$D=|;_K1+8@GK(IYbLbgIM13icK2aT=oC=MHA~k zAU^#(M~Evn=QrH^Nc@;Iq<9I#kZ>11dfB*ZZsxWlTGey%{*|Lw$4#Hy8$LR@T&k6t z)7sMI`39J##qXaNKP%-yI(tm(m8=AfRm{4qqk47X`R6CD>dL*>*}0l~{`uV1;cF;a zdT@<6V)W5W0|;ZVR5Z;oatX0@?drrwKRR*s8ZKhV{sb_jps*jsv-Yh74B?RIcm;CR zlr6Qss6*KTq7VTNIu4x>h?3_Aun}qb=nU+sKPj!I$(fr%WhkBW3_|%{UIH5Y9n@PmN`;4lLNhfIK@y6Ti!ydHB4MGsD+5W3QFhw;Gw=fJQ$*c0fFe%CZr z->A2HMm~|RL2meEtVuAxl_p@ULZqMMKQuL*5Qw>x(I%o4y5bLtxLpr@H0tZbJwbO1 z6!l%loFfr%{Zu&Se|yps|0ZSex5`Jub-yG2OnhAGm{`q$mH{VLxq)SJ#Ugl`-hSYL z_AL)QaEtjan!}%Xl-Htc^Ih?2$cP~+!!vUOa?h-uu~$H;ZYcDKV3i1fC8G|VAGBp4 z*!5365$9rM$>H|67r$73l_%<0sJo+qK-B$x&FZh7Kvuv)8RRJc z!IK8&591rMSHWaSL5%+xlqGRHuxWd>6=xu938 z=9@`7c$y~2oVE#DocD%I(Cu)t+9*d@JnS8yFYB2gsVKagghRpfj)ZA-OPbi;B9*HR z+9%zX0~-m%&NZZUAKaVzmh4kVSB{K$&)+Z$(?D6k(mt% zON#YI5e;l1+bA~z5kMPlyp#iUMP>cp$WiCw@K8 zL}gJV_!O~MW7&UkOmx7NIREi%isoP_j04Otj75a(A*W4wn0P*`R<2QE*-!>CUQY2} z>zaj^x$2>pKM9=!vFc`CztOvx>1B8Ncp4>#4DJPzyWunR&5(!Q)_kg;e3`qO&$zDc z-fslv^iUtNbO3aa8@8f<^L}%*!#a7i7ozBL^vQQs<6f>$%vM>AvrPWvDNNMBw!u;N z&uQHc-%K-iwb_+FL~GX-@wEHHYT6Qp$Cd3q|4(Z9!4Cf6A7Qk^W3SxrZS@EyZ5((Y zuCvPhM;p1l- zmoGJ%Po`31`Mf@s3arh}S@6!?g%i6cwbzfQ$Ivwv|LBUFaA#(o1l%0_dc;y{Kp6xK z#?o-H+=1&~yKeIYgC1b6f~{8YcF75=Lf_h|1wFg`=0fXQ>w+h^0sdz~TySj$<*78n z(jwdUee@k%40#jP4aM|KkMwr6Gs*-8d`KmBDXB4rZZgbHm-~~yPl>SBN>#wL(VD(q zuX6crqo(Gt_1284H{;FCu?NVR^Mq-`3$%vDt+A)`lA7Z(>>;otmZA45MP~mO8zy-> zdt2211cJ>1y>A_I5N-pR)3t+?&rsNylFiCM+ffPHc%1E0vJ8?Ip>G*}HV9i$rHqfE ze@wxIc?P(s@m0YKgWZ4a{|pce!5kfFz1Ze=9%XdZJ)rIbJMe%@fI(;Etvf;#CT(!OfUatCKGKge&`|rXw*HQ# z2AaP$-%MsQdNXsarrp88*e9C<-O5mwWHt_$Iiyq{aPB!)@igX$ysiB@W;d z42`5}H^Z;NH@}ps6=In$cJoN&lFvguj}>Z0E#LiOMw-TkfH20H`T3g`lF#V_Pfxn}Tyo*2`S~+OcbJ8sU0jP8sJe|=2|6gu+mR66(31wZ z1oEjs9forjmL{Wtj!_^T;B}CC4_I)-OEBhsV?$5ayWORG8{RiGm%Wk zrhL^594x+@uFO4g_Uv;GU(o2FjMwq@T_L+G@$s>-wMrOqczSAl>DDFlIoX!1Z3W#X z>6tWb`LvLu2A;$ubmg*kqZWba&H7l~c<=>L9gC(bhqX!Z4b>ar?6ro||E^g2>uEGT zj3RMt(JeF_y3F;iV{)wp+fC$FNS1>ayTC#KP*|=sQ0@mvQE4TjWx{M|3Yo^l&{10@wuM3Aa9 zGBFYd0m3$|>`Ief0#dcHy1Z&6aRyF<*;}3l&%dlODKQll@g+|%;CFhR{-E0*4tS#J zU^0>k#j4r3?$<+ZUnrnWXaRS~<9=13=8xoEUhjB1pPJ2%U3v7rbjC5G7vAm986FK+ zaCwF1@Q2-gUtm04_PIkohf8z7K7f4cUqyCWe<`UWyfQkza!Y--y0|biyLzsk(fc$= zTOC4Ppob})r-4DkaB8p%0OueR=JOelcwU+i;KJb}R%ACUz`BEvUsCXu7y>lX`spLn z830z0^D-PyjZbx=iAX9K^|~`SG@gj~+zt_*3OY_9xF^H93r$$CGxK40DiLz~6KNx# znusRs4o@JFE+rEFvNs&|`yzpmU$eWbSU{C-OI?*#P{jE#cNPCJz8n5WzVHuWtY69H z?)=J~6FJPgTy8Em^695?6Zj6taGc){e;8e91CkPcEnCTPdwGBMJCBp0HXJ75g=Vp1qEIW}?{+t%H_!O;VR5q;xoYuDbFYrWMwB~tJI|fX1!TYe6?pK+ zus&4CUmE2KXbY?tv?eh}6?eI^1p6DzQ-Igt3s`Z%c@V%REmb(C=<>8AN3HDs%aqgS z_6DcNC#%K07IFFfi$9SHIJ}<1t4{j^!SHL(6iOnM{%HQ5%b6JP+YCMt7CSm~( zvi*B&A%-goIUa`Tx>e{^Z#>c3gQX5s3*dHw$HP(>N5R1`GNo#tmQy$`>`_Ttrr zOMfK9#d-W_0cre9TA?4-jr%dfKRBXPA6yDN=mL#ESO#^Nz7@zr8?fXwp^ahN+p$0x zKw=R2A^(72kyy_TSa7E^cz)_)G8h#}An;5F@ju)68`!l_Eo^0KGDJV~j2i-ooW~dqwkr&< zBe6*erqh=r9GEZ#w3Qhl2Q8~^Zxf`1ZIf5DaB1!Kb=%JRI{u%CF{@#MJ-EK!%_mWEJ|FR3@JA!Q3s^IP;jq+6taY6< zKx>HNXY|76Q1!{gu7aOQi!ieCOF>O3xXAemu935=QsTl^IuZOv@I+Z*7k^PP{Zj+i z$~-jN0RZ#DOrbFIK7~wF+wMTc79BGyl6k(_r^;5423KQo8?3j|43E4aTxE;kTheF2 zLb6~F1=N94HIBf^AZr46O<*aW3~{bvV=T2Wm7iKjjYZt@zV2UMxZ4oZ#@(M8w2?^u zoy?I?PRmc{wOr`Po*s?lljz4NQj44Zp=4*FQd!s@<=Q{5$B+gd`Q2j#vZy}(CgvHF z56(fR18<8b4M`5G4J@YQ&oZG?qwMNun1cTW^(r{?l-$%9d4zoSRQCLx=dl&@Q)Zi| z=EeI4z4&#IL>I5-)!}ClAI-*$blQkzmuKo{&1P56)@NQA4Am73UQiZ33g&-f3xi8_wBxVa;^{;p9pA(Yd+p(80IA#{ zzpy{R-^7FJ?cdy}?M$D|w!*03U7O-x7aFJ-3hIX9n)cpY}9 zmoY24FNktHPFE~ACW?MweTDrYVHd`@d&)4fuF3c46V9Ar6z%pL@{Orp- z%Ek+cvL5loJep%H>37>jESB(lobb|l(;mC?MMrsY!tN*^nGhnsP_o+#sdULcWe-Ks zfT&*t;DQT8Lyx1WZZu0cToZv@E->MeJ{428`k`pQZ#B~_`hoduP+IF{X#ahRe4kJ= zpq5?ev!I0=lYUK|omap8F+DmF2!{g`QGG}zWDwOfCDswDr?kg~CV|+0hS#yVG&}(~ z07hzkxu5VqQIs}kgA9yRR( z#K<9-6&^E~A288q34;Mf;diM0vPpFm|B;4;CVXCS-glZvuEDZ;+xV~skQ%HHraZ*! zxv`$H*adXdQ-~0IxeIS^tpnn<@8Wygwe`&#Tz^wAP#iu!VpbV0u56;TIqkuL*q1M8 zhg4x#(!vc9V8r_A!lUi8cM98X8*V;**hI0R@J84FtN3H-3r%7SWuTTsL`poQLzYCZ zi2K)r!QV;Wn!XSWemhwF+dBir;Dsl|Tb>9OaTrI7INbYhcLoA?K4Hn6lvUF3y1~|< zbn_De;);y-LHs$Sz=XSxC=uJnb=w(^XLbrz%)EhLU{S8#Kd5zIAbSfaV2Tw}yxCvC zZc{08=nvXhxQ5gI0}D3B#WJFSF!C#-(k1e z?22Yi@BIm1n?*fy`oDaAYDSrC32Q<$@#i0)EAl>nr&6A_Oq&To8}EXoFZoctsEaF3y7e zJKTT;cwFhs-LARFvfJYeM^he`h`q|Kp`?`-PE1UtV_rmqqk_)ZgbW0k)3mV1bXSZ9?M{zBn#>g!9$L&qbNAgsQcx;J5>rCC@WD1v?HGiE zKhfTU+0{CSQ(Hz;iULJ_MTCpo2fkwcEMIAO0a- zfh|A}2#;4^_5OAOUmYb2QEgGI4Afl$8G?-=ANnc`ozTr-2gEI{H1lF_tqV0#g%HRn z8B=@ewg6y~A@r;Vg^EnnT==YtT=&Go(oL4WC*0R27_=W z5K2TiEOc05NUM`(s7xSu|HpHs%tHlxDWhox6kA#xUq9k&q_drii?g?7dhhxwj(AQl zrEp+&WkHE@)b&WG}GTZ0duH-q|y^UWwhB5pM%{ay$_~J#+HbE8%&M$wK~j z@lik|qi7`nh!rG9L}V~g=M0XmI2b1^J~5yBrAP9WU(U^4jn&KXnfrgwsDCo|dvm#8 zuH+y2rQCcmUarSx?(g;L#wRg&YAn@qfUC+hl?b6yc^8ofj8>`DmFH(ZKl8RFcsFmJ z$>qNG=x^n6GdH_yIQXU|w>4nOyv+nbTrcZBp zPCl@LUyxQHp5h)VikNN-9peX=fx!HTf&{@VVMUS#eMIjfhE&c7a!@)Y5zcGdk$=rw zZ|&TAYYSE{uy$tRLb)3x1;LW3{1$NT!HWUwK}(rLuKy+O$%G{^%c~~@1Ja@9V>HN# zWKLcK;xNrZa2c1+K!k<(im#KxcH)tv#XRE9!rrReHD18SqmP_FqhG(84YPZBT!q*MU(2pcpU|fP?6>QCmjF;18W8X~w*V z$JPWTTC)?52;k1ZaH&O7atldOpEHI=XOvw43#Ne?+!-cV^q8DGa8zJjMnsu?Qjhtf zv5Y6;tK4-Y;4e;kLlrHkJIW>bO?-^s+{teWzTmW*-yn@Rf7_L3o5%WRhyCj8NpJA5 z>yUI5{eN9FvFE~AMjI~Vdey(&d*7G8%o>4!zjk<@hZ~GJUH1VQ$}}k>GodtdF$KRP zOrLmhpt~&{t*@*dJc3T6$Jg}tZsZ903fLG!uH?ub8y3&#oPKoeXJ2~ZGF$y#<84D*c(C9Iiv z9@u&yps=ABNy9Z+fy#x&RmTr-GGna3T05Otkv0;ssBRoF^k^($q{TGqLuJ6!JK*RU zug4+YJ~vZ&O=V`TTAi&<-#?A5Xx=k3^HRVckNcsyar-l#sNMToB$H{TW3Tnvqn=;S zW-{3t(g`Nj+6J22#+ z0y7r~2C=*#mWM;289ztt1z))0Qybe@x1=o%6~Evqr5n-qWF9eB6g3$Q*aLlRZxfh6 zG4k)wJ{MMBx{?VVZeZn7HnlSBY>-ImTzSR!*DvI2cc`jipN+vCh`U*we{MQ zPnzqi)qeKJt@n#hP9fZ{tiL`A)SmozXK(Titx>Wb83x|PPo5ZtCdfmmRtKsS6sKeTSqf$q+KZ2r_K7}D5YbMAR0^jJCF7&!_rt95n6 z@i6_n^w7}Dq;-|hwbwCeB;72kzZmQA*}n%Uk|g7KC>F_8YL#3B z?zKDyQ^{o(-LNXhA#?*Sq|vsj8Z}Bju`X0^O0dAf>?iupHVWDeU~Fps@?Om9a%jIv zFMDOA-_D$x``Fycef_p@Y7X6req;M-a^Hl!Hh~O;$K_hN-=Yq5864(PY+hM)sQ$!5 zQG15LeTZvxjJ{>vS27qv|KB)<9o=CcUl@yyaUi$zBL?+kek@FzX;`4lGW+=Qc#Jlr z>}<+&8(E8_^)A}@lH{upzYp+4lsJ<~Ay94;Omz!`B^ly56%#FLa&AguLQey-Lsg

y})F$tjs}{ zFRE)ly0R|r}TGIWh1ZW+lfFjzZyua*Y$ijkPSra;b0~h{v>K7W0@ID?r%oJ z;b=a875Nuxop`XBp9(~x{#ydEsNbohxk~1>+FX(*+6{^(0uE^ZJny!5{1|ERXy2#KPp|gb~x4Pkr^g+vOei`u}Wbk@323 z?RsK*IQMSS1?Dk&f@=buhb0VmW zuDPE=f#b%=9QhvXQq518{V*gi9lqkqV3hhO%lz-n&CUI+aiCh?Q})rH|*z<=jF(SI(Am`PYmz`MT{RAL)Jse{xz6^`!}?!rEwE^T2`*DXNxV zo+?yx)xwl9)Vr-0Uf6vBf1~UAfHo;ZCJ&bYsqj_|3C$So8U5nK($d7IF69;%bNhSf zn-_D7OSwyza!ZR~buho8?`dwM`j^T8{#wG|I`VbT;g%bGs4LLvuYXH4_?v@z6W?sa|mHiVi^aY(BC>#8@| zCXAOdB@Wr( z@hBDo{9z?f{jnqK8z^Ys1ndIS(4K7ZhO%MeK2e&SnM9K@8|sEpC?OSfFsfJdtoTso z67R+9*3!FUy!nnB$z0Ro(M<16*-O|JC2XLw$|j;1@VSz!y2jtovP8SYb@6%d229(M zo|IPVMjaMLtg;1IbHV~lA{0gBp?KEq2x_9L1s(2ZyPpH-spj$hj>><(fo! z>pS9a&`v+-N96}5NJxX+)^Bxj=uYCq$&y4l8I7&vytK!1v;4E{uJmRszjUWG&dusO# z-+bu?Pp$ZNS2WQQ(x(K?vcL=TDnXxvc@XJyVHrp44pwszkEPSS1o=wG47&{1@37Y2`Vl zGYSW&E-N#~WD&m|e8o_GrH4u5w7iWpbP!W0#T`g`SpQJy0U#lIKE-nm`^3?Fv*GYM z?amXoOr9<{?RH1+-#guQNB+q2(~sosLi0MZv-3YTH#_d=I33}b&nPs`HVQ}~G&a9F zKNk1Fzv$35%Gp!~d2^D9WZoBWX~N|U9u@X*%Mk+6R6 z%8|

MK1S&KpiA@*h1cBB2~I^?2<-7}>oJ_ZyvF$9!sRY0lww3CBz_l}gSydp$?k zh)=If)F<#CW^(5kCRlB3p%@K#Lk^EN9gi$#U2eB4ITH-qh0Ci6`>du%lgB5zEw=&}4%p_tCa!VYKPoIenag#$6e>2SlquLZ_jFlz|E?~h%; zF8YF+aX#lxPOdLG9UgdS?Z(MW@?25(M-!Qn)8+9PnY&6ZU-VtLquUj5rNV(^D1|J5 zhUN=8UBQerFL8bS3xtb)0-VZa`*HBcBb6h^gbP%bG<4}T$0O8_6qU;zz7RkeS0Ug` zIFbgwrkzbbEIJ6kA-&Uyvf6;;g}mSBtwo$wmxRw$3iwaUEUlGLHhynKtY~R})a8qK z_3@DA5QTWel}x}#?zG1e?r_BI_ojS7$gD=l7%K-uPKQI!+8qwKJ|em+A^a1*Fw$LR zQgl%R-0Alw(G|iD6Yk3WCxQ7CM!FKoy9;@d!s8co;ACTynXK^Hkrhk84-Wr%*l>dq zLq|`<67c53LF1n?+-|qW<&HarE8-0~$HoE~O%Dc~8vM1mmd_jY!Wuk(dC3C}%M!;J zvA-ZAvEd)6&?@OJV&*e`nseovT_eb$Cn6ZBOd%kvcUvW zfccJ=i?uj92e`e7!en8ofOuNZkEpnKz3H4Dk9wmnM>2kMJn3*ny)mQcy+t^XW^k}bx#F6uX8Tkg1w-Bx=5({6Mavp*T*N)GbN0RYSz~gpR1G!)%f)62Y-Wv+V{QyJ;BU$w+laKfX0%hVz))s)SbbT|?Y8adx&i2nGp=H=6K2Bg1GH?PgQS zly<~7aE={u8qA{6KqfuJHh@A)pgR0SJf2QFtLJCJ=fX3+$C?{R95#OU-OoVw>>{78 zuyuJIGI18aqk%L8CJq~-ZlIz#?%IHzv<(l$mwNx0S#RETUuJJ>{!4$DXz!(E?b@|2bJoRzLkg-A zgW<8V#Lxy*4PH~zD>Z>DW~5LFoW$5>*<_N;(I!BkX&kWtcBB1 z5073hIpl`F$Sh*DtV z^TgR|X7%BNVIIJIz6JLYEk)csF2y+98G?iQ1KxNj*IfrqMM_bal)!_~6eS?O1cibT zYEbM)4V#uC1yd5bOq1#rd@`$TX_-Qw)KOGy%NuMrw|BjP>$bpV;+P8dwCxtq92ZN7c>S0#lzaeBfBrw~iC_sv=`Hv|#)dZqT zc3L`ilaZNCyL{QO{emwX@n7%(SIi=9(M5vx@+J#c?K+B9>1@PdO@k9uHHB_=wq%q; zh=o9CU&CH}4WOsl()<+L_9XD&FN~obC;LsSCC6qj)&r3UP@Zg4T>{3#K#hZ{2Xy16 zZwVpWU^$2MJ^}>R)<=3Dsl1!(8>1s>E>$wUrVI*Y+Ne}(MffM&L^m02@o z;TmSg>=QQFn95%%$5mdJGy-qN4XC7l`Hia=>KF7wZ_$x-bLeg4l6|e;e%jvm&m_ZT z8TFT;VhcHQlsmFRgbr%&(23e2KQLz%Q&aSIa6eI#*t9{PJES!Q%VzyRKdJPo!{pwC z>1h9)hj>An(xt5f3Fr3FI!K*%AuM!Y>=24|`)~J&nm*D^nJ=m44fcuUIk;4VGKrED zU9bNa@vWD?KJZY|;D;#-NAkYw|3PkkE;on&^SSx`ckx?a;JaZuj7lHpfnJBj9gk2M zXfl%*xaZ}LS+w%s+O@-XU59cPCX|@J);Y0V{yM#3)ZH!NC>N@n8Pc9a6 zx}Ga6%9WR54*1bmksfIkvnvVlJOnEXHEu>cK^&KII|X&4j*k@MRf=XQ=0iYRHIiaG z?9q~m#eyGrI1glUujVf-CX$*boSOr_BWuLNevjMX_JZ{!^we0jRG!;2W-IfxQ_#7c z_=Dnosy1JlHD&bHwfp<}#5ngqNl! z<56ccYY%CsD4y|k$rnv{#gTh{+9iWX7)vsL_d+3>&4xV)84aeBmDhMY0&;#6!hg}D zFWf!f+iNxle!h;WLWD7H#J?1%%W6aKFf;Z#t=-+$@H^s>sWS6Fp529)P1>^u7%O=# z9oHHDC$A+J1YC3Q{y%Un*g@rWtoI+TT?SeupV54m?dnilkgXc*jXtLmxt|5^WGzXo zBScrwUDnS>DrMc8h$_)nAl?}Rd0&%Gh~_il#NyPuK314dKS{K87q5&zADLR}?JP{D zD(FJBh9GVYGz3gf9A%F|y8x`h)J^1J=j3vDZt^*(UC*yH3vbPcmh*ZY(= z<9*Wibz+{Lc5Jm%6B&m?LAaK-oj%-UTG6KiF6_MXj>~ zWk!-t-*-DqhX$Sar(Yef?pv=;TaqnHvZX4!Y?rLMx=K}DN7vO| z-D$ZyX*yK8lXPNtLc*kSb`k}$IY<_gW?T@muuad9!)Aa0fec|lnSmW3WR^f&vwS|x zkl`~-*fPuPvKyEg2K9cQ|NqrtS5*`Ej1L{}EB){P^M8)t^F05iuv8S4zg{n2VLd9l z$aopka1DZ(Pzv_4FrOe|SM1^lyAaO?-wGUT5#N&Zo=$iHCPI*?HH&@z;;L>aIbR}>TK-${9*3?e?I zhhhiiNvUWEDR)rbPGfVcLwQ=A#^z*fL>&o8h_BPUoy7-EZ1ZoRy%Db}x}oXtE#vL> zd5%R_RCjbi{d!hvGJptyI~qYKO1zgQI?YR$o6XCYn%f||Z`JFUF5S9xY1ohJsw_!U zAdZ;&M5oB1lM$YB8nh%S6NXne71cxAt$mF``spfH?JGdZA+TQ*1}6ttMm>G8UT^AG z^kpzF8?0_|c-BFfCR(DWu*!*npL1d`KlE^;xe)%d8m~k1EHV1XWjx+>iVF2Ce6dG(V<@uxi=qoM%6rz}pr4#)ebRhO>{-jgdB$Cy zqZ+mcox~jvb3$sZms(5tQ~sM6w<@XR0T!8-A;hg;P<*Hb#NB)p^NKn+wzUco84qpz zO9TfC`2-qn?GR|f7u+T^v+#h#R>Q-qvn#KA+YFyg6WDBMc|<`i(#PYtyW1UoN9cgc zv(0KHM-5sBzR03oX{@(5&>j=_dZR5%uf5UU+?4N)XugwG9?`27y{>#o*}4^P)>vO# z@2#zEHdyX$q_no($DZ*PRwq`j7LbM3DgunBjAuCl7n~3B44?oJ2UiN>YasHCh-XSh zD61$G2tTzS3k9m#nX8!`$OOZk49x~oq2Sb0=nE?S?$;b%r!(O4V2E=9wMx!qjJBhY zpPzpy8c+V`%yQKo2x0qkdOR`H?er$Bn9t!j%fw?0C0&j;K|FOybCXZaP3GOcd~pWC z!?}dK^aneM7_IU93={F=Y86#x*!bkz( zP%ewk6lnF}HlOSNdMcKj3i^UBZ`R{-8@XyB91wb<&%{4q-33HxJYF|iDqVM3++74{ zDVF4WR2~fZsNI{1W^;E`-nQbyy1lt%yckkd+w|<8vPR$}kkLe9mUK-jvJOB3_LUC4 zLspg<1SF=45HKIhB$1FK0W-8}I6%XNy9Al>IgC{ayo21F%orO_nsHw^=rFz+z!q&7 zmSq?ouPg9P!x0So;^vcj%ylXRQ|V_Q?)*AsnW?3QMk|>zdKd$YiEUvfw>kIGhSl3B zId^w=>pH@cnmdgJSLL)wF%5+kSCX-Ewy_vZs2F2XN{1M&?fT78DS8fWA}c!OypgQW zEp*}Zn(>xU0z4NmLqV%H0mC;BoIKE+Io_!AdV5=PY;SK9V`)J1dz3TCe~q6Ot{0kZ z7AALlT{Fnt&0WnX1KET1=G2nCr%f8;-3YiI84e3$eygbY+k zXy)7Ud1N2ktf&oZg14KHoi)%R+JH~4$l@1%L?nJzZ@H&9Too;b;Dr2O1t)j1=)>E> z`$`%ncGiZ3-P*F+Fev=Mci8p$6rV6H9Gq~uVr-HmPn0eHvaF{E9#@-G(!Z58VldQQ zYBlP&sY&q28ynoYDfLLby>()Hw%dE_aSrRD(IR;RpdG75>;lTnVw{WESkXkO5nJ{&8es51X zgxKecHC2u(O%M*0V{rHm3%b2t-&E!BLdwx=@Ok6C7&9k~D&(H;i*gFm+!75Q2m=Zc zof_{v_$FSB=MD2j+vi*@TQh-@D;eT~zkRCHI;>bJ7zO_me?#N+ z@cnSz$bQncD6~(UML6Lxq>B*16@U#G#Et9i_6<_Qwy)o~(Z1e=7`NNq7xZhnWRJrx zAy-9Tt^*hgzKorM2wWpA|IjV zUsv>#(N^i*(#d36y&xlqD8cO1e)f~BS7;1p{4asg68|`{4h@{(@FH8mi<^YS9DLed zs))XhB_tv!)ElVf&Eo1_aE(cKl4!fU?fpY5hspVdvSIMg8Z!#_R(GWL_D~@ z_)zMgnUAH4t{)SEb3LBj6dtd?{lbQriN4BlGvIx9jW+U@gjW%L~ z5!0_#dQn-K@-M=Ktg-R`o{WWzhW)3Xx0Q^fR5Kzh5zL>E<7h92Kfq(xBvH>MzJB`0 zZX)<=|;d4ym*gN%=(KrkMSBVhRS5)#DN5iE===X+{3s~t<6;#9 zv?nRGQ~(JWS!58h7J|@9V|&)`2lwTZ)x*eQqGrJVeCcb22&`$;G~b1{as)^HBIygv zLPXw~<~u#=DN^{F83zFnBhq?2!dFZ_8uPr9kIUx@W-x9RDI?0e;l;0Ubw)H2N_V5% z`~l7~3FeE;p&*{P)e22&LP5w)U{8?knKZ$6yKg})l7;(Z!>Qb6#s-%UUGN?dpw$8I zg+tsCB^7@*@7jakk$lB~g%D@iC#*&oRZK7{?A35@_vWYH^wf6aO&PUOM-@zD-qhHB z>e-ojDpI!^l6FzzXG$Lgmwj`h1V(*A=$>7;d1ptkF7`>AL4HmQ`$$%n7rY#b^U z3zENh)IOnQns?Tr*eArpn~)PW@oG(Ju2GQcgOnTN;$w%`-FL|oC&c?H${yT8{Si9MgJsu3c zLqGNZdb_^e+m-_#TueKj^#}5muo&UPm3+XDgD+CK{1|H*T%{kOeJXO)fS03hgtWre zZGvJ|hkypkG*xs3(QZJ_YO4$@@hsZOL`vJ5u4T!GWhr^2})0vZtk&FG8 zNHh{Nwqm*2CH7x8GdZ118xxsiX)3Mv%ij>8mwe${>C%Zg_tB&7xf3nEP?xWLv&1g; ze_Z7Ww{*_%&y($hzfP)+k3Ri?oq6g1Q^&?Dctg}MPEmN6`wWxD3EEf4=t@g;0ZTk! z`{WuJo@%oSBhOXI28-QxDdi#kt1{b(jyolSF`4G|aq;kJkEdbYS*b|DKfLanBO}iWpp`6A(1m zX}8I~`XXPGj?A@lY=TKA0CZSAz9Wn?|J;OQX7LHQ_PAM`8PH)|yT*4LjQ?Ct>{iJE@0*VYX8W<`;#L zDAxL0A`%p;ZYu;wgU-LdTlj_X{)-xq{>REv%k~!GgA~fN+iueoMPhFo-_1DPC)vsp zD*_o;Bc#pujF=6U-#22yKhRDYHpY)%UXdAirAi$hu-*r7j zYPdepvLfvL^OQDYO5P{YKw?HhT3rQjx<<|Mmsm>^t;OW?qn2Hd)VQMPImKUJP+ox?QFwLz+)uL#`7N2NI4UMwl8V~ z44-#5;5`)xNBn2qzMBNAnye*BMvX!)S<9cvmS-}@T&@%8>65_Jn_U3p(D7kfr$MD){-Pd zpN5GB*J_BuDuotD*iDJDRB#ZZPi+2BAbnN&CqUiPHV}ZVDXs>vsIv4Bx$G6j8bi$b zXfc(Dgl88EF8Al0M1Sx)BZ;`z|9Y2;oX(*CA99-!mn$ESe0H{6%}si}2dec(>fp57 zktyd%IGqV4@!kj&>e0O0xoB)A5L~N=V~L0}5}KVfrfQRAhbI*;yXtXk)#Xpba^BhE zTril*mMV`}V-J zcj2)M^OiqQ_XT_*kFPNG^qZcZDjs^}(M(w86?R0;>uF_{fa)2x>Rc~Y3D`MUx&psc z@y&%VSs6%R#;^2$fKCNo?+rT&u2?eWD&XAqdO&^sZzLx3bNT$2lKFgXa?)r=1AiQd z`n;EfIk@B{WFl{Wd1`KI_(xN;%0)yKQ4N*B^&?DGT1yK3Dv3IoTEa_FVwn;wELCjp^J6R^L>Hf~l%dq@ov@#I)X__{orX#% zYR$2?FiYr=MS`^&7+)mB_>ku|p7s_C-sZ!L&Bs^j7Z-xnMGoruGZyI?o0Uplc<p8X*(Y-3|8nPDUfs1l*?9`62@fG5BItm*e- z@{l)N+h_+;5%b3@D=U>BHzTP)drQ8Ms`J5+uOgoq{8i*ze$8NuK4SyiwFNUY$3|0$ zQ=<2Ra zXI4|>PVGpC{Bf6&Z``{tHU<7OD4sT+P9zk@Zn{--mJ|Q#Rb zJ`@dmai()kEoSCh7iI&1A|uOZA6h!Tu<9|q*DgiNrHtPb%{=$m``-66?|a|BI8Y6s zsc_}8E>|+1D7J$BR*G!L$>8k!F9nG1ZMbUh$`?$p&$3*>pOCNo%=?5oYQ=`MIUuPqj~-M_5U!uA~!zARW9msY3U#j6)-JP1WUAl zk%2i4#K;c$c1QjxOe%NDJ%x2#q{RQmBK{Ccxh!J&6BADp{rJ6Fj^G_NzfbTdiS{jb7qM+}6po*N9wjweD}r(s!*#()@NzLh6Ws8m!}ydh zhJRTome5arFUdOtffYYeyEo=>C-bE^*}xOdXCw;1r%Zn=mBSy-A4`W!4`Jqi%j0+B zpc)DKvDF8^XYQ?Y)4%*=z;nnMN#;sZso<;ccZZ4Bj>GV%4yo!)fLdaKr(cW0!0&X$ z^2tCrJCh7}e%=!Z*)?RT$S{(D_e%vKpGi`Kh~NFe>FJI1JKyFBgfnq}Fg11H$#>%? z=f~EqO%DH;@nymodf`&zkcNpC1`ISi3r20ZBLZfhd7i-)(H`4T3Cmr5%9ZyVXio~}W(OOl zKGAGdk)W>l+p;4PO0^>%ECFR%#)qs!TZRC9Qq~G26Bbx=gGF>Jno)q-a7wUy@oOjU zGcGDCB0YN~4Ne1(*cK2bglCQt22fd>jO~AwKvSBH-Lym%)c<$0D=X(Sj+`SjN65#Z z-?{jxVJv=^FB)`Oo{mHLUw%C3yV-~(jzx|Y{rRiu`RuRyf@I&s5Oq6-+!HfWvFz`z zJg|~BvPP&_F9v+UX$MgZ7iZ(~z^Sy4V5{L68P*!d6Gx**%X6tzYAq-xRP&{mUb@Zs zEz~Kk)RxN=XX*K!R0a|cbo|!W?F?EX7!Y8(iewR==YwwQmy;LfJ zwv4X^^wWiSJVJJxa5!MH@F9t|%6|kS9%NrbVJ33D9P6lJ^}oyr|3Vq$ALCKEHf@^& zZC%xlis1-GW%#^?6fBdch?({(ES?io0@S2J~blI(X zUMCC)fT!jWC8ve|J-nMTa$w&OoN~)}ab@N$#aXYXVLCdVoLPG)7~FC$hfhSFh};)J zjr~@FV=7wnB`-YA(ARfXE!?C>-U7Tkt%p@!qA zRY^Bd_onhmZ*nT_nadSjuGmZ?kO`#^ro!pS{A|?iHr|*H5DEc*{6KoLUY&bIJ6aB< ztPTcQrDGAENPtVrVzh7WBO_>hZbH_O`c&W&c~)Z9do`B2c{!*rJpa@9B*uaxiP=_IJ^`owE$V&`r*GH3{ zTDExLtJkGZA`5?0h1C@3TZxlX<4x@tkG7nSVO?~oSU!xlMIf_wCsj(7+Wy%yE0dEe zXJ!K{z?zm`v7#PEa{mMOujDUh8uPDx&7=4W+vk;p*NfQFEnd%webh@*J&22~ zWHmP=zqwLEkE|`DbCm7URS6lj`{?sX)#c-}36~p}mY91!l|uw)0x)GfB~PKyYn!cC z?d42C7a^iAlGdCN^RC1X7x>PGHcb+mK`fN7`*7)dX*>Ihhp!+rqJ`9^Ab~1!MCzz9 zm>va9%>rP2Ca~~S^6idd6*}#F4C=DbMYxPZ0ly|MULZInHX2|ap!Akxv0ZZJ4| zB8~}tg2wB935{nziy3oNG5%d*_kw2G%}TJcwULk&K0z1u_4IAZqx@d|?Sn;;AJt{* z-cfbW+ovwQcEwHnpjEqiSByom^kZyqeo-o79}OJ5c6fPq$=w;F9gJJxh# zb8=Rk;u*vgqi6{fT{3vjPVV&A+JEa=m`V|{Z-ZNWq9KvX5w^OisRhs9s{YBo()~+t zc2a*Lt%MP^Y*ctJs6Cno@f8#JhO8mU>c|p8PHCk}2ZEJ+ceB&2G>IJkn{yZP1?xx= zEq3Qd;PB(W?Yv^V>OiS{D_3n;KP8_r-o0AP7gHHoUfCPbgsiXKMl^OsmKSaLFN#k^ zGIDEWr7T^sCFA0}iC$0?CMq_P3fsRYM|s3pj%H`F;jGWc!%Q~1Jm#8@<9>f9 zY#dA$CNndVoMR?4Sx6qVC31;QkkTu+!XYA-En(zTue331f9i&`B&D6Wv&x@R(eH=B z{W^D6X<+Ob?XZUM1dOdn%X(}hV)5BCx*SD1F`*oHAWUJb$41ynUg^9r7~rCH{b+e? zls(;zzZ{P8@9?(>S8P(71~AZoNljVXsI=_Hv3nFuJ9!{KOW z=Mq+Fr)0!jdK09$t<02f_0XfeYe2CUw=OBg& zI!3NA8(gCX=5!+D_SCbv5NbN1sG!=%^Bx|3>i3eNKsXgBXYTW?0^ZM?drEqo2`h2!bGPn{IK|5vqf^8#1qaB@|JRSezP6Mm#B7 z-)WRePed<6c@6`DZ$o4Xt$KR??0jL>D&)@BIP+FsNj|$)?%;3onYA?tRjS@9@RYWS zxx(Sc-@tLl`c-wO(7Ipcl^9R><-E}gc~Jn+>KATsNqOq7SoVh`?}9XnPY%3}MbRRF zC;e+o#G-RE3;AicdnSLNSSb`L#RK_i6Ju?w)-GlaRf_3E(C2mr1EB+rd=Qwr+b=0U zgZajRP$1}Z`+|vdv4XPzCeC0aRW2KuXvpgZB!FZZie`**EIt(tx*Z*i;3iSN+%u7Q z$m>GAf`Y~64aFlfggoPx%Wd-vGR}T>0LLchjCiE%tgW|qcG?y}!+YYqpk;&)@VT(< zdwBG@UJNyI$&lO0rVd!xIdu){bt$wy4q>Hp0ce3P1I0A5|1cxvJ;tXM@=6lKv9luo(TWJvHO z9VM%!CN8b!3c{wpAQPc4X~INId6`Z7zM3WEZ1q*ryQI`d1))%bSN5k zL|9_yh7*1wHU&J<1VOr@UbFw-j*_i6T8f48alfm_mx8fWer9gbaCw7PwtC>ii38QF z6(k|ol~yembl)&Nu}C_W&m_qYNw0)c$Gmz>+TX{H$U=2o)ADpDkosgUE!HqDAS47b6$xFe`(x3kvaZ#+Tt zrd;T3jvqiH4f{=$Pvdb$Cjey&#(=U1Yse|fkAIQE1p!UXWq}OIvuGb1c-7nj`?IxX zDUH`nQ4Sar@`#4O67Y7XgN~zzLtR%EA1br0b^}i=7F}ES50ZD2rIef~$=0@Az==4g zR|k|u^caIi7!#0&>g0h`EIpYiCDL_*R_hy%2mBjKkJSLt7tEz-K zd|O9o0uS^L$yve9QHXhrtNnj(g9_?4qQF>t__5gshPZ;Zh80-t|2h43hQr>1JrdT7 zKanu8^Qr#DP%IXDvCH`BqeAwJOZw4Dx6;$(7gA1R18c+=S1(thr(cUhVcJ}GX z21nW&Vy(=Zb`X|`MI865E9vPP$yybFPU9?6Mx6*iv{{ybdbmv-7u`mQ6#oHwu9Ciz z>y|+mQEXpf6P>M*J};)rYplsA>_~fg*i|K}GHH=!k*9@WRIOv~2ER7EZ7BK>hFy;^ z)rx$}c9maa6a10r!Mkces0m+j)78H%aX;TKH-umB$_u0<8GO7`)K@+xpSbBVg{X|r zX$aN~6AfcS(p`oLH2`to23=*YjUH?U>S9%zI^Rfqz$K&e@isK+^lNCzr`z%vmkZjg zpjCbnfqPOEU=_(hwQqihfptjE;aMShvG_6)oJXSCP+0%X(t%EY+ejX(AK&fZJH+A| z-d~dlIgS5#dHM2ieRerSQ`7~{hC_aTbq2iHCV{`zxG^r-1~@;7k3YJ^`gF@8WuD}? z7BfOw*j8g;GDzDpFciTO>ItQTV2e%&wi>972$X{z{ciE1Ziw4?|2Nc2s)9$bvtRAV zJ9hl=PFFsy*nm6gZ?fkGrHisu)hEyw)dJ_BO+(Aq&~(0`s#H}-#vt{MS~m9>J5@C}@T|Xe zwsG{qqvxz6bCu(#9$T36U0$soJ62sfH>CGHUimpKCk$Ml(qsu}DJ?o+uRTUiLv&{o zoN?E$T)Hl&v05VXXjnT9qjC8%%^qJGY6{hZcp1Q0X+OhhqjBxT%=IoiyS?#nwhO~I z*y{p6(QEbPSL(eN>D`y7R^9I!J7nL|9ygM3y~>(eR$vEGJp<@NomVqkaARdt#R?Mu zM2(0ztt!_&E3596DmmCWx~&wkL(x*KzH7O?P<>x}xmY<{m^T~l*J^mq|Jg9-3zL)T zl5thuOikIJEL8LI!KoSbkz)le->Borbl6olz0mVX%dGoEes_WM8VxsF_skwi|g3ZtHy+0fX|X?&s&(8 zI#(dVad~R0?C^OD=cZ-~9@xq~*S$WuzM+@o6_l&)*zuW|5hv)ZzkECv1DNagxZ*}^ z`b5ly91-VkZ2YF_=H|?CJ>S~1L(T|#SlM@w)#P-m*?}Kp0@NOyJ+bWV#wonH@!%3d zwSkZWtx|WNIrh-{jtVSh3~8(OtV2m@XXF#_Jnd!;X@VNcj)vH-5(jN->y{3~1rLC8 ziazM>o{*38)20t5X7CcF!$eqR&U(S`2w!mr-Rt0T-r4N1L^|TsIi!EP?e?0*8psPR z8eJbBBQb@s-)*0Ol|6=X1F!SFGPwYZCmOf9y^#nm`LS&tMnDWs+N^v6CACvRyG+2H z!r_gie}K-y74K5^Jwa2a#JRoEzkP3*RKF)e^}wVj$wUuK9Gy4=_oNkkBc>8&7?g`X zWpx6ua(c*N>BjBz?fA?uP9L4-Pd`nS4jwH1syxI4M751ZU#Hm5V+z`;x0tax{IvQ~ z-TngKD#;F)apDlMQE{*Rom;nd8=Eq-FtD4l zL`0peq39JwZCLt7nw}D;iqK5cqD#QAtb};Mej+ZOLa0CKU?@B*M6s%R5DyKuE9m1e zKFz6v7n4y}AZ_&j!dxs^v%$AoPoJEdJ#^K|#w*2x@uhj+>a~ND2fhEqd+^=X^3qhG zzZqJYE;ND(>>x(cnT$4P>PuE-DV;oeA)0nuxu=gEIvAarZ=9d&)TgKGC#?u#NB`GC zL{(p%uHaTLwCDddzF>TUQvy!0vLreNSQJ>s8q`I!Sabrdl`)Z9h*uMdSH0_9?<%F! zrR=FQr?R{#B;%E4ZZZC<6YqN0^y810viy`De|#`L0-M`lJ&NBR)m4ONV2lZr3jf1d zt_FJe3JP{7m{TAO#Aq-!Q~j+}8($2v-G*+foVU?v|CV;!`*Ey3r1Fj*K7If4?d>i; zgwd4iSushaQu6q$D-~6iBNdDS1JU(B;4+QWyt3?@ApNhhcBNG`NTtJc7l0L5Or$7u z-Rh40=C4}S>T1>R?SBpIbd`U3Ie2AkR#z+4RpWO-^YS!XTa{Nex%RstmoFiI z$P-eE){wFk*;-Rzygg*ZzFnoNcR z0FWI{ltB)!ClpN;iWWG9q}vGl(Fk%MK)cC3(@7xgU^G>H`ta;uSDIGbsOF>L_=)o; z%IO>$Q`0D{oFYoS&lQX&Cf(>K>QjGJnEzj_sgN&e5`W$w&m~OEnCPXP4xh_ARi6rb zEw_UN=ZRb#?*rm2m_%mxxxG^hvxl3N)LfA8uS9;w{#AAa8rf9Y>oh%ul|p%v@a+D4 z!W(k=OUbFafrpn`-&#)3i~5i3H_-3lKMbWXmHOYQq60DdvMM*k8KFy1kFLC^hkSJj z!ohj+uG*;wO7N!zQmF5yq>41OsjBbhWyZ`nJ zr9=Mzt=&HFUoOlYIWlL5p_7XktJ?WJmyONx6zY!2*(2AEv~^zdEp?^co+`_=WH!NN z>APOjJ$QNz40_oX((=1D!?CqxbX5hqcpWchSIiE2pAO2GeLCvq{w|{6fo<2LbN71M z;&a`;TU~O!{r9X7vqxGaJHZm&wZ0!Hv|59|yHvV8xW|X6+Fr9llLYXCUmVkjN)$4% zK=N3%t5N3aofa@z)I%Cu+e$ zo7Wgw9Tr^2;E|Bm0wCcmlh}7uy)vF7$9{d>Ave&Vs}CRwB6iB@F1(h=)W)XpEtnIC zfW6g|C&07zh2EG023f$lvyOU=sGWGLt2gT-T>%HG3i zaK%{IxhgMEuiN{tYh0vHz1BJAP zwbe0VV()XeR5+@C=s=*oxIOIp%Z^23?RJAuXZ&{?>pa?THb#05X|uqTgtzXZSJjYG zY3CAfbb#F&X{=N+twDAn&`B!GkcKLucn}o}tJRWBpa7N1q)CueL+{SF|0b688Ly$W zGFgk+`m2mwEE@^F@00It{7|LB^i?X7cj!ZT@NBmt!6(#&GRf_FcCns)B^N^}_xrGS zZ&Y4auUE$A4wHak4JNON+t#=Aq#0-7%=OFeVE&LCnLpNN1*noo1#)B(jqQ5<7q9le zZY;{j+r~uUYF%E*nCKMD1U|XPS{`}8-!IuzT1di8=99BPNb&GrqAN`EUN8t^EF)Tu z`iEy3erEjhYE^aC@nK7~tqw-=wgJLjM_++zqA}iOB<-y ziVlnR8Z!}xY0137iE!Fu_f6x9h4)rUILg&lQ}9IYDwhOS+>#ww8-66cBA?*{1kCZQ z`hD1TTt68OUot=JF)xKe{52*Gj&k=!v;TF6^8uIZ0p1zLr_}8SJZ{tNc_0|NXd2s| z)qppcZ>^EE#Nm1|6u#*BK~+RJT%R)dn9F_H^c&6x+yU1EIL*1ACw}-n_L>m7L;Oo}wxA~-$_1wk1F;`#>4Z~*WiWWBshKQ@yIpJ2 z0R4$kybwO9)Mu$)$C7@a>j6lyHTJsGONmU2R&Sl`(rBwtkE1$Pxey z`kyNjb69A3$2IN>>FIh7HLn$*&c3!YuFS5>c)>cv$N29xWE<>M#}hbokY?E z+N}6`$f$x8tLbqr9%?K*oF^obDu!75sVnT7z0bjQ zb4uYnLNH#>v>-yD=&i&C{zd-&ABT* zh6*uiYP37O5+TP`IqjTwVrQ6mEcj{Hi|$*&A9gP;IveIA#v_G~ee7c9`%&GuLZR7n zMzQ~yD$L?If9gahg(R9lKh)CF6m}|f@nUILE_`U(G)_~=T#9)&0hK5)sS?y^Y`^F2=AwS)0zBqFp%{H3C|tz<-MfznhN?;zA#P(fpkc|aVp~V=kw3K$8S3Q zVbWx!Q=ve><;IaH5|4!Q^-#d)@;J??AN@KCRmQ+D&TtSW5ucZs?(>kmadi%MGO^mV zBz~s&Ppno4Z*baW4ai%xEO&gym^gpq+_@VcmxnLL17;lG^Jc-Di>0HarOM`xzdv7y zW`e*>i$PZ+m-lw<53LqGIfCc-9IkZ!_{p*edFo*+R0_!o~z`c|&Yt-oQy%{UB=EtYB3fkmGx^he`4wac8dM((W^sI0VpF?=>A z0L>hI>TUAyp(&qlD!4isi%nV!Q`zj)q_Jt=;(q_HL-F}UD3{M150@_$qqEy+o7 za)RTu>GZ%yrN{m;Gr{Q+1hwtn^Gm^!L=&L7vaJz|Umy7*QY)4)f%#iJ(Q3llck1<< z!ucDE{jXm&+G4h(g&-|)>^rD!G{dnO$%EO<(;a?bk8F}0xaLj8E%j3sl^mK9Bxs#8-7 zA!}-DOj)SAA(lz6wggJpZy6a3GGc2QSa_jCM&ruY3txwMBo?pCkC+$5bk4;qn;7bZ z8_XLqUirt>3+ zck-KuK6hWTkPxb`I4j9pI3b!VQBtK_sH|EjsrVh_@sm3WskfxBuS!0wV~1v}DRVv< z4_rHacy2Q3bNN?GkKSKcsuW{nf%GLR#rn(~JH$#HtRA1e7!EIajvl;rFMi{LYxZV`jIrTBvVr3(5(kQ%%7x1KJX?%yi33+Kzr zgL?i8hRF`mC_77SZtxcwuNUD#p@wCC2W=M{-rZV{zK1TM_7juOpm?0D)(D0>UM34x zV(+OnBj^ADYOxq7Q=+oTI51U;{bg)$4rzkdoxl(M%Y+dBclj9*02_<_1fpPMA0kT$8jDkl*x(o`^qON2Rb4!+)DhT4dV-9zQa-u}HK{E%kQ7#~mmI zZXn!`Zqr|(6}nzQa?Og|Wr;#c?V$aY4e8Vrf0~5=*S38SbB|RN(`E@qMT90?_qDXX(BjNui&C) zC)XxtrNZ;FrnCr78T$YLBC4lIP*oUcNT3Y+v&=v%WT8TeaVg>J%j0T9;(&W<0LfzHBb*3e)*=i-PBqNczR?8~ov;IW0nz#~gUhv%O zPQr}aYf86$Nm{S8aoAY)Hm;_-bP89Wy&bAaWGZYmh#}R(%HRK)Bm0_uq)eY;QOEke z>lX@ZbSV|~RUI)?JN-X%WMBJ_%y>hdXe0H>eb+A(${vq(Y^s`x(g}Vv>!fMi44PmG zzp{_I5$r`wNFE3qmNAurtu`dBTpXuzMrnR3Jn1=cf>5x(DlVdyb>R3ue}^x=b!t8u z%>2T7Fcu50e?xnqe&ZK@LB^EYdq$gAa`r0SoyD;#SfI9Obw#l1c6aK?%~-4D)X3qbv+6VSF4Q6_o7Ff4#854h3BSc&sjD3*vmVGcp z=14k(yEMlhhC629%_5tO+H>bDwD&b=|4eA!NITxc$H1+#^Mvsfa;?1HUK$NUcsD9sIz*-wopmlP>-CN;}_5>K6|R6ydxT?o)y0e@Wm{R`rJ9A%?0IG zahT6^@U_sRzzcglXi;0?bN47hY+Q?08USq}iw5HYX`)BQ#GL?_IvoN&gC$p-#zDY* zmmN6B7{mc$@FarJy4)9amaK(8HGanUw34$_OlLwRqpH+)KMO&?gL;Yy@fe=Ze7Ly& zk@dn8Z!E}*!e?HkUK*eN%ts3AANfe(RqMqMzlv9d�Gn-^3|F$D~HG0GN#m0p3RY zr7SoIfJ0vd2T3YbJWDzZja4heZgt?BP$4(Edf>WUZbS>UR2M5|d!VBDit&P7c3I?> zmnj`xlGVC<9XpcdBSx2(D>ailF>|`ozTB=fwv>`|vv@MV=60^Lj*314X&V3X3g#~~j`LaQ5w<9oaB z^x_byo*D=L_Tb|O56(Nh{aG@Tey@?u^rWTo=?C)LsbcKvEFK}nBi6a-8|8L1MxZ~LyxjEk zg}jj~9*jPC?htdGvCaadQ)9BD>J@l8n^#x_1fYQ0r)!yH8N{4K_aR_eIFR%tf+`*zZPb9$1cK*5S$IJ94So|^{jB*9b-D|D zSTwD+V)`z3jO|kYHt?VltdzK$r(tvRc(VbH(5)2b0^!ms>~|<3JHBjb0BhR#<^J=*IB~$= z%wzxG%p?*zJK=5eE#gldhzOu1yOALIo8~_y$z$Rk(BtFnr+aeNz6kvOhX*m z7%rQVp6P{#k!suk`@6ACNYe)1S15(MTS_BlfA^O0G%XR372ojG&`>w!^i@i0d1|Q( z+uaRtT&efJKlSX|vzB#}T(6e(>fEK*o;>-UP-rWB=~DQoPcEN)btv?XwLc36vjXE{ zThK@5TrbwVSN>`0ADCVYWQ_Lg6 zS#u7Eu!X&c5TnB0$VHVVO;R_Br;;@Cjgzy*LIkJJNTh1aw`L3ZcsP^^8x^B`qLwL? z%Z0ZduN*HOojvjGOo*Qh{CFenbNgdt8p=;*8(C8BMEpU&k(x9<2a3J$IerSEbXc!B ztOxoSLu>JJ#~3N07OQf6fljdSkyVV#;m2FIZgF(Q7m`mu_jGb0e(}%k>u@zYHmk*W z=(VBEvf9wk+EB(Hbv#-SDy_#AMo-}~l{!j>M1Z>zvJFibH;oMvo1zXBU!4X{X#9-5 z;rvGj*}1iLmwWaHX=?^-w0o+Tg^oC_91o}5cu~&Y5pzy^V$!pV-epl8+T_&;PJ}6SjMrHV>r-5$(k{ zf}D{ellq5Th*QL%l&(mlgZ~cIGh(_(0iSI&kd6ig)1VPM z76RI-*zUb!MkMNKfl3M7ZhYwazag~{D_>>Y+B1Zk7!xEx)p*%DG1W-b)@3p~+d}J`~y%-|I=iY7`{7MZN#6EFvbGeQcif>eeY0PVH?w8Kr0+ZcoEC zbMD;s*|Rbz!-(EwuLR{puqA(e++upd(YM?Lnz@oJI7B7e92gXSZu^IaH#9I;$_mG-=O`m{OUt{}-p(V32DjF|I6qHw7I^TaSIK7**>YA6R$ zQ4i_@^nr;^T2UkTbI!NaMbq-9AoO0DEl4J@*(@SX3NURjB?_fbTn(KDIVnsLm*pWf`k?) zQ^s41&122tEZmvY{<9GY9iEEhsB*PZ*`cDzrDFNyyjxfNeF5S#e~=)}{*!7v)X2~V z&O>7Kh$UJBQs-1V%6BwG{8z-28{_||4RXQQq~l`^>42cY&qX)mTBEUBT%MdbAG7iQJkortH7@0A*>N5 zdjP`jm6x}cug6m;*~qA#O5tpYV^u01H9uosm9rlk02V9qu>Y(jilOycYEVzhv)0c> zQ>nV<9tP$|X-gQ6Cy(&BG=zFGIpSnZ)u;o3AR%9)hA@Y%tdUq%HhP3r?+0J~q854GToxv0OeD3V+g7 zPyM=Tc;(2`(s0*ob_$-=Sy1eZ-q$_&1Wg--$72I4D#7x_H+!Yglb;=Vz`uJ(UiCM6 z%>Rf!M?_vpz|D?Z)>wt2+-Zt>hhk7Rmzy9Qgk&i?c7nMUN{j0(guy0l+{WT0Or+qH z*ud1oexA4`GhGq7h0m%%Mo(Qo_eA|I&Wehr?>BM@PciP~Mb40M;;4F?euMs8&@V^4Nsd*B12*Zlc$uL6;3%uXD6N=^P#A#3xjczR4`64 zMUOi$3#3j@vDR;b`0fgGC7WfFRJLMAMMA)!D8wHbK~$W=+Niw?a!ORk+FZ#YXj5$I z3G0QSvPGp@tSrY2AJ_p}(UHQ*oYPRXz%|A>ABLJ)Ijoh=80)EMbM^T}Ck)n#c4TH4 zhbj?eDie-;_yPe93p@TpfaI0pWmEesy;FNIy;G|s3~#?@h5pe$G7|ygBn^5&J3)*; zelwxOE2Ywv{<2;LG@Y@P)W~~aZG;lR4PzElBnuV*Qnb6+y^aY-i@&ztvsJ5?&7u-OIQ$Gw9yd8bFI>fRc)xNb#DRk?kjq}Qv^ z%`K>SM0m;s=~-4h1BK%>@+eA%-TK+Nn>Ur{-rwrooI7iL-hJp|qpOrP3!QI#zHt$f zD>OuxCF<5mId_#oO*$cQDsW4{^+^*w@rGy-#iy)@TRweahO(|TDz4{U8_A=8;{Sw8 zs??M$o62&NM8dHTfBxBQ>GwKQQ$O?#so&mjvIqV#wfp4U0aqbn-fGLjy9(p5miotN zzd9c81IJ8*fU;MXZY@>1OBJvKWZ%VaD4rGd_9WMh#v44xtJUM4H*An7N>btEHvmzj zKxJq>cbc?O?E$@)HbfP-C0Mz`!@jGotJ+%9w3=00O_L%~n#N>{i?i&^0nt~(Q4H%A zRK7s-x<}GKdG_pDHD{GP52T(NG_s+`rjQl`kZOpu_RM2PGQaCO`*|9hj$ce()y+Ly zx9O)i_MuoLjc5(huKx#IrmS#4OK@U>NWnuuVV;Ff>xistYXg%Mf{tC@&vRa&IpU;1 zjm|;FP8Ah-Jujen{EU69r5iB0Ki=%aYJ;V>Jl*8kBaADs&XL(HR?35gr*A zvFGaLUDI*9b-Zt*(+LY9V4v?juQ0a0J)rO;H#YaVBGYU&AJA(hla7^5R<4O;8qf3# z%N?WpAA%C*xqOQgS)B!ZagFcT0bwkZYpO}jp^}#bnd;l;mxWYg+N6wtp$e%FJe%}d zfT^%45OFp}eM8wPEJONo@BdBiisAS|>pyp+V=7r8{=_yKPiz!~Rcf>;6~JmWCZ#BRXIzjfs%u zcgM4tNY>66(G6#ClJr|4jw2ZcQs^=E@C=_ao>!a)3_BE8tZT1I&z%H!UUqKs&y;LXNaP`< zs8)*Tnd4s?ZN|0^si5NCT)ApahN=WB(|l zjEd#AzK{(r6w>cot}VzS%kqf6er(eoeQJ$_Ch6n?8@zS9un=56pIxw2$h!7u2dj8~ zoV|>{(D#TkSK*bopQff+-NI-w8$as5t|BPvVdJ#E>SSWRRWCgYvIK$);C~DsBpRZ zW9Pl$xM9S@=?BwZ4-BNS{Sm`(y4~qiV(Q~DeXn+M|Gjv@*fiq#{x9U?j%Yc5rts>A zg9m@Q`H@#2PA_H((_Yg^Lz!H=jdVfqA*Nzj|Ez3<1? zyW|p3@H3I96}4j4(0J=I z%Vj)c*>xNxPVnv?DmJnAx})*YCV9aQ(+wO$Cwer8|A5$0BJ@;%K8xCLQ@Q; zKJQO>eLnAe*yr}8vQ9_RZAA|_9RI8R=bUpI266tHWEE5&{0Z;OOf3<;5cH+9g&=q% zm*t9Di`Dsfq?S#2JiaB%Ww?^ym8!<4+)ucp-YH=b~RFn=iE_n0nUIOru`p*tH+OfCmhI7!nl!6LygO$rQH zAHTxFIK;ybBUEKHXQHWU+~|K*Z7g`>?(U5nn**L@r_0xE(%ZAY&&gO3Kh;63EX1Z& z0@^}pDCb6RXACsExqGA3Ma*Q&3SwU1^LBZN5xbNpsW+x&$xCp4-6oY`l+dnF5T7(b&dIdt2Gy1|nwzf?SYHryK!nR2B749Run((8Qw5VJRw0 ztuVkoqimB1;vKdtdR9_JlN>shjfcbWtuCe+iH=3w>CSfJ7D_W^w#mjzFczUwgU^Xu z9P~!GExYZS?H3&OorjdxOxnO8Bw!ASJ*>Y}#cJUJAokc|LaB}>KyL7$>^~emY8{DM zK@8fGyOy{{FyQ;R0SpM1;tZyTebvNN^rt$um6WT4tT6;~%s{u~n$S@OK*rlZKGGkN zIBmpX6J-R$rP~DE?RJ%jOrNFy(k6vNzgvq4@L>=7SVNS;OEp9}R(AC$$b~v)fn}+89-i*Mz6oKQ?IK?cC=fs-LDv3HD+S8xo2%!DLB^p&o)@BV-7e% zXb20W*5ZKfbz!?_DOKaM_bhzt4m~1=Q@z8oLtV*=8>!1RA233a!93M~Jp6|Rh zM!TaHT}Pg11Pa)(5g=$_j5bnfj36r`rzaWnz3Wd#K}FCRtnzUZbeAztghB~CY|#_% zAN6l4Dl;THdk3CMp}#f_kPPS*d~iA6P^^s)K6D>;czLxlSgLnhU&h9u5fEXfzAxT* zDhy+H-&|}%`QqV{OoBLw|EgNX`xm&3$7o$kbXO4_?$xrptqh|*XwYy}_RfYTz=NT= z|IP^+t$!79RMP_}-W~2JhM4~F7ap7Ij>O#EM;Au@5!!~LfxbdzXr}baZ3S`0Dw?U+Lv% zaJXUai2uk`HtHCW?@ivxPt>&u{Ak_SC!+Rf5zbwlKH<&LkM8fEtfK)rvT4$&GudBN zf$&sE6+f`2t29f*(jjjkLHHX=w6fQbNCSFRX=dbZGdUv67JXH$fbc|Y_Z?vdlr$rk zhv8axWLc|~rC5S{5NFo7;t%Ak)9q5J34}a-C#~9rDN+o9tZ>@0mq5b`YEFzNxRRHn z(c&!!C%>OlN+`{NXAeUrxu*6qV*MRz+8*1l5~)XG#*%;+u@nR6%bs+W>`=l+-hCXq z+x7bPJw|Vwrs_HYo!qm=U1|BwzA=K`foITlC^t(N7W| z1BQDqFUwqMB0hR?2UpwQ8Sv6Fu>+#M2BDCpqCH(TFXn*`&Fg565*J5m8?2kVx9RVg z2G+H#Y~4bb3gP!(Zhhkxsv4*czig}&jw1j-O7Fpj*s3AT*A3dPR{KA!<+Ao=_3s_g zJNLk#nW}N45xsNH2Xsk$j^4#%RE*=|fFWuJZT!@`bbNbksW#dCBFgV^n#)of-;Xk% zccn`xdG1<|#KYLHUm4LQG303JL}gXpSqLux7b6;j{WGJa z$=>)J2*!}Jsy9Y9PjGmQADN0Tk+scmN+U(Sl+8DqD@m(UCVozv@fmA@BzN3DKSaf} zBu*tK+n&~q$w|_rx(Jlx=g7A#YPMwftaclfEAJHdIU%jD1G(kGXwJ4Rt1YuG-{6a% z9f(q6b2w~jzxDZt|Kzv@@(uZmpik|BpvA9B6Xvx zp|RaX1nk~ww9(m@5x27O-a0De34*mt`}G0C3cKf{HDh(8^&|)Ksb^pMS~>B zwI;&>x7TZ?@=FhUy-rWkd#dfRJWh}2;l;_6>HVPX-Z8aI0PJJ(@N)sDGZ-NxsKez+ zIh}z>z!#3WAJ$(wb;`qcEziTQc-R;CH4PbfaccRvI2|5ehQn8C*xSYyeLAGT_w2`r zWEYm4iCTdKgh4ntl&-dhTJ){UD@8I0I{~~d8Zofw#^*=k^5t`=m4G{~=$*m2?Ju zUkxP9OHPMl#z79?{+}5!x5vo#U(6ZIs$T!Vp#_59!q@a7vtTRyQL2k}w^d=CX;lD< z-WKZMFyV{n#fTRbUHjox7F^4-NYW}kPVcy6?3nJ5H-K4_plkhK>PYxet3h*q;Jnx6 zi+T?}XeI+aMFPd6JlH#MDf$0Y%vi{*nDO8jO;0qG)N1c!DEgx~8`OjThv!|fsLPf6 zFgo)%8^2D<&`T5ER7hYkxmZcj)j%kL?CzreyazLb)5EfJPU;I>ZBVtk zvO!B+{Kd^f=A?Zw<1_}hC%H_Vb@@bIKIx=B<^i)451%sLEP!54N3n=74@s2O%@uJR zLiLy=tHY<>b9VKy*4g)5x$@`_JbLwN<6!g3;*r+UmBR-QE1w)x){C28374zev!&R(? z!qO@z)$O#Dy z&5}@lCtrys3?mVptV}NC^9z&7VECYcPsh@u%f8t&xx&m$A$R)G#A?x7Tun?@PhUA* z#c%M;;m4m@YdUi2{G~@P<dwdI-jQ=V~_>T19nsNzUtt8WG+*M?ndv^#xwe)L}LjWwy zn>|EVh?YZ3Iy*Z8f5SCnjEiG!jO0(Z%6L^m0)0@O zsi5G8qXf|rpwi(g@KnviU}Lha*qpu+aS9pc(Vb zaWV3Jdf@b9Q=>fe<4?`bPE99ku3Wx+tZY2_q`^}@=c*;Ar@$Rp=`<#jfqp^kd0IaM z*ts_C9tW4ev4Iv%i$~L&jA{}&rsdaz=AZIMjERW9|1F|lc2fC3wEtIXkp0oXY%tjW z-S(h-Z6ERr6->0I(@p{bLknBL5Co5Edxa=6_$Cmv$sfLPY3IS)jT%z@ zzq-+Ae1fuP$Lg~6&e8{g>r)4LzDIJD-F`RyN^1&i{L=mod_#5Y15&MVZLDbNMltnv zDwVMk`RKOsC(uS6omtu6pkCC#pQIP(kEs`|g`IuUY%N(WH`ZQv(__{wiH+9qy4@wG z=d+TF(sYsl+-nUIQ-1aR{Xb_Y>+69){6oPH-Ezk~M@;9FWT|wStE5;Ct`BldzTNzh zAH47j7eDd951l>fc0cs~tEsDl_Tjjo#zDu0Lf#lQMi2uk2|73>s1}E)ZrB~EF?)0G zt@qzwf8S|oO!qE{EmIdW7t$AhSL*+v2R>ns4dX8JJjkb{e5PS5Wn$K~uKR17Jt#3|Q!M5AN+}v8Z$YeLiMj?~9-P^GM6~K%tTq?Z@nqI2Byy;p)%-9< zf&&oO-qndy6R#0k4V{HUmv~1!C@?QUPMLW(V<#6J{snh0il1)mcN&dgh zCQZ^Mo2zZoHqC+jJ+_I{BW{S0-+Sn1SGLE4QqGZ&2nQrmFg(>FTJZ>PXUr z&o96wPnQ596_JKrgL_GFU8Uf-#>aspRCT}}|As*b%{`6{gV>p785K&oh-xBZ2FSlc zejpwp(rHMlSJm|DmrNTd*)c&5$W$32q}6nBtJ~nhG@5OIZ&KFF1->ClQRDMx zE1|&4uGlD13)_**op)xAtU(f{L%#gHVpH4Jo{gL*JK|}uu2_+<&~UB;kEG1bG%fX= z!_**C&VYx7I1ioz`VQQmjuiM3D;eoxqbOS61HUmYd;o(dzk{NCpL>qd<#%|r_m63# z6e}(kzh}-7Jabd3lT5E9N!ytY)XG>qa^eK)nA~W$z_yGn?W}<-gads?LQd5@!#z3( zpH9*%!|OZHOF$yGw}AwZs1L%Pm1>Fo&+8aE1mdPdR`#<;L-vCm7xq=-Dp>eB^ZgCb zq}QaT;{7VPBgi~%sw3En9TKR*n(raD$nx2_`sVdPI1fH&OVsy13FoayK5R481NBuZ zIATR@KxtC1){H~bN6o4@D>ZEIgVxT{ul06$V@o~E-?9zDU~LAiVBRHFR{A=#As!jh z*0FT!Qpaa0>|CI6|04ca{AhoP2G0;*RLjU>Q*Gg+XC0~Zk6_WkB8WebFa9BKloc`+ zTQgZSRee7nFZ*MaaewUR5YM?>MNEr-icNy{8yQW!Kc;02EDDn`5zi+ABT;WS74pV1 z!9*c$7eP-vqWQ3n#wOza1hNN5bf~C0j`4$&ZoD0i$%Er=ydUvo=4Zm`g=vpxdLbR2 zna})nI2Uq)9NL{uyW4AbgvVjm@rFX0H$CEuM*X8n50I|Dh)Iio8_TauRmsq>Ac|nw zQc3JGFnA4=LUKq67XaL4@g>dSaym3S)OA90`tQo$tLM+&hA?;Y?q26xXTNn;)HNp- zMqGka)Idz~k_0co6|wK&3U9c={JIdSR z>o4G&Iez$CqM*sz?xlGPDXLTD-Kf5U6E0UdCF}gN)0uVn9LdQqO}=$XR?QDVEU^u@sCeCm~SR0hWQ9nhm7M2HK#meCUb#WK!Pw58jIVs@c59QvKt}NnMue zNn9{^F4YZ8dRu3JGpPA;eOrREKQZh=Kg6u`V8g10YJ=5YXkJVfNVa5H&0;bXYsJNq z$31a&0`01`|MKi#ij6`NA@HR35>Rh{vY^Ki^*k6yBiCeWAIDY0G{=V(j$TFVB=sa_ z2EeoE!b8`c_jvhRO~W|&Z1$b!&z^th=(|d5XW{QDk4Mq{^-*~|`_8Z9xY>_i6qm3U zAXv>SQi!=^u0@3DN^w%WtJg(p``&j{gqB~0h>EZ+;-WlSRMB8BtHi<9xawjpklyxt zLZX&2mP-f;1^{KP3D*ZGmg=qbgPHk4@9%&g>%iw<0!KHF$JSJ6la9%QajcPpfUbwJ z3bCA0+pW_6kUa;F3IX@o)aj`iZ*Y8qO@HH$y{sAVu432e{o|?AsTpM2lHZ#z`>`8& z!NhnF`3^9~z~g-#FLA1x$x4`MU-dex&{4wBJoTj@yOgcUVCmXyu7UDDauFF zbAh34e^}X?a1KLkj~6Zuf@ZW|xCrOh*IR2gapej-QW%_Z;0~cn1uYuG*rw)Qkya_d zk@_A+0u|fBOdtmCNhj|telw2!{cja`bKl$eecXg{ZdgNR?+aloJrqk zjo9ttCH>-=4(X589@|)9b23yXVZs>XG-+N-h_tIpL!;+VVa10}>-l693|5~ay-?$b zbzeA{4ErSC1;GlnktFILU$~vXFPVL3CCE}qL+C+qojDqYfGDRhWm%#%Xe%Dxifuk~ zPaBz&uXc*}&1SOM%&a-CBQA_F~pRdQ?Aa~U`kf-0k0#$SBoFuAkX zFpL+ROs5evVx#xH7aSeJzrpcr(O9nIDv6qW`VX1XbfV(>hm`C5Jr$4n_&<7sLhg`e zOeKfY?1PA!SV!b77bwnAgo9wPF0~bkx7yw1&Fgqbi&BEc-;wib8(~P1SxoIbR?CRaar@JkxTAkJ~QI-C( zW8olR1c+XS13aSiD}M`*&-bAZVQ%Y3&X$q25iKwU))0!8G3}lYW^P!Sk47^e%&gpi zZ8H*Zcka0OY?{ zdRQvD0PA=@(AQq za-v7xpdY;?XD9(9G?@FyOK{PkmxrzTR5 zdi{Z9K01aVx3{9Zu@x z#bk6!sQ^~4wbmq?7B7;f%=&?c$GhF}hdatFwXN)1Z=RZ9fRl--{&?FIw{sN7 zqs{H-#cgnxgY=XVCZD^*8wJ-7NQXDgyivw+Q9i*f2F^s=fXc*LxvX#&|tuFN~tZk0~eg zrqSIL$@%HbI&BRZg_RHDS6N9M4Xc2N=7vDOHC~)<6vl%T@sA~gz`0Es~yAh60Dev zeBHZzy$GQD5#xB`#94j_U1~@47YGR2+cvMm#d3V~>2?m#fES?!+EAHagebg71bCA^ zSP|gShj8&=0DiyJonW3@kAUfd5+Hr=uFGY^>`Jeb1yd6wailL0DNCw_(9=8Djh4lA z>+i*1Lq}4RZUg%%GgqL%0slx?A?6&BlF->KV)2E3jw+j)=1P*&tTZ)us+K~44E#G3 zGdZ6W|I?LEdBJ?v^i#f5zWSs)6P`-CLXklD;+XFa{E3$(4I~KZePCbGWChlPZfgagCV=;B-UxCd;U&;el(xWU(|dBJ@dKP@o-ps{d9i% z1~5tlC1RzrXwerje-sUo+*e7jKqz(LEd>rPHI+)f+PhMy=D*2ct)H*vt9ks#TP;P; z%rOyx=4cu)Os?d6Z3@}~0ftEOW_Q4j*enx=SS#o4eMAYuh^eUHR&a3R%#3TzGqpVB zS#!;tF|PWm$`7Q~@~!3%xT#MZuaAz8k0R1kZ)>oBSv3`kYSIBl@+0NFHnJUbzMUb{ zD8Lwd-Ks4~tFkZba5D^qT~1H5!TSrcoC|;iUt^75X zKDl;ci2;Eo!2l~5%^yV~i$y0!ok1B2tiN8Jovl`9W~zh^7mKKiqM`qYvIR+L95O-Z zLL6Wbuo>*2e1+Ay}y4cqKS$SKFu~DZ&5|BW34~{D#}9+sX!Wh%nf!O z5Rb}^X=sf!$Aa3%7dB>{E(k4E6Ul>d2{2GOg9x-vXWpe}(=ONH_qfto-8FJpN9tq` zVrN6Lg7eDWcMld8hj`5E_j`I@5yw1!zqj|*exLsVczZ%ZY$_$|_0zJ(QRml2);#SL z-eDu$2^)L9O(i=?1~DXqt~SDk)kTg6w4Jh3$aFpETUeS00s#`fVpYZ`9}M9_W`TuD z3i)7prra{IS<-gVHncU50i=u(27pkjd)jzoFO1I{+F^LC4{Q!pJt5j6KDp_v4aRr} zJgbB-4q^Ff#1BhbK7<9S@_49_D@p5QX%v~eB$GVxN;pj1REQorK^x|YL(xL|v>~~= zY2)-wJE*Q4&(OT1?;Uss9dWT1FgHdVgiwJvuuNU^G&=c_H=(_*bo~c|zXH6!Wr#~C z!11MWdFl9}SUz>ez-Y(6ab^`56sc&zoI;zES5$LQrUap`Npe5f))rFG|2L%(fKS|( z0f1-Tey(@9wT`$Y@D@V^1moP>-uC2$ZubIj$2Eq$?lxvA$Yb2Jqk}P%;nmn{we%GU-*ttd&@h8e;`pl8iJdm#FAvrDVn; z8JbvEN{G{2TL9!j*NsGp6$D~jS2SefLI<&0;qfUm6cIA0%H*^-O1 zg!)ommEl^b;KzbIjK?AtD+Q)qY$%H6#Z#}~sac`>9|czIQNOwA96fsUCt9tomT0Nc z;2QWYqb$8o2Hgjp&V%mYs{-!*PUn7iV03hB?BQ~2?C8<47W)HbWha9c&<@4+7^AJ@ zhqMX(!pPVQln5y`e1Skb5IDWPjkJBTZPqGp;{1~hgfsB~8fbi!4KzA_0iG(BJB)&+ zF-z^d1y#KsJdLqKAkIUYhjS6NPGusS7l5&qB7Xm%Wi{)os6^L7()|ab>-@d#kqC!m z#7|9kD;o(R$89DGO%QZ*msCi}B=UWwW3g*NZbi8Nm*G-_HKWxrjD;XvkJLBD5?-ui zlli1xgj!IxDdx-#a#d?U@5u2}$J_Id z=s?bW_G@>ZGUng<)3>VfJTGl=Gn6c(Y0$LD$VQdJ0_-kJDGfH5z-Ft$732#=L~KC3 zK=8T6bg7ia*K=dDW9RS{oxa1vgu4tKHm~B3C`rlka*k*yGikeWkv#}*_XZ{9T80#; z%A}G`imsrNWXai7kUz02O)qFay05Ywr3nUG5@UpmZG)Lq?pj#7phxC+9Oyx4gSR<9 zcIsQqc|>F(kuH2=S_wG%;s8IW!GHn}eCw4iWTvmnGViqyvCL;|x7+TsJwp0R$-LY^ zAvmc~(!C{TDG7pf$Wz$Iw#L%qE$fOT^D2^#F3nCj*nreQC$__aKcp1WK-t9_f| z8LJtBZ^HMl(}offix<|nbyO9#>cWXmuI7lv0Q?U?zI1UwTzM`byQ}!|{DFS$AG5vL_HNsU(FWj4ATKO5sU4K` zWvm7q4WVNcN`SruW{iMLt`ZCLh%Q&7ua|TIP%3nXMS8%=U3J8jl4vYQJ-ij>O_SO( zjCoi#fQ{2CJdbH5&m$OB6wy-UX?gbI#DS3gmG+PffIFH_rP8A^&h2#$PACR8sWu?X zGD2=rZF)bSaR$6;ciM>@8VEt=3pnw`8*pYsQXO;43*;epny1C~fr(KlEUhP|j;E|* zTyxM+Om=S%&n1Nd^@ELb@1+E}{gwpm(P}gdM0Eyli#!2_l_r2+89r%t7Q6Hq+mLyqP!|Tm``ODJA1r7eOR)%iCCT?;KxVJcy+_Txstdu zpFUEy*xXr{;W;%UL44(rnP@(P=#b^yv^F&eWcRs&@Y%iv@ zds|pF8OZ)7Zi2y^6?-MWF#!I|%t{>ZsJZ1n-w<2bgIo3bmRxcF6(8)w0lynl0V2%t zVg>4KR?q}sKsjt(7VQ|srwj*#H}dhnK>$G;vadg{P(X|yXhBCqN#`qT$K_IB!GKJj zeI4yi_Xo?qXayVtHAbc$5a_NqAR{1VV(Wnba=l=|?ro5d*o7GpGlZ(ye)&1xt8maG zwt%z}%XL|jOY{+}_Zo<#RDk20WXhoM<6>;a1+_!{0cxi~c$aZOZAiy-Y^vFuItCPM zdEOn*%i)-hyXQIJ^4Umj(i}{awMaHUed}%}77qT(=H{;i!_Y&`mm}eY@o6<0r^gq< zk@EZ+epp#a*K>C-n3|LN!ri%gdZmIBeI4_AF)Aa_PSOgm=sC48m@AlG0CT_^1j7+R zR!hMhRe-!B45coqcMi_A;;D8jQOvq#mYe%qi4}LKqRk%aq!UjGT`}`i1QV8k+C=5c8|FLV(mrn`mzCMJx#y%uA5d zlI2kR%w;JjmVp~qsF5Yi&11GxwpGv?jE)M0b;RbyQjR~1+;YuVB-bUm1+Z=82Ta~T zlHQ?xjxqthhVd_>83<0T=UWV&1#J-8OPt%;X@Qg80n2Iq15kh{3h-Vx+N~r!=kb!^ z?RVCbbsZF$%f0oInGuw(W)}u0>S~}y!CZoy6@>+{t(P<^K5z^ZN7&NwdOQtAoo!(K zE{V~AEJzLOM_?uqXi#4h4)v=M-s4}o?UwvyI^OF4_A+jPXM%U&{H2#77=kt~7sq;E zx#p33o>zgFn)w5;7^zZ2?5_3xW$-}Z*z-W^w@@gl=RtQUSra_62F+pr$^Ut93v-v1 zHcPImuI|OMgF|eZN=V&QKN=r$m+B?=hs@1RJT03n4aK0;!9%85leRxbMzvKGuY@vO zvxB%vh&-<(3e)CiZUhKu7laf_t=OK;r+Sy!FQk{>kuEVVP%m00xKN~O@ctkJM#59p zl`v=s@!R?59?ReI9AegI^y9{nl@>{K>l^v!9?#!;D;&VfnF;^vE?n3^Nz}d3@w?(7 z)IG);#N|q(q9#)vo`Qu;HYWLrgu5X&8GNmG0iU0GQ|-UeKjnY8+#Yd07Wy8QZTM)v z>*Q}jwSa%wMy3vwdM4_CY+&;Se^E#{{XaSvf$Yn7tM~#h(V~29z4hU%#Mbb)4H(m8 zyd2fPwEsZTGBf2U%8X2)%Dw@+MR#EBK)blu@DkHP`F~c*tC&m5!B@Fo+38zBivl}9 zG5;V7(yV83V8h=4RA>l)acL@ToWApnk(pZBz@qE(WHRaGx|+XOd>`N*w*Oui?ex@A z(V$k_;IA$~RD@O&r`IKEV8rfVvIR>!w*=yFoa_L*{v+ti0#U*hSlci(7!erbB`+A{ z09gQGctDc_isGnMi9spAGJ%4-tK!=Y&q&y4G?r)Xt9e9kcRiBP^vZ!(R`N6VSGAGT zi%71WtUP|Ol7H~#aQ5~0g%BX&{Q3HAjg?^G|3rfo{Q-M&|80$9!D#Oz_Xi7siY^{Z z?q3%nsS8y4pOlU6qKouX0j>#)3!P!$4x@0K@b>}CRq2Gl(OIkif~hW)>nSze8dB+` zlvF|T1iK?V_%!-+V1eyxFR`|YhTZOq2hxE!VDB!wJLDhnhcxF+K`Od~H<8f^20t<| z_MeJnykqm>X&&~v{f_;@DZ=w*??}w&DIGk1a7=i7uNN+0+3j|x&+c;AVScnb-A*8V zgRzhZ7DCYw{s%aNL&2CgV?PFcN(d?I-G1S)pRs4WF<;o}O--cJwY1CW1jV(;kU{bb za}nzW@Dch9TK0x`M`5*o`eJfEdiR0Cfz&PC|2mReJ04kB(c?FF`zDKbLAeI^?YLSh z={-*h%tRCD@&YV`3*V_8t>S-mm3c(oxRSqgDZf&KTFR&%z3FI`8GKjr7jbOYVz=cq zSSM+K&C2vR$67-33=@1{B3UJTW1lr%x;H!-TG?lE#?!GAo8q9!Xy16CGHdeLCkQxD zFu*ko2|}GQ78>l@GN8TCWHslIX0$;tWRs16;ZjbywK?=Ra($SBsA&5W{>4bJv1+%k zHedtxEnairc|~^b%rx(`BFXiegi7^4Js-~g?*KbQ_TW$Lt%szeh0=zo+=SGTp zY9w=8efqfO87o(3+imHQs7UjU_$1UJ0V%f4p@-Fw!-xaAje}3^jk)`};3h^T08G#* zL7ZahLfhJQBoG2pcvy{HcZDMM)##3dvbRw!4lNmMuh2nv;|@Mn>buzFt$yP^lO6Ya#?H2G@K>hNQ zMI^~p@ShNtPZ|T7$o*!LTrh@EP}U9uABa0jj9Kef+wJ$guZ|nS@BXu9HkTG}_rA!| zBlj5piM!x}2lsV@nA5cj77MH{P%>X#KwUSAm-ZAA2pSlm_LLN33ou_sL7>Y9@1cM> zn7{yON?Q-c6cV|v%Q=e_y|Cp-A1%>dTVG!*FG({`8J@w2ya4xLywrI8I+j%*>Mie? zOo5W`Y;2r+%|r}*l&!t7acASey-U#a+7yj~TAkOE+zoz#IS<9Y(5)YScVmOb1nbA+ zK-RR{vQ7R)`~gI`2}I&Mf;K^pS4dGvzrmDAHMa)k33O0cO;SlBGr5#B_alpfWo!ai z(^^nOI3ZH|X7;7|nTWeX8ZxN{0`ACECY%a4d{vJ-;L<|A*y~Jb0x=wNO4R&RT%XyO z%;3k#xXbPY^OKnMrClD~D`ElPoY(JxU+O=MBAJgALq_Y$C57~aCJeU2;l3m(o=GQYG$qva_#Sseo=C1uOr7D)P}uwo6;{ul}wZoka4i#Bx~nB2i6ap zL&??!(c0l`k1>8DW|&gz;Me?-Vg%Kvu5TmQJLVjEA0FV?1Dn-MMIBM?dtdB+vD;C6 zT}O@o@5tnWq`hDo34w<}6qK+pRJ%c+hLWbtL1`fJ$MeS{V)Z6OrD6L=!#a{{z;`>P zuf8Nde!Ot(?W?O{nc@-Msv`qOv#{^@KK$noBvv0Pkflc-DU+q@qdr`#frdlin9?r0 zrCtX++1pxQyNo|TAGWOVExwBWU<^;LmIhKTkzm5o27=jyab|uI@Q;O*c&i9_?sDyS z-2;y9kO+F8(r(nA^aaI#bslhvdpzD&%kS>(_#*4;5#O7U32$$?%5)oWVR-~6mjw9A z{DYoB1*{^XQx1OJGOvm4+mrrp-#+hurP~z>Mnh4bf83=9TS475KAI>*Ost1qn%)0! z>23SP-43|zMv~dFiP^PtfnYFjZtbS#L?-CmQRJFkIG~*oTM6~WJfk!MEgSd*Fr85n z7Z`Zy{DF}OfSC;|Pa#X)gIt8HUC~C|j**#Iu8JJSAX~l7z2EUH)L)L7ZBP!TlODr2 z5)H!6G@Y1N;Q-bN;jGG7yQ)xDXbX!%f9RpWL`p483@>j0%G*3ff^Q#F0duTz^5WgGN<(CxAn;K|iSYMrtUrOfo6v>v@(GzTulvlY+vb4FNy3mz?1pdfEjBT8E}EwOxy&qkBYrDif3pProwkJl=psNPEY z>V_mx(kJr=kgn?WRq($n(PS!>jK*TIawrnPmHNdt+%gqii)GeHhb52J7iVqFGV*pd znkn#o8ks+QP(K81?Jk(Qj;`~QZ!me8*lwNf5>VKXgah2p>awjdl0PP10u@4nd`{oL zz9v0}aW_sT4lTL&Ogx*dj*gDrd-Lk#)bi=KoH_K+!NU_L_q~QktJ%Mqnq0m4-ZO7G zy?pSYL;FrnnDa(KPSO}bQ|Qf-8o`#f6^2YDN7dwG=<3EjyG#MNKIFN23L^hVJU)d1 zN}vaoZpMj=d!bKPOizP#13k@oZa`&OKY8&4s|nirU&MbGA18H0CLXG|ulE-DN+Frg zBhF(!pTah|AKOAdBc;)~P!d@m9e&3XMs@5_ z&pvXvtvanJ7dE)x7ORR(_WtMr1Dt6qGg{AP#=HUh%)>W^KbXx+i@ zk-qTSWL<AH>@|)X`1c;ZYe6@rE4Vc0uGihU`!K?s)fxtlqSwm&Cc#`+&u|PDh^N%( z6Xi5Kr9V}kKjEERng3S$*wH z@t1wVKNE-JAO+-vuqy1UOd4#@9r1n0 z>vY4Nu(ePJYC$mEpox^LA2A?Y57nB8iDR~QWiWg8G&w-SdHr;BokR=PX>2~&IN>h3 zPqO7jp_!k36mxjYW`?g{!tinU%GECOGI8uy(fOKM?w~2V;5&o!A{< z7)@gz1QXsDV-)@H3+M-_#72GjM`K*y0*9=FDVkR`jJ;o2%dH&AtsN;!;h^}PL(WFS zaZrAibHHV^bDe#3+eTu({rm3EwZ_XwbGf7C@fM$@)@eirZdPCWR=l|U;ne|~Ii;{75Z z56(sh^Vh(d2&=^)Nu)yJlrUxxpo^ALF|xI7h|BZa%52)%+`QZw2br_(@z z@Nf8oo$Zn8#<-gUM9~`3*MO~f^>aA7`w!7EynpFO0He9uIM;0Mbzg*&oZc)*mA_f=XKnk`RnTWK)m;Bd|WSk6EMs*!W4w&p}NRXCN}d{t>K`(h0QikOa#$h-}S<8%LmLgC-S$ zk#RiLd`-xmDCgYz*dK1D$DI%}-OCf3u2&>;>D*{$5$@>;pNOX%Ip=ul{pX6}MxVSm z=kEPgKK;#a*A_Z=M%*6fv@0CVy4-e0De+V)*Fr;bjrg9FYY8ofX&_F8I{^|m0UmQ>Ew9YEc-WgEfuIwVjCIAj9+gB9S29g&!98=l*i;7>Jw z*CHaPc8@(8`|6ukX4X1~9=jX`lV00KR z7Zgn$VD;u8E#d)JJ4nwgcRI^6db^#N$QVJdWajWuPTbpQA3WG@+?x>E_{olIY+7Og zp}#WS=H1Y~FdIxpmSO^u`2w69h7899lR*py*G;|vxJ-OiZ|RHz!Z&ot9E}8%5r9TW z-0-%YGy(#?zrZ%owk2!`eF_6G_d&xcp@3#02iedD2PF0|$+LX*y6Q^qtDj>B_&5ov zrf+%-ZA;y22Q56%Qw^fC&%t;@m-Q6@IMJP~AHmdghofH|x1fUMC{{zc!;^H~C$2jM zZDW!M0!(CGdZ57r7TQ*M<(Rt*7V+}sZ5B-`z6e}{`x&UEGIM9dvXOZ|9qf6YmoO(A zegotjL4v6K4nUnaFWLmrb$Fg1xE87@wv%)tM*X^|-;yjn;eGwLj)D%orG$wYVs2Tl z!F!!lT>hgVcwP0C%a?pzb=>?)LpjDTWwW3RrDL`5F!Z4Bu)IJ{a=}Cs4v(0)HF_w5 zL)(1Sh-ukJqS zl>wy5ifUQIY-BBLaBxsT2{?#R{`sT>#g*z3iSD7|fa3@80?HC}i7mKo_@u!m-hv9D z4n+Z?M9TdwF8r5)oB(E0kRG@2s%Ls1k{5DU{5!xZpj^jw9Kv!OlW%pwp<_xQETe&( zMJ~=R~7zPD_WVjt=G98|~*P6oR93C=_U-g|s86!!)9oV5@$v3>Z$zb)i`1u0+ zuY+m;FF6nEVtWwlWZT5v;TG7n;xoa9w4+8jF|u2-F5nO4xL!wHl)dWO8Z0z8?-~T5 z43`Q|Z`YFu)V4l&FaW4Pk>Zxn$w)f;G-RFuWqToND=C--SYuB+u4<)}*+Mn5b*>@B zn}cTBgyTlP>0}eJfrjWa0#-<%HQGghn#qgt(MH>VY^ZkO`0Qexcp5eFLIbh{$ku7w z%`&dKTrp}$3JlKQQj24p%5}r6$r6}o&MipbW=#x);x5-*B;%*+F=`5?hN5z(wGMPhJgUmmcA5}e6 zEMjC~=ts?#Glm)lowfQ-M0ca-Ifhw3>P9I$bL}B*KEs&Ilm%5WNn~{dI@M|=rLD6n z#>&>fi8T8)szG4QiJHvX2Ev0MTAgJMn!hoeb?6=5nbmurV-0@K_yjisAH z@y@S%12f;&^+-ewYjaT74QJKco6SPnLC>i^n{@alvr3-mpmv#Q4)5@n23=_CB)ZV8 ztFc`k)Qoy82~_EiZPIgH((G%;cneemCfKXTxtSpL-}D@+uOwDet6lS)o0SK({Ji>M zyY#EhD<5l4S-&~I6b;%7J-Zo@^nM@qYbyH`Xl!$YrWU|9nfot9gA@ZKSs}1l$y7^7 zQqtRIUvYo&opN_uWYd3&VtPJ4pZY4WF%k9r!G zxtnZ2j#hvXMa&KNi~v}Llmj-n8uUasfJhxcJk+pREHF?u=Oma}SazB?fFC8VMsN33 zf#Ox7=yc>A?utL;b~=_FPIoX+apQ=yD6CU~;5DZz1N~d(Q%b|x)jVmZd%;#IId&JJX(!b;{?w`qZxs>+&`fFcej%zC!6n=td<&!pJpV;WqX!I#Olww~8}p zEEwIcI3scV2mYV)U2%c)6nwx&w@aM=*#lQ>TNmWymCY(YusYE8T&d|m5h2*~0)ljJ zyyD10Y~nTNx*P5A$)$S_H10I7zw(#h`8K8GHwHW|#u`A>QaMAYu2ifxQ-lvmoMa~* z`$@ZfGrpf*OlrG7{y{Ome|-GW$X(um_pTVtx>>jP&M2;k-lb_HFC5$eL|?cx!l-h$cya$aIe%>O(&U-R-aq6;VDcMJ zK>B_53WmCwc$ht+z1$&=0XYfsajdAzY4FV<*9nH*gb!uyVUER$CneLa~`kO^3=Xg zx7Edlx0CnmpiUge2og>2Px$JTMCaE#onOCVgRhYdaolO)>KGPelI`yw=0Md9=PXAa zNafKCLq6)$Gz9#%wvb2rLh`o5o#hVSo{=@t*@64`c0IX#8&t}jPG(u!zflItY?e%F zqwW8{}O-Vg@XTL{0z&lV6P5=+oQ9XP-KS?u7qE+TYjL1@ypLKR`NN}x#I4(y2d z^gWr(<{gC(P1>7(D-Bw@Me(8$Me7A32-=GYuu0(zD^lcwawGlDXk`H z46zcH2E+vT%9XpX$c0KtT4Sv(LOD&8bHet5CL*-v4B z2Kr;PIS^Y|LmCV5y_#bkKdP@=x6f?DzZL;@uGJa;iTHoT|Ao~FdQlhr*T70PqRjnWZsf zSzFHBp)GISSZH)<7nUjsrNDvS0?tnzI0Ilxfyk&gTm(3V6)(XMdklF5j$cHPLk)6s zv?jJUH;nFvig=^~K3O56hOUoCk0M(De$i}S=W>&NbVLhJ0v)a3N|It|Sa!bfg%+n$ zhsC)1x+ZRk`*w_?b&-tJO5GSUjU*vu*}$y96DuT;b79)vtWqHls~%G7Fj^2eAB;-{ z{blqr93+yF?la);qZ970N0unol?dV%FP{28*4Z8_a2;_4TOvJh!%*C2Q)7N zMIa4BvoM~{`GUoR$z(0yLHucVG?1Y6rMPCK56A{#5cE$WLk1OD@y8_-|#)A%!ePY&g0kYPETw@8mu`0v5$m$V`Lpc-6 zokTjbGX3ho7JZ%8A#;~3+43btTBYTQ0 zKjl(PxVRDkazd`j)N z5`uY}q$NI9mz#2?j$>tY8b~(j|NU>d97rA9t^Y7NbA<&~Hr#yppT)QWB zJ2&2l|7~k?`ZV^sQkmI-dvkpaVM9O#P2QRJWiBUOI-E;nX`?xK0=VZeRLbV_B)+tB zHY!Hc&3k|GMB&{X`2ZEpuv1T@!3`x|WR}=3nB40u=rtix~QmM%JT(NRbDV$D4a`k$y6iXK; z#4+OIafuIK!c>tiEfhQCRnZmpsWN~Beb}y zUpj^u9V!{-nJS|>jAR+1bT&3Nb~duT4e=_od_`5bCuN!PRuOMMDq0(@&8%4e9C(Po z(({pYabbLNa{S=2R3bYzS{o_p#rjhH!$(m@@)duDwf_UQ$8CRro>#<7x>V4I0k|Cm zHvo;p9;Q4P49F;My$t$>Ey)|EKKAIhAP+#;%R5tOQP4RV-UGf6kOv{%&dq~KVNf;f z6B7>zSO_*Z)SNqXpx`5FVDYiTOBS0A7$HG@aPh+Y0&cf}K*CI|CI1#w_>fdmOC?~9 zS_Gm?3Yj5$O2@-tqtX)M4;_AAA%d)ac9HPAAwtK&w%CQ;>&`^-XY!E@@(2jK+ZBjI zw08UB!XX^4NY3SPg4Bjw?ohz#aJc*)7mPyzr_UMj$Bmdj>hL)O37;E;2VN8QUtg%k$q z!eq`BcA+Q^;j|<68wi(hhJ7)t-tJhU0F4ok)I>j^GJu$(KCV4)}`07-7V@$P|zW1a%nQ3;qx+eyv%sGa4L>tHaB#4C%)vl0&;bcGWE9G`J7 zx{ijT@irto3VG>$;pB+7;s_;z>3C+=wP-IzecmkcJXY}G^+ikeMb~U5o(?8Lj*53A z8QzCkYsvl^xGPFyL}N8k2LhQ;B&Zt!ZUTD@G_2;vumw>EQ{L2Zh7dz&v|v<5OaUd2 zkBLX4g?zI9`P|Jn=VnJU;n3s3aOVGpH)OsLy<=_E8(JKBcw{l;9bNmmBX9oPQ*Zv< z?YaAX5$)*g%-Z7O+Pb%xN)^4!@s$xR;=4chgZz>=m#k}AJ(=?^;1^F}POC=W z1)miJN(~gp)Wqaq!G-ybYEY$?V)DZZkI{UttfZ78DP1ZkhVW;itH?{9zWA<-=AJkh zN%Ul#u^8iU#xi+faE+SQN{PwI$xU-#w~s^*x6Boc>Ngm+6A)aKexLG{*W|cuB`S5{ zp9eo_tT{FF4OvyX6tsG4J3D~Vx8WTCyGb2(6a16rU-@(KW$_VEFc_n z=q%x4NAv_TCq{t%afloYT_&{zC775@o`9CE0bbnsjJ!VTTAE7#Bu)qAFsM@V-nX7!5~!A%`RMaW*0pkjs;EhlG9U{zIkm>GAjed=*4T zOZY{oaKsSyxmsZsadz#$kcfuj!s~MQq9eDcMz+RhSMupx8L?KwT?KMEZ4i=A7ae30 z>TK874H`f(q&XKcj(5eVlyjIMg>!L1$|=lViDe3qS`An=*!}qd?Fe@@%uc!0u_iTe zRU*}J|L-s5a>caY?>u<(jNg}cHsdaBI_`r))t(5hAU$H+Oz75-MM|9|` zbw$*XNHZxZH9-GcZQh|aVxy8xl(a}PSQ-z9$4kLv1oKzov`XOG!{fz}9yO2Px~Lv1 zj)wtNEa`o<5inm+9`$w@Y9R(louxbZI>smiXw)%2Pxo6wAF3nTS2v#M~JLEdaMG zJ+>fdP|ARt8w1-Yj|GN2AetXC$Ps{ZFf1W+TP+H1`%T$GAdJUvWGfM%GUsyjLOy;w zw$Asul0lrPud9NR{r<7hf;SWWKfhPWrsMenRGI*NMyN7|TwwX6J394g3>-l{6|`LytltZcvIDwC@!OxiCI8rSy`P$#+&B67 z#N$)xH+DKk;+g*-F_QsC*qnzf7*tJN=9z)CnXEf+QZc#@z6tTmoVvmLk_E5`ZcTA56HzMU{ z7wmp9V+Q3gH^X{p<+q_6o*}!?dKE9h)}U3QG(f~lknfu{OB3BEUB+Xn)MIdfTP)sD z6a{=qU6K1|ko%SqX3SC5;`v3l?;o-MRh8Mc-XBk#hkq-62XYE!JQ)CyI!eCr zFV%u{rXWk!jlU`}8h--0($B1&4g@lR@m~yoFdTc}JdS-IZ{a(=b|x^66R*MX)d%EQ z_*3y`=tD1X;&eGLL&wDV%k0$VREEzA03OX0*pqptjFEwE6z|#;sh@+#*p~xul0F%C zIs-3<`*|y=XAVsx4DD1NSnR23oh$)plR#1csf|kj^n<`aUC(btGreD%!jFyoTYUC%N0>FrxlY$R9P5kxUSWy*`{r$~GWAV6Qf4 z#l~%-K|?thnr?LuiR1O*|4N5T}aty6AKW2l9=L1INT`YQ0ZY>z*%rJ|6i@ zaJ(PP$kyWG%TIV7 zI`2L4*9Tv6XlSmhd!yW>KQ7jwf`kwtW2!)qs)TL)fm8b1RH>eMru_Q?=Pyd zp_H<0N`LI*?_CJmjMCvxI3Sv(#Fvk_pLu5NwXb;dsQ4NChn9_>7(X&{>#Z9v_q=%& ziep#s-7ot9?_rjK`Xf+MvwC~VaaKR|!1&(6ykYLX!=AM@&*A%q3WQs!HJ5d&VQr(< z4WnL$S*EXk4U)Y?ibLR+rcdbHz}MA|*d0kkY@ZQ}M5=^Uhf0HO{36(}5AcKQI~{3x&!h?azyhFkE~fHI~AEKL+!}$*D0t zTh2K4&#cVMl*Ad|%;G)!dtY(;nYly@mCK<}_#+I@hR}mi{xmgICsHpag0NMgIkHxq!jao=z4NK3KJ(O5Ded+{ zIPlfh(L3)v`c+F20K%u8n(DSXShC8U zmMq(M;m^AXuB#}^M&&P%$8M;s(s=|2Ymt&xcuM+Cf*_jos3ThJ6-H?gF!%@?q#~=Ih#zub3@N)2gqm6jG@dj| zUpUP0u2@z&UA?!Z>z4r-MTDjnatE!$yxEZfTCMvqy{{K{Dd9O1*T`GY1rX~BEj_q% ziJ(T_H!9l5tfcD~7~!$rLU6s-*4kEAIyNNrmY!_2de6fnG->M1Id>gEsWB}PLrs$dimZx1*w)$?U*hZN-R8AFp7SE(I`9zEQC33dguXYp5d-7 zha;Mo;wJ@AwsaVDks<;{DjaA+AOs^5&}5dgozaNX9)gB1GTO`)LNe74-u)*t+BM7WC$B^i@;eFA@2Ld4g z2?OJ23t$HIn@z|D@;3-Y&Y=edH{yac5gS6$2D>4TzO9|kf>m<2 z$4e;79wFL5j}&i)*zlCaEijlp^hLWfgPNKtp*pF{qcG9hl4(4aVAueR)4a$=ol(t zlZl_$*VQk?kWcN{!F>L!k9;kkKX}Y7+TFy{F}FPSwMV`xk4fk~`WXBxV|7TsdIrQB z2&D*1av017!*@W7nu0cpVLRZO7%m`?CH(5!ZR-o2t&5|D`W%jf0oyhGudPE|S25}o zO=K!psO*T{Z2_c?Esvnw-kl1BZ-Pvejrh4GUZ0h64cau%c zTL-o~tgzZ)%lE({%2MJbFH z_RXOP`hwi3k`zXN&TXI6g7aB%c4pEYDmu9CsyW6uJYlXBqNL;)3mb(P5SVlTlEZut zIwwDSfUN9wghmplIwl|ZLfnD(qU=RVmjJD!zY0A?X2GMG;gT)fCdTQQ+wzIPyoSM= zO!fXM!MKcD&n?|77=K5uHtZgWsg`3FtE0qHKx-`CzkL~z=BWl${vFH+fQxVeMlXPx z9lAsGJ|z7n=qJ&^d3Z_e(3b-G=^k90=t@CwxuVw$Ics6dfiAhm&lCkEJ(8ixu^sj_ z#hp66%lHuR{G|+sro$)X0t7(khkOR+H!&2Jej7v*{2UiJLqzEb$C>NE8}-G5C~!2& zyIi%p^-aFoErUp2%a;`%wut$T#T6a_n-WjR?ikRKq2~~nCgs*BfL4tZ-c&BbhAV{{ zJaR$k|HcQY=deCjn?Y>4I)22ST0taJRvRFSH~BR6!J54rP+|)=Y*kOiWf@d)dkA!l zdQ$IA4B+7T1k6(m0ChQQ}y%rj08 zQ+Zoqwk4WLeS=6n;obz?c_N(L&f*wh&$zncKvs zZS%`^%hD5($G67Ezp8&wBsuiK*K!uAxwKwizhcA3HUQhAeZB741j9BM`}BcS0T~ey z0zqFDw4BY~e=|{s#Mj|@WHWR*+ZdNfRUU8!{`F9A{9j&E;M^8CKzKxgXy64&g|9Wq zmY6hz{O$0wVSfODB~RObvM!A~O+1m_OEsKnnDg+5JbUAZKATuZYYZUrkTu(ywSF5Y z*A=~Adp!Fa&B4SHd-Ta>h)DDJqtnluoV&bgOKApt}5_ zTvpJ-(2Wgo3YkMdG8y>%R<2u;Sv-$==$~m!jC}Z3=Lk z7M6#7#_*s?JeBfWnVj;~>mtmxcsu|paPCJ$Oo}WBiO^&yJUJCOYi6E(c6()IW#22C z+s{7xv1g2D-tmSvOik^jXLWT=oR{Pc;|(vH!Vo1-q5J7^DPO4Y(6&eg%L* z=1RT@IUpO0iId$R$!DMoxaB6oW~u-eFXlvM%sk z%5xkh_r8MyB3>|ytHlUtN{0f@h|v)9qVHHOT42FsjKi^|-rrMR3I@gNd%u$mb~?eN zm`4ZyzLK%`=ccreX;aMqj%&cMA@G{~Kn@jJS$3kI{cIGY0f6gmB|BXhA4R$lwU7QG zzd{`rQ$~%TU$93~mIYFk=MM$qzv9`&#|Yif>bW5yglA9{~N}Rh^)b_l2{f5<|r| z_Vh)!yV>o1M|IOTWPe11sy{x3Gh3>oP_4l_t)8ROME{UyaY|FOIrPl2;ATKQ6ZpSO zJbrinQhqz%&JRC3I3}MR&+v-d^B422{2HS1uzk&Omx6Yi2qYSWL4YAVfmlL#0)2pJ zBsmj$;pobnS;sM)IWh=1w+nUD5H#<`s zn}2N(cqji0I{7Kh>-G75#_jV3z1{;ZAMil&C~&7* z#C`Ma(a0@F^s`}CCS8~q%N|^OW5}x=oji6@JgX$)-WmKBzvIVXfuW$0LKTNH!omX= zODMzzhUHLM+jie@Y+xe935wQul{mbLEby4LKHhr9#Qda zP{D#V;9_lV)iVZ9h)Mm~7L{mt7*ujsJ+F<#WZMKiDq{8}2^=m!K%&8h)=n6)5q~~K zNCx70*snF1iSu(4>Cp-!+Lkhz>Ro3Hgih|7mSb~HwX;Vu@FGeaPMPtP>D_{V)1FN_ zs-Dlhe_kwh2vP-jv#OefJRQOp>~=dBE^P04hAz0=L&CZ0&Vo0G@>Av?g$oo?xdCDW zIRlBJ+mAnf^UYOgh&!Dpf8+i2SD586iB1CK73(ls9eMt+&;UhEg)M|~P!H=z~a^;DMa_-bE*3J)7$y~9ROQw2j)}GivUhq54-+_eT{hgihW25Qgw;WH8 z9vdI*_S;1nq@xgEZE+MuLO@}VZY*RmU7#dr2YhIatS?Ys`tXOBcGfS8R=gBIQv^!A zPa9&U_if_`-)0+|bqj!%z{(z{7@%~|XkF9^BMbekT$P%j7D_8jO%ATx1``1U?)wi< z8&iktP(**@-sIgJYMp3?<4UTHF|0RdPI)FLnVbXq=a<}b3nJ{330dnaSkwZhN@e^O{y^r}L4)K5=)_IE%QxGkI#o13a4;%Bk`ed32p=ahQ3fi0# zRpuNS({QMbM?=SzU#^s>#VwN`IG4V43|tvhlFcOC zh@hYZeRid^kLJqdd}*;zSQM#z?-%pGRm^+ym0+lnTgs%hRL;vm*Yg;$k8BiNY_W zPrYJk@sTCh*V8j>Tg8~ZS~AFK&|PU=AzDzz)UAS6G3o~rX0$L9Mia>c#}6bE_jv>L z!1flW%a*=!!^Ff5D?89TLIo)W*6&INUnz`KXpubHhz0>0k#kZM!xnDqfEPP3Y^knD zL68QZ4glk!GT4vUY0K^xVqMC{Cn9ab{eA96PRv2IVnfkVNq2ew!Re$s=7r9`4)~7@ zXAwUF+XYq#!o}B8@p@ZNuBmdz_8*u@YGaK9so*!vva>Cizm#hba~&^44Ley4sk%oD z@`RoM6Dk8$iH)_jb{Ek{Z*XK{KdyUI?+#`${OO_s3%y#|;Q}+Wq>`UrpbSr_d_I zD7ArSQ{IsKCBXB0Jez@#v0=RWezQ-}(z{T=re!^d_-yW{H;1x9kZ%Go8^N8C$Y{4; z{+OyyufDdn%PKg7RuyEmx^fv%YYgx0zzQ>l@eacxJRrcNVNtf834m+4Xy0?Q#QAcHHIDqL2E5?+V7@*gy15UNC4^WjuobIWXoUyBAfQ zN)aGgR`8@0vkqgu6F1#-Q|i>crP95pE@hCIkm4k%snUK$GxyBR-Fe7$#~rRi$bth6 zCSrDiK{9vDHJ#5K#Yzg$V+D7nz+@Hj!uk@cCRhKig%VtIbA?0#~^5!#PW@9 zc!8z>8Ig`{NEdQ#J7k2v{!aW|y1EU=A3M1zGyN=C|GxT{e*{JPGj1k6gq20uwjXcfmxi9jG(94qPmz&D-o4E-43_25TxPG{X88!csHeqSW$j|ReC zM>MJ-V);IQJXaY>_%5RW)uuCk-=?C=36_!I65Ap~iFoF#K%S&c*`3-Ys} zYsFX42oaCZ;{mWZ5Ds`;b$>iNmW}$oQC~C|_Bf+BtBDD-5x(h;_dgYoua9wg%Ef zxX>E#Itl1ezbB+;YF@w76%2ww1_q32v2-#?0;sL ziWu34<{H^g7;<2*aj+knEtJn4pGXvn$wVGQ{kGC`x>(CD%^uo+_d;;)LBvCI1I~`&6cH@XOahSGRx%+bkeWsR z=6n7x6DD}wdn)SAc7}ixN2@9!9S;9WMmKF1u(nYQqP|ti5N%~Ju_Ofb`xN@gCZLm7 z_OKMOVpJVC;Axm@LPw&EIF?@5yyy3)o|zn@O~&WUI$Pm}c^`NC&hpvv z#(So1Q!8uFVZE4p-~TV5(VQVA?>^U|P$(3t{`$ig-|zeIBv1u!z88ETy_?e1t7iiz zyhZOA5jg4_k=?h5JbL29qc6XB{l?gd6X@*G_NOqbU*)Q!u9I8bVM8J|q{nh}NUR&d zX9LI4fGetJV1XZ)CU5l|Sgz7*h1cD;su8fZxd|ZZ%Z471BuMtsaff+njmeR*r*VBk zLZIhczc9cMBTIAGO^2jG0(KgTO$L0orsk6sQ1lA(OY z8wzfulyZgJ*%IuqYOOPjH%2=S;O!9YAZAMZK7>xdH)<#usVrOw!<1wYR$G7^ z{#~+i*Wt#cz|`W2MHqGVUF%fCs3V&QB-|4oGeanND)q&zfP*V70^K)kUwLt9*c7%6p+vdE;Zs|Wgb(CvMPpnw%a+cqs#ZO?wRP7QrchL@ zh#y-pI{5`-!a44(*S*DxQ#ImhmtCW@N(IG^kva&e9a~xs^cxJTR&F4eTLIX1im5`2 zGM_Q8Hb3ETR8TzWlcUaK0!KcnDk^VC2xS8s+{0whfW4uz=>QO2)3?Ln$-O!E-pN!w;7ppOXtZP|!{Pf} zd#_}o@yWeL90z7`-0|cH&9|!S4S1wn$7GNSgN7+6A%i-MnS=}u--{Rf8_bq1+SvZP zkoTf56!Km4hQ1=V^1WCsBz8{f|2l$|y??{gJ~G@`&j#x%ZAFz?crW;&=*^PH$wA6sw_Z3b+Oq&tbSVp24z>tjde|UI~dP{-{#0Q#pp#<|I(re z3fCyvb+NTAR(I$fk7Lau_oF>lLXLQR{8RnkfQP$_Bmvu_{L@Ml3f&vVEYKb4j3Up` zCA$bA+EYbiG|7A*ilBfxRu2C~FO*%&hC1o+oMxow5+NCcu_kOz#9Acg(uOt{PRnGt zfFg+1OemDu2&bX2JE!eF$m~!myqq#d zfRR{%6`-1&$UpQ@{@$le^XaEqkTH^4Oa19nmoGngMq63Y{vNeH+Nr3n(||PsVdwJ_ z@&)SkPkUk`E?Mg#TDblR&%POozdjyXlQR1E(*rL~L=uU}#4}wPez7CxkmiEEfsW`v zZNqg4=6=%<(H$yB2sF3ER(7{mQjueT*1v3UfV)2i(Ypr#al0+LsHPN2;n?i%aX}$% zB=x>_t;-BsBYnuWEYQvQ{kH~dktgI|my^iK#wK&JHAPR+{8;@p+iFkb+x<--_MkcR@NYI1#ouT)EoSts zWmJ`63O4?;i!46LHt3*ypf-kMfp80>_@arVEKM;FjvmZhVC!4^_~vM z?wa9p9n>P)yJ-r1H+BxXTn19_e)m3~8|e@3E0~)ytu5ENYS#qAC2ndLXb?ya?mhrg z44S5qAiYA{!l*434UaZ29?|o8s8Tn#FP_ZCV%cPTR~rkFL@=0$6o$=|^yphMOv#WE z282U!z?)=7yP<=8Vn~4wML?V7n-x6>TsKLMi@iw5*IoUf)4$42dOnp}u7-=#1)n#W zgXAc@y?Y$(Zhs9rvMl{JY(v+wBELc#5M}_|>fq+c8V`007ZPe}+^Q89`fKYBz*`9E zTaQ4Ie|bATy6FoM{Q^M~uDul`NW&U~j`C&DW?D|e(oSK?12v5?hA@}|fh1@4-xUgX z77AZJci;I#&lL_HS~~e%arD0X?)#;4{l7kU?zzq1KGbafC$1UA%f5v*1N*o@{jwJ7 z$b!n_L140i`e}^A8JLhDco03z%o^R%oEyld`{&7Q&X*}-t>Gz4!qGq>c%c3TxrX~&_IP8bD zXb`ebS&NCBN8s)aELl3<2SNp1r!~l$cG=TA0tckwGBa;SK#7^gXSLH&emRaeQY(zU zS>2RB$e(Hc2SzWRl5cyk_Uni+ePW^pU|$& z-3?nEZP(_YVQ7}pwZ17%!K(-aM2uJ*PDMmFK~4pPU3O8Uci*Y!%`Zh#rvw7lt-X`? z0tg-L{jz#d{cq{Q3{9B=$38uFW$ZpsbY%xtCeKRhq4Hlfv zsP1z`5oS^JIU*5P&dg3;tL4m`D+1g}Q9BzedW*>^-?%Sc@?-aQryh0r^r-Vqp#&}% z;_$0}-T*zX(U%;nA(s(<>Dp7jAdU$tKcM3C`1@6EfUPNT6jRE8_{o}ttakz&NMIdzT18P^ z>ETorc-CM!RXj{x%SFH&WH+sZ(PI$CtuMNG5knljw17t#y?FP){M^C%t?nS(i_N#B ztx?{g2CJ)7STJMY+c{e}w{cN@v z--D-5TDGCA7-DSrt%vdl<^FHVEyqmJciOpFzx)WpSE2I}8jQuPw(yb>h>QiTwzLuB zW4XmCD8fYvm0!Y1*b=OV!(|iE$O*H9T;#ou-o`7E8zz?PkQsWb5Y=^Pl6pM>JppIn z9Ztfb#PVuSuj6~D<%fEHtGqxP1vOyHk>PqO^t}u((LDU~2ggnz5g>-6vZvO7!ApY# zL2EVAHAvevHBd5_8cfd@(M))_#7 zT(#ehgi$gjd~eu^sL#VyX~cbgyDt_UR4TV;OPVhcnVKGt#C~;Zdiv*$NdtzOx>@qpek)V+ zme%Eg&wFc`ss3N>#N5N&pyr7ROM_NQuQkZ82I$BJbNXzGdKV?adeB1TJiqauWog%W zypdzaj6N7b>C7YJO&~)QR182Z7ymd(Ti3D?HlYv$ft1ZCM9L9|wRP zvu`-+a=HzM1=CGFIn^d*Zdyb?NCc%Ef7q<#m@jh{bm8(x9O|lRZg&AeQ`10Nyf9Q9 zOa`0{{k6M|v*kLG2$^dVj7lpVJ;R`iOAXYZK!zn(*(Iy2f>P3APW=&)nwIHGz3wD_ z2ht)IaJw#QXO~93Uc;nDA0o$g0(EhQ>#4`}v(eVA4pno!$7nW?X|6kb zELTC-#07Aup5SyE_#0VTico0EZi}+a&q(vECSsK7ENR5iuF+-=#+qUCj3i}C(L5L% zai{)utnR`1FLTKI8*CNZ$+qzaCCA$BvuEj_;(9eX^lWe4eC75@nn1>-xSQ&_28)rE z_n=cp$O5SajZnH%9z{QsP@wPH_=mEjgCtn=q0`~?6v!xyPUD7xKU;$KojKdHh(>)I zQ+1t*+8+@=c z8;-{^Ru89R{l8*fx-Stdt(u5^Ob@aBH7(yPE-8~s&PIkl`rDLCzy>E8S z$ymCMNzv}gZkJO84?mzelwDQmANY@y4`8roQ<+v&v|o6r_rgP<9@Ke6@1Ym?XV$mK z^FgyL`f8U{iwQdn1kCYiFlNZJj%O5OSnnIaJL9jutk{6Llzl!dG)XJKpQ|YSDTx_2f7$edvb2 zk4*MTh3IUzahl{7>kPyhEt;C@t@h3q=ivWZy`-fAdH^-h29?-qWRe+`987dksGiJ>7flTaXwY;BIyua0NSaDM<8xUCdHCQ=81n}du`a6otKnX_2V^p9EvM+Kc~xGA zJ0X1_pKBL$>uvXL!O?IOmzUR9m=-5y3sTKfM1_GIqOPprx7o?JKA!Jcbt^i{`PRqs zy9-|o!mq|K-|W)Tp<)e~L<&+7XxvC9IL1VC1u!sA!#`|-YrYL~KyD^M|I9vmnH`PT z1<{o5boW$l(BN2!{s>12M#3hWiIP-#W|PEpE^u9(Cf||5oPp}fR2k2iyYPtv#*q=FrwTnt(2)M!3k&2`9%+k`? zv-oeyma3+oWi}BxK1}<-&{yiL(&jw4+McTRviFSI@cMjSA-5y@0)?4+UccYlL*S3x z%J-K1rqbA`RFr_UF_n$L>-xsVX1h;V4b#1;e>^Yfr+nT4@{#ht98spXLDGso&?GBc z@Iyho-p2RZ!|#mThk5LI5BZ%=x4+u$LIOjM9qT@P#rG5~Bdu2`OBgSBH^$F%{xms< zbQYSB)h0-?5XHaQGdG9#RLFc<;6MdS&6|1*300^s_E+U-bg}KfP5QXNkGkk29>!)T z-5px6t39NtjO91j9<;4JXwK$(zo%NZ^BhbCq!N0`)-at58YO=_0==;79|QtV0%ku5 zGv4Vx6>Kc8fm~L&bQ4zK=JM_<;}3*|!jEIVzIy~O@y-*T<; zb=c3HE*LomN&RuK$RYaM+(H2#j@8cf&^|R*1X=TXo45jFoYh#XFLPe?*c7FI4xVxN zY&-pe`|(sY|Gp+eu4!QygLbit$~0c~9$tZ6p9{UsQDw4_kIRf9eB1v$>mWk+P%?2y zKXBr$_boc~C*qx?%&<8_34l8Uw!#`Rc)~b9dm441B^<&Vv1z|^`A{WYjwKwqxIR_a z7f~(*IpUUV_F_0(y!)6KKk~*mpL);9csg1U6E^4Ri?O43CMw#acG)!+zZu(-I1qaB zkc@Mf%>}BJQZ!yBVOkca! zU%R%dA`{hi4K5jZ1~woE8=Oxgb{=YCEXFt1;td&{8bg5ydJQbfDz!2yLBLS}v|K@i zAW1F_V{9QAJxC>>AS%v)QLZ@eyTW(ibo!u;dGwso6rewT53}(6b|-a4EZltD&hw2k zsm^yC_BVz7$4;k_*&8U%6@iRMP9*nky90KcpzI5qAK3}--A2aW$ zkVT6zV9GNa)j}b)6w62F-0e9C{x`-RZhuy+CK7pAPjPyoo_S{~vK~!&y;*TFUhuhb zZmip$HJ?OH5wwxEg3&fAYrz{ zZf@N?f#!maDRlZK%C)S6S4NoGm<8OKKa;)5SJX0=(I%2%vWgsLFYM4jm>q$cH{?qC zkNJ}}{~d+QiCv6Bo$G^exh+XW|b#;k{r2Li`6&(C$n$2&$h z8hAVql^c|SGfk9$1I@ADxBdpNv@h6$98A4EsO_nLZRKcNQv&Yj|k&fF9d~TS%=s7c!cLmGq|u{DZNChp6F+G(L#2 zB*tcDKAU;?;ZFCyWYR28XEs)S#YF8yefD58m)wJ-_cJq3W*+W!fB3$rHto&fgiJ0| zs^5QM$&2S)L<8pbNHIb21*YP#$w(_`As{C*`5~grBynst0e$2y4#>C=tt@@8SiRCr zvuG?B+D5Nk^ucBt$fuBn)%aBEw#CKUQh7f!5&QpIz2w!w19{PD|Db=IpU6X}lHwY_ zmCCc!c0g|AWl{$ii7w^2>#&>tI^>ZeW*c}SrhXZV0MxmKw7Zm!ksNavv@-M9dD9W` zI-PH+&fHNwyijX~^l&0kG>q-)ZEmk^;>nA_{;&SR@s*Ff_RxboT$DDHfsFP(iBpGd z6owE9Bx8~m#TW*ptBE$qKu~s!fFWe3q~HcA)#heLnwFw%=~$F?MB-I0!zImX?P3p@*zWE-LZ}unhJB-L->eNqHFn9b}$( ze5QQ+?d6%rnY(U#7x#M0oTHKnXFWcjCmYUG9CI|+$kZ;Yy@RQT9!ed&UKa_KXhCgF zkg`fB5DW%F2y^wNqSyJ1*vNG^v(X?yQm?N_BNMx3pp##N2Zpj6QHJOp47U1b_dtJxXLw*GxC-i#TFqXi? z(jIwW*oEqRTpCxPv5r2Pj7TKz?;2Jn)5h-|YmeQIw1l0p`^R33k%MU`2Dg*B^e zX`C8tPm^IBK*~d)VV2#ROT!ks2-<<)!*X?CDZvi{_h@-(4_zTuI7JxQhZha29Qn&? zC+k3nvXt(!dP&qz)^ObE@M%k$ujcnoB|kiAOnJY;*nivow+nH*c*~s4HYdJ1<@HY< z!bu*F@7}3o4e1q-;o3Ys4&U?Z&f7-<1y2qO^jD#mqtc60g;#oKaeF(*odD^iP zh@LJb!ZpK)Mh&ADhGL-BKF2??|4yq+SO1KwKzz%{ay%;TUx3!Rl(+#_3)g-scEl3&LD! z=HKv!d~?N=*DX(%5r;IqojqUPT;k_TUD={+!9Kj9y?_ZkxF?@W-V^qCbx%XZK2TU? znhEk3KrWCxIx)QE=Ksts6>oVTWMXhvE9o61U`9pqmoXwT(Oo>8jVI&y%ZB6Q2Xx#j zUmu^!<&(*LZfd-qN7g$@D^+UV0KLD?nsOsBjb2OC2+>`Ddm0?%U%oavm%$}U&!N8C z-R&Zh8b&@ZDzA<5y48cvp~TxyEGuzx0xjUJe;8-=cupdGRlTUO zQ4#DxTDL1!50MeImRe3^QU$4o4NXPOOHrAvAPR#Y(DVxFxkM|QSamr8f`q|e_jwil z1_g+wK%*(w%PPS=kZ**UMxNJP;b1HPvNw?r`Oj|PO9>K;1ZbF&_DwJWf=kr=LGO^K z#)*AzSyPps99W1XA*WFf!~yhbkmdoT8_+vu$6v^WPnr{lt9I|i;^G7o<|A8*-^Z9~ z<`zwvS;p2>=P=x0nmtwqXw)2V{sYrvYLfa zLrqlDt&w(-wWtPL9Vl^fggozAYHu=SB<(RGPYZxYngRaJNb}2!OiVEH0FId{lV@`C z79n-0{x+`CQ)EVMSsH*3Hz5|wh_y#_QKJfm<@5GNSrXSN<|KFzvA9fKBomy-xi|2e zjdr+dKjW8Q{*3Us4(6%+HlGbJ7BzFF{)PsPJQW8;HeGV|k*BM?34;S?(^D#g%$3X3jT1R=DOoegmSh4}+N$c5`h?%|B9D21!;`E2?0;4%1!ppaqR=0iv zRDQ*nc411q6mE83wb^)#mCowQU>yE~_-(15#Gs$RqK`zKL-4S*XJ|{Z>{n3CqG%I- z`7UoWX6>L+dE1hB=TdC%-q_L!!}!5+V4@NzPltjIcLXt_{;4OPxRT9I1%mE)KsX8~ z@Ac2#b)ss^$C5|xTo!MrAFb7n)@{IRrcJDmG)m~Kh+xbe_D$t-SDtuc%IkE6J+t?o zELLsR6U(!u&Yee+1Gt$KUw#};<0+U$SVR6OmkeM^fGjC(TM2=rDL^Wq;6xQfF9CfP zsyPlI=)tIh4ni6>s>t%QqO}L|t9C8jMLy_1Lh;i6&KN9~-yQ?wn=zrDbS~Ts*%8V5+t?*bqNUe1?e0we0 z$T}RzfR9ho#|pU#ZBHPP4VOcD%B`30a@(_qK;(i4L$3G4!^OF{FBU1zB|c;F?v%Dw z6&5a~m*i6NL-?(-rXx@o48@<7<=4RMUf~VwwL5eSJ}zT{nbcKnjv;XY&4DP5G94^% zAFQi~dCr^y&$_Q@dBA5qC#C zPPYeuhz(oV{iw(72zegGCGh66c!RBaGyG&~u=rT~!x2Sswcrj#EhlR}ha((uxMF@u z&8b?-rML<*)0X5^uC3ivU6PJhTak*BgHJKDFjOqXIf;PY12Mj~@cmL6pC63iC!AUV zgIDnTP!|DN!ZG%K_e2yK%K{9%%+}`0`$0c%Tf_nKH}oNhC?*L?UYZFC?+Noxe=q`! zX-elzfNHXbsy)fhmPJw@#2mQAlaBC@S0JazDFrJ4>`|yMj7Q~4hoA&BF=5US2|1-? z9h2|(nI-c(K38_3hRe9$&S?^ubB7%s_brZnPlCJbA9qCquJWAQgUK-$uz4aO`z?-< zw7KQj|0-Avo$6^Q=@Xz6vWC=-tP3t`4B(74gK4r`EK*1qQ$@qr8XC||S`C&OF(!G5 z42?x`aYn{w8mT?0XYYxpot26+9T%x8ws+r+_n&N}8tKtUS}SkU>S>P$)s?0*AG(~L ziT>H;^lbS5)*>_MU&C>>dB@F4qk;(o%@U|un__^H&?y5AXqqv?(Pj2@i_y0v@d9O2 zPov2PX?J8;Z-+d*&%xUx>SP%GEfOOZRZ<=!hWxgN&n3?Bkv8O$=M<0cC{}KXPRu2h z*&IC8Wj+v}gJwFqajrq+WbH13&Gy~;DN46$t(_G-(R>74x{!V)v3OJSQPKG3hF(6V z!64RXXpw++ObhR7_stFM|Iu;Q3)-`Xb%Ktg$*SG||>fmx?KL!R3v8# zEU~ckV99AI*6>-yT!}(@aK)M!b~$xCaA$0C_6QR_+>D`7`1NmNLl(t0(mq6>DyqI{ zQOLTu1f@ohv?vCOR~&hU1jO#6Fv3Y5jrBH0CxK+zVTU6(1u8e!oR?uM+R2a=|!thz}ZN9AGm@{5UXW0K5 z449-eMa$^055P*KDcS>EC7c8@QnofQ8UV8f3_PKe3Py>Jm!L|T8J1vTsO5pPmPQJh zd;`^D93SmO14Obc0g_FkC!dmt$+HqYS&~S~2YC3GkN9HwxexBDE3=9b0UGkH z<*7{VjS?35qd-h<5hb}vyyQuRo!rF1>8Y}}_V7*BXO!5^kXFhXgy#a(ZBfD3xaCzDrPQzVCYz zTqX^n%vYf`8w2wj-qF4Jy_)t36Q~WKrB>OnHb5Za)!W)zYoZ`95FbUoDRa!Nw3qAF z8f4Yh2%JBc(0UFgQeP%mgax9aO_K>vFxC(SASfWMA(BbZM|Sim*y{MA~v6M?2BuVBtwy)!{J3`bd>kC+dTP%%d0t1+qUL{a7g*^TQGzDlmy(J z!)nz4a%RB{NIi^qfFTDDh>FDkJIaYfaCEIjB?5NQBMjWG4Q$tT7qwTIYh(!kL{^CB z?p{C&7}wJX0^9Gl1ru&_@*X%}67Hhz%TK$DG2;~KaQJLql;UuCVkEYy)a!EP;!-hQ z^h_7x{y%iI{NaG(gwy71x=}bA8Q|`-+uWM^w3sVTR4^ zZxdN{7xFdf_7VRG7l$^+bb0{3sG_NmZID5$1SEZ$VjS95?Q^m1is>?`;G4oae~ z*MBl!%^#{2s`r}rJo;#4ze+y5|910_j_8FNoDP(s{z80Fd{N$0nV$(PMt)g@Tk+Cx z(-1a{if*vfqc{PK(JQzc{=^w<-dA78_TK=EzyuVD8V*n6e*G_1^R?!YBjSZ>p%y>V z|Kr{moO&vG9229lN`eAKsX7VF)Lnx!ZHFKdF~NHxJD^d+!vZAFLJ?&?_&Ge)55jn6 znOZ;6ZXZxh%D=r{{}6T`04fF8zA2pdUw7=WtM$*|GvUI~ceSypez3mLmh&3x_rJiD zSU&2ukde5v zkSzuS)o^S+6|bf8t;yo~J*P6O$B#5>lTFoxu=_-GnU(z7%q^C5}+uNAL-p4w9Ur!TLDD zl?sp`NK^Sf2$hWQm#la2B|~Rp>Of6~FGP*~dLs9DcXEllBEq#in~Rdo$C^_k;?}(Hp)0j_e7~J%~9MZciXt ztmM5O?E5@d+~@Rv=|!Di;Yk-iJ!7?=>0$v{svrYL4VfKPH5q_?3vVsFb?~<_*ufDw zgP@^Pq99BNlL~Z!E~1hXt|$Qw2Vk?@e9VJ5_$R+(0-DsOXLdwsD?xg3$>lmRAvTVHqk1?USH1 z0DFclbb@w7zDFzB+F?rxuv`YBs7-|PPLg@v*=j4LNI(;Dmr|sRK0s$cD8RO}jFKR{ zn7Q6r7dk6Az$?9O0w%Q6&YpZ$QauE;wDcCl31q~oRZwTU-P_(;MW(6l*2bH%AN`GA zv;WZNY@bLy^OebKxHT!YGR`}pbJ8Sx*VyZE4REtrQ9&3#Q7$OASH>!-jk^*B8@vVT zy~zxgTv^heiHVrd3gDUJwV1RVwU&_ML{{@dHaWx~#*}oZ2;=GSU9;Nq zGZOdD1D4{9 zOa};x^bm^W*^3{5dUVy{N@yOp*X4Gg6SjogVNW8Zp3~VgYKCcIBWu#Fx*Y8$livj( zDj{QpFXXn1TGH=qwjD03UCgJ#=?*=3J!*5_f|(&W9!Xvk$E<3N59c~n54mLL!sS`CsAL_g$AqD(FR zpIez zFf$QUSE#FRiH9@E$z&!R-})u*{G@f;A4<8x;j z8eA!|qodL|q{#B0igPNrsVZTMrvn?t(>9HtGQ8$*&CyB}87U``AO#=zVGHtvA}7@dzX^F>11>LWM>h_1qHd3{ z`@=q`C)zpC$QU>d+l2SmlxYjo(i+D<0qbCt*EGhF`L>DJlfSa5a3qg3QWHD6q)fN{ zp-Ur;bbD)Wu$ouK5V>Og>&7Y7G8WqYiOh!v?Mp8nxT7GOc6RT4KJ6BUJ-gE`)pyLp zCrLc=9hL!hq%2=90l8|5wYuK)_x(-1F3wzcepi_7jg^%RLhCI*FtODx&@Cm1Lk0!< zS<{KuZz4*kC1Dtf!C^i^)rGV$QI|#T+rW zU%5AXU+A9feZtY}jo)+jo^76hSWljCYHSbuX*5oZ+d`=h!D-Fx<)TRt4#9RRnHgplIU#kE4`RAVN|Ne95&jWti zf6nve^9P@M?$EjC4xT>;KjDyeF#i+LmxJDFQm_M1a9G_%;!=iw&S6&~VFmlaX7jpy z#k1{7rHxJ0=JKTfK>0KGqSnBry?a;LU*%}p4>M6HdQ*56 z%gJPa4LiC$TIc&V#&@|In%R{>PJk!Q0nNe<*`q5vCGgTV<9FgklyY{woJ9hW(Y$h; z|AVzdyc|?usDm)`BjJ@=(}1O*m+=@ii|#gB;F_CHKKZvWIe6T;(9~pQ{6ph8DD&t(S2;hD7cBtnA>_ zQka0iMlmi9@uH&$Ha_P-3F=}VlAkgX?j~+3;N4)xd~g(17J)0%P-Pm>ElAKYSfRVP zX#aX4nNBAG%8fm)R^~GIV?6pJYQ?^cb^iB4>d3JpseEj1aW0@%>V$j~l^;B>)-c;G zE%1;9NON}zo{hxPgG4EVSh>UuAX?+6VYglq6q~_N>|NcAsBa`DnM> z-zL$qN_b+YuR<+0QBamZI7Chiez=F?Ue>dWwqvX{MED_wf>&o*m7Rao4Njm6CcdlW z7~(UMV=SEod5^pq^Hg>`^8u74w%urepT}W^!>eIr(_Ld+a&$ zs+oK^Y5wSV`MphX=mMv0d$Cw+PIvPw$A0w2Si8OQ03;==z2Ct--B>3D@{8DjUl>@6 zOf+Azq#}s3H5k@0Qz0rr4XJIY*;p=C&2+K9R!p1K-!2v>P%H{Kf~j&o4#Lz?({I!3 zjp~ThOzTmv_YWrSDo#XaW8L~2yHn%iSFRML0r|f|ZTvwXJDG)}2EV7354wt?B?{Z6 zi?_f1?U?innA{8LbpNGT?B09hZm-aB_{g#LLMpY;K6d1>!gTC`2V-%A!A#b?=y8P# zrw;LkLii{4#YOL@;`;{q1BYrDqdmb-V>;NOG!M%dWNBn1_=kX`@`&LM!?mz?t#;D1%^$#N&E;4! z5jc3~9QuYsfwhk3{BzLdD&QlFGB+EHVqEGjxWMKpeS*q>)*!lNc#M^^w869l-n+sm zf_O>$VEu@D>W;eS$Z=nGL#%D&yvL7dlRQxWAc~ADS?~SDwphY{&xqHr(V%uM>wBqQ zf61Fu@9J>_o-(Q=Z@P2|CU`{?VKQbs9MO9jB{RofW^y3ye;Hd5VdBZv{&q53iW_1q887Ax`tOkcxrcMMc&4aF(ntu1G$Qpx;!e#I499gn z9!5o{pQHDCse<-NUSk8gUdGx_LL1(TF-D(pQ28rkU=q5VIF#L?EJ{y@66wd8UI_jL zXr%0Su?q8s4W*PrMtWjjDd}~z*`#LWWF#)yHoMywOCIuiVlfXu&6RJjuOnj2<3l=K zWUfktk%WiklkkNr;pt?(?hpE-zThv}Gsm-bTw{dv;BJ&)n)=-|fEZ_pHxgqsM*l176#c z_w-7W6EhDm`a#Viy;Z?;jLfT5#G>}M5mvXn-2W=}*YR!1lJuWvcoeu0xDx(w#eoh? z`M-o~(i}oot?k+w$zRYxxXc#x2XhmfR1^Wuu;C#iz}6PU8>GI&Rvv^y+M-Y7O|qP1 z1wcnQ7=iO2;MG+i7Hp(wJz$qV!%ON*OYC<`^nb^pp`M}J9S+0{p*chgc#Lm(nL0P()?`~) zL59zXIq@pbshBdJ_Lk3!BC2hK7~kTVdAu#3doUlC;lSqIW`P83BgSnkW+e~ZiNS>x zNoKwo1(yy9BJ6<5(vG24sydvRYG<`B0i-JO4yg&YwwCJ*Qsd?n)-6cNH`U8$mAYbO zIfgMR;rFbAfO3Uf4#Pp&WN{W z%>K6{DcfU=+lZus-4NXM$%`pC_#>gJQLKk2P>O%HGeP_)q%VoZuWZ+U3nzK0%O$)Edl z9**LNY8D}E?b z@Q1d-Nn24I^z{GI6i-fkLp+@6Kb0+b^sp$TQ6TzDzbnV?-%BtUfi5S|M^c_ipbQKR z1+WChA|t3haJ9I%r^V=ikK2d!A>x&ci*^B?D*AqRYp5wbs-dorb|eRJsDniV{A`hW+rd_y&-AWE45^Mbx7!Ki#zXEKnRcMVTWz)z z$dsq}2Xkf+z*q(U=#T>gfWeq|EK*phY1P+}I|O+zu#AUs-82K^4OTeUGT5h-g_&X> z-=+sZ&I~CS!}JsqV#D`y&Y<(>eAdgx>gwupqF9_M786+4u|VL?$B_#y=5xB7n!_cE zFyCvw0LoOtq8*D|4Y(e3I39E%qlmS0+nt}g^UlxNONo8B3O1#J_W%jR0dL@qsYJ|( zB)ws$oe3y4pA8Ac{Vq@3S4xIsVM_&nNqiKptpFYzP9%0Ho}moD1}q>%+qGhV4a5?z zO35w?NIri|950tY3G*9-+xlP=9k}{E|=rohxdIc;T2cC-u{bTWGXD} zV$BS)u~;)YMlNy*BXh@6Zm+ zZ)-=A87%ZI@p-ruqyiz$C7l1{UvdSMnnp{S&A#@vuX%h*@b(qpf|EaD{}22C@cNr_ z?fGNhU59UcMdnVo+Q|j(r6HzLW9S!HM$V=n0mv^yO%pzRby4L|uZ!jS`iH{2UijPG z{zm4fe|msc0W$DQAW9|(`hN7m0$99c#}H@aBx8dm%LUJX_mPeeYb6gep#wV9f~xwt zi^fbSR!I1~m>sMdwO6Elb;rpR_aB3+!!nBg?$-{z;lgF?cUcS#N@1%M_ZqZ5yep9QqJ^ox0 z5^)mHZ9lU~sI7R7&3O(rF_9az(`1PuL|E8D3*URC&QTZnD|`&?Y?7kX5Ic8%W!rL^8jiJ6jY?r zX*9dfw4V{(Ht`VXD~qaJ1Hn#VbQf?8%8N)Scbz1=K~Y}dB3!^a1cDFjm|oddnF)`< zxNC5(8VGJ^ElKvREf8#@wHBm$w;-MkJEOtzh$rp=^~J(+I)n{S7+u`v4!ENZxAPuh z%y{8iwY5^-Q0Ji&0DAbGczZHfPd{)6Eadx9X?gtoc+yPxvbw{oL-nz1`A{tP#XBM~ zU&7_l-r&{^l!5SEE_P}UKXyfE;kei1_g+qwJy&0clG=F8ku{O0N)wX?0t`Cj3mLU> zKrnBEj84Q>YGFue4lxDZN+nN1{-m23-SHw&f{wc~jxZ{v2VgJzbq6ZV<{IH}BX^bK zzUOUz1O~iq5BEPEN6|XRbeuSeF7S!L=|{>@0XS zx96z^4c+@5XW8;`*bEF{^X#Z7B_Bhw6 zr0>utXwf3}nRK-=*rB-zk|X09zyM0(jrkcZokqE!^1{N2dGO+J$Ub*sVd1~0pi7p^ zUsW%c`paVNqxP_8ZowV4?-66`)vV8#B{qF#9EMJBX$HHWoM@EGjS02=o#OAfHG4R0 zce_8VgkoZQnEV>b9aSEEA#O-1#iG*GBQeu83F>Vuz;Q<_CzdX8EHuOV7VlUPn(VX^L~u`+_;%)m)(KI<7TDJNbz#5IJt0^+UD8GGEOw|!Eme?jhT_?x=p*# zSVGuFMJb&$ZmdH%q`84Txyalsq`uHH<((A)1W+3-sIf268mPpoS81D-jx>-Qfye~V zV2KV#15>d1ln;C!mVsUy@4&VGFKOvmx1oRsYSA$Y&4hI+lFFStP+o=AA%hrT$=q~l zENNTojI7?xSyf>MOX!&zJQ6ukBj^k0svTrnLrm}exBqr;VP)lv#f_nwDE|EP-um7= zvXtP!>+1XZTl?y-V++alF{hMB!LbQ|gT`nstJIKCP3re>38J(jcAGVwbVxA*7qD0pLI)3q7A_x}Jrm|UTUAia~XQc(kN37#Yn37{Y(yBM0z=b+eOiWviq zcqn;_vD=OvS#-IYE=0E!{d14ZY0g|0Z<;RG;*nz?R&oBKr=tGNI^*={b61!n;8|1i z>SQDA3LXoEj=6j`)L)a=n@?pr?I>j^ z_rG3g5AU%o>9)Lwuv9A$?Q#XOB2BJHdCWD*bg5XjuY3;}@@{bxjIB~ie-Hctei?8w zfDV;cNILyAJ)y&CKq(q12&E0+hP5&{n57lef}p5NKmmI^!eK90-dZW!;idN)$Xw{v zVqOhMsOdts?nEWlY+*VQ%4y!1=5_pJBJVH)!tFj#ot&&5aJxkSR{lhG&S?(@3rSbl z8%{)n!Ds?Iu4Ew?v^$Z0js0Rpx3%Q_dJL_ems%YK)J2Jeq``aSjpPf!@q+C#xf4VS zQd^fs=Q8M+oQQ@KXGwhllak%Abc-*Tq8!Z`)wEvH4tf0DN(Qc{gPuUFX87YFC zcroUm_s7CT6pNQxU4v0?A{)9fHkYg+Qv^RN%JXhMy(dDN&-sg)iV=gwNLR0aWRId8 zp{Y4^hbA`xcVYvHSZyeH7;xUBy8|vqg0dnu^_{bVZm1SxplbNpl|WGO|A8}nj#7+L z+LhxQ!oYAA(+NIE%g23)2lBrH4q-y7BrS&1h>mZT%u+vaL0})AA!`SefkE^uE13#T zz(Kgmncx-Qp{HE^Tqj4UWL79o0Fbx=zT`mLK^t2z0yZFullJbZ!YJ6RxysE1LnE`X`XESotfCVg{c2ob{E>93O6iDEdau_ypJ?fs`}qlPjJ}MS=h32Q*E)=p}>}@ zRF9lHQsr)s+CMO4+~@yv0V;6RUrm1rD<6MLc!NKh6Fm&?)bZ~tnAZBIo)`iEh|#lS zF~CPjG^JQTn%RVv5b2(Q1s&|sJF1sEwg)brpPn->9Y1yD)H5gRrGpntM32DqU7lE6 zMi%GKyKu-PtuWOA}oKl#il^TNT>GP2ps!JuAWoZz(KI=e1@(UKdLnUZ=0{#g=U z(&;MoXi_0aw}-?X;_m*>%K!1}MoHXV?Eg;5_{8auQTpboPv7?0k`av>rT%u*7(a7n z+<<}5(k=LmUOXMcF~Eahd)UsO|4s9y^ZA|_%b(x6F@`w*r+G`6r27gJ7CJ z|C0HeI0rjoZ0mep&Lf4V9+ds!I=3kCs~g;$7L8?MRnc8pLDG#Sj{)IK#7q z{r<-FjSZAXZwqs4#QZjDibKwOU_p9#PVi6k<@?Z=4Y+m&x+N#D%CK?>;Z8aE4y`0z zhee!)>_NkbR_4DQX`GSrLvs{K2#WrAc7i%ARt__1aCfmB@XRmyikM!Woi~WN5CnkZbaCxUk%+aYLUFghv3t zn0OgP4E2pAh(t=1aBw1#!p3gXP=B4nkG^F;(-Gl>D}o?v7NgrYb__`WGh-J}C}@nl zz1ctl3?*4JIEzOVOYY7^g+pz~koiFW<1vzZ3` zkAM*{P7#jW#mpOIE^3h8UVF9Og~W{X`1m2<4PY&zwU*79OarA&o{@oy03bwCi<$oK z!%v*(v_aghoYiaXYfu%}+t&Q1v-H;e1c9Ako1K0l?ujnuofr%pF)castKz-VF@o91 zUVz01YAP53cEyWV&1>hc_CIz0YW}Jz-gEW*HS_8hO}shJI0_}FVhq&x`BfBzF6&2B z97jXjJjd_-x2xvrxvTuvxz#_$zj;-CSFVMtSQS7@S6Ka~G_o4Sy?0IA-tPYyYKQj_ zKfC$7{#Ly$18Jw)_`0pU-gz#>KIEY$k@-T}Udi)nmTU{T&kk7Qo8Wg==7?Z#;H?==^@S zV|H4I=~;(+zg*YKc^$`^ETa{iCA5%A3m)YkC{Y!}B`~mLX%X4Dnyqcdn@0sk$r;fx z9M5I!c6~;7x^2Cg_v^?~u3VhI;D|il-~6GB!|ULuSKdGKev4NT>{bQ^pl%M+tb9m5 z=-{7N9t_FOKOq9NKky%9WuR|KJ=@JDcirtKX%}K>LP*$}&N$ zEc9r_+{bBlAJG<>FP;mCI1ka@qy`H2_p?JNC$NjilfI6Xpf4|PDi1gE8OvBFRRA6z z<3~lGZ(?1u_<>4LKaF*L7)6LKjopJeG!R_ugPoycez?=3;J}ZEM}|K8+TdGKi{N>~ zBLn*|%XC0<-d#}nuhqdPcD-1q?EZqOq#@8OsebQ%SyKnCmtAMW*ps>523VMpp(3;q7CumRN5SR@TwZgZ&%OC*LKS%N{l_$O9H zD%@WSr_*81Lt;m+2RslcJMu)-V@f32oDbk>82xR`MHgg9LP(pObX;DTi7kU#?&|V# zXA}QGLv}&I2(fR&q0Er8Ar0a8A!%T>;@cr+58vM0Bw$s3L!CUJH`ck*25j9z$H|zi z0(C~zrPaCXpiT0+gdrn*K!Zeute)zeb@d&^m({$oo&i%8%LFpd@Js8X?KXFw$7=uZ zKI)ru0{4+$LBmnIkI#W;bq@LeVE)!{5Km0m7BLMLXNe7ljeW?GL)r=iH=!eRU;kTY zd@xCEsV$F)GxUex7!K*aGi}l1wl3dq)UCOq?2&QMNr3NZG>5#f0}t5+1;FBg(--z9 zARVNM0Pm!N2C--xD6CgOhb$7>;dTb2n!oOK6m?ENnY14p@g|G&bk%Vz6; zl{?6s(7Z=D9R2UygGz=DAjW^m?r_5yjk8bmZ`kb!sIu99@5UI8x_R*E7Z9e1s)xs| zS7BVX*`4;~D+pU8d6Xm)bGZkGDbZ~$cz2tS!xKgm@uo^5SD+l?a9|yjr~z}Xy6?8z z_F)R>J9QRY`Sa%oe;d=MqqFhXz3X-H+34xN+^MbD|C_-XI2HFFkV2}qbaD@oV6>E} z)GIrl&{gyFU1v<#$G&tfm3y(+L=w#QQn9$SF>sBV$>aC!V7hSm5q8Ari(_L@btH~( z#Fvfd#5yERf$#;p4-7~nM@VJ{^K8hwcMOpFTsE#nbW9TDBuQfC7_lPePS_Pm;8-f| zie=TD)O6`V|0^t=*@R5r0f8#);fcj625@rH)#e!c+@W zX7G_2=fG;QHou0kn?b1X5#*^Hi>b$;8H?yhEFG*<+Enoi<9H~}}!Lz1!J=ecit4#Fd1DzUAIHT;2WYp&OME%LCs{}Jv zC8L*IACbG3zm;@{%GuzlRP4zHo{281kVINbp%wKU!1qx36)d={+rfRv2T}PB76)~( z-Rq$k2Legp?j76gkQzWgVXg+)q@aL9nZZ`tqf{Lo%zc;-|44iUg376}70@^2RYP7y zSp48{L1IM)K(?ARFfkt=ES;`a-WIgcYS@A$G{Ja>D#T{=F;BrvF_5(6u#KO=;{{*I zEWStoCc;aZvklin8MZ$U&FwK0&QNeNA%YoC*fYHZkiZWJPciF>6tj-I96y+;$6dww zbh7HtxYMERv{ueWLeZ8pVu(~JDTHS#{spfqztE`rJa%7N6E0t4A@1|U+(&J0Z>|_d zO2pto*i0lG`T0GGSV9y;C}1oVd`2LW5J(9aDds)lVB$me;@qAo-EL3C!hx_2DL70N zPxU;KDjBw9BwNj`ytQC`q*;pu02&Q$tk<$H+t|N%MUr1CCyN=&`RVYGy@VBS{_4`B&HwO6Oc^69<*nlcw)A_xw5r_x-;wWiT0j+63Xi) zf;uqK*i_7Ci~mhZMPDfdT&Kz~%^p$~R6YYF0l7piBR-5iF=g&FG0C9#s?~YOrqqN3 zHl;A+7;v~O9UCTdQl1)p^LLU3n)T&n>U2`Jht9t#_r>aB`Q~q^ulLpIh|W?MP~TAd z90ER^_#DOoBLWi~I0KLZANffBbHA1U@Q3rCSxi7ohC`|Wz-FlXGN|iF{CttA@^)kp65)pxB)o#@wDZ7Cds%NL6 z<9j{*AZ+p#`(P&j{N=*pt9L~O=j5pe?cARTZVS+$q%{C>k)CXrUcQQjl?*PH z=jYF6(vZJ#o5qH5m^20#8`9 zn>h-C3g@q2p$+5%#quU*NF0x%D2ad1XTIY1Kju%EtD+b9t3Wxh=hyt@z@w<3C(R1V z9K< zhldXV`4VY0cJ5Md9+9nh;8LQ3`yc4|WJ|=$qEJ3Eu5Ld+Ihnv2zQnw0FXxDo>vwn> zX#QV)Ghycl>6hbM4+{bM05;trHkkgY#9xb}5% zRnE0Iu04=G?XdkrDufsgKi-&Sr@-es3!mI@`WD+w(Jo}nYQeRz+}J>Jdmuyr&O7!*>0t&p`#g<1=8Fn8 zveQmwD#p5%9%M>#%;AVKkQ|Z*^W!l$k!tNBx9iP?b5LK-6`n%sq;)07bzM*8&-K3x z8Onby|CEbs7Grb`CTP0fAQdMJ>tZr8LK0-=v{WKxceaKL)@D^IPs>&!)}goe|1~bT z50$auO~jwN85*vxe^&M{XThLGr2l1%`=Y%|3$df-Jl5#5IKZ`g`J8%-0C%^{yFPu(zCAYtAMf_0Bvs2cj1p(yuGn67tNH%7pC@HIx*RY zm6eaMb1xz(27ZQDxEJT2A`h>4Pl@7dzuJ8j;oy|HA-*GiRuQ0GorkC$tpQ1-u9{EQz5!BGzS|M`3Iaxv-;ymvSa$x;{@!D+~7yfV^x z!ZoTJOzUrme};uVfn`ISv=kech&9xa zb5sIZrA-Kw38GA^_PgWtR(2s*YWiF2^TFEw{`$U5{5^{Ek=l-~WcJ@BQ`n`9MvS7_Cs349TLO>^2e^b~{@xBXmc7CaTytKf@|(z=sMC zDE4^v@H>M~n;YcVO&>l{Y-hIg2<$e z70W^b37G;PHk!e2Z3$MG+7cuOT3cXjzEV+9xw}L2+skxYz<;5wK*go^!QtkJbOE=ZJx=AfM;&zv@z##;N3Iu z^Y}ftKl?}v<%aRG!!u{xK0D_LOiZG7CWJAy7Abl%qy6`~mz-9dUYL%rc+W4&z~xuH zFV7f=A{)r>8-SVyp{p_wAmDw5Doz#vebE3e1l*Ni7bFTT>u@#TNNuUfl?#+G5M<_c z#Hr?sUehz77sE*-@~9Ec&uT?SIjx(V@~fu#t@?qwD-utabUkbotGV24K+jp-4T7;D z-UFft&=HhVxVtfJ<;@{`77Lbf3AQyuugGo1bv?g8Y za-{s~;?2f3l*YQHq$&;Q_a#}Y6U;SG>6Fq4us%Q9d1l^+)r@FW(Lur3QX{r=ZFtt} z8>^k={fE1MD@DMk_Ahr8MYFm$vA1dEeU}xty(Bs8v0Two~1NES~g8P1{M}lSZG;y zX%|X&U!bgKyKi9$l-rxx1@>jT3%iT*etyq$B+DL8lJfrX+R`~kM@Q#8*WdHIet(^9 zg@|Y`X;LR~)mE$WAjgiU5d}HOnZNhqMd^nFjCiL_DsXA1JxN6()r+ze?3V-f$@kii zhSwAQo*KGX-7eo?ky9(;YHAE+R}F=&!8~HyZ38#j5SU)BaHb0l9ut#;$q5z<}87@Gw0FH`QECXvPqx z0QG=G1Y-fwTJD5fWtI^3TR4=hBpTnOBv}WcwFKp77a;967S3I?!DXWkdbU5|=hc?) z;(^T;^`gIM6>$#O>#ZzHgDgXk_%o_DCk8-Q$^`zRqWhc%Z#re7<%ma&!c7`B!jbqJGEH<{TYsQhp>pi2-%eK*n z=SVy57=LO!r(&Lkff#ZbfZ+lHE2Lg=cp}zYWZlKS1JJZ!$cqA~TtXqE1tjB7yUW@8 z=klZ>_{qYEk9n=8OA?f`?g;s$4onc~m1^|I=taRZG>Qf9qDcCfrvert|&pcbbt_!qN_Q z7IWFYm(UvJ8ZJ?Gd)zWQyy~Lpj>H+8pfHQb5oHu&aW(4OJ+^qe*a%j9#kiysG0VQO zb~ZeBOaxxxHEd_Zq201XEUc05X{?>IGAf%J&qo`==5D-%;NmI_r!vxk(kUVxsE49I zY%Uvjc)gX>Ew>qOIAM*C1e3vNW!{*b$^|!<2=+YJy8Yb9aKq!AJyKtAKxS+<32VIE zw<4of43UT5TdbaHj4*Bnk6-kTRMNNH=6J(esyqVvYP52MN9Mt6kr`UsLgweC3UJp6 zy8v_ZQh>K%0LEOtiTHS(Jy!w(Jf;=uKwtNX>zz3HuQ;OnNt(N5obI(ye$*)tAj`rFcNB0o9*hPU1y zy#M|ShIRMdR>SXGUNYt#&Q*tV#o z^W1YEbvlh7e$MmUr#>akAZvgY*R)M~2$RMrI*Mx8p?0v5YHw_1j~~xwS62SI@#K>Y z-p|^fjqR1JI&`Vijm8t|vMiHdXqDVsXJCBY(1!46(!NV&fgu*N(U^$^g+@(`8iYpC z7RbklPT^(y@P&Wx?on7L(Co$GF2M+2tI=IUnhuhaFKl zS#kJ1!&%%^vKXevQOjr`pdyoZ`d=$?{BkrsVVrO2Hf5}DDqaB&SW!Jq1s4hIGjS|~ z!VLPVmW>@Ha7dJi(e7?vy{aa2TSQjHWy1TnI|!Lt?A?-QFkXB7zUZuk;}`0>Cw>Uf zt>XHF5B0eI`V|~)2RZ-xmOVGQm*8qCduGLIgdGh_990Zhd;ahd-D+Jy2g_STSf2L< zv~l`+afcletMT5up}1%2I6%FY=&DAEbyXXqYbFbTVtjh=1V-(u%;Y+kh!gi7_CR<0 zC3z%bo~m<)S&IqU7MdZ`kSNkCLl$k&YDop8C@^6o&@4~2MJ|WznPjO|s?{elv4XcX z8cyRBaJxR?_m@QO{do3_H8M9hGLwsDd@Ya1M_wo2@XhuaC%P&lP_@R7p<73Sk`mhF$--YK@0DS6D7g#aupjES*GCtywdvQy9ifn+Xoa05Gs{ zj}ti(HUoxNcnuTZN&DnJ0N3}sJK&Yy9{hvVfY-HQY-|Acy)v-$;Mn@|P^T00?(BGj zS9q&qO^SL6TUR8uUMV}S%@wIUf8ecU6|AdJUReueZK7C2QmLe-mU5h+EsoGA$qR?2 zhFlmIRfEhk2`=epk=%smI~Q4gF*lh5AU_!L27cmT7D)0b?n~1unIfB{J1v_4fmQ%e zibs*$gtY#>B7Z^RMK01$`^r=iQ!+ZxSI>nACMI-GNFO{!&-Llh21uynaQNmJPwV0b zLhxt5Rw_E_^fXFqmEVkoJ-6YwmD#VW6g= zkq8=Q4;kFb^InoBdglX9Z!E0OxyS8uBvSkcx9=q;-rs=Bad$M}4p#@pVgx~T3dl^f zpaYp5dVw@*MG(V6PgCD__&QulnYG<&WeYh(Vw%=OBuu`s0STJ3rwQG7rPu^(P6I1imN^%+Zo8?3yR;k2t(L`eK_!hpE ztKM_P@l{9om%Tp!cl&%MZ!gEiuR5+EWm*$cqhx(sT&>ks7ZYYMl?ue8i3#h#$6wZ$ z$kl&l`u%mE*X#Q|uP^9p;u|it*Ne48;D=F&0s06f&}p)f*a$03R&A9p!8l?Uk$)!( zT1lF`WbF31_MPQM9Z0F=$xY^2BOEwSTYc*ESUcgU&tO{mc3Ja~ICd&tF|EjmBL#s*^(9kt{e! zunroG-)pi6qB@r!ut6qlGcfdGFD{^7C5nK52E&9%);O>>8Cz|lSK5+DOFa_MgLFr# zs&w-Gb5dnp?;V7Yo+9Vf;Ht4d6Uz(3V*geYr2XHC16^R!Q))xssELTojL@U6y5D3{vECLY;u2D=Lf!|Bz2W4^3gl*?C>(4D!#7B z>-D$b34ZV5;=PaDv(&vjb@HxLlar_JIytp-Z?%4Yg7OGe*Adq)Xn>$Y300?o;>(~E z!aPI2#5||iSS{o;8T+D7AK=9>w`b4XGv57j;*L3!EC!~a4mf9qK^>?E|6V7T{{_7> zwl3oZ*8SS-@p^rF#)Vm7v_788jn_w``7?T9vzIr@C*$*Fxc6L=MS5{}y0@Yi|cp)-s zwDOaad5_oYi9`~)Tq2xIhI7Gl3k2EnS~wTX5xi6zDTI4~7b4dP3bw+Tjvo|ZU^qpz z@gQ{KD8q2qvrN3=IFvPtPGbah1|%B<9qQb@^0C~QF$Lq}8;J&L?vZe8tXVU*_enYk zK9^qF&7=$;PJ|(sKN|IcyqFHB@(6&mnoWkT+9XU^5th&>5C#N%9UzR(CJltPk`x5S z#g~VKnNu*Hf71ZS0wI(5C3y$D{qF)V51pJnd0w6)B<4k!*Qc0BDn|jv&?ab#3N!|q z!lw@dhH~=c{k#hgJn%DT3Xgro5Tq17s#B+b=4|2duh{ouu#2~vP9MLY!Pu9qi{w_8 zsnSN6sI*#mG1*9P10cA6FkfljetQ#z)8-ybTz7XbI-)amQ)oK$#wXv%_9oqCFaIls z+83ya063w2var3CCC?G5633{EFxImUw3Q-K!0eC~O~$zrbD(IApKP3T7hSjhqno_0 zyH4@W+n;0f9vVy~ud?-LF09`8*qU({kOFt*^@pwiPS;U#k|%-#x>4(kg&ojZX*-yd zk;UWT3;Hs%nC&!Y>4CV(nk)Khu{X%x*d@@ZyDO>(qb^ZYWIZ5_RQ=_l%}s1S9ku1L zvLM>RG~~8c-z8_o#ua9%+0kV3>#zdP*ikW{{0%8N3VvBmCAig*? zsA`o)5@3q5@wM)K**K-RC(`}P4Uzh`L;`%socYw_#wt^P#dGp@pYdEa-u-km9XW2y zth`Z6ebI+*o|!QckHO%4v2H|neD0I@I|;M+b;ipx97%AaWcE?vww0;~bNovC!7kC|F~qPu9#-`E7`Ocbg=0J7j~Z`qONX0+GIQnsnpAF zP+7H9k2PV|gibm^bYq^Nk=H^oDU9f$4>X&hBdtuPrFF0!!f*vI8NdCpR^5Gk)h&~| zw`7SRE~c_>vrg2{F z`BG0>>Q8oG9yoqSWhMB31(DSiACKo>&4zgG!Acu0fYE4w{*u;7wH2r|D|ypYsl=*r zunuF?LVF!vw+>ZH3Qi@eSTRtZ5E^yea;N37Gv8-fvoqGcuU6LoAf=p{QST3_;?Zxk zr+B_anR!Eq4FmcqaZ8}_`hB-uS3Z6!9Q=k8C!)>U^7-4E*nE5bB)hTn)k@{odH2mX zyXR$0aL1>a(+(KCA#|5jowUUH?-mztdvZSYeX02;$zi)A?uTgFWDNb^#<#QlNiMn} z&`5>vR-;>@wNw~r*)$cVXB{?WoKa8eYY9*Kcc9(xkbW}F$VWX2M~iCHsiM$NIp z%-mFHY$`Wim|RF^4J&4@&eX>rDHr_yrSY*qC}%uCNZ%xQE#W9$EaQPhp_WQGGDRz0 z%LHT5YSX43ovI8_ zGc`LPBSK2#E!sksQd?7~_CoGTgu6l|+q`vr`p^Jl|L1+}p-?+vAK4oiV`MKs+3t}# zQ7Ve3E`Jy0e(JB*kt+1YfdD9=J_F)YmjdCDm0P_9ueVd*+-<@Bw~SjaJm2X&|FNBI zqF?yE7G_0Y7V0FBq+&g-aHoBgK%zfw@@>~we;%X@-M`WW+k#~htWu>W+oKN3#JJrv zGzts(CC0DNML*ulMcN!fO=_Gb;v1S}t5UKkzp`J+2!R}Bv-S4QcV)X*ANqG)MB(`x#w2r+*V0GeB0d@joPE{^#C)d4JsBDx}`f5rH^)ISTR_5fM8SZf_A{x(nR0uRxA?%UlOKT z)`y_2zyu{k?+a*6~3RZ(708R4!L}@ImQE`uq#< z-8wdJs9CXGCEKr~q#H;QZOQw*aXQ@n_eP+{cZH2y4ZHE~?(cu+IH%^@0w>wXR(G zEKENZhqX$6Z6!ZhvQpzkJo-~sX}C7m-I%Lo#?yDC$2&R|ofD3an$C}KtMH4R67$R6z zJc2;55@SDaP?^@-$+j}XE3tSNn)a-Uj7th{jv5ej%BH2D1@}Bd1bi6lA;VJzgqhgF z!H;A*d&hXbr-fCu;8)A(f9i5k8VHubRQ>`fO$9iDIR(+~GY@H0HG$ z;r7U_56wFL-mw%2Q<>KECpvY3Ws|=C8R$;W*9Yqs#$6V5*sVFqA|>n!%A4lbjz0S6 z(cDKSbGgZnq#r-=o;U%zq zvvfDh;_=ft_D*A{*y$7>0(e35DILSFud6WB354ohw<(uB$Yp9S?kGc(1Fu2+HjG8_ zJ?JgS5C)HUwum0bXg~Sn&J_W67rF7IC?^TQ8hWDGft_WsKvu!}43BG|f)##4-*<$W zpmLee;`&CegO31}zERfM{0LAww-r zJljGxA*D2O=7+6XI5ArW3NXq{H(dyEeuUDs4P{rQxaolv+2f`^`7@wTMtwcua8&Wo6p zD>|@a{3;PiW#N<=g)jo5>VZv0%_N#uTRW_=1UT)&>p^C?csw?ZMs6x=CVnTqI-5ls zoU7(WeL?S3_kR@D{rLLibEgZ&2PQ#L4*qs!Ry4n&3l^PlBqI9Z{N$a5^;`j7m7p`J zmW)BYE{Gl~FLIF7OUA!PR7^|FLBKV-#v|oaDqsbCu>8Mg8i`~ky3|~JW-8zP_@7d*4p|Q8G`|S1y(s{ezNS23cFe%>2A~+QfO1 zaOfg!iIcHJ?|~DcKbCB&kKGVq1V+%?y~4JDgscyZjow}$G59m#nOPzM3LtnuWDyzfCj;igFbezr!-me+}j^E&kHXa2;43> zU^@zq%;>~ZsrcYn)BI<5n+!VUmRJGpd9b5+F-90OpNy6;^;oU9yyd=! zAHGj*AAY#dfAvrD)h7qe+x3$uV9{ly8F53B+c%0p2>0C=fW-Q71FVJ8fui8U3Air$ zyeJr2o$&?93nE#5;EPNYs_9rOnr;y#Ile2p-ZX(2F13bUF?Q5*MEflCRb19EWEx6e zpbfp!mVH|p>JgP9S^?pjqA)PvBYN-tO87YjFRbT#uOy;bYtqV+!g5D3Y5RhnR^*z= z+}DfIpx@(mlh`NPYu8^eew5lvyod)V$R+Qu&=yMLd&G5^Mq|L3tEQOT1G zM`f#08ClN%Z)0df>PP?ds{pETCH|2r5(IIIUp>d7}>FjWC$j*5?=M4gXP0_G@{klEm= z8dHV`2ygmEiL;B)CW)krHxLb*BIjB-6c|Lr#Jc~L=&2v`XFvGdwGd|J(8@C1nbpXKUyXid`*`8rTW`Hr z-p?+dII+yTPy57XZk#60+dS!l{b zqM2c-H8EeQ1@Nj_4KH`56U{=URddxxj{juRRrjn+B-Lqid30gok)qLx$VH|_Xw~?U zUoTWD^Y)4SBSl(AJ^LkNlO;!i)x>fAaYEA>t|(fzuB@+LYT=Z6*J)#m?7o+;Y#%#w z$tI^eimi%4Pt7B`Yx>+9XC7a8WQ zR=V0U2-3tiP0^%&o@{Ur!?itXAD##x~Rg}{VU_7EIRN7n~ zBaE@AoW*inVs9`KM94v9Rc~*z*>2YvE*D#^?$uU{K#vyEt|Idi`MZ%Ww2>y@dKm)I1UVtYDTXFB%OxR_FkV z9zNl8bfvbn^%C(;{FysDSAp$R`rkdZqrS)f-|zjd_ZzLI{!JzJ3u%;arQ;}{K31i5u@bmBZ-6sp#W&&>STUF-zww}!I=efkPSwoK z@N@`7u84WQF20KuC?o%3z7eCOa4iIdNLEL2apx;W zB@5BA%I*l;#8<|@m?~Nm!-gw1dgNrQUTg2vA7}+eLLPs*ld%T?S_CA!>&=le2 zObRE=wdj47>mAYx#hT8Vo0)adA`Y@KxT%f;M6EVf{@ zGv#eGCQ4_+H2XKr zE{_`%FCLHY-637G%Pzn7DVGN^m7$1cl3Ul@tUZ-K=bK6u>pS~z>YrRF-}a)Jsksi` zU8_)DGQJK?iL%%=gyN1mkbz-@<{XgxMeD%l%7M>ccN2W!m~*->c=Uni!Zl}%irYEw zaLjX2@4(n{wcYMFs8`$dk{q>N`qUHlY4xSh9j#^(m8*DZ4b&s}WcVwoFtAz*w|C@}eiOk15vxV}J zg)=>53{gA$IiYmVDCIQduVPxvFa`csFkm?}?-8#m>_D>R*~P%VLQL$~cx?65xYu2p z)(`xS*CQF`%Co8@FTo!CWxjUn$PK5)V>gUhrKj{myPenNrXrq^6(cUpgP;`2 z5yPC_sKHE|s1_U^x2cT0T*@ULmH*fa~ar>4;TEZ(OgWMx2gd zx;TF_6EH#}BZTb`iBd}BvPnlWwo-|N(njj0r#vyw)RCAowLE|0v0NBz)R_mT^Y=VB z<8nshk!UFCbB;NTK)?NzsP07li=sU)XbZwRKm(+>qWQ(Zr+7IbQTP&yKe@E8EKm?v zmd0-9PrRj6wiNKENgU@L34606=@|L{d`WM}aQXf=_J1CXnU?LksRNbt+BlCx;=mVE59Ocpt~&bL?7ujQHMK;r?a4V*BD8{ z2Fh5H2_;jW=c=(3?|&2>x!5Jd1|hP5O6Z<6PYcaYGDS{C0 zS1h&GMu^EVX&Kws7VU$FRUuh}O5CzAo;z5)Scoc*SdlzmQ0wPhW$oV z+a7cZSw&1!JfS!S^#wIXT1UAh$d^6w__MTy9rRo&SD9^!KS^k=-9(MibJi7mpRpcw zmnyAw$(u8=San}4zJw9w+|i@=Z*Fe6tBWMiQs0)`(Tl~4^2NEMnStl# z5rL?If0QPS3>DURw9WR)fZPBFO8uDG#yYp!ckj3BXTC|yKDY(&_5M=n=Mw$O_dHwk zx6+;=Ozk-&0NPY3z!f_#j!Q6=qQHX<=b@qtFgCBSDhXgs?#M56Setfg8=YNDhMVwL zS4lI%uDh$e)}=}9`h5*rD}pt>7Kfu#nrg-L3;p7@;!-UR5Nvh*c5AH|GL<8lG&Yh+ z4pPw;n4ud<6=e)XtJgA7x(zB3&4@#Z4#d;yza41%o}0&zp%gZKS1%>oGQ4Ge5Br6r)+Z{oAJHa~k5Gl9PJ|_$<`RSn zjs(t$?Wlocx5P`HkffZ#Ov0ofm5X#*)PadF@N5AH5@z@9mSI>HASz%DsYJ5?p7i@2z zp(_|2Iftj*p8wCb%qdxO#bo?GQHF9aTUp1NES;_ixQwwL)T{zxFg8V;+emr?Tc|yu z*s@E~G&B&}GWuVXK0=g5|D;YZtQF7IdzRujUfa{K=816k3J=}9uwGlg-jlz1LF8Pa zqrGRhBsu(Rtt<2s!RI=T$*)kRw;$%8e4WOrLv`^{PK3or+3z3pQ5HV6SMG16&6v0l zqgN>3E4EqV!Uik6OF9i6M^<`q&XUZZL#Qr<$mw@O#K6Hb74cu9yV`Zqu#iX*cW`l4 z?}GZc)84$g(Q0jMnox^cl0!b29fEo^FD^QWxX`*o)3$4ynQbCFn1NkMk;g@pyf(YK zUrD2CqpCxD{-yC%g$1342@yWH{T>IqiU55MhM*E3h`?c+7{^$SX0?O389>ue| zkZVTnGM-l7Ge2zISl zdZEgIKnd;EZ{5cfL{!IB;{3R~%r6x_CcL#0s*E+)5Oyd_V$Hyz^|esOS(BC_+aHENKfIJj1I7?r#ZS+Cl1UX+H+ zLE2amgW28`ul-FNMmB4kl3A0Fm;vNt?;g){kEBFt#+7=r z@2cXdBF8Cvi*zRLF7^7mP8Uw=v=!}P5$-pYZEw@q>}+g&JKyQAH^_P*ISQbd;_e~* zj^vn%^yMQQR2UOIwh@m{Z6PajR(QI_ICY^1)ms#+Bwkm^<(ijY%2r4y)s|4a4qa}-tst5dCuTEqrM<+AU-BOH^u#rOHUjEO&fwx?KKxDw9c(Vd(P%0*pW58~uBl+Y7z-96 zR__iZS5z-zEF@+TqqPT6sB|>$yA}yvO(VvwzxJuA1$QQg(yy$D`R&06x}AfxLJP! zS^yWvQlM3u#I>=+OP-R&hJxg0aVbm8UDJa*P?6kf<8YQ3=^KVlk;U>X zl;<$1x(W$_&`emO?JF-XH{G5DimPVXZISuA42ePWzsR9yfiEFNeB)W>+KK8RvUech zxxo`~z9CWZyMJiP?W>HrW}VJi*Y7|H9FF^(&Qnh37}&pZ)gzN`f91JE#pk|ONdJnF z;m>G{1yh!l3f>cm6pP^_ky1EPjI@eHwjau5vzZ3iBjs|y!Y4?0#lHrf^v9Gj9S%Yg znp1WrqOA{vEaC)KZK|y19y~ZLK#ePIuTPuJj25~SX0@h!WK(3VP8={js$D9=iXJA(u|ptOf@(2a6SSECkfJCl;5;kFOq}=zuJ~uwpRuP z>8b0>a`mhz z#e4TvjxNgDbI6^Y*SkB)^+WG3?%{)Fm-aw@vs1J&wGXt2dH`BUXgd2;IQs9ZDL}?Iu2w44~puQuU@zeI|Un-rK zB|a99cYhCu3sN+rdV8x@-$!*`0ZB@UGJmR&TDxTphT+V{nNh`0MCZt&fWWq=2ej4r z9mx!Ji^_k=nlDw*?IZTMG}eb>B54tpLQo9;A0Fn-0E~b|Bn?I`tne7Wu$MLw(uKqd z@h(>jpa!>E3-4TDJ6ck5duep*n3c_1@0884)knt*n?Og!(wl|xM@5UA_juk}uT?w= ze<&T|+7DrI>W_P%dS@7uvJZ;F0etMK*Fh2m$6)krc~OeTL+?+gZE zo6+BvNo60jxatMDrkMPo-btDCI(&s4w%?}mFKxm*Veu7l3TJ-#)BwU#{|iRD{7b}{ zWUr_j4wokoNoL0j>5vuo#}bkZ(%I;rE)}A=s5cbICn8>t)985IHu6w#BoTG{6QQJk zqz6V6_9a6uZ@?S%hX!oZVm}hCt*w(9a210Q!8T?s3Skz<=4@rFvsL*x0SyBCxrNWs z=0pbb&PHb95-MEGQrmrALVV~lj83zp?2SrifyOIuxO#NU*nJsxXF{@n6NIRAT|~`w z>cX{Mm3G}Rwc5g_FPES%+CDpEXumJDMZaNgn3zg5>W|*{Xwn|)kZ8pE|H`7?{{@;W zZa`nT6#pVRTX7>Tph?4yT9JugbyD_0^GSb^?MGq)lI9Snc*HwQjSgcqy>JV$KA3TA zchaf|XTe}o@5a*e<8g(a5g(ubYWmg%lJH_X!knc?UQO3sZ#UxOa~VW71hvfEIB|bN zqL+O6s`AI%vsp`siUM4&cwoHHxw|YZa}7donx>~h3=Rw#JXV8Yk0JdRe|q!I6Wy=K z_UO;Q(^&lZcfSAP#mL2r@7mnlyz_z6tJ!}${=IW=URV1U9=iR+IPWhW|MsN~&lP1|Rl5}~>Crtkbt4xTzw+ot?`JZBn@ zfT3p3hfwj`=!TdF5(DcttprL50YR%zSB%JLEfqO2HhNECY(6#iOe``x_Rhz~CnpNO z5ikC;=}gK>*FTd>-d`eTMj`c+(oTB*eVQ@OYD)?6M_%0Ny!H9#-)d}bKmWX44juB5 zV2T~UW?_NE&jYp&&I7CRFVj6$`d1FY`My}Cq+OLZ-Xzrs3j0Ul*?+-Ll zMVBx=sh=v0s-HdQ2I_J`iv>Wjsh|g8LGb!a3P#G-p{3qY?KFrZK>PLkL)8PqBJrke zs?o7)ai9)O`!T(_$0(MO)#^vZP;R5n^U(wE?;+Yl^CbgyU|xt&<2-QFCUr12btU$0 zqcqE^5(j%}uRlJm`$N1+CH$hLDq$WnuBL3RO`1&V;9^7*BEWh*F`}&Hf@`KKbO8kZxiW$Orn>Vjv~_E!Q>Y9E)PnKWRFF- z6CbN48U@Stm1$^QmtY}@IAV(qaO1Y`i1_oU@79c62y^C9uQwk2P|*8G#O-yROya_t zNa9g}EoEUGYHh~Nn5iJX%L;*08+E?TIX4{ky(t(oeD_A(<3>$+vu5H)E0v@1jPhxf z{2ST1m^WNcBZcq+THFfVGzIyWp~n-Hc*d)>6#znFtUlx! zXgLJK_sQ=BcTKk5;n<55a8)H0Wyp_ec)8%$J66v7B#cx$zrT*8e*nJr{&X}1AJb8R>mwT)pb-IjR ztQGHbbAX6ml7U^Eo>hx9kOvGIl3%IwWqP~^?jOfBmOL_;xuNLS;}jbAf9 zCN|TGhtU>tpg2~#FLbI3&4ytF8maM2wVDV9CmRhSy=Ru^a=E$X>2N5~XiNr!e>O3} zL6s2jkZEP-a{nnem$ghjg{lqQ#r1PuGM;2r@e6kctZS6VQ2D3ZCye&w+?p{{HMTzY zx$cI?@k_t#Pzo2Vb-6+!0trCWKuRaLm0p;2KxZF(h3P`jFKm-3p#&;DJjbF0CbmqX z*?N9Z4daU*pU>0%hR1)e9Ng>o)EA1Q^J4@~FRQ=qH`hFVzh~`Njd%M!-Jey*e$T(~ z_&NQVdw$^j`5!pnXq?lpa}D)PYbZ#vI^rp;WDCzedwAYd>A6 zjCTKaVzgphm_2v?+-$woY7{046TEI>5mxK4CRZ;q#5S??vM^WhJvISLmlYRdb`$s; zYL63~fL`YfXoI2*oKq|xxxv%v_5`@3B&AJ`jC<=@Ts}WoN3%3GiI?Q?KbHmh>2!Ky zB0?yM-W`=#E zjy?O#YDqy=&7PSfA4nVUy*gT>T50tR=I&aDyj6q&3B{H*28oWIy{aTf@rqp?YEfh4 zMxn)U9->SWF+)!m4?+hs2*?p;7oD!G4FDeZm=TG?k-`}}o&O^cjRu|xMBfn!`=S9) zAdvD0NBom6Z#04V^TBAKyaC3#P{!{NcU6ibOk^a`{f2mMo$$M(LAT$X$}X(7quvpR z!ygYs0MC?I-B`ffG%360UiZrW4=?w(RNil`s5CFjpWVh9U-ci-vc~`Un%mQ8zs6RS zVqM#YGIReyCHz+Ud~;{#rPo}_|DVdZgJbh+E~BPFG8Uze?;N_TPcOf<8HBb3GxGJE zBwza=_{d>SldpAPT;GY(9xuHBd>BZ{mIM1EiU@_xNz{hG^7i~-6h*L=tJe*_FDRWU zd6Etfyx)OL*ISw%>clNk?43nU*OV{7q}0v zp66YjMDLEr%qO0>Drb2@Z$9kMk2)e!5}1fKsIe#sT@-CImkWKl@ROgISi@rx=NvZwF6#GkRDw&J_Krvton2^=H+rCzsXy_5)8 z5&I-wrytRG0`|p{L1M=g8p|qN=k!S(;TL>FMGfXuWZ+Eqzgaq7=k%H#@0ZW4NyMN; z5>7JW{XXiYHD_PodHBwWF3E->M6bAaZ0wND3TW%_uDxf}d=ucowQ0|H&-@y>u-59H zf6*(u^s#`f>aq{qrNZ4k$k{T)t15#1cY3$02mO!w^2PAymUXE5Z@*pN^zM&$zZuT^ z9`y%3-#w{#!5$qIPy|z;fewNq2wWfl(rQ4!YBT^&Qo5IpQXG-@t=qxE%}m*^+^e^D zcjTp|J_dSck*Nm_li^)-z&(|g)ge@j@l|LYI$6Ly}c1X!lJ+z07YuYn+kfR zvc*;;W)j|t0GyBm4@c3KE8RKLR`&`L#o5`?=xB-ELieAb%NfmtL{}~_4XDZ&I1IEF zBtK~&01sGJah1`Dn=At*`N?!t6y%~Vw?s{@>o4O@cxPs1v?TCl^l+D1EUD`{8lsGA z^?29U4%t_!3p%P^eQ$7;AoQR|xRwaY=0VT!AB6ck=p7!$lNY@K<>8^9H@+J>sxtr` z#oOtOaOB$7xLjS9Ih~XQM>t4^j0r(}aLGAwsr1Mx<%fx99wPg!culH3=RM+YDSN_v zMRx&T`QsMy#rfH2xg4GC9~s_QEE%+x%gGP)4$k_6$yg;>UOsE4Qnf^)rnbM;JG-lS z)E~0;-$>o^<~TpI`1$4D!Jh@Vb%jUln7uo3zjyS`N)zmJ8!wEg<(cJRT(3Bx*AsV8|QST~rTizC0U!e5W-q`JK)Bw8W zpTCZ5+Pi8?XA|lo)3pW!?Pk5*vdbnkcSLXpDoq9tPe2#WBy1Sp{$}pgy#MOOOYMLB z3*Fz98+_syeV^Fu>`2$LF7&{|umoHS9Cj#R*kM>hs!|Rehk*8y>8v9YaItxf zPjFRTD?&C_T-E-O{nVRdXIECwXsoicD>JKsrBrGuusUNO1##*bq9vqqvMz*J83feu z*w9VzgeaVZW5GdMg6qX|s-H)}!hb|r)T_M%*J4j}R`I6GeS4biW79YS?17fMX&?x&Rza+_|v{f#Ee9q@`nxf0-34y-CyT|i0_xU;w^GTIDDGJWH|gC`jgM-g#CAQ z)D>ssd@}q!q-bIHe*NiI{bN73d1IIdnBkk`E`DF+d-y2Nq1vwgTJKgdC`Tk}9TO4u zwnfAWQ3mwu!v~dA0S9LBzsIFd+vV|}6B_MDIu% z>h9L8@!0&Z1=fd1_^86zS#Zl z1K*-)d~$K@d?2<`UMS~@aZeKJF2V4Qk=eXX0rj2X)iAu<`B-3>OJ+wLsJOYJ&V~7M zLkH5G;~F)G*ckAda3r`?Vq#r{7uM;f$Q*^_FM#Pvv%&fgANCEd9i>;+xSsV!6%)7? z?RJYg0c{4U%BqWN4wO<_d82zwa0#g!<4;`t@$m{CfAH9`2ah-J&yQKB-*{%0tRD3{ z=G-f1&mD8Gyy?jie_(`-f24e*yc&qE#BBS=(oA*&kU^YoCr{SSo?X6s@t+(1kq1Ts z0XBY6RmR5B`Dnm21DH&at8CtJ1b(6*D<(byNk#k6M5uM3A+d)E3wN4j4hcR6cT+rv zY5M29DKnCcbj*~OUFG~)N9^>EosK!qp5LF|dE1YNr9Tq!hg>68I2>pj)8^!OATT~@ zPXCDQN^I{mt?5NR!Dk*=>4XcwhK%2yrZ=90E8b`(b0X7fvC;d3tKY8-d?(iow81cK zkQF#9!Fib2{nt5zh0-{swp-*OAwv zhp7K2Nf0542J(IEK;^}%{##1@Dgcwh%M0qsG{AUdj!_&p_ESUwSyv>0l67SvNqTmI z<%PLKNrs6TCrfga@s{9mKiJmUVx{}1m0BxZGrouQh1?9}GViFP%f!TPkkp-zHRBy1 zUURLHt(@Wt7NT_bKi*uc%7O7iweDr2*11~9ujX~HfOukJJ!jO!86Co3sqx;AKE@s; zu@S;+5g!2|f*pX-ItzgGN!Q={KH1|EBDkZ zjqmIB+x5oz_4`mf24Bl~w;K*Dn^zm`Z?Xr~D~N1p9m)#b8G-QiEZyER2v(IgPr2cT_T+Rs3wcd^)zb~V- zknr(fl7+diCcq*_ASf9d%l~V2wXk|a;Rar-f7v>6%ozH^8}jgx%1{Oji08bP{T|I%o^^Wtc| zmW+Ifl)TA^{CoxEgs^Kk=5_@l6~mPYJKY9J4uj#9`V zc=6)J?ndX1bF3-r{k^AQ!j=MB`p=#(t2fgu?Vcv?A{aJ`(v<@R|5I z;q6gh;cF>58^KM{5ECZln(n~R#5#kC3utQD+#+QFMEjaT*Lv~vzWAqDJ-L| za9d?LnFK!(x26fDV`>@~oVU3h$+**w-98>8|As$63c2{W<3cX@y5RS_-M2ZN%@ctb zu}vo;bA{NuA96Y$ayklgkrVz)53i)hPVdChR>B`}`s1-)7`QW6^7xa{sp+w3{9jH@ zPyaLsuILtO^^&jprEJw#+Eyoi!B@>r{pG{0)YzSBK78HyJL5UD6G{4|E-=Z!)hjsx zbv$#-uu7&Sb^#amOAM9REj_&>2SIXp8RXO6x^eQ}4+2U2!*f8K;Y`>jy<+{uV=b2G zx>aiyS{38DVlohFt#rR$uM~|B)c;G>NW{`xb#fuL9y_ri8IudmTCz>_Qg3Y*?=~m% zR3ryfnoZ`Zvae`lIqdR_OHEptewok-#P;0xuGVU1S^4oJ9mG6=n$KNy`xbtA&q*xZ z60kjy7JY7Ch-}u8;7HCJikBB~z}xdMv&pf5q={k^KT}90IVn)CNG6KCBosE;WlCN# z-h=>MRbfJK$*f4c0Fn_#k(V&o2hRydeej%t!e+WQd47^@ZDy+a#_H6}YdEu07qE$X zE}PAD_71Ud^iTJe2MNq}(dn{m!tW;+;`A~GAqj?E5!DVE6XG#wI)=Ja>=X_c|@Q#g*clf5O_vjJbA6C2ejpF^xwR8gCpJDkzjDd0K~VAG07O(7M(ip zC)Q;(eR)W}UEeU0|NV+AX?=AUYxQBuGb#+3K2(MF$L&J%!-c~XY4aO}<_~ByPhadt zLKgV$QUdvrx!JMcTDNT+S8Ec#@SbjT08Uo~c*_zi@>M|;0CdH^6Y2G#RKEGGY7 z)Wb|KnRoXt>~8$)!8`CgqhC(^{0**MjEY6A>WPZ>bLYu|{8YRqy1#25&+Y$>ia0DO zGhDSKlWgxo)3|Kk;J|a@v_Ye!9%GeA-fPV1d!rX6RN(O6G-+>=9jXUKNg-liWe)zD z`e;_|D(z4}5MPzKC}|$Z;-I}!u=0rwv+u7WSva&|nk7@|btDL+Dv``6cZ|6}$o+9q zB%8~PPAu*B<688&sQ(F3Adb&gd=be*-g?^Q%Z1lNLG50;RV-qg`yOX@y1niTNBrx) zND+wDWHEXqfJUWg_pvS`zVWYCLJ5eF@`|cSN+oYe`KUFghZgaZZ)7FTRc6PfoKN_p zk!Lg4mhf>$X8LR+5Qzl*ekorg;#>FQq_XZu-Gus*PWy^+BZ?M{lRd#_cpCnD>;x?a z@;dy6e)lzd##a=RP~5@8bpw{7zP^qL_lb>-qMi4)rN5UX&}bHm5|7zf*UCJ3tTuOC z<=MS3g(?f_F=4k<0Tz{6$lfX@6Iv$gfc>tzdS(&mn>Ik2`iT;z*AdQ!HEC;kd4p2% zT3+s6)!dEI%RE0&!hNM|JW;c?j&^ay{HeiI1XOKL1$1=iM&(DWhS7oY%HnlMu@w%p z*dU}DC{K0C`&DS6blod{ordkwq)+y$Kt-;qk6=JZ+4@!4OvkPYo2EjXW9h~^Ew0_n zmhG0;DWvsQs-sON(*D}rss|Hzow~5hiPifxmpmO^zg}746}F_k^9#U zA9`d;ZogST6h!o3njC0tQhxPEhBWOVqho*5?rYX-N5()A`-AtIVPVf7Q3XiwYDudF zwb5g5?)I%7eSkrt4)pZKQ6Iwy(E^|vB9^9Of{%79eb}IB=wXtAe~*M{D)=~oP8T5T z-i6P~RgHK&VTzn6O4^*J@A5KOCw|MQmy138(A6~{2-xlJqRlXv#jhFbeFbjCGmJE)pmLZ zQcT^?y|QL#MafnwfR%@omtICYP=@sa;8<(C;2TI)ittUg~@L3~y zcGwI(sgAoZ$+2nAp=%3V9Ovuxb$&L!vv=6BN9LXiNVl)z1`jJOt@|1qb+7?ntu>3i z*4t~w9v{~0??c0rX1Kn@iG95+YX?bC3A69a5a?b&B%DR|bo+byzXlg38caaQbXW zzYu$EA`k?kY7sEv!@Fpaz%FtQ!VO*9Nd{>G2Ky-1x^QmtsaNSI8m6rl!2KQ7bFq}1 zZ`vJ1dP$F7O`G*rWgxE5O^5UnF@$p|8hFovNg8} zGvsx9Gxd5=w@|;GbeVQ=hZA+B0D$Y&SQa}ydKwbG-(QUTMN(^4jRlLWcF~uIE?&gW z1xTFuLmRMZomg5JmpXd{z*bvFkSIBcez;=14UT^d`3iBz1<3~iVGV?_Srw)s(OW0L z$j00P7R>u<%Xf%ED^QDiy#?=hmivxm&K4`ycnro0b0;3((;o11@oTd)Gsrc*-#*awJW@@EOPRiN+ z5BY3qYL?vPl-{N4LM;uGptQN$JU5Z4JzFu3jdb#h@nf-+S#saxxlPy)S={Nnby?xX zCj~Dx&w8i*LgAmbpG6h)Z%4P=&vFTTC^EFHEn%d&SsBzRB%a+aS_18rQ@YFbSVVa6@pe>fJ+I{cn=%;R^&vaw(;7&=~Q z&Sy)fO9NlzqQQJ1e0*YgE?Y9p%tR&Y4aCA(a@QtffgdbZ;J*sa@s!6${@3w%*5~%t zA{mg|3J<0e5tkWEK5%0#Sy^0r<`usCCt=eJyAu9nW2RC_#eySb4Du(Y;-(od`clQ3 z*Np(e+@qaDrzY*RICRsiwo&snG{P^AMRPPlN*V#+fIyDAR+@9U;!d_Qk?{>yb)r&? zjY?JhsF7Z&s;{X!wtT!neG*W8f*Gm`=s?1}WdQR}NZMe30TR)UlCUtD3rGDvq31q- zyHb+oPfM9%rK>LwxkrMrRG~7{Ncs~l-K;0}T5%K~K+P)&FlHPokK=k}0!4u6@FcE9 zfmk<|Dw5j{uWkel7zQcQgi=O|8`CoWGn#)_3QFX5g^{mJ|5|1@zM87sy|#ERIJIzc z!5FF@>wXg!0Wqft9H!S#d{sJD+}69nFJ8zEpSXK%-g{$h{^YT0^9(qiuCUdh3bOUD0{HAz;O!KDJ~U*Z+^&XFl$_$OD8v+h1sKXdFRsd zL^_-Zd&3ErxZP7eIjl-qVZI9Cz3b@#a_I3ITf8s zHz#BHP&5+C#j2H9A(09sxtLYGRq?YTn)=_GOJv{hz{VnNuXzWNUj*n_q*P2s*FxEY zye^*l$_>%OuJ3-h56(WiQM+fHfDjJ z05e_z#|M5=K5{M??EX!?eyLX5V!CYFi8j3hNjI-K2H`@bf|f4lJ!JelcocfQGAA4q zu9*;bOucXoz$V$PvjhW^T*S{BG`m~e-r+MJBCYu`mjgqYD@n$(V4?1E`9j7w9JiRm zp5a@4zGGN-hldmIX}8}N3lvPJffr?;$GfD!$i|c#<)HswU%5&VwAj~||Fnzao_ktN z^Y8E1%GN*N6UrihK3C7a0hZF;X&C#R!CK#zoCqlBjm(8AQIYW39Xr&0tl6Q3E%kNZ6fWe`T* zRVZ#;*eDjVx171u>jGslf*-ClQk(tLra zh0Qj{NJxz*hTZPrONp_>LV35{z9659!tG#h(sS$Un0Pa)=a%4>-@x2b16F}8i?LK* zgsh5y1g2FI-vCkvfhZ+dQsk6ZaW*%gH{&a@mk_>VlLVGvWp~A@S{{2WlyW9V5+ezg z%cBXiX(o=w-R4Mg7-rmZMw1~U*sTSJ&7jBY+^j{c@P%5y5efMsyU-DIy0LU2nK;U? z%tSV0bYh|V$1)JXaOV#|c~w_C|t z+vJq2i2eHsAJ~_$<61o=-P2I|5d4p@1Y(o&3@RU>Wm?tPfl3Ny75&!Uym-gev$t$D z^i=$1+X}LIiG&wD&HTnrvdjAF^F1pTC9Sw+YrB+*3?zU}LNSG2;x8j)l78(GPDT^% zJme?@h!ca1Wumo_<+D+3D2Ei*j#kU-o{0vdooLVustg*z$V79y^Hi-+<8`uLsPk$< zEVta#ksudEyH};PU*bnq5-fE1`sCilD#mYbeN=A!@#Uld4G2g)P)z9j8fpNjR zb*NOjrBapd`)pOaZ?)QX+m`L|*)!w0y2o?Cc!psB_e?lF5D1`|Fff}Tkg%UNAuPP! zuwg@sK#~QrxjyM+bL=il0!g~xWV2ajb3tr&Ur55fZ<2lG_xpREDz)79!0a3TNVimy zN~Nl&p5u4_zP}N`|jP8_>}cwdr}JKtUcc#FTsr#H0gj z3(uRwG{7*CS$kR|{j1~(T4 z(({Zx4e?P`pd$*UsoUgHG0cO2mB1wg?x!g)>HiP$NGrCOU!yas5iQ0YGNVY^;JJJbxzDY#SwRjp#*lG$p>$xV#)O z;IGR_B>=cLfaG41@RBhi%a`jq;@9H8sL5VGkfGMv%Q4^Zw~$*94FvwZcsVa#27^<} zat4;oc%*#EYlh;POgvDD z5ptBtLOC8Vm?J$BayX17Bgpb3eSj#8_+OcRA%27{GcDnnt>nN;pnERr_ObR>2I9|g)54;RjeNY6l5?VSG8D7_LV|u)u%&q6!U(Ey&C<}g;D7&`d!c$ zxYXuB*r9R>z$+wRBq^wm?tWGfalmttDXt1bBSbdnXk?4jU>4ChH}F)xB_wbR@Y6egmLxOf5YU2w^6TQaFgZMV2 z9}u=`$LB)?2egp{wd?=Dev>^1O0}Dj=rLFq`XqlcjjY-D1TH^%E;COQknQvr8D3vr z{>?+5EEIu`j*rfh1&7z^J^e+Q=WWZsap*UT#lr3QxZ*sCkU?02fc*@(#`x9us9+T0 zL@GC^6<0e4nX__;aBH91P0gCR^KDyCxJpg!bVY#F=)lv8#UG^W@*Nvt_Wr;pXGe$VmJWyZqU`t;GG)AejPhL5h)@SE(TJlLW^v{fbr zi&XIraFyYjgoy#lE+zzEhbev!<_E~Ko--FDp_fbfvU2yK!b5kjoGw-J50t<@3d@Da zGW%#^_+ws$^l-)dRN2BI%z8`psktwge&*mIe#{}xy~)V_QLKXmW!&TXNXy`tZ_3)d z!C9z5^PodjlFmHJ#8ug&Pn}+Qu>IhJ)|y3E+R*4i8e7i|udXA?9Y&s2%r~J_k^t)l z5(xu@t6Ol83>tfidZ8zb2(V#L&>=$c$-qVr8s*FF%X9@YJircyzcC|;%7g4^%5+dK z3{h-m^^4!WH2gN!^W!{CIuIj-cAs&ta(#8|rANZr=F6p}v0 zyeburq4%mK>g!Slwb<8m#jKk&aWQB9t(Isv!+5eoTC<%9<2n4B_+(nEPG+?K9M>{- zO-oPSFEA_TrC+O)s_6ACIdPbw=&^h`5ifgAa$J zrWp-C{Nv6&^7aq6dh06*w3jKx*oA?(8?hbHQR-uz^N%K!GnlR26c8X5P}pIC9b_>q zC(*~FNCHY&boBq&&f&to$>QO|g}HowuJGvlQ&a*d#SlWBsb(^g*nJ|jukhu07 zF3my(fJLiTv75+}+{yjkV^LJ*KXXe=J6p&g4Anr7JB^0rY`M1v|^jC??nYN)O$ zNpliPZ?c*seJoP+AzVKk_9nf0G4lDHog3Lpk7IN?3CJi%Xhr=wD+OA*bd zlZk!UveivG9Y{XH8TqLJZ30&cPKw*>azP+(~MRLMFjUtk^iKS5*{sQU__ZnP`TXRSh=`z<0M1+F0g4~J(@9@so^a(m)v=zoNc zZnsizNj~LQ?+Bb>^691CMKXn5ygbur;I7@dMD#NRkue_Vz~d`MFzTq` zwOVZs1!O8 zR6r6my}U4zH#u8?%^KghAO*W7bf&5jiYO+7S|akRYU@D0SGROclFdLiszxKoXH$J< zE9jS)HyTR^blDHB2^HbW*<=7pz3B@v>0Z?4sH*@)&y=HKpUPxeVqraKq|?RLUT47Y z&!bVV4|SEalu2kT+)?n_>?JQES*^J#c0ou^tc(A1W6dz^V>iLbU-KT0POBZ*U!_M(H?Y z8ig?w^ach|(o^{;kiUzYgTxSxVsY7o%3x{UiXq5QQ^UESdG^V(W-u34wFwYf$TX}J zibovGMXHf!0Hne1%ZANh!2%KV;jb+St7Si7)OQDqif7iw^KWQl5W zGVAW|pqWC3VCJ}OY5>nKk$Lz|K|`25ZlfC52%W;W&Wp=u++Zw1B|xebE<;_7^N+X) zf!!btjC#UNC*Ujx9#CYg(gu73#j-hn;TveUFq^?{?Obce9*pxBv6gV31KhKWyRHzW zz(v3VkorS6PB$o?;+7%3!SF`NYIYyz#fjG-;2Q`NT(t)~1H!F?;*871!Lp1H&7-mN z!xprAesCJWXGYg?Ps}?FCtnlibQ+H-h!;O>F~Ni6Z0x0!lAqyl4X2Eg_naK11`0^IJ@)j_4Aol!$hsK|rsQrB?plonvT=1TBuwM8MLcRGb|K( z*&VS3%BBQ>%p0!N!ii{P&&O{Iix=1Vuk-PAWuu$J&MAEkq<~Nk_e7l&kRdP*_dx4y zZVq?I-a}&{ER)wjV}!MzP)$g@!W_owZfWm#T&^U}66KxWBAU{+2R)KHVE@Owws?^l zDzytDce5t|5q@wvh$Mcr0d_pBF=_*?eZmFcn6_M=-y1It1Q;|;7&vYfGYvU+EKV8h zjiZhAJMBld#6lS*^MDKvMlQoxdQD{VT)4qyINm?Ibcxe`x_RNf1PR7uL&(g_Xix8D zHDpgCkOPkX*#d3cO+*#xTs$xgrp^daC<4GCdnby9QV>33m0{XiU4IY22VM_koA$GK zQ@}%AU;hSPAj`fUdwz7C_1Av~Z&(yN?{0qpTU<`?2I9Ab4pgUEG0sKir@AlqQ-i$?~F*85ayZt`9+eKUzZ#!@U)IjY@Nx#KSLhx{sArG}j;v9(ghZj=h8Txem%eTDe@9_`dH;@KSxLW5<4dHw8-sbg}yjWO6D@AG_iMvnE0TPLhn>a8wG6FhmJn z{Tq6&o=@A2X?yPE{K5$o@4UqMHEvRJ><1r)N4tcp;O<1Y6{J&?0c>=`3?UCBsxCBT zeEBKa@0DIF!QZ2N$R|gNb1h%#q@sNYrEC9#r2D?CNM7kHDyd1Od+z!#hkx|g4|_FT zVjogug|5Zd@DsQ@bTX6S?K6$U8O;UBSIx_9`WYVY7!hS&cT zYyRV){1L32Jp7>hM2azwaL^ics|)1yAHSSTYj{^8Futq;pu!ho8{Qqt&}V zfNy6GLcrzY2|LYSL$@|?ADB%5Dg)mX<~ZtJk`f7wg#&;!A`G@R%(nlTlJxD9{# z2lmVw#F(wOA?^(a#7r6D?-DmpKF*t*YtvkA@OXinuY^c}n;Im8S)g9!jdL{~fAd(I z3Md|i*}QkkzwX9%4gVtxIDQH0ga7?@ASv^E(vGXw{&D^BJ!;2w&-Op29UAET_oP2w z{58`#F6+I28tqsqp&ddW{2NX~Nv@?7 z^jp$Vg!glkNB3qb$LXm*5b$sNgTY5&1hM~np@eF%g^675HHA#3fYcBoszLv7K!>qa ze-K4X+WljB(6~~e_0;RlLgplnJAM>R`bUh>_l~x1Li(n;@@MQ%Ag}nrDa(kO^3;jz zAwUPhA%I^=*M$g~gqSHEmI@NLB9kQAP84qac%#!?`2=;HR+psU$Rmr?Ejim5L8HX}g9;JcSVYwf-9GWnx$1 z@}rGSU)uK7tC$eHFR9kUfa|&iO4o;7Mu6bMRfw4x;J8Wo{@5hY(MZ${R)@RmsK=McI;B%BRYvSxMze=2ER0O~+B5 zV6-E?=LcWe^Mk$LGdr3N1b44+IJV~pw9aVUh3`7W?QJ9L2EvP9*CnvZ#1e0fD0J5vM+Eq8I1*I2|sz0b{(xUaLF+ej-o@_ zDqD9{0vLQzMf86x69&g(z5dZHoMwdHg~SimUVebSSgdoF;OGUg)IcVV5=vp6l5mj! zTz1nrNLQpdWM(5~r@b~{9v()-%;C;i>!P&*i!4&}Nc~1alWm&3Z_(msU<;%`ZXnTc zFL9Y5(=3u}!hZE;$BeZBI4{@WJ?#Ih+$VnL(iLI5>Wi0MTGGe(QPr3v^gzV$ zCjp|5X^W|g4ktzdUefRN)++_%*z}eg7aKo*_O63Jv~uCd=kCnsKGE+n^DEf-k)wCM zuQ%5BDy76Ba_n`?aSpo(+GL zZm$LPEquEL^=y^Foax*%VV3&%%5?8m)=XjKpt;;sJF^2)`PYToV%7dVrS z{hE|2Q?yP(tz(Vz{y@98IKT6NIq&|*Fe0P>Ug;(N%<=tfbNrJt@95kCP^}iEDHy8= z@s*st6gZeu16;od*U;Wk31x z(^BO?4ItTe&$QZ>Nw0mgXIZ_zb;Poc41ldT|G>f*7UqVZQ`^1z$1AmeQSY_Y2^+`Y zDD&M2xk}*a(kAlvkPQG9$K5z+5${ZKuu0B+xn0Z+e@^63Nimm*n@CdFibql+;`s#a zY~`L)z5ZY%8jS=|?2*$6oL5`}7C>aK5V=9-rpr#f8V{-G4AtJ=?hSV~B5W?2uB0Ii z>DW}#(K(nF2ZMfi$|z>j72taXE9q>}fP_l64nFs&PK7|TZKJPyh-(KjxD&RWB)LJ9 zH-wpZaej6Vk?R()i7@?lpGE;F3)L>qCW3<%VbKsq_Uv&2tuB5|gktq_31r9RwL77+ zvMr5fasfOgfxi<=sSL{i!SXgEg_zLJVJdSLD#6p;*qKTZYm3==a5;uW+G!>n& z^k5c0z-uUDvOS+i^Y#kn7V!hDWAcHKv5d^mB%lF=@yZjiz~Mmb@h3vs6Pd}(XMf|< zgpBrSw)wo0g%8w2?2>Z);p0lO*vPB{BenSc zV@mF}oWhRmJ91>7QcY#++uQYQs`{`7x#p%Uh3@2P!jcoxN zPl>0!*6_E%w6g4jufMmoc=m2K4MuYre249~vcoqXxOcvH!EGzyCda^SFiT0khP|EQ zMvDwJNk*;x*-UkPFErh!@9gBQEM*fB}w zzV3lD5Pu-j_=Bus#nKx<@ykSqo6$@rYPHu8aY~U&*F6w1_*}S-jF%Un-{2#~IaSGV zfi8xU;><3}!*OUirPoDZ2Lxbs>1_+i2Omr>JgF^U$A0?QFV*F+#4?W6CS7$1``Un!0*p;5FkyLRNs{*y=eW~Z`@8olSHe!XrkSEkO* z)WhMrv9)KXVPN+w5Q?@1;92LluTv^Ht3Iuqw{jI_Qknicvvga@oOt*h;}T9;p}oxG!j{^4dB!7UAlT{;-1^Zd0P~;TPor7NNT>c^?k=z#Wif& zJBd?@7~*e2C;JhkFCRlZ<2{IGe9ZGYT#Y)~o&BRVK|M_uu2Od=EkqJcBi*eD$qr$x zG%a}SNsCezdMe!qXeJSV3oBa7kbTkUlElk+?RDa*r;N~z)d1$zFN;sOl-Zd9Jz zi$TSTCNCSDGX(WUnlRoG2mvNNX~ZVgIk+L-?lNKcU&cJelfU1x09kKYeHdT-ZEW`7 zobB^X9hma%vo~!##D^9_NbZ8>l<=NCOD|}=phM4q4(3cGsAFw?hu1bQ zTxdhez-b|t!T&}wS#ZqLPgNBiLl2}hn5r=B2&F>WBZ07E!11l4Wsg)PR4jaZ)*k+G zENw<#dCxsO{zrZFd+b2>;6LoJ2B`g5+|OOv;d^uN_-`XrW0elZ+klRvyN~US0OC9u za@{p{h2KBOl&C?2)gep~T^1|5A){#bd=uqnemvWYZm!4Ee)cbiUjycNJRJ?Th9CL+ zzh}>7hfidokz?pR(ZKL8Fq5d?Lzde52X`J3P>#r+f?NsBziPN1Tgh}w0n}8#s+JoF;LGf|_+AQ^;$C&*_vjE7a=^H1} zi>1;9aK_&Bbborf$J_efxGgV=^#T2c=hIP{Dllt~X`pfA5ShymTT1rNZc|2FFTUG7 zhIx>Kgj^z&g=x2LOGIMGHi|{gpmuEGj0qkL40z~2fQzTvEtH;w2Y&He8Uz`@{6@3h zlj30Z7$D`5Un?-<(U-(SU0Y)kEu02_JB67f0yVLEKo{I7U&v8Zy#@Oyl>xD1y9YVw z$u}Lpj_@GRq1BYpHd6gT%CL=OpA9JBroV%U50zjoiJhrF+aNBs+V5`zH0;3#0VD0aubk z1p%5Ad~;1)Xx^HL4kqgbvdwO7j>^JWy|g{e{>2DsLk2i-81Q zM{l3)DiyiYkt<4lE&2>y1~&z^N6>c= zMvS|Rj;d$#XXq;X7V+|{cz=!MT#}1i|%p`a-`me*M8$gDgkP`O| z+rGHIesQ}8h%G$&f=xm{B5pZ={jb-%*xzhp`L+=fOMBa)SO^a>el#%w;%G|b zsS#s@C?4cy^VFz?MF|eM!#`_ z1T>D)^j8ly&JQ=w|MULJ3LfN89G9VNT8!(9D=Uk5@@sPY&<1#E3c58}I;frv^jq+w z!vaV}3=_$rxFAyTBEHj)WR`BrB&vVr^S#?#2aK9&w})%MSzyO}KFK(*Jr*~;hnD5Y zIT}IxTDyIjGCS}GekkO|Ft^Tt>cA=!ld;+{9n@x*))zA;pPal5V9*}x(bg16zDShu zKznOnqzz7m^P%lzqaixR&qp{}BrOB>ks6IKLz-ytyomgpvEOgm>o&gxgbj{r2pO@G7nCQ#|G8%bLg`xtGG1=$DKM{H*)-bxIfqH2t^2j3+}iH;!T7c1O>Jt z5?mn7_58t-T?+oQm2f=ZGfF@qykt8bm63qc5Bb(hrFCE@hE0D|*=O4qAnm}62A*;K z>+BCPHwluPsu7>ZSfWj2Dh$JF)t~~Jcu%B=P)YDMLGPPfx}n^56nrAXBK9q6AWaB2 zBI30`A0&La2)`B*Zly*Oq|Ic&y+B$Cyk1cYnfx-K4+42J62!icPm3gj{=a$bNd-3? zkdLk!YVe@$eT|oe;@Adf6=mOjAMz_fR(mKOESF&?4I+~<;?u$s(pdlqlMe)tbEE6b zipB%Fgsc^>%qRm!dGfKp@rTZ9-Vfck&!0Gmv&BN##Dk}##C=EAMC@Li5oXtN83~WO z_KQi+F{eK?P+SD^5hK80XiX~7Owsiqd)Q!#L+$TE_eYc%S8bh-_(B{~cYcN6J7*$o z7toQX^5JmOvJAzt6vF}u3+GSWc`6@@jPHzu@~3{+N+vBm5HcenC6Q1<5i=BEr}pg7 zaS+?cq~TO-px9>{H9s4e7U@hT?Kj4D8UA$Up4{=%$8%aptLvG3JD<_(c)#Z(9pcDh zM862W8M7lIHwhXAQvs^NGzbT6QT*2thSt!Mar+m&UQ=uF2*DzN ziN3gUQu7AmURw*sHSdY;7rk+>>AfmK_-W0;XM^>26xW2d3{FCRcq-UR5=0(zjM8ta z+j=kq5H?Hk#xlUoL?O1~yu$IcE-3Rwe9L8->sP@yJ|turmgL3KhzK(F$p?p@``m*M z{`Fr!Sa=(YvL6*6zwp-&(-2y(?GR1}5pi031$l3sTyitW14j8PC zqRibaX5k+$w@4>D)M9vK0tYp=vP3+YTA=U^BUc zNL91FlT55r;n4MByn3RLNFpHB884EZW$+t*4SALj#2_@#vL*?GXEeKK?W zR~b-bUZVrRA)bPa$HNVY z*z<<>Hm9Zzuw=rRodviPJ1}J;TEFe}PtRJ3nc0As=)E`}`6>mpCd>;7v=Ialvc}q$mK}v)J%^hGoK?Dmd2jX~%2M+qv!~d77iqH#!ruzJAUh}+a20<+= zfurX_unGfLHFWN1Fhcc^+oSuT{=#e{Uc+s{XaE;yFeV_o9he(16ds<&gaK}&gEmQK zfrhcY-5=eD=yz!Dyk9Ibo;!(-AQ$dEKnlh>rIBq`6<#N_n9djdXudyZK3Xu_|FCaK zsC=0d*K+ll5o0!W&i#n!_#zA@(2)jq2tgaM9U2B~ z&S?mNK&*n0Rm3%XxCWoUUH5drJ-hV{S2%wAvF*0AC^hgr#Wc9*C*uR?xth#iKXL<*>+e5yKhk4FhLnjLsE zIuSUHsn$B+?+|l^@|r!9gi;d%4!sV1{tzl$`$C#umnCmJ0F=T&D7+1aFaB81)I&II zi+T)yc-eZD6!t~5j27?(kawW!{$wmN|0cpR)hT?X)S(`)Q23r;ZVnC>Vwe zUW*MNJqry`%MZ%M}d{%q8erq2C>5e(I5XN{yUj-Ta^-5uqA zp4+XQZ(p{TY$o;pyO*_frGU@>0w2wKN-?dVFCWJT+`7;?UIY(PAmKN7zOiPM4Z@p* zr2_sdIPM7zi-;`J;weOcry$RQcVmLiGtY~w%v!y)bNn-(IsPUi8BTZ=O$|iKteUEX zv`Q>?tTJ&*VH=+q{vFf)I&b=Pc)dcXO~Q0JBR)SL&9l9QxtCyfdYyI zkltpw5l^Vzcr=-x1=775SIWvQA2X74(>Jp+?UElAKXB&)`GP3shN!xLdL{Xz3&#gp zv|NPa5hx6KCxO=CVC6UJryzPmM&x*ffyAnZmWO4Dxk;RA_yhWSH{(A=q2Cex*bdk&8TJng%42&<8<$98r$M2$E==6$*uf^hI)<^#}lgH>Hmt zqm2y?I6*HKcJ{X+#qdlyq&*?wop0J{hb8W?cXAhshc%#+;Ow|r8jdcw93hF2+5>g~ zE~dc{LJ~F)c!&8;k7t>8xu?sERkPwRsl`|@#`NB8s=QcBRQ)9-@vEr8T|9KCNR_(T zIVl-GWItJ*k|i@%ibcJM^L(v+)cG8Y{wxkgDR0^?ljw)e*y8D*K@1KrE)K{8(pSiZ z$rm}iIlw)@ldap^_QvIF1Nl$oTWWrlt$HW*jkCRJl66vHXggZ@OV$#Um!w8xbXffp3gH?(oFl+?ymP0y#_9SRX66yZj z{^Lvy2yOW2e*2HV_5b?4zVp5JzTZP(FfVW1$87bnAl|tcYz|vQIQ9##-p>}XK z+;JCXhjrKNpklC^4a`0_v(_;SxzG_E2qBt-AOML2QA6008H{3Lz}LG?ZV|x|Tz{g7V9ZfO z7$t$8Pa6mk6n@m{LdScnPx^-Bd+QH8{n`?W89bJ6c#e2W=_%PD+hjKYWA9U4H4semd{x-f zh=`HNCW~K&#T$<{O%Z*q1il7S&#ph83aRuv9Zu#;=wl2uu0)>E zAjigp;sIquICND9eCiO=WYKxB$-1TE_dhoL7B5Gi$eq|akz=cg%0wl>H$U>~L^XlO ztHXLatvmNc9)>6^NJSn?33n#qm#Rexk);SFA-^lk`(;$IgtHHv1boSBvhP1#R~32o z^!<@pZ|L#W!ar*VkR|qb$Q!T3H`=B@z}DCNKJE3tQdtkMwd2RBsM;C}w9ibet%Y>D zEl6AZ-uiCjgcHr|*c73daPa0Wa)EP*W+?1^{Dh`ISr49pzE_8YJ0=&xlEejEVI?6& zgZSD!mIIX%N8bGhf7Trdlorbu&Muz)wA2^UAI3pACVo~+OkC()@J5hOLK5NEkg5Cu zND_I{t?CGxlc1UqI87G|%>5uO?)k*NZY?d=b;Al|<%PQ{Gv)j4S_Kk?+$pBlO`xxW+l(;# zt>|M-l2wHw6vjl#G7*37UIGiKzvS()_ZRo=EAU5gYWSt;#{N^M_JgIFJV=Pgk1PO& zzjfj++WdF-$f@GK$use(#H)VbRf(zinQ!cdnhXcdvG{?*uE-lC#Lg0rx*8XjWD|IT zut+p<*IiRmKNYN z-EEJ+_PC)vNHimk28Ro00=t&OI!v>7tf4_J&qKHHXdKjh!2^pAb^_2bbP_^tFjDB63T^OJ2Yi=vUheRKJ!3H0 zZoIP5o@}?9)2#^e5WUy$QvxT}v~%}KYi+JZ z!k7uR5AkLP-h2b7{Ev8E<#`Qe^(|T>qid)QCK)JPXBZlb7FpzfaRq~MlQCpA?kjs~ zoAJJh=EKd2eQn$X?tpG(*NSZVgBJnpI&Mf-P^I0?Xpk<-NbsK@@ z_uc8e5BUaLuY&hF;!FDinpZ_l2UQOwV~_@!ub{p9Uzr7~1oL z?z-?H!`@1&8+-$hM7Z!t2`SA+6AT;j3`%n&1h~EJRUvS~lmy|EfLAHs0ng1%%^M9H zA)1#V14y4VAHU8>yrt|BD*ld$EKdU#6{_tu@ePAF|F1BX%`&N5nT-2t>+h>5b0*_yv547M4 z7;>>1927gW!&$)dD3ydf3MlE^Il_G}Yh&s=vhZNvM-UA3cfJ{^@BP85%MZSQc{hn{ z>mHWD9L&xz;pLelFXK}1hN8p{1Q4`h8VMAr{Mf0Ic%3982H3>xK{iXCdTQfG6EVba z#S@uEC2eQ@k7bxCr6NBO3%%d+hqOoSRHfdtiWV4XKODy!)<<`tX~AH9p)Q&7tUoWy zKN7J*?@#LH`y}k_MJy|ist#t}vLX<|+%>!ArU1+pxLM?^KnPDBmf$3F&0Pj8Nu-7m z>mZdI;8TLu{R2nn^px2x zAUb#%T%>DGr4isu?GXAF=_OgmtOIJ}j5#4~WAHhNA-p+Z ztJYN>RA4?--~_!`_`te3quV*Z$ckh-_c9^P@1y>?Vryx(9tcpBcOZa3+{^ZQFH=!w zM5g47nw}Eh7dwU5y{^zfv}9cI`I^7_ zt4*IzfzLq{iP&DGZx<1@CnGjOUSH=vYnl(BFR+4NcCUr(Z*eVyuH`z!=}LfUhRzCd zXs(M(tzUM}PM3*>ihuA2#ZXk)y%fL3`g*XiQxI9p;yQ$>f^wTe-iOSAMBfqJ=ea%u zr_rO<$F~qWvnAT>G<|);@sNm$C!&Nr89M}{M7kd0Vg;lqoL=}pA`r($+>P}Lm8>;U zwu_}~t0*a|Z_no?&}lel*mP{UvOL*Hn?aw#3N65nC^zl-xN!1Ne+u23=5H8!Kk2nM zV#_sM_Nr0D9Gsyvona3JxuY^etT&DpR*)3dE)xJ0%9F_pKVK2UQ?JRpNq5b!qy!}6LaBrj3k>I5FLM=+3E6WfH0G0-l*nH>k#sl%1HNDYwSRVj+twhSK$SF1 ziw`D5b+i=i>!|P&Z#BJY8BXfntPzVY)`n}DyO4^X%2~-69NvjsYQE{~nI|I-yT8i5 z0dYr#0~aX+u!cjJLOKilBqUVcs2Z?u^wxXNAjULY?bj$p__u?x*!Ja}%~eGBwA-=Z z@E2$=I~4?W1(`2IA)GzuhTL|mb6>-``-7WK4Or{FXC6N{1s{oa-}0;!7z|TBME>z6 ze+8GihT?}ewD>aa!kbr6h&egINU88lHum2o42J;&_J zTY#DAZPi5J7>=d+$(@`OdW&?XSP$i05FUrEla4@bN9^9%vExOSMou#Fe-Sz&z1F$p z3Lsj%=LvO0zwq9D(lP72O+(1iHiO7)18T&5hmXiv+vJfoeT3I+qBt|;d&;f z^LSr5t>z7O-w(K#5#7q0&AS;e8fZCG7-~Pg(g5&|r)Iy5ai+d<`wchFACCHxE{0|e_zuy>$2Q!{W2*Csjw_D!oZD}hb=#-`PG9!XDh{;G$5^nM--Gy^LGcJOZwY;PjI!a1 zV*Qc)ut-@V2@U)mmU9!SuiRpB@gnXL^=Kze6dTCOzxT}KGm|u(kRr&<=k`@|HJ<(x zXvDIdRrI$%)BZt>kt-q%K&c5R;N^rI0-}eq87T4)sdg_B;P==LLMq#V5~9)jFBRCg z%5(lc&yPV{h!(r5Sp-jg3e zk^*em&@D%5rK@bNuC1O#yz(i&_(Zauo2+2EVl0Kj@)@wpc!1JE_&YFh@Nb$O)Z`*V z$NV-0r=i;cUQ9Urc#o7-`s-o*ufgC#AtM&sxlE`#kXbKu;NPH&3lNZN;CTem-}H!- z>t%%T!}tjo1Dsh+Kva>31s5X48q&VAMZykA`;=-;p$+sLiTwzU6wwFlNlpE$)lY$W zdn;s&vaAun^-9THTp4Zyy9W=fE=T+)+bxno*@pbSS1B={zfTolR-wD0T4g=^Ll;Ut zWLnZ+N2ITbtr%CdnpBk-S5?M^a57v&J%L-1>=)=Vs0fgTp{2Xd)v*lmfo&zq-sfz4 z+FMTKYPB3v!j18)a15#4N7iDyZ6s^mx=r62e960WYYpq`AcC%_4HV*c3)2Klb~KP~ z`WUH9FV!|~om(F>T+meGiUY#w%#!vVyFIOy2wger4+Ii{04ehW%sY|JPC4!9M4Y9) znoNK)B$CjU;k=sH z4s`;F$yU;g&dfyVX(kU_e_+~?ddU>hH^{Z3hNyOQNL83E#iRI(zpEJdIe)KkBzLZq zrK&2C2jqBE^~HnmhDIU@dLo!lpO>Z*@wW((A5+f}<4IlD9oGR7QodRce?uivjXcu<#zm+h$>d>hY%L_TEyrZ={uYf)X|P5ul1 zLM)jlm5sJ-SJ4u@kLX;Gx0oP~XjB|86I?9ZU?73E@unjj)2uoMqn{}ssJH6}$|BR+ zL;%c2J=-VKL_b^Ks`c95qes2%UM)YH%gyHdFq*mZ!Mz^1-FLqpD7izLZhhSzyry>V zJ71gUchL1|Eq;^z341TrbQU9oMs<_03R`v9yQ`q=xM5`9P{WJa4tn z{r-RVJDW21hHJp!_Lg?-`N(B*&YUqQWKQ`8 zN=knM6a`~=HrVpF3g3JedbEJ&(rvNsjKAk^7aEyA`DWo; zMQ8t1rcr2P|4cV_8(*iwwKd-7#N9iH494DESV2-C}Wd)APkCU^K7g{6q5U_B_t%RhB+^VZ*almAyFo^?b%3^E?+^NrD zzQ|a_Wrn8K;RYBA^FeeCa!-uZ>9?P;YW~?-GF&f~k_KeabH0Xk=Iy7G33#N9B=*t) zd|h5;UjZE=*Ui12H{vob@f(REGJNphig2>P<^xLpLU^uGUGaLOnQStHS{$fk;tgc*L}(&tPVC^ZJ7a1*kXtaT zkx(j9$oeA@f3^@wg(6jRAs2|Nu{)0)j2WnXK}G+V>Xj5{ZVFwKBq0x39zbuXXA)jS zwai1=>%iy?*^OeC5MRbII!FV7b^BK)izVhM6({E!pKQ!syLjCr1guigE(M^37hha3 zA`xRjtVQSoXbH^DK1e%h@vM&Zwxa-wsZ6#}6nXClyd$P|H0N958= z$N`BYGqwHYlwauyU)_mVg7qXB8B3`{e%&c2GfchuV7daXxENLVV{@@&bk#bbqIzHC$v|KPF7qi6y| z3tXC-K&W9JO6>A#(O^EpCY12~|`l{%OiEshRQQMRLfJa-Fpu8h1JSAEBD-)XdWSiA z7=z6awn6Lu`@kpJ`a`wM)cV%p^Yp{M zNbl*}N3M!@tbhNJrF(tHvWbQ-jGy7xVP7MW-JY*98dn-0!kX`6f^tk|xF@*tZ5&aJ zhahA5=63;x5Uk%9m_|H*h{Z~o#Y~B`NOD_2W)tAzLK?d6u?)XIWLN_i>XRf@_p*@a zZ*@^f8(LE<@43+L+ht?nBmmp@T;h=fli`!EaJcO?*2C?j1Qd)xCrWB%VQg|8%aBoV zpSuu{Fh-2mT_Ih80oLxTmGaeSLV zk7#rVSRb*84rCrP9&mSWd|5+i(jL;0gg9z-3#9XQqAHa@sv=5TcETMeB zJAjtnbPAjYCjdg1gFST!^9|1RA~cu<{J1DNxKl}XuT>~a77EV+{Wq_8>w&OWk(a&9 z8w%D@HMk(FMaGJ%TwtnPM?x1;p=5==^x|-}#D@PVY#6yjVin;}hNPr`7p*h^B%D(4 zQBEXez84_F4SW&ddnFSMv5R;#(u%sEN)g@LlohS%)gw%j7E~o238xkBJZdCI{c6jr zNG;VLmAvy_B^~}0T`gy%qB7Dwff0l5&*;F2Da&$H$5H5M>`f~QU}gA+sGp`4+4r}& zU7GX~*Ye>(y*OyC9sJ)YV=$}{vOdw14IFeLzzB_UK8JraN)j}I+0-A5gE+zaM1OQ$ z!N{>Han%TDD_|+Y5++%_d{_d#9^&(Gg~ zfp6==K6t}<3Hlr&L$?g%2w}W}3@Z7XSD_`Uqt*6 zK?FCcf+&J;BY7MkUmA4cMiQGYigG~kMCvPYxC>IU0!6#o=r+0l4p{8Yq96%oZWl>3 z^iN?!xX9wXwrJsp)*^m`vTb}iCl{w-yar?NT0rMP+Y${r0@xiz&^`!yGZnMI0DtFA zHWLU`SX@ADIK21bZ37s9Xn1p$0yP`_Qimm+iwCB5Q5_aPG^qia7cE$904#^Spd$Il zOr(s3Fj8!SUg+q$B4K0j9-#EE)~VvZgT>ki5(? z5*qTO2qwwr*RY6SLqHKnh2aeJNk#>8V8YPJpn@QA3CBj1)c(Aj^`nG16dZ4^h%$BI zW-WnhGgg{11IXZ#6wOo_SfQ+b)fY%bST3JMfpd+Y0cRy`2}dhB&ZjWb2r(@MT`8FG z1rSOpt0CY)h4EvY$nT~5j3|DFdk1gTHPj^!+%`2k=QB)Ms#vm5Ls+6;MR`d%9H&!z z>Et-Etf;Vypv1YNF)s^R$uv4G7GcGZ%oLxjFjYaUq!f}>A9@!zgtO}*#UBlLHNS?l z$PwA_1rVPZvnrAvRgl2x^9F+6SUthyOe^Zg9in$2EWksi%9>lRf#miGki3aWkU<@0 zS&?i6Z;Xlh*~p57U_{D07#|2OV)7~odLhdg>7}H=!FR_qk#dQj=BJUX36?)fBthm6Vkmgn5@P0=`SjBp1F(4x-McYc z-}lC;T&=v|FN97o&!rNSO_$CM|GvEM4f~Rfg5E-62-jzzm#pJj9A5%XSVE)$kpy~D zkGtRj-bvEY<_^+P-L_F=RRRXQDv=GcFpwNVL1ZK@kWvl~3$qy2Sth2-KK^gG(9pMm z(Wv{9KQ{S;ljm}>E}N4H<&Xaj;A}WzNjg5IY}?OH`f@V9F=Yy!;9f*V|k zq{A*DT%|AZ+T#^r0hn^j2lupd-##qJMCfTF?)4h`WA`He*o5Go}DdZOYz zh#{p&apD44HGBm!$P@k-yU=u8;bVWWnD(}_aCrGu_QSwLL9%`{TC0S7D&o6xpKdi` zN+g($RwGEp3&fTldBY=1OOLP(=9e?=f|>QJAO!w$x|EHED#+9hhW&_Y4=B-2IvNiu z@ut0>e(=Uex+C?JAoU=R8?myO-{>F;IHP!Kq?%9NIfcj04jesD3t`(CZgSPp=DHqD z3rs;wJK^;e>QD@J0}4Wh@c`osNsi7)*;e*$xdVH%`(P{{B;6nqi9Oiu_cPNq!>CPX z`mE;*hhxDIU8}dCL%YxydbUxUnVYE@8=+_@$l)Y+ubYDB9AjV*Y!$ZyQNQww^8rA; zUOpCH=n<}|*9LN4sdwAq{mXhb!W)s*m-ipO?I3s!Ktm7C{Jq zbi7ov%f()=SniunOLp5qDfZA9j97iF0rjLds_|ema%j`#;NBko!|(p?_^n<>9^PU- zWt@Bb@$YwU(lsHhgA_q7cJC0eb;KsAU&Wo-Y;l3#Qh)wn_tmA+tGfs1;h#TsbYbD> zsZP&g>vS8L*1CDbU2_y-0ag^P~P8jU}eD=uMj2 z_}|;3?XsCDO_URfa&Kz7+%O7suLYxBn3}3o5~YyW8!9C#mHD3-?_FvdJ==vP6Fp!a z%(m@{F=P0A*i>%O&pKo{(7s!>bksoJINl{=ZMx&+k>kgYoV)|0+}%I7cyLDai`#&y z*6M0&ipKY7q1>lwjj_G{m+VU*d2P=jDxL?cBNj3V2M}IpNrN*aNw5$S3e}C`5)5KC zXlN+$n9E6As-R+0$wl}v7N^)B2mSR@uC5w-%x^^}prmQRnacFh?qWV^LP}871I>0l zE6p{>}&r)8!8)@>Uf|*288lu+=$%CcU?bVq(_Z5C3WtZdevYje*N_a^Y zZ5!yT?D?X(NYU;Vj?F1Z>6!F)?we_x^5GZ^LA(er4qn;Ynchz&ej%*1k}X2LJ55o7IsG-;bwNEoZ|;xZ5E;l7DdM{MZIeMaN`%_nc9*1R>O+E zJCO|~LM}9`MEAS2<8IV_(5`YRkwbV^8Seuzvo$*k1;C3KCX}WI4JPNpo&XH0#dw%fL-Gu`iK43!8OytW8`dyj zEdMCkcZDQkl9#J-|p{l?Tb9{0)mzx zFL_B8A<8*{>~1O{JRKAzLES|?mxOo+!y^K+=OEnpBpTLgE!>Y%PEZ9&(Cz{mA=1*j;a1z*3zDU%s z0Nqp9lc^U3hR0uEj$ei_L*~*hVtA032oyRF6EF)80UAS*-m`+@V8}=DB{zR1L$9fd zaBGUgZdt`_CDmGbmiFgw+CAI>EFn%cXZch!MDNl@ z>Vlh6f^p+(GzzLjmMpU0qwAX^`x0gfXi;;tZxlqyKGSS|B9bI^Jibs z{mo?6YO?5+DTBEl=^j7?d@-f096y@`F0aTvHP2Gr^0-A^QOW7+038_^h zevT%I$fywwym`+J)+3~Y|Iy0+wf!sE+1|>M{OQ4;y~p;v|{Cc>{gRK*E!o*tdRecVC6$8Y(zAa8tGd#3Ff+hb`w#=zL|_|dYl zF|om59PzY`a}#Gn4Z+b>=sm`fW=X~dT{J;NK7-kF+pCZ8%XuRoWYR;rZkD&GX&k95e zDoyn-s)mAp8z{b~s%=Ff9Gp4*D5{u+nZgZ$Og+@Hq7gHw1-1CEZ;km0X9{rlsG%b_9-1yn)|e zxeZi3KpUWA`?1?-3kMHxkFOb9ZD0??brfSoBZX1In2h$F zJX`=mniz24GB7r)bTj}k+F-KY!0=e;Hy9I+!liM?{GftUy%igCy-Tz4P@!w%@ zsU+F@XFkowlTZAPP8oot4-s;A9TMLQos@pn#Ev0;h^2<#W?rWcfBmgD{51}cecdAi(SC8TSCX1K@hBFw2(?DdpUQ2?5gT-ZdGpeQH%vH0QNvVR;u+n5E z{Rk4q-&>KIH&yqacIwjMyY|i9RCn~>J?X4qTk@yrTZ@_5t7gs`bD2{5+&K|dWnWEGV2ET&Yx0KRnF`Kb^=-jD-*1 zcD|f16j*oTqgfPlBB@Z_)G!bG0 zr1%&_Fg9@%mOx|l451y;suqZhr9mui_%hyYmgyc!BSI&XO#q7oN(4yg!NCmefc#X@ zbKkZjUh{@Aw<=C@sS@O7Kd%%tD$m^jDVgDYGx!a_8(k;6rKjBZJ`Mp6&jkwbY zv!xX|arLyz>kWCm=aXXruavH2CcGgq#JOFba6D|Sq^c>n?`#RT6F&~fRwjqM`IOHU zkNI5DG_w}sZ)QnvNXFZA?m`EkIZ8zRyr4VB&zRXs1-hJDtUrhha|g-+)axCb6TsP& z4H6GuTXkI$nCELQ0+7`Ha>O^8MPIAgRM^b z?z~#Q@!>-i=h0btv3 z^d19hin((8FY?|HdkyZHY;i~rU9cOxBqQt_%z+@a;4AA@G!}tH% zv7-R}El$nuXV!&R@6Q*GkN^CCD8Uo$jLOWPT>|0oY&p9p=<{2DI~wvwnA>6Vgc2u@ z9UGB_GUkVZ)YbZ6en^-gU=fXA^`pK8y6pgA1jX)=gAIoq_XR@$lpD@E+(-z_@EMbv zTRQVt?hkXRS^0BIu3CVdH0Z=CP?v{Ij`fr{O#;=20&9*qNod z{Q4d--j-)S0ZT;G?7ZkQ5nV<5z}6p_4Y z^;;=ejvaeQG#nX(;}#&>u*YGhVUl5wuffeiQ;mHPbRkpo(P`KDICxa`_703*J6L+hif# zxVHACo|od`K352y(=?>u1#jVgVe_DrDaMENG2vd9xjz;X9&UW{mltZZ{(!Vy-Bba| zQ7^P%12YsP*#OX{Kue1j9F4J%R}>DAp+Ag~?ZhPp-y;yR!!eaIS>+@sBAB??Jz$?B zoX@Agl508*9tX7I@+#6uxnJ)qWv|x zr+ScN__ydp2T$~dw_GiI8{)w{_isWs6(!;cBco7-as<3*C}9ghNJ1y`Ti3XI-@_~A z8z;^iADIo#E&yinL^(PEE%f-*duC4s|5GqH^F?UPIg4K?vk(~AI>a~lb3!{X+JC0T)k@^* zo6IK)-csQ=7{Aqgk{VBmr%&MRNXRMf+3LiRo34&j)bXj|ll}!%ol7AtBHcEhsLZ08 z&pY_Q8H(`x!TJ=oFzs}(nh0lrbE7a9Kpo(&9o4JABnmz#tX*6{M3s!CGmA6q{4vyV zx&9QoH_${Um2xIDAkby2XO?EK_d8w3&a;`t?%*3xOe>*GnH(wnd#3JBbC_(^JP5Rw zEGKX+^XSeACHF23?du=iVqPv*!UfR4S`y4XS~Wv_da?s|v{ z%d#(`tPMbHka5E{u|9We5i1nl+}h4o-d;=v_5B;$kKf!=^e&tfV~XRF>><=Bu-li- z7G$zIaA5cdNWPe0j{bMPH}$<8#b&7pm-q0mAEvGfnS24qwLuGm?w2o<<|$Cwm)fXV zbqR?UUDoOKHrI?5NI_F~{S=T)CJG*MC|^ejr6y%a(C<6ITK#!3Qv$lCl=(yChj+XG zzLY6t@ISKaF(^KV-;wm9V>raZt6!>oJX6dvS1DWUKU2N_mg}nwWv}WuObP!FaT}*< zp2v6D_u)HtlJ^9=nKMZ|w?tt>3IVem?$*Ee{YLlj9qs$ZZydj`&AL;Q{Xb-l$tivQ ziE!xgdA@&tm;C_85FR9c6oPQn#WCQbcGjRJRXL8BPLqy0f7P28SFb6ZEZuk0owuEJ z@3neu&F)*Fb5jGSe`)!-BWFXQCu%jH-EW_qTJ3hZGDy0@Mc&^O*8hIKM#vNCR-fR|e+#pGlsRd`OoUf^A3mN*nYzjEFEi}miiyY>B1#Wj8A3+?-g zEE19*@&tpP@oLc%Y+y4s)?I#&!;=bJl|1*<^5oRiwT2+GTzU=9X^ znhVW(0|9UDCmq|Pjkh+BZX4THHrpBk z{KZ<>Hh%}>GdhJU>D*-H+M|=(MtVNv@qzbbWFG&|jI}+LuT+j-GkK-4me5M6wsWk7 zUPkLL3Xn#fEDe(SRXP#AgkY(Y`3~GYqFR{RK`pu$7xzWB!_|}1N!GB_i>ub%TJw4UKL1r9Pz1S1w%1U zL$W3&bkMUb2LreZ6(qt9Hm`Ml zn;f`vQ~+$P|0r~0qR_l-ZemmX$);p-CiTiQF*((`!W0~tH)M-b?2s;=2JuG*)vk;4 zj$d3|eNN02a5Zeny+@yW?#O5VcE=>yI_C(yowGQ8VJPB2!D$1B-JBYE`BnIR#-&^P zi|ywW<$E+gCN5iiOcyfk+sUIzlJ8Uf|NBa(%=bT9cOT~2a@hYg$r*vQW+PJFgV;fi zCH1MX@14Fn`Rug*7qMEU(PbY>PDPXbKfL?uBs(SlMfTwQ0suPsZKo6#xm^l+t6pc zL04(k-0ZgRbk9AvO+bA6+wUJxM=bwkl#E*fqqPhVdD%}QxJ(wR$2$40* zR1tHGQd|y#VC?RtT6p5Y8&*3rGnK^yv2?C7&RVU&v4vOdt)E$~R;$Tq%n!bHIwsjR zB2`1o?HU2!27Xm4zW_5F*Jxn6A+H{!6PL>-L{EWw7=%#)_(us{{f=Zl7zE;boeFTl z5pzz>QlNWR_RR-`|GBWJzRHnOVhb+_m{NO_Y{(@Ch2rj19oxhU&G z#K~kE*C;J$yM0g_&_B*KD4~iYI|;iXwJK16VKNIvkXr%ao~QxaLpnh;m!3)Gqadv$ zhZUUHqe&Sn$T_bUi%%;`H0XEX4;-C*?EaYhHNueX6NuRwK;#OW5bB4D(6*?mf&L)_ zNaQdKtrs3{rddx;n-MmQ4X-1aijBSA;a$rn^-^|xE}T@NWbcO)iDDx0Qxkgwhcbt? zBvCI5K8STiu>v#Wgjh6)XUx-^8&AbNiWU0*B>kqCK!7%-p}10D@AdHLaK8y(n=i2M zK*x1Kb1q;+&8TJs09v3J8{GW?s0CmI+!#Um-3=rKUOhMW*^(=~;PU!beO}k1KI;o) z02V`4-i}~6>#vraF3+ou%UaxhJg^vy+JV^JipQ<9+cAeJ8jwfE3AxanwS0~H(hyzy z_*ciyC35U-eUM|SVIZ7hKkKVyh^s7`bB?To*C18`ouCL_f3WCt^SV|Lo-Wq={sR+6 zIFj0v`su$|Vg*nc>Z}m>4QFysDpA0ujP-~Ww2pJ21nN|}7y3OQGFayV z2oTx>--?)fA=stl3nsC^K?7S)xF2??j%rF1Ne`9yT^k#E{4QR08nhts14vmzeaR5K z&l_;wfQr)mNMCP@bA$d%ZFz`UjrxNWe25BXh=Q<~&{&e|MvtxaCN zC|h6@n6QLMA@2GiG{HeH1~-D#lMSZI9%Qn1y>1;|QoQjCo15g`K`vDPACQjDNvJ4W z1Wq|{=*u2O-19d&x*;q|u&+=MS@>qYj`1SvuZUHMSr$QvWE+<>lqV-ny9l2U?Kc8= zig}HMw9b$~&Re(uf(c_bu(%kQl@C;_2V|ls!Sxy?l&he$@Wu_Zfdzc&27GC8A_}$< zPT2Vq^aWz{U!*UWdb@Px|A&6`R{wSMW4-&YqaUj)|2q27ZT;)$N2~I$qaTLyzuJ%d zzsS1Pcj?9e`|y`smgNVsjP#uC(u_9cy0)zsdF%{88$+5ABUq;>2ZQn#y5;aXC~OuAHUmsip4C5w#Xkth8kh_CFzGY4<~9 za7UjwpVsz1T`pbCu3S;F4tp>nR)zgctVfi8c*V8}3<|P5SY${kfPjayt=SuwLm~N# zbT@uP$n!nH#l_$rbr-4LU4*>HMOj=3%uY@!*Gxd7LqWz~EY4fE?8E+dkP2n)cJ37Y zjUxRHdS-z#g~);@7@=d^brNIZpldX;>llT(Xv71KfGK-4>Ba5_;!Xd~UC6v*Bh;pq z)?5KuaR2~&(@N3{A8e>Fx68zeQjE#N&xQ1gG9sR{&{YZVb}bMFZSeizoDe4@8xNWW z9Bf(>A(~oUP?wMnf*5BRz6qdRV5Q+h=M0>+z<_H|a?4Ge{QwPz%TOvWU>tBTg#x3J zvwo?mgUox}sVL6zP$oFltZaWn-&;|u*;A$LjQX=v9>Wp)PE0a9({BLhqc}94RQ6W(qOBlOOANzP)f|#q^*CnK@iCSut1~kK zKx(K}@{(3_9z%*vO(pCG#)oWh(&Z_Jq!BYApne3ExJ*4qfoan0g-ae566saAk@ANO z)#b~T^ZEYfId|kyvWf;wj)7F~a&5eOkt#Oxh&FtrPzyy|kL<<`_6_t)M(k-@K@spW z4^nEV@iAC{p<0xEBU2USL#mnTTR%kV7L-jz+3eoTONHQF{BNTrXjfoJbp40^COi)O z{6!YA1|J0cE(6pBv?i#J0&dLtet1bV9;^_CEBTTKSAP{|6RErc_jidh0KkwpQ_8#Eys4Y8lAx;PE`_!#aTfMEG5aY9=inT??}>JhqM4HT+>1=N+9vjN;`yWgVRP zR)>1UYS9fx*Te93!8exR_NSru*K}^NQeQT6u&2~q&<$r8cZ=nGfq-u?HebaxAWRDR z1)RvU8hGXqz%JCakfMPMiGsyWt(H8^hhQRkpBN2UaTx3a$(2!fp$@-seu!;Xe zXCV~k_822$zt?h=2f z8nfLKRMniS{`t1Se3p6SkkwJNF(eG89FCODDKnISwS^=kC(#G8wC#PjLU}g|gG*rh zm}BmdjNf2?hVgYFMnTvv3$dSSl!^jkLOerBryUx-4U?U{FP&Bs;c#MFak-Sp-RPl- zIo)JZ>iUctzv^&&TJa`iH8TGvqY3W)6?jp|&v_A<^As~Diw<%bh7pXF7mbG=!hi5{ z7#A-Z1K$nF&LH=@3`seV0}-JjL}2yUULk7F{kd~H(YyUWIoiD+0S$9MrQ=bYNF}cr z?c3D8O`!e&C<1N1d2l#_;0of2g!_*y-rzoPb^^!mp%fTf%{?clwvLbWgAt_k zJK8fL{fnSXfc?&~?II*!pEm`Y5OZ5Rk1xcEXO?Q$`zGg(%rQ%O-+LNV!vNp|Z*u^^ ze>P=5cxGvj`>M*GBm2t5Tbd|g0PlnrZQLeA_TU_ceJI24y>x|M@Sr2%)I{)xAZ~-K zWsCvVR%1A&+0LFV1k{%-*{P|l=ito;;mhur-N-h*1AB5uS5E||mUM82OjUAIw+&7z z+lWTRzQE_kz(q~FTuq}#yao;auvfz;>=VZvV~(H0?O5ry zzrF3Jm+U9)OXcX_Mvo)U)+I@g(SyU`UBKTDKls6u>Ga7DeBdrrmcf6Uc-R`Zzh`J0 z>`{A38WfdT;*Y_}YSq+|_3F$#-qM2nE%b-Rhx{|NbCU-Ph-@Bf7TO4DBz2vw_1i08o>>7azR6Qg zKNG)QN6f|xA5(z}O!18io#vPh1e?j>1o$k#l_)1cbWq6n8j|o4x&^P9rO}Q&5LbDy z`OmVAPN$K*=O6GYs?6(iA_QH4wq%{5&jOyZF7Kc>s}bIZilr(h8_l29%{NL4%Q~0*7X~3H*r&Z>ZSMzFmkNu>lV0KXY=k{aTOx zh&`QrZSp|uj)I)r5H<6-X)vgT&$(^r`udV-@KN@)+`w5%lD)ph5@OSg&Ot_7^ zauQ0Gb@cP8Y;ra#(y}g$sMQeh_->A_6XyG%U!>d55nA#}+C5B2s2y0xO)O%HdcfaF z5OY8h5&dE3F7L~QXMQbsWYX&x2iz6W4$|M!k-O+?6oH7a zSf@jM6#nQmo;&s#WI%C*~X%-khDy9?hyTS7lD3mieF4&pt8)e|~?O(VVxK-*Ag z5AD~>XqjvwGOvfo+j#i?u^5(N%rB{6%d*5)OD2ucY}WV3+;Yxu zbuty-!8fTC_5z$NHn`{V3>g%j_>9ElGMtBgqmyn6B;@G^O;O}Q2 z=Q=8)Z$;wRVa++M>?FaTwK^k+-?Q}(27|v0@#JBjzHO3uBy07|mw(yjv(2_$t~QHX z-L?Bnw!{Lt~4{tf;XXx@fih$)pnbcpVHSbwdRtggC&)Z z+Aj9yCTz?b!V11JIVM)mj=lgsbfv!Ruz?4R4!bUoY=8az4j=DCm-i~ROJBMhsv`Qp zI|X0GAa8Ap$uocm8|_q0%hl)?LLzjlBlyQ9tw?l$?C0SZc*h`pe~kB#I(CUE;?~wt ztd0|G;tqvDZF$y`h3K0SfHBZ;0DL`L@*_2xf<8UxvYVR zG~dKV0fmADka)9dC9NGMwgS}#QE1AS!6K#I4tT3t{h3@NTbatniXf^}i|(QwHK8LF zXkjuOc%5TD?;av~-Fu>#cx%Cw@ada*Babc;l~5# z&4}UrsMq81j>S@$=yV`39nByL&gYkzr%PxxYS}81ae2cd319F`QGzt)7WPcqyZO@D zX__Os%PbLW9q9`?hTiS8*+(+LZrt86>MBh;(k(7>o(LOqNlshNp@-O~%Mz9Z(Ks~_+wb?-3v0UyU zS2T3w>X_~hMU_}o+n+3==yI^0wI;>`nS>hlXxU^sJ|2yRCJN*8N=(gpeR3m}(?C__ zaz{~dI|4FWhdUN7*zJ{1hOO4@gfEZ?173!s%hgOW6wl^RIvJMUo}kOs2>OFc$l+QJ zfc`Bw24|776knW~h$&+e%Y{6C;++nqbLo6U4S5nFNtRrNvCKp#oKPo2vJc31r;COQ z(+C4ZYL1Oe7St`T+u%$UI~ocqZLH}VElfe@2Mxr5nclI4jT3ZLfapnSf+aGF?+CCwoa4f56^uw`j)1nC`}p(AOh320 z3EdK?lz8Z28BlH|3NFga^~)E}bP6RDz6l#op}=-Yoo-&}AuB}vJEg+!jy zs7eWBqJLZ=FEnBF5xCCekRn%pA(Us!u%oB5xw`;7fg;`nh-CQ^#^YW+5$bOQ6X=%* z{7}d*hRTgES_epz=4A5Emgkn8Ix6-gf=mx36t%yBK5dB;&JV@LFbDXu#{8EcS%Hdd zXfX4zYdD)4iE7Da8;FWCW6Au!#@xY!bB%q;Bl~lwmLf-vs>Z3|;`Muz!DzU((h5g| ziPSC2QsYFWa-sp#2_rzu^*M}%j4MSc#su`rk@?1)RKORCFUmI}pBa+?TvhP>G@2y|bt5kBjzKlOz@4%;@ z!>$4-IiLS+%zi=ENotK*{HF;pE+@E#@77G6fgD59%(iTNGVbZNTbTtyU$^)iXw$vm zFfn!%r8KH=p*c$fLzGh&M+>l=KVPbuH{hSGm=xW|fX zI^1HJkHJ`>EtWlnZ{_gq{+F4teUGJevw>}y$V;69Tp0<~LIfc}9_#jXX~R-oUjr`Z z4ZaX`^h6?r;sFWJFoNLLp!-(kNgw88mw(g^_3ww6!Jk;0v~>|3$Q&i0@!*DuWD)KR zUnJ;E9kLg+1@OwxlZfs>h?|wvt8g?Mi1RRXjVg9u!L+{UhHN{N9}6Mz}KI z-Xa6cGy;1_wMmD(sK^#B&+)XI_VjeNiZbwYPdP!8bLB8T_J%|X@^SMsd_%0im*65M zVpp_Bt^pjJBmqPcL_m{kpx8p4bz!+PWBrA*4>GGma=oehpv@sE>g;&8O$qID*(nB| z^FuD{rM8o z?ZNJwTwvtm4}aZmBfEk@jDziaYI@S@>VFPohWr^j2$5)%7zsO4;pRQm17tQqqsBgh#RP?_M@?GUgJ95e|9Cd|}6d^>h2fR!OaR!m2J8ctFQ<3&%3rMORiZ`V|i@7t7KF>paauT5^f@28sldPsp5L;b}7DWgerK;e&y5=9F*X+Ie zP3_HgyL0_BU#!2op4Qp=lfU<#_x#?Iy{nr4SiccMVqqPB^$%6RknvCd*nH>V+n=N_ z@HqtX3XD~V$dpkYQ$wz*m6#`BG}vJ8mk**I2+CLY*B-@sNi3Yat{(Eqwfv*^9y}Oo zUXxB=gZ;VkYTx2@_y8Z5^ELU^{b!5CtM^EU4@=PHg{&kvu#KA|SlWo{F~!mS$LpV2 zUS<}^v(@()CzL&Z&6MscpIa9}>QAY05u_jj^k|B&Ezn(g=&Yi7jX8~^`4Ga@nC$FQ zhtjgdUB?hi&#P1+6V@-vylo(5i|1{*y}b(;1@aZ9E>I$t4)$&#Lr2=D`SX+Y0OAGv zEA8d4)R*6hDp%E`_4#Q16?(O57^S6hc?tFi_IB*+|HR%qm@f%PHDFgjhzW_g9Tq|u z?u^wzNf#h6G3f*HY~4fVjt9s-KtL2gMBdvS-#^yhfCjogarA~GlSGS1Ul~|O6BALO zL|&(S%uzA+D@CK?_*jPv;z?t4&oTFR3xifq|9He;mQ-F+z{s4(7LVNr(!PvDZ8+XQ zJl(QdC6_l4Rwt4^hcdx~7a}b-KJgNA+W9UH#$MJ!NXg@Od2+$vXy{^t$1PTe@^>U9 zjml17Q_fS!5dskWIkb1utZ2KU+S){Im{^yf_@X`zlrnhdS5Pkp1!VbLGHoxK3zUGhi`#k2s-rXM z3~jIQny~APwY43NWxoBc^5c`9_gz3`K7=t#!BJ>HMqz%Fr=$#hDhlKhBq4VaIH{a= zQz%*VZq>?@ngL!Su>fSg*h|2bkI-@lK2jww!{(9mPK9S~8* zg=5F?13-}v5YYX3Dj&iVj}KagMBX^+TG zOM_1aP5_hl2u=jzqIQBCfh&Ve)Y)#9%3#&j>ZP5`N4J9Vs5tX9u^y#fxVx$zd943s zB0q8%8BijDId&%jl3kk2rlm2^9u+fpPiseh<~Xq*Ro{>%S|n4({v>@ww}!ooV1Fyu zU#^eWZFTPCx!?mY-@(U5y2gSJz!2LBR>#0ce^A z$Gah33^*G+EF7;k2n;BogR)CAx9;D6+T|!5uU0T3v!^mCj03PS>CEJL5UR{Qer~yf za%K*YOzpetFlrE--e0|`DOGeSot?ZIV}DhrTFT7T(zpVXN6!(3kl3ea4F9M47s0Z? zsz==WU%Y?JK^>$uw87pFdyL>_Gn9Z!;Y9Ai;3fg0nRCq$wlSjbAlH?O#5A>u6g9rN zNhm9X^@d-}j+MYc&WiPV5p3QWRbosko?6OyXG`&<)qcim&nA5dfQ_ta&_9Gg?aSsr zZnf4=%v=Ajc@TC>?A;O|1GCGgmI59-ll}}2fW-32tk(%*@IyqG7Y6Z#urDq#9ec_? z4r#PB&6Hqtn#gh}LkK`IdIV(+{OaU1#RGk9m{XT8)41Y>>?RQ$?KtfUtQ>OcGZb4= zDCM0Z1N28!KD704Bxc|@Fa*&#^|kI!wmy}F8Ts#JakJfVgg*iL*xu~J1Q(gBK< zVqEzhxx&c#K>7eS!Da#Shd7gW1lyq>Fa?xf#%a*9aHiFYHhE++(@-*rW99j?wc1%? z=bArlYeNT7D@|fp)s$=^!x@mMDKbwsV2aVDjd1Y`BLvqFqNK?pRVyfzBwS0Z3($pN zGgkDun;Q!=dy@S}|8x21|W%WfoS=Mn*54xl|cUttQ0^F^i+XG1|O1+6!6 z;?T8I?48M(Jqy%IuhjowvmgaRBO<)wRrB{Oo zpKtKyJefUoqpU-G`daam*NE@_(Y9Bw5nnk@o?-2W(!xY#VnGq;hb!G1Kfwo(CKLOe zQ&Ubt2@37>>ktnFf+<0Bo`ZJ~FuFmoo-}6>tT#vFvJjAC_=zdhpk;Fvn#W`589?Jd z+#VEqi7Heg!EYSO7e4(C5}=^8Zh5?Q0gs}5j?oyAgTQyk<_5(k9U>uWRO3tF9L&Ct z01cqCV(ubG3{r?}HIh7|5QAU;^>;0R7j1vCL&O$?|J!?H=o?-A)>HIhIa9`eG$h22 z2pqXFI}yGEaWpsEwQ@*s(vMZG^QiU#$qTV0kWZhE8aL(hHyP36BVj3outtJL*Pm{> zt~=>$o}Oayt>6~XvyKFdgxG*Ky2+k`eNTn>;ANv2sPJYFA=AT&>jd`;c1+8)Po8zX z^PR4cm_}$o+-Gy z)PegjyN!ZVpc3DaLgVJZu(n}L{L-$vd--!uQ=Wcc^# zH-q1`U=-1Rt~Fi6xKomfu=g!m4Z0>}LlPz&;+L44%X!k|3q-wE;uaf*p|@VHauaYP zH@0+&W!#liORYzhFSS~VuGEt^&5HccT4hRmC^PFDAGc*9%HOTS_rd2l&WnQYGLIp^ zCxgpNH>8Q;st;Qi`zqHR(I&kOB@%cHn4D`ZWK>eBr9nBVcqjg7x7&fL0virtBwPwu z*kl31%qBBSY=_h)*`x)oUGHd#HlQ-bOCya-s8vAlh>lS~=2!gpa22 zhdb70irFwF%7Uhl?|(eulg=8a%=aGJ0^!PzC}>K=!SRHj+{ioR9iz#?&l!#uSfnfA zcn4DqPv}`F-bJQ2Uc+P8M(zSK@F^vop5eqRIBUEfId2^>r405u3dmDCVra3#gdYy{ zoH%1Ni2JQkN5f>$0)&a?+WhQj5w#4Yz3XTSXO4v>MjEe>iO|NxLK28!tm7+m(&C&S z#yL~!KU|*3yX7_1DLaFoC5p&ceA4abyb-TnY>uD1U1F=={{Lusyk4Zx0?e9fF*jE| zNi{Qr>Uqn(q|lh5eAvN=yFo4vWF(33Z%OCBiGFbdobr^Dq;#ge`4GW)so*0IsVH-lk60F_SE zC<^#cwDPCC)`Z{5axtG4j07^wZXEC^5r+(H3+fgHT`NwP%l-}<^C%uC8VJDH7y>MQ$P5(x5@t;cNth)hJ6=Yju77#buIUoEdAmb@4qUl%SsCI*Mb#7qa`Y zXf4xBQZ73tm%+x42=um4o-b zS(n&_#&Xa7N3Syu^(LhqC9Ep~R^b=~Vu^uKWP#QmXf-jU7S z|CLPWzT!Vv179!srl!h&VbCd2+XR$;8&*jf>yzmBkDzTHZNT(F;tD1%k1r$8M7*_x z6&bQ3Q2Y|7JixV(Eiza;wAQG4w%hq*~D* z>&_KosF(5nn2jWvE%tttt&1T^PUtY*wMus_9+D$IUqr^DM`U!=a~tC01~4W8w}grS z+kwlmCN2z?MY-vK*8MC3?L}kRD6U?_8s4WwX2;kxL?5&8ck$`iBzB|Km6Zn^^5J-V z`WTIqxc(nucVfg46$TCg3Q&L{q5&0%J<)&RRd0Iak&nD@`jG>VOea|NRgXOK$TWX} z-$EAP?s0ZC#Y%)%7DL9C7oWK2J15xHi%%Z^&OP*%9c>^St2L=wJB1NzU%?S?>A!%Q z)2JZmPw2h#mV7Y zfnHIxMs`%c>y?x`TqOYi26}K0?gWHNpKi69Q@*uSdL>p~!aozP~WKrs0CyKAkE(Kg7_ zzrNa8TNCpf`x)t9{5KAq2kJef z?Trn1v)4MEP8YwXTgB*fpc8itzP?7=B|RIzi;y~^G%ul!*hXayKV8Gmn1McbM7x-s z!*$Pt`k}l7D-$sltVJwJR_(te7A5o2s$^AKm2awUU-u+~aF&|$_fF7~{5+Qa6Y#t2 zSo4v52=WAgQ4Sn<6RX~WBM!t0yAx6dFL#$K)E~a=pCz$!eBa^|XvaMM*7ZRzu+#{U zh55@`bgum#ohxFi;{3%p^)TOhm~V(96=|ZQ=SZch(dDJ33MRyz<9lgj^i6x1K(mG^7C$o(elLrwgU`H8kTKJThpsxQbhrY`p)qP6y@<-pBoS^`8FJ0P4lf z-3`3E-cfOxNy_4yUEVhIVTKlHvPDFrCT^<6Ksy=1*l3ux6lJ5wK@VsvGJDbA>~>m4 z8#k8IS9F%!`X~%~Y+jic{c8b-(CM@dV@v-g1d&;^c~k|#b~&{BsU%_9wEag=L8guW za~Cc^1*Xk#v|2|?Q23x!AU-IN?knch1&qCi{5}Gr-=vIJq3%FSUtNtaqNoD73ZS%7 z7RNdV2jkoHI~#t7D^G5jCMF~=1URPxTGrHh-4=dKIm4CBP6x4~u6YC;>(UIOAk;qA z86_-{ddY=j6}*U0`bYpovQ{|$8eZ1s$)$~87ycd``>2R_wfUv?~31Z{2(Rp zHsNh8*0mXH1FjUz7+5IBlE&(tm1O^7SLpx&&AY@pNu&Rd#?)kT|F3sF-^%&Xs~_oK zn zQsr%u`#)k|W4{cE|I3ztYxymVr3&w%3Z)%Be&iby)~GC%p|rz9rP5`HhT%U)tiyM! zI@L1K9_vsVN%b$omgO0ch@mv7cauSFe=Lc zGtg!F3uH?VWh@NnOVcN+)f3al(WdFYXhR-RA(2Va?+1~6QoIIc{5BcN{n7;D z+x{6`>dZYw}BX~z@&%p7%W0$1MtNteJX1!D{Y*Ukk6lo&O|5+3mf2o%)zsf z-Vb%s+;nh+k9IS+-=5j-NA3T2{^rPaq2oo6%y;<_fhz*a9q!s~N5zn{%KyND2Rp$K zJWV^Cr@wRGNr^vM(iuX#1b}LaD=qI8bvd6C6lC3~A zFNkLsn%Eryiw6dg#KcI0q4yp_y|4D5*2?mhn z(dErPpD5o>ZSKIFsbmh344S)c6vFR#`%X&%z1G_G;z@%ph|0?<2 zO2SLc%>;2+qWZ5F8f5wa^NU)(AQaLtvVPW#l18m|uz~57?$q({zA3wXYG3&H6ui{c zz-G6*8K~Z9{ky-jveg!X4;$TT8IEziT&-x)bv>$eJaT1ZpC<&F8~!Ei3Qd7%tB3Mr z6-6juj4%Nd_O);vk&?BwXVew-1PbQx4aTCwWW|AD;t0KQgZ(|0BiUX&Zzh7_AtSD4 zmOis0Z3euG(B>%l5$ZEypq!q&SNE_D0wUjVN*oUa$KF2m#vk2sNe$8+x*#LY{A2I|^s zMR97Y=Rt+;MJ5!elr}dpp|)vO_{d_y2)TW+m3%EqIGOQSg52Y zN1fbG4nc-7&j8=EjrZr!D@8 z-5ZGYU#y)KEzJX|G%r`P-s=8rRn7p%E=+TB-H~Yzp^Q)zs{!t$5yc1`?|>xvtq9d0 zz@kLBLW5x_injf%ID_t>JbYXU`@pLnR@SMFo9BDHO?F#{5_6*CGw}{cn`)-rn2#gsH8Vy0Gby*;2M~m$5B^of5V~*?C{BcFn_kV(*UadHBnn3`p@ZtB*h4>u`oz>3)O1URxiPtmd_bi@Jvyn}i}^K_r`q-T_}59t{baf&qsQH9YNb77iu!1y(&d z;~zhFqHzLr&z%)xn z9z2dbU$D{(Y~lP1N};(eE{X&cyw5QYctoTfe>}->ZLLSo)!`dGvp^5@s{Yr^o#j$x z1>aezboCDI2QOAk>llRu$>Qg_N^r-yh)N&Z6D;XmmZAQQbjh~Ug$mdQ&3~>1jyzr| z<#Kh{(=A=`Wpgi~S>cbiJJZa6`3y|xUXWRT#Mc+t@gRusk22}X>@!i>orxEdnfQS_ z0PD`zr}j_J7st~F?ieKcU1WcX-x0SShafc}La8VbRydHK8@Ipr+FuMv_Wqw|GLI}j zlF72w;(M2WF_2ag@1=L%ltBbksDORA4u2DJnkvkJ1(9)^hwPqmvxpb;5)ueTF+HI8 zPNvyAm7O>i$@u#pXFs30ex+CVmF3KI@8~TX{!W^`Hj=HZE@iX#2D0)?{Rc8P+_;*2 z%R**swf?H_$Q{JjA)j9Ab2&|%4HP8hZE0wSj2~wCl|m1P?BVatZ+`RqTav4*$sc2UA&0T{r5yuzFc$!L_s1M*reg10w7|GG+UEoFSEWM+RjfU`4|?F~q)*wug|uGIHa|jUt~CNsX(< zO1s@NJ~c7;8%b}Z{7TBIWK+%`#DAn9xALEUsQ$nks0Mugs-JH39Oo|Noxuz!eNJ2% zKH8%X-mdQjW1_2fb%!CyRn}Q2Z ziWyL7$C(c`^GqRu(St6$fimM{npOI13AT6%2(?WT(k<4dh1mZa9B1J2Bd&i6>GQce z08x^M3}|QCD9B|8Erw>*@$^KxE^O<|tNz;8HTH)$-g{9NC0t zg5Y4_VD!V>By`QTYPCWj$HS|rk++|4BK!T<&x%a4!TvK8=p?!Ig&Ch4j59L}ypZ0? z&0W#te);hU%&BQazmLgPT9^>Gccbq8A(1G1+N&rPS0LuH+n;nzBy-)|*rcQMK7JiOXY<}zZq1)qaWe{efT=J>nm%db-!Vhze z3c#k3O5@pBL2%B*)*`WUgBX)o58uLCqa?2>tPLz#8|FQtv&{%>8)Bvvo(LF2 z1P~#%>=|Gph!u#v;Br|HTm8=dZw#J%we9qHoNbKgUrIK2Q2JHLc8??Ib)01#ue1MO zT(Z~6_PFGiETA*-1Z2q(@Yx&>IQ-HB5|e`tz7N3sQ6PQl;Fa(q;UP%aKBNgKBd-1DJGo~J;LUP5ue(j+1kyvOwj|NMoa>&W z=C}F~fZ`jH;iE$}XqdFA;H^QRgk%QmjcTqvpX;22H_S+26)Y4I4XU|?zrQa@4d&o-ec!KbpAXZ zzjVhj@3{9EV4}z9_3QboJMc$O7U>(uXpCt6n3+Rnq6f6UVKz@0($)z ztlPA(U~_4Z&Q%iRY?#`!nu<;2=5pX!T?LEp5{P_-!12ZR1(exja#jiKW9uW?KIKFA zH0Hw|7b?roH|~+Z<*P4E=_1ViYzVwzPA7Q7LL=b?TwQ{_1D3MJ6haCO^cD&|a40w> zh&JgPdb_)}cB$R2;9JnOaYtbX{GK2S8|~FL;%pcPyid^Q5jPs!u|g>wmwdT&tK(*R zuDSoX|NeFxPP8uFZ|M`9(~uLi0*8)2?37h-oY!SRmXu)LSlu zNDy&R1$o4cJ%W8Z&>N`KwIc78Qll>sLpJL{4uFal`Nw((337s23BJVs@1u)4Ytj7% z`l4fH4*sx!0S2dB0N|nVJN)4b_$Cbxt_()x5;OQdGmhuPA_djc9A{ z>ukb13w|l{fxIf4xck1S??rrQsNv1;HiUt{3VwS0|9_#)0toW!rP9l{DdhAfKTpzK z;kFrstA*}La35TU(!9`JRm2ZQfIj_C&Ch!~D6Km0_0BVc`}+A^s~xRI+jJ+!lJAe7 z;7MF{TxncM9q!JmmCVd4^IJ*TBArS!3Xq(+w1*y81}Uz_G{@Nd-k9o*?E`*18Miv^ zkiZtVx7CBh2b}1gcz|E_sS|ErsJ3rLbA$r%AWP2fn+sU&?31)zEVnN`C3M;WOm_gk zB0GrI>}WbXl2f^#1rY;iuei}_M*slS1mY18^!^VE$(aQgpj(-7ew@Ob4v5 z0&E`-gZ(|$_xtb+GYWYz)-K3l@U9L8;*ziq+ccf_z??EQdbbxgX0{TC&#ZQ5$Hf1ruoLz4my zY`=U?<2q1E9oc(j+V?<6g_>kgYlmZBCIcHRFC)9f80!Wqlg0jKNw0))k;zJEtz5ej zctVm^q_89&)@cD5JeJj7zh`-6`U!k=kJI@$9#*)>!CXW8=4?00+ zf__0&JNFFxC_V1{yOm|23`s-7n*LMBqn+1$yHpaMsbx6rPg~BwasOJ&Pr-TLvD|NY z16=rTvHT32_>WtjvOH~hujQ94AGADU`QI%cv;0TP7cBo7D+#7D+3R$Jy*zxr^Y#B% zpEaoA%WvS}iG&bFa6*%>6zQ*!6Mv^B)UfFqn3&K)|6JNPvp-v;f0+{0K8IFtxw6Sb&gII-*(smo zd&DPsAMs1RKbIwMQI_QE@mTUYIRyRZ$gEUB)e=%F5ql1KHOPZZ9T$$#lY-SWbEq zsiZIYT|GGAohXKi@lvoDFNR8qQm7QC+l1RS!Gisbcx1xsxZNI3`K8x7f)#b%$IiJ^ z^6lK!B4jO*N9jmw;x!8>d6rf^k$zIF7~+urK}CdRTEhweOpVA}2`;4pyhF%ixL-^S zh^-gAp^*23-p~W6JQDIcz22DYbIB795H|)j-%o|Sg|^b|J_H}od!Qs!tg03C_P<3% ziw??C$Ok6HSaNQ$6>__*RypDg>Zm`r^3=Jfpf%&$Je6GdVhH|2sY&n+@w%Agf1s-F zqU#i7<}UHZDrydL3E@M&omYYCyy*j2%d{YLorJKy>T|E*qk)}3L}8Rl!f89Ow?n!L z*llr#_Cp+PaPJz(m^W4+S_RRN@FkE>0U^nCy|c|+AZ(C@!nlw` zuh$P_wf;NHCoP|`e9rRwmj7z`s^#mJA2A#AvIxVuBGiWTmAPiEpy9qRvUij-;8@CWDL-$Xd)uDdA~g-*(xg zY}65TA7OU8Rr&;DHk(fdjZdW|IJjlwDV$EnCKB zmF)2I05@h&`2ALN0IjOX7h?=f_-rn_)!}h5YfQGe@!cc8x{RM$>CfSEgivHO7@#3w zHfLU*(H$8{&IiV&c)%C3!krLwGKWWUF^42P5vm@JUwYuw`++R%;OV_?lCt5e+df)CUZyo3=@;oxcVB<~sC4?AVw_m<-@W zgZ4snHr!2wDa7L8oFk+J9l5X?4TDg5KiHMS(cem*K5J{API}_8#W+}&@jt#8!;#3J zh=Y^8BMr5#6m&#rMm!KzhI6Dz_CHx3v`50$q%s2tK{gd6JiuM}lBKKi5dKDG(pUTh zWkIx84So4UtbQBIA!TxU>OZ_J5^7NodRqhxUfyA$&0!1><9{17p#`7$Acxl18Jfi~cI7X#W@rW(iu zW-^6XU~$^2>(=Q-?TkKCu2ig3UGmr8xey<_HqP{90AID+tC_JtQkOkQb@a&kL@wx` zIP7!L3m~-g{Q+we;Ft8GN%xV1m+5DGUeMYI}{~4oz?5c;>Ml7J%kSl-EJK^ z(hMirJ^ae&GeGGL^2ag!CcX&si_QdB3I3MFK&+6N5f?!VninCwaAYwwc+nP)1Vj&! z*`5sII@oM<9a0rpMvlMi(KBOX8QsHQ$Q?S57RF#4g0l_HXvK zQ=AE&8IF4!#H|Uy)#V_4QuTP{L0~_SZ3GVrTgOr|)jbFk7-1JTDBGVLD?&bg9(&1X z3<(nd%1HvW1CTs69|>l?Gee-q+2$b3$kDS)asV3V-W`%@xH8nfI9Fbm4GttoGw$w% z^Ousm7T|saP7tjUi@|6%f<|O5P#EOgRZM^ObsG}C}SAG^}&utigbOIB+4eg+uYQ1b-BI+>5qDeOmEe5 z>-AiVhDXHt$WAXI@u&)7m#kJ$Xjy3F6+QvOPro1eXFNhCyKh!_-*yq1@Bf0RB_}_ z7sOJ#bqGrn6RZyVkS`%xz9OW|LH`Gs#0Gp(m-kG$=TP@ma`0iUD0tnJ2yg~8;0#ny zWa01Z-ESQ|bZCQWzv46y%A?$XmQ2?hx*d`BQ$c|S@9nNyO`d|~G`>x8)m=9J1G45r zT8j86QQj0)vHJgPRuR}X=)08^NF{g`f#B#^kMu2zRndgUp~h7gnBWj;yL6&>1&yrr zu$$f6J#-J2>Bz-rPEloRw9Blcs2hh4E$G{NQn|ba0$pnd-9b0)4!y;&AUIVk?NnR{ zk|3-p5r`M6DXSwO(}iLW*|37A+#AB&+lGwaMOUxf?4EbJICXpc0;=2Lw5fe*oSk3I|D)&PLpf z*gfIK#gbF1U@@lBUR+8LDUn*6E$sR&sz*X~{s3BLU;LCm;c~^GZ;oj|LAVnBPdY%< za^O|~ApOk6O)^A;Ox<2Xk$iA^X zd3e5Lug&h6K3*BmBJGjCJLdDE7$wYkyVElfnaF?$l0L}q8S}~by48~#uNIHUS_CS9Pcda$3YA)t=zs~Jt zu9l*zaG;)dPbDjrqQGrs&Nq_H(~yHlEZ4z@WdT?i0Z|BG z8f=IT%4@9?mb_7;QO8<_>j>Qu%t#*ee7`@dtJMK_@iP^oy>Q`)zRB3Fl z-I{L{twNrO`-w`ik+<6Sj+Ih;`3avStrdwA7D4-m{twilLaHhG-~dts60~I~YQ^ZU zD+bivRozh6SQqapz{IIY&F>mU7xYi&_5D2i2>cHXjPbQt(MUW!1OeV z+@*(&Z@#G!xi9%`%YY0aa~Wuvg9z(GNI3~q1YL*-FG;yf0c!kKpX9cCl4>wQ95JvY zyg`@ba|fPey6fAa6zFu**-EnlX3hVHwKsv2>niU=>r~aPTl;?Rt$km*>vmT!)zziF zOS>#fmSwA3mSro##(>oZOo$9Ngp|QC10q0hT0kJdFu{O2ykwFgB#?v(Stg0$0STor zj|qWnL!?ZSA!KH5S4 z_862NA7pJi5^g-5nhhc{1R*Ka3y-!zi2B_@xXZVV@)OV+SRxv!8;J!&@lbYZEf-;? zV2ZRBYHo7n4&N!w3lmgNyS9E9PT9;3f~f{Rbk+X8dgp^}(8xzGRC$GZ@Nkm7xBnUa zlKP=v?ET~nSgqwY?GrkKg&%=I*vbLUZN$r9s^7Yzl}iV`$5k&6XPRTX+= z2#+ispoF=~oj)d@OXo`${1I>1Q;Vk;!k$X0@<+g|)7dHo3bC-rsr$d;rSSW_d(TW* z!|AA2ibWSo|KZi8pM+KZyDqk?Upov1nmB7IIRa%vh0hW!-6oL3z`q(krvg5jFEXrU zv*kQ0w?~IPKUI^Vg+KsU(K{yMi36EuG|HQkRp>HhcrlK9+LJ;9*otG`H(zx(6#*qc2)Gjn?OiU%w_r#1h=zR2E*9v{Gbz`YWN z5At*J!`cn)F@K^wQCSwS(i`FkuoA1yIjEp;iopfl=1{bj3Y*CSOTDrFxOTuU#jJsl z%c{-WgF%PAbW9HUQg&`Y;9A-g?tJ7ab0?OxF)H>68}^U_(nE$F`A z8+C&Pl1dIh)%^nu2Twtt|5m5l7I3{KFBd=WGN<4M6YT~uCN)Zgx5{V}VQ6h^c2%_T z>u87)bkks?8F!7fQgRlkMX=?&oo}+TCq%8KkybURRnix!5jd(LYWx(o4|kDA^dCWi z5Nrw8;yF+a$w?6$I)8k~?v?|uasi3(+*U?c>f%PzEe zxmf1c*~6mT2rwYYGnWVIk&HNF<$SAzgQvY^5zKN(a>>DmT^N3h<)t{JC&XFOmfz53 z0D zQ6=Yfh~MF|KBavok)O9F%ZxNqgN6>fz%04t{5;x|j4c!%x4U+0<#3egx%iZG!mY<( zj)_df+t!Ol^H=!IW~Z#F6ZyH)M75Oj&dy9W3jiQl)XJ$`DpyNsTB?@I&1t*I-VK`y+xkn=cwo)y*2GpA%T4_1nnsC^cD&k5swnhZt}^F+7d)PnU6!b(wT2{E8hAtfuFJI@M7 zDt{X(AX1vW)xIozrj$;uor5BeLpSwTIv?`^TmNGn=oaXDosJ=Kypj6Q$(1IZRC_$$;JQ67Gr%W9=`nSvzLJ=J2KQ`^ZOF(+|=8#I>-CEWu;<#iG87bkHXpA zTvOxygyKtRz{WowOtYx@d*)ITZ_PO#)O|_J?BG3yn);31ED+PknXCvpiu0p9glFRn zHgKqSTbtl1h_}%hx#jh58oE-h5M6^Rmvpz#i6Kamo((mr8viJ05CWea9ba@OW$^EGY~Pjjf&27CDO8I6-XnG2WB#YV>V1R%p(h{tVgDiTm(~IY zy=TyO+RH-CPR^ll0yjuL7Li@m!~4CiIAG29{qVG;g6aFb~u z01@_j1fd=6bbjrJce2Z!T<*}$Wr{n~cN+6T;>Z-K5+Lxw!xGw4lL4odf@R6=YP5EU z4nvs+-UTrM<^>8c=4`t{m}nSeaTn{AQt{B~!ffGmDDEJom?IwAZ?EmB+4qOysnVq! z{M>yxLSXCdY6q>B<&-#Ob0Hnxq9Or(ge(F9W zsq%Xd|9U1FNysOyFApRzDdMc5wo#xxb}OYW#}Nh}D40r=a)>vFtL>cLJg%4 zpAfOziQb6akNTn7$5IvlrrDBsZ}tn3nb~?Iq_%dq)KW-oDp;%eBj7 zOM>q(^eXIZI1&km$*r;&Qq>R~FxQ4Ty%6w2Iuq!X`Qtz}y^5J4)Igy=r$q#znsyKV zi5k)_qJMJlCX=q|P)IvjGpROr^ww{JJd&d)NMo0^``zbZKn8x&H)>bVYMlAx_kR;8 z=J+A=9wPK$=(_p50C~)0B?96Ln0xdK5%K| zB}XqQOa|jE(0<_@A}lWER;0|L)fs5cdehCA+uigz zLz*wOIO`2a{x^G)L0N@+COnhXR6vd;0c_!eJJk9W&$Au`;6gu-p?s^)6N=&Mvp#&s z*R;C)i!;15*F8@D^;q()o>WlQP|_>xeuVKj_T^?Of#1V-Y0tO~y16oNY#I-kG?Y5Cr2C)z<*#%Ud zuY)W<27M+THG-W2TxmW91a+@r2aqlVy~gl_3RsRe=}fK{nuU7p(jpQtLq@Pr{=>qY zwcEAM71oy5ud!=BA8Z0cdPL4ykhqCra4RVgD`DajI}l9=Qe_1>tmHcU@sO7h|ICt^ zacKFhu4fY~iz^9wk=GnEPlX-`oxnd^tEA(wu1(Qqr000L@`B|WelTu0#|&33I@6p` z?n0>+QCd(>RIxpZ3N+WGkB)%nR~p|x@v?gVd*B9LMTWD8Tr{i4#V__Ydnr>_xqPc9-+6yX4(p zA8>DEYbWcrF)rj@O!>x2Fx!y&b+GQSbn-;LE5bF3+~&ypgVq31N1IOFYg2968jer~Y zqHQ>ynXYH*_?ym5_rJAuL&p5s+S@mWuhH+aZ}7EWC2VeR&V2o2)6>YH?})+@JA$7R z^a)+73T7S|aQ{TVT6=#De^>RD)!HMv{zz@LR$CPw<6k$f=vV18aa9p!A!9vtnGR|I z+ZOn9s+;s;w9Q*^GbUp5wSD^D=T0p&Te{Rrx9m0M{pd%tSFUuM=imF@^UbbUJ8**} zcPkNcPYz4it)>?YHQPLQyQ?^t;Qpen;!FiiVjTr)d|E-s1EQ<~+yUhgk26{x(S$8Z z4AJi4OJi8-I@~NkAI6Jq_ix@H+z1rS)v_s`_GPD>Wp3E<0e8-ainr=Bxu9n-AdR_UcAq%Aur&h(;K~{5Gh-5bh zN|zwK0OsPBC{2M|xnvih zbsRfjz!Hf}qWUBlFd+7V?J_>8@au0eKj!D$|A%~wPvSHJ(JdE%mP9sVAWRY6BZnu0 zeN|w|H?k=hO~q0~#_e)47LLRaQVF$YJRB}~wWCc*^A;jlf#Ckuy&p}MLm?gclXw;- zaDsZkpOETD6aL^B!uJdRgZ0=mIBy}RQUnC_Z?dX|D3XE(aE66|*c7VBFg{NNf9UxO zL1Y)72wwOSz3Ay@5c14Uc|ukEggpH}H($A!PnP@N^ZPBvnNG669J#(i=0ZR)S6y;< zTp5Zk&O_oO4keBKfL%e#OG-||ngewoTdypXnG_7!({np#(|9EnmXzF~CAVD)`z2OR zBuZ8(6tc7Q?5?>~e_ad(kT$KQ1T4h6Qsm{Hnwbl@a|f5ye8KDAJy)yYOT+89MKKs- zv6l!veBjW%&sv9vKlluyhQM1GakJOJuCw*4xf#VXxqE3waX1!ASC`^R{rJjpJsDpj zRG?LTTH+UROSZJ&nAX+31^u{=zrtR%P1^~y0{JYECzP}XhzhCV1cX5p9?NhMrnnX$ zZo|VL;l;Wgs$}V!RGBE*^|3d-dzXXvJ^0{#!87M;!)C)ir=Cq~|rKPt8Do9quT9^`Tk8z2{~_^REsa0d$*`;DadCo;)G zC|*g#BH_8gvaLa{KVK{)GpC-&q@Y8g1v|22#lr2C=5YhjYs?3DDMFP`K!UPB0BIH> z*+R<2Gr5*gu6B?jnLa@#BU0DnIy;%K)_BlE4T;jLtakX$!&Rn4UJa{!C{tB<=mWDv z4_EoCboFplIdbX<0vQkAS;&6_A1c*Mh!{=6 zBNRHhaCS#4>`u)|dKLJf6Fbf>i0uX3C`2u<8qA2-{y`qTh%w2&{(%YcCxUK}sk<^8Fu^7LQC|Gr?&kIyna+90N4bPVqj9CaL z%nVjMoh#IWs`&zOU!YQ)T0(T~DC&Qw7{AY}iF8D{p+wS&UrFW5vE-V| zmri$ur=o)K!zi|q``sU&oelfFP6xb0gJG>X8xF>TFq@3Z5T_ zY~15X`OAsPorzrLzQ{~rPdlY1bBW#6($lr#%Uv^SJWwb`d;#BV{9>w^%K)opCgu0c zm*Z2K_S(wy?K4Mm5f>cEV!0*H=2q;vWv`0)>e{#Q9v%6{1Pi!AJ9j-;uVcfo^9Q=p^Tiz>R>+B2H>irkH(46sXZE z;3iuOP28w~qB}s`HOC(~?Kz*C^6k=r=U-#CV-CmSksJnm??TS=|15bTnVJ4CB$pHo zA06AdC)xiQM5N)cIcBr9mb~H2%&FFbt(o%O~mK>oq9Nd+^#`rvL@| zID{KU*E{V&stbbrOREhKXj@nKlgqcLvfXK$eeCghcXQngj%9=xYUm|m4>VvTfR}C% z0kt8{Meu3lafqG8J$3mU{44a`xY3Ko(4HY1$5pIB0scgTOuhlo2v#6Xi8w!y z%Xxw>MjI+zJ|bxdSAn((b{LzCe01u2^#3BS@`KE+y7$!M=eUBX8%H#@15uKg3)y$7 zfo3V{nm7wJt5s{9@}Xgf>*abTs1w{Sk8e0mq^prYk7!R@c5^J=7Dek}WX47Zg9B29 zl~P5dG@1v8+#U_hO}N?ao-s!Up^4Ym4m) zif&K*(7FP@-(DylVeh|`%fXq6fQt&vn8RxSeZWmZlV{F}s58g)7TeZo6E!vbGpg zZx0n7m~YOLiM9v~Z64t$0(F#@Mg|8caVYc=RGi##Acq3H9?^6(>dImh6v5|$wD%>h zLZR9-b-f6DZGz2N%jK{pzi2J)_GG5THC#6Mi0`8R6e?8V4s%owSvTNGI8gV)=E$=! zad;%c8mn-ma;Ecm%fEXc?KT(_S62R3vZ+&w-JZ19-#YbH+6P!2H|U>-hCny*Hk+y| zHn%NhD?d5)B>GLEIKuu`h23QbH0B2^w_9MD6H&JSJt9Y6VTXjya`1}tRt<>!W9f%U zB|@qki9`wnk{fJJ!+gP(VW`6>X&#s2_I=W=xIEfDcPEtnWr#B=iswzw&6BS71uNb&&(*F_c<{K2@~nARCYA~1evq;0owDFh;j|jUX$TiTME#Q<31pZ#8gI;fprM{W9~2DXH=)4{#jgV@jvg3W zIDTnCJAdzr;HKLYp>z#`eH@3QY3{~|69TkQ*~7}#g3Ku)LXSE{in>(}o4-tf3)lO# z6{x}$;5RZ$|9W>cYS;^MjZvbdD&!{|BID~3hBVkw!4&L#;790T7t|Mqv9F$KDS&G? zF5v1&`fK1NTrx;99a&TlIH_CJ1BWW0DsNp8PzTqxs|e79n2rr~K`--mRo-=I%ydEH35M&|eWd!}LX8EyZ8uTpttOGfi_%PP z9N(8xH_6_}fO?C%(WzTZE3R%iw-|^Q?KhYE!9>4U^|zd6(SR-Iy0W1S5L&m{K+M8% zTt!)1js;uh!^|JrTW%&=-$U9)EHGC?;V>arC8*}P=?%11gkG7)9`GBXDq{L|ptN3J z?h(fgN@jB0HNu0V?An~=UN)KS_+32m(J)n+>^8R8OJuikdTq^bSK$GM^K=^?|0=jC zgQl*7rV4aD>|#Qf;g)d(Ig^KwjPzji%T2OSWaE$_EJorXh_N-pIhjSty^$!a+UO0t z+{5{O?b7iD_1^OuTqJmXefHNl%LuVvrxdMYD@zt$*G&azJ^`*>qBuKnwi;I~A;~BX zIc6DB#2@99QJviHPxBA!O0bLShubF9i@`Ca9QZ^4V1vMOw{k&wQQ`rp9{rojC56{`gR?c=ZrjMUjfC4h#Aq#3h8(Z!Dr{Wzuy)BXJCX{5 zl4#O?f|+d-7h@`=1_8cErka;kNPJNDEirX$?fnMoMrdzKJbj;z?V}7nKnTGK`FGOd zAF>#v@DyQFcm%g$`7i?O>d}Oz-py$(+H#$}7cI+@!ig)H;noCUx`{;xYzT-ov>~7l zBR*OtmQWfZgqt&~*onH+&FKgBaUS5W`1gr7oyUGLzUqJx9}2pPMxqCF z!z6>y-mSnrj#x9nph3~pdPYlR_GA)TIvClXbj!i_!u*x=?7nMxpND)C+BthJ63?Y3 zQn`2puh|Y=OC~j4){^e1?AE?Vx9fXi>OMUgq1$gi$WmcoPDjHjcJTI`I7bNqL?jym zPjri9LxR3+k!I*k9MVIF9Iz?P(C--ZgT!G`4<#8w#kWW@#EgozN-tCqRc)PKsQ-xp zS_sugQERKHt484$48uu~xmcN88A6yh8Pa`W#X=R)T0}@NktR$LbdeQu0mag#sfIrX zyO}~x8Kq*?^ATw#S1;y^ntI2~p}MRqF~1t~_rFEN{uSswAX|@ zwas~pjfLHHt239Jl<3^0vqmIsqAUgm>IQk~3EX|*ae;s@AnzmO4F7_!fcL~O@Cn?7 zKvICXL?|Z+H#8t@rJq$aTC zwY7E+KU^&XIZ4M7=)Z<7lXZ`U23*0i8EQbu;YFQM?q)JpEAJN7 zLV@a|DA?Su#jF`Xb-XslnJBX=QMXasSQF4v5Kc~)sLzy~+(j zfz}TV-)Xc`sEqz$F;_9E;RlG;X#-^ z%1x6+VSxk)BL%tw@LFJQi4&7f`D zLfSvlgAi;dU4_{IbB~!FM< zjrPw0hmnftUqrN56Yb>@C}|!8NL=NM_jY6dmIsaRyl6*{j&*Mx4Zewg&ZxYkZg$7J z$JLVpmB$4IH4rkPk_3h=G*iS7gVMv`WH438-v&38N{8yhSh;+I=rMoT<$5^bWoQnv z7q#_O_*C%7w}|h4cfigg->_D!pr=$9IVk!H&UlESGK6E!<#|w8(UPx zX$zUcDXNwy4khgm%mT83o5RhL5EB79fHQY5Ll!ZEd&5FtZR=DOOUZ4^)TXEQOl9&s z)d!qLRy*utGlzWrZ*@9-n>|+Zc$TVVH96xpU4>1)u!DLD8wWbT281^5XUo)&wP}~J^baBT-Q}6XwAUkAXg@txZxmZFv z?~-d?FDIe2^v=5HvJ*RSdi8Ho5*ReN1TzuwASQY-4}~ZjK3gPUAU+lGfxzt&(E$hr z?s`52ROU~4jHfP?WNSZm(dW2ew*wrZYrZ&o=D9Oxp1b=!$41JhtPR{95`doD*1j38A7X4tSj=lTX%yyLw$BE1}q?bb-pnBfgBtMK-gfWb!`6*) z9F!F#_alL`VV0&fs#2BWMsRM))zL!pU-=4KJn>WwFER`NGMJ}TY-IEM5Mg;=9>l0*;9%F_CYt>Sq`lp8r)3#9EiVJN z0@6so@F<|@cX0Mibdm@*44{w-m5K~H3X8qC4RRy&P7qXPtayf+QHHEjZP92f4&UXDEZbCqrGg!~#`D3zN;>~R)du>Cg#kSV8%x1|5mH_=1Ol72E!h^c zRvD@&`nQF&W_7lSNOICr-~)Ol=TmGHnSI4}()KZlJ!@lk*=?t->;PkT+3cs8_n_~Y zk3MtK%H)Fw4>}Isz~gNP5B~Hs2cKb0#_qGT>9cn0{p>!#>qf1!R`}ulLgik1F~jaV zQ91GQlV?t{d-^{(a}v>nzj{x#Qu*aiRzCU1c%HAEs9Zc#UFQ4nyX^PTuN_zcmNHJu zBBA*!VA|ki0y$Kp`6kF^{0a>OddK78dD1D|1_Ps`O8#CPKfq9`HRic)jX$w3Nc*a+ zwL2TLCxg{k67aj}t-s_yIbxC#WQH6ZKR18f<-u zTK>^j7bbV_o-Di?JAg#Izhcip8X<6`DR^JP4<~}K9q@5TM@DKv?jWGS(;EXo8WPei zlEbNj;lUq{Z1Smvluk@7di~sFnN=qy%9RO!Fc?U)d)yw?CwqK0=HF3bdU2w{0IED0 zFZ)7)AQI8q{ISDFm~P!OHMfgdci+D&U%ajKo?oii0V5UlFn@NR&a89Q>}=5IxBfEn zaz&U+vbjTv|90evP(vXRW(UNHV%)%zx3EhkaxH-P0DFF&l}81Mv5>c$*ZNmyDm#xJ z-AS{|)3d(n9?C}xxnTlMfOzQDY6_BV*P{=<`N3#CeB0kH+{16dLx0`42R9Nm5yuRP z?LMwHws5O1G4OD$LTb!W2evU|8q$LkKcj~I%gZBPQ}DZj<;=9IG0SC@FxotiT^c%M zojJ89H)35gRplhoQqo+F4sotXA}bo?Dzbkx@Ia!MBIG`po^p#zi@BTP5pns5#TSp= z(KjPE8S6%f>lBkT1K+3JSWHEXxllD5p09|TA;&Fpeklscu8I#JdS;-egbzJDJ{-`s zVVdx7Z%QHLcO^STfH{WM|>5o57H+$%=8Xn$7 z-*FmkhF7|!i}@il*&MBPVMu7eL<%inVbH)G@|;Eyv+o1~YR6reva>h9WAj zq4n^ZzGd568je()N%%$L9U@WutfuUF_>7LMBgx(2OgVY`d!e#oyOXtkcT<<_)nq19 zt7Nm#2?KM5P2C%c|7k`qXS1=)nT)N>){?u^GZFoE>ToiUJhg2v9ggaIXJ!sW@PG1L z+YUGN_>c0prSzGM9aaH;%=8dtMCuvx?jpl|fqQd6^(`T#f(`#e_nipFpxQvc;MPMf zM3nBm5rJ)8x56@@K+TLFQfwezoB&|)z@tiP&|Q$i3kLBH(ELOs62k|$fYjq1iq7k= z<9?bGA;OWk??G!ggg4j$lG+s;tZWo8M$UYiOlhep-2r@}dR<2{i#44{EZ#G(EGHoln+6^ua4m1a_)ZlN)HAO_aYR)6+S=sd zsx0}bnr_#qsGCZ;?9s@>2M#=3zo+f7M#7>x#5ak)d}+`Zuq)tJutb20x4ADLnaWJn zxs%Ow_DiEZ(#h`zXx+G$WoI^bYpfpX*GN6v_iMB|@8;f(R{EChyU1y>P_dE7jdfEV z@x;Q(#Wi9;@(e-fC&?d#njFB$(j@e#19vEBYvBcE_r6kZHrr5&ZS=#_q zovw4tA&bsg&Tc+|U9Do}90IDz&|m_H8c;`sajdd< zBjc1E*~0uv!_m4|2|SnImCx@wNDm*NLW;5Ppp>xFjbch{Ht!54Y@do~m68_l%E+A{ z$^LLMA=#8bJfO!i^XXD1s@dkNpI#^ufK9hCofDzztmr0 zYp{aVpuL9#B$BT|JTW}F;M;}RNy?-LUy=4Y)IKnpi>G$mSnuW;Y{7j2HiLTy-^ku| zSC;ePy&jlMuYahgH{f{2>}o_t@V0q>>Ypf?EJ#BxQspx?t!pb&VoEp zE&SfZ?&Y()Q~VqMwA_wF+J9qyZDcHhmM2j{!EZ%emf;>gw}^%22j5;n5|auNMqolz zNI(_vemE2Xz5}0YK2ajpD1!<)i`c^A1bc{ei|LddglY-)klx^9ewU_V`O*h`6%)gZ z7aQRP8X=Xrf-YvaI&F$qmTfV=9q3w4kL(Y`f%7GMBdJ0#>JNC3)5C7FJKfChLNuK{ zBspDSmt>V9$bV5wC@!Sb@c8f^&{koq-5qo|;S&d!XNSw}Q(_yT3QjS&q5GIqwmKbH zUC@Ds?Jk?-wo%p&Kzy;?T0zTO{VI^G06J=uz47RMF&jY6tdd6#NQ&xJRHy9sdSuBC zcGoG{P@gO83#6SPr%krIoaGo){H7EQ-!2>>Dh@OYMahGauF~j~HH@t$)0iQ!lDyn0 zDRP7TGQzEFg$#hrJ=Ol7@uyPVYb*TH+~S?}+4REV-P5zshdt0}JfJIgo-E0*ugC4iy_9DedAv!$~PW!{P z;mhm%8tx&w!PoUFnmEr>AsDTKDi$r`-trWC34JUBUDW0XZGitG>lHzE;xj&)aF)mN zs$|n@#P4>lIo)1|!-f4F@VR19mxK=>ccrtHSQZI<0?p}s{9E_>wRlDeu~m;d zH)6-oib%hLm~mT^_ep7xV_lPY271Nr%kRkNcO2M}%k8keaz|5p#p2@LyN@28oSZ!R z__4jO+%q|M=36;j7dL(8Y~?IVU3Pjq4fX{p@c%@$m0G@%MHK z@+*?`dR&lVPfB(#J-hhhNlD_Ll7uU}XJ$Sz^9kdOBy*84dzQH4jj0hf!Za5aDYV;+ ztI2b;FNAP{+8Btwi>wX92VgFWkwl`BNc6wE-pN(;M2@ZG5_%<`Q zX4)cX6jmp1740K5nVj3vVl36{h%@s)jx{&J+uFZ2Xe+Z*TWw|xIoPbLW9@$bwv86& z12pN7cW?-r24oB$2)hgx=O*WT<6*d9Fr2dMD=V;Ha?7u=2lw;!6NPCDcn*YkV?s9+ z=NA!X&h4_4JCgY7h|d?%QBv*OIV9yoLLuz=yTMpvE7O8xR2Gz*ycMRK3h@G9ovA%& z3mQTV;wi(?oDO}WC>=$CbF1hJmEl5f5aA6fM1Ehq9|ZVr^a2&*dwPdg$sefyI34i~ zvLf^UF3*1g2RJg9=|=nLJ}9>6KI1O%>C3o@pgTtT0PW-EJ~W5T$5)KD1F43~45I%d z?Vv7G*C`zWEb*vf1%E~zx@a%QMWNwAipIC^w-_2^L)K5Q>|4>4{SF&eIQNh^p!&S?>XUw=U z*v706zfY(sVm3!tia-qG3*LYU6YG8WJ(4uddZ||<-!>Bs}NNdF`EgCa*rH*!mbLldp#H6KYeb=7}{v#^&j@p}8Yv zQ!o#oH{&$hSTGF%oo*WjL7a3OiybLf;%5LKf=xwsmN%59uWu-6I7j4=FV=xc5BVv% zsm#HtIX(bGa=D>~E!QqTQD@kuwM#t4h9>jVc2k+7^f1C5R7RtK~WN^G1 zV-fSyapR62)UMd~DX~zyNo$ zq2$p$!4r!JZe{BY0kL9?f)OWki}LtBhLRQ{2eniDN7apcp-W4hv%d#NN=LaS*F#M4 z=m|91WVk9!F~y%Zu+ zL+psYdJUtoYpHxx7BVOv*N4M7#?r2@EA%7sTF0xdnHSi~z@o^;-g z)>X!cf@W>53yc8jB7SaI7a~ZEU8;$5?VD;c`$e|QAfd-0h{IZ_TY=;P zqj(uE#|XOI2)}|$H+=HKmE6Y=98f)$u{zRnQr*zfUMEQrR?_ns3W zcN*1fUEnH&TDViDMsIvU0>|?!3<* zpy6EnePBc=^=aj8+P-}n{{KMnxui0onB_ChjMt~>`EYh|X(4Bg2Aq0Xa`~XB>R*d9 zUo<*BjsNw1G5Tt(|1Eg+D#yRe*+e4%h}E2e7N z;n(TO(<@Z z&mG%_5FcppRXA9{4F_IxaA1KNj)(k25X6eicRz1qY9>+CtC>h7sAa>YaJI-Ccl#5L z*v{xbpVh-90Zq|%xz%(m1?cr~(BqE>vdOy>e%MRhg^Vw7==F01QbFy47MGth!*)?1 z&i_HnD8JlGZXNsiXJ1MKp@dgI1RYa{o?`WqfX8iU#N2;4&- zwLE3HYWXDA7N;|?+NwlMXxG8*6;|&>;TBB05?9P$P#9dK%d!I-avYO4w;-&*p@%xSl|kORx= zwl7&FSm9->4c^w0)hhWEyVHuKUH-tU;U5i}3zI%N8zlN`o3gsX{%pX3oMO!C)qKI% z1u;-oo7HBsf%3cTIKE9;i0qXFyRi`>06Ux^ORK2NneYVa?nK z>yrokQ-S+_ptWihC3?f?KxhMFK0@(=({L~ zY#lBO#wKZXtFx>ITiUGmUv|yOyO5dZPQ&V#zbk$r6 zgv$^bD)brDO|(&1Fgx^)Ycj}6Hf$qo7e=nAn`8r6UdLGSGYL0QJ;a0IOd_7EX$%23 zE}CN_#Jz@ix=BV(46hg>^Tj&)fOCqho-|OySDX3+lt?iK10fP|PpFrUF0Sw}Is`d+ zyg$Ud6AgMl^ksCW!50VghCIjcN_KD}B9Kjq2&n@@G_zO(Hb`d2^>qCXyWQrMSX8`$ ztGwV8*)ukq7M2)3Zq(o)@34gwC%s#kI5`DBMuPWT#0VKs_(PNNT_6U~_j$Z0-04vcotD)ia!Cr9 zB&=@nLN6l5I8pJ&_MZq*obm9j%SrFqaSVJi9R61%4@gELy-2K_jD`x|d$lzdsg1sA z3an4@IFw7*;Ts4p3ZPuPL)ca@W5N4L1f>#7yPH+X-)6L(k0&dt(ygXHxU8Tc&od?0C7A}}@!)$fI-p~uJc)00x|CwN5KT}E- z_J&J^W;nj1P#a|45Nr54Q%TbeA#QBgbXQ2bh3zhWhF zj@h*!;Q-cA4e$-1qrNoUV9YuEE$}IzAqbo?%i+EhMTBk0?a#eV(Ipv-r_EOLtk+iC z*fhRiP>m#VL636PMCT`2SV7>jY1zVB%))mOyQm6`J^Cg07U*%{=uKPJq%ofYsh+HUE5ouJ+IW-o20dd>PyjK!!>9ZeM@XYe7rII;Ly{A{PfyrJ-mB&Q8K8 zA{z^)q)pqH@vYnM^w#^GWq{p}>izWP9_Zb$%ntTak}L%PB{Tg=D2{2&s-=bU&0_N- zBYq=4Vb&q)TmS757m=G|_4Tj!NYFF);tKi@BkyH`jp0*5B7vAGvD;`5G>csz6shVO z$0?c=PAdQ5Qmsw6M3Zd+PShqxnahx)UQ`y8^npl7T(ebULS$}`GaUUU4l|LOL{NFXtW zJWp-yx^U-NhnH$43q1Ry@JmYPQxn{)Cle;eqXZ-f9MPk0JYC`8^EX2mq^@vMGUkx- zvN$k{0x|#~o|?_9R)*dS3;{vr7Ag!f6TDcBdclM|?}<2)Fo+?Ms!yq%PUIzc}36?X?a4U8NZ6>zlf} zWq&u8{-XUIt8x4Oj<(?z-5tnkq$iE>@aa9+L!%zLHlDf4QGnn82o-?W3=rlAOHX*_ zBAk1pbL}(o!F>ni`eVPX%#`<)XOtpmLD#cWQ~Rc-vN%Br402-*uaEmMT7+4|03o7$)A`=-dL69+D*$zQ;ML+~{z9uZ_|?XzaA5Mk&*Z^AQpUPIIm#i%SS zMxZwusAzHiz=iHFLdY#w2Pc2qJ-3CwV!e2qPc4>aXOGR!er1U3Amhn^|dorV3U z$`dp7s$QC9)^D)c+h+0Ce{u-xaBWW}1s;j^^b23GGPFyAU2YNp4U|#TgrOMdh|w5? zXAy=L=RZVf9~?>dF*r#=Z0D|fjf!o!9L!z5OifZb=qyLaNb}IK351M&g}d-Y0DCNpmwWyWT01qpO^=mjQTAVMuK+Frm zU&&XJz@YX4dHPPvIa)17+Xfz!P#SV&9rov5R>>C#c{BrY60-oMgwTj_&qR_ojeXr* zC=*~R@dPr_J(4e(Wo)IqMa>4{$(S?dhScVc**%gs2`$7&Id(a#C1d6Mua;BAHoLFX zE~b7e=bd;RNu3T3)``O8`R_57;1rz`lO$frLYK@2(O z2fDf!{t!s>p8(&r7Zd?=1H5)ZWWg4|FY=l=SX^8VzLa?74g}rG!+6JrwpTh0xpekT;ao{AtA-4!P8bk__%iKB#2y>718t zN&B@d-c+kW-yKP&&~46%2)=Q**PVq34*m?gqsuzrmE7>s;`|Z-LCEheBsGEN0u~Kn z^bkcY-Oj!Po&Mjn^-dcnYUHV>Sm(9f{hokBMtrg-;BrS}P?HcJ+XXDsZ-K)a!d{KpVn8(k zHp##y*~ z(bH=@ta(cfMYa9N($XUxdT0-^N4M2muodHGe52nPLXn#5=yU8mPM#8{ZEfsVvaJwl z#iWy}rnw-21n{+hS*BPuO7Si-DZwdpz@k7hq-b04D*x$CzJ?ZXzRBm){NaC2mixc< zggt~XnkOX5X?Ogy(`Wk$gTI1|Onl`z@%Cjs&F^;xdfL3tRZfQF9s+P|QqLKbY(6X- z!;XJ3UW&y^aTY7a@iao8hjU!S?$|KPl%%SG;J{Jgb!?{luUYTGyMvHPVEtajJae@a z>2i>BlcZPW_MC!W%(bw+n$VKa7n)R!17I~Ifkq$7izQ@&m##LOur_Q!iCmwZUGHBL zWunz2v)Fj731k&pp-3BxxbrCJ5u6mb76p?+$^z)Y#7;weTd%nojD|FSa0*y@Z7#Q7 z%0z=M8TwJc?1f{iy&jZDR@oJdW;(NKW}=4Z8NWN?3;KI90Ss_GsNm5lPIm|qXSm6X z3&}PEq?G}5+VCDQ{bV>SbqyvK{0LetoD}-&J)H~$!nV>y9X80y1Uo@I+$P5eVJXG# z#L*vu*8*|_uWnUY7v9PntAZs0f^yG1yG7jbF!v|lmE{o#I0Lo_a{s(45j8-4EyznU z{?|xfYxcwFEI{H=0sVt8Kw;UdT^srW@y6`o4M4#0sD8x>Z}KS4M64hVv_%|rl}DYB z0*xRu$gYmV631n?I$y=#@d|!!e+NCDc<0FLZk(=GAKG+5+=O8^&Ip2wkulCi*svgf zl#R&6mZ5waReX?Dnq+y%ofJh#Dbv7A54Jb5CQVI6@&Eoq)lT&gb}Yy3C&<&Y)qAUF z*C}(-Ajc8`l0nmWlYb)`y-JE}b00vZb{+CeO$}zMFpUK{+k8#fu}wKqWcucw|0E}B zNHRgX#sH#jD4et1UtRCHy#KYsX4Yz}y>(zpbvh;uruin&!D&Pt!S=+t7=rg5_{ir6 zuLkMH8YVp}V+g=30~U?_ls)LV;R)KOd`{KrLmnb}>OU{^l7A|+l>P7KZscCDAj>3M zb9=q+&NU8CtI*@Mcxxw8_<){+>k8O#rgePpt}i3GP_`_M}}%>qC^f4(&J(6 zVf0Ng1&sfe9RRJyGS%{$c_T(iNM@96HL2v}nVSBToKxT$74>*@PtZ1v!NS36;ZM`H zko(4sT>pB`8;!;zk$*wA;?XGUV)nEslyp%|r!Pi59gn-SPQFemzU_6bcYsK9u}0s) z{rpjk{|lgD{PrOGxBt39>-%p<*YH^ys^Lp&|pqm9|bAR5uc<~bHmASBs#~%5N zjdiR${Nx^c%=~9pKJ$APF6i(0&&8igKUL{6hg;5=wYX#Ng2XRTm^@PS87 zA-t`6y|J=ITcQ3mW3lM0CEJdveyVcb4H74~HG)S(RItdEu&Y{96G|)?^5z0=mdx&a zfOR-fyE_bwFT||pGLe9`mr&Y==OL9%s42H9pCYMfZ*N;qndFIWD}y~$#9Nx9)6s!n{BJ^Vol)(bd2OE@}+zhT2o<)gs0DQi>_*;(Re2c1|OcA;8ZOgxdAGZsGuZwvcqrm(q3l z10Rs<>C(J2S?I0-YW~t9&JVbwp)KI^QTI*uFtkzd0fHW$H00dunFcrm_%y9a_~QKB zhHIbU*<5YH8biihN3nWk?(qDi>sT!mFJzXNfwDX8hUzT~C_BJJ#1YHDd| z3JuiBI4tC$t2p-w9@wJUz(jd4F4#<*k!h~C+t-klp05EoGy`({?F?YR zzT8z(>E*xW_|FZIZeant5@uYc4C8(O^K%c(mFMQ?-;U?q?(o~g?n7?;@fUV1T=PuqVAbxm9L5R8^Okc!OVR^? zFrg!u9-i%h5PA47f*8<=I!n-D+`s7zmf~Y{lQwkou91H2fk`H zknja3@j01w)hOG5#Z=s-0A=5 z+FBQr1cfcp_ZQfIhkn=%Ekg;m$tI{62g7Q%>edz(dz0RQ+jmq)6=T{kw;Nm=z)8Vy z4RFQ7lk38e6~Aj?^*5&Us9l=MeweNGSD$yxXQF8dxx!LPS~^nM={VK@Yv<0= zXHH3lg;aJ18X2Nj!?=Pfady~&!{oVR*n{vx<=Qy{6C>`k(b{M<9C2Q+dR-9UE-Q=I z7nO~6!VxF<4pONgp9<1?=yV>UJ!k>JUVETV<&oB;-G>f?6KSyakSf5HiF3Fa%2Pww zG~mSQ1S*C<^^$rViW9Jp*ElBIwQJuQ$wv4|iWTp7xf_Hp|QpM?adYB#)EH07ISy2*1z=@*qVZt z(mEz6d~hrvCnOj{I3pN$4RQdYyXy5gd<@stmX~R@vE@#^-qAZCWSnQAzWz7%m+a@z zYY)mGFB6h`!8<^y2OVAn99T;$b3dTr$@iBR7j=E{sUK?A^yWqW*#C9$5mr4=&bt?z zdae26{GB_#Y1Ntud}hp^@sB^-5%#@@H%i7TOa=;uBf_+LyVd98l~ zkF0v-$`z)!Z~JmQ{0YT*`n0PO5Ap2^xBWXxM~{|{@;wQ>cj(|8!fS~0fCzx$qA=;O zA!&g+37xr!cQc}1V3e|OB0&lBsnf}>q6^+H3qjgV?UT@`GRFXqD1b-=$nku zK;5+2kpf4`5F^b71uSyK!W0Pq>`h^WBEkSUVE*?>=5gR6M~W zwXr+@i4b9@vd0BWg7b6a-Hq`@+P_|}7N^{PPc>exzjN%)k-bG6az*HKr9tQ&wo!G= z7h{C!(r^vu6pT1#A8$npjNWe1A!WR^Bj)7v5MRX|keJS^yzme5kp zt1Yul+JF*(D&UkwHUrLg?PT4z zmYQ%UC)q(crp>KnLT%CLb^2BSKb-TG#^>@am1$dL`f_kC6P!B}i%GT8VJPGt50 zQt*f3>BGB=)<=}fmuY{a&!p?%_)TOvC5AEtz8Pn|>kVtJH|Sj*$yK0NyUJGkJs5q2 zd`RE%aBuYy;lM`11Np*I5p0!Xptc`)LveSgLItfM8nz9^=UOpMrJ-sn>-+3WgR+Ro zf&-xrkC(LoB-3o2@JzGybAtk3ZGMCcOc@qy@HV6)qI9oico+dRo>0GdY7NdW(@F)W z3R%G^%DU(<`naBa@D=CQhC&Zw|Lmi4is!^`lHMcLKsu8y;f{`!v1d{_te595# zx<%$=%JNe})loB9keN;gFy&BAIS^$ukosU8|02<5UQ0ylU;Co1au^i5uYAbVQkCqlvIP>Mnm&_`b45>;jOI89s zrntl{NAs`u$K(6w0y}mDesl9cenHx^N79$_`K2c}jv*Zl|H}S^J&js2IO-^C$u!6f z1t5_#3z-{=*qOySdgUPRh9v~hl_3nkNFgH^P5=<|T2V%vAp$2`NJ#f}wGL2sm$mkG z-HJ#$m-UcMl7H9X_+44*|4Hkq&o!+l-*C2iGF8#`9;lp*+gRw$|9IuiA@<3`?~-I$ zdg>{9{F*Z$y+^`dVE?B+^{J1^A7rIBL@yut{FOJHv)L9t^3X#cS>UHS4s)=kWcnf{ z_6&}+H(1_odB0`d@*7+!FlJ>2Er%p(D7?7DJ)Q~@=b5SRQPvUi>xlB2}jmi9w)8la-poiuJB9*N4@TAl0b=LEU%CS{# zh-^5vLf5a+Lp?_yRO!;OWxDNm>B0EE4FNwBxbk}X?AUI)Y4`h`-lW~?PehXA-r9@C zw+=YH2`Z46YESS_%@0ml?MbimVWWmkpRQBGMeXJ_l#}3}iVyI5<(SQW>eQ)+4e^aa zg9*AMPRd&-7l@`nUMJTX@=he3Eg>&Ra6Vdu%&zoS8mVMCQ@XDN1n-pV+8Sh;$(h3k zR&Gc1Msdeqgn_*14FAQBV!4ycE$4DQe=-o0T_nCUXMQ=I`Px} zADsK#Ie#eRyXQCW@r6SEFFNGX(Yge1SBXDNA4RT$%gLk^OU3P}ls%Twz{iUtoy5o> z*b~YU3RQ#1wFw0eC6h-=N!f3Ok5h30?I5C2!T!R#MK0l5LcVpccimgUzjqz!JBrqz zq#`&k$Cx|l@=0hB;2@=3j;#%D<99!d^r4Cr^0*{-NcINYvNsvEM*PXjXLFvX(K_>DsJp_FJA1z`-Kdda7e%p7r_H?h#&y}7Mv6I*CkS$I;=eQb@+RpE_sL6N_EKvpjFuU|?O5^Lh)HG0`!H?9$Z z;NQT*nod!12$gHM6{xa8$_*-NS-b{jQLI*rh57mUZJrgLgB^i#Le*mYLrVbt$LQN4 zdlt?L?Y%|T$qimG%d`9^m%C^@V>m|FV3`!tV6HsP6E!iRc(P(RI|Wqh8N{V zR{lLvU!c}njKa$sQI1v>fe9I?3UwV@RNpAl_x~lj*s2A5aJtJNenCZ8q}Aj9IKNkk z(liN`PnWeJfDpq6VVQ(nO)itM476Rw%&=}|bv1M1f7A9R@R4NYonXE^BJ#c?@>DAC zlrnTnsjMp1kzHqZ9eq@Hs;jy=ilXUmr0xc63XI)AHUpSngRvK|*UQ+_*kjLZ53}Q=G&A-rw6ERCp8xk=L}o-Pr7HIK+bZRuRAjvGUEll8 z|JVCHij#tmTKQr6{ZdC;tJl{>cpT&o^oc~k7Lsl$D4BV`mn8AIkByi9niqDpz_&|lxEp=qr=fEj| zlBJMU=sLo*UzB1E91%(r-Uo0ztbByK_&uJ0{|)@vixS5(HEu<#&FH#MuM2nrd%CPq zp~-WpBAv;_)VYV@zQ9dbB*Ij3jiv6R!n=8@~Wd@fqQ^0wvL z@uEEhkHp2L$CepuH7Cd7`PPwm*sn|$8^KuU#2h@1&gY$O=9!s|M`z|d`0n#ghdqAv ztyh1mz~3y&_XJdt>F_{2&qe&|>!!ll*slI{A!loZ%)gzRq7jFoaR& z!o~_hAfl3>m`WqI%|S+5JQ{eo@POYL#uOA+Z9{rT{$J{$)z#Kb{Ocj)iC9&KWcUu( z9FVO_VX5%dbd0onOb)~TN^mzZ$-ez|QTx==Ft`?4MNLZ4woGkr_ilp!v9;b!@IbbP zMtZ-xv9a2v_FKR=Li1z@6R2Yp?1zdP$om7}AK+y5ej|;cW9~O~6v>xLjk4*m4KNI( zDdUhpi{gQ7yHcCAjBaBMV@a;AQmgQ*w9I`bt_}knLM9MM=)$~VF+x^0^%ssauCP&m zg;Pf;Y6Q1hYJ@~~HAVuzp{M9>?9eoqNmsi)zT<2Goijw2&zZD+j5O z#LbYUXe=C9#$n>x#Ob$l?b~PsHoT{Rv-ILMwcXy_L`4K{)Vq1@n&=LmnP%I?{d`!5 zh6x9H7!Lr!wa>q+vn#&SdKW)Nu^;iBn|r&8$rr9Xspx%iI8Q)$fO2UXS>3rBw}-q;@t+#S`6hsHdC3{;qCh@e~j zF;~rFzRKsGXoKu*^oJ(9t#|0fYpp?l=zPbR>)*lnnZKp468(!}f#~0*;b(j-NIr#S z;I1V4I|%Ow$m#kxg2&%Ndo>Q)j}uFRt_-P*1P|js!C^pOQ6(rdluNC;BpINsq-Me^ zMu}EHs`yMT@3P+q1+RD8?nsu@>Nrx5ov8W|cE~aVI*QvJ*5<;|-ak%;oc1qOj>iHM z^*{)<*O|L^GU{~wlmj&*CJyHhFGJk}{7uQ0b^Xq0hl4&@+Y;P}7YL4U4V$}@sYTNGtZin? zb+m_@-!5l2Hag~J72afT7ba*>*5+>8+cEw74Y1~A9-a~1h)2e z_a&=rOofkuXxE36fLEynB%RS9JibP$ zr5GFzBzjS=$svy68JNSn{nl$|CVBNGq5{1mzyV7^+w!%p%)D7tVqy(W62;ka zk_e^{KNu67QJ9~9jdke5I-G(<2ktOy(IoDjH*^LOBnAy#=GpF0c3>lG8t>Ud9rriC z>FvDF`_2E&_fR5USMfidD6X7cDQ<`eT%ZH2iE!LTaiYAFhjmfWO=3-5Xu4=~S zGO+O$SCYbEhP=-U;+=4d60KWY1|lQ!JS18RwSD&r%sWC#g^7@g7U^?J^NGSE7~MS` z!pK|5@BJg%McnY~MAY##3<8v*9^Z+p6Q>gjdIn*b2dAK<#-JyEW%dd}vDle7!)unG zRF=mk&rIx6Cp8VxFS+?_c0QMa8YSj{%6!q8N-LAna*QZsoRax;l{AaE62hfPjFryKS9PMyn6JJ?-BVTV6|wSEy@s%_zc z^^CLb)jwzdiG3Qo&JTJT7|YWLTz?39&+BYY(rTfQ2xtRf{^Jb%xC(3Evm}!AN)|b!n;|E{1ZR z`bs3{|5*J}+I_6>^GCe?XEQmL3M4WgEJezZ=j*SlXOriXzce2!gg!iVwG@n;9eXI` z^JX$$Ur27gyXsJ54(ZaOmod-MCE1B;ZI$PjfBSd{C24-5a>yS9W$O5POjbfc|DnoM zVak3!7Ai;IPuW2}r(JlokayM*57w@) z^1xuhQ!L-1pmG~qj3BlejIBZXIOZM?rfg9{6aUA!2b^vx`FVH*Vg*Gm%Piqo}^kzatQIn=z;`Sb%T~8`m-gU+t~p$$Umd zcz8Jc0Z4OzG7N!YLAS1zC~X{-V05lRZ^oe^g7H!5)pjK1?*hf+rXMen?#=G92>ZVr zO$W|j2&Bt_fImRKvYU}W*N@9ec&X#Mn=0%8Q2lS+|PiVhH#^=cShRaL(UNi!QkQ_ivS=s}F1$G;$G`LU*kF~fq7 zf{MB>Sr2!9eRC5f>2*T%x%s$d1ik>4N$ZE(e)u@J!3SyFb?K`=>a<8`8knACW*U9C z3sJVSKtapcX{B{B6Dq>8x2%(axCbbuHtb;l&x#58x|kl;wvZKl3QA=c44Y^h$b?bu zaiAH(oD1m>h$=!MP5^+kiBw@@?ZVg9RCFKBYP-#SHBX&B{Z#K2As@un>wxnSDO_!` zPGHg0U$vb+jrc)vCU324>sx4F@CcHLqZIxzs%_qJAp%;P`~ub3Yz?>5=AO&ep1z4f zAN%)B59YTv5#hbk!}*6>(tCt+uufqM;H%^grlgh?4mR-+KH;)8OgIoEo3J=zj!Av! zM_pC+q%H|ngX|zRB%&k?$)lfe2H!SG(<)%|*1KBe*Gbw81X$bdmp|q9*~dLnK=N$4 z>G}6QrG6tIq|wibm{_)6O>bo?iaN#CH#9X}-4Vj)YbBISymCYGdgXK)b-Sb+54Bq2 zPr7s}`2Wl79hfo5NQ)VU0%7@=Uw(Oghu!GC*ro1^we$y=%e3vJ?NQqr=96c9!yti! zo5Vhq(gcmtT`<_T%Z*jK zwEVpz^W}6dA2c^ zNtWjyzCKx<9&Z-L)VSa2iYoDmrQ(rd?bL+d8*-Ft7v?MWR4Agx@5$Q(;ZW&F=}J20 z2VAUA0_I?TZd^apzs^3zQ_g7zAmWxEcx3j&HUkI|_8J9YP+)%IzTA;8S$3ICl1}G( zzg*drI_-exoptuf+!4QL$K!XN&RyEv+-!FKP5T0B>tbHS+;!PKXbrG>aP3j5k+3jx zi<`JRYi-|t)h2H42>|vB=8{ds7~-CO&xQ7Fx*g3iU*}{uq@V}rkT{=>c$Q-@*^;Li z^-KYbRiF$4;S2^q7MNGxj6*gY4n^+u`Ml(4L3Ab=@(`!F3G*SC2=eU)-q<-Q=I;R2 zeGVo#QFW=l-MJTk5Y8^4pO0n3h_us&)f7-?ypaq9yd+RbIi z>^P+1;#7gG0|$w|59nK&11ergEhv$v@yMX7t4A8(#8jnWDCA$asmGMNzp4KF` zI9{2&lu-hag6v2|V+ltpBDn+Q^P?F_5qWa5;Vm(GjrC{)+u7mJ~(Nh;S(Ij2f>cim(bU_{lXgvtvip zmf7UP zQ)>bxr;MEqWjCVa${hLV{S(`ShV&b`591nE7Fb3G4wh7A9OP(H;2vQuiLFd(tjKOz z#zA5O=ofY^gi)LX6p;pqKg8qonMpr-a|q7}N#ICwfDQ<~aNS$v6k1nTbR&?|E7D;C%v>?YJ2<=UHAdk~$=$ z0Z4pQgoe^brXUfVLq~|kKx-lPLxKP_ZsUCK8%z419MBswK5~;FLg-v zc<@BqoIjyYWcj87rwv;R;5oE8C^v+gKmV_pa3fR`Xo=_;q0l510U5raA}56pR`^_ zA<_^^y?Rzc18cG6t0sW3Z|68&2SXbr{fys;X!Jx%M zP|zowijdg#)P}`Ig)c=FUKV7;3_#Z|VTTKhl@9haZFt)Ez26V1>EmfNw2Kra#T!Tog>b4%-VA8=rtx4#{zdo`aG~MPCtYildoV z&qWYKjY3Xi!q90B_g%?+;2&uPo`6evGRy@ zFfIL!k7iq~tQz&+KQkd=jE{O^iSfiq0OChkc%eK#D?O2$&^Nqkd(&7F%pw6UjAAob z3mlk?ya!g8MY&m{`UK$r)^e|->!*HiIW$WZ1!jXoRbM}0-nyoeuciFa3D@Dnt_i?j z5WTN{j|cBkVjJ*FD}|xabcXjPiXDE-5<@Zzs4B|ZL0aa`bL^# z5zziJER@0uL>8TlKGR^@P3$J(-UQiRz%q1^##12Vy_}toC>-rX7^xv0q}aT({xv-J zzSCkIz+}8kYCXy^d^|N*j=gG&mFH5Wh0O)zDh9uzEJJ}ZIb8{#|b6O5M>2OiF?Z{Lcd1^8}550TO{}exFMXk1}F@9mg}2v8bd$; zh%JF98Bsa{N(EA&QE8DRT!wAgD znc%#VSOHVuOklV~56L1tXM!RKns^{$hHN>c*Yj}X7^VOdsDph|_v>{S6f6_)GURZA zw5H;W+=>xznt*!O#Fr*g@Cq2d10|XjbtYp z1A=+ne+>3d9~vGB#X2XZ+@U>V(zQ;DDak>sON@rG7qC+I6dJYc1hU5)Ubm&?(ffgK z2+YICJ;C$UX_7EgG&dw#8{;!EJTHcBCSooO)5NH~!NJL~La;Q4Ck2znSB2iP=(FBt z0&5bA@+&U)7rk1L3_pA<+X$6V!)R~q0)ju8I3pvoQ&EcqFgCb&$oy6 z1~rY2!`8NkH(ADj5xQ_q4f(0;NekhVA1l&Fe_1cQ+o%Hw`7?gACx?BEHmvEmTet7(Sz0j3sUr@b-+R# zj2jiw8#A?C+Go@#h-=iKt=@6W1iZ-L0K&@KZ^YnkM53&f?ln;Y-F&`!u%5|AY|M4( zz|jKbcNi?V5v^_Rv&N{jX4Pod!X`&;+g;R!zy`%}oBGt=k;5$NJd!RrXw8*|)*P24 zj3f%-MIByx3f+>Q^LvL==au9xHIHc&8X}^|#h6<9b^wbU^zb15NO(nhUk_rAgEcwW z%fzg?r*7n`q%8}V@SeftWrpv#E=TQU63=KzhX+*UO^sNZywr$!90z;3Px}F@Q}p1V zEhj57{$>TU2-sV!BE1&`;r^e(ZY+ z4|;RZF>G{f|3q3bj~G8Xhp8wwc@W^vT_oHNr8H_F$@2%k3_!NwaTL|D>GU_jQ}R`4 zUV{L`+H(%;Rk()-khU&0wPyf#L{p~m^Ku>5O#8uGm-pbH&8v6jpxw)Phdy>x_!}ZK z#ts{5^sphhe|W^UfIGK$w9I?f1v?CU-n2t4dkVtP(9AQ$MQ;sl8ceTgjOboCkpztg z4Ntps(8z%3gGOa=7EtkH(%wxPuF%#;akkMVkU4Y1PTAVn*urXtD|mQmnf7OdXS@mH z1f2%-fRGG){(%J3g{n%NI~5)3B29$R%$`w1pLCss+8EN>MV~CQGbHsHZC*Zr>FwLP zS)dt=ZD01ISdoLa>Zpy%tGJI^d4qjQavEQE6#IpMddnEn0M_>|KYrT-#;z~>88jcX z2DyANG)I&W5--?Q!U)`uY^@k=2&( zI%}USJHfI>NnQED8QxBmhD0LmOG;E(*7VH@SzP3!C`gvD#~q)Ui1UrBHH4b=H5OYxa|8q9ctP%33MEx zRI}dc0~Y__3{3DiWs+y0!VIj|2Drc|?m~(^?R)X^oR!CuB}w1<{AHB1VV2FvJ~`m* zoCt1~V+eAnA*)r*tU19C{fjYls5QeBR z?FX#?!Cc62{6n(ma{;Y?)Yx}Bqht{c@rHYjQ{37l*U1Fp0vQ-Q1!snNp>bWrDpX+- z0j@kmHQjHpXXt)hF2xvv*8RtfQ#>?VmL-d(4p^z?@zM2ElD#3YiDS7jT2Iim#=Xh{ zNx)F|ZF`4nAh(eoiLo+NQtF_ke_ejckC5K@y%D{=XXFOs*0&U!`(Tk`EGv#Chqrdn z2%<&aDaCr$T9=t=ok`GPNHV2(Qh6Umi%|XQo#DL=d2y7;Yg%U#*03#xJa0H;t%F7a zFLFkPSK7|b`uYLmMfW4wPtbbMKyiwPZf{v=MEn7w?qDD4Iv27`jxn*;#CjV&R3zn~ zYk&l@jutqdp$pw%%(%{lS_xo$d^6F8!s@ehcA(k~DM03ChI(h-ue#1PqEBXCU|oCt zp6$Q*4rtxH{03v&w{6ne!|^VcMitwPbP1XS|LA$oDqLP(U&jO6a7cqNtwXXyVjXgT zl-h{JC~iG+Me>`Yfjz6zJf3|!XTKjOhGaNko&c7Z7vwPa=Aad-cWnDE_puv1n0m?g z1{Tf81A`CY-kscPA$@3j?+BXD3^%vNkhnWy07vg;+!P@Udq!@+|LC6Fhd|>t%vi0< zPf&i)c=1l$K47#4>#ncsE9CD(hei$-EcN)=b82vN?WhxWaAp{~K6!Ua&7l*P-*spc z?PH=fud%+aZ_sREsMf&}ln=FGVSl_62b{DN(?V!wFCYMs?7sBLNuS6jO<^E0lZFz?eEjo&tq904<4NfRGSK(Dszb5y69@HfSgz<<+^l z(n2sPjjMBi(?b3LKfLf94p&c9RTT*1l*Zc4FOIUwBE+xb;jptarx9Oj-*;!*(Ayr{i0pcp~ch(8s7 z(Dv;pm$#@dH+d9~jt)VA-iU1lxDF)_Bawl7h!DU-sly6tXd?hA(QFu%vJl0ifzYQg z|6KXnLDqs+SBDcRwlNdbpN$I_i1A*yV90x-eO1J^FdYs82zR^{odlp_Ac6?tcVwc$ z85Su3qZ<%2qAJ_PacXh=BHg~Fa3UyG?p0gIAYz@GTqn7V3JulQ>B@CL2tqdCdaD3K zm0*!5lfF>Fs=~os;|hzewUEwEV5k@wgfd|YsR|X=Lkn;m$c-65nMGDpPpx*?DkiIa z8#+oVdYhWV6O0DPo6>II)^+8-#JGE59pL3TD!i^WlG~cgh&0A(HyYb+0V3jmbz~i0hoaFHFHEubaANB9+kzxPjo=5O|5QqX z^G@1eym@p3hdWzi{nJ@-!@Mq(%b(&Vm)s{3cu_2X)#g&IE2o9+JC(X zT5?|^{?LRpN$a2V_TOjU(`n(L(|0i%5IZ>XDM1y0Z5pAuI$@zqZ}UZO^b5v>{MpIe z$z*2Y(4hwpT@xU*I(gU+t=q|%X?}YD1=ogf;h~9aO2=v)wLg&R2tHOak!rwijocsl z+B9$*_5FdpgOkv<&kh;bg^j{<&;|iupbM~rbQI!HRC=z0m4mQROwqmt=>F&TCZ3*F z_bEeH|3BY@ze2gdoN#-Q(JtKhcWjrK6~I-|cw*ny|C743l;A(=(tb32Q(VBGi44~e zE!;YOCu%4^l{U-1l)P%&*#VRe+|i^~3}jqhjt>Y?0-ei?wfQPX5AuU6&LG?E6wbJZ zZEvu>$@Uf=fk&BJNRU9%1R@X(<2ki0tcp1EYKY87ek{;jk<2xSSfqD!Xk#`PX8{d` z)Cq*m3${v;q5`9$hCe3&?uTSs#M0YswQ^#-R2ol|Ywa_^csy7-BVN8-x?DPyIseG{ z%on|(c<}V;U_2Bn;@_{~Qt_onOGR8Cj2BDW{foOxuPY_SFF$s9JW+Zb!{3YeyZ&-X zQF6s%t`qX5g7M9GFy#wHicc0lf-9fazx79_Pk)f8_~4Vp;>X1095Dd`E@K^VIT;a~ z6ia*v6og44{wmvSka!1?gZ0pzJ3%#w0GyGyazVwZG6^FVM^YMNy7}# z+~MVC&J;0On6c9DKlRj^GiL^qRyCGDt@o4t*<~%7EJe9woy6kiX+Ei^i^WY^4*!#w zCD!QA`qQuTn`X4X-*(tzi2S7t-g$~O1#S&8uaMBuM4URWt>K_l75v828IW!wOSL!z z6B$A4cn`QIqyp7Y?k5@!M|0EKOg5Lx&S;vOs#?1Xg|d=LspZ0l?eFl~f8On|yWaPs z4);Itvd8A8o}ZeF#frfBEXHEJzjJ2_tA&i41%ipp$xI>`_@^$_7069KJK+z=k^D!L zSaCwPyHM6X(R}(Y>E)*>o$SQO`E-eC!!e8W8Gt4pNWD@n{4bie=yAgF&;MyHU?14; zq6c5cF`eVc!*#@swUA||Apc(Ce9jnmf&*`272egz1EiNS9Ato6G!~JBk1j#`YAoj1 z9lOx`-YvkyF+2Ncr}KVh54wW4-uM0ve!ufXAhj>(wY%-BnwEP=K+lp-}9ZZ()`3PPRti`_3=W13%DfX(%UUBZz95^EAkY`2#B<=?=t4F|1CiTxW+DNXXEUs$M3i(#eJWN zK??ykCclb5l~VUIrvqn<-?Q|&I+9tO(u-c-c?fDaR7tn}@9a<52SC{w%r#H_Qn7mo z6&)xL)&1XL>xun{?7SKh@Q?ro=m;P~)>t@SPcDZG-to^#QNMKE9hR^2H=eK?ZvrxX z@N!fYdEWZ7=$!hg+YKAXk^h?BJL$)QBLHSSo|6-$9BNTW%fu({|(Em~d z+DxO+;N0bpBEHa6*cT3Zk@AEZ*g?N1XFd6`g*k-Rn=%&ojsebp!&!vARUxR9wSb2rl5&@ky*&SHl}M@P*Ay+hf=Qv z2VV%Nid>;_O|UJ2DL`5i<@qz)DouNxEvrw@sHaJc99#eoyRElbhgVYV-F}rsDX=2L zKGNYnP>?d*stnJ*D2hQPQ%FxTjGSxjT=OHj5pH}`R?Rg(oa5_9@Xf+cM#o9Dq%nhE#z<5-h(e)?-+?aD!tX%QF0_sQdfY-JSeE=tqp1i9vwR=1 zaYXCX;<^}`y$!Fg!S<=w88h`=;%!pj#jy)8$GaHr`}RbCQc-9AxdQIm#csc&R7->RE5~M>X}PseOLRN^9!Qe#dUOC^?1h2t%^?f zwzt~-ev7uM6oG$-)&Nblh-JALJD}C;JCs%4+P`hF0AIC%0t3Np2mKusctZjkW_@5m zgl&Tibt^!l0u%s7Lg1J=a7fcZO%G%u(h?wGwUYbGG!R#P+2ou@-y1o=X z__7;tYGm~wMmFa0s3~Ji0IJ22mNr@~nhTfClYgDB3d-yvlyS>^5D0(7kPu*qGZKjt zIF@l#lfZ46p6zYmd1)zqg08Qv?I7F`INYXbg0-$*?^1*vQ2jvJ?M`bGmOIchu*;C$ zzl^gBiTyM-i&O*4ygXo}f*nM#ur@;k3Y`g$_5Lobs$u5Ab3J$QQtlFdF6J&ObR=kP zH9YwH-x+_ypM?#?d^S-I(@=wSHUTe4kVBd_F;B9_>^-4SSA!GuOUI7ojvdV%#m}+5 z2Nf>iWPRMYBzFwrrWk_(PX{0UL3lcVxB0ON*Q z89tzGiQ@*|?U_d>4*9AGxE{P`@nG`07cVX!cezg7IDB}2>b`XG;t5w+I{rgd&_=Qx z*$_M2wvX&Qk{)U0l5D~KFhnUNokgUNv+eBsShs#NU9ETO)%4AJ7n!l^NQ(uqQ6+;s z{tckt^ssElaHtM+gLSM>QOr37J(Z(#p4HvkA`F ziKNt)+J<4+wyteMU|-$Zs`KNWDOjr1IXTc-y-j=VLKg!-P%xgREevbx>CiUc2yw z)LZ+nS_Mc}m=o|`%)>5l4oDiN*gT3>)1U}ZHa`}v{@m!7`|D#f0Y?uWDJpQ(0NxGT zQh|J;09w6+ht}H=*jV2aFU3ave0z7?kE&s9rgU0q;2qFo{Y6pWPdvZaXsmbEjADwq zoF2xE75SOTXC`M~IBo|RCCq4|NLK%d26|KtdM_`sJXnMU5CC|c4+>bkE0vYNzYVOg zjlf`vVvGwEGk722?=i2g9Q*4BCc09n!|fzqXj(A z&&&CVyqpWp9-0kC0ZF=N<=)EYf%y3;e<>D)#ZZw$^RBe) z9boPe77I*`pb6#}@>p;}_tItBOf%WpV9ua01afyqk=QeBu8tBJ*J-`RDJANO-oZYX zv7#utmyeBHa6z9A+V#4{i?Af=>kH^as4y60m_Y2rh2=AuCw}CKOc*EF+x_}X`g3YJ zIa|(`XOn3a061bO=a%PKb@AxY#fZOB*5|WcuH=+RIIpVta71}~4n=+eDMK|?26XvR zQR58Gb=`CYgG8|kR!t0m19rg=L;L|~9zc&EV+4-2X<(^Lfq&{Gqtl7sg;ZQuCg)-jy{0M|)p5m(JlQtc;I;m}qzVX2xK! zrMb7KGXZ;yiY&OK;;E^*rrtNI$^c+ktW85^qTGD4Q=SDDlqkX7x^~A>k4JEW5##` zDooOQJS*sX9}$^~DdWnZkE}z()0|5d)Fjv-zZFaR-1?xrYO||R-uI69G9|u?uJZHV zkc%?hGE1wUfADfmmLsR9kGo_yz30q}w)!NK^6Oe=uD>hi&ftR<`{`^n zkxC_^*~Q7mNn;L9HYVFNVu4R9QDen_ntsQ2w2U8Vdt~z%8b9vP(-|nqZiJ7I{_9-w z@b!1kP`BSIxaSf^Zf4p#QqND*$b6Pq=ZElS8Yir&UE<-Sk6XExOqw?5pq61VWcxi# zRP38|^N`GmRWd9C+!7yuYA_fd5MS2!&7We<0yt9^fNujnP$9e}7|vj!Qn|qoD1B7A z8yg*7MUJzI-JYl!)kpe!1QIx;Z~SkvpFZIZC)~-TI}vfeK6|dJqZqfb<`@d8u*gCw zG9id)3oN%s5;L@pRCQ+Rgh!2dk|}p2;l4j<@CjOjP8MY>T3U$Q0&h)WK1Ii#O-$1& z#57=-^*&MT0@*h+I3dn~7tp}c0P~ecZ^)3vX|2&_H(|)4o)nc@K~xn(4Xhb(L0$zE zX8x|AbVF>(xxiqaqpw}oyRMyRyrNSrUfyC5tz6mc=<$8<+B+&1U&gBLPGQ@xlPkffl9!xmk|r*tDYDMSGo zDj36^FpE^Bj~b}}R+==5AgdBw8^@4aT;`a7R4WX)W#9CKQ7#U^cM=MDyP|0u)>$odha#qr^+v{L%4>0*8XTTvvfdc2291eec%;2^wlMmhG#nBOhCJ{fh(jrW`p3KxZwh~P zIP7+NJZ+zDRv9ewFyu>xV8j;&B&gfz0&HQ-RaD2Oonc>ux$JgeWrxmtFf0)~&cQJv zq3{B8xW@gtoPXS9A6l!T^r=}w8}K?qGQ-Z?f6WR;VU`$!2Xnf<(D~WFMth^YkFVt{A-m9!o~l;^upA=~0^of} zaou}_d>SI8N$#RCr9#7GV>VM_mBss9_)cV*hViOkx0?B&8$qFY1YZ^$_RE6<57a{5 z1#SNxafaj%ZBSh?;thy7fI|uF3qf2i6>kwthTrfnYx4Jzq}PjMM8#;2PPI~)%? zo&1?CND{n1zvIWV^hVkDJ3cw$e6Pd#9;bNz{+!)DXLnq4;u$~AYmP~;_g6fgU%|7_ z_p0sVF8jTxRB3m8+-bkpjvpeC;vu_;6?loCUqyJqPT1}R*4|?z(dtIXepQ8`64g-R zt6;6*nqY`vuBfU)7ED+}N;)hQsz;Fq1QU$Ht)1lM?TWg{H^j>YU5a`HXEhzV5KkGa zu7t;4yOc-;)Z^31-d|D@j%K&RC{&<`*Dg(hgmDF{WGB_B58${ZrpT z#!(ssP|L%wrsjcQzOlZ= z+Xo5#A2StjG_I}_DEpfJ5PXpAMik?a20y0?bV>2iklGK{nFLLTNGnVs;ST1e%9pKy1bmZ5?Ej zI}EpwBxdy(uA?L-Haxf8b|8IYH4Rz4?m!?)?YM`CaR)Xw0`673pjug7n7c-|%=Le) z6hbW*s|Txw8Z-?0gi%HF)r1q8Au9`ZQY-~>jXvM)w#ey=A|Ql9Ps0FvDVa`b-|F{t za7+at9977PeZZZm;Pt4xx3(z=&3b#?X7QV-j8%e`4;{ZUV~5XDsS>M$HQi-YBjCRZk5fJ|*hx3>=Q=6K9@VFF)t^9#hG90H;z437JXQEE0EcrZM z;LZZ#G{AY`HmZRU;)n-!NkWZ6a0t4M{8U1G6mfA8Ju&SV+uFEXX_Obc0nY|Ja(D_L zOLV7u^667wZ?}O9-1{6od)k;PF<)KmA1Cfj)&$#Psn%FQEcIfO48KTsBP?=c2+>2d ziJ5M10b{Ax^?Ok82`IxJ|8Lh0RZ!GJV{I(DE;WnhmF+Xnp5<%&ui1ZttvLw0fDHw5 z5seeefp6CwGpGQ`qxmsa@LiGc-(;?Yl8uCaE`0oOIQ+BT!Ux~xn<*$|@9E&Y>Oe8~ z&oY1bc((W7vXT6WEDJ^AZ}~=4Da;fJs#RxeV%Qz=x;L}&rbrjo85muX&K&k zx}3~ucQX5Z|LR!?&p@5-&j;zQqEes_D?Cv`!DSySIAR56TX^IA^MC*RF5B7tZ11bx z_U1MKw$~BUu{+>}FK|A5hF4^=GQ0!W9sEGpA<7EG1u{ZliWDGOW49o>o>EH=Hm*OD z42M`5x`am#`l~KE7#^RmVj+wQlt6$&*XLK=9$@TB?r_NCbINK^O?{vWg_e9-w|U+{ z2>gTBe`mu!KQhOlAUyZ>5pU9i{YjWe{YC!TwS4PC`Bp1`O{0=Hrt<@=tM?WDcU*$M z-)foLbM=wz$SP1X?mys%BAz%>_%{FYw~Qu;`|+luyg48LTr_|nfBgWZraKIWBNy;^ zt_xwx+J^gvf=Dnmp+n&e-8G!a^gexl`TRB3f%z9vFqtp|ws&v)TI(8l)bNkri~L_y zTZHN(3mHJv7&(kQn!Y~_?!AR&D*Thcqk-A2Qamu#vcU;mf@*^uk2h3n1T|-|=^HLV z4MhWMS~!E^Pg{7C>74;!A3WCedT$#*qj1 zN75pGci};=Jm-fxgsXWa7x-ls*)FvXdbUJA(2=)p0aX#5vGFdTKU?Sz|0}vT+>IVb zdqnosHo9VTs8h!&g?V-9=eXE=v%Ch#@M(VV?$aqX$IKqQ=Wb%qTXhjfqaLu=kfe)q z6fp;FIBdlJx(WUw;=RBt^$HG9c6hiKhac#BlM;r)u|cQ*4u3-8td5?JwU4MD>lVYf zS#aKYn^>oR1fQCVBj-YIgcWCz+|D&jS53x?G7F7l>WL>VJn=*d&%b-&`0>vd-u{8Y z=d}&~uebBs*FL(iaDIV;H29kN_viyM%PZgnSkAZyAwwhUtC?7o3G7lY4tE=S0TU~|MIy?V8Jj02-y0*F5;z+E`S=UoWDbg)ww zNM1&W4^+#+=Q`RA^iD%iHU;r7HrlixNd3bxi$jb<+7%OyS>wJ3?;SE8&KsypN3AhGrwZn1nz@rd) zHjLFktP64R9E->@MlzROOK2Ihi`b(E9}^LiYm5j!7wu6Fb_+wm^W~wN=uIKM20b#s zoLBW$z$Y-fR4zm8zdYoAqklro!u?S@r7)=HOAQIXz|u1B8<)XxvJk&TJ%3DV zkq&QI+t{Xvz1i6ju{=P285El2GW5XL4ll%z)-f1uuu!liTK?pjY@iwq5adxs`@k3$ zt+PKfLYAB0K~!er1@0%JN|&}+0vvp=8kT5!poCzn!J%**c3_bz0vLM*C_k$M&Fctw z`P*0ss@ck9@B1z_07eyhAjKYB{n0^$rj}tp)kE#l%E~E*YCh0eg37%{r80w_ELL2V zY*_nJ1Zl4%^hlheH3kQ%L6=M^rz*zZMA-_RGEY48&=%45fn@KGYfeF(ei5`;c;Fm{KK|B3cEMRU?V=E^>26(SUP z2wIMyWjX?1W+?L;eFCTo=;5qxZ|BG+B>b_|77i#AsuY^#>e)eE)uE-x0=5TU#?oh< zL4u_oh%YthJ7J>RD#X-9ml4OJ^GxF64l@A500bSOh%n_1C3JVVH#JY39_%i~DE>#c z57G2B@>s)k*jZLy7kp_iZd->iX7^6Fsjq`Pc{&>oT+f83q78!wnYzSqRPL-E z1Sw$Zi@-`0b7{;h#@aHpUBC(Oqj@>Ri)LR2F!h%NFbh`6?mz$mM%3OJ)nyPaW^}L_tm}r3W+5LF-w^FK zXg8ZjK;%0ohB={SAsc8-LKGU}CYCwZc?zcsvvRz=R+Q-6x!&mDKo|t{8~7au1Gq>vdJY&lLEcT8H)9OT+Q#DNS2eHqgS7N?5HQT(|Z*rQ_1zaA5H!9f1dj2?@G>E3f6KI z;!Y;#ADEtgaGsLWXl-w!%DnK`(<}~CL7|;+(jzPpVtA9&K=FHK!uHbiwc6QaK2x|{ zOc#=8Cl-mG@-UTq3H*2|=Zqy&ac8bnC;H6v3RkGh6(n7(2;7isG}=_{``#=}6>LLs-)frlZ{<&EV$x z{$jtv^J5HKNDH$-vGqJd4?)oQ@4_yxC=}*H@n7&H!!}IbAn`y}iRSac4$`Q!;2(mg zpuY8MPF~QhE9_)k{~g@7h~EL2;=+R}l9LIN$De}dqTZlkelnWa>a4Z+&3rznf0RH& zmFU4AI(1m$y1ZRyRcO7K7JUsF4^T4nXBgcfBr5ZzEo~|8%TP9*W$+u{U42m@n76^fXb~*z15R7269ocq-o_T#++a;vpCT?h97#Q;=!k}Q~B zdcMwNw?qDwLx)`cX^$%yi>6eUXFA}Vnr=*c+)7yW_#7Wr;vY_4Py)~8m+e}f_5S9O zm?M-(JK*U6&Os^F`)k+KS;PnYGtca?=~T^bhx{^gkL&l~8g~0)>hX8Fv)Ps$_^eL~ zE0X68_l+}`?Bub@106_2b^RE620l(gcK+`foIk^=ZVy(13YOTyUvJTgfFLAN&^PN}J|;&BH92)B<#Wsg4+ zL+#jfu~ST=h-@t4NBBgD`P6(olJMH&CQ{SIXDkowxxECuu`*NfghSqU_`;zoWvA>*$+z+<3b^LOo(sN6*n7bj z&IdxF0LEOXhP$lA8L9w`3JKz1=X}sw>&N>1mfk%^luBHId zCzhSahJ!ADBs-A|M)3==K>92o1(l;sc<}-jfax1kjEcw zyHX+kYs&Q###{cE7Tqi8d0D*V#Y?~1{7a@Wc;f%xQRu_CY#GQcINd*2RYJ}XAC7=? z&u~NnQb;)}foWqn#LE}N%ea7ifo+In69|+rH@}hu_>VCtQV@gki2f@E>jV0r1XHe{ zC(xohdSB+xdH&qH1+jpH8=bKUTPK%6D+sOyGglMK2*NKRQxgB_TwiV!C3eA4DHdwZ zdZAD#z3rZ*>akKLTRc`>y60`*n|`EFcw{;@UlP8N_RaGIRG_g9>2Q#YE&= z3mX8|1TrPyc*VIZj#6=sE~t<(puaeHv(&UMbLjs08j*wo-xoke-B~LXEB6XwirGww z6H`{)*)g{w%aL#rC=iNwSsPb;E`JDNJ%v(O8=p{u-vg-$PV}ZAIOKAMIl;eFs3}UV z_vd!za{I$dCO;XeW=au%Jf-GhN!JN&JnVt6jg19~;s^0BqZ0UC_?LU%-&#A!!3^cL zFMkReb`e)fRkez+Ur^2~BtjHi6G;<#>crAAl_7T-@=ITkK_~~*S;R}=urLy+Q|#F5 z>%Ete^^uOn^epP{c5>IJb8LOJy-tA_^w^E2-qC1S@|W|S@#|9*1A*b``yffA1#Wet z;NmWBl??g|O}5+9#1uI4#b14y*AvIw2Bh)n^yXNK_v|g978xkQ_MIa+aE&Py`B7G+4a+RmXCw81!Z!@7i0vot9ky2?)BtivRih?atP*&_^0lVgihT% zHIjHpbmx0gp2eNOGK!EW*Fbv@i`TpJZ>MGU* z*)jgqZeu?Syxk!8`B2V3#hlc1V}Gqd1}_(xD+=@m156keWambxDqIAlTm4$e?e7L+ zT5k){WL+)Y`xstZS2D*OQ6D~kI>U;aoA5Zb%W^F6XWHktJ6k)ymEQSxS2D+a!C2t$ zpU(8Yu=O>pK9FRhiDIa!;_4i7X_4bjae5UI8I+(iZm%DSsrCIPH?0j?9SMUzQNAv+<9P zNal~Y{po02t*Y^8+V8H-veg;Z5%HM+A(gGyo|-tLloY2v>7CN9ZK{dcaKYbDog=2l#_ z{<~X5M|b6c$m#L%Q_%-jj^0o2PDdVCnLg@YN+y^5N2m37ft461uiy6$xGqKHCBXS* z1yy7kXg{HVr6S5t(DCbUee12azV)9z|LCL7KMHRH%+VeC;MQ9;eDLV=@9FpVzrttr zaokO0L{Y3O0#hj@RquDdhrG|SasSzJ`O(s&_|ad-)9DlGRtrz!^$fN7X43_9;cuEQ zpbLLSbPKs0#A8Uoa&Yg>7;I{kn|Z=^iAz3<=w^d4 z)J%W@Sb5c!4Ll=^&lA_je)iqWq2Mpj_pXGrq)OtTn$$ktZUfqoEYxdV&XXy|bj$Xj z?Hc$O60m9_%9!IMbC6RE05p1qw0s%_df|wuWOFEu5nwW=4e4lHv7#7My5ap3pRqgEty)g~b46Fpj?Tz}wAz#ev z!8H;Vyw4@QYLnc^62m`_?3S1fA4|QztEOW)g@9j_Tr3SAI$Wg2xqltM)JlBkQ92U! zi~q-NEW%1DR7n`IF=*mHGSR>%^vg~VFr)adBrs%68W8#q2siz!U|`iHw(Vtwa9WMU z{Ar{eA^*sy2J+tJwPkNUp!&QH_@mrue=LTc7QD6E-Cmsz7nrxkwBfsm&qv%QI6kV; zeJ|%UV!Q_O7u7B_V&dT^<^VnpY!MF1g31>4!`Cw?8L$D&j0Vh$T4U-yh~jW7m}IRW zH**c&1(tOJ%z;co7AB>r|0P^g^UHbssI~A7SRx{t$oozw!U$@j z$z-&*NzbeJi6&v;TZL~GhOUWh_U&ENgkY_7FwS0Wq)BE zf|R1I>yK49%TU!7UieISV}mCvp|YKVf>o$*r{Z5%RrP&CXMcif3{YY^rWPgukOHFt z8iK_D6eNHSCpTsxeJNOq;Qb|h4oFi37UD7#Ph!t|=8LW3yk~Y+e>3yNrHqt{AmMSm z7|b+S|F=j=$}GV*j*H7>y1205{^&>D3x!rbA5O{ix1~(5n9oP(7rT8aBc~#HvBw9- zd0G!NU^F%jiwEPv%^Npv-q3EeZs3Q?7j5k9Y#@^m?{u3NIY9)5FhBLM*3GtL!jOTJ zSr1x4N~3{utRK50fPBSy$Kj22anCH@?m^MjuH}VM9V0%V1(t-nr37`gap)gR$j&3a_y@Y=RpwB~g>BYfi9shZO zB|Jd)-J%<>3%4A#YNnzuM;mi+_x%oG&e8LO`)$A5enaMh{PTy*HC=cwj-WG%70P%agJx6iV%D+d(?$uN{Yjgan8Ol^@8RA5>C3B zj{msU7DK?=?Nbg_Q&3VV>!{!o3_bB*K?liw<9qy}DzIVR*ngtm}_m;zj&m>p-3CFZMC z>76U_pj(FC>%ap7^x~h(z@>3bmYhDPV?}a0N{f=)?)sOm_WJvQs{2+=djT&w{J4O8 zEPLhe%N|GJlEB6==4LPrwmZC zd>ys5FnS5d@X(@QC`_J?gm_yx;{m)c^GZ z^+&?E4{F=hd0!Cob#PrfL=_V_p+F&%g(VMSB7SecRJ81(PhbL;>4Ooa?Y?2)3C=w5 zZoDn!^WGF**=iCMx$s7DM9CJmf0;Y>V~N^qEy15UFfB^iNn}#V z(^EJ=Ke9N~$$Nrh{KFX~T)~@X1x_-5W-TkRAnl}mwn7AJcofF$L@dn%T)^DMLGg@9 ztS(qoN%y8*NsrO=ig{=dwVZyvR>y{c*^Lx`E3t#*lkv=VGvf*bA+ibYArfR`ggK3P zX+?{Ee=*AU>7TPdW}m>>U4X@;iQMN4KwYx|lM;{wP9k?%yu9PZafV$PC#`NG6Pq4%AV z6s;dxu1X8u%0$+#T`Ri+4wok+vyjgfVIOtHfsaH_Z+6AhkX^!4rS2#Mj#NJ%9dl0M zmgTr}Eb@hkBS6!s{mt|*XB$<2baKoWiFk7HKT*D*#?mRx?)Qf6m!*$;+^!HnE?l8} z|J~2HBV1G!Jmu@Ft93573;X5YvTNYnL9R8ErLTzqV__qJFBP5o{ShTdrin%dVa~ zclGMIcr5A(hLIP{F9a*pP5{jhR}<1V5xzc% z{l`hxkd26TF4yQ&Mj2qQ+;>A=h+I8%eD2UjbNs?P^w552H9!iWcy@|=6A2!yvwAwR zbaDb0rpI>qafpyI#Ie)Ss0SS)VImr&@xmU*x*?gIBGe2-BAXGRMpC6fw22vIO}T9^ zLZ=+|{{~J`Jxo$Ncdm2pTz8xQ+d^{)u#2Wv;TfS&WBk-#wbkpJIIsqGZ}QSW+O9y5 z!m1#-3XzvWuY_Y$_+yqE5VeSnfR4V+MJ%udmAyEwp`PgY)YLd$v~kOCo5H*s6*yGg zQI{BBXrl-Re%eB1#E=MCknCintH2jq0S;3WGe(LaNh7GKiRr;-kooCBcujZ!4uT%Y z_*!IVG++H^3^+k7k9FrKLXiGNT~#7kd4 zHfVvav=2TIn%$2aPzikPVceiv-lzC9JOn}g_j%2SAR&^I`dC68ogDoI(J(ZRbWX2B zZmbY;Eh>o#X|OAd(N=!H zaJV?%`2N)M1_vm+6I^pK; zZHq@sh0&k|W!5EooaG6)BDVm;0Yf`B8zA~uyXvayRlPU80cS;xPm!SmHX`i#o7nSY z=LU9Bgd29T*CQMC`VL~-;AX0$WB@MX1nbult*|Na>q+6ng9=*V9lmyx7VBDTV}pUu zbh?zqK+TAKB-)Y@*FfK1EZ{+KB(PkiFhEa;|Klfg6;vj+AK*}TtkM|z)8lK(uflGqM%+F zdI5m~+lDFj4?vX|XXusP_D)+-=n0+cVL#v>7<_RREDN|m zts{B?Bw@Uv*ZeX2B*qUS;0e1ZuoZH^cca4vH~-n=zad4XkR*NLU7_itxoL+-a!fz= z!n-~p;lrr(8;^&kbB|2}Bg?^|DfBt~3VR1eSV0dVK02BJaD_E24!Nc#lQW22d~iVJYUR?ViyRnvA>wW!0WQ9fPEdZ!~=)worE{Zej?{F5p0833;&*%s4 zmkcW@bU{iL0u(rmrLeIAbqZ!L#MF{wt%koL&Ij&8Zfqr1e#_%rd>|KyX!$~8JQ3H% zPUl+fi}9_zR?D83pPH8f@yYO^YfA1+R*NUb8?0@A^m-|oP3P;{_;S8hD`~l-nT_?1 zq}B7a+49Nxw_S5;p}@0iH?t?QQ?QH|n&ULxE_y;Nf{1}8{S`4L^Nl9LW-#GYB!lcY zHI%WSSr?C6x7OF##)ev7-KDwIwB5C}T`b%UfI_j*T>S7HPAcR=(gNmdir?R($2#a$ zjbqrO95W~4qT0oXVG%Ye;Bax*0kjSr=Xh*u+iM%WTenzCDY~&fUb)d)Yq2((WgBzZ zVy}zW*4plFJD$L2`3sw!&L;LWz;r~{XzlzyWZR~#MJxF@qnuA+8YSy1CSZ96;9Qs& zgsqTj0QSp+n~?=WK;g&jGXpR`_N+IchV9`*z?VyY*cmJ55NE6eeln(LcF7)6lrhyl zky=?U%RrP)7K?L*0`n}oqCPt;hhgCBx)z=BXQO#JQY^Tf?)9dF0*Ic%|CCy@0nHmavgM*{>Hkxlm$hV22}95UXzv$Q^X2HKH^2VXXvZ zZR)rCgzFs{?oW&FBXJIid6}XNvf)_)h#jQM6JT-Rc(i|@HDVgzUceMIQPB-1p5>(~ z6me`aQgHA$Tmp7$>Ct;;<45btn2UM5@iFf#jxS%>rA!Zhpv)>Ov{Fq*$^Um&sjnzw z{z%Z_@n#k8tS{qpg?)gRo9=(eJcCbhi~5RXy~Q9+L+c&x8P$7&FKqt~Hu1Op`)BDM zpRi{XWkfGuv!~Z1I!QD3jIzRM-`iKu*x<9_u8O_Igbo#*sW^`mTLF)nlc$MYE9Z9xOTtVeDK{edgE%_HmlRjH*n<(%7#}+4kOS+yy zdC7gcFm-S2q1-<_JLthX|9kQu2fmsQK`&HcQJ95I<-F~x?Yiwr+Zt(X*a8^x8g}$? z)(1SR8IX~XR=IG%1AQSpkl~om5eX8Iz)Yz)4!Tr=$kpH`=l;E7xQuQO2t0z6El8=9 zR8WMS-4g(6do&s-E!0&7Sv2axXZc?(q z8%;&=^Y(?(#EE<|Qy7~ZD=qYX4;Sc-I+dXC&@*j725`v4hbW(iyBg=puko|)5XOo; z7(z*n5sQTV6(SP;V;7PDMfG7(1fXfStrJoSixFNT7+iiN=Zhk47O>dLyq^~WNG}~s~bW=BCyWQVzlHT3+2i^bqz5xhI zlItP`GacWxpOv1f!u)5TbK5n0O4C?+s}>7m;G|2nz-iLCFUzlXQR?G2I&VDi;i4 z%;E=f;5!iqNA~U}vc4}39YIBiJBIE@|33m-0$fw-+g2;#O4 z|E~It;HW0oCCTR7sP~cmE zkS$3o4g4(p?9KRblRr8tvHN2wL(^iZd>R`F1Ap;M2%z-PBflGnhE+AJ$8>BWy83J& z91a`~slTp<76Yhh@Uvmb|GtHVSK+T%{J3~i&O~QFKE}qs9x^kzlo`S%kFd&n?uuc> zd^gbW!f!%&4IdwA7XpwMqB)4EWhr-cRi@qXz;9&R52ZL?EXOSJJjmYmd+t}LN z+`)U&VOs5#D`@iluLtA;zn;*vnoj?EU&f`NnzWbKu5&$ZM~CdX>1Dw6LS{XHR42l9ODT)*C>wVogTDMmAnJ zJSHDJD32Y!u+O{iP#IhJg?4$P3z|esB>CFmr|3~avO^O^b1925xm{`7?%(_(f|oij zk~qS;DX|qGax93BkXCJuF?h`}qs}qc$uFpkvYzLkfH|lN! zdrrV!k}Y?iulr?YuXj2yyY0Cb+Ie;Fz4~p+{Xe~X^`4Dw_M7o>+zU(uMlyP|Z}*?- zJD1S1ZFfsN+7QsqhcFx8fw9IpDcsS-RFIRI5;pTZygX+!y$1$fsAMEZf*(i8 z1Wr8<4rEssU>iqX4*+QKhC=2=HfO@f*TGeJtq~-t5U3f7K&oEn4y8n8-bub zI-kxkC)X%W`h24~RQ5tKreRG=CL+E_6qqGfilm}cAjB{GRTTE{2bG{t2ZF~}#(*=d zqOE97W)?MZ95WNMR3D?EBc|aC+;nTfumvMBnXh571+)so6E<90tx65zdsiE9S!l1J zHVlyG5TeLQXCaRxguVgm?AG=MtfXZ1>Ie%h-JevHZ4N^uh#nv){e%VmV2|cJ3PRDc z0-1*vVOlb%ylHQ1JniK3lllDb3VUXQ`P5L}teSepcUV>wxzXUSpYb3t0tjRI)oj!W zCG|j1&cu|Uf-qdA)!ibRs7)wlQj`axl1IB#LA~)}XwjUFa^;BC0k7u z@H5uVIc7AdU@ic7Mu58w0^D)XnXCk(rjr9RYP%E?t`{?-nc<`s!U7*fteuKYFr+1s zA~jRgSD_ZKKu&{s1m**xL%}$ve#5$DRvokgRCuAjRVyADl%oc}eKPyCs*t+TGbvzg z+Z5*fcKd45Hm)N6&qd)Uum02UFAOtx1!UD$x?5LKd)2f2zX(`DxyAoW2s7`?{=%?l z?%H847TH};mJ6^S_?IVjh|0RNSam5aCYqIU*2A+fi^Uiy4L-wW(#hkgbV*nct^ogS z+jFIcG#W04D@XVznyoD(l}6Zm%4oqFKUZ#*=5R*1I#+^edI-x2!Nkb5qwoNjI5#?t zV5A8#=>#cZCWp>)TO&v2V5Q;diNHi?B_Ko-Z3#?)HidYE9zl3Mv0{Fl0Q1PV0dFtA z#@RrKTQFe6a8W#|yGGFQE`nob{r)1tgf7%yqoba^&zJHcA`t0umJ{1J&&Jsu+F}W# zAInY#LS%X(^OEH&CUpHZ^i8Yi)9_W;FRf*Z*%IzX(XPUTBcR!o>U%dG2q5V-0~QeWgCd@ zzP@9kT#}kX*rdwN_Y|#{;5!DL{P$_-*%iR;>079AKPj{ zN?YF8*xuT5yE_0k!86eN?iQYf96bZyHH9$GLX+aVTkXxwy=dkZTr6*MA<-V`}9 zMte&w0YF5xJq!nE&_dNDuPr(Kp?V2q8W5Fa5UDd4sw7mxwC5^Es_kJ&9f0jW!QGDZ z()|KOqJ!b>5K5|1*(9GjPJ|T%`H^`F4|w5r!M0?}=4`pQ zmNl<=L+(-6TD8{Sr~Ue9rhAF(4y;Divju=}O{o0qB2(6uwYs{D%ynMNl8FKJLH2Bj zG>m6X-w9qkjoJocI2Qx3fo%~!y(aRDfKoILBoXYQMT?7fDtEb1u_nUfv5zE1lt3Vs zUzmSTHv_eB!YZ`f!fZirp~8w9hAT%224ZQyYK1PB4vqNPg_U$Db|bqDInQIUylKLK zAHdN;JroDLNsv3Q*HCMb_ovI*P>!KPJsAJBQ! zz3@E1pvGVEfe7YD``8b&Z^dY#1Z|QVT?hc#f9vJt;SClJZzYOq9p)VhM~11Vt`^6x z-tlLm6S^I-rDhd#lN=0ZhwdAC2sDk<=P0M|Xas3nLeW20iwPPkc!WPU z<90Y24cl?^B~I~d_mYSW@BSCD-KOSILTM`%Qq3ghpo45M@kGuVCVTz92XTlW^hRWN z!^`0&q`pt1T~rwGi|D~BNqs!f8No7C&>hY?pvS3X3*;wY79f3~e6m`vs=rpr{6?mt zcfNALIAC1JR`tKpE0YuQi4*d~(nKJY3QU|ZQ*TR|>~?cu!OWxR6khY@cg#m0H7{o? zm27+X!i8b#8$Rye%_03Xex|_5X`FEGfVRdui=o3EKl9Z-52K7o5P3YA?hs=een(#j z0h|$9&>eq87WI_mKL*P}ZlXI;QU|yfAYlGW6oU(hj}iu1^g~G>?ery?E?C#ba%+W$ z2oPC4LyO?c4&=8Xu&81c?2m3$=>i0zyro)D{~;p7Pz|B(Qo|l&O#43kGF# zc*8AE^ZAbTg2rT;4Adru9B?cs5s$@5sZt@$Dr|p^k|JY>!Br|@WY!m)Ia0e5x@6TC z?(+F6h^wqkpUpMyxd-zMv-D5yy^Y2EQW5)?Pvw-?zCMRC&&>aM{qB?S2TIMGDR8zj zA_oIOHHrKOf9{k1nZa2|yNkJq5>iqz#s9^a#Mu$X2NBA_Eh=2nX&88isCp5Ztg4tT zQ0e;MF`rsR<2X%e2r?mu@6xmK%oXnD2Bn_Z*kmxuxI47F=bc*x27jA0kli_Y&(OPu zK7n!2*P1aaF{8)`xZk^;1rd`K^N(y5I14kFLVz&A8VO5ED#8yZfG2VP*5c8R1~Hd z`rt&J)TK*_h&q9zOA$kM>YkNNLjU9Z$dT9>PdFw{%GU{W^{dGJV$ONGM?YBWS zCj=ediu1WhvOZU~EHUsQbNN`Tl%V~MR@@~J9NocG-qOZZilz1a#OcMpup zK|B&hksAcOiYMPfc`vXm)cIl-V<_}h4lNyyj3!WNjM>q2G#HMA4Lc#97sjIVaw0si zxBI^Zn`4ShaX~@+Q_KY63wO~jB3c;Yj|tX=8Qe#!ktMaKhmtLRzxS&i4iqJmQin;= zbm3Upt!fd6pnJ?aF?3- z%H~XAW)q@8p;ibd00TOC0q-sRhS?BRp$coOg~F;9ZWZY5g_9>Q-~+!UfB6RMV7v}N zmckRlF?hiKQteCj7e^m^@x{kRAM?(;vcp~gdj@D00Xy&vA~`Qqa54;0a9q3fOulfj z@buGo$v=bih3#k0G#|@1&zx!IA8Vd@78fCw_BZhFZQ==s;UVe8i1loNVsrq#MQhzK zqkLs>2MpYc{YfykHxpF%SM!DYTJ7c5I^BHzz9MV$R8U6fq!uesfLej4zbbV9_+oS6 z*>?Nc<>q6B1IrDdC%vV%M-K_$d!fEp(c?kQp(tHL#(TeLed&Gn`;l{F|GR${t$1$q z+>5vc+F%EDVLK4IVG6(#@&;F(0$PpQ{F!3tv4vOhc7GK><3bz|H0EhkycCTjrSVqt zu6Z?~DZ|Hji@BipI&Br!B$--kp}}dOh7!yEx6$_rC@Nz--Cdo;KC+27pib2hL*UfO ziA=y5tk_O7%BGRUR0Y1ORAoa;a>+IzHKQKUaB4CqA6aha<|3nkT&1X{^icD=7P~a^ zSL_$9Q+Z|Q!13B`6Up!m4<4L2HM6{Nc+MJ|U7ShlOQ()h*b^g9!gw_a*T*1TWMIic z)uWhzQWQnhIUyuF$fH0F6B*!EFh*0Vnq9gvYL}15xyh6uCT^GH?$=pNI>CN}eac$( z$rsB9gYl#?VtK@)>e9@q2~N@R14lk;oOqa3DvPPaJMOwAo}540quU$nJN>af@zVXa z+iTvWy1L^srs%e(G0Kb2T&L&sh#2KBz9=RhALC-Yy&%ThD9uJ8K1+gESBR=IVL+Au;V}4!HYIk?Zs) ztj<&DPemZWkqcagz+GiXgrw6zqx?7}==7*^4wS<8-Jd(x^k?_$`}gO*b71h^1hsC~ z;a1?JVyHD8#12W&4?t{5{r={_+RM#>?w@;efO}rRPu7W_aJ~#}1bxLhGS~@vnDb)v zFaDn0!%v1i7tKrbX_dHd?~2#3y^k-q1mgoPZ~tCxwVxHNkNE$t`VbrP(16I#(O8lI zEvW+905n6DU=C4<^kfP(Xd8u58%V8B|SZ}xP@gD>6K^} z&w;VHa%rL@FJU6PG_OaRAw8uQzkRuO8K6^;upbQ=-wjGj1H%+o&0*lEHgcdr!E}K) z4{!>r(X_VzkB~rZATTau+R75LmonR8sW16x(IfLW$3=3(01Q6dNWjYpZpBkmhp8Ok z;i=Rj1R^L8olT(kQid8iUGE?yx7Mkjj;JXAxJr^8pUXm}qIwMgTkJ_CVVNh z;=WFaZU+#tsK)IT-C47XdC1ZEqWv^wp1h`F10cHxO7m(E`nVQU=Sv3w;e{(=psh_v zG$LjTFl-KG5prM-PwOCd1ID&J33Qx2sH4?OeF9G6{)N5N4WwFHy@n7MbRcW{-gG;I znU}=+N-?xP9>sx#m_-X!SRkJd%7Mb2KoTv%x-Pq1bQXX-i;@6bzD#*C22g3P`#cAt zqQBAZq}H0a{uo6>P~~G7RdzK+#KKbLYBIZ#<*E<2>W6Kx&7;*$^(d(>y?ShSRqw6d z1yiGl;K3G_6omOOIIwn=$#@FDPpF@k7Y_uJ_3K#Aq9GX!BG@Q-#1P%QUCK9esknc9T-8%K#E7`V z$(E!_7(b~FX~@qG`vd5ukU)XA zAQLxW6dYIqs|1WYGjuX}@c5bV>Y|`MAv1s|?VUDD7Dl@|LupC4IRZvXIuB+c^{O*b z@7bO+xk-a8mKd8ng$LRPNDkO(dRIU-!?2_P;N_Q40UKq6wOCvO+`*3w+hUK6EYeEw zwphqc`&1vm6+R@^4;n^5=br%(Q$vC9DbxbAQW|g__+9`tnvs!Oi{cDPj)p@DlQrYP ziSgFxtR9L?M{>=3F5J`1;ay0d9c_)fWI8Y`J)kLJlr%PCc{`%{bwdWKQbVd~Z*R6} z=n~S)#ELhRzTjkxJ`&efgB`;d!NSOJXGnLv)&-sJ6wR*r@(RQ zMDPC9%C;3oKND4}pvmQ-Jw(&@&10NPV;%04Xxqt3pa7wB~^Y?Z`bZJRCIHr_ob z`y|z`#ba6&b{+-80^O}hVa-RtoRID9ykWQ)iy<8kOhagXHHeNFS+pbQJte^VFkpw& zaOvdBb{BQ(w?u*!z$U=NQ2dw3RoN7g`eUuB+*eds09jWClCO^N-Oc+}(&U2%vk|9p}W zJ6V9Zt=clo+?CM;86n8vt&Glt;nzQcJj7wd>jrfckJog2A{vWDC;p>M`H90?!TW6U zqup=KJIw$))pX|d?sN3Y&YygQ_H}>hyM2ra|5^zo&8_6x_Mlw!%DeYvYofD2Y z()9N5qsB;iG?N)EkC>mMmv_NVRC^!odrK$?AxFq~A|DjRW!^mW20T9>T2x=2e0<2J zNk(-trDG4)T|_g9(aalyn?D7)6bN~A;XXyv zl>08o%2un}35C^&FCMlR&0s`Q)j%+hfCjLxfQ18oBVy$T&yWL%bi4YD0U3?zCFe2Q zNr%Rw1L1=gA(JS$uWo^Ta^!Wj)JIjZV~hIjlls4*CD4Mz*@o{7&ag`1^qRCi2QMyxGihxGdCGW(Bg3(iQ-{b(Xd5!O9GIUKV8!^=V7EM(P3 z{}I}!R7HHYKuz^QUE3()SnFPP@5uQf9}WE@{GuNVCFHZ^v+MU9M-+89<`NIRq74{gv$Ys)pnD!oGDYTplS zbXs^-w zr0%xY@3W6X4^67E2L4>$;>B6qXHty6`l0~{A6-GE)4O->>+ zgZKBFqU&B1#Qv@%{UfCU_h(PKx1L`|AIpi*$4wTRn8;0tZ%ll954Fq(ZmNanKT+FS zx7UIpC|p7Z`vPSC4EW^nq1QlWsgUNmP$jekw&0fZ3x)|5AH1STAuBjE1(Aae(0-Cv zz%_}7F2MW+WPViQGEDC}v`pe$u#qZzeG~}`XC-MG5KgSrSSU(iRSu4XBFd^3lvKH@ z%GsbVVrfpqQZf-cav|)~lF1;`6HzV8hLML`zBdH?ry7%d20RyGz()g)6HB;C%&&#+ ze&~VaSU3VGrauzC`L-JlojhvAr+qP8Ab8^Jp++Jali++^{NY16Tb`1GhWlDKp~s|% zQNK7J3ro@jd|jw>mCZUzC}>D55H6o9B?%=!%_Y=G3kJx;l+>}Qk{ONW=UfvhAA0_% zefRFE@QC0H30^&cUGEP2qcVza!~^L-E*B1X6)he&Gk&C ze)Dm$Deu+({#p+PDu!j^Dy7A8Ue~lr%=SLLefL}R<-%Sqkh^LKFZxl>6+kQq_y-}A zkb9K^237bs>30+w5TtF0H1K`Q@i(l~bJ`IHBsVAhcfXx0-hFp5H~!`~CvvG{sa*2N zk!|7UjKkx(4V(YJ%M~35XABQN1nE4NG>idNou)LRVTcL$eY-Np1T-x z22eKO#D_l$`omQ|Tp4B=S|=fwElI%0L?vkJ99jp)0+FrWoG)R8oM!Vb?T6S+NQ_^U zd~ztnLLp6JGlPC#z_Affn@DC-wiWT;T}WywdEK1+^l)zG-yke6!jih4MnXe19P+W^ z?`0x>`GG+AW*9zD!Ur#J9M;v4x~>|@*GpPr;zq>arddf!m6DP)H|xK^9

f5LEo{ zqDR#*ZnxN9u%AQg62?V1e5n2e80IJfmnp*4!GCW{?|n?I7L6)p$gEPPhPsG@g;oVl z4z~`H&+?yxY%AO9ZjQ6FuDh}HGuySzC6jboIJRpWgf*o%?9uL#ENo-rpRR3~OYQF8 zxt}waxQIfokS_Y-NhsboKtus39r7$ZuodXlJ_7tC?b@UG@LY%CV-@`_EGHkvKK$jL>(Cez=A$k45JVV_Tw}0KBM1X| z+A)7INs!UE)55q|U9Ig*Pw!+}EZF_tM_)A-duSrDl9+gC_Zq*6w)C!n^l8L%VCRN6 zgKR}j_L)}qdn`EcMMS^!uiB^MMRpt9cvOaqC%VAb)hfm6lTQ|Qt4-kRazF7CIUo%1 zvsqitz2`l-9iXCJZh{aZvqA11m_kb;(~H3E&)G<0LTfYd1cVN9dVbtFfS%bekF87? zXI9P_6DwoM``&h6EG8M@_eHc71MA#vu-F-r;(NekZ^C(YE@$Jk?8r#>FZ^!_$AXU- zYV2ENrRy*@gRT|kkZq(+SOzK$lf@LK!aNKJWT=Ma%%cIOOYThG#a3;@!=HWxC7>ej zjc5Ml7ssx#G(cXIlcK@_t74&cp*<2%;XbfK13kCeN z_Bw|@-YS&CaBv}*=W;1s$SCqu(l{pHnu_HYdKryxXe|7d z@(92NLyePAP)k_6VVy=Y=Ui~|N%PSCrSjyVezl9?+3sJX19nSY?3AritCScupGhug zw@$gedKcuq`%Mw;){A)~_mYqe9ziP!Q!)iOLRP{r<~!+(9IIl}3IQJpDHX7-V%1TJ zopIam?)M<-lQ9uZOMXP}T>eO<-o;UU;IR=CkjBoc^O5w!apjGmE@7K@GBpb-^< zIT1gsSJOwP`1PW#op_#CWej~Hq z6~M@;EFZ=Y5V_>3;_gx#k!h5Wm}72`4-+i`y%Z|=0+`i+4VJAM3;E)KBL4CVhGiQi zr&dWJrbsd3IcdZgjwN27na*UUn^W2B)URd=<;B||1!ZpN{!$I3YNn?D zdv1QQp3Bu2=czmioc-vpO%JA$hQVM0sH-J}D(=Ro^x3A`kXhPQgk<&$PuD z5W{gGe<@`GuWv;X4Cxo-%)!J&))Fy&G1BUI=Lvc=Ww*@8$wJaBn1N6MDJOQ^LIHp8 zJ#m7DL9O<@6)^$Wnv`Q2GX8W>`=w(>S`qU?i*8MF@?Rp%>}f7(WO?!<@3tgKf(l>< zNvr_(#3zR`sPTL$oR^?54pyutyC`lCLXyaOaiL&F#tKK)or?iM%kfVni2|Py1TBv^ z7c5IFj7Q9ZwQgTTNK~WoNa40mIK(rsMy_LxBx4Y{pOJF|fx_Sy;7!n@O<0U!hQ*wO zKuLBEeAw0OFBS@^saSNzogSOI+3zGR)ehzpzl(}0J}^#g`kkVynA-irZ^+sBP18T$ znSPF)L*cDp$w;aX%CZ%22cweK_4)>L0W?s$ECuTmq6+|bf+~&XAW!9Xi`5X^2~;ra zAiT4^y-BAJeg_FB`rqj}p^4Fgw~+PFyF_<~V|{9EBnYS>cPU+qo7p+m5#WhE*Cgy7 zIsg`iQQje(aTD|QMns7`VcS%&hEW1?$aA}y!f@qKVNX`D9-kJ^n84cAqqv9lqP_;g z3%%`;d%2$ktVil*s|6iFl*seeA#puNIH#^^0|ed(-)$2YC3wOR}k&uG^^afsIx zU*4cD5&9)em%oEHqe!cx;6ZlX!7?uft3_r6BpQVG!@=CG<|Qn9XiM^eKwBp_K%VuJ zIrm}5|4^8e7H9O?X*Y9k?vAt^zcmz(2H6p}Vp@sG>V!KPfg{46b!=_ecvJU(3MTX} zY`}58QJ9?6>yw>FQ`6^jx1TihW4dz3ZTkI>-oNQ~KJK=XA-}DSjl{IT^kKoT?)FA{ zZyZp1FDiS2QD%ar!*xi37GMO>oM8bJ=D*h3$5_(i#1^4lsGE__T$# z-lC(UnJob3SKHKJLO!AE%ZSv=5k^@|BvR4#+z3fw_+kseWS&ML{OGuHdwchOzurN_ z!uF=s$&5lXrCarG+1)0DK5kpij%NBY$SZj!jGK~m%`^QdGTQC)NNXTy;F;b$@J#$V zujHAaZ0-L@zk-YNXF?Jj+U|WOv0hNBx+qW8AR<;p8}_>Dnij+?!_1)28n$`~>p#Q5 z&(8k)4shp}(2VKI`f_a>d6Vf;cSPsyxhtf0>O|3pB26B}!4)t{&}>2jCwCsi0ZPKb zfpAEdO|y~G5(A6f?H~w+ZhZxdTZIChYvkjFe!PQw;*WRRPKTP+TNA(EXT;4KP&=;w zjNl*bmv~5IRa|zxF|!UAl8>*(AQx~B&a$xHa9u)}m^q{kxi0z)2PKnsfc7+G{TqhQ zV6dJT>F_r%MYIhqvV+1D(ZC_u-!_c4Uw)^7%yz9nw0pS)e;!y4pMO_=ANt|Hg+4}r zH6W*Hn&FWsrU&t>q!d-bFv!7ArVpc7WiB!-uA%xwj{S$+J4rzjagVAy*Zo5mx)yOg zHe}_xx8&aGZevy9AwNJ$@HU1Fyu&^VsVWXWT_EFU-%Ra5l0{8*IBDzR9jxiFoAC%n z^lH-wvnRID)j%N3E!#*KRdAd~YR6sJ)3ceWOl~|2WWncTI1g1=L zo+35T&ZGu4d3#fvi+{Em42R8dc=?~Bi9|FP);hs(9dEl=TCFwoXdC~wy@FTq13X1L z_@9DdDT>!f%hbDH*G)GV0yx;zSw%MicR`*$Bs8eiTKKK4LL6^l2O>8yy@crSHTG68 zU<`mJa)$`N4;+s)3V0Tg3N%`Wo(fKOWm=h?It|pZBt4g#o_@oD<3|q<=lA=82@Q$I2V z$Ealb{88lcZ?)E2D}1}0F3K&tm9E&WO+=JQemF6;gEfD|_198I4gV@#Z!*tXHp>1b z506ww4n`h%BytdM7L%1k(z-w&=`;K6 zy_p;H!3pFa%Cb*>H8ma2M)g8AR&#DF-gVd83&WA|Y%Y{Avyt*WrtWurHgmJx^X#@n zeE9ZqVdkylsm!tV-I2oFV{S6+YO&!n#6n1vzYMgqK#5Pl=sggAAp$H&+`4YoSras? zpthIyfC3`~RAisLvxU8x57w}v^z$0vJq9!}AD(%Zog7GlAli+KZ_8jjHoPu`4hG5r z;I$&w5MI^WgeeI+8KHJ40jSTtWvts7yT$dTUhFQjjqTY}I?L*(5UL2jvQ|Igx+m(W zECUePrP{|Eu8UY4KA$|3+X7b+tMw&rjwDQlqCzDnBpL1;B?vHjOXQt}0RZU~=YWHR zT!IQ$9A<~1$`xFvv3YF9mz&NM<|9kD-`G&|rI|4w0hOW?S}JPf4Bv2JOf9A}fow4w zmu6bG9D48|KX3BX%umyY+m|Bqg<>q(qvj_DowyuKqxF3aPQy&>vQbhoBXBD9gn>2CVw=S z$+qrz7Y^&r;#UFalRIO@>4L1qw@(SuL z5hCX(7%fyg9GzDMC*Unc%LU4W4hh5L2j_3Q^UYgZ<4bW5%r#udFwjkCuD@7}Cw}H0 z)C=$2eqlrJeH9g3VCPaU=#Bc(>i!Xl;tMyu%-&L#hiu#XC#97fa7N z7TO&+t6{HoTUhX|cnT(F{6Iw#-c}On#lp$O8DO$VMoZY-htT_Ais(oM3uLj;_ zf{ceGPR@`B8|DNQYkFiAlbYVV@oZ&oB44;NRLD)tRoEC*w(Zr`P67#5Qi)Fg9cx7s z_2+XFg;1z4k$b+Lh$1%-l;)nwL24YC#Ib{F!jMl`h+B|y`nF0C;el?rHZsi`=wlwJ z=Ti5&^^wlV{Axv3+Isu*?D9@kPq%a)+zu?T_%=Rrmt6d@^P$4Iv;e#O6x|H>BDd6&IC zvQ4xARM0Yv)(X`F+Q<$2l>5l2cb{J#&b3<9ZN$gPto^LMY&qnG9e&1}*4v^JA@7XjMP z+mS(p2A|C(LWf&cNTfs!QrP3jNZg>-2YpYe@kH4S1$^w$R{P|^tlmz?(AEDu9ZR?M z?8Ko95Y&8ukXg3kSd}&lCZZBlJs1fg*{z=0iluAoTj|(VM(?byg@U@efQ&Q8*TvFx znLUi;Pa+!I0ehX6@PZJL3UxIFv4Cbu%YmsulLKsqjMoi70>ofp*`9U^ARmZ^Apd088w#p)(L2UyCj!Xcjmb#*AFa~@WO&n019?C~>2q4R#5y};Uv7qKNqE0LxTMKAv&_97FJ>oavggoI7s#;(ThwP~FX*GIJ zQ(lY79lxpDUm26-F?BVdX`w*Y%tkSN;)ubFW~cZ8G#da4nBipTG~qVysWn5ewqW__ z=`KQJ>0?mP6nJ*yh zS{v?jPB3cdA-VHlWj%%z{==q*~TIi3lu5GHZ(m%-pKm}6mh=lLDry+U_$?-lmiY%So| z&BSoFT$BS*Usf?AD-l!4YB4!Fp3g%`s1?iE;RMvN0DJ1_QCUUKUoEU^^NLbcv<)~v zBO97h4Ht~^OxYjF&11&n3?|dOk~o{BG&cb&VH_WXL{z9*T%vUi%RQMx ztp0sAySOxFAhJw}+w|@O%!BddU0uWx(XB|Z#(jwGf168}cA}ica9wvv`(eif9!216qI*n2YtQU(T>^3a21l_Csw&xerjGb8Xd7Uacr? ze15fJsO@ur2;HZue+2UxDyp78b?S};y^Tah#2&thL~gp{j#FFb5IKLJ`0jq!LZ+7p zeDJk9PTlc?BIyg#z0#hx`1A)jAm%MOjS0XJfUH5$LC{^vi0vbZ8KxyjVUU+?2l;Q| z@h9sNLzvCN^T;$`Yax|y_tICD)a@o)&_B( z5VSlS5(=*aiTjX_f%TzLe~J68!Y+cp$M?VI8Xc>#xS)fVxC|{qclRo&B&eFuX>Xt+gI4L_u(cMA1!T*DKpYBYGB-VZlQEwkx4v7h*N@lhtTmlY zAPa-6EJL(c;3FxOhD{@w$N)q1U#*;lKafGZ3oq}6F(1|=dQO=61bhH|45A}{mBU+83+mO@vSx(qcc5Ljx*w|YK zOul}y_4A+v1b@X-E{{C%N7<~_B$?DtM;cR6H%%_!l(aTFcY*lkG zP!7^;gKtv(>K57yOcP;eWb5C>w*VYp2W3b-0jpabNll1ao{6PLF$ZlBub~VtcU9js z5So_VL(&dtMeLcN+lxG7Lp$WI0BIQwBVi;7keW`(wM+SF@!eH9aIoQ)7J%*G{u~2@( zjM@p)j+zsz2v8@#3DzMMDyNaUlro~RNVoHXq~5Dr^o7??|7_mwrTx!C>JyVjL| z#Pd;}cK&>b6ycZIePs_`^UZ&}=ITV3upUsp6q1psX2P`<*s#_@9uo7I<}bHcK^{Wy zA_!pL{Rl_E;>#0)be~7viLHj1&XI!a79!d*O=e7P`V`jKstB1(BYMC{7rK|95916> ze>>C)+4N@c)9!er`b}v_bp-CgT0%xbf_C%-5I7cmFvG}KjZneP+$)*fSd&lGJ#VGaq`pVbfkoo{xG|x4TDM_hT z6xD|UehdzC6Cx)S>Lb@VmG`44y@lo++*EWH**#UHOa-H=uwM&}CZ>Z%Ne6UyxIU@) ze>j+bN&?hLGMSF5ZSM~IVv?pwK4cA#Q=asE@Q3}%WXh+rw@En}5q5s9`$txKGBiw7 z>u_XgLBFn@3j`%ydvC%%9*9Z*1C|}&)1|oH-LcbI1#Ucy*FKM(;rvxdI&*dtmIDjP zjBFs^U~OK29{`QNKq?ZP0>lOCd=XLwdxaGhtd@C&%1-2zayd5KG-K!Ac0Oh{hhyck zGt;r+2)dMONb4TCV>ecIOBj9{y4ES$@q8kcO622qu`}b8%fWa&WXHg*(sAc?Jr*}S z+vip91}rv*w!ek13^05Mk3WndWK@Qv=Jd=@X3rWcd_u&*uzvEzt4?LDFs@*XcHn$0 zDn~ie?I;qy31&r7)eq31xLFNJsue3JQb;9m6?~OfhF`ByMJ27i z&ah4i4AF?>Tti=!;7An^2fS~HL=m+5q7{&)VGWh#4E=)Xtf9n_3%K3|Bc&VgdF5>* zt$cl0E8E}wu3grK-5_N%3Z~*;SCDH=$o^z)n&OtctL|15ciz2Qf6eE2B?~PUX5^#W z?%lq7$uVm+U>TQtG+bUzIL`G686f8`hlxzPEO@IoRx@Y?^tezGxWkluR~VGsq0c?4 zY6&PTOfW<|HVqz9RjDdGT?s!8PA?2??qg+bu|ghILO!_wxL~huUke1Qru$#VhB{Q* zZ7xwbY>r2(rlLfmY)rM1sr=Xhf|l|QHex8W)azi;y(_Km3;3pG29oJG(uyO&cMgEU z8_f8DF;<}d#`923Z;3-#cpeaj+!l3bFf~$d0K=}r-4+PjL^+0$3bP)6d~FlA=iw1= z8#{oq?FYs(quO23Dg4JXqipD6p(7rS)F7(sj=#caCLX;@Ytah^Q%`0gIwIg?S*-jM zXxl*=>JVg+#cWs6fy0fY0F?^>Rb=q$k%0-Zx^~f{h3+tVzLKUbTN|LH+u2#|Zd~%{ zA!5^&7N?x(AvuJs$&?4jf!7FdR2IE|A7LT z#3%Pcfm;xoU8=n^dQ;-(s1G~tMjY7o^?{l@tCqWrGfKm>06-B)#g8NwZubOgUS)^o zHuayN!^Dg_h!!G!m?(k#f(3`i%X@`(UJ+H+NUpp2W6IbqpL<#IcA}+i%O1OBjOyyV z1f632Cpwd2rXkm+byW)iUyeu#ncGKbvcXQ)thRq8xlVcouN$fbB4PNp-k(L9Zfhdp zzcle96UeLDZ=ET>I{O$+0hCg4P)Dn18^1DGM6{-5N#mVDttDnR`%Jq}VJz z3C%kdUlUabSW9<&v-fs)Mwqp;36&8oPuwpa{msn|*&%REl5uwfRvhwuqQ!-|W6!qL z20jwjs=*CgU4{{QrT+rCTgXQpUS;fdjx@Pv=+$1Gp+|8)sC8KJ$V!F2HSkaA9?{D@ zWgi*zuzW(+00xHq%v^T@4h4EU7Etf}Q5Xm)^$m)#3o`*X8OZzYWm}fjx-!&43C9&{ zH5h<|4UInH_XUxLUqI~qoYe!m)A#R=U_+YUr+{zDP>{r6On6V}M?Hf*h~bqYz1 zbv2DN3yO@WGFb~c@EG_dIiack(-xieP|nVsHmqEL>2}T@@&4f--FG+1m1rB`DWz(S zuppurcsn5~9X-9PP&9UGwaWzm-GhMNrE!#5EgOJz|gbpWXi0MgQL za{(_1dBp|jTD$d67Hn@P3oSuAop;Nw#I54=z|)@?{q@ zdBZKaqcC0j<+CUe7gBr@0^y_aknCrY8VrQ|(TJ-1kafYAkyxRnsKE%Z&Wge$Z8&4a zBN%oFN`#jxq#KqK@Eh^8oi~vaGAPB8Rt*A{WERrdq=M_RV^T64W60YOiakDC$;T~! zG^;xb;4!J>ggJKCp<*nIBE>ez>kFj zad^Q3ba%=u;tL|WBp8Umnl**gp~xTV_p`Xdm=?|;PHNnOsXKsdEvCexVI(3|xM_>) z$?zpC!=BKq{){mK6-XpB7lDD8xg11DAXW|^0kc9*AwBJ zu0g{>Mj`LxCJwc|UGQ{`W^k4Z><3P&jUDZNnm*q6#ug5UJv2u#4?q{?{gjdI$c0=0 zEPz=`KwhjuYK8lP;+Tm@Y^^$U7)QaTiHM9kKg(GFeQK3&wrjqT(Ar|QSRc!$mqu!* z3XOEmbrSh}&0NfMf9{W6D>w44PvU3a4r#OR3yg zy@;|8+m)ZYdzXW?%3~g8?e@tJBajueaO;6CH)eyoS1%$yO zrh>U6a1fJ|?I-mv8{x%p_>3M)rOrMP`RMK0qAwLLMdCkrIuhC3NBm_c!iOWJ$g6zX z*(bsuxx-v6#q?Ap96ybnTrU$y9~zm2i-A5U>q4R9JzYOr;+Fu#?H;_p3wis%3KKsMZs4wU)CWl=c()t z+HV;C60-aD)oUn-P{YaL55pn(kGK>>b4Z9{SnctJN{M~OE|3|BL{<$6ddwEwX&u;L zT+|<@Re(_7rn6bFgAuJwC$+VpU9h3LLSwvi1@=x4Kuqh#&tsbGvVBTBHVX2Lq5<*- zuuZ#EAT1c&_=qfRvMq9A(H++WUKyU?);uceB<5SzDi1&h)SV=c-5ah|ma5gIO3M>% zNTv6ayM;hHjZvP~oT5zWUnn!&rS(oW1HlR4auPcU{|s;~5l{Ns&gSosC(Bx%>=VUuU0hhPVwb>8>w%k_dufmiUq;#px zhtp-Yimvlx0^nMRcP1*qnE%EDF&kFI)hVU6!t6x>eJ#x zafI9pLFuBf;t^m)OHLUv<&(+m_$1GyuR)7mCxhg$bUpI1uiBM!=hk zf?XB?R8EA#BVy+RV&{U`Y>mZ_hk$1|qAZS4`~Xm}VcjO@2f#0ZQR24oNb4mwmN>R6 zc97{b36nl4qZrE+*acn+JEYpz&^<>bOsCvt);3a42BvP93Op$i69CrqqUc(&nL9}(W2@G3(jK_n0k3`v0m1L6Q+N1Qpyur!xUkVFLT z3Rog4j$3Ig_D7N&&;YISp(cz!cz5nzD|e<1_vEb7?R@3*^JkWUJ4UkxX%6OFfW|Qw zn3W(T03_{-XmaST48C&b8AX{@&2N0=%vV@DLC$2r-*5e;D|0btc4 zA^dwSq~k0>1D^ZKUjLC<<>h*h^h1(L!5v?=Eg*Yhj=yYs2p?+8YZFe-GrUh;2|W&4 zMEFvxFH4WP>rsVq^<{?5GrPXkNl$DbbAlhUECFLbPhtPM)Z*Rd6OMcs%OS|2Or%z^Y;($KZwN`CUJ(!t3wMx(Pe=a zaF9C*1Bnk=nhORl*WEm`bNX%!P%&<*XMXL>-=A@4G>Uml*AdT0QH%RN9bIpd$kPGM zI9;VHxBvdk&a)eAKce|S$F*TXU)ICLD(ppomqvN$ZvL^<1^wtnXlq#Z(dWaJ!%uEcGtAY z;1J%^HXrl`>|p!cMPs;z(b;RG-WVucw~Yp_zfW7eC~mS(d;L=HRvvHqJ@%8=dxky3 ze$O*}y_Ycwsgw5h^l5$s5skUYX-u}>^E?felg2bX&sBq&y2Pmt-s^|JcK_KIO+l{VGT`5`pXEH*9cp9!#=;F51xoWQG-DO|^E3|!qIZ}po}ABX zddxe}y5Vlb5&>H)&#wu`7kD@iSO8)R2Vj(kpFw%Y;>|wQi8U6ugK2jFFQj zawE#w_(J?n)4UU#v+;YP`fwy;1frqjh)+UcUluXa!H|+wqhZ6au?uVS+RcZ?tr+Tz zR+5esf%7XNr_2#U&X<1eY#bM9m~=g}@eX9B3L|SGV}-O9RMIMH{^)T(E-SOJk%cKJ zrC}`=V{wbMFy2MES(F0qm9!<;5A2crm#sE*uX^rxH#bG9r7J_@g+t^18xAPrhn}fz z!x-YJP9!_}Ac<1ST`)PAv8tvDWn=*A(u2PEMyM`|h2&#Zv~r1LOaKjGq4NIUi@aTa z1;|h;h8l#T++ryE*V3(H0K>R7-M*E!EkZeN{E`v;FF636euBXRy9u19g+CGZDCP+_H<%b^CaG(suMr9FwVH@CMx z_`&wxTMT5!X4(7h!^MAZZyL10WY~N@qD03pvkzlFl9LIBhbHkN1-wXV!k#BksY#hE zoU~(sU|2t27$2$rU~|d}B?Hfc zka;pRY@xW&vFTgy-yM&gJ#901X9#y#P+>&()=|uGUcU&jt9+ip7}VU4l2+Q1WAUIG zX@I||xlU9G2Bik7Zv~<;JAD;lt^1WgE+(-Tg5W~H4N}ExIrst;=}=jriPM7#JP0}= z7LJmcg9wYlrG~{G!$A=7#`xD*r9L86($Qq#Yw2`1 z`4lsHv>|Z)J>>ycrH~^`B{Dow_6ADmUh9;bqtFG*^9QDF)zIz;hTSj<$kUp!k%f_V zBi=YL#g99YFNK4xRuBjp+=Wd4Gl8~X}fmaI}Em6$jh*SrL||%dWjZX<2u8> zx8u@3k^^3^33(fCv2U?ogd{|oCh6o3iYhj^KPWFX^RSzvU73-ks5zX{>?}A?Bqmh`1M(KG?N`3o1mW$6w0r< z^-q5*o1B1>nvTDVZZ$li`M1mn}t)%L;XU=~8z><`xHaJSPt&wGw{v$ud2 z>J9EAqxFp=%EUs595s-%>6cama;uR5&xT@#WuznVkweE0jl?5qe2Ot&ES8Asv&U!k zC@N30x5TYfs+z9mVb_MmI*+%hlr<~)OytNb#wnv%yohXhU}1vq|0Ue^9ki$ot`7|c zD-R`86p`k>d68Ywft8bLp5mAT%laH<;f=_SgPF*N79JR{%sk$Ce5Nw~Krs#FXw107 zI-?rd;^}jzi`C@e{DHBajJ?2G#e98qY;3fSlCe7z1uYtWeeNkqE+;dYWIdkv=HW5_ z4NZCMaBiUAvakf+h=jUlhVI3>BqS6{EJ}glLcOwq-M1BA-#vv^Y@pQu5+@HdP$PXL zN$-ttR1;vXx2G>f)leb|jfYrODI(<@UY1~rKIH9kd2Z_TFN6~mLVJhU{D6qHyLc=?n1YS{j9@1 z4of=1r6|ps!CU~uMJ(E;Z3cr8ladDD4_f6ed4yIc#A=SG{UCLd#w=R49}mYT6-_Ms z!)1reD7&Fwy+{|>2I`yp(Nx>m=%SQ!pYlHijb7$xkEjh!6GLV-KnDSl*d?AP0rG$n zUu7*g=x!K#-Oxveo*ViCBv1-_0h9^EPBUn@AQ_{ALv1OA`v~FuImQTUrV7r08Bi&a zWCmjbz9P+IbWwOD2jTVKcnK{lz-z(thZ7+p;7Ukt$t@FDPsodaTs+btmX~<)Nf;`q zJ87KoK`p_vMf9K|0{>ET!A4AJNr9Z)T%ZI3_@%^Ezkt!@gMh0@exPKnjHMWXNGt%@ zC1OHVE1XK+pz26w%Y3pNjYfk{K+zsSB4>D&lQ#4F!hRofl6VvKl@Mwf_Q|MI;P-Ea z0o+1e1HTHT9SV^Zi>T2ULZt!@yO)rwnEdZboC`(%cTk``BGCQBMFpk$-5Aex0u_L!i+C5k)(FeIUWJj{j=dTEf7 zO^HkgV0#{dqEV#u7RyGeJSU((bDvy>@C5hWmW419*0yO9*>fcxLV+5awoQ4{R!}*o zcVEg*@)4L7iTRRh36{#GY}^pbFb_BZ*aNE*2_gbTg4G(6d9(WynN#R>;ISgPO!sds z_k-5E=E|HLHiVoFCH9WYDLac>Bdx?m+|ok&d`=J?dH+Q51Tq%J-u;Qi%kwrn6unu1D9jd=*(N7}S1-s&=1c z08c$p`&5s@=@tki`u6qPIjF>BJ#G7gFX({a=otF0&Ny|jH11S zAn}`Q4GtDEzF1%;I#Q0sL!V4lJ-hhG*k$_zkoE>!lerIS${)mwX)FcI0? z#43O*@~dxomwNy93cP)EakkmNQg?;f-OJMq&(XUL%?&bS60U+``6zQhFSkb>Y+JN4 zwR8grU2<(xg=k9E0V$0SRLg{YZ}2=|P-{rqMr%mFx|WM*zc$~$Lvz-3L6|s50UorY zyLtKY3iKrW5IH=Hut(Ew-jiuBKLN-Y-H#Ns3n}}IDB?6jHN&|Oefe{&A*z~|EUNMv zN6jxP0fvy}8p*%iOWT}2zyUf)8@;iYy3}DhVY@@*5w(=C!xJtEhh}nN4&Hb5DpA2V zLY8OBDMBL=RmPEYCnsUCVgQeI+!kN>(c7udma};suxegPz1nI`D3yhSwYVHOgotVs z(-l5?#I~fmJ62wU%9S)*t*nb!w}s(Ro(%_mC}_z*Hh|!=4>kP?W!I%@zanL0%bTy9 zx=Rr4YWtGNdCV2`DH%TU-YA1f6)cyBOF#_Z!as5UV*j0tX-@wnvUIFVR>B_(T@J9Egq|7%HIqy*O_@T^uh2Xh5JA2{6jbSa6a{Np0LmIUL=XY129K0Ly z9pTa^cw)C9R^)0EqTaZML{Z9wY^qc#vJY>jr2ac3A#=zO4V{u8CYV(W8XZZWHwzS% z>(rV#ly?KJYW>8?lNT>OPVogTpd&FSXd1#A?18d!&6>UJA+?gV@$uT&8W4%pevH5T zF}s_3Q`pnCo;rN|KOGMLD7|`fVv9Y7zx+d9^e zVHi+I-Wa_4o(g%iypqWS^**n<)qn~1LzgbyI-a}rr>?!L&^x&DvFbj-&+(ii1lS4S z{v}F`+DCyw^AlBfDZmsmDIOHCsw()z0#nb0{)s3R{dVzuYliSbq4Yo*tF8x_VOd=unNDpcqB{p75Al)>|m+@rco)ml1!4qUK$A@Tki_jBNT)6t<0D9XXUgtwHY50QJs^I+Zi}+GbKrJSs zkTu zjJjh{=)?dmP-B@z*SF*Iqe+vE6rcQWhaskTq=etHwbiCueApPxSOsB4RV14I|4| zp?2Z|551%7t)5uWk$Y{_PcV6sZ*!4O_FxG91Yg|l>xgOn=4tu{iC?tc#q-kD7 z@pj|lMbv-j>_%LPI48GUUZntQaARCg6g(g>;^CndK6`!ISNjP!Ntefb1XhsVIrzgP z;Ep{^WrYkmP(6xZhEyn(9*jTUi)O?sG$Q6|0Wm&yVTG4N$cAGQ>LEn*?*9ifKGu`n zFMI|T4CGe7fE4SEMq#inf}cAbInVE)RaDG}gH)1;WH;pGD5}VFPOd0Q;{|#R2e@>C zv6Ewhhq+Rwa~om;uVP3a)Y%0Xq39?O@HSlLa1(f53OI~vtym(FnaLy)vDOO#6=162 zTv7!FfQ7?~FTi|?7Kx+Inm=UP8bfg>2|780;*5F%0SiG4Ee!n)%3VNzfXjR`8XE}* zRiA;BC(&3=3uVACeLkN(t!utWE*JyY!LMnuKM0(=77j_W3Ae(K&&<)Fm-Wi*5oPRb^KR2iRT zc5Ctj_wy5cK<8^gl(%Ajm%(iwB~71|pZfp}Gdv2$)^D+AxFM6cd zLrl{iI{%QC4n}?A+OhNPLwH9!wJ5`mNqjnXe)pO`4%twG#)NA+Rq$OT{P%qY zIV2vRPCn&Kzjf`$e|!tE97vqT5d$qqO!$5%;kA2KIbwD0w?$NNNo;Jc`V{_~D;nunCw%D$Ty&w``RUUUmSz^UKMZtw#E8I)mxewg$BRVlT2~j&= zc`2gahUo`Z^(;0pAR>*j*uEsGo)vLTpgzSbwei1-{(h`;pMKvfp}!;uCi;ovip@*6 zH0RCb)Vi>RLLT6?BtSp()P39kR`BIs-}lMvcSU~>3@VphW2yH_94BmK&d7)jp8Eis_HQ~$O7a_zY4KkzFbS5Li?e%U*$yzco| zk1M2B5VN2^9r^?8rReYeFVRK48Q~4EUO((VhrK2jGh+7vuy%U-haWl%p(+lbuP3nUM#>kaP>7wtGoJ| z|37PQ0vOqK*7?@0ecx~Gs#R4bRcSAk%DuR|y4~%i+q)y#Z97S)<2a;c;%qj=Ve-n( zfQJY5ycm_yFizO^(2?1otyctNC2?2E=GhxCo0mcG6OMv%)DbMda=a!b1+BUqA zRJU&3x;p1O=bq(T{~s7hU?@^9Wo?%U-7_F|Df)8$AY@j5dYxHGHz7#p) zpV3YR@-_O@c=?9@GwKpk^TF-A_VXhSW$&Ev!rSl685z|oGI(b$GQOF68#^;m&zKe> zU!NZ}5m}r@JeSCg%4zf}IZxSGg^7n}RPs2!tC%oV;N8^%W$Va;;V<@XdD|`CsnVyT zr`nan$z0~b-zWUt()(ig!6W5zC-~{+Trr<6*Vnmkq>tDF%Cv$(x??-R*pa|F z)PvgL2Tt7bU2PjnDgp+VER;RU$|vdqb>c#L({>WE=RcpUMSLV;3i&o#8@^CBe##eb zO-Bj)BbdbyHNl6h_u)5mjL1gIcqTKECMMPw>h}S~Vl{20d}cJ7C!0AzVIh577b{_G z9pRoIy{3u$B5|%|;7#vpZ1hZNoP&|I)!dPp+ojKCecph--w+yzdJ^#m38!>z zIxPAy*8`NYlI*+Up;!WMt6jthVKcY)kIen6P!fSAarPgi?qAh(XqrACG<^k1p+V-* zmy{EdJa>txZ`Oe_R=*LuThVk}>@dCGyT_Qud!~P5pc<|Q&-mTpn*!Cd)#Z16LFQzC z{AiX-Zwc1|^GDNf!H_Z1Q3%GW1d55Hj*UDB&4_`H$dOhK2VirI1Xz?`p3O7=^-${* z#^gt@d)sRnwKy5ZbGi8O<(2Pw=aWEvgM)qaVL_BrViu z@u(&hy*B!y^25~u*N=49Bujy$Ei!(k^QF?^{E>VlQ_LQ(Tt9O-zmc1%Cvp#eEER9O z`;MYx;Y-CM`6HEk?j{3l<8Z!~sL$l4Di8m=3qLq}vB?e6K6Id#oEyM_OQ*P;b` zgX5`szHT0Vlld7j*eh-KMVw$#*;s2M5}e4s*b+tw^M&!IQZRA_9PqsH#BlSACjUml z4Zct*IAXK0Z0brV<(jzC%HAc4H+lAwJ@MC%k8&y{1 z6i!87h`G|q)EXL&UF)wTZ-ocijoi4W91E*)uw9rAEjpmQZ>XTBQF)>nwxWpkl(!p$ z@msbF-3`0g-b<=Qt6twE<(kdVE;!=U!su2SGi4@Vv}~IT3|sAb^Y`+_iBo@?KVcBk z;Co^vzop>DjJ0C^_sr{SL_N3iCtQ9&KjwYG<$MH?LeL7846ALfCfd1{ScI(_wZo0x zoAy@@kU)0^b-w~9LJOiuC`M*-gi2?V#j9u;zWDeNvsBuqsF;)-Rk@i+@c`1k@>s`T zeQpnZTS|W?y)8VI(iJgAWt1vi%}9eOS72?}yTnMbL5eX_#4fib)>VuVJJGI&?A!RY zFifuwbG62c*k{CU8j%oJLiN%}2v}vvawqO{qBNIT%Vel|j6WPckiXk(*A@7GQ` zeRn(==~X1%U8#}t8$X`EJF!&XeCPWf{eZ)D$6ps}$ETgOOun8|TiNd#-=Jw>2BmDo zH!HcjUihZnzq(JJ3P zWwLGd=H`_q9@}%87mkQcnk8N__;|wiv+nl5Y0VqILWIlz6U(;mGVaF-Z}@xYfFiBW zP%%!a{cLP?^Pz`Y&i1VF(cw*bY?H>}cAf?I6K!Mm?XBT|Z#UZSpK~XIPF$O^n-AS+ znM#%Dei^nwSRMungGDMeS#o)xI%rx%3^j@*e}%e5nQmd6>1_4FaZzrnJnD|A);bu=0`ZM!NWX=ZcdcAr%f*IQqPbi&)goOHiH5|P6BB`n^-H;k zz}_$c#V^~>CLt>NicCmJ$A*7{@@o^YXNP!N2_}eo;qqX^h0VBp=)&QN)0yGlW=>D9 zgl>^M9xJzmjAbql2Heo97K_!FY|E7ri_Th!l4ZG}d@=cnkFzX|GO3t6Bk)1l^(3U- zSi5{#+yT@ylF)HAt1w3I(mKZt>1NB^q{|ews;J#5wF$L71Z*)jjP_Citd^1yXO?%0 zmTHW_CPL`uZe1=`a#j95n(>djX33DLHfVK}V$o?|T`GHw)9Qx-{b127rT$ZCrtp?% z`F9l1V%n!{Ey9S;c0hU=!xcjbKw|nt#-W&-Mf<&WrPV##I@=YPcweYhN7;UHW#u9% zbTHk5)n{!FqjIX(F3G`Tv|N6#F7$!&S?nB0_ZMY^3^%N@1qyPRge7WS(k2_HGIXif zW>gV?Ra;qtrECYE876?bYK0bgd1`~BpBw&c;m&Mj`S08L7dK9UgQ^UKe{y*B$I;6l zUC!TWuV(=RC>Y}#gM7UuVnIB#a#2`J#^Jirmlh`AyGY>yI^dSUtf23)~0(0C1fEMl9EV&@sk94Cf7mhQ#A5lXZ^)gpBzGiEIwz9p5qB^>|g z@Gr3%BuCFk*o+%&I1<<0xZO$cw5NvJAM+F(Py;+^*dH;%6YkX&+)Hc(y$)tGH2)o# z;!diE{nQkWZV5l-k(aTtj`JJNYVo5-+#a9dUv9eydhvK&M-0R33&dJrw|KmXBgYQ> z_OjL%kse~-KkY3tLeSMFy^>Cn1lfV}((sQs_=3q?W9lfVIk{{xUoxIB?2b(3 z?CXBe8I2UOwNkTOFP2it;a>)V`RsV18V3+37)#}=c*Bj>BcUzA-f;x#<_S)eira?r zhU^_k>8!osQD2C$W<<2{XwL8Q1{)_nTJYR3est!#gQ>Qgx$@DeMlKn|Q!rD?7qdud z#Y%Pd%JpkE+^n5;|nYJu%V7)IJ<4^Umlk+;0!*659Y;f<;{DyHpZ@m6`-`Bg z9DU}2;seGf1cjw||Khhl{dAYhp`#CQRgVoNDtt5R6x>LG_QNzbY zD0t!iP%Lbcf;*l{<`d3%q?D~@fQ+>}{Xugy{%NDIloR*{<6x+~aXn0eh+Q`gjz9)G z0YB2@CO|X%daBwW$lX>Kz@o|bu!Ku0gqE9lmkyBMwo14%&)Jw^Y_($16R$5!pA7jY z>_#XuHr{b|mhv&+3(Q5~cs8Po%};ekBK$3rT+&Luf1=j%Jdz;*nz2%oGykXi%VB z`7<33fp3?@R-rR~fK1#bkidatw!Sb9)N3SG8edRA?xSUF9oD5N;e~>rnN*lXvWl_n z^LEV6tZQSkMY99olG>`8q8kycF;r|Ye_xxp&Kr(gHxUMzEu3jr;_*s5;|jMjW(i#4 z($v)Pl%tqPm4n_ikUhrWx(O&7PflFte&B5`?w#RZz+xIRy;H}gGRbVI74{Qs2HJuw zXA(Z8**WdiDA?56=Xm7bC|X;!NwJ;Qe#^_Ga238lj^^_6 zaAS0Z>qM(8Zzxb5zTu4T)X(Pf@@RS0VSnOf32Gg+vY9p+>wThc#EEy!SQDvq4K=T3 zi+1iu_Lj}rC85-a{=yjJb27Xn$k?R)h2Off(A0akz!GOww(UfK8m=&hUtgavyRp8f|-Hp2wFq{h+U7 z8WX!14oOR;cDoeV>?0fs{j^`vB$``E#Z6Sx9Al?i%mRU&s%C`9l7} zec+<;7xs9R+NztI;oRlurN{&qR~CgTUn_f+n_yL@+O@xE_5*P+8F zPu+ET;>g_8sm9i0cyCOV0*_yO+d}T>K#PrEWJ&%ZD4t?Ai|5EG#tVs9Is{#+7`1IZ znWk3sWYP!~Kq*LIm{x^$K{YE8yd~0U$dNzl*_l}Dx7Qzn;MZ=TO} zU*n&g0E91^$s1=>(~@Q1e7W()a-=v-`(+Gi)^^M2!j@{^h>CKM=vC6+@z`U<6UM@c zqP!3P-HBV@^{(QH6Ge5j{_hGbG5R}LNf`j}3k2?5W}=du2V74{&aBJdfMufm3iH_% z@l{3(4pi&y;WsX0Nq`Q+ zeFsmS2rD!(vWvhW^nkIov)waMMr)9)K-yRezA-lKoxlG2dGGY$(aC+7 zBDVh?mYCyq$aEzp5-u||I^p5E)B~1wh?h&6cAVbDgAg<_k~vjd4r*NwwW(^@5&Wi! z9d!U`B&P4eq?1Iimh`ZN1mxW#fnnwV_d9lqnCozs8Vrk)dNz)kxb`Ey5SkhNxx zT5q(){?bdb8PXmFD8%*!+qA7?Nw9j2)W>b&F{1B$XEZ+Cpz^zmx87E~jlWxqw9tLZ@$z%#?rx2OtT6@p(^cNO}bYIp3Lp?AJB zWDYls{zDH9H{Q9c_zhj9R1Q-hk429$v6hT@8f7ExG5zEvVZD;F$C0k}goFMtcK>$! zIT9|db=&PrkN)wazhkUzT_TRQy>-c`AC|O3YL03&@TBFHKh4@9Tf1n!6eG@7FHzuP zhEx&l$51}&lx8j&z3h!~x*UJ=Hr-BcTS;yIRrGMf7kCx|i|z^C(IMM+sx|1`5%K^_ z&OK{u99SpTAyRrm+9y1VUN5q;-`7DH90i+LdP0G6WYOs1AZfTtE}E(2 zNZb0GcKdIx&&`oIXN9tbU;ka>k68;vmAs(l%7JQRFkE%q%yv^GJ_(T5RN6SJ6vj8C z^Gac?Ak_b4r*Vmee4}5l6%SAlU*6r^PsYv0@iWKcSJ4DNhtK(eG!fM;t=_M~?jA(a zt@OllJols;xO7f3eE>yQbl2pfqwe}--2Y*oE$fPUwrK?BBK(ksyQyK~)_8(Sr6uY( z0&HcWmxTuB8&Ztwm$CkjvF@ZVcsb~k5WnH)kW!qe0l#Vb1HbSdfAv>& z`0=q+41A23DX-z5wXY25EBJN#O4BKO$tdgK;cHV0V}Lcixzlso^b+`{c!q=MeX$=N z4@(APdh%5fJ^b+xdA;fVl)pH*LjUThy(@eAmngD-QtvvD!VqtapYT`dR(tkC~`BQqfeN_u;Q0qK(GD zhN5w&Zx2CbO1zE5f+Lm*vGc=|^p;YNE;zhoVP;^;Zp~s&Ms)omi;eI-#!q;Ckv~*) z!YTy*C|Z3fQjJ*Mx>}eoyeB`Omsb)`VqmBSk*e=s{DK~)8?Yzu_4$V%{E*N0p=T|s zaU0N%17`HYt9ReM-LEot^4sIqW*j_wt{w^3olgeGdrion`H6QY)CBkLeClaAn~Xp*?fmS)}?Sk4ux~$Dh$T^Z-SbRG(qIT~|Z%XtW?9J|AI-{<30J@Ik2}rcs zmfZ&8w@tQ-ej|tI-8%k=Vcfd_&J07TGCjZ74?)rFYmtMl9IEpe779b90 zB{5>XwPpF766xu|*AwW#N=+-yowx#-rrY+=L zd>A1|;wcuepCFR5^og}wYC!h#SlB4NrW?*yO91`A8ys$Ls223O>`MWU^H#f9IpWrd zy%+FbP*>KBHw01wqL>OS8OE&+59~uN%ZXP^-+`XPaRK8vmv(pr?QJ4H2Oy^yJPa(b z66TZc5J%=~b+Vf&7XhjDN4r|Jv@7gu2FMqM4g>3HiIG>Snsx!RVO;=6MjhH$$&BlmEF?ph_&;Tc z-4V$>=INjqjFA*~JBhsnz1RK%GpQaKB9-120OIsY|LpTXU~#Z?gsko0Q0s7CJj-ni!y4od+*F0fe|02 zYOdf_f(lC}<6f%GwKe36?$VZ?Oyri7$jJ|75|zSSp_0fLw$F!J6RptR$R{y8n#y_cfg_+00}#?DI%m zQxa8dWfAwVPPN@iiP;Mr8k-H69NqttEw)SF-?E=#l?}VsBrpgAZ4)~T#@yyV^BMGo zSnr5*!QNu^`X@Yz;g(RJYPG8!-WFf~3J*l&Iq}N+zu7Nhl3{|VG%_5>j)Cu*EPY)R z959KDACVeVy2Xg_j7lHAGhHOJstN`sc8nSS0>iinT4F|gEi+^cDV9NjXNn+51N1pQ{;X9s-INzNRv)7Liz{#@+HakS|p9gUbeMGuh2T-#;+7ELuT@-2^I z`8Z1{SSGH^eAU;xe3CQethFVcf2~zuLt5e#AfCW@#o(INk7w6g^?VBtVceBkMjwrS zJ-@sx{>57x7cUAi{Y$w+;-7c6!rtB@(1}|AIfEmB9c@>^ zdMwDErgc>Gj_lcFvttN?&VYf6r))}=)b;+>mZj5@sOXVSOF2VT&`QWo4}Z&sgFTMV z@@`-%V?1&MF2(>xi{KWRA6DGq`sU@qx?#SsA>$FA?@RD}Vb-Uol>Q@)qd9_{N1~n; zYtu=SN<#EYD54omJT|g6s=>-?CHn-oT0D^GPB21?L0S^BC{?ul8-H3%v~;}M(kZHI z{?u5YOd@SX@oU(^rYjz8#Q2TIUFP@u&~IX7jc0w$C6`$+T}w?Lsxq$^1)0wmnvAe$ zL?#1IL^F;=(wr&ALmpo|8}<96Fj?NIz9Uo4IF3(y$l9td#>kWwFV2|Bgd@|A2A!UB zUhg@NGZ@WH_!VXGNVr4!cC!w zBO6bKO8sJpWyiS?ikcXx=ecN-x}g-phu#qh-L&9yM$M7DBA&Ank&R=w0PpNLo3R_P z{&>Wj+4LA~{POg&hY!)(>bf8SjB+Q!EDQ6tvbwpvy1K0Rx0j4BVrO=-*Q?C$V!)B@ zPAk*U=8DH~DNRRmGY%Rx_{sSgy3Xx_aeGpRbBh{tq}5PnzW2Yj+CO?jmIC-#1Feo+h}8K zPotSDC|IR|l2CBe;*;9O>SCU}giInXh+<(?sVt;6fou>@R@K5$eQ7oqSU!~rh}iJW z%NtUjZeUOf4ntxM{PnW$+etcPAhl`c^9=Hge(wcUQ@0 zS6m+Ez6NWz@t1G2=$NH$(E*BXZBOmSt7yAL07LZ}J)o(0xlRz-L_FDd_kkMP*uyZy zHDBp@@AhxMa8O6=c6B#jzCT8E?DWSjN?y%a*iFpeU8_%a6C^zUHHU|q1EN!ZQc1ua zl_~fd8f+x^tF-x|RTs|R?GfCLgY?*6Xgh1)Hd+}H$HphBkMx7CPhL4dn{Bq|$4B#K zy;w`N$Q-KYj_AL3XcSlLt~kwIQ`3I!QKcr7aFhqp`nS@X(fshrd0#?kW{y3Qi}z=p z?E|Pq?XaGU4Te`#eoX$6ITy{f3FR5d!lN}>fe9aoKLHb&ZfXgCA!Y2v&DgrK+Lk=a zXaWzwqPR4;*m_LsXqn^EKVJhm;}SUw-)wu__5s^>*nSw9vWFf^IOlFt1ysPd6|ppl zc~CAcvPo+XrnDFuxzton_iUl+I=KqvLQghxa2xra(>iaG38Kk$;kQs=NN#a(AgIWW z+AJleE7^|$lEh~WF0q;F!5uMBn*4|QPQw4nM8)KnFi7UJUNaFXr=8@fbUL#2SSk}v zXA)q;fvVtjkUKpc3#Y-12;+6>HKLJFG8H5Pp@2aG9$j&jt}FL@j-czvjn!in&=(!a zxw73Ltzcp0jZ@M2cN`=AC@73h`=N>CX@BT?|NB}uweW&37U%Aojf5ippm9HOJ^7vy zkIv__{&0SQ+zW2Q>vej}Sn4oYw$u6AY%Lb_g&kgxBa%)`ET$$R=~z04XPlFK(9X$r zvzSk$f?zy?#25>mG@{|65p+4qkr)@;xy-b~2dd@dlrtVp!4!8(q#|;<8a*TV>mKLz zr9%@pG~Kbl^ldYdyf5NTSiIVX@i^S08~G@td~?to)q3K{wC8QLyZT|-%$Kivf9!m! z^{n-h{Z{jfmlXf!X1;^5(yd^Y9pOK$3O3sX0fCsyd@wWjICyBoEdheq1PFqSL&ll5 zUxwg3WUWxKRdrBA(BP|Chao8@oF2Gh5^EqiO6ExqD7q~eGgN@WzKMYo4pscU#MjFh zKso?1qNcd8@`5i!DpOx*__;#06^xVoD;jFMy^(mWN01AP>$0)TjlL~ka4_6lLAAdT zypYQRp^*%`1F@(-=<;SF*)cF*Tdhlj0qq{i5u$eyoxWII5fsF|52|rWhaRQb?J7;n z{z_Re?2yOhG*HC0P>sh#4v4WP2hzAS*wy$x>;Hvn+_eW?*jHH=;RPa3T zhLe7Q9{8(~)^Yn}4<#yqV7LMHCjIi9rss{&13dF?dNwbwDR^5`lQN#!atgt_e zC&hv|!)m8}7!z15R#?3}ZR_Yrry#P6NM3T(?o_6hVNl}sRM6=$Lniz{(`85=F(_Kl zZ!@TO`78BIvscpRI*(>C3UbTXM% zC;B2IC`0o+Q82RS4cDJtm85E) zPd)zFTKnQfElBP}D(Wza8XDmvwwqYHUr)wa68KqEGHHOy(-de=!5#p*YEZPd7ZxYYx>P-6h*~S z#Mh+uF%E%`@$rmxO?_bbWnn_sA<%&HWvTNg&bnV^=~2nxs*f zSoSWMY%p;8lHhNI3JG@K3o;zrOGz#`=qb+$0wH?&5cg_8LWaWg^OsIwTTL-NPu=prvVTvzwLS6=;5S^Xry^6#i&m^|&JvXXLsN58 zcNfoNJX^cc9dHS(2w`BMStBIuk3K<%q#PI5n-7~YXFcz7zNh(ZA$PQt@C6f@wkH_! zk)r}gr(bQ97Jt87?)OU{Xp}pd>FkC(a(BLN7=NCf{);d%SFNBg3tXE!K!|w=&-q^S zNcY|4!~On|4{!#(ti3!Z;g7sLC+&&AJZma{jF^k3ueUD-g~D7#$kQX@deN?nLPb83 zNV>he3E-hf&MFkn2E)gXY&1w=tAzFr$O5{ea)0Kc!^=7ZZl$%t*914Mh+bFIB0lG$ z)75D>@xBp#NM%u+wQFpV^Tz~RTWLaNlSG%CTR`BX6+kE9_P1$oy;ay8wu~?yFNs<(-Ycc_(wi#v;=x)1B?Z__ zzf#8KV~_re`DCFhr!3zRMj$DHt4)05#VsP~hE$#{4)gdjp)72s;VeDrhVj|Aq-Kxy z7G3#ruIzr;KBz7gj30YyaA>}tNZ-}8r{0@5Rv!PRMxo%J>4ofXafY48d)>nDfj>U{ z#<52O6NyGR^^wpql=gbwNeEL^>C^VwnXD~qpEYS@q}%Z4ZM&>gmbHQ*p~l1}`q$^-^74$&8S!mW+&gPE+Z1~i41nZOLDwV9 zb9(g2`aoEzXl2{NQ{Nf%u`Mmnt(1%T8=K=Na>eppQ>7)d7-^>JW5vY61HRx}V*oH3 zcf$1+?mR3OqObqA@k%j2mQ584<>fT@M$^SuVm0Wy|Ir7-Nzq^GIloGu3-_|)*FQ3a zTLxUlDJ&ho7C$AP-J&TUy>H0AC|p!raR9$(HiZi_=WL|Ew=8ni! zK}Ero@}CzeM?#wPk&)M2?*KiY{wK(OvM22z+}U~~ zud;2hvHe#P`|be(UsmgJI2RDyPFZ+q%rZVbtnK9lh~)Ux*Z61y`KAVfy@KJhk`@o2 z-t*Ho}OG=n>-ztk~g=DU0E5f2m1HTyyfJ{x6ItvH_A%8#Ja{>zol#_J5fuv zIw9LvhjF{8N!Bs|Srk5*Kz16f-J#dR-y+wDz^@>8_K{(BvyFhfwo(@__F)3F94?{b zQlsebEh{t;dB`JrDHXdeT+~S5TfK~H3nB%5zPcv%WPv9YxNok)EU!ybWUUt8 zmp3r3@QKG0UXK>k_~bZ1D}(S;#X=w}kCM|D`3#f6<4LK7hn&>dFD$i7%Q7mCKGfN3>*S=BDA+%=_%l!%m|glA9A}9N*MheD4%VC_Zf#qMkzwz+JFuoCJMb!8eU$&p)`6ynXj>bZu0(LY8>24k4mO`)s z1{F^p)^4}4y1RNp{fp&$@2wOkzxk0wF>_-BdNNY<+jJoKBaE6NSPX zit*r=d0S2hV5i@R%=q*@12(BFJvrvsLkL&N{Pp9Z9(_6`lpQ1rfQ z(eXc6pK`3)6WbgKTk9^*2+KTo+)!ICdPJ0bi%s?_#ilf5tNot*vU_-$OslX)+4Kv)hZEJJSW{({|Oq8AwS<~J4atpdy^gIssoGw6ajA{!v{_(&2BO} zun#foB(|!#v<*kUtpeCSF*Y34#8@;No`}{Hjbz0hs?>@xvu#Ft#bd5k+wMLbI_&dy zGE4DHvSB*PjaD^VDHcM*ztNhH3C(xktMxRip-8kD$#`4gd1or#jAat@nQ5cs1Q+$&BA5GX28VON#nmW`}ai6gCVyi-N9DfmDR_G3`){`{jy1=G z#-DIFAX3JjUe9%A6P-nbbd42Lw2Ab{z6>IcF2LI?=CX&rAjv^SErg~G38iVjK-Amb zc7r!|i61r2_q1Q(UGfz6S3@n5GsWPQwsvm><=vG@x)fcv>USzFAw+;f%UkyxTI-<-H^(r6r>klbaWa~|;08$XFiH^z??%kyqmCY!Gz zxnCS>*jv3x+;&Fm;ud2xg?466{0k*V3C=orw=zn!+FJ&PD~SaMjeJi~1y!`qh?kWB zZ5dFstYd7DtK^#}f%&0&V;N$Hf0T$FDOONajj9)Bw_g8VO(=*CZ9EP($cCyJl=W&p zs~dJWo*0|2$-UkBs#2tn_FK^>1?bP)S;Z~GENgNaK|y}8K8XdP1Vf`gf#fJ_k?<{u z2*(V8Es+(efqdLs;#02(&Vk%-+%xe0_P-4bp7Q_pZ~MQ^<#G9fu9zo~NEBfx{VtN1 zI(>;GDeSz#iBv94`oU1Z?v(sQIFAKm4uh;=ZkIQK#fDtX)roF*qFSBob|*JHZV|I$ z3#KcQxozC#60nA7I~kqN1^tm=GEbf_Pc(5|9&qwEfOL*5g*_wUkB0++sLKO#K|<*= zv|oTqS}Yz#JfE~IuC#-dRw>i>CY3X>{g_U;cWiUB*@N3Hj`;)q)P^Q4gJ z%aq@Dv-O|aNwpm1H|T5lg3QgzNU)0J{BM|C|=dP#?8H^PQR-r!_UPR$aR> z{WE=)`=-kV{}vQx<^D?fWg7wzgfu`o-D1${x-7o$H}LlqV4{L;QfyTCX)q6Zmbpc% zkS%7IRb;o{SWnit?m)H)`WsaxXTGtyz3DT)0PZ6Icq+VJw)(PCjD%uTZmrZS>K zHvW{kbenYp_7tWh6xd$cp=I3C?!Fu~E|iw^Ut^Cq+sjck+{~Ci^_2b6t01n3t!UtR z_YR4ui$-hQpVMCf_Td^mW~*bDCW>g0xvzkkdpn6XfNhZ=|3!dZ#7EiKa5+*_B-GA1 zT@s7MT|MT&X@@I@zg404QYz1fGEv%iP{`h zL5qw_>$qJ*{3BM3r>e#%u99YjTByTH1L{&yiZ+00v6rA!*}aQ*JQ9u}W(<6w*4HnO z_DM3NXs|$d{&XQhr(GLNpq%d?m0&RuP4 zvP14jiCDFzMJyqpyQ)?hTN}^WeD6evrBq*D!8AlcYkbyd@--fyh0uJ)m0Bv)vE zmMA>Wl4uqLiDnz)4$(?fyt01czS-^I#ECHoC7#%UL<5UW)tw?|EfY|T1nw$*tQVj` z>hZ@<<^oZB!k-lkmXVKm45;{+Z$ z(!p}RU1%0g^18>72!TKp#O-q|W6qfwUuG{$IhRRzO(>4z6Yhj`Vu(_<|9{^jEP>L>_5)P5fN{dCq9kQt+sn-V*N4@rp z^NX6jM1w7mmxD*__Ip={ms2Mcho;NdSDaNSI~tHLw^&C|eaSHaHDYRX;?^js+J zZhP&+2go5eRYJ|1Uo7L0pe}KE5jUEt%K4T+v_1+C&+iQQ^DF zW@3Q5W%N--*u!!6ve$Tcr~Eg6>NV}xEVmNWu;TH*^(kG$Q%^kdSo>eDDxOJfpii=L z&^OnjT^Ja4b^7QUZO}cmza7ed!)lAJCxFdER(Hh|=`vrgO}gM~wo8?NjkXy||08ym zJaY^WTk%T3p`W&(6~l@l3uFy{o3G_v^#?>!l3;&VK9pEb80}WK+&ycWfxaL7zv0&m z#;0xv{E^tvW5@$oL@~=&#J^QI&5riRLEny7$)(RMoh<)gt>80*V}e#S7G$2*E3>oN=7S{Y4#dZPc`P2NN;<`{+uFz9oXfrW zc>A_LjRzf$;@p_s8A_C<%2x`7lq-c7RxAa-Va-!bV+oGqrh}+-5r+dI$~xdd+*V#} z+CCr(3AZ@Y?Qh3kx`$uV)Ri=?U;VMkIcK{$asNcK?VO9wp4!){tD0dbic^aEe@NXq zi?2=6G?PX=K6~exRC#wJX_n%pG|qx#wUYd2FfSv0??^^x^^{@CN-ZN6OltMGndCT0 zNo>oAo6CN-FN`!(xV@^*IN!A}ip`9#*7?45i4)!9#)(_o&NtdM8z<*?3yq~$oI)X^9Osq057-q=)o zy}J98%WZv%c-^4%c>-ULvRPBCb-BbP&-SN?hvMC>sp#K+qEbvcz1$n{;IKk9yem?u z{HdakxGhd1et)9vbdVX`A<3|D%iMR~B3n0Zm}KWBx%jotTl&AtFZaFUU&foS``ujQ z3>mwn!aW85&^x38htrNb9b385=L-+2vClLfhqm#v%PP&G7O2%C0JG$>1aUTZ2J_BK zKCcl8DTcgAKb|cwllAmLOig|Lk|Xo4mNPQr*^AluW6wVOSUf8Mc`xv~gagV&*`jx? zNkWrG=OC}s!L$(82@&ZYE+J&NKZt^Pnbz_G&iC@=0|;1IxlAMyJ}{SCYVZClEy z9x+>=gu@Ro|B0wd=w8ywh>;NAWl`;Hn&z@;DwcLxg-XbdDSAct&nxYL>I=#e{&2?* z%Sr$YoA7)rfFiO9v(;59l8#_JD}m0ziTIAfT-4``#nTH5zf7^q{Gd1_!{)O3B!(Sw`;y!()zi^V$(jpRKEtn*ce~>uf{L2 zj;&y2u++C1K{cOQ>I_? zFE*d>xX{*x?e?%QT`8p>dn{clr9**0NUlH8Ocl#1f9Q+uLds!x`+x!VIDNoj$ZD^9 z$#456+qW>vXobn@j<8Nx>w#T##7OPyq|r5Z3MJbT&u~{q?Y%PUe>G@y$1$x^hHc{b z_zmBC!}#%ug?+tNOxe@B`>mK(pN&%5o`PJ}cd5~-)%OdTX4n~YIi(j#>1eFhPquQo z*2#Kne+QanV{Z?pDwHiMVPB1^QPxh;%zAh+RP?7&!W-+B#~1T@C_{AfLW_w66oNnESGUt3)|JE?*Z5v zor!k3<2L2vEY@fEZDUgfVwMV_h&>T=8}a&*3s0C>yfoo;k*AWt1-Cm@$S2dGbT$z6 zMFaUsXDo8+oP%ZeNYyu{J$sXZ(ck!7SGpebFIY&od*o!`cArW%}^#`Z&f~q{k2FXj2A2H zMaF>Q?sl9~C~{B5lk_WLAi4SZoau3n%`a$HQs6*u?kGyC^OK8rl6Hg}W8r*#_QZ+V zdOjTEV|%p)ufNlFarVHmPX_EB{!-XWr9_ul8%2@i48{+Xp_f#1nHhX~BAqB_3TdlH zPMeKJBjA?UQwCQ9$XB1cK-~1&#Od3+lk?SDK3@~c?l?U${15d^I^qlBxfO_{QW3#^ zjfT8gPe6^2-yr~ho#!Hsv8Ob32e7|zq@&P$9$OQRfF(@AITVd*R`E$@lqh)&8|H{+ zVLFqDMiZIog1|-2R%cZd^FsMVqk#a}fNlwybq5+=SHbO@G9+zR_e}Rl*^I@^@)1tC zFg$+O=XBH(lRgT6>Q9Pnhlp=gPo9`*HKFwPPv(Q%HJgkM+p z^>!=+9st4sD-gkrt2_AAq)sOC%f(Ko*jX$t^0%*ddG6;mqVtay7r9N}sRau?7R6ce zz$Y#>izhTPA1TnUuKn}_ola?Sv80ass^y{HAoS>41XE2KZ+xD78Zx(PSPWnlx_BX` zc`|B0RjAd+?8fKY?K3N9Fmx{7zZCX`bJZNjrTZ5Va=Ch@-F>iUPsVeBWEvJM7f;%I z4^p%UU1FpfFq%Ee^-?>fh*{O70v)z0eL4D-r3Brd3YNtwdc%x;HkPf8%da}r>T}KV z?U!K5;8|Pag*X3*Y zGeBoXUmJWy?nk99<<^!wft}Q>8BxyfsI;%5Kx1wnQ0FBaYY(n!xVbr6uSe}16I0Z7 z9TIq<8>F4Fq>-J(RTYn_Tv<^KgB3;r2`{#` zK1YROc1E4BzSHh?(Z~?KcF;qn=RrDVuI;Uhr?K7l67RZugeB+)ZGjzizyWn$p@&xh zQKr!cSNxJqJRNYdZfDh8(|zthJS&J>iKuVMV5E&O`zY8R3nF^y0Z)RJ_NG)tg}d55 zpdW=4bX3{R*5!k{fFy}RiyH5A#h$*1$V$517cL1n?s%^C#BI{#&7Gd#Zu%zN!ur)i zO$o%Kc6$&@XT-oEEk|D2X}!y8?e^Hy4Yp93t|mqLVW%f-G+&QG#(O**j%Po+L)|7G zucJYML1;7-v#~N-VuQepJO zd7x&BFC$K<)^e#S-ZD3K$WT*8dV#6gZV}FI%6DeJ&o!HAuJ7&~oO~hDV6Lm6fxfgz z?kD%uNb&Jy_yY&KiEunblZYEqf)0a!X{0+U;6g}2%0_n8F0!oV^rMV^(r*g5Y|Wio zec^>cDu$Zn+<@$Vg6Y9QcOwhA)MzyFfY%ufvdLe}#z+Jh%Px$Yawl*;tTg@0*;u|o zw!nPD8tX5qASE4MVe8@A(pwT|JLOqHuq9a&@vDFeSQ-zWMyANq-<7^)de#>jpAd(F zn?Lw)51&>}oxY!eRsG8JE$LaGQ~X?g!QR6kyjgCV7!UbwVJT#DJ*9MacLpJWa7pR6+7|t1wz5_nNV38fN$= zG)*^!IkTst#)W8VI9yqo{H1VQ*57#emtsin*NZ+>&2L?rU~TLz+^%XItZZV-92Fmv%J>=8@q+PLp7|))3fWt%+2ZcV=tBt#FJ{(=PZKX_ zLRd{b7MT1R^~fb2)S`Fkj1(}&yOR~q_?gtLx0+|$XUwy_)qE4vrPB0-k2K{tk&S!X zvtypx@E?6a>~W$0Y$b*LS~~frsqvYa@u}Ha{r;w`>8&hQyk_=s86%Hp(t*j@intvb zD(*_XS?!Pq!E@3%=YUp3NzKGTMbBU$A_yLRmX1nyn_J_zE*w7AnmxC+cGo*5;+b<_M7y;PbIOU_+P8a!Q7E(Crq61UcaN5gZI(aX?(ak6H%7d~8UgcoYVuckaL zchUG@E7Xh**UOdgMDT|l^HYgh)A{E1pm(@<*jROv4%B&n0Suw>>naoO&g6T-jsQtq znm=4<%m|#)XXQVP{!6yOz_9)F%*@EZ zBmtUrC2e%1r8qGls-;bjbK}K)zBoQt$}9vL{>f10ScZRU1Qs%-(O2zz zOQmC_l3#&wsV?C8|20PN?^6;{k0gFQye$MSx#=n44XHdbKyONu^+Kl%mbg*WVI(rD z8FTILO}(aL-rM%xJ9GPOv-f&i_nMvM)JIy^xV~YwPqp5WntiA5;fKBNnoYg4eX4C9 za7{g9Yc9Tw!4rK4z2=b>xC6D2P9JuaFx=T=X8gzHe5F`%RPxJ($`^SRD|xw4SiZ{6 zcu9Tt9AD%sf35BqsGI+3#!p2~8W=^kR*xyW0>FxNB*gBaN*O<2EK6l)gtYRm)2j%> z0Q$kJZ&7#4GsHnf_0>S>E9%Of_&6|XENS)Hhyx*1$AYPF$^IjD`OYW;Y}bkP6*y9G zP?fH5ucqwC>xhpq-7BK6<9)bpZAG{0o#{5e+MsT;t`a`e$5&|UGTB!Y_r7YeG&)K7 z{v&g<-M(m=DQiqJ*RI&UN_#MFDm%T%i8_7{JBqPBJ&E0Ya=O);YGHHdxKYUG3+)so zD2FZne~Wb{slcMpmi1^eTDuN^Y#8GHfQ${>C>sYGxz<>U9i3ofwTO2+1EmWci=J+e zA8R=L0`n-^xrrn0U;sDeyfA0k?-NB{yC4t}4HQ!~BH;!mcXgUh0``E{HJ7ng>1QNu zVm)xOdW2PgZr65FoJ@_h`1z4T#8XFy-1KNRR?GYD#r1e7OTJy-S1q*?4wkds5#UF!evjn0OJ9}m-QY8sibeI6UbgmAU_fG;+8l?0k1D zjX$>Ei*g*?PKV3ybGr*X`bGrtpq*MqhTm~$SL z@hyUj7^)id2Sz%^qdZz^F^IP$64#v|I#QG*(l2d6OA>%qlFF+Q%LrC>nl!!9=)sYs z8{7flI4n!rv*b##wYpis1<}t~3-~ihPoq9|tP=|RO}up$i0#4tAb&EZ;}XxQ219Ff z8Klwrr^h;Rui*(E9>aEQ2IBFhMC|9ILC5jrUpm~KDd+Gv?CyoO139eP{VM#696a~gp5k1BmXx>Ytcd~=tG!$+T$!7 z3wZ*OqhZf`ld7mDahpG@34S zH>|nU&1tMWsG@;`)!i)pXirO!g}_eY?aPI0b*T6XA;m5BgkRdFAT^@(h9{Zvt7Ss< zVZh~Xso6!(Dh%^L5`)6-iU~K9l@_(XMhLGT579 z(0t{QoG8Mecwnh0eRg*!VED4mkk6T|y4?JjdKil;?oubrarJaR;3E z`ea?ckSpu82ZC;c1v}tydn#F{FXYVn?EcYw(a%iFHfi|MJ8j=*dzSffjq#1B%JXC$ znwLq^Y|z_aS1&EV{2gPCNpE9M$Gwv!38znbdqzE%#z9LO+z0kywr~mApMRxc!nUw$ z92k{rJp!YS`6uB6S-|7}Q@hn>SH=fgl-usBdi>jclkw3v9F^L@DJXW+8k=bNi}LJ4;*WRJ#t_RyR!>XK_9 zLvRgfK6Nc}L#)^|cXL~^`pER%#dRgz!MHmTGgAAep6Xwjj(X}@{p)_CFX9N*-0_gR zHs|xXqP{siH)2sc*AgL*x)xE_K4LbD(dKOJ@VLQ5lzqLHRg7H2+2|%bv7kHB{B5_} z@asWU$uQw$a><0-ca7(vd2*5ef@r%W)!4XA!g1!AZ(>a>8agBkHJ~h)Nw;If1v0P1 z>7^-2iAPePO|e$6WV|yL1x|gN!>iX}@XmL#o!kYaKtr=`ihr}fA`ElH#C_nd+;sc` zpT1>V{zI0w0A+P5g9VcQ*$l;a!InW6?5KolXyGBfn>XFVsP6e7Xan-}3^^9zx30+M zXRrmDR=hkx^T5KWn>h3d+LHS@7|T{XvgRrgFNEV%Z`+tdvYv^4XbV7)??*!;);#3v z1WSeoF3Mg)l}Kh`b^z%^c8KGK+9Om^xP*-rB0u|A$1B`(X%L8KMJjffRj5xg1%d}=~Y|R%Mt7W4GRz~I}0d0VcOGh zd7A8hSGOWEU5Xyq2%nEe{fONib2v#j?svoj{;~Yqg2o%){mi?)``Z>RO_SQ$YMPJE zP)+k+(oK8FABZ_HnNwDbB{ulB{D&x}yQjgL_kWVHFTu^&7G1JQ%bwh17{y?|dNoc= zbTtAM+A(^eYA#pJf`l5&Z7%0xtM|K_St3m2Y7->vb}qJt;(NGBI(3xXqW^jUfIa~g zsM3$b#-wm@CUA_>;ChAKV5dRa?x||h-RXM>$GqPai^U86SlO2?4lg~Ii{1Zzj z$8ujueJNE&IMOs}xaEM-kB!5zW5y!yBVMx75N0oGbgU2x zS<6gYc3Mg8K(>>CH0ksGSkdeI@RfFBv9TeLU-%Bja$CGdV!mKtYfG|Q@^LK&h=*9= zY2D{YXK)4>Amu#Ee#?W0xlhUN*{HE8vm@i4BpylfNkjqptiBeZ0VYbu3fF`+MYry8 zuO@A&Je<&pqzKbrX{a#ZJm@cD=Syj zaj?=?AaE;KSxI?6Brn-T@-xe^zhT`q&?}=(pCn!u654Mwln%%2DEpL(9<+k`nSln5 z_r#@N5zC!ET){%tM&X1#OtH_xMB{-kY7CwirEM7l_>G_n>SO*1%-!}QNw8P!1axVI zI8jCB<|fIO>b>#tJ1jRZ6hh!-v0>SkhgZgX@}03vm89&Hh_1mXJ)KpbXu35ZK$9zb zD#7=xllI6KrG#PD6>%>RtE*^aRdH0-8g9OL^pd9Ghc?)lRpmQ@`Zj?EKXSk9t%#z_ zeO14V&yn{)iu%RYCz@Yv$bKadJ)|k6H*%KL{Co7DMBX@loh# zA3di5o(4o!%WA4=NGq3KTOABA#tC@}7~EJth?2wH1dp$0V(Y@???} z^hAVeD|APmhDqur5@OO^V^ij8Ul4VfPgky(t1CxmXOFI|Zb_jRWtd`eFqda%m(6W2 zw7ehK{;%fGDe9C}N#=A)e8R~C6$?D;i0@Z7oT;Y=|;DvX#ds@MEt z&WHugP_~#fJa&i2U+|W)sr*>EkO;$*XM?dosuGSm9dpG@(zT2i2iBb=H2Jx(ZAn?cyX^Y+XDprM2dX5ogwwtw63V$Fc@CZywlX zgPdZ#@gVUrh-Kx21WJlYzisvj=~dQ!J&gKoQ!IQ|-PayFx+;OS7^TnZO6K|=6pY@X zU{s|9D@$gS!OE3AZz^6BHKR3z(W^0ph$85>>?U4+&O`JO!oC(iP zrFSQYiRta@X$=NshK`&$5|aG(Dtiovfd-t>$BpXbB+Ip)ucC>TG&17NJMtzS$s~JV zBDT|Ls;E9$WpPRKboM5y*@YW1wuhwq>PJFf2_4x@({QkpduGob+69q`fuNt!?obMW zg+(fnmXemt zd0EDac%-lkUSv6YJU8g@f7nz!sM+s}OQlk^&?o1XBns%Ci?L%T$0xXrY{E}7V1QrVa{)D8`Qx4-$i zaMZLL1gL)`AzWnQBlHivKD_$Y`o?R5)x@AME@s8O^~q{`jry?JV(f+$N0jtjRpAe> z{s6hesWj?4u*#dxf6`1*ZN%KJ??h-;Si9vRyi zG71|{#5cW|A>SE+g?r|UMR*}L60_Bxnq8d^8s(*OsugQpcf)w4)F5+dsWLNvsO60q zgWBO*y)vlh2x%V<8^^`DH#dik?w^SxNSJU?ri#Wcq5*AHxuY%=d_il7}_O|r!E9u*2c{dvA+kW5UG0yPXwIQ`;CMIUc zvd3|doJsPh`e}nTbb~XWc!c0{&_jp6eFWokW25%*kJm;=V`J^or8}Q^BEPn#kBT4D zWr#0_q_nb;&Q4S$@<&My^~td5LMU(J34YY4*S{x!=~C|0rM0!!zyAFB;pe4TWTtH% zPx?bVkWf7A=?{mXp!G1rsdsVglJsQqzPnG}zS!?CPM*&d3OQb5laq`6R-K z{rm6luP(17aVDy#lPk-s%gd`YO9maXWQyL!H%46NR51X$!H9?how2oY&QqDFc+U0v z*2%_lKat5K`j_>a6k*?0jsQg*R8n)KF`&pBJTr%9JU8_F)(I<$q`{@+!uWWBlGR&F zu8rgDY4J;2><1~vz$`QQ2F0z4c%waIiR%=m5r$E$it;qH-h#kS(V$A*3jdL-eB8!5 zgz?D6*ILUPg7Oq!mASggrJI6D$<`i%jGP^L6-F@mQd&q6I;4fde4*?^a8ZX#S8s`b!$bMTYdKak`1J3HN#C#TEGZUT`;8oeHt=JXdv3DjTi0#`m?{Evy_R;^@_&+IMuXY{lKMq?r zOFuHkEINXsPpKnTlh>EkoNPkdYb2HuYFk`sCU1GudEtmhsTZl(Jp8|DdlNXv?&{9B zuC}XvySmy-Qb|=(l~h&TwW!ofb+_Dhx7*#`XuHZQU>m&9f*1le;5dVT34u5p3DrQh zaUc#aUBi%<2~0A9P|4&o$qe~~kW4kq<0U{|CL!*STAXy@H@Cyql&3q(gp~ZVvJ3crMT6n?y#0F7#jgqT5{r5-~Hwr2IV<@ z+!4E=?&liv=SvhP^qn6+0~#ldQ?dlQtO{UO)N?GHm5xn)#jnV0iwR1mnlH2a);I^E zC!XhU|K!c}$!OxYLm5W)(lhn-pe^P7r5Cu+7p&LiJn!eubMMb z@lUGSlGeS|a%$RgY8QRYABj-Yo=a`@Xinr*KB?zYTMCt zJ>jp+HFGNcPNdwzlfiD46`$CeJ&xv&KtdO7J3lj52_&a7`iqO4bAB+3J0kVb^GDK? zifcX4N<~E#Q5{fMnfZ`i!C6b(Mm38dT@sRpS^W%mCUa0!zx;1Rxy)AcE})wesmaBg zZb{sISM?~NtW=UTM_`tKa&|Hcpf_(=*~QwCwaRq;!i@mD2Kv><;iVhw2CL%jIMo(S zygHt!O`wyXt6T! zR7otqJpR#rv+3M*Z{KV>cN?rL=^N4apf4PDOrmBDX0kEnbV%y~-4&Z*rzeyuS#eju9KtoCgh_9HeQkFP`&|ZKue1Kx=3wlEzB@AS zP$V2GrM8E%Y(fp-;-k90{b)9y^akw+e1MD~L+b=R*7SEBUN*tF`AncXGTC4+I_45V zr}7P#Nh$`P84r19s;66PMzenV_0MVh7(IAJ_G=x^%AV-AF5!Z-vA%9Q zG#(wG?9v^Up;?DK0}GbGt{qu>oFYYp?{9I4C}&-{c;@;>+=$gHcZZGefwO*p+Rok+ zu7yk4Q@ObBWIZ+;n=IWGu14n0kmlDXy34^n@=i7X_O@g1CtB5&RwZm&l?c+R@m$^Q z=cCuBKAytN(jRH$J>#Pd?hnf9QzY$0|0R&s3E0I;=%cPkgZcBwLFtLz$UQmHrHT(t zXVk|}adVFBd-&b=N{!DCa5}Jx#*|@rVY9#++ijg1cn5AO%ljqf7YXZ#-_OpqfesAXr@icAt8~(Un@dINbeL3^T!wxGo*sB{C?W>>`PLiDF zEO@^=;0ZA95Jyf4mm*-w6K(9?6K(k{a?#-Y@Uz&?onJYxn1>L3q(bVE+xc({LkwD0 z(&R{PjBP&99F-=6d7&>8!x~^M=TD_h#R`g1k@oVZ-}9}gZ=JuKxXZwA>y#kU-xB)o z80{w$=Fo(QE2idTFe$TD>s%p@VlM{M?}&E;vvk{7p14$UK+$j2D!sSrtR!3gd4hEG zf(ds^nVf^8^6%?+N_?fUFGCgH4v@M6?VjA3)hc|ToL$%Z{mTHAcy#=&AMO?Dr z_+mWwr-%SXu3i~jPUypdLLdN!1bFWY4 zM0DNxM)}OVXZfbXk<`gjSI0Pz>8AIZ%f?4Zc~nxEC>5S)QPF95Cs-$QK?Z>nig6;> z5rzk0FBu0xc^G5IeEx{lw!+wjk1%ubbr zmMk$<1Y&J;-CIGR`Mb3vFsU(Cm`cPx|D?a1JhV7BUP0^|)bQ{_JAXZ>UpQavO%*_g zyzRH+mSGq3q4`_qcdK~#p(ES7)vJ_dsg3Lej_pyxw$>dF2k|t9ED%4LCAA{%L;Ira zLMg%e%93F&&Ur$s>&fhTHaUpF``d|Aikzs`w7$MY3_c!qH>^~*sbO%jD(wOgdyO+gO+Px@O0T}oftt;~uUnzJ!yxd+!UEf!pn=8-HtK+w= z@UIT8dTbr}750c&o3Ma&@EB!E%UT3G@hnNY48cneSqq5cK zZ#d6(%OH&|idanNmtdub%s4gxaTI{i;rfH>!4w&0-X&}k>Tg1L0-oc@&TVXvRJc@jV^wY} zPZ?7MA$5_+*K+l_Q2mc{)6-d3w0v9B=l9eP*4*RSs9h$sN`Pd?E3cjM`N*}{kAjvY zH&%YqRbQUMJ5|7aR;?Ir2L8&fMxv9=cxl|_%9h;KgAGqHGaij$K_-0Bbi zk(J4MwbUNXO}HIlwD}(>YZ+o;f-qY`p=m~Ys4Zk2aW~KgEGp`Yh7VmI`nK)9HuM@> zx&mBB`&2^NOSChY>s`9k9_Y?=yL4TgG`4%|!n7J_E3vlk)=OoLtmEIRP4PqCU)Sow zR$sJ^q%4OCliCGC670Nx@nTmC7Q@OBfkC*m=9a4eL84Fh2}6A_nd|ol3O?%S@NL3( zjI$RLn}PnJGjOl0;~S>{1Z8wq0Bs^MX$bZ!nwyV)j*xw!$yakI-DHz#0ei z(m8ZOPQWY)b0J|DghwWyXzqlTH$PWV@~igj%}HbjODS@d2hq6Fpa>I=83CI)BIyoHXcP7n2W?XN^6@0L%(NF*@C$>Hv0V?lFMxC3Gy9U$^jH0 zGp2zPrp7C%b+D%%2VQ0^*pVPzYGJ;3O#rqiy7*F+`EJEQT%%8l%m+;`uj&)ZRSb%B z)c*b<4t`>!Mv8K_uIeF4YaDlN1{ zBvejTEV6WBdVk6K{z2s#Nz_jCdQWJ=@^~^N#VN!E->gW$Zog_tv!*EHS=Rqx1z^2X z!*A>#Y0y`w`6lFwhR!{Om;khyj5D+iHbu3@?&(#MW>47MyHH@ha!{=&DxnJS%4o#2 zD#R#SB@JMgFwYkn>0ip1o*!>TDtcAWo^ERRf z@G1MXzJ~+>AlaS?u~lPt7u`h)k~6w2fX3DYe|;ysU%$PmDk2s07mh}Hx;=|Ttn zMcD2Jl<-FS3#g1h78S0MY6&n!s_DSm#cNEM(QkW=@uRpjW>d)^3CI0JM@q&*cEZYL z;_*N%AMr<`2`d`T$QijNF*u{H8U9MH`TID2J#PGg-JXCyR7nIQIAewQ6!eFm;S)hL z{rXcifvcHZ>Eb&z$F=;Z!|*PQooC;>N*4vjL&Np=HEYmvLH(<~7@Qb(h5AX<5TzMY zR`FlCuf=I>h{lW)Of-_T?RX5|q-Y>kijzJnY5!~K48Q)I;IrjiALaW*u%VEO!@E6B zAZjlOfXOOVB#^4tZMujdsy+omAK^<0DaywZU#d&VN5!S!U1V?3{DycKilv;8f)acf z1wEPwwshe$bONz7{DyMi?2twgjFd#&SAI~K296oVHd3(XXD8F1Sb=yWo0HZ#U@C54 zKA!rqMenTF6J5>!hURlW5=~v<>PzV(^H$|m@E%3By4iV;e>_=Q3e?MqKp_!5sZHv0 z#55hqb{DbVNs4Uo!5_nFB-RwpiY*h;{$!0NfWJu zRM1S*w2k@Z&EbX}sOJ5ph@S!Q`+UJjq?W5D31J-b#S5-bq~I?6wH2{$Sa{S51ampl zhmT@48cpQ9s0*gzl~OJc@&qk3(EbGsR0WrJs$y3Ch3U*fpl%XT%V$*1n{5Ql;=6`8Rv>bW;UOb7LX*h@uy4XHJCepzkAp4*YJP`Mci0m;v#SHwfw zBuOdOS?yINt5S8#yz#%BhQMCYuKGJo8duUs!0q zu4f$uKmA_-Rn z7?{&@fD`Ds@j#(rHzGIq5-iX#>81_im}T2miVQKKSlAbddBU+!o=CSLRBVG)D?UpV zrI8v;Nnj9IxZ6x%rm$d%AgXLO^$v1!P5fS!Un{4K9^s*Rv=Y^$aZe+VEmZ4wthVY8 z#K(OLp6Hn~!B#$I9!s@Kc4+##=sDv79UJt)$&%MaG^>2{LgtCkEqQk=`rdFd{aB>&hG`R@q%SYXUJGeD%k zZutEcKyQBpzg8eVJ`Xr3U5HW>?KeOX^AmMW-{(uGv4Z_t@`$|!3@Rb$iE8j`WnzXEst8T83 zr{X~->x=fZ>R>2{C+LpGgTj3%t{!dAMWl-3=!S14zJxPF{>eS&7EPOU{#CENe|(=5 zOQq&isnq&cJSTa6m-AUqtAA{Jjmnvu9w}Yp2^m)sxAX%R#*PhWKe3dM5ZxGRSgexk zYrVN}-^8oma^EYOkGIlI9Q3wM9R8`+Gbhi`jY?vE-uM>3_ad{)d}X?t%g}j})(JZz zNDrlS2WkNMs~g|EaIVriyHz?PtElo$9(Tig$8&a z4=#~fJD|&|t2BMOG#^e!M`BgF?6Pgc&F zx(=^$If(oDnBN^7tw?O6@uvQqpSJ7zNZ-Yj^=Zt)!xV#A19hbA$qlcDGo&~x&@g-H zG&z~=o%a~GEyQB|$wfL7O@#Z;jl7C}3WxHhg56p$7bl-xN1&TI-0w@CutJEdH>ENnc&Be)nEVi)ozZ*~4h$ushr<%`AE}9E1o3zn8S8~axo&(PR;pt#Em*}D+lR9W}FZtTVT!^uF zz@(9mPDQ8|vkCn21pGVUh6V}g1{v^-^)7%EkuJ!97IISHUF>3T8{8XVKr-x^$~@0K zB*3s2YZzRHQtXOokKp1O+wAVBtZ-MZD25JsU0e{vbSJ1lZKqV>%3k=2@inKuwU?-` zqal~6d#!q}%+HtR=Sp)t=C9F$&&=_)a|KON(?XXkSx4%^&|zViuosnC$zg2iGdIKL z9WB~+ebHD02d?tc<&s}?sbH?gPY-TR@hE5dw*M!k+0u^@qtx0{JY-7b@(Puv2_7-G~k1`}mNX+{CL z#8MPL6jnFYH0_2YrRAM5cKfN>KuAZ^3I%3Q{mSKDFMa9xw9!qcpTA`M!eXm{##Hn< zDtlj{)q3pY$vY~Q@j@gTjkqfnA^WNh;qccHf#4xR&t#-vWE`hj0 z+9!9?#U4<&%b%)jrPEtzZMxl_+-`R(i6NTJvUy`z8mtZGtkP2=b3+smP-J_Bv4Fuy znHp{bw>WqM*h!;WjGx{4MXOk}jGH+|&xT{)9}9!D7`*v?&B*t3KVQ~JA7i6v?f&Zd zvtfRb=O^+~(j#|B15Sv^EH|L;nuG}mAi|mk7Bh50RP{!lR%xi(8FE@0Eu~(S<%L^q z7th)!M?e5$EI$-U1OR;EiP8H8xUT~-mH?Scq)^kwSKTw>hzi=e$L+e}DWsRLU{iX1 zxf@ShT%GKe3VEb3+0z|PT4n6m zmNZ$ErTc@sT~>6+7VyFpYX=L-)pr+#ifWC}3uAq>gjMd(gYMAlLKU&0+M?4XXgVro zm`Vm2v)rIOGE1-zHFP!D75?Jk8T&i!nTM0DyS|7Q@g)P5+X@lN7T&S|&Vy>oxH(PX*bEl*4nB(Je#_Zn*GV?=^s${-0ka6?cQU5 z&5YZ3fB1E|k+Jr?s>^e#F1s|e=YV#!d-uRhG9Wg}2~+mX4o^|5PVrO@m}(6;?w1&; zFJI%F+0m|O_Z#(TefDW?P7>XLLsWG31Jf3dzM7)1Yj`%iXo?ziD)Fs7Hz{4 zbJtpGb~eRxwNN;6gy)s55q#2?`YM%LRbL$`s4@J1aBg`oGb*W+BCtBg5nr&hBA6j% z%bN_qT9@cSi1VOS>}{`BhopS38=tuQ?n-I;4UgNU{ONotcl~w80*%FkRWg9zIBA#6 z)7|dQS2YbZPL?JznTgWO`1qqD@8punpUh4Kt;RxjsuuN^Eg|y*^PpzKwvB%az4S8z z6;Zwqi8rbHeAR|c;tLmu^u^;YulLwX$ z$jiYWVN2-u?R5U&i5pHFB)Emj>;7E&WHx)!Sm%PJ1Cy!L&_GD^ocv~nowo5 zIy0>|e%~8gGo4a0cisB>b-8585i2A#Q&o&U0@{J|)23IM1)>G%nM_ij!jA;6kW3_TbD1h?nE^E6M)7)Ci`+H$^t{n zlwL}AEW|TWP?)0d^qJrEwI%~eZ^-gh%_UzpJ89a%5J8sgtY>DbgwMLW;`7ywYRx86 zu-8)}vyt0^FzP*2D_v=&aka`7^+Bz!EOCLX4e zfyG}>I}9h{qoge;Ug0`AYC)Y*C^|p=jItkeb_3}epSkl$^P|n9Gd!Cg1-j!7JocF8=#BTs zZw{>Z&-pt6o*vJ5awe71>r}>D^$Fx=x2!Y-_*$iTS%U-|(wLF;uOQ1KM}u_| zkYz8K>(U;kI<+SPg1WDY03!F6z+rmI$$b&#)x8^xpgg^>quN9V+$>j&rlUrbLoxR; zg|Yzf4mY~LIQFm+5q`H!VI1}sCNmsNhh`s$y0oVtK01&NV=bHP5_n3rDUqj*u+d$o zT@tZe`b)KIPbq`$Ql-cYRZI#D*(SHnkJD$r9JQn5B+4f)5#)mewrX`E1PnWHSeWqa znuXmh@7s)!0D)!s1JX$5q_kgRq{ed}Q$<~?=VX{49!F zwl8enV_5g?{D@(F=m*#~yWOYK&qx30Cl1}eI&vpizpF;5}yFSgFN=mR|;V|R`{sIn7E*kpN#9YPeD@D3b#NH|6tdkm~2 z4-8S5W@zFPY@~WfxX$*>gbpH_Gyg4rxzFfv24z9{xBo)&W+=ijg=r|^*W)T-)$TV27RWV1od<~ z_LxW&Jyf_|1cD*FvQrBaP7uV}>^-f=8f=jj#DB_ZTTPN^M` z`0ZSTGNtX!bk@?Xi18|-4v2dKu=Fvo+`#DNeUG#J;g})hgclVk49`FPw*d;t`NKG< zBX4Z=MD*9|eQQWxUShqA*rO=seyY6l7b5tOG_iS&HLqx;ta*tcb&)m8G@D}J!Gt6C z5TjnXK1zgt#qxqwXruAO)Ea&?mwdL}e%7{o?RKw+Rsj%N#!BQi+bg0%TWPCPO4T6u z7d7Ea-XALt)&%sD$kF@m|L+D$Nz{*fOF64_m0Bw)!z|k4&lCA^3yvy=+D%w$EvPkO zgnlGQt%PqD-ydC8T2?(P$14FLJ4QEBDn)p{A+x-k;rSEk`D8v8`rXox{%Gk(%i!ly z7GRg1pUvg&T{X7Gqml7(6mCnI?9viI0vEp6C$eAA7l-1x)WUo$>C4@iyN6UoR74$^ z0Wz{n){=YU=jMLSVe;rBXO4=G%9z34D7gKBoa=^u?BVXdw(#7-RlMD%0j65B^rAi2 zaT=739cCVz1a5|n45|*MvZxzjlyu5bWtG@CcMdWnhpmAj;_ySCID4+$`lK9Gzv_KK z;sRB$CBdT&Zj0GtPgEdFO%}p5papA_yLk7GBcXs$wx0W(6gYIdCM3~l_#dOvZne*a z&Yh+B{q5RQx+(Y<5VTGX`H=#5n=o3;Zfm96WzM|pwxL{kk)lT0_R(R-jg~svxGTf{ zR&<@-6jioFv6Cor;&XyZ%Enm(rK)q>75j&g4Y56CKu2h>rl`DyMgbp98=Ls^h&*;f)Im7Nt0KS4ed(Y?y0s8n1`9n&xv&UxbblS$@ zcEAS@e5n-r{p#83?JVJHyktxPOd@QdF)%eKoebVPulvB~U$^sH#=3fA92(KBt|LLT zK5+E&JHHi?7Xz5mZkd}yKC2DAMu#YDghYeXJOxzSGZxc!rXhuc|z}2l?J4oK|NaS&}{{F}KV>4Oa*6(sdHP zp=s>xW|YhQ9(f6AlBz$=8K%o43kZgwZPjGX?~pzZmX&JB85w_(hjhKfhf&uHV-K0= z5(dRNSU{B!(;U=x=|#JO@Wa~@YjIGfllbk*T9f@+id5fWVH2NP73XqTwL#vu=H~Wp zy39+`bt5#y4cJCvfs6@ax&u=+G}%gsGKOa$Rp}8@PL`J(%P z<;Z#zx-61Bin`qx7fvo>P5mL$D(c`hXUL0C>3jA~oIUY+ZoA(xFn9M)Cx?Hz$ovdZ zvzl(&#S#lW8cJo1O=icR&wU8Y*)NjHeca;rW!T-FV_rGw7Guf>EzL! z-%sSC6QI_1p6^1U3Ay^hnCbtS?#_QcBHC*!JOSeVD_yC+Dnr(YHd)ix1Dbrb$r>_5 zhil06pl5#FHDbCJPHxaaBi3u|I>OQImbGa-tNOgexGG6rb1TXuMX!t9NRpjli`eg0 zYggX3l)mr2^b+f6Q^t9dgm&Gn3ul+p_uiKQ893An>3yaMCpQnLu39x}Kb7&7XdQ~Y z>h%S=W$%>5)vir2*+iFB+h2v9O%>$NxTGTf-2l;r6XAo5Vpj>x>d^1@Ak6E1T-=B= zdYMC0KC5-Ng-&DCJTdI^0oSHxpR*f@>_6!55!=M`gRp#qF4uO6i(NcucK6!oQbI%1{1A&`yT zFHlE<8&Y&`8~DN|8jm^9xpy#|>3=$17*+{kCL9YXYm}tGH>8*0A9x6}d|508Z(I1C{=vunQn9m#WhtM{M{Nb`U;h($3Ylm5L z_&&{^{GQW(&(5o-0P~rX97r^62gBju&j0YH!qTR2%DVvh_^N5fqN%X_D4dGM4w+t0 z?ma=w>|KB#x73$zneilYlfFp8H)%!^YK;G!F}?_u@uDKnOMDv3gfNiot^@oAd3r@h zT@@^y55{nw;26+c@Hs*_%nd*TYtOH3=W5MYHOa`CF4bSr7|$fP``4dWB>#?+!0Xr6 zP^7f_0iS950xmCNHEBk?AAHPLO>ZSi2_9Q^jZF|8F_S^eQ=%^psnu5#31~fM*IR}1 zr9GJOuiLXWn)ZU*{rPv!_UG2RGZ_=zj=vH&2r_T~-5${R8B{cGcLC7blkaT4ORA{( z)VDKs64`2ym6Irj;@&9ACYh?D>rp`s;Sog&92i#I1N++0; zkqx?n>6mq(9FEkE6vKDxSdA0Z0w5bBxw!wSxpPSZ2WiPbj2|93LWe!T>PLZ1hY{}ph2xQ>U5-W2)QF( z-NUw^GFk>XZ`_dxN_)cN3(;RD2E1!o%8x|e_fX*n4UcQLh1Dam^M!Bd)^zj>CIGW+ ze%)zT?w38@P~~=A@5pNkKVy->)wV^ys#i^V81`4+-$}AZ(w`jU#0CDpYZ&bMkPX_deWIodxHcP*x(v86zbMVF( zi^V288CZQ^I+*QT-%S^bUc;A5*hOn0U&13G8F$q}vHIeI1mt(c)Ba+dEXm3vA7GNa ziO>PORQ0Ep$6P#pZrm657H;Uag4sgtUI>x5c;?1jGG%O9;hI&-CJ#<7E=-1ER^jGi zV!SnvGNphr~4v~*F-W8r;d}5Y)Cf@ItcSv2Wu6% z@EFlXl+Icp{}G{e=!?2LLk9^cmdsbqR8giaiA&|EU45ptT*spxyPx`r@uk8I!9?!5 zs?$rh_jLusiujhvmEvDD=o-S4E(9^?u}ve;rLMn@omPlG!XIlcCs65*gVjP9(yX zCz3v0Or-Ca8uuoAp=ivuGUJt0Hef~qp`9=5Di{&Dp6)`8qAZ#M^5ioDDCuAKsInlA z#wXi7EKrX6s<*lM%{DB)qqw@Fwp>l-#6?<%47s+L%a$%mH<5wlxo3Od`NRe2si@t= z-n3U$v(_gL1^ba2UdZVcqYnaLU__Ws?b+upf?SkIq<-VvEKL@a$P`e%_;D)MJhtJR0GrxNs;-d1!SB90+LhfLqC zg|ahghJ9d^mYRr(L0WF}9M)umf(xUyxq{ew<;vcwG`F`~yS2e)gW|N;lIc!==#&~7 zd#MBm15rQC0Y)U4|vMD#2Ue@`wQ=y+9&?5iEv)HRzVhbi+EG zpvx8ZUvKpe17(;?q`94v?4iI-uP$G0rt53%ozJz~o9ivo+6ZT%eeuP5Yn)qYGSKw$ zig9jquLaXdnKD;jQ0#?lq+>>dWh%M?iF4^}PZ`DLk?Ci+i5ed}=<>L&NPafftE`j( z)<4mDVsce*iclk?axfb5`J%~;RavP__u6x<)>~5>=Z542F=tq&B-Qvfr82C;-Qq<` z-nww1`;vuMTI<8&g?*&VE#~`xg^{_QaLX!k{<}uMI|#j_!tZEH_?C@gp)WtzYjgA- zqA*o6B*Bc(Gg7Tbpg9bCA2wIT@RtuV2e3awjaof@FGuy~cMRc(&zRChmO-*m6jHG> zh)u(Nug$#S&W&q>9DqV(|moUr_w7b66B{HYHaLa>RGV!ekHg z`hwwD{9(Cpy7=>Qfto~IOkJh9(q7abn`{9AR_6-If$o>oFCvG+R@dChwkAR1h_b49 zY?#u)_Ly;$40>uc>g3M2o_PdJh0B)Y>)T`nF+tuzZPUs}96!PYqQLEHlwH zVBavl^zNqruL_@`roq5FK9fCGkEQQBAna}v>0L$)u^Yuhy&imb%lxatubxciyzh7} znvhEjGq)sw% z;hlFCcp}3&KSE4_mnE|3iiMg)O!5)^W!S8{#xP3TX)RJ<}57H^TvB%?T^C--ws3c&=_l(yn+q* zz>dTI!5o@Mp^g_bvm#?-u29Ea85O=*XXZp;9WehxWU@8z@e)2+p_O-OA?{8^w<{l? zuT~FKjY8B;rY87(vJ(?oi#NW;Qo~o?JyG_?a68IYs|P3ga_3B9f!lD~ zo&Oe=A`*|ut*hDVb%|=d2+B)`7Z3%M?5S)(5;07kvigTQE;Lh;$U?>t<_V*Xl zv?LczOSBZb+Z>eC=-VXHARNi%qs@3>(k2gzk=~L~+>!~owE=$S)+3>*gJZ945 zvD39diL2j;uuW1I42m+hmY8n_dC2g9^9485F%Y&A)zpJ_HEwNb9{-}Q3GUv{6D`Zg zCey?cZEeB+PGH{l6$)~k0N%eG zF~-uVtf$m0d9v>qsbDZ}dZJb`XhrO9_Y%@tfJB08&r`Xo?6uX{s|PiVypEiyQ9>^U zqTtIN9z|5CqB>XwY60?xflBs4=d9VBK&{G}=S zsZJQLyQ=cTRt>?%AJSF-R5&G#5%-2fE@iBZwjk>?>o%t)s`B=@#0Ev3!)YOkMTK!LpEvv6}Wmr1D}?OvPd!%*IQl_(3*?M5&a3q8okZX54XS)43bBtkhoh*sE%p^7(tum(?MoPHfX1 z{%qDyw!C!C3r{GR?3c`t;i8AAs=2ZM_~IAP+yC^%R^uoAC$_!f}_JIV%0 zWH5%r7!!;wzh6>#vlFhBy0Lw0bo$iv_V)7K%f@GU7rixY@P7LZ zQ7aOg@_S9wOL#KU97Y1+KrrM<6i8lZ#i9X#ydHOvi&6p7$#b2{TQ`hSEVl2W%~pAW zJGZ#48SV3~T53g2KDFK-a=QXXriwBpPzBd!WaAM(xF&;18JZ3GC1?V{G327Kcv6Q* zw3!&s7_*7M$R&ZG>6ixo)VLGF61a2>d^BBUg_N;l#}dSs@qaD5BK~}9`S@}x?~k~a z-Lc5S|MlTW?1|s;2S~#RF4=7a{J#^)x?(XGcXuf#YZp9s2?Z$0?ngT}`8_VzQ+ zJR{d?eo)l(0kxwa8M{Gt^o}iaX^Blw^Zk;soii9@A`XE)Kg>;HJXV)1; zJoZ)nZDP11-O8pRhmWlj2NjWJmr2{~chz`0a;^@I*Qmt|i4@BUYcG{uODBkI1?<)! zyBzU^!ViJn6&h?q#h<=^8W&Wt!I0UiCmYiC*4ChY+T4_dqpU+o91RKLmJ&Nj0pe5= z57#ABDf(rgCR+~?5x~6dUDWyu>%~@SuCI=Q1`#2+8w~kw6Kfb@+U{BHuJIh@b99+= zjwB4PsO%}!W z*dbhjRk6ArxB2=fPYN)1Th)Pj(0Im%_HG$1!s!$x1=JL%GJ%?~+}M5U4bjd*xugT; zS?R1yjm{JVtnwk&kXUU(g1toAg6A~O!_!S#k#Hy$2}OS~N#K@vHk6$5lr{-=IN^`x zqk*bF7O5YMOibj`VJqYdBm=%MJWh6g;^1EzDO98$(uPOLO=Otfs2TEyh#3DK)0-tI zjVJ3huV2jfk*R)@HDoITgGg16k3BPXaqQz`pF&a)aH%*Z zsTR>jRLN1JQzb5&FbEB4lyGsj@=N!*2Q0f=8U0k0?G-q>n)He-jK+}JoZ^Svj~ncpbKXNgyO-9`-Fw0JmRd9t=LWc zl}O!=jfY(X;&DYMfwP*tj0fT*w8m6tco?mHMYNFTPu!Jp4`rx&b?->H~-4lTC+Nk2U!v z>f*|*K9bKr^0r6vfwXnailoEF@s*WscO^#7&AnAX=gQjFp3efG5=sqkx2sFnp2_Aw z-625@kat*mBYx1zPr0YVN47RAg?6Db0^1X(qV*o?D7oNi!sv*rkB~?`cLrr^-NUs@ zr%>sC<^8_veyxh#g6|}$G5dm}-FJ#3hVI(h+NDc+%tzYD_W2?$6!9LWU+wcyjjJ1I z=dCxVE5($*!j9}gEWf(UpG)S;&9W>RkEF=uWI1VHRkl!jJucOa39RnTGLXo0+JNUE=% zsA9y}A@&EcM_oGAI&h$MN*(uFrCK|eH+rvlMUSWAJ$C2Ji?(XFoU2>)hU4{CtA1P^ z_qFPY2hN;%;DMW9(uBv^Er%Yx=D2AO>8p!q&91Jl9@uyD)(7WSSC4|le3|!FZroSj zyDK+2w(s62F3znU1Dvbwt-Y_seGZ#}O0+hrwq-2X8Het3Y>6^X0!orF0QMqI)kZ%v zg}yxaWQc>LxanGdBLmg%Z}bxR{wB(nc;H+p5f7dV#rcqrMJkm@%<$-iKs^6m%YUXX z^FnM%8p1CWdeDnPcOiR?VUcctE3ka3wSJd7oc!rT;CnZEX^bH~0b-Clt^ZK2Z^8Zs!s0jO&V0w7cHaqWb$c1cY;ShuFcHxO4XS-Qp+vv5;? z1;tn+LAeTJ(!YvMh&@bfQ!h!S2IQ*Es=9jkHnq;l$=CCd($DN0$+iv?@dNth$&VI) z#?hG!)|Q0jz4q!7J&Lf+z=~IvO?XY-rc?VC+80B)?0xliCLgkvLdoTYRA%3D`$jNu z`4)dLe)4GOmTX1FaWAc|!HZqH7e?zK(@caKssTpg>aJMzXHu`I9!S~2ggNC41?E~r z_uAJTb$?*%wCRtQW2vKF?+qb8lW1>U#Kv;%x}+!_dAlY$GXAL!a~-QYie!lT)%EH6 zVMR@L)1b#E$_=*4gV)$f01en!#!?Y~5Mi7!Y?wUj^`|NoHPy8@iI{#+V#|yZ>qExI z|EUfCk-&jPA}Tl@B}U_8GUYb==v{joAN2g^ktj2^BZ|G=<+_V$ns$vinlK!rBqS;L z?)_6TV3+h^IcyCdmjl(czu>+RxvvAh_r1xv}&%uFdY5u7+*h|YHAi~EM; z-r|8mwGfTZ9Btak$}0*O)TqGTI!PwZYt#wF9sRJhCy(rQ(fCMTMu=EOcSVT@gV z_E{d!J}X7-Z6D?BpOf|y@fdf@ySjDJxl+AeI#4Oqi}ljJ#@So%fB)8x@JCrf0%Waq zDOF6ZGifvtV$OLs;?$p6)U{`jauA)Iw)DED8enrWR{U(%}oKA&Z z`2Pn&sY)#yccCOKTZPKp;^_>^!gM|5%f(YUfieCLUh(D3rEtnFr#F-1iAk$ydR)slGND&d!wU`L3yoZ5of9?-fus#xC%O%N(y;Lu zU1qFTwyK>Z$-Vqx;}!3EYC^q>v}R{+oHLS@mE$WFb@=6l1+zOF8;@ko*)*@Svyp7U z48&RE1BX_{{bwwcHyF&?D;UvLoQ#Vo zjF4-7gI$D|8}%nq{PF3YJ)b5y$xkK{#Cfd*#0<(Obx=3r)0+Hf@Nm+<>CetL#w+sC z*+SZ2LXIi5j8*|I5-(RW``k8mH-5ht#@;;kG%ZH;BKs|_(*piumdfsfB?wzOSL|k^c^45r8)WL)^vq5 zHPt=5OwZmAeS?K5Gv|q`CF~3t1_%|ZI@T1@kg3zl5*9=efRZ>>3jc*YLI4q53+-Z+ zbs!RAH_vns?K46zOnfgJ#uAAYt$4ngD}|DgSaf<8-F`S}|K6iR^> z)i3At$^U-vo$owYYVjIw-6xphqIXkY>sON{FVH?LZz&i{^4e6zQx# zwKhcMh4~jslUYFgQWh9-?w8b9v!cNoce}k9UJhYPa=ZN^m?wdYl``4YO!jCtQ%V$# zZUZ28C6lg%+$^4)k#AV30>LxQfDsav+354lK2x%Bo4#NFm}s^?W?Jg+Q8tbof%Y>K z=^!^r)R&W~gda147>(F5rQJy28a5*&1oVu68i36RO>|yF*(#VC>^qup>I;Xb=!d~K z#fWwbR0Ou>6nB`j-58jvvE1- z59&KU@bx_3IhS%h=Ny2GZqNC#`^H{7_J*-1$KLTT*|uTCt=&`v0}{FGBQQ8KB$~q> z@l;ihR6YNw9@)91fi3@5D?gvoFAlukd3ji0vaj=W4-Ps{`cyhEE`6%HSoia689=@u z@dZZ1n-A)jpWE}vDP9}e1c<03IUN1x zC^Lb<0XQxZ^i8)lcn}bIGy-PGUN96N;l@S%V}>i96AKa zE!Ohb!;*n;*-D#Hi>%Ut7;qu>0}j77CV8I8n+w)o0gFYIhYS25zpBKjVV!}HQWkpl zk3O?w;D&_oO^23i9{X1THM=;n7o(RnZj|ZC}p262$8}*=Uw*XA}uCec>KL7|J9I5fPGm_ju>@^aUj-7w_fp={X7tV$1 zC+LKjBU3URwEH9aF~X0)9V%5Fo2}vz;1D!SOe3`ggal_LwaegmARGk@2n^L`Ss*rK zRdgpUQ{!#qLpI|vOGW1!PMcP8_rnmLV}u9ZlUTPyr@zma3bj=B&^0J#z*gpgtx(E$ z>ztq5JfGS6!PMEE|A{+g*egDjUGDEC!aeEPObz2PJsG#506hZmG0EPhuPDluo}f{D z*7U_e(ui;bi1Ezy?ZJ@a(?l4+ZW5=?@6CHW@x-0xd_m~&adLx)J$G)ptKg%@f%l?Yks(s;O44Tt?D zdM9Fz`=jA%>yw^P+>Cg=ZafK-ac?lj2VZJ;E1a3gkv%8C3ibwbnf9vbu?ce}hgG%b z>UbAk^p_}oL6FL}hhkZL7D#Y~V%^M0f@ymxtv6q>YisolO*I~<+z?+5l@6u)I0mF8 zLs&nVdrR&7sp;ucGsOeN;(1jo_h;?9iD{BfgUi26`iSXMuQ)aR55!&wdU?Dw zKJJ}ayS4jh!zvih`d@kdrJYYa9Sod59|*Fy1i9|JvoU{`>!#*g_6?6`9*t$K!p_AT zUK?rM(AwGZH0mDICAv=904FiMZlI4;lxkFmqC><%TNq9Vu%@!YKr~c@Pbjy@Ho}UQ zhz12LL9ik+>Vgp@R_uEB0$`_GTZZ4$j;H)S&$`Fww-U=9ztM6T?pec_BmD+nd)t2h zx$=znKq)ijyPK2U*12=7ZkuQG%Vz=CfIC0r0WEk4OgaFMvtTo7FxfSi-*Xme-S&CA zuKD9LF4uUPb1VhXZtb=ygH-z3vF{jr>)1QTzE9eRKHmi1siJ+O&=Tzql^=@MFV$p* zX{5zyG)dwk+6gwKCH5z_VR#nWe~sH-V^{@Jj_Cv;I3(aGQC}}y2tTn(TbIK@2 z%unXean~^t4?DV$PNvTM??jn|Xge|;(FtWtl&EF{S=t!eax#GDCnuLDr*h+wO61n% zNYtH9yJO*xq}|cT@^U!lUMt0mF=KOmHv{+`lS`94j< zARp^By^6;f)>UTF6sAncw{;l41}!OCU7fVtEmek=Q2U`0=i5|#Q17j+#;KW&jhR!8 zm(zmnBd@M1#SB?5wcp3?C*YgeFwgf&xn4Vo9!3vpDUU~$*r{BTwsOSf!EdeCich`**S+fr2N zNUrQFQ(R|sw#OxjQwze7@_{_@q-gcZLRIf2V3O2hP$z=DsLuc)mDB1rv<6_jsM*v( zylaMUA=#YVG-J(}xqbzMirq@LdaX6m-d~`is=k*%`%`sQV{HYIy)Ys+L9ci{CnOg~ zEwPxkc&8mL5OR#MJ`e+=$&Rqy>;bdy+2U%@?GhH+_^=pAFy3!VAISdtb>{qshW$=8 zuq=W%7tA@4LEFaGTO)6K+uI^o5Y#=JMZ=B8~CKbjXWHrJxr zyc0=sV`>4{BE27oPU}OgO&t@1{rv!t!|J@NgC=&Rgz`?ueqHM0lLLL%!`UT;-K@wuoK&_!JV}wSY8jAnbca_aEKd zr=jWNu11IK9tJ$Y!|TcEaWk-1TC>zEsXunsjn}LN%<*Z9v+|l$?J(3jka@*D4VgzG z<20B}0%MUeV~QKw&Bx7&=?U}k=HLy%3fH%+Ovc(WF6q~os-vw87BpR=y+%pz%1)dcf6d4^$tW>(3E!+11Nc|C6<`dYXxXf5qS;b@aeC=0?U=w_ z0k3Y8sLEJxe#_%C{66oU9xv!k&s#c1I8cK;tT#&tYd+5c)MBmc^_=whOmElYHSE{A zJb}o@Mw5sHZp;J^O804io{X=A9}w8hVMSH-OqAIu$~wF*CKR|97pMuQt6sfWf-xOQ zZINVE?U!yTsT$M*VWYEic|nRk_APtotEZ&GBu+KP?(+Jiy3`65%468NK9PXO_1Xvh zagTc)Q!zgK>#YsB2==M#6;P)hYuN+##ij-}CThHZ|O+EQpzne8AzZys4V(rg})jY02=x}MPADI~rF5MXv7 zL<0VI{j8Tw7WzsD0l`?>TUk|5tLYMmwd;TGsj=hbn*6;jvDZgkYJCr46-q2m<`el> zSS2G-3fY9!!mqiU%yBwwL_@nb2N3(AhGs~rAeYdm}RQ~Oeil`WU zy%<+G723E~ZMK;zqkD=U*9GEpO=%6lVp>8kLJYJ}>_rk)7H}AXh8}t3LECs^JROUr z;}0Kx=!g!6yR)?*aa_%8_C(uf1|%tPFuWOx%XLA-_iZJ@|Hl^BWV7CC(#Ag{O0?=Q zb)iojyPBU!uHsw_$D{lfNPGp!bgH5i<|wnMi|CL|U&irhNE=h}G)2XKerH`N8=Q!- z)TVv^c>GA+=t)iD@lD(gd8usc>gdR`QlW#*`f9?rs#_)fBXWzj^#$QWB!byN2T6e4 zMsj>mErdw6aaEfYh&f`4NGbwn>#zqY%}LvCr!x~ZPzHkr4d1B1kp>YgkIdhaiAUyc z&BSjEP8WkStIckrw7!tZno8Yo;pE)PTJO; zVp98+Cw8`Eb!p)K==}%5Xs*6LcLfG@%_258dM}KL2h~-Dv@Tp(8x|sS=Cj5N(7Pn_ z_ZG>`=|H-jz>OHu(D#rp3waVHh8(pDgO~J@kSnnGpKqOUd z|DhOuh@p@)zvnePfk58tLOGE!j0_qH!|0=>#D|lALx0O?T0AR>LtAy&Sav ztcoV6sl^Z|jZ1*2lK%Nk7gRM-kNzcEEy(Nc8mh^ETAO9e1xzg|-NYRaEaV7`Unl%& zj85CN!7fd-Oc4uZMh!``Y!U1R>Tj?nM(+(zv;XcA;$d{w?kRytk7T01MltJz5q8QE zc|*pn2lc;o?5<%MBePccsK!5g+Nzp;+@;)SrTLrxtO0a-EfnH@vDeabm;Y%)IGndV zsOrsQ7#N4E7J(m@UU8BCLairR%{ozE{)O7!+EzhM|A`HkaVL^L^h)qR8X~Xxjimt$ zKva}VY$HgC3j8EYK}Yl;WDJsxysvlsC;R`+ET_xXLh8U{`NzK_|LC#cOy6Lu7pQ`M z5NjJAuTW|=?;y|F#2tqgRlqXMvrBH5ELsJr!;6(TMERM6%57e&)Xyn|N*RQY)Q^aq z`-`JOiiWA2B|FzC~O>rU^g>MrSm2#E>=p@^h`HTXtsc>9y09mOUM->`{dq5cgxZla*X zV4&()OO&Ns6z0VLQHCSj>kXCZobQdZX42z|nN2em4tTxCZ?WC+z~jLpYLQ~_4gLgD z-Yv$zLXGb69*XO16@Mjct|H934!3~d>19oT5Yk(=La6h{VDlDBI2CDqa~NL>l@e*4!^RuSW{8?-*zTJthz`b zfPf@>hu8?lhFVCWJi1S0=E+KMVt%pYv^eZ!^BUwil1Rh~g5JlRx3LlNuj`kz>W-Z& zt=73_^DJA;82YAUt{Dk5X@MM?>I6Fje{_$Q$;GZNj-h%Lsv%KA8jO()Ppy3=jo6pI ztd6jNY*m8?_ZZ0E`X03xzYBL8-f@crBeuPz?x^4Iy{|67sUPNjv~j=|#Kcp>ay4=z zBCN2N+IH8e+-1`2IzQgiKJ|M`|9-S0#GsL%>za@-clYPIU7JqXI3`@<*Q0l0V`YWf zqb(b~->_1pmPF-i-9&{xQywZZxyhkWSTO++$u4 zSWg`XBhu@wtjKdX)?bBZFwq)J(kCGP*&S+xY7lQ?j-nhDQ1fzKEYf8{MRy)Mc0=jy zrPa^IGnsg8u`*S%o9{bzAvQM`n~ND2R&O}QxA{tDB7^_Lz4uNYj@d_>Z&>95E{Qw( z1krC15~-s!5{NY@Ddb-O1Nv5FocB zU5lHa){d;O2d#+IpsnayV zL7mm_-z`4@{c)gPKX|ZSKTs(PGP7)eSQTA_AV=1_g;c_hd<2E``nu8=i@rrWB6_vI zl%zBy%oFxuVd)`ILX*H;DUFDFx6;;rk)q@=?5*bWm-__rS_x#*!8U=rc;61DGl3P} zlgEgZ3`}BZQ3O~4v}xz^?t82jVn>zWHeL3z)v+#?;aiEByRJe8DTNQ7F=F=@y3GtY zY7A)S9)%}7I5@7Q1h7xua@A141OKVuJ82vHw?wp1Ph?j-fo@6iEB>-^%938KceTlwS#975bl87f$uq)tL z@1fUmUW5Xk?HGxkhd@XiA}ZQUpHt zb8phMlGbJ|gPnT_AO*2?y2+TsbTF_sMuKvPkQRjIu*nIPkl@lv#}wF#8h9TZR@L3d zs?1drbb!$y(PS>Nrl1HJP_}5Iqze>15j3E~LH*{s$EU_K)43Ao>N1(HL6L@JI7A?D zSb{M{gj?vM!5e6cuFEc$>{KTFrVfYfHq@6Rv}@pe6&!BQ)Gn|QiNzyLu>w>UC;6;m9z>@_jB@Y(P-c7PM_n4GAPfAk;Qld1&g% zZSGXm&p2NUy^aTaDbAN|fLLL2Va#(zjjRX=;OS5Ak+R9ZP{`b23)`B^d29W~Z8?h8 zrCaX!f1J+$Y_rJDKm1h;oyiM93CX>5DAVB>dIf7)n6hZc2K&SLAhH&a0E^GGXnNeh z3T89TN=)VQ1*~6^XTb*0DGnQ~2~~+NHjt=NCkG$FBA}fd01O^22(msra27KOj_O#v z@H-(}5%oXq9+ZNYJb9p70|j-QOT@97o~hh>8(R*+1p8PPQy(lGi6yv33|b&`=;RC# zuwcsCnPvuuz_u83uix)w?lq`|M&ou@GBC?p4sUm} z+-TE0puPPf`%RpsHCof~^ugf>1a`tmBrJOLzY2Xlr4g*pAaS)Ur7d;tq(qCI?2jOp zZU_DBSL{K*6;3sQ1d=U99YfRhl9mC^;gX6=Fai8jRs0p_t=(5SNIo;`h7cKU8`JMXQvcv6l!Y(3# zffj8bA9gM|LK9yzPEhhLK8Ti3?hrDb;)Ot#dipaY?jvsT>Ma(xFFQXSKf0YDrfDhuj}p z!^Wyb+#V}jB2A|?Yceal)!@izE*Sp(k*<8WbcRf|_ZP^&$m43%j*y`2!b86eES6fa2t*qg zq&$}lXMd&_<6LNJ#EXCj1?VGj5RJVqw(t#n{kPLeF_Tq{%RrdJ-x}nB-P)oJmJNK^ z>l@0E40HH&u_I`UQw?74Q-baU$U%MGpE|v&;^`+86A3t$oYp?_`>wWd0~&%kB=~>I z2`R%zB~BKfIuhnm4{E{#4*B4EeTq}oq`U@{2N2U~G}`MNo~B?Z7uKj`&q-vo)%9fx ztK;3*>pIjad>KgJVvgfJa8{<=xqBpG&Y&|u)Xc+UM1KKE82eLA1KuAec%7r^6o5KJ z1F?NPo9%X^dx4Y8nuP>LlM~kFqe;ZI_Zrf5u!e~Er3Ur&RU3UJG_CMof!_&i#Z~}= z3Bw{~&cyMZ2anKMR9ec{AofyDBCKcpkw=cAh_u;Q`}YDc-kdM%;Bm-r)zIM9dnMMv zEW%dID+;6N5*|&XRDI38$m{tvUOM8CQR??Q9jb=#b&+7sJloe$J^?(c=;=C>DO7>R zl{ybC7-ULGPq4ca8Fye6)G9yJ_p8fl?L~H7qWer@&=m`P{Y^xB%#LMq1TmR@sJNhr^zj2CJ(O3T0KYH7XkfOgTc1Cwj=fie4)i zDZms$42Cxo-@XtY$WfD#%(H_701^CsIPQQzfqNCWoDN7^Bi0Ag3p@|zj*ykw(4GiT zX4A8ba?&0`#P%8V1>sqMSBFpsTx2XCnypytWMel!(`$IgXYxFo#7qRsL%>QKRA?>-H8dfrbYmAZv4UNM*OwK1s(v!pgC(RYT57ggMGWn=6TPh0jNCae|N)p zv&w%4=S=zq^*yzVPy_z|Zx^{A8zEFz+OF61#W!7f>mKb3uQJXx(kWQ^zLLU;fvmZ- za7e7>OCQpJ22m$Vf-f$TG*0`W*b|AbpdAuPzJ&W;HCzqIjbSIiyYRdoNsq; zOSH#Uw8KAO+T2U!eJ7wlb+L~o+AHc|eU`oDo_#0V^H9p0x;?B7)fNJ z8A=%|nZxnM6OLyttd}2lTzL2kuy!Cy4F9@t4eCGw;yfGa6v)<;Lr;VMM*%2{-*lQoO5<5B6bR?5N4z4}F2Y+1j6iw5tHFgLET?n*^7jXuZ+{?rUpn zIs|dys1rL&%dfSJPBNV{z?H7x(4!P^hCbD_|7G?nnUZZFkbt_1g7vnS&V4T~po--d zloI__0048HSHkr?;6u2cr^Puto-RgsPMPhPgHR%TE`X5H7n?w86WWN#?!HQ439--z zBMbSFqr++&z^Tc}IeK!?9`sG*S}-UeJM&1Y{zt~wxCciy>7c=5_UIS_hgl>4waZch zwEL_Al^-`}?4$~v-A~mA!V5)ErFH+|9juus0GM^<^7N(hMBmKYIzxUSzeaD^q7$IW zEwL6rCm~l5kkSH;3y(qZv!Eull9;^6XT_CdI8&-MuBAN0f>2iBA8DE}A7~%PqXw1K zlmHU+Vh?jYfVPKVoX<3y9+$f9a*`BAjmAc3d}%zy){r?}a>($223UYyE~@|; zfvcig7T1|^eG~Z?z&-q$+ilpopwrR0Y)TnM>x3pky}Wx*Go@3Wm5~eNqDj~fG2_V9 zm0+F0t`I0baqmzH=xr~gBc+)VqAhP48Ts@Gu*O*tNd~smBwnsAA7Gp@sb`^jB6&HBgt26= z#5zO&(qbS94mt^1ZrvB-3_jZ6j0N~$yGhO?l$a&X;w`>&G%&P+CI2#x1Inl~NfVI! z{LfJM3l|l*#*vf`7&S9ebh^I+H8KFd;(oT+5oZg{fa!Y;fjn_|1!8;Xw zV{?9l`)2JMP86Is`3g7rLW#nkjh)mgP8+%p4yIER*WdVB`ql7|*ZD4T)Vglpv&DGG zcat-7le3V31w^ocm*5#l_<@9Ok0lh<p6lMmdWZg&?VxN%hSggZR`lDW&1l*(#9X zkg}k=#9!YNO=f{>HV}M;%*TjRX^r zM-#zFOIUZ8cN5nA6a#aX2vE)>2@s-z#D<|{BAr6Z8SM6>}tc zINn1jt*|`2E@?3!>?gpT-jp@_*{X9lvE<3)s#@$-tE{^=v?2O`MC7nP%II6uN2SU z=?j(b^eKMVz4yjkZr>fRa|c6i>p3K;2)d^t^w)0FbmZgyCah;a318+mM~NcgLr95Y z2;B}E`wJ<8(h`70@H1$JaI zXJHm@um%{KQ&x15DUxC_*^f{6t8#QDcJXBWb+*NK6Aw7GKdZNxslIg2ac9|QO- z_HDDA01s#ZGrCn00#HgQQX>v#XNfOqmP#CK^}%#sv0scvKT|2{C0ym}>HCHYi%2&K zrLqBPRN`wI>I!o47l_^XfWwMgA+VWq``aYG0*?k2|CT2}&p5!Hv4KbvN@j~%BA<^X zr<1Vo1zZU=l89%N@u6`g6$mFZM4<)XzN{#~27wNEv`Ju5L$M1^r$4N{KCb+Z6owrM zPY>F>k_Q>MJiu?kpUW2rzg`Rboz7oY2UYxkuR zWX4&h$f-3_m$w}vBX5jY{YW;FYC*r|wK zLH%bvfw0Lr zH;o+JY11b&VzEYN0FHa{tqj}4jG@2P(ku*pH}*NYm6YBG*?$YzO4Y2rRGkj{T#^lD zK3~y%^Xp-Iwpy}fs`nA${V^k&%%jXD0MRlzL=Ze`9fEr1(Z1SxpRnh{EfILo3)& zk}`zoL1HO!MZ{}zW_bTlJCERR&z~T#)FU)vtW_=tJ>B2OXAe8>39h#{bmM%YGAU$+ z0-boK0xmA@DjDZBv9N$7T=VTLU4hTQ_VOF;*Ydj%}tj zS4wm0gBJ#MrSJfL9y2}HVodI1 z9qOJXo=Z;fKVN760Fi}Eexu|ZCIl;NjnvmTxlDBi2lOHhNLYeYg{Uxq??VL&?F@-| zV4Itv82-mX&qQB!!KGaWec&6|TUnEsG2E*9Jj#qv4N z%yl<>4W?41EKbzN<_8lc%mwg_mx!)Uak|D3)Otiv2BTw-vLaX5lMo81F`~@6CHcXB z+FX#};V4niE796!P44L|eLZ ziNp^sMBl~+Fyjtd!rqoQ-2L07dr1%ZOd{%Zi7ehXeLV5%jki6Axp&a=K}^5}jLJPa zxClOf%(GU7VTzyH!h8yrOe4fdE}~e;Udj_Z&~hVtD?iH*DH?qEPwb!n5~fe)hokQt zoIZd}D>Dd`pYc&TgAXMZhHzzcp5hc{#(tP#hX*tG&4KB`;wUbO^$os;!mAaiLWg^& zmbnyrsu9|s?6f=O$xQW)#Oi@BR=V2hjHD6SC7bbkHz5 z5a19)KDlUE;IN6CTg}Fr5*Y9SSqt~3eCh8B*ADPejmDwZnVSWXDh_#D)NzF!Z02x}lJgk=v7^PJ2XK ziYMw-vmZ7g5>PJ??Epfx%Z|ld%%5=U7gR-5Ci~I-_inq5#yWy1wE1Wn+JY#1pFencgj_! zV0I}bxE0MEO$p06LA0$S;2Gii4LvuP4{_jbvXOazq{B0F8FRkepswGlhoGvn#0g;e zpjcQ&w$&AuOBe%Dk>x+G!Q!!1)di@UDMnUzcst9>57<0g)vi{=T~kM zEos1G@6jeW$nD*xb(m55+C=rda+_!l@rw3p6I}5w*QV~8sEy7Z!Q=W+n{b7IBxnkf z;}*m10qP*kT=KO+c2_ZP053COx&&nA&z$E0K`iu@C9UKsgywQf8RJUNt!TD}?( z33+BXswgg3R(9GQem5LW1H*8raR*iSvf1ptW2!%ey+}W^bGxLeWIVLK_uID1?{gh; z18O_^+p$rub1%m={>;5x1gkDAri6PyX?UR~SjKJ$Bd2D*mnVXN;Oa*4YGmv6Civ^($?P7<>T$3#RdLT6zzrb7kGX){BD-Jzc2UjSA9>&*{X-92!g)zmh@mD< zl7KK2oDP(+inz4Oz(5ugy^cqLA4FtX$I?W)KP34h6qztSnkX#_#Kt^1fxt%FU4sO} z;SXW4jlEDVuky?IhEC!R*~0OLkP=CP={DI$cNLep_12(?x1At|chOW=xPiVF#q!SaDHMnV@SnI_*3l8GiU9>l>|(MzNYgjo>H zM}L^SAU8w8P6#tH*+tk=zZvrBasx+aqeJ|hh!O9=O}NRuz@Y_1dxa4anDo1in;2>0 zL4ZF;I-Knm$m+?Ho><=N@p>SdZnHo>3sHI~?!{kxXb1g6m!%(~FjWIn6;-;s9l%WX z@ETE}cSm!Y@gWl8MV)BU7S~68CU~yBdyS+c$l%-;6$3|5Hzw1yt0&i_tU{V&B`a0* z@;XicKw0mggfd>&hk%BH<6FR4Qx{+97;-Cees|mN-D?atxgFU!?GOq|&c$`EL!m$q z^Ux!QM1Gc$j^$?|MS9(A-HM>}LB+3x3F09Za{1B`J)I~IefS<%SxLD=V;-k(I9fju z3lc&RPX2Yw5dwOobRcsi#Y1ZV+;tq0)f&B1U_z@a{2g7h!vjVT07uh7R!v(qEL^UI zs~XG+nEXym4Mpe?3Be)1?{R71^r_NVv6dWN@J#6;l?768YFEP^yQFXf$>1Qi9T!tQ zE}gkO44JJxtifDfrno!>zj}cbZnHO^bUzV@2h$;S*yFN8dniH`X*ggMF`AUZiAV7V zgx5a+e&F(CLxfT_MZ)y3ziiukum+vWH=;c{c>Swhb^YKdj_1qtL3dLqlsAm#Ce90osr1!@XdbRa(>_E*-zm?J8IF9LB4(qesz zM0bW0eeFW|nV{c2Uyw%|T0S+*fRa0klQ5O*erst7Hm62;eLwbhzb_JC#dtZX9vB%O z9yy@m*7b{qNt%5Jb=$$eQpWQd@<;!c`ITfBJy5)?5{aCwodX$!H#d9cGkAw{oN$1TMB){$rkewA7t z3VSxtTw1WF$EL>8cHN#I&D#&EdAv)H#d3AGKPG4Y`^EA_MQ^MuEls>?bo5md`%awL zw{c=0KD_FnKR$6_9b<4g8sKXzs)e8+=K(D{t`s*Vd%(Z*A?dR0O?COQ@ z9CkrtSN3Z}Yftk{#fzIt|m3H?oXEcN|Ni>O+%Ke|W4>0d^C{M^3ML}3VH!bh@ zxMQA?CIzaMo%8H+8l_!5{m*-7m2TVJx80|_+JS2h02O!N!8!!Z`hhyq_u$H<#`d{E zIUe_-ha?l8;hw9vDwK{0x-PEw+TCjpnwqZ2!&|DZZ7YFylv1DHr+EEvE)IA+0lfIV z%D(wJc39I7!p}8Lg(hhQA*soanP1xXcwUtN_4S)cxGS8sLylb{R-#+hI`1II5s zSCX}yqN)n@#-3}VK86wjKuJ6CO25{jG+B4KF|Jd_I}7nG}DHlG^im2_Q=3J3_AA$8aN1;8)#h+ zCIf@@I75m+KY*Ue9;<-c#)vuYSa{0cuIj{(?^$+v*?M9@^$iF6A|K=K3#;tC`g7IOSf zt46AmWK{;a7~hz6Fjq&pE}C5wa$(Rkc$pBl2-EEUTQcF9swGbO78 zv^OWzT~@pf1#M@&UaQmR`X5EB=lx#q`#sho(A}7&1t31V#r|nzX0hFmqAbrcW(QIr z@?*=CF$fO^+%qe)p&VSZSr`EMn5E1f&)X( zPPx|$Va&hJ1Xg5QA!&I8k!Vn}Ij!Ni5?1yFb-&PowG zn4kI#W(XiY$qYt53BU|2*5S*Mw(#Hlg`EM3+#d}37nOQ_#OG5o3~I$-q!wNbv*cRb z9tg_;H?xQFxfTfq-ANP%RA1c$DjmCo)D|#nhy+uZcG40LyvhHlbC-Wx-7LFKQci?mqi3Y#+{+M&pXw z_&xSLK5mUyZlm_{?V_j#)6M*4$M4CPZ`|9*M$@DCKb9UFdxe3FzQQQR%yQCWuyq+e zau>jxixi|}JD`1wR4w!m8hkQ$LU+Ul;5n^@Gts1`C8L?JHhkorwWZoQwlaL=y6KV0 zTt1P==O#y{uRAily1abuipmE6O*)M|%C29o?3GpvWpDA_R?g*vw<>@OFk?U|7YA|n z;7PeB42h9AIE)wK1Hj>P>0$-SB%_|;^wDqdE5oyC^PYc?ucAqO#iY-T zOe)Ic)5DYM@n3v?a#B4qnZ)~}e;}?eJU2P19D&jleFlE-zd{p4z~@PBZNss|^=aG$ z!c+4=TZxRD8syO`Ksz+{jYlj_)fv!nE;zjM2V{4M{Zhc)?O5;r&B;?Y-;%JsMt#e^ z|7LM}WMB&@!SdoUv&%GmRkngvYlVqqy0CcsMwvc`S z(%85K=W7q>34lPtQ|#7AA{l0<>G==J<)fw2QE(yjl7)dM9u7YzUf4<^(*3<~G7({? z!^zQ+5&Oic8&6Hx%{Na7#ff+}cw#}D0674Exr;jJw0q{OEx$XHu)Qe!7)(({a-?xV z*Xv(~%JNnoC0!79ZX1>TeQ3o>`dY<&$w7lb$w-v61;>)CAP#)o zQUYr>QwPffMIy0t#S-NpsNv+=+WMF>ell-&+%P+PdquL6E>Zo@$K0rCv{)|JjNz)o&c1y+PKcYwq1Ybz{vYjSQxw+~na(;cbnnbaDK_)QDV` z{>l6WehQj}CY7L9gsotp&f~AaZIZt-7(b|9X0X2j)fRddbP_s@f|;Q^ZhqhVJy(~b$H(;6PeL?>}+}b8l*tU7bcobT&&*m zW*$^(uCopH999_tF^^$JQAjV8E?BJSI&ihvTge3(KJmQIKv+pqDb#{?Ef}$56TxUO z7>(2u?%|dP6*tBV*;72($!n;yQK=>m5sKTOPD!d zX7B6mliWhw%fh#NRrRjGmkND_jS4f3NWqk`dbP5MDJ#0wYCyVz<3_@w~Ty`z?Py3WoEvUxGawatf#S0(MP5#xV!! zof5YWut^;1BF_#dinup2q(MkA_k$kgyRWeO#vfAdh*EslctiPv6l}JK@ExI*a4!mKRLFcAnZ$u-Gax7kqf(pl_mCPGM1ZVfH&Ay27D}` z;Y5Ge;4{S8k6wap&X}5|Aqbm38+$M5F)1xhWPkvWP7DknI~mFWTvz`~9fv8DMp&yN z8dXQHLZJ+$GWX@;Q5aCr@dUSIZ6@_i3%Mtdh5{;!Ws3V=r%YZHZSOqm)hlK1S>$PT zAw5hm=JLe8w6fAbb`52{iQGcwqZ12yBKE%rw!yl~Lr$z77c5>Yz!&;^d&C1h>4oyr zitu9>u{Ztgfb8%uZiyYpr{w7iXVL1_w5IzDOrcyMq%mH(swOp8F0`7^`I3I;A~*0S z0R17LFtDp*4EP9}gTQ@Qi}1gpEQ0VGBej4ml_tr62;Z^k89H~qHaO)-?L?Zom6DVgW7*|&$%_KEb+)GFYzR)Ll^G^OZn00abF>4;=w z(1;?Qc%@DA5qdMsz%O$@O!95yu!k&fP7KpB%$YCfErc%)rYD6Q!5aa=s$f%v#dwzk z<~CQx2KRSc;?FPd#&~fVa5b$)!{FTo&qdzr+_G$XAdB9kL9O$tO0Z)}mbGD&M&Lc3 z?rpc5oetcasY93&3vxETjZ|Nfum3q4qmdPp{P2l z0Rsmc6q*0(3VYwdgEt>KbhCJ#ntIUXdeE6V@|q`H2;Fq@CvW~pDs|R-HZ?t*ylHCK z1gshhWz=1Cq2 z@2qmyO~-pN+INA8rKn=4_-NRP{UW&slOKjgiZ%daNXk{gDni|g^(wAXY#!D#JDvsxcB!#sY2p#v*wEC3zRy~Sq$b9Xo@gA+#)dvFyO6u{q!)R|T&{p8 zc>t-qH9sC#20&d8gKEbTRf04yRP7{j5~CqI5AbY<;aLV zcwmLj!*4h&NyM`QFl?6M*;5qa1%B7fLz_8}SZa`hwnn>Ox}CQ0o0!7E9RBUFg?&uT zpk(!c`;6NkaqF!o^Ha6rF^7v7H;;$CWR!_gK1U@S)IYcD%Aev^ci5iN5==Q1snD@b0V%RpXY0e=|FgKZtJXUc zHq@$GofZ(qS~m|b{)B6L%!>bg5=wRC?6RH(NrDE{OY0~KF&rj+IM$Y6wHJ?mwT2%u z%OO}g>auvndJ>JL%w;O~aD+YiuM+XOxp-pkU?eg+iU-39Nq?p@7SsQZe?ONP<=>A+ z%rPJuWYB=Hi@G26K);3EeQ#O-6`@tdO%+z{h^j{4w--U>?rQPRyeYxXFLj6}JpQ8? zhApbPou4ck>M-~fnPam7WdWh8%M0HeSAhM7#E@WiA<}Y$ zY^S<^kK5Quhcgn21rQ&t24W#}lG#oFgWV3_!Pg8t0Fnfg0a;ChM;9sLq2c0oC19?S z>Vi%LV$$d!AX%M^Ot^@DxLQ&){spw6{8|lf_>FYyln_zD2Ig^h4ZmmCO0w*-W|CHi z%`ygiNMab)1l!ZLWA;$mCfgm}xF-OkgcYfu95%@f*I#58RkT#ZZ?BZC$VU>%kR2uv zj9YE!AK=w`C3i$|sm_em^^44Db4gCc<-i)SuLEp5KJP#V2$%hU%w)Ii5lg}n)g+fJ zxvUPC>hn5-*n^@$3-aWmporC`_@h!$nu6WM5=8>rh(F}8cxR9*w^tb%?c!oT04fObID#rjfL+~{(tm?Nw{S3o0O0?q|9RuvqWl?VW(Xl@teE7Co zZ?&TE?&oh?zV+SX>2db#{i2Sy2ELpArQ2@1)kgJLZ(Y9i1(+phy$Lp81Mng|b!CB2 zX^4MS*h-_*X{@vwt@ZVHgiGhd+5{imVjsdWMnJbnNk?;tf`cjek2}diSPq-A2^&Zh z){61izgfgt!Q&Fb?Ah**3yJ0BMB#g(n0qDD%ygeOl98DD8-luXfX^1X8}7sh-!_tz zp$0VIF;FF6&b^O>^n{f?gZ;p)9TK+CK~sCn?Np(5{A+45C zU_u70rpx}Mh!4#WN@A^WN}wk4WJ{wNbY-6nhrC$_;H6vT@D=dJu7NcGs|e*DLyq~S zDC*uwz>p8!jzJT#-j;k>KZYVMzo7Hh3H%dTsZ(AR?2vI_NU6-CrsFH0!p; zFTcSjNb6-9v2$!M4P2n@LD24D&Qa9bilVP_ zmogDt$^$J{noVHLkY0Oxc*R9%IrK$?4ZqTQXbB>c?5gTn=k-8;%OSDW&>9N7f&Pzl zA_py$oFr`_LC|L*bp~L1`=uSqV@oJ!Y)9_;EgPTFbVOhiD+3xZ>w3vT1ixq=T^7{f_9YwJ3vG=LSxR-Sy|%w-k__1Lm8hJWX{6gg2|mP)$B$q zpeABp0zhEm-ysMKef7wG%F`a7bEHDN2jQnjsY%ea>u1jvfGe2zci$#|%(1ubx5GX3 z++0vY5;tm419Zpd(6vgla+X6Oqt7V4vX}3Cu>ndv%F`Vn91B4?)XFEgTNco=&Gv z&u&ZIeX&$JH6ifJ(NL)S|6&L7D4rNMkQrz;Y$D}_yNiIp8_gM7G;8-OM)$H6HL!J4chk7ZYE9Uj09wXUr@n^GsJE|#a3XRwPPkW1 zuVxwIV!l4PM|U*M`escMUV_$abaTgGum-P_`EVDf;St=$Z^G}lX2I6@{{(Z}3dK@Z z^a~~u1_hi!mUcEM@9AKPXmyiC(4dh3oEY*t5@!I^aaK+gQu$)$Bg>B03g-8G=9HdU zrGQh#uny1{ks za4T!K*@ybTiPy?49n(S&_d^e3u3>~V%}zUQF7y3n|$c6`F;c0GR2?H_pU-K=@+*dNbsY}`IRQhsORX*QDjb;}6fpZ^MF z6X325{y|X>0LC^1jO!tUM-hvYOxR8bE zz@{i$LYJf!ibMTb!yyaBi@w>aqktOssDT7)}*CY6q zdI={R5%8ZcJ5<~I%;-Afg-C^5xvLNBkSu?0im#S*qoa+NJto_pEjTB--FQJ09G7Xw z$*XS3?m@WPCT$-ST zILr8*{6_a?uUG!29LK}^*--WxwvY`yx_|$pnup!$c6UGK(H_0K70Ks$x#%HUzmzx% zk=Hx7*?JdLv#hTj|}$Z~x^)2)X6th&P-_ zguM~jtA!E?;rw=uFYLqr?X;#4Z3A5%+es@r9?n1@ljJSH7eN@Pfl_i15*`=elC}|< z&@vz}v(K6-zQ^hFg?zr9q&<<*_TeUaviZ!)$PjcB2mD%n}Utz}@n2u6$4D`vk4j6_OwbS>NbIs3 zi3lAY$r*8Hqk(WBp#m>^KlL}8qh6lFd_fz<9`$ALM z`Ctn`y6K|$Onfa^C&TBacmJ+8nt6o*fQ%TZ>dMDHkM!;C&m%e2lX%is8fWqOnE2L6 zRr_7ROc`#O%j#}N+CJ+79+*0*ZUsp`TcpeUYHPKpON3qPav#n_wQ7dw95)~mnv&R zD!erCp=@sM*j!F0{M2Jp6VQy||J^)mAM*C$Pw)+bwk+5G;)LEsmt4glpu;gBr0W0& zyNgh=d~7Ff1^N+XSy86Gu#L?BvXi!<$%fKyD-D5@+D|3u6MWm>@OcsjCyn*UH+H2? ziM{*n_iUikSYCQ_&a~EBE02#p#@g#^ZSBE9tI5|Fgf+acTyh6UV6W%G2{*ihH_q3r zT+vDnWpa&N01R_`L4RyiX)U!Io!^;$iNp{x{aXtV7Fgok$Mv=K->7k2gP@yymMNVY zNkx#OX)14@&d_-9)hPqB4XioUHD4GnI0JsyL+*gT*udHTER?zfc<3225@!OgMSO#& zV8-M3dwxRx&44{=n0puLDUCW!wCBC+ERmfnNN&{Z>B9JsnXV0WCPJU15~<`)hSqN; z;6#1A<_x81TWn&Vqihe1M(l4&rP-xu33PR!GuA(XeE4T z1#4WJBxWWOUe}>q#0f1hd{G&UKl~J-0B<@~pqmv#QZ^$ihO9|2kI%mE!n9z%Zg|cfXo607KKmEeaxw9@Xg^je1 z-HyOP_JkuY0foHh=weuVdsZ9t6Li)z_Ge0GYUsViJ^+0f*epbb!W=aPx6mmKCL`)v zIg8%UEBuMTs!G@#XoEnygDg@m;;$WuSvnm{ETCI$RuQUiugi{x%Q&TqI3 z0X(IERSi2a(up9C*1Adp^fGG$c41|Gk>urNv{&#=;&%@GGHCpEjA5kZT7d*}vxM&Q zhw#VR{RREoBg&IUDt5CtV_j^54nKIw9F?ZQi?J7?z-^mbu{jEqTs3`t{Tc6dQzHbP zjEoYd>z1Ptm=NSHOdJ?Fa`xyj%%0qX3!Yt>rk=d>@V>P2 zF=;-Fzp@w-c8K>Lpx0?kxISl{r*NfxECcQ22=?cfT^EJElDATN;2cl$lpgKA${Hef z5zji#pTO&cz5lq40&^ab{*K3cuo5C$@t?;=gW_+KXM9?7QKq-Ynrm59eCYnj~W|8*tJb-#D3z4ruN#i39lkhjeG z+*yAB4yXRC+c#^;2NI#7qN{P`-Qn&2WUE8O{Nra+12(b|ve_YMh#x})y9O?T1`Ds) zrFcR!;%w-UA}Is^m8wz){1+K!bj_mZ5!mdILqspH!M(KEY_LXaX^He>y4zLCoGH0& z(WuQ`B8=P>xRoOoLg<4wq0b_{EG1YQzt zV~1A)V6!!SiBj|-hue~|zfjH>2UZC27lLtwTq@;rJi}?7^BZ)i$T)&afQBdhHnuLn z`t_iHa3&Mzs!{@aN0& zO(_e-5X#(Z6TZ99aI#Hg2q%A5vNT(3hq@dO(OHLyZakRWd!eM%%NQ)fRtPK6MHXsDr!5?PUwYu z)kC&=1Xv>)5g>)ThFN&?uI*J%7qwGG_}kJ|P+g}9ab%C4g10|}T#|7K3`6+vD6|2W zNLK*wYV5?CO0JQEEW$GgfT_~p(l^udOxaD~QBAYLfiP)v5;6l2CTv!(HEy#gR=bA9 zZnMPU+h~*N3#WswOUs5@aaYHE5NwInHe|CnV9rYdUBQyHNEVl6$YKjAL5r<`MAi_i zlVEe;Qt7q~Nh}w&wT#(_zZ40 zEAzugum6;;Xc4^;(cY7s*k|1M0I=?X9Y^!dq><>GB42|&D6}Ib5izl#4kRkuC?vxJ z*&Ftt^6fFURH_h_XZ$N$H2TQ`LfG~@2px&B*gFzhq&%3tZ;RA_)?eVn@->3Jo=7@%U#nysW0R+tD4l=t#e+e!InHq2okvl%ZMW9Y1J3N#~ zT#batFL(jz-2a@!wRJTdQoKH&R|$nx_{kuHkymZD;oV}q-}-*!p*|QQ%tog(6q!?k zE{86;t8NLKQA?NIRhOhYTtQ_n5^_2>&!0E=~ zYXNVM(Xzg#;9Om4tw@1jgaqkGFd#{2mg@0Ijin`Zuj|{}19`P0IRoLjNWdXyWY3&O z%48a{BM_Mj2b>bF%z9)Dxi~LHdvtPp-`*BLNgF3NcT&T6084f6Gd-fmm(H)MPL z_PT5@+W~K5k0+`Lo2)8!d1+f$|D#>TU3LIAtBNGWtBJVXB1`tqp>z9b33H9>Uj5pu zo^-D}h?95r;CiAOmn5QM8*#h(>h|eG0(5|Qn>=HX7m+b(#k%-1m*Xi?xhEjkC}kIB zBW?5~Vb*Eihx&j=AyQ{?p&m*ViUyv>y*2oYVvdqG)k{P3TFM(yBi`iX@zK+%>oH9O zl|i*(mn1uqP<$YudfnHjP9u3Q?jC{@Q8}H=`Te=say~bawMEBpKQfMWM3mIPBPiHmA)~+4ejxqs8_TXm!v5n5jb*+4 zz~H;5Zg{mv8oP@QLU9iMZz$8owV{+j1#%gJt)!?7yq_ znjdhlA{{_~i@Ls8p83J@@4vQo*9YD~Tf3xBLI^O|5}oHFBuk(e+7%oqN)}Q93IwxQ ztrf_3i9~b_Ja8TF7&4!7!|=fI{j2+rH`sD_4Xik{iwbL}b4qLfIjvC8UOl^3J`jyp zC^JN>J!rwcX7IgVW^K&2Fl-Q2oEX_Hj1!&^hiB0M#2HZDh~MUqJP;i5pa@F(Vz<5T zhf|U+>i|y}8nKP_zrWd5wsH95KErIAqEW!UiGOE?Xzdw(f6*MIdkSOXJ^mM&hjz4#Lw<1=j_Q+ zkmpKzT2Ii@n`N6#zxKk^j-* zot(IVCwJ_AA!BjGpz%Qxt{n1uKtYfwGWeuZ#BcOM0?-rs@DUmket5y3x50aoBe{n8ytwS#0KzKP8y>Am%!V@N z1kH#^yy}=CL&LVwn{2x66Xe*)26oJY)>;{hPOLfFlPRZRku(fFOox6;-y93Wv6E8o zfve=2XXMh@6bQ)cW>nEy^9`=blp3ChCfxC|?tZ9+Fmzxje~7%%MAqEyW*py7L|x8Q zxx7ZFTt5w7tP`GpXZy(jd_X$osD5~(8TI!eId7fH{3!bc$ME>z;P|j3R#q>NYc-kW z1Y1a02UyPtty80pp-SGNAuv+cg-brsLgxadhb3M#4NerZS+FDE66zYkEgXOtS&|XS zh&7^U{8+j`t-~?i2*#G-35Ej84I$hi;JKlyjaX=N4gQYEdjqXTS#6&?M|BaOBIcF#Ov)%XQx(c}WzRz2@NsnO$1-N%J=|%^#JE%EC zf(#icsR^V87Y%^7ydj?vvjyygEt*u41(8kZ0^?-Iz5%z-W)sezin7w`>qBIuA!^}y z#^1ESL$xrU!DkpUxxzW7Dzwhm4%~u%#q^z?(Q2fYpJOvB?eQE=Ml5?A?^yhF5gQe~ z&>YVz9NH7_>@@Sy1}Xy@-5fzFk6XBwmo+m1O$%T;r!t{9%dpXOz!?})>Eh57%M1;M zGD@c7a=Trv?n_>WKNDG|56g+qQrZ@)-HjX)e{G3oRW?|jD>LLP%%@9Lzdjtz05m33 z%}-3^X8oUqTT(j#E;V9Lw8OsQkdm(LC1DFmR8MAP6lqD=D0_?9iU$vrNqKr9U6ON+QmLi}51a@ZZ!4qGhQkRu#EIXZeW{FoyEXVPp~ zYto_*dDc?-{2eUf^o5yIas`7q5A>CuAisj>yU?}^{kPy`6!Mq6flQ zizPhh$h7vo7h5Aub1)R7;v&@m-eB_Mnw5WnxrL7{1p01lAn}{|iku4gBdx$1PU|KQ zlxeVLxxKO0Zg)H472k6IX#U#Nn{2tkZ+uyL5i~bAtwPd zQM*lRpVPT!&^d`6dEx3Qg_%c#GY>++;TI`14fh34$qOb(|+fvTGMa zFtu=`0xt-D2;OGg29!n!JHk<6Tbrrdi=`U!EB({a+i$t$_M?(ilY>%x&@=J63D00$ z3d%L9`=Aom(pk0;R&uF7S9HkWMem(DuRN5w!rsd~q?|w1rv3wuw{1<%5GLtWjx-P4g9?N) zs_k~2xQZs&Pbz6OXzKI88DCj*SlR{88aV2a3j}aunxqZ{NCq{{X|&Ijy=ZTo1q{dn zQf^#rJLw=LA0HBe`(Ll3g^*Vp?KZLE=JORcv5FHFY$$(Flc0;abcy>wW}ri)mO$}N z!X#Lry<|zN0+xxb4G(#pmGKi=#c4wyL0+7ixSq?4&o$cTJvL`0dSa~N^bQRRsqp%V zDM*D*4|5~Dn#%*CPO&F&e0QqZ6l5<`cb^=qaXN^(CR%_^An!>Hq*tp<(rdXCPb60w zZGCz9yvHJ6hP>~k;_>0`B@$X0o92<=)JHqlA#B}OIkQV(pRQtb+iO=gnm_8mF|V*d25b7X`Hj*g|CucG6?_znABod zL9U*8cv`#lR&DyqDE?7vaaz0WHVq=Q$@grXZ(>iqTDrlyQQG)93mGP_Sd)eM0Lv(p z1Xo7)b0mlm&7?Q^5!b;Hit-R74r05Ytq>AX4bnH&}0L1^bx;#9e$;=PqU?u&@#a^9L@S1(q z%h$^xBDl8-sUrxYy*`6?n2o|!7%5}P@*_N(1*q|!6fVH@L#7gL`f-JWZXc2yidVAw z7+?;fl*#xbmyMU+<%Xf5z4Vu`J`=E(7kaq?_+5#xG4vbIsOxZJpa4bo zb!AMkx~)lhCXnkSL zE^sw1VY5Qt0d|O-5}~+76 zAA3Ig#Oe0Z(n9&{!ovOa`%x^-gmq-2T7xbxN0ybsltwCh6bd&v?qd&s@fzXj0*4r$ za+n!8M8KCw#R6ZG5^HBt)^!TA^*A%dL&b>+xcV?j^IFv5Xy4n3iFIEvgv#5q51jT{ zZKbJVqfpCCOk{jo(yK)(Be5sFK-kv8m2wo9jae#a)4c%#+rBtoBddGZEI zM@Lpx)Ud^%(fjb_DReh(9>0HK;Srm&pVGkZybP5%RWYkcJ5SM|9J96nWIwJuLqsTy zJmfc8GoHbVAWoPZIU^8kFp7|eF+ploN(&_}vrps$$UO+h9STitkLJCgTLy_GOMoMN-pqyN}lCmVsa z1`h8?+TrC^1b5S6$yj~t4E~o^yH(F6%3- z0eP5^WZ|O?4J1rN3QR;~830B=->1#t@>{CyW-g&$!v==+NANx$FE2FKn)iG_zx!yj zZNBM^8+OpXvatmcJS})|vOysuXWu8LY!!Z~uW+_k>4Jm)FR;oC5(kYgHEp?uF_jY0 znU-D|iPbQ7pVCf@SDc>0Fm>aJcidA)_u#F~$-?P3O{UNM*%oW<^wjTp#|gTxRPZ`) z;9pZ;fonJG)cNkSC+D8F7~|W|J6Ev%k+T*RSQ+C?yq6PT)YSca*21~wkzsJn%`@rA zH>EjKzbDn-OD2eEw)o<*rF|wn@h0qzHba^g8jVqSk#KohoJ$nZQr{A&v0^w}Hiar- zRnO3QE@OdDL8_iQwD9W-ho&G_LpF|OJe7MYvK?|YiO&bpr_;s4r_1Gc;SDR?J`qbK zViQ8L)&eA1`xhj)B@pGm{>#DB=|b_g<@xmK!Qz0ljXv_i*#}wfN@(nt`VD$XlDh(W z`}6?Ww38G6t#bLUDNJ@7nT|*kLIgD2qAp0B*j_T$ry_WD;)2fO9rPr1zri8 zBk)}-jIS8Pppc(*TwZ_Vk-x5a{2Rg8(-jx{D1E&iijn82 zulmu(*|#pwxRBDmQlz$Q)g46tkY^~bn*!E}JMXL4S~6+{t_w~g63<2DX3f`cjD7MO zh{8a<<$3*Hc)jt;yIr&H>sCL(4rWmI|I+95)*3b4uvCx-ffH>{!PdrU2y@5zEcOO+ zxgg#f4+>Zyph#hvNBwkEv|#_~b^s;>yMxm;c$ z8DgW2x`ma9>K3?aqV6&HrSi%I{H5XUh$|2Sq2(thKT)&kEwzGL1*maIU+v(JGzefK z=~)3l1%p8lRy95Z3^w%c`l`|Z6UB)T+$&jLDc*=Y%4RtCO1@7b{Ry2w6eYrKXV|Ye z*mIAIHnk+w6>XwJX*6IEgCVj3b02^|a1DMIv1YTwse%QR+%t8A=<7NL3U)I>RyZV_ zF}{{jjO+)*zlk{+fW8m>TNu_N+NV<@gaQVPK)wxcJ zcveHPM}t}{AHARG0=!G3p@d@h5jM>|qv?IDavh+_gWrFY#d0z2Qa@RrzK@V@?$#~o z48{r(at1vij28KAi~?`@5G-3_zHVcOG&t^p@xkn=!=WII;mTteBl2Wv2Dq8Vc~cG2 zEEYpqW8doDo*dEL5%&fjmO}S4qxa{hBBAr{0>;thv8Nn4ect0-a(db?Jl#+likp2r zInwPkI#YSI;65LUFswBX^1!EUica5lUwom-=L4T}qFx5_6bRXxxc+J6B{sh#ZJ_9rfHESPXD+>6f$H3FzT)xBla^>Y-7f)R-`z_`aX zfs=^k(OVrDb|Gwr;c+7)!+8<={UHYT4l(Wwfm_sH+)e5QXyagzGy)xeL=Hd4S+0^p zI<=s0|8JG?*XKa6gvBF59K|ydau0k^%jL!+aZSA;O3P?#Z*@Z&<`@LDuM02`?B)d0 zPKiYLfscJ%(I|;dHYaN)*?faNKua|2Ngud0V7XJWBPwemDBBmGej01{(ts?#mWON7 zUVE_n&0x%zo@E1fxLlF(Tu^o|{`1pi1_&t2upkrNNJ~i^iJ}|F!KfcI#OAEA-DRn5fbQnl6Jt4o$+jk}@O_}wLrRDX2-zVpMuhCZg#dder9!J! zVUgnU6UDAl)R2tF%0{`iSYE7^8>_1>PkHF;I8E3}dwGdaOOfzGQIbRJ?KXUmuoHfPu&>1a7}qWw&P*7c+XBz~oTrGAV_+>qe#E$KXH&+ow@EF*u@M z1tib_VXsp*5*ZQ}+%b?@ZjCkD;O5xsa)a~fI1uPJ0*b)s3F-|@5MzpLmecXwS3AyQ$Ah9>$@ z7jk}}BAVE!w@FnQf)(`z0WVT88A6WW-GC?LA3;<;Trt3fFE2BFV;Nnzj1=PxZl^*Z zBZim5Fol)=ATTtINJV#|Q!t1f{tVz@2w?biV|im4|994nxkpt38=d0GfS_+y-P}N} zpkNihr>;TWM*nb{`Ao~!suU1LZfPrhx3jicNZ;>Tf@aJ@U>%~tobxdVM$I~rNTdof zQ9!Q=yXwx;oPjp4&Wl2%R;#a<`l{|5n*h{46!K60-zM+{;q{XUK;-Pi{wRtAbUPBs zGL-tpx+XVhQ6^xkc9%-V4z!KD;C7ZAL@o(zU0{c{7mnGq)@rxcXmMlCqg2W!K?*Ah zi__}ZHt0{}=v7WAQvWEuTNt-Eh0ufXmI4H_R?B&VIGMeDUJ) znnHWz|3})Jz)6;sb)tDSJk<{FWaQB_$>RCQKW*U}5!9a&wyRyWX% znT?20tqtfzL&GQyLJwrIh=PNPR{9g)4EFo^1WZt$O3PEn$pl=1@!?qchMuQ@%VVP6 z|2ya2SaPYV)~bv>;-2qp-}%=6hf5Cjk{ju02o5hmk#v@hUP3{r0H<3xW*M)fE2Ehxw>~1mg!U^lIeC= zf$<>B)Z9+d301$s3?*Etg)5yD<7%g+%3&>v`R6?y~X7xa*vi*D` z(y%KKgaKj6^#;s+LD+Z*_Yqu>BQ0{RpD@o7pGv`={%eGVww5X(1{~SwMv1j~ws^)A zf4Pd$CPO;qq5;fKe3~kOEKb+ous>rT<@|-if}wOLY@x8_lP!{4Maia**LV}zepHKk z8kG+qd;l=E(z1(rt}lFGPM@>>m^yeq=UEz0%$L=ZmSFyFIO(JeF3EoSL>BxWlK7_r6N2BbO7jV-&xDGl#;qNlL(&4#pC3 z(q?iJ_$(%wwPCNpYR9+%%op~Ut*thqe34BnfSqsz)>f8z5U&`Q>p0Jz#R)?p;T7z5 zb1@O?AO%>)sTkekJ*v(|W?@G6I+U|zW#=2~emDP0*X{2@Q}N*y1TehS?Vw-KlF*Y4 z^h=z-R<#|-KqQ5b3>`Heoz`n&m*`^~z?GfORepbc%zS}&Ht{xI!>@uH>#VO+LlEuv zXs0kXM)n?R1y&0F$eA&&&e^??ILwxeK@+h4kk1>}zls|WG`pQ^!U^t#>>^SZ2>?;_ zW~>B2K03zi3NA>;NK=RkGD2c z^VSu^4W8m{UA2bnBJe~MJlb(#w%of)7w2aOcO+$y2Ky++N0@ElmL*P$@M~V_QsG4} z;W(t?@r@S6CoeLUmxQMjSlD`~I5$qnAQhd5ErL!?0Nmm}%a2fA#Eo=qHinc9{2iay zt1}jYHUYlO-~WEQEy|p6m&?H%WlDgR;|^OC0m#7O$453tT=L+f5^9Zmg4yvpAdjVR)Asxz_Ge8Q`Iq0G+tHoRJEbY&Nym#@IgR1lbz!uyOC5}b~;=x3{TYd zs2CbQjm`X^*l0?x^0E3_5Zw*hF(AxMBjiY+ZaW_qfFX$Yp=l>j{+&k1W6wLB{jm}9 zImtCStQkmWlxEeW%tyGLV5w*{;RfQs6o{tELptaJKDpPO7*D4nhhw?%+U!I=oem$4 z<;N%HP?oOK?k(50{a!V2B$V`r3?H5y4J867E!mf~SIJyY@-k$w;imAapipz=${gLH zL6W499FDc0OT~lDP%<+D*Qj3j-Y!OAl{E8L3&n0Vgg@Cz8?;A=G{Y!%kqrWKXJHoI<* zKa>x7T$`a#zzrVg4upOI2uCjd!57@K@wE3NHDk$>sbxG%*tfAlIhoBS%Z0boU9A67 zJX=ek`b7pDFYTF`@uZ=5VZcmNKh2I0G6KOgOp^>V>XPYiZmeU7FfwsJ3I_lP1st4k zh%^960psGZ$L7$WN^^pk9avQx!EDyE5l2pUP@@?djo_BnBWM)T<=LilRo|oW$O` zm>55w=v^`vXOM|Ev#7wXCCib-VVB2eZ^y^)(C+|NM*XgUOu{gsXJ|HH+w&|GXXq+?-?2BBS$#X|@)IF2da2HA@^Mc{}f&5Kt`>(U^0wz}%mPk-3q zq(~fl+A)Jb9Lrc--J0y?E_d*eN`@C_1)mN2{S~wo0WTjXX`ZKdp&3(vLMHkEhmDN? zt<4V7pSnE#yz^&RQ%IMYQk)K4Q9(M}31bpi@02>V;Y>L^b`_u9$6FIx_ZE8rat*?x z;KwoT;`D?Dxj@GTRG0?kKBAwzXx97!&V?4;;ccE>Oio?6fEpxpHsIxiWgpMkCBf70 zr#VJF*+1m9WBJnuPqyK7J}&tqQsX0dHhY|6Ue9^u+`=)pU!KW^b6Ow>t4rJ&WA7K7 zy!UJHH;`Ke4~T=9T}1fzDJg>5Vy&OT(?bBxbeHRslDDf**f0HiS&Je-0-eI#U1R?@ zz?doAs72-4D#&2KoFS+Qgz~r;bRf$xfhhD04v26B#HJB1tZ3~2)R)>57Zdj!T+)n) z=E{|Gu6WeYmJZ&NxL9r9rY|<`HS*HJsRb!-+}n6aUy3+Sjvw(XJ?1$Bw;Q}#XFQKB zd5(;qlp?q3hXbeI{8+j$HC0GI_U6+8ns2eszlr&FLZ>`Jq0vl13``Tqpk!o3=o2P_ zJW_}&p$uHqVkaE{5PWAq_+6;BGb`Kk78?2*=$eswk4_h*qKx~8V#q;JXV#Y zN@2$BRxtwkSRfF~YerP@xTlL11!8gpqP2M7Po%?lP=x-8H)F z^8WuV`yTH<)jb4v6Vjyq1lbhAZlPti*%BNDY9544&Ul6! z?|l!g^X8eN+RP&aWwvad5jq<1Ib7pJDAtjLTw{wCakh}PGX!TZf<9V=L?t#IX?6hZ zBES%Syb&3wlTv}xA9^1zaLecVT|p`rkaRhYmoCIhf1~83=i2S(kW2@?_jg_P6ZGzh z5LF$xFQOr6t6640ti&%U4`C&v=2BF{J6FY9Z!*7NuFET+i;5nR6P|b;AzaeNK$H<3 zIHYxu215D)*pJfbc3>Jntx`ZhaYy@l2N9#o9bf^~)*-^c1Z4Gh6@dkl+?uXX;2PKr z@pG=bqQrs?StIaw><323W_*En*O%%O{<|ATCkt|FCiU5{_cFmV76C^XT0r<&`+27) z9Xz}=TRZNaJ2F|AW68G!HjQb*x zj?I?@Vc>vcAwLyv)x5I+0}uIEVGIY~hH#`(@eRJFaQJ1ClfgGg`C49@IrR7;_%qkP zV#B+|^h*=BCptgm@BKDb2$sqk3PWhosHQ~?Y%1ia;!8?&ms^iddd4Krt-RKcn?Eq9H z!)FZ9u74>M6UXxwz$MSu4;`(|T(mCwx-PEza@6Ua4yUKqtZN4qadBbQ-Gz*%TSCuOY$+L%M_+-5yIGMx@tcuC`g&*>U);7RY44R;*mY#c9Op0n~ zvA!jofEDwY7pwwAsuR#B&N~FyVs#^!87H3XMTTF%WWUOi)pcuum z5C)eUz#m}hxK0fd0+<%$Askom52*rp;@Zre)6;j(9K>j%$Hm9O_vGO2>h^Hpk)aD< zDj(s;#Zt3gZ!T>dPS3r8)(BZoM%(6LfH!M>)cX!HHF-Z$4h}r*2XgK34Tv&0C^ElW zTe(<)5yz5)Uqtve>1q^~g?Z-#Ax3_bkQQZ%B4T%J?!MXC`yQveIhe4^$IjE;<&)Ye z|Bq_Vu=Vz8_o-vYo`U%n5E+;Re)rQSwUeiwQJ)c(FwP?gJU0j3u#Kesd$FSjV6m`! z+W5}aVAddEm84ghtGNXE4K=*NmF-Gd<~lKj^wTD2B58}_@>C7API1&Sg&&UPWIt{G zv1ruo!J8@1W5uKv^Z`+bu`z=1_J!2cGfp|A7G@EBzSd^3a3LP`y6nA=$6pKCWK&ep zS$27O9>3)F-2MM~TiQ!q|f|1LaY;P=vj$SROK_eUZd%1}}UD6_i%FE^C_W6Om6v zAP2c0;nu*m*u$F`TawWz=pR?HHkeFGB>^4?lr>Up*#^JZ$~J%(p{#OsW4kM^)n;RB z+%8YPV^ek@onF`!q3Dxjg#qU>pbVv*?3k4>c$|2Tq%JN-AWpIg&mP~v*E;lX^Lrup z!#w@Hvz!Q?5lfDUm708YnBdpml_vqBRAUxqw~X`wj~c!+o*Y|A(- z@Er0Fd0;5@k_0h4u#X8>P)fTEt{`5f^ic?Ps>=`8dT5E~2O*-c!~Yc3@V|)=3HZlT zT6%|jXcID`-*u&ycmbE_7@P3xZi??BBLU!)2COaA&%eYvqJE}f*P7s=kUYR|-`>GC zfaE6X9}ZV~!fn{p8-ymP6{|Ni1nj5H{=~_(#rt#F>y4p^H=;9Zh!lW>xt92>5qdv= zqgLD9i}`vi^i$oZbFW-RU)&MU2Vf2dBe6z)qs#oim|j$>)z+lx|Ynmi&A~iV2Y6>TzyPaBoAL#0) z*kgi_MEmC*vg~+`@je2gFB-jVUq*Zi?g!FkS|k*~h~b4FX^!h+F7&;w*xb zk*3O|3-;siWER_6x$f$W{dpT`Ehp ze^X#-3Bx>KzJs&KZk|avtjPTmuV`9j(fTs68uR=ergt7Z=JYG0xnha60QiCxy8KG} z&=o9$)Xtp%1(WPht#`6j^u8hWkz}-mvAJhlR=_Kx5~^QohtaM;b@DQIS@1 z*EnlE;L-I^HXG9Qpsue;l?HO&_}B7McqO+Y&?XxEQ}H!gim*RnN03L8Jbk4;e8 zBO+ipqN-q{*q#-`Fh-A1dWHDj}Fo=Nb1q$6FRrUEjUpV|$U)3K=#k62Zi>3h-1k~?Z z*w_0F`kbBig?r!kGC)44u~aymiYbXu(d0M6mO??)V zd*KFRR_tY8EL{zUC(;q`_|Fu(C2uI?{XK7(g_7&*Payg`n3$lZs%jwrGDz_vPc9tt zvNK-TRvGtYh<-nNqka=YFZx}!`YrQ*zoytNdc$Gw@8j;(K7Z90V`=m}sKwGO=G)cv zfA$jCh1qj8j-Fe5j%2QJ$O4NT))W#jbUYj^R$wAksl@T0SLzg>2yc+xG7LcRB%BU` z)DB+6ae;Lke4zK1>nb=H+~F}BOKHE)#+*_pR4@N$Vcq?w>|`{c#-eHfj1pua zwibvrHZ##O@jkUs$uvT%9p?j$SODT-io!LF$!xrs%xGFBS&U~VpP-)wR78xKYlr&b zg9RL%kpcxc!-Ls2OujpK=+=#Amge<44qtu}uDVqqfq!pf8n3JW`!bxxUBr_KUFw@S zdw&*dIt2--3d;@wXTrZ#hIxsM3^7?fYO7#TK=wrRA_)Wvg`2ieaESIDeMKs8t2iSPm?TC%=-*wa?|+A4s0ge>C9leV>GHBOYPX{7C|QGoi+l5B}I< zzei|tN2+p=?i=`fBGk(4nn79Z--qQk3_p4d`Zww1scN8dI(x-5eWgOx$g7G z*y~`U0?{zULG*7Hs3S87{LswKwaN=XB}3Ol2UUqgd*D{`uZdsm_;qE_XBTODHyU zDu1>Zi>XmQNIu)l6JH*E`2+ZBmw)e7Z4fi`yO%LwwMdE$MviRhRIr!$4y7$ojFuUT zJ8+&%vnbp(0Cc0MERv7`V+80o@FL*+b*?BiHvZlyby`io_>0{P!DQSR-KtC z)`M|5tIeFlcRXiJ$4a!$PF`;3>V-^1^90mvZsz~U)r*-(+#S&Hg6345HD3U2G1$0a z=XIKz+#;jIQY=2OAr&ETO-`A{Dbp$nC#=E=Q&{)~GRv%Y{rc+KW%ui6W&pmb1?z>G z87&KoRK2JO)vtS2au}<J)s;fRr1k~DV}K7hmz&PjL?ksbmV z3__g2I<8<-APK8|N|xz^Ii#WZ-0etWwKFGv_#k3{!79LK;4wiu5H>1k6FL@VHJV3g zpuvzwg-Fvi9%+it@g?#vApR#hFlW(r;Mxj_|9H+tNudk?u#8KE$_Co6x&1W+0oPU# zas=uwq+9WRtwNi$K4vwx(a)wqrV;3ej|%L^67yhi=u#X46<)=b2L2xSS&OpI?jn^ zT7L*Hh1ZoZ{O3#7xKr%?^CFeNFCN(3hChsuQ|v5FLztFk_qqH9-xXi)Me&6rR{_!| z4rOuwo(-hlT?zYLK0E(`MtkOpukaD^G2-<(FZ&AnJMc0;&L>U}KRThSjs!5j16^T#Iy8J`hRo7^@k+N5!! zR6h=XuzRF1*+aCDVhwsQUc*FD$SJu=N5|^r5eh$ZeCCukfIqiy?6SV>x~yLwL`Zf`ziJV>AJlA|VC1O-XakNc zM8qRz6ihcyjCV(52_+aC$7-?en;!4JDPM~rX@+2ZZ=;%i2q;Q9W}cgRNAFvdtAc-z zzp4A!n*oyx)KCXL=Q%#*cT7F!AR!sNho1o!E!?8NKP5yFd3*P0eG?hf>pL0*f-wBO z#NSBAw%QPh-23(xCOa;f5~JRyr`!rn)`}hNnWku?#@qZld{bRW&;8_aL{IfCus~7f z5wrs`oZy_qJ;^xAzBo0hPvVd4vCqFLXT-Ygnu75rq!d_Cwt#?SeXLJS_AtigP$Ls& z3$>4ESaC+}8e8f+&2?UZwuMr;Wcwmz7~-f%sQ?zN0@pgfS?Nq|MzKWUEr`&O4i3dO z0j|@G8z@LLTvENmk>^)VnaDpz0$)7&IXi?>!<` zOxGnE5je8KFN}!L?pkX@Xj}487784}#@gQLQE>2RBK}S*S6L z4mF3y%6i>R*q)1aH*NbY zT@w_Te98ylhlHOV@s>DKHFy}w&}&5tU^PO|HKSg*jRqcha<~W_4muloF%Z}s=t!Ps z1b_gQM@a7fGOxAH1+OR%1)>zu#6vt{k?>+&UM%z1nTaC~|6EvhyX8d*Rpg}=1Yl(o z75U*yjv5R2{S%prf>^7`Pd)>!@?6HngM#tXxDhP8yEMmN9;jY+Bkn!mZlcDN9?zvp z&Q9P}3NJaud6yWt>$IIdH)mp9eq;1N$|Mkk-zo>roe~2%!vriZ=l-0w( z*iN#s?>lhRz06G_WM>j~6Ei}iRSt zM<#;qYlee-61>*3bwj?v>5nrEdj(muJWps7-gDO7Ub6}x<2zgIIBc+4Z~;gj+_!~x zIg`gDO*oa+A?4fh|Isr@9AqPcU-&8+i*Tw-PQ`)JC3MfIaQHQ35?{N9CzrflxZEz{ zUP1s3>^0~=`2g&&uJCh>gL@;4Oc=BTTn!AnWb1{^n{BUeq=3)jhQ5iA0-w7%(aPfl zTPdZYp_eLtmrBM<_^>MvdrwZzk*$5W4fE8N$;K|Eg!#Rif|VJ4mQk{7ebeXu8CUql z(KeOvq1xLVXcnfYcw~3ePT#8^e)uaR{qxd@4xdvn;WqbdT=dgCny!zHwv672BWeE* z5Blrng^GsGM(3^e+ibnJy?^fo88;aKLCZHVzoP#`eD5anJk09;an~3Ob2ubo?l<-3 z+>7=bqkQ+4$6}b0-govNkYSo&MZMv=5c^)Ndy0~{*~*7DL`G#=w06sUw0kS$=G+h6 z?cfyVg%5V`o#C3vJ@jq~K~8XejP)^P$R2O)MFQO8(2odZzQr|jj7du2823gHo4E1T zx$5`-(7`FN0JkLFbQ>M=B{Prf^i?;u6t`yyI=v>9!z+CMUA5;J?z7EykL13)ZqLCS zj3w>CgJUOl?EQb`nBKy+93I(Q*`lL^E7qmhFJcAU+K%0GY=<|_jxD@9y@x^ zQMPPC*8UdbJVf!W?(v;#cbM`UZTaEB9`3-6xBuvn(|YFTE}_;ah`m96bTdCgvCV_x znXo#@P58QG?$l=}oZO{zjsgc0;SC)4?MtQ?Q zC6-hXXp2M`QDqSpdlDECWNb%nD$n;eO?KdBY^<^2A=^+5c7-g?sSUL!eVjaM|F zwftT9oX9t=P((6C$szQWV&mY#9+Ud-0y7iIa@k?BQeHs6O*t+JBEt&ZnxW8#}E`V^EC{- zS?T`QJ4PyZ((barE!Byod+uYl+C;%qIW#djxty2`dSma+8>z|{wW@}JsTp}sE-N)U*kR1NnDG=Z0iagqk8eumorY#EZ<8mM*aB(NT2+jBzR;iFxO5d+j9Y) z#W_-){WIfjLppTWVYGQWxHj=f3Hw*YbC}KvQV8l7g0-83(E;9u;F?VW2imCByzOYn zJ3cw?4YBS9@EMeOUH4Wgk`z%)rVUqIk0PoI;5<#9_iU$pMeuQ@LUYG=1~>TtLR&)c z_a@cj*g{B_QwoMLN#P*$CzNPjXZ1^;`qY0wZ9mBwb?IT6nXvAPIwkV6f!;qud}0`J zGez!YyMy?Q6{=|wkEC(pZx}k#=IAK`n_2-IlE~==I*EeO*q&g}6&3Y+K`A{aOn27i zn3?IAdSK~*8k-}ZJAwpiK6e7zc`#k`sd2m&Q`wj!;r0bk>o-Pff$FQR;SnDxCyrOE z$4{)_SS0i?x8M6xK5H+w8iBmqKOI|mui{1Ay|SIn>kF}IzdIjjw2Gvs^1eL?>wE;> z9s>Zz=f)nyXmZ0d7QZICgy4pX*@>p;lhf=*C>J)&^(NL9 z;W$vPEG<$@3@~x_B%eZQp{KY&5--n6bI@`7HFP34>G(ApZUG+vxd! zHSA9Hy$Vw6Y~JAiCF(i0#RHu~_`@rDFq4_lZy^)IN5Ib#WKh5hmX8AIhU_wcjDf+a z2S}Uc?lK%~tlQ~rGNreTOq7)slmF6h=@beQM<0%nZGpFA(ZQ~_BS03&Wxw9+becRq z7D{Qi4Y7I$EmUTCtN|ce4a*ih9VX>`hahjZh!9W#vX}xoKoy`}ZiN=RI2%TTb$8MN zn80OAo+mpdL2Uy^j><`3+2IgDMNI;w6?+YVN!@RiDM+>V`>A_*pz4v-bAL+_xo|=q zNZs3enc{N8M|hqX$;slH6k9}DOQY95Vh0@E76u+#-kl`veE9eJDY9HCa%8$lX`C(`&R93V`kyQ zwbsNoYhz7>NuEcTWD^{ON8M-~a38#_TxjBu1C%sOr&<%?sAbeN_!V0*L8qqA=X80J z2m=f!wi01Q?REb`#!kCk9WN~unKKrM+=(jV%5F+kK`=g|6y(R04wb=5-NbT{z5(? zvJQCQ`@`xuEAAK*#>AjtPY_?+elC%pyugFv2;dUB4bG&2{>r`PmXvSj2@xG6 z-7o_iX8EL)pU6u~q(_klIPn5%%7y~I)G59CMxDMwA%ERyJRTi}VZ&DfA%CyOza`Ed zi=F`FpeaJ70l!f431cDZSi}VqQbz}oJy%g}ja3n2=kiE@t;#;`#Lwb&+ zNugCQ5uNg3@H^-ikJJ!XPhW)6&5ZwaN}qU0|EXd6h+bh?>i{Z?QQ)8$Gs<6x!`4kj zqDgNC91A}`gvWXpRZ+_fPAT@}CR7mpj26C5xFSmt3(xN#w~gWd3TY+4lqc3 zn5Y*vKp@hC2lVth9B6MDSNZf|;%@`GNY0)m?EvK3h96TmjrDK>y8S{f_jSH}7WBzdG!mm^ldLyn3q?ag1aBuIr!)DMKG7nE4^!o2 zcKiVHXUyCZ`jQf)aU0M>824mP+OOdjlAnb)54qN0T7v8fdwzHOKp=g|?c?NiiQK5R zu~+-Qxv8jvJR&#DRZ*d9Z^2h?$uK;|oUDoz2A79WKz0KPV{gKOi$eDdjIX!V?OtVL z*T?V@_iMPPqI}5ALg*Waaz(9f- zC;6Wr#3tq`jXA4f^dISMtt7{jS3m$vK%)bXEM<&6u(uUOMabPcmVl58cC3M0Tmd&8 z@|}&3%sLG-oh2gQ*ALs#A<99ELUV*|q=7i~qpVD^tbFb}s)F|8g z?{6cU#e>jQsphf!&N-c3{-W!)`#etP+k$3tFx0)}%LqhzH<@$A;4#RlhV}<6J1%1Hf1{naW1uB$r_7NJ|(h< ziA-c8K=L$rlzOBEXV>}r3=W77^KZ`Akl$ZaBK(%J6^qazq{beC^v&-}i zwji)NwnS>ox{$Ir#RFFL_3PKa1eAr#hO~kKM?piXD%zTZm676_xJQf5J9>t)GX1J;>5NmJdCg4zs2%5MEFMdT zVn7H^vyY~7yztwOEgYG@n1G29R9tE0A{rJta)pAf))Q zoo9$01=5C3ivI#VdxSY{U+tKZ3Za+KUZS`Jj&Ro!0wlm?t!YH;H4P1xFOqg3AHZ~% zVGRJtSYJSbDw26HYB2Cwwx!Kty?(l0FW}sP>&*7k*_2VvmZ#EMIGD+&t3Pa$ewEZ1 zn23Rx5InVfG88&#hVifL7vDWk|}xjgec zN}~hZ8bd<+j-;6vS zce|P6UmN-bzs@BbX82p>{zv4PT2d|XxE$u?IJ}9-mE<1IU~v zmNs6&90=JTvqGoZuKqIUyPKj7gw+wQS16P%Hq=N!rK2OKv^?JH=*P)kdcoxG8@xUOWK{^}W6&;@k z6;O8EEko%by+b@uf2{0*0meDyg)JfbclSPo?a&FXFVMV%noUMy_{Mj=x4Tz_zD=Fs z5y24*C<>hLK2dkF#v1Pxy^%GjmqUFU-R$eERvYvRk}3d-t&Z|nqdkPplY6zF1&8p1 zGgzhes*qNx#?FDU+X=yjW)J)^Pd!205O^z87JiFb&&63x0+jU*g|g#RAdSMzwja_c zIsm0%k08~vgSvp2QruQ4@l*Umyt7xIiUrgt^4VikI^1!g7*q_7VFOvg`W_{MP_n2B zt2)07U~Z;#EZ|H$p234Y^(3^8fI^Va=pRW%l&MNaWX<{!(uTeMLNcZv*&pK3DHL zcqBmA3&`eX>z8c}$ z4g2%WZ0{O+!|vOyra?`-Vb9=vq<(ew(%r_OJ6Jql$b`ZYK)JFcKPeK0^BrTt>_xd|F(%2ktCqI#l5k z*t^7C#MT5Z%IJRE?rcz`6tb`2bu*}_DoE_V*IOIxGPocRMMVZmWt;ziiQmySGv8ku z-D8%;g3jqU=pIwke3{Ok-lX~s~iK^A)Ew|Yj?Ddqu*@#E7evqabUtd zH-CPJ2AF30jXz$d=BfwM$(M)8;CAgXMA_h!Be@g#_K5W{Bf~L8)-yCkk`IPk;8DVw z&!~VXjVZr}7r;WAr8*&5*m{6(u=ll~kRP?R>ROYqiS~p*8ENW!83)TQj9eX#x2<2XZLO~> z%rrxZR({5{0zFPAW8{!NBkIu%s2)7S%Cf`KwsUo%C=ILaUSikBHpO*KSw<(P%zmp3 zF$Xp*GCCK)P%x0N_KXftrg0PqyX4;6*%ZXDR?+SKnGNpyYxBNbC*($|_kmD}ecD7T z1mcKc+^5a$4O9f!vqfWbWv$D8MfD#mY!dg4&Nu5459}Op;>}7AC zb~Mf$@JmMB8i+C=xT0D9Sltts4IZtFy!Z2onhi{E- zkn{`r2ElKZglg1K&%~@pfJ|mOqxcx(M`Q^X+Q5$A(3WrFHuT$TkVk79<^@)%tSj_# zevM^}jLbEPF>=80>Ww255Uv^Pk`GnfIs=NR^e@h-P7Ou6&1)|c^T7J!*H&?DkV||J zk>F%bht(3jE3nR0fQSkmoJ6qg+6MIu*XaLt8GVE5JvthYw)&fMsCOHX>hNdvkB#vp z)&U*o&1;R&01#W~=>k;&+>t`Lxio0A!mtr@-7%?p&rozWx+bjG!cIeWHiPFF3}NhI z@ST>aq6AYl8Q-Yx8Qp_h!)1ur3788IjfjPh;K{Cl2b*d>+IvwvWe3^@6!|W05PQgz z6p9{-z8_dnXLBn}fs?S&G^@0Iy|YT0rF7edQ`gu~l#NTs)XP!jK$?qDS}BUnB99i! ztEw07f~WmDVKHRm_YXCK($5GPw20yfMvKBYbG{e4s;r z9QtD?ZtUD(h`)iSfEi%{KExf^GZ6tb;Dt?#HuP{Xt#Ve_hyzy`fjZrureL>#orIWAG)OtZE8-`bUmG&7;4={=dLi^{lQh z3tRDTgzlE*4>=>!-J$m>TJ_|F-il5B$cZ1p(u6IlPiuIrinx)3uzDWH&bMrteGBzI zRN~|S%?d)SVJ4=Uf7CU|+}gS@VyA@lI0GHiV0Q2VI|rh>?`9PBD5vSDE$!PuhX!skim zR9Px4z~o(SE|4v}EYnk}x8*Fu_K89oa7myJTZ=x7$>kOmlfl>UEmS3os-%gHUX}_! z8bhv)5C1Uq*U9v-8Lro{^x*Q#xDgp0( zWja6ixcWZV|3sVHh)1u_HGutFKuR;6WqY@>Pdhl-a_Efci^yIi={zs=fc^S{^A}1x zLlwng#88YCF1Om=bHFy%HrIvS+sa53$Qz{_w?w11Z)-Pd?-T7yyhY2OIOrRp2|#8i zJ!ilEStEIamT%NHA5`8v)*jBvE6|3iwj)*u@Ulki-emhAZJwmlu8GpNpB@ysFMidz8IEE8|3AE)IQ?~df07= z@H+Z}GMS7aQkp|=4*C&h+>I9DWE4R7%>$5 z`fo)2mk~Z6LYYYFNb)|Hhm-`-87{fiiyHN!RVuZp7h192`;tGxJQu@K@hT1g>V`c8 z!=&)#P!u3Vj~K9ZP^6+5&;}Py#ZYqlGL9Y^=w0v2IC3g7mk!%lKC}SfyWl|%^qPhk zuU}lvovY>8I${Dba##`c(19ml_+@S-cea+ZWYsR#o*S!A*cG{~Oa7Qcvv4EpKgMe+oI9)~g$u=E!eov2d3Y{hI6p&B7{zwNdATrz~D5=wmBq7c~fh>{uZFV2dQ-(nY7eI^3UYjit?Snt+_KniVGfyyx0?`}w% z;G+9ok*u6>i(sRP>u#bP<6!HXqi9~5Z~QKAV3=O2_(T2VeQgxL%Npj$ZDPzY?=)QN zf-a$(iFqXr53yH+-?l(S1vmJ0iKvEn5C$N)HOzT2>BLph+o<1_PqE&K%MbUF zuYX3#bxevPr% zGWS_=_!_1Ds-u}TcN$s!n*~8C1Lh?i6149P91gQsAJpb<~H^x>&Gy@q$2%Q+bL--IoRBFZ_|D!lG6r?$#GW(YwLWdwsjtHu*V zK`1-}S~-T}RD`?qX{uO35ZjS}%l&a**x_{f9S6?a68VH3rS9yJcs$Z2ViDnRk-{Kw z@`(rNjm`&Arq1Vf%8PmkV685J?295KVofB_bj1UWn^@o9MrI(zz`S-0 zx=v{t8JNh$rQntd>Q$iz6jH7vNcCz9!5l!+)+jF*R&~_RBkZXP;J3B@=Oz43mXI|_ z$W*Nb`kAcZLL?zTeItBU`a%m|L7@hEkKTfE!MxqV@~&+aJ3 z6+I${+{qk#)uB=%q~2pW5VhMRyHob~V-B0`xq#bgXUy(& zr>!Ty5{1dLl>wnI^4V2piPW5}oo*esOTB|gGS=1$1K%#~<_|TSsXS-vNW^4_p zjC;+B#(fMlB@p`dp9J0%Gxz{X_ZJ)(VQbWv0*P=cN?%DC#!I-m`b`6h_z4xQ3!*18ExyaN*5ln=~ufH<|49>lW z-tMp;1QMdDcaYrbz-cM4DP;}A0^Ubyp0vqG(m;HiNO(TNP>5AV&0p}RyT|9E%4^nE z58QR|V8!bNAULnKu=dtQGyge*y)ki{*I6r!MhF^X2pim_(c1Sr>2e|ugp6C zDYKVnl?g*VI3t}$_|FA%C_3#m6gpb#EO(xKy7F}8GBWh>9JkZ_<(tOG=&vL?Vkp5E=J$7}F^hliV|dyYpt}D}P$15Xuf3x7qh{xB*!~A` z{p!>EHsAYa(LQ(_bZUyJq?iUFL22AyQ-Y?18QCk+W^K7`w3$Koz0EBe0ddDLYy2M$ z$}YW)0|>D&m@aeOjkI$N5iV%SDH8BrNjuwnH$yfvflx+%e)6qNlkE{Ws1#)2 zbMM8;2l{hH^hB^b3b5>PJTnmpC({@bSsFqkKntQghABZtCtaV)h|%MdOG{5)9HD}g zKWe>$oD`x3uJENLHuk`tG>|QUtQUj@GR8~|m4`0~MaD!k2O*-oC0VGKQGl_Y!#g?Ehxnu+I#tYB7135hbW$2BbPtnKq^jQnnQq(W`c3N!>}pM4mng-#$!3+FZO zvnkZHEuGd&WsbLU$SO2Eeb;T|Cu3byqZ~h~1Y()IEfx1n-}&&J)4fezA8LFNbpj#8 z*PxDanPZd|Xll1Y4WSlu{)NYzP;`Xr&o?D$6-ovES@sRucYg4I1}y1!!IsX?9tbdV zT-a+$St zQBS4x;%qif7oG6Ovx<_%zaJa=`kh11#hS&KlMluT&Sy~m4*0T+&e3)eHIh{*2INpJ z!2`*&s5z`F&pd7Y<&S0`n9NFZCwY0~W6Pzv16A^BQbDrZF;R>7gPmvaCH*~S`QZ!4 z9Ia9nnFUkX+T<}_g}7_VpML@Qvj`d}n*-6O&PsvuRbV)wBLf9%36c|IEM8U0h-Ggv zJ0hL|&r~KngQE;`Y6V8KU_ac}u<^`}a+7^-G3A(*-ODb2LXip{j`9&vZT3p;0#1_; zr%$Fo7?RYxoO(3kEhvH9Cj^W}nNu_@&%kM?5q;| zpmw0~Cz70xEa?%=md(#sUqhxdju_&_Sd*{j&za~WA-o<&EarV<52K%0Jprl_+($E+ zhun>x@|a;PCg6dfGsd`lo{D(3J6WdQ1sUCC1a)U?^GsSam+1 zwP_KQs?W=k&Z8nZjEK4ah0H(|`=)plHRgPHx}m=D*)BtGqq&~8fk|l#G~bwM89|EV z&wyLJ!p90_zS!sPmjSQgODfX14=LXg%EEX9avM|pB0xe?ZuhzJdoj;y=43j`5kxwx zgdpN8-S5K7=%Gv@lTwi7Qwt??`8G}MqX5gT!4AJbv0uvqW!xD2sMup6PcIj>*E z+SR#SKh5(F?iTY(`lq=9X;SgDKdplqZ7pB|QH&arl7;|yoaWO&1;RIZ=e7Qv@~Ldg z0k2BvAl`8s#}e^K_kS6aXc%ui?{=pSPJ3sh^f=%`;L~%swfV&BJP}a3N_Z(S{Qg4f zcs`pDAR+10xZfp!MdS-#rs=Ew<$2lRlk+M2B31*|MAn^{jRbyFiQ2J}(PIctm^zr| zt_#+k#D?uNZBntpv6 z&oP@r^7ta+?0DB*#@t;Z#BOk0ObuGS(ZNN&ZW)JHp>>mkB0?mbJbBZTV#~N|&cK;q znJBhkq7ZK47$`zl^VD4pQ6Kalukvh@0wXq&zQT|pE^cfLFdf^SHP{eWaq5_+S?gM( z*BSnO|9AKeO!4%?q4oi(v5NvKp+m9kY~4U0`Q{ahR;1esj=TQV5KX$eiZE{OS`ng_ zjtxlyyhu##p9Fw)gQx}Ri?jbmsW~FXz+ePhQiWDIiCj#zxz_4S{Af6O!4{912SS#4 z`l1YEEkNKw=xS@R{sCcgdCZgH63JJ6iR*civ`}7(i(R7oq(WW6aUCWTJ^_3L!0?f~ za})tel)Xc~pjHD%0w-7gspMoup~SZa2pBwLpEI0_ zf65-7{_U80FWAxRVe;SdMWtiUwaciso;Hx?Hh=$o?buT#!ylNgd~wR{JbN!^K)(rR zQzYRz*4t>OO3MV|hme7e(YQF@ehL+o_;wVWG)2~K@K6|Oh>hTXh5X+Ynip|g692^0 zIc^T)&l~J>Z&|v}8;MOwsc5zqJ)iY>Wp`99KTcFOCZ3qmgOX<VzCtUmEO{p z=K}tv@q?x4{6%jds6^BGO7d|cHS1NLIPu8Lcq{;J>Rj|Yxe=e(#h?D(69u)!E+yAr-nQi=xa>uyRdpz}!6OV6Gmup8?Qg8p$cKdbr zmYgTc|14Yn3ADG+!ewXwEHf?U_4 zIb;@U>3A-x@zsIN@RG=TY?hl7bK`{+&l_ysML2RcL|KvLLU?w~w)&Vv6*AuJXfE2S zY>1|SOIRIk?L+;hzEoYhYpAh#Bq{a~l4WY|B$2vcBbbFuO8!n^4cRllQs(XRN#?ng zqrD{(%IQfpZ1wj9&!n77Dzbw^`gMT)gK%TypJgxY&YN7@ku;f^3-oCuO_6Avqxit+ z4Qbpf2Xu6pMriCOe41o_@`g0-k=xn31}Ztr#JrKkiL4YEE_INOCKAp1kuoxd3~{Wq zXUZbEr?P;YI#RmlH(`TEHs9Ms5!BzGzH|CZo>=^+QYH6=KB(poVR<*$w=UWJ9oidN=0~-(SVjJM(rTQ?ewYX*F4jBZF!;xIwTk|qy$WExnYsb zy~L0PcTiY_rVDF)I9oPS*)O?lAFihJnPAu*$o_<&y}Ad@hG~!Yc*9Dn9aE5x=W^MV zkSzL=8|lG7<0UJF0vjG#DJ;#LU_rSN9$O7HAE9y#Bxw$y-v*C6-;$=mkkr`^Uz#cS)EQ6AM9(~)P4r`3Dj8Gt9=;LFr)Ac zAT8#`bgW-l0T)iai;dlcn%XM9H&fZzMG{Ga*rBw>2AO8U);nOLjvN(E86>M7g+1^n-XZB1(OG4gRGk26elYULPz+!|X{qpE!FSVWI;}VG9=Dq# zIE=kMpgF=mZzb)w`6_lhd)%Ri4@e$8oOMQg-rM}lSH`=KIWm!!?AE0taDn(-@r2J| zk9eM+n4*9$E$tuQw)rP}TjDh$!6<-hYNGNGdvhqT;H+i6MSsodmDF(5;q%CkIz!#61QC?8h~SknSS3M2R~TxMgza3~iF9h*L99DMAD zA3JEAo1Q&t+o4+UM zcJ%%plM*1O9|f3*k`ffeN&t9B%t1;JQYCHRUAedq}Oz4+k= z9zc@#G7Kkc%y{Ml-#&8W+ehAvuo_|$d`m3zU{0Q7gf&I-niZaOjP*SXF#C$s3lYuV3@Rw`bR04y59ucCvr!T%2)-PIZCd9i>s-5beqw}-Pov$eNr@j|D3M5KYxNyN zbf9SzZzUpLFCK?gHtmJW;g-LjYFw{G+?h;qoptK=XnWG_gH=&~m8nK4jFr4!5 zH45QHhM>A_9tJ|+H2WdeuAg8V88?=meGP3 zd#jCIGz07o+l=U%*uF%s;`)48 z`aD7;vP~eg;UwpsyOY^)+)JezjcH>u5`BSOl?DEwJp^9 zEtt3?ksyAmZC2)eXOWq7CWKmdZ$Wrd8gK=UQck?t1?q;RSuj zG6ViZVyPd_Gpx5(KfwU22Idpast}GqC0LvD!1mBu9C?MDF31yz)VxB)wUA%XTzDU+Ju^uB~F*t;RfSe*daJOphh?18|my9dAJD_E8w&T3c94z2 zJOdqM?)G_(-BOsX&6lCSm;!!r_W1GHq6yvt9&f5-1l}@^HNgYM|5fw?6Z=+at^Moh z{M(W76}|%;(9qc}w!d4o+jo2)*BcGJF`sEPGV`0aNcaoJo$s zh1E*ii7y6jXn+$*h}%P2HyLB>+*`s$>r%=vQYEru>{N&k{D6LLTxYBJtaf~^)tWm_ zvt5HGTAr`X7DyGhmcjM0RsD`}n0;vOH+iW9KWsELN|Way!C0G|poKm?bFh5izc3A% zvQ`wPAxp9Wk1%aVm6p!fSfQTM3Pm+lFBA?H+PR#-$H8+UihX4IF0g?@)?efmtIEE7 z5!zod+o(;>R2zD+UPBV<;fH6&wTwPdn9LzlwIejF-ZttG;4fD2M!Aq&&=K5EF@m=C4ru$ z#W4-DCv*9@KZqYiirJ~iIk$&+K1TdmX7s}tEXj&XY0y+HIg1n@uI8+hOho}~^jPC} z@En3Sbt!B?Jen`Wdi!5INn3{^0d#%zmb@LreGCM1QE(CYhbW+vB025c1wtb<{4PcG z;ztB6%|kyCds`t>Ceel?nr#G8I6V~8bBL49_#|&2>R0^H=L(6A4sa>S8|1G8Udfjk zmkW*Dcu)-ju!CLd0?6l$VSxAqL%0jP$rkogLR#;S5`~~o35DNai+bq|KmTIT7xVi! z<3;3mctRo1rZ*V!VEBX_(&fP@6eftNT;Sz_Wr;K;@*6a`LOo+EQ%E}k)`GV3ID5e7 zVBT1()&hrJ<1ZRszY^B)@_JQl40Z|^*Y1yd|MG( z6~O)$*jV6IndXv|bDngERD+)ls!7c9t1`(; zhmSvXv_n5RI%&{PlF>E1BR+~1V%Ug!Zk8pT zp-+5Xf!+&s+j>JmKEF{fZmgXXSWS)Jp7Nwvp<{gk z?LLGxDGaJWUcw&5*<64#ivRB$1WB#HDGJ#K&XJZzE)w`!p~>(M1ZN_fHNTKj;4z4_ zqj4EF=5+cz0hdRzdwdS0{Wv6dP>a>l7z5cQtGbG8MakvzdKAUub-5(G#GCjCBb2Vi zG!)vjsV*q1b_og_TeCYnzEDJ|sexoJqU*rZR-?Ml<1bAGeX`TW)MQdM42RQ=8gWjC zVbE)4bIQKpRLSGhQ@M~w*CV-PK#f&PQ4bg4NsL^F_ZB8{*j{m#;Y7pQ;Y(zOP1`7_ zhlg2KWGDI#b2MbH85R|`OaPhuxI=SHo|rkl5I9n%^$Q$20W@>-(8P3_1C*SZq0)*&esW^ zZHYK^e32+`Dr7*wgbk*JX)_bV;K86UQ+W4*TPzo%gSgx^UGIHIuVv-(tNpq=7L2Ls zd|FHRYSoES?cmd<3GM3DN6);bhAL&bls8Zbc+-a~YnN*uXW9>d4jAUFWxIun1LQz5 zxb;e?p5tZ89gKp#0|5|t{Rl{f)eqKj2!rKH){WNh<8Eo^|gF(TEmL z^j(vx7jf5qptftZ`)m{qK2#N5uQxc!!K6*1Z2c)~F2IT#|5qQR@SiQvjzyPoVP>^KA)WJRSx% zC@KYtem6}HS7xux=Zk^B>O>|pQOGDt<_|`EE+Aux7}2N!*GU+ zK}P5RjKjcrtHX^##VxV#Ebi8i;NC^`Q{%CC?`k|Y9?^0Sz>kiUr|1JY&3U&Nt%&H< z9zFQBHx$)YRy5R*DajG}#8Xwfz53J%JoRpfS?Y>Da<=^EO!OrP(+8sROBJkRIO8;o zIfr`VLr#MaKM;2tf-w^R+coeg3J`olFkGnLy<_-$S5qBZz2Nq>8CBIBnSpy!-+hBz zFNTif?l16pm{@(vDCAysZ~mWB07om-?d@c$QW%|x6Zb&VrXxkr?uFSV!;zOv+G(Bh z00ck;f>5(3L-fmt8;6ZbEFEsLub@jbU0UmROVkIcXj8w|UqD6Pqu$@AmhIG!BeE6= z3{6P{GsTwgNwId3`VuMymCyJ4Q8Ih>>D02%js6@B$)4cQoRs)%@h+LFx!`+22+CtA z)`&W>ccD&VW5Y36=c%!33kB#ikkuTk9#(8{p?1B1gPP~HTpxo)6w!~HhEdc@ zlcaN2|6iG)(t@xqoXs5E@?%bd3&L4*y5qB zP~2wpK8^62EfD?I5KbZXPI&jN-!9{~dG7rpv6B03l$a&^HW!)|I?DkqLqae|^`u>l zm*VXIu0wLLWH{t=cL6EOg5e~Nd50HS0d_nrqvWjJ=45M<;}VnedeP{#DH;P0B|R^( zOAhHj*qL3D)x`RGLX}~1z~JN0G^a{XB!FB1_y`zIHOL$Qx1@};{=n*BBdTV(423-e zQ8qS^Mef6y2<@|rh@Y}*w<&I2F_tRMCy*cmoR`8OBzhQL4>FhB zu@2xvBW{J8f8YH0L0eIhX3iM?#1jf-$q4mfgU@-A)@9VJOhGaNc_d)!w~Vq;LH@sZ z>N>nw)!eM-6soa*T?m%1LkuKqX9{pu6*8n;2+#JS7XVa=3SeMU?9z}6EnL0eRZ^v&&7F29-7`LWG(LZ4 z&Xe#2FD|;>uN{vwML5qsQA!2FaR1%!DyD<~KWT3Q=T=(XiR#mGucRyK>Pouz>T0>V z+N-2e?UKBf<)!UzySr^;s-WGZaZGm;tm$qV+NRkB0m4gnLV%QeU)oO8)J z8Voj+sPubwAfWEU#~&^fCMn|w&DXDB9r-a5@a2zuy>VJPU_AgC;1?9(n5CeKRuwV< z#0E$Qlu?tpMApl%)v-~**5}J+JSh3=9>=(EWuju_9=Ye9kW~zaLg6A(dWtNx{k5kO z!H7bsB!g-oaWSf^c@2ro(yQI2+ND)*bBd-piO*E7ex68i8dqQ7f?4W)w@w%mQX|ey$ZnsiDQ#}+rb4)va zTGvii(svy{l)@F#b7VPwOQ0@if)a$38i*vvT)4%jrz%ol}(wI0s_;9YyEdH zb|S+gPIpmPl#cUF%m|uca64K0U#fbd+uj`-rOyx75VUI=` zV(f!JhNY5)R6eFiuR6~9?>zfE%l{hx;(QN5%; zl9o;d1F`SvyvC+qV#xB$u{qzEKQm|BFqmUI=(Wz&)O@zBhnam zA@T!mPw9|O^00B&8y7LK#CRYtM2mK-yaUNI-3AeC)U?{d-KBi4(!XBK<)`O%*Zja@ z?m)QZ$%ac#9899L7Sq~TZRxfabLM7rL{=3&q6eE}y~fA-03mWA9%Ec(_~VD;I>_?B zW%PXz-NgqY4Dq*e6$}New>ghZ4S{+Pg@=T>EwXZ!IY~RJn#pLk{wAYlLludpbThDlS+FC~xI?oLgVCqzOw5TXnkb&*6XKTd z|4eFH$`%S~XEvtqt2s%>bW~Fw&Cwcm)EuOwdt5k<26IGfWf&$X^84P&B;B&Fe6>XY zDjzPlvAJs>xpD3eY~SI*I!sI_#}?w|e3pOd=J|Zb_PrnHD;nG;4h(n%vI1WrgV%6E z;e(K2wjpf{M;G=GII)b=6LShkECDBJMX*2Xzb12^DmIfGj`zPC4nvPEX;$XlW9327dbj=Se_Lo2$;vP`e0tfR$E9wtc5m8Cos$yRLciB777(!{7!sw zzQx|J*lLDK+Hx>adgjo~Oun?g^pcWN|DylBQ|af^saDHkcHPE*E`=&>_*>4TtljfN z_(wKBgRhmA&ZaV1E0s!h)9Ee%KPBCE>N(~l6jjBy1YaOPC{=8w=qcz=IAzGpM@5o^ zF%Z*07Qrm)L*|2259Lk&?70IX@%>NMSd`Y)sN?IKs33qZ2+u55ksgZD!eEdM2J(O z_|XGUxOmYZ>jj8&2%J5C6);hhZzC_rs7T9Zl?;(pXPHAuSGi+_$RW8|oJSrQ@EkIM zQN0c1^nlyO#JNndv4jh+HesH}s6Y!7NX{(lt|K!aa)GaIkk}atTo8A#cj*wIkO8&V zTgA%&Rr4F>z{db%8Cf(PYFp^6bjFaTRDvY~a!dJ^O~Qc>ZVbN`h-(*7H*tY&+j!TS zp0SRhtylfZ!llc&g;rr)ALQ z58y_F34p!o>0@u1uj-FJee^9g?G>4QyY`*gt!H*ejzuy@HLdp9r|)`8e4&+iwD$DT zr=w@^cIFkkjZEZdWLM^BY+j>gx&H7!**DowK#C(1F15j7m{@VVZ2&S!M~A9{g9|*1 z9#Mu5R_Qf*g-GzbjZaq8oO(jtXWtuNj01LAse0?VxVqcf9hiDsZ@PET`;YV)d%t?G zYTp}+P2(dI!ANc@fRCv09H&F91=<%8j)cU%AS@&)blftTkm6bqzXCkp)DTxurey+2 zn*m=6`=AzAwDPH|1W-jx*2)ExVyShmpz`i?GNvQ!IgSd_r~yL>(Mb%!{rZJ2>J3r^ z&2T*o+b;>}h!B!HQXmhSCm1blA#U%6O@0xGw}thaN$P=`HLT5`f<;<0j9XAvC#qgV z{Y|Xamt1}$Op7=5~k?7)EoTKn#7_U`sO`&WLfypV{_9y@hxHkw!{|5)8=9o}2@C+G5()!6gq z)XLYLa{1V-boj6|%cg7hNB7-(|AAuh!2S2`i{5`dzq{nkEFRillO!o{^qn0VL*Wjf zI4xeopbSQW-AgVG;lC!ul*i)W0EGjPB(F!BwfOxmcKTDjPeLZ5uziiKC z%d@CG-ttP4w}o_AIir=Tq!NKWm84~+GpZ3$P{zop#C!?ClI{za)7d$j`S(=d_mKh; z1@EA~azQH1gu;!~WLni7E3W$GWG#7W7{$-1BkU4f8hPBKeUK*9N;3S?7NA{;(}uP} z8)%~3lwoBdf$f>qCmNX9I{+8y={WmXlKFzw9fiYOe|7E^^Fz{>aAe=6gd5$s| zZFTk4g+s2@1mc5yA4EQodgzde=X6rjk%Y)X3Upa)F@RnwDT8k6Fl=Zk;N1hEIz3;h zq*i(PTh!56tJ5O})O?TL>ZB?N_t84|N@cNvm+*jFM)Vq1BKjxn3u~+c-^7yZeoiGH z*MVq2R1kfF9z24n30Bl4@+ZPjGwKonC5y-mEXu$O+DXbFve70e!_D9}RS5-yp-Sp1 zQK&{k^?C?9ihp82JIx6_M`%ushp+?QqK5&uHNtwTg3h5|in6XK!|tF@n`7RAeXIb< z0~Q?yR~JTAP>u1FY36nwZK9ZPbbP>(Dm|_ciAp@YF*ep$Mx_4MV6b0usVb*QJ$ds; z~*y8Uk{i1m)-t4iDq8U|9E7-RcHA;4supIUJAK`2G9Ns!>L;CZ`w{W6sp zxP0L)^-oE_ek%g5m_+nTGj>o5?ERa6Co*tqA0oZ0O94F5R3)Ea5-uU zyK}wMA(l43%k=wgDPZKxLR7VNvyhf2{k~UTxNtm?3~TjFNX-DL2ij^`(gUT3&Tq`YusAy{q=plDb#G#4^P3Y6w`OaSJU9Q`I{VLt=B z?WFyh^>E0^6ty@SapUPyce!pE>AamU&%-n`SR*UAjx^wBgUirW_A`Kc>d4ZQ$Tji( z*ZUu9bUV|>b$i#FJ7eGNfoos|$Kl!n+!foN?2sfiZ)Fl2t>&_$sU5venI*zhxdaJ{ zAaclZedF`UMiHq+Vs*$UIRw@Y`4Hurr>Y#_mUK=@*u31tjTS`Il7}=bS`kd2I5g>= z^hlC}bn~m#nTfmNb^Nei<={lq7lIwT^Kk6$2E6F7Q5c=xK&Bx-tO+TcS85dC97)!p z3y@lb8`MX06DCG@WXZZ~ZfRV!jTobu>MCqfjx2dW#-WMXGfk-waLW;+l(|09Sa>zM zOVq%D-?%&WFj59n!vSbjF#wJGW*UkeN%{V<@tB^Qrptu&hv4xX8V`pJxT%h9QLSJBQ5+R{V2y<~95@M_1(f2*q}v%p zy>Xhr1({NBs5ZpH$V$MAX$j}%~@tdAjS6yCAjNO@#>;pF!Q+_uLZ!G04m_;9XX z?|S3Qo-L$)00*N=+F(|9JTP!S(g8?=&h(o`=H`ixusFKzao=vFyiAN#%>4?&h$BmK z@1}9uer^0F1}DONTSw3Byin92r?-@zCK4}}{IBIgd-_}YL-p`(g*Hweex?ldDH1z^hXUf}=*R?mdG zXXx83w?-m75e`j+6X`fJ)ulNW<1Sev2~rvq^)P(P9)wqc!Lvw;RqZZ0flX--hRu6>AoI8DJ2yYy*nc2+UgnB`wPcKdI~j)|Nq0IHf>6v8XdCVu?$_U5wjS&o z=w1YYAdLsM74j*8CndJuMCE|$_tlYTFc69E!qZ=?aocy8U3Kg61Zv^=Ee=CK=csIk3iQ2UgZ92DO1CVkfyqQ}q5 zgSXhPzy?DNKsqUkdL`V#G$Si132Oi?5TnP*-U9G!o25Ek%lVY3FQ>R8s^6{DkfPNu z4_*tg!D|t(f1B0&tdf(Wieyjv{oaUNQ`~+v;>K%gNXpgdHGeJS_D928#(vKA;EpSK z=hcc8aK~M|kzZ_g{!VVwL;p4-vCUHFg7{5~`q%ha_;NLQ%UJlL+l6=1ag-jq6o&t`1=)Zppc~<14o#`%Y#DF)%9cgUS0dTSQOpP&(>w+@gQnaE)Mr z9<+=gtUQGHfeon*QyPTL0&c7G2t$xj781olD15jubZaBr=eGjx|C0rd=d3qc0C~L8 zs(l16xF2V|bwud!P@clx)o4`JP+8*&N^3-;(NFVu(DlKaNB0)Q82=~s9rg zcnK!rb~P?67ce@N!Scw4i2oJ^?Ey$;c2526sV|&;qM|qLoRRDQ$rEQQO>+@Gn7@~# zc~pg|o;rn3^nY;ni86gex8MH6*>clt+BQm=X!4wdPY53P=j^xGr(i21gsKbhYwpTK z5=3frz~9&djp+wZAQt5hrcX4UJ7KHe+4uRgjR)D?)6-{9#GCOGjS~$UFaPDf&p+6} zZpPK{!*i4oR+B;iDKOo^YoeU)v?tdIN8})AOZyNS=9%&cq@Wbb)?Z)rb zR#)L=L0}T@aC1h~qu~6I>U|0yB78(`Zpwo(9&y!GoZhh00K!5r9>S_}_hxZ#GmZ6JWXWbF56k>UJt&XMLQqwUSCETHeG}}LFpCe}1veQjY2Ed$DDwgUzQREip z59b=UwUKQ*k5z(+iZIlt;OR-p`v$BPTqflB;Xu8-*70D7LKdAG z(>sqz(*(J4VW6#dJmKZOtc&%rHgxjm(^SLa52@`|tpJt#@57$$+v#k?5#+vYJ1??t zu%Cym{6~@hwOVN-&k8B6^h^E#9%cu(0NTcqqq<2H1R=@v0m@@hq_Xh{&VaI8q*w42 zII#)03A-G=#r0r-f1o3g@&8f4c|De7#IqB+9E?ro;)aw#P(YYjMTBO>7j`ei-AQwNd6ES&N!-Dd}dK zomRcx$N|MJ_zksg0v8RA>w4+`Wq;1z&v`HTE8#hBn@w3V72|w2q$5+ z92s(Ww%=+qvmk|8uKS4#KNplgsYKjeuO3#UPevp11)uRIB*%o+21_-2w;f)8hvu*r z>Ja^J&jt4(pKeP1aM*oF&PV&9@N=QK64Juoj9I@%{6w646bdE-Nq3qf={Wa5$QMGt zh;Q(4#G}@3L(cU6|0cKH1FgL5Q@gaM~fRXb6r~=|8 z&?w*#@VljmAq?WLR>u4Vhfl$Qz}CnW5YCb-AUnP33i$1zx1f5c!c{%qFYprdj1X$b z3k?Um$z1F6uWGZkmENB2eJ~hfe(~Nqd^>bL(W#GUK;Y$05Oh3gMBd6 z|5k`C2&9UxUtO;2{q-Jmf%&84BGO}{bUbQ3;F840L>hzxuEV${_}J*TNg6EH&F~k` zs0IFf_?VvY$MhaA7*%8_%2n5mnnBgMP@vYp0|NpD-POCD3;L?AvsHMa_y_8Azs%q5 z=*x!Q(NQGbzzh0-HW6C@+iqO=C}H~na%p(lFraG&0f)%sLjfp&Tj)iUM8bY-Z6rJq ze?08dbsiO=>%MT@AMqsWQqgS~D=5!UWUDCg9Z6~aM^VYILhQLhCH?$bDq_ZK=adQe za`srpFfzxo%kGJ>@d}f#j^zoqLuU}MWfc#2=3d60>0cwA>D#@jH%#RmwmN0g3%zgK zQ~jO;hZybEVd{w()*tzTwqA!$ei~IBM*gi={8`F049D8m%dVr?cdxrf7st=$^~G8N z4vNlTnxM8mJUxKaHe|T@M-B6quG8hO5vfx)Gi>ApiuS)BHO=T((PR&WNF4NvzcW>) zm;2v~n!HugO^1CVl>7}n@(C6A#@_V*Hq&^*e&*Z_{rR?ySD#&>3y)vdAxU@ZNa1{k zlrcCEsY^hbLI{NWY;zLaxXxFJSQd<$Z*Y3YapsQC$#t}jH~qYuA9i{t9C(n&+tn~f zH?&JYf}7^1f91;R4Lw<}T^5tFc|EFaS`;%q{Tha1e2B0LX#T|@Z5!;5;uOEs`i|p9@3(duyUn(#j_gf+qqHMfU8LC{ z0q6~T^Rt`f+U)oZ3*ozC@0}A%Vr-2K`?+bLIlykSHrR5zZ4duGxkG3FY4`zra>p(Y z_{BAxEq+(WbppAWY0Ze}AQLhTysdPbV;K-Na<_u#&4a}b-K}l%Mncsq%8(2ffga+~ znc&WpNlW=k%Ga!~6&X{-_13F+J!g7~0g>;k8xdo7|Nkf5- zH({#c-Ny|1*z=`PVMlRSnAff8G2CLPyk0jN z^Q40qE4P=$bPcx^B(zSuJqV^BON8jwHD8Nj%8v&yIgtI8Zxlh@yo-f_{cEUHyNixx?Q& z+?ha%|68b{k3$4Sp|=6f2xrfA*hEM!%0n)9`EVo<;A@Co5%`rVI0&87bY?)}Ew;@f z+qmG5MEn3<;_lbi*H_U^6!jw9b=be`j|j|n1P{Xi?l{Oe6mo#K9;}`5Hi7-#zE$F0 z6=JcuCI(p=w0dcW{B5=|B3|4ICbH7 z-1_F<-tZkJyBQ#GWcSGD2S&O0SA$B+d^$G4$4m(D` zKVq_Y25TN}>FhhX(ydxY=A_AkyZlqW+P=fhthcx)Z_UIiY;_otSv$GUS+81ChZjSL zFhtZHwj?DJCW2_L16(`GJKJiL&JCrtwm4!jM)UZ-Ev3 z^Tor5VL40uE%L|1gwes{^vq)v1-HTG|XbGF9Q!mmOMy- z{G@IZ7#vtjtt!X2SP)hlL> zfhP{f2oJBHzWMrXI>m6BQMlgN)t5xo(cCo7teYD63!7fX9}GrY`rt!sDeQ5$Cay+_ zyL63r#Z#5Fg+H_pJZ_)r!Qez)=ytFEqkZ5B`}D7DQr}+(@%mtX)_JZ1vWg*^fR~jA zi!IWBn|1Y0zt_>%V4z%v2u}t0mRFaTFR!c&#uT~~#WMRKXC=^Q6SlB8ilfANR5N;u ztGohMmrS+Pe`C7kPjH#gy*Fi`{S6>+5g5|9+xz zQ|F>;<-p#nI8fm87(!E6v)O$9dHio6m3>Y(UgS@nZRVGpsOgppU!N9aY^Bv2WV ztA-)gM$2~>&K2_&PtEg+53qE91+g@&gXsV4y^}{T9qF$lY2O<0FRTrUJyv1qtN=X& z)nO>dL68=y`-UesSQd$2B=5j-Zz2OYBy1#hCqBXu5N-Vg&>fI-=UUw^ zQVY@Q9DS%mpD?1ZfwoA^y0lWmlm(zStiukvj#DLw==12v4q5~~gOSO%bCA25Sgh3r zxPh=_t4IxE${4dMvaEI1*YV$9?m^k4ALH^roGcaAODC1z$NzJ93~ib|vW}cKKtZne zj86SYyrtl+)srR1!D9>u{<#kG9@M7zQPkdhgX=NZldg-dx4PcxdXMY-6K?zme*C7_*olf1PsXK6 z1@KaTxD)mZ8zp~e;1!g(pc{I4!<#|rulNYj4FOR{Kd?Im>p@>S9O&@xu9GFF(+MCG zl%HP_H@bKw99ZW~;LWrz*fB`8uj7wDxU%&rkGaDt1Ff|9dS@eJmBR^QU@pxMEG5^Wjq986J+ z_@Ff$$q+a;4b{R;;<@ovtg1od8{p==+^=Cto4F)|YCMQtY_M#|9bhwGV+ z1_&(AgmrIuIX8Q3|0@Cws_dqVMRc9?hEyCdZ9ZB+?g!XXH1x=y{=pfeR`pz~vEyQk z{Xo<(++Q=O3yA)uu#b^EKzSj`WT_o#raV4{@Xd`>uyAPz{Qh|e9#v#28tr+5H>YRU+D)I zEAU!uLaT)tjaD)!5m};XFn}tD6a;f9c{`9Tj^x`SeH>>)`}3l?;~?oi!<;Bs+J#HI z3rEj&@-@w_B19@%M|2d5+jTLap#3z_rMK;gyAn8RjVt$A5B1IlcSB0GqljjsC>G7e zIZArjOaBC3`$3G;K}6HP&UMN4Gp>(fU(V-%JBFPy;zo+F!i;;`!{P9xAyHV;lKX%g zxeg+3+4dmruRZNS-K7PHH4DCG#DfD5%TKqxdl3}qY11o^)JU3Y51vlDac{SieArz)A+?j(pEyI7qZ1tA+jVZqgVUij6~Q6 zJ#MdC4ut&uKSo&&8BaXJSEd#D*JWjT_;Q;0{E~zWaLDy0Nq!&urt|ExCp)qqueiN6 zyoe&U0OOy(4{t(0KZSqh^~rC%4`>OzH43$!Mp+=emR1AUcdqlM552w2>Zf+Rl+CT#HJ{~i8Qv6tavx@TXdA?<%hR>asU zGKw+OCd)}l3RNbiDxZ7$=?VNi&6KCb4|}^J_kUSd6nTjc0*38RXYM-OP(sF$BWIh< zQ-=@#$l=2eHJkkx$DVBRueZZ4M!1iYE>vuUmhVkOyvQ%?u8umfeiZnynR*;c&80o3+d-6co9O`gK>NP@O7$#FMNp zye)uI!MpNCFrfxdK{d)4VfQcP+KJ=TmE%gr&OeR3YM75WdwV2Vn4Ddloh&3H3X*E@ zexg3HlKF@|U$x#B0$T0aIZ28AvJy)>75$go8H0Z&l!(aRKr%ICB!U3S`^;s+%b34I zt|wgYbA1eF2uMbu8Ek}UH)_?6b$i}+gImkE1O0B%Q`#kzUC2#)3wkESGEjC7oWEvs zhO3>>LCI?fga+~XDuhA)QEV&X{D9Bc?zVUZSH(8-m


C~-^J9kuf1f~B&vG+GBd zx-&Uj&&Qcj&1!!c%UMy+t7XOOi6BPFty+aAg7HWo5b;MTL839gStAsTMgs20r;SQh^Tcd36iF50vcyLZ zjUpGwlqJC=m#O~ikdf6C`PIm17gs$2e*$E_Qb~NCl49*gH%SQXF0^c>A?;J6Hi+zP{ z1-@2A9HtM>bPE3#TPeTIHquhr3}re=MRS=f>-1k_%J1R__cw2#&%N^5GpA0Sd3JpJ z4A;*FbZ{!9lyD8A6h;<#Iv0etPss|%V9xa{S{mYT85tqz9MdkNT9T!$Uja0S*S=VV zl&*!tg#o%BB2mAGqiYVtLISzmsTnnR;e=g{pceQen#cz7BKv>XGdRWe!Q$(ROK@5X za2j;?D#3N=6|xNgy+8mS4#N}A5nO{;#OGuf!t?mQY#3h%#8bhu#tDST#UxvjZ2!IH zSz~Exr#Iec+cuk~n~TPh@%cbH7I@IO*Kf-*zkvUQ`Jgeiq<>-CH@<}L;Rk(zPZ;}? za5OjpVNG(=am!p}0fGSrjvm~;5>N2aF}<6zU=2Sl_7%1)Z9f$H9DJ3&L{|`r&PUf7 zTn;ZI0Wz*hV=3m>2MWjnM^3f{6Djf`&JBEnLYux$Zu6^GVFTgF8>@Ng`AhKctcY2I zB8|Bl`MA5JjRI)_?2jySOx@IRD&zKu0Zm4l`!dsulM-j52{HuxF0^pC`5%J@_z zoeFL_b7;}vF1a?tdWCg>$ACjpwqh^DihF+pvQ7`nm0~;p_>sL<;odd(A`a948zk_itN;|`KBQ-*ceOs0 zRcV}xpoDadt)oQHWUJSzlz>?$e>D8ZU5p}j2=MZ{Q(WqM#awU#81ioWg!G{7#SJ=wQ1HRZo zom#AXfX)a72$cjc;&f?26vH|PG6erfUu9X#l_<)bAtQ*t6sV`6-S@vwYQ3gT6b^d5 zz@`yIt=He^J!4rbm8dh7Q-VoK;QFE!`0iXxDPh6;@y@H<}8D4P|gAHB>on%&D z93CuX4)jHyF;a^3s<{;p%!aOLq8BNzwxf4-h@%C9RzQRMKSRVS*~R!i-TT!|V%LG1 zO(zDZ;NK-Q@DLiz-VP1QNUQ*fbR*qZHejl8Q1`RL5BAhSw!&Up z=DIImU$n+B&EQx(%>d3Ad}VEIb#-lR2$=){qL1{=%~7P0##oQ{=mH?LoBdb=ccm>p znky<|x6KvGo7dbjGjuiNmfCJU*6LS>lWE{-U2`Gm2eiWqaA0gnSpVMU2!4GM4+g^kjtwOjB7tnvC9rqs z(j(1<8217Y-$ay_uWnBW5%CiEFp<)2qAHlH8#aKSwZ^F#r=-@Mo9p(ktVfbo+!r*$ znsr5|>LQx}Kn3!ET z9SVm-r&net3TXqmf&2gJ*!>4*oJ7KzIe7n10eZrPT<4Mct{{lLbelGT4*^os*s;lMwcDNXg|}}q8$5UJ1rrWUNW7d4 zu5fQkmDWv}L|c|yT-a0IsB%q-dZ)OD=e_QW z*PQ-UM;KxM1}+eCW@}oHQuXxKxIZb>KX*Y`M0Jr^`2PYnx1pswphc|T z>sY@YZp)^+>b!s+iA7{+BdL$XeLBXuT!e5ku4T)lLb`>$i)Xilj2@zYpueY zw2BA6tz;94tS)J@g~Dv%sCsnes7g1iOBs!jGLCj)9gL24qh|fA!V(!>&!E5neIZ$$ zovl{q=7biy!B)WTRP1^eCP$cI2M39Vo?}k|SjD}%l%b|bxED%}9SU^)$V#k4Wo865 z)x+TX8~Eeku|u-Az#|b&OU79w5Uo|rxd346v@iY?qS+T*Pr;A*0jw6{tdtLy0ziS< zG9ct4+rLEV{&Ae}O@kF=>cD-qu%-wVjeN#(1!6H3`It-Kldx>tAd|rVBs&viqlHWD zg|W&8^1T9PfExA~Snvs4W^?^vUUY&&m7(F&swIW z1Z+zRC2};U*A`;Ydp|EFOw+7`~I>WRO zq^OdF`~|p@f7v?QqXr;q(CaHZi(3qLgK#SM;VK^FX=xW4=N8`PB%ZSs=QXcz- z8|RtN`j&~_5*$_~UP%jM%eAvj)__kA^d~{f2 z&Jl(+oL)%uU}rOllcvY>`}UU^edyISKtA! zV_Y_)*ou_Hfv6k0IBwKLNn0Rck#rB}BSc4kgZQmbJs~cV?zCBLmuOglpA|__@dLS0 zhC8Ti#(5-c6^;j-9`>veFp}>;L)Xwkr@Y;1A!F#y8*#0Jx5)%PW_fZ7d|T}9DMURN?>6+A%381YHr4%6_#y^Hz@Nyat0(uok%p6u zsFba3vfO!aPD&qzbtsn)hL(w+ijR-zy*4&h4*+|8`_b}MH$mn_2-Ay@cE`}^I5W4R z(?`j`MmE+Rrk_;=-duP4QcRJ2K%z5mAdnh^qU%gb4M6J5D=Yl1Hw^FtJFS$T&~U9G z{ygLJ0hTV%>QYb=FUuZ!*(1}-Oq@0tA3A6LBY6EMU`$JJpVkuAR+U?#Xx1oeVh#e= zG$3&N>>>F|!ertMkP(c@#an=?*O`3@`gsj$~t`RE%X;quJSr?bjzrDUcP zsm=M3IPEEgTKw4{>mi`}B3OlVFkkI~;XlJSn!S3w&)B zS`8rxxN(R~Lqi+hFbyhf6*zRs6w~4XIj_(Y#m|7q}FvYk9G%o-DQ0? zsGsa1Bz8#YItcCcx=pJf7F4TtqTP&HA*isYMr24C2GIjremmjA$1{O17BMA!le|L6K?t;qu2C(tv|Aa+o1)SCQ^*6XXGvoV;U@xFPq9jlPccMG}ut&@mGp zE&z!I1V*egAT|xIcM9Na55UXSRgUOfU8mUq>c2;+b4kk_t`kJiB7hb*41xR08${xW zjZk%QkzT+cbyJjWz`|X~gFOJiPybDGhBh2x=K%S_>fohn8a^~(?)|IB%s2FUwZn(s z{=YEEmHO!(m8EF}f;239{tB%vA3F3aU=u&Un?sn}OW)nH{mG7cJ3$o|ngakq0OGsD zmVZW_Su&GLGiqzcjsC@b6TaPT@8mvyERx1`ja@?p`mAf&^^oiJpyCGW2*I%kx@}NV zdW7qYohC0M*2zcaSz;8U2hWgQg=a>7QmW?vjdKl(L>~5*;L8qu>VFT1Od9DFJ%ht$ znanZ7dJ#Q4aU^l>gj;@XAhi1OLZNiJWIEm&;oC^mT8Dji1^brLUkJD?SRzV}app!0 z&V!K}F~ot&laP2htu5o4AK9NsixE*eHRl?yoPc(}FKkRd7}}rsI58K$;|>!TYR(NU zO@czyNEmgSXJ}r-`XM2MITpAmZOe)oZJUD}Q z1kh5)!;3 z`CKG%I5c=E7HcBUP<`_oR+mlXytHNZ@At}{A|Mz=kL*1T9GV`HcX@q2?=DF>|8dla zRnN(*MRmSyL!jFO@qqRxcl?#q zVzdzsH==9_fij6`QhQ}SyyKYVB>vfjR25$h7LYsV;lSn)>R5?4jG!-c{;wNW?9ID& z`E3}FE0uiafQDEbe=_)=oSTPKT%n!|=BxOmVf%OOa%bj?a^PX|kI}li22q|;d)yG5 z4P}B`S{EyFzM1!M=^dq}c`=CJcNh2Gl_hICTbUK2dsmp}6$OQn0Cuo0cluWexFAyX ziZ%?09}dpQMV!`o{f5K3;sN{?p$||JnC|{FhWL1#&2Xn#u|IQfu;u<5+sm7(`@=om z|8v6wA&eR`!=^YaRD@ejV)bdT%&x2;~qES)4U-Dz$+FHqQ_ugL98R6LN}-5Fx?u z$*;(btyiwp`MJl@7)whBv|aaPGxxNCyP|`Ztqd%zh*yhQ*GE+)&@SimgLY#$&-1h3GYFs}$Q08$DeK@|q`gc1z2N}&>IjpoV}zH91hmfT zE53dEeDwqQ{DJpyQw7<1aS(3|p$!z0d0 zxkf&OD(v}&4*CI$z|%7S|G}>n zA}~^!Rt`7z2*bh0d z&IQ_hv?H4A=cesnJnvLLZ8y%vnw9wE*{_++Pui;-2=ujv{pqT6{uk}(V!YCfO`h%d zo8~9&FA_+IENFsPpj6RE2W_Tq(PnX{wwBj+Xy<8;`{w)zZT$T0`!(E}*rq%5>$QVW zOGH~Xc4+lyHUlyVkvP^zDkqSoaixG88c>1~3OFI+A%|lPsR({swmx}w5(9cI7q;nl z`niVvYngYS!%+X|GwENl&zenE!ACHzi}Zn9#BMw{ZTI`>cmF7c{M@tY@7QOXK$Q&I zr_e$Q`I;g~E{YHeMOq#{h{GmL@$@8_34a$?KuEQQKM4{U@C5}}e>vQ55Rdd76s=Uh z5>O&PuUW{=D5H2~z4jmW&pooD$mPj^E-crvfdTsgMN0gof|K%#0mUQ5BEev8%Iz*c z@<>?Lz$V2x|KAWBxyBu-G)l-@hEd`nd~gQ>DOinj#}>sI0u}_+90XbzZ&1}BSMNOL z(KL@SHMv?>GqsFbXLY^llO$g-Xy$TeQ`h^y6O`rPkq^FY{k>jY_r4cxqG9m*OW8>+%E{sh%dpg0}!jMu=D4DN30{0_qp>-k=swA3a-@ur)9D-px}Kd z6kJBidFjk^!~O_)nB;d{eO%XLRQt0k?D1F(O;aTQ+TCupyY785{eF^S6z?bQ1`uRZ=B74)!5MF(j5a)@HkxQ=Yb#IxYm!3P_Y_yzC$7wZ; z2kMY9%?$g{9<~0fkDQJr>aQ5CV=CuGW$H7O3}jQHL1x7=pgBXChO~T7(_H3a0;1$r z$S1sMIIzCd8_6+a-eS_>QD^LX>*uJyLpuVMFEij=+U@FK=K#{o*98R-01XZoQ?&(N zPe#6$hZZU2*?^3}MN^okuz@K3o(F3QTZmnZ7t`wQle;465{j1vUZqxE6+w6iYsIYT zef7@=Q886h_f1>-twJcOtf}c@9JcTY`j*2j-2U9F0_C*Ec3YYpKDp4V8L14u)|FOCI)=t3gjFN?bl@p{YsG26GN(npr6cG7e=F~8^Bk%&CO8^29(V- zvs6x-hr4n6-e`)4LzKnwIGpLY4rr&aS)zGtC*F8h42VGlSXU@*{YN{D%CiF*lq69$F-F~X z!^8Q{1`{+j_{p*(P1}tXcEwJjj$F0mwpxSynt?tt z3p!s9-oeYdQb3^4y7Tj#adA6JoAOkWJl!7LLsy487p6JM15gT&x=#T0hTYF^V6WoN zeB@%h;T~VRucRdHvPx;X;Bn9NPk(rK80d<9Cn$Nz3Gc%&B!xeudv$01L~6hH2ibrV zyKGMZ;j5Ura?rC|q7NLcAEmnw)PI7$bvdB1-U+K3Lz-5rYN;8!p{g0S_Vt7r^Ykgi zvmUnqWq4O-$;}?KBe8}Zi^yj@EGH-V2TSX+>haQgizY#0=HxH5pL}J& zh!$HOL?MOUVY^mR3YLF)#)~*95nlNpa2|aE+?i6NR9tr<$nxId8Cc` z!~tb4n0mz|s2t5CPiM|G1aLW&;v|qy0h$Ho8oNp_wlJ&w#Qbqzvsp!HK{cSpja=DE zL|@bYJKfaM3HxD>5{kzg(iy7?{I5|-GT_XO+^%_db~a;9s`09$J&Y9QIK|(aQjJ*6 z+EtBZB2ir{J;*eu5}NfP-L&+E#U#{StLycJl?Ab!!1i~A9Ou9z(gta3%tSNl5zCQPAixE zf;Rn%T&*!VQ7{c}l~q$2Gn^%(QMYtFGj$ILxNDEoa;BEP0C?zxy=Sg|XlYuDRVUt1 zs#*iN?0N9IC?Qa>tZ1JB2_|BCX`V>%fQrQ3rtByYHWeC2rE zFbfl`J5laVpgsIebjuSp-WBN2d5lGGBGHUJW8>|zVsLpH-!{`L~EW2dkJxxiTd#q&4dg;;88*QnGE~I{y(Fr zb3PW01eLj5zF>E#P)s~jddzG2gC2LsJCTj~HJ`_bAC4OyNrMa1)Sk)oA7uLqNVSS= z=!uYNWfJA^=^(EXvt_M>!Sm1)VQX20D%WP7=FmAs@(N>LO2witxzc6jp^t!^=Yk4P z&dB^FD+uRV!=i;-ghE?4U7o!9y}U@k<^8 zq{FcRcLo*5{>Vd0In7*&NNV3puAt&Q`&;aChc~PQ-~8r!jn?XiKNW!kFKF!!1-<@{ ze~I}zkclk~7U#;pee*pJZJ9Gl4@Zfnwxm zCJkH1Awwx9c4!}`A|kl&d@vpexA*+Uq~BOL_Qpn&U%vMZTY8wx(G^Dx1;#KM;65L}BLHUn@W?j=5Szn})3#{5xJ zRfC4Qq|FzziB|vb!r+hQPXd(bzI57|`C=-Gf-vrAvgnj#kJpcYN6m;Qf{{7dAE43w zR7v&D-ZgI)cIOqpvp<P37ieMwG0_rW`72xayeI!mnOcMHb#cb0lfb=y|8)z)3MTqbv zuEvjY%8J}Vye~={$ca%Y_hUIv$Pa*atX=R}j^?xuWSke|Qb|r!r0jy`_3xGAI3Kc$ zDK*z}{9k;Rl{@&hJiy=nP`Ex-roJ96&-jy;s#~6ks*^d;!d2cEiI!5)d`fPh-WjT$ z9hRa|W=d*)TNc)`rDkKAcIA*z($NGP!S!!sP&s-p- zAGw&H*{4~%&%bH+$-rfy(o?TGsY6JYr=L@3V=9$@@n5Z2*zmQ(Dy+Epp7M+pLjo@6 zWY`|T(>B+q1(}*)bNAfX3vwC}r8905hWOD+h3yGS|4<0QOz|lLkhqFuc2&X&4;JUB zGu~J1rDBdKtQ9HE1WzE$pAdIP zUN5LvWSE8vhj0e?#qJW^@p*4Ds2y+3-{V{QJ+!$yysWKj@i6nr-iRH(>;YC5ga5pL z+N#-gBb|)x{|t3)kM~8#X}Yzr90?>BbC<)|A7k_cVSj?|MDzd)45VR(QhNG>_Y^V(%hLBw zpPyr1XGE?uwXZzqKA*CEau88}un|E5xym{?VF2;O-VuBeSpjGaCBYiOALYS2p!tS( zm}}W^>WU(vj%=#9tUEP44!LzT_0!`|iu_YSImGZWU55-F{_@hRR!}{|g&tEo5Q`W!AYKRm=nD$lC^kx_j8tz{iw8|G3_p@l|c^SJ7 zR!#thxD|%nA`n+2aC;?q$$Ox)OvudO7>L5Av=0#QiYOwE!x3ss-BA$9w83vz6UPIg zqv_SjyW+?Fwk9D3gCpM`yQcvMIO6wvIf|(gx9bx{i2ey}e&VYW1w2~bfQ(^ zJuplIw0%ePY+PBt4JDLw@%ChJI{pW2N$-Jm7w*3;v-)xf+A^JgcpKWb%q5H8Zm>vp zA)h48VFG++f|s&x!yiF;WRNJ&Hw-v{yR|w{d<2xMxKJ%)P^(SIVO%hS2(H7#orVp@ z?ObJ)G!QK1El-pK3WO&;W1FD80>pf>}qIE%fE9TOj;_$H#rTe_9>g(~@As_kLl z#>qZCM&A|h6Xjq~5Pv-y?H&D^=+joZ*;Xp|j&)$q>dB*{#3+o9HTi=u>g^)zs-ElJ z)$VGK)z|tPV%=_Ve~}NpL&2K`c+}$n@WqSQPgPEx!biK`%b&@^oKIf|Hs&(N zk-#HDUKr>%avP>$!l^WilvRTW#;iixge1~=Hs@S)o_Pj0xo0~J5HG6t&|#~~FPv^a zm200q-OfGLKK+7TU!@~`8O`v$NwNj4BS^I4CznU)O_0rSU;&RNEF~nu5h9v=2#BfS z-ryciCU3@p9o}tLOGZjhMzxTm23b0{`}~kyP2WGG#Z`PJ!Gf_6@`t;bW5-o0lfPD+dLS=W$+WgGeOCVlrlO9f2MbwFP_fR=8~k&r&` zkS=h~=56U=<+VGa1ppzA1*WrYIB$^M$Iq1EyxnfR*iEx{i}BiK0&hKNw4C{xrcyFc zALDtT>G0cOJ-v0Ur9&R4B%kyVF|Ois;CI7M=8JIzYz;nrpx^k#!B<||`W*!pa#tK7 zw&dnVF-I6f+C1{42$U@pQEK-^Bp>t1ze>0Mlh!B0k({B1-=!hM9_%6O^QoHe5w91w zUwqGlvZWe1|2?Pc_5Qlx58vkDHl)+L@&jQ7#z2xII6wy$FvzXgHneGoHJL2)YouP# z2^~+Cv-a`U@n3R(5_@D&;?frHS+QS}6O-pU=Oi_m6uGYX2L}Cv>_TC99`b%84<_jrskuGDHIX#O1|>_mg+MWqEb-yzL81spd9e~qTxU!7K{dz7?Qzx-4?FY?N;=A zr`wY>wpfh=JE8_TXFsfnCtYV;uYtynC3ntl2gaA4w? ztlN1MK~Y(@R{J@plw%>qoin4w`M;9_7t-ZQ>Vg{h1DHM>=MP0(ae0piNh+lv(jKL+ zr~427FP7BoVz$bdg%ScdQ+4;uOmUB@R?>mOq%(Kad9*f+GUa?$ z*i%*7L*x}e!cBB)GWfj?%?|sA<@qHE*c#nYmZ@v3<9}g;@#VcoW<$HH| zy$?y@^{^B;0-D&9$98>O3gPKPUhgyxZ($!9wv~VukBJc0BiN3xkWj_UBvc268kTfG zi0~TTK{5{7Qyl+$1m$w6xkv8p|MHV+ZQqA;XE-^*{Mp>=-c1geBLPkV+T3;TM?Tb1 z|Br|E^>fpLvXGSjsfFCGV?+z|RWPToVEwD01iKn(7Rdoa;qkP&bl<@J(uNw(=Nu=? zyusFyPvq5$C?bX$4gIx=yHI`0=wAs3F05P#gs&qB$if4Q3CxmTpFA>&KL{UCP3q+0 z=3{-0{YS_%26>^%6uFK?h5ZAz#p`^`gKPO9asi@)cNXysNFdsRCi~^AnkzXcolMT- z%di+#(3sckhx-4FVsn91jD=zWIT2_w$z#a!ui7W?HIaii*0dX07Mn*Ij+h;MOCTW! zVj&hw1^gcGLcpW@`7j9Go#;wJhCYgM;Z7frLBF&dDDTD+rUag;8>q$0U=*J1X+D|J z%MuH#rgLBd^Q8Oas^m7}dKxz3t=%Z_-u=UNePP{*RoAN#(<@E-aE*vOu}?3BBDKWU z-sO3p`#-*YCxzXHFcu+r$;pDUNA#3u;uCfV1ait1c@UNb6G{tyInoM7c@ePy1f+~$ z%a|ZKTPm14z^8_GiQVU))>2+Xs;9I>Hd{@*;SNq$v)P}CAfH1b@r=sv?*0Dv@Am|J z*(~z~+|DOP#U!3Ozx%)Hnk+^2%tSU74+LYW>_jF)-yHtc)F*v#t_7LTcLr;U`X%;M z2rD@bi`d~!FEN%d*+Eez5e^zkkOwm!8IncZTZjzBr@f0$(#i@gORFWcLtYPKfLH&0H zd-aREr|U%VG_uLS9C+$&Fw(u_Qdq^~0ry-HDr!pG2inMYF`S1O$I}Q)bQZpM%5M!I zZa)=`(@Mv3Hhgr)$x)XM(-ER-@)04+JirKsnG$ zKOQ)C`duGJf~R!!qIcpXV>9&%+7)usd%(xy#J?$BFO+kb`vwg|l~dhCGzLVW4kP0V zu72XeiF9-ct+`)dlxUq_6OEj>7)^g@DRAsO+@>VAk$icLeUIy?gsTJ_HrrJW3*!n= z7MdjvJD&Ruh(c~&gib^U}Fvv;=?mG`>S0rl>&rFvuFwMP)Zm4C!j>#4-^EN7^eVY5?$9 z0M5&lk??K!I)^`w5sUW?S}2rJdO&O<>Cu8t7x1b_)ceDna&n9tC$^rWzZW!RPyhSuNy+|?1l_N{%jbr z(HSsa9@fVX0Fo#GoUIO4c6%Uw%#ri~`>&8b@S%|&zp38C|H8g(Y4LhqH>d2=@f1|} zs(LyY4aJTAf5$oQWtMh&&MD_YK}aLXXledKvVWk<=ZD(8yPWjMYJrVij}>~$b>)w zbf?bsEgvmD*b=*-KL?B&_fP^oJ0mQdB;)~B%N+pw`N4rD*BauC@{kANuxySFlMzQ^ z`>YRJD}&5wNS{Vd0P;Urn#i9r12*9c{R6A}=*(Sv#`RGqGd zT7$c~h-bSX;_t*-BaG`Bc2F1=K8%04x&SvZmKkRlFsoo1+5q?oD^Zbk9(_~~1&~U0 z=ELcaKKJ%?|I1-K3$1_k_4+cnWS}zhVEUu~@@;8_o{%wxc(h1S>j5I25aEO^biuyW zBn3f7`g|G{0!?TbEArOtXT#j6z13Hgo2A8d-Xd>^Q4|0StXHqDANsMwf3QrA_CLj& zUhYyJRKcUjzMCU&P#M8^q`6eNZv>m#q%dmk`{pbQ2RBw4h`~w6T#-obu5>*ChrE-S zkHzLQ@JnaYS+Ji~9_!NSVAaYoUX=e(8!;b(ziMie!d*P|rapVUP zj))oI2Zrzm10rry}g3;}cc~$?$)SGX-h8xe2-_i%yMd zsMZ`ipPjJwxLNXTe6~6Rn#Fwa^xZhqc33U9pczy6GH9K+a_4mJ;f9^fIsT!?b#vC+ zFNfAEo2y{@&Z&Nq$ApOZE(|g0R@@gzDJ4<^wB-N!^W4jaxGq8TJ zB*H0Txh$loEMzT6-<3P_>hxFL?v6DP*Tdg@Uo9LOZP|oYv2&_ccZ`YPtUt^CReH*q ztX2zC*t#bkNKd=nd#s6U-cH8;^zUn)!7eV9@)LF;l}$M{6X+JATi67yvoE0sA=sQr z!rbNRfP0aDut?H0T$F8ad1OBn&;CE!-UZB&>nayj=~a45rBYSt{eE<-x?8PQt2Hy- zGb7vcusvfBV_WTK%-D%-JPqVw#w4*5WXB{N98O5M-64=0e9yT+Xpw|hfD;HbiYA%(XrgHR|`t3S+%m&WsRiF#&*236`=7e);txF* z9{x*8c--T&Q$#iQ2VR3No4kP`wYi}XLx>ZUV;c0;@G_yD5J4}%J2-F{LUMIt9s0SB z>@%b(bL2aPtTOB?(tCqYiG_lnNc@mzjVZkUg=@>6AkEny6%LmiP^h23!vn2aLVWlI zWvxs5CXi>IwJH4t!300H*9a5V*>z#j2iJiE;co^ESN{?^?i<95bsb$7mQPz^qpkzh zW0puOHfQ|opkNOHlZO_j1eJ#|b674=Nx`#`<RSF@u!6;26kD`1~31a^i9AyP00| zF|95sQ;_JsNwXzCUQ>quc{%URi7u~HIa7V%uy%~8I1j}W=i^hPrMVRomWVvQrLRO? zIj0mR83+6aat_H+eyjnTRj&$TE!J<#ft1BsOK!ETN>#TKn(_@hKPuO>%UxwcrTWYI zDXlTwc}%;6m?m~sBA@j&tg?hHPr4A9>1d&D=%5G*EGwiBp@4d%EN5L!P-u^Iw%LS| zANr;~k}?1>~!M!ZvcdaIJwL?hNb+P zU}?3l2ZKJiR{xwR>CDJ!@&@o=p~&mOV5P@vK{G*&n0n$NoF3ztotjCHD1EetB=;dk zttS7d`vV3&<|-jZj}PX`M2q$2h!!ttkL5mKP-9*_#i{YmkC(S}y<|`#?StH=8Gs~d z8<+2d2}mS+AGGWi#mizUpHEp;DOdVO4pFes4Yt$B=g&!#?L0CIKjVpZ(C!306hEO% z=z*I3{DsL@E?lP#nRF8qLn^*~vW?-_j=lX+9L28<3p{amwG-~W%Q~L^H!z z)6J)!zg{~;GrQnoN-xNPJ2B71m{GG}0-8pCRXRNZ&y{9s>XH6#c=pmT zYs)&YMt&)soNVe*snMN;Y4<$QxF#E!Y=HnVWirx#63<0meF72?1F< zFu;yrW7SAdc?7Rx^=7||Wu_P=ReUJ)4L>XBE}wgA|L~#ReHE_RSCjPxqTjc(lURz8 z13J6Xe;BKBa$GPoTw`1~dD6t~+tW|?4;s{$^8E|D$8_y}V6iy3pYYoc>S&n4;>J|n z$e0jUeQ;m>RQJHXzAAwO?CFa%CI{06@OJ?AP9D_H#mnFkH#A33G9K6qxW@s+aPh4M zBe{{js4Fa-ed*!kQ(!R%boRF^*(Nd18|jN^@4#_AyLv!R7qN%z?&sR;X~drP9~I+N z2Xr=KT9f0-Uxy}$haH4O;${c*cCpVG+hkwYraz$Yz>W@@tDP6P-s|^;Z$d{-$=Z`- zGdLh!J4(qHm%Wx9X??iYE^+^ljdQnyoX_8hX3QQUQ}oEGZovV5#uKNV@W zJ+awjf~EKzr*Vg4(y-s_lis(UDa}_e#wd3I*OigKj|PrR)(oamL>_fGZDFvG_bKj{ zS7m4^m5~X9(gB%okZBj@cUY?+6PdvSUxhQf-6J8L?{cG@9$tomTA%=agkA**W>mYR zYoC4^fs4J<;qYl_S97zuoZS`lgfFVavjl0sx5IbJf^K??bYSr{Qj zTwt%!l;uBw-tQF{gWhrY5mLUAtZeqft5)ppsRkn+Me&g)+3hg9Wd1_rSr3jp+4pZ^ zh2-y=ec;mE53(=`7#MJ;{*u08#z=5L4&(0P++Fo&^Fo&*BHnR0U!y`@2wyhfqO%O; z4anH;u{{jhY9m6-D8@xL38*_Uk)(&LVNzwJ217PcR&bFiUKNN*@KS*VT$#)$y3~e2 z97gdaeA%2?VXMaj{XgV$#1fU1JE$DWSDx73{*dOftL|hF{t@=N=!8kmuGlq=o}EdL z*Xgp??GEF%{Yhw(ktFVmPax4DW&YFR?t+r4xU@L( zbQCylK^n$6dVq5-#qcuw8P4*g{u)1|LZz(wvLDqiKQ$38`|4E9>AS*C zD1}#M?dg{ZLZ4!Pm}!e7%7qFm*eQ*u5Ui>KT`(=mv zJk5#^9E=Z3QaTNqu@=nyaM%)6mJ8xKsDYAi7ha%1CKC#?{utHh$kMz&y58*dl+%k6 zWt@{16E%0!{+YCr@g6$lP(n&N zFUw9R%)u(H&!8oS1 zNht}RBkX}-df?|Z@;bwDr1q_wp|nOr&AGK$C=<;X7fGejXuocXdvCtc$mTQzqGe9W z;g@r$D5_;n%He#291=$OIS-GrCqRwwBTFX;1uLIYA%6R)PP--w|MlBReS`gRtbALj zuyif_gFbO;=cWH-$a{OT^Fnb6eLi-elD0-HpYMW+dp0*W+ue4LQoizpxbz_^n?vDE zjt7uIjCLJ1AKHceloS(iPlH-P*%SYTtUZIxUa#H#tfdcZF+E-1K+5?p!WzcCAcLYn z@&v6dQ|A={UxzQ2T(+; zwxAo}(C5cz|0584jFUefM6b6w?va-%HENa88sPGp7g-MSh`oVFKa0&&q(WP(X<(7< zMY!%u5ZNdgOog}zS%+dX;bTgc3E0({R|Yw5@W9a{lF(iG#!8@^Sij=z20{yEsSvnT z@OuJ2f6(JsBbVzRE-j$u9Z7IUVwvIPndNV+gcH&5J5eQG40Zzrsk{&hAPOTG4j^rZ z9E>D{ZGEAvAR@&g%Zk{sfhFvJh-rcI4g%{S$dQAmhU^(+Cg&lo%{J0Ob$$K|{z|1% zkh6|*0^)%Z$$UEXV>9`Mg#2A8A?%9zS1!1fwj$?!@qFEj(Ch3wQ$H5(9o17I=lxGX z#cs;ce}Q}-VZ=ToQVCulW8XVy|0}5HR7Fi36$u`Zm1K!H3G=<9WD!V<@tZ$^0Nw?N zC9=!&aZ0>!S@kW+k~bRk_!7Q|Z^`wq@Ug4p@6OK#f2LUem`9ZGWkh!eKYPjUqKzg4Ol{! z;3s^W4IW1_RtaPVq7I^4_(hV7H2)`)Lj&R+kyQhw?nl`~fC*Ww!l_mjI}oxKJIFUk zzZg!RsM+B8Og{#SVnGeqZdy$vdk92G*mbEo48ok7IE{5;Vk`B4OPDEY$x5n~IF6vEccwW=_o_uN{CG*ox|OTxT5$2 z%FczmkYDf(V26(9OD^mZA|BfmI2H`riwZ(kqbX0=Upw3Mm5Scb6wY&wY8fB+BsuAc z_-be81AcrGSFZ2!~QqN01N=PNk$> zPVk~o`gq1Zf41fidy=x`iz>xR)u9B%ny*mu2jP&|9RRovn?3X0*pY2_%1l1`VH10%m$I#-@l>0S`BYf?uP8$$%aC<-2fYz9}pWP~8^Uf6)qMyJJTR93ys6 z>cWEq#jQZYXtON9AcRRY9*9sJ4+vSRATP6G%S*KBva*=01~b*ZWTjZ3iTU#(;H5v| zGJoCiWm7&U0!>0rUn=XPcP>Ovgk5;I&Q(Mg>lF2jCkRzUrJ3^VT%Rl+n z6bbp!F#$*3DHL1BF^;mWD=<7VUs|r`=g&MTJC1W5(ty=EC<0He^^{W*k&D$@%PnkE zZDxSr?3A@yFjUpb9j88gRn4v0bHAF?bN032Kxv%zyyQ9EP=5JDIQxmLpkG{AT3WcM zmz%N#vAzsPzxte#SyJ;EW$v^3(b?If`dTGL=O{9%T!HHnrBe05AVEpOaIAL0Vp1!} zlm<-9!L0~qDR>@+5&d%9&R*>u{#MwcN~}1HzvvG3@4rv;`c%}PoSuorX7IQLZ|Fwb zcvb4E@Mxghrh9m7vM8_h0BP zWGjsiPrK`4+GAPf*p^X1Ub$*>PiNEOZMlVRL-=2G*ZduN>%Q3h#boM<<)ufL-R#pc zKCHy*YC`JLlPV=HGS}PgMb`K;S!x~Q6Gr2Ma49G}-!{hJ#wm}iStR$j*%Jhrxl`+i`1`13ztX|sg24vji(!lQpw_XI++^&b`l z%eqe)_l^JcJ$JSgRqb{M16^NT-P-E+Rr;pd?{96bLYf~8x?L*U$wVaM$ikfAJ7&=- znMz_nvyTMQ(5xU#it|tyHbFz6B+wJDj8R8fj1aWGq7%tEdbB5S$7#i=K!w5>Zp77I zwS|06dyrMfK<9Au1d1$2CaQ9lrF94M4UWj8lt@V8<}!^h+HF3-egF9Q{m@L zQjowV$WJRvoi^+wC7jT-BKQ$S4JvfEMlY5g+(J*0olCp;4u{)9G@zS?HV1K6j69N;C3BD z6)u+AQ;o6u%8!I|{^1M4%&{3kC8~ML*)5AQ;o>`sgT+OkGR}^Rj`Y>nVFn# zGZA0LVFiS{H9M3 zG+E)LaR=R?94Qn~4qE!T&{XbGuN08n9}?A&lz3KU1>A}1pe?{4w=5N{zyztfjRaR& z{t&urJBVi5+QMcn=v!O$;f|p2hxvORS;Q-1F`sj-C9&LP9pDH?NI27A^W5s8M$8VX zujxozwtwHKNFz~I9V)n4z})tPwRObOBOMAJJ?gZ+g+CkoAqeiv7P!rtc09XUgK}@M z*3b%OO1GoNCqlODNbHC9Dfie>loBBLC}y74GQ=9C3syZp|F`q=cz$SpUZ?*L&$EkH z@ghX#0R{BkJ$;p}-ab|^uIhDM3}`iD8{Y@6F(e!sRx6D9(*@KDLiJDj!?R#p&^#D9TdAHmxDMrnS3os% z1RvpMSHHZvS~qH>qfq)PV?VSF+JwO#Tr#L#gdIRi)J`+fHXb1E;T0NrT~KIBwzfFr z;Awq^8j{wS_^^w<_&jlpplzeHDs5s)3vH8Em^tg<&)Bp_Gk@mHnM-%lpMK^Hfz0u; zfo;yL#%2==QUT_AM!O}@AnMs*wg3qx2~$L@nWE-c_Byh5?SYMtnP8cOXSl_I+1%u0 zcx7vA1js&Xh|_VQ?ZO->h+60}(Tw*z!V`zdWdB=2*BA%K4FtamehFOY=7JMY)JU*x z)6Pbq^L}aVQT#Nc3&HT;ppBA>EeOB`sxhz!Nr;Rb=y~|pjNpjo)`H&QWr~6mP#qCj zO~9@AgZi-36I*9)T5}XW4vVJ7=s?_BUq`GVo)C1_>(v35B`XnWp4o3G`vgt-pq=BBY1u8%lDmo{D8RLbFRt61FRVj-1n}#P-8{?hmjdnl|$1zH> zfWrWI2u?jDanb&x(L%-$g@MsKQf)GDkg@q|z_PHq)?b6qO@DY9B_}a{2FIE|<~~Uq z#wl1?kP{z7iZ!pGP8cg>4l&TcJN9YheuD!JGLoV*bOrHE(Kq`f3*&jvuMe=~20Dpw z#&6)Si{B84<6i+t0i=U74E=5u%K-(I*bj*bjDL%OBI<9?k6EwdpHsi12CRJ(cjA5T zX@b@i!LH~RITVoRb%JBu5WzC0If`R~_X(n@D5k0nEMWA&0CO7yF2;ptg)QAFCi6)# zxk=;epI~pCx^juDX9r0AD1`?Y^?>TK*88hLWOa+OZDibE4hKb6!{UG*X_{YqpI|tX zonq$AUiaV|qXWL!6cag_v%FfT;Sk!{JTvAxIoIT$W6t$t3+9ZQZJ2XzHZnQyeBO+C z-_wvW`{Sm}`5!fArGdf-CQbu;nzK-X*`$>g#*I$WLxDtd3q1g5j3j7Yu1ytvj>px5 z=z?tz*Q54dLo;sXq)Y{X+K!P$09Bea|*)-448B-xmmHU>S_Z8ax9V4r8$sG%=nFf}cM)UGUcM%=U|Mdt>@A8?@30 zU-K3k*$o~VG-$=z*De%ah~jUk)+V2`ZF(ZIwWKi+fq?~#pn+~>Mw-H!U~ z*Slt)80=)HP}>^4j>l;1BOJ+m8BY!qo$eax{@v<|+3#RH!NzF8(f1oKr#Ewc4<7Tb zac_al#uPRhIh%D828?~r=rQHy_)Qsm6%zJ5WyrPcr28RZMD-)=BM}o2XxR~o6%Z>f_R{KD8aW6d-^O({0(1YBH9lvr znpuD*B-(33JV`}w-1?dXdW7B43WJ{G>b9LKW^)ZANkK?RRC5$im!r)zQq0_BNCkqv zRDXF#$cQSFdYG19pE>FK#&8V=^7`s1zXQ{sSlT5Cdr!OYvzTaa2aXftwgwO-NDl)y zh=0B&d{(E1iT3`=l25_f@{dhA9hf+HH#8-r?Sb@0x=U>l{=hK0aa>?~HWy#J)ZT$r z_}72rfr#>+Z2^9S*p3(~F4gl+=Rf>-$n$5z4@qC_`Jvase=KXRPXa#7K5%N-zmL}5 zw!4E}?VcgbjB#VOc@W&NG$COp>`S%I9=N|?LB+0K6btqY9nwcJ4<5+q9YD_$=Pju4 zVS_52LPStXf)wl&o&$RxqIlqf+FCdUTPjP3xPa^;)d5dCwe6V8J(Hb7_SXm^cpO5+ z_lz$hC_*IgR)_XJx0KZa_K*7%_gP0uJ?VCx!IDeK@;?-GJ+B2|O4kCBNZ{)sC7g>% zp+rgk9BSUaEBaP13|>~uZqlt3U?<+SWParHV zdnfYbMiX7$qSt$1i&E0KHzVcj#3F=llV@YgkZZkDi&_-DPA zf!JU3@VO}g>g;h--SLQ&*M_q-cH%IW$whmQZGROU`vBV zJy517^Ki=jKSr^hSScOzq~K!qV{AvvPl$B(IyCS-#1#YVZG>f%GT4-LJyV)H_dd)$ zihq@nF&fHyTn#^l41qlXu_)1mutnE8tcjp&{H}INJ5R=;^NABRyxrk$LNJZg`4xQ+ zUq&xIC?ty(P$U+A z{Az7HRFo$;Hz+#n+k?R^&HvgIn3&Lo`3#vSsSQ}q496fkOWum;g8RX#$z_2J8m4l{ zQb--i7CSi#DTu7V>bKkh(_kEz5|KGfzNwiPqD7VwltwxxN(xee$7MNQZC5lo->#|= zx1{1;BIcIUzk<~)!HmUUz5A^mNdUvl#` zWxm%v-XkOc(tjlJyXletiZvbJUiyCX8#~V$giU1UqkMrZ7RQWwe%-hT?ic2K(?}U4 z5IY@)tVOZTrxuu_;ueeDHtFJF+u9q98HB4rG~Kn-~kYoxQ z?(4=$=t#VHSK_9zF#LQM?I3yu(jv>LFfgj=y_QVdETJP+b)^k;BBi71&dB>E-OeK^ zcXY$n*M%v|j>rVh zUmEa`uJgv>vGURD!evdZcU=hYvmUQO%Q%?nqkvqPuTDw14KnmuA? z*UYP~2)~1(*)xjMnR3p(IP>D%M?;bQX87|CRaYE7N7_+&VdjOWKI++Tf&mlZ@4qwr zDR4}-xtPl?uMcnkevNqI(2-*@33yc15AKaD(Fy#$!DYMeh@aK#1aKaGaS{}%2jAXfZG zrg9@Ce7q2ZTNZv%5L75c_!u}%dTlGfs#arO-AE`ouNbRBgMRgTsAYo^*4v@Rv3UGw zBm8oui4|fOJ&Evs7zRvoZe_}K=#Xn_<>zs%TP{IUAKVYmtGUs--T;>G1)fK^#90r% zI2^r5k9`cP6*DQl61!$@dv>z6N_oix^VIK~*FO3nTl~sFN$Qc|WZ%5@fnX^EUpTJ! zGWh|G>&zQDE^vt(9ZzELy2gT25vL&@jP=IOkCnUJ=y*PE$t(N1M)vX~12Xx~2ID_> z@8v%Sv7a$fA^ffd7~_Edd`>u! zAmc@6rcj?4P$pjZPG1p~rR4xvsN$E?C?f%Nr%^*;--!Rq}md;q>j5n@i0|V_t8I)6cte8|7wfa{S7a5Fb%}^h$WH;+H@tv zOY?L8<@}2|;WoEB9E~UP*-Bx#=yH2!z45?3M~hTENO1mSfYqaae>Qoy-*^8?_Q~86 z_lu6Z66d42v!&&^Pa>}u6pNBlJkkrq@l&@ecdSs!<`eN~_~jrpMy15d*^k`i5bu8? z`$YDBpC3HJ#?(JFE{d(91Q`oR1#uL#cbZY3IWh$Kuucf$r888}{mJ z8D+%pat0!er90=cOH=iHu2x%U@ZkoL*kLqYXGnVIwTJwEAzy6Hb<(qE+Eegbj3^C0 z^q^xr@_^I%QwI$mv;^9r*b<5>qf~dWKgiJCaZ}N8sxN|QH`EtFZupCkrn~yZ;p)YU z7X{KUK{MCw!m+GQxnGDbM{S8_TV?~KJ!&beJ!(r>qh@$}Mq|{D-c@*8WYD?-r}GV# zey&NPn@}R2OisQy<}ta9)P*EkkXt0OT#-2k=Rhi02$KlZ@1%Oedsf>Emk2?tmRc(O z+;LFtl1pP9>X8XDjV`ur72i>0Oi%sjZ17g$-f}jT%9iJI@dba?Hyw;00j=oHpO6pxrVr2W{_t2l zIPI$(Lmu_ik80jq5&T0cU^9hA68vTs;{72MB?d!crS3FPKPAaPdPFMBWgN({v|*{L zF+Hb&!~f1; z?7^z*-)EW`cg0@Rs?l&V(P|~$Rq^P)4<(Ygd@2}wpyHyUQujE{r&PPck&7R0WEn1gE$NL;Y!{`20JpPde&RI86s!a}T~8 zZL;PdoTh`AfD!JFLc(Hp`F0a8IF>N>vI~1aiqv0fD^hZMHA3k@z-93FNoNY^qXQzL z7{ME=lvvN_*OQU{<$5xrl81jCz~Vo#BU*pkIFfGQDvT9arsESPvNJ{|f)*IoBp4xT zbm}A9gz!7+ z))Z`h2)-a{8e@bogX1Y;$Y?T6*2`GtBuJ>?iZCON8H6lI*x!?g?`24ugzpQ4j^XAA zJHQyQr4PvFZz78DL?v0f%-r0hXlSHmr5Hz8#wqd75;w~MRa`Pgh*7O5R@)_Bp$j%X zC@V+U`>HP@`7ik*5np+(l7``X_^U!+O=ywrL^PV%5Uy-NrQWVo`jY=n`YN7K;4_DV zFj>X(TesQ+!I+d-MaHZA7B@Va>IH%^%l7E~A%u3}4Fz#c@}KdABY29m2}Hl2Kx}XC z3!+6f^Ptd55{7$7uoXfXEyr<28DbZ7uLhkK@l2Mp+(DiP$gqRTyGTnz$_CCkNvLA- z1|{wl{Dio6l{PS}+802P5NuA2lbLg^39NDgow!sx1kAQ*~NAKAQ_a)m9kA45I5EB=UM7IsN*K(OHj)nC5)7uxV&gaid*eT!SM zzhW4(yWW7`*B>y;EVIuJ*18*O3Yp57)eFz0h5|fa2c5(aqlu6WS%T^Y(gUmg-XiG% zCVggF(pZiw7@e4q-0A*>*iT4O;&MV#)GfB-2V5Rs#9scDdotPOw^4+Zg5?9cloEFF z(Qaj_EVyE!XjmXkY)XY3)UH@yGgM(;JFa@B#)EQz_e%usvLb?N#5x&ZS@06E8tqM&XLsI96A2Yn5{J zfv>RkC{Kih5Gr!lHo3$o?^K1nYhf_%@MCtzRca%uS?KdQ4`LqRdNBOgdiU02^-eud z)6!~b_>Uerpj_gW;PO}xSQY(l{gKbD#Wd-;D=(!HP>VmBi?0c!UUyMiLl=|1T;{$x z+Lo9W4b=pnVA}5CXK9aAmfG086%~p&2_gK@UOx^lyUMqlg!Fr!((*~o+1ZEVM!%a5}L8=ah?w%6Ki{Y6LM!_*(|L%5xq-Wtr$4~Cm+jQ7aa+-MvWhQ^fB zyeDL$p4?-r#8Wiuu5y&5aLTbr+pamtOQQ`oa|%Oz-m=NoIV}Heyt#f=qS2cBE6D=b zW-)d;i<sg=526s2Twx|lAgY9Wn_q$G;=`bz4gg3qUm#p%?^ z($Q=@lQ=YWp)*}xDaKN%bn-}*uKb~>Du_;@gKUqYN0L0EA8hddbc%wCipb!B{(tgC zA5h!{SF|RT6<6MM%tfyhn1^#xm&su^xuZ!ijg_!j?@;1Lc)XyXkTP5+cExxITZ@mt zq|bsVQA846IT$cDd5C8nq_0rPrEm8=mOXw@uh$w=4^1^{_4-V``e+r;^|>kBnVK{2 ztP)4q(kY9Bp2q0<<4a^4rTM^mWH4;NwE(;TG1ll0JOz|Vp}wSZGZP9>$w^cA5Z0K1 zy^Hu{I)4oi5V=qq;Pi#V9DRbw%>jL|x=JT9e89S4Pvo(~To|yIqVW*9`mu7@$B+jU zX9E1^FG7EG$?h1i^52)Ri%`AAT`j;HVGJ-fn8_A1w1aHY)9$u)<32uQG|F(o1Gptf zV3;f!TvtQ5GMFR@$Y>i9G|RH5!>wn)5?5SsihZ~96^MMoT35Yl+j2Yed8ZqpUMv?L z-=}%-eGuH290_^5OcaNhG|JouN`Q-pRA6miT64Plq7X*A!!>;y4s&RJ)!O#f_V!i2 zws;O5&fDjhQ>B@R0IhRIzbAjJRpc4vEqIkXl=0{H3uonYS|0uip8pdQLRhtyyZNUV zCPac4jql0y8%wIz0sj_gfc8!^O{_=`gWPjVDmbi=2;jE}00#kYgX0&M!4r$ih+^MF zZV=q<8Fz4-$jS`lC%s7&nlLK52$`8QC!C~PZ61JJYB3iuY;Yp>H+sOyjUI^CMfGa2 zL?S+69|sJi{Gg5Cd1o=}N+`~{E9=rN*WRo%JN!+sHbLLmK=oGSts&nb{E+>z7lcdF zAB`E~90<=bYNC0kY>oJ*UWH_72&x+ zAe)&k*0Zqv04dpeaXOPd)TjES_~Uy!^&w+tuh@{MLS{-a5gHgK)3U^v5>p0HZbeej zz$8fJ5M};?fvZ0#XHK$_-MR} zS~y%bcmQu7OO=<3M#eKX94I~Z=?N*)c}K%v{RT|PnyWnfoZtZ#_+TQFRJQ(!Uz2-y+Gt)!_qc+DRUtC7fCwZ0}G!O3O) z-zL`+k@b&8@C`Mx!C%xq)UTL##;=~k=>g0JrGHDK6$>33;U;9)NYR7M6U+luYDCm? zD6(}MOCS+^u+YgHm3|=(mXbf#>!f9;n(?gy|;5us!}NMC5)Uc^esN#ZwkMUxwyu7p&K3fgY7%sai!nvYMfOKA^L{F5p7J?B9 zv_S=_br5Yzq8ij3Oc74vDG`WUfx|udNtz*eujFYjak#?vLsR7?*Gw~vD6!^@YpEO# z+nHJt27aUlN(h&r*7#Mf17wA_6~7b^#hhMFH^Oy2+<+R^Zl_Ojs_0Be@b$tu9nO;y z(j(B`dR6#!$XF>z*j4NRfYgChMU)hZm!QBE0u>yPxkV%zL7ooU_jZD+>yq1}h2}%5 zGjwOjsp3lWxG%ZXV7>nAeEj|K`IlQy3jJ_kxE)MO;b6HO3`^;tpa;TGb9KA_@PY9j zL^6&aQd0>#v8@7G5~_a4>@Yqt%)#RnYno*q?1bz}lX52^6(RKW$S-c&es|!OSvA(U zdv05e&7Ffw(B^Z&TOJBvhR)99^w45SOA3LIsOYn|`rUJPKkJ^WY6!QSy|r5C$o9Fr z=B7`UmcqF^YRK&i_R4U=&;NNOBv=BktFgmajb;kwR@fxyQZ=tTLQTWe)yRaA6KJ|? z%t==G{BPK!iJ~WwjmBcRd`in^3Ny!{(toMwi$$}ETXOkACaa|?pG!pTMM*9tvQi^i zL7YRUbS$3D-mTw$_&9X=^lT$aq`9 zNkPMEBF!0&@Tjj6Qz2}uZhAcL6}`9S177jH9?$TP;l1z6i*vb1{C-J`zwgKU{U7&) zU8h}&f~W8=C{m`D*CKv!90)Qvm!QnbWfo3AtCmvhP*NkMKzbQh3*`|soWnso%*rAI zGM?%PGy`^}T)MQr2{j$77xhP5EE&-n5;xIdw|gny=XIng%ij=ZR_6RN?sE$Xgk)wh z$4Vs@O4LcQN^QwOIow(m6AlVsU~2c?CNWY<&sM)`TW1FXf@5G_D|CtfEK&4V;W7)*t~96H((@ zVt#1R_~PQgJ4RIx?`RMkA(p4KBn%((o>%s4OuvN{YFwXY$ ziK(d*_t4XyB-r}oYxT#euylaQhB+tz( zKGl6n6rol%2txF7!W#<7k;rj+r>Ygai-l1d6a_wcV&wtT zB~IhCc^kCrJ(P%g%Jw$fyKFD+htC@LJ{Dt%Wtrt$Cfg_}loMO2aU60nl#|sZ=5}zy z8TPT!1?N8C*rp=Cv-ghq(Ik3`rzdlc89!H>J6Lb_U7fZs%? zNo5z@MW|Ic?(uPRpU+>RV7^>#lfOJW)(}|gxgOyk`kcX_6N!+$9>lci?stk0qru!CbmBk4#{_>W9yGN9ZJFfV{xJdV%wcGyL80M76vS2|XE#ER>^#fUA1=gNLhv zjc=pOjvNgL+TsI?_>btMV(|zHwi9Ml{_;D(8wK9*SkEAT_wMvUNiGBe1-Y~k4z{b) z(~u-_F0;~I64Ko~{Bll#Z<`1hp=5-K(S_qc+T&lLeA5aK1?%${9SaWs*Nk`j64i28 z3FA9vrfS$S>D%88L#G@GHzD2-H;e8|IN$KoFYRDtCN1=_va-;Ent>7&f=Z=%EGnAg zLIH7-BW(%F`z4HUnG8M1M2w#WAtq#q~Rd6EADx++4}(TR6Y z@t!DoAnf#8kfC@GKTlXl)S9?U$~c30T!cRi>;i&|z=HtfF)bP1(Ti|C?c5NG{`M9;B9u!`M-B&b4Y@q%xek{ypF8jNZME)SLI(4x6ZNJ0TUX|)*@gRbq#@6I=$2--`eEIb z$xb5|6{^LAd~RQmPDvyypde7%6P!oRa+mIE+_`#Z1Fy@Eeu91fKT)3Yzvrz`gBTmm zPnaRfP3(YOe#(^VJ7Iw=f=o+LZP-b&>@30k1rp_GDxh5vb_N4M$w2?>`D7sGK4cGi zAA7S~6(4`h8{DFWTTVb@gDD$`cfuH0R2AQse4gM3z1|N7pW#dUBM(2k3yc5`z_a{# zQ5)^)*o+W`0a_RXf?BaaVnJ)gYONX|>GB5spA2cvB_Zg2@=c;DzUfJC5W|QChd(m+ z%K3M$02YH;52C>@+MNb49{1URV|G*BdB{A9@387)1%?p#av|F&{JA&=@RrHj23~3% z8Rd;|Hpi(An4J0CO1GSC8d#81HMeVc#YB$lU8!$&0w}^3RCmNreD2{^?j+&jf2L}7 zh8gi)so{3VsUpxGNjeR!0D%(4IkAOZpFGNF)f?#&I$EbvYmI8g;Vt={AvE3sZY%Y? zgRrpV#P?LESW6B6*SY8BI26uP?-le?_GSIhN-@_k5%!a*=bb^1)BeR^)Lu)qH|ID+ zfs%nik$) znbl)ZiDv5hhX z2@56ozrm%jbd4IO@Wv(C* zY*V>1zH($%OQp0~5>uGqQ?FFI+?|RuF2hbpFto^5_xf-+762*EimGhtp+<+7>p-^B z@EL{TDDL7zFM>&U^uonH)F2KmL2*6f1qXJAJ4C$!|FwdBbt&#=idL9#TV-Dvlm&y?h(o$lQ0ggj*olXP^ND zZ?7=l1#)>E7rN)Fnxg_-&zPhHp$~E)^fS!)LWM=&P5Lr-H{iQU=P55@LIS;S<@G%N z_hT^H1Y$d@PWMH3_zZn~nV!z{u6*gliOmxyemE#^%0a`nM?MP$+IXRjXHq5YXRM|Y zoLj zg$q+8SG7=daRi_+sFy^KyD@i%%HRrm&Uk_hWE^LQzn-^y5+RIBPZkxs2?PMX6m&P@ zcg!@L0avX`u7eDE_TyKzJiKQAha;5m2vd`wGoHlt_z_B|CD)kvio&Vnjsb{e#1knf zm}zI0^c|wZ^Hpeu{~m7hpVU-$Y4Na@@INRd>r8$7;qxr!VEDfYKb`vIY;^HZLlq@C z{{Yj6@{)`scSmsMAxk<|5UYwiTA7AQ^e83|fRL^Vm;rA1Nd@jc#AAg|le$i#Btcc+~oj{xFINb^9IecDu(!$IRU#)u%C8g9|on4>$s0(WVS9E^>$cW~kpg@Mbd z%qk8?+By5;?2E(y0l-+w>>lX}FY{5rAs$YYD0c#wahry%AJdNgmQ$To9e(_@)}MLt zk7;J*MIQe_$}OK z!|G*=)qGi9HwL^mK<40jZ&0W2uF~+K!`tjpM;P8s_p$w>2aHW$AKh5S zXH?V(HwWdko-VVeKDV}@jx2wVn_Yg3!3BK>`P+mMQ#6H`5*zV$wh06CWH%paSs?UU z@7G2j49uR&3ml^VF}jgfI5?jtcnLfPeZhdpHXaK;n=*icPZD6F90TxK?$iYQtFk0Q z?2Jn1RO7L<_^Kv^vcvyRL$ZR|@Wj8!TzD>UpZReB?;;bQhi3z2&?5P+QB75{Ifcmw zs)HD7c%RxkqE-_-2*GAA+Fuuo&pd;N+G{j=tBpptT<&(EIQmDr`+eV6e2Lv%rJ{c9 z6QXmp4ZgJ_2+Xq-K47FH!aQ>i1e$d|_sstl$8i4X$Q!<59;^^tk{4U4Y|I3Xi-XeMLRa#;V)j}yK2b(36 z3MPXxaQ?$;61KX%)h-H;b-Nd_rgQ~U&x%-n4f{N5Sm6V1Hb3NT(Zz z=F{nU_ld}!9_Lc?hvrl4sdlcG&O$FaqOZ}o3@lEBG#KORv&n)>k9AlaX+m%Jz|1+C z9NT`a?>DwRUF{m$-d^_^9HSAe%NIrxo{jVnV^1v*A-Fn8arBtT4g59JxI3BdceuT= zarrVtL!70t7O8D6YeZm+LD{--YZP;n*xlWh*{V?+kcgTB_7gqUEDV;zKN0S?=Gmog zcwd*9c_7Qy7iqS!J#o3SrBKyS+U?AdA^9zNsxs3y79Z8ufrB*kB4o5+9b&CPgFylp zKk86~EOsHD-K-0o!9GZ9*etne@@DLCzlJV@iHP*}fs zbXHJxqLZDqqhDZAAf%f>z3O|>>L0(iar&Q1M@snLyGGlTB^G5*_i1}ar=_*EtLfpN zqV1pC+cu>-+kh@Lgk1@{fIy8RuXm^9z_Ay{4sHlIimYuI5MNFV^0}jHYs>@xA`J&6 z2d~<|jEKyPD}`d)e@bbT1ghyA$!GpULs5$F`eHNj1kT z^dt}AK_wj-<*;Y+Zot8U&QuUlEUt@8o+0lC5_!11!c1;`P_POK4Yv>0 zXv5B*g%>M?0v725yLbmFRuJB#3Eli+)jvPEJs0`BnkhtJsMrq%x6K-ZW zlrot118KNDb#iL66j~pHR=bnIwimPoe04kf!AStIKJW*9K_6aRpduw~uN}7|wA&rF zm*9Q{Z9v$8JJ2d2rx*p4kZzj&gZ>6OW2!V@gr8DfUwpJkmK4yU@H0}{llH~LutN~N zj;Px%I^gpV^p*ls{ya+diek`X_qx3SQT9lFkJI6Z`IM;7?RCoeShgfT8a>lPepN(d@NU*)c3R5_Uq7lQGCBj`pVb*J4K@&~X^EE3{KQ9JS$99@W}K4o-gba9Q3euRt=(D0Y)WWF#p{LDV_J-z^mMxBY5 ze>d^Y_-x;s|Jg8u1OwhXEEbYl)#v|yE^=9)yVf`SdY@ZFI`C%&-4G5bOTpM9@L}6q zY~N#h*7gIS_8YU6I83n-R;69;zv7-dqwiefqZ=@|^d`n?4A~G#jd$0&`5J9BSw3st ziI+Pj-Wi|mdy{ytkw?MDcSWAPNTl>jsG&h=;%Xh*4Ult5_|xGd>F2-eQt_pi+{eD> z{CVY6dnKu_eC)g9tw+m#;b+s&d!AZ9cP@GCVzc?kF=sRR@sS8ZpqGvAB! z1#IsyY}8Rmv#?6-*K$cjk>dhwTYEZ?o;q>jDPi@CcV=fE-_y_VGLp{O{(yb9YYghX zJ;9KPy0#M|cnT$ucY(i!4TSK{^>zd|?dtnr#DIHmqXyKgd)ww9Z=i=soC8_=^ZF=MKufl7sBRGOxfu(QeZA2V*lmlLINMOoBjP>^-##tQre7X0eQEttEVyjF;c5 z#u4tGm<@+#6S#=08R+f;-!gu?8xG6`(;{GQtZjVC zqJ1B=wqm&nkl6VCP52uo(@T>u;c$nRtt~$PWcqAAIcn?PC&|`orBemFr)69sm<~iw zFe5i2u}G~2i5d#5QJaZaKk&gEZjr zM3O9YuJFhZ=?TVvdcbuBq*%a%!-7;m5bN*(MT|jdMN%DmQ*-g~B}y1Zw~&94d}xKO zY7%=HcC=)b*o2N#D_%bXhZAKj_-g@g&l_A*go^<$t3i(lf>roYK((5zN)o^XIiHW&#SPOASRSNCOD8GSbPC>6@{1> zc;JP5$G653L(1CaxG)#R_Djl1iEJQ1?*E)449}rR$jnTv;0MaPbjDgE#|QGdSc{VJ z*4*#bu-DBZPRYb7IvaOLNaYAcG!h4o{ab4(U4&1zzvJGkpyik z8oF@t;)PIDmxCA9){tgobYalb4savGii$iRW^Nj8oS<2RZxN|)===tkE|$|zK@g~M zkNtq`7abKdeVn#>qEtIx@DH*Q^JR!uZ4$g-HfqJ-7jK=j?R0@-z2>Qd^?Fc%wKRQ|AW%P{& z$xt`Wo(kvLj-=&WTV&*ue=-vRJ?NyVj$*Laku43t?D)pdO*}^9QuTBd( ziL9^z?*>EyCKYUK&?jmo)rIHND*qAMKm%-jYzw~u-FpgUq{wFL2HRr{j#U6!7Tl&M zG~67pmq2WD;|NKvR!oZy_G3wrM^%NGOB+SY*Kqh$$v?jn5`<7V2Cwx@>CluN2_jH< z&+UnQWjV5(SWaaZ1Cd#aVrIHAf#OgxV_$whs9si zyQh53+|;3b5lQQUvLp3@crCG<=-Tt?%AH|{J(gG~xxD_6AMzCbtF9o;fP8x z*`0}HmSZP_k`r=+G5!I@pTW7=7(bIuYi$DoA}I`*=?h~s2Sr*KI-AVdkHJ*IFoEN= z6%`^-1c^^u>fq->C=i6YFrU}s8DPNf6$k}(U-1#QTJ(AY(fMR2Ra4rIlrDP<@c=`G z5D+;ow2TkoCw3N+aKO=(zoby@yG0(+Wts$rd$%FqubJ~+y8 zC7pJ~u4(k_OnTsMYOmWJ#%=qP+^h8iU!)yEfEG?shy7m^TdL%=m+d}}J&lajX`jzt zcG?k?>9kkuP{E|&v6}LG9c95`=dpKfo(3)<{cgD zHLYFifLC`^ERq@&P7R^0naq`IpgZDHAoMMgk$w)<}$jv!oIw5Hbu?#-RQ34~2^K_QQ6 z;qM&IsT7>XXA#!pNar0sQS>=K>=bs^U=h_fxy2Fc09ZdxIR){k%ZCN%SxGuPt}T~n zf6nReK!Xn3JjuIc9?`GdQvPWsni+Bq@rf`Zadp_eDYA{iWmyhuS?YT}}Nq zb`=bwTEp6bkr+z|M-6@;pruyCJ`ZgtPTm?K{*bzIE1Ez8KffPzl6X@reY$D}95{TQ z+{~1QzuA|x*;!57@Ym*Q{<2p-?uj7xUoa8yc+SStmF1vdOGJHYBqm9*i0Z=#V&!7vb$xoE5|=v~_I|2l&*r#8}Z zVGIi`t~TI%Dk9vD39e!d!#DN(wQ4PEM*&=%32JU)DU?tP$v9YI8nTk0C@PE3pd1lJ z5n6^?6@f`Go8Sy9ew>Cmd#@nKtL@^kxHAYuv>sgXdXvKU27*q+W3*RgyA<|`-jxSi zKoPLxb`j1{G0W$FhVY|(iX$kvTuH~zdOU$d(2W2)@p#ntmnx0@(EM^zi)!)Y?75~t zn0Lttznxp2_qx3E=VlR+3QWD?@p2RzU$5H#hp5FGW=d@52pUc-rB2zatu12)3M1iMyUJtqad3>uL4q^wiY! ziiTefH`MlY_Da*8m#gy|8#$NglBOjA zEEK|$a2(#McPX7}G+dU$QY@^2vVn8*z2rC-AqO;VU7QS1>ckw0whO%7BV%Noqm%1v zofva`caNd}v}LGs-i(y22zv92*PStQ%>Qv>Og}eE7?>5SX(VHT1*LXm_^oSCrJ*}} z0c({a!dXt1#afdcP)iUBVMfXbv<1{CF0j1_!zA7ykdc+y01?*A0Th%cCHU$q^b)BB}NHWIDR9u?Z25F~N@4|yO*eKMy;5~zGE#iEIb zn(J@+k?32DB50R<i68h+h8+$hp>R6GNq^)C zxuHO)Ta&|n)>W#tH-O=;~#3r(od`kYsd?^x>{}?`i?_-_4wK2)j>BY zb-7OvY}sVT_b}TO%LG{{N!TPIB=IOzm4!epblOstM85+39U$*WJg)8-*$Yu(vtExu zU85t9FpMP&Wi^(b%jfe#9afWaTGq-7vUY)PAl9G0hcUzcqL&u@f{;^Q#wWO=4F4*y zP}0M*BHr`;-Gpr#`F8H6bL|K=t=WcP!VNxH~T~4C1aw1CiXc%ln3LtzH4|6;i)@Vq9x<4VE zV3m{=g_Tu4Atn5EJ~T2oDXaJ;{h2Zh>E6fQz&55)#*oNtO+_Z~%oiF?38u1?*a@ZR zA}$CuI*JNK|9|S<1x${sIv4F--Bs1y)$i)6>euvRdb)e2Yu+@&M8jaQ(|8ewXqD5eHoXR7Fixu}M8@gkNUWqbb zpc*><&kMNigT;k`WSwpuyXf4ORQ>HJYji$$>5`)#t${AXsWig-t?1|r1jA$#DZFzB zSy=c-$%>9|8LD3mK?eMTV*ps_EPH#l5(stqg?zzO3pM>(QO-7WRXL2mv6#_fugG?O zI$M!@tou$io%r3>>ki@Df`u=6-d=pFQCy7uPo5Mj^f^H<)rG9{>=RTdA4D&3Phc2Q zFi53_>0bk=yM|^WNVVKB0OINvs!tcqKQUsJV&!n*P?1<&f6^8MI6a8&zj=y(y|Gw1 zQYgHx_ymT5|KKiz28q(1Uy8CI=S9vH-|uAIxh1WfDvlie)NN@XLoRe}#+uq->##s7 z;Tiw1NQrq6symXs z-flC`PJBI$pBpgEKQwHigovXajhZ8xgbRD@>2rBNv#xc(*{F$cWfkt{4rT8ZpTiyJ_`ZK`^BZs3{Kjv> z58fi#0UW5~dvbl=|DW*?=N1A-|Nr6P(=HE5PZH}e0Hk1+XNQ5gfVRWRF|h2L4Lks? zkKUs21d;ExS>~l7DHe_#EjV1n2dDuKWHv&dP?F}Wmu=KvMBPuIn}_VmUx`_Nb=@~& zwIYdje)LyFuxF-ajri)`(R@3xf(otm(Zd#*CE3b(G3%<8*TV}lftkx*NDQiU!=FcmT@9QfjkSxrUfrDNcb}I%n}3 zQMIq3WX34Fr}76>#=fYslCdBKj+u9)3yDOrP${J6lL7lyw)fT`jJV93GR3I?75g9U z{A%UF;XOAOis2B-=o^N=kX$#CtaNMVi?^mSxY)U3jN}UTGvRClI8!S);T?sUFb%!z z3j$>lFiZrSv6@yEkwmqK+zx~fMEXVg?Yv&QD1*=@90s}+I@uSL4+5B`Q~D&2Y)A0N zxo;Ht`*dey*s)D_#32s;l;KZ+93XkK4`GqgMmqWk=zQ^@V*bVbrgHEsX5=iZzrK&6 zO*t>C^;80o0D-<(FK(cX&c<)De`L?XnmF!x4d_~+P776nszbEl5fM`A2~GAS>bQ$O zX%syK9H0!uFs$$H14SCE2jKc3WH-JEmlR-4VleOsQJFVfi2Y?k@`hUpD-juK4khEk zS4a690Hr6@8;+;r5jh?T$W|yA0?OA2YGxpG{}EMbDN3#$jkgk!^UBDxK`W?g>6_uF zZYfNmi?!$~Bau+@)r(R7Iu=lOM>JgyX;CE^*U3Nu)B?DQBMSbLnq8_7BVd5PCq_6R zrWMf=GxQOrOX!13h+$Dgn)1sjV~5%_l9d@Jk1M%gsbV9eObYsoAL;_pL4c60Eg?Ux zh46Gs)Gz%y`x+{~QT>p-W4FPxtJiqUM8&DCplT<4MFrfA;Xl(#ef(nXZMJ=D zy?#tj+3a8(VG@)TP9*T*;@FL_Th`RAwAr)G42r@xp(MA-eJim$XnP@Ps1#8vG8|O#zmm-Olju~$~q9vtj)Kp$uu-C~-Kc3H9{4YUn+x=psv&!l>6yI08yLiN=@4hjg zH{CCTOz@G@+IA|MOhcm0BKEIRomdM!X{gyvH}K!h)J5Bp8dpzD1Hh2wsPfD+^;;&w zh6Ry2Le-+t${2;WBat8#LyAXp(L^A%Ef>bfM=M+sX(BRmmHV@%K@kOMgQ9}fzbx~2J zZjTkV>=G4C_|vF_nuw|n;fZDur0@GG${_b;!>Yvd`Vmg%@FGDrM|*`l&*D>W!jX$O_#Ij zYGR(h2LGpwlZ#_`D~?anm_uqZEi-s1fd&F;?DVnx#4CpW&$YGnd~;WR7ydT$&8P8_ z-p>!)_vf2hAgk7BoF&v6s1sQUmx{#; zeL6c`gQTSxDQc{XVo@p*5wJUur$=ymajAIciy0)!FE4DkUgu(lWiGC+7HN6+XcIYr z{Hg?o;D9I~btrsE2X>E4BvBv?=~quY-bXE^Q6TYIIWdst6i3l}u-I^@!NZ82&V=?s zJ|@mLRRPwdiKb}r3Jm~_7kK{)(Z%BN6RJOW@I&YhhG8K53D+WJYKXjz6H5EwLFx!l z=cDPZ2?eJBv=6?N&vY2R%YLz#jt4M1{hBFmMhCx63Zu)zFV~&K8f|F2+ih- z*Cq%PhP2Hs>YWSigJT2kgO&;h4|2N`^LvpIrZ7bj$|iUwoQs5)z&S<=Dxs+;kl=PP z;OT<&Ehw(e*O7R_QMy3=hV#7RD}P{%a4UB%5k_?_B2Uoo2|03>&^l}INw12&8}u6B z$m38`@jGeZT`P%aLr|_<+1R5IWOr{1bMD%xk?znAck`zP?2|o+rU&{b3-SkY78!e35)JPQ?LzC#gRiLxhE1jHM*N(83Toa{}{n` zq)NMx64Vd}96$sGS-NZ`mN;V@EFsO#7lgi#2xQf5Ey-IUW+<=>(r)+k9 z7bPkSnKAkP`{gkfLrSh5NTf50zd|;XN2X$5fCu>H?uk-Dlf( z6~>v2!LttmpNQVVzHza-oZiBJjo!lFXPK?Ng};EIuoa||1>3+>1K0|U5%B8egC9I= z2oIfj1d7bo2E5=ej|^k51^M%B4P%7r-NG48!+j;+wk5m=o1q<{{3Unwu2gyc#T*(blm6L zggaiLyx_*zX@&76C7VFr{k3nWrZaP&C-HlPuBEva{ z#4e=lz{2EUpSdP=%$>vbfx-h!Hob{a&^n_fg}QshZk!FR*0E!Ys8CMBQ3%W|HS*let-C~y(}8}I&J2ciPJ)l?$Jtp z24{KI?(M0?ipNO-0@=F^y{Uz`oM|b@O@VU(EmcH%%;XokV!jf>r(-O@{JiJDH zCjFfFybS4Hg?^4;2;_CD3f?@>c7nkNj&UCdkN4mUa>Hg#OPf`fB+)ySM zBCfkee@DqC&;r6tWR-p2GpWBs;TbMG3>4VGHztR(J{AAvj$JK8bL5Lfcj7_7J3lHzgH4zitZ&+ z1yj#IAuFfPiDL>H{^`W+&Wqj}rhJed?NoREWmE6){5r-!60iM-7|82@tf7Ixcub_x zA93hiKK1k?VrkfXAkGUeu4$c6Oq#|*>jd~XXtuOq0fQv*Va-saev+vXi6*1w^1fR! zvnx8D`|xZzHtMsYr%vU|Gs=(n$5MJujTJ^q4Z(FbykSM#MtSx(qq_YrtvO<*e7+pk zXG#|wCvOcoY{V<9XJLl2)2ApbDc%qvNFr6_Id^(U6!Pbi_Ac^FFWdwu1Fko5k!i4{H8u zpqP*Ye%&&0!bg2Es0`_p5h(=YiZ`Ta<=G*be1g50i=X$o>h-pf4af`|SsT|nj^={! zzGGAvkl+Tk_Bz00DB{dKrj$=gzL*$dYyn$%@DQ_k8ls$xCi6ux&blS3VV#{5y=YF| z>esVI{E4$tw0`mqO|1nAI+P>0w2);J@x?LXR5}?g1QM!Olk>3*0RPD%MxImj6G(LM z9Zf`>xm$%^fGiIjL72M&G=TjQCmzL04*KHEyqK2j2S!$hqdGG#n2)G(;ERi&9NAr( z^Hc5)=HKxNx9|dEMg?A6XWKPEP`ho`032~_9W&Zp1h3VNUApAeBXPb6STx+X2n2^{ z5g5?L6&;A9d5r6LJ_V-4>UW;-2kOCmf|wG5<83Qbz>HRl)4z`1!>eRPS9&}^Pe|%` zj716em>grti$>s7Gu5uQz=*XK^L47?|M$y3(m2v?b4F<3h1dr@pG*%SGQc+j&ncJf zB;OHt8Tg!hzHTNqH|09tfx8Gl=QjKz^>DLOrjB&a`h~tnd(o-kKzmi-MTpXV8gbU+ z#Mwg@dK3SU+E8kuN(;4VcPim>qZ9g*aPr}|+V^~|)jG}pQZ*i%dQsCMB@)+{-OsvT zTC?$k5=l_D)DK$PVDcY6?}0H|MyQ7oJ|=+J%P4 zF5l?$`!ly@itmf%M&D9E8rJx(>Zl%3CzM1uoCv*;iUzaU!ubP_&i|;auwW!#$mnT9 z;i8z|jXzvudp)njt%u7vC~8p#pgGVhyfS_Fky2oV1DcXfNz>eiK*$ciK`j1IvsAXG z`dMiqQuL*Lqkh#^1LJDQ)?r?`7#Y&NjpO*K(hGeLfUYk$nm?n1q&d zikb0;Mgxi+P$pz`+$W97-jTE~uIX`P@(>mVCc@xH$*XD!^QKe+H9iEpY3y?zGDqPN zZ^9O%JV5y4EbzJa2weREzzflwg*>2O4_JX(GWZhxfgWb#(>a@Y{hFRm6{nPuKzKBy z*&%g2pxSwj6d!jU#pVOqEma~%em@kl{&& zlTpPo#vk}0h-tM2Eb0ZSMT3>q#QRDUUjtj=(FQk7e82ludUSEclvz(OeiY8`cW;3!aFFV z^GA0yPMnxOIk!|WBf;SCZT5eWvgyUq;e6?N->WN?VARAHZY z<%a?8ch}A`TrO0;8V3qN-5?;qd5AYc5nxxhDYqNOAPP}lr01yNL@FAU(W26ZPAgTW z7BEi$X2Vbwadj*AjT9d|R(}(Rw8qYfU+k^?e^~RTo3%1o-yIKgz`>+9x__)PCLNv}*8hr{WTRa+ ze{|&@t`{A{c+)806|4Rb?9H_7bo8y(L| zzlMqF9}c^46|>Su|L*nmtC|ugtxwF!BwPj5hL6CgS4a8IlY)HJGJ4Q1uq%(|$}{tQ zJw48r#?x%`2(Ny6o=EHCL6;)kk0MhGwA-gGS@bV@T^q-!_kN8uabp@4qm zE*KcGq#n@y)^Yj+&G9DE2FO^Wb_>WO&&}+a$t`Cq?UDaRWH?BY)~y*Y$bkgQu)yM23+EePawy}taC z=gd>92&8c`R@)ct%bg3~d8iKWHF1elCvKhy$U+G66y*(g`6qFyrd2C7nil$6SO_e@ z|8H?v!d(_!Q4i(!z2pgg|HB_fz<+fvPw0cYEV^k4DQes~Drw|68vz6twSy48M_8rG=zwfMjIx!pXYJv! z>|w(!hk5&&vd?_>0wrk`&HE+ z@BA6GsbCn-A_afr+Rjhi=lsu|y1-kJqbsq3&uKIUq?|;J0l2d_@j=WsJi*oJZpP z*;yabs}v?#d$Z=DvZ2M3*@{p0`>pKpiX4ppbP#p-E+6l9;&r#$Tx7a<~tYeuDxP(sk3&C6vK}4K(1VYZoyYd zQHco{GqNlx_BD(HoQJjNN|2a53zO%O0O$wRSV(^a!CHu47juRB477(AfS! z>J#IlYkG0^Q5hHtgKoNVS4*TTZ-7a;S0_ufSD%&;Qp@fga7iK_@(J0yb9 z!xZhkK-xH7&G79Ho^nITdF8wyIl$HsEsPmqVzh1sQdQj!5h{0^K z7!Ap)mt6bcz2mA$aV|L=+8U-NiOwV7h*F0FZj`#OSRO!1Zjc(zc<|r3t{2xWi_?#K z=TKOBOVn6(!n%tWF0|8e3QeOr0rwQpp~u6zA6mC@J|@y96r{WKV$}y>kkS~$nMeRc zkBo@phI;^l4dGBO!9rkP%RV^Oy}X`f&%zn;MRo@mlYP*=w4`S{e?=R<^Jygs9?@9b zGq*rNYQ5&f*s0byz)qWQrz6k9Xg+1Ly$EFmEAfeqH~qiA);`FVfu4BDgI1jAJ>7Zl zrklU`B8`jgORW!2LxW2KjN++~u?j~SVJM(lxlt?^e-3LKX1PVV@DRn^7NU{>3fs{6 z5E={I%tC2FP*b*2<$@N-wV!V1a_tjQ6^N+*#)m&EoYJd2APP+<5)UR4#?gE4J$m$B z=2cUcyopY1zHR8FlMYc`*sE7b<;mVlDAP=&n$5fEbiwK|_j|N_+*PHqvXF2U7_q3O4y_Y4 zLXhNcd21zj8RwcT_Y*&o9bH{!o_*OrzUK>AK<|0gPussiZ+b7Z?bN<(mX)X>E3~o(O1~It9GO(esKPG(ne0uWXe4yfWT{xT z^VOC$W-{CO%E!^1j=e2=lWas*fTphI(W^20#{A0YPoWB%(fQ6-T6_7~-`fv)1hHWK z=@gnrK0dj*ountD25&bp7;6#EUo!XwTd{UwO=0a4o?@Z-n}t-qlpQJ00?26Be^S;K z)A0q>O0jfyk98TY>D1Be6Ag)M1rlB=yQ2^{W=BxA=>zu3>f2c&9n?C%oZVf&FgudA zgGaN!Pwl-W*$+4u(J4xCQ<=#lkkuIfoS}%qa6|ztY+j*=2ioApLUa)E9s+YsG9X(- zba)Qlg}wy==-IJj@WUygn`vEG)4L_47&a=FE}7n$Q?ETWW8c#Gdl4yqvC^vCG;7b^ zRB5rhZX|C#suzVy5AEf7g*>ZpdMqBDxodj*u9?Z(=Q@8XRui&5=Wh3Z;uHSc=kS!) zFX@_>*dMe10PQ>uI|u8k+q983= z%-|N%SFZqk}x3*f3 zPZ)bo-thh8{*A-9*(-Tr{%C>5vvn*XpYpT85O$NuW?d#d+2J+T3fayvfYx#(@gZ_) zwZfo)hECOWL7Rp81vu`ppj}}5qbH+Dt5mk{vCAbZ89n(#u~jS{X&UoJ^Nb;)dY?L( zOeJ%%WHOe+lao(;7j?oPZN}rxGY^P(p_pr~S5PTOvbX_C2aE5AI&nvcP@q}G z9|F=jr1c6RtJwF@{YHliX)6{9ekN)jy7%5gX7n?`NX$wXhDVRT^{spJm4&x7s`;k{ zX31GapTbXsWP`1Ksz4TQ#9gDV<8IMQ3xWnmv1%O6|hMzx_4g zbZKBymsx9_gakTP;n#D7EWvCJyg{qoUgdNP-vQmn%hRSye5SD;d5=F_*O6KP)xj5Q zs=!dw>cs6DtH_1}TA>YvkoOI-*Vkbz*zM)^#_`bj&=#xRCO-A#ri%L!kdE;S8&Dw> z?h+MJlJd4`|3WMMr%)6uyD2*t#?8RBQ`u)nrTUv$E{H3?H#-+`SSOvzetitA>$^u# ztX#-uBAzl)x88;!w+ap+WA3RUzft|+zB{p9=j&1mQSu^g_5=GXo9@^7g_VQL){D+P zd-G4Fk+)d^afF7jEc;hM{NhDe{R8IdJVPf3F&=SkO7Ej0{&(PwK zvkc3tahfVlpKj19J4q=-Voq?AbZ6OJX&06p-x1BfxHg~vD_@_q0)Vs1)BqIsq0*YC z7ibaO*=k+F0wAvjU(lOxcD^kP=iZt#_{t_Q(6;<)&}u{Dw>T_Dq!MDJ8&>%*pkL2o z8|_{AjkoTl^JkZ^9KlB$4LC4QbcP6h!GJ%i1ld9@+{uH2QSola_>Cl&CV8q5^o5Ru z#>=#R=CY@VuV%wegy*uIe`}>i*M1gUeb(bMcB*;Abk?c!&R_ZdcHF8fPMW2fHx zk#zjNM}xR6=d-wP#8ZSVFb1uGbOv`_QkwVHwTUc43(FHnK;QaYs{fC^75YFbwPdz{ zP+00N(nsx+o7U;4twm$vth9JH-y7~ay^>TBY>&@@?;FE5EEvSR=nMM1(`MeEv&ulV zXG$Zp_s@=$GDGEDbxg^y*pSA~iAzk1R@E!hmNyiVy@5nfLnFb27A$uX_-QC{06VLSh|Ju3yg9VJ_;H$wOk{8j*=ZQ`flbr((MH!x=)aJ zvFV-eN05lyegq?vJQDyC_5FI&hF8vKY~y#FSB~4GExaGjFO=Zr*^yWCE)5qx*lot# z8?o*V;)gQOYabz;^L$L#IyUkv{W z4vBPb^ul+r45>#JC(e%MER|0Ks-0_Rdl=8MVV74I%R^8mcoT=`rShJZZ7(OD!`%>^ zp=!M_X*XRDPCL4u4VRkHZ4Xa=SX^@+7aV(@Et$#QHE~7e`9)u-chPvC&qjrg4NZtl zfOt|R3)b=JBBl7Noj;?PM85NAwiJPRGO;H+!*&y8{t|m4TMFq!<8C;8db(8*<0Yx< z_-LRA<7^>gBR&t!na$K#IsQc+>Ohn;yQlM2L_kVe_Qb1S@_11QhF@GA`&Q?3S=@-? zCZ%lW(J@MfaQF(J%s0VT4QCl|!|XU@ETo1G;O}SqI#b`ak<&Ilaz8z_mF1jA?!BM` zQ_E-fUeHAc@xK3NU*0qe{dY@knGazr--|ff7@+&Nz~VttryHjL)`iC~ct`_YrWplc z4iVExT1gSSAj1fM$c$6UD0Do#0RINrp^e{;CKr`JO!HIqUWLU25!oLLr(>GTWJyA# zArh5*cS}CW3!h{_@yaYHLIX&qP1)fhZgK`(hwaWG6arkG5J-J_oMOfcp0YlBXO|G6ID~NUj1{U{0F|hTeOl zmR?NdEGw5P>elF?P@@r@+HYC=r`XEqp|R?GeY#xEX3OR2`g|4NzEmvk8T0Mlr9ctv z*LNuajp7`LR)XbpV9yA9Pb9~=bif|OAEE+1AAx-!R6eJonj1IcE)iq!-1$@^Gc%Jh zR3Bc2b7N zY^Zod_1?Js)~DX~w&AzJdRby~Z~buRJ1qWTJiXA>x5>|6z$q>Y0Krvh@dyL-Y8AZX zS-EcZD6B5%q&$pF;zd*}L%Jzx;YRs;x4y-ii@mbBf2z6CEFOC+bX1aC(EAr{VQKQ0 zOTcHd_Tu6A{J}ANF*9_zO=f7DK5VzKw0EWIM1AhQ15 z53cQhIR68b|ZCpbWaN+-KdV7`cVwmt#qwh)gZwh)cSqbB_-AgL$1LdX2(uCjv{%8>fJtl*thSLDA5Wh?T^A;ccy#tJ$)_HW)uUru z@T8h1(#Od7suBrd0E;)RD}ZCK)k)sfET=QXm>gOsOXSE_=S3X z4T+O=+#E&5Rx+`##LIgQ zp5IsGZ-P4XS#>BOYG@V+g1C6l8*<2?*fffuXXD5O;}j7|%Wd>K?_5ZvTv9+GsMCDU z!w*HIp@cYzI8GO(%Jg^ypzpQvNG9_flo6p<;uR1^EtFi@kzweL+rrfG%zC3>RQMxlf zH;}s{SHICuFZq=J3))nD4EhD^4`xEIgbyCQNtza(ksb_Ec;8d#aMa|q#=aB^?R{=< zctoqV@~y@E-if{WJ;lA@a21VAt9W~Fo)z(H&&SaTwT7=e%fGTWzc*YCiSLB>!o$d0 zLtaJ;@AIC2WgeDeRe*JFULgUlR2nvFRdn2>{Mag>#z_UQQ5~58(!*3Gnaf%$ ziO}*8N|@laV(_L9Nfc+DBZTmrX;?}4=jiFIIj1I(oIrgc==U5xL00XoK`7z{M1_Dm zIv@d(4d2gf!!j3|jRopmfOqh;Y0d5fbLZ%B9^Xd7Qv)b&;MS{U8f(pflCvMUZRAfP zDHM1HfR|`GNMd0|^2iOrnV?KkL=R0FYe?$h&sC0df})0U353vs=azz=bST&GXNoNl z;vKwMz!VZ}91$xh)_}j7(0FTAs8o4q6^O-sRgX%N1YeQF5P3qOe931@X!U7GUPaO+ z*(XVHS-~4D?$hw8<^v*1k`y_v!k&;Az9LD6;=@x@@f%)mNQ%RFh@xY~mMcqA3SZmq z;;>-4SNA3GiZR@r>3AmN20mO~!u6$)q~iwhxZ?W>S&{tcY^wSEfuW;$*f^Q+=4E9XAu3##5=Q2q$h0zR)6^!{m&0h~n61BF}P^ckqpLQ zsX08rSYUGLKEYr=5cw<$1}jpy%i!Mi9UgDJJ}!qM`I{yXw?MjrWPm$5tT5n9BQzq+T&(=5@p0uJ;7K z6PO@kv@N!GO$_rdvsJ3uGn%D*Xc{iiG?bfyzX;2t{SzA>gL|eMdsv0V7~&ZZZtQ_T z3UTIznIKTB;{I0G(>IqLrK?o4oeyG}5E#p$VW}!eK>T5hXsBcxOzLzH_52oGQ-YdB zClPzo+!B&?2X5nZ5kMQNgtN^YFY=a~R4@xIH@BJW&cF4XJP3Pio_ECYccR3ZcQWi< znzp4#%>OOCC8wyXwJlwIA-rRv=Y!&N^pEVjSpO9Bo(@Npc6;^Hmg=YzJ7 zCK8T)rITq#AOxV>2$|#nCpwvC`V~ z6YW!V8MuiE28| zW=)%cz>vFJS8e-G`}Xt%GJ*(bLa{F~*LAGU8f?$^2d8K8*?QR;=r-3F_ zuo5QWZK6ixkP0e|jE@U^<)$KKT5{MFSNXV+=!C*euK)uME5N2Guqr9=0Jk9&Pyr5N z%i0SxzBkbD9+HC5Ptt*Pua-+q2e38u6xMtj&1uMI5MuuP!Bkf4wH$5C@dER-Q~EfD z_L zW-5sfml+3Lp(&8Mrgfe&Tyx|=9VeK~x2VM8je(%9O>EYY1cWj@2u$3A<4pGU^1S&&F@s%8K zIt!4N$EgJ&MF61_@cayDU=k!I5Y?1uNB!s&b+*PsQ#`AHTh<&kXuz%pv=xU!%_2N_ z6=4Acur}1(W~cYXju+oMdU&jIW70l4#wBTO3Ypf*_qx)wD>~!zh2&TwT0NM0r6SFZ zm^!-m5@6khbZ!u>@!V9-><`e zU4xei;XinMHXZ78QW8=LDEw|N5^D3(xSc~ZiX~6^NnC08gEt5YKe=!>8V#Y(UOimz>nE^;NW z%};+V8h0gfq^BeV;z~&Jr82cc%iX!|Y6stf4Mo7RWf(U37BE_$<7!Tx$**)4FMc7W z7T_W5-@>Fd)fDfb-3u=%t#A>7r;roZck}Q>dH66FZZ(Irx%N~@mF-LApwX&UG zO%ETHFq=Zfh3;$3j=rNbwHsfsOUdx?>?jJX$0M}wkHZ^uFc=_xJ`!$ae-Ke`PDJ19 z%%n6MW2NB)KKn|Y75#y|x;l#GjkAb0yx75*ACgk8m4XQO%e7GY`$^o{l}+3x^)cKcsbrl?K86vdoe{;o-CEUvm^AY;o`9H@Ia&*5o}sS-V+~khiKU zYsq}xR?zBA$BTuMq+GjzfQ1J}NLZg5L1R{afKCF-#2iVZX-UHvC|^Hbjlpy_!=`^E zU}q^^HJuhBc8>Yp+!G>t%2}Qn-8)FUcD_-Kq1d1nObwyVb2^QNZ?xwK8TP}TU#LZ{ zi}7WcFYj|fZE!AL?<}wP{E~1?yPluN;3wMyzrmfDZE``vn6^lv#Svn`rrvsf!0R(W z``gA}dAXQ1Gb1zd?xJ<$h*W;fm^`5yy(o5B)U+aQm~YXberkxK9bIV#XK`%O?Kf;WGH6Hj!!DdfJ9 zD@>ladI|Lbl{sWHw)6>P- z8|VQYq^%I@Gl4banZ=xwW=XM=N%&=v4a{H%Qj-#H0(vP)(aB!iN1sstk_~SliH@f( zv9{wTgRgA0=QNw@Jw;|#o!Ke!h)vN$r-Na%#8Bwh^2V1yjkViij|wlC;TeX17I~pa z`BO1Fv`?M9O6c%_hVq`5I9Kte#XskSlET-Rw*X#)lbNjy?~W&vTsOyTDDpGz)5#Nu z)fj(4eih!=eswq}_0gnhtnQEw`acACCZ`_GuV4|Lm6o7Yc(p<fsJL?LB?8qTU@G-k`=I?hTsO$5r^_&i0e4;gG9~NFmQ+ zrMY+bdOfsSJeS7kYdCd9S}(%+clERe;b%lljmv4l*O#>hP-Kw;I9Iy{+I07;UjxU` zpbWH9^wagS+(6mETfHlAlh7(}D4$lY*2F;E_R!$3t(A(6xq-|R`bWfzln-8y#E z)`t?2DaS`$$fnFtZ3-2QwsD%Y@{=gwfPCl4p_U03LN11-G0A<@kh3fhi;g629`Ey! z2;K`l+>3aw!S^4?Yk*G6IV1?Ex}PCtL!z&M(su4z-mnWvWoN&boE@7qQrKs^r&gLb zBW3)cylZl%es~mb0X8>M7h8}k=nw10o{y(SwMi`>BjJ!Z@1J--so|M=aMo*8Oj_nR z37w5din+^ws@#+XDh|c?ORy0{gag_oX_x}0N4e{BF#dr95U60n@ezP;*5uI*3S&wOt1f#J)WfC>&8mN0tH6swUpu+~Gg5%P`OVMM&SX?_6h!x3v zEykw9(P+5n=+1(!0?>MdI}@p(5KICIfalXp|8 zfi%ox@DVK*t+qfRYYXD2?4`YKtDz5~oM8PWk3(MIm==!(k7=GQ4skY4Inydg6B z=%K1uea*0VHVr&leT!m8ir6o+B}=~=l2l(?RbwD($^K7Uh$1;g5yWK_Xs7b*9+aBu zMhmGK$PfTjw24p`g>z$Kw07*#Fv0=H02P;MQPzs7Y$ zw4mGvH)?}NR3Y-IUYquU%dvD$16{|kzS?F%NkwMM)A%uqiWQwbmdm(2I~Q!VDy>%* z%}~fP(<8G`^p;84gMp}7Mury(A@P}ppgggx7zxK;BK>#nHRE~0+LXbzJq z61!gTOMk@qcYc7*+G-oYb1wIi7V7kVd3$Y?fTU}ZhpVDl&$Q=3&zm3+`jscJ)KNXf zu9)ATOYH%Y5ZiW^=LyxKyiGgd32Q1nq6b?IU`hZJ53qU44+eq}hyy$VbKVVR_bD;I zCW&)MQMzH9XyO(-_$q+hP~JN3^D-OQvVcGB^BQo4rU1@Ep$i$OiPxuw(<;3=rKgk0 zwBE1peAPLtOe6Rn#`@H>>eOewtRe-p94?SU8Cz+@>x&z4Ngk0jErQFRpzN`X9$qU&4OIkw> zWP*UIDA{e!HF3oAoEcObv=A>@z?WTU4)eGMkCqI%8mpo>woXtE8|l;lizk=@U{6hl zRbnf^m7J+5dJ|0b2Y?bJw#G9)$z<#yG5Qt98k(1+hrv|*B^%K+9AhY}`_=~7!(TGu zGMK0ZB+h4)cps4^u-WIun|{Pfz-N3|K^YJ+c_f}CtW9xL`QgCpCKUn`Va0)gZL&Y? ze45u}>YUB$i(h*%dzjrJsxYxTvU=yI79Y%V5ihP0;-wF}iG=V^I>nw)pMlLxvG~Rc zPhVR^IjL8^=4&Vcu&K1uB6}Par9NiA*y-@XSUASWHJ9MK97Znc^K=ypNF6j>0r&@g zHnw6KZC=&lH~i&2H=jGVwz}$nRa+pV3=@f&zjbbvY-h+d=bDu43Ehg)Gg0@wt58`+ zmE3k^aG{0-P22w)wB6U+hPkq`cJ3VXXTzil98i$jukstHhPHMNmn3;9+)P9(r63NZ zb%WPvGtEEK=M36H{n`dEPv8BLILyj8JP65UY`Up#ajnCJ=Pj@F-O@aFuK$LBW~~@~ zEMtvxn{LVX=05`T`54N?nc@J276bP+u*VY2R~3pAq<_Og+ZY5L5J)3c%8fYy0LM!* zWRDzepqM|0)vTO*$umkIHG!cS71%Z^RQG5mo@m_6&$Yz5aqgVCYcyx!dvvC)IEXfJ zgc3b8lLT~v`bqS_MGhnuJU&JlWs9zgDm}G=&C+iB4TAezfi7Tp9+iS&RDA-tXFJN= zVzB=eDmx`nQn$1mrJSL|qSfRTOAu}}_;IBo=14V%a7@9TXOHg93?EPb$JT^5)=FAY z<%2JN&-(2bzKj&X^_H)d9zLFb&-vuggENXWvDV74JQc!FyV#?#|EV*spYc3OOe)oH_mR)=0E<_r$}e z?C4Cc^U8lYf4+{UXQw~@C=iYt@8OJR>phy-l1M~!?^Ee~h#h>uzTdged+f7se#ZXF z3ulUdXOE275A1s2{_d@w+>M0lh2r1-=+Qpe5_UMpm1nn6W`N2}iJ}-VeGFa#=4;uVJ#C>p%J=()OtzlqeL%+k`c*_M~O!?2qw+0HvAE;Hlz z?Qg|1HoX@=ykx&J+sec*#WTR(Ub@sbz62m%1ZYH70TQW52POLrrb*u|VMXCXGOfhz zYmM^y=qQquXe4`APU7Z^DSF=ao?2RgbOHuAwUDw3PT_)X|}6T%s_ffm$uCtC1N*f0B_BfHa}W1h<@g41O~rj=GUT(Y#_$-U3j zPcAX9uxNtlT9sPN{!V>VvZeY>EH%+ybm?10X|0Kq%XVE@Rfkb~eHr##w)0QYnAx(I z&rW#F7HDtM8@D*C{z73{)ZG&SXrdRbKP`^(Y|ZI$p))_zWSNM z>|XRtwnq<-;uOvvX}0h)bU4c@?+OGHX*rJ;tF2Z%B~76M6gyQY&)qx!0sG9@p)piU zIkG_CzSNvLobCL|Ps^yb7RZ;X@1+0n&t_~&N)03HpJ=^=g16^EYaXj=8taOO$A}J4 z0&01kF&KtIAw&gzr&cJ^LWJ(YJfM;8)oRV(^BTH-%NRX;$KlZn8)_i16;OAHJ_S{1 z?A-YS@zr;NT>Le0exV*1P~P;5<{Y%~Gmr`%koJs39v$WNWaJM+6oFp=ijuilldFL>t(=`mhE;(8!Z*Bz|it}RM&B?@95^@`eX)gdwrb0 zblV2GTnF8UGR@%L8*nrJKJZ(d*CP4f3vL&wyq^xOpEKGi1IbEst`9@jDyWr)TT#v; zzuoupJzRI^@7WSu71dJ7VrxdLjhp^=4hF?XNyC5eU0h(Q}FNoUNOJCiJdH6T_!0;Bco?l(-*>yQE10DO(nNKH$Ggei3_H1gW8xpdiYqy ztEt{0pKl25J-ij4H!cIx;q_G{lw8Q68B=g-@Zz8wCcb&zT1 z>cxC%Xf(YW-9)zIXSrDKeD?ZS%J=sg59x^HeVoydOg1I`s`#ga!^B{>%tL><2~;Ve zup6oxywF`XXnvhNTyWU|BsxkStY9tisjm%>V?Fei1no6$$8Wg*L63)&OLA^ftVl!@ zVN?#-11iF4Tb4kR!#9xhj09*1&6SNL^;US@E^eAfsg)kpQT~dEF4i_v>x`mU-!LoE z?)2yoOcE9Q_P??JgFVd?i=y1B%8>N0SX7l`u4w`MHpS-X2yK?}o(1nDOu>5>o_uoQ z{hw|&Kl2w0#+`K|J8XXaaQNZm++6Zkn&J2T>g(U|iPwMP6CWCFJ$mDM`ryAG9o>VBDGK%)XdC13`Jh$OK(8itmAJWTS;UAd0J>+|${FV>z-TUF%%UQ!~QftP0$N2}t z?|WbPyVtoy`^IVlba^-IF`PUIoVw$s)@=>c9C_J0`|s{QYTOZ1Wq0U@rmIKqA9-0q z@W1=_-8U1A=q?lXNJG*-|5E46*U1dheQ3Xmh7J^9*|=Loaz%&iC)X-t|yk2K$do0NQ`Jlv`ECt?Saf%y<2&ZI|e>e3iV*0H;QXfBY`1 zbbUVSzj+^qyF^@Yir7#{L!+X9+&chu0VV$$qzwrVD5>M5vIun@u57kmUpjjhMdx{~ zb~n0WBe-$_Fzh;_XlG$>^aWKYs^;8_k|=|8f;Z`!2)QG6LR~pTThQK(sD~J8zS{NW z#l_`1JKMR4OLoI0@2syNWV%Qy;36VCBp-zHL-;%#Uyll35BYLAd~8Okky;5+L7`E2Kv*=JC{DiIw$ zoEpPeX}n(yeBRKK1a${jh`xsXLejc4NFfGWSf?v-V~ zTGXPcP%v3~?Q2U(Efk7s5(9sPo=U}K(+KCkFL^2pBd3kx0ilq1MJArmOUTY!#cr$!dsFCWZXIfb z3W4Z?d{(HLch|t{M#R?2p@kBP8ySi8=TBDVE6mL1MNP4ELOPrMmu3jHS;8heRL)oN zHB{XA!0)5=Ou6&nY##NW#+0J^?N1eZ-{q&?nd_hOWa{+P$qo@QcnVf@2+7LT4 zN_}+MXY2u#vE%oOn}%+hK#hVv`sxqWw@~h$G)f7v#Y$SKR>XG+#$0DQzzul?{N zrE*eh?VI_p0abF{WT%G@za^DQMen|Ps_%M5=#95T z2UE@U6X?tT%$|a_K%k}{LkXo%de-qCM3bUIXCfdQDSM(}4ERm*i#o-C&G@(meTW^x-G=EpFmEWofM-yU31Gs;XWtGOdOd;O zGypG5j|a7hsfeb?%$uksjDX?`gvZU0X8N^|p7eRGh>SX-QOoPIjA+PjY9VtRRk=Gq z@09~X0Tfg~Z}*g{cu)C!0aKQ|0bjtve|U$_49I>wL0vfX$9VwXm1UHCPX!g!FL<3l zmelmo1ezQM)tK%NGf9sH!?EE+AYw%W@!?oli|8z(qOpeL^XFJnOB8i2i2#O|q1lfv z>j6!dQZdvp)zq+@1FSrj3i!2nAZU(747E}yj`)+&Q8S=K1O7lNUehyqUoe$L^u=qa zNSOgBTrcNSL0>)t34ji@I{NWNybRS%ty@swAZX~sfUB$o;>+JRZ!X0%`<}N+XF8zZ_Di=7pm9)S+T5n26lX0_cB>VtFd_qbfxp=8Xik zjCXiMvO=KTQoSlAUgDhmXZBH?GzS5ke7EQ0p5Gd@`jB6aqj7<+94N^s>p=^!Z?QpY zZnv6du$(Fumh*;ni~fY}!lDm0EiDc+LFi!HrG*+L*vfoG^VNnXjNcBJsP495bukDQ zEDsB1Ey|L2NDXXUOaE@$wIa(h>)dmDdfeYzmO)MS7yW2)vE9N^m3e3fzyA(~m6MeQ zuAIP|6ii8P{SI0@QbCbaEP!BOL{f7IVRcu_?(G)DM^6Ox?ot~n`g}!ya^TwVfkgJP z|Md2#g2S4J0zwK&ffo>VjZsv*qdIR?41-!O z;xvnL>mGin2$swO4mx0UxQkMpeMXXfCaDIHRxHP2GJc`?ZY*iOa@W}5u~ahS2l$@d z6Ssm|@-4T;=11Z&KgvT!RXsD38J@|{4%Kc%xcx>+i-p56wb@kZwrqR7Yx!kReD*A>UlY}NTe}9jIb2Z`sJ@A;#%>D;uHSOKmczMd zop80x(J9d|gc#r8?Kb!_g7cOjf4XT zViJ7HKq`6wZsk!k7=l|l6g2T1Z`yWlW@rhpIXD{X_BrwY_r`&l-VXZ|s%g!&!EM8mBy(fnCsU z0jN+neO!y(JT6PH@j@17pfmc~P05F|owqNfD%ue&PU)36H}$+Gw<4z7eb#P5TILCXHK2&(lyki2q>`;s^5E;oFX50fY%v z1hW`o9pn8)J4q0kr!>FkV!5}$V(ivTkZ7z^Q+2aIJH zF4KD7^>-YHbAv(SSjH^|jssymj)K1WIdOr`Tjzvhng+d)Y2T46>90rj) za3ITc6a3Jg6cB0hRn)n!q8kC)vRB*)pDIvuv+x8E;CO*~%=5HA#qQw%%ga>x=Z;;i zy8{4wPF6EeWdn`T;r`9^DPN^kp zd-iOh%BO@lS+v~}5!J`{+wuUy3<7D2?e{4k`=r=@#Q~&o`S^!86DV=NL{Q9)kaALr zcm)?nP*U3dHrVle!+5yIv!QYyQv41|uV13G&FJUXM~oH;cL!1K`uB+z6W;Jq0GUbO zfx6ZUq>+NpHMklNBU0a`CTv7Ra>^DUd?JL4G>95>L7cX$0$!O;JZv=bl-_@{X_N{p zc4Ig{5!SA@Czh8B5NFF8 zaD}w@xv%*OQu$?p2bm}OWRJC>Ac*_Hb$|u!;e0>)e@z-aeB_#ef!JeoriyWAJSQlP z5!wwu7DRQ}K5Q!X(#sooo0j9kg4QTC zq#42bRD0g&?j}KX%sFU9R5g=X$PZ>ue-=mzSDyIak1`A=awx)Jj3<46``LZ{v+{1= zm+i;L{W&i_M4bkbX}x=k$Jo>VG=XZmQ{_`!%(=)oV)QzTh#TNRWIavA9Wl*LOdX1 zG(#g|Rz80p>L2GSlOw@cEO-vd0!k$8QuHvumyX`h2%#6KrU8{^Hh4Zk6iEf~KE62V z7`^>BfI69U8l6^J*buT8Ob`nNAnptaKlu+x;uorgeLMr5FqmMzUDf;!$^W=g*6=oqw~B zfRW}ox+(45zeTL~qtF7vI495$90mvN*I{IZz$CZeyXMA1lRf!lTlxJ3IQD<_uMp0G zSD!e$kA3jT51fP95$}BGxu@uT-cMOuIbe2q#&si0#!8LTy+PgL|T zq|O1%<5$N{PAO2;U%!veN3>ao_vJXXl7GT!GIDZCo?bQf^F|}|;XBc2#O0ruABxFs zKR*?)(uETZnkN_ugc=$=SprYw%-26~zkix=TfO<(vUeJ4HwzviA1r0cf=5q@En3`q zI*o42<*XeT@gvP0Qy8lb(&CoVX(X->p>QpxGKRs@+7Yy5xlXxx?EM>N8)^n>Z;Jy6 z8mzr-A<3cXn|#0QFdtX|h=UUn3oxVsM%!!hlT;IwW3UF!%1!R403cy%xK2xH-haf? zoP_N=$g(DI2!)1K{OhS>La**z>ZW6_bXNJ<07Rs)v3cYa8%SV2=svEEjWd^RXJxw? z;t1iES(`FzT+|j>+KuJQF4BYQ!uDT~jcrvPE>MfNBgu z11Kx9DmZ49T%a6?%_Fsx_y+YEq1swgbPir0;DX{lDhisDkE-*$iMkGVD%nrPv&x;= zA1edgPUMa1b4)Grk`nu3x*prdx1Cr&qS5UPs6XMk_j*PEF$YfsJOtbc2e%u7sDN)` z|I=_#PK87P#>jRYRUR0Do~P|tIv%sU2ZGxA0r+g=Y3(Y;h={-GI@^Nrv>u&M^z=j& zlN!>oUkLLf#v4Tx(?Y?;yF9P*yoPjVazF{NG5kZK2?|Blufg945T!{TN7+>xx)E&v zf?);O4Ovm-ph-V<(`;YC=@`@=gjX)yxg=_6u8CjxPi)yxtaVJy}iMj4Br6K}rXSe~jyCo<%O&*_$O*=*tl=SQVGl(GHay`2Q zK3g~O#6jWmSJ`OS<>-_1@F;RqTfw_}4S^$RC_v8RzT}dqKl0xCQ%wqqJNq z=Xz%q`cD$r1`jXG>;7LY{Fvflh5r^WfBXs?VUYLz=iH0XrSRiiGIYhwu*D7EXSd7% z1w^=jYnR=`EC5>YXkEoT{w-!SLah*F*6jS?%Do z;j4juy5nlxD5E>yo1=yG=d-l1u3}96^10!RjYf#^^`E6JoJH3&9|Ssu(n*+CfS;(} zN8ihx$JY5@vBH!RPAIXMk_i7^|BI^_TOnGUQWIe{8dbvywf_az(|YIZU7puo&*%ot zU5&Rl=?)U*D*MO0^N2Uj=HIF66pdev#uWXdiZV5&hIIuo)x=c{zkh1$N&;7Mn4$K+ z5ITp5f0dy#9r92qJBSukoF*URFvYQNGYY|M|on`$GeTG+gIk@FZX3s?a0CU=G-bl<8|^7DoxkpvLg?_+~
-lP`}JtxJl{3Z9DdfL7+lUDHqFpz~n6xfe8UIv2K^d_m`y6Jo>k z_t7fO3h=bIi>~slkO!=RE1j^V0juDO=WKscB=`$o8Ek1$axcz3!sIIxzHF7ly1f<( z4%I9w5!xURx9s9xK0Uqfrp5zf)tPgxS6w)Me0b^2wYm0Oc+cVb2{uCLl*Q?6sW4X= z?R@LZnauIIYBdfo>d*I=(fc;=cvOF)jHtVZvh8q3Abf!mRuKklQa)>yz_&Q~Db)dq ztsFywN{-^j?Q=8Lu?HIV@Ntu6Qg;NyxzdTdPLyhMts8!f!!1~gQ!rYYE0oqUXY#&4 zeK;_T>KdtRHZ@mW2<|Q*ifCdp6#c>NUBm(r9HMF-A;crL&K4zscIT*%MJ`GGvo+g4OE)-7 z`p;B{uWzoN?oLt5WzwPpJGsu;;z>WX9cODlz#^?Ha|YAd5>9677ECO;mf51lW;nv# z`j0!!)?G9Mje4=s*pVpP#Yzztnq)hXM)Bqer@UML{<4s>i;92Fw(6U*?yY@T6?yIsXL;5m;wPVno< zB1vDFnXe{O1oe2GP=Zqiie_1)OkV{tFAu`dT@}IdQ1$#Kp(4xa@c+CHJcBdluoR7N zkU@%`n5cMv{F;FcB(KO#Aa+0rZYgvn+aSa(IxmFWUVu0!XMzQ4J* z&c%6tNdL%j1ATmKW^M_w_b;*gawOLSr5`(!YnZw+vrVAAU!bJ`V#0>rnQ{~#5Gv3% zV1*5&*CwU}>6vu!X9ej$*o<80C;Vib2v>*C3BrwS@C(kGbdM`4S2RskB{xt{nfv_s z1QOX{f3s>4#(NN0U<293poYy{jT?e^)5_H5Ke8o0-%t4SQs&HDW$3*`zC0XEzjsiW z9{dK4?phh<>6urti^u@$?uBj6*Rj*F@Ewc^+`F*-!^JTlQ0H|c{KZi)^ms+_xKc)fmHkOCZR#% z`4JRn-x$V5B-xb;(dY)DAjGrQAJ9fHnP#y^w>bC+|92Hr*)wgLJyN%s(ogmR%ad20 z+@KSGCYwzZZdwCNsiaZ_0Ga~Wih=`3nVm%~Hqv0}!~+MZk__}ryre$p-B_~+O6>5r zNsHwg-A}Z*dU=-XxT|j5*?1_OJ_BVIuH?*9qa*W$QmHUMGTMQSj~}kZ^_JQ&s%N&Y zu-Hf-I$QM00pTsHFRKLO&0_ukrR`1NBe|-3VclM;dhf38uBzVD`yzE|ms&le+1i6= zJf0bEW4FBGOa{l;BMcar0TKg^*%A*~fJl%>Ad|cRLE^oH#SQ_31%!me`9cEG07*#v z_&t_bNq8^$g>2u~{{H9Qs$Qg)X2vFxy47plbI(2Z+_Rr+ZWJ4}`0%!>j9Un?7>&f@ zj@guRjCShUZWS6WV}J-k0(aROwgDG*C)Nj%{k%*Mxrzsrkj#37C!69@s6z?G!Z39k zus!h$D~|srf?{?9Q5Yy@WZeSM~%@@16lyb10RDz_4C_<=qO%>$N#{qVh+<<=EKl*vpisp zwalTqfpfnbme%+bsq&9G7zK+w%l;jwX`F`+%;+j5Mo_U4p@_g{2Q#cbf7w$=i~9oV z4X@Z=YrVZy8&_kg+y8L!q0+x^J$%;Wv?mq3CVBe8iP5pK(FLC^KR5RdrLn`o(}hn2 z^&voDFnpw>?S4*PpXdcp(+R*M^@F94Z3XdfQ-#EK7@L{aWnoNlcDe%w0U_$zTn5O= zUKj-uM~|G`zmOUEjjdo_9025OCE=O5?Xqx2xPf~soK$w_YQRg>CsUV$Dwr6%X$Nq4 zP>`U#Ft7HDYMX-C>Z)v?=Hz!7aQ>Z*t9o+rD~q2|)qf+x3v5LaGX#ZwKZ#OZ^PsrD z+Xm}~LFr3F%6sN3x^I1rm6;G>3?Z&cvTx-U!vU7{#Cy@)LC=}tX?x^M~P%N_4P zr)zKL6^i?*!;Xcz)E>!6H`VKuP`zvJjtB3UMFOP5-hKud`H2XAaEBV(;+YNqP*C+= zQUCLe#Qir_zhu+=PP>8I?41wXIg9dMs#mtz8lrsXIq}sWh-YW1Y-&7O70*=TQmaKl zALiU$FreRoaF4SnJ^L!~U`sQrBV8|GwnU(gsW9xD|Mnp{Sv*4yAL;;f?~v6;%Se|% z^E~88o6Zthg9k-KEzXrYC7U`Xo~D58plueo07B*@q#moda~k|kb``V!2>!hO$n;U! zro@0B#b%QZRD(cNz&Cbs{GvdUE^r5Lk6~O8FJ13dQSywV3Ekx-x54jG&sK7)Hd`fv zA_<FVX4%A}yc8V1! zO@Sq0-}9RwlU^DUk1a|XjY`8TwRG=4C@?lEdiMUWj z4#mN!+7-X197RGkmt#cWO;qcI5|Njl&;#;7x3rm~vR%Q$NFvN^(*9}yAP2o_5EB+y zBAU{ivRyLxo$RvPF=xg=V5*jMp{&LU6Ki6=f6bj!o8f>b;?Ky(ragYVuJ}|h$i$-% zk%1O%2nDfm{0$&72qah2jxz%d+#}g;hIV-+}rh$(=y2I(N_!ym4B!il@v9Tn-Bg z{9n(b=J99j_Q8~jvd1nguE#aLpb83YitWE7(EHk}E_+Ngz0M6W)M4*|p${OxA9{zy zi6mi*Xksl*hTHy+t2P;leMIU}cOTu( z<4gXl_;Zho>VqK@htgXF=5) z1T_Y#`z0F-gID@dN>M&K!_*vlH?TlmK+3*QQ{EEkW*zl@8 zg;>e-F&Tv#af&R8i<%tz>y|l1kQTWLTac+KRObdX<2=I=dNrp$td#RO)`Z}=%gNv8 zRs_~Aclt*oU)kmS|D9f^^W{W>&TM2 zMQ_l=Aq+qqpnQUdL1cb+^aYaHaX|{yh!xE-{=LT)`r#iBt$}gVx%Ead&Vjys21uG* zQ19hrcZ1yi>o{5M$H2kXUO4v>85X9JVo8{Cam#4==O1P}_z!QQXl^|K(IwHH#K-OY0 z5Z3@57?knVT||Z~&VsR%rvy$82ufKJGka!`G7PLKAKFb$fTC$!SNWE>1c|KJ*?Yw0 z2}7`F0!`F_!o__ALLG+IpPSKCr9i16a2D{rh6(dvUP@9YyDr5uy@hg{Zddh@YfoJ} zGIH%G<%XdmPkd7ZJE4yMb34JkdUsys4$tEjmElF5=7)Eg?7oP#ExIckfK~d9TCBu4XDGaUa7Ts7}cZE zc`B8lM`2$#RvWC^zQn5OJn|s|FL^dKl}b(RnM|c7RIr+|TJgPr8gu-3;LzRbZ9Sdo4w1kmZED{et zs@A@P%r*tdZU5FS2?3Jo;yHx?=GxF<9x~2x%EK)NAlxE7JGFs9bf<~$OtGB=8k~dyOGl>poP01@?O? zaEOW(l!QjOU*T!r2hc(C#-Y0@39W>asqcU)OilCSiXTzbqZM{WtMUdFek2=HC(^eo zSk*!ul##VU4AmD%oWx?1dAzOsUtDs4&N$#RD#PB>8%=x5I*0XMM~W zy0~Tf-;>e)X$v_J>#)|Dj;#O! zX73+*HTF}7D;8*X)J^h42TGXJc0RGxG;@*@Z5|Fu!je8;7p65XQEjtrlzQp;aWVT3 zWN!!^xWMP4PTevAvoo2{RM-=wD!-Fm4qLj={${{u<5=@#M{sO`NlsrU*%cCa(3;UE z?_-tjWSJ^(+FY7Q6eU7=+EHsxV-W_NRj3Df&2hI9@C+w7Dt!qj)X42eSE9Q%ghyep zC4+#awcS2+4+%d&1ax2Eq+CFuvHs(WTWUFp)#|_zNk1q%YazdGJ?Pl@v3HPTgW8=@ zY$KTZ4+Ao%H0$=;?GydB+VLBw>~?-iw8UA_ZzcQRQ7W*3zFfDW62_Y($se)JxKWd_ z-&Q*}eQQms*y#}S+g~EivVH@Yg9>%vGH&PCqec%7NCdhUwDd}9KM=7PgKin5V41>R z*;%_c&*#e{jT#lyqlmBsJL;Ak;q^bBHjhg2FBaHA#m9LaNDf9|hDDCqMkS{|@{!)c zA<$m9`(#NVzz6HYTWcwMrRRJBFieMLt^t}Gp^T{-$bNRnhv0rB*cPrvj7 z>j`KL1tAA8CySCgv_*Lpltp1>Qdr5Sv~4w&T}Z`uu)zjok2L>nK~n==0G~tE02EJj zErFM(8^F;<$T!dpz-|l1-TCpVK;u9YK-Gh+AI;-;H*qoC(e@6QOpB_|wZODUb9>!T z3r=kUorE{C{nMVi0(@PWt*I-v?;7*9A-GJ-4Oj5a=-bucWLg5A^|_Y_huN`=+egBC z<8guU7kT||?@stMb~iYg;``?Fp8|~nj>&un>x5bUkOH4K_3{)^+-?%c&ePva+OBs-{WPh|(A z14)gRHl_zlK+7)`are3|YFPGGCo%0?QI>hTD{7t{&FqMzOs2q(Gx9Y#lp?UTQo^Mk z?_#X|(OYq@NX}c+xj~*NNDKmh&+r{M4WWTLYrF(I(DV#}x$MrWsA(qmCDkouYXHw0 z&>tAxg*IIQr|A1tJu+G$(O;w-XbA*n{i9 z^jiR$D%4Xwx)bhPHjm_zC1=33({XumK+P6YbTh3gBRKb%4fVGNq7?mVQH=-9YFs-V zn@?;l_CnE1VyjBL$ra+@>MHgcehWH!Mo^DB6-R!JH?OO~Pupss;e}RhXv$05UrDyc z4Yi>e#zP~hIjoSh8iHEP;wp#*sV5PbE#Vei~ZBukvQ1!(a^8fh|~F z_x2&2g?taW8FH4Rb1MQaD)quViosI?FppA&=7uWRh{aQNv!Vm4^^;_mX0b+$%8|ZL z`=1o5#aJfUKKbct_1RzgnQPtQ>UhZKi)4docaC`#AM-oMO34o)#p^8+SLGOMT@w#i z-F|gViQ}v6Q~zkZeC?NhsTDU=mlg^oSP(Qtg8Dyk3>Qx8H0+#orE zy6>Un;QFxac8n7$)dUlH7}sa27nZ} zFtC4WRH{#}h^Yry1U>06S(oHT#rsSkVzY$;`Yd9AXvSIibKdlrh%yYh-EVg&H07Xk z;+NH59$Q(F@h|A&NN_9K$~W_}2VZqD3B~sl5N33@53>&LaVd`Lkt-KhUY-o*?>D~? zDlV25zq+=!S!ym&-El%?`wJgjM4Gx8)%6V8Z1dQ~-cnflELz)}H?<7wP92j1RjQ(+ z9asR`S0Hd2w!H#*66fKP!LHHh4&%e37I;}6;X z2Q5G!dbpMAc~#a#h3g({eg^iJtFNrtoqrbbarf>ve-raBu(;+R6ht+w*#EHoIFR76 zkDvIFcjT%A3xqY7TFUdXVms3xXq|Y|j+71){dOuxL3Od8!2M|q-llTrF)SM2X&jTn zw+|(#n?|GkB+hOx;(>=yae>0D72X*YMZya>J;aTDGr5nK+{-1|MH|j&zG+cDJ-I;C z74hYg?G@R@kQ}zSnCB7A)^$VR_d^j`=LTTW7+0Uw?Oo2GKyrsQI+^3u1NWgbZh263n%N_6j&>%n}p-ec`sygA3JtcNK=)i*bcG&TIEo_q`tdwCwH&*c@j| ztadVVt9rt9;(Yj&S;pbPlkO9T(Ec$z8huxXSMw@s?8p`JpXx%aibS4qs5_r*& zrk8`$?0*X#hrOtIVLZ&5MIfIhz=`cV+?^16@OeZQb>@67xPV!5j(A&l`u}v* zyIGvsUHpi(>c`KHtMvjIoQ0o3tNa;{{Xbp^e)?#_X7>=bq8j?~lx%KqirLYa6#Wa3 zB&?{4%~`a0y(x#CrSPV$Xmcv6UxXTCUkRCJ)1)6N50^j=1X32vouwno4&g)8wXj3g z;Cm2SDxLbm*5+#epSZH}#gBK1;L+Yv!=2qV4`2^`X|%hpf48OPa6e38UXVMF80O9n zbLQ$|OVtXr;mpmp6)bB3+Mi$()%F_!+e*(`^uuOtwsQu6t3J0gY+~3H-b}egI=rsq!4WLuOvh0R|r%4h@yE zNV;t35S~I;0svqiUxV_pii2a7y$&qs5P0Hu1QUD^>-KU{!uHZBpF>|`qu@S1aG|PT zfGV)^CvCSSeR*uVKC3*M@n$ewUq|8uFj-9D_Kl^Iqem}E02T_?;l;9F>4_p3MqM6Ql# z)egRk4#&JP2(>LOL$9E|-vt$wV4*}2phdrUAp_3+#4roF^?Ti<`@t8>+p_&C-YNg=pOBjEBa*?g7AGT`q_R^$EtRk@1OMW&jGXc_A*V-b$9$LoO>_390Y?o z_uaq{7%25YLiW~mPRF7F7|#Fx24g)IGb<>O^TZ9oZTbyRn^rI;dX8}x(?ewlF%_(a z%YN3FLiQwGp<_jWH9^FIiM9gvTuskWU36INc+4nrBTd5sEQ1=^z=$DN+pA?ZwccUJ zOQiZQE?WI_n9<(&(FrRoQQ)8W9j$-)a`fJ1C4(?eJNr_HhYVW#Eqp_a%lYf&X@2*y z%~judc(LZe9tcDxxm8m25Vt*FefeJQYM`)~8RXv~2n3D?>)GW?r?&rDPGl1@x=duA zl#V;x8RkcZE;aofsz(v$)qzV?dg+{~-1|F+ zx z5gh0g9S~r4D{v9+f7+MuhdmQd;lRr8E7U3z6Thlaj6;K(KNk1p5Pa&B0!~+4Db5)F zP$2B}=k^svXrC4j7iOB_c+Q7!FX473`l1_OFw@woe2%eli@NDR!b(DM(v`9DEqI=AS|t_Mu1}4VYmnqgK?^*O{6$qlmGdr-|_b zQhE++R^e~fd0Zyd&au!y!43s-C)F$P1!AT=+_qjqxB$d3m4dqHFLCy*ItBc8CG+9g}{n4mDRw#VQX7}10X&Z9| z+>+bnaj@&)lJ*Z*6PflOQ$%OG6=#~)gGRDJWF7^=RVAXhgW;KwJNX;QSjLkopeVn( z_bx@RYf(+3j~TTPYkv{8BYNH#a=hUX6!2jnGyR zU1Z4TPpRxfm@XwJimuq8aBaR$&jXagEfSFHbJ?czshRMm!-GV#YmTHJ?ztDW}6Pg#)QW!?vlD6>rddYh3sje~toi z(cB3~23yAa-LIP0L`O(m)R#z%75uU{Xm@_^{aIIHZK2Vbd-6L?$a}!4nG0qhoF49>&2Ra}RDb??1t@X^c3kCETNoN}*G+lq* z{|{=r9gdUvp?%MHs@1oyE7%rq8y-vF0KlIH-Nuj4&-@8@csm|g417KSU9>+C=9C+edg$l9#Mx2 zt%Wmt7pAnzg%s{D* zeQ!PFW)>{>Yu$iCP2~NB8QZNBH%;Kg*?VT;&{Q`6^U1L>4th4L@;SNk@v!4!>Rr(! zzT(c$6x@za;~OKDYz^??q{^no7mh7(*eB*Evf1mz)coCtF)JqbW*aYlhXu*Xe2+mfHUY9(1F5V9bta=~p{Q z6KRhVDJU-4W%I?HXxEOEOedZ@?Wv#m2zFNNx8Hm0F6FKgK4_QhHn+zoJDCIJ8*C1+ zSOgl=$J%$Z$71jG;&VjdBz%95XZcW3rXhx1Zg!ZNRbi0;2ZK?f23{s2C&Wsk^NmCDqrSs9#i z4Snl1Me!Czqflm&w6}5 zkE*7M_=3l~Zd8qpVoFtJfg@s7UDzp2V?V;}PhxxR0zDw4s1uYyNAT~Undoz1UE~ZX zS7s3uRTw;t3rqMhd>))wo!L|y?oSp|uXd{l99h~vng5I2l7`3k53;X!PKyZzlT%(1 zvg@?&WOOEldIh;|G@~*(DV!!s)o7jS%IrgB5>)X8A12fz)d6M~tWiN%>#Y3QRPpa^ z%4a!xs{k!E`50k%{j3VKNx}RXpdF7?LhHwzxpz~-ORK?;9Wky0jMay6rx3(5gvBS) zs_~n^8E`@(b>HgisGTBkR#)rmOV0Z(>?nyYc3RICQ=e59&n_3GCYBKp{JGchv7Y5^ zfJ{@x^cjF-viUV;@ZMM0pb?@iPHF^<883vYKeN~in0#~52*+DZgLEyNrB$5CAfvdl zNOySa61>N2mpFcDb9JseMYZ7JG}wM^C(W5(J4bJmR4MxA;AI+@(uHV9+#x|{6Qfnz zo6RPqM}$u`@q7>f04*K{kcM%|;5waZLiTm8cNB89wm%rd!@wG3C0KzaF&W%4>_rVjS_+2Zugn6J|RAUz20cBrT|Rbzte);XXjth!Kn!PUlDH;jsZRK>#M{a*#^*udRN@V z=;FKLj*$D~#+?b-RpM@(V7)rrUE?(1`*ZHb& z_uSC)#vRxb9Co|nE_Rtcdx;bMj~#acva7`%Dn4Hw-I*K*S{-=pCU`HY6=YU3<(gSy zG^DZOo>Vhpy~JWUn_X{1G1ACp11{r-^MfDL+`hH6)LL9zURv5dH!%?QF6Pq3;STenLwn$S zzQ4A%v9`AT>NE+`x`hlZK^Ck*ni`@SXh=t(L{`#IM3yg32B<1L6N93x<_;m$ld>;5 zc^MH@$v`e68%maxyTWnwuSsVj8VoP#S~Q(uHtM@djU(l9;+kW{d?bprU*{dkuRerN zvPNkxe3wE^Z>pJe6fMQC9nm70bo&DD%IbGttHpykCoUF^+?j0u$3r%JQpoSmL2haR z@-&AWN*`%ZRK*vX2mL~ta&2HjAWPx zp9!AVxNQi!C2Stp+I$w-BxZ5qkU4<`z$i4@o2toh)NTNNuixQzgj|xNN?MEG>rw)H zkRpvw<`1eg8~coyNPDBO?+97dU`>9;6VN?&hcD7CWhH- zk}2rnxZ(CK`8*rCBkW5-UGew~<7n|{N~@=rm8i#Ok0C<Q>Z8~obBk-`qdH;}Er z)LC~LC(hNF=fED{jM(*KXft;Y(uGhYieW)zl41!jw9~QIsZThuDd6rPI{=$1-#3-A z6F$r`vS?)~&r^)aqydcwpT@V4Aqxf}k&X+wyiO^ysE^EFtEU;Ri^z9e3FZ&lm1G8i zX_qahB1Od&twvo+F_H=@x<8yz$vRynBej|d`*o%LhpJ0*dtq>NM*Ti}NS3m}Xdvbf z9FK-VBcae?&Fgmt?E$Y8v;}J7wIg0w4^&$!9*BlAvK+K~3Qnh=wOk===`0VA+dp(FGrVATyOhs|<0t7qED?Oq z1IA6(;LT)*A}FtcP%|D%Eu)<*&QVm~kY}50(Qw{>##i(G7H((mcN#xhaeR=$kzFNA z0JL#ji%c6|XB$`xJ7#~3ml~xgiP=aVsZ0E?Qq$<1p5cG6DylfhDCMcZU#|ohDWZB* zmB@%F$!ToCH0+D?i|qz#vRg_kJFU)+NAv07BlsK6)(}e^PF&AbXgCwg6atcA3$diAcp~tz z!TuijaDfM2H*|ux#k4g2dI6p-9QttWfKScVU`LHg#MI?Nr5t2PMgxa|p{;(9W>1{RRt<;U=7}-p^lPE8p2!t$ zE94S-IE0eCjJ1C&qi0!J&uC2na)VbQ7#=$oURVep`?wEDH#YlyZ*#fcb{{x`%kR6z z=5Tv`PRZ%8;|JTr>GL8py&=0!o^;8`HsSm6>k!j^9lZMR&~bP{hnz_Lhwn=e08GZJ zW)VQWmdAW)$~wZ|Dby02Sr!IlT6i$&N{zZu%PJ%u9qh%*@?;x)y^p0*$M|~JvY>-B z=s-=)`Xg@TwZ~)ojR}w2=B=bB?2ch&RM93v0p!MoLbpssj-DBFFx~xowCn}gYWf!2 z7Um@IkH&C37jSBGg;60XGAw3ezCFK=!wZ)a zdkW{@5=?w{B+ld_zLOTujJnNwz=b0O5aV+pS3Y7kjXI~?rv++zfX3->KCX!q^aC%mP`ha~4& zr_^eJJw!kHREH74pCL9J1FgGOPPMtVD zgJ(LpL@XS&#Ix|&wWt%6h_J51zKVX4?bWZi&;+%Mv@EYVy=Hq^dsEdQyjf^!|CuNw zEn?Pb9HKh~m`PKtGJ@4}6(NA$mfTBu`7uSw7>H_a6z;{@n$W)b5-mi?A#LZ2vit{MlGCfDxrY1mfqS((0Nxr z>3j*em&IKxy+x1y_jG%6+Fg%WLR zFckZi+@zM_a(>-J>Wb|l*66U4R&R3B=O##L5eU;ZN9-J5n_Kddto#Dn7a>pu!832} z40PobI|H!Q&Cn!C?bKUBNC2wKL4eR?t27JaEByaC-H))vOm5HJC`%?#wT6f(R2+D1 z=*Z&HVDRYTk$ouWgF-Yg9<<*d@H6$i@4#%R#qoB5Dhz~uYI$m^T%MdPLt?;Zx12>H zLnMupo=Sy)$9K*m(644uFU(HjNU{#hK`@Kc=ov$WbY-&TZyqonaXWu&2cXUKX#V73 z+nu1n=Z4ld{ejY8sD)fcv}OmL)rJlT+@f+d0HzWy;%uV6;#8A^i0?8z;5dr^1>_eP zPk6oU)i1DsPdX>D()QMGMsrPa_@XiUcze_4I1x-i$yb2mw-0XoCTw^DR^B6qpDTS3 zasXjOfwTx_-gONV>C#PDr^t0GNWrimWUs`Qk?etq+qd^VX|`;-1z^Gp_#A3td4~ol z-M#C^sY}ulmqc`l?^`m1(}H){*X4k$Np`OtpdDW}z90@pE`{vh3gm_(90g$DJ2uCE zV9nQe0MB%-3t5h2(In^-Q9&gEA35_mU*X%@f)(O7P93Os6#Xc0I-~LOP~gd|;l%28 z*bN7-MbKW_w%$+4e!hWfCQ;fP*AHH3>?KQIAiC5M0KhG_Bt;1B$4gzAQWLkT59*D_ zDe(g@0dOu`&Il^))gMl-Z*PZZG&ca2JnWooZyrJM%0VsgIw1)pXOaauhMi3vUa8Hm@&X?n1^cVD6^Ohz$tgx_d%fnBZ1_mBdEG`xyQ& z@)O}gXWGp*gXG4R4H9HkoB}k}O>Umy>rX+KEoe|tV4Gsjp_B?ac^+YZX5a}w1XaX) z@Om@EuGr}l#B_|FGf=I9m1i`c=YfYB?M=HYKX;rHBGifv;~aw3#xjmqSm8%BrqI4A!(@5Yn@znUX>XmP=rv2MmmE zxxVbceFR#0C8wh7k2*~XH+Tpv(e=MvWc$@8pKSkZa%5Z`XD=!xaaJ|8&(_)N@QT*n zEKzBno@ucG1V0yj46cAy z`VukuhT2LithaUgAdQT!@k5ZW>4XpmZnlqMKTXu!VC zYz}-M2{B+E%MYaL8>C$}ws*2*) zw51}k#vrgbT z_Cp;uibmHde?r(1g_({bzc^1I9V0TG!osdz($w%H(pRUZw5+5DXNsK;r9cf-j8r&^ zb3Z?toQdE-sb#08vKh_q)zw5{=0b0yQb8NyOp~~jM|r)I6pBdLqRy$71!lIsg`KLq zgWNLEK=l@W&^_W*TGkYh=)>O zI5HA|MX5kmEkb2!ehzMoJp7^T$xr(C2S1%+zuEqLvJ~_O0+X@AOp&=IDJ3h?Bm0Y= z4DJs;o@(Fy!D1@n^G5ZVLaMkXDRN4Zej4#OPSBO`ook@xJg)&g1YaRK4nhvIvJ&^P z>2k%c8x+06g)}JWtaM6~K;u7%hyl>C6}b9PiEoUieq?*A2@ zN#+z$z-q{^1hr7q=SP8`kQP)vjWh$*xZCAIj%^j>7}XD$Rjjav;CjRZ1&r{au&aZS zt5jDG;rTUodFYn7!qwF|Wb6vq$6>J|wZCHO2=MO)k>6$FOV7apCn|#4L3rX9tF1F0 z0$FLk?f&+6lMMuO*w`J_hbUC$OVxH8I?9m8Gn#~x*F^FB!LgTb07=cy-p`WBMnFNl zkAdd~kmwjqGLI~o*bTqD=L`|}gI(=v@z<*dTsa=SLNmDnTv}=ZhgHa%&lgriV02~A zD~HwSkw&jz^|#8&)}DTI&z?57G(|z7%_2wuK@jqedphUSzeRhRyCISI8kn0u&dzSz z*Nrq1!Gx>wb%Bx0wT;uYL5$DhdvAsnU>MpsQ6}uZg2|W=!T+q(fh=-GBHs(K2!pIa zh9}s8E2_6IJ%s`G%7ZYfG(%(9F?#W)q$fjz}V&s#7 z*Pgqp-!CF)kjA39i24UOTKa}7V0x&%g;+8;>pM;v_LijI#9GVtD53r#ctE~pjl7-= z*g6B-G1-gfPNAj5&sf8Q1iE~g?2Zs&povkOvr?(M!H?yNiXxKb_FshKBT4r2?caa0 zl|AQ4mO#K`qsjJ1*?!R3Ib4V4Ai}BL(D%$5EQp>W5dr}%1!D8~m32oN!S*%jL(NvQv_zq|Xra(-Zpc;FQYqP5 zG@5RIwegt9jR#6d7Q`MSd!Mk>bBiv-Q~(0~PpEzXjbbho92{Ktq<{?aMCQ8TJzQt4R0`SC?!RuzY zWxhj9GJJ@%A+_0F+7 z$Ieb%UvRok?OV8e0$r_dy}L1!E=~T@s8p3xH%O!DVP_*f)0ilKPc<~VJ!$vcde``! zXe=bvZ<|=SRW{@oJ+Lr+YR)N*W``x?hUsf2OK-#_$`h|19+j&Swm0dR&oY9aYzf2A zZL1=g?aIJK>>~w1BJ7Z$k$J%i{^nJwX)( zp)m!J1zjd?P4XZqPj-|)s2AXrhP#%vRSW%y=RL z?hhU&ajIoN(wf}2=N?s(*l6&&=5>Jp?)GQKGx)0^kul=)p}q!%-61pOo%w^a!C;VF zmZhnw5?q$}+!%c(;^VwQz?Fcfnfq6_!NvC|GU*Y_cV)1tYJ2rzo9l{z3%Jj1FbCTa zK&(}l50YmUXQ9aX=BXV>3)aC$5OXK;6e$IjeWQI(s-fx#+$tVU>_^0Y^`5=2LW23n zm8zG0B-Kb9rYs6w-S_%CjQ8D*boE#5{WwnEE}snGRG}!XZ6i?}B;*Wm1zoc9Is~xL zL7|{LUy4WFGW3(kUC5rV-Z1gDEC(Q~;f1PN-2%p5ygD~=?vC*rvaCVr^RL>QtyJ-% zuzQ17nYy-B34y9;ffA(g5 zAf)Rd<_YQTA6&vutJOPhdlP`*Z5MqAp^b<*qkZYdT!|i6utz4rMfM{)^B4+m+{rta z70PqC5l4cc1i}NylM~WgyQA6#WIvNDl5k0?C zkXq$VyB$HK(YXB>EES9@DIncuAt<3He9AxPZXNPQ(vxpZ`A_+OPLhtHR^=gII6XOe zC^VT4|Hbxbwq<=pkB5Ws^vL139(6c!PJ`iqaFU6H6V-tIhb7;OIc0^P-9|Q9 ze=6l);)M0mpe|*#sj1@3;?z`OCJ>V{+8_90%;&MW>Mx$>+RQ272s(bxfhRlaEd+Dwi*L0sx%Mz}Lul#`TH5X1Lik&Uk!wL^Ro>OeL#1NKUzGa!T=hRDA4fDmr%BY`3FFYp>f<;UZMH}jaGv#A;t1Fb0oFlN2SE@YPGS^T6zE}C6+!QeA8+2O-FD^ip<50 zE=M;=Yum(>S3nsV9!tdPjm+mXd7RyPB->0y8QK%%I`vb@v@Tdf#>Gk<5L@OVUT~yz@xkadhr|&gf6AKeA!*$)g*8!K9vneYFA<^e>GV&q_0o33ji5*~| zD2GWEv(^KY;pHKn2iO{FO(52=v4ILTM`vcfE&lzfFRDd-aHqUdih5Pm8iIjW|;0L567if}m2pG~=38 zO34P5FliKLBIfgiqnJuhr;M@EFh~^jil>K*X?b4-g_LVW1G{eKQ`R%TJ6S^R#V~ZI zqY+--12Q|-bdwEnIft;h54GT^uPi5EsI-EjEy@=E6^p>>f3IK6@{g_4IWEG-`Mr3! z#-q-KTMmKhY=}NXxqQ}-cmCpMFnUS4u)Uw$c ztlkZ0NWu>?QGGt?Ek17{Z+;Gcqq;bYfb7Q-T3NSMLNj4 zfCvst)+e-*nn}BdZc+B(;zY?43VF_Xl~9TL2fqJ}K1J~rT18(dKj{rDWhpNq8}gj+ zhJv_Lvc6!@cQNE+*ZGucRq@>~*K$rzDtH2&0tF2cTs-->M4BuOM>Mq^yj{T3r#1HB zy8%tI2fX!u$QWB19BbC<0(Udc#{>ZzFNm_lSPv z=>$YB2f8`V*MM^cPeg$kz=r$+vhtx^(}j^ehtucIrw^A8mBDuQjJ*DE`aGV# z9?xmH`1jX2|Fyn9E92nd-(J6%8CxW`_i-3Bn`4>U%1RB7JKuX+j9U`pVI^y`oXgeO z)925n5APYdZ~?;{zQ6|@*<;|z>kpe_3Z6d{5p0nUNf&qq*T>njH4-+dPF(wRy<%!y@jp@=lxMt3;Y>KRbrr#nxW^)M#3 z9pI(Xpw^hyDgyML6^7z&(bAfjXPtjb3`VWIY5A@+UO$wG=cDjv;8) zqP%%xoqWS>p?njLX8;KHI;|21m0wHHKj7)3|L&F6JIiE3&<|l}y)F<36W0I;925&K zS}+W~ZH)*wy$jh{uN7J^>kNso9TQNBgE7`+!N zv1PD)0wn8NV&4EB>>Kj}*4DvQw-O97#U6UDt>H*(Rs);jhE;K}jp6yRbouL3?p3)VOOR_Ls2boW;WB4Sfq8O3@%O{Z07 zY0mwNIIVhD?|c_OByV87NCy;G5HRtHg4y*f&&4go)V&7bNAUK3?9lm%VNJ}8&?4ag zvrd@q_X#J&+k0^WU7(AN46TcGl!-H!a6n_yGSEpzk#Xb55uoZM2ZpX4qP*~1DK`x^0)j;bIw^CI z-*~M>6;7N2oqmIg5zOu^3lhuaPAcY}*qzn@eRUqQ`CD?=HGS&t5AGpv^F2P1GIQjeHhHu$V^Z#?3|Ar_Y5%+-Me<1V?*VLYKH)N?_NVy=z9>~k62rfq7^zCRP(C6V zuKoP&H%Uf0kxEIq;l#*?d%ir9s2EZ{&%Y&xz~yl{J|_{QMP>C=XznHMdElBJ#kBEd z%;5o6CSN8_gsf9*Ms>1h)0%N}G6ZeDh{S<4dX=p~h;FpkQG!c}uP!d0>46BE9_5VV zeI$^t@=rWBw77^sYQ)9hwYY-R;-1g@pzvMdZ_%4^l7)pH^C`#)E?A~``6m%ThJX_! zq(Dfaas;N9iqIXnI;b|lPkCIyaE-L${gY5dn`zX2;komVdYtam^zh7$!S;7st@dps zj0pX5g&A0J%50$Wi-Zg)7etqI;L!^+^UybD84N+lj7D*vW))=|K{d>{1h5wu*Puph z;B{`l7T0XCM}Y4l6|Q7ZL+RHvhd|$_kQo`KLzuBGOQI;U%dJvmOr%JeSTq%i@^Zk@ zP%0XW7G_`?%xIH3zn?73ut(5tez=;irV&Mt@-1mR98TW}6W?$+<__qY?4+i90xuaeKk*g40F6Q|$S9bs1D`YVY@hKb#?95nB3oQ+Xp2DUMzguHw6?Ym z{1S`6H6S00ngKHL7bs@n@A51e!GJd81finjnQOxjTwg`~04g7V6~9!aHFeSj*b{6K zSF!Tpq3I#+7T-fqV!edDM252^xF0WF`p;6jjGn>e^dDClj;p5ej&i!3#$Tk-7<{d| zc`d4@;)FenLjT3JO1M`0IesmaY+E$$>A93SrxlJD%9o}&k*1Y%((-d^V8y97OfEDR zku$%J-1!!3py=wlw%Rz`1B<28k}VbXfP&hAV@5}9V)8u9*Qvlk4*nvhRzH?5W!nE% z&XgX{r=!EJe{u~+)A{k6C)nb|&9LayFx4{tzNmPMs#^3a20TLe+ctNyKmd=kwGIy9 zB<7}(N+~C-aGQKE=E7k6X_#wiKvrz8@)}&M*&Xd68i_^}qtTLK-MCJ)0;&;t7uYLx zm?5EL*I;;@N>j2Yh?UKE{wGg=bBOH{K21nbncFkd8d7{_UPZmqj1K3NQ>Wp z&{4ea{>70S(?!Qye|colqN_)--$m><>Pr;J{W=?=Ky3KFXCthdOedEwH5Nw?RS!)p zO)N2Z)T_(wP0-jfgLjL51bvczLDv!ViM6y-TsM#GX7#;)yXT#&An^4nDaZ`OjT|d= ziIb@5%O>B7_&#NsU^Nk}LKM-VaWPPC_}ccTamx=6~5-=vlLSufD0HMfDf{0_2c78US}w&?|<1dgv`fzcBRPq2Cx<8+u~sDT1HQ zUQ+?SqDSO>+XpFa(Clh+kU%j%F}unDI@GW5HRlz6jy=uGnrpn;xys2y?Y`m}h|~7t zKMAD1iBP(43t8S72)jLTk0;_s$~-9PE`P*>=k9O-X##lO{_V?r;A?SSj$Meny!}W+ zJm&Xt$>-j>W^P~Z5EgBO*6h!=knPP8LDrEn?ID+3zRKssI<|`uCc7u60?yo7W~9=o z6)<~^S0Um&bW@Ze5@O8va9q1#PA-64M4TT*rb1(dnUpdBRYVBz5;`JCg8eS4;K%KD z)%f|=cx$}+-uBnoA_P%UCvfGf4o3pn)_C{P@kdA1_cnAx562TI<)@%3pydMl0mgJ- zOwmS~#;WUD6yw4J0U0LOKcpS;7)-_W#y^$Bz~idZ^{o{ad!RGu3Z*UK?MJ_wvb!<1 z>UdAD1>q8C9x5HB_@E}p90=La{_6%(t+74y1PaxC*<;ma@ znSc-1Om$#O*u!wH{hB1H_w3m>iL(NK;QAC@^oR@M_=+K7ih{xGsyYuCYKVZLVlX&+ zF#k>n!1P&I!=DYuz3jBHK2;I{Mi)dB5^zRhg9Up8F4+Bju-6B`H3>r^Z{WPkd@R^K z+aP>OdMR5>quTh^$(W!wwt!d(KKoj~_ZO9fm`Xx8!7@~lFX z-;c7WqU5C&+zSFjF&*JB=jSsaxcdsRTyTtX$0yqPOp}mDow(x4rchkoE&hE88&&c9 z@5TC1Nec1rqzDvbDqkdiR~3cO#JxtJ9rS1IGddc4Fg8I<>~o<-=$Pe-J3J+%#`gNl zl9KdpNm^ai;3t6`Z+g)Xw$lC%dB@ypi&QzFNw~zt7}RbPul0@6S4s!6BE~^I5o*mq zF3;W}dy2xog%7KJ5D*~9t#@?PgXMiqaEA(G0HIX{G+=|YWHx@hJcar4*;2m(k&!}r z9Z3zmz8D}N4-(70jf=W1NW4&>4k3WwP`jS1Uw~dUU4~Z(;%WD~F%ky{To*PsWmX$- zWmQ|f$340A+VVTv8?in7;@xZS3NuA6Abq+YX0$y;1A{Fv@4rfzw_lmV{M%cv&0)T= z2j-`NXD0<$IAJOTJB0ZWau^P5(wVIAv@-jtg;@TE_|rfq^a?_@;(c4r-oT6LJn;St z!i(AdJzuEUT|;qg3icD%rXXu7L9xTtfB&9UP3>M@5tqM#8SjvLu1{6N%(WzXrBXwK z){<(_QPBPtWN)l)#q?2<<;D8Z^{6f2pzE2mvE_;!$zSffCdV+^r1o4>Lvr1qYnm|P zn*6-nO3WJ#+8W#8#fyzbKg>Y-&h!i&Z_o$=_HARB@QXnNUjBsRd6zlJuoWWSmgr{- zzW*dMj!+Ex%S>#Yi6b*HVZGg1QyMEq1(SB3&km#U`8;V|aLagnR$AYHg6FMZJRuDr zr50_eaK;vpxvIkyh*)gQi#z!76qc&FGQ5b0nWz=MoDC1#ymG8)&xErjM0J!C9^ZIo zHXiZS$w0}nk&H)jSF+m)&`zZInT~hE7{>zIJ(NTh; zo3J(m#ry!{7vSIiJD?c#PrbHq(v??af65=pX%BEVeL~|6xQ`BUw)@ zOJ4>(3zJLB#NRB+NTDEmhr%rM^&!1XfgAC%E&k!C=p`_Jq6Hf z4pHWmVFB_qX%m)m6a}`3u~Lsz2x8Xocu#vvrBaRvhNw&p4gYKM0SmbIB>(L;M>3jY zw59i-meg8j+2v@u{q^KaZ|@LE>^;f$*KV61$!eC2^#!&L6I=#i`quz1O6i8VjZ|NR zee)BSf?-iZls(KkNfReWwXVrZ@*E$d0dzP)XH(Pln=?}G6L;j=!12sEah2^x-hz9gw>OMHE^XM+( zU1ASWx`HSf1t|`EopuXSB9U8z>V?jNjzOrD2OWy+b3gMazxn~Rsk68Lo57Ut|4J#W zukg`JKWz?TJ4o&6&cPA$E3tH?{e8r3nY!90=0hi-70O7u8i_7+d!E6J5N6@IzM_yu zxVKtx4v;T#_qax;p%Js7;SIP^8r&s^&_)ETabR&KBe!8zMIsmO;3DE4DJ$+0wmYgc z0esa6EETmBs(RE=Z90uyh3oX$2HMfUIk8l&cpb5r!&|v2Tk&||tr{{G7pselE7-KW ztS=~g9pe)XSa?GM0Tv&(3I;F%8jL}_Pfi=2Zi4?X8R7?_o!n}Ohvt6-$>BxB-8IQH z&P%W_E_N{laQKgP-hCYVPUqGY-d=*yj-#w75miaTKfDbGnbWdkaIuj@N8H#)J^8?2 z`=w;b<6ZT7z7g`Yzlt_wiAdy@>D2V(Olo=@|5+>K_Ph~+v+G{!G~xZ!&v^2mjm9I9 zc=VvAXbDwO>1MhC1UwX+ScMEjDf>G>1crcG@s%rt>xYd%F_677;MyPhIW&?S0HKw3 zcM0w^ascHxlyk%l2Ss{9C*y&r&d@2Ix_ueA024ZI zaCpEu0bPZ_WPe_oC|c3604y19KXEBw|MK6r+trPY)X{raS6813+gEo04yA?&urd9T z(V&LDq?2s$rnb?3-H+P_xSkf(iK28iPleKzOG;c-FSYL97tf!hWIER3r;+Ou?Mu^< zMjR?E@gHvIT7!*6fz&_=$zv1}OyOK2mbL| zfu)XAWHqv^sj8atXHeo-FTxZvs*AwY0dqD1|R?+8^ScT zQIPsU9DpMFB46%+Nu3oam5rR~gTc~U94;*Oa51%*Dh^M7`f>oOu=ow|>ND6{!led4a&(Ez3s5W}=ck0@a zyQQ#%Se39(DpgAo2Ls~c76gu5n?Svxl;jIb#WQD$Qn&{m4X!LuqcGTQTSYnuF?KI7 zg_=MufFy)l_^q*_{>8OvB^uBKP9rp;oOtmaVj6?i`Cn%VHeUx)6OA0HE8Gpo-MK$t z-(>H@PC`Nu1<}wAyWTvbR=jC+sQdMe6M?m%|>aZO( zW)&5lS@0=fo5JiUkb)AyhZr*Ita>5T_Q8&H0lP?X5sbCtLTAf84I9GLkzkqHHtj>_ zRSE&(*;U<|B2>kMihiK@nfL@gwm}J4M7B?n`<_LVy_HR8Z3tqZwH*A36tMXV_aUAYVtLKJ5D9C=DDPWlbFK?H?N7 z`-51V=9FUu_Gc_G{|eK2Soy6{no(wyN?l;1Le3$2_VE&E!bfy1k|=LO@%sA+qrK;U z?AxRIpaDR8bxi=x1PBzKSFCoe1%J+Z1Pf|a}n0@p^ zk5Z}Xe6RDJ$N!uY|4l@e8TniCKh=Hy3>}QKrAY^%A2r0K_VFuyl|PPkuP$ICVtm7}3!WS}3rOjk2i}5#2TS8PIgFxLA&j30t3_|@ zc!gk7s+0vR=H@H^6abj8a(b|K@|g_H0R~36M{$rsPWbG`23znjg~U0$?)%YE#OYpl z;LuCx$XqrSH=+?Ugw6`wq^i^|&$i4&GKW4I8OmkHX1$o9g=6w57BIpLA6O_5J~)#9 zL~iCV`X5#7$Io4SRze?YR1*H^0Ti@9FnWl5TeD-?+|Wqgz{L`#W#dATh^pQcKwqMg zJiZY_Z2myl2mls*6Btg+3(5CIB~y!!QC5J1hi9_oi|59_ZCad~M4a<+(U%r^_eu^{ z1GYw3)aw9%G{8OyzewhwVjhsQUOo2nP_mQ5-20E>cmq!i^$W89?0G2I$$uy6vTs7F zdiRKN>pHFrKoSB`$)t@Pu8u@R6ATNK3_HLmQI28u5?$zgzXbd>BTaUQ!w|}~3X*~S ztK|8g?bm@HI&%E@GF9D1aroLYu}ESB;FHH_KLu2^*M^>J+hNOsdQoV;Nx)%#@sPeo zU#0z1&}?uyAJzxB0?BC1!T$d41rZy>Ub^S6_*eZ+5OocI`GfD2?h#jPlDR?U7yk}j zm-evUbt#1_pR-&;C9x85xu6wY!Cj5KD=Kw9$C`dl-Cy0)`D6d`Nb?8$U6tlXlV5!8 zo@bzFiPz88?j`#B?T1c9dxY@m!$8xeom3>MbI32nszms8moKyK^#u9r)R$u4U4{M4 z<<^Ft4;%FMWMO_upk%nQ0itOh$|8aaozR4LzKW}?Wy9W zE@S`>_YHt!k#7|MUzh>}4;N`g0^EB(4){0%@Ediff(+4pVHi6$fw>?`(z-+ec~V`; zY2HAbF2K~|K4R}u#s{1QSRwZJudsFH?YzrI1EzLGGXtYs6ClkH!HQRMS90t<7vxZK zI9g3t6&V%nZ}W%zuAjYuDhz6<*+wX;l{S@oZ!dCXD=t*=3kwT>eZedxnM6Wg0@hPl!2r2fJ=mA1kQj_RM`*tkA)GKwOk32Cb3RxNpeLis z2>#crE5LiU9lkSlu5c{>_+c2Y508`isY(gt>1SnSe*DI9{E@+Hp4}QcH8DRwaVpfo zJHZ=zuy{&N)zf2xWT4;%C!TngKs{h+MeHfC`qTQOD3)pb!NAUQA}piRs2*QsXv#`b ziMcu1mkb)}bBdCd?693`CM;cHfbAi|v?XxpE5Dj3T1lTgN9E~~K~4TuNy$rUDrUm4 zK7+QwLK%E}=geDOa(B_%cfaVV`)c69mUNVLtZh&|Q?ho9hK zf|(PiYyho=lLVyG>01=oh2hrxA{kmHA~q5ktwa;xIw}3%rSDFEW~G#@BI}lrZ{EZF z4o+xA6BmqH+$D>R8?QarYPHtZI%_U$41-l6vGn?s)=wTYkgR!_b$#Kx4tO^3wq!9N zsDW596r4g!yuY|8_GFz1W3_pt=JjIpwXm`p(pTFsOAxXS;2j{~yTG!lF*dlkI5=jY zDkbRsc9TN*|9y`h!Q&}Rhm!4d?REfWifKok#3vl)JzpQ3-?tIgU&94Z-4>paRuvdF zDDxXlYA9_4m~r!f6``I(ZI$Mc&^LPbsE}QRLc+l@u6iSGAw;{UX@6O7?Y$*P?jIvZR3Bv3M5Z;3Cml!Le`e( zCaX9K<25!Q2h&4FzlA>-Ec zZcF3y!g`H_9Y9`D@nGjlb8)eib0Op9Oa+nnJSIP<8-~76t*)@@lL|Kvb}kdi)CIgB zP}-|k0+52LINvML9qFI6nmkXMYfW3k=-P04EiQJ}78e=z+zxzH%k8CFjk>4X0f;q$ zVuv|TkE{GX#4r96`h!Y%T1a@q!!ChEn5~xxl!J^DP6N9_#z%#@IhzA}+w<9_ASd`0 z`NwPnn$Yn6&T0Pi=-q{Q{KUmO3LlpZH}rbr>5%D$9y2~l?>=fgLhoL%{hn#t@@;t2 zg3^`SKYUp{9k{!2$Hf!zc;VwA#|*s=Uv>@pa>zCLmt8~tOyZblM(gx#7ugOmce`yG z8n}S;Pm5$(>9+v}0Fa1B6gmd95%vM%-FWn9TQ(SJO-Nx$OdRjLt2{^8xNo)*gvDWd zXI(l2#(wQxcNN>F=?{iXGayS+Sg)A=fH`W`{Q+al@GFx4gl%U$J^UeheRrl!Pwfn9 zRZISNWl+2p?~owdF44UrzDmPx$tMS%9C!{ZSt1bxGh61xhFt`c;SH8C`BTXm4MD3?CWmcf7Rv#{g$Fu7 zb-}R$=*#$slCDGIqjPYe0oky7gpSdvv$!(97_U1GJsQS0et;}){JW?*F6Itqra4_r(gcVb9!j2m8`z$RX$5jh;vI9oY3Mz`Og>)lqyCENn49j*{4hDSz zzZ8*i3M__UDPS@y5K?446qTZCM1pAMNC+tP2clY9O-Z48OgC}cNK}>lk}ptIdG+yt zDFx&p3Y=dfvKDbMgXR!e@nO^zzK97#TneKGDV)sKkY};HfW{#A1eb}5-15J965Q27 z2$;5xuo6_CuD*o8K(TjYwqs>tMfwIDP1C|5O;c;OuG!X|cbYNXuxqO3XsV`%w6Jm+ z;=*Mm-1)8J$L+Xz(Tp>vU7jhoTbEm`78#7FVLfcQvEUumNE{&aA??T^y%dXsksH-J zg0b+HQ#${QWrNhE45i^mM@MzXOe9RF^H)_aXF=%dE+4qVs7kN~=ojL+DDn|?0T8zw zp{WU17}BOer}L&;g zwpKYgvb;QUG7;Us-}d_@XUO&A?!n@yZ@qux`T5SO*1Rx&|MBDZk6&oM-?a=cpfP{E zQi}x@V9!ocn}xWuifx`0n}Y+_@JwoaTzi}fW5&n7|IpLP;Ps&sWe5ZQ9^-B7dVwrj zsUak_T~YMrP)hvqcQ~3FT0-VBp~ULjo;Kq0c$%9u-1N8{&y0oQc;?X{349U{jlDny zVlj0Wwmor|##h)cvaiA|2$2O{38OSwl87H}&cp5RVPz|J!TSZNIdSvC%@fFrk6+U< z`M;5^IpskO2maer`);0?xOv~YW}4bh{d;=+wcn@5-~VL-#{5}eGB;TMNxT#+8C6@p z4O)g_TpehD7%1J~TD12Q)55BP=FRmq8LvPgJ@#bW{(9=ItKKtlKFmr=z))|F-#F2@ z7;6NW6iP%)L(91#ROF7CNl6a5SwH@3h_>1G?*vV)VV)ep-o7+(b8+gc7?s# z1@28=kSzA>X^aTsps4|1D8!|&+EU(P1lVWMDE!M((u}1cc(^$f)QBXIt2NMwU2LEc zWTqcEX*M(f8@DwUjb}C7BkX2<2AYOeJ+6WGBc91sKQeU${fB-SuRIMIss1uG?|IQw z(d;E^c7H5a(M}TUw#}@)8;pVU1V4nVjJUN*Z}hJ6EZj%+=H&S|o}bLQvLF9wuLVS2 zV9P)zOSPfYjsYz-&ooOfFHN4G#NQXUxAg`ZMKo%ml!Pz!x9H_lU!*pD@e&_a-o7uE znkD=ZPaqTI8u(zhoovs+|2@!BEJ6Iws5C!?fKueE3iAcFx9KyZ&+F zADt_cbsM7-)88?x5nFkx4s465akYZzUE_Hn1*Mhl5-QI^(4kdC7&XD!vhYG|V|m_e z_Y;_ohvFxOXXazgU{ts4P{#ZyOvs-HU9-zwuJ>5rWxT4FhBEoNeJ|)S%oO{~g8+8k z!M;G$T&h3xJ$e@W@2ihltU$!)(S4-S2|9K3DY9;C?@#iN9A@ZK>Q{&nepI`KwT~W< z6PFvHdH+I;qX0D$<`9vnJ_y1=ET82z!HXyH~y4$?B0qzh_tnPaEf9+ z4ek(`+A^_dBxa208b)Hga?k`1`I>WK%!xmpA7&4gBhlR)TCutgeu=*id zL~p59=!v)eD|}8lFpbfy$OHAZAJ3@OW-3SIlRI%q~y7@S9$e-98d^w{8q;QLFN0 zYP48pFV;RuZ$4C;6sxN@4+N~FNLdi~2yWoPAV~WI6FQt=m;;m_37Z4FT$tHA!YbPP z_StEG%A(3de#^_95f-0By4d(o)Jq+yeT%=eyyQ`cSz=xiJ#n}bU`E@6o?bB2YoUmT zUOc>okS#B_(!`@Mesyo6Hce@MiZE`VG_?)uqKCv54ew!=Gdi7P@0~AX<~rY=%M{kv z*!*?*%-mcC4jgI^SNGa@MOEtukWy9lqr5_~Qi4SvjtH+JXHjhCm$h$dAHMUD@ArM| zXr{mj@L9;5G?>q5BL9GMFqxDxh45{+srl^jZ+?^algJPm!W=H+9uS&%W=a`rQec8f zMCEBskST&fAB%FM$d;RyVOZzx1WOsTTl4U0M8kKUYs2)oIQ?d*u+gllW}`2?mDz)E z9R!z_f^Z=W+U%`wq|~t-+9k}}8AwYfkWKN1ftw&TVXrMg5^hlPV!|p*J(thXbID`lt92TN~T#d ztdL?=T_+q4XXEnVpd8=0D^!aQg@)p_&|OM+Wqu{x`4a+vw)x-u{D$8bQX)oZ#@3~P zMaX4K)$N&(6AcC4luG$y8Pm+f!k(5zKy^rWfHl-Z!b%p>JL^p}9jO;;P2TTRJ$99c zZbE_QRnXA9$!_CC7%XazZDzlu&6Wzh@fbe#RCcsv+uO>GUGrOAFrZ&H&C5@lt7DmB zBjv=?uz+O7-fYIG#@ItWc;IT_1D(r&c68@}fLc>H0nZp#vdA+iS0J=eY$91f`<3N{ zQczz*u5^m_Y_(v_?UulbsP9(cF2)0Eu3jc{B$8Sp$3IROp%1>J>MCw2B5&xH6dO$z zU&2IFf>Pmj;9SNS!d8jMGMuuC4=(qpPP~~07@xBNIu-Q6oz_K7s3;fV0>4ku)IEGH7#LY` z;0=^#8^EQaWN97IR364^mXv2C1VvUAnCQ!torvD?_))fU;O@_qq0oE``c3(7vR1Gb z9IDm+Je$S~86F|RCmmd0hbR6-5?}+OufmDlMkQn&65_5#tx1IbI^DI^qjr4-t~GlPk{{&MX89-PCe5pa zxj(&?a9GN^eG5!~2^mP?nU@_I#@y)!!onz36(j+yc<`923#51xX!McRd!6cH?7i=e zEmocPwwA=P)(AgC926(CxJoEk3-oWy;QqBSMI6L`;9?sww!9eI;NRYG(3iAbi0|Yv z8^`cH52<5hFcuO?h({N}T^oQQgF0}hO1V;kX$tSKd3i3oM8uURPfYL6pe~~I+zEc^ z6VC=lq@d5QnYGT}PVKvH-}z5{_|_3M#Ew!cDm7Dsl}Q>2JbQvub>cZobq6#1r%z0d z${}^+)?fJ0d3=e+TJ+gpvd_Z{L#5Cqc0T0aD!-owZFENA^?L)v9_A5T$@qZn)6zjVCjRy}uVBBxdo0ej{ zc#N@M427m|H4A2IIy9QK%v=9iF%1RWM~>yo4t~=i)rH8H8)oWCrXGfQd57wNQP~EbBds*A?~%5*3f;a<_GUm|==t zjil2NJ)QoydM2Z9`DX)k(r7lyPt)eNeW>ei<6qJ#l!R0$F?WK*H;}3pC1QX%X|R^k z*?_G9$#jsBiC$%v=G)!5Mzs4O+!NjKeX?n?zfE>W6Ip!nMNBX8OJfQKx6!Gx%bjKm z#<*c!lH3aEsh8<52ktMA~zQ5*h$yVd#+(^DOIOsTogQfgPt_%odEY(Li ziu+T7tM2_R+!CIi?p@aC%4_^$tleqT92D(b;Ffw9-xBuunORSm=ex%DUXHW5fEUR{ z6S*^p$`?-M55vJ6edKw5Eirz?|81?5HROeI4WUA)GV#ugW zfkJGcU2S(gl7xVq9(d!x0|Rg8?d@5ZrwPjm(Su;}Bw5G^WQ$=4lgLd5=0gkL7W-`q`_o*Kmue_w|sHM$RuTfVz8+ynwyA)Ekjau&(bVIHDWo-a8d_xj-gs!b|e}`)RhmyiSYH}{co#~64m=?1Vt z_ksdvXM$yDh)1xFWs*UmjAP!hHNV8diDKAv_uDVU0+vZ{075+Ce$VYZ3rqh?u>0To zePz&AzON*0cG4GQ;bJ0eT7lS0_I}r-H%xJy@4H97ti*77Ah_^-)lTAcd$7MmFJWpP zqM%mTMZnl7~@6yf&BxZU&2PBoZpsXI5ZvP5;Kgvv)CSlcfR|EZ5%z^c(`%+ zXl2+A=u@YrjIfzMk~hN!Uh4sSxYAk2dQl^0%Ayw_IbpEn6n?6ah@@K^w4rVww+^5| zkUhm)OP3;%CS~b}ZYUaj5L;gMRxYi!G$C3j&1Df;Ma#%R4zbulVUapL7ah>bYsQg) z=LlaKrYfZA_3HI{y;;|X<=Pe4 z^xbBY5`SY$cBV}{jCcqyDw!^P?O9OdBW+4%qIt@PiZtQsQiP5=# zqO+zEfg3uz@cAv28PRO=+_79eH#hqJ;5FT)Cg`EwIfZR=f{7Y>e7XXyMukvBU-TkS zuxXx?D-KXzJqRg>wRy>|GY5~24K;oIse;v~$ zRSvS&qxInNF?8qLXg%s6JN1!Km47Q6HFzhQ&k*gOUpR|~$TLh!D{9EUh{}CReRK}3 z7`rA|*G7-jYFU!duw!(`Iu3=gK5%^C48~i4$l$HmYznlMapEDpHqiJx9<>xZ3r!7| zf?0$$lO*__(6AH}lc3w4;`FF!2>fu__;0vKjYYEoRf&7^Bgfk`%G&*DAzFm0deg<9 z7p)1(YCNMZ%iSr$1~#Y78a3?*LbnHi)$2(RBGy%;FBCcl#Tbg@wnxzB*A3i_^^2tg zB@nrzpj$Z8Wti5){|pv%1qZQ;k&{q_tU^PFl3=&(NE%RnjC@7IiKkMt_ zSu~$MK%4MW1?C5@03||e=so>)5I%~+kM!kLG!CC5pcV22a;1cLd)n+LAzO$-nPXg2 zo8v8TDM}v$2U0-C*3p4bC?p8-ZSi&pZcQVM!DOvsXeMF=kp05Ehv=xqZRBA^R#q4{ zYw;+KS5-?HT1MDF8$q}r=~SxCiAA2)cqTm}QnS`-H^P(w>dCjishtZfWWFb%QOX=j zT}ItVoyI$pmskO63B60mDVkH5k#&;H$ok^PS!}&sxVM0AXs@&h3Wj)T{H(9kypi^Z zCpwThZSu6y891$q4(zN0B-yzB`o_vUug22FiqJkrbE0QA;N}Y4dm8&1MjkJA&`0m- zbE1SYLZc7xgOORm_z9Y-$hL|fSOHL30`~=JwUu_4mUbJ_(m0)_WmogqPQ#By!PW2n zYPar+Bt40F96M-FMn)1NZX`p~hz-)#y?JDMszUuyms`6e;`T0?*|)URTHX|m-`E$D zFE^`AxXm}UWRluJ1EKKxH}4AVWb)W~jMAfG${-u_t4QcwnfxtptT6e9wFjDy%9{e)P*{u)1bZbvE$F|L3^eQ1Oy_Kkr!em5#3PbBmWBf?;-ntWd z@QGI%z|-^;y9%64u-QWou_1zUg@}+o~@P+CZh2v zO;L@8mQbIDi|#j~k+?c!PMfN7?avzNCr+I1YOfSa(c3v88Dm-EzgL3OK|Yfu#6mE) zb7k|NwEzmm-p}`k8kc9u3Umq4DbU@5kg0e{3K6CRnE@^BC{I7jWit?JalJ?&X9$KGuG?qQ1@7jUF4zD>=a7VD4;G?6_dGzOg5*WrDFwO!Z79=YY(RN@?x z@{X(b7`?~MR50K{1|{#`EF97hF3YG}z2%PZmH-wT&6R7(?6>5=$A^>oOwf_ST5cN+ zHDT>rR@JDJY(|nO_bn^FK@~#fUNr6O%^ykAwjRDZP22kX)oB9Hxddx0l~*W2(jBlN zMfN}~WGo_hbdWYNH7!cBl=trJ< z>LZ;?>^3f>)kYafZUtRwLUv;aMPH+H@Nn+bsi9M+*8D*~s9Du=ctpmIDokcVp6t>U z!>s6y<_^jbI|Xl5CI4g4*4cRKBOiH+Ij@1fjZdCBRot6CF=s^?#{$OCg5l1BWwF>Z zwNS^vy9lfgI7$!!ENl&h1Y36??hIvDr~`n!58Kimh!R;t2@X^pT&pry4U=b*xHw%XRBv`YpnxEBxr4P2CqR)9jms19iXi?l|ua3UlCL2~RRv-44Q{2||R&2xOw z#C;H~ew%IzmAFeuI3|5iEt%DagDp2<`R^m-Q#P!Ax%LAqLBxdBpQ7;)Uby#RjY1ND z?n42A6#spc!SaCLMiIZ$90@Hmhw3(r9r4*um#WnX_w+uv9V#()WX!2n-xoMBuBeZm zo*iprhoNDS_E4;FaR<^C4=ZVS4r-9}1uZOY>dJ}FjEe4 zr5vf8`rI7{$T&dSI$LWk)Xyv+uwfH#(G8rN>A^0lm5J)@m8z~>SzNrL=$9d$wXlXs zzY%zfF8`#tD2n7@jfkA;;Gg_9(6_pID|#6!7GcNc@p}}p1TPhjo`UHL^MU{iIEuDz z>P;H#bY#1R6@WDCZu3wIhD2Ya)rw$;hwi~^Ds!_c4q_)kaTz3cSZ*RHtN9nv1jF_i z|ARK%Avm;*9hOiFXboiUW{q^CVgeJSg~h>v3S1`wJd=G9dc-g+fd>&Ca}y}w8xaM? z^ewpg{wtWiDU((i4&l7l>vF6>f#UHah#A&g1hTqtzLUR}UXtJLGzBX2uw^#Tk6u2V z_|TPH=Q3piL-6uH0>y(^o=9wb-+0V&_aEHvmMo{~Sdmh>glHQJz5E=ofBa`KLp_j-uV~5r6Lg9KL#8y@Zd?ilbb$n7AOogIRv_yldxxT&AIqFSFT3RvUj6*1 zGhaWiqz;ogjyoQNSE84#}p6cP_ZZY`bpy6a)4aN9|0%jb(pJy^^bLi?+&w>MrSCdl=hr`fo~|EFD(63Swh(XLv#Do& z6)~oq$H2YSkF>+x2uVim;b|^Jl9z4i(Ye-#+ouMN^Kh5(#_*fD@_8peeDda#!^0;> zHdBN}b7xI}uZ|Ic+j^xsQU~MVUm*6>%awJ{9ZTcLdCm2~H3X?pU!3N-c=qm%DU5_v ztQb761G0xAkcA$P!hKvu0;Xy2D4XFMk>`4iDaS)H9j7nvu$ywR@~&R|8e^_6FlYt* ztmX>@l~5w!cYMfI=yUvmgcXD@!5@(IgiHq~M0D5}tn{f}eg2A{m3)ep!s#i0Nb?Q( z1D0d?f@#ieqlX9z8rd2>=>k(SM{@yra9w`FLS}D(0mJhvM+8 z==Sui?U+)$61}ZyuwQFNL>lrupzQ(_hV>&48bF1zO){|(PY-mmt~$MjFw-?26H-w+|28Xno7 z$Vdi>c5|^qOhYWHOa?Vbx2VU#EtchPr|ltg=OX{X@P6ZX=6F0wwQC7Ylg<9!{(^n& zc{Lf`y1wiChf^L-G*Gs+3M>r}HQaW)#=gYoHf5sEVRShaJ7zd!2kyfnKNkBuSm~{| zggmg)nOljKs!09#pKCQZrC?5HuRs6w?5B53r_Kd3=-0YPzE#|B47j+X0Gi&6a5utq zJc1GLg|EJqe|O;HRFeup(eag)$_6v8z^kA2oVM`Y%uc zUVPZMtFk9^uBD^bbj!_Ik%*OZ%?RE`O!4+f(WMkYkH2{+1o(sVkzVW<2T6g!A8DKT zn-`z`nwwPu_^umJvaXqsWq@6G9%<2Fjb{HIx(KdN5MP`YmuZTFO7}Bt;<$SEGvGAI zHcS0TvD<^-N@SfqGO&Q2eCNOu15Xe9?7%NUZ|${z(+=C?4*hVkt{WMh+?!>xm~054 ziOC|4P{0$Y%pj#zf*Qfa7056+HH%m|!rDl{H9{s9qvdgwFkOdh>5fO`b|``oj`i*k z7BS$H6Kz^!`t3$gd{s)M#g)0-z5sw`V}AS#Dgx4#?W9%L859W#P9@hCnaGe16g z#EaT)suJ})qw9pH5~p+S#HV3? z9u^)SQ{wl8?Zes!t`J?yaW+1nCeY203t;aPA-a_=APuJ(jIC#`iA5W;xzq^-tNywJ z-kGu*`h5A&;>8pHdr(4-U$*#uG7+S1g+BP8JsR> zZ!2H7-%RF*#%7YUE;87YEC>SESQ{LyZ^dTFI)?;6P_j1vp;9hEqK6q|aekisFfeMj zI~y(xK=ebGfnR~|AzQCSHWqTnK#3#BZV^`$+RC)!u**<(R+~$(wm~!}{2O$owY4h* zFUC*bj`d;CrUAi5avHkH51~|&XIrk^ zGVe(HrrtgIwkPos3mhInjZ7!6jXd;F_3+gDn^SL_eD~D8ejiX?1_OI?hR}i-Cny_$ z8q-~%==y1mi2K2A=kZ)(av3pnPiC{#b6GZ$PLHt3?76SR6}b$)fQ$xnQ>|2b-*CE~ z#Yumh%MxWcCD-}=;eF}U(Rwz2Ln%y6C`U?S2yD+YDg!8u!i_y?zn*< z$GIioUXW~P6B39oRM**(R`8}mJd%lo^YM5-d?9{va`NPk_d5~{{uTc?UWnuD$rF>? z-*Gv!OWzPQ4nm=WXa7i=8UPz1H^(MC9+Q(TkIXr`r)xRS%W3Cghek#Y#dI$mruX3+ zow*Sxmzxc#k>*_5JA3_j^q{$KV_f1|JJCG=(tsT0TSWJ<9_;STF(fjC*n`cS2xe{A zZffwVK7#+*&gYa=G@6S3C4>%&bs0UymezP$1_~&@^f{I5jf!~s3~?M`=l(HE#gi6{<%i}sBXY8a-7unNJpZ-_vjLO;O0z6iWs4SBtq;Gkq=A+|}K%JGnB zUvEe5LLj?=*1+6gVt~t%INh%e*N!GG14orL&Us^oopm)7Y(S9#B-iOWA*q-H?S*_n zuRf2U&#e0`*F5KrAy(GS27VrUV`w3ofQ_ZaLpZvrANjofbM_640asj#0 zkaomJkXxRV0|JKUkSy#qgiZzSgB*n$n3{1{F3#+qaAixm0fjI1|7+4XbjX<04vmc+ zQe*g8U7~Y$(V`fJclY%^skI@d)V#8}vA+&-mck{tUh`ows6ExsoawF{4no z%1YT#hp%${=W{1!2bGcLiP@w&^8fzm^S52+OFI9i_&&9T>x*1JSJBJBgd-G<7oWwx z0E4~kL4wDy1EjRPT)Aa=e)*PmWqJB7BPZUx0j9IQ-iGU9{kj*H9CQTMOjo{4V6^H; zO93t{L*Iv2tsoV7EJnQ>(NeC6G;GjVxGk&9O|D#61P}nwPj1j^g~CZIhUm~iIc6op zp~?iCpZFJ^W>$+Fz3FH~`$HeF$-dmZ6V->S;h7UNPbJbL!*3q;`G((IuBHdWm3XTa zulyGy9*M*$SuXsOHZ&P9Od7zlu4G;o`Rc<&I-vML#o)G(kVYjBqOtjRHUN;o+AH0jZi0f+_gki96` zop2BUFp4K65lO<1#jWWuP`g(lud~thvw}&&>v{8)Y_eL;X&IGLwWRZ@;TJ-CQv4qT zoo(R+MZ{myiK=Q)OZpV}K|Rg_`1Sy|&OF4q8BFwRG1Xx=CnG}^$4wT3#BUrpJzxPBun4|spfDGlLHVBDx47Jy(E(6T%Jad|}+yp2P zdrqx(g%E<ffaK%gygj|@aE@M+*?U2;v%!e9V?#iIesjY;TAS%A!Ga40^tQp88aN#Lq!_+XTu zZuHD&4%v~XW~XUb9h}APR!AO8E5oym5yOhusz0EpRvW53Q|*Xlj5KDea)>^tMslX^ zApNE*xh%l!KtRWU>XMB&mIlGgGXH+i;*jOspv7ixoMJ2>DY6uz+rs)_3@IRPHQ2t8BL300yD!V*nbi+7!(7+lNo=7+$i?BV4 z4eu+M25T^a#1R@q0S9mp!|Mqc-)kiWnQEyHJgctL)Tf7AEW-swgszYz+)9#gkS%o} z9RZES6Y23)(t?|`Pni(k1ZA`V3AzY6o`P_;yKjL03ihalc@HxeB!hnd3R&S?q=sZ& z2=!R*lNDWG@2m=9*P?=`BD&7)5z5vm#b2K?ICiUDlCg9(qO8}8pj8M909w%4*<@Va zHF}_s(2-XoY;y#y%a@l>6pY5LuyrhV3}TzjBj+z4ydEL&<;Tdm*2j+KwN6`1Hk%HW6_fia)AWpk}!zFmE6_9S8VXgwTO z3tBW~Bdxk1BwV=4A|--y5l;}597ZJMuAwCK?M|MtZ78ugv4!|x{vcyLPKB(y_t^d% zN}p>5RR?)t(N8iW%uff z+7s{)c#z;LAOVdhiKDbmMS6$XR2Nb7+`28prUxOdvau<1k+d{CoKPKo&WM|4+?dlH zRZk2LBOY+FN}t+B%9k*Pha!5RY7F{P266yMEkAOO^~9{8?3WT1C!2~V%tIE199xIX zL_C#sDhbIipQP-FsYs^ij+AVxP;*P!ND8?TxfMfH0;8lagRlVeu10o!$X(^4f7*gQ zMVKHFIzaX$XBPGYZpt7?0@54+;WB8g)oL8+vbebT?jiN3$3`=w_#>z;FDUZssCv}l zxEBcGYwcF;Tr|=-Y1?D>H?%8^eTn|`51;gJ$w;FltFdH*&%>T^s!E){dh zcnU8uGfBYMR903Q^D9~`Q5vr#QuWbB#t8e7?oth_k&rsyQbWl42-!EJBDy^@ls5Ii z*xaByaj0t%s!6h`+nTPqa%8lTn<$Ov@`KDTV-lqu2PyFs+0S&-bfd0eNryZ$5m7Nx zu5hYsB755KWsP+!G7|Qae1TX;+-gQvt<6`EGK=VNsA&{w0G$R{A6Z0>5$dO1Bb^%7 zt0<+t#-o+E(p+h-C9K*8z&*(2xCTE0uhs@g44^XN5t&m45Ilx_*e#?Xfj<*}#F5eG z=;_O>1{46IBT9%JcL2EO_%cjo7t*%@e`J^TLwcw$$G>S5h^Q(Hq#4QiX zrY0e0uWhwAa5Z7Tqf16$uqoi8xFVDzZllGV3PK4jpRhU^`(^!Yx-+RyPwI~qF14N6k<7-VoU=>&mX|Z(pfzmyBL0a-u!Hot1Uc`!ZW0?t zK;#cX3}SscNR}?lQI4X)bL(=oex`b+US*dunOZrQtJZV5S{bh~ixHXCetu%&xV`1S zXEdVg%aAIQq>_|&Topakza#X0k3u2QO181%9-Y7J-9C5bOs>{`YRir2ra$B)U~pPB zAuEaDppNkb_l4Zl*RG_`QsfM-eUhDatk z7}g7weAJDl?3!b{rlDtsa-(Uj7%t{emMNR_qTygPwhu5D#M&EfxRbV{IT>V_PU7^-`8$K?C4RCEsq;zyeJ>Y|Xc8jw?yh&%x2gcb;BGRqlF2 zdO3g~c}~?Ju+ngT9A%So1!+i-KB1dO6*yq^V;XZ0OidkdSGFZ>UCSvf^a6b#!u zt^X?LlaZgLfK=)@O|aQ@ILZi&jwQb}D=n<%n7Ht_A1?uby<#UrC&ugh=BHsBE1xaoDky$f$khwT51dl3S5lU8vJ~)7+&Wn&-a<|u0tPL0 zGdglmo((?C-3)LwAgd5MtO4zu9K6H@YOcH9LOt45pzkRw{Su5!thNNae!E>;+GwpJ z&ab@+<}2-SZRixcuU={7y{p{eV>&Z*cdy%^uiCvk^?2CJXonxR)dVF+poB1T5s96l z3S-c54~Mo|>^cq1YiM66sKe&(9CCeMgR^?xaoqAl?e>4_=Vln%MA z@h<2O{RIO%-G}mDQg0Rcrc$rud8d&ZxjsEheb#Fgs;V_ep>!Rmv*I{k^SMJg+~{Lr zW`;c?p?(il99<2im(Yp2QqB#zOD*2K&Y#}Xj2F&|aeCz|+(|&0>j>~O)^8z+C|J7` z-Gv=Nv^2vgzZWG%fPGDb>BF6j(b9k-Jp2?UWT{yVe$I7S%b7UTX(0(&d(%6J0GulT z4-N%!Ug6*nve7Ndk#nim(xw9xG+}&q&@=?FX|Lb+rmBQUHUcBPX3CDS5xw)b@@t{* zP0h7!6w+9&q0eYe5S;m@f!n*(k>lUtcE?_Sm1$mh|6>qHKA+r7-SMHi;OE7h!Xo*X z{|*o&=HIG|>(r4ZgQlP))mqd49T-RfeBROrS!4%9j!nKcuF?w)Oy%JJlAicjxbrt* z_RRmJ{(!;x*MICT5$l)uou9AZEa&Io6n>d=Zg2^}a%w*EVD=r%^hR)tcJmUAD~e8D zI|hdLgB~jMG9aQDv(Eq5v@u-A{o1vyH}n9Z9|Ag*s~`kMrTe;2L59fCPouEyzUcY9 z{2FeqE7Xx*?bT@rPc~~i$mr5RMPmH0A9@32a_I8e5aR$IVw2#KBp9RBWJKBvp~`3a zCHFG*g%S61vpJ{TUf%^!MUVVLuIi#k&S<&WR(&sIYL~Z>GnZ&0o=O0HK@;)r-msL5 z=pAy{ygF6yPIbw0;{kNi$F4%xYQEZ|%t0^hN!sS#DCnYcM}n@scNL-!+veW;3ZMIb zw7P3!!7Oe=Qz1iz2zDmWK0!LE3}%|j7FFQ??biAOZ^yPm`8U2^WtQW7XW6=td=A49 zZzX>hED~;(Kbxy9U9x^A`P>C`dn<`F{(Q{EwKZ-v=E2l9`ciE3*qabVLNFvG&Zr;~ zs4|UCcTnWdnNGIiD2e@Cvh#ed`2hN|ZPjiHf1vsu$N2#WV4p~0_itZ#F3HqpyJcC> z&z5R)e}?wZIwMeUZ%os@`F@oh8GT1;6Iw=s$E)=rJ4#YgbI*>X54dNG-=BcOKhFIj z?DkatR~bY0$QJPMUR2z-6+2AhO2A=C(dG#_cmo>`nmS$Y%OzzA)zI^h6JRyr_!*dB z`pEiD3~NjK4ce*g^389eJ^XE5)bLIFjg&y5em6FqJkwH>gV?HHZ$gRCWBcJLs<(njW;9-;>7 zJ(+&`LL3A-X!=kz5nF=UvOZlX6rZ*dEB;_f1z=ZQC32B{;iW_{X(uEo_H7 z-`v@d3`mCe{PR28^Xq5?n&j4phEkFE2N0PQR-~P+StTd^Y^l82s7?MZz)h6$bpWY% zkQ9-RL?7NJ)&Rn#`V$e8F>m({bFkZLv$Ime_1pNbb(RGf;MYmxt0L=7w_-;DW*KL` zbA=#p^uP3!h~)Z*OZ2na`Frv9sXEuqNWQ+p{t~<+1no=&2NJ9j`ULg3D?^JdLU|?` zmOx>E1t6;tW-4DUq>E11VJa$;d5bdlu>Z#ya{_80DPMkK?1{0ecN^04)KaoqZGVn3 z_^j7>vLH;@pLWMwzdt3n-#_-mXw;(=Kewf1|717M50a_yQ~P^2*^X#e5h09J{Bx5g zOz#~uO{0wFCRKS*%N*YWM2nP>d2*v_`vKolpBlEbS~Daf;sKxUfi4X)J12<1qVCcm zf>3&NP*43hbRZ*vU^JliN6^DJpysR4B=(_Zm#&wgFK+hFk4+bu;<$+q8}+OA(*k8( z=o+P8g*uO$ti_qscft!n;8Yp&3;;A(_b{8hJV#lfJ_4Uo^7J}(*H&kh@+saN-iOyW ztuHODaP#XQ#+MgY=~}ek2|h=lZVGWga$;nl#+*cg_Tr8!vU{uFs@;SuG2~xxHm|!n zKfk=Rva&|YT3lLr<&{^iK#y5Pi0mx*&b0_Yp~Bnu4?GACM3^L0iH2#H+s?_i$_?fm zL`ggqHYR*Z@pxpTD?_ZUpr(L0>Q!V4-^4sE@=qH$v*h7I2Ew0lo$jYW^a-t~BAgm( zrK|@0<0H8w>O(IFW!P3!4djQFuojYnmoy`m%n#q5jNU$b({1tCcsb>!3@wXlO%vy< zu-6CW9PG@UpU=stM$c*i>1mXp(NVmcA)6hnDNP_%v`kJ#HX6SbL7_Zz8Re?fz$j`o zQJ;ik!O?&!E1_k4`VC!#wfeOCg92+K2^47#qxr3=$my7l{lBm`-pHAp8Jr7Y5sL@*z`wa!jBZ#J`Y% z<5Oeso2aayn89c!ZAUaWtLgr9rW^`6IS05r_ZyNw9yArxb^S>*Vzd1|9Z@7sCe8wZ zbkf7Pq?3xQ#5}l@Wjm4#83x=d0Uch={*W4ZQIP>8^XnSmy%9U@NofgJ zbsRiM>45qT%mz2>elKY@4 z-u1eDT+WDYagCraor&_!wzu?k%=AZq>k_>kjM|F6+24LikD;MP)J4Q%au$rI!5GJyRs2w&ea1fCE4fe(SA1?9~# z@EN+13@`&FmuzVU2g|74o&GugOBQ`b#*VknemSWuvh zqegr35~CanrDUy^EaAn-iS3l07)cK1%+aY)GdGwNL^HBGR*y|K8k5JW^m6#bNO`8Z zuSk>^_f==gxX6m8+kV?|@Stn7m*B5Er%8kgLSz-uxH1`kWdX58NHfKHkfn!U5>#jl zm^Y+<;8m!I8M5EKC7qdj_%dqc`HHZgQENPOR?|^KBtK)w!GKwIiJoP zdg~OZKvW+2S6ETnW&h--MJ#kEqB^->7G`0udW3==@pbUnZ}8{`19@> zyPy6l?OlWnjJchazl??>?Hs{qbEbNl>g(bm7dFlCQ-qcStT2QK@eZ11M-`L&m|dTuDy!$f@*+UR^|Wp5HcFw{;Bx${IM zRp;=r5s~MO;z`w7cSLtFBijR^Mk5x%YrRY69 z^05UESp$7!4Cl%yOWa(2j0%AhZYp;X@YlNjwWK?ZFSbf z?K#@w6^PzcH=1G#;ryh021w*fg(-olrfON9Xy*XaqX2vR*iQzrKeL*w`+`6DZgR^c z);_E0_(*-vFUY{4N9AAWU7z@~xV|kMPNm)rwp_o0JTvu1w^fcW5|vsZcJJm*-ux@K z)^0t-ZxqLU=4JIKo)GtW;@uBCQv1cFUT+GwX3va=4FcH^30Y9IXsbk?ZXa4l~aTr$CQMbE?w4nJ#E-JWP zCs-*6mO9NIzF5424R_kl9f+}ge|$%Au^r#Vts{OSt}pT&pn zO?RCer_a5K#Qn#3KE=1b4$~5_gKj@ioDBLB8yVybA@qyQ71A9mdVUUX!UrDTaU1NV z?;468?&4zVED#DigXQ-nS&}{FuQOC>Htf{COw2^(*wS~A&OfYJS|l8GA(1$N_a!@j z`VppTs6(KJ**=K8aSO=Vo*R}-;JvtTa+*&ID^L-t2jp!q)*xvhgr-4MASE=LV>a=! zC4`|=n;k^fS_uY&GP3ThHBpzoxk1@X*-|1(S_R<5q(h50NTD;Z(sR*nzb}UJwcNP@ zy`9XKSHJt(%KEF^ABBRdpkPz(oW~xWf_g_WOWfd%I3F-cVfvcumB2(qB*_tA>RizD zxa5&#TQfPaW^TqjagA~6!bua-0{+fLuNy^*l!KlBL`E+yEX@rMjv5e(d>`G6qFgGcF170kjnn>qj z@piJLUI2sYeBoR$z!DmZR}ho^iKIX1>R@$oR!W|BVrE2>P#yvxW z<4b%^Z)wvUa%Lc+?X|VXj~ugPgF(|FP?5n{#u&#boFvIQ&_tY4Idoy89z?D z;AKFLr8gPC;?*>@kg4rzooL@HJRZHrv)+LA^@M!Pb{+|g1>AkHnYN7Zj$mR!A1Cul zPb)_Nu?#*8)59D$hlAHO5L-b5PKI%=th1YhZS^jc;TcY)-Xz{#BP*y-u6$fo%!D2F zGNVS~P{J6^Aj3n#R8*WBV^}d}Qi-G@3Z6@h(FHt;e)m4>6+HZXR=oRjx>7{BDPZfV zJPV|vF6z;tBApve1z0|%+X37-6v|ITO`p$^T822 zfGJCUe;ih_!{x4dAaek!zcbGyuU;cS+k48q=OIi#>zj z_1ts?XDs&13L7}rPNmxCjF2xF3G)pBabZ5ktK<|3$3^(wJ+MHsh1*Y^x}9lCG#a1@ zPg@7dX*iZ~>h=ZUJ|L`Eb1PlMuK?{O1|{g?WKp6Ugcm}E`wg= zH+mI%Vqtc4cJ}DeStE$@L|3C_VS69(*sY_;=+$S2m@>Qi$R-`B4&i%WWU&spy zg^8O625ndT4`=Zy-{% z$=lt%2f2KQNSY#Z`tA#(rXD7!xWCM{Uwswn`{}MhHn8LRZ(Vq?Mz@9t+mpF3L*|ws zg+S)!=`;nJnhmTsS+)6c{Y;&;*H%~CtxNOt9WgHAJ7l6qJU{OOAW@KYj{~unn(OP$ z<)zDy;=5?)+A5n`c=5#-#RYKVu8BVk96M%y4`2py-CwAXcZ&ZK_u{`KTnnLs%zpG? z@1w10@E=4BKq6p;opfzWaDjHu)f_@!V-_fmsHsiN&|(K|+AL%0_0pXpYN+et4BTU)6m z182o1B_z_7H@Ep^KNr!gc)Dsib~2U-2ZMoNNHL;Q@!@DP7?eU`Bj%;@LF`4h^^&UN zxtHSoz};_TL(z=wsy- zo}4S>4-}Me@gYiinT(#@Kb&^2Ngs!I%eQxfluBBKof&j0<(Qgna~cqDcKM=ZaZxs8Sj7vPJg%%!T_d z%ErQI;|+Nj`VNfm6wle8VSiIyuZv;|t=eYh$-$z2fWcdtK4X-ZD1R zy#SuW1{RY)m0~L9sSibW1=+mYz7TW>7hH3k=T9Z?fROEE zXboUx4esa#n0vDULB0)6bNRhd;krC_=$To>;Di4cGi3K-4y7hRA~7UDzl8ry;ycgV z*Il^I9*@28u{Xj&((Q>NJF(^P8iom9SDLiv(8D8JsK2E=F;PBn>ePYP_50xBEnn#! z6zhezt&Nc@!+~@T^A5T;CK9cft?ok{%~Sa<9(MqVG`M|;C7HXI&`|!REfxzl&};(D zprE#1LQ|VfHo(V|4^L;?03V#p6!`cRGLr}SKyOqzmf`;l_R`D*udU7Sp%mjYvu$+u z-x;5Z9V_uM94;M;O~vor&qtiYH@3{tEcRoH)j0qi>s7LvgBw8Ll(AhyO7#$$fsHyy z{+>$EgR&?!5M=5hK#qGGIN`YU<`nw_uN2E#nLr>TN$k&KB`;@nuCdE_Vh?&{yZ=$E z`&CTb+U6WDc%@0T`Z;&pRg$yG<;jwlt^S*RWjtQ*mG^Z&NzDK!2WSdfvB55avy%gx zyd`;4ICy9A%ywS0Ec9BiQbA+}*aknx5zc8n8J9|&!j6n3OfaEcfyVnSWRS)=dz zq%{0}rHr+USybDN`iF-lV=yx~n5<>IrcXkKZ_HO;Ga48fk&Q&Aku8qjc-M{NOE8D< z6#Y~?2kG?MBd6R3zLu(H;`n;hkJBSfAGsx>Qn1-Q-f&Ni@J;VUvcDkD{)rQEo^?aW zxFEyfpA^zQ!16-R?DznB=W0@A_Z7p4Y*?T&_jl7Eh@JDjB5HPeYMfYN5VhNH1V$gX&eVf9|vk9 zd?KjI*8Qsf6hbPMw*)2seUFVCZ1R`MZJ)k4a?pRDkb8cQ+r1QkelzI7f$2P4Mm!^4 zu!2DYXok2EOmjSwkxU8;s+&v$YRsBpltzZ1@A-w!8cS6Fx{#fESBCxaKi87+tie9D zR9g&w+pRbh!<~A)zgn9tWVCl>Iv0Pdiu5$j3JkF8m92Iv1-mccCQTDec(ZI2Hs(atEn@kop@>ZIl!6UO;$a=fi%Zr2pSCvvZ|l0w zMY%DYgBdsg&N-NIFp~hm2?RljGzH1BWQnq6Nd_%DilaErU?FpCC(hu&Y2qev(!^gw zC7snaO*e-#NWb^)?StRH_C5y$2gyV3 zr9=z|;Mr@hJ+1Ly)lH6b)&~>XYz4M*+7j3*{9Sm>MxLYfKhSdsvC+@NQZc(xHyL%N z75GRHRfk{NYHL*l#jY^i`zqk*@q}Z3wco3xhzys}zwc19n4P^Toe_U?2A3%U18=-g0`24Zj zv;1)bLFFCfIP>%4uYfkQj$qUF$TFlGc)D?d&|?;<&Jtj}8$gZBvM8+$zg;w*kaE;Y2)%T(u$Z+m(=TL0pbG zfRJOislrzG(0AE-J_DEix-;oOwbPQ#p=gTDQM7sN5CSW;Jn4|{UcMqueL~X{y1|Z;LI{uG2P3R+5L7ESz$DicIuB_L z7EF~@YUn4ltfU8L3X}K|FIjhYZJ=IO54dA`tTKw@NydS|!x#8jLDy-W%PsmkrLbes@KlL5s(|)tQ62Wc zDm$gZzTm?4@0KEg5R_jf9(t>$wWHCPrbo2P_*sSV;-+f#CMg$1e&ie=qNEE1x_CkI z!8)M@o+k0;YkvK;+B;;)P-Pk4m-FlJ#qqw7Z-n9svamH$HNTr_|AP&g{2)-=u^O zW1a(dyX?kzFX@X+mFv3Uj!Tn9J2&Z^_SWK(|46ETDF%DHq$}fD=Bfu_i85K@gRzeG zh;LzBe-^Lu*qu*OdSVHia|T6t$lA}94>I{9T9IN{2pSA;F|yQ8!2&`+#CK(#Phv13 z0&ANJOSA^m*d6R(SDm)I3(aqrfngR5h7y_5*lgDCG7K=~P_>X^Y?v1Z#*}E%rpz7% zH@m#30NEv2W5`ABFrzLB0q|La(5c0Ye_FppH{0FBG-`S8y1S z2nU^Vn{AY3&(*lOh_%^b4Zt!1QH5Lt=C1XWb#cK%QvZsY`%2sjNl1uYnb^> z!7U|WoZ@W5i^s9;U^;s+YiKD1gU74Fc$5mdTwafJG9ty5aA3*ra%YGg9~Wz6ixvVq zN!;?gz3^7SyytiOWLN*HSRL)Dl2{*)iN(d&2Gy+D;HaR4S|ZTmzzkaOmerMvUL+@A zTeIVtWCpG>ts1H~GkfFgosGtwZ@9Cet&-G0+ZBTM*C8~tGMXz>JxdR7+(p%skj;ju zs+nKIcbRWDfju~tDf0jXigTa*#bo2W3l+T)Z}p?pFQNEU2$I-#bd+xehiS2K7QX zY8m!=c{?itxCL^}9x2GfWgwf&lz{*+M7Q%#mM?!`+&5dwsP2ra&7QySe51^MnvRIU zx)J<1jMMJ5KQc!kic-hz6E-p-G~mv{65GR@m&KRIXwXlWZYV;GYn=AS^xX^!ykzd& zgY-uYi8s#bVTuM_oV2@la7uu$ih3}lX+b(3R3XKn4^|X57L5W#@k^2dWCfBI*tC`u zMcIq>ycXwY@C}X<~ z+WkIO^`RDlxA2E7Ah|sf>KNcY z;;tK_VaH^q@up_3PDG5A02s;V7aFAl_8}s<1uef-X~@8XuE?+k z(0qJLIq^iY9PEAVqB5^sOjUy43zqBS&XXsd<2Te@@wjXJWF-Ffc!U`%2p2jPnVXAb zSK4hnW+VR=dCOZO&!x)cR40A$Vp{EB+Wx3?A=01I^{?e5=nD0|{%WNazKB=f4OS)u zT}$JjOCDd2#NUyKe4?|m@}kJ1J&n&f@~e|o;jX}^hq4mQy zpf)xU9t)S%LZPtm`!t^YO>PAcx*W_A_-Pjo9y?gz4-61=+m!+~fcT3DiJ$0QTIGAJ zuy_F52XQY0ssLff>0lh{s=vu=4fQYjq zYz4S4MdkFbZqvI-^c|bg1cfjc^AstnF+ep-DZzIU^7JV{K5VB-L98D5qjtD22VoNw zaMFUJrVHyng2{ygpj8IEKYRf2A9E+;i~YJ@250 zgF=ET`7)Fc6}cn@{r;fTlj%vmfZ8o|bt$MQLH$d~!^vR&Z0=Ed&YjJF78heN_LH19 z-F@Al8={bSNrF4ecLIqP(TOM?trs7j9vP;rj7aNtF&5g7y8ORd)Ct=D9K1RXD-*nEFs+thKLXMf>_=tFp~BRdV22R& z1w{^d4cK$BdLdG@=Ew;OwVPw{Tbi!&E?? zcfe!6<72nO;d42F-@G(#OQfgYhD35MXFbQLpQiz%^16{rBX8cPufSuwepd-%Lq>WU z1bH~Pap*(ZK#rQ;0xKGt>4fLzsQ}}S8=6rfF#Bb(0#Ow8P$N-s8LmpA5vu$B_0Vjh z?9$yXyOVEoEHRc4xg?kNqna?o$il1N!n&CgP0?CkGvjpWN-g|#2Et1&h%iF z40-ePm(~Ak&yJ&ehVRDR40^dU<4b!co(fl&jqkbEKC+i@FLxJ#DDb0Aj12%>?Ajk* z>h?i;&bliU6p6}X=#=Z9%MLQQgo~dgtkIU(E zdgHEu90(?FONRV%z#RuyUAoJFD( zME+hnfe%NI%qmAw9R>*>C`SZ2v&v;yG5;u@K;trE8C*p09}Z*{vK*j>EFT(jAZs|F zMT8I1PMS>rbZ=D6QJKFU<#vaE)h9jp;3dd1$h2f<*VW!=E|k{^ph1W(QTE^i^jRUk zAs`yI+jhYFRiGXN+Ed!DA-L>jo^D^K|2?t}kft?Ei{Jskw_Y3% zFa^K|GDTdQ7q8`Ji0kp=5sMPyiKwIcl6XQ9g77Pl9DIGA+&qEWsRWFisZU&oGrv|B zC06O1e4GSLFO4@OJVA7Vrrf$VZ+^|9CNnW{Jr2E-lZ-Ece2kYkkGA0VqNpN7YLK=m zL)YZ_2^8=>w=L~&l75Ne-Ot!k)9G;T9iq|;t8JjF7V9Z-iPFb?uM+X**S|NQp_E*6 z-+SAhK?d#X_uM-pJwNgr_Scy=r}6y{?3F#(gUG`?2HG)l)<2Q-38x95DzQyA$#6^n zoOZ6^u-_>b@Q*(f;>wp5wP;kPO3z)syg_i4#|}bciL(pE?H{UNkuFq>qG~+bU+*Co z?H{>X!^iaBI2~TB_ZorCl`vR?Su~(Xu3U>I_WA6@M3#mH|7WgC*~joT>&yLZ>WX{F z<9n~jgA|^9=u))SF@>1DS%45;k=d8u+v}XVl474d@;|EU<<&^>Jx6-C{Cuka3U&e( z^vk>mk)@N7O@Qy=*fS~UiX1gOg;C~P$lg7ic~3l`%_w)yFHOy_wzA8h4+uUUTh_Ur>ON8(YaL+!)^g`VdMXfQWc9^s)2ahq*8oPYqb+mlY< z|9rr)jvuco|0X^EI(q-QQGyiBWB`^o}h?v;n&iXpxL-WU-RIxGmFZ$1M!j3Qx4?7Mfj{k)Bd>-foP)&dh}?|tV!aMWjHD=LWSDOvVubUp1%(#u+silbrUBl_cqUaof~^f9B!ZiO#@1-ASp2l( z3()xyWzuz;97L&j!6s+Y<8m-()rr9Rq!Z4UA${P^e~W(Prr8@@KoxQZ75kif!65}hj(P2&x+CJ7 z;BRjCI&5B#E5basM1pw|x0c@TvAKQz;6c|XCFWJ6H+p_d#FVd5OFBAyd zrZjDb>Crw7(~pSCZO+RL0-_tC)UfWCFGJDFl{N(YNE?h)6v10aSQ1j>h zpi91!eZBt+$zn94<${4|oYNF+ZCb9nH+otcQ{3yWi&8OZrZ~JT8uXpk}fzy8$do%dVH8X;SsQ~{0nhs_2 z^56!FY#?w9^b7suY;O_c5pX`l`d`jBPVp`s^15qhstTugtiim=YGx*PjQZ#pPtK!z z1=}kNI&&S3YvMb{*sBY0)S@H*ameocsOG40YWt5R$AXg8L$`N4*?$(jyIb}?d(<4A z?RcUH*PPO@{}-?~0vs3H<1~(wY1BypVm>s`re2X-DB}U>hYDOd>>C?$NZybn@w9Q_ z(F+&U_r33ZZ=e_7pzBf?zw~r$=|U!R;WgO2PV-m74=?7af*4!!7?BqQ0cH^ZD?sR_ z_5=+OfT=jJyiE(q=rV#2z(>F{w)CqvbZUo|1RYD6qZclGC;8e_;_az>lKnrF!WW3L z_EI#EV7D}uQUQFMleUyeT*!QkzRlm_+lZ%?zH%W`s;W!(E;$mWUE>+7;}9fes<8sz z@Rcml0SnFmu3iN-Ez~mB**7<^cs86)&xYM&-|#s9?{|LeLm&FkTi?0DnpiAPyCRNd z#+DtC?>|0y_w4NKosVx|GST`Fya-^;8t@1W)~qB?GPTmgqUCu)wA*6Mwh%!{JP~Vk z!|8Axxxe~@*eqt5%@pFI4|=C96NZm8im*uSn)J)yXwjp}VSP`pkQ zz9AKAjeppfy#c*345!oWD;lM9OEu*UE%ad=Km~^m+>Fo07n5vUcgo>2zNmD@7x@KH z%~}R98Vub0hFL@QI_yO$>Y6dfRH# zTjOWp_fgvKr$EaB2Wb}(aM%(lG(9SnDVhzVh<_B)K08;T!-{{56mUphIIQ?*l_q6E zn_top4F;bsal7(;#;;20oiYJO;-Oe1JRm({~P~vPrnN0-3$UGF+Z9Bis z&Z(nXYBpU;mkl}ObRcMV=LOqRGFPdlw6yMZA*q<9jnT2RmWlyz?$@sQN7h}2)_NVh zI00E6k#WOZK#<>_w}J_DZZO%7-qV?Z%?CWAlf*QyO*X115$td%D^nAAtvxT&R&LQT>$paY3K#1g)O)68%{mT765)K#NC;WN;B4UX8{|OltN_-U_8UCUt z{5|WR@Z;mWUpIIRs=;v#{*oa^n-{mZ2<_?ZBkv#iASfwgTP>S8ybbspMU;t1pTMHf zTdM5jWx{CtAmIc8D%mmv4F7eCXCyN%{==NfkINa@PaxLfKM&R$gyprY%)+1zXDNa? zAq#4H<&cd*zhMliwL!Zx9E{oAKs)UJ*FZEH_*>`K;aOsNRByuY1Ok#I14B~=uwTG# zcfdyL5Knf10Qhlwc|$(gE(HSkvJ*G8*_^LVmMV>M$tgm&9A00ofy5lI$Kem0t-AcS z&qj1+0~SCK?m~~vxkRmgGZ2;jfLr%QT|iKfa9wsekzL`!X%qBe(fI)M>5u{*Mj!Zm z5Hrl{=gW->+B+gFmmfKB*4Guk7Ib3>g1Q{|gx(2wdrOijvLQws`*CPUk28XEWT=M%HmE zh|(@1e~8B~*?~-@Li?ZRg9?cs;Jh3iG+#z^POHf^D8z#S1_dElgp3DA z4M!72MjiM3<3mKWm<7NCzFZNpBLJN9KIjRC+@*<93hVQN2PQ5NC-a41(vu-Ew^myA zgcR?xJA{A&fTVhT!Juz0L@XeQ&7w(x41J8^h=BV_8|xrC$0}`(%H~uQFpn*Z=%ny4 z+FL;+&k43--b66j=8pR2i<{YGt$b+IUd&N(^Ur_z0%%QvW_Kv)dC(gQZtSgVjtvI& z`63>dOOthdj)?XGMK-I=h1|=8in#3Mec0BNMHbWuc}sHmCEHpDv1qV)Jkf5eNI60x z($ZGNATu!Je>#53FMuUy(fLe?5XSTO$VX)*?pwHx!~t31L&2L z0ZuaD(DRXEwr$3uE;a(p_RxH9^I!1tEk zp=S2nvC7kpyK_yI69RK0pQa;3#q%SZtA>I0uohtrA}v#t=TlK01?Fc;t)i_5D_OCV zl!TX*(+sQb_zmNitIr`z3b}^}@&^i!w?+j@oh8acyyA;SeTFi`E4nY0NxSx)v#iuC z?YTR50$ryGM`s1%I_+2g%D%=v4lOxH(P}Vy25b|yC7T9S6EI&DJd!l1L1#fS3&(}g zNNs@&9|kT$1wu{7Xdp1wYK`&7H=tB$z?qCVolf15qG~LhCE7F9Gv01zJmJTnN_Cj+X*d5`Xeiyk>;IG&-Jh3VSXp3n|86zMvDPw~T z2DxIoRBl0-Z*iWtra8Z537^0ikg*}}6N8|khkT&q0~jAlIU@8ijxP3bPTWVX`d!kQ zaN&Xkrl#$|pv!3wl+ZzVcb)61f!k(J|+mUk8}2X_>2Ccaz>J$h(_b#bk6Ox zv3OXH3*I!!9{>2kbTQ=*{oa0`^AQs>jdDP%$c`IXsqXYtne0FCYMUPU zyqT8y?Le5KF6`q=OXm+A$`KkOQ-PZZq+y?@w?>KOD$nEoZ20DUYC6&tx|4Y9(%+n4 zGSLvZLW5qAG#Y~Kbi(x1oyBND+LClgq&$@kx;aT;1P(|Z4;#s8K{kUdelCA$1C(s2 z`=VciD_Gv*%4uL*doXW|up0eJG*k82LkQ53d|~N7>Cr?!5gijGZiuIg!({(|Qrw#l zD1|XCAfL-bSu}mSx1KJBq@c?$NnxM#kJ70~G7-L2`gg${zj$hhrymnuJoFTs_z3I4 zj0FQ0kc^OUkRwnIIJl^~8p8dXr2QhYrr<7W7um?MkUUv)+&B^X3DL2Dm3#=-Q}5a$-Bb8KIJL-PlyUN z{jG8W#}uWs3)oHz0+P~Gmnhk}WCagJtQU6c#Q?T*AbUf?5JNY(GWZTh0w**PoRN5X zvv`^iPiMswGe0!nnjhALeFLXC{;mi}T=8taHJ_dz+3zY19UWl8tm?tG0tL!h0eiVz zK?oLPBqWO}Kwe2asOw*HLKb{=x z{{{B{Kj?JkV81v%|1*%k{^@kAx4 zFLdlPG1`7GuSjqwD3u&G)H+x?fcH1KWjr{pu%3rQ~RSW6R;Q**MKOUa01d*qy#?nyf5{VU+kR$Iro=Tz4go&Q0 zdV|DDnn&Ao6JVY-*{?x2@IJ_TMmgG4ixM$`K$W7@RiqYJH2=&#G;i8$7D%Fv*`fe1 zCGr8@XtP~|=%6g{5>b#w@~4RY<9G7m7sBVW*s29|I>M2Js(3ETlPi*Y4v{A75(i0>_5af zb&Gc&5ACKd6!d!7pMWOterWH|MUW@kXXhYX7D^AMBalEAD0XJghVgv_a&)TPnuScL zy*ou`Yinx-IeGvAGQ&KDfsLGC9Nd%hgnSW2EiSU8iBTio{&*7`n`IgVQRb?9XxMsOLB~p4&;U1jA5TOs> zVZVVro)kcmuL4NRkr418Lf7CH$b@saH(-w8r5=Y+8s(rcr~hi z5|xJ7gC5Vj+!@dRro_}tJm!n3+2ViprV%qnb5yir$5}Q)=nbvwHU>K+^WKl2;B{Mk zkC&Z$>y;}%w{NrW^6+!?IVhj^!irALJr1%1QHu*ow6T~H6RakBgk1IXi(s49danmj z=cBGiQ!(1q7Q(M{jXrWmXgVYqe}e`uS*xEyi*6(Rd~HUVMvq zE7ri*urBv$Tenk_X6rgh59GENzoPBmd1Tb}y6^(E9!ovydjE82dO=wXeYg@G?NQt3 z*kUMpzK-T^bVbJ0O7tD0vC3U$+b~jq%M{-2^D2NyE70#f_4|l*8+dSCJ7NN9Mk!JZ@K@HPg z3noOzSZHrwHnT)^wy-qjJa)`Ewp93lHyHGO&=U-LmUstwS3TG16ox_U&!5LRmlee= zhLVwy7srt(U^@^yAhd2;eb@vM%3qv8#D2n?PTzX|)^s`;#Rg|fyw0Cd5-V(^J5xj` z@e<0zWphR*9rU$P=OG;bp3`}T%Nl(A36d>>^L2#nvVW095c3@1dmH^8m(2KMzsGuy zot!%fvtV}^1`jr}k?zIzMRdp1J!qT=q7{L>OdK+B@7c%&NVSQe&)^?N&Dk6GuxXdQ ziPt~;`h*no1K&ry^v8UEUp^9>TW#ov%jLs*V|6Zeghe2cw2mBU0m0mRmsgeC{0)kz zo%gDD11b!VVf{7nY#QbSU1C4JK4r3ssReH($yfVCXIzWQY~i(UeQkjre(t5wYurUe zspz4*i*i0kz(;}vh+(~s@EsUFYDoLUM~-G9U;*+n_6ohs{$SlF?H5je|MY>+9=N!OI8L9_495W%upJ2U2zPi4-NohC`X3%^%PJ09TMvfMPfE37J2+JCH%(ZulJEX`%^oTZP zU6YYMD-;~mEF98sKCYjrPrCiZQ5uEU+-q_O(hax=_p-}BGj;a%*U+Dh7X9vgDFh&9pC^`qG82z?Xib4W(gDc?H9=6Sr96^@ z2$8wMz4fNv$1OIXo3o$+(-eo#V9h zf8VeH$P3orS|YDj_vyj|erYmxVtmr!LqMSD^tq{Nev@Z)BT?)BhaJFR-`?FFnpd3P zSHSN{0+)V4j<=dS0OAmt0CN<@oN)NK>o9(53fOD0z)V3i2tuwnHFa&iztfnSGP0WA ztE-8^%wvY;^8r5&fO1n1=!G2dRd&T3gB$p{_|itfe%)TYl)>2Btrs^ItZ}_QigmEX zR&YjgjUK8y;fIihOr=lgxd4A9sq_mBh7KI{u%2Q276uqd(}d)UvxdK7>tvDabGu}< zO0U@pJyxq)^%lDlRqVG^wV{_BcohkMil1;-#fuIMnph&Ls%jcw&pa9&q2~M{I_;1r z3z$nFiX5q!`Meq)EPH&q^Q!H18e;1tCo6el$(HIj*cyMnLc)94$2#ryTDJ@1D$a&v znA6H1aBDtSw*a+5?NI(Ak{bb8NYTDLzKie86!)bH-GT=co;%X%Ol4E5R;=DzEo!PB zFH=1%hQclB!o2sUmCiwTB$Nz~Ecilgm!>807$ts)JkJd-L6mkR^5z?W) zWCKj%b=~xU@7$QVqt&`&rn}cczrNBt*u5nXxTSlr_r3jG^IqaB+6Ay6+SSQPL~@@z zfp%NEotlRw36#8m6P}qgY;0^m7g|MG%X@b_-Zux7tgQ6cJ%{hC-*@E5ef2vJKYdM) zJJui0B9bepAQ2UJYJxt#?=_(~T1Nm^+%OG?pJAaZP)e0<{!;Ow9uhflvLH2qzp4WL z5GA)cjLdqiMiso;y&lPOcrj#eQLktp$p3N>Ktur>3p7tLyDfbq(;T_^8W68+*gg z2p%AK>vm_MHaS^az}LhX{vGh`k&yuC!x;|TH5?N#7122XRbQCsQOFHm(;7@Gl>5O8 zaNxwFSc5C0^T8t-REe@m3S<%O84qtIl=bz^s1CCd__#^X{rFZ8`ui#lF9QgBDj6F? z$<5AtBeUseA>Ep?VGm>I1~ptFcIFVgi7kdlMmGyO0j-jrt`i<5(r59z+35h_c#T-1 z_MnpE_lZtt`3s%pWdqnm7z?pCZ?U#{Um6EMP8TW!M2nbjl+1$n7afCkMW{a53-;dV z!!?DFr+2j30iR7C(%f6e+#^Q`iWg$s;C>WR2Z;#<=x1D6$9S6XT#;=+eqr^WLD}5P z&5uecMbBx4nGVdDX)W4L)RUQM-{bwiCCfmwRK?y$+aF>`P6Q)4{pOj%M!EpS&3*sP ziHT$`+5enrMM&Vt#dj?^jp#Ea?h>bsjMD`bJ2)3)5IPIexZ?u@i#?jq#F_)YzyOkx zeerSMbS7C(w4)kgOX|*GR~yx9IbBIfA8lUlU&0oSR$Wjoo28PW8)TOi7jSk+^0{wXKtAG zTt&FwRnLsfMvtB`5%8Wz?OR@02oD>VCgY`7(AuVb@Ovm7MQJc4E}xi&N5FWJJVZ9i z*5DEsz;MX{XEdTJkuU+nRz=Q|k6Lg2NibMQDOt(y@X8Tau9PZf-Vlw9rxeZM%21wJ zsE``3bQYIA({S%Z;vUJtrai%h%$Qaf9sBa$uU^`F!^%R?GYy2yc*HG*U6Y>W#l^95 zJ~Bpqfueyu{cD&T1anM4NfX#Pj|lks2$Yz-4wJTXwuLa&B8o*bPzZQw38 zTU3!x$3KjiWq_K>x2h=ym>J+1J5=v!*}v$t9Y5ZWDGI+!cezK0iE*xRbRn zT;+Ci0^z%L3tE{}%Sgz{Lan|)$Ymc~b9xjh<7J*t zH)|KK3V$Cn(FIBIze*+=`t5cO+8{O|@hcdxdDF-#lQT7!%NcOtnk#^7d1uJ$OjjN9 zT}|M6!7p!O^X?9mq2O)k4%8L&6j*SiF%Zsri|k9-FNM}gs7Ww@@Kr}!1@;Rn+KbZ6 z9F~eJrP%En>@jaJ6bacv-t2fJphY8EATs`6YB)XP%Co9lQn>R4#!qh~I-196T04>` zmH@pj=bc5J-4#^n&tEs5jTIAVT~8;9vF!LJR5OafG4eLPI4g#ndRsVN<)t6TvueuR zM<^JFf`6JwE`5=G!f^mRw}y&DC$l#kQxg3lKvVRX1YYVdd_4R2t$Y*jTgdtJ`SM-m z^I9~n+*EFhZYpl(@VRNgw1P7l_O`CyKNQp*snzb16zbe1-c=i_r3W3DJ}EWiG~jHs z_Vx{SnD-S>@U3f(9?ffz&ofB44v5;p=x5;pZy*@OAo(&hND-hlN5&7ieTk$oXLuh# z70r&%vp=alpZgX+z7NY@}RF7g5(wH=ds(#B_Y3-Lhks$-2~-zG;A5@*R11IH4!b670NoJk8==fWc% zn0!M(ma|gGpAH8+vQvqsrB}IipJ&_`_xfDk9=0=Yq$yx9o`9V2pO^e0uh*UP1(cNQ zZl~<@dgg8MNG4&o*@JQSPx0@oDwJ&RPc4eo-sr*uV8szUZPJdMo7T&soQ@m)Ux;c$ z3I;&6o2bq>U*(E{YHxyC?lGczPWV=Sn?nb@47&eazzGPsi}qI+EZiy*c1SiFxKSWq zIITA&h+f2AV8if7E?lZO`c>gRhfLNJJgGNd)&GLI8P2x{`zhqi+6Ezawwr?Zjpk$G z#j~9*8M^8BD*2w;19*>Z`c&?L;(!ORVeNAQI4v=l+!BM39aw-7&WA8WXbRTG-d`2O zeRyrHD_-TB2;W@6er=J_H7UDNds>kASQE<1&hv;MPX%n}3(y1ih=BNj%x)2RJ-Xh{ z!5IjmAv^I)FF@dj1+oUma`?hFsY2(y%*M&PR)Ri2B?)U!K6&YmPOa0$5lWpwY83w* ziyPmNx3)hvKYt_ibNoHLX;@R0%lOkvSHHrZ9Q^&@bEroRnScK2;mL0;AIekITdHVl@D=mC`8%99 zWk}c*QvTX4X z55wE-e{V21aSy|`ezA-qJaK5La}5U>O!Pk*|?TW8!15TJKb@g z;?;725Kx(2N<0`-i}BHKziaxThXT#Wygx8KVfQ*vg386*%xm{1bSlKJ~aJMPV&!%Tew#prK}uYyW4}jcX3V< z498^-!%@Zv!8{5x?f`%Tb_~-Ste44j3O!pzRQgT~j=!2aKXc%ox8J>hgIrY(c8t64 z-idi}$+_^#Ipk5!zM|z&4m94CvT(X$0I%KtU)IMdZ(*DupRP^GN3E}9>O6@@@Zz5^CJtERrno%5 z@2LW?2AnufDzUBtBEZx@c^(SYMZ!dDA+a0gyB7N_w*Pngo6&iHaC#C6jv2e%<-#e{ zKfBrm7CCpIW4iQU9`G9DK0`H@;IaPvyQkl6$iBH~3x8I(+kv=_asjA-5Q5O z`6Z$P-4bJy#RHdG(=fmj{gkA(f*F;C4d^uO=};Kx*9!KAZUy}crU0HSH%I7(uvx(~ z!b1ivhaoShjIVOlc>xwyu4dv}tfvoB(L5#HA8ALvm7Oz;x$L`b@1>N*XSHm=@6+Nl zg(pzcLcbW&9wi^hm32ciw$st@CK2=-hCld6#@y1J;R(vfDMt09xXb2G9G_`t$FrIT zFw6!W1;V#Lwn7(KNlRD^SR@c#5N<*lfRwpK_*h78VZClz?+TLp>AqsT{~hD)#Qs6CvLhu3u82q+m=v01HC4HF6xfD9Bq;Z^2OlKc_ob6Y^&~UI0A=#p`YOUkY;Wut4|IDw+ccw!cDIRr zh$a?1JHi!~rCV=6_+8Rvj)KB3fA=?8LwZmytG8uP` z)X72jDSnasvQ)c4bf4`_qZDlDsdig>GNB}h4F~tlqhz-Uo}5XCQ3o@X9FMyj;EFZA zg1(uTK%L+dQFd*zdaGT~bbW%VV3`V9OkUx%ruYU0+97sj2J^d^4z#{0FopawO@!FO z0M#Nz9iJ9R-T)Q=Tu%}M>=@!}kRXOs`S^-qphi5ZlEK7f0CG=u0?C54;l&p@TTs)U zA2EUv=(#R{QbGLildKW&!kp>h)5Rpm&dEVGYzZiP%{@fPqH$2Nhb|d&SQM=sCafYm zRELy8M!DNAp?F#^+^oBvOPqx*ZcUjjw@G-awP{~yuaK)0>87LxZ-8H{hFUhY6)gQ~ zhhCY8h+%{V)9{FjnzY6FVdzf4u??Avd>X1^-5nJWnvL8p0xW{qy48^K=ZUNR)xDGe zeUTs-slm;}|FM%8h)jb%`!ODI1h%-D$@*ou`=!1WJqq1qBKGLTKHX0~8X3a}{!qPC;ZSeAuI%bQNwwN(g-) zEGC^UqcVy#5eaUN#3&^Wmm1|b&~YHzagl?2*KvTIldsRAV*%O9-AkEPt(CdD-AZ_4 zgJE+JXG0euHQVhVyArdC_eZ2}P>p-EL}?WG2frMWCFr1#xztN9NROtIqrx-WK6QKj z$i@1(pZ;2AaV`_9XO_n^KxN7pnflF({!Ds-^45OxT>Z!*zVuU9GKIFSI=*xl ze(NU}f|<-BKb}PUv=t>O*or6+<|mQH(F7I}yoFS)gyRXA(Ldq|uvo-zPSMJdYVDXW z*n9l@v1;^883M-&cBcp|_gbh{snv)g046?l%&z%YVvm0oM&2_BA&iGb=s_rMOuHX7#61X5{mcNAj$limp?@$ zr`oGM90lw%eA*l9zkA}0`(dAaw*$~wsQykbyuJ)Oa!kLu|E&|BI8iy4SVnvlH%md( zA+gn>gA`a;W%eaxCmom|poJ#MKJ+BE$$=LgLUi#H`_aTM4wLkjfjCVni4bdt>AD74 zJNSc~O0GS@e6bH%!)#jOVl8A=h`29?Vej50<`Ru!3g zcYXaGcKed#uK1jaYtCh(fp$3NU5e9gf4~}UjPueh+Ntr69qa#)R0X0}jI~8C!mmm% znO+K=9~$|WLN~Y0wqFwIR|Zpp)Bh~{4(95QNWV2dNJ4!{e7{J*x28t)l6vtcLsM;_ zUJ&wk7EU=B>Rw2_uyfUe(0W=;a#fMQDK;m1O(jsw(8q?Z0@`CA?c$02G?WXk8VVI= zpcIfwfTx)fdoUEbmQKMO&_ke=IPwx#NV3`!TnD*A8p#udnM?PFq=5;H)QSLh*Bqr_ z414ek4PAKeg-=mev5hqmK1%4D*9o*_=SFX&Qgv|bAFDE!A+J7n?YrRG?^C#?)9Wk% z4akbObe{xqc34f=nCat36?^k<@P}%5GEuznWs1B+xT7!Ny4e-rp_gu-*Hf-|tyF~# z%&$1q7?McfMTgsS@K2!w%lfBK05=t1Mg$B0Wmk;-e>i|f|Ej<~BftUtJ}~rE#H9`W zAWrQvt8Vh>ByL(VO*3IGCsFk!AY}6M3$}5Tt7;sAX|_?(>1d#n6P2@Y6<%$WtTO9a z@sq0?M1?9tU8*~lmmPKG-2an^9Irc4wxC0$+EsV9J@fY&kuN06N{3Ma!<}X?!7*}cknFnG$KE7;546=NAZxD!y*=b)X}343 z)eX4C@l+FL#A|rQS85$kvu5mcdRy7eWcDPPE(Em3H0VMNa!aN|&Vq=_p}eOTa8n`7 z*oZJ|VRu!@IGgxVC+ zK6lUKOBY6Oy3gn7c;HopC%eX0Q9rQUj!u)IqNa8hB|pk^T;HJUus&b5!qnL5~j(`BXmB zNf%PnzqE(2Xqze$_PZ)-8hhCTFiz%X{f&kQzqAMy<_waFh|c0jo946`{An>|504-T zRj!k}v%Zto`#7mRcGB<|7(br96A8+G%#!PH@KUBHZp>Y1UnM|+lSQR6SK>INaR0$XsY`I%qU<`(3p<_1Dqx-GSTC4OYKFJ} zyUAA?$!swC+u2g5(;B}k`Hbycr&cy%8`*TWI!&+sE&0mv)^s(SGD_Lsj@I_3b~Tcjyp>+T{~dB6MfWMyTL9&I)t^x_ww9S%maUhSbBjsk>{?jarh zAraivx#`~5rG0SsJ+xc*-%YyN0IiQdHC=uwuGR12ikUDjqA#Fr^G@te9N%iMAeI6h z*_}J?nloyK+H4w@UN72;iNv~VCy-yeInlxW8{~b=4>vimS(x)`pB6FCP&<^A`#t&a zyp`?w#Ixb^ZLW}8wh&5%&tlc=<(imd``vn|3&S_()Vsv(hsOPS>w!C@V1(VZ9$*cx zw)f1b@53o&uJ?a8*BNXp`%n&!w1n47Z}JtlhcPR}<7U-pHg^wrgC@a>Sa@RZrM6yZ zyv=q@U)zr61hY1%t&dWxI~wFH%TRM&wEGg)i|8IWw`aXryxX;2IP=hewU>9fE>@u+ z`F%J@Sn~sn8$`WQ?$HdY0a9&|IX2?>EizMc*oFLPxm~)7NO=5j-{CGL!xQC1IBc{4RUTg+|^3$GD7O{tykR<2q((zWXXL;fcm>lPi!Oy{R2UN`_N;~MGB`Pk?^_{ z5l4Q5y&y?G>CR1uyf0DKncIaVormr{0>1{lUc);%0OTzv5~-%Zra;(zg8(rv4_GsC zlot+0?p^8#j*Dtoghn;Q0Hb%1ht`?g)=Rj)YZIUUp(Yd_c zWEDknE)QBoG6(q!%t4r_*#~WQ+Z$+;_5jOHsX|;Ga&gm9PL6Lj$DR@XYrm0XzZ6&2 zYYXgv%_AJtVLu}De}w|Z`hP6%w0j2W6y!+Y0zak&p&Bwh-0ED7CmAMb_~GlQFC_c# zt8d+hJPugSZKFW%2D}*AZx1F+D5Pr1sZ-!TVocn4o;RyP2r&PmQ4G@8L3g1oj8w z(clcCR2%_>N~Va0ggDwkN@rn^getQU?-lNvg%LiHEa!qqBfrcx<8hQGE+lL2q6=B5 z+3a|z+)O6GCwwg)zT%BWkyh@ISK@J`oTg(Q#B&=V1X1xdDCm(fd!gBv;Fd#dMN3B2 z7#>D#p@&k;cH64RkFMivyx-Iu=rII5k;_ zBzDmF*f9BmUhE(OZLV0^*Y zi9@=gXXy)@;t3yx9_V5?z#V-1N@=8r{|VE zM5Hp1XNq)5ta`Jb70XBkGhf9lktq_PcIvd|oqtO-A48u$y4@_o0Wa`EJf|n#BYJv{ z1}LlDhwpXwt$rcs`a1g_`yGUd5M5(rJBtiP-+ICQbUO91mdkoo;g!M|KCpYoquSU4LvSuQWrtGCa4mg@B-&wMI1 zcm?D={9!V3Sp?g+@uv@-EiW&Z&-xb@1Lw-iC(CC8iwh5@m)y0Qdnr9XKX^q`3wu1~ zlL&b+@XBJUPQDld|ASV}12fDjg6s;fGCiIRQREu*@HGB^(2<=3NG~c_FO63n9~2kq zGn6Qp%kF3cO5S!GO&G9tNGLowh*I--s1R8s%;pY-Lf%qxjckLx;RdW$*RYW3Lwo~} zZD?6ghQ@gRR`7(L0(*FU4SAER+t)R^-fC2Ey@$)(hw^pq?^9uYTjI%JBTgP2EYe>n zLpVlC+|~I5x|7VQC}n# z_U1kPpRYkQ2EeY8P&EYbD36B{Jj9c%snuz(+X(2Dl-q?mVxxM%aI-U24V4iLV>J=_ zKV5}|o6?DpRt4-FzTMx#)6PB!$R~mo+qVyPL^lywFW-6xRCAvtx@#V*O#}&={kcXb zS_ntF!{IeaM`Q;gT&X`Gi2v-Z0wtO^@Ll%UW3xcOw(ifHX5& z58U&8;r2W1D_9N^-0>VpfHX(A3GfDz2I>>Si9xBnaB1M`W4@@@9W|o5 zv0Qsk(=c2mmocR}yZtMzd!~aLl`#I_dAEAL}Zu1(a3Yq_$9yik-NvF3x5ICDAR|%DL?T`}?DV@GMa(5;lk5?PN3x?#j9o$XWS^`5 zi@(9t4b+of?PbQ?Q@!NySj&J4}x*@J1U4c z-=OaCnDf_x1c@WFEgM0??(O$s$rW&EPLyR7w5cGCy)Hjpy z_yH&iC%`)W_3U;^`y-H%YS51eG-K$v-yR7B4h}0O6&~KG!hXa(rKl^pvm;xaa#jn+ zHMKZt)2`5P{IGj^8D%%T;JHB%sfIF1RQ{ zKl)okblG%aYb4v7;2F)^X{wmAAJ?{L?TaAHTujYt6K0O)G?g1Mo*Nkb2kAOKu8r44QA4q8o^7H1oqPDrl9nWJsAy( z(=9r#*qly&x&?8%g>bq#-^!$jhfcSUCy1(f*5URFj>9g{*i`^#z=`OGNCNaDSQR;& zz?#df1{Ym~!v09&CK;&4fZI%g(a;(w5>Z@(BZK_P2nH@N6^7zcvfbwQ+U$_oqPBt% z{TixUloKn7a?S4oKzMH**OfS6Wbi-=!1I>KPoX3G3d+C*Fr)u1X`g2_K)v5jrvEmz ztj;xi*rG_L-z)zrB5a%F__*?vjpTUh`!Fp~cK4@+9|k114-4-^9dK#)p(aoJWEZZB zPdmJyBf|Dl!@fjB*q&OSnnHmNO5CTIa?pb%5B{&io$N>GQiagf7$j}vLIRZ&Qx5oY ze7czkfHH6rkhDb`V~$hVXhJCAk{QK|BUEz^`K+`gStk)Y7E4rta1Sj2cxdG|pwx`9 z(Uh@hq(+(Joeqd}3FdIv9c&9(j}C^6NZ@~rjK)+oHX7BD5!!Ai)Uel$d8H;$0K)CY zgU;S4IoeI{cpP=oWUm*~-xeSDHro!$m;-+Y{UMVu8501q(}HZ+1ag0d2&eE0)3dJlVade@aIcry3q`J7Ju*LD!T?SHaz3 zTf^-q1<)3ZSvaqWA?7-5&FLn;aMo1HtXH?0E#qV;#zXT5TFfBM2qqaB&Kz***^9cz zLlk*DM3SM>Y2Hd_QXlkq6%}hBsiI!fn5fkxYc3ZT>HZ!FR+mS-7)uhRMoJKsVX1^V zBcT`w6=0VEUC|^0=LYr_-88sF*+_c!=-C@@JbQHZU8>f)r&776rKyzpg&?z#-`@ma z4bJ^fCMW%$^3Ke7Kjoi%z5Th-VsZ32yMJL}0eeRvyn0a`EU4nwbt-uu87~y{5*_x(Oi(#Bb(B`CVTA!{=qZBUdgyL)>qS~~v+yA-y zbK&gC%z=5&_;kss#}-3c{PotyQR~IqQ8)1{$Klm{?izL&zbkgGe|3d^jzk}LQ}@x^ zf9_4sbpQEwHlisLESZbFy~F;wi#VJ4m@XBk$32U-n1b!1W`1lw_5YRqO7blC(3n_n zZr{28T?68q8d=9(S%=@2L89TNi%qQ6bso|s!h%Oo9&D$XlG_TEhJv_wUgn(rydTl; zN+Q8kcB&UXvbhFzrn|C&j}l71$3N>S{kNcaD1Cf&>oR$_`Che&eVW=cFh6x9 z49e^f9ver8WFPU1T&XPphG#+UIT>J+tIBX#>QegD?{KrbzekPMO9is#%#=nJtAo{$q0ky>~rPN49 za$lv;QB9-A{@V6yafR_Z8(MXXj#~b(mME1Hir;I*w7l0Jg4}@Giv)+&8+zH}Z|Fg& zbx*SAu^;IODL9W6k1$^m1OvD?$YuDY!31WD%>BuP)`>vzLIuV*2m^Ui^krZXl?j@l zf=8t9(;+j9NdVoS-ry<7QVfPd<|sOCVMObCgLFp?!%L#J z;LSWtA@_`20&f;k85@WSWtfvGY#s~%P7A#OH^|H^lVsRvq2GiR25z);dIXECEOlVV z?cggiHmyn%h)CthrqChFP4->Qjy^h))NRfYbUWb$CoGmQDdBMmj>z7mlc{#c>jd$? z{8a7W6nHyzP!**p-h@5c2h!@RkJxvB(AIM@d= ztKMi%4Wjsx6>3X`m}Q)90&kEKMu6wfp(Yw?&DNv}i4980P%zyoMu8g(;aNuRJIa!= zHHw8;Uq{|>XMH`S8mi01!Ti^2HDs$HZ3hO{Ud0zdM}sIsQ0WN-vA>2(vIqHyTmjpG z(R8}<*0*uAu;GFLL2L&5*SO*Rap zY8YL^c-9!Y883M!ZtB6j-Gtec3i1*jFJYup80(>tqg2(4O--9BH8=9}m|7C)m*8WV z1B6;r!;~g$aT*lb!bq+}3>;V7AmytKwcNyx8f7ZBkcq{`3I4=xfVx$UPDF9q;z(8L z6`p%|xvH|Cw9y`AlaEiXPaT)7H&g4A$KN?0&;FawcM`{4?^XQyYx6Aor}MFFYd&kr zzJxStVONe|=xF}nSDZYS>(5T9lKAHYp=?#fAVK@HtPi5L3`4S4x63faDDiQ-)=VGc zT5&nr%N^|<>4+NHD9YBxht=r&hj#!_HPCwBt~z*LdJRQt}>1%HzP z)rR86f3s1<6t6zl}AtW*)%&qogBE4$&tvu z87tkf)VR$*Hgj}_jZ_Zw|K5jEQsMAJ;_3bI$Ky|=9Ea{$nsOhmP8~f^DZN&qN>s|P z)3-1e6OW^^saW%Z2CB++fLxdRQ2}EjCLPIB;t&Qyq9x0#JP7rIm8r6avW1}b{0O{+ zSn>8si`ED@6CJ&2Dk3E%}Rd7uu)L5f-#H zvbM${TVv8DlMe&{vV}^MdA+qu)w!lu^+Mt8R=pS3r%wIW6CPkxtX5|ZY+w_wZ5)`X zuCBM&0GDODd7i`?xD9;3^n-f=bp|stq9t>w>r_be%!Xd!| zVQe|xXv`K3L=Ts74~jXSJ^zL~8}(aZNdU+ALk~xlf;VvbQ3xpJJJuTgvffqjrh}7@ zb!z>qJQJ)s-hTIhL3b@Q_B@tisF&5C!*#{k+41Lm&SbVT*2#)$4-sP zVSJ{z@tN159;Rf4!oU3gyuAyYBUgDR+ND=XDwU*?R8@Ml-j8loKc-u));xMM zcsw4DZMALen2Ev09$}0_W{4jUVaO6<2r*8#7Xrzc1W39e5Lnpk=A|_ucY$PqknSaq zOD1eK*-U4X-`!oaH}@v;{=ajoB=yrn?*4Aiw4|0wRp0sQobP? zP$pe@U$N*?>AU`d^<5vGmwgxKb*O&dxa`Ge0Y?_q5h%{sN2iGfUL6?}MPdB5x=mYr zgd#5-+19ovX-n73a2eELIFkB`sv@Bc?+K#1Fy~CyLaz%Cf~q0_h+85+JakEDE~(~% zGJP9i&cZ_kKjz>%L5PO})cVaQrP6k8%hHZXmqjk$@R_O5mS41EnrlO+2K*Yo$`1FB%utiW@>3pR#1V{m z3{eoCb~|KIFzC~#g_d6tpYP02Gse<8KIUEeWl8oJUjI8jCPw`Ji1;zKmGNsw;2gtN zMs+a!>dhJJ`em}g*t?{k&(2q&#aBc?Sy$_fi2H9t^x5M%_K-*TF^||=qf5WZ;cbaZ zPk>e`m(%wi{$%n?enUbYoC#**{i$}&yqNjG+8X&{NuB!^ zTC;w}Qh_M{cmIfq2;7|%m!&E@4>UGShw(-DZU{lb{?cKNv06J0?gr>s!gzzFf{*ct zzYwLRmq>}>FJQ*>Ut4dn7J*g2-;qoTej`x{#&D1-*rD)`CQIHhz-UWK{oE;V1if4SZA`0*G&>KfbGjH^| z#jsa#`3@b)9AvNWe3U(1CcZ&VbTKEnTFn7iNEx1^Sd*~XC4=U*5T|N&9{#F%Y-VVG zSUn238NS`>4c&vndk>7?&BJP&lJ;{2!ZW#mlm7Eap{V;G7 z=DJOLv)I(C8m6Bu`t8x82}gB%j@lASmOw5=;ZT(4EmU#ykhu`OTg&;j z43aX~dK)YkgFQ?*rQ8(0o6jjTxlkQ{DSXgJ?Kgw4AT9aZ6|TU93}L=gHZu3%Yh$f6E=K zAo1XT?tDs~>%`-KojKIKV4S;1w;pODi}ZEz$`5Yv){2NKQY{pq0Rc{$udE9hyL4cZR9!g#X6~?rp8eO#HTM18x#)9eFCnLd`^053wP{MY21IrUvp&i!00o@Xh%Cxyz|s3j%S~6 z9r3#GO{nKS+(Uz4;oAeSu5?>e<|Qtv>yYOvX1_3IvNOEq35QRCi32Jfg$v(o34#MXp=* zJX#;i-kI33GE~Eya&~Is%#~=Ys5y!SL4RXBti(r8H$}ncRwu_2PC?pCdkyj#xpD{> zbCQAcL9G}WHYO|pD7lPsC`#7gDp_H+Q8A+86A47XFT_P+#C5|DS z7%ODhkP6VAlgr0VtwV)OK9TnWcr7!hAvlwq<8sm2{*31sjuVCSZ>6;bJk z9RY*zaXCd-lZz!(5eEO0A>aE1P;gcnX7EPgv4_e^If zoRyipSYxtbEB&K(Y#**OYJ3VcmD=sOZE}l{*Gw0-1-) zX74&D{ACc=7@{1+7@!>gK{yV6&|I$7u5+?4*ie`Q8G}D~!@r$P7q35((R=oyBsq>|JU!s10gBNN#~7LT|DmD4dq!Ofe2&1dgoJ z2MjSS8V63#-QzNIsT6+Al@(#Be(&7jH^k;Akjgb5d&A+md+V4J{PWupWhLL!b%Z*X zp$AbmGF72*17piY#bH+xZEZS~c5HG@p$i|_(Df-?$GR4eoqWg2%0p%tSaGpc~<^X9+LJq+lB- zF#;I6HA6**!_o>Kp475X;UW>hG-i*27i|P|YO|#^+6321v%R&f8j`%JSS;lY1l8cu zrauRfH!=@5MY%$cm?SKbggg@jdm}QX`N?KNQD%=FPc+}&`-CSD-k*tQ(3R)-EWFd> zc!e&Nq$fYswBBo8d5=1wG&6T)$E`2c@Cq#|*_`2Exs){tOM)7+(QMf~V-W2kdtY@z z!?OLd!k1H(q|fj7-RJfDlg+TE{9dO6kh9bNXgVFm`?q=}$$Kk~AhZs_MV~RBE&0Uw zH6@y*(V=r9XJVI2Q^SwB$_BeaN5QNMc<;f3crq9Zswttx&%UOItCBeHl>>MPRDI~` z;RO~w3&FnnDng;lu;mia)$Sj;i1eKiHcXaViIbyI{Qwf!iC8n7#msdK1RrYS%^byQ zl|Z}@n4Uibi-CCwd4iwy2Q)nUXqv^~7P;fekDw$pApA)FM8qc>^0`7h6bS#(X`PN%TU}Zr z@b_0=LF&yiG|Uqt=a4e>`jN*lv&b7y8VrS$xGNs7sEv^h4;%B!lP7+@c>tUyURweI z+=H~jJ9J<_?9_h&2Qha=(b@420*%ftyvZF%A{HKtj7Or96va~vk?~}}Ed<5jYzb8q zZja9&43=i`_e(KZaRx#W3D#cFC5m2AOk)y70>J5Ef4PK^6bS{K2zE%%IfJEYvzg6j zQrT)Xo66*~&1Mxne1(7%g#`6D+0SfAjY>#7FHBAZMOQ@2j_q?jg4H1V4u$<5k3W2f z{qg2~V_7ZY5`zzM+}aS=Q2Lm zL^%^v6x;zc)G1H6e3{&M?{5N5+2`^2WM?3!MWVi#ptwb}+!12FXhh2`B3Toimf2%} zU!y(4ja|Mrf_>f%M-O~H@HyH4Y;-xAtJp>0%AZA1uoamVeuDMuIh))1lk#{!_NB;d zN>f?#8YQr)W}N)NmiwG9oe@?~W=^ErJx#*Z-%Y z91PhOF~lKJtZaviiFRFp^04iPYU5UxKIT=v)Q7!mCm^v7daQ$mmErIFH}6VsJ^Bb- zMo=M)Kh2&iB+N~Gb0VRW(k+mYkAlNK&&2B9Tr*d1h-2{C38*LQ|Lnr9A$~dGv*OK2 z8AaG!8P|5?SreMUVZlZTG*`d58^7|3_hUA@K+?gzSOw2o3!vp(A0c~y(q6d_8x#%p zSYC|FZ|UB=LJ$g3QK`=a`^6433^*Ee@GJHqc;1a=jAu4|V~8Q~=B+~%{s6q=B>v2e z@XsRgsT=0up9_DniH9_`p<RdYJUKJ4wL(PH^S9na__hy)^1AOLd?!iS%a5ZwbZ7e47J{BTY(%`+E)5i zrz+<)EgbV#I}is<*Bnkqv(9FxpwT(|sb-%;s@dmozM6F|mR&|Rh;<&S_U~ZLRN=z{ z_D5eSEs7MEp4G95!I*GB*ATHYGR=*tA5Bsb=Iit({S)AeN2W!sjhJytH2R?#beo_jg z5~Xw@q5~&h(Ncvm%Pu2&OVEgpleb>ikY~RWjZ}1wPERcHo>3U0U7!84Ag`f}HHyOH zNk7VXb^kVsPap8rPo%}0N()nS3lo)O48Zn|IFyt`G8zf;(F!fc9mlql9#dXCGae1r z^hhCHN~H9CV}+Ea1ias5!{wUE9|+%t-N;U}m?XD1-L1nDlho>lW6;m zxW6pT7{-iL?!WKII9ZRrLVQArW{+gEO<63)ab!iBjc50jGO1Liv@aW{bB)XKBbz^R zlx!Q9Y@IUfs|6~HDTDggpq7qc(JS;5rpiIfA|JMigt;@NOd6MO7y(8PTmp;=V-94c zGo>>>+nAqkyaG!HRTN0SAVcSWPP`V)7>;pwmWKMT63X+@G*wBBMxIv^D$npH*+KW^ z+bAD+2_C6qSV3InFH|7hbttM7wTD7Gji#^2$V7sir72^LH>%AHY{vpVWYQpnB$x(* zEE2cF-xE*P6&>YZ4pc*j{El0qlg6DX)$12sE;&3Yt4E5N8CeTzJ|!?aW>gBoWq1}~ z!uNhJ8#|_=YlKTif|DoUm^)!y%*k%Fxo~)45}Ao~ZB#F)z;;*Ocqa6#JYRvMl-O~P zLE~}gMop}29eHB3&hvOpzHJOgEF*SCrX=#3fW3<(r6N-MPyf<#_m_gppZQF;x7hv6 zXKJ;FvXhzKUrl8uZ-P(FG|dhs`}*h%CvNjX2Eh8*+dc{zYNn}>mYP>Ug3^4a zxw4%mhRjpWi}@;YUy)TxFmy#oXx+IxWmHo{^jUem=e$qXp7tv5dHef{ zK}mIYZH2@;B@bh{Zl#v`Gct-X4{-OXGB!*2h!oqbP!1fToD?9!oo0JTy}^V1%#qaA z5(=`9sMZZ48|BpO#jm4;#6)Bh@l6(p2cwWVgs?uj5=mwcT?cygja-SqHMm0y5Wl-# zb$OkfX!Nk#_17q5bBbK?%o^nWVybedbmfH+>>%j&K;|%pPHqP~?8hoTXu)psH)8f6 zWw{`tW3;I0NYp?Cp0>Vcb9cuAUQt6#axTyCUm0Haq5D{UI|J*E9#PKaE-S^kdf^3G zy{GE*R9**L>i;?AQ{qb0MJT-)K=672xe8p(V))_+b+POl*LiFOizv- z>ixgvlrrkgOriZTP+06jeumR}ITf$h6F(PF@2$Aqm3!6XKb-a|dRTR{s{33c;Iqex zHtyk&G?np={_YmQ0BgjG_x9v%7es}{D9BFxGvP0VUl_?FLun2gi;4NfkaqxKjn$6S z6MN_2C_D&U;0<{HaFZ$UjARu6MIeexDgg?@njRG6#mb4mLQ$wy>&5W&q*{oTlhaZr z5MGcnQUHIy(EGX6qoGK;IVOre`H_?8HhloTxoG^Jzs;N&)sn)`tCLgVLcNN{O>(jv zEvOSRzIsRrWCBz8JA&^&BDuVwv9vxFee`yvhEC6w0?;nkYlt8ElwDJe7{Y3 zz{$R&Q)wKi|1kgfE1Y`nhyFI?7@=m>FfT?Btbzti&I1)1D!d20K8m-EA(0D6L%X3T zwuIu^|Zk1*M)=XgzEC4KIRYKHSw;Au}Q-@Rg0&>E_AEr#|eh< zBdVb}ooT24DI86W+?|2Vp z>sqw;(zTGExyQAbEkM3frrCgsov!=eB`FcsSn0ABPV9PpQl zHSz$s4ijaaAqOfm(z3}yZp^M zQ<;!*@+j`vcD~;KajbUl;odiXW%GHL+PG(fQ_~uPd{`HrW^o!~b+RRy-sivwR1mq_>76Gqu9_XeJ)djE)y-8K{*s zuNXa-89n=8A@4y^mAUPy9Kq7uu(D{`G2)o_oi8%byp_zb0!TJFQaA+c^=Kfa#FVh$ zP{Ofb2r!_bpc+zkp?gkI6NzfFn&sMX7B3SCb;jY0>Z6%_gjCZ=J~OIEZJF>ztdSVJ zw?J58OM(_OPmx1}h9&{RLP%ccfdtfiVS6{y;lrm76>9}|Bt|(?-X~Ls9(12R>p^vT zF`>Whd`fs6|CA~oqG;}!9Xqfm}@Vkk8QEF#MuRm3VXQm}bIn89L%ZZ(DM zKCRX1nC-UFZvW@F?>@<|1oP4@a&*QW{H&Ueg)c@z2mSvvO3FX1y zSV(fO%eoh8tr&p8S3@D!cfIx zDXKZT@4;X&kb9Ghoghis7FN2&_h9C7bLk=z5I%z89uUO4zziuE4c;P$q^pb< z9>faKCB$OEcu;cpzWl>3m*a!NQDpz2qFO%VbfJ{!_V=QS_D$|XGY*S0bqpT(3h$3p z{h|!!-0TT()_{1Q>+u0U9!NVp2rvbBdG?*BPdX{8^Dn+B2#!bGp}UDM+=OUDm8OL6 z3kWdYH*ygZ6a$(T=87Vi!>mFTdNsI%F{2Cs<74H=Ea|EN5x_K4bSAXJhcuZ`ccf5t zUlBk_xJF=V$>ZU7#HZ|Ep9_9SIM%Q$L?C?%=bTG#2(mGt^tZb!}GwBB|+%mwN9 z(AIFhhH^*48FGd^Pn|N&pUi~rJMVWMuWO3SQF8dbjx@%YMma&rG33UfAR9MG8!@;FN*hi};5y4}RD-3IVqYwJ`=o zw#dTyFh^mfK!!CDY(iQpA+2KpB7hIy222<%L;^mlz^m|T5rW4pl`1jBUSsKm?wBp! zG<9&*Y+SBL!DLXXtR9@2MfKP0$>?Yp04ol`?G2X?7ia&>ZzNl-)`uPV`EV;~_|LN~ z{Tg#+Q2VDbQmLa1hlf4jcEUeE7CMJGhZxhL#YRbqZJ_)FOsOJEO-bN?X$G=g`AtfY zUQE1cvD<2ym+*@!J%IHjB3JTclO!V75yepw@L2R-$pL`h#P2-r1*!I&4g#Vbhta-? z4hxm~h6stodn=!D26m@J@!fx&@PcA9x$p_f;C~jV0j8G|g4Vn?W=6{ia46U%QNI|J=MuEh$ErNyV>4jXH|BQXjUP zDhSDd#iUlsnA?zp@I~N?ML~B3K1D|BDq(`Omk<=P8mOo?*i;8_Zg;nPD<(C)usW#F zI$smM|Jvgsdl?sls|V|8+qkY#Kb8iKVe7y)Orirr=Huem+H+jwp(O_`1RF%{)^TkR z@vKkCwsBFz4!cnZPe38li1u1PoIB*AKv^wVhqH_IX;hOAm!IQmW$c;4D*U(CFJE3> zMP)yQSQ6jr(yoDqs-2E;IoDzDG3+kDMG#Dco$O*?i}tQjcGs+H5n=&YS9J2J!T}9{ zxQ=_5XO}~S5ZyE(g;B~f0;Obi`I2?PF8sX02%jhPVW-yK;C#H!?wK27qWM8a%y6f3 zmc0Qb5(7dS45edlZgl>sh~vdig%aNYTz@RkL6`5%jmJl^)Qx1=&>fhi)YaQIHEEu> zG5eX@dh1nRv)B2j0xtAArz>_=RxWM6WK6Srov&G3wZ} zO@PDFD%dtcldu~2g4;SeS_4$lN!Q`%A}kmSBg|UbJC1B)b+xy|F12Y`gX?S?lGD=p zmRZ3O6+8{3$JW81C#%SoH&z0stYEBe8`bg^iKR=>-o*sT(74pgm#ypr>)zSv4^~S_ zU~@62EiJUy8mDQ{Wp*4ZzrMxS9mi{@2~?m%u(TdKpR^_71|t8{Bsu=x>OPEUD@J+YHssA6UL}5l{j4-KG9yZ^nJyfW+ZuEk7r@I!D~( z$%2b>cz>vCq!kO*;a%ZH*Ed&JRVtZN683hW9m5&<+`JAQxCve2Ufio{6K&gIia_rr zQv^P7GW5w5ffWM0r_II)tQL-i)Hg*4z6)JJRU8d?Xj-jsw9X^aBm9*v2)fgu0S<}~ zj%sef<@a)gBTeHlQFvd#2W~*JyJ43+%B_&z7kJUQ!)v(1o`A|r$xDjlaogBNX}3G= z@^Bz1kKeQXZGjsh!bPese}^Au5?rI%@lu^C&bgdh6Kp=*LoT)d&zx{>Do@v$Hxc}* z@Cx;RK08#qmi=MD+j6>tTI@}{nEju}k^A};?@mW1KMDnFQ1#CApRVv}%nxqU=P>6W zjjPsgw2uHV(?3>a>ogS5JFKljG3jS$sQ%Gd^T3MD> zK6JIF4L8ug7HniR^=&iGf7 ztuISTc&G=I5pwG*4FW5cBmypOg#Blwa0m~;5E<-&L=OQxZ)*{Rgm2*Z3<^LI=CFtx zfCK|Qos^3{LEZIjpw-B8u$mSf3%e%QLR)~IIW#cnfjou$B3*|{xS39c(lw3ZJgiI* znnyHG8zml-&Du+1pm0U+V$%uJv!VRPe`E1oK%>{5h|Tck*y=00eJs zG3CuCwec%SIVo8?M7W zuT0QR*srmzLW=J^-XP0BGIt#`%5vxkKL2@0kn=cCVU<0v&c+SD$ZL^6<3}Gqy3Vd- zfC=lI5ZXKc$I!igO&(xx$Ht276<|s`^WgUE)Kr%84e@_h3VQz&hu8;Vx{*8>rsD?r z0fX_i$RU0_W?yM9lE9Qd-$axTH1T`10QdOK@ZYsYehB!AkFp{G*sLf6LP9Uk;bAY? z?Z4u_q0C0gZlP)%)Y$D^jf1}PmYPk4?0OS%C@XF(d}~N# zR!qpy-j_%RTNPH&R?H)#p*oQA+Z?@oAU1OZWBv*c5<6T6(OJwJPx;;!vA~v@s?TYw zQ|0gvKph+^u%_Uppj3xCA}~;D_8?NIG5QYG4*rxg;`Y1-p=F_ViKzTNbRSDboMIS> ze1vjhO)~;M=74{bEc@apWyA?g)WTf?uu-Ug6+~f>k=WFWbJcnVs2BKC#S1((@EX0l zoAgA7z^K46c)&|ab7ICPl)}W7)S@0U7E`BU`uY>8MI`DkK9Q>Fu~VrI|KJIFvb9pK zN!BX+l9QqJeU;GUZ&vozLK8Tay~Q4C`zkej%$6}tF|nB}9j2}K zVW1BRBkTCtLcn@waS@$)HeG|8{G}bZWar(H_Cgn9t7!N_pPF2l#Q*N{G7=`1H(%>A zgcm-2ls;Le-H^nSJucc1sY+nmxWwU5EZMR4AU82zVX2|)p|@g=2+OxQBkxlaCpV{05@WrzZ~uB* zXQF@>8quNOO~dSc!#*EQym@?EDZvG~%0Xyaq-DG+jh7K4Ku(3(p?4cybRsZ(ANh!PVzfBRG6|`|?p;=81yu?V zfFB|9+<^)(+J>owh(qL)>c{^oR+td8*CE+*G<%V9xZ^VtjLCs-;hhZsA^h?va)q6a zd50639EfkHBEs!>?ENYHQWVNy-Vvr(BL$L2tG)msj-Zv$s! zCaHG4>k!!#;In^QNaP@}3$_Q?ufXpB<}>F3SM>+0bppJ2JwU@pD8J{QH$Ir8H^4sv z`&@d>0l%^{t3ot`&7pzPfOj0Mxi`bsR+t*dt6L@3F$&cKge-(05PpFx1P5gUh0tJz z@LS*f%(Le4xCwBff2k;)e>6VZ>6DRmZkT`<`g7$1A>1MWg&zUFF3e@9@=9G$QC=%R z>0>56J~P>82oEBRcZgQe2EXGRQWoFBF>UJ@X>b&+HDoVva|8o2Q;*3P?@-3o)t{H2f46+)5&6DzGQ2_<6XfSL!9cbF<%S|}2Vr0q=!Jqrkl9t9 zkBXUth#aL#!5P8wWDlXP0EZ%{j1ux5Ohnr>@2_4Zt)??uyryLX{%AzOD>TW=&gb6l z6yH^x6`r}ZkT~?vRY}DX%VFuD+%c!gNCOddV5-0m-^hi-vnAAunGZ4gz=#ctKI+Kw zgVIN}`!`J8E32dwKPa5Qp7185E9h22v#8}=7iTl zQ44fOro0Ti#}aSrLVG6nFd3lfTw!{)_{rRNQxE+*xHg{uq13aoZ_)s&@4Iv7&|@iB z%2Z~H8&oJXkxqKja>Oq@P|@==SKlQ%-_CF7wc@N2iTVRs z4XC-PP4BJ*JqLunq8tB}t_ z1f_o9`|R%f718ndhG*k)-^G}jdaYZ3uwUAhK>?@D*K4R|8At9Y=B8VtB3RsQI0I>W zLE;Ev|0YXMxuOw(^ye^B_|z2PU1K&3io_FcAE~;+QS@-i)PinynXa zNEUI7;3s&6ua6pztoHS<(*|;l7~cDSX;wJ>5Sp5~J_)_nS zvn9b#R9qu^zW#MB>o7*YPIUIZk3&T{GHRX>{h>D0-54Tt~hccyxOLex8JkCx)acRxD3eCWn6kuc^r+P8HMe0yls5UuT@d%eqS=zV6>>LC-J5F7>wUQI}* zqv(Ej8uA_+JTgYHvBSBBUx;u>Dd_DMau7bIO$h?3pIQtn7TB%;q$lHwR03$HMWNkA z;tYO(a%5^=d1;BkuF;dW+&8+QiZ8FM03sc~!U!^Zq2_JWV30HO+$W<89;t9#orBZ# z)sZf8S{4V@)2j?c&kD>TsS34dRw)UhuiKa$9VLYaySjm^z6^tN?M%D#QSdAF~eicD3Kk>K4v zvMqk9S`Y?=W~YxxW%HZM7g?6}{@33fj3g_tMSOP$H`6Rah7-ld2fTFJTqN8M9l3JD zca}-X=5DlapbQDr0}qdI?aZ1x9&=TQ{=|_yA5TyWxc_>mAuxvb(8UAXEgUKdz9ZAw z!Hhsp*W6A+VY)KuakQQ&Kn&Gx7v573D8_wSUDg%^RvV#6WD~1nnufBbVy*UhwgC}u zJNdM8h_{#(UUcaF?sApyI^?pnX%OKshwP+0OPZG!FHzCKoj5x%)6-pHdkMmAg`3DC z3#QXqBLK+@0l!}z@M`k5eWgSBm0|jpI?Kiy7-i1-U7*aGRzP8&cN^}S`PR*3ZYGrA zsmR;Pr$(*EBYzwtDNlQ%wsy#q}&BX$@<&?ifL2*0^C@I)hcCAobB zO3ay@cw)J>YanWP3{_0rTlm7-#D1ij49^!#7ZOnoT71#H2Z9w>ll)v(RgSB&Ci{Ye zX@vVDh1{59&u<%!+Igpg$*EEn#T1G?p8(14kORUefU>{Kh=vycjprBvF0&MV=*!G3 zVT*B(5$!p-h6glpCK3!sByEQQt!|%U{Sob}Iy{Bc_7Qz!msw`76|T@wrX=;A*i8gm z+usZ%uuf1z2-^}u5p9B`0h78*v&)z(RyHjUUD9;uWVP!kt&3^F=)~cPnQ$~5(!w;g zzBYGraA;kOmi)Q-<>g#qe>$d*CQEU&tjPPrXxl`-?Y`rbD_}KHyVKSO#LgY>0t|#* z2p^W;59KJI>dh9CipJyIFiBI=;td_ZXmR-ZTmGz zd0Q2WLKQ=&mF>Gr2&sZhrmn88Zrf1O$lEPy(8qd9WYG++P0l(7VEhAZc+ka$*|qC- z*Iea#n57o%veiLd!+j;1xMIy+@UT?Njrxw7`%>a|}|6tlkhV-sewkx?>~& z491itbTEONBH(}IF{3bae;lDuVQvnLLDS^RFs>%DuE&RIA^wbyARNV%5>n5HSNe|R zH32!q*8&V^IFLIX_}2`7fD0;gBb(SxC14)mMVZLeXgyr-^tgChnBGe3)yG}rebO%5 zO8nRRh6u?cmg`2EvXeG4rYxawZkS?HtD(!#Mkibx8@p-jxel<)NMG8nMy=Lr7lFCf z7S0;~C)B0FHYKXF++UAGN0C7{i4@a%3~;DX5zwrvX!EWrxKMRno`i6WCQ_ z#9Z%O+P3PUMp|akBa9?#jd7iV_<=fs8&b9*?{TAWpZI*<5xTLp0rxEc!SnZCF_ECXZ|q8NdGAx`(tk!d1EpzlIINhRF6psu3%aGl;B2 zco8w9_Am>(i3E@jiYdca@@g^(gD{%T?rIh;CV+G~I~w;(kOyJR>rJ$h%)%Vp!p}OU z)oupi&NL4*c6W2|TRV|H%;%lW!RZVcY&{2X=x?YVG&f5`u{*DO7}$>%df z7ngCAp0JZlBLj6v?p19GH%yJO>UK*kk2FVr)=j}_s4#~RjY$BHS(eJ`( zZu5|30qy9_*evrbw0ym~x9D3x5|1CA4mBFVz4&*hXa9cB*g`J1z<6iVL+c!+3R~vo z-o|yGuHnhJtH$xY0eQnSaF>-nIUtkKd0n7=?0>U9_FQ`}ee8?ariQNVwDwSLRdAbP zPyR4F36dGyQSBXJ=MAIT>Eznb$2!)Yu%p{S;CmIvbVv0BD zkFd0pTJ_`|C#&*o>VQ{haOAOTwZ+BStzSxgN_wC+9tY?F7!@2XNn%LODrg};q4-1K zQY1@_H1L1?WVL$oXgzf>g1JY5iyrpfD|XF8zEDN`QTktPXc&Qo$e?RYHR?u>51`yp zND|m9!tdm>qbD4`-yuM^sV{}V7|N)bXc%xt1NdlIWmHhQfNWw^a(?aQ1fB)Hla}G^?Xxk zuN$34CJvleS&oQdwfBl9)X)wAy*pP6#{i^8pwb?M(TH%3ig2Zp)qMNl0)f`lL_VeTW;!6_zyG!__z`%-lxO2I}!;U<8dL9IxaP|Re% zY6JDkKx2lE^}O|Oz*%km3P|DpFUoJWTc#llDik4Gs?d4K4UYIc>cvNCa>DY&BdR!P z%3{sHnO9|vmhq}i>8O-QCoC<5^g?DTlnJ5DOgywO=`ak(U z%;n)ZV9)6rq3?!f^d98yz+|kkJ;>gJ%eG7-NLcc%`Kj%m0DuPcgI9E_uZuZ}Wq?5BJaIMiQWcUskJYovUkqbz^Wo zwI(dq{=qsGUt9KhBxqJ6O(csVbDRA}(V_^lN^cg;0U5o{8hI4xw^b7^5xD{?Brchl zNDd+n*br^Jg3OHSqEjh%zW#MXSQIJ`KP(_}ze$KKwtr-I41(=0OcVP)rD%6@V~!1GpyeK%!7g_(@vhRN z?+-q#eMLsj2$DZP&f8MP5JJ;H6#n=;c@9mml;PT$_bJNEb~>Xi?9-~ z0W_dPP-;=X_OCx4a_vH^+cGBhbz!wbrTUtNG(lAbHs(j5#$Y5r#-C)A*ZzksgE`|u zj*(hUEv3q;HZh^`m)D2KVRn9a%Sg`5mM|&k{`{%%Ji3f0CM?zH+G=crMlZv}@ITXsq&~Ur1ErKR2dU zzc&+}5gt#?KQVJYJo;Qp_$gP_xHA;K|3lbSnGVeThbio~u$s#aTmyS2_r-}S*vLXJ zw9O+rKmi!+yA6WrMK{KN)5A`iB~-RsU5vO}YXft%z1V6ku5$hBH%_7eA3wRq$;t|9 zGXlQWN@pTfsiY>}RJqwOZmztM*FMsG~zJ>teM0jZ%P3l(5>kY9fG$IE<156kqcfYHy=WSv#=4+e=`3A{Kjqcf@G{S*F#0 z33+JKLtuYI3$+GBjFDZgiq<(H~L)sIB8gIF_b2N2gG+$>lxKH3hmFh~pAvD4${w!+3$rC!5OtivhVf3ZNZq zOBnDuPh_HD4d{_BUX+NWG%$8S^fDISa;m&xEY?<5)=VrwQ$UV%Brz#Yfu?6s37?q| zrxOvPyhYi3t(QGhqYoc2jIKfOzXruwI4^lTf!Y8f8May^7)U7DxWV-Xnrf4ZT2#dk z{8h9oNNoRHc{U1_IJ$=Fz1sClm#(+5V;PgMg!=mADrP?67a;M5(tz!A(24kY4S}xI zq-Z>ypUG}v6v;*m^4AX#xsj!#;zRgXte%}?r$R;QDqn-J>T|UFnfpfX}paLvdW06)I?p8;g3bFkKo`i+Xm5g8q^Kj zPrL=k@e#5~u&R-80(nBeEYq6ON7=n>(4>O}hjot49m2mJ9fEX)LkAGE4S+A&ngDgN zZ$%Qt*@W`;WqLvSh0|lBnp@71y9n?4Qy+cNl=J z>l!D|<>sa3$HWOa#rb4oV zFk#=tdBB8_L*!T_=e#(#t73_HwWn(T463NtVEYGrmnF>txihzQL z(o0ib@4v8R2YP)6VzIzkGur#FbiXlEfMkYOaK0$aCZ8?hE%M!TqOvJRO<*tE5WkiFGy!D>-EUJ%_GyeO6FXB+vOKeD09ch@nLdw`_(aa zTyGhAk`pPz0FeckervPwFV z+19xw8zYGHf07trXK@&#fNDO-zeHER#=dQSkzasRfZF=HNdlt#B=7AADD6#f&T>@^*?<)_@QV;f4R$yFa~L zKq~84ao(K^xb_t;ygK3@RnTrxS5o4U$Boyu9Ao=~QU;|EGLU^G;Zx})B+O10qHRGmKxF6WhilI@8C&IC<&8~f^Q~6zc z?0jDNAsN!NGRdcmX{y(oI^6Vdc0yI;B4KtOJ;3S%GpN;BjKA>7mhrZ8D#?DokT5EjI;oJ+CK||2B|V$4C`+)m z_mf5oICx$nPa+7e490w_joY+n2ND$Wlol9#`?fGOiSIBR5ro4tE#@}fISl~|1z*Na zkaUn?z%3d8WijY8qeXpf2_-ec@I$(hgk>15l^RuSFBkjf0i*j*h5w2*sbHTfqL6|# zagd1MA<;rn#0I9gt=>S~HuBZ{tcHfy!-J!wU2G2w1pTl87>RZ`AzW}tAkR^7Bu{Y) z?=pISZwL!0YP~rv$!uhfzeyAGD0*DtQ$c6TtEP@KN^Au5!bFG|Uv`}eY{Yc%!x z)ZzF-G5#I5&mRi>Os)1VmmZ2F0`EguC?(uJFS@lP1YBx9^3xGdaI8UznD(3_d`&y^ z3k}tQ&d-)I#1PH9Dr8jECPZh1>Ex!ust~ab{<;`H;ZzdQ;N7>aFTURII$_cBMn>D= z$NZXnPz7KBBIY>&>Ezim@q&gqLBnB2=t- zrtrkzTEiNkznJz+CN)Q&p*e@D!MsDy!shQWAA?+I6PQVw9*L0OFEB4Lk=7?jjo zV>_HNC+UkFK-49E3%>e}l*?U`XkmoXURO|exuONX%NNEZlmW}f7D;U}8D0dE?VB+f z*A@Xmz-1`EzcOp$j3NY*BM^%uOAwtZSLT}ZCpg=rzdh3e7KvJpZ&A9uupr825?xb8!Kp8#YW@Ug932@xmkKrjrs_BeoJuXMZJix;h} zgzYCi;Olle);M__gJN173y9a{^0N&pF5o^QKN~TBWN_+(um`8k-%k&-7cb&Eo31hh zFTYBOmu!u);*Jik2F)c;`3MX#giOMr{ix0xTMCjSECVPcl&_?c_TD3eSzCi-N^}7j zBo>pdl4PXKMztCm*gPWrOvI=P*a6YLq>9DoRO)>sPL%q?T?19zNsB-iT%J@c1gMYP zvct>HNh)YGo@AG6#cM$oxE{htZ#@nrl|D;Eu6iBIy=8t`t~;#@AH=MeA^UMvWFR%s z?FJRPI;>vours1wft#R-*>gmIKmd$dMJb%fD4$ieyU{1cn{gd%g@xDm+HcEbV$EjE z9PRZWJP)=4qcNXycSw}pOUK9V0+8iBxmYk5Gc&z^q;-a?4PP4`gd4c}QR=1PiQNDZ zldp@_qmkDp<&pa%ktixrZ27t@JcSu66J{P2pQA1dmL^FfBULw2mqUCrY!DD4D%iypVK;EEK57*r1(P zNJJy591O~8B)YK?q)yU76#1b9P&M0d+aaV6Y%G(;?O^*qtxsz4JOW^Il5y~+K)@Y! zI_>RK_=V09zxM^DFr&QS6{JoUPVh)vQG_edG4TFO0q^^ccIJEkH@%%u=-jmSzlZxw zZ91dar74=hPYvTYD^RqQGJK9YLW1#;_tClE_wiKkiJu+!g#wW`W&NG`Y)AMJe1fy% z6XAnj8<){YCzW+{vhyA0QwGHw!ZFJOOHq(Bcn3xw7)u_ZMxH$~cG~I+v?pj)SXb~Y zvlvLBg87a^2p%5sBlcx{497IFJ(3{!eMsLTUi7}{3j*0a=qMgN`sf?o{%8H~q(7s< zhTmQAy5yfdKOG823U2=ip+l{vnHocaz6<4&9~noAjO_KM(dQT6gcCIc&~ovXv4}h^ zd(j6PKLUH$Kw)?YJcGAscqD-MvB`n2iO$V768Z}6CF2KuPv8DcnC4_>)rZcoT!UkA z_%z*1mzFl22NHWL1vt;9bHFAaBBZ-yt#9(xQKm3uQBgJ~ZH2U!Xr|Nerct3S4L&A; zZT|`ztLlons%eAqYQ2uCF1OoD?Y5~x=K-WT{&$!)OiaKo(J}Eun}y9olkGWFMvKXo zXOBdFz9DSTiC<;+6*jbBZrHqpPnrQCF<#R5^?qI-jik?L9h#4ji<@{kJffjnLA2R1k~Vf1;v7NS9LE_T*Wf1yrWjkMq@!$}3-fUD zTNSb_YFV6bP(uNPQSCJ>Y{1E3u0hrr%EDkc3yNhgTs=AdmJ1(OI-k4!$KpI3u?oNb zBJj7dC6L^3zUqIqSKSa}s$JJwamCg(gPrQY2@$`?KcH2Fra#)VW1NkuK% zCLpJBex&aKePP5f(r;uFPNh69#dzZzv3gat4J)kA!$t6ruD3G}w~T5#|Aq#aDHJk; zJ!g1;T;JOOu#PRyunv)txP^yR2uI3apl90shHeu81KN}gfmRpDtQssLRa?1K(};(* zETa7fvS_QMC^H#Eiyn?M0LW1Ue^`1TK;OYUhn_=^L$YKEdw^olC%7uE!)*$R!BK_) z!Xst)NQx8~hCX3g|GE|e3^0-!sEe@%M>0a77%bKSg746;gjL!1VC#;3GXdXOuN-js zruCaAr~QF))h93Ba#_8S>uBuh>{(x6X5SsH2Px^XT9&=jQ#b3=K372ggUi~LvmG#(_50OtlC zC|p#*Wf1PKQq}_Y3``z`{?Mdo=-T95ir~U8{@sEeYi)D^cYr>{abN2GE!P%m3-`IC zXIf^f)hW-HGxL!^(6Gp$d4*MIk3EOi{qVsKV|UUl+HK70$`0dw72Ykngl&7-8*bdwrg2O$`E~O-50v1hiPIA zC<#We*vH2l+@}Ux+-I`#hYr>b{SM_&+m`s}y~gVEdKqW_pio=k#4tNtgBr=kMPN*? zF)lVNpz>gR7O?!*alMBPEBmj9%5b)h?j{=C_=B5jZ*1Aw#$Es!H{dFKlMrCwD?A-K zO*z%^GVLS`T$y@#0GP!Gmn3Bcz}NZ=`hLh5&)|Htj(0jA!*S-IN5iL#>b;eh9a~Ns zaJ_jASsvK5_}nGCHiUaINqNQgDj}IpK{jU*ZgPr%G$CsTdZ#6sNxxTtAxo^c?)g9F zBnhZb?D2CsEvM!Zkp>*8CN@w@YVadbX-g9VzZcJ*y@+TvLe`y&?B4yA@LkMn1$qI+ z0BI);v2Z0Eb?|5se(D^(LUcxpHIe3~;qxl$8;TmjH~b)UhkaeRIyN4BS`CG2^G)?B zcr0cY&OH!&(yQxnf3zhEVIguTw-9TlyrN1+sKKBr374rJ;O%O&S;L=C#hUYPSUCGY zKKzvE_j%R1csT8e)|G|aAytz-IJf#F4pm)D?sXw=z6|?VgZ~=X@6mY#XsGf6jmJdx zS})=yOEDqg%k#H)dahP53LQaN46ZWm!m&6Lz&!Z#5!l;TJ&JfFdSasD8TYy( zGaf{~Yk+I2s(kbytoc6hlQDu-3`-O0kKZo~`hr6;$nW2buYY$+?YY12@Vh*OQ`z z4w|dPn74B#afV%_cQ&-FFCX-_j055&#;uT;&WznC$CfTTJV|K`5p#9uH>*7!h`k30 zPL+no_Za6~Nc5ghjeP7j*qwx1;wD$UiMi$su60ewyjAPYF(^_nar-Orr(- zxtz=A{qJby_Vdo*@zvFFw-#KbqgELPGAE1NKykutLLmh-AY^D_GQ*1s7tAPbBuYe- zJ{{PLm}+Y2h^w){6(kpiJd$e$i3^E4y#Wp&j7&MCXW&Yb9QD3V@szrLN%CKGOgj~? zaGYJ=K%*NL%V(ks+uwhJ=;AN|Y}*BQEHr2vmmKdB=A zhaYAp}RZZ6-*gMzYVQ{eoTR)e$Ian@=p%@Fwek ziSy8yoJ?KlyPznUgc~6=!p)--;Sy3X>&VSO$6=EyE+M&MWQQTHpwO0v#go-GjSlHS zz4f&<`nW^79>3?LQj!al=3NOZU`TUikPlF$XD&urj`4wL$GWkoti5?G9eg-n1UOE=T{joPnC8X~#X`h>jwgpy6qDsBNxnwDk+gxC85 zfU50)%>b)2ki|;(opNq~=**s=jiA85;2Ev#Gd$2|1|_<}IoYY<2T}@6Az^g<|1}1s z$yV_VjsYIP8yrKg%LjoBKFCs%=@g19vl6*`M}B1FIq;q?5SjP!%2i!mNb`3=3bUZx)8%qA$ZDB@4tpA6_!0hn47=xCboP z*cVU(ewB6y)sH3u$VH~t-GI-aXTulRpf?xkVU>MCLM?`VKC%Z{B2-$nghaat{B5Eb zr~HLJ`25JQ#_JA#k@Dd8fd(0`x%tLnZc-FZ%3Ed^R6;gidHxu75aes{z!l$H zDfmGfyuHaoNf$=Q-x=wPw%+>ETF8Gt5*N@krtCvEm@874tK2kk6OoSMoVXs6!t>PX zfcK4=5BtzEChX_#7@Mvvl}c{iL0D)U?nR23!V8*@^0@)squ)EGAM2V$UFu+4K|6Y+ zvyqfXflOGs;tz#=pfC+e@Aro=XBl;5N*HUpD8p~ms`WnN4=d7HUwEF-g(Zndo)1gR z9sTNcw6LT(TZBXRC~Ks_lJSrN#S`%mHAj^s!pS`Ah~r8kNJWM8l+1CRz+4Db{OHAE{P_v#Z9DML?4<4k(*U@N3JF8`)=#O3CbL0D< zUs%dzM&pSjI!Wg)X2w}~dTPSR%pc_$SjUbQ4;GVCkxU|yiA*K&hry>%tKETI8MxUg z4N}2coZ=x0B=L~owz7A~dE&NOW>bbR9~m-U>|sFS@nM)?rhqI$Wn;B>eGX8W_1f4; zpe8JVos-$@9}&secp=rWo6|;T&fN=~%sJD-el$%wY%*(6XVXV%u}(N1ijdR|mY#;| z!PNy9omdcy40ecV@dSQ?+D|+o21@Ii)_%Xhr;2n_%2pV`_M5piQ?8uJXg_`a{LBGV z!A@kglK&}RSwpc$?|VFR=YR00-w!LgX?l22rP;2QC>>D=aoEn{zkAB)L!51C5Puhc zOmfHMCw~3;b91f7oNz}5y{G)8iL(E)Cy&a2a_HKHD%8W3=Nh1~$(N|z#^I0v zO~JiQdXUM0s5sphFcFYp$*|qp0e`FtZyJb@5SpkYqYDnl+NDcp0{V+2bjV3481423 z41N5!qzGD2<>XKZTxU8{Uw;#=5aNiflkt6Rcl~XH=H*IXvT>ghiI29iy10Sax|6y# zd`+$gSK!*%CdX_|xUVZB#jM^i9BQ5LDF#w&a8U#!4XDU)SPaW5OR{oRafJ?{Bdq)K zx6oUYECg{FdnrN;%wtRg9t@fUssM$RL=P~!L~i9#vv%9ctCL057LbBAkn)JrLOHFq z|HkbYOF3QcNteUxOy^MNhs6Bn(It9hvh+zT{yvX@&d*9e%E81_4DzN~rRFN!H@JC|$~Qo~@D0KS^}ABeKb&~iL=Pn< zLwgeXWz>EVJ+qz8l*{+j#Jg+HVkE>@PTl{a?Og!dxXv?CoEcySgZFDNcn}~+yvP|o z#0LmTq$o(1EX%Sj$1*58b{yIDBNdYPCXF38%>#Cl=DA7ZmWtCPy>7O38Zzl_+fABo z-G<4{-rOX;yEpEV?KWxa+s$^nVjs7?x7*t`h4=fgO3ZXf@lHvemVL?8520D8;#}w5?zNmoG4+vH}not!QK$&c^aEs>(DUv zp0#k@KzUZdKgk$JJy^)|ffUp}3T;^ERHE}(kX>2y%-vZ-fp+K;OdzE z)?qw0amtY61r-rtN8=Kg@CzjCeNArrSDo^WNWo&wL|`l!91A3}2_qaf64{oc#n~vK zweM^_pG-wcfj}ve8Xt`?9Oy+&jCvF>88;azhPuPh5ThVisk2~%kLYoAGVDo(=>l9plB!> zO=i-(K6UtHz9A~uY+8}bT0aMgr-+sA zpjDsEInY!a+mqI-A8SH#+p&w8-h>yYwP}wI=6tvH9-CYd=-a?S!eFtW18%j^w|!}U zkn#Z6FUf{<+K*CmZB&TSp*isfP`))OFSutBp zo;znY&gr2TC8~9x=fnM-W~TrZo;Rh*#`v;HAW=$8(Rxbvm*PD4jgm3D{|P(}Bl{9$ zEiVter4$trLlK9#M{3?QjQZqAC95xl#wz(jV8NhFV4k!uvN}l}5(ep~woS2hi{&*%)&`wEV$b8-wir=F(6yPqVJHPS)2qR(B ztp#uNXS_?z%tP7eqfbrZJKmuBE9WwP9+InukDogyXznWPO%%$V$KIqA2E9&wFnC>G zxEx5$5pLfoDZrI(+90sa`(=<nep|DlY%U$!#4KVzkES^spSMKg%*UgH z4aNhgCh7Sltpxyf(z|>!6S1hnM)8L zct9YZ;6+H%2Z579w+L38F|aH2!}>}f1z{f?%758z9}q;q$Ndz%tWFpXP}gp2C9Ji( zY?am8LTjg;a=TC<%Ov%@a_pW6H;uzq#Tz(yH8d=0na% zs+cof196SUqrvb*X#>4^TBHeWQu5>$N{?8SR^I!NE~IofQA*&uu*p*bs0Ds@%yk~^ zMky!*?h^7;I91drN|-ZdQbCAE7w3qdRV&9KUJ?I3h753gL|TB37CWfIhEI9M4I*K9 zI*0N4P)bgE6W&Bk*AFLjWbGY}E4nx7CY@Q1CPOUPF@tVBsA_V{j2PidW~&6kWyfrPhN5cPe8Mj~<-ZoQq*Udr?9bqrpa7~xSi;V_?s36Q73U%9SYs8&46LmR z_c$i1&ZuJfsFWTYWLS5I4hn@Z9Y@f#IC~NBN>bJW#YgCKReX!ozhjh{%?SokA$52Z zNIkqGfS4sDxFluCpZ0rYV?4-0K95H(`ZP`gx?TfGc$4z&W>VJFpzeOa41|ryoo2)r zib!uo--d|acMmLn$xJpugadUlDanc_>t=7&Kn9_RM^=2H``9DCup}4xQUgb7X7s*L z`ZXcHFa5|R*&mDg9|TFngCBqrx+>o@mX2N436&w;N=l5mhh(3i368HPZEW3&?u_^D zqKO)GKbomMTcbY1%O_DSnxu*(Td`9-`|l74fN-n{{TW)7*ciH!jkKkwJh_;jgT_?T zy}lBvlK8MK#tqpE>`5~1mCo-E+$0kdPg$DmgBtDDC;0X#W)u+2m@EiJ^Au$Xn}gjK z@}b&E1bB;Cdv{9bAAp|QWEt3yb-^QmkMDwhve+eL(Ia0IVZ@;yay#=4-=i4#>_JVl z3rO(XmvX@W9kr&4stc6D)FYuT)p&I!Zu5#Rp|A%z5hbIY|2B|h3Zwuv8nD>wQJ6Ud z*$7erO6=Vu$m4NNG5%dg?%tVIiozK2OYg= z6CDI4P@|k-W>4&q_{U4T*8imI z&V6QWbBu#b7TVAcdEGy_2KUbY#F9U2ntRt<%)PhX=k}TTD_Cz*pnnMKTv&TWON`k% z>-+!hTHhbW{_gLQ{zG2p2m1P|qtMU)#ESoDU+49O9b296b%B@O+W#>3dS77S4}k`r z#6)Hy{*AnO~9Lz;9Djkdyzbco{KybpwB<}6V zoL!0QmC2je0^^!;B^wCjP9ZXY20IWUL$OG})(I)bLx%qiy8j&NQB}AvivpMsvT3b# zwsDYAEguxD1-UALv?{n@IgRO4&-9`{EOSOP@-ZI+xdWNn1&fXh$wlXZUW#1g@ z^U@3KuV7aTao$~Ty-$-j`R}nU5cOKkqqS^=rP0;wH)2{GBFJmIK9(pbEaiL!r z!bSw`gbU{!>!`bH`wl%bh+(060C3+zn3!Ma`aJ*7q4dWKS0O)|?uh@YKjNN1iljGq zZ}_Ch3u2=Wj2(tq?_?@VWjo-oLV@eojU0(zx-Fo;ja>h29uSz!6_L}8h<9qrS%Bd$GlwKw35BxqsoK109#<=SiIX674v+eT- zw6|pf#~Z-`!N{gumCz-O+-~2l)0mL zOg}w0{x1I^P!wC$W|wDu+ioSW?VC9^tDXO3{$HHS!?h-8b(?(-w)1iLAYn5o*0||W z)MKC}wDWCABA^-t7^#M3g#O8gvnG#?<`EUB1#`t?X}F4zQPI|o@8>^E1Ap#Ef7E+s zy0{p9o>uAk=wfmD%tr7lUkUohj6&+R+foH%?8FXOzJ@(W#V=N{gBMVEfJ^HXO3R46 zAMm*Tz1J zxs`BB3Brii&D>Rw+pDD{cf!F{f_YMiIrUWWq1T({mlCQ_`nyEodOK+(R&z5$Lo51tx-W@bQH&W#-kxuL+djIcmt1*9g zsGOe0LepF}K}KH%m(78%&tV4;^9FTOtqVBL5RW)lgTZE*s{QMUvIvpEjF6L{il8i1 z;Q86ph54B%nj0b1Ey+VhUUJ!R0@xOUrt0PL-&W5r<8y~1vc;|`ndL7lo z?Ti1AuB(^qbCv9v1r8J9K`bg7fs++hOfsY^Hz zh7U!CdzTyRVb$Ur%fDvXQ zh(`Rl=4KP_tnQU(BlB@z9jGQ`pJ=jy9A0?0%n0fq05p0NmgzJcw-xg=Rhk=rO9n-# z(ou>rp$I054W|$Yl9P@L*Uq;KjSbV}CFdNOf@GR1EEvbIk6m%@vZQhV+-aktc0b~s zA(q!GRcP+Kz6M{hhB0u5aSB>bE7((O^(zewPYp{$rN;5N3hi@ z-Y1{d=AlCy8>^>#>FFeMlFglL#f}%c3fcsxp%irbrL=SkEOuV^Kcnvim0Y64G`7-c ztdMyaA)XC(rP1hIrY&lJ=z@sWXf$-#vC*jlbOMJmux0B6ZP-c?kyr*Df(2F~`-1<^ z09gwlLK3|I0vBv}-XrW|Xe3fatQ1*_aj@fStbVqH3jNk_DHhHLBB_`WO=X^YA{Xm> z+aGn_-n5Lwn2}5daIG)o4J0F3)K2Za>G#`j+P;Eq*6doc;r+x>u2$hf#EA|@Le1{L zMBqDw6eHxWZrEAZ^@$2PqE-ZZRv-19K4c6XNm$1b3#oWim3x2Li3WJdMCVJ$)2@}v zECLdR2eR{f8kfh`_1NKP$vc%UB|To%@H6gP_NLJD1YdiczEZ0QSIku{6N_cyT=pVf zu@27wVq3a>Cy39Hi>N=kg7WT0iC51h^aOiWlo9>t*J+#B{^Dp@b$7NlTA~tZOGJ0j zj!(zF?rvXotH|vaa#?Ro2x`4iDMV~UpCz_3D8i;9gT|bZe|m$NxMQ?CIt_yNI$QSm z=T!G*%MJJh1muK>vQs9P^Mwu*ga4l5dP*R&DG9B!B_xPM$)#ja&1%q$_(f?ucvxA( zT|HLJ&R2A%gR@R7IC3e z9*cGljR*2X<^>reyT39Y$^#JSJgiDCcXg?hosS#Z6W9&-S^YjAurt%T+2hN1 zra%CIdG-4(8;<2K2HLEX7u)d@|0lo`0q&^~ z5vY#oc?p|D)t9B}l!Q%-T@B12xl=_&pbBIb1W{C~OrJVi^my-BJbKTR;+em2Ph&P; zp8lzE#Z-rGRmSrouMb@YO2sW-gt=*%7S9%a0cQ$}Y_Oqbt@FIA>~ zEH|#23M%{(em0?Vw(!aa9v$Nxj&?$?Kp@5J+Y1Cf4ZPKh=msF7eTt~n(^nO+^QRP^ zxbFV!M?d;(0XZm$x5@h@yBOg2Eocx0f5Y0OI*=WWKL=B7VArWjg>gh6l}f0$bTA=93g=MY zIAvZYgU(99i@G|6=#p)~jfTOoBs6W3h57-IA*!u%I|DK)`04mr6h53B4<}Mt94ncP zZMMk)5)Z4aB>-!S!*LzZg=bLwT!ZMo3(U?Y9K3>`_Ti*F5G#YA+JTuK5Rbqdat-8& zQEi`GcU*xZijUljCB81;4p2?`>4UW@4}b?j6}vDM!;)=pWRgHsDiN-*NEcC0;|zw7 zu@hG-w33#pD;g@rPe-@bz*(BZ1 z%5$#7MP@w0OF{%Lsqr4qpKngYlUvTD; zN*r&J2s(!*yBt7dm)D9EbBSj}$&w&TpmXL%vCkMhn77alM9HhDEa8i)1h+5pvm9{p zQqvCr+~jkB-`aw;>l|zUo+L4;W9saL`I}KI^6zj7T4=b;_3lJ~ckr%lHW=@aMPCu# zJ;3?P;TvHXFOO`CzAWjHP>%WR45ruw;#3ij zr;Qwz+0#@x7)T=n@!*=RI_ub|L2o-)zQ$50`TpSdWtOyvb)$nJBo5ioQk4im~k zJ-#r-{A>gsboRy0l|a;^e9;q*ggswWJkhWI0=u#E*MIN^){Ypy&eyz}=4H!1BhvXI zD-<@kEG{vzNnF}ej^d_Yo$MteO|w|$|f(MzVA2JQKv=os2(@+=Dophxc#b6h}0r2Gk`+? zY7*7v1gFOcup5?ZhN9N1;;7;!Vesw@+0US*P$&Vi`T^f4OrWp}@RGlGnkw2?7~k*w zUO5?_FIMvg8X{t-;8-@OD4IW#m<)R32&#~Rk)e=Q&_Y=%*myy9#*Y%R- zd(&vp>j}Voru+Tt8m8r*bStvzIpVL4_#&gWShkv)kXaHG-f9vjL3!` zTLkNQ1hQN&w1!Tr0o4X2gLWgGE3^H@W)3(b1(_3u-3?fYMRqnEY^l!tKLtm?Fgn=D%v03?RH> zD9j%DVDx*@U_r;p*?A*tSFAs>*fg2fsLx6(n$8D9;P za%K5@FQU#FidlF!)~Mjw+A8_aR@sx}Is6iOD{IPCdjIMsy^q2%Fc#yzpm)m~1o%Wl zj`>DZ{RGa0f{JQDLPOhkLPA~FATH)+Q-;HK-1=7Z!#*P-_VXtBa zBVM21?+utz)pRVp&1NP_mfe*=HW@Nhk6%MyS5GMB*EHkjc%-rIrXlxw45^OPkA<(| zE{G`B8hH@Z0PmoHbw0sX9yxU?a}f9_X8R@AsZ;-Pe>k}bfTv_?-LeL*GN-o@?%6<@ zY?9NUe~@Oy(EKZ!M*A=H14fJBRcKAyurxqSTd^9g1}r+@K?mimTOX=;08yB^5Ha1ns#6lM}Y69~uRR%2SnA=@$JY-$sM%crzy%>sRDk%S^ zT|}vfKG-M}p3;{N@$`&7vjObShQb9fEIw-RBU^67v2XGmC$doUyoV2oA;$R4%Y2~D zw^mxTq4h0b>hsKf3KdfYxX%he3mod#K(lIbyv0^!m_@fKq`}Si%8Pt`$aoKn7vao+ zyo+V-VvR6HS`joNpvOdQ88~&wZWR1xv-vl-jHVYK0yZ{~QqHkqNV-+Mbu`s@2t(`` z!#1YYX^L~$Z+#R%)x|JvGQ@KxU0+>kecFq0_`JX`AZsCXUFD;3>%T6@AZAFCVKrZH z1_T|yw870Z)a}JU*feH3XjT*#=b1&RDy3Kri|SVJAH#u;M+m%d3qTw*j}*t)<*;9DS-Dq~5>or${P?vhZJ3Ql2Jm)xn8q|5F!^aVJ< zkZ+b&>CI`86b1nf4*zum_UU4+ z&E%{U62$zBbr&LzR(_D6`(mCKFn+U@WnnP2*s8hRY{6+rgW@yIgWze}LztJCr*N_j zq-efRiF@wdr7fht?A)PE98bOb3P;B%X2gwYUH1x~l)dmYEiyl~nG5^T-kBTTPh%~u z71*3MXeah95T?-(XCR%)l=A;Q#Ye<>nxlMD~cjzd5kh(qF`K7xqztj8<{<4-g5GWrlb}#~k2+*Oa z;S{|BD!=?W>>gkWGfYB;f)ku3(z~zBoslENb*_1SLR%epc&=X_aBgn48_r(o@fXrG z0OvqCfR98o%v3TD4s zGF(Zg;bF?9e2D!iL_ml;Vaf=539TzU%Y#NIF_jCl4yV%5vlts=b>->+2;S}{5tdVM zXR`t7w5)TxKq$Z&Pr@th&DIr&NJM8;eU{Er+LPCy0VGj$EzARGfCc&r&+aCLW87Fg zm7l`@9b=MgNb~?4TuV0W8+ss-vyr~R2hjVU?H>P+`p#ACt^MfUGmX9^yz1bf87G%h zsbkaO8sbNH9kUmd!-tizr9xrJUUM;?;7KGwT>HF5NHa{c$B}S8kovz9s@1~N$5N@~ z0UO|98g-1ucj!&t+XH3+?#g+& z;2Q$=3LMnCcQB%%gl-470jWz|uR}EyR9Q7@q*Wtq0Q{I%Z^iv}k|F}AU|Bg{ff%s? zt3oO?TReoHWI-{)v$Tg_3`em+0={zNcB@@T1_DMhU79T%I@H2%VK^D|8+xV)J#z{!gqnVLFOie8kxGE%{S$d_Ej91w|C=m}$J=CJjNyU=|?_2R-< zb;zsUCF44c(~$#L7S=ATF!2JC0jU#C&sLD*RTv0`YyfbpE7p}axWmo?4)8{Q41_y2 z5I7*O(Ml$4HVE*N&Cc@!q3g*LR{*IGXMBXhG0JoBiO5k31vOCE5-n3lr=5sqRuR#q-A-r-%awrKj%q;yQh^_ZeLx_yy>k z&dWH0g19xST!H!t*^6vfFkDcY#yq0fc$C;8g5kNb4jwd;%7DHidm&Z6xIA}zaD4U@ zsJeP&F`RtKMFFM0<98iL-03DcyuUc)K7Miekaog6bm~a8d~;-C*_t?hd;<9cBS;%3 zx*>b=Cen3VkYEvsYF7v6)-#gTsR#xa-mqXO^n=<^(uXnPc<}bQ<%{K1)Ki*^9cRxAESiXy6W7#i1wfqZMJhHs{Vy@5>hB)3u(NS zUlcvuW?&yi^A+UsZ_id>(A2DAsKSjR2U z^nfXjHV`Xe(~8i`uVWp>c-LOXcVXQ9S8>fA{=n-9c^`r$BF6^Jk#5!)Fv%b+2HiOl ztsH!g_ITHvP>A0u|yMNZ&XHo$V_K{Ca>4NBN!x%|Ff#1g$$wTO519 zEy84XT4;%{IeQ){Z2Q0qJd*u$A5wXkOrYrjv@$_f(0m^~mPp1OIL7WhzwdZ`TYjH$ zyL&z+hVSaa6jn*W@XIJXigJdt2xfp&Uz{d5!TQgxsuO5fC5s@mj^5D%d+8US%~n`B z>pqmvPWba<*5#c?+r*g%AN{#Sh^q)x#O#~)zoj3t=#j(@lEy_mRu*V2@wzB=4Y~VHd6c3gM-<5);^{SA+KA5fmr$IK>)Y-**zSNGkir)HU`Xt z@cI?@5_p$^ScSU=P$Y5zIrD&MQAIoj+3EU><0y#CO9#vu2n_*oP`O2z$MJ}+7CH*C z^i1R~>8*WCM$V4{s2}J|$@nOt%JLv@%9l~Vfn~JzG-OGaJQ+=MGmnLjRWxnresq?C z*t0Rq7wBU~?(o>@b7k4D$~m_?C#!zB?3SY*zb7WU%Mz-247p)MSA7!Rj(I%(s5~sv zvp8)D9F$Nr03LDBShC7e)d-Bhl&{`Yx6z-??os)><1p|#svgZ z_9=qc>d*~I72tKM*>i{g^UUeFFK>CNf$-Ju}|W(6i;PeCLUI zRtScm2Go%?#_uoWhZKd#4V)KeOZ`U3y>sG<1{wbboXFIt7XKYxgXpLvT7q0t%dq9} zYmeK9%PTa<-tl|*bikl9WrvP;3iG}W9j`t(USMJNAd27FXbkPO`yv}kN3W>~{%SZC zPJ2B;EgJKA!ij*-mxh^J;PQ_Vw?jGwZ?7@{m$YtnD)|n(Dtr^Lm<|#}+sGo=X<2Qi z(*tDDL;a>zm^u65DZ?MSA06#t?biWZzX*CTD0?#K`909O=q&1^0g{>zN&)az)Vua# zq-A15g5kaF+P^2=tVEDg3X`?Bq*+<2hgT%<1`R@cewEIW~28j3Qhp1gda+Vq`uze#C;tGNE%` zd1(2rW%tq1>JbY??Ey)7$lI70rVB(n67q9C2}qoTwVeqQ%Ot0I>P4A6QNm_K2QwNB zp|LtCz`K5(?6Us%sUi?_HP-NqG`G+1E-mWDkq3^RnCJZv3d>&J`ky;l%xrCKh}GU|wfZy65pGLqx%gQr)L_E3Qw+K9pW3wKFcw7spuZ+1@{1M_aE{h- zI&@R|_Zc2*ICWn1rq~aXmVE)PGLJmKLB+!!px_(E_-)pPTs!0{Kmx!<;zgRLdD(W6 z_T}+gQk|rv(C(&UU4MN~a164PYNo!4A6&{S!7%zaER-AP+e1U`pKA|EeknMcbBEpPVwD&B%_&N=fDN&y z8NxZEsNkFB-@N#C%aI2 z@rOb0kj}_^oj`F1VO>i;XUnLH7^K!V$&tFE2vA2Bf>HlS&4=hJKAEBR`R8}_jS2s5 zu%dei@br2Rm4czeSB5?1oUHk27H96R4d@~RC1dA&GWNA?WwH-1O1xKX5Y<4{k>_^Lq#zKl_?39xTb($*uyEYt z`#NT(coJn)jb7hxCXg$+EzY5_6R(iQDzLb~*diu;Q0fXLhJNG;dvXUQthB$jB&NsD z1QEmQ<@^c0(=tyMiq1uu9nQ;LAH3Bkf-1;Fp~4%0b-+J5XZc?u{Sw*eJXjU=1t{c# zTz}Z4Z?~+97DBL^+X{tzvKyt~)v;(gRR~9Q)NPo|ySp!4Ucfa-S3?qEds zs){=ma4T9i;KLXEeI_hZ2)LWO6--zryx{ab|!+vQIxDF5Yei_o&fz#|EPii zKXTV06#$wZ+-(ZGHUA(tGLD#Mf56RDm^%CjHB>{IKN>!2wJ6fJJIiQi&6!Lilhzb> zAmNo2x8JM8f|BZ15q+HwhF3+HmQY1DAWFzQ+#JUi#TY;^rrP@aOa+#KS%67x+`zKx zm>~rTQ#iA;BHN~^7iUdyIxj+@)qv^q6ja~rn|Wo2UdvS^I?qyB@u*MnhkS^*3wnpN zFp9J5bRnH^-D`VXhWZB2xNZk(0f&fH1c!l9rjN&Pl#2K&s)-?hTZDJ++PtRWck8J7 zf_^oqYNQEXQ>y#J-k?7=5==)MNCs^Xyc=LQI}I2c(Tq-9@_&s5m?$-FjViJ`;6uc% ziNk>wq_N*d?Q&2mj((U&ZjxHft1F=whl`!~-*#z<@vNuYY0pB+G)or7~36)%a{Ba5~G#g>X8VXqm$a+1tER~_pv)4aH+?=?eGakt~5YiY!wWna>ac`hFskWA0jaR8BCL3>&i>@p zk5=?remFVY`M(~0b){y^Lmzk`@wGS$X-f6>s-ny)D}R3bpC5kpqh-2I&;P`uuSWV_ zEuT*&5?_t8lelUOJ$7f5Q@G5A=PIK2)**Y5<$n$(e<*T76iy;z-VU9hDo$gxxw8{C zyE&LN1w{Ap1=j_8!Q%^{`nF$$_`X#Rl0fNBkijsRYjY2(F4|b#1vYgYb?AKEE;2(MsKF`rAkG#j z5s^s1?uSM!-Uclj?RNyB5Kqj_{1Xi4u)sfoCxm0aBmeO{TgQcamY9It+5>x+7DX`` z!lh{9GLX_p9e6p|kwEh79+1ut1pTI$24M3q_5*%nYl~-X^!ANtTC&(jmwSM7c21lk zVI7xi*R2UdNPVB(!!uh}MdLTS1)S%Z{4@J+AuRWTO-5oV9>V3sdxRBf16DX0`Et7 zw@v+(7L~%MZiOJZ=<(j_b}zZn)2vDtArIUIvl;$xQN<1|npxBosVg#4aTl@^96|wn z6g%QtUIGnqcY-OAP}qa6w{1uwhs0)Y(ql}UNxy|ZY35{ZQ7wC zscz0M;rXaj-K{b;I-&|4bk0+lwE@c$RO;4?n(`giOzIsI#L52LLS-TxyvWU8y@-P1 z9qLiKVOnhzRO06=rxRrNyzKowLarEaf3}MFoc#tM&*)3M(UfTW=c3TdFhc=-QvM+V z_jSDBp}15C>Az&NM~~vyZbU7}9<9xo`J4RxquCdC_58C?^~mNiTWl4S;0Lx+IG-tN z4dHG`*+EYsJc?pR#tcxnpz3wu>$by^aUvfFWVEZF8&@Wj+?!6!pyH9qOBnrBE{DQL z>S*r1!?SlU`6fd5E>7Q`G+QG#-#mg}c4oFQU2dT)(hw>gQE{YE)IDmnFON>vCT=@a zKRaDD8)rx9YHWW1#UHj^)cgxsfml1y)^m<+cToBS@;banP5j_GNnDFH;yJ6(b3|)* zEO+;75VsJ1z|D{rAy`P@40PqwQ9 zav!J=H1g)*h=y$eMk^BLpthn$lYueS;?ogBj>lyq@~KEl3Jh7+P(VsWKJ}^4m%kkP z6uQBM-~8rqA`w0V`{kK%!dx*?fz{!s>+A%gBuiwmDnlD`?oBKNN+Rm?W`FOUzC-KB3}&01OC&h3h-3* zv_D|BT6a~XmD5o(dYa?NmanOB83Nlqv#7|`Q^!!B%Qj945x5@4enQ0$=E^1`9xcvo zdQ<7-=wyl8^cM3ce?7ms#`n|WqOK%j5;y6oqhW5(doh2*m-Cw@?Kb@G9v`IY=^I;h z#)gR|$-{T3oLY^|B(r?5qov8wWLkg_*E~<;FKy<3y}2G%_)y_dl@Be&zE2-~`BhYw z9u0C}RoP%0c-6C?7I;(-s1Bzs>R;N{QxzX1%>u?;91dX;Uo8;v$-4o1C@J5tm16qqAyIiNM)rOvfa^LVFa)AkDo}0C7n8d9tT6@BvzjWp`rG#Y(H<*9)G+> zzxwpFj^7QN$OI`ZE<%9eA0wciKGt;$6h=7ed~z|Hp`pPOd>sE2ph^-E;KiIs=d}sJCI}*mK4QQ!w>LK#GNvtj*m(Ry91Ta0GE@ZM z#wCdTmmZ_JAH}cD2e}S(1-RD9?_U-eMv7VY=1`hkyM+OuV*zvIk)RA|(o+%B5Dy_0FS(5L2OYs(#SlX@Rkf&qzNqMTwU|iC z@KJ!PeV82{FE5R-Cv&Ad3S0l&_+c#i$Wl2Jm-3}jV{;QN3C+WKHo84Xs6j(A>NTpt2U8rZ>T?L@E9P(<8FTZMxWLUEJ2F-RZrVd-O!hyI9l^&VOQm33 z8ZL)8YE1L+@aSTxm}jM-Q2fMUv$Qzc03Jg_rOvvI7=f3aFc4l23I)f@%Ys5^d0A)# zQm|IU2d}axK{KNH8tfRNq5=sSwC`qlHD4-5$eO&0Fz2m zx?n;I{aQYI@d1&{E9>E>talTwk(^0(siz^qRJh+*9fpjlLeO-^gvvwWomveuPd9fN z+FZSQ0XIHrWsYa?ztO-0%Y_m#0S)`IlgYe=wBilCnVpK-m(k^NJ|s;D*dBLso8N~- zXB($~$zh@z3VpK|f&DmXs;F5D-qoFY360DUY~#sXEdJZ|?wl`XJjiN9SF6&+88R%> zT8aBoE4f|wg<>q`2%8w49rh?##2uq(Zq1o2Jtx`TFH2} z86JX!brrhxpTVr}24#K_8z4I+zB2P1Q7uz zBY0#{CzXIsz~gLG<*6eWl{&bQC{68=$^ES(Lo4BjFdoUCyL?XdNUG1TdK;0zH&EU! zP;77e;z2l6S2B^uZ*DYh{_m{r*8Jf}^nHyS1rM?_fv9LCc=yTEHwiW;^*$ANWpIv63mCg*k8HE|z zMFQy?frz=j!NO|X$02$=k|FqhXZZn!p9jvM@Q!Il1D)R>@N(u6hP?sa3O=y2;4L!M zSuHOaXgjFZ$j^fF4oxngZlG8j6hdAFT(8e0VYogn2?bD}xqvdZQ}-N2qLHU~_FFye z&NHr9o*XH6O-J`@nV$JOW{$q@22{YkaCGX%$BRvI>a7dAPSHKsi z$ch3ZHvT1{b@AwHILgt@xAza8eH1XJcn#Pi@|XuC9<@=x&!`MNHaC81+(^)$&JTM> zG+WhCCjXc@bZF=uh53k1AC0(G-9R*UZbAQ=b16M{w)AQ?iYv`yL(|szrD2FApz|(_ zChEmCfX6>>EU@m{MJh3Pg*?Xf;X`0#|_|aj9<%)EA_`)|<`EO@D!{^?%g) z$4i}mq&FJ6zCtw#dSg(zXBSSmXq9%nE|Aq5QLfWCtX(J|l3}&~o_JlOu^8U%{G&WmgW*g^KG6Y?)`1a@it`S{8T?!PUypLI)zE&5h$>Ns z>FOAyBaSn$bq-oK+m8bAT2FSi)<&XKalu|tf=#in>?15({x{ywcV39T4xvp=;H3|IsFXlNJ6eXQVjbP5^r%20IZ|s|L;RvznhFgi|1S&nW^> z$oMWeeiU01QMxb_UfKZ{*eZ-s^cDg?H#eKjy$4I7jE#4hUjpk?yVY9Jb-^Px`S^6c z*zKbSaD2{ZjVM+V#|*;%YZPEdb>RkZu2mR@S8?KSn7|(TQD}3}!ZMrsRh@Y{4M4Hd zLPa{D0|9upu0_qYhLHDmBkdsU4>BS^z=BkztH^yL(G%9&TD8mraOyCnQc81jSW2oq z=mke|XQDYjx;IH4EjGF~8q++ivnEm7-?))q%Nubtwe>J2 z%f3J&U0N%p5jHQ&=y3z{-kNpP6G>%q6Mp|hE|Wq82FlE8ng?xgkujIcma`+_@CcrA zDb4Q-`9rFvsd)1F**vU7moMYc!w+m0E#k~|!lb9MzRp&4%)PzNX~F(nf(5~kYobA@ zm=MPFnhwiI=gJR$&~EE&WxdsEodYdyeF#<_=e(xk)DgrnB(aX5tU82po|EtRH$5t9 z0@hJfM>x&Mw#k(z@c8Wwv$c(AW&H2FcxmJ8l)-McQ%iBenT^ej4Xf3vA>bL;{Q8N1C~~YH;718Q9BU%e~y_EDSrt56@b*?SR$7sYmYA8xH!rmC@de9S^hmm zDVv=Ysxj}Y zqxHO;oz1SmOnXq=Qxz79vVE88?z;na=CW`1mcAikluoAClvQj3BIi z3!>@(&*Eeb)W1A-=Xt6Fa$Y?BxC8imBi;Atqt1(6(Cz&~c&GCF^nw?B8+)i znxB%;7X_`ioH@+w958kK)bT@^%pvjQ%;&%E8vTV-_Y%4iB+Kb~g(Zm^9Uq+IXZxao21(K2wK=}q2hk0MPC>Ap#uEe*Xof+jZ1#M^V>Rze}jQt(R^{E zuR=ejz`ZhF zXe=`jh^Aje&={I|ak{q0^YZZ^50{;6TbYM@krFP#2H_!FfI*qyS(pQ#nuBnH^P5r2 zMBMI|5LiP*i4q&Lvwx325{N}c*aig&J|@OvezdFNkZ_oq_&gB6m78fq2=vLB5yU_r zb=?Fk?pWnGI-gSGDK1Xn1tRTL7#npor83~s;UWf#CRUXMq(C%f(Tj-4M{xcwx*Hk4 zZ#U342vZ! z&@g->3ZB9q`kCKO*7R>8RkIp-CKQc&uf>~K09S;bp^HE8a_nixzM-6cXpXz~4R05~ zK_mPiembF47v^c7K+D*(KLW<#rNh8G{@X9+N$^^rhu!<&|A00d&z`#Jh9P<}bi+-j z+>>vdn0VvQPP}n)@{Nv;_5%2s3?Jn%I2tm_;^djaD#CsYA2n&X6d_C1>4e=J^>m)~UqlJ+9Zfe#G^NtL1vs^<%ELx_-j-F4wzV?{j@fOt+3H5Bl}& z^FCes&+!?0%ry4=N7>4MmUqdi-1n30du<|Pr~l_#e_=Vu)h)JL7Wlu}b)W0UUH`)M zIoEIDK$e6k%vDK{ECghp2Z3#fGXVZ*a0wWxY+ixSMUCZ!I#>$~ya;Y5Rs#N^&^su2 zT|{*O`+JbQi2)%pOI(P1igmS`ED#)vXLZe&8u5GZ;~!0Fnx08`3gJXh)znf6&8LETSeA<^J)(F#N@QwO z_N1bd!Qf=ncwjUbMd-a!C@4Nviv}A5Z#EV(6_iP+vt zkM6n-9W!=KU@RCIk7vhsP2;}7Uo#1;_CR`@|!6R9ENTG`_l8y<>G{^$x3e$M-LkZfLGF+M73h zM&I0QQzg%K`%>q{M#DZX(H;&Xah0V!QisB2khix=;YOddZeLiqe0k%8ryKwNNb4hK zKJt-!iG9%V;E3^bu;3odKzi?N?SU6q+^u*Jy9T_(v-O=&KMmfIY$TJr zA>V>IjGF-ZVGm-3Mu;Q!-%ZA0-!J^o43M|M?|ON_9Qci?%y^%+V^5@aEK@)X^1(gO z&ANITKX-sKGW?;yZC?&y8N;n4F%7+!sfS*Hh=MRFimdO5rQ*(100tepVb|r;TtG|UitCg7dMGS}Yk*n=MnPUg0=Qj2eWp;Pd+&OKiE=#v+!V$m%J48q z$Wq7=jMktPp5#;kx2r9n5jZ~Sr{pgvC~X#sETJtKT5v~#O!a%@s4p}k$&%#uBk(q& zxbb0PC>YpDH}|TMAijGUAEH`=4@dG4y0%M9LqMiSmSk0ueMcd-1w1|}u4#mt9({Qs z(DDRhh6Ew5j;qvAfeNK7Ndg=p!&GCPW&tiubD&Bx^8>e#qDDf1WI7laN&p&PME1J< z9s+A5gckE2zsiCUnjVAKW#>LCsrX_ra<8VvQT8P;cGM@so+iQaVrWcCWygjfYxwvK zzdDGD#rlZzE&%7t;%+*=zUlQ7dgH*e>fZ@R4nCp&y+Z4;NNU`5uE+kH32S%IRbe7> zj_`QWDRFhXl!9< zCYP+{BXgBv8-DABGlp5u!vj}b`k3TCHik5SNWPk^E~?fA)4Wr=P|w#*@;R1Ia5IbG zZ~qD7n!xNSj9goWSWJd=8X1xXVs1Edpdfpg2|?nB#|AJIgxLcI+LEK?qrv(TYD|sM zK&XQfK2loOJuo0PU_69!-@Fj1%ti8JNDUcU82f)jl7oK1ZJwa&RRn#?@N2`Ca%bbB zsz@Gm^YX4-Hs3BGotGwx8I2utpS0}_!bGwGb-Ax>cIYhf}G*Ftmc zUG1Fby)W5^xcyx^z43j4tN+4237&9<()2u#35ZkK4Z6tbju23UxFFDF7!EXKLoFjr zj}i-j#Tl3y47fK93NTZrQFDz{VA7=Ug48J9PIbf`Lf++#SxpJKN308Ti}@QGV|SY6I#mO5K~T%9`l{L-*+~Ruy{pPJ)VFseb#sXDc`Zt)1KI={8H#l$Z#zm8J^Ei;w}MnIo8SAWST3EWsA-QuE({I{${rYI93Y$fwKoxMpl2Qx%dMqqi}*rDxFC%Vb&FH#zV90 zr*kPUrIvg1qsxKxTArvPA1w&AUU>NRGV-A{@ zKH6YLilrXPcJ9f(Ns(vdO2)6HpGilf|8(XD*4xw32)l@r?j01~+-6x%*B5WhjT-BI`!)rjLnf7`+8t(kPjwl#+P>Ru#SP0pHYzMWtB;{_`AQ{Hm>Bl^QaLIsBhE1alMa{) zND(7rnXpj621#`p5S3%psxo=vv5cUoePJU3VKv}+&uYsbjR|6oq4OVx%t6l zJDKvL>0UB&mw4Ks081Tjf5eM7BgwnO6Kx?lbND`LgF;9e;Uzl2jR)MG9A;u{h}Y-# z401Cc{Bo7&?Lhj~Prf;te8YLSG zpX8CKG9wfTA9JI@Pt1oJjP4!v2;V?AA5Id<3;AISE*sL|vDPCvFA!QbkE0Kbj9|{A zlLNX{e;z9~+Mc3=n^#c{efwYCpUkv3(J7|U_^W&1d&!oj%1+V2mOr6*N<;1Y1L!oj zW$s_dkL+Oo#Qp$9@BH9NW$cb4u9J{$?gnpCVPE1w!HP;T*bAhX@h+q|w{ZwTpTjCq zUt92Tyo94fyjQ_mig)U`5Pa4yuh6ZV`Qpb@uoYEaUo0gO=cmpF-O6Y*olBY{ldsZ} zKLXW2IjSU5Ob&(>BQ$P7_rsdqlu-gPWi0#K`Q=QSyHmqM!UfA3AI}^)Y*s2IC6uXK zQUClzG!Qf<$F;~KYBZ=GnSI)jys{QhQr@Pi#)E3sxFe%PgUYy^$S;SK*DT_6a?PA46I(pyH zg{YQ5g>>Mrg2M`x2H+Rqe@Br$hc3Mkn*^6eA&&+sF+htgrYRZGgd~GBWqR5FCjuDg zW)0HQ5zh?TvSFr_kx{@5If`_8a&nNq?j$qxK}0DyXl}G(ZSER*6Tt=R=BB0ZH-;bd zOD-p}`>QC}16w*nu}o}v?yndy`@c(Pv*}SinbhApnlOySXeyg!AMK9YY|@PN!`Nwo z$XtCc91Mo>6bb0{rNgMj&_C7gT%Q2n^iwE%9P%Z?kLkBMVC=W%Po2s?@JA0kfM@3F zj>)ksK6`+F1{V*FLrsYYrQQ8{1!o~|(OV|bbWTM!G|ExXf^#aM2l8>z4gptoN?5?H zI0a1#{w|OROg|ouUhoZ5T5B!jtPmK|$ju%k^W)YShSbe!)P82jF-ppfrfNzSI zRC$ygg`aV=zC!-!FG$iCHo}v0lVNOdqA&(^vV8^d^ly}9#E+5mkG`e|R*9v3hR>wk zu}yTiy-iUxdb`!|*HQ2BC|Iwh41Q?3-XA^$B962sNjj-hCy)&cV1S zSebsQU099*;^JyF4Hkn8R9y>f1@IUI)Jc?t0hpbuTWES@kwX*a(U)Af1XqYhQYs*9 zuR%rPp-6zU2iud}E?Y)m4FUkbKQUAfnBFU5r5qwcAmOj*fyCFwjgc{nE@b=>BLkFn zy9u8XyNsw7n6$6*G}@$iyc$cxF$87?5H@;Y@qdqV?MYZTljH#A1<*)(MY<&PP$v-` zB8ctofh_~;Mx8E%c?Fz|k~=AykbTNIBbM_Y6{kcM{l^Q1Q`w2QF<6)pK{Kq<@}O3r7pO=foyhp$SPK=g@xgiuBV0<3Q#gpx~wv~RB>F_FLIra zO5dB%5N-rlr{j~1k5DIRJCmV+_|06`;?jK)r!$DGG#uZgR6AclC~s4!b1Su)CmE7L zNl!ecH=Y&67JeFM3{-~~^f(&XCXy=)3m%G}odeqZlFzh3qqL6%jZ$fmVaSXNJUGqKV)p?V47P6qap!7Sph&kSS!n^n zVUpQZSw4V$0vMJGI0&QZ!izTe&kBg|E!>=n^H09L3*c2y7>EincLH$WhEJu@UR^Va z-f?`2IS5^7gEhcm$?5@{5gGi6xgy4Jq>Mwys6+Wdq&Nlj>iJu4$+y7i*Q`~uoxk%`iATyjEb3#YgAwsE&hr0`_B25HN?0UNa&rv8cT&j&`j6i@{z1R2z z5RZ(Gr-wb32W8!}Df9+v>Uh+`M@NdsnLDZv(gOIZJ_T=!bw$tTGBAg2wt zn~<;CZU!4h8`x~Qjc&7OJL}6vR^P1zpo;6Al{NUXHbu}~`=W+!urX>}TmC7eeNwWJBhNu2F5DGLluimK+G> zcs;{~axkBqO)fcVpm?VQe#A=d>`y-;i0Hci2X@ zA0c|lzdu6q0-X_`KxZxj9CRLn)ej!3!#G%DfxrXw5DVzkYj1e?viR&K@x*G^iN4C- z1!xB10sMcF+)0R)ZHqhq|Kfydh5$$;^hI$^kB3uPj3l(e8xbdQ8!!*7BjyLVLjg=2 zm}u!oe~4OcqzLJ>ld)ImHE0Q&h4O@akQLQx%GjeHbRG&HK9 z*CKI+nzKWEfs8=@On8um{pt64DIq6F44hdn%Ag^bZz0d)>>n9b$e&&Wh#tfxuCJ}N zLw@!)Uzmmco%j1gYdT~O)}RpFrpfY;gc6AmJ)m}+)o^^gz!t^*IC2_nY1hOJ*^YUz zT(ySqbwI>h-s?#%u(}%1R>V{Cv;Ghud4e8)pkH=?Shp}$pC3Ad7O>*shr@CHfZ!Z* zMH8=pt`B&AANGf^9USMx9zk2&f99UgHKL8$v&_VEaK|G6fT~OWFwK=%s}i)G=0AYlTJMQbsbkCl{p!}#XDf6 zp!FI&FYsg85+C^q5hFhbJy@L~w+hTNV1{LQ3qummR@@2aH#dTSDh-#)uytkQ%A`9p z$zf4C&ubB{JD7<1VvqC#`^^oShc}{_c@tlla%ZM!rZF}8v@ezjy1fz9OZwgph_RNy z>0h%ac%#}Pd>KcGgOKEuM@I$XzVrw=6{bLP8Z7`=Y`=xF^TI<#h$wK6xCvW&OZXcx z(__sKyWc^N9@8)9qUNV>o_+J1g1RT1NxH*Kb6$165oK#{9v#h{JS~;jTN8H{e^kxn zH7jFehEW(^JswNAl}vC_f2|bG>h5qhF)c^v7MbLiV`kg$<90ieWxtC#dJ`N~c z2v0@An%w!{(T9LT!%o&}x5!GyneJ_G@#Zk&4>|KhhvRn`_SDpqh-gT{%oK@e(r>6@ zTArsC3^b&%XM9s)EQCqVIdc_sg>~6rC*a%4fnOm?or*SdW)1*>9s=GTNu>C{&DsQ~}>hE@H*Zza}5|WE>Tsa9H-(2R6TV6Gb#vLhLz8s!R=Vyi}er8%3NkAkS zN{lEKaTw}-ol1;+!hjPx2`dEBE+PIH30<6{J76n=P8tJYgAh&@UXoe3XtKx>2L}^k zRv14yfIXwt%`yfqCGHDwI0e$^Fq|qnTO6DU!Vfh z3!sfYUg?K4&C|xp9Me$Xz>B$b=8y%6llEs=AxxZGP*pH&*!`<)Q}AVqy+T$&^xFmH zO}h1bWT`k?Bx4+fGQreD7qJFJ-`V1J6c@sSW$C$M0|m+<3@4j#rqVQeJlt=`)S|o} zQNSR$DDEH9J5MDPiX|l?^aDtIY7c;6|F2m3o80R2kl~S(U^sA+31SzVu@r10K0lXQ zZd7&wD`4Hgd8~knDgGCG4!|09>?(jPOvzl^;CinBmLv$WrWAEv*cA@VL=`h2feM9P zR|!?WZCE7#;0JOKktzM5^iZ=y{>8TS6#E~ir8Xzi`^~Q-C}o( z-QC@Z-QC@t+fMw(TniN4p4jJquj@yFhs9#fF>~}i!V9Ssj^0oe_Hr!xefGezkZFqE zAgo3ZABpY+6}We}hj;&yQGp^FA^#DqA;`Uh0}|Z&3B6OD&WkeI`CXnkYlF$rU}FR?{~qot6R;XHsbC zf@t6}UfQC;PV2P`${x!gSOgRPIoTK@8x!qKnD?gp$D^HvhlIkv;BahdctSkd1*`;U zV-Q)4?(_g;c7Yuhia`C~KLJ|}vD0P2!Rdq3)=UdugEOQHsvVTBcLZ=m;Qp3rS|Q1N zeUrt-M#RL#$GH95HX)Q9ahLz5&8n!$`16C(#0jvTr9;s)$a_F|q7adJg#m#92nG|( z5AZz4YjXi!pYVV|>TWpru!v+S1O2y4dD2J{rRs*qt2NM@SvU`_WKfa7-w+L+cSBe0 zl<5dfPnnGH_{pL@8WBn}gm=L`n6O6>T_`3kIq*;qWnkS8$_9t{hm{|^vR+#b6ZRXv zANaUYu!q-a=OHmo9%*}8NviIpWr&xu>JA~q(+VY52*XZ5`3n!pkuGJ@48$-mkMMqt z#cjh&vS%0q;UvUgd*;#$;~>CYl*OaJCDLC1@tlGi3H|@?=GF7o|9);0==3Iz7DjW6 zHltUf{@>>~p5%Wx&mP+U`CQ+`Zo|I)IoA$&iIIK`>exS>>*fiyx>97wQ0l*$@Xm>< zX<_;Pn=S3x(+M>HocBajGym(}{)PO1Hu;IiA^oH64tI9~-y%V?l)(ysfK)>~)|H|@ zRefqg=2b(GT_Cv@kX4b<9rAAj5&z8w{1{|gCmZnJY`}NXcgA+$WP_s}!7f8tMsM^S zGT9+qtyD~+G)dfmOAcLAC;;NTOs8Yg`6+&MI7j;_BMBlkj$0U(6^D2rEHyz)SNu5I zrezt-;GCaw1RO~5`0&vv<`{THi1%CcdCX%`1Ir(1nkt_R#kToo7A!&1MZpwhMTX+O z@ME~Ipu#)gpC4B_-mcD2o?XQQ})!uze7B8=H+kyKg<~% z!5{4Z|9Z~q{V3&`BE$dX%zXoCBcW-y!;pXfK9szP_S|8>F^rTNV7EfTdl-sI0Hgu{ z$N~3QbTraC04(HCqeh!&mn``X^p*s>sSWaw1Nyj67}#;WR$b)LM6ofzNr8JnO;1nt zLa_Hjj(>irCFrrgUL9jKFl z=tjO3r0WDAAgn)WI}BKFQB(lpU>3wv0X`ox6=e7NZ2zRNq{=Egl%Jg$KD>{KHKNX0 zQzf+=L9+e)GiP23pZ-5y@X+(!1Nn%2JzzcY$Qr4@e1&|L`7mVXhS*mJOl<*xh4q6o zg0TyzLke10P$~!6FaaK7lH;`WL@HTX(<}_kYT4g?{Jna^B^1E~cDQ9;;Q#ZWxp_jC z0?lOSvzfANX0vGDr(UfA5DYmf5?SpcC6AtP6}u0-DmlzoNW48B>?5cghKXVd!8ie? z_G~ac9E$_Dw^>A4p2l zKqk|VHAc`Ip`KD-If6n_tam09;f(-40pObPRHZ_f7c4eJ#-flE&#+K1IMPckBMV9` z3!@ZN))TJS(uQ2#r$2Yb>0FXeNn` zi;aZ3c^m~vQXD))Mn+;;S(Q&A6TFhqCJBPTc}Pu3p~xI7syJzg0gx&cf6i_}>{(_2 z6GbJOVGASE1 zH|~s#kcgGY-gq*I%z-sSTPi=E4^@_db%0-i8pTlX zi-byTCdz@sx+@?IL(DQTVu0fD_p=3{gBNU-VGSjNQ$Fr$^cC6@=x{3<%dFVQ+r!n@ zlf)n@N!92#EV2 z@I!2ir%nS>DNsrRh{I^!EimVS_YEw2KOO*T9QL2*x99;X2qC+;$BG{j5s;Az%N`tJ zW;CD_U5+Z5Q+DP#*G-u$SxVP60O!^Y1nFNi&`W7EyDECc@by>u?pdG_!0XH-rnX3^ zpU7(@B)dfrP@9krrbrq-NGjobut1@oY4`@?g3ow6AA%(-0C7rXkfqOn(}JLjL6@@A9GB480FrzYx0=3LZPJ>nkk50~QsNG%zGK%7Sci zxX**VnXpm1ogqAftqW+AL`oVj1W!b9BCunIqAw6O5|hT)3Yi!Qp-5?bm-?o;O2b}~ zw1DKAu4~C-0F}oVEvPq4)ECftmQ}5~%=@Qs^Pq=#)6H36V@N4X1ump8Sj3;^U$|WX zR?zEJ@CHQ$dJqX2z@~%41V&k8Z;H3-U?(Blg9J!J;!Jw*l7~d1ZG=*&q43UyRz#y5 z4Ryt}^klRWm^^u4@|nn;9s*wK)$nG=`_3eKJCy$uuWwC$^euiK+Oa)z~P7(7DPt;Oyx?%FW@|+a40Vc(h$c?$j@FV5|d&KL{Rca zOUL;Jc>9f=1ciY-#{k@6rh^4f_0W;5>96js1X@D>5iLKAH{hK8Pc-%R1WSbfN5TS; zW6tAxLoEIsu+#>yo|%v-jzUgYRLC+^^DGz~yoB$N9s$PhwHm`IGkN^yrt2D5c6IWO?<1(D-K;XOQ}wMEA*G0jCm-LCQfjdB!3=NSYO`iH0g zaa?wa^Z^j!8I;N|B*66bO_$OyB!!ziNr>M+8SoB)@~1cledS$&PD%0c=MbS~d27)k z3}X-rb%!47nVs0z<*0;6NOuj0FLQ$%tXGanYRUu}zC{ zBOtjl3Qt=&Eyg5cF!+u~MLi?4r;)P6rO8hEWx=Ar1)95IZulR`N#K@Mn6yRGVivZJG1Vk7l7I7Xa|7RaEC};r5l+Xu~tkC{I{XocI ze3YZN7ld1Gh3lS|qH50ofRZqXh&)e%Wsi*!j5F9HF7`KdveS%Z7knBJ$zkyl6p$ zEri%&5pl~>dp;+i5AmGes4YBC(xabpMDWalMgq`rrCv1sjIpJr&uvj?X9$C$M|NK}ZZ!54o z=tu`Kzz|SN5cCRH5VY-SG6V~bUmnzGX=ogEVnO545ebV^ECzKD=@$kysUZ0U<|`2& zNT?|1gQm;V5dt_s+y{0-9y~M^>;cqt_*39q@BxMp1Y?Wtq~Kt94L&@?dsQSvdjgyy zN|u6T4lg4^+X|^Wp6lLoLB+357#5Y#utz;hyys9D9hhiPPfySn4^P<&cNJm=VD0tJ zm-kKu*E5>*L~IIm2gLv2P_fH^@asSL6KViHezxHOaQow(4-Fv>^6P~ky=)%)_v_wc zgict;i7?Zk&cpuC258aVRRn$;1(gjjI|6O?9HAIO#E!-6xaj!p9g%SFAV?ha_i%U( z)Ig~5+l~%_R{UY>qK3l5;nUkva9sDF`!)DjNb1xf#}dYg)(4%-pXZAyX7q%q|Dg;g!_A3_-NS`7-{0C!ih7`Z@;)V$? zXGjnCsb>t{_Pt|B+2iNGmP#b&!?v*3k>PUaefMIJ_U*Mmp%0ql5>NDqhQTZxfLW= zAe|-}MvA}`1JHQmS$HB5)QBe*%CC3|za;aDvp)`e)%czWuT*#O{(m)|_)f4tjmOi|zaG#Nk3j70FX4W* zA<#a4g@4Fl3G0kf9GD=q+DLQ_ur0LW8$GgS{JMJuSoXSi>6dziP1r*}`|yqlct#o| z6UUz!EB+iA@f*S05#|HRoL8XrO3cfCbZ0?F35RB>S9nH?1iK<$c!oYHbOwINxG13< zHcLGG4D7$3@+Pov59kkcZv0K!jNAT0*0j=wmlKWZ7cRv9CTW)XDQ4P9gC_!V6^tMG zWjw-Y?kt|P%y?P|u(~CI^kT5NA@E1$PjWY4<9Gy6WQ>8E7J)YYB8W#pV)*Z}xaSC` z2msN$dM;TV_){_m)jawS!a0Z3fkraaPw^}22f$@NNcGIy6U-|QqaE&`6O|yZf=p~6 z*%5sLuSYfZ5@h3_qVW`HCG0Plm_K$BD#ai~wmO2Bc>;S%Q#^?isXR-hRC@ za!RBxC-j?GP7Xs02AEa0iH!B=;`qC~dYq*| zU!r>sNj4y1f|Jk7(>>z`u9xO_$udFIjKP3CBX<830PrH?p7H_+nN__4E;7niO^`1^ z()2-EeKaIEghU}3HwStG8kiq6Ao)s#x%UGb38e9ZvjPF&f(gPSC2A>=pa^&H4`LFC zivNy9BN`%~cnN~InWy2QIpWTHNCJ5qhyrmNk%S2OA(Xs7h6LY_h?uHK>_sVy9{K6# z`Ssp;z+1gs;BR*Xa?<^FL;T_N*)kJ<5-aOYE+B4og>us0wz#SmCU5^~+SuJSL z42&QmNF?UB1tEnAPwjhOGx_T%@d2K6Hl z)AVxo2n(%-g@kNiVIY#mOZ5Qe;FYi88c3|0d)F6E{J&gZ7!xdmNA~-b69AtE4*5q; z0Kg_5DG-e#K?X#;8jSpZlEr_n_s`D$yzbsU{~!~3*B*?LKl)9O3(@NT>+ylg{6l>E zZ69MkiKMqb4s%3e@ePeNK~_u{>%ZZ7i97xy=liAmf6V}Ykyt%;9*-QzgY*R!DbK1R zu>`~*`06c@gvJ>)dw9f!3*dr-deI&cZenoJSD+*;_0&82kKV(V|Y_(Sob>fW+ zNCSt93HBtqlRfffOoEmH+alsZRFqf7^o6>9X!D^`Ls$$PCXcbyyEm3W-5d(IjxXr< zo@$jAxH3?gH}Kj91R9~pH4O*~-~tVUGNQpn(#BnLlVVjpbzsUkW||y4os~^)Vm?c# z%q2rUxdj5imxv0*VA>L>`<*Yy2F{RLD3Tx_p#E4mxk-TAz*UEZdR^TXWJQ9c4OU*% zZ$>-_Lfbv=*OX8i8NwH>pIyabK4z-SSu>|HL*lE^#4Vi&gaHYOJ6r}yKJXrRYZ4DV znSrtp50NmpNUuH*p(S2gY|qI+cJbe+Nj&&J(UzF3h@TXO|AE5as0;azw0hV72aSez zeSV!Sm>Dq5|5&YG$blKj`eUX3*86XZh4ve|TfK9F^kbxNdDaJFEmQrn3;sM2&|U0* zoB`D9e;zo{@^f!W32S4(U=b)V@&$ut<#k*HL3ve+O0-vyyB8&BX3g;wD4K{kFF;Vi z7udK%Ys`sYXC%|j`TIDsL2e<|Z`LF7{ z8c2{rps+M5mEiGgqgVs4zZ&~*s=t<@*s>&I;%?wt$IzsD?b^tPi6mw~$ilq70@#c;YOU1(oG4Wm$CSIFg;5uAQdkpX7G0z9#(jNtQwiAUCspK}rdHocT6Vj(OW zU~{4vad5OJg#0;)!v84rG75czBp3r-C3T6#S75ffh?#+yzdOF&4di0eyjj zo}N%}3xYZTJR}0ecBpby1ZbjysmN;sLa`Hwj=+CG1ti!Z^$mhQyp;j|(EY_i01C-u z%ZAV#3o+_%-EJ)m!9;ZS>p$+Zb|KVfwrr@+ zLJW*l^*MmNp6~%Ke$Q9*jDrSc#lKF#Q?mGH5}vcfKO+#sV)4&3oW6?j&phy&#_`Vr zygnNCB1UrXO0dt|_-7or(y{nw0$#ro|4jM>V`Tg@yAxYwru0ywtbt(CXG5~ zY~HbB+uWHlHI08gW1}{$e9A)bc}JfnKJ9&4z*9@$|3%=Z4)9YmpVshGNhq1r2A(?j zRD#!=`E-K!G=O*i_kZ`_zq6``4%9d5(I3_`Blr`4|NF%B{iLoq{B3K`-+RZ?82-K? zlpyj4$~yzySz(kN0cO`9KHEe4t>CGcryn%>mhi6)ywcY5yGVGY5xhI2Pjk;-wS{oj zOz;nZ^tOgq65gNDGdHc!`S5&rcv1XwqHoC=s6atrBnD{x7=y7Ghw+$ziI@by915ml z8m40gW@3O`jyaf%CBc$nzF0Cqq)P!&n*LZyfayqurN+`=fe@;h7E1@E;X|z*0SZ*v2zys$4B#;8&q$r3L!U|(Wu%cKotTR1h|CRPipjn%>GV)d~4SOcsf)(C27G{Kr; z&9LTJ3oH_g!dhaju+~@`tS#0KYmarnI%1u$&R7?$E7lF`j`hHLV!g25SRaUW?u+%q z`eOsIf!H8yFg64miVeetV55R${BL)z}(rEw&C@k8Qv>>6DdyJuEj%V0&>;?7`dj&uyudz4S zTkIXA!hFC!VxO?j*ca?8_6>`}zT-Y9q84hBKy?wE#u=Q&Ih@A@T*M_@#uZ$}HC)FH z+ysGM%i|UBig+cwGF}Cbz^mfb@alLCye3`?uZ`Ei>*DqB`gjApA>IgYj5ooX;?3~p zcndrdkHTBxt?<@(8@w&v4sVZlz&qld@XmM_yer-f?~eDtd*Z$D-gqB88t;qu!~5d{ z@PYUsd@w!)ABqpdhvOsgk@zTlG(H9&i;u&{;}h^0d?G#xpNvnzr{dG_>G%wMCO!+F zjnBd7;`8wN_yT+(z6f88FTt1M%kbs+3VbEL3SW({!PnyJ@b&lxd?UUI-;8g;x8mFI z?f4FSC%y}h#dqU-@V)pxd_R5wKZqZ~593GhqxdoWIDP^@iJ!tx<7e=*_&NMMegVIT zU&1frSMaO&HT*h$1HXyi!f)eu@Vodu{678we~3TAALCE(r}#7cIsO8FiNC`C!e8TW z@VEFo{5}2w|A>FWKjUBUulP4S4*yR05D*>>kChy+3;Btj+>LM1dp zCk(8X}MgBGMA+h+rawNKa%SG7_1H z%z)>gmB>b9CqjuFL>Q5i$VKEP@(_86d_;bt01-|UBnlCQi6TT%q8L$}C_$7YN)e@r zGDKOT98sRAKvX0u5tWH5L?F_)M}%qJEQ3yDR;NPo^XT$W&x%G7T9>29asWbYw6YLZ&A(kQvEL zWM(o8nU%~&W+y|*9Ap@olgvftCi8&qm5PtU=Z!Ymv3dI%Hk49$BAkKsF>Bk&VeFWK*&k z*_>=aMv_rvOR^Q&nruV1CEJnh$qr;kvJ=^v>_T=WyOG_=9%N6l7ulQaLq?N*$$n&i zasWAy97GN#hmb?bVdQXf1UZr%MUE!NkYmYl`lmF#xr}Q9LD3A|+8WrBEuR zQ95N%CS_4J4=b)-5`ovAKVSE?J;o$5jLqnVLdPrKVBSsTtHv zY8Ew{nnTT{=27#h1=K=n5w)0FLM^41QOl_n)Jkd!}UYMrsqanc6~a zrM6MqsU6f#Y8Mqt?WXond#QcYe(C^qkUB&irjAfYsbkb}>I8L?Iz^qP&QNEmbJTh2 z0(FtPL|vw?P*ILe|Gd+G!Ak@`e^roK>Lsc%#q^_}*iF&d`{NJyX{ErFp~nxlCr2r1GMEz=6E z(i*MP1|Z&BkTC7gE}eu?oIchqv^hM zKe|6XfF4K>q6gDM=%Ms5dN@6T9!Za)N7G~IvGh24JUxMqp(oOl=*jdHdMZ7Qo=(r8 zXVSCi+4LNGEkJBgUlk_S2G<}9XOP{09 z(--KA^dpP)IX76UyX(bdH=%E+#jVhsn$2WAZZvm~f^bsQ87MB1}=H7*m`n!IWf5 zF{PO@Oj)KJQ=X~7RAeeKm6<9`1XGo%##Co&Fg2N4Ol_tPQQ%ur?+Gn^U0jATYJqnRRm^H;4YQV6$E;^IFdLao%w}c_ zvz6J#Y-e^bJDFWfEVG;0!|Y}DG5eVV%t7W5bC@~89A%C%$C(q%N#+!DnmNOqWzI3@ znG4KC<`Q$6xx!p!t})k{8_Z4S7IT}q!`x-=G547V%tPi8^O$+UJY}9S&zTp@OXd~x z7xS8V!@OnQG4GiV%tz)E^O^a=d}Y2dam;tths9VZmcf!>5T#j$MTSt68z-_7E3*o# zvKp(i25YhwAhbKI%O+uyvc7CGHaVMu^<(|nlxzT-icQU?VFTG9HZ7Zu4Q4~w^lSz; zBb$lM%w}P;vf0?|Y$%(94P$e%x!Bxn9yTwVkIl~(V8hvhY$3KVTZApj7GsOECD@W| zDYi6QhAqpMW6QG@*otf=wlZ6VjbN*?)!6E64Ynp*i>=MpVe7K>*!pY(wjtYyZOk@d zo3hQ==4=Z#l8s_pvaQ(GY#X*M+m3C|c3?ZQo!HK77q%)7?|26iL6iQUX@ zVYjl|*zN2Nb|<@wjb(SUd)U3~K6XEQfIY|_Vh^)N*rV(*_BeZjJ;|P8PqSy(v+Ozc zJlNnavX|J)>=pJZdyT!$-e7OCx7ge49riAJkG;=6U>~xN*vIS>_9^>}ea^mMU$U>* zzu4F88}=>xj(yL5U_Y{-*w5@2_AC31jbp!aJ{-p390c=n6i0Im$8u0vk`p+QlQ@}E zIF-{loijKS3I*7l!?|1%E-B~BCF1~EiSy(9xs+T0mx@cxrQrg(ATBMJjtk~Oxb$2G zE+dzT%gklrvU1tD>|7|9gA3zwa=EzNTplhjmygTO6@V&%1-U|8VXg>Qlq<#+=SpxT zxl&wdt_)X}E60`RDsUCKN?c{G3Ks!@xYfAoTn(-!SBtC7)#2)L^|<<61Fj+0h-=I> zftuaTxaM37E|QDlT5_$p)?6E|E!U1~&voEBa-F!&Toa|5`6+#qf+H-sC?4daG$Be;>=C~h=2h8xR`g$x}SdGd#<4JkJZf$n!F< z@G7tII&bhMZ}B#it8n=wd{W+*PsS(bQ}BMgKcA8h;8XFb`80eWAH=8S(}A-ogip_B z;4|`>_{@A3J}aM%&(4SPIruO>C!dSY&FA6s^7;7ud;vb3FUS|-3-d+zqI@yFIA4M< z$(Q0w^JVz5d^x^6UxBa4SK=%4Rrmy_nUyrZPH{cucjrhiV z6TT_mjBn1j;3N4cz9rv^Z_T&i+w$%B_IwAvBj1Vd%y;3t^4<9Ed=I`S-;3|f_u-@Y zzI;EvKR24{{xW}szsg_Zuk$zfoBS>QHh+h|%irVg^AGrk{3HG`|Ac?aKjWYCFZh@I zEB-J3HUEZx%fI8_^B?$+{3rf1|Aqg`f8*o$?}Cqj3AjKAq(BL@zzD3s3A`XcJxNKB z1w~K=P0$4c0&^_E797D9k_br!Um=;0Tu34K3I0M#AwWnaq!!W$fkKdwR!AoV3n4;! zA%l=n$RuPIvItoL>@K?yD&!Etgq%VyA-9l6$SdR%@(TroaG{`3NGL265sC`MgyKR8 zp`=hsC@qu`$_nL#@^XqgtfvtVZE?H*eGlg zHVa#Xt->~8yRbvpDeMwrh26p)VXv@H*e@Iq4hn~a!@?2asBla;E}Rff3a5nA!WrSL za85WcTo5h_mxRm072&FIO}H-H5N-;$gxkU$;jVB`xGy{q9tw|y$HEigsqjpAF1!$4 z3a^B}gxA6w;jQpacrSbqJ_?_N&%zhstME;T6TXW+A|~P@A(A2`(jp_WA}8{qAc~?S z%Az8wq6U6qLo^{>!WJFT6_bcbMPD(Qm|RRD`icHxN-;o8C8ieBh=F2|m{v?D215oz zdNG5TQOqP}7PE+1#cX1BF;vVUhKV`FTw-o9kC<1?C*~Im06K6%v5;6;EFu;ai;2a> z5@JcQlvr9UBbF7*iRHx#Vnwl%SXrzhMu=6#YGQSMy#Npxyailm(94(F!$BN^`@!|wA29U2OiIc@C;#6^( zI9;3}&J<^fv&A{$TydT_UtAzA6c>q$#Ul ziJQeO;#P5+xLw>K?i6>4vEpuVkGNOdC+-&yhzG?(;$iWKcvL(l9v4rDC&g3ZY4MDB zRy-%3hhjY!#Y^I4@rrm=ye3{3Z-_U=TjFi;j(AtRC*Btyh!4d_;$!iN_*8r*J{Mnz zFU42lU*c==jrdl4C%zXyh#$pI;%D)T_*MKS#);o09|@CiiI7N%l4yyMSc&5$K@ufN zk|hPadYYt5hGa^XWJ`|ZN=c-olCP9ZN-m|4{3L%Vr4%5gl2S`)q(CW1N-L$4f~62C zy_7-9C}ol|OIf6>QZ^~O6e{JA!lay1E-AN^N6IVZlk!Uiq;RRAR7ff;6_JWc#iZg= z38|!1N-8atk;+Qtr1DY)siIU#sw`CjUt?9N8ld#mkZMY`q}oy)sjgH{sxLK=8cL0% z#!?fhsnkqrF13Ih_9&^P)JkeCwUOFN?WFcn2dSgfN$MMiww zf9BM}Iw~ELj!P$`lhP^av~)%~ zE1i?hOBbYz(k1D#bVa%8`=E$Oy&N4hKBlkQ6oq=(WY>9O=gdMZ7Wo=Y#J zm(nZgFX^@PMtUo~lio`oq>s`k>9h1j`YL^s;-v4gkBmXtA3`Q&N~UE-W@S$1WkD8Y zNtOZIOqDfRmkrsJE!mbG*_D&XNo8L-nVeisA^XYxa!NTsP9>+7)5w8xkepUd2e92C za(X#~oKemsXO^?bS>-ZIggxI&L`)W3&`PeLAj7zSS}(Lm5a&6 zC3UWocl3ZD?B1gzo&SKGdUAcaf!t7T zBsZ3u$W7&Da&x(b94SZ1E#+2nYq^cwR&FP^mpjNEZe-a*RAto+M9}r^r*~ zY4UV=hCEZACC`@U$aCd+@_c!Lyii^wFP4|cOXX$qa(RWkQeGvmme%(ud|tjFUz9J&m*p$+Rr#8HUA`gTlyAwmR$ zLX`AM1|_4CNy)5aQL-x8lPiizrcz6(t<+KKD)p55N&}^# z(nx8nG=T~j&6MU!3nfyCQd%mll-5ccrLEFVX|HrpIx3x%&Po@htI|#BuJllPD!r86 zN*^U!>8tcp`YQvJfyy9durfp$sti+xDx8S*@&5)++0i^~wfi zqq0fatZY%XD%+Ip$_{0xvP+3ob}M_7y~;jizj8o1s2oxbD@T;0$}#1*azZ(&oKj9J zXOy$bIpw@^LAj`0QZ6f3l&i`$<+^f1xvAVzZYy_`yUIP~zVbkMs60|0D^HZC$}{D; z@zO{=C; zgVhi>y!rfM^_x!OXFRHM|EYAdz1+D2`wwo}`y9n_9$C$+QMMeV9~Q@g7@)ShZD zwYSN0h?xJ{~>dQH8q-cWCy~)W_-*^{M(y zeXhPxU#hRvztq?28}+UFPJOR_P(P}l)X(Y{^{e_#jZ?pCJ{qRs8UdxgDGiFEYplj; zye4R(CTX&!XsV`Zx@KsmWrDX_>VwT2=^6&#nO`h!&>h)N*OLwLDs0EuWTOE1-pI1+_w2VXcT( zR4b+x*Ggz5wNhGXt&CPyE2ov$Drgn8N?K*DiWZ?&)v9ULwHjJYt(I0>tE1J`>S^`0 z23kX{k=9siqBYf;Y0b43TBH`GwbWW^t+h5!J13 zdTG72K3cTaSL>(s*9K?S7{Mrb3oQQBy2j5byqr;XPpXfaSaWs){o zo1#tCrfJi)8QM&3mNr|Pqs`UkY4f!O+CpuSwpd%DE!CE3%e58SN^O<4T3e&7)z)e2 zwGG-vZIiZH+oEmNwrSh79okN9mlmt-*7j(7wSC%t?SOVrJER@fj%Y`eUDmE>SG8-}b?t_BQ@f?z*6wI`wR_rq?Sb}Cd!#+qo@h_C zXWDb^h4xZ=rTwM7*4}7uwRhTk?SuAF`=ou=zGz>yZ(5x8UH8#39oGq+)G3|T8J*QR zC;}tsfN84Bx}vK(VEpKYZt9k9>yGZ~N%W+;ubxa#uBXubbbmdi9-ybvQ|oE;Ks`uL ztEbb0^$rM2gdNaMb-a?Pmqx6<~E4{VeMsKUP)7$GE^p1Kby|dm$@2YpxyX!sl zo_a66x86sO*8A%H^#1w)eV{%_AFL12hw8)h;ra-Dq&`X?t&h>i>f`kB`UE{jpQumL zC+k!6srod1x;{gnsn619>vQzE`aFHUzCd57FVYw5OZ27sGJUzeLSLz`(pT$i^tJjr zeZ9Ux->7fWH|tyUt@<{7yS_u;sqfNb_1*d&eXqVx->)Cg59){X!}<~ZsD4a8uAk6P z>ZkP6`WgMKeojBHU(he=m-Nf}75%DyO~0<+&~NIu^xOI!{jPpbzpp>gAL@_v$NCff zss2oVuD{S<>aX;_^w;_u{jL5^f3JVgKkA?K&-xertNu-o)4v-&24>&}VUPx8&<10$ z250bwV2Flf$cAF5hGyu7VVH(x*oI?3eMJC|^EHwg$&D0-pW$z$Gy;rNMrtFC5oiP% zX^nJ7un}UUH!>I*jZ8*nBa4yM$Yx|WLX8|on32=SW#l&U7hrQQoLvR5U6Xm5nM!gi+O~W>hz77&VPrMs1^xQP-$v z)HfO!4UI-dW21@D)M#cjH(D5xMwHRgXl1lE+8Aw(c1C-ngVE9GWOO#V7+sBSMt7r! z(bMQ<^fvk!(MDgRpV8kKU<@<{8H0@>#!zFJG29qoj5J0Wqm41fSYw1XCFsgMl+L{+00^QHM5!7%}_Ik8D{1*a{*Le9y70*&&+QYFvHD)W+Ah% zS;Q=A7Bh>RCCrj$DYLX$#w=@=Gs~M5%!+0uv$9#mj4-R3)y(Q<4YQ_M%dBnIG3%Q3 z%=%^nv!U6@Y-~0$o0`qc=4J~s(u^`&nyt*%W*f7u+0JZlb}&1doy^W=7qhF`&FpUW zFngN4%-&`nGurHH_A~pN1I&TuAak%e#2ji4Gl!ca%#r3ObF?|e9BYm<$D0$(7;~aI z$((FXF{hf-%<1L~bEY}VoNdlA=bH1(`Q`$1p}ELhY%VdEn#;`P<_dGAxyoE^t})k| z>&*4$26Lmi$=qyiF}IrA%j5T+gd(6G&K6Af$z&vOkG7pSwIxE-;vC>-^tc+GBE3=iw%4%h^vRk264lB&cY2|{77kR9_Rz54gRlo|j3R;D% z!d4Nhs8!4=Zk4b~TBWSgRvD|TRn97JRj?{rm8{BE6)VE3YE`qUTQ#hjRxPWxRmZAp z)wAkb4XlP%Bdf91#A<3avzl8itVk=$YH78yT3cqqpZ=^7;CIG&Khq`uwtx< z)+B4PHN~20O|zz3Gpw1`ENiwk$C_)+v*ue1tcBJhYq7P&T52t`mRl>VmDVb2wYA1t zYpt`^TN|v6)+TGSwZ+!NkZx@=vsu3Fcu>(&kHrgh7@ZQZf%TKBB`)&uLI^~ic` zJ+Yoz&#dRx3+tuz%KFQCZN0JHTJNm))(7jO^~w5deX+h;->f+6yX|9RHf|F(X;U_B zGd62;Hg5~IXiK(iE4FHDwr(3x_1>~=z)^JVBz98U*G^_9w^P`Dw!fXy4zN?%sqHiX zju>R8wbKDSTZoGufH#EKnIVo1NVbwR6~Ec1}B&o!ic1=e6_M`RxLBxLwdL zWEZxJ*hTGPc5%CeUD7UPm$u8;W$kiydAovL(XM1ywyW3?c2&EYUEQu>*R*Tdwe31~ zUAvxL-)>+xv>Vxt?Iw0pyP4hGZed5-QFcqamEGEIW4E>2+3oEPc1OFD-P!J9ceT6O z-R&NBPrH}h+wNmW+kNeRc7J<-Jbd!9YtUSKb@7uk#LCH7K#nZ4XzVXw4T*{kg} z_F8+Lz24qnZ?rero9!+3R(qSh-QHpEw0GID_HKKRz1QAn@3#-w2kk@lVf%=E)IMe( zw@=t7?Njz?`;2|oK4+h|FW49DOZH{^ihb3-W?#2&*f;H4_HFx)eb>Hc-?tyw5A8?x zWBZBy)P80^w_n&V?N|0+_G|l%{nmbGzqdcwAMH=}XZwr&)&6G3+20)>2Xk8og_|D$Ja^bBzICcevZGB(g|=U5J+-c!NI#EtbrlhfJh;&gSo zIo+KePEV(o)7$CeL_2+*eolX9fHTk;_oh8mvXPL9yS>dd7RynJk zHO^XRowMHA;B0g@Ih&m=&Q@oev)$R@>~wZHvCeL1kF(d==j?Y5I0v0W&SB?>bJRKJ z9CuDQC!JHyY3Gb{);Z^#cP=;=olDMT=ZbUHx#nDVZa6ocTh49gj&s+!=iGN5I1imi z&SU3^^VE6fJa=9=FP&G;U(Rdijq}!d=e&15I3Jx)&S&R~^VRw0#5vzx9~X0RmvBj! za%q=wS(kGGE6^2P$(3EjRb9>1UBfk9%e7s{b=@RxQrFi_<|cPjxPGp`o6-$%Q@N?# zG;W|9M;mYq_=E zI&NLJo?G8-;5Kv{xsBZ>Zd13J+uUv8M!HdMOShHV+HK>ub=$e^-41R?x0Bo1?c#QI zySd%n9&S&!m)qOz<3_uE-F|L=cYr(49pnynhqy!CVeW8uggeq5<&Jj8xMSUM?s#{C z8{2L+)Ysh;i~H66=Ek|-llUaT{vTs! z8Q4hD9PH!_vMft7?+)$V%aAC!+ufruGczZ$G?uj%oklWjn3eVV zMzZ(v{jk+l4b#)pP~5>o!Ah_itOe^qCD;h6!Ddhkwt{-l2%5omz-|lK4=B65WHgWXz*BY zJGc|v4IU4k2%Zd{3Z4#LDR|}JRf1OyUM+a_;5CBR3|=dE?cjBS*9~4Tc>UlFf;SA_ zD0t)GO@cQK-Yj_Y;4Ol;4Bjeu>)>sIx8=gGw-4SSc*o$Kf_DzyC3x51-GX-y-XmxS zM?oj(25E2{^n#P1AKVL0gF!G1M!`6k1kVK1APZ)}JU9!^gNxuYxF5V{@Ls`t2k#TS zZ}5J>`v)Hod|>cF!3PH)5`1XzVZnz79}#?H@KM1>2OkrBZ18cx#|NJfd}8oP!6yfw z5`1d#X~CxlpAmd!@L9oU2cHvsZt!`*=LcU9d|~iK!50T#5`1a!WxZSZx$*9YGad}HuU!8Zrr5`1g$ZNaw(-w}Lg@Lj=o2j3HXZ}5G=_Xj@^{9y1y z!4C&N68vcJW5JIHKN0+7@KeE02R{@1Z18iz&j-H{{9^D+!7p~{G9M}!_NypKm3C53&Sr8 zzc~Do@Jqul3%@-4itsDLuL{39{F?AnV+@JGWR3x7QPiSQ@Gp9+6E{F(4)!=DR(KKzC7 z7sFo)e>wb>@K?iM3x7TQjqo?a-wJ;_{GIT3!`};kKm3F655qqS|2X`U@K3`(3;#U) zi|{YQzY704{G0G^!@mpvKKzI9AH#nN|2h1Z@L$7!3;#X*kMKXk{|f&*{GafDqnC+Z zHhL&piB_YvXg#V#8&NgdjB3$VRF4`_Gun=JqTOgO+K&#R!{|nIGYXql=8ydeKSL zkM2dM(I6T|qi7sWqGzIMltr^>9-T$!(M5C_-H+ZgdavlcqxXs4H+sM5{i6?vJ}~;A z=!2sVi9R&?u;|01kBB}p`l#rmqmPL`Hu|{eH-iM}-Yvgpf+ko}d>S4CePeNFVW(bq*^AALjg zjnOwn-yD5Q^sUjiMc*EMNA#W1cSYYFeNXhg(f38)AN@e|gV7H~KOFr?^rO*_ML!<> zMD&x<;(a%LcAN@k~i_tGdza0Ha^sCXYMZX^XM)aG}Z$-Zy{Z90|(eFjS zAN@h}htVHJe;oZu^rz9EMSmXsMf8`^Uqyc%{Y~_@(ceXXAN@o0kI_Fx{~Y~G^smvs zMgJcCNA#c3e?|Wt{ZI72@yo<78$T4U#H;aIydGELjkp?b#uTI@pI$n#m|pl5Wg^fQT*cgCGkt+my2IMZpE(< zzheAo{8)TDz7yY#ACI4ipNyZ1pN?NCe&zU8;#ZAdEq?X*HR9KdUn_p?_;upfjbAT* z{rC;yH;msXe&hH};x~=oEPnI&E#kL~-zt9V_-*31jo&VQ`}iH=cZ}aDe&_gI;&+YT zEq?d-J>qtJ6nElooW{p-FFuL;@xAyo9>l|V6p!Oc{7gKJvv?NIx@sGwo7XNts6Y)>RKNbIU{4?>-#y=PTeEbXXFUG$V|8o2*@vp|e z7XNzu8}V<(zZL&>{5$dQ#=jT;e*6dVAI5(a|8e{$@t?+j7XNwt7x7=le-;0A{5SF6 z#(x+8ef$scKgRzQ|8x8=@xR9Z7XN$vAMt<2{}umt{6F#kCNGn`Z1PaDlB_0c$$C;r zHj-+xnbeZ4q@FaAX0n~^B)iF8vY#9zhsllPW)dV}5+!kxB)5`>lSh*0B+pHrmpngt zLGr@nMahekmn1JuUM_k0q?Nov@`}l$$z#dw4*GOJ7d9CENlh;XJH+j9}^^-S9-Y|Ki@ z$ur3`$&y(zPtKC_cX$`Wn|xmK z`N7Ld{^?_$@e7Rn|xpL{mBm`KbZVb^25oGBtM$`Sn}h^Pb5E?{8aMO$$THTk`M8e+8(JexJ!{b>s? z>~4RCOLaQk1U_oxBt0H&kem$Kqjbv>EjqQ;X=k(6SsOR*(QK`arZBEAnnmih`yQ%cI+8!R^UOwuiq$Y#@aX+1|1D=ehmG-DR9rwE%=jo9j zQ-^3}vw62aUTaVIpj-OCb=)6y(`nTK{c+~e{mx)K?|L9>A2Tjn;!oacpQqV)n66SG ztH>wmpQQ)w>9jrSrLCiBf7ELokEiGDY4>muI~%v~Rv*ps!dW`%wvO7JQz^V}g%wL# z$*6)HpR*1IJ1%uJp3TO?)*wBe?Ji)Z{oaY8It)~MlBH5_)0OIu&qv!uvNb#DcTS~$ zv@Uskr$M*nKGCh~(Kg*5Ud}#AFXUTVez{e?!sMD(OK7X*JC|Ne_;#g^%bWT*VDB) zsgFf_C8V`iZD(1ZO>Z=Ns6E?k&t~n;$uJ$wHjl>RQ?{k7-`Qx-WsUVOYMPi&2IF?O zD(NYqBhEM4XRTR(m`+!Z+DDh0vc8Vy(;jPIlG&u)NgI;lC8ud7l_)qmtsJq)$K7hA{TU4EK0O}^M2j=RWk?tFxAoYg zdGdCVyi+9a7Rkqpqv=A+XQ z8{XPc$^=?F9`LPd`oEP9C$r1FQrf0o-QoQ6wvT9{b(D53d-W(yr?o}IV6bsSL=rt$ zUBVr4RRyG{E+xmsj^gy-@Q>J3Og2c<360O%ZjN`R<1AY}>Yt{KVPAkT`{5A{Z1Qj1 zkx(ny%29t@}cL$GH!Bgc3389)^21c{glmqnjSOFPqvQ+978Eo8qIMK zrRzsfRo!gsXfUS6NjjLM(``8&Igf>uXr+)8)uX{Yg?^fyH1kxeEobXa0YiO^paAOy zhSjlKKv_DQ(fzE1nsJO~$Ff8RbHQu&^Lz;q`bf-H#Qix-GJl*jCR89Xr#6vqT+#hBAZd&vCvYA_Y z#HjEB+6Y~dV%DZ^@&;tH%Ry@0;6$K@T1NKM+z(Q2W_Pbr6+5ermyZ+kI zbUYsNf1aJJ9L;+T=*0narBFMpjtv1B*AaQydWY>G?XGs(rzw>1Y1$gJFVkt-b%38A zn~aJqG!BOik}RC|v|$N1uL{tS&3P{LWao4z2aS-vaRuYXvYz8*N;PxHO`almmR`(? zXU@jm_GOjAgVqo_S^7&V<&>+rWIxN&uGAi|0d!J!#;z-rvA}249CmaPRL__-5TWCX zdY+QqjHN%8tZqL<>L04qjnd@ zz_%(D<#WMl`Q0(?(uHg`kPb8c92%1o)^DAi@UmqzR5Qo(I#4=|0`4-anx(?B@JiXN z-_zZqw1D#AN+{cfYaLnk$9=lN7d#R6F@u>J52`{f!1qi$+m=e(GF?Wg&w>hSx~vmO zv~h3R9&S3gRA|yq*K}y81fwqdUSn~n4i-VrI3(9%Z9or~a{V~d9iAZ{LH6IYTNHD! zF(pgIJlYz+v7GH&FX6p#zWAqOE|eXr@1n8%Q!h7_Ls`(Zn?9BoKNIgzPa;J4oCxa%h8&AVpncHS?`?8 z;e@vxi{8pknL{$oRy+L}+tHvu(T?xrDU-Q0OBj(C?3du2IlY3EzLeVXU!_shl})kK zG#%}nu1oghvab8EjVpZfGp4@$mkpAh_>{G} z7!UFgd2MmF-b@1=B)YsD&GvH4rL6O5Rummx_(XGgs?Si{+pV$+n_7VBi-| z(k#tff3uko-Bry*9FW)4c?y}jLt#go{?{fr z9ap@;Hj<2z$IG-oSb(mS(fON~QOL^Nw3>GOSVrCv|FQS2V3|VQ&5_fw2xl1%zKQD? zu@pVZn#`Z|%pCq$SOMQQ!|v)h;>6GlkVDII%%3lSm5@=B&*FYF$Q*(B=DuO@qij4# zp%JD?g}jt>*zON#o0yM?<2vJsOg|6I*%y4e%PiHyjG=b9v@A!PhqCrr%EWM40?3K9 zA&4pEw3sAhh0`sE^{bc(GCu7~uMyg&)0NKne6Ito*rz+vQQ!Nxj9dObH_MqKQm|U9 zuy&KG{6k!rrVUNOv2-akN$Uzu##4IPXIqkDPQJcLI?LqT&ZLe{wtACn4e)%l+L<5m z_WZLaRTU6#o{8+8Bc={_J4ANRD?$ry zwvSpfS#hJ@dbi(6TaUS)+wSL%`?>3W9(O-aYvPr(vlQXd@Yp_u{+GXGbhhrRtcHfC@^p(>4pQx)3sFgn@#=S5=lbcC!IvcX9yXw zjlu@Tx!4yEas(R&!XQ`UFvrRVzXpARwB^!D-^@#o(m9JhFHbl8(QOxxC)w-fv#x<_uf@a zi!REQX9I+1S7d)E1LF$FG;`0f^TZWbvDB6p_p{6a_a;4gk^?5)V*#34Y$98a?nZk{ zu#`D)I0S^eid!aNT_5DYa8K1;#351U`T>xXG~w_+HIe?ilzilMAWj(> z8X*gP@1=}@j-Zg<6p)p%Dqc3jV9D22dX*!lk&1vVIW#3?ZGi^ zp?PNNi^hS+I6x&P>&FA;{H6TxiPrT@W_;vmMq21-pr!|H*WL4QZ#<@>t?m@T4(dv+ z;-``Wbf5AW%KFHTR`Uos>#Sv)Uk8?F9IZBYV;Sp5(YonDYgi7Ny078|SRQh$#Om>Q z%$(w%Yy~pXk~E<#z)V!vyrfGo-pr)-fX_mAJq}6rFr86m%I3mpM;P)Jn*j4>e*q`T z@&57U&H_?6%H0KwvbgkLTN9-hebO{m1?{QTb}RtXQ#z;Fd^H~L9&Du?PPx{FQX;6e zr@AuwRNhIOI!O`XOVkP z&InS#t#F5&K)=kkeF+$jHX^FYi4FZTbIzp}tZ&AS>nddZ`+1A9X~D{#Ovm%yNo)nm zNSmqlglvA4b=c|hDV5DR!yL+FF~|2hZkMJEecGKK6R40$@00khXQ z=bfOLub>=zU~^GR&17$~FXJ#{QSFLx!5W>K4=el^vjns&=bT&9eo2VA?!Zltg^;cL zq-$aG7{NMki{(bMNVep#-#DI+lqjwAkl{|+-KPJwA*}V<8C0(xIjboA(zRZD4$;#%! z5VBZOPNywj+?^gCP%_$b^j)l%qLw?l+;gmi)7kn#Z5H~;S=t_EHQyFSN0&uDNkH9StuaGFb&78MoA zPcJu4kXFGx#4($m^rwuaVS8@@bqp%a z{44kepLC}?3x$LPxUqnlLF=~QhLP7V;Ln(<@B|HqwD((g+`)E##0>HWh!BOfKEfP1 zVd3caN@*L9D(YjJql+~@lwqS{;qo-)`PjCxqnW1DdS5Ll*>?c5$~}w|M(O41z5cYl zaW6aWcf07YPSYNLmz(?v=frZVO43PMBqfxf<~lO4COD(>Nb5GZYY8Qe)i9@?qY#2+ zjRKNGdn*T7Rm~ijrn5P-JBN`0ZRdbZ_tSB=zc#?!a8TF(HWDjH+-m&sx@yGGkhI8A z9H?1P&bl1P>dpBytq$V1>4b)IIJ+YiUGB+jICy+72k*7d;8KN3*vfH}lS#7xE@x;0 zk;n4gJ17V_fhO%s;Vn%JiIpFRZv$4beP1Z2Y5#bTHgj+y%DBOP{>}^l3>AEMmhQ+$ zM}F2G+6%7_+8oU%{Gj&EHrf&``Nep=&EMN;q~b^q(u$d*C!;`{pcUU6g#er4F6Z1U$6o70^l>1V}W31gL* zB340OzFbKxX)u3aC#Uy2`Q($GUG@<=g#HxGxv0<@j^gPsEF!V2vAyW6Ppx^MalBfeYY*yPzOp^RoI7xOdsuvDzH%BqSMn=MkY^ zALS!p4PYlvwfsPDIgFb~n+_0hVzWr9T!p7#AJLL5H|_-}UI-!$ zD3!?iP|9qmC)*|DIh0bmK5BD%q;>bxnxtdI5}Tv;SzoLW$D{R8nsVSZvLUn?%s-^%E?Q{k^QYfozO>j!LogpBN7wkmzzavgU&N>u^b z1a|V2jfcyVsdz|UU(Gh?7E}@>Ba35Dfd^)BcIy7O^{Djb)&i7&U~BbYG214&VINy) zLZJsY;j)*TxV_MXLJw}jWiK~zXQ2s&9^8b>UT)&9G?BloLN)~X2t6)k9^A0YUT#>i zc@wT-+l1{2`4@R&;YAdB@bg^u^7EctXhNX}H{r6En|NxW356cqgv(xT;^~DZ6nbzI zF55S;Yg6lKr3|H==UqizX)L^^jBl|zLQA4PFBNY=(Oj~msE@m&@u@JAqyA}sJKsoU zzd*aTGVTxdL|=m{j#FUB%GIr44UVbTc0071-a@%6r(6>eY747EM3;G*RlhFyes_%@ zNM!5`VF!>xS;CfoqfENbCoAw#6(nG%9Clm&SC7X{1Ll*aCGCt@f*r5ar5V(#Fwp+D z)$X2&eO`A>oGjX8kGf;J#xFm^HsxHRB@%NqE>Vss)P6RLgFMgFdX`hvI>&~v1^ElJ zXWv_QLNO%GwSgGxGC*RSLx-lP@RxLtlZBU;^TqA>`(?lyt2?Bb%`8AxW@XYoU*S8f z^VdO*=YC|K?G{NZT=OU)>#QV`q9Xm{)9rE$ii}}`E|yo4jd@K^_@+DObIazsgS`lC z%R#~o%_lyK*#dig+HhIoKEO%b+jO8jzG}&yuRc`EO<#f0>>;|aJbm-7&of%WH+DAe zPac}|*C%~>>6J;pw~9=0Kw?zkPbPhp-xMuJn%47_6c#)OCU5)P2Qwiyc59RV{rl}z z5%FxxKWV`7YKm}Qa<7!O{7uE_TO7J1CYc@SW{TIhHvi>Ek@xP}-V4(l@9j*SENozOv`g@w}jQd`oejeA>WZA34#eck`U{ z7vsq>YYm|x>Hxn^Hzp7ZqRAkEwLTtdt0V@wYamOm0s-$aLEbbeY3+8(fDS@M6=e7W`rp=_ZrzefQ}06{AB!!}c!U7ROOvV~ zMQsjon5TF{5%I1~=7TILT&#)*PtD6D|#ZEIuBJmwBg5OLq%B_5?k^l+WL< zh&?R~d)@!GRM=h>hK25^mRQ10Qhdh_hh}DFOhj=LJ z4jNP6LS?&XF2k}kAK`AXI;9s|^3S@xj-43OZigicJIHjhjGD&?N4Hl> zTRyF54SnE#8L$$#d?InjP#Z8?9;R~`!HwyB)Dl(xYQ|VqGdeP0 zqNO`|%9>o$(QN2{F%3u3J|3<+L+7TO&@Jr>)4wM0xt{R^{#H?qE&TnZqAl68AIiF` zc^7r@M+Bq)4*ILj-P!zV{YT9LvM@V1EI} z)R}XZySmIRL>6heuAyArjV#58iM2bKh z0-)-YMX}|6oCJf)g0t4?UKy16NqdTtsp^xmjn;kI?b=NbS#Pni>tS!F)(o47*(Uz{ z6^UC~*Z=m3*PSVm`8hFVWN0=rB-ti; z1km%5+e6?&00-#}{V!UD`EUe<0*!?zE1llFia)}dXPWLUWVqd8cL4|6F+16GC^5>d zxg-=sk!bK|HBA`2AK>5sfem74O`u^2f=9 zCH0o1Ocp?wSYqze(=0YdEM7yW{BC}p+azc?b+>e<|?RgNg9K$fD8CyYnUKPhNjh9eY7cy&f!$FTd zT5*XxJ3hN`m)LZe47yZX(dkgf0ZKStw=8xRAl+$w*pV#@KO$3L(z5%b9gA{mtfP|78&tF$$qoLp|XAA)Oew((5C zSrG&M?sVvLJ!qwPAB=!0%YWpt11Q(&<=zZh0QHX0aaM5KvNpRXY&fv8Q+=lhWs+L?QKg~ zcUCzI$6NBxzUHB`)+dSsgmAGz8(JjxC3J-yU5!5^B8uO#ShpRCg)2`fIXtw~*u^ZrgNeahJlS7Bpr*qCpwBLhb-;XigWK zQQhY^Ja~yaE;YpD#nokd?aB){ya+~IE4a_X54lG@gSm!BW5UKU;tHRq=_#EarsMS^ z2wq|X2w#nEnT{j)2DUz zIP{RVu=DU4LLHnPVf2RZ^L&O$-DB9EFbrEcZ;#gS zRv|u;{uiSK$WsqE6A8)3s$KufE71Zl!aSAjZF*=voHVfRkfTX9zR_Y3k2$df&fDHNe&GVBq zg`^hmV2EN76CL$Mq_eBWG(t0ogjo%u!$lNAPUe|%05h6_smV*@2JSQV7BhH_(dFtn z>a7j=C!cMLffnnwF;ank^&AQQgxS>Ik~e~=W0147UIw~N4-Fxwh6p-xxIa?3=JQ2d z-|%U~A3`SY6v_dYkyVAt6`@)YAWY1|kWI~2#gKCSTz0h+bu2?Fm3y+4oKP;1+5|PiA!%O2%zJ#+rf$a5#k*k+dVO7xz8!nGEN8GI+7W8d}1pMReEBJ!Egg|gYSnPDn( zb`e}uc73Rvrc5@>c{pr6Dc~ZN2!Th~4NlJSg~q4IkO^a^ITY2AKe&n4py3Z>G3Y>> zj-(9O+Y?-1gr1s$YDqXh5|*pHnbV4ut%%PbFdng!OO?u*6P%Ek4dz~xAd@ovEAJHJ58 zZ=9T4!+_nq2Cox9M^l+oCgeIoC6?}uVuynNR3WBD)#L1tZn_gzB=F9C=>*HbbhIaa z9cJs{Kdz542IZsd*OoJX=jdk25{bvzldcog1>5tR<@!pB_(oQ-E1lpQt!ko{`th1t zq#`kburaUeiZdzIEk8jDnwedta27EG|0~%d#!enoR|m_gns~&w>*VSW$aDs$X6?UJ z6QK?EZnAr_im@@yjeTu-IN$YqXt=Q38yLOC;7R zQ*fd+NLfxT1aK;7V|(ePtFt+dmXHO+06E>Z9n;1(4`J!IQ2oAXE4MWiGtEQ!W@Q}P z7@zhkdIU>1I9Mu;#)x&kzl4SM!#+%oOk}PZF=dMcx z1{CW~*S+P=Q0Gx`=l}{xlq4K>ojkDV(8?x=e5GE3@h5Q5kfU(H(AZbTR1{s2d)Rid z)4CHDTh-hyQ8rmIL*xX{&H4oAjOtXLSrZ2}PC-#u?UmBjQ49!R^AQ3&<+&cWUJWiS zp+)sZuV`0i^x#7D59|^60ZeB*POIP-isi1QFFy46ybHJw{tNDw5a zF?7^H4XsV9-RS}MKRM$jNM_+<+> ze3=b(G;#Q7!oap5rdEicgRKIVE;o!d%K0}MfCnoWE8)Q$ZiAhqb;*0xRO>7%gAO8Q z*+S)5Px0v2NCs~9;5FZ_o=ALJ_R(nt!9y2)|C$>5>`vL3#fhmnV73iq+kedq8iYDg z0kV=VXmd~>tPu~R-z7+Hn`pdniR1feUE)~^YtCH8L4dvq6>R6@5yWH>cFaO|Skx@K zNUY#I1d6lsz2O%@zES$NT(}9RsU^q)jJMb}!5Xj!V=Tg$%6OxVf}EFBzK%uHQ8>eQ zWk>K$7VhoPDDZ@NhPjSPRpTVsC<)M@#HiosyclQ)Cbioa64{2(IkotQY@3MM+z4}9 zUPDN4S4Z>HbkmtqFz5mU6~ME3A?D>GWG2CtF`HvL*5+oye9kUM=Nq{3z6p3 zE8B&%xTUcsov>9r;6><)JZw$;xh~h|6F4!LSdnM6yqJlQ#yyGfxW-I6x?DvLa=FTp zKiPpXaOTrCqD{pV!tuJ=j@qX@Sb(e!CNb#+dQJ@tXQtwZI%1j@ z#4^hhK`VTYcJ3a*tMjN$$}u`nNGAcC4pd@EU{CSUSAY#jVs_)~6w(jrzDy+OwwXBk zPW<`qkCalNC(*mrmFKrtfmxE^JqBt(7h%MWU(u2G!6A5RU6_IsdA>Zc<~R_2*BYCJ zwbImd!71&R!v(FcwBLMe0r_bwfuwCxD?fnPw|$E9w6ZSV=X1R$ zj;idl`lF#Io+FgaGWRMhQNG-b<2i*Z+f=pf7y(U+SD5VG;(4x0NO5KJ@NSW`H`z8H zGMhDcg^f?~AVWpUC~e?RgzRK?S@^af?!?F=-}uEL*BMN37>JLGRKpkuh>GAYqNCEqxcLQ3pdLsiQGwSJ!R3bw=CMT3|&ceM_hT@VH*gAViAO7!w{GN zLT66-fnFG3q{q>!^WLc;oh_T6sA@!}7B7&an0%?sJ-0W*oQNfby^_ql89EISj^)EQ z<=Dd5py_`NkGT(rS4! ziS5>AxXZ|U=ZpY7v{G<&6v~*zvRndy9C*-CV?p zvBkB8bx3Y47FHZH#j0$Z!GcNBQSgf!&d>wfCg1>*9KTz$|~HA04KKa&K)7dbndK9v3tat4}C*gdf& zuAo9k1D(~&!q&OpzGYc3aR%MJh0UIj!px@V8l24lU*DewdHozN)nC9_{q4o$W1unf z&0$`9BrW(T;&#ZmZdns`*My!pc%v>rQaQMSv6>=CLzV6*UC#~g_84y&cprEX$BrDu zj);wtjMWlKUTx1Rx>DNL?M2*tf`7Yfon{a7^!d2-v}PGiG2zS*@L}sCLciK6@=%?7 z5TR^aL>aj#Nwkp`2{E9$6(kI5t*X)`3*zB*pQiH@5^J8lsF40FNv_#yW#dM!B<4&1 zALaBYe&PS!o>D#1V zTVAcE=bB{cd{Q^hWbG#q{ zMTNAGbBno$K)$={Fiw)?P#Z=_N^Cc!C~ch)`b?x7KH7{IEI*bDmW?ftF*2WjIx8_< zIu$vr>Bpw33OJq8*%}+zz4o?s*B){}ZM*^ek!e^g5JhLqi6DXyos(oLxy9(v%YgLQQ(gzF zLOtN_jp3^Xd*xhI@T@3_0U!YK4Wp1M&Yb>kwNAAyupF>u#z^&|>BJHmvJ&?`);qz z%jvNAEjdTdCm!R(!rIs(Mw;?>q4+Y|kUwlZYCduL6`2_t+g%NIm8RZ5TBFPzg8)t#&%IvzlA8-7z#Rv4mwsYuYH3@|yN+8F8K229RqIJX2F% z&F=w76(2rUY+aaPP67&XlS!~m3G=B|V5{Qxz#eJDzs<5Dykci`SpXP27QnqpDd%(w zYiP0{Swls+*?AZFg^R)H^)CcTB$B3D_Ym-KgdqEHDd3^sE%q1U9(rUAQWh~8^3qXn zgI$ChjJTRab;vq(I8sqpu`Kc8AqQ>M^pq=$W~;~ZbWri9xCJ_CL(X0@AF~``SD%!_ zj<6jxMUBO}Q*MlHtD)*F3^$?hd5Y6+No+EwgmghaoNPw|7`U(my>TJ1n^p(R0FIp@ ziU*d0gg%3;I9dAB6H^=Cwt2}*cIq*jeQg@lgSjC$O*vTidE$4A^B*{Y#x z`-pUrfNyZPsWra%;%dUad^4v)-S-9-g?>vrqW zWz?P4W6P+=ucDp=RWj=IQ57@oVD(}+nIxtYvcpdu%^f*%ua20d21aVi&LkJv($E%S+I%Y5?LGM{?3%%>lH_`!pqwE1%$obOk1g_~nKco^;! z*LV1w(#-+(0g0>*Z#u>1#hEFXjG2(nC9SNlZ)OBuS+Lq2kEb>H=S+9HRZR05Hgw}9WYPI) zn!)&Hr%qPv=j*2Kp-OUBILbtYvU)Nf%&S6{iq2wKRU2I)5!X*SF=uIoE9ou?K)fOB zl<1nh%ccuJgG5=x@tlHK;EUsmc&oq~`ko>4;NVfSD%7vyUV%aZCpXN+g_DC2!Y+Qt z0pnvi=fxyDLoFcLsQ<;Po)m2ZWHK_CdjlnV6YQ!ACz&-0KCTN-*y>$(jE4F#9>!8)7(RE+~{o` zjj~ufn-dM8f{sW|(}P00NDpMYMIAS2nAe@V&o2kvp^|SXYVwLUScxikcG$32M9M85 zEK5Xap_RF@lw-`1$9uxEC@MMaYd=+r`!Q4;C*&2gPp)CW1X$cW#2iSHYJTYPs6d>XOJQ zHeDbc`NS1eSCf-x275~ZR1ZXn}S3k4*_xIu~oAbakncywlL z=G@NbS!TaeZ!d2RP(l`cMMke8Bo9`cW&_Uj=yNM3GSKNvtd{(G+;@65)-AoZ&*_oQ za@dfjk#klNxvec%pFl41dilPirw6y0qLEx{kBISo^-8_RuDJs5@oR8TK6>-YVePjA zZjggnl}qb({l#5uCDvEGt5wVF! z+P-Ydrq^)sGi>82Ob!O~wvz;9oFp?B=c8m8;>b&fkj2xmC>gl8!7w)_%>267_BCu`8I{S1@;OEZ6b_ zxx%FmH{A>pc;*>)P5pvU31HY@xU1H#`n75$JB(FP%&hRbdS#l}pdumRbgPPx zgIxk4ia%BTS~Q`Dl13_ZASgOgIW{AY3To{kNd5zqMHXtx5l=ZZ#q^XX6o>CFkCL=P(t_`xl&3HW+>QYh; zeU1!*K$h5bjBR0F;c$^q_lXzQ?W+aU%BY>~`qd_^KfEA=_1Mj;D0j?VEqnWF+1n2) zd*^D|I}a**_iEX@uI&Dm&Oy$`*CA~VTy4s)E*FJF{fFyvE@`+C`Orkj6gwY{-hd66 zqt666vVx<_^=bPE#%jN;3AM?$U4$xt1jnM8=mTm!BF~D{ zf|c*f^0ST3-e=Ftgv%=d{Uc}D6}L2dmiP~=o3XU*84X8ZskMif)Cf#Fp!L=~_H1FaxJ_~96ja?QQ6}9vkZYM#z~J{2yqQGYpxcS( zI+(KJYI0wV#%dyk@Jg%gQd*-f1Z9MCSn%f+t{-@j6jS?P3HEbp87m8Esp{>es(za9 zFIK&+LZhXscb2O9S-({E&UIDqE>*Qfu=v!wS~Xfk>Xu-0CS1(ZjlzG*oy9D^b#Mh^ z%`ElCx6mZYf=nzcRa4j*83^yoaqmmYxuilV?QkwJf_BSid45=VV*y_?zw;g<9i3wh zVJ0jSrUiu1bLsKX4CgwZp>#|m_r?$b!R4Xj*Yw`Yk};mwN;tG}aa<@(7#hc1yS^EkT;B&bkia4>W<-aOfF)}F}8c; zIbK6ryzo|+uRFw)pnW=R7gv^g-mN&(oiPJyLp$>!^GXzeOvh3tQ>g@T#+Pox#Li;W zmHVwSZn=_r{-Qp8J+E$XkC$us#NgW5ocL*k>GiZbK5KK`)}^}?M|@!9`d8F%ki()1 z+jI;m`j1Y*jylGmfF1Wx6-rR0=QWPlj!rYSIcHSnyHN&g9c)N-5u0pTLiiWQfSM7K zyOG79yrxjkB0WIdr3w@G6uY!z@og8bNKl%Or=W_!1sU>i(}z7j?h_#&-iT$TSMME^ z0Z0~i)1C%J7uC`}%#II=UYZEX0hz+23|Pk>8V?;0tA~xFY=jE0d*Pb5Npg@Mx-wwx z)Pq9cP>7^*@e=(&#Hh97DpdjcZO7~&6y==qt=k$vMY5AL7&7A4zyn_n{DYjgd&jyJOhu|3f0hW6c* zS;ZH;()}y1mALLH{(+spn&EpUlj};8o{-4%^liOynjo*X<|W8QrdIJ-Z?a}D7`hIF zz4DIh@@>bnhWoJ!l_PE$#09#z*Af!PBU?nPO@v$dO zxn7;aqwvAd&AyNe$ubd}6XC?u{d`3@af0@pOQnnJhGn_QEy?-)!-B9!<|X}D7bOj0 zCG$&-ZICZ;YjKU{7%MB*EBZJc;S0Gbx&&IOx=BT0v*yDs4(h8jvB49{mLM07cn~An9jHyG z*f8->a0O$1T0@s|oHq17D+K)w*B0!;JrISW%;R7Q?@;b#5y+sCM=uXyRwOZdR}z6h ze;ljMb3)aoh7-`=3xG`KYj%*khISlXHI;IBkbybittcqiZI)3gWpD>;<0M-4Oec2(*I zDidWldwR~^Mz-z`Sy$y?0kSe%9;?f&iWiMKb!R(yDlh1CpiXKXTnV{k#SWHo+{aou zJIOGUmIKn?v9he0^dBQGj7Aq6pOFA^$>ABIU~Df%tmoP-#dr|=`0=?2K~)3$(xRaU z+0dF{!-m9O;1i#25zACQ17Ed2Uc=)HyCL1-$D{gDn=3C=)`An!_5#!r9ez1mdeg6rDMZ|-Gq8WPlztn_L}`NU=KemG?==9<$Y2{(Bz^>>)oD;kUQUxMc|zm z_xbM4^Q*2GiF+7HWuo*ZYLT_G!0R5Tboy+yI~cV^T?qlV(jE7>Fqa#QnRU&Q>6mOO zn~o8cKw}d+z(S2wHJ>Pp3PYRG+!9k2nW?M`*iSKwa8uZ;Q(> zw@}N5tlJV!jUdLTUNmSBZoLq|yNcALeGiYa+qLBESwhLa=bF#&;F?dwybZafNjMJ| zLF*OFA~)DD2U4#Abk55hP?vj7CFl|E$6q<+alQU@;NymHcEibx2?8OvR3V@QlR5+2by0V_ToW;{q0`SUdcoRvc@Z`2<=h|yb)Q*W-3IR+9*kk5u2m;rm+cr0& z5b`uPY!*k`369fMVuIpwBO$BN6L6-x5S9=G z+sXx%C<7mLQRx%6C%YX4BNZ&!bDg6^eQ_@*DV%c=b&IgrrED~6rRZ%N7PYN;AEjKI z@RA%;Q~VLO44!fkUflyUhat^&4sqUzRjFn7MA6*e^x1=SY>nu>L{YG)78_XHRs03^3VDWd*N}QgBt4#E2<<;xdCmOP|t>4Xt#RP~6u745R$tKl_ltryZ)C3b{LgwYVH<2J??U95{y zDNBW#;O#~5&LVhs5qx|Rd}0xNauIwA>Kp$#EC^Z<{n)k@fDLH~Q7ZaK zQEW0A(rwFXtaPBCI&@8f2stLNR+uk6hbMkQyj9F_7c1a0U?-?2lzLT1k7o zP5xREyNM!>Zr9fLN@?rBL(ssgLC1e|FxV}UR={iJQL@nZPEPXMCl0P)tfEtt3S~{S z7!^XQ=nQFN0a#h?4OX3LDL{ozE^hX8zE0>0(7hYv2>6>hs6JH%A)0$dVcUgaiIJnL z5}geXSLTO?ozJgC%-oDwf^RRucb4G0OYq}M@DsRFaP^}2d|JX@7jtUXl&;e}WqEan z@ss{w0kSfOxs~>Gj*CBZyfEDv28SB<4#^|3Fs#)dUeNblmD>?iOjL))!+Pf$dy0=` zFGjKPU6=5rgc4k>&V2P2y{@l@t=cA+58ZZ0FN zsU6KAB0S#Xu4r%tV`VGZdVcj|vL|2y-)bN_qhf6x8zh5x3D46Q90Us;joE93 zM&%?vJuj6xE2Ym%>5EcY?@aM^?+cz|axmx;;RB|Q6dPY27_HE*iOPuUD{{WcsiyGR zDGAZs(vGgd*_6x6t3YC@dyTC>m&qY#bH#I+T#m7_SdWTzF=8MT za5{ANz+Y# zKIy$l4h1E`p?qD&e8M7U8~2Vha-nC_y;)8JRm}$Du{?Dw4l)qCm=YY|S`p>sG#kAW&pBF(Q|wuugrZ*of7S+hBXTL?fy z+YJkpmEK#-(&-glgR}Cvfq)-*|1JgPtpt`epp=PK&AY31;)cybotcE-rd2kCmE43` zWgd!k6*3lFt#O^taye6h?ukr461 zNLeX$8Wc-wto={}3wsG)C2oTf_f3&TEv^a)jAREo*h1_OgQx__xVU@QEnhJ9B#q#f z*EB5MDz{)XL=xm49r*`^j0d}z91<^*>upe9GSVCD zZpWhXMzAEN1i3`r52Cj)SQMeGOE?;0>MJ#b78FRNOk#Rneqr;X@a5NnhOoebEI5=YKNZesOjM>66n2b`0Dr@S{W7+p4s;8kPbRujB zUXt$D@UHPcNy52w1vg7OgBrUUut>PQo62XLVfb~@FnzFL{j+;?!6mjfSyV(_M z;F7)erbz7E4zOD!t%V|Do`2eoo(+7Ld}26Jm?Oim_oOdMs8uy7^lD90u7CxHw~fKK ziub>AJZ19MEHM@dJS(a6rLVn?d;un4rH8BqWZasloJb@f*a18X@FVCTMjN>hrxNaDM}yXA;1l1kx?<4F=mj+g3y}4PJNrglaVR92 z-bkgg!V;`!g4|lDOAx#5QAs(Wc&R}zV3$M>!%c!*x94@Vbie_cwJy+nq9u%dB+%Dz zf@S%JEWY{VUdHuMa!t2f2PL& zy;!R_&8gWD(|%4Ya0(Qz4LR0{s{Lbf8m9F9Z`o#HN2Hgk`6@RoJAb4Xz!|>uin$zd zVf(smz+;d`;p>s6mXcX`q$zHI=n9 zoUhqgtZAT?@->waG@P$#L00`U4YX3erm~HO^EK^o@HGvzQog1#nTGQ_oUb`te5Qd`%GXq;-f+Gq z`$&0g4YX3eriuUz=WC7^YZ_>!d`%S?7|z!;hS$HRfmX`bRPlo0e9dPTpJ||#@-unh8J98^HSDE~MGmWAeHTtNscPt&?29uA{P@?SK$R=-$g9oT#g@h?;!4p2InAdnrf>Q6m}3fG2xDz zxRg`GZS_s>E@#ds;Z>A9WFbr%&J{(;vJ#S8Jj|(FM_=-yYjD;oeZcHmM4`DvjXo@+ zth5hzzeGXZfVD1rpIYgHbw;DI@7Z9z&B97-2=goVc;I&K5|&dSJco5NUnWaW-|WIn zpv%XDdqccMQAv#&mcUD}H@!Su1nn9194(j8<3!*p!$Dla5f{MK@)BRUcm{Er`-APg zh7Yq`&j^Sb$j;m&J*Ow9&iiy(Pqs(wl-{JdWS{jjI_NX7C!k+THCI zwlCK9Y9H(V?OgDEB8Lcp@^I`whW}?As^Y+?CIaP<|GIghv&5;iGtOKB!J13pA&Dm{ z?6LUV9Jn)NX%K2Tj1aAqwr(|ZoR@y)!gqgm-dsjl&27uLyCGRem zG{lvXk1v-r#FdgyESEIIm6A^`mo&tcl20v{G{lvXPcN4=gq1w7@qF4FLMhRcT#L0j z$ZMF_C)hY4HS#IT!x?`h@f!Ua-q$l_>1!9aPiY*fLn)&!yb6}8q6lBATAz$zr4fho zpZni(7ZfK3&Os+B(7Wl!EiOe9tv5ayL)>~LGOFHEPvgFmTY58j%bBpsz2GzM$wq?b zvk3{=o^j^S2ns~3?i*h5ZNb;A7#B{cdVGPl$uA-lVNzZ~0IO!2c9jD9CmK!^B36!= z$dDc;CX}4RD;O04TJU7_X=5&==K7$}%l`^Yenzh#v*IG=wmk(AkJ_lT&{S}}tcIo3 z7ph{xIKn-BfESIWtkOCd6#0jq+FSZ$c(<_QiLosKbm7<-P7 zCRx&P`m!aAmGyBZm3;FJdq<2i%1ZkXl(}}(JEi2Xm8%(9#$^^eI_H$)@t+N53KCRo z;TPhh9yqi{HpMPvvG8)d(@o+B$lU^*p1H(oVOgxZOCu^+GRPe<)g$6)A%SW4>MF3L zKLet`^=lHR9w$n%quDE^?eV2>Vg8+hg3!0O^j+O02TEG5B*%_aFJa_DN|Dwn5r`+>9p6ML;D{fM2hg?pDSaiVM594V#5l2UuEFN-CF+@6A1!=Oa0O#! z_njpuAMCh|p$)nl+@s>_kXED6+sJi5g;S|xTy}EHF;jTe(3K3^oV3|#R&~k|5!b8U zL->Q8JY`QH>>^QLk({0jopI+;@8ze`Cj5eMBrALSZF%pEiMVr^O_w@}nN61h*0|9} z()nDmAvb{g0nb(E=&2tu+&Yw)5}_=XMo7u{5O&YjVh+29UbKFFJ!!yh zP>^~I34M3ItxPbkO)3FIrJRW8s_JYKEF&ZW^g47M?oFJB@*_htx}Or?LLoxvbuGu) z39k{anm{Q&{{Lf-61a)=OJG^K0H)>urGE<}39)0tV7YU;CI4*UH^hV)bAEJR`0-~P zlxn+-jpcZ{Qy4EpWJ(05{2-Ij^}`kUb5e(KX$ZMEhyHLa4T=$YZI_bw%>(h9P`;uR zKsqG?Hg^hg%;BGzrMoB~B#s4SEBCo*gy`@p%DUo858<5HZkvgd`v&poBTtlH`PIV~G$rT_29c#%+UTqf)$;_H4My6{m!5 z=ARQZG>fDf)K(RiV}46h7p~Y&8PI|^JjTcQ(ph)TNZeY&%aUU6mKG&@&u8a%3+7Mq z826-dwtEuSEXjps$mOjm_oM>9^d#5+`{n+7pw$2S4`{W(FSWXB4L?u z_kck^6NebwS~`$na!9u?(FoHidLrsxvGBx3U@_uS?ww$JCNo@^Rbnfhu@*MF#3DwQ z2i3Nzd_7b*fr=N7r^g;$L)Sjdz5etN(CH!TN&3EU0OUCmz>F{mdd9h%w{ojuwGYlO zSipn{X(u5zRXV^O)3QZ#OIM3Zhy3L(w$cLlNVS&;qqak z7wS2|k%>Xi@?z|nxThJnFo z4|`Z=KgWGeCs+Xq zdTLCOUv$d5!et{a^#bcJd3_@-<>XDeAa7bj3kobw{{PP2};C}KbVhce8n z99g}H5zC)Nj8F&RLM_4M{BOgui0g)A%n2;jCu!gWmM(3*b5crN1Lv~8wuHS1b!%Ec zS!u5IW(Xniw=H2gMyl)iWu*E7En(z&S#x8!vY}zbHY%a*RDO~h=s8gakxn_T&|I-7 z((>N*=s{^G9Hm6KlSAS$7v@DxEZ6T5{|r}^l3B#6L<8NBf3hFc{bzIILwGu#U>lB7 zEe6OA!uEso)Ly>n_*n_TtTLz75!+d1%%Z_TfQzfyRkd>*r zNQp9FKIL|Ef>g@EmezCGmyA;bDig|=S*&4Dst#mMAG*}g-TjmoxUqRl7hrZQ*j+_7AO@>yDO}tB$5CrfF>X@>bIT#bYx#gE9Go6`P=?i9 zX`g3AkM0R0#VyeI=9dBKFKrjOg0QNDEGuWY8MHwFOpHdwpc#fyR%5=Y1y?ZEQi&9X zTs$chvaD8Q{r>eKIQ8HlDmrRbi^}aFE29?1VoI$VR~cs(3VVwXw~X)K@@VLvh5toMp%@ zU=?QY0c<=C^?8?>s)2u+1*nY?9gRLQrD{&ub`0O2?qI_yl3e``Na_i!!$IgGk(AaY z0gN@2h;Bw))1rXxLq6@!g1UZ0&SrH3cGn>oluxz%xa0(YNGEJUU3_MRgX3xh0t}3f zJCN^s4Wpj|O+l4*Gl?Ijmm1_70S7wTUJY*YFj0|pqlTrkq&M2tad?p-ACPYyjjt(} zhe3M&vt?QfL=xkiVY9u%b)Dn;_XlZk1!HAvmct0ZfpnnVpl^5bl$BeXLcnl#ajCdU zu~6a=!BqZP2@BMWBP5M5vVP#WqZ_U7Iu41s2A z)={*`mg1E*9?}9^a&4V`EI1#0YegD?7mrWbD3|g;VR!()#W-L3 z1>)P?KqjP_^XyS^u`lj?<=skjKKFiA`h2N7Y)R1QW}b2c&y6M6Iv_6ju13p^h73h~ z9nxw@uY8UCC31|7sJP-TG|RC1(j4&KvPv`og`Jf^MHytcj%H<_A<~x!0+96(+(r&@ z`y~E$F+5z<8BH#s=X{s4xna3qY2vRVXqHjkk)nKaF6z!9=jdKnxgu6uI9ap@&hf}t zX_0$a|3tu6FxlGC@G2@VZB2B>=L8ZF-=I2*9(Vh^INh09Q7TdTt(IKjJ-BR||CA3p zS@FVc@G9iC(p4^Nc$d$wVa#jMY+Y9@5mo_jQWYz#BryW zPIVWTQ_QqQi`*(qp6=^SPv?mCNak1w-+?S@G{ZGYV^ZfK(zBfWahz^W);Q35e!~cZ z{FHQ58B_()?43WLm2LP)WT;StlJys~L8t5eZmTl&oPtO7cBFn0U!2)C*+?226I2(>aP0r4!=u^^6)l1>- zbU6xHDo`w#GL)9)ei^Waxjs`bzA;+`-3rZCVPRjiaG81RGNw>|XOV1@6;#&}V#{AD z#0l?5zTv216Fm{OOM-YAXg%4nReClS;)gfl;++n(Lca~SpOs5Oyjwj<|<%Gi#YEHW(&f7U)B}AwuNFCKu+VW`=83X$jdj(n+ zn17xvS52J{5S+P$m8C5ajiBM^r3mQqbdgWowi9>W?jc99be``t$(rNDU7`-?`p8p5 zW;=3lQ2+*|P*VnW%4f_eU;KX+u>Mu= zaj0C%Tkqs4%UhF>bmP!5pK?stXS4!k3qD=9H)Wd=(Ey{ru#gFUm1mf*baV~QT2_U& zZ%B3=xaLx6hq3Y5K<|1gZv7bfokLwC?{Jf&QNS`44$a1lpy#ER$Fw*v-Ps_bF!~SfDsgm{ej<0#lHa=4P$3hT zQvchxz<8}cm~wxzQ!By@P2_wm{17=41Y<|eRBX+Tk8fR3&UGZx7?jP zWlbDpr&yK>HLXS|zTthvdM%z6-T8lgz2|ac$C9r7#iurO07=ldk+wVMA0xI}W@avj z1~h6C-~eQsx%%_GY0501M-ggPWo4OFD3g`efUOy+S57n1#M@oY=3m)`(&CrW)PBv! zjj_wlnG)S6cl*g8pDk@Ye}9^OMLQo=04by%4qsVn9{EQ6_Mw(k;rn6nQXs@cBxpd8g{$7*X9=-BkcaQ)<-SvPRx zZ@iVgOk@iqu34mIQcvM0c!e_6*SE-caZ$Y3jlYS?B^ZkK$m74xs;0hW6N|W2I+PV? z7hNbNErKI_x004@F1)8An5p2j(4`5ydKpD)yd#i&I*?`yUgXa zz0jZH971Com{y)vuW>O`-OOZ^X~oZ3w+qA6brStaI$>!O8qB3l?zdP9WCes|>Z?Cy zT>rpm(}`Q3m_h=dA}R-e+Vy=y%(!X$;KAv`(>RsOkn-cWER5VEb}9pV=HUZJ5KgqB zBH)`MtlW(jZqhj;8@gd}2s9;Bk|(lc$0bykibAj$dq(aLv|G)^B-2c+r$@L7aA)jn zu9p7lu3Gvlm(3pcRT8{kz)2pStw0j@zz)0c@)2j1!(4?S@rwVScmpIVdJv2GHz;H# z`@09gI9UVJI&!w3F1LFb0r2TRp^Jwu7&1z8{$$!*?zEGY@N7~lC8Sd&_PKcaY=A}0 z`x3+9mY7qnJtoUOyen}#nqWKv)z}S+S)9bm9Y3BA8U* z_cljeG=+hs+Cf{M-XXoia~{?3w(g(rEbzJ15!_K1zbR9-Of9g0O4R-A_`kHGt)d@h z+#n9Aud`$r8Ea}#{_^yXwYBX&%n)dtv({U-D=X%D-`{Pb7tSxP|H47n zjx-{YZ}C>z^|R%4%%U)wnWA=&C$Arc#3Mr1N>TjPK&5qFb7O4^xBK;w+Q?1!Lf1&t!IL(Mj3n(;1#;uPr=r z7HuQ|Cb=YcV%KIFyDmXZXdH|G4sY|z{Asx-Q3U?yOIV1F1Z=S5pXZ3zWN1?&q2}oh zCrKQBnzvD9hX>L=fH5rTkCfT$P#eJF*lwI7b1xHOd}*wJc&zMqIlG^1ZCA=K7;!(Z z2j_s?Sxc^&sPn<<41ie!iPB7uaWkwzx9yvWM5PsfG(aOE~d|_Vl>^--A$s*=r(7Cgr_ogT&{9}58o0!j*ve#!E~}&AD44o?ua3bI8cBGw?L4S zI*#(p=3F2SYeL^9l%AMg3oh8izZ1`!>z|J|KF&z0AbJdAZSjoaOqL zl8dA07j4{T_jq#-j=HWAIiU26cIYWR@5667-&76}Nu9lVWSZnaB-B5QjV&f>0^eH~ z=Fi?WmzzFrgTdGKgo#uIs3aHF$oFOz}gLXOz&lY@Dn!zQHyDx)%199P95y_MST? zGY}I`)8(O;cqWIw>p<+erqV}7Rn=Ov_XTeWcs?N)d*rOKDACKM6zrewM)q&EgJt{z z{da;Y>flGqCUQR4{u~IYZ!RVnkBrgwOG*IW+;cV0uHlko+#k7A+kb!*0GHD}PNGTP zVO4o`)0nB+_d9eT-Q|rmsxs~BblX}=#+4k^X4FYU8M3ew*AFvTrNDcE*2Le zXbCaLS%Yh8IbmDkNX=E+Uw^s4<=>9|t3jeyz2zC5uMtDe9wrfn*U~wREq^h7MZ7Sn z$x^9sjJj`!jKl007k8NFIDmW#s;NtV{!luAB0HpJ$LH@Tv{`W!t&q4k_2KoOS`yi>0sIxYcJx^e6 zhA-3v?Hfp~Cqy#Q+qh*CmT!Hraq_KiES=a2xvrZ7AYHRGplt2UJ-)v#Zr!hlezwDW zj<)02afz2(4{YJR1e!&geo~X!;C=(*mt!rStw0iYVwbpCd1ahTj=B|klO$`_t727i+B`BD#7maDL7 z{VAgo^St{liTc7a+zTgrkP?dN)xzqjX+V4O*DGxe`-wL~p(uIC}n1Dr%0D=QdD>Z6>?g zzZKodA}m~z=Dd=CAQAVBp~G$RaIVjJCO!*1*BN2|^zPJ?V0w*)*VwOVylq>kg~LAU zAAK+YiWr9lf?|VArAJ|Oqllbg>cZHe@Cp>&SO#%dVi=45U#mE)fv>Q{MX&DH?Af!Q`s{Cg_V+&fN1y#O zvqVUsqh5~!vDwv$~bZ(5=P`kNVl2n^|iL^#g-d&O2=nXlZg|hY9mUO z%u=K-SU|;*f(sWiUGWnn8}nrLjfZU}>tK(?bEw%~n+DK9=w3RkYKf2RBDLtRJPz6} zM@f>}5-$~f!AHe+i32YnqJHFfPP1r*7|(*{olhj^Mp$Mva%tLRh8@{_)?v3}KC~U8 zedTNo`)21E>LPc}pIzzk0q*9r)L(s{-(FyRJ^lQ4hN>zKKK9+I zlR67@42LoGDoc@o@^TiOrAOX04^1R0<##96&GOC}AdrL30BPvL;E14&#`7FHiGWL@ zhzZu2fNcI?4ea$5Y>x#jLM-qSZ~MO&{w&a49%=hcN0A9$p^w%mimZC#u*(N@*K}zm z{Ltb4j7(sBZV3Al8mQ1>x785lIA;bU z%5w7%mX}*&6@-@+SXI2#pJNa#hv&8L~BTLc0NklqFDDV)>s?|%3(#%Ss59^nX zPhro@beNb@F+;|miW$O=LE3KqmW6ngGOTB|ZqUPVy^%>xX0LG0t<+W?%<`H^jNqKQ z4o;8-&P)vuA3lO<&*2S6OPrcrlNjMUR^|@mw~K#8#HBTAsJF$PmtjPOJ9)+f8(Yra zU(s6!0_R9ROtgy9HGmENUv@$H4i zYyD&e>bmeaMjT)p85WI{`%jeJ{Ba2NCMMoQ!9|jYTMr2ZF5%h_2l8QkkvH{zeW4Ah zZL{>{<62wfEuJ(jmRgK(Fe=`(L_`Pzb;~C(L@puM!CNVY^ z_-m4<&b^`q7dwII&+@!^``t`~T^}ThJopS+B0NpAA+*<0S1qux(@98s1|7wl$2M)T z@yVBvF8+MoA`z9JK*$X_9W(KXIofGFk;#^ZX(3cHrxn*|&154y7g1RK?)vUXYxuzz zTTVu34Nqz^zr^VdJ2Tw8vpYWgT2@uRmfHhx&NX6S+#nN6GUwmRjKpcMQA%G#-pwQlXG4xO5zB1LgRti}#25Lv=<^ zCWq{sLHB*gwcFcXoGatz>=upl&+}&piM^8N7MFzbHM52+#vLt_CP0<$E(Xv3S;`60 z(F#N}ZGo&h`sl4fTT!wbe{-Pd>*584rIY~lb%&yi4S__qABGkc?-g82qY$e-el!GH zzbmNf<9LYbKj@A--}O84u+8M462sPQVpwK~;hjet-3;K+P<%A|SR5LbbhZHd-(bnQ zI2q&XPDaI_e!zQ zC1OJ8?`G5X6=y4u>}#(r(JY@10f{MDR%z9T|85nO*b4Xuw)JjCf052|MF|YWglM>3 zM)=TGsrPc&X0mKPJbz&mE zyao9j{w)U3;Kt;}sS)$g)r_K7^7~p|)GZ&%t(nU)cWi?%+5AqT3+6d!3ic<1eB!~s zPP{y4-mQWX`z-=p?Po$vb6MVg$H{{qd(JTs9~;lyLr~U6hqNtvc{&{e5|gFtf;9TV zNUEf>+?+ZnZsLt}x$bKP{^+imJ~@T`YG-}D&#LP`0M=Mo1O&DHIk zS~>NAmGw7G%!p*^1@+~<<@h(46HRI|D~%i!({)%Em+ohXF_fe6vG;9F$nuUri z$ZBF+LflZ6nS=-ljv*@5NWbQ@-42AxIwYV^i@ZcS6@T+6&moB32Tm>{B1r}#vl-*A|tjKDL@*hO}#EZHti&Ir%1cQ6*} zX}!tzk*Vs-({`kEXYJ51&X!Qeq+nb#D%)mLnhvkr(3Z4HPS+h}>eQUoC08cb!6D2} zVktZs^_oB!0&c!3k~Ta?hC zY^-7=(|P?zIQE;H_iJF;<#8>`GfH3l^LlXB^6=hRG)-{(cQC@oRh!zlIO> zx~xmsHD%i0w|!Q$zpq^{+3Fh48S$I6Rea|~L082h7-eIy7Ru^k+7pcLZ^(idmgv=d z^DkM6;tPAa<;Lgwr3-@toh(giR>VvL)fBXWc@<4x(EZWISpI}p2YGhDqT2$zNK0q& zo!|`jSariD+tlG*J7;u)K6U91Kss9 zevVPo48>j#@9??S@hgz&R7r;SRY<&j=}X}>rUrc6mEfewr>w#qbNXsP3W6U&=uqTQ zjLFzEcrXZ`VwyaLf^ZduWx}>73^-wgh$Dm$I=R5TIqHKl zFGQ!B^ZlN32R);oMnoneWup;;oem`V6el_ba`j!J$ongg(JGu<9MOHQS=su|YWC^= zzj1veu?=Pp1TFsS^I@Aw*7V-;`vYepDjK*JL9+NTX#hM^r2E}~h;DN68PJD{l_2Ur z+!c=g+Pu`x3oq@Cjt#2-7k)1jS?|yQcnDZF(vuJC zfLX(PGWykfa#A*aJ};&I;@L|rnRUn3aJll2`)p!)8+KfJ8{NsdX_d5Q_e&~kjtr6< zv7;`RI1sqZW03VtI?H{Gg%I*FmTY4AD2!ohZM3w+tGh23SLtlrJi=kJ2Xoyw$1Xqb zEzuyerPD?;?&9$hrC|AShql^*K6}DvJJk2=^I@CGs(Hbi--W#3-3ded9B)5E^4`v8 z$LYZuyHqLKM)AHL@Wv|Dy{#SpN?)^MpAoeQk$-Gw2VVg;eaRPmP z9QWD8DgofwQH5L3sFRd?brAJoJJf46(FaXB+Z}U=KxQRzaolGM)`FNb9BUzP+P0B;(>>^wUN?$jf*&Vln>Vd_{uBu z0o41&UUlmWRfD3@ZUvZO2u`Zg5XBR)F0KCEC<7uJt}O8>{`+uSVq4zc`rxH@jJ%$ zIn7(~R#qz#BRQow@<&Ll<1No=8E-5V{`T9q^ZzebK}JDdlFDZjfVlN$qTE7OY3BhWbI&P;M6#-6ccCdKuo zVQxhly0OIIfuTr&@4l}KvIgGnF*J3Qj50&;x3iTGxfdio&zoIGzf*r-taUN;W zQdqG?ZAjN#186B(C;>X%K~~IMxZ&MfJ6(Bb$KRZ>&aaBCz|OBqcdWT&vvuH|S0;-T z72NQg`5|rmT444!v6awWGOp*@($Ky{`lEJR3~HVS54@pq7A{2~lx_6op%6Eum?;(w53rVK}OldiyH*+;BO z8VNfaQaLbK{{$Q@JfWK#)Qw@Lij2sKOw@?XX78kk%x38R^lreHM?nt3)AZH_%JDaQ-?qFzCC%fgkg>d}l1K6*=jb-s)S2X_1jnt&+)BMoW0}&{o`-pb&&uYId}giNr(Z zeg7a;4mZTqlF-qBRUZVNiw9oGQPh^da_R#=#zlduOnjF>c}7apRD}qiD}(&)gs4_2ocuaSO)WERxT%b(@j%% zwcm-zRQ7|x3h+cWsDOIGW*plVy2eu0E(F{UvZG2iE9_yDYIXzjp!W`k0ChMr!a$xc zl{1G6TND5q+6LH(T?0^- z`%U{I>wCyEegwWqy4`+4&PWU9Qxc3&yL~q--PhMAG zpPmJ6$C`qKw;eDQ2|jDa=~J?<#HS`ph)^#=-F(k2uI`H432tg02OO!XJIF#i9RjkE zJxE)|5pGvG6ME08Mi}{~#?k{Ud1{OJ?0BKbd3UF1f=Ulp2u=bwIO*72PI!-w;DL^v9^R#0v`WF1z5$dQ*Mr>}DOeEc%i zZJk7EA)_?bBuYDAnHA?Z!|=Rv|B$*pAvX_=EgzXg9;M*WUX=)TaHER=$kyk?6n%Ll zK*`0Ad}JUq?cV49UCy?-$Id6Y<2_UwZTi1w`#ekHpuaD*0HvYefP`EW9|v zw2-x5aRtmKaZpO2_N!rikiusxkZg~54&p9LN8z20i0S=#kTCTrvv-&z?2Bl@_xQ-1?KvXWmqft?jFpP^F!- zt{_KQf9$r+O#i+4hFU#`r17rrATbz0?I3}wmIJSIF)XEO{XN$d<_FXvt|Ix6|4;dd zAx4}3ac7Ceh*pOSFu$e#bWIHvf>T%BYFU0soyrv)|B%%oM(>H=ukVBokjN6_OJZ81 znLTOu*N&%yX0AAS^c*y}3B$La*`Z8ZeO449C2*VJi04K&!n510C88-;Y{S9e!+aOs zuz9A8^KN9i-nc2UxBpR>%dThx9V=7Oo77~MPV_ZFI;TM24dvzLZ-%f!2yld7P(DbI zeKuU*7UrLSGz1#$GwGqCcm^#Rt7to3K1}h}v7U2Jk0|T12(TCONKw00rum4V^ zX;k7QnNE}Q)s;Nz3d)d7X;+U11s%opqMi@pO#eM~2O7Tw!T*jgmY1_V z3|=U+hv{o9x)#$jx6la!(lo!}1!<*@d)RTG%^pTYWm+2_TlCPVwqqbBruPAI|2&GO zeEQxjzdypb!F#!;#?B9H3`;sYigNqfDDNgD%54usdAA?-y-j|FY%#EssbD>)b|l{) z2AOt_#D|2RblKh>?%;jOy^FNzeHI4P)oPeF_7yZ&u^;gSZ z+svokQgVmZ=Hq;nc^rZ~T+|%lQGV@mpHBD|GwFw9zSbilrtWwMcSV<<*MqYb@jTIy zK)6++v!R%3=I8d?qL^AUSqIj%8>qA2YBEdFd9_mgtZ4F=be3Z%Ww1E*yIkT-@+g4R zSC};xYw=oAL5Xe7W6k9P`wBkR%M-63aq6WPi@FJ6?CwRthugAPTw#UW-J_j%F($6D zrjrg%V@=nps#e9ax$Yp|$F>BD zygqobe%ou(c7E@-0Bf{EQJa$%#hdJKBplg!et{&5J$U394l2A36xZOd7HrwK2u!4F z^fC7qd=Y|8*~_Xv)m)HUUBRR`l2a4#7I>BLx(L~sJ4GDqBIE%uCm2ctTFeV;J0I6V zvrdS~;i8C9P4$MK5)m^6(VS%!96E`4YGj%?ETbm>@GROPE>4CGl$K!n&gWac=5aiP3zR#NsY+%;drpbe<9n0} z%(e)Rx?EN&IJSTaPPg*09B@TwUqQ!xHd}g2l&R-Z4NI@$0+Q#WCb)?IHq(|eQ;aZN6z+Rf$5CFds;_0DpBQ*5laE#v-G zp+hO?eXZ`;eH4e+wo^iAHND{MR17dg`WFv~c1V7nD^%X5G!<0V<#mDWwL|39O_!Cz}Q$^DVM@w$tI$~DYu41rr zcpi1R><-mIlmI&V)tn*00z*$PGz3_%IXeGzPKW6m+Shzh_ z-3TZG*x)59mBy%;LFVd%U0e#XS*-jkLIVHc5_|{_=up(i(bj;sdB2d#MNG**D~fBB zufh4hj^kE{?vZp|Q~#$!`%#A<91HE*H9h^}g+Cn0&t9&BZC&*!{!!N_xjs-Sl5c=? z>pFy|U)NK|m(r)=Ov;5YA!n$$A(cI&?%d|gPY6V9I*mP(^J}XVY7gITG2?F@F0N5x z!bV>{2})cLHTMQNEezn-Se{%@iA?-}I<{Gh3~0^c&;p1ppL_S`_2BGylxph|L*Eq_ zNtR2TZDXghqo0x7Cca)NBI}Biqy%IwaXO7a%>slCJs>gh?cfDIhAx*lZ+t0_V@1cb z?WNH%Vw5W=iz~deEzUEOb$|AIvJg2raX|&pCf<=tt>ZqMjc{iQD>^3n32KbyoiBUa zko6ls>eu~DlqTPX7l^(1TMAx7Z7ipl0Q0Zp8w42fbPUnM;4Wsn77iCJgn(~*battB zKERo|KtONl9Nw$T`^7bCA#=pCn3)i}SIH%=*-@XI_zDhJadvp4ph>x6IZU66OLRP% zL#rYV{&g=7K8|H4oKA;;?6`HG9k}ld*Zpk=s9>8ajB}B4V(ksyflkV^+#iftdmkP3 z9gUpY2&~uVV`qmWv?z<>3yW-ugY1>_Qjy^SQ_&qRyZnml1vCKlLCY z`kF7*s6Wzbpo08S&hW(H=P6r1UEwxV+6G!0&x&(V7QRy~x$rxR1woK+4!#TVTS@0P zZXp4T<7HBlS-PQxBW=1cak%2GDK!tx(x^JQBzIJEWol3Z$PETl1V+palOiuca6Ck} z>g6FFtMc94W6PPjyB=<0{McDmK$+;?kBuAE#KC=)qB?nK{j zEtWf2{S8J)0hm9N*~J&!vl)#M`=B*r(;jNAnv~BD-g4Ic#Y14Xb0+iWzc<61%%A@b z$2=lqk(@r>!v~k*-H6fP$UuC=+12;T8M6Z(8nPZl7Ykapuq3VX#@fCgOvTf->vGu%N*2l9^wBhq1o|JM!3@*oTD8|O zZF~jT(?AQe;wC6Z(2UE9yseLe3Vjd9dZKH?_dDW!1)E`%5o)nqhGj;jMcIczz0SDt zY*1JYv+5|iH&p}n`^0zJQE8{;lAl!QH+fddS*h?oPEBp4ZM$MS|0`RmL+KXAVd<2g zCUK3&VRIU@QoCwb?`f%$f(Wqj{a9tpp-XedMc64>W{86z-j14cf-N<mu8;v-PTQv2`K+JF3%kxz^W5G}3Y^gwL)7L=wsdgCkzbQJ z?rj74S~zIZeYua`%lj{Z;fh_S?JPn-lcZ;EeNSW~qpHC`@llscoCexll^-i^1I;@7 zw?uL4^zlXk@y!ftMz%$^t6j*|Y-IIYbIZo zU6keCkY!hsEiFJTVd9IuACB|5u4uqHT1`tME6Ij1J_0Xu*$%W-ENUoFL{yOx?lWb$ z8Na+YCE(ZQm~GR2yTLlx@MDOdCKK7Dd3?jQ1Z*CO8!VM&+fNt8vH7m0>p3J@$Nj@W z6E`kvO=|qO1R)NTx41YW_9Istb7>c!gN2`w<(5qRT?du(!%UCPn@4`M+v4d=Y4O^7 zWUpz@?hp?{)Eqq7^QggubKm6>XWO7mKDw&d083P7=`0UPp5{FydHxdwVdphi51Gh% z=2gg<;a1dMM`mPIrIT631%7SwJ~+Q^d~p5E<0I;BodC7AUK=(5+t~WP=4|mE+lvP` z?V!Y^F;1M+WR}K~#h40)-Zc_zwHUd?i54F4-W4qJr?S9Ot%h;kWsjR!_tr<7ZR^jOokeD!cH3G++-yZkb z#6mz?u=F#W4DyNB_G^P}`|U>G_RGNAew*)T`;|ne?bnRqlGJI&qb=0qRY7mgR6XO* znwtF~A9HRqlN;uJgPpMa_I9kIK-)1G^_siM+tBbMMtJ)r5voQXQA+Fhk!b06@PUSp z>VDKQuQ|Aw*UaWvqZbV;dTB=(^aS3DpOT)ibk=@@M|@Y5dD3|;p9mU zevSKH^4Z2Fo{uiB5%@jx7>bnbGvhO}1T0L9;xGz&iWKQD57#Y^DAiPCm+bu$LOQr$ z=ZxuOkk9UrEL1$r_vsLjn3E-*Wy~ok`iuxtKb`-2H~{^@P4o$?+uPHT7#v# zyuoTIaPz?1(Ay`qv5u*OO>y@5@?=huyi#TE9H6lwaV3wX;u_#|4GaolZt5LFWGk@a z;QhL4@#x&b$qr0@{WK#p^eg^Ax?Ije5sD>R5sD?CV1}z50&lN^u0DOBvqScoZ5m; zu^so>9NegY^?gOdu%k38j&8(?)83EUr5(A~2tCE-^}UlYo%V-qCPz|QK&Vn$kbotA zqSAu8-Om<$3>?2_E0C;MdTYm9X2;3WGCQ8ls^!b=swrRIT|5;>Pr8cJKJd!7vA)Z< zkxS?{Q|TmMtV}DITMgMdU%YVSY4K9qToWtp_SvR^ zv_U-TLrb4-SQ$gy%S3+RK^iJH>uI;Z{0t)>nx54z2H<r4Z* zYnj8NVEH{QG|oCf?S6OdANK12V(qc_3m9#q2vTPCqx zRO-hkl)NFu*k0>pg*lXrm^$KiA_@ajh|{i*v7q*)&Ku=7rOe|i-a8ZZ4^YepDFmpFO*8` z#M7_RL|DQXM1c?8BHp)-`?r;X*e8jAwLq;ImCjn2Q_xZJ_tla?dpQ3ngS&pIdanO! z;Dx+ODk=xFBkjw~Aah0)GjoXdbt+w8<%B9_Ce4$?TXe7Hi;KIR_-nuqYx|4O=!8@{ z>^mV9Zus$lGB{c8}_`wx@E`X61hgqVVlXXKy%-{OZ$owbMM_MD6x??wb(fF z9|95+_5So)En>3Et>8FGl{g(qRgPjKhZ3bFhl)e(AafF@Cv$KzB9nEyg7F_x(m59N zxdpqcq7$MR3DTQjO#+C`#h_+$<)R3OcHv+dA~KaWNO&niWZLAisbbu4B~PsKMp?Fv z-%u9b1_vI`P4ot3bzP6`CM)V~cy%cO9d+(+d0uiK$qgRyIYv28y*85r*$%hMy8qHG zbAFFtyRH8*DI)3K{fZVBferD@*JQHAX8d}}H}0g(Azf^PCWudTcV-8TeRmEZaGPiq zHxDle8D%5DYaNd*|EQIQMLC|ZF!G%N<%o>Z)5k^@@Va|;o28;&BDkxhY zHWEW0)+k?u_n=iS#Ldlzb-?Unm2VNvt=4M#`PWL5O<^|uw;v<;oYx-t3b5cp9ll!*iz77xZO z=Q+N`OEODgutJkbZx;e^zs(qHzK4hpmwN19rm4qX#Y>@&{K)B%QGRs}T)(!eO^!Y7)UcOwLw=n(HO>qz~rSo&;CCtlxhmS*x78kZs z%}*QE$d1Cs(+k@;TR5xDW8omeZ>15coYqZxm^R*?Jf|#u{%lQSKw1H|gvKr8<;mmy zNO^H$2J2=UnCJJqRZxE8#?{sH7k#w(&E;-2-FgdupzwWcDbW>*E)dDADBqfZj4(N9 z(pkRaFsC>U+e~7}3{_`Td?rHG9$<9WDk!U;_C=8WvA-iU>HX}9-Lkm4c<-S~J&$*t z1?G%<})Hu*wnguj;V-dXQ6wYcCM+5oq0`dC^p}~&1BDv zGrrIC8#?mWM5@6~1oNi{*q9#wV#%TUuz8KD`(jBTAoCiTgoNEI{%#rLgb3C;rfNpP z)vR$%nyh}Poq`P4aa1y*qIXNqPlj64e%y+zl~9rWm#ukcj_sGmk_k3~#>Z?-_E_9t zM_n#|GO?LZp*1V3hbhh^6`WIhb@BbM%_RP~xP2t{+tuB1pG_>tOB_F(UvN&~OBR>u z59e6T@DVa1;21qyfn-g;_^xmvU+a3s|?^Nmkxvvn4{^eEifB*O5?Dpe&wAkgQa$b8jEjuQ)9jI&G z<(K~Je=E#B2UF!OtnU#A)7R5Mj|MB>Iq0!3{6UY7)c4rI5ZpgL$zhal_P5t_0ukKL zHg8_A1{LAJ#)TAviz(Xl`l!ogr^m@{t)ZCt)aReqgR>SMBH&twdLV}=CPVjAUYPb^ zKWsBuBQcipBb^wQNeo;sUwwYSW0~n+`n$JDCt8%-F^Yw(bTvChbe8K}&2qa8VtFe@>s`@e4EYwcJ3mNK-SQ znC!y`X!^Jeb{d40f824;naj=j^LlU&4b?CCCYJfG->kZGpWVWDGn`v9)g_hnCQZni zILzOzf)YD@N!ZFtUlQFi>-b+PO%pVQ}3Sr#nQlEIRO}rB)Y*k4R=&%1)yDU z)aA0(!*sd>@%VC$F}OZ?3~?l7Xt9bI3QUDITdEH1LageCb-=8#g_b3KKu+MTo2LtH z%j@*HvjFXt*=Mt&+*t>f(d8$DeB$kxXeQozhixV?TzF$I-Qq#`y&?9n#NW1nUH&FH zXwq4Z8X5Xjd=Q3FHJPQlOwZxd!oYza#Pi&o0HJ7>P^dPHiQ!!la;8CUqTDpd9Jw=| z4jMPFINIWebp_>@Y=lcbF|9j;xJ<@G^bpj=16yiEwgxY5dD#MQPY0NGSE&#;1cw93r5 zs`8r$mYU6~5lMg%?>l~@oA6IN5@avRUi%!=3)iQ;Qx15_z}JtT%;CX)NoARNq7`jyo@kZmO1MCu+(#{mrsV0nj+@>P@z+20 zS{c9mew+>g*~D&Bpx@|ZkWai;kHGKCR*#@34@PO^b9q6epQ0pWxomHDHvJ0qsJqi< zZLj9NF6ZTyB(GxF zOnT}uA96Xk!yPEMe_~iIUmH_?(^>OW83r;+4ze>FIKUq!HJM-an$uGtDBH` zOk7G5yqCCjPA`}yP_SJJB6PzQxPabovG^66?>cvqPA}Witq7q>g@G56)iStt<8+Z0oiOGVh>CXVnbp z6_h1wBTtCL2zNldE+4*^SVIsBka;)=t<-?|1ag`}K7lNiZM>4^;Ew)D$ez<65-}5m z04`f-v^YS1rtX^)^gd=rSBE3pVimjx|L4{b(UA9cB`6&|fbc!Wo*R;IAOxcDE0LDzGRWW7Oe zrvVACO@d%wgz#W`{@b7b-irr!IWta&fb15Z7m$bq@62ym>YdN4dtnlPMa2oC^dKk` zmNTT%BjFvNr$K!z1+!cA`VC%eUS1w?`=vkG>Q1n`jIe)$>rQxZ+j?pm!(zF_r>mZq zMeT`A0~I8HZ_d_kqe8^l(92R`H>$(P_0d=7O~|+U#A{YLJEbKa^wki+#R8%^*A-- zV6LM;ZJSMX{xU-tDJ#P34WiTX44BSB7+`!0oAi!v5dp$Gim>_goWH|%3K9qp(S8ih zpakvOtH)z7tIfS8Z*%DZiX6cwbkm5OC3n;=q9%C4qA*RY`Jo87&V4d$7GuXbRpqq3 z{di7QHGmw`*g7cd-<@8TY+~(3q@_GhP6qkJLknhUI)!?|9JZOn*iWFT1q$tK1(LXv zlpNF#e76cp8PwK{h&%ksO!#(&g(Lj|Qsr|KdRn)NA}ZO0zyCp@ew~j$DDxlYXjp3P z9S)&t2tueIfwwR=no^H<`#rb)w6jHsb98t)X^#*m4ngc!-Vpj$Uwn3Hpti5Q*j*r4 znL1&(Yxjn!R~W*{AYW#^!t>{D^e+;W*j4#Qi>507_!9D))B+JgDI)z~z&t|js;oci z*$O0E?{T%ydtBT3F+aH`ySry`1G(+@rBzno6;MnNYbg1zf z&lnJi)IHJraaQ?Ws+vL^u(ct$ouKHfp0SlNs5b3Elg@8RJzl0cKZ|6RW^Fy$vUdA? z%Mth`lp`2OU|jt<=%S-8m;HoG8M~q#p}nHF(>XA7=0TIr+T(-;UDsz5YiFqwJ${tK zWRJ?!hP`d?w-4)pS%aMt5j{*QX+O~Z0ES--X zxMbeyqTx3{#E+a#%12vv>f1i|7qLczHsG;_>_^wq;$ix~{M*EPa5rMMowRZNzE#MO7U7ApJ`E*s*& zEMd=gZWz%jBnbFJ_PU{X>tb^4Wg<)VdFJCUs(DGCu0Y~?L9NM9^I>^B$OjrR%pN{7 zg|I0VN4VO`v9;{fM^M>1aGm;S0NJ+lYNEi- zS?ATXki-@LN4$p=cZmPf<`Zx0_WL72j`450bTQr)JQCZ2Of(T02(2fFBc94iaz^s( z(S2-tYQ1Hm;6OWGn|sLplFBmT0Y8aC4OZyU1E-L7(^FC>8bEUc&-8OQH?ZZiu?COF z(XapR^PdL!-v;^L2l+n+`9BBw{}|-|bCCb9e~(?hpWNKzKAWT7bTEeoG@gDK9UrmI zFlu!jkeHv1CxW}%Z(_8yjrhyV;e2kV;d;3_q&EPaN@=^6q|iYd^$00ni41d2xGDW%eHqGQYeANCNJ^0;i#E7 zGYIRz;!+p;C6$#=a4_jAVZD%Zx4amghj~=<%@l77Di@WoR`7NF01L+B5XQDAuJZ~k zdp1F<$ZQLNE+J}W5(5XzykqrK@0V1T9SKs$6#Wr&7C-tD@DV0AQdwhU?+4v{db=HU zxx_gzXv{>kx!-(mwp|w)Cjcw=?K8uHC;B#?#BaaMAE3(SyYV;MkMIXgix@9x%~AY9tqcNtX3|f6IEzHDXT6_Q0dZ`=g)W5uancBmE8Tu zkBf4QCqtAVXMgztJnJDyhWl+lt?TQF+(Y=u-8>w{$F{0XH(0kYq@NHoY@D26@e19perFuwGQEWk@pX=H;17Coj*;Cmt%e_P}tG69!2ZNd+b;hcmeAd#EW!g&`fs*4K;6x17`S>*=@M_?us_ zXCVfn1KoF6g~JRs{@eMlZRS&(`K`_T-e&&TYuG@xT3dkq65|F#L`RdgOQXsA+{5S< z0Vqa+s+ELof&LVOXu|LgizMrxQA^fF`@+< zSG3UW(JilJ{JWaW+EJ>7vg@V3W?0u2ivxK+MMiIAl}U@|%RENuJkuDZXR=a^(l>%P zVCiAGjKkwA@J)=ic%1oB-yO_*eM@I~e21QIF+O|AMeS0`HjB#qFj;rxpnR}*xx|St zjIEd`I0-2)?C3*w!_kM5S-+HGpW(G71Rj=(V;`j?vs5vvO$kXG9ht_{cqw0jDEs68 z4-WfVxg4J^U;~GIFV`1q@%h`EBSt`(0a?XSbnO2uBkvyir&vj##7QJy89?oy)oQ-x=`-R2F_|dx)8&DW!SbRy1v^?*^`z#il! z_Pe5v23eI%spCGI?Tv_M!(uSgRj!vNH^XU+gkZ_B-O$Td4ew0FREgW~u+3zn5jovY zUB7I*Q`bm&m&1#2w^Y`Bb93=>MRa!mlUtx8yJ72GPCM0cgJ^6>T+;E3W*7nCXB5*D z#KboU`WbEzKo3ANG=Y_ubx@X{!|+E&Qy{Q9rVCW!9;JK}o@>PaaG6O+bVywBO|d9h_Mmp zdT0ldL#m8X|H%?we*h7Y3B|5En#2Mif&ZvLvvFz|!HH6ParM50*OBw4LD4sUtcu<{ zIZRea00oexBQNh&jeKN?e!_#P5yms!}p6x^0p1a@9Z5Vuvepa0| zefOu=n~SefIUf6;9Mhh^8O#%qHC?n9{Uk{_y5+JGk4F&!&JhSJJ5!yOf>pmNit>p# zZilIfqD(fnl|Xn5HJPQQO1otVJ&PKQAaD2=tJGJYXYlk?T`{$ajpY<;C%+d`@Qg6c5o zZu-E*doW>*PnF+i;OhQ+gY^A(Z8t3!nrP9C>|B%zT)BMx|`>+m}HI9abwj4gL zg=U?VV4=R`R)U50D^W(8NJ?Bjv}HHpcQIMqRw7SvIzHw4zRe3t_e=Jxd%YIu)6P~P ziHmcY2G>67-6|-t54s{B_xm-l#NWKTe!Pe8x_Ewb@q!zti@mfJ&vWy12*|3$Otp)c z+L$l1P@m6MAc;F^OI(=$ZWWZ+UCXv}yOz7XT>N`!6ygha%~odLUJKVLhyRE={Pvpb zdbj!RdN)Xpw0Im-@9_wK-!@zx=J611%UBTIXqyGnwHrr$H!iyfx^Z>Pk?w1CQFUJ{ zKz_jh6J7Imi0!f7jVV|s-M0oTTkd{yUy0ps-fyaI9J+zKakO;c0CWB{z^qJ`9uxjb zkJ&I>y0Q8x-i3S_oQt1OC~X7{V$*{z4*><2WF*Ce;_OA zlFLfn6&Q_Tgi=!3A+D~~p`(i}Imjno^kEw^`sg<2rq^RzNu!Y#wVLJLAd=Zm%uF75 z2_89SG6}m};t-Tbt>wxuXTPtCm|I`yF-`rdf9LPCkWHX~iB(Pf)W@hj+x;#|0irL! zd)Aw186RcBIKW3;u8g5V{X@|m zc#v1Usw0240x6YCNq$i%g_hs@bO^|*t_M*hNB&B)HUD>exUMV7x`!+z+&vO5OC(iv zy<>gGO&*a4{93oKKWmFSj`*6AnEAi2)+xVfL?!EI({6W81i;f zSMUl8Q6))ml;gIGeQNqyRnB-c1jf;k?>ReOZ{!!)-WtnI5q0PANT#nZWz4c=|Dr;6 z^?A#ffrO*HAOy)h7KN5%jo!mFT@vcN!XD-E1Fp}HjLNK&81}znghRu#ZbNTdlvG!3 z(x!z7ACCOz_28Tx*%)>)<3`tW!th97rJ&O;pB=X8^4TFYn;bdqEG@h9``J;KOPp~7 z<%5s=Y+~)DLP$#0MzTtR6aIKE`sAp~WhJv*G8~(#W8EOASq2 z5D((5dG^6g$GcTfjs}XP@uqs-EU8hdci0bf)a9}^2E?ucvV_4<^nH~{jFZGLErzz%GCw>|K;9~ETHfy#^)U9SY=3oe#%uLPrc?3G~JneB1)l|63z-Dq~!7w3+Z z#Hn)FX3C&Zlp(A{_v@w`qV5jB`kyCn^E2t>`LGU{P4nm<)bLy7mmk2h9zFyH^-ReW zMt10&ib8^S+~l$<-j-1Kfw^%nLHtpdOPm`0Gk%E!=ahAvrBjDl*nzH~6^XkP^JjCT zq#F(Kjx@K}PR-*REt(mj>Ddud+43WN@;rY*QRI%PowyWrA(&vn48(Y0hX;`dys)Kd?u z^_JfsvB;Zr^$gUZ=4HsBe`!%0cnW+j$Ym_18R0UNN#r;xbEY8Ql{6)J7^B;n~cwB!o+kCA`KA7ro!Y`W=1#5DINnVn9FS`Q8)32{3zEM&;j)J z8MhcOPkXppQrLSe+8*bZFvunqAU=jzdxsUou_M_g8q_QyASSl6No4kAS>x}kjXP+p<@v9le!6?P#1gW& zS~`i~>&Y%i7hs(33mq5TWqusMM2D#XF1lO1$M{uo?y9MfR$df@n z@lZxu;(rqsrLiN>T#Br(!CGu2cg@=PkkSRV22$&Kmv5dRf2Pk{FH1bu8`sdB6=Fol z!RUJL&nSct92#NamJ-f5v4At8)lJPnI?$2UJR;F}w+bp>bI+v&0T}ngri*N8y4Y3d z`fKT`@~f-BJ}TSls2Dcvj2vo{B|>Lu4_7t*h{l`EC`I?Tq2= zvjZ}Frt|KB?N;>nvt(zgLzxY(o%i;B_GJz;oU7IT##+8d<2QwqK|5JfzX|k+kFWiKjtj60a9k>yon+#)eqY83birV0rYbZts=qQ zRNg=m7Yk*T;O+~>gL6~y-zjVX=#FEQgP&S80VksO?Gk}xF30263rflyjvTI&n#^uS p0rCgIQI|`clYkC?qur#;<$xM>@8W(e@@D!t86e?S>i^@v{|B&!fM>nbmn}br=nuOoO6zdIe`(wnd7oXjBsX5 zm@q4tGZ;=iWoO^NXIR3&^D|2zz8-$gwNl3@@^;@;6{c7^#D8gns5#lkwS*xIs#L3B<384TI-K}4j zfpkPWZ$iAh9lNHD+Oy2rqt{YHF=-bP5pHF)Q6&n`m-5BgDN*-vQmaOdMf8g!c0Yaq#ZfW#m9@b-^Cb$KiQ>|1SNy zKV9!Jldw{_76S$j7&6q{kHml;1HV6TaQA`hdVD=gNYEd6=QqN6#r$34Ck$-R+4<+c zNij5o--%q8N*rIOEkAzsGF`V1wi|*=d%}1ret1vYR|e1QfBWhsH?$8{YEthhN2xF` z!EqibLRu3k|9)XK2jYkZ*Mc~m&c_`hEtf)3rH_h*%cKWy#?llaS%jIJ6MY91>Urh$ zn>DLXY7$~LX^2cn5AAY>8+0|lCsvaTxX=?pn2mnt|L8Z=4`9w@4Vy>e#5ZJwIG*&E z?vhyXAJUz6Cq3C=GL4-f0m5KXLYzsO(uJfX3n!(S7nv_KCa!pX2w*FqBcKx?9IzZP z70?7Q5D-Ii$#j}b%8D+effz%Uij~N8;WTNa4I;gzDyaJ#*&>CL5mF7ZMVt-ji|Zj| zw6uq8VHL@Ku{Q~qM3grrTQqsNhjM8m87?^~xF2ZWEFL4x#Z#oR6ijAIo}`4f82JV7 zR2450XEB|$WjbWq-#O**r^xYh%&BKBe|i4(GjuSOu{h0mm{ zaF!GSZii=T(hp=8u$wf9Ou_jqF&ezyNIIZDv0^B3rmx5%@i}P^`nqd=BOQcAWRZ|Y zdWikW1WiMfZzXe?iA)yjkuEHU)CN>%lgSt{jw}~mkY8C5vIt{36y>9ZKLM$v2gb9F zCY&_aR3!sIOC9ZK^Lw!liQ@bd50Z`IUu2dhjWiVvWW2b5)JI(%#Fb=;c$##UmXnh7 zD_J29!I(B9eyl9KH?V_xIqdl|CfPnrvNNMk-8;w+5411Ta3q>^$CS<+I}S&EFe)GdXO zVPbvIY9d21zC8hhFvdLq>k0Yl1*o90C&|$1m7EUA3%WfM^3;v26Xv5&cW_UF{H-Hi znl8ix<6{&Lkd=}>`4hHgxn?%0BTd10m|-t&p--2{W{krEyUO7AN3uYA3)#3z`hm|? z#d4&qwgL&0{(w9kCJAB!WNH9#Z!!gVrY4Bg5RaJeD|NRg%Ox4S%K`6=paJrN@!KN4 zMjOpwm#ULhTo1&}q!%Do+)t`O-hYxRp`DtLuTSK6&0-P-e#dCqk_f3hsVx3RT8dgS zN}ERNXois*TG&C&S~4Hc4i`(3?$Qq8FX>4=$VP&Oq3!pif}ke@M0Y~$%EGeeW0nFt z?f`oZ4<=5)c`(k`0l2NdtQve42D=TAYC=Y9z+LOg}JZY)jO6ss4q%R-}Hs&YTng}5p`T;wpX+wN8^T{T= z;o$izoR`PAjfWk%O?*T@QcfI7^il)TQECQ$KZAX`NP5{-BkLpzzI&3TngG&Ta|8Uj zM7n8uLl5S`Kg

cagf#ht1+iQUlL-Wlm;;I2pRieTfUHE(Vclq8%yE8k4Eb_DFnhN4u;1#4Z=ZIY>>0lR5{s8^lj*bR27oABPKs2B>?EPTiiGW~0 z(|lM8+zm2cUo1}wiLFV1#slNnlemjx$xtx>x}qn)iVaD;cnI|Wq2Oro5sAn6#S43I z-5U53DNmo1L|!g#C*6c|!2G>X5-hAGg@j$W=5-zdEx^J|^zkCz%ON$So+KK)iiRu< zlLnIjv>UChMFO?WNW3%@?O(vVQ8+IJyWxob*8r`rQPvdxCXED&KCt0saNV2yqGVc$~yY zjbS@WLATw=Lg^P^XR=V7i2LX-Y!he z9yFwo$u!Tr5Bl~KUznQ;s%=;k`G7@9| zlM+jWKyDYo|IP*^k@n&o=+8==BPQYTh%k!$E@qORkRt+rZZCWRA2_ccK}I1crO3iw%+zB7LV-h!B7 zzi^w(L0`jpoP=0)3y(3Or)%ju#5ss{fq&B(dk?&d1{a6>AZb^SGGH2p=~^RuG%>_?XA& z)|khsJT6uG!ei2j=A#O58w=h4uK@eN?T9td=jNlZw{w9{19mHRm+Q@sz-_oSa2s#k z7Pmdt0DENJj^&)&bQ|Eh`P{q&uoaLFS~P$-0e(R72Ybk5=(OS=I9BN6zJY@^johzT zfcpz;;C!)wbswzG6<@{s#DV*;d{Fdewz;gd#~cY+{Y6@Aekz5S-K8GT{Y3K$E3hfF91_c1f8BBL3#jSY-J}Y>{nc{>U+ zY2x!oi=DF2s@NXTq0C({-%w*{^EbOF(!u^W=ro_(BL277F@>j?*KmGlG1uVp17$q; zT-wSGT6D-_*Od4a^D#arv%L4cZt#rrg7Z$n7F%M8>n#}b6h4>Wd{=Dmj~MeCWe$RQ zjWYMZoZ8agf5+zZe=q+Rd;UZJEbm$R_usKOSNz3%@W0*Xyo3K)0sJS%dfJcn)9Sju zINyB2>e|-cTIRq13;$?0=fjR-zHFH{|2J%rt^dGlVZ$NU$~-Wi|6FId{95KP+%HLz z`5Fh@6NC=tJgJKLvlxin2G5Z|p159cJydkHFLBjio`Cq>Hn+17G51E~cNRjYHq5(50@972jV#2 zpK?9tzR`m7edF}+`ebRF$0bf`U1*2%? z@jjn3>?esD#EgnRLA%@+SU`C`U$?&N2>c#z8+tJf(uWTGf2&*O;4nH|3n@K4l=xP_`whel!=el2P7 zupr^1gyN#O}6iJzinfE^yev%E|>wbv>yfgX)0*-Q2U=M@f-$2d&mYtL4<;9nqe5M`;PI^C7{b0yqWAHCkeiSJWX;?%=>XrTp+NSgqky zgZZ3#5ljKWoE-|id~CoUyrKM8*vebwuZ#A4toV;p1WMFm3_3w=d~DRag2HHCKi*+l zjM4WW?;4ky??1c;nlQGE4Lt!49yQL0Huj{+vRcs$=|F&Q1QqbNQN>Un?IG-e=GWnd4+L0oUqC^TC5+ zIRNuI?6jboOM!BYXD#edv8dtyxIU;n_|GFJ%=*WB`JYc&l_)eTbSta`M?nbJLXgEz zCFq5f*eVV4&Y}tohYcMdAJU8Wlz{`wKrHVruS_vD-~&z+4dkN^#^l>H$W4AJuTiN& z5qu~bCjlITrgKZfp#+YwkqSm8P7_Z=O@CZ}Bonc+gG?tDZwev9y@qTjJIFC|id-U3 zNe+>zGj*Y*X&?=zt!QW3la8ko=sdcRuB8T=OU=xSMY1S%n4M;4***3_pwJ?F!CCMZ z;)U75LSe075K@G*!bRbVkSUfHgT%UGGqI~UKpZ7b7gvj0#ANZHcu~9|W{ZDIRMJUq z-qgE>_cZT!-XFaG@oA#B*E{N6^d5R|y`Mf%AFL16SJVHjucIHTpP*l_->ToPPu3sQ zAMurZ-F%Dq`uPU#6AVTw#&$r;sch6w-yu=rz{$#9*Ei;zRKh2G+%! zcvttH=)K1Kz4u4-n&=($I=!3TQ?J*TMz2HkRloQ8PyI&yHuO40f7qti9rAnaV%6&y z^qQjA6ur(vuOS8IPv*z;rui>=-kb*4c?@t6un&OD4K)I`0=Aorn6+j}{vyAkZ#lE% z?s6UKZ@Ou^VLEHtW7=%mWLjrhWr|0Qvf0F+FhRD=_w(dDtlZ_H&OFq`*G%%(0+s<5 z;C>lEX`EyIz=fFGXC+iCu5(C%O0FPBpa(M*?qJ7WXEQAd9)=v>e1Tl=Gng4 zo>)_S4|tRHH0w!LQr3d3d0A5*EY2F0)#Sm}``aHRJy`W1;lZK@GamGL(E34(J8#_f zJABq0V#n!eMeaFq1;58QMUQAvK!_D^J+S)Gp~xuzmmlrRZ{UgfIBr%SqNxxlEXVTv zHfss!3YZI64mb+92zaPIYkOo@Y_HWT_7|Q9{Qvye1U8XPVw2evHWeAhF>D^2&la$S zY!O>bkUL~cSOQCAOW86ql}uyH*$TFjtzt=RHJMIku&rzx+s<~doopA0BQu$SB{L)2 z%`p3Cqsc7fkj7$->=Ap+p0KCv8AJAhy) zK9dDxA^XDqVPDxdmd8wF5m_ua355im;3BvRZfqPI&!(|8LV2NrP*JEPI0%kHVZj-i zxl5Q%48jZ{4!P!JVie{J3xtJaH}q^V*&{4LhIX%zNcIU!k+oVTEGGwq6(ofm6jlnW zgd}0Lum*N$9o7R*2pfcrI4ztZpD;uH3>)!OI7gXq9;WjG?BpdO zgNjt58rY6!!WF8ecGO;+Bs>>hP)}Nv7Nf<5m%=OIjqn=wsVpr=%Zn3f1zM3-qCqrR zoGea()e51ZG)#CaRdWj`y2l@x?NISu* z&7_^hl43j^KnK!Ebh0>GoJAAG;dB+jz5_xW59dqrKUNaWy%Mv6LOAEZy_O!pH4tGv zY_tMwBrvQA{1hSG06SE`S~-E75cn=aU_)Tb2|07eE|<^8&V$8Gz+{fJG%{*cE4#?*-PW0L>%RMFr>}p{@W}QilG~02Rn=;6N3i zqlCiR(qKGu8@RFxWDYR5dyy!A1YAW00$W9^0&1fC1#m4uZO{Uq&|d++p&b374FQc% zz5uu}pasg&9}1gCTcLaraBDzkl%r2H8qftp3Mrsn0o`%V`_u!_6VHqT?ghYD3+})e zGY$kir@UPf3cL%z`G>Kfxhe=4E6fcQVAFu%k(BiZ{$3sc{1wWh z?V^BUIEUwA#Q|P8FAU6i10XAbqf{WPfFZ*iga^RjJN9A_k_3z$IvfbC5-a(N-ao7xu3uPV%dEmQ&IFN0?&MI*E7W`Gow2V4YjS}p^wp!^ar>;wmHGejT`!ed~JEeCiJ*h&=$-obtY1>jjQ)l`98 z1(pDIcpmaAV*Ig(guvqv5qiQw0MErjDhN-23#$NML`2952X3p7dsP7biC|4s0dBuU zSAZMp0nhnbJO^&iL=P1>AH^boqA0%&TucSdSFyMX@NY!)Qi0n+u>`;mb%NK(EfKL4 z-n|c8S_R=R-~d1n%CmrjRe(PvVr4)W%3lJ9s{rpv#0WqYl)nY8ssg+vc7_3dLHRr2 z>MHOtLoP`H@;7izKrPUNF%)a7!0oK~s|tK9#X2f*yDQdJfsd_N56}$te*tc;0&+@3 zY@vd14!ETXl#gdC6@>G^tyQ3WY})|Zfd4c1{i>H2jGE#L8$*Z@L<3&lzRdX2aG^D=jTWjgg3yWRKVULB8~=3 z$Mbv);{dP$+$SK9rou$vIe-NyuK>Idum~_2uo#et^2)$V0n5-9AEV`fRVe3Um;`|S zi&Ft>0MJ?PL&U9sZFoKxcspPR0JMr+2X>+SJ+J|g3;=zi5pWRi@^Ry`#bE*fx{Q5N zik}gW;`|t393U0&7wY*4d>nxBq)mbOn4Jf39`NzFi1N0;mjE~L{Ab{sDo~6W_TZ>M zfp6ynL<0MGi1+}&09k-+)Ds2#5WwY*j~ACSUf&qN7r;LNFThuT3D0)`mH}n}crT$| z4%{zFXpaN-(GUr3NIH~91G}go#sj+opuZGy;EngZ@w|Zcy{iLi;5-X>B48TMuL7?D zyhELM*c<%y{(y4y&l^1Q=CnbMe441h`K2cS*d00;*a6^(bMRIVTJ)fU`(QoV*Sq6< z60nB~Tz2%H0JKA=0HY$kAI>3L`qF?voX-UgR)H=64grLMo;$!*0oCx#Lg1fO5bgm( zPdQM?oqnhabO|u013(ji|5Sm?v3|V@G!b|sU@M-1oa(o!!1Y59+2ep1l<1RHph>_f zfP*Ms4GbC6AHn%rf~30&6z%w;?;I%F@hzeP-2jZfa-e9_H$Vk~x_m3CKsNzn?0q}o znauG}_<_e9C}{U9uL7T;`!!I3?goxl zfzRIkVgTLo{9ZyzV~jb_{V=T*06ORagrUb(;Isa3DE}s+96XTCD$u_We&zv8D95t~ zQlXK-zInT3O6Nu$pyp|YsU?%`h0dKS8fXQ*zHV$C1C6d|U=<9soNq;gP(feMAe64x zvYmgFK3*UHTTHyZp1xO?7=u_^!MM>qJ}O9WAg$WP;@G;Kuc2m?*Z0%zQBl<@8bn?V z-oVrGQK+DIeg(ivQIM&kL8{P5Zx8~Sw`=tZYf; zU0w59Dpkbj>ZnBr)NwP`C{BkMJM+T?eh4Z~hZ>vl!vKDm#}B*s!ORan#py8q#xVZI zF#g6cqq8@EmmhNY!N(iVb>@e8{BVgM%=}Qp8xIfQhaf$k8-N3BB`Jp)0QOXnk%-b_ zNK?|D%plREEeT^klf%&HxjgzL?s7D7XDf(a@Fk9jVcg+gb&`R&Yl;#N*bEmzb}H$b;UcUX5r_t|BTONMJH*D0>A-DYNl(FZfahOD?Tc0|I-}^tV(!J76q{RYL$N2tD;Dok{HRxDuO(ie zOB5+_q{Qozi@il}op&Yg=RVA*hR+nAYx?H;fymQ7_0{;+_8sbb%=et{6JN7mF~2c> zS^nPs%l&goMVHo>o?rS=K%0QQffWL01#S%dRHjy$31u?MRw$cXu5r0>N59%MZHt0&w+hB*_rorul zCk5}ST%mGQhuDXV54jmyD|CNYrLZnx*TQRuuMU41(I;YA#D~akk$bD?s`RaL zqN-ihhE?}ebE!76TJBGEemeBC=g$j&arkBYFITJUs>fFUt48G-n`^wOS*7O0n(u3s zsnxI6wpt%+H>sUmTmE%i9p^fI>fEi{y6%{|SL)TPmsam<{g(BY*MHccMuYwhmj4#; z+aJHJ`t43beZ!Fr?=%W%w5+kd@z}*s6kG3#QU#=MV_yEpB=vitoW&3pXS)2rvip0j%{?d94lzE?u8b-i}> zIv86jc3Ny!Y))^Xw{vf=-m$$e^l8)Qbl-@+%lqc_>(ei@e{}yx18NRfG~nsLDg$>7 zJT&n1z)$~|fAS#BAl;zigF*(i9W;8-szC<^ofwoc*luwB!CMAj7<_B+iy=-!9t`<5 zwCK?CLu(A3K1?@k=kOZC8;vMGV&2F?Be##zjhZ#;$>= zj!zpt?cwy0>7Ax;o}rmBZpO|ykGN5BsWYq3TsZSYylZ@;_%ZP(W|f%Lcvk$Zy|YWq z9ya^h9G^Ku=4_v1n(I3^X72L2d*^l3G+bj?>$`UEx}Vlv`Lphyd;k2h zzRmhw>+f!e+HhdQrH$bmM{g>&dT-1B_RU@^0td`rV+Ei`yVve9yXWp+zkB=cJ-ZL@zOeh|?yNlx_9X5(vA6Wz zk$Z3LYrQXNzqr50{`3RC9%yvnX-a6y>Xe*=y$)s`3dFylLrV^QJKX;8sw2XY;zueU zX>g?Tk&#Ch99eZ_%aPP0H;%kLsy*s`H2i4equq~=J-X=V)}v`hZytSj%h@H%M=t9-ZDdePsH)^bP6B=||Gf zre9BgeU6ow@8*(oG+@I$TpSynU?fJ&%cb`u`pMCzzg~AsCFI2zK=0e{K zQ!XsOV7PGl!u<<>Uv#<{bn*9#y)RC>xb))AizhDLyZGr6yHxm6=}SLfYI&*mrHPjk zF73E<>e9VSA2S>?{4%O$w9JUjn3$1}u`AhCAU`H+HmXet*f{0 z+Itj@0Y({=YHe+ zt?&1_Kl%QO`+wd)eE<6Ww-2-rd>%wRX#Al2gYgd%9~d4Sc#!(w)`Rz1j#>U$)v}sr z#b!;)TAsB#>wMPZY?|$z9grQ8T|K)E*2|`4ugcz+eKGr4w)tVvhrtgUJ?#E){KLeD zhKFY#K79D?k^7^Hj~YDc_GrMPF^?8L+VUv%QRbtZ$J)pG$5kG;cpUq9^5f-?_ddS# z_~~QQ6ZFKBU zpZ@*K@tNl{|7StZetOpOS?sfk&k~>Qe0K8L-De-3J3QAvukgIe^E%I)KkxZ`{PQKx zw>?jNe*XE*=Z~M~KF@n$_rm>!{zaJ=aW9^~EdR34%S*2+y&C!I%xmA*BVSK^J^OXS z>!jBkU+;Xq@Ac8wr(R!to%#CB8}W_Tn~*n+-o(5a_a@=Zt~Y1iWWV|P*6nSDw{_ok zdfWT$@VArS&V9T5?Y6i3-yVN^>Fv|EUvk78T~3LdGC5&6HFFy0w96Ttvmj@4&Yqmq zobx$1a~|j9=Gx`@%IT` z^6zWEZ}`6D`}Xgqqvn@Wc#D^09CQ>Ma_)$Q_XiuDoGZ|!b(z&>}Ry8>33?zde zHOkRmITp&mjIC}v0}Jv>X5Q7Klna6j;#xh*h=c~-G$QA~kyb@^3QBfx`e<}gOA0B- zz;wxlojwLv_Vsn~6qUI9#-Z@f z2_!mMn5n~s&T^r!8N@4(6~~?8oXsVjIQ3%3&)-Jp97~{QWc@?nOjgxNEc?{^7VC>Ru!? zBtmF6Y1#GT$2Kk5eCWXR!6U{`qm{R{IJbZC!K*0?r%y?sBmNj4TI=%K^;g{Q-1U5Y zVa~=e{d!k`yAvNdO5WRmfPizXG}_So-Ua z3x7VukRgW*gF{fVi&)S_L6=e63lD2Z_kGWhF~%UP9|)FoFgxHN|QE3z3LWQ-L2 zITIs;f-Ad)MTCYF@j!3={Q|;0m9B<|hXsHQG%P}|+|gU#;0%%isb}n_DbqG=nlyQ9 ze7lDAe{Z|EE&FK`)ok7*=kbyTZGZo*ew3_@Wv64srBk+Ui>p6%)23P4rro=?`K@V> z9xd}OPua40R{bekHqFvB>)x$R!)7tvT7Rf54z3NW)7|`9{2-k`3Nny{V#ccox{W-P z0DnqYRG=s>igMxbE5U`sSkAr#M}l8Dj&$YxIC4=7-PA{lsi=rcG2Anh&?Wm6$c53@ zM=^DftI7qX3acU&Y2gfmbZBV=WJBxeAE*KIN=YG+RLg}&aQBRihyV}4s_w%!bg6w} zbHa(J0extlI-AC1-0#xxbkFNhlN*ah%d31hE%O^byiQ0=YV6q;}nhjRw*!MaN7YK38}WJ-=1(@6~^e8bI)kpy*5ReLL)rPPIN# zzV!jI+}@ZxCebC*0(m}tfTyR)<=7HUAL0UQWhfkE5S8I~b&d4I)>W;}t%#>KAdpQP zl{+b5;URlEr_Hc{X`^1VW)JBa+PdE8fpVDqsEs^ce!Mk$P{WRmRHy`wy zyj6|?oh4Wop$%+dVWL+@Uc~r{ie_XKGmxO7276%pprTOV(vcEub!kt@O)Ch2w4r>Z z60Kyv%z>7zBwsi+_TZjz!j1Nc18Ff{^q4{x&zg z;l8YpT$Da%K1e!KG9R98IMxB}v9nIm3oW>#h4d%0f>whoM{@rKDfJ7OUv=Qxm*|R)`TH>;T<01Z;_4Qt=!e!tu{e>U!~NGU zvc&suUfmZ`rp}u?na!LvbDF^V$%o_}!wF6Xf67 zE$rmhkZLMr5-5`_lof;^Sml78i$Tdk0Yye^@I)y>4SyFYymTnLbx@wgTuX|VXKv|yLeXze(oC(}#tB>MPWCLQ(ZDi{g3gmSrPC$bTiwuce`WOW)Ts^nVuwt=g@Ds3 zr5F@SeZ|ncdi2Y{Ht|E^m!(kQ*16XRcSf^2(^&9?)olhZTs8abm+Q$l~JZzC!4GAxqzj;i4EfilmTY<4BP45}_T9s|g)s4B}^(-}%+;Am|tF{+{HiH>^(f7O-1GIH-J>PzK&PFTV~e>#2Elmzq0 zc`2sj7hjI)J#vbf$US89!G!VC=dN5dO9)}p2U9Y0(2gg!|LSb45MY>a;_3Z;L*i#o znGlCX1V+L!8qFcI4zLRi)&AOe1jR`3{$l46rR+NJ9 z5(SrFsfRy4R`^ab2@luduS)nKoKmBUumGW%-%T@dA9DKWqrWd+mh-UPtJRgxYkby? z8aHo&l)Os(l08-acr9CgPivX#W9#o0$uw|q+d6yh9$1oqWi(2#rYM%iC}>#vT}B z4-0n`vEz~!Xz#&?FA$m)NITk$tWZ10>bBU#yphaasRytVIvn>X{;j$Xd>%iMWl@fkx0%$#|DHl!fNY!<#KJuO8#s9aR0 zMV5ZLq0?@>pMo1#89u!sf^z0&E2_4J9+L^{-a;ODc%<}+%Y=)Ej!6FDuo|U9;1Vqn zw@|&>+UW6zdJH%pck>_FAnzy@_~euPw&SW&Nux$Dp2sHEZ9O(SZsE(Z@)7w(g#5ca zN?IvC`#QLF!+nnrEnAX?ea6$_8T(=9MF4UA#CJEinm-Fe2qGgsHB}U|c=f2@%6PIY z{B;{V8Hi^d2t%lb=$we0%ReV?9bZ43n}?XY{HY%V-aoU_3DZ?OfY7|<+1us({p>5t)7Egtv^7MuBv{X>j z$o#i39OGRSTHi|Tjg3dsW4!ek?_{rnK*C78xXUtP!w(mMfA?xc^=fcwk&)lMS_B3g zZU7$;c@)g0yR(ocQ(E_r?J+imJ=%BV>bicvrR7hpmyd{VJ)?8K*b#j@tUG-!dDqsy zEtbm13+CFr<)1W}QX>37ZPJ$*Le!|m4m8_wO&2nZ&LMW3M&}@-WarG!>~zUhSpla# zG7KTQWG|}{OnA#>7|I1D`&$({>ym30TypV+-Bm*TfXE0}-YZW*0}~wSiY0k`uA^}k z`IVfsK8tanr7-l% zhqO}(u<@vtILqis6c_3lllzk)JQvgHh+4J_SxY5)Vrh|F3-JymPXm5}YkmaH+CVboE3u zB5DN}7<6O{Sl|}A;wUY(ny!{_ow%BQ|MQDX$*@^YKil!5oW7AsuHR-+cXOLB)QxWl zQD~{B(2^g0D1v42JKrNYM^VG23>hnHgDL8413O)^oi%-k;t(;ZAY_?lvU_>mghi%` zYy?|t%3CEFlH>{&8iGKBJ?x1h-2W=}Mti12lbF=~K!epxkxM*}A$haHdDE&?VY;ar z>&B*-#_{I(U%49%Ik^it@!__MtJ43Flm9-CGJ2~%*gI&?G4D&>tm7VMZy%0ocsBz| zE@{n-(hw%UQY;V=m~V*a>Cb#I0n3*q?qtNf4du@Uqx?FNL1BwLrbT>GBjo#Or)k!) zzU#u}T}*eZckCt_c5VXwjrM+#NqyyavU$Yc@`K>2wEjwUEb;j%m#dy?&uqrhW};|O z}kh6m+T+dvq8pr_I#Ft0^@3XI@o%^mFXI1H+0%1RI*Dm`K6|^ z`)L^6&XU12mks8li~UD*1gH`arz_1_rnkz4g%G8#P&y(t6_4VraLlOA*DXjSB(py0~(EEN56gV%8b#>awKHTx&kRrXsX`@3O$zx^Su zhueu{G2gn2OHHdyXF*W@XmI(pCykBNfrq#MGAIfmmO-&dk3yow#2cBUE^jD^3l`;U zrmBegr=_t6$HcDRl0e8Zu_x^DaPwaTE2e$Jb5LnW`h6v zc=pv6|KzP6tfkXOQE`fVp+WQS{562TsTYp!y)0a&Lpgu1%9q-n zANA4oJCC=@Y1b)!o}9;D<*a-jW7nq0MY1sRP2G%AQ6*_3=?q2wXH;g%IT&?nRHn1> zRYpfeK@5cUmiYn29#oakWd7Tw|FF2q{qeexA6omeJMuG&- zNUW;*(?Bf_q4ZISvQ)p07AxcPFil>)OTOmmDWBaXuSuonQg;Yn^6U&JgvVc-i=_t) z_;v^MQG$Kp;zgV}l0N^!0-NaNyFup8$dYt7;LD zizY>bA}plyE@1zu!aS-tU!H}cp=>Jc_z-IeHy+E&<)x44O*u4Mn9M4fDw+IP71J4Z zpIzZR#m;T<5Gb{STq>T&X0U9c1`DP6#DQ06k2}Rs)}4;MEjy&j4tLpgb|-IuDVzBS z3wZr)QU7SvZ%^u}_1jcwk#=iQH;P1=1tNnXS?RL9q*Xe}0|Bhthx>ZaszR-AcLndf z9O3h-RrAHkNppCM3*|G+Q8N+xRf-@r&y%Azie!_!Lnq))d4$azj~$a|&{5L!e?~6V zVskkqWw4%61+**c8CZMgBV^Ghq);ItWehCZAQ}GQQH{NPhE7r1MNS4!(;&X-z^V&; z3S<-ByP?@|gctU7v^+g6O*8RJgQc1{-f~TLOF+y7O$xNpqymA@FjCBu;Fr*h#BD?V z+<5EJ?X>&^T5g+oNcLtoOl47c;?@KFDfX z&gaAa1%iW^DIgH;RT=PRsbbPkhtuem_!i#RV3VJ8R3KHeH6q)Nhg4?$CO<@RD}AIqe(VKmB`G-e+!w z_25}y?Az#JbS>`1`|PSS2sdvg0FbbZ}Az*vTfc;mcoE zOG98h&))}X`NSnc@9Ltge`#HKmPph;PQ5VDerw7=8lRoAaOVEzZT3uC%v`?6R~L-a z5YzEla;9vOj$GU-SJ-+HBmM_Q>@`NLBxz*SdHa9{Rb`cQo`qyfykjjpJUBuM601?z z=z(OO4S}4$p@l&t&pxPZSF#TpWFLyK>fILG?UII{?0--GHuToweedjc+0Bccvts#_ zk?lKfj-i2+_#}ObyS+1Z#<^7gL-+`Ukj@rXRUU~Gbw@*_O8~NPonIe2Iv{1M z{eV-4-=r*^ZfMbJd)!hM@DB}|%)-8sp>Z_qi}pZ95`DJ}7MGEZp#B56>;XRaHQFhB z<_xq%WD0>6(k+t$V{tnrQ(7F;^Wv9^V?u5EEAzICbEm%V{nnc1$uDJ7 zlQk!s*KT)NNdI$D;W;a~wfY&|O4oRxN8OFiMYu|;a-;M_pReIIBcizHAN$Bf+iF>e z=UJ^%M6jL)w+sjv&lMrjkDg#ew0s0SJoswcvu)cBZmn6vAt=0k*Jsa!ZSw}~JnE8Q zAKP{Cyu3Exd$inEcn`i8gI}0#^eY{}r3M>#9P{mw4S|X-S_o8T$nN?5P|TL1r2_A% z(b-d3yMWQLO0F0^l$+dMStU+*2W?hpRH=&0pX6gt1GF|goC{bakG)j+ihh}PYJmNg zf36J6`YC$E_8Ex-Qjfkmm@s2k%QjnQK+sII{Opn6vaY<3`F+5mrSTmn(vT1PFR!L= zS6so^%!UDf09|n*4UG=2Zpzr`R2@;AuceQcXi(9S!Z6K+c^}o30QX}K))tjUgzEWp zm?sf6%DkV}9dnZYE~L=d0qx@gQc{HdiSjs8I6FUVV06Y=WEL+>=Yto4WqQ(5%|Cy{grEw@o*YIE$uKVE7l$36?MYi05 zX5ONIkCLZqNM7d=G)Ddze-#IRSso+T2GrW-y)4vPhDse3ioxLHP5EDT(2P|4$w;GU z;lhi{C$;0s2ZyQXAPk0ew!SD2i##zlp71(~ zyyou>@plRH_v2zqt4Sl$AGM6wF`UL|QhJZ;8RvNL*}h*>#A+jF?`#?^&oGr|=|hK% z>17IGCtt6~dx?*rEINgLxscXI$9$dQL5xkmY`S7`?F#i)GZ1BZ3aj8~qg|lcR=wy? znz3iB)Jv=ux6)d@Ko%n%5PO7yDrfAcscUp9QIg9##Mdof))fJ>@YdoIZJZwBD65qN z?)133CVUqkY!b0-<5RfUVcdgx_o&OL?1gvboP(QY&)K+T_RP&JaJ3vSUz7_aeVa`~ z^6dBAzIWPq?>4BLEk}#q3U$TFK%<-Lv)u}EJvN%C%u_9-D!j8;Uxmer^;Lo+s~E|8 zujY^5TaA%0;GtX`Y=b24hiNAVrEIYuboTh8l$CLtTesRaZ54C*EMFOC`YhcZIa|Ih ze--y%TVndQ_$s$zo#kjDC%-5CeuzH)LkevCh$8Bio>)e}HV&~Fj~~17-Cg**a35h4 zguFbNI=~L0-oXS7ohV#^;t3RmV~OP|@2i!vN9eFAqJ*$m zyTXLOfiP}CVXi$qdOL)+d0xlfDz9TR=$4I`MnTz8$+zSdQg+f=D>(RLox&`kGx%ok zO_!x?v?(m0lx63`k2`Ud{R8UG7l93upKWNCz3ae}gOj>;AKaUIY;W~EW%8LpDblRL zu@k6IqgFq+9@>1`fuoBX_itDK*E-ePj{1GUu0J+JckI`O_sib=nzfZ`A`0qaENm48 zDHCc7PnFFNmJ3UUjfXbMem*`!wAx9=_wHCNLLq$M8+u&1S;L&wU&+rzdO#Ec!g)mG zLT99>N7T|+`K|8Q@h4A8HRZ4KOkHZ#a!PPdh-a(kVLt*Tap3-4*b97gYefFz`^eh} zs%2M$Vyl(8fG0Ksl-v;yUl6DXW%^#;v6rTtxmGX5&}YKglPuL# z_fwMK_U#m?@r6q{2x|T{V`O2IB6^mK?*@P4-dbjy&?nH=)M2Q>vxL zcjnSnoH~(cqol+es+`-5iH)4wXn>_Lg%1`RZX}M%^h{EbgMvVZk}=}bU^ll=v0+Av zd@@1)$4nCBQwOf+Einr}eLE$D<((I+lET~s*z8NhHvd9gOhE+m4-5?VL1p zs2UrUw}G`W?GeHf6XS$p%ck%aYsw2*lI9oeVF@w172}($2)6bh*;BAL&FG`WW-Lv? zHx5QOgucpm9WXE9VgBJE;o;b-;;C`L_7rSzclBf=lXqXc#&+!vxV&kTa8X_u^5pR8 z4-4LB?9UDz@~iwb{ZUl=Cl}>6wL!ryY)Y$R$u<4Q-dUccqIH%mk>6{Ma(dlB@8EoT zrF?pk9w{1Rba7N-T$doDj|=E^wW3#Y<->}NxDnVw9SNFsm~j-rl6$C!ANTQEw{zOP zdoKqh8|k%cdv|@SMIG)wYu)n2Ia>VJAtBi*S8^77NI(2A1np0u3&kA44{Hi_j4sNW zf~r?aXj7C&X&DA*B^%&wvo{unKUy?LE+>4Evl3DS8V{`!Oc(Kl#Dt4Ehh{dIxTRsa zrmfc=nALc;p=Qa(odx@(Tj7gK_36acT&%g)feq~ppFB%mN_&V+l$k}S)y#s&`T2=E zi(=b;n!|Vm#&daY{%$;i=i8gNZvOsd4%`0iwba-$pP=~4!V!C817NpW8;PI4A}8GE zE77S%K);aUAg-j63!XS^Fv_Rf0b%%s&uekSSO70}^$&hMF&F z7=wI?=G6R@-DlF1QxZ}&YPw{_lu=RR&lZ32(vOz7>wk@w^nLii^IC!>X+p6RkBEHk z@LB`HLbg*%r50=f3`9PkmGpV+_APri4*OP%%1b5Uv z%Epv`?io&#o3SyKrrA|z_vp7TP0EBYyA5mX|2}i{{;>%I zVkg_v8m#}_d10$8dCejnCjgK?5)V)ZN5M{G< z0K`@!Hd}r9((37xXZ0GmX!4?@<0n=xnVQ(Y$GoX|(L+u=JTYj{$$^7T3>i3ea@>qL zE7LFjnHZNaa@5k9%l|xgV)gtuHfGGV(POTT8GUus$ZK4`c~-s@tU(ccAxD&1tCiof zjFx471c$^|M2%Xi%!0me2b2o7n_=5;vc1(Mh6o#hv3Ce7fe0xOSRl26D8z#+BkVMC z?ED`hX5@tVKjiqmXxMdm0hQ##w2pi@P5z5k2WaI5H-%y>(G)yx!&vz!tvzPzUbh=gYW{Lc`t-B>=WK@FT04NAg^Jh z4w-87uUn6gq`%G(j*-mIr21nP=+CPvV#hVnP(+tpqhR=qtVj)Bip*MJ{>53cb$TY) zU)j?atV@oxdZT1yaDFR+8Oldb1^2j(Qum+p_$DA+$T>^p=c3e2#4s+ zN+a>izuYMzVg`z5#Zd?AHjwik4?J6M*1cF{EqV=CztP=rUZ_*irobJ<&b9frgp^6`90#OkXK zzHka@P*g&h^r^{=(w0vZyXSAE+^J%z1K&OQ^Uvk;&7y#r=PT(c#)@lQRkF+&SnVgy z$3Vs2;TVyxeU&g^l`PU5fr|(pNeU5__|rnr9%sQvU>%JPl_Ge7L(m@LpmRV$Vdd+` zWEU#|=2N4BOQV;vdS{5xCF={mOfyu1J{Mf(yBY4QdA`OnRQbEdOS`+`(*jp)IxFSR zw_jpqUXM)=`MV&*&O4G;9XYmQ&GvaTP56Atjn<^DYm($QYuCuHR}VQv z8_|ih;h{b9-cu*#z57_3WoxhQ>uUR0g#*MV}_N~-!(+2tO z)^ytb^l5ox`bl~73{bXAV3CVt z7@5c~jE)N8izV0(Uf9b0yEv*3W249aA?-cjqo}(6@x3#%y9toqAOX@yg0ui>7CO?U zNf(jck=~0`={=Byn$Wu}BOnPN2}MwZ#7ZwBiV6ZMDkXdK`<^>Hn;GDF-uM0gKObFo zH=FFe=bn4&_ncGwE+tD0Bm<4~WJz)YLad~b<1}(1Rib4|h^3`LrEG6a8#iOy?je&K zwcfCM-iND0`R2-<%MNeXMaqkc?Krvru5pSS>1&9EWkl?0iQ=yc(q;<)Xl!QNB^&&!mVbIw4d*9!mn&%#!4rgaCcGfj=vTC($P&d>!!x zj`(=07_D9WW4d%Ec1r;>Ce$qEMk@(o0edEMEhH#9HZd+XE{;lM5R8d_=Xu5(1=h^k zzyjB;vfM>1aMg}!6Pe#KZ`pU0V{OyUt@_NDEepOdyJM_xg>1hb$~37#ax0;{Wx$`rB~M4=f>03C*o)1ste zHD?bg%No1{ygftCl_ukyNm(k|x?R^|PAwOTY;w~cwM9^Br+mPl)cu+V;u zYSez~wUH~P4jnMK^)jrm4mxbF#tLIC3)KiigvPW&Q3!?=s+KY$j&F%SILtB?9d_kz zYF!kA9rOVLEuLP9f-tPuUc6$pgtt~bhKex59Sal{VQM+;FQOzYqWD*^FUpR%w?!hH z3S96&0T2x!nUsiTD1~JNZ9uz<+4;(M7fdimXPt5M8+GY%YNF7)QwC@85wX{ z6p0c-q}EOTXeCBLU#62?jmY4A_^tkywyM|j7#!U@5bnGFLWEQFh@j4jrV6i;b}#Kv z{epvCAr;C%#z7*WvvvQ`r|aZw^X#@WwJn0y&N-XbX2=oGJ{vWs8Ly0CpjcBwaD6>k zVI?e;RY_p-H60>?9wu%R@pKE>MTq130rW(0s7OC)cKe_CzpTX1%uDj%-+x#1v<>~; zRB14qAUA`L9-_)Fd?P$954!pn!>)F584@_1sMu7kR8+b|wW9HL>(cL!<}Il=Kjd`- z)#^i)9@@I}Ttack1?1TuV2idv&?16`4?67nmypRyafV2Z4dMiU#HFxurB-DvvA6D2 zuUAB3*z%qu1}DZ>sRS$yzIURuhCKj1Z14}50iz^b9}_)@x0T`o&tgt=7kEMw*-_xh z9;~~_di&#AcX@5v7)Y9lk}AhR#+5>Tx`8Tdv2NJdzR&3%wM3Z6@S_ah*PxOi^g@bX z3PKXIgOtx#%-bg(S-s}SVgBW(n|iiy*S%-Ewml@J_xclgTbpMdKfcA*XXL29t$L3f z+EdfI8S;2^+>K?aUKpXyQrRGMMl7-*cxhc`-D8PkpA}t^GVt#TR@&mh>{5jEJx<71 zI~binqS6U0VEtVD&I)vf_YlAPy_CW1?37%-_;+-?nfM*_{{2);XRgt|ClYpHBo3l_4N&q;K2;tMzrHk(m|av)4T%X!T^5vdWiiF)ai0*iiUf0@ zP*(8Be<>+)L_)KhvU%RJ-L8S%5=2oMEP7NNiGTo%#hSs=TkMq{he}GL-|sUeTl(RX zliz2(-@sL2ByArwb!=YmnD|KG z6}7q(B$(X9@p`0B1q_c^-S4?_Q&ac^7)+5s0u=T+G=NcK`Mc0zk&!YL&_H2P?PowF z%4qDJ3K#h}zdUzK9xi|4Y#AuEavlnn@}BNxXTn)eo@sSt@K@5Ezq9euHQb#pm@IHj z=?x9~s^|;gsR2}gu`l5%LZXT+8YM6hktDCuTAZexXf}=?V$H|#1N;D9wPCF%@qOZfJ0`KVd@n>8aLt=gU33o-rwBw&2dGM=%JgRy zvWn?3)^)c`rDtwxhWd(7X|(u<+{iG2Q!(b|feNiaf5}*)44oq!0KjWfVqLW}At?#= z-~el22xUBg%i0JQE^k0-YPb#d^OG@mw6~JgY=vC*Ht`pqo z=(pG0$z=oD5k7j#mZHP_a_>ir@PHP($I&tPB?Y?I7Os8S`GeEtBuB262Ic`+fWSI6UX8IP*BmGB7;lz|$nnIp6xMr%Jr(5a%)EssPp*JTq11(ugIYk=aK!dM{Z zT(cSc*qhn;Ir~pdYjLFG*@JBl#8$2`Cu#7A=0`g%7|{8$(y8F?$C*>kHcIHebnaW3 zYL&8UBC5Ric4Cjz`E9%8w|{RizXBd?Rdmlb8JVj}s1~ek`9hU64+BO)HB@c-I$m?} zpb6Pl4)Uy=uJ28E-5qU{%F$g{OIZb)trQ?WrSeO`+5mdQw|K8=Kq&z@3DrLRy7|;C8VO7_1?O5Z1WQpUtg*YtgnNKVG{rbilxchyFY~%2BiKM+3k9#aYq*(aIGQ z;_Iz1^lZAm=It>H2gz+lt@M*ZX9w=@_}-rMbsu#YJZWg#fF%dowQJpp7yUZQaqO+| zxf9ZwC;u)DZP&7!oVaU2_^ed&i$4H|Rkc+CZmKeDXM2^Z#4U(iRCLi@n4~(Vxzi** zWhhKf^_za;nGu46-!`)o12jrxyG6^WB_ z49}mwX+rfymz(9z`sB3-dyh67AVn^CciF~m)26Jl24U<_|8DD@OQ+wQo%-vHktY_d z=smM*jm+c))B6A$F?mzdFv3#xF(j}N>%g@mvP%eEbUaghStXp;hEsk5Bro% zjXa3!O1Z5eoBJ8;BH@IQCFTg$-xjVxB>L|N(>W>@H^=o%sahB+|Ln}t3^kXz*7*>7 zU07^&>J)O(<^!f1MSCU!XK+a1*J6SAQiO*41*SC-*s*-IH~y({%oJsb43)JEg&bZGb2^7gSntZZ*$c&*w$2JiC&m93LhfjJSN@ z;4o*KGFP&}X)A$Nh=V8aJi@RP_VzLyr%>p+9j|8%F$z~`#bO-i{|=+zM_0}SUjk9EXF0!^^#Vo#H)S{09|F5+h6U*fA#Y7-U450shBi3>K7lCoil>JFnTiM; z0kBOC0)rK(ij6!H)yGTN9)NHJi@FQL;gQd5E_y*P3=KDloCe`2DW;qdlzZo zt3~1K(Cz}Y0`5Sl#X!McWJ3x|z<^kFAW4Iuu~npJ?1sGqyIg`kObHGow?rP^)#d|A zlM?Wvc96mVR%!O^JZE$s9;It}g}tO}097ttTxg+kLIne|qtGfK%DMPB^d>Im7;thZ2iPHp(&hNA)vycd;%O%SmYX zD69`gHY8a$?L-9LML!XDE}fMUT!b(m&H+}50a`-mfFc+}yA!e~kzzufBtlFGT9<%i zU@<{fQ6g(k0^R@}pX~ez)d+&}a*Os;+B@^tNz2f0S=vZc!>XhbxECcYEwojMT%E2m z+~y+FY}Ws{DoA6o2CPJM;!6o4=!>?3A?w%YEM1x-_pLptwli4Tlrkwrx<%i;k+)F( z5M0_-wTW6cZ3!j|?nU!emntIo0wyLwX)xtfFK^LF!QY!~2(siT9wMNmNl8?lff5bn zk6mkPCws@#p6g6NUFJCyEI7C4_^;EurMrFe}#`|%-Z+Zrr8 zy1~3*Q}(t6->?3t;B4We&4>Kgc^#MjT`=v#!f$Z{B+G!JyLPI13_+zrn#wA~kl=y} z40UND6YH6RSSEYSEfEo`GRQnNz#;-%kc7rYIxw*e=xW-Xp(_>HSqA3?7lw&-;7Mxw>^u z&%VkZXJ;*#m$hO3oQ+D=-f6*-_dF>si_aU=r{5@kcl6FvLq3=_yie~DtUCAnLy^@z6NN3s1Ja zk<;K18B{OX@~E?jOrm04J95{6l3HNWN=h7j)JUqh$mT!tJo(Y1Yg-o7jt^e{3x@6W zS<8Rhw&S`_Vg5IPaLXHwu``L4eLZxES7$zl?`waGA3M07S+7K0z70uMbep%3j(}d} zEu+=I@CfWh+la_Z>GTr2(&dE72@-w}2@N!od=5`wK$(+_N8;88;A@jVDAbT!W+W$x zS^)P6*n<+J9%r|&u3gi+e8c)pcI}e(Zg``8aBQtz%2|2WGrsK;|5UF5?<&fY@!O6B zrIt7`5vPN`kk)m!6v&SlO9v#?M7|A{Y?SMOgx#d8F1M2K@eA^ z=&ywl+!eo+4o>j3qBEkgrrJ+=Of}WJ_&+O=5-Yj;;hG-Zw(%!D*{AtOMPc=^vszvC zc2+09&)2N}?ltzAv-rogcmJc{yn^-O>QKhWTOvGg4ki-?Ln?Mq12m}!b4{0uCK;gn z<*H2)J~(6rvN2{)oOWe!GTm0W*bE__%rIdsR8J;({@f<@((;?ZCcn=A$lkVS!L}U> zV3Cs{KHsCyG=42%{*GW6<1FDB5W`opeGgm~v1?RQ*~(!ad#I(QTFRi0{NYmj>*paV zfb|!82wi1fqC*yx01O5kjzLs|fr4nsNFMmvq!(&kNA=9ycbq-?rkSDM^}CYuQosJH zl=Fkryf7HFHkQ3YegIQx^--3hvZSYK7d2nneRvVV5VQ}XBm)5a z;)NO0jrSQ6$e~mBafxRqbX8PrVmVroUn$Ss*G7 z2dEz9%9Ff@8U!Jh=Yp!oAsv(yNuD~| zg)$%yN$jzrtIT`y#fb&KO6Tkw=H^UlhK9+#(u16T%~M+QZ=Y0H`FIiIzmDF1X2_J; zg-M&|k!rx%?oe)HmbC@(>O`%Y6t*AILH2Mv%wUE^M^FwHD!Tqa&%F@80jj!WsUyMGTfh#2;2u+cb5?EeZ79a6!owdWx68t{%FM$ZYD-Vn8$Z*8oOHj4uK1oKiYkbFa z<*ankdI7pEPW5!@HgsI`kzwO|7N_1cUjTO=UnTMku6&wwaSMO6HT|t-jayqUOh{cZ zzH#eTO|-S&M=j5Bti6mXc~Xe?d02^%4;qwYkqbG}Nk`I2mI=y!DbCgg`J+HfB~=a* zX-(Mo)bm>wZLaO{YF$7s$>`VMO2Xk1**=O}SVa&Tfoz zQL}+{TBk8%cTb$yG5*a4y&5&971!jgF{kTQi!U&q2serqyK)G+8N1I~oOh|`>Ej#j z8}D1!S3$Wm$uPSU5gvnCa2d|H4RXx$G@jG4m&z@AZYsaRc6RHg8*k$#r^j(vb zOL86SFVHCU#CF6f?)UKs_dr+=8-nu!fCl*4r}zuWgbXyigklNNjzh;rijZ7+i6WbF zok{P$Qmbd>vah^8c|y17S9>IcSANZUb;#_%I$m{a*at5ReBJ-es?Y-ODFt#B@EG-q zdqV?5!gYB`LX-5ZwE(Q__6%vEc5t;_&vv3EZnV@bpZ~Sv{Zp6ItVR4Q7SF#TUGo7S z%)To+AhPC^*pP4*7I!R*~1g1>lQTOA^nc;ppw22 zJ%|ev5ZEdaenzD2gFelh^y<;iF`fpOjHsMWN_m8MxO7-&U zda4)W#}_DJR$Z!fo+38O#O}!@2f#C^$()oFr9hqsuy%cJT8*u%fho z&MUWB3H}c&fqlHnH}Zg@vAEY-*I>IbQD&u!M;Tq`tJ;nJ+jXJQ8A-X%*4QXMh|Wj^ zxg{>aKsFI-s zkSxQJ#5{;@fr|LE?$x=GYwU+3edq98ZLLy@_OER&e;i|mutA2p^4XA~<8hug+Jlgv z`w+*d4zJw`k4k83p&E62!yQ_IX=E^Eu^xe)RH{20UpZTlY#@_Zpxc@_~9#i|8R95BrZv`I0ok7!Pv%Pc3dJ0OkVD zxm(GW$Q^?p4JX}8StiTRS=Mjxt zA~lzqEM4ye&RM2@yVlY8<{;RK(UzfV35{oglrMwuUNO%Ke7#O`fhwS=L_nYz+7Lj} zM)mL%@oGfpp^WD4k_rs-7|3T4aC-|Wb?T*#m~@Dr4LJqa*U8CpgAI%= zT~f69_%nWH%IF239Cvkr?_Pz)KU{IY8ET-NQHRbT z6Rv!5;J_D3;lDJQtEo}?IzgW@72Spx!33Bk-kMgGeo|$)tKag|TmX&!@$&d>>B`@d0%)e88 zcp4iN!YchPm3BVZbfJvA8EYN^zBmhsQUNiGGNN8yV-JyM(^uw>OVVzl;hBl~66O#Z z8E{Yt0CXAe0wU>=1#q%aJC%$|hs4+jDsey$NaO~z@&^hKik^^mv}lojn7>*+&Ogds zw~Pl~8#I0q-;m{8ERP>_m6zQZ#>)OS`_4a4e;VnRhdegH zr_>=4vk5$X@M<3zNBWd)GhCBug;TZJ~?+_e9pvt)_?BcA!)42()VVsUif}m zhw&d+PhR<`Yeu!ICuW>`(48k)_YFBRm{00AXYt^|6Nz=RrjOksXJE(;vs452?gso> z59&ST@<(WwrusD#_D=V4(O`!HIV8RGc19&w>7)F^96swP3zTD@74bNBQ+^7X_JEF! zvz3LVSqZ*=phi=ax#*E1AuII=n7d>hhP|PTQw<9g;qkEeeHBYmYF11MqHqh!flN^& zF+|1H;v!HqN7aI(R2YOzbbywIhMu^xaK3fym1WoYlOs!6@4MF)EQk6wCOuHQ-zNcRZ;WI%B8!rHfY}lW8jKal^SL35#MI6I}DedbMO>k+o zOpriLBf9ro<3Yh82+t6#Q!A|?IiTb90~3&Qv$682V@IsXF8T}u<2v`c^F_{+>?MPT z&v|t6=5MTe%U(m%KGR>0C{miPH|`2^%}IATg3A`bh) zg)m0$VLPcoh@fJ8D}}tO$13voj(dOInlp3ibn28bD*< zepfmMcpB}d0$}=T$?<1C{fK1`nfC6CC?sI!u08eTv&~A|xsyA!Dtv(3CW{WV6xk+x zQhCctRTlAJa_fM%$77gFvI=(5b%t(IsNP!LhBxZWyvgds!~P}SncmWf{l~oX@sAqs zjncDx`XQcm+yB732=9W!Ooj5$Hik$LzSbCw#nwcWRd!7XL7OYF!yqfgg(A@X*#F** zEBBRqH?H4RoRLz@g1NI7N-@qW%bBuBlBV%vd=GnzC7xroSu1{opR1Dc;~#(gm>>7k z(}zFeTuu}{l3IWkrCu6I(~T9QMNhI{NO_7T`1!HPDfOzyvBu4wK%`%&Td!1l0E?9) zh+AWd9w=|X-wU<8t@`Q_P)&U67J-oE!f+rP7e11aJ9YGzI1PwxLz)|lK=zG69&163 z*f<%cFacaBYG&;ZWQ*86R`KiicMCufw3 z>DWeUTllwPz58l4X>lp6xi23l?*K>X}fB#8pLbxLrEK!YRSk(5|XAzRK>k`*G4oYiwt7Hj!o z+QHLHna|{i)&rUjeyzq^KkpbxQ3j}@0^u9MHF`-Al#9H03DNhlfFlP3i)BD6g{vjcv{TS8; z9WT3dJDrWxCjU`Mw0k}=GH1lOS?zYsNn7^en59Z9{xfgzkpD8-`B=Wa{@%30GpQ#| zoV$4uZN!Ol=F2}|)lulxV-Z+iH+03cV7>hd7KE?{Ez7|3jxdu^EZAJv9YMZUT|5(` zppcKMY?G6v+DGr~ojq*U8dh(1uQpQe=Dp%;H12rs@wf|0tMB#?oq6Ts2wvDbwp@=k zb+^^&kX);A<;nqxjD1rn*wJ=$$bg}Dt$r1gx<08`Q!+{V_z z$VZ6`b^+3~-d!n?!ak(MgUZSze*4VCYYQ*)f5u)~DAg;>%$mO-bHjppnev7e{DI%X zyK`B5kypl_bD8tPCl@ZA-F^N`(77%2`z5T`7j!oEfDnADYZ6^>QOUM(ov4s8LNauw zrKS40BcySJ@R2X^MFT6>sPxvLDPtJlBF~jKI|qIkIwLW4xs*zI*CklTKUfF#EcG^M zG}B=Vdg+VOoeiVWfp7NnC8IJ{P6+n%wNMh-k2U*z`cCWE6C-%h<>O~0)J9C;`A-kt zVUd6EU-=WBck_aTxmS{<6OXdKg*B7`*S)9uXb5wJUPGa`N^4R}_}cmkOlMh~EH9ue zxY62&Ifny|D9(E$Gg|>praz=Du;w8eY865Y6$a4(Fcv6Z5hM-4{Gz+lr}o`Y;=tDV zBWC?>BEJ8@A)ZI`f}iuMUPkh#V-W$1gT%}_02mj zzD@V2JFjSMDE0(Yyel6?-3)Z2U*C&qV>~awN7}j(img@YpVVJi*gcTn$qRz`YwYt-mW&e0pSkz( z+ht?~+C)ElTN$i8+R{}G6R`kIwwgG?v{HQ@mDpW*=$GS+<#C+`9^EP#rR zz%P;u?Jrhb%sSLakt}S<&o_mgoNpgFXvm1eY{cL}Bkl7~%*j9Uu)`~x#~sO^1EAAS z56=F$XDh49&u`v&>&pl5z|b1+cb?KG{8vkA?;@yU7*j!kCYV{6z!@#P>sTYZF$6YfH)sx%;%eoa z6iZ=wAyS1ODi7||G_itLT;mG-!ZCg^ zu3?;4g~TSE2Un79>{;*5Vd);No#ULJNwuUotv%Apw(mxFzB%&BVM6Z2!o%^<@T-WB zmUo?tsXL*5E`q__Y8@d^gHTjG{KT2zdZ3CLaDZTPf{aF}8eT$l2d_XfJvumuEK=e2 z`z5A8tE1{RlEeadk-FvxC)pM@x89Lmf3$1&aOcr_qpe?Yt~4(^+(PNmdEf}?ury*& z#~$*A-KY2ie(u2oR-FYNQ&&0v*?IcRj8E%=U z$}Ufh)-4R*=RFBZ1&D-z(O^-7wMyM!VB~}IgW*l&2g8xb42DZlM9<>sp?ffOxWI$a zIwl{&;Fgjn6HZ6>vMDNdL_76CDp&PEDoa>N2MtomEwe2>`@BS5=1tR77JSZrNYc-28Cn* zYC)14+r2qp9)=cZMu%TyFm=wi1EeNPk_`#$lsZyM09A2(s5^1XYTr0 z)7DCK7a{gNs7r)DEY%NHrdg`cF?vMKg!K^V7Jc(>tC}{iD=c)Z6u@5Oo)j^-nDXi% zgQ41mSl0-|M)=Br>k|wN9Iu-IU|xiU^n#d?()nCA=oUjq^c&7^oHg_E@&#H-P9e-6xn|1c~V%&bR`4H z2g1Hgv0q$3{{m1=zkrbKT7ORc_HA`O%-Z|(PdSgx+q`3IE+2q)F#fzv#mm=tRdzmO zb|q&W?cO=~Dy0Z3Eoo`yu96n|S0}tloWE2&8vQ#5%{vVc$Y@Mffh2I`frh+Z9PuOCzi}y`8-z~A=@*2q_l@t;SbrQzVIHZ?> z1q6|bkJx>@N~E&^8+4ml(8k*NwLBHCx-ZFGwFrcIOTK;b)Ncw-)z^6~W7?#}f_rQ7 z)u@A{=?X!J>-%df#zmr@vc!1Liz`FEkg{^%gK~bz+9Fbp zw&4kpbTw^~_4Ki4cXQde_l9{#$o)Tkc3Aq12LyQy=4)7AzFLw8vA*9)!=C=GjN$E{ zagwTGs76c@d^krFD1wgq(VCEMrfh_J<+LZ$p}WJJFh-#Ld=d8Zg;>qUgYjVCsi_`% zZ6*i=SgmWm8==ah5qm)Rl_2yQyj^EhI0V@ zk4YU4=Uhx@r~lg)7SS!EnGu7aGb&ofsIsuPv`v~gN5u7A!4gCCo>U0Z^D)69!4iW+ zXbdTf7&gM#P*C;LQdGgB+yx1k@}^VLB1@>cCmo37l3h$7i9#^K1*q|jLEsy%@`@d+ zrtQg{dVBsOz><|A4FfFfTpC!@Of2`kAoZ48 zK5IC-XM$&j(l@b-l8jhsyP}iUA5p_flM*XIUX;@E2k@&Rs4`Dv5deP(iN{1=!Gu8& zAq8l$DFh*gNkc#&{A}paN>-Vn+a+uiB-!wH=*)t(_BHlsbQ7a#GrpMomVjQ^seT@B?`{a^~1VV4(3+cQ02Kyj9 z^+6>+p=bUNU$47gFMd5CwovROnbsjr!%tsJs{fWJnD!!6I4$Q6FTpS>4SL)cw$33u zBR$?zWtvumO-Im#ZC5_K?abP{BNq9rf7&kPh_rwXqt)YD|Kb>JYWjv zx18Veet6Y=aptOp(BB{Z^x3JqvbD5xyROJ(3-A@T>R2&Nq6$IJC4a5*5}MqGhO5Q6 zRgt!o zyf{4Rq z?4BwNHmev&LR=9^CcAbnCMuYWFd;5=zS6~|>Qh35OHk9?-3MeS!o&X7KHYtgH(TP9 ziGS31AIh825Ah7v7+xBa&_sy;Rlx!oXV4YN+W6V$hQQe_Q^CSk{$!=cSGl4W@*eXM(LD7K%0U3k$3p^C0MKr76C%W8FFbr=*+2l=_68+6N_BQ{S`TfQ63xD5| z%0l^rwOgbV=jYOpVXSx$@TT~>?op%=A>Yu&F+vF{`Zqmw%7FwiMX`=f4YkWsI0Sf6JCKse9*UZJ0MdYlB?KAKdU;^~Z-S z`tNsG2e!OQnWlB8EG!oum%Vyt#wQznKRWy6$yM2~TL7I=UO~K!rs`s5N5);w> z=6@c;Yv5gNcC1MMX^<0_4v3CPi13YzUdOgxyz@@yUgNHu;RUSb=u!9ichC#}IF;Aa zm$#S@5i+~m%Ju9D&*|7|;|f;Y3R$%p(6lDluNm{HN6p=)^vf}yaue>ABkhql6n4j- z0Dn~D$CXq;y+HC2HKaRq3e80>rKxLi$@RalUviW41T|zAHX`)0U4**eYGDB;9}!J! z0?0WelNm_`;Uh{j>kaYold>0NJH4_Qi)VlEk4yTcw_eDQF)!@KD~m3k-${=#{r4#L z9t2IOV6{P(Wd@a@uT6+1{e>w^>ZS_mzyHBMJVyRu5k2Uh;t11b|8Jh6e0N6n4F1(` zY$o4$lZ8yp{(zOa$v3c>zp?LmCHh~gE|uW*7=jKg*ZH^eE7C`ui+-1P1LG1)(M3a# zGeLcQhXU|IQUxtS^cSWBE%q4g5^ca!`~y+s_6+5w+1cDH8(qlI<~*qIE;2sCAE0m4>eR<; z-)Q1>Q*zJrjlyFm(j%$>=6BVpi`sNG-v-@=vUR9_L)rQ;8+5%77<30|ntW@WK4oht^F>i6fll(|RC#t#4yJrSuuMCLt@Rq_0X> zgJM;tE9kbd&8_P_^w#yRW26-(NYB{tJK22WG`=SL;oov29A`k`?{bAgni`;S5N0{R z(^;UMr}!d$38velYXGsHVmroHs|Hbr(Ol+Zp81|AcB+fH%=(OGA53Q6pXs@m<~0}5 zsAjx@u%P@A2b9jp#vOZcpt>I$e26$%51)tGUbKu z%A3=md;9Pn)`38-g~D>IZkevyYt$ss108^v0Uj$ui@a>+ndu~idHFmLOsvwK!G?r0 zM6xJ%ZLm2UuM{}SQYM$g3vc$27X@ALI19qMH_ ze(%uNUwzWEQFen42ftF@S~#h0eAR}N=M}y`W8&-am1<9%C3!L*mRyeI^UBfu3x4$h z|2cwpVB5>F(7%1Y{2{RL55HXX;1Pe>&+oE0O@2(7A@~q+23JcK(;YR*8MjU~a1F$Y zJ1{Lg+qF6D&+O^`TMNI2@aiUSf_ALP>VxMIoR*I&Z&-Y3T8d$2hDmyvz!N$*sik~` z@q@Oe2GE4S;*($(Q3eV!B*;f|CQdv1os@08J#AtRn;TJ(%Np`e{)~`9UA$|(DRzsP zyxWD=xl3Gp{e?-0>lfcB7r}92>oAjw;|m?x!fdu6=jjoB>+&XjhQ=~}%=SLM+sE>j z+h8$K`aggDe~K@7zAUWJLR&(H|JJ7vHQE8_hk&n#B~>1>`52!5*SLaC2Yu`Rzv2p- zK}nv1?w6NmPg$8m-(St)$^00e2MicFtPh0D0_n(xjVEPvZ{Pz5cY9})q}k2ZsaS6b zSk4qxuxU{Ro2aeEqn_guOV!tHGO=_QU7WeD5><`UbL+Ql&4Nj)V>y4WCg)p8yb%5{{3{Z_7S zIkMl%<ov6a%n04HR`THL_7WW&sx)dM8R(Pk$2S4c8ZD(Je|4%poWjD9=TX1MY z#`1mO_;rXIRL3p@vCk~kOT!;VL8Gzqq4yV(3 zVgKdppY6L&GsKW(kWYgX32WS24b*xe0#BoJqDd;5Y&5t1>aWFp{Y_IzRJ$ysGz>UH zVpzA>qM7Igmm<4E1gCTOuSI8=?|@;~bFL5R!eaS9{U_4JVOuajFE2K8(24_$?{D3c zvHpF5i}?k8b!Y}-lx2?U<-#?Fzr^!1VVQ)=g3cCmH`I6x-%x$%p?nz{%<3o~kK!4l zSXZSoq8|kmxlt4vlE zYRckjs$trt3qv_>Sa_H;a{sZg{4nCzu)Sfpq4{Aq@Q+#)MpOwSwhgOGKOPn~6(3fQ zg(3DA=qsl0K6h_{4mIF9Pt*?>}EA$nd!asZQQ@caqMVU$gfc7}UOe5|Pg4bS0rK-?NZzQM{L{N|fa z_$z#GNZ{Hn^^-fa^a_!Vuzmwgnk$OayH}H4(-P;n}lWpHfXdKIz4D8sp zhv+r}KhL%eyCodQ2QR^K2n$%3RHn#*uGXI0x}V5^Ve7Dwu|H!506cBDrw*jbUk2cC zDHcr%>FOIY2!27-{;w__g#w40Annw4DQ#e@cyDE2TKZwBgcGP#!|qs-6OxB+a2d-a zwUi4{NhNrYttP3ft3UA*UHhoV+*l(YdRE3)G&?9`noExH4MM47Z^i(%2J1jhkBa13 zq;_i!gID#-I)Q&_8o;__Nj6JVKIKnLV_20>(|7ICtmm~N4p5S&vcJrFHraH#^c1_& z?JA?}5iBN*Ns2sy#(!q>J=q-mKxW*t&-hvf8;QI}=(911@kUUmlt`-oF_^P@7Qob@ z%Y;%Zb|OJ|-KJO3@d|&)#1dtNfhmF~0?{cfZ7nQ{WxAf&#{6*N{arN@)e%Q8u)LAI zM$R}rdEg)ntABR=v#XuDbm?^EgcAGg+NAmOCM(g;u1%RcZ;BE{)SHf36ML|q^4NvV z(ErGEqlM1Z8QxSmW!i;)@l{)p*oE<0hq`w`P(jUG5TRXt4=H}uJzsqES(onTx8<^I z*0o))VL5%@?a~(^9%r26vlS~&IHar2=ze3y_m?g?ft1?n!p)3WS49bNAN<-+Rs~vBZSwD#+0PJOEv!#tVeaY1K?*Q?F`X&GQbR1Rx~oL(nv~!VO{$0x8HukD;+zQ!|LOu|G*K#%63R!aI``~=$19&hn>@Tqj7zD zPLXgXpA`LW%ff`4Sj&91ydj<^cvt7FSm1+W^%r_`Gr`r-_z4xRs=ih+H&ts4X%(>w zbl5UpNhlQKA;AzdG#4T)E~oaxJj1=NZz3$$`#JlmTRx zRp>>u0h+gh<+LgrYIaRxsseUfLFdg#yol6ODS8G@^(iZ?2_IOBKKVXSt#y4`Q+g@i z=LY@b;}h-!t(@tzmy%7Ce^PyrV%i_?QLb*PJ z1Xn|}??&!NU@k#KLi=h%<2AKRI9Z{!r8td(?T+~tedSWlvocDs1H1*4v#z_p;=Z{M z_5E)!522#hr)TZa6u0dgB=bTy06Rgb{<)uaZ2*qB`K$znJo1*JII^U{{m$2j?@h6^1-@d zu)>mvJ{Z@fpWgpwUFhuqixKNGL`P{|J}+NaoL%~TO!nk)M_EoLJNhXv!{VovF3n!y z7wCUs=jO3Dx^%(nK8M!-8&nH`l`}=7npludH4}RCrE*W)KHWbttIZ%uu#N!15bnhY zm4lpt0}V`nu=o%O6rw8NB7(xmf{^bKDYN-(4oe~erwL-O=O5?gNsT~jsf*m{X&as5 z>=18ibrkLtG(Uov>uu0H07#u_hF$427rWA5{9kuv@uhShAOQ|mV8kQ>5=SW>80djO z`4p%j{S>;I+;ElLWj8)_pp%CV{&I}E@ zY;|#F<$yvOua?&k#)$5DyJWu*0r~-&RKFh15yzzGM$l@lENuuqr;PY;q^GbI0E+Qg zUS#tlOu-4d(b!6CY+N)URO2Y^j(>rh!|rgDkxKorNB4kMoxJ+Ppgga+>t`sr^1Z(* z@$ri4%=BfU&ckx0Z!hv0Z2Zz0QnWK&8XG)m5ueOHxcIF!+c}Z_LN+)MLRPBH41*0m zMlGw^;K;{i4 z`Axx|eaoi@poi6A&kt7alip>GvA=^rPmjb|MnUhbRAaSDhS=gt24P+3XDJMA{e|gZ zqo4w!bQNGCgNPiHUi7pIA>wHYWCDIhl_!9uDdLpT#v8`CsR{)qYl^sxh@s(JUv}zr z+R`c3n)iZ=>%u1}AM^3tFD$PDMAMr;bMq| zIM8(oMev{t%z90l2|eKzWpYr;yZl#odGwi0FWEsiqrj%u1iW3rfp zs3UT~2r?wM)QT7;i(h`OO++ctCIWydV?zklry5#eRijjeqcZ&Y%Hfrf@u{TM_tqpU z33&s=$TYkx#VnQRXcYB^pz{G506@_L;2>bL5whL|PrAHr4nNN-qX=R8s2TJ4zc&*X z%?NKkanY8IiL*2Lr>kbOx`)%V_{gX0luARVWn5JIZ?5{vo*5^9lHVWLz-LO*_TCd` zGPYs@^RQ;fTU@R5NMgJN8jZD87c|OLt7$aC;=@5B)B_r6q-y{-W4u5kQSws}far>p z>Z+Juks=rs_g17BW5uZzk;O7jX>d^wrA5X}%zr0b91)H@T`gDq9NnnMmGH&}!fl&6 zoPW;ZzPR77>xIA0)CAR902Z<_d1S-7{Fha8S->TYY_ey=cG9Yy3!06q&|vS1y&Bn4 zw)X_tr0Uh0Zj>|Rayr?Hdr$d6V}@gDn4(EqNCgxn;8Cw$5gJ4nL2k{7MvewwK@HX# zs|JH^fKVt$Iin{aNL*&P=b(OxnP& zPTA-qz30D4G-}nOvI)=LTyrQ#ns6XB9q@C^4TpVt&3XcRZlX$te7Vr9`bmp`mj1%M zVP+GpW}q<*-BBP8&;ti%K!_a{0qo=isbOR^^GKN8zZ$DoFPu-_$?XMf?2PGh-SqKn zSFQHXCO`pVB^Vv9lmw!~k5*#9pbL4XQ`;1I(yNJ8W)&U2aeoaaj95tk(wtfc7O@s~ zC8W%{mb;ro2YHnXujR`xEaEedvRZxmNa25$Ug1%_YT84H{PV*9=YreGdSDAb}E6o=+n`dYNMRdSNAMNEmdU}A(62OGmC zi7rZr;U@bhDNi~7G5aU}2V>rMvTrf@*s4X@shc)0&t8&_{(sl_vgqkkG2NL(_h1#+ z*zmFAWB5{j$$pc0M)&L!&hOvocAeh~@7E`amApmrv1`#h@c04jEXMMVt2+!;$I(PC za*a%ZBRv8}AHe3|&_N|Wms*Cki~SjuCxtyQ5L4_*U@%?tu)!5nvrk(TomP?(x_+CT zopb5h!R-B)q{h9+j_#Y?YvhRD*;3rstWwnQVG;b|HQ$T;V!6RX!dcu^J|X z4$WSmmhcj}6;x{(1MZM*263cD1Pb703<3EaRSGEP@@j$O)p*PW-B-1E#GE7E*O6G@ zNQ~cC%kbu_zK%Bw9L?|_bv&dhUQ>h%mAyg8Lh0cxcbp6AH6TdqAsPhYQ2}syiBYdJ z(i_T^!g#CgqPj3Y z^}DMJ4npmM>L{21)jdlITrl9Qh6n;>stgE0H9SB_nhJv6FhlSMQVJX?@s6qmj;itd zsu*Zo)z^_w;7Ewy_lDuk6kkWf0!PDmtjp2VNP9iFXeK=fD=K)CD5>(_NZ(+4ZtnJi z?(u7TZOT(}x4+%(T}1G*+3=oiyLD^3vr6j^a;ujfIc@5&SDJtFKCfS2Uf=Z%<;^R{ z`Hj5GD_b-#ILvD1UCEd`nO~nYZ+!o|_xq2TJB39~p36>8jd;7{FrvGEo3ea%tGWXO z-6bvlifmT|;vKV8yM|RoE;r6aZ~q8_xx{t^F2t8Q_r5#uxl z1|hg1&BZ=Z@$ZO@-xpyZ0h}~=PSI`>{Kp6{a}nS_M0yKT__C6N2Tz+u zI&uu3r5r(&vWA<@uF;$W!y2__FNCd(Ca97?N{1v!8?*O)JMO}Qk00(`(s$O{v>ERs zs4%=di@g-R>dE{cw)b6l`9S#gE24^bG;EBe);iFB0Tze1MmXJ!1s$yR7&$s1CdDfL zPmu9i>dYeFv|AF6llf|6l*Bi6wBU|pUn5O(D`*ioDod|C)-Zg0#dwixqmH872af24UvyYEJ4v*DRmn_wiRj7}5^_aoH(JShJ4A#}1o1ZDggY z!{&{xHDpj;6I;-bp%uJ``^Ud7eGt~p5B-AsS%Z0dTPI+pONoBORv_AlsUZVH?9P54 zztPfqb<)Do^}&74&G>Ap{#oiuT!5Y7vvDbL2|><3TE4*!ScB`2UO36(@idH|WCyK# z@mE7(LnT=nSXx`&wG09%!O-N)@4o(q_hACO>btLQ@jF1(;%Qa9wG{6{B!sNbE(%JN(g& zHQo^x59ue4O2l1sAtUOi%EIn-A0prmXp<9yJ0!=UQ8Y`j2F2hGC0SWYOo)})t#L7O zoQy^UApv%o$CsSgqw(vd@F11*VlDaBXJfqh$Lt+>t;FiR$*&atCGp%wEVi=Wiu#|) zJ^WTQI9baZz1(^#8@*BAk;VN=P43m?4SHZ7`L25NOyOd`RgKO_wd1Tw9?zc#$iQjVP=0=Fz+_;zI=7brf(@@?$v1MP-@I!b^LiYXZZa7t5R54{jM|CNzPN{Ccrz8EDO;`EgBwu z0C;+wT2|{0g}ARiebt0#F&Pg+o$8QV9TuQUqJ~)Y^rc+C>Mi~uhscQD0FKY#F<@hX z+Kxmg)r1g89OH06>@Fl(DL-h~(4k#Mof?t7!*j&v?kRz9*XlR)otl#0{q!mQCcQev z`LFfz_=Sd9fpMey_wPk^!A6`W{|QR8 z>}-%LoyoSAwmrRXb+9)0`^(^JHL#9_Hj8(|l}%9)w=zfQ!oa%t!>&IoH{hN*>~Xe+ zxMsCz)%*AjWiq&mxgS!*6KBtU>+FdYQuofE%?e3h*>_7H2iuf1NWi+?4j*_Ihz`068@n0fM=H~1Ji-ov141K1JS8-j zfL$XpXFyI+hY96tKAau>gKuoJVnANrfE6uSLnIYiIVEZFqeo6;RGd?prN|;p$7)yO zZV-w$&@x$Dt?8Z%M$=7F_X26P?y!z#L!-xOCbco89;fuo)!`IH4fMt^ZxpW>$NDi( zEhJR{Gwo&DfK0|V-r*myad-LMnk)L|-$d4L z0ch^6PslXg>z5nn)PQx1|1dU{0YmbC+fobmhg6j>6cs>HU-sRq!tPoX5ZwU> zzhTGlOJMN_t9}BDPcw_e?o74(rrfWd-9aA%0nh^?5gOVMu_h`TdJ8#_fG}h;K=hZW z4xv7Z#u}B!1Z^sVT>p9P;ZItWPK5ttqY9(aSiQfikDE(Ji%5-r9C~72>`PaDDhm-d zAXbksg+b8J>Wz3|^nWwNacK2WCRAE18d|%QiBKs2WIbk4a^P31s!yJDBx|!)5G8#G zg%Z2zhp^=lX;YSO+{9 zL@@;+PxTZx2q};oASB|Y&jD-=wl!VBxMJd{!GUq~#h{=eE1^ckRiJkPo zzX(r@>hzRYKUX8lpg=njF$Cf0#8_l}l(p)@u}c>IF!j`$X5Dtot5zj%&yt1ewAMYj zPi8;4+4#n+)N2h^GXHI_pJU$Z_bh)k?_tS}%JFx5y`8fF|cHiP@5aJ3q=p(^4N4fRXU%S;lKOY_tw(s zjHN&O5ZzVuo;TtAm^BzH_rdHGC}(lWO*t1GJWfWeQ5RrQK;0QJR5JA_fZ_vaQ(I9G zR^eVv4Srub`GozMGtGZX;n(t}^z_03Ynj^7_rBkOKtXs6s zME@R27l|Igo!Gprl@rG2<&B)W^6>-3>fkk3&tl2^Yp+P@Ahq#{^1A=arOWIB);AL# z$|bBj80)jS>~mV52^?aw)ZN#}M;i>_6K`rmjkUTA&`8&sfOWzu;iqUzl`rKqZkOgb zjGDi_Y3&=K=r6!?&WB!K9zfyWfp0=tY5rRYKa~G5%RE@1IiNLVHm!!trf`&XA*nA% zaD)!hM(+y&PqCUN_EN_LQNZbfU{TfPyxi=wkN?DAn0cFypr?{^bJE2dyc#=~F+0Wi z7GzJ|qTj4X5z8otykCDcL_^eIB6mEYnYuiBc?rqg0)8V#;3oN@ij zkGICx``UR^`t;*n>yHPsw(OOz0jD;;GbM083*X2$@lS_zyZUdtB~_E;cOozS!~yV^ zimoGn-y7b38Q_M-sDT{rUr`W1N zH>n}oFF}DBnnshfv}hX+se>_p{@5-hlCWEmtH+O|qgVO8@#9ka2F^M&{F~n}RsQ4o z9}OEZmtPv5;V+fb9&Q_DMlC4aFg)qBwz@X{v!z49e^ zDHweygIs*>3S^t?PLq4!-mBIyj#?W+a!~xZSS>&inL!6&dvdiBSg<9??K#IqvOalv zA4=?&^D)2^Pkxq`E|pH7=J&vIOQaFbxxxJFr|_L`XXJhU#n+4^$7(dbrJm5isJ-xV zt=MI?nX>t&%juSaKwbpE^9q1fSws(b22UU$KLFNfJiU>RHz*SQoD7H1HkcL=GNPE0 z%pl4^yL?H26Q-Ux-)Hym>W}wqQFC&-viUcqKH<0acRMvXVEJo5&tEQSUKo5Z$jo>| z5s|5aYy=1&u@GNnbkR|~Uj=c(PlPu5Q+r>YiTEJJH(DqhpAWL^aK|@ZkeQ~?nTP=D zQ75;0f)2u5x9&93O$>Jnmq3GI(p1cKbB%Y?W+aYOAK)iyCOx#Kha&owz4Q=I4|OFr zlFUb=sQ}x+!0#lCNrg~eIxYpQi^4MUH`qw&%iLXSYtaz;`c0jQXdvhuDlK=7q3{2$ z^qq4mHi|vd4En#tX>U+V804^ELH+KT6rO3%Zqr@c^Dr!1+oD)Kd=KdccCGqgC;Ky{ zz4Tmc5^so&Ydh75Blc=w0@HMt4;`22$Ua_7M@2|uA zcJcYYT)g!Sc*s0?yr*m84bIR#d|c2~*CBcU**uBYaK3cnEJ_+{XyGe)jnK7QTe zba44VK1QjC(+WjLppvdm>8{p&x}W`jUvz21@K`KbR1d+KV{Ko{&^O{8DqJh?+>R=-0630=7`Ld6Ihf-I`Qi3kViDFFV?aT;iOn8 zc2_+_``S}>13!HOH#bdi;Jw!3r@I$3`YG9m9_X-VV`wFc&%MT5SiQwx(QNYe@-~-E z-a;uWeqXc6+e-)Vo0!l5>!&Y1Pd)A4Ru!%O9A1xJ^=q<%^q`w+VIoTam_6)ZW4shL zhoPE>1Qxo6L{%W5DP$MYZZJ0FO~;)#Zu5VOZnF3JhJ_n4=gXs{+E3g3dG<6$1XYq= zO`A3&lVNS>S!N?EI0UH2cU8NFdW7vyW7bGgiwmW5q+5&HJ%q(TO3ZwnN))KRTFEE0 zk%0$+6{Zzd0FpYv5BTvaW#y+6 z=nkK?czwo)k3RqGcNtr_%cSL#Hg0<}edvi_)=96X^GtGazh=B!vYcUwCvT8v;w-b|_Gv-;h~O9e-BF0y{7`|Wr#OUXHi0S>Ij>>Jnj z980Z(`MPKD+Ib4QT0c*{a7twrMdwOXKo|uLatemAGS zx~%+jnjiILJS=(H@ z!6|}oZLydP8yy`db`AJwn_Tj3SbxqR}!bLx*;(bKA0(~ZCgx)r|{yH;0w-1~K4ux2drfJzxv0~as z^l^6O*T4C%EbiKnj-MW7t9!K^*xsvuf^?Z3N|!dMX>$K|voJ-?{abo7+S z58vBQXYppyUHfp{rf5rF)nb_HVk-2FAb^=JNc4m$`54AK_5WCV5BMmmy?=Pl%?(EDdzh0jb(xWYmTPqtFEnp4lQL-%3+^K5;+7gi< z>Y*TZ+2KG%H8p{kGZ&Fo`gBX3ovq4^3P3%SpU%8+@aR8lN80X+7Xk3}$CQ8qt1>HO}ZvBe;UsU=FjJd3NwYm?#DmN3&?Hm99u;5HKvv z&YQzuGC5)hRF*nEL3xoMH>L3(=$<-qD$&K#H57T|$w~VUvZoXIWBN`$x>viBmOpLX zza}5cr#;(U{DUI{dxmb_T3AIwbe#fPQB8==C4xKrpL=yljW(OE#7+xNp!H`Tc^U zU$Xv}hwOSXM?H3&C6Ho5x(e20Ik;py>~y5GT`MnQ`}H-kc(N^6X`~5>H4%~>LAV3j zW}-I6LAr_KnuGiz4$S+S~h#7FuSl6VJ z!8_pby&01h(UfLp0`jXg<95_udF<-hZsat8hekZ)U&nVI^zjtML+M0!%)r;>!+ZCA z*fD?dUH(8ldK{}T0n#^RT33=2gsgt% znezavnA>%6bIz~xIiI{Pubsc{+QA+@7G4^Kkq;`qhx#$?5&hXh3pM5KTcV5&y}`V| zn$6#cGB#;H)VH`!a_xj#f}_E50~xZ8kuE?JkYDZFT@KSCnR@o^oBX#4H20JJQY#35QK-Yx3c{4!s5#@QnkO87P!P%OXG+_`Gz8b7%Dnd2 zXbA6>DVZ$}$y(m%Q;6-Ne+obdW|d80f-w=T7@?E~C+tV?ny6@A@> zb*YVdT>0nv8Lht4C~NiYUlcWj?+^s%TaOwYUA5swSLz5 zR(XkWgfWJrvi*pd~!T%$WEVG#Jh1>#>OAHfY610k3sf;P76` zv3~Z@Rx?*F96$IX?o&f8&05+?bG6<_(0aO$%@OFJro%vO!x>$iZ`bEx{Fd>m^L&*u8T-pJ;% zW@0ZIsHNrkxLZ7%SBgHL#~KNUh~pp01EoJP)?n#H%};n5C=w^@f@*C( zynv5mnepFD_AwFDp`+5uuE{Q6)h70b zBKVP~nFLQyMJ8wR&sjpI91pmi8_MS4cip5MInekW>fI|2L4Xw^oGcu_WIwP3{`oQ{ zbFLibQ$zVwwv1)rm-VI5%5b>E6vU;1M8b(tKBwBZSvwFEitYTm;iLczQ#m^Ibs|LRe+$Ilz>cf@uwrSCkF!AS;){*!g)SI z$i8Av{%ZGJO&bVktRuV8d|i*+T;Dl;eO{TqaQe{; zzkZxQV%oatN2f1@91;a$PzMy5s&&MI7FCfB>U(L)L=%<{V~dO+fs!pJTaL4o=$M2e zPGLy-L(PG(s4%$~O)M@Ewpr2GmzXZnFD;h;C}d=bs12t_Kh=qaM-oDuw%Oka|8*58 za)nxa1S#fPf-m*f#G*l{gW&`&LJ_-6725CzPbi2xi%E#J)k=z~Tq}Vk#oAuGg@5ny z)4czw&++dR+|*g`7WHHG`+XsYUF9G1wi74Hw}&eGa#rQ=GVDkC!&_N(7s+Z-;i^@u za*h=Ju!-cPov5s)VC|^a><%qf&+LnJg45_rXpwov5*qx>lG)}BDkOg9b*8}*Vdk@7 zyQT)aFk%zL1r=&BVM1PxNi@63V8$RYtB^<%vMG!R3uWqW9-kD9PVNp7EQ%T-6rTXs zF=!(>TW$PuohGrhS?dO)kGj~0fxZ~kzt7UFr?r;YV6<|@HSk7k>Wj|9q++4 z@g7_g@2iTtJzuER(8qyW*DTbM^b_2vPNDXaI3XZL{tbZGfj`CbpN{SyxaBkpar|CeE4ASu`YMI9vkxW)hb(O4?5N3L6?KPReJ0( zIb&qpL4I?8rJ*MD8UA~pI zojHk7V~{83<*(ewU!Nf#aJPT&tW5l=546=taD-TCi570Ml3FlVa5W-vvAzP=Vyzqj z))tesjWDwmNSYJKNyjL}-GCQFMMWh>ffq!ZcmZTmgybMt0!V80=)y2BB2Z$%hds0` z1Z93bMG-*!!()_J`7HI&_VI(mCQbT_e`nY5&yQ93WB7uwQKPp3zGw1TY?fT%%=Jo} zD?+y|HEq#!W@k}RZ^d3YF?|to#|Q^c00+y$HWLd9c0%7rv0DbIH`0QjnwmXDTHJFY zO9+x&dK}9*BE>o5qT?_f$Y@74MFj3U2xX9Qo$nyc*}bzL z&P~s*Sv~ttcC>cy>~8E%7lNFsP>(6fv79taUpI>o;Uz`j^d{>S>G_Dh6=S9eKE(<# zS!BrvlF)3iB?XAQ1WYm(6LWxO$FlHPMt+>+m}E4z!a=$GbK~GkFXV*$`6c`1JNK{b z@97)D-S500ht~L$|B$HU+CpA^eWP~BeYTW5Y&sj!bK^-L(M2-4_*bqPgpzRVQ57_qD+>L5Goxa7yrO) zE_vfhSJo!kr7*`Wmy!{~Gx--sFWzFdXm@S-atwd;+4*y<0vlBcCI4iBuOw|yZR2!( zuPoZL*9~u11jn-{S|kR59@r5!#SgNXUz8t$=FDT(IURNg3<_HeFG*Ahu3{oYbPch} zX#Ix_MNj9v7`ce&zk3b;YTPUAepdYCUN2&(a3rq=Adf|)w;1WGC4+>_Pl2fg`LguPNb;`FuDQm4VYFp=3 z_7H8nv8bkSvYJ#=t&Zq4lvgKFtLrCBl647Wb(P-}XI+xbSkz7% z^ecH+&eSPeHcp+qVR7rGP1>b4Y1o!IcQX5~oxEtzVnfg5_F?jcVQR(E%XckmIeYJ$ zW9qdV+@W>*L2c`~p=JtQbLSGfSFij-=xcx-MDHlWVU>!2$83lesz+IZ))+Ap0+5VY z1H-Y zGy1UHd6Tj~*gGQq%Wgwz#1B!z@7{~dit(>1oHYt~wA0%vYdifLhY(h&;wQ&6+5QowwpHjpG z_C*%?CvX}>z$!?B7=v*kCOBR#ef0R74;L)|Ywo=7<|=M!;<~f@`10&2a^$$)V{;i> znT67zOa55?GCwwYic)n7zsD+OkhP>!@gv(o+j=R1oiF}Eo{!g6(!aol9CDlz27Sn> z?~73cP(*AEEPiC~Xgee&$We&;T1CHM+daR5gWvd#;m#Mo8Gzrkwr#_2Vk93qOZ)~g z_To8vN`7MmZ;9V@!`R&7H?dNb=Qq)w-}El|P084>FT>%Dtcjk=L9ZS40*CGB`^I|bi{rDIgGEjH8hsf5V$%0ZH*H$HY?B(fS>f%PFa3OS z{p|1>ygeUX^8~-KoyGncc#}DEj&FAEx%T&$4THK5hlH@ZxSDzgc;f(lA(srHhZk|6 zw+VJ?j?h6MIi+&oPrc)E*Kw&0KC%7sIMhB5iz&Ur|4{b|EKC;0V!E3*P7N%{l-CV& zI6i?hG zFH!EnucH8W#NY*flzF*ZzNsLwPLq^-Meiuh0CF{Sl#Z1=t;lI$#Z? z49(H-Wr7sYTWHZZ*7orGXNzIrLJ&qFb(T%k9HI*cT%y7|1e`Xj8IVD%lt?mpHOP<* zqcTP)Kq+1?C*?^x1GEvdl00_dd(s; zeLZW&t%Yy?@@m@s6(6wDf2ZwOIM!9$zs%SbY4dm3{=H+~xD!dfrC(p3ws5-~v=aWd zWBCVU)`Y49PW8L#^4Wjuon28?`VM0 zWvDF^E;Z6*Prf}tk3f8bV~fpzd&J`PfD^catGK>I2*KW<4g5I zUWi$rzokK^GL`Eb8S&Pxur~wpZDseI3}5E|CGdR^E2H`=4>5*n=tLT+M=C-hBOjHL zs0AsIn!qCiz%2s6AkD59#UpZ(++~X62IJJNr1VB?A{hZ=af4Xgz~s~QIuFQZYKm1P z)w)_CYMa6cj2){J5kZ7H9JC=JA)cxjI!Zo`DEV}7jX6y_q~tVhKY#F$dF`8SX`b42 zP7PLLHa=Y4JZ;`!MxW-Sbik*|yju0-*!EGgPL7J|7$rAvaHm#%IksKQtanC5wU5O) z;dPF*Uim`(1om$@VM1XSFhLq*5J*_iTXBS{gH$D_>02mELBv7{1wq`v8L4McC@HPb zR+TT@zbxxBazFE54G$Dw+h^h#erpvw%(5QVcWo}-!tC|0Y$+z*^0Fi=Z>SAng^8B> zHI`ml2f}xtc#V4^MG+C82+D1!G=k=UN$Ryy;3-gUs%iLbC25@Zw_mv@7{3)X;~BpN zOjH93-vpho!B0?E^U>`zuzDF?um5S`C*EwANI2Jg#0#cQ>FK^IJFyg#xh!-EZ2fINB-*S zCTeGlT+nSgf$RW{0yb#u4S6j?N#4TWlgvz3H#1Y7%ue%0>@@9c&*DDpHR(R+V6@4H zOg~f;4>eZPRM@t~y=uJZ^}U`O)=JJ#-O_5*%${v~9HcP=NYp=pz41~Cc&S555!D)m zE~mUNu(~XIY59n%V4(Wm+ALz9EZA+##gcv_0)dTh46$A8x=>_EF9P0~2tIKZQ`8cP zY#^l6=L8}ejOJdtfI3~Uo&?8WaW3!Od+nX{y;0LMCJy`RE4g(+fwDKN=i$o@H`E+4 zqIXtNXRJJBk5@PljbUUn*f5Ub|04G6nF0;9uVC%k>E;p68>8Yb6gO^lLk&YSdc zij^|PX<2un0vM|+remB4mSmh%g{Dx|IH`h@Dzxr2(O8^Ng9~vYln^?JcIL;J2tnmS zk|mzn7wQ-F&mBSX9VV+=0gWYq-x_=L!`{6Gdm1FNrX z3yUyj|H3)|HR5X2cM%DuVpDj*tIdo=P<43XeNlOHb;}k ziJe$0K|Zn7Neh5p>cH*>l$06GOb?q#`I}Dr==SAi~6V4o%yv(Fa&G@ zi|4V2lh2Ci6kr2cBNb(%s$f`YRU`{SeM6cMna|0M6-V)3gfjXIY!J2Vsh20ht<|pS zgt;e94DR2xXH?~i1#k2pGX+BMF46MO z*aTh~p4(93_tF z;y6(pr;6iDahxlT3&n9MB)o>Y^3wt^(1L6OGg>Rvv?)_@m^~4Pne}k+YuJKDisDMb z2uFB;zz^8ugy5s4i7=VGw8Z=|4sWc77M?an{0KpOC7%+*s%$!ikOYr!l|(|M7Yb1e zKEJl<+lJ2k1||A?UPEWzh{8Nf60^n9G;rpPEX*5Pm^ZL6uTdd@Ew4#oUJGYl-@?3} zg?U{I^V$^Vrq6XC4-7iZgFsVct|{ z9+qr|GjCC0-b`oS(!#vi&b&-eINc4?x^GKC?|ABR{f!VfSeqZru-^%PFZ zaucV)s5S(Z4~+qX83L4I!%>zMz|X=Vz}HR)B}LHlCzL|Z`%wB8`EkrJ*5Z}Q(F=b# zUX_>L7&v&AJY(pfS#q-z{l|8yS-X&Dr8H@rlG3zsYo(y)unt{E^%`2G&fjM<&f1>4 zFy^mOEa|N6XI5uSQO_Ae`d?wC-91>iyC>8qzmoSSdQGU;pjXj@4DruVX^i;CKJGtx zQt#LMOqvBFS^9)U(U$5%+J}Q zScUPscaP`a?Jhd9yJH7cNf|Hx{ashTzj8LMN=5!r(TvAM;eXH2Um%J0bbsRb)MuQ~ zd81LW<2k9r!Qf!0TJ4}39Eqb}aD-Zo+_&(JLw%_T;6}YfgqlWHRH~8PR~HUroE~#u zfFvwQ&}*V9ig!^^H+&Tv($+*-Y;2wbP8fYhQ6D=3F$msQP^-+x*v}u{UlliP0(J7B*jb!Bpzw%=%k6HY@Fg;h;Mkm>oc@bOfx z#qQ^R#s-AQ-CmmYI!SA3#gF7%%o~w*QY%f-JNZJRG%5iK?rc29Fh~$rcAD-FdSY6U zr|~g?DzAnUcad{*GM8*%>z8Ea$hnK>sY~Xn?3K6n@7ug=>;8SYj#GyYzIPa7>RkL- zS*PYgYR#mhYg)Mjr~0O)4W69^KTm=zU7oH$H6A0 zHf}n1W7fz~OMn%9i+@wz#@NH*1*k3!(nl|BzQ*XiT)%2zUe!eHR#hZGMB!jgjMS8> z6vn3omaR(U8!~{&Qv_w#%+bYi3u0%7*8_MX7;&ru847V~ui3%>-1|)0l&@Gfco~OxOU_f{m!m0_P2C}}*&2z(&tiAf{V zd;*1&1vTDmK7^^}Tn*wsChI7M1CO?yOdG^R1fV22r5FWt2u!4Ao!aq=RPo~Nz}jot z@4s~G8nW7eQBZBF!}>ocaRD>o>|@?UE7>HfU0pM2bgHDW35&)PM9Zt=ExpUua5 z&BAQXVZAD#)>S!E_K{d3V;0_mZzy49UM~j|<+vS*7H6)_LE%{>>%%2LzLFBDj@F43 zfY4CzF{NZelzX5HZ$M1PwpZj`?uV5Jj63$}t+RXY255n^`lnA`I&N6gDsnS9Hwam1qO+>(;#%dAopJN)0mH8T-2BzT8?~D zixvu%hDf9qAil;1kX8)6I02@Mm|%yJbl^aN`x#j=9Oc)+59oHk5j_jPF9qN zRc((|-2|MAm$I~IQ;$Re4#p^qlqHP?iU?WwUEZZ~YzNr8sML1o7Q2r^Zik{+BE5KO zv;j2Cc63Y-zFq8!xw}nRWkGSv3XW$DI;5!x8QDYgb%@eC+JOF`{EPTHCYJS`GU1Jp z>HTNA{&n!g7lV3y^3&;e?z-lTOrObr&XCs+=+v=qk9JEB9oUe%sB+^E*A*OGlRBV( zk27RLX^)+_jJcNq-|{u(s|Xrt%-zek%pOJXEyXGD0>snoriSEO3JvHa+EfqUB0=9e z31sVCF51NQ4(T<%_vCp6kIo#qF7XFiN#gpV* zbvY1gc-;R* z+}~g7_>B7txxtv8asQHuldPgYOtXt;!gWR7Pt6yJHO2_Q7wG?5@^dWeCV!o+y~#h} zpWQ^pz_>4woO{rH(tVg6=dZ|ZWQcDJ^OS54FrpCT6bFWqET#`kY_%~KVRJD~gr(0o z@fsp%dyGOm8WYhAnq7Yh5HDDuh-8Ed(g7nx&qC^bdB8vDuk8;5N}WH(Z|vtqjPZwW z^G}bm__W5##G?82)09C^#wn|9wxSUjB*qKBq}tKELzaPBc1TEjv}nwO1Jq53o?S~W zSGF8$e4Z!2&66*%xZXXL5l_bH_a9&Uo9c(R!SFMwruteIo@rSRW24LlOib3(%mTqd zI>`!F{T_dK{ZHj+*1S1cYG%>HBVT@WLNQ@Wn@}VVV*RW z+JN^wm>{k8d^}A!_#h9sd4`LRQ$A517L^jx0F#;l!@mNCSEf34|6nxUG7WO1@Spn% zTM2|Gvr_<~p$Wf9M~Nm)>3G%gy;z|DKUSXs-|^Ksn-8smUeMN{}J8NnsiMYw6Mp@-B;ckJQiW{GAt0( z12t0$fYvdtNMmJ%ZcM># z9^MoycjrI3*q%>*xW}T;yTAYQ^+oe%{6Ib zLR!E`)z0aIKbyw?uG8XserM*7Ywoh}qx&|j+NbW%*|0~B+wn(>&0{VEpoG28%e$Gf zn7_~ewx7R#&DHt6&px`~S?}^#Z>qSGs`=>^S71OXhE`N@E=*ZX$u!l_1T+4{8u~1So*D@+3h62oyyVjZ0bX_X=zI`{S%K~P=!=O6FzA6Uel zpIE4Tbl>_l2lBEv?3Uw@r}-hP$s8}E+FWg3SZq6g{l>YbXFkR1Atwva+7+wkE4`wF zr=Up&cv{Ga!N&y@8$;G)8B_3?RpE&Vi3=_EFX|C?U6e^|-S3qzm2x=(ty(#Ff zJMY1QaZ_j9n07O{ zRZ+1kJKMMq@G27#M4pU63+h|e)=N4G-;A(tR8b}6OG7Xxz4(bUKmjG}AfgkT0yDd@ z(&d`XGQZ<7GW$k$EaMB*O!p_t*?RZiZZa=O)j(a_VH82AmT!AHlgL+V9?*N3s|^{1yhV$lu%M4MZOZnB2I&Utcph)?+b!VI4178e?<4z=h5Ag-MQ9$i!G+ z*Lx}gMeu4$>{Qyg(ZnFwy-W6CfA9b`b1l!I9cxw`s(fV|2VbBkhFh3FjOSH?!JEPX zHCeAx1CCt^PbQI_j2@=g3Nq=KDo5p25)q_0!XsA6X%0UD*c;qiwAwS}rR)9+iV!9b zhLB}EJp9Uz)mzV(F!3|HR~Ou}F!9;@oS%Og{@%h8Mm~Fo^P6u%-&;k@9C_7{ckTl& zq9sr5f01Nl%u~p6G|wQ1FcE@Z2bM(0l5-MLzB$9ehXU6r;uGQPCeszgGl<^tF{p}y z7zQM;B`1sAwRrGLW2O{NoF9JGrrY>10RqNnd?6sm)}0yoW+4^DugwR7+!My=~|K7J}*p zbHK9+yfFp=&&oXaNtgVDMN&H)l2bW?Oy;JhN+4S!I{VN-KhYuGP!si`@}=8zhrg$Jo6`j%Q4moXO0{7E-5*~z@zDMoEx;6}JX zfd@WOsR{GHh-Z|NUeW9U1Qhx+EOLXvlgx%uXd1xB{~iY^kKsq;twj^rtNeiSnmdc7 z$n|)iwaeL2c4YZl-iKfoa+)2_4+hPsXvC>NMb>E%rh1ccRCot{0%xf?be%v*{9U zKr`6FEem=WNo1n5icZ>shKtgHAQ4U*64Y$ST0<1P;`|qL@?XAl-Q|BU=MOIK!y2vI zuGHC)le0rD9q{G0%|< zAWqofsR&0@Nd#FKLp0180>Yxfbwx=sEV5aN0CmPtQQXjM^b8g`n8b8Y705{GhY*6m z?W9^%?w&LZcu^>*PCmYH=KkCb`!Z+pmk%6d<$w5*MQVq6!`!G_@5diJb^2(`)mzcI z*}1G<#a~%0zxgPVU)ex)L*t8owpGWPmz73qrH%fLPgB+s>%K8NPzjO?OeCCw$7~3o zmkA4~q6o;JIk_3oZUQSJ_~g?K7R(dI{v?mN7JI@L^9{-(zAAge$KT$$ojG&*tlTv& zm?75kPhTuNd-7!Vs7Z4s*FKV{%Jw}BF`S#ekKJ{ zD=j{qmRA~r>1JvL-nVpmX{5{4Kr3+leTF3;1PY%?F3>6}l*Ebo2#JxJ5YUt$G79|} zQxq2eWVJ?E(TBJBgQ-8{T>W>bD`(+GoGF?rD)td=HL_bo?AFtB70_nrD0zrJGZ`}TumGkC zT3T3$SeCFvvm#4swn^&4{9q&?X){oE#3sW-4A(|5=7w^i`p(&({Ob&_#(M|(x67Vd zUwxtPtA1fhAd5SF+g+c9kDWVb92>p;f~-8`gMRt*b+(^Ss;Z1Nx-v zb^?bl<{EVv5}9ZsK`ZGdA_#|8fm9XdnRx;!lrEYmEr9zN7zAVCrEu>k6H(8GpmYXS(E;F20@(g39WzJTfeGK6rj9aD{%FBGw78 ziBK$^(^@dy-~a^SCeoxS{(>Q(cnee;^R5HPO}j3(SvMuoCNlxpNXS-JyZ5u;5B~N2 zIbKci=Vxed`7Pz&{Px-H+b+s9Sh1M7v>gNkx)K*2zM?k=0pH{NE|yA^a})o=3+Y~fw@C-4shawqEN+G+T7Ywj zQPTn%Pl@pu1!1Eid)Q=hs9MJbt{AW_uen;KcUpk1KRx8L`5u19wq0>-{8ol8#iUAz z;`PUff~DpfGx>}x{NUNLJ@cVmdCDS)+8GR8mmO%EfJOpjiG1`t3;TrkuAH_fJ}u1N z^TpQDeDDpq#w7WZqE}kK>Cb#t+Fq=$Y{FO;gNBhm&mVOyeLYpU{zt0sCG=*zCMre} ztY}C?JQTFP`P*m!lm=Q~kVDkSL+lyiMkVEzSb>%nubBl*EGuBBZ(4v}06hRTJ1=IQrrA6*Ct_yV zh5woJnTH`Lxz6vz{Amqr=O3SSv4v>S1H>U-r}I0p^7hy9{2-~D=I?>a|8eClR*L_; z4P@b?+EwPw5QDj}KV-+__x16Z_e2azhV4aCZ(vO1Eknl#5u-<3Dcr+@E#$+Hw#nXM z5;`?MhmbNUh}I&0l3~^=YUzR|!a>1`OY2NH7G-vCe1Dc#<#`mBIrqJx{8bVuk%T%L z92lYtPwBdqpCB<3To}12 zi{>K&rbw&7;4SK;MUMmWi@{@?YkEcw@j>+=!NElm1W(gt2Qg~Uqm;9Jo*_CgsSUK5 z@Fv~A6qks0C&{rA=HS+H%= zx2vxKqbJW9bKI44;LP~h$3Nn?9=^Wy?*$(mr?oHs%^r^Vkq8RkX-dY;i|j)ehWEn1 zSb2W`H#s0acjy*PhL7zQk5OtIQrR@nL4S;wq}Tv-$Y7p2kVFS9wAf(T*a_hb2l+MA zepmz$90v=N)zal*)R1pPWy)Ief^S{ld?P<`pZr!A*s@{V$67e0*&1x67_~Rq+JY+<1DOFl0+PIw4)Fc2h-0$0YLbr#eY8&6Izu6G$xYap zjk|{N43E?$ci_#9$>@R??I%fv1XW?uWX)gTfWDs=hH4>qmI(;OL(slpqJ7hl?1){H zXxAi|4?Hg!WQsx@s*Y#V9HQzJwD&DXe;{Coqu?p%~)P| zp-#>3*tNsQ-apcNf_ud`NBR#xZwss6fW5-1mSYNgZsVDYF+bk%(by{q_n69yAJpYv zXd$3GS0}&0D%Rb%m7jt108gBV;EQJ;0c;&|ywse34LJxZ6!jbe9K-_~GXMupX`}{Z z!c4rKe=Y91|BQ`>X$R4GWVq4%b$_1XFB~B-RG1`LEl~1U83}GdIHBoSBlKR}wQKy- zF?u|O2^2H}^~9)czhl%vuvq(ArArH8|6d4{7JoEF=lT=UJtbo5wkMKzo9`!?pRb3} zX|>!!7c$A>RJ4ukJSDRK)7?BRFe$Y2r(sfa>MQ2_N4HGa5JE}rwsgyc{T%pDwe_G1 z3>dch#3jWwWa#Q4gP;t=_@6)Hcc}m^nsTR3^8f7@|4L8_giauIS?ZSg-=p~q_9FNb z5h_)0zJzdEli3Mz;UJqEeOu61j5wIpXfR096;i-sYtmiroHC%O1H+X%=`k;wcR zsfAY-xPyo_O7kJ^X4x?VU9}iJ{2rC)-lZaRCJ7-A-r^V$RSimM4$Fht-qdZ!)IhSd z=pacAGllz}8fGep5Tl-%%A3XfgB{1#_8Dwj@YAxtn6qgA>7#8Iq`lPO*qW@vc6sf7 zC#&>_|M^|LCze|I^BepgchAm074_VT=MvT6_qLVavIjHl4e56nW>^~5d}tZMnon9r zglC3gQpV;R%J_fnD`yVyKzzQb5F5CFSD+Pr<-{%|z^V;RnHqx1E&t7`$a8;Q`4|69 z>2Uh!%H=OLIko7`gLd~2Y zi7|;<%E<@aCzQG}-<|(q(Wl+^HkjhFEgH9Q#p3z1fQJ+Kdgr+%J5N6ULidf`1`ZwG zXE@@zMNW+;LM{vz`3a^NxxhlQ!WtT&h2a^(y2Z&*R>b2>LqQYpyRyXZ%BGhken&4E z`6iP!DTG!}kr2+o5QJC`g)kY0_)r49`1q$H>bSacm#=$*-`kmQ?)8xu`yw{+X(u_4 zJaH)Rlrr(mzJn*QTSoLqf~08`Og*ba*0cd_UQ%tZAZ+Y*lm)S)vLg`O@ujaVvE;lPBuAzwCyno!Qa=@bRUo~p|lM6oE8OJWyw3uKW}4(CT1)WK!K6M`tE zxDufTKn(X1yn*2{SPMNQ1wyr6RoN1if|$BBe6+%{_(;DvJu;QNPcc9OYl6a4G8Jh%B*{*h%%3H}YS6L%Ynir$Xp%1C zqsbr*+Yd;@Gs?6X?qw(|WJ6^r(>B`uk^H=S#R*pXos-#X-`(2#wNAbJb?nfOA2wn} z-&rOrs|${;Ps=%Sbc3zi@L@eWbRRmTchO-}FsV#_E_E>IAysyquSt4GL&JF~Fw0mC zLsHgCmlEW!^gqZ$i=QTLI- z5lcWpe`KnGWrJ#{dcuceW8`g|7o5UBcJ18V?@scssFFOKm~-Z)^Sg%*9m?sJBd1;6 zwf&0P?ZKq}1E&B#UPduIx&~8qe3ORi*#b$wQNSl&z9AeEN(L=%-LC1JVaoxR#G23zqWEQuG-L z)y$ZoS1B;1nw5-`i~yiyP?UZAN$;^_oMA6S##yakhnzNIL@r-sXOp+^xwnE@wb{FO z50>qaVq+qS3iZG$@5Cs|O9S;W2wB@0gP~lJZ&&p#NyT>rh(s}@@0BeXl4f&=Y&2LX z^z^;ZlJAHPQ;`ypzULr+zMhYW^gUyp9qBdM*L-W~CMmPBHqW2D)4tyCjV7(yr?jrm z=CBoW_f%LkdD@#Z1`TM_{N;Aluzp=I^1Vt$*uJ9Bi$b8d5NM3C8!UztS5`6-Qc7_ot^B#fvf zgF$ksk;x>IOXcl+>kih7*Oy1g$K9{UD`$glreZZV0b4>L>pdq;*Y7U0d*kjxpC$=9 z&Mr#k#w8xP6?Z?b7X%dIi{CPX@1^n{3Y7rBWOs`&3>sami->+vb$U6SJq!$X?X`HGwzgMeI+XPDHrV z=0Jo^Ld}vyYxd_WgC=BdePhuEg^x>KGk0q5s;Ld?w@qP5fdwLft)oh3f8wNZ>|hGX)+9)}r{k=gQMWwLL}Js5X{I+sESSAYiPA zE(#>2IxG%|J0RhW9I1{zjxi3km(JmiG?G*0J~UlKL`jK_gM)xEiHNjImHJ3yq?wWr zE_6bDDU0fCWr+EOnu=Dy3|hA26k|d~X@{O}E;5Rf^)xEse`Wda+#EZ5V5{Z>`n6~^ zuyd`r*cvrrE7!D-J@#pfe!W|_?AiO3*qSfK#n-HjnSD zCBdjHSOt|xEs`MuxieV_lJ(WKYr=3A&VDZU##rxG^}j@9lgV=Hcpe->a0#%`mUeSadFke zlxZD?pYzYX9QNd|a=nsMx{Ym{(nOZGcbqz=xMDrKX4uqX1w-yDSn8a1cVR8(54wI29IyAYK5*jPI^MoQi z9;pV(?2-KUQ{R7kmidmXls7yh&;9y}1s}DFTrpz)>IX={F8?ry8V~d0U)y^^_}g2(4q%uWpphXRoPXK7A=%Bqdcy~zwMU>}E=fkUI}0_z-xj%THed>Ao4qYRZ8-!q}bJ3fc*GJ#NHUS(bOduk}`>a2o- z8La-7d_LR%C40pE?NZS)G%pNwAM~u1`WS2F?RsX}WT9giYh~GS!y}?eV#hU`{^BcA zz%d5XYOt}VPL+}eJaCVY-}yy8>~4d_m@F@F*LR202(TK;19bbgW>NhgRs$7%33u%J zi=UB-Y~B!-rcyl9;@@~RR{TAsy4cGUz0Tg|0dAM!*^L5)_Jen!l_u*RHgJkC59C|S zvWA6>L`Abd7t)u>kWCfb$O#Q%hB_1|Zls6dE@s2tda_jEm-ycsw-ua!=ct-F@6S!` ziuer#hHouA)%eu=SQ8^QHBxG?DJDCR#iD80N=Q+G{tq*c#YSg|!6bu=h{Jwnq^V9u zpA~1ilWod=Mu_Q^cZR=n4I!qA;BEJ@a)E+sjL zBJShG9PX?61PNyu*3((S8ECaFikMgX(jzMwR+}0|R~AxsLhNF;=EJZ1bR97Mi%UrF zw~w20kNWzd9qP%<4fK_cJ+!&+Fg$Y-Z<^%*FvoXsORd z;O5g>W(gN3G1FI1=k4R)}ea4RMliaXT(ii6? zxoDeuf?u_-1YVVq)_IHKYQ?CGtEE$UTz#bPdcoL;#$%2B_0D6B!c)WX6gXVV zU|wZP=0*H7JVA(j1VsrD0QuFvEs`=Sg~cXz>f0jmjq0&AGWQ;tWSgEctf_CU`0zF( z+SH2Y-_SmcR=-iZ+E+v4@gwQnDF16i?4?L1kRXiG7zzi;4$Hc!ec_9>~Z5NouwoL$pWP6YbECWQ7?U&DC9 zrEvmIZL~B;f^1Q?L>r!{iXsWd=)40%2C|6$aTHFY0W^LZu3=3MOvI;wQGtnpjRI2x z`vd~o17I$2ko#E+3nY_>ca*3}OJpKhx7;|C7JJT}+s&LOPO>KTGi|fxr!-*d_h1(G zX>-(aG0l2*ZC$^qqk(7qE$km-{NhoTqCqT#YAZ7jEQKnUC=#PX2rrC zYUG!S9wQhbEOQulKvY0tK%;=vfIa~jHxk>CXop^LWSKLeD-7Earc-!c_2QX;gUYp% z1y)*t*E6x_=bY)=q|WH)D%5G$w{g{J@lmza?>BCIc<1HbEnlb*+Nghv=OaOPNJE*2 zZch&6-zono-^r_}K>M(yI3Z#|go?;lU6g{?)OMEF5J`Cd|4=7=J^mAQf}<`Npc!0( z#YTx9LSGYg>brK^U<+{)qq{9%b||2ok*GB3?a=uT82c}@Q-Gg`z66!fmpSKs)bG%~Y0dhMm*HzplQZR9+cCw#E&#=Hz`q1%62cjYZB7`XD59;7oP(~EZ+p5@ zdan~&3SB30u1=sAg9l^aSnV%`7BDxpVOr~en!!x&w zdm-)tWAofg*ny0DrQ%+jX#8@VxTdWBJYmhDdx5Zn`%oGa-LbX&ro38QUD^C(uRvdx zt^+jBK&(Oq^v$UV>8X?{vq$J*bX!urywX!CfpM^knWFhYe9VbDM2m!Pz>fM1=nao} zf;ft56Nx%9Dhq{>Z7vZu?un|tc+=!?_0dlNmD*o%(wMwM~ z`K*+9s8OZVN|3mMDn;SN8dYA|j($?!nW>(cIUJsuQ8Qp$#b*4wyyN`FE@eH7Jp6#g zR613$V8h{`{n(_B=8Zi}@s&X*`;Em6uRs4KYk%a<7ps@@o4>c%$NyYfuLf(e9-Ag~ zvtXfbgj3xNZ%&5c4HTlIu}5Y}+ay|(ozvnHCs9xhfut>~h!n-nP=Z^m2KOqfo3Fmj z-@EeDt-I*7^zR>SdHeX;i!T@Q)A_P3^Y2#pr#L?CK&7AN>j!9=OMx{ z%A*4avUnQssNwW2Mi+_7yFaKtTyp6@| zeVavZW$%u@Fn!Ybu`J`#lYquG-#$JuQoGNZQQ#3Rb_E zR(3|QD#lMW)lua|R8%8w9qSpt7pVyP1_}y`ci|v{Ps5GEmmpYeirkVn9YR@V>Tc2ecjJY{-aa@YjM8bRhD-0 zIM4flZDlNLdGUr?-Wf4CI3)QJq;aba*^tEz;DF!z8D+;r=!U2_cFDz;%YISHjwQP; z6LmmhoEoie{zvUKu|7}V+>*VA+G~JUk|~s6Vg16YnM<&NR8f!^a*P=g{Dqy6iiW~i zMK%tkk4G0RVD9OD%JjigR=Xx$pK<(~b9}x$X%4$Iu2WK{k;`6Be|O}uocu$aVgZ8q zR^@BVz6{y?{q^J@VXnX!%_az#XEd+RpR_=;(ggduDUv}e6QS2)6Nz02)rD?~z7WYo zy(lCKj{fi6|mi8^bT73C>?d|!8K6RaHAiVq|%lvupZ~n!QC0#FX-@APX!Q9LI zh`JeLB+rhg28!S*#xh#WD~4I#Y_xzSGf#+tz-cTVd^@DeQ<%A4O_2IHQ#HXa&z&o9 zSCDU9a5s?sBG+W|qpbBPHKxc{E=s~$4dRz6Z$^5~nXE>wInAH~_@Y@e=AE-C`qqXmDUoiajN^HDR zW-lM#SeE&tZ|?JN$1WLkZClondQ?>|g&$EUlFANDCCQr*Qm{qZS(9fQwiVBIk@g4! z`S0${1@dd|^2#nX_VG$vBh>1Ur8(;7@^yQm6afD^ddC}G#{Vxe44hcd|3vde=tyW! zoEX+9EHw-|5skwm z^)R}{6cq5aLd$^V#6AlC^-!sTv`GsWwO;ZN>*VL5f)?bJbql^NIXFSD7h@mg9>ACB6`xoSv}T1h zAC~=*PafR;8Ks|`-jYvF825Adq5y|7#8(u4BB+>+4%dy;EubEiQEd|WbOOqRBtgiD z0wreCp)E|rrXXfWvC%sVGk|yzZDs~Gh&u2Op&6Kn?GGikE2u~)z92Fpyk6{9{>|`- zN3R#ZetqseW|LR&KMrh~5I^PiuuYY=teBaz_1%Y`4`X59Zuofyzsdi6e3KXKZ?LQ; zE9%){)wy$L_O8B!9zRET8#V;JWJuN_#i*`l0ByYfPE1K#_IB+2@GE7jOzcDZeJZ^tl$xC$wE94Jbtx)fKm5A*C7E2WgUP~l|0vCT1o|?W@rwJClnvTo()3h6T7rQ zdd9f~F_57%3hteWdwaA3vGy=}(|n5`^KPs=?hr4ouuI!6`eEdr-{HRWJLs&%KP!KW zs3K3FWlK1b;aL$QkAjCQ3et{QZPm&~kwS)`vO`g26A@09=i}|yhqACx)e$9Rkuocn zu*pyWxdIcn;O*Y1xde8mL)U&|7cS`ZOZx#IsmIv4OC!z<;=k@b^6BA;Ll4)QI-q~& zMJ(ZE{>W{YA6>uExj#P=v~~WztI%3xX%cpM5ir&t>s?=8aqk{m6cz|)=HduYRZJ2n z2%=MpmJ~$1MN6TUN_@%cBK{+<#Q()uS@t#l3bfqyntWvax_lWKuXp)5)_{eDu`u>B zKg;h0T>kd~`e#J~dQLEiXp4D7o5WC63RFGZ%~%DC+FGg_oa34ir#c0926wS+5Jbo)K!bM?OB#s*m45Eh1J~B2N7FhVTD(;b*;KS- z^&57{eP#*&h!;B!-Ppsc@BNG*u_qw$KKy?bq&AvlsxBsA(D39K61SP|l6a0-TBopM zTGNa`$UseN1)_{C_4LyLO)m^V#l+;s16KLu*(RMGeTzSt@a4)Q4}9``vW8}@&z&== zd+%KXP(~~|_wV^%>>sw^gLh+2T*5l{z&d05px?mO;fXHIE2n$+JbmoM(i#KyM#RuM z3$`iNSrtY#fAK==Yznuebv9`ch=CE~M)#KB*aR$ie0+lNp(j%V8+(t84`!VlFuQS)K#Rocc+?Tmij^9+2Ia{v%SemqS>609L{%4!mgS9tk2E2U-^O*LAmn7+g&cUN^Z0%b@k#gr{8<*+Ogz7$Bu6= z+b+ld$!e~eRTOxiyOV1!u39s1*K=>Mx(^+BpKoFJazDkayJO#)d%Vkab-G~LCqcZ4 zxS3tX&)x}Ce9`mpJR9LD5Z!&&cgw$GeO-X(mitU#-b(D-T$_IG5t;c z)7^x;FIT&tthz;W>B0Ld#h6PF?7E}0GUX$QE5Pfmfc_A;{AZ{VC~eHe*akqANXhUM zFBWkSFl5p?2t7P7gd~Hf;pX30&yEQM4Jx?s*tKWrjxJr_TDC{7{D{?_KlX9FtWIJ{ ze>(QxS}6x--NGDtfdc)3IfMbX2WdWfKUfeK!>S@iYHWca+iGR?#Ak58cgtP_2YgD> zwMe#LIwnjPq5TQ)l+gNz>vd`nGs`?N{c^?~{*^zQ_SLLUesstAytj7qq?hLKU&rMH z%h8L%Sj2bj*FRd!`ETQMFLs|fR=K=+P1!l?XfOKmF3^nHV<##D!x0ZadlCD8#_$O6 z`v{^|Hbr<6f#IegaV=c`G{WLgBn-FMJiNOj)EJMF{0{{0`{S9*>CW6o-*h<8Bza2K z>P2HtoxE4Ddf|Z%o%bwSBUgUR5?9VFvfV9yzRKd(J2%#w#cDqGIsDOP_UrmWlE+@d zwCCH7f-r}}o2N)akjd~Sq?!t#aW$oNTJ>7BX$`824q7-`tWhNX5r`T)Do)B_^5tmq zRRbupUyIRS993iJEHp;+rhuYia;9ow6$Mo<4Id(|iIl`y*)T!{ExMv8eh5-uqlBdr z0Emd3WR#uo#7H?DXq8ec%n<=%k7zLz5CEf6!XhG)J#>csxc5f;p>5jqdVBf&{PnF_ zsaJN*yl}mD_J?l{=U)zNJ0iSMou(aIHLcsqx&4hU^V`%(9XfK{sx|4$$JFNEjnBQk z<9ff0wQX3f*7ZBJ?xjfeTD(-FLA%2qGft--V+N9{h)R4UMtID7J+>DNv4g$NTfaThGgDlq&A; zOR>VD`mA}V9L{I0X3z7F)XX*f&<}D=%!@omh+TkY7LIBIh~A+gLMt$;_6d+Q;L{tp zB8yZs_&v2C{T(J{wxB^_wus!J$hH*j{a9pMhKe8x#Ck1uojZH)?u|n(*O6Is7fw_& zuc+sC>^}LkQk8cf*`Mk&Q})RPWS<z``OJ2|ehSo4|w~ zq1>2@tnhW?+pM0Mg__P=roOVe=v+f~DRu0c1MOcN<(RxesUf2 zZA2xW+YfP%-ZV_!Q~$;}CA+`7XKfUE#*QExMLmcepv_FZs&bG0&6TP`X3=lf=VvJwnc+gGA?J#7f`8`RMr8$N@yfsQR$$G{Hy)^WYN z*KdE$blFvS*oW^VE+UEW^HUs*ja^PLx!NQ)b(;WhX>WvH$s|p^d!*YKGR^A`-B+Nlv_4X|j=yGl$B(}L z`lCbk`o!*;iN93!Fu%>6aKojCtL*hNXX+gnNfg*KMXSi^Y1V_0UVY-XV?2hefvM>+ zWQ`LZ4X=z(Mb&6^Xa+BYRmiCS5QS6NvzRo~gO6Rdl44mvS& zLg*Yc+k0oIbpQSEQY|9<$6kz-9drAF2!JcibN@9!BY1--GRNCzVPTnvIR4<>CfOZ2r1v`8wz#e1#4(;P= z@O_MZP{uHlCH-q~$7^bkI`@b>8iWsu!Y1!{&b`A(GdrnkR6AsLSE8@|LudupJ7Me6 zjC<62=U1-3jdu1=JCEy~U0E83)Omgh#INY``qHV1ovUUX1-pSK%bM7;jpvSno#DyS z#nx-@T~5XrE5P=o6L8WnDII4A96u<$pX&1N{5?ru8kXig^ku7&$OVlp;~ELb50lD z-$3qx<^-j!?`h7R?Als8EgS4ix1?%_%Jyr?ALL%r)+=dE>|C~$J`%g#pJ2~6N{@!^ z)sjp5gn*MbjHv2;1SjoN`3_eF*kjc3(Dv#y;JXuY>E>mob!PD$Y1=toNl#9;Ki_gL zY3%V{6FXNeO=8PNsk%;&{S)ljXjotg0@}xUB^BDzT3t@Y7zdNBHNb8L@9jO_(`ic| z3-9b~hF!{4)06bY-fC{@dfbeo|GzhEAe(+}Ne#5fm!$NDvCd0Qs_oj2n%KE&)KRcc zJ}P$Dn0@<^luuSEltVF(kFfE^82bn=PN{}l5b!+4m<<S3?1IUHJBG*Av8J+eKrB2;Xmv2s9?(E}r@Ag1dVJT!&Q(K`*nS#zNu#4; zQ_35HQU;WLX$xi1L6?s)EIAH153rlUxgPr0@j{ctMOL10K1?{zRmUfJ@ngh*bHNt+ z8ar%^xgwx0Jvm*<PMrsp`uhd!oxT_yc<<%>4c@bL?S_HPXh+$*G z*jhfWZ(H(C@^Ia#j_ij=c^=j|%f}8V*RMwT2aj@^F^`!E%Eu09pRBRzJGDp*l(k4r z=y7=cKv`mk^_CFR-{@9Of?+fr%}d{w9_*5|lqv5@XO5Vxk$+rcnSsPYtCR@``OTW> zTpc}G)m~@ch>c|<16IvRvWE{dZl2n)*BzI3>t4VAHCNyK_M=s^A6sdj@|r69EtL1i zpi{3MdO`DhPPt|1Gh@}H#MDsU;V~xRg=vgS47B!=nLU-2gWkHqpsYb3N=NP%)OrRa35x+D{jdSXUq z@|5ASjxxm5qx%V&ncgG>Z|>D`$24YbS#^1I(o+@Mx6uj86VlTjd~a@{QhVN?e802MkhiU)a+VkIf1TiKp2Y)2k#AZIW^hkAU z@I6UQ+Ov(dN2Be<9@S~n<_Rb~`<ps{B6E!0>MEa;Kq77bgzGs&^jk?py8^D;d6ZF5d!=%Lb<`}b8A0Io2m5%o) z4=4UTIcypojSDokT54?!HR5}IytSH`-@3KVzvvIX-SPgK*4taNHRN{v({TMUkgNG? z`2GEXt%tW}Mc@q@cZa^p2a6%7d(BV(a2ayxEc{F`{-!SUErcJB=lS-;_4V3P4FDTU zbzNYod{3X(+Os`EIjwm>d7iP1l6teg1IphO+DxlrA8f`nEJzw3C z?4|g$mo)OCahJBPdzbcn#S8&o=00s+xl3HgGv7`OwEL5{IG#76OC46TfiiK!Hy2|2 z{luLZUw+AN?k>q|UTxVp$(3sPde*qtNii6#JFfl~0zJj5h8GYbbAaf_XZOxg~CqF}DubMCRRTyC*|0v{X3}=j#_l z`VYE@wjNDbQY*=3{z(nxRnR9f3U|_)lNg0d8JNlA?F;RaRxZDTi`$&-J(5?kec`ms z>h>+Gqd#k)A)9Wwd$PKta~(TcyU(Abk|n)yOQQ0=tq*S4Th-ovZ^n(&GZSA-c(I|` zs@C*RZ|@lteC##0YFpNJUe(h~6sfvoZo#1Q%z3Xp+u+HUwY78gGTHN=W4xVgfr0KE z`Y0Buokv;54~6nYLU}eZg=aN_ zXtI-MHC)PF(O{SIJfi}89(XP>$Wr{*_M3Td7V6Lm$tT}F75fe zv*JkWPhVB+g-ctvC71SmHW)jSZ@=GkZ`Ch$k;K^0W_RMHYD;1!b>No$S)Yp8U7c(M z^@>sUE1@U+mbdlpq=K?UJrKX(DwoD zdCp*Jp(bq)+i04&O5GjG0~^}#@Oq>+^V<$32C7@61}|~1uJYQDnwqBVugk}LqeZet zd_I=c^>pR~yx8wpRF`s^(Z%F0wBSi%@C#W(($Ubg(~L`1xm@o-J9;Rs2h_W`HK^`a zJ$!k~V2Q4s#%?>(bNI|0(e_tdY$wzC!N(4I739xcf0wu_6p~VQ)z3sDpG*8My!5l{ zNoySFT|Xuf;rcxMV~e!Y;Ds?ObT8NFs7~{#2bs=VUTpL%67Qb&0@#B*?564kA6xXA zwc>t%6;D&!ZXvutTX-3pc!y_RnW(L<5MH37uTu;9y0%;`LQ8yJ;C++*g^}Ufb3Zd9 zr9=|uB8eM>4={%kHw-fJTeAgg{v5pzYwKEF*?=|w-C9HrU2C0P%bb|My_TBz&*8Pk z*Lt9qHSzs5wYF=7fgt3s(RU22HJqJW^KZ~3;-CicLrNKp`RbFZ0(jLN%w_CCBthNI zSJ_qnbjv_n);VnKhL)$QOy-KjqUyT!bJ)_BMG`|i>}!!o&6d~L>oFqFP%V)sv_+n4 zMQ%?dYO~+I&Y(a=u4nr4tj5b6rW0oQ)B{i8=e(=)f+x5)@C3faVsfKsne&Ox6ohsA z5WcCw8$!qGnqoouKs_=uhYyjTKwm~`kBH!Kkkt{f%Fu051shy zrXc?E`{#KrJ-hB^EHeVi^HdX+a|C7IXSkHL&(M^$&v-WJGXmOvZ0FL>3TVH{8^n&x zZ+5J8FqnDk($_g3m;ReZ33cIRTYUOU+SNWNi`TSucnfV`C7QyXT%svclA0oSXiaJE z=Qz=~^`a@{6g0N+&!nb^ht$223{O+uqUEg;O@X#(#7NPI%M!KCnW8CBk(T$XT(8N? z9Ai#WQvzOEdY*kGyc7n!pedUJO$j(@=y~=**t&_5;m-0(`D8K+9q3?Zuaxu$tdE5< zb8$o_+M;{yLFPT`Qg-%AS(El`W9HFldt6tiP2Y>Ab_8Xg>%=AYMDYr6Ejh_KV!4MW z`dJ@~{NPWn4|9H_E(cXPsrcBV+{9e253l+q6`$*w5+Bs$e2%dY-SxN$q;m3~a6V^3 zAn!mXe%ALiIAK&0JCv zMKW9EQ_gGT*%g3G+~U;&&s*^N1c;*>Az+~lR0^xJ}cRiHpt~) zM52kk!NO=Ac8YI!!!Q+S`WUGf9y-)vQo^f=<`C9Hi#|8PzpBd!hIVh2~ll})4ev9j$KF{ zBb!a0B^ZMX@;-GvyHGtljV&gP>{-7c-|V+up)BKd@DCqjXuZMcdJs`%pw+&P;@j+d zrJQHU9l7kA8}JhJr~DWU%VfPL7UR;MuWmmIZN~b= zrU`Ay%DJ@Xt6E2)eT*l=ntabO-b~uofNwuutIjuG_?*Bi1YCQy;~cX+*JZ$Y@J=#H>!yVD+nbg( z<(18?*)@i^olB$y_4Tr*j=nIwsq0z(gi252{j%d6_B+xM>mB*6kK^|3`eQsF?p8>0 z^^W}E1hd{2Nm8pPqA^vPEA<0hh0Turb{O@Ie2aGqN zaI0!1WzOG{dR~jDiLJ+h18nJsX>8xGR>!9O+#cYH3^i`Lr-LqT9ghz^4&2V?BB0yA zboEtmLwHJ$XFU$w%D3(T<%VW*CW}k`p5P8W4&3>OJ5pz|xOd#|-rXd`Bpy*e&0s|+LA%ge1tqc7*RI6rr_o_ z3UI|PYuvDl>wE?72?4Gi1#XorVL-W-%eC_!*u6E^!i63MzBE~*0d`&Z_D6w{3414@ zFKU~}`wioHc40`3O-0_G#<0fMzDBs&D%gFE{Yh@b^J#3q=TH+nSN-KE*sVON)Wn|6 zUO$0c0@`i7`f;%}-!3O_V2=X61MJqRe2ZLM>@mg%Nx1~r?U9Q=7Cf1f){&Ba@0D~- zk{gM`bx9j}yw}9mBi;e;{zPX#$758-Mh|ZZa0AMI*TwxMX#INpwY9G+KK2rs zH%3OW5hD+JN4J#m*J@MK|NHS**|w|Z_^a_R$6sGmKctMm=H24%2zNJ|!Rd|Qf>7$Y zv8s;V8?LG?JHu&9g(h^<@|0H%>WJaiq&%eutmWA{MT?Wz)a|68ZUfx5DLULOv?HKA zUky46WwcT(QcXVQ7}Jx|Ptx}I(CxalaIJkQ@xp0AO$9p8Jc(;979DVH-Gs9P9q?^k zFlHt;G^BOF#ho`cpzGru4$+Vc4-#dZbQSW!$UtBQ%f^w~SOF zTZyr&X-hCt#bQ+!6&&9+zxDBW(7st?OFn5};#IdS_zLagishNJnU@k!3B0Z6 zL7nIEMXqPj9x=^$!)czh(1D*zbD!zF1NMbl2R+X`oPbnd8H4N_2*p%E^R#)uu-?`>2Nhtw?5Bf&p#BDC7^((l(u&=HB(^tk<$dtGuY|HHdqQ?usCDTrWFD3G(hsVb{lExH~*S3R99i}bLxJ@X^g z83{|T|KNFG3m;<>uOEfV9Aj~^27%dpJ_U#)G(y@*bAbxATB!AYh`Y%qiukTJK?6l0{A=!c{>+Z>xdf{ z=?s6sosS*N8FnKs`Yj&zYvebBeoGP?9r1U((|0r$t#aw>41W-J1)MW#=g!&3e@#wI z);pWj$b9+!OWyS5&q=6}`3kw2FJ358J0)jyWaf+aoz%z^vHm?J^Ht~W@u!dVGhf#f z{%(Kp^dk>H&6|oV?p@mL#A}DRiLYCRe)pku+~I@wJovzURy}PA>4AmHrJk9)EY|Ie zq;>|D`Z!PHs>hdT=b3?a2G+x$@h-R$z3Nz$Uevfih5>E{v8$iUVK$SsLpWLQwUd|g59=}dQ@ra_wC+1+Qii+2=WzX0@A@>>@HkF{5oD-i0W%v5 z9jB|%;Uv^ruAj-Ya7}-hT;IcUx6AdV9{%Za{blDMTU1KNs6kklj{1Ka`qSmSV{p!#A%3Tv{4SX)IX}z)T}CFuy1e}Ufi9=~ zPB~qAGAbSB4G`XWc!>Otrg^{Xk#FZdm;OeMfQtTu5-wbsHA=Ce5pSJ zZ=}pJ%mJHiglJ)l)yd8uKDJE4(%2_@nZds%Mp$v7{kezTKS^8KqsI1U3xA0gTomr$ zX#u)=QpBem=zyQMeHuP~5smo<%3D#6r<_3L|@pnxn)LPCvOyh4FcHFsu%S` z<^p-k=qKZ1VLkfE`Ah8MuwQ<^Q_kDcikHgyHR!!Eu1Q>MPqqgT+28K!ruavmC5q}l zSWZN8zM1rGX1-}0W@o7J&>TBn|0EWYY_=i|iOEob&^enHo!9j?9mtoe!P3ia??18(c9`q~4Q zCl;A@Ro6s=DOPB9`t{S)#HwXhhI;se&~xcp%XTC8+hzWOZhhFcDKS427Ra5fc3w+Q ziXwZ#cV$23t^nT`0fPd`btocb(E_9_I@2eq1-=BCvgXE|Zp~^f(A2etwQ~YJ2u$4OC~sesfh69(H1yY`T3Wxy*U2`^Re^Sytr`Z{0xiyC(EzpzWp9kRX^%f{RxDCTRwq|Z&)@=`OQP+B+Y5lc(WTe*?{JY!38zLmr@TG+>WBa;8hOHi|RH{p$M@FrR!=V%G% z`gcd3RwTU5Q>P`LCca!h&7X_Q-GAaE+>+Mx5n2*#&x{TFXYlk?pCR+9#iw+V-%o=Z zJ@W1QkQzS2kW~v})A|X%%#@V#0doEd_bZtr5O+&s%y;(r{ZlE8wr756YFbFWYfmeo zcDYzYnZM1Pe!Xv1#{Y$VtJsD2h<&ThV&AHFLw6S3zBO@Z@{iB4Z`HfCp1$?TmtSJv zs$p-9Qk{5l`|Mw)>y4|vS>FER)w&L4{ee{L+zE;w+&0`c=?;^wIet-(G6=ty0u;puimv%Q=%fe)RY>r`4Zn4!?o2tg&y2$^t$F6o(< zXQ#}(oa0>J{OH#}a;}5t6T8_>)cKmKdPJy-{gM)4X|yFaXC-Sy@=3b3kMT-G-G=X$ zQRu-Q_M&8of(XxFbM*PB0`now-z2bZbovRWvw^lvVtG{-GYBzVsPrZ zSgsF|>(Ww0CbSgp??SA-U1aj9oY#mkh_Q{d9^!SkNQvjE-;!Q8n1R{M^YO=`hqiFP z-@_iB^lHA&=lR$*pVdM~BWZd*R0sF&qpsd-;62M-7pQF~+DcsE0c_ZY*huW$)!YJKAJ?^nT0So2F{)=$K0f6odS?&)1{kd&E_E#**S?K0 z{+^UiVBeVW6Wk$j?0>YEf;-o^fM>YI%DWQ;Z5E^AGE|^ z{v5Gkup^9q!aA9Wsh^N$ylK3FU-9G_#6V4$iP_N8%@?p7Lx&CoBt|kj+Z` zpydYKH{c14+&i4r$ZK!-vET{WW7CfMgwv`$VQ=t+99I1u@81!Wp&n0Y>OE7a{gv1vlx%(^PDX-VqX15cA2A}6A3Mtxnm znAyxFAK*VB$$QdjI!m!>6=KueCuCn2XkN7^_%W$2!vkrI6?;#}F`iYOj`{@8YU*8` z?Ezxb+$ZD=3v62O1a^?f>)`3OenS7WNbrPSl%e5KpP+Z;)Y{;xA0J<&G5PmhkuE^MNsXx$N7-Ur@Ytc2$MB#(DZ`^+>Q;|XnA!fw^guj7Drd-SxkSI3(E zQfUdAe%Q>qF=z<^^;9i7pC{B#BU|A;A)D2cXCLu|wmiX$qns5yp}VvM_X*iI1uY?X zLQAyh1dk(EJ~|)cmLUgU((1z|S?4`E$v(S*X z{<7>C_XIY8m1bPe@vf7jzy?gm{}z!UlXY=|PmY!A?&>!k`Gc=*gS|%uJ~HT~H1ee4 zuCCKkx!S{iBq%`d3C>$9*`$-8M)M6l9nhl^Pn9{7pZ9LsYmUY zAK+sLa|c>@wONyPU)3*3J6N^X;!kMzH8v(`OZ{k@c6>G3+Sa>#FW_bJK}-_x?XTAr zzQYs1cKKdl|IImk1mFHF2A6Lgleo0sV6-uicffZmPg7i(=r6D!{sMLHqn)0z|%9);~d@R?SBv_*-nlj9z)4~~v zrbx~;O=}AHqA4G!fOGMex;ATj5|_TecoC=w_Jv7J33}!k9`7#gb^+}-B%bm#CFuFr z^Q7YD6|}w9w2?~Np#2E0uFFOq<>84!dm%#{vb&PeiCoP*^L+T}W6W_z@m}-%uC2Va zx2MsfQdR+*gUz!=9w#PddGh#0%Yz*BO1b_5_+N|s$Rz0NCcSp##M|MlPwg|{?spHr zQm!unUylrT)MLOJ-&;-m68PtfyczqG>&!QU&e@48LZ61{H>-=?>sHwLgb|r-iL33A z+RLj;-0P-tmg|;Go?<(eHmvtVF-&J8(btkt9xIKHH%7Tr2mH|hnN%W;TkmCL)=Ae( zOxXm#LAvbI+@R}{y2)7t`o(q)WScj3!%x}VO>f(rGOd6a1nt?`$7aGn8hfkD&gz*K zFGAHXTj*pC+NZ`8D^BklCCEI86N+~nDUL64yY9VnHRxp1KIxl|4sh&p8qlvz^Koj9Kx{QM&v|- zKrQ|HwM6FiyXN0pzs5v;*_$bk4YGOJNu6YYkhHgXy}MVG`9PxL^Tms;2dd6f_05G< zmzxV`n&W0CPNQ*Pi43h>aB)!z7qpN+;iB3~fq$2QyAwrAXU{elCF-ja)b>PMwSA^q zF)Oi&=l@C{`ZTn#G5Zr8DTQhk>Wf6s#NccBG;rn9plg2D2CQaS!$)fE=BK&8r&Ztk zpLb=l>pz=x^A693O26=0>t}M8bGGWv#dnpg=%4W`BrdGe>h$yknFC!f08W9rLB^6S)sd`ck{-w5 zB^mR1kz}3L++*rWjbn{c-&J9|SJT8O)#eSea;^o)zy9bUim7F|;&rvSIPp^A#h=x? zbN`ySZKoQphV4q+_JTRP>P9oW>T7fMO!K~~^=6lQ8{+6COMXKmt%`pwg|_1Mq#Ga`#p8;=0E=UUY+~S?8N5H`{F+&Hve7iOteKDa^6hNU*x=7XbE$e zn>W_?PvyKFhmPUc6(BFe>xbs(Ou5ViA`3`K7upS-D*p~Y`=@vE z_IG|Zh9mp_X{YcE^il4}R%iKl1pKq>K0C*{S)a~2b0yCh;N4*+pAlqY*yY-vTjSIL zZ?8PV&BiP=e@;F_bX%8$-SK(2x;A&v#{_CEcYQy3ej_ve(NV|G2+pKzc^Fqb`L zWPid?*F1kW)VC9dQg^ANOeMzE*rF#BC8@jAaecJWpX*wdsk^ZGne}O82}g)*2Dv4% zE_FFhER?yU9ra2UU6Rmxx&AoU@0Khf834Jy*~d@aSq=OXb0`ww5T<9|QGAS3YFgf-VzsS}qv^)-<4-x$FWM zWC(&;bxpiJrOX!%{mK)WFDls25?^|DG?=mH@3;OI@=DqN3psuud_R;}n7aQLS=9^W z`XKtlsry|mvR8?Y4Ntt3x_=dP9+iIeY2c^y7rDMv@M|aLr|vSvb=T*(nU-R>mv(6O zw2ReX{Fg)!e$StMlJay45ZPd>?W#1LDd;7oeZzQP1^w;7j`H3O!ETH1U#iy>8P|YK zpSWeP?jqu$dJOf+Vn;Gf}XOqt-HOdHxD z_}6;ZFO%y-p?|O7pXJeaTm4nge^2nQ_paZl@e`+$`5746jE%^|9Hgl`s#rUK1R5cM z2_a_9=$$y=XR%Y1*h&w0BxT)8du0W6Z@HdWnApMfDd0aBVuh?K_O7oI{HaLf$xth< z|Lk2aOl${#6RX)q3I0|bil*O6@Q;ViRdRiUhd)ZLlS#vx@wQi0;o)Z`ihMp<3mMjY zay|q8%H;g?;G8ww{Ek)Q_w)IEhdx*9{oiFZX;`ly=J%QKJ6L}IIrv?#oDC~74KDo< zZ<*tKyMON8zfI0%?I)`r!+NEti*Fw<_(gIqD;VYc2RW}#xmw8i206!8+o#DnIRxbN z9zN$k+do4n{s$}Ew8R!`d@Uig_h0NQA`*T?R>bWEU)zoD$u(}`Y4vJdf7P(8`V@Km zDCMgm-~Xa~tbDdE5ee-Qituk=Dg3yzN^(_)BtH^fYkvGO^>)Mwb!E2zC8eErbFk)4 zA`y-2&wy?OW%i5sUv-POzEjso!mVq)UqGO1nzIqICYxzKvkB{6BH*s3=2g=)dNAiF23Z^JSBV^7b?u@gso+qI zWHWZ|Z{~NiWCu0f86*vr`ik#xon~}z^E)-uuhP3euT$5i`SDI94vbFtp1FK`|AtNz zIqWW)a3Z@%-6Z{A({+CM)EJ$%pfza^YkUn#Q& zT|VrpflvM8trvzq+4+ROUHinl4HMU@zc*eqedrB0T=jYA#Sl`NLA3M-qj2fO)_KZ( zN1VSrR|F%T(ie=l2HpRxYtykD}ed$?kof^^am`zzPh!ab<%r0>-t5bu5s&2I+=cbRbxw9fvzu0-eO8d zv7yc@roP2jv(q9eW{s&A9;n z|IGTknltm!CmXAK-ukL>;s!Opm1_0#h}VCgzTxACCV%tkm`~S?e;947Y4^;;;LvS) z)woG7QZl-q$ZTV`4e1rwZX24w498#%w%>+=`I2ty2HSL7_k>;nuFR6t((&it-9UQ_ zOZzF8_A%3mhk8)cviky_aF;5P>$Slv*D;~GPioJv=Ss$X_ zl=bgKy`9~iE`^R>yH1W7kJnet7kpZ0a;-Dhb7`-dj$9Wz?&6P8x5;&poY*@&hNfe@ zF4w)cix5H3zvTMs>VDzVds_$B=|$@6#tOOqHo5H7*&?qqi$d>%HH>xhsk231$0um} z;q9J7c{4rwt>pTQ#Fb+8#D56=s8I`iJ%WCNL>x~FzKo#rtvS6#YDfOM^67q8^zXZR z-}M_adwAcil^2<8K~2y3K&wM|Np*?%1(yhUlLrwHY#c(&&kIjvm!z$oLz_PaZ#H^v$_rM@$?# zdg7#8$KT%O^e(4mW}Tr4WVyee>LIviZEl^^W<;CG6Gx01J#NIr+uDr3$$Lx}_i65D zmyzSg^|@u@t&=9-I^y;=+&OyU%ydQ_X-+eeL_*k0Bd?jQmbu@bGb5>#FLvSg@y3n7WMBx_Zf1AmvBn56h6>&!?jH|T{md>rF_ZV+oFQkLgRE-z zpIU=LD(yDV(Hx8bCPRG$PakcJlPBHAweiMHe5RJBOSQA=zl;Qb9Fn<3q%sMLw?avC z={{4Ja5B%+oL|guBYD>CQu0yYH-fFk!n|@n##u{u3Sug^}#Y-%3O?ndjg#6B3#7`Qyz zpJKLmEk>&J*r@*Az(q1on@~^M}5A!*Vf5rPx^czqfH(ucL zMPeR>Wqh5_w~R$ReF^`{Sjt*@MUHeCpP%!u*w^4oKEL8$v99?WJ`1rK%2;cx<8uT5 zinR>e_}t0AGIsN?m~p;`&r;(MpH=)T!%>PEeU_qit6HiypG{PAK3k|3e6~^T_&k9~ z)>0?&?gpLL@6KmWvXM%i!J844I#>1O^L%vypBFJ6snlTlv`Sshtahb_vEQ3gH)5-l z8l^_@d5dC#i5jEE@_D;rDyf=)l~VYpr99gl99&Oyje*S(nda%wza$Vm9ToIV<^;c_Q_o%#%$xH%~QB<+Gca$>(r$B%k-1 zyZGE~J#HxLNeh`5 zvLEL25u4hyr`u4opSRcYx!x}4v%>y^&%-v-4yA?aBXg}M25%`h*d;=tF>mqzHvjMN zzkvUR?1GKVRY%o{-$Url>*&HFkBlS~w*2oEyCKwHF8$I!M@+2+={i(SKn;9JSSuLOr&pLs(4k^}-)sne$ z$C8^kj{JEus2)!?q9q!w-yU@$(fLW_y-%T~bfNWV`*S+>s5}0$CzdFi{6;TqQ*Y)8 zoJE_y8LfZVn9BI{)5c$!tGa~j+1*&3x8;&V1f{ z!JKKnXwKrj*&muq%}>nF%;n}6<_dGA`L(&){MP)=Tx+g3H=3KxAIvRgk-5#>VeT@2 zHg}s*bB|eS?la5GaR9!x23CgE&}wWov6@=Vtrk`* ztBuvpI>G8-b+S5JCtIgl)2v6W>DFV`4C`_03F|5AY3mv5uh!qJXRYU~=dBm4nbwQe zEbArfW$P8|Rcn#8*m~E>vzA!-)_dsgKdgURA6Oq+A6ZMSkF8IvPp!|;<>l7r))&?W zYm@c8^&>hQw+`58c73~%{TK9i8k$*K^u;vl^rHQs<7kmOnD$-wmEBjS9jCN z>|PDN$nKThD{Ff8P1*OSugJMGqhpWWe4dkiQ_i;;(|WAznaKIJXX2Pz4a1FUHQL+w ziJUtd|E=*W*}aaN*6i-)V~(G2{IuhrIR0;~o@n*AR^PTZTR+ibZjZTbKg({~?uPc) zci+}wx#pqAdHOTEX~!3O%;jwEiRW|otS+SZn{_I z37IEk-*ozf)Bn)lGEbmf)8YKi%>Hn^vd0VExAo|q^`ZXHZmPe#WpuB1Uzs^U%cJ|s zUbVV6?0!Qpv->AGdvoHw%$zt!`R~3sC$8n>{%6nVnMnQbj{Mwzmt&W@kKJ=>)^(}> zJ)Us?wfy}5oI7*wgy-vg=>DzyuWP2q6Ey+)y^>FoIy0#^U32=n3%$5^x)0g+%m0jQ z{&SwAHt*Cms{ebL{MVwSDgSa!U)K`gpX1){pSb_tZ?)j`Ud;pbJeBW@v+m8w*XLTo zuKpmUsol3_H|;r9mo(>2%6e~)l`c-!hds{IclB85Q_1ez{oCvr-M3|3M|sh!oI88; zMoupvndkJs=Gmb?)2+b|Kk6u<*aL4OF`4@aUN7X@bUiLW6e6K zdG3}vDRE!&{xNI1Cv`3PJF{nKt<3I)-mlF15D5ik(z1is`?D77wnRJR7t!0Gc6Hm- z?M~X}omv9OCm&o-W2sHi-d;p7_!wI}N0{DVjOWb;c-j|;KDrsR%uHgCm&|@< zKjUTdeDeb1744^t*?6kI7<2Jf&l&UZKXZ)_%=zXU#xnCA^IhXh^L_IZV-?=$Gh;m- zX}Pfhuk?kn5zn;3*o1dlV~9sGcHonWjGysK+l*p-(+*=d{%MyH!9PU}?W6V>CHSdQ zV-LP+pRpHzRc4gpv#N}k>6ni3JK-QPfW@D22!GYUIE>HAFskrd4UGi;s*T~`vpO)r zsgu=7+4!x_Dr9xFvQ^mXW1X)utV^tc>R9V?>vGl98g1RGnpxwl@v4<|w{^E_i-&t$ zwZpT$s!p`#T60yl^}6-C$|3%GQ}wdmvEET!moX#&cT~~s?Nuktxy+Q zE3L28AZwNNtr}vjw>GGuc(zUID!kkG>S{b(k-Em(ZWXKRt%wy-qpZDFsTz&fi>sTh z1J)sRiJZ zEhP_|t3I~xvhPx#+xOY`t1om6s8-ky+7GD$d#XKEePvIxr>U>)nfA+SmHn#ys`}2J zW6xDl)d-DQi8j+4(``0R5aFtOh^^&=C0C`N6&mSO!j0+I3@ETtnJh6V=RU zY|b*8P~#1mf5DqcfyaTDfLDPHT;BwI5B$jaUZXLwLlb)fFcFvxOas0!8rv&?mC$8p z5T^}MT!z!cXb5z0hB6cAH(GpSqo1?QIG=q+E&v7q7Xg<6R{%rVx9MtUuW^l2!YYvx z<2kO)0$%1?J~ZA3KIZ&We*2o^D&QM_TMymMz^_iJvVi)|P}P)UbEibL;@A%0tuyL8 zj{P{^z;Og{8!*jjqGkY30Z#*^&T_TSS#D+m4>&{3DZqokL%_qpRNxWdC1;!YGVluU zDli+E1Iz{HIi==&;5FcN;0<5_un<@TEC${M@|?Zq5+EOV4|v}xG5-Pl6Z#)O=R=Mk zaa_vrV~(G4&obb1;7gzY_zFM{<~Kkgum)HMYydU^-vhf7znQ;tJOorZrL_0PwD!id z^~Tn*&R**{pc!yH&=P13w0BCZ)1BoOafZ@OhV5GCx9u3?K+zQ+Vj0464cTlED zKrV0>ZEhAkppW(|+&33^9h|p0qI32#e*Y4@0^l2GxxF6P>nx`)m(8wRy_{m>3}(rn z>1@S*&^L27sb)?wHe?evWRof-3%So|fIn+s&T_V5Q#N5!HepjXS#6j>(vE8<0H+%b zEO4yuKo6iNkOgD|mjIUn1A)iEeF=CK_#7G=ps@+~9{7=Kd!1tIfV0(}089iX19v%_ z>}edAas0w5wpRcv8D0CvXkf1g_R_;{Non#Z%|1%9mXhRAk~~VXkCNn3l03Ly3-=5+ z01bh5oSy(Z4!i`s3VhD>A35%2UxowDTDVvX7i-~SEnMWm#ag(?gNuD|v5z@;U7Y z4sZr=CU7=zF3<<)2V4zY3k(BB0IvXV0}CkkIY=pnlwwFJhLmDRDTah%NGOJcVn`^4 zgknf2hJ<2BD29Y$NGOJcVn`^4gkne|hBRVGBZf3$NF#tR{2e$1 zRPkg=g&mGzZ+WK`kO5o-TmlRP1_RK-9>uUnF>Fu_I}+1+=}g6gPsK}4#Y;}bOHRd0 zP8H3Mq4_a1KZfSV(EJ#hA4BtFXnqXMkD>W7G(U#s$I$#3njb^+V`zR1&5zNO2(uGS zUEmt00*_x|d!1PJEsWWCA^ahk<8-7lHSH z6|~9?a8nC74mciY3A6^<0_Or_;Hn?cAGiP*089g(0sad74S=Tk9PkP78L%Aq0$2-B z0&^p<8TbwO12{|xP6cKFGXW%HagVhRh{JtdpgxceTnJnYTnY>Vh5(lXLxHORq-$RX zTo2p;%mF^6Z0At=2&Iou`Us_uQ2Gd^k5KvurH>dNI$t1x3?vXi0udw-K>`sZ5J3VF zBoILY5hM^n0udw-K>`sZ5J3VFBoILY5hM^n0udw-K>`sZ5J3VFBoILY5hM^n0udw- zK>`sZ5J3VFBoILY5hM^n0udw-K>`sZ5J3VFBoILY5hM^n0udw-K>`sZ5J3VFBoILY z5hM^n0udw-K>`sZ5J3VFBGL|cz~0V!{Kf`i%wl59Vq=A~%h=+qCyp#unH>87!<_Zz z15PpVU@`GvG4WtA@nA9WU@`GvG5%!(aa%DlTQTukG5%!({$&HPQ87Md1MyKYerAL9 zva=pvv%vz_`hxF2@_iTI4{)sH{5QV;frqo4^~5a2#4E+bD#gSp#l$GZ#3#kXCdI@h z#l$4V#3RMTBE`fZ#rUfY_^S>0s}1<74a5b-^v5%JZ%#v?gHuQe3n^it@fGc15bg`%x)81l z;kXcv3*opBjtk+q5RMDsxDbvD;kXcv3*opBjtk+iklw-yJh*AB#-sj1WU>^?UW8>Y z!m<}(*^7+9=qfsmz1wV{*I4=@`UzXH8auHXJF)sjSp6dU30txJMOcxY#%FleWz_KJ z;D13s;Y(+aQNW7(l};4TP=seF;)y>S-*C^j&Ufs^xY78|`N@cZPx~^;fePRtPzn4B zK5f&WZ5oGw1nu4cET>3?I5u@QW3_hTWs2}JMeK51p?U(nfwO?~xON%GD}XBj+9O`5 z2rpEG7b?OF72$=7@Ipm+p(4Cck@*gGV1ct4+rAmwz8TxT8QZ?u%yYKVZ`ew|VJrQH ztysmKSjC-qts=Zu5nihZuT_NCD#B|O;kAnJT193dum)HMYydU^-vbAD4&^j|0e%I3 z=NX59DrYnOgRS%rw$eY?O8;Oh{e!La54K`~cjE1ethv~u`JBHF?weeDoA2-NeF4W6 z{En5iR&xFoN92yh-ic={vcBbf9k8DBEx=B`N4Os4Sju^f@8v)R-yNq2&sk)f0Cw1} z1JrXi<3)??433SRomlyuc2l4QzqRCg7LWs+0h|e(4V(+~0r~+Kao;7tKwvO{ZsGqn zgrz(2VD0q`Yw1?cGg_`faqzb$Bd9F32o@o_Xhj)uq4@G>;K2n{bn!{cap z91Sl+!{cap5n3Ii<)ow0d(r4P8XZTYSD?{lXmk{fjia4$w6X}TjH8utv@nj=#nHMr zS{KL1Zo$WH!N+dF$8N#LZb1{{Xkr{qjH8KhG%=3Gm7#HEXj~Z@SBAzFp>aiMTpW#y zqj7OGE{?{<(YQDo7f0jbXj~kPi=%OIG%k+D#nHGpT2+Qtm7!H-XjK_nRfblTp;bj_ zRUC~fLz{}wrZP0C3{8roJ#niK971 zXigl>iK97jw1xK?Pzz0fra(*1vw$4n4B$-QY~Wmg*@S3G98HL$32`(bjuynxf-B}j7Ii)YB^yQSkoYI$5`T|N{K{=t>k_iJ~h}bR~+eMA4Nfx)MbP zqSSws`j3)bUrj6BN8SG7EKt3O+u213&-V*`Ze^^d_xBmmc0G>ukXN$zcOmB&aef(h z>t5hBUa=;0OBuKN64s1jk$HO%vU#QfHZp@qHi1gZy5}_ut45WB|uF`^<($eX}v&oAdoN z`ofvcGV1Nf9w%8LJlkG#5wI9|7kJ;OYyJcHFMFeSuD#|Vph{=3jJjm7mXX0)Mh0t{ z)dT1WWC7Vg4!!(7KwqFA&>uJ-xY(#qc54~gtz~4lmRWFv&kW?r8ozzUeu)F$QQgri>PB(R>Ij?&oCFXjTEB3w z4Xgr}*=zJ5uLt%M)piH^0-ST#0q#1$T?e@90CyeWt^?e4fRU?foP%=bFpl($u)YU{ zLUZR}Diy5iL9FUQtmi=}RzR@=in{-K5bJqRD6i+Z1twu!98vvgwEPA`a~hC%Qi}*jY#1yN;N59o$CXwhUhpfm0pV zt~1tyzZu}k>@K{|*hx$g;rxg6583|_{aqK!` z*mbJ5vzwgRM*K}gwQ+tXhFwShM@yrOSauz`wDs7o6{PF~}#FC7{l8*&{oU;m_wi=(d8lScrpSBvGw%XMFsCS%oNIino zBgCfbh)vfKo30}^T}KXYJvqGfNeJri+YhMAYxW1aG;#~*x4hsFwWV5gv*d{84~>riGGGeKeO6%{wDA_-&b*5 z4{QNSfeK367-#}C1?~VQ0lC0k&S!A?8C;gZVHtUqZ20Vj=j%;d!&{=e$T`!6n)cexE!t{aQz)RrrUEl+(*!{5_GHtozm^Q9G!}yPy5iP z2>P@Z-HB3~2&IWonh5$4MK_}8MikwM()T`qZbZ?E{gg0*PH4MOPTfbT<0$nTrEayI zD5q|%aNpzjKF9U^PIi^C?+hfhgIQ9InIVMO<8d6DaqW1H*nQO+Xba?U?OcxiIO-O90Y}|RFXVU$$3fgX7`O_( zxDg#0=WSdR0&E_ zHM@hF-A>JJCqGnTO(WAhgX80zKgIW%e1D1WuL3-ayio~xqY`R-2Q|Ij+QqfKeBZ~l zIB85)1?U2F15O9J0~d1d z#lWS&AYce^IWQEs3Se}TTvQ3Us1kBfTBEk3QQOg|?P$~vu>|*WoW}Vq=*n88%U=Oq|*k{kzfQ}Pe<3&(e?BimPvc92)dh&L?h^JI#P{TFB31m%8?it z-A#9`6xV*_+Ahxbay$SKKcTbf=xn-e5lb~9?m8AY4ru1=MsG{d+jR6c9lcFQZ`0A+ zbo4eIy-i1N)6v^>^fn#6O-FCjsU7W^v{%v|Nn5tv_Px*{kBc6rdlpW6p$M}?l!h^zKuTa0eT-ckco72h$;GT?8k8sM2gd%KZRF}k-03H^-j?M6a6hgyu@?MCl* zW4HI9cYDygJ(R4Nk`+_3VoLTiB`T&gKQk9L8*Y0`33gF}VoI=!66~b)6jOp?DZxID z2k@gdkSSxMyC_95rPxI&Sl`R_VH|G)#sd==sczuxg8N-?zYA`CPItkn=1^yMi>q;X zm$M6wb}^=tO|J4x+U$Cco5g!GXMu71S+q08wxL=I)ly_qflMlpNd+>gKpwgsmLi7= z!*x!2Q6B z0Pze_Q<>4;NRBL35;Ip4B~?<2gK(=ymnz|~5)LYfL60`dR7qr1NiR7oUM zNhDNBe3&}QRB2T>l|)6AL`9WEMU_NFl|)6AL`9WELzP5BmCUr>haacUf<4-297b;# zsmA8)!`|$Ji+!}$eYCZGtQ4u433TVi#0@_KsIz~5w$IP->A5Z~fIrLf{lsruf!%m{ z=2ECi^ywI&IdB>>2;UV>n^3& zT}m&zlwNizz3ftY*`?Ms0COU&>j36O(915Rmt9IPyOf@EoSt+kz35VU(Q$gwdLBt! zGJ`q`=w|>^vw!Z~kT|{M(tj)S_rK5ANM;4y`5JM0!*P1UrM92(V;&B@-BNnHrSx=5 zncE(wr&<>vuShNDkrT@!Czi*&O7`vIs7E)h;F!$u>tH<^!(*uLExYM;ra{b3`9- z&qn|)!u%9mW@eBB%rn0P3V^Qwl7bXC-q+^~o94CudaO`Wf5^IBwo3kDO+nrSnF=bNvwDFpEV2Cg6^w zu#Xy}71i@cd3I~Gx-HNi=m2yAIs+#IrvhDp(|}B%2ap9lX583k0A~Vc1Lp#L0A}IX z|NE#*9{JNedl=x3y5v>MH=#SUvOHSZW?ESudDXoCI_K0tEVAxN;Z3m0aaKvylO9zs zzFz<^qAWe5aeSxugN2S`q2tWfIiK9>1;7BEn+2`_o&#n99|KY4L_*MQf7 zH-JxpWx(gamp}pV6~MF2Z-7Ez4X_T_0Bi!jC!aVQSOLJN1)dcFVn8|I81-xV+V6`gn$vV#zmuP|UUWpKhVa(L*TQcLOM}TT(+}x<(Uu4|y#bNAhT}ErC0*?TX z0@H!VXk$MCMZk7&YEg4bi5J!o-TXvN4Wfo#RU_eXG%>?C=VGB%2`wE(R6?r~T9weM zgqDsJDxp;gtx7UB?!5Un#vo?BT*fXYS31ua*J6E}I#bl=&NEoLDfrtdWW%SJi-C86 z-+@CwmBWizooB2xpf*q!s1Ll(^>=`kK%w&tEqMy9cnYm-3R&GLWOb*I)ty3CcZz)l za3wGtm{pxMo!+DRff61Beq+u}2GEc^eq$n^i^-ha&2b9l zdXVoAkri1Bkj=4o0%T9@KZq4IwcSuFhgvDr_CRe9)b>Da57c%;Z4cCTLv0V#%AvL! zYP+Gf8*00uwi{}DpthS;gDzkD^>bMqxY_wY{ej4vHytftSb$3zRE_8t8FNFQ-8y^~*@@2T1Eso4$m`!;iT0lAPUs~PLF zmQlCA&5{H83GR0@Zgd*=uy&IEbwm0Ii&?AI&?trWK4+0phR#%xGf`wW)5x#1AbZut z*{ZtH#>xGta{xyDc*Yhr-1$`93hr2VGvPvOPafa)krid0pi!IN?3Y|$19#uiGmXOC zc6y@g6mzHOE6s(ob*!lv>Wt%^#7`LGs+Jk|C;nnQnE1q)=A3Li=3ImfMj(Tyjb%={ z@#X(%@66+?D6&0XT~#+EA&`Y70a*nU5di_0Q3eGS6$BJqP!tygHxLAz4RypB(dW## z`v!4FaZi9SE+`(u%ESS;Y_Ljfxf2qaXE1K#w`p<#e;PqJp~A;ptaWpV}r2 z>rkf})TuVTA)oSfp+`)mZuO{J7wT4I2;P!zzUIZ=u5|k^QhHa zYPHuHU0 zTB9#@`fKnW>uEN?pEXFe4N7f?N?(zBI~4c|3Tz_Q+x+p{ljjZO%lAF_GmEl{UT`L9 zHj`$Xen}lipOLw8bc7LK1o=n`<{sd-fzV+lB`Xi7(_-(FZWigDqgCD_?INBxiINHz zuP2YCJa;MiEP>)*LW55!;YMii8SOnVe1bBZjqi4Rx8wU2GH(U{{cJV$sPTI8*+7lg zQ`2?Sbgg`&E4R+oQf2bbPi@-f5!&KwGoN++Wl(WNSWJD&;qY~7TF+-FS)}!Z0?f_~ z;D6GAaDOMZ%Kd;=e}VFpnc)>PY4O(N+M5=?lNNuJ+D_vMi{ay&Xyq$t<=c4D5Ge34 zt$a1DJepP>#FL+dk8`2QdiZz}r5FPr-wcJGgO6{7k8g&Le-9tu2*v&g#U?l+ z@bLur_(sb3JbWw^yn&ieq^*ZR$&J+J8mM_M)GURM$HK?CQ1zZl*)R+G&4PZjX!~dl zZ$33zD?AK!R}i{_&=rKrSYN0my4o^YUi7qEX*H23k~WuqkVD$fNn5+Jy&|cT0ev<= z3*qYZglr*K`Fh(*x^ZwZ^Kga{G3~G!O00r=SJPgrkyd>D8Ba@>;o3o}9i-w9XMFg3 zS+u;y*36MV!)i}0ypn&pTJgVd(iFtba2<4wO@8dCyvlu*U$~xSH@!#7(Hxup@TVuQtei{BTd`x4>zt)EOnDBPa+3XHcrsbjZVTpz< zMiNRK(6aV6k}ft-u+oITOO}{)RsM1KfnUQ3KOHxsM<}BrHS~2s53Sbhzbr9TQurapJCgt^K4@ByUckD7E|OKtTZ zO;!~cZiH($!PUyg;it&612(+TO!#;lJ!Dog`~Z7J_*gh2WCb~LET7ezQ^JMeTG|~< z9x*(L-X^pNkKp{0_kszRR)(=6FLE8I9d720q=q#q`;N5f~syV%KfCQO;bt;KV$T?2GUbbRe_{duLo-YbT!%4d(8hBDxpqMo&#X zyZV?1;v1sZCBM%pFSLc;vE-_x^nv72SuWNOX-+EV;DR+jk(L%z83m#UI(&5SKNg?2 z=`S!5J(E=Z1zA)ksgzI3AIjfwTs0;y=@;Ibbf>y1d$8~>D`W_%?5p9zD3;JorC(*D zaB;=UygSoOcx>A3kKUw8t^G$7?025~4&y!(?g+<*0rLli>t@xU6#7a{szvjl2i*pPYNrXs_#BmSg%73vx zX~L7kIbkR4USZd;El(Lmk{TQ)JTx4ils=586OvhYZ^a+@a+Elx;xg`Y#P?^LpCL!% zu}|tVlCmqD9?nh;NxJ!#G}LWVI8jD5;gix2)fDJ^5!t%0p??pL^9%orRQm2Fo;4Gh zsn5VwlOvEf9e$FNV`O|7T$Hq22CmR`XqR zjM>7`mEEYnV0Fzm94CT<@IBuP6(%&@10N(n`V%CC9*Tr;sv;qr76=AHFU3IUqZkNh zDF#A6#X#t<7ziLBfPnx40vHJADF(s-#XvY841_z(g~6S{U1qRiAPiCTgQ1FkaD}2D zT&3s-!xa5sxS}77RP=-E6#Zb7q92S_^n>da{ouEtA3SM(r-%oSfOs(9JgLYAFACO< znXAYKuPd^_d_^``pvVRb!QRVRHR(ykU#Wz@@_y$WA-(Z>I8+@qv1}hcc z;3LI1_*n4`K2dywRbcbfHLJnrsc+VR(NkpBg45H`tOKj3ky#I3PZP62F%Vcmba&0vkaP4>~I1!BHR{ECm%ounxK_*1^e&b#RJe9rRGFgPw|YaHe7%oCVgwcR_ze zIk;F+4lY%cgCUA?aD}2AT&XArBNXLef}$Kes3-?d`^)@gL9xHwUmlbw;=yD^Ja|SC z51v)TgXb0TV7ek6yr_r=GZgV)rXn89QN)8+6!BoLA|A|B#Dn>Yc(6bb4;Crn!D2-` zC|AS-R9xMSBL9h-!R;+_h6zgD>VjZkjtb;X*b+A^k4%R8w0rL;R z810`8w0}0x{@GmnXLI^zEBdP7&^H2&Mr@~WWPpj%1Ic(QN1^urOzr=k z{@)K7(VxSCTXHsW1Rbh4iY%2BUL{2hl@!fXMid|+KB3<0Ihr9SHe!pUXsD6`OazV^Dk+*GDJnp54LNG4 zylATOqN&OYi@YdernLcx5RHR|tQgNicC;gA`=Gr!IOu>JX^0%@WD0`LL1$1DjsjPu zrplC>DpP7AO->^8WN=mLsvHTBBNqxvKkH};fx%vL)EUyeuovaSQ576O}tnRPNMLxs$7Mr;f@U z!G9YI{+pn#)JE>yYAo1b<4qm#!R{~#Fv0F8^Z`4;WP`?n_Qp=MlR!*+6m3hPBC}*7 zrzRV3r-0AmkXA34EKtK#m}KR+m!Q+h z1f6Ut?q%q9GQlZ(1NWQgcrxt@yMl6xl+0EsSyQECkxI!Tm6Am&C5!A13-XuUX?J4p zvfp5TYrlmKyX|i3xX13n{hj>|_xJXD+&|bKa0_ZoJ(a5URI1ifsVYcktom1}T3e-R zwo27(m8#h)RkKy9W~)@qR;hXrQWf2oYrzWrEO60U;%?5eolTt_5wu1aLq>LZbJMIsYA#0@b`+)#IwX(@6UAMj|1Ki-Wu z7Sy%dOaj!kJHS8t3n(Wdsqe)9E_at{1P0sPgx=%s;feRV`_Y#E-Tj@I6Wj!FPabp+ zQqzfUBB>r?omK(JZ2!bP$xSj|q`Yw=<*5Y&DY;E^)6Bu(wmoOE1-p$rUtn!l zD-hh^B2e6B@Z6bhCUIuDS;U{?B4ol>dE#6**VF;kZ642k&ArAGUw5yY3^yO`T_$gf zg*>Iqm6;lD5xTrWuyPjj^m11Y!p0Ibdzo&jTWT8eMtKYWw?T3_NZu>hVCZ140M8}I zeaQa?S#Bko;|9EAR$;GkYpBs$)|*+k&arO6t#|7w8#p`Ux!G+tjUBigqylY+5^hIx zSP16M4szqKYy7`veOiIr<#th$Z&{~i-EOy=eD<(j&ARX0cepED1$l;O95Z=)fwAd< z&@%-d17bx@&)Cc7_#ETpeTH4&3rr2r?CO|SzAk#|EMJcmZ>@ZN{&&dog{*vQ<%@g~ z?k22!v%aZsYBGE?-wbzi-yHYBtc0_^g=cM$Z^?={>s$F&xDR1vob`wLLvgoeg`D+= z`NMFxVWph)hx@~Ew`Ikg^+)(4aJOUSob~N}d)ysZL1)3yKN5FG-w}5w-wAhT-x>E& z{wUl>`=d?5AA=4x(;w@P#r-REshR#be;n@P(Wz$oF1`!yU;AIwTra#f2 zh`XEbhP%7(j{78Zu9^O1e=_b<(7k5zUhfI5dih>Z=?s4c?%uvP?moT`?!LY+?lb+F zxXYiZruXCgIJAtn_*?J?L5Ver zASjV)f}dc#e~{IM)=%_|yZuA{A?o#re}s}u@{=e7m`bJ|BaEj^BmcC28XhS2#e{;d zgk6dr)B9|&b8*u}Jvu?uc+n(zmwi8$ai@g)HEG}q*;Zqn6|_j1F1zf!94kuMWl=^tHNRK=2e zIR#B5n-NTXMk|6rooe`+qa1R`HE95`WZVMcDqhSDFkZ^Su7{m6mzs?Ji(GNJ_m|jK zl_+xQcj*2i@8h3A-Gw?yBXyBlh;h-S(vIq%o_|f!Hz2%bWt@DyHef_1rkUD%Tas%% zPNCjGYKxET3)x)nB)<4WPY*PX_$4WkUSbK8P*3Z{c%2cNY?3xn9I>NZllS?RWf7mK z7RhHzdI=Z*W|S`7G@xY3k|y(YnkM3yIEBziOtM5#>d1G0c2hW9G#Yi`bFt+bnTA!a z{iXd+_zO?}lqux9p(T+D_%;A@9&KoJrlu3W*wi9M`us+brZJ?COrtpJey>psNheQ_ z(@FHyC+#6jMmndT(j((Dn>ti?)+bI5brWfxTXjm#Nov-j{gX#^+>;4UMTg91$x&FDBKDUY zV^f`99G1LBv7-AX^cp!L{*Rv_*Ooj<_S+B>OFY(?rQD~!rJ_3JAbX_N(o#ZOk=AIb zp@NtM?sWMbwamd)`D?UF`dBEO4_}C6j^1)v$U?b`<$@z$p>li*wM9ya5!)$G$(^JU zBN952&5B+(^L zDPwkUnZ4Ke{b0GD7PUNB?xIfX6D5{-Og=hZtvH(H}13h^&*s6ZQWn3D&HDElC#7WK99?gL0oCi z>dR4G?3zC-wn+H>=PlA8E=l4?N?kO#v98anFI z!DcERmzo#Vep&5B!>+x4xLH1I#Nc7(J+(hldoA9h%x5Dc^ox;V?;JgR@JO>~^l0`b zGT0r14D3!p4tD3D0Q;z*2>a-u3HC8T%Q2)1+Gx44XvwHoOTUr2$eZ118_M`8(0(E< zou#M57q^6n{0NX$VoNU*2_SZqF5;7jK2aYK?qzLvW&FE8(myi4-NiX_uKc?BL-VH=)GioSaC5;k z1#gj3QiCBK>@ju8T;F0OU3G1w5S57x1> z(Hds)Rt29hqxVs;5(MQH%<#P*ycfJ1yc4|5E)bsuo9t+Ny&YqJV@KKF+J5W_@j3H+ zTZ1oxFN19X7`N;Xv6I~)b_L%A-v+ybJ;8VE67fS&0f7TwVJ-Vac$;ANu^Kj$eIl}L zO?$kp#mr!?&GX-~XG9%a*Vbd#h(cRr8`y(vBiqC_mf0lck~+FhuCqJJ9qo>B$GTs+ zP~Pcx^AvJb4(|@Q(O;ssyoe{?s~dj?hIy}`nbOCOm~*+=lV1AbdEdM zo#zI)^W6n*pu5mrP!g_eXcL8|Q9ue{z3zw=%qu@6M%unSX;X&*lE# ze0jd@-|_GI_x$^Of3EN!`j!48zCl0ntNd!e#;^73{CdB^Z}guAAz!7N_$K|_Z}D6G z7ye7Xjc?N(>|U{xuhU%#m+puwjfb6A@AV--!bC<;*Jr? zp8pXD;@AC>K5j3!qg@B-em-Co?+&*ES zv`^WmZLuvuqcg=$wWW5N{g-{lK5L(|&x>XUjm|8zH*?U`%tI@)06olNbS}%#ul(D- zZQr%;qhncVKensv8oS>!|o9@2#>nQ(I7mD{@`g>>`KreOmS10?Vs-! z2o65;`-_>^U&4I;GWUji(=B&kmbiD^d+r0~@4sXQ{wwCtGktAl#&2TI^-umbc6sJc z7v9?$j33*W?zGw{+DS&o0X_k(C4F1IF9O;+>HoVF|2`@Hmn8k|niPN8O{g*-Cwtn( z`FBY1U!LM$l=Szf>nN$%OeImv;7~?8Rq}>1X4p&F$LTUV*j}Q$DrE>y+BHyMIVt6f zNq05M=*W&0qs$X#8v6{Do9~0#Xfk`U7u8L{-RwEFi*driwu|k5QbBp=WMuZ>A0#paED@?3-av0S&;K$uhG|?E+?@pTbotE_8#W-~{iB zIc&?G1H~Gap6~4v3(bM#dmDB!ngjAhXCV1Lggup0@_2x2iG5FU(kF?3>0YJ$tHklA zNr?RmcCqh)J%u$FlG{JAr_x55QZwe#CBIL#Wb#jn>{6y7c9VvDt|6kMF6E>IZngM( z(Nv@JVk8>PpS85x#ovCV@zHm&OZMNfi|t+5lNsUWF)D7t+&~+&@kcXD@9-_L_ed&q z8pOAEOMG-1Qr7#hC!-mNDLM;R34D-EKJ`r_TOs!_pip!+?o$7##;q*9ldsqkm#yJ* zB%D)95B4Z2UR9sH%QUaDO#dxu(S}Hwgx;*3z@EZ75-HQ;*l}yj$6bmxL24L3`CaZx z&?FFo7LL?uR1zLx6^4eckWjQM($ZtF;SVjNtZOJi3n8UW=M&+C5_DZsvWeKm=(>bj z(x#KW_(c5oG_HvMr0y~QP0_l`-QM|1ol4MINxqL^7o)S1QXP*y+5ZDO%2z3)d?)nO zCuqN};u`-i{7dX-`lM$yPRvi6HDrs1Jg*^9ZP$oD8XU`WMu2e1x<=zGQ4C$$*=$|BR+?ELquc_g$ zNI0i(QLg&TRiE^dNS#akU?y7u_GJGAcFa2qaF?QklG?=2qhFJ{OhVi{ z*y+48T|=+aQ0dFX=;Wl8uE&mf=MdZ_=&q!!$RBsO+^g$|Dp%Vo7rISCQ>iYTQ({Ga z75h`Mr`VO)ll{ZkQ&VI50r-^oOR!7*1=z*@LhLDi5ccG>nCIhD!k?lNb0Bsxe~wDb zi?P#V4#lU$UyEJpuf#6)S7T4{!?4q1UV%@EAAw!!ufi_&*I-Za!?Dp7B7>jACA^-` zdYQv`e;m&Gy9DcjIwRkXX0;D^Gpz7oj}k^f^%({AMk~^nv5&0h8;G2eF;5#aj-##l z6UPyZf5tN>BRf2{X9V;&H&C*qe$zHnRc3jEU3^bUk$d#A)j~_&c7&C(Ia;}wy*lN|?br+F z0z1eKu;OnrFSLDaPut6$VSC#?y!RW~{#JT0>lBzzG`;HNzmL57kXtWu9%35W{^Z${9BpNe=h#8K)zWgI zEElDe?0iaf0o<9of1~W)SeH~XHX*;b#5{xYQp%K4NEs+;+7tXe{@!F9%6T92jSYB1 z*XKEsXJckI>yb)0F4EaG!YANKeQB}&)FKnQ4PuSd5NcJYDtEXy7{?vE0+BM}85wuV zD0G6ZkWQ>NiLRa$# ZcAgz$Pp~K2ZnnEU$(~HkLK9l*e*jr~ZsGs{ literal 0 HcmV?d00001 From 3ba9caa1184687611affb4ce5b4b7378a92c98b3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 6 Aug 2024 02:50:36 +0100 Subject: [PATCH 2163/2607] socket: socket::set_sockaddr() for IPv4 addresses in IPv6 builds (#7196) --- esphome/components/socket/socket.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index b200046d7f..5d3528dad8 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -19,24 +19,22 @@ std::unique_ptr socket_ip(int type, int protocol) { socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) { #if USE_NETWORK_IPV6 - if (addrlen < sizeof(sockaddr_in6)) { - errno = EINVAL; - return 0; - } - auto *server = reinterpret_cast(addr); - memset(server, 0, sizeof(sockaddr_in6)); - server->sin6_family = AF_INET6; - server->sin6_port = htons(port); + if (ip_address.find(':') != std::string::npos) { + if (addrlen < sizeof(sockaddr_in6)) { + errno = EINVAL; + return 0; + } + auto *server = reinterpret_cast(addr); + memset(server, 0, sizeof(sockaddr_in6)); + server->sin6_family = AF_INET6; + server->sin6_port = htons(port); - if (ip_address.find('.') != std::string::npos) { - server->sin6_addr.un.u32_addr[3] = inet_addr(ip_address.c_str()); - } else { ip6_addr_t ip6; inet6_aton(ip_address.c_str(), &ip6); memcpy(server->sin6_addr.un.u32_addr, ip6.addr, sizeof(ip6.addr)); + return sizeof(sockaddr_in6); } - return sizeof(sockaddr_in6); -#else +#endif /* USE_NETWORK_IPV6 */ if (addrlen < sizeof(sockaddr_in)) { errno = EINVAL; return 0; @@ -47,7 +45,6 @@ socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::stri server->sin_addr.s_addr = inet_addr(ip_address.c_str()); server->sin_port = htons(port); return sizeof(sockaddr_in); -#endif /* USE_NETWORK_IPV6 */ } socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) { From 7074fa06ae98c8f42821269b3fcfcce7f052854e Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Mon, 5 Aug 2024 23:53:52 -0400 Subject: [PATCH 2164/2607] Adds MQTT component to Alarm Control panel component (#7188) --- .../alarm_control_panel/__init__.py | 141 ++++++++++-------- esphome/components/mqtt/__init__.py | 21 +-- .../mqtt/mqtt_alarm_control_panel.cpp | 128 ++++++++++++++++ .../mqtt/mqtt_alarm_control_panel.h | 39 +++++ tests/components/mqtt/common.yaml | 6 + 5 files changed, 260 insertions(+), 75 deletions(-) create mode 100644 esphome/components/mqtt/mqtt_alarm_control_panel.cpp create mode 100644 esphome/components/mqtt/mqtt_alarm_control_panel.h diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 7ad4358011..8987d708fd 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -1,16 +1,17 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import web_server from esphome import automation from esphome.automation import maybe_simple_id -from esphome.core import CORE, coroutine_with_priority +import esphome.codegen as cg +from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( + CONF_CODE, CONF_ID, + CONF_MQTT_ID, CONF_ON_STATE, CONF_TRIGGER_ID, - CONF_CODE, CONF_WEB_SERVER_ID, ) +from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@grahambrown11", "@hwstar"] @@ -77,67 +78,72 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_( "AlarmControlPanelCondition", automation.Condition ) -ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( - web_server.WEBSERVER_SORTING_SCHEMA -).extend( - { - cv.GenerateID(): cv.declare_id(AlarmControlPanel), - cv.Optional(CONF_ON_STATE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), - } - ), - cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger), - } - ), - cv.Optional(CONF_ON_ARMING): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger), - } - ), - cv.Optional(CONF_ON_PENDING): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger), - } - ), - cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger), - } - ), - cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger), - } - ), - cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger), - } - ), - cv.Optional(CONF_ON_DISARMED): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger), - } - ), - cv.Optional(CONF_ON_CLEARED): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger), - } - ), - cv.Optional(CONF_ON_CHIME): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger), - } - ), - cv.Optional(CONF_ON_READY): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger), - } - ), - } +ALARM_CONTROL_PANEL_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) + .extend( + { + cv.GenerateID(): cv.declare_id(AlarmControlPanel), + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( + mqtt.MQTTAlarmControlPanelComponent + ), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), + } + ), + cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger), + } + ), + cv.Optional(CONF_ON_ARMING): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger), + } + ), + cv.Optional(CONF_ON_PENDING): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger), + } + ), + cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger), + } + ), + cv.Optional(CONF_ON_DISARMED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger), + } + ), + cv.Optional(CONF_ON_CLEARED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger), + } + ), + cv.Optional(CONF_ON_CHIME): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger), + } + ), + cv.Optional(CONF_ON_READY): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger), + } + ), + } + ) ) ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id( @@ -192,6 +198,9 @@ async def setup_alarm_control_panel_core_(var, config): if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: web_server_ = await cg.get_variable(webserver_id) web_server.add_entity_to_sorting_list(web_server_, var, config) + if mqtt_id := config.get(CONF_MQTT_ID): + mqtt_ = cg.new_Pvariable(mqtt_id, var) + await mqtt.register_mqtt_component(mqtt_, config) async def register_alarm_control_panel(var, config): diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index f4bd34bfd3..240b407819 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -1,10 +1,11 @@ import re -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition +import esphome.codegen as cg from esphome.components import logger +from esphome.components.esp32 import add_idf_sdkconfig_option +import esphome.config_validation as cv from esphome.const import ( CONF_AVAILABILITY, CONF_BIRTH_MESSAGE, @@ -13,21 +14,21 @@ from esphome.const import ( CONF_CLIENT_CERTIFICATE, CONF_CLIENT_CERTIFICATE_KEY, CONF_CLIENT_ID, - CONF_COMMAND_TOPIC, CONF_COMMAND_RETAIN, + CONF_COMMAND_TOPIC, CONF_DISCOVERY, + CONF_DISCOVERY_OBJECT_ID_GENERATOR, CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_DISCOVERY_UNIQUE_ID_GENERATOR, - CONF_DISCOVERY_OBJECT_ID_GENERATOR, CONF_ID, CONF_KEEPALIVE, CONF_LEVEL, CONF_LOG_TOPIC, - CONF_ON_JSON_MESSAGE, - CONF_ON_MESSAGE, CONF_ON_CONNECT, CONF_ON_DISCONNECT, + CONF_ON_JSON_MESSAGE, + CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PAYLOAD_AVAILABLE, @@ -45,12 +46,11 @@ from esphome.const import ( CONF_USE_ABBREVIATIONS, CONF_USERNAME, CONF_WILL_MESSAGE, + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, - PLATFORM_BK72XX, ) -from esphome.core import coroutine_with_priority, CORE -from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.core import CORE, coroutine_with_priority DEPENDENCIES = ["network"] @@ -110,6 +110,9 @@ MQTTDisconnectTrigger = mqtt_ns.class_( MQTTComponent = mqtt_ns.class_("MQTTComponent", cg.Component) MQTTConnectedCondition = mqtt_ns.class_("MQTTConnectedCondition", Condition) +MQTTAlarmControlPanelComponent = mqtt_ns.class_( + "MQTTAlarmControlPanelComponent", MQTTComponent +) MQTTBinarySensorComponent = mqtt_ns.class_("MQTTBinarySensorComponent", MQTTComponent) MQTTClimateComponent = mqtt_ns.class_("MQTTClimateComponent", MQTTComponent) MQTTCoverComponent = mqtt_ns.class_("MQTTCoverComponent", MQTTComponent) diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp new file mode 100644 index 0000000000..660a030d11 --- /dev/null +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp @@ -0,0 +1,128 @@ +#include "mqtt_alarm_control_panel.h" +#include "esphome/core/log.h" + +#include "mqtt_const.h" + +#ifdef USE_MQTT +#ifdef USE_ALARM_CONTROL_PANEL + +namespace esphome { +namespace mqtt { + +static const char *const TAG = "mqtt.alarm_control_panel"; + +using namespace esphome::alarm_control_panel; + +MQTTAlarmControlPanelComponent::MQTTAlarmControlPanelComponent(AlarmControlPanel *alarm_control_panel) + : alarm_control_panel_(alarm_control_panel) {} +void MQTTAlarmControlPanelComponent::setup() { + this->alarm_control_panel_->add_on_state_callback([this]() { this->publish_state(); }); + this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &payload) { + auto call = this->alarm_control_panel_->make_call(); + if (strcasecmp(payload.c_str(), "ARM_AWAY") == 0) { + call.arm_away(); + } else if (strcasecmp(payload.c_str(), "ARM_HOME") == 0) { + call.arm_home(); + } else if (strcasecmp(payload.c_str(), "ARM_NIGHT") == 0) { + call.arm_night(); + } else if (strcasecmp(payload.c_str(), "ARM_VACATION") == 0) { + call.arm_vacation(); + } else if (strcasecmp(payload.c_str(), "ARM_CUSTOM_BYPASS") == 0) { + call.arm_custom_bypass(); + } else if (strcasecmp(payload.c_str(), "DISARM") == 0) { + call.disarm(); + } else if (strcasecmp(payload.c_str(), "PENDING") == 0) { + call.pending(); + } else if (strcasecmp(payload.c_str(), "TRIGGERED") == 0) { + call.triggered(); + } else { + ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name().c_str(), payload.c_str()); + } + call.perform(); + }); +} + +void MQTTAlarmControlPanelComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT alarm_control_panel '%s':", this->alarm_control_panel_->get_name().c_str()); + LOG_MQTT_COMPONENT(true, true) + ESP_LOGCONFIG(TAG, " Supported Features: %" PRIu32, this->alarm_control_panel_->get_supported_features()); + ESP_LOGCONFIG(TAG, " Requires Code to Disarm: %s", YESNO(this->alarm_control_panel_->get_requires_code())); + ESP_LOGCONFIG(TAG, " Requires Code To Arm: %s", YESNO(this->alarm_control_panel_->get_requires_code_to_arm())); +} + +void MQTTAlarmControlPanelComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { + JsonArray supported_features = root.createNestedArray(MQTT_SUPPORTED_FEATURES); + const uint32_t acp_supported_features = this->alarm_control_panel_->get_supported_features(); + if (acp_supported_features & ACP_FEAT_ARM_AWAY) { + supported_features.add("arm_away"); + } + if (acp_supported_features & ACP_FEAT_ARM_HOME) { + supported_features.add("arm_home"); + } + if (acp_supported_features & ACP_FEAT_ARM_NIGHT) { + supported_features.add("arm_night"); + } + if (acp_supported_features & ACP_FEAT_ARM_VACATION) { + supported_features.add("arm_vacation"); + } + if (acp_supported_features & ACP_FEAT_ARM_CUSTOM_BYPASS) { + supported_features.add("arm_custom_bypass"); + } + if (acp_supported_features & ACP_FEAT_TRIGGER) { + supported_features.add("trigger"); + } + root[MQTT_CODE_DISARM_REQUIRED] = this->alarm_control_panel_->get_requires_code(); + root[MQTT_CODE_ARM_REQUIRED] = this->alarm_control_panel_->get_requires_code_to_arm(); +} + +std::string MQTTAlarmControlPanelComponent::component_type() const { return "alarm_control_panel"; } +const EntityBase *MQTTAlarmControlPanelComponent::get_entity() const { return this->alarm_control_panel_; } + +bool MQTTAlarmControlPanelComponent::send_initial_state() { return this->publish_state(); } +bool MQTTAlarmControlPanelComponent::publish_state() { + bool success = true; + const char *state_s = ""; + switch (this->alarm_control_panel_->get_state()) { + case ACP_STATE_DISARMED: + state_s = "disarmed"; + break; + case ACP_STATE_ARMED_HOME: + state_s = "armed_home"; + break; + case ACP_STATE_ARMED_AWAY: + state_s = "armed_away"; + break; + case ACP_STATE_ARMED_NIGHT: + state_s = "armed_night"; + break; + case ACP_STATE_ARMED_VACATION: + state_s = "armed_vacation"; + break; + case ACP_STATE_ARMED_CUSTOM_BYPASS: + state_s = "armed_custom_bypass"; + break; + case ACP_STATE_PENDING: + state_s = "pending"; + break; + case ACP_STATE_ARMING: + state_s = "arming"; + break; + case ACP_STATE_DISARMING: + state_s = "disarming"; + break; + case ACP_STATE_TRIGGERED: + state_s = "triggered"; + break; + default: + state_s = "unknown"; + } + if (!this->publish(this->get_state_topic_(), state_s)) + success = false; + return success; +} + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.h b/esphome/components/mqtt/mqtt_alarm_control_panel.h new file mode 100644 index 0000000000..4ad37b7314 --- /dev/null +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/core/defines.h" + +#ifdef USE_MQTT +#ifdef USE_ALARM_CONTROL_PANEL + +#include "mqtt_component.h" +#include "esphome/components/alarm_control_panel/alarm_control_panel.h" + +namespace esphome { +namespace mqtt { + +class MQTTAlarmControlPanelComponent : public mqtt::MQTTComponent { + public: + explicit MQTTAlarmControlPanelComponent(alarm_control_panel::AlarmControlPanel *alarm_control_panel); + + void setup() override; + + void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override; + + bool send_initial_state() override; + + bool publish_state(); + + void dump_config() override; + + protected: + std::string component_type() const override; + const EntityBase *get_entity() const override; + + alarm_control_panel::AlarmControlPanel *alarm_control_panel_; +}; + +} // namespace mqtt +} // namespace esphome + +#endif +#endif // USE_MQTT diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index a2a751df63..b7d1655ec9 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -426,3 +426,9 @@ valve: } else { return VALVE_CLOSED; } + +alarm_control_panel: + - platform: template + name: Alarm Control Panel + binary_sensors: + - input: some_binary_sensor From 71ea2cec1f21d5ea66c84f7bbe2c063a705d063b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:56:48 +1000 Subject: [PATCH 2165/2607] [lvgl] Final stage (#7184) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/lvgl/__init__.py | 50 ++++++------- esphome/components/lvgl/automation.py | 2 +- .../components/lvgl/binary_sensor/__init__.py | 43 +++++++++++ esphome/components/lvgl/light/__init__.py | 32 +++++++++ esphome/components/lvgl/light/lvgl_light.h | 48 +++++++++++++ esphome/components/lvgl/lvgl_esphome.h | 13 ++-- esphome/components/lvgl/number/__init__.py | 52 ++++++++++++++ esphome/components/lvgl/number/lvgl_number.h | 33 +++++++++ esphome/components/lvgl/rotary_encoders.py | 2 +- esphome/components/lvgl/select/__init__.py | 46 ++++++++++++ esphome/components/lvgl/select/lvgl_select.h | 62 ++++++++++++++++ esphome/components/lvgl/sensor/__init__.py | 35 +++++++++ esphome/components/lvgl/styles.py | 4 +- esphome/components/lvgl/switch/__init__.py | 54 ++++++++++++++ esphome/components/lvgl/switch/lvgl_switch.h | 33 +++++++++ esphome/components/lvgl/text/__init__.py | 39 ++++++++++ esphome/components/lvgl/text/lvgl_text.h | 33 +++++++++ .../components/lvgl/text_sensor/__init__.py | 40 +++++++++++ esphome/components/lvgl/touchscreens.py | 2 +- esphome/components/lvgl/trigger.py | 2 +- .../lvgl/{widget.py => widgets/__init__.py} | 12 ++-- .../components/lvgl/{ => widgets}/animimg.py | 14 ++-- esphome/components/lvgl/{ => widgets}/arc.py | 10 +-- .../components/lvgl/{ => widgets}/button.py | 4 +- .../lvgl/{ => widgets}/buttonmatrix.py | 20 +++--- .../components/lvgl/{ => widgets}/checkbox.py | 12 ++-- .../components/lvgl/{ => widgets}/dropdown.py | 12 ++-- esphome/components/lvgl/{ => widgets}/img.py | 10 +-- .../components/lvgl/{ => widgets}/keyboard.py | 8 +-- .../components/lvgl/{ => widgets}/label.py | 10 +-- esphome/components/lvgl/{ => widgets}/led.py | 10 +-- esphome/components/lvgl/{ => widgets}/line.py | 11 ++- .../components/lvgl/{ => widgets}/lv_bar.py | 12 ++-- .../components/lvgl/{ => widgets}/meter.py | 24 +++---- .../components/lvgl/{ => widgets}/msgbox.py | 72 ++++++++++--------- esphome/components/lvgl/{ => widgets}/obj.py | 8 +-- esphome/components/lvgl/{ => widgets}/page.py | 12 ++-- .../components/lvgl/{ => widgets}/roller.py | 10 +-- .../components/lvgl/{ => widgets}/slider.py | 12 ++-- .../components/lvgl/{ => widgets}/spinbox.py | 12 ++-- .../components/lvgl/{ => widgets}/spinner.py | 10 +-- .../lvgl/{lv_switch.py => widgets/switch.py} | 6 +- .../components/lvgl/{ => widgets}/tabview.py | 16 ++--- .../components/lvgl/{ => widgets}/textarea.py | 10 +-- .../components/lvgl/{ => widgets}/tileview.py | 16 ++--- tests/components/lvgl/common.yaml | 72 +++++++++++++++++++ 46 files changed, 840 insertions(+), 210 deletions(-) create mode 100644 esphome/components/lvgl/binary_sensor/__init__.py create mode 100644 esphome/components/lvgl/light/__init__.py create mode 100644 esphome/components/lvgl/light/lvgl_light.h create mode 100644 esphome/components/lvgl/number/__init__.py create mode 100644 esphome/components/lvgl/number/lvgl_number.h create mode 100644 esphome/components/lvgl/select/__init__.py create mode 100644 esphome/components/lvgl/select/lvgl_select.h create mode 100644 esphome/components/lvgl/sensor/__init__.py create mode 100644 esphome/components/lvgl/switch/__init__.py create mode 100644 esphome/components/lvgl/switch/lvgl_switch.h create mode 100644 esphome/components/lvgl/text/__init__.py create mode 100644 esphome/components/lvgl/text/lvgl_text.h create mode 100644 esphome/components/lvgl/text_sensor/__init__.py rename esphome/components/lvgl/{widget.py => widgets/__init__.py} (98%) rename esphome/components/lvgl/{ => widgets}/animimg.py (89%) rename esphome/components/lvgl/{ => widgets}/arc.py (92%) rename esphome/components/lvgl/{ => widgets}/button.py (82%) rename esphome/components/lvgl/{ => widgets}/buttonmatrix.py (95%) rename esphome/components/lvgl/{ => widgets}/checkbox.py (68%) rename esphome/components/lvgl/{ => widgets}/dropdown.py (89%) rename esphome/components/lvgl/{ => widgets}/img.py (92%) rename esphome/components/lvgl/{ => widgets}/keyboard.py (86%) rename esphome/components/lvgl/{ => widgets}/label.py (85%) rename esphome/components/lvgl/{ => widgets}/led.py (80%) rename esphome/components/lvgl/{ => widgets}/line.py (85%) rename esphome/components/lvgl/{ => widgets}/lv_bar.py (81%) rename esphome/components/lvgl/{ => widgets}/meter.py (96%) rename esphome/components/lvgl/{ => widgets}/msgbox.py (72%) rename esphome/components/lvgl/{ => widgets}/obj.py (76%) rename esphome/components/lvgl/{ => widgets}/page.py (91%) rename esphome/components/lvgl/{ => widgets}/roller.py (92%) rename esphome/components/lvgl/{ => widgets}/slider.py (88%) rename esphome/components/lvgl/{ => widgets}/spinbox.py (95%) rename esphome/components/lvgl/{ => widgets}/spinner.py (82%) rename esphome/components/lvgl/{lv_switch.py => widgets/switch.py} (72%) rename esphome/components/lvgl/{ => widgets}/tabview.py (88%) rename esphome/components/lvgl/{ => widgets}/textarea.py (90%) rename esphome/components/lvgl/{ => widgets}/tileview.py (89%) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index a963fca98b..9eb4665874 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -21,28 +21,10 @@ from esphome.final_validate import full_config from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid -from .animimg import animimg_spec -from .arc import arc_spec from .automation import disp_update, update_to_code -from .button import button_spec -from .buttonmatrix import buttonmatrix_spec -from .checkbox import checkbox_spec from .defines import CONF_SKIP -from .dropdown import dropdown_spec -from .img import img_spec -from .keyboard import keyboard_spec -from .label import label_spec -from .led import led_spec -from .line import line_spec -from .lv_bar import bar_spec -from .lv_switch import switch_spec from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent -from .meter import meter_spec -from .msgbox import MSGBOX_SCHEMA, msgboxes_to_code -from .obj import obj_spec -from .page import add_pages, page_spec -from .roller import roller_spec from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code from .schemas import ( DISP_BG_SCHEMA, @@ -57,13 +39,7 @@ from .schemas import ( grid_alignments, obj_schema, ) -from .slider import slider_spec -from .spinbox import spinbox_spec -from .spinner import spinner_spec from .styles import add_top_layer, styles_to_code, theme_to_code -from .tabview import tabview_spec -from .textarea import textarea_spec -from .tileview import tileview_spec from .touchscreens import touchscreen_schema, touchscreens_to_code from .trigger import generate_triggers from .types import ( @@ -74,7 +50,31 @@ from .types import ( lv_style_t, lvgl_ns, ) -from .widget import Widget, add_widgets, lv_scr_act, set_obj_properties +from .widgets import Widget, add_widgets, lv_scr_act, set_obj_properties +from .widgets.animimg import animimg_spec +from .widgets.arc import arc_spec +from .widgets.button import button_spec +from .widgets.buttonmatrix import buttonmatrix_spec +from .widgets.checkbox import checkbox_spec +from .widgets.dropdown import dropdown_spec +from .widgets.img import img_spec +from .widgets.keyboard import keyboard_spec +from .widgets.label import label_spec +from .widgets.led import led_spec +from .widgets.line import line_spec +from .widgets.lv_bar import bar_spec +from .widgets.meter import meter_spec +from .widgets.msgbox import MSGBOX_SCHEMA, msgboxes_to_code +from .widgets.obj import obj_spec +from .widgets.page import add_pages, page_spec +from .widgets.roller import roller_spec +from .widgets.slider import slider_spec +from .widgets.spinbox import spinbox_spec +from .widgets.spinner import spinner_spec +from .widgets.switch import switch_spec +from .widgets.tabview import tabview_spec +from .widgets.textarea import textarea_spec +from .widgets.tileview import tileview_spec DOMAIN = "lvgl" DEPENDENCIES = ["display"] diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index 7a862fb58b..556e286208 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -38,7 +38,7 @@ from .types import ( lv_disp_t, lv_obj_t, ) -from .widget import Widget, get_widgets, lv_scr_act, set_obj_properties +from .widgets import Widget, get_widgets, lv_scr_act, set_obj_properties async def action_to_code( diff --git a/esphome/components/lvgl/binary_sensor/__init__.py b/esphome/components/lvgl/binary_sensor/__init__.py new file mode 100644 index 0000000000..8789a06375 --- /dev/null +++ b/esphome/components/lvgl/binary_sensor/__init__.py @@ -0,0 +1,43 @@ +import esphome.codegen as cg +from esphome.components.binary_sensor import ( + BinarySensor, + binary_sensor_schema, + new_binary_sensor, +) +import esphome.config_validation as cv + +from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import EVENT_ARG, LambdaContext, LvContext +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, lv_pseudo_button_t +from ..widgets import Widget, get_widgets + +CONFIG_SCHEMA = ( + binary_sensor_schema(BinarySensor) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t), + } + ) +) + + +async def to_code(config): + sensor = await new_binary_sensor(config) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + assert isinstance(widget, Widget) + async with LambdaContext(EVENT_ARG) as pressed_ctx: + pressed_ctx.add(sensor.publish_state(widget.is_pressed())) + async with LvContext(paren) as ctx: + ctx.add(sensor.publish_initial_state(widget.is_pressed())) + ctx.add( + paren.add_event_cb( + widget.obj, + await pressed_ctx.get_lambda(), + LV_EVENT.PRESSING, + LV_EVENT.RELEASED, + ) + ) diff --git a/esphome/components/lvgl/light/__init__.py b/esphome/components/lvgl/light/__init__.py new file mode 100644 index 0000000000..27c160dff6 --- /dev/null +++ b/esphome/components/lvgl/light/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +from esphome.components import light +from esphome.components.light import LightOutput +import esphome.config_validation as cv +from esphome.const import CONF_GAMMA_CORRECT, CONF_LED, CONF_OUTPUT_ID + +from ..defines import CONF_LVGL_ID +from ..lvcode import LvContext +from ..schemas import LVGL_SCHEMA +from ..types import LvType, lvgl_ns +from ..widgets import get_widgets + +lv_led_t = LvType("lv_led_t") +LVLight = lvgl_ns.class_("LVLight", LightOutput) +CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( + { + cv.Optional(CONF_GAMMA_CORRECT, default=0.0): cv.positive_float, + cv.Required(CONF_LED): cv.use_id(lv_led_t), + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(LVLight), + } +).extend(LVGL_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) + await light.register_light(var, config) + + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_LED) + widget = widget[0] + async with LvContext(paren) as ctx: + ctx.add(var.set_obj(widget.obj)) diff --git a/esphome/components/lvgl/light/lvgl_light.h b/esphome/components/lvgl/light/lvgl_light.h new file mode 100644 index 0000000000..67372d89dd --- /dev/null +++ b/esphome/components/lvgl/light/lvgl_light.h @@ -0,0 +1,48 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/light/light_output.h" +#include "../lvgl_esphome.h" + +namespace esphome { +namespace lvgl { + +class LVLight : public light::LightOutput { + public: + light::LightTraits get_traits() override { + auto traits = light::LightTraits(); + traits.set_supported_color_modes({light::ColorMode::RGB}); + return traits; + } + void write_state(light::LightState *state) override { + float red, green, blue; + state->current_values_as_rgb(&red, &green, &blue, false); + auto color = lv_color_make(red * 255, green * 255, blue * 255); + if (this->obj_ != nullptr) { + this->set_value_(color); + } else { + this->initial_value_ = color; + } + } + + void set_obj(lv_obj_t *obj) { + this->obj_ = obj; + if (this->initial_value_) { + lv_led_set_color(obj, this->initial_value_.value()); + lv_led_on(obj); + this->initial_value_.reset(); + } + } + + protected: + void set_value_(lv_color_t value) { + lv_led_set_color(this->obj_, value); + lv_led_on(this->obj_); + lv_event_send(this->obj_, lv_custom_event, nullptr); + } + lv_obj_t *obj_{}; + optional initial_value_{}; +}; + +} // namespace lvgl +} // namespace esphome diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 71e0fd069f..5f2f0ea8df 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -1,13 +1,6 @@ #pragma once #include "esphome/core/defines.h" -#ifdef USE_LVGL_BINARY_SENSOR -#include "esphome/components/binary_sensor/binary_sensor.h" -#endif // USE_LVGL_BINARY_SENSOR -#ifdef USE_LVGL_ROTARY_ENCODER -#include "esphome/components/rotary_encoder/rotary_encoder.h" -#endif // USE_LVGL_ROTARY_ENCODER - // required for clang-tidy #ifndef LV_CONF_H #define LV_CONF_SKIP 1 // NOLINT @@ -19,6 +12,12 @@ #include "esphome/core/log.h" #include #include + +#ifdef USE_LVGL_ROTARY_ENCODER +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/rotary_encoder/rotary_encoder.h" +#endif // USE_LVGL_ROTARY_ENCODER + #ifdef USE_LVGL_IMAGE #include "esphome/components/image/image.h" #endif // USE_LVGL_IMAGE diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py new file mode 100644 index 0000000000..53aef2790d --- /dev/null +++ b/esphome/components/lvgl/number/__init__.py @@ -0,0 +1,52 @@ +import esphome.codegen as cg +from esphome.components import number +import esphome.config_validation as cv +from esphome.cpp_generator import MockObj + +from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET +from ..lv_validation import animated +from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LvNumber, lvgl_ns +from ..widgets import get_widgets + +LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number) + +CONFIG_SCHEMA = ( + number.number_schema(LVGLNumber) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(LvNumber), + cv.Optional(CONF_ANIMATED, default=True): animated, + } + ) +) + + +async def to_code(config): + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + var = await number.new_number( + config, + max_value=widget.get_max(), + min_value=widget.get_min(), + step=widget.get_step(), + ) + + async with LambdaContext([(cg.float_, "v")]) as control: + await widget.set_property( + "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] + ) + lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + async with LambdaContext(EVENT_ARG) as event: + event.add(var.publish_state(widget.get_value())) + async with LvContext(paren): + lv_add(var.set_control_lambda(await control.get_lambda())) + lv_add( + paren.add_event_cb( + widget.obj, await event.get_lambda(), LV_EVENT.VALUE_CHANGED + ) + ) + lv_add(var.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/number/lvgl_number.h b/esphome/components/lvgl/number/lvgl_number.h new file mode 100644 index 0000000000..461ea51be4 --- /dev/null +++ b/esphome/components/lvgl/number/lvgl_number.h @@ -0,0 +1,33 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace lvgl { + +class LVGLNumber : public number::Number { + public: + void set_control_lambda(std::function control_lambda) { + this->control_lambda_ = control_lambda; + if (this->initial_state_.has_value()) { + this->control_lambda_(this->initial_state_.value()); + this->initial_state_.reset(); + } + } + + protected: + void control(float value) { + if (this->control_lambda_ != nullptr) + this->control_lambda_(value); + else + this->initial_state_ = value; + } + std::function control_lambda_{}; + optional initial_state_{}; +}; + +} // namespace lvgl +} // namespace esphome diff --git a/esphome/components/lvgl/rotary_encoders.py b/esphome/components/lvgl/rotary_encoders.py index ede6905a67..d8a82dbc78 100644 --- a/esphome/components/lvgl/rotary_encoders.py +++ b/esphome/components/lvgl/rotary_encoders.py @@ -16,7 +16,7 @@ from .helpers import lvgl_components_required from .lvcode import lv, lv_add, lv_expr from .schemas import ENCODER_SCHEMA from .types import lv_indev_type_t -from .widget import add_group +from .widgets import add_group ROTARY_ENCODER_CONFIG = cv.ensure_list( ENCODER_SCHEMA.extend( diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py new file mode 100644 index 0000000000..34a70a23f7 --- /dev/null +++ b/esphome/components/lvgl/select/__init__.py @@ -0,0 +1,46 @@ +import esphome.codegen as cg +from esphome.components import select +import esphome.config_validation as cv +from esphome.const import CONF_OPTIONS + +from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LvSelect, lvgl_ns +from ..widgets import get_widgets + +LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select) + +CONFIG_SCHEMA = ( + select.select_schema(LVGLSelect) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(LvSelect), + cv.Optional(CONF_ANIMATED, default=False): cv.boolean, + } + ) +) + + +async def to_code(config): + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + options = widget.config.get(CONF_OPTIONS, []) + selector = await select.new_select(config, options=options) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + async with LambdaContext(EVENT_ARG) as pub_ctx: + pub_ctx.add(selector.publish_index(widget.get_value())) + async with LambdaContext([(cg.uint16, "v")]) as control: + await widget.set_property("selected", "v", animated=config[CONF_ANIMATED]) + lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + async with LvContext(paren) as ctx: + lv_add(selector.set_control_lambda(await control.get_lambda())) + ctx.add( + paren.add_event_cb( + widget.obj, + await pub_ctx.get_lambda(), + LV_EVENT.VALUE_CHANGED, + ) + ) + lv_add(selector.publish_index(widget.get_value())) diff --git a/esphome/components/lvgl/select/lvgl_select.h b/esphome/components/lvgl/select/lvgl_select.h new file mode 100644 index 0000000000..407045d605 --- /dev/null +++ b/esphome/components/lvgl/select/lvgl_select.h @@ -0,0 +1,62 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace lvgl { + +static std::vector split_string(const std::string &str) { + std::vector strings; + auto delimiter = std::string("\n"); + + std::string::size_type pos; + std::string::size_type prev = 0; + while ((pos = str.find(delimiter, prev)) != std::string::npos) { + strings.push_back(str.substr(prev, pos - prev)); + prev = pos + delimiter.size(); + } + + // To get the last substring (or only, if delimiter is not found) + strings.push_back(str.substr(prev)); + + return strings; +} + +class LVGLSelect : public select::Select { + public: + void set_control_lambda(std::function lambda) { + this->control_lambda_ = lambda; + if (this->initial_state_.has_value()) { + this->control(this->initial_state_.value()); + this->initial_state_.reset(); + } + } + + void publish_index(size_t index) { + auto value = this->at(index); + if (value) + this->publish_state(value.value()); + } + + void set_options(const char *str) { this->traits.set_options(split_string(str)); } + + protected: + void control(const std::string &value) override { + if (this->control_lambda_ != nullptr) { + auto index = index_of(value); + if (index) + this->control_lambda_(index.value()); + } else { + this->initial_state_ = value.c_str(); + } + } + + std::function control_lambda_{}; + optional initial_state_{}; +}; + +} // namespace lvgl +} // namespace esphome diff --git a/esphome/components/lvgl/sensor/__init__.py b/esphome/components/lvgl/sensor/__init__.py new file mode 100644 index 0000000000..6e495eb685 --- /dev/null +++ b/esphome/components/lvgl/sensor/__init__.py @@ -0,0 +1,35 @@ +import esphome.codegen as cg +from esphome.components.sensor import Sensor, new_sensor, sensor_schema +import esphome.config_validation as cv + +from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import EVENT_ARG, LVGL_COMP_ARG, LambdaContext, LvContext, lv_add +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LvNumber +from ..widgets import Widget, get_widgets + +CONFIG_SCHEMA = ( + sensor_schema(Sensor) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(LvNumber), + } + ) +) + + +async def to_code(config): + sensor = await new_sensor(config) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + assert isinstance(widget, Widget) + async with LambdaContext(EVENT_ARG) as lamb: + lv_add(sensor.publish_state(widget.get_value())) + async with LvContext(paren, LVGL_COMP_ARG): + lv_add( + paren.add_event_cb( + widget.obj, await lamb.get_lambda(), LV_EVENT.VALUE_CHANGED + ) + ) diff --git a/esphome/components/lvgl/styles.py b/esphome/components/lvgl/styles.py index 09f1c376d0..26c2694a52 100644 --- a/esphome/components/lvgl/styles.py +++ b/esphome/components/lvgl/styles.py @@ -12,10 +12,10 @@ from .defines import ( ) from .helpers import add_lv_use from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable -from .obj import obj_spec from .schemas import ALL_STYLES from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr -from .widget import Widget, add_widgets, set_obj_properties, theme_widget_map +from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map +from .widgets.obj import obj_spec TOP_LAYER = literal("lv_disp_get_layer_top(lv_component->get_disp())") diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py new file mode 100644 index 0000000000..831fa9308b --- /dev/null +++ b/esphome/components/lvgl/switch/__init__.py @@ -0,0 +1,54 @@ +import esphome.codegen as cg +from esphome.components.switch import Switch, new_switch, switch_schema +import esphome.config_validation as cv +from esphome.cpp_generator import MockObj + +from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import ( + CUSTOM_EVENT, + EVENT_ARG, + LambdaContext, + LvConditional, + LvContext, + lv, + lv_add, +) +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns +from ..widgets import get_widgets + +LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch) +CONFIG_SCHEMA = ( + switch_schema(LVGLSwitch) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t), + } + ) +) + + +async def to_code(config): + switch = await new_switch(config) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + async with LambdaContext(EVENT_ARG) as checked_ctx: + checked_ctx.add(switch.publish_state(widget.get_value())) + async with LambdaContext([(cg.bool_, "v")]) as control: + with LvConditional(MockObj("v")) as cond: + widget.add_state(LV_STATE.CHECKED) + cond.else_() + widget.clear_state(LV_STATE.CHECKED) + lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + async with LvContext(paren) as ctx: + lv_add(switch.set_control_lambda(await control.get_lambda())) + ctx.add( + paren.add_event_cb( + widget.obj, + await checked_ctx.get_lambda(), + LV_EVENT.VALUE_CHANGED, + ) + ) + lv_add(switch.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/switch/lvgl_switch.h b/esphome/components/lvgl/switch/lvgl_switch.h new file mode 100644 index 0000000000..f20f4ed960 --- /dev/null +++ b/esphome/components/lvgl/switch/lvgl_switch.h @@ -0,0 +1,33 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace lvgl { + +class LVGLSwitch : public switch_::Switch { + public: + void set_control_lambda(std::function state_lambda) { + this->state_lambda_ = state_lambda; + if (this->initial_state_.has_value()) { + this->state_lambda_(this->initial_state_.value()); + this->initial_state_.reset(); + } + } + + protected: + void write_state(bool value) { + if (this->state_lambda_ != nullptr) + this->state_lambda_(value); + else + this->initial_state_ = value; + } + std::function state_lambda_{}; + optional initial_state_{}; +}; + +} // namespace lvgl +} // namespace esphome diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py new file mode 100644 index 0000000000..55f1b2b3fc --- /dev/null +++ b/esphome/components/lvgl/text/__init__.py @@ -0,0 +1,39 @@ +import esphome.codegen as cg +from esphome.components import text +from esphome.components.text import new_text +import esphome.config_validation as cv + +from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LvText, lvgl_ns +from ..widgets import get_widgets + +LVGLText = lvgl_ns.class_("LVGLText", text.Text) + +CONFIG_SCHEMA = text.TEXT_SCHEMA.extend(LVGL_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(LVGLText), + cv.Required(CONF_WIDGET): cv.use_id(LvText), + } +) + + +async def to_code(config): + textvar = await new_text(config) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + async with LambdaContext([(cg.std_string, "text_value")]) as control: + await widget.set_property("text", "text_value.c_str())") + lv.event_send(widget.obj, CUSTOM_EVENT, None) + async with LambdaContext(EVENT_ARG) as lamb: + lv_add(textvar.publish_state(widget.get_value())) + async with LvContext(paren): + widget.var.set_control_lambda(await control.get_lambda()) + lv_add( + paren.add_event_cb( + widget.obj, await lamb.get_lambda(), LV_EVENT.VALUE_CHANGED + ) + ) + lv_add(textvar.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/text/lvgl_text.h b/esphome/components/lvgl/text/lvgl_text.h new file mode 100644 index 0000000000..8dc0281364 --- /dev/null +++ b/esphome/components/lvgl/text/lvgl_text.h @@ -0,0 +1,33 @@ +#pragma once + +#include "esphome/components/text/text.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace lvgl { + +class LVGLText : public text::Text { + public: + void set_control_lambda(std::function control_lambda) { + this->control_lambda_ = control_lambda; + if (this->initial_state_.has_value()) { + this->control_lambda_(this->initial_state_.value()); + this->initial_state_.reset(); + } + } + + protected: + void control(const std::string &value) { + if (this->control_lambda_ != nullptr) + this->control_lambda_(value); + else + this->initial_state_ = value; + } + std::function control_lambda_{}; + optional initial_state_{}; +}; + +} // namespace lvgl +} // namespace esphome diff --git a/esphome/components/lvgl/text_sensor/__init__.py b/esphome/components/lvgl/text_sensor/__init__.py new file mode 100644 index 0000000000..c0f0bc36a8 --- /dev/null +++ b/esphome/components/lvgl/text_sensor/__init__.py @@ -0,0 +1,40 @@ +import esphome.codegen as cg +from esphome.components.text_sensor import ( + TextSensor, + new_text_sensor, + text_sensor_schema, +) +import esphome.config_validation as cv + +from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..lvcode import EVENT_ARG, LambdaContext, LvContext +from ..schemas import LVGL_SCHEMA +from ..types import LV_EVENT, LvText +from ..widgets import get_widgets + +CONFIG_SCHEMA = ( + text_sensor_schema(TextSensor) + .extend(LVGL_SCHEMA) + .extend( + { + cv.Required(CONF_WIDGET): cv.use_id(LvText), + } + ) +) + + +async def to_code(config): + sensor = await new_text_sensor(config) + paren = await cg.get_variable(config[CONF_LVGL_ID]) + widget = await get_widgets(config, CONF_WIDGET) + widget = widget[0] + async with LambdaContext(EVENT_ARG) as pressed_ctx: + pressed_ctx.add(sensor.publish_state(widget.get_value())) + async with LvContext(paren) as ctx: + ctx.add( + paren.add_event_cb( + widget.obj, + await pressed_ctx.get_lambda(), + LV_EVENT.VALUE_CHANGED, + ) + ) diff --git a/esphome/components/lvgl/touchscreens.py b/esphome/components/lvgl/touchscreens.py index 499b33aa02..292b0873f3 100644 --- a/esphome/components/lvgl/touchscreens.py +++ b/esphome/components/lvgl/touchscreens.py @@ -34,7 +34,7 @@ def touchscreen_schema(config): async def touchscreens_to_code(var, config): - for tconf in config.get(CONF_TOUCHSCREENS) or (): + for tconf in config.get(CONF_TOUCHSCREENS, ()): lvgl_components_required.add(CONF_TOUCHSCREEN) touchscreen = await cg.get_variable(tconf[CONF_TOUCHSCREEN_ID]) lpt = tconf[CONF_LONG_PRESS_TIME].total_milliseconds diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index c640c8abd9..df87be718b 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -13,7 +13,7 @@ from .defines import ( ) from .lvcode import EVENT_ARG, LambdaContext, LvConditional, lv, lv_add from .types import LV_EVENT -from .widget import widget_map +from .widgets import widget_map async def generate_triggers(lv_component): diff --git a/esphome/components/lvgl/widget.py b/esphome/components/lvgl/widgets/__init__.py similarity index 98% rename from esphome/components/lvgl/widget.py rename to esphome/components/lvgl/widgets/__init__.py index fcaee29085..dff43cf257 100644 --- a/esphome/components/lvgl/widget.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -8,7 +8,7 @@ from esphome.core import ID, TimePeriod from esphome.coroutine import FakeAwaitable from esphome.cpp_generator import AssignmentExpression, CallExpression, MockObj -from .defines import ( +from ..defines import ( CONF_DEFAULT, CONF_FLEX_ALIGN_CROSS, CONF_FLEX_ALIGN_MAIN, @@ -32,8 +32,8 @@ from .defines import ( join_enums, literal, ) -from .helpers import add_lv_use -from .lvcode import ( +from ..helpers import add_lv_use +from ..lvcode import ( LvConditional, add_line_marks, lv, @@ -43,8 +43,8 @@ from .lvcode import ( lv_obj, lv_Pvariable, ) -from .schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES -from .types import ( +from ..schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES +from ..types import ( LV_STATE, LvType, WidgetType, @@ -368,7 +368,7 @@ async def add_widgets(parent: Widget, config: dict): :param config: The configuration :return: """ - for w in config.get(CONF_WIDGETS) or (): + for w in config.get(CONF_WIDGETS, ()): w_type, w_cnfig = next(iter(w.items())) await widget_to_code(w_cnfig, w_type, parent.obj) diff --git a/esphome/components/lvgl/animimg.py b/esphome/components/lvgl/widgets/animimg.py similarity index 89% rename from esphome/components/lvgl/animimg.py rename to esphome/components/lvgl/widgets/animimg.py index ad84713d7f..a973ca0702 100644 --- a/esphome/components/lvgl/animimg.py +++ b/esphome/components/lvgl/widgets/animimg.py @@ -4,15 +4,15 @@ import esphome.config_validation as cv from esphome.const import CONF_DURATION, CONF_ID from esphome.cpp_generator import MockObj -from .automation import action_to_code -from .defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC -from .helpers import lvgl_components_required +from ..automation import action_to_code +from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC +from ..helpers import lvgl_components_required +from ..lv_validation import lv_image, lv_milliseconds +from ..lvcode import lv, lv_expr +from ..types import LvType, ObjUpdateAction, void_ptr +from . import Widget, WidgetType, get_widgets from .img import CONF_IMAGE from .label import CONF_LABEL -from .lv_validation import lv_image, lv_milliseconds -from .lvcode import lv, lv_expr -from .types import LvType, ObjUpdateAction, void_ptr -from .widget import Widget, WidgetType, get_widgets CONF_ANIMIMG = "animimg" CONF_SRC_LIST_ID = "src_list_id" diff --git a/esphome/components/lvgl/arc.py b/esphome/components/lvgl/widgets/arc.py similarity index 92% rename from esphome/components/lvgl/arc.py rename to esphome/components/lvgl/widgets/arc.py index d036464c7a..a6f8918e2f 100644 --- a/esphome/components/lvgl/arc.py +++ b/esphome/components/lvgl/widgets/arc.py @@ -8,7 +8,7 @@ from esphome.const import ( ) from esphome.cpp_types import nullptr -from .defines import ( +from ..defines import ( ARC_MODES, CONF_ADJUSTABLE, CONF_CHANGE_RATE, @@ -19,10 +19,10 @@ from .defines import ( CONF_START_ANGLE, literal, ) -from .lv_validation import angle, get_start_value, lv_float -from .lvcode import lv, lv_obj -from .types import LvNumber, NumberType -from .widget import Widget +from ..lv_validation import angle, get_start_value, lv_float +from ..lvcode import lv, lv_obj +from ..types import LvNumber, NumberType +from . import Widget CONF_ARC = "arc" ARC_SCHEMA = cv.Schema( diff --git a/esphome/components/lvgl/button.py b/esphome/components/lvgl/widgets/button.py similarity index 82% rename from esphome/components/lvgl/button.py rename to esphome/components/lvgl/widgets/button.py index 96329b3fa9..b59884ee67 100644 --- a/esphome/components/lvgl/button.py +++ b/esphome/components/lvgl/widgets/button.py @@ -1,7 +1,7 @@ from esphome.const import CONF_BUTTON -from .defines import CONF_MAIN -from .types import LvBoolean, WidgetType +from ..defines import CONF_MAIN +from ..types import LvBoolean, WidgetType lv_button_t = LvBoolean("lv_btn_t") diff --git a/esphome/components/lvgl/buttonmatrix.py b/esphome/components/lvgl/widgets/buttonmatrix.py similarity index 95% rename from esphome/components/lvgl/buttonmatrix.py rename to esphome/components/lvgl/widgets/buttonmatrix.py index 75ed43f909..274b4de5ab 100644 --- a/esphome/components/lvgl/buttonmatrix.py +++ b/esphome/components/lvgl/widgets/buttonmatrix.py @@ -5,9 +5,8 @@ import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_WIDTH from esphome.cpp_generator import MockObj -from .automation import action_to_code -from .button import lv_button_t -from .defines import ( +from ..automation import action_to_code +from ..defines import ( BUTTONMATRIX_CTRLS, CONF_BUTTONS, CONF_CONTROL, @@ -19,11 +18,11 @@ from .defines import ( CONF_SELECTED, CONF_TEXT, ) -from .helpers import lvgl_components_required -from .lv_validation import key_code, lv_bool -from .lvcode import lv, lv_add, lv_expr -from .schemas import automation_schema -from .types import ( +from ..helpers import lvgl_components_required +from ..lv_validation import key_code, lv_bool +from ..lvcode import lv, lv_add, lv_expr +from ..schemas import automation_schema +from ..types import ( LV_BTNMATRIX_CTRL, LV_STATE, LvBoolean, @@ -33,7 +32,8 @@ from .types import ( char_ptr, lv_pseudo_button_t, ) -from .widget import Widget, WidgetType, get_widgets, widget_map +from . import Widget, WidgetType, get_widgets, widget_map +from .button import lv_button_t CONF_BUTTONMATRIX = "buttonmatrix" CONF_BUTTON_TEXT_LIST_ID = "button_text_list_id" @@ -151,7 +151,7 @@ async def get_button_data(config, buttonmatrix: Widget): width_list = [] key_list = [] for row in config: - for button_conf in row.get(CONF_BUTTONS) or (): + for button_conf in row.get(CONF_BUTTONS, ()): bid = button_conf[CONF_ID] index = len(width_list) MatrixButton.create_button(bid, buttonmatrix, button_conf, index) diff --git a/esphome/components/lvgl/checkbox.py b/esphome/components/lvgl/widgets/checkbox.py similarity index 68% rename from esphome/components/lvgl/checkbox.py rename to esphome/components/lvgl/widgets/checkbox.py index be7b029269..6299a2a6a2 100644 --- a/esphome/components/lvgl/checkbox.py +++ b/esphome/components/lvgl/widgets/checkbox.py @@ -1,9 +1,9 @@ -from .defines import CONF_INDICATOR, CONF_MAIN, CONF_TEXT -from .lv_validation import lv_text -from .lvcode import lv -from .schemas import TEXT_SCHEMA -from .types import LvBoolean -from .widget import Widget, WidgetType +from ..defines import CONF_INDICATOR, CONF_MAIN, CONF_TEXT +from ..lv_validation import lv_text +from ..lvcode import lv +from ..schemas import TEXT_SCHEMA +from ..types import LvBoolean +from . import Widget, WidgetType CONF_CHECKBOX = "checkbox" diff --git a/esphome/components/lvgl/dropdown.py b/esphome/components/lvgl/widgets/dropdown.py similarity index 89% rename from esphome/components/lvgl/dropdown.py rename to esphome/components/lvgl/widgets/dropdown.py index d7bdebaade..dc0346b080 100644 --- a/esphome/components/lvgl/dropdown.py +++ b/esphome/components/lvgl/widgets/dropdown.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_OPTIONS -from .defines import ( +from ..defines import ( CONF_DIR, CONF_INDICATOR, CONF_MAIN, @@ -11,12 +11,12 @@ from .defines import ( DIRECTIONS, literal, ) +from ..lv_validation import lv_int, lv_text, option_string +from ..lvcode import LocalVariable, lv, lv_expr +from ..schemas import part_schema +from ..types import LvSelect, LvType, lv_obj_t +from . import Widget, WidgetType, set_obj_properties from .label import CONF_LABEL -from .lv_validation import lv_int, lv_text, option_string -from .lvcode import LocalVariable, lv, lv_expr -from .schemas import part_schema -from .types import LvSelect, LvType, lv_obj_t -from .widget import Widget, WidgetType, set_obj_properties CONF_DROPDOWN = "dropdown" CONF_DROPDOWN_LIST = "dropdown_list" diff --git a/esphome/components/lvgl/img.py b/esphome/components/lvgl/widgets/img.py similarity index 92% rename from esphome/components/lvgl/img.py rename to esphome/components/lvgl/widgets/img.py index dd962fcf31..59b2c97c63 100644 --- a/esphome/components/lvgl/img.py +++ b/esphome/components/lvgl/widgets/img.py @@ -1,7 +1,7 @@ import esphome.config_validation as cv from esphome.const import CONF_ANGLE, CONF_MODE -from .defines import ( +from ..defines import ( CONF_ANTIALIAS, CONF_MAIN, CONF_OFFSET_X, @@ -12,11 +12,11 @@ from .defines import ( CONF_ZOOM, LvConstant, ) +from ..lv_validation import angle, lv_bool, lv_image, size, zoom +from ..lvcode import lv +from ..types import lv_img_t +from . import Widget, WidgetType from .label import CONF_LABEL -from .lv_validation import angle, lv_bool, lv_image, size, zoom -from .lvcode import lv -from .types import lv_img_t -from .widget import Widget, WidgetType CONF_IMAGE = "image" diff --git a/esphome/components/lvgl/keyboard.py b/esphome/components/lvgl/widgets/keyboard.py similarity index 86% rename from esphome/components/lvgl/keyboard.py rename to esphome/components/lvgl/widgets/keyboard.py index 7ce73d2170..cff322f5af 100644 --- a/esphome/components/lvgl/keyboard.py +++ b/esphome/components/lvgl/widgets/keyboard.py @@ -3,11 +3,11 @@ import esphome.config_validation as cv from esphome.const import CONF_MODE from esphome.cpp_types import std_string -from .defines import CONF_ITEMS, CONF_MAIN, KEYBOARD_MODES, literal -from .helpers import add_lv_use, lvgl_components_required +from ..defines import CONF_ITEMS, CONF_MAIN, KEYBOARD_MODES, literal +from ..helpers import add_lv_use, lvgl_components_required +from ..types import LvCompound, LvType +from . import Widget, WidgetType, get_widgets from .textarea import CONF_TEXTAREA, lv_textarea_t -from .types import LvCompound, LvType -from .widget import Widget, WidgetType, get_widgets CONF_KEYBOARD = "keyboard" diff --git a/esphome/components/lvgl/label.py b/esphome/components/lvgl/widgets/label.py similarity index 85% rename from esphome/components/lvgl/label.py rename to esphome/components/lvgl/widgets/label.py index 6c3e1f4a00..38f688f2b0 100644 --- a/esphome/components/lvgl/label.py +++ b/esphome/components/lvgl/widgets/label.py @@ -1,6 +1,6 @@ import esphome.config_validation as cv -from .defines import ( +from ..defines import ( CONF_LONG_MODE, CONF_MAIN, CONF_RECOLOR, @@ -9,10 +9,10 @@ from .defines import ( CONF_TEXT, LV_LONG_MODES, ) -from .lv_validation import lv_bool, lv_text -from .schemas import TEXT_SCHEMA -from .types import LvText, WidgetType -from .widget import Widget +from ..lv_validation import lv_bool, lv_text +from ..schemas import TEXT_SCHEMA +from ..types import LvText, WidgetType +from . import Widget CONF_LABEL = "label" diff --git a/esphome/components/lvgl/led.py b/esphome/components/lvgl/widgets/led.py similarity index 80% rename from esphome/components/lvgl/led.py rename to esphome/components/lvgl/widgets/led.py index 9b6e819278..647973c9b7 100644 --- a/esphome/components/lvgl/led.py +++ b/esphome/components/lvgl/widgets/led.py @@ -1,11 +1,11 @@ import esphome.config_validation as cv from esphome.const import CONF_BRIGHTNESS, CONF_COLOR, CONF_LED -from .defines import CONF_MAIN -from .lv_validation import lv_brightness, lv_color -from .lvcode import lv -from .types import LvType -from .widget import Widget, WidgetType +from ..defines import CONF_MAIN +from ..lv_validation import lv_brightness, lv_color +from ..lvcode import lv +from ..types import LvType +from . import Widget, WidgetType LED_SCHEMA = cv.Schema( { diff --git a/esphome/components/lvgl/line.py b/esphome/components/lvgl/widgets/line.py similarity index 85% rename from esphome/components/lvgl/line.py rename to esphome/components/lvgl/widgets/line.py index ab50832bbf..8ce4b1965f 100644 --- a/esphome/components/lvgl/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -3,11 +3,10 @@ import functools import esphome.codegen as cg import esphome.config_validation as cv -from . import defines as df -from .defines import CONF_MAIN, literal -from .lvcode import lv -from .types import LvType -from .widget import Widget, WidgetType +from ..defines import CONF_MAIN, literal +from ..lvcode import lv +from ..types import LvType +from . import Widget, WidgetType CONF_LINE = "line" CONF_POINTS = "points" @@ -32,7 +31,7 @@ def cv_point_list(value): LINE_SCHEMA = { - cv.Required(df.CONF_POINTS): cv_point_list, + cv.Required(CONF_POINTS): cv_point_list, cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t), } diff --git a/esphome/components/lvgl/lv_bar.py b/esphome/components/lvgl/widgets/lv_bar.py similarity index 81% rename from esphome/components/lvgl/lv_bar.py rename to esphome/components/lvgl/widgets/lv_bar.py index d5dcff0bf0..57209370c0 100644 --- a/esphome/components/lvgl/lv_bar.py +++ b/esphome/components/lvgl/widgets/lv_bar.py @@ -1,11 +1,13 @@ import esphome.config_validation as cv from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, CONF_VALUE -from .defines import BAR_MODES, CONF_ANIMATED, CONF_INDICATOR, CONF_MAIN, literal -from .lv_validation import animated, get_start_value, lv_float -from .lvcode import lv -from .types import LvNumber, NumberType -from .widget import Widget +from ..defines import BAR_MODES, CONF_ANIMATED, CONF_INDICATOR, CONF_MAIN, literal +from ..lv_validation import animated, get_start_value, lv_float +from ..lvcode import lv +from ..types import LvNumber, NumberType +from . import Widget + +# Note this file cannot be called "bar.py" because that name is disallowed. CONF_BAR = "bar" BAR_MODIFY_SCHEMA = cv.Schema( diff --git a/esphome/components/lvgl/meter.py b/esphome/components/lvgl/widgets/meter.py similarity index 96% rename from esphome/components/lvgl/meter.py rename to esphome/components/lvgl/widgets/meter.py index 1a6bef7c57..7cf154d6f3 100644 --- a/esphome/components/lvgl/meter.py +++ b/esphome/components/lvgl/widgets/meter.py @@ -14,9 +14,8 @@ from esphome.const import ( CONF_WIDTH, ) -from .arc import CONF_ARC -from .automation import action_to_code -from .defines import ( +from ..automation import action_to_code +from ..defines import ( CONF_END_VALUE, CONF_MAIN, CONF_PIVOT_X, @@ -25,10 +24,8 @@ from .defines import ( CONF_START_VALUE, CONF_TICKS, ) -from .helpers import add_lv_use -from .img import CONF_IMAGE -from .line import CONF_LINE -from .lv_validation import ( +from ..helpers import add_lv_use +from ..lv_validation import ( angle, get_end_value, get_start_value, @@ -39,10 +36,13 @@ from .lv_validation import ( requires_component, size, ) -from .lvcode import LocalVariable, lv, lv_assign, lv_expr +from ..lvcode import LocalVariable, lv, lv_assign, lv_expr +from ..types import LvType, ObjUpdateAction +from . import Widget, WidgetType, get_widgets +from .arc import CONF_ARC +from .img import CONF_IMAGE +from .line import CONF_LINE from .obj import obj_spec -from .types import LvType, ObjUpdateAction -from .widget import Widget, WidgetType, get_widgets CONF_ANGLE_RANGE = "angle_range" CONF_COLOR_END = "color_end" @@ -171,7 +171,7 @@ class MeterType(WidgetType): """For a meter object, create and set parameters""" var = w.obj - for scale_conf in config.get(CONF_SCALES) or (): + for scale_conf in config.get(CONF_SCALES, ()): rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2 if CONF_ROTATION in scale_conf: rotation = scale_conf[CONF_ROTATION] // 10 @@ -208,7 +208,7 @@ class MeterType(WidgetType): color, major[CONF_LABEL_GAP], ) - for indicator in scale_conf.get(CONF_INDICATORS) or (): + for indicator in scale_conf.get(CONF_INDICATORS, ()): (t, v) = next(iter(indicator.items())) iid = v[CONF_ID] ivar = cg.new_variable( diff --git a/esphome/components/lvgl/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py similarity index 72% rename from esphome/components/lvgl/msgbox.py rename to esphome/components/lvgl/widgets/msgbox.py index 6dd529d77f..4ae5be7701 100644 --- a/esphome/components/lvgl/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -4,16 +4,7 @@ from esphome.core import ID from esphome.cpp_generator import new_Pvariable, static_const_array from esphome.cpp_types import nullptr -from .button import button_spec -from .buttonmatrix import ( - BUTTONMATRIX_BUTTON_SCHEMA, - CONF_BUTTON_TEXT_LIST_ID, - buttonmatrix_spec, - get_button_data, - lv_buttonmatrix_t, - set_btn_data, -) -from .defines import ( +from ..defines import ( CONF_BODY, CONF_BUTTONS, CONF_CLOSE_BUTTON, @@ -23,10 +14,9 @@ from .defines import ( TYPE_FLEX, literal, ) -from .helpers import add_lv_use -from .label import CONF_LABEL -from .lv_validation import lv_bool, lv_pct, lv_text -from .lvcode import ( +from ..helpers import add_lv_use +from ..lv_validation import lv_bool, lv_pct, lv_text +from ..lvcode import ( EVENT_ARG, LambdaContext, LocalVariable, @@ -36,11 +26,21 @@ from .lvcode import ( lv_obj, lv_Pvariable, ) +from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema +from ..styles import TOP_LAYER +from ..types import LV_EVENT, char_ptr, lv_obj_t +from . import Widget, set_obj_properties +from .button import button_spec +from .buttonmatrix import ( + BUTTONMATRIX_BUTTON_SCHEMA, + CONF_BUTTON_TEXT_LIST_ID, + buttonmatrix_spec, + get_button_data, + lv_buttonmatrix_t, + set_btn_data, +) +from .label import CONF_LABEL from .obj import obj_spec -from .schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema -from .styles import TOP_LAYER -from .types import LV_EVENT, char_ptr, lv_obj_t -from .widget import Widget, set_obj_properties CONF_MSGBOX = "msgbox" MSGBOX_SCHEMA = container_schema( @@ -73,15 +73,23 @@ async def msgbox_to_code(conf): *buttonmatrix_spec.get_uses(), *button_spec.get_uses(), ) - mbid = conf[CONF_ID] - outer = lv_Pvariable(lv_obj_t, mbid.id) - btnm = new_Pvariable( - ID(f"{mbid.id}_btnm_", is_declaration=True, type=lv_buttonmatrix_t) + messagebox_id = conf[CONF_ID] + outer = lv_Pvariable(lv_obj_t, messagebox_id.id) + buttonmatrix = new_Pvariable( + ID( + f"{messagebox_id.id}_buttonmatrix_", + is_declaration=True, + type=lv_buttonmatrix_t, + ) + ) + msgbox = lv_Pvariable(lv_obj_t, f"{messagebox_id.id}_msgbox") + outer_widget = Widget.create(messagebox_id, outer, obj_spec, conf) + buttonmatrix_widget = Widget.create( + str(buttonmatrix), buttonmatrix, buttonmatrix_spec, conf + ) + text_list, ctrl_list, width_list, _ = await get_button_data( + (conf,), buttonmatrix_widget ) - msgbox = lv_Pvariable(lv_obj_t, f"{mbid.id}_msgbox") - outer_w = Widget.create(mbid, outer, obj_spec, conf) - btnm_widg = Widget.create(str(btnm), btnm, buttonmatrix_spec, conf) - text_list, ctrl_list, width_list, _ = await get_button_data((conf,), btnm_widg) text_id = conf[CONF_BUTTON_TEXT_LIST_ID] text_list = static_const_array(text_id, text_list) if (text := conf.get(CONF_BODY)) is not None: @@ -97,16 +105,16 @@ async def msgbox_to_code(conf): lv_obj.set_style_border_width(outer, 0, 0) lv_obj.set_style_pad_all(outer, 0, 0) lv_obj.set_style_radius(outer, 0, 0) - outer_w.add_flag("LV_OBJ_FLAG_HIDDEN") + outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN") lv_assign( msgbox, lv_expr.msgbox_create(outer, title, text, text_list, close_button) ) lv_obj.set_style_align(msgbox, literal("LV_ALIGN_CENTER"), 0) - lv_add(btnm.set_obj(lv_expr.msgbox_get_btns(msgbox))) - await set_obj_properties(outer_w, conf) + lv_add(buttonmatrix.set_obj(lv_expr.msgbox_get_btns(msgbox))) + await set_obj_properties(outer_widget, conf) if close_button: - async with LambdaContext(EVENT_ARG, where=mbid) as context: - outer_w.add_flag("LV_OBJ_FLAG_HIDDEN") + async with LambdaContext(EVENT_ARG, where=messagebox_id) as context: + outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN") with LocalVariable( "close_btn_", lv_obj_t, lv_expr.msgbox_get_close_btn(msgbox) ) as close_btn: @@ -119,7 +127,7 @@ async def msgbox_to_code(conf): ) if len(ctrl_list) != 0 or len(width_list) != 0: - set_btn_data(btnm.obj, ctrl_list, width_list) + set_btn_data(buttonmatrix.obj, ctrl_list, width_list) async def msgboxes_to_code(config): diff --git a/esphome/components/lvgl/obj.py b/esphome/components/lvgl/widgets/obj.py similarity index 76% rename from esphome/components/lvgl/obj.py rename to esphome/components/lvgl/widgets/obj.py index 40d7e55381..20a24c86f6 100644 --- a/esphome/components/lvgl/obj.py +++ b/esphome/components/lvgl/widgets/obj.py @@ -1,9 +1,9 @@ from esphome import automation -from .automation import update_to_code -from .defines import CONF_MAIN, CONF_OBJ -from .schemas import create_modify_schema -from .types import ObjUpdateAction, WidgetType, lv_obj_t +from ..automation import update_to_code +from ..defines import CONF_MAIN, CONF_OBJ +from ..schemas import create_modify_schema +from ..types import ObjUpdateAction, WidgetType, lv_obj_t class ObjType(WidgetType): diff --git a/esphome/components/lvgl/page.py b/esphome/components/lvgl/widgets/page.py similarity index 91% rename from esphome/components/lvgl/page.py rename to esphome/components/lvgl/widgets/page.py index 4566b7eea4..f80d802b33 100644 --- a/esphome/components/lvgl/page.py +++ b/esphome/components/lvgl/widgets/page.py @@ -2,7 +2,7 @@ from esphome import automation, codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME -from .defines import ( +from ..defines import ( CONF_ANIMATION, CONF_LVGL_ID, CONF_PAGE, @@ -10,11 +10,11 @@ from .defines import ( CONF_SKIP, LV_ANIM, ) -from .lv_validation import lv_bool, lv_milliseconds -from .lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp -from .schemas import LVGL_SCHEMA -from .types import LvglAction, lv_page_t -from .widget import Widget, WidgetType, add_widgets, set_obj_properties +from ..lv_validation import lv_bool, lv_milliseconds +from ..lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp +from ..schemas import LVGL_SCHEMA +from ..types import LvglAction, lv_page_t +from . import Widget, WidgetType, add_widgets, set_obj_properties class PageType(WidgetType): diff --git a/esphome/components/lvgl/roller.py b/esphome/components/lvgl/widgets/roller.py similarity index 92% rename from esphome/components/lvgl/roller.py rename to esphome/components/lvgl/widgets/roller.py index 7af3ef3c3d..50fdf6113c 100644 --- a/esphome/components/lvgl/roller.py +++ b/esphome/components/lvgl/widgets/roller.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_MODE, CONF_OPTIONS -from .defines import ( +from ..defines import ( CONF_ANIMATED, CONF_MAIN, CONF_SELECTED, @@ -11,11 +11,11 @@ from .defines import ( ROLLER_MODES, literal, ) +from ..lv_validation import animated, lv_int, option_string +from ..lvcode import lv +from ..types import LvSelect +from . import WidgetType from .label import CONF_LABEL -from .lv_validation import animated, lv_int, option_string -from .lvcode import lv -from .types import LvSelect -from .widget import WidgetType CONF_ROLLER = "roller" lv_roller_t = LvSelect("lv_roller_t") diff --git a/esphome/components/lvgl/slider.py b/esphome/components/lvgl/widgets/slider.py similarity index 88% rename from esphome/components/lvgl/slider.py rename to esphome/components/lvgl/widgets/slider.py index 1886f79b44..d5017668e4 100644 --- a/esphome/components/lvgl/slider.py +++ b/esphome/components/lvgl/widgets/slider.py @@ -1,7 +1,7 @@ import esphome.config_validation as cv from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, CONF_VALUE -from .defines import ( +from ..defines import ( BAR_MODES, CONF_ANIMATED, CONF_INDICATOR, @@ -9,12 +9,12 @@ from .defines import ( CONF_MAIN, literal, ) -from .helpers import add_lv_use +from ..helpers import add_lv_use +from ..lv_validation import animated, get_start_value, lv_float +from ..lvcode import lv +from ..types import LvNumber, NumberType +from . import Widget from .lv_bar import CONF_BAR -from .lv_validation import animated, get_start_value, lv_float -from .lvcode import lv -from .types import LvNumber, NumberType -from .widget import Widget CONF_SLIDER = "slider" SLIDER_MODIFY_SCHEMA = cv.Schema( diff --git a/esphome/components/lvgl/spinbox.py b/esphome/components/lvgl/widgets/spinbox.py similarity index 95% rename from esphome/components/lvgl/spinbox.py rename to esphome/components/lvgl/widgets/spinbox.py index 62c58c54a3..b84dc7cd23 100644 --- a/esphome/components/lvgl/spinbox.py +++ b/esphome/components/lvgl/widgets/spinbox.py @@ -2,8 +2,8 @@ from esphome import automation import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_RANGE_FROM, CONF_RANGE_TO, CONF_STEP, CONF_VALUE -from .automation import action_to_code, update_to_code -from .defines import ( +from ..automation import action_to_code, update_to_code +from ..defines import ( CONF_CURSOR, CONF_DECIMAL_PLACES, CONF_DIGITS, @@ -13,12 +13,12 @@ from .defines import ( CONF_SELECTED, CONF_TEXTAREA_PLACEHOLDER, ) +from ..lv_validation import lv_bool, lv_float +from ..lvcode import lv +from ..types import LvNumber, ObjUpdateAction +from . import Widget, WidgetType, get_widgets from .label import CONF_LABEL -from .lv_validation import lv_bool, lv_float -from .lvcode import lv from .textarea import CONF_TEXTAREA -from .types import LvNumber, ObjUpdateAction -from .widget import Widget, WidgetType, get_widgets CONF_SPINBOX = "spinbox" diff --git a/esphome/components/lvgl/spinner.py b/esphome/components/lvgl/widgets/spinner.py similarity index 82% rename from esphome/components/lvgl/spinner.py rename to esphome/components/lvgl/widgets/spinner.py index 2f798d0fbf..2940feb594 100644 --- a/esphome/components/lvgl/spinner.py +++ b/esphome/components/lvgl/widgets/spinner.py @@ -1,12 +1,12 @@ import esphome.config_validation as cv from esphome.cpp_generator import MockObjClass +from ..defines import CONF_ARC_LENGTH, CONF_INDICATOR, CONF_MAIN, CONF_SPIN_TIME +from ..lv_validation import angle +from ..lvcode import lv_expr +from ..types import LvType +from . import Widget, WidgetType from .arc import CONF_ARC -from .defines import CONF_ARC_LENGTH, CONF_INDICATOR, CONF_MAIN, CONF_SPIN_TIME -from .lv_validation import angle -from .lvcode import lv_expr -from .types import LvType -from .widget import Widget, WidgetType CONF_SPINNER = "spinner" diff --git a/esphome/components/lvgl/lv_switch.py b/esphome/components/lvgl/widgets/switch.py similarity index 72% rename from esphome/components/lvgl/lv_switch.py rename to esphome/components/lvgl/widgets/switch.py index 5db2c2ce38..a7c1356bf2 100644 --- a/esphome/components/lvgl/lv_switch.py +++ b/esphome/components/lvgl/widgets/switch.py @@ -1,6 +1,6 @@ -from .defines import CONF_INDICATOR, CONF_KNOB, CONF_MAIN -from .types import LvBoolean -from .widget import WidgetType +from ..defines import CONF_INDICATOR, CONF_KNOB, CONF_MAIN +from ..types import LvBoolean +from . import WidgetType CONF_SWITCH = "switch" diff --git a/esphome/components/lvgl/tabview.py b/esphome/components/lvgl/widgets/tabview.py similarity index 88% rename from esphome/components/lvgl/tabview.py rename to esphome/components/lvgl/widgets/tabview.py index 7b6a864e21..226fc3f286 100644 --- a/esphome/components/lvgl/tabview.py +++ b/esphome/components/lvgl/widgets/tabview.py @@ -4,9 +4,8 @@ import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INDEX, CONF_NAME, CONF_POSITION, CONF_SIZE from esphome.cpp_generator import MockObjClass -from . import buttonmatrix_spec -from .automation import action_to_code -from .defines import ( +from ..automation import action_to_code +from ..defines import ( CONF_ANIMATED, CONF_MAIN, CONF_TAB_ID, @@ -15,12 +14,13 @@ from .defines import ( TYPE_FLEX, literal, ) -from .lv_validation import animated, lv_int, size -from .lvcode import LocalVariable, lv, lv_assign, lv_expr +from ..lv_validation import animated, lv_int, size +from ..lvcode import LocalVariable, lv, lv_assign, lv_expr +from ..schemas import container_schema, part_schema +from ..types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr +from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties +from .buttonmatrix import buttonmatrix_spec from .obj import obj_spec -from .schemas import container_schema, part_schema -from .types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr -from .widget import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties CONF_TABVIEW = "tabview" CONF_TAB_STYLE = "tab_style" diff --git a/esphome/components/lvgl/textarea.py b/esphome/components/lvgl/widgets/textarea.py similarity index 90% rename from esphome/components/lvgl/textarea.py rename to esphome/components/lvgl/widgets/textarea.py index d383e1f098..61d83dee9c 100644 --- a/esphome/components/lvgl/textarea.py +++ b/esphome/components/lvgl/widgets/textarea.py @@ -1,7 +1,7 @@ import esphome.config_validation as cv from esphome.const import CONF_MAX_LENGTH -from .defines import ( +from ..defines import ( CONF_ACCEPTED_CHARS, CONF_CURSOR, CONF_MAIN, @@ -13,10 +13,10 @@ from .defines import ( CONF_TEXT, CONF_TEXTAREA_PLACEHOLDER, ) -from .lv_validation import lv_bool, lv_int, lv_text -from .schemas import TEXT_SCHEMA -from .types import LvText -from .widget import Widget, WidgetType +from ..lv_validation import lv_bool, lv_int, lv_text +from ..schemas import TEXT_SCHEMA +from ..types import LvText +from . import Widget, WidgetType CONF_TEXTAREA = "textarea" diff --git a/esphome/components/lvgl/tileview.py b/esphome/components/lvgl/widgets/tileview.py similarity index 89% rename from esphome/components/lvgl/tileview.py rename to esphome/components/lvgl/widgets/tileview.py index aa841fa23e..9a426c7daf 100644 --- a/esphome/components/lvgl/tileview.py +++ b/esphome/components/lvgl/widgets/tileview.py @@ -3,8 +3,8 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_VALUE, CONF_ROW, CONF_TRIGGER_ID -from .automation import action_to_code -from .defines import ( +from ..automation import action_to_code +from ..defines import ( CONF_ANIMATED, CONF_COLUMN, CONF_DIR, @@ -14,12 +14,12 @@ from .defines import ( TILE_DIRECTIONS, literal, ) -from .lv_validation import animated, lv_int -from .lvcode import lv, lv_assign, lv_expr, lv_obj, lv_Pvariable +from ..lv_validation import animated, lv_int +from ..lvcode import lv, lv_assign, lv_expr, lv_obj, lv_Pvariable +from ..schemas import container_schema +from ..types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr +from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties from .obj import obj_spec -from .schemas import container_schema -from .types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr -from .widget import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties CONF_TILEVIEW = "tileview" @@ -68,7 +68,7 @@ class TileviewType(WidgetType): ) async def to_code(self, w: Widget, config: dict): - for tile_conf in config.get(CONF_TILES) or (): + for tile_conf in config.get(CONF_TILES, ()): w_id = tile_conf[CONF_ID] tile_obj = lv_Pvariable(lv_obj_t, w_id) tile = Widget.create(w_id, tile_obj, tile_spec, tile_conf) diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 6d0c1967b4..35d924d939 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -54,3 +54,75 @@ font: "\U000f0084", "\U000f0091", ] + +sensor: + - platform: lvgl + id: lvgl_sensor_id + name: "LVGL Arc Sensor" + widget: lv_arc + - platform: lvgl + widget: slider_id + name: LVGL Slider + - platform: lvgl + widget: bar_id + id: lvgl_bar_sensor + name: LVGL Bar + - platform: lvgl + widget: spinbox_id + name: LVGL Spinbox + +number: + - platform: lvgl + widget: slider_id + name: LVGL Slider + - platform: lvgl + widget: lv_arc + id: lvgl_arc_number + name: LVGL Arc + - platform: lvgl + widget: bar_id + id: lvgl_bar_number + name: LVGL Bar + - platform: lvgl + widget: spinbox_id + id: lvgl_spinbox_number + name: LVGL Spinbox + +light: + - platform: lvgl + name: LVGL LED + id: lv_light + led: lv_led + +binary_sensor: + - platform: lvgl + id: lvgl_pressbutton + name: Pressbutton + widget: spin_up + publish_initial_state: true + - platform: lvgl + name: ButtonMatrix button + widget: button_a + - platform: lvgl + id: switch_d + name: Matrix switch D + widget: button_d + on_click: + then: + - lvgl.page.previous: + animation: move_right + time: 600ms + - platform: lvgl + id: button_checker + name: LVGL button + widget: spin_up + on_state: + then: + - lvgl.checkbox.update: + id: checkbox_id + state: + checked: !lambda return x; + text: Unchecked + - platform: lvgl + name: LVGL checkbox + widget: checkbox_id From e6b1780a31d54b46628c919f90433db4e7681ec4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:39:47 +1200 Subject: [PATCH 2166/2607] Move ``CONF_BACKGROUND_COLOR`` and ``CONF_FOREGROUND_COLOR`` to const.py (#7202) --- .../graphical_display_menu/__init__.py | 17 ++++++++++------- esphome/components/nextion/base_component.py | 13 +++++-------- esphome/const.py | 2 ++ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index 1b3ed7f8cd..d7146a7381 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -1,19 +1,22 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import display, font, color -from esphome.const import CONF_DISPLAY, CONF_ID, CONF_TRIGGER_ID from esphome import automation, core - +import esphome.codegen as cg +from esphome.components import color, display, font from esphome.components.display_menu_base import ( DISPLAY_MENU_BASE_SCHEMA, DisplayMenuComponent, display_menu_to_code, ) +import esphome.config_validation as cv +from esphome.const import ( + CONF_BACKGROUND_COLOR, + CONF_DISPLAY, + CONF_FOREGROUND_COLOR, + CONF_ID, + CONF_TRIGGER_ID, +) CONF_FONT = "font" CONF_MENU_ITEM_VALUE = "menu_item_value" -CONF_FOREGROUND_COLOR = "foreground_color" -CONF_BACKGROUND_COLOR = "background_color" CONF_ON_REDRAW = "on_redraw" graphical_display_menu_ns = cg.esphome_ns.namespace("graphical_display_menu") diff --git a/esphome/components/nextion/base_component.py b/esphome/components/nextion/base_component.py index 784da35371..d12434ec8f 100644 --- a/esphome/components/nextion/base_component.py +++ b/esphome/components/nextion/base_component.py @@ -1,12 +1,11 @@ from string import ascii_letters, digits -import esphome.config_validation as cv + import esphome.codegen as cg from esphome.components import color -from esphome.const import ( - CONF_VISIBLE, -) -from . import CONF_NEXTION_ID -from . import Nextion +import esphome.config_validation as cv +from esphome.const import CONF_BACKGROUND_COLOR, CONF_FOREGROUND_COLOR, CONF_VISIBLE + +from . import CONF_NEXTION_ID, Nextion CONF_VARIABLE_NAME = "variable_name" CONF_COMPONENT_NAME = "component_name" @@ -24,9 +23,7 @@ CONF_WAKE_UP_PAGE = "wake_up_page" CONF_START_UP_PAGE = "start_up_page" CONF_AUTO_WAKE_ON_TOUCH = "auto_wake_on_touch" CONF_WAVE_MAX_LENGTH = "wave_max_length" -CONF_BACKGROUND_COLOR = "background_color" CONF_BACKGROUND_PRESSED_COLOR = "background_pressed_color" -CONF_FOREGROUND_COLOR = "foreground_color" CONF_FOREGROUND_PRESSED_COLOR = "foreground_pressed_color" CONF_FONT_ID = "font_id" CONF_EXIT_REPARSE_ON_START = "exit_reparse_on_start" diff --git a/esphome/const.py b/esphome/const.py index fcb630badd..d7b1f558a1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -74,6 +74,7 @@ CONF_AWAY = "away" CONF_AWAY_COMMAND_TOPIC = "away_command_topic" CONF_AWAY_CONFIG = "away_config" CONF_AWAY_STATE_TOPIC = "away_state_topic" +CONF_BACKGROUND_COLOR = "background_color" CONF_BACKLIGHT_PIN = "backlight_pin" CONF_BASELINE = "baseline" CONF_BATTERY_LEVEL = "battery_level" @@ -309,6 +310,7 @@ CONF_FLOW = "flow" CONF_FLOW_CONTROL_PIN = "flow_control_pin" CONF_FOR = "for" CONF_FORCE_UPDATE = "force_update" +CONF_FOREGROUND_COLOR = "foreground_color" CONF_FORMALDEHYDE = "formaldehyde" CONF_FORMAT = "format" CONF_FORWARD_ACTIVE_ENERGY = "forward_active_energy" From b0d9800817921fe98f888b296596f3a4ccf39e18 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:02:08 +1200 Subject: [PATCH 2167/2607] [helpers] Set default flags of ExternalRAMAllocator to ALLOW_FAILURE (#7201) --- esphome/core/helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index b4ad22b083..3e6fe9433e 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -680,7 +680,7 @@ template class ExternalRAMAllocator { } private: - Flags flags_{Flags::NONE}; + Flags flags_{Flags::ALLOW_FAILURE}; }; /// @} From 9188836f707db9924c95233cb604dbc51a8fa24f Mon Sep 17 00:00:00 2001 From: guillempages Date: Tue, 6 Aug 2024 13:08:06 +0200 Subject: [PATCH 2168/2607] Add runtime online image support (#4710) --- CODEOWNERS | 1 + esphome/components/online_image/__init__.py | 161 ++++++++++ .../components/online_image/image_decoder.cpp | 44 +++ .../components/online_image/image_decoder.h | 112 +++++++ .../components/online_image/online_image.cpp | 275 ++++++++++++++++++ .../components/online_image/online_image.h | 184 ++++++++++++ esphome/components/online_image/png_image.cpp | 68 +++++ esphome/components/online_image/png_image.h | 33 +++ esphome/core/defines.h | 1 + platformio.ini | 1 + .../components/online_image/common-esp32.yaml | 18 ++ .../online_image/common-esp8266.yaml | 18 ++ tests/components/online_image/common.yaml | 37 +++ .../online_image/test.esp32-ard.yaml | 4 + .../online_image/test.esp32-idf.yaml | 4 + 15 files changed, 961 insertions(+) create mode 100644 esphome/components/online_image/__init__.py create mode 100644 esphome/components/online_image/image_decoder.cpp create mode 100644 esphome/components/online_image/image_decoder.h create mode 100644 esphome/components/online_image/online_image.cpp create mode 100644 esphome/components/online_image/online_image.h create mode 100644 esphome/components/online_image/png_image.cpp create mode 100644 esphome/components/online_image/png_image.h create mode 100644 tests/components/online_image/common-esp32.yaml create mode 100644 tests/components/online_image/common-esp8266.yaml create mode 100644 tests/components/online_image/common.yaml create mode 100644 tests/components/online_image/test.esp32-ard.yaml create mode 100644 tests/components/online_image/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index d94c34c019..82e6e0ea4b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -276,6 +276,7 @@ esphome/components/nfc/* @jesserockz @kbx81 esphome/components/noblex/* @AGalfra esphome/components/number/* @esphome/core esphome/components/one_wire/* @ssieb +esphome/components/online_image/* @guillempages esphome/components/ota/* @esphome/core esphome/components/output/* @esphome/core esphome/components/pca6416a/* @Mat931 diff --git a/esphome/components/online_image/__init__.py b/esphome/components/online_image/__init__.py new file mode 100644 index 0000000000..ee5357457a --- /dev/null +++ b/esphome/components/online_image/__init__.py @@ -0,0 +1,161 @@ +import logging + +from esphome import automation +import esphome.codegen as cg +from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestComponent +from esphome.components.image import ( + CONF_USE_TRANSPARENCY, + IMAGE_TYPE, + Image_, + validate_cross_dependencies, +) +import esphome.config_validation as cv +from esphome.const import ( + CONF_BUFFER_SIZE, + CONF_FORMAT, + CONF_ID, + CONF_ON_ERROR, + CONF_RESIZE, + CONF_TRIGGER_ID, + CONF_TYPE, + CONF_URL, +) + +AUTO_LOAD = ["image"] +DEPENDENCIES = ["display", "http_request"] +CODEOWNERS = ["@guillempages"] +MULTI_CONF = True + +CONF_ON_DOWNLOAD_FINISHED = "on_download_finished" + +_LOGGER = logging.getLogger(__name__) + +online_image_ns = cg.esphome_ns.namespace("online_image") + +ImageFormat = online_image_ns.enum("ImageFormat") + +FORMAT_PNG = "PNG" + +IMAGE_FORMAT = {FORMAT_PNG: ImageFormat.PNG} # Add new supported formats here + +OnlineImage = online_image_ns.class_("OnlineImage", cg.PollingComponent, Image_) + +# Actions +SetUrlAction = online_image_ns.class_( + "OnlineImageSetUrlAction", automation.Action, cg.Parented.template(OnlineImage) +) +ReleaseImageAction = online_image_ns.class_( + "OnlineImageReleaseAction", automation.Action, cg.Parented.template(OnlineImage) +) + +# Triggers +DownloadFinishedTrigger = online_image_ns.class_( + "DownloadFinishedTrigger", automation.Trigger.template() +) +DownloadErrorTrigger = online_image_ns.class_( + "DownloadErrorTrigger", automation.Trigger.template() +) + +ONLINE_IMAGE_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(OnlineImage), + cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent), + # + # Common image options + # + cv.Optional(CONF_RESIZE): cv.dimensions, + cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(IMAGE_TYPE, upper=True), + # Not setting default here on purpose; the default depends on the image type, + # and thus will be set in the "validate_cross_dependencies" validator. + cv.Optional(CONF_USE_TRANSPARENCY): cv.boolean, + # + # Online Image specific options + # + cv.Required(CONF_URL): cv.url, + cv.Required(CONF_FORMAT): cv.enum(IMAGE_FORMAT, upper=True), + cv.Optional(CONF_BUFFER_SIZE, default=2048): cv.int_range(256, 65536), + cv.Optional(CONF_ON_DOWNLOAD_FINISHED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DownloadFinishedTrigger), + } + ), + cv.Optional(CONF_ON_ERROR): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DownloadErrorTrigger), + } + ), + } +).extend(cv.polling_component_schema("never")) + +CONFIG_SCHEMA = cv.Schema( + cv.All( + ONLINE_IMAGE_SCHEMA, + validate_cross_dependencies, + cv.require_framework_version( + # esp8266 not supported yet; if enabled in the future, minimum version of 2.7.0 is needed + # esp8266_arduino=cv.Version(2, 7, 0), + esp32_arduino=cv.Version(0, 0, 0), + esp_idf=cv.Version(4, 0, 0), + ), + ) +) + +SET_URL_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(OnlineImage), + cv.Required(CONF_URL): cv.templatable(cv.url), + } +) + +RELEASE_IMAGE_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(OnlineImage), + } +) + + +@automation.register_action("online_image.set_url", SetUrlAction, SET_URL_SCHEMA) +@automation.register_action( + "online_image.release", ReleaseImageAction, RELEASE_IMAGE_SCHEMA +) +async def online_image_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + if CONF_URL in config: + template_ = await cg.templatable(config[CONF_URL], args, cg.const_char_ptr) + cg.add(var.set_url(template_)) + return var + + +async def to_code(config): + format = config[CONF_FORMAT] + if format in [FORMAT_PNG]: + cg.add_define("USE_ONLINE_IMAGE_PNG_SUPPORT") + cg.add_library("pngle", "1.0.2") + + url = config[CONF_URL] + width, height = config.get(CONF_RESIZE, (0, 0)) + transparent = config[CONF_USE_TRANSPARENCY] + + var = cg.new_Pvariable( + config[CONF_ID], + url, + width, + height, + format, + config[CONF_TYPE], + config[CONF_BUFFER_SIZE], + ) + await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_HTTP_REQUEST_ID]) + + cg.add(var.set_transparency(transparent)) + + for conf in config.get(CONF_ON_DOWNLOAD_FINISHED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + + for conf in config.get(CONF_ON_ERROR, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/online_image/image_decoder.cpp b/esphome/components/online_image/image_decoder.cpp new file mode 100644 index 0000000000..50ec39dfcc --- /dev/null +++ b/esphome/components/online_image/image_decoder.cpp @@ -0,0 +1,44 @@ +#include "image_decoder.h" +#include "online_image.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace online_image { + +static const char *const TAG = "online_image.decoder"; + +void ImageDecoder::set_size(int width, int height) { + this->image_->resize_(width, height); + this->x_scale_ = static_cast(this->image_->buffer_width_) / width; + this->y_scale_ = static_cast(this->image_->buffer_height_) / height; +} + +void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) { + auto width = std::min(this->image_->buffer_width_, static_cast(std::ceil((x + w) * this->x_scale_))); + auto height = std::min(this->image_->buffer_height_, static_cast(std::ceil((y + h) * this->y_scale_))); + for (int i = x * this->x_scale_; i < width; i++) { + for (int j = y * this->y_scale_; j < height; j++) { + this->image_->draw_pixel_(i, j, color); + } + } +} + +uint8_t *DownloadBuffer::data(size_t offset) { + if (offset > this->size_) { + ESP_LOGE(TAG, "Tried to access beyond download buffer bounds!!!"); + return this->buffer_; + } + return this->buffer_ + offset; +} + +size_t DownloadBuffer::read(size_t len) { + this->unread_ -= len; + if (this->unread_ > 0) { + memmove(this->data(), this->data(len), this->unread_); + } + return this->unread_; +} + +} // namespace online_image +} // namespace esphome diff --git a/esphome/components/online_image/image_decoder.h b/esphome/components/online_image/image_decoder.h new file mode 100644 index 0000000000..908efab987 --- /dev/null +++ b/esphome/components/online_image/image_decoder.h @@ -0,0 +1,112 @@ +#pragma once +#include "esphome/core/defines.h" +#include "esphome/core/color.h" + +namespace esphome { +namespace online_image { + +class OnlineImage; + +/** + * @brief Class to abstract decoding different image formats. + */ +class ImageDecoder { + public: + /** + * @brief Construct a new Image Decoder object + * + * @param image The image to decode the stream into. + */ + ImageDecoder(OnlineImage *image) : image_(image) {} + virtual ~ImageDecoder() = default; + + /** + * @brief Initialize the decoder. + * + * @param download_size The total number of bytes that need to be download for the image. + */ + virtual void prepare(uint32_t download_size) { this->download_size_ = download_size; } + + /** + * @brief Decode a part of the image. It will try reading from the buffer. + * There is no guarantee that the whole available buffer will be read/decoded; + * the method will return the amount of bytes actually decoded, so that the + * unread content can be moved to the beginning. + * + * @param buffer The buffer to read from. + * @param size The maximum amount of bytes that can be read from the buffer. + * @return int The amount of bytes read. It can be 0 if the buffer does not have enough content to meaningfully + * decode anything, or negative in case of a decoding error. + */ + virtual int decode(uint8_t *buffer, size_t size); + + /** + * @brief Request the image to be resized once the actual dimensions are known. + * Called by the callback functions, to be able to access the parent Image class. + * + * @param width The image's width. + * @param height The image's height. + */ + void set_size(int width, int height); + + /** + * @brief Draw a rectangle on the display_buffer using the defined color. + * Will check the given coordinates for out-of-bounds, and clip the rectangle accordingly. + * In case of binary displays, the color will be converted to binary as well. + * Called by the callback functions, to be able to access the parent Image class. + * + * @param x The left-most coordinate of the rectangle. + * @param y The top-most coordinate of the rectangle. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @param color The color to draw the rectangle with. + */ + void draw(int x, int y, int w, int h, const Color &color); + + bool is_finished() const { return this->decoded_bytes_ == this->download_size_; } + + protected: + OnlineImage *image_; + // Initializing to 1, to ensure it is different than initial "decoded_bytes_". + // Will be overwritten anyway once the download size is known. + uint32_t download_size_ = 1; + uint32_t decoded_bytes_ = 0; + double x_scale_ = 1.0; + double y_scale_ = 1.0; +}; + +class DownloadBuffer { + public: + DownloadBuffer(size_t size) : size_(size) { + this->buffer_ = this->allocator_.allocate(size); + this->reset(); + } + + virtual ~DownloadBuffer() { this->allocator_.deallocate(this->buffer_, this->size_); } + + uint8_t *data(size_t offset = 0); + + uint8_t *append() { return this->data(this->unread_); } + + size_t unread() const { return this->unread_; } + size_t size() const { return this->size_; } + size_t free_capacity() const { return this->size_ - this->unread_; } + + size_t read(size_t len); + size_t write(size_t len) { + this->unread_ += len; + return this->unread_; + } + + void reset() { this->unread_ = 0; } + + protected: + ExternalRAMAllocator allocator_; + uint8_t *buffer_; + size_t size_; + /** Total number of downloaded bytes not yet read. */ + size_t unread_; +}; + +} // namespace online_image +} // namespace esphome diff --git a/esphome/components/online_image/online_image.cpp b/esphome/components/online_image/online_image.cpp new file mode 100644 index 0000000000..a4cf0158aa --- /dev/null +++ b/esphome/components/online_image/online_image.cpp @@ -0,0 +1,275 @@ +#include "online_image.h" + +#include "esphome/core/log.h" + +static const char *const TAG = "online_image"; + +#include "image_decoder.h" + +#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT +#include "png_image.h" +#endif + +namespace esphome { +namespace online_image { + +using image::ImageType; + +inline bool is_color_on(const Color &color) { + // This produces the most accurate monochrome conversion, but is slightly slower. + // return (0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b) > 127; + + // Approximation using fast integer computations; produces acceptable results + // Equivalent to 0.25 * R + 0.5 * G + 0.25 * B + return ((color.r >> 2) + (color.g >> 1) + (color.b >> 2)) & 0x80; +} + +OnlineImage::OnlineImage(const std::string &url, int width, int height, ImageFormat format, ImageType type, + uint32_t download_buffer_size) + : Image(nullptr, 0, 0, type), + buffer_(nullptr), + download_buffer_(download_buffer_size), + format_(format), + fixed_width_(width), + fixed_height_(height) { + this->set_url(url); +} + +void OnlineImage::release() { + if (this->buffer_) { + ESP_LOGD(TAG, "Deallocating old buffer..."); + this->allocator_.deallocate(this->buffer_, this->get_buffer_size_()); + this->data_start_ = nullptr; + this->buffer_ = nullptr; + this->width_ = 0; + this->height_ = 0; + this->buffer_width_ = 0; + this->buffer_height_ = 0; + this->end_connection_(); + } +} + +bool OnlineImage::resize_(int width_in, int height_in) { + int width = this->fixed_width_; + int height = this->fixed_height_; + if (this->auto_resize_()) { + width = width_in; + height = height_in; + if (this->width_ != width && this->height_ != height) { + this->release(); + } + } + if (this->buffer_) { + return false; + } + auto new_size = this->get_buffer_size_(width, height); + ESP_LOGD(TAG, "Allocating new buffer of %d Bytes...", new_size); + delay_microseconds_safe(2000); + this->buffer_ = this->allocator_.allocate(new_size); + if (this->buffer_) { + this->buffer_width_ = width; + this->buffer_height_ = height; + this->width_ = width; + ESP_LOGD(TAG, "New size: (%d, %d)", width, height); + } else { +#if defined(USE_ESP8266) + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + int max_block = ESP.getMaxFreeBlockSize(); +#elif defined(USE_ESP32) + int max_block = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); +#else + int max_block = -1; +#endif + ESP_LOGE(TAG, "allocation failed. Biggest block in heap: %d Bytes", max_block); + this->end_connection_(); + return false; + } + return true; +} + +void OnlineImage::update() { + if (this->decoder_) { + ESP_LOGW(TAG, "Image already being updated."); + return; + } else { + ESP_LOGI(TAG, "Updating image"); + } + + this->downloader_ = this->parent_->get(this->url_); + + if (this->downloader_ == nullptr) { + ESP_LOGE(TAG, "Download failed."); + this->end_connection_(); + this->download_error_callback_.call(); + return; + } + + int http_code = this->downloader_->status_code; + if (http_code == HTTP_CODE_NOT_MODIFIED) { + // Image hasn't changed on server. Skip download. + this->end_connection_(); + return; + } + if (http_code != HTTP_CODE_OK) { + ESP_LOGE(TAG, "HTTP result: %d", http_code); + this->end_connection_(); + this->download_error_callback_.call(); + return; + } + + ESP_LOGD(TAG, "Starting download"); + size_t total_size = this->downloader_->content_length; + +#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT + if (this->format_ == ImageFormat::PNG) { + this->decoder_ = esphome::make_unique(this); + } +#endif // ONLINE_IMAGE_PNG_SUPPORT + + if (!this->decoder_) { + ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported."); + this->end_connection_(); + this->download_error_callback_.call(); + return; + } + this->decoder_->prepare(total_size); + ESP_LOGI(TAG, "Downloading image"); +} + +void OnlineImage::loop() { + if (!this->decoder_) { + // Not decoding at the moment => nothing to do. + return; + } + if (!this->downloader_ || this->decoder_->is_finished()) { + ESP_LOGD(TAG, "Image fully downloaded"); + this->data_start_ = buffer_; + this->width_ = buffer_width_; + this->height_ = buffer_height_; + this->end_connection_(); + this->download_finished_callback_.call(); + return; + } + if (this->downloader_ == nullptr) { + ESP_LOGE(TAG, "Downloader not instantiated; cannot download"); + return; + } + size_t available = this->download_buffer_.free_capacity(); + if (available) { + auto len = this->downloader_->read(this->download_buffer_.append(), available); + if (len > 0) { + this->download_buffer_.write(len); + auto fed = this->decoder_->decode(this->download_buffer_.data(), this->download_buffer_.unread()); + if (fed < 0) { + ESP_LOGE(TAG, "Error when decoding image."); + this->end_connection_(); + this->download_error_callback_.call(); + return; + } + this->download_buffer_.read(fed); + } + } +} + +void OnlineImage::draw_pixel_(int x, int y, Color color) { + if (!this->buffer_) { + ESP_LOGE(TAG, "Buffer not allocated!"); + return; + } + if (x < 0 || y < 0 || x >= this->buffer_width_ || y >= this->buffer_height_) { + ESP_LOGE(TAG, "Tried to paint a pixel (%d,%d) outside the image!", x, y); + return; + } + uint32_t pos = this->get_position_(x, y); + switch (this->type_) { + case ImageType::IMAGE_TYPE_BINARY: { + const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; + const uint32_t pos = x + y * width_8; + if ((this->has_transparency() && color.w > 127) || is_color_on(color)) { + this->buffer_[pos / 8u] |= (0x80 >> (pos % 8u)); + } else { + this->buffer_[pos / 8u] &= ~(0x80 >> (pos % 8u)); + } + break; + } + case ImageType::IMAGE_TYPE_GRAYSCALE: { + uint8_t gray = static_cast(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b); + if (this->has_transparency()) { + if (gray == 1) { + gray = 0; + } + if (color.w < 0x80) { + gray = 1; + } + } + this->buffer_[pos] = gray; + break; + } + case ImageType::IMAGE_TYPE_RGB565: { + uint16_t col565 = display::ColorUtil::color_to_565(color); + if (this->has_transparency()) { + if (col565 == 0x0020) { + col565 = 0; + } + if (color.w < 0x80) { + col565 = 0x0020; + } + } + this->buffer_[pos + 0] = static_cast((col565 >> 8) & 0xFF); + this->buffer_[pos + 1] = static_cast(col565 & 0xFF); + break; + } + case ImageType::IMAGE_TYPE_RGBA: { + this->buffer_[pos + 0] = color.r; + this->buffer_[pos + 1] = color.g; + this->buffer_[pos + 2] = color.b; + this->buffer_[pos + 3] = color.w; + break; + } + case ImageType::IMAGE_TYPE_RGB24: + default: { + if (this->has_transparency()) { + if (color.b == 1 && color.r == 0 && color.g == 0) { + color.b = 0; + } + if (color.w < 0x80) { + color.r = 0; + color.g = 0; + color.b = 1; + } + } + this->buffer_[pos + 0] = color.r; + this->buffer_[pos + 1] = color.g; + this->buffer_[pos + 2] = color.b; + break; + } + } +} + +void OnlineImage::end_connection_() { + if (this->downloader_) { + this->downloader_->end(); + this->downloader_ = nullptr; + } + this->decoder_.reset(); + this->download_buffer_.reset(); +} + +bool OnlineImage::validate_url_(const std::string &url) { + if ((url.length() < 8) || (url.find("http") != 0) || (url.find("://") == std::string::npos)) { + ESP_LOGE(TAG, "URL is invalid and/or must be prefixed with 'http://' or 'https://'"); + return false; + } + return true; +} + +void OnlineImage::add_on_finished_callback(std::function &&callback) { + this->download_finished_callback_.add(std::move(callback)); +} + +void OnlineImage::add_on_error_callback(std::function &&callback) { + this->download_error_callback_.add(std::move(callback)); +} + +} // namespace online_image +} // namespace esphome diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h new file mode 100644 index 0000000000..30e97760ea --- /dev/null +++ b/esphome/components/online_image/online_image.h @@ -0,0 +1,184 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/components/http_request/http_request.h" +#include "esphome/components/image/image.h" + +#include "image_decoder.h" + +namespace esphome { +namespace online_image { + +using t_http_codes = enum { + HTTP_CODE_OK = 200, + HTTP_CODE_NOT_MODIFIED = 304, + HTTP_CODE_NOT_FOUND = 404, +}; + +/** + * @brief Format that the image is encoded with. + */ +enum ImageFormat { + /** Automatically detect from MIME type. Not supported yet. */ + AUTO, + /** JPEG format. Not supported yet. */ + JPEG, + /** PNG format. */ + PNG, +}; + +/** + * @brief Download an image from a given URL, and decode it using the specified decoder. + * The image will then be stored in a buffer, so that it can be re-displayed without the + * need to re-download or re-decode. + */ +class OnlineImage : public PollingComponent, + public image::Image, + public Parented { + public: + /** + * @brief Construct a new OnlineImage object. + * + * @param url URL to download the image from. + * @param width Desired width of the target image area. + * @param height Desired height of the target image area. + * @param format Format that the image is encoded in (@see ImageFormat). + * @param buffer_size Size of the buffer used to download the image. + */ + OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type, + uint32_t buffer_size); + + void update() override; + void loop() override; + + /** Set the URL to download the image from. */ + void set_url(const std::string &url) { + if (this->validate_url_(url)) { + this->url_ = url; + } + } + + /** + * Release the buffer storing the image. The image will need to be downloaded again + * to be able to be displayed. + */ + void release(); + + void add_on_finished_callback(std::function &&callback); + void add_on_error_callback(std::function &&callback); + + protected: + bool validate_url_(const std::string &url); + + using Allocator = ExternalRAMAllocator; + Allocator allocator_{Allocator::Flags::ALLOW_FAILURE}; + + uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); } + int get_buffer_size_(int width, int height) const { + return std::ceil(image::image_type_to_bpp(this->type_) * width * height / 8.0); + } + + int get_position_(int x, int y) const { + return ((x + y * this->buffer_width_) * image::image_type_to_bpp(this->type_)) / 8; + } + + ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; } + + bool resize_(int width, int height); + + /** + * @brief Draw a pixel into the buffer. + * + * This is used by the decoder to fill the buffer that will later be displayed + * by the `draw` method. This will internally convert the supplied 32 bit RGBA + * color into the requested image storage format. + * + * @param x Horizontal pixel position. + * @param y Vertical pixel position. + * @param color 32 bit color to put into the pixel. + */ + void draw_pixel_(int x, int y, Color color); + + void end_connection_(); + + CallbackManager download_finished_callback_{}; + CallbackManager download_error_callback_{}; + + std::shared_ptr downloader_{nullptr}; + std::unique_ptr decoder_{nullptr}; + + uint8_t *buffer_; + DownloadBuffer download_buffer_; + + const ImageFormat format_; + + std::string url_{""}; + + /** width requested on configuration, or 0 if non specified. */ + const int fixed_width_; + /** height requested on configuration, or 0 if non specified. */ + const int fixed_height_; + /** + * Actual width of the current image. If fixed_width_ is specified, + * this will be equal to it; otherwise it will be set once the decoding + * starts and the original size is known. + * This needs to be separate from "BaseImage::get_width()" because the latter + * must return 0 until the image has been decoded (to avoid showing partially + * decoded images). + */ + int buffer_width_; + /** + * Actual height of the current image. If fixed_height_ is specified, + * this will be equal to it; otherwise it will be set once the decoding + * starts and the original size is known. + * This needs to be separate from "BaseImage::get_height()" because the latter + * must return 0 until the image has been decoded (to avoid showing partially + * decoded images). + */ + int buffer_height_; + + friend void ImageDecoder::set_size(int width, int height); + friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color); +}; + +template class OnlineImageSetUrlAction : public Action { + public: + OnlineImageSetUrlAction(OnlineImage *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(const char *, url) + void play(Ts... x) override { + this->parent_->set_url(this->url_.value(x...)); + this->parent_->update(); + } + + protected: + OnlineImage *parent_; +}; + +template class OnlineImageReleaseAction : public Action { + public: + OnlineImageReleaseAction(OnlineImage *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(const char *, url) + void play(Ts... x) override { this->parent_->release(); } + + protected: + OnlineImage *parent_; +}; + +class DownloadFinishedTrigger : public Trigger<> { + public: + explicit DownloadFinishedTrigger(OnlineImage *parent) { + parent->add_on_finished_callback([this]() { this->trigger(); }); + } +}; + +class DownloadErrorTrigger : public Trigger<> { + public: + explicit DownloadErrorTrigger(OnlineImage *parent) { + parent->add_on_error_callback([this]() { this->trigger(); }); + } +}; + +} // namespace online_image +} // namespace esphome diff --git a/esphome/components/online_image/png_image.cpp b/esphome/components/online_image/png_image.cpp new file mode 100644 index 0000000000..c8e215a91d --- /dev/null +++ b/esphome/components/online_image/png_image.cpp @@ -0,0 +1,68 @@ +#include "png_image.h" +#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT + +#include "esphome/components/display/display_buffer.h" +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +static const char *const TAG = "online_image.png"; + +namespace esphome { +namespace online_image { + +/** + * @brief Callback method that will be called by the PNGLE engine when the basic + * data of the image is received (i.e. width and height); + * + * @param pngle The PNGLE object, including the context data. + * @param w The width of the image. + * @param h The height of the image. + */ +static void init_callback(pngle_t *pngle, uint32_t w, uint32_t h) { + PngDecoder *decoder = (PngDecoder *) pngle_get_user_data(pngle); + decoder->set_size(w, h); +} + +/** + * @brief Callback method that will be called by the PNGLE engine when a chunk + * of the image is decoded. + * + * @param pngle The PNGLE object, including the context data. + * @param x The X coordinate to draw the rectangle on. + * @param y The Y coordinate to draw the rectangle on. + * @param w The width of the rectangle to draw. + * @param h The height of the rectangle to draw. + * @param rgba The color to paint the rectangle in. + */ +static void draw_callback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]) { + PngDecoder *decoder = (PngDecoder *) pngle_get_user_data(pngle); + Color color(rgba[0], rgba[1], rgba[2], rgba[3]); + decoder->draw(x, y, w, h, color); +} + +void PngDecoder::prepare(uint32_t download_size) { + ImageDecoder::prepare(download_size); + pngle_set_user_data(this->pngle_, this); + pngle_set_init_callback(this->pngle_, init_callback); + pngle_set_draw_callback(this->pngle_, draw_callback); +} + +int HOT PngDecoder::decode(uint8_t *buffer, size_t size) { + if (size < 256 && size < this->download_size_ - this->decoded_bytes_) { + ESP_LOGD(TAG, "Waiting for data"); + return 0; + } + auto fed = pngle_feed(this->pngle_, buffer, size); + if (fed < 0) { + ESP_LOGE(TAG, "Error decoding image: %s", pngle_error(this->pngle_)); + } else { + this->decoded_bytes_ += fed; + } + return fed; +} + +} // namespace online_image +} // namespace esphome + +#endif // USE_ONLINE_IMAGE_PNG_SUPPORT diff --git a/esphome/components/online_image/png_image.h b/esphome/components/online_image/png_image.h new file mode 100644 index 0000000000..a928276dcc --- /dev/null +++ b/esphome/components/online_image/png_image.h @@ -0,0 +1,33 @@ +#pragma once + +#include "image_decoder.h" +#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT +#include + +namespace esphome { +namespace online_image { + +/** + * @brief Image decoder specialization for PNG images. + */ +class PngDecoder : public ImageDecoder { + public: + /** + * @brief Construct a new PNG Decoder object. + * + * @param display The image to decode the stream into. + */ + PngDecoder(OnlineImage *image) : ImageDecoder(image), pngle_(pngle_new()) {} + ~PngDecoder() override { pngle_destroy(this->pngle_); } + + void prepare(uint32_t download_size) override; + int HOT decode(uint8_t *buffer, size_t size) override; + + protected: + pngle_t *pngle_; +}; + +} // namespace online_image +} // namespace esphome + +#endif // USE_ONLINE_IMAGE_PNG_SUPPORT diff --git a/esphome/core/defines.h b/esphome/core/defines.h index b7bdbb1f9d..61a4940d01 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -53,6 +53,7 @@ #define USE_MQTT #define USE_NEXTION_TFT_UPLOAD #define USE_NUMBER +#define USE_ONLINE_IMAGE_PNG_SUPPORT #define USE_OTA #define USE_OTA_PASSWORD #define USE_OTA_STATE_CALLBACK diff --git a/platformio.ini b/platformio.ini index e4f363d650..87a239207f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,6 +40,7 @@ lib_deps = wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 pavlodn/HaierProtocol@0.9.31 ; haier + kikuchan98/pngle@1.0.2 ; online_image ; This is using the repository until a new release is published to PlatformIO https://github.com/Sensirion/arduino-gas-index-algorithm.git#3.2.1 ; Sensirion Gas Index Algorithm Arduino Library lvgl/lvgl@8.4.0 ; lvgl diff --git a/tests/components/online_image/common-esp32.yaml b/tests/components/online_image/common-esp32.yaml new file mode 100644 index 0000000000..8cc50fc3e0 --- /dev/null +++ b/tests/components/online_image/common-esp32.yaml @@ -0,0 +1,18 @@ +<<: !include common.yaml + +spi: + - id: spi_main_lcd + clk_pin: 16 + mosi_pin: 17 + miso_pin: 15 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + lambda: |- + it.fill(Color(0, 0, 0)); + it.image(0, 0, id(online_rgba_image)); diff --git a/tests/components/online_image/common-esp8266.yaml b/tests/components/online_image/common-esp8266.yaml new file mode 100644 index 0000000000..01e3467413 --- /dev/null +++ b/tests/components/online_image/common-esp8266.yaml @@ -0,0 +1,18 @@ +<<: !include common.yaml + +spi: + - id: spi_main_lcd + clk_pin: 14 + mosi_pin: 13 + miso_pin: 12 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 15 + dc_pin: 3 + reset_pin: 1 + lambda: |- + it.fill(Color(0, 0, 0)); + it.image(0, 0, id(online_rgba_image)); diff --git a/tests/components/online_image/common.yaml b/tests/components/online_image/common.yaml new file mode 100644 index 0000000000..8f7ea6238b --- /dev/null +++ b/tests/components/online_image/common.yaml @@ -0,0 +1,37 @@ +wifi: + ssid: MySSID + password: password1 + +# Purposely test that `online_image:` does auto-load `image:` +# Keep the `image:` undefined. +# image: +online_image: + - id: online_binary_image + url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png + format: PNG + type: BINARY + resize: 50x50 + - id: online_binary_transparent_image + url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png + type: TRANSPARENT_BINARY + format: png + - id: online_rgba_image + url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png + format: PNG + type: RGBA + - id: online_rgb24_image + url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png + format: PNG + type: RGB24 + use_transparency: true + +# Check the set_url action +time: + - platform: sntp + on_time: + - at: "13:37:42" + then: + - online_image.set_url: + id: online_rgba_image + url: http://www.example.org/example.png + diff --git a/tests/components/online_image/test.esp32-ard.yaml b/tests/components/online_image/test.esp32-ard.yaml new file mode 100644 index 0000000000..4111cbd0ad --- /dev/null +++ b/tests/components/online_image/test.esp32-ard.yaml @@ -0,0 +1,4 @@ +<<: !include common-esp32.yaml + +http_request: + verify_ssl: false diff --git a/tests/components/online_image/test.esp32-idf.yaml b/tests/components/online_image/test.esp32-idf.yaml new file mode 100644 index 0000000000..3f01009812 --- /dev/null +++ b/tests/components/online_image/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +<<: !include common-esp32.yaml + +http_request: + From 455df35e50c5c83cdaf46e79156ee203b03dce3a Mon Sep 17 00:00:00 2001 From: Mimoja Date: Tue, 6 Aug 2024 13:17:02 +0200 Subject: [PATCH 2169/2607] Update i2s_audio_speaker.cppi2s_audio/speaker: Fix fallthrough compiler warning (#7167) --- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 6b07ecb1b6..1c6c50d8c9 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -233,6 +233,7 @@ void I2SAudioSpeaker::loop() { switch (this->state_) { case speaker::STATE_STARTING: this->start_(); + [[fallthrough]]; case speaker::STATE_RUNNING: case speaker::STATE_STOPPING: this->watch_(); From 8667f51cf08f1147cf02f56bd882beab837317ba Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 7 Aug 2024 07:15:15 +1200 Subject: [PATCH 2170/2607] Move CONF_ITEMS/CONF_FONT/CONF_TEXT to const.py (#7204) --- .../components/display_menu_base/__init__.py | 29 ++++++++++--------- .../graphical_display_menu/__init__.py | 2 +- esphome/components/lvgl/defines.py | 3 +- esphome/components/lvgl/schemas.py | 5 ++-- esphome/components/lvgl/types.py | 4 +-- .../components/lvgl/widgets/buttonmatrix.py | 4 +-- esphome/components/lvgl/widgets/checkbox.py | 4 ++- esphome/components/lvgl/widgets/keyboard.py | 4 +-- esphome/components/lvgl/widgets/label.py | 2 +- esphome/components/lvgl/widgets/msgbox.py | 3 +- esphome/components/lvgl/widgets/textarea.py | 3 +- esphome/const.py | 3 ++ 12 files changed, 34 insertions(+), 32 deletions(-) diff --git a/esphome/components/display_menu_base/__init__.py b/esphome/components/display_menu_base/__init__.py index 0c738ba838..8ae9cbc2a4 100644 --- a/esphome/components/display_menu_base/__init__.py +++ b/esphome/components/display_menu_base/__init__.py @@ -1,23 +1,26 @@ import re -import esphome.codegen as cg -import esphome.config_validation as cv + from esphome import automation, core +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +from esphome.components.number import Number +from esphome.components.select import Select +from esphome.components.switch import Switch +import esphome.config_validation as cv from esphome.const import ( - CONF_ID, - CONF_TYPE, - CONF_TRIGGER_ID, - CONF_ON_VALUE, + CONF_ACTIVE, CONF_COMMAND, CONF_CUSTOM, - CONF_NUMBER, CONF_FORMAT, + CONF_ID, + CONF_ITEMS, CONF_MODE, - CONF_ACTIVE, + CONF_NUMBER, + CONF_ON_VALUE, + CONF_TEXT, + CONF_TRIGGER_ID, + CONF_TYPE, ) -from esphome.automation import maybe_simple_id -from esphome.components.select import Select -from esphome.components.number import Number -from esphome.components.switch import Switch CODEOWNERS = ["@numo68"] @@ -29,10 +32,8 @@ CONF_JOYSTICK = "joystick" CONF_LABEL = "label" CONF_MENU = "menu" CONF_BACK = "back" -CONF_TEXT = "text" CONF_SELECT = "select" CONF_SWITCH = "switch" -CONF_ITEMS = "items" CONF_ON_TEXT = "on_text" CONF_OFF_TEXT = "off_text" CONF_VALUE_LAMBDA = "value_lambda" diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index d7146a7381..f4d59b22b8 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -10,12 +10,12 @@ import esphome.config_validation as cv from esphome.const import ( CONF_BACKGROUND_COLOR, CONF_DISPLAY, + CONF_FONT, CONF_FOREGROUND_COLOR, CONF_ID, CONF_TRIGGER_ID, ) -CONF_FONT = "font" CONF_MENU_ITEM_VALUE = "menu_item_value" CONF_ON_REDRAW = "on_redraw" diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index ac28f9ed5f..1b41b32c90 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -5,6 +5,7 @@ Constants already defined in esphome.const are not duplicated here and must be i """ from esphome import codegen as cg, config_validation as cv +from esphome.const import CONF_ITEMS from esphome.core import ID, Lambda from esphome.cpp_generator import MockObj from esphome.cpp_types import uint32 @@ -115,7 +116,6 @@ CONF_SCROLLBAR = "scrollbar" CONF_INDICATOR = "indicator" CONF_KNOB = "knob" CONF_SELECTED = "selected" -CONF_ITEMS = "items" CONF_TICKS = "ticks" CONF_CURSOR = "cursor" CONF_TEXTAREA_PLACEHOLDER = "textarea_placeholder" @@ -460,7 +460,6 @@ CONF_SKIP = "skip" CONF_SYMBOL = "symbol" CONF_TAB_ID = "tab_id" CONF_TABS = "tabs" -CONF_TEXT = "text" CONF_TILE = "tile" CONF_TILE_ID = "tile_id" CONF_TILES = "tiles" diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 796783890d..62536bf4d5 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_ID, CONF_ON_VALUE, CONF_STATE, + CONF_TEXT, CONF_TRIGGER_ID, CONF_TYPE, ) @@ -25,7 +26,7 @@ WIDGET_TYPES: dict = {} # A schema for text properties TEXT_SCHEMA = cv.Schema( { - cv.Optional(df.CONF_TEXT): cv.Any( + cv.Optional(CONF_TEXT): cv.Any( cv.All( cv.Schema( { @@ -330,7 +331,7 @@ DISP_BG_SCHEMA = cv.Schema( # A style schema that can include text STYLED_TEXT_SCHEMA = cv.maybe_simple_value( - STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT + STYLE_SCHEMA.extend(TEXT_SCHEMA), key=CONF_TEXT ) # For use by platform components diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index b6f65c8c1b..be17cf62c2 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -1,10 +1,10 @@ import sys from esphome import automation, codegen as cg -from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_VALUE +from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_TEXT, CONF_VALUE from esphome.cpp_generator import MockObj, MockObjClass -from .defines import CONF_TEXT, lvgl_ns +from .defines import lvgl_ns from .lvcode import lv_expr diff --git a/esphome/components/lvgl/widgets/buttonmatrix.py b/esphome/components/lvgl/widgets/buttonmatrix.py index 274b4de5ab..e61c5e3477 100644 --- a/esphome/components/lvgl/widgets/buttonmatrix.py +++ b/esphome/components/lvgl/widgets/buttonmatrix.py @@ -2,7 +2,7 @@ from esphome import automation import esphome.codegen as cg from esphome.components.key_provider import KeyProvider import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_WIDTH +from esphome.const import CONF_ID, CONF_ITEMS, CONF_TEXT, CONF_WIDTH from esphome.cpp_generator import MockObj from ..automation import action_to_code @@ -10,13 +10,11 @@ from ..defines import ( BUTTONMATRIX_CTRLS, CONF_BUTTONS, CONF_CONTROL, - CONF_ITEMS, CONF_KEY_CODE, CONF_MAIN, CONF_ONE_CHECKED, CONF_ROWS, CONF_SELECTED, - CONF_TEXT, ) from ..helpers import lvgl_components_required from ..lv_validation import key_code, lv_bool diff --git a/esphome/components/lvgl/widgets/checkbox.py b/esphome/components/lvgl/widgets/checkbox.py index 6299a2a6a2..79c60a8669 100644 --- a/esphome/components/lvgl/widgets/checkbox.py +++ b/esphome/components/lvgl/widgets/checkbox.py @@ -1,4 +1,6 @@ -from ..defines import CONF_INDICATOR, CONF_MAIN, CONF_TEXT +from esphome.const import CONF_TEXT + +from ..defines import CONF_INDICATOR, CONF_MAIN from ..lv_validation import lv_text from ..lvcode import lv from ..schemas import TEXT_SCHEMA diff --git a/esphome/components/lvgl/widgets/keyboard.py b/esphome/components/lvgl/widgets/keyboard.py index cff322f5af..ba7edb302e 100644 --- a/esphome/components/lvgl/widgets/keyboard.py +++ b/esphome/components/lvgl/widgets/keyboard.py @@ -1,9 +1,9 @@ from esphome.components.key_provider import KeyProvider import esphome.config_validation as cv -from esphome.const import CONF_MODE +from esphome.const import CONF_ITEMS, CONF_MODE from esphome.cpp_types import std_string -from ..defines import CONF_ITEMS, CONF_MAIN, KEYBOARD_MODES, literal +from ..defines import CONF_MAIN, KEYBOARD_MODES, literal from ..helpers import add_lv_use, lvgl_components_required from ..types import LvCompound, LvType from . import Widget, WidgetType, get_widgets diff --git a/esphome/components/lvgl/widgets/label.py b/esphome/components/lvgl/widgets/label.py index 38f688f2b0..6b04235674 100644 --- a/esphome/components/lvgl/widgets/label.py +++ b/esphome/components/lvgl/widgets/label.py @@ -1,4 +1,5 @@ import esphome.config_validation as cv +from esphome.const import CONF_TEXT from ..defines import ( CONF_LONG_MODE, @@ -6,7 +7,6 @@ from ..defines import ( CONF_RECOLOR, CONF_SCROLLBAR, CONF_SELECTED, - CONF_TEXT, LV_LONG_MODES, ) from ..lv_validation import lv_bool, lv_text diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index 4ae5be7701..63c4326c7c 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -1,5 +1,5 @@ from esphome import config_validation as cv -from esphome.const import CONF_BUTTON, CONF_ID +from esphome.const import CONF_BUTTON, CONF_ID, CONF_TEXT from esphome.core import ID from esphome.cpp_generator import new_Pvariable, static_const_array from esphome.cpp_types import nullptr @@ -9,7 +9,6 @@ from ..defines import ( CONF_BUTTONS, CONF_CLOSE_BUTTON, CONF_MSGBOXES, - CONF_TEXT, CONF_TITLE, TYPE_FLEX, literal, diff --git a/esphome/components/lvgl/widgets/textarea.py b/esphome/components/lvgl/widgets/textarea.py index 61d83dee9c..23d50b3894 100644 --- a/esphome/components/lvgl/widgets/textarea.py +++ b/esphome/components/lvgl/widgets/textarea.py @@ -1,5 +1,5 @@ import esphome.config_validation as cv -from esphome.const import CONF_MAX_LENGTH +from esphome.const import CONF_MAX_LENGTH, CONF_TEXT from ..defines import ( CONF_ACCEPTED_CHARS, @@ -10,7 +10,6 @@ from ..defines import ( CONF_PLACEHOLDER_TEXT, CONF_SCROLLBAR, CONF_SELECTED, - CONF_TEXT, CONF_TEXTAREA_PLACEHOLDER, ) from ..lv_validation import lv_bool, lv_int, lv_text diff --git a/esphome/const.py b/esphome/const.py index d7b1f558a1..13559ecf95 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -308,6 +308,7 @@ CONF_FLASH_LENGTH = "flash_length" CONF_FLASH_TRANSITION_LENGTH = "flash_transition_length" CONF_FLOW = "flow" CONF_FLOW_CONTROL_PIN = "flow_control_pin" +CONF_FONT = "font" CONF_FOR = "for" CONF_FORCE_UPDATE = "force_update" CONF_FOREGROUND_COLOR = "foreground_color" @@ -407,6 +408,7 @@ CONF_INVERTED = "inverted" CONF_IP_ADDRESS = "ip_address" CONF_IRQ_PIN = "irq_pin" CONF_IS_RGBW = "is_rgbw" +CONF_ITEMS = "items" CONF_JS_INCLUDE = "js_include" CONF_JS_URL = "js_url" CONF_JVC = "jvc" @@ -841,6 +843,7 @@ CONF_TEMPERATURE = "temperature" CONF_TEMPERATURE_OFFSET = "temperature_offset" CONF_TEMPERATURE_SOURCE = "temperature_source" CONF_TEMPERATURE_STEP = "temperature_step" +CONF_TEXT = "text" CONF_TEXT_SENSORS = "text_sensors" CONF_THEN = "then" CONF_THRESHOLD = "threshold" From eccc5a3ea31853986aeae1b66ceaca438aede161 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 7 Aug 2024 05:15:28 +1000 Subject: [PATCH 2171/2607] [lvgl] Fix compile error when using encoder with buttons only. (#7203) --- esphome/components/lvgl/__init__.py | 6 ++-- esphome/components/lvgl/defines.py | 2 +- .../lvgl/{rotary_encoders.py => encoders.py} | 24 +++++++------- esphome/components/lvgl/lvgl_esphome.cpp | 4 +-- esphome/components/lvgl/lvgl_esphome.h | 21 +++++++----- esphome/components/lvgl/schemas.py | 8 ++--- esphome/components/lvgl/widgets/__init__.py | 32 +++---------------- tests/components/lvgl/test.esp32-ard.yaml | 27 ++++++++++++++++ tests/components/lvgl/test.esp32-idf.yaml | 2 +- 9 files changed, 68 insertions(+), 58 deletions(-) rename esphome/components/lvgl/{rotary_encoders.py => encoders.py} (77%) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 9eb4665874..87fbcab4dc 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -23,9 +23,9 @@ from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid from .automation import disp_update, update_to_code from .defines import CONF_SKIP +from .encoders import ENCODERS_CONFIG, encoders_to_code from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent -from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code from .schemas import ( DISP_BG_SCHEMA, FLEX_OBJ_SCHEMA, @@ -256,7 +256,7 @@ async def to_code(config): async with LvContext(lv_component): await touchscreens_to_code(lv_component, config) - await rotary_encoders_to_code(lv_component, config) + await encoders_to_code(lv_component, config) await theme_to_code(config) await styles_to_code(config) await set_obj_properties(lv_scr_act, config) @@ -336,7 +336,7 @@ CONFIG_SCHEMA = ( {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} ), cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, - cv.GenerateID(df.CONF_ROTARY_ENCODERS): ROTARY_ENCODER_CONFIG, + cv.GenerateID(df.CONF_ENCODERS): ENCODERS_CONFIG, } ) .extend(DISP_BG_SCHEMA) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 1b41b32c90..d0047b59f7 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -388,6 +388,7 @@ CONF_DEFAULT = "default" CONF_DEFAULT_FONT = "default_font" CONF_DIR = "dir" CONF_DISPLAYS = "displays" +CONF_ENCODERS = "encoders" CONF_END_ANGLE = "end_angle" CONF_END_VALUE = "end_value" CONF_ENTER_BUTTON = "enter_button" @@ -441,7 +442,6 @@ CONF_RECOLOR = "recolor" CONF_RIGHT_BUTTON = "right_button" CONF_ROLLOVER = "rollover" CONF_ROOT_BACK_BTN = "root_back_btn" -CONF_ROTARY_ENCODERS = "rotary_encoders" CONF_ROWS = "rows" CONF_SCALE_LINES = "scale_lines" CONF_SCROLLBAR_MODE = "scrollbar_mode" diff --git a/esphome/components/lvgl/rotary_encoders.py b/esphome/components/lvgl/encoders.py similarity index 77% rename from esphome/components/lvgl/rotary_encoders.py rename to esphome/components/lvgl/encoders.py index d8a82dbc78..caddc2e47f 100644 --- a/esphome/components/lvgl/rotary_encoders.py +++ b/esphome/components/lvgl/encoders.py @@ -5,25 +5,26 @@ import esphome.config_validation as cv from esphome.const import CONF_GROUP, CONF_ID, CONF_SENSOR from .defines import ( + CONF_ENCODERS, CONF_ENTER_BUTTON, CONF_LEFT_BUTTON, CONF_LONG_PRESS_REPEAT_TIME, CONF_LONG_PRESS_TIME, CONF_RIGHT_BUTTON, - CONF_ROTARY_ENCODERS, ) -from .helpers import lvgl_components_required -from .lvcode import lv, lv_add, lv_expr +from .helpers import lvgl_components_required, requires_component +from .lvcode import lv, lv_add, lv_assign, lv_expr, lv_Pvariable from .schemas import ENCODER_SCHEMA -from .types import lv_indev_type_t -from .widgets import add_group +from .types import lv_group_t, lv_indev_type_t -ROTARY_ENCODER_CONFIG = cv.ensure_list( +ENCODERS_CONFIG = cv.ensure_list( ENCODER_SCHEMA.extend( { cv.Required(CONF_ENTER_BUTTON): cv.use_id(BinarySensor), cv.Required(CONF_SENSOR): cv.Any( - cv.use_id(RotaryEncoderSensor), + cv.All( + cv.use_id(RotaryEncoderSensor), requires_component("rotary_encoder") + ), cv.Schema( { cv.Required(CONF_LEFT_BUTTON): cv.use_id(BinarySensor), @@ -36,10 +37,9 @@ ROTARY_ENCODER_CONFIG = cv.ensure_list( ) -async def rotary_encoders_to_code(var, config): - for enc_conf in config.get(CONF_ROTARY_ENCODERS, ()): +async def encoders_to_code(var, config): + for enc_conf in config.get(CONF_ENCODERS, ()): lvgl_components_required.add("KEY_LISTENER") - lvgl_components_required.add("ROTARY_ENCODER") lpt = enc_conf[CONF_LONG_PRESS_TIME].total_milliseconds lprt = enc_conf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds listener = cg.new_Pvariable( @@ -57,7 +57,9 @@ async def rotary_encoders_to_code(var, config): lv_add(listener.set_sensor(sensor_config)) b_sensor = await cg.get_variable(enc_conf[CONF_ENTER_BUTTON]) cg.add(listener.set_enter_button(b_sensor)) - if group := add_group(enc_conf.get(CONF_GROUP)): + if group := enc_conf.get(CONF_GROUP): + group = lv_Pvariable(lv_group_t, group) + lv_assign(group, lv_expr.group_create()) lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) else: lv.indev_drv_register(listener.get_drv()) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 544643d532..6f23c2421b 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -127,7 +127,7 @@ void LVTouchListener::update(const touchscreen::TouchPoints_t &tpoints) { } #endif // USE_LVGL_TOUCHSCREEN -#ifdef USE_LVGL_ROTARY_ENCODER +#ifdef USE_LVGL_KEY_LISTENER LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { lv_indev_drv_init(&this->drv_); this->drv_.type = type; @@ -143,7 +143,7 @@ LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_ data->continue_reading = false; }; } -#endif // USE_LVGL_ROTARY_ENCODER +#endif // USE_LVGL_KEY_LISTENER #ifdef USE_LVGL_BUTTONMATRIX void LvButtonMatrixType::set_obj(lv_obj_t *lv_obj) { diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 5f2f0ea8df..45841b99d9 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -1,6 +1,13 @@ #pragma once #include "esphome/core/defines.h" +#ifdef USE_LVGL_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif // USE_LVGL_BINARY_SENSOR +#ifdef USE_LVGL_ROTARY_ENCODER +#include "esphome/components/rotary_encoder/rotary_encoder.h" +#endif // USE_LVGL_ROTARY_ENCODER + // required for clang-tidy #ifndef LV_CONF_H #define LV_CONF_SKIP 1 // NOLINT @@ -12,12 +19,7 @@ #include "esphome/core/log.h" #include #include - -#ifdef USE_LVGL_ROTARY_ENCODER -#include "esphome/components/binary_sensor/binary_sensor.h" -#include "esphome/components/rotary_encoder/rotary_encoder.h" -#endif // USE_LVGL_ROTARY_ENCODER - +#include #ifdef USE_LVGL_IMAGE #include "esphome/components/image/image.h" #endif // USE_LVGL_IMAGE @@ -202,7 +204,7 @@ class LVTouchListener : public touchscreen::TouchListener, public Parented { public: LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt); @@ -218,9 +220,11 @@ class LVEncoderListener : public Parented { enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); }); } +#ifdef USE_LVGL_ROTARY_ENCODER void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor) { sensor->register_listener([this](int32_t count) { this->set_count(count); }); } +#endif // USE_LVGL_ROTARY_ENCODER void event(int key, bool pressed) { if (!this->parent_->is_paused()) { @@ -243,7 +247,8 @@ class LVEncoderListener : public Parented { int32_t last_count_{}; int key_{}; }; -#endif // USE_LVGL_ROTARY_ENCODER +#endif // USE_LVGL_KEY_LISTENER + #ifdef USE_LVGL_BUTTONMATRIX class LvButtonMatrixType : public key_provider::KeyProvider, public LvCompound { public: diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 62536bf4d5..f172ba9f2b 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -16,9 +16,9 @@ from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid, types as ty from .helpers import add_lv_use, requires_component, validate_printf -from .lv_validation import id_name, lv_color, lv_font, lv_image +from .lv_validation import lv_color, lv_font, lv_image from .lvcode import LvglComponent -from .types import WidgetType +from .types import WidgetType, lv_group_t # this will be populated later, in __init__.py to avoid circular imports. WIDGET_TYPES: dict = {} @@ -61,7 +61,7 @@ ENCODER_SCHEMA = cv.Schema( cv.GenerateID(): cv.All( cv.declare_id(ty.LVEncoderListener), requires_component("binary_sensor") ), - cv.Optional(CONF_GROUP): lvalid.id_name, + cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t), cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, } @@ -249,7 +249,7 @@ def obj_schema(widget_type: WidgetType): cv.Schema( { cv.Optional(CONF_STATE): SET_STATE_SCHEMA, - cv.Optional(CONF_GROUP): id_name, + cv.Optional(CONF_GROUP): cv.use_id(lv_group_t), } ) ) diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index dff43cf257..f1946015bc 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -6,7 +6,7 @@ from esphome.config_validation import Invalid from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE from esphome.core import ID, TimePeriod from esphome.coroutine import FakeAwaitable -from esphome.cpp_generator import AssignmentExpression, CallExpression, MockObj +from esphome.cpp_generator import CallExpression, MockObj from ..defines import ( CONF_DEFAULT, @@ -44,15 +44,7 @@ from ..lvcode import ( lv_Pvariable, ) from ..schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES -from ..types import ( - LV_STATE, - LvType, - WidgetType, - lv_coord_t, - lv_group_t, - lv_obj_t, - lv_obj_t_ptr, -) +from ..types import LV_STATE, LvType, WidgetType, lv_coord_t, lv_obj_t, lv_obj_t_ptr EVENT_LAMB = "event_lamb__" @@ -317,7 +309,8 @@ async def set_obj_properties(w: Widget, config): value = await ALL_STYLES[prop].process(value) prop_r = STYLE_REMAP.get(prop, prop) w.set_style(prop_r, value, lv_state) - if group := add_group(config.get(CONF_GROUP)): + if group := config.get(CONF_GROUP): + group = await cg.get_variable(group) lv.group_add_obj(group, w.obj) flag_clr = set() flag_set = set() @@ -404,20 +397,3 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent): lv_scr_act_spec = LvScrActType() lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {}) - -lv_groups = {} # Widget group names - - -def add_group(name): - if name is None: - return None - fullname = f"lv_esp_group_{name}" - if name not in lv_groups: - gid = ID(fullname, True, type=lv_group_t.operator("ptr")) - lv_add( - AssignmentExpression( - type_=gid.type, modifier="", name=fullname, rhs=lv_expr.group_create() - ) - ) - lv_groups[name] = literal(fullname) - return lv_groups[name] diff --git a/tests/components/lvgl/test.esp32-ard.yaml b/tests/components/lvgl/test.esp32-ard.yaml index abfb324ea5..2d6a6871ba 100644 --- a/tests/components/lvgl/test.esp32-ard.yaml +++ b/tests/components/lvgl/test.esp32-ard.yaml @@ -24,6 +24,33 @@ display: invert_colors: false update_interval: never +binary_sensor: + - platform: gpio + internal: true + id: up_button + pin: + number: GPIO38 + inverted: true + - platform: gpio + internal: true + id: down_button + pin: + number: GPIO37 + inverted: true + - platform: gpio + internal: true + id: select_button + pin: + number: GPIO39 + inverted: true +lvgl: + encoders: + group: switches + enter_button: select_button + sensor: + left_button: up_button + right_button: down_button + packages: lvgl: !include lvgl-package.yaml diff --git a/tests/components/lvgl/test.esp32-idf.yaml b/tests/components/lvgl/test.esp32-idf.yaml index 0f740db980..927d72d15c 100644 --- a/tests/components/lvgl/test.esp32-idf.yaml +++ b/tests/components/lvgl/test.esp32-idf.yaml @@ -67,7 +67,7 @@ lvgl: displays: - tft_display - second_display - rotary_encoders: + encoders: sensor: encoder enter_button: pushbutton group: general From da0dbe8753645b753a9dc64fb6ad21ccd29a867c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 7 Aug 2024 07:29:05 +1200 Subject: [PATCH 2172/2607] Revert "Add null GPIO pin " (#6621) --- .../cst226/touchscreen/cst226_touchscreen.cpp | 18 +++++++++++------- .../cst226/touchscreen/cst226_touchscreen.h | 2 +- esphome/core/gpio.h | 18 ------------------ 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp index 69728dc666..d4e43d30f5 100644 --- a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +++ b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp @@ -5,13 +5,17 @@ namespace cst226 { void CST226Touchscreen::setup() { esph_log_config(TAG, "Setting up CST226 Touchscreen..."); - this->reset_pin_->setup(); - this->reset_pin_->digital_write(true); - delay(5); - this->reset_pin_->digital_write(false); - delay(5); - this->reset_pin_->digital_write(true); - this->set_timeout(30, [this] { this->continue_setup_(); }); + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(true); + delay(5); + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + this->set_timeout(30, [this] { this->continue_setup_(); }); + } else { + this->continue_setup_(); + } } void CST226Touchscreen::update_touches() { diff --git a/esphome/components/cst226/touchscreen/cst226_touchscreen.h b/esphome/components/cst226/touchscreen/cst226_touchscreen.h index 1b15b952c4..9f518e5068 100644 --- a/esphome/components/cst226/touchscreen/cst226_touchscreen.h +++ b/esphome/components/cst226/touchscreen/cst226_touchscreen.h @@ -35,7 +35,7 @@ class CST226Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice void continue_setup_(); InternalGPIOPin *interrupt_pin_{}; - GPIOPin *reset_pin_{NULL_PIN}; + GPIOPin *reset_pin_{}; uint8_t chip_id_{}; bool setup_complete_{}; }; diff --git a/esphome/core/gpio.h b/esphome/core/gpio.h index b3f6b00196..1b6f2ba1e6 100644 --- a/esphome/core/gpio.h +++ b/esphome/core/gpio.h @@ -62,24 +62,6 @@ class GPIOPin { virtual bool is_internal() { return false; } }; -/** - * A pin to replace those that don't exist. - */ -class NullPin : public GPIOPin { - public: - void setup() override {} - - void pin_mode(gpio::Flags _) override {} - - bool digital_read() override { return false; } - - void digital_write(bool _) override {} - - std::string dump_summary() const override { return {"Not used"}; } -}; - -static GPIOPin *const NULL_PIN = new NullPin(); - /// Copy of GPIOPin that is safe to use from ISRs (with no virtual functions) class ISRInternalGPIOPin { public: From 1e63fddf36390794c4aa70e6a9e508b23b4fa852 Mon Sep 17 00:00:00 2001 From: iannisimo <11798717+iannisimo@users.noreply.github.com> Date: Wed, 7 Aug 2024 01:02:30 +0200 Subject: [PATCH 2173/2607] [remote_transmitter] Change default carrier_frequency to valid value (#7176) set current_carrier_frequency_ default value to esp-idf's default (38000) --- esphome/components/remote_transmitter/remote_transmitter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index b897fa8fab..a5896796c0 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -49,7 +49,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, #ifdef USE_ESP32 void configure_rmt_(); - uint32_t current_carrier_frequency_{UINT32_MAX}; + uint32_t current_carrier_frequency_{38000}; bool initialized_{false}; std::vector rmt_temp_; esp_err_t error_code_{ESP_OK}; From 73f786c606dd3ad913e4d27553acd620548a0349 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:46:37 +1200 Subject: [PATCH 2174/2607] [code-quality] Organise script imports (#7198) --- script/build_codeowners.py | 8 ++++---- script/build_language_schema.py | 14 +++++++------- script/bump-version.py | 2 +- script/clang-format | 12 +++--------- script/clang-tidy | 29 ++++++++++++++--------------- script/helpers.py | 2 +- script/lint-python | 19 ++++++++++--------- script/list-components.py | 9 +++++---- 8 files changed, 45 insertions(+), 50 deletions(-) diff --git a/script/build_codeowners.py b/script/build_codeowners.py index 6bc558d351..db34ad7702 100755 --- a/script/build_codeowners.py +++ b/script/build_codeowners.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 -from pathlib import Path -import sys import argparse from collections import defaultdict +from pathlib import Path +import sys -from esphome.helpers import write_file_if_changed from esphome.config import get_component, get_platform -from esphome.core import CORE from esphome.const import KEY_CORE, KEY_TARGET_FRAMEWORK +from esphome.core import CORE +from esphome.helpers import write_file_if_changed parser = argparse.ArgumentParser() parser.add_argument( diff --git a/script/build_language_schema.py b/script/build_language_schema.py index cb3dc1832d..8b2c28b06b 100644 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -1,9 +1,10 @@ +import argparse +import glob import inspect import json -import argparse import os -import glob import re + import voluptuous as vol # NOTE: Cannot import other esphome components globally as a modification in vol_schema @@ -94,13 +95,12 @@ load_components() # Import esphome after loading components (so schema is tracked) # pylint: disable=wrong-import-position -import esphome.core as esphome_core -import esphome.config_validation as cv -from esphome import automation -from esphome import pins +from esphome import automation, pins from esphome.components import remote_base -from esphome.loader import get_platform, CORE_COMPONENTS_PATH +import esphome.config_validation as cv +import esphome.core as esphome_core from esphome.helpers import write_file_if_changed +from esphome.loader import CORE_COMPONENTS_PATH, get_platform from esphome.util import Registry # pylint: enable=wrong-import-position diff --git a/script/bump-version.py b/script/bump-version.py index a55bb65cd6..8389d482b8 100755 --- a/script/bump-version.py +++ b/script/bump-version.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 import argparse -import re from dataclasses import dataclass +import re import sys diff --git a/script/clang-format b/script/clang-format index b065d80795..d922c5b6f1 100755 --- a/script/clang-format +++ b/script/clang-format @@ -1,15 +1,6 @@ #!/usr/bin/env python3 -from helpers import ( - print_error_for_file, - get_output, - git_ls_files, - filter_changed, - get_binary, -) import argparse -import click -import colorama import multiprocessing import os import queue @@ -18,6 +9,9 @@ import subprocess import sys import threading +import click +import colorama +from helpers import filter_changed, get_binary, git_ls_files, print_error_for_file def run_format(executable, args, queue, lock, failed_files): diff --git a/script/clang-tidy b/script/clang-tidy index bd919825fd..ea522157c5 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -1,21 +1,6 @@ #!/usr/bin/env python3 -from helpers import ( - print_error_for_file, - get_output, - filter_grep, - build_all_include, - temp_header_file, - git_ls_files, - filter_changed, - load_idedata, - root_path, - basepath, - get_binary, -) import argparse -import click -import colorama import multiprocessing import os import queue @@ -26,6 +11,20 @@ import sys import tempfile import threading +import click +import colorama +from helpers import ( + basepath, + build_all_include, + filter_changed, + filter_grep, + get_binary, + git_ls_files, + load_idedata, + print_error_for_file, + root_path, + temp_header_file, +) def clang_options(idedata): diff --git a/script/helpers.py b/script/helpers.py index 52b0658fb6..56349b6052 100644 --- a/script/helpers.py +++ b/script/helpers.py @@ -1,8 +1,8 @@ import json import os.path +from pathlib import Path import re import subprocess -from pathlib import Path import colorama diff --git a/script/lint-python b/script/lint-python index 7de1de80b0..01e5e76190 100755 --- a/script/lint-python +++ b/script/lint-python @@ -1,19 +1,20 @@ #!/usr/bin/env python3 -from helpers import ( - styled, - print_error_for_file, - get_output, - get_err, - git_ls_files, - filter_changed, -) import argparse -import colorama import os import re import sys +import colorama +from helpers import ( + filter_changed, + get_err, + get_output, + git_ls_files, + print_error_for_file, + styled, +) + curfile = None diff --git a/script/list-components.py b/script/list-components.py index 559919bb8a..0d4777436b 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 +import argparse from pathlib import Path import sys -import argparse -from helpers import git_ls_files, changed_files -from esphome.loader import get_component, get_platform -from esphome.core import CORE +from helpers import changed_files, git_ls_files + from esphome.const import ( KEY_CORE, KEY_TARGET_FRAMEWORK, @@ -13,6 +12,8 @@ from esphome.const import ( PLATFORM_ESP32, PLATFORM_ESP8266, ) +from esphome.core import CORE +from esphome.loader import get_component, get_platform def filter_component_files(str): From 9b0c2234d89c4f6a642a9fefc77f2e7f0a1c5ef7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:47:46 +1200 Subject: [PATCH 2175/2607] [max31856] Use cv.frequency as validator (#7212) --- esphome/components/max31856/sensor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index 71f1f3bfa5..bf9741aeed 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import sensor, spi +import esphome.config_validation as cv from esphome.const import ( CONF_MAINS_FILTER, DEVICE_CLASS_TEMPERATURE, @@ -15,8 +15,8 @@ MAX31856Sensor = max31856_ns.class_( MAX31865ConfigFilter = max31856_ns.enum("MAX31856ConfigFilter") FILTER = { - "50HZ": MAX31865ConfigFilter.FILTER_50HZ, - "60HZ": MAX31865ConfigFilter.FILTER_60HZ, + 50: MAX31865ConfigFilter.FILTER_50HZ, + 60: MAX31865ConfigFilter.FILTER_60HZ, } CONFIG_SCHEMA = ( @@ -29,8 +29,8 @@ CONFIG_SCHEMA = ( ) .extend( { - cv.Optional(CONF_MAINS_FILTER, default="60HZ"): cv.enum( - FILTER, upper=True, space="" + cv.Optional(CONF_MAINS_FILTER, default="60Hz"): cv.All( + cv.frequency, cv.enum(FILTER, int=True) ), } ) From c348efa401ea64b6a07ae6671fc16f62f3dcb1e2 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 7 Aug 2024 05:49:51 +0200 Subject: [PATCH 2176/2607] [code-quality] Organise base entities imports (#7208) --- esphome/components/binary_sensor/__init__.py | 10 +++--- esphome/components/button/__init__.py | 8 ++--- esphome/components/climate/__init__.py | 10 +++--- esphome/components/cover/__init__.py | 16 +++++----- esphome/components/datetime/__init__.py | 26 +++++++-------- esphome/components/event/__init__.py | 10 +++--- esphome/components/fan/__init__.py | 28 ++++++++--------- esphome/components/light/__init__.py | 33 ++++++++++---------- esphome/components/lock/__init__.py | 6 ++-- esphome/components/media_player/__init__.py | 8 ++--- esphome/components/number/__init__.py | 17 +++++----- esphome/components/select/__init__.py | 14 ++++----- esphome/components/sensor/__init__.py | 20 ++++++------ esphome/components/switch/__init__.py | 6 ++-- esphome/components/text/__init__.py | 10 +++--- esphome/components/text_sensor/__init__.py | 14 ++++----- esphome/components/valve/__init__.py | 6 ++-- 17 files changed, 119 insertions(+), 123 deletions(-) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 11a1887206..95fd17bcc0 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -1,10 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.cpp_generator import MockObjClass -from esphome.cpp_helpers import setup_entity from esphome import automation, core from esphome.automation import Condition, maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_DELAY, CONF_DEVICE_CLASS, @@ -16,6 +14,7 @@ from esphome.const import ( CONF_INVERTED, CONF_MAX_LENGTH, CONF_MIN_LENGTH, + CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, CONF_ON_MULTI_CLICK, @@ -26,7 +25,6 @@ from esphome.const import ( CONF_STATE, CONF_TIMING, CONF_TRIGGER_ID, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY_CHARGING, @@ -59,6 +57,8 @@ from esphome.const import ( DEVICE_CLASS_WINDOW, ) from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_generator import MockObjClass +from esphome.cpp_helpers import setup_entity from esphome.util import Registry CODEOWNERS = ["@esphome/core"] diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 773ab9d37f..3010d3006a 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -1,16 +1,16 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, CONF_ICON, CONF_ID, + CONF_MQTT_ID, CONF_ON_PRESS, CONF_TRIGGER_ID, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_IDENTIFY, @@ -18,8 +18,8 @@ from esphome.const import ( DEVICE_CLASS_UPDATE, ) from esphome.core import CORE, coroutine_with_priority -from esphome.cpp_helpers import setup_entity from esphome.cpp_generator import MockObjClass +from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@esphome/core"] IS_PLATFORM_COMPONENT = True diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index ccd7a3da4e..c7e4ce7745 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -1,8 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.cpp_helpers import setup_entity from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_ACTION_STATE_TOPIC, CONF_AWAY, @@ -21,6 +20,7 @@ from esphome.const import ( CONF_MODE, CONF_MODE_COMMAND_TOPIC, CONF_MODE_STATE_TOPIC, + CONF_MQTT_ID, CONF_ON_CONTROL, CONF_ON_STATE, CONF_PRESET, @@ -33,20 +33,20 @@ from esphome.const import ( CONF_TARGET_HUMIDITY_STATE_TOPIC, CONF_TARGET_TEMPERATURE, CONF_TARGET_TEMPERATURE_COMMAND_TOPIC, - CONF_TARGET_TEMPERATURE_STATE_TOPIC, CONF_TARGET_TEMPERATURE_HIGH, CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC, CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC, CONF_TARGET_TEMPERATURE_LOW, CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC, CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC, + CONF_TARGET_TEMPERATURE_STATE_TOPIC, CONF_TEMPERATURE_STEP, CONF_TRIGGER_ID, CONF_VISUAL, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, ) from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_helpers import setup_entity IS_PLATFORM_COMPONENT = True diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 313b2c5928..d25dd91148 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -1,23 +1,23 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation -from esphome.automation import maybe_simple_id, Condition +from esphome.automation import Condition, maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( - CONF_ID, CONF_DEVICE_CLASS, - CONF_STATE, + CONF_ID, + CONF_MQTT_ID, CONF_ON_OPEN, CONF_POSITION, CONF_POSITION_COMMAND_TOPIC, CONF_POSITION_STATE_TOPIC, + CONF_STATE, + CONF_STOP, CONF_TILT, CONF_TILT_COMMAND_TOPIC, CONF_TILT_STATE_TOPIC, - CONF_STOP, - CONF_MQTT_ID, - CONF_WEB_SERVER_ID, CONF_TRIGGER_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_AWNING, DEVICE_CLASS_BLIND, DEVICE_CLASS_CURTAIN, diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index c118216a2d..4fda97c5bc 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -1,32 +1,30 @@ -import esphome.codegen as cg - -import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt, web_server, time +import esphome.codegen as cg +from esphome.components import mqtt, time, web_server +import esphome.config_validation as cv from esphome.const import ( + CONF_DATE, + CONF_DATETIME, + CONF_DAY, + CONF_HOUR, CONF_ID, + CONF_MINUTE, + CONF_MONTH, + CONF_MQTT_ID, CONF_ON_TIME, CONF_ON_VALUE, + CONF_SECOND, + CONF_TIME, CONF_TIME_ID, CONF_TRIGGER_ID, CONF_TYPE, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, - CONF_DATE, - CONF_DATETIME, - CONF_TIME, CONF_YEAR, - CONF_MONTH, - CONF_DAY, - CONF_SECOND, - CONF_HOUR, - CONF_MINUTE, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity - CODEOWNERS = ["@rfdarter", "@jesserockz"] DEPENDENCIES = ["time"] diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py index 241e884386..031a4c0de8 100644 --- a/esphome/components/event/__init__.py +++ b/esphome/components/event/__init__.py @@ -1,24 +1,24 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt +import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, + CONF_EVENT_TYPE, CONF_ICON, CONF_ID, + CONF_MQTT_ID, CONF_ON_EVENT, CONF_TRIGGER_ID, - CONF_MQTT_ID, - CONF_EVENT_TYPE, DEVICE_CLASS_BUTTON, DEVICE_CLASS_DOORBELL, DEVICE_CLASS_EMPTY, DEVICE_CLASS_MOTION, ) from esphome.core import CORE, coroutine_with_priority -from esphome.cpp_helpers import setup_entity from esphome.cpp_generator import MockObjClass +from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@nohat"] IS_PLATFORM_COMPONENT = True diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 847a59baa1..62624ec6e3 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -1,31 +1,31 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( + CONF_DIRECTION, CONF_ID, CONF_MQTT_ID, - CONF_WEB_SERVER_ID, - CONF_OSCILLATING, - CONF_OSCILLATION_COMMAND_TOPIC, - CONF_OSCILLATION_STATE_TOPIC, - CONF_SPEED, - CONF_SPEED_LEVEL_COMMAND_TOPIC, - CONF_SPEED_LEVEL_STATE_TOPIC, - CONF_SPEED_COMMAND_TOPIC, - CONF_SPEED_STATE_TOPIC, CONF_OFF_SPEED_CYCLE, CONF_ON_DIRECTION_SET, CONF_ON_OSCILLATING_SET, + CONF_ON_PRESET_SET, CONF_ON_SPEED_SET, CONF_ON_STATE, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, - CONF_ON_PRESET_SET, - CONF_TRIGGER_ID, - CONF_DIRECTION, + CONF_OSCILLATING, + CONF_OSCILLATION_COMMAND_TOPIC, + CONF_OSCILLATION_STATE_TOPIC, CONF_RESTORE_MODE, + CONF_SPEED, + CONF_SPEED_COMMAND_TOPIC, + CONF_SPEED_LEVEL_COMMAND_TOPIC, + CONF_SPEED_LEVEL_STATE_TOPIC, + CONF_SPEED_STATE_TOPIC, + CONF_TRIGGER_ID, + CONF_WEB_SERVER_ID, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 161b4d8cd9..d9f139d2f4 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -1,8 +1,9 @@ -import esphome.codegen as cg -import esphome.config_validation as cv import esphome.automation as auto +import esphome.codegen as cg from esphome.components import mqtt, power_supply, web_server +import esphome.config_validation as cv from esphome.const import ( + CONF_COLD_WHITE_COLOR_TEMPERATURE, CONF_COLOR_CORRECT, CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, @@ -10,36 +11,36 @@ from esphome.const import ( CONF_GAMMA_CORRECT, CONF_ID, CONF_MQTT_ID, - CONF_WEB_SERVER_ID, - CONF_POWER_SUPPLY, - CONF_RESTORE_MODE, + CONF_ON_STATE, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, - CONF_ON_STATE, + CONF_POWER_SUPPLY, + CONF_RESTORE_MODE, CONF_TRIGGER_ID, - CONF_COLD_WHITE_COLOR_TEMPERATURE, CONF_WARM_WHITE_COLOR_TEMPERATURE, + CONF_WEB_SERVER_ID, ) from esphome.core import coroutine_with_priority from esphome.cpp_helpers import setup_entity + from .automation import light_control_to_code # noqa from .effects import ( - validate_effects, + ADDRESSABLE_EFFECTS, BINARY_EFFECTS, + EFFECTS_REGISTRY, MONOCHROMATIC_EFFECTS, RGB_EFFECTS, - ADDRESSABLE_EFFECTS, - EFFECTS_REGISTRY, + validate_effects, ) from .types import ( # noqa - LightState, - AddressableLightState, - light_ns, - LightOutput, AddressableLight, - LightTurnOnTrigger, - LightTurnOffTrigger, + AddressableLightState, + LightOutput, + LightState, LightStateTrigger, + LightTurnOffTrigger, + LightTurnOnTrigger, + light_ns, ) CODEOWNERS = ["@esphome/core"] diff --git a/esphome/components/lock/__init__.py b/esphome/components/lock/__init__.py index c2d6054ed9..6b92bc264b 100644 --- a/esphome/components/lock/__init__.py +++ b/esphome/components/lock/__init__.py @@ -1,14 +1,14 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition, maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_ID, + CONF_MQTT_ID, CONF_ON_LOCK, CONF_ON_UNLOCK, CONF_TRIGGER_ID, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, ) from esphome.core import CORE, coroutine_with_priority diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 320014e355..423cb065dc 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -1,20 +1,18 @@ from esphome import automation -import esphome.config_validation as cv -import esphome.codegen as cg - from esphome.automation import maybe_simple_id +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_ID, + CONF_ON_IDLE, CONF_ON_STATE, CONF_TRIGGER_ID, CONF_VOLUME, - CONF_ON_IDLE, ) from esphome.core import CORE from esphome.coroutine import coroutine_with_priority from esphome.cpp_helpers import setup_entity - CODEOWNERS = ["@jesserockz"] IS_PLATFORM_COMPONENT = True diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index d9c16fd7a9..ece738af49 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -1,24 +1,23 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation -from esphome.components import mqtt -from esphome.components import web_server +import esphome.codegen as cg +from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_ABOVE, CONF_BELOW, + CONF_CYCLE, CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, - CONF_ID, CONF_ICON, + CONF_ID, CONF_MODE, + CONF_MQTT_ID, CONF_ON_VALUE, CONF_ON_VALUE_RANGE, + CONF_OPERATION, CONF_TRIGGER_ID, CONF_UNIT_OF_MEASUREMENT, - CONF_MQTT_ID, CONF_VALUE, - CONF_OPERATION, - CONF_CYCLE, CONF_WEB_SERVER_ID, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, @@ -72,8 +71,8 @@ from esphome.const import ( DEVICE_CLASS_WIND_SPEED, ) from esphome.core import CORE, coroutine_with_priority -from esphome.cpp_helpers import setup_entity from esphome.cpp_generator import MockObjClass +from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@esphome/core"] DEVICE_CLASSES = [ diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index 073fbef1d4..2bc68d43ec 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -1,20 +1,20 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( + CONF_CYCLE, CONF_ENTITY_CATEGORY, CONF_ICON, CONF_ID, + CONF_INDEX, + CONF_MODE, + CONF_MQTT_ID, CONF_ON_VALUE, + CONF_OPERATION, CONF_OPTION, CONF_TRIGGER_ID, - CONF_MQTT_ID, CONF_WEB_SERVER_ID, - CONF_CYCLE, - CONF_MODE, - CONF_OPERATION, - CONF_INDEX, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 3b76466dec..867cdc1f48 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -1,22 +1,27 @@ import math -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( - CONF_DEVICE_CLASS, CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_BELOW, + CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, CONF_EXPIRE_AFTER, CONF_FILTERS, + CONF_FORCE_UPDATE, CONF_FROM, CONF_ICON, CONF_ID, CONF_IGNORE_OUT_OF_RANGE, + CONF_MAX_VALUE, + CONF_METHOD, + CONF_MIN_VALUE, + CONF_MQTT_ID, CONF_MULTIPLE, CONF_ON_RAW_VALUE, CONF_ON_VALUE, @@ -30,14 +35,9 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, - CONF_WINDOW_SIZE, - CONF_MQTT_ID, - CONF_WEB_SERVER_ID, - CONF_FORCE_UPDATE, CONF_VALUE, - CONF_MIN_VALUE, - CONF_MAX_VALUE, - CONF_METHOD, + CONF_WEB_SERVER_ID, + CONF_WINDOW_SIZE, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, DEVICE_CLASS_ATMOSPHERIC_PRESSURE, diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index 3539d0e34e..fef4f7f007 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -1,8 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import Condition, maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, @@ -10,11 +10,11 @@ from esphome.const import ( CONF_ID, CONF_INVERTED, CONF_MQTT_ID, - CONF_WEB_SERVER_ID, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, CONF_RESTORE_MODE, CONF_TRIGGER_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_OUTLET, DEVICE_CLASS_SWITCH, diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index 5a8e763495..386baaf756 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -1,18 +1,18 @@ from typing import Optional -import esphome.codegen as cg -import esphome.config_validation as cv + from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_ID, CONF_MODE, + CONF_MQTT_ID, CONF_ON_VALUE, CONF_TRIGGER_ID, - CONF_MQTT_ID, - CONF_WEB_SERVER_ID, CONF_VALUE, + CONF_WEB_SERVER_ID, ) - from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index f4e795924c..ba8a2def41 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -1,21 +1,21 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, CONF_ENTITY_CATEGORY, CONF_FILTERS, + CONF_FROM, CONF_ICON, CONF_ID, - CONF_ON_VALUE, - CONF_ON_RAW_VALUE, - CONF_TRIGGER_ID, CONF_MQTT_ID, - CONF_WEB_SERVER_ID, + CONF_ON_RAW_VALUE, + CONF_ON_VALUE, CONF_STATE, - CONF_FROM, CONF_TO, + CONF_TRIGGER_ID, + CONF_WEB_SERVER_ID, DEVICE_CLASS_DATE, DEVICE_CLASS_EMPTY, DEVICE_CLASS_TIMESTAMP, diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index c03d13fec8..3c03bab857 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -1,8 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation -from esphome.automation import maybe_simple_id, Condition +from esphome.automation import Condition, maybe_simple_id +import esphome.codegen as cg from esphome.components import mqtt, web_server +import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, CONF_ID, From ddd80272386c923db6043e3659997c1e34398b3f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:33:12 +1200 Subject: [PATCH 2177/2607] [spi] Remove ``SPIDelegateDummy`` (#7215) --- esphome/components/spi/spi.cpp | 6 ------ esphome/components/spi/spi.h | 21 ++------------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index b13826c443..f9435b0424 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -7,10 +7,6 @@ namespace spi { const char *const TAG = "spi"; -SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - new SPIDelegateDummy(); -// https://bugs.llvm.org/show_bug.cgi?id=48040 - bool SPIDelegate::is_ready() { return true; } GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -79,8 +75,6 @@ void SPIComponent::dump_config() { } } -void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); } - uint8_t SPIDelegateBitBash::transfer(uint8_t data) { return this->transfer_(data, 8); } void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_(data, num_bits); } diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index f581dc3f56..4cd8d3383c 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -163,8 +163,6 @@ class Utility { } }; -class SPIDelegateDummy; - // represents a device attached to an SPI bus, with a defined clock rate, mode and bit order. On Arduino this is // a thin wrapper over SPIClass. class SPIDelegate { @@ -250,21 +248,6 @@ class SPIDelegate { uint32_t data_rate_{1000000}; SPIMode mode_{MODE0}; GPIOPin *cs_pin_{NullPin::NULL_PIN}; - static SPIDelegate *const NULL_DELEGATE; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -}; - -/** - * A dummy SPIDelegate that complains if it's used. - */ - -class SPIDelegateDummy : public SPIDelegate { - public: - SPIDelegateDummy() = default; - - uint8_t transfer(uint8_t data) override { return 0; } - void end_transaction() override{}; - - void begin_transaction() override; }; /** @@ -382,7 +365,7 @@ class SPIClient { virtual void spi_teardown() { this->parent_->unregister_device(this); - this->delegate_ = SPIDelegate::NULL_DELEGATE; + this->delegate_ = nullptr; } bool spi_is_ready() { return this->delegate_->is_ready(); } @@ -393,7 +376,7 @@ class SPIClient { uint32_t data_rate_{1000000}; SPIComponent *parent_{nullptr}; GPIOPin *cs_{nullptr}; - SPIDelegate *delegate_{SPIDelegate::NULL_DELEGATE}; + SPIDelegate *delegate_{nullptr}; }; /** From 132269c5b84c6c7502db239094bb14b27615de7e Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 7 Aug 2024 09:31:44 +0200 Subject: [PATCH 2178/2607] [code-quality] Apply ruff linting suggestions (#7206) --- esphome/config_validation.py | 2 +- esphome/mqtt.py | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 6e1d3ba2f9..ef60d6e0d6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -91,7 +91,7 @@ _LOGGER = logging.getLogger(__name__) # pylint: disable=consider-using-f-string VARIABLE_PROG = re.compile( - "\\$([{0}]+|\\{{[{0}]*\\}})".format(VALID_SUBSTITUTIONS_CHARACTERS) + f"\\$([{VALID_SUBSTITUTIONS_CHARACTERS}]+|\\{{[{VALID_SUBSTITUTIONS_CHARACTERS}]*\\}})" ) # pylint: disable=invalid-name diff --git a/esphome/mqtt.py b/esphome/mqtt.py index d7e14a1d08..c1c45799cc 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -3,7 +3,6 @@ import hashlib import json import logging import ssl -import sys import time import paho.mqtt.client as mqtt @@ -103,10 +102,7 @@ def prepare( if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS) or config[CONF_MQTT].get( CONF_CERTIFICATE_AUTHORITY ): - if sys.version_info >= (2, 7, 13): - tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member - else: - tls_version = ssl.PROTOCOL_SSLv23 + tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member client.tls_set( ca_certs=None, certfile=None, From 2a8424a7f2022dced130a80139729015792b7f39 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 7 Aug 2024 09:32:06 +0200 Subject: [PATCH 2179/2607] [code-quality] Organise logger imports (#7205) --- esphome/components/logger/__init__.py | 33 ++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 99aa39c4ba..f30bc23e38 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -1,9 +1,21 @@ import re -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation from esphome.automation import LambdaAction +import esphome.codegen as cg +from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant +from esphome.components.esp32.const import ( + VARIANT_ESP32, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) +from esphome.components.libretiny import get_libretiny_component, get_libretiny_family +from esphome.components.libretiny.const import COMPONENT_BK72XX, COMPONENT_RTL87XX +import esphome.config_validation as cv from esphome.const import ( CONF_ARGS, CONF_BAUD_RATE, @@ -18,27 +30,12 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_TX_BUFFER_SIZE, PLATFORM_BK72XX, - PLATFORM_RTL87XX, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, + PLATFORM_RTL87XX, ) from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority -from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant -from esphome.components.esp32.const import ( - VARIANT_ESP32, - VARIANT_ESP32S2, - VARIANT_ESP32C3, - VARIANT_ESP32S3, - VARIANT_ESP32C2, - VARIANT_ESP32C6, - VARIANT_ESP32H2, -) -from esphome.components.libretiny import get_libretiny_component, get_libretiny_family -from esphome.components.libretiny.const import ( - COMPONENT_BK72XX, - COMPONENT_RTL87XX, -) CODEOWNERS = ["@esphome/core"] logger_ns = cg.esphome_ns.namespace("logger") From 4b91ef5123e064d33975c928fa40e7cffaa5b468 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 7 Aug 2024 09:33:41 +0200 Subject: [PATCH 2180/2607] [code-quality] Apply ruff linting suggestions to core (#7207) --- esphome/core/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 9d3d14492e..a97c3b18c9 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -336,7 +336,7 @@ class ID: else: self.is_manual = is_manual self.is_declaration = is_declaration - self.type: Optional["MockObjClass"] = type + self.type: Optional[MockObjClass] = type def resolve(self, registered_ids): from esphome.config_validation import RESERVED_IDS @@ -500,7 +500,7 @@ class EsphomeCore: # The relative path to where all build files are stored self.build_path: Optional[str] = None # The validated configuration, this is None until the config has been validated - self.config: Optional["ConfigType"] = None + self.config: Optional[ConfigType] = None # The pending tasks in the task queue (mostly for C++ generation) # This is a priority queue (with heapq) # Each item is a tuple of form: (-priority, unique number, task) @@ -508,17 +508,17 @@ class EsphomeCore: # Task counter for pending tasks self.task_counter = 0 # The variable cache, for each ID this holds a MockObj of the variable obj - self.variables: dict[str, "MockObj"] = {} + self.variables: dict[str, MockObj] = {} # A list of statements that go in the main setup() block - self.main_statements: list["Statement"] = [] + self.main_statements: list[Statement] = [] # A list of statements to insert in the global block (includes and global variables) - self.global_statements: list["Statement"] = [] + self.global_statements: list[Statement] = [] # A set of platformio libraries to add to the project self.libraries: list[Library] = [] # A set of build flags to set in the platformio project self.build_flags: set[str] = set() # A set of defines to set for the compile process in esphome/core/defines.h - self.defines: set["Define"] = set() + self.defines: set[Define] = set() # A map of all platformio options to apply self.platformio_options: dict[str, Union[str, list[str]]] = {} # A set of strings of names of loaded integrations, used to find namespace ID conflicts From 9a9757ddebfc025d19c65c6c0c3467eeb887061f Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 8 Aug 2024 02:29:32 +0200 Subject: [PATCH 2181/2607] [code-quality] fix clang-tidy sprinkler (#7222) * fix clang-tidy * fix build error * clang-tidy * clang-tidy --- esphome/components/sprinkler/sprinkler.cpp | 4 ++-- esphome/components/sprinkler/sprinkler.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 982d9add1a..59565251c3 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -647,7 +647,7 @@ void Sprinkler::set_valve_run_duration(const optional valve_number, cons return; } auto call = this->valve_[valve_number.value()].run_duration_number->make_call(); - if (this->valve_[valve_number.value()].run_duration_number->traits.get_unit_of_measurement() == min_str) { + if (this->valve_[valve_number.value()].run_duration_number->traits.get_unit_of_measurement() == MIN_STR) { call.set_value(run_duration.value() / 60.0); } else { call.set_value(run_duration.value()); @@ -729,7 +729,7 @@ uint32_t Sprinkler::valve_run_duration(const size_t valve_number) { return 0; } if (this->valve_[valve_number].run_duration_number != nullptr) { - if (this->valve_[valve_number].run_duration_number->traits.get_unit_of_measurement() == min_str) { + if (this->valve_[valve_number].run_duration_number->traits.get_unit_of_measurement() == MIN_STR) { return static_cast(roundf(this->valve_[valve_number].run_duration_number->state * 60)); } else { return static_cast(roundf(this->valve_[valve_number].run_duration_number->state)); diff --git a/esphome/components/sprinkler/sprinkler.h b/esphome/components/sprinkler/sprinkler.h index 5311ae4c05..c4a8b8aeb8 100644 --- a/esphome/components/sprinkler/sprinkler.h +++ b/esphome/components/sprinkler/sprinkler.h @@ -11,7 +11,7 @@ namespace esphome { namespace sprinkler { -const std::string min_str = "min"; +const std::string MIN_STR = "min"; enum SprinklerState : uint8_t { // NOTE: these states are used by both SprinklerValveOperator and Sprinkler (the controller)! From 24b6c1d3eb85e1c50552a2aff040e0250d749e26 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 8 Aug 2024 02:30:49 +0200 Subject: [PATCH 2182/2607] [code-quality] __attribute__((packed)) (#7221) --- esphome/components/climate/climate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index 7c2a0b1ed3..d81702fb0c 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -141,7 +141,7 @@ struct ClimateDeviceRestoreState { float target_temperature_low; float target_temperature_high; }; - }; + } __attribute__((packed)); float target_humidity; /// Convert this struct to a climate call that can be performed. From 7fd65987d33f21433975ef252c29f20a33ef33a0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 8 Aug 2024 03:29:49 +0100 Subject: [PATCH 2183/2607] hx711: Check for DOUT going high after a reading (#7214) --- esphome/components/hx711/hx711.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp index dbbf4c91f4..1a7169eed7 100644 --- a/esphome/components/hx711/hx711.cpp +++ b/esphome/components/hx711/hx711.cpp @@ -39,8 +39,8 @@ bool HX711Sensor::read_sensor_(uint32_t *result) { return false; } - this->status_clear_warning(); uint32_t data = 0; + bool final_dout; { InterruptLock lock; @@ -59,8 +59,17 @@ bool HX711Sensor::read_sensor_(uint32_t *result) { this->sck_pin_->digital_write(false); delayMicroseconds(1); } + final_dout = this->dout_pin_->digital_read(); } + if (!final_dout) { + ESP_LOGW(TAG, "HX711 DOUT pin not high after reading (data 0x%" PRIx32 ")!", data); + this->status_set_warning(); + return false; + } + + this->status_clear_warning(); + if (data & 0x800000ULL) { data |= 0xFF000000ULL; } From 3f1d2c0cafe246c88e4d257b36e70c5e3be4ec71 Mon Sep 17 00:00:00 2001 From: dentra Date: Thu, 8 Aug 2024 07:49:37 +0300 Subject: [PATCH 2184/2607] [mqtt] Add extended device info (#7194) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mqtt/mqtt_component.cpp | 36 +++++++++++++++++++--- esphome/components/mqtt/mqtt_const.h | 2 ++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index bb46ce732d..295fbba5e5 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -150,12 +150,40 @@ bool MQTTComponent::send_discovery_() { const std::string &node_area = App.get_area(); JsonObject device_info = root.createNestedObject(MQTT_DEVICE); - device_info[MQTT_DEVICE_IDENTIFIERS] = get_mac_address(); + const auto mac = get_mac_address(); + device_info[MQTT_DEVICE_IDENTIFIERS] = mac; device_info[MQTT_DEVICE_NAME] = node_friendly_name; - device_info[MQTT_DEVICE_SW_VERSION] = "esphome v" ESPHOME_VERSION " " + App.get_compilation_time(); +#ifdef ESPHOME_PROJECT_NAME + device_info[MQTT_DEVICE_SW_VERSION] = ESPHOME_PROJECT_VERSION " (ESPHome " ESPHOME_VERSION ")"; + const char *model = std::strchr(ESPHOME_PROJECT_NAME, '.'); + if (model == nullptr) { // must never happen but check anyway + device_info[MQTT_DEVICE_MODEL] = ESPHOME_BOARD; + device_info[MQTT_DEVICE_MANUFACTURER] = ESPHOME_PROJECT_NAME; + } else { + device_info[MQTT_DEVICE_MODEL] = model + 1; + device_info[MQTT_DEVICE_MANUFACTURER] = std::string(ESPHOME_PROJECT_NAME, model - ESPHOME_PROJECT_NAME); + } +#else + device_info[MQTT_DEVICE_SW_VERSION] = ESPHOME_VERSION " (" + App.get_compilation_time() + ")"; device_info[MQTT_DEVICE_MODEL] = ESPHOME_BOARD; - device_info[MQTT_DEVICE_MANUFACTURER] = "espressif"; - device_info[MQTT_DEVICE_SUGGESTED_AREA] = node_area; +#if defined(USE_ESP8266) || defined(USE_ESP32) + device_info[MQTT_DEVICE_MANUFACTURER] = "Espressif"; +#elif defined(USE_RP2040) + device_info[MQTT_DEVICE_MANUFACTURER] = "Raspberry Pi"; +#elif defined(USE_BK72XX) + device_info[MQTT_DEVICE_MANUFACTURER] = "Beken"; +#elif defined(USE_RTL87XX) + device_info[MQTT_DEVICE_MANUFACTURER] = "Realtek"; +#elif defined(USE_HOST) + device_info[MQTT_DEVICE_MANUFACTURER] = "Host"; +#endif +#endif + if (!node_area.empty()) { + device_info[MQTT_DEVICE_SUGGESTED_AREA] = node_area; + } + + device_info[MQTT_DEVICE_CONNECTIONS][0][0] = "mac"; + device_info[MQTT_DEVICE_CONNECTIONS][0][1] = mac; }, this->qos_, discovery_info.retain); } diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index 0e063c66d2..71f169fbe8 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -62,6 +62,7 @@ constexpr const char *const MQTT_DEVICE_MODEL = "mdl"; constexpr const char *const MQTT_DEVICE_NAME = "name"; constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "sa"; constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw"; +constexpr const char *const MQTT_DEVICE_HW_VERSION = "hw"; constexpr const char *const MQTT_DOCKED_TEMPLATE = "dock_tpl"; constexpr const char *const MQTT_DOCKED_TOPIC = "dock_t"; constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "fx_cmd_t"; @@ -322,6 +323,7 @@ constexpr const char *const MQTT_DEVICE_MODEL = "model"; constexpr const char *const MQTT_DEVICE_NAME = "name"; constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "suggested_area"; constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw_version"; +constexpr const char *const MQTT_DEVICE_HW_VERSION = "hw_version"; constexpr const char *const MQTT_DOCKED_TEMPLATE = "docked_template"; constexpr const char *const MQTT_DOCKED_TOPIC = "docked_topic"; constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "effect_command_topic"; From a3d5b69a9c7690efcfb3441e2d69166bb8cc703e Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 8 Aug 2024 07:02:41 +0200 Subject: [PATCH 2185/2607] [code-quality] NOLINT readability-identifier-naming (#7220) --- esphome/core/entity_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 434111de79..4ca21f9ee5 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -63,7 +63,7 @@ class EntityBase { EntityCategory entity_category_{ENTITY_CATEGORY_NONE}; }; -class EntityBase_DeviceClass { +class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming) public: /// Get the device class, using the manual override if set. std::string get_device_class(); @@ -74,7 +74,7 @@ class EntityBase_DeviceClass { const char *device_class_{nullptr}; ///< Device class override }; -class EntityBase_UnitOfMeasurement { +class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming) public: /// Get the unit of measurement, using the manual override if set. std::string get_unit_of_measurement(); From b71c03424ecf1aaa74a12bdc86e28bdbed9488dd Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 8 Aug 2024 07:02:55 +0200 Subject: [PATCH 2186/2607] [code-quality] Organise time imports (#7219) --- esphome/components/time/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index c888705ba2..6a3368ca73 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -1,32 +1,32 @@ -import logging from importlib import resources +import logging from typing import Optional import tzlocal +from esphome import automation +from esphome.automation import Condition import esphome.codegen as cg import esphome.config_validation as cv -from esphome import automation from esphome.const import ( - CONF_ID, + CONF_AT, CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, + CONF_HOUR, CONF_HOURS, + CONF_ID, + CONF_MINUTE, CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_ON_TIME_SYNC, + CONF_SECOND, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID, - CONF_AT, - CONF_SECOND, - CONF_HOUR, - CONF_MINUTE, ) from esphome.core import coroutine_with_priority -from esphome.automation import Condition _LOGGER = logging.getLogger(__name__) From a47a17d7e7d4649d7a92c3fb96c921374b14d2d6 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:24:10 +1000 Subject: [PATCH 2187/2607] [lvgl] Fix set state on updates (#7227) --- esphome/components/lvgl/lvgl_esphome.h | 4 ++-- esphome/components/lvgl/widgets/__init__.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 45841b99d9..1497e1004a 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -1,9 +1,9 @@ #pragma once #include "esphome/core/defines.h" -#ifdef USE_LVGL_BINARY_SENSOR +#ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" -#endif // USE_LVGL_BINARY_SENSOR +#endif // USE_BINARY_SENSOR #ifdef USE_LVGL_ROTARY_ENCODER #include "esphome/components/rotary_encoder/rotary_encoder.h" #endif // USE_LVGL_ROTARY_ENCODER diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index f1946015bc..603de6aa3e 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -271,6 +271,7 @@ async def set_obj_properties(w: Widget, config): """Generate a list of C++ statements to apply properties to an lv_obj_t""" if layout := config.get(CONF_LAYOUT): layout_type: str = layout[CONF_TYPE] + add_lv_use(layout_type) lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}")) if layout_type == TYPE_GRID: wid = config[CONF_ID] @@ -334,7 +335,7 @@ async def set_obj_properties(w: Widget, config): for key, value in states.items(): if isinstance(value, cv.Lambda): lambs[key] = value - elif value == "true": + elif value: adds.add(key) else: clears.add(key) From b43c5b851aaaf15f170dbaf23a6ec5feaf4ee664 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Fri, 9 Aug 2024 13:15:25 +0200 Subject: [PATCH 2188/2607] add missing overrides (#7231) --- esphome/components/lvgl/number/lvgl_number.h | 2 +- esphome/components/lvgl/switch/lvgl_switch.h | 2 +- esphome/components/lvgl/text/lvgl_text.h | 2 +- esphome/components/spi_led_strip/spi_led_strip.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/lvgl/number/lvgl_number.h b/esphome/components/lvgl/number/lvgl_number.h index 461ea51be4..659fc615c9 100644 --- a/esphome/components/lvgl/number/lvgl_number.h +++ b/esphome/components/lvgl/number/lvgl_number.h @@ -19,7 +19,7 @@ class LVGLNumber : public number::Number { } protected: - void control(float value) { + void control(float value) override { if (this->control_lambda_ != nullptr) this->control_lambda_(value); else diff --git a/esphome/components/lvgl/switch/lvgl_switch.h b/esphome/components/lvgl/switch/lvgl_switch.h index f20f4ed960..67be11faba 100644 --- a/esphome/components/lvgl/switch/lvgl_switch.h +++ b/esphome/components/lvgl/switch/lvgl_switch.h @@ -19,7 +19,7 @@ class LVGLSwitch : public switch_::Switch { } protected: - void write_state(bool value) { + void write_state(bool value) override { if (this->state_lambda_ != nullptr) this->state_lambda_(value); else diff --git a/esphome/components/lvgl/text/lvgl_text.h b/esphome/components/lvgl/text/lvgl_text.h index 8dc0281364..4bd5b76744 100644 --- a/esphome/components/lvgl/text/lvgl_text.h +++ b/esphome/components/lvgl/text/lvgl_text.h @@ -19,7 +19,7 @@ class LVGLText : public text::Text { } protected: - void control(const std::string &value) { + void control(const std::string &value) override { if (this->control_lambda_ != nullptr) this->control_lambda_(value); else diff --git a/esphome/components/spi_led_strip/spi_led_strip.h b/esphome/components/spi_led_strip/spi_led_strip.h index 0d8c1c1e1c..8b713378ec 100644 --- a/esphome/components/spi_led_strip/spi_led_strip.h +++ b/esphome/components/spi_led_strip/spi_led_strip.h @@ -13,7 +13,7 @@ class SpiLedStrip : public light::AddressableLight, public spi::SPIDevice { public: - void setup() { this->spi_setup(); } + void setup() override { this->spi_setup(); } int32_t size() const override { return this->num_leds_; } @@ -43,7 +43,7 @@ class SpiLedStrip : public light::AddressableLight, memset(this->buf_, 0, 4); } - void dump_config() { + void dump_config() override { esph_log_config(TAG, "SPI LED Strip:"); esph_log_config(TAG, " LEDs: %d", this->num_leds_); if (this->data_rate_ >= spi::DATA_RATE_1MHZ) From 15602b0664b71ac6362e5cf4ff3c0e94cf066c38 Mon Sep 17 00:00:00 2001 From: Michael Davidson Date: Mon, 12 Aug 2024 06:06:29 +1000 Subject: [PATCH 2189/2607] Add text_align_to_string (#7243) --- esphome/components/display/display.cpp | 31 ++++++++++++++++++++++++++ esphome/components/display/display.h | 3 +++ 2 files changed, 34 insertions(+) diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 75205292f7..63c74e09ca 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -675,5 +675,36 @@ void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; } void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; } const display_writer_t &DisplayPage::get_writer() const { return this->writer_; } +const LogString *text_align_to_string(TextAlign textalign) { + switch (textalign) { + case TextAlign::TOP_LEFT: + return LOG_STR("TOP_LEFT"); + case TextAlign::TOP_CENTER: + return LOG_STR("TOP_CENTER"); + case TextAlign::TOP_RIGHT: + return LOG_STR("TOP_RIGHT"); + case TextAlign::CENTER_LEFT: + return LOG_STR("CENTER_LEFT"); + case TextAlign::CENTER: + return LOG_STR("CENTER"); + case TextAlign::CENTER_RIGHT: + return LOG_STR("CENTER_RIGHT"); + case TextAlign::BASELINE_LEFT: + return LOG_STR("BASELINE_LEFT"); + case TextAlign::BASELINE_CENTER: + return LOG_STR("BASELINE_CENTER"); + case TextAlign::BASELINE_RIGHT: + return LOG_STR("BASELINE_RIGHT"); + case TextAlign::BOTTOM_LEFT: + return LOG_STR("BOTTOM_LEFT"); + case TextAlign::BOTTOM_CENTER: + return LOG_STR("BOTTOM_CENTER"); + case TextAlign::BOTTOM_RIGHT: + return LOG_STR("BOTTOM_RIGHT"); + default: + return LOG_STR("UNKNOWN"); + } +} + } // namespace display } // namespace esphome diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 4ee7ef93cb..34feafea6e 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -8,6 +8,7 @@ #include "esphome/core/color.h" #include "esphome/core/automation.h" #include "esphome/core/time.h" +#include "esphome/core/log.h" #include "display_color_utils.h" #ifdef USE_GRAPH @@ -737,5 +738,7 @@ class DisplayOnPageChangeTrigger : public Trigger DisplayPage *to_{nullptr}; }; +const LogString *text_align_to_string(TextAlign textalign); + } // namespace display } // namespace esphome From 442e765187e73aeff3e24f727de5662359943493 Mon Sep 17 00:00:00 2001 From: Nis Wechselberg Date: Mon, 12 Aug 2024 04:18:11 +0200 Subject: [PATCH 2190/2607] [sml] Fixed crashing sml parser (#7235) --- esphome/components/sml/sml_parser.cpp | 72 ++++++++++++++++++--------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/esphome/components/sml/sml_parser.cpp b/esphome/components/sml/sml_parser.cpp index c782c0fc5e..2cc71e87fa 100644 --- a/esphome/components/sml/sml_parser.cpp +++ b/esphome/components/sml/sml_parser.cpp @@ -10,7 +10,7 @@ SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) { this->pos_ = 0; while (this->pos_ < this->buffer_.size()) { if (this->buffer_[this->pos_] == 0x00) - break; // fill byte detected -> no more messages + break; // EndOfSmlMsg SmlNode message = SmlNode(); if (!this->setup_node(&message)) @@ -20,40 +20,66 @@ SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) { } bool SmlFile::setup_node(SmlNode *node) { - uint8_t type = this->buffer_[this->pos_] >> 4; // type including overlength info - uint8_t length = this->buffer_[this->pos_] & 0x0f; // length including TL bytes - bool is_list = (type & 0x07) == SML_LIST; - bool has_extended_length = type & 0x08; // we have a long list/value (>15 entries) - uint8_t parse_length = length; - if (has_extended_length) { - length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f); - parse_length = length; + // If the TL field is 0x00, this is the end of the message + // (see 6.3.1 of SML protocol definition) + if (this->buffer_[this->pos_] == 0x00) { + // Increment past this byte and signal that the message is done this->pos_ += 1; + return true; } - if (this->pos_ + parse_length >= this->buffer_.size()) + // Extract data from initial TL field + uint8_t type = (this->buffer_[this->pos_] >> 4) & 0x07; // type without overlength info + bool overlength = (this->buffer_[this->pos_] >> 4) & 0x08; // overlength information + uint8_t length = this->buffer_[this->pos_] & 0x0f; // length (including TL bytes) + + // Check if we need additional length bytes + if (overlength) { + // Shift the current length to the higher nibble + // and add the lower nibble of the next byte to the length + length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f); + // We are basically done with the first TL field now, + // so increment past that, we now point to the second TL field + this->pos_ += 1; + // Decrement the length for value fields (not lists), + // since the byte we just handled is counted as part of the field + // in case of values but not for lists + if (type != SML_LIST) + length -= 1; + + // Technically, this is not enough, the standard allows for more than two length fields. + // However I don't think it is very common to have more than 255 entries in a list + } + + // We are done with the last TL field(s), so advance the position + this->pos_ += 1; + // and decrement the length for non-list fields + if (type != SML_LIST) + length -= 1; + + // Check if the buffer length is long enough + if (this->pos_ + length > this->buffer_.size()) return false; - node->type = type & 0x07; + node->type = type; node->nodes.clear(); node->value_bytes.clear(); - // if the list is a has_extended_length list with e.g. 16 elements this is a 0x00 byte but not the end of message - if (!has_extended_length && this->buffer_[this->pos_] == 0x00) { // end of message - this->pos_ += 1; - } else if (is_list) { // list - this->pos_ += 1; - node->nodes.reserve(parse_length); - for (size_t i = 0; i != parse_length; i++) { + if (type == SML_LIST) { + node->nodes.reserve(length); + for (size_t i = 0; i != length; i++) { SmlNode child_node = SmlNode(); if (!this->setup_node(&child_node)) return false; node->nodes.emplace_back(child_node); } - } else { // value - node->value_bytes = - bytes(this->buffer_.begin() + this->pos_ + 1, this->buffer_.begin() + this->pos_ + parse_length); - this->pos_ += parse_length; + } else { + // Value starts at the current position + // Value ends "length" bytes later, + // (since the TL field is counted but already subtracted from length) + node->value_bytes = bytes(this->buffer_.begin() + this->pos_, this->buffer_.begin() + this->pos_ + length); + // Increment the pointer past all consumed bytes + this->pos_ += length; } return true; } @@ -101,7 +127,7 @@ int64_t bytes_to_int(const bytes &buffer) { // see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c if (buffer.size() < 8) { const int bits = buffer.size() * 8; - const uint64_t m = 1u << (bits - 1); + const uint64_t m = 1ull << (bits - 1); tmp = (tmp ^ m) - m; } From d04e706295a495c0b8dbbf08c6ad95bbfa623712 Mon Sep 17 00:00:00 2001 From: Flo Date: Mon, 12 Aug 2024 04:20:51 +0200 Subject: [PATCH 2191/2607] Allow project name and version as improv_serial identity (#7248) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/improv_serial/__init__.py | 14 ++++---------- .../improv_serial/improv_serial_component.cpp | 4 ++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/esphome/components/improv_serial/__init__.py b/esphome/components/improv_serial/__init__.py index 2b377d77b8..544af212e0 100644 --- a/esphome/components/improv_serial/__init__.py +++ b/esphome/components/improv_serial/__init__.py @@ -1,12 +1,10 @@ +import esphome.codegen as cg from esphome.components import improv_base from esphome.components.esp32 import get_esp32_variant -from esphome.components.esp32.const import ( - VARIANT_ESP32S3, -) +from esphome.components.esp32.const import VARIANT_ESP32S3 from esphome.components.logger import USB_CDC -from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER -import esphome.codegen as cg import esphome.config_validation as cv +from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER from esphome.core import CORE import esphome.final_validate as fv @@ -19,11 +17,7 @@ improv_serial_ns = cg.esphome_ns.namespace("improv_serial") ImprovSerialComponent = improv_serial_ns.class_("ImprovSerialComponent", cg.Component) CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(ImprovSerialComponent), - } - ) + cv.Schema({cv.GenerateID(): cv.declare_id(ImprovSerialComponent)}) .extend(improv_base.IMPROV_SCHEMA) .extend(cv.COMPONENT_SCHEMA) ) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 12809e38cb..425a5c8576 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -170,7 +170,11 @@ std::vector ImprovSerialComponent::build_rpc_settings_response_(improv: } std::vector ImprovSerialComponent::build_version_info_() { +#ifdef ESPHOME_PROJECT_NAME + std::vector infos = {ESPHOME_PROJECT_NAME, ESPHOME_PROJECT_VERSION, ESPHOME_VARIANT, App.get_name()}; +#else std::vector infos = {"ESPHome", ESPHOME_VERSION, ESPHOME_VARIANT, App.get_name()}; +#endif std::vector data = improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false); return data; }; From 34d435c99643280c297e0741a14a58574e7c879e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:56:54 +1000 Subject: [PATCH 2192/2607] [lvgl] Implement default group for encoders (#7242) Co-authored-by: clydeps --- esphome/components/lvgl/__init__.py | 6 ++++-- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/encoders.py | 10 +++++++--- esphome/components/lvgl/touchscreens.py | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 87fbcab4dc..6bf6e287f8 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -47,6 +47,7 @@ from .types import ( IdleTrigger, ObjUpdateAction, lv_font_t, + lv_group_t, lv_style_t, lvgl_ns, ) @@ -335,8 +336,9 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_THEME): cv.Schema( {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} ), - cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, - cv.GenerateID(df.CONF_ENCODERS): ENCODERS_CONFIG, + cv.Optional(df.CONF_TOUCHSCREENS, default=None): touchscreen_schema, + cv.Optional(df.CONF_ENCODERS, default=None): ENCODERS_CONFIG, + cv.GenerateID(df.CONF_DEFAULT_GROUP): cv.declare_id(lv_group_t), } ) .extend(DISP_BG_SCHEMA) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index d0047b59f7..1c6fd2678c 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -386,6 +386,7 @@ CONF_COLOR_DEPTH = "color_depth" CONF_CONTROL = "control" CONF_DEFAULT = "default" CONF_DEFAULT_FONT = "default_font" +CONF_DEFAULT_GROUP = "default_group" CONF_DIR = "dir" CONF_DISPLAYS = "displays" CONF_ENCODERS = "encoders" diff --git a/esphome/components/lvgl/encoders.py b/esphome/components/lvgl/encoders.py index caddc2e47f..cfd0e42996 100644 --- a/esphome/components/lvgl/encoders.py +++ b/esphome/components/lvgl/encoders.py @@ -5,6 +5,7 @@ import esphome.config_validation as cv from esphome.const import CONF_GROUP, CONF_ID, CONF_SENSOR from .defines import ( + CONF_DEFAULT_GROUP, CONF_ENCODERS, CONF_ENTER_BUTTON, CONF_LEFT_BUTTON, @@ -38,7 +39,10 @@ ENCODERS_CONFIG = cv.ensure_list( async def encoders_to_code(var, config): - for enc_conf in config.get(CONF_ENCODERS, ()): + default_group = lv_Pvariable(lv_group_t, config[CONF_DEFAULT_GROUP]) + lv_assign(default_group, lv_expr.group_create()) + lv.group_set_default(default_group) + for enc_conf in config[CONF_ENCODERS]: lvgl_components_required.add("KEY_LISTENER") lpt = enc_conf[CONF_LONG_PRESS_TIME].total_milliseconds lprt = enc_conf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds @@ -60,6 +64,6 @@ async def encoders_to_code(var, config): if group := enc_conf.get(CONF_GROUP): group = lv_Pvariable(lv_group_t, group) lv_assign(group, lv_expr.group_create()) - lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) else: - lv.indev_drv_register(listener.get_drv()) + group = default_group + lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) diff --git a/esphome/components/lvgl/touchscreens.py b/esphome/components/lvgl/touchscreens.py index 292b0873f3..4d430a428e 100644 --- a/esphome/components/lvgl/touchscreens.py +++ b/esphome/components/lvgl/touchscreens.py @@ -34,7 +34,7 @@ def touchscreen_schema(config): async def touchscreens_to_code(var, config): - for tconf in config.get(CONF_TOUCHSCREENS, ()): + for tconf in config[CONF_TOUCHSCREENS]: lvgl_components_required.add(CONF_TOUCHSCREEN) touchscreen = await cg.get_variable(tconf[CONF_TOUCHSCREEN_ID]) lpt = tconf[CONF_LONG_PRESS_TIME].total_milliseconds From f2e99fa3192f3792189c73326be5fa6563cdf032 Mon Sep 17 00:00:00 2001 From: "David K." <142583+neffs@users.noreply.github.com> Date: Mon, 12 Aug 2024 06:14:58 +0200 Subject: [PATCH 2193/2607] [bme68x_bsec2_i2c] BME68X Temperature+Pressure+Humidity+Gas Sensor via BSEC2 (#4585) * Added initial bme68x component * Initialize all child sensors to nullptr This was added to all other sensors in #3808 * Update BSEC2 and BME68x Libraries Current versions from Bosch Sensortec * Add myself to codeowners for bme68x_bsec * Move constants to const.py, according to ci-custom checks Move constants to const.py, according to ci-custom checks * Update library dependencies We'll stick with 1.4.2200 for now. 1.4.2200 is not on platform.io registry, use tag instead. Update to 1.5.2400 needs some work due to multi instance support. * Update BSEC2 to 1.6.2400 * Add consts to bme680x_bsec Enable inclusion with external_components * Update device class for pressure * Update to use multisensor API * Tidy up some constants * Add tests * Remove scd30 changes * Import CONF_SAMPLE_RATE * Pull BSEC config blob from repo based on config * Rename component to `bme68x_bsec_i2c` * Fix tests + codeowners * Cleanup for review * Rename using `bsec2` * Apply suggestions from code review Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Download file during validation stage, instead * Make `dump_config()` only dump stuff * Compile safely without sensor and text sensor headers * Use `intf_ptr` * Save state if measuring static IAQ, too * Update CODEOWNERS * Simplify esphome/components/bme68x_bsec2_i2c/__init__.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Remove extraneous colon & imports * Track & save the maximum accuracy value * Polish up accuracy sensor handling * Log static sensor, update `defines.h` * Walruses make it better * Add some logging of setup failures * Update esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp Co-authored-by: Trevor North * Break out some things * Update CODEOWNERS * Update CODEOWNERS take 2 * Use `add_extra` in base schema * Another walrus in the sensor Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Keith Burzinski Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Trevor North --- CODEOWNERS | 2 + esphome/components/bme68x_bsec2/__init__.py | 196 +++++++ .../components/bme68x_bsec2/bme68x_bsec2.cpp | 523 ++++++++++++++++++ .../components/bme68x_bsec2/bme68x_bsec2.h | 163 ++++++ esphome/components/bme68x_bsec2/sensor.py | 130 +++++ .../components/bme68x_bsec2/text_sensor.py | 33 ++ .../components/bme68x_bsec2_i2c/__init__.py | 28 + .../bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp | 53 ++ .../bme68x_bsec2_i2c/bme68x_bsec2_i2c.h | 28 + esphome/core/defines.h | 3 +- tests/components/bme68x_bsec2_i2c/common.yaml | 34 ++ .../bme68x_bsec2_i2c/test.esp32-ard.yaml | 5 + .../bme68x_bsec2_i2c/test.esp32-c3-ard.yaml | 5 + .../bme68x_bsec2_i2c/test.esp32-s2-ard.yaml | 5 + .../bme68x_bsec2_i2c/test.esp32-s3-ard.yaml | 5 + .../bme68x_bsec2_i2c/test.esp8266-ard.yaml | 5 + 16 files changed, 1217 insertions(+), 1 deletion(-) create mode 100644 esphome/components/bme68x_bsec2/__init__.py create mode 100644 esphome/components/bme68x_bsec2/bme68x_bsec2.cpp create mode 100644 esphome/components/bme68x_bsec2/bme68x_bsec2.h create mode 100644 esphome/components/bme68x_bsec2/sensor.py create mode 100644 esphome/components/bme68x_bsec2/text_sensor.py create mode 100644 esphome/components/bme68x_bsec2_i2c/__init__.py create mode 100644 esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp create mode 100644 esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h create mode 100644 tests/components/bme68x_bsec2_i2c/common.yaml create mode 100644 tests/components/bme68x_bsec2_i2c/test.esp32-ard.yaml create mode 100644 tests/components/bme68x_bsec2_i2c/test.esp32-c3-ard.yaml create mode 100644 tests/components/bme68x_bsec2_i2c/test.esp32-s2-ard.yaml create mode 100644 tests/components/bme68x_bsec2_i2c/test.esp32-s3-ard.yaml create mode 100644 tests/components/bme68x_bsec2_i2c/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 82e6e0ea4b..999449a3df 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -65,6 +65,8 @@ esphome/components/bluetooth_proxy/* @jesserockz esphome/components/bme280_base/* @esphome/core esphome/components/bme280_spi/* @apbodrov esphome/components/bme680_bsec/* @trvrnrth +esphome/components/bme68x_bsec2/* @kbx81 @neffs +esphome/components/bme68x_bsec2_i2c/* @kbx81 @neffs esphome/components/bmi160/* @flaviut esphome/components/bmp3xx/* @latonita esphome/components/bmp3xx_base/* @latonita @martgras diff --git a/esphome/components/bme68x_bsec2/__init__.py b/esphome/components/bme68x_bsec2/__init__.py new file mode 100644 index 0000000000..1930c7c9e3 --- /dev/null +++ b/esphome/components/bme68x_bsec2/__init__.py @@ -0,0 +1,196 @@ +import hashlib +from pathlib import Path + +from esphome import core, external_files +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_MODEL, + CONF_RAW_DATA_ID, + CONF_SAMPLE_RATE, + CONF_TEMPERATURE_OFFSET, +) + +CODEOWNERS = ["@neffs", "@kbx81"] + +DOMAIN = "bme68x_bsec2" + +BSEC2_LIBRARY_VERSION = "v1.7.2502" + +CONF_ALGORITHM_OUTPUT = "algorithm_output" +CONF_BME68X_BSEC2_ID = "bme68x_bsec2_id" +CONF_IAQ_MODE = "iaq_mode" +CONF_OPERATING_AGE = "operating_age" +CONF_STATE_SAVE_INTERVAL = "state_save_interval" +CONF_SUPPLY_VOLTAGE = "supply_voltage" + +bme68x_bsec2_ns = cg.esphome_ns.namespace("bme68x_bsec2") +BME68xBSEC2Component = bme68x_bsec2_ns.class_("BME68xBSEC2Component", cg.Component) + + +MODEL_OPTIONS = ["bme680", "bme688"] + +AlgorithmOutput = bme68x_bsec2_ns.enum("AlgorithmOutput") +ALGORITHM_OUTPUT_OPTIONS = { + "classification": AlgorithmOutput.ALGORITHM_OUTPUT_CLASSIFICATION, + "regression": AlgorithmOutput.ALGORITHM_OUTPUT_REGRESSION, +} + +OperatingAge = bme68x_bsec2_ns.enum("OperatingAge") +OPERATING_AGE_OPTIONS = { + "4d": OperatingAge.OPERATING_AGE_4D, + "28d": OperatingAge.OPERATING_AGE_28D, +} + +SampleRate = bme68x_bsec2_ns.enum("SampleRate") +SAMPLE_RATE_OPTIONS = { + "LP": SampleRate.SAMPLE_RATE_LP, + "ULP": SampleRate.SAMPLE_RATE_ULP, +} + +Voltage = bme68x_bsec2_ns.enum("Voltage") +VOLTAGE_OPTIONS = { + "1.8V": Voltage.VOLTAGE_1_8V, + "3.3V": Voltage.VOLTAGE_3_3V, +} + +ALGORITHM_OUTPUT_FILE_NAME = { + "classification": "sel", + "regression": "reg", +} + +SAMPLE_RATE_FILE_NAME = { + "LP": "3s", + "ULP": "300s", +} + +VOLTAGE_FILE_NAME = { + "1.8V": "18v", + "3.3V": "33v", +} + + +def _compute_local_file_path(url: str) -> Path: + h = hashlib.new("sha256") + h.update(url.encode()) + key = h.hexdigest()[:8] + base_dir = external_files.compute_local_file_dir(DOMAIN) + return base_dir / key + + +def _compute_url(config: dict) -> str: + model = config.get(CONF_MODEL) + operating_age = config.get(CONF_OPERATING_AGE) + sample_rate = SAMPLE_RATE_FILE_NAME[config.get(CONF_SAMPLE_RATE)] + volts = VOLTAGE_FILE_NAME[config.get(CONF_SUPPLY_VOLTAGE)] + if model == "bme688": + algo = ALGORITHM_OUTPUT_FILE_NAME[ + config.get(CONF_ALGORITHM_OUTPUT, "classification") + ] + filename = "bsec_selectivity" + else: + algo = "iaq" + filename = "bsec_iaq" + return f"https://raw.githubusercontent.com/boschsensortec/Bosch-BSEC2-Library/{BSEC2_LIBRARY_VERSION}/src/config/{model}/{model}_{algo}_{volts}_{sample_rate}_{operating_age}/{filename}.txt" + + +def download_bme68x_blob(config): + url = _compute_url(config) + path = _compute_local_file_path(url) + external_files.download_content(url, path) + + return config + + +def validate_bme68x(config): + if CONF_ALGORITHM_OUTPUT not in config: + return config + + if config[CONF_MODEL] != "bme688": + raise cv.Invalid(f"{CONF_ALGORITHM_OUTPUT} is only valid for BME688") + + if config[CONF_ALGORITHM_OUTPUT] == "regression" and ( + config[CONF_OPERATING_AGE] != "4d" + or config[CONF_SAMPLE_RATE] != "ULP" + or config[CONF_SUPPLY_VOLTAGE] != "1.8V" + ): + raise cv.Invalid( + f" To use '{CONF_ALGORITHM_OUTPUT}: regression', {CONF_OPERATING_AGE} must be '4d', {CONF_SAMPLE_RATE} must be 'ULP' and {CONF_SUPPLY_VOLTAGE} must be '1.8V'" + ) + return config + + +CONFIG_SCHEMA_BASE = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(BME68xBSEC2Component), + cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), + cv.Required(CONF_MODEL): cv.one_of(*MODEL_OPTIONS, lower=True), + cv.Optional(CONF_ALGORITHM_OUTPUT): cv.enum( + ALGORITHM_OUTPUT_OPTIONS, lower=True + ), + cv.Optional(CONF_OPERATING_AGE, default="28d"): cv.enum( + OPERATING_AGE_OPTIONS, lower=True + ), + cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum( + SAMPLE_RATE_OPTIONS, upper=True + ), + cv.Optional(CONF_SUPPLY_VOLTAGE, default="3.3V"): cv.enum( + VOLTAGE_OPTIONS, upper=True + ), + cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature, + cv.Optional( + CONF_STATE_SAVE_INTERVAL, default="6hours" + ): cv.positive_time_period_minutes, + }, + ) + .add_extra(cv.only_with_arduino) + .add_extra(validate_bme68x) + .add_extra(download_bme68x_blob) +) + + +async def to_code_base(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + if algo_output := config.get(CONF_ALGORITHM_OUTPUT): + cg.add(var.set_algorithm_output(algo_output)) + cg.add(var.set_operating_age(config[CONF_OPERATING_AGE])) + cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) + cg.add(var.set_voltage(config[CONF_SUPPLY_VOLTAGE])) + cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET])) + cg.add( + var.set_state_save_interval(config[CONF_STATE_SAVE_INTERVAL].total_milliseconds) + ) + + path = _compute_local_file_path(_compute_url(config)) + + try: + with open(path, encoding="utf-8") as f: + bsec2_iaq_config = f.read() + except Exception as e: + raise core.EsphomeError(f"Could not open binary configuration file {path}: {e}") + + # Convert retrieved BSEC2 config to an array of ints + rhs = [int(x) for x in bsec2_iaq_config.split(",")] + # Create an array which will reside in program memory and configure the sensor instance to use it + bsec2_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) + cg.add(var.set_bsec2_configuration(bsec2_arr, len(rhs))) + + # Although this component does not use SPI, the BSEC2 library requires the SPI library + cg.add_library("SPI", None) + cg.add_library( + "BME68x Sensor library", + "1.1.40407", + ) + cg.add_library( + "BSEC2 Software Library", + None, + f"https://github.com/boschsensortec/Bosch-BSEC2-Library.git#{BSEC2_LIBRARY_VERSION}", + ) + + cg.add_define("USE_BSEC2") + + return var diff --git a/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp new file mode 100644 index 0000000000..5425bbd5b7 --- /dev/null +++ b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp @@ -0,0 +1,523 @@ +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#ifdef USE_BSEC2 +#include "bme68x_bsec2.h" + +#include + +namespace esphome { +namespace bme68x_bsec2 { + +#define BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(a) (a == ALGORITHM_OUTPUT_CLASSIFICATION ? "Classification" : "Regression") +#define BME68X_BSEC2_OPERATING_AGE_LOG(o) (o == OPERATING_AGE_4D ? "4 days" : "28 days") +#define BME68X_BSEC2_SAMPLE_RATE_LOG(r) (r == SAMPLE_RATE_DEFAULT ? "Default" : (r == SAMPLE_RATE_ULP ? "ULP" : "LP")) +#define BME68X_BSEC2_VOLTAGE_LOG(v) (v == VOLTAGE_3_3V ? "3.3V" : "1.8V") + +static const char *const TAG = "bme68x_bsec2.sensor"; + +static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"}; + +void BME68xBSEC2Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up BME68X via BSEC2..."); + + this->bsec_status_ = bsec_init_m(&this->bsec_instance_); + if (this->bsec_status_ != BSEC_OK) { + this->mark_failed(); + ESP_LOGE(TAG, "bsec_init_m failed: status %d", this->bsec_status_); + return; + } + + bsec_get_version_m(&this->bsec_instance_, &this->version_); + + this->bme68x_status_ = bme68x_init(&this->bme68x_); + if (this->bme68x_status_ != BME68X_OK) { + this->mark_failed(); + ESP_LOGE(TAG, "bme68x_init failed: status %d", this->bme68x_status_); + return; + } + if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) { + this->set_config_(this->bsec2_configuration_, this->bsec2_configuration_length_); + if (this->bsec_status_ != BSEC_OK) { + this->mark_failed(); + ESP_LOGE(TAG, "bsec_set_configuration_m failed: status %d", this->bsec_status_); + return; + } + } + + this->update_subscription_(); + if (this->bsec_status_ != BSEC_OK) { + this->mark_failed(); + ESP_LOGE(TAG, "bsec_update_subscription_m failed: status %d", this->bsec_status_); + return; + } + + this->load_state_(); +} + +void BME68xBSEC2Component::dump_config() { + ESP_LOGCONFIG(TAG, "BME68X via BSEC2:"); + + ESP_LOGCONFIG(TAG, " BSEC2 version: %d.%d.%d.%d", this->version_.major, this->version_.minor, + this->version_.major_bugfix, this->version_.minor_bugfix); + + ESP_LOGCONFIG(TAG, " BSEC2 configuration blob:"); + ESP_LOGCONFIG(TAG, " Configured: %s", YESNO(this->bsec2_blob_configured_)); + if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) { + ESP_LOGCONFIG(TAG, " Size: %" PRIu32, this->bsec2_configuration_length_); + } + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication failed (BSEC2 status: %d, BME68X status: %d)", this->bsec_status_, + this->bme68x_status_); + } + + if (this->algorithm_output_ != ALGORITHM_OUTPUT_IAQ) { + ESP_LOGCONFIG(TAG, " Algorithm output: %s", BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(this->algorithm_output_)); + } + ESP_LOGCONFIG(TAG, " Operating age: %s", BME68X_BSEC2_OPERATING_AGE_LOG(this->operating_age_)); + ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->sample_rate_)); + ESP_LOGCONFIG(TAG, " Voltage: %s", BME68X_BSEC2_VOLTAGE_LOG(this->voltage_)); + ESP_LOGCONFIG(TAG, " State save interval: %ims", this->state_save_interval_ms_); + ESP_LOGCONFIG(TAG, " Temperature offset: %.2f", this->temperature_offset_); + +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->temperature_sample_rate_)); + LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); + ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->pressure_sample_rate_)); + LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); + ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->humidity_sample_rate_)); + LOG_SENSOR(" ", "Gas resistance", this->gas_resistance_sensor_); + LOG_SENSOR(" ", "CO2 equivalent", this->co2_equivalent_sensor_); + LOG_SENSOR(" ", "Breath VOC equivalent", this->breath_voc_equivalent_sensor_); + LOG_SENSOR(" ", "IAQ", this->iaq_sensor_); + LOG_SENSOR(" ", "IAQ static", this->iaq_static_sensor_); + LOG_SENSOR(" ", "Numeric IAQ accuracy", this->iaq_accuracy_sensor_); +#endif +#ifdef USE_TEXT_SENSOR + LOG_TEXT_SENSOR(" ", "IAQ accuracy", this->iaq_accuracy_text_sensor_); +#endif +} + +float BME68xBSEC2Component::get_setup_priority() const { return setup_priority::DATA; } + +void BME68xBSEC2Component::loop() { + this->run_(); + + if (this->bsec_status_ < BSEC_OK || this->bme68x_status_ < BME68X_OK) { + this->status_set_error(); + } else { + this->status_clear_error(); + } + if (this->bsec_status_ > BSEC_OK || this->bme68x_status_ > BME68X_OK) { + this->status_set_warning(); + } else { + this->status_clear_warning(); + } + // Process a single action from the queue. These are primarily sensor state publishes + // that in totality take too long to send in a single call. + if (this->queue_.size()) { + auto action = std::move(this->queue_.front()); + this->queue_.pop(); + action(); + } +} + +void BME68xBSEC2Component::set_config_(const uint8_t *config, uint32_t len) { + if (len > BSEC_MAX_PROPERTY_BLOB_SIZE) { + ESP_LOGE(TAG, "Configuration is larger than BSEC_MAX_PROPERTY_BLOB_SIZE"); + this->mark_failed(); + return; + } + uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; + this->bsec_status_ = bsec_set_configuration_m(&this->bsec_instance_, config, len, work_buffer, sizeof(work_buffer)); + if (this->bsec_status_ == BSEC_OK) { + this->bsec2_blob_configured_ = true; + } +} + +float BME68xBSEC2Component::calc_sensor_sample_rate_(SampleRate sample_rate) { + if (sample_rate == SAMPLE_RATE_DEFAULT) { + sample_rate = this->sample_rate_; + } + return sample_rate == SAMPLE_RATE_ULP ? BSEC_SAMPLE_RATE_ULP : BSEC_SAMPLE_RATE_LP; +} + +void BME68xBSEC2Component::update_subscription_() { + bsec_sensor_configuration_t virtual_sensors[BSEC_NUMBER_OUTPUTS]; + uint8_t num_virtual_sensors = 0; +#ifdef USE_SENSOR + if (this->iaq_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_IAQ; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); + num_virtual_sensors++; + } + + if (this->iaq_static_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_STATIC_IAQ; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); + num_virtual_sensors++; + } + + if (this->co2_equivalent_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); + num_virtual_sensors++; + } + + if (this->breath_voc_equivalent_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); + num_virtual_sensors++; + } + + if (this->pressure_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_PRESSURE; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->pressure_sample_rate_); + num_virtual_sensors++; + } + + if (this->gas_resistance_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_GAS; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); + num_virtual_sensors++; + } + + if (this->temperature_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->temperature_sample_rate_); + num_virtual_sensors++; + } + + if (this->humidity_sensor_) { + virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->humidity_sample_rate_); + num_virtual_sensors++; + } +#endif + bsec_sensor_configuration_t sensor_settings[BSEC_MAX_PHYSICAL_SENSOR]; + uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR; + this->bsec_status_ = bsec_update_subscription_m(&this->bsec_instance_, virtual_sensors, num_virtual_sensors, + sensor_settings, &num_sensor_settings); +} + +void BME68xBSEC2Component::run_() { + int64_t curr_time_ns = this->get_time_ns_(); + if (curr_time_ns < this->next_call_ns_) { + return; + } + this->op_mode_ = this->bsec_settings_.op_mode; + uint8_t status; + + ESP_LOGV(TAG, "Performing sensor run"); + + struct bme68x_conf bme68x_conf; + this->bsec_status_ = bsec_sensor_control_m(&this->bsec_instance_, curr_time_ns, &this->bsec_settings_); + if (this->bsec_status_ < BSEC_OK) { + ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC2 error code %d)", this->bsec_status_); + return; + } + this->next_call_ns_ = this->bsec_settings_.next_call; + + if (this->bsec_settings_.trigger_measurement) { + bme68x_get_conf(&bme68x_conf, &this->bme68x_); + + bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling; + bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling; + bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling; + bme68x_set_conf(&bme68x_conf, &this->bme68x_); + + switch (this->bsec_settings_.op_mode) { + case BME68X_FORCED_MODE: + this->bme68x_heatr_conf_.enable = BME68X_ENABLE; + this->bme68x_heatr_conf_.heatr_temp = this->bsec_settings_.heater_temperature; + this->bme68x_heatr_conf_.heatr_dur = this->bsec_settings_.heater_duration; + + status = bme68x_set_op_mode(this->bsec_settings_.op_mode, &this->bme68x_); + status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); + status = bme68x_set_op_mode(BME68X_FORCED_MODE, &this->bme68x_); + this->op_mode_ = BME68X_FORCED_MODE; + this->sleep_mode_ = false; + ESP_LOGV(TAG, "Using forced mode"); + + break; + case BME68X_PARALLEL_MODE: + if (this->op_mode_ != this->bsec_settings_.op_mode) { + this->bme68x_heatr_conf_.enable = BME68X_ENABLE; + this->bme68x_heatr_conf_.heatr_temp_prof = this->bsec_settings_.heater_temperature_profile; + this->bme68x_heatr_conf_.heatr_dur_prof = this->bsec_settings_.heater_duration_profile; + this->bme68x_heatr_conf_.profile_len = this->bsec_settings_.heater_profile_len; + this->bme68x_heatr_conf_.shared_heatr_dur = + BSEC_TOTAL_HEAT_DUR - + (bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &bme68x_conf, &this->bme68x_) / INT64_C(1000)); + + status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); + + status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &this->bme68x_); + this->op_mode_ = BME68X_PARALLEL_MODE; + this->sleep_mode_ = false; + ESP_LOGV(TAG, "Using parallel mode"); + } + break; + case BME68X_SLEEP_MODE: + if (!this->sleep_mode_) { + bme68x_set_op_mode(BME68X_SLEEP_MODE, &this->bme68x_); + this->sleep_mode_ = true; + ESP_LOGV(TAG, "Using sleep mode"); + } + break; + } + + uint32_t meas_dur = 0; + meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_); + ESP_LOGV(TAG, "Queueing read in %uus", meas_dur); + this->set_timeout("read", meas_dur / 1000, [this, curr_time_ns]() { this->read_(curr_time_ns); }); + } else { + ESP_LOGV(TAG, "Measurement not required"); + this->read_(curr_time_ns); + } +} + +void BME68xBSEC2Component::read_(int64_t trigger_time_ns) { + ESP_LOGV(TAG, "Reading data"); + + if (this->bsec_settings_.trigger_measurement) { + uint8_t current_op_mode; + this->bme68x_status_ = bme68x_get_op_mode(¤t_op_mode, &this->bme68x_); + + if (current_op_mode == BME68X_SLEEP_MODE) { + ESP_LOGV(TAG, "Still in sleep mode, doing nothing"); + return; + } + } + + if (!this->bsec_settings_.process_data) { + ESP_LOGV(TAG, "Data processing not required"); + return; + } + + struct bme68x_data data[3]; + uint8_t nFields = 0; + this->bme68x_status_ = bme68x_get_data(this->op_mode_, &data[0], &nFields, &this->bme68x_); + + if (this->bme68x_status_ != BME68X_OK) { + ESP_LOGW(TAG, "Failed to get sensor data (BME68X error code %d)", this->bme68x_status_); + return; + } + if (nFields < 1) { + ESP_LOGD(TAG, "BME68X did not provide new data"); + return; + } + + for (uint8_t i = 0; i < nFields; i++) { + bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance + uint8_t num_inputs = 0; + + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_TEMPERATURE)) { + inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE; + inputs[num_inputs].signal = data[i].temperature; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HEATSOURCE)) { + inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE; + inputs[num_inputs].signal = this->temperature_offset_; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HUMIDITY)) { + inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY; + inputs[num_inputs].signal = data[i].humidity; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PRESSURE)) { + inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE; + inputs[num_inputs].signal = data[i].pressure; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_GASRESISTOR)) { + if (data[i].status & BME68X_GASM_VALID_MSK) { + inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR; + inputs[num_inputs].signal = data[i].gas_resistance; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } else { + ESP_LOGD(TAG, "BME68X did not report gas data"); + } + } + if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PROFILE_PART) && + (data[i].status & BME68X_GASM_VALID_MSK)) { + inputs[num_inputs].sensor_id = BSEC_INPUT_PROFILE_PART; + inputs[num_inputs].signal = (this->op_mode_ == BME68X_FORCED_MODE) ? 0 : data[i].gas_index; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } + + if (num_inputs < 1) { + ESP_LOGD(TAG, "No signal inputs available for BSEC2"); + return; + } + + bsec_output_t outputs[BSEC_NUMBER_OUTPUTS]; + uint8_t num_outputs = BSEC_NUMBER_OUTPUTS; + this->bsec_status_ = bsec_do_steps_m(&this->bsec_instance_, inputs, num_inputs, outputs, &num_outputs); + if (this->bsec_status_ != BSEC_OK) { + ESP_LOGW(TAG, "BSEC2 failed to process signals (BSEC2 error code %d)", this->bsec_status_); + return; + } + if (num_outputs < 1) { + ESP_LOGD(TAG, "No signal outputs provided by BSEC2"); + return; + } + + this->publish_(outputs, num_outputs); + } +} + +void BME68xBSEC2Component::publish_(const bsec_output_t *outputs, uint8_t num_outputs) { + ESP_LOGV(TAG, "Publishing sensor states"); + bool update_accuracy = false; + uint8_t max_accuracy = 0; + for (uint8_t i = 0; i < num_outputs; i++) { + float signal = outputs[i].signal; + switch (outputs[i].sensor_id) { + case BSEC_OUTPUT_IAQ: + max_accuracy = std::max(outputs[i].accuracy, max_accuracy); + update_accuracy = true; +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_STATIC_IAQ: + max_accuracy = std::max(outputs[i].accuracy, max_accuracy); + update_accuracy = true; +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_static_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_CO2_EQUIVALENT: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->co2_equivalent_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->breath_voc_equivalent_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_RAW_PRESSURE: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->pressure_sensor_, signal / 100.0f); }); +#endif + break; + case BSEC_OUTPUT_RAW_GAS: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->gas_resistance_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->temperature_sensor_, signal); }); +#endif + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: +#ifdef USE_SENSOR + this->queue_push_([this, signal]() { this->publish_sensor_(this->humidity_sensor_, signal); }); +#endif + break; + } + } + if (update_accuracy) { +#ifdef USE_SENSOR + this->queue_push_( + [this, max_accuracy]() { this->publish_sensor_(this->iaq_accuracy_sensor_, max_accuracy, true); }); +#endif +#ifdef USE_TEXT_SENSOR + this->queue_push_([this, max_accuracy]() { + this->publish_sensor_(this->iaq_accuracy_text_sensor_, IAQ_ACCURACY_STATES[max_accuracy]); + }); +#endif + // Queue up an opportunity to save state + this->queue_push_([this, max_accuracy]() { this->save_state_(max_accuracy); }); + } +} + +int64_t BME68xBSEC2Component::get_time_ns_() { + int64_t time_ms = millis(); + if (this->last_time_ms_ > time_ms) { + this->millis_overflow_counter_++; + } + this->last_time_ms_ = time_ms; + + return (time_ms + ((int64_t) this->millis_overflow_counter_ << 32)) * INT64_C(1000000); +} + +#ifdef USE_SENSOR +void BME68xBSEC2Component::publish_sensor_(sensor::Sensor *sensor, float value, bool change_only) { + if (!sensor || (change_only && sensor->has_state() && sensor->state == value)) { + return; + } + sensor->publish_state(value); +} +#endif + +#ifdef USE_TEXT_SENSOR +void BME68xBSEC2Component::publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value) { + if (!sensor || (sensor->has_state() && sensor->state == value)) { + return; + } + sensor->publish_state(value); +} +#endif + +void BME68xBSEC2Component::load_state_() { + uint32_t hash = this->get_hash(); + this->bsec_state_ = global_preferences->make_preference(hash, true); + + uint8_t state[BSEC_MAX_STATE_BLOB_SIZE]; + if (this->bsec_state_.load(&state)) { + ESP_LOGV(TAG, "Loading state"); + uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE]; + this->bsec_status_ = + bsec_set_state_m(&this->bsec_instance_, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, sizeof(work_buffer)); + if (this->bsec_status_ != BSEC_OK) { + ESP_LOGW(TAG, "Failed to load state (BSEC2 error code %d)", this->bsec_status_); + } + ESP_LOGI(TAG, "Loaded state"); + } +} + +void BME68xBSEC2Component::save_state_(uint8_t accuracy) { + if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) { + return; + } + + ESP_LOGV(TAG, "Saving state"); + + uint8_t state[BSEC_MAX_STATE_BLOB_SIZE]; + uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE]; + uint32_t num_serialized_state = BSEC_MAX_STATE_BLOB_SIZE; + + this->bsec_status_ = bsec_get_state_m(&this->bsec_instance_, 0, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, + BSEC_MAX_STATE_BLOB_SIZE, &num_serialized_state); + if (this->bsec_status_ != BSEC_OK) { + ESP_LOGW(TAG, "Failed fetch state for save (BSEC2 error code %d)", this->bsec_status_); + return; + } + + if (!this->bsec_state_.save(&state)) { + ESP_LOGW(TAG, "Failed to save state"); + return; + } + this->last_state_save_ms_ = millis(); + + ESP_LOGI(TAG, "Saved state"); +} + +} // namespace bme68x_bsec2 +} // namespace esphome +#endif diff --git a/esphome/components/bme68x_bsec2/bme68x_bsec2.h b/esphome/components/bme68x_bsec2/bme68x_bsec2.h new file mode 100644 index 0000000000..7b9db2b7bf --- /dev/null +++ b/esphome/components/bme68x_bsec2/bme68x_bsec2.h @@ -0,0 +1,163 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/preferences.h" + +#ifdef USE_BSEC2 + +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif + +#include +#include + +#include + +namespace esphome { +namespace bme68x_bsec2 { + +enum AlgorithmOutput { + ALGORITHM_OUTPUT_IAQ, + ALGORITHM_OUTPUT_CLASSIFICATION, + ALGORITHM_OUTPUT_REGRESSION, +}; + +enum OperatingAge { + OPERATING_AGE_4D, + OPERATING_AGE_28D, +}; + +enum SampleRate { + SAMPLE_RATE_LP = 0, + SAMPLE_RATE_ULP = 1, + SAMPLE_RATE_DEFAULT = 2, +}; + +enum Voltage { + VOLTAGE_1_8V, + VOLTAGE_3_3V, +}; + +class BME68xBSEC2Component : public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void loop() override; + + void set_algorithm_output(AlgorithmOutput algorithm_output) { this->algorithm_output_ = algorithm_output; } + void set_operating_age(OperatingAge operating_age) { this->operating_age_ = operating_age; } + void set_temperature_offset(float offset) { this->temperature_offset_ = offset; } + void set_voltage(Voltage voltage) { this->voltage_ = voltage; } + + void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; } + void set_temperature_sample_rate(SampleRate sample_rate) { this->temperature_sample_rate_ = sample_rate; } + void set_pressure_sample_rate(SampleRate sample_rate) { this->pressure_sample_rate_ = sample_rate; } + void set_humidity_sample_rate(SampleRate sample_rate) { this->humidity_sample_rate_ = sample_rate; } + + void set_bsec2_configuration(const uint8_t *data, const uint32_t len) { + this->bsec2_configuration_ = data; + this->bsec2_configuration_length_ = len; + } + + void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; } + +#ifdef USE_SENSOR + void set_temperature_sensor(sensor::Sensor *sensor) { this->temperature_sensor_ = sensor; } + void set_pressure_sensor(sensor::Sensor *sensor) { this->pressure_sensor_ = sensor; } + void set_humidity_sensor(sensor::Sensor *sensor) { this->humidity_sensor_ = sensor; } + void set_gas_resistance_sensor(sensor::Sensor *sensor) { this->gas_resistance_sensor_ = sensor; } + void set_iaq_sensor(sensor::Sensor *sensor) { this->iaq_sensor_ = sensor; } + void set_iaq_static_sensor(sensor::Sensor *sensor) { this->iaq_static_sensor_ = sensor; } + void set_iaq_accuracy_sensor(sensor::Sensor *sensor) { this->iaq_accuracy_sensor_ = sensor; } + void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; } + void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; } +#endif +#ifdef USE_TEXT_SENSOR + void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *sensor) { this->iaq_accuracy_text_sensor_ = sensor; } +#endif + virtual uint32_t get_hash() = 0; + + protected: + void set_config_(const uint8_t *config, u_int32_t len); + float calc_sensor_sample_rate_(SampleRate sample_rate); + void update_subscription_(); + + void run_(); + void read_(int64_t trigger_time_ns); + void publish_(const bsec_output_t *outputs, uint8_t num_outputs); + int64_t get_time_ns_(); + +#ifdef USE_SENSOR + void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false); +#endif +#ifdef USE_TEXT_SENSOR + void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value); +#endif + + void load_state_(); + void save_state_(uint8_t accuracy); + + void queue_push_(std::function &&f) { this->queue_.push(std::move(f)); } + + struct bme68x_dev bme68x_; + bsec_bme_settings_t bsec_settings_; + bsec_version_t version_; + uint8_t bsec_instance_[BSEC_INSTANCE_SIZE]; + + struct bme68x_heatr_conf bme68x_heatr_conf_; + uint8_t op_mode_; // operating mode of sensor + bool sleep_mode_; + bsec_library_return_t bsec_status_{BSEC_OK}; + int8_t bme68x_status_{BME68X_OK}; + + int64_t last_time_ms_{0}; + uint32_t millis_overflow_counter_{0}; + int64_t next_call_ns_{0}; + + std::queue> queue_; + + uint8_t const *bsec2_configuration_{nullptr}; + uint32_t bsec2_configuration_length_{0}; + bool bsec2_blob_configured_{false}; + + ESPPreferenceObject bsec_state_; + uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day + uint32_t last_state_save_ms_ = 0; + + float temperature_offset_{0}; + + AlgorithmOutput algorithm_output_{ALGORITHM_OUTPUT_IAQ}; + OperatingAge operating_age_{OPERATING_AGE_28D}; + Voltage voltage_{VOLTAGE_3_3V}; + + SampleRate sample_rate_{SAMPLE_RATE_LP}; // Core/gas sample rate + SampleRate temperature_sample_rate_{SAMPLE_RATE_DEFAULT}; + SampleRate pressure_sample_rate_{SAMPLE_RATE_DEFAULT}; + SampleRate humidity_sample_rate_{SAMPLE_RATE_DEFAULT}; + +#ifdef USE_SENSOR + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *pressure_sensor_{nullptr}; + sensor::Sensor *humidity_sensor_{nullptr}; + sensor::Sensor *gas_resistance_sensor_{nullptr}; + sensor::Sensor *iaq_sensor_{nullptr}; + sensor::Sensor *iaq_static_sensor_{nullptr}; + sensor::Sensor *iaq_accuracy_sensor_{nullptr}; + sensor::Sensor *co2_equivalent_sensor_{nullptr}; + sensor::Sensor *breath_voc_equivalent_sensor_{nullptr}; +#endif +#ifdef USE_TEXT_SENSOR + text_sensor::TextSensor *iaq_accuracy_text_sensor_{nullptr}; +#endif +}; + +} // namespace bme68x_bsec2 +} // namespace esphome +#endif diff --git a/esphome/components/bme68x_bsec2/sensor.py b/esphome/components/bme68x_bsec2/sensor.py new file mode 100644 index 0000000000..419f47b248 --- /dev/null +++ b/esphome/components/bme68x_bsec2/sensor.py @@ -0,0 +1,130 @@ +import esphome.codegen as cg +from esphome.components import sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_GAS_RESISTANCE, + CONF_HUMIDITY, + CONF_IAQ_ACCURACY, + CONF_PRESSURE, + CONF_SAMPLE_RATE, + CONF_TEMPERATURE, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + ICON_GAS_CYLINDER, + ICON_GAUGE, + ICON_THERMOMETER, + ICON_WATER_PERCENT, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, + UNIT_OHM, + UNIT_PARTS_PER_MILLION, + UNIT_PERCENT, +) + +from . import CONF_BME68X_BSEC2_ID, SAMPLE_RATE_OPTIONS, BME68xBSEC2Component + +DEPENDENCIES = ["bme68x_bsec2"] + +CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" +CONF_CO2_EQUIVALENT = "co2_equivalent" +CONF_IAQ = "iaq" +CONF_IAQ_STATIC = "iaq_static" +ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" +ICON_TEST_TUBE = "mdi:test-tube" +UNIT_IAQ = "IAQ" + +TYPES = [ + CONF_TEMPERATURE, + CONF_PRESSURE, + CONF_HUMIDITY, + CONF_GAS_RESISTANCE, + CONF_IAQ, + CONF_IAQ_STATIC, + CONF_IAQ_ACCURACY, + CONF_CO2_EQUIVALENT, + CONF_BREATH_VOC_EQUIVALENT, +] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_BME68X_BSEC2_ID): cv.use_id(BME68xBSEC2Component), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + icon=ICON_GAUGE, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon=ICON_WATER_PERCENT, + accuracy_decimals=1, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} + ), + cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( + unit_of_measurement=UNIT_OHM, + icon=ICON_GAS_CYLINDER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IAQ): sensor.sensor_schema( + unit_of_measurement=UNIT_IAQ, + icon=ICON_GAUGE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IAQ_STATIC): sensor.sensor_schema( + unit_of_measurement=UNIT_IAQ, + icon=ICON_GAUGE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IAQ_ACCURACY): sensor.sensor_schema( + icon=ICON_ACCURACY, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + icon=ICON_TEST_TUBE, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + icon=ICON_TEST_TUBE, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, + ), + } +) + + +async def setup_conf(config, key, hub): + if conf := config.get(key): + sens = await sensor.new_sensor(conf) + cg.add(getattr(hub, f"set_{key}_sensor")(sens)) + if sample_rate := conf.get(CONF_SAMPLE_RATE): + cg.add(getattr(hub, f"set_{key}_sample_rate")(sample_rate)) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_BME68X_BSEC2_ID]) + for key in TYPES: + await setup_conf(config, key, hub) diff --git a/esphome/components/bme68x_bsec2/text_sensor.py b/esphome/components/bme68x_bsec2/text_sensor.py new file mode 100644 index 0000000000..fce00afe34 --- /dev/null +++ b/esphome/components/bme68x_bsec2/text_sensor.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.const import CONF_IAQ_ACCURACY + +from . import CONF_BME68X_BSEC2_ID, BME68xBSEC2Component + +DEPENDENCIES = ["bme68x_bsec2"] + +ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" + +TYPES = [CONF_IAQ_ACCURACY] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_BME68X_BSEC2_ID): cv.use_id(BME68xBSEC2Component), + cv.Optional(CONF_IAQ_ACCURACY): text_sensor.text_sensor_schema( + icon=ICON_ACCURACY + ), + } +) + + +async def setup_conf(config, key, hub): + if conf := config.get(key): + sens = await text_sensor.new_text_sensor(conf) + cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_BME68X_BSEC2_ID]) + for key in TYPES: + await setup_conf(config, key, hub) diff --git a/esphome/components/bme68x_bsec2_i2c/__init__.py b/esphome/components/bme68x_bsec2_i2c/__init__.py new file mode 100644 index 0000000000..d6fb7fa9be --- /dev/null +++ b/esphome/components/bme68x_bsec2_i2c/__init__.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +from esphome.components import i2c +from esphome.components.bme68x_bsec2 import ( + CONFIG_SCHEMA_BASE, + BME68xBSEC2Component, + to_code_base, +) +import esphome.config_validation as cv + +CODEOWNERS = ["@neffs", "@kbx81"] + +AUTO_LOAD = ["bme68x_bsec2"] +DEPENDENCIES = ["i2c"] + +bme68x_bsec2_i2c_ns = cg.esphome_ns.namespace("bme68x_bsec2_i2c") +BME68xBSEC2I2CComponent = bme68x_bsec2_i2c_ns.class_( + "BME68xBSEC2I2CComponent", BME68xBSEC2Component, i2c.I2CDevice +) + + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( + cv.Schema({cv.GenerateID(): cv.declare_id(BME68xBSEC2I2CComponent)}) +).extend(i2c.i2c_device_schema(0x76)) + + +async def to_code(config): + var = await to_code_base(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp b/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp new file mode 100644 index 0000000000..874c8bf388 --- /dev/null +++ b/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp @@ -0,0 +1,53 @@ +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#ifdef USE_BSEC2 +#include "bme68x_bsec2_i2c.h" +#include "esphome/components/i2c/i2c.h" + +#include + +namespace esphome { +namespace bme68x_bsec2_i2c { + +static const char *const TAG = "bme68x_bsec2_i2c.sensor"; + +void BME68xBSEC2I2CComponent::setup() { + // must set up our bme68x_dev instance before calling setup() + this->bme68x_.intf_ptr = (void *) this; + this->bme68x_.intf = BME68X_I2C_INTF; + this->bme68x_.read = BME68xBSEC2I2CComponent::read_bytes_wrapper; + this->bme68x_.write = BME68xBSEC2I2CComponent::write_bytes_wrapper; + this->bme68x_.delay_us = BME68xBSEC2I2CComponent::delay_us; + this->bme68x_.amb_temp = 25; + + BME68xBSEC2Component::setup(); +} + +void BME68xBSEC2I2CComponent::dump_config() { + LOG_I2C_DEVICE(this); + BME68xBSEC2Component::dump_config(); +} + +uint32_t BME68xBSEC2I2CComponent::get_hash() { return fnv1_hash("bme68x_bsec_state_" + to_string(this->address_)); } + +int8_t BME68xBSEC2I2CComponent::read_bytes_wrapper(uint8_t a_register, uint8_t *data, uint32_t len, void *intfPtr) { + ESP_LOGVV(TAG, "read_bytes_wrapper: reg = %u", a_register); + return static_cast(intfPtr)->read_bytes(a_register, data, len) ? 0 : -1; +} + +int8_t BME68xBSEC2I2CComponent::write_bytes_wrapper(uint8_t a_register, const uint8_t *data, uint32_t len, + void *intfPtr) { + ESP_LOGVV(TAG, "write_bytes_wrapper: reg = %u", a_register); + return static_cast(intfPtr)->write_bytes(a_register, data, len) ? 0 : -1; +} + +void BME68xBSEC2I2CComponent::delay_us(uint32_t period, void *intfPtr) { + ESP_LOGVV(TAG, "Delaying for %" PRIu32 "us", period); + delayMicroseconds(period); +} + +} // namespace bme68x_bsec2_i2c +} // namespace esphome +#endif diff --git a/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h b/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h new file mode 100644 index 0000000000..a21a123f7b --- /dev/null +++ b/esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/preferences.h" + +#ifdef USE_BSEC2 + +#include "esphome/components/bme68x_bsec2/bme68x_bsec2.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace bme68x_bsec2_i2c { + +class BME68xBSEC2I2CComponent : public bme68x_bsec2::BME68xBSEC2Component, public i2c::I2CDevice { + void setup() override; + void dump_config() override; + + uint32_t get_hash() override; + + static int8_t read_bytes_wrapper(uint8_t a_register, uint8_t *data, uint32_t len, void *intfPtr); + static int8_t write_bytes_wrapper(uint8_t a_register, const uint8_t *data, uint32_t len, void *intfPtr); + static void delay_us(uint32_t period, void *intfPtr); +}; + +} // namespace bme68x_bsec2_i2c +} // namespace esphome +#endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 61a4940d01..a711148ec8 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -158,6 +158,7 @@ #endif // Disabled feature flags -// #define USE_BSEC // Requires a library with proprietary license. +// #define USE_BSEC // Requires a library with proprietary license +// #define USE_BSEC2 // Requires a library with proprietary license #define USE_DASHBOARD_IMPORT diff --git a/tests/components/bme68x_bsec2_i2c/common.yaml b/tests/components/bme68x_bsec2_i2c/common.yaml new file mode 100644 index 0000000000..b8a16ee7bb --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/common.yaml @@ -0,0 +1,34 @@ +i2c: + - id: i2c_bme68x + scl: ${scl_pin} + sda: ${sda_pin} + +bme68x_bsec2_i2c: + address: 0x76 + model: bme688 + algorithm_output: classification + operating_age: 28d + sample_rate: LP + supply_voltage: 3.3V + +sensor: + - platform: bme68x_bsec2 + temperature: + name: BME68X Temperature + pressure: + name: BME68X Pressure + humidity: + name: BME68X Humidity + gas_resistance: + name: BME68X Gas Sensor + iaq: + name: BME68X IAQ + co2_equivalent: + name: BME68X eCO2 + breath_voc_equivalent: + name: BME68X Breath eVOC + +text_sensor: + - platform: bme68x_bsec2 + iaq_accuracy: + name: BME68X Accuracy diff --git a/tests/components/bme68x_bsec2_i2c/test.esp32-ard.yaml b/tests/components/bme68x_bsec2_i2c/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bme68x_bsec2_i2c/test.esp32-c3-ard.yaml b/tests/components/bme68x_bsec2_i2c/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..84a9dd4bb4 --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO6 + sda_pin: GPIO7 + +<<: !include common.yaml diff --git a/tests/components/bme68x_bsec2_i2c/test.esp32-s2-ard.yaml b/tests/components/bme68x_bsec2_i2c/test.esp32-s2-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/test.esp32-s2-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bme68x_bsec2_i2c/test.esp32-s3-ard.yaml b/tests/components/bme68x_bsec2_i2c/test.esp32-s3-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/test.esp32-s3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bme68x_bsec2_i2c/test.esp8266-ard.yaml b/tests/components/bme68x_bsec2_i2c/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bme68x_bsec2_i2c/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml From e769804fe6f2502e98ddd8ced9db78898ac8ff1e Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 12 Aug 2024 06:27:22 +0200 Subject: [PATCH 2194/2607] [code-quality] clang-tidy media_player (#7238) --- esphome/components/media_player/automation.h | 58 +++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/esphome/components/media_player/automation.h b/esphome/components/media_player/automation.h index fc3ce7a764..f0e0a5dd31 100644 --- a/esphome/components/media_player/automation.h +++ b/esphome/components/media_player/automation.h @@ -7,30 +7,24 @@ namespace esphome { namespace media_player { -#define MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(ACTION_CLASS, ACTION_COMMAND) \ - template class ACTION_CLASS : public Action, public Parented { \ - void play(Ts... x) override { \ - this->parent_->make_call().set_command(MediaPlayerCommand::MEDIA_PLAYER_COMMAND_##ACTION_COMMAND).perform(); \ - } \ - }; +template +class MediaPlayerCommandAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->make_call().set_command(Command).perform(); } +}; -#define MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(TRIGGER_CLASS, TRIGGER_STATE) \ - class TRIGGER_CLASS : public Trigger<> { \ - public: \ - explicit TRIGGER_CLASS(MediaPlayer *player) { \ - player->add_on_state_callback([this, player]() { \ - if (player->state == MediaPlayerState::MEDIA_PLAYER_STATE_##TRIGGER_STATE) \ - this->trigger(); \ - }); \ - } \ - }; - -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(PlayAction, PLAY) -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(PauseAction, PAUSE) -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(StopAction, STOP) -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(ToggleAction, TOGGLE) -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(VolumeUpAction, VOLUME_UP) -MEDIA_PLAYER_SIMPLE_COMMAND_ACTION(VolumeDownAction, VOLUME_DOWN) +template +using PlayAction = MediaPlayerCommandAction; +template +using PauseAction = MediaPlayerCommandAction; +template +using StopAction = MediaPlayerCommandAction; +template +using ToggleAction = MediaPlayerCommandAction; +template +using VolumeUpAction = MediaPlayerCommandAction; +template +using VolumeDownAction = MediaPlayerCommandAction; template class PlayMediaAction : public Action, public Parented { TEMPLATABLE_VALUE(std::string, media_url) @@ -49,10 +43,20 @@ class StateTrigger : public Trigger<> { } }; -MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(IdleTrigger, IDLE) -MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PlayTrigger, PLAYING) -MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(PauseTrigger, PAUSED) -MEDIA_PLAYER_SIMPLE_STATE_TRIGGER(AnnouncementTrigger, ANNOUNCING) +template class MediaPlayerStateTrigger : public Trigger<> { + public: + explicit MediaPlayerStateTrigger(MediaPlayer *player) { + player->add_on_state_callback([this, player]() { + if (player->state == State) + this->trigger(); + }); + } +}; + +using IdleTrigger = MediaPlayerStateTrigger; +using PlayTrigger = MediaPlayerStateTrigger; +using PauseTrigger = MediaPlayerStateTrigger; +using AnnouncementTrigger = MediaPlayerStateTrigger; template class IsIdleCondition : public Condition, public Parented { public: From 82c5cd18de86307cd6a047abc0f5489caf1af137 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:30:27 +1200 Subject: [PATCH 2195/2607] Bump docker/build-push-action from 6.5.0 to 6.6.1 in /.github/actions/build-image (#7232) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index bd9ceb8072..f9c44cfb63 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.5.0 + uses: docker/build-push-action@v6.6.1 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.5.0 + uses: docker/build-push-action@v6.6.1 with: context: . file: ./docker/Dockerfile From 8a076cc9064612f51e2a356259544890c66d82a5 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 12 Aug 2024 06:49:35 +0200 Subject: [PATCH 2196/2607] fix build error (#7229) --- esphome/components/api/api_connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 81fa4cb339..8e4c6faaee 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1336,7 +1336,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { update->check(); break; default: - ESP_LOGW(TAG, "Unknown update command: %d", msg.command); + ESP_LOGW(TAG, "Unknown update command: %" PRIu32, msg.command); break; } } From f13cf1f7a02c6fbe3d867151aac276b306e0820a Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 12 Aug 2024 06:52:09 +0200 Subject: [PATCH 2197/2607] adjust to new python pre-commit hooks (#7178) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- script/clang-tidy | 35 +++++++++++++++++++++++++---------- script/helpers.py | 9 ++++----- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/script/clang-tidy b/script/clang-tidy index ea522157c5..5bb93846b2 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -115,9 +115,10 @@ def clang_options(idedata): pids = set() -def run_tidy(executable, args, options, tmpdir, queue, lock, failed_files): + +def run_tidy(executable, args, options, tmpdir, path_queue, lock, failed_files): while True: - path = queue.get() + path = path_queue.get() invocation = [executable] if tmpdir is not None: @@ -139,17 +140,20 @@ def run_tidy(executable, args, options, tmpdir, queue, lock, failed_files): invocation.append("--") invocation.extend(options) - proc = subprocess.run(invocation, capture_output=True, encoding="utf-8") + proc = subprocess.run( + invocation, capture_output=True, encoding="utf-8", check=False + ) if proc.returncode != 0: with lock: print_error_for_file(path, proc.stdout) failed_files.append(path) - queue.task_done() + path_queue.task_done() def progress_bar_show(value): if value is None: return "" + return None def split_list(a, n): @@ -237,7 +241,15 @@ def main(): for _ in range(args.jobs): t = threading.Thread( target=run_tidy, - args=(executable, args, options, tmpdir, task_queue, lock, failed_files), + args=( + executable, + args, + options, + tmpdir, + task_queue, + lock, + failed_files, + ), ) t.daemon = True t.start() @@ -245,14 +257,14 @@ def main(): # Fill the queue with files. with click.progressbar( files, width=30, file=sys.stderr, item_show_func=progress_bar_show - ) as bar: - for name in bar: + ) as progress_bar: + for name in progress_bar: task_queue.put(name) # Wait for all threads to be done. task_queue.join() - except FileNotFoundError as ex: + except FileNotFoundError: return 1 except KeyboardInterrupt: print() @@ -262,7 +274,7 @@ def main(): # Kill subprocesses (and ourselves!) # No simple, clean alternative appears to be available. os.kill(0, 9) - return 2 # Will not execute. + return 2 # Will not execute. if args.fix and failed_files: print("Applying fixes ...") @@ -272,7 +284,10 @@ def main(): except FileNotFoundError: subprocess.call(["clang-apply-replacements", tmpdir]) except FileNotFoundError: - print("Error please install clang-apply-replacements-14 or clang-apply-replacements.\n", file=sys.stderr) + print( + "Error please install clang-apply-replacements-14 or clang-apply-replacements.\n", + file=sys.stderr, + ) except: print("Error applying fixes.\n", file=sys.stderr) raise diff --git a/script/helpers.py b/script/helpers.py index 56349b6052..6f36faaeb1 100644 --- a/script/helpers.py +++ b/script/helpers.py @@ -159,20 +159,19 @@ def get_binary(name: str, version: str) -> str: binary_file = f"{name}-{version}" try: result = subprocess.check_output([binary_file, "-version"]) - if result.returncode == 0: - return binary_file - except Exception: + return binary_file + except FileNotFoundError: pass binary_file = name try: result = subprocess.run( - [binary_file, "-version"], text=True, capture_output=True + [binary_file, "-version"], text=True, capture_output=True, check=False ) if result.returncode == 0 and (f"version {version}") in result.stdout: return binary_file raise FileNotFoundError(f"{name} not found") - except FileNotFoundError as ex: + except FileNotFoundError: print( f""" Oops. It looks like {name} is not installed. It should be available under venv/bin From 8148eae1340c5de43c1333761b27d01f8e9d9ba9 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Tue, 13 Aug 2024 01:16:42 +0200 Subject: [PATCH 2198/2607] add windows script/setup.bat (#7140) Co-authored-by: Keith Burzinski --- script/setup.bat | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 script/setup.bat diff --git a/script/setup.bat b/script/setup.bat new file mode 100644 index 0000000000..0b49768139 --- /dev/null +++ b/script/setup.bat @@ -0,0 +1,28 @@ +@echo off + +if defined DEVCONTAINER goto :install +if defined VIRTUAL_ENV goto :install +if defined ESPHOME_NO_VENV goto :install + +echo Starting the Virtual Environment +python -m venv venv +call venv/Scripts/activate +echo Running the Virtual Environment + +:install + +echo Installing required packages... + +python.exe -m pip install --upgrade pip + +pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt -r requirements_dev.txt +pip3 install setuptools wheel +pip3 install -e ".[dev,test,displays]" --config-settings editable_mode=compat + +pre-commit install + +python script/platformio_install_deps.py platformio.ini --libraries --tools --platforms + +echo . +echo . +echo Virtual environment created. Run 'venv/Scripts/activate' to use it. From 5f3f10628318d01d4a01e8fc23161f2ce075052b Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 01:29:09 +0200 Subject: [PATCH 2199/2607] [code-quality] add NOLINT haier_base (#7236) --- esphome/components/haier/haier_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index c0bf878519..7d92a6611c 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -80,8 +80,8 @@ class HaierClimateBase : public esphome::Component, const char *phase_to_string_(ProtocolPhases phase); virtual void set_handlers() = 0; virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; - virtual haier_protocol::HaierMessage get_control_message() = 0; - virtual haier_protocol::HaierMessage get_power_message(bool state) = 0; + virtual haier_protocol::HaierMessage get_control_message() = 0; // NOLINT(readability-identifier-naming) + virtual haier_protocol::HaierMessage get_power_message(bool state) = 0; // NOLINT(readability-identifier-naming) virtual void initialization(){}; virtual bool prepare_pending_action(); virtual void process_protocol_reset(); From 64ee40d3704a4e40ffea6f962ada64fc803d4f62 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 01:33:51 +0200 Subject: [PATCH 2200/2607] [code-quality] clang-tidy bedjet (#7251) --- esphome/components/bedjet/bedjet_codec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/bedjet/bedjet_codec.h b/esphome/components/bedjet/bedjet_codec.h index 527e757d7f..07aee32d54 100644 --- a/esphome/components/bedjet/bedjet_codec.h +++ b/esphome/components/bedjet/bedjet_codec.h @@ -90,7 +90,7 @@ struct BedjetStatusPacket { int unused_6 : 1; // 0x4 bool is_dual_zone : 1; /// Is part of a Dual Zone configuration int unused_7 : 1; // 0x1 - } dual_zone_flags; + } dual_zone_flags; // NOLINT(clang-diagnostic-unaligned-access) uint8_t unused_4 : 8; // Unknown 23-24 = 0x1310 uint8_t unused_5 : 8; // Unknown 23-24 = 0x1310 From f24fd34d860ab39fa66d100aff96dc0f0ec43ee2 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 01:38:13 +0200 Subject: [PATCH 2201/2607] fix name conflict with zephyr macro (#7252) --- esphome/components/fingerprint_grow/fingerprint_grow.cpp | 2 +- esphome/components/fingerprint_grow/fingerprint_grow.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index c2cab368c9..0dfea49b8b 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -307,7 +307,7 @@ void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) { void FingerprintGrowComponent::delete_all_fingerprints() { ESP_LOGI(TAG, "Deleting all stored fingerprints"); - this->data_ = {EMPTY}; + this->data_ = {DELETE_ALL}; switch (this->send_command_()) { case OK: ESP_LOGI(TAG, "Deleted all fingerprints"); diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.h b/esphome/components/fingerprint_grow/fingerprint_grow.h index 20ff60997b..1c3098ef14 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.h +++ b/esphome/components/fingerprint_grow/fingerprint_grow.h @@ -36,7 +36,7 @@ enum GrowCommand { LOAD = 0x07, UPLOAD = 0x08, DELETE = 0x0C, - EMPTY = 0x0D, + DELETE_ALL = 0x0D, // aka EMPTY READ_SYS_PARAM = 0x0F, SET_PASSWORD = 0x12, VERIFY_PASSWORD = 0x13, From 8d5be27746ed6a510b87f53cff6811a277a2589d Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 02:47:18 +0200 Subject: [PATCH 2202/2607] [code-quality] Apply ruff linting suggestions (#7239) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 9ef75e0fb9..f5ddbc0da7 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -1,8 +1,6 @@ -from esphome.core import CORE import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components.esp32 import add_idf_sdkconfig_option - +import esphome.config_validation as cv from esphome.const import ( CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT, @@ -10,6 +8,7 @@ from esphome.const import ( PLATFORM_ESP8266, PLATFORM_RP2040, ) +from esphome.core import CORE CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["mdns"] @@ -42,11 +41,10 @@ async def to_code(config): if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", enable_ipv6) add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", enable_ipv6) - else: - if enable_ipv6: - cg.add_build_flag("-DCONFIG_LWIP_IPV6") - cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") - if CORE.is_rp2040: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") - if CORE.is_esp8266: - cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") + elif enable_ipv6: + cg.add_build_flag("-DCONFIG_LWIP_IPV6") + cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") + if CORE.is_rp2040: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") + if CORE.is_esp8266: + cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") From fc146dabed431ff1c7f314d329cad62ea9d06731 Mon Sep 17 00:00:00 2001 From: juanluss31 <40864809+juanluss31@users.noreply.github.com> Date: Tue, 13 Aug 2024 03:12:48 +0200 Subject: [PATCH 2203/2607] Add support for LYWSD02MMC Xiaomi device (#7080) --- CODEOWNERS | 1 + esphome/components/xiaomi_ble/xiaomi_ble.cpp | 23 +++++- esphome/components/xiaomi_ble/xiaomi_ble.h | 1 + .../components/xiaomi_lywsd02mmc/__init__.py | 0 .../components/xiaomi_lywsd02mmc/sensor.py | 77 +++++++++++++++++++ .../xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp | 73 ++++++++++++++++++ .../xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h | 37 +++++++++ .../components/xiaomi_lywsd02mmc/common.yaml | 12 +++ .../xiaomi_lywsd02mmc/test.esp32-ard.yaml | 1 + .../xiaomi_lywsd02mmc/test.esp32-c3-ard.yaml | 1 + .../xiaomi_lywsd02mmc/test.esp32-c3-idf.yaml | 1 + .../xiaomi_lywsd02mmc/test.esp32-idf.yaml | 1 + 12 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 esphome/components/xiaomi_lywsd02mmc/__init__.py create mode 100644 esphome/components/xiaomi_lywsd02mmc/sensor.py create mode 100644 esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp create mode 100644 esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h create mode 100644 tests/components/xiaomi_lywsd02mmc/common.yaml create mode 100644 tests/components/xiaomi_lywsd02mmc/test.esp32-ard.yaml create mode 100644 tests/components/xiaomi_lywsd02mmc/test.esp32-c3-ard.yaml create mode 100644 tests/components/xiaomi_lywsd02mmc/test.esp32-c3-idf.yaml create mode 100644 tests/components/xiaomi_lywsd02mmc/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 999449a3df..9865e51f11 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -453,6 +453,7 @@ esphome/components/wl_134/* @hobbypunk90 esphome/components/x9c/* @EtienneMD esphome/components/xgzp68xx/* @gcormier esphome/components/xiaomi_hhccjcy10/* @fariouche +esphome/components/xiaomi_lywsd02mmc/* @juanluss31 esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_mhoc303/* @drug123 esphome/components/xiaomi_mhoc401/* @vevsvevs diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 95faea0446..85434341cc 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -49,8 +49,8 @@ bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_ const uint16_t conductivity = encode_uint16(data[1], data[0]); result.conductivity = conductivity; } - // battery, 1 byte, 8-bit unsigned integer, 1 % - else if ((value_type == 0x100A) && (value_length == 1)) { + // battery / MiaoMiaoce battery, 1 byte, 8-bit unsigned integer, 1 % + else if ((value_type == 0x100A || value_type == 0x4803) && (value_length == 1)) { result.battery_level = data[0]; } // temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 % @@ -80,6 +80,17 @@ bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_ result.has_motion = !idle_time; } else if ((value_type == 0x1018) && (value_length == 1)) { result.is_light = data[0]; + } + // MiaoMiaoce temperature, 4 bytes, float, 0.1 °C + else if ((value_type == 0x4C01) && (value_length == 4)) { + const uint32_t int_number = encode_uint32(data[3], data[2], data[1], data[0]); + float temperature; + std::memcpy(&temperature, &int_number, sizeof(temperature)); + result.temperature = temperature; + } + // MiaoMiaoce humidity, 1 byte, 8-bit unsigned integer, 1 % + else if ((value_type == 0x4C02) && (value_length == 1)) { + result.humidity = data[0]; } else { return false; } @@ -111,7 +122,8 @@ bool parse_xiaomi_message(const std::vector &message, XiaomiParseResult } while (payload_length > 3) { - if (payload[payload_offset + 1] != 0x10 && payload[payload_offset + 1] != 0x00) { + if (payload[payload_offset + 1] != 0x10 && payload[payload_offset + 1] != 0x00 && + payload[payload_offset + 1] != 0x4C && payload[payload_offset + 1] != 0x48) { ESP_LOGVV(TAG, "parse_xiaomi_message(): fixed byte not found, stop parsing residual data."); break; } @@ -190,6 +202,11 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service } else if (device_uuid == 0x045b) { // rectangular body, e-ink display result.type = XiaomiParseResult::TYPE_LYWSD02; result.name = "LYWSD02"; + } else if (device_uuid == 0x2542) { // rectangular body, e-ink display — with bindkeys + result.type = XiaomiParseResult::TYPE_LYWSD02MMC; + result.name = "LYWSD02MMC"; + if (raw.size() == 19) + result.raw_offset -= 6; } else if (device_uuid == 0x040a) { // Mosquito Repellent Smart Version result.type = XiaomiParseResult::TYPE_WX08ZM; result.name = "WX08ZM"; diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.h b/esphome/components/xiaomi_ble/xiaomi_ble.h index c1086605d1..6978be97f4 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.h +++ b/esphome/components/xiaomi_ble/xiaomi_ble.h @@ -17,6 +17,7 @@ struct XiaomiParseResult { TYPE_HHCCPOT002, TYPE_LYWSDCGQ, TYPE_LYWSD02, + TYPE_LYWSD02MMC, TYPE_CGG1, TYPE_LYWSD03MMC, TYPE_CGD1, diff --git a/esphome/components/xiaomi_lywsd02mmc/__init__.py b/esphome/components/xiaomi_lywsd02mmc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/xiaomi_lywsd02mmc/sensor.py b/esphome/components/xiaomi_lywsd02mmc/sensor.py new file mode 100644 index 0000000000..43784ef698 --- /dev/null +++ b/esphome/components/xiaomi_lywsd02mmc/sensor.py @@ -0,0 +1,77 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, esp32_ble_tracker +from esphome.const import ( + CONF_BATTERY_LEVEL, + CONF_HUMIDITY, + CONF_MAC_ADDRESS, + CONF_TEMPERATURE, + DEVICE_CLASS_TEMPERATURE, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PERCENT, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_BATTERY, + CONF_ID, + CONF_BINDKEY, +) + +AUTO_LOAD = ["xiaomi_ble"] +CODEOWNERS = ["@juanluss31"] +DEPENDENCIES = ["esp32_ble_tracker"] + +xiaomi_lywsd02mmc_ns = cg.esphome_ns.namespace("xiaomi_lywsd02mmc") +XiaomiLYWSD02MMC = xiaomi_lywsd02mmc_ns.class_( + "XiaomiLYWSD02MMC", esp32_ble_tracker.ESPBTDeviceListener, cg.Component +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XiaomiLYWSD02MMC), + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Required(CONF_BINDKEY): cv.bind_key, + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=0, + device_class=DEVICE_CLASS_BATTERY, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ) + .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + cg.add(var.set_bindkey(config[CONF_BINDKEY])) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature(sens)) + if humidity_config := config.get(CONF_HUMIDITY): + sens = await sensor.new_sensor(humidity_config) + cg.add(var.set_humidity(sens)) + if battery_level_config := config.get(CONF_BATTERY_LEVEL): + sens = await sensor.new_sensor(battery_level_config) + cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp new file mode 100644 index 0000000000..cc122f2264 --- /dev/null +++ b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp @@ -0,0 +1,73 @@ +#include "xiaomi_lywsd02mmc.h" +#include "esphome/core/log.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_lywsd02mmc { + +static const char *const TAG = "xiaomi_lywsd02mmc"; + +void XiaomiLYWSD02MMC::dump_config() { + ESP_LOGCONFIG(TAG, "Xiaomi LYWSD02MMC"); + ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + LOG_SENSOR(" ", "Temperature", this->temperature_); + LOG_SENSOR(" ", "Humidity", this->humidity_); + LOG_SENSOR(" ", "Battery Level", this->battery_level_); +} + +bool XiaomiLYWSD02MMC::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { + if (device.address_uint64() != this->address_) { + ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); + return false; + } + ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); + + bool success = false; + for (auto &service_data : device.get_service_datas()) { + auto res = xiaomi_ble::parse_xiaomi_header(service_data); + if (!res.has_value()) { + continue; + } + if (res->is_duplicate) { + continue; + } + if (res->has_encryption && + (!(xiaomi_ble::decrypt_xiaomi_payload(const_cast &>(service_data.data), this->bindkey_, + this->address_)))) { + continue; + } + if (!(xiaomi_ble::parse_xiaomi_message(service_data.data, *res))) { + continue; + } + if (!(xiaomi_ble::report_xiaomi_results(res, device.address_str()))) { + continue; + } + if (res->temperature.has_value() && this->temperature_ != nullptr) + this->temperature_->publish_state(*res->temperature); + if (res->humidity.has_value() && this->humidity_ != nullptr) + this->humidity_->publish_state(*res->humidity); + if (res->battery_level.has_value() && this->battery_level_ != nullptr) + this->battery_level_->publish_state(*res->battery_level); + success = true; + } + + return success; +} + +void XiaomiLYWSD02MMC::set_bindkey(const std::string &bindkey) { + memset(this->bindkey_, 0, 16); + if (bindkey.size() != 32) { + return; + } + char temp[3] = {0}; + for (int i = 0; i < 16; i++) { + strncpy(temp, &(bindkey.c_str()[i * 2]), 2); + this->bindkey_[i] = std::strtoul(temp, nullptr, 16); + } +} + +} // namespace xiaomi_lywsd02mmc +} // namespace esphome + +#endif diff --git a/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h new file mode 100644 index 0000000000..19092aa2a9 --- /dev/null +++ b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h @@ -0,0 +1,37 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/xiaomi_ble/xiaomi_ble.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_lywsd02mmc { + +class XiaomiLYWSD02MMC : public Component, public esp32_ble_tracker::ESPBTDeviceListener { + public: + void set_address(uint64_t address) { this->address_ = address; } + void set_bindkey(const std::string &bindkey); + + bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; + + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; } + void set_humidity(sensor::Sensor *humidity) { this->humidity_ = humidity; } + void set_battery_level(sensor::Sensor *battery_level) { this->battery_level_ = battery_level; } + + protected: + uint64_t address_; + uint8_t bindkey_[16]; + sensor::Sensor *temperature_{nullptr}; + sensor::Sensor *humidity_{nullptr}; + sensor::Sensor *battery_level_{nullptr}; +}; + +} // namespace xiaomi_lywsd02mmc +} // namespace esphome + +#endif diff --git a/tests/components/xiaomi_lywsd02mmc/common.yaml b/tests/components/xiaomi_lywsd02mmc/common.yaml new file mode 100644 index 0000000000..e63f585830 --- /dev/null +++ b/tests/components/xiaomi_lywsd02mmc/common.yaml @@ -0,0 +1,12 @@ +esp32_ble_tracker: + +sensor: + - platform: xiaomi_lywsd02mmc + mac_address: A4:C1:38:54:5E:18 + bindkey: 2529d8e0d23150a588675cc54ad48400 + temperature: + name: Xiaomi LYWSD02MMC Temperature + humidity: + name: Xiaomi LYWSD02MMC Humidity + battery_level: + name: Xiaomi LYWSD02MMC Battery Level diff --git a/tests/components/xiaomi_lywsd02mmc/test.esp32-ard.yaml b/tests/components/xiaomi_lywsd02mmc/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/xiaomi_lywsd02mmc/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-ard.yaml b/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-idf.yaml b/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/xiaomi_lywsd02mmc/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/xiaomi_lywsd02mmc/test.esp32-idf.yaml b/tests/components/xiaomi_lywsd02mmc/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/xiaomi_lywsd02mmc/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 8d106e97a2bd03239e11609fb6a53b1e493c634b Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 03:14:25 +0200 Subject: [PATCH 2204/2607] [code-quality] fix clang-tidy web server (#7230) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/web_server/web_server.h | 2 +- esphome/components/web_server_base/web_server_base.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 5b98806af1..d4ab592b7b 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -334,7 +334,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { /// Override the web handler's handleRequest method. void handleRequest(AsyncWebServerRequest *request) override; /// This web handle is not trivial. - bool isRequestHandlerTrivial() override; + bool isRequestHandlerTrivial() override; // NOLINT(readability-identifier-naming) void add_entity_to_sorting_list(EntityBase *entity, float weight); diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index c312126472..2282d55ec1 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -134,6 +134,7 @@ class OTARequestHandler : public AsyncWebHandler { return request->url() == "/update" && request->method() == HTTP_POST; } + // NOLINTNEXTLINE(readability-identifier-naming) bool isRequestHandlerTrivial() override { return false; } protected: From 390d5f2f9361c00c558d64fb00c9ce66b92703e1 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Tue, 13 Aug 2024 03:26:39 +0200 Subject: [PATCH 2205/2607] [test][web_server] Rejig test for v3 (#7110) --- tests/components/web_server/common_v1.yaml | 3 ++- tests/components/web_server/common_v2.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/components/web_server/common_v1.yaml b/tests/components/web_server/common_v1.yaml index bf5aab4ce6..3c51f894b8 100644 --- a/tests/components/web_server/common_v1.yaml +++ b/tests/components/web_server/common_v1.yaml @@ -1,4 +1,5 @@ -<<: !include common.yaml +packages: + device_base: !include common.yaml web_server: port: 8080 diff --git a/tests/components/web_server/common_v2.yaml b/tests/components/web_server/common_v2.yaml index 564c43e553..2af5ceca44 100644 --- a/tests/components/web_server/common_v2.yaml +++ b/tests/components/web_server/common_v2.yaml @@ -1,4 +1,5 @@ -<<: !include common.yaml +packages: + device_base: !include common.yaml web_server: port: 8080 From ab51bbd8f7a9ca8648f7a245cdec02f8fa08e14b Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Tue, 13 Aug 2024 03:52:31 +0200 Subject: [PATCH 2206/2607] [api] Error log when NONE Update command is sent (#7247) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api_connection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 8e4c6faaee..bd438265d4 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1335,6 +1335,9 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { case enums::UPDATE_COMMAND_CHECK: update->check(); break; + case enums::UPDATE_COMMAND_NONE: + ESP_LOGE(TAG, "UPDATE_COMMAND_NONE not handled. Check client is sending the correct command"); + break; default: ESP_LOGW(TAG, "Unknown update command: %" PRIu32, msg.command); break; From 2b25daa199b175e1f2d3f1db94b6516f37b90748 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:12:06 +1200 Subject: [PATCH 2207/2607] [api] Add new flag to request state/attribute once from HA only (#7258) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_pb2.cpp | 15 +++++++++++++++ esphome/components/api/api_pb2.h | 2 ++ esphome/components/api/api_server.cpp | 10 ++++++++++ esphome/components/api/api_server.h | 3 +++ 5 files changed, 31 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index b62fddf815..72eaeed6d7 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -686,6 +686,7 @@ message SubscribeHomeAssistantStateResponse { option (source) = SOURCE_SERVER; string entity_id = 1; string attribute = 2; + bool once = 3; } message HomeAssistantStateResponse { diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index a57627a66c..bb37824403 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3109,6 +3109,16 @@ void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { out.append("SubscribeHomeAssistantStatesRequest {}"); } #endif +bool SubscribeHomeAssistantStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 3: { + this->once = value.as_bool(); + return true; + } + default: + return false; + } +} bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -3126,6 +3136,7 @@ bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, Proto void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->entity_id); buffer.encode_string(2, this->attribute); + buffer.encode_bool(3, this->once); } #ifdef HAS_PROTO_MESSAGE_DUMP void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { @@ -3138,6 +3149,10 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { out.append(" attribute: "); out.append("'").append(this->attribute).append("'"); out.append("\n"); + + out.append(" once: "); + out.append(YESNO(this->once)); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index bb5263cffa..3eb945fd8d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -836,6 +836,7 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { public: std::string entity_id{}; std::string attribute{}; + bool once{false}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; @@ -843,6 +844,7 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class HomeAssistantStateResponse : public ProtoMessage { public: diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index a61ae89243..0fde3e47af 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -359,8 +359,18 @@ void APIServer::subscribe_home_assistant_state(std::string entity_id, optional attribute, + std::function f) { + this->state_subs_.push_back(HomeAssistantStateSubscription{ + .entity_id = std::move(entity_id), + .attribute = std::move(attribute), + .callback = std::move(f), + .once = true, + }); +}; const std::vector &APIServer::get_state_subs() const { return this->state_subs_; } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 43bc8a7348..899eaede49 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -112,10 +112,13 @@ class APIServer : public Component, public Controller { std::string entity_id; optional attribute; std::function callback; + bool once; }; void subscribe_home_assistant_state(std::string entity_id, optional attribute, std::function f); + void get_home_assistant_state(std::string entity_id, optional attribute, + std::function f); const std::vector &get_state_subs() const; const std::vector &get_user_services() const { return this->user_services_; } From 8696f922d120e787f7231d9d4b8a00f74eec0125 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:33:16 +1200 Subject: [PATCH 2208/2607] [homeassistant] Add ``HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA`` (#7259) --- CODEOWNERS | 2 +- esphome/components/homeassistant/__init__.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 9865e51f11..663a942cb4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -168,7 +168,7 @@ esphome/components/he60r/* @clydebarrow esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hm3301/* @freekode -esphome/components/homeassistant/* @OttoWinter +esphome/components/homeassistant/* @OttoWinter @esphome/core esphome/components/honeywell_hih_i2c/* @Benichou34 esphome/components/honeywellabp/* @RubyBailey esphome/components/honeywellabp2_i2c/* @jpfaff diff --git a/esphome/components/homeassistant/__init__.py b/esphome/components/homeassistant/__init__.py index 776aa7fd7b..6d997e48ca 100644 --- a/esphome/components/homeassistant/__init__.py +++ b/esphome/components/homeassistant/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_INTERNAL -CODEOWNERS = ["@OttoWinter"] +CODEOWNERS = ["@OttoWinter", "@esphome/core"] homeassistant_ns = cg.esphome_ns.namespace("homeassistant") HOME_ASSISTANT_IMPORT_SCHEMA = cv.Schema( @@ -13,6 +13,13 @@ HOME_ASSISTANT_IMPORT_SCHEMA = cv.Schema( } ) +HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA = cv.Schema( + { + cv.Required(CONF_ENTITY_ID): cv.entity_id, + cv.Optional(CONF_INTERNAL, default=True): cv.boolean, + } +) + def setup_home_assistant_entity(var, config): cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) From 2a70ef05d17c0645fd4e9023d6b1bc5c2ea078ca Mon Sep 17 00:00:00 2001 From: nkinnan Date: Mon, 12 Aug 2024 23:48:12 -0700 Subject: [PATCH 2209/2607] [const] Add some units for future use and adjust case (#7260) --- esphome/const.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/esphome/const.py b/esphome/const.py index 13559ecf95..c5d0e8f838 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1034,8 +1034,10 @@ UNIT_KELVIN = "K" UNIT_KILOGRAM = "kg" UNIT_KILOMETER = "km" UNIT_KILOMETER_PER_HOUR = "km/h" -UNIT_KILOVOLT_AMPS_REACTIVE = "kVAr" -UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kVArh" +UNIT_KILOVOLT_AMPS = "kVA" +UNIT_KILOVOLT_AMPS_HOURS = "kVAh" +UNIT_KILOVOLT_AMPS_REACTIVE = "kVAR" +UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kVARh" UNIT_KILOWATT = "kW" UNIT_KILOWATT_HOURS = "kWh" UNIT_LUX = "lx" @@ -1066,6 +1068,7 @@ UNIT_SECOND = "s" UNIT_STEPS = "steps" UNIT_VOLT = "V" UNIT_VOLT_AMPS = "VA" +UNIT_VOLT_AMPS_HOURS = "VAh" UNIT_VOLT_AMPS_REACTIVE = "VAR" UNIT_VOLT_AMPS_REACTIVE_HOURS = "VARh" UNIT_WATT = "W" From 506e69addf81fc8cc542520d7db17937a8b74c5b Mon Sep 17 00:00:00 2001 From: guillempages Date: Tue, 13 Aug 2024 09:44:43 +0200 Subject: [PATCH 2210/2607] [online_image] add option to show placeholder while downloading (#7083) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/online_image/__init__.py | 6 ++++++ esphome/components/online_image/online_image.cpp | 8 ++++++++ esphome/components/online_image/online_image.h | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/esphome/components/online_image/__init__.py b/esphome/components/online_image/__init__.py index ee5357457a..d9a7609543 100644 --- a/esphome/components/online_image/__init__.py +++ b/esphome/components/online_image/__init__.py @@ -27,6 +27,7 @@ CODEOWNERS = ["@guillempages"] MULTI_CONF = True CONF_ON_DOWNLOAD_FINISHED = "on_download_finished" +CONF_PLACEHOLDER = "placeholder" _LOGGER = logging.getLogger(__name__) @@ -73,6 +74,7 @@ ONLINE_IMAGE_SCHEMA = cv.Schema( # cv.Required(CONF_URL): cv.url, cv.Required(CONF_FORMAT): cv.enum(IMAGE_FORMAT, upper=True), + cv.Optional(CONF_PLACEHOLDER): cv.use_id(Image_), cv.Optional(CONF_BUFFER_SIZE, default=2048): cv.int_range(256, 65536), cv.Optional(CONF_ON_DOWNLOAD_FINISHED): automation.validate_automation( { @@ -152,6 +154,10 @@ async def to_code(config): cg.add(var.set_transparency(transparent)) + if placeholder_id := config.get(CONF_PLACEHOLDER): + placeholder = await cg.get_variable(placeholder_id) + cg.add(var.set_placeholder(placeholder)) + for conf in config.get(CONF_ON_DOWNLOAD_FINISHED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/online_image/online_image.cpp b/esphome/components/online_image/online_image.cpp index a4cf0158aa..480bad6aca 100644 --- a/esphome/components/online_image/online_image.cpp +++ b/esphome/components/online_image/online_image.cpp @@ -35,6 +35,14 @@ OnlineImage::OnlineImage(const std::string &url, int width, int height, ImageFor this->set_url(url); } +void OnlineImage::draw(int x, int y, display::Display *display, Color color_on, Color color_off) { + if (this->data_start_) { + Image::draw(x, y, display, color_on, color_off); + } else if (this->placeholder_) { + this->placeholder_->draw(x, y, display, color_on, color_off); + } +} + void OnlineImage::release() { if (this->buffer_) { ESP_LOGD(TAG, "Deallocating old buffer..."); diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h index 30e97760ea..775cc46e0b 100644 --- a/esphome/components/online_image/online_image.h +++ b/esphome/components/online_image/online_image.h @@ -50,6 +50,8 @@ class OnlineImage : public PollingComponent, OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type, uint32_t buffer_size); + void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override; + void update() override; void loop() override; @@ -60,6 +62,14 @@ class OnlineImage : public PollingComponent, } } + /** + * @brief Set the image that needs to be shown as long as the downloaded image + * is not available. + * + * @param placeholder Pointer to the (@link Image) to show as placeholder. + */ + void set_placeholder(image::Image *placeholder) { this->placeholder_ = placeholder; } + /** * Release the buffer storing the image. The image will need to be downloaded again * to be able to be displayed. @@ -113,6 +123,7 @@ class OnlineImage : public PollingComponent, DownloadBuffer download_buffer_; const ImageFormat format_; + image::Image *placeholder_{nullptr}; std::string url_{""}; From 3598560472b844c172a1ed2783f13ba258be378d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:06:01 +1000 Subject: [PATCH 2211/2607] [lvgl] Add initial_focus for encoders (#7256) --- esphome/components/lvgl/__init__.py | 3 ++- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/encoders.py | 8 ++++++++ esphome/components/lvgl/schemas.py | 25 +++++++++++++++-------- tests/components/lvgl/test.esp32-ard.yaml | 1 + 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 6bf6e287f8..7c51d9c70d 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -23,7 +23,7 @@ from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid from .automation import disp_update, update_to_code from .defines import CONF_SKIP -from .encoders import ENCODERS_CONFIG, encoders_to_code +from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent from .schemas import ( @@ -272,6 +272,7 @@ async def to_code(config): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) await build_automation(idle_trigger, [], conf) + await initial_focus_to_code(config) for comp in helpers.lvgl_components_required: CORE.add_define(f"USE_LVGL_{comp.upper()}") diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 1c6fd2678c..e48679996b 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -413,6 +413,7 @@ CONF_GRID_ROW_ALIGN = "grid_row_align" CONF_GRID_ROWS = "grid_rows" CONF_HEADER_MODE = "header_mode" CONF_HOME = "home" +CONF_INITIAL_FOCUS = "initial_focus" CONF_KEY_CODE = "key_code" CONF_LAYOUT = "layout" CONF_LEFT_BUTTON = "left_button" diff --git a/esphome/components/lvgl/encoders.py b/esphome/components/lvgl/encoders.py index cfd0e42996..81bcda95b4 100644 --- a/esphome/components/lvgl/encoders.py +++ b/esphome/components/lvgl/encoders.py @@ -8,6 +8,7 @@ from .defines import ( CONF_DEFAULT_GROUP, CONF_ENCODERS, CONF_ENTER_BUTTON, + CONF_INITIAL_FOCUS, CONF_LEFT_BUTTON, CONF_LONG_PRESS_REPEAT_TIME, CONF_LONG_PRESS_TIME, @@ -67,3 +68,10 @@ async def encoders_to_code(var, config): else: group = default_group lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) + + +async def initial_focus_to_code(config): + for enc_conf in config[CONF_ENCODERS]: + if default_focus := enc_conf.get(CONF_INITIAL_FOCUS): + obj = await cg.get_variable(default_focus) + lv.group_focus_obj(obj) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index f172ba9f2b..e4b1c3f8fa 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -14,11 +14,19 @@ from esphome.const import ( from esphome.core import TimePeriod from esphome.schema_extractors import SCHEMA_EXTRACT -from . import defines as df, lv_validation as lvalid, types as ty +from . import defines as df, lv_validation as lvalid from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_color, lv_font, lv_image from .lvcode import LvglComponent -from .types import WidgetType, lv_group_t +from .types import ( + LVEncoderListener, + LvType, + WidgetType, + lv_group_t, + lv_obj_t, + lv_pseudo_button_t, + lv_style_t, +) # this will be populated later, in __init__.py to avoid circular imports. WIDGET_TYPES: dict = {} @@ -46,7 +54,7 @@ TEXT_SCHEMA = cv.Schema( LIST_ACTION_SCHEMA = cv.ensure_list( cv.maybe_simple_value( { - cv.Required(CONF_ID): cv.use_id(ty.lv_pseudo_button_t), + cv.Required(CONF_ID): cv.use_id(lv_pseudo_button_t), }, key=CONF_ID, ) @@ -59,9 +67,10 @@ PRESS_TIME = cv.All( ENCODER_SCHEMA = cv.Schema( { cv.GenerateID(): cv.All( - cv.declare_id(ty.LVEncoderListener), requires_component("binary_sensor") + cv.declare_id(LVEncoderListener), requires_component("binary_sensor") ), cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t), + cv.Optional(df.CONF_INITIAL_FOCUS): cv.use_id(lv_obj_t), cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, } @@ -161,7 +170,7 @@ STYLE_REMAP = { # Complete object style schema STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( { - cv.Optional(df.CONF_STYLES): cv.ensure_list(cv.use_id(ty.lv_style_t)), + cv.Optional(df.CONF_STYLES): cv.ensure_list(cv.use_id(lv_style_t)), cv.Optional(df.CONF_SCROLLBAR_MODE): df.LvConstant( "LV_SCROLLBAR_MODE_", "OFF", "ON", "ACTIVE", "AUTO" ).one_of, @@ -193,12 +202,12 @@ def part_schema(widget_type: WidgetType): ) -def automation_schema(typ: ty.LvType): +def automation_schema(typ: LvType): if typ.has_on_value: events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,) else: events = df.LV_EVENT_TRIGGERS - if isinstance(typ, ty.LvType): + if isinstance(typ, LvType): template = Trigger.template(typ.get_arg_type()) else: template = Trigger.template() @@ -261,7 +270,7 @@ LAYOUT_SCHEMAS = {} ALIGN_TO_SCHEMA = { cv.Optional(df.CONF_ALIGN_TO): cv.Schema( { - cv.Required(CONF_ID): cv.use_id(ty.lv_obj_t), + cv.Required(CONF_ID): cv.use_id(lv_obj_t), cv.Required(df.CONF_ALIGN): df.ALIGN_ALIGNMENTS.one_of, cv.Optional(df.CONF_X, default=0): lvalid.pixels_or_percent, cv.Optional(df.CONF_Y, default=0): lvalid.pixels_or_percent, diff --git a/tests/components/lvgl/test.esp32-ard.yaml b/tests/components/lvgl/test.esp32-ard.yaml index 2d6a6871ba..51593e7967 100644 --- a/tests/components/lvgl/test.esp32-ard.yaml +++ b/tests/components/lvgl/test.esp32-ard.yaml @@ -46,6 +46,7 @@ binary_sensor: lvgl: encoders: group: switches + initial_focus: button_button enter_button: select_button sensor: left_button: up_button From c9979ad90c950198d3cc624e88d43975e5af497a Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:46:23 +0200 Subject: [PATCH 2212/2607] [code-quality] fix order in esphome/const.py (#7267) --- esphome/const.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/const.py b/esphome/const.py index c5d0e8f838..55f1c23b40 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -7,22 +7,22 @@ VALID_SUBSTITUTIONS_CHARACTERS = ( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" ) +PLATFORM_BK72XX = "bk72xx" PLATFORM_ESP32 = "esp32" PLATFORM_ESP8266 = "esp8266" -PLATFORM_RP2040 = "rp2040" PLATFORM_HOST = "host" -PLATFORM_BK72XX = "bk72xx" -PLATFORM_RTL87XX = "rtl87xx" PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" +PLATFORM_RP2040 = "rp2040" +PLATFORM_RTL87XX = "rtl87xx" TARGET_PLATFORMS = [ + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, - PLATFORM_RP2040, PLATFORM_HOST, - PLATFORM_BK72XX, - PLATFORM_RTL87XX, PLATFORM_LIBRETINY_OLDSTYLE, + PLATFORM_RP2040, + PLATFORM_RTL87XX, ] SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} From b082a64d3248d4a272924f5887915109427b5d68 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:48:27 +0200 Subject: [PATCH 2213/2607] [code-quality] fix clang-tidy network (#7266) --- esphome/components/network/__init__.py | 1 + esphome/components/network/ip_address.h | 3 +++ esphome/components/network/util.cpp | 3 ++- esphome/components/network/util.h | 4 +++- esphome/core/defines.h | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index f5ddbc0da7..96db322bde 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -32,6 +32,7 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): + cg.add_define("USE_NETWORK") if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: cg.add_define("USE_NETWORK_IPV6", enable_ipv6) if enable_ipv6: diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 30a426e458..941934cf0a 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -1,4 +1,6 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include #include #include @@ -140,3 +142,4 @@ using IPAddresses = std::array; } // namespace network } // namespace esphome +#endif diff --git a/esphome/components/network/util.cpp b/esphome/components/network/util.cpp index 445485b644..ed519f738a 100644 --- a/esphome/components/network/util.cpp +++ b/esphome/components/network/util.cpp @@ -1,6 +1,6 @@ #include "util.h" #include "esphome/core/defines.h" - +#ifdef USE_NETWORK #ifdef USE_WIFI #include "esphome/components/wifi/wifi_component.h" #endif @@ -63,3 +63,4 @@ std::string get_use_address() { } // namespace network } // namespace esphome +#endif diff --git a/esphome/components/network/util.h b/esphome/components/network/util.h index 5377d44f2f..b518696e68 100644 --- a/esphome/components/network/util.h +++ b/esphome/components/network/util.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include #include "ip_address.h" @@ -16,3 +17,4 @@ IPAddresses get_ip_addresses(); } // namespace network } // namespace esphome +#endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index a711148ec8..a4d473b76e 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -51,6 +51,7 @@ #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT +#define USE_NETWORK #define USE_NEXTION_TFT_UPLOAD #define USE_NUMBER #define USE_ONLINE_IMAGE_PNG_SUPPORT From 9663b7d67ccf2c2e188a709a512ffe0aaae45865 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:53:42 +0200 Subject: [PATCH 2214/2607] [code-quality] fix clang-tidy core optional (#7265) --- esphome/core/optional.h | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/core/optional.h b/esphome/core/optional.h index 5b96781e63..770b77081e 100644 --- a/esphome/core/optional.h +++ b/esphome/core/optional.h @@ -104,7 +104,6 @@ template class optional { // NOLINT has_value_ = true; } - private: bool has_value_{false}; // NOLINT value_type value_; // NOLINT }; From 4bd7ba0d30dca6cb3c13cdd7a0cfab64253e9720 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:54:37 +0200 Subject: [PATCH 2215/2607] [code-quality] Fix variable naming in base_light_effects (#7237) --- esphome/components/light/base_light_effects.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/light/base_light_effects.h b/esphome/components/light/base_light_effects.h index f7829a3f44..9e02e889c9 100644 --- a/esphome/components/light/base_light_effects.h +++ b/esphome/components/light/base_light_effects.h @@ -25,7 +25,7 @@ class PulseLightEffect : public LightEffect { return; } auto call = this->state_->turn_on(); - float out = this->on_ ? this->max_brightness : this->min_brightness; + float out = this->on_ ? this->max_brightness_ : this->min_brightness_; call.set_brightness_if_supported(out); call.set_transition_length_if_supported(this->on_ ? this->transition_on_length_ : this->transition_off_length_); this->on_ = !this->on_; @@ -43,8 +43,8 @@ class PulseLightEffect : public LightEffect { void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; } void set_min_max_brightness(float min, float max) { - this->min_brightness = min; - this->max_brightness = max; + this->min_brightness_ = min; + this->max_brightness_ = max; } protected: @@ -53,8 +53,8 @@ class PulseLightEffect : public LightEffect { uint32_t transition_on_length_{}; uint32_t transition_off_length_{}; uint32_t update_interval_{}; - float min_brightness{0.0}; - float max_brightness{1.0}; + float min_brightness_{0.0}; + float max_brightness_{1.0}; }; /// Random effect. Sets random colors every 10 seconds and slowly transitions between them. From f81ce2c70743098796493ce703c7c388de10f783 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:56:09 +0200 Subject: [PATCH 2216/2607] [code-quality] fix clang-tidy mqtt (#7253) --- esphome/components/mqtt/mqtt_backend.h | 4 +++- esphome/components/mqtt/mqtt_backend_esp32.cpp | 5 ++++- esphome/components/mqtt/mqtt_backend_esp32.h | 4 +++- esphome/components/mqtt/mqtt_backend_esp8266.h | 4 +++- esphome/components/mqtt/mqtt_backend_libretiny.h | 4 +++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/esphome/components/mqtt/mqtt_backend.h b/esphome/components/mqtt/mqtt_backend.h index d23cda578d..3962c40a42 100644 --- a/esphome/components/mqtt/mqtt_backend.h +++ b/esphome/components/mqtt/mqtt_backend.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_MQTT #include #include #include "esphome/components/network/ip_address.h" @@ -67,3 +68,4 @@ class MQTTBackend { } // namespace mqtt } // namespace esphome +#endif diff --git a/esphome/components/mqtt/mqtt_backend_esp32.cpp b/esphome/components/mqtt/mqtt_backend_esp32.cpp index 9c2e487ae7..ed500c6d44 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.cpp +++ b/esphome/components/mqtt/mqtt_backend_esp32.cpp @@ -1,7 +1,9 @@ +#include "mqtt_backend_esp32.h" + +#ifdef USE_MQTT #ifdef USE_ESP32 #include -#include "mqtt_backend_esp32.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" @@ -189,3 +191,4 @@ void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t b } // namespace mqtt } // namespace esphome #endif // USE_ESP32 +#endif diff --git a/esphome/components/mqtt/mqtt_backend_esp32.h b/esphome/components/mqtt/mqtt_backend_esp32.h index b1f672da10..9054702115 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.h +++ b/esphome/components/mqtt/mqtt_backend_esp32.h @@ -1,5 +1,7 @@ #pragma once +#include "mqtt_backend.h" +#ifdef USE_MQTT #ifdef USE_ESP32 #include @@ -7,7 +9,6 @@ #include #include "esphome/components/network/ip_address.h" #include "esphome/core/helpers.h" -#include "mqtt_backend.h" namespace esphome { namespace mqtt { @@ -174,3 +175,4 @@ class MQTTBackendESP32 final : public MQTTBackend { } // namespace esphome #endif +#endif diff --git a/esphome/components/mqtt/mqtt_backend_esp8266.h b/esphome/components/mqtt/mqtt_backend_esp8266.h index 06d4993bdf..a979634bf4 100644 --- a/esphome/components/mqtt/mqtt_backend_esp8266.h +++ b/esphome/components/mqtt/mqtt_backend_esp8266.h @@ -1,8 +1,9 @@ #pragma once +#include "mqtt_backend.h" +#ifdef USE_MQTT #ifdef USE_ESP8266 -#include "mqtt_backend.h" #include namespace esphome { @@ -70,3 +71,4 @@ class MQTTBackendESP8266 final : public MQTTBackend { } // namespace esphome #endif // defined(USE_ESP8266) +#endif diff --git a/esphome/components/mqtt/mqtt_backend_libretiny.h b/esphome/components/mqtt/mqtt_backend_libretiny.h index ac4d4298fc..2578ae9941 100644 --- a/esphome/components/mqtt/mqtt_backend_libretiny.h +++ b/esphome/components/mqtt/mqtt_backend_libretiny.h @@ -1,8 +1,9 @@ #pragma once +#include "mqtt_backend.h" +#ifdef USE_MQTT #ifdef USE_LIBRETINY -#include "mqtt_backend.h" #include namespace esphome { @@ -70,3 +71,4 @@ class MQTTBackendLibreTiny final : public MQTTBackend { } // namespace esphome #endif // defined(USE_LIBRETINY) +#endif From 2e58297a16e2ea0e94235b5268fa98e19744f954 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 13 Aug 2024 21:58:30 +0200 Subject: [PATCH 2217/2607] [code-quality] fix clang-tidy wifi related (#7254) --- esphome/components/wifi/wifi_component.cpp | 2 ++ esphome/components/wifi/wifi_component.h | 4 +++- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 2 ++ esphome/components/wifi/wifi_component_esp8266.cpp | 2 ++ esphome/components/wifi/wifi_component_esp_idf.cpp | 2 ++ esphome/components/wifi/wifi_component_libretiny.cpp | 2 ++ esphome/components/wifi/wifi_component_pico_w.cpp | 2 ++ esphome/components/wifi_info/wifi_info_text_sensor.cpp | 2 ++ esphome/components/wifi_info/wifi_info_text_sensor.h | 2 ++ esphome/components/wifi_signal/wifi_signal_sensor.cpp | 2 ++ esphome/components/wifi_signal/wifi_signal_sensor.h | 3 ++- 11 files changed, 23 insertions(+), 2 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 8c40f87879..583a27466a 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -1,4 +1,5 @@ #include "wifi_component.h" +#ifdef USE_WIFI #include #include @@ -856,3 +857,4 @@ WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-con } // namespace wifi } // namespace esphome +#endif diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d79cde0b18..dde0d1d5a5 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -1,9 +1,10 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_WIFI #include "esphome/components/network/ip_address.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" -#include "esphome/core/defines.h" #include "esphome/core/helpers.h" #include @@ -442,3 +443,4 @@ template class WiFiDisableAction : public Action { } // namespace wifi } // namespace esphome +#endif diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 71548b7a3e..b8724838c8 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -1,5 +1,6 @@ #include "wifi_component.h" +#ifdef USE_WIFI #ifdef USE_ESP32_FRAMEWORK_ARDUINO #include @@ -802,3 +803,4 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddr } // namespace esphome #endif // USE_ESP32_FRAMEWORK_ARDUINO +#endif diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 997457e2d2..92f80c1e52 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -1,6 +1,7 @@ #include "wifi_component.h" #include "esphome/core/defines.h" +#ifdef USE_WIFI #ifdef USE_ESP8266 #include @@ -834,3 +835,4 @@ void WiFiComponent::wifi_loop_() {} } // namespace esphome #endif +#endif diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index a8d67ed44d..6008acb95d 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -1,5 +1,6 @@ #include "wifi_component.h" +#ifdef USE_WIFI #ifdef USE_ESP_IDF #include @@ -1010,3 +1011,4 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { } // namespace esphome #endif // USE_ESP_IDF +#endif diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index f6b0fb2699..19ade84a88 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -1,5 +1,6 @@ #include "wifi_component.h" +#ifdef USE_WIFI #ifdef USE_LIBRETINY #include @@ -468,3 +469,4 @@ void WiFiComponent::wifi_loop_() {} } // namespace esphome #endif // USE_LIBRETINY +#endif diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 4afcf2d78b..bac986d899 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -1,6 +1,7 @@ #include "wifi_component.h" +#ifdef USE_WIFI #ifdef USE_RP2040 #include "lwip/dns.h" @@ -218,3 +219,4 @@ void WiFiComponent::wifi_pre_setup_() {} } // namespace esphome #endif +#endif diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.cpp b/esphome/components/wifi_info/wifi_info_text_sensor.cpp index eeb4985398..150c7229f8 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.cpp +++ b/esphome/components/wifi_info/wifi_info_text_sensor.cpp @@ -1,4 +1,5 @@ #include "wifi_info_text_sensor.h" +#ifdef USE_WIFI #include "esphome/core/log.h" namespace esphome { @@ -15,3 +16,4 @@ void DNSAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "WifiInfo DNS Addre } // namespace wifi_info } // namespace esphome +#endif diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.h b/esphome/components/wifi_info/wifi_info_text_sensor.h index 0f31a57cc5..0aa44a0894 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.h +++ b/esphome/components/wifi_info/wifi_info_text_sensor.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/wifi/wifi_component.h" +#ifdef USE_WIFI #include namespace esphome { @@ -131,3 +132,4 @@ class MacAddressWifiInfo : public Component, public text_sensor::TextSensor { } // namespace wifi_info } // namespace esphome +#endif diff --git a/esphome/components/wifi_signal/wifi_signal_sensor.cpp b/esphome/components/wifi_signal/wifi_signal_sensor.cpp index ba22138e2a..4347295421 100644 --- a/esphome/components/wifi_signal/wifi_signal_sensor.cpp +++ b/esphome/components/wifi_signal/wifi_signal_sensor.cpp @@ -1,4 +1,5 @@ #include "wifi_signal_sensor.h" +#ifdef USE_WIFI #include "esphome/core/log.h" namespace esphome { @@ -10,3 +11,4 @@ void WiFiSignalSensor::dump_config() { LOG_SENSOR("", "WiFi Signal", this); } } // namespace wifi_signal } // namespace esphome +#endif diff --git a/esphome/components/wifi_signal/wifi_signal_sensor.h b/esphome/components/wifi_signal/wifi_signal_sensor.h index f797aaa590..fbe03a6404 100644 --- a/esphome/components/wifi_signal/wifi_signal_sensor.h +++ b/esphome/components/wifi_signal/wifi_signal_sensor.h @@ -4,7 +4,7 @@ #include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/wifi/wifi_component.h" - +#ifdef USE_WIFI namespace esphome { namespace wifi_signal { @@ -19,3 +19,4 @@ class WiFiSignalSensor : public sensor::Sensor, public PollingComponent { } // namespace wifi_signal } // namespace esphome +#endif From 9ec61cbff3ec79a7fb3d5fe7720ced35dd69989f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 08:12:56 +1200 Subject: [PATCH 2218/2607] Bump docker/build-push-action from 6.6.1 to 6.7.0 in /.github/actions/build-image (#7269) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index f9c44cfb63..56be20bd87 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.6.1 + uses: docker/build-push-action@v6.7.0 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.6.1 + uses: docker/build-push-action@v6.7.0 with: context: . file: ./docker/Dockerfile From 0c567adf639585474881d8ee8aff8e316b501a80 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 14 Aug 2024 08:13:09 +1200 Subject: [PATCH 2219/2607] [CI] Dont run full CI on ``build-image`` action changes (#7270) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8e93248bb..126a541b3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: paths: - "**" - "!.github/workflows/*.yml" + - "!.github/actions/build-image/*" - ".github/workflows/ci.yml" - "!.yamllint" - "!.github/dependabot.yml" From 68c56b3e03bffb47c4f4481ff534d8d3ac3bc38e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 14 Aug 2024 07:29:31 +1000 Subject: [PATCH 2220/2607] Implement ByteBuffer (#6878) --- esphome/core/bytebuffer.cpp | 134 ++++++++++++++++++++++++++++++++++++ esphome/core/bytebuffer.h | 96 ++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 esphome/core/bytebuffer.cpp create mode 100644 esphome/core/bytebuffer.h diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp new file mode 100644 index 0000000000..fb2ade3166 --- /dev/null +++ b/esphome/core/bytebuffer.cpp @@ -0,0 +1,134 @@ +#include "bytebuffer.h" +#include + +namespace esphome { + +ByteBuffer ByteBuffer::create(size_t capacity) { + std::vector data(capacity); + return {data}; +} + +ByteBuffer ByteBuffer::wrap(uint8_t *ptr, size_t len) { + std::vector data(ptr, ptr + len); + return {data}; +} + +ByteBuffer ByteBuffer::wrap(std::vector data) { return {std::move(data)}; } + +void ByteBuffer::set_limit(size_t limit) { + assert(limit <= this->get_capacity()); + this->limit_ = limit; +} +void ByteBuffer::set_position(size_t position) { + assert(position <= this->get_limit()); + this->position_ = position; +} +void ByteBuffer::clear() { + this->limit_ = this->get_capacity(); + this->position_ = 0; +} +uint16_t ByteBuffer::get_uint16() { + assert(this->get_remaining() >= 2); + uint16_t value; + if (endianness_ == LITTLE) { + value = this->data_[this->position_++]; + value |= this->data_[this->position_++] << 8; + } else { + value = this->data_[this->position_++] << 8; + value |= this->data_[this->position_++]; + } + return value; +} + +uint32_t ByteBuffer::get_uint32() { + assert(this->get_remaining() >= 4); + uint32_t value; + if (endianness_ == LITTLE) { + value = this->data_[this->position_++]; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++] << 16; + value |= this->data_[this->position_++] << 24; + } else { + value = this->data_[this->position_++] << 24; + value |= this->data_[this->position_++] << 16; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++]; + } + return value; +} +uint32_t ByteBuffer::get_uint24() { + assert(this->get_remaining() >= 3); + uint32_t value; + if (endianness_ == LITTLE) { + value = this->data_[this->position_++]; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++] << 16; + } else { + value = this->data_[this->position_++] << 16; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++]; + } + return value; +} +uint32_t ByteBuffer::get_int24() { + auto value = this->get_uint24(); + uint32_t mask = (~(uint32_t) 0) << 23; + if ((value & mask) != 0) + value |= mask; + return value; +} +uint8_t ByteBuffer::get_uint8() { + assert(this->get_remaining() >= 1); + return this->data_[this->position_++]; +} +float ByteBuffer::get_float() { + auto value = this->get_uint32(); + return *(float *) &value; +} +void ByteBuffer::put_uint8(uint8_t value) { + assert(this->get_remaining() >= 1); + this->data_[this->position_++] = value; +} + +void ByteBuffer::put_uint16(uint16_t value) { + assert(this->get_remaining() >= 2); + if (this->endianness_ == LITTLE) { + this->data_[this->position_++] = (uint8_t) value; + this->data_[this->position_++] = (uint8_t) (value >> 8); + } else { + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) value; + } +} +void ByteBuffer::put_uint24(uint32_t value) { + assert(this->get_remaining() >= 3); + if (this->endianness_ == LITTLE) { + this->data_[this->position_++] = (uint8_t) value; + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) (value >> 16); + } else { + this->data_[this->position_++] = (uint8_t) (value >> 16); + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) value; + } +} +void ByteBuffer::put_uint32(uint32_t value) { + assert(this->get_remaining() >= 4); + if (this->endianness_ == LITTLE) { + this->data_[this->position_++] = (uint8_t) value; + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) (value >> 16); + this->data_[this->position_++] = (uint8_t) (value >> 24); + } else { + this->data_[this->position_++] = (uint8_t) (value >> 24); + this->data_[this->position_++] = (uint8_t) (value >> 16); + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) value; + } +} +void ByteBuffer::put_float(float value) { this->put_uint32(*(uint32_t *) &value); } +void ByteBuffer::flip() { + this->limit_ = this->position_; + this->position_ = 0; +} +} // namespace esphome diff --git a/esphome/core/bytebuffer.h b/esphome/core/bytebuffer.h new file mode 100644 index 0000000000..f242e5e333 --- /dev/null +++ b/esphome/core/bytebuffer.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include + +namespace esphome { + +enum Endian { LITTLE, BIG }; + +/** + * A class modelled on the Java ByteBuffer class. It wraps a vector of bytes and permits putting and getting + * items of various sizes, with an automatically incremented position. + * + * There are three variables maintained pointing into the buffer: + * + * 0 <= position <= limit <= capacity + * + * capacity: the maximum amount of data that can be stored + * limit: the limit of the data currently available to get or put + * position: the current insert or extract position + * + * In addition a mark can be set to the current position with mark(). A subsequent call to reset() will restore + * the position to the mark. + * + * The buffer can be marked to be little-endian (default) or big-endian. All subsequent operations will use that order. + * + */ +class ByteBuffer { + public: + /** + * Create a new Bytebuffer with the given capacity + */ + static ByteBuffer create(size_t capacity); + /** + * Wrap an existing vector in a Bytebufffer + */ + static ByteBuffer wrap(std::vector data); + /** + * Wrap an existing array in a Bytebufffer + */ + static ByteBuffer wrap(uint8_t *ptr, size_t len); + + // Get one byte from the buffer, increment position by 1 + uint8_t get_uint8(); + // Get a 16 bit unsigned value, increment by 2 + uint16_t get_uint16(); + // Get a 24 bit unsigned value, increment by 3 + uint32_t get_uint24(); + // Get a 32 bit unsigned value, increment by 4 + uint32_t get_uint32(); + // signed versions of the get functions + uint8_t get_int8() { return (int8_t) this->get_uint8(); }; + int16_t get_int16() { return (int16_t) this->get_uint16(); } + uint32_t get_int24(); + int32_t get_int32() { return (int32_t) this->get_uint32(); } + // Get a float value, increment by 4 + float get_float(); + + // put values into the buffer, increment the position accordingly + void put_uint8(uint8_t value); + void put_uint16(uint16_t value); + void put_uint24(uint32_t value); + void put_uint32(uint32_t value); + void put_float(float value); + + inline size_t get_capacity() const { return this->data_.size(); } + inline size_t get_position() const { return this->position_; } + inline size_t get_limit() const { return this->limit_; } + inline size_t get_remaining() const { return this->get_limit() - this->get_position(); } + inline Endian get_endianness() const { return this->endianness_; } + inline void mark() { this->mark_ = this->position_; } + inline void big_endian() { this->endianness_ = BIG; } + inline void little_endian() { this->endianness_ = LITTLE; } + void set_limit(size_t limit); + void set_position(size_t position); + // set position to 0, limit to capacity. + void clear(); + // set limit to current position, postition to zero. Used when swapping from write to read operations. + void flip(); + // retrieve a pointer to the underlying data. + uint8_t *array() { return this->data_.data(); }; + void rewind() { this->position_ = 0; } + void reset() { this->position_ = this->mark_; } + + protected: + ByteBuffer(std::vector data) : data_(std::move(data)) { this->limit_ = this->get_capacity(); } + std::vector data_; + Endian endianness_{LITTLE}; + size_t position_{0}; + size_t mark_{0}; + size_t limit_{0}; +}; + +} // namespace esphome From c5b1a8eb81c4187c3c0f7ca4da40232425845113 Mon Sep 17 00:00:00 2001 From: PaoloTK <60204407+PaoloTK@users.noreply.github.com> Date: Tue, 13 Aug 2024 23:29:55 +0200 Subject: [PATCH 2221/2607] Add min and max brightness parameters for Light dim_relative Action (#6971) --- esphome/components/light/automation.h | 17 ++++++++++++++- esphome/components/light/automation.py | 21 +++++++++++++++++++ esphome/components/light/types.py | 7 +++++++ esphome/const.py | 2 ++ tests/components/light/test.esp32-ard.yaml | 2 ++ tests/components/light/test.esp32-c3-ard.yaml | 2 ++ tests/components/light/test.esp32-c3-idf.yaml | 2 ++ tests/components/light/test.esp32-idf.yaml | 2 ++ tests/components/light/test.esp8266-ard.yaml | 2 ++ tests/components/light/test.rp2040-ard.yaml | 2 ++ 10 files changed, 58 insertions(+), 1 deletion(-) diff --git a/esphome/components/light/automation.h b/esphome/components/light/automation.h index b63fc93dc5..6e055741da 100644 --- a/esphome/components/light/automation.h +++ b/esphome/components/light/automation.h @@ -7,6 +7,8 @@ namespace esphome { namespace light { +enum class LimitMode { CLAMP, DO_NOTHING }; + template class ToggleAction : public Action { public: explicit ToggleAction(LightState *state) : state_(state) {} @@ -77,7 +79,10 @@ template class DimRelativeAction : public Action { float rel = this->relative_brightness_.value(x...); float cur; this->parent_->remote_values.as_brightness(&cur); - float new_brightness = clamp(cur + rel, 0.0f, 1.0f); + if ((limit_mode_ == LimitMode::DO_NOTHING) && ((cur < min_brightness_) || (cur > max_brightness_))) { + return; + } + float new_brightness = clamp(cur + rel, min_brightness_, max_brightness_); call.set_state(new_brightness != 0.0f); call.set_brightness(new_brightness); @@ -85,8 +90,18 @@ template class DimRelativeAction : public Action { call.perform(); } + void set_min_max_brightness(float min, float max) { + this->min_brightness_ = min; + this->max_brightness_ = max; + } + + void set_limit_mode(LimitMode limit_mode) { this->limit_mode_ = limit_mode; } + protected: LightState *parent_; + float min_brightness_{0.0}; + float max_brightness_{1.0}; + LimitMode limit_mode_{LimitMode::CLAMP}; }; template class LightIsOnCondition : public Condition { diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py index cfba273565..ec0375f54a 100644 --- a/esphome/components/light/automation.py +++ b/esphome/components/light/automation.py @@ -19,10 +19,15 @@ from esphome.const import ( CONF_WARM_WHITE, CONF_RANGE_FROM, CONF_RANGE_TO, + CONF_BRIGHTNESS_LIMITS, + CONF_LIMIT_MODE, + CONF_MIN_BRIGHTNESS, + CONF_MAX_BRIGHTNESS, ) from .types import ( ColorMode, COLOR_MODES, + LIMIT_MODES, DimRelativeAction, ToggleAction, LightState, @@ -167,6 +172,15 @@ LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema( cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable( cv.positive_time_period_milliseconds ), + cv.Optional(CONF_BRIGHTNESS_LIMITS): cv.Schema( + { + cv.Optional(CONF_MIN_BRIGHTNESS, default="0%"): cv.percentage, + cv.Optional(CONF_MAX_BRIGHTNESS, default="100%"): cv.percentage, + cv.Optional(CONF_LIMIT_MODE, default="CLAMP"): cv.enum( + LIMIT_MODES, upper=True, space="_" + ), + } + ), } ) @@ -182,6 +196,13 @@ async def light_dim_relative_to_code(config, action_id, template_arg, args): if CONF_TRANSITION_LENGTH in config: templ = await cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32) cg.add(var.set_transition_length(templ)) + if conf := config.get(CONF_BRIGHTNESS_LIMITS): + cg.add( + var.set_min_max_brightness( + conf[CONF_MIN_BRIGHTNESS], conf[CONF_MAX_BRIGHTNESS] + ) + ) + cg.add(var.set_limit_mode(conf[CONF_LIMIT_MODE])) return var diff --git a/esphome/components/light/types.py b/esphome/components/light/types.py index a453debd94..64483bcc9c 100644 --- a/esphome/components/light/types.py +++ b/esphome/components/light/types.py @@ -26,6 +26,13 @@ COLOR_MODES = { "RGB_COLD_WARM_WHITE": ColorMode.RGB_COLD_WARM_WHITE, } +# Limit modes +LimitMode = light_ns.enum("LimitMode", is_class=True) +LIMIT_MODES = { + "CLAMP": LimitMode.CLAMP, + "DO_NOTHING": LimitMode.DO_NOTHING, +} + # Actions ToggleAction = light_ns.class_("ToggleAction", automation.Action) LightControlAction = light_ns.class_("LightControlAction", automation.Action) diff --git a/esphome/const.py b/esphome/const.py index 55f1c23b40..37f20796b5 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -95,6 +95,7 @@ CONF_BOARD_FLASH_MODE = "board_flash_mode" CONF_BORDER = "border" CONF_BRANCH = "branch" CONF_BRIGHTNESS = "brightness" +CONF_BRIGHTNESS_LIMITS = "brightness_limits" CONF_BROKER = "broker" CONF_BSSID = "bssid" CONF_BUFFER_SIZE = "buffer_size" @@ -429,6 +430,7 @@ CONF_LIGHT = "light" CONF_LIGHT_ID = "light_id" CONF_LIGHTNING_ENERGY = "lightning_energy" CONF_LIGHTNING_THRESHOLD = "lightning_threshold" +CONF_LIMIT_MODE = "limit_mode" CONF_LINE_THICKNESS = "line_thickness" CONF_LINE_TYPE = "line_type" CONF_LOADED_INTEGRATIONS = "loaded_integrations" diff --git a/tests/components/light/test.esp32-ard.yaml b/tests/components/light/test.esp32-ard.yaml index 7e5718d8d4..1d0b4cd8f0 100644 --- a/tests/components/light/test.esp32-ard.yaml +++ b/tests/components/light/test.esp32-ard.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio diff --git a/tests/components/light/test.esp32-c3-ard.yaml b/tests/components/light/test.esp32-c3-ard.yaml index 8e1709838a..79171805a6 100644 --- a/tests/components/light/test.esp32-c3-ard.yaml +++ b/tests/components/light/test.esp32-c3-ard.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio diff --git a/tests/components/light/test.esp32-c3-idf.yaml b/tests/components/light/test.esp32-c3-idf.yaml index 8e1709838a..79171805a6 100644 --- a/tests/components/light/test.esp32-c3-idf.yaml +++ b/tests/components/light/test.esp32-c3-idf.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio diff --git a/tests/components/light/test.esp32-idf.yaml b/tests/components/light/test.esp32-idf.yaml index 7e5718d8d4..1d0b4cd8f0 100644 --- a/tests/components/light/test.esp32-idf.yaml +++ b/tests/components/light/test.esp32-idf.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio diff --git a/tests/components/light/test.esp8266-ard.yaml b/tests/components/light/test.esp8266-ard.yaml index 4611fb374a..555e1a1b67 100644 --- a/tests/components/light/test.esp8266-ard.yaml +++ b/tests/components/light/test.esp8266-ard.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio diff --git a/tests/components/light/test.rp2040-ard.yaml b/tests/components/light/test.rp2040-ard.yaml index 0215a17e71..a509bc85c9 100644 --- a/tests/components/light/test.rp2040-ard.yaml +++ b/tests/components/light/test.rp2040-ard.yaml @@ -15,6 +15,8 @@ esphome: - light.dim_relative: id: test_monochromatic_light relative_brightness: 5% + brightness_limits: + max_brightness: 90% output: - platform: gpio From 1d25db491c26b7400a8483ab2199fa8d05badfbc Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Wed, 14 Aug 2024 04:03:12 +0200 Subject: [PATCH 2222/2607] [homeassistant] Native switch entity import and control (#7018) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../homeassistant/switch/__init__.py | 30 ++++++++++ .../switch/homeassistant_switch.cpp | 59 +++++++++++++++++++ .../switch/homeassistant_switch.h | 22 +++++++ tests/components/homeassistant/common.yaml | 5 ++ 5 files changed, 117 insertions(+) create mode 100644 esphome/components/homeassistant/switch/__init__.py create mode 100644 esphome/components/homeassistant/switch/homeassistant_switch.cpp create mode 100644 esphome/components/homeassistant/switch/homeassistant_switch.h diff --git a/CODEOWNERS b/CODEOWNERS index 663a942cb4..0c36cda527 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -169,6 +169,7 @@ esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hm3301/* @freekode esphome/components/homeassistant/* @OttoWinter @esphome/core +esphome/components/homeassistant/switch/* @Links2004 esphome/components/honeywell_hih_i2c/* @Benichou34 esphome/components/honeywellabp/* @RubyBailey esphome/components/honeywellabp2_i2c/* @jpfaff diff --git a/esphome/components/homeassistant/switch/__init__.py b/esphome/components/homeassistant/switch/__init__.py new file mode 100644 index 0000000000..3d7c80682a --- /dev/null +++ b/esphome/components/homeassistant/switch/__init__.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import CONF_ID + +from .. import ( + HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA, + homeassistant_ns, + setup_home_assistant_entity, +) + +CODEOWNERS = ["@Links2004"] +DEPENDENCIES = ["api"] + +HomeassistantSwitch = homeassistant_ns.class_( + "HomeassistantSwitch", switch.Switch, cg.Component +) + +CONFIG_SCHEMA = ( + switch.switch_schema(HomeassistantSwitch) + .extend(cv.COMPONENT_SCHEMA) + .extend(HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await switch.register_switch(var, config) + setup_home_assistant_entity(var, config) diff --git a/esphome/components/homeassistant/switch/homeassistant_switch.cpp b/esphome/components/homeassistant/switch/homeassistant_switch.cpp new file mode 100644 index 0000000000..05ef46e30e --- /dev/null +++ b/esphome/components/homeassistant/switch/homeassistant_switch.cpp @@ -0,0 +1,59 @@ +#include "homeassistant_switch.h" +#include "esphome/components/api/api_server.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace homeassistant { + +static const char *const TAG = "homeassistant.switch"; + +using namespace esphome::switch_; + +void HomeassistantSwitch::setup() { + api::global_api_server->subscribe_home_assistant_state(this->entity_id_, nullopt, [this](const std::string &state) { + auto val = parse_on_off(state.c_str()); + switch (val) { + case PARSE_NONE: + case PARSE_TOGGLE: + ESP_LOGW(TAG, "Can't convert '%s' to binary state!", state.c_str()); + break; + case PARSE_ON: + case PARSE_OFF: + bool new_state = val == PARSE_ON; + ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_.c_str(), ONOFF(new_state)); + this->publish_state(new_state); + break; + } + }); +} + +void HomeassistantSwitch::dump_config() { + LOG_SWITCH("", "Homeassistant Switch", this); + ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); +} + +float HomeassistantSwitch::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } + +void HomeassistantSwitch::write_state(bool state) { + if (!api::global_api_server->is_connected()) { + ESP_LOGE(TAG, "No clients connected to API server"); + return; + } + + api::HomeassistantServiceResponse resp; + if (state) { + resp.service = "switch.turn_on"; + } else { + resp.service = "switch.turn_off"; + } + + api::HomeassistantServiceMap entity_id_kv; + entity_id_kv.key = "entity_id"; + entity_id_kv.value = this->entity_id_; + resp.data.push_back(entity_id_kv); + + api::global_api_server->send_homeassistant_service_call(resp); +} + +} // namespace homeassistant +} // namespace esphome diff --git a/esphome/components/homeassistant/switch/homeassistant_switch.h b/esphome/components/homeassistant/switch/homeassistant_switch.h new file mode 100644 index 0000000000..a4da257960 --- /dev/null +++ b/esphome/components/homeassistant/switch/homeassistant_switch.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace homeassistant { + +class HomeassistantSwitch : public switch_::Switch, public Component { + public: + void set_entity_id(const std::string &entity_id) { this->entity_id_ = entity_id; } + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + + protected: + void write_state(bool state) override; + std::string entity_id_; +}; + +} // namespace homeassistant +} // namespace esphome diff --git a/tests/components/homeassistant/common.yaml b/tests/components/homeassistant/common.yaml index 07a6e8090c..2b2805d06e 100644 --- a/tests/components/homeassistant/common.yaml +++ b/tests/components/homeassistant/common.yaml @@ -32,6 +32,11 @@ wifi: api: +switch: + - platform: homeassistant + entity_id: switch.my_cool_switch + id: my_cool_switch + binary_sensor: - platform: homeassistant entity_id: binary_sensor.hello_world From a5fdcb31fc56d928aa7a3b340829970f6ce0bbc0 Mon Sep 17 00:00:00 2001 From: Landon Rohatensky Date: Tue, 13 Aug 2024 19:04:12 -0700 Subject: [PATCH 2223/2607] [homeassistant] Native number entity import and control (#6455) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../homeassistant/number/__init__.py | 33 ++++++ .../number/homeassistant_number.cpp | 100 ++++++++++++++++++ .../number/homeassistant_number.h | 31 ++++++ tests/components/homeassistant/common.yaml | 5 + 5 files changed, 170 insertions(+) create mode 100644 esphome/components/homeassistant/number/__init__.py create mode 100644 esphome/components/homeassistant/number/homeassistant_number.cpp create mode 100644 esphome/components/homeassistant/number/homeassistant_number.h diff --git a/CODEOWNERS b/CODEOWNERS index 0c36cda527..3ea9c75ac2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -169,6 +169,7 @@ esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hm3301/* @freekode esphome/components/homeassistant/* @OttoWinter @esphome/core +esphome/components/homeassistant/number/* @landonr esphome/components/homeassistant/switch/* @Links2004 esphome/components/honeywell_hih_i2c/* @Benichou34 esphome/components/honeywellabp/* @RubyBailey diff --git a/esphome/components/homeassistant/number/__init__.py b/esphome/components/homeassistant/number/__init__.py new file mode 100644 index 0000000000..a6cc615a64 --- /dev/null +++ b/esphome/components/homeassistant/number/__init__.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +from esphome.components import number +import esphome.config_validation as cv + +from .. import ( + HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA, + homeassistant_ns, + setup_home_assistant_entity, +) + +CODEOWNERS = ["@landonr"] +DEPENDENCIES = ["api"] + +HomeassistantNumber = homeassistant_ns.class_( + "HomeassistantNumber", number.Number, cg.Component +) + +CONFIG_SCHEMA = ( + number.number_schema(HomeassistantNumber) + .extend(HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = await number.new_number( + config, + min_value=0, + max_value=0, + step=0, + ) + await cg.register_component(var, config) + setup_home_assistant_entity(var, config) diff --git a/esphome/components/homeassistant/number/homeassistant_number.cpp b/esphome/components/homeassistant/number/homeassistant_number.cpp new file mode 100644 index 0000000000..d3e285f4ac --- /dev/null +++ b/esphome/components/homeassistant/number/homeassistant_number.cpp @@ -0,0 +1,100 @@ +#include "homeassistant_number.h" + +#include "esphome/components/api/api_pb2.h" +#include "esphome/components/api/api_server.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace homeassistant { + +static const char *const TAG = "homeassistant.number"; + +void HomeassistantNumber::state_changed_(const std::string &state) { + auto number_value = parse_number(state); + if (!number_value.has_value()) { + ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_.c_str(), state.c_str()); + this->publish_state(NAN); + return; + } + if (this->state == number_value.value()) { + return; + } + ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_.c_str(), state.c_str()); + this->publish_state(number_value.value()); +} + +void HomeassistantNumber::min_retrieved_(const std::string &min) { + auto min_value = parse_number(min); + if (!min_value.has_value()) { + ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_.c_str(), min.c_str()); + } + ESP_LOGD(TAG, "'%s': Min retrieved: %s", get_name().c_str(), min.c_str()); + this->traits.set_min_value(min_value.value()); +} + +void HomeassistantNumber::max_retrieved_(const std::string &max) { + auto max_value = parse_number(max); + if (!max_value.has_value()) { + ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_.c_str(), max.c_str()); + } + ESP_LOGD(TAG, "'%s': Max retrieved: %s", get_name().c_str(), max.c_str()); + this->traits.set_max_value(max_value.value()); +} + +void HomeassistantNumber::step_retrieved_(const std::string &step) { + auto step_value = parse_number(step); + if (!step_value.has_value()) { + ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_.c_str(), step.c_str()); + } + ESP_LOGD(TAG, "'%s': Step Retrieved %s", get_name().c_str(), step.c_str()); + this->traits.set_step(step_value.value()); +} + +void HomeassistantNumber::setup() { + api::global_api_server->subscribe_home_assistant_state( + this->entity_id_, nullopt, std::bind(&HomeassistantNumber::state_changed_, this, std::placeholders::_1)); + + api::global_api_server->get_home_assistant_state( + this->entity_id_, optional("min"), + std::bind(&HomeassistantNumber::min_retrieved_, this, std::placeholders::_1)); + api::global_api_server->get_home_assistant_state( + this->entity_id_, optional("max"), + std::bind(&HomeassistantNumber::max_retrieved_, this, std::placeholders::_1)); + api::global_api_server->get_home_assistant_state( + this->entity_id_, optional("step"), + std::bind(&HomeassistantNumber::step_retrieved_, this, std::placeholders::_1)); +} + +void HomeassistantNumber::dump_config() { + LOG_NUMBER("", "Homeassistant Number", this); + ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); +} + +float HomeassistantNumber::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } + +void HomeassistantNumber::control(float value) { + if (!api::global_api_server->is_connected()) { + ESP_LOGE(TAG, "No clients connected to API server"); + return; + } + + this->publish_state(value); + + api::HomeassistantServiceResponse resp; + resp.service = "number.set_value"; + + api::HomeassistantServiceMap entity_id; + entity_id.key = "entity_id"; + entity_id.value = this->entity_id_; + resp.data.push_back(entity_id); + + api::HomeassistantServiceMap entity_value; + entity_value.key = "value"; + entity_value.value = to_string(value); + resp.data.push_back(entity_value); + + api::global_api_server->send_homeassistant_service_call(resp); +} + +} // namespace homeassistant +} // namespace esphome diff --git a/esphome/components/homeassistant/number/homeassistant_number.h b/esphome/components/homeassistant/number/homeassistant_number.h new file mode 100644 index 0000000000..0860b4e91c --- /dev/null +++ b/esphome/components/homeassistant/number/homeassistant_number.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "esphome/components/number/number.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace homeassistant { + +class HomeassistantNumber : public number::Number, public Component { + public: + void set_entity_id(const std::string &entity_id) { this->entity_id_ = entity_id; } + + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + + protected: + void state_changed_(const std::string &state); + void min_retrieved_(const std::string &min); + void max_retrieved_(const std::string &max); + void step_retrieved_(const std::string &step); + + void control(float value) override; + + std::string entity_id_; +}; +} // namespace homeassistant +} // namespace esphome diff --git a/tests/components/homeassistant/common.yaml b/tests/components/homeassistant/common.yaml index 2b2805d06e..8c9a4ad75f 100644 --- a/tests/components/homeassistant/common.yaml +++ b/tests/components/homeassistant/common.yaml @@ -46,6 +46,11 @@ binary_sensor: attribute: world id: ha_hello_world_binary_attribute +number: + - platform: homeassistant + entity_id: number.hello_world + id: ha_hello_world_number + sensor: - platform: homeassistant entity_id: sensor.hello_world From a0eff08f39c69059d74929e6c91b8b61fb7ee51f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:05:25 +1000 Subject: [PATCH 2224/2607] [lvgl] Rework events to avoid feedback loops (#7262) --- esphome/components/lvgl/automation.py | 4 +-- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/light/lvgl_light.h | 2 +- esphome/components/lvgl/lvcode.py | 6 ++++- esphome/components/lvgl/lvgl_esphome.cpp | 15 +++++++---- esphome/components/lvgl/lvgl_esphome.h | 5 +++- esphome/components/lvgl/number/__init__.py | 22 +++++++++++++--- esphome/components/lvgl/select/__init__.py | 13 ++++++++-- esphome/components/lvgl/sensor/__init__.py | 16 ++++++++++-- esphome/components/lvgl/switch/__init__.py | 6 +++-- esphome/components/lvgl/text/__init__.py | 17 ++++++++++--- .../components/lvgl/text_sensor/__init__.py | 4 ++- esphome/components/lvgl/trigger.py | 25 +++++++++++++++---- tests/components/lvgl/common.yaml | 1 + 14 files changed, 108 insertions(+), 29 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index 556e286208..a39f589136 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -17,6 +17,7 @@ from .defines import ( from .lv_validation import lv_bool, lv_color, lv_image from .lvcode import ( LVGL_COMP_ARG, + UPDATE_EVENT, LambdaContext, LocalVariable, LvConditional, @@ -30,7 +31,6 @@ from .lvcode import ( ) from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA from .types import ( - LV_EVENT, LV_STATE, LvglAction, LvglCondition, @@ -64,7 +64,7 @@ async def update_to_code(config, action_id, template_arg, args): widget.type.w_type.value_property is not None and widget.type.w_type.value_property in config ): - lv.event_send(widget.obj, LV_EVENT.VALUE_CHANGED, nullptr) + lv.event_send(widget.obj, UPDATE_EVENT, nullptr) widgets = await get_widgets(config[CONF_ID]) return await action_to_code(widgets, do_update, action_id, template_arg, args) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index e48679996b..8f7a973722 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -470,6 +470,7 @@ CONF_TOP_LAYER = "top_layer" CONF_TOUCHSCREENS = "touchscreens" CONF_TRANSPARENCY_KEY = "transparency_key" CONF_THEME = "theme" +CONF_UPDATE_ON_RELEASE = "update_on_release" CONF_VISIBLE_ROW_COUNT = "visible_row_count" CONF_WIDGET = "widget" CONF_WIDGETS = "widgets" diff --git a/esphome/components/lvgl/light/lvgl_light.h b/esphome/components/lvgl/light/lvgl_light.h index 67372d89dd..50ae4c5327 100644 --- a/esphome/components/lvgl/light/lvgl_light.h +++ b/esphome/components/lvgl/light/lvgl_light.h @@ -38,7 +38,7 @@ class LVLight : public light::LightOutput { void set_value_(lv_color_t value) { lv_led_set_color(this->obj_, value); lv_led_on(this->obj_); - lv_event_send(this->obj_, lv_custom_event, nullptr); + lv_event_send(this->obj_, lv_api_event, nullptr); } lv_obj_t *obj_{}; optional initial_value_{}; diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index f54a032de2..6d7e364e5d 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -29,7 +29,11 @@ LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) LVGL_COMP_ARG = [(LvglComponent.operator("ptr"), LVGL_COMP)] lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") EVENT_ARG = [(lv_event_t_ptr, "ev")] -CUSTOM_EVENT = literal("lvgl::lv_custom_event") +# Two custom events; API_EVENT is fired when an entity is updated remotely by an API interaction; +# UPDATE_EVENT is fired when an entity is programmatically updated locally. +# VALUE_CHANGED is the event generated by LVGL when an entity's value changes through user interaction. +API_EVENT = literal("lvgl::lv_api_event") +UPDATE_EVENT = literal("lvgl::lv_update_event") def get_line_marks(value) -> list: diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 6f23c2421b..92f7a880c3 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -27,7 +27,8 @@ static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { area->y2++; } -lv_event_code_t lv_custom_event; // NOLINT +lv_event_code_t lv_api_event; // NOLINT +lv_event_code_t lv_update_event; // NOLINT void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); } void LvglComponent::set_paused(bool paused, bool show_snow) { this->paused_ = paused; @@ -40,15 +41,18 @@ void LvglComponent::set_paused(bool paused, bool show_snow) { } void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) { lv_obj_add_event_cb(obj, callback, event, this); - if (event == LV_EVENT_VALUE_CHANGED) { - lv_obj_add_event_cb(obj, callback, lv_custom_event, this); - } } void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2) { this->add_event_cb(obj, callback, event1); this->add_event_cb(obj, callback, event2); } +void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, + lv_event_code_t event2, lv_event_code_t event3) { + this->add_event_cb(obj, callback, event1); + this->add_event_cb(obj, callback, event2); + this->add_event_cb(obj, callback, event3); +} void LvglComponent::add_page(LvPageType *page) { this->pages_.push_back(page); page->setup(this->pages_.size() - 1); @@ -228,7 +232,8 @@ void LvglComponent::setup() { lv_log_register_print_cb(log_cb); #endif lv_init(); - lv_custom_event = static_cast(lv_event_register_id()); + lv_update_event = static_cast(lv_event_register_id()); + lv_api_event = static_cast(lv_event_register_id()); auto *display = this->displays_[0]; size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_; auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 1497e1004a..3a3d1aa6c5 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -38,7 +38,8 @@ namespace esphome { namespace lvgl { -extern lv_event_code_t lv_custom_event; // NOLINT +extern lv_event_code_t lv_api_event; // NOLINT +extern lv_event_code_t lv_update_event; // NOLINT #ifdef USE_LVGL_COLOR inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } #endif // USE_LVGL_COLOR @@ -133,6 +134,8 @@ class LvglComponent : public PollingComponent { void set_paused(bool paused, bool show_snow); void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event); void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2); + void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2, + lv_event_code_t event3); bool is_paused() const { return this->paused_; } void add_page(LvPageType *page); void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time); diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index 53aef2790d..6336bb0632 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -3,9 +3,17 @@ from esphome.components import number import esphome.config_validation as cv from esphome.cpp_generator import MockObj -from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET +from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_UPDATE_ON_RELEASE, CONF_WIDGET from ..lv_validation import animated -from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..lvcode import ( + API_EVENT, + EVENT_ARG, + UPDATE_EVENT, + LambdaContext, + LvContext, + lv, + lv_add, +) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber, lvgl_ns from ..widgets import get_widgets @@ -19,6 +27,7 @@ CONFIG_SCHEMA = ( { cv.Required(CONF_WIDGET): cv.use_id(LvNumber), cv.Optional(CONF_ANIMATED, default=True): animated, + cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean, } ) ) @@ -39,14 +48,19 @@ async def to_code(config): await widget.set_property( "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] ) - lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + lv.event_send(widget.obj, API_EVENT, cg.nullptr) async with LambdaContext(EVENT_ARG) as event: event.add(var.publish_state(widget.get_value())) + event_code = ( + LV_EVENT.VALUE_CHANGED + if not config[CONF_UPDATE_ON_RELEASE] + else LV_EVENT.RELEASED + ) async with LvContext(paren): lv_add(var.set_control_lambda(await control.get_lambda())) lv_add( paren.add_event_cb( - widget.obj, await event.get_lambda(), LV_EVENT.VALUE_CHANGED + widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code ) ) lv_add(var.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index 34a70a23f7..b55bde13bc 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -4,7 +4,15 @@ import esphome.config_validation as cv from esphome.const import CONF_OPTIONS from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET -from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..lvcode import ( + API_EVENT, + EVENT_ARG, + UPDATE_EVENT, + LambdaContext, + LvContext, + lv, + lv_add, +) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvSelect, lvgl_ns from ..widgets import get_widgets @@ -33,7 +41,7 @@ async def to_code(config): pub_ctx.add(selector.publish_index(widget.get_value())) async with LambdaContext([(cg.uint16, "v")]) as control: await widget.set_property("selected", "v", animated=config[CONF_ANIMATED]) - lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + lv.event_send(widget.obj, API_EVENT, cg.nullptr) async with LvContext(paren) as ctx: lv_add(selector.set_control_lambda(await control.get_lambda())) ctx.add( @@ -41,6 +49,7 @@ async def to_code(config): widget.obj, await pub_ctx.get_lambda(), LV_EVENT.VALUE_CHANGED, + UPDATE_EVENT, ) ) lv_add(selector.publish_index(widget.get_value())) diff --git a/esphome/components/lvgl/sensor/__init__.py b/esphome/components/lvgl/sensor/__init__.py index 6e495eb685..82e21d5e95 100644 --- a/esphome/components/lvgl/sensor/__init__.py +++ b/esphome/components/lvgl/sensor/__init__.py @@ -3,7 +3,15 @@ from esphome.components.sensor import Sensor, new_sensor, sensor_schema import esphome.config_validation as cv from ..defines import CONF_LVGL_ID, CONF_WIDGET -from ..lvcode import EVENT_ARG, LVGL_COMP_ARG, LambdaContext, LvContext, lv_add +from ..lvcode import ( + API_EVENT, + EVENT_ARG, + LVGL_COMP_ARG, + UPDATE_EVENT, + LambdaContext, + LvContext, + lv_add, +) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber from ..widgets import Widget, get_widgets @@ -30,6 +38,10 @@ async def to_code(config): async with LvContext(paren, LVGL_COMP_ARG): lv_add( paren.add_event_cb( - widget.obj, await lamb.get_lambda(), LV_EVENT.VALUE_CHANGED + widget.obj, + await lamb.get_lambda(), + LV_EVENT.VALUE_CHANGED, + API_EVENT, + UPDATE_EVENT, ) ) diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index 831fa9308b..957fce17ff 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -5,8 +5,9 @@ from esphome.cpp_generator import MockObj from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import ( - CUSTOM_EVENT, + API_EVENT, EVENT_ARG, + UPDATE_EVENT, LambdaContext, LvConditional, LvContext, @@ -41,7 +42,7 @@ async def to_code(config): widget.add_state(LV_STATE.CHECKED) cond.else_() widget.clear_state(LV_STATE.CHECKED) - lv.event_send(widget.obj, CUSTOM_EVENT, cg.nullptr) + lv.event_send(widget.obj, API_EVENT, cg.nullptr) async with LvContext(paren) as ctx: lv_add(switch.set_control_lambda(await control.get_lambda())) ctx.add( @@ -49,6 +50,7 @@ async def to_code(config): widget.obj, await checked_ctx.get_lambda(), LV_EVENT.VALUE_CHANGED, + UPDATE_EVENT, ) ) lv_add(switch.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 55f1b2b3fc..9ee494d8a0 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -4,7 +4,15 @@ from esphome.components.text import new_text import esphome.config_validation as cv from ..defines import CONF_LVGL_ID, CONF_WIDGET -from ..lvcode import CUSTOM_EVENT, EVENT_ARG, LambdaContext, LvContext, lv, lv_add +from ..lvcode import ( + API_EVENT, + EVENT_ARG, + UPDATE_EVENT, + LambdaContext, + LvContext, + lv, + lv_add, +) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText, lvgl_ns from ..widgets import get_widgets @@ -26,14 +34,17 @@ async def to_code(config): widget = widget[0] async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str())") - lv.event_send(widget.obj, CUSTOM_EVENT, None) + lv.event_send(widget.obj, API_EVENT, None) async with LambdaContext(EVENT_ARG) as lamb: lv_add(textvar.publish_state(widget.get_value())) async with LvContext(paren): widget.var.set_control_lambda(await control.get_lambda()) lv_add( paren.add_event_cb( - widget.obj, await lamb.get_lambda(), LV_EVENT.VALUE_CHANGED + widget.obj, + await lamb.get_lambda(), + LV_EVENT.VALUE_CHANGED, + UPDATE_EVENT, ) ) lv_add(textvar.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/text_sensor/__init__.py b/esphome/components/lvgl/text_sensor/__init__.py index c0f0bc36a8..cab715dce0 100644 --- a/esphome/components/lvgl/text_sensor/__init__.py +++ b/esphome/components/lvgl/text_sensor/__init__.py @@ -7,7 +7,7 @@ from esphome.components.text_sensor import ( import esphome.config_validation as cv from ..defines import CONF_LVGL_ID, CONF_WIDGET -from ..lvcode import EVENT_ARG, LambdaContext, LvContext +from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText from ..widgets import get_widgets @@ -36,5 +36,7 @@ async def to_code(config): widget.obj, await pressed_ctx.get_lambda(), LV_EVENT.VALUE_CHANGED, + API_EVENT, + UPDATE_EVENT, ) ) diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index df87be718b..ba93aabb2d 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -11,7 +11,15 @@ from .defines import ( LV_EVENT_TRIGGERS, literal, ) -from .lvcode import EVENT_ARG, LambdaContext, LvConditional, lv, lv_add +from .lvcode import ( + API_EVENT, + EVENT_ARG, + UPDATE_EVENT, + LambdaContext, + LvConditional, + lv, + lv_add, +) from .types import LV_EVENT from .widgets import widget_map @@ -34,9 +42,16 @@ async def generate_triggers(lv_component): conf = conf[0] w.add_flag("LV_OBJ_FLAG_CLICKABLE") event = literal("LV_EVENT_" + LV_EVENT_MAP[event[3:].upper()]) - await add_trigger(conf, event, lv_component, w) + await add_trigger(conf, lv_component, w, event) for conf in w.config.get(CONF_ON_VALUE, ()): - await add_trigger(conf, LV_EVENT.VALUE_CHANGED, lv_component, w) + await add_trigger( + conf, + lv_component, + w, + LV_EVENT.VALUE_CHANGED, + API_EVENT, + UPDATE_EVENT, + ) # Generate align to directives while we're here if align_to := w.config.get(CONF_ALIGN_TO): @@ -47,7 +62,7 @@ async def generate_triggers(lv_component): lv.obj_align_to(w.obj, target, align, x, y) -async def add_trigger(conf, event, lv_component, w): +async def add_trigger(conf, lv_component, w, *events): tid = conf[CONF_TRIGGER_ID] trigger = cg.new_Pvariable(tid) args = w.get_args() @@ -56,4 +71,4 @@ async def add_trigger(conf, event, lv_component, w): async with LambdaContext(EVENT_ARG, where=tid) as context: with LvConditional(w.is_selected()): lv_add(trigger.trigger(value)) - lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), event)) + lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events)) diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 35d924d939..002c7a118d 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -75,6 +75,7 @@ number: - platform: lvgl widget: slider_id name: LVGL Slider + update_on_release: true - platform: lvgl widget: lv_arc id: lvgl_arc_number From bec2d42c793c59b18e15a0fbb5cbe22761858290 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:06:13 +1000 Subject: [PATCH 2225/2607] Add `color_filter_opa` style property (#7276) --- esphome/components/lvgl/schemas.py | 1 + tests/components/lvgl/lvgl-package.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index e4b1c3f8fa..f1c7ff4df6 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -103,6 +103,7 @@ STYLE_PROPS = { ).several_of, "border_width": cv.positive_int, "clip_corner": lvalid.lv_bool, + "color_filter_opa": lvalid.opacity, "height": lvalid.size, "image_recolor": lvalid.lv_color, "image_recolor_opa": lvalid.opacity, diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 09ff9c9d39..54022354f5 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -101,6 +101,7 @@ lvgl: border_side: [bottom, left] border_width: 4 clip_corner: false + color_filter_opa: transp height: 50% image_recolor: light_blue image_recolor_opa: cover From 56e05998efb14b7e91fea7e4ef3cfe76a7128c61 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 14 Aug 2024 04:08:10 +0200 Subject: [PATCH 2226/2607] [code-quality] fix clang-tidy wake_on_lan (#7275) --- esphome/components/wake_on_lan/wake_on_lan.cpp | 2 ++ esphome/components/wake_on_lan/wake_on_lan.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/wake_on_lan/wake_on_lan.cpp b/esphome/components/wake_on_lan/wake_on_lan.cpp index 080e1bbac8..d18cdf89c8 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.cpp +++ b/esphome/components/wake_on_lan/wake_on_lan.cpp @@ -1,4 +1,5 @@ #include "wake_on_lan.h" +#ifdef USE_NETWORK #include "esphome/core/log.h" #include "esphome/components/network/ip_address.h" #include "esphome/components/network/util.h" @@ -85,3 +86,4 @@ void WakeOnLanButton::setup() { } // namespace wake_on_lan } // namespace esphome +#endif diff --git a/esphome/components/wake_on_lan/wake_on_lan.h b/esphome/components/wake_on_lan/wake_on_lan.h index 42cb3a9268..f516c4d669 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.h +++ b/esphome/components/wake_on_lan/wake_on_lan.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include "esphome/components/button/button.h" #include "esphome/core/component.h" #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) @@ -32,3 +33,4 @@ class WakeOnLanButton : public button::Button, public Component { } // namespace wake_on_lan } // namespace esphome +#endif From 4cb174585c0521801d6e8ffda189d37b5a40aa30 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 14 Aug 2024 04:14:29 +0200 Subject: [PATCH 2227/2607] [code-quality] fix readability-braces-around-statements (#7273) --- .../binary/light/binary_light_output.h | 5 +- esphome/components/demo/demo_sensor.h | 5 +- .../light/addressable_light_effect.h | 20 +++--- esphome/components/lvgl/number/lvgl_number.h | 5 +- esphome/components/lvgl/switch/lvgl_switch.h | 5 +- esphome/components/lvgl/text/lvgl_text.h | 5 +- esphome/components/rgbct/rgbct_light_output.h | 5 +- esphome/components/rgbw/rgbw_light_output.h | 5 +- esphome/components/rgbww/rgbww_light_output.h | 5 +- .../components/spi_led_strip/spi_led_strip.h | 5 +- esphome/core/application.h | 63 ++++++++++++------- esphome/core/base_automation.h | 5 +- esphome/core/color.h | 40 +++++++----- 13 files changed, 108 insertions(+), 65 deletions(-) diff --git a/esphome/components/binary/light/binary_light_output.h b/esphome/components/binary/light/binary_light_output.h index 86c83aff5c..8346a82cf0 100644 --- a/esphome/components/binary/light/binary_light_output.h +++ b/esphome/components/binary/light/binary_light_output.h @@ -18,10 +18,11 @@ class BinaryLightOutput : public light::LightOutput { void write_state(light::LightState *state) override { bool binary; state->current_values_as_binary(&binary); - if (binary) + if (binary) { this->output_->turn_on(); - else + } else { this->output_->turn_off(); + } } protected: diff --git a/esphome/components/demo/demo_sensor.h b/esphome/components/demo/demo_sensor.h index b4afa03e11..d965d987de 100644 --- a/esphome/components/demo/demo_sensor.h +++ b/esphome/components/demo/demo_sensor.h @@ -16,10 +16,11 @@ class DemoSensor : public sensor::Sensor, public PollingComponent { float base = std::isnan(this->state) ? 0.0f : this->state; this->publish_state(base + val * 10); } else { - if (val < 0.1) + if (val < 0.1) { this->publish_state(NAN); - else + } else { this->publish_state(val * 100); + } } } }; diff --git a/esphome/components/light/addressable_light_effect.h b/esphome/components/light/addressable_light_effect.h index 73083a58b7..d622ec0375 100644 --- a/esphome/components/light/addressable_light_effect.h +++ b/esphome/components/light/addressable_light_effect.h @@ -114,10 +114,11 @@ class AddressableColorWipeEffect : public AddressableLightEffect { if (now - this->last_add_ < this->add_led_interval_) return; this->last_add_ = now; - if (this->reverse_) + if (this->reverse_) { it.shift_left(1); - else + } else { it.shift_right(1); + } const AddressableColorWipeEffectColor &color = this->colors_[this->at_color_]; Color esp_color = Color(color.r, color.g, color.b, color.w); if (color.gradient) { @@ -127,10 +128,11 @@ class AddressableColorWipeEffect : public AddressableLightEffect { uint8_t gradient = 255 * ((float) this->leds_added_ / color.num_leds); esp_color = esp_color.gradient(next_esp_color, gradient); } - if (this->reverse_) + if (this->reverse_) { it[-1] = esp_color; - else + } else { it[0] = esp_color; + } if (++this->leds_added_ >= color.num_leds) { this->leds_added_ = 0; this->at_color_ = (this->at_color_ + 1) % this->colors_.size(); @@ -207,10 +209,11 @@ class AddressableTwinkleEffect : public AddressableLightEffect { const uint8_t sine = half_sin8(view.get_effect_data()); view = current_color * sine; const uint8_t new_pos = view.get_effect_data() + pos_add; - if (new_pos < view.get_effect_data()) + if (new_pos < view.get_effect_data()) { view.set_effect_data(0); - else + } else { view.set_effect_data(new_pos); + } } else { view = Color::BLACK; } @@ -254,10 +257,11 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect { view = Color(((color >> 2) & 1) * sine, ((color >> 1) & 1) * sine, ((color >> 0) & 1) * sine); } const uint8_t new_x = x + pos_add; - if (new_x > 0b11111) + if (new_x > 0b11111) { view.set_effect_data(0); - else + } else { view.set_effect_data((new_x << 3) | color); + } } else { view = Color(0, 0, 0, 0); } diff --git a/esphome/components/lvgl/number/lvgl_number.h b/esphome/components/lvgl/number/lvgl_number.h index 659fc615c9..a70c9eab9c 100644 --- a/esphome/components/lvgl/number/lvgl_number.h +++ b/esphome/components/lvgl/number/lvgl_number.h @@ -20,10 +20,11 @@ class LVGLNumber : public number::Number { protected: void control(float value) override { - if (this->control_lambda_ != nullptr) + if (this->control_lambda_ != nullptr) { this->control_lambda_(value); - else + } else { this->initial_state_ = value; + } } std::function control_lambda_{}; optional initial_state_{}; diff --git a/esphome/components/lvgl/switch/lvgl_switch.h b/esphome/components/lvgl/switch/lvgl_switch.h index 67be11faba..dbc885219b 100644 --- a/esphome/components/lvgl/switch/lvgl_switch.h +++ b/esphome/components/lvgl/switch/lvgl_switch.h @@ -20,10 +20,11 @@ class LVGLSwitch : public switch_::Switch { protected: void write_state(bool value) override { - if (this->state_lambda_ != nullptr) + if (this->state_lambda_ != nullptr) { this->state_lambda_(value); - else + } else { this->initial_state_ = value; + } } std::function state_lambda_{}; optional initial_state_{}; diff --git a/esphome/components/lvgl/text/lvgl_text.h b/esphome/components/lvgl/text/lvgl_text.h index 4bd5b76744..d3513c3697 100644 --- a/esphome/components/lvgl/text/lvgl_text.h +++ b/esphome/components/lvgl/text/lvgl_text.h @@ -20,10 +20,11 @@ class LVGLText : public text::Text { protected: void control(const std::string &value) override { - if (this->control_lambda_ != nullptr) + if (this->control_lambda_ != nullptr) { this->control_lambda_(value); - else + } else { this->initial_state_ = value; + } } std::function control_lambda_{}; optional initial_state_{}; diff --git a/esphome/components/rgbct/rgbct_light_output.h b/esphome/components/rgbct/rgbct_light_output.h index 9257d67cd1..9e23f783ae 100644 --- a/esphome/components/rgbct/rgbct_light_output.h +++ b/esphome/components/rgbct/rgbct_light_output.h @@ -23,10 +23,11 @@ class RGBCTLightOutput : public light::LightOutput { light::LightTraits get_traits() override { auto traits = light::LightTraits(); - if (this->color_interlock_) + if (this->color_interlock_) { traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::COLOR_TEMPERATURE}); - else + } else { traits.set_supported_color_modes({light::ColorMode::RGB_COLOR_TEMPERATURE, light::ColorMode::COLOR_TEMPERATURE}); + } traits.set_min_mireds(this->cold_white_temperature_); traits.set_max_mireds(this->warm_white_temperature_); return traits; diff --git a/esphome/components/rgbw/rgbw_light_output.h b/esphome/components/rgbw/rgbw_light_output.h index 0f55775608..a2ab17b75d 100644 --- a/esphome/components/rgbw/rgbw_light_output.h +++ b/esphome/components/rgbw/rgbw_light_output.h @@ -16,10 +16,11 @@ class RGBWLightOutput : public light::LightOutput { void set_color_interlock(bool color_interlock) { color_interlock_ = color_interlock; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); - if (this->color_interlock_) + if (this->color_interlock_) { traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::WHITE}); - else + } else { traits.set_supported_color_modes({light::ColorMode::RGB_WHITE}); + } return traits; } void write_state(light::LightState *state) override { diff --git a/esphome/components/rgbww/rgbww_light_output.h b/esphome/components/rgbww/rgbww_light_output.h index 5a86b88595..9687360059 100644 --- a/esphome/components/rgbww/rgbww_light_output.h +++ b/esphome/components/rgbww/rgbww_light_output.h @@ -20,10 +20,11 @@ class RGBWWLightOutput : public light::LightOutput { void set_color_interlock(bool color_interlock) { color_interlock_ = color_interlock; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); - if (this->color_interlock_) + if (this->color_interlock_) { traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::COLD_WARM_WHITE}); - else + } else { traits.set_supported_color_modes({light::ColorMode::RGB_COLD_WARM_WHITE}); + } traits.set_min_mireds(this->cold_white_temperature_); traits.set_max_mireds(this->warm_white_temperature_); return traits; diff --git a/esphome/components/spi_led_strip/spi_led_strip.h b/esphome/components/spi_led_strip/spi_led_strip.h index 8b713378ec..1b317cdd69 100644 --- a/esphome/components/spi_led_strip/spi_led_strip.h +++ b/esphome/components/spi_led_strip/spi_led_strip.h @@ -46,10 +46,11 @@ class SpiLedStrip : public light::AddressableLight, void dump_config() override { esph_log_config(TAG, "SPI LED Strip:"); esph_log_config(TAG, " LEDs: %d", this->num_leds_); - if (this->data_rate_ >= spi::DATA_RATE_1MHZ) + if (this->data_rate_ >= spi::DATA_RATE_1MHZ) { esph_log_config(TAG, " Data rate: %uMHz", (unsigned) (this->data_rate_ / 1000000)); - else + } else { esph_log_config(TAG, " Data rate: %ukHz", (unsigned) (this->data_rate_ / 1000)); + } } void write_state(light::LightState *state) override { diff --git a/esphome/core/application.h b/esphome/core/application.h index 2697357456..462beb1f25 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -246,162 +246,180 @@ class Application { #ifdef USE_BINARY_SENSOR const std::vector &get_binary_sensors() { return this->binary_sensors_; } binary_sensor::BinarySensor *get_binary_sensor_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->binary_sensors_) + for (auto *obj : this->binary_sensors_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_SWITCH const std::vector &get_switches() { return this->switches_; } switch_::Switch *get_switch_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->switches_) + for (auto *obj : this->switches_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_BUTTON const std::vector &get_buttons() { return this->buttons_; } button::Button *get_button_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->buttons_) + for (auto *obj : this->buttons_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_SENSOR const std::vector &get_sensors() { return this->sensors_; } sensor::Sensor *get_sensor_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->sensors_) + for (auto *obj : this->sensors_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_TEXT_SENSOR const std::vector &get_text_sensors() { return this->text_sensors_; } text_sensor::TextSensor *get_text_sensor_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->text_sensors_) + for (auto *obj : this->text_sensors_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_FAN const std::vector &get_fans() { return this->fans_; } fan::Fan *get_fan_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->fans_) + for (auto *obj : this->fans_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_COVER const std::vector &get_covers() { return this->covers_; } cover::Cover *get_cover_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->covers_) + for (auto *obj : this->covers_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_LIGHT const std::vector &get_lights() { return this->lights_; } light::LightState *get_light_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->lights_) + for (auto *obj : this->lights_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_CLIMATE const std::vector &get_climates() { return this->climates_; } climate::Climate *get_climate_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->climates_) + for (auto *obj : this->climates_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_NUMBER const std::vector &get_numbers() { return this->numbers_; } number::Number *get_number_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->numbers_) + for (auto *obj : this->numbers_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_DATETIME_DATE const std::vector &get_dates() { return this->dates_; } datetime::DateEntity *get_date_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->dates_) + for (auto *obj : this->dates_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_DATETIME_TIME const std::vector &get_times() { return this->times_; } datetime::TimeEntity *get_time_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->times_) + for (auto *obj : this->times_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_DATETIME_DATETIME const std::vector &get_datetimes() { return this->datetimes_; } datetime::DateTimeEntity *get_datetime_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->datetimes_) + for (auto *obj : this->datetimes_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_TEXT const std::vector &get_texts() { return this->texts_; } text::Text *get_text_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->texts_) + for (auto *obj : this->texts_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_SELECT const std::vector &get_selects() { return this->selects_; } select::Select *get_select_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->selects_) + for (auto *obj : this->selects_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_LOCK const std::vector &get_locks() { return this->locks_; } lock::Lock *get_lock_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->locks_) + for (auto *obj : this->locks_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_VALVE const std::vector &get_valves() { return this->valves_; } valve::Valve *get_valve_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->valves_) + for (auto *obj : this->valves_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif #ifdef USE_MEDIA_PLAYER const std::vector &get_media_players() { return this->media_players_; } media_player::MediaPlayer *get_media_player_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->media_players_) + for (auto *obj : this->media_players_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif @@ -411,9 +429,10 @@ class Application { return this->alarm_control_panels_; } alarm_control_panel::AlarmControlPanel *get_alarm_control_panel_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->alarm_control_panels_) + for (auto *obj : this->alarm_control_panels_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif @@ -421,9 +440,10 @@ class Application { #ifdef USE_EVENT const std::vector &get_events() { return this->events_; } event::Event *get_event_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->events_) + for (auto *obj : this->events_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif @@ -431,9 +451,10 @@ class Application { #ifdef USE_UPDATE const std::vector &get_updates() { return this->updates_; } update::UpdateEntity *get_update_by_key(uint32_t key, bool include_internal = false) { - for (auto *obj : this->updates_) + for (auto *obj : this->updates_) { if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) return obj; + } return nullptr; } #endif diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index 1bf0efb9a4..dcf7da2f21 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -278,10 +278,11 @@ template class RepeatAction : public Action { this->then_.add_actions(actions); this->then_.add_action(new LambdaAction([this](uint32_t iteration, Ts... x) { iteration++; - if (iteration >= this->count_.value(x...)) + if (iteration >= this->count_.value(x...)) { this->play_next_tuple_(this->var_); - else + } else { this->then_.play(iteration, x...); + } })); } diff --git a/esphome/core/color.h b/esphome/core/color.h index 8965d9fc83..1c43fd9d3e 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -85,22 +85,26 @@ struct Color { } inline Color operator+(const Color &add) const ESPHOME_ALWAYS_INLINE { Color ret; - if (uint8_t(add.r + this->r) < this->r) + if (uint8_t(add.r + this->r) < this->r) { ret.r = 255; - else + } else { ret.r = this->r + add.r; - if (uint8_t(add.g + this->g) < this->g) + } + if (uint8_t(add.g + this->g) < this->g) { ret.g = 255; - else + } else { ret.g = this->g + add.g; - if (uint8_t(add.b + this->b) < this->b) + } + if (uint8_t(add.b + this->b) < this->b) { ret.b = 255; - else + } else { ret.b = this->b + add.b; - if (uint8_t(add.w + this->w) < this->w) + } + if (uint8_t(add.w + this->w) < this->w) { ret.w = 255; - else + } else { ret.w = this->w + add.w; + } return ret; } inline Color &operator+=(const Color &add) ESPHOME_ALWAYS_INLINE { return *this = (*this) + add; } @@ -108,22 +112,26 @@ struct Color { inline Color &operator+=(uint8_t add) ESPHOME_ALWAYS_INLINE { return *this = (*this) + add; } inline Color operator-(const Color &subtract) const ESPHOME_ALWAYS_INLINE { Color ret; - if (subtract.r > this->r) + if (subtract.r > this->r) { ret.r = 0; - else + } else { ret.r = this->r - subtract.r; - if (subtract.g > this->g) + } + if (subtract.g > this->g) { ret.g = 0; - else + } else { ret.g = this->g - subtract.g; - if (subtract.b > this->b) + } + if (subtract.b > this->b) { ret.b = 0; - else + } else { ret.b = this->b - subtract.b; - if (subtract.w > this->w) + } + if (subtract.w > this->w) { ret.w = 0; - else + } else { ret.w = this->w - subtract.w; + } return ret; } inline Color &operator-=(const Color &subtract) ESPHOME_ALWAYS_INLINE { return *this = (*this) - subtract; } From 8756b41b6344a61a49a3b4cdb66437b1b6064036 Mon Sep 17 00:00:00 2001 From: Olivier ARCHER Date: Wed, 14 Aug 2024 04:19:46 +0200 Subject: [PATCH 2228/2607] [mqtt] fix missing initializer in MQTTClientComponent::disable_discovery (#7271) --- esphome/components/mqtt/mqtt_client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 876367aaea..c19b24c0cf 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -632,6 +632,7 @@ void MQTTClientComponent::disable_discovery() { this->discovery_info_ = MQTTDiscoveryInfo{ .prefix = "", .retain = false, + .discover_ip = false, .clean = false, .unique_id_generator = MQTT_LEGACY_UNIQUE_ID_GENERATOR, .object_id_generator = MQTT_NONE_OBJECT_ID_GENERATOR, From b2b23f2a4f2fbbba0ded4b77104df871a2f27260 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 14 Aug 2024 04:21:19 +0200 Subject: [PATCH 2229/2607] [code-quality] fix readability-named-parameter (#7272) --- esphome/core/automation.h | 8 +++++--- esphome/core/optional.h | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index 5a0a17ea1a..e77e453431 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -82,7 +82,7 @@ template class Condition { } protected: - template bool check_tuple_(const std::tuple &tuple, seq) { + template bool check_tuple_(const std::tuple &tuple, seq /*unused*/) { return this->check(std::get(tuple)...); } }; @@ -156,7 +156,7 @@ template class Action { } } } - template void play_next_tuple_(const std::tuple &tuple, seq) { + template void play_next_tuple_(const std::tuple &tuple, seq /*unused*/) { this->play_next_(std::get(tuple)...); } void play_next_tuple_(const std::tuple &tuple) { @@ -223,7 +223,9 @@ template class ActionList { } protected: - template void play_tuple_(const std::tuple &tuple, seq) { this->play(std::get(tuple)...); } + template void play_tuple_(const std::tuple &tuple, seq /*unused*/) { + this->play(std::get(tuple)...); + } Action *actions_begin_{nullptr}; Action *actions_end_{nullptr}; diff --git a/esphome/core/optional.h b/esphome/core/optional.h index 770b77081e..1e28ef1354 100644 --- a/esphome/core/optional.h +++ b/esphome/core/optional.h @@ -24,7 +24,7 @@ namespace esphome { struct nullopt_t { // NOLINT struct init {}; // NOLINT - nullopt_t(init) {} + nullopt_t(init /*unused*/) {} }; // extra parenthesis to prevent the most vexing parse: @@ -42,13 +42,13 @@ template class optional { // NOLINT optional() {} - optional(nullopt_t) {} + optional(nullopt_t /*unused*/) {} optional(T const &arg) : has_value_(true), value_(arg) {} // NOLINT template optional(optional const &other) : has_value_(other.has_value()), value_(other.value()) {} - optional &operator=(nullopt_t) { + optional &operator=(nullopt_t /*unused*/) { reset(); return *this; } @@ -130,29 +130,29 @@ template inline bool operator>=(optional const &x, op // Comparison with nullopt -template inline bool operator==(optional const &x, nullopt_t) { return (!x); } +template inline bool operator==(optional const &x, nullopt_t /*unused*/) { return (!x); } -template inline bool operator==(nullopt_t, optional const &x) { return (!x); } +template inline bool operator==(nullopt_t /*unused*/, optional const &x) { return (!x); } -template inline bool operator!=(optional const &x, nullopt_t) { return bool(x); } +template inline bool operator!=(optional const &x, nullopt_t /*unused*/) { return bool(x); } -template inline bool operator!=(nullopt_t, optional const &x) { return bool(x); } +template inline bool operator!=(nullopt_t /*unused*/, optional const &x) { return bool(x); } -template inline bool operator<(optional const &, nullopt_t) { return false; } +template inline bool operator<(optional const & /*unused*/, nullopt_t /*unused*/) { return false; } -template inline bool operator<(nullopt_t, optional const &x) { return bool(x); } +template inline bool operator<(nullopt_t /*unused*/, optional const &x) { return bool(x); } -template inline bool operator<=(optional const &x, nullopt_t) { return (!x); } +template inline bool operator<=(optional const &x, nullopt_t /*unused*/) { return (!x); } -template inline bool operator<=(nullopt_t, optional const &) { return true; } +template inline bool operator<=(nullopt_t /*unused*/, optional const & /*unused*/) { return true; } -template inline bool operator>(optional const &x, nullopt_t) { return bool(x); } +template inline bool operator>(optional const &x, nullopt_t /*unused*/) { return bool(x); } -template inline bool operator>(nullopt_t, optional const &) { return false; } +template inline bool operator>(nullopt_t /*unused*/, optional const & /*unused*/) { return false; } -template inline bool operator>=(optional const &, nullopt_t) { return true; } +template inline bool operator>=(optional const & /*unused*/, nullopt_t /*unused*/) { return true; } -template inline bool operator>=(nullopt_t, optional const &x) { return (!x); } +template inline bool operator>=(nullopt_t /*unused*/, optional const &x) { return (!x); } // Comparison with T From 8f093823672a49d63d9276c4072d2a3189d194d6 Mon Sep 17 00:00:00 2001 From: Philippe Wechsler <29612400+MadMonkey87@users.noreply.github.com> Date: Wed, 14 Aug 2024 04:25:45 +0200 Subject: [PATCH 2230/2607] support illuminance for airthings wave plus device (#5203) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../airthings_wave_plus/airthings_wave_plus.cpp | 7 +++++-- .../airthings_wave_plus/airthings_wave_plus.h | 2 ++ esphome/components/airthings_wave_plus/sensor.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp index a32128e992..8c8c514fdb 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.cpp @@ -14,8 +14,6 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { ESP_LOGD(TAG, "version = %d", value->version); if (value->version == 1) { - ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); - if (this->humidity_sensor_ != nullptr) { this->humidity_sensor_->publish_state(value->humidity / 2.0f); } @@ -43,6 +41,10 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { this->tvoc_sensor_->publish_state(value->voc); } + + if (this->illuminance_sensor_ != nullptr) { + this->illuminance_sensor_->publish_state(value->ambientLight); + } } else { ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); } @@ -68,6 +70,7 @@ void AirthingsWavePlus::dump_config() { LOG_SENSOR(" ", "Radon", this->radon_sensor_); LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); LOG_SENSOR(" ", "CO2", this->co2_sensor_); + LOG_SENSOR(" ", "Illuminance", this->illuminance_sensor_); } AirthingsWavePlus::AirthingsWavePlus() { diff --git a/esphome/components/airthings_wave_plus/airthings_wave_plus.h b/esphome/components/airthings_wave_plus/airthings_wave_plus.h index 23c8cbb166..bd7a40ef8b 100644 --- a/esphome/components/airthings_wave_plus/airthings_wave_plus.h +++ b/esphome/components/airthings_wave_plus/airthings_wave_plus.h @@ -22,6 +22,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } + void set_illuminance(sensor::Sensor *illuminance) { illuminance_sensor_ = illuminance; } protected: bool is_valid_radon_value_(uint16_t radon); @@ -32,6 +33,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { sensor::Sensor *radon_sensor_{nullptr}; sensor::Sensor *radon_long_term_sensor_{nullptr}; sensor::Sensor *co2_sensor_{nullptr}; + sensor::Sensor *illuminance_sensor_{nullptr}; struct WavePlusReadings { uint8_t version; diff --git a/esphome/components/airthings_wave_plus/sensor.py b/esphome/components/airthings_wave_plus/sensor.py index 643a2bfb68..d28c7e2abc 100644 --- a/esphome/components/airthings_wave_plus/sensor.py +++ b/esphome/components/airthings_wave_plus/sensor.py @@ -12,6 +12,9 @@ from esphome.const import ( CONF_CO2, UNIT_BECQUEREL_PER_CUBIC_METER, UNIT_PARTS_PER_MILLION, + CONF_ILLUMINANCE, + UNIT_LUX, + DEVICE_CLASS_ILLUMINANCE, ) DEPENDENCIES = airthings_wave_base.DEPENDENCIES @@ -45,6 +48,12 @@ CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( device_class=DEVICE_CLASS_CARBON_DIOXIDE, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), } ) @@ -62,3 +71,6 @@ async def to_code(config): if config_co2 := config.get(CONF_CO2): sens = await sensor.new_sensor(config_co2) cg.add(var.set_co2(sens)) + if config_illuminance := config.get(CONF_ILLUMINANCE): + sens = await sensor.new_sensor(config_illuminance) + cg.add(var.set_illuminance(sens)) From d6f130e35ab2ecd0d2c09ef31459c205852aa751 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Tue, 13 Aug 2024 23:40:07 -0400 Subject: [PATCH 2231/2607] [micro_wake_word] Bump ESPMicroSpeechFeatures version to 1.1.0 (#7249) --- .../components/micro_wake_word/__init__.py | 47 +++++++++---------- platformio.ini | 2 +- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index c2faca25f4..cd45f75b01 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -1,39 +1,34 @@ -import logging - -import json import hashlib -from urllib.parse import urljoin +import json +import logging from pathlib import Path +from urllib.parse import urljoin + import requests -import esphome.config_validation as cv -import esphome.codegen as cg - -from esphome.core import CORE, HexInt - -from esphome.components import esp32, microphone -from esphome import automation, git, external_files +from esphome import automation, external_files, git from esphome.automation import register_action, register_condition - - +import esphome.codegen as cg +from esphome.components import esp32, microphone +import esphome.config_validation as cv from esphome.const import ( - __version__, + CONF_FILE, CONF_ID, CONF_MICROPHONE, CONF_MODEL, - CONF_URL, - CONF_FILE, + CONF_PASSWORD, CONF_PATH, + CONF_RAW_DATA_ID, CONF_REF, CONF_REFRESH, CONF_TYPE, + CONF_URL, CONF_USERNAME, - CONF_PASSWORD, - CONF_RAW_DATA_ID, TYPE_GIT, TYPE_LOCAL, + __version__, ) - +from esphome.core import CORE, HexInt _LOGGER = logging.getLogger(__name__) @@ -174,12 +169,12 @@ def _convert_manifest_v1_to_v2(v1_manifest): CONF_SLIDING_WINDOW_AVERAGE_SIZE ] del v2_manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE] - v2_manifest[KEY_MICRO][ - CONF_TENSOR_ARENA_SIZE - ] = 45672 # Original Inception-based V1 manifest models require a minimum of 45672 bytes - v2_manifest[KEY_MICRO][ - CONF_FEATURE_STEP_SIZE - ] = 20 # Original Inception-based V1 manifest models use a 20 ms feature step size + + # Original Inception-based V1 manifest models require a minimum of 45672 bytes + v2_manifest[KEY_MICRO][CONF_TENSOR_ARENA_SIZE] = 45672 + + # Original Inception-based V1 manifest models use a 20 ms feature step size + v2_manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE] = 20 return v2_manifest @@ -502,7 +497,7 @@ async def to_code(config): ) cg.add(var.set_features_step_size(manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE])) - cg.add_library("kahrendt/ESPMicroSpeechFeatures", "1.0.0") + cg.add_library("kahrendt/ESPMicroSpeechFeatures", "1.1.0") MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)}) diff --git a/platformio.ini b/platformio.ini index 87a239207f..4a0a3f2ef4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -145,7 +145,7 @@ framework = espidf lib_deps = ${common:idf.lib_deps} droscy/esp_wireguard@0.4.2 ; wireguard - kahrendt/ESPMicroSpeechFeatures@1.0.0 ; micro_wake_word + kahrendt/ESPMicroSpeechFeatures@1.1.0 ; micro_wake_word build_flags = ${common:idf.build_flags} -Wno-nonnull-compare From cf6ea7cb2cf1636cb18e60ecf010fa6bb559c464 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Wed, 14 Aug 2024 05:42:43 +0200 Subject: [PATCH 2232/2607] Implement the finish() method and action. implement the is_stopped condition (#7255) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 12 ++++++++++-- .../i2s_audio/speaker/i2s_audio_speaker.h | 2 ++ esphome/components/speaker/__init__.py | 19 ++++++++++++++----- esphome/components/speaker/automation.h | 10 ++++++++++ esphome/components/speaker/speaker.h | 5 +++++ tests/components/speaker/test.esp32-ard.yaml | 11 +++++++++-- .../components/speaker/test.esp32-c3-ard.yaml | 11 +++++++++-- .../components/speaker/test.esp32-c3-idf.yaml | 11 +++++++++-- tests/components/speaker/test.esp32-idf.yaml | 11 +++++++++-- 9 files changed, 77 insertions(+), 15 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 1c6c50d8c9..cf5a2c2766 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -180,7 +180,11 @@ void I2SAudioSpeaker::player_task(void *params) { } } -void I2SAudioSpeaker::stop() { +void I2SAudioSpeaker::stop() { this->stop_(false); } + +void I2SAudioSpeaker::finish() { this->stop_(true); } + +void I2SAudioSpeaker::stop_(bool wait_on_empty) { if (this->is_failed()) return; if (this->state_ == speaker::STATE_STOPPED) @@ -192,7 +196,11 @@ void I2SAudioSpeaker::stop() { this->state_ = speaker::STATE_STOPPING; DataEvent data; data.stop = true; - xQueueSendToFront(this->buffer_queue_, &data, portMAX_DELAY); + if (wait_on_empty) { + xQueueSend(this->buffer_queue_, &data, portMAX_DELAY); + } else { + xQueueSendToFront(this->buffer_queue_, &data, portMAX_DELAY); + } } void I2SAudioSpeaker::watch_() { diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 1800feaeec..0bdb67ceba 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -53,6 +53,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud void start() override; void stop() override; + void finish() override; size_t play(const uint8_t *data, size_t length) override; @@ -60,6 +61,7 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud protected: void start_(); + void stop_(bool wait_on_empty); void watch_(); static void player_task(void *params); diff --git a/esphome/components/speaker/__init__.py b/esphome/components/speaker/__init__.py index 79d5df8c5a..d28b726d1f 100644 --- a/esphome/components/speaker/__init__.py +++ b/esphome/components/speaker/__init__.py @@ -1,13 +1,11 @@ from esphome import automation -import esphome.config_validation as cv -import esphome.codegen as cg - from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID, CONF_DATA +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_DATA, CONF_ID from esphome.core import CORE from esphome.coroutine import coroutine_with_priority - CODEOWNERS = ["@jesserockz"] IS_PLATFORM_COMPONENT = True @@ -22,8 +20,12 @@ PlayAction = speaker_ns.class_( StopAction = speaker_ns.class_( "StopAction", automation.Action, cg.Parented.template(Speaker) ) +FinishAction = speaker_ns.class_( + "FinishAction", automation.Action, cg.Parented.template(Speaker) +) IsPlayingCondition = speaker_ns.class_("IsPlayingCondition", automation.Condition) +IsStoppedCondition = speaker_ns.class_("IsStoppedCondition", automation.Condition) async def setup_speaker_core_(var, config): @@ -75,11 +77,18 @@ async def speaker_play_action(config, action_id, template_arg, args): automation.register_action("speaker.stop", StopAction, SPEAKER_AUTOMATION_SCHEMA)( speaker_action ) +automation.register_action("speaker.finish", FinishAction, SPEAKER_AUTOMATION_SCHEMA)( + speaker_action +) automation.register_condition( "speaker.is_playing", IsPlayingCondition, SPEAKER_AUTOMATION_SCHEMA )(speaker_action) +automation.register_condition( + "speaker.is_stopped", IsStoppedCondition, SPEAKER_AUTOMATION_SCHEMA +)(speaker_action) + @coroutine_with_priority(100.0) async def to_code(config): diff --git a/esphome/components/speaker/automation.h b/esphome/components/speaker/automation.h index e28991a0d1..2716fe6100 100644 --- a/esphome/components/speaker/automation.h +++ b/esphome/components/speaker/automation.h @@ -39,10 +39,20 @@ template class StopAction : public Action, public Parente void play(Ts... x) override { this->parent_->stop(); } }; +template class FinishAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->finish(); } +}; + template class IsPlayingCondition : public Condition, public Parented { public: bool check(Ts... x) override { return this->parent_->is_running(); } }; +template class IsStoppedCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->is_stopped(); } +}; + } // namespace speaker } // namespace esphome diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index b494873160..142231881c 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -17,10 +17,15 @@ class Speaker { virtual void start() = 0; virtual void stop() = 0; + // In compare between *STOP()* and *FINISH()*; *FINISH()* will stop after emptying the play buffer, + // while *STOP()* will break directly. + // When finish() is not implemented on the plateform component it should just do a normal stop. + virtual void finish() { this->stop(); } virtual bool has_buffered_data() const = 0; bool is_running() const { return this->state_ == STATE_RUNNING; } + bool is_stopped() const { return this->state_ == STATE_STOPPED; } protected: State state_{STATE_STOPPED}; diff --git a/tests/components/speaker/test.esp32-ard.yaml b/tests/components/speaker/test.esp32-ard.yaml index 416e203d7b..e10c3e88c1 100644 --- a/tests/components/speaker/test.esp32-ard.yaml +++ b/tests/components/speaker/test.esp32-ard.yaml @@ -1,8 +1,15 @@ esphome: on_boot: then: - - speaker.play: [0, 1, 2, 3] - - speaker.stop + - if: + condition: speaker.is_stopped + then: + - speaker.play: [0, 1, 2, 3] + - if: + condition: speaker.is_playing + then: + - speaker.finish: + - speaker.stop: i2s_audio: i2s_lrclk_pin: 16 diff --git a/tests/components/speaker/test.esp32-c3-ard.yaml b/tests/components/speaker/test.esp32-c3-ard.yaml index c7809baace..08699d8b22 100644 --- a/tests/components/speaker/test.esp32-c3-ard.yaml +++ b/tests/components/speaker/test.esp32-c3-ard.yaml @@ -1,8 +1,15 @@ esphome: on_boot: then: - - speaker.play: [0, 1, 2, 3] - - speaker.stop + - if: + condition: speaker.is_stopped + then: + - speaker.play: [0, 1, 2, 3] + - if: + condition: speaker.is_playing + then: + - speaker.finish: + - speaker.stop: i2s_audio: i2s_lrclk_pin: 6 diff --git a/tests/components/speaker/test.esp32-c3-idf.yaml b/tests/components/speaker/test.esp32-c3-idf.yaml index c7809baace..08699d8b22 100644 --- a/tests/components/speaker/test.esp32-c3-idf.yaml +++ b/tests/components/speaker/test.esp32-c3-idf.yaml @@ -1,8 +1,15 @@ esphome: on_boot: then: - - speaker.play: [0, 1, 2, 3] - - speaker.stop + - if: + condition: speaker.is_stopped + then: + - speaker.play: [0, 1, 2, 3] + - if: + condition: speaker.is_playing + then: + - speaker.finish: + - speaker.stop: i2s_audio: i2s_lrclk_pin: 6 diff --git a/tests/components/speaker/test.esp32-idf.yaml b/tests/components/speaker/test.esp32-idf.yaml index 416e203d7b..e10c3e88c1 100644 --- a/tests/components/speaker/test.esp32-idf.yaml +++ b/tests/components/speaker/test.esp32-idf.yaml @@ -1,8 +1,15 @@ esphome: on_boot: then: - - speaker.play: [0, 1, 2, 3] - - speaker.stop + - if: + condition: speaker.is_stopped + then: + - speaker.play: [0, 1, 2, 3] + - if: + condition: speaker.is_playing + then: + - speaker.finish: + - speaker.stop: i2s_audio: i2s_lrclk_pin: 16 From ccf57488c5432372dcdb2e87072ed15a9c7953a4 Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Tue, 13 Aug 2024 23:43:35 -0500 Subject: [PATCH 2233/2607] Correct offset calibration (#7228) Co-authored-by: descipher Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/atm90e32/__init__.py | 7 ++ esphome/components/atm90e32/atm90e32.cpp | 84 +++++++++++++++---- esphome/components/atm90e32/atm90e32.h | 27 ++++-- esphome/components/atm90e32/atm90e32_reg.h | 2 + .../components/atm90e32/button/__init__.py | 43 ++++++++++ .../atm90e32/button/atm90e32_button.cpp | 20 +++++ .../atm90e32/button/atm90e32_button.h | 27 ++++++ esphome/components/atm90e32/sensor.py | 26 +++--- tests/components/atm90e32/test.esp32-ard.yaml | 9 ++ .../atm90e32/test.esp32-c3-ard.yaml | 9 ++ .../atm90e32/test.esp32-c3-idf.yaml | 9 ++ tests/components/atm90e32/test.esp32-idf.yaml | 9 ++ .../components/atm90e32/test.esp8266-ard.yaml | 40 +++++++++ .../components/atm90e32/test.rp2040-ard.yaml | 9 ++ 15 files changed, 288 insertions(+), 34 deletions(-) create mode 100644 esphome/components/atm90e32/button/__init__.py create mode 100644 esphome/components/atm90e32/button/atm90e32_button.cpp create mode 100644 esphome/components/atm90e32/button/atm90e32_button.h diff --git a/CODEOWNERS b/CODEOWNERS index 3ea9c75ac2..1236c8d842 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -46,6 +46,7 @@ esphome/components/async_tcp/* @OttoWinter esphome/components/at581x/* @X-Ryl669 esphome/components/atc_mithermometer/* @ahpohl esphome/components/atm90e26/* @danieltwagner +esphome/components/atm90e32/* @circuitsetup @descipher esphome/components/b_parasite/* @rbaron esphome/components/ballu/* @bazuchan esphome/components/bang_bang/* @OttoWinter diff --git a/esphome/components/atm90e32/__init__.py b/esphome/components/atm90e32/__init__.py index e69de29bb2..8ce95be489 100644 --- a/esphome/components/atm90e32/__init__.py +++ b/esphome/components/atm90e32/__init__.py @@ -0,0 +1,7 @@ +import esphome.codegen as cg + +CODEOWNERS = ["@circuitsetup", "@descipher"] + +atm90e32_ns = cg.esphome_ns.namespace("atm90e32") + +CONF_ATM90E32_ID = "atm90e32_id" diff --git a/esphome/components/atm90e32/atm90e32.cpp b/esphome/components/atm90e32/atm90e32.cpp index e27459b18a..43647b1855 100644 --- a/esphome/components/atm90e32/atm90e32.cpp +++ b/esphome/components/atm90e32/atm90e32.cpp @@ -132,10 +132,77 @@ void ATM90E32Component::update() { this->status_clear_warning(); } +void ATM90E32Component::restore_calibrations_() { + if (enable_offset_calibration_) { + this->pref_.load(&this->offset_phase_); + } +}; + +void ATM90E32Component::run_offset_calibrations() { + // Run the calibrations and + // Setup voltage and current calibration offsets for PHASE A + this->offset_phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA); + this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA); + this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset + // Setup voltage and current calibration offsets for PHASE B + this->offset_phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB); + this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB); + this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset + // Setup voltage and current calibration offsets for PHASE C + this->offset_phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC); + this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC); + this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset + this->pref_.save(&this->offset_phase_); + ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_, + this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_); + ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_, + this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_); +} + +void ATM90E32Component::clear_offset_calibrations() { + // Clear the calibrations and + this->offset_phase_[PHASEA].voltage_offset_ = 0; + this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEA].current_offset_ = 0; + this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset + this->offset_phase_[PHASEB].voltage_offset_ = 0; + this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEB].current_offset_ = 0; + this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset + this->offset_phase_[PHASEC].voltage_offset_ = 0; + this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_; + this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset + this->offset_phase_[PHASEC].current_offset_ = 0; + this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_; + this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset + this->pref_.save(&this->offset_phase_); + ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_, + this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_); + ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_, + this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_); +} + void ATM90E32Component::setup() { ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component..."); this->spi_setup(); - + if (this->enable_offset_calibration_) { + uint32_t hash = fnv1_hash(App.get_friendly_name()); + this->pref_ = global_preferences->make_preference(hash, true); + this->restore_calibrations_(); + } uint16_t mmode0 = 0x87; // 3P4W 50Hz if (line_freq_ == 60) { mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz @@ -167,27 +234,12 @@ void ATM90E32Component::setup() { this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50% this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750 this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10% - // Setup voltage and current calibration offsets for PHASE A - this->phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA); - this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // A Voltage offset - this->phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA); - this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // A Current offset // Setup voltage and current gain for PHASE A this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[PHASEA].voltage_gain_); // A Voltage rms gain this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[PHASEA].ct_gain_); // A line current gain - // Setup voltage and current calibration offsets for PHASE B - this->phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB); - this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // B Voltage offset - this->phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB); - this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // B Current offset // Setup voltage and current gain for PHASE B this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[PHASEB].voltage_gain_); // B Voltage rms gain this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[PHASEB].ct_gain_); // B line current gain - // Setup voltage and current calibration offsets for PHASE C - this->phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC); - this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset - this->phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC); - this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset // Setup voltage and current gain for PHASE C this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[PHASEC].voltage_gain_); // C Voltage rms gain this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[PHASEC].ct_gain_); // C line current gain diff --git a/esphome/components/atm90e32/atm90e32.h b/esphome/components/atm90e32/atm90e32.h index 0a334dbe8b..35c61d1e05 100644 --- a/esphome/components/atm90e32/atm90e32.h +++ b/esphome/components/atm90e32/atm90e32.h @@ -1,9 +1,12 @@ #pragma once -#include "esphome/core/component.h" +#include "atm90e32_reg.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/spi/spi.h" -#include "atm90e32_reg.h" +#include "esphome/core/application.h" +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" namespace esphome { namespace atm90e32 { @@ -20,7 +23,6 @@ class ATM90E32Component : public PollingComponent, void dump_config() override; float get_setup_priority() const override; void update() override; - void set_voltage_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].voltage_sensor_ = obj; } void set_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].current_sensor_ = obj; } void set_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_sensor_ = obj; } @@ -48,9 +50,11 @@ class ATM90E32Component : public PollingComponent, void set_line_freq(int freq) { line_freq_ = freq; } void set_current_phases(int phases) { current_phases_ = phases; } void set_pga_gain(uint16_t gain) { pga_gain_ = gain; } + void run_offset_calibrations(); + void clear_offset_calibrations(); + void set_enable_offset_calibration(bool flag) { enable_offset_calibration_ = flag; } uint16_t calibrate_voltage_offset_phase(uint8_t /*phase*/); uint16_t calibrate_current_offset_phase(uint8_t /*phase*/); - int32_t last_periodic_millis = millis(); protected: @@ -83,10 +87,11 @@ class ATM90E32Component : public PollingComponent, float get_chip_temperature_(); bool get_publish_interval_flag_() { return publish_interval_flag_; }; void set_publish_interval_flag_(bool flag) { publish_interval_flag_ = flag; }; + void restore_calibrations_(); struct ATM90E32Phase { - uint16_t voltage_gain_{7305}; - uint16_t ct_gain_{27961}; + uint16_t voltage_gain_{0}; + uint16_t ct_gain_{0}; uint16_t voltage_offset_{0}; uint16_t current_offset_{0}; float voltage_{0}; @@ -114,13 +119,21 @@ class ATM90E32Component : public PollingComponent, uint32_t cumulative_reverse_active_energy_{0}; } phase_[3]; + struct Calibration { + uint16_t voltage_offset_{0}; + uint16_t current_offset_{0}; + } offset_phase_[3]; + + ESPPreferenceObject pref_; + sensor::Sensor *freq_sensor_{nullptr}; sensor::Sensor *chip_temperature_sensor_{nullptr}; uint16_t pga_gain_{0x15}; int line_freq_{60}; int current_phases_{3}; - bool publish_interval_flag_{true}; + bool publish_interval_flag_{false}; bool peak_current_signed_{false}; + bool enable_offset_calibration_{false}; }; } // namespace atm90e32 diff --git a/esphome/components/atm90e32/atm90e32_reg.h b/esphome/components/atm90e32/atm90e32_reg.h index dac62aa6b4..954fb42e79 100644 --- a/esphome/components/atm90e32/atm90e32_reg.h +++ b/esphome/components/atm90e32/atm90e32_reg.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace esphome { namespace atm90e32 { diff --git a/esphome/components/atm90e32/button/__init__.py b/esphome/components/atm90e32/button/__init__.py new file mode 100644 index 0000000000..931346b386 --- /dev/null +++ b/esphome/components/atm90e32/button/__init__.py @@ -0,0 +1,43 @@ +import esphome.codegen as cg +from esphome.components import button +import esphome.config_validation as cv +from esphome.const import CONF_ID, ENTITY_CATEGORY_CONFIG, ICON_CHIP, ICON_SCALE + +from .. import atm90e32_ns +from ..sensor import ATM90E32Component + +CONF_RUN_OFFSET_CALIBRATION = "run_offset_calibration" +CONF_CLEAR_OFFSET_CALIBRATION = "clear_offset_calibration" + +ATM90E32CalibrationButton = atm90e32_ns.class_( + "ATM90E32CalibrationButton", + button.Button, +) +ATM90E32ClearCalibrationButton = atm90e32_ns.class_( + "ATM90E32ClearCalibrationButton", + button.Button, +) + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_ID): cv.use_id(ATM90E32Component), + cv.Optional(CONF_RUN_OFFSET_CALIBRATION): button.button_schema( + ATM90E32CalibrationButton, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SCALE, + ), + cv.Optional(CONF_CLEAR_OFFSET_CALIBRATION): button.button_schema( + ATM90E32ClearCalibrationButton, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_CHIP, + ), +} + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_ID]) + if run_offset := config.get(CONF_RUN_OFFSET_CALIBRATION): + b = await button.new_button(run_offset) + await cg.register_parented(b, parent) + if clear_offset := config.get(CONF_CLEAR_OFFSET_CALIBRATION): + b = await button.new_button(clear_offset) + await cg.register_parented(b, parent) diff --git a/esphome/components/atm90e32/button/atm90e32_button.cpp b/esphome/components/atm90e32/button/atm90e32_button.cpp new file mode 100644 index 0000000000..00715b61dd --- /dev/null +++ b/esphome/components/atm90e32/button/atm90e32_button.cpp @@ -0,0 +1,20 @@ +#include "atm90e32_button.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace atm90e32 { + +static const char *const TAG = "atm90e32.button"; + +void ATM90E32CalibrationButton::press_action() { + ESP_LOGI(TAG, "Running offset calibrations, Note: CTs and ACVs must be 0 during this process..."); + this->parent_->run_offset_calibrations(); +} + +void ATM90E32ClearCalibrationButton::press_action() { + ESP_LOGI(TAG, "Offset calibrations cleared."); + this->parent_->clear_offset_calibrations(); +} + +} // namespace atm90e32 +} // namespace esphome diff --git a/esphome/components/atm90e32/button/atm90e32_button.h b/esphome/components/atm90e32/button/atm90e32_button.h new file mode 100644 index 0000000000..0617099457 --- /dev/null +++ b/esphome/components/atm90e32/button/atm90e32_button.h @@ -0,0 +1,27 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/atm90e32/atm90e32.h" +#include "esphome/components/button/button.h" + +namespace esphome { +namespace atm90e32 { + +class ATM90E32CalibrationButton : public button::Button, public Parented { + public: + ATM90E32CalibrationButton() = default; + + protected: + void press_action() override; +}; + +class ATM90E32ClearCalibrationButton : public button::Button, public Parented { + public: + ATM90E32ClearCalibrationButton() = default; + + protected: + void press_action() override; +}; + +} // namespace atm90e32 +} // namespace esphome diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index 2bc7f0498d..be2196223c 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -1,21 +1,21 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import sensor, spi +import esphome.config_validation as cv from esphome.const import ( - CONF_ID, - CONF_REACTIVE_POWER, - CONF_VOLTAGE, + CONF_APPARENT_POWER, CONF_CURRENT, + CONF_FORWARD_ACTIVE_ENERGY, + CONF_FREQUENCY, + CONF_ID, CONF_PHASE_A, + CONF_PHASE_ANGLE, CONF_PHASE_B, CONF_PHASE_C, - CONF_PHASE_ANGLE, CONF_POWER, CONF_POWER_FACTOR, - CONF_APPARENT_POWER, - CONF_FREQUENCY, - CONF_FORWARD_ACTIVE_ENERGY, + CONF_REACTIVE_POWER, CONF_REVERSE_ACTIVE_ENERGY, + CONF_VOLTAGE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, @@ -23,13 +23,13 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLTAGE, ENTITY_CATEGORY_DIAGNOSTIC, - ICON_LIGHTBULB, ICON_CURRENT_AC, + ICON_LIGHTBULB, STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, UNIT_AMPERE, - UNIT_DEGREES, UNIT_CELSIUS, + UNIT_DEGREES, UNIT_HERTZ, UNIT_VOLT, UNIT_VOLT_AMPS_REACTIVE, @@ -37,6 +37,8 @@ from esphome.const import ( UNIT_WATT_HOURS, ) +from . import atm90e32_ns + CONF_LINE_FREQUENCY = "line_frequency" CONF_CHIP_TEMPERATURE = "chip_temperature" CONF_GAIN_PGA = "gain_pga" @@ -46,6 +48,7 @@ CONF_GAIN_CT = "gain_ct" CONF_HARMONIC_POWER = "harmonic_power" CONF_PEAK_CURRENT = "peak_current" CONF_PEAK_CURRENT_SIGNED = "peak_current_signed" +CONF_ENABLE_OFFSET_CALIBRATION = "enable_offset_calibration" UNIT_DEG = "degrees" LINE_FREQS = { "50HZ": 50, @@ -61,7 +64,6 @@ PGA_GAINS = { "4X": 0x2A, } -atm90e32_ns = cg.esphome_ns.namespace("atm90e32") ATM90E32Component = atm90e32_ns.class_( "ATM90E32Component", cg.PollingComponent, spi.SPIDevice ) @@ -164,6 +166,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(CONF_GAIN_PGA, default="2X"): cv.enum(PGA_GAINS, upper=True), cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean, + cv.Optional(CONF_ENABLE_OFFSET_CALIBRATION, default=False): cv.boolean, } ) .extend(cv.polling_component_schema("60s")) @@ -227,3 +230,4 @@ async def to_code(config): cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES])) cg.add(var.set_pga_gain(config[CONF_GAIN_PGA])) cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED])) + cg.add(var.set_enable_offset_calibration(config[CONF_ENABLE_OFFSET_CALIBRATION])) diff --git a/tests/components/atm90e32/test.esp32-ard.yaml b/tests/components/atm90e32/test.esp32-ard.yaml index 131270f8ad..3bdc2bcec6 100644 --- a/tests/components/atm90e32/test.esp32-ard.yaml +++ b/tests/components/atm90e32/test.esp32-ard.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 13 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,11 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" diff --git a/tests/components/atm90e32/test.esp32-c3-ard.yaml b/tests/components/atm90e32/test.esp32-c3-ard.yaml index 263fb6d24e..9ec0037a61 100644 --- a/tests/components/atm90e32/test.esp32-c3-ard.yaml +++ b/tests/components/atm90e32/test.esp32-c3-ard.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 8 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,11 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" diff --git a/tests/components/atm90e32/test.esp32-c3-idf.yaml b/tests/components/atm90e32/test.esp32-c3-idf.yaml index 263fb6d24e..9ec0037a61 100644 --- a/tests/components/atm90e32/test.esp32-c3-idf.yaml +++ b/tests/components/atm90e32/test.esp32-c3-idf.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 8 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,11 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" diff --git a/tests/components/atm90e32/test.esp32-idf.yaml b/tests/components/atm90e32/test.esp32-idf.yaml index 131270f8ad..3bdc2bcec6 100644 --- a/tests/components/atm90e32/test.esp32-idf.yaml +++ b/tests/components/atm90e32/test.esp32-idf.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 13 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,11 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" diff --git a/tests/components/atm90e32/test.esp8266-ard.yaml b/tests/components/atm90e32/test.esp8266-ard.yaml index e8e2abc1a9..fbb3368efa 100644 --- a/tests/components/atm90e32/test.esp8266-ard.yaml +++ b/tests/components/atm90e32/test.esp8266-ard.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 5 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,42 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True + - platform: atm90e32 + cs_pin: 4 + id: chip2 + phase_a: + voltage: + name: EMON Line Voltage A + current: + name: EMON CT1 Current + power: + name: EMON Active Power CT1 + reactive_power: + name: EMON Reactive Power CT1 + power_factor: + name: EMON Power Factor CT1 + gain_voltage: 7305 + gain_ct: 27961 + phase_c: + voltage: + name: EMON Line Voltage C + current: + name: EMON CT2 Current + power: + name: EMON Active Power CT2 + reactive_power: + name: EMON Reactive Power CT2 + power_factor: + name: EMON Power Factor CT2 + gain_voltage: 7305 + gain_ct: 27961 + line_frequency: 60Hz + current_phases: 2 +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" diff --git a/tests/components/atm90e32/test.rp2040-ard.yaml b/tests/components/atm90e32/test.rp2040-ard.yaml index 525e0b801a..a6b7956da7 100644 --- a/tests/components/atm90e32/test.rp2040-ard.yaml +++ b/tests/components/atm90e32/test.rp2040-ard.yaml @@ -7,6 +7,7 @@ spi: sensor: - platform: atm90e32 cs_pin: 5 + id: chip1 phase_a: voltage: name: EMON Line Voltage A @@ -49,3 +50,11 @@ sensor: line_frequency: 60Hz current_phases: 3 gain_pga: 2X + enable_offset_calibration: True +button: + - platform: atm90e32 + id: chip1 + run_offset_calibration: + name: "Chip1 - Run Offset Calibration" + clear_offset_calibration: + name: "Chip1 - Clear Offset Calibration" From 350f17e48f60cdd7100945c82a14e284adf517b5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:56:53 +1200 Subject: [PATCH 2234/2607] Bump version to 2024.9.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 37f20796b5..6157ce32f7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0-dev" +__version__ = "2024.9.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7b233d6871eef2a9860b994940ee6669560e576c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:56:53 +1200 Subject: [PATCH 2235/2607] Bump version to 2024.8.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 37f20796b5..47aacd6452 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0-dev" +__version__ = "2024.8.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 7133e08755fb9c65abc62af9dc0df47900caa0a3 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 14 Aug 2024 00:55:23 -0700 Subject: [PATCH 2236/2607] remove extra number from pronto (#7263) --- esphome/components/remote_base/pronto_protocol.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 625af76235..35fd782248 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -201,9 +201,6 @@ std::string ProntoProtocol::compensate_and_dump_sequence_(const RawTimings &data out += dump_duration_(t_duration, timebase); } - // append minimum gap - out += dump_duration_(PRONTO_DEFAULT_GAP, timebase, true); - return out; } From 80a0f137224c82fdc3cf17dfdd5dd3683ad9e796 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 14 Aug 2024 23:05:16 +0200 Subject: [PATCH 2237/2607] [code-quality] fix performance-unnecessary-value-param (#7274) --- esphome/components/lvgl/number/lvgl_number.h | 4 +++- esphome/components/lvgl/select/lvgl_select.h | 4 +++- esphome/components/lvgl/switch/lvgl_switch.h | 4 +++- esphome/components/lvgl/text/lvgl_text.h | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/esphome/components/lvgl/number/lvgl_number.h b/esphome/components/lvgl/number/lvgl_number.h index a70c9eab9c..77fadd2a29 100644 --- a/esphome/components/lvgl/number/lvgl_number.h +++ b/esphome/components/lvgl/number/lvgl_number.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/components/number/number.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" @@ -11,7 +13,7 @@ namespace lvgl { class LVGLNumber : public number::Number { public: void set_control_lambda(std::function control_lambda) { - this->control_lambda_ = control_lambda; + this->control_lambda_ = std::move(control_lambda); if (this->initial_state_.has_value()) { this->control_lambda_(this->initial_state_.value()); this->initial_state_.reset(); diff --git a/esphome/components/lvgl/select/lvgl_select.h b/esphome/components/lvgl/select/lvgl_select.h index 407045d605..97cc8697eb 100644 --- a/esphome/components/lvgl/select/lvgl_select.h +++ b/esphome/components/lvgl/select/lvgl_select.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/components/select/select.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" @@ -28,7 +30,7 @@ static std::vector split_string(const std::string &str) { class LVGLSelect : public select::Select { public: void set_control_lambda(std::function lambda) { - this->control_lambda_ = lambda; + this->control_lambda_ = std::move(lambda); if (this->initial_state_.has_value()) { this->control(this->initial_state_.value()); this->initial_state_.reset(); diff --git a/esphome/components/lvgl/switch/lvgl_switch.h b/esphome/components/lvgl/switch/lvgl_switch.h index dbc885219b..af839b8892 100644 --- a/esphome/components/lvgl/switch/lvgl_switch.h +++ b/esphome/components/lvgl/switch/lvgl_switch.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/components/switch/switch.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" @@ -11,7 +13,7 @@ namespace lvgl { class LVGLSwitch : public switch_::Switch { public: void set_control_lambda(std::function state_lambda) { - this->state_lambda_ = state_lambda; + this->state_lambda_ = std::move(state_lambda); if (this->initial_state_.has_value()) { this->state_lambda_(this->initial_state_.value()); this->initial_state_.reset(); diff --git a/esphome/components/lvgl/text/lvgl_text.h b/esphome/components/lvgl/text/lvgl_text.h index d3513c3697..4c380d69a2 100644 --- a/esphome/components/lvgl/text/lvgl_text.h +++ b/esphome/components/lvgl/text/lvgl_text.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/components/text/text.h" #include "esphome/core/automation.h" #include "esphome/core/component.h" @@ -11,7 +13,7 @@ namespace lvgl { class LVGLText : public text::Text { public: void set_control_lambda(std::function control_lambda) { - this->control_lambda_ = control_lambda; + this->control_lambda_ = std::move(control_lambda); if (this->initial_state_.has_value()) { this->control_lambda_(this->initial_state_.value()); this->initial_state_.reset(); From 5646ec7f9c601b5b3a0c1917edeae5b4487eff79 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 14 Aug 2024 23:41:29 +0200 Subject: [PATCH 2238/2607] [code-quality] fix clang-tidy prometheus (#7284) --- esphome/components/prometheus/prometheus_handler.cpp | 2 ++ esphome/components/prometheus/prometheus_handler.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index 09913bd713..3e9cf81e6e 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -1,4 +1,5 @@ #include "prometheus_handler.h" +#ifdef USE_NETWORK #include "esphome/core/application.h" namespace esphome { @@ -350,3 +351,4 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) } // namespace prometheus } // namespace esphome +#endif diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index a9505a3572..f5e49a1419 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include #include @@ -117,3 +118,4 @@ class PrometheusHandler : public AsyncWebHandler, public Component { } // namespace prometheus } // namespace esphome +#endif From 1bc3ccd96907ff392d4e321e5cc1e5833e107ccd Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 00:30:29 +0200 Subject: [PATCH 2239/2607] [code-quality] fix clang-tidy ota (#7282) --- esphome/components/esphome/ota/ota_esphome.cpp | 3 ++- esphome/components/esphome/ota/ota_esphome.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/esphome/ota/ota_esphome.cpp b/esphome/components/esphome/ota/ota_esphome.cpp index 9d5044aaeb..7e2ef42a97 100644 --- a/esphome/components/esphome/ota/ota_esphome.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -1,5 +1,5 @@ #include "ota_esphome.h" - +#ifdef USE_OTA #include "esphome/components/md5/md5.h" #include "esphome/components/network/util.h" #include "esphome/components/ota/ota_backend.h" @@ -410,3 +410,4 @@ float ESPHomeOTAComponent::get_setup_priority() const { return setup_priority::A uint16_t ESPHomeOTAComponent::get_port() const { return this->port_; } void ESPHomeOTAComponent::set_port(uint16_t port) { this->port_ = port; } } // namespace esphome +#endif diff --git a/esphome/components/esphome/ota/ota_esphome.h b/esphome/components/esphome/ota/ota_esphome.h index 42629b4346..e0d09ff37e 100644 --- a/esphome/components/esphome/ota/ota_esphome.h +++ b/esphome/components/esphome/ota/ota_esphome.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/defines.h" +#ifdef USE_OTA #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" #include "esphome/components/ota/ota_backend.h" @@ -41,3 +42,4 @@ class ESPHomeOTAComponent : public ota::OTAComponent { }; } // namespace esphome +#endif From ce7adbae995ecd4dbb3368678d6de5be9d1d4855 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 00:31:19 +0200 Subject: [PATCH 2240/2607] [code-quality] fix clang-tidy e131 (#7281) --- esphome/components/e131/e131.cpp | 2 ++ esphome/components/e131/e131.h | 4 +++- esphome/components/e131/e131_addressable_light_effect.cpp | 2 ++ esphome/components/e131/e131_addressable_light_effect.h | 3 ++- esphome/components/e131/e131_packet.cpp | 2 ++ 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/esphome/components/e131/e131.cpp b/esphome/components/e131/e131.cpp index c3ff21c1a0..a74fc9be4a 100644 --- a/esphome/components/e131/e131.cpp +++ b/esphome/components/e131/e131.cpp @@ -1,4 +1,5 @@ #include "e131.h" +#ifdef USE_NETWORK #include "e131_addressable_light_effect.h" #include "esphome/core/log.h" @@ -118,3 +119,4 @@ bool E131Component::process_(int universe, const E131Packet &packet) { } // namespace e131 } // namespace esphome +#endif diff --git a/esphome/components/e131/e131.h b/esphome/components/e131/e131.h index 91b67f62eb..d0e38fa98c 100644 --- a/esphome/components/e131/e131.h +++ b/esphome/components/e131/e131.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include "esphome/components/socket/socket.h" #include "esphome/core/component.h" @@ -53,3 +54,4 @@ class E131Component : public esphome::Component { } // namespace e131 } // namespace esphome +#endif diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index be3144f590..4d1f98ab6c 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -1,5 +1,6 @@ #include "e131_addressable_light_effect.h" #include "e131.h" +#ifdef USE_NETWORK #include "esphome/core/log.h" namespace esphome { @@ -90,3 +91,4 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet } // namespace e131 } // namespace esphome +#endif diff --git a/esphome/components/e131/e131_addressable_light_effect.h b/esphome/components/e131/e131_addressable_light_effect.h index 56df9cd80f..17d7bd2829 100644 --- a/esphome/components/e131/e131_addressable_light_effect.h +++ b/esphome/components/e131/e131_addressable_light_effect.h @@ -2,7 +2,7 @@ #include "esphome/core/component.h" #include "esphome/components/light/addressable_light_effect.h" - +#ifdef USE_NETWORK namespace esphome { namespace e131 { @@ -42,3 +42,4 @@ class E131AddressableLightEffect : public light::AddressableLightEffect { } // namespace e131 } // namespace esphome +#endif diff --git a/esphome/components/e131/e131_packet.cpp b/esphome/components/e131/e131_packet.cpp index e1ae41cbaf..b8fa73b707 100644 --- a/esphome/components/e131/e131_packet.cpp +++ b/esphome/components/e131/e131_packet.cpp @@ -1,5 +1,6 @@ #include #include "e131.h" +#ifdef USE_NETWORK #include "esphome/components/network/ip_address.h" #include "esphome/core/log.h" #include "esphome/core/util.h" @@ -137,3 +138,4 @@ bool E131Component::packet_(const std::vector &data, int &universe, E13 } // namespace e131 } // namespace esphome +#endif From ecd3d838c937d59bd9ee71d0ea714034033d8c4c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:35:03 +1000 Subject: [PATCH 2241/2607] [api] Bump noise-c library version (#7288) --- .github/workflows/ci.yml | 4 ++-- esphome/components/api/__init__.py | 2 +- esphome/components/host/__init__.py | 10 +++------- tests/components/api/common.yaml | 4 ---- tests/components/api/test.esp32-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-idf.yaml | 4 ++++ tests/components/api/test.esp32-idf.yaml | 4 ++++ tests/components/api/test.esp8266-ard.yaml | 4 ++++ tests/components/api/test.host.yaml | 3 +++ tests/components/api/test.rp2040-ard.yaml | 4 ++++ 11 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 tests/components/api/test.host.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 126a541b3d..2437dd5b8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -397,7 +397,7 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 @@ -451,7 +451,7 @@ jobs: run: echo ${{ matrix.components }} - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 38b50d4b9d..27de5c873b 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -155,7 +155,7 @@ async def to_code(config): decoded = base64.b64decode(encryption_config[CONF_KEY]) cg.add(var.set_noise_psk(list(decoded))) cg.add_define("USE_API_NOISE") - cg.add_library("esphome/noise-c", "0.1.4") + cg.add_library("esphome/noise-c", "0.1.6") else: cg.add_define("USE_API_PLAINTEXT") diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 39e418c9ea..e83bf2dba8 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -1,15 +1,14 @@ +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( + CONF_MAC_ADDRESS, KEY_CORE, KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_HOST, - CONF_MAC_ADDRESS, ) from esphome.core import CORE -from esphome.helpers import IS_MACOS -import esphome.config_validation as cv -import esphome.codegen as cg from .const import KEY_HOST @@ -42,8 +41,5 @@ async def to_code(config): cg.add_build_flag("-DUSE_HOST") cg.add_define("USE_ESPHOME_HOST_MAC_ADDRESS", config[CONF_MAC_ADDRESS].parts) cg.add_build_flag("-std=c++17") - cg.add_build_flag("-lsodium") - if IS_MACOS: - cg.add_build_flag("-L/opt/homebrew/lib") cg.add_define("ESPHOME_BOARD", "host") cg.add_platformio_option("platform", "platformio/native") diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml index 6c2a333598..7ac11e4da6 100644 --- a/tests/components/api/common.yaml +++ b/tests/components/api/common.yaml @@ -11,10 +11,6 @@ esphome: message: Button was pressed - homeassistant.tag_scanned: pulse -wifi: - ssid: MySSID - password: password1 - api: port: 8000 password: pwd diff --git a/tests/components/api/test.esp32-ard.yaml b/tests/components/api/test.esp32-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-ard.yaml +++ b/tests/components/api/test.esp32-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-ard.yaml b/tests/components/api/test.esp32-c3-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-ard.yaml +++ b/tests/components/api/test.esp32-c3-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-idf.yaml b/tests/components/api/test.esp32-c3-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-idf.yaml +++ b/tests/components/api/test.esp32-c3-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-idf.yaml b/tests/components/api/test.esp32-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-idf.yaml +++ b/tests/components/api/test.esp32-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp8266-ard.yaml b/tests/components/api/test.esp8266-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp8266-ard.yaml +++ b/tests/components/api/test.esp8266-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.host.yaml b/tests/components/api/test.host.yaml new file mode 100644 index 0000000000..1ecafeab77 --- /dev/null +++ b/tests/components/api/test.host.yaml @@ -0,0 +1,3 @@ +<<: !include common.yaml + +network: diff --git a/tests/components/api/test.rp2040-ard.yaml b/tests/components/api/test.rp2040-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.rp2040-ard.yaml +++ b/tests/components/api/test.rp2040-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 From 965141fad75618afea619e9d4b7dfd8ac4007c89 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 06:38:49 +0200 Subject: [PATCH 2242/2607] [code-quality] fix clang-tidy wireguard (#7287) --- esphome/components/wireguard/__init__.py | 15 +++++++++------ esphome/components/wireguard/wireguard.cpp | 3 ++- esphome/components/wireguard/wireguard.h | 4 +++- esphome/core/defines.h | 1 + 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py index 16d0d0226e..5e34a8a19b 100644 --- a/esphome/components/wireguard/__init__.py +++ b/esphome/components/wireguard/__init__.py @@ -1,19 +1,20 @@ -import re import ipaddress +import re + +from esphome import automation import esphome.codegen as cg +from esphome.components import time +from esphome.components.esp32 import CORE, add_idf_sdkconfig_option import esphome.config_validation as cv from esphome.const import ( - CONF_ID, - CONF_TIME_ID, CONF_ADDRESS, + CONF_ID, CONF_REBOOT_TIMEOUT, + CONF_TIME_ID, KEY_CORE, KEY_FRAMEWORK_VERSION, ) -from esphome.components.esp32 import CORE, add_idf_sdkconfig_option -from esphome.components import time from esphome.core import TimePeriod -from esphome import automation CONF_NETMASK = "netmask" CONF_PRIVATE_KEY = "private_key" @@ -91,6 +92,8 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) + cg.add_define("USE_WIREGUARD") + cg.add(var.set_address(str(config[CONF_ADDRESS]))) cg.add(var.set_netmask(str(config[CONF_NETMASK]))) cg.add(var.set_private_key(config[CONF_PRIVATE_KEY])) diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp index 17ebc701e3..7b4011cb79 100644 --- a/esphome/components/wireguard/wireguard.cpp +++ b/esphome/components/wireguard/wireguard.cpp @@ -1,5 +1,5 @@ #include "wireguard.h" - +#ifdef USE_WIREGUARD #include #include #include @@ -289,3 +289,4 @@ std::string mask_key(const std::string &key) { return (key.substr(0, 5) + "[...] } // namespace wireguard } // namespace esphome +#endif diff --git a/esphome/components/wireguard/wireguard.h b/esphome/components/wireguard/wireguard.h index a0e9e27a1b..5db9a48c90 100644 --- a/esphome/components/wireguard/wireguard.h +++ b/esphome/components/wireguard/wireguard.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_WIREGUARD #include #include #include @@ -170,3 +171,4 @@ template class WireguardDisableAction : public Action, pu } // namespace wireguard } // namespace esphome +#endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index a4d473b76e..52cf7d4dd0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -75,6 +75,7 @@ #define USE_VALVE #define USE_WIFI #define USE_WIFI_AP +#define USE_WIREGUARD // Arduino-specific feature flags #ifdef USE_ARDUINO From 5c31ab40607a9418ada87ad19f59abb85eb5db83 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 15 Aug 2024 06:51:44 +0200 Subject: [PATCH 2243/2607] fix some small rtttl issues (#6817) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/rtttl/rtttl.cpp | 127 ++++++++++++++++++++++++----- esphome/components/rtttl/rtttl.h | 21 +++-- 2 files changed, 121 insertions(+), 27 deletions(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 0bdf65b7bd..a97120499d 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -29,6 +29,13 @@ inline double deg2rad(double degrees) { void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); } void Rtttl::play(std::string rtttl) { + if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { + int pos = this->rtttl_.find(':'); + auto name = this->rtttl_.substr(0, pos); + ESP_LOGW(TAG, "RTTL Component is already playing: %s", name.c_str()); + return; + } + this->rtttl_ = std::move(rtttl); this->default_duration_ = 4; @@ -98,13 +105,20 @@ void Rtttl::play(std::string rtttl) { this->note_duration_ = 1; #ifdef USE_SPEAKER - this->samples_sent_ = 0; - this->samples_count_ = 0; + if (this->speaker_ != nullptr) { + this->set_state_(State::STATE_INIT); + this->samples_sent_ = 0; + this->samples_count_ = 0; + } +#endif +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->set_state_(State::STATE_RUNNING); + } #endif } void Rtttl::stop() { - this->note_duration_ = 0; #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); @@ -117,16 +131,35 @@ void Rtttl::stop() { } } #endif + this->note_duration_ = 0; + this->set_state_(STATE_STOPPING); } void Rtttl::loop() { - if (this->note_duration_ == 0) + if (this->note_duration_ == 0 || this->state_ == State::STATE_STOPPED) return; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { + if (this->state_ == State::STATE_STOPPING) { + if (this->speaker_->is_stopped()) { + this->set_state_(State::STATE_STOPPED); + } + } else if (this->state_ == State::STATE_INIT) { + if (this->speaker_->is_stopped()) { + this->speaker_->start(); + this->set_state_(State::STATE_STARTING); + } + } else if (this->state_ == State::STATE_STARTING) { + if (this->speaker_->is_running()) { + this->set_state_(State::STATE_RUNNING); + } + } + if (!this->speaker_->is_running()) { + return; + } if (this->samples_sent_ != this->samples_count_) { - SpeakerSample sample[SAMPLE_BUFFER_SIZE + 1]; + SpeakerSample sample[SAMPLE_BUFFER_SIZE + 2]; int x = 0; double rem = 0.0; @@ -136,7 +169,7 @@ void Rtttl::loop() { if (this->samples_per_wave_ != 0 && this->samples_sent_ >= this->samples_gap_) { // Play note// rem = ((this->samples_sent_ << 10) % this->samples_per_wave_) * (360.0 / this->samples_per_wave_); - int16_t val = (49152 * this->gain_) * sin(deg2rad(rem)); + int16_t val = (127 * this->gain_) * sin(deg2rad(rem)); // 16bit = 49152 sample[x].left = val; sample[x].right = val; @@ -153,9 +186,9 @@ void Rtttl::loop() { x++; } if (x > 0) { - int send = this->speaker_->play((uint8_t *) (&sample), x * 4); + int send = this->speaker_->play((uint8_t *) (&sample), x * 2); if (send != x * 4) { - this->samples_sent_ -= (x - (send / 4)); + this->samples_sent_ -= (x - (send / 2)); } return; } @@ -167,14 +200,7 @@ void Rtttl::loop() { return; #endif if (!this->rtttl_[position_]) { - this->note_duration_ = 0; -#ifdef USE_OUTPUT - if (this->output_ != nullptr) { - this->output_->set_level(0.0); - } -#endif - ESP_LOGD(TAG, "Playback finished"); - this->on_finished_playback_callback_.call(); + this->finish_(); return; } @@ -213,6 +239,7 @@ void Rtttl::loop() { case 'a': note = 10; break; + case 'h': case 'b': note = 12; break; @@ -238,14 +265,21 @@ void Rtttl::loop() { uint8_t scale = get_integer_(); if (scale == 0) scale = this->default_octave_; + + if (scale < 4 || scale > 7) { + ESP_LOGE(TAG, "Octave out of valid range. Should be between 4 and 7. (Octave: %d)", scale); + this->finish_(); + return; + } bool need_note_gap = false; // Now play the note if (note) { auto note_index = (scale - 4) * 12 + note; if (note_index < 0 || note_index >= (int) sizeof(NOTES)) { - ESP_LOGE(TAG, "Note out of valid range"); - this->note_duration_ = 0; + ESP_LOGE(TAG, "Note out of valid range (note: %d, scale: %d, index: %d, max: %d)", note, scale, note_index, + (int) sizeof(NOTES)); + this->finish_(); return; } auto freq = NOTES[note_index]; @@ -285,14 +319,17 @@ void Rtttl::loop() { this->samples_gap_ = (this->sample_rate_ * DOUBLE_NOTE_GAP_MS) / 1600; //(ms); } if (this->output_freq_ != 0) { + // make sure there is enough samples to add a full last sinus. + + uint16_t samples_wish = this->samples_count_; this->samples_per_wave_ = (this->sample_rate_ << 10) / this->output_freq_; - // make sure there is enough samples to add a full last sinus. uint16_t division = ((this->samples_count_ << 10) / this->samples_per_wave_) + 1; - uint16_t x = this->samples_count_; + this->samples_count_ = (division * this->samples_per_wave_); - ESP_LOGD(TAG, "play time old: %d div: %d new: %d %d", x, division, this->samples_count_, this->samples_per_wave_); this->samples_count_ = this->samples_count_ >> 10; + ESP_LOGVV(TAG, "- Calc play time: wish: %d gets: %d (div: %d spw: %d)", samples_wish, this->samples_count_, + division, this->samples_per_wave_); } // Convert from frequency in Hz to high and low samples in fixed point } @@ -301,5 +338,53 @@ void Rtttl::loop() { this->last_note_ = millis(); } +void Rtttl::finish_() { +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->output_->set_level(0.0); + } +#endif +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + SpeakerSample sample[2]; + sample[0].left = 0; + sample[0].right = 0; + sample[1].left = 0; + sample[1].right = 0; + this->speaker_->play((uint8_t *) (&sample), 8); + + this->speaker_->finish(); + } +#endif + this->set_state_(State::STATE_STOPPING); + this->note_duration_ = 0; + this->on_finished_playback_callback_.call(); + ESP_LOGD(TAG, "Playback finished"); +} + +static const LogString *state_to_string(State state) { + switch (state) { + case STATE_STOPPED: + return LOG_STR("STATE_STOPPED"); + case STATE_STARTING: + return LOG_STR("STATE_STARTING"); + case STATE_RUNNING: + return LOG_STR("STATE_RUNNING"); + case STATE_STOPPING: + return LOG_STR("STATE_STOPPING"); + case STATE_INIT: + return LOG_STR("STATE_INIT"); + default: + return LOG_STR("UNKNOWN"); + } +}; + +void Rtttl::set_state_(State state) { + State old_state = this->state_; + this->state_ = state; + ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(state_to_string(old_state)), + LOG_STR_ARG(state_to_string(state))); +} + } // namespace rtttl } // namespace esphome diff --git a/esphome/components/rtttl/rtttl.h b/esphome/components/rtttl/rtttl.h index bf089ce980..3cb6e3f5fb 100644 --- a/esphome/components/rtttl/rtttl.h +++ b/esphome/components/rtttl/rtttl.h @@ -14,12 +14,20 @@ namespace esphome { namespace rtttl { +enum State : uint8_t { + STATE_STOPPED = 0, + STATE_INIT, + STATE_STARTING, + STATE_RUNNING, + STATE_STOPPING, +}; + #ifdef USE_SPEAKER -static const size_t SAMPLE_BUFFER_SIZE = 512; +static const size_t SAMPLE_BUFFER_SIZE = 2048; struct SpeakerSample { - int16_t left{0}; - int16_t right{0}; + int8_t left{0}; + int8_t right{0}; }; #endif @@ -42,7 +50,7 @@ class Rtttl : public Component { void stop(); void dump_config() override; - bool is_playing() { return this->note_duration_ != 0; } + bool is_playing() { return this->state_ != State::STATE_STOPPED; } void loop() override; void add_on_finished_playback_callback(std::function callback) { @@ -57,6 +65,8 @@ class Rtttl : public Component { } return ret; } + void finish_(); + void set_state_(State state); std::string rtttl_{""}; size_t position_{0}; @@ -68,13 +78,12 @@ class Rtttl : public Component { uint32_t output_freq_; float gain_{0.6f}; + State state_{State::STATE_STOPPED}; #ifdef USE_OUTPUT output::FloatOutput *output_; #endif - void play_output_(); - #ifdef USE_SPEAKER speaker::Speaker *speaker_{nullptr}; int sample_rate_{16000}; From 9713458368dfb9fd9aab8016cfe8c85d77b04887 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 07:17:38 +0200 Subject: [PATCH 2244/2607] [code-quality] fix clang-tidy improv_serial (#7283) --- esphome/components/improv_serial/improv_serial_component.cpp | 3 ++- esphome/components/improv_serial/improv_serial_component.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 425a5c8576..c3a0f2eacc 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -1,5 +1,5 @@ #include "improv_serial_component.h" - +#ifdef USE_WIFI #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "esphome/core/hal.h" @@ -313,3 +313,4 @@ ImprovSerialComponent *global_improv_serial_component = // NOLINT(cppcoreguidel } // namespace improv_serial } // namespace esphome +#endif diff --git a/esphome/components/improv_serial/improv_serial_component.h b/esphome/components/improv_serial/improv_serial_component.h index f737f93d86..5d2534c2fc 100644 --- a/esphome/components/improv_serial/improv_serial_component.h +++ b/esphome/components/improv_serial/improv_serial_component.h @@ -5,7 +5,7 @@ #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/helpers.h" - +#ifdef USE_WIFI #include #include @@ -78,3 +78,4 @@ extern ImprovSerialComponent } // namespace improv_serial } // namespace esphome +#endif From abb2669f0fb94c72deb55781bb087c86fe2e382c Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 23:16:06 +0200 Subject: [PATCH 2245/2607] [code-quality] fix clang-tidy captive_portal (#7280) --- esphome/components/captive_portal/captive_portal.cpp | 2 ++ esphome/components/captive_portal/captive_portal.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 630e00f0b7..d1960e9a93 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -1,4 +1,5 @@ #include "captive_portal.h" +#ifdef USE_CAPTIVE_PORTAL #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/components/wifi/wifi_component.h" @@ -91,3 +92,4 @@ CaptivePortal *global_captive_portal = nullptr; // NOLINT(cppcoreguidelines-avo } // namespace captive_portal } // namespace esphome +#endif diff --git a/esphome/components/captive_portal/captive_portal.h b/esphome/components/captive_portal/captive_portal.h index df45d40d12..24d1295e6a 100644 --- a/esphome/components/captive_portal/captive_portal.h +++ b/esphome/components/captive_portal/captive_portal.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_CAPTIVE_PORTAL #include #ifdef USE_ARDUINO #include @@ -71,3 +72,4 @@ extern CaptivePortal *global_captive_portal; // NOLINT(cppcoreguidelines-avoid- } // namespace captive_portal } // namespace esphome +#endif From 9001d1c0d46cf214f989baac9c1f05f4ed321804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Kiss?= <70820303+g-kiss@users.noreply.github.com> Date: Fri, 16 Aug 2024 00:35:00 +0200 Subject: [PATCH 2246/2607] Fix overflow in ESPColorCorrection object (#7268) --- esphome/components/light/esp_color_correction.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/light/esp_color_correction.h b/esphome/components/light/esp_color_correction.h index eedd71ab27..979a1acb07 100644 --- a/esphome/components/light/esp_color_correction.h +++ b/esphome/components/light/esp_color_correction.h @@ -41,29 +41,29 @@ class ESPColorCorrection { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.green == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.white == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } protected: From c3668b9a4de8408c28089c8c0652e0c36119cdcd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:05:26 +1200 Subject: [PATCH 2247/2607] [validation] Allow ``maybe_simple_value`` to not have default key in complex value (#7294) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index ef60d6e0d6..1c00e0699b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1850,7 +1850,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict) and key in value: + if isinstance(value, dict): return validator(value) return validator({key: value}) From a0c54504cdc54521309364609883c002f88ae137 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 00:27:23 +0100 Subject: [PATCH 2248/2607] Add HMAC-MD5 support for authenticating OTA updates (#7200) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/hmac_md5/__init__.py | 2 + esphome/components/hmac_md5/hmac_md5.cpp | 56 ++++++++++++++++++++++++ esphome/components/hmac_md5/hmac_md5.h | 48 ++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 esphome/components/hmac_md5/__init__.py create mode 100644 esphome/components/hmac_md5/hmac_md5.cpp create mode 100644 esphome/components/hmac_md5/hmac_md5.h diff --git a/CODEOWNERS b/CODEOWNERS index 1236c8d842..9159f5f843 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -169,6 +169,7 @@ esphome/components/he60r/* @clydebarrow esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hm3301/* @freekode +esphome/components/hmac_md5/* @dwmw2 esphome/components/homeassistant/* @OttoWinter @esphome/core esphome/components/homeassistant/number/* @landonr esphome/components/homeassistant/switch/* @Links2004 diff --git a/esphome/components/hmac_md5/__init__.py b/esphome/components/hmac_md5/__init__.py new file mode 100644 index 0000000000..fe245c0cfd --- /dev/null +++ b/esphome/components/hmac_md5/__init__.py @@ -0,0 +1,2 @@ +AUTO_LOAD = ["md5"] +CODEOWNERS = ["@dwmw2"] diff --git a/esphome/components/hmac_md5/hmac_md5.cpp b/esphome/components/hmac_md5/hmac_md5.cpp new file mode 100644 index 0000000000..90bf91882f --- /dev/null +++ b/esphome/components/hmac_md5/hmac_md5.cpp @@ -0,0 +1,56 @@ +#include +#include +#include "hmac_md5.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace hmac_md5 { +void HmacMD5::init(const uint8_t *key, size_t len) { + uint8_t ipad[64], opad[64]; + + memset(ipad, 0, sizeof(ipad)); + if (len > 64) { + md5::MD5Digest keymd5; + keymd5.init(); + keymd5.add(key, len); + keymd5.calculate(); + keymd5.get_bytes(ipad); + } else { + memcpy(ipad, key, len); + } + memcpy(opad, ipad, sizeof(opad)); + + for (int i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + this->ihash_.init(); + this->ihash_.add(ipad, sizeof(ipad)); + + this->ohash_.init(); + this->ohash_.add(opad, sizeof(opad)); +} + +void HmacMD5::add(const uint8_t *data, size_t len) { this->ihash_.add(data, len); } + +void HmacMD5::calculate() { + uint8_t ibytes[16]; + + this->ihash_.calculate(); + this->ihash_.get_bytes(ibytes); + + this->ohash_.add(ibytes, sizeof(ibytes)); + this->ohash_.calculate(); +} + +void HmacMD5::get_bytes(uint8_t *output) { this->ohash_.get_bytes(output); } + +void HmacMD5::get_hex(char *output) { this->ohash_.get_hex(output); } + +bool HmacMD5::equals_bytes(const uint8_t *expected) { return this->ohash_.equals_bytes(expected); } + +bool HmacMD5::equals_hex(const char *expected) { return this->ohash_.equals_hex(expected); } + +} // namespace hmac_md5 +} // namespace esphome diff --git a/esphome/components/hmac_md5/hmac_md5.h b/esphome/components/hmac_md5/hmac_md5.h new file mode 100644 index 0000000000..e6a97ad2e3 --- /dev/null +++ b/esphome/components/hmac_md5/hmac_md5.h @@ -0,0 +1,48 @@ +#pragma once + +#include "esphome/core/defines.h" +#include "esphome/components/md5/md5.h" + +#include + +namespace esphome { +namespace hmac_md5 { + +class HmacMD5 { + public: + HmacMD5() = default; + ~HmacMD5() = default; + + /// Initialize a new MD5 digest computation. + void init(const uint8_t *key, size_t len); + void init(const char *key, size_t len) { this->init((const uint8_t *) key, len); } + void init(const std::string &key) { this->init(key.c_str(), key.length()); } + + /// Add bytes of data for the digest. + void add(const uint8_t *data, size_t len); + void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); } + + /// Compute the digest, based on the provided data. + void calculate(); + + /// Retrieve the HMAC-MD5 digest as bytes. + /// The output must be able to hold 16 bytes or more. + void get_bytes(uint8_t *output); + + /// Retrieve the HMAC-MD5 digest as hex characters. + /// The output must be able to hold 32 bytes or more. + void get_hex(char *output); + + /// Compare the digest against a provided byte-encoded digest (16 bytes). + bool equals_bytes(const uint8_t *expected); + + /// Compare the digest against a provided hex-encoded digest (32 bytes). + bool equals_hex(const char *expected); + + protected: + md5::MD5Digest ihash_; + md5::MD5Digest ohash_; +}; + +} // namespace hmac_md5 +} // namespace esphome From a7167ec3bf1adaec467944586c71d442a93a68d2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 02:32:00 +0100 Subject: [PATCH 2249/2607] [network] Always allow ``enable_ipv6: false`` (#7291) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 6 +++++- esphome/config_validation.py | 14 ++++++++++++++ tests/components/network/test-ipv6.bk72xx-ard.yaml | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/components/network/test-ipv6.bk72xx-ard.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96db322bde..caa873a746 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -24,7 +24,11 @@ CONFIG_SCHEMA = cv.Schema( esp32=False, rp2040=False, ): cv.All( - cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + cv.boolean, + cv.Any( + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), + cv.boolean_false, + ), ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 1c00e0699b..6d6cb451d6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -370,6 +370,20 @@ def boolean(value): ) +def boolean_false(value): + """Validate the given config option to be a boolean, set to False. + + This option allows a bunch of different ways of expressing boolean values: + - instance of boolean + - 'true'/'false' + - 'yes'/'no' + - 'enable'/disable + """ + if boolean(value): + raise Invalid("Expected boolean value to be false") + return False + + @schema_extractor_list def ensure_list(*validators): """Validate this configuration option to be a list. diff --git a/tests/components/network/test-ipv6.bk72xx-ard.yaml b/tests/components/network/test-ipv6.bk72xx-ard.yaml new file mode 100644 index 0000000000..361ca09977 --- /dev/null +++ b/tests/components/network/test-ipv6.bk72xx-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "false" + +<<: !include common.yaml From bc20fd57fe3bdd52a5ed5000d29b90063f76dd0a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 14 Aug 2024 00:55:23 -0700 Subject: [PATCH 2250/2607] remove extra number from pronto (#7263) --- esphome/components/remote_base/pronto_protocol.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 625af76235..35fd782248 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -201,9 +201,6 @@ std::string ProntoProtocol::compensate_and_dump_sequence_(const RawTimings &data out += dump_duration_(t_duration, timebase); } - // append minimum gap - out += dump_duration_(PRONTO_DEFAULT_GAP, timebase, true); - return out; } From e3bfbebb8fd3368ac3c351af33407cf77956910d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:35:03 +1000 Subject: [PATCH 2251/2607] [api] Bump noise-c library version (#7288) --- .github/workflows/ci.yml | 4 ++-- esphome/components/api/__init__.py | 2 +- esphome/components/host/__init__.py | 10 +++------- tests/components/api/common.yaml | 4 ---- tests/components/api/test.esp32-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-idf.yaml | 4 ++++ tests/components/api/test.esp32-idf.yaml | 4 ++++ tests/components/api/test.esp8266-ard.yaml | 4 ++++ tests/components/api/test.host.yaml | 3 +++ tests/components/api/test.rp2040-ard.yaml | 4 ++++ 11 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 tests/components/api/test.host.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 126a541b3d..2437dd5b8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -397,7 +397,7 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 @@ -451,7 +451,7 @@ jobs: run: echo ${{ matrix.components }} - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 38b50d4b9d..27de5c873b 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -155,7 +155,7 @@ async def to_code(config): decoded = base64.b64decode(encryption_config[CONF_KEY]) cg.add(var.set_noise_psk(list(decoded))) cg.add_define("USE_API_NOISE") - cg.add_library("esphome/noise-c", "0.1.4") + cg.add_library("esphome/noise-c", "0.1.6") else: cg.add_define("USE_API_PLAINTEXT") diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 39e418c9ea..e83bf2dba8 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -1,15 +1,14 @@ +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( + CONF_MAC_ADDRESS, KEY_CORE, KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_HOST, - CONF_MAC_ADDRESS, ) from esphome.core import CORE -from esphome.helpers import IS_MACOS -import esphome.config_validation as cv -import esphome.codegen as cg from .const import KEY_HOST @@ -42,8 +41,5 @@ async def to_code(config): cg.add_build_flag("-DUSE_HOST") cg.add_define("USE_ESPHOME_HOST_MAC_ADDRESS", config[CONF_MAC_ADDRESS].parts) cg.add_build_flag("-std=c++17") - cg.add_build_flag("-lsodium") - if IS_MACOS: - cg.add_build_flag("-L/opt/homebrew/lib") cg.add_define("ESPHOME_BOARD", "host") cg.add_platformio_option("platform", "platformio/native") diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml index 6c2a333598..7ac11e4da6 100644 --- a/tests/components/api/common.yaml +++ b/tests/components/api/common.yaml @@ -11,10 +11,6 @@ esphome: message: Button was pressed - homeassistant.tag_scanned: pulse -wifi: - ssid: MySSID - password: password1 - api: port: 8000 password: pwd diff --git a/tests/components/api/test.esp32-ard.yaml b/tests/components/api/test.esp32-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-ard.yaml +++ b/tests/components/api/test.esp32-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-ard.yaml b/tests/components/api/test.esp32-c3-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-ard.yaml +++ b/tests/components/api/test.esp32-c3-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-idf.yaml b/tests/components/api/test.esp32-c3-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-idf.yaml +++ b/tests/components/api/test.esp32-c3-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-idf.yaml b/tests/components/api/test.esp32-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-idf.yaml +++ b/tests/components/api/test.esp32-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp8266-ard.yaml b/tests/components/api/test.esp8266-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp8266-ard.yaml +++ b/tests/components/api/test.esp8266-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.host.yaml b/tests/components/api/test.host.yaml new file mode 100644 index 0000000000..1ecafeab77 --- /dev/null +++ b/tests/components/api/test.host.yaml @@ -0,0 +1,3 @@ +<<: !include common.yaml + +network: diff --git a/tests/components/api/test.rp2040-ard.yaml b/tests/components/api/test.rp2040-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.rp2040-ard.yaml +++ b/tests/components/api/test.rp2040-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 From e17c7124f48ac3fc2fbc2c45bbe01b23a203f65a Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 15 Aug 2024 06:51:44 +0200 Subject: [PATCH 2252/2607] fix some small rtttl issues (#6817) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/rtttl/rtttl.cpp | 127 ++++++++++++++++++++++++----- esphome/components/rtttl/rtttl.h | 21 +++-- 2 files changed, 121 insertions(+), 27 deletions(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 0bdf65b7bd..a97120499d 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -29,6 +29,13 @@ inline double deg2rad(double degrees) { void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); } void Rtttl::play(std::string rtttl) { + if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { + int pos = this->rtttl_.find(':'); + auto name = this->rtttl_.substr(0, pos); + ESP_LOGW(TAG, "RTTL Component is already playing: %s", name.c_str()); + return; + } + this->rtttl_ = std::move(rtttl); this->default_duration_ = 4; @@ -98,13 +105,20 @@ void Rtttl::play(std::string rtttl) { this->note_duration_ = 1; #ifdef USE_SPEAKER - this->samples_sent_ = 0; - this->samples_count_ = 0; + if (this->speaker_ != nullptr) { + this->set_state_(State::STATE_INIT); + this->samples_sent_ = 0; + this->samples_count_ = 0; + } +#endif +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->set_state_(State::STATE_RUNNING); + } #endif } void Rtttl::stop() { - this->note_duration_ = 0; #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); @@ -117,16 +131,35 @@ void Rtttl::stop() { } } #endif + this->note_duration_ = 0; + this->set_state_(STATE_STOPPING); } void Rtttl::loop() { - if (this->note_duration_ == 0) + if (this->note_duration_ == 0 || this->state_ == State::STATE_STOPPED) return; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { + if (this->state_ == State::STATE_STOPPING) { + if (this->speaker_->is_stopped()) { + this->set_state_(State::STATE_STOPPED); + } + } else if (this->state_ == State::STATE_INIT) { + if (this->speaker_->is_stopped()) { + this->speaker_->start(); + this->set_state_(State::STATE_STARTING); + } + } else if (this->state_ == State::STATE_STARTING) { + if (this->speaker_->is_running()) { + this->set_state_(State::STATE_RUNNING); + } + } + if (!this->speaker_->is_running()) { + return; + } if (this->samples_sent_ != this->samples_count_) { - SpeakerSample sample[SAMPLE_BUFFER_SIZE + 1]; + SpeakerSample sample[SAMPLE_BUFFER_SIZE + 2]; int x = 0; double rem = 0.0; @@ -136,7 +169,7 @@ void Rtttl::loop() { if (this->samples_per_wave_ != 0 && this->samples_sent_ >= this->samples_gap_) { // Play note// rem = ((this->samples_sent_ << 10) % this->samples_per_wave_) * (360.0 / this->samples_per_wave_); - int16_t val = (49152 * this->gain_) * sin(deg2rad(rem)); + int16_t val = (127 * this->gain_) * sin(deg2rad(rem)); // 16bit = 49152 sample[x].left = val; sample[x].right = val; @@ -153,9 +186,9 @@ void Rtttl::loop() { x++; } if (x > 0) { - int send = this->speaker_->play((uint8_t *) (&sample), x * 4); + int send = this->speaker_->play((uint8_t *) (&sample), x * 2); if (send != x * 4) { - this->samples_sent_ -= (x - (send / 4)); + this->samples_sent_ -= (x - (send / 2)); } return; } @@ -167,14 +200,7 @@ void Rtttl::loop() { return; #endif if (!this->rtttl_[position_]) { - this->note_duration_ = 0; -#ifdef USE_OUTPUT - if (this->output_ != nullptr) { - this->output_->set_level(0.0); - } -#endif - ESP_LOGD(TAG, "Playback finished"); - this->on_finished_playback_callback_.call(); + this->finish_(); return; } @@ -213,6 +239,7 @@ void Rtttl::loop() { case 'a': note = 10; break; + case 'h': case 'b': note = 12; break; @@ -238,14 +265,21 @@ void Rtttl::loop() { uint8_t scale = get_integer_(); if (scale == 0) scale = this->default_octave_; + + if (scale < 4 || scale > 7) { + ESP_LOGE(TAG, "Octave out of valid range. Should be between 4 and 7. (Octave: %d)", scale); + this->finish_(); + return; + } bool need_note_gap = false; // Now play the note if (note) { auto note_index = (scale - 4) * 12 + note; if (note_index < 0 || note_index >= (int) sizeof(NOTES)) { - ESP_LOGE(TAG, "Note out of valid range"); - this->note_duration_ = 0; + ESP_LOGE(TAG, "Note out of valid range (note: %d, scale: %d, index: %d, max: %d)", note, scale, note_index, + (int) sizeof(NOTES)); + this->finish_(); return; } auto freq = NOTES[note_index]; @@ -285,14 +319,17 @@ void Rtttl::loop() { this->samples_gap_ = (this->sample_rate_ * DOUBLE_NOTE_GAP_MS) / 1600; //(ms); } if (this->output_freq_ != 0) { + // make sure there is enough samples to add a full last sinus. + + uint16_t samples_wish = this->samples_count_; this->samples_per_wave_ = (this->sample_rate_ << 10) / this->output_freq_; - // make sure there is enough samples to add a full last sinus. uint16_t division = ((this->samples_count_ << 10) / this->samples_per_wave_) + 1; - uint16_t x = this->samples_count_; + this->samples_count_ = (division * this->samples_per_wave_); - ESP_LOGD(TAG, "play time old: %d div: %d new: %d %d", x, division, this->samples_count_, this->samples_per_wave_); this->samples_count_ = this->samples_count_ >> 10; + ESP_LOGVV(TAG, "- Calc play time: wish: %d gets: %d (div: %d spw: %d)", samples_wish, this->samples_count_, + division, this->samples_per_wave_); } // Convert from frequency in Hz to high and low samples in fixed point } @@ -301,5 +338,53 @@ void Rtttl::loop() { this->last_note_ = millis(); } +void Rtttl::finish_() { +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->output_->set_level(0.0); + } +#endif +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + SpeakerSample sample[2]; + sample[0].left = 0; + sample[0].right = 0; + sample[1].left = 0; + sample[1].right = 0; + this->speaker_->play((uint8_t *) (&sample), 8); + + this->speaker_->finish(); + } +#endif + this->set_state_(State::STATE_STOPPING); + this->note_duration_ = 0; + this->on_finished_playback_callback_.call(); + ESP_LOGD(TAG, "Playback finished"); +} + +static const LogString *state_to_string(State state) { + switch (state) { + case STATE_STOPPED: + return LOG_STR("STATE_STOPPED"); + case STATE_STARTING: + return LOG_STR("STATE_STARTING"); + case STATE_RUNNING: + return LOG_STR("STATE_RUNNING"); + case STATE_STOPPING: + return LOG_STR("STATE_STOPPING"); + case STATE_INIT: + return LOG_STR("STATE_INIT"); + default: + return LOG_STR("UNKNOWN"); + } +}; + +void Rtttl::set_state_(State state) { + State old_state = this->state_; + this->state_ = state; + ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(state_to_string(old_state)), + LOG_STR_ARG(state_to_string(state))); +} + } // namespace rtttl } // namespace esphome diff --git a/esphome/components/rtttl/rtttl.h b/esphome/components/rtttl/rtttl.h index bf089ce980..3cb6e3f5fb 100644 --- a/esphome/components/rtttl/rtttl.h +++ b/esphome/components/rtttl/rtttl.h @@ -14,12 +14,20 @@ namespace esphome { namespace rtttl { +enum State : uint8_t { + STATE_STOPPED = 0, + STATE_INIT, + STATE_STARTING, + STATE_RUNNING, + STATE_STOPPING, +}; + #ifdef USE_SPEAKER -static const size_t SAMPLE_BUFFER_SIZE = 512; +static const size_t SAMPLE_BUFFER_SIZE = 2048; struct SpeakerSample { - int16_t left{0}; - int16_t right{0}; + int8_t left{0}; + int8_t right{0}; }; #endif @@ -42,7 +50,7 @@ class Rtttl : public Component { void stop(); void dump_config() override; - bool is_playing() { return this->note_duration_ != 0; } + bool is_playing() { return this->state_ != State::STATE_STOPPED; } void loop() override; void add_on_finished_playback_callback(std::function callback) { @@ -57,6 +65,8 @@ class Rtttl : public Component { } return ret; } + void finish_(); + void set_state_(State state); std::string rtttl_{""}; size_t position_{0}; @@ -68,13 +78,12 @@ class Rtttl : public Component { uint32_t output_freq_; float gain_{0.6f}; + State state_{State::STATE_STOPPED}; #ifdef USE_OUTPUT output::FloatOutput *output_; #endif - void play_output_(); - #ifdef USE_SPEAKER speaker::Speaker *speaker_{nullptr}; int sample_rate_{16000}; From 033ab552068374f4ad06dca122a250f18ba2a979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Kiss?= <70820303+g-kiss@users.noreply.github.com> Date: Fri, 16 Aug 2024 00:35:00 +0200 Subject: [PATCH 2253/2607] Fix overflow in ESPColorCorrection object (#7268) --- esphome/components/light/esp_color_correction.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/light/esp_color_correction.h b/esphome/components/light/esp_color_correction.h index eedd71ab27..979a1acb07 100644 --- a/esphome/components/light/esp_color_correction.h +++ b/esphome/components/light/esp_color_correction.h @@ -41,29 +41,29 @@ class ESPColorCorrection { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.green == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.white == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } protected: From 2c47eb62a7f1060be9fc727c8a5fc70ed92c1fd8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:05:26 +1200 Subject: [PATCH 2254/2607] [validation] Allow ``maybe_simple_value`` to not have default key in complex value (#7294) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index ef60d6e0d6..1c00e0699b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1850,7 +1850,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict) and key in value: + if isinstance(value, dict): return validator(value) return validator({key: value}) From 343650e37d29058a5f2ef7caf8c7f868c9b1746c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 02:32:00 +0100 Subject: [PATCH 2255/2607] [network] Always allow ``enable_ipv6: false`` (#7291) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 6 +++++- esphome/config_validation.py | 14 ++++++++++++++ tests/components/network/test-ipv6.bk72xx-ard.yaml | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/components/network/test-ipv6.bk72xx-ard.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96db322bde..caa873a746 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -24,7 +24,11 @@ CONFIG_SCHEMA = cv.Schema( esp32=False, rp2040=False, ): cv.All( - cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + cv.boolean, + cv.Any( + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), + cv.boolean_false, + ), ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 1c00e0699b..6d6cb451d6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -370,6 +370,20 @@ def boolean(value): ) +def boolean_false(value): + """Validate the given config option to be a boolean, set to False. + + This option allows a bunch of different ways of expressing boolean values: + - instance of boolean + - 'true'/'false' + - 'yes'/'no' + - 'enable'/disable + """ + if boolean(value): + raise Invalid("Expected boolean value to be false") + return False + + @schema_extractor_list def ensure_list(*validators): """Validate this configuration option to be a list. diff --git a/tests/components/network/test-ipv6.bk72xx-ard.yaml b/tests/components/network/test-ipv6.bk72xx-ard.yaml new file mode 100644 index 0000000000..361ca09977 --- /dev/null +++ b/tests/components/network/test-ipv6.bk72xx-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "false" + +<<: !include common.yaml From e779a09586e16f03f4544dff36044e6e1318e4a3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:38:06 +1200 Subject: [PATCH 2256/2607] Bump version to 2024.8.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 47aacd6452..39d2ee74a1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0b1" +__version__ = "2024.8.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 56aa58780da5fe73637ed9f583fafbd0b3a26db7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 18 Aug 2024 20:27:03 +1200 Subject: [PATCH 2257/2607] Revert "[validation] Allow ``maybe_simple_value`` to not have default key in complex value" (#7305) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 6d6cb451d6..719cc43b31 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1864,7 +1864,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict): + if isinstance(value, dict) and key in value: return validator(value) return validator({key: value}) From ac9417d4694a69d843457ce3fa40f6e9c959c64a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 19 Aug 2024 08:43:23 +1000 Subject: [PATCH 2258/2607] [lvgl] Bug fixes (#7300) --- esphome/components/lvgl/defines.py | 32 ++++---- esphome/components/lvgl/lv_validation.py | 86 +++++++++++++-------- esphome/components/lvgl/schemas.py | 32 +++++--- esphome/components/lvgl/widgets/__init__.py | 23 +++++- tests/components/lvgl/common.yaml | 8 ++ tests/components/lvgl/lvgl-package.yaml | 58 ++++++++++++-- 6 files changed, 173 insertions(+), 66 deletions(-) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 8f7a973722..6a8b20b505 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -6,8 +6,8 @@ Constants already defined in esphome.const are not duplicated here and must be i from esphome import codegen as cg, config_validation as cv from esphome.const import CONF_ITEMS -from esphome.core import ID, Lambda -from esphome.cpp_generator import MockObj +from esphome.core import Lambda +from esphome.cpp_generator import LambdaExpression, MockObj from esphome.cpp_types import uint32 from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -22,19 +22,22 @@ def literal(arg): return arg +def call_lambda(lamb: LambdaExpression): + expr = lamb.content.strip() + if expr.startswith("return") and expr.endswith(";"): + return expr[7:][:-1] + return f"{lamb}()" + + class LValidator: """ A validator for a particular type used in LVGL. Usable in configs as a validator, also has `process()` to convert a value during code generation """ - def __init__( - self, validator, rtype, idtype=None, idexpr=None, retmapper=None, requires=None - ): + def __init__(self, validator, rtype, retmapper=None, requires=None): self.validator = validator self.rtype = rtype - self.idtype = idtype - self.idexpr = idexpr self.retmapper = retmapper self.requires = requires @@ -43,8 +46,6 @@ class LValidator: value = requires_component(self.requires)(value) if isinstance(value, cv.Lambda): return cv.returning_lambda(value) - if self.idtype is not None and isinstance(value, ID): - return cv.use_id(self.idtype)(value) return self.validator(value) async def process(self, value, args=()): @@ -52,10 +53,10 @@ class LValidator: return None if isinstance(value, Lambda): return cg.RawExpression( - f"{await cg.process_lambda(value, args, return_type=self.rtype)}()" + call_lambda( + await cg.process_lambda(value, args, return_type=self.rtype) + ) ) - if self.idtype is not None and isinstance(value, ID): - return cg.RawExpression(f"{value}->{self.idexpr}") if self.retmapper is not None: return self.retmapper(value) return cg.safe_exp(value) @@ -89,7 +90,7 @@ class LvConstant(LValidator): cv.ensure_list(self.one_of), uint32, retmapper=self.mapper ) - def mapper(self, value, args=()): + def mapper(self, value): if not isinstance(value, list): value = [value] return literal( @@ -103,7 +104,7 @@ class LvConstant(LValidator): def extend(self, *choices): """ - Extend an LVCconstant with additional choices. + Extend an LVconstant with additional choices. :param choices: The extra choices :return: A new LVConstant instance """ @@ -431,6 +432,8 @@ CONF_ONE_LINE = "one_line" CONF_ON_SELECT = "on_select" CONF_ONE_CHECKED = "one_checked" CONF_NEXT = "next" +CONF_PAD_ROW = "pad_row" +CONF_PAD_COLUMN = "pad_column" CONF_PAGE = "page" CONF_PAGE_WRAP = "page_wrap" CONF_PASSWORD_MODE = "password_mode" @@ -462,6 +465,7 @@ CONF_SKIP = "skip" CONF_SYMBOL = "symbol" CONF_TAB_ID = "tab_id" CONF_TABS = "tabs" +CONF_TIME_FORMAT = "time_format" CONF_TILE = "tile" CONF_TILE_ID = "tile_id" CONF_TILES = "tiles" diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index b351b84af6..a2be4a2abe 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -1,17 +1,14 @@ from typing import Union import esphome.codegen as cg -from esphome.components.binary_sensor import BinarySensor from esphome.components.color import ColorStruct from esphome.components.font import Font from esphome.components.image import Image_ -from esphome.components.sensor import Sensor -from esphome.components.text_sensor import TextSensor import esphome.config_validation as cv -from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_VALUE -from esphome.core import HexInt +from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_TIME, CONF_VALUE +from esphome.core import HexInt, Lambda from esphome.cpp_generator import MockObj -from esphome.cpp_types import uint32 +from esphome.cpp_types import ESPTime, uint32 from esphome.helpers import cpp_string_escape from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -19,9 +16,11 @@ from . import types as ty from .defines import ( CONF_END_VALUE, CONF_START_VALUE, + CONF_TIME_FORMAT, LV_FONTS, LValidator, LvConstant, + call_lambda, literal, ) from .helpers import ( @@ -110,13 +109,13 @@ def angle(value): def size_validator(value): """A size in one axis - one of "size_content", a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: - return ["size_content", "pixels", "..%"] + return ["SIZE_CONTENT", "number of pixels", "percentage"] if isinstance(value, str) and value.lower().endswith("px"): value = cv.int_(value[:-2]) if isinstance(value, str) and not value.endswith("%"): if value.upper() == "SIZE_CONTENT": return "LV_SIZE_CONTENT" - raise cv.Invalid("must be 'size_content', a pixel position or a percentage") + raise cv.Invalid("must be 'size_content', a percentage or an integer (pixels)") if isinstance(value, int): return cv.int_(value) # Will throw an exception if not a percentage. @@ -125,6 +124,15 @@ def size_validator(value): size = LValidator(size_validator, uint32, retmapper=literal) + +def pixels_validator(value): + if isinstance(value, str) and value.lower().endswith("px"): + return cv.int_(value[:-2]) + return cv.int_(value) + + +pixels = LValidator(pixels_validator, uint32, retmapper=literal) + radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") @@ -167,9 +175,7 @@ lv_image = LValidator( retmapper=lambda x: lv_expr.img_from(MockObj(x)), requires="image", ) -lv_bool = LValidator( - cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal -) +lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal) def lv_pct(value: Union[int, float]): @@ -185,42 +191,60 @@ def lvms_validator_(value): lv_milliseconds = LValidator( - lvms_validator_, - cg.int32, - retmapper=lambda x: x.total_milliseconds, + lvms_validator_, cg.int32, retmapper=lambda x: x.total_milliseconds ) class TextValidator(LValidator): def __init__(self): - super().__init__( - cv.string, - cg.const_char_ptr, - TextSensor, - "get_state().c_str()", - lambda s: cg.safe_exp(f"{s}"), - ) + super().__init__(cv.string, cg.std_string, lambda s: cg.safe_exp(f"{s}")) def __call__(self, value): - if isinstance(value, dict): + if isinstance(value, dict) and CONF_FORMAT in value: return value return super().__call__(value) async def process(self, value, args=()): if isinstance(value, dict): - args = [str(x) for x in value[CONF_ARGS]] - arg_expr = cg.RawExpression(",".join(args)) - format_str = cpp_string_escape(value[CONF_FORMAT]) - return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()") + if format_str := value.get(CONF_FORMAT): + args = [str(x) for x in value[CONF_ARGS]] + arg_expr = cg.RawExpression(",".join(args)) + format_str = cpp_string_escape(format_str) + return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()") + if time_format := value.get(CONF_TIME_FORMAT): + source = value[CONF_TIME] + if isinstance(source, Lambda): + time_format = cpp_string_escape(time_format) + return cg.RawExpression( + call_lambda( + await cg.process_lambda(source, args, return_type=ESPTime) + ) + + f".strftime({time_format}).c_str()" + ) + # must be an ID + source = await cg.get_variable(source) + return source.now().strftime(time_format).c_str() + if isinstance(value, Lambda): + value = call_lambda( + await cg.process_lambda(value, args, return_type=self.rtype) + ) + + # Was the lambda call reduced to a string? + if value.endswith("c_str()") or ( + value.endswith('"') and value.startswith('"') + ): + pass + else: + # Either a std::string or a lambda call returning that. We need const char* + value = f"({value}).c_str()" + return cg.RawExpression(value) return await super().process(value, args) lv_text = TextValidator() -lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") -lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") -lv_brightness = LValidator( - cv.percentage, cg.float_, Sensor, "get_state()", retmapper=lambda x: int(x * 255) -) +lv_float = LValidator(cv.float_, cg.float_) +lv_int = LValidator(cv.int_, cg.int_) +lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255)) def is_lv_font(font): diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index f1c7ff4df6..e9714e3b1a 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -1,5 +1,6 @@ from esphome import config_validation as cv from esphome.automation import Trigger, validate_automation +from esphome.components.time import RealTimeClock from esphome.const import ( CONF_ARGS, CONF_FORMAT, @@ -8,6 +9,7 @@ from esphome.const import ( CONF_ON_VALUE, CONF_STATE, CONF_TEXT, + CONF_TIME, CONF_TRIGGER_ID, CONF_TYPE, ) @@ -15,6 +17,7 @@ from esphome.core import TimePeriod from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid +from .defines import CONF_TIME_FORMAT from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_color, lv_font, lv_image from .lvcode import LvglComponent @@ -46,7 +49,13 @@ TEXT_SCHEMA = cv.Schema( ), validate_printf, ), - lvalid.lv_text, + cv.Schema( + { + cv.Required(CONF_TIME_FORMAT): cv.string, + cv.GenerateID(CONF_TIME): cv.templatable(cv.use_id(RealTimeClock)), + } + ), + cv.templatable(cv.string), ) } ) @@ -116,15 +125,13 @@ STYLE_PROPS = { "opa_layered": lvalid.opacity, "outline_color": lvalid.lv_color, "outline_opa": lvalid.opacity, - "outline_pad": lvalid.size, - "outline_width": lvalid.size, - "pad_all": lvalid.size, - "pad_bottom": lvalid.size, - "pad_column": lvalid.size, - "pad_left": lvalid.size, - "pad_right": lvalid.size, - "pad_row": lvalid.size, - "pad_top": lvalid.size, + "outline_pad": lvalid.pixels, + "outline_width": lvalid.pixels, + "pad_all": lvalid.pixels, + "pad_bottom": lvalid.pixels, + "pad_left": lvalid.pixels, + "pad_right": lvalid.pixels, + "pad_top": lvalid.pixels, "shadow_color": lvalid.lv_color, "shadow_ofs_x": cv.int_, "shadow_ofs_y": cv.int_, @@ -304,6 +311,8 @@ LAYOUT_SCHEMA = { cv.Required(df.CONF_GRID_COLUMNS): [grid_spec], cv.Optional(df.CONF_GRID_COLUMN_ALIGN): grid_alignments, cv.Optional(df.CONF_GRID_ROW_ALIGN): grid_alignments, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, }, df.TYPE_FLEX: { cv.Optional( @@ -312,6 +321,8 @@ LAYOUT_SCHEMA = { cv.Optional(df.CONF_FLEX_ALIGN_MAIN, default="start"): flex_alignments, cv.Optional(df.CONF_FLEX_ALIGN_CROSS, default="start"): flex_alignments, cv.Optional(df.CONF_FLEX_ALIGN_TRACK, default="start"): flex_alignments, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, }, }, lower=True, @@ -338,7 +349,6 @@ DISP_BG_SCHEMA = cv.Schema( } ) - # A style schema that can include text STYLED_TEXT_SCHEMA = cv.maybe_simple_value( STYLE_SCHEMA.extend(TEXT_SCHEMA), key=CONF_TEXT diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 603de6aa3e..4abb25c61d 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -20,6 +20,8 @@ from ..defines import ( CONF_GRID_ROWS, CONF_LAYOUT, CONF_MAIN, + CONF_PAD_COLUMN, + CONF_PAD_ROW, CONF_SCROLLBAR_MODE, CONF_STYLES, CONF_WIDGETS, @@ -29,6 +31,7 @@ from ..defines import ( TYPE_FLEX, TYPE_GRID, LValidator, + call_lambda, join_enums, literal, ) @@ -273,6 +276,10 @@ async def set_obj_properties(w: Widget, config): layout_type: str = layout[CONF_TYPE] add_lv_use(layout_type) lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}")) + if (pad_row := layout.get(CONF_PAD_ROW)) is not None: + w.set_style(CONF_PAD_ROW, pad_row, 0) + if (pad_column := layout.get(CONF_PAD_COLUMN)) is not None: + w.set_style(CONF_PAD_COLUMN, pad_column, 0) if layout_type == TYPE_GRID: wid = config[CONF_ID] rows = [str(x) for x in layout[CONF_GRID_ROWS]] @@ -316,8 +323,13 @@ async def set_obj_properties(w: Widget, config): flag_clr = set() flag_set = set() props = parts[CONF_MAIN][CONF_DEFAULT] + lambs = {} + flag_set = set() + flag_clr = set() for prop, value in {k: v for k, v in props.items() if k in OBJ_FLAGS}.items(): - if value: + if isinstance(value, cv.Lambda): + lambs[prop] = value + elif value: flag_set.add(prop) else: flag_clr.add(prop) @@ -327,6 +339,13 @@ async def set_obj_properties(w: Widget, config): if flag_clr: clrs = join_enums(flag_clr, "LV_OBJ_FLAG_") w.clear_flag(clrs) + for key, value in lambs.items(): + lamb = await cg.process_lambda(value, [], return_type=cg.bool_) + flag = f"LV_OBJ_FLAG_{key.upper()}" + with LvConditional(call_lambda(lamb)) as cond: + w.add_flag(flag) + cond.else_() + w.clear_flag(flag) if states := config.get(CONF_STATE): adds = set() @@ -348,7 +367,7 @@ async def set_obj_properties(w: Widget, config): for key, value in lambs.items(): lamb = await cg.process_lambda(value, [], return_type=cg.bool_) state = f"LV_STATE_{key.upper()}" - with LvConditional(f"{lamb}()") as cond: + with LvConditional(call_lambda(lamb)) as cond: w.add_state(state) cond.else_() w.clear_state(state) diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 002c7a118d..7ef7772ac9 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -127,3 +127,11 @@ binary_sensor: - platform: lvgl name: LVGL checkbox widget: checkbox_id + +wifi: + ssid: SSID + password: PASSWORD123 + +time: + platform: sntp + id: time_id diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 54022354f5..800d6eff27 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -16,8 +16,6 @@ lvgl: border_width: 0 radius: 0 pad_all: 0 - pad_row: 0 - pad_column: 0 border_color: 0x0077b3 text_color: 0xFFFFFF width: 100% @@ -55,6 +53,13 @@ lvgl: pages: - id: page1 skip: true + layout: + type: flex + pad_row: 4 + pad_column: 4px + flex_align_main: center + flex_align_cross: start + flex_align_track: end widgets: - animimg: height: 60 @@ -118,10 +123,8 @@ lvgl: outline_width: 10px pad_all: 10px pad_bottom: 10px - pad_column: 10px pad_left: 10px pad_right: 10px - pad_row: 10px pad_top: 10px shadow_color: light_blue shadow_ofs_x: 5 @@ -221,10 +224,47 @@ lvgl: - label: text: Button on_click: - lvgl.label.update: - id: hello_label - bg_color: 0x123456 - text: clicked + - lvgl.label.update: + id: hello_label + bg_color: 0x123456 + text: clicked + - lvgl.label.update: + id: hello_label + text: !lambda return "hello world"; + - lvgl.label.update: + id: hello_label + text: !lambda |- + ESP_LOGD("label", "multi-line lambda"); + return "hello world"; + - lvgl.label.update: + id: hello_label + text: !lambda 'return str_sprintf("Hello space");' + - lvgl.label.update: + id: hello_label + text: + format: "sprintf format %s" + args: ['x ? "checked" : "unchecked"'] + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: time_id + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: !lambda return id(time_id).now(); + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: !lambda |- + ESP_LOGD("label", "multi-line lambda"); + return id(time_id).now(); on_value: logger.log: format: "state now %d" @@ -396,6 +436,8 @@ lvgl: grid_row_align: end grid_rows: [25px, fr(1), content] grid_columns: [40, fr(1), fr(1)] + pad_row: 6px + pad_column: 0 widgets: - image: grid_cell_row_pos: 0 From 8b6d6fe6616f0c83c72c9ff395f74134a8956dd4 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Mon, 19 Aug 2024 00:45:10 +0200 Subject: [PATCH 2259/2607] [speaker] Fix header includes (#7304) --- esphome/components/speaker/speaker.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 142231881c..193049402d 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + namespace esphome { namespace speaker { From baedd74c7a5f54a871eb413a629d6dd94c15510a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:45:22 +1200 Subject: [PATCH 2260/2607] [microphone] Fix header includes (#7310) --- esphome/components/microphone/microphone.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index e01a10e15c..883ca97710 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -1,6 +1,9 @@ #pragma once -#include "esphome/core/entity_base.h" +#include +#include +#include +#include #include "esphome/core/helpers.h" namespace esphome { From 7464b440c078794c0dec88c3a991e2c081695855 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 18 Aug 2024 20:27:03 +1200 Subject: [PATCH 2261/2607] Revert "[validation] Allow ``maybe_simple_value`` to not have default key in complex value" (#7305) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 6d6cb451d6..719cc43b31 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1864,7 +1864,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict): + if isinstance(value, dict) and key in value: return validator(value) return validator({key: value}) From 5c7d070307c7a04e452cd641cdc3fa4baa477e18 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 19 Aug 2024 08:43:23 +1000 Subject: [PATCH 2262/2607] [lvgl] Bug fixes (#7300) --- esphome/components/lvgl/defines.py | 32 ++++---- esphome/components/lvgl/lv_validation.py | 86 +++++++++++++-------- esphome/components/lvgl/schemas.py | 32 +++++--- esphome/components/lvgl/widgets/__init__.py | 23 +++++- tests/components/lvgl/common.yaml | 8 ++ tests/components/lvgl/lvgl-package.yaml | 58 ++++++++++++-- 6 files changed, 173 insertions(+), 66 deletions(-) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 8f7a973722..6a8b20b505 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -6,8 +6,8 @@ Constants already defined in esphome.const are not duplicated here and must be i from esphome import codegen as cg, config_validation as cv from esphome.const import CONF_ITEMS -from esphome.core import ID, Lambda -from esphome.cpp_generator import MockObj +from esphome.core import Lambda +from esphome.cpp_generator import LambdaExpression, MockObj from esphome.cpp_types import uint32 from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -22,19 +22,22 @@ def literal(arg): return arg +def call_lambda(lamb: LambdaExpression): + expr = lamb.content.strip() + if expr.startswith("return") and expr.endswith(";"): + return expr[7:][:-1] + return f"{lamb}()" + + class LValidator: """ A validator for a particular type used in LVGL. Usable in configs as a validator, also has `process()` to convert a value during code generation """ - def __init__( - self, validator, rtype, idtype=None, idexpr=None, retmapper=None, requires=None - ): + def __init__(self, validator, rtype, retmapper=None, requires=None): self.validator = validator self.rtype = rtype - self.idtype = idtype - self.idexpr = idexpr self.retmapper = retmapper self.requires = requires @@ -43,8 +46,6 @@ class LValidator: value = requires_component(self.requires)(value) if isinstance(value, cv.Lambda): return cv.returning_lambda(value) - if self.idtype is not None and isinstance(value, ID): - return cv.use_id(self.idtype)(value) return self.validator(value) async def process(self, value, args=()): @@ -52,10 +53,10 @@ class LValidator: return None if isinstance(value, Lambda): return cg.RawExpression( - f"{await cg.process_lambda(value, args, return_type=self.rtype)}()" + call_lambda( + await cg.process_lambda(value, args, return_type=self.rtype) + ) ) - if self.idtype is not None and isinstance(value, ID): - return cg.RawExpression(f"{value}->{self.idexpr}") if self.retmapper is not None: return self.retmapper(value) return cg.safe_exp(value) @@ -89,7 +90,7 @@ class LvConstant(LValidator): cv.ensure_list(self.one_of), uint32, retmapper=self.mapper ) - def mapper(self, value, args=()): + def mapper(self, value): if not isinstance(value, list): value = [value] return literal( @@ -103,7 +104,7 @@ class LvConstant(LValidator): def extend(self, *choices): """ - Extend an LVCconstant with additional choices. + Extend an LVconstant with additional choices. :param choices: The extra choices :return: A new LVConstant instance """ @@ -431,6 +432,8 @@ CONF_ONE_LINE = "one_line" CONF_ON_SELECT = "on_select" CONF_ONE_CHECKED = "one_checked" CONF_NEXT = "next" +CONF_PAD_ROW = "pad_row" +CONF_PAD_COLUMN = "pad_column" CONF_PAGE = "page" CONF_PAGE_WRAP = "page_wrap" CONF_PASSWORD_MODE = "password_mode" @@ -462,6 +465,7 @@ CONF_SKIP = "skip" CONF_SYMBOL = "symbol" CONF_TAB_ID = "tab_id" CONF_TABS = "tabs" +CONF_TIME_FORMAT = "time_format" CONF_TILE = "tile" CONF_TILE_ID = "tile_id" CONF_TILES = "tiles" diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index b351b84af6..a2be4a2abe 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -1,17 +1,14 @@ from typing import Union import esphome.codegen as cg -from esphome.components.binary_sensor import BinarySensor from esphome.components.color import ColorStruct from esphome.components.font import Font from esphome.components.image import Image_ -from esphome.components.sensor import Sensor -from esphome.components.text_sensor import TextSensor import esphome.config_validation as cv -from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_VALUE -from esphome.core import HexInt +from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_TIME, CONF_VALUE +from esphome.core import HexInt, Lambda from esphome.cpp_generator import MockObj -from esphome.cpp_types import uint32 +from esphome.cpp_types import ESPTime, uint32 from esphome.helpers import cpp_string_escape from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -19,9 +16,11 @@ from . import types as ty from .defines import ( CONF_END_VALUE, CONF_START_VALUE, + CONF_TIME_FORMAT, LV_FONTS, LValidator, LvConstant, + call_lambda, literal, ) from .helpers import ( @@ -110,13 +109,13 @@ def angle(value): def size_validator(value): """A size in one axis - one of "size_content", a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: - return ["size_content", "pixels", "..%"] + return ["SIZE_CONTENT", "number of pixels", "percentage"] if isinstance(value, str) and value.lower().endswith("px"): value = cv.int_(value[:-2]) if isinstance(value, str) and not value.endswith("%"): if value.upper() == "SIZE_CONTENT": return "LV_SIZE_CONTENT" - raise cv.Invalid("must be 'size_content', a pixel position or a percentage") + raise cv.Invalid("must be 'size_content', a percentage or an integer (pixels)") if isinstance(value, int): return cv.int_(value) # Will throw an exception if not a percentage. @@ -125,6 +124,15 @@ def size_validator(value): size = LValidator(size_validator, uint32, retmapper=literal) + +def pixels_validator(value): + if isinstance(value, str) and value.lower().endswith("px"): + return cv.int_(value[:-2]) + return cv.int_(value) + + +pixels = LValidator(pixels_validator, uint32, retmapper=literal) + radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") @@ -167,9 +175,7 @@ lv_image = LValidator( retmapper=lambda x: lv_expr.img_from(MockObj(x)), requires="image", ) -lv_bool = LValidator( - cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal -) +lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal) def lv_pct(value: Union[int, float]): @@ -185,42 +191,60 @@ def lvms_validator_(value): lv_milliseconds = LValidator( - lvms_validator_, - cg.int32, - retmapper=lambda x: x.total_milliseconds, + lvms_validator_, cg.int32, retmapper=lambda x: x.total_milliseconds ) class TextValidator(LValidator): def __init__(self): - super().__init__( - cv.string, - cg.const_char_ptr, - TextSensor, - "get_state().c_str()", - lambda s: cg.safe_exp(f"{s}"), - ) + super().__init__(cv.string, cg.std_string, lambda s: cg.safe_exp(f"{s}")) def __call__(self, value): - if isinstance(value, dict): + if isinstance(value, dict) and CONF_FORMAT in value: return value return super().__call__(value) async def process(self, value, args=()): if isinstance(value, dict): - args = [str(x) for x in value[CONF_ARGS]] - arg_expr = cg.RawExpression(",".join(args)) - format_str = cpp_string_escape(value[CONF_FORMAT]) - return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()") + if format_str := value.get(CONF_FORMAT): + args = [str(x) for x in value[CONF_ARGS]] + arg_expr = cg.RawExpression(",".join(args)) + format_str = cpp_string_escape(format_str) + return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()") + if time_format := value.get(CONF_TIME_FORMAT): + source = value[CONF_TIME] + if isinstance(source, Lambda): + time_format = cpp_string_escape(time_format) + return cg.RawExpression( + call_lambda( + await cg.process_lambda(source, args, return_type=ESPTime) + ) + + f".strftime({time_format}).c_str()" + ) + # must be an ID + source = await cg.get_variable(source) + return source.now().strftime(time_format).c_str() + if isinstance(value, Lambda): + value = call_lambda( + await cg.process_lambda(value, args, return_type=self.rtype) + ) + + # Was the lambda call reduced to a string? + if value.endswith("c_str()") or ( + value.endswith('"') and value.startswith('"') + ): + pass + else: + # Either a std::string or a lambda call returning that. We need const char* + value = f"({value}).c_str()" + return cg.RawExpression(value) return await super().process(value, args) lv_text = TextValidator() -lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") -lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") -lv_brightness = LValidator( - cv.percentage, cg.float_, Sensor, "get_state()", retmapper=lambda x: int(x * 255) -) +lv_float = LValidator(cv.float_, cg.float_) +lv_int = LValidator(cv.int_, cg.int_) +lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255)) def is_lv_font(font): diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index f1c7ff4df6..e9714e3b1a 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -1,5 +1,6 @@ from esphome import config_validation as cv from esphome.automation import Trigger, validate_automation +from esphome.components.time import RealTimeClock from esphome.const import ( CONF_ARGS, CONF_FORMAT, @@ -8,6 +9,7 @@ from esphome.const import ( CONF_ON_VALUE, CONF_STATE, CONF_TEXT, + CONF_TIME, CONF_TRIGGER_ID, CONF_TYPE, ) @@ -15,6 +17,7 @@ from esphome.core import TimePeriod from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid +from .defines import CONF_TIME_FORMAT from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_color, lv_font, lv_image from .lvcode import LvglComponent @@ -46,7 +49,13 @@ TEXT_SCHEMA = cv.Schema( ), validate_printf, ), - lvalid.lv_text, + cv.Schema( + { + cv.Required(CONF_TIME_FORMAT): cv.string, + cv.GenerateID(CONF_TIME): cv.templatable(cv.use_id(RealTimeClock)), + } + ), + cv.templatable(cv.string), ) } ) @@ -116,15 +125,13 @@ STYLE_PROPS = { "opa_layered": lvalid.opacity, "outline_color": lvalid.lv_color, "outline_opa": lvalid.opacity, - "outline_pad": lvalid.size, - "outline_width": lvalid.size, - "pad_all": lvalid.size, - "pad_bottom": lvalid.size, - "pad_column": lvalid.size, - "pad_left": lvalid.size, - "pad_right": lvalid.size, - "pad_row": lvalid.size, - "pad_top": lvalid.size, + "outline_pad": lvalid.pixels, + "outline_width": lvalid.pixels, + "pad_all": lvalid.pixels, + "pad_bottom": lvalid.pixels, + "pad_left": lvalid.pixels, + "pad_right": lvalid.pixels, + "pad_top": lvalid.pixels, "shadow_color": lvalid.lv_color, "shadow_ofs_x": cv.int_, "shadow_ofs_y": cv.int_, @@ -304,6 +311,8 @@ LAYOUT_SCHEMA = { cv.Required(df.CONF_GRID_COLUMNS): [grid_spec], cv.Optional(df.CONF_GRID_COLUMN_ALIGN): grid_alignments, cv.Optional(df.CONF_GRID_ROW_ALIGN): grid_alignments, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, }, df.TYPE_FLEX: { cv.Optional( @@ -312,6 +321,8 @@ LAYOUT_SCHEMA = { cv.Optional(df.CONF_FLEX_ALIGN_MAIN, default="start"): flex_alignments, cv.Optional(df.CONF_FLEX_ALIGN_CROSS, default="start"): flex_alignments, cv.Optional(df.CONF_FLEX_ALIGN_TRACK, default="start"): flex_alignments, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, }, }, lower=True, @@ -338,7 +349,6 @@ DISP_BG_SCHEMA = cv.Schema( } ) - # A style schema that can include text STYLED_TEXT_SCHEMA = cv.maybe_simple_value( STYLE_SCHEMA.extend(TEXT_SCHEMA), key=CONF_TEXT diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 603de6aa3e..4abb25c61d 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -20,6 +20,8 @@ from ..defines import ( CONF_GRID_ROWS, CONF_LAYOUT, CONF_MAIN, + CONF_PAD_COLUMN, + CONF_PAD_ROW, CONF_SCROLLBAR_MODE, CONF_STYLES, CONF_WIDGETS, @@ -29,6 +31,7 @@ from ..defines import ( TYPE_FLEX, TYPE_GRID, LValidator, + call_lambda, join_enums, literal, ) @@ -273,6 +276,10 @@ async def set_obj_properties(w: Widget, config): layout_type: str = layout[CONF_TYPE] add_lv_use(layout_type) lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}")) + if (pad_row := layout.get(CONF_PAD_ROW)) is not None: + w.set_style(CONF_PAD_ROW, pad_row, 0) + if (pad_column := layout.get(CONF_PAD_COLUMN)) is not None: + w.set_style(CONF_PAD_COLUMN, pad_column, 0) if layout_type == TYPE_GRID: wid = config[CONF_ID] rows = [str(x) for x in layout[CONF_GRID_ROWS]] @@ -316,8 +323,13 @@ async def set_obj_properties(w: Widget, config): flag_clr = set() flag_set = set() props = parts[CONF_MAIN][CONF_DEFAULT] + lambs = {} + flag_set = set() + flag_clr = set() for prop, value in {k: v for k, v in props.items() if k in OBJ_FLAGS}.items(): - if value: + if isinstance(value, cv.Lambda): + lambs[prop] = value + elif value: flag_set.add(prop) else: flag_clr.add(prop) @@ -327,6 +339,13 @@ async def set_obj_properties(w: Widget, config): if flag_clr: clrs = join_enums(flag_clr, "LV_OBJ_FLAG_") w.clear_flag(clrs) + for key, value in lambs.items(): + lamb = await cg.process_lambda(value, [], return_type=cg.bool_) + flag = f"LV_OBJ_FLAG_{key.upper()}" + with LvConditional(call_lambda(lamb)) as cond: + w.add_flag(flag) + cond.else_() + w.clear_flag(flag) if states := config.get(CONF_STATE): adds = set() @@ -348,7 +367,7 @@ async def set_obj_properties(w: Widget, config): for key, value in lambs.items(): lamb = await cg.process_lambda(value, [], return_type=cg.bool_) state = f"LV_STATE_{key.upper()}" - with LvConditional(f"{lamb}()") as cond: + with LvConditional(call_lambda(lamb)) as cond: w.add_state(state) cond.else_() w.clear_state(state) diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 002c7a118d..7ef7772ac9 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -127,3 +127,11 @@ binary_sensor: - platform: lvgl name: LVGL checkbox widget: checkbox_id + +wifi: + ssid: SSID + password: PASSWORD123 + +time: + platform: sntp + id: time_id diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 54022354f5..800d6eff27 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -16,8 +16,6 @@ lvgl: border_width: 0 radius: 0 pad_all: 0 - pad_row: 0 - pad_column: 0 border_color: 0x0077b3 text_color: 0xFFFFFF width: 100% @@ -55,6 +53,13 @@ lvgl: pages: - id: page1 skip: true + layout: + type: flex + pad_row: 4 + pad_column: 4px + flex_align_main: center + flex_align_cross: start + flex_align_track: end widgets: - animimg: height: 60 @@ -118,10 +123,8 @@ lvgl: outline_width: 10px pad_all: 10px pad_bottom: 10px - pad_column: 10px pad_left: 10px pad_right: 10px - pad_row: 10px pad_top: 10px shadow_color: light_blue shadow_ofs_x: 5 @@ -221,10 +224,47 @@ lvgl: - label: text: Button on_click: - lvgl.label.update: - id: hello_label - bg_color: 0x123456 - text: clicked + - lvgl.label.update: + id: hello_label + bg_color: 0x123456 + text: clicked + - lvgl.label.update: + id: hello_label + text: !lambda return "hello world"; + - lvgl.label.update: + id: hello_label + text: !lambda |- + ESP_LOGD("label", "multi-line lambda"); + return "hello world"; + - lvgl.label.update: + id: hello_label + text: !lambda 'return str_sprintf("Hello space");' + - lvgl.label.update: + id: hello_label + text: + format: "sprintf format %s" + args: ['x ? "checked" : "unchecked"'] + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: time_id + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: !lambda return id(time_id).now(); + - lvgl.label.update: + id: hello_label + text: + time_format: "%c" + time: !lambda |- + ESP_LOGD("label", "multi-line lambda"); + return id(time_id).now(); on_value: logger.log: format: "state now %d" @@ -396,6 +436,8 @@ lvgl: grid_row_align: end grid_rows: [25px, fr(1), content] grid_columns: [40, fr(1), fr(1)] + pad_row: 6px + pad_column: 0 widgets: - image: grid_cell_row_pos: 0 From 0f82114e64f50a167c85374ec299c43fd2cd84ff Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Mon, 19 Aug 2024 00:45:10 +0200 Subject: [PATCH 2263/2607] [speaker] Fix header includes (#7304) --- esphome/components/speaker/speaker.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 142231881c..193049402d 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + namespace esphome { namespace speaker { From c96784f59108b476597a6f09a83de358d18ef3b2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:45:22 +1200 Subject: [PATCH 2264/2607] [microphone] Fix header includes (#7310) --- esphome/components/microphone/microphone.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index e01a10e15c..883ca97710 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -1,6 +1,9 @@ #pragma once -#include "esphome/core/entity_base.h" +#include +#include +#include +#include #include "esphome/core/helpers.h" namespace esphome { From 409e84090eff4d3c8aa536e2077f036cd51cda54 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:09:59 +1200 Subject: [PATCH 2265/2607] Bump version to 2024.8.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 39d2ee74a1..a321ddd19f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0b2" +__version__ = "2024.8.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b425912a80aea1ed71ebf5e3515963f09f559832 Mon Sep 17 00:00:00 2001 From: Roving Ronin <108674933+Roving-Ronin@users.noreply.github.com> Date: Tue, 20 Aug 2024 07:18:06 +1000 Subject: [PATCH 2266/2607] Update const.py - Add missing UNIT_LITRE (#7317) --- esphome/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/const.py b/esphome/const.py index 6157ce32f7..b9c37a53a8 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1042,6 +1042,7 @@ UNIT_KILOVOLT_AMPS_REACTIVE = "kVAR" UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kVARh" UNIT_KILOWATT = "kW" UNIT_KILOWATT_HOURS = "kWh" +UNIT_LITRE = "L" UNIT_LUX = "lx" UNIT_METER = "m" UNIT_METER_PER_SECOND_SQUARED = "m/s²" From 1ffee9c4d2d89823346b48585a987e9ab7233a93 Mon Sep 17 00:00:00 2001 From: Ali Jafri Date: Tue, 20 Aug 2024 03:12:41 +0530 Subject: [PATCH 2267/2607] Fix RP2040 Neopixel flickering issue (#7307) --- .../rp2040_pio_led_strip/led_strip.cpp | 36 ++++++++++++++++--- .../rp2040_pio_led_strip/led_strip.h | 5 +++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.cpp b/esphome/components/rp2040_pio_led_strip/led_strip.cpp index 3e5e82898d..2aaa2ceb19 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.cpp +++ b/esphome/components/rp2040_pio_led_strip/led_strip.cpp @@ -7,8 +7,10 @@ #include #include +#include #include #include +#include namespace esphome { namespace rp2040_pio_led_strip { @@ -23,6 +25,19 @@ static std::map conf_count_ = { {CHIPSET_WS2812, false}, {CHIPSET_WS2812B, false}, {CHIPSET_SK6812, false}, {CHIPSET_SM16703, false}, {CHIPSET_CUSTOM, false}, }; +static bool dma_chan_active_[12]; +static struct semaphore dma_write_complete_sem_[12]; + +// DMA interrupt service routine +void RP2040PIOLEDStripLightOutput::dma_write_complete_handler_() { + uint32_t channel = dma_hw->ints0; + for (uint dma_chan = 0; dma_chan < 12; ++dma_chan) { + if (RP2040PIOLEDStripLightOutput::dma_chan_active_[dma_chan] && (channel & (1u << dma_chan))) { + dma_hw->ints0 = (1u << dma_chan); // Clear the interrupt + sem_release(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[dma_chan]); // Handle the interrupt + } + } +} void RP2040PIOLEDStripLightOutput::setup() { ESP_LOGCONFIG(TAG, "Setting up RP2040 LED Strip..."); @@ -57,22 +72,22 @@ void RP2040PIOLEDStripLightOutput::setup() { // but there are only 4 state machines on each PIO so we can only have 4 strips per PIO uint offset = 0; - if (num_instance_[this->pio_ == pio0 ? 0 : 1] > 4) { + if (RP2040PIOLEDStripLightOutput::num_instance_[this->pio_ == pio0 ? 0 : 1] > 4) { ESP_LOGE(TAG, "Too many instances of PIO program"); this->mark_failed(); return; } // keep track of how many instances of the PIO program are running on each PIO - num_instance_[this->pio_ == pio0 ? 0 : 1]++; + RP2040PIOLEDStripLightOutput::num_instance_[this->pio_ == pio0 ? 0 : 1]++; // if there are multiple strips of the same chipset, we can reuse the same PIO program and save space if (this->conf_count_[this->chipset_]) { - offset = chipset_offsets_[this->chipset_]; + offset = RP2040PIOLEDStripLightOutput::chipset_offsets_[this->chipset_]; } else { // Load the assembled program into the PIO and get its location in the PIO's instruction memory and save it offset = pio_add_program(this->pio_, this->program_); - chipset_offsets_[this->chipset_] = offset; - conf_count_[this->chipset_] = true; + RP2040PIOLEDStripLightOutput::chipset_offsets_[this->chipset_] = offset; + RP2040PIOLEDStripLightOutput::conf_count_[this->chipset_] = true; } // Configure the state machine's PIO, and start it @@ -93,6 +108,9 @@ void RP2040PIOLEDStripLightOutput::setup() { return; } + // Mark the DMA channel as active + RP2040PIOLEDStripLightOutput::dma_chan_active_[this->dma_chan_] = true; + this->dma_config_ = dma_channel_get_default_config(this->dma_chan_); channel_config_set_transfer_data_size( &this->dma_config_, @@ -109,6 +127,13 @@ void RP2040PIOLEDStripLightOutput::setup() { false // don't start yet ); + // Initialize the semaphore for this DMA channel + sem_init(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[this->dma_chan_], 1, 1); + + irq_set_exclusive_handler(DMA_IRQ_0, dma_write_complete_handler_); // after DMA all data, raise an interrupt + dma_channel_set_irq0_enabled(this->dma_chan_, true); // map DMA channel to interrupt + irq_set_enabled(DMA_IRQ_0, true); // enable interrupt + this->init_(this->pio_, this->sm_, offset, this->pin_, this->max_refresh_rate_); } @@ -126,6 +151,7 @@ void RP2040PIOLEDStripLightOutput::write_state(light::LightState *state) { } // the bits are already in the correct order for the pio program so we can just copy the buffer using DMA + sem_acquire_blocking(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[this->dma_chan_]); dma_channel_transfer_from_buffer_now(this->dma_chan_, this->buf_, this->get_buffer_size_()); } diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.h b/esphome/components/rp2040_pio_led_strip/led_strip.h index 9976842f02..7b62648974 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.h +++ b/esphome/components/rp2040_pio_led_strip/led_strip.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace esphome { @@ -95,6 +96,8 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { size_t get_buffer_size_() const { return this->num_leds_ * (3 + this->is_rgbw_); } + static void dma_write_complete_handler_(); + uint8_t *buf_{nullptr}; uint8_t *effect_data_{nullptr}; @@ -120,6 +123,8 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { inline static int num_instance_[2]; inline static std::map conf_count_; inline static std::map chipset_offsets_; + inline static bool dma_chan_active_[12]; + inline static struct semaphore dma_write_complete_sem_[12]; }; } // namespace rp2040_pio_led_strip From 30414667d023c18767852d12f3da7bc119c6ae1e Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Tue, 20 Aug 2024 00:22:19 +0200 Subject: [PATCH 2268/2607] add the ability to add more idf components to an existing setup (#7302) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 0a5dd46478..b630c7638e 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -172,6 +172,19 @@ def add_idf_component( KEY_COMPONENTS: components, KEY_SUBMODULES: submodules, } + else: + component_config = CORE.data[KEY_ESP32][KEY_COMPONENTS][name] + if components is not None: + component_config[KEY_COMPONENTS] = list( + set(component_config[KEY_COMPONENTS] + components) + ) + if submodules is not None: + if component_config[KEY_SUBMODULES] is None: + component_config[KEY_SUBMODULES] = submodules + else: + component_config[KEY_SUBMODULES] = list( + set(component_config[KEY_SUBMODULES] + submodules) + ) def add_extra_script(stage: str, filename: str, path: str): From 3cbdf63f567621bf559f7cf82b05d078b56a8e28 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 20 Aug 2024 00:53:15 +0200 Subject: [PATCH 2269/2607] [code-quality] fix clang-tidy socket (#7285) --- esphome/components/socket/socket.cpp | 2 ++ esphome/components/socket/socket.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 5d3528dad8..e260fce05e 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -1,4 +1,5 @@ #include "socket.h" +#if defined(USE_SOCKET_IMPL_LWIP_TCP) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS) #include #include #include @@ -74,3 +75,4 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po } } // namespace socket } // namespace esphome +#endif diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index 5c12210d15..cefdb51e0d 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -5,6 +5,7 @@ #include "esphome/core/optional.h" #include "headers.h" +#if defined(USE_SOCKET_IMPL_LWIP_TCP) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS) namespace esphome { namespace socket { @@ -57,3 +58,4 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po } // namespace socket } // namespace esphome +#endif From fa497d06b047334de87267ade785c9394b0074f5 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 21 Aug 2024 00:01:50 +0200 Subject: [PATCH 2270/2607] [code-quality] fix clang-tidy cstddef (#7324) --- esphome/components/microphone/microphone.h | 2 +- esphome/components/speaker/speaker.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index 883ca97710..914ad80bea 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 193049402d..375ccc4e8c 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include From bd3d065a23693340fffdc887178e76ca93830be2 Mon Sep 17 00:00:00 2001 From: Sung-jin Brian Hong Date: Wed, 21 Aug 2024 08:44:21 +0900 Subject: [PATCH 2271/2607] Fix waveshare 2.13" epaper stride calculation error (#7303) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/waveshare_epaper/waveshare_epaper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 24df428e6f..7c1d436673 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -480,7 +480,7 @@ void HOT WaveshareEPaperTypeA::display() { this->start_data_(); switch (this->model_) { case TTGO_EPAPER_2_13_IN_B1: { // block needed because of variable initializations - int16_t wb = ((this->get_width_internal()) >> 3); + int16_t wb = ((this->get_width_controller()) >> 3); for (int i = 0; i < this->get_height_internal(); i++) { for (int j = 0; j < wb; j++) { int idx = j + (this->get_height_internal() - 1 - i) * wb; @@ -766,7 +766,7 @@ void WaveshareEPaper2P7InV2::initialize() { // XRAM_START_AND_END_POSITION this->command(0x44); this->data(0x00); - this->data(((get_width_internal() - 1) >> 3) & 0xFF); + this->data(((this->get_width_controller() - 1) >> 3) & 0xFF); // YRAM_START_AND_END_POSITION this->command(0x45); this->data(0x00); @@ -928,8 +928,8 @@ void HOT WaveshareEPaper2P7InB::display() { // TCON_RESOLUTION this->command(0x61); - this->data(this->get_width_internal() >> 8); - this->data(this->get_width_internal() & 0xff); // 176 + this->data(this->get_width_controller() >> 8); + this->data(this->get_width_controller() & 0xff); // 176 this->data(this->get_height_internal() >> 8); this->data(this->get_height_internal() & 0xff); // 264 @@ -994,7 +994,7 @@ void WaveshareEPaper2P7InBV2::initialize() { // self.SetWindows(0, 0, self.width-1, self.height-1) // SetWindows(self, Xstart, Ystart, Xend, Yend): - uint32_t xend = this->get_width_internal() - 1; + uint32_t xend = this->get_width_controller() - 1; uint32_t yend = this->get_height_internal() - 1; this->command(0x44); this->data(0x00); From 848fd0442d67dece75bf8eddf6a5242ead5b6dc4 Mon Sep 17 00:00:00 2001 From: NewoPL <27411874+NewoPL@users.noreply.github.com> Date: Wed, 21 Aug 2024 01:46:15 +0200 Subject: [PATCH 2272/2607] [rtttl] fix STOPPED state (#7323) --- esphome/components/rtttl/rtttl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index a97120499d..495b5c1c8a 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -32,7 +32,7 @@ void Rtttl::play(std::string rtttl) { if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { int pos = this->rtttl_.find(':'); auto name = this->rtttl_.substr(0, pos); - ESP_LOGW(TAG, "RTTL Component is already playing: %s", name.c_str()); + ESP_LOGW(TAG, "RTTTL Component is already playing: %s", name.c_str()); return; } @@ -122,6 +122,7 @@ void Rtttl::stop() { #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); + this->set_state_(STATE_STOPPED); } #endif #ifdef USE_SPEAKER @@ -129,10 +130,10 @@ void Rtttl::stop() { if (this->speaker_->is_running()) { this->speaker_->stop(); } + this->set_state_(STATE_STOPPING); } #endif this->note_duration_ = 0; - this->set_state_(STATE_STOPPING); } void Rtttl::loop() { @@ -342,6 +343,7 @@ void Rtttl::finish_() { #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); + this->set_state_(State::STATE_STOPPED); } #endif #ifdef USE_SPEAKER @@ -354,9 +356,9 @@ void Rtttl::finish_() { this->speaker_->play((uint8_t *) (&sample), 8); this->speaker_->finish(); + this->set_state_(State::STATE_STOPPING); } #endif - this->set_state_(State::STATE_STOPPING); this->note_duration_ = 0; this->on_finished_playback_callback_.call(); ESP_LOGD(TAG, "Playback finished"); From 8fae60931622771feb31af6ee788e4cf8ac96f9c Mon Sep 17 00:00:00 2001 From: Ali Jafri Date: Tue, 20 Aug 2024 03:12:41 +0530 Subject: [PATCH 2273/2607] Fix RP2040 Neopixel flickering issue (#7307) --- .../rp2040_pio_led_strip/led_strip.cpp | 36 ++++++++++++++++--- .../rp2040_pio_led_strip/led_strip.h | 5 +++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.cpp b/esphome/components/rp2040_pio_led_strip/led_strip.cpp index 3e5e82898d..2aaa2ceb19 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.cpp +++ b/esphome/components/rp2040_pio_led_strip/led_strip.cpp @@ -7,8 +7,10 @@ #include #include +#include #include #include +#include namespace esphome { namespace rp2040_pio_led_strip { @@ -23,6 +25,19 @@ static std::map conf_count_ = { {CHIPSET_WS2812, false}, {CHIPSET_WS2812B, false}, {CHIPSET_SK6812, false}, {CHIPSET_SM16703, false}, {CHIPSET_CUSTOM, false}, }; +static bool dma_chan_active_[12]; +static struct semaphore dma_write_complete_sem_[12]; + +// DMA interrupt service routine +void RP2040PIOLEDStripLightOutput::dma_write_complete_handler_() { + uint32_t channel = dma_hw->ints0; + for (uint dma_chan = 0; dma_chan < 12; ++dma_chan) { + if (RP2040PIOLEDStripLightOutput::dma_chan_active_[dma_chan] && (channel & (1u << dma_chan))) { + dma_hw->ints0 = (1u << dma_chan); // Clear the interrupt + sem_release(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[dma_chan]); // Handle the interrupt + } + } +} void RP2040PIOLEDStripLightOutput::setup() { ESP_LOGCONFIG(TAG, "Setting up RP2040 LED Strip..."); @@ -57,22 +72,22 @@ void RP2040PIOLEDStripLightOutput::setup() { // but there are only 4 state machines on each PIO so we can only have 4 strips per PIO uint offset = 0; - if (num_instance_[this->pio_ == pio0 ? 0 : 1] > 4) { + if (RP2040PIOLEDStripLightOutput::num_instance_[this->pio_ == pio0 ? 0 : 1] > 4) { ESP_LOGE(TAG, "Too many instances of PIO program"); this->mark_failed(); return; } // keep track of how many instances of the PIO program are running on each PIO - num_instance_[this->pio_ == pio0 ? 0 : 1]++; + RP2040PIOLEDStripLightOutput::num_instance_[this->pio_ == pio0 ? 0 : 1]++; // if there are multiple strips of the same chipset, we can reuse the same PIO program and save space if (this->conf_count_[this->chipset_]) { - offset = chipset_offsets_[this->chipset_]; + offset = RP2040PIOLEDStripLightOutput::chipset_offsets_[this->chipset_]; } else { // Load the assembled program into the PIO and get its location in the PIO's instruction memory and save it offset = pio_add_program(this->pio_, this->program_); - chipset_offsets_[this->chipset_] = offset; - conf_count_[this->chipset_] = true; + RP2040PIOLEDStripLightOutput::chipset_offsets_[this->chipset_] = offset; + RP2040PIOLEDStripLightOutput::conf_count_[this->chipset_] = true; } // Configure the state machine's PIO, and start it @@ -93,6 +108,9 @@ void RP2040PIOLEDStripLightOutput::setup() { return; } + // Mark the DMA channel as active + RP2040PIOLEDStripLightOutput::dma_chan_active_[this->dma_chan_] = true; + this->dma_config_ = dma_channel_get_default_config(this->dma_chan_); channel_config_set_transfer_data_size( &this->dma_config_, @@ -109,6 +127,13 @@ void RP2040PIOLEDStripLightOutput::setup() { false // don't start yet ); + // Initialize the semaphore for this DMA channel + sem_init(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[this->dma_chan_], 1, 1); + + irq_set_exclusive_handler(DMA_IRQ_0, dma_write_complete_handler_); // after DMA all data, raise an interrupt + dma_channel_set_irq0_enabled(this->dma_chan_, true); // map DMA channel to interrupt + irq_set_enabled(DMA_IRQ_0, true); // enable interrupt + this->init_(this->pio_, this->sm_, offset, this->pin_, this->max_refresh_rate_); } @@ -126,6 +151,7 @@ void RP2040PIOLEDStripLightOutput::write_state(light::LightState *state) { } // the bits are already in the correct order for the pio program so we can just copy the buffer using DMA + sem_acquire_blocking(&RP2040PIOLEDStripLightOutput::dma_write_complete_sem_[this->dma_chan_]); dma_channel_transfer_from_buffer_now(this->dma_chan_, this->buf_, this->get_buffer_size_()); } diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.h b/esphome/components/rp2040_pio_led_strip/led_strip.h index 9976842f02..7b62648974 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.h +++ b/esphome/components/rp2040_pio_led_strip/led_strip.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace esphome { @@ -95,6 +96,8 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { size_t get_buffer_size_() const { return this->num_leds_ * (3 + this->is_rgbw_); } + static void dma_write_complete_handler_(); + uint8_t *buf_{nullptr}; uint8_t *effect_data_{nullptr}; @@ -120,6 +123,8 @@ class RP2040PIOLEDStripLightOutput : public light::AddressableLight { inline static int num_instance_[2]; inline static std::map conf_count_; inline static std::map chipset_offsets_; + inline static bool dma_chan_active_[12]; + inline static struct semaphore dma_write_complete_sem_[12]; }; } // namespace rp2040_pio_led_strip From c043bbe598f7b3d92c2a12969b1f2fbecc1f4fb6 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Tue, 20 Aug 2024 00:22:19 +0200 Subject: [PATCH 2274/2607] add the ability to add more idf components to an existing setup (#7302) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 0a5dd46478..b630c7638e 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -172,6 +172,19 @@ def add_idf_component( KEY_COMPONENTS: components, KEY_SUBMODULES: submodules, } + else: + component_config = CORE.data[KEY_ESP32][KEY_COMPONENTS][name] + if components is not None: + component_config[KEY_COMPONENTS] = list( + set(component_config[KEY_COMPONENTS] + components) + ) + if submodules is not None: + if component_config[KEY_SUBMODULES] is None: + component_config[KEY_SUBMODULES] = submodules + else: + component_config[KEY_SUBMODULES] = list( + set(component_config[KEY_SUBMODULES] + submodules) + ) def add_extra_script(stage: str, filename: str, path: str): From 436c6282da1a1c784ab7365f99e59fc00f88cf0f Mon Sep 17 00:00:00 2001 From: Sung-jin Brian Hong Date: Wed, 21 Aug 2024 08:44:21 +0900 Subject: [PATCH 2275/2607] Fix waveshare 2.13" epaper stride calculation error (#7303) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/waveshare_epaper/waveshare_epaper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 24df428e6f..7c1d436673 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -480,7 +480,7 @@ void HOT WaveshareEPaperTypeA::display() { this->start_data_(); switch (this->model_) { case TTGO_EPAPER_2_13_IN_B1: { // block needed because of variable initializations - int16_t wb = ((this->get_width_internal()) >> 3); + int16_t wb = ((this->get_width_controller()) >> 3); for (int i = 0; i < this->get_height_internal(); i++) { for (int j = 0; j < wb; j++) { int idx = j + (this->get_height_internal() - 1 - i) * wb; @@ -766,7 +766,7 @@ void WaveshareEPaper2P7InV2::initialize() { // XRAM_START_AND_END_POSITION this->command(0x44); this->data(0x00); - this->data(((get_width_internal() - 1) >> 3) & 0xFF); + this->data(((this->get_width_controller() - 1) >> 3) & 0xFF); // YRAM_START_AND_END_POSITION this->command(0x45); this->data(0x00); @@ -928,8 +928,8 @@ void HOT WaveshareEPaper2P7InB::display() { // TCON_RESOLUTION this->command(0x61); - this->data(this->get_width_internal() >> 8); - this->data(this->get_width_internal() & 0xff); // 176 + this->data(this->get_width_controller() >> 8); + this->data(this->get_width_controller() & 0xff); // 176 this->data(this->get_height_internal() >> 8); this->data(this->get_height_internal() & 0xff); // 264 @@ -994,7 +994,7 @@ void WaveshareEPaper2P7InBV2::initialize() { // self.SetWindows(0, 0, self.width-1, self.height-1) // SetWindows(self, Xstart, Ystart, Xend, Yend): - uint32_t xend = this->get_width_internal() - 1; + uint32_t xend = this->get_width_controller() - 1; uint32_t yend = this->get_height_internal() - 1; this->command(0x44); this->data(0x00); From aaae8f4a87d2ed38c35e16705cea0186120e876e Mon Sep 17 00:00:00 2001 From: NewoPL <27411874+NewoPL@users.noreply.github.com> Date: Wed, 21 Aug 2024 01:46:15 +0200 Subject: [PATCH 2276/2607] [rtttl] fix STOPPED state (#7323) --- esphome/components/rtttl/rtttl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index a97120499d..495b5c1c8a 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -32,7 +32,7 @@ void Rtttl::play(std::string rtttl) { if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { int pos = this->rtttl_.find(':'); auto name = this->rtttl_.substr(0, pos); - ESP_LOGW(TAG, "RTTL Component is already playing: %s", name.c_str()); + ESP_LOGW(TAG, "RTTTL Component is already playing: %s", name.c_str()); return; } @@ -122,6 +122,7 @@ void Rtttl::stop() { #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); + this->set_state_(STATE_STOPPED); } #endif #ifdef USE_SPEAKER @@ -129,10 +130,10 @@ void Rtttl::stop() { if (this->speaker_->is_running()) { this->speaker_->stop(); } + this->set_state_(STATE_STOPPING); } #endif this->note_duration_ = 0; - this->set_state_(STATE_STOPPING); } void Rtttl::loop() { @@ -342,6 +343,7 @@ void Rtttl::finish_() { #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); + this->set_state_(State::STATE_STOPPED); } #endif #ifdef USE_SPEAKER @@ -354,9 +356,9 @@ void Rtttl::finish_() { this->speaker_->play((uint8_t *) (&sample), 8); this->speaker_->finish(); + this->set_state_(State::STATE_STOPPING); } #endif - this->set_state_(State::STATE_STOPPING); this->note_duration_ = 0; this->on_finished_playback_callback_.call(); ESP_LOGD(TAG, "Playback finished"); From 4ed6a648699c47c135ac992171757d49c75fbf74 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:46:56 +1200 Subject: [PATCH 2277/2607] Bump version to 2024.8.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index a321ddd19f..788eca10a1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0b3" +__version__ = "2024.8.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 5d4bf5f8e5431cb3e08ccfddba9ce4bc269ab263 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:20:29 +1200 Subject: [PATCH 2278/2607] Bump version to 2024.8.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 788eca10a1..f99d442be3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0b4" +__version__ = "2024.8.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 68272c39c0176ce33c13646ac29ccb3d3d0ca981 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Thu, 22 Aug 2024 02:58:11 +0200 Subject: [PATCH 2279/2607] Add output source priority "hybrid" (#7322) --- esphome/components/pipsolar/pipsolar.cpp | 3 +++ esphome/components/pipsolar/pipsolar.h | 1 + esphome/components/pipsolar/switch/__init__.py | 2 ++ tests/components/pipsolar/test.esp32-ard.yaml | 2 ++ tests/components/pipsolar/test.esp32-c3-ard.yaml | 2 ++ tests/components/pipsolar/test.esp32-c3-idf.yaml | 2 ++ tests/components/pipsolar/test.esp32-idf.yaml | 2 ++ tests/components/pipsolar/test.esp8266-ard.yaml | 2 ++ tests/components/pipsolar/test.rp2040-ard.yaml | 2 ++ 9 files changed, 18 insertions(+) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index 2cd1aeba44..c4bc018b75 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -136,6 +136,9 @@ void Pipsolar::loop() { if (this->output_source_priority_battery_switch_) { this->output_source_priority_battery_switch_->publish_state(value_output_source_priority_ == 2); } + if (this->output_source_priority_hybrid_switch_) { + this->output_source_priority_hybrid_switch_->publish_state(value_output_source_priority_ == 3); + } if (this->charger_source_priority_) { this->charger_source_priority_->publish_state(value_charger_source_priority_); } diff --git a/esphome/components/pipsolar/pipsolar.h b/esphome/components/pipsolar/pipsolar.h index f20f44f095..373911b2d7 100644 --- a/esphome/components/pipsolar/pipsolar.h +++ b/esphome/components/pipsolar/pipsolar.h @@ -174,6 +174,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { PIPSOLAR_SWITCH(output_source_priority_utility_switch, QPIRI) PIPSOLAR_SWITCH(output_source_priority_solar_switch, QPIRI) PIPSOLAR_SWITCH(output_source_priority_battery_switch, QPIRI) + PIPSOLAR_SWITCH(output_source_priority_hybrid_switch, QPIRI) PIPSOLAR_SWITCH(input_voltage_range_switch, QPIRI) PIPSOLAR_SWITCH(pv_ok_condition_for_parallel_switch, QPIRI) PIPSOLAR_SWITCH(pv_power_balance_switch, QPIRI) diff --git a/esphome/components/pipsolar/switch/__init__.py b/esphome/components/pipsolar/switch/__init__.py index 7658c7d4f8..80bcdad62e 100644 --- a/esphome/components/pipsolar/switch/__init__.py +++ b/esphome/components/pipsolar/switch/__init__.py @@ -9,6 +9,7 @@ DEPENDENCIES = ["uart"] CONF_OUTPUT_SOURCE_PRIORITY_UTILITY = "output_source_priority_utility" CONF_OUTPUT_SOURCE_PRIORITY_SOLAR = "output_source_priority_solar" CONF_OUTPUT_SOURCE_PRIORITY_BATTERY = "output_source_priority_battery" +CONF_OUTPUT_SOURCE_PRIORITY_HYBRID = "output_source_priority_hybrid" CONF_INPUT_VOLTAGE_RANGE = "input_voltage_range" CONF_PV_OK_CONDITION_FOR_PARALLEL = "pv_ok_condition_for_parallel" CONF_PV_POWER_BALANCE = "pv_power_balance" @@ -17,6 +18,7 @@ TYPES = { CONF_OUTPUT_SOURCE_PRIORITY_UTILITY: ("POP00", None), CONF_OUTPUT_SOURCE_PRIORITY_SOLAR: ("POP01", None), CONF_OUTPUT_SOURCE_PRIORITY_BATTERY: ("POP02", None), + CONF_OUTPUT_SOURCE_PRIORITY_HYBRID: ("POP03", None), CONF_INPUT_VOLTAGE_RANGE: ("PGR01", "PGR00"), CONF_PV_OK_CONDITION_FOR_PARALLEL: ("PPVOKC1", "PPVOKC0"), CONF_PV_POWER_BALANCE: ("PSPB1", "PSPB0"), diff --git a/tests/components/pipsolar/test.esp32-ard.yaml b/tests/components/pipsolar/test.esp32-ard.yaml index fcd4575739..b7a7e0cbd9 100644 --- a/tests/components/pipsolar/test.esp32-ard.yaml +++ b/tests/components/pipsolar/test.esp32-ard.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: diff --git a/tests/components/pipsolar/test.esp32-c3-ard.yaml b/tests/components/pipsolar/test.esp32-c3-ard.yaml index 12e9266343..83d7070669 100644 --- a/tests/components/pipsolar/test.esp32-c3-ard.yaml +++ b/tests/components/pipsolar/test.esp32-c3-ard.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: diff --git a/tests/components/pipsolar/test.esp32-c3-idf.yaml b/tests/components/pipsolar/test.esp32-c3-idf.yaml index 12e9266343..83d7070669 100644 --- a/tests/components/pipsolar/test.esp32-c3-idf.yaml +++ b/tests/components/pipsolar/test.esp32-c3-idf.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: diff --git a/tests/components/pipsolar/test.esp32-idf.yaml b/tests/components/pipsolar/test.esp32-idf.yaml index fcd4575739..b7a7e0cbd9 100644 --- a/tests/components/pipsolar/test.esp32-idf.yaml +++ b/tests/components/pipsolar/test.esp32-idf.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: diff --git a/tests/components/pipsolar/test.esp8266-ard.yaml b/tests/components/pipsolar/test.esp8266-ard.yaml index 12e9266343..83d7070669 100644 --- a/tests/components/pipsolar/test.esp8266-ard.yaml +++ b/tests/components/pipsolar/test.esp8266-ard.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: diff --git a/tests/components/pipsolar/test.rp2040-ard.yaml b/tests/components/pipsolar/test.rp2040-ard.yaml index 12e9266343..83d7070669 100644 --- a/tests/components/pipsolar/test.rp2040-ard.yaml +++ b/tests/components/pipsolar/test.rp2040-ard.yaml @@ -220,6 +220,8 @@ switch: name: inverter0_output_source_priority_solar output_source_priority_battery: name: inverter0_output_source_priority_battery + output_source_priority_hybrid: + name: inverter0_output_source_priority_hybrid input_voltage_range: name: inverter0_input_voltage_range pv_ok_condition_for_parallel: From 11e155d86657c24014694cca23200d5a80b75cb2 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 21 Aug 2024 17:58:43 -0700 Subject: [PATCH 2280/2607] Enable verbose mode from env ESPHOME_VERBOSE or --verbose (#6987) --- esphome/__main__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 5c197ff486..cf2741dbdb 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -38,7 +38,7 @@ from esphome.const import ( SECRETS_FILES, ) from esphome.core import CORE, EsphomeError, coroutine -from esphome.helpers import indent, is_ip_address +from esphome.helpers import indent, is_ip_address, get_bool_env from esphome.log import Fore, color, setup_log from esphome.util import ( get_serial_ports, @@ -731,7 +731,11 @@ POST_CONFIG_ACTIONS = { def parse_args(argv): options_parser = argparse.ArgumentParser(add_help=False) options_parser.add_argument( - "-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true" + "-v", + "--verbose", + help="Enable verbose ESPHome logs.", + action="store_true", + default=get_bool_env("ESPHOME_VERBOSE"), ) options_parser.add_argument( "-q", "--quiet", help="Disable all ESPHome logs.", action="store_true" From ab620acd4f086242dd6ecbe6f5763962982dc303 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Thu, 22 Aug 2024 02:59:31 +0200 Subject: [PATCH 2281/2607] Tuya Number: allow to set hidden datapoints (#7024) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/tuya/__init__.py | 1 + esphome/components/tuya/number/__init__.py | 38 ++++++++++++++++++- .../components/tuya/number/tuya_number.cpp | 19 ++++++++++ esphome/components/tuya/number/tuya_number.h | 6 ++- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/esphome/components/tuya/__init__.py b/esphome/components/tuya/__init__.py index 2eaaa2a625..0738f9b6a4 100644 --- a/esphome/components/tuya/__init__.py +++ b/esphome/components/tuya/__init__.py @@ -15,6 +15,7 @@ CONF_DATAPOINT_TYPE = "datapoint_type" CONF_STATUS_PIN = "status_pin" tuya_ns = cg.esphome_ns.namespace("tuya") +TuyaDatapointType = tuya_ns.enum("TuyaDatapointType", is_class=True) Tuya = tuya_ns.class_("Tuya", cg.Component, uart.UARTDevice) DPTYPE_ANY = "any" diff --git a/esphome/components/tuya/number/__init__.py b/esphome/components/tuya/number/__init__.py index 4dae6d8d60..25be6329ab 100644 --- a/esphome/components/tuya/number/__init__.py +++ b/esphome/components/tuya/number/__init__.py @@ -8,18 +8,36 @@ from esphome.const import ( CONF_MIN_VALUE, CONF_MULTIPLY, CONF_STEP, + CONF_INITIAL_VALUE, ) -from .. import tuya_ns, CONF_TUYA_ID, Tuya +from .. import tuya_ns, CONF_TUYA_ID, Tuya, TuyaDatapointType DEPENDENCIES = ["tuya"] CODEOWNERS = ["@frankiboy1"] +CONF_DATAPOINT_HIDDEN = "datapoint_hidden" +CONF_DATAPOINT_TYPE = "datapoint_type" + TuyaNumber = tuya_ns.class_("TuyaNumber", number.Number, cg.Component) +DATAPOINT_TYPES = { + "int": TuyaDatapointType.INTEGER, + "uint": TuyaDatapointType.INTEGER, + "enum": TuyaDatapointType.ENUM, +} + def validate_min_max(config): - if config[CONF_MAX_VALUE] <= config[CONF_MIN_VALUE]: + max_value = config[CONF_MAX_VALUE] + min_value = config[CONF_MIN_VALUE] + if max_value <= min_value: raise cv.Invalid("max_value must be greater than min_value") + if hidden_config := config.get(CONF_DATAPOINT_HIDDEN): + if (initial_value := hidden_config.get(CONF_INITIAL_VALUE, None)) is not None: + if (initial_value > max_value) or (initial_value < min_value): + raise cv.Invalid( + f"{CONF_INITIAL_VALUE} must be a value between {CONF_MAX_VALUE} and {CONF_MIN_VALUE}" + ) return config @@ -33,6 +51,16 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_MIN_VALUE): cv.float_, cv.Required(CONF_STEP): cv.positive_float, cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_, + cv.Optional(CONF_DATAPOINT_HIDDEN): cv.All( + cv.Schema( + { + cv.Required(CONF_DATAPOINT_TYPE): cv.enum( + DATAPOINT_TYPES, lower=True + ), + cv.Optional(CONF_INITIAL_VALUE): cv.float_, + } + ) + ), } ) .extend(cv.COMPONENT_SCHEMA), @@ -56,3 +84,9 @@ async def to_code(config): cg.add(var.set_tuya_parent(parent)) cg.add(var.set_number_id(config[CONF_NUMBER_DATAPOINT])) + if hidden_config := config.get(CONF_DATAPOINT_HIDDEN): + cg.add(var.set_datapoint_type(hidden_config[CONF_DATAPOINT_TYPE])) + if ( + hidden_init_value := hidden_config.get(CONF_INITIAL_VALUE, None) + ) is not None: + cg.add(var.set_datapoint_initial_value(hidden_init_value)) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index e883c72d3d..7eeb08fde2 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -15,8 +15,18 @@ void TuyaNumber::setup() { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); } + if ((this->type_) && (this->type_ != datapoint.type)) { + ESP_LOGW(TAG, "Reported type (%d) different than previously set (%d)!", static_cast(datapoint.type), + static_cast(*this->type_)); + } this->type_ = datapoint.type; }); + + this->parent_->add_on_initialized_callback([this] { + if ((this->initial_value_) && (this->type_)) { + this->control(*this->initial_value_); + } + }); } void TuyaNumber::control(float value) { @@ -33,6 +43,15 @@ void TuyaNumber::control(float value) { void TuyaNumber::dump_config() { LOG_NUMBER("", "Tuya Number", this); ESP_LOGCONFIG(TAG, " Number has datapoint ID %u", this->number_id_); + if (this->type_) { + ESP_LOGCONFIG(TAG, " Datapoint type is %d", static_cast(*this->type_)); + } else { + ESP_LOGCONFIG(TAG, " Datapoint type is unknown"); + } + + if (this->initial_value_) { + ESP_LOGCONFIG(TAG, " Initial Value: %f", *this->initial_value_); + } } } // namespace tuya diff --git a/esphome/components/tuya/number/tuya_number.h b/esphome/components/tuya/number/tuya_number.h index f64dac8957..545584128e 100644 --- a/esphome/components/tuya/number/tuya_number.h +++ b/esphome/components/tuya/number/tuya_number.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/components/tuya/tuya.h" #include "esphome/components/number/number.h" +#include "esphome/core/optional.h" namespace esphome { namespace tuya { @@ -13,6 +14,8 @@ class TuyaNumber : public number::Number, public Component { void dump_config() override; void set_number_id(uint8_t number_id) { this->number_id_ = number_id; } void set_write_multiply(float factor) { multiply_by_ = factor; } + void set_datapoint_type(TuyaDatapointType type) { type_ = type; } + void set_datapoint_initial_value(float value) { this->initial_value_ = value; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } @@ -22,7 +25,8 @@ class TuyaNumber : public number::Number, public Component { Tuya *parent_; uint8_t number_id_{0}; float multiply_by_{1.0}; - TuyaDatapointType type_{}; + optional type_{}; + optional initial_value_{}; }; } // namespace tuya From 5cc8dbace41f3f5863473d60367f0d32c876ac7c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 23 Aug 2024 04:56:53 +1000 Subject: [PATCH 2282/2607] [lvgl] Bug fixes (#7338) --- esphome/components/lvgl/automation.py | 16 +++++++++++++--- esphome/components/lvgl/lvgl_esphome.cpp | 7 +++++++ esphome/components/lvgl/lvgl_esphome.h | 1 + esphome/components/lvgl/widgets/__init__.py | 6 ++++++ esphome/components/lvgl/widgets/line.py | 12 +++++++----- esphome/components/lvgl/widgets/msgbox.py | 3 ++- tests/components/lvgl/lvgl-package.yaml | 6 +++++- 7 files changed, 41 insertions(+), 10 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index a39f589136..efcac977ab 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -5,6 +5,7 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome.cpp_generator import RawExpression from esphome.cpp_types import nullptr from .defines import ( @@ -26,6 +27,7 @@ from .lvcode import ( add_line_marks, lv, lv_add, + lv_expr, lv_obj, lvgl_comp, ) @@ -38,7 +40,13 @@ from .types import ( lv_disp_t, lv_obj_t, ) -from .widgets import Widget, get_widgets, lv_scr_act, set_obj_properties +from .widgets import ( + Widget, + get_widgets, + lv_scr_act, + set_obj_properties, + wait_for_widgets, +) async def action_to_code( @@ -48,10 +56,12 @@ async def action_to_code( template_arg, args, ): + await wait_for_widgets() async with LambdaContext(parameters=args, where=action_id) as context: + with LvConditional(lv_expr.is_pre_initialise()): + context.add(RawExpression("return")) for widget in widgets: - with LvConditional(widget.obj != nullptr): - await action(widget) + await action(widget) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) return var diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 92f7a880c3..6882986e7c 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -294,6 +294,13 @@ void LvglComponent::loop() { } lv_timer_handler_run_in_period(5); } +bool lv_is_pre_initialise() { + if (!lv_is_initialized()) { + ESP_LOGE(TAG, "LVGL call before component is initialised"); + return true; + } + return false; +} #ifdef USE_LVGL_IMAGE lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 3a3d1aa6c5..df3d4aa68c 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -40,6 +40,7 @@ namespace lvgl { extern lv_event_code_t lv_api_event; // NOLINT extern lv_event_code_t lv_update_event; // NOLINT +extern bool lv_is_pre_initialise(); #ifdef USE_LVGL_COLOR inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } #endif // USE_LVGL_COLOR diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 4abb25c61d..50da6e131d 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -1,3 +1,4 @@ +import asyncio import sys from typing import Any, Union @@ -223,6 +224,11 @@ async def get_widget_(wid: Widget): return await FakeAwaitable(get_widget_generator(wid)) +async def wait_for_widgets(): + while not Widget.widgets_completed: + await asyncio.sleep(0) + + async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]: if not config: return [] diff --git a/esphome/components/lvgl/widgets/line.py b/esphome/components/lvgl/widgets/line.py index 8ce4b1965f..4c6439fde4 100644 --- a/esphome/components/lvgl/widgets/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -3,7 +3,7 @@ import functools import esphome.codegen as cg import esphome.config_validation as cv -from ..defines import CONF_MAIN, literal +from ..defines import CONF_MAIN from ..lvcode import lv from ..types import LvType from . import Widget, WidgetType @@ -38,13 +38,15 @@ LINE_SCHEMA = { class LineType(WidgetType): def __init__(self): - super().__init__(CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA) + super().__init__( + CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA, modify_schema={} + ) async def to_code(self, w: Widget, config): """For a line object, create and add the points""" - data = literal(config[CONF_POINTS]) - points = cg.static_const_array(config[CONF_POINT_LIST_ID], data) - lv.line_set_points(w.obj, points, len(data)) + if data := config.get(CONF_POINTS): + points = cg.static_const_array(config[CONF_POINT_LIST_ID], data) + lv.line_set_points(w.obj, points, len(data)) line_spec = LineType() diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index 63c4326c7c..c377af6bde 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -13,7 +13,7 @@ from ..defines import ( TYPE_FLEX, literal, ) -from ..helpers import add_lv_use +from ..helpers import add_lv_use, lvgl_components_required from ..lv_validation import lv_bool, lv_pct, lv_text from ..lvcode import ( EVENT_ARG, @@ -72,6 +72,7 @@ async def msgbox_to_code(conf): *buttonmatrix_spec.get_uses(), *button_spec.get_uses(), ) + lvgl_components_required.add("BUTTONMATRIX") messagebox_id = conf[CONF_ID] outer = lv_Pvariable(lv_obj_t, messagebox_id.id) buttonmatrix = new_Pvariable( diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 800d6eff27..1479ce7358 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -379,6 +379,7 @@ lvgl: format: "bar value %f" args: [x] - line: + id: lv_line_id align: center points: - 5, 5 @@ -387,7 +388,10 @@ lvgl: - 180, 60 - 240, 10 on_click: - lvgl.page.next: + - lvgl.widget.update: + id: lv_line_id + line_color: 0xFFFF + - lvgl.page.next: - switch: align: right_mid - checkbox: From 3c65cabe1dc7a1d94cb889617427f2239e6fb734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Mart=C3=ADn?= Date: Thu, 22 Aug 2024 23:30:22 +0200 Subject: [PATCH 2283/2607] feat: Expand ByteBuffer (#7316) Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/bytebuffer.cpp | 225 +++++++++++++++++++++--------------- esphome/core/bytebuffer.h | 90 +++++++++++---- 2 files changed, 201 insertions(+), 114 deletions(-) diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp index fb2ade3166..65525ecfcf 100644 --- a/esphome/core/bytebuffer.cpp +++ b/esphome/core/bytebuffer.cpp @@ -1,19 +1,64 @@ #include "bytebuffer.h" #include +#include namespace esphome { -ByteBuffer ByteBuffer::create(size_t capacity) { - std::vector data(capacity); - return {data}; -} - -ByteBuffer ByteBuffer::wrap(uint8_t *ptr, size_t len) { +ByteBuffer ByteBuffer::wrap(const uint8_t *ptr, size_t len, Endian endianness) { + // there is a double copy happening here, could be optimized but at cost of clarity. std::vector data(ptr, ptr + len); - return {data}; + ByteBuffer buffer = {data}; + buffer.endianness_ = endianness; + return buffer; } -ByteBuffer ByteBuffer::wrap(std::vector data) { return {std::move(data)}; } +ByteBuffer ByteBuffer::wrap(std::vector const &data, Endian endianness) { + ByteBuffer buffer = {data}; + buffer.endianness_ = endianness; + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint8_t value) { + ByteBuffer buffer = ByteBuffer(1); + buffer.put_uint8(value); + buffer.flip(); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint16_t value, Endian endianness) { + ByteBuffer buffer = ByteBuffer(2, endianness); + buffer.put_uint16(value); + buffer.flip(); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint32_t value, Endian endianness) { + ByteBuffer buffer = ByteBuffer(4, endianness); + buffer.put_uint32(value); + buffer.flip(); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint64_t value, Endian endianness) { + ByteBuffer buffer = ByteBuffer(8, endianness); + buffer.put_uint64(value); + buffer.flip(); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(float value, Endian endianness) { + ByteBuffer buffer = ByteBuffer(sizeof(float), endianness); + buffer.put_float(value); + buffer.flip(); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(double value, Endian endianness) { + ByteBuffer buffer = ByteBuffer(sizeof(double), endianness); + buffer.put_double(value); + buffer.flip(); + return buffer; +} void ByteBuffer::set_limit(size_t limit) { assert(limit <= this->get_capacity()); @@ -27,108 +72,102 @@ void ByteBuffer::clear() { this->limit_ = this->get_capacity(); this->position_ = 0; } -uint16_t ByteBuffer::get_uint16() { - assert(this->get_remaining() >= 2); - uint16_t value; - if (endianness_ == LITTLE) { - value = this->data_[this->position_++]; - value |= this->data_[this->position_++] << 8; - } else { - value = this->data_[this->position_++] << 8; - value |= this->data_[this->position_++]; - } - return value; +void ByteBuffer::flip() { + this->limit_ = this->position_; + this->position_ = 0; } -uint32_t ByteBuffer::get_uint32() { - assert(this->get_remaining() >= 4); - uint32_t value; - if (endianness_ == LITTLE) { - value = this->data_[this->position_++]; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++] << 16; - value |= this->data_[this->position_++] << 24; - } else { - value = this->data_[this->position_++] << 24; - value |= this->data_[this->position_++] << 16; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++]; - } - return value; -} -uint32_t ByteBuffer::get_uint24() { - assert(this->get_remaining() >= 3); - uint32_t value; - if (endianness_ == LITTLE) { - value = this->data_[this->position_++]; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++] << 16; - } else { - value = this->data_[this->position_++] << 16; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++]; - } - return value; -} -uint32_t ByteBuffer::get_int24() { - auto value = this->get_uint24(); - uint32_t mask = (~(uint32_t) 0) << 23; - if ((value & mask) != 0) - value |= mask; - return value; -} +/// Getters uint8_t ByteBuffer::get_uint8() { assert(this->get_remaining() >= 1); return this->data_[this->position_++]; } -float ByteBuffer::get_float() { - auto value = this->get_uint32(); - return *(float *) &value; +uint64_t ByteBuffer::get_uint(size_t length) { + assert(this->get_remaining() >= length); + uint64_t value = 0; + if (this->endianness_ == LITTLE) { + this->position_ += length; + auto index = this->position_; + while (length-- != 0) { + value <<= 8; + value |= this->data_[--index]; + } + } else { + while (length-- != 0) { + value <<= 8; + value |= this->data_[this->position_++]; + } + } + return value; } + +uint32_t ByteBuffer::get_int24() { + auto value = this->get_uint24(); + uint32_t mask = (~static_cast(0)) << 23; + if ((value & mask) != 0) + value |= mask; + return value; +} +float ByteBuffer::get_float() { + assert(this->get_remaining() >= sizeof(float)); + auto ui_value = this->get_uint32(); + float value; + memcpy(&value, &ui_value, sizeof(float)); + return value; +} +double ByteBuffer::get_double() { + assert(this->get_remaining() >= sizeof(double)); + auto ui_value = this->get_uint64(); + double value; + memcpy(&value, &ui_value, sizeof(double)); + return value; +} +std::vector ByteBuffer::get_vector(size_t length) { + assert(this->get_remaining() >= length); + auto start = this->data_.begin() + this->position_; + this->position_ += length; + return {start, start + length}; +} + +/// Putters void ByteBuffer::put_uint8(uint8_t value) { assert(this->get_remaining() >= 1); this->data_[this->position_++] = value; } -void ByteBuffer::put_uint16(uint16_t value) { - assert(this->get_remaining() >= 2); +void ByteBuffer::put_uint(uint64_t value, size_t length) { + assert(this->get_remaining() >= length); if (this->endianness_ == LITTLE) { - this->data_[this->position_++] = (uint8_t) value; - this->data_[this->position_++] = (uint8_t) (value >> 8); + while (length-- != 0) { + this->data_[this->position_++] = static_cast(value); + value >>= 8; + } } else { - this->data_[this->position_++] = (uint8_t) (value >> 8); - this->data_[this->position_++] = (uint8_t) value; + this->position_ += length; + auto index = this->position_; + while (length-- != 0) { + this->data_[--index] = static_cast(value); + value >>= 8; + } } } -void ByteBuffer::put_uint24(uint32_t value) { - assert(this->get_remaining() >= 3); - if (this->endianness_ == LITTLE) { - this->data_[this->position_++] = (uint8_t) value; - this->data_[this->position_++] = (uint8_t) (value >> 8); - this->data_[this->position_++] = (uint8_t) (value >> 16); - } else { - this->data_[this->position_++] = (uint8_t) (value >> 16); - this->data_[this->position_++] = (uint8_t) (value >> 8); - this->data_[this->position_++] = (uint8_t) value; - } +void ByteBuffer::put_float(float value) { + static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); + assert(this->get_remaining() >= sizeof(float)); + uint32_t ui_value; + memcpy(&ui_value, &value, sizeof(float)); // this work-around required to silence compiler warnings + this->put_uint32(ui_value); } -void ByteBuffer::put_uint32(uint32_t value) { - assert(this->get_remaining() >= 4); - if (this->endianness_ == LITTLE) { - this->data_[this->position_++] = (uint8_t) value; - this->data_[this->position_++] = (uint8_t) (value >> 8); - this->data_[this->position_++] = (uint8_t) (value >> 16); - this->data_[this->position_++] = (uint8_t) (value >> 24); - } else { - this->data_[this->position_++] = (uint8_t) (value >> 24); - this->data_[this->position_++] = (uint8_t) (value >> 16); - this->data_[this->position_++] = (uint8_t) (value >> 8); - this->data_[this->position_++] = (uint8_t) value; - } +void ByteBuffer::put_double(double value) { + static_assert(sizeof(double) == sizeof(uint64_t), "Double sizes other than 64 bit not supported"); + assert(this->get_remaining() >= sizeof(double)); + uint64_t ui_value; + memcpy(&ui_value, &value, sizeof(double)); + this->put_uint64(ui_value); } -void ByteBuffer::put_float(float value) { this->put_uint32(*(uint32_t *) &value); } -void ByteBuffer::flip() { - this->limit_ = this->position_; - this->position_ = 0; +void ByteBuffer::put_vector(const std::vector &value) { + assert(this->get_remaining() >= value.size()); + std::copy(value.begin(), value.end(), this->data_.begin() + this->position_); + this->position_ += value.size(); } } // namespace esphome diff --git a/esphome/core/bytebuffer.h b/esphome/core/bytebuffer.h index f242e5e333..d44d01f275 100644 --- a/esphome/core/bytebuffer.h +++ b/esphome/core/bytebuffer.h @@ -15,55 +15,103 @@ enum Endian { LITTLE, BIG }; * * There are three variables maintained pointing into the buffer: * - * 0 <= position <= limit <= capacity - * - * capacity: the maximum amount of data that can be stored + * capacity: the maximum amount of data that can be stored - set on construction and cannot be changed * limit: the limit of the data currently available to get or put * position: the current insert or extract position * + * 0 <= position <= limit <= capacity + * * In addition a mark can be set to the current position with mark(). A subsequent call to reset() will restore * the position to the mark. * * The buffer can be marked to be little-endian (default) or big-endian. All subsequent operations will use that order. * + * The flip() operation will reset the position to 0 and limit to the current position. This is useful for reading + * data from a buffer after it has been written. + * */ class ByteBuffer { public: + // Default constructor (compatibility with TEMPLATABLE_VALUE) + ByteBuffer() : ByteBuffer(std::vector()) {} /** * Create a new Bytebuffer with the given capacity */ - static ByteBuffer create(size_t capacity); + ByteBuffer(size_t capacity, Endian endianness = LITTLE) + : data_(std::vector(capacity)), endianness_(endianness), limit_(capacity){}; /** - * Wrap an existing vector in a Bytebufffer + * Wrap an existing vector in a ByteBufffer */ - static ByteBuffer wrap(std::vector data); + static ByteBuffer wrap(std::vector const &data, Endian endianness = LITTLE); /** - * Wrap an existing array in a Bytebufffer + * Wrap an existing array in a ByteBuffer. Note that this will create a copy of the data. */ - static ByteBuffer wrap(uint8_t *ptr, size_t len); + static ByteBuffer wrap(const uint8_t *ptr, size_t len, Endian endianness = LITTLE); + // Convenience functions to create a ByteBuffer from a value + static ByteBuffer wrap(uint8_t value); + static ByteBuffer wrap(uint16_t value, Endian endianness = LITTLE); + static ByteBuffer wrap(uint32_t value, Endian endianness = LITTLE); + static ByteBuffer wrap(uint64_t value, Endian endianness = LITTLE); + static ByteBuffer wrap(int8_t value) { return wrap(static_cast(value)); } + static ByteBuffer wrap(int16_t value, Endian endianness = LITTLE) { + return wrap(static_cast(value), endianness); + } + static ByteBuffer wrap(int32_t value, Endian endianness = LITTLE) { + return wrap(static_cast(value), endianness); + } + static ByteBuffer wrap(int64_t value, Endian endianness = LITTLE) { + return wrap(static_cast(value), endianness); + } + static ByteBuffer wrap(float value, Endian endianness = LITTLE); + static ByteBuffer wrap(double value, Endian endianness = LITTLE); + static ByteBuffer wrap(bool value) { return wrap(static_cast(value)); } + // Get an integral value from the buffer, increment position by length + uint64_t get_uint(size_t length); // Get one byte from the buffer, increment position by 1 uint8_t get_uint8(); // Get a 16 bit unsigned value, increment by 2 - uint16_t get_uint16(); + uint16_t get_uint16() { return static_cast(this->get_uint(sizeof(uint16_t))); }; // Get a 24 bit unsigned value, increment by 3 - uint32_t get_uint24(); + uint32_t get_uint24() { return static_cast(this->get_uint(3)); }; // Get a 32 bit unsigned value, increment by 4 - uint32_t get_uint32(); - // signed versions of the get functions - uint8_t get_int8() { return (int8_t) this->get_uint8(); }; - int16_t get_int16() { return (int16_t) this->get_uint16(); } + uint32_t get_uint32() { return static_cast(this->get_uint(sizeof(uint32_t))); }; + // Get a 64 bit unsigned value, increment by 8 + uint64_t get_uint64() { return this->get_uint(sizeof(uint64_t)); }; + // Signed versions of the get functions + uint8_t get_int8() { return static_cast(this->get_uint8()); }; + int16_t get_int16() { return static_cast(this->get_uint(sizeof(int16_t))); } uint32_t get_int24(); - int32_t get_int32() { return (int32_t) this->get_uint32(); } + int32_t get_int32() { return static_cast(this->get_uint(sizeof(int32_t))); } + int64_t get_int64() { return static_cast(this->get_uint(sizeof(int64_t))); } // Get a float value, increment by 4 float get_float(); + // Get a double value, increment by 8 + double get_double(); + // Get a bool value, increment by 1 + bool get_bool() { return this->get_uint8(); } + // Get vector of bytes, increment by length + std::vector get_vector(size_t length); - // put values into the buffer, increment the position accordingly + // Put values into the buffer, increment the position accordingly + // put any integral value, length represents the number of bytes + void put_uint(uint64_t value, size_t length); void put_uint8(uint8_t value); - void put_uint16(uint16_t value); - void put_uint24(uint32_t value); - void put_uint32(uint32_t value); + void put_uint16(uint16_t value) { this->put_uint(value, sizeof(uint16_t)); } + void put_uint24(uint32_t value) { this->put_uint(value, 3); } + void put_uint32(uint32_t value) { this->put_uint(value, sizeof(uint32_t)); } + void put_uint64(uint64_t value) { this->put_uint(value, sizeof(uint64_t)); } + // Signed versions of the put functions + void put_int8(int8_t value) { this->put_uint8(static_cast(value)); } + void put_int16(int32_t value) { this->put_uint(static_cast(value), sizeof(uint16_t)); } + void put_int24(int32_t value) { this->put_uint(static_cast(value), 3); } + void put_int32(int32_t value) { this->put_uint(static_cast(value), sizeof(uint32_t)); } + void put_int64(int64_t value) { this->put_uint(static_cast(value), sizeof(uint64_t)); } + // Extra put functions void put_float(float value); + void put_double(double value); + void put_bool(bool value) { this->put_uint8(value); } + void put_vector(const std::vector &value); inline size_t get_capacity() const { return this->data_.size(); } inline size_t get_position() const { return this->position_; } @@ -80,12 +128,12 @@ class ByteBuffer { // set limit to current position, postition to zero. Used when swapping from write to read operations. void flip(); // retrieve a pointer to the underlying data. - uint8_t *array() { return this->data_.data(); }; + std::vector get_data() { return this->data_; }; void rewind() { this->position_ = 0; } void reset() { this->position_ = this->mark_; } protected: - ByteBuffer(std::vector data) : data_(std::move(data)) { this->limit_ = this->get_capacity(); } + ByteBuffer(std::vector const &data) : data_(data), limit_(data.size()) {} std::vector data_; Endian endianness_{LITTLE}; size_t position_{0}; From 43f8f2fd2ef30802025e078c4be0f0afcc08308f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:09:40 +1000 Subject: [PATCH 2284/2607] [core] Clean build if the loaded integrations changed (#7344) --- esphome/writer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/writer.py b/esphome/writer.py index c6111cbe3f..57435d3463 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -106,6 +106,8 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool: return True if old.build_path != new.build_path: return True + if old.loaded_integrations != new.loaded_integrations: + return True return False @@ -117,7 +119,9 @@ def update_storage_json(): return if storage_should_clean(old, new): - _LOGGER.info("Core config or version changed, cleaning build files...") + _LOGGER.info( + "Core config, version or integrations changed, cleaning build files..." + ) clean_build() new.save(path) From a01fea54a03e26ce265cd44780c6166d73973a28 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sat, 24 Aug 2024 02:32:08 -0500 Subject: [PATCH 2285/2607] [ledc] Tweak fix in #6997 (#7336) --- esphome/components/ledc/ledc_output.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 90e11fe4ad..7f91eb2d7a 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -8,6 +8,8 @@ #endif #include +#include + #define CLOCK_FREQUENCY 80e6f #ifdef USE_ARDUINO @@ -120,13 +122,17 @@ void LEDCOutput::write_state(float state) { ledcWrite(this->channel_, duty); #endif #ifdef USE_ESP_IDF +#if !defined(USE_ESP32_VARIANT_ESP32C3) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)) // ensure that 100% on is not 99.975% on + // note: on the C3, this tweak will result in the outputs turning off at 100%, so it has been omitted if ((duty == max_duty) && (max_duty != 1)) { duty = max_duty + 1; } +#endif auto speed_mode = get_speed_mode(channel_); auto chan_num = static_cast(channel_ % 8); int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); + ESP_LOGV(TAG, "Setting duty: %" PRIu32 " on channel %u", duty, this->channel_); ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); ledc_update_duty(speed_mode, chan_num); #endif From caaae59ea9db397bc80e6e51504bd698ece059f3 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sat, 24 Aug 2024 19:56:13 +1000 Subject: [PATCH 2286/2607] [ledc] Fix maximum brightness on ESP-IDF 5.1 (#7342) Co-authored-by: Keith Burzinski --- esphome/components/ledc/ledc_output.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 7f91eb2d7a..4ced4b8f76 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -117,24 +117,22 @@ void LEDCOutput::write_state(float state) { const uint32_t max_duty = (uint32_t(1) << this->bit_depth_) - 1; const float duty_rounded = roundf(state * max_duty); auto duty = static_cast(duty_rounded); + ESP_LOGV(TAG, "Setting duty: %" PRIu32 " on channel %u", duty, this->channel_); #ifdef USE_ARDUINO - ESP_LOGV(TAG, "Setting duty: %u on channel %u", duty, this->channel_); ledcWrite(this->channel_, duty); #endif #ifdef USE_ESP_IDF -#if !defined(USE_ESP32_VARIANT_ESP32C3) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)) - // ensure that 100% on is not 99.975% on - // note: on the C3, this tweak will result in the outputs turning off at 100%, so it has been omitted - if ((duty == max_duty) && (max_duty != 1)) { - duty = max_duty + 1; - } -#endif auto speed_mode = get_speed_mode(channel_); auto chan_num = static_cast(channel_ % 8); int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); - ESP_LOGV(TAG, "Setting duty: %" PRIu32 " on channel %u", duty, this->channel_); - ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); - ledc_update_duty(speed_mode, chan_num); + if (duty == max_duty) { + ledc_stop(speed_mode, chan_num, 1); + } else if (duty == 0) { + ledc_stop(speed_mode, chan_num, 0); + } else { + ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); + ledc_update_duty(speed_mode, chan_num); + } #endif } From 71d6bbc7e6e7389d00609bad87e6fbab37ad34a4 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:03:25 +1000 Subject: [PATCH 2287/2607] [lvgl] Fix race condition involving numbers, switches etc. (#7345) --- esphome/components/lvgl/__init__.py | 5 ++++- esphome/components/lvgl/binary_sensor/__init__.py | 3 ++- esphome/components/lvgl/light/__init__.py | 3 ++- esphome/components/lvgl/lvcode.py | 3 +++ esphome/components/lvgl/number/__init__.py | 3 ++- esphome/components/lvgl/select/__init__.py | 3 ++- esphome/components/lvgl/sensor/__init__.py | 3 ++- esphome/components/lvgl/switch/__init__.py | 3 ++- esphome/components/lvgl/text/__init__.py | 3 ++- esphome/components/lvgl/text_sensor/__init__.py | 3 ++- esphome/components/lvgl/widgets/__init__.py | 13 ++++++++++--- 11 files changed, 33 insertions(+), 12 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 7c51d9c70d..ea020435dc 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -266,7 +266,10 @@ async def to_code(config): await add_top_layer(config) await msgboxes_to_code(config) await disp_update(f"{lv_component}->get_disp()", config) - Widget.set_completed() + # At this point only the setup code should be generated + assert LvContext.added_lambda_count == 1 + Widget.set_completed() + async with LvContext(lv_component): await generate_triggers(lv_component) for conf in config.get(CONF_ON_IDLE, ()): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) diff --git a/esphome/components/lvgl/binary_sensor/__init__.py b/esphome/components/lvgl/binary_sensor/__init__.py index 8789a06375..56984405aa 100644 --- a/esphome/components/lvgl/binary_sensor/__init__.py +++ b/esphome/components/lvgl/binary_sensor/__init__.py @@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import EVENT_ARG, LambdaContext, LvContext from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, lv_pseudo_button_t -from ..widgets import Widget, get_widgets +from ..widgets import Widget, get_widgets, wait_for_widgets CONFIG_SCHEMA = ( binary_sensor_schema(BinarySensor) @@ -29,6 +29,7 @@ async def to_code(config): widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] assert isinstance(widget, Widget) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pressed_ctx: pressed_ctx.add(sensor.publish_state(widget.is_pressed())) async with LvContext(paren) as ctx: diff --git a/esphome/components/lvgl/light/__init__.py b/esphome/components/lvgl/light/__init__.py index 27c160dff6..a0eeded349 100644 --- a/esphome/components/lvgl/light/__init__.py +++ b/esphome/components/lvgl/light/__init__.py @@ -8,7 +8,7 @@ from ..defines import CONF_LVGL_ID from ..lvcode import LvContext from ..schemas import LVGL_SCHEMA from ..types import LvType, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets lv_led_t = LvType("lv_led_t") LVLight = lvgl_ns.class_("LVLight", LightOutput) @@ -28,5 +28,6 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_LED) widget = widget[0] + await wait_for_widgets() async with LvContext(paren) as ctx: ctx.add(var.set_obj(widget.obj)) diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 6d7e364e5d..8d029ce0ca 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -176,6 +176,8 @@ class LvContext(LambdaContext): Code generation into the LVGL initialisation code (called in `setup()`) """ + added_lambda_count = 0 + def __init__(self, lv_component, args=None): self.args = args or LVGL_COMP_ARG super().__init__(parameters=self.args) @@ -183,6 +185,7 @@ class LvContext(LambdaContext): async def add_init_lambda(self): cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) + LvContext.added_lambda_count += 1 async def __aexit__(self, exc_type, exc_val, exc_tb): await super().__aexit__(exc_type, exc_val, exc_tb) diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index 6336bb0632..3e1ede0dec 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -16,7 +16,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number) @@ -44,6 +44,7 @@ async def to_code(config): step=widget.get_step(), ) + await wait_for_widgets() async with LambdaContext([(cg.float_, "v")]) as control: await widget.set_property( "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index b55bde13bc..e77d0cfb32 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -15,7 +15,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvSelect, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select) @@ -37,6 +37,7 @@ async def to_code(config): options = widget.config.get(CONF_OPTIONS, []) selector = await select.new_select(config, options=options) paren = await cg.get_variable(config[CONF_LVGL_ID]) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pub_ctx: pub_ctx.add(selector.publish_index(widget.get_value())) async with LambdaContext([(cg.uint16, "v")]) as control: diff --git a/esphome/components/lvgl/sensor/__init__.py b/esphome/components/lvgl/sensor/__init__.py index 82e21d5e95..a2a2298c27 100644 --- a/esphome/components/lvgl/sensor/__init__.py +++ b/esphome/components/lvgl/sensor/__init__.py @@ -14,7 +14,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber -from ..widgets import Widget, get_widgets +from ..widgets import Widget, get_widgets, wait_for_widgets CONFIG_SCHEMA = ( sensor_schema(Sensor) @@ -33,6 +33,7 @@ async def to_code(config): widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] assert isinstance(widget, Widget) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as lamb: lv_add(sensor.publish_state(widget.get_value())) async with LvContext(paren, LVGL_COMP_ARG): diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index 957fce17ff..f855c2a034 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -16,7 +16,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch) CONFIG_SCHEMA = ( @@ -35,6 +35,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as checked_ctx: checked_ctx.add(switch.publish_state(widget.get_value())) async with LambdaContext([(cg.bool_, "v")]) as control: diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 9ee494d8a0..56fa42e131 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -15,7 +15,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLText = lvgl_ns.class_("LVGLText", text.Text) @@ -32,6 +32,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str())") lv.event_send(widget.obj, API_EVENT, None) diff --git a/esphome/components/lvgl/text_sensor/__init__.py b/esphome/components/lvgl/text_sensor/__init__.py index cab715dce0..ae39eec291 100644 --- a/esphome/components/lvgl/text_sensor/__init__.py +++ b/esphome/components/lvgl/text_sensor/__init__.py @@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets CONFIG_SCHEMA = ( text_sensor_schema(TextSensor) @@ -28,6 +28,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pressed_ctx: pressed_ctx.add(sensor.publish_state(widget.get_value())) async with LvContext(paren) as ctx: diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 50da6e131d..17d73c1714 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -1,4 +1,3 @@ -import asyncio import sys from typing import Any, Union @@ -224,9 +223,17 @@ async def get_widget_(wid: Widget): return await FakeAwaitable(get_widget_generator(wid)) +def widgets_wait_generator(): + while True: + if Widget.widgets_completed: + return + yield + + async def wait_for_widgets(): - while not Widget.widgets_completed: - await asyncio.sleep(0) + if Widget.widgets_completed: + return + await FakeAwaitable(widgets_wait_generator()) async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]: From 60fced53c214b5ccdb7fb0907cd01e06ba899456 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:08:30 +1000 Subject: [PATCH 2288/2607] [lvgl] Bug fixes: (#7341) --- esphome/components/lvgl/automation.py | 2 +- esphome/components/lvgl/defines.py | 8 ++++++- esphome/components/lvgl/number/__init__.py | 1 + esphome/components/lvgl/select/__init__.py | 1 + esphome/components/lvgl/switch/__init__.py | 3 ++- esphome/components/lvgl/text/__init__.py | 1 + esphome/components/lvgl/widgets/__init__.py | 25 ++++++++++++++++----- tests/components/lvgl/lvgl-package.yaml | 16 +++++++++++++ 8 files changed, 49 insertions(+), 8 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index efcac977ab..eb1b54e3ec 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -157,7 +157,7 @@ async def lvgl_update_to_code(config, action_id, template_arg, args): widgets = await get_widgets(config) w = widgets[0] disp = f"{w.obj}->get_disp()" - async with LambdaContext(parameters=args, where=action_id) as context: + async with LambdaContext(LVGL_COMP_ARG, where=action_id) as context: await disp_update(disp, config) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) await cg.register_parented(var, w.var) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 6a8b20b505..7bb1667e77 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -505,4 +505,10 @@ DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" def join_enums(enums, prefix=""): - return literal("|".join(f"(int){prefix}{e.upper()}" for e in enums)) + enums = list(enums) + enums.sort() + # If a prefix is provided, prepend each constant with the prefix, and assume that all the constants are within the + # same namespace, otherwise cast to int to avoid triggering warnings about mixing enum types. + if prefix: + return literal("|".join(f"{prefix}{e.upper()}" for e in enums)) + return literal("|".join(f"(int){e.upper()}" for e in enums)) diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index 3e1ede0dec..07f92635b5 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -50,6 +50,7 @@ async def to_code(config): "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] ) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(var.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as event: event.add(var.publish_state(widget.get_value())) event_code = ( diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index e77d0cfb32..73ac50aa55 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -43,6 +43,7 @@ async def to_code(config): async with LambdaContext([(cg.uint16, "v")]) as control: await widget.set_property("selected", "v", animated=config[CONF_ANIMATED]) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(selector.publish_index(widget.get_value())) async with LvContext(paren) as ctx: lv_add(selector.set_control_lambda(await control.get_lambda())) ctx.add( diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index f855c2a034..8c090543f9 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -3,7 +3,7 @@ from esphome.components.switch import Switch, new_switch, switch_schema import esphome.config_validation as cv from esphome.cpp_generator import MockObj -from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..defines import CONF_LVGL_ID, CONF_WIDGET, literal from ..lvcode import ( API_EVENT, EVENT_ARG, @@ -44,6 +44,7 @@ async def to_code(config): cond.else_() widget.clear_state(LV_STATE.CHECKED) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(switch.publish_state(literal("v"))) async with LvContext(paren) as ctx: lv_add(switch.set_control_lambda(await control.get_lambda())) ctx.add( diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 56fa42e131..540591d24b 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -36,6 +36,7 @@ async def to_code(config): async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str())") lv.event_send(widget.obj, API_EVENT, None) + control.add(textvar.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as lamb: lv_add(textvar.publish_state(widget.get_value())) async with LvContext(paren): diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 17d73c1714..062c268135 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -118,7 +118,14 @@ class Widget: def clear_flag(self, flag): return lv_obj.clear_flag(self.obj, literal(flag)) - async def set_property(self, prop, value, animated: bool = None): + async def set_property(self, prop, value, animated: bool = None, lv_name=None): + """ + Set a property of the widget. + :param prop: The property name + :param value: The value + :param animated: If the change should be animated + :param lv_name: The base type of the widget e.g. "obj" + """ if isinstance(value, dict): value = value.get(prop) if isinstance(ALL_STYLES.get(prop), LValidator): @@ -131,11 +138,12 @@ class Widget: value = value.total_milliseconds if isinstance(value, str): value = literal(value) + lv_name = lv_name or self.type.lv_name if animated is None or self.type.animated is not True: - lv.call(f"{self.type.lv_name}_set_{prop}", self.obj, value) + lv.call(f"{lv_name}_set_{prop}", self.obj, value) else: lv.call( - f"{self.type.lv_name}_set_{prop}", + f"{lv_name}_set_{prop}", self.obj, value, literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"), @@ -319,8 +327,15 @@ async def set_obj_properties(w: Widget, config): lv_obj.set_flex_align(w.obj, main, cross, track) parts = collect_parts(config) for part, states in parts.items(): + part = "LV_PART_" + part.upper() for state, props in states.items(): - lv_state = join_enums((f"LV_STATE_{state}", f"LV_PART_{part}")) + state = "LV_STATE_" + state.upper() + if state == "LV_STATE_DEFAULT": + lv_state = literal(part) + elif part == "LV_PART_MAIN": + lv_state = literal(state) + else: + lv_state = join_enums((state, part)) for style_id in props.get(CONF_STYLES, ()): lv_obj.add_style(w.obj, MockObj(style_id), lv_state) for prop, value in { @@ -384,7 +399,7 @@ async def set_obj_properties(w: Widget, config): w.add_state(state) cond.else_() w.clear_state(state) - await w.set_property(CONF_SCROLLBAR_MODE, config) + await w.set_property(CONF_SCROLLBAR_MODE, config, lv_name="obj") async def add_widgets(parent: Widget, config: dict): diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 1479ce7358..0e2c37048b 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -1,6 +1,8 @@ lvgl: log_level: TRACE bg_color: light_blue + disp_bg_color: 0xffff00 + disp_bg_image: cat_image theme: obj: border_width: 1 @@ -78,6 +80,9 @@ lvgl: on_click: then: - lvgl.animimg.stop: anim_img + - lvgl.update: + disp_bg_color: 0xffff00 + disp_bg_image: cat_image - label: text: "Hello shiny day" text_color: 0xFFFFFF @@ -304,6 +309,17 @@ lvgl: src: cat_image align: top_left y: 50 + - tileview: + id: tileview_id + scrollbar_mode: active + tiles: + - id: page_1 + row: 0 + column: 0 + dir: HOR + widgets: + - obj: + bg_color: 0x000000 - id: page2 widgets: From dc9c00105666276540fd3a634a4609c777f9b158 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:07:18 +1200 Subject: [PATCH 2289/2607] [const] Move ``CONF_LINE_FREQUENCY`` to const.py (#7351) --- esphome/components/atm90e26/sensor.py | 20 ++++++++++---------- esphome/components/atm90e32/sensor.py | 2 +- esphome/const.py | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/esphome/components/atm90e26/sensor.py b/esphome/components/atm90e26/sensor.py index a702e23cf0..42ef259100 100644 --- a/esphome/components/atm90e26/sensor.py +++ b/esphome/components/atm90e26/sensor.py @@ -1,34 +1,34 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import sensor, spi +import esphome.config_validation as cv from esphome.const import ( - CONF_ID, - CONF_REACTIVE_POWER, - CONF_VOLTAGE, CONF_CURRENT, + CONF_FORWARD_ACTIVE_ENERGY, + CONF_FREQUENCY, + CONF_ID, + CONF_LINE_FREQUENCY, CONF_POWER, CONF_POWER_FACTOR, - CONF_FREQUENCY, - CONF_FORWARD_ACTIVE_ENERGY, + CONF_REACTIVE_POWER, CONF_REVERSE_ACTIVE_ENERGY, + CONF_VOLTAGE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_VOLTAGE, - ICON_LIGHTBULB, ICON_CURRENT_AC, + ICON_LIGHTBULB, STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, + UNIT_AMPERE, UNIT_HERTZ, UNIT_VOLT, - UNIT_AMPERE, - UNIT_WATT, UNIT_VOLT_AMPS_REACTIVE, + UNIT_WATT, UNIT_WATT_HOURS, ) -CONF_LINE_FREQUENCY = "line_frequency" CONF_METER_CONSTANT = "meter_constant" CONF_PL_CONST = "pl_const" CONF_GAIN_PGA = "gain_pga" diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index be2196223c..0dc3bfdc4f 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_FORWARD_ACTIVE_ENERGY, CONF_FREQUENCY, CONF_ID, + CONF_LINE_FREQUENCY, CONF_PHASE_A, CONF_PHASE_ANGLE, CONF_PHASE_B, @@ -39,7 +40,6 @@ from esphome.const import ( from . import atm90e32_ns -CONF_LINE_FREQUENCY = "line_frequency" CONF_CHIP_TEMPERATURE = "chip_temperature" CONF_GAIN_PGA = "gain_pga" CONF_CURRENT_PHASES = "current_phases" diff --git a/esphome/const.py b/esphome/const.py index b9c37a53a8..6e29667887 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -431,6 +431,7 @@ CONF_LIGHT_ID = "light_id" CONF_LIGHTNING_ENERGY = "lightning_energy" CONF_LIGHTNING_THRESHOLD = "lightning_threshold" CONF_LIMIT_MODE = "limit_mode" +CONF_LINE_FREQUENCY = "line_frequency" CONF_LINE_THICKNESS = "line_thickness" CONF_LINE_TYPE = "line_type" CONF_LOADED_INTEGRATIONS = "loaded_integrations" From 0f2064193f91a609ab64dc763aa17a194231be1e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:20:26 +1200 Subject: [PATCH 2290/2607] [api] Fix sending the ``once`` flag on ha entity subscription (#7357) --- esphome/components/api/api_connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bd438265d4..195fcab0ab 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -179,6 +179,7 @@ void APIConnection::loop() { SubscribeHomeAssistantStateResponse resp; resp.entity_id = it.entity_id; resp.attribute = it.attribute.value(); + resp.once = it.once; if (this->send_subscribe_home_assistant_state_response(resp)) { state_subs_at_++; } From e10f8128c8f48fd63b1d09d4e3f059da0a9a573a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 26 Aug 2024 23:41:09 +0100 Subject: [PATCH 2291/2607] bl0942: Fix init sequence, add address and line_frequency options (#7250) --- esphome/components/bl0942/bl0942.cpp | 109 ++++++++++++++----- esphome/components/bl0942/bl0942.h | 15 ++- esphome/components/bl0942/sensor.py | 28 ++++- tests/components/bl0942/test.bk72xx-ard.yaml | 22 ++++ 4 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 tests/components/bl0942/test.bk72xx-ard.yaml diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index 38b1c89036..606d3629da 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -2,6 +2,8 @@ #include "esphome/core/log.h" #include +// Datasheet: https://www.belling.com.cn/media/file_object/bel_product/BL0942/datasheet/BL0942_V1.06_en.pdf + namespace esphome { namespace bl0942 { @@ -12,33 +14,41 @@ static const uint8_t BL0942_FULL_PACKET = 0xAA; static const uint8_t BL0942_PACKET_HEADER = 0x55; static const uint8_t BL0942_WRITE_COMMAND = 0xA8; -static const uint8_t BL0942_REG_I_FAST_RMS_CTRL = 0x10; -static const uint8_t BL0942_REG_MODE = 0x18; -static const uint8_t BL0942_REG_SOFT_RESET = 0x19; -static const uint8_t BL0942_REG_USR_WRPROT = 0x1A; + +static const uint8_t BL0942_REG_I_RMSOS = 0x12; +static const uint8_t BL0942_REG_WA_CREEP = 0x14; +static const uint8_t BL0942_REG_I_FAST_RMS_TH = 0x15; +static const uint8_t BL0942_REG_I_FAST_RMS_CYC = 0x16; +static const uint8_t BL0942_REG_FREQ_CYC = 0x17; +static const uint8_t BL0942_REG_OT_FUNX = 0x18; +static const uint8_t BL0942_REG_MODE = 0x19; +static const uint8_t BL0942_REG_SOFT_RESET = 0x1C; +static const uint8_t BL0942_REG_USR_WRPROT = 0x1D; static const uint8_t BL0942_REG_TPS_CTRL = 0x1B; -// TODO: Confirm insialisation works as intended -const uint8_t BL0942_INIT[5][6] = { - // Reset to default - {BL0942_WRITE_COMMAND, BL0942_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38}, - // Enable User Operation Write - {BL0942_WRITE_COMMAND, BL0942_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0}, - // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS - {BL0942_WRITE_COMMAND, BL0942_REG_MODE, 0x00, 0x10, 0x00, 0x37}, - // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS - {BL0942_WRITE_COMMAND, BL0942_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE}, - // 0x181C = Half cycle, Fast RMS threshold 6172 - {BL0942_WRITE_COMMAND, BL0942_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}}; +static const uint32_t BL0942_REG_MODE_RESV = 0x03; +static const uint32_t BL0942_REG_MODE_CF_EN = 0x04; +static const uint32_t BL0942_REG_MODE_RMS_UPDATE_SEL = 0x08; +static const uint32_t BL0942_REG_MODE_FAST_RMS_SEL = 0x10; +static const uint32_t BL0942_REG_MODE_AC_FREQ_SEL = 0x20; +static const uint32_t BL0942_REG_MODE_CF_CNT_CLR_SEL = 0x40; +static const uint32_t BL0942_REG_MODE_CF_CNT_ADD_SEL = 0x80; +static const uint32_t BL0942_REG_MODE_UART_RATE_19200 = 0x200; +static const uint32_t BL0942_REG_MODE_UART_RATE_38400 = 0x300; +static const uint32_t BL0942_REG_MODE_DEFAULT = + BL0942_REG_MODE_RESV | BL0942_REG_MODE_CF_EN | BL0942_REG_MODE_CF_CNT_ADD_SEL; + +static const uint32_t BL0942_REG_SOFT_RESET_MAGIC = 0x5a5a5a; +static const uint32_t BL0942_REG_USR_WRPROT_MAGIC = 0x55; void BL0942::loop() { DataPacket buffer; if (!this->available()) { return; } - if (read_array((uint8_t *) &buffer, sizeof(buffer))) { - if (validate_checksum(&buffer)) { - received_package_(&buffer); + if (this->read_array((uint8_t *) &buffer, sizeof(buffer))) { + if (this->validate_checksum_(&buffer)) { + this->received_package_(&buffer); } } else { ESP_LOGW(TAG, "Junk on wire. Throwing away partial message"); @@ -47,8 +57,8 @@ void BL0942::loop() { } } -bool BL0942::validate_checksum(DataPacket *data) { - uint8_t checksum = BL0942_READ_COMMAND; +bool BL0942::validate_checksum_(DataPacket *data) { + uint8_t checksum = BL0942_READ_COMMAND | this->address_; // Whole package but checksum uint8_t *raw = (uint8_t *) data; for (uint32_t i = 0; i < sizeof(*data) - 1; i++) { @@ -61,17 +71,58 @@ bool BL0942::validate_checksum(DataPacket *data) { return checksum == data->checksum; } -void BL0942::update() { +void BL0942::write_reg_(uint8_t reg, uint32_t val) { + uint8_t pkt[6]; + this->flush(); - this->write_byte(BL0942_READ_COMMAND); + pkt[0] = BL0942_WRITE_COMMAND | this->address_; + pkt[1] = reg; + pkt[2] = (val & 0xff); + pkt[3] = (val >> 8) & 0xff; + pkt[4] = (val >> 16) & 0xff; + pkt[5] = (pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4]) ^ 0xff; + this->write_array(pkt, 6); + delay(1); +} + +int BL0942::read_reg_(uint8_t reg) { + union { + uint8_t b[4]; + uint32_le_t le32; + } resp; + + this->write_byte(BL0942_READ_COMMAND | this->address_); + this->write_byte(reg); + this->flush(); + if (this->read_array(resp.b, 4) && + resp.b[3] == + (uint8_t) ((BL0942_READ_COMMAND + this->address_ + reg + resp.b[0] + resp.b[1] + resp.b[2]) ^ 0xff)) { + resp.b[3] = 0; + return resp.le32; + } + return -1; +} + +void BL0942::update() { + this->write_byte(BL0942_READ_COMMAND | this->address_); this->write_byte(BL0942_FULL_PACKET); } void BL0942::setup() { - for (auto *i : BL0942_INIT) { - this->write_array(i, 6); - delay(1); - } + this->write_reg_(BL0942_REG_USR_WRPROT, BL0942_REG_USR_WRPROT_MAGIC); + this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC); + + uint32_t mode = BL0942_REG_MODE_DEFAULT; + mode |= BL0942_REG_MODE_RMS_UPDATE_SEL; /* 800ms refresh time */ + if (this->line_freq_ == LINE_FREQUENCY_60HZ) + mode |= BL0942_REG_MODE_AC_FREQ_SEL; + this->write_reg_(BL0942_REG_MODE, mode); + + this->write_reg_(BL0942_REG_USR_WRPROT, 0); + + if (this->read_reg_(BL0942_REG_MODE) != mode) + this->status_set_warning("BL0942 setup failed!"); + this->flush(); } @@ -104,13 +155,15 @@ void BL0942::received_package_(DataPacket *data) { if (frequency_sensor_ != nullptr) { frequency_sensor_->publish_state(frequency); } - + this->status_clear_warning(); ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms, watt, cf_cnt, total_energy_consumption, frequency, data->status); } void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity) ESP_LOGCONFIG(TAG, "BL0942:"); + ESP_LOGCONFIG(TAG, " Address: %d", this->address_); + ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_); LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Power", this->power_sensor_); diff --git a/esphome/components/bl0942/bl0942.h b/esphome/components/bl0942/bl0942.h index 12489915e1..52347c1bc3 100644 --- a/esphome/components/bl0942/bl0942.h +++ b/esphome/components/bl0942/bl0942.h @@ -28,6 +28,11 @@ struct DataPacket { uint8_t checksum; } __attribute__((packed)); +enum LineFrequency : uint8_t { + LINE_FREQUENCY_50HZ = 50, + LINE_FREQUENCY_60HZ = 60, +}; + class BL0942 : public PollingComponent, public uart::UARTDevice { public: void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } @@ -35,9 +40,10 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; } void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; } + void set_line_freq(LineFrequency freq) { this->line_freq_ = freq; } + void set_address(uint8_t address) { this->address_ = address; } void loop() override; - void update() override; void setup() override; void dump_config() override; @@ -59,9 +65,12 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { float current_reference_ = BL0942_IREF; // Divide by this to turn into kWh float energy_reference_ = BL0942_EREF; + uint8_t address_ = 0; + LineFrequency line_freq_ = LINE_FREQUENCY_50HZ; - static bool validate_checksum(DataPacket *data); - + bool validate_checksum_(DataPacket *data); + int read_reg_(uint8_t reg); + void write_reg_(uint8_t reg, uint32_t val); void received_package_(DataPacket *data); }; } // namespace bl0942 diff --git a/esphome/components/bl0942/sensor.py b/esphome/components/bl0942/sensor.py index 9612df6d4c..c47da45b8c 100644 --- a/esphome/components/bl0942/sensor.py +++ b/esphome/components/bl0942/sensor.py @@ -1,25 +1,27 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import sensor, uart +import esphome.config_validation as cv from esphome.const import ( + CONF_ADDRESS, CONF_CURRENT, CONF_ENERGY, + CONF_FREQUENCY, CONF_ID, + CONF_LINE_FREQUENCY, CONF_POWER, CONF_VOLTAGE, - CONF_FREQUENCY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, - DEVICE_CLASS_FREQUENCY, STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, UNIT_AMPERE, + UNIT_HERTZ, UNIT_KILOWATT_HOURS, UNIT_VOLT, UNIT_WATT, - UNIT_HERTZ, - STATE_CLASS_TOTAL_INCREASING, ) DEPENDENCIES = ["uart"] @@ -27,6 +29,12 @@ DEPENDENCIES = ["uart"] bl0942_ns = cg.esphome_ns.namespace("bl0942") BL0942 = bl0942_ns.class_("BL0942", cg.PollingComponent, uart.UARTDevice) +LineFrequency = bl0942_ns.enum("LineFrequency") +LINE_FREQS = { + 50: LineFrequency.LINE_FREQUENCY_50HZ, + 60: LineFrequency.LINE_FREQUENCY_60HZ, +} + CONFIG_SCHEMA = ( cv.Schema( { @@ -61,6 +69,14 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_FREQUENCY, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_LINE_FREQUENCY, default="50HZ"): cv.All( + cv.frequency, + cv.enum( + LINE_FREQS, + int=True, + ), + ), + cv.Optional(CONF_ADDRESS, default=0): cv.int_range(min=0, max=3), } ) .extend(cv.polling_component_schema("60s")) @@ -88,3 +104,5 @@ async def to_code(config): if frequency_config := config.get(CONF_FREQUENCY): sens = await sensor.new_sensor(frequency_config) cg.add(var.set_frequency_sensor(sens)) + cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) + cg.add(var.set_address(config[CONF_ADDRESS])) diff --git a/tests/components/bl0942/test.bk72xx-ard.yaml b/tests/components/bl0942/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..4ed3eb391d --- /dev/null +++ b/tests/components/bl0942/test.bk72xx-ard.yaml @@ -0,0 +1,22 @@ +uart: + - id: uart_bl0942 + tx_pin: + number: TX1 + rx_pin: + number: RX1 + baud_rate: 2400 + +sensor: + - platform: bl0942 + address: 0 + line_frequency: 50Hz + voltage: + name: BL0942 Voltage + current: + name: BL0942 Current + power: + name: BL0942 Power + energy: + name: BL0942 Energy + frequency: + name: BL0942 Frequency From 5a707b558dbb9e1e0e2184fd8a0c5da2ec7f5514 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 26 Aug 2024 18:38:49 -0500 Subject: [PATCH 2292/2607] Add supported formats to media player (#7318) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 15 ++++ esphome/components/api/api_connection.cpp | 9 ++ esphome/components/api/api_pb2.cpp | 83 +++++++++++++++++++ esphome/components/api/api_pb2.h | 20 +++++ esphome/components/api/api_pb2_service.cpp | 19 +++++ esphome/components/api/api_pb2_service.h | 4 + .../components/media_player/media_player.h | 15 ++++ 7 files changed, 165 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 72eaeed6d7..84183357dc 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1107,6 +1107,19 @@ enum MediaPlayerCommand { MEDIA_PLAYER_COMMAND_MUTE = 3; MEDIA_PLAYER_COMMAND_UNMUTE = 4; } +enum MediaPlayerFormatPurpose { + MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0; + MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1; +} +message MediaPlayerSupportedFormat { + option (id) = 119; + option (ifdef) = "USE_MEDIA_PLAYER"; + + string format = 1; + uint32 sample_rate = 2; + uint32 num_channels = 3; + MediaPlayerFormatPurpose purpose = 4; +} message ListEntitiesMediaPlayerResponse { option (id) = 63; option (source) = SOURCE_SERVER; @@ -1122,6 +1135,8 @@ message ListEntitiesMediaPlayerResponse { EntityCategory entity_category = 7; bool supports_pause = 8; + + repeated MediaPlayerSupportedFormat supported_formats = 9; } message MediaPlayerStateResponse { option (id) = 64; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 195fcab0ab..a655d06e66 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1026,6 +1026,15 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play auto traits = media_player->get_traits(); msg.supports_pause = traits.get_supports_pause(); + for (auto &supported_format : traits.get_supported_formats()) { + MediaPlayerSupportedFormat media_format; + media_format.format = supported_format.format; + media_format.sample_rate = supported_format.sample_rate; + media_format.num_channels = supported_format.num_channels; + media_format.purpose = static_cast(supported_format.purpose); + msg.supported_formats.push_back(media_format); + } + return this->send_list_entities_media_player_response(msg); } void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index bb37824403..c944d0dae8 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -387,6 +387,18 @@ template<> const char *proto_enum_to_string(enums::Me } #endif #ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::MediaPlayerFormatPurpose value) { + switch (value) { + case enums::MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT: + return "MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT"; + case enums::MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT: + return "MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef HAS_PROTO_MESSAGE_DUMP template<> const char *proto_enum_to_string(enums::BluetoothDeviceRequestType value) { switch (value) { @@ -5123,6 +5135,64 @@ void ButtonCommandRequest::dump_to(std::string &out) const { out.append("}"); } #endif +bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->sample_rate = value.as_uint32(); + return true; + } + case 3: { + this->num_channels = value.as_uint32(); + return true; + } + case 4: { + this->purpose = value.as_enum(); + return true; + } + default: + return false; + } +} +bool MediaPlayerSupportedFormat::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->format = value.as_string(); + return true; + } + default: + return false; + } +} +void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->format); + buffer.encode_uint32(2, this->sample_rate); + buffer.encode_uint32(3, this->num_channels); + buffer.encode_enum(4, this->purpose); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void MediaPlayerSupportedFormat::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("MediaPlayerSupportedFormat {\n"); + out.append(" format: "); + out.append("'").append(this->format).append("'"); + out.append("\n"); + + out.append(" sample_rate: "); + sprintf(buffer, "%" PRIu32, this->sample_rate); + out.append(buffer); + out.append("\n"); + + out.append(" num_channels: "); + sprintf(buffer, "%" PRIu32, this->num_channels); + out.append(buffer); + out.append("\n"); + + out.append(" purpose: "); + out.append(proto_enum_to_string(this->purpose)); + out.append("\n"); + out.append("}"); +} +#endif bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -5159,6 +5229,10 @@ bool ListEntitiesMediaPlayerResponse::decode_length(uint32_t field_id, ProtoLeng this->icon = value.as_string(); return true; } + case 9: { + this->supported_formats.push_back(value.as_message()); + return true; + } default: return false; } @@ -5182,6 +5256,9 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(6, this->disabled_by_default); buffer.encode_enum(7, this->entity_category); buffer.encode_bool(8, this->supports_pause); + for (auto &it : this->supported_formats) { + buffer.encode_message(9, it, true); + } } #ifdef HAS_PROTO_MESSAGE_DUMP void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { @@ -5219,6 +5296,12 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { out.append(" supports_pause: "); out.append(YESNO(this->supports_pause)); out.append("\n"); + + for (const auto &it : this->supported_formats) { + out.append(" supported_formats: "); + it.dump_to(out); + out.append("\n"); + } out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 3eb945fd8d..3f609c793c 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -156,6 +156,10 @@ enum MediaPlayerCommand : uint32_t { MEDIA_PLAYER_COMMAND_MUTE = 3, MEDIA_PLAYER_COMMAND_UNMUTE = 4, }; +enum MediaPlayerFormatPurpose : uint32_t { + MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0, + MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1, +}; enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0, BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1, @@ -1267,6 +1271,21 @@ class ButtonCommandRequest : public ProtoMessage { protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; }; +class MediaPlayerSupportedFormat : public ProtoMessage { + public: + std::string format{}; + uint32_t sample_rate{0}; + uint32_t num_channels{0}; + enums::MediaPlayerFormatPurpose purpose{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesMediaPlayerResponse : public ProtoMessage { public: std::string object_id{}; @@ -1277,6 +1296,7 @@ class ListEntitiesMediaPlayerResponse : public ProtoMessage { bool disabled_by_default{false}; enums::EntityCategory entity_category{}; bool supports_pause{false}; + std::vector supported_formats{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 269a755e9e..16c0e5654f 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -311,6 +311,14 @@ bool APIServerConnectionBase::send_list_entities_button_response(const ListEntit #ifdef USE_BUTTON #endif #ifdef USE_MEDIA_PLAYER +bool APIServerConnectionBase::send_media_player_supported_format(const MediaPlayerSupportedFormat &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_media_player_supported_format: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 119); +} +#endif +#ifdef USE_MEDIA_PLAYER bool APIServerConnectionBase::send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "send_list_entities_media_player_response: %s", msg.dump().c_str()); @@ -1135,6 +1143,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); #endif this->on_update_command_request(msg); +#endif + break; + } + case 119: { +#ifdef USE_MEDIA_PLAYER + MediaPlayerSupportedFormat msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_media_player_supported_format: %s", msg.dump().c_str()); +#endif + this->on_media_player_supported_format(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 83bfc2ed98..83b5e3a444 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -145,6 +145,10 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BUTTON virtual void on_button_command_request(const ButtonCommandRequest &value){}; #endif +#ifdef USE_MEDIA_PLAYER + bool send_media_player_supported_format(const MediaPlayerSupportedFormat &msg); + virtual void on_media_player_supported_format(const MediaPlayerSupportedFormat &value){}; +#endif #ifdef USE_MEDIA_PLAYER bool send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg); #endif diff --git a/esphome/components/media_player/media_player.h b/esphome/components/media_player/media_player.h index 77746e1808..26bef55afc 100644 --- a/esphome/components/media_player/media_player.h +++ b/esphome/components/media_player/media_player.h @@ -27,6 +27,18 @@ enum MediaPlayerCommand : uint8_t { }; const char *media_player_command_to_string(MediaPlayerCommand command); +enum class MediaPlayerFormatPurpose : uint8_t { + PURPOSE_DEFAULT = 0, + PURPOSE_ANNOUNCEMENT = 1, +}; + +struct MediaPlayerSupportedFormat { + std::string format; + uint32_t sample_rate; + uint32_t num_channels; + MediaPlayerFormatPurpose purpose; +}; + class MediaPlayer; class MediaPlayerTraits { @@ -37,8 +49,11 @@ class MediaPlayerTraits { bool get_supports_pause() const { return this->supports_pause_; } + std::vector &get_supported_formats() { return this->supported_formats_; } + protected: bool supports_pause_{false}; + std::vector supported_formats_{}; }; class MediaPlayerCall { From 7e18a5c44f70a5eea4bff4d94e4c05a2311f8f0e Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Tue, 27 Aug 2024 03:26:01 +0200 Subject: [PATCH 2293/2607] Add reset to esp32_rmt_led_strip (#7354) --- .../esp32_rmt_led_strip/led_strip.cpp | 16 +++++++++++-- .../esp32_rmt_led_strip/led_strip.h | 5 ++-- .../components/esp32_rmt_led_strip/light.py | 24 +++++++++++++++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index 7727b64f29..71ab099de5 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -38,7 +38,8 @@ void ESP32RMTLEDStripLightOutput::setup() { } ExternalRAMAllocator rmt_allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8); // 8 bits per byte, 1 rmt_item32_t per bit + this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + + 1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset rmt_config_t config; memset(&config, 0, sizeof(config)); @@ -66,7 +67,7 @@ void ESP32RMTLEDStripLightOutput::setup() { } void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, - uint32_t bit1_low) { + uint32_t bit1_low, uint32_t reset_time_high, uint32_t reset_time_low) { float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f; // 0-bit @@ -79,6 +80,11 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi this->bit1_.level0 = 1; this->bit1_.duration1 = (uint32_t) (ratio * bit1_low); this->bit1_.level1 = 0; + // reset + this->reset_.duration0 = (uint32_t) (ratio * reset_time_high); + this->reset_.level0 = 1; + this->reset_.duration1 = (uint32_t) (ratio * reset_time_low); + this->reset_.level1 = 0; } void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { @@ -118,6 +124,12 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { psrc++; } + if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) { + pdest->val = this->reset_.val; + pdest++; + len++; + } + if (rmt_write_items(this->channel_, this->rmt_buf_, len, false) != ESP_OK) { ESP_LOGE(TAG, "RMT TX error"); this->status_set_warning(); diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index e9b19c9399..43215cf12b 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -49,7 +49,8 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { /// Set a maximum refresh rate in µs as some lights do not like being updated too often. void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; } - void set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, uint32_t bit1_low); + void set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, uint32_t bit1_low, + uint32_t reset_time_high, uint32_t reset_time_low); void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; } void set_rmt_channel(rmt_channel_t channel) { this->channel_ = channel; } @@ -75,7 +76,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { bool is_rgbw_; bool is_wrgb_; - rmt_item32_t bit0_, bit1_; + rmt_item32_t bit0_, bit1_, reset_; RGBOrder rgb_order_; rmt_channel_t channel_; diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 4c8472b8d2..4a04918275 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -43,13 +43,15 @@ class LEDStripTimings: bit0_low: int bit1_high: int bit1_low: int + reset_high: int + reset_low: int CHIPSETS = { - "WS2812": LEDStripTimings(400, 1000, 1000, 400), - "SK6812": LEDStripTimings(300, 900, 600, 600), - "APA106": LEDStripTimings(350, 1360, 1360, 350), - "SM16703": LEDStripTimings(300, 900, 900, 300), + "WS2812": LEDStripTimings(400, 1000, 1000, 400, 0, 0), + "SK6812": LEDStripTimings(300, 900, 600, 600, 0, 0), + "APA106": LEDStripTimings(350, 1360, 1360, 350, 0, 0), + "SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0), } @@ -58,6 +60,8 @@ CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_LOW = "bit0_low" CONF_BIT1_HIGH = "bit1_high" CONF_BIT1_LOW = "bit1_low" +CONF_RESET_HIGH = "reset_high" +CONF_RESET_LOW = "reset_low" CONFIG_SCHEMA = cv.All( @@ -88,6 +92,14 @@ CONFIG_SCHEMA = cv.All( CONF_BIT1_LOW, "custom", ): cv.positive_time_period_nanoseconds, + cv.Optional( + CONF_RESET_HIGH, + default="0 us", + ): cv.positive_time_period_nanoseconds, + cv.Optional( + CONF_RESET_LOW, + default="0 us", + ): cv.positive_time_period_nanoseconds, } ), cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH), @@ -113,6 +125,8 @@ async def to_code(config): chipset.bit0_low, chipset.bit1_high, chipset.bit1_low, + chipset.reset_high, + chipset.reset_low, ) ) else: @@ -122,6 +136,8 @@ async def to_code(config): config[CONF_BIT0_LOW], config[CONF_BIT1_HIGH], config[CONF_BIT1_LOW], + config[CONF_RESET_HIGH], + config[CONF_RESET_LOW], ) ) From 34cce0e9201ab5408cfcd18ee7d2d7c5a24ffdd5 Mon Sep 17 00:00:00 2001 From: Gilles van den Hoven Date: Tue, 27 Aug 2024 14:07:32 +0200 Subject: [PATCH 2294/2607] [ili9xxx] Make `invert_colors` required (#7292) Co-authored-by: Gilles van den Hoven Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/ili9xxx/display.py | 35 +++++++++--------- .../components/ili9xxx/ili9xxx_display.cpp | 2 +- esphome/components/ili9xxx/ili9xxx_display.h | 36 +++++++++---------- esphome/components/ili9xxx/ili9xxx_init.h | 3 -- tests/components/ili9xxx/test.esp32-ard.yaml | 1 + .../components/ili9xxx/test.esp32-c3-ard.yaml | 1 + .../components/ili9xxx/test.esp32-c3-idf.yaml | 1 + .../components/ili9xxx/test.esp8266-ard.yaml | 1 + tests/components/ili9xxx/test.rp2040-ard.yaml | 1 + 9 files changed, 41 insertions(+), 40 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 483f2b886c..2182ca9a6d 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -1,31 +1,31 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import core, pins -from esphome.components import display, spi, font +import esphome.codegen as cg +from esphome.components import display, font, spi from esphome.components.display import validate_rotation -from esphome.core import CORE, HexInt +import esphome.config_validation as cv from esphome.const import ( + CONF_COLOR_ORDER, CONF_COLOR_PALETTE, CONF_DC_PIN, - CONF_ID, - CONF_LAMBDA, - CONF_MODEL, - CONF_RAW_DATA_ID, - CONF_PAGES, - CONF_RESET_PIN, CONF_DIMENSIONS, - CONF_WIDTH, CONF_HEIGHT, - CONF_ROTATION, + CONF_ID, + CONF_INVERT_COLORS, + CONF_LAMBDA, CONF_MIRROR_X, CONF_MIRROR_Y, - CONF_SWAP_XY, - CONF_COLOR_ORDER, + CONF_MODEL, CONF_OFFSET_HEIGHT, CONF_OFFSET_WIDTH, + CONF_PAGES, + CONF_RAW_DATA_ID, + CONF_RESET_PIN, + CONF_ROTATION, + CONF_SWAP_XY, CONF_TRANSFORM, - CONF_INVERT_COLORS, + CONF_WIDTH, ) +from esphome.core import CORE, HexInt DEPENDENCIES = ["spi"] @@ -177,7 +177,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INVERT_DISPLAY): cv.invalid( "'invert_display' has been replaced by 'invert_colors'" ), - cv.Optional(CONF_INVERT_COLORS): cv.boolean, + cv.Required(CONF_INVERT_COLORS): cv.boolean, cv.Optional(CONF_COLOR_ORDER): cv.one_of(*COLOR_ORDERS.keys(), upper=True), cv.Exclusive(CONF_ROTATION, CONF_ROTATION): validate_rotation, cv.Exclusive(CONF_TRANSFORM, CONF_ROTATION): cv.Schema( @@ -287,5 +287,4 @@ async def to_code(config): prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) cg.add(var.set_palette(prog_arr)) - if CONF_INVERT_COLORS in config: - cg.add(var.invert_colors(config[CONF_INVERT_COLORS])) + cg.add(var.invert_colors(config[CONF_INVERT_COLORS])) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 4f035edbb0..81976dd2c9 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -118,6 +118,7 @@ void ILI9XXXDisplay::dump_config() { ESP_LOGCONFIG(TAG, " Swap_xy: %s", YESNO(this->swap_xy_)); ESP_LOGCONFIG(TAG, " Mirror_x: %s", YESNO(this->mirror_x_)); ESP_LOGCONFIG(TAG, " Mirror_y: %s", YESNO(this->mirror_y_)); + ESP_LOGCONFIG(TAG, " Invert colors: %s", YESNO(this->pre_invertcolors_)); if (this->is_failed()) { ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!"); @@ -154,7 +155,6 @@ void ILI9XXXDisplay::fill(Color color) { } } return; - break; default: new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB); break; diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 6121488d15..5033f702de 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -28,8 +28,8 @@ class ILI9XXXDisplay : public display::DisplayBuffer, spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> { public: ILI9XXXDisplay() = default; - ILI9XXXDisplay(uint8_t const *init_sequence, int16_t width, int16_t height, bool invert_colors) - : init_sequence_{init_sequence}, width_{width}, height_{height}, pre_invertcolors_{invert_colors} { + ILI9XXXDisplay(uint8_t const *init_sequence, int16_t width, int16_t height) + : init_sequence_{init_sequence}, width_{width}, height_{height} { uint8_t cmd, num_args, bits; const uint8_t *addr = init_sequence; while ((cmd = *addr++) != 0) { @@ -144,7 +144,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, bool need_update_ = false; bool is_18bitdisplay_ = false; PixelMode pixel_mode_{}; - bool pre_invertcolors_ = false; + bool pre_invertcolors_{}; display::ColorOrder color_order_{display::COLOR_ORDER_BGR}; bool swap_xy_{}; bool mirror_x_{}; @@ -154,54 +154,54 @@ class ILI9XXXDisplay : public display::DisplayBuffer, //----------- M5Stack display -------------- class ILI9XXXM5Stack : public ILI9XXXDisplay { public: - ILI9XXXM5Stack() : ILI9XXXDisplay(INITCMD_M5STACK, 320, 240, true) {} + ILI9XXXM5Stack() : ILI9XXXDisplay(INITCMD_M5STACK, 320, 240) {} }; //----------- M5Stack display -------------- class ILI9XXXM5CORE : public ILI9XXXDisplay { public: - ILI9XXXM5CORE() : ILI9XXXDisplay(INITCMD_M5CORE, 320, 240, true) {} + ILI9XXXM5CORE() : ILI9XXXDisplay(INITCMD_M5CORE, 320, 240) {} }; //----------- ST7789V display -------------- class ILI9XXXST7789V : public ILI9XXXDisplay { public: - ILI9XXXST7789V() : ILI9XXXDisplay(INITCMD_ST7789V, 240, 320, false) {} + ILI9XXXST7789V() : ILI9XXXDisplay(INITCMD_ST7789V, 240, 320) {} }; //----------- ILI9XXX_24_TFT display -------------- class ILI9XXXILI9341 : public ILI9XXXDisplay { public: - ILI9XXXILI9341() : ILI9XXXDisplay(INITCMD_ILI9341, 240, 320, false) {} + ILI9XXXILI9341() : ILI9XXXDisplay(INITCMD_ILI9341, 240, 320) {} }; //----------- ILI9XXX_24_TFT rotated display -------------- class ILI9XXXILI9342 : public ILI9XXXDisplay { public: - ILI9XXXILI9342() : ILI9XXXDisplay(INITCMD_ILI9341, 320, 240, false) {} + ILI9XXXILI9342() : ILI9XXXDisplay(INITCMD_ILI9341, 320, 240) {} }; //----------- ILI9XXX_??_TFT rotated display -------------- class ILI9XXXILI9481 : public ILI9XXXDisplay { public: - ILI9XXXILI9481() : ILI9XXXDisplay(INITCMD_ILI9481, 480, 320, false) {} + ILI9XXXILI9481() : ILI9XXXDisplay(INITCMD_ILI9481, 480, 320) {} }; //----------- ILI9481 in 18 bit mode -------------- class ILI9XXXILI948118 : public ILI9XXXDisplay { public: - ILI9XXXILI948118() : ILI9XXXDisplay(INITCMD_ILI9481_18, 320, 480, true) {} + ILI9XXXILI948118() : ILI9XXXDisplay(INITCMD_ILI9481_18, 320, 480) {} }; //----------- ILI9XXX_35_TFT rotated display -------------- class ILI9XXXILI9486 : public ILI9XXXDisplay { public: - ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320, false) {} + ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320) {} }; class ILI9XXXILI9488 : public ILI9XXXDisplay { public: - ILI9XXXILI9488(const uint8_t *seq = INITCMD_ILI9488) : ILI9XXXDisplay(seq, 480, 320, true) {} + ILI9XXXILI9488(const uint8_t *seq = INITCMD_ILI9488) : ILI9XXXDisplay(seq, 480, 320) {} protected: void set_madctl() override { @@ -246,34 +246,34 @@ class WAVESHARERES35 : public ILI9XXXILI9488 { //----------- ILI9XXX_35_TFT origin colors rotated display -------------- class ILI9XXXILI9488A : public ILI9XXXDisplay { public: - ILI9XXXILI9488A() : ILI9XXXDisplay(INITCMD_ILI9488_A, 480, 320, true) {} + ILI9XXXILI9488A() : ILI9XXXDisplay(INITCMD_ILI9488_A, 480, 320) {} }; //----------- ILI9XXX_35_TFT rotated display -------------- class ILI9XXXST7796 : public ILI9XXXDisplay { public: - ILI9XXXST7796() : ILI9XXXDisplay(INITCMD_ST7796, 320, 480, false) {} + ILI9XXXST7796() : ILI9XXXDisplay(INITCMD_ST7796, 320, 480) {} }; class ILI9XXXS3Box : public ILI9XXXDisplay { public: - ILI9XXXS3Box() : ILI9XXXDisplay(INITCMD_S3BOX, 320, 240, false) {} + ILI9XXXS3Box() : ILI9XXXDisplay(INITCMD_S3BOX, 320, 240) {} }; class ILI9XXXS3BoxLite : public ILI9XXXDisplay { public: - ILI9XXXS3BoxLite() : ILI9XXXDisplay(INITCMD_S3BOXLITE, 320, 240, true) {} + ILI9XXXS3BoxLite() : ILI9XXXDisplay(INITCMD_S3BOXLITE, 320, 240) {} }; class ILI9XXXGC9A01A : public ILI9XXXDisplay { public: - ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {} + ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240) {} }; //----------- ILI9XXX_24_TFT display -------------- class ILI9XXXST7735 : public ILI9XXXDisplay { public: - ILI9XXXST7735() : ILI9XXXDisplay(INITCMD_ST7735, 128, 160, false) {} + ILI9XXXST7735() : ILI9XXXDisplay(INITCMD_ST7735, 128, 160) {} }; } // namespace ili9xxx diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h index 5a67812bc1..b176680f43 100644 --- a/esphome/components/ili9xxx/ili9xxx_init.h +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -101,7 +101,6 @@ static const uint8_t PROGMEM INITCMD_ILI9481[] = { ILI9XXX_MADCTL , 1, MADCTL_MV | MADCTL_BGR, // Memory Access Control ILI9XXX_CSCON , 1, 0x01, ILI9XXX_PIXFMT, 1, 0x55, // 16 bit mode - ILI9XXX_INVON, 0, ILI9XXX_DISPON, 0x80, // Set display on 0x00 // end }; @@ -121,7 +120,6 @@ static const uint8_t PROGMEM INITCMD_ILI9481_18[] = { ILI9XXX_MADCTL , 1, MADCTL_MX| MADCTL_BGR, // Memory Access Control ILI9XXX_CSCON , 1, 0x01, ILI9XXX_PIXFMT, 1, 0x66, // 18 bit mode - ILI9XXX_INVON, 0, ILI9XXX_DISPON, 0x80, // Set display on 0x00 // end }; @@ -204,7 +202,6 @@ static const uint8_t PROGMEM INITCMD_ILI9488_A[] = { ILI9XXX_SLPOUT, 0x80, // Exit sleep mode - //ILI9XXX_INVON , 0, ILI9XXX_DISPON, 0x80, // Set display on 0x00 // end }; diff --git a/tests/components/ili9xxx/test.esp32-ard.yaml b/tests/components/ili9xxx/test.esp32-ard.yaml index ecee21686e..850273230a 100644 --- a/tests/components/ili9xxx/test.esp32-ard.yaml +++ b/tests/components/ili9xxx/test.esp32-ard.yaml @@ -19,6 +19,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ili9xxx + invert_colors: false dimensions: width: 320 height: 240 diff --git a/tests/components/ili9xxx/test.esp32-c3-ard.yaml b/tests/components/ili9xxx/test.esp32-c3-ard.yaml index 9526ae1f6b..fd03bd54b7 100644 --- a/tests/components/ili9xxx/test.esp32-c3-ard.yaml +++ b/tests/components/ili9xxx/test.esp32-c3-ard.yaml @@ -20,6 +20,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ili9xxx + invert_colors: false dimensions: width: 320 height: 240 diff --git a/tests/components/ili9xxx/test.esp32-c3-idf.yaml b/tests/components/ili9xxx/test.esp32-c3-idf.yaml index 9526ae1f6b..fd03bd54b7 100644 --- a/tests/components/ili9xxx/test.esp32-c3-idf.yaml +++ b/tests/components/ili9xxx/test.esp32-c3-idf.yaml @@ -20,6 +20,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ili9xxx + invert_colors: false dimensions: width: 320 height: 240 diff --git a/tests/components/ili9xxx/test.esp8266-ard.yaml b/tests/components/ili9xxx/test.esp8266-ard.yaml index 0791c25aca..b8192e69d1 100644 --- a/tests/components/ili9xxx/test.esp8266-ard.yaml +++ b/tests/components/ili9xxx/test.esp8266-ard.yaml @@ -20,6 +20,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ili9xxx + invert_colors: false dimensions: width: 320 height: 240 diff --git a/tests/components/ili9xxx/test.rp2040-ard.yaml b/tests/components/ili9xxx/test.rp2040-ard.yaml index 54083ebce8..0423f41a1c 100644 --- a/tests/components/ili9xxx/test.rp2040-ard.yaml +++ b/tests/components/ili9xxx/test.rp2040-ard.yaml @@ -20,6 +20,7 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ili9xxx + invert_colors: false dimensions: width: 320 height: 240 From 92ae506ffb0c04d91cad1318fa13847325ed05a6 Mon Sep 17 00:00:00 2001 From: Angel Nunez Mencias Date: Wed, 28 Aug 2024 01:40:21 +0200 Subject: [PATCH 2295/2607] Add WS2811 to esp32_rmt_led_strip (#7353) --- esphome/components/esp32_rmt_led_strip/light.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 4a04918275..1e3c2d4f72 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -48,6 +48,7 @@ class LEDStripTimings: CHIPSETS = { + "WS2811": LEDStripTimings(300, 1090, 1090, 320, 0, 300000), "WS2812": LEDStripTimings(400, 1000, 1000, 400, 0, 0), "SK6812": LEDStripTimings(300, 900, 600, 600, 0, 0), "APA106": LEDStripTimings(350, 1360, 1360, 350, 0, 0), From 388abaf09f8a5d2da7e4b8355738dad8852b752f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 23 Aug 2024 04:56:53 +1000 Subject: [PATCH 2296/2607] [lvgl] Bug fixes (#7338) --- esphome/components/lvgl/automation.py | 16 +++++++++++++--- esphome/components/lvgl/lvgl_esphome.cpp | 7 +++++++ esphome/components/lvgl/lvgl_esphome.h | 1 + esphome/components/lvgl/widgets/__init__.py | 6 ++++++ esphome/components/lvgl/widgets/line.py | 12 +++++++----- esphome/components/lvgl/widgets/msgbox.py | 3 ++- tests/components/lvgl/lvgl-package.yaml | 6 +++++- 7 files changed, 41 insertions(+), 10 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index a39f589136..efcac977ab 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -5,6 +5,7 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome.cpp_generator import RawExpression from esphome.cpp_types import nullptr from .defines import ( @@ -26,6 +27,7 @@ from .lvcode import ( add_line_marks, lv, lv_add, + lv_expr, lv_obj, lvgl_comp, ) @@ -38,7 +40,13 @@ from .types import ( lv_disp_t, lv_obj_t, ) -from .widgets import Widget, get_widgets, lv_scr_act, set_obj_properties +from .widgets import ( + Widget, + get_widgets, + lv_scr_act, + set_obj_properties, + wait_for_widgets, +) async def action_to_code( @@ -48,10 +56,12 @@ async def action_to_code( template_arg, args, ): + await wait_for_widgets() async with LambdaContext(parameters=args, where=action_id) as context: + with LvConditional(lv_expr.is_pre_initialise()): + context.add(RawExpression("return")) for widget in widgets: - with LvConditional(widget.obj != nullptr): - await action(widget) + await action(widget) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) return var diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 92f7a880c3..6882986e7c 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -294,6 +294,13 @@ void LvglComponent::loop() { } lv_timer_handler_run_in_period(5); } +bool lv_is_pre_initialise() { + if (!lv_is_initialized()) { + ESP_LOGE(TAG, "LVGL call before component is initialised"); + return true; + } + return false; +} #ifdef USE_LVGL_IMAGE lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 3a3d1aa6c5..df3d4aa68c 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -40,6 +40,7 @@ namespace lvgl { extern lv_event_code_t lv_api_event; // NOLINT extern lv_event_code_t lv_update_event; // NOLINT +extern bool lv_is_pre_initialise(); #ifdef USE_LVGL_COLOR inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } #endif // USE_LVGL_COLOR diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 4abb25c61d..50da6e131d 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -1,3 +1,4 @@ +import asyncio import sys from typing import Any, Union @@ -223,6 +224,11 @@ async def get_widget_(wid: Widget): return await FakeAwaitable(get_widget_generator(wid)) +async def wait_for_widgets(): + while not Widget.widgets_completed: + await asyncio.sleep(0) + + async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]: if not config: return [] diff --git a/esphome/components/lvgl/widgets/line.py b/esphome/components/lvgl/widgets/line.py index 8ce4b1965f..4c6439fde4 100644 --- a/esphome/components/lvgl/widgets/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -3,7 +3,7 @@ import functools import esphome.codegen as cg import esphome.config_validation as cv -from ..defines import CONF_MAIN, literal +from ..defines import CONF_MAIN from ..lvcode import lv from ..types import LvType from . import Widget, WidgetType @@ -38,13 +38,15 @@ LINE_SCHEMA = { class LineType(WidgetType): def __init__(self): - super().__init__(CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA) + super().__init__( + CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA, modify_schema={} + ) async def to_code(self, w: Widget, config): """For a line object, create and add the points""" - data = literal(config[CONF_POINTS]) - points = cg.static_const_array(config[CONF_POINT_LIST_ID], data) - lv.line_set_points(w.obj, points, len(data)) + if data := config.get(CONF_POINTS): + points = cg.static_const_array(config[CONF_POINT_LIST_ID], data) + lv.line_set_points(w.obj, points, len(data)) line_spec = LineType() diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index 63c4326c7c..c377af6bde 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -13,7 +13,7 @@ from ..defines import ( TYPE_FLEX, literal, ) -from ..helpers import add_lv_use +from ..helpers import add_lv_use, lvgl_components_required from ..lv_validation import lv_bool, lv_pct, lv_text from ..lvcode import ( EVENT_ARG, @@ -72,6 +72,7 @@ async def msgbox_to_code(conf): *buttonmatrix_spec.get_uses(), *button_spec.get_uses(), ) + lvgl_components_required.add("BUTTONMATRIX") messagebox_id = conf[CONF_ID] outer = lv_Pvariable(lv_obj_t, messagebox_id.id) buttonmatrix = new_Pvariable( diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 800d6eff27..1479ce7358 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -379,6 +379,7 @@ lvgl: format: "bar value %f" args: [x] - line: + id: lv_line_id align: center points: - 5, 5 @@ -387,7 +388,10 @@ lvgl: - 180, 60 - 240, 10 on_click: - lvgl.page.next: + - lvgl.widget.update: + id: lv_line_id + line_color: 0xFFFF + - lvgl.page.next: - switch: align: right_mid - checkbox: From 86777634922a9c1b695d2f3da30630a827ccd2cf Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:09:40 +1000 Subject: [PATCH 2297/2607] [core] Clean build if the loaded integrations changed (#7344) --- esphome/writer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/writer.py b/esphome/writer.py index c6111cbe3f..57435d3463 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -106,6 +106,8 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool: return True if old.build_path != new.build_path: return True + if old.loaded_integrations != new.loaded_integrations: + return True return False @@ -117,7 +119,9 @@ def update_storage_json(): return if storage_should_clean(old, new): - _LOGGER.info("Core config or version changed, cleaning build files...") + _LOGGER.info( + "Core config, version or integrations changed, cleaning build files..." + ) clean_build() new.save(path) From c1774c42c25350cebc4f649184ba9b1374c6397c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:03:25 +1000 Subject: [PATCH 2298/2607] [lvgl] Fix race condition involving numbers, switches etc. (#7345) --- esphome/components/lvgl/__init__.py | 5 ++++- esphome/components/lvgl/binary_sensor/__init__.py | 3 ++- esphome/components/lvgl/light/__init__.py | 3 ++- esphome/components/lvgl/lvcode.py | 3 +++ esphome/components/lvgl/number/__init__.py | 3 ++- esphome/components/lvgl/select/__init__.py | 3 ++- esphome/components/lvgl/sensor/__init__.py | 3 ++- esphome/components/lvgl/switch/__init__.py | 3 ++- esphome/components/lvgl/text/__init__.py | 3 ++- esphome/components/lvgl/text_sensor/__init__.py | 3 ++- esphome/components/lvgl/widgets/__init__.py | 13 ++++++++++--- 11 files changed, 33 insertions(+), 12 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 7c51d9c70d..ea020435dc 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -266,7 +266,10 @@ async def to_code(config): await add_top_layer(config) await msgboxes_to_code(config) await disp_update(f"{lv_component}->get_disp()", config) - Widget.set_completed() + # At this point only the setup code should be generated + assert LvContext.added_lambda_count == 1 + Widget.set_completed() + async with LvContext(lv_component): await generate_triggers(lv_component) for conf in config.get(CONF_ON_IDLE, ()): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) diff --git a/esphome/components/lvgl/binary_sensor/__init__.py b/esphome/components/lvgl/binary_sensor/__init__.py index 8789a06375..56984405aa 100644 --- a/esphome/components/lvgl/binary_sensor/__init__.py +++ b/esphome/components/lvgl/binary_sensor/__init__.py @@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import EVENT_ARG, LambdaContext, LvContext from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, lv_pseudo_button_t -from ..widgets import Widget, get_widgets +from ..widgets import Widget, get_widgets, wait_for_widgets CONFIG_SCHEMA = ( binary_sensor_schema(BinarySensor) @@ -29,6 +29,7 @@ async def to_code(config): widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] assert isinstance(widget, Widget) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pressed_ctx: pressed_ctx.add(sensor.publish_state(widget.is_pressed())) async with LvContext(paren) as ctx: diff --git a/esphome/components/lvgl/light/__init__.py b/esphome/components/lvgl/light/__init__.py index 27c160dff6..a0eeded349 100644 --- a/esphome/components/lvgl/light/__init__.py +++ b/esphome/components/lvgl/light/__init__.py @@ -8,7 +8,7 @@ from ..defines import CONF_LVGL_ID from ..lvcode import LvContext from ..schemas import LVGL_SCHEMA from ..types import LvType, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets lv_led_t = LvType("lv_led_t") LVLight = lvgl_ns.class_("LVLight", LightOutput) @@ -28,5 +28,6 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_LED) widget = widget[0] + await wait_for_widgets() async with LvContext(paren) as ctx: ctx.add(var.set_obj(widget.obj)) diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 6d7e364e5d..8d029ce0ca 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -176,6 +176,8 @@ class LvContext(LambdaContext): Code generation into the LVGL initialisation code (called in `setup()`) """ + added_lambda_count = 0 + def __init__(self, lv_component, args=None): self.args = args or LVGL_COMP_ARG super().__init__(parameters=self.args) @@ -183,6 +185,7 @@ class LvContext(LambdaContext): async def add_init_lambda(self): cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) + LvContext.added_lambda_count += 1 async def __aexit__(self, exc_type, exc_val, exc_tb): await super().__aexit__(exc_type, exc_val, exc_tb) diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index 6336bb0632..3e1ede0dec 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -16,7 +16,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number) @@ -44,6 +44,7 @@ async def to_code(config): step=widget.get_step(), ) + await wait_for_widgets() async with LambdaContext([(cg.float_, "v")]) as control: await widget.set_property( "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index b55bde13bc..e77d0cfb32 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -15,7 +15,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvSelect, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select) @@ -37,6 +37,7 @@ async def to_code(config): options = widget.config.get(CONF_OPTIONS, []) selector = await select.new_select(config, options=options) paren = await cg.get_variable(config[CONF_LVGL_ID]) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pub_ctx: pub_ctx.add(selector.publish_index(widget.get_value())) async with LambdaContext([(cg.uint16, "v")]) as control: diff --git a/esphome/components/lvgl/sensor/__init__.py b/esphome/components/lvgl/sensor/__init__.py index 82e21d5e95..a2a2298c27 100644 --- a/esphome/components/lvgl/sensor/__init__.py +++ b/esphome/components/lvgl/sensor/__init__.py @@ -14,7 +14,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvNumber -from ..widgets import Widget, get_widgets +from ..widgets import Widget, get_widgets, wait_for_widgets CONFIG_SCHEMA = ( sensor_schema(Sensor) @@ -33,6 +33,7 @@ async def to_code(config): widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] assert isinstance(widget, Widget) + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as lamb: lv_add(sensor.publish_state(widget.get_value())) async with LvContext(paren, LVGL_COMP_ARG): diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index 957fce17ff..f855c2a034 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -16,7 +16,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch) CONFIG_SCHEMA = ( @@ -35,6 +35,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as checked_ctx: checked_ctx.add(switch.publish_state(widget.get_value())) async with LambdaContext([(cg.bool_, "v")]) as control: diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 9ee494d8a0..56fa42e131 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -15,7 +15,7 @@ from ..lvcode import ( ) from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText, lvgl_ns -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets LVGLText = lvgl_ns.class_("LVGLText", text.Text) @@ -32,6 +32,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str())") lv.event_send(widget.obj, API_EVENT, None) diff --git a/esphome/components/lvgl/text_sensor/__init__.py b/esphome/components/lvgl/text_sensor/__init__.py index cab715dce0..ae39eec291 100644 --- a/esphome/components/lvgl/text_sensor/__init__.py +++ b/esphome/components/lvgl/text_sensor/__init__.py @@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext from ..schemas import LVGL_SCHEMA from ..types import LV_EVENT, LvText -from ..widgets import get_widgets +from ..widgets import get_widgets, wait_for_widgets CONFIG_SCHEMA = ( text_sensor_schema(TextSensor) @@ -28,6 +28,7 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_LVGL_ID]) widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] + await wait_for_widgets() async with LambdaContext(EVENT_ARG) as pressed_ctx: pressed_ctx.add(sensor.publish_state(widget.get_value())) async with LvContext(paren) as ctx: diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 50da6e131d..17d73c1714 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -1,4 +1,3 @@ -import asyncio import sys from typing import Any, Union @@ -224,9 +223,17 @@ async def get_widget_(wid: Widget): return await FakeAwaitable(get_widget_generator(wid)) +def widgets_wait_generator(): + while True: + if Widget.widgets_completed: + return + yield + + async def wait_for_widgets(): - while not Widget.widgets_completed: - await asyncio.sleep(0) + if Widget.widgets_completed: + return + await FakeAwaitable(widgets_wait_generator()) async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]: From 9975e8b544d0d2943503b90e75a4723d130e68b9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:20:26 +1200 Subject: [PATCH 2299/2607] [api] Fix sending the ``once`` flag on ha entity subscription (#7357) --- esphome/components/api/api_connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bd438265d4..195fcab0ab 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -179,6 +179,7 @@ void APIConnection::loop() { SubscribeHomeAssistantStateResponse resp; resp.entity_id = it.entity_id; resp.attribute = it.attribute.value(); + resp.once = it.once; if (this->send_subscribe_home_assistant_state_response(resp)) { state_subs_at_++; } From 28eda4b220519edfd761d65c3d24f0df0aab4f3c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 28 Aug 2024 12:54:31 +1200 Subject: [PATCH 2300/2607] Bump version to 2024.8.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f99d442be3..b27949bf29 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0" +__version__ = "2024.8.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From d6df466237142c542d4ea19ddabe0a7a2f7bb898 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:29:41 +1000 Subject: [PATCH 2301/2607] [lvgl] Add lvgl.widget.focus action and related triggers. (#7315) --- esphome/components/lvgl/__init__.py | 15 +++- esphome/components/lvgl/automation.py | 81 ++++++++++++++++++++- esphome/components/lvgl/defines.py | 5 +- esphome/components/lvgl/lvcode.py | 6 +- esphome/components/lvgl/lvgl_esphome.cpp | 54 ++++++++++++++ esphome/components/lvgl/lvgl_esphome.h | 9 +++ esphome/components/lvgl/schemas.py | 10 +-- esphome/components/lvgl/trigger.py | 5 +- esphome/components/lvgl/types.py | 2 +- esphome/components/lvgl/widgets/__init__.py | 4 +- esphome/components/lvgl/widgets/arc.py | 6 +- esphome/components/lvgl/widgets/page.py | 58 +++++++++++++-- tests/components/lvgl/lvgl-package.yaml | 25 +++++++ 13 files changed, 253 insertions(+), 27 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index ea020435dc..cab6462d1a 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -21,8 +21,8 @@ from esphome.final_validate import full_config from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid -from .automation import disp_update, update_to_code -from .defines import CONF_SKIP +from .automation import disp_update, focused_widgets, update_to_code +from .defines import CONF_ADJUSTABLE, CONF_SKIP from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent @@ -67,7 +67,7 @@ from .widgets.lv_bar import bar_spec from .widgets.meter import meter_spec from .widgets.msgbox import MSGBOX_SCHEMA, msgboxes_to_code from .widgets.obj import obj_spec -from .widgets.page import add_pages, page_spec +from .widgets.page import add_pages, generate_page_triggers, page_spec from .widgets.roller import roller_spec from .widgets.slider import slider_spec from .widgets.spinbox import spinbox_spec @@ -182,6 +182,14 @@ def final_validation(config): raise cv.Invalid( "Using RGBA or RGB24 in image config not compatible with LVGL", path ) + for w in focused_widgets: + path = global_config.get_path_for_id(w) + widget_conf = global_config.get_config_for_path(path[:-1]) + if CONF_ADJUSTABLE in widget_conf and not widget_conf[CONF_ADJUSTABLE]: + raise cv.Invalid( + "A non adjustable arc may not be focused", + path, + ) async def to_code(config): @@ -271,6 +279,7 @@ async def to_code(config): Widget.set_completed() async with LvContext(lv_component): await generate_triggers(lv_component) + await generate_page_triggers(lv_component, config) for conf in config.get(CONF_ON_IDLE, ()): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index eb1b54e3ec..8138551c30 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -4,13 +4,15 @@ from typing import Callable from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_TIMEOUT -from esphome.cpp_generator import RawExpression +from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT +from esphome.cpp_generator import RawExpression, get_variable from esphome.cpp_types import nullptr from .defines import ( CONF_DISP_BG_COLOR, CONF_DISP_BG_IMAGE, + CONF_EDITING, + CONF_FREEZE, CONF_LVGL_ID, CONF_SHOW_SNOW, literal, @@ -30,6 +32,7 @@ from .lvcode import ( lv_expr, lv_obj, lvgl_comp, + static_cast, ) from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA from .types import ( @@ -38,7 +41,9 @@ from .types import ( LvglCondition, ObjUpdateAction, lv_disp_t, + lv_group_t, lv_obj_t, + lv_pseudo_button_t, ) from .widgets import ( Widget, @@ -48,6 +53,9 @@ from .widgets import ( wait_for_widgets, ) +# Record widgets that are used in a focused action here +focused_widgets = set() + async def action_to_code( widgets: list[Widget], @@ -234,3 +242,72 @@ async def obj_show_to_code(config, action_id, template_arg, args): return await action_to_code( await get_widgets(config), do_show, action_id, template_arg, args ) + + +def focused_id(value): + value = cv.use_id(lv_pseudo_button_t)(value) + focused_widgets.add(value) + return value + + +@automation.register_action( + "lvgl.widget.focus", + ObjUpdateAction, + cv.Any( + cv.maybe_simple_value( + { + cv.Optional(CONF_GROUP): cv.use_id(lv_group_t), + cv.Required(CONF_ACTION): cv.one_of( + "MARK", "RESTORE", "NEXT", "PREVIOUS", upper=True + ), + cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), + cv.Optional(CONF_FREEZE, default=False): cv.boolean, + }, + key=CONF_ACTION, + ), + cv.maybe_simple_value( + { + cv.Required(CONF_ID): focused_id, + cv.Optional(CONF_FREEZE, default=False): cv.boolean, + cv.Optional(CONF_EDITING, default=False): cv.boolean, + }, + key=CONF_ID, + ), + ), +) +async def widget_focus(config, action_id, template_arg, args): + widget = await get_widgets(config) + if widget: + widget = widget[0] + group = static_cast( + lv_group_t.operator("ptr"), lv_expr.obj_get_group(widget.obj) + ) + elif group := config.get(CONF_GROUP): + group = await get_variable(group) + else: + group = lv_expr.group_get_default() + + async with LambdaContext(parameters=args, where=action_id) as context: + if widget: + lv.group_focus_freeze(group, False) + lv.group_focus_obj(widget.obj) + if config[CONF_EDITING]: + lv.group_set_editing(group, True) + else: + action = config[CONF_ACTION] + lv_comp = await get_variable(config[CONF_LVGL_ID]) + if action == "MARK": + context.add(lv_comp.set_focus_mark(group)) + else: + lv.group_focus_freeze(group, False) + if action == "RESTORE": + context.add(lv_comp.restore_focus_mark(group)) + elif action == "NEXT": + lv.group_focus_next(group) + else: + lv.group_focus_prev(group) + + if config[CONF_FREEZE]: + lv.group_focus_freeze(group, True) + var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) + return var diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 7bb1667e77..e05bf52120 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -148,6 +148,7 @@ LV_EVENT_MAP = { "DEFOCUS": "DEFOCUSED", "READY": "READY", "CANCEL": "CANCEL", + "ALL_EVENTS": "ALL", } LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP) @@ -390,6 +391,7 @@ CONF_DEFAULT_FONT = "default_font" CONF_DEFAULT_GROUP = "default_group" CONF_DIR = "dir" CONF_DISPLAYS = "displays" +CONF_EDITING = "editing" CONF_ENCODERS = "encoders" CONF_END_ANGLE = "end_angle" CONF_END_VALUE = "end_value" @@ -401,6 +403,7 @@ CONF_FLEX_ALIGN_MAIN = "flex_align_main" CONF_FLEX_ALIGN_CROSS = "flex_align_cross" CONF_FLEX_ALIGN_TRACK = "flex_align_track" CONF_FLEX_GROW = "flex_grow" +CONF_FREEZE = "freeze" CONF_FULL_REFRESH = "full_refresh" CONF_GRID_CELL_ROW_POS = "grid_cell_row_pos" CONF_GRID_CELL_COLUMN_POS = "grid_cell_column_pos" @@ -428,9 +431,9 @@ CONF_MSGBOXES = "msgboxes" CONF_OBJ = "obj" CONF_OFFSET_X = "offset_x" CONF_OFFSET_Y = "offset_y" +CONF_ONE_CHECKED = "one_checked" CONF_ONE_LINE = "one_line" CONF_ON_SELECT = "on_select" -CONF_ONE_CHECKED = "one_checked" CONF_NEXT = "next" CONF_PAD_ROW = "pad_row" CONF_PAD_COLUMN = "pad_column" diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 8d029ce0ca..a3d13f7f8c 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -28,7 +28,7 @@ LVGL_COMP = "lv_component" # used as a lambda argument in lvgl_comp() LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) LVGL_COMP_ARG = [(LvglComponent.operator("ptr"), LVGL_COMP)] lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") -EVENT_ARG = [(lv_event_t_ptr, "ev")] +EVENT_ARG = [(lv_event_t_ptr, "event")] # Two custom events; API_EVENT is fired when an entity is updated remotely by an API interaction; # UPDATE_EVENT is fired when an entity is programmatically updated locally. # VALUE_CHANGED is the event generated by LVGL when an entity's value changes through user interaction. @@ -291,6 +291,10 @@ class LvExpr(MockLv): pass +def static_cast(type, value): + return literal(f"static_cast<{type}>({value})") + + # Top level mock for generic lv_ calls to be recorded lv = MockLv("lv_") # Just generate an expression diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 6882986e7c..89c9828740 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -15,6 +15,60 @@ static void log_cb(const char *buf) { } #endif // LV_USE_LOG +static const char *const EVENT_NAMES[] = { + "NONE", + "PRESSED", + "PRESSING", + "PRESS_LOST", + "SHORT_CLICKED", + "LONG_PRESSED", + "LONG_PRESSED_REPEAT", + "CLICKED", + "RELEASED", + "SCROLL_BEGIN", + "SCROLL_END", + "SCROLL", + "GESTURE", + "KEY", + "FOCUSED", + "DEFOCUSED", + "LEAVE", + "HIT_TEST", + "COVER_CHECK", + "REFR_EXT_DRAW_SIZE", + "DRAW_MAIN_BEGIN", + "DRAW_MAIN", + "DRAW_MAIN_END", + "DRAW_POST_BEGIN", + "DRAW_POST", + "DRAW_POST_END", + "DRAW_PART_BEGIN", + "DRAW_PART_END", + "VALUE_CHANGED", + "INSERT", + "REFRESH", + "READY", + "CANCEL", + "DELETE", + "CHILD_CHANGED", + "CHILD_CREATED", + "CHILD_DELETED", + "SCREEN_UNLOAD_START", + "SCREEN_LOAD_START", + "SCREEN_LOADED", + "SCREEN_UNLOADED", + "SIZE_CHANGED", + "STYLE_CHANGED", + "LAYOUT_CHANGED", + "GET_SELF_SIZE", +}; + +std::string lv_event_code_name_for(uint8_t event_code) { + if (event_code < sizeof(EVENT_NAMES) / sizeof(EVENT_NAMES[0])) { + return EVENT_NAMES[event_code]; + } + return str_sprintf("%2d", event_code); +} static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { // make sure all coordinates are even if (area->x1 & 1) diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index df3d4aa68c..e248530971 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -40,6 +40,7 @@ namespace lvgl { extern lv_event_code_t lv_api_event; // NOLINT extern lv_event_code_t lv_update_event; // NOLINT +extern std::string lv_event_code_name_for(uint8_t event_code); extern bool lv_is_pre_initialise(); #ifdef USE_LVGL_COLOR inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } @@ -143,6 +144,13 @@ class LvglComponent : public PollingComponent { void show_next_page(lv_scr_load_anim_t anim, uint32_t time); void show_prev_page(lv_scr_load_anim_t anim, uint32_t time); void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; } + void set_focus_mark(lv_group_t *group) { this->focus_marks_[group] = lv_group_get_focused(group); } + void restore_focus_mark(lv_group_t *group) { + auto *mark = this->focus_marks_[group]; + if (mark != nullptr) { + lv_group_focus_obj(mark); + } + } protected: void write_random_(); @@ -158,6 +166,7 @@ class LvglComponent : public PollingComponent { bool show_snow_{}; lv_coord_t snow_line_{}; bool page_wrap_{true}; + std::map focus_marks_{}; std::vector> init_lambdas_; CallbackManager idle_callbacks_{}; diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index e9714e3b1a..548ebda6dc 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -20,7 +20,7 @@ from . import defines as df, lv_validation as lvalid from .defines import CONF_TIME_FORMAT from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_color, lv_font, lv_image -from .lvcode import LvglComponent +from .lvcode import LvglComponent, lv_event_t_ptr from .types import ( LVEncoderListener, LvType, @@ -215,14 +215,12 @@ def automation_schema(typ: LvType): events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,) else: events = df.LV_EVENT_TRIGGERS - if isinstance(typ, LvType): - template = Trigger.template(typ.get_arg_type()) - else: - template = Trigger.template() + args = [typ.get_arg_type()] if isinstance(typ, LvType) else [] + args.append(lv_event_t_ptr) return { cv.Optional(event): validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(template), + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template(*args)), } ) for event in events diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index ba93aabb2d..5288745fab 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -19,6 +19,7 @@ from .lvcode import ( LvConditional, lv, lv_add, + lv_event_t_ptr, ) from .types import LV_EVENT from .widgets import widget_map @@ -65,10 +66,10 @@ async def generate_triggers(lv_component): async def add_trigger(conf, lv_component, w, *events): tid = conf[CONF_TRIGGER_ID] trigger = cg.new_Pvariable(tid) - args = w.get_args() + args = w.get_args() + [(lv_event_t_ptr, "event")] value = w.get_value() await automation.build_automation(trigger, args, conf) async with LambdaContext(EVENT_ARG, where=tid) as context: with LvConditional(w.is_selected()): - lv_add(trigger.trigger(value)) + lv_add(trigger.trigger(value, literal("event"))) lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events)) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index be17cf62c2..e4735ea58d 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -57,7 +57,7 @@ lv_group_t = cg.global_ns.struct("lv_group_t") LVTouchListener = lvgl_ns.class_("LVTouchListener") LVEncoderListener = lvgl_ns.class_("LVEncoderListener") lv_obj_t = LvType("lv_obj_t") -lv_page_t = cg.global_ns.class_("LvPageType", LvCompound) +lv_page_t = LvType("LvPageType", parents=(LvCompound,)) lv_img_t = LvType("lv_img_t") LV_EVENT = MockObj(base="LV_EVENT_", op="") diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 062c268135..ae06bf20b0 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -225,7 +225,7 @@ def get_widget_generator(wid): yield -async def get_widget_(wid: Widget): +async def get_widget_(wid): if obj := widget_map.get(wid): return obj return await FakeAwaitable(get_widget_generator(wid)) @@ -348,8 +348,6 @@ async def set_obj_properties(w: Widget, config): if group := config.get(CONF_GROUP): group = await cg.get_variable(group) lv.group_add_obj(group, w.obj) - flag_clr = set() - flag_set = set() props = parts[CONF_MAIN][CONF_DEFAULT] lambs = {} flag_set = set() diff --git a/esphome/components/lvgl/widgets/arc.py b/esphome/components/lvgl/widgets/arc.py index a6f8918e2f..dc120e4cbb 100644 --- a/esphome/components/lvgl/widgets/arc.py +++ b/esphome/components/lvgl/widgets/arc.py @@ -1,5 +1,6 @@ import esphome.config_validation as cv from esphome.const import ( + CONF_GROUP, CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, @@ -20,7 +21,7 @@ from ..defines import ( literal, ) from ..lv_validation import angle, get_start_value, lv_float -from ..lvcode import lv, lv_obj +from ..lvcode import lv, lv_expr, lv_obj from ..types import LvNumber, NumberType from . import Widget @@ -69,6 +70,9 @@ class ArcType(NumberType): if config.get(CONF_ADJUSTABLE) is False: lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB")) w.clear_flag("LV_OBJ_FLAG_CLICKABLE") + elif CONF_GROUP not in config: + # For some reason arc does not get automatically added to the default group + lv.group_add_obj(lv_expr.group_get_default(), w.obj) value = await get_start_value(config) if value is not None: diff --git a/esphome/components/lvgl/widgets/page.py b/esphome/components/lvgl/widgets/page.py index f80d802b33..0e84ab6791 100644 --- a/esphome/components/lvgl/widgets/page.py +++ b/esphome/components/lvgl/widgets/page.py @@ -1,6 +1,7 @@ from esphome import automation, codegen as cg +from esphome.automation import Trigger import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME +from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME, CONF_TRIGGER_ID from ..defines import ( CONF_ANIMATION, @@ -9,12 +10,39 @@ from ..defines import ( CONF_PAGE_WRAP, CONF_SKIP, LV_ANIM, + literal, ) from ..lv_validation import lv_bool, lv_milliseconds -from ..lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp +from ..lvcode import ( + EVENT_ARG, + LVGL_COMP_ARG, + LambdaContext, + add_line_marks, + lv_add, + lvgl_comp, +) from ..schemas import LVGL_SCHEMA from ..types import LvglAction, lv_page_t -from . import Widget, WidgetType, add_widgets, set_obj_properties +from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties + +CONF_ON_LOAD = "on_load" +CONF_ON_UNLOAD = "on_unload" + +PAGE_SCHEMA = cv.Schema( + { + cv.Optional(CONF_SKIP, default=False): lv_bool, + cv.Optional(CONF_ON_LOAD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template()), + } + ), + cv.Optional(CONF_ON_UNLOAD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template()), + } + ), + } +) class PageType(WidgetType): @@ -23,9 +51,8 @@ class PageType(WidgetType): CONF_PAGE, lv_page_t, (), - { - cv.Optional(CONF_SKIP, default=False): lv_bool, - }, + PAGE_SCHEMA, + modify_schema={}, ) async def to_code(self, w: Widget, config: dict): @@ -39,7 +66,6 @@ SHOW_SCHEMA = LVGL_SCHEMA.extend( } ) - page_spec = PageType() @@ -111,3 +137,21 @@ async def add_pages(lv_component, config): await set_obj_properties(page, config) await set_obj_properties(page, pconf) await add_widgets(page, pconf) + + +async def generate_page_triggers(lv_component, config): + for pconf in config.get(CONF_PAGES, ()): + page = (await get_widgets(pconf))[0] + for ev in (CONF_ON_LOAD, CONF_ON_UNLOAD): + for loaded in pconf.get(ev, ()): + trigger = cg.new_Pvariable(loaded[CONF_TRIGGER_ID]) + await automation.build_automation(trigger, [], loaded) + async with LambdaContext(EVENT_ARG, where=id) as context: + lv_add(trigger.trigger()) + lv_add( + lv_component.add_event_cb( + page.obj, + await context.get_lambda(), + literal(f"LV_EVENT_SCREEN_{ev[3:].upper()}_START"), + ) + ) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 0e2c37048b..737d8703b0 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -54,6 +54,17 @@ lvgl: long_press_time: 500ms pages: - id: page1 + on_load: + - logger.log: page loaded + - lvgl.widget.focus: + action: restore + on_unload: + - logger.log: page unloaded + - lvgl.widget.focus: mark + on_all_events: + logger.log: + format: "Event %s" + args: ['lv_event_code_name_for(event->code).c_str()'] skip: true layout: type: flex @@ -70,6 +81,10 @@ lvgl: repeat_count: 10 duration: 1s auto_start: true + on_all_events: + logger.log: + format: "Event %s" + args: ['lv_event_code_name_for(event->code).c_str()'] - label: id: hello_label text: Hello world @@ -229,6 +244,16 @@ lvgl: - label: text: Button on_click: + - lvgl.widget.focus: spin_up + - lvgl.widget.focus: next + - lvgl.widget.focus: previous + - lvgl.widget.focus: + action: previous + freeze: true + - lvgl.widget.focus: + id: spin_up + freeze: true + editing: true - lvgl.label.update: id: hello_label bg_color: 0x123456 From 4b2032a98e7b93c359da92af00d0926bb2d9551d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 29 Aug 2024 05:07:31 +1200 Subject: [PATCH 2302/2607] [datetime] Fix templated args (#7368) --- esphome/components/datetime/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 4fda97c5bc..5429121d56 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -186,7 +186,7 @@ async def datetime_date_set_to_code(config, action_id, template_arg, args): date_config = config[CONF_DATE] if cg.is_template(date_config): - template_ = await cg.templatable(date_config, [], cg.ESPTime) + template_ = await cg.templatable(date_config, args, cg.ESPTime) cg.add(action_var.set_date(template_)) else: date_struct = cg.StructInitializer( @@ -217,7 +217,7 @@ async def datetime_time_set_to_code(config, action_id, template_arg, args): time_config = config[CONF_TIME] if cg.is_template(time_config): - template_ = await cg.templatable(time_config, [], cg.ESPTime) + template_ = await cg.templatable(time_config, args, cg.ESPTime) cg.add(action_var.set_time(template_)) else: time_struct = cg.StructInitializer( @@ -248,7 +248,7 @@ async def datetime_datetime_set_to_code(config, action_id, template_arg, args): datetime_config = config[CONF_DATETIME] if cg.is_template(datetime_config): - template_ = await cg.templatable(datetime_config, [], cg.ESPTime) + template_ = await cg.templatable(datetime_config, args, cg.ESPTime) cg.add(action_var.set_datetime(template_)) else: datetime_struct = cg.StructInitializer( From b3f03c07c615ae072de8fc1c9f7e6171497a7e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Kry=C5=84ski?= Date: Thu, 29 Aug 2024 02:52:13 +0200 Subject: [PATCH 2303/2607] esp32_can: suppress compiler warning (#7372) --- esphome/components/esp32_can/esp32_can.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/esp32_can/esp32_can.cpp b/esphome/components/esp32_can/esp32_can.cpp index 79e4b70f97..214b72e864 100644 --- a/esphome/components/esp32_can/esp32_can.cpp +++ b/esphome/components/esp32_can/esp32_can.cpp @@ -111,6 +111,7 @@ canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) { .flags = flags, .identifier = frame->can_id, .data_length_code = frame->can_data_length_code, + .data = {}, // to suppress warning, data is initialized properly below }; if (!frame->remote_transmission_request) { memcpy(message.data, frame->data, frame->can_data_length_code); From 0375072bdfe57d5f8eb50b622e9ad9d6d298fd4a Mon Sep 17 00:00:00 2001 From: Aiden <37043404+tarontop@users.noreply.github.com> Date: Thu, 29 Aug 2024 08:52:49 +0800 Subject: [PATCH 2304/2607] Add support for BL0906 energy meter (#7339) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/bl0906/__init__.py | 1 + esphome/components/bl0906/bl0906.cpp | 238 ++++++++++++++++++ esphome/components/bl0906/bl0906.h | 96 +++++++ esphome/components/bl0906/const.py | 4 + esphome/components/bl0906/constants.h | 122 +++++++++ esphome/components/bl0906/sensor.py | 184 ++++++++++++++ tests/components/bl0906/common.yaml | 62 +++++ tests/components/bl0906/test.esp32-ard.yaml | 5 + .../components/bl0906/test.esp32-c3-ard.yaml | 5 + .../components/bl0906/test.esp32-c3-idf.yaml | 5 + tests/components/bl0906/test.esp32-idf.yaml | 5 + tests/components/bl0906/test.esp8266-ard.yaml | 5 + tests/components/bl0906/test.rp2040-ard.yaml | 5 + 14 files changed, 738 insertions(+) create mode 100644 esphome/components/bl0906/__init__.py create mode 100644 esphome/components/bl0906/bl0906.cpp create mode 100644 esphome/components/bl0906/bl0906.h create mode 100644 esphome/components/bl0906/const.py create mode 100644 esphome/components/bl0906/constants.h create mode 100644 esphome/components/bl0906/sensor.py create mode 100644 tests/components/bl0906/common.yaml create mode 100644 tests/components/bl0906/test.esp32-ard.yaml create mode 100644 tests/components/bl0906/test.esp32-c3-ard.yaml create mode 100644 tests/components/bl0906/test.esp32-c3-idf.yaml create mode 100644 tests/components/bl0906/test.esp32-idf.yaml create mode 100644 tests/components/bl0906/test.esp8266-ard.yaml create mode 100644 tests/components/bl0906/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 9159f5f843..40511e2f41 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -58,6 +58,7 @@ esphome/components/beken_spi_led_strip/* @Mat931 esphome/components/bh1750/* @OttoWinter esphome/components/binary_sensor/* @esphome/core esphome/components/bk72xx/* @kuba2k2 +esphome/components/bl0906/* @athom-tech @jesserockz @tarontop esphome/components/bl0939/* @ziceva esphome/components/bl0940/* @tobias- esphome/components/bl0942/* @dbuezas diff --git a/esphome/components/bl0906/__init__.py b/esphome/components/bl0906/__init__.py new file mode 100644 index 0000000000..b077792604 --- /dev/null +++ b/esphome/components/bl0906/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@athom-tech", "@tarontop", "@jesserockz"] diff --git a/esphome/components/bl0906/bl0906.cpp b/esphome/components/bl0906/bl0906.cpp new file mode 100644 index 0000000000..bddb62ff64 --- /dev/null +++ b/esphome/components/bl0906/bl0906.cpp @@ -0,0 +1,238 @@ +#include "bl0906.h" +#include "constants.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace bl0906 { + +static const char *const TAG = "bl0906"; + +constexpr uint32_t to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; } + +constexpr int32_t to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; } + +// The SUM byte is (Addr+Data_L+Data_M+Data_H)&0xFF negated; +constexpr uint8_t bl0906_checksum(const uint8_t address, const DataPacket *data) { + return (address + data->l + data->m + data->h) ^ 0xFF; +} + +void BL0906::loop() { + if (this->current_channel_ == UINT8_MAX) { + return; + } + + while (this->available()) + this->flush(); + + if (this->current_channel_ == 0) { + // Temperature + this->read_data_(BL0906_TEMPERATURE, BL0906_TREF, this->temperature_sensor_); + } else if (this->current_channel_ == 1) { + this->read_data_(BL0906_I_1_RMS, BL0906_IREF, this->current_1_sensor_); + this->read_data_(BL0906_WATT_1, BL0906_PREF, this->power_1_sensor_); + this->read_data_(BL0906_CF_1_CNT, BL0906_EREF, this->energy_1_sensor_); + } else if (this->current_channel_ == 2) { + this->read_data_(BL0906_I_2_RMS, BL0906_IREF, this->current_2_sensor_); + this->read_data_(BL0906_WATT_2, BL0906_PREF, this->power_2_sensor_); + this->read_data_(BL0906_CF_2_CNT, BL0906_EREF, this->energy_2_sensor_); + } else if (this->current_channel_ == 3) { + this->read_data_(BL0906_I_3_RMS, BL0906_IREF, this->current_3_sensor_); + this->read_data_(BL0906_WATT_3, BL0906_PREF, this->power_3_sensor_); + this->read_data_(BL0906_CF_3_CNT, BL0906_EREF, this->energy_3_sensor_); + } else if (this->current_channel_ == 4) { + this->read_data_(BL0906_I_4_RMS, BL0906_IREF, this->current_4_sensor_); + this->read_data_(BL0906_WATT_4, BL0906_PREF, this->power_4_sensor_); + this->read_data_(BL0906_CF_4_CNT, BL0906_EREF, this->energy_4_sensor_); + } else if (this->current_channel_ == 5) { + this->read_data_(BL0906_I_5_RMS, BL0906_IREF, this->current_5_sensor_); + this->read_data_(BL0906_WATT_5, BL0906_PREF, this->power_5_sensor_); + this->read_data_(BL0906_CF_5_CNT, BL0906_EREF, this->energy_5_sensor_); + } else if (this->current_channel_ == 6) { + this->read_data_(BL0906_I_6_RMS, BL0906_IREF, this->current_6_sensor_); + this->read_data_(BL0906_WATT_6, BL0906_PREF, this->power_6_sensor_); + this->read_data_(BL0906_CF_6_CNT, BL0906_EREF, this->energy_6_sensor_); + } else if (this->current_channel_ == UINT8_MAX - 2) { + // Frequency + this->read_data_(BL0906_FREQUENCY, BL0906_FREF, frequency_sensor_); + // Voltage + this->read_data_(BL0906_V_RMS, BL0906_UREF, voltage_sensor_); + } else if (this->current_channel_ == UINT8_MAX - 1) { + // Total power + this->read_data_(BL0906_WATT_SUM, BL0906_WATT, this->total_power_sensor_); + // Total Energy + this->read_data_(BL0906_CF_SUM_CNT, BL0906_CF, this->total_energy_sensor_); + } else { + this->current_channel_ = UINT8_MAX - 2; // Go to frequency and voltage + return; + } + this->current_channel_++; + this->handle_actions_(); +} + +void BL0906::setup() { + while (this->available()) + this->flush(); + this->write_array(USR_WRPROT_WITABLE, sizeof(USR_WRPROT_WITABLE)); + // Calibration (1: register address; 2: value before calibration; 3: value after calibration) + this->bias_correction_(BL0906_RMSOS_1, 0.01600, 0); // Calibration current_1 + this->bias_correction_(BL0906_RMSOS_2, 0.01500, 0); + this->bias_correction_(BL0906_RMSOS_3, 0.01400, 0); + this->bias_correction_(BL0906_RMSOS_4, 0.01300, 0); + this->bias_correction_(BL0906_RMSOS_5, 0.01200, 0); + this->bias_correction_(BL0906_RMSOS_6, 0.01200, 0); // Calibration current_6 + + this->write_array(USR_WRPROT_ONLYREAD, sizeof(USR_WRPROT_ONLYREAD)); +} + +void BL0906::update() { this->current_channel_ = 0; } + +size_t BL0906::enqueue_action_(ActionCallbackFuncPtr function) { + this->action_queue_.push_back(function); + return this->action_queue_.size(); +} + +void BL0906::handle_actions_() { + if (this->action_queue_.empty()) { + return; + } + ActionCallbackFuncPtr ptr_func = nullptr; + for (int i = 0; i < this->action_queue_.size(); i++) { + ptr_func = this->action_queue_[i]; + if (ptr_func) { + ESP_LOGI(TAG, "HandleActionCallback[%d]...", i); + (this->*ptr_func)(); + } + } + + while (this->available()) { + this->read(); + } + + this->action_queue_.clear(); +} + +// Reset energy +void BL0906::reset_energy_() { + this->write_array(BL0906_INIT[0], 6); + delay(1); + this->flush(); + + ESP_LOGW(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_INIT[0][0], BL0906_INIT[0][1], BL0906_INIT[0][2], + BL0906_INIT[0][3], BL0906_INIT[0][4], BL0906_INIT[0][5]); +} + +// Read data +void BL0906::read_data_(const uint8_t address, const float reference, sensor::Sensor *sensor) { + if (sensor == nullptr) { + return; + } + DataPacket buffer; + ube24_t data_u24; + sbe24_t data_s24; + float value = 0; + + bool signed_result = reference == BL0906_TREF || reference == BL0906_WATT || reference == BL0906_PREF; + + this->write_byte(BL0906_READ_COMMAND); + this->write_byte(address); + if (this->read_array((uint8_t *) &buffer, sizeof(buffer) - 1)) { + if (bl0906_checksum(address, &buffer) == buffer.checksum) { + if (signed_result) { + data_s24.l = buffer.l; + data_s24.m = buffer.m; + data_s24.h = buffer.h; + } else { + data_u24.l = buffer.l; + data_u24.m = buffer.m; + data_u24.h = buffer.h; + } + } else { + ESP_LOGW(TAG, "Junk on wire. Throwing away partial message"); + while (read() >= 0) + ; + return; + } + } + // Power + if (reference == BL0906_PREF) { + value = (float) to_int32_t(data_s24) * reference; + } + + // Total power + if (reference == BL0906_WATT) { + value = (float) to_int32_t(data_s24) * reference; + } + + // Voltage, current, power, total power + if (reference == BL0906_UREF || reference == BL0906_IREF || reference == BL0906_EREF || reference == BL0906_CF) { + value = (float) to_uint32_t(data_u24) * reference; + } + + // Frequency + if (reference == BL0906_FREF) { + value = reference / (float) to_uint32_t(data_u24); + } + // Chip temperature + if (reference == BL0906_TREF) { + value = (float) to_int32_t(data_s24); + value = (value - 64) * 12.5 / 59 - 40; + } + sensor->publish_state(value); +} + +// RMS offset correction +void BL0906::bias_correction_(uint8_t address, float measurements, float correction) { + DataPacket data; + float ki = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097; // Current coefficient + float i_rms0 = measurements * ki; + float i_rms = correction * ki; + int32_t value = (i_rms * i_rms - i_rms0 * i_rms0) / 256; + data.l = value << 24 >> 24; + data.m = value << 16 >> 24; + if (value < 0) { + data.h = (value << 8 >> 24) | 0b10000000; + } + data.address = bl0906_checksum(address, &data); + ESP_LOGV(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_WRITE_COMMAND, address, data.l, data.m, data.h, data.address); + this->write_byte(BL0906_WRITE_COMMAND); + this->write_byte(address); + this->write_byte(data.l); + this->write_byte(data.m); + this->write_byte(data.h); + this->write_byte(data.address); +} + +void BL0906::dump_config() { + ESP_LOGCONFIG(TAG, "BL0906:"); + LOG_SENSOR(" ", "Voltage", this->voltage_sensor_); + + LOG_SENSOR(" ", "Current1", this->current_1_sensor_); + LOG_SENSOR(" ", "Current2", this->current_2_sensor_); + LOG_SENSOR(" ", "Current3", this->current_3_sensor_); + LOG_SENSOR(" ", "Current4", this->current_4_sensor_); + LOG_SENSOR(" ", "Current5", this->current_5_sensor_); + LOG_SENSOR(" ", "Current6", this->current_6_sensor_); + + LOG_SENSOR(" ", "Power1", this->power_1_sensor_); + LOG_SENSOR(" ", "Power2", this->power_2_sensor_); + LOG_SENSOR(" ", "Power3", this->power_3_sensor_); + LOG_SENSOR(" ", "Power4", this->power_4_sensor_); + LOG_SENSOR(" ", "Power5", this->power_5_sensor_); + LOG_SENSOR(" ", "Power6", this->power_6_sensor_); + + LOG_SENSOR(" ", "Energy1", this->energy_1_sensor_); + LOG_SENSOR(" ", "Energy2", this->energy_2_sensor_); + LOG_SENSOR(" ", "Energy3", this->energy_3_sensor_); + LOG_SENSOR(" ", "Energy4", this->energy_4_sensor_); + LOG_SENSOR(" ", "Energy5", this->energy_5_sensor_); + LOG_SENSOR(" ", "Energy6", this->energy_6_sensor_); + + LOG_SENSOR(" ", "Total Power", this->total_power_sensor_); + LOG_SENSOR(" ", "Total Energy", this->total_energy_sensor_); + LOG_SENSOR(" ", "Frequency", this->frequency_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); +} + +} // namespace bl0906 +} // namespace esphome diff --git a/esphome/components/bl0906/bl0906.h b/esphome/components/bl0906/bl0906.h new file mode 100644 index 0000000000..5a9ad0f028 --- /dev/null +++ b/esphome/components/bl0906/bl0906.h @@ -0,0 +1,96 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/datatypes.h" + +// https://www.belling.com.cn/media/file_object/bel_product/BL0906/datasheet/BL0906_V1.02_cn.pdf +// https://www.belling.com.cn/media/file_object/bel_product/BL0906/guide/BL0906%20APP%20Note_V1.02.pdf + +namespace esphome { +namespace bl0906 { + +struct DataPacket { // NOLINT(altera-struct-pack-align) + uint8_t l{0}; + uint8_t m{0}; + uint8_t h{0}; + uint8_t checksum; // checksum + uint8_t address; +} __attribute__((packed)); + +struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align) + uint8_t l{0}; + uint8_t m{0}; + uint8_t h{0}; +} __attribute__((packed)); + +struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align) + uint8_t l{0}; + uint8_t m{0}; + int8_t h{0}; +} __attribute__((packed)); + +template class ResetEnergyAction; + +class BL0906; + +using ActionCallbackFuncPtr = void (BL0906::*)(); + +class BL0906 : public PollingComponent, public uart::UARTDevice { + SUB_SENSOR(voltage) + SUB_SENSOR(current_1) + SUB_SENSOR(current_2) + SUB_SENSOR(current_3) + SUB_SENSOR(current_4) + SUB_SENSOR(current_5) + SUB_SENSOR(current_6) + SUB_SENSOR(power_1) + SUB_SENSOR(power_2) + SUB_SENSOR(power_3) + SUB_SENSOR(power_4) + SUB_SENSOR(power_5) + SUB_SENSOR(power_6) + SUB_SENSOR(total_power) + SUB_SENSOR(energy_1) + SUB_SENSOR(energy_2) + SUB_SENSOR(energy_3) + SUB_SENSOR(energy_4) + SUB_SENSOR(energy_5) + SUB_SENSOR(energy_6) + SUB_SENSOR(total_energy) + SUB_SENSOR(frequency) + SUB_SENSOR(temperature) + + public: + void loop() override; + + void update() override; + void setup() override; + void dump_config() override; + + protected: + template friend class ResetEnergyAction; + + void reset_energy_(); + + void read_data_(uint8_t address, float reference, sensor::Sensor *sensor); + + void bias_correction_(uint8_t address, float measurements, float correction); + + uint8_t current_channel_{0}; + size_t enqueue_action_(ActionCallbackFuncPtr function); + void handle_actions_(); + + private: + std::vector action_queue_{}; +}; + +template class ResetEnergyAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->enqueue_action_(&BL0906::reset_energy_); } +}; + +} // namespace bl0906 +} // namespace esphome diff --git a/esphome/components/bl0906/const.py b/esphome/components/bl0906/const.py new file mode 100644 index 0000000000..67f21d35b0 --- /dev/null +++ b/esphome/components/bl0906/const.py @@ -0,0 +1,4 @@ +# const.py +ICON_ENERGY = "mdi:lightning-bolt" +ICON_FREQUENCY = "mdi:cosine-wave" +ICON_VOLTAGE = "mdi:sine-wave" diff --git a/esphome/components/bl0906/constants.h b/esphome/components/bl0906/constants.h new file mode 100644 index 0000000000..546916aa3c --- /dev/null +++ b/esphome/components/bl0906/constants.h @@ -0,0 +1,122 @@ +#pragma once +#include + +namespace esphome { +namespace bl0906 { + +// Total power conversion +static const float BL0906_WATT = 16 * 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) / + (40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000); +// Total Energy conversion +static const float BL0906_CF = 16 * 4194304 * 0.032768 * 16 / + (3600000 * 16 * + (40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 / + (1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000)))); +// Frequency conversion +static const float BL0906_FREF = 10000000; +// Temperature conversion +static const float BL0906_TREF = 12.5 / 59 - 40; +// Current conversion +static const float BL0906_IREF = 1.097 / (12875 * 1 * (5.1 + 5.1) * 1000 / 2000); +// Voltage conversion +static const float BL0906_UREF = 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) / (13162 * 1 * 100 * 1000); +// Power conversion +static const float BL0906_PREF = 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) / + (40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000); +// Energy conversion +static const float BL0906_EREF = 4194304 * 0.032768 * 16 / + (3600000 * 16 * + (40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 / + (1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000)))); +// Current coefficient +static const float BL0906_KI = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097; +// Power coefficient +static const float BL0906_KP = 40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 / 1.097 / 1.097 / + (20000 + 20000 + 20000 + 20000 + 20000); + +static const uint8_t USR_WRPROT_WITABLE[6] = {0xCA, 0x9E, 0x55, 0x55, 0x00, 0xB7}; +static const uint8_t USR_WRPROT_ONLYREAD[6] = {0xCA, 0x9E, 0x00, 0x00, 0x00, 0x61}; + +static const uint8_t BL0906_READ_COMMAND = 0x35; +static const uint8_t BL0906_WRITE_COMMAND = 0xCA; + +// Register address +// Voltage +static const uint8_t BL0906_V_RMS = 0x16; + +// Total power +static const uint8_t BL0906_WATT_SUM = 0X2C; + +// Current1~6 +static const uint8_t BL0906_I_1_RMS = 0x0D; // current_1 +static const uint8_t BL0906_I_2_RMS = 0x0E; +static const uint8_t BL0906_I_3_RMS = 0x0F; +static const uint8_t BL0906_I_4_RMS = 0x10; +static const uint8_t BL0906_I_5_RMS = 0x13; +static const uint8_t BL0906_I_6_RMS = 0x14; // current_6 + +// Power1~6 +static const uint8_t BL0906_WATT_1 = 0X23; // power_1 +static const uint8_t BL0906_WATT_2 = 0X24; +static const uint8_t BL0906_WATT_3 = 0X25; +static const uint8_t BL0906_WATT_4 = 0X26; +static const uint8_t BL0906_WATT_5 = 0X29; +static const uint8_t BL0906_WATT_6 = 0X2A; // power_6 + +// Active pulse count, unsigned +static const uint8_t BL0906_CF_1_CNT = 0X30; // Channel_1 +static const uint8_t BL0906_CF_2_CNT = 0X31; +static const uint8_t BL0906_CF_3_CNT = 0X32; +static const uint8_t BL0906_CF_4_CNT = 0X33; +static const uint8_t BL0906_CF_5_CNT = 0X36; +static const uint8_t BL0906_CF_6_CNT = 0X37; // Channel_6 + +// Total active pulse count, unsigned +static const uint8_t BL0906_CF_SUM_CNT = 0X39; + +// Voltage frequency cycle +static const uint8_t BL0906_FREQUENCY = 0X4E; + +// Internal temperature +static const uint8_t BL0906_TEMPERATURE = 0X5E; + +// Calibration register +// RMS gain adjustment register +static const uint8_t BL0906_RMSGN_1 = 0x6D; // Channel_1 +static const uint8_t BL0906_RMSGN_2 = 0x6E; +static const uint8_t BL0906_RMSGN_3 = 0x6F; +static const uint8_t BL0906_RMSGN_4 = 0x70; +static const uint8_t BL0906_RMSGN_5 = 0x73; +static const uint8_t BL0906_RMSGN_6 = 0x74; // Channel_6 + +// RMS offset correction register +static const uint8_t BL0906_RMSOS_1 = 0x78; // Channel_1 +static const uint8_t BL0906_RMSOS_2 = 0x79; +static const uint8_t BL0906_RMSOS_3 = 0x7A; +static const uint8_t BL0906_RMSOS_4 = 0x7B; +static const uint8_t BL0906_RMSOS_5 = 0x7E; +static const uint8_t BL0906_RMSOS_6 = 0x7F; // Channel_6 + +// Active power gain adjustment register +static const uint8_t BL0906_WATTGN_1 = 0xB7; // Channel_1 +static const uint8_t BL0906_WATTGN_2 = 0xB8; +static const uint8_t BL0906_WATTGN_3 = 0xB9; +static const uint8_t BL0906_WATTGN_4 = 0xBA; +static const uint8_t BL0906_WATTGN_5 = 0xBD; +static const uint8_t BL0906_WATTGN_6 = 0xBE; // Channel_6 + +// User write protection setting register, +// You must first write 0x5555 to the write protection setting register before writing to other registers. +static const uint8_t BL0906_USR_WRPROT = 0x9E; + +// Reset Register +static const uint8_t BL0906_SOFT_RESET = 0x9F; + +const uint8_t BL0906_INIT[2][6] = { + // Reset to default + {BL0906_WRITE_COMMAND, BL0906_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x52}, + // Enable User Operation Write + {BL0906_WRITE_COMMAND, BL0906_USR_WRPROT, 0x55, 0x55, 0x00, 0xB7}}; + +} // namespace bl0906 +} // namespace esphome diff --git a/esphome/components/bl0906/sensor.py b/esphome/components/bl0906/sensor.py new file mode 100644 index 0000000000..bc370c9252 --- /dev/null +++ b/esphome/components/bl0906/sensor.py @@ -0,0 +1,184 @@ +from esphome import automation +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +from esphome.components import sensor, uart +import esphome.config_validation as cv +from esphome.const import ( + CONF_CHANNEL, + CONF_CURRENT, + CONF_ENERGY, + CONF_FREQUENCY, + CONF_ID, + CONF_NAME, + CONF_POWER, + CONF_TEMPERATURE, + CONF_TOTAL_POWER, + CONF_VOLTAGE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_FREQUENCY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + ICON_CURRENT_AC, + ICON_POWER, + ICON_THERMOMETER, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + UNIT_AMPERE, + UNIT_CELSIUS, + UNIT_HERTZ, + UNIT_KILOWATT_HOURS, + UNIT_VOLT, + UNIT_WATT, +) + +# Import ICONS not included in esphome's const.py, from the local components const.py +from .const import ICON_ENERGY, ICON_FREQUENCY, ICON_VOLTAGE + +DEPENDENCIES = ["uart"] +AUTO_LOAD = ["bl0906"] +CONF_TOTAL_ENERGY = "total_energy" + +bl0906_ns = cg.esphome_ns.namespace("bl0906") +BL0906 = bl0906_ns.class_("BL0906", cg.PollingComponent, uart.UARTDevice) +ResetEnergyAction = bl0906_ns.class_("ResetEnergyAction", automation.Action) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(BL0906), + cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( + icon=ICON_FREQUENCY, + accuracy_decimals=0, + device_class=DEVICE_CLASS_FREQUENCY, + unit_of_measurement=UNIT_HERTZ, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + icon=ICON_THERMOMETER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + unit_of_measurement=UNIT_CELSIUS, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( + icon=ICON_VOLTAGE, + accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLTAGE, + unit_of_measurement=UNIT_VOLT, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TOTAL_POWER): sensor.sensor_schema( + icon=ICON_POWER, + accuracy_decimals=3, + device_class=DEVICE_CLASS_POWER, + unit_of_measurement=UNIT_WATT, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TOTAL_ENERGY): sensor.sensor_schema( + icon=ICON_ENERGY, + accuracy_decimals=3, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_TOTAL_INCREASING, + unit_of_measurement=UNIT_KILOWATT_HOURS, + ), + } + ) + .extend( + cv.Schema( + { + cv.Optional(f"{CONF_CHANNEL}_{i + 1}"): cv.Schema( + { + cv.Optional(CONF_CURRENT): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_CURRENT_AC, + accuracy_decimals=3, + device_class=DEVICE_CLASS_CURRENT, + unit_of_measurement=UNIT_AMPERE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_POWER): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_POWER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_POWER, + unit_of_measurement=UNIT_WATT, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ENERGY): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_ENERGY, + accuracy_decimals=3, + device_class=DEVICE_CLASS_ENERGY, + unit_of_measurement=UNIT_KILOWATT_HOURS, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), + key=CONF_NAME, + ), + } + ) + for i in range(6) + } + ) + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.polling_component_schema("60s")) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "bl0906", baud_rate=19200, require_tx=True, require_rx=True +) + + +@automation.register_action( + "bl0906.reset_energy", + ResetEnergyAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(BL0906), + } + ), +) +async def reset_energy_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + if frequency_config := config.get(CONF_FREQUENCY): + sens = await sensor.new_sensor(frequency_config) + cg.add(var.set_frequency_sensor(sens)) + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + if voltage_config := config.get(CONF_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) + cg.add(var.set_voltage_sensor(sens)) + + for i in range(6): + if channel_config := config.get(f"{CONF_CHANNEL}_{i + 1}"): + if current_config := channel_config.get(CONF_CURRENT): + sens = await sensor.new_sensor(current_config) + cg.add(getattr(var, f"set_current_{i + 1}_sensor")(sens)) + if power_config := channel_config.get(CONF_POWER): + sens = await sensor.new_sensor(power_config) + cg.add(getattr(var, f"set_power_{i + 1}_sensor")(sens)) + if energy_config := channel_config.get(CONF_ENERGY): + sens = await sensor.new_sensor(energy_config) + cg.add(getattr(var, f"set_energy_{i + 1}_sensor")(sens)) + + if total_power_config := config.get(CONF_TOTAL_POWER): + sens = await sensor.new_sensor(total_power_config) + cg.add(var.set_total_power_sensor(sens)) + + if total_energy_config := config.get(CONF_TOTAL_ENERGY): + sens = await sensor.new_sensor(total_energy_config) + cg.add(var.set_total_energy_sensor(sens)) diff --git a/tests/components/bl0906/common.yaml b/tests/components/bl0906/common.yaml new file mode 100644 index 0000000000..944791369c --- /dev/null +++ b/tests/components/bl0906/common.yaml @@ -0,0 +1,62 @@ +uart: + - id: uart_bl0906 + tx_pin: + number: ${tx_pin} + rx_pin: + number: ${rx_pin} + baud_rate: 19200 + +sensor: + - platform: bl0906 + frequency: + name: 'Frequency' + temperature: + name: 'Temperature' + voltage: + name: 'Voltage' + channel_1: + current: + name: 'Current_1' + power: + name: 'Power_1' + energy: + name: 'Energy_1' + channel_2: + current: + name: 'Current_2' + power: + name: 'Power_2' + energy: + name: 'Energy_2' + channel_3: + current: + name: 'Current_3' + power: + name: 'Power_3' + energy: + name: 'Energy_3' + channel_4: + current: + name: 'Current_4' + power: + name: 'Power_4' + energy: + name: 'Energy_4' + channel_5: + current: + name: 'Current_5' + power: + name: 'Power_5' + energy: + name: 'Energy_5' + channel_6: + current: + name: 'Current_6' + power: + name: 'Power_6' + energy: + name: 'Energy_6' + total_energy: + name: 'Total_Energy' + total_power: + name: 'Total_Power' diff --git a/tests/components/bl0906/test.esp32-ard.yaml b/tests/components/bl0906/test.esp32-ard.yaml new file mode 100644 index 0000000000..811f6b72a6 --- /dev/null +++ b/tests/components/bl0906/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO12 + rx_pin: GPIO14 + +<<: !include common.yaml diff --git a/tests/components/bl0906/test.esp32-c3-ard.yaml b/tests/components/bl0906/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..c79d14c740 --- /dev/null +++ b/tests/components/bl0906/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO7 + rx_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bl0906/test.esp32-c3-idf.yaml b/tests/components/bl0906/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..c79d14c740 --- /dev/null +++ b/tests/components/bl0906/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO7 + rx_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bl0906/test.esp32-idf.yaml b/tests/components/bl0906/test.esp32-idf.yaml new file mode 100644 index 0000000000..811f6b72a6 --- /dev/null +++ b/tests/components/bl0906/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO12 + rx_pin: GPIO14 + +<<: !include common.yaml diff --git a/tests/components/bl0906/test.esp8266-ard.yaml b/tests/components/bl0906/test.esp8266-ard.yaml new file mode 100644 index 0000000000..3b44f9c9c3 --- /dev/null +++ b/tests/components/bl0906/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO1 + rx_pin: GPIO3 + +<<: !include common.yaml diff --git a/tests/components/bl0906/test.rp2040-ard.yaml b/tests/components/bl0906/test.rp2040-ard.yaml new file mode 100644 index 0000000000..b516342f3b --- /dev/null +++ b/tests/components/bl0906/test.rp2040-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 + +<<: !include common.yaml From 1922f2bbee79ba1c4830ec286ef7032cd8b7d613 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 29 Aug 2024 10:55:37 +1000 Subject: [PATCH 2305/2607] [platformio] Add environments for ESP-IDF 5.3 for development (#7371) --- platformio.ini | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/platformio.ini b/platformio.ini index 4a0a3f2ef4..147159a841 100644 --- a/platformio.ini +++ b/platformio.ini @@ -153,6 +153,13 @@ build_flags = -DUSE_ESP32_FRAMEWORK_ESP_IDF extra_scripts = post:esphome/components/esp32/post_build.py.script +; This are common settings for the ESP32 using the latest ESP-IDF version. +[common:esp32-idf-5_3] +extends = common:esp32-idf +platform = platformio/espressif32@6.8.0 +platform_packages = + platformio/framework-espidf@~3.50300.0 + ; These are common settings for the RP2040 using Arduino. [common:rp2040-arduino] extends = common:arduino @@ -229,6 +236,15 @@ build_flags = ${flags:runtime.build_flags} -DUSE_ESP32_VARIANT_ESP32 +[env:esp32-idf-5_3] +extends = common:esp32-idf-5_3 +board = esp32dev +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32 + [env:esp32-idf-tidy] extends = common:esp32-idf board = esp32dev @@ -265,6 +281,15 @@ build_flags = ${flags:runtime.build_flags} -DUSE_ESP32_VARIANT_ESP32C3 +[env:esp32c3-idf-5_3] +extends = common:esp32-idf-5_3 +board = esp32-c3-devkitm-1 +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32c3-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32C3 + [env:esp32c3-idf-tidy] extends = common:esp32-idf board = esp32-c3-devkitm-1 @@ -301,6 +326,15 @@ build_flags = ${flags:runtime.build_flags} -DUSE_ESP32_VARIANT_ESP32S2 +[env:esp32s2-idf-5_3] +extends = common:esp32-idf-5_3 +board = esp32-s2-kaluga-1 +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32s2-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32S2 + [env:esp32s2-idf-tidy] extends = common:esp32-idf board = esp32-s2-kaluga-1 @@ -337,6 +371,15 @@ build_flags = ${flags:runtime.build_flags} -DUSE_ESP32_VARIANT_ESP32S3 +[env:esp32s3-idf-5_3] +extends = common:esp32-idf-5_3 +board = esp32-s3-devkitc-1 +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32s3-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32S3 + [env:esp32s3-idf-tidy] extends = common:esp32-idf board = esp32-s3-devkitc-1 From f28418d0b472e9c641cb4ebcda206f65916fa3bc Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:34:41 +1000 Subject: [PATCH 2306/2607] [lvgl] Bug fixes (#7370) --- esphome/components/lvgl/__init__.py | 2 ++ esphome/components/lvgl/lv_validation.py | 15 +++++---------- esphome/components/lvgl/schemas.py | 8 +++++++- .../components/lvgl/widgets/buttonmatrix.py | 6 +++++- esphome/components/lvgl/widgets/checkbox.py | 11 ++++++++--- esphome/components/lvgl/widgets/tileview.py | 10 ++-------- tests/components/lvgl/lvgl-package.yaml | 18 ++++++++++++++++-- 7 files changed, 45 insertions(+), 25 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index cab6462d1a..a4ca9d56f3 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -327,6 +327,8 @@ CONFIG_SCHEMA = ( { cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, } ) ), diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index a2be4a2abe..d8af9f7aa9 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -52,9 +52,7 @@ opacity = LValidator(opacity_validator, uint32, retmapper=literal) def color(value): if value == SCHEMA_EXTRACT: return ["hex color value", "color ID"] - if isinstance(value, int): - return value - return cv.use_id(ColorStruct)(value) + return cv.Any(cv.int_, cv.use_id(ColorStruct))(value) def color_retmapper(value): @@ -82,10 +80,10 @@ def pixels_or_percent_validator(value): """A length in one axis - either a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: return ["pixels", "..%"] + value = cv.Any(cv.int_, cv.percentage)(value) if isinstance(value, int): - return cv.int_(value) - # Will throw an exception if not a percentage. - return f"lv_pct({int(cv.percentage(value) * 100)})" + return value + return f"lv_pct({int(value * 100)})" pixels_or_percent = LValidator(pixels_or_percent_validator, uint32, retmapper=literal) @@ -116,10 +114,7 @@ def size_validator(value): if value.upper() == "SIZE_CONTENT": return "LV_SIZE_CONTENT" raise cv.Invalid("must be 'size_content', a percentage or an integer (pixels)") - if isinstance(value, int): - return cv.int_(value) - # Will throw an exception if not a percentage. - return f"lv_pct({int(cv.percentage(value) * 100)})" + return pixels_or_percent_validator(value) size = LValidator(size_validator, uint32, retmapper=literal) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 548ebda6dc..9ff0fec5bc 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -359,7 +359,13 @@ LVGL_SCHEMA = cv.Schema( } ) -ALL_STYLES = {**STYLE_PROPS, **GRID_CELL_SCHEMA, **FLEX_OBJ_SCHEMA} +ALL_STYLES = { + **STYLE_PROPS, + **GRID_CELL_SCHEMA, + **FLEX_OBJ_SCHEMA, + cv.Optional(df.CONF_PAD_ROW): lvalid.pixels, + cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels, +} def container_validator(schema, widget_type: WidgetType): diff --git a/esphome/components/lvgl/widgets/buttonmatrix.py b/esphome/components/lvgl/widgets/buttonmatrix.py index e61c5e3477..c65bb4b354 100644 --- a/esphome/components/lvgl/widgets/buttonmatrix.py +++ b/esphome/components/lvgl/widgets/buttonmatrix.py @@ -13,11 +13,13 @@ from ..defines import ( CONF_KEY_CODE, CONF_MAIN, CONF_ONE_CHECKED, + CONF_PAD_COLUMN, + CONF_PAD_ROW, CONF_ROWS, CONF_SELECTED, ) from ..helpers import lvgl_components_required -from ..lv_validation import key_code, lv_bool +from ..lv_validation import key_code, lv_bool, pixels from ..lvcode import lv, lv_add, lv_expr from ..schemas import automation_schema from ..types import ( @@ -57,6 +59,8 @@ BUTTONMATRIX_BUTTON_SCHEMA = cv.Schema( BUTTONMATRIX_SCHEMA = cv.Schema( { cv.Optional(CONF_ONE_CHECKED, default=False): lv_bool, + cv.Optional(CONF_PAD_ROW): pixels, + cv.Optional(CONF_PAD_COLUMN): pixels, cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr), cv.Required(CONF_ROWS): cv.ensure_list( cv.Schema( diff --git a/esphome/components/lvgl/widgets/checkbox.py b/esphome/components/lvgl/widgets/checkbox.py index 79c60a8669..75f4142eb1 100644 --- a/esphome/components/lvgl/widgets/checkbox.py +++ b/esphome/components/lvgl/widgets/checkbox.py @@ -1,7 +1,8 @@ +from esphome.config_validation import Optional from esphome.const import CONF_TEXT -from ..defines import CONF_INDICATOR, CONF_MAIN -from ..lv_validation import lv_text +from ..defines import CONF_INDICATOR, CONF_MAIN, CONF_PAD_COLUMN +from ..lv_validation import lv_text, pixels from ..lvcode import lv from ..schemas import TEXT_SCHEMA from ..types import LvBoolean @@ -16,7 +17,11 @@ class CheckboxType(WidgetType): CONF_CHECKBOX, LvBoolean("lv_checkbox_t"), (CONF_MAIN, CONF_INDICATOR), - TEXT_SCHEMA, + TEXT_SCHEMA.extend( + { + Optional(CONF_PAD_COLUMN): pixels, + } + ), ) async def to_code(self, w: Widget, config): diff --git a/esphome/components/lvgl/widgets/tileview.py b/esphome/components/lvgl/widgets/tileview.py index 9a426c7daf..05259fbd3c 100644 --- a/esphome/components/lvgl/widgets/tileview.py +++ b/esphome/components/lvgl/widgets/tileview.py @@ -1,7 +1,7 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_ON_VALUE, CONF_ROW, CONF_TRIGGER_ID +from esphome.const import CONF_ID, CONF_ROW from ..automation import action_to_code from ..defines import ( @@ -29,6 +29,7 @@ lv_tileview_t = LvType( "lv_tileview_t", largs=[(lv_obj_t_ptr, "tile")], lvalue=lambda w: w.get_property("tile_act"), + has_on_value=True, ) tile_spec = WidgetType("lv_tileview_tile_t", lv_tile_t, (CONF_MAIN,), {}) @@ -46,13 +47,6 @@ TILEVIEW_SCHEMA = cv.Schema( }, ) ), - cv.Optional(CONF_ON_VALUE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( - automation.Trigger.template(lv_obj_t_ptr) - ) - } - ), } ) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 737d8703b0..0feb6d6ce6 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -337,11 +337,25 @@ lvgl: - tileview: id: tileview_id scrollbar_mode: active + on_value: + then: + - if: + condition: + lambda: return tile == id(tile_1); + then: + - logger.log: "tile 1 is now showing" tiles: - - id: page_1 + - id: tile_1 row: 0 column: 0 - dir: HOR + dir: ALL + widgets: + - obj: + bg_color: 0x000000 + - id: tile_2 + row: 1 + column: 0 + dir: [VER, HOR] widgets: - obj: bg_color: 0x000000 From c09df3c05d4012da3b815ddccc5149a714094274 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 30 Aug 2024 06:16:16 +1000 Subject: [PATCH 2307/2607] [bytebuffer] Use existing bit_cast operations. (#7374) --- esphome/core/bytebuffer.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp index 65525ecfcf..9dd32bf87a 100644 --- a/esphome/core/bytebuffer.cpp +++ b/esphome/core/bytebuffer.cpp @@ -1,6 +1,9 @@ #include "bytebuffer.h" #include -#include +#include "esphome/core/helpers.h" + +#include +#include namespace esphome { @@ -110,18 +113,13 @@ uint32_t ByteBuffer::get_int24() { } float ByteBuffer::get_float() { assert(this->get_remaining() >= sizeof(float)); - auto ui_value = this->get_uint32(); - float value; - memcpy(&value, &ui_value, sizeof(float)); - return value; + return bit_cast(this->get_uint32()); } double ByteBuffer::get_double() { assert(this->get_remaining() >= sizeof(double)); - auto ui_value = this->get_uint64(); - double value; - memcpy(&value, &ui_value, sizeof(double)); - return value; + return bit_cast(this->get_uint64()); } + std::vector ByteBuffer::get_vector(size_t length) { assert(this->get_remaining() >= length); auto start = this->data_.begin() + this->position_; @@ -154,16 +152,12 @@ void ByteBuffer::put_uint(uint64_t value, size_t length) { void ByteBuffer::put_float(float value) { static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); assert(this->get_remaining() >= sizeof(float)); - uint32_t ui_value; - memcpy(&ui_value, &value, sizeof(float)); // this work-around required to silence compiler warnings - this->put_uint32(ui_value); + this->put_uint32(bit_cast(value)); } void ByteBuffer::put_double(double value) { static_assert(sizeof(double) == sizeof(uint64_t), "Double sizes other than 64 bit not supported"); assert(this->get_remaining() >= sizeof(double)); - uint64_t ui_value; - memcpy(&ui_value, &value, sizeof(double)); - this->put_uint64(ui_value); + this->put_uint64(bit_cast(value)); } void ByteBuffer::put_vector(const std::vector &value) { assert(this->get_remaining() >= value.size()); From bb6693a2552f94b1b375a4e5d195e51e27523751 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 08:17:28 +1200 Subject: [PATCH 2308/2607] Bump actions/setup-python from 5.1.0 to 5.2.0 (#7375) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/sync-device-classes.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index ee08a0246d..8112c4e0ff 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -23,7 +23,7 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: "3.11" diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 91c02b0a17..891367d16a 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -42,7 +42,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: "3.9" - name: Set up Docker Buildx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2437dd5b8d..7c4fa65695 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d454076c84..937c7aac90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: "3.x" - name: Set up python environment @@ -85,7 +85,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: "3.9" diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 89a3627c64..7677425236 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -22,7 +22,7 @@ jobs: path: lib/home-assistant - name: Setup Python - uses: actions/setup-python@v5.1.0 + uses: actions/setup-python@v5.2.0 with: python-version: 3.12 From acb00c9c59bd79847fdab7602e06486511bd6dc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 08:17:34 +1200 Subject: [PATCH 2309/2607] Bump actions/setup-python from 5.1.1 to 5.2.0 in /.github/actions/restore-python (#7376) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index d3fe2a89dc..c618a5ca97 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -17,7 +17,7 @@ runs: steps: - name: Set up Python ${{ inputs.python-version }} id: python - uses: actions/setup-python@v5.1.1 + uses: actions/setup-python@v5.2.0 with: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment From 725e50348b240c00c2c287d09d9ba8dec138561d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 30 Aug 2024 06:20:12 +1000 Subject: [PATCH 2310/2607] [gt911] Add reset pin config (#7373) --- .../components/gt911/touchscreen/__init__.py | 12 +++++---- .../gt911/touchscreen/gt911_touchscreen.cpp | 17 +++++++++++++ .../gt911/touchscreen/gt911_touchscreen.h | 2 ++ tests/components/gt911/common.yaml | 25 +++++++++++++++++++ tests/components/gt911/test.esp32-ard.yaml | 25 +------------------ tests/components/gt911/test.esp32-c3-ard.yaml | 25 +------------------ tests/components/gt911/test.esp32-c3-idf.yaml | 25 +------------------ tests/components/gt911/test.esp32-idf.yaml | 25 +------------------ tests/components/gt911/test.rp2040-ard.yaml | 25 +------------------ 9 files changed, 56 insertions(+), 125 deletions(-) create mode 100644 tests/components/gt911/common.yaml diff --git a/esphome/components/gt911/touchscreen/__init__.py b/esphome/components/gt911/touchscreen/__init__.py index 9a0d5cc169..6c80ff280f 100644 --- a/esphome/components/gt911/touchscreen/__init__.py +++ b/esphome/components/gt911/touchscreen/__init__.py @@ -1,11 +1,10 @@ -import esphome.codegen as cg -import esphome.config_validation as cv - from esphome import pins +import esphome.codegen as cg from esphome.components import i2c, touchscreen -from esphome.const import CONF_INTERRUPT_PIN, CONF_ID -from .. import gt911_ns +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from .. import gt911_ns GT911ButtonListener = gt911_ns.class_("GT911ButtonListener") GT911Touchscreen = gt911_ns.class_( @@ -18,6 +17,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(GT911Touchscreen), cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, } ).extend(i2c.i2c_device_schema(0x5D)) @@ -29,3 +29,5 @@ async def to_code(config): if interrupt_pin := config.get(CONF_INTERRUPT_PIN): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) + if reset_pin := config.get(CONF_RESET_PIN): + cg.add(var.set_reset_pin(await cg.gpio_pin_expression(reset_pin))) diff --git a/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp b/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp index 99dba66c22..84811b818f 100644 --- a/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +++ b/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp @@ -26,6 +26,23 @@ static const size_t MAX_BUTTONS = 4; // max number of buttons scanned void GT911Touchscreen::setup() { i2c::ErrorCode err; ESP_LOGCONFIG(TAG, "Setting up GT911 Touchscreen..."); + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(false); + if (this->interrupt_pin_ != nullptr) { + // The interrupt pin is used as an input during reset to select the I2C address. + this->interrupt_pin_->pin_mode(gpio::FLAG_OUTPUT); + this->interrupt_pin_->setup(); + this->interrupt_pin_->digital_write(false); + } + delay(2); + this->reset_pin_->digital_write(true); + delay(50); // NOLINT + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT); + this->interrupt_pin_->setup(); + } + } // check the configuration of the int line. uint8_t data[4]; diff --git a/esphome/components/gt911/touchscreen/gt911_touchscreen.h b/esphome/components/gt911/touchscreen/gt911_touchscreen.h index a9e1279ed3..17636a2ada 100644 --- a/esphome/components/gt911/touchscreen/gt911_touchscreen.h +++ b/esphome/components/gt911/touchscreen/gt911_touchscreen.h @@ -19,12 +19,14 @@ class GT911Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice void dump_config() override; void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } void register_button_listener(GT911ButtonListener *listener) { this->button_listeners_.push_back(listener); } protected: void update_touches() override; InternalGPIOPin *interrupt_pin_{}; + GPIOPin *reset_pin_{}; std::vector button_listeners_; uint8_t button_state_{0xFF}; // last button state. Initial FF guarantees first update. }; diff --git a/tests/components/gt911/common.yaml b/tests/components/gt911/common.yaml new file mode 100644 index 0000000000..7bb88108da --- /dev/null +++ b/tests/components/gt911/common.yaml @@ -0,0 +1,25 @@ +i2c: + - id: i2c_gt911 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 10 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: gt911 + display: ssd1306_display + interrupt_pin: 20 + reset_pin: 21 + +binary_sensor: + - platform: gt911 + id: touch_key_911 + index: 0 diff --git a/tests/components/gt911/test.esp32-ard.yaml b/tests/components/gt911/test.esp32-ard.yaml index a47f7bf260..dade44d145 100644 --- a/tests/components/gt911/test.esp32-ard.yaml +++ b/tests/components/gt911/test.esp32-ard.yaml @@ -1,24 +1 @@ -i2c: - - id: i2c_gt911 - scl: 16 - sda: 17 - -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 13 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -touchscreen: - - platform: gt911 - display: ssd1306_display - interrupt_pin: 14 - -binary_sensor: - - platform: gt911 - id: touch_key_911 - index: 0 +<<: !include common.yaml diff --git a/tests/components/gt911/test.esp32-c3-ard.yaml b/tests/components/gt911/test.esp32-c3-ard.yaml index 43f7ac5902..dade44d145 100644 --- a/tests/components/gt911/test.esp32-c3-ard.yaml +++ b/tests/components/gt911/test.esp32-c3-ard.yaml @@ -1,24 +1 @@ -i2c: - - id: i2c_gt911 - scl: 5 - sda: 4 - -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -touchscreen: - - platform: gt911 - display: ssd1306_display - interrupt_pin: 6 - -binary_sensor: - - platform: gt911 - id: touch_key_911 - index: 0 +<<: !include common.yaml diff --git a/tests/components/gt911/test.esp32-c3-idf.yaml b/tests/components/gt911/test.esp32-c3-idf.yaml index 43f7ac5902..dade44d145 100644 --- a/tests/components/gt911/test.esp32-c3-idf.yaml +++ b/tests/components/gt911/test.esp32-c3-idf.yaml @@ -1,24 +1 @@ -i2c: - - id: i2c_gt911 - scl: 5 - sda: 4 - -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -touchscreen: - - platform: gt911 - display: ssd1306_display - interrupt_pin: 6 - -binary_sensor: - - platform: gt911 - id: touch_key_911 - index: 0 +<<: !include common.yaml diff --git a/tests/components/gt911/test.esp32-idf.yaml b/tests/components/gt911/test.esp32-idf.yaml index a47f7bf260..dade44d145 100644 --- a/tests/components/gt911/test.esp32-idf.yaml +++ b/tests/components/gt911/test.esp32-idf.yaml @@ -1,24 +1 @@ -i2c: - - id: i2c_gt911 - scl: 16 - sda: 17 - -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 13 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -touchscreen: - - platform: gt911 - display: ssd1306_display - interrupt_pin: 14 - -binary_sensor: - - platform: gt911 - id: touch_key_911 - index: 0 +<<: !include common.yaml diff --git a/tests/components/gt911/test.rp2040-ard.yaml b/tests/components/gt911/test.rp2040-ard.yaml index 43f7ac5902..dade44d145 100644 --- a/tests/components/gt911/test.rp2040-ard.yaml +++ b/tests/components/gt911/test.rp2040-ard.yaml @@ -1,24 +1 @@ -i2c: - - id: i2c_gt911 - scl: 5 - sda: 4 - -display: - - platform: ssd1306_i2c - id: ssd1306_display - model: SSD1306_128X64 - reset_pin: 3 - pages: - - id: page1 - lambda: |- - it.rectangle(0, 0, it.get_width(), it.get_height()); - -touchscreen: - - platform: gt911 - display: ssd1306_display - interrupt_pin: 6 - -binary_sensor: - - platform: gt911 - id: touch_key_911 - index: 0 +<<: !include common.yaml From d754bdde1b74b39f6d78a40a5fa92b721ce4cd93 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 30 Aug 2024 06:27:35 +1000 Subject: [PATCH 2311/2607] [st7701s] Add delay feature in init sequences (#7343) --- esphome/components/st7701s/display.py | 88 +++++++++++++------------- esphome/components/st7701s/st7701s.cpp | 17 +++-- esphome/components/st7701s/st7701s.h | 1 + tests/components/st7701s/common.yaml | 7 +- 4 files changed, 61 insertions(+), 52 deletions(-) diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py index 516d770f8b..9310e9d760 100644 --- a/esphome/components/st7701s/display.py +++ b/esphome/components/st7701s/display.py @@ -1,47 +1,39 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins -from esphome.components import ( - spi, - display, -) -from esphome.const import ( - CONF_DC_PIN, - CONF_HSYNC_PIN, - CONF_RESET_PIN, - CONF_DATA_PINS, - CONF_ID, - CONF_DIMENSIONS, - CONF_VSYNC_PIN, - CONF_WIDTH, - CONF_HEIGHT, - CONF_LAMBDA, - CONF_MIRROR_X, - CONF_MIRROR_Y, - CONF_COLOR_ORDER, - CONF_TRANSFORM, - CONF_OFFSET_HEIGHT, - CONF_OFFSET_WIDTH, - CONF_INVERT_COLORS, - CONF_RED, - CONF_GREEN, - CONF_BLUE, - CONF_NUMBER, - CONF_IGNORE_STRAPPING_WARNING, -) - -from esphome.components.esp32 import ( - only_on_variant, - const, -) +import esphome.codegen as cg +from esphome.components import display, spi +from esphome.components.esp32 import const, only_on_variant from esphome.components.rpi_dpi_rgb.display import ( CONF_PCLK_FREQUENCY, CONF_PCLK_INVERTED, ) -from .init_sequences import ( - ST7701S_INITS, - cmd, +import esphome.config_validation as cv +from esphome.const import ( + CONF_BLUE, + CONF_COLOR_ORDER, + CONF_DATA_PINS, + CONF_DC_PIN, + CONF_DIMENSIONS, + CONF_GREEN, + CONF_HEIGHT, + CONF_HSYNC_PIN, + CONF_ID, + CONF_IGNORE_STRAPPING_WARNING, + CONF_INVERT_COLORS, + CONF_LAMBDA, + CONF_MIRROR_X, + CONF_MIRROR_Y, + CONF_NUMBER, + CONF_OFFSET_HEIGHT, + CONF_OFFSET_WIDTH, + CONF_RED, + CONF_RESET_PIN, + CONF_TRANSFORM, + CONF_VSYNC_PIN, + CONF_WIDTH, ) +from esphome.core import TimePeriod + +from .init_sequences import ST7701S_INITS, cmd CONF_INIT_SEQUENCE = "init_sequence" CONF_DE_PIN = "de_pin" @@ -59,6 +51,7 @@ DEPENDENCIES = ["spi", "esp32"] st7701s_ns = cg.esphome_ns.namespace("st7701s") ST7701S = st7701s_ns.class_("ST7701S", display.Display, cg.Component, spi.SPIDevice) ColorOrder = display.display_ns.enum("ColorMode") +ST7701S_DELAY_FLAG = 0xFF COLOR_ORDERS = { "RGB": ColorOrder.COLOR_ORDER_RGB, @@ -93,18 +86,23 @@ def map_sequence(value): """ An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py, or can be a literal array of data bytes. - The format is a repeated sequence of [CMD, LEN, ] where is LEN bytes. + The format is a repeated sequence of [CMD, ] where is s a sequence of bytes. The length is inferred + from the length of the sequence and should not be explicit. + A delay can be inserted by specifying "- delay N" where N is in ms """ + if isinstance(value, str) and value.lower().startswith("delay "): + value = value.lower()[6:] + delay = cv.All( + cv.positive_time_period_milliseconds, + cv.Range(TimePeriod(milliseconds=1), TimePeriod(milliseconds=255)), + )(value) + return [delay, ST7701S_DELAY_FLAG] if not isinstance(value, list): value = cv.int_(value) value = cv.one_of(*ST7701S_INITS)(value) return ST7701S_INITS[value] - # value = cv.ensure_list(cv.uint8_t)(value) - data_length = len(value) - if data_length == 0: - raise cv.Invalid("Empty sequence") - value = cmd(*value) - return value + value = cv.Length(min=1, max=254)(value) + return cmd(*value) CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 43d8653709..7f02fe1774 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -138,11 +138,16 @@ void ST7701S::write_init_sequence_() { for (size_t i = 0; i != this->init_sequence_.size();) { uint8_t cmd = this->init_sequence_[i++]; size_t len = this->init_sequence_[i++]; - this->write_sequence_(cmd, len, &this->init_sequence_[i]); - i += len; - esph_log_v(TAG, "Command %X, %d bytes", cmd, len); - if (cmd == SW_RESET_CMD) - delay(6); + if (len == ST7701S_DELAY_FLAG) { + ESP_LOGV(TAG, "Delay %dms", cmd); + delay(cmd); + } else { + this->write_sequence_(cmd, len, &this->init_sequence_[i]); + i += len; + ESP_LOGV(TAG, "Command %X, %d bytes", cmd, len); + if (cmd == SW_RESET_CMD) + delay(6); + } } // st7701 does not appear to support axis swapping this->write_sequence_(CMD2_BKSEL, sizeof(CMD2_BK0), CMD2_BK0); @@ -153,7 +158,7 @@ void ST7701S::write_init_sequence_() { val |= 0x10; this->write_command_(MADCTL_CMD); this->write_data_(val); - esph_log_d(TAG, "write MADCTL %X", val); + ESP_LOGD(TAG, "write MADCTL %X", val); this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); this->set_timeout(120, [this] { this->write_command_(SLEEP_OUT); diff --git a/esphome/components/st7701s/st7701s.h b/esphome/components/st7701s/st7701s.h index 2328bca965..80e5b81f4a 100644 --- a/esphome/components/st7701s/st7701s.h +++ b/esphome/components/st7701s/st7701s.h @@ -25,6 +25,7 @@ const uint8_t INVERT_ON = 0x21; const uint8_t DISPLAY_ON = 0x29; const uint8_t CMD2_BKSEL = 0xFF; const uint8_t CMD2_BK0[5] = {0x77, 0x01, 0x00, 0x00, 0x10}; +const uint8_t ST7701S_DELAY_FLAG = 0xFF; class ST7701S : public display::Display, public spi::SPIDevice Date: Fri, 30 Aug 2024 09:20:01 +1000 Subject: [PATCH 2312/2607] Add now required `invert_colors` option to test files referencing ili9xxx (#7367) --- tests/components/animation/test.esp32-ard.yaml | 1 + tests/components/animation/test.esp32-c3-ard.yaml | 1 + tests/components/animation/test.esp32-c3-idf.yaml | 1 + tests/components/animation/test.esp32-idf.yaml | 1 + tests/components/animation/test.esp8266-ard.yaml | 1 + tests/components/animation/test.rp2040-ard.yaml | 1 + tests/components/cst226/common.yaml | 1 + tests/components/cst816/common.yaml | 1 + tests/components/display/common.yaml | 1 + tests/components/ft63x6/test.esp32-ard.yaml | 1 + tests/components/image/test.esp32-ard.yaml | 1 + tests/components/image/test.esp32-c3-ard.yaml | 1 + tests/components/image/test.esp32-c3-idf.yaml | 1 + tests/components/image/test.esp32-idf.yaml | 1 + tests/components/image/test.esp8266-ard.yaml | 1 + tests/components/image/test.rp2040-ard.yaml | 1 + tests/components/online_image/common-esp32.yaml | 1 + tests/components/online_image/common-esp8266.yaml | 1 + tests/components/qr_code/test.esp32-ard.yaml | 1 + tests/components/qr_code/test.esp32-c3-ard.yaml | 1 + tests/components/qr_code/test.esp32-c3-idf.yaml | 1 + tests/components/qr_code/test.esp32-idf.yaml | 1 + tests/components/qr_code/test.esp8266-ard.yaml | 1 + tests/components/qr_code/test.rp2040-ard.yaml | 1 + tests/components/tt21100/test.esp32-s2-ard.yaml | 1 + tests/components/xpt2046/test.esp32-ard.yaml | 1 + tests/components/xpt2046/test.esp32-c3-ard.yaml | 1 + tests/components/xpt2046/test.esp32-c3-idf.yaml | 1 + tests/components/xpt2046/test.esp32-idf.yaml | 1 + tests/components/xpt2046/test.esp32-s2-ard.yaml | 1 + tests/components/xpt2046/test.esp8266-ard.yaml | 1 + tests/components/xpt2046/test.rp2040-ard.yaml | 1 + 32 files changed, 32 insertions(+) diff --git a/tests/components/animation/test.esp32-ard.yaml b/tests/components/animation/test.esp32-ard.yaml index 5dc132eb2d..af6cd202dd 100644 --- a/tests/components/animation/test.esp32-ard.yaml +++ b/tests/components/animation/test.esp32-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/animation/test.esp32-c3-ard.yaml b/tests/components/animation/test.esp32-c3-ard.yaml index 9bcfbdb118..10e8ccb47e 100644 --- a/tests/components/animation/test.esp32-c3-ard.yaml +++ b/tests/components/animation/test.esp32-c3-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/animation/test.esp32-c3-idf.yaml b/tests/components/animation/test.esp32-c3-idf.yaml index 9bcfbdb118..10e8ccb47e 100644 --- a/tests/components/animation/test.esp32-c3-idf.yaml +++ b/tests/components/animation/test.esp32-c3-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/animation/test.esp32-idf.yaml b/tests/components/animation/test.esp32-idf.yaml index 5dc132eb2d..af6cd202dd 100644 --- a/tests/components/animation/test.esp32-idf.yaml +++ b/tests/components/animation/test.esp32-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/animation/test.esp8266-ard.yaml b/tests/components/animation/test.esp8266-ard.yaml index ef0f483a79..ced4996f25 100644 --- a/tests/components/animation/test.esp8266-ard.yaml +++ b/tests/components/animation/test.esp8266-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 5 dc_pin: 15 reset_pin: 16 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/animation/test.rp2040-ard.yaml b/tests/components/animation/test.rp2040-ard.yaml index 6ee29a3347..0e33959cc6 100644 --- a/tests/components/animation/test.rp2040-ard.yaml +++ b/tests/components/animation/test.rp2040-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 20 dc_pin: 21 reset_pin: 22 + invert_colors: false # Purposely test that `animation:` does auto-load `image:` # Keep the `image:` undefined. diff --git a/tests/components/cst226/common.yaml b/tests/components/cst226/common.yaml index 4cbf38ef50..7e1c5dde36 100644 --- a/tests/components/cst226/common.yaml +++ b/tests/components/cst226/common.yaml @@ -12,6 +12,7 @@ display: dc_pin: GPIO4 reset_pin: number: GPIO21 + invert_colors: false i2c: scl: GPIO18 diff --git a/tests/components/cst816/common.yaml b/tests/components/cst816/common.yaml index f8deea6e98..91abbfd4f6 100644 --- a/tests/components/cst816/common.yaml +++ b/tests/components/cst816/common.yaml @@ -26,6 +26,7 @@ display: mirror_x: true mirror_y: true auto_clear_enabled: false + invert_colors: false spi: clk_pin: 14 diff --git a/tests/components/display/common.yaml b/tests/components/display/common.yaml index a22aa76780..1df2665067 100644 --- a/tests/components/display/common.yaml +++ b/tests/components/display/common.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: false lambda: |- // Draw an analog clock in the center of the screen int centerX = it.get_width() / 2; diff --git a/tests/components/ft63x6/test.esp32-ard.yaml b/tests/components/ft63x6/test.esp32-ard.yaml index 32d6634dae..5c43cdff45 100644 --- a/tests/components/ft63x6/test.esp32-ard.yaml +++ b/tests/components/ft63x6/test.esp32-ard.yaml @@ -19,6 +19,7 @@ display: mirror_x: true mirror_y: true auto_clear_enabled: false + invert_colors: false touchscreen: - platform: ft63x6 diff --git a/tests/components/image/test.esp32-ard.yaml b/tests/components/image/test.esp32-ard.yaml index ff9adde6b1..34c7914976 100644 --- a/tests/components/image/test.esp32-ard.yaml +++ b/tests/components/image/test.esp32-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: true image: - id: binary_image diff --git a/tests/components/image/test.esp32-c3-ard.yaml b/tests/components/image/test.esp32-c3-ard.yaml index c083a97c94..91ff0a0579 100644 --- a/tests/components/image/test.esp32-c3-ard.yaml +++ b/tests/components/image/test.esp32-c3-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: true image: - id: binary_image diff --git a/tests/components/image/test.esp32-c3-idf.yaml b/tests/components/image/test.esp32-c3-idf.yaml index c083a97c94..91ff0a0579 100644 --- a/tests/components/image/test.esp32-c3-idf.yaml +++ b/tests/components/image/test.esp32-c3-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: true image: - id: binary_image diff --git a/tests/components/image/test.esp32-idf.yaml b/tests/components/image/test.esp32-idf.yaml index ff9adde6b1..34c7914976 100644 --- a/tests/components/image/test.esp32-idf.yaml +++ b/tests/components/image/test.esp32-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: true image: - id: binary_image diff --git a/tests/components/image/test.esp8266-ard.yaml b/tests/components/image/test.esp8266-ard.yaml index 3632b95485..5a96ed9497 100644 --- a/tests/components/image/test.esp8266-ard.yaml +++ b/tests/components/image/test.esp8266-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 5 dc_pin: 15 reset_pin: 16 + invert_colors: true image: - id: binary_image diff --git a/tests/components/image/test.rp2040-ard.yaml b/tests/components/image/test.rp2040-ard.yaml index b79c8a9195..4c40ca464f 100644 --- a/tests/components/image/test.rp2040-ard.yaml +++ b/tests/components/image/test.rp2040-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 20 dc_pin: 21 reset_pin: 22 + invert_colors: true image: - id: binary_image diff --git a/tests/components/online_image/common-esp32.yaml b/tests/components/online_image/common-esp32.yaml index 8cc50fc3e0..d3a304cdc0 100644 --- a/tests/components/online_image/common-esp32.yaml +++ b/tests/components/online_image/common-esp32.yaml @@ -13,6 +13,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: true lambda: |- it.fill(Color(0, 0, 0)); it.image(0, 0, id(online_rgba_image)); diff --git a/tests/components/online_image/common-esp8266.yaml b/tests/components/online_image/common-esp8266.yaml index 01e3467413..ba15b5025c 100644 --- a/tests/components/online_image/common-esp8266.yaml +++ b/tests/components/online_image/common-esp8266.yaml @@ -13,6 +13,7 @@ display: cs_pin: 15 dc_pin: 3 reset_pin: 1 + invert_colors: true lambda: |- it.fill(Color(0, 0, 0)); it.image(0, 0, id(online_rgba_image)); diff --git a/tests/components/qr_code/test.esp32-ard.yaml b/tests/components/qr_code/test.esp32-ard.yaml index 3e70d3258f..8689d4d73f 100644 --- a/tests/components/qr_code/test.esp32-ard.yaml +++ b/tests/components/qr_code/test.esp32-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/qr_code/test.esp32-c3-ard.yaml b/tests/components/qr_code/test.esp32-c3-ard.yaml index 63973b1aa2..3690d2598c 100644 --- a/tests/components/qr_code/test.esp32-c3-ard.yaml +++ b/tests/components/qr_code/test.esp32-c3-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/qr_code/test.esp32-c3-idf.yaml b/tests/components/qr_code/test.esp32-c3-idf.yaml index 63973b1aa2..3690d2598c 100644 --- a/tests/components/qr_code/test.esp32-c3-idf.yaml +++ b/tests/components/qr_code/test.esp32-c3-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/qr_code/test.esp32-idf.yaml b/tests/components/qr_code/test.esp32-idf.yaml index 3e70d3258f..8689d4d73f 100644 --- a/tests/components/qr_code/test.esp32-idf.yaml +++ b/tests/components/qr_code/test.esp32-idf.yaml @@ -11,6 +11,7 @@ display: cs_pin: 12 dc_pin: 13 reset_pin: 21 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/qr_code/test.esp8266-ard.yaml b/tests/components/qr_code/test.esp8266-ard.yaml index 3c304d7575..02dc183440 100644 --- a/tests/components/qr_code/test.esp8266-ard.yaml +++ b/tests/components/qr_code/test.esp8266-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 5 dc_pin: 15 reset_pin: 16 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/qr_code/test.rp2040-ard.yaml b/tests/components/qr_code/test.rp2040-ard.yaml index 94cb772ba3..0d86f8d213 100644 --- a/tests/components/qr_code/test.rp2040-ard.yaml +++ b/tests/components/qr_code/test.rp2040-ard.yaml @@ -11,6 +11,7 @@ display: cs_pin: 20 dc_pin: 21 reset_pin: 22 + invert_colors: false lambda: |- // Draw a QR code in the center of the screen auto scale = 2; diff --git a/tests/components/tt21100/test.esp32-s2-ard.yaml b/tests/components/tt21100/test.esp32-s2-ard.yaml index 7ebabcb130..86b9e7530d 100644 --- a/tests/components/tt21100/test.esp32-s2-ard.yaml +++ b/tests/components/tt21100/test.esp32-s2-ard.yaml @@ -18,6 +18,7 @@ display: data_rate: 40MHz dimensions: 320x240 update_interval: never + invert_colors: false transform: mirror_y: false mirror_x: false diff --git a/tests/components/xpt2046/test.esp32-ard.yaml b/tests/components/xpt2046/test.esp32-ard.yaml index bb166866f4..f15d1f9b41 100644 --- a/tests/components/xpt2046/test.esp32-ard.yaml +++ b/tests/components/xpt2046/test.esp32-ard.yaml @@ -12,6 +12,7 @@ display: cs_pin: 13 dc_pin: 14 reset_pin: 21 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/xpt2046/test.esp32-c3-ard.yaml b/tests/components/xpt2046/test.esp32-c3-ard.yaml index f3a2cf9aae..ef4daa800d 100644 --- a/tests/components/xpt2046/test.esp32-c3-ard.yaml +++ b/tests/components/xpt2046/test.esp32-c3-ard.yaml @@ -12,6 +12,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/xpt2046/test.esp32-c3-idf.yaml b/tests/components/xpt2046/test.esp32-c3-idf.yaml index f3a2cf9aae..ef4daa800d 100644 --- a/tests/components/xpt2046/test.esp32-c3-idf.yaml +++ b/tests/components/xpt2046/test.esp32-c3-idf.yaml @@ -12,6 +12,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/xpt2046/test.esp32-idf.yaml b/tests/components/xpt2046/test.esp32-idf.yaml index bb166866f4..f15d1f9b41 100644 --- a/tests/components/xpt2046/test.esp32-idf.yaml +++ b/tests/components/xpt2046/test.esp32-idf.yaml @@ -12,6 +12,7 @@ display: cs_pin: 13 dc_pin: 14 reset_pin: 21 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/xpt2046/test.esp32-s2-ard.yaml b/tests/components/xpt2046/test.esp32-s2-ard.yaml index 6232ca957b..df2a99b4f5 100644 --- a/tests/components/xpt2046/test.esp32-s2-ard.yaml +++ b/tests/components/xpt2046/test.esp32-s2-ard.yaml @@ -14,6 +14,7 @@ display: data_rate: 40MHz dimensions: 320x240 update_interval: never + invert_colors: false transform: mirror_y: false mirror_x: false diff --git a/tests/components/xpt2046/test.esp8266-ard.yaml b/tests/components/xpt2046/test.esp8266-ard.yaml index a917290e8e..0daa25ad60 100644 --- a/tests/components/xpt2046/test.esp8266-ard.yaml +++ b/tests/components/xpt2046/test.esp8266-ard.yaml @@ -12,6 +12,7 @@ display: cs_pin: 15 dc_pin: 4 reset_pin: 5 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/xpt2046/test.rp2040-ard.yaml b/tests/components/xpt2046/test.rp2040-ard.yaml index a7a49309ac..8afc45d04d 100644 --- a/tests/components/xpt2046/test.rp2040-ard.yaml +++ b/tests/components/xpt2046/test.rp2040-ard.yaml @@ -12,6 +12,7 @@ display: cs_pin: 8 dc_pin: 9 reset_pin: 10 + invert_colors: false lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); From 69f98e0f87eacdad0be79fc33287e869c37587ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Kry=C5=84ski?= Date: Fri, 30 Aug 2024 01:43:47 +0200 Subject: [PATCH 2313/2607] esp32_can: make queue lengths configurable (#7361) --- esphome/components/esp32_can/canbus.py | 25 ++++++++++++++++------ esphome/components/esp32_can/esp32_can.cpp | 7 ++++++ esphome/components/esp32_can/esp32_can.h | 4 ++++ esphome/const.py | 2 ++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/esphome/components/esp32_can/canbus.py b/esphome/components/esp32_can/canbus.py index f4ba032009..37bdfa3962 100644 --- a/esphome/components/esp32_can/canbus.py +++ b/esphome/components/esp32_can/canbus.py @@ -1,18 +1,23 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import canbus -from esphome.const import CONF_ID, CONF_RX_PIN, CONF_TX_PIN -from esphome.components.canbus import CanbusComponent, CanSpeed, CONF_BIT_RATE - +from esphome.components.canbus import CONF_BIT_RATE, CanbusComponent, CanSpeed from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( VARIANT_ESP32, - VARIANT_ESP32S2, - VARIANT_ESP32S3, VARIANT_ESP32C3, VARIANT_ESP32C6, VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_RX_PIN, + CONF_RX_QUEUE_LEN, + CONF_TX_PIN, + CONF_TX_QUEUE_LEN, ) CODEOWNERS = ["@Sympatron"] @@ -77,6 +82,8 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend( cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate, cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number, cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number, + cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t, + cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t, } ) @@ -87,3 +94,7 @@ async def to_code(config): cg.add(var.set_rx(config[CONF_RX_PIN])) cg.add(var.set_tx(config[CONF_TX_PIN])) + if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None: + cg.add(var.set_rx_queue_len(rx_queue_len)) + if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None: + cg.add(var.set_tx_queue_len(tx_queue_len)) diff --git a/esphome/components/esp32_can/esp32_can.cpp b/esphome/components/esp32_can/esp32_can.cpp index 214b72e864..5a45859b1f 100644 --- a/esphome/components/esp32_can/esp32_can.cpp +++ b/esphome/components/esp32_can/esp32_can.cpp @@ -69,6 +69,13 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config bool ESP32Can::setup_internal() { twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL); + if (this->tx_queue_len_.has_value()) { + g_config.tx_queue_len = this->tx_queue_len_.value(); + } + if (this->rx_queue_len_.has_value()) { + g_config.rx_queue_len = this->rx_queue_len_.value(); + } + twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); twai_timing_config_t t_config; diff --git a/esphome/components/esp32_can/esp32_can.h b/esphome/components/esp32_can/esp32_can.h index a428834f65..b3086f9a48 100644 --- a/esphome/components/esp32_can/esp32_can.h +++ b/esphome/components/esp32_can/esp32_can.h @@ -12,6 +12,8 @@ class ESP32Can : public canbus::Canbus { public: void set_rx(int rx) { rx_ = rx; } void set_tx(int tx) { tx_ = tx; } + void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; } + void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; } ESP32Can(){}; protected: @@ -21,6 +23,8 @@ class ESP32Can : public canbus::Canbus { int rx_{-1}; int tx_{-1}; + optional tx_queue_len_{}; + optional rx_queue_len_{}; }; } // namespace esp32_can diff --git a/esphome/const.py b/esphome/const.py index 6e29667887..95773630d0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -730,6 +730,7 @@ CONF_RW_PIN = "rw_pin" CONF_RX_BUFFER_SIZE = "rx_buffer_size" CONF_RX_ONLY = "rx_only" CONF_RX_PIN = "rx_pin" +CONF_RX_QUEUE_LEN = "rx_queue_len" CONF_SAFE_MODE = "safe_mode" CONF_SAMPLE_RATE = "sample_rate" CONF_SAMSUNG = "samsung" @@ -881,6 +882,7 @@ CONF_TVOC = "tvoc" CONF_TX_BUFFER_SIZE = "tx_buffer_size" CONF_TX_PIN = "tx_pin" CONF_TX_POWER = "tx_power" +CONF_TX_QUEUE_LEN = "tx_queue_len" CONF_TYPE = "type" CONF_TYPE_ID = "type_id" CONF_UART_ID = "uart_id" From f8e8bd2c24666fe1efaf60a44ea46dfae3093341 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Fri, 30 Aug 2024 02:03:44 +0200 Subject: [PATCH 2314/2607] [code-quality] fix clang-tidy web_server and web_server_base (#7286) --- esphome/components/web_server/__init__.py | 26 +++++++++---------- .../components/web_server/list_entities.cpp | 2 ++ esphome/components/web_server/list_entities.h | 4 ++- esphome/components/web_server/web_server.cpp | 3 ++- esphome/components/web_server/web_server.h | 2 ++ .../web_server_base/web_server_base.cpp | 2 ++ .../web_server_base/web_server_base.h | 4 ++- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 232ab40d10..02074dcf11 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -1,35 +1,36 @@ from __future__ import annotations import gzip + import esphome.codegen as cg -import esphome.config_validation as cv -import esphome.final_validate as fv from esphome.components import web_server_base from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID +import esphome.config_validation as cv from esphome.const import ( + CONF_AUTH, CONF_CSS_INCLUDE, CONF_CSS_URL, + CONF_ENABLE_PRIVATE_NETWORK_ACCESS, CONF_ID, + CONF_INCLUDE_INTERNAL, CONF_JS_INCLUDE, CONF_JS_URL, - CONF_ENABLE_PRIVATE_NETWORK_ACCESS, - CONF_PORT, - CONF_AUTH, - CONF_USERNAME, - CONF_PASSWORD, - CONF_INCLUDE_INTERNAL, - CONF_OTA, - CONF_LOG, - CONF_VERSION, CONF_LOCAL, + CONF_LOG, + CONF_OTA, + CONF_PASSWORD, + CONF_PORT, + CONF_USERNAME, + CONF_VERSION, CONF_WEB_SERVER_ID, CONF_WEB_SERVER_SORTING_WEIGHT, + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, - PLATFORM_BK72XX, PLATFORM_RTL87XX, ) from esphome.core import CORE, coroutine_with_priority +import esphome.final_validate as fv AUTO_LOAD = ["json", "web_server_base"] @@ -208,7 +209,6 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID], paren) await cg.register_component(var, config) - cg.add_define("USE_WEBSERVER") version = config[CONF_VERSION] cg.add(paren.set_port(config[CONF_PORT])) diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp index 332f358352..a02f84c34b 100644 --- a/esphome/components/web_server/list_entities.cpp +++ b/esphome/components/web_server/list_entities.cpp @@ -1,4 +1,5 @@ #include "list_entities.h" +#ifdef USE_WEBSERVER #include "esphome/core/application.h" #include "esphome/core/log.h" #include "esphome/core/util.h" @@ -188,3 +189,4 @@ bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { } // namespace web_server } // namespace esphome +#endif diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h index 5ff6ec0412..53e5bc3355 100644 --- a/esphome/components/web_server/list_entities.h +++ b/esphome/components/web_server/list_entities.h @@ -1,8 +1,9 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_WEBSERVER #include "esphome/core/component.h" #include "esphome/core/component_iterator.h" -#include "esphome/core/defines.h" namespace esphome { namespace web_server { @@ -78,3 +79,4 @@ class ListEntitiesIterator : public ComponentIterator { } // namespace web_server } // namespace esphome +#endif diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 6fb04f558a..1bb7c6c249 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1,5 +1,5 @@ #include "web_server.h" - +#ifdef USE_WEBSERVER #include "esphome/components/json/json_util.h" #include "esphome/components/network/util.h" #include "esphome/core/application.h" @@ -1659,3 +1659,4 @@ void WebServer::schedule_(std::function &&f) { } // namespace web_server } // namespace esphome +#endif diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index d4ab592b7b..3195fa7109 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -3,6 +3,7 @@ #include "list_entities.h" #include "esphome/components/web_server_base/web_server_base.h" +#ifdef USE_WEBSERVER #include "esphome/core/component.h" #include "esphome/core/controller.h" #include "esphome/core/entity_base.h" @@ -366,3 +367,4 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { } // namespace web_server } // namespace esphome +#endif diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp index f90c7e56a3..7c09022f27 100644 --- a/esphome/components/web_server_base/web_server_base.cpp +++ b/esphome/components/web_server_base/web_server_base.cpp @@ -1,4 +1,5 @@ #include "web_server_base.h" +#ifdef USE_NETWORK #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" @@ -121,3 +122,4 @@ float WebServerBase::get_setup_priority() const { } // namespace web_server_base } // namespace esphome +#endif diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index 2282d55ec1..f876d163bc 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_NETWORK #include #include #include @@ -145,3 +146,4 @@ class OTARequestHandler : public AsyncWebHandler { } // namespace web_server_base } // namespace esphome +#endif From a5d46ae9e553d27e7f66dc3bd87c64dc86b2cf36 Mon Sep 17 00:00:00 2001 From: Trevor Schirmer <24777085+TrevorSchirmer@users.noreply.github.com> Date: Thu, 29 Aug 2024 20:36:32 -0400 Subject: [PATCH 2315/2607] Update MiCS Values (#7173) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mics_4514/mics_4514.cpp | 62 +++++++++------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/esphome/components/mics_4514/mics_4514.cpp b/esphome/components/mics_4514/mics_4514.cpp index a14d7f2f80..ed2fc6c826 100644 --- a/esphome/components/mics_4514/mics_4514.cpp +++ b/esphome/components/mics_4514/mics_4514.cpp @@ -70,72 +70,62 @@ void MICS4514Component::update() { if (this->carbon_monoxide_sensor_ != nullptr) { float co = 0.0f; - if (red_f <= 0.425f) { - co = (0.425f - red_f) / 0.000405f; - if (co < 1.0f) - co = 0.0f; - if (co > 1000.0f) - co = 1000.0f; + if (red_f > 3.4f) { + co = 0.0; + } else if (red_f < 0.01) { + co = 1000.0; + } else { + co = 4.2 / pow(red_f, 1.2); } this->carbon_monoxide_sensor_->publish_state(co); } if (this->nitrogen_dioxide_sensor_ != nullptr) { float nitrogendioxide = 0.0f; - if (ox_f >= 1.1f) { - nitrogendioxide = (ox_f - 0.045f) / 6.13f; - if (nitrogendioxide < 0.1f) - nitrogendioxide = 0.0f; - if (nitrogendioxide > 10.0f) - nitrogendioxide = 10.0f; + if (ox_f < 0.3f) { + nitrogendioxide = 0.0; + } else { + nitrogendioxide = 0.164 * pow(ox_f, 0.975); } this->nitrogen_dioxide_sensor_->publish_state(nitrogendioxide); } if (this->methane_sensor_ != nullptr) { float methane = 0.0f; - if (red_f <= 0.786f) { - methane = (0.786f - red_f) / 0.000023f; - if (methane < 1000.0f) - methane = 0.0f; - if (methane > 25000.0f) - methane = 25000.0f; + if (red_f > 0.9f || red_f < 0.5) { // outside the range->unlikely + methane = 0.0; + } else { + methane = 630 / pow(red_f, 4.4); } this->methane_sensor_->publish_state(methane); } if (this->ethanol_sensor_ != nullptr) { float ethanol = 0.0f; - if (red_f <= 0.306f) { - ethanol = (0.306f - red_f) / 0.00057f; - if (ethanol < 10.0f) - ethanol = 0.0f; - if (ethanol > 500.0f) - ethanol = 500.0f; + if (red_f > 1.0f || red_f < 0.02) { // outside the range->unlikely + ethanol = 0.0; + } else { + ethanol = 1.52 / pow(red_f, 1.55); } this->ethanol_sensor_->publish_state(ethanol); } if (this->hydrogen_sensor_ != nullptr) { float hydrogen = 0.0f; - if (red_f <= 0.279f) { - hydrogen = (0.279f - red_f) / 0.00026f; - if (hydrogen < 1.0f) - hydrogen = 0.0f; - if (hydrogen > 1000.0f) - hydrogen = 1000.0f; + if (red_f > 0.9f || red_f < 0.02) { // outside the range->unlikely + hydrogen = 0.0; + } else { + hydrogen = 0.85 / pow(red_f, 1.75); } this->hydrogen_sensor_->publish_state(hydrogen); } if (this->ammonia_sensor_ != nullptr) { float ammonia = 0.0f; - if (red_f <= 0.8f) { - ammonia = (0.8f - red_f) / 0.0015f; - if (ammonia < 1.0f) - ammonia = 0.0f; - if (ammonia > 500.0f) - ammonia = 500.0f; + if (red_f > 0.98f || red_f < 0.2532) { // outside the ammonia range->unlikely + ammonia = 0.0; + } else { + ammonia = 0.9 / pow(red_f, 4.6); } this->ammonia_sensor_->publish_state(ammonia); } From 721b532d71b4ca82c811e3db3b3e189e134704d8 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Fri, 30 Aug 2024 02:53:34 +0200 Subject: [PATCH 2316/2607] Tuya Number: allow restoring value of hidden datapoints (#7346) --- esphome/components/tuya/number/__init__.py | 3 ++ .../components/tuya/number/tuya_number.cpp | 45 +++++++++++++++++-- esphome/components/tuya/number/tuya_number.h | 9 +++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/esphome/components/tuya/number/__init__.py b/esphome/components/tuya/number/__init__.py index 25be6329ab..c00ea08d23 100644 --- a/esphome/components/tuya/number/__init__.py +++ b/esphome/components/tuya/number/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_MULTIPLY, CONF_STEP, CONF_INITIAL_VALUE, + CONF_RESTORE_VALUE, ) from .. import tuya_ns, CONF_TUYA_ID, Tuya, TuyaDatapointType @@ -58,6 +59,7 @@ CONFIG_SCHEMA = cv.All( DATAPOINT_TYPES, lower=True ), cv.Optional(CONF_INITIAL_VALUE): cv.float_, + cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, } ) ), @@ -90,3 +92,4 @@ async def to_code(config): hidden_init_value := hidden_config.get(CONF_INITIAL_VALUE, None) ) is not None: cg.add(var.set_datapoint_initial_value(hidden_init_value)) + cg.add(var.set_restore_value(hidden_config[CONF_RESTORE_VALUE])) diff --git a/esphome/components/tuya/number/tuya_number.cpp b/esphome/components/tuya/number/tuya_number.cpp index 7eeb08fde2..68a7f8f2a7 100644 --- a/esphome/components/tuya/number/tuya_number.cpp +++ b/esphome/components/tuya/number/tuya_number.cpp @@ -7,14 +7,28 @@ namespace tuya { static const char *const TAG = "tuya.number"; void TuyaNumber::setup() { + if (this->restore_value_) { + this->pref_ = global_preferences->make_preference(this->get_object_id_hash()); + } + this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { if (datapoint.type == TuyaDatapointType::INTEGER) { ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); - this->publish_state(datapoint.value_int / multiply_by_); + float value = datapoint.value_int / multiply_by_; + this->publish_state(value); + if (this->restore_value_) + this->pref_.save(&value); } else if (datapoint.type == TuyaDatapointType::ENUM) { ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); - this->publish_state(datapoint.value_enum); + float value = datapoint.value_enum; + this->publish_state(value); + if (this->restore_value_) + this->pref_.save(&value); + } else { + ESP_LOGW(TAG, "Reported type (%d) is not a number!", static_cast(datapoint.type)); + return; } + if ((this->type_) && (this->type_ != datapoint.type)) { ESP_LOGW(TAG, "Reported type (%d) different than previously set (%d)!", static_cast(datapoint.type), static_cast(*this->type_)); @@ -23,8 +37,26 @@ void TuyaNumber::setup() { }); this->parent_->add_on_initialized_callback([this] { - if ((this->initial_value_) && (this->type_)) { - this->control(*this->initial_value_); + if (this->type_) { + float value; + if (!this->restore_value_) { + if (this->initial_value_) { + value = *this->initial_value_; + } else { + return; + } + } else { + if (!this->pref_.load(&value)) { + if (this->initial_value_) { + value = *this->initial_value_; + } else { + value = this->traits.get_min_value(); + ESP_LOGW(TAG, "Failed to restore and there is no initial value defined. Setting min_value (%f)", value); + } + } + } + + this->control(value); } }); } @@ -38,6 +70,9 @@ void TuyaNumber::control(float value) { this->parent_->set_enum_datapoint_value(this->number_id_, value); } this->publish_state(value); + + if (this->restore_value_) + this->pref_.save(&value); } void TuyaNumber::dump_config() { @@ -52,6 +87,8 @@ void TuyaNumber::dump_config() { if (this->initial_value_) { ESP_LOGCONFIG(TAG, " Initial Value: %f", *this->initial_value_); } + + ESP_LOGCONFIG(TAG, " Restore Value: %s", YESNO(this->restore_value_)); } } // namespace tuya diff --git a/esphome/components/tuya/number/tuya_number.h b/esphome/components/tuya/number/tuya_number.h index 545584128e..53137d6f66 100644 --- a/esphome/components/tuya/number/tuya_number.h +++ b/esphome/components/tuya/number/tuya_number.h @@ -1,9 +1,10 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/components/tuya/tuya.h" #include "esphome/components/number/number.h" +#include "esphome/components/tuya/tuya.h" +#include "esphome/core/component.h" #include "esphome/core/optional.h" +#include "esphome/core/preferences.h" namespace esphome { namespace tuya { @@ -16,6 +17,7 @@ class TuyaNumber : public number::Number, public Component { void set_write_multiply(float factor) { multiply_by_ = factor; } void set_datapoint_type(TuyaDatapointType type) { type_ = type; } void set_datapoint_initial_value(float value) { this->initial_value_ = value; } + void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } @@ -27,6 +29,9 @@ class TuyaNumber : public number::Number, public Component { float multiply_by_{1.0}; optional type_{}; optional initial_value_{}; + bool restore_value_{false}; + + ESPPreferenceObject pref_; }; } // namespace tuya From ba6963cf72811cd75d4cd5510d1b81378c049ded Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:59:55 +1000 Subject: [PATCH 2317/2607] [udp] Implement UDP sensor broadcast (#6865) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: clydebarrow <366188+clydebarrow@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/udp/__init__.py | 158 +++++ esphome/components/udp/binary_sensor.py | 27 + esphome/components/udp/sensor.py | 27 + esphome/components/udp/udp_component.cpp | 616 ++++++++++++++++++++ esphome/components/udp/udp_component.h | 158 +++++ tests/components/udp/common.yaml | 35 ++ tests/components/udp/test.bk72xx-ard.yaml | 1 + tests/components/udp/test.esp32-ard.yaml | 1 + tests/components/udp/test.esp32-c3-ard.yaml | 1 + tests/components/udp/test.esp32-c3-idf.yaml | 1 + tests/components/udp/test.esp32-idf.yaml | 1 + tests/components/udp/test.esp8266-ard.yaml | 1 + tests/components/udp/test.host.yaml | 4 + tests/components/udp/test.rp2040-ard.yaml | 1 + 15 files changed, 1033 insertions(+) create mode 100644 esphome/components/udp/__init__.py create mode 100644 esphome/components/udp/binary_sensor.py create mode 100644 esphome/components/udp/sensor.py create mode 100644 esphome/components/udp/udp_component.cpp create mode 100644 esphome/components/udp/udp_component.h create mode 100644 tests/components/udp/common.yaml create mode 100644 tests/components/udp/test.bk72xx-ard.yaml create mode 100644 tests/components/udp/test.esp32-ard.yaml create mode 100644 tests/components/udp/test.esp32-c3-ard.yaml create mode 100644 tests/components/udp/test.esp32-c3-idf.yaml create mode 100644 tests/components/udp/test.esp32-idf.yaml create mode 100644 tests/components/udp/test.esp8266-ard.yaml create mode 100644 tests/components/udp/test.host.yaml create mode 100644 tests/components/udp/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 40511e2f41..807829eafd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -423,6 +423,7 @@ esphome/components/tuya/switch/* @jesserockz esphome/components/tuya/text_sensor/* @dentra esphome/components/uart/* @esphome/core esphome/components/uart/button/* @ssieb +esphome/components/udp/* @clydebarrow esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ise/* @pvizeli esphome/components/ultrasonic/* @OttoWinter diff --git a/esphome/components/udp/__init__.py b/esphome/components/udp/__init__.py new file mode 100644 index 0000000000..ca15be2a80 --- /dev/null +++ b/esphome/components/udp/__init__.py @@ -0,0 +1,158 @@ +import hashlib + +import esphome.codegen as cg +from esphome.components.api import CONF_ENCRYPTION +from esphome.components.binary_sensor import BinarySensor +from esphome.components.sensor import Sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_BINARY_SENSORS, + CONF_ID, + CONF_INTERNAL, + CONF_KEY, + CONF_NAME, + CONF_PORT, + CONF_SENSORS, +) +from esphome.cpp_generator import MockObjClass + +CODEOWNERS = ["@clydebarrow"] +DEPENDENCIES = ["network"] +AUTO_LOAD = ["socket"] +MULTI_CONF = True + +udp_ns = cg.esphome_ns.namespace("udp") +UDPComponent = udp_ns.class_("UDPComponent", cg.PollingComponent) + +CONF_BROADCAST = "broadcast" +CONF_BROADCAST_ID = "broadcast_id" +CONF_ADDRESSES = "addresses" +CONF_PROVIDER = "provider" +CONF_PROVIDERS = "providers" +CONF_REMOTE_ID = "remote_id" +CONF_UDP_ID = "udp_id" +CONF_PING_PONG_ENABLE = "ping_pong_enable" +CONF_PING_PONG_RECYCLE_TIME = "ping_pong_recycle_time" +CONF_ROLLING_CODE_ENABLE = "rolling_code_enable" + + +def sensor_validation(cls: MockObjClass): + return cv.maybe_simple_value( + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(cls), + cv.Optional(CONF_BROADCAST_ID): cv.validate_id_name, + } + ), + key=CONF_ID, + ) + + +ENCRYPTION_SCHEMA = { + cv.Optional(CONF_ENCRYPTION): cv.maybe_simple_value( + cv.Schema( + { + cv.Required(CONF_KEY): cv.string, + } + ), + key=CONF_KEY, + ) +} + +PROVIDER_SCHEMA = cv.Schema( + { + cv.Required(CONF_NAME): cv.valid_name, + } +).extend(ENCRYPTION_SCHEMA) + + +def validate_(config): + if CONF_ENCRYPTION in config: + if CONF_SENSORS not in config and CONF_BINARY_SENSORS not in config: + raise cv.Invalid("No sensors or binary sensors to encrypt") + elif config[CONF_ROLLING_CODE_ENABLE]: + raise cv.Invalid("Rolling code requires an encryption key") + if config[CONF_PING_PONG_ENABLE]: + if not any(CONF_ENCRYPTION in p for p in config.get(CONF_PROVIDERS) or ()): + raise cv.Invalid("Ping-pong requires at least one encrypted provider") + return config + + +CONFIG_SCHEMA = cv.All( + cv.polling_component_schema("15s") + .extend( + { + cv.GenerateID(): cv.declare_id(UDPComponent), + cv.Optional(CONF_PORT, default=18511): cv.port, + cv.Optional(CONF_ADDRESSES, default=["255.255.255.255"]): cv.ensure_list( + cv.ipv4 + ), + cv.Optional(CONF_ROLLING_CODE_ENABLE, default=False): cv.boolean, + cv.Optional(CONF_PING_PONG_ENABLE, default=False): cv.boolean, + cv.Optional( + CONF_PING_PONG_RECYCLE_TIME, default="600s" + ): cv.positive_time_period_seconds, + cv.Optional(CONF_SENSORS): cv.ensure_list(sensor_validation(Sensor)), + cv.Optional(CONF_BINARY_SENSORS): cv.ensure_list( + sensor_validation(BinarySensor) + ), + cv.Optional(CONF_PROVIDERS): cv.ensure_list(PROVIDER_SCHEMA), + }, + ) + .extend(ENCRYPTION_SCHEMA), + validate_, +) + +SENSOR_SCHEMA = cv.Schema( + { + cv.Optional(CONF_REMOTE_ID): cv.string_strict, + cv.Required(CONF_PROVIDER): cv.valid_name, + cv.GenerateID(CONF_UDP_ID): cv.use_id(UDPComponent), + } +) + + +def require_internal_with_name(config): + if CONF_NAME in config and CONF_INTERNAL not in config: + raise cv.Invalid("Must provide internal: config when using name:") + return config + + +def hash_encryption_key(config: dict): + return list(hashlib.sha256(config[CONF_KEY].encode()).digest()) + + +async def to_code(config): + cg.add_define("USE_UDP") + cg.add_global(udp_ns.using) + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + cg.add(var.set_port(config[CONF_PORT])) + cg.add(var.set_rolling_code_enable(config[CONF_ROLLING_CODE_ENABLE])) + cg.add(var.set_ping_pong_enable(config[CONF_PING_PONG_ENABLE])) + cg.add( + var.set_ping_pong_recycle_time( + config[CONF_PING_PONG_RECYCLE_TIME].total_seconds + ) + ) + for sens_conf in config.get(CONF_SENSORS, ()): + sens_id = sens_conf[CONF_ID] + sensor = await cg.get_variable(sens_id) + bcst_id = sens_conf.get(CONF_BROADCAST_ID, sens_id.id) + cg.add(var.add_sensor(bcst_id, sensor)) + for sens_conf in config.get(CONF_BINARY_SENSORS, ()): + sens_id = sens_conf[CONF_ID] + sensor = await cg.get_variable(sens_id) + bcst_id = sens_conf.get(CONF_BROADCAST_ID, sens_id.id) + cg.add(var.add_binary_sensor(bcst_id, sensor)) + for address in config[CONF_ADDRESSES]: + cg.add(var.add_address(str(address))) + + if encryption := config.get(CONF_ENCRYPTION): + cg.add(var.set_encryption_key(hash_encryption_key(encryption))) + + for provider in config.get(CONF_PROVIDERS, ()): + name = provider[CONF_NAME] + cg.add(var.add_provider(name)) + if encryption := provider.get(CONF_ENCRYPTION): + cg.add(var.set_provider_encryption(name, hash_encryption_key(encryption))) diff --git a/esphome/components/udp/binary_sensor.py b/esphome/components/udp/binary_sensor.py new file mode 100644 index 0000000000..d90e495527 --- /dev/null +++ b/esphome/components/udp/binary_sensor.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +from esphome.config_validation import All, has_at_least_one_key +from esphome.const import CONF_ID + +from . import ( + CONF_PROVIDER, + CONF_REMOTE_ID, + CONF_UDP_ID, + SENSOR_SCHEMA, + require_internal_with_name, +) + +DEPENDENCIES = ["udp"] + +CONFIG_SCHEMA = All( + binary_sensor.binary_sensor_schema().extend(SENSOR_SCHEMA), + has_at_least_one_key(CONF_ID, CONF_REMOTE_ID), + require_internal_with_name, +) + + +async def to_code(config): + var = await binary_sensor.new_binary_sensor(config) + comp = await cg.get_variable(config[CONF_UDP_ID]) + remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID)) + cg.add(comp.add_remote_binary_sensor(config[CONF_PROVIDER], remote_id, var)) diff --git a/esphome/components/udp/sensor.py b/esphome/components/udp/sensor.py new file mode 100644 index 0000000000..860c277c44 --- /dev/null +++ b/esphome/components/udp/sensor.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +from esphome.components.sensor import new_sensor, sensor_schema +from esphome.config_validation import All, has_at_least_one_key +from esphome.const import CONF_ID + +from . import ( + CONF_PROVIDER, + CONF_REMOTE_ID, + CONF_UDP_ID, + SENSOR_SCHEMA, + require_internal_with_name, +) + +DEPENDENCIES = ["udp"] + +CONFIG_SCHEMA = All( + sensor_schema().extend(SENSOR_SCHEMA), + has_at_least_one_key(CONF_ID, CONF_REMOTE_ID), + require_internal_with_name, +) + + +async def to_code(config): + var = await new_sensor(config) + comp = await cg.get_variable(config[CONF_UDP_ID]) + remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID)) + cg.add(comp.add_remote_sensor(config[CONF_PROVIDER], remote_id, var)) diff --git a/esphome/components/udp/udp_component.cpp b/esphome/components/udp/udp_component.cpp new file mode 100644 index 0000000000..799ed813d3 --- /dev/null +++ b/esphome/components/udp/udp_component.cpp @@ -0,0 +1,616 @@ +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/components/network/util.h" +#include "udp_component.h" + +namespace esphome { +namespace udp { + +/** + * Structure of a data packet; everything is little-endian + * + * --- In clear text --- + * MAGIC_NUMBER: 16 bits + * host name length: 1 byte + * host name: (length) bytes + * padding: 0 or more null bytes to a 4 byte boundary + * + * --- Encrypted (if key set) ---- + * DATA_KEY: 1 byte: OR ROLLING_CODE_KEY: + * Rolling code (if enabled): 8 bytes + * Ping keys: if any + * repeat: + * PING_KEY: 1 byte + * ping code: 4 bytes + * Sensors: + * repeat: + * SENSOR_KEY: 1 byte + * float value: 4 bytes + * name length: 1 byte + * name + * Binary Sensors: + * repeat: + * BINARY_SENSOR_KEY: 1 byte + * bool value: 1 bytes + * name length: 1 byte + * name + * + * Padded to a 4 byte boundary with nulls + * + * Structure of a ping request packet: + * --- In clear text --- + * MAGIC_PING: 16 bits + * host name length: 1 byte + * host name: (length) bytes + * Ping key (4 bytes) + * + */ +static const char *const TAG = "udp"; + +/** + * XXTEA implementation, using 256 bit key. + */ + +static const uint32_t DELTA = 0x9e3779b9; +#define MX ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (k[(p ^ e) & 7] ^ z))) + +/** + * Encrypt a block of data in-place + */ + +static void xxtea_encrypt(uint32_t *v, size_t n, const uint32_t *k) { + uint32_t z, y, sum, e; + size_t p; + size_t q = 6 + 52 / n; + sum = 0; + z = v[n - 1]; + while (q-- != 0) { + sum += DELTA; + e = (sum >> 2); + for (p = 0; p != n - 1; p++) { + y = v[p + 1]; + z = v[p] += MX; + } + y = v[0]; + z = v[n - 1] += MX; + } +} + +static void xxtea_decrypt(uint32_t *v, size_t n, const uint32_t *k) { + uint32_t z, y, sum, e; + size_t p; + size_t q = 6 + 52 / n; + sum = q * DELTA; + y = v[0]; + while (q-- != 0) { + e = (sum >> 2); + for (p = n - 1; p != 0; p--) { + z = v[p - 1]; + y = v[p] -= MX; + } + z = v[n - 1]; + y = v[0] -= MX; + sum -= DELTA; + } +} + +inline static size_t round4(size_t value) { return (value + 3) & ~3; } + +union FuData { + uint32_t u32; + float f32; +}; + +static const size_t MAX_PACKET_SIZE = 508; +static const uint16_t MAGIC_NUMBER = 0x4553; +static const uint16_t MAGIC_PING = 0x5048; +static const uint32_t PREF_HASH = 0x45535043; +enum DataKey { + ZERO_FILL_KEY, + DATA_KEY, + SENSOR_KEY, + BINARY_SENSOR_KEY, + PING_KEY, + ROLLING_CODE_KEY, +}; + +static const size_t MAX_PING_KEYS = 4; + +static inline void add(std::vector &vec, uint32_t data) { + vec.push_back(data & 0xFF); + vec.push_back((data >> 8) & 0xFF); + vec.push_back((data >> 16) & 0xFF); + vec.push_back((data >> 24) & 0xFF); +} + +static inline uint32_t get_uint32(uint8_t *&buf) { + uint32_t data = *buf++; + data += *buf++ << 8; + data += *buf++ << 16; + data += *buf++ << 24; + return data; +} + +static inline uint16_t get_uint16(uint8_t *&buf) { + uint16_t data = *buf++; + data += *buf++ << 8; + return data; +} + +static inline void add(std::vector &vec, uint8_t data) { vec.push_back(data); } +static inline void add(std::vector &vec, uint16_t data) { + vec.push_back((uint8_t) data); + vec.push_back((uint8_t) (data >> 8)); +} +static inline void add(std::vector &vec, DataKey data) { vec.push_back(data); } +static void add(std::vector &vec, const char *str) { + auto len = strlen(str); + vec.push_back(len); + for (size_t i = 0; i != len; i++) { + vec.push_back(*str++); + } +} + +void UDPComponent::setup() { + this->name_ = App.get_name().c_str(); + if (strlen(this->name_) > 255) { + this->mark_failed(); + this->status_set_error("Device name exceeds 255 chars"); + return; + } + this->resend_ping_key_ = this->ping_pong_enable_; + // restore the upper 32 bits of the rolling code, increment and save. + this->pref_ = global_preferences->make_preference(PREF_HASH, true); + this->pref_.load(&this->rolling_code_[1]); + this->rolling_code_[1]++; + this->pref_.save(&this->rolling_code_[1]); + this->ping_key_ = random_uint32(); + ESP_LOGV(TAG, "Rolling code incremented, upper part now %u", (unsigned) this->rolling_code_[1]); +#ifdef USE_SENSOR + for (auto &sensor : this->sensors_) { + sensor.sensor->add_on_state_callback([this, &sensor](float x) { + this->updated_ = true; + sensor.updated = true; + }); + } +#endif +#ifdef USE_BINARY_SENSOR + for (auto &sensor : this->binary_sensors_) { + sensor.sensor->add_on_state_callback([this, &sensor](bool value) { + this->updated_ = true; + sensor.updated = true; + }); + } +#endif + this->should_send_ = this->ping_pong_enable_; +#ifdef USE_SENSOR + this->should_send_ |= !this->sensors_.empty(); +#endif +#ifdef USE_BINARY_SENSOR + this->should_send_ |= !this->binary_sensors_.empty(); +#endif + this->should_listen_ = !this->providers_.empty() || this->is_encrypted_(); + // initialise the header. This is invariant. + add(this->header_, MAGIC_NUMBER); + add(this->header_, this->name_); + // pad to a multiple of 4 bytes + while (this->header_.size() & 0x3) + this->header_.push_back(0); +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + for (const auto &address : this->addresses_) { + struct sockaddr saddr {}; + socket::set_sockaddr(&saddr, sizeof(saddr), address, this->port_); + this->sockaddrs_.push_back(saddr); + } + // set up broadcast socket + if (this->should_send_) { + this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (this->broadcast_socket_ == nullptr) { + this->mark_failed(); + this->status_set_error("Could not create socket"); + return; + } + int enable = 1; + auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + if (err != 0) { + this->status_set_warning("Socket unable to set reuseaddr"); + // we can still continue + } + err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int)); + if (err != 0) { + this->status_set_warning("Socket unable to set broadcast"); + } + } + // create listening socket if we either want to subscribe to providers, or need to listen + // for ping key broadcasts. + if (this->should_listen_) { + this->listen_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (this->listen_socket_ == nullptr) { + this->mark_failed(); + this->status_set_error("Could not create socket"); + return; + } + auto err = this->listen_socket_->setblocking(false); + if (err < 0) { + ESP_LOGE(TAG, "Unable to set nonblocking: errno %d", errno); + this->mark_failed(); + this->status_set_error("Unable to set nonblocking"); + return; + } + int enable = 1; + err = this->listen_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + if (err != 0) { + this->status_set_warning("Socket unable to set reuseaddr"); + // we can still continue + } + struct sockaddr_in server {}; + + socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); + if (sl == 0) { + ESP_LOGE(TAG, "Socket unable to set sockaddr: errno %d", errno); + this->mark_failed(); + this->status_set_error("Unable to set sockaddr"); + return; + } + + err = this->listen_socket_->bind((struct sockaddr *) &server, sizeof(server)); + if (err != 0) { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + this->mark_failed(); + this->status_set_error("Unable to bind socket"); + return; + } + } +#else + // 8266 and RP2040 `Duino + for (const auto &address : this->addresses_) { + auto ipaddr = IPAddress(); + ipaddr.fromString(address.c_str()); + this->ipaddrs_.push_back(ipaddr); + } + if (this->should_listen_) + this->udp_client_.begin(this->port_); +#endif +} + +void UDPComponent::init_data_() { + this->data_.clear(); + if (this->rolling_code_enable_) { + add(this->data_, ROLLING_CODE_KEY); + add(this->data_, this->rolling_code_[0]); + add(this->data_, this->rolling_code_[1]); + this->increment_code_(); + } else { + add(this->data_, DATA_KEY); + } + for (auto pkey : this->ping_keys_) { + add(this->data_, PING_KEY); + add(this->data_, pkey.second); + } +} + +void UDPComponent::flush_() { + if (!network::is_connected() || this->data_.empty()) + return; + uint32_t buffer[MAX_PACKET_SIZE / 4]; + memset(buffer, 0, sizeof buffer); + // len must be a multiple of 4 + auto header_len = round4(this->header_.size()) / 4; + auto len = round4(data_.size()) / 4; + memcpy(buffer, this->header_.data(), this->header_.size()); + memcpy(buffer + header_len, this->data_.data(), this->data_.size()); + if (this->is_encrypted_()) { + xxtea_encrypt(buffer + header_len, len, (uint32_t *) this->encryption_key_.data()); + } + auto total_len = (header_len + len) * 4; + this->send_packet_(buffer, total_len); +} + +void UDPComponent::add_binary_data_(uint8_t key, const char *id, bool data) { + auto len = 1 + 1 + 1 + strlen(id); + if (len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) { + this->flush_(); + } + add(this->data_, key); + add(this->data_, (uint8_t) data); + add(this->data_, id); +} +void UDPComponent::add_data_(uint8_t key, const char *id, float data) { + FuData udata{.f32 = data}; + this->add_data_(key, id, udata.u32); +} + +void UDPComponent::add_data_(uint8_t key, const char *id, uint32_t data) { + auto len = 4 + 1 + 1 + strlen(id); + if (len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) { + this->flush_(); + } + add(this->data_, key); + add(this->data_, data); + add(this->data_, id); +} +void UDPComponent::send_data_(bool all) { + if (!this->should_send_ || !network::is_connected()) + return; + this->init_data_(); +#ifdef USE_SENSOR + for (auto &sensor : this->sensors_) { + if (all || sensor.updated) { + sensor.updated = false; + this->add_data_(SENSOR_KEY, sensor.id, sensor.sensor->get_state()); + } + } +#endif +#ifdef USE_BINARY_SENSOR + for (auto &sensor : this->binary_sensors_) { + if (all || sensor.updated) { + sensor.updated = false; + this->add_binary_data_(BINARY_SENSOR_KEY, sensor.id, sensor.sensor->state); + } + } +#endif + this->flush_(); + this->updated_ = false; + this->resend_data_ = false; +} + +void UDPComponent::update() { + this->updated_ = true; + this->resend_data_ = this->should_send_; + auto now = millis() / 1000; + if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) { + this->resend_ping_key_ = this->ping_pong_enable_; + this->last_key_time_ = now; + } +} + +void UDPComponent::loop() { + uint8_t buf[MAX_PACKET_SIZE]; + if (this->should_listen_) { + for (;;) { +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + auto len = this->listen_socket_->read(buf, sizeof(buf)); +#else + auto len = this->udp_client_.parsePacket(); + if (len > 0) + len = this->udp_client_.read(buf, sizeof(buf)); +#endif + if (len > 0) { + this->process_(buf, len); + continue; + } + break; + } + } + if (this->resend_ping_key_) + this->send_ping_pong_request_(); + if (this->updated_) { + this->send_data_(this->resend_data_); + } +} + +void UDPComponent::add_key_(const char *name, uint32_t key) { + if (!this->is_encrypted_()) + return; + if (this->ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) { + ESP_LOGW(TAG, "Ping key from %s discarded", name); + return; + } + this->ping_keys_[name] = key; + this->resend_data_ = true; + ESP_LOGV(TAG, "Ping key from %s now %X", name, (unsigned) key); +} + +void UDPComponent::process_ping_request_(const char *name, uint8_t *ptr, size_t len) { + if (len != 4) { + ESP_LOGW(TAG, "Bad ping request"); + return; + } + auto key = get_uint32(ptr); + this->add_key_(name, key); + ESP_LOGV(TAG, "Updated ping key for %s to %08X", name, (unsigned) key); +} + +static bool process_rolling_code(Provider &provider, uint8_t *&buf, const uint8_t *end) { + if (end - buf < 8) + return false; + auto code0 = get_uint32(buf); + auto code1 = get_uint32(buf); + if (code1 < provider.last_code[1] || (code1 == provider.last_code[1] && code0 <= provider.last_code[0])) { + ESP_LOGW(TAG, "Rolling code for %s %08lX:%08lX is old", provider.name, (unsigned long) code1, + (unsigned long) code0); + return false; + } + provider.last_code[0] = code0; + provider.last_code[1] = code1; + return true; +} + +/** + * Process a received packet + */ +void UDPComponent::process_(uint8_t *buf, const size_t len) { + auto ping_key_seen = !this->ping_pong_enable_; + if (len < 8) { + return ESP_LOGV(TAG, "Bad length %zu", len); + } + char namebuf[256]{}; + uint8_t byte; + uint8_t *start_ptr = buf; + const uint8_t *end = buf + len; + FuData rdata{}; + auto magic = get_uint16(buf); + if (magic != MAGIC_NUMBER && magic != MAGIC_PING) + return ESP_LOGV(TAG, "Bad magic %X", magic); + + auto hlen = *buf++; + if (hlen > len - 3) { + return ESP_LOGV(TAG, "Bad hostname length %u > %zu", hlen, len - 3); + } + memcpy(namebuf, buf, hlen); + if (strcmp(this->name_, namebuf) == 0) { + return ESP_LOGV(TAG, "Ignoring our own data"); + } + buf += hlen; + if (magic == MAGIC_PING) + return this->process_ping_request_(namebuf, buf, end - buf); + if (round4(len) != len) { + return ESP_LOGW(TAG, "Bad length %zu", len); + } + hlen = round4(hlen + 3); + buf = start_ptr + hlen; + if (buf == end) { + return ESP_LOGV(TAG, "No data after header"); + } + + if (this->providers_.count(namebuf) == 0) { + return ESP_LOGVV(TAG, "Unknown hostname %s", namebuf); + } + auto &provider = this->providers_[namebuf]; + // if encryption not used with this host, ping check is pointless since it would be easily spoofed. + if (provider.encryption_key.empty()) + ping_key_seen = true; + + ESP_LOGV(TAG, "Found hostname %s", namebuf); +#ifdef USE_SENSOR + auto &sensors = this->remote_sensors_[namebuf]; +#endif +#ifdef USE_BINARY_SENSOR + auto &binary_sensors = this->remote_binary_sensors_[namebuf]; +#endif + + if (!provider.encryption_key.empty()) { + xxtea_decrypt((uint32_t *) buf, (end - buf) / 4, (uint32_t *) provider.encryption_key.data()); + } + byte = *buf++; + if (byte == ROLLING_CODE_KEY) { + if (!process_rolling_code(provider, buf, end)) + return; + } else if (byte != DATA_KEY) { + return ESP_LOGV(TAG, "Expected rolling_key or data_key, got %X", byte); + } + while (buf < end) { + byte = *buf++; + if (byte == ZERO_FILL_KEY) + continue; + if (byte == PING_KEY) { + if (end - buf < 4) { + return ESP_LOGV(TAG, "PING_KEY requires 4 more bytes"); + } + auto key = get_uint32(buf); + if (key == this->ping_key_) { + ping_key_seen = true; + ESP_LOGV(TAG, "Found good ping key %X", (unsigned) key); + } else { + ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key); + } + continue; + } + if (!ping_key_seen) { + ESP_LOGW(TAG, "Ping key not seen"); + this->resend_ping_key_ = true; + break; + } + if (byte == BINARY_SENSOR_KEY) { + if (end - buf < 3) { + return ESP_LOGV(TAG, "Binary sensor key requires at least 3 more bytes"); + } + rdata.u32 = *buf++; + } else if (byte == SENSOR_KEY) { + if (end - buf < 6) { + return ESP_LOGV(TAG, "Sensor key requires at least 6 more bytes"); + } + rdata.u32 = get_uint32(buf); + } else { + return ESP_LOGW(TAG, "Unknown key byte %X", byte); + } + + hlen = *buf++; + if (end - buf < hlen) { + return ESP_LOGV(TAG, "Name length of %u not available", hlen); + } + memset(namebuf, 0, sizeof namebuf); + memcpy(namebuf, buf, hlen); + ESP_LOGV(TAG, "Found sensor key %d, id %s, data %lX", byte, namebuf, (unsigned long) rdata.u32); + buf += hlen; +#ifdef USE_SENSOR + if (byte == SENSOR_KEY && sensors.count(namebuf) != 0) + sensors[namebuf]->publish_state(rdata.f32); +#endif +#ifdef USE_BINARY_SENSOR + if (byte == BINARY_SENSOR_KEY && binary_sensors.count(namebuf) != 0) + binary_sensors[namebuf]->publish_state(rdata.u32 != 0); +#endif + } +} + +void UDPComponent::dump_config() { + ESP_LOGCONFIG(TAG, "UDP:"); + ESP_LOGCONFIG(TAG, " Port: %u", this->port_); + ESP_LOGCONFIG(TAG, " Encrypted: %s", YESNO(this->is_encrypted_())); + ESP_LOGCONFIG(TAG, " Ping-pong: %s", YESNO(this->ping_pong_enable_)); + for (const auto &address : this->addresses_) + ESP_LOGCONFIG(TAG, " Address: %s", address.c_str()); +#ifdef USE_SENSOR + for (auto sensor : this->sensors_) + ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id); +#endif +#ifdef USE_BINARY_SENSOR + for (auto sensor : this->binary_sensors_) + ESP_LOGCONFIG(TAG, " Binary Sensor: %s", sensor.id); +#endif + for (const auto &host : this->providers_) { + ESP_LOGCONFIG(TAG, " Remote host: %s", host.first.c_str()); + ESP_LOGCONFIG(TAG, " Encrypted: %s", YESNO(!host.second.encryption_key.empty())); +#ifdef USE_SENSOR + for (const auto &sensor : this->remote_sensors_[host.first.c_str()]) + ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.first.c_str()); +#endif +#ifdef USE_BINARY_SENSOR + for (const auto &sensor : this->remote_binary_sensors_[host.first.c_str()]) + ESP_LOGCONFIG(TAG, " Binary Sensor: %s", sensor.first.c_str()); +#endif + } +} +void UDPComponent::increment_code_() { + if (this->rolling_code_enable_) { + if (++this->rolling_code_[0] == 0) { + this->rolling_code_[1]++; + this->pref_.save(&this->rolling_code_[1]); + } + } +} +void UDPComponent::send_packet_(void *data, size_t len) { +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + for (const auto &saddr : this->sockaddrs_) { + auto result = this->broadcast_socket_->sendto(data, len, 0, &saddr, sizeof(saddr)); + if (result < 0) + ESP_LOGW(TAG, "sendto() error %d", errno); + } +#else + auto iface = IPAddress(0, 0, 0, 0); + for (const auto &saddr : this->ipaddrs_) { + if (this->udp_client_.beginPacketMulticast(saddr, this->port_, iface, 128) != 0) { + this->udp_client_.write((const uint8_t *) data, len); + auto result = this->udp_client_.endPacket(); + if (result == 0) + ESP_LOGW(TAG, "udp.write() error"); + } + } +#endif +} + +void UDPComponent::send_ping_pong_request_() { + if (!this->ping_pong_enable_ || !network::is_connected()) + return; + this->ping_key_ = random_uint32(); + this->ping_header_.clear(); + add(this->ping_header_, MAGIC_PING); + add(this->ping_header_, this->name_); + add(this->ping_header_, this->ping_key_); + this->send_packet_(this->ping_header_.data(), this->ping_header_.size()); + this->resend_ping_key_ = false; + ESP_LOGV(TAG, "Sent new ping request %08X", (unsigned) this->ping_key_); +} +} // namespace udp +} // namespace esphome diff --git a/esphome/components/udp/udp_component.h b/esphome/components/udp/udp_component.h new file mode 100644 index 0000000000..69bf335a90 --- /dev/null +++ b/esphome/components/udp/udp_component.h @@ -0,0 +1,158 @@ +#pragma once + +#include "esphome/core/component.h" +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) +#include "esphome/components/socket/socket.h" +#else +#include +#endif +#include +#include + +namespace esphome { +namespace udp { + +struct Provider { + std::vector encryption_key; + const char *name; + uint32_t last_code[2]; +}; + +#ifdef USE_SENSOR +struct Sensor { + sensor::Sensor *sensor; + const char *id; + bool updated; +}; +#endif +#ifdef USE_BINARY_SENSOR +struct BinarySensor { + binary_sensor::BinarySensor *sensor; + const char *id; + bool updated; +}; +#endif + +class UDPComponent : public PollingComponent { + public: + void setup() override; + void loop() override; + void update() override; + void dump_config() override; + +#ifdef USE_SENSOR + void add_sensor(const char *id, sensor::Sensor *sensor) { + Sensor st{sensor, id, true}; + this->sensors_.push_back(st); + } + void add_remote_sensor(const char *hostname, const char *remote_id, sensor::Sensor *sensor) { + this->add_provider(hostname); + this->remote_sensors_[hostname][remote_id] = sensor; + } +#endif +#ifdef USE_BINARY_SENSOR + void add_binary_sensor(const char *id, binary_sensor::BinarySensor *sensor) { + BinarySensor st{sensor, id, true}; + this->binary_sensors_.push_back(st); + } + + void add_remote_binary_sensor(const char *hostname, const char *remote_id, binary_sensor::BinarySensor *sensor) { + this->add_provider(hostname); + this->remote_binary_sensors_[hostname][remote_id] = sensor; + } +#endif + void add_address(const char *addr) { this->addresses_.emplace_back(addr); } + void set_port(uint16_t port) { this->port_ = port; } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + + void add_provider(const char *hostname) { + if (this->providers_.count(hostname) == 0) { + Provider provider; + provider.encryption_key = std::vector{}; + provider.last_code[0] = 0; + provider.last_code[1] = 0; + provider.name = hostname; + this->providers_[hostname] = provider; +#ifdef USE_SENSOR + this->remote_sensors_[hostname] = std::map(); +#endif +#ifdef USE_BINARY_SENSOR + this->remote_binary_sensors_[hostname] = std::map(); +#endif + } + } + + void set_encryption_key(std::vector key) { this->encryption_key_ = std::move(key); } + void set_rolling_code_enable(bool enable) { this->rolling_code_enable_ = enable; } + void set_ping_pong_enable(bool enable) { this->ping_pong_enable_ = enable; } + void set_ping_pong_recycle_time(uint32_t recycle_time) { this->ping_pong_recyle_time_ = recycle_time; } + void set_provider_encryption(const char *name, std::vector key) { + this->providers_[name].encryption_key = std::move(key); + } + + protected: + void send_data_(bool all); + void process_(uint8_t *buf, size_t len); + void flush_(); + void add_data_(uint8_t key, const char *id, float data); + void add_data_(uint8_t key, const char *id, uint32_t data); + void increment_code_(); + void add_binary_data_(uint8_t key, const char *id, bool data); + void init_data_(); + + bool updated_{}; + uint16_t port_{18511}; + uint32_t ping_key_{}; + uint32_t rolling_code_[2]{}; + bool rolling_code_enable_{}; + bool ping_pong_enable_{}; + uint32_t ping_pong_recyle_time_{}; + uint32_t last_key_time_{}; + bool resend_ping_key_{}; + bool resend_data_{}; + bool should_send_{}; + const char *name_{}; + bool should_listen_{}; + ESPPreferenceObject pref_; + +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + std::unique_ptr broadcast_socket_ = nullptr; + std::unique_ptr listen_socket_ = nullptr; + std::vector sockaddrs_{}; +#else + std::vector ipaddrs_{}; + WiFiUDP udp_client_{}; +#endif + std::vector encryption_key_{}; + std::vector addresses_{}; + +#ifdef USE_SENSOR + std::vector sensors_{}; + std::map> remote_sensors_{}; +#endif +#ifdef USE_BINARY_SENSOR + std::vector binary_sensors_{}; + std::map> remote_binary_sensors_{}; +#endif + + std::map providers_{}; + std::vector ping_header_{}; + std::vector header_{}; + std::vector data_{}; + std::map ping_keys_{}; + void add_key_(const char *name, uint32_t key); + void send_ping_pong_request_(); + void send_packet_(void *data, size_t len); + void process_ping_request_(const char *name, uint8_t *ptr, size_t len); + + inline bool is_encrypted_() { return !this->encryption_key_.empty(); } +}; + +} // namespace udp +} // namespace esphome diff --git a/tests/components/udp/common.yaml b/tests/components/udp/common.yaml new file mode 100644 index 0000000000..3bdc19ece5 --- /dev/null +++ b/tests/components/udp/common.yaml @@ -0,0 +1,35 @@ +wifi: + ssid: MySSID + password: password1 + +udp: + update_interval: 5s + encryption: "our key goes here" + rolling_code_enable: true + ping_pong_enable: true + binary_sensors: + - binary_sensor_id1 + - id: binary_sensor_id1 + broadcast_id: other_id + sensors: + - sensor_id1 + - id: sensor_id1 + broadcast_id: other_id + providers: + - name: some-device-name + encryption: "their key goes here" + +sensor: + - platform: template + id: sensor_id1 + - platform: udp + provider: some-device-name + id: our_id + remote_id: some_sensor_id + +binary_sensor: + - platform: udp + provider: unencrypted-device + id: other_binary_sensor_id + - platform: template + id: binary_sensor_id1 diff --git a/tests/components/udp/test.bk72xx-ard.yaml b/tests/components/udp/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.bk72xx-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.esp32-ard.yaml b/tests/components/udp/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.esp32-c3-ard.yaml b/tests/components/udp/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.esp32-c3-idf.yaml b/tests/components/udp/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.esp32-idf.yaml b/tests/components/udp/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.esp8266-ard.yaml b/tests/components/udp/test.esp8266-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/udp/test.host.yaml b/tests/components/udp/test.host.yaml new file mode 100644 index 0000000000..e735c37e4d --- /dev/null +++ b/tests/components/udp/test.host.yaml @@ -0,0 +1,4 @@ +packages: + common: !include common.yaml + +wifi: !remove diff --git a/tests/components/udp/test.rp2040-ard.yaml b/tests/components/udp/test.rp2040-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/udp/test.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From ca2f25e73bc04858d488540373475e600542d415 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 1 Sep 2024 13:20:31 +0200 Subject: [PATCH 2318/2607] update logs for bluetooth proxy (#7382) --- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index f188439d0e..bd1c8b7ea4 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -54,6 +54,9 @@ bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_p } resp.advertisements.push_back(std::move(adv)); + + ESP_LOGV(TAG, "Proxying raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0], + result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5], length, result.rssi); } ESP_LOGV(TAG, "Proxying %d packets", count); this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); @@ -87,6 +90,8 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi void BluetoothProxy::dump_config() { ESP_LOGCONFIG(TAG, "Bluetooth Proxy:"); ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_)); + ESP_LOGCONFIG(TAG, " Connections: %d", this->connections_.size()); + ESP_LOGCONFIG(TAG, " Raw advertisements: %s", YESNO(this->raw_advertisements_)); } int BluetoothProxy::get_bluetooth_connections_free() { From 61223a3cc9df12d07e9c8e288a691ef5cc1b30fd Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 2 Sep 2024 06:45:40 +1000 Subject: [PATCH 2319/2607] [font] Make display an auto-load, not a dependency (#7366) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/display/__init__.py | 9 +++---- esphome/components/font/__init__.py | 33 +++++++++----------------- esphome/components/font/font.cpp | 5 ++-- esphome/components/font/font.h | 15 +++++++++--- esphome/core/defines.h | 1 + tests/components/font/test.host.yaml | 23 ++++++++++++++++++ 6 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 tests/components/font/test.host.yaml diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index c4bb12b75d..32a8b3b090 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -1,15 +1,15 @@ +from esphome import automation, core +from esphome.automation import maybe_simple_id import esphome.codegen as cg import esphome.config_validation as cv -from esphome import core, automation -from esphome.automation import maybe_simple_id from esphome.const import ( CONF_AUTO_CLEAR_ENABLED, + CONF_FROM, CONF_ID, CONF_LAMBDA, - CONF_PAGES, CONF_PAGE_ID, + CONF_PAGES, CONF_ROTATION, - CONF_FROM, CONF_TO, CONF_TRIGGER_ID, ) @@ -195,3 +195,4 @@ async def display_is_displaying_page_to_code(config, condition_id, template_arg, @coroutine_with_priority(100.0) async def to_code(config): cg.add_global(display_ns.using) + cg.add_define("USE_DISPLAY") diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 7e4674ffda..b5ed02e89a 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -1,43 +1,35 @@ +import functools import hashlib import logging - -import functools -from pathlib import Path import os +from pathlib import Path import re + from packaging import version import requests -from esphome import core -from esphome import external_files -import esphome.config_validation as cv +from esphome import core, external_files import esphome.codegen as cg -from esphome.helpers import ( - copy_file_if_changed, - cpp_string_escape, -) +import esphome.config_validation as cv from esphome.const import ( CONF_FAMILY, CONF_FILE, CONF_GLYPHS, CONF_ID, + CONF_PATH, CONF_RAW_DATA_ID, - CONF_TYPE, CONF_REFRESH, CONF_SIZE, - CONF_PATH, - CONF_WEIGHT, + CONF_TYPE, CONF_URL, + CONF_WEIGHT, ) -from esphome.core import ( - CORE, - HexInt, -) +from esphome.core import CORE, HexInt +from esphome.helpers import copy_file_if_changed, cpp_string_escape _LOGGER = logging.getLogger(__name__) DOMAIN = "font" -DEPENDENCIES = ["display"] MULTI_CONF = True CODEOWNERS = ["@esphome/core", "@clydebarrow"] @@ -400,10 +392,7 @@ class EFont: def convert_bitmap_to_pillow_font(filepath): - from PIL import ( - PcfFontFile, - BdfFontFile, - ) + from PIL import BdfFontFile, PcfFontFile local_bitmap_font_file = external_files.compute_local_file_dir( DOMAIN, diff --git a/esphome/components/font/font.cpp b/esphome/components/font/font.cpp index 3b62b8ca66..aeca0f5cc0 100644 --- a/esphome/components/font/font.cpp +++ b/esphome/components/font/font.cpp @@ -1,9 +1,8 @@ #include "font.h" +#include "esphome/core/color.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" -#include "esphome/core/color.h" -#include "esphome/components/display/display_buffer.h" namespace esphome { namespace font { @@ -68,6 +67,7 @@ int Font::match_next_glyph(const uint8_t *str, int *match_length) { return -1; return lo; } +#ifdef USE_DISPLAY void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) { *baseline = this->baseline_; *height = this->height_; @@ -164,6 +164,7 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo i += match_length; } } +#endif } // namespace font } // namespace esphome diff --git a/esphome/components/font/font.h b/esphome/components/font/font.h index 57002cf510..5cde694d91 100644 --- a/esphome/components/font/font.h +++ b/esphome/components/font/font.h @@ -1,8 +1,11 @@ #pragma once -#include "esphome/core/datatypes.h" #include "esphome/core/color.h" -#include "esphome/components/display/display_buffer.h" +#include "esphome/core/datatypes.h" +#include "esphome/core/defines.h" +#ifdef USE_DISPLAY +#include "esphome/components/display/display.h" +#endif namespace esphome { namespace font { @@ -38,7 +41,11 @@ class Glyph { const GlyphData *glyph_data_; }; -class Font : public display::BaseFont { +class Font +#ifdef USE_DISPLAY + : public display::BaseFont +#endif +{ public: /** Construct the font with the given glyphs. * @@ -50,9 +57,11 @@ class Font : public display::BaseFont { int match_next_glyph(const uint8_t *str, int *match_length); +#ifdef USE_DISPLAY void print(int x_start, int y_start, display::Display *display, Color color, const char *text, Color background) override; void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override; +#endif inline int get_baseline() { return this->baseline_; } inline int get_height() { return this->height_; } inline int get_bpp() { return this->bpp_; } diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 52cf7d4dd0..ffd5cc6f1b 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -28,6 +28,7 @@ #define USE_DATETIME_DATETIME #define USE_DATETIME_TIME #define USE_DEEP_SLEEP +#define USE_DISPLAY #define USE_EVENT #define USE_FAN #define USE_GRAPH diff --git a/tests/components/font/test.host.yaml b/tests/components/font/test.host.yaml new file mode 100644 index 0000000000..017328ec83 --- /dev/null +++ b/tests/components/font/test.host.yaml @@ -0,0 +1,23 @@ +font: + - file: "gfonts://Roboto" + id: roboto + size: 20 + glyphs: "0123456789." + extras: + - file: "gfonts://Roboto" + glyphs: ["\u00C4", "\u00C5", "\U000000C7"] + - file: "gfonts://Roboto" + id: roboto_web + size: 20 + - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft + size: 20 + - file: + type: web + url: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" + id: monocraft2 + size: 24 + - file: $component_dir/Monocraft.ttf + id: monocraft3 + size: 28 + From 3a7aabb2eb3fe58c2925cd3f5e1f605e15797b1a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:36:18 +1200 Subject: [PATCH 2320/2607] Bump Dockerfile dependencies (#7386) --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 16f37274c6..4393d5a447 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,8 +34,8 @@ RUN \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ git=1:2.39.2-1.1 \ - curl=7.88.1-10+deb12u6 \ - openssh-client=1:9.2p1-2+deb12u2 \ + curl=7.88.1-10+deb12u7 \ + openssh-client=1:9.2p1-2+deb12u3 \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ libmagic1=1:5.44-3 \ @@ -49,7 +49,7 @@ RUN \ zlib1g-dev=1:1.2.13.dfsg-1 \ libjpeg-dev=1:2.1.5-2 \ libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.13-1~deb12u1 \ + libssl-dev=3.0.14-1~deb12u1 \ libffi-dev=3.4.4-1 \ libopenjp2-7=2.5.0-2 \ libtiff6=4.5.0-6+deb12u1 \ From 6490fc9c620d602fae2957f31e2756be886354ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Skowro=C5=84ski?= Date: Mon, 2 Sep 2024 03:56:35 +0200 Subject: [PATCH 2321/2607] CH422G support (#7356) --- CODEOWNERS | 1 + esphome/components/ch422g/__init__.py | 67 ++++++++++ esphome/components/ch422g/ch422g.cpp | 122 ++++++++++++++++++ esphome/components/ch422g/ch422g.h | 70 ++++++++++ tests/components/ch422g/common.yaml | 20 +++ tests/components/ch422g/test.esp32-ard.yaml | 6 + .../components/ch422g/test.esp32-c3-ard.yaml | 6 + .../components/ch422g/test.esp32-c3-idf.yaml | 6 + tests/components/ch422g/test.esp32-idf.yaml | 6 + tests/components/ch422g/test.esp8266-ard.yaml | 6 + tests/components/ch422g/test.rp2040-ard.yaml | 6 + 11 files changed, 316 insertions(+) create mode 100644 esphome/components/ch422g/__init__.py create mode 100644 esphome/components/ch422g/ch422g.cpp create mode 100644 esphome/components/ch422g/ch422g.h create mode 100644 tests/components/ch422g/common.yaml create mode 100644 tests/components/ch422g/test.esp32-ard.yaml create mode 100644 tests/components/ch422g/test.esp32-c3-ard.yaml create mode 100644 tests/components/ch422g/test.esp32-c3-idf.yaml create mode 100644 tests/components/ch422g/test.esp32-idf.yaml create mode 100644 tests/components/ch422g/test.esp8266-ard.yaml create mode 100644 tests/components/ch422g/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 807829eafd..ab11086980 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -83,6 +83,7 @@ esphome/components/cap1188/* @mreditor97 esphome/components/captive_portal/* @OttoWinter esphome/components/ccs811/* @habbie esphome/components/cd74hc4067/* @asoehlke +esphome/components/ch422g/* @jesterret esphome/components/climate/* @esphome/core esphome/components/climate_ir/* @glmnet esphome/components/color_temperature/* @jesserockz diff --git a/esphome/components/ch422g/__init__.py b/esphome/components/ch422g/__init__.py new file mode 100644 index 0000000000..cf8b5f65d3 --- /dev/null +++ b/esphome/components/ch422g/__init__.py @@ -0,0 +1,67 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import i2c +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, + CONF_RESTORE_VALUE, +) + +CODEOWNERS = ["@jesterret"] +DEPENDENCIES = ["i2c"] +MULTI_CONF = True +ch422g_ns = cg.esphome_ns.namespace("ch422g") + +CH422GComponent = ch422g_ns.class_("CH422GComponent", cg.Component, i2c.I2CDevice) +CH422GGPIOPin = ch422g_ns.class_( + "CH422GGPIOPin", cg.GPIOPin, cg.Parented.template(CH422GComponent) +) + +CONF_CH422G = "ch422g" +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(CH422GComponent), + cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x24)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE])) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +CH422G_PIN_SCHEMA = pins.gpio_base_schema( + CH422GGPIOPin, + cv.int_range(min=0, max=7), + modes=[CONF_INPUT, CONF_OUTPUT], +).extend( + { + cv.Required(CONF_CH422G): cv.use_id(CH422GComponent), + } +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA) +async def ch422g_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_CH422G]) + + cg.add(var.set_parent(parent)) + + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/ch422g/ch422g.cpp b/esphome/components/ch422g/ch422g.cpp new file mode 100644 index 0000000000..25038991ed --- /dev/null +++ b/esphome/components/ch422g/ch422g.cpp @@ -0,0 +1,122 @@ +#include "ch422g.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace ch422g { + +const uint8_t CH422G_REG_IN = 0x26; +const uint8_t CH422G_REG_OUT = 0x38; +const uint8_t OUT_REG_DEFAULT_VAL = 0xdf; + +static const char *const TAG = "ch422g"; + +void CH422GComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up CH422G..."); + // Test to see if device exists + if (!this->read_inputs_()) { + ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_); + this->mark_failed(); + return; + } + + // restore defaults over whatever got saved on last boot + if (!this->restore_value_) { + this->write_output_(OUT_REG_DEFAULT_VAL); + } + + ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), + this->status_has_error()); +} + +void CH422GComponent::loop() { + // Clear all the previously read flags. + this->pin_read_cache_ = 0x00; +} + +void CH422GComponent::dump_config() { + ESP_LOGCONFIG(TAG, "CH422G:"); + LOG_I2C_DEVICE(this) + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with CH422G failed!"); + } +} + +// ch422g doesn't have any flag support (needs docs?) +void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {} + +bool CH422GComponent::digital_read(uint8_t pin) { + if (this->pin_read_cache_ == 0 || this->pin_read_cache_ & (1 << pin)) { + // Read values on first access or in case it's being read again in the same loop + this->read_inputs_(); + } + + this->pin_read_cache_ |= (1 << pin); + return this->state_mask_ & (1 << pin); +} + +void CH422GComponent::digital_write(uint8_t pin, bool value) { + if (value) { + this->write_output_(this->state_mask_ | (1 << pin)); + } else { + this->write_output_(this->state_mask_ & ~(1 << pin)); + } +} + +bool CH422GComponent::read_inputs_() { + if (this->is_failed()) { + return false; + } + + uint8_t temp = 0; + if ((this->last_error_ = this->read(&temp, 1)) != esphome::i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); + return false; + } + + uint8_t output = 0; + if ((this->last_error_ = this->bus_->read(CH422G_REG_IN, &output, 1)) != esphome::i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); + return false; + } + + this->state_mask_ = output; + this->status_clear_warning(); + + return true; +} + +bool CH422GComponent::write_output_(uint8_t value) { + const uint8_t temp = 1; + if ((this->last_error_ = this->write(&temp, 1, false)) != esphome::i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("write_output_(): I2C I/O error: %d", (int) this->last_error_).c_str()); + return false; + } + + uint8_t write_mask = value; + if ((this->last_error_ = this->bus_->write(CH422G_REG_OUT, &write_mask, 1)) != esphome::i2c::ERROR_OK) { + this->status_set_warning( + str_sprintf("write_output_(): I2C I/O error: %d for write_mask: %d", (int) this->last_error_, (int) write_mask) + .c_str()); + return false; + } + + this->state_mask_ = value; + this->status_clear_warning(); + return true; +} + +float CH422GComponent::get_setup_priority() const { return setup_priority::IO; } + +// Run our loop() method very early in the loop, so that we cache read values +// before other components call our digital_read() method. +float CH422GComponent::get_loop_priority() const { return 9.0f; } // Just after WIFI + +void CH422GGPIOPin::setup() { pin_mode(flags_); } +void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } +bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } + +void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } +std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); } + +} // namespace ch422g +} // namespace esphome diff --git a/esphome/components/ch422g/ch422g.h b/esphome/components/ch422g/ch422g.h new file mode 100644 index 0000000000..781df65437 --- /dev/null +++ b/esphome/components/ch422g/ch422g.h @@ -0,0 +1,70 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace ch422g { + +class CH422GComponent : public Component, public i2c::I2CDevice { + public: + CH422GComponent() = default; + + /// Check i2c availability and setup masks + void setup() override; + /// Poll for input changes periodically + void loop() override; + /// Helper function to read the value of a pin. + bool digital_read(uint8_t pin); + /// Helper function to write the value of a pin. + void digital_write(uint8_t pin, bool value); + /// Helper function to set the pin mode of a pin. + void pin_mode(uint8_t pin, gpio::Flags flags); + + float get_setup_priority() const override; + + float get_loop_priority() const override; + + void dump_config() override; + + void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } + + protected: + bool read_inputs_(); + + bool write_output_(uint8_t value); + + /// The mask to write as output state - 1 means HIGH, 0 means LOW + uint8_t state_mask_{0x00}; + /// Flags to check if read previously during this loop + uint8_t pin_read_cache_ = {0x00}; + /// Storage for last I2C error seen + esphome::i2c::ErrorCode last_error_; + /// Whether we want to override stored values on expander + bool restore_value_{false}; +}; + +/// Helper class to expose a CH422G pin as an internal input GPIO pin. +class CH422GGPIOPin : public GPIOPin { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + std::string dump_summary() const override; + + void set_parent(CH422GComponent *parent) { parent_ = parent; } + void set_pin(uint8_t pin) { pin_ = pin; } + void set_inverted(bool inverted) { inverted_ = inverted; } + void set_flags(gpio::Flags flags) { flags_ = flags; } + + protected: + CH422GComponent *parent_; + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +} // namespace ch422g +} // namespace esphome diff --git a/tests/components/ch422g/common.yaml b/tests/components/ch422g/common.yaml new file mode 100644 index 0000000000..02061bda59 --- /dev/null +++ b/tests/components/ch422g/common.yaml @@ -0,0 +1,20 @@ +ch422g: + - id: ch422g_hub + address: 0x24 + +binary_sensor: + - platform: gpio + id: ch422g_input + name: CH422G Binary Sensor + pin: + ch422g: ch422g_hub + number: 1 + mode: INPUT + inverted: true + - platform: gpio + id: ch422g_output + pin: + ch422g: ch422g_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/ch422g/test.esp32-ard.yaml b/tests/components/ch422g/test.esp32-ard.yaml new file mode 100644 index 0000000000..cd3f1bbeef --- /dev/null +++ b/tests/components/ch422g/test.esp32-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ch422g/test.esp32-c3-ard.yaml b/tests/components/ch422g/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..cd822cb308 --- /dev/null +++ b/tests/components/ch422g/test.esp32-c3-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ch422g/test.esp32-c3-idf.yaml b/tests/components/ch422g/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..cd822cb308 --- /dev/null +++ b/tests/components/ch422g/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ch422g/test.esp32-idf.yaml b/tests/components/ch422g/test.esp32-idf.yaml new file mode 100644 index 0000000000..cd3f1bbeef --- /dev/null +++ b/tests/components/ch422g/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ch422g/test.esp8266-ard.yaml b/tests/components/ch422g/test.esp8266-ard.yaml new file mode 100644 index 0000000000..cd822cb308 --- /dev/null +++ b/tests/components/ch422g/test.esp8266-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ch422g/test.rp2040-ard.yaml b/tests/components/ch422g/test.rp2040-ard.yaml new file mode 100644 index 0000000000..cd822cb308 --- /dev/null +++ b/tests/components/ch422g/test.rp2040-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ch422g + scl: 5 + sda: 4 + +<<: !include common.yaml From fc930327b48989eb31e1cb38f45b5aeafb09c042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Mon, 2 Sep 2024 04:30:13 +0200 Subject: [PATCH 2322/2607] [rpi_dpi_rgb] Add enable_pin and reset_display method to driver (#7383) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/rpi_dpi_rgb/display.py | 6 ++++++ esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp | 18 ++++++++++++++++++ esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h | 3 +++ 3 files changed, 27 insertions(+) diff --git a/esphome/components/rpi_dpi_rgb/display.py b/esphome/components/rpi_dpi_rgb/display.py index 969b9db78e..6cc8d2c27b 100644 --- a/esphome/components/rpi_dpi_rgb/display.py +++ b/esphome/components/rpi_dpi_rgb/display.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import display from esphome.const import ( + CONF_ENABLE_PIN, CONF_HSYNC_PIN, CONF_RESET_PIN, CONF_DATA_PINS, @@ -112,6 +113,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PCLK_PIN): pins.internal_gpio_output_pin_schema, cv.Required(CONF_HSYNC_PIN): pins.internal_gpio_output_pin_schema, cv.Required(CONF_VSYNC_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_HSYNC_PULSE_WIDTH, default=10): cv.int_, cv.Optional(CONF_HSYNC_BACK_PORCH, default=10): cv.int_, @@ -164,6 +166,10 @@ async def to_code(config): cg.add(var.add_data_pin(data_pin, index)) index += 1 + if enable_pin := config.get(CONF_ENABLE_PIN): + enable = await cg.gpio_pin_expression(enable_pin) + cg.add(var.set_enable_pin(enable)) + if reset_pin := config.get(CONF_RESET_PIN): reset = await cg.gpio_pin_expression(reset_pin) cg.add(var.set_reset_pin(reset)) diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp index 2ffdb3272a..f173a2ec44 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp @@ -104,12 +104,30 @@ void RpiDpiRgb::dump_config() { ESP_LOGCONFIG(TAG, " Height: %u", this->height_); ESP_LOGCONFIG(TAG, " Width: %u", this->width_); LOG_PIN(" DE Pin: ", this->de_pin_); + LOG_PIN(" Enable Pin: ", this->enable_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); for (size_t i = 0; i != data_pin_count; i++) ESP_LOGCONFIG(TAG, " Data pin %d: %s", i, (this->data_pins_[i])->dump_summary().c_str()); } +void RpiDpiRgb::reset_display_() const { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(false); + if (this->enable_pin_ != nullptr) { + this->enable_pin_->setup(); + this->enable_pin_->digital_write(false); + } + delay(1); + this->reset_pin_->digital_write(true); + if (this->enable_pin_ != nullptr) { + delay(11); + this->enable_pin_->digital_write(true); + } + } +} + } // namespace rpi_dpi_rgb } // namespace esphome diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h index 0319b46391..6d9d6d4ae9 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h @@ -36,6 +36,7 @@ class RpiDpiRgb : public display::Display { void set_pclk_pin(InternalGPIOPin *pclk_pin) { this->pclk_pin_ = pclk_pin; } void set_vsync_pin(InternalGPIOPin *vsync_pin) { this->vsync_pin_ = vsync_pin; } void set_hsync_pin(InternalGPIOPin *hsync_pin) { this->hsync_pin_ = hsync_pin; } + void set_enable_pin(GPIOPin *enable_pin) { this->enable_pin_ = enable_pin; } void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_width(uint16_t width) { this->width_ = width; } void set_dimensions(uint16_t width, uint16_t height) { @@ -62,10 +63,12 @@ class RpiDpiRgb : public display::Display { protected: int get_width_internal() override { return this->width_; } int get_height_internal() override { return this->height_; } + void reset_display_() const; InternalGPIOPin *de_pin_{nullptr}; InternalGPIOPin *pclk_pin_{nullptr}; InternalGPIOPin *hsync_pin_{nullptr}; InternalGPIOPin *vsync_pin_{nullptr}; + GPIOPin *enable_pin_{nullptr}; GPIOPin *reset_pin_{nullptr}; InternalGPIOPin *data_pins_[16] = {}; uint16_t hsync_front_porch_ = 8; From 094c867fba5e329af1f6795318dee1936ccf5b35 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 2 Sep 2024 04:32:34 +0200 Subject: [PATCH 2323/2607] Enable IPv6 when manual IPv4 is enabled (#7381) --- esphome/components/ethernet/ethernet_component.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 962a864a29..fdb6eb2da0 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -472,13 +472,13 @@ void EthernetComponent::start_connect_() { if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) { ESPHL_ERROR_CHECK(err, "DHCPC start error"); } -#if USE_NETWORK_IPV6 - err = esp_netif_create_ip6_linklocal(this->eth_netif_); - if (err != ESP_OK) { - ESPHL_ERROR_CHECK(err, "Enable IPv6 link local failed"); - } -#endif /* USE_NETWORK_IPV6 */ } +#if USE_NETWORK_IPV6 + err = esp_netif_create_ip6_linklocal(this->eth_netif_); + if (err != ESP_OK) { + ESPHL_ERROR_CHECK(err, "Enable IPv6 link local failed"); + } +#endif /* USE_NETWORK_IPV6 */ this->connect_begin_ = millis(); this->status_set_warning(); From 854bafbd4a86316168717af4c1ebc72b55da48a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:33:58 +1200 Subject: [PATCH 2324/2607] Bump actions/upload-artifact from 4.3.4 to 4.4.0 (#7379) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 937c7aac90..7895e7624a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,7 +141,7 @@ jobs: echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT - name: Upload digests - uses: actions/upload-artifact@v4.3.4 + uses: actions/upload-artifact@v4.4.0 with: name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests From ca8e45cf4c35785ac4417a3349825d26e21ad305 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Sep 2024 19:11:21 +1200 Subject: [PATCH 2325/2607] [core] Only clean build files with esp-idf (#7388) --- esphome/storage_json.py | 16 ++++++++++++++++ esphome/writer.py | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/esphome/storage_json.py b/esphome/storage_json.py index e2e7514904..2d12ee01a0 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -48,6 +48,8 @@ class StorageJSON: firmware_bin_path: str, loaded_integrations: set[str], no_mdns: bool, + framework: str | None = None, + core_platform: str | None = None, ) -> None: # Version of the storage JSON schema assert storage_version is None or isinstance(storage_version, int) @@ -78,6 +80,10 @@ class StorageJSON: self.loaded_integrations = loaded_integrations # Is mDNS disabled self.no_mdns = no_mdns + # The framework used to compile the firmware + self.framework = framework + # The core platform of this firmware. Like "esp32", "rp2040", "host" etc. + self.core_platform = core_platform def as_dict(self): return { @@ -94,6 +100,8 @@ class StorageJSON: "firmware_bin_path": self.firmware_bin_path, "loaded_integrations": sorted(self.loaded_integrations), "no_mdns": self.no_mdns, + "framework": self.framework, + "core_platform": self.core_platform, } def to_json(self): @@ -127,6 +135,8 @@ class StorageJSON: and CONF_DISABLED in esph.config[CONF_MDNS] and esph.config[CONF_MDNS][CONF_DISABLED] is True ), + framework=esph.target_framework, + core_platform=esph.target_platform, ) @staticmethod @@ -147,6 +157,8 @@ class StorageJSON: firmware_bin_path=None, loaded_integrations=set(), no_mdns=False, + framework=None, + core_platform=platform.lower(), ) @staticmethod @@ -168,6 +180,8 @@ class StorageJSON: firmware_bin_path = storage.get("firmware_bin_path") loaded_integrations = set(storage.get("loaded_integrations", [])) no_mdns = storage.get("no_mdns", False) + framework = storage.get("framework") + core_platform = storage.get("core_platform") return StorageJSON( storage_version, name, @@ -182,6 +196,8 @@ class StorageJSON: firmware_bin_path, loaded_integrations, no_mdns, + framework, + core_platform, ) @staticmethod diff --git a/esphome/writer.py b/esphome/writer.py index 57435d3463..79ee72996c 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -9,6 +9,7 @@ from esphome.config import iter_component_configs, iter_components from esphome.const import ( ENV_NOGITIGNORE, HEADER_FILE_EXTENSIONS, + PLATFORM_ESP32, SOURCE_FILE_EXTENSIONS, __version__, ) @@ -107,7 +108,10 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool: if old.build_path != new.build_path: return True if old.loaded_integrations != new.loaded_integrations: - return True + if new.core_platform == PLATFORM_ESP32: + from esphome.components.esp32 import FRAMEWORK_ESP_IDF + + return new.framework == FRAMEWORK_ESP_IDF return False From 91c7c436827ef7c538b8ee1be74dd00a2179f2d6 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 2 Sep 2024 17:26:10 -0400 Subject: [PATCH 2326/2607] Fix build for esp32h2 using esp-idf 5.3 (#7393) --- esphome/components/debug/debug_esp32.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp index cfdfdd2a61..34aea9e26b 100644 --- a/esphome/components/debug/debug_esp32.cpp +++ b/esphome/components/debug/debug_esp32.cpp @@ -16,6 +16,8 @@ #include #elif defined(USE_ESP32_VARIANT_ESP32S3) #include +#elif defined(USE_ESP32_VARIANT_ESP32H2) +#include #endif #ifdef USE_ARDUINO #include @@ -61,7 +63,7 @@ std::string DebugComponent::get_reset_reason_() { case RTCWDT_SYS_RESET: reset_reason = "RTC Watch Dog Reset Digital Core"; break; -#if !defined(USE_ESP32_VARIANT_ESP32C6) +#if !defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32H2) case INTRUSION_RESET: reset_reason = "Intrusion Reset CPU"; break; From 816b060edcdf5c579b7df0c5a7fecf329c48759d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 29 Aug 2024 05:07:31 +1200 Subject: [PATCH 2327/2607] [datetime] Fix templated args (#7368) --- esphome/components/datetime/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 4fda97c5bc..5429121d56 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -186,7 +186,7 @@ async def datetime_date_set_to_code(config, action_id, template_arg, args): date_config = config[CONF_DATE] if cg.is_template(date_config): - template_ = await cg.templatable(date_config, [], cg.ESPTime) + template_ = await cg.templatable(date_config, args, cg.ESPTime) cg.add(action_var.set_date(template_)) else: date_struct = cg.StructInitializer( @@ -217,7 +217,7 @@ async def datetime_time_set_to_code(config, action_id, template_arg, args): time_config = config[CONF_TIME] if cg.is_template(time_config): - template_ = await cg.templatable(time_config, [], cg.ESPTime) + template_ = await cg.templatable(time_config, args, cg.ESPTime) cg.add(action_var.set_time(template_)) else: time_struct = cg.StructInitializer( @@ -248,7 +248,7 @@ async def datetime_datetime_set_to_code(config, action_id, template_arg, args): datetime_config = config[CONF_DATETIME] if cg.is_template(datetime_config): - template_ = await cg.templatable(datetime_config, [], cg.ESPTime) + template_ = await cg.templatable(datetime_config, args, cg.ESPTime) cg.add(action_var.set_datetime(template_)) else: datetime_struct = cg.StructInitializer( From 04ec6c5677201b47e74049509487e61b13bef246 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 2 Sep 2024 04:32:34 +0200 Subject: [PATCH 2328/2607] Enable IPv6 when manual IPv4 is enabled (#7381) --- esphome/components/ethernet/ethernet_component.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 962a864a29..fdb6eb2da0 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -472,13 +472,13 @@ void EthernetComponent::start_connect_() { if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) { ESPHL_ERROR_CHECK(err, "DHCPC start error"); } -#if USE_NETWORK_IPV6 - err = esp_netif_create_ip6_linklocal(this->eth_netif_); - if (err != ESP_OK) { - ESPHL_ERROR_CHECK(err, "Enable IPv6 link local failed"); - } -#endif /* USE_NETWORK_IPV6 */ } +#if USE_NETWORK_IPV6 + err = esp_netif_create_ip6_linklocal(this->eth_netif_); + if (err != ESP_OK) { + ESPHL_ERROR_CHECK(err, "Enable IPv6 link local failed"); + } +#endif /* USE_NETWORK_IPV6 */ this->connect_begin_ = millis(); this->status_set_warning(); From c9c5ca28d20f68f6412c0997c345217da2f971fd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Sep 2024 19:11:21 +1200 Subject: [PATCH 2329/2607] [core] Only clean build files with esp-idf (#7388) --- esphome/storage_json.py | 16 ++++++++++++++++ esphome/writer.py | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/esphome/storage_json.py b/esphome/storage_json.py index e2e7514904..2d12ee01a0 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -48,6 +48,8 @@ class StorageJSON: firmware_bin_path: str, loaded_integrations: set[str], no_mdns: bool, + framework: str | None = None, + core_platform: str | None = None, ) -> None: # Version of the storage JSON schema assert storage_version is None or isinstance(storage_version, int) @@ -78,6 +80,10 @@ class StorageJSON: self.loaded_integrations = loaded_integrations # Is mDNS disabled self.no_mdns = no_mdns + # The framework used to compile the firmware + self.framework = framework + # The core platform of this firmware. Like "esp32", "rp2040", "host" etc. + self.core_platform = core_platform def as_dict(self): return { @@ -94,6 +100,8 @@ class StorageJSON: "firmware_bin_path": self.firmware_bin_path, "loaded_integrations": sorted(self.loaded_integrations), "no_mdns": self.no_mdns, + "framework": self.framework, + "core_platform": self.core_platform, } def to_json(self): @@ -127,6 +135,8 @@ class StorageJSON: and CONF_DISABLED in esph.config[CONF_MDNS] and esph.config[CONF_MDNS][CONF_DISABLED] is True ), + framework=esph.target_framework, + core_platform=esph.target_platform, ) @staticmethod @@ -147,6 +157,8 @@ class StorageJSON: firmware_bin_path=None, loaded_integrations=set(), no_mdns=False, + framework=None, + core_platform=platform.lower(), ) @staticmethod @@ -168,6 +180,8 @@ class StorageJSON: firmware_bin_path = storage.get("firmware_bin_path") loaded_integrations = set(storage.get("loaded_integrations", [])) no_mdns = storage.get("no_mdns", False) + framework = storage.get("framework") + core_platform = storage.get("core_platform") return StorageJSON( storage_version, name, @@ -182,6 +196,8 @@ class StorageJSON: firmware_bin_path, loaded_integrations, no_mdns, + framework, + core_platform, ) @staticmethod diff --git a/esphome/writer.py b/esphome/writer.py index 57435d3463..79ee72996c 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -9,6 +9,7 @@ from esphome.config import iter_component_configs, iter_components from esphome.const import ( ENV_NOGITIGNORE, HEADER_FILE_EXTENSIONS, + PLATFORM_ESP32, SOURCE_FILE_EXTENSIONS, __version__, ) @@ -107,7 +108,10 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool: if old.build_path != new.build_path: return True if old.loaded_integrations != new.loaded_integrations: - return True + if new.core_platform == PLATFORM_ESP32: + from esphome.components.esp32 import FRAMEWORK_ESP_IDF + + return new.framework == FRAMEWORK_ESP_IDF return False From e5e06a12ef22aeec591880ec53de572bad1f8a3b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:57:28 +1200 Subject: [PATCH 2330/2607] Bump version to 2024.8.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index b27949bf29..00f2d6a13b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.1" +__version__ = "2024.8.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 01c50432c91b871a91a403778250d5b21121cd2a Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 3 Sep 2024 00:16:59 +0200 Subject: [PATCH 2331/2607] Bump mDNS and follow ruff's suggestions (#7308) --- esphome/components/mdns/__init__.py | 12 ++++++------ esphome/idf_component.yml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index fb90986314..dd68fbb93c 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -1,17 +1,17 @@ +import esphome.codegen as cg +from esphome.components.esp32 import add_idf_component +import esphome.config_validation as cv from esphome.const import ( + CONF_DISABLED, CONF_ID, CONF_PORT, CONF_PROTOCOL, - CONF_SERVICES, CONF_SERVICE, + CONF_SERVICES, KEY_CORE, KEY_FRAMEWORK_VERSION, - CONF_DISABLED, ) -import esphome.codegen as cg -import esphome.config_validation as cv from esphome.core import CORE, coroutine_with_priority -from esphome.components.esp32 import add_idf_component CODEOWNERS = ["@esphome/core"] DEPENDENCIES = ["network"] @@ -91,7 +91,7 @@ async def to_code(config): add_idf_component( name="mdns", repo="https://github.com/espressif/esp-protocols.git", - ref="mdns-v1.2.5", + ref="mdns-v1.3.2", path="components/mdns", ) diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml index 5f4701b5a3..c79ba1b0ed 100644 --- a/esphome/idf_component.yml +++ b/esphome/idf_component.yml @@ -7,7 +7,7 @@ dependencies: version: v2.0.9 mdns: git: https://github.com/espressif/esp-protocols.git - version: mdns-v1.2.5 + version: mdns-v1.3.2 path: components/mdns rules: - if: "idf_version >=5.0" From 29f0b504b9b5944d6b95d135d8ef973c57056604 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Tue, 3 Sep 2024 00:28:18 +0200 Subject: [PATCH 2332/2607] Bump rp2040 Arduino platform and framework (#7134) --- esphome/components/rp2040/__init__.py | 15 +++++++-------- platformio.ini | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index f5c3b8bda2..8f1d26f780 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -1,6 +1,5 @@ import logging import os - from string import ascii_letters, digits import esphome.codegen as cg @@ -8,6 +7,7 @@ import esphome.config_validation as cv from esphome.const import ( CONF_BOARD, CONF_FRAMEWORK, + CONF_PLATFORM_VERSION, CONF_SOURCE, CONF_VERSION, KEY_CORE, @@ -15,10 +15,9 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_RP2040, - CONF_PLATFORM_VERSION, ) -from esphome.core import CORE, coroutine_with_priority, EsphomeError -from esphome.helpers import mkdir_p, write_file, copy_file_if_changed +from esphome.core import CORE, EsphomeError, coroutine_with_priority +from esphome.helpers import copy_file_if_changed, mkdir_p, write_file from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns @@ -81,19 +80,19 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/earlephilhower/arduino-pico/releases # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 7, 2) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4) # The platformio/raspberrypi version to use for arduino frameworks # - https://github.com/platformio/platform-raspberrypi/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 12, 0) +ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0) def _arduino_check_versions(value): value = value.copy() lookups = { - "dev": (cv.Version(3, 4, 0), "https://github.com/earlephilhower/arduino-pico"), - "latest": (cv.Version(3, 4, 0), None), + "dev": (cv.Version(3, 9, 4), "https://github.com/earlephilhower/arduino-pico"), + "latest": (cv.Version(3, 9, 4), None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), } diff --git a/platformio.ini b/platformio.ini index 147159a841..ee18068a29 100644 --- a/platformio.ini +++ b/platformio.ini @@ -168,7 +168,7 @@ board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.7.2/rp2040-3.7.2.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip framework = arduino lib_deps = From 3b14b0efce1e9be58f5da6364713ff3d7a12d06d Mon Sep 17 00:00:00 2001 From: Dan Greco <21044725+dangreco@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:35:54 -0400 Subject: [PATCH 2333/2607] [gree] Add support for YX1FF remote (#7298) --- esphome/components/gree/climate.py | 3 +- esphome/components/gree/gree.cpp | 57 ++++++++++++++++++++++++++++-- esphome/components/gree/gree.h | 12 +++++-- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/esphome/components/gree/climate.py b/esphome/components/gree/climate.py index c88a428391..75436f2cf5 100644 --- a/esphome/components/gree/climate.py +++ b/esphome/components/gree/climate.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import climate_ir +import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODEL CODEOWNERS = ["@orestismers"] @@ -17,6 +17,7 @@ MODELS = { "yaa": Model.GREE_YAA, "yac": Model.GREE_YAC, "yac1fb9": Model.GREE_YAC1FB9, + "yx1ff": Model.GREE_YX1FF, } CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( diff --git a/esphome/components/gree/gree.cpp b/esphome/components/gree/gree.cpp index cce2a8ffee..6d179a947b 100644 --- a/esphome/components/gree/gree.cpp +++ b/esphome/components/gree/gree.cpp @@ -6,7 +6,15 @@ namespace gree { static const char *const TAG = "gree.climate"; -void GreeClimate::set_model(Model model) { this->model_ = model; } +void GreeClimate::set_model(Model model) { + if (model == GREE_YX1FF) { + this->fan_modes_.insert(climate::CLIMATE_FAN_QUIET); // YX1FF 4 speed + this->presets_.insert(climate::CLIMATE_PRESET_NONE); // YX1FF sleep mode + this->presets_.insert(climate::CLIMATE_PRESET_SLEEP); // YX1FF sleep mode + } + + this->model_ = model; +} void GreeClimate::transmit_state() { uint8_t remote_state[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00}; @@ -14,7 +22,7 @@ void GreeClimate::transmit_state() { remote_state[0] = this->fan_speed_() | this->operation_mode_(); remote_state[1] = this->temperature_(); - if (this->model_ == GREE_YAN) { + if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF) { remote_state[2] = 0x60; remote_state[3] = 0x50; remote_state[4] = this->vertical_swing_(); @@ -36,8 +44,18 @@ void GreeClimate::transmit_state() { } } + if (this->model_ == GREE_YX1FF) { + if (this->fan_speed_() == GREE_FAN_TURBO) { + remote_state[2] |= GREE_FAN_TURBO_BIT; + } + + if (this->preset_() == GREE_PRESET_SLEEP) { + remote_state[0] |= GREE_PRESET_SLEEP_BIT; + } + } + // Calculate the checksum - if (this->model_ == GREE_YAN) { + if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF) { remote_state[7] = ((remote_state[0] << 4) + (remote_state[1] << 4) + 0xC0); } else { remote_state[7] = @@ -124,6 +142,23 @@ uint8_t GreeClimate::operation_mode_() { } uint8_t GreeClimate::fan_speed_() { + // YX1FF has 4 fan speeds -- we treat low as quiet and turbo as high + if (this->model_ == GREE_YX1FF) { + switch (this->fan_mode.value()) { + case climate::CLIMATE_FAN_QUIET: + return GREE_FAN_1; + case climate::CLIMATE_FAN_LOW: + return GREE_FAN_2; + case climate::CLIMATE_FAN_MEDIUM: + return GREE_FAN_3; + case climate::CLIMATE_FAN_HIGH: + return GREE_FAN_TURBO; + case climate::CLIMATE_FAN_AUTO: + default: + return GREE_FAN_AUTO; + } + } + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_LOW: return GREE_FAN_1; @@ -161,5 +196,21 @@ uint8_t GreeClimate::temperature_() { return (uint8_t) roundf(clamp(this->target_temperature, GREE_TEMP_MIN, GREE_TEMP_MAX)); } +uint8_t GreeClimate::preset_() { + // YX1FF has sleep preset + if (this->model_ == GREE_YX1FF) { + switch (this->preset.value()) { + case climate::CLIMATE_PRESET_NONE: + return GREE_PRESET_NONE; + case climate::CLIMATE_PRESET_SLEEP: + return GREE_PRESET_SLEEP; + default: + return GREE_PRESET_NONE; + } + } + + return GREE_PRESET_NONE; +} + } // namespace gree } // namespace esphome diff --git a/esphome/components/gree/gree.h b/esphome/components/gree/gree.h index 524a95aebd..6762b41eb0 100644 --- a/esphome/components/gree/gree.h +++ b/esphome/components/gree/gree.h @@ -25,7 +25,6 @@ const uint8_t GREE_FAN_AUTO = 0x00; const uint8_t GREE_FAN_1 = 0x10; const uint8_t GREE_FAN_2 = 0x20; const uint8_t GREE_FAN_3 = 0x30; -const uint8_t GREE_FAN_TURBO = 0x80; // IR Transmission const uint32_t GREE_IR_FREQUENCY = 38000; @@ -70,8 +69,16 @@ const uint8_t GREE_HDIR_MIDDLE = 0x04; const uint8_t GREE_HDIR_MRIGHT = 0x05; const uint8_t GREE_HDIR_RIGHT = 0x06; +// Only available on YX1FF +// Turbo (high) fan mode + sleep preset mode +const uint8_t GREE_FAN_TURBO = 0x80; +const uint8_t GREE_FAN_TURBO_BIT = 0x10; +const uint8_t GREE_PRESET_NONE = 0x00; +const uint8_t GREE_PRESET_SLEEP = 0x01; +const uint8_t GREE_PRESET_SLEEP_BIT = 0x80; + // Model codes -enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9 }; +enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9, GREE_YX1FF }; class GreeClimate : public climate_ir::ClimateIR { public: @@ -93,6 +100,7 @@ class GreeClimate : public climate_ir::ClimateIR { uint8_t horizontal_swing_(); uint8_t vertical_swing_(); uint8_t temperature_(); + uint8_t preset_(); Model model_{}; }; From d6eeac06199e562d2d25deaf8bd7cfe1ec90605f Mon Sep 17 00:00:00 2001 From: Tercio Filho Date: Mon, 2 Sep 2024 20:56:19 -0300 Subject: [PATCH 2334/2607] [modbus_controller] Allow duplicate command config (#7311) --- .../components/modbus_controller/__init__.py | 3 +++ esphome/components/modbus_controller/const.py | 1 + .../modbus_controller/modbus_controller.cpp | 22 ++++++++++--------- .../modbus_controller/modbus_controller.h | 8 +++++++ .../modbus_controller/test.esp32-ard.yaml | 1 + .../modbus_controller/test.esp32-idf.yaml | 1 + 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 1d0f406783..8146124c28 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -13,6 +13,7 @@ from esphome.const import ( ) from esphome.cpp_helpers import logging from .const import ( + CONF_ALLOW_DUPLICATE_COMMANDS, CONF_BITMASK, CONF_BYTE_OFFSET, CONF_COMMAND_THROTTLE, @@ -126,6 +127,7 @@ CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(ModbusController), + cv.Optional(CONF_ALLOW_DUPLICATE_COMMANDS, default=False): cv.boolean, cv.Optional( CONF_COMMAND_THROTTLE, default="0ms" ): cv.positive_time_period_milliseconds, @@ -253,6 +255,7 @@ async def add_modbus_base_properties( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS])) cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE])) cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES])) if CONF_SERVER_REGISTERS in config: diff --git a/esphome/components/modbus_controller/const.py b/esphome/components/modbus_controller/const.py index 1f5c39895c..5d9a61dee7 100644 --- a/esphome/components/modbus_controller/const.py +++ b/esphome/components/modbus_controller/const.py @@ -1,3 +1,4 @@ +CONF_ALLOW_DUPLICATE_COMMANDS = "allow_duplicate_commands" CONF_BITMASK = "bitmask" CONF_BYTE_OFFSET = "byte_offset" CONF_COMMAND_THROTTLE = "command_throttle" diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 378e5c06c0..8f48847a4f 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -175,16 +175,18 @@ void ModbusController::on_register_data(ModbusRegisterType register_type, uint16 } void ModbusController::queue_command(const ModbusCommandItem &command) { - // check if this command is already qeued. - // not very effective but the queue is never really large - for (auto &item : command_queue_) { - if (item->is_equal(command)) { - ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u", - static_cast(command.register_type), command.register_address, command.register_count); - // update the payload of the queued command - // replaces a previous command - item->payload = command.payload; - return; + if (!this->allow_duplicate_commands_) { + // check if this command is already qeued. + // not very effective but the queue is never really large + for (auto &item : command_queue_) { + if (item->is_equal(command)) { + ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u", + static_cast(command.register_type), command.register_address, command.register_count); + // update the payload of the queued command + // replaces a previous command + item->payload = command.payload; + return; + } } } command_queue_.push_back(make_unique(command)); diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 3bc11da879..e88f4c07f7 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -448,6 +448,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { /// incoming queue void on_write_register_response(ModbusRegisterType register_type, uint16_t start_address, const std::vector &data); + /// Allow a duplicate command to be sent + void set_allow_duplicate_commands(bool allow_duplicate_commands) { + this->allow_duplicate_commands_ = allow_duplicate_commands; + } + /// get if a duplicate command can be sent + bool get_allow_duplicate_commands() { return this->allow_duplicate_commands_; } /// called by esphome generated code to set the command_throttle period void set_command_throttle(uint16_t command_throttle) { this->command_throttle_ = command_throttle; } /// called by esphome generated code to set the offline_skip_updates @@ -482,6 +488,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { std::list> command_queue_; /// modbus response data waiting to get processed std::queue> incoming_queue_; + /// if duplicate commands can be sent + bool allow_duplicate_commands_; /// when was the last send operation uint32_t last_command_timestamp_; /// min time in ms between sending modbus commands diff --git a/tests/components/modbus_controller/test.esp32-ard.yaml b/tests/components/modbus_controller/test.esp32-ard.yaml index 3e022b10ab..b6e38aeb9c 100644 --- a/tests/components/modbus_controller/test.esp32-ard.yaml +++ b/tests/components/modbus_controller/test.esp32-ard.yaml @@ -20,6 +20,7 @@ modbus_controller: - id: modbus_controller1 address: 0x2 modbus_id: mod_bus1 + allow_duplicate_commands: false - id: modbus_controller2 address: 0x2 modbus_id: mod_bus2 diff --git a/tests/components/modbus_controller/test.esp32-idf.yaml b/tests/components/modbus_controller/test.esp32-idf.yaml index c5fe3fd057..d5407ac406 100644 --- a/tests/components/modbus_controller/test.esp32-idf.yaml +++ b/tests/components/modbus_controller/test.esp32-idf.yaml @@ -12,3 +12,4 @@ modbus_controller: - id: modbus_controller1 address: 0x2 modbus_id: mod_bus1 + allow_duplicate_commands: true From f8ec5242c98649cb590e24667dd3791a5f6b6df1 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Mon, 2 Sep 2024 20:47:54 -0400 Subject: [PATCH 2335/2607] Better support for task blocking ring buffer reads and writes (#7390) --- esphome/core/ring_buffer.cpp | 15 ++++++++-- esphome/core/ring_buffer.h | 56 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/esphome/core/ring_buffer.cpp b/esphome/core/ring_buffer.cpp index 9bd3d9d853..d8ca831de0 100644 --- a/esphome/core/ring_buffer.cpp +++ b/esphome/core/ring_buffer.cpp @@ -20,13 +20,20 @@ std::unique_ptr RingBuffer::create(size_t len) { return nullptr; } - rb->handle_ = xStreamBufferCreateStatic(len + 1, 0, rb->storage_, &rb->structure_); + rb->handle_ = xStreamBufferCreateStatic(len + 1, 1, rb->storage_, &rb->structure_); ESP_LOGD(TAG, "Created ring buffer with size %u", len); return rb; } size_t RingBuffer::read(void *data, size_t len, TickType_t ticks_to_wait) { - return xStreamBufferReceive(this->handle_, data, len, ticks_to_wait); + if (ticks_to_wait > 0) + xStreamBufferSetTriggerLevel(this->handle_, len); + + size_t bytes_read = xStreamBufferReceive(this->handle_, data, len, ticks_to_wait); + + xStreamBufferSetTriggerLevel(this->handle_, 1); + + return bytes_read; } size_t RingBuffer::write(void *data, size_t len) { @@ -39,6 +46,10 @@ size_t RingBuffer::write(void *data, size_t len) { return xStreamBufferSend(this->handle_, data, len, 0); } +size_t RingBuffer::write_without_replacement(void *data, size_t len, TickType_t ticks_to_wait) { + return xStreamBufferSend(this->handle_, data, len, ticks_to_wait); +} + size_t RingBuffer::available() const { return xStreamBufferBytesAvailable(this->handle_); } size_t RingBuffer::free() const { return xStreamBufferSpacesAvailable(this->handle_); } diff --git a/esphome/core/ring_buffer.h b/esphome/core/ring_buffer.h index e602068844..97ffefcefa 100644 --- a/esphome/core/ring_buffer.h +++ b/esphome/core/ring_buffer.h @@ -12,13 +12,69 @@ namespace esphome { class RingBuffer { public: + /** + * @brief Reads from the ring buffer, waiting up to a specified number of ticks if necessary. + * + * Available bytes are read into the provided data pointer. If not enough bytes are available, + * the function will wait up to `ticks_to_wait` FreeRTOS ticks before reading what is available. + * + * @param data Pointer to copy read data into + * @param len Number of bytes to read + * @param ticks_to_wait Maximum number of FreeRTOS ticks to wait (default: 0) + * @return Number of bytes read + */ size_t read(void *data, size_t len, TickType_t ticks_to_wait = 0); + /** + * @brief Writes to the ring buffer, overwriting oldest data if necessary. + * + * The provided data is written to the ring buffer. If not enough space is available, + * the function will overwrite the oldest data in the ring buffer. + * + * @param data Pointer to data for writing + * @param len Number of bytes to write + * @return Number of bytes written + */ size_t write(void *data, size_t len); + /** + * @brief Writes to the ring buffer without overwriting oldest data. + * + * The provided data is written to the ring buffer. If not enough space is available, + * the function will wait up to `ticks_to_wait` FreeRTOS ticks before writing as much as possible. + * + * @param data Pointer to data for writing + * @param len Number of bytes to write + * @param ticks_to_wait Maximum number of FreeRTOS ticks to wait (default: 0) + * @return Number of bytes written + */ + size_t write_without_replacement(void *data, size_t len, TickType_t ticks_to_wait = 0); + + /** + * @brief Returns the number of available bytes in the ring buffer. + * + * This function provides the number of bytes that can be read from the ring buffer + * without blocking the calling FreeRTOS task. + * + * @return Number of available bytes + */ size_t available() const; + + /** + * @brief Returns the number of free bytes in the ring buffer. + * + * This function provides the number of bytes that can be written to the ring buffer + * without overwriting data or blocking the calling FreeRTOS task. + * + * @return Number of free bytes + */ size_t free() const; + /** + * @brief Resets the ring buffer, discarding all stored data. + * + * @return pdPASS if successful, pdFAIL otherwise + */ BaseType_t reset(); static std::unique_ptr create(size_t len); From 39b2f30b16d263864a9d5fb8444d4814d8658cc4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:36:18 +1200 Subject: [PATCH 2336/2607] Bump Dockerfile dependencies (#7386) --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 16f37274c6..4393d5a447 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,8 +34,8 @@ RUN \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ git=1:2.39.2-1.1 \ - curl=7.88.1-10+deb12u6 \ - openssh-client=1:9.2p1-2+deb12u2 \ + curl=7.88.1-10+deb12u7 \ + openssh-client=1:9.2p1-2+deb12u3 \ python3-cffi=1.15.1-5 \ libcairo2=1.16.0-7 \ libmagic1=1:5.44-3 \ @@ -49,7 +49,7 @@ RUN \ zlib1g-dev=1:1.2.13.dfsg-1 \ libjpeg-dev=1:2.1.5-2 \ libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.13-1~deb12u1 \ + libssl-dev=3.0.14-1~deb12u1 \ libffi-dev=3.4.4-1 \ libopenjp2-7=2.5.0-2 \ libtiff6=4.5.0-6+deb12u1 \ From cb4bede6d8790937e287cd69649c81871b1ac6b4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:06:54 +1200 Subject: [PATCH 2337/2607] Bump version to 2024.8.3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 00f2d6a13b..05be1877b3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.2" +__version__ = "2024.8.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From c6e64a9ed344dc8d34071fd3cfaefa9cd47d1f92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:22:56 +1200 Subject: [PATCH 2338/2607] Bump pypa/gh-action-pypi-publish from 1.9.0 to 1.10.0 (#7395) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7895e7624a..9e932a3dfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.9.0 + uses: pypa/gh-action-pypi-publish@v1.10.0 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From 10ccc5f12584c498c179974877a6b15f327066d7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:55:41 +1200 Subject: [PATCH 2339/2607] [api] Remove id from ``MediaPlayerSupportedFormat`` (#7406) --- esphome/components/api/api.proto | 1 - esphome/components/api/api_pb2_service.cpp | 19 ------------------- esphome/components/api/api_pb2_service.h | 4 ---- 3 files changed, 24 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 84183357dc..ad6fc79cf3 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1112,7 +1112,6 @@ enum MediaPlayerFormatPurpose { MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1; } message MediaPlayerSupportedFormat { - option (id) = 119; option (ifdef) = "USE_MEDIA_PLAYER"; string format = 1; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 16c0e5654f..269a755e9e 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -311,14 +311,6 @@ bool APIServerConnectionBase::send_list_entities_button_response(const ListEntit #ifdef USE_BUTTON #endif #ifdef USE_MEDIA_PLAYER -bool APIServerConnectionBase::send_media_player_supported_format(const MediaPlayerSupportedFormat &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_media_player_supported_format: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 119); -} -#endif -#ifdef USE_MEDIA_PLAYER bool APIServerConnectionBase::send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "send_list_entities_media_player_response: %s", msg.dump().c_str()); @@ -1143,17 +1135,6 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); #endif this->on_update_command_request(msg); -#endif - break; - } - case 119: { -#ifdef USE_MEDIA_PLAYER - MediaPlayerSupportedFormat msg; - msg.decode(msg_data, msg_size); -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "on_media_player_supported_format: %s", msg.dump().c_str()); -#endif - this->on_media_player_supported_format(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 83b5e3a444..83bfc2ed98 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -145,10 +145,6 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BUTTON virtual void on_button_command_request(const ButtonCommandRequest &value){}; #endif -#ifdef USE_MEDIA_PLAYER - bool send_media_player_supported_format(const MediaPlayerSupportedFormat &msg); - virtual void on_media_player_supported_format(const MediaPlayerSupportedFormat &value){}; -#endif #ifdef USE_MEDIA_PLAYER bool send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg); #endif From 1a71cc304740f7823ca77eb3bbab7128f7dd612a Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Wed, 4 Sep 2024 04:02:33 +0200 Subject: [PATCH 2340/2607] Drop max BLE client connections limitation (#7088) --- esphome/components/ble_client/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/esphome/components/ble_client/__init__.py b/esphome/components/ble_client/__init__.py index 6bf4ff739e..bc7d517695 100644 --- a/esphome/components/ble_client/__init__.py +++ b/esphome/components/ble_client/__init__.py @@ -65,9 +65,7 @@ CONF_ON_PASSKEY_NOTIFICATION = "on_passkey_notification" CONF_ON_NUMERIC_COMPARISON_REQUEST = "on_numeric_comparison_request" CONF_AUTO_CONNECT = "auto_connect" -# Espressif platformio framework is built with MAX_BLE_CONN to 3, so -# enforce this in yaml checks. -MULTI_CONF = 3 +MULTI_CONF = True CONFIG_SCHEMA = ( cv.Schema( From 188faa6530cd7d2a2f6a5a24eca6db1fcc9943f3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 4 Sep 2024 04:38:47 +0100 Subject: [PATCH 2341/2607] [bl0942] loop and overflow cleanup (#7358) --- esphome/components/bl0942/bl0942.cpp | 32 ++++++++++++++++++++++------ esphome/components/bl0942/bl0942.h | 2 ++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index 606d3629da..c70b5f1775 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -41,20 +41,33 @@ static const uint32_t BL0942_REG_MODE_DEFAULT = static const uint32_t BL0942_REG_SOFT_RESET_MAGIC = 0x5a5a5a; static const uint32_t BL0942_REG_USR_WRPROT_MAGIC = 0x55; +// 23-byte packet, 11 bits per byte, 2400 baud: about 105ms +static const uint32_t PKT_TIMEOUT_MS = 200; + void BL0942::loop() { DataPacket buffer; - if (!this->available()) { + int avail = this->available(); + + if (!avail) { return; } + if (avail < sizeof(buffer)) { + if (!this->rx_start_) { + this->rx_start_ = millis(); + } else if (millis() > this->rx_start_ + PKT_TIMEOUT_MS) { + ESP_LOGW(TAG, "Junk on wire. Throwing away partial message (%d bytes)", avail); + this->read_array((uint8_t *) &buffer, avail); + this->rx_start_ = 0; + } + return; + } + if (this->read_array((uint8_t *) &buffer, sizeof(buffer))) { if (this->validate_checksum_(&buffer)) { this->received_package_(&buffer); } - } else { - ESP_LOGW(TAG, "Junk on wire. Throwing away partial message"); - while (read() >= 0) - ; } + this->rx_start_ = 0; } bool BL0942::validate_checksum_(DataPacket *data) { @@ -133,10 +146,17 @@ void BL0942::received_package_(DataPacket *data) { return; } + // cf_cnt is only 24 bits, so track overflows + uint32_t cf_cnt = (uint24_t) data->cf_cnt; + cf_cnt |= this->prev_cf_cnt_ & 0xff000000; + if (cf_cnt < this->prev_cf_cnt_) { + cf_cnt += 0x1000000; + } + this->prev_cf_cnt_ = cf_cnt; + float v_rms = (uint24_t) data->v_rms / voltage_reference_; float i_rms = (uint24_t) data->i_rms / current_reference_; float watt = (int24_t) data->watt / power_reference_; - uint32_t cf_cnt = (uint24_t) data->cf_cnt; float total_energy_consumption = cf_cnt / energy_reference_; float frequency = 1000000.0f / data->frequency; diff --git a/esphome/components/bl0942/bl0942.h b/esphome/components/bl0942/bl0942.h index 52347c1bc3..a5e48bdf1d 100644 --- a/esphome/components/bl0942/bl0942.h +++ b/esphome/components/bl0942/bl0942.h @@ -67,6 +67,8 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { float energy_reference_ = BL0942_EREF; uint8_t address_ = 0; LineFrequency line_freq_ = LINE_FREQUENCY_50HZ; + uint32_t rx_start_ = 0; + uint32_t prev_cf_cnt_ = 0; bool validate_checksum_(DataPacket *data); int read_reg_(uint8_t reg); From a96de54d46f54a25a15eb889abeea4e53bb3d18f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:45:40 +1200 Subject: [PATCH 2342/2607] Bump peter-evans/create-pull-request from 6.1.0 to 7.0.0 (#7405) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 7677425236..e834ff3793 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.1.0 + uses: peter-evans/create-pull-request@v7.0.0 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From a7fd3b34aae0b9465a6bea66c00b2746d8cfea12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:47:59 +1200 Subject: [PATCH 2343/2607] Bump pypa/gh-action-pypi-publish from 1.10.0 to 1.10.1 (#7404) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e932a3dfc..522de63360 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.10.0 + uses: pypa/gh-action-pypi-publish@v1.10.1 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From e882cea47e76c50db674baf8dae0fa8744aabc4c Mon Sep 17 00:00:00 2001 From: Jeff Cooper Date: Tue, 3 Sep 2024 23:48:13 -0400 Subject: [PATCH 2344/2607] Voice assist improvement - configurable conversation_id timeout (#7385) --- esphome/components/voice_assistant/__init__.py | 6 ++++++ esphome/components/voice_assistant/voice_assistant.cpp | 8 +++++++- esphome/components/voice_assistant/voice_assistant.h | 3 +++ tests/components/voice_assistant/test.esp32-ard.yaml | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/__init__.py b/esphome/components/voice_assistant/__init__.py index 031edbf27a..a4fb572208 100644 --- a/esphome/components/voice_assistant/__init__.py +++ b/esphome/components/voice_assistant/__init__.py @@ -43,6 +43,8 @@ CONF_VOLUME_MULTIPLIER = "volume_multiplier" CONF_WAKE_WORD = "wake_word" +CONF_CONVERSATION_TIMEOUT = "conversation_timeout" + CONF_ON_TIMER_STARTED = "on_timer_started" CONF_ON_TIMER_UPDATED = "on_timer_updated" CONF_ON_TIMER_CANCELLED = "on_timer_cancelled" @@ -100,6 +102,9 @@ CONFIG_SCHEMA = cv.All( cv.float_with_unit("decibel full scale", "(dBFS|dbfs|DBFS)"), cv.int_range(0, 31), ), + cv.Optional( + CONF_CONVERSATION_TIMEOUT, default="300s" + ): cv.positive_time_period_milliseconds, cv.Optional(CONF_VOLUME_MULTIPLIER, default=1.0): cv.float_range( min=0.0, min_included=False ), @@ -182,6 +187,7 @@ async def to_code(config): cg.add(var.set_noise_suppression_level(config[CONF_NOISE_SUPPRESSION_LEVEL])) cg.add(var.set_auto_gain(config[CONF_AUTO_GAIN])) cg.add(var.set_volume_multiplier(config[CONF_VOLUME_MULTIPLIER])) + cg.add(var.set_conversation_timeout(config[CONF_CONVERSATION_TIMEOUT])) if CONF_ON_LISTENING in config: await automation.build_automation( diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index e4f388db68..43c7428858 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -171,6 +171,11 @@ void VoiceAssistant::deallocate_buffers_() { #endif } +void VoiceAssistant::reset_conversation_id() { + this->conversation_id_ = ""; + ESP_LOGD(TAG, "reset conversation ID"); +} + int VoiceAssistant::read_microphone_() { size_t bytes_read = 0; if (this->mic_->is_running()) { // Read audio into input buffer @@ -299,7 +304,8 @@ void VoiceAssistant::loop() { break; } this->set_state_(State::STARTING_PIPELINE); - this->set_timeout("reset-conversation_id", 5 * 60 * 1000, [this]() { this->conversation_id_ = ""; }); + this->set_timeout("reset-conversation_id", this->conversation_timeout_, + [this]() { this->reset_conversation_id(); }); break; } case State::STARTING_PIPELINE: { diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index a160972e22..88cb0dd413 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -147,6 +147,8 @@ class VoiceAssistant : public Component { } void set_auto_gain(uint8_t auto_gain) { this->auto_gain_ = auto_gain; } void set_volume_multiplier(float volume_multiplier) { this->volume_multiplier_ = volume_multiplier; } + void set_conversation_timeout(uint32_t conversation_timeout) { this->conversation_timeout_ = conversation_timeout; } + void reset_conversation_id(); Trigger<> *get_intent_end_trigger() const { return this->intent_end_trigger_; } Trigger<> *get_intent_start_trigger() const { return this->intent_start_trigger_; } @@ -262,6 +264,7 @@ class VoiceAssistant : public Component { uint8_t noise_suppression_level_; uint8_t auto_gain_; float volume_multiplier_; + uint32_t conversation_timeout_; uint8_t *send_buffer_; int16_t *input_buffer_; diff --git a/tests/components/voice_assistant/test.esp32-ard.yaml b/tests/components/voice_assistant/test.esp32-ard.yaml index 2e0209311d..7f6fd85303 100644 --- a/tests/components/voice_assistant/test.esp32-ard.yaml +++ b/tests/components/voice_assistant/test.esp32-ard.yaml @@ -33,6 +33,7 @@ speaker: voice_assistant: microphone: mic_id_external speaker: speaker_id + conversation_timeout: 60s on_listening: - logger.log: "Voice assistant microphone listening" on_start: From 71a7f6383f66d7e0730a7854d1f5739406310395 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 5 Sep 2024 01:08:39 +0100 Subject: [PATCH 2345/2607] Support BL0942 calibration (#7299) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 2 +- esphome/components/bl0942/__init__.py | 2 +- esphome/components/bl0942/bl0942.cpp | 20 +++++- esphome/components/bl0942/bl0942.h | 71 ++++++++++++++++++++ esphome/components/bl0942/sensor.py | 17 +++++ tests/components/bl0942/test.bk72xx-ard.yaml | 4 ++ tests/components/bl0942/test.rp2040-ard.yaml | 2 + 7 files changed, 115 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index ab11086980..8c706fa2d6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -61,7 +61,7 @@ esphome/components/bk72xx/* @kuba2k2 esphome/components/bl0906/* @athom-tech @jesserockz @tarontop esphome/components/bl0939/* @ziceva esphome/components/bl0940/* @tobias- -esphome/components/bl0942/* @dbuezas +esphome/components/bl0942/* @dbuezas @dwmw2 esphome/components/ble_client/* @buxtronix @clydebarrow esphome/components/bluetooth_proxy/* @jesserockz esphome/components/bme280_base/* @esphome/core diff --git a/esphome/components/bl0942/__init__.py b/esphome/components/bl0942/__init__.py index 8ef7857b7b..38b68d84b5 100644 --- a/esphome/components/bl0942/__init__.py +++ b/esphome/components/bl0942/__init__.py @@ -1 +1 @@ -CODEOWNERS = ["@dbuezas"] +CODEOWNERS = ["@dbuezas", "@dwmw2"] diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index c70b5f1775..af56e77de6 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -122,6 +122,20 @@ void BL0942::update() { } void BL0942::setup() { + // If either current or voltage references are set explicitly by the user, + // calculate the power reference from it unless that is also explicitly set. + if ((this->current_reference_set_ || this->voltage_reference_set_) && !this->power_reference_set_) { + this->power_reference_ = (this->voltage_reference_ * this->current_reference_ * 3537.0 / 305978.0) / 73989.0; + this->power_reference_set_ = true; + } + + // Similarly for energy reference, if the power reference was set by the user + // either implicitly or explicitly. + if (this->power_reference_set_ && !this->energy_reference_set_) { + this->energy_reference_ = this->power_reference_ * 3600000 / 419430.4; + this->energy_reference_set_ = true; + } + this->write_reg_(BL0942_REG_USR_WRPROT, BL0942_REG_USR_WRPROT_MAGIC); this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC); @@ -184,11 +198,15 @@ void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexit ESP_LOGCONFIG(TAG, "BL0942:"); ESP_LOGCONFIG(TAG, " Address: %d", this->address_); ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_); + ESP_LOGCONFIG(TAG, " Current reference: %f", this->current_reference_); + ESP_LOGCONFIG(TAG, " Energy reference: %f", this->energy_reference_); + ESP_LOGCONFIG(TAG, " Power reference: %f", this->power_reference_); + ESP_LOGCONFIG(TAG, " Voltage reference: %f", this->voltage_reference_); LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Power", this->power_sensor_); LOG_SENSOR("", "Energy", this->energy_sensor_); - LOG_SENSOR("", "frequency", this->frequency_sensor_); + LOG_SENSOR("", "Frequency", this->frequency_sensor_); } } // namespace bl0942 diff --git a/esphome/components/bl0942/bl0942.h b/esphome/components/bl0942/bl0942.h index a5e48bdf1d..1dc930183f 100644 --- a/esphome/components/bl0942/bl0942.h +++ b/esphome/components/bl0942/bl0942.h @@ -8,6 +8,57 @@ namespace esphome { namespace bl0942 { +// The BL0942 IC is "calibration-free", which means that it doesn't care +// at all about calibration, and that's left to software. It measures a +// voltage differential on its IP/IN pins which linearly proportional to +// the current flow, and another on its VP pin which is proportional to +// the line voltage. It never knows the actual calibration; the values +// it reports are solely in terms of those inputs. +// +// The datasheet refers to the input voltages as I(A) and V(V), both +// in millivolts. It measures them against a reference voltage Vref, +// which is typically 1.218V (but that absolute value is meaningless +// without the actual calibration anyway). +// +// The reported I_RMS value is 305978 I(A)/Vref, and the reported V_RMS +// value is 73989 V(V)/Vref. So we can calibrate those by applying a +// simple meter with a resistive load. +// +// The chip also measures the phase difference between voltage and +// current, and uses it to calculate the power factor (cos φ). It +// reports the WATT value of 3537 * I_RMS * V_RMS * cos φ). +// +// It also integrates total energy based on the WATT value. The time for +// one CF_CNT pulse is 1638.4*256 / WATT. +// +// So... how do we calibrate that? +// +// Using a simple resistive load and an external meter, we can measure +// the true voltage and current for a given V_RMS and I_RMS reading, +// to calculate BL0942_UREF and BL0942_IREF. Those are in units of +// "305978 counts per amp" or "73989 counts per volt" respectively. +// +// We can derive BL0942_PREF from those. Let's eliminate the weird +// factors and express the calibration in plain counts per volt/amp: +// UREF1 = UREF/73989, IREF1 = IREF/305978. +// +// Next... the true power in Watts is V * I * cos φ, so that's equal +// to WATT/3537 * IREF1 * UREF1. Which means +// BL0942_PREF = BL0942_UREF * BL0942_IREF * 3537 / 305978 / 73989. +// +// Finally the accumulated energy. The period of a CF_CNT count is +// 1638.4*256 / WATT seconds, or 419230.4 / WATT seconds. Which means +// the energy represented by a CN_CNT pulse is 419230.4 WATT-seconds. +// Factoring in the calibration, that's 419230.4 / BL0942_PREF actual +// Watt-seconds (or Joules, as the physicists like to call them). +// +// But we're not being physicists today; we we're being engineers, so +// we want to convert to kWh instead. Which we do by dividing by 1000 +// and then by 3600, so the energy in kWh is +// CF_CNT * 419230.4 / BL0942_PREF / 3600000 +// +// Which makes BL0952_EREF = BL0942_PREF * 3600000 / 419430.4 + static const float BL0942_PREF = 596; // taken from tasmota static const float BL0942_UREF = 15873.35944299; // should be 73989/1.218 static const float BL0942_IREF = 251213.46469622; // 305978/1.218 @@ -42,6 +93,22 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; } void set_line_freq(LineFrequency freq) { this->line_freq_ = freq; } void set_address(uint8_t address) { this->address_ = address; } + void set_current_reference(float current_ref) { + this->current_reference_ = current_ref; + this->current_reference_set_ = true; + } + void set_energy_reference(float energy_ref) { + this->energy_reference_ = energy_ref; + this->energy_reference_set_ = true; + } + void set_power_reference(float power_ref) { + this->power_reference_ = power_ref; + this->power_reference_set_ = true; + } + void set_voltage_reference(float voltage_ref) { + this->voltage_reference_ = voltage_ref; + this->voltage_reference_set_ = true; + } void loop() override; void update() override; @@ -59,12 +126,16 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { // Divide by this to turn into Watt float power_reference_ = BL0942_PREF; + bool power_reference_set_ = false; // Divide by this to turn into Volt float voltage_reference_ = BL0942_UREF; + bool voltage_reference_set_ = false; // Divide by this to turn into Ampere float current_reference_ = BL0942_IREF; + bool current_reference_set_ = false; // Divide by this to turn into kWh float energy_reference_ = BL0942_EREF; + bool energy_reference_set_ = false; uint8_t address_ = 0; LineFrequency line_freq_ = LINE_FREQUENCY_50HZ; uint32_t rx_start_ = 0; diff --git a/esphome/components/bl0942/sensor.py b/esphome/components/bl0942/sensor.py index c47da45b8c..3574443636 100644 --- a/esphome/components/bl0942/sensor.py +++ b/esphome/components/bl0942/sensor.py @@ -24,6 +24,11 @@ from esphome.const import ( UNIT_WATT, ) +CONF_CURRENT_REFERENCE = "current_reference" +CONF_ENERGY_REFERENCE = "energy_reference" +CONF_POWER_REFERENCE = "power_reference" +CONF_VOLTAGE_REFERENCE = "voltage_reference" + DEPENDENCIES = ["uart"] bl0942_ns = cg.esphome_ns.namespace("bl0942") @@ -77,6 +82,10 @@ CONFIG_SCHEMA = ( ), ), cv.Optional(CONF_ADDRESS, default=0): cv.int_range(min=0, max=3), + cv.Optional(CONF_CURRENT_REFERENCE): cv.float_, + cv.Optional(CONF_ENERGY_REFERENCE): cv.float_, + cv.Optional(CONF_POWER_REFERENCE): cv.float_, + cv.Optional(CONF_VOLTAGE_REFERENCE): cv.float_, } ) .extend(cv.polling_component_schema("60s")) @@ -106,3 +115,11 @@ async def to_code(config): cg.add(var.set_frequency_sensor(sens)) cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) cg.add(var.set_address(config[CONF_ADDRESS])) + if (current_reference := config.get(CONF_CURRENT_REFERENCE, None)) is not None: + cg.add(var.set_current_reference(current_reference)) + if (voltage_reference := config.get(CONF_VOLTAGE_REFERENCE, None)) is not None: + cg.add(var.set_voltage_reference(voltage_reference)) + if (power_reference := config.get(CONF_POWER_REFERENCE, None)) is not None: + cg.add(var.set_power_reference(power_reference)) + if (energy_reference := config.get(CONF_ENERGY_REFERENCE, None)) is not None: + cg.add(var.set_energy_reference(energy_reference)) diff --git a/tests/components/bl0942/test.bk72xx-ard.yaml b/tests/components/bl0942/test.bk72xx-ard.yaml index 4ed3eb391d..12772f9375 100644 --- a/tests/components/bl0942/test.bk72xx-ard.yaml +++ b/tests/components/bl0942/test.bk72xx-ard.yaml @@ -20,3 +20,7 @@ sensor: name: BL0942 Energy frequency: name: BL0942 Frequency + voltage_reference: 15968 + current_reference: 124180 + power_reference: 309.1 + energy_reference: 2653 diff --git a/tests/components/bl0942/test.rp2040-ard.yaml b/tests/components/bl0942/test.rp2040-ard.yaml index 8d16efed4f..d07e0c4402 100644 --- a/tests/components/bl0942/test.rp2040-ard.yaml +++ b/tests/components/bl0942/test.rp2040-ard.yaml @@ -18,3 +18,5 @@ sensor: name: BL0942 Energy frequency: name: BL0942 Frequency + voltage_reference: 15968 + current_reference: 124180 From dc4e60526cd63525363cf36be8625fd52840fea8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:49:01 +1200 Subject: [PATCH 2346/2607] [micro_wake_word] Remove duplicated download code (#7401) --- .../components/micro_wake_word/__init__.py | 27 ++----------------- esphome/external_files.py | 8 +++--- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index cd45f75b01..a8aa590951 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -4,8 +4,6 @@ import logging from pathlib import Path from urllib.parse import urljoin -import requests - from esphome import automation, external_files, git from esphome.automation import register_action, register_condition import esphome.codegen as cg @@ -26,7 +24,6 @@ from esphome.const import ( CONF_USERNAME, TYPE_GIT, TYPE_LOCAL, - __version__, ) from esphome.core import CORE, HexInt @@ -179,26 +176,6 @@ def _convert_manifest_v1_to_v2(v1_manifest): return v2_manifest -def _download_file(url: str, path: Path) -> bytes: - if not external_files.has_remote_file_changed(url, path): - _LOGGER.debug("Remote file has not changed, skipping download") - return path.read_bytes() - - try: - req = requests.get( - url, - timeout=external_files.NETWORK_TIMEOUT, - headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, - ) - req.raise_for_status() - except requests.exceptions.RequestException as e: - raise cv.Invalid(f"Could not download file from {url}: {e}") from e - - path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(req.content) - return req.content - - def _validate_manifest_version(manifest_data): if manifest_version := manifest_data.get(KEY_VERSION): if manifest_version == 1: @@ -223,7 +200,7 @@ def _process_http_source(config): json_path = path / "manifest.json" - json_contents = _download_file(url, json_path) + json_contents = external_files.download_content(url, json_path) manifest_data = json.loads(json_contents) if not isinstance(manifest_data, dict): @@ -234,7 +211,7 @@ def _process_http_source(config): model_path = path / model - _download_file(str(model_url), model_path) + external_files.download_content(str(model_url), model_path) return config diff --git a/esphome/external_files.py b/esphome/external_files.py index baf62286e4..057ff52f3f 100644 --- a/esphome/external_files.py +++ b/esphome/external_files.py @@ -80,10 +80,10 @@ def compute_local_file_dir(domain: str) -> Path: return base_directory -def download_content(url: str, path: Path, timeout=NETWORK_TIMEOUT) -> None: +def download_content(url: str, path: Path, timeout=NETWORK_TIMEOUT) -> bytes: if not has_remote_file_changed(url, path): _LOGGER.debug("Remote file has not changed %s", url) - return + return path.read_bytes() _LOGGER.debug( "Remote file has changed, downloading from %s to %s", @@ -102,4 +102,6 @@ def download_content(url: str, path: Path, timeout=NETWORK_TIMEOUT) -> None: raise cv.Invalid(f"Could not download from {url}: {e}") path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(req.content) + data = req.content + path.write_bytes(data) + return data From b4962334251ee8920d46c912588a0adc4bd58201 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:57:44 +0200 Subject: [PATCH 2347/2607] Add StatsD component (#6642) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/statsd/__init__.py | 65 ++++++++ esphome/components/statsd/statsd.cpp | 156 ++++++++++++++++++ esphome/components/statsd/statsd.h | 86 ++++++++++ tests/components/statsD/common.yaml | 29 ++++ tests/components/statsD/test.bk72xx-ard.yaml | 2 + tests/components/statsD/test.esp32-ard.yaml | 2 + .../components/statsD/test.esp32-c3-ard.yaml | 2 + .../components/statsD/test.esp32-c3-idf.yaml | 2 + tests/components/statsD/test.esp32-idf.yaml | 2 + tests/components/statsD/test.esp8266-ard.yaml | 2 + tests/components/statsD/test.rp2040-ard.yaml | 2 + 12 files changed, 351 insertions(+) create mode 100644 esphome/components/statsd/__init__.py create mode 100644 esphome/components/statsd/statsd.cpp create mode 100644 esphome/components/statsd/statsd.h create mode 100644 tests/components/statsD/common.yaml create mode 100644 tests/components/statsD/test.bk72xx-ard.yaml create mode 100644 tests/components/statsD/test.esp32-ard.yaml create mode 100644 tests/components/statsD/test.esp32-c3-ard.yaml create mode 100644 tests/components/statsD/test.esp32-c3-idf.yaml create mode 100644 tests/components/statsD/test.esp32-idf.yaml create mode 100644 tests/components/statsD/test.esp8266-ard.yaml create mode 100644 tests/components/statsD/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 8c706fa2d6..52b5f48a34 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -385,6 +385,7 @@ esphome/components/st7701s/* @clydebarrow esphome/components/st7735/* @SenexCrenshaw esphome/components/st7789v/* @kbx81 esphome/components/st7920/* @marsjan155 +esphome/components/statsd/* @Links2004 esphome/components/substitutions/* @esphome/core esphome/components/sun/* @OttoWinter esphome/components/sun_gtil2/* @Mat931 diff --git a/esphome/components/statsd/__init__.py b/esphome/components/statsd/__init__.py new file mode 100644 index 0000000000..3623338aec --- /dev/null +++ b/esphome/components/statsd/__init__.py @@ -0,0 +1,65 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, binary_sensor +from esphome.const import ( + CONF_ID, + CONF_PORT, + CONF_NAME, + CONF_SENSORS, + CONF_BINARY_SENSORS, +) + +AUTO_LOAD = ["socket"] +CODEOWNERS = ["@Links2004"] +DEPENDENCIES = ["network"] + +CONF_HOST = "host" +CONF_PREFIX = "prefix" + +statsd_component_ns = cg.esphome_ns.namespace("statsd") +StatsdComponent = statsd_component_ns.class_("StatsdComponent", cg.PollingComponent) + +CONFIG_SENSORS_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(sensor.Sensor), + cv.Required(CONF_NAME): cv.string_strict, + } +) + +CONFIG_BINARY_SENSORS_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(binary_sensor.BinarySensor), + cv.Required(CONF_NAME): cv.string_strict, + } +) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(StatsdComponent), + cv.Required(CONF_HOST): cv.string_strict, + cv.Optional(CONF_PORT, default=8125): cv.port, + cv.Optional(CONF_PREFIX, default=""): cv.string_strict, + cv.Optional(CONF_SENSORS): cv.ensure_list(CONFIG_SENSORS_SCHEMA), + cv.Optional(CONF_BINARY_SENSORS): cv.ensure_list(CONFIG_BINARY_SENSORS_SCHEMA), + } +).extend(cv.polling_component_schema("10s")) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + cg.add( + var.configure( + config.get(CONF_HOST), + config.get(CONF_PORT), + config.get(CONF_PREFIX), + ) + ) + + for sensor_cfg in config.get(CONF_SENSORS, []): + s = await cg.get_variable(sensor_cfg[CONF_ID]) + cg.add(var.register_sensor(sensor_cfg[CONF_NAME], s)) + + for sensor_cfg in config.get(CONF_BINARY_SENSORS, []): + s = await cg.get_variable(sensor_cfg[CONF_ID]) + cg.add(var.register_binary_sensor(sensor_cfg[CONF_NAME], s)) diff --git a/esphome/components/statsd/statsd.cpp b/esphome/components/statsd/statsd.cpp new file mode 100644 index 0000000000..68b24908d2 --- /dev/null +++ b/esphome/components/statsd/statsd.cpp @@ -0,0 +1,156 @@ +#include "esphome/core/log.h" + +#include "statsd.h" + +namespace esphome { +namespace statsd { + +// send UDP packet if we reach 1Kb packed size +// this is needed since statsD does not support fragmented UDP packets +static const uint16_t SEND_THRESHOLD = 1024; + +static const char *const TAG = "statsD"; + +void StatsdComponent::setup() { +#ifndef USE_ESP8266 + this->sock_ = esphome::socket::socket(AF_INET, SOCK_DGRAM, 0); + + struct sockaddr_in source; + source.sin_family = AF_INET; + source.sin_addr.s_addr = htonl(INADDR_ANY); + source.sin_port = htons(this->port_); + this->sock_->bind((struct sockaddr *) &source, sizeof(source)); + + this->destination_.sin_family = AF_INET; + this->destination_.sin_port = htons(this->port_); + this->destination_.sin_addr.s_addr = inet_addr(this->host_); +#endif +} + +StatsdComponent::~StatsdComponent() { +#ifndef USE_ESP8266 + if (!this->sock_) { + return; + } + this->sock_->close(); +#endif +} + +void StatsdComponent::dump_config() { + ESP_LOGCONFIG(TAG, "statsD:"); + ESP_LOGCONFIG(TAG, " host: %s", this->host_); + ESP_LOGCONFIG(TAG, " port: %d", this->port_); + if (this->prefix_) { + ESP_LOGCONFIG(TAG, " prefix: %s", this->prefix_); + } + + ESP_LOGCONFIG(TAG, " metrics:"); + for (sensors_t s : this->sensors_) { + ESP_LOGCONFIG(TAG, " - name: %s", s.name); + ESP_LOGCONFIG(TAG, " type: %d", s.type); + } +} + +float StatsdComponent::get_setup_priority() const { return esphome::setup_priority::AFTER_WIFI; } + +#ifdef USE_SENSOR +void StatsdComponent::register_sensor(const char *name, esphome::sensor::Sensor *sensor) { + sensors_t s; + s.name = name; + s.sensor = sensor; + s.type = TYPE_SENSOR; + this->sensors_.push_back(s); +} +#endif + +#ifdef USE_BINARY_SENSOR +void StatsdComponent::register_binary_sensor(const char *name, esphome::binary_sensor::BinarySensor *binary_sensor) { + sensors_t s; + s.name = name; + s.binary_sensor = binary_sensor; + s.type = TYPE_BINARY_SENSOR; + this->sensors_.push_back(s); +} +#endif + +void StatsdComponent::update() { + std::string out; + out.reserve(SEND_THRESHOLD); + + for (sensors_t s : this->sensors_) { + double val = 0; + switch (s.type) { +#ifdef USE_SENSOR + case TYPE_SENSOR: + if (!s.sensor->has_state()) { + continue; + } + val = s.sensor->state; + break; +#endif +#ifdef USE_BINARY_SENSOR + case TYPE_BINARY_SENSOR: + if (!s.binary_sensor->has_state()) { + continue; + } + // map bool to double + if (s.binary_sensor->state) { + val = 1; + } + break; +#endif + default: + ESP_LOGE(TAG, "type not known, name: %s type: %d", s.name, s.type); + continue; + } + + // statsD gauge: + // https://github.com/statsd/statsd/blob/master/docs/metric_types.md + // This implies you can't explicitly set a gauge to a negative number without first setting it to zero. + if (val < 0) { + if (this->prefix_) { + out.append(str_sprintf("%s.", this->prefix_)); + } + out.append(str_sprintf("%s:0|g\n", s.name)); + } + if (this->prefix_) { + out.append(str_sprintf("%s.", this->prefix_)); + } + out.append(str_sprintf("%s:%f|g\n", s.name, val)); + + if (out.length() > SEND_THRESHOLD) { + this->send_(&out); + out.clear(); + } + } + + this->send_(&out); +} + +void StatsdComponent::send_(std::string *out) { + if (out->empty()) { + return; + } +#ifdef USE_ESP8266 + IPAddress ip; + ip.fromString(this->host_); + + this->sock_.beginPacket(ip, this->port_); + this->sock_.write((const uint8_t *) out->c_str(), out->length()); + this->sock_.endPacket(); + +#else + if (!this->sock_) { + return; + } + + int n_bytes = this->sock_->sendto(out->c_str(), out->length(), 0, reinterpret_cast(&this->destination_), + sizeof(this->destination_)); + if (n_bytes != out->length()) { + ESP_LOGE(TAG, "Failed to send UDP packed (%d of %d)", n_bytes, out->length()); + } +#endif +} + +} // namespace statsd +} // namespace esphome diff --git a/esphome/components/statsd/statsd.h b/esphome/components/statsd/statsd.h new file mode 100644 index 0000000000..ef42579587 --- /dev/null +++ b/esphome/components/statsd/statsd.h @@ -0,0 +1,86 @@ +#pragma once + +#include + +#include "esphome/core/defines.h" +#include "esphome/core/component.h" +#include "esphome/components/socket/socket.h" +#include "esphome/components/network/ip_address.h" + +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +#ifdef USE_LOGGER +#include "esphome/components/logger/logger.h" +#endif + +#ifdef USE_ESP8266 +#include "WiFiUdp.h" +#include "IPAddress.h" +#endif + +namespace esphome { +namespace statsd { + +using sensor_type_t = enum { TYPE_SENSOR, TYPE_BINARY_SENSOR }; + +using sensors_t = struct { + const char *name; + sensor_type_t type; + union { +#ifdef USE_SENSOR + esphome::sensor::Sensor *sensor; +#endif +#ifdef USE_BINARY_SENSOR + esphome::binary_sensor::BinarySensor *binary_sensor; +#endif + }; +}; + +class StatsdComponent : public PollingComponent { + public: + ~StatsdComponent(); + + void setup() override; + void dump_config() override; + void update() override; + float get_setup_priority() const override; + + void configure(const char *host, uint16_t port, const char *prefix) { + this->host_ = host; + this->port_ = port; + this->prefix_ = prefix; + } + +#ifdef USE_SENSOR + void register_sensor(const char *name, esphome::sensor::Sensor *sensor); +#endif + +#ifdef USE_BINARY_SENSOR + void register_binary_sensor(const char *name, esphome::binary_sensor::BinarySensor *binary_sensor); +#endif + + private: + const char *host_; + const char *prefix_; + uint16_t port_; + + std::vector sensors_; + +#ifdef USE_ESP8266 + WiFiUDP sock_; +#else + std::unique_ptr sock_; + struct sockaddr_in destination_; +#endif + + void send_(std::string *out); +}; + +} // namespace statsd +} // namespace esphome diff --git a/tests/components/statsD/common.yaml b/tests/components/statsD/common.yaml new file mode 100644 index 0000000000..5878101de8 --- /dev/null +++ b/tests/components/statsD/common.yaml @@ -0,0 +1,29 @@ +wifi: + ssid: MySSID + password: password1 + +statsd: + host: "192.168.1.1" + port: 8125 + prefix: esphome + update_interval: 60s + sensors: + id: s + name: sensors + binary_sensors: + id: bs + name: binary_sensors + +sensor: + - platform: template + id: s + name: "42.1" + lambda: |- + return 42.1f; + +binary_sensor: + - platform: template + id: bs + name: "On" + lambda: |- + return true; diff --git a/tests/components/statsD/test.bk72xx-ard.yaml b/tests/components/statsD/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.bk72xx-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.esp32-ard.yaml b/tests/components/statsD/test.esp32-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.esp32-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.esp32-c3-ard.yaml b/tests/components/statsD/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.esp32-c3-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.esp32-c3-idf.yaml b/tests/components/statsD/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.esp32-c3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.esp32-idf.yaml b/tests/components/statsD/test.esp32-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.esp32-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.esp8266-ard.yaml b/tests/components/statsD/test.esp8266-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.esp8266-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/statsD/test.rp2040-ard.yaml b/tests/components/statsD/test.rp2040-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/statsD/test.rp2040-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml From 1548fa0811144302fc9700a50bf8966b7a7d9157 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:09:49 +1200 Subject: [PATCH 2348/2607] [homeassistant-switch] Support different entity domains (#7331) --- esphome/components/homeassistant/__init__.py | 13 ++++++++++++ .../homeassistant/switch/__init__.py | 17 +++++++++++++-- .../switch/homeassistant_switch.cpp | 4 ++-- tests/components/homeassistant/common.yaml | 21 +++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/esphome/components/homeassistant/__init__.py b/esphome/components/homeassistant/__init__.py index 6d997e48ca..223d6c18c3 100644 --- a/esphome/components/homeassistant/__init__.py +++ b/esphome/components/homeassistant/__init__.py @@ -5,6 +5,19 @@ from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_INTERNAL CODEOWNERS = ["@OttoWinter", "@esphome/core"] homeassistant_ns = cg.esphome_ns.namespace("homeassistant") + +def validate_entity_domain(platform, supported_domains): + def validator(config): + domain = config[CONF_ENTITY_ID].split(".", 1)[0] + if domain not in supported_domains: + raise cv.Invalid( + f"Entity ID {config[CONF_ENTITY_ID]} is not supported by the {platform} platform." + ) + return config + + return validator + + HOME_ASSISTANT_IMPORT_SCHEMA = cv.Schema( { cv.Required(CONF_ENTITY_ID): cv.entity_id, diff --git a/esphome/components/homeassistant/switch/__init__.py b/esphome/components/homeassistant/switch/__init__.py index 3d7c80682a..384f82bbad 100644 --- a/esphome/components/homeassistant/switch/__init__.py +++ b/esphome/components/homeassistant/switch/__init__.py @@ -7,19 +7,32 @@ from .. import ( HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA, homeassistant_ns, setup_home_assistant_entity, + validate_entity_domain, ) CODEOWNERS = ["@Links2004"] DEPENDENCIES = ["api"] +SUPPORTED_DOMAINS = [ + "automation", + "fan", + "humidifier", + "input_boolean", + "light", + "remote", + "siren", + "switch", +] + HomeassistantSwitch = homeassistant_ns.class_( "HomeassistantSwitch", switch.Switch, cg.Component ) -CONFIG_SCHEMA = ( +CONFIG_SCHEMA = cv.All( switch.switch_schema(HomeassistantSwitch) - .extend(cv.COMPONENT_SCHEMA) .extend(HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA) + .extend(cv.COMPONENT_SCHEMA), + validate_entity_domain("switch", SUPPORTED_DOMAINS), ) diff --git a/esphome/components/homeassistant/switch/homeassistant_switch.cpp b/esphome/components/homeassistant/switch/homeassistant_switch.cpp index 05ef46e30e..0451c95069 100644 --- a/esphome/components/homeassistant/switch/homeassistant_switch.cpp +++ b/esphome/components/homeassistant/switch/homeassistant_switch.cpp @@ -42,9 +42,9 @@ void HomeassistantSwitch::write_state(bool state) { api::HomeassistantServiceResponse resp; if (state) { - resp.service = "switch.turn_on"; + resp.service = "homeassistant.turn_on"; } else { - resp.service = "switch.turn_off"; + resp.service = "homeassistant.turn_off"; } api::HomeassistantServiceMap entity_id_kv; diff --git a/tests/components/homeassistant/common.yaml b/tests/components/homeassistant/common.yaml index 8c9a4ad75f..9c6cb71b8b 100644 --- a/tests/components/homeassistant/common.yaml +++ b/tests/components/homeassistant/common.yaml @@ -33,6 +33,27 @@ wifi: api: switch: + - platform: homeassistant + entity_id: automation.my_cool_automation + id: my_cool_automation + - platform: homeassistant + entity_id: fan.my_cool_fan + id: my_cool_fan + - platform: homeassistant + entity_id: humidifier.my_cool_humidifier + id: my_cool_humidifier + - platform: homeassistant + entity_id: input_boolean.my_cool_input_boolean + id: my_cool_input_boolean + - platform: homeassistant + entity_id: light.my_cool_light + id: my_cool_light + - platform: homeassistant + entity_id: remote.my_cool_remote + id: my_cool_remote + - platform: homeassistant + entity_id: siren.my_cool_siren + id: my_cool_siren - platform: homeassistant entity_id: switch.my_cool_switch id: my_cool_switch From 18a1191e03578fb395156cb2578dc2f41d2a44f5 Mon Sep 17 00:00:00 2001 From: Adam DeMuri Date: Wed, 4 Sep 2024 23:08:02 -0600 Subject: [PATCH 2349/2607] Add support for using BMP280 with SPI (#7053) Co-authored-by: Keith Burzinski --- CODEOWNERS | 3 + esphome/components/bmp280/sensor.py | 97 +------------------ esphome/components/bmp280_base/__init__.py | 88 +++++++++++++++++ .../bmp280_base.cpp} | 15 ++- .../bmp280.h => bmp280_base/bmp280_base.h} | 14 ++- esphome/components/bmp280_i2c/__init__.py | 0 esphome/components/bmp280_i2c/bmp280_i2c.cpp | 27 ++++++ esphome/components/bmp280_i2c/bmp280_i2c.h | 22 +++++ esphome/components/bmp280_i2c/sensor.py | 22 +++++ esphome/components/bmp280_spi/__init__.py | 0 esphome/components/bmp280_spi/bmp280_spi.cpp | 65 +++++++++++++ esphome/components/bmp280_spi/bmp280_spi.h | 20 ++++ esphome/components/bmp280_spi/sensor.py | 22 +++++ tests/components/bmp280/test.esp32-ard.yaml | 15 --- .../components/bmp280/test.esp32-c3-ard.yaml | 15 --- tests/components/bmp280/test.esp32-idf.yaml | 15 --- tests/components/bmp280/test.esp8266-ard.yaml | 15 --- tests/components/bmp280/test.rp2040-ard.yaml | 15 --- .../common.yaml} | 10 +- .../components/bmp280_i2c/test.esp32-ard.yaml | 5 + .../bmp280_i2c/test.esp32-c3-ard.yaml | 5 + .../bmp280_i2c/test.esp32-c3-idf.yaml | 5 + .../components/bmp280_i2c/test.esp32-idf.yaml | 5 + .../bmp280_i2c/test.esp8266-ard.yaml | 5 + .../bmp280_i2c/test.rp2040-ard.yaml | 5 + tests/components/bmp280_spi/common.yaml | 18 ++++ .../components/bmp280_spi/test.esp32-ard.yaml | 7 ++ .../bmp280_spi/test.esp32-c3-ard.yaml | 7 ++ .../bmp280_spi/test.esp32-c3-idf.yaml | 7 ++ .../components/bmp280_spi/test.esp32-idf.yaml | 7 ++ .../bmp280_spi/test.esp8266-ard.yaml | 7 ++ .../bmp280_spi/test.rp2040-ard.yaml | 7 ++ 32 files changed, 388 insertions(+), 182 deletions(-) create mode 100644 esphome/components/bmp280_base/__init__.py rename esphome/components/{bmp280/bmp280.cpp => bmp280_base/bmp280_base.cpp} (95%) rename esphome/components/{bmp280/bmp280.h => bmp280_base/bmp280_base.h} (88%) create mode 100644 esphome/components/bmp280_i2c/__init__.py create mode 100644 esphome/components/bmp280_i2c/bmp280_i2c.cpp create mode 100644 esphome/components/bmp280_i2c/bmp280_i2c.h create mode 100644 esphome/components/bmp280_i2c/sensor.py create mode 100644 esphome/components/bmp280_spi/__init__.py create mode 100644 esphome/components/bmp280_spi/bmp280_spi.cpp create mode 100644 esphome/components/bmp280_spi/bmp280_spi.h create mode 100644 esphome/components/bmp280_spi/sensor.py delete mode 100644 tests/components/bmp280/test.esp32-ard.yaml delete mode 100644 tests/components/bmp280/test.esp32-c3-ard.yaml delete mode 100644 tests/components/bmp280/test.esp32-idf.yaml delete mode 100644 tests/components/bmp280/test.esp8266-ard.yaml delete mode 100644 tests/components/bmp280/test.rp2040-ard.yaml rename tests/components/{bmp280/test.esp32-c3-idf.yaml => bmp280_i2c/common.yaml} (56%) create mode 100644 tests/components/bmp280_i2c/test.esp32-ard.yaml create mode 100644 tests/components/bmp280_i2c/test.esp32-c3-ard.yaml create mode 100644 tests/components/bmp280_i2c/test.esp32-c3-idf.yaml create mode 100644 tests/components/bmp280_i2c/test.esp32-idf.yaml create mode 100644 tests/components/bmp280_i2c/test.esp8266-ard.yaml create mode 100644 tests/components/bmp280_i2c/test.rp2040-ard.yaml create mode 100644 tests/components/bmp280_spi/common.yaml create mode 100644 tests/components/bmp280_spi/test.esp32-ard.yaml create mode 100644 tests/components/bmp280_spi/test.esp32-c3-ard.yaml create mode 100644 tests/components/bmp280_spi/test.esp32-c3-idf.yaml create mode 100644 tests/components/bmp280_spi/test.esp32-idf.yaml create mode 100644 tests/components/bmp280_spi/test.esp8266-ard.yaml create mode 100644 tests/components/bmp280_spi/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 52b5f48a34..1d4df3ccb8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -70,6 +70,9 @@ esphome/components/bme680_bsec/* @trvrnrth esphome/components/bme68x_bsec2/* @kbx81 @neffs esphome/components/bme68x_bsec2_i2c/* @kbx81 @neffs esphome/components/bmi160/* @flaviut +esphome/components/bmp280_base/* @ademuri +esphome/components/bmp280_i2c/* @ademuri +esphome/components/bmp280_spi/* @ademuri esphome/components/bmp3xx/* @latonita esphome/components/bmp3xx_base/* @latonita @martgras esphome/components/bmp3xx_i2c/* @latonita diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index a23bc0766a..a624889982 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -1,96 +1,5 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import i2c, sensor -from esphome.const import ( - CONF_ID, - CONF_PRESSURE, - CONF_TEMPERATURE, - DEVICE_CLASS_PRESSURE, - DEVICE_CLASS_TEMPERATURE, - STATE_CLASS_MEASUREMENT, - UNIT_CELSIUS, - UNIT_HECTOPASCAL, - CONF_IIR_FILTER, - CONF_OVERSAMPLING, + +CONFIG_SCHEMA = cv.invalid( + "The bmp280 sensor component has been renamed to bmp280_i2c." ) - -DEPENDENCIES = ["i2c"] - -bmp280_ns = cg.esphome_ns.namespace("bmp280") -BMP280Oversampling = bmp280_ns.enum("BMP280Oversampling") -OVERSAMPLING_OPTIONS = { - "NONE": BMP280Oversampling.BMP280_OVERSAMPLING_NONE, - "1X": BMP280Oversampling.BMP280_OVERSAMPLING_1X, - "2X": BMP280Oversampling.BMP280_OVERSAMPLING_2X, - "4X": BMP280Oversampling.BMP280_OVERSAMPLING_4X, - "8X": BMP280Oversampling.BMP280_OVERSAMPLING_8X, - "16X": BMP280Oversampling.BMP280_OVERSAMPLING_16X, -} - -BMP280IIRFilter = bmp280_ns.enum("BMP280IIRFilter") -IIR_FILTER_OPTIONS = { - "OFF": BMP280IIRFilter.BMP280_IIR_FILTER_OFF, - "2X": BMP280IIRFilter.BMP280_IIR_FILTER_2X, - "4X": BMP280IIRFilter.BMP280_IIR_FILTER_4X, - "8X": BMP280IIRFilter.BMP280_IIR_FILTER_8X, - "16X": BMP280IIRFilter.BMP280_IIR_FILTER_16X, -} - -BMP280Component = bmp280_ns.class_( - "BMP280Component", cg.PollingComponent, i2c.I2CDevice -) - -CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(BMP280Component), - cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - unit_of_measurement=UNIT_CELSIUS, - accuracy_decimals=1, - device_class=DEVICE_CLASS_TEMPERATURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - unit_of_measurement=UNIT_HECTOPASCAL, - accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, - state_class=STATE_CLASS_MEASUREMENT, - ).extend( - { - cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( - OVERSAMPLING_OPTIONS, upper=True - ), - } - ), - cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( - IIR_FILTER_OPTIONS, upper=True - ), - } - ) - .extend(cv.polling_component_schema("60s")) - .extend(i2c.i2c_device_schema(0x77)) -) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await i2c.register_i2c_device(var, config) - - if temperature_config := config.get(CONF_TEMPERATURE): - sens = await sensor.new_sensor(temperature_config) - cg.add(var.set_temperature_sensor(sens)) - cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) - - if pressure_config := config.get(CONF_PRESSURE): - sens = await sensor.new_sensor(pressure_config) - cg.add(var.set_pressure_sensor(sens)) - cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) - - cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) diff --git a/esphome/components/bmp280_base/__init__.py b/esphome/components/bmp280_base/__init__.py new file mode 100644 index 0000000000..c0f9af9dd7 --- /dev/null +++ b/esphome/components/bmp280_base/__init__.py @@ -0,0 +1,88 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_ID, + CONF_IIR_FILTER, + CONF_OVERSAMPLING, + CONF_PRESSURE, + CONF_TEMPERATURE, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_HECTOPASCAL, +) + +CODEOWNERS = ["@ademuri"] + +bmp280_ns = cg.esphome_ns.namespace("bmp280_base") +BMP280Oversampling = bmp280_ns.enum("BMP280Oversampling") +OVERSAMPLING_OPTIONS = { + "NONE": BMP280Oversampling.BMP280_OVERSAMPLING_NONE, + "1X": BMP280Oversampling.BMP280_OVERSAMPLING_1X, + "2X": BMP280Oversampling.BMP280_OVERSAMPLING_2X, + "4X": BMP280Oversampling.BMP280_OVERSAMPLING_4X, + "8X": BMP280Oversampling.BMP280_OVERSAMPLING_8X, + "16X": BMP280Oversampling.BMP280_OVERSAMPLING_16X, +} + +BMP280IIRFilter = bmp280_ns.enum("BMP280IIRFilter") +IIR_FILTER_OPTIONS = { + "OFF": BMP280IIRFilter.BMP280_IIR_FILTER_OFF, + "2X": BMP280IIRFilter.BMP280_IIR_FILTER_2X, + "4X": BMP280IIRFilter.BMP280_IIR_FILTER_4X, + "8X": BMP280IIRFilter.BMP280_IIR_FILTER_8X, + "16X": BMP280IIRFilter.BMP280_IIR_FILTER_16X, +} + +CONFIG_SCHEMA_BASE = cv.Schema( + { + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_PRESSURE): sensor.sensor_schema( + unit_of_measurement=UNIT_HECTOPASCAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + ).extend( + { + cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( + OVERSAMPLING_OPTIONS, upper=True + ), + } + ), + cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( + IIR_FILTER_OPTIONS, upper=True + ), + } +).extend(cv.polling_component_schema("60s")) + + +async def to_code_base(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING])) + + if pressure_config := config.get(CONF_PRESSURE): + sens = await sensor.new_sensor(pressure_config) + cg.add(var.set_pressure_sensor(sens)) + cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING])) + + cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) + + return var diff --git a/esphome/components/bmp280/bmp280.cpp b/esphome/components/bmp280_base/bmp280_base.cpp similarity index 95% rename from esphome/components/bmp280/bmp280.cpp rename to esphome/components/bmp280_base/bmp280_base.cpp index c92daa07fb..f94456f6e6 100644 --- a/esphome/components/bmp280/bmp280.cpp +++ b/esphome/components/bmp280_base/bmp280_base.cpp @@ -1,9 +1,9 @@ -#include "bmp280.h" +#include "bmp280_base.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" namespace esphome { -namespace bmp280 { +namespace bmp280_base { static const char *const TAG = "bmp280.sensor"; @@ -59,6 +59,14 @@ static const char *iir_filter_to_str(BMP280IIRFilter filter) { void BMP280Component::setup() { ESP_LOGCONFIG(TAG, "Setting up BMP280..."); uint8_t chip_id = 0; + + // Read the chip id twice, to work around a bug where the first read is 0. + // https://community.st.com/t5/stm32-mcus-products/issue-with-reading-bmp280-chip-id-using-spi/td-p/691855 + if (!this->read_byte(0xD0, &chip_id)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } if (!this->read_byte(0xD0, &chip_id)) { this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); @@ -122,7 +130,6 @@ void BMP280Component::setup() { } void BMP280Component::dump_config() { ESP_LOGCONFIG(TAG, "BMP280:"); - LOG_I2C_DEVICE(this); switch (this->error_code_) { case COMMUNICATION_FAILED: ESP_LOGE(TAG, "Communication with BMP280 failed!"); @@ -262,5 +269,5 @@ uint16_t BMP280Component::read_u16_le_(uint8_t a_register) { } int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); } -} // namespace bmp280 +} // namespace bmp280_base } // namespace esphome diff --git a/esphome/components/bmp280/bmp280.h b/esphome/components/bmp280_base/bmp280_base.h similarity index 88% rename from esphome/components/bmp280/bmp280.h rename to esphome/components/bmp280_base/bmp280_base.h index 96eb470155..4b22e98f13 100644 --- a/esphome/components/bmp280/bmp280.h +++ b/esphome/components/bmp280_base/bmp280_base.h @@ -2,10 +2,9 @@ #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" -#include "esphome/components/i2c/i2c.h" namespace esphome { -namespace bmp280 { +namespace bmp280_base { /// Internal struct storing the calibration values of an BMP280. struct BMP280CalibrationData { @@ -50,8 +49,8 @@ enum BMP280IIRFilter { BMP280_IIR_FILTER_16X = 0b100, }; -/// This class implements support for the BMP280 Temperature+Pressure i2c sensor. -class BMP280Component : public PollingComponent, public i2c::I2CDevice { +/// This class implements support for the BMP280 Temperature+Pressure sensor. +class BMP280Component : public PollingComponent { public: void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; } @@ -68,6 +67,11 @@ class BMP280Component : public PollingComponent, public i2c::I2CDevice { float get_setup_priority() const override; void update() override; + virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0; + virtual bool write_byte(uint8_t a_register, uint8_t data) = 0; + virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0; + virtual bool read_byte_16(uint8_t a_register, uint16_t *data) = 0; + protected: /// Read the temperature value and store the calculated ambient temperature in t_fine. float read_temperature_(int32_t *t_fine); @@ -90,5 +94,5 @@ class BMP280Component : public PollingComponent, public i2c::I2CDevice { } error_code_{NONE}; }; -} // namespace bmp280 +} // namespace bmp280_base } // namespace esphome diff --git a/esphome/components/bmp280_i2c/__init__.py b/esphome/components/bmp280_i2c/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/bmp280_i2c/bmp280_i2c.cpp b/esphome/components/bmp280_i2c/bmp280_i2c.cpp new file mode 100644 index 0000000000..04b8bd8b10 --- /dev/null +++ b/esphome/components/bmp280_i2c/bmp280_i2c.cpp @@ -0,0 +1,27 @@ +#include "bmp280_i2c.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace bmp280_i2c { + +bool BMP280I2CComponent::read_byte(uint8_t a_register, uint8_t *data) { + return I2CDevice::read_byte(a_register, data); +}; +bool BMP280I2CComponent::write_byte(uint8_t a_register, uint8_t data) { + return I2CDevice::write_byte(a_register, data); +}; +bool BMP280I2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + return I2CDevice::read_bytes(a_register, data, len); +}; +bool BMP280I2CComponent::read_byte_16(uint8_t a_register, uint16_t *data) { + return I2CDevice::read_byte_16(a_register, data); +}; + +void BMP280I2CComponent::dump_config() { + LOG_I2C_DEVICE(this); + BMP280Component::dump_config(); +} + +} // namespace bmp280_i2c +} // namespace esphome diff --git a/esphome/components/bmp280_i2c/bmp280_i2c.h b/esphome/components/bmp280_i2c/bmp280_i2c.h new file mode 100644 index 0000000000..66d78d788b --- /dev/null +++ b/esphome/components/bmp280_i2c/bmp280_i2c.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/components/bmp280_base/bmp280_base.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace bmp280_i2c { + +static const char *const TAG = "bmp280_i2c.sensor"; + +/// This class implements support for the BMP280 Temperature+Pressure i2c sensor. +class BMP280I2CComponent : public esphome::bmp280_base::BMP280Component, public i2c::I2CDevice { + public: + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool read_byte_16(uint8_t a_register, uint16_t *data) override; + void dump_config() override; +}; + +} // namespace bmp280_i2c +} // namespace esphome diff --git a/esphome/components/bmp280_i2c/sensor.py b/esphome/components/bmp280_i2c/sensor.py new file mode 100644 index 0000000000..991bb827a3 --- /dev/null +++ b/esphome/components/bmp280_i2c/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from ..bmp280_base import to_code_base, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["bmp280_base"] +CODEOWNERS = ["@ademuri"] +DEPENDENCIES = ["i2c"] + +bmp280_ns = cg.esphome_ns.namespace("bmp280_i2c") +BMP280I2CComponent = bmp280_ns.class_( + "BMP280I2CComponent", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( + i2c.i2c_device_schema(default_address=0x77) +).extend({cv.GenerateID(): cv.declare_id(BMP280I2CComponent)}) + + +async def to_code(config): + var = await to_code_base(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp280_spi/__init__.py b/esphome/components/bmp280_spi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/bmp280_spi/bmp280_spi.cpp b/esphome/components/bmp280_spi/bmp280_spi.cpp new file mode 100644 index 0000000000..a35e829432 --- /dev/null +++ b/esphome/components/bmp280_spi/bmp280_spi.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include "bmp280_spi.h" +#include + +namespace esphome { +namespace bmp280_spi { + +uint8_t set_bit(uint8_t num, uint8_t position) { + uint8_t mask = 1 << position; + return num | mask; +} + +uint8_t clear_bit(uint8_t num, uint8_t position) { + uint8_t mask = 1 << position; + return num & ~mask; +} + +void BMP280SPIComponent::setup() { + this->spi_setup(); + BMP280Component::setup(); +}; + +// In SPI mode, only 7 bits of the register addresses are used; the MSB of register address is not used +// and replaced by a read/write bit (RW = ‘0’ for write and RW = ‘1’ for read). +// Example: address 0xF7 is accessed by using SPI register address 0x77. For write access, the byte +// 0x77 is transferred, for read access, the byte 0xF7 is transferred. +// https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf + +bool BMP280SPIComponent::read_byte(uint8_t a_register, uint8_t *data) { + this->enable(); + this->transfer_byte(set_bit(a_register, 7)); + *data = this->transfer_byte(0); + this->disable(); + return true; +} + +bool BMP280SPIComponent::write_byte(uint8_t a_register, uint8_t data) { + this->enable(); + this->transfer_byte(clear_bit(a_register, 7)); + this->transfer_byte(data); + this->disable(); + return true; +} + +bool BMP280SPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) { + this->enable(); + this->transfer_byte(set_bit(a_register, 7)); + this->read_array(data, len); + this->disable(); + return true; +} + +bool BMP280SPIComponent::read_byte_16(uint8_t a_register, uint16_t *data) { + this->enable(); + this->transfer_byte(set_bit(a_register, 7)); + ((uint8_t *) data)[1] = this->transfer_byte(0); + ((uint8_t *) data)[0] = this->transfer_byte(0); + this->disable(); + return true; +} + +} // namespace bmp280_spi +} // namespace esphome diff --git a/esphome/components/bmp280_spi/bmp280_spi.h b/esphome/components/bmp280_spi/bmp280_spi.h new file mode 100644 index 0000000000..dd226502f6 --- /dev/null +++ b/esphome/components/bmp280_spi/bmp280_spi.h @@ -0,0 +1,20 @@ +#pragma once + +#include "esphome/components/bmp280_base/bmp280_base.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace bmp280_spi { + +class BMP280SPIComponent : public esphome::bmp280_base::BMP280Component, + public spi::SPIDevice { + void setup() override; + bool read_byte(uint8_t a_register, uint8_t *data) override; + bool write_byte(uint8_t a_register, uint8_t data) override; + bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override; + bool read_byte_16(uint8_t a_register, uint16_t *data) override; +}; + +} // namespace bmp280_spi +} // namespace esphome diff --git a/esphome/components/bmp280_spi/sensor.py b/esphome/components/bmp280_spi/sensor.py new file mode 100644 index 0000000000..511d45b24e --- /dev/null +++ b/esphome/components/bmp280_spi/sensor.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi +from ..bmp280_base import to_code_base, CONFIG_SCHEMA_BASE + +AUTO_LOAD = ["bmp280_base"] +CODEOWNERS = ["@ademuri"] +DEPENDENCIES = ["spi"] + +bmp280_ns = cg.esphome_ns.namespace("bmp280_spi") +BMP280SPIComponent = bmp280_ns.class_( + "BMP280SPIComponent", cg.PollingComponent, spi.SPIDevice +) + +CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( + spi.spi_device_schema(default_mode="mode3") +).extend({cv.GenerateID(): cv.declare_id(BMP280SPIComponent)}) + + +async def to_code(config): + var = await to_code_base(config) + await spi.register_spi_device(var, config) diff --git a/tests/components/bmp280/test.esp32-ard.yaml b/tests/components/bmp280/test.esp32-ard.yaml deleted file mode 100644 index aeb1cb262b..0000000000 --- a/tests/components/bmp280/test.esp32-ard.yaml +++ /dev/null @@ -1,15 +0,0 @@ -i2c: - - id: i2c_bmp280 - scl: 16 - sda: 17 - -sensor: - - platform: bmp280 - address: 0x77 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - iir_filter: 16x - update_interval: 15s diff --git a/tests/components/bmp280/test.esp32-c3-ard.yaml b/tests/components/bmp280/test.esp32-c3-ard.yaml deleted file mode 100644 index 5f7f85d3e2..0000000000 --- a/tests/components/bmp280/test.esp32-c3-ard.yaml +++ /dev/null @@ -1,15 +0,0 @@ -i2c: - - id: i2c_bmp280 - scl: 5 - sda: 4 - -sensor: - - platform: bmp280 - address: 0x77 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - iir_filter: 16x - update_interval: 15s diff --git a/tests/components/bmp280/test.esp32-idf.yaml b/tests/components/bmp280/test.esp32-idf.yaml deleted file mode 100644 index aeb1cb262b..0000000000 --- a/tests/components/bmp280/test.esp32-idf.yaml +++ /dev/null @@ -1,15 +0,0 @@ -i2c: - - id: i2c_bmp280 - scl: 16 - sda: 17 - -sensor: - - platform: bmp280 - address: 0x77 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - iir_filter: 16x - update_interval: 15s diff --git a/tests/components/bmp280/test.esp8266-ard.yaml b/tests/components/bmp280/test.esp8266-ard.yaml deleted file mode 100644 index 5f7f85d3e2..0000000000 --- a/tests/components/bmp280/test.esp8266-ard.yaml +++ /dev/null @@ -1,15 +0,0 @@ -i2c: - - id: i2c_bmp280 - scl: 5 - sda: 4 - -sensor: - - platform: bmp280 - address: 0x77 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - iir_filter: 16x - update_interval: 15s diff --git a/tests/components/bmp280/test.rp2040-ard.yaml b/tests/components/bmp280/test.rp2040-ard.yaml deleted file mode 100644 index 5f7f85d3e2..0000000000 --- a/tests/components/bmp280/test.rp2040-ard.yaml +++ /dev/null @@ -1,15 +0,0 @@ -i2c: - - id: i2c_bmp280 - scl: 5 - sda: 4 - -sensor: - - platform: bmp280 - address: 0x77 - temperature: - name: Outside Temperature - oversampling: 16x - pressure: - name: Outside Pressure - iir_filter: 16x - update_interval: 15s diff --git a/tests/components/bmp280/test.esp32-c3-idf.yaml b/tests/components/bmp280_i2c/common.yaml similarity index 56% rename from tests/components/bmp280/test.esp32-c3-idf.yaml rename to tests/components/bmp280_i2c/common.yaml index 5f7f85d3e2..edf52b2cd4 100644 --- a/tests/components/bmp280/test.esp32-c3-idf.yaml +++ b/tests/components/bmp280_i2c/common.yaml @@ -1,15 +1,17 @@ i2c: - id: i2c_bmp280 - scl: 5 - sda: 4 + scl: ${scl_pin} + sda: ${sda_pin} sensor: - - platform: bmp280 + - platform: bmp280_i2c + i2c_id: i2c_bmp280 address: 0x77 temperature: + id: bmp280_temperature name: Outside Temperature - oversampling: 16x pressure: name: Outside Pressure + id: bmp280_pressure iir_filter: 16x update_interval: 15s diff --git a/tests/components/bmp280_i2c/test.esp32-ard.yaml b/tests/components/bmp280_i2c/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bmp280_i2c/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bmp280_i2c/test.esp32-c3-ard.yaml b/tests/components/bmp280_i2c/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp280_i2c/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp280_i2c/test.esp32-c3-idf.yaml b/tests/components/bmp280_i2c/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp280_i2c/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp280_i2c/test.esp32-idf.yaml b/tests/components/bmp280_i2c/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/bmp280_i2c/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/bmp280_i2c/test.esp8266-ard.yaml b/tests/components/bmp280_i2c/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp280_i2c/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp280_i2c/test.rp2040-ard.yaml b/tests/components/bmp280_i2c/test.rp2040-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/bmp280_i2c/test.rp2040-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/common.yaml b/tests/components/bmp280_spi/common.yaml new file mode 100644 index 0000000000..798804de5b --- /dev/null +++ b/tests/components/bmp280_spi/common.yaml @@ -0,0 +1,18 @@ +spi: + - id: spi_bmp280 + clk_pin: ${clk_pin} + mosi_pin: ${mosi_pin} + miso_pin: ${miso_pin} + +sensor: + - platform: bmp280_spi + spi_id: spi_bmp280 + cs_pin: ${cs_pin} + temperature: + id: bmp280_temperature + name: Outside Temperature + pressure: + name: Outside Pressure + id: bmp280_pressure + iir_filter: 16x + update_interval: 15s diff --git a/tests/components/bmp280_spi/test.esp32-ard.yaml b/tests/components/bmp280_spi/test.esp32-ard.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/bmp280_spi/test.esp32-ard.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/test.esp32-c3-ard.yaml b/tests/components/bmp280_spi/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/bmp280_spi/test.esp32-c3-ard.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/test.esp32-c3-idf.yaml b/tests/components/bmp280_spi/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..2415ba5dc6 --- /dev/null +++ b/tests/components/bmp280_spi/test.esp32-c3-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO6 + mosi_pin: GPIO7 + miso_pin: GPIO5 + cs_pin: GPIO8 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/test.esp32-idf.yaml b/tests/components/bmp280_spi/test.esp32-idf.yaml new file mode 100644 index 0000000000..54e027a614 --- /dev/null +++ b/tests/components/bmp280_spi/test.esp32-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO16 + mosi_pin: GPIO17 + miso_pin: GPIO15 + cs_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/test.esp8266-ard.yaml b/tests/components/bmp280_spi/test.esp8266-ard.yaml new file mode 100644 index 0000000000..dbd158d030 --- /dev/null +++ b/tests/components/bmp280_spi/test.esp8266-ard.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + cs_pin: GPIO15 + +<<: !include common.yaml diff --git a/tests/components/bmp280_spi/test.rp2040-ard.yaml b/tests/components/bmp280_spi/test.rp2040-ard.yaml new file mode 100644 index 0000000000..f6c3f1eeca --- /dev/null +++ b/tests/components/bmp280_spi/test.rp2040-ard.yaml @@ -0,0 +1,7 @@ +substitutions: + clk_pin: GPIO2 + mosi_pin: GPIO3 + miso_pin: GPIO4 + cs_pin: GPIO5 + +<<: !include common.yaml From 8bd46a43b94cb230298cf8d591af386f0022fcca Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 8 Sep 2024 19:54:20 -0500 Subject: [PATCH 2350/2607] Add voice assistant announce (#7377) --- esphome/components/api/api.proto | 17 ++++++ esphome/components/api/api_connection.cpp | 10 ++++ esphome/components/api/api_connection.h | 1 + esphome/components/api/api_pb2.cpp | 53 +++++++++++++++++++ esphome/components/api/api_pb2.h | 23 ++++++++ esphome/components/api/api_pb2_service.cpp | 21 ++++++++ esphome/components/api/api_pb2_service.h | 6 +++ .../voice_assistant/voice_assistant.cpp | 16 ++++++ .../voice_assistant/voice_assistant.h | 1 + 9 files changed, 148 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index ad6fc79cf3..1c40e8014e 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1553,6 +1553,23 @@ message VoiceAssistantTimerEventResponse { bool is_active = 6; } +message VoiceAssistantAnnounceRequest { + option (id) = 119; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + string media_id = 1; + string text = 2; +} + +message VoiceAssistantAnnounceFinished { + option (id) = 120; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + bool success = 1; +} + // ==================== ALARM CONTROL PANEL ==================== enum AlarmControlPanelState { ALARM_STATE_DISARMED = 0; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index a655d06e66..6b7051a704 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1213,6 +1213,16 @@ void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistant } }; +void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return; + } + + voice_assistant::global_voice_assistant->on_announce(msg); + } +} + #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 714e806470..e8d66a5e07 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -151,6 +151,7 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; + void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override; #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index c944d0dae8..2a1552d6fc 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7061,6 +7061,59 @@ void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->media_id = value.as_string(); + return true; + } + case 2: { + this->text = value.as_string(); + return true; + } + default: + return false; + } +} +void VoiceAssistantAnnounceRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->media_id); + buffer.encode_string(2, this->text); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAnnounceRequest {\n"); + out.append(" media_id: "); + out.append("'").append(this->media_id).append("'"); + out.append("\n"); + + out.append(" text: "); + out.append("'").append(this->text).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantAnnounceFinished::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->success = value.as_bool(); + return true; + } + default: + return false; + } +} +void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->success); } +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAnnounceFinished {\n"); + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + out.append("}"); +} +#endif bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 3f609c793c..6fab1f57e0 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1825,6 +1825,29 @@ class VoiceAssistantTimerEventResponse : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantAnnounceRequest : public ProtoMessage { + public: + std::string media_id{}; + std::string text{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; +}; +class VoiceAssistantAnnounceFinished : public ProtoMessage { + public: + bool success{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 269a755e9e..faa977389a 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -486,6 +486,16 @@ bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAud #endif #ifdef USE_VOICE_ASSISTANT #endif +#ifdef USE_VOICE_ASSISTANT +#endif +#ifdef USE_VOICE_ASSISTANT +bool APIServerConnectionBase::send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_voice_assistant_announce_finished: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 120); +} +#endif #ifdef USE_ALARM_CONTROL_PANEL bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( const ListEntitiesAlarmControlPanelResponse &msg) { @@ -1135,6 +1145,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); #endif this->on_update_command_request(msg); +#endif + break; + } + case 119: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantAnnounceRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_announce_request(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 83bfc2ed98..f3803ad628 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -247,6 +247,12 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){}; #endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &value){}; +#endif +#ifdef USE_VOICE_ASSISTANT + bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg); +#endif #ifdef USE_ALARM_CONTROL_PANEL bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); #endif diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 43c7428858..577de630fb 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -396,6 +396,10 @@ void VoiceAssistant::loop() { this->set_timeout("playing", 2000, [this]() { this->cancel_timeout("speaker-timeout"); this->set_state_(State::IDLE, State::IDLE); + + api::VoiceAssistantAnnounceFinished msg; + msg.success = true; + this->api_client_->send_voice_assistant_announce_finished(msg); }); } break; @@ -866,6 +870,18 @@ void VoiceAssistant::timer_tick_() { this->timer_tick_trigger_->trigger(res); } +void VoiceAssistant::on_announce(const api::VoiceAssistantAnnounceRequest &msg) { +#ifdef USE_MEDIA_PLAYER + if (this->media_player_ != nullptr) { + this->tts_start_trigger_->trigger(msg.text); + this->media_player_->make_call().set_media_url(msg.media_id).set_announcement(true).perform(); + this->set_state_(State::STREAMING_RESPONSE, State::STREAMING_RESPONSE); + this->tts_end_trigger_->trigger(msg.media_id); + this->end_trigger_->trigger(); + } +#endif +} + VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace voice_assistant diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 88cb0dd413..b0a172332f 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -132,6 +132,7 @@ class VoiceAssistant : public Component { void on_event(const api::VoiceAssistantEventResponse &msg); void on_audio(const api::VoiceAssistantAudio &msg); void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg); + void on_announce(const api::VoiceAssistantAnnounceRequest &msg); bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } From 9722876ef667a628e1df3d7623e73db14c8d2d2f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:59:09 +1000 Subject: [PATCH 2351/2607] [lvgl] Msgbox fixes and enhancements (#7380) --- esphome/components/lvgl/automation.py | 16 +++++--- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/widgets/__init__.py | 2 + esphome/components/lvgl/widgets/msgbox.py | 41 +++++++++++++-------- tests/components/lvgl/lvgl-package.yaml | 24 ++++++++++++ 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index 8138551c30..cdc7553e81 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -229,19 +229,23 @@ async def obj_hide_to_code(config, action_id, template_arg, args): async def do_hide(widget: Widget): widget.add_flag("LV_OBJ_FLAG_HIDDEN") - return await action_to_code( - await get_widgets(config), do_hide, action_id, template_arg, args - ) + widgets = [ + widget.outer if widget.outer else widget for widget in await get_widgets(config) + ] + return await action_to_code(widgets, do_hide, action_id, template_arg, args) @automation.register_action("lvgl.widget.show", ObjUpdateAction, LIST_ACTION_SCHEMA) async def obj_show_to_code(config, action_id, template_arg, args): async def do_show(widget: Widget): widget.clear_flag("LV_OBJ_FLAG_HIDDEN") + if widget.move_to_foreground: + lv_obj.move_foreground(widget.obj) - return await action_to_code( - await get_widgets(config), do_show, action_id, template_arg, args - ) + widgets = [ + widget.outer if widget.outer else widget for widget in await get_widgets(config) + ] + return await action_to_code(widgets, do_show, action_id, template_arg, args) def focused_id(value): diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index e05bf52120..ee8472f90d 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -374,6 +374,7 @@ CONF_ANTIALIAS = "antialias" CONF_ARC_LENGTH = "arc_length" CONF_AUTO_START = "auto_start" CONF_BACKGROUND_STYLE = "background_style" +CONF_BUTTON_STYLE = "button_style" CONF_DECIMAL_PLACES = "decimal_places" CONF_COLUMN = "column" CONF_DIGITS = "digits" diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index ae06bf20b0..e093cebd16 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -89,6 +89,8 @@ class Widget: self.obj = MockObj(f"{self.var}->obj") else: self.obj = var + self.outer = None + self.move_to_foreground = False @staticmethod def create(name, var, wtype: WidgetType, config: dict = None): diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index c377af6bde..1af4ed6e05 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -1,11 +1,12 @@ from esphome import config_validation as cv -from esphome.const import CONF_BUTTON, CONF_ID, CONF_TEXT +from esphome.const import CONF_BUTTON, CONF_ID, CONF_ITEMS, CONF_TEXT from esphome.core import ID from esphome.cpp_generator import new_Pvariable, static_const_array from esphome.cpp_types import nullptr from ..defines import ( CONF_BODY, + CONF_BUTTON_STYLE, CONF_BUTTONS, CONF_CLOSE_BUTTON, CONF_MSGBOXES, @@ -25,7 +26,7 @@ from ..lvcode import ( lv_obj, lv_Pvariable, ) -from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema +from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema from ..styles import TOP_LAYER from ..types import LV_EVENT, char_ptr, lv_obj_t from . import Widget, set_obj_properties @@ -48,9 +49,10 @@ MSGBOX_SCHEMA = container_schema( { cv.GenerateID(CONF_ID): cv.declare_id(lv_obj_t), cv.Required(CONF_TITLE): STYLED_TEXT_SCHEMA, - cv.Optional(CONF_BODY): STYLED_TEXT_SCHEMA, + cv.Optional(CONF_BODY, default=""): STYLED_TEXT_SCHEMA, cv.Optional(CONF_BUTTONS): cv.ensure_list(BUTTONMATRIX_BUTTON_SCHEMA), - cv.Optional(CONF_CLOSE_BUTTON): lv_bool, + cv.Optional(CONF_BUTTON_STYLE): part_schema(buttonmatrix_spec), + cv.Optional(CONF_CLOSE_BUTTON, default=True): lv_bool, cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr), } ), @@ -74,7 +76,8 @@ async def msgbox_to_code(conf): ) lvgl_components_required.add("BUTTONMATRIX") messagebox_id = conf[CONF_ID] - outer = lv_Pvariable(lv_obj_t, messagebox_id.id) + outer_id = f"{messagebox_id.id}_outer" + outer = lv_Pvariable(lv_obj_t, messagebox_id.id + "_outer") buttonmatrix = new_Pvariable( ID( f"{messagebox_id.id}_buttonmatrix_", @@ -82,8 +85,11 @@ async def msgbox_to_code(conf): type=lv_buttonmatrix_t, ) ) - msgbox = lv_Pvariable(lv_obj_t, f"{messagebox_id.id}_msgbox") - outer_widget = Widget.create(messagebox_id, outer, obj_spec, conf) + msgbox = lv_Pvariable(lv_obj_t, messagebox_id.id) + outer_widget = Widget.create(outer_id, outer, obj_spec, conf) + outer_widget.move_to_foreground = True + msgbox_widget = Widget.create(messagebox_id, msgbox, obj_spec, conf) + msgbox_widget.outer = outer_widget buttonmatrix_widget = Widget.create( str(buttonmatrix), buttonmatrix, buttonmatrix_spec, conf ) @@ -92,10 +98,8 @@ async def msgbox_to_code(conf): ) text_id = conf[CONF_BUTTON_TEXT_LIST_ID] text_list = static_const_array(text_id, text_list) - if (text := conf.get(CONF_BODY)) is not None: - text = await lv_text.process(text.get(CONF_TEXT)) - if (title := conf.get(CONF_TITLE)) is not None: - title = await lv_text.process(title.get(CONF_TEXT)) + text = await lv_text.process(conf[CONF_BODY].get(CONF_TEXT, "")) + title = await lv_text.process(conf[CONF_TITLE].get(CONF_TEXT, "")) close_button = conf[CONF_CLOSE_BUTTON] lv_assign(outer, lv_expr.obj_create(TOP_LAYER)) lv_obj.set_width(outer, lv_pct(100)) @@ -111,20 +115,27 @@ async def msgbox_to_code(conf): ) lv_obj.set_style_align(msgbox, literal("LV_ALIGN_CENTER"), 0) lv_add(buttonmatrix.set_obj(lv_expr.msgbox_get_btns(msgbox))) - await set_obj_properties(outer_widget, conf) + if button_style := conf.get(CONF_BUTTON_STYLE): + button_style = {CONF_ITEMS: button_style} + await set_obj_properties(buttonmatrix_widget, button_style) + await set_obj_properties(msgbox_widget, conf) + async with LambdaContext(EVENT_ARG, where=messagebox_id) as close_action: + outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN") if close_button: - async with LambdaContext(EVENT_ARG, where=messagebox_id) as context: - outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN") with LocalVariable( "close_btn_", lv_obj_t, lv_expr.msgbox_get_close_btn(msgbox) ) as close_btn: lv_obj.remove_event_cb(close_btn, nullptr) lv_obj.add_event_cb( close_btn, - await context.get_lambda(), + await close_action.get_lambda(), LV_EVENT.CLICKED, nullptr, ) + else: + lv_obj.add_event_cb( + outer, await close_action.get_lambda(), LV_EVENT.CLICKED, nullptr + ) if len(ctrl_list) != 0 or len(width_list) != 0: set_btn_data(buttonmatrix.obj, ctrl_list, width_list) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 0feb6d6ce6..0db6a6a995 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -52,6 +52,29 @@ lvgl: - touchscreen_id: tft_touch long_press_repeat_time: 200ms long_press_time: 500ms + + msgboxes: + - id: message_box + close_button: true + title: Messagebox + bg_color: 0xffff + body: + text: This is a sample messagebox + bg_color: 0x808080 + button_style: + bg_color: 0xff00 + border_width: 4 + buttons: + - id: msgbox_button + text: Button + - id: msgbox_apply + text: "Close" + on_click: + then: + - lvgl.widget.hide: message_box + - id: simple_msgbox + title: Simple + pages: - id: page1 on_load: @@ -98,6 +121,7 @@ lvgl: - lvgl.update: disp_bg_color: 0xffff00 disp_bg_image: cat_image + - lvgl.widget.show: message_box - label: text: "Hello shiny day" text_color: 0xFFFFFF From 32995a352bc224da579056969192c250717b8b51 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 9 Sep 2024 06:05:09 +0100 Subject: [PATCH 2352/2607] libretiny: Allow specifying version of explicitly imported sources (#7408) --- esphome/components/libretiny/__init__.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index a8034f8fab..a640e2e9b9 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -1,10 +1,6 @@ import json import logging -from os.path import ( - dirname, - isfile, - join, -) +from os.path import dirname, isfile, join import esphome.codegen as cg import esphome.config_validation as cv @@ -282,10 +278,10 @@ async def component_to_code(config): # if platform version is a valid version constraint, prefix the default package framework = config[CONF_FRAMEWORK] cv.platformio_version_constraint(framework[CONF_VERSION]) - if str(framework[CONF_VERSION]) != "0.0.0": - cg.add_platformio_option("platform", f"libretiny @ {framework[CONF_VERSION]}") - elif framework[CONF_SOURCE]: + if framework[CONF_SOURCE]: cg.add_platformio_option("platform", framework[CONF_SOURCE]) + elif str(framework[CONF_VERSION]) != "0.0.0": + cg.add_platformio_option("platform", f"libretiny @ {framework[CONF_VERSION]}") else: cg.add_platformio_option("platform", "libretiny") From 7a93dde5d4611c22ee9471640f9c7e848bbe7d7e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 9 Sep 2024 06:05:19 +0100 Subject: [PATCH 2353/2607] [libretiny] Report version 1.7.0 for 'dev' and 'latest' (#7415) --- esphome/components/libretiny/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index a640e2e9b9..9ba889f493 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -172,9 +172,10 @@ def _notify_old_style(config): # NOTE: Keep this in mind when updating the recommended version: # * For all constants below, update platformio.ini (in this repo) +# The dev and latest branches will be at *least* this version, which is what matters. ARDUINO_VERSIONS = { - "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"), - "latest": (cv.Version(0, 0, 0), None), + "dev": (cv.Version(1, 7, 0), "https://github.com/libretiny-eu/libretiny.git"), + "latest": (cv.Version(1, 7, 0), "libretiny"), "recommended": (cv.Version(1, 5, 1), None), } From c90dcfc0ca681ffeb025cf520a2d9ac458c0e510 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Mon, 9 Sep 2024 19:25:37 +0200 Subject: [PATCH 2354/2607] LTR-501, LTR-301, LTR-558 Series of Lite-On Light (ALS) and Proximity(PS) sensors (#6262) Co-authored-by: root Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/ltr501/__init__.py | 1 + esphome/components/ltr501/ltr501.cpp | 542 ++++++++++++++++++ esphome/components/ltr501/ltr501.h | 184 ++++++ .../components/ltr501/ltr_definitions_501.h | 260 +++++++++ esphome/components/ltr501/sensor.py | 274 +++++++++ esphome/components/ltr_als_ps/sensor.py | 4 +- esphome/components/veml7700/sensor.py | 4 +- esphome/const.py | 2 + tests/components/ltr501/common.yaml | 9 + tests/components/ltr501/test.esp32-ard.yaml | 6 + .../components/ltr501/test.esp32-c3-ard.yaml | 6 + .../components/ltr501/test.esp32-c3-idf.yaml | 6 + tests/components/ltr501/test.esp32-idf.yaml | 6 + tests/components/ltr501/test.esp8266-ard.yaml | 6 + tests/components/ltr501/test.rp2040-ard.yaml | 6 + 16 files changed, 1313 insertions(+), 4 deletions(-) create mode 100644 esphome/components/ltr501/__init__.py create mode 100644 esphome/components/ltr501/ltr501.cpp create mode 100644 esphome/components/ltr501/ltr501.h create mode 100644 esphome/components/ltr501/ltr_definitions_501.h create mode 100644 esphome/components/ltr501/sensor.py create mode 100644 tests/components/ltr501/common.yaml create mode 100644 tests/components/ltr501/test.esp32-ard.yaml create mode 100644 tests/components/ltr501/test.esp32-c3-ard.yaml create mode 100644 tests/components/ltr501/test.esp32-c3-idf.yaml create mode 100644 tests/components/ltr501/test.esp32-idf.yaml create mode 100644 tests/components/ltr501/test.esp8266-ard.yaml create mode 100644 tests/components/ltr501/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 1d4df3ccb8..0b1b88fbc8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -227,6 +227,7 @@ esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lock/* @esphome/core esphome/components/logger/* @esphome/core esphome/components/ltr390/* @latonita @sjtrny +esphome/components/ltr501/* @latonita esphome/components/ltr_als_ps/* @latonita esphome/components/lvgl/* @clydebarrow esphome/components/m5stack_8angle/* @rnauber diff --git a/esphome/components/ltr501/__init__.py b/esphome/components/ltr501/__init__.py new file mode 100644 index 0000000000..dd06cfffea --- /dev/null +++ b/esphome/components/ltr501/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@latonita"] diff --git a/esphome/components/ltr501/ltr501.cpp b/esphome/components/ltr501/ltr501.cpp new file mode 100644 index 0000000000..4f4e26f44f --- /dev/null +++ b/esphome/components/ltr501/ltr501.cpp @@ -0,0 +1,542 @@ +#include "ltr501.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +using esphome::i2c::ErrorCode; + +namespace esphome { +namespace ltr501 { + +static const char *const TAG = "ltr501"; + +static const uint8_t MAX_TRIES = 5; +static const uint8_t MAX_SENSITIVITY_ADJUSTMENTS = 10; + +struct GainTimePair { + AlsGain501 gain; + IntegrationTime501 time; +}; + +bool operator==(const GainTimePair &lhs, const GainTimePair &rhs) { + return lhs.gain == rhs.gain && lhs.time == rhs.time; +} + +bool operator!=(const GainTimePair &lhs, const GainTimePair &rhs) { + return !(lhs.gain == rhs.gain && lhs.time == rhs.time); +} + +template T get_next(const T (&array)[size], const T val) { + size_t i = 0; + size_t idx = -1; + while (idx == -1 && i < size) { + if (array[i] == val) { + idx = i; + break; + } + i++; + } + if (idx == -1 || i + 1 >= size) + return val; + return array[i + 1]; +} + +template T get_prev(const T (&array)[size], const T val) { + size_t i = size - 1; + size_t idx = -1; + while (idx == -1 && i > 0) { + if (array[i] == val) { + idx = i; + break; + } + i--; + } + if (idx == -1 || i == 0) + return val; + return array[i - 1]; +} + +static uint16_t get_itime_ms(IntegrationTime501 time) { + static const uint16_t ALS_INT_TIME[4] = {100, 50, 200, 400}; + return ALS_INT_TIME[time & 0b11]; +} + +static uint16_t get_meas_time_ms(MeasurementRepeatRate rate) { + static const uint16_t ALS_MEAS_RATE[8] = {50, 100, 200, 500, 1000, 2000, 2000, 2000}; + return ALS_MEAS_RATE[rate & 0b111]; +} + +static float get_gain_coeff(AlsGain501 gain) { return gain == AlsGain501::GAIN_1 ? 1.0f : 150.0f; } + +static float get_ps_gain_coeff(PsGain501 gain) { + static const float PS_GAIN[4] = {1, 4, 8, 16}; + return PS_GAIN[gain & 0b11]; +} + +void LTRAlsPs501Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up LTR-501/301/558"); + // As per datasheet we need to wait at least 100ms after power on to get ALS chip responsive + this->set_timeout(100, [this]() { this->state_ = State::DELAYED_SETUP; }); +} + +void LTRAlsPs501Component::dump_config() { + auto get_device_type = [](LtrType typ) { + switch (typ) { + case LtrType::LTR_TYPE_ALS_ONLY: + return "ALS only"; + case LtrType::LTR_TYPE_PS_ONLY: + return "PS only"; + case LtrType::LTR_TYPE_ALS_AND_PS: + return "Als + PS"; + default: + return "Unknown"; + } + }; + + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Device type: %s", get_device_type(this->ltr_type_)); + ESP_LOGCONFIG(TAG, " Automatic mode: %s", ONOFF(this->automatic_mode_enabled_)); + ESP_LOGCONFIG(TAG, " Gain: %.0fx", get_gain_coeff(this->gain_)); + ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); + ESP_LOGCONFIG(TAG, " Measurement repeat rate: %d ms", get_meas_time_ms(this->repeat_rate_)); + ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + ESP_LOGCONFIG(TAG, " Proximity gain: %.0fx", get_ps_gain_coeff(this->ps_gain_)); + ESP_LOGCONFIG(TAG, " Proximity cooldown time: %d s", this->ps_cooldown_time_s_); + ESP_LOGCONFIG(TAG, " Proximity high threshold: %d", this->ps_threshold_high_); + ESP_LOGCONFIG(TAG, " Proximity low threshold: %d", this->ps_threshold_low_); + + LOG_UPDATE_INTERVAL(this); + + LOG_SENSOR(" ", "ALS calculated lux", this->ambient_light_sensor_); + LOG_SENSOR(" ", "CH1 Infrared counts", this->infrared_counts_sensor_); + LOG_SENSOR(" ", "CH0 Visible+IR counts", this->full_spectrum_counts_sensor_); + LOG_SENSOR(" ", "Actual gain", this->actual_gain_sensor_); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with I2C LTR-501/301/558 failed!"); + } +} + +void LTRAlsPs501Component::update() { + if (!this->is_als_()) { + ESP_LOGW(TAG, "Update. ALS data not available. Change configuration to ALS or ALS_PS."); + return; + } + if (this->is_ready() && this->is_als_() && this->state_ == State::IDLE) { + ESP_LOGV(TAG, "Update. Initiating new ALS data collection."); + + this->state_ = this->automatic_mode_enabled_ ? State::COLLECTING_DATA_AUTO : State::WAITING_FOR_DATA; + + this->als_readings_.ch0 = 0; + this->als_readings_.ch1 = 0; + this->als_readings_.gain = this->gain_; + this->als_readings_.integration_time = this->integration_time_; + this->als_readings_.lux = 0; + this->als_readings_.number_of_adjustments = 0; + + } else { + ESP_LOGV(TAG, "Update. Component not ready yet."); + } +} + +void LTRAlsPs501Component::loop() { + ErrorCode err = i2c::ERROR_OK; + static uint8_t tries{0}; + + switch (this->state_) { + case State::DELAYED_SETUP: + err = this->write(nullptr, 0); + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "i2c connection failed"); + this->mark_failed(); + } + this->configure_reset_(); + if (this->is_als_()) { + this->configure_als_(); + this->configure_integration_time_(this->integration_time_); + } + if (this->is_ps_()) { + this->configure_ps_(); + } + + this->state_ = State::IDLE; + break; + + case State::IDLE: + if (this->is_ps_()) { + this->check_and_trigger_ps_(); + } + break; + + case State::WAITING_FOR_DATA: + if (this->is_als_data_ready_(this->als_readings_) == DataAvail::DATA_OK) { + tries = 0; + ESP_LOGV(TAG, "Reading sensor data assuming gain = %.0fx, time = %d ms", + get_gain_coeff(this->als_readings_.gain), get_itime_ms(this->als_readings_.integration_time)); + this->read_sensor_data_(this->als_readings_); + this->apply_lux_calculation_(this->als_readings_); + this->state_ = State::DATA_COLLECTED; + } else if (tries >= MAX_TRIES) { + ESP_LOGW(TAG, "Can't get data after several tries. Aborting."); + tries = 0; + this->status_set_warning(); + this->state_ = State::IDLE; + return; + } else { + tries++; + } + break; + + case State::COLLECTING_DATA_AUTO: + case State::DATA_COLLECTED: + // first measurement in auto mode (COLLECTING_DATA_AUTO state) require device reconfiguration + if (this->state_ == State::COLLECTING_DATA_AUTO || this->are_adjustments_required_(this->als_readings_)) { + this->state_ = State::ADJUSTMENT_IN_PROGRESS; + ESP_LOGD(TAG, "Reconfiguring sensitivity: gain = %.0fx, time = %d ms", get_gain_coeff(this->als_readings_.gain), + get_itime_ms(this->als_readings_.integration_time)); + this->configure_integration_time_(this->als_readings_.integration_time); + this->configure_gain_(this->als_readings_.gain); + // if sensitivity adjustment needed - need to wait for first data samples after setting new parameters + this->set_timeout(2 * get_meas_time_ms(this->repeat_rate_), + [this]() { this->state_ = State::WAITING_FOR_DATA; }); + } else { + this->state_ = State::READY_TO_PUBLISH; + } + break; + + case State::ADJUSTMENT_IN_PROGRESS: + // nothing to be done, just waiting for the timeout + break; + + case State::READY_TO_PUBLISH: + this->publish_data_part_1_(this->als_readings_); + this->state_ = State::KEEP_PUBLISHING; + break; + + case State::KEEP_PUBLISHING: + this->publish_data_part_2_(this->als_readings_); + this->status_clear_warning(); + this->state_ = State::IDLE; + break; + + default: + break; + } +} + +void LTRAlsPs501Component::check_and_trigger_ps_() { + static uint32_t last_high_trigger_time{0}; + static uint32_t last_low_trigger_time{0}; + uint16_t ps_data = this->read_ps_data_(); + uint32_t now = millis(); + + if (ps_data != this->ps_readings_) { + this->ps_readings_ = ps_data; + // Higher values - object is closer to sensor + if (ps_data > this->ps_threshold_high_ && now - last_high_trigger_time >= this->ps_cooldown_time_s_ * 1000) { + last_high_trigger_time = now; + ESP_LOGD(TAG, "Proximity high threshold triggered. Value = %d, Trigger level = %d", ps_data, + this->ps_threshold_high_); + this->on_ps_high_trigger_callback_.call(); + } else if (ps_data < this->ps_threshold_low_ && now - last_low_trigger_time >= this->ps_cooldown_time_s_ * 1000) { + last_low_trigger_time = now; + ESP_LOGD(TAG, "Proximity low threshold triggered. Value = %d, Trigger level = %d", ps_data, + this->ps_threshold_low_); + this->on_ps_low_trigger_callback_.call(); + } + } +} + +bool LTRAlsPs501Component::check_part_number_() { + uint8_t manuf_id = this->reg((uint8_t) CommandRegisters::MANUFAC_ID).get(); + if (manuf_id != 0x05) { // 0x05 is Lite-On Semiconductor Corp. ID + ESP_LOGW(TAG, "Unknown manufacturer ID: 0x%02X", manuf_id); + this->mark_failed(); + return false; + } + + // Things getting not really funny here, we can't identify device type by part number ID + // ======================== ========= ===== ================= + // Device Part ID Rev Capabilities + // ======================== ========= ===== ================= + // ltr-558als 0x08 0 als + ps + // ltr-501als 0x08 0 als + ps + // ltr-301als - 0x08 0 als only + + PartIdRegister part_id{0}; + part_id.raw = this->reg((uint8_t) CommandRegisters::PART_ID).get(); + if (part_id.part_number_id != 0x08) { + ESP_LOGW(TAG, "Unknown part number ID: 0x%02X. LTR-501/301 shall have 0x08. It might not work properly.", + part_id.part_number_id); + this->status_set_warning(); + return true; + } + return true; +} + +void LTRAlsPs501Component::configure_reset_() { + ESP_LOGV(TAG, "Resetting"); + + AlsControlRegister501 als_ctrl{0}; + als_ctrl.sw_reset = true; + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + + uint8_t tries = MAX_TRIES; + do { + ESP_LOGV(TAG, "Waiting chip to reset"); + delay(2); + als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + } while (als_ctrl.sw_reset && tries--); // while sw reset bit is on - keep waiting + + if (als_ctrl.sw_reset) { + ESP_LOGW(TAG, "Reset failed"); + } +} + +void LTRAlsPs501Component::configure_als_() { + AlsControlRegister501 als_ctrl{0}; + als_ctrl.sw_reset = false; + als_ctrl.als_mode_active = true; + als_ctrl.gain = this->gain_; + + ESP_LOGV(TAG, "Setting active mode and gain reg 0x%02X", als_ctrl.raw); + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(5); + + uint8_t tries = MAX_TRIES; + do { + ESP_LOGV(TAG, "Waiting for ALS device to become active..."); + delay(2); + als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + } while (!als_ctrl.als_mode_active && tries--); // while active mode is not set - keep waiting + + if (!als_ctrl.als_mode_active) { + ESP_LOGW(TAG, "Failed to activate ALS device"); + } +} + +void LTRAlsPs501Component::configure_ps_() { + PsMeasurementRateRegister ps_meas{0}; + ps_meas.ps_measurement_rate = PsMeasurementRate::PS_MEAS_RATE_50MS; + this->reg((uint8_t) CommandRegisters::PS_MEAS_RATE) = ps_meas.raw; + + PsControlRegister501 ps_ctrl{0}; + ps_ctrl.ps_mode_active = true; + ps_ctrl.ps_mode_xxx = true; + this->reg((uint8_t) CommandRegisters::PS_CONTR) = ps_ctrl.raw; +} + +uint16_t LTRAlsPs501Component::read_ps_data_() { + AlsPsStatusRegister als_status{0}; + als_status.raw = this->reg((uint8_t) CommandRegisters::ALS_PS_STATUS).get(); + if (!als_status.ps_new_data) { + return this->ps_readings_; + } + + uint8_t ps_low = this->reg((uint8_t) CommandRegisters::PS_DATA_0).get(); + PsData1Register ps_high; + ps_high.raw = this->reg((uint8_t) CommandRegisters::PS_DATA_1).get(); + + uint16_t val = encode_uint16(ps_high.ps_data_high, ps_low); + return val; +} + +void LTRAlsPs501Component::configure_gain_(AlsGain501 gain) { + AlsControlRegister501 als_ctrl{0}; + als_ctrl.als_mode_active = true; + als_ctrl.gain = gain; + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + + AlsControlRegister501 read_als_ctrl{0}; + read_als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); + if (read_als_ctrl.gain != gain) { + ESP_LOGW(TAG, "Failed to set gain. We will try one more time."); + this->reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw; + delay(2); + } +} + +void LTRAlsPs501Component::configure_integration_time_(IntegrationTime501 time) { + MeasurementRateRegister501 meas{0}; + meas.measurement_repeat_rate = this->repeat_rate_; + meas.integration_time = time; + this->reg((uint8_t) CommandRegisters::MEAS_RATE) = meas.raw; + delay(2); + + MeasurementRateRegister501 read_meas{0}; + read_meas.raw = this->reg((uint8_t) CommandRegisters::MEAS_RATE).get(); + if (read_meas.integration_time != time) { + ESP_LOGW(TAG, "Failed to set integration time. We will try one more time."); + this->reg((uint8_t) CommandRegisters::MEAS_RATE) = meas.raw; + delay(2); + } +} + +DataAvail LTRAlsPs501Component::is_als_data_ready_(AlsReadings &data) { + AlsPsStatusRegister als_status{0}; + als_status.raw = this->reg((uint8_t) CommandRegisters::ALS_PS_STATUS).get(); + if (!als_status.als_new_data) + return DataAvail::NO_DATA; + ESP_LOGV(TAG, "Data ready, reported gain is %.0fx", get_gain_coeff(als_status.gain)); + if (data.gain != als_status.gain) { + ESP_LOGW(TAG, "Actual gain differs from requested (%.0f)", get_gain_coeff(data.gain)); + return DataAvail::BAD_DATA; + } + data.gain = als_status.gain; + return DataAvail::DATA_OK; +} + +void LTRAlsPs501Component::read_sensor_data_(AlsReadings &data) { + data.ch1 = 0; + data.ch0 = 0; + uint8_t ch1_0 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH1_0).get(); + uint8_t ch1_1 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH1_1).get(); + uint8_t ch0_0 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH0_0).get(); + uint8_t ch0_1 = this->reg((uint8_t) CommandRegisters::ALS_DATA_CH0_1).get(); + data.ch1 = encode_uint16(ch1_1, ch1_0); + data.ch0 = encode_uint16(ch0_1, ch0_0); + + ESP_LOGD(TAG, "Got sensor data: CH1 = %d, CH0 = %d", data.ch1, data.ch0); +} + +bool LTRAlsPs501Component::are_adjustments_required_(AlsReadings &data) { + if (!this->automatic_mode_enabled_) + return false; + + // sometimes sensors fail to change sensitivity. this prevents us from infinite loop + if (data.number_of_adjustments++ > MAX_SENSITIVITY_ADJUSTMENTS) { + ESP_LOGW(TAG, "Too many sensitivity adjustments done. Something wrong with the sensor. Stopping."); + return false; + } + + ESP_LOGV(TAG, "Adjusting sensitivity, run #%d", data.number_of_adjustments); + + // available combinations of gain and integration times: + static const GainTimePair GAIN_TIME_PAIRS[] = { + {AlsGain501::GAIN_1, INTEGRATION_TIME_50MS}, {AlsGain501::GAIN_1, INTEGRATION_TIME_100MS}, + {AlsGain501::GAIN_150, INTEGRATION_TIME_100MS}, {AlsGain501::GAIN_150, INTEGRATION_TIME_200MS}, + {AlsGain501::GAIN_150, INTEGRATION_TIME_400MS}, + }; + + GainTimePair current_pair = {data.gain, data.integration_time}; + + // Here comes funky business with this sensor. it has no internal error checking mechanism + // as in later versions (LTR-303/329/559/..) and sensor gets overwhelmed when saturated + // and readings are strange. We only check high sensitivity mode for now. + // Nothing is documented and it is a result of real-world testing. + if (data.gain == AlsGain501::GAIN_150) { + // when sensor is saturated it returns various crazy numbers + // CH1 = 1, CH0 = 0 + if (data.ch1 == 1 && data.ch0 == 0) { + ESP_LOGV(TAG, "Looks like sensor got saturated (?) CH1 = 1, CH0 = 0, Gain 150x"); + // fake saturation + data.ch0 = 0xffff; + data.ch1 = 0xffff; + } else if (data.ch1 == 65535 && data.ch0 == 0) { + ESP_LOGV(TAG, "Looks like sensor got saturated (?) CH1 = 65535, CH0 = 0, Gain 150x"); + data.ch0 = 0xffff; + } else if (data.ch1 > 1000 && data.ch0 == 0) { + ESP_LOGV(TAG, "Looks like sensor got saturated (?) CH1 = %d, CH0 = 0, Gain 150x", data.ch1); + data.ch0 = 0xffff; + } + } + + static const uint16_t LOW_INTENSITY_THRESHOLD_1 = 100; + static const uint16_t LOW_INTENSITY_THRESHOLD_200 = 2000; + static const uint16_t HIGH_INTENSITY_THRESHOLD = 25000; + + if (data.ch0 <= (data.gain == AlsGain501::GAIN_1 ? LOW_INTENSITY_THRESHOLD_1 : LOW_INTENSITY_THRESHOLD_200) || + (data.gain == AlsGain501::GAIN_1 && data.lux < 320)) { + GainTimePair next_pair = get_next(GAIN_TIME_PAIRS, current_pair); + if (next_pair != current_pair) { + data.gain = next_pair.gain; + data.integration_time = next_pair.time; + ESP_LOGV(TAG, "Low illuminance. Increasing sensitivity."); + return true; + } + + } else if (data.ch0 >= HIGH_INTENSITY_THRESHOLD || data.ch1 >= HIGH_INTENSITY_THRESHOLD) { + GainTimePair prev_pair = get_prev(GAIN_TIME_PAIRS, current_pair); + if (prev_pair != current_pair) { + data.gain = prev_pair.gain; + data.integration_time = prev_pair.time; + ESP_LOGV(TAG, "High illuminance. Decreasing sensitivity."); + return true; + } + } else { + ESP_LOGD(TAG, "Illuminance is good enough."); + return false; + } + ESP_LOGD(TAG, "Can't adjust sensitivity anymore."); + return false; +} + +void LTRAlsPs501Component::apply_lux_calculation_(AlsReadings &data) { + if ((data.ch0 == 0xFFFF) || (data.ch1 == 0xFFFF)) { + ESP_LOGW(TAG, "Sensors got saturated"); + data.lux = 0.0f; + return; + } + + if ((data.ch0 == 0x0000) && (data.ch1 == 0x0000)) { + ESP_LOGW(TAG, "Sensors blacked out"); + data.lux = 0.0f; + return; + } + + float ch0 = data.ch0; + float ch1 = data.ch1; + float ratio = ch1 / (ch0 + ch1); + float als_gain = get_gain_coeff(data.gain); + float als_time = ((float) get_itime_ms(data.integration_time)) / 100.0f; + float inv_pfactor = this->glass_attenuation_factor_; + float lux = 0.0f; + + // method from + // https://github.com/fards/Ainol_fire_kernel/blob/83832cf8a3082fd8e963230f4b1984479d1f1a84/customer/drivers/lightsensor/ltr501als.c#L295 + + if (ratio < 0.45) { + lux = 1.7743 * ch0 + 1.1059 * ch1; + } else if (ratio < 0.64) { + lux = 3.7725 * ch0 - 1.3363 * ch1; + } else if (ratio < 0.85) { + lux = 1.6903 * ch0 - 0.1693 * ch1; + } else { + ESP_LOGW(TAG, "Impossible ch1/(ch0 + ch1) ratio"); + lux = 0.0f; + } + + lux = inv_pfactor * lux / als_gain / als_time; + data.lux = lux; + + ESP_LOGD(TAG, "Lux calculation: ratio %.3f, gain %.0fx, int time %.1f, inv_pfactor %.3f, lux %.3f", ratio, als_gain, + als_time, inv_pfactor, lux); +} + +void LTRAlsPs501Component::publish_data_part_1_(AlsReadings &data) { + if (this->proximity_counts_sensor_ != nullptr) { + this->proximity_counts_sensor_->publish_state(this->ps_readings_); + } + if (this->ambient_light_sensor_ != nullptr) { + this->ambient_light_sensor_->publish_state(data.lux); + } + if (this->infrared_counts_sensor_ != nullptr) { + this->infrared_counts_sensor_->publish_state(data.ch1); + } + if (this->full_spectrum_counts_sensor_ != nullptr) { + this->full_spectrum_counts_sensor_->publish_state(data.ch0); + } +} + +void LTRAlsPs501Component::publish_data_part_2_(AlsReadings &data) { + if (this->actual_gain_sensor_ != nullptr) { + this->actual_gain_sensor_->publish_state(get_gain_coeff(data.gain)); + } + if (this->actual_integration_time_sensor_ != nullptr) { + this->actual_integration_time_sensor_->publish_state(get_itime_ms(data.integration_time)); + } +} +} // namespace ltr501 +} // namespace esphome diff --git a/esphome/components/ltr501/ltr501.h b/esphome/components/ltr501/ltr501.h new file mode 100644 index 0000000000..07b69fa0d0 --- /dev/null +++ b/esphome/components/ltr501/ltr501.h @@ -0,0 +1,184 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/optional.h" +#include "esphome/core/automation.h" + +#include "ltr_definitions_501.h" + +namespace esphome { +namespace ltr501 { + +enum DataAvail : uint8_t { NO_DATA, BAD_DATA, DATA_OK }; + +enum LtrType : uint8_t { + LTR_TYPE_UNKNOWN = 0, + LTR_TYPE_ALS_ONLY = 1, + LTR_TYPE_PS_ONLY = 2, + LTR_TYPE_ALS_AND_PS = 3, +}; + +class LTRAlsPs501Component : public PollingComponent, public i2c::I2CDevice { + public: + // + // EspHome framework functions + // + float get_setup_priority() const override { return setup_priority::DATA; } + void setup() override; + void dump_config() override; + void update() override; + void loop() override; + + // Configuration setters : General + // + void set_ltr_type(LtrType type) { this->ltr_type_ = type; } + + // Configuration setters : ALS + // + void set_als_auto_mode(bool enable) { this->automatic_mode_enabled_ = enable; } + void set_als_gain(AlsGain501 gain) { this->gain_ = gain; } + void set_als_integration_time(IntegrationTime501 time) { this->integration_time_ = time; } + void set_als_meas_repeat_rate(MeasurementRepeatRate rate) { this->repeat_rate_ = rate; } + void set_als_glass_attenuation_factor(float factor) { this->glass_attenuation_factor_ = factor; } + + // Configuration setters : PS + // + void set_ps_high_threshold(uint16_t threshold) { this->ps_threshold_high_ = threshold; } + void set_ps_low_threshold(uint16_t threshold) { this->ps_threshold_low_ = threshold; } + void set_ps_cooldown_time_s(uint16_t time) { this->ps_cooldown_time_s_ = time; } + void set_ps_gain(PsGain501 gain) { this->ps_gain_ = gain; } + + // Sensors setters + // + void set_ambient_light_sensor(sensor::Sensor *sensor) { this->ambient_light_sensor_ = sensor; } + void set_full_spectrum_counts_sensor(sensor::Sensor *sensor) { this->full_spectrum_counts_sensor_ = sensor; } + void set_infrared_counts_sensor(sensor::Sensor *sensor) { this->infrared_counts_sensor_ = sensor; } + void set_actual_gain_sensor(sensor::Sensor *sensor) { this->actual_gain_sensor_ = sensor; } + void set_actual_integration_time_sensor(sensor::Sensor *sensor) { this->actual_integration_time_sensor_ = sensor; } + void set_proximity_counts_sensor(sensor::Sensor *sensor) { this->proximity_counts_sensor_ = sensor; } + + protected: + // + // Internal state machine, used to split all the actions into + // small steps in loop() to make sure we are not blocking execution + // + enum class State : uint8_t { + NOT_INITIALIZED, + DELAYED_SETUP, + IDLE, + WAITING_FOR_DATA, + COLLECTING_DATA_AUTO, + DATA_COLLECTED, + ADJUSTMENT_IN_PROGRESS, + READY_TO_PUBLISH, + KEEP_PUBLISHING + } state_{State::NOT_INITIALIZED}; + + LtrType ltr_type_{LtrType::LTR_TYPE_ALS_ONLY}; + + // + // Current measurements data + // + struct AlsReadings { + uint16_t ch0{0}; + uint16_t ch1{0}; + AlsGain501 gain{AlsGain501::GAIN_1}; + IntegrationTime501 integration_time{IntegrationTime501::INTEGRATION_TIME_100MS}; + float lux{0.0f}; + uint8_t number_of_adjustments{0}; + } als_readings_; + uint16_t ps_readings_{0xfffe}; + + inline bool is_als_() const { + return this->ltr_type_ == LtrType::LTR_TYPE_ALS_ONLY || this->ltr_type_ == LtrType::LTR_TYPE_ALS_AND_PS; + } + inline bool is_ps_() const { + return this->ltr_type_ == LtrType::LTR_TYPE_PS_ONLY || this->ltr_type_ == LtrType::LTR_TYPE_ALS_AND_PS; + } + + // + // Device interaction and data manipulation + // + bool check_part_number_(); + + void configure_reset_(); + void configure_als_(); + void configure_integration_time_(IntegrationTime501 time); + void configure_gain_(AlsGain501 gain); + DataAvail is_als_data_ready_(AlsReadings &data); + void read_sensor_data_(AlsReadings &data); + bool are_adjustments_required_(AlsReadings &data); + void apply_lux_calculation_(AlsReadings &data); + void publish_data_part_1_(AlsReadings &data); + void publish_data_part_2_(AlsReadings &data); + + void configure_ps_(); + uint16_t read_ps_data_(); + void check_and_trigger_ps_(); + + // + // Component configuration + // + bool automatic_mode_enabled_{false}; + AlsGain501 gain_{AlsGain501::GAIN_1}; + IntegrationTime501 integration_time_{IntegrationTime501::INTEGRATION_TIME_100MS}; + MeasurementRepeatRate repeat_rate_{MeasurementRepeatRate::REPEAT_RATE_500MS}; + float glass_attenuation_factor_{1.0}; + + uint16_t ps_cooldown_time_s_{5}; + PsGain501 ps_gain_{PsGain501::PS_GAIN_1}; + uint16_t ps_threshold_high_{0xffff}; + uint16_t ps_threshold_low_{0x0000}; + + // + // Sensors for publishing data + // + sensor::Sensor *infrared_counts_sensor_{nullptr}; // direct reading CH1, infrared only + sensor::Sensor *full_spectrum_counts_sensor_{nullptr}; // direct reading CH0, infrared + visible light + sensor::Sensor *ambient_light_sensor_{nullptr}; // calculated lux + sensor::Sensor *actual_gain_sensor_{nullptr}; // actual gain of reading + sensor::Sensor *actual_integration_time_sensor_{nullptr}; // actual integration time + sensor::Sensor *proximity_counts_sensor_{nullptr}; // proximity sensor + + bool is_any_als_sensor_enabled_() const { + return this->ambient_light_sensor_ != nullptr || this->full_spectrum_counts_sensor_ != nullptr || + this->infrared_counts_sensor_ != nullptr || this->actual_gain_sensor_ != nullptr || + this->actual_integration_time_sensor_ != nullptr; + } + bool is_any_ps_sensor_enabled_() const { return this->proximity_counts_sensor_ != nullptr; } + + // + // Trigger section for the automations + // + friend class LTRPsHighTrigger; + friend class LTRPsLowTrigger; + + CallbackManager on_ps_high_trigger_callback_; + CallbackManager on_ps_low_trigger_callback_; + + void add_on_ps_high_trigger_callback_(std::function callback) { + this->on_ps_high_trigger_callback_.add(std::move(callback)); + } + + void add_on_ps_low_trigger_callback_(std::function callback) { + this->on_ps_low_trigger_callback_.add(std::move(callback)); + } +}; + +class LTRPsHighTrigger : public Trigger<> { + public: + explicit LTRPsHighTrigger(LTRAlsPs501Component *parent) { + parent->add_on_ps_high_trigger_callback_([this]() { this->trigger(); }); + } +}; + +class LTRPsLowTrigger : public Trigger<> { + public: + explicit LTRPsLowTrigger(LTRAlsPs501Component *parent) { + parent->add_on_ps_low_trigger_callback_([this]() { this->trigger(); }); + } +}; +} // namespace ltr501 +} // namespace esphome diff --git a/esphome/components/ltr501/ltr_definitions_501.h b/esphome/components/ltr501/ltr_definitions_501.h new file mode 100644 index 0000000000..604bd92b68 --- /dev/null +++ b/esphome/components/ltr501/ltr_definitions_501.h @@ -0,0 +1,260 @@ +#pragma once + +#include + +namespace esphome { +namespace ltr501 { + +enum class CommandRegisters : uint8_t { + ALS_CONTR = 0x80, // ALS operation mode control and SW reset + PS_CONTR = 0x81, // PS operation mode control + PS_LED = 0x82, // PS LED pulse frequency control + PS_N_PULSES = 0x83, // PS number of pulses control + PS_MEAS_RATE = 0x84, // PS measurement rate in active mode + MEAS_RATE = 0x85, // ALS measurement rate in active mode + PART_ID = 0x86, // Part Number ID and Revision ID + MANUFAC_ID = 0x87, // Manufacturer ID + ALS_DATA_CH1_0 = 0x88, // ALS measurement CH1 data, lower byte - infrared only + ALS_DATA_CH1_1 = 0x89, // ALS measurement CH1 data, upper byte - infrared only + ALS_DATA_CH0_0 = 0x8A, // ALS measurement CH0 data, lower byte - visible + infrared + ALS_DATA_CH0_1 = 0x8B, // ALS measurement CH0 data, upper byte - visible + infrared + ALS_PS_STATUS = 0x8C, // ALS PS new data status + PS_DATA_0 = 0x8D, // PS measurement data, lower byte + PS_DATA_1 = 0x8E, // PS measurement data, upper byte + ALS_PS_INTERRUPT = 0x8F, // Interrupt status + PS_THRES_UP_0 = 0x90, // PS interrupt upper threshold, lower byte + PS_THRES_UP_1 = 0x91, // PS interrupt upper threshold, upper byte + PS_THRES_LOW_0 = 0x92, // PS interrupt lower threshold, lower byte + PS_THRES_LOW_1 = 0x93, // PS interrupt lower threshold, upper byte + PS_OFFSET_1 = 0x94, // PS offset, upper byte + PS_OFFSET_0 = 0x95, // PS offset, lower byte + // 0x96 - reserved + ALS_THRES_UP_0 = 0x97, // ALS interrupt upper threshold, lower byte + ALS_THRES_UP_1 = 0x98, // ALS interrupt upper threshold, upper byte + ALS_THRES_LOW_0 = 0x99, // ALS interrupt lower threshold, lower byte + ALS_THRES_LOW_1 = 0x9A, // ALS interrupt lower threshold, upper byte + // 0x9B - reserved + // 0x9C - reserved + // 0x9D - reserved + INTERRUPT_PERSIST = 0x9E // Interrupt persistence filter +}; + +// ALS Sensor gain levels +enum AlsGain501 : uint8_t { + GAIN_1 = 0, // GAIN_RANGE_2 // default + GAIN_150 = 1, // GAIN_RANGE_1 +}; +static const uint8_t GAINS_COUNT = 2; + +// ALS Sensor integration times +enum IntegrationTime501 : uint8_t { + INTEGRATION_TIME_100MS = 0, // default + INTEGRATION_TIME_50MS = 1, // only in Dynamic GAIN_RANGE_2 + INTEGRATION_TIME_200MS = 2, // only in Dynamic GAIN_RANGE_1 + INTEGRATION_TIME_400MS = 3, // only in Dynamic GAIN_RANGE_1 +}; +static const uint8_t TIMES_COUNT = 4; + +// ALS Sensor measurement repeat rate +enum MeasurementRepeatRate { + REPEAT_RATE_50MS = 0, + REPEAT_RATE_100MS = 1, + REPEAT_RATE_200MS = 2, + REPEAT_RATE_500MS = 3, // default + REPEAT_RATE_1000MS = 4, + REPEAT_RATE_2000MS = 5 +}; + +// PS Sensor gain levels +enum PsGain501 : uint8_t { + PS_GAIN_1 = 0, // default + PS_GAIN_4 = 1, + PS_GAIN_8 = 2, + PS_GAIN_16 = 3, +}; + +// LED Pulse Modulation Frequency +enum PsLedFreq : uint8_t { + PS_LED_FREQ_30KHZ = 0, + PS_LED_FREQ_40KHZ = 1, + PS_LED_FREQ_50KHZ = 2, + PS_LED_FREQ_60KHZ = 3, // default + PS_LED_FREQ_70KHZ = 4, + PS_LED_FREQ_80KHZ = 5, + PS_LED_FREQ_90KHZ = 6, + PS_LED_FREQ_100KHZ = 7, +}; + +// LED current duty +enum PsLedDuty : uint8_t { + PS_LED_DUTY_25 = 0, + PS_LED_DUTY_50 = 1, // default + PS_LED_DUTY_75 = 2, + PS_LED_DUTY_100 = 3, +}; + +// LED pulsed current level +enum PsLedCurrent : uint8_t { + PS_LED_CURRENT_5MA = 0, + PS_LED_CURRENT_10MA = 1, + PS_LED_CURRENT_20MA = 2, + PS_LED_CURRENT_50MA = 3, // default + PS_LED_CURRENT_100MA = 4, + PS_LED_CURRENT_100MA1 = 5, + PS_LED_CURRENT_100MA2 = 6, + PS_LED_CURRENT_100MA3 = 7, +}; + +// PS measurement rate +enum PsMeasurementRate : uint8_t { + PS_MEAS_RATE_50MS = 0, + PS_MEAS_RATE_70MS = 1, + PS_MEAS_RATE_100MS = 2, // default + PS_MEAS_RATE_200MS = 3, + PS_MEAS_RATE_500MS = 4, + PS_MEAS_RATE_1000MS = 5, + PS_MEAS_RATE_2000MS = 6, + PS_MEAS_RATE_2000MS1 = 7, +}; + +// +// ALS_CONTR Register (0x80) +// +union AlsControlRegister501 { + uint8_t raw; + struct { + bool asl_mode_xxx : 1; + bool als_mode_active : 1; + bool sw_reset : 1; + AlsGain501 gain : 1; + uint8_t reserved : 4; + } __attribute__((packed)); +}; + +// +// PS_CONTR Register (0x81) +// +union PsControlRegister501 { + uint8_t raw; + struct { + bool ps_mode_xxx : 1; + bool ps_mode_active : 1; + PsGain501 ps_gain : 2; + bool reserved_4 : 1; + bool reserved_5 : 1; + bool reserved_6 : 1; + bool reserved_7 : 1; + } __attribute__((packed)); +}; + +// +// PS_LED Register (0x82) +// +union PsLedRegister { + uint8_t raw; + struct { + PsLedCurrent ps_led_current : 3; + PsLedDuty ps_led_duty : 2; + PsLedFreq ps_led_freq : 3; + } __attribute__((packed)); +}; + +// +// PS_N_PULSES Register (0x83) +// +union PsNPulsesRegister501 { + uint8_t raw; + uint8_t number_of_pulses; +}; + +// +// PS_MEAS_RATE Register (0x84) +// +union PsMeasurementRateRegister { + uint8_t raw; + struct { + PsMeasurementRate ps_measurement_rate : 4; + uint8_t reserved : 4; + } __attribute__((packed)); +}; + +// +// ALS_MEAS_RATE Register (0x85) +// +union MeasurementRateRegister501 { + uint8_t raw; + struct { + MeasurementRepeatRate measurement_repeat_rate : 3; + IntegrationTime501 integration_time : 2; + bool reserved_5 : 1; + bool reserved_6 : 1; + bool reserved_7 : 1; + } __attribute__((packed)); +}; + +// +// PART_ID Register (0x86) (Read Only) +// +union PartIdRegister { + uint8_t raw; + struct { + uint8_t part_number_id : 4; + uint8_t revision_id : 4; + } __attribute__((packed)); +}; + +// +// ALS_PS_STATUS Register (0x8C) (Read Only) +// +union AlsPsStatusRegister { + uint8_t raw; + struct { + bool ps_new_data : 1; // 0 - old data, 1 - new data + bool ps_interrupt : 1; // 0 - interrupt signal not active, 1 - interrupt signal active + bool als_new_data : 1; // 0 - old data, 1 - new data + bool als_interrupt : 1; // 0 - interrupt signal not active, 1 - interrupt signal active + AlsGain501 gain : 1; // current ALS gain + bool reserved_5 : 1; + bool reserved_6 : 1; + bool reserved_7 : 1; + } __attribute__((packed)); +}; + +// +// PS_DATA_1 Register (0x8E) (Read Only) +// +union PsData1Register { + uint8_t raw; + struct { + uint8_t ps_data_high : 3; + uint8_t reserved : 4; + bool ps_saturation_flag : 1; + } __attribute__((packed)); +}; + +// +// INTERRUPT Register (0x8F) (Read Only) +// +union InterruptRegister { + uint8_t raw; + struct { + bool ps_interrupt : 1; + bool als_interrupt : 1; + bool interrupt_polarity : 1; // 0 - active low (default), 1 - active high + uint8_t reserved : 5; + } __attribute__((packed)); +}; + +// +// INTERRUPT_PERSIST Register (0x9E) +// +union InterruptPersistRegister { + uint8_t raw; + struct { + uint8_t als_persist : 4; // 0 - every ALS cycle, 1 - every 2 ALS cycles, ... 15 - every 16 ALS cycles + uint8_t ps_persist : 4; // 0 - every PS cycle, 1 - every 2 PS cycles, ... 15 - every 16 PS cycles + } __attribute__((packed)); +}; + +} // namespace ltr501 +} // namespace esphome diff --git a/esphome/components/ltr501/sensor.py b/esphome/components/ltr501/sensor.py new file mode 100644 index 0000000000..153d1b3ad1 --- /dev/null +++ b/esphome/components/ltr501/sensor.py @@ -0,0 +1,274 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ACTUAL_GAIN, + CONF_ACTUAL_INTEGRATION_TIME, + CONF_AMBIENT_LIGHT, + CONF_AUTO_MODE, + CONF_FULL_SPECTRUM_COUNTS, + CONF_GAIN, + CONF_GLASS_ATTENUATION_FACTOR, + CONF_ID, + CONF_INTEGRATION_TIME, + CONF_NAME, + CONF_REPEAT, + CONF_TRIGGER_ID, + CONF_TYPE, + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_ILLUMINANCE, + ICON_BRIGHTNESS_5, + ICON_BRIGHTNESS_6, + ICON_TIMER, + STATE_CLASS_MEASUREMENT, + UNIT_LUX, + UNIT_MILLISECOND, +) + +CODEOWNERS = ["@latonita"] +DEPENDENCIES = ["i2c"] + +CONF_INFRARED_COUNTS = "infrared_counts" +CONF_ON_PS_HIGH_THRESHOLD = "on_ps_high_threshold" +CONF_ON_PS_LOW_THRESHOLD = "on_ps_low_threshold" +CONF_PS_COOLDOWN = "ps_cooldown" +CONF_PS_COUNTS = "ps_counts" +CONF_PS_GAIN = "ps_gain" +CONF_PS_HIGH_THRESHOLD = "ps_high_threshold" +CONF_PS_LOW_THRESHOLD = "ps_low_threshold" +ICON_BRIGHTNESS_7 = "mdi:brightness-7" +ICON_GAIN = "mdi:multiplication" +ICON_PROXIMITY = "mdi:hand-wave-outline" +UNIT_COUNTS = "#" + +ltr501_ns = cg.esphome_ns.namespace("ltr501") + +LTRAlsPsComponent = ltr501_ns.class_( + "LTRAlsPs501Component", cg.PollingComponent, i2c.I2CDevice +) + +LtrType = ltr501_ns.enum("LtrType") +LTR_TYPES = { + "ALS": LtrType.LTR_TYPE_ALS_ONLY, + "PS": LtrType.LTR_TYPE_PS_ONLY, + "ALS_PS": LtrType.LTR_TYPE_ALS_AND_PS, +} + +AlsGain = ltr501_ns.enum("AlsGain501") +ALS_GAINS = { + "1X": AlsGain.GAIN_1, + "150X": AlsGain.GAIN_150, +} + +IntegrationTime = ltr501_ns.enum("IntegrationTime501") +INTEGRATION_TIMES = { + 50: IntegrationTime.INTEGRATION_TIME_50MS, + 100: IntegrationTime.INTEGRATION_TIME_100MS, + 200: IntegrationTime.INTEGRATION_TIME_200MS, + 400: IntegrationTime.INTEGRATION_TIME_400MS, +} + +MeasurementRepeatRate = ltr501_ns.enum("MeasurementRepeatRate") +MEASUREMENT_REPEAT_RATES = { + 50: MeasurementRepeatRate.REPEAT_RATE_50MS, + 100: MeasurementRepeatRate.REPEAT_RATE_100MS, + 200: MeasurementRepeatRate.REPEAT_RATE_200MS, + 500: MeasurementRepeatRate.REPEAT_RATE_500MS, + 1000: MeasurementRepeatRate.REPEAT_RATE_1000MS, + 2000: MeasurementRepeatRate.REPEAT_RATE_2000MS, +} + +PsGain = ltr501_ns.enum("PsGain501") +PS_GAINS = { + "1X": PsGain.PS_GAIN_1, + "4X": PsGain.PS_GAIN_4, + "8X": PsGain.PS_GAIN_8, + "16X": PsGain.PS_GAIN_16, +} + +LTRPsHighTrigger = ltr501_ns.class_("LTRPsHighTrigger", automation.Trigger.template()) +LTRPsLowTrigger = ltr501_ns.class_("LTRPsLowTrigger", automation.Trigger.template()) + + +def validate_integration_time(value): + value = cv.positive_time_period_milliseconds(value).total_milliseconds + return cv.enum(INTEGRATION_TIMES, int=True)(value) + + +def validate_repeat_rate(value): + value = cv.positive_time_period_milliseconds(value).total_milliseconds + return cv.enum(MEASUREMENT_REPEAT_RATES, int=True)(value) + + +def validate_time_and_repeat_rate(config): + integraton_time = config[CONF_INTEGRATION_TIME] + repeat_rate = config[CONF_REPEAT] + if integraton_time > repeat_rate: + raise cv.Invalid( + f"Measurement repeat rate ({repeat_rate}ms) shall be greater or equal to integration time ({integraton_time}ms)" + ) + return config + + +def validate_als_gain_and_integration_time(config): + integraton_time = config[CONF_INTEGRATION_TIME] + if config[CONF_GAIN] == "1X" and integraton_time > 100: + raise cv.Invalid( + "ALS gain 1X can only be used with integration time 50ms or 100ms" + ) + if config[CONF_GAIN] == "200X" and integraton_time == 50: + raise cv.Invalid("ALS gain 200X can not be used with integration time 50ms") + return config + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(LTRAlsPsComponent), + cv.Optional(CONF_TYPE, default="ALS_PS"): cv.enum(LTR_TYPES, upper=True), + cv.Optional(CONF_AUTO_MODE, default=True): cv.boolean, + cv.Optional(CONF_GAIN, default="1X"): cv.enum(ALS_GAINS, upper=True), + cv.Optional( + CONF_INTEGRATION_TIME, default="100ms" + ): validate_integration_time, + cv.Optional(CONF_REPEAT, default="500ms"): validate_repeat_rate, + cv.Optional(CONF_GLASS_ATTENUATION_FACTOR, default=1.0): cv.float_range( + min=1.0 + ), + cv.Optional( + CONF_PS_COOLDOWN, default="5s" + ): cv.positive_time_period_seconds, + cv.Optional(CONF_PS_GAIN, default="1X"): cv.enum(PS_GAINS, upper=True), + cv.Optional(CONF_PS_HIGH_THRESHOLD, default=65535): cv.int_range( + min=0, max=65535 + ), + cv.Optional(CONF_PS_LOW_THRESHOLD, default=0): cv.int_range( + min=0, max=65535 + ), + cv.Optional(CONF_ON_PS_HIGH_THRESHOLD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LTRPsHighTrigger), + } + ), + cv.Optional(CONF_ON_PS_LOW_THRESHOLD): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LTRPsLowTrigger), + } + ), + cv.Optional(CONF_AMBIENT_LIGHT): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_BRIGHTNESS_6, + accuracy_decimals=1, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_INFRARED_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_5, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_FULL_SPECTRUM_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_7, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_PS_COUNTS): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_PROXIMITY, + accuracy_decimals=0, + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_GAIN): cv.maybe_simple_value( + sensor.sensor_schema( + icon=ICON_GAIN, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + cv.Optional(CONF_ACTUAL_INTEGRATION_TIME): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_MILLISECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x23)), + validate_time_and_repeat_rate, + validate_als_gain_and_integration_time, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if als_config := config.get(CONF_AMBIENT_LIGHT): + sens = await sensor.new_sensor(als_config) + cg.add(var.set_ambient_light_sensor(sens)) + + if infrared_cnt_config := config.get(CONF_INFRARED_COUNTS): + sens = await sensor.new_sensor(infrared_cnt_config) + cg.add(var.set_infrared_counts_sensor(sens)) + + if full_spect_cnt_config := config.get(CONF_FULL_SPECTRUM_COUNTS): + sens = await sensor.new_sensor(full_spect_cnt_config) + cg.add(var.set_full_spectrum_counts_sensor(sens)) + + if act_gain_config := config.get(CONF_ACTUAL_GAIN): + sens = await sensor.new_sensor(act_gain_config) + cg.add(var.set_actual_gain_sensor(sens)) + + if act_itime_config := config.get(CONF_ACTUAL_INTEGRATION_TIME): + sens = await sensor.new_sensor(act_itime_config) + cg.add(var.set_actual_integration_time_sensor(sens)) + + if prox_cnt_config := config.get(CONF_PS_COUNTS): + sens = await sensor.new_sensor(prox_cnt_config) + cg.add(var.set_proximity_counts_sensor(sens)) + + for prox_high_tr in config.get(CONF_ON_PS_HIGH_THRESHOLD, []): + trigger = cg.new_Pvariable(prox_high_tr[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], prox_high_tr) + + for prox_low_tr in config.get(CONF_ON_PS_LOW_THRESHOLD, []): + trigger = cg.new_Pvariable(prox_low_tr[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], prox_low_tr) + + cg.add(var.set_ltr_type(config[CONF_TYPE])) + + cg.add(var.set_als_auto_mode(config[CONF_AUTO_MODE])) + cg.add(var.set_als_gain(config[CONF_GAIN])) + cg.add(var.set_als_integration_time(config[CONF_INTEGRATION_TIME])) + cg.add(var.set_als_meas_repeat_rate(config[CONF_REPEAT])) + cg.add(var.set_als_glass_attenuation_factor(config[CONF_GLASS_ATTENUATION_FACTOR])) + + cg.add(var.set_ps_cooldown_time_s(config[CONF_PS_COOLDOWN])) + cg.add(var.set_ps_gain(config[CONF_PS_GAIN])) + cg.add(var.set_ps_high_threshold(config[CONF_PS_HIGH_THRESHOLD])) + cg.add(var.set_ps_low_threshold(config[CONF_PS_LOW_THRESHOLD])) diff --git a/esphome/components/ltr_als_ps/sensor.py b/esphome/components/ltr_als_ps/sensor.py index ac9f7e6788..e9a5264941 100644 --- a/esphome/components/ltr_als_ps/sensor.py +++ b/esphome/components/ltr_als_ps/sensor.py @@ -4,8 +4,10 @@ from esphome import automation from esphome.components import i2c, sensor from esphome.const import ( CONF_ACTUAL_GAIN, + CONF_ACTUAL_INTEGRATION_TIME, CONF_AMBIENT_LIGHT, CONF_AUTO_MODE, + CONF_FULL_SPECTRUM_COUNTS, CONF_GAIN, CONF_GLASS_ATTENUATION_FACTOR, CONF_ID, @@ -27,8 +29,6 @@ from esphome.const import ( CODEOWNERS = ["@latonita"] DEPENDENCIES = ["i2c"] -CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" -CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" CONF_INFRARED_COUNTS = "infrared_counts" CONF_ON_PS_HIGH_THRESHOLD = "on_ps_high_threshold" CONF_ON_PS_LOW_THRESHOLD = "on_ps_low_threshold" diff --git a/esphome/components/veml7700/sensor.py b/esphome/components/veml7700/sensor.py index 7b0f75e70c..308f1c1c00 100644 --- a/esphome/components/veml7700/sensor.py +++ b/esphome/components/veml7700/sensor.py @@ -3,9 +3,11 @@ import esphome.config_validation as cv from esphome.components import i2c, sensor from esphome.const import ( CONF_ACTUAL_GAIN, + CONF_ACTUAL_INTEGRATION_TIME, CONF_AMBIENT_LIGHT, CONF_AUTO_MODE, CONF_FULL_SPECTRUM, + CONF_FULL_SPECTRUM_COUNTS, CONF_GAIN, CONF_GLASS_ATTENUATION_FACTOR, CONF_ID, @@ -28,9 +30,7 @@ UNIT_COUNTS = "#" ICON_MULTIPLICATION = "mdi:multiplication" ICON_BRIGHTNESS_7 = "mdi:brightness-7" -CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" CONF_AMBIENT_LIGHT_COUNTS = "ambient_light_counts" -CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" CONF_LUX_COMPENSATION = "lux_compensation" veml7700_ns = cg.esphome_ns.namespace("veml7700") diff --git a/esphome/const.py b/esphome/const.py index 95773630d0..169b11a715 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -44,6 +44,7 @@ CONF_ACTIONS = "actions" CONF_ACTIVE = "active" CONF_ACTIVE_POWER = "active_power" CONF_ACTUAL_GAIN = "actual_gain" +CONF_ACTUAL_INTEGRATION_TIME = "actual_integration_time" CONF_ADDRESS = "address" CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id" CONF_ADVANCED = "advanced" @@ -323,6 +324,7 @@ CONF_FREQUENCY = "frequency" CONF_FRIENDLY_NAME = "friendly_name" CONF_FROM = "from" CONF_FULL_SPECTRUM = "full_spectrum" +CONF_FULL_SPECTRUM_COUNTS = "full_spectrum_counts" CONF_FULL_UPDATE_EVERY = "full_update_every" CONF_GAIN = "gain" CONF_GAMMA_CORRECT = "gamma_correct" diff --git a/tests/components/ltr501/common.yaml b/tests/components/ltr501/common.yaml new file mode 100644 index 0000000000..b7074f52f2 --- /dev/null +++ b/tests/components/ltr501/common.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: ltr501 + address: 0x23 + i2c_id: i2c_ltr501 + type: ALS_PS + gain: 1X + integration_time: 100ms + ambient_light: "Ambient light" + ps_counts: "Proximity counts" diff --git a/tests/components/ltr501/test.esp32-ard.yaml b/tests/components/ltr501/test.esp32-ard.yaml new file mode 100644 index 0000000000..4c710c74fe --- /dev/null +++ b/tests/components/ltr501/test.esp32-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ltr501/test.esp32-c3-ard.yaml b/tests/components/ltr501/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..9e7de2768d --- /dev/null +++ b/tests/components/ltr501/test.esp32-c3-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr501/test.esp32-c3-idf.yaml b/tests/components/ltr501/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9e7de2768d --- /dev/null +++ b/tests/components/ltr501/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr501/test.esp32-idf.yaml b/tests/components/ltr501/test.esp32-idf.yaml new file mode 100644 index 0000000000..4c710c74fe --- /dev/null +++ b/tests/components/ltr501/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/ltr501/test.esp8266-ard.yaml b/tests/components/ltr501/test.esp8266-ard.yaml new file mode 100644 index 0000000000..9e7de2768d --- /dev/null +++ b/tests/components/ltr501/test.esp8266-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/ltr501/test.rp2040-ard.yaml b/tests/components/ltr501/test.rp2040-ard.yaml new file mode 100644 index 0000000000..9e7de2768d --- /dev/null +++ b/tests/components/ltr501/test.rp2040-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_ltr501 + scl: 5 + sda: 4 + +<<: !include common.yaml From 198bd3b41afc46c499ccfacf32b90866e33a98d9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:35:39 +1200 Subject: [PATCH 2355/2607] Bump libssl-dev to 3.0.14-1~deb12u2 (#7426) --- docker/Dockerfile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4393d5a447..e255f4e2fc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -49,7 +49,7 @@ RUN \ zlib1g-dev=1:1.2.13.dfsg-1 \ libjpeg-dev=1:2.1.5-2 \ libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.14-1~deb12u1 \ + libssl-dev=3.0.14-1~deb12u2 \ libffi-dev=3.4.4-1 \ libopenjp2-7=2.5.0-2 \ libtiff6=4.5.0-6+deb12u1 \ @@ -96,14 +96,19 @@ RUN \ # First install requirements to leverage caching when requirements don't change # tmpfs is for https://github.com/rust-lang/cargo/issues/8719 -COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini / +COPY requirements.txt requirements_optional.txt / RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ - export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ + curl -L https://www.piwheels.org/cp311/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ + && pip3 install --break-system-packages --no-cache-dir /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ + && rm /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ + && export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ fi; \ CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \ pip3 install \ - --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ - && /platformio_install_deps.py /platformio.ini --libraries + --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt + +COPY script/platformio_install_deps.py platformio.ini / +RUN /platformio_install_deps.py /platformio.ini --libraries # Avoid unsafe git error when container user and file config volume permissions don't match RUN git config --system --add safe.directory '*' From 9f42b76de3679a1ef2fd5945766ccf9f78ae4fd2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:57:42 +1200 Subject: [PATCH 2356/2607] [gh-actions] Don't produce docker build summaries (#7430) --- .github/actions/build-image/action.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 56be20bd87..d277ec06c7 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -47,6 +47,9 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr uses: docker/build-push-action@v6.7.0 + env: + DOCKER_BUILD_SUMMARY: false + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: ./docker/Dockerfile @@ -70,6 +73,9 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub uses: docker/build-push-action@v6.7.0 + env: + DOCKER_BUILD_SUMMARY: false + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: ./docker/Dockerfile From d10feafa9bb68301c060e190309ba6dbf6d7b483 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 00:58:57 +0100 Subject: [PATCH 2357/2607] Add BK72xx support to require_framework_version() (#7409) --- esphome/config_validation.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 719cc43b31..e55879e37e 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -2045,6 +2045,7 @@ def require_framework_version( esp32_arduino=None, esp8266_arduino=None, rp2040_arduino=None, + bk72xx_libretiny=None, host=None, max_version=False, extra_message=None, @@ -2059,6 +2060,13 @@ def require_framework_version( msg += f". {extra_message}" raise Invalid(msg) required = esp_idf + elif CORE.is_bk72xx and framework == "arduino": + if bk72xx_libretiny is None: + msg = "This feature is incompatible with BK72XX" + if extra_message: + msg += f". {extra_message}" + raise Invalid(msg) + required = bk72xx_libretiny elif CORE.is_esp32 and framework == "arduino": if esp32_arduino is None: msg = "This feature is incompatible with ESP32 using arduino framework" From b5e5741ffdeb10f75285b45e5998a8cafcec768d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 00:59:46 +0100 Subject: [PATCH 2358/2607] Switch IPv6 platform check to use require_framework_version() (#7410) --- esphome/components/network/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index caa873a746..772ba230d9 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -1,13 +1,7 @@ import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option import esphome.config_validation as cv -from esphome.const import ( - CONF_ENABLE_IPV6, - CONF_MIN_IPV6_ADDR_COUNT, - PLATFORM_ESP32, - PLATFORM_ESP8266, - PLATFORM_RP2040, -) +from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT from esphome.core import CORE CODEOWNERS = ["@esphome/core"] @@ -26,7 +20,12 @@ CONFIG_SCHEMA = cv.Schema( ): cv.All( cv.boolean, cv.Any( - cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), + cv.require_framework_version( + esp_idf=cv.Version(0, 0, 0), + esp32_arduino=cv.Version(0, 0, 0), + esp8266_arduino=cv.Version(0, 0, 0), + rp2040_arduino=cv.Version(0, 0, 0), + ), cv.boolean_false, ), ), From f5c2921b85dca99cd9591e968bba4f3b4d9c75ca Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 02:11:26 +0100 Subject: [PATCH 2359/2607] [bl0942] Improve energy reporting (#7428) --- esphome/components/bl0942/bl0942.cpp | 4 +++- esphome/components/bl0942/bl0942.h | 2 ++ esphome/components/bl0942/sensor.py | 9 ++++++--- tests/components/bl0942/test.bk72xx-ard.yaml | 1 + tests/components/bl0942/test.esp32-ard.yaml | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index af56e77de6..e6f96c1b19 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -137,7 +137,8 @@ void BL0942::setup() { } this->write_reg_(BL0942_REG_USR_WRPROT, BL0942_REG_USR_WRPROT_MAGIC); - this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC); + if (this->reset_) + this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC); uint32_t mode = BL0942_REG_MODE_DEFAULT; mode |= BL0942_REG_MODE_RMS_UPDATE_SEL; /* 800ms refresh time */ @@ -196,6 +197,7 @@ void BL0942::received_package_(DataPacket *data) { void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity) ESP_LOGCONFIG(TAG, "BL0942:"); + ESP_LOGCONFIG(TAG, " Reset: %s", TRUEFALSE(this->reset_)); ESP_LOGCONFIG(TAG, " Address: %d", this->address_); ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_); ESP_LOGCONFIG(TAG, " Current reference: %f", this->current_reference_); diff --git a/esphome/components/bl0942/bl0942.h b/esphome/components/bl0942/bl0942.h index 1dc930183f..37b884e6ca 100644 --- a/esphome/components/bl0942/bl0942.h +++ b/esphome/components/bl0942/bl0942.h @@ -93,6 +93,7 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; } void set_line_freq(LineFrequency freq) { this->line_freq_ = freq; } void set_address(uint8_t address) { this->address_ = address; } + void set_reset(bool reset) { this->reset_ = reset; } void set_current_reference(float current_ref) { this->current_reference_ = current_ref; this->current_reference_set_ = true; @@ -137,6 +138,7 @@ class BL0942 : public PollingComponent, public uart::UARTDevice { float energy_reference_ = BL0942_EREF; bool energy_reference_set_ = false; uint8_t address_ = 0; + bool reset_ = false; LineFrequency line_freq_ = LINE_FREQUENCY_50HZ; uint32_t rx_start_ = 0; uint32_t prev_cf_cnt_ = 0; diff --git a/esphome/components/bl0942/sensor.py b/esphome/components/bl0942/sensor.py index 3574443636..550f534b74 100644 --- a/esphome/components/bl0942/sensor.py +++ b/esphome/components/bl0942/sensor.py @@ -27,6 +27,7 @@ from esphome.const import ( CONF_CURRENT_REFERENCE = "current_reference" CONF_ENERGY_REFERENCE = "energy_reference" CONF_POWER_REFERENCE = "power_reference" +CONF_RESET = "reset" CONF_VOLTAGE_REFERENCE = "voltage_reference" DEPENDENCIES = ["uart"] @@ -58,19 +59,19 @@ CONFIG_SCHEMA = ( ), cv.Optional(CONF_POWER): sensor.sensor_schema( unit_of_measurement=UNIT_WATT, - accuracy_decimals=0, + accuracy_decimals=1, device_class=DEVICE_CLASS_POWER, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ENERGY): sensor.sensor_schema( unit_of_measurement=UNIT_KILOWATT_HOURS, - accuracy_decimals=0, + accuracy_decimals=3, device_class=DEVICE_CLASS_ENERGY, state_class=STATE_CLASS_TOTAL_INCREASING, ), cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( unit_of_measurement=UNIT_HERTZ, - accuracy_decimals=0, + accuracy_decimals=2, device_class=DEVICE_CLASS_FREQUENCY, state_class=STATE_CLASS_MEASUREMENT, ), @@ -82,6 +83,7 @@ CONFIG_SCHEMA = ( ), ), cv.Optional(CONF_ADDRESS, default=0): cv.int_range(min=0, max=3), + cv.Optional(CONF_RESET, default=True): cv.boolean, cv.Optional(CONF_CURRENT_REFERENCE): cv.float_, cv.Optional(CONF_ENERGY_REFERENCE): cv.float_, cv.Optional(CONF_POWER_REFERENCE): cv.float_, @@ -115,6 +117,7 @@ async def to_code(config): cg.add(var.set_frequency_sensor(sens)) cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) cg.add(var.set_address(config[CONF_ADDRESS])) + cg.add(var.set_reset(config[CONF_RESET])) if (current_reference := config.get(CONF_CURRENT_REFERENCE, None)) is not None: cg.add(var.set_current_reference(current_reference)) if (voltage_reference := config.get(CONF_VOLTAGE_REFERENCE, None)) is not None: diff --git a/tests/components/bl0942/test.bk72xx-ard.yaml b/tests/components/bl0942/test.bk72xx-ard.yaml index 12772f9375..ea61734441 100644 --- a/tests/components/bl0942/test.bk72xx-ard.yaml +++ b/tests/components/bl0942/test.bk72xx-ard.yaml @@ -10,6 +10,7 @@ sensor: - platform: bl0942 address: 0 line_frequency: 50Hz + reset: false voltage: name: BL0942 Voltage current: diff --git a/tests/components/bl0942/test.esp32-ard.yaml b/tests/components/bl0942/test.esp32-ard.yaml index 45ac85aa2a..4138543967 100644 --- a/tests/components/bl0942/test.esp32-ard.yaml +++ b/tests/components/bl0942/test.esp32-ard.yaml @@ -8,6 +8,7 @@ uart: sensor: - platform: bl0942 + reset: true voltage: name: BL0942 Voltage current: From dcfad31770b18fe917c9017325bc3a019a55e3b7 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:15:56 +1000 Subject: [PATCH 2360/2607] [rpi_dpi_rgb] Add bounce_buffer config for ESP-IDF 5.x (#7423) --- esphome/components/rpi_dpi_rgb/display.py | 33 +++++++++---------- .../components/rpi_dpi_rgb/rpi_dpi_rgb.cpp | 24 ++++++++++---- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h | 1 + 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/esphome/components/rpi_dpi_rgb/display.py b/esphome/components/rpi_dpi_rgb/display.py index 6cc8d2c27b..c26143d63e 100644 --- a/esphome/components/rpi_dpi_rgb/display.py +++ b/esphome/components/rpi_dpi_rgb/display.py @@ -1,31 +1,28 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import display +from esphome.components.esp32 import const, only_on_variant +import esphome.config_validation as cv from esphome.const import ( - CONF_ENABLE_PIN, - CONF_HSYNC_PIN, - CONF_RESET_PIN, + CONF_BLUE, + CONF_COLOR_ORDER, CONF_DATA_PINS, + CONF_DIMENSIONS, + CONF_ENABLE_PIN, + CONF_GREEN, + CONF_HEIGHT, + CONF_HSYNC_PIN, CONF_ID, CONF_IGNORE_STRAPPING_WARNING, - CONF_DIMENSIONS, - CONF_VSYNC_PIN, - CONF_WIDTH, - CONF_HEIGHT, + CONF_INVERT_COLORS, CONF_LAMBDA, - CONF_COLOR_ORDER, - CONF_RED, - CONF_GREEN, - CONF_BLUE, CONF_NUMBER, CONF_OFFSET_HEIGHT, CONF_OFFSET_WIDTH, - CONF_INVERT_COLORS, -) -from esphome.components.esp32 import ( - only_on_variant, - const, + CONF_RED, + CONF_RESET_PIN, + CONF_VSYNC_PIN, + CONF_WIDTH, ) DEPENDENCIES = ["esp32"] diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp index f173a2ec44..655b469b91 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp @@ -6,9 +6,14 @@ namespace esphome { namespace rpi_dpi_rgb { void RpiDpiRgb::setup() { - esph_log_config(TAG, "Setting up RPI_DPI_RGB"); + ESP_LOGCONFIG(TAG, "Setting up RPI_DPI_RGB"); + this->reset_display_(); esp_lcd_rgb_panel_config_t config{}; config.flags.fb_in_psram = 1; +#if ESP_IDF_VERSION_MAJOR >= 5 + config.bounce_buffer_size_px = this->width_ * 10; + config.num_fbs = 1; +#endif // ESP_IDF_VERSION_MAJOR config.timings.h_res = this->width_; config.timings.v_res = this->height_; config.timings.hsync_pulse_width = this->hsync_pulse_width_; @@ -20,7 +25,6 @@ void RpiDpiRgb::setup() { config.timings.flags.pclk_active_neg = this->pclk_inverted_; config.timings.pclk_hz = this->pclk_frequency_; config.clk_src = LCD_CLK_SRC_PLL160M; - config.sram_trans_align = 64; config.psram_trans_align = 64; size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); for (size_t i = 0; i != data_pin_count; i++) { @@ -34,11 +38,19 @@ void RpiDpiRgb::setup() { config.pclk_gpio_num = this->pclk_pin_->get_pin(); esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_); if (err != ESP_OK) { - esph_log_e(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err)); + this->mark_failed(); + return; } ESP_ERROR_CHECK(esp_lcd_panel_reset(this->handle_)); ESP_ERROR_CHECK(esp_lcd_panel_init(this->handle_)); - esph_log_config(TAG, "RPI_DPI_RGB setup complete"); + ESP_LOGCONFIG(TAG, "RPI_DPI_RGB setup complete"); +} +void RpiDpiRgb::loop() { +#if ESP_IDF_VERSION_MAJOR >= 5 + if (this->handle_ != nullptr) + esp_lcd_rgb_panel_restart(this->handle_); +#endif // ESP_IDF_VERSION_MAJOR } void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, @@ -53,7 +65,7 @@ void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uin } x_start += this->offset_x_; y_start += this->offset_y_; - esp_err_t err; + esp_err_t err = ESP_OK; // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. if (x_offset == 0 && x_pad == 0 && y_offset == 0) { // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother @@ -69,7 +81,7 @@ void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uin } } if (err != ESP_OK) - esph_log_e(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err)); } void RpiDpiRgb::draw_pixel_at(int x, int y, Color color) { diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h index 6d9d6d4ae9..10f77a2624 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h @@ -23,6 +23,7 @@ class RpiDpiRgb : public display::Display { public: void update() override { this->do_update_(); } void setup() override; + void loop() override; void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; void draw_pixel_at(int x, int y, Color color) override; From c8aed151571ba10b5ef679aef271f1c2089e84cd Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:24:18 +1000 Subject: [PATCH 2361/2607] [LVGL] Add color gradients (#7427) --- esphome/components/lvgl/__init__.py | 22 +++------ esphome/components/lvgl/defines.py | 17 +++++++ esphome/components/lvgl/gradient.py | 61 ++++++++++++++++++++++++ esphome/components/lvgl/lv_validation.py | 57 +++++++++++++++------- esphome/components/lvgl/lvcode.py | 5 +- esphome/components/lvgl/lvgl_esphome.h | 3 -- esphome/components/lvgl/schemas.py | 9 ++-- esphome/components/lvgl/types.py | 1 + esphome/components/lvgl/widgets/meter.py | 9 +++- tests/components/lvgl/lvgl-package.yaml | 50 ++++++++++++++++++- 10 files changed, 190 insertions(+), 44 deletions(-) create mode 100644 esphome/components/lvgl/gradient.py diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index a4ca9d56f3..64f254cde8 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -22,8 +22,9 @@ from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid from .automation import disp_update, focused_widgets, update_to_code -from .defines import CONF_ADJUSTABLE, CONF_SKIP +from .defines import add_define from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code +from .gradient import GRADIENT_SCHEMA, gradients_to_code from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent from .schemas import ( @@ -128,17 +129,6 @@ for w_type in WIDGET_TYPES.values(): )(update_to_code) -lv_defines = {} # Dict of #defines to provide as build flags - - -def add_define(macro, value="1"): - if macro in lv_defines and lv_defines[macro] != value: - LOGGER.error( - "Redefinition of %s - was %s now %s", macro, lv_defines[macro], value - ) - lv_defines[macro] = value - - def as_macro(macro, value): if value is None: return f"#define {macro}" @@ -153,14 +143,14 @@ LV_CONF_H_FORMAT = """\ def generate_lv_conf_h(): - definitions = [as_macro(m, v) for m, v in lv_defines.items()] + definitions = [as_macro(m, v) for m, v in df.lv_defines.items()] definitions.sort() return LV_CONF_H_FORMAT.format("\n".join(definitions)) def final_validation(config): if pages := config.get(CONF_PAGES): - if all(p[CONF_SKIP] for p in pages): + if all(p[df.CONF_SKIP] for p in pages): raise cv.Invalid("At least one page must not be skipped") global_config = full_config.get() for display_id in config[df.CONF_DISPLAYS]: @@ -185,7 +175,7 @@ def final_validation(config): for w in focused_widgets: path = global_config.get_path_for_id(w) widget_conf = global_config.get_config_for_path(path[:-1]) - if CONF_ADJUSTABLE in widget_conf and not widget_conf[CONF_ADJUSTABLE]: + if df.CONF_ADJUSTABLE in widget_conf and not widget_conf[df.CONF_ADJUSTABLE]: raise cv.Invalid( "A non adjustable arc may not be focused", path, @@ -268,6 +258,7 @@ async def to_code(config): await encoders_to_code(lv_component, config) await theme_to_code(config) await styles_to_code(config) + await gradients_to_code(config) await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) await add_pages(lv_component, config) @@ -351,6 +342,7 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_THEME): cv.Schema( {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} ), + cv.Optional(df.CONF_GRADIENTS): GRADIENT_SCHEMA, cv.Optional(df.CONF_TOUCHSCREENS, default=None): touchscreen_schema, cv.Optional(df.CONF_ENCODERS, default=None): ENCODERS_CONFIG, cv.GenerateID(df.CONF_DEFAULT_GROUP): cv.declare_id(lv_group_t), diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index ee8472f90d..3db49d26a4 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -4,6 +4,8 @@ Constants already defined in esphome.const are not duplicated here and must be i """ +import logging + from esphome import codegen as cg, config_validation as cv from esphome.const import CONF_ITEMS from esphome.core import Lambda @@ -13,8 +15,19 @@ from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from .helpers import requires_component +LOGGER = logging.getLogger(__name__) lvgl_ns = cg.esphome_ns.namespace("lvgl") +lv_defines = {} # Dict of #defines to provide as build flags + + +def add_define(macro, value="1"): + if macro in lv_defines and lv_defines[macro] != value: + LOGGER.error( + "Redefinition of %s - was %s now %s", macro, lv_defines[macro], value + ) + lv_defines[macro] = value + def literal(arg): if isinstance(arg, str): @@ -173,6 +186,9 @@ LV_ANIM = LvConstant( "OUT_BOTTOM", ) +LV_GRAD_DIR = LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER") +LV_DITHER = LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF") + LOG_LEVELS = ( "TRACE", "INFO", @@ -406,6 +422,7 @@ CONF_FLEX_ALIGN_TRACK = "flex_align_track" CONF_FLEX_GROW = "flex_grow" CONF_FREEZE = "freeze" CONF_FULL_REFRESH = "full_refresh" +CONF_GRADIENTS = "gradients" CONF_GRID_CELL_ROW_POS = "grid_cell_row_pos" CONF_GRID_CELL_COLUMN_POS = "grid_cell_column_pos" CONF_GRID_CELL_ROW_SPAN = "grid_cell_row_span" diff --git a/esphome/components/lvgl/gradient.py b/esphome/components/lvgl/gradient.py new file mode 100644 index 0000000000..bc89470d47 --- /dev/null +++ b/esphome/components/lvgl/gradient.py @@ -0,0 +1,61 @@ +from esphome import config_validation as cv +import esphome.codegen as cg +from esphome.const import ( + CONF_COLOR, + CONF_DIRECTION, + CONF_DITHER, + CONF_ID, + CONF_POSITION, +) +from esphome.cpp_generator import MockObj + +from .defines import CONF_GRADIENTS, LV_DITHER, LV_GRAD_DIR, add_define +from .lv_validation import lv_color, lv_fraction +from .lvcode import lv_assign +from .types import lv_gradient_t + +CONF_STOPS = "stops" + + +def min_stops(value): + if len(value) < 2: + raise cv.Invalid("Must have at least 2 stops") + return value + + +GRADIENT_SCHEMA = cv.ensure_list( + cv.Schema( + { + cv.GenerateID(CONF_ID): cv.declare_id(lv_gradient_t), + cv.Optional(CONF_DIRECTION, default="NONE"): LV_GRAD_DIR.one_of, + cv.Optional(CONF_DITHER, default="NONE"): LV_DITHER.one_of, + cv.Required(CONF_STOPS): cv.All( + [ + cv.Schema( + { + cv.Required(CONF_COLOR): lv_color, + cv.Required(CONF_POSITION): lv_fraction, + } + ) + ], + min_stops, + ), + } + ) +) + + +async def gradients_to_code(config): + max_stops = 2 + for gradient in config.get(CONF_GRADIENTS, ()): + var = MockObj(cg.new_Pvariable(gradient[CONF_ID]), "->") + max_stops = max(max_stops, len(gradient[CONF_STOPS])) + lv_assign(var.dir, await LV_GRAD_DIR.process(gradient[CONF_DIRECTION])) + lv_assign(var.dither, await LV_DITHER.process(gradient[CONF_DITHER])) + lv_assign(var.stops_count, len(gradient[CONF_STOPS])) + for index, stop in enumerate(gradient[CONF_STOPS]): + lv_assign(var.stops[index].color, await lv_color.process(stop[CONF_COLOR])) + lv_assign( + var.stops[index].frac, await lv_fraction.process(stop[CONF_POSITION]) + ) + add_define("LV_GRADIENT_MAX_STOPS", max_stops) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index d8af9f7aa9..8593deb869 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -1,12 +1,19 @@ from typing import Union import esphome.codegen as cg -from esphome.components.color import ColorStruct +from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw from esphome.components.font import Font from esphome.components.image import Image_ import esphome.config_validation as cv -from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT, CONF_TIME, CONF_VALUE -from esphome.core import HexInt, Lambda +from esphome.const import ( + CONF_ARGS, + CONF_COLOR, + CONF_FORMAT, + CONF_ID, + CONF_TIME, + CONF_VALUE, +) +from esphome.core import CORE, ID, Lambda from esphome.cpp_generator import MockObj from esphome.cpp_types import ESPTime, uint32 from esphome.helpers import cpp_string_escape @@ -23,14 +30,9 @@ from .defines import ( call_lambda, literal, ) -from .helpers import ( - esphome_fonts_used, - lv_fonts_used, - lvgl_components_required, - requires_component, -) +from .helpers import esphome_fonts_used, lv_fonts_used, requires_component from .lvcode import lv_expr -from .types import lv_font_t, lv_img_t +from .types import lv_font_t, lv_gradient_t, lv_img_t opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") @@ -59,11 +61,17 @@ def color_retmapper(value): if isinstance(value, cv.Lambda): return cv.returning_lambda(value) if isinstance(value, int): - hexval = HexInt(value) - return lv_expr.color_hex(hexval) - # Must be an id - lvgl_components_required.add(CONF_COLOR) - return lv_expr.color_from(MockObj(value)) + return literal( + f"lv_color_make({(value >> 16) & 0xFF}, {(value >> 8) & 0xFF}, {value & 0xFF})" + ) + if isinstance(value, ID): + cval = [x for x in CORE.config[CONF_COLOR] if x[CONF_ID] == value][0] + if CONF_HEX in cval: + r, g, b = cval[CONF_HEX] + else: + r, g, b, _ = from_rgbw(cval) + return literal(f"lv_color_make({r}, {g}, {b})") + assert False def option_string(value): @@ -132,7 +140,7 @@ radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") @schema_extractor("one_of") -def radius_validator(value): +def fraction_validator(value): if value == SCHEMA_EXTRACT: return radius_consts.choices value = cv.Any(size, cv.percentage, radius_consts.one_of)(value) @@ -141,7 +149,7 @@ def radius_validator(value): return value -radius = LValidator(radius_validator, uint32, retmapper=literal) +lv_fraction = LValidator(fraction_validator, uint32, retmapper=literal) def id_name(value): @@ -242,6 +250,21 @@ lv_int = LValidator(cv.int_, cg.int_) lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255)) +def gradient_mapper(value): + return MockObj(value) + + +def gradient_validator(value): + return cv.use_id(lv_gradient_t)(value) + + +lv_gradient = LValidator( + validator=gradient_validator, + rtype=lv_gradient_t, + retmapper=gradient_mapper, +) + + def is_lv_font(font): return isinstance(font, str) and font.lower() in LV_FONTS diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index a3d13f7f8c..3a080d63e9 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -184,8 +184,9 @@ class LvContext(LambdaContext): self.lv_component = lv_component async def add_init_lambda(self): - cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) - LvContext.added_lambda_count += 1 + if self.code_list: + cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) + LvContext.added_lambda_count += 1 async def __aexit__(self, exc_type, exc_val, exc_tb): await super().__aexit__(exc_type, exc_val, exc_tb) diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index e248530971..d5cff51de2 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -42,9 +42,6 @@ extern lv_event_code_t lv_api_event; // NOLINT extern lv_event_code_t lv_update_event; // NOLINT extern std::string lv_event_code_name_for(uint8_t event_code); extern bool lv_is_pre_initialise(); -#ifdef USE_LVGL_COLOR -inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } -#endif // USE_LVGL_COLOR #if LV_COLOR_DEPTH == 16 static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; #elif LV_COLOR_DEPTH == 32 diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 9ff0fec5bc..780057623a 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -17,9 +17,9 @@ from esphome.core import TimePeriod from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid -from .defines import CONF_TIME_FORMAT +from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR from .helpers import add_lv_use, requires_component, validate_printf -from .lv_validation import lv_color, lv_font, lv_image +from .lv_validation import lv_color, lv_font, lv_gradient, lv_image from .lvcode import LvglComponent, lv_event_t_ptr from .types import ( LVEncoderListener, @@ -94,9 +94,10 @@ STYLE_PROPS = { "arc_width": cv.positive_int, "anim_time": lvalid.lv_milliseconds, "bg_color": lvalid.lv_color, + "bg_grad": lv_gradient, "bg_grad_color": lvalid.lv_color, "bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, - "bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of, + "bg_grad_dir": LV_GRAD_DIR.one_of, "bg_grad_stop": lvalid.stop_value, "bg_image_opa": lvalid.opacity, "bg_image_recolor": lvalid.lv_color, @@ -160,7 +161,7 @@ STYLE_PROPS = { "max_width": lvalid.pixels_or_percent, "min_height": lvalid.pixels_or_percent, "min_width": lvalid.pixels_or_percent, - "radius": lvalid.radius, + "radius": lvalid.lv_fraction, "width": lvalid.size, "x": lvalid.pixels_or_percent, "y": lvalid.pixels_or_percent, diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index e4735ea58d..b452ab5fb3 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -59,6 +59,7 @@ LVEncoderListener = lvgl_ns.class_("LVEncoderListener") lv_obj_t = LvType("lv_obj_t") lv_page_t = LvType("LvPageType", parents=(LvCompound,)) lv_img_t = LvType("lv_img_t") +lv_gradient_t = LvType("lv_grad_dsc_t") LV_EVENT = MockObj(base="LV_EVENT_", op="") LV_STATE = MockObj(base="LV_STATE_", op="") diff --git a/esphome/components/lvgl/widgets/meter.py b/esphome/components/lvgl/widgets/meter.py index 7cf154d6f3..36f6643022 100644 --- a/esphome/components/lvgl/widgets/meter.py +++ b/esphome/components/lvgl/widgets/meter.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_COLOR, CONF_COUNT, CONF_ID, + CONF_ITEMS, CONF_LENGTH, CONF_LOCAL, CONF_RANGE_FROM, @@ -17,6 +18,7 @@ from esphome.const import ( from ..automation import action_to_code from ..defines import ( CONF_END_VALUE, + CONF_INDICATOR, CONF_MAIN, CONF_PIVOT_X, CONF_PIVOT_Y, @@ -165,7 +167,12 @@ METER_SCHEMA = {cv.Optional(CONF_SCALES): cv.ensure_list(SCALE_SCHEMA)} class MeterType(WidgetType): def __init__(self): - super().__init__(CONF_METER, lv_meter_t, (CONF_MAIN,), METER_SCHEMA) + super().__init__( + CONF_METER, + lv_meter_t, + (CONF_MAIN, CONF_INDICATOR, CONF_TICKS, CONF_ITEMS), + METER_SCHEMA, + ) async def to_code(self, w: Widget, config): """For a meter object, create and set parameters""" diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 0db6a6a995..9d157ea5b0 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -1,12 +1,32 @@ lvgl: log_level: TRACE bg_color: light_blue - disp_bg_color: 0xffff00 + disp_bg_color: color_id disp_bg_image: cat_image theme: obj: border_width: 1 + gradients: + - id: color_bar + direction: hor + dither: err_diff + stops: + - color: 0xFF0000 + position: 0 + - color: 0xFFFF00 + position: 42 + - color: 0x00FF00 + position: 84 + - color: 0x00FFFF + position: 127 + - color: 0x0000FF + position: 169 + - color: 0xFF00FF + position: 212 + - color: 0xFF0000 + position: 255 + style_definitions: - id: style_test bg_color: 0x2F8CD8 @@ -31,7 +51,7 @@ lvgl: - id: date_style text_font: roboto10 align: center - text_color: 0x000000 + text_color: color_id2 bg_opa: cover radius: 4 pad_all: 2 @@ -386,6 +406,22 @@ lvgl: - id: page2 widgets: + - slider: + min_value: 0 + max_value: 255 + bg_opa: cover + bg_grad: color_bar + radius: 0 + indicator: + bg_opa: transp + knob: + radius: 1 + width: 4 + height: 10% + bg_color: 0x000000 + width: 100% + height: 10% + align: top_mid - button: styles: spin_button id: spin_up @@ -586,3 +622,13 @@ image: color: - id: light_blue hex: "3340FF" + - id: color_id + red: 0.5 + green: 0.5 + blue: 0.5 + white: 0.5 + - id: color_id2 + red_int: 0xFF + green_int: 123 + blue_int: 64 + white_int: 255 From de7d2c33e18246668a64993ce3badc4e1b053359 Mon Sep 17 00:00:00 2001 From: marcovaneck <67060615+marcovaneck@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:22:58 +0200 Subject: [PATCH 2362/2607] [dsmr] Add internal 'telegram' text_sensor to support bridging (#6841) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/dsmr/dsmr.cpp | 6 ++++++ esphome/components/dsmr/dsmr.h | 6 ++++++ esphome/components/dsmr/text_sensor.py | 9 +++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/esphome/components/dsmr/dsmr.cpp b/esphome/components/dsmr/dsmr.cpp index f382730912..193ea1d4e5 100644 --- a/esphome/components/dsmr/dsmr.cpp +++ b/esphome/components/dsmr/dsmr.cpp @@ -256,6 +256,7 @@ bool Dsmr::parse_telegram() { MyData data; ESP_LOGV(TAG, "Trying to parse telegram"); this->stop_requesting_data_(); + ::dsmr::ParseResult res = ::dsmr::P1Parser::parse(&data, this->telegram_, this->bytes_read_, false, this->crc_check_); // Parse telegram according to data definition. Ignore unknown values. @@ -267,6 +268,11 @@ bool Dsmr::parse_telegram() { } else { this->status_clear_warning(); this->publish_sensors(data); + + // publish the telegram, after publishing the sensors so it can also trigger action based on latest values + if (this->s_telegram_ != nullptr) { + this->s_telegram_->publish_state(std::string(this->telegram_, this->bytes_read_)); + } return true; } } diff --git a/esphome/components/dsmr/dsmr.h b/esphome/components/dsmr/dsmr.h index 6621d02cae..7304737b50 100644 --- a/esphome/components/dsmr/dsmr.h +++ b/esphome/components/dsmr/dsmr.h @@ -85,6 +85,9 @@ class Dsmr : public Component, public uart::UARTDevice { void set_##s(text_sensor::TextSensor *sensor) { s_##s##_ = sensor; } DSMR_TEXT_SENSOR_LIST(DSMR_SET_TEXT_SENSOR, ) + // handled outside dsmr + void set_telegram(text_sensor::TextSensor *sensor) { s_telegram_ = sensor; } + protected: void receive_telegram_(); void receive_encrypted_telegram_(); @@ -124,6 +127,9 @@ class Dsmr : public Component, public uart::UARTDevice { bool header_found_{false}; bool footer_found_{false}; + // handled outside dsmr + text_sensor::TextSensor *s_telegram_{nullptr}; + // Sensor member pointers #define DSMR_DECLARE_SENSOR(s) sensor::Sensor *s_##s##_{nullptr}; DSMR_SENSOR_LIST(DSMR_DECLARE_SENSOR, ) diff --git a/esphome/components/dsmr/text_sensor.py b/esphome/components/dsmr/text_sensor.py index 202cc07020..7c13fe7d58 100644 --- a/esphome/components/dsmr/text_sensor.py +++ b/esphome/components/dsmr/text_sensor.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor - +from esphome.const import CONF_INTERNAL from . import Dsmr, CONF_DSMR_ID AUTO_LOAD = ["dsmr"] @@ -22,6 +22,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional("water_equipment_id"): text_sensor.text_sensor_schema(), cv.Optional("sub_equipment_id"): text_sensor.text_sensor_schema(), cv.Optional("gas_delivered_text"): text_sensor.text_sensor_schema(), + cv.Optional("telegram"): text_sensor.text_sensor_schema().extend( + {cv.Optional(CONF_INTERNAL, default=True): cv.boolean} + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -37,7 +40,9 @@ async def to_code(config): if id and id.type == text_sensor.TextSensor: var = await text_sensor.new_text_sensor(conf) cg.add(getattr(hub, f"set_{key}")(var)) - text_sensors.append(f"F({key})") + if key != "telegram": + # telegram is not handled by dsmr + text_sensors.append(f"F({key})") if text_sensors: cg.add_define( From 7abbb0fb97de87469520b45909fb54e83a411b57 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 20:42:46 +0100 Subject: [PATCH 2363/2607] Pull in new AsyncTCP for IPv6 on BK72xx (#7431) --- esphome/components/async_tcp/__init__.py | 6 +++--- platformio.ini | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index eae8c0e2df..99e250b6fc 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -1,13 +1,13 @@ # Dummy integration to allow relying on AsyncTCP import esphome.codegen as cg import esphome.config_validation as cv -from esphome.core import CORE, coroutine_with_priority from esphome.const import ( + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, - PLATFORM_BK72XX, PLATFORM_RTL87XX, ) +from esphome.core import CORE, coroutine_with_priority CODEOWNERS = ["@OttoWinter"] @@ -22,7 +22,7 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): if CORE.is_esp32 or CORE.is_libretiny: # https://github.com/esphome/AsyncTCP/blob/master/library.json - cg.add_library("esphome/AsyncTCP-esphome", "2.1.3") + cg.add_library("esphome/AsyncTCP-esphome", "2.1.4") elif CORE.is_esp8266: # https://github.com/esphome/ESPAsyncTCP cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0") diff --git a/platformio.ini b/platformio.ini index ee18068a29..7d912aaf54 100644 --- a/platformio.ini +++ b/platformio.ini @@ -119,7 +119,7 @@ lib_deps = WiFi ; wifi,web_server_base,ethernet (Arduino built-in) Update ; ota,web_server_base (Arduino built-in) ${common:arduino.lib_deps} - esphome/AsyncTCP-esphome@2.1.3 ; async_tcp + esphome/AsyncTCP-esphome@2.1.4 ; async_tcp WiFiClientSecure ; http_request,nextion (Arduino built-in) HTTPClient ; http_request,nextion (Arduino built-in) ESPmDNS ; mdns (Arduino built-in) From 7b90bfaec69bf685f75ac44ec7e50b56bc614a0d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 20:43:19 +0100 Subject: [PATCH 2364/2607] Bump LibreTiny recommended version to 1.7.0 (#7432) --- esphome/components/libretiny/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 9ba889f493..cc7fae7e70 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -170,13 +170,11 @@ def _notify_old_style(config): return config -# NOTE: Keep this in mind when updating the recommended version: -# * For all constants below, update platformio.ini (in this repo) # The dev and latest branches will be at *least* this version, which is what matters. ARDUINO_VERSIONS = { "dev": (cv.Version(1, 7, 0), "https://github.com/libretiny-eu/libretiny.git"), "latest": (cv.Version(1, 7, 0), "libretiny"), - "recommended": (cv.Version(1, 5, 1), None), + "recommended": (cv.Version(1, 7, 0), None), } From 39ad358b51c105c78e7b060303aa0fb78372f6b3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 10 Sep 2024 23:02:05 +0100 Subject: [PATCH 2365/2607] Enable IPv6 support for BK72xx (#7398) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 4 ++++ .../components/wifi/wifi_component_libretiny.cpp | 16 +++++++++++++++- .../components/network/test-ipv6.bk72xx-ard.yaml | 6 +++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 772ba230d9..be4e102930 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -17,6 +17,7 @@ CONFIG_SCHEMA = cv.Schema( esp8266=False, esp32=False, rp2040=False, + bk72xx=False, ): cv.All( cv.boolean, cv.Any( @@ -25,6 +26,7 @@ CONFIG_SCHEMA = cv.Schema( esp32_arduino=cv.Version(0, 0, 0), esp8266_arduino=cv.Version(0, 0, 0), rp2040_arduino=cv.Version(0, 0, 0), + bk72xx_libretiny=cv.Version(1, 7, 0), ), cv.boolean_false, ), @@ -52,3 +54,5 @@ async def to_code(config): cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6") if CORE.is_esp8266: cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY") + if CORE.is_bk72xx: + cg.add_build_flag("-DCONFIG_IPV6") diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index 19ade84a88..afb30c3bcf 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -85,7 +85,16 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { if (!this->has_sta()) return {}; - return {WiFi.localIP()}; + network::IPAddresses addresses; + addresses[0] = WiFi.localIP(); +#if USE_NETWORK_IPV6 + int i = 1; + auto v6_addresses = WiFi.allLocalIPv6(); + for (auto address : v6_addresses) { + addresses[i++] = network::IPAddress(address.toString().c_str()); + } +#endif /* USE_NETWORK_IPV6 */ + return addresses; } bool WiFiComponent::wifi_apply_hostname_() { @@ -321,6 +330,11 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ s_sta_connecting = false; break; } + case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: { + // auto it = info.got_ip.ip_info; + ESP_LOGV(TAG, "Event: Got IPv6"); + break; + } case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: { ESP_LOGV(TAG, "Event: Lost IP"); break; diff --git a/tests/components/network/test-ipv6.bk72xx-ard.yaml b/tests/components/network/test-ipv6.bk72xx-ard.yaml index 361ca09977..d0c4bbfcb9 100644 --- a/tests/components/network/test-ipv6.bk72xx-ard.yaml +++ b/tests/components/network/test-ipv6.bk72xx-ard.yaml @@ -1,4 +1,8 @@ substitutions: - network_enable_ipv6: "false" + network_enable_ipv6: "true" + +bk72xx: + framework: + version: 1.7.0 <<: !include common.yaml From ffc2b587141d9984698214b2a4858df1756e275b Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Wed, 11 Sep 2024 01:30:46 +0200 Subject: [PATCH 2366/2607] Move I2S config settings the the base i2sAudio files. Phase 1 (#7183) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/i2s_audio/__init__.py | 77 ++++++++++++++++--- esphome/components/i2s_audio/i2s_audio.h | 18 ++++- .../i2s_audio/microphone/__init__.py | 69 ++++------------- .../microphone/i2s_audio_microphone.h | 10 +-- .../components/i2s_audio/speaker/__init__.py | 50 +++++------- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 10 +-- .../i2s_audio/speaker/i2s_audio_speaker.h | 4 +- 7 files changed, 129 insertions(+), 109 deletions(-) diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index 05e44696d8..90dc8a24ee 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -1,16 +1,16 @@ -import esphome.config_validation as cv -import esphome.final_validate as fv -import esphome.codegen as cg - from esphome import pins -from esphome.const import CONF_ID +import esphome.codegen as cg from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( VARIANT_ESP32, + VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3, - VARIANT_ESP32C3, ) +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE +from esphome.cpp_generator import MockObjClass +import esphome.final_validate as fv CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["esp32"] @@ -25,16 +25,22 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" CONF_I2S_AUDIO = "i2s_audio" CONF_I2S_AUDIO_ID = "i2s_audio_id" +CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_I2S_MODE = "i2s_mode" CONF_PRIMARY = "primary" CONF_SECONDARY = "secondary" +CONF_LEFT = "left" +CONF_RIGHT = "right" +CONF_STEREO = "stereo" + i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component) -I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent)) -I2SAudioOut = i2s_audio_ns.class_( - "I2SAudioOut", cg.Parented.template(I2SAudioComponent) +I2SAudioBase = i2s_audio_ns.class_( + "I2SAudioBase", cg.Parented.template(I2SAudioComponent) ) +I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", I2SAudioBase) +I2SAudioOut = i2s_audio_ns.class_("I2SAudioOut", I2SAudioBase) i2s_mode_t = cg.global_ns.enum("i2s_mode_t") I2S_MODE_OPTIONS = { @@ -50,6 +56,59 @@ I2S_PORTS = { VARIANT_ESP32C3: 1, } +i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t") +I2S_CHANNELS = { + CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, + CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, + CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT, +} + +i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t") +I2S_BITS_PER_SAMPLE = { + 8: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_8BIT, + 16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT, + 32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT, +} + +INTERNAL_ADC_VARIANTS = [VARIANT_ESP32] +PDM_VARIANTS = [VARIANT_ESP32, VARIANT_ESP32S3] + +_validate_bits = cv.float_with_unit("bits", "bit") + + +def i2s_audio_component_schema( + class_: MockObjClass, + default_sample_rate: int, + default_channel: str, + default_bits_per_sample: str, +): + return cv.Schema( + { + cv.GenerateID(): cv.declare_id(class_), + cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), + cv.Optional(CONF_CHANNEL, default=default_channel): cv.enum(I2S_CHANNELS), + cv.Optional(CONF_SAMPLE_RATE, default=default_sample_rate): cv.int_range( + min=1 + ), + cv.Optional(CONF_BITS_PER_SAMPLE, default=default_bits_per_sample): cv.All( + _validate_bits, cv.enum(I2S_BITS_PER_SAMPLE) + ), + cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( + I2S_MODE_OPTIONS, lower=True + ), + } + ) + + +async def register_i2s_audio_component(var, config): + await cg.register_parented(var, config[CONF_I2S_AUDIO_ID]) + + cg.add(var.set_i2s_mode(config[CONF_I2S_MODE])) + cg.add(var.set_channel(config[CONF_CHANNEL])) + cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) + cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) + + CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(I2SAudioComponent), diff --git a/esphome/components/i2s_audio/i2s_audio.h b/esphome/components/i2s_audio/i2s_audio.h index d8d4a23dde..727fb6c4e1 100644 --- a/esphome/components/i2s_audio/i2s_audio.h +++ b/esphome/components/i2s_audio/i2s_audio.h @@ -11,9 +11,23 @@ namespace i2s_audio { class I2SAudioComponent; -class I2SAudioIn : public Parented {}; +class I2SAudioBase : public Parented { + public: + void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; } + void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } + void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } + void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } -class I2SAudioOut : public Parented {}; + protected: + i2s_mode_t i2s_mode_{}; + i2s_channel_fmt_t channel_; + uint32_t sample_rate_; + i2s_bits_per_sample_t bits_per_sample_; +}; + +class I2SAudioIn : public I2SAudioBase {}; + +class I2SAudioOut : public I2SAudioBase {}; class I2SAudioComponent : public Component { public: diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index 844f176bea..e2ece03e68 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -1,20 +1,19 @@ -import esphome.config_validation as cv -import esphome.codegen as cg - from esphome import pins -from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER, CONF_SAMPLE_RATE -from esphome.components import microphone, esp32 +import esphome.codegen as cg +from esphome.components import esp32, microphone from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_NUMBER from .. import ( - CONF_I2S_MODE, - CONF_PRIMARY, - I2S_MODE_OPTIONS, - i2s_audio_ns, - I2SAudioComponent, - I2SAudioIn, - CONF_I2S_AUDIO_ID, CONF_I2S_DIN_PIN, + CONF_RIGHT, + INTERNAL_ADC_VARIANTS, + PDM_VARIANTS, + I2SAudioIn, + i2s_audio_component_schema, + i2s_audio_ns, + register_i2s_audio_component, ) CODEOWNERS = ["@jesserockz"] @@ -23,29 +22,13 @@ DEPENDENCIES = ["i2s_audio"] CONF_ADC_PIN = "adc_pin" CONF_ADC_TYPE = "adc_type" CONF_PDM = "pdm" -CONF_BITS_PER_SAMPLE = "bits_per_sample" + CONF_USE_APLL = "use_apll" I2SAudioMicrophone = i2s_audio_ns.class_( "I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component ) -i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t") -CHANNELS = { - "left": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, - "right": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, -} -i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t") -BITS_PER_SAMPLE = { - 16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT, - 32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT, -} - -INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32] -PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3] - -_validate_bits = cv.float_with_unit("bits", "bit") - def validate_esp32_variant(config): variant = esp32.get_esp32_variant() @@ -62,19 +45,7 @@ def validate_esp32_variant(config): BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(I2SAudioMicrophone), - cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), - cv.Optional(CONF_CHANNEL, default="right"): cv.enum(CHANNELS), - cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1), - cv.Optional(CONF_BITS_PER_SAMPLE, default="32bit"): cv.All( - _validate_bits, cv.enum(BITS_PER_SAMPLE) - ), - cv.Optional(CONF_USE_APLL, default=False): cv.boolean, - cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( - I2S_MODE_OPTIONS, lower=True - ), - } + i2s_audio_component_schema(I2SAudioMicrophone, 16000, CONF_RIGHT, "32bit") ).extend(cv.COMPONENT_SCHEMA) CONFIG_SCHEMA = cv.All( @@ -89,6 +60,7 @@ CONFIG_SCHEMA = cv.All( { cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number, cv.Required(CONF_PDM): cv.boolean, + cv.Optional(CONF_USE_APLL, default=False): cv.boolean, } ), }, @@ -101,8 +73,8 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - - await cg.register_parented(var, config[CONF_I2S_AUDIO_ID]) + await register_i2s_audio_component(var, config) + await microphone.register_microphone(var, config) if config[CONF_ADC_TYPE] == "internal": variant = esp32.get_esp32_variant() @@ -112,11 +84,4 @@ async def to_code(config): else: cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) cg.add(var.set_pdm(config[CONF_PDM])) - - cg.add(var.set_i2s_mode(config[CONF_I2S_MODE])) - cg.add(var.set_channel(config[CONF_CHANNEL])) - cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) - cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) - cg.add(var.set_use_apll(config[CONF_USE_APLL])) - - await microphone.register_microphone(var, config) + cg.add(var.set_use_apll(config[CONF_USE_APLL])) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 07ca0528aa..56fb4c252a 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -30,11 +30,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub } #endif - void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; } - - void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } - void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } - void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; } protected: @@ -48,10 +43,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub bool adc_{false}; #endif bool pdm_{false}; - i2s_mode_t i2s_mode_{}; - i2s_channel_fmt_t channel_; - uint32_t sample_rate_; - i2s_bits_per_sample_t bits_per_sample_; + bool use_apll_; HighFrequencyLoopRequester high_freq_; diff --git a/esphome/components/i2s_audio/speaker/__init__.py b/esphome/components/i2s_audio/speaker/__init__.py index 72455af1b7..11fdae0436 100644 --- a/esphome/components/i2s_audio/speaker/__init__.py +++ b/esphome/components/i2s_audio/speaker/__init__.py @@ -1,15 +1,18 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins -from esphome.const import CONF_ID, CONF_MODE +import esphome.codegen as cg from esphome.components import esp32, speaker +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, CONF_ID from .. import ( - CONF_I2S_AUDIO_ID, CONF_I2S_DOUT_PIN, - I2SAudioComponent, + CONF_LEFT, + CONF_RIGHT, + CONF_STEREO, I2SAudioOut, + i2s_audio_component_schema, i2s_audio_ns, + register_i2s_audio_component, ) CODEOWNERS = ["@jesserockz"] @@ -19,18 +22,16 @@ I2SAudioSpeaker = i2s_audio_ns.class_( "I2SAudioSpeaker", cg.Component, speaker.Speaker, I2SAudioOut ) -i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") -CONF_MUTE_PIN = "mute_pin" CONF_DAC_TYPE = "dac_type" +i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") INTERNAL_DAC_OPTIONS = { - "left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, - "right": i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, - "stereo": i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, + CONF_LEFT: i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, + CONF_RIGHT: i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, + CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, } -EXTERNAL_DAC_OPTIONS = ["mono", "stereo"] NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] @@ -44,28 +45,21 @@ def validate_esp32_variant(config): return config +BASE_SCHEMA = speaker.SPEAKER_SCHEMA.extend( + i2s_audio_component_schema(I2SAudioSpeaker, 16000, "stereo", "16bit") +).extend(cv.COMPONENT_SCHEMA) + CONFIG_SCHEMA = cv.All( cv.typed_schema( { - "internal": speaker.SPEAKER_SCHEMA.extend( + "internal": BASE_SCHEMA, + "external": BASE_SCHEMA.extend( { - cv.GenerateID(): cv.declare_id(I2SAudioSpeaker), - cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), - cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), - } - ).extend(cv.COMPONENT_SCHEMA), - "external": speaker.SPEAKER_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(I2SAudioSpeaker), - cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), cv.Required( CONF_I2S_DOUT_PIN ): pins.internal_gpio_output_pin_number, - cv.Optional(CONF_MODE, default="mono"): cv.one_of( - *EXTERNAL_DAC_OPTIONS, lower=True - ), } - ).extend(cv.COMPONENT_SCHEMA), + ), }, key=CONF_DAC_TYPE, ), @@ -76,12 +70,10 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) + await register_i2s_audio_component(var, config) await speaker.register_speaker(var, config) - await cg.register_parented(var, config[CONF_I2S_AUDIO_ID]) - if config[CONF_DAC_TYPE] == "internal": - cg.add(var.set_internal_dac_mode(config[CONF_MODE])) + cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL])) else: cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) - cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index cf5a2c2766..ab26edd8cf 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -64,17 +64,17 @@ void I2SAudioSpeaker::player_task(void *params) { xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); i2s_driver_config_t config = { - .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX), - .sample_rate = 16000, - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .mode = (i2s_mode_t) (this_speaker->i2s_mode_ | I2S_MODE_TX), + .sample_rate = this_speaker->sample_rate_, + .bits_per_sample = this_speaker->bits_per_sample_, + .channel_format = this_speaker->channel_, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 128, .use_apll = false, .tx_desc_auto_clear = true, - .fixed_mclk = I2S_PIN_NO_CHANGE, + .fixed_mclk = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256, .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 0bdb67ceba..8d602e1ead 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -38,7 +38,7 @@ struct DataEvent { uint8_t data[BUFFER_SIZE]; }; -class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAudioOut { +class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Component { public: float get_setup_priority() const override { return esphome::setup_priority::LATE; } @@ -49,7 +49,6 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud #if SOC_I2S_SUPPORTS_DAC void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } #endif - void set_external_dac_channels(uint8_t channels) { this->external_dac_channels_ = channels; } void start() override; void stop() override; @@ -76,7 +75,6 @@ class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAud #if SOC_I2S_SUPPORTS_DAC i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE}; #endif - uint8_t external_dac_channels_; }; } // namespace i2s_audio From dbecade12215d3db7362c2f003c12177561cfd02 Mon Sep 17 00:00:00 2001 From: ArkanStasarik <103874616+ArkanStasarik@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:53:09 +0800 Subject: [PATCH 2367/2607] Implement all supported thermocouple types for MAX31856 (#7218) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/max31856/max31856.cpp | 13 +++++++++++- esphome/components/max31856/max31856.h | 7 +++++-- esphome/components/max31856/sensor.py | 20 +++++++++++++++++++ esphome/components/mcp9600/sensor.py | 4 ++-- esphome/const.py | 1 + tests/components/max31856/test.esp32-ard.yaml | 1 + .../max31856/test.esp32-c3-ard.yaml | 2 ++ .../max31856/test.esp32-c3-idf.yaml | 2 ++ tests/components/max31856/test.esp32-idf.yaml | 1 + .../components/max31856/test.esp8266-ard.yaml | 2 ++ .../components/max31856/test.rp2040-ard.yaml | 2 ++ 11 files changed, 50 insertions(+), 5 deletions(-) diff --git a/esphome/components/max31856/max31856.cpp b/esphome/components/max31856/max31856.cpp index 8ae4be6657..6a4d34b430 100644 --- a/esphome/components/max31856/max31856.cpp +++ b/esphome/components/max31856/max31856.cpp @@ -32,6 +32,12 @@ void MAX31856Sensor::dump_config() { LOG_PIN(" CS Pin: ", this->cs_); ESP_LOGCONFIG(TAG, " Mains Filter: %s", (filter_ == FILTER_60HZ ? "60 Hz" : (filter_ == FILTER_50HZ ? "50 Hz" : "Unknown!"))); + if (this->thermocouple_type_ < 0 || this->thermocouple_type_ > 7) { + ESP_LOGCONFIG(TAG, " Thermocouple Type: Unknown"); + } else { + ESP_LOGCONFIG(TAG, " Thermocouple Type: %c", "BEJKNRST"[this->thermocouple_type_]); + } + LOG_UPDATE_INTERVAL(this); } @@ -129,7 +135,12 @@ void MAX31856Sensor::clear_fault_() { } void MAX31856Sensor::set_thermocouple_type_() { - MAX31856ThermocoupleType type = MAX31856_TCTYPE_K; + MAX31856ThermocoupleType type; + if (this->thermocouple_type_ < 0 || this->thermocouple_type_ > 7) { + type = MAX31856_TCTYPE_K; + } else { + type = this->thermocouple_type_; + } ESP_LOGCONFIG(TAG, "set_thermocouple_type_: 0x%02X", type); uint8_t t = this->read_register_(MAX31856_CR1_REG); t &= 0xF0; // mask off bottom 4 bits diff --git a/esphome/components/max31856/max31856.h b/esphome/components/max31856/max31856.h index 4deb6bc855..8d64cfe8bc 100644 --- a/esphome/components/max31856/max31856.h +++ b/esphome/components/max31856/max31856.h @@ -50,7 +50,6 @@ enum MAX31856Registers { /** * Multiple types of thermocouples supported by the chip. - * Currently only K type implemented here. */ enum MAX31856ThermocoupleType { MAX31856_TCTYPE_B = 0b0000, // 0x00 @@ -78,11 +77,15 @@ class MAX31856Sensor : public sensor::Sensor, void setup() override; void dump_config() override; float get_setup_priority() const override; - void set_filter(MAX31856ConfigFilter filter) { filter_ = filter; } + void set_filter(MAX31856ConfigFilter filter) { this->filter_ = filter; } + void set_thermocouple_type(MAX31856ThermocoupleType thermocouple_type) { + this->thermocouple_type_ = thermocouple_type; + } void update() override; protected: MAX31856ConfigFilter filter_; + MAX31856ThermocoupleType thermocouple_type_; uint8_t read_register_(uint8_t reg); uint32_t read_register24_(uint8_t reg); diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index bf9741aeed..679e02b11d 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -3,6 +3,7 @@ from esphome.components import sensor, spi import esphome.config_validation as cv from esphome.const import ( CONF_MAINS_FILTER, + CONF_THERMOCOUPLE_TYPE, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, @@ -18,6 +19,17 @@ FILTER = { 50: MAX31865ConfigFilter.FILTER_50HZ, 60: MAX31865ConfigFilter.FILTER_60HZ, } +MAX31856ThermocoupleType = max31856_ns.enum("MAX31856ThermocoupleType") +THERMOCOUPLE_TYPE = { + "B": MAX31856ThermocoupleType.MAX31856_TCTYPE_B, + "E": MAX31856ThermocoupleType.MAX31856_TCTYPE_E, + "J": MAX31856ThermocoupleType.MAX31856_TCTYPE_J, + "K": MAX31856ThermocoupleType.MAX31856_TCTYPE_K, + "N": MAX31856ThermocoupleType.MAX31856_TCTYPE_N, + "R": MAX31856ThermocoupleType.MAX31856_TCTYPE_R, + "S": MAX31856ThermocoupleType.MAX31856_TCTYPE_S, + "T": MAX31856ThermocoupleType.MAX31856_TCTYPE_T, +} CONFIG_SCHEMA = ( sensor.sensor_schema( @@ -34,6 +46,13 @@ CONFIG_SCHEMA = ( ), } ) + .extend( + { + cv.Optional(CONF_THERMOCOUPLE_TYPE, default="K"): cv.enum( + THERMOCOUPLE_TYPE, upper=True, space="" + ), + } + ) .extend(cv.polling_component_schema("60s")) .extend(spi.spi_device_schema()) ) @@ -44,3 +63,4 @@ async def to_code(config): await cg.register_component(var, config) await spi.register_spi_device(var, config) cg.add(var.set_filter(config[CONF_MAINS_FILTER])) + cg.add(var.set_thermocouple_type(config[CONF_THERMOCOUPLE_TYPE])) diff --git a/esphome/components/mcp9600/sensor.py b/esphome/components/mcp9600/sensor.py index 8557c7205e..65ae5f2eec 100644 --- a/esphome/components/mcp9600/sensor.py +++ b/esphome/components/mcp9600/sensor.py @@ -1,14 +1,14 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import i2c, sensor +import esphome.config_validation as cv from esphome.const import ( CONF_ID, + CONF_THERMOCOUPLE_TYPE, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) -CONF_THERMOCOUPLE_TYPE = "thermocouple_type" CONF_HOT_JUNCTION = "hot_junction" CONF_COLD_JUNCTION = "cold_junction" diff --git a/esphome/const.py b/esphome/const.py index 169b11a715..7ad31f276f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -852,6 +852,7 @@ CONF_TEMPERATURE_STEP = "temperature_step" CONF_TEXT = "text" CONF_TEXT_SENSORS = "text_sensors" CONF_THEN = "then" +CONF_THERMOCOUPLE_TYPE = "thermocouple_type" CONF_THRESHOLD = "threshold" CONF_THROTTLE = "throttle" CONF_TILT = "tilt" diff --git a/tests/components/max31856/test.esp32-ard.yaml b/tests/components/max31856/test.esp32-ard.yaml index 5561903207..9a4da6b2a2 100644 --- a/tests/components/max31856/test.esp32-ard.yaml +++ b/tests/components/max31856/test.esp32-ard.yaml @@ -10,3 +10,4 @@ sensor: cs_pin: 12 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N diff --git a/tests/components/max31856/test.esp32-c3-ard.yaml b/tests/components/max31856/test.esp32-c3-ard.yaml index 2794866c59..71bbfffb7b 100644 --- a/tests/components/max31856/test.esp32-c3-ard.yaml +++ b/tests/components/max31856/test.esp32-c3-ard.yaml @@ -10,3 +10,5 @@ sensor: cs_pin: 8 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N + diff --git a/tests/components/max31856/test.esp32-c3-idf.yaml b/tests/components/max31856/test.esp32-c3-idf.yaml index 2794866c59..71bbfffb7b 100644 --- a/tests/components/max31856/test.esp32-c3-idf.yaml +++ b/tests/components/max31856/test.esp32-c3-idf.yaml @@ -10,3 +10,5 @@ sensor: cs_pin: 8 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N + diff --git a/tests/components/max31856/test.esp32-idf.yaml b/tests/components/max31856/test.esp32-idf.yaml index 5561903207..9a4da6b2a2 100644 --- a/tests/components/max31856/test.esp32-idf.yaml +++ b/tests/components/max31856/test.esp32-idf.yaml @@ -10,3 +10,4 @@ sensor: cs_pin: 12 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N diff --git a/tests/components/max31856/test.esp8266-ard.yaml b/tests/components/max31856/test.esp8266-ard.yaml index dfd9572ca9..b9c42542fd 100644 --- a/tests/components/max31856/test.esp8266-ard.yaml +++ b/tests/components/max31856/test.esp8266-ard.yaml @@ -10,3 +10,5 @@ sensor: cs_pin: 15 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N + diff --git a/tests/components/max31856/test.rp2040-ard.yaml b/tests/components/max31856/test.rp2040-ard.yaml index 0abc8a081b..8607eb18cf 100644 --- a/tests/components/max31856/test.rp2040-ard.yaml +++ b/tests/components/max31856/test.rp2040-ard.yaml @@ -10,3 +10,5 @@ sensor: cs_pin: 6 update_interval: 15s mains_filter: 50Hz + thermocouple_type: N + From 04248b6840211a9752e74252400230b68620a87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=5Bp=CA=B2=C9=B5s=5D?= Date: Wed, 11 Sep 2024 07:12:20 +0200 Subject: [PATCH 2368/2607] [i2s_audio] Add more options to speakers and microphones (#7306) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/i2s_audio/__init__.py | 24 +++++- esphome/components/i2s_audio/i2s_audio.h | 4 + .../i2s_audio/media_player/__init__.py | 12 ++- .../media_player/i2s_audio_media_player.h | 2 +- .../i2s_audio/microphone/__init__.py | 19 +++-- .../microphone/i2s_audio_microphone.cpp | 33 ++++---- .../microphone/i2s_audio_microphone.h | 4 - .../components/i2s_audio/speaker/__init__.py | 32 ++++++-- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 76 +++++++++++-------- .../i2s_audio/speaker/i2s_audio_speaker.h | 3 +- tests/components/speaker/test.esp32-ard.yaml | 1 - .../components/speaker/test.esp32-c3-ard.yaml | 1 - .../components/speaker/test.esp32-c3-idf.yaml | 1 - tests/components/speaker/test.esp32-idf.yaml | 1 - .../voice_assistant/test.esp32-ard.yaml | 1 - .../voice_assistant/test.esp32-c3-ard.yaml | 1 - .../voice_assistant/test.esp32-c3-idf.yaml | 1 - .../voice_assistant/test.esp32-idf.yaml | 1 - 18 files changed, 136 insertions(+), 81 deletions(-) diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index 90dc8a24ee..d376907925 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -30,6 +30,10 @@ CONF_I2S_MODE = "i2s_mode" CONF_PRIMARY = "primary" CONF_SECONDARY = "secondary" +CONF_USE_APLL = "use_apll" +CONF_BITS_PER_SAMPLE = "bits_per_sample" +CONF_BITS_PER_CHANNEL = "bits_per_channel" +CONF_MONO = "mono" CONF_LEFT = "left" CONF_RIGHT = "right" CONF_STEREO = "stereo" @@ -58,6 +62,7 @@ I2S_PORTS = { i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t") I2S_CHANNELS = { + CONF_MONO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ALL_LEFT, CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT, @@ -67,17 +72,25 @@ i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t") I2S_BITS_PER_SAMPLE = { 8: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_8BIT, 16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT, + 24: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_24BIT, 32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT, } -INTERNAL_ADC_VARIANTS = [VARIANT_ESP32] -PDM_VARIANTS = [VARIANT_ESP32, VARIANT_ESP32S3] +i2s_bits_per_chan_t = cg.global_ns.enum("i2s_bits_per_chan_t") +I2S_BITS_PER_CHANNEL = { + "default": i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_DEFAULT, + 8: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_8BIT, + 16: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_16BIT, + 24: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_24BIT, + 32: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_32BIT, +} _validate_bits = cv.float_with_unit("bits", "bit") def i2s_audio_component_schema( class_: MockObjClass, + *, default_sample_rate: int, default_channel: str, default_bits_per_sample: str, @@ -96,6 +109,11 @@ def i2s_audio_component_schema( cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( I2S_MODE_OPTIONS, lower=True ), + cv.Optional(CONF_USE_APLL, default=False): cv.boolean, + cv.Optional(CONF_BITS_PER_CHANNEL, default="default"): cv.All( + cv.Any(cv.float_with_unit("bits", "bit"), "default"), + cv.enum(I2S_BITS_PER_CHANNEL), + ), } ) @@ -107,6 +125,8 @@ async def register_i2s_audio_component(var, config): cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) + cg.add(var.set_bits_per_channel(config[CONF_BITS_PER_CHANNEL])) + cg.add(var.set_use_apll(config[CONF_USE_APLL])) CONFIG_SCHEMA = cv.Schema( diff --git a/esphome/components/i2s_audio/i2s_audio.h b/esphome/components/i2s_audio/i2s_audio.h index 727fb6c4e1..7e2798c33d 100644 --- a/esphome/components/i2s_audio/i2s_audio.h +++ b/esphome/components/i2s_audio/i2s_audio.h @@ -17,12 +17,16 @@ class I2SAudioBase : public Parented { void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } + void set_bits_per_channel(i2s_bits_per_chan_t bits_per_channel) { this->bits_per_channel_ = bits_per_channel; } + void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; } protected: i2s_mode_t i2s_mode_{}; i2s_channel_fmt_t channel_; uint32_t sample_rate_; i2s_bits_per_sample_t bits_per_sample_; + i2s_bits_per_chan_t bits_per_channel_; + bool use_apll_; }; class I2SAudioIn : public I2SAudioBase {}; diff --git a/esphome/components/i2s_audio/media_player/__init__.py b/esphome/components/i2s_audio/media_player/__init__.py index 600a308e6c..dfa69ecadd 100644 --- a/esphome/components/i2s_audio/media_player/__init__.py +++ b/esphome/components/i2s_audio/media_player/__init__.py @@ -12,6 +12,10 @@ from .. import ( I2SAudioOut, CONF_I2S_AUDIO_ID, CONF_I2S_DOUT_PIN, + CONF_LEFT, + CONF_RIGHT, + CONF_MONO, + CONF_STEREO, ) CODEOWNERS = ["@jesserockz"] @@ -30,12 +34,12 @@ CONF_DAC_TYPE = "dac_type" CONF_I2S_COMM_FMT = "i2s_comm_fmt" INTERNAL_DAC_OPTIONS = { - "left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, - "right": i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, - "stereo": i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, + CONF_LEFT: i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, + CONF_RIGHT: i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, + CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, } -EXTERNAL_DAC_OPTIONS = ["mono", "stereo"] +EXTERNAL_DAC_OPTIONS = [CONF_MONO, CONF_STEREO] NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index 5afe778122..4672f94d7e 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -23,7 +23,7 @@ enum I2SState : uint8_t { I2S_STATE_STOPPING, }; -class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, public I2SAudioOut { +class I2SAudioMediaPlayer : public Component, public Parented, public media_player::MediaPlayer { public: void setup() override; float get_setup_priority() const override { return esphome::setup_priority::LATE; } diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index e2ece03e68..161046e962 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -8,8 +8,6 @@ from esphome.const import CONF_ID, CONF_NUMBER from .. import ( CONF_I2S_DIN_PIN, CONF_RIGHT, - INTERNAL_ADC_VARIANTS, - PDM_VARIANTS, I2SAudioIn, i2s_audio_component_schema, i2s_audio_ns, @@ -23,12 +21,13 @@ CONF_ADC_PIN = "adc_pin" CONF_ADC_TYPE = "adc_type" CONF_PDM = "pdm" -CONF_USE_APLL = "use_apll" - I2SAudioMicrophone = i2s_audio_ns.class_( "I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component ) +INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32] +PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3] + def validate_esp32_variant(config): variant = esp32.get_esp32_variant() @@ -45,9 +44,15 @@ def validate_esp32_variant(config): BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( - i2s_audio_component_schema(I2SAudioMicrophone, 16000, CONF_RIGHT, "32bit") + i2s_audio_component_schema( + I2SAudioMicrophone, + default_sample_rate=16000, + default_channel=CONF_RIGHT, + default_bits_per_sample="32bit", + ) ).extend(cv.COMPONENT_SCHEMA) + CONFIG_SCHEMA = cv.All( cv.typed_schema( { @@ -59,8 +64,7 @@ CONFIG_SCHEMA = cv.All( "external": BASE_SCHEMA.extend( { cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number, - cv.Required(CONF_PDM): cv.boolean, - cv.Optional(CONF_USE_APLL, default=False): cv.boolean, + cv.Optional(CONF_PDM, default=False): cv.boolean, } ), }, @@ -84,4 +88,3 @@ async def to_code(config): else: cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) cg.add(var.set_pdm(config[CONF_PDM])) - cg.add(var.set_use_apll(config[CONF_USE_APLL])) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index cb49a744fc..23689afb91 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -58,7 +58,7 @@ void I2SAudioMicrophone::start_() { .tx_desc_auto_clear = false, .fixed_mclk = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256, - .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, + .bits_per_chan = this->bits_per_channel_, }; esp_err_t err; @@ -167,21 +167,24 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { return 0; } this->status_clear_warning(); - if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { - return bytes_read; - } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { - std::vector samples; - size_t samples_read = bytes_read / sizeof(int32_t); - samples.resize(samples_read); - for (size_t i = 0; i < samples_read; i++) { - int32_t temp = reinterpret_cast(buf)[i] >> 14; - samples[i] = clamp(temp, INT16_MIN, INT16_MAX); + // ESP-IDF I2S implementation right-extends 8-bit data to 16 bits, + // and 24-bit data to 32 bits. + switch (this->bits_per_sample_) { + case I2S_BITS_PER_SAMPLE_8BIT: + case I2S_BITS_PER_SAMPLE_16BIT: + return bytes_read; + case I2S_BITS_PER_SAMPLE_24BIT: + case I2S_BITS_PER_SAMPLE_32BIT: { + size_t samples_read = bytes_read / sizeof(int32_t); + for (size_t i = 0; i < samples_read; i++) { + int32_t temp = reinterpret_cast(buf)[i] >> 14; + buf[i] = clamp(temp, INT16_MIN, INT16_MAX); + } + return samples_read * sizeof(int16_t); } - memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); - return samples_read * sizeof(int16_t); - } else { - ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); - return 0; + default: + ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); + return 0; } } diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 56fb4c252a..ea3f357624 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -30,8 +30,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub } #endif - void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; } - protected: void start_(); void stop_(); @@ -44,8 +42,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub #endif bool pdm_{false}; - bool use_apll_; - HighFrequencyLoopRequester high_freq_; }; diff --git a/esphome/components/i2s_audio/speaker/__init__.py b/esphome/components/i2s_audio/speaker/__init__.py index 11fdae0436..22a5af259d 100644 --- a/esphome/components/i2s_audio/speaker/__init__.py +++ b/esphome/components/i2s_audio/speaker/__init__.py @@ -2,11 +2,12 @@ from esphome import pins import esphome.codegen as cg from esphome.components import esp32, speaker import esphome.config_validation as cv -from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_MODE, CONF_TIMEOUT from .. import ( CONF_I2S_DOUT_PIN, CONF_LEFT, + CONF_MONO, CONF_RIGHT, CONF_STEREO, I2SAudioOut, @@ -32,7 +33,6 @@ INTERNAL_DAC_OPTIONS = { CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, } - NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] @@ -45,14 +45,33 @@ def validate_esp32_variant(config): return config -BASE_SCHEMA = speaker.SPEAKER_SCHEMA.extend( - i2s_audio_component_schema(I2SAudioSpeaker, 16000, "stereo", "16bit") -).extend(cv.COMPONENT_SCHEMA) +BASE_SCHEMA = ( + speaker.SPEAKER_SCHEMA.extend( + i2s_audio_component_schema( + I2SAudioSpeaker, + default_sample_rate=16000, + default_channel=CONF_MONO, + default_bits_per_sample="16bit", + ) + ) + .extend( + { + cv.Optional( + CONF_TIMEOUT, default="100ms" + ): cv.positive_time_period_milliseconds, + } + ) + .extend(cv.COMPONENT_SCHEMA) +) CONFIG_SCHEMA = cv.All( cv.typed_schema( { - "internal": BASE_SCHEMA, + "internal": BASE_SCHEMA.extend( + { + cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), + } + ), "external": BASE_SCHEMA.extend( { cv.Required( @@ -77,3 +96,4 @@ async def to_code(config): cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL])) else: cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) + cg.add(var.set_timeout(config[CONF_TIMEOUT])) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index ab26edd8cf..4b427898a2 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -56,6 +56,21 @@ void I2SAudioSpeaker::start_() { this->task_created_ = true; } +template const uint8_t *convert_data_format(const a *from, b *to, size_t &bytes, bool repeat) { + if (sizeof(a) == sizeof(b) && !repeat) { + return reinterpret_cast(from); + } + const b *result = to; + for (size_t i = 0; i < bytes; i += sizeof(a)) { + b value = static_cast(*from++) << (sizeof(b) - sizeof(a)) * 8; + *to++ = value; + if (repeat) + *to++ = value; + } + bytes *= (sizeof(b) / sizeof(a)) * (repeat ? 2 : 1); // NOLINT + return reinterpret_cast(result); +} + void I2SAudioSpeaker::player_task(void *params) { I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params; @@ -71,12 +86,12 @@ void I2SAudioSpeaker::player_task(void *params) { .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, - .dma_buf_len = 128, - .use_apll = false, + .dma_buf_len = 256, + .use_apll = this_speaker->use_apll_, .tx_desc_auto_clear = true, .fixed_mclk = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256, - .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, + .bits_per_chan = this_speaker->bits_per_channel_, }; #if SOC_I2S_SUPPORTS_DAC if (this_speaker->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { @@ -114,10 +129,11 @@ void I2SAudioSpeaker::player_task(void *params) { event.type = TaskEventType::STARTED; xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); - int16_t buffer[BUFFER_SIZE / 2]; + int32_t buffer[BUFFER_SIZE]; while (true) { - if (xQueueReceive(this_speaker->buffer_queue_, &data_event, 100 / portTICK_PERIOD_MS) != pdTRUE) { + if (xQueueReceive(this_speaker->buffer_queue_, &data_event, this_speaker->timeout_ / portTICK_PERIOD_MS) != + pdTRUE) { break; // End of audio from main thread } if (data_event.stop) { @@ -125,17 +141,28 @@ void I2SAudioSpeaker::player_task(void *params) { xQueueReset(this_speaker->buffer_queue_); // Flush queue break; } - size_t bytes_written; - memmove(buffer, data_event.data, data_event.len); - size_t remaining = data_event.len / 2; - size_t current = 0; + const uint8_t *data = data_event.data; + size_t remaining = data_event.len; + switch (this_speaker->bits_per_sample_) { + case I2S_BITS_PER_SAMPLE_8BIT: + case I2S_BITS_PER_SAMPLE_16BIT: { + data = convert_data_format(reinterpret_cast(data), reinterpret_cast(buffer), + remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); + break; + } + case I2S_BITS_PER_SAMPLE_24BIT: + case I2S_BITS_PER_SAMPLE_32BIT: { + data = convert_data_format(reinterpret_cast(data), reinterpret_cast(buffer), + remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); + break; + } + } - while (remaining > 0) { - uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF); - - esp_err_t err = i2s_write(this_speaker->parent_->get_port(), &sample, sizeof(sample), &bytes_written, - (10 / portTICK_PERIOD_MS)); + while (remaining != 0) { + size_t bytes_written; + esp_err_t err = + i2s_write(this_speaker->parent_->get_port(), data, remaining, &bytes_written, (32 / portTICK_PERIOD_MS)); if (err != ESP_OK) { event = {.type = TaskEventType::WARNING, .err = err}; if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { @@ -143,21 +170,8 @@ void I2SAudioSpeaker::player_task(void *params) { } continue; } - if (bytes_written != sizeof(sample)) { - event = {.type = TaskEventType::WARNING, .err = ESP_FAIL}; - if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGW(TAG, "Failed to send WARNING event"); - } - continue; - } - remaining--; - current++; - } - - event.type = TaskEventType::PLAYING; - event.err = current; - if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGW(TAG, "Failed to send PLAYING event"); + data += bytes_written; + remaining -= bytes_written; } } @@ -213,13 +227,11 @@ void I2SAudioSpeaker::watch_() { case TaskEventType::STARTED: ESP_LOGD(TAG, "Started I2S Audio Speaker"); this->state_ = speaker::STATE_RUNNING; + this->status_clear_warning(); break; case TaskEventType::STOPPING: ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); break; - case TaskEventType::PLAYING: - this->status_clear_warning(); - break; case TaskEventType::STOPPED: this->state_ = speaker::STATE_STOPPED; vTaskDelete(this->player_task_handle_); diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 8d602e1ead..7adc4e8a24 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -21,7 +21,6 @@ static const size_t BUFFER_SIZE = 1024; enum class TaskEventType : uint8_t { STARTING = 0, STARTED, - PLAYING, STOPPING, STOPPED, WARNING = 255, @@ -45,6 +44,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp void setup() override; void loop() override; + void set_timeout(uint32_t ms) { this->timeout_ = ms; } void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; } #if SOC_I2S_SUPPORTS_DAC void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } @@ -69,6 +69,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp QueueHandle_t buffer_queue_; QueueHandle_t event_queue_; + uint32_t timeout_{0}; uint8_t dout_pin_{0}; bool task_created_{false}; diff --git a/tests/components/speaker/test.esp32-ard.yaml b/tests/components/speaker/test.esp32-ard.yaml index e10c3e88c1..ab20f36eb6 100644 --- a/tests/components/speaker/test.esp32-ard.yaml +++ b/tests/components/speaker/test.esp32-ard.yaml @@ -21,4 +21,3 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 13 - mode: mono diff --git a/tests/components/speaker/test.esp32-c3-ard.yaml b/tests/components/speaker/test.esp32-c3-ard.yaml index 08699d8b22..c966f9daa7 100644 --- a/tests/components/speaker/test.esp32-c3-ard.yaml +++ b/tests/components/speaker/test.esp32-c3-ard.yaml @@ -21,4 +21,3 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 3 - mode: mono diff --git a/tests/components/speaker/test.esp32-c3-idf.yaml b/tests/components/speaker/test.esp32-c3-idf.yaml index 08699d8b22..c966f9daa7 100644 --- a/tests/components/speaker/test.esp32-c3-idf.yaml +++ b/tests/components/speaker/test.esp32-c3-idf.yaml @@ -21,4 +21,3 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 3 - mode: mono diff --git a/tests/components/speaker/test.esp32-idf.yaml b/tests/components/speaker/test.esp32-idf.yaml index e10c3e88c1..ab20f36eb6 100644 --- a/tests/components/speaker/test.esp32-idf.yaml +++ b/tests/components/speaker/test.esp32-idf.yaml @@ -21,4 +21,3 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 13 - mode: mono diff --git a/tests/components/voice_assistant/test.esp32-ard.yaml b/tests/components/voice_assistant/test.esp32-ard.yaml index 7f6fd85303..cbf9460087 100644 --- a/tests/components/voice_assistant/test.esp32-ard.yaml +++ b/tests/components/voice_assistant/test.esp32-ard.yaml @@ -28,7 +28,6 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 12 - mode: mono voice_assistant: microphone: mic_id_external diff --git a/tests/components/voice_assistant/test.esp32-c3-ard.yaml b/tests/components/voice_assistant/test.esp32-c3-ard.yaml index 248ae4d0dc..86357fad36 100644 --- a/tests/components/voice_assistant/test.esp32-c3-ard.yaml +++ b/tests/components/voice_assistant/test.esp32-c3-ard.yaml @@ -28,7 +28,6 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 2 - mode: mono voice_assistant: microphone: mic_id_external diff --git a/tests/components/voice_assistant/test.esp32-c3-idf.yaml b/tests/components/voice_assistant/test.esp32-c3-idf.yaml index 248ae4d0dc..86357fad36 100644 --- a/tests/components/voice_assistant/test.esp32-c3-idf.yaml +++ b/tests/components/voice_assistant/test.esp32-c3-idf.yaml @@ -28,7 +28,6 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 2 - mode: mono voice_assistant: microphone: mic_id_external diff --git a/tests/components/voice_assistant/test.esp32-idf.yaml b/tests/components/voice_assistant/test.esp32-idf.yaml index 2e0209311d..da9b50721f 100644 --- a/tests/components/voice_assistant/test.esp32-idf.yaml +++ b/tests/components/voice_assistant/test.esp32-idf.yaml @@ -28,7 +28,6 @@ speaker: id: speaker_id dac_type: external i2s_dout_pin: 12 - mode: mono voice_assistant: microphone: mic_id_external From e3ae8cd31ec501541dbe5f93366ca0b6cac3d2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Trevi=C3=B1o?= Date: Wed, 11 Sep 2024 07:16:52 +0200 Subject: [PATCH 2369/2607] [uponor_smatrix] Modifies sending algorithm (#7326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rafa Treviño --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 10 ++++------ esphome/components/uponor_smatrix/uponor_smatrix.h | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index a7014dc96c..e058de2852 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -45,11 +45,8 @@ void UponorSmatrixComponent::loop() { // Read incoming data while (this->available()) { - // The controller polls devices every 10 seconds, with around 200 ms between devices. - // Remember timestamps so we can send our own packets when the bus is expected to be silent. - if (now - this->last_rx_ > 500) { - this->last_poll_start_ = now; - } + // The controller polls devices every 10 seconds in some units or continuously in others with around 200 ms between + // devices. Remember timestamps so we can send our own packets when the bus is expected to be silent. this->last_rx_ = now; uint8_t byte; @@ -60,7 +57,8 @@ void UponorSmatrixComponent::loop() { } // Send packets during bus silence - if ((now - this->last_rx_ > 300) && (now - this->last_poll_start_ < 9500) && (now - this->last_tx_ > 200)) { + if (this->rx_buffer_.empty() && (now - this->last_rx_ > 50) && (now - this->last_rx_ < 100) && + (now - this->last_tx_ > 200)) { #ifdef USE_TIME // Only build time packet when bus is silent and queue is empty to make sure we can send it right away if (this->send_time_requested_ && this->tx_queue_.empty() && this->do_send_time_()) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.h b/esphome/components/uponor_smatrix/uponor_smatrix.h index b7667b5b87..e3e19a12fc 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.h +++ b/esphome/components/uponor_smatrix/uponor_smatrix.h @@ -93,7 +93,6 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component { std::queue> tx_queue_; uint32_t last_rx_; uint32_t last_tx_; - uint32_t last_poll_start_; #ifdef USE_TIME time::RealTimeClock *time_id_{nullptr}; From 955a909846c45d93fa49e91079683a9eef053cdd Mon Sep 17 00:00:00 2001 From: ajwahab <1449672+ajwahab@users.noreply.github.com> Date: Wed, 11 Sep 2024 01:20:30 -0400 Subject: [PATCH 2370/2607] User configurable frame buffer. (#7360) --- esphome/components/esp32_camera/__init__.py | 4 ++++ esphome/components/esp32_camera/esp32_camera.cpp | 10 +++++++++- esphome/components/esp32_camera/esp32_camera.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index 4187429412..2f1f9b90bb 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -140,6 +140,8 @@ CONF_TEST_PATTERN = "test_pattern" # framerates CONF_MAX_FRAMERATE = "max_framerate" CONF_IDLE_FRAMERATE = "idle_framerate" +# frame buffer +CONF_FRAME_BUFFER_COUNT = "frame_buffer_count" # stream trigger CONF_ON_STREAM_START = "on_stream_start" @@ -213,6 +215,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All( cv.framerate, cv.Range(min=0, max=1) ), + cv.Optional(CONF_FRAME_BUFFER_COUNT, default=1): cv.int_range(min=1, max=2), cv.Optional(CONF_ON_STREAM_START): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( @@ -285,6 +288,7 @@ async def to_code(config): cg.add(var.set_idle_update_interval(0)) else: cg.add(var.set_idle_update_interval(1000 / config[CONF_IDLE_FRAMERATE])) + cg.add(var.set_frame_buffer_count(config[CONF_FRAME_BUFFER_COUNT])) cg.add(var.set_frame_size(config[CONF_RESOLUTION])) cg.add_define("USE_ESP32_CAMERA") diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index 555f6ca5f1..e9e9d3cffb 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -127,7 +127,7 @@ void ESP32Camera::dump_config() { sensor_t *s = esp_camera_sensor_get(); auto st = s->status; ESP_LOGCONFIG(TAG, " JPEG Quality: %u", st.quality); - // ESP_LOGCONFIG(TAG, " Framebuffer Count: %u", conf.fb_count); + ESP_LOGCONFIG(TAG, " Framebuffer Count: %u", conf.fb_count); ESP_LOGCONFIG(TAG, " Contrast: %d", st.contrast); ESP_LOGCONFIG(TAG, " Brightness: %d", st.brightness); ESP_LOGCONFIG(TAG, " Saturation: %d", st.saturation); @@ -212,6 +212,8 @@ ESP32Camera::ESP32Camera() { this->config_.frame_size = FRAMESIZE_VGA; // 640x480 this->config_.jpeg_quality = 10; this->config_.fb_count = 1; + this->config_.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + this->config_.fb_location = CAMERA_FB_IN_PSRAM; global_esp32_camera = this; } @@ -333,6 +335,12 @@ void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) { void ESP32Camera::set_idle_update_interval(uint32_t idle_update_interval) { this->idle_update_interval_ = idle_update_interval; } +/* set frame buffer parameters */ +void ESP32Camera::set_frame_buffer_mode(camera_grab_mode_t mode) { this->config_.grab_mode = mode; } +void ESP32Camera::set_frame_buffer_count(uint8_t fb_count) { + this->config_.fb_count = fb_count; + this->set_frame_buffer_mode(fb_count > 1 ? CAMERA_GRAB_LATEST : CAMERA_GRAB_WHEN_EMPTY); +} /* ---------------- public API (specific) ---------------- */ void ESP32Camera::add_image_callback(std::function)> &&callback) { diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h index 0c25381039..71f47d3c06 100644 --- a/esphome/components/esp32_camera/esp32_camera.h +++ b/esphome/components/esp32_camera/esp32_camera.h @@ -145,6 +145,9 @@ class ESP32Camera : public Component, public EntityBase { /* -- framerates */ void set_max_update_interval(uint32_t max_update_interval); void set_idle_update_interval(uint32_t idle_update_interval); + /* -- frame buffer */ + void set_frame_buffer_mode(camera_grab_mode_t mode); + void set_frame_buffer_count(uint8_t fb_count); /* public API (derivated) */ void setup() override; From 625726c65074530e06b74c31254db700956bc23b Mon Sep 17 00:00:00 2001 From: Tercio Filho Date: Wed, 11 Sep 2024 02:21:31 -0300 Subject: [PATCH 2371/2607] [Modbus Controller] Added preference to change command retries (#7312) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/modbus_controller/__init__.py | 3 ++ esphome/components/modbus_controller/const.py | 1 + .../modbus_controller/modbus_controller.cpp | 37 ++++++++++--------- .../modbus_controller/modbus_controller.h | 18 +++++++-- .../modbus_controller/test.esp32-ard.yaml | 1 + .../modbus_controller/test.esp32-idf.yaml | 1 + 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 8146124c28..6917807b07 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -21,6 +21,7 @@ from .const import ( CONF_CUSTOM_COMMAND, CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, + CONF_MAX_CMD_RETRIES, CONF_ON_COMMAND_SENT, CONF_REGISTER_COUNT, CONF_REGISTER_TYPE, @@ -131,6 +132,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional( CONF_COMMAND_THROTTLE, default="0ms" ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_MAX_CMD_RETRIES, default=4): cv.positive_int, cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int, cv.Optional( CONF_SERVER_REGISTERS, @@ -257,6 +259,7 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS])) cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE])) + cg.add(var.set_max_cmd_retries(config[CONF_MAX_CMD_RETRIES])) cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES])) if CONF_SERVER_REGISTERS in config: for server_register in config[CONF_SERVER_REGISTERS]: diff --git a/esphome/components/modbus_controller/const.py b/esphome/components/modbus_controller/const.py index 5d9a61dee7..5cf7d230f1 100644 --- a/esphome/components/modbus_controller/const.py +++ b/esphome/components/modbus_controller/const.py @@ -5,6 +5,7 @@ CONF_COMMAND_THROTTLE = "command_throttle" CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates" CONF_CUSTOM_COMMAND = "custom_command" CONF_FORCE_NEW_RANGE = "force_new_range" +CONF_MAX_CMD_RETRIES = "max_cmd_retries" CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id" CONF_MODBUS_FUNCTIONCODE = "modbus_functioncode" CONF_ON_COMMAND_SENT = "on_command_sent" diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 8f48847a4f..1dcb533629 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -18,11 +18,11 @@ void ModbusController::setup() { this->create_register_ranges_(); } bool ModbusController::send_next_command_() { uint32_t last_send = millis() - this->last_command_timestamp_; - if ((last_send > this->command_throttle_) && !waiting_for_response() && !command_queue_.empty()) { - auto &command = command_queue_.front(); + if ((last_send > this->command_throttle_) && !waiting_for_response() && !this->command_queue_.empty()) { + auto &command = this->command_queue_.front(); // remove from queue if command was sent too often - if (command->send_countdown < 1) { + if (!command->should_retry(this->max_cmd_retries_)) { if (!this->module_offline_) { ESP_LOGW(TAG, "Modbus device=%d set offline", this->address_); @@ -34,11 +34,9 @@ bool ModbusController::send_next_command_() { } } this->module_offline_ = true; - ESP_LOGD( - TAG, - "Modbus command to device=%d register=0x%02X countdown=%d no response received - removed from send queue", - this->address_, command->register_address, command->send_countdown); - command_queue_.pop_front(); + ESP_LOGD(TAG, "Modbus command to device=%d register=0x%02X no response received - removed from send queue", + this->address_, command->register_address); + this->command_queue_.pop_front(); } else { ESP_LOGV(TAG, "Sending next modbus command to device %d register 0x%02X count %d", this->address_, command->register_address, command->register_count); @@ -50,11 +48,11 @@ bool ModbusController::send_next_command_() { // remove from queue if no handler is defined if (!command->on_data_func) { - command_queue_.pop_front(); + this->command_queue_.pop_front(); } } } - return (!command_queue_.empty()); + return (!this->command_queue_.empty()); } // Queue incoming response @@ -77,7 +75,7 @@ void ModbusController::on_modbus_data(const std::vector &data) { current_command->payload = data; this->incoming_queue_.push(std::move(current_command)); ESP_LOGV(TAG, "Modbus response queued"); - command_queue_.pop_front(); + this->command_queue_.pop_front(); } } @@ -99,7 +97,7 @@ void ModbusController::on_modbus_error(uint8_t function_code, uint8_t exception_ "payload size=%zu", function_code, current_command->register_address, current_command->register_count, current_command->payload.size()); - command_queue_.pop_front(); + this->command_queue_.pop_front(); } } @@ -178,7 +176,7 @@ void ModbusController::queue_command(const ModbusCommandItem &command) { if (!this->allow_duplicate_commands_) { // check if this command is already qeued. // not very effective but the queue is never really large - for (auto &item : command_queue_) { + for (auto &item : this->command_queue_) { if (item->is_equal(command)) { ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u", static_cast(command.register_type), command.register_address, command.register_count); @@ -189,7 +187,7 @@ void ModbusController::queue_command(const ModbusCommandItem &command) { } } } - command_queue_.push_back(make_unique(command)); + this->command_queue_.push_back(make_unique(command)); } void ModbusController::update_range_(RegisterRange &r) { @@ -224,8 +222,8 @@ void ModbusController::update_range_(RegisterRange &r) { // Once we get a response to the command it is removed from the queue and the next command is send // void ModbusController::update() { - if (!command_queue_.empty()) { - ESP_LOGV(TAG, "%zu modbus commands already in queue", command_queue_.size()); + if (!this->command_queue_.empty()) { + ESP_LOGV(TAG, "%zu modbus commands already in queue", this->command_queue_.size()); } else { ESP_LOGV(TAG, "Updating modbus component"); } @@ -346,6 +344,8 @@ size_t ModbusController::create_register_ranges_() { void ModbusController::dump_config() { ESP_LOGCONFIG(TAG, "ModbusController:"); ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, " Max Command Retries: %d", this->max_cmd_retries_); + ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE ESP_LOGCONFIG(TAG, "sensormap"); for (auto &it : sensorset_) { @@ -560,8 +560,9 @@ bool ModbusCommandItem::send() { } else { modbusdevice->send_raw(this->payload); } - ESP_LOGV(TAG, "Command sent %d 0x%X %d", uint8_t(this->function_code), this->register_address, this->register_count); - send_countdown--; + this->send_count_++; + ESP_LOGV(TAG, "Command sent %d 0x%X %d send_count: %d", uint8_t(this->function_code), this->register_address, + this->register_count, this->send_count_); return true; } diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index e88f4c07f7..1fa35e1535 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -312,7 +312,6 @@ struct RegisterRange { class ModbusCommandItem { public: static const size_t MAX_PAYLOAD_BYTES = 240; - static const uint8_t MAX_SEND_REPEATS = 5; ModbusController *modbusdevice; uint16_t register_address; uint16_t register_count; @@ -322,9 +321,9 @@ class ModbusCommandItem { on_data_func; std::vector payload = {}; bool send(); - // wrong commands (esp. custom commands) can block the send queue - // limit the number of repeats - uint8_t send_countdown{MAX_SEND_REPEATS}; + /// Check if the command should be retried based on the max_retries parameter + bool should_retry(uint8_t max_retries) { return this->send_count_ <= max_retries; }; + /// factory methods /** Create modbus read command * Function code 02-04 @@ -413,6 +412,11 @@ class ModbusCommandItem { &&handler = nullptr); bool is_equal(const ModbusCommandItem &other); + + protected: + // wrong commands (esp. custom commands) can block the send queue, limit the number of repeats. + /// How many times this command has been sent + uint8_t send_count_{0}; }; /** Modbus controller class. @@ -464,6 +468,10 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { bool get_module_offline() { return module_offline_; } /// Set callback for commands void add_on_command_sent_callback(std::function &&callback); + /// called by esphome generated code to set the max_cmd_retries. + void set_max_cmd_retries(uint8_t max_cmd_retries) { this->max_cmd_retries_ = max_cmd_retries; } + /// get how many times a command will be (re)sent if no response is received + uint8_t get_max_cmd_retries() { return this->max_cmd_retries_; } protected: /// parse sensormap_ and create range of sequential addresses @@ -498,6 +506,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { bool module_offline_; /// how many updates to skip if module is offline uint16_t offline_skip_updates_; + /// How many times we will retry a command if we get no response + uint8_t max_cmd_retries_{4}; CallbackManager command_sent_callback_{}; }; diff --git a/tests/components/modbus_controller/test.esp32-ard.yaml b/tests/components/modbus_controller/test.esp32-ard.yaml index b6e38aeb9c..cd95d149cb 100644 --- a/tests/components/modbus_controller/test.esp32-ard.yaml +++ b/tests/components/modbus_controller/test.esp32-ard.yaml @@ -29,3 +29,4 @@ modbus_controller: value_type: S_DWORD_R read_lambda: |- return 42.3; + max_cmd_retries: 0 diff --git a/tests/components/modbus_controller/test.esp32-idf.yaml b/tests/components/modbus_controller/test.esp32-idf.yaml index d5407ac406..ba28e94d73 100644 --- a/tests/components/modbus_controller/test.esp32-idf.yaml +++ b/tests/components/modbus_controller/test.esp32-idf.yaml @@ -13,3 +13,4 @@ modbus_controller: address: 0x2 modbus_id: mod_bus1 allow_duplicate_commands: true + max_cmd_retries: 10 From 63cda412f9e658b6c031ce47bdfb18a7a2e92d0a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:37:40 +1200 Subject: [PATCH 2372/2607] Bump version to 2024.9.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 7ad31f276f..fb745fd506 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0-dev" +__version__ = "2024.9.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 664b219387b350197becdc552a2f68c62962dce4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:37:41 +1200 Subject: [PATCH 2373/2607] Bump version to 2024.10.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 7ad31f276f..6e7bbdec98 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0-dev" +__version__ = "2024.10.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From cb7b4d93653f61a93e9416641df73c7e3d9a5b49 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:08:41 +1200 Subject: [PATCH 2374/2607] [voice-assistant] Dont error on ``no_wake_word`` timeout error with streaming wake word (#7435) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 577de630fb..a2210f188d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -755,7 +755,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { message = std::move(arg.value); } } - if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") { + if (code == "wake-word-timeout" || code == "wake_word_detection_aborted" || code == "no_wake_word") { // Don't change state here since either the "tts-end" or "run-end" events will do it. return; } else if (code == "wake-provider-missing" || code == "wake-engine-missing") { From 43f6793ad9abe54d2f87a9d07b0514c85911130a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 11 Sep 2024 23:58:15 -0400 Subject: [PATCH 2375/2607] Create codeql.yml --- .github/workflows/codeql.yml | 90 ++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..71ca55e907 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,90 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + schedule: + - cron: "30 18 * * 4" + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: autobuild + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 6f9e725a2c86385339392751e235a3e7bb66f06f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 11 Sep 2024 23:58:57 -0400 Subject: [PATCH 2376/2607] Update codeql.yml --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 71ca55e907..d4cda309db 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,6 +12,7 @@ name: "CodeQL Advanced" on: + workflow_dispatch: schedule: - cron: "30 18 * * 4" From 95a340d7a329a1a116b06cd7e479630ff4b53d80 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 12 Sep 2024 00:04:25 -0400 Subject: [PATCH 2377/2607] Update codeql.yml --- .github/workflows/codeql.yml | 80 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d4cda309db..e9f212d7a8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,10 +40,10 @@ jobs: fail-fast: false matrix: include: - - language: c-cpp - build-mode: autobuild - - language: python - build-mode: none + # - language: c-cpp + # build-mode: autobuild + - language: python + build-mode: none # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' # Use `c-cpp` to analyze code written in C, C++ or both # Use 'java-kotlin' to analyze code written in Java, Kotlin or both @@ -53,39 +53,39 @@ jobs: # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 6207510279673db4be7dc0612febb35d802e6543 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 12 Sep 2024 00:05:40 -0400 Subject: [PATCH 2378/2607] Update codeql.yml --- .github/workflows/codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e9f212d7a8..7f510782a8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -55,7 +55,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -65,10 +65,10 @@ jobs: # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. - + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - + # If the analyze step fails for one of the languages you are analyzing with # "We were unable to automatically build your code", modify the matrix above # to set the build mode to "manual" for that language. Then modify this step @@ -84,7 +84,7 @@ jobs: echo ' make bootstrap' echo ' make release' exit 1 - + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: From 323c641ecdfaeb3769c3e9aae86d0079800ac474 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 12 Sep 2024 00:09:25 -0400 Subject: [PATCH 2379/2607] Update codeql.yml --- .github/workflows/codeql.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7f510782a8..ddeb0a99d2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -44,14 +44,14 @@ jobs: # build-mode: autobuild - language: python build-mode: none - # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository uses: actions/checkout@v4 From 78d0e0baae5efa3f918596be88192a45e7e10829 Mon Sep 17 00:00:00 2001 From: Tomer <57483589+tomer-w@users.noreply.github.com> Date: Fri, 13 Sep 2024 03:56:04 +0300 Subject: [PATCH 2380/2607] =?UTF-8?q?Improve=20manufacturer=20data=20traci?= =?UTF-8?q?ng=20to=20identify=20BLE=20devices=20a=20bit=20easie=E2=80=A6?= =?UTF-8?q?=20(#7332)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ble_presence/binary_sensor.py | 4 ++-- esphome/components/esp32_ble/ble_uuid.cpp | 7 +++++++ esphome/components/esp32_ble/ble_uuid.h | 1 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 20 ++++++++++--------- .../esp32_ble_tracker/esp32_ble_tracker.h | 6 +++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index d1fdc80289..3a0f1ade98 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -41,7 +41,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, - cv.Optional(CONF_IBEACON_UUID): cv.uuid, + cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_TIMEOUT, default="5min"): cv.positive_time_period, cv.Optional(CONF_MIN_RSSI): cv.All( cv.decibel, cv.int_range(min=-100, max=-30) @@ -83,7 +83,7 @@ async def to_code(config): cg.add(var.set_service_uuid128(uuid128)) if ibeacon_uuid := config.get(CONF_IBEACON_UUID): - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) + ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: diff --git a/esphome/components/esp32_ble/ble_uuid.cpp b/esphome/components/esp32_ble/ble_uuid.cpp index 57c2f9df94..07ac719434 100644 --- a/esphome/components/esp32_ble/ble_uuid.cpp +++ b/esphome/components/esp32_ble/ble_uuid.cpp @@ -31,6 +31,13 @@ ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) { memcpy(ret.uuid_.uuid.uuid128, data, ESP_UUID_LEN_128); return ret; } +ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) { + ESPBTUUID ret; + ret.uuid_.len = ESP_UUID_LEN_128; + for (int i = 0; i < ESP_UUID_LEN_128; i++) + ret.uuid_.uuid.uuid128[ESP_UUID_LEN_128 - 1 - i] = data[i]; + return ret; +} ESPBTUUID ESPBTUUID::from_raw(const std::string &data) { ESPBTUUID ret; if (data.length() == 4) { diff --git a/esphome/components/esp32_ble/ble_uuid.h b/esphome/components/esp32_ble/ble_uuid.h index 790a57c59d..d90db3a599 100644 --- a/esphome/components/esp32_ble/ble_uuid.h +++ b/esphome/components/esp32_ble/ble_uuid.h @@ -20,6 +20,7 @@ class ESPBTUUID { static ESPBTUUID from_uint32(uint32_t uuid); static ESPBTUUID from_raw(const uint8_t *data); + static ESPBTUUID from_raw_reversed(const uint8_t *data); static ESPBTUUID from_raw(const std::string &data); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index d154d4e519..74b4b9aa89 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -462,14 +462,16 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str()); } for (auto &data : this->manufacturer_datas_) { - ESP_LOGVV(TAG, " Manufacturer data: %s", format_hex_pretty(data.data).c_str()); - if (this->get_ibeacon().has_value()) { - auto ibeacon = this->get_ibeacon().value(); - ESP_LOGVV(TAG, " iBeacon data:"); - ESP_LOGVV(TAG, " UUID: %s", ibeacon.get_uuid().to_string().c_str()); - ESP_LOGVV(TAG, " Major: %u", ibeacon.get_major()); - ESP_LOGVV(TAG, " Minor: %u", ibeacon.get_minor()); - ESP_LOGVV(TAG, " TXPower: %d", ibeacon.get_signal_power()); + auto ibeacon = ESPBLEiBeacon::from_manufacturer_data(data); + if (ibeacon.has_value()) { + ESP_LOGVV(TAG, " Manufacturer iBeacon:"); + ESP_LOGVV(TAG, " UUID: %s", ibeacon.value().get_uuid().to_string().c_str()); + ESP_LOGVV(TAG, " Major: %u", ibeacon.value().get_major()); + ESP_LOGVV(TAG, " Minor: %u", ibeacon.value().get_minor()); + ESP_LOGVV(TAG, " TXPower: %d", ibeacon.value().get_signal_power()); + } else { + ESP_LOGVV(TAG, " Manufacturer ID: %s, data: %s", data.uuid.to_string().c_str(), + format_hex_pretty(data.data).c_str()); } } for (auto &data : this->service_datas_) { @@ -478,7 +480,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e ESP_LOGVV(TAG, " Data: %s", format_hex_pretty(data.data).c_str()); } - ESP_LOGVV(TAG, "Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str()); + ESP_LOGVV(TAG, " Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str()); #endif } void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 3db7a54f6e..d2bb6a6e6d 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -44,10 +44,10 @@ class ESPBLEiBeacon { ESPBLEiBeacon(const uint8_t *data); static optional from_manufacturer_data(const ServiceData &data); - uint16_t get_major() { return ((this->beacon_data_.major & 0xFF) << 8) | (this->beacon_data_.major >> 8); } - uint16_t get_minor() { return ((this->beacon_data_.minor & 0xFF) << 8) | (this->beacon_data_.minor >> 8); } + uint16_t get_major() { return byteswap(this->beacon_data_.major); } + uint16_t get_minor() { return byteswap(this->beacon_data_.minor); } int8_t get_signal_power() { return this->beacon_data_.signal_power; } - ESPBTUUID get_uuid() { return ESPBTUUID::from_raw(this->beacon_data_.proximity_uuid); } + ESPBTUUID get_uuid() { return ESPBTUUID::from_raw_reversed(this->beacon_data_.proximity_uuid); } protected: struct { From e315b4d939e003e587d63a7e7bf67ea2beae51d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:22:28 +1200 Subject: [PATCH 2381/2607] Bump peter-evans/create-pull-request from 7.0.0 to 7.0.2 (#7437) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index e834ff3793..1418867240 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v7.0.0 + uses: peter-evans/create-pull-request@v7.0.2 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From 0df44b5df194a5b4b163ef2691e684dee89037f6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 13 Sep 2024 04:06:50 +0200 Subject: [PATCH 2382/2607] Bump recommended ESP-IDF to 4.4.8 (#7349) --- esphome/components/esp32/__init__.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index b630c7638e..9cb9ac257a 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -239,7 +239,7 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) # The default/recommended esp-idf framework version # - https://github.com/espressif/esp-idf/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf -RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 7) +RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 8) # The platformio/espressif32 version to use for esp-idf frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 diff --git a/platformio.ini b/platformio.ini index 7d912aaf54..e3593bf43f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -139,7 +139,7 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script extends = common:idf platform = platformio/espressif32@5.4.0 platform_packages = - platformio/framework-espidf@~3.40407.0 + platformio/framework-espidf@~3.40408.0 framework = espidf lib_deps = From 08c0715a30669fe76d43415ea76ce2d33a9939db Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:15:00 +1200 Subject: [PATCH 2383/2607] [tm1638] Fix linting and formatting issues (#7443) --- esphome/components/tm1638/binary_sensor/__init__.py | 5 +++-- esphome/components/tm1638/display.py | 10 +++++----- esphome/components/tm1638/output/__init__.py | 5 +++-- esphome/components/tm1638/switch/__init__.py | 5 +++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/esphome/components/tm1638/binary_sensor/__init__.py b/esphome/components/tm1638/binary_sensor/__init__.py index 6623228555..de6ea35e54 100644 --- a/esphome/components/tm1638/binary_sensor/__init__.py +++ b/esphome/components/tm1638/binary_sensor/__init__.py @@ -1,8 +1,9 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import binary_sensor +import esphome.config_validation as cv from esphome.const import CONF_KEY -from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID + +from ..display import CONF_TM1638_ID, TM1638Component, tm1638_ns TM1638Key = tm1638_ns.class_("TM1638Key", binary_sensor.BinarySensor) diff --git a/esphome/components/tm1638/display.py b/esphome/components/tm1638/display.py index 2fb8dc7a55..14b70be94d 100644 --- a/esphome/components/tm1638/display.py +++ b/esphome/components/tm1638/display.py @@ -1,13 +1,13 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import display +import esphome.config_validation as cv from esphome.const import ( + CONF_CLK_PIN, + CONF_DIO_PIN, CONF_ID, CONF_INTENSITY, CONF_LAMBDA, - CONF_CLK_PIN, - CONF_DIO_PIN, CONF_STB_PIN, ) @@ -51,4 +51,4 @@ async def to_code(config): config[CONF_LAMBDA], [(TM1638ComponentRef, "it")], return_type=cg.void ) - cg.add(var.set_writer(lambda_)) + cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/tm1638/output/__init__.py b/esphome/components/tm1638/output/__init__.py index 2d982e409d..b16b08d504 100644 --- a/esphome/components/tm1638/output/__init__.py +++ b/esphome/components/tm1638/output/__init__.py @@ -1,8 +1,9 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import output +import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LED -from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID + +from ..display import CONF_TM1638_ID, TM1638Component, tm1638_ns TM1638OutputLed = tm1638_ns.class_("TM1638OutputLed", output.BinaryOutput, cg.Component) diff --git a/esphome/components/tm1638/switch/__init__.py b/esphome/components/tm1638/switch/__init__.py index ed6aa91d03..8832cf8b92 100644 --- a/esphome/components/tm1638/switch/__init__.py +++ b/esphome/components/tm1638/switch/__init__.py @@ -1,8 +1,9 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import switch +import esphome.config_validation as cv from esphome.const import CONF_LED -from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID + +from ..display import CONF_TM1638_ID, TM1638Component, tm1638_ns TM1638SwitchLed = tm1638_ns.class_("TM1638SwitchLed", switch.Switch, cg.Component) From e4c90489f725b22f4c2abc8821b103a9fc37dce2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:16:24 +1200 Subject: [PATCH 2384/2607] [image] Fix linting and formatting issues (#7440) --- esphome/components/image/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index e5a205f1e0..e80ba4498f 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -1,18 +1,17 @@ from __future__ import annotations -import logging - import hashlib import io +import logging from pathlib import Path import re + from magic import Magic -from esphome import core -from esphome.components import font -from esphome import external_files -import esphome.config_validation as cv +from esphome import core, external_files import esphome.codegen as cg +from esphome.components import font +import esphome.config_validation as cv from esphome.const import ( CONF_DITHER, CONF_FILE, @@ -239,12 +238,11 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) def load_svg_image(file: bytes, resize: tuple[int, int]): # Local import only to allow "validate_pillow_installed" to run *before* importing it - from PIL import Image - # This import is only needed in case of SVG images; adding it # to the top would force configurations not using SVG to also have it # installed for no reason. from cairosvg import svg2png + from PIL import Image if resize: req_width, req_height = resize @@ -274,6 +272,9 @@ async def to_code(config): elif conf_file[CONF_SOURCE] == SOURCE_WEB: path = compute_local_image_path(conf_file).as_posix() + else: + raise core.EsphomeError(f"Unknown image source: {conf_file[CONF_SOURCE]}") + try: with open(path, "rb") as f: file_contents = f.read() From c702a3f3ee09f779efc3d18b44e618628003141e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:16:57 +1200 Subject: [PATCH 2385/2607] [animation] Fix linting and formatting issues (#7439) --- esphome/components/animation/__init__.py | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index dbfc82c891..eb3d09ac96 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -1,26 +1,26 @@ import logging from esphome import automation, core +import esphome.codegen as cg from esphome.components import font import esphome.components.image as espImage from esphome.components.image import ( CONF_USE_TRANSPARENCY, LOCAL_SCHEMA, - WEB_SCHEMA, - SOURCE_WEB, SOURCE_LOCAL, + SOURCE_WEB, + WEB_SCHEMA, ) import esphome.config_validation as cv -import esphome.codegen as cg from esphome.const import ( CONF_FILE, CONF_ID, + CONF_PATH, CONF_RAW_DATA_ID, CONF_REPEAT, CONF_RESIZE, - CONF_TYPE, CONF_SOURCE, - CONF_PATH, + CONF_TYPE, CONF_URL, ) from esphome.core import CORE, HexInt @@ -172,6 +172,9 @@ async def to_code(config): path = CORE.relative_config_path(conf_file[CONF_PATH]) elif conf_file[CONF_SOURCE] == SOURCE_WEB: path = espImage.compute_local_image_path(conf_file).as_posix() + else: + raise core.EsphomeError(f"Unknown animation source: {conf_file[CONF_SOURCE]}") + try: image = Image.open(path) except Exception as e: @@ -183,13 +186,12 @@ async def to_code(config): new_width_max, new_height_max = config[CONF_RESIZE] ratio = min(new_width_max / width, new_height_max / height) width, height = int(width * ratio), int(height * ratio) - else: - if width > 500 or height > 500: - _LOGGER.warning( - 'The image "%s" you requested is very big. Please consider' - " using the resize parameter.", - path, - ) + elif width > 500 or height > 500: + _LOGGER.warning( + 'The image "%s" you requested is very big. Please consider' + " using the resize parameter.", + path, + ) transparent = config[CONF_USE_TRANSPARENCY] @@ -306,6 +308,8 @@ async def to_code(config): if transparent: alpha = image.split()[-1] has_alpha = alpha.getextrema()[0] < 0xFF + else: + has_alpha = False frame = image.convert("1", dither=Image.Dither.NONE) if CONF_RESIZE in config: frame = frame.resize([width, height]) From cf4bfcdce8b9492872ff22fbbd449d4079c1be9c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:03:25 +1200 Subject: [PATCH 2386/2607] [thermostat] Fix linting and formatting issues (#7442) --- esphome/components/thermostat/climate.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/esphome/components/thermostat/climate.py b/esphome/components/thermostat/climate.py index 89d6b13376..a529bbd474 100644 --- a/esphome/components/thermostat/climate.py +++ b/esphome/components/thermostat/climate.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import climate, sensor +import esphome.config_validation as cv from esphome.const import ( CONF_AUTO_MODE, CONF_AWAY_CONFIG, @@ -15,15 +15,15 @@ from esphome.const import ( CONF_DRY_ACTION, CONF_DRY_MODE, CONF_FAN_MODE, - CONF_FAN_MODE_ON_ACTION, - CONF_FAN_MODE_OFF_ACTION, CONF_FAN_MODE_AUTO_ACTION, + CONF_FAN_MODE_DIFFUSE_ACTION, + CONF_FAN_MODE_FOCUS_ACTION, + CONF_FAN_MODE_HIGH_ACTION, CONF_FAN_MODE_LOW_ACTION, CONF_FAN_MODE_MEDIUM_ACTION, - CONF_FAN_MODE_HIGH_ACTION, CONF_FAN_MODE_MIDDLE_ACTION, - CONF_FAN_MODE_FOCUS_ACTION, - CONF_FAN_MODE_DIFFUSE_ACTION, + CONF_FAN_MODE_OFF_ACTION, + CONF_FAN_MODE_ON_ACTION, CONF_FAN_MODE_QUIET_ACTION, CONF_FAN_ONLY_ACTION, CONF_FAN_ONLY_ACTION_USES_FAN_MODE_TIMER, @@ -50,8 +50,8 @@ from esphome.const import ( CONF_MIN_HEATING_RUN_TIME, CONF_MIN_IDLE_TIME, CONF_MIN_TEMPERATURE, - CONF_NAME, CONF_MODE, + CONF_NAME, CONF_OFF_MODE, CONF_PRESET, CONF_SENSOR, @@ -892,7 +892,7 @@ async def to_code(config): if name.upper() in climate.CLIMATE_PRESETS: standard_preset = climate.CLIMATE_PRESETS[name.upper()] - if two_points_available is True: + if two_points_available: preset_target_config = ThermostatClimateTargetTempConfig( preset_config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW], preset_config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH], @@ -905,6 +905,8 @@ async def to_code(config): preset_target_config = ThermostatClimateTargetTempConfig( preset_config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW] ) + else: + preset_target_config = None preset_target_variable = cg.new_variable( preset_config[CONF_ID], preset_target_config From de19d25a3c7f3993df2d51e89a7589eeaa6786b5 Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Mon, 16 Sep 2024 00:59:10 +0300 Subject: [PATCH 2387/2607] Add OpenTherm component (part 1: communication layer and hub) (#6645) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/opentherm/__init__.py | 57 ++ esphome/components/opentherm/hub.cpp | 277 +++++++++ esphome/components/opentherm/hub.h | 110 ++++ esphome/components/opentherm/opentherm.cpp | 568 ++++++++++++++++++ esphome/components/opentherm/opentherm.h | 347 +++++++++++ tests/components/opentherm/common.yaml | 3 + .../components/opentherm/test.esp32-ard.yaml | 1 + .../opentherm/test.esp32-c3-ard.yaml | 1 + .../opentherm/test.esp32-c3-idf.yaml | 1 + .../components/opentherm/test.esp32-idf.yaml | 1 + .../opentherm/test.esp8266-ard.yaml | 1 + 12 files changed, 1368 insertions(+) create mode 100644 esphome/components/opentherm/__init__.py create mode 100644 esphome/components/opentherm/hub.cpp create mode 100644 esphome/components/opentherm/hub.h create mode 100644 esphome/components/opentherm/opentherm.cpp create mode 100644 esphome/components/opentherm/opentherm.h create mode 100644 tests/components/opentherm/common.yaml create mode 100644 tests/components/opentherm/test.esp32-ard.yaml create mode 100644 tests/components/opentherm/test.esp32-c3-ard.yaml create mode 100644 tests/components/opentherm/test.esp32-c3-idf.yaml create mode 100644 tests/components/opentherm/test.esp32-idf.yaml create mode 100644 tests/components/opentherm/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 0b1b88fbc8..f7fbbf9374 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -289,6 +289,7 @@ esphome/components/noblex/* @AGalfra esphome/components/number/* @esphome/core esphome/components/one_wire/* @ssieb esphome/components/online_image/* @guillempages +esphome/components/opentherm/* @olegtarasov esphome/components/ota/* @esphome/core esphome/components/output/* @esphome/core esphome/components/pca6416a/* @Mat931 diff --git a/esphome/components/opentherm/__init__.py b/esphome/components/opentherm/__init__.py new file mode 100644 index 0000000000..23443a4028 --- /dev/null +++ b/esphome/components/opentherm/__init__.py @@ -0,0 +1,57 @@ +from typing import Any + +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, PLATFORM_ESP32, PLATFORM_ESP8266 + +CODEOWNERS = ["@olegtarasov"] +MULTI_CONF = True + +CONF_IN_PIN = "in_pin" +CONF_OUT_PIN = "out_pin" +CONF_CH_ENABLE = "ch_enable" +CONF_DHW_ENABLE = "dhw_enable" +CONF_COOLING_ENABLE = "cooling_enable" +CONF_OTC_ACTIVE = "otc_active" +CONF_CH2_ACTIVE = "ch2_active" +CONF_SYNC_MODE = "sync_mode" + +opentherm_ns = cg.esphome_ns.namespace("opentherm") +OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component) + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(OpenthermHub), + cv.Required(CONF_IN_PIN): pins.internal_gpio_input_pin_schema, + cv.Required(CONF_OUT_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_CH_ENABLE, True): cv.boolean, + cv.Optional(CONF_DHW_ENABLE, True): cv.boolean, + cv.Optional(CONF_COOLING_ENABLE, False): cv.boolean, + cv.Optional(CONF_OTC_ACTIVE, False): cv.boolean, + cv.Optional(CONF_CH2_ACTIVE, False): cv.boolean, + cv.Optional(CONF_SYNC_MODE, False): cv.boolean, + } + ).extend(cv.COMPONENT_SCHEMA), + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]), +) + + +async def to_code(config: dict[str, Any]) -> None: + # Create the hub, passing the two callbacks defined below + # Since the hub is used in the callbacks, we need to define it first + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + # Set pins + in_pin = await cg.gpio_pin_expression(config[CONF_IN_PIN]) + cg.add(var.set_in_pin(in_pin)) + + out_pin = await cg.gpio_pin_expression(config[CONF_OUT_PIN]) + cg.add(var.set_out_pin(out_pin)) + + non_sensors = {CONF_ID, CONF_IN_PIN, CONF_OUT_PIN} + for key, value in config.items(): + if key not in non_sensors: + cg.add(getattr(var, f"set_{key}")(value)) diff --git a/esphome/components/opentherm/hub.cpp b/esphome/components/opentherm/hub.cpp new file mode 100644 index 0000000000..c26fbced32 --- /dev/null +++ b/esphome/components/opentherm/hub.cpp @@ -0,0 +1,277 @@ +#include "hub.h" +#include "esphome/core/helpers.h" + +#include + +namespace esphome { +namespace opentherm { + +static const char *const TAG = "opentherm"; + +OpenthermData OpenthermHub::build_request_(MessageId request_id) { + OpenthermData data; + data.type = 0; + data.id = 0; + data.valueHB = 0; + data.valueLB = 0; + + // First, handle the status request. This requires special logic, because we + // wouldn't want to inadvertently disable domestic hot water, for example. + // It is also included in the macro-generated code below, but that will + // never be executed, because we short-circuit it here. + if (request_id == MessageId::STATUS) { + bool const ch_enabled = this->ch_enable; + bool dhw_enabled = this->dhw_enable; + bool cooling_enabled = this->cooling_enable; + bool otc_enabled = this->otc_active; + bool ch2_enabled = this->ch2_active; + + data.type = MessageType::READ_DATA; + data.id = MessageId::STATUS; + data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4); + +// Disable incomplete switch statement warnings, because the cases in each +// switch are generated based on the configured sensors and inputs. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" + + // TODO: This is a placeholder for an auto-generated switch statement which builds request structure based on + // which sensors are enabled in config. + +#pragma GCC diagnostic pop + + return data; + } + return OpenthermData(); +} + +OpenthermHub::OpenthermHub() : Component() {} + +void OpenthermHub::process_response(OpenthermData &data) { + ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id, + this->opentherm_->message_id_to_str((MessageId) data.id)); + ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str()); +} + +void OpenthermHub::setup() { + ESP_LOGD(TAG, "Setting up OpenTherm component"); + this->opentherm_ = make_unique(this->in_pin_, this->out_pin_); + if (!this->opentherm_->initialize()) { + ESP_LOGE(TAG, "Failed to initialize OpenTherm protocol. See previous log messages for details."); + this->mark_failed(); + return; + } + + // Ensure that there is at least one request, as we are required to + // communicate at least once every second. Sending the status request is + // good practice anyway. + this->add_repeating_message(MessageId::STATUS); + + this->current_message_iterator_ = this->initial_messages_.begin(); +} + +void OpenthermHub::on_shutdown() { this->opentherm_->stop(); } + +void OpenthermHub::loop() { + if (this->sync_mode_) { + this->sync_loop_(); + return; + } + + auto cur_time = millis(); + auto const cur_mode = this->opentherm_->get_mode(); + switch (cur_mode) { + case OperationMode::WRITE: + case OperationMode::READ: + case OperationMode::LISTEN: + if (!this->check_timings_(cur_time)) { + break; + } + this->last_mode_ = cur_mode; + break; + case OperationMode::ERROR_PROTOCOL: + if (this->last_mode_ == OperationMode::WRITE) { + this->handle_protocol_write_error_(); + } else if (this->last_mode_ == OperationMode::READ) { + this->handle_protocol_read_error_(); + } + + this->stop_opentherm_(); + break; + case OperationMode::ERROR_TIMEOUT: + this->handle_timeout_error_(); + this->stop_opentherm_(); + break; + case OperationMode::IDLE: + if (this->should_skip_loop_(cur_time)) { + break; + } + this->start_conversation_(); + break; + case OperationMode::SENT: + // Message sent, now listen for the response. + this->opentherm_->listen(); + break; + case OperationMode::RECEIVED: + this->read_response_(); + break; + } +} + +void OpenthermHub::sync_loop_() { + if (!this->opentherm_->is_idle()) { + ESP_LOGE(TAG, "OpenTherm is not idle at the start of the loop"); + return; + } + + auto cur_time = millis(); + + this->check_timings_(cur_time); + + if (this->should_skip_loop_(cur_time)) { + return; + } + + this->start_conversation_(); + + if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) { + ESP_LOGE(TAG, "Hub timeout triggered during send"); + this->stop_opentherm_(); + return; + } + + if (this->opentherm_->is_error()) { + this->handle_protocol_write_error_(); + this->stop_opentherm_(); + return; + } else if (!this->opentherm_->is_sent()) { + ESP_LOGW(TAG, "Unexpected state after sending request: %s", + this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode())); + this->stop_opentherm_(); + return; + } + + // Listen for the response + this->opentherm_->listen(); + if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) { + ESP_LOGE(TAG, "Hub timeout triggered during receive"); + this->stop_opentherm_(); + return; + } + + if (this->opentherm_->is_timeout()) { + this->handle_timeout_error_(); + this->stop_opentherm_(); + return; + } else if (this->opentherm_->is_protocol_error()) { + this->handle_protocol_read_error_(); + this->stop_opentherm_(); + return; + } else if (!this->opentherm_->has_message()) { + ESP_LOGW(TAG, "Unexpected state after receiving response: %s", + this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode())); + this->stop_opentherm_(); + return; + } + + this->read_response_(); +} + +bool OpenthermHub::check_timings_(uint32_t cur_time) { + if (this->last_conversation_start_ > 0 && (cur_time - this->last_conversation_start_) > 1150) { + ESP_LOGW(TAG, + "%d ms elapsed since the start of the last convo, but 1150 ms are allowed at maximum. Look at other " + "components that might slow the loop down.", + (int) (cur_time - this->last_conversation_start_)); + this->stop_opentherm_(); + return false; + } + + return true; +} + +bool OpenthermHub::should_skip_loop_(uint32_t cur_time) const { + if (this->last_conversation_end_ > 0 && (cur_time - this->last_conversation_end_) < 100) { + ESP_LOGV(TAG, "Less than 100 ms elapsed since last convo, skipping this iteration"); + return true; + } + + return false; +} + +void OpenthermHub::start_conversation_() { + if (this->sending_initial_ && this->current_message_iterator_ == this->initial_messages_.end()) { + this->sending_initial_ = false; + this->current_message_iterator_ = this->repeating_messages_.begin(); + } else if (this->current_message_iterator_ == this->repeating_messages_.end()) { + this->current_message_iterator_ = this->repeating_messages_.begin(); + } + + auto request = this->build_request_(*this->current_message_iterator_); + + ESP_LOGD(TAG, "Sending request with id %d (%s)", request.id, + this->opentherm_->message_id_to_str((MessageId) request.id)); + ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(request).c_str()); + // Send the request + this->last_conversation_start_ = millis(); + this->opentherm_->send(request); +} + +void OpenthermHub::read_response_() { + OpenthermData response; + if (!this->opentherm_->get_message(response)) { + ESP_LOGW(TAG, "Couldn't get the response, but flags indicated success. This is a bug."); + this->stop_opentherm_(); + return; + } + + this->stop_opentherm_(); + + this->process_response(response); + + this->current_message_iterator_++; +} + +void OpenthermHub::stop_opentherm_() { + this->opentherm_->stop(); + this->last_conversation_end_ = millis(); +} + +void OpenthermHub::handle_protocol_write_error_() { + ESP_LOGW(TAG, "Error while sending request: %s", + this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode())); + ESP_LOGW(TAG, "%s", this->opentherm_->debug_data(this->last_request_).c_str()); +} + +void OpenthermHub::handle_protocol_read_error_() { + OpenThermError error; + this->opentherm_->get_protocol_error(error); + ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", this->opentherm_->debug_error(error).c_str()); +} + +void OpenthermHub::handle_timeout_error_() { + ESP_LOGW(TAG, "Receive response timed out at a protocol level"); + this->stop_opentherm_(); +} + +#define ID(x) x +#define SHOW2(x) #x +#define SHOW(x) SHOW2(x) + +void OpenthermHub::dump_config() { + ESP_LOGCONFIG(TAG, "OpenTherm:"); + LOG_PIN(" In: ", this->in_pin_); + LOG_PIN(" Out: ", this->out_pin_); + ESP_LOGCONFIG(TAG, " Sync mode: %d", this->sync_mode_); + ESP_LOGCONFIG(TAG, " Initial requests:"); + for (auto type : this->initial_messages_) { + ESP_LOGCONFIG(TAG, " - %d", type); + } + ESP_LOGCONFIG(TAG, " Repeating requests:"); + for (auto type : this->repeating_messages_) { + ESP_LOGCONFIG(TAG, " - %d", type); + } +} + +} // namespace opentherm +} // namespace esphome diff --git a/esphome/components/opentherm/hub.h b/esphome/components/opentherm/hub.h new file mode 100644 index 0000000000..ce9f09fe33 --- /dev/null +++ b/esphome/components/opentherm/hub.h @@ -0,0 +1,110 @@ +#pragma once + +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" +#include "esphome/core/component.h" +#include "esphome/core/log.h" + +#include "opentherm.h" + +#include +#include +#include +#include + +namespace esphome { +namespace opentherm { + +// OpenTherm component for ESPHome +class OpenthermHub : public Component { + protected: + // Communication pins for the OpenTherm interface + InternalGPIOPin *in_pin_, *out_pin_; + // The OpenTherm interface + std::unique_ptr opentherm_; + + // The set of initial messages to send on starting communication with the boiler + std::unordered_set initial_messages_; + // and the repeating messages which are sent repeatedly to update various sensors + // and boiler parameters (like the setpoint). + std::unordered_set repeating_messages_; + // Indicates if we are still working on the initial requests or not + bool sending_initial_ = true; + // Index for the current request in one of the _requests sets. + std::unordered_set::const_iterator current_message_iterator_; + + uint32_t last_conversation_start_ = 0; + uint32_t last_conversation_end_ = 0; + OperationMode last_mode_ = IDLE; + OpenthermData last_request_; + + // Synchronous communication mode prevents other components from disabling interrupts while + // we are talking to the boiler. Enable if you experience random intermittent invalid response errors. + // Very likely to happen while using Dallas temperature sensors. + bool sync_mode_ = false; + + // Create OpenTherm messages based on the message id + OpenthermData build_request_(MessageId request_id); + void handle_protocol_write_error_(); + void handle_protocol_read_error_(); + void handle_timeout_error_(); + void stop_opentherm_(); + void start_conversation_(); + void read_response_(); + bool check_timings_(uint32_t cur_time); + bool should_skip_loop_(uint32_t cur_time) const; + void sync_loop_(); + + template bool spin_wait_(uint32_t timeout, F func) { + auto start_time = millis(); + while (func()) { + yield(); + auto cur_time = millis(); + if (cur_time - start_time >= timeout) { + return false; + } + } + return true; + } + + public: + // Constructor with references to the global interrupt handlers + OpenthermHub(); + + // Handle responses from the OpenTherm interface + void process_response(OpenthermData &data); + + // Setters for the input and output OpenTherm interface pins + void set_in_pin(InternalGPIOPin *in_pin) { this->in_pin_ = in_pin; } + void set_out_pin(InternalGPIOPin *out_pin) { this->out_pin_ = out_pin; } + + // Add a request to the set of initial requests + void add_initial_message(MessageId message_id) { this->initial_messages_.insert(message_id); } + // Add a request to the set of repeating requests. Note that a large number of repeating + // requests will slow down communication with the boiler. Each request may take up to 1 second, + // so with all sensors enabled, it may take about half a minute before a change in setpoint + // will be processed. + void add_repeating_message(MessageId message_id) { this->repeating_messages_.insert(message_id); } + + // There are five status variables, which can either be set as a simple variable, + // or using a switch. ch_enable and dhw_enable default to true, the others to false. + bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false; + + // Setters for the status variables + void set_ch_enable(bool value) { this->ch_enable = value; } + void set_dhw_enable(bool value) { this->dhw_enable = value; } + void set_cooling_enable(bool value) { this->cooling_enable = value; } + void set_otc_active(bool value) { this->otc_active = value; } + void set_ch2_active(bool value) { this->ch2_active = value; } + void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; } + + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + void setup() override; + void on_shutdown() override; + void loop() override; + void dump_config() override; +}; + +} // namespace opentherm +} // namespace esphome diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp new file mode 100644 index 0000000000..b830cc01d3 --- /dev/null +++ b/esphome/components/opentherm/opentherm.cpp @@ -0,0 +1,568 @@ +/* + * OpenTherm protocol implementation. Originally taken from https://github.com/jpraus/arduino-opentherm, but + * heavily modified to comply with ESPHome coding standards and provide better logging. + * Original code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International + * Public License, which is compatible with GPLv3 license, which covers C++ part of ESPHome project. + */ + +#include "opentherm.h" +#include "esphome/core/helpers.h" +#if defined(ESP32) || defined(USE_ESP_IDF) +#include "driver/timer.h" +#include "esp_err.h" +#endif +#ifdef ESP8266 +#include "Arduino.h" +#endif +#include +#include +#include + +namespace esphome { +namespace opentherm { + +using std::string; +using std::bitset; +using std::stringstream; +using std::to_string; + +static const char *const TAG = "opentherm"; + +#ifdef ESP8266 +OpenTherm *OpenTherm::instance_ = nullptr; +#endif + +OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout) + : in_pin_(in_pin), + out_pin_(out_pin), +#if defined(ESP32) || defined(USE_ESP_IDF) + timer_group_(TIMER_GROUP_0), + timer_idx_(TIMER_0), +#endif + mode_(OperationMode::IDLE), + error_type_(ProtocolErrorType::NO_ERROR), + capture_(0), + clock_(0), + data_(0), + bit_pos_(0), + timeout_counter_(-1), + device_timeout_(device_timeout) { + this->isr_in_pin_ = in_pin->to_isr(); + this->isr_out_pin_ = out_pin->to_isr(); +} + +bool OpenTherm::initialize() { +#ifdef ESP8266 + OpenTherm::instance_ = this; +#endif + this->in_pin_->pin_mode(gpio::FLAG_INPUT); + this->out_pin_->pin_mode(gpio::FLAG_OUTPUT); + this->out_pin_->digital_write(true); + +#if defined(ESP32) || defined(USE_ESP_IDF) + return this->init_esp32_timer_(); +#else + return true; +#endif +} + +void OpenTherm::listen() { + this->stop_timer_(); + this->timeout_counter_ = this->device_timeout_ * 5; // timer_ ticks at 5 ticks/ms + + this->mode_ = OperationMode::LISTEN; + this->data_ = 0; + this->bit_pos_ = 0; + + this->start_read_timer_(); +} + +void OpenTherm::send(OpenthermData &data) { + this->stop_timer_(); + this->data_ = data.type; + this->data_ = (this->data_ << 12) | data.id; + this->data_ = (this->data_ << 8) | data.valueHB; + this->data_ = (this->data_ << 8) | data.valueLB; + if (!check_parity_(this->data_)) { + this->data_ = this->data_ | 0x80000000; + } + + this->clock_ = 1; // clock starts at HIGH + this->bit_pos_ = 33; // count down (33 == start bit, 32-1 data, 0 == stop bit) + this->mode_ = OperationMode::WRITE; + + this->start_write_timer_(); +} + +bool OpenTherm::get_message(OpenthermData &data) { + if (this->mode_ == OperationMode::RECEIVED) { + data.type = (this->data_ >> 28) & 0x7; + data.id = (this->data_ >> 16) & 0xFF; + data.valueHB = (this->data_ >> 8) & 0xFF; + data.valueLB = this->data_ & 0xFF; + return true; + } + return false; +} + +bool OpenTherm::get_protocol_error(OpenThermError &error) { + if (this->mode_ != OperationMode::ERROR_PROTOCOL) { + return false; + } + + error.error_type = this->error_type_; + error.bit_pos = this->bit_pos_; + error.capture = this->capture_; + error.clock = this->clock_; + error.data = this->data_; + + return true; +} + +void OpenTherm::stop() { + this->stop_timer_(); + this->mode_ = OperationMode::IDLE; +} + +void IRAM_ATTR OpenTherm::read_() { + this->data_ = 0; + this->bit_pos_ = 0; + this->mode_ = OperationMode::READ; + this->capture_ = 1; // reset counter and add as if read start bit + this->clock_ = 1; // clock is high at the start of comm + this->start_read_timer_(); // get us into 1/4 of manchester code. 5 timer ticks constitute 1 ms, which is 1 bit + // period in OpenTherm. +} + +bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) { + if (arg->mode_ == OperationMode::LISTEN) { + if (arg->timeout_counter_ == 0) { + arg->mode_ = OperationMode::ERROR_TIMEOUT; + arg->stop_timer_(); + return false; + } + bool const value = arg->isr_in_pin_.digital_read(); + if (value) { // incoming data (rising signal) + arg->read_(); + } + if (arg->timeout_counter_ > 0) { + arg->timeout_counter_--; + } + } else if (arg->mode_ == OperationMode::READ) { + bool const value = arg->isr_in_pin_.digital_read(); + uint8_t const last = (arg->capture_ & 1); + if (value != last) { + // transition of signal from last sampling + if (arg->clock_ == 1 && arg->capture_ > 0xF) { + // no transition in the middle of the bit + arg->mode_ = OperationMode::ERROR_PROTOCOL; + arg->error_type_ = ProtocolErrorType::NO_TRANSITION; + arg->stop_timer_(); + return false; + } else if (arg->clock_ == 1 || arg->capture_ > 0xF) { + // transition in the middle of the bit OR no transition between two bit, both are valid data points + if (arg->bit_pos_ == BitPositions::STOP_BIT) { + // expecting stop bit + auto stop_bit_error = arg->verify_stop_bit_(last); + if (stop_bit_error == ProtocolErrorType::NO_ERROR) { + arg->mode_ = OperationMode::RECEIVED; + arg->stop_timer_(); + return false; + } else { + // end of data not verified, invalid data + arg->mode_ = OperationMode::ERROR_PROTOCOL; + arg->error_type_ = stop_bit_error; + arg->stop_timer_(); + return false; + } + } else { + // normal data point at clock high + arg->bit_read_(last); + arg->clock_ = 0; + } + } else { + // clock low, not a data point, switch clock + arg->clock_ = 1; + } + arg->capture_ = 1; // reset counter + } else if (arg->capture_ > 0xFF) { + // no change for too long, invalid mancheter encoding + arg->mode_ = OperationMode::ERROR_PROTOCOL; + arg->error_type_ = ProtocolErrorType::NO_CHANGE_TOO_LONG; + arg->stop_timer_(); + return false; + } + arg->capture_ = (arg->capture_ << 1) | value; + } else if (arg->mode_ == OperationMode::WRITE) { + // write data to pin + if (arg->bit_pos_ == 33 || arg->bit_pos_ == 0) { // start bit + arg->write_bit_(1, arg->clock_); + } else { // data bits + arg->write_bit_(read_bit(arg->data_, arg->bit_pos_ - 1), arg->clock_); + } + if (arg->clock_ == 0) { + if (arg->bit_pos_ <= 0) { // check termination + arg->mode_ = OperationMode::SENT; // all data written + arg->stop_timer_(); + } + arg->bit_pos_--; + arg->clock_ = 1; + } else { + arg->clock_ = 0; + } + } + + return false; +} + +#ifdef ESP8266 +void IRAM_ATTR OpenTherm::esp8266_timer_isr() { OpenTherm::timer_isr(OpenTherm::instance_); } +#endif + +void IRAM_ATTR OpenTherm::bit_read_(uint8_t value) { + this->data_ = (this->data_ << 1) | value; + this->bit_pos_++; +} + +ProtocolErrorType OpenTherm::verify_stop_bit_(uint8_t value) { + if (value) { // stop bit detected + return check_parity_(this->data_) ? ProtocolErrorType::NO_ERROR : ProtocolErrorType::PARITY_ERROR; + } else { // no stop bit detected, error + return ProtocolErrorType::INVALID_STOP_BIT; + } +} + +void IRAM_ATTR OpenTherm::write_bit_(uint8_t high, uint8_t clock) { + if (clock == 1) { // left part of manchester encoding + this->isr_out_pin_.digital_write(!high); // low means logical 1 to protocol + } else { // right part of manchester encoding + this->isr_out_pin_.digital_write(high); // high means logical 0 to protocol + } +} + +#if defined(ESP32) || defined(USE_ESP_IDF) + +bool OpenTherm::init_esp32_timer_() { + // Search for a free timer. Maybe unstable, we'll see. + int cur_timer = 0; + timer_group_t timer_group = TIMER_GROUP_0; + timer_idx_t timer_idx = TIMER_0; + bool timer_found = false; + + for (; cur_timer < SOC_TIMER_GROUP_TOTAL_TIMERS; cur_timer++) { + timer_config_t temp_config; + timer_group = cur_timer < 2 ? TIMER_GROUP_0 : TIMER_GROUP_1; + timer_idx = cur_timer < 2 ? (timer_idx_t) cur_timer : (timer_idx_t) (cur_timer - 2); + + auto err = timer_get_config(timer_group, timer_idx, &temp_config); + if (err == ESP_ERR_INVALID_ARG) { + // Error means timer was not initialized (or other things, but we are careful with our args) + timer_found = true; + break; + } + + ESP_LOGD(TAG, "Timer %d:%d seems to be occupied, will try another", timer_group, timer_idx); + } + + if (!timer_found) { + ESP_LOGE(TAG, "No free timer was found! OpenTherm cannot function without a timer."); + return false; + } + + ESP_LOGD(TAG, "Found free timer %d:%d", timer_group, timer_idx); + this->timer_group_ = timer_group; + this->timer_idx_ = timer_idx; + + timer_config_t const config = { + .alarm_en = TIMER_ALARM_EN, + .counter_en = TIMER_PAUSE, + .intr_type = TIMER_INTR_LEVEL, + .counter_dir = TIMER_COUNT_UP, + .auto_reload = TIMER_AUTORELOAD_EN, +#if ESP_IDF_VERSION_MAJOR >= 5 + .clk_src = TIMER_SRC_CLK_DEFAULT, +#endif + .divider = 80, + }; + + esp_err_t result; + + result = timer_init(this->timer_group_, this->timer_idx_, &config); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to init timer. Error: %s", error); + return false; + } + + result = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to set counter value. Error: %s", error); + return false; + } + + result = timer_isr_callback_add(this->timer_group_, this->timer_idx_, reinterpret_cast(timer_isr), + this, 0); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to register timer interrupt. Error: %s", error); + return false; + } + + return true; +} + +void IRAM_ATTR OpenTherm::start_esp32_timer_(uint64_t alarm_value) { + esp_err_t result; + + result = timer_set_alarm_value(this->timer_group_, this->timer_idx_, alarm_value); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to set alarm value. Error: %s", error); + return; + } + + result = timer_start(this->timer_group_, this->timer_idx_); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to start the timer. Error: %s", error); + return; + } +} + +// 5 kHz timer_ +void IRAM_ATTR OpenTherm::start_read_timer_() { + InterruptLock const lock; + this->start_esp32_timer_(200); +} + +// 2 kHz timer_ +void IRAM_ATTR OpenTherm::start_write_timer_() { + InterruptLock const lock; + this->start_esp32_timer_(500); +} + +void IRAM_ATTR OpenTherm::stop_timer_() { + InterruptLock const lock; + + esp_err_t result; + + result = timer_pause(this->timer_group_, this->timer_idx_); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to pause the timer. Error: %s", error); + return; + } + + result = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0); + if (result != ESP_OK) { + const auto *error = esp_err_to_name(result); + ESP_LOGE(TAG, "Failed to set timer counter to 0 after pausing. Error: %s", error); + return; + } +} + +#endif // END ESP32 + +#ifdef ESP8266 +// 5 kHz timer_ +void OpenTherm::start_read_timer_() { + InterruptLock const lock; + timer1_attachInterrupt(OpenTherm::esp8266_timer_isr); + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP); // 5MHz (5 ticks/us - 1677721.4 us max) + timer1_write(1000); // 5kHz +} + +// 2 kHz timer_ +void OpenTherm::start_write_timer_() { + InterruptLock const lock; + timer1_attachInterrupt(OpenTherm::esp8266_timer_isr); + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP); // 5MHz (5 ticks/us - 1677721.4 us max) + timer1_write(2500); // 2kHz +} + +void OpenTherm::stop_timer_() { + InterruptLock const lock; + timer1_disable(); + timer1_detachInterrupt(); +} + +#endif // END ESP8266 + +// https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd +bool OpenTherm::check_parity_(uint32_t val) { + val ^= val >> 16; + val ^= val >> 8; + val ^= val >> 4; + val ^= val >> 2; + val ^= val >> 1; + return (~val) & 1; +} + +#define TO_STRING_MEMBER(name) \ + case name: \ + return #name; + +const char *OpenTherm::operation_mode_to_str(OperationMode mode) { + switch (mode) { + TO_STRING_MEMBER(IDLE) + TO_STRING_MEMBER(LISTEN) + TO_STRING_MEMBER(READ) + TO_STRING_MEMBER(RECEIVED) + TO_STRING_MEMBER(WRITE) + TO_STRING_MEMBER(SENT) + TO_STRING_MEMBER(ERROR_PROTOCOL) + TO_STRING_MEMBER(ERROR_TIMEOUT) + default: + return ""; + } +} +const char *OpenTherm::protocol_error_to_to_str(ProtocolErrorType error_type) { + switch (error_type) { + TO_STRING_MEMBER(NO_ERROR) + TO_STRING_MEMBER(NO_TRANSITION) + TO_STRING_MEMBER(INVALID_STOP_BIT) + TO_STRING_MEMBER(PARITY_ERROR) + TO_STRING_MEMBER(NO_CHANGE_TOO_LONG) + default: + return ""; + } +} +const char *OpenTherm::message_type_to_str(MessageType message_type) { + switch (message_type) { + TO_STRING_MEMBER(READ_DATA) + TO_STRING_MEMBER(READ_ACK) + TO_STRING_MEMBER(WRITE_DATA) + TO_STRING_MEMBER(WRITE_ACK) + TO_STRING_MEMBER(INVALID_DATA) + TO_STRING_MEMBER(DATA_INVALID) + TO_STRING_MEMBER(UNKNOWN_DATAID) + default: + return ""; + } +} + +const char *OpenTherm::message_id_to_str(MessageId id) { + switch (id) { + TO_STRING_MEMBER(STATUS) + TO_STRING_MEMBER(CH_SETPOINT) + TO_STRING_MEMBER(CONTROLLER_CONFIG) + TO_STRING_MEMBER(DEVICE_CONFIG) + TO_STRING_MEMBER(COMMAND_CODE) + TO_STRING_MEMBER(FAULT_FLAGS) + TO_STRING_MEMBER(REMOTE) + TO_STRING_MEMBER(COOLING_CONTROL) + TO_STRING_MEMBER(CH2_SETPOINT) + TO_STRING_MEMBER(CH_SETPOINT_OVERRIDE) + TO_STRING_MEMBER(TSP_COUNT) + TO_STRING_MEMBER(TSP_COMMAND) + TO_STRING_MEMBER(FHB_SIZE) + TO_STRING_MEMBER(FHB_COMMAND) + TO_STRING_MEMBER(MAX_MODULATION_LEVEL) + TO_STRING_MEMBER(MAX_BOILER_CAPACITY) + TO_STRING_MEMBER(ROOM_SETPOINT) + TO_STRING_MEMBER(MODULATION_LEVEL) + TO_STRING_MEMBER(CH_WATER_PRESSURE) + TO_STRING_MEMBER(DHW_FLOW_RATE) + TO_STRING_MEMBER(DAY_TIME) + TO_STRING_MEMBER(DATE) + TO_STRING_MEMBER(YEAR) + TO_STRING_MEMBER(ROOM_SETPOINT_CH2) + TO_STRING_MEMBER(ROOM_TEMP) + TO_STRING_MEMBER(FEED_TEMP) + TO_STRING_MEMBER(DHW_TEMP) + TO_STRING_MEMBER(OUTSIDE_TEMP) + TO_STRING_MEMBER(RETURN_WATER_TEMP) + TO_STRING_MEMBER(SOLAR_STORE_TEMP) + TO_STRING_MEMBER(SOLAR_COLLECT_TEMP) + TO_STRING_MEMBER(FEED_TEMP_CH2) + TO_STRING_MEMBER(DHW2_TEMP) + TO_STRING_MEMBER(EXHAUST_TEMP) + TO_STRING_MEMBER(FAN_SPEED) + TO_STRING_MEMBER(FLAME_CURRENT) + TO_STRING_MEMBER(DHW_BOUNDS) + TO_STRING_MEMBER(CH_BOUNDS) + TO_STRING_MEMBER(OTC_CURVE_BOUNDS) + TO_STRING_MEMBER(DHW_SETPOINT) + TO_STRING_MEMBER(MAX_CH_SETPOINT) + TO_STRING_MEMBER(OTC_CURVE_RATIO) + TO_STRING_MEMBER(HVAC_STATUS) + TO_STRING_MEMBER(REL_VENT_SETPOINT) + TO_STRING_MEMBER(DEVICE_VENT) + TO_STRING_MEMBER(REL_VENTILATION) + TO_STRING_MEMBER(REL_HUMID_EXHAUST) + TO_STRING_MEMBER(SUPPLY_INLET_TEMP) + TO_STRING_MEMBER(SUPPLY_OUTLET_TEMP) + TO_STRING_MEMBER(EXHAUST_INLET_TEMP) + TO_STRING_MEMBER(EXHAUST_OUTLET_TEMP) + TO_STRING_MEMBER(NOM_REL_VENTILATION) + TO_STRING_MEMBER(OVERRIDE_FUNC) + TO_STRING_MEMBER(OEM_DIAGNOSTIC) + TO_STRING_MEMBER(BURNER_STARTS) + TO_STRING_MEMBER(CH_PUMP_STARTS) + TO_STRING_MEMBER(DHW_PUMP_STARTS) + TO_STRING_MEMBER(DHW_BURNER_STARTS) + TO_STRING_MEMBER(BURNER_HOURS) + TO_STRING_MEMBER(CH_PUMP_HOURS) + TO_STRING_MEMBER(DHW_PUMP_HOURS) + TO_STRING_MEMBER(DHW_BURNER_HOURS) + TO_STRING_MEMBER(OT_VERSION_CONTROLLER) + TO_STRING_MEMBER(OT_VERSION_DEVICE) + TO_STRING_MEMBER(VERSION_CONTROLLER) + TO_STRING_MEMBER(VERSION_DEVICE) + default: + return ""; + } +} + +string OpenTherm::debug_data(OpenthermData &data) { + stringstream result; + result << bitset<8>(data.type) << " " << bitset<8>(data.id) << " " << bitset<8>(data.valueHB) << " " + << bitset<8>(data.valueLB) << "\n"; + result << "type: " << this->message_type_to_str((MessageType) data.type) << "; "; + result << "id: " << to_string(data.id) << "; "; + result << "HB: " << to_string(data.valueHB) << "; "; + result << "LB: " << to_string(data.valueLB) << "; "; + result << "uint_16: " << to_string(data.u16()) << "; "; + result << "float: " << to_string(data.f88()); + + return result.str(); +} +std::string OpenTherm::debug_error(OpenThermError &error) { + stringstream result; + result << "type: " << this->protocol_error_to_to_str(error.error_type) << "; "; + result << "data: "; + result << format_hex(error.data); + result << "; clock: " << to_string(clock_); + result << "; capture: " << bitset<32>(error.capture); + result << "; bit_pos: " << to_string(error.bit_pos); + + return result.str(); +} + +float OpenthermData::f88() { return ((float) this->s16()) / 256.0; } + +void OpenthermData::f88(float value) { this->s16((int16_t) (value * 256)); } + +uint16_t OpenthermData::u16() { + uint16_t const value = this->valueHB; + return (value << 8) | this->valueLB; +} + +void OpenthermData::u16(uint16_t value) { + this->valueLB = value & 0xFF; + this->valueHB = (value >> 8) & 0xFF; +} + +int16_t OpenthermData::s16() { + int16_t const value = this->valueHB; + return (value << 8) | this->valueLB; +} + +void OpenthermData::s16(int16_t value) { + this->valueLB = value & 0xFF; + this->valueHB = (value >> 8) & 0xFF; +} + +} // namespace opentherm +} // namespace esphome diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h new file mode 100644 index 0000000000..609cfb6243 --- /dev/null +++ b/esphome/components/opentherm/opentherm.h @@ -0,0 +1,347 @@ +/* + * OpenTherm protocol implementation. Originally taken from https://github.com/jpraus/arduino-opentherm, but + * heavily modified to comply with ESPHome coding standards and provide better logging. + * Original code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International + * Public License, which is compatible with GPLv3 license, which covers C++ part of ESPHome project. + */ + +#pragma once + +#include +#include +#include +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +#if defined(ESP32) || defined(USE_ESP_IDF) +#include "driver/timer.h" +#endif + +namespace esphome { +namespace opentherm { + +// TODO: Account for immutable semantics change in hub.cpp when doing later installments of OpenTherm PR +template constexpr T read_bit(T value, uint8_t bit) { return (value >> bit) & 0x01; } + +template constexpr T set_bit(T value, uint8_t bit) { return value |= (1UL << bit); } + +template constexpr T clear_bit(T value, uint8_t bit) { return value &= ~(1UL << bit); } + +template constexpr T write_bit(T value, uint8_t bit, uint8_t bit_value) { + return bit_value ? setBit(value, bit) : clearBit(value, bit); +} + +enum OperationMode { + IDLE = 0, // no operation + + LISTEN = 1, // waiting for transmission to start + READ = 2, // reading 32-bit data frame + RECEIVED = 3, // data frame received with valid start and stop bit + + WRITE = 4, // writing data with timer_ + SENT = 5, // all data written to output + + ERROR_PROTOCOL = 8, // manchester protocol data transfer error + ERROR_TIMEOUT = 9 // read timeout +}; + +enum ProtocolErrorType { + NO_ERROR = 0, // No error + NO_TRANSITION = 1, // No transition in the middle of the bit + INVALID_STOP_BIT = 2, // Stop bit wasn't present when expected + PARITY_ERROR = 3, // Parity check didn't pass + NO_CHANGE_TOO_LONG = 4, // No level change for too much timer ticks +}; + +enum MessageType { + READ_DATA = 0, + READ_ACK = 4, + WRITE_DATA = 1, + WRITE_ACK = 5, + INVALID_DATA = 2, + DATA_INVALID = 6, + UNKNOWN_DATAID = 7 +}; + +enum MessageId { + STATUS = 0, + CH_SETPOINT = 1, + CONTROLLER_CONFIG = 2, + DEVICE_CONFIG = 3, + COMMAND_CODE = 4, + FAULT_FLAGS = 5, + REMOTE = 6, + COOLING_CONTROL = 7, + CH2_SETPOINT = 8, + CH_SETPOINT_OVERRIDE = 9, + TSP_COUNT = 10, + TSP_COMMAND = 11, + FHB_SIZE = 12, + FHB_COMMAND = 13, + MAX_MODULATION_LEVEL = 14, + MAX_BOILER_CAPACITY = 15, // u8_hb - u8_lb gives min modulation level + ROOM_SETPOINT = 16, + MODULATION_LEVEL = 17, + CH_WATER_PRESSURE = 18, + DHW_FLOW_RATE = 19, + DAY_TIME = 20, + DATE = 21, + YEAR = 22, + ROOM_SETPOINT_CH2 = 23, + ROOM_TEMP = 24, + FEED_TEMP = 25, + DHW_TEMP = 26, + OUTSIDE_TEMP = 27, + RETURN_WATER_TEMP = 28, + SOLAR_STORE_TEMP = 29, + SOLAR_COLLECT_TEMP = 30, + FEED_TEMP_CH2 = 31, + DHW2_TEMP = 32, + EXHAUST_TEMP = 33, + FAN_SPEED = 35, + FLAME_CURRENT = 36, + DHW_BOUNDS = 48, + CH_BOUNDS = 49, + OTC_CURVE_BOUNDS = 50, + DHW_SETPOINT = 56, + MAX_CH_SETPOINT = 57, + OTC_CURVE_RATIO = 58, + + // HVAC Specific Message IDs + HVAC_STATUS = 70, + REL_VENT_SETPOINT = 71, + DEVICE_VENT = 74, + REL_VENTILATION = 77, + REL_HUMID_EXHAUST = 78, + SUPPLY_INLET_TEMP = 80, + SUPPLY_OUTLET_TEMP = 81, + EXHAUST_INLET_TEMP = 82, + EXHAUST_OUTLET_TEMP = 83, + NOM_REL_VENTILATION = 87, + + OVERRIDE_FUNC = 100, + OEM_DIAGNOSTIC = 115, + BURNER_STARTS = 116, + CH_PUMP_STARTS = 117, + DHW_PUMP_STARTS = 118, + DHW_BURNER_STARTS = 119, + BURNER_HOURS = 120, + CH_PUMP_HOURS = 121, + DHW_PUMP_HOURS = 122, + DHW_BURNER_HOURS = 123, + OT_VERSION_CONTROLLER = 124, + OT_VERSION_DEVICE = 125, + VERSION_CONTROLLER = 126, + VERSION_DEVICE = 127 +}; + +enum BitPositions { STOP_BIT = 33 }; + +/** + * Structure to hold Opentherm data packet content. + * Use f88(), u16() or s16() functions to get appropriate value of data packet accoridng to id of message. + */ +struct OpenthermData { + uint8_t type; + uint8_t id; + uint8_t valueHB; + uint8_t valueLB; + + OpenthermData() : type(0), id(0), valueHB(0), valueLB(0) {} + + /** + * @return float representation of data packet value + */ + float f88(); + + /** + * @param float number to set as value of this data packet + */ + void f88(float value); + + /** + * @return unsigned 16b integer representation of data packet value + */ + uint16_t u16(); + + /** + * @param unsigned 16b integer number to set as value of this data packet + */ + void u16(uint16_t value); + + /** + * @return signed 16b integer representation of data packet value + */ + int16_t s16(); + + /** + * @param signed 16b integer number to set as value of this data packet + */ + void s16(int16_t value); +}; + +struct OpenThermError { + ProtocolErrorType error_type; + uint32_t capture; + uint8_t clock; + uint32_t data; + uint8_t bit_pos; +}; + +/** + * Opentherm static class that supports either listening or sending Opentherm data packets in the same time + */ +class OpenTherm { + public: + OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout = 800); + + /** + * Setup pins. + */ + bool initialize(); + + /** + * Start listening for Opentherm data packet comming from line connected to given pin. + * If data packet is received then has_message() function returns true and data packet can be retrieved by calling + * get_message() function. If timeout > 0 then this function waits for incomming data package for timeout millis and + * if no data packet is recevived, error state is indicated by is_error() function. If either data packet is received + * or timeout is reached listening is stopped. + */ + void listen(); + + /** + * Use this function to check whether listen() function already captured a valid data packet. + * + * @return true if data packet has been captured from line by listen() function. + */ + bool has_message() { return mode_ == OperationMode::RECEIVED; } + + /** + * Use this to retrive data packed captured by listen() function. Data packet is ready when has_message() function + * returns true. This function can be called multiple times until stop() is called. + * + * @param data reference to data structure to which fill the data packet data. + * @return true if packet was ready and was filled into data structure passed, false otherwise. + */ + bool get_message(OpenthermData &data); + + /** + * Immediately send out Opentherm data packet to line connected on given pin. + * Completed data transfer is indicated by is_sent() function. + * Error state is indicated by is_error() function. + * + * @param data Opentherm data packet. + */ + void send(OpenthermData &data); + + /** + * Stops listening for data packet or sending out data packet and resets internal state of this class. + * Stops all timers and unattaches all interrupts. + */ + void stop(); + + /** + * Get protocol error details in case a protocol error occured. + * @param error reference to data structure to which fill the error details + * @return true if protocol error occured during last conversation, false otherwise. + */ + bool get_protocol_error(OpenThermError &error); + + /** + * Use this function to check whether send() function already finished sending data packed to line. + * + * @return true if data packet has been sent, false otherwise. + */ + bool is_sent() { return mode_ == OperationMode::SENT; } + + /** + * Indicates whether listinig or sending is not in progress. + * That also means that no timers are running and no interrupts are attached. + * + * @return true if listening nor sending is in progress. + */ + bool is_idle() { return mode_ == OperationMode::IDLE; } + + /** + * Indicates whether last listen() or send() operation ends up with an error. Includes both timeout and + * protocol errors. + * + * @return true if last listen() or send() operation ends up with an error. + */ + bool is_error() { return mode_ == OperationMode::ERROR_TIMEOUT || mode_ == OperationMode::ERROR_PROTOCOL; } + + /** + * Indicates whether last listen() or send() operation ends up with a *timeout* error + * @return true if last listen() or send() operation ends up with a *timeout* error. + */ + bool is_timeout() { return mode_ == OperationMode::ERROR_TIMEOUT; } + + /** + * Indicates whether last listen() or send() operation ends up with a *protocol* error + * @return true if last listen() or send() operation ends up with a *protocol* error. + */ + bool is_protocol_error() { return mode_ == OperationMode::ERROR_PROTOCOL; } + + bool is_active() { return mode_ == LISTEN || mode_ == READ || mode_ == WRITE; } + + OperationMode get_mode() { return mode_; } + + std::string debug_data(OpenthermData &data); + std::string debug_error(OpenThermError &error); + + const char *protocol_error_to_to_str(ProtocolErrorType error_type); + const char *message_type_to_str(MessageType message_type); + const char *operation_mode_to_str(OperationMode mode); + const char *message_id_to_str(MessageId id); + + static bool timer_isr(OpenTherm *arg); + +#ifdef ESP8266 + static void esp8266_timer_isr(); +#endif + + private: + InternalGPIOPin *in_pin_; + InternalGPIOPin *out_pin_; + ISRInternalGPIOPin isr_in_pin_; + ISRInternalGPIOPin isr_out_pin_; + +#if defined(ESP32) || defined(USE_ESP_IDF) + timer_group_t timer_group_; + timer_idx_t timer_idx_; +#endif + + OperationMode mode_; + ProtocolErrorType error_type_; + uint32_t capture_; + uint8_t clock_; + uint32_t data_; + uint8_t bit_pos_; + int32_t timeout_counter_; // <0 no timeout + + int32_t device_timeout_; + +#if defined(ESP32) || defined(USE_ESP_IDF) + bool init_esp32_timer_(); + void start_esp32_timer_(uint64_t alarm_value); +#endif + + void stop_timer_(); + + void read_(); // data detected start reading + void start_read_timer_(); // reading timer_ to sample at 1/5 of manchester code bit length (at 5kHz) + void start_write_timer_(); // writing timer_ to send manchester code (at 2kHz) + bool check_parity_(uint32_t val); + + void bit_read_(uint8_t value); + ProtocolErrorType verify_stop_bit_(uint8_t value); + void write_bit_(uint8_t high, uint8_t clock); + +#ifdef ESP8266 + // ESP8266 timer can accept callback with no parameters, so we have this hack to save a static instance of OpenTherm + static OpenTherm *instance_; +#endif +}; + +} // namespace opentherm +} // namespace esphome diff --git a/tests/components/opentherm/common.yaml b/tests/components/opentherm/common.yaml new file mode 100644 index 0000000000..4148b280d0 --- /dev/null +++ b/tests/components/opentherm/common.yaml @@ -0,0 +1,3 @@ +opentherm: + in_pin: 1 + out_pin: 2 diff --git a/tests/components/opentherm/test.esp32-ard.yaml b/tests/components/opentherm/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/opentherm/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/opentherm/test.esp32-c3-ard.yaml b/tests/components/opentherm/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/opentherm/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/opentherm/test.esp32-c3-idf.yaml b/tests/components/opentherm/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/opentherm/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/opentherm/test.esp32-idf.yaml b/tests/components/opentherm/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/opentherm/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/opentherm/test.esp8266-ard.yaml b/tests/components/opentherm/test.esp8266-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/opentherm/test.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 7f00b5eb658e2871afb73c5988d49b8da0fbde8b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:08:41 +1200 Subject: [PATCH 2388/2607] [voice-assistant] Dont error on ``no_wake_word`` timeout error with streaming wake word (#7435) --- esphome/components/voice_assistant/voice_assistant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 577de630fb..a2210f188d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -755,7 +755,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { message = std::move(arg.value); } } - if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") { + if (code == "wake-word-timeout" || code == "wake_word_detection_aborted" || code == "no_wake_word") { // Don't change state here since either the "tts-end" or "run-end" events will do it. return; } else if (code == "wake-provider-missing" || code == "wake-engine-missing") { From 80e3de94d3d581f91f0197ea2ab49c2c5b6fca45 Mon Sep 17 00:00:00 2001 From: Tomer <57483589+tomer-w@users.noreply.github.com> Date: Fri, 13 Sep 2024 03:56:04 +0300 Subject: [PATCH 2389/2607] =?UTF-8?q?Improve=20manufacturer=20data=20traci?= =?UTF-8?q?ng=20to=20identify=20BLE=20devices=20a=20bit=20easie=E2=80=A6?= =?UTF-8?q?=20(#7332)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ble_presence/binary_sensor.py | 4 ++-- esphome/components/esp32_ble/ble_uuid.cpp | 7 +++++++ esphome/components/esp32_ble/ble_uuid.h | 1 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 20 ++++++++++--------- .../esp32_ble_tracker/esp32_ble_tracker.h | 6 +++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index d1fdc80289..3a0f1ade98 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -41,7 +41,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, - cv.Optional(CONF_IBEACON_UUID): cv.uuid, + cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_TIMEOUT, default="5min"): cv.positive_time_period, cv.Optional(CONF_MIN_RSSI): cv.All( cv.decibel, cv.int_range(min=-100, max=-30) @@ -83,7 +83,7 @@ async def to_code(config): cg.add(var.set_service_uuid128(uuid128)) if ibeacon_uuid := config.get(CONF_IBEACON_UUID): - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) + ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: diff --git a/esphome/components/esp32_ble/ble_uuid.cpp b/esphome/components/esp32_ble/ble_uuid.cpp index 57c2f9df94..07ac719434 100644 --- a/esphome/components/esp32_ble/ble_uuid.cpp +++ b/esphome/components/esp32_ble/ble_uuid.cpp @@ -31,6 +31,13 @@ ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) { memcpy(ret.uuid_.uuid.uuid128, data, ESP_UUID_LEN_128); return ret; } +ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) { + ESPBTUUID ret; + ret.uuid_.len = ESP_UUID_LEN_128; + for (int i = 0; i < ESP_UUID_LEN_128; i++) + ret.uuid_.uuid.uuid128[ESP_UUID_LEN_128 - 1 - i] = data[i]; + return ret; +} ESPBTUUID ESPBTUUID::from_raw(const std::string &data) { ESPBTUUID ret; if (data.length() == 4) { diff --git a/esphome/components/esp32_ble/ble_uuid.h b/esphome/components/esp32_ble/ble_uuid.h index 790a57c59d..d90db3a599 100644 --- a/esphome/components/esp32_ble/ble_uuid.h +++ b/esphome/components/esp32_ble/ble_uuid.h @@ -20,6 +20,7 @@ class ESPBTUUID { static ESPBTUUID from_uint32(uint32_t uuid); static ESPBTUUID from_raw(const uint8_t *data); + static ESPBTUUID from_raw_reversed(const uint8_t *data); static ESPBTUUID from_raw(const std::string &data); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index d154d4e519..74b4b9aa89 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -462,14 +462,16 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str()); } for (auto &data : this->manufacturer_datas_) { - ESP_LOGVV(TAG, " Manufacturer data: %s", format_hex_pretty(data.data).c_str()); - if (this->get_ibeacon().has_value()) { - auto ibeacon = this->get_ibeacon().value(); - ESP_LOGVV(TAG, " iBeacon data:"); - ESP_LOGVV(TAG, " UUID: %s", ibeacon.get_uuid().to_string().c_str()); - ESP_LOGVV(TAG, " Major: %u", ibeacon.get_major()); - ESP_LOGVV(TAG, " Minor: %u", ibeacon.get_minor()); - ESP_LOGVV(TAG, " TXPower: %d", ibeacon.get_signal_power()); + auto ibeacon = ESPBLEiBeacon::from_manufacturer_data(data); + if (ibeacon.has_value()) { + ESP_LOGVV(TAG, " Manufacturer iBeacon:"); + ESP_LOGVV(TAG, " UUID: %s", ibeacon.value().get_uuid().to_string().c_str()); + ESP_LOGVV(TAG, " Major: %u", ibeacon.value().get_major()); + ESP_LOGVV(TAG, " Minor: %u", ibeacon.value().get_minor()); + ESP_LOGVV(TAG, " TXPower: %d", ibeacon.value().get_signal_power()); + } else { + ESP_LOGVV(TAG, " Manufacturer ID: %s, data: %s", data.uuid.to_string().c_str(), + format_hex_pretty(data.data).c_str()); } } for (auto &data : this->service_datas_) { @@ -478,7 +480,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e ESP_LOGVV(TAG, " Data: %s", format_hex_pretty(data.data).c_str()); } - ESP_LOGVV(TAG, "Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str()); + ESP_LOGVV(TAG, " Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str()); #endif } void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 3db7a54f6e..d2bb6a6e6d 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -44,10 +44,10 @@ class ESPBLEiBeacon { ESPBLEiBeacon(const uint8_t *data); static optional from_manufacturer_data(const ServiceData &data); - uint16_t get_major() { return ((this->beacon_data_.major & 0xFF) << 8) | (this->beacon_data_.major >> 8); } - uint16_t get_minor() { return ((this->beacon_data_.minor & 0xFF) << 8) | (this->beacon_data_.minor >> 8); } + uint16_t get_major() { return byteswap(this->beacon_data_.major); } + uint16_t get_minor() { return byteswap(this->beacon_data_.minor); } int8_t get_signal_power() { return this->beacon_data_.signal_power; } - ESPBTUUID get_uuid() { return ESPBTUUID::from_raw(this->beacon_data_.proximity_uuid); } + ESPBTUUID get_uuid() { return ESPBTUUID::from_raw_reversed(this->beacon_data_.proximity_uuid); } protected: struct { From 5d8fb7cdf4a21b649427318cd9d883bb679c8d80 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:01:34 +1200 Subject: [PATCH 2390/2607] Bump version to 2024.9.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fb745fd506..ce6b9f3d01 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0b1" +__version__ = "2024.9.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From f652cd3851d17a4434876ab546021c6f698cb47f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 16 Sep 2024 08:42:45 +1000 Subject: [PATCH 2391/2607] [st7701s] Make use of IDF5.x to speed up display operations (#7447) --- esphome/components/st7701s/st7701s.cpp | 32 +++++++++++++++++++------- esphome/components/st7701s/st7701s.h | 2 ++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 7f02fe1774..7248bc044e 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -8,8 +8,22 @@ namespace st7701s { void ST7701S::setup() { esph_log_config(TAG, "Setting up ST7701S"); this->spi_setup(); + this->write_init_sequence_(); +} + +// called after a delay after writing the init sequence +void ST7701S::complete_setup_() { + this->write_command_(SLEEP_OUT); + this->write_command_(DISPLAY_ON); + this->spi_teardown(); // SPI not needed after this + delay(10); + esp_lcd_rgb_panel_config_t config{}; config.flags.fb_in_psram = 1; +#if ESP_IDF_VERSION_MAJOR >= 5 + config.bounce_buffer_size_px = this->width_ * 10; + config.num_fbs = 1; +#endif // ESP_IDF_VERSION_MAJOR config.timings.h_res = this->width_; config.timings.v_res = this->height_; config.timings.hsync_pulse_width = this->hsync_pulse_width_; @@ -21,7 +35,6 @@ void ST7701S::setup() { config.timings.flags.pclk_active_neg = this->pclk_inverted_; config.timings.pclk_hz = this->pclk_frequency_; config.clk_src = LCD_CLK_SRC_PLL160M; - config.sram_trans_align = 64; config.psram_trans_align = 64; size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]); for (size_t i = 0; i != data_pin_count; i++) { @@ -34,15 +47,21 @@ void ST7701S::setup() { config.de_gpio_num = this->de_pin_->get_pin(); config.pclk_gpio_num = this->pclk_pin_->get_pin(); esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_); + ESP_ERROR_CHECK(esp_lcd_panel_reset(this->handle_)); + ESP_ERROR_CHECK(esp_lcd_panel_init(this->handle_)); if (err != ESP_OK) { esph_log_e(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err)); } - ESP_ERROR_CHECK(esp_lcd_panel_reset(this->handle_)); - ESP_ERROR_CHECK(esp_lcd_panel_init(this->handle_)); - this->write_init_sequence_(); esph_log_config(TAG, "ST7701S setup complete"); } +void ST7701S::loop() { +#if ESP_IDF_VERSION_MAJOR >= 5 + if (this->handle_ != nullptr) + esp_lcd_rgb_panel_restart(this->handle_); +#endif // ESP_IDF_VERSION_MAJOR +} + void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { if (w <= 0 || h <= 0) @@ -160,10 +179,7 @@ void ST7701S::write_init_sequence_() { this->write_data_(val); ESP_LOGD(TAG, "write MADCTL %X", val); this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); - this->set_timeout(120, [this] { - this->write_command_(SLEEP_OUT); - this->write_command_(DISPLAY_ON); - }); + this->set_timeout(120, [this] { this->complete_setup_(); }); } void ST7701S::dump_config() { diff --git a/esphome/components/st7701s/st7701s.h b/esphome/components/st7701s/st7701s.h index 80e5b81f4a..a1e3c2e54a 100644 --- a/esphome/components/st7701s/st7701s.h +++ b/esphome/components/st7701s/st7701s.h @@ -33,6 +33,8 @@ class ST7701S : public display::Display, public: void update() override { this->do_update_(); } void setup() override; + void complete_setup_(); + void loop() override; void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; From 857d79dc714f123dabafe46eacbbbae0e979a19c Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 15 Sep 2024 18:46:54 -0500 Subject: [PATCH 2392/2607] Add sample_bytes to media player supported format (#7451) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_connection.cpp | 1 + esphome/components/api/api_pb2.cpp | 10 ++++++++++ esphome/components/api/api_pb2.h | 1 + esphome/components/media_player/media_player.h | 1 + 5 files changed, 14 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 1c40e8014e..a966643d30 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1118,6 +1118,7 @@ message MediaPlayerSupportedFormat { uint32 sample_rate = 2; uint32 num_channels = 3; MediaPlayerFormatPurpose purpose = 4; + uint32 sample_bytes = 5; } message ListEntitiesMediaPlayerResponse { option (id) = 63; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 6b7051a704..20e9a45314 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1032,6 +1032,7 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play media_format.sample_rate = supported_format.sample_rate; media_format.num_channels = supported_format.num_channels; media_format.purpose = static_cast(supported_format.purpose); + media_format.sample_bytes = supported_format.sample_bytes; msg.supported_formats.push_back(media_format); } diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 2a1552d6fc..955f17612a 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -5149,6 +5149,10 @@ bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt va this->purpose = value.as_enum(); return true; } + case 5: { + this->sample_bytes = value.as_uint32(); + return true; + } default: return false; } @@ -5168,6 +5172,7 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(2, this->sample_rate); buffer.encode_uint32(3, this->num_channels); buffer.encode_enum(4, this->purpose); + buffer.encode_uint32(5, this->sample_bytes); } #ifdef HAS_PROTO_MESSAGE_DUMP void MediaPlayerSupportedFormat::dump_to(std::string &out) const { @@ -5190,6 +5195,11 @@ void MediaPlayerSupportedFormat::dump_to(std::string &out) const { out.append(" purpose: "); out.append(proto_enum_to_string(this->purpose)); out.append("\n"); + + out.append(" sample_bytes: "); + sprintf(buffer, "%" PRIu32, this->sample_bytes); + out.append(buffer); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 6fab1f57e0..1ce6482b09 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1277,6 +1277,7 @@ class MediaPlayerSupportedFormat : public ProtoMessage { uint32_t sample_rate{0}; uint32_t num_channels{0}; enums::MediaPlayerFormatPurpose purpose{}; + uint32_t sample_bytes{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/media_player/media_player.h b/esphome/components/media_player/media_player.h index 26bef55afc..78b3ed6216 100644 --- a/esphome/components/media_player/media_player.h +++ b/esphome/components/media_player/media_player.h @@ -37,6 +37,7 @@ struct MediaPlayerSupportedFormat { uint32_t sample_rate; uint32_t num_channels; MediaPlayerFormatPurpose purpose; + uint32_t sample_bytes; }; class MediaPlayer; From bfde7fd9d796a2e65f92e6d074e432de00a8989b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:32:39 +1200 Subject: [PATCH 2393/2607] [docker] Bump git from 1:2.39.2-1.1 to 1:2.39.5-0+deb12u1 (#7452) --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e255f4e2fc..85823687c2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -33,7 +33,7 @@ RUN \ python3-venv=3.11.2-1+b1 \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ - git=1:2.39.2-1.1 \ + git=1:2.39.5-0+deb12u1 \ curl=7.88.1-10+deb12u7 \ openssh-client=1:9.2p1-2+deb12u3 \ python3-cffi=1.15.1-5 \ From e7fe9b374fb8ac9c1e7c5ab5869f8114509fbe6a Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 15 Sep 2024 18:46:54 -0500 Subject: [PATCH 2394/2607] Add sample_bytes to media player supported format (#7451) --- esphome/components/api/api.proto | 1 + esphome/components/api/api_connection.cpp | 1 + esphome/components/api/api_pb2.cpp | 10 ++++++++++ esphome/components/api/api_pb2.h | 1 + esphome/components/media_player/media_player.h | 1 + 5 files changed, 14 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 1c40e8014e..a966643d30 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1118,6 +1118,7 @@ message MediaPlayerSupportedFormat { uint32 sample_rate = 2; uint32 num_channels = 3; MediaPlayerFormatPurpose purpose = 4; + uint32 sample_bytes = 5; } message ListEntitiesMediaPlayerResponse { option (id) = 63; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 6b7051a704..20e9a45314 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1032,6 +1032,7 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play media_format.sample_rate = supported_format.sample_rate; media_format.num_channels = supported_format.num_channels; media_format.purpose = static_cast(supported_format.purpose); + media_format.sample_bytes = supported_format.sample_bytes; msg.supported_formats.push_back(media_format); } diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 2a1552d6fc..955f17612a 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -5149,6 +5149,10 @@ bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt va this->purpose = value.as_enum(); return true; } + case 5: { + this->sample_bytes = value.as_uint32(); + return true; + } default: return false; } @@ -5168,6 +5172,7 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(2, this->sample_rate); buffer.encode_uint32(3, this->num_channels); buffer.encode_enum(4, this->purpose); + buffer.encode_uint32(5, this->sample_bytes); } #ifdef HAS_PROTO_MESSAGE_DUMP void MediaPlayerSupportedFormat::dump_to(std::string &out) const { @@ -5190,6 +5195,11 @@ void MediaPlayerSupportedFormat::dump_to(std::string &out) const { out.append(" purpose: "); out.append(proto_enum_to_string(this->purpose)); out.append("\n"); + + out.append(" sample_bytes: "); + sprintf(buffer, "%" PRIu32, this->sample_bytes); + out.append(buffer); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 6fab1f57e0..1ce6482b09 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1277,6 +1277,7 @@ class MediaPlayerSupportedFormat : public ProtoMessage { uint32_t sample_rate{0}; uint32_t num_channels{0}; enums::MediaPlayerFormatPurpose purpose{}; + uint32_t sample_bytes{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/media_player/media_player.h b/esphome/components/media_player/media_player.h index 26bef55afc..78b3ed6216 100644 --- a/esphome/components/media_player/media_player.h +++ b/esphome/components/media_player/media_player.h @@ -37,6 +37,7 @@ struct MediaPlayerSupportedFormat { uint32_t sample_rate; uint32_t num_channels; MediaPlayerFormatPurpose purpose; + uint32_t sample_bytes; }; class MediaPlayer; From 6483ceb6eb0b4aeee7f2fe1dc9c2cf8d5f3d448d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:32:39 +1200 Subject: [PATCH 2395/2607] [docker] Bump git from 1:2.39.2-1.1 to 1:2.39.5-0+deb12u1 (#7452) --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e255f4e2fc..85823687c2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -33,7 +33,7 @@ RUN \ python3-venv=3.11.2-1+b1 \ python3-wheel=0.38.4-2 \ iputils-ping=3:20221126-1 \ - git=1:2.39.2-1.1 \ + git=1:2.39.5-0+deb12u1 \ curl=7.88.1-10+deb12u7 \ openssh-client=1:9.2p1-2+deb12u3 \ python3-cffi=1.15.1-5 \ From a63b9a9e0c58b27279ead5d3238273fce45cd6ba Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:17:06 +1200 Subject: [PATCH 2396/2607] Bump version to 2024.9.0b3 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index ce6b9f3d01..24deba1f15 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0b2" +__version__ = "2024.9.0b3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 3835ad8c1f793f19d21cf2a158744ae6228ae0b4 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 15 Sep 2024 20:40:45 -0500 Subject: [PATCH 2397/2607] Add voice assistant configuration messages (#7445) --- esphome/components/api/api.proto | 30 +++++ esphome/components/api/api_pb2.cpp | 143 +++++++++++++++++++++ esphome/components/api/api_pb2.h | 48 +++++++ esphome/components/api/api_pb2_service.cpp | 35 +++++ esphome/components/api/api_pb2_service.h | 9 ++ 5 files changed, 265 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index a966643d30..92fb57b711 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1571,6 +1571,36 @@ message VoiceAssistantAnnounceFinished { bool success = 1; } +message VoiceAssistantWakeWord { + uint32 id = 1; + string wake_word = 2; + repeated string trained_languages = 3; +} + +message VoiceAssistantConfigurationRequest { + option (id) = 121; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; +} + +message VoiceAssistantConfigurationResponse { + option (id) = 122; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + repeated VoiceAssistantWakeWord available_wake_words = 1; + repeated uint32 active_wake_words = 2; + uint32 max_active_wake_words = 3; +} + +message VoiceAssistantSetConfiguration { + option (id) = 123; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + repeated uint32 active_wake_words = 1; +} + // ==================== ALARM CONTROL PANEL ==================== enum AlarmControlPanelState { ALARM_STATE_DISARMED = 0; diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 955f17612a..791de29511 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7124,6 +7124,149 @@ void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->id = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->wake_word = value.as_string(); + return true; + } + case 3: { + this->trained_languages.push_back(value.as_string()); + return true; + } + default: + return false; + } +} +void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint32(1, this->id); + buffer.encode_string(2, this->wake_word); + for (auto &it : this->trained_languages) { + buffer.encode_string(3, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantWakeWord::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantWakeWord {\n"); + out.append(" id: "); + sprintf(buffer, "%" PRIu32, this->id); + out.append(buffer); + out.append("\n"); + + out.append(" wake_word: "); + out.append("'").append(this->wake_word).append("'"); + out.append("\n"); + + for (const auto &it : this->trained_languages) { + out.append(" trained_languages: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +#endif +void VoiceAssistantConfigurationRequest::encode(ProtoWriteBuffer buffer) const {} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { + out.append("VoiceAssistantConfigurationRequest {}"); +} +#endif +bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->active_wake_words.push_back(value.as_uint32()); + return true; + } + case 3: { + this->max_active_wake_words = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantConfigurationResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->available_wake_words.push_back(value.as_message()); + return true; + } + default: + return false; + } +} +void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const { + for (auto &it : this->available_wake_words) { + buffer.encode_message(1, it, true); + } + for (auto &it : this->active_wake_words) { + buffer.encode_uint32(2, it, true); + } + buffer.encode_uint32(3, this->max_active_wake_words); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantConfigurationResponse {\n"); + for (const auto &it : this->available_wake_words) { + out.append(" available_wake_words: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + sprintf(buffer, "%" PRIu32, it); + out.append(buffer); + out.append("\n"); + } + + out.append(" max_active_wake_words: "); + sprintf(buffer, "%" PRIu32, this->max_active_wake_words); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->active_wake_words.push_back(value.as_uint32()); + return true; + } + default: + return false; + } +} +void VoiceAssistantSetConfiguration::encode(ProtoWriteBuffer buffer) const { + for (auto &it : this->active_wake_words) { + buffer.encode_uint32(1, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantSetConfiguration {\n"); + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + sprintf(buffer, "%" PRIu32, it); + out.append(buffer); + out.append("\n"); + } + out.append("}"); +} +#endif bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 1ce6482b09..8631884f94 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1849,6 +1849,54 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantWakeWord : public ProtoMessage { + public: + uint32_t id{0}; + std::string wake_word{}; + std::vector trained_languages{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantConfigurationRequest : public ProtoMessage { + public: + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: +}; +class VoiceAssistantConfigurationResponse : public ProtoMessage { + public: + std::vector available_wake_words{}; + std::vector active_wake_words{}; + uint32_t max_active_wake_words{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantSetConfiguration : public ProtoMessage { + public: + std::vector active_wake_words{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index faa977389a..454f20d50a 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -496,6 +496,19 @@ bool APIServerConnectionBase::send_voice_assistant_announce_finished(const Voice return this->send_message_(msg, 120); } #endif +#ifdef USE_VOICE_ASSISTANT +#endif +#ifdef USE_VOICE_ASSISTANT +bool APIServerConnectionBase::send_voice_assistant_configuration_response( + const VoiceAssistantConfigurationResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_voice_assistant_configuration_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 122); +} +#endif +#ifdef USE_VOICE_ASSISTANT +#endif #ifdef USE_ALARM_CONTROL_PANEL bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( const ListEntitiesAlarmControlPanelResponse &msg) { @@ -1156,6 +1169,28 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str()); #endif this->on_voice_assistant_announce_request(msg); +#endif + break; + } + case 121: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantConfigurationRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_configuration_request(msg); +#endif + break; + } + case 123: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantSetConfiguration msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_set_configuration(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index f3803ad628..e69954f7ab 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -253,6 +253,15 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_VOICE_ASSISTANT bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg); #endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){}; +#endif +#ifdef USE_VOICE_ASSISTANT + bool send_voice_assistant_configuration_response(const VoiceAssistantConfigurationResponse &msg); +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){}; +#endif #ifdef USE_ALARM_CONTROL_PANEL bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); #endif From 73e469ae528cb4a522f8125837416f97a91e50de Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:43:45 +1200 Subject: [PATCH 2398/2607] [modbus_controller] Fix linting and formatting issues (#7441) --- .../components/modbus_controller/__init__.py | 12 ++++++---- .../binary_sensor/__init__.py | 14 +++++------ .../modbus_controller/number/__init__.py | 11 ++++----- .../modbus_controller/output/__init__.py | 24 ++++++++----------- .../modbus_controller/select/__init__.py | 2 +- .../modbus_controller/sensor/__init__.py | 16 ++++++------- .../modbus_controller/switch/__init__.py | 15 ++++++------ .../modbus_controller/text_sensor/__init__.py | 19 +++++++-------- 8 files changed, 54 insertions(+), 59 deletions(-) diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 6917807b07..488baa245a 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -1,27 +1,29 @@ import binascii -import esphome.codegen as cg -import esphome.config_validation as cv + from esphome import automation +import esphome.codegen as cg from esphome.components import modbus +import esphome.config_validation as cv from esphome.const import ( CONF_ADDRESS, CONF_ID, - CONF_NAME, CONF_LAMBDA, + CONF_NAME, CONF_OFFSET, CONF_TRIGGER_ID, ) from esphome.cpp_helpers import logging + from .const import ( CONF_ALLOW_DUPLICATE_COMMANDS, CONF_BITMASK, CONF_BYTE_OFFSET, CONF_COMMAND_THROTTLE, - CONF_OFFLINE_SKIP_UPDATES, CONF_CUSTOM_COMMAND, CONF_FORCE_NEW_RANGE, - CONF_MODBUS_CONTROLLER_ID, CONF_MAX_CMD_RETRIES, + CONF_MODBUS_CONTROLLER_ID, + CONF_OFFLINE_SKIP_UPDATES, CONF_ON_COMMAND_SENT, CONF_REGISTER_COUNT, CONF_REGISTER_TYPE, diff --git a/esphome/components/modbus_controller/binary_sensor/__init__.py b/esphome/components/modbus_controller/binary_sensor/__init__.py index 5315167479..2ae008f630 100644 --- a/esphome/components/modbus_controller/binary_sensor/__init__.py +++ b/esphome/components/modbus_controller/binary_sensor/__init__.py @@ -1,16 +1,16 @@ +import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv -import esphome.codegen as cg - from esphome.const import CONF_ADDRESS, CONF_ID + from .. import ( - add_modbus_base_properties, - modbus_controller_ns, - modbus_calc_properties, - validate_modbus_register, + MODBUS_REGISTER_TYPE, ModbusItemBaseSchema, SensorItem, - MODBUS_REGISTER_TYPE, + add_modbus_base_properties, + modbus_calc_properties, + modbus_controller_ns, + validate_modbus_register, ) from ..const import ( CONF_BITMASK, diff --git a/esphome/components/modbus_controller/number/__init__.py b/esphome/components/modbus_controller/number/__init__.py index fe99b28a00..b5efd7abf0 100644 --- a/esphome/components/modbus_controller/number/__init__.py +++ b/esphome/components/modbus_controller/number/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import number +import esphome.config_validation as cv from esphome.const import ( CONF_ADDRESS, CONF_ID, @@ -12,14 +12,13 @@ from esphome.const import ( from .. import ( MODBUS_WRITE_REGISTER_TYPE, - add_modbus_base_properties, - modbus_controller_ns, - modbus_calc_properties, + SENSOR_VALUE_TYPE, ModbusItemBaseSchema, SensorItem, - SENSOR_VALUE_TYPE, + add_modbus_base_properties, + modbus_calc_properties, + modbus_controller_ns, ) - from ..const import ( CONF_BITMASK, CONF_CUSTOM_COMMAND, diff --git a/esphome/components/modbus_controller/output/__init__.py b/esphome/components/modbus_controller/output/__init__.py index 1bf989ce8b..1800a90d57 100644 --- a/esphome/components/modbus_controller/output/__init__.py +++ b/esphome/components/modbus_controller/output/__init__.py @@ -1,20 +1,15 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import output -from esphome.const import ( - CONF_ADDRESS, - CONF_ID, - CONF_MULTIPLY, -) +import esphome.config_validation as cv +from esphome.const import CONF_ADDRESS, CONF_ID, CONF_MULTIPLY from .. import ( - modbus_controller_ns, - modbus_calc_properties, + SENSOR_VALUE_TYPE, ModbusItemBaseSchema, SensorItem, - SENSOR_VALUE_TYPE, + modbus_calc_properties, + modbus_controller_ns, ) - from ..const import ( CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_TYPE, @@ -65,6 +60,7 @@ CONFIG_SCHEMA = cv.typed_schema( async def to_code(config): byte_offset, reg_count = modbus_calc_properties(config) # Binary Output + write_template = None if config[CONF_REGISTER_TYPE] == "coil": var = cg.new_Pvariable( config[CONF_ID], @@ -72,7 +68,7 @@ async def to_code(config): byte_offset, ) if CONF_WRITE_LAMBDA in config: - template_ = await cg.process_lambda( + write_template = await cg.process_lambda( config[CONF_WRITE_LAMBDA], [ (ModbusBinaryOutput.operator("ptr"), "item"), @@ -92,7 +88,7 @@ async def to_code(config): ) cg.add(var.set_write_multiply(config[CONF_MULTIPLY])) if CONF_WRITE_LAMBDA in config: - template_ = await cg.process_lambda( + write_template = await cg.process_lambda( config[CONF_WRITE_LAMBDA], [ (ModbusFloatOutput.operator("ptr"), "item"), @@ -105,5 +101,5 @@ async def to_code(config): parent = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID]) cg.add(var.set_use_write_mutiple(config[CONF_USE_WRITE_MULTIPLE])) cg.add(var.set_parent(parent)) - if CONF_WRITE_LAMBDA in config: - cg.add(var.set_write_template(template_)) + if write_template: + cg.add(var.set_write_template(write_template)) diff --git a/esphome/components/modbus_controller/select/__init__.py b/esphome/components/modbus_controller/select/__init__.py index 5692fea3e3..c94532da51 100644 --- a/esphome/components/modbus_controller/select/__init__.py +++ b/esphome/components/modbus_controller/select/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import select +import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_OPTIMISTIC from .. import ( diff --git a/esphome/components/modbus_controller/sensor/__init__.py b/esphome/components/modbus_controller/sensor/__init__.py index 0e4588cfef..d8fce54ece 100644 --- a/esphome/components/modbus_controller/sensor/__init__.py +++ b/esphome/components/modbus_controller/sensor/__init__.py @@ -1,17 +1,17 @@ +import esphome.codegen as cg from esphome.components import sensor import esphome.config_validation as cv -import esphome.codegen as cg +from esphome.const import CONF_ADDRESS, CONF_ID -from esphome.const import CONF_ID, CONF_ADDRESS from .. import ( - add_modbus_base_properties, - modbus_controller_ns, - modbus_calc_properties, - validate_modbus_register, - ModbusItemBaseSchema, - SensorItem, MODBUS_REGISTER_TYPE, SENSOR_VALUE_TYPE, + ModbusItemBaseSchema, + SensorItem, + add_modbus_base_properties, + modbus_calc_properties, + modbus_controller_ns, + validate_modbus_register, ) from ..const import ( CONF_BITMASK, diff --git a/esphome/components/modbus_controller/switch/__init__.py b/esphome/components/modbus_controller/switch/__init__.py index 9490325968..258d87fd25 100644 --- a/esphome/components/modbus_controller/switch/__init__.py +++ b/esphome/components/modbus_controller/switch/__init__.py @@ -1,17 +1,16 @@ +import esphome.codegen as cg from esphome.components import switch import esphome.config_validation as cv -import esphome.codegen as cg +from esphome.const import CONF_ADDRESS, CONF_ID - -from esphome.const import CONF_ID, CONF_ADDRESS from .. import ( - add_modbus_base_properties, - modbus_controller_ns, - modbus_calc_properties, - validate_modbus_register, + MODBUS_REGISTER_TYPE, ModbusItemBaseSchema, SensorItem, - MODBUS_REGISTER_TYPE, + add_modbus_base_properties, + modbus_calc_properties, + modbus_controller_ns, + validate_modbus_register, ) from ..const import ( CONF_BITMASK, diff --git a/esphome/components/modbus_controller/text_sensor/__init__.py b/esphome/components/modbus_controller/text_sensor/__init__.py index 81d6453c6f..35cae645e1 100644 --- a/esphome/components/modbus_controller/text_sensor/__init__.py +++ b/esphome/components/modbus_controller/text_sensor/__init__.py @@ -1,26 +1,25 @@ +import esphome.codegen as cg from esphome.components import text_sensor import esphome.config_validation as cv -import esphome.codegen as cg - - from esphome.const import CONF_ADDRESS, CONF_ID + from .. import ( - add_modbus_base_properties, - modbus_controller_ns, - modbus_calc_properties, - validate_modbus_register, + MODBUS_REGISTER_TYPE, ModbusItemBaseSchema, SensorItem, - MODBUS_REGISTER_TYPE, + add_modbus_base_properties, + modbus_calc_properties, + modbus_controller_ns, + validate_modbus_register, ) from ..const import ( CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, + CONF_RAW_ENCODE, CONF_REGISTER_COUNT, + CONF_REGISTER_TYPE, CONF_RESPONSE_SIZE, CONF_SKIP_UPDATES, - CONF_RAW_ENCODE, - CONF_REGISTER_TYPE, ) DEPENDENCIES = ["modbus_controller"] From 435789a96020435b6d0c345bebb6ef19a98fd818 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:21:42 +1200 Subject: [PATCH 2399/2607] Bump pylint from 3.1.0 to 3.2.7 (#7438) --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 94abe1cd76..5d94f7f640 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==3.1.0 +pylint==3.2.7 flake8==7.0.0 # also change in .pre-commit-config.yaml when updating black==24.4.2 # also change in .pre-commit-config.yaml when updating pyupgrade==3.15.2 # also change in .pre-commit-config.yaml when updating From 857a3dcf72d74fa53fba2f6c63f2ceaaec3e5e59 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:03:51 +1200 Subject: [PATCH 2400/2607] Dont replace project name spaces with underlines (#7455) --- esphome/core/config.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/core/config.py b/esphome/core/config.py index 739a8a1aea..f4253bee87 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -100,9 +100,6 @@ def valid_include(value): def valid_project_name(value: str): if value.count(".") != 1: raise cv.Invalid("project name needs to have a namespace") - - value = value.replace(" ", "_") - return value From cb86749545ef26b543118aa2b349376add89829f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:47:16 +1200 Subject: [PATCH 2401/2607] Bump peter-evans/create-pull-request from 7.0.2 to 7.0.3 (#7457) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 1418867240..eeb8386e74 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v7.0.2 + uses: peter-evans/create-pull-request@v7.0.3 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From 5a3e1d57921a839a5f383350e45cdd3304efa311 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Tue, 17 Sep 2024 18:38:39 -0500 Subject: [PATCH 2402/2607] Add voice assistant methods for configuration (#7459) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 8 ++-- esphome/components/api/api_connection.cpp | 33 +++++++++++++++ esphome/components/api/api_connection.h | 3 ++ esphome/components/api/api_pb2.cpp | 41 ++++++++----------- esphome/components/api/api_pb2.h | 9 ++-- esphome/components/api/api_pb2_service.cpp | 29 +++++++++++++ esphome/components/api/api_pb2_service.h | 13 ++++++ .../voice_assistant/voice_assistant.h | 16 ++++++++ 8 files changed, 119 insertions(+), 33 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 92fb57b711..684540ffa6 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -62,6 +62,8 @@ service APIConnection { rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {} + rpc voice_assistant_get_configuration(VoiceAssistantConfigurationRequest) returns (VoiceAssistantConfigurationResponse) {} + rpc voice_assistant_set_configuration(VoiceAssistantSetConfiguration) returns (void) {} rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {} } @@ -1572,7 +1574,7 @@ message VoiceAssistantAnnounceFinished { } message VoiceAssistantWakeWord { - uint32 id = 1; + string id = 1; string wake_word = 2; repeated string trained_languages = 3; } @@ -1589,7 +1591,7 @@ message VoiceAssistantConfigurationResponse { option (ifdef) = "USE_VOICE_ASSISTANT"; repeated VoiceAssistantWakeWord available_wake_words = 1; - repeated uint32 active_wake_words = 2; + repeated string active_wake_words = 2; uint32 max_active_wake_words = 3; } @@ -1598,7 +1600,7 @@ message VoiceAssistantSetConfiguration { option (source) = SOURCE_CLIENT; option (ifdef) = "USE_VOICE_ASSISTANT"; - repeated uint32 active_wake_words = 1; + repeated string active_wake_words = 1; } // ==================== ALARM CONTROL PANEL ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 20e9a45314..7ea52e9a9e 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1224,6 +1224,39 @@ void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnno } } +VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) { + VoiceAssistantConfigurationResponse resp; + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return resp; + } + + auto &config = voice_assistant::global_voice_assistant->get_configuration(); + for (auto &wake_word : config.available_wake_words) { + VoiceAssistantWakeWord resp_wake_word; + resp_wake_word.id = wake_word.id; + resp_wake_word.wake_word = wake_word.wake_word; + for (const auto &lang : wake_word.trained_languages) { + resp_wake_word.trained_languages.push_back(lang); + } + resp.available_wake_words.push_back(std::move(resp_wake_word)); + } + resp.max_active_wake_words = config.max_active_wake_words; + } + return resp; +} + +void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return; + } + + voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words); + } +} + #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index e8d66a5e07..f176cf7c56 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -152,6 +152,9 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override; + VoiceAssistantConfigurationResponse voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) override; + void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override; #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 791de29511..8df152881c 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7124,18 +7124,12 @@ void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { out.append("}"); } #endif -bool VoiceAssistantWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { - switch (field_id) { - case 1: { - this->id = value.as_uint32(); - return true; - } - default: - return false; - } -} bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { + case 1: { + this->id = value.as_string(); + return true; + } case 2: { this->wake_word = value.as_string(); return true; @@ -7149,7 +7143,7 @@ bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimit } } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const { - buffer.encode_uint32(1, this->id); + buffer.encode_string(1, this->id); buffer.encode_string(2, this->wake_word); for (auto &it : this->trained_languages) { buffer.encode_string(3, it, true); @@ -7160,8 +7154,7 @@ void VoiceAssistantWakeWord::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantWakeWord {\n"); out.append(" id: "); - sprintf(buffer, "%" PRIu32, this->id); - out.append(buffer); + out.append("'").append(this->id).append("'"); out.append("\n"); out.append(" wake_word: "); @@ -7184,10 +7177,6 @@ void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { #endif bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { - case 2: { - this->active_wake_words.push_back(value.as_uint32()); - return true; - } case 3: { this->max_active_wake_words = value.as_uint32(); return true; @@ -7202,6 +7191,10 @@ bool VoiceAssistantConfigurationResponse::decode_length(uint32_t field_id, Proto this->available_wake_words.push_back(value.as_message()); return true; } + case 2: { + this->active_wake_words.push_back(value.as_string()); + return true; + } default: return false; } @@ -7211,7 +7204,7 @@ void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const buffer.encode_message(1, it, true); } for (auto &it : this->active_wake_words) { - buffer.encode_uint32(2, it, true); + buffer.encode_string(2, it, true); } buffer.encode_uint32(3, this->max_active_wake_words); } @@ -7227,8 +7220,7 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - sprintf(buffer, "%" PRIu32, it); - out.append(buffer); + out.append("'").append(it).append("'"); out.append("\n"); } @@ -7239,10 +7231,10 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { out.append("}"); } #endif -bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarInt value) { +bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { - this->active_wake_words.push_back(value.as_uint32()); + this->active_wake_words.push_back(value.as_string()); return true; } default: @@ -7251,7 +7243,7 @@ bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarIn } void VoiceAssistantSetConfiguration::encode(ProtoWriteBuffer buffer) const { for (auto &it : this->active_wake_words) { - buffer.encode_uint32(1, it, true); + buffer.encode_string(1, it, true); } } #ifdef HAS_PROTO_MESSAGE_DUMP @@ -7260,8 +7252,7 @@ void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { out.append("VoiceAssistantSetConfiguration {\n"); for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - sprintf(buffer, "%" PRIu32, it); - out.append(buffer); + out.append("'").append(it).append("'"); out.append("\n"); } out.append("}"); diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 8631884f94..063c217bf7 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1851,7 +1851,7 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage { }; class VoiceAssistantWakeWord : public ProtoMessage { public: - uint32_t id{0}; + std::string id{}; std::string wake_word{}; std::vector trained_languages{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1861,7 +1861,6 @@ class VoiceAssistantWakeWord : public ProtoMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; - bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class VoiceAssistantConfigurationRequest : public ProtoMessage { public: @@ -1875,7 +1874,7 @@ class VoiceAssistantConfigurationRequest : public ProtoMessage { class VoiceAssistantConfigurationResponse : public ProtoMessage { public: std::vector available_wake_words{}; - std::vector active_wake_words{}; + std::vector active_wake_words{}; uint32_t max_active_wake_words{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1888,14 +1887,14 @@ class VoiceAssistantConfigurationResponse : public ProtoMessage { }; class VoiceAssistantSetConfiguration : public ProtoMessage { public: - std::vector active_wake_words{}; + std::vector active_wake_words{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; #endif protected: - bool decode_varint(uint32_t field_id, ProtoVarInt value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 454f20d50a..6e11d7169d 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -1681,6 +1681,35 @@ void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVo this->subscribe_voice_assistant(msg); } #endif +#ifdef USE_VOICE_ASSISTANT +void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); + if (!this->send_voice_assistant_configuration_response(ret)) { + this->on_fatal_error(); + } +} +#endif +#ifdef USE_VOICE_ASSISTANT +void APIServerConnection::on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->voice_assistant_set_configuration(msg); +} +#endif #ifdef USE_ALARM_CONTROL_PANEL void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { if (!this->is_connection_setup()) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index e69954f7ab..51b94bf530 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -434,6 +434,13 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_VOICE_ASSISTANT virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; #endif +#ifdef USE_VOICE_ASSISTANT + virtual VoiceAssistantConfigurationResponse voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) = 0; +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) = 0; +#endif #ifdef USE_ALARM_CONTROL_PANEL virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0; #endif @@ -535,6 +542,12 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_VOICE_ASSISTANT void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override; #endif +#ifdef USE_VOICE_ASSISTANT + void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) override; +#endif +#ifdef USE_VOICE_ASSISTANT + void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override; +#endif #ifdef USE_ALARM_CONTROL_PANEL void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override; #endif diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index b0a172332f..56ada0e75a 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -77,6 +77,18 @@ struct Timer { } }; +struct WakeWord { + std::string id; + std::string wake_word; + std::vector trained_languages; +}; + +struct Configuration { + std::vector available_wake_words; + std::vector active_wake_words; + uint32_t max_active_wake_words; +}; + class VoiceAssistant : public Component { public: void setup() override; @@ -133,6 +145,8 @@ class VoiceAssistant : public Component { void on_audio(const api::VoiceAssistantAudio &msg); void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg); void on_announce(const api::VoiceAssistantAnnounceRequest &msg); + void on_set_configuration(const std::vector &active_wake_words){}; + const Configuration &get_configuration() { return this->config_; }; bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } @@ -279,6 +293,8 @@ class VoiceAssistant : public Component { AudioMode audio_mode_{AUDIO_MODE_UDP}; bool udp_socket_running_{false}; bool start_udp_socket_(); + + Configuration config_{}; }; template class StartAction : public Action, public Parented { From f87d9be60dc74208ce18cdcb1dd9cf87c43fe7aa Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 15 Sep 2024 20:40:45 -0500 Subject: [PATCH 2403/2607] Add voice assistant configuration messages (#7445) --- esphome/components/api/api.proto | 30 +++++ esphome/components/api/api_pb2.cpp | 143 +++++++++++++++++++++ esphome/components/api/api_pb2.h | 48 +++++++ esphome/components/api/api_pb2_service.cpp | 35 +++++ esphome/components/api/api_pb2_service.h | 9 ++ 5 files changed, 265 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index a966643d30..92fb57b711 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1571,6 +1571,36 @@ message VoiceAssistantAnnounceFinished { bool success = 1; } +message VoiceAssistantWakeWord { + uint32 id = 1; + string wake_word = 2; + repeated string trained_languages = 3; +} + +message VoiceAssistantConfigurationRequest { + option (id) = 121; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; +} + +message VoiceAssistantConfigurationResponse { + option (id) = 122; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + repeated VoiceAssistantWakeWord available_wake_words = 1; + repeated uint32 active_wake_words = 2; + uint32 max_active_wake_words = 3; +} + +message VoiceAssistantSetConfiguration { + option (id) = 123; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + repeated uint32 active_wake_words = 1; +} + // ==================== ALARM CONTROL PANEL ==================== enum AlarmControlPanelState { ALARM_STATE_DISARMED = 0; diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 955f17612a..791de29511 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7124,6 +7124,149 @@ void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { out.append("}"); } #endif +bool VoiceAssistantWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->id = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->wake_word = value.as_string(); + return true; + } + case 3: { + this->trained_languages.push_back(value.as_string()); + return true; + } + default: + return false; + } +} +void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint32(1, this->id); + buffer.encode_string(2, this->wake_word); + for (auto &it : this->trained_languages) { + buffer.encode_string(3, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantWakeWord::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantWakeWord {\n"); + out.append(" id: "); + sprintf(buffer, "%" PRIu32, this->id); + out.append(buffer); + out.append("\n"); + + out.append(" wake_word: "); + out.append("'").append(this->wake_word).append("'"); + out.append("\n"); + + for (const auto &it : this->trained_languages) { + out.append(" trained_languages: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +#endif +void VoiceAssistantConfigurationRequest::encode(ProtoWriteBuffer buffer) const {} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { + out.append("VoiceAssistantConfigurationRequest {}"); +} +#endif +bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 2: { + this->active_wake_words.push_back(value.as_uint32()); + return true; + } + case 3: { + this->max_active_wake_words = value.as_uint32(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantConfigurationResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->available_wake_words.push_back(value.as_message()); + return true; + } + default: + return false; + } +} +void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const { + for (auto &it : this->available_wake_words) { + buffer.encode_message(1, it, true); + } + for (auto &it : this->active_wake_words) { + buffer.encode_uint32(2, it, true); + } + buffer.encode_uint32(3, this->max_active_wake_words); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantConfigurationResponse {\n"); + for (const auto &it : this->available_wake_words) { + out.append(" available_wake_words: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + sprintf(buffer, "%" PRIu32, it); + out.append(buffer); + out.append("\n"); + } + + out.append(" max_active_wake_words: "); + sprintf(buffer, "%" PRIu32, this->max_active_wake_words); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->active_wake_words.push_back(value.as_uint32()); + return true; + } + default: + return false; + } +} +void VoiceAssistantSetConfiguration::encode(ProtoWriteBuffer buffer) const { + for (auto &it : this->active_wake_words) { + buffer.encode_uint32(1, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantSetConfiguration {\n"); + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + sprintf(buffer, "%" PRIu32, it); + out.append(buffer); + out.append("\n"); + } + out.append("}"); +} +#endif bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 1ce6482b09..8631884f94 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1849,6 +1849,54 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class VoiceAssistantWakeWord : public ProtoMessage { + public: + uint32_t id{0}; + std::string wake_word{}; + std::vector trained_languages{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantConfigurationRequest : public ProtoMessage { + public: + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: +}; +class VoiceAssistantConfigurationResponse : public ProtoMessage { + public: + std::vector available_wake_words{}; + std::vector active_wake_words{}; + uint32_t max_active_wake_words{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantSetConfiguration : public ProtoMessage { + public: + std::vector active_wake_words{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: std::string object_id{}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index faa977389a..454f20d50a 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -496,6 +496,19 @@ bool APIServerConnectionBase::send_voice_assistant_announce_finished(const Voice return this->send_message_(msg, 120); } #endif +#ifdef USE_VOICE_ASSISTANT +#endif +#ifdef USE_VOICE_ASSISTANT +bool APIServerConnectionBase::send_voice_assistant_configuration_response( + const VoiceAssistantConfigurationResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_voice_assistant_configuration_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 122); +} +#endif +#ifdef USE_VOICE_ASSISTANT +#endif #ifdef USE_ALARM_CONTROL_PANEL bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( const ListEntitiesAlarmControlPanelResponse &msg) { @@ -1156,6 +1169,28 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str()); #endif this->on_voice_assistant_announce_request(msg); +#endif + break; + } + case 121: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantConfigurationRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_configuration_request(msg); +#endif + break; + } + case 123: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantSetConfiguration msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_set_configuration(msg); #endif break; } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index f3803ad628..e69954f7ab 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -253,6 +253,15 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_VOICE_ASSISTANT bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg); #endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){}; +#endif +#ifdef USE_VOICE_ASSISTANT + bool send_voice_assistant_configuration_response(const VoiceAssistantConfigurationResponse &msg); +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){}; +#endif #ifdef USE_ALARM_CONTROL_PANEL bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); #endif From 749f6643308109cae5387bf7e5114fa16a0d78b0 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:03:51 +1200 Subject: [PATCH 2404/2607] Dont replace project name spaces with underlines (#7455) --- esphome/core/config.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/core/config.py b/esphome/core/config.py index 739a8a1aea..f4253bee87 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -100,9 +100,6 @@ def valid_include(value): def valid_project_name(value: str): if value.count(".") != 1: raise cv.Invalid("project name needs to have a namespace") - - value = value.replace(" ", "_") - return value From 571c0eb82703e29de70f5c82ed018b4dde2d9dc3 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Tue, 17 Sep 2024 18:38:39 -0500 Subject: [PATCH 2405/2607] Add voice assistant methods for configuration (#7459) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 8 ++-- esphome/components/api/api_connection.cpp | 33 +++++++++++++++ esphome/components/api/api_connection.h | 3 ++ esphome/components/api/api_pb2.cpp | 41 ++++++++----------- esphome/components/api/api_pb2.h | 9 ++-- esphome/components/api/api_pb2_service.cpp | 29 +++++++++++++ esphome/components/api/api_pb2_service.h | 13 ++++++ .../voice_assistant/voice_assistant.h | 16 ++++++++ 8 files changed, 119 insertions(+), 33 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 92fb57b711..684540ffa6 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -62,6 +62,8 @@ service APIConnection { rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {} + rpc voice_assistant_get_configuration(VoiceAssistantConfigurationRequest) returns (VoiceAssistantConfigurationResponse) {} + rpc voice_assistant_set_configuration(VoiceAssistantSetConfiguration) returns (void) {} rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {} } @@ -1572,7 +1574,7 @@ message VoiceAssistantAnnounceFinished { } message VoiceAssistantWakeWord { - uint32 id = 1; + string id = 1; string wake_word = 2; repeated string trained_languages = 3; } @@ -1589,7 +1591,7 @@ message VoiceAssistantConfigurationResponse { option (ifdef) = "USE_VOICE_ASSISTANT"; repeated VoiceAssistantWakeWord available_wake_words = 1; - repeated uint32 active_wake_words = 2; + repeated string active_wake_words = 2; uint32 max_active_wake_words = 3; } @@ -1598,7 +1600,7 @@ message VoiceAssistantSetConfiguration { option (source) = SOURCE_CLIENT; option (ifdef) = "USE_VOICE_ASSISTANT"; - repeated uint32 active_wake_words = 1; + repeated string active_wake_words = 1; } // ==================== ALARM CONTROL PANEL ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 20e9a45314..7ea52e9a9e 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1224,6 +1224,39 @@ void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnno } } +VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) { + VoiceAssistantConfigurationResponse resp; + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return resp; + } + + auto &config = voice_assistant::global_voice_assistant->get_configuration(); + for (auto &wake_word : config.available_wake_words) { + VoiceAssistantWakeWord resp_wake_word; + resp_wake_word.id = wake_word.id; + resp_wake_word.wake_word = wake_word.wake_word; + for (const auto &lang : wake_word.trained_languages) { + resp_wake_word.trained_languages.push_back(lang); + } + resp.available_wake_words.push_back(std::move(resp_wake_word)); + } + resp.max_active_wake_words = config.max_active_wake_words; + } + return resp; +} + +void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + if (voice_assistant::global_voice_assistant->get_api_connection() != this) { + return; + } + + voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words); + } +} + #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index e8d66a5e07..f176cf7c56 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -152,6 +152,9 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override; + VoiceAssistantConfigurationResponse voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) override; + void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override; #endif #ifdef USE_ALARM_CONTROL_PANEL diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 791de29511..8df152881c 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -7124,18 +7124,12 @@ void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { out.append("}"); } #endif -bool VoiceAssistantWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { - switch (field_id) { - case 1: { - this->id = value.as_uint32(); - return true; - } - default: - return false; - } -} bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { + case 1: { + this->id = value.as_string(); + return true; + } case 2: { this->wake_word = value.as_string(); return true; @@ -7149,7 +7143,7 @@ bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimit } } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const { - buffer.encode_uint32(1, this->id); + buffer.encode_string(1, this->id); buffer.encode_string(2, this->wake_word); for (auto &it : this->trained_languages) { buffer.encode_string(3, it, true); @@ -7160,8 +7154,7 @@ void VoiceAssistantWakeWord::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantWakeWord {\n"); out.append(" id: "); - sprintf(buffer, "%" PRIu32, this->id); - out.append(buffer); + out.append("'").append(this->id).append("'"); out.append("\n"); out.append(" wake_word: "); @@ -7184,10 +7177,6 @@ void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { #endif bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { - case 2: { - this->active_wake_words.push_back(value.as_uint32()); - return true; - } case 3: { this->max_active_wake_words = value.as_uint32(); return true; @@ -7202,6 +7191,10 @@ bool VoiceAssistantConfigurationResponse::decode_length(uint32_t field_id, Proto this->available_wake_words.push_back(value.as_message()); return true; } + case 2: { + this->active_wake_words.push_back(value.as_string()); + return true; + } default: return false; } @@ -7211,7 +7204,7 @@ void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const buffer.encode_message(1, it, true); } for (auto &it : this->active_wake_words) { - buffer.encode_uint32(2, it, true); + buffer.encode_string(2, it, true); } buffer.encode_uint32(3, this->max_active_wake_words); } @@ -7227,8 +7220,7 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - sprintf(buffer, "%" PRIu32, it); - out.append(buffer); + out.append("'").append(it).append("'"); out.append("\n"); } @@ -7239,10 +7231,10 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { out.append("}"); } #endif -bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarInt value) { +bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { - this->active_wake_words.push_back(value.as_uint32()); + this->active_wake_words.push_back(value.as_string()); return true; } default: @@ -7251,7 +7243,7 @@ bool VoiceAssistantSetConfiguration::decode_varint(uint32_t field_id, ProtoVarIn } void VoiceAssistantSetConfiguration::encode(ProtoWriteBuffer buffer) const { for (auto &it : this->active_wake_words) { - buffer.encode_uint32(1, it, true); + buffer.encode_string(1, it, true); } } #ifdef HAS_PROTO_MESSAGE_DUMP @@ -7260,8 +7252,7 @@ void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { out.append("VoiceAssistantSetConfiguration {\n"); for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - sprintf(buffer, "%" PRIu32, it); - out.append(buffer); + out.append("'").append(it).append("'"); out.append("\n"); } out.append("}"); diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 8631884f94..063c217bf7 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1851,7 +1851,7 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage { }; class VoiceAssistantWakeWord : public ProtoMessage { public: - uint32_t id{0}; + std::string id{}; std::string wake_word{}; std::vector trained_languages{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1861,7 +1861,6 @@ class VoiceAssistantWakeWord : public ProtoMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; - bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class VoiceAssistantConfigurationRequest : public ProtoMessage { public: @@ -1875,7 +1874,7 @@ class VoiceAssistantConfigurationRequest : public ProtoMessage { class VoiceAssistantConfigurationResponse : public ProtoMessage { public: std::vector available_wake_words{}; - std::vector active_wake_words{}; + std::vector active_wake_words{}; uint32_t max_active_wake_words{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1888,14 +1887,14 @@ class VoiceAssistantConfigurationResponse : public ProtoMessage { }; class VoiceAssistantSetConfiguration : public ProtoMessage { public: - std::vector active_wake_words{}; + std::vector active_wake_words{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; #endif protected: - bool decode_varint(uint32_t field_id, ProtoVarInt value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 454f20d50a..6e11d7169d 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -1681,6 +1681,35 @@ void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVo this->subscribe_voice_assistant(msg); } #endif +#ifdef USE_VOICE_ASSISTANT +void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); + if (!this->send_voice_assistant_configuration_response(ret)) { + this->on_fatal_error(); + } +} +#endif +#ifdef USE_VOICE_ASSISTANT +void APIServerConnection::on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->voice_assistant_set_configuration(msg); +} +#endif #ifdef USE_ALARM_CONTROL_PANEL void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { if (!this->is_connection_setup()) { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index e69954f7ab..51b94bf530 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -434,6 +434,13 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_VOICE_ASSISTANT virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; #endif +#ifdef USE_VOICE_ASSISTANT + virtual VoiceAssistantConfigurationResponse voice_assistant_get_configuration( + const VoiceAssistantConfigurationRequest &msg) = 0; +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) = 0; +#endif #ifdef USE_ALARM_CONTROL_PANEL virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0; #endif @@ -535,6 +542,12 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_VOICE_ASSISTANT void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override; #endif +#ifdef USE_VOICE_ASSISTANT + void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) override; +#endif +#ifdef USE_VOICE_ASSISTANT + void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override; +#endif #ifdef USE_ALARM_CONTROL_PANEL void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override; #endif diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index b0a172332f..56ada0e75a 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -77,6 +77,18 @@ struct Timer { } }; +struct WakeWord { + std::string id; + std::string wake_word; + std::vector trained_languages; +}; + +struct Configuration { + std::vector available_wake_words; + std::vector active_wake_words; + uint32_t max_active_wake_words; +}; + class VoiceAssistant : public Component { public: void setup() override; @@ -133,6 +145,8 @@ class VoiceAssistant : public Component { void on_audio(const api::VoiceAssistantAudio &msg); void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg); void on_announce(const api::VoiceAssistantAnnounceRequest &msg); + void on_set_configuration(const std::vector &active_wake_words){}; + const Configuration &get_configuration() { return this->config_; }; bool is_running() const { return this->state_ != State::IDLE; } void set_continuous(bool continuous) { this->continuous_ = continuous; } @@ -279,6 +293,8 @@ class VoiceAssistant : public Component { AudioMode audio_mode_{AUDIO_MODE_UDP}; bool udp_socket_running_{false}; bool start_udp_socket_(); + + Configuration config_{}; }; template class StartAction : public Action, public Parented { From a930b377b0cc7d6c2b60611fba7361cbbd8040e9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:57:27 +1200 Subject: [PATCH 2406/2607] Bump version to 2024.9.0b4 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 24deba1f15..929a6bea84 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0b3" +__version__ = "2024.9.0b4" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 34229af38abf12bb09bce8a58cb5820ed8e2fc36 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:56:07 +1200 Subject: [PATCH 2407/2607] Bump version to 2024.9.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 929a6bea84..8d5996a548 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0b4" +__version__ = "2024.9.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 969971930523fc7ed4e6cb61587115e91142c1dc Mon Sep 17 00:00:00 2001 From: Andrey Bodrov Date: Thu, 19 Sep 2024 07:07:39 +0300 Subject: [PATCH 2408/2607] openeth ethernet / qemu support (#7020) --- esphome/components/ethernet/__init__.py | 5 +++++ esphome/components/ethernet/ethernet_component.cpp | 13 +++++++++++++ esphome/components/ethernet/ethernet_component.h | 1 + tests/components/ethernet/common-openeth.yaml | 2 ++ .../components/ethernet/test-openeth.esp32-idf.yaml | 1 + 5 files changed, 22 insertions(+) create mode 100644 tests/components/ethernet/common-openeth.yaml create mode 100644 tests/components/ethernet/test-openeth.esp32-idf.yaml diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 1c6acda724..475d60df53 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -59,6 +59,7 @@ ETHERNET_TYPES = { "KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081, "KSZ8081RNA": EthernetType.ETHERNET_TYPE_KSZ8081RNA, "W5500": EthernetType.ETHERNET_TYPE_W5500, + "OPENETH": EthernetType.ETHERNET_TYPE_OPENETH, } SPI_ETHERNET_TYPES = ["W5500"] @@ -171,6 +172,7 @@ CONFIG_SCHEMA = cv.All( "KSZ8081": RMII_SCHEMA, "KSZ8081RNA": RMII_SCHEMA, "W5500": SPI_SCHEMA, + "OPENETH": BASE_SCHEMA, }, upper=True, ), @@ -240,6 +242,9 @@ async def to_code(config): if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True) add_idf_sdkconfig_option("CONFIG_ETH_SPI_ETHERNET_W5500", True) + elif config[CONF_TYPE] == "OPENETH": + cg.add_define("USE_ETHERNET_OPENETH") + add_idf_sdkconfig_option("CONFIG_ETH_USE_OPENETH", True) else: cg.add(var.set_phy_addr(config[CONF_PHY_ADDR])) cg.add(var.set_mdc_pin(config[CONF_MDC_PIN])) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index fdb6eb2da0..00c7ae4ab8 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -120,6 +120,8 @@ void EthernetComponent::setup() { phy_config.reset_gpio_num = this->reset_pin_; esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); +#elif defined(USE_ETHERNET_OPENETH) + esp_eth_mac_t *mac = esp_eth_mac_new_openeth(&mac_config); #else phy_config.phy_addr = this->phy_addr_; phy_config.reset_gpio_num = this->power_pin_; @@ -143,6 +145,13 @@ void EthernetComponent::setup() { #endif switch (this->type_) { +#ifdef USE_ETHERNET_OPENETH + case ETHERNET_TYPE_OPENETH: { + phy_config.autonego_timeout_ms = 1000; + this->phy_ = esp_eth_phy_new_dp83848(&phy_config); + break; + } +#endif #if CONFIG_ETH_USE_ESP32_EMAC case ETHERNET_TYPE_LAN8720: { this->phy_ = esp_eth_phy_new_lan87xx(&phy_config); @@ -302,6 +311,10 @@ void EthernetComponent::dump_config() { eth_type = "W5500"; break; + case ETHERNET_TYPE_OPENETH: + eth_type = "OPENETH"; + break; + default: eth_type = "Unknown"; break; diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index f0fe6cab87..5ee430c046 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -25,6 +25,7 @@ enum EthernetType { ETHERNET_TYPE_KSZ8081, ETHERNET_TYPE_KSZ8081RNA, ETHERNET_TYPE_W5500, + ETHERNET_TYPE_OPENETH, }; struct ManualIP { diff --git a/tests/components/ethernet/common-openeth.yaml b/tests/components/ethernet/common-openeth.yaml new file mode 100644 index 0000000000..fbb7579598 --- /dev/null +++ b/tests/components/ethernet/common-openeth.yaml @@ -0,0 +1,2 @@ +ethernet: + type: OPENETH diff --git a/tests/components/ethernet/test-openeth.esp32-idf.yaml b/tests/components/ethernet/test-openeth.esp32-idf.yaml new file mode 100644 index 0000000000..220316f3ee --- /dev/null +++ b/tests/components/ethernet/test-openeth.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common-openeth.yaml From d0dc275e3020a9f3e719f28e3f82c8e58743e03e Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Thu, 19 Sep 2024 06:08:15 +0200 Subject: [PATCH 2409/2607] [nextion] Optionally skip connection handshake (#6905) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/nextion/base_component.py | 1 + esphome/components/nextion/display.py | 4 ++++ esphome/components/nextion/nextion.cpp | 23 ++++++++++++++++---- esphome/components/nextion/nextion.h | 16 ++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/esphome/components/nextion/base_component.py b/esphome/components/nextion/base_component.py index d12434ec8f..2924f66d3c 100644 --- a/esphome/components/nextion/base_component.py +++ b/esphome/components/nextion/base_component.py @@ -27,6 +27,7 @@ CONF_BACKGROUND_PRESSED_COLOR = "background_pressed_color" CONF_FOREGROUND_PRESSED_COLOR = "foreground_pressed_color" CONF_FONT_ID = "font_id" CONF_EXIT_REPARSE_ON_START = "exit_reparse_on_start" +CONF_SKIP_CONNECTION_HANDSHAKE = "skip_connection_handshake" def NextionName(value): diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index ce45d25e7b..e403ba7ae8 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -23,6 +23,7 @@ from .base_component import ( CONF_START_UP_PAGE, CONF_AUTO_WAKE_ON_TOUCH, CONF_EXIT_REPARSE_ON_START, + CONF_SKIP_CONNECTION_HANDSHAKE, ) CODEOWNERS = ["@senexcrenshaw", "@edwardtfn"] @@ -72,6 +73,7 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_START_UP_PAGE): cv.uint8_t, cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean, cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean, + cv.Optional(CONF_SKIP_CONNECTION_HANDSHAKE, default=False): cv.boolean, } ) .extend(cv.polling_component_schema("5s")) @@ -118,6 +120,8 @@ async def to_code(config): cg.add(var.set_exit_reparse_on_start_internal(config[CONF_EXIT_REPARSE_ON_START])) + cg.add(var.set_skip_connection_handshake(config[CONF_SKIP_CONNECTION_HANDSHAKE])) + await display.register_display(var, config) for conf in config.get(CONF_ON_SETUP, []): diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index ddbd3328ef..a80f6efc91 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -43,6 +43,16 @@ bool Nextion::check_connect_() { if (this->get_is_connected_()) return true; + // Check if the handshake should be skipped for the Nextion connection + if (this->skip_connection_handshake_) { + // Log the connection status without handshake + ESP_LOGW(TAG, "Nextion display set as connected without performing handshake"); + // Set the connection status to true + this->is_connected_ = true; + // Return true indicating the connection is set + return true; + } + if (this->comok_sent_ == 0) { this->reset_(false); @@ -126,10 +136,14 @@ void Nextion::reset_(bool reset_nextion) { void Nextion::dump_config() { ESP_LOGCONFIG(TAG, "Nextion:"); - ESP_LOGCONFIG(TAG, " Device Model: %s", this->device_model_.c_str()); - ESP_LOGCONFIG(TAG, " Firmware Version: %s", this->firmware_version_.c_str()); - ESP_LOGCONFIG(TAG, " Serial Number: %s", this->serial_number_.c_str()); - ESP_LOGCONFIG(TAG, " Flash Size: %s", this->flash_size_.c_str()); + if (this->skip_connection_handshake_) { + ESP_LOGCONFIG(TAG, " Skip handshake: %s", YESNO(this->skip_connection_handshake_)); + } else { + ESP_LOGCONFIG(TAG, " Device Model: %s", this->device_model_.c_str()); + ESP_LOGCONFIG(TAG, " Firmware Version: %s", this->firmware_version_.c_str()); + ESP_LOGCONFIG(TAG, " Serial Number: %s", this->serial_number_.c_str()); + ESP_LOGCONFIG(TAG, " Flash Size: %s", this->flash_size_.c_str()); + } ESP_LOGCONFIG(TAG, " Wake On Touch: %s", YESNO(this->auto_wake_on_touch_)); ESP_LOGCONFIG(TAG, " Exit reparse: %s", YESNO(this->exit_reparse_on_start_)); @@ -262,6 +276,7 @@ void Nextion::loop() { this->goto_page(this->start_up_page_); } + // This could probably be removed from the loop area, as those are redundant. this->set_auto_wake_on_touch(this->auto_wake_on_touch_); this->set_exit_reparse_on_start(this->exit_reparse_on_start_); diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 4546baa4d8..732ee9b455 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -926,6 +926,21 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ void set_exit_reparse_on_start(bool exit_reparse); + /** + * Sets whether the Nextion display should skip the connection handshake process. + * @param skip_handshake True or false. When skip_connection_handshake is true, + * the connection will be established without performing the handshake. + * This can be useful when using Nextion Simulator. + * + * Example: + * ```cpp + * it.set_skip_connection_handshake(true); + * ``` + * + * When set to true, the display will be marked as connected without performing a handshake. + */ + void set_skip_connection_handshake(bool skip_handshake) { this->skip_connection_handshake_ = skip_handshake; } + /** * Sets Nextion mode between sleep and awake * @param True or false. Sleep=true to enter sleep mode or sleep=false to exit sleep mode. @@ -1221,6 +1236,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe int16_t start_up_page_ = -1; bool auto_wake_on_touch_ = true; bool exit_reparse_on_start_ = false; + bool skip_connection_handshake_ = false; /** * Manually send a raw command to the display and don't wait for an acknowledgement packet. From 446f7e0a7ea55e0c2b7a17088087df5063e0335c Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Thu, 19 Sep 2024 06:09:27 +0200 Subject: [PATCH 2410/2607] Haier climate integration update (#7416) Co-authored-by: Pavlo Dudnytskyi --- CODEOWNERS | 1 + esphome/components/haier/climate.py | 7 +- esphome/components/haier/haier_base.cpp | 77 ++++++-- esphome/components/haier/haier_base.h | 32 ++- esphome/components/haier/hon_climate.cpp | 187 ++++++++++++------ esphome/components/haier/hon_climate.h | 20 +- .../components/haier/smartair2_climate.cpp | 42 ++-- esphome/components/haier/switch/__init__.py | 91 +++++++++ esphome/components/haier/switch/beeper.cpp | 14 ++ esphome/components/haier/switch/beeper.h | 18 ++ esphome/components/haier/switch/display.cpp | 14 ++ esphome/components/haier/switch/display.h | 18 ++ .../components/haier/switch/health_mode.cpp | 14 ++ esphome/components/haier/switch/health_mode.h | 18 ++ .../components/haier/switch/quiet_mode.cpp | 14 ++ esphome/components/haier/switch/quiet_mode.h | 18 ++ tests/components/haier/common.yaml | 14 +- 17 files changed, 492 insertions(+), 107 deletions(-) create mode 100644 esphome/components/haier/switch/__init__.py create mode 100644 esphome/components/haier/switch/beeper.cpp create mode 100644 esphome/components/haier/switch/beeper.h create mode 100644 esphome/components/haier/switch/display.cpp create mode 100644 esphome/components/haier/switch/display.h create mode 100644 esphome/components/haier/switch/health_mode.cpp create mode 100644 esphome/components/haier/switch/health_mode.h create mode 100644 esphome/components/haier/switch/quiet_mode.cpp create mode 100644 esphome/components/haier/switch/quiet_mode.h diff --git a/CODEOWNERS b/CODEOWNERS index f7fbbf9374..c95a94c509 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -166,6 +166,7 @@ esphome/components/haier/* @paveldn esphome/components/haier/binary_sensor/* @paveldn esphome/components/haier/button/* @paveldn esphome/components/haier/sensor/* @paveldn +esphome/components/haier/switch/* @paveldn esphome/components/haier/text_sensor/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal esphome/components/hbridge/fan/* @WeekendWarrior diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index f7423a1356..f2dc7174cb 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -114,7 +114,6 @@ SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS = { SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS = { "AWAY": ClimatePreset.CLIMATE_PRESET_AWAY, "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, - "ECO": ClimatePreset.CLIMATE_PRESET_ECO, "SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP, } @@ -240,7 +239,9 @@ CONFIG_SCHEMA = cv.All( ): cv.ensure_list( cv.enum(SUPPORTED_HON_CONTROL_METHODS, upper=True) ), - cv.Optional(CONF_BEEPER, default=True): cv.boolean, + cv.Optional(CONF_BEEPER): cv.invalid( + f"The {CONF_BEEPER} option is deprecated, use beeper_on/beeper_off actions or beeper switch for a haier platform instead" + ), cv.Optional( CONF_CONTROL_PACKET_SIZE, default=PROTOCOL_CONTROL_PACKET_SIZE ): cv.int_range(min=PROTOCOL_CONTROL_PACKET_SIZE, max=50), @@ -254,7 +255,7 @@ CONFIG_SCHEMA = cv.All( ): cv.int_range(min=PROTOCOL_STATUS_MESSAGE_HEADER_SIZE), cv.Optional( CONF_SUPPORTED_PRESETS, - default=["BOOST", "ECO", "SLEEP"], # No AWAY by default + default=["BOOST", "SLEEP"], # No AWAY by default ): cv.ensure_list( cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True) ), diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index 0bd3863160..ba80c1ca1b 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -52,8 +52,6 @@ bool check_timeout(std::chrono::steady_clock::time_point now, std::chrono::stead HaierClimateBase::HaierClimateBase() : haier_protocol_(*this), protocol_phase_(ProtocolPhases::SENDING_INIT_1), - display_status_(true), - health_mode_(false), force_send_control_(false), forced_request_status_(false), reset_protocol_request_(false), @@ -127,21 +125,34 @@ haier_protocol::HaierMessage HaierClimateBase::get_wifi_signal_message_() { } #endif -bool HaierClimateBase::get_display_state() const { return this->display_status_; } - -void HaierClimateBase::set_display_state(bool state) { - if (this->display_status_ != state) { - this->display_status_ = state; - this->force_send_control_ = true; +void HaierClimateBase::save_settings() { + HaierBaseSettings settings{this->get_health_mode(), this->get_display_state()}; + if (!this->base_rtc_.save(&settings)) { + ESP_LOGW(TAG, "Failed to save settings"); } } -bool HaierClimateBase::get_health_mode() const { return this->health_mode_; } +bool HaierClimateBase::get_display_state() const { + return (this->display_status_ == SwitchState::ON) || (this->display_status_ == SwitchState::PENDING_ON); +} + +void HaierClimateBase::set_display_state(bool state) { + if (state != this->get_display_state()) { + this->display_status_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + this->force_send_control_ = true; + this->save_settings(); + } +} + +bool HaierClimateBase::get_health_mode() const { + return (this->health_mode_ == SwitchState::ON) || (this->health_mode_ == SwitchState::PENDING_ON); +} void HaierClimateBase::set_health_mode(bool state) { - if (this->health_mode_ != state) { - this->health_mode_ = state; + if (state != this->get_health_mode()) { + this->health_mode_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; this->force_send_control_ = true; + this->save_settings(); } } @@ -287,6 +298,14 @@ void HaierClimateBase::loop() { } this->process_phase(now); this->haier_protocol_.loop(); +#ifdef USE_SWITCH + if ((this->display_switch_ != nullptr) && (this->display_switch_->state != this->get_display_state())) { + this->display_switch_->publish_state(this->get_display_state()); + } + if ((this->health_mode_switch_ != nullptr) && (this->health_mode_switch_->state != this->get_health_mode())) { + this->health_mode_switch_->publish_state(this->get_health_mode()); + } +#endif // USE_SWITCH } void HaierClimateBase::process_protocol_reset() { @@ -329,6 +348,26 @@ bool HaierClimateBase::prepare_pending_action() { ClimateTraits HaierClimateBase::traits() { return traits_; } +void HaierClimateBase::initialization() { + constexpr uint32_t restore_settings_version = 0xA77D21EF; + this->base_rtc_ = + global_preferences->make_preference(this->get_object_id_hash() ^ restore_settings_version); + HaierBaseSettings recovered; + if (!this->base_rtc_.load(&recovered)) { + recovered = {false, true}; + } + this->display_status_ = recovered.display_state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + this->health_mode_ = recovered.health_mode ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; +#ifdef USE_SWITCH + if (this->display_switch_ != nullptr) { + this->display_switch_->publish_state(this->get_display_state()); + } + if (this->health_mode_switch_ != nullptr) { + this->health_mode_switch_->publish_state(this->get_health_mode()); + } +#endif +} + void HaierClimateBase::control(const ClimateCall &call) { ESP_LOGD("Control", "Control call"); if (!this->valid_connection()) { @@ -353,6 +392,22 @@ void HaierClimateBase::control(const ClimateCall &call) { } } +#ifdef USE_SWITCH +void HaierClimateBase::set_display_switch(switch_::Switch *sw) { + this->display_switch_ = sw; + if ((this->display_switch_ != nullptr) && (this->valid_connection())) { + this->display_switch_->publish_state(this->get_display_state()); + } +} + +void HaierClimateBase::set_health_mode_switch(switch_::Switch *sw) { + this->health_mode_switch_ = sw; + if ((this->health_mode_switch_ != nullptr) && (this->valid_connection())) { + this->health_mode_switch_->publish_state(this->get_health_mode()); + } +} +#endif + void HaierClimateBase::HvacSettings::reset() { this->valid = false; this->mode.reset(); diff --git a/esphome/components/haier/haier_base.h b/esphome/components/haier/haier_base.h index 7d92a6611c..f0597c49ff 100644 --- a/esphome/components/haier/haier_base.h +++ b/esphome/components/haier/haier_base.h @@ -8,6 +8,10 @@ // HaierProtocol #include +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif + namespace esphome { namespace haier { @@ -20,10 +24,24 @@ enum class ActionRequest : uint8_t { START_STERI_CLEAN = 5, // only hOn }; +struct HaierBaseSettings { + bool health_mode; + bool display_state; +}; + class HaierClimateBase : public esphome::Component, public esphome::climate::Climate, public esphome::uart::UARTDevice, public haier_protocol::ProtocolStream { +#ifdef USE_SWITCH + public: + void set_display_switch(switch_::Switch *sw); + void set_health_mode_switch(switch_::Switch *sw); + + protected: + switch_::Switch *display_switch_{nullptr}; + switch_::Switch *health_mode_switch_{nullptr}; +#endif public: HaierClimateBase(); HaierClimateBase(const HaierClimateBase &) = delete; @@ -82,7 +100,8 @@ class HaierClimateBase : public esphome::Component, virtual void process_phase(std::chrono::steady_clock::time_point now) = 0; virtual haier_protocol::HaierMessage get_control_message() = 0; // NOLINT(readability-identifier-naming) virtual haier_protocol::HaierMessage get_power_message(bool state) = 0; // NOLINT(readability-identifier-naming) - virtual void initialization(){}; + virtual void save_settings(); + virtual void initialization(); virtual bool prepare_pending_action(); virtual void process_protocol_reset(); esphome::climate::ClimateTraits traits() override; @@ -127,13 +146,19 @@ class HaierClimateBase : public esphome::Component, ActionRequest action; esphome::optional message; }; + enum class SwitchState { + OFF = 0b00, + ON = 0b01, + PENDING_OFF = 0b10, + PENDING_ON = 0b11, + }; haier_protocol::ProtocolHandler haier_protocol_; ProtocolPhases protocol_phase_; esphome::optional action_request_; uint8_t fan_mode_speed_; uint8_t other_modes_fan_speed_; - bool display_status_; - bool health_mode_; + SwitchState display_status_{SwitchState::ON}; + SwitchState health_mode_{SwitchState::OFF}; bool force_send_control_; bool forced_request_status_; bool reset_protocol_request_; @@ -148,6 +173,7 @@ class HaierClimateBase : public esphome::Component, std::chrono::steady_clock::time_point last_status_request_; // To request AC status std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level CallbackManager status_message_callback_{}; + ESPPreferenceObject base_rtc_; }; class StatusMessageTrigger : public Trigger { diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index a1c5098cec..e7be1fa418 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -31,9 +31,32 @@ HonClimate::HonClimate() HonClimate::~HonClimate() {} -void HonClimate::set_beeper_state(bool state) { this->beeper_status_ = state; } +void HonClimate::set_beeper_state(bool state) { + if (state != this->settings_.beeper_state) { + this->settings_.beeper_state = state; +#ifdef USE_SWITCH + this->beeper_switch_->publish_state(state); +#endif + this->hon_rtc_.save(&this->settings_); + } +} -bool HonClimate::get_beeper_state() const { return this->beeper_status_; } +bool HonClimate::get_beeper_state() const { return this->settings_.beeper_state; } + +void HonClimate::set_quiet_mode_state(bool state) { + if (state != this->get_quiet_mode_state()) { + this->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + this->settings_.quiet_mode_state = state; +#ifdef USE_SWITCH + this->quiet_mode_switch_->publish_state(state); +#endif + this->hon_rtc_.save(&this->settings_); + } +} + +bool HonClimate::get_quiet_mode_state() const { + return (this->quiet_mode_state_ == SwitchState::ON) || (this->quiet_mode_state_ == SwitchState::PENDING_ON); +} esphome::optional HonClimate::get_vertical_airflow() const { return this->current_vertical_swing_; @@ -474,16 +497,19 @@ haier_protocol::HaierMessage HonClimate::get_power_message(bool state) { } void HonClimate::initialization() { - constexpr uint32_t restore_settings_version = 0xE834D8DCUL; - this->rtc_ = global_preferences->make_preference(this->get_object_id_hash() ^ restore_settings_version); + HaierClimateBase::initialization(); + constexpr uint32_t restore_settings_version = 0x57EB59DDUL; + this->hon_rtc_ = + global_preferences->make_preference(this->get_object_id_hash() ^ restore_settings_version); HonSettings recovered; - if (this->rtc_.load(&recovered)) { + if (this->hon_rtc_.load(&recovered)) { this->settings_ = recovered; } else { - this->settings_ = {hon_protocol::VerticalSwingMode::CENTER, hon_protocol::HorizontalSwingMode::CENTER}; + this->settings_ = {hon_protocol::VerticalSwingMode::CENTER, hon_protocol::HorizontalSwingMode::CENTER, true, false}; } this->current_vertical_swing_ = this->settings_.last_vertiacal_swing; this->current_horizontal_swing_ = this->settings_.last_horizontal_swing; + this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; } haier_protocol::HaierMessage HonClimate::get_control_message() { @@ -519,8 +545,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { out_data->ac_power = 1; out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::FAN; out_data->fan_mode = this->fan_mode_speed_; // Auto doesn't work in fan only mode - // Disabling boost and eco mode for Fan only - out_data->quiet_mode = 0; + // Disabling boost for Fan only out_data->fast_mode = 0; break; case CLIMATE_MODE_COOL: @@ -582,47 +607,34 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { } if (out_data->ac_power == 0) { // If AC is off - no presets allowed - out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; } else if (climate_control.preset.has_value()) { switch (climate_control.preset.value()) { case CLIMATE_PRESET_NONE: - out_data->quiet_mode = 0; - out_data->fast_mode = 0; - out_data->sleep_mode = 0; - out_data->ten_degree = 0; - break; - case CLIMATE_PRESET_ECO: - // Eco is not supported in Fan only mode - out_data->quiet_mode = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 1 : 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; out_data->ten_degree = 0; break; case CLIMATE_PRESET_BOOST: - out_data->quiet_mode = 0; // Boost is not supported in Fan only mode out_data->fast_mode = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 1 : 0; out_data->sleep_mode = 0; out_data->ten_degree = 0; break; case CLIMATE_PRESET_AWAY: - out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; // 10 degrees allowed only in heat mode out_data->ten_degree = (this->mode == CLIMATE_MODE_HEAT) ? 1 : 0; break; case CLIMATE_PRESET_SLEEP: - out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 1; out_data->ten_degree = 0; break; default: ESP_LOGE("Control", "Unsupported preset"); - out_data->quiet_mode = 0; out_data->fast_mode = 0; out_data->sleep_mode = 0; out_data->ten_degree = 0; @@ -638,10 +650,23 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { out_data->horizontal_swing_mode = (uint8_t) this->pending_horizontal_direction_.value(); this->pending_horizontal_direction_.reset(); } - out_data->beeper_status = ((!this->beeper_status_) || (!has_hvac_settings)) ? 1 : 0; + { + // Quiet mode + if ((out_data->ac_power == 0) || (out_data->ac_mode == (uint8_t) hon_protocol::ConditioningMode::FAN)) { + // If AC is off or in fan only mode - no quiet mode allowed + out_data->quiet_mode = 0; + } else { + out_data->quiet_mode = this->get_quiet_mode_state() ? 1 : 0; + } + // Clean quiet mode state pending flag + this->quiet_mode_state_ = (SwitchState) ((uint8_t) this->quiet_mode_state_ & 0b01); + } + out_data->beeper_status = ((!this->get_beeper_state()) || (!has_hvac_settings)) ? 1 : 0; control_out_buffer[4] = 0; // This byte should be cleared before setting values - out_data->display_status = this->display_status_ ? 1 : 0; - out_data->health_mode = this->health_mode_ ? 1 : 0; + out_data->display_status = this->get_display_state() ? 1 : 0; + this->display_status_ = (SwitchState) ((uint8_t) this->display_status_ & 0b01); + out_data->health_mode = this->get_health_mode() ? 1 : 0; + this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01); return haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS, control_out_buffer, this->real_control_packet_size_); @@ -765,6 +790,22 @@ void HonClimate::update_sub_text_sensor_(SubTextSensorType type, const std::stri } #endif // USE_TEXT_SENSOR +#ifdef USE_SWITCH +void HonClimate::set_beeper_switch(switch_::Switch *sw) { + this->beeper_switch_ = sw; + if (this->beeper_switch_ != nullptr) { + this->beeper_switch_->publish_state(this->get_beeper_state()); + } +} + +void HonClimate::set_quiet_mode_switch(switch_::Switch *sw) { + this->quiet_mode_switch_ = sw; + if (this->quiet_mode_switch_ != nullptr) { + this->quiet_mode_switch_->publish_state(this->settings_.quiet_mode_state); + } +} +#endif // USE_SWITCH + haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { size_t expected_size = 2 + this->status_message_header_size_ + this->real_control_packet_size_ + this->real_sensors_packet_size_; @@ -827,9 +868,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * { // Extra modes/presets optional old_preset = this->preset; - if (packet.control.quiet_mode != 0) { - this->preset = CLIMATE_PRESET_ECO; - } else if (packet.control.fast_mode != 0) { + if (packet.control.fast_mode != 0) { this->preset = CLIMATE_PRESET_BOOST; } else if (packet.control.sleep_mode != 0) { this->preset = CLIMATE_PRESET_SLEEP; @@ -883,28 +922,26 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * } should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value()); } - { - // Display status - // should be before "Climate mode" because it is changing this->mode - if (packet.control.ac_power != 0) { - // if AC is off display status always ON so process it only when AC is on - bool disp_status = packet.control.display_status != 0; - if (disp_status != this->display_status_) { - // Do something only if display status changed - if (this->mode == CLIMATE_MODE_OFF) { - // AC just turned on from remote need to turn off display - this->force_send_control_ = true; - } else { - this->display_status_ = disp_status; - } + // Display status + // should be before "Climate mode" because it is changing this->mode + if (packet.control.ac_power != 0) { + // if AC is off display status always ON so process it only when AC is on + bool disp_status = packet.control.display_status != 0; + if (disp_status != this->get_display_state()) { + // Do something only if display status changed + if (this->mode == CLIMATE_MODE_OFF) { + // AC just turned on from remote need to turn off display + this->force_send_control_ = true; + } else if ((((uint8_t) this->health_mode_) & 0b10) == 0) { + this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF; } } } - { - // Health mode - bool old_health_mode = this->health_mode_; - this->health_mode_ = packet.control.health_mode == 1; - should_publish = should_publish || (old_health_mode != this->health_mode_); + // Health mode + if ((((uint8_t) this->health_mode_) & 0b10) == 0) { + bool old_health_mode = this->get_health_mode(); + this->health_mode_ = packet.control.health_mode == 1 ? SwitchState::ON : SwitchState::OFF; + should_publish = should_publish || (old_health_mode != this->get_health_mode()); } { CleaningState new_cleaning; @@ -958,17 +995,36 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * } should_publish = should_publish || (old_mode != this->mode); } + { + // Quiet mode, should be after climate mode + if ((this->mode != CLIMATE_MODE_FAN_ONLY) && (this->mode != CLIMATE_MODE_OFF) && + ((((uint8_t) this->quiet_mode_state_) & 0b10) == 0)) { + // In proper mode and not in pending state + bool new_quiet_mode = packet.control.quiet_mode != 0; + if (new_quiet_mode != this->get_quiet_mode_state()) { + this->quiet_mode_state_ = new_quiet_mode ? SwitchState::ON : SwitchState::OFF; + this->settings_.quiet_mode_state = new_quiet_mode; + this->hon_rtc_.save(&this->settings_); + } + } + } { // Swing mode ClimateSwingMode old_swing_mode = this->swing_mode; - if (packet.control.horizontal_swing_mode == (uint8_t) hon_protocol::HorizontalSwingMode::AUTO) { - if (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO) { + const std::set &swing_modes = traits_.get_supported_swing_modes(); + bool vertical_swing_supported = swing_modes.find(CLIMATE_SWING_VERTICAL) != swing_modes.end(); + bool horizontal_swing_supported = swing_modes.find(CLIMATE_SWING_HORIZONTAL) != swing_modes.end(); + if (horizontal_swing_supported && + (packet.control.horizontal_swing_mode == (uint8_t) hon_protocol::HorizontalSwingMode::AUTO)) { + if (vertical_swing_supported && + (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO)) { this->swing_mode = CLIMATE_SWING_BOTH; } else { this->swing_mode = CLIMATE_SWING_HORIZONTAL; } } else { - if (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO) { + if (vertical_swing_supported && + (packet.control.vertical_swing_mode == (uint8_t) hon_protocol::VerticalSwingMode::AUTO)) { this->swing_mode = CLIMATE_SWING_VERTICAL; } else { this->swing_mode = CLIMATE_SWING_OFF; @@ -985,7 +1041,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * if (save_settings) { this->settings_.last_vertiacal_swing = this->current_vertical_swing_.value(); this->settings_.last_horizontal_swing = this->current_horizontal_swing_.value(); - this->rtc_.save(&this->settings_); + this->hon_rtc_.save(&this->settings_); } should_publish = should_publish || (old_swing_mode != this->swing_mode); } @@ -1017,7 +1073,7 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::BEEPER_STATUS, - this->beeper_status_ ? ZERO_BUF : ONE_BUF, 2)); + this->get_beeper_state() ? ZERO_BUF : ONE_BUF, 2)); } // Health mode { @@ -1025,13 +1081,16 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::HEALTH_MODE, - this->health_mode_ ? ONE_BUF : ZERO_BUF, 2)); + this->get_health_mode() ? ONE_BUF : ZERO_BUF, 2)); + this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01); } // Climate mode + ClimateMode climate_mode = this->mode; bool new_power = this->mode != CLIMATE_MODE_OFF; uint8_t fan_mode_buf[] = {0x00, 0xFF}; uint8_t quiet_mode_buf[] = {0x00, 0xFF}; if (climate_control.mode.has_value()) { + climate_mode = climate_control.mode.value(); uint8_t buffer[2] = {0x00, 0x00}; switch (climate_control.mode.value()) { case CLIMATE_MODE_OFF: @@ -1076,8 +1135,6 @@ void HonClimate::fill_control_messages_queue_() { (uint8_t) hon_protocol::DataParameters::AC_MODE, buffer, 2)); fan_mode_buf[1] = this->other_modes_fan_speed_; // Auto doesn't work in fan only mode - // Disabling eco mode for Fan only - quiet_mode_buf[1] = 0; break; case CLIMATE_MODE_COOL: new_power = true; @@ -1108,30 +1165,20 @@ void HonClimate::fill_control_messages_queue_() { uint8_t away_mode_buf[] = {0x00, 0xFF}; if (!new_power) { // If AC is off - no presets allowed - quiet_mode_buf[1] = 0x00; fast_mode_buf[1] = 0x00; away_mode_buf[1] = 0x00; } else if (climate_control.preset.has_value()) { switch (climate_control.preset.value()) { case CLIMATE_PRESET_NONE: - quiet_mode_buf[1] = 0x00; - fast_mode_buf[1] = 0x00; - away_mode_buf[1] = 0x00; - break; - case CLIMATE_PRESET_ECO: - // Eco is not supported in Fan only mode - quiet_mode_buf[1] = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 0x01 : 0x00; fast_mode_buf[1] = 0x00; away_mode_buf[1] = 0x00; break; case CLIMATE_PRESET_BOOST: - quiet_mode_buf[1] = 0x00; // Boost is not supported in Fan only mode fast_mode_buf[1] = (this->mode != CLIMATE_MODE_FAN_ONLY) ? 0x01 : 0x00; away_mode_buf[1] = 0x00; break; case CLIMATE_PRESET_AWAY: - quiet_mode_buf[1] = 0x00; fast_mode_buf[1] = 0x00; away_mode_buf[1] = (this->mode == CLIMATE_MODE_HEAT) ? 0x01 : 0x00; break; @@ -1140,8 +1187,18 @@ void HonClimate::fill_control_messages_queue_() { break; } } + { + // Quiet mode + if (new_power && (climate_mode != CLIMATE_MODE_FAN_ONLY) && this->get_quiet_mode_state()) { + quiet_mode_buf[1] = 0x01; + } else { + quiet_mode_buf[1] = 0x00; + } + // Clean quiet mode state pending flag + this->quiet_mode_state_ = (SwitchState) ((uint8_t) this->quiet_mode_state_ & 0b01); + } auto presets = this->traits_.get_supported_presets(); - if ((quiet_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_ECO) != presets.end()))) { + if (quiet_mode_buf[1] != 0xFF) { this->control_messages_queue_.push( haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index 64c54186ed..58173f8154 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -10,6 +10,9 @@ #ifdef USE_TEXT_SENSOR #include "esphome/components/text_sensor/text_sensor.h" #endif +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif #include "esphome/core/automation.h" #include "haier_base.h" #include "hon_packet.h" @@ -28,6 +31,8 @@ enum class HonControlMethod { MONITOR_ONLY = 0, SET_GROUP_PARAMETERS, SET_SINGLE struct HonSettings { hon_protocol::VerticalSwingMode last_vertiacal_swing; hon_protocol::HorizontalSwingMode last_horizontal_swing; + bool beeper_state; + bool quiet_mode_state; }; class HonClimate : public HaierClimateBase { @@ -86,6 +91,15 @@ class HonClimate : public HaierClimateBase { protected: void update_sub_text_sensor_(SubTextSensorType type, const std::string &value); text_sensor::TextSensor *sub_text_sensors_[(size_t) SubTextSensorType::SUB_TEXT_SENSOR_TYPE_COUNT]{nullptr}; +#endif +#ifdef USE_SWITCH + public: + void set_beeper_switch(switch_::Switch *sw); + void set_quiet_mode_switch(switch_::Switch *sw); + + protected: + switch_::Switch *beeper_switch_{nullptr}; + switch_::Switch *quiet_mode_switch_{nullptr}; #endif public: HonClimate(); @@ -95,6 +109,8 @@ class HonClimate : public HaierClimateBase { void dump_config() override; void set_beeper_state(bool state); bool get_beeper_state() const; + void set_quiet_mode_state(bool state); + bool get_quiet_mode_state() const; esphome::optional get_vertical_airflow() const; void set_vertical_airflow(hon_protocol::VerticalSwingMode direction); esphome::optional get_horizontal_airflow() const; @@ -153,7 +169,6 @@ class HonClimate : public HaierClimateBase { bool functions_[5]; }; - bool beeper_status_; CleaningState cleaning_status_; bool got_valid_outdoor_temp_; esphome::optional pending_vertical_direction_{}; @@ -175,7 +190,8 @@ class HonClimate : public HaierClimateBase { esphome::optional current_vertical_swing_{}; esphome::optional current_horizontal_swing_{}; HonSettings settings_; - ESPPreferenceObject rtc_; + ESPPreferenceObject hon_rtc_; + SwitchState quiet_mode_state_{SwitchState::OFF}; }; class HaierAlarmStartTrigger : public Trigger { diff --git a/esphome/components/haier/smartair2_climate.cpp b/esphome/components/haier/smartair2_climate.cpp index 028e8a4087..63c22821b3 100644 --- a/esphome/components/haier/smartair2_climate.cpp +++ b/esphome/components/haier/smartair2_climate.cpp @@ -376,8 +376,10 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() { } } } - out_data->display_status = this->display_status_ ? 0 : 1; - out_data->health_mode = this->health_mode_ ? 1 : 0; + out_data->display_status = this->get_display_state() ? 0 : 1; + this->display_status_ = (SwitchState) ((uint8_t) this->display_status_ & 0b01); + out_data->health_mode = this->get_health_mode() ? 1 : 0; + this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01); return haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, 0x4D5F, control_out_buffer, sizeof(smartair2_protocol::HaierPacketControl)); } @@ -446,28 +448,26 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin } should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value()); } - { - // Display status - // should be before "Climate mode" because it is changing this->mode - if (packet.control.ac_power != 0) { - // if AC is off display status always ON so process it only when AC is on - bool disp_status = packet.control.display_status == 0; - if (disp_status != this->display_status_) { - // Do something only if display status changed - if (this->mode == CLIMATE_MODE_OFF) { - // AC just turned on from remote need to turn off display - this->force_send_control_ = true; - } else { - this->display_status_ = disp_status; - } + // Display status + // should be before "Climate mode" because it is changing this->mode + if (packet.control.ac_power != 0) { + // if AC is off display status always ON so process it only when AC is on + bool disp_status = packet.control.display_status == 0; + if (disp_status != this->get_display_state()) { + // Do something only if display status changed + if (this->mode == CLIMATE_MODE_OFF) { + // AC just turned on from remote need to turn off display + this->force_send_control_ = true; + } else if ((((uint8_t) this->health_mode_) & 0b10) == 0) { + this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF; } } } - { - // Health mode - bool old_health_mode = this->health_mode_; - this->health_mode_ = packet.control.health_mode == 1; - should_publish = should_publish || (old_health_mode != this->health_mode_); + // Health mode + if ((((uint8_t) this->health_mode_) & 0b10) == 0) { + bool old_health_mode = this->get_health_mode(); + this->health_mode_ = packet.control.health_mode == 1 ? SwitchState::ON : SwitchState::OFF; + should_publish = should_publish || (old_health_mode != this->get_health_mode()); } { // Climate mode diff --git a/esphome/components/haier/switch/__init__.py b/esphome/components/haier/switch/__init__.py new file mode 100644 index 0000000000..6076cb0bd5 --- /dev/null +++ b/esphome/components/haier/switch/__init__.py @@ -0,0 +1,91 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +import esphome.final_validate as fv +from esphome.components import switch +from esphome.const import ( + CONF_BEEPER, + CONF_DISPLAY, + ENTITY_CATEGORY_CONFIG, +) +from ..climate import ( + CONF_HAIER_ID, + CONF_PROTOCOL, + HaierClimateBase, + haier_ns, + PROTOCOL_HON, +) + +CODEOWNERS = ["@paveldn"] +BeeperSwitch = haier_ns.class_("BeeperSwitch", switch.Switch) +HealthModeSwitch = haier_ns.class_("HealthModeSwitch", switch.Switch) +DisplaySwitch = haier_ns.class_("DisplaySwitch", switch.Switch) +QuietModeSwitch = haier_ns.class_("QuietModeSwitch", switch.Switch) + +# Haier switches +CONF_HEALTH_MODE = "health_mode" +CONF_QUIET_MODE = "quiet_mode" + +# Additional icons +ICON_LEAF = "mdi:leaf" +ICON_LED_ON = "mdi:led-on" +ICON_VOLUME_HIGH = "mdi:volume-high" +ICON_VOLUME_OFF = "mdi:volume-off" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_HAIER_ID): cv.use_id(HaierClimateBase), + cv.Optional(CONF_DISPLAY): switch.switch_schema( + DisplaySwitch, + icon=ICON_LED_ON, + entity_category=ENTITY_CATEGORY_CONFIG, + default_restore_mode="DISABLED", + ), + cv.Optional(CONF_HEALTH_MODE): switch.switch_schema( + HealthModeSwitch, + icon=ICON_LEAF, + default_restore_mode="DISABLED", + ), + # Beeper switch is only supported for HonClimate + cv.Optional(CONF_BEEPER): switch.switch_schema( + BeeperSwitch, + icon=ICON_VOLUME_HIGH, + entity_category=ENTITY_CATEGORY_CONFIG, + default_restore_mode="DISABLED", + ), + # Quiet mode is only supported for HonClimate + cv.Optional(CONF_QUIET_MODE): switch.switch_schema( + QuietModeSwitch, + icon=ICON_VOLUME_OFF, + entity_category=ENTITY_CATEGORY_CONFIG, + default_restore_mode="DISABLED", + ), + } +) + + +def _final_validate(config): + full_config = fv.full_config.get() + for switch_type in [CONF_BEEPER, CONF_QUIET_MODE]: + # Check switches that are only supported for HonClimate + if config.get(switch_type): + climate_path = full_config.get_path_for_id(config[CONF_HAIER_ID])[:-1] + climate_conf = full_config.get_config_for_path(climate_path) + protocol_type = climate_conf.get(CONF_PROTOCOL) + if protocol_type.casefold() != PROTOCOL_HON.casefold(): + raise cv.Invalid( + f"{switch_type} switch is only supported for hon climate" + ) + return config + + +FINAL_VALIDATE_SCHEMA = _final_validate + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_HAIER_ID]) + + for switch_type in [CONF_DISPLAY, CONF_HEALTH_MODE, CONF_BEEPER, CONF_QUIET_MODE]: + if conf := config.get(switch_type): + sw_var = await switch.new_switch(conf) + await cg.register_parented(sw_var, parent) + cg.add(getattr(parent, f"set_{switch_type}_switch")(sw_var)) diff --git a/esphome/components/haier/switch/beeper.cpp b/esphome/components/haier/switch/beeper.cpp new file mode 100644 index 0000000000..1ce64d0848 --- /dev/null +++ b/esphome/components/haier/switch/beeper.cpp @@ -0,0 +1,14 @@ +#include "beeper.h" + +namespace esphome { +namespace haier { + +void BeeperSwitch::write_state(bool state) { + if (this->parent_->get_beeper_state() != state) { + this->parent_->set_beeper_state(state); + } + this->publish_state(state); +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/beeper.h b/esphome/components/haier/switch/beeper.h new file mode 100644 index 0000000000..7396a7a0dd --- /dev/null +++ b/esphome/components/haier/switch/beeper.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../hon_climate.h" + +namespace esphome { +namespace haier { + +class BeeperSwitch : public switch_::Switch, public Parented { + public: + BeeperSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/display.cpp b/esphome/components/haier/switch/display.cpp new file mode 100644 index 0000000000..5e24843dcf --- /dev/null +++ b/esphome/components/haier/switch/display.cpp @@ -0,0 +1,14 @@ +#include "display.h" + +namespace esphome { +namespace haier { + +void DisplaySwitch::write_state(bool state) { + if (this->parent_->get_display_state() != state) { + this->parent_->set_display_state(state); + } + this->publish_state(state); +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/display.h b/esphome/components/haier/switch/display.h new file mode 100644 index 0000000000..f93ccfcdb7 --- /dev/null +++ b/esphome/components/haier/switch/display.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../haier_base.h" + +namespace esphome { +namespace haier { + +class DisplaySwitch : public switch_::Switch, public Parented { + public: + DisplaySwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/health_mode.cpp b/esphome/components/haier/switch/health_mode.cpp new file mode 100644 index 0000000000..3715759bdd --- /dev/null +++ b/esphome/components/haier/switch/health_mode.cpp @@ -0,0 +1,14 @@ +#include "health_mode.h" + +namespace esphome { +namespace haier { + +void HealthModeSwitch::write_state(bool state) { + if (this->parent_->get_health_mode() != state) { + this->parent_->set_health_mode(state); + } + this->publish_state(state); +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/health_mode.h b/esphome/components/haier/switch/health_mode.h new file mode 100644 index 0000000000..cfd2aa2f22 --- /dev/null +++ b/esphome/components/haier/switch/health_mode.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../haier_base.h" + +namespace esphome { +namespace haier { + +class HealthModeSwitch : public switch_::Switch, public Parented { + public: + HealthModeSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/quiet_mode.cpp b/esphome/components/haier/switch/quiet_mode.cpp new file mode 100644 index 0000000000..056312b5f0 --- /dev/null +++ b/esphome/components/haier/switch/quiet_mode.cpp @@ -0,0 +1,14 @@ +#include "quiet_mode.h" + +namespace esphome { +namespace haier { + +void QuietModeSwitch::write_state(bool state) { + if (this->parent_->get_quiet_mode_state() != state) { + this->parent_->set_quiet_mode_state(state); + } + this->publish_state(state); +} + +} // namespace haier +} // namespace esphome diff --git a/esphome/components/haier/switch/quiet_mode.h b/esphome/components/haier/switch/quiet_mode.h new file mode 100644 index 0000000000..bad5289500 --- /dev/null +++ b/esphome/components/haier/switch/quiet_mode.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../hon_climate.h" + +namespace esphome { +namespace haier { + +class QuietModeSwitch : public switch_::Switch, public Parented { + public: + QuietModeSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace haier +} // namespace esphome diff --git a/tests/components/haier/common.yaml b/tests/components/haier/common.yaml index b8a23bac5a..368b88b69c 100644 --- a/tests/components/haier/common.yaml +++ b/tests/components/haier/common.yaml @@ -16,7 +16,6 @@ climate: name: Haier AC wifi_signal: true answer_timeout: 200ms - beeper: true visual: min_temperature: 16 °C max_temperature: 30 °C @@ -38,7 +37,6 @@ climate: supported_presets: - AWAY - BOOST - - ECO - SLEEP on_alarm_start: then: @@ -112,3 +110,15 @@ text_sensor: name: Haier cleaning status protocol_version: name: Haier protocol version + +switch: + - platform: haier + haier_id: haier_ac + beeper: + name: Haier beeper + display: + name: Haier display + health_mode: + name: Haier health mode + quiet_mode: + name: Haier quiet mode From ddde64a48dceb0cb407fb420f67fc99345534123 Mon Sep 17 00:00:00 2001 From: Pietro Date: Thu, 19 Sep 2024 06:16:39 +0200 Subject: [PATCH 2411/2607] Added i2s_comm_fmt parameter to i2s speaker component (#7449) Co-authored-by: PxPert --- .../components/i2s_audio/speaker/__init__.py | 19 +++++++++++++++++++ .../i2s_audio/speaker/i2s_audio_speaker.cpp | 2 +- .../i2s_audio/speaker/i2s_audio_speaker.h | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/speaker/__init__.py b/esphome/components/i2s_audio/speaker/__init__.py index 22a5af259d..bba886b39b 100644 --- a/esphome/components/i2s_audio/speaker/__init__.py +++ b/esphome/components/i2s_audio/speaker/__init__.py @@ -25,6 +25,7 @@ I2SAudioSpeaker = i2s_audio_ns.class_( CONF_DAC_TYPE = "dac_type" +CONF_I2S_COMM_FMT = "i2s_comm_fmt" i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") INTERNAL_DAC_OPTIONS = { @@ -33,6 +34,20 @@ INTERNAL_DAC_OPTIONS = { CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, } +i2s_comm_format_t = cg.global_ns.enum("i2s_comm_format_t") +I2C_COMM_FMT_OPTIONS = { + "stand_i2s": i2s_comm_format_t.I2S_COMM_FORMAT_STAND_I2S, + "stand_msb": i2s_comm_format_t.I2S_COMM_FORMAT_STAND_MSB, + "stand_pcm_short": i2s_comm_format_t.I2S_COMM_FORMAT_STAND_PCM_SHORT, + "stand_pcm_long": i2s_comm_format_t.I2S_COMM_FORMAT_STAND_PCM_LONG, + "stand_max": i2s_comm_format_t.I2S_COMM_FORMAT_STAND_MAX, + "i2s_msb": i2s_comm_format_t.I2S_COMM_FORMAT_I2S_MSB, + "i2s_lsb": i2s_comm_format_t.I2S_COMM_FORMAT_I2S_LSB, + "pcm": i2s_comm_format_t.I2S_COMM_FORMAT_PCM, + "pcm_short": i2s_comm_format_t.I2S_COMM_FORMAT_PCM_SHORT, + "pcm_long": i2s_comm_format_t.I2S_COMM_FORMAT_PCM_LONG, +} + NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] @@ -77,6 +92,9 @@ CONFIG_SCHEMA = cv.All( cv.Required( CONF_I2S_DOUT_PIN ): pins.internal_gpio_output_pin_number, + cv.Optional(CONF_I2S_COMM_FMT, default="stand_i2s"): cv.enum( + I2C_COMM_FMT_OPTIONS, lower=True + ), } ), }, @@ -96,4 +114,5 @@ async def to_code(config): cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL])) else: cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) + cg.add(var.set_i2s_comm_fmt(config[CONF_I2S_COMM_FMT])) cg.add(var.set_timeout(config[CONF_TIMEOUT])) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 4b427898a2..97c1d86c36 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -83,7 +83,7 @@ void I2SAudioSpeaker::player_task(void *params) { .sample_rate = this_speaker->sample_rate_, .bits_per_sample = this_speaker->bits_per_sample_, .channel_format = this_speaker->channel_, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .communication_format = this_speaker->i2s_comm_fmt_, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 256, diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 7adc4e8a24..9d1817c86f 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -49,6 +49,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp #if SOC_I2S_SUPPORTS_DAC void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } #endif + void set_i2s_comm_fmt(i2s_comm_format_t mode) { this->i2s_comm_fmt_ = mode; } void start() override; void stop() override; @@ -76,6 +77,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp #if SOC_I2S_SUPPORTS_DAC i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE}; #endif + i2s_comm_format_t i2s_comm_fmt_; }; } // namespace i2s_audio From 6d24e9ebb5de546f529c7cf981718a1368e5d023 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:17:04 +1000 Subject: [PATCH 2412/2607] [lvgl] Enhancements (#7453) --- esphome/components/lvgl/__init__.py | 17 ++- esphome/components/lvgl/hello_world.py | 64 +++++++++ esphome/components/lvgl/lv_validation.py | 157 ++++++++++++++++++++++- tests/components/lvgl/lvgl-package.yaml | 4 +- tests/components/lvgl/test.host.yaml | 11 ++ 5 files changed, 246 insertions(+), 7 deletions(-) create mode 100644 esphome/components/lvgl/hello_world.py create mode 100644 tests/components/lvgl/test.host.yaml diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 64f254cde8..a3a6f7ddaf 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -22,9 +22,10 @@ from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid from .automation import disp_update, focused_widgets, update_to_code -from .defines import add_define +from .defines import CONF_WIDGETS, add_define from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code from .gradient import GRADIENT_SCHEMA, gradients_to_code +from .hello_world import get_hello_world from .lv_validation import lv_bool, lv_images_used from .lvcode import LvContext, LvglComponent from .schemas import ( @@ -32,7 +33,7 @@ from .schemas import ( FLEX_OBJ_SCHEMA, GRID_CELL_SCHEMA, LAYOUT_SCHEMAS, - STYLE_SCHEMA, + STATE_SCHEMA, WIDGET_TYPES, any_widget_schema, container_schema, @@ -292,6 +293,13 @@ def display_schema(config): return value or [cv.use_id(Display)(config)] +def add_hello_world(config): + if CONF_WIDGETS not in config and CONF_PAGES not in config: + LOGGER.info("No pages or widgets configured, creating default hello_world page") + config[CONF_WIDGETS] = cv.ensure_list(WIDGET_SCHEMA)(get_hello_world()) + return config + + FINAL_VALIDATE_SCHEMA = final_validation CONFIG_SCHEMA = ( @@ -313,7 +321,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(df.CONF_STYLE_DEFINITIONS): cv.ensure_list( cv.Schema({cv.Required(CONF_ID): cv.declare_id(lv_style_t)}) - .extend(STYLE_SCHEMA) + .extend(STATE_SCHEMA) .extend( { cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, @@ -349,4 +357,5 @@ CONFIG_SCHEMA = ( } ) .extend(DISP_BG_SCHEMA) -).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) + .add_extra(add_hello_world) +) diff --git a/esphome/components/lvgl/hello_world.py b/esphome/components/lvgl/hello_world.py new file mode 100644 index 0000000000..2c2ec6732c --- /dev/null +++ b/esphome/components/lvgl/hello_world.py @@ -0,0 +1,64 @@ +from io import StringIO + +from esphome.yaml_util import parse_yaml + +CONFIG = """ +- obj: + radius: 0 + pad_all: 12 + bg_color: 0xFFFFFF + height: 100% + width: 100% + widgets: + - spinner: + id: hello_world_spinner_ + align: center + indicator: + arc_color: tomato + height: 100 + width: 100 + spin_time: 2s + arc_length: 60deg + - label: + id: hello_world_label_ + text: "Hello World!" + align: center + on_click: + lvgl.spinner.update: + id: hello_world_spinner_ + arc_color: springgreen + - checkbox: + pad_all: 8 + text: Checkbox + align: top_right + on_click: + lvgl.label.update: + id: hello_world_label_ + text: "Checked!" + - button: + pad_all: 8 + checkable: true + align: top_left + text_font: montserrat_20 + on_click: + lvgl.label.update: + id: hello_world_label_ + text: "Clicked!" + widgets: + - label: + text: "Button" + - slider: + width: 80% + align: bottom_mid + on_value: + lvgl.label.update: + id: hello_world_label_ + text: + format: "%.0f%%" + args: [x] +""" + + +def get_hello_world(): + with StringIO(CONFIG) as fp: + return parse_yaml("hello_world", fp) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 8593deb869..3dee0189fb 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -49,17 +49,172 @@ def opacity_validator(value): opacity = LValidator(opacity_validator, uint32, retmapper=literal) +COLOR_NAMES = { + "aliceblue": 0xF0F8FF, + "antiquewhite": 0xFAEBD7, + "aqua": 0x00FFFF, + "aquamarine": 0x7FFFD4, + "azure": 0xF0FFFF, + "beige": 0xF5F5DC, + "bisque": 0xFFE4C4, + "black": 0x000000, + "blanchedalmond": 0xFFEBCD, + "blue": 0x0000FF, + "blueviolet": 0x8A2BE2, + "brown": 0xA52A2A, + "burlywood": 0xDEB887, + "cadetblue": 0x5F9EA0, + "chartreuse": 0x7FFF00, + "chocolate": 0xD2691E, + "coral": 0xFF7F50, + "cornflowerblue": 0x6495ED, + "cornsilk": 0xFFF8DC, + "crimson": 0xDC143C, + "cyan": 0x00FFFF, + "darkblue": 0x00008B, + "darkcyan": 0x008B8B, + "darkgoldenrod": 0xB8860B, + "darkgray": 0xA9A9A9, + "darkgreen": 0x006400, + "darkgrey": 0xA9A9A9, + "darkkhaki": 0xBDB76B, + "darkmagenta": 0x8B008B, + "darkolivegreen": 0x556B2F, + "darkorange": 0xFF8C00, + "darkorchid": 0x9932CC, + "darkred": 0x8B0000, + "darksalmon": 0xE9967A, + "darkseagreen": 0x8FBC8F, + "darkslateblue": 0x483D8B, + "darkslategray": 0x2F4F4F, + "darkslategrey": 0x2F4F4F, + "darkturquoise": 0x00CED1, + "darkviolet": 0x9400D3, + "deeppink": 0xFF1493, + "deepskyblue": 0x00BFFF, + "dimgray": 0x696969, + "dimgrey": 0x696969, + "dodgerblue": 0x1E90FF, + "firebrick": 0xB22222, + "floralwhite": 0xFFFAF0, + "forestgreen": 0x228B22, + "fuchsia": 0xFF00FF, + "gainsboro": 0xDCDCDC, + "ghostwhite": 0xF8F8FF, + "goldenrod": 0xDAA520, + "gold": 0xFFD700, + "gray": 0x808080, + "green": 0x008000, + "greenyellow": 0xADFF2F, + "grey": 0x808080, + "honeydew": 0xF0FFF0, + "hotpink": 0xFF69B4, + "indianred": 0xCD5C5C, + "indigo": 0x4B0082, + "ivory": 0xFFFFF0, + "khaki": 0xF0E68C, + "lavenderblush": 0xFFF0F5, + "lavender": 0xE6E6FA, + "lawngreen": 0x7CFC00, + "lemonchiffon": 0xFFFACD, + "lightblue": 0xADD8E6, + "lightcoral": 0xF08080, + "lightcyan": 0xE0FFFF, + "lightgoldenrodyellow": 0xFAFAD2, + "lightgray": 0xD3D3D3, + "lightgreen": 0x90EE90, + "lightgrey": 0xD3D3D3, + "lightpink": 0xFFB6C1, + "lightsalmon": 0xFFA07A, + "lightseagreen": 0x20B2AA, + "lightskyblue": 0x87CEFA, + "lightslategray": 0x778899, + "lightslategrey": 0x778899, + "lightsteelblue": 0xB0C4DE, + "lightyellow": 0xFFFFE0, + "lime": 0x00FF00, + "limegreen": 0x32CD32, + "linen": 0xFAF0E6, + "magenta": 0xFF00FF, + "maroon": 0x800000, + "mediumaquamarine": 0x66CDAA, + "mediumblue": 0x0000CD, + "mediumorchid": 0xBA55D3, + "mediumpurple": 0x9370DB, + "mediumseagreen": 0x3CB371, + "mediumslateblue": 0x7B68EE, + "mediumspringgreen": 0x00FA9A, + "mediumturquoise": 0x48D1CC, + "mediumvioletred": 0xC71585, + "midnightblue": 0x191970, + "mintcream": 0xF5FFFA, + "mistyrose": 0xFFE4E1, + "moccasin": 0xFFE4B5, + "navajowhite": 0xFFDEAD, + "navy": 0x000080, + "oldlace": 0xFDF5E6, + "olive": 0x808000, + "olivedrab": 0x6B8E23, + "orange": 0xFFA500, + "orangered": 0xFF4500, + "orchid": 0xDA70D6, + "palegoldenrod": 0xEEE8AA, + "palegreen": 0x98FB98, + "paleturquoise": 0xAFEEEE, + "palevioletred": 0xDB7093, + "papayawhip": 0xFFEFD5, + "peachpuff": 0xFFDAB9, + "peru": 0xCD853F, + "pink": 0xFFC0CB, + "plum": 0xDDA0DD, + "powderblue": 0xB0E0E6, + "purple": 0x800080, + "rebeccapurple": 0x663399, + "red": 0xFF0000, + "rosybrown": 0xBC8F8F, + "royalblue": 0x4169E1, + "saddlebrown": 0x8B4513, + "salmon": 0xFA8072, + "sandybrown": 0xF4A460, + "seagreen": 0x2E8B57, + "seashell": 0xFFF5EE, + "sienna": 0xA0522D, + "silver": 0xC0C0C0, + "skyblue": 0x87CEEB, + "slateblue": 0x6A5ACD, + "slategray": 0x708090, + "slategrey": 0x708090, + "snow": 0xFFFAFA, + "springgreen": 0x00FF7F, + "steelblue": 0x4682B4, + "tan": 0xD2B48C, + "teal": 0x008080, + "thistle": 0xD8BFD8, + "tomato": 0xFF6347, + "turquoise": 0x40E0D0, + "violet": 0xEE82EE, + "wheat": 0xF5DEB3, + "white": 0xFFFFFF, + "whitesmoke": 0xF5F5F5, + "yellow": 0xFFFF00, + "yellowgreen": 0x9ACD32, +} + @schema_extractor("one_of") def color(value): if value == SCHEMA_EXTRACT: return ["hex color value", "color ID"] - return cv.Any(cv.int_, cv.use_id(ColorStruct))(value) + return cv.Any(cv.int_, cv.one_of(*COLOR_NAMES, lower=True), cv.use_id(ColorStruct))( + value + ) def color_retmapper(value): if isinstance(value, cv.Lambda): return cv.returning_lambda(value) + if isinstance(value, str) and value in COLOR_NAMES: + value = COLOR_NAMES[value] if isinstance(value, int): return literal( f"lv_color_make({(value >> 16) & 0xFF}, {(value >> 8) & 0xFF}, {value & 0xFF})" diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 9d157ea5b0..a3ed3047be 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -38,8 +38,8 @@ lvgl: border_width: 0 radius: 0 pad_all: 0 - border_color: 0x0077b3 - text_color: 0xFFFFFF + border_color: tomato + text_color: springgreen width: 100% height: 30 border_side: [left, top] diff --git a/tests/components/lvgl/test.host.yaml b/tests/components/lvgl/test.host.yaml new file mode 100644 index 0000000000..3a490bbe15 --- /dev/null +++ b/tests/components/lvgl/test.host.yaml @@ -0,0 +1,11 @@ +display: + - platform: sdl + auto_clear_enabled: false + dimensions: + width: 480 + height: 480 + +touchscreen: + - platform: sdl + +lvgl: From fb7e7eb80b6e6ee3c3b871831b1d3e910bceb274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Obrembski?= Date: Thu, 19 Sep 2024 06:17:22 +0200 Subject: [PATCH 2413/2607] Add tca9555 GPIO driver (#7146) Co-authored-by: Michal Obrembski Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/gpio_expander/__init__.py | 0 .../components/gpio_expander/cached_gpio.h | 38 +++++ esphome/components/tca9555/__init__.py | 72 +++++++++ esphome/components/tca9555/tca9555.cpp | 140 ++++++++++++++++++ esphome/components/tca9555/tca9555.h | 64 ++++++++ tests/components/tca9555/test.esp32-ard.yaml | 27 ++++ .../components/tca9555/test.esp32-c3-ard.yaml | 27 ++++ .../components/tca9555/test.esp32-c3-idf.yaml | 27 ++++ tests/components/tca9555/test.esp32-idf.yaml | 27 ++++ .../components/tca9555/test.esp8266-ard.yaml | 27 ++++ tests/components/tca9555/test.rp2040-ard.yaml | 27 ++++ 12 files changed, 477 insertions(+) create mode 100644 esphome/components/gpio_expander/__init__.py create mode 100644 esphome/components/gpio_expander/cached_gpio.h create mode 100644 esphome/components/tca9555/__init__.py create mode 100644 esphome/components/tca9555/tca9555.cpp create mode 100644 esphome/components/tca9555/tca9555.h create mode 100644 tests/components/tca9555/test.esp32-ard.yaml create mode 100644 tests/components/tca9555/test.esp32-c3-ard.yaml create mode 100644 tests/components/tca9555/test.esp32-c3-idf.yaml create mode 100644 tests/components/tca9555/test.esp32-idf.yaml create mode 100644 tests/components/tca9555/test.esp8266-ard.yaml create mode 100644 tests/components/tca9555/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c95a94c509..a2fe77dc84 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -398,6 +398,7 @@ esphome/components/sun_gtil2/* @Mat931 esphome/components/switch/* @esphome/core esphome/components/t6615/* @tylermenezes esphome/components/tca9548a/* @andreashergert1984 +esphome/components/tca9555/* @mobrembski esphome/components/tcl112/* @glmnet esphome/components/tee501/* @Stock-M esphome/components/teleinfo/* @0hax diff --git a/esphome/components/gpio_expander/__init__.py b/esphome/components/gpio_expander/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/gpio_expander/cached_gpio.h b/esphome/components/gpio_expander/cached_gpio.h new file mode 100644 index 0000000000..784c5f0f4a --- /dev/null +++ b/esphome/components/gpio_expander/cached_gpio.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include "esphome/core/hal.h" + +namespace esphome { +namespace gpio_expander { + +/// @brief A class to cache the read state of a GPIO expander. +template class CachedGpioExpander { + public: + bool digital_read(T pin) { + if (!this->read_cache_invalidated_[pin]) { + this->read_cache_invalidated_[pin] = true; + return this->digital_read_cache(pin); + } + return this->digital_read_hw(pin); + } + + void digital_write(T pin, bool value) { this->digital_write_hw(pin, value); } + + protected: + virtual bool digital_read_hw(T pin) = 0; + virtual bool digital_read_cache(T pin) = 0; + virtual void digital_write_hw(T pin, bool value) = 0; + + void reset_pin_cache_() { + for (T i = 0; i < N; i++) { + this->read_cache_invalidated_[i] = false; + } + } + + std::array read_cache_invalidated_{}; +}; + +} // namespace gpio_expander +} // namespace esphome diff --git a/esphome/components/tca9555/__init__.py b/esphome/components/tca9555/__init__.py new file mode 100644 index 0000000000..db0451d4e6 --- /dev/null +++ b/esphome/components/tca9555/__init__.py @@ -0,0 +1,72 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import i2c +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, +) + +CODEOWNERS = ["@mobrembski"] + +AUTO_LOAD = ["gpio_expander"] +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + +tca9555_ns = cg.esphome_ns.namespace("tca9555") + +TCA9555Component = tca9555_ns.class_("TCA9555Component", cg.Component, i2c.I2CDevice) +TCA9555GPIOPin = tca9555_ns.class_("TCA9555GPIOPin", cg.GPIOPin) + +CONF_TCA9555 = "tca9555" +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(TCA9555Component), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x21)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +def validate_mode(value): + if not (value[CONF_INPUT] or value[CONF_OUTPUT]): + raise cv.Invalid("Mode must be either input or output") + if value[CONF_INPUT] and value[CONF_OUTPUT]: + raise cv.Invalid("Mode must be either input or output") + return value + + +TCA9555_PIN_SCHEMA = pins.gpio_base_schema( + TCA9555GPIOPin, + cv.int_range(min=0, max=15), + modes=[CONF_INPUT, CONF_OUTPUT], + mode_validator=validate_mode, + invertable=True, +).extend( + { + cv.Required(CONF_TCA9555): cv.use_id(TCA9555Component), + } +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_TCA9555, TCA9555_PIN_SCHEMA) +async def tca9555_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_parented(var, config[CONF_TCA9555]) + + cg.add(var.set_pin(config[CONF_NUMBER])) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/tca9555/tca9555.cpp b/esphome/components/tca9555/tca9555.cpp new file mode 100644 index 0000000000..cf0894427f --- /dev/null +++ b/esphome/components/tca9555/tca9555.cpp @@ -0,0 +1,140 @@ +#include "tca9555.h" +#include "esphome/core/log.h" + +static const uint8_t TCA9555_INPUT_PORT_REGISTER_0 = 0x00; +static const uint8_t TCA9555_INPUT_PORT_REGISTER_1 = 0x01; +static const uint8_t TCA9555_OUTPUT_PORT_REGISTER_0 = 0x02; +static const uint8_t TCA9555_OUTPUT_PORT_REGISTER_1 = 0x03; +static const uint8_t TCA9555_POLARITY_REGISTER_0 = 0x04; +static const uint8_t TCA9555_POLARITY_REGISTER_1 = 0x05; +static const uint8_t TCA9555_CONFIGURATION_PORT_0 = 0x06; +static const uint8_t TCA9555_CONFIGURATION_PORT_1 = 0x07; + +namespace esphome { +namespace tca9555 { + +static const char *const TAG = "tca9555"; + +void TCA9555Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up TCA9555..."); + if (!this->read_gpio_modes_()) { + this->mark_failed(); + return; + } + if (!this->read_gpio_outputs_()) { + this->mark_failed(); + return; + } +} +void TCA9555Component::dump_config() { + ESP_LOGCONFIG(TAG, "TCA9555:"); + LOG_I2C_DEVICE(this) + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with TCA9555 failed!"); + } +} +void TCA9555Component::pin_mode(uint8_t pin, gpio::Flags flags) { + if (flags == gpio::FLAG_INPUT) { + // Set mode mask bit + this->mode_mask_ |= 1 << pin; + } else if (flags == gpio::FLAG_OUTPUT) { + // Clear mode mask bit + this->mode_mask_ &= ~(1 << pin); + } + // Write GPIO to enable input mode + this->write_gpio_modes_(); +} +void TCA9555Component::loop() { this->reset_pin_cache_(); } + +bool TCA9555Component::read_gpio_outputs_() { + if (this->is_failed()) + return false; + uint8_t data[2]; + if (!this->read_bytes(TCA9555_OUTPUT_PORT_REGISTER_0, data, 2)) { + this->status_set_warning("Failed to read output register"); + return false; + } + this->output_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0); + this->status_clear_warning(); + return true; +} + +bool TCA9555Component::read_gpio_modes_() { + if (this->is_failed()) + return false; + uint8_t data[2]; + bool success = this->read_bytes(TCA9555_CONFIGURATION_PORT_0, data, 2); + if (!success) { + this->status_set_warning("Failed to read mode register"); + return false; + } + this->mode_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0); + + this->status_clear_warning(); + return true; +} +bool TCA9555Component::digital_read_hw(uint8_t pin) { + if (this->is_failed()) + return false; + bool success; + uint8_t data[2]; + success = this->read_bytes(TCA9555_INPUT_PORT_REGISTER_0, data, 2); + this->input_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0); + + if (!success) { + this->status_set_warning("Failed to read input register"); + return false; + } + + this->status_clear_warning(); + return true; +} + +void TCA9555Component::digital_write_hw(uint8_t pin, bool value) { + if (this->is_failed()) + return; + + if (value) { + this->output_mask_ |= (1 << pin); + } else { + this->output_mask_ &= ~(1 << pin); + } + + uint8_t data[2]; + data[0] = this->output_mask_; + data[1] = this->output_mask_ >> 8; + if (!this->write_bytes(TCA9555_OUTPUT_PORT_REGISTER_0, data, 2)) { + this->status_set_warning("Failed to write output register"); + return; + } + + this->status_clear_warning(); +} + +bool TCA9555Component::write_gpio_modes_() { + if (this->is_failed()) + return false; + uint8_t data[2]; + + data[0] = this->mode_mask_; + data[1] = this->mode_mask_ >> 8; + if (!this->write_bytes(TCA9555_CONFIGURATION_PORT_0, data, 2)) { + this->status_set_warning("Failed to write mode register"); + return false; + } + this->status_clear_warning(); + return true; +} + +bool TCA9555Component::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); } + +float TCA9555Component::get_setup_priority() const { return setup_priority::IO; } + +void TCA9555GPIOPin::setup() { this->pin_mode(this->flags_); } +void TCA9555GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } +bool TCA9555GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } +void TCA9555GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } +std::string TCA9555GPIOPin::dump_summary() const { return str_sprintf("%u via TCA9555", this->pin_); } + +} // namespace tca9555 +} // namespace esphome diff --git a/esphome/components/tca9555/tca9555.h b/esphome/components/tca9555/tca9555.h new file mode 100644 index 0000000000..ea464db043 --- /dev/null +++ b/esphome/components/tca9555/tca9555.h @@ -0,0 +1,64 @@ +#pragma once + +#include "esphome/components/gpio_expander/cached_gpio.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace tca9555 { + +class TCA9555Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { + public: + TCA9555Component() = default; + + /// Check i2c availability and setup masks + void setup() override; + void pin_mode(uint8_t pin, gpio::Flags flags); + + float get_setup_priority() const override; + + void dump_config() override; + + void loop() override; + + protected: + bool digital_read_hw(uint8_t pin) override; + bool digital_read_cache(uint8_t pin) override; + void digital_write_hw(uint8_t pin, bool value) override; + + /// Mask for the pin mode - 1 means output, 0 means input + uint16_t mode_mask_{0x00}; + /// The mask to write as output state - 1 means HIGH, 0 means LOW + uint16_t output_mask_{0x00}; + /// The state read in digital_read_hw - 1 means HIGH, 0 means LOW + uint16_t input_mask_{0x00}; + + bool read_gpio_modes_(); + bool write_gpio_modes_(); + bool read_gpio_outputs_(); +}; + +/// Helper class to expose a TCA9555 pin as an internal input GPIO pin. +class TCA9555GPIOPin : public GPIOPin, public Parented { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + std::string dump_summary() const override; + + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } + + protected: + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +} // namespace tca9555 +} // namespace esphome diff --git a/tests/components/tca9555/test.esp32-ard.yaml b/tests/components/tca9555/test.esp32-ard.yaml new file mode 100644 index 0000000000..e0c046b443 --- /dev/null +++ b/tests/components/tca9555/test.esp32-ard.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 16 + sda: 17 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/tca9555/test.esp32-c3-ard.yaml b/tests/components/tca9555/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..5c49b27640 --- /dev/null +++ b/tests/components/tca9555/test.esp32-c3-ard.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 5 + sda: 4 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/tca9555/test.esp32-c3-idf.yaml b/tests/components/tca9555/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5c49b27640 --- /dev/null +++ b/tests/components/tca9555/test.esp32-c3-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 5 + sda: 4 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/tca9555/test.esp32-idf.yaml b/tests/components/tca9555/test.esp32-idf.yaml new file mode 100644 index 0000000000..e0c046b443 --- /dev/null +++ b/tests/components/tca9555/test.esp32-idf.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 16 + sda: 17 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/tca9555/test.esp8266-ard.yaml b/tests/components/tca9555/test.esp8266-ard.yaml new file mode 100644 index 0000000000..5c49b27640 --- /dev/null +++ b/tests/components/tca9555/test.esp8266-ard.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 5 + sda: 4 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false diff --git a/tests/components/tca9555/test.rp2040-ard.yaml b/tests/components/tca9555/test.rp2040-ard.yaml new file mode 100644 index 0000000000..5c49b27640 --- /dev/null +++ b/tests/components/tca9555/test.rp2040-ard.yaml @@ -0,0 +1,27 @@ +i2c: + - id: i2c_tca9555 + scl: 5 + sda: 4 + +tca9555: + - id: tca9555_hub + address: 0x21 + +binary_sensor: + - platform: gpio + id: tca9555_binary_sensor + name: TCA9555 Binary Sensor + pin: + tca9555: tca9555_hub + number: 1 + mode: INPUT + inverted: true + +output: + - platform: gpio + id: tca9555_output + pin: + tca9555: tca9555_hub + number: 0 + mode: OUTPUT + inverted: false From 8e5d7337c8e9490c901cd17f59b72ed300f775b1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:18:51 +1000 Subject: [PATCH 2414/2607] [st7701s] Fix initialisation race (#7462) --- esphome/components/st7701s/st7701s.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 7248bc044e..403bff789d 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -9,14 +9,6 @@ void ST7701S::setup() { esph_log_config(TAG, "Setting up ST7701S"); this->spi_setup(); this->write_init_sequence_(); -} - -// called after a delay after writing the init sequence -void ST7701S::complete_setup_() { - this->write_command_(SLEEP_OUT); - this->write_command_(DISPLAY_ON); - this->spi_teardown(); // SPI not needed after this - delay(10); esp_lcd_rgb_panel_config_t config{}; config.flags.fb_in_psram = 1; @@ -179,7 +171,12 @@ void ST7701S::write_init_sequence_() { this->write_data_(val); ESP_LOGD(TAG, "write MADCTL %X", val); this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); - this->set_timeout(120, [this] { this->complete_setup_(); }); + // can't avoid this inline delay due to the need to complete setup before anything else tries to draw. + delay(120); // NOLINT + this->write_command_(SLEEP_OUT); + this->write_command_(DISPLAY_ON); + this->spi_teardown(); // SPI not needed after this + delay(10); } void ST7701S::dump_config() { From 5f7bde2a2cb7d66023f4cdb3687248458f1666e0 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 22 Sep 2024 14:44:53 -0500 Subject: [PATCH 2415/2607] Copy active wake words to message (#7481) --- esphome/components/api/api_connection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 7ea52e9a9e..e28b244722 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1242,6 +1242,9 @@ VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configura } resp.available_wake_words.push_back(std::move(resp_wake_word)); } + for (auto &wake_word_id : config.active_wake_words) { + resp.active_wake_words.push_back(wake_word_id); + } resp.max_active_wake_words = config.max_active_wake_words; } return resp; From c2876739474e0e6a5f226c29339856d6040e13b1 Mon Sep 17 00:00:00 2001 From: Tarik2142 <31830530+Tarik2142@users.noreply.github.com> Date: Mon, 23 Sep 2024 00:35:57 +0300 Subject: [PATCH 2416/2607] add "fan_mode" and "swing_mode" to REST API (#7476) --- esphome/components/web_server/web_server.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 1bb7c6c249..3bb7eee8f1 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1012,6 +1012,16 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url call.set_mode(mode.c_str()); } + if (request->hasParam("fan_mode")) { + auto mode = request->getParam("fan_mode")->value(); + call.set_fan_mode(mode.c_str()); + } + + if (request->hasParam("swing_mode")) { + auto mode = request->getParam("swing_mode")->value(); + call.set_swing_mode(mode.c_str()); + } + if (request->hasParam("target_temperature_high")) { auto target_temperature_high = parse_number(request->getParam("target_temperature_high")->value().c_str()); if (target_temperature_high.has_value()) From 66f9597d9e977410802a2dab0ed0743e9f776d2f Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 22 Sep 2024 14:44:53 -0500 Subject: [PATCH 2417/2607] Copy active wake words to message (#7481) --- esphome/components/api/api_connection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 7ea52e9a9e..e28b244722 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1242,6 +1242,9 @@ VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configura } resp.available_wake_words.push_back(std::move(resp_wake_word)); } + for (auto &wake_word_id : config.active_wake_words) { + resp.active_wake_words.push_back(wake_word_id); + } resp.max_active_wake_words = config.max_active_wake_words; } return resp; From f314ad8a5bf26711683c20bdff75824cfddf807a Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:40:47 +1200 Subject: [PATCH 2418/2607] Bump version to 2024.9.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 8d5996a548..29084c8955 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.0" +__version__ = "2024.9.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 402a6a9edb6f50a1e7199392160326205d23ac4f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 22 Sep 2024 23:54:31 -0500 Subject: [PATCH 2419/2607] [esp32_improv] Add triggers for various states (#7461) Co-authored-by: NP v/d Spek --- esphome/components/esp32_improv/__init__.py | 83 ++++++++++++++++++- esphome/components/esp32_improv/automation.h | 72 ++++++++++++++++ .../esp32_improv/esp32_improv_component.cpp | 18 ++-- .../esp32_improv/esp32_improv_component.h | 15 ++++ esphome/core/defines.h | 5 +- 5 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 esphome/components/esp32_improv/automation.h diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index 705dff0f1b..ecc07d4c91 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -1,7 +1,8 @@ +from esphome import automation import esphome.codegen as cg from esphome.components import binary_sensor, esp32_ble_server, output import esphome.config_validation as cv -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID AUTO_LOAD = ["esp32_ble_server"] CODEOWNERS = ["@jesserockz"] @@ -11,13 +12,36 @@ CONF_AUTHORIZED_DURATION = "authorized_duration" CONF_AUTHORIZER = "authorizer" CONF_BLE_SERVER_ID = "ble_server_id" CONF_IDENTIFY_DURATION = "identify_duration" +CONF_ON_PROVISIONED = "on_provisioned" +CONF_ON_PROVISIONING = "on_provisioning" +CONF_ON_START = "on_start" +CONF_ON_STOP = "on_stop" CONF_STATUS_INDICATOR = "status_indicator" CONF_WIFI_TIMEOUT = "wifi_timeout" +improv_ns = cg.esphome_ns.namespace("improv") +Error = improv_ns.enum("Error") +State = improv_ns.enum("State") + esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv") ESP32ImprovComponent = esp32_improv_ns.class_( "ESP32ImprovComponent", cg.Component, esp32_ble_server.BLEServiceComponent ) +ESP32ImprovProvisionedTrigger = esp32_improv_ns.class_( + "ESP32ImprovProvisionedTrigger", automation.Trigger.template() +) +ESP32ImprovProvisioningTrigger = esp32_improv_ns.class_( + "ESP32ImprovProvisioningTrigger", automation.Trigger.template() +) +ESP32ImprovStartTrigger = esp32_improv_ns.class_( + "ESP32ImprovStartTrigger", automation.Trigger.template() +) +ESP32ImprovStateTrigger = esp32_improv_ns.class_( + "ESP32ImprovStateTrigger", automation.Trigger.template() +) +ESP32ImprovStoppedTrigger = esp32_improv_ns.class_( + "ESP32ImprovStoppedTrigger", automation.Trigger.template() +) CONFIG_SCHEMA = cv.Schema( @@ -37,6 +61,37 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional( CONF_WIFI_TIMEOUT, default="1min" ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_ON_PROVISIONED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + ESP32ImprovProvisionedTrigger + ), + } + ), + cv.Optional(CONF_ON_PROVISIONING): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + ESP32ImprovProvisioningTrigger + ), + } + ), + cv.Optional(CONF_ON_START): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESP32ImprovStartTrigger), + } + ), + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESP32ImprovStateTrigger), + } + ), + cv.Optional(CONF_ON_STOP): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + ESP32ImprovStoppedTrigger + ), + } + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -63,3 +118,29 @@ async def to_code(config): if CONF_STATUS_INDICATOR in config: status_indicator = await cg.get_variable(config[CONF_STATUS_INDICATOR]) cg.add(var.set_status_indicator(status_indicator)) + + use_state_callback = False + for conf in config.get(CONF_ON_PROVISIONED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + use_state_callback = True + for conf in config.get(CONF_ON_PROVISIONING, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + use_state_callback = True + for conf in config.get(CONF_ON_START, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + use_state_callback = True + for conf in config.get(CONF_ON_STATE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation( + trigger, [(State, "state"), (Error, "error")], conf + ) + use_state_callback = True + for conf in config.get(CONF_ON_STOP, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + use_state_callback = True + if use_state_callback: + cg.add_define("USE_ESP32_IMPROV_STATE_CALLBACK") diff --git a/esphome/components/esp32_improv/automation.h b/esphome/components/esp32_improv/automation.h new file mode 100644 index 0000000000..52c5da125b --- /dev/null +++ b/esphome/components/esp32_improv/automation.h @@ -0,0 +1,72 @@ +#pragma once +#ifdef USE_ESP32 +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK +#include "esp32_improv_component.h" + +#include "esphome/core/automation.h" + +#include + +namespace esphome { +namespace esp32_improv { + +class ESP32ImprovProvisionedTrigger : public Trigger<> { + public: + explicit ESP32ImprovProvisionedTrigger(ESP32ImprovComponent *parent) { + parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { + if (state == improv::STATE_PROVISIONED && !parent->is_failed()) { + trigger(); + } + }); + } +}; + +class ESP32ImprovProvisioningTrigger : public Trigger<> { + public: + explicit ESP32ImprovProvisioningTrigger(ESP32ImprovComponent *parent) { + parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { + if (state == improv::STATE_PROVISIONING && !parent->is_failed()) { + trigger(); + } + }); + } +}; + +class ESP32ImprovStartTrigger : public Trigger<> { + public: + explicit ESP32ImprovStartTrigger(ESP32ImprovComponent *parent) { + parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { + if ((state == improv::STATE_AUTHORIZED || state == improv::STATE_AWAITING_AUTHORIZATION) && + !parent->is_failed()) { + trigger(); + } + }); + } +}; + +class ESP32ImprovStateTrigger : public Trigger { + public: + explicit ESP32ImprovStateTrigger(ESP32ImprovComponent *parent) { + parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { + if (!parent->is_failed()) { + trigger(state, error); + } + }); + } +}; + +class ESP32ImprovStoppedTrigger : public Trigger<> { + public: + explicit ESP32ImprovStoppedTrigger(ESP32ImprovComponent *parent) { + parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { + if (state == improv::STATE_STOPPED && !parent->is_failed()) { + trigger(); + } + }); + } +}; + +} // namespace esp32_improv +} // namespace esphome +#endif +#endif diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index d90eaac3b6..d36b50feb0 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -68,7 +68,12 @@ void ESP32ImprovComponent::setup_characteristics() { void ESP32ImprovComponent::loop() { if (!global_ble_server->is_running()) { - this->state_ = improv::STATE_STOPPED; + if (this->state_ != improv::STATE_STOPPED) { + this->state_ = improv::STATE_STOPPED; +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK + this->state_callback_.call(this->state_, this->error_state_); +#endif + } this->incoming_data_.clear(); return; } @@ -217,6 +222,9 @@ void ESP32ImprovComponent::set_state_(improv::State state) { service_data[7] = 0x00; // Reserved esp32_ble::global_ble->advertising_set_service_data(service_data); +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK + this->state_callback_.call(this->state_, this->error_state_); +#endif } void ESP32ImprovComponent::set_error_(improv::Error error) { @@ -270,7 +278,7 @@ void ESP32ImprovComponent::dump_config() { void ESP32ImprovComponent::process_incoming_data_() { uint8_t length = this->incoming_data_[1]; - ESP_LOGD(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str()); + ESP_LOGV(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str()); if (this->incoming_data_.size() - 3 == length) { this->set_error_(improv::ERROR_NONE); improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_); @@ -295,7 +303,7 @@ void ESP32ImprovComponent::process_incoming_data_() { wifi::global_wifi_component->set_sta(sta); wifi::global_wifi_component->start_connecting(sta, false); this->set_state_(improv::STATE_PROVISIONING); - ESP_LOGD(TAG, "Received Improv wifi settings ssid=%s, password=" LOG_SECRET("%s"), command.ssid.c_str(), + ESP_LOGD(TAG, "Received Improv Wi-Fi settings ssid=%s, password=" LOG_SECRET("%s"), command.ssid.c_str(), command.password.c_str()); auto f = std::bind(&ESP32ImprovComponent::on_wifi_connect_timeout_, this); @@ -313,7 +321,7 @@ void ESP32ImprovComponent::process_incoming_data_() { this->incoming_data_.clear(); } } else if (this->incoming_data_.size() - 2 > length) { - ESP_LOGV(TAG, "Too much data came in, or malformed resetting buffer..."); + ESP_LOGV(TAG, "Too much data received or data malformed; resetting buffer..."); this->incoming_data_.clear(); } else { ESP_LOGV(TAG, "Waiting for split data packets..."); @@ -327,7 +335,7 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() { if (this->authorizer_ != nullptr) this->authorized_start_ = millis(); #endif - ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); + ESP_LOGW(TAG, "Timed out while connecting to Wi-Fi network"); wifi::global_wifi_component->clear_sta(); } diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h index 3ed377a6ad..062b3f585b 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.h +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -9,6 +9,10 @@ #include "esphome/components/esp32_ble_server/ble_server.h" #include "esphome/components/wifi/wifi_component.h" +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK +#include "esphome/core/automation.h" +#endif + #ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" #endif @@ -42,6 +46,11 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void stop() override; bool is_active() const { return this->state_ != improv::STATE_STOPPED; } +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK + void add_on_state_callback(std::function &&callback) { + this->state_callback_.add(std::move(callback)); + } +#endif #ifdef USE_BINARY_SENSOR void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } #endif @@ -54,6 +63,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; } uint32_t get_wifi_timeout() const { return this->wifi_timeout_; } + improv::State get_improv_state() const { return this->state_; } + improv::Error get_improv_error_state() const { return this->error_state_; } + protected: bool should_start_{false}; bool setup_complete_{false}; @@ -84,6 +96,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { improv::State state_{improv::STATE_STOPPED}; improv::Error error_state_{improv::ERROR_NONE}; +#ifdef USE_ESP32_IMPROV_STATE_CALLBACK + CallbackManager state_callback_{}; +#endif bool status_indicator_state_{false}; void set_status_indicator_state_(bool state); diff --git a/esphome/core/defines.h b/esphome/core/defines.h index ffd5cc6f1b..bf676107c7 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -29,6 +29,7 @@ #define USE_DATETIME_TIME #define USE_DEEP_SLEEP #define USE_DISPLAY +#define USE_ESP32_IMPROV_STATE_CALLBACK #define USE_EVENT #define USE_FAN #define USE_GRAPH @@ -45,10 +46,10 @@ #define USE_LVGL_BUTTONMATRIX #define USE_LVGL_FONT #define USE_LVGL_IMAGE -#define USE_LVGL_KEYBOARD #define USE_LVGL_KEY_LISTENER -#define USE_LVGL_TOUCHSCREEN +#define USE_LVGL_KEYBOARD #define USE_LVGL_ROTARY_ENCODER +#define USE_LVGL_TOUCHSCREEN #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT From 2ff863deb3ed699d3ef24c8f0298dfe063fee42b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 23 Sep 2024 01:35:26 -0500 Subject: [PATCH 2420/2607] [micro_wake_word] Workaround for failing IDF 5+ tests (#7484) --- esphome/components/micro_wake_word/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/components/micro_wake_word/__init__.py b/esphome/components/micro_wake_word/__init__.py index a8aa590951..0862406e46 100644 --- a/esphome/components/micro_wake_word/__init__.py +++ b/esphome/components/micro_wake_word/__init__.py @@ -419,6 +419,13 @@ async def to_code(config): repo="https://github.com/espressif/esp-tflite-micro", ref="v1.3.1", ) + # add esp-nn dependency for tflite-micro to work around https://github.com/espressif/esp-nn/issues/17 + # ...remove after switching to IDF 5.1.4+ + esp32.add_idf_component( + name="esp-nn", + repo="https://github.com/espressif/esp-nn", + ref="v1.1.0", + ) cg.add_build_flag("-DTF_LITE_STATIC_MEMORY") cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON") From 4ece4a389e009ef2230b07e4ae9b1fdc18a0a148 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:31:38 +0200 Subject: [PATCH 2421/2607] Bump peter-evans/create-pull-request from 7.0.3 to 7.0.5 (#7469) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-device-classes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index eeb8386e74..c066ae9fb4 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v7.0.3 + uses: peter-evans/create-pull-request@v7.0.5 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot From cc53eb42b273631b14ddf3d0a0308372a58043e7 Mon Sep 17 00:00:00 2001 From: Nick Kinnan Date: Mon, 23 Sep 2024 20:53:13 -0700 Subject: [PATCH 2422/2607] Add CSE7766 reactive power (#7301) --- esphome/components/cse7766/cse7766.cpp | 11 +++++++++++ esphome/components/cse7766/cse7766.h | 4 ++++ esphome/components/cse7766/sensor.py | 12 ++++++++++++ 3 files changed, 27 insertions(+) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index f1420aa127..47058badce 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -147,6 +147,7 @@ void CSE7766Component::parse_data_() { float power = 0.0f; if (power_cycle_exceeds_range) { // Datasheet: power cycle exceeding range means active power is 0 + have_power = true; if (this->power_sensor_ != nullptr) { this->power_sensor_->publish_state(0.0f); } @@ -178,6 +179,15 @@ void CSE7766Component::parse_data_() { if (this->apparent_power_sensor_ != nullptr) { this->apparent_power_sensor_->publish_state(apparent_power); } + if (have_power && this->reactive_power_sensor_ != nullptr) { + const float reactive_power = apparent_power - power; + if (reactive_power < 0.0f) { + ESP_LOGD(TAG, "Impossible reactive power: %.4f is negative", reactive_power); + this->reactive_power_sensor_->publish_state(0.0f); + } else { + this->reactive_power_sensor_->publish_state(reactive_power); + } + } if (this->power_factor_sensor_ != nullptr && (have_power || power_cycle_exceeds_range)) { float pf = NAN; if (apparent_power > 0) { @@ -232,6 +242,7 @@ void CSE7766Component::dump_config() { LOG_SENSOR(" ", "Power", this->power_sensor_); LOG_SENSOR(" ", "Energy", this->energy_sensor_); LOG_SENSOR(" ", "Apparent Power", this->apparent_power_sensor_); + LOG_SENSOR(" ", "Reactive Power", this->reactive_power_sensor_); LOG_SENSOR(" ", "Power Factor", this->power_factor_sensor_); this->check_uart_settings(4800); } diff --git a/esphome/components/cse7766/cse7766.h b/esphome/components/cse7766/cse7766.h index 0b724d6bbb..5d89b3b75b 100644 --- a/esphome/components/cse7766/cse7766.h +++ b/esphome/components/cse7766/cse7766.h @@ -16,6 +16,9 @@ class CSE7766Component : public Component, public uart::UARTDevice { void set_apparent_power_sensor(sensor::Sensor *apparent_power_sensor) { apparent_power_sensor_ = apparent_power_sensor; } + void set_reactive_power_sensor(sensor::Sensor *reactive_power_sensor) { + reactive_power_sensor_ = reactive_power_sensor; + } void set_power_factor_sensor(sensor::Sensor *power_factor_sensor) { power_factor_sensor_ = power_factor_sensor; } void loop() override; @@ -35,6 +38,7 @@ class CSE7766Component : public Component, public uart::UARTDevice { sensor::Sensor *power_sensor_{nullptr}; sensor::Sensor *energy_sensor_{nullptr}; sensor::Sensor *apparent_power_sensor_{nullptr}; + sensor::Sensor *reactive_power_sensor_{nullptr}; sensor::Sensor *power_factor_sensor_{nullptr}; uint32_t cf_pulses_total_{0}; uint16_t cf_pulses_last_{0}; diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index b64dcf7de3..ecb59c4b5f 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -8,18 +8,21 @@ from esphome.const import ( CONF_ID, CONF_POWER, CONF_POWER_FACTOR, + CONF_REACTIVE_POWER, CONF_VOLTAGE, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, DEVICE_CLASS_POWER_FACTOR, + DEVICE_CLASS_REACTIVE_POWER, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, UNIT_AMPERE, UNIT_VOLT, UNIT_VOLT_AMPS, + UNIT_VOLT_AMPS_REACTIVE, UNIT_WATT, UNIT_WATT_HOURS, ) @@ -62,6 +65,12 @@ CONFIG_SCHEMA = cv.Schema( device_class=DEVICE_CLASS_APPARENT_POWER, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE, + accuracy_decimals=1, + device_class=DEVICE_CLASS_REACTIVE_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema( accuracy_decimals=2, device_class=DEVICE_CLASS_POWER_FACTOR, @@ -94,6 +103,9 @@ async def to_code(config): if apparent_power_config := config.get(CONF_APPARENT_POWER): sens = await sensor.new_sensor(apparent_power_config) cg.add(var.set_apparent_power_sensor(sens)) + if reactive_power_config := config.get(CONF_REACTIVE_POWER): + sens = await sensor.new_sensor(reactive_power_config) + cg.add(var.set_reactive_power_sensor(sens)) if power_factor_config := config.get(CONF_POWER_FACTOR): sens = await sensor.new_sensor(power_factor_config) cg.add(var.set_power_factor_sensor(sens)) From 294fe8d9708bfb904824f38c7619ccd673905dc3 Mon Sep 17 00:00:00 2001 From: David Sichau Date: Wed, 25 Sep 2024 02:50:01 +0200 Subject: [PATCH 2423/2607] Support inkplate 5 and 5 V2 (#7448) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/inkplate6/display.py | 2 ++ esphome/components/inkplate6/inkplate.h | 32 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index 58a146d2fd..8fe7f7d41d 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -53,6 +53,8 @@ MODELS = { "inkplate_10": InkplateModel.INKPLATE_10, "inkplate_6_plus": InkplateModel.INKPLATE_6_PLUS, "inkplate_6_v2": InkplateModel.INKPLATE_6_V2, + "inkplate_5": InkplateModel.INKPLATE_5, + "inkplate_5_v2": InkplateModel.INKPLATE_5_V2, } CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/inkplate6/inkplate.h b/esphome/components/inkplate6/inkplate.h index 2946c89e1c..ca2ad46f1e 100644 --- a/esphome/components/inkplate6/inkplate.h +++ b/esphome/components/inkplate6/inkplate.h @@ -15,6 +15,8 @@ enum InkplateModel : uint8_t { INKPLATE_10 = 1, INKPLATE_6_PLUS = 2, INKPLATE_6_V2 = 3, + INKPLATE_5 = 4, + INKPLATE_5_V2 = 5, }; class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { @@ -29,7 +31,7 @@ class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { const uint8_t pixelMaskLUT[8] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; const uint8_t pixelMaskGLUT[2] = {0x0F, 0xF0}; - const uint8_t waveform3BitAll[4][8][9] = {// INKPLATE_6 + const uint8_t waveform3BitAll[6][8][9] = {// INKPLATE_6 {{0, 1, 1, 0, 0, 1, 1, 0, 0}, {0, 1, 2, 1, 1, 2, 1, 0, 0}, {1, 1, 1, 2, 2, 1, 0, 0, 0}, @@ -64,7 +66,25 @@ class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { {1, 1, 1, 1, 2, 2, 1, 0, 0}, {0, 1, 1, 1, 2, 2, 1, 0, 0}, {0, 0, 0, 0, 1, 1, 2, 0, 0}, - {0, 0, 0, 0, 0, 1, 2, 0, 0}}}; + {0, 0, 0, 0, 0, 1, 2, 0, 0}}, + // INKPLATE_5 + {{0, 0, 1, 1, 0, 1, 1, 1, 0}, + {0, 1, 1, 1, 1, 2, 0, 1, 0}, + {1, 2, 2, 0, 2, 1, 1, 1, 0}, + {1, 1, 1, 2, 0, 1, 1, 2, 0}, + {0, 1, 1, 1, 2, 0, 1, 2, 0}, + {0, 0, 0, 1, 1, 2, 1, 2, 0}, + {1, 1, 1, 2, 0, 2, 1, 2, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}}, + // INKPLATE_5_V2 + {{0, 0, 1, 1, 2, 1, 1, 1, 0}, + {1, 1, 2, 2, 1, 2, 1, 1, 0}, + {0, 1, 2, 2, 1, 1, 2, 1, 0}, + {0, 0, 1, 1, 1, 1, 1, 2, 0}, + {1, 2, 1, 2, 1, 1, 1, 2, 0}, + {0, 1, 1, 1, 2, 0, 1, 2, 0}, + {1, 1, 1, 2, 2, 2, 1, 2, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}}}; void set_greyscale(bool greyscale) { this->greyscale_ = greyscale; @@ -146,6 +166,10 @@ class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { return 800; } else if (this->model_ == INKPLATE_10) { return 1200; + } else if (this->model_ == INKPLATE_5) { + return 960; + } else if (this->model_ == INKPLATE_5_V2) { + return 1280; } else if (this->model_ == INKPLATE_6_PLUS) { return 1024; } @@ -155,6 +179,10 @@ class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { int get_height_internal() override { if (this->model_ == INKPLATE_6 || this->model_ == INKPLATE_6_V2) { return 600; + } else if (this->model_ == INKPLATE_5) { + return 540; + } else if (this->model_ == INKPLATE_5_V2) { + return 720; } else if (this->model_ == INKPLATE_10) { return 825; } else if (this->model_ == INKPLATE_6_PLUS) { From 8e54a622d3051e091b494896194f21205913d301 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 24 Sep 2024 17:50:44 -0700 Subject: [PATCH 2424/2607] fix bl0906 reset energy action (#7488) Co-authored-by: Samuel Sieb --- esphome/components/bl0906/sensor.py | 5 +++-- tests/components/bl0906/common.yaml | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/esphome/components/bl0906/sensor.py b/esphome/components/bl0906/sensor.py index bc370c9252..42c6f06092 100644 --- a/esphome/components/bl0906/sensor.py +++ b/esphome/components/bl0906/sensor.py @@ -145,8 +145,9 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ), ) async def reset_energy_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var async def to_code(config): diff --git a/tests/components/bl0906/common.yaml b/tests/components/bl0906/common.yaml index 944791369c..29321a9471 100644 --- a/tests/components/bl0906/common.yaml +++ b/tests/components/bl0906/common.yaml @@ -8,6 +8,7 @@ uart: sensor: - platform: bl0906 + id: bl frequency: name: 'Frequency' temperature: @@ -60,3 +61,9 @@ sensor: name: 'Total_Energy' total_power: name: 'Total_Power' + +button: + - platform: template + id: reset + on_press: + - bl0906.reset_energy: bl From fcce70d416602da087617920fbfe02a428b5e51c Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Tue, 24 Sep 2024 22:09:24 -0400 Subject: [PATCH 2425/2607] Add remote transmitter triggers (#7483) Co-authored-by: Jonathan Swoboda --- .../components/remote_transmitter/__init__.py | 20 +++++++++++++++++-- .../remote_transmitter/remote_transmitter.h | 6 ++++++ .../remote_transmitter_esp32.cpp | 2 ++ .../remote_transmitter_esp8266.cpp | 2 ++ .../remote_transmitter_libretiny.cpp | 2 ++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index d203ff3417..f979939739 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -1,10 +1,14 @@ +from esphome import automation, pins import esphome.codegen as cg +from esphome.components import esp32_rmt, remote_base import esphome.config_validation as cv -from esphome import pins -from esphome.components import remote_base, esp32_rmt from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN, CONF_RMT_CHANNEL AUTO_LOAD = ["remote_base"] + +CONF_ON_TRANSMIT = "on_transmit" +CONF_ON_COMPLETE = "on_complete" + remote_transmitter_ns = cg.esphome_ns.namespace("remote_transmitter") RemoteTransmitterComponent = remote_transmitter_ns.class_( "RemoteTransmitterComponent", remote_base.RemoteTransmitterBase, cg.Component @@ -19,6 +23,8 @@ CONFIG_SCHEMA = cv.Schema( cv.percentage_int, cv.Range(min=1, max=100) ), cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True), + cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True), + cv.Optional(CONF_ON_COMPLETE): automation.validate_automation(single=True), } ).extend(cv.COMPONENT_SCHEMA) @@ -32,3 +38,13 @@ async def to_code(config): await cg.register_component(var, config) cg.add(var.set_carrier_duty_percent(config[CONF_CARRIER_DUTY_PERCENT])) + + if on_transmit_config := config.get(CONF_ON_TRANSMIT): + await automation.build_automation( + var.get_transmit_trigger(), [], on_transmit_config + ) + + if on_complete_config := config.get(CONF_ON_COMPLETE): + await automation.build_automation( + var.get_complete_trigger(), [], on_complete_config + ) diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index a5896796c0..4abe687d23 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -33,6 +33,9 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, void set_carrier_duty_percent(uint8_t carrier_duty_percent) { this->carrier_duty_percent_ = carrier_duty_percent; } + Trigger<> *get_transmit_trigger() const { return this->transmit_trigger_; }; + Trigger<> *get_complete_trigger() const { return this->complete_trigger_; }; + protected: void send_internal(uint32_t send_times, uint32_t send_wait) override; #if defined(USE_ESP8266) || defined(USE_LIBRETINY) @@ -57,6 +60,9 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, bool inverted_{false}; #endif uint8_t carrier_duty_percent_; + + Trigger<> *transmit_trigger_{new Trigger<>()}; + Trigger<> *complete_trigger_{new Trigger<>()}; }; } // namespace remote_transmitter diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index eea35019ff..bce2408723 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -124,6 +124,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen ESP_LOGE(TAG, "Empty data"); return; } + this->transmit_trigger_->trigger(); for (uint32_t i = 0; i < send_times; i++) { esp_err_t error = rmt_write_items(this->channel_, this->rmt_temp_.data(), this->rmt_temp_.size(), true); if (error != ESP_OK) { @@ -135,6 +136,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen if (i + 1 < send_times) delayMicroseconds(send_wait); } + this->complete_trigger_->trigger(); } } // namespace remote_transmitter diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp index 1c0eb94e61..613f00b7f5 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp @@ -76,6 +76,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen uint32_t on_time, off_time; this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); this->target_time_ = 0; + this->transmit_trigger_->trigger(); for (uint32_t i = 0; i < send_times; i++) { for (int32_t item : this->temp_.get_data()) { if (item > 0) { @@ -93,6 +94,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen if (i + 1 < send_times) this->target_time_ += send_wait; } + this->complete_trigger_->trigger(); } } // namespace remote_transmitter diff --git a/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp index 78bb280482..ad9265fb14 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp @@ -78,6 +78,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen uint32_t on_time, off_time; this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); this->target_time_ = 0; + this->transmit_trigger_->trigger(); for (uint32_t i = 0; i < send_times; i++) { InterruptLock lock; for (int32_t item : this->temp_.get_data()) { @@ -96,6 +97,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen if (i + 1 < send_times) this->target_time_ += send_wait; } + this->complete_trigger_->trigger(); } } // namespace remote_transmitter From fa9df329795f746bc0fdec04e521d3db41c0612f Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Wed, 25 Sep 2024 04:27:14 +0200 Subject: [PATCH 2426/2607] tcs34725: fix color/clear channel percentage calculations on long exposures (#7493) --- esphome/components/tcs34725/tcs34725.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 88c59eb761..9bb7c9a3b2 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -211,7 +211,7 @@ void TCS34725Component::update() { if (raw_c == 0) { channel_c = channel_r = channel_g = channel_b = 0.0f; } else { - float max_count = this->integration_time_ * 1024.0f / 2.4; + float max_count = this->integration_time_ <= 153.6f ? this->integration_time_ * 1024.0f / 2.4f : 65535.0f; float sum = raw_c; channel_r = raw_r / sum * 100.0f; channel_g = raw_g / sum * 100.0f; From b61577b68b1e79595e751e158ee9873863b6d51c Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Wed, 25 Sep 2024 04:28:22 +0200 Subject: [PATCH 2427/2607] tcs34725: Add check for Division by Zero (#7485) --- esphome/components/tcs34725/tcs34725.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 9bb7c9a3b2..c9b2ae321a 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -1,6 +1,7 @@ #include "tcs34725.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include namespace esphome { namespace tcs34725 { @@ -254,7 +255,8 @@ void TCS34725Component::update() { // change integration time an gain to achieve maximum resolution an dynamic range // calculate optimal integration time to achieve 70% satuaration float integration_time_ideal; - integration_time_ideal = 60 / ((float) raw_c / 655.35) * this->integration_time_; + + integration_time_ideal = 60 / ((float) std::max((uint16_t) 1, raw_c) / 655.35f) * this->integration_time_; uint8_t gain_reg_val_new = this->gain_reg_; // increase gain if less than 20% of white channel used and high integration time From 21fbbc5fb9477704be8b1ec8293d2a729f7a0072 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:34:27 +1200 Subject: [PATCH 2428/2607] [config_validation] Fix bug with extras on schemas (#7497) --- esphome/voluptuous_schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/voluptuous_schema.py b/esphome/voluptuous_schema.py index 7f1573b443..15f9206f21 100644 --- a/esphome/voluptuous_schema.py +++ b/esphome/voluptuous_schema.py @@ -226,4 +226,6 @@ class _Schema(vol.Schema): if isinstance(schema, vol.Schema): schema = schema.schema ret = super().extend(schema, extra=extra) - return _Schema(ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas) + return _Schema( + ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas.copy() + ) From 3b1b1071f1f001755cffed5568c6578bf4a881a1 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Thu, 26 Sep 2024 17:25:20 -0400 Subject: [PATCH 2429/2607] [core] add ring buffer destructor (#7500) --- esphome/core/ring_buffer.cpp | 14 ++++++++++++-- esphome/core/ring_buffer.h | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/core/ring_buffer.cpp b/esphome/core/ring_buffer.cpp index d8ca831de0..f97c686684 100644 --- a/esphome/core/ring_buffer.cpp +++ b/esphome/core/ring_buffer.cpp @@ -11,16 +11,26 @@ namespace esphome { static const char *const TAG = "ring_buffer"; +RingBuffer::~RingBuffer() { + if (this->handle_ != nullptr) { + vStreamBufferDelete(this->handle_); + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + allocator.deallocate(this->storage_, this->size_); + } +} + std::unique_ptr RingBuffer::create(size_t len) { std::unique_ptr rb = make_unique(); + rb->size_ = len + 1; + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - rb->storage_ = allocator.allocate(len + 1); + rb->storage_ = allocator.allocate(rb->size_); if (rb->storage_ == nullptr) { return nullptr; } - rb->handle_ = xStreamBufferCreateStatic(len + 1, 1, rb->storage_, &rb->structure_); + rb->handle_ = xStreamBufferCreateStatic(rb->size_, 1, rb->storage_, &rb->structure_); ESP_LOGD(TAG, "Created ring buffer with size %u", len); return rb; } diff --git a/esphome/core/ring_buffer.h b/esphome/core/ring_buffer.h index 97ffefcefa..c0511fb52e 100644 --- a/esphome/core/ring_buffer.h +++ b/esphome/core/ring_buffer.h @@ -12,6 +12,8 @@ namespace esphome { class RingBuffer { public: + ~RingBuffer(); + /** * @brief Reads from the ring buffer, waiting up to a specified number of ticks if necessary. * @@ -83,6 +85,7 @@ class RingBuffer { StreamBufferHandle_t handle_; StaticStreamBuffer_t structure_; uint8_t *storage_; + size_t size_{0}; }; } // namespace esphome From c55b4f5e1b28259a3cf54539f5b709ab2ed7595e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:51:08 +1000 Subject: [PATCH 2430/2607] [ch422g] Add support for pins 8-11; make input work. (#7467) --- CODEOWNERS | 2 +- esphome/components/ch422g/__init__.py | 43 ++++++---- esphome/components/ch422g/ch422g.cpp | 119 +++++++++++++++----------- esphome/components/ch422g/ch422g.h | 36 ++++---- tests/components/ch422g/common.yaml | 11 ++- 5 files changed, 121 insertions(+), 90 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a2fe77dc84..1eb13a534b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -86,7 +86,7 @@ esphome/components/cap1188/* @mreditor97 esphome/components/captive_portal/* @OttoWinter esphome/components/ccs811/* @habbie esphome/components/cd74hc4067/* @asoehlke -esphome/components/ch422g/* @jesterret +esphome/components/ch422g/* @clydebarrow @jesterret esphome/components/climate/* @esphome/core esphome/components/climate_ir/* @glmnet esphome/components/color_temperature/* @jesserockz diff --git a/esphome/components/ch422g/__init__.py b/esphome/components/ch422g/__init__.py index cf8b5f65d3..6a7bace0a2 100644 --- a/esphome/components/ch422g/__init__.py +++ b/esphome/components/ch422g/__init__.py @@ -1,18 +1,20 @@ from esphome import pins import esphome.codegen as cg from esphome.components import i2c +from esphome.components.i2c import I2CBus import esphome.config_validation as cv from esphome.const import ( + CONF_I2C_ID, CONF_ID, CONF_INPUT, CONF_INVERTED, CONF_MODE, CONF_NUMBER, + CONF_OPEN_DRAIN, CONF_OUTPUT, - CONF_RESTORE_VALUE, ) -CODEOWNERS = ["@jesterret"] +CODEOWNERS = ["@jesterret", "@clydebarrow"] DEPENDENCIES = ["i2c"] MULTI_CONF = True ch422g_ns = cg.esphome_ns.namespace("ch422g") @@ -23,29 +25,36 @@ CH422GGPIOPin = ch422g_ns.class_( ) CONF_CH422G = "ch422g" -CONFIG_SCHEMA = ( - cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(CH422GComponent), - cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, - } - ) - .extend(cv.COMPONENT_SCHEMA) - .extend(i2c.i2c_device_schema(0x24)) -) + +# Note that no address is configurable - each register in the CH422G has a dedicated i2c address +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_ID): cv.declare_id(CH422GComponent), + cv.GenerateID(CONF_I2C_ID): cv.use_id(I2CBus), + } +).extend(cv.COMPONENT_SCHEMA) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE])) await cg.register_component(var, config) - await i2c.register_i2c_device(var, config) + # Can't use register_i2c_device because there is no CONF_ADDRESS + parent = await cg.get_variable(config[CONF_I2C_ID]) + cg.add(var.set_i2c_bus(parent)) + + +# This is used as a final validation step so that modes have been fully transformed. +def pin_mode_check(pin_config, _): + if pin_config[CONF_MODE][CONF_INPUT] and pin_config[CONF_NUMBER] >= 8: + raise cv.Invalid("CH422G only supports input on pins 0-7") + if pin_config[CONF_MODE][CONF_OPEN_DRAIN] and pin_config[CONF_NUMBER] < 8: + raise cv.Invalid("CH422G only supports open drain output on pins 8-11") CH422G_PIN_SCHEMA = pins.gpio_base_schema( CH422GGPIOPin, - cv.int_range(min=0, max=7), - modes=[CONF_INPUT, CONF_OUTPUT], + cv.int_range(min=0, max=11), + modes=[CONF_INPUT, CONF_OUTPUT, CONF_OPEN_DRAIN], ).extend( { cv.Required(CONF_CH422G): cv.use_id(CH422GComponent), @@ -53,7 +62,7 @@ CH422G_PIN_SCHEMA = pins.gpio_base_schema( ) -@pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA) +@pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA, pin_mode_check) async def ch422g_pin_to_code(config): var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_CH422G]) diff --git a/esphome/components/ch422g/ch422g.cpp b/esphome/components/ch422g/ch422g.cpp index 25038991ed..0db179d99e 100644 --- a/esphome/components/ch422g/ch422g.cpp +++ b/esphome/components/ch422g/ch422g.cpp @@ -4,33 +4,33 @@ namespace esphome { namespace ch422g { -const uint8_t CH422G_REG_IN = 0x26; -const uint8_t CH422G_REG_OUT = 0x38; -const uint8_t OUT_REG_DEFAULT_VAL = 0xdf; +static const uint8_t CH422G_REG_MODE = 0x24; +static const uint8_t CH422G_MODE_OUTPUT = 0x01; // enables output mode on 0-7 +static const uint8_t CH422G_MODE_OPEN_DRAIN = 0x04; // enables open drain mode on 8-11 +static const uint8_t CH422G_REG_IN = 0x26; // read reg for input bits +static const uint8_t CH422G_REG_OUT = 0x38; // write reg for output bits 0-7 +static const uint8_t CH422G_REG_OUT_UPPER = 0x23; // write reg for output bits 8-11 static const char *const TAG = "ch422g"; void CH422GComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up CH422G..."); - // Test to see if device exists - if (!this->read_inputs_()) { + // set outputs before mode + this->write_outputs_(); + // Set mode and check for errors + if (!this->set_mode_(this->mode_value_) || !this->read_inputs_()) { ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_); this->mark_failed(); return; } - // restore defaults over whatever got saved on last boot - if (!this->restore_value_) { - this->write_output_(OUT_REG_DEFAULT_VAL); - } - - ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), - this->status_has_error()); + ESP_LOGCONFIG(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), + this->status_has_error()); } void CH422GComponent::loop() { // Clear all the previously read flags. - this->pin_read_cache_ = 0x00; + this->pin_read_flags_ = 0x00; } void CH422GComponent::dump_config() { @@ -41,82 +41,99 @@ void CH422GComponent::dump_config() { } } -// ch422g doesn't have any flag support (needs docs?) -void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {} +void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) { + if (pin < 8) { + if (flags & gpio::FLAG_OUTPUT) { + this->mode_value_ |= CH422G_MODE_OUTPUT; + } + } else { + if (flags & gpio::FLAG_OPEN_DRAIN) { + this->mode_value_ |= CH422G_MODE_OPEN_DRAIN; + } + } +} bool CH422GComponent::digital_read(uint8_t pin) { - if (this->pin_read_cache_ == 0 || this->pin_read_cache_ & (1 << pin)) { + if (this->pin_read_flags_ == 0 || this->pin_read_flags_ & (1 << pin)) { // Read values on first access or in case it's being read again in the same loop this->read_inputs_(); } - this->pin_read_cache_ |= (1 << pin); - return this->state_mask_ & (1 << pin); + this->pin_read_flags_ |= (1 << pin); + return (this->input_bits_ & (1 << pin)) != 0; } void CH422GComponent::digital_write(uint8_t pin, bool value) { if (value) { - this->write_output_(this->state_mask_ | (1 << pin)); + this->output_bits_ |= (1 << pin); } else { - this->write_output_(this->state_mask_ & ~(1 << pin)); + this->output_bits_ &= ~(1 << pin); } + this->write_outputs_(); } bool CH422GComponent::read_inputs_() { if (this->is_failed()) { return false; } - - uint8_t temp = 0; - if ((this->last_error_ = this->read(&temp, 1)) != esphome::i2c::ERROR_OK) { - this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); - return false; + uint8_t result; + // reading inputs requires the chip to be in input mode, possibly temporarily. + if (this->mode_value_ & CH422G_MODE_OUTPUT) { + this->set_mode_(this->mode_value_ & ~CH422G_MODE_OUTPUT); + result = this->read_reg_(CH422G_REG_IN); + this->set_mode_(this->mode_value_); + } else { + result = this->read_reg_(CH422G_REG_IN); } - - uint8_t output = 0; - if ((this->last_error_ = this->bus_->read(CH422G_REG_IN, &output, 1)) != esphome::i2c::ERROR_OK) { - this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); - return false; - } - - this->state_mask_ = output; + this->input_bits_ = result; this->status_clear_warning(); - return true; } -bool CH422GComponent::write_output_(uint8_t value) { - const uint8_t temp = 1; - if ((this->last_error_ = this->write(&temp, 1, false)) != esphome::i2c::ERROR_OK) { - this->status_set_warning(str_sprintf("write_output_(): I2C I/O error: %d", (int) this->last_error_).c_str()); +// Write a register. Can't use the standard write_byte() method because there is no single pre-configured i2c address. +bool CH422GComponent::write_reg_(uint8_t reg, uint8_t value) { + auto err = this->bus_->write(reg, &value, 1); + if (err != i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("write failed for register 0x%X, error %d", reg, err).c_str()); return false; } - - uint8_t write_mask = value; - if ((this->last_error_ = this->bus_->write(CH422G_REG_OUT, &write_mask, 1)) != esphome::i2c::ERROR_OK) { - this->status_set_warning( - str_sprintf("write_output_(): I2C I/O error: %d for write_mask: %d", (int) this->last_error_, (int) write_mask) - .c_str()); - return false; - } - - this->state_mask_ = value; this->status_clear_warning(); return true; } +uint8_t CH422GComponent::read_reg_(uint8_t reg) { + uint8_t value; + auto err = this->bus_->read(reg, &value, 1); + if (err != i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("read failed for register 0x%X, error %d", reg, err).c_str()); + return 0; + } + this->status_clear_warning(); + return value; +} + +bool CH422GComponent::set_mode_(uint8_t mode) { return this->write_reg_(CH422G_REG_MODE, mode); } + +bool CH422GComponent::write_outputs_() { + return this->write_reg_(CH422G_REG_OUT, static_cast(this->output_bits_)) && + this->write_reg_(CH422G_REG_OUT_UPPER, static_cast(this->output_bits_ >> 8)); +} + float CH422GComponent::get_setup_priority() const { return setup_priority::IO; } // Run our loop() method very early in the loop, so that we cache read values // before other components call our digital_read() method. float CH422GComponent::get_loop_priority() const { return 9.0f; } // Just after WIFI -void CH422GGPIOPin::setup() { pin_mode(flags_); } void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } -bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } +bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; } -void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } +void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value ^ this->inverted_); } std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); } +void CH422GGPIOPin::set_flags(gpio::Flags flags) { + flags_ = flags; + this->parent_->pin_mode(this->pin_, flags); +} } // namespace ch422g } // namespace esphome diff --git a/esphome/components/ch422g/ch422g.h b/esphome/components/ch422g/ch422g.h index 781df65437..30780e09ad 100644 --- a/esphome/components/ch422g/ch422g.h +++ b/esphome/components/ch422g/ch422g.h @@ -23,32 +23,30 @@ class CH422GComponent : public Component, public i2c::I2CDevice { void pin_mode(uint8_t pin, gpio::Flags flags); float get_setup_priority() const override; - float get_loop_priority() const override; - void dump_config() override; - void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } - protected: + bool write_reg_(uint8_t reg, uint8_t value); + uint8_t read_reg_(uint8_t reg); + bool set_mode_(uint8_t mode); bool read_inputs_(); - - bool write_output_(uint8_t value); + bool write_outputs_(); /// The mask to write as output state - 1 means HIGH, 0 means LOW - uint8_t state_mask_{0x00}; + uint16_t output_bits_{0x00}; /// Flags to check if read previously during this loop - uint8_t pin_read_cache_ = {0x00}; - /// Storage for last I2C error seen - esphome::i2c::ErrorCode last_error_; - /// Whether we want to override stored values on expander - bool restore_value_{false}; + uint8_t pin_read_flags_ = {0x00}; + /// Copy of last read values + uint8_t input_bits_ = {0x00}; + /// Copy of the mode value + uint8_t mode_value_{}; }; -/// Helper class to expose a CH422G pin as an internal input GPIO pin. +/// Helper class to expose a CH422G pin as a GPIO pin. class CH422GGPIOPin : public GPIOPin { public: - void setup() override; + void setup() override{}; void pin_mode(gpio::Flags flags) override; bool digital_read() override; void digital_write(bool value) override; @@ -57,13 +55,13 @@ class CH422GGPIOPin : public GPIOPin { void set_parent(CH422GComponent *parent) { parent_ = parent; } void set_pin(uint8_t pin) { pin_ = pin; } void set_inverted(bool inverted) { inverted_ = inverted; } - void set_flags(gpio::Flags flags) { flags_ = flags; } + void set_flags(gpio::Flags flags); protected: - CH422GComponent *parent_; - uint8_t pin_; - bool inverted_; - gpio::Flags flags_; + CH422GComponent *parent_{}; + uint8_t pin_{}; + bool inverted_{}; + gpio::Flags flags_{}; }; } // namespace ch422g diff --git a/tests/components/ch422g/common.yaml b/tests/components/ch422g/common.yaml index 02061bda59..d65956ecac 100644 --- a/tests/components/ch422g/common.yaml +++ b/tests/components/ch422g/common.yaml @@ -1,6 +1,5 @@ ch422g: - id: ch422g_hub - address: 0x24 binary_sensor: - platform: gpio @@ -11,10 +10,18 @@ binary_sensor: number: 1 mode: INPUT inverted: true +output: - platform: gpio - id: ch422g_output + id: ch422_out_0 pin: ch422g: ch422g_hub number: 0 mode: OUTPUT inverted: false + - platform: gpio + id: ch422_out_11 + pin: + ch422g: ch422g_hub + number: 11 + mode: OUTPUT_OPEN_DRAIN + inverted: true From 3df25a183a3a3d7018955e9335336791d704a4ed Mon Sep 17 00:00:00 2001 From: victorclaessen Date: Thu, 26 Sep 2024 23:57:51 +0200 Subject: [PATCH 2431/2607] Add clean_session as configurable option to the MQTT component (#7501) --- esphome/components/mqtt/__init__.py | 3 +++ esphome/components/mqtt/mqtt_client.cpp | 2 ++ esphome/components/mqtt/mqtt_client.h | 2 ++ esphome/const.py | 1 + tests/components/mqtt/common.yaml | 1 + 5 files changed, 9 insertions(+) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 240b407819..336d928f71 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CERTIFICATE_AUTHORITY, + CONF_CLEAN_SESSION, CONF_CLIENT_CERTIFICATE, CONF_CLIENT_CERTIFICATE_KEY, CONF_CLIENT_ID, @@ -209,6 +210,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_PORT, default=1883): cv.port, cv.Optional(CONF_USERNAME, default=""): cv.string, cv.Optional(CONF_PASSWORD, default=""): cv.string, + cv.Optional(CONF_CLEAN_SESSION, default=False): cv.boolean, cv.Optional(CONF_CLIENT_ID): cv.string, cv.SplitDefault(CONF_IDF_SEND_ASYNC, esp32_idf=False): cv.All( cv.boolean, cv.only_with_esp_idf @@ -325,6 +327,7 @@ async def to_code(config): cg.add(var.set_broker_port(config[CONF_PORT])) cg.add(var.set_username(config[CONF_USERNAME])) cg.add(var.set_password(config[CONF_PASSWORD])) + cg.add(var.set_clean_session(config[CONF_CLEAN_SESSION])) if CONF_CLIENT_ID in config: cg.add(var.set_client_id(config[CONF_CLIENT_ID])) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index c19b24c0cf..b5ac285026 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -147,6 +147,7 @@ void MQTTClientComponent::dump_config() { this->ip_.str().c_str()); ESP_LOGCONFIG(TAG, " Username: " LOG_SECRET("'%s'"), this->credentials_.username.c_str()); ESP_LOGCONFIG(TAG, " Client ID: " LOG_SECRET("'%s'"), this->credentials_.client_id.c_str()); + ESP_LOGCONFIG(TAG, " Clean Session: %s", YESNO(this->credentials_.clean_session)); if (this->is_discovery_ip_enabled()) { ESP_LOGCONFIG(TAG, " Discovery IP enabled"); } @@ -246,6 +247,7 @@ void MQTTClientComponent::start_connect_() { this->mqtt_backend_.disconnect(); this->mqtt_backend_.set_client_id(this->credentials_.client_id.c_str()); + this->mqtt_backend_.set_clean_session(this->credentials_.clean_session); const char *username = nullptr; if (!this->credentials_.username.empty()) username = this->credentials_.username.c_str(); diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index b0d3bbe66d..887800f201 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -51,6 +51,7 @@ struct MQTTCredentials { std::string username; std::string password; std::string client_id; ///< The client ID. Will automatically be truncated to 23 characters. + bool clean_session; ///< Whether the session will be cleaned or remembered between connects. }; /// Simple data struct for Home Assistant component availability. @@ -254,6 +255,7 @@ class MQTTClientComponent : public Component { void set_username(const std::string &username) { this->credentials_.username = username; } void set_password(const std::string &password) { this->credentials_.password = password; } void set_client_id(const std::string &client_id) { this->credentials_.client_id = client_id; } + void set_clean_session(const bool &clean_session) { this->credentials_.clean_session = clean_session; } void set_on_connect(mqtt_on_connect_callback_t &&callback); void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback); diff --git a/esphome/const.py b/esphome/const.py index 6e7bbdec98..40b7a1c419 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -120,6 +120,7 @@ CONF_CHANNELS = "channels" CONF_CHARACTERISTIC_UUID = "characteristic_uuid" CONF_CHECK = "check" CONF_CHIPSET = "chipset" +CONF_CLEAN_SESSION = "clean_session" CONF_CLEAR_IMPEDANCE = "clear_impedance" CONF_CLIENT_CERTIFICATE = "client_certificate" CONF_CLIENT_CERTIFICATE_KEY = "client_certificate_key" diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index b7d1655ec9..f7a727ab2f 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -10,6 +10,7 @@ mqtt: port: 1883 username: debug password: debug + clean_session: True client_id: someclient use_abbreviations: false discovery: true From 529ff4bd526c258069e388dcdd16bfc1b5c43535 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 26 Sep 2024 17:24:18 -0500 Subject: [PATCH 2432/2607] [wifi] Use custom MAC address if programmed (#7498) --- .../wifi/wifi_component_esp_idf.cpp | 7 ++- esphome/core/helpers.cpp | 45 ++++++++++++++++++- esphome/core/helpers.h | 8 ++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 6008acb95d..c430d160f2 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -130,11 +130,16 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi } void WiFiComponent::wifi_pre_setup_() { -#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC uint8_t mac[6]; +#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC get_mac_address_raw(mac); set_mac_address(mac); ESP_LOGV(TAG, "Use EFuse MAC without checking CRC: %s", get_mac_address_pretty().c_str()); +#else + if (has_custom_mac_address()) { + get_mac_address_raw(mac); + set_mac_address(mac); + } #endif esp_err_t err = esp_netif_init(); if (err != ERR_OK) { diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index e75b06ccd3..2e99b0df70 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -671,9 +671,17 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame // match the CRC that goes along with it. For those devices, this // work-around reads and uses the MAC address as-is from EFuse, // without doing the CRC check. - esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48); + if (has_custom_mac_address()) { + esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48); + } else { + esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48); + } #else - esp_efuse_mac_get_default(mac); + if (has_custom_mac_address()) { + esp_efuse_mac_get_custom(mac); + } else { + esp_efuse_mac_get_default(mac); + } #endif #elif defined(USE_ESP8266) wifi_get_macaddr(STATION_IF, mac); @@ -685,20 +693,53 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame // this should be an error, but that messes with CI checks. #error No mac address method defined #endif } + std::string get_mac_address() { uint8_t mac[6]; get_mac_address_raw(mac); return str_snprintf("%02x%02x%02x%02x%02x%02x", 12, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } + std::string get_mac_address_pretty() { uint8_t mac[6]; get_mac_address_raw(mac); return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } + #ifdef USE_ESP32 void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); } #endif +bool has_custom_mac_address() { +#ifdef USE_ESP32 + uint8_t mac[6]; +#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) + return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac); +#else + return (esp_efuse_mac_get_custom(mac) == ESP_OK) && mac_address_is_valid(mac); +#endif +#else + return false; +#endif +} + +bool mac_address_is_valid(const uint8_t *mac) { + bool is_all_zeros = true; + bool is_all_ones = true; + + for (uint8_t i = 0; i < 6; i++) { + if (mac[i] != 0) { + is_all_zeros = false; + } + } + for (uint8_t i = 0; i < 6; i++) { + if (mac[i] != 0xFF) { + is_all_ones = false; + } + } + return !(is_all_zeros || is_all_ones); +} + void delay_microseconds_safe(uint32_t us) { // avoids CPU locks that could trigger WDT or affect WiFi/BT stability uint32_t start = micros(); diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 3e6fe9433e..7df4b84230 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -635,6 +635,14 @@ std::string get_mac_address_pretty(); void set_mac_address(uint8_t *mac); #endif +/// Check if a custom MAC address is set (ESP32 & variants) +/// @return True if a custom MAC address is set (ESP32 & variants), else false +bool has_custom_mac_address(); + +/// Check if the MAC address is not all zeros or all ones +/// @return True if MAC is valid, else false +bool mac_address_is_valid(const uint8_t *mac); + /// Delay for the given amount of microseconds, possibly yielding to other processes during the wait. void delay_microseconds_safe(uint32_t us); From 023cb4937e2ee3abac2c7c46cc54f9705c46a795 Mon Sep 17 00:00:00 2001 From: zry98 Date: Mon, 30 Sep 2024 03:22:27 +0200 Subject: [PATCH 2433/2607] Add support for Sharp GP2Y1010AU0F PM2.5 sensor (#6007) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/gp2y1010au0f/__init__.py | 0 .../components/gp2y1010au0f/gp2y1010au0f.cpp | 67 +++++++++++++++++++ .../components/gp2y1010au0f/gp2y1010au0f.h | 52 ++++++++++++++ esphome/components/gp2y1010au0f/sensor.py | 61 +++++++++++++++++ .../gp2y1010au0f/test.esp32-idf.yaml | 16 +++++ 6 files changed, 197 insertions(+) create mode 100644 esphome/components/gp2y1010au0f/__init__.py create mode 100644 esphome/components/gp2y1010au0f/gp2y1010au0f.cpp create mode 100644 esphome/components/gp2y1010au0f/gp2y1010au0f.h create mode 100644 esphome/components/gp2y1010au0f/sensor.py create mode 100644 tests/components/gp2y1010au0f/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 1eb13a534b..3f5ff46c02 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -152,6 +152,7 @@ esphome/components/ft63x6/* @gpambrozio esphome/components/gcja5/* @gcormier esphome/components/gdk101/* @Szewcson esphome/components/globals/* @esphome/core +esphome/components/gp2y1010au0f/* @zry98 esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core esphome/components/gpio/one_wire/* @ssieb diff --git a/esphome/components/gp2y1010au0f/__init__.py b/esphome/components/gp2y1010au0f/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp b/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp new file mode 100644 index 0000000000..95b7653e51 --- /dev/null +++ b/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp @@ -0,0 +1,67 @@ +#include "gp2y1010au0f.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +#include + +namespace esphome { +namespace gp2y1010au0f { + +static const char *const TAG = "gp2y1010au0f"; +static const float MIN_VOLTAGE = 0.0f; +static const float MAX_VOLTAGE = 4.0f; + +void GP2Y1010AU0FSensor::dump_config() { + LOG_SENSOR("", "Sharp GP2Y1010AU0F PM2.5 Sensor", this); + ESP_LOGCONFIG(TAG, " Sampling duration: %" PRId32 " ms", this->sample_duration_); + ESP_LOGCONFIG(TAG, " ADC voltage multiplier: %.3f", this->voltage_multiplier_); + LOG_UPDATE_INTERVAL(this); +} + +void GP2Y1010AU0FSensor::update() { + is_sampling_ = true; + + this->set_timeout("read", this->sample_duration_, [this]() { + this->is_sampling_ = false; + if (this->num_samples_ == 0) + return; + + float mean = this->sample_sum_ / float(this->num_samples_); + ESP_LOGD(TAG, "ADC read voltage: %.3f V (mean from %" PRId32 " samples)", mean, this->num_samples_); + + // PM2.5 calculation + // ref: https://www.howmuchsnow.com/arduino/airquality/ + int16_t pm_2_5_value = 170 * mean; + this->publish_state(pm_2_5_value); + }); + + // reset readings + this->num_samples_ = 0; + this->sample_sum_ = 0.0f; +} + +void GP2Y1010AU0FSensor::loop() { + if (!this->is_sampling_) + return; + + // enable the internal IR LED + this->led_output_->turn_on(); + // wait for the sensor to stabilize + delayMicroseconds(this->sample_wait_before_); + // perform a single sample + float read_voltage = this->source_->sample(); + // disable the internal IR LED + this->led_output_->turn_off(); + + if (std::isnan(read_voltage)) + return; + read_voltage = read_voltage * this->voltage_multiplier_ - this->voltage_offset_; + if (read_voltage < MIN_VOLTAGE || read_voltage > MAX_VOLTAGE) + return; + + this->num_samples_++; + this->sample_sum_ += read_voltage; +} + +} // namespace gp2y1010au0f +} // namespace esphome diff --git a/esphome/components/gp2y1010au0f/gp2y1010au0f.h b/esphome/components/gp2y1010au0f/gp2y1010au0f.h new file mode 100644 index 0000000000..5ee58e68d2 --- /dev/null +++ b/esphome/components/gp2y1010au0f/gp2y1010au0f.h @@ -0,0 +1,52 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/components/output/binary_output.h" + +namespace esphome { +namespace gp2y1010au0f { + +class GP2Y1010AU0FSensor : public sensor::Sensor, public PollingComponent { + public: + void update() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override { + // after the base sensor has been initialized + return setup_priority::DATA - 1.0f; + } + + void set_adc_source(voltage_sampler::VoltageSampler *source) { source_ = source; } + void set_voltage_refs(float offset, float multiplier) { + this->voltage_offset_ = offset; + this->voltage_multiplier_ = multiplier; + } + void set_led_output(output::BinaryOutput *output) { led_output_ = output; } + + protected: + // duration in ms of the sampling phase + uint32_t sample_duration_ = 100; + // duration in us of the wait before sampling + // ref: https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y1010au_appl_e.pdf + uint32_t sample_wait_before_ = 280; + // duration in us of the wait after sampling + // it seems no need to delay on purpose since one ADC sampling takes longer than that (300-400 us on ESP8266) + // uint32_t sample_wait_after_ = 40; + // the sampling source to read voltage from + voltage_sampler::VoltageSampler *source_; + // ADC voltage reading offset + float voltage_offset_ = 0.0f; + // ADC voltage reading multiplier + float voltage_multiplier_ = 1.0f; + // the binary output to control the sampling LED + output::BinaryOutput *led_output_; + + float sample_sum_ = 0.0f; + uint32_t num_samples_ = 0; + bool is_sampling_ = false; +}; + +} // namespace gp2y1010au0f +} // namespace esphome diff --git a/esphome/components/gp2y1010au0f/sensor.py b/esphome/components/gp2y1010au0f/sensor.py new file mode 100644 index 0000000000..7e1bd277a6 --- /dev/null +++ b/esphome/components/gp2y1010au0f/sensor.py @@ -0,0 +1,61 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, voltage_sampler, output +from esphome.const import ( + CONF_SENSOR, + CONF_OUTPUT, + DEVICE_CLASS_PM25, + STATE_CLASS_MEASUREMENT, + UNIT_MICROGRAMS_PER_CUBIC_METER, + ICON_CHEMICAL_WEAPON, +) + +DEPENDENCIES = ["output"] +AUTO_LOAD = ["voltage_sampler"] +CODEOWNERS = ["@zry98"] + +CONF_ADC_VOLTAGE_OFFSET = "adc_voltage_offset" +CONF_ADC_VOLTAGE_MULTIPLIER = "adc_voltage_multiplier" + +gp2y1010au0f_ns = cg.esphome_ns.namespace("gp2y1010au0f") +GP2Y1010AU0FSensor = gp2y1010au0f_ns.class_( + "GP2Y1010AU0FSensor", sensor.Sensor, cg.PollingComponent +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + GP2Y1010AU0FSensor, + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_PM25, + state_class=STATE_CLASS_MEASUREMENT, + icon=ICON_CHEMICAL_WEAPON, + ) + .extend( + { + cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler), + cv.Optional(CONF_ADC_VOLTAGE_OFFSET, default=0.0): cv.float_, + cv.Optional(CONF_ADC_VOLTAGE_MULTIPLIER, default=1.0): cv.float_, + cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput), + } + ) + .extend(cv.polling_component_schema("60s")) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + + # the ADC sensor to read voltage from + adc_sensor = await cg.get_variable(config[CONF_SENSOR]) + cg.add(var.set_adc_source(adc_sensor)) + cg.add( + var.set_voltage_refs( + config[CONF_ADC_VOLTAGE_OFFSET], config[CONF_ADC_VOLTAGE_MULTIPLIER] + ) + ) + + # the binary output to control the module's internal IR LED + led_output = await cg.get_variable(config[CONF_OUTPUT]) + cg.add(var.set_led_output(led_output)) diff --git a/tests/components/gp2y1010au0f/test.esp32-idf.yaml b/tests/components/gp2y1010au0f/test.esp32-idf.yaml new file mode 100644 index 0000000000..eb5ad0ea67 --- /dev/null +++ b/tests/components/gp2y1010au0f/test.esp32-idf.yaml @@ -0,0 +1,16 @@ +sensor: + - platform: adc + pin: GPIO36 + id: adc_sensor + + - platform: gp2y1010au0f + sensor: adc_sensor + name: Dust Sensor + adc_voltage_offset: 0.2 + adc_voltage_multiplier: 3.3 + output: dust_sensor_led + +output: + - platform: gpio + id: dust_sensor_led + pin: GPIO32 From 49a3d385eb9f7b61457b97d87fe599ff4653f647 Mon Sep 17 00:00:00 2001 From: Nick Kinnan Date: Sun, 29 Sep 2024 18:59:12 -0700 Subject: [PATCH 2434/2607] Prevent rp2040 randomly breaking the build (#7507) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/wizard.py | 2 +- platformio.ini | 2 +- .../test_build_components/build_components_base.rp2040-ard.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/wizard.py b/esphome/wizard.py index 319fb31938..b1057189fd 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -92,7 +92,7 @@ rp2040: board: {board} framework: # Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git + platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c """ BK72XX_CONFIG = """ diff --git a/platformio.ini b/platformio.ini index e3593bf43f..fc38923f65 100644 --- a/platformio.ini +++ b/platformio.ini @@ -165,7 +165,7 @@ platform_packages = extends = common:arduino board_build.filesystem_size = 0.5m -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip diff --git a/tests/test_build_components/build_components_base.rp2040-ard.yaml b/tests/test_build_components/build_components_base.rp2040-ard.yaml index 6c6a27e0a7..f9815578c5 100644 --- a/tests/test_build_components/build_components_base.rp2040-ard.yaml +++ b/tests/test_build_components/build_components_base.rp2040-ard.yaml @@ -6,7 +6,7 @@ rp2040: board: rpipicow framework: # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git + platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c logger: level: VERY_VERBOSE From 20cb2e147fd6bae669facaeeaf967c588f4b55d1 Mon Sep 17 00:00:00 2001 From: Nick Kinnan Date: Sun, 29 Sep 2024 20:27:22 -0700 Subject: [PATCH 2435/2607] Make time dependency optional (#7425) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/datetime/__init__.py | 28 ++++++++++++------- esphome/components/datetime/datetime_base.h | 9 +++++- .../components/datetime/datetime_entity.cpp | 2 ++ esphome/components/datetime/datetime_entity.h | 2 ++ esphome/components/datetime/time_entity.cpp | 2 ++ esphome/components/datetime/time_entity.h | 2 ++ 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 5429121d56..55066006d3 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -26,7 +26,6 @@ from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@rfdarter", "@jesserockz"] -DEPENDENCIES = ["time"] IS_PLATFORM_COMPONENT = True @@ -62,20 +61,28 @@ DATETIME_MODES = [ ] -_DATETIME_SCHEMA = ( - cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) - .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) - .extend( +def _validate_time_present(config): + config = config.copy() + if CONF_ON_TIME in config and CONF_TIME_ID not in config: + time_id = cv.use_id(time.RealTimeClock)(None) + config[CONF_TIME_ID] = time_id + return config + + +_DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( + web_server.WEBSERVER_SORTING_SCHEMA, + cv.MQTT_COMMAND_COMPONENT_SCHEMA, + cv.Schema( { cv.Optional(CONF_ON_VALUE): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), } ), - cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), + cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock), } - ) -) + ), +).add_extra(_validate_time_present) def date_schema(class_: MockObjClass) -> cv.Schema: @@ -138,8 +145,9 @@ async def setup_datetime_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) - rtc = await cg.get_variable(config[CONF_TIME_ID]) - cg.add(var.set_rtc(rtc)) + if CONF_TIME_ID in config: + rtc = await cg.get_variable(config[CONF_TIME_ID]) + cg.add(var.set_rtc(rtc)) for conf in config.get(CONF_ON_TIME, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) diff --git a/esphome/components/datetime/datetime_base.h b/esphome/components/datetime/datetime_base.h index c8240390e3..dea34e6110 100644 --- a/esphome/components/datetime/datetime_base.h +++ b/esphome/components/datetime/datetime_base.h @@ -4,8 +4,9 @@ #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/time.h" - +#ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" +#endif namespace esphome { namespace datetime { @@ -19,23 +20,29 @@ class DateTimeBase : public EntityBase { void add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } +#ifdef USE_TIME void set_rtc(time::RealTimeClock *rtc) { this->rtc_ = rtc; } time::RealTimeClock *get_rtc() const { return this->rtc_; } +#endif protected: CallbackManager state_callback_; +#ifdef USE_TIME time::RealTimeClock *rtc_; +#endif bool has_state_{false}; }; +#ifdef USE_TIME class DateTimeStateTrigger : public Trigger { public: explicit DateTimeStateTrigger(DateTimeBase *parent) { parent->add_on_state_callback([this, parent]() { this->trigger(parent->state_as_esptime()); }); } }; +#endif } // namespace datetime } // namespace esphome diff --git a/esphome/components/datetime/datetime_entity.cpp b/esphome/components/datetime/datetime_entity.cpp index 9a61d341e4..f215b7acb5 100644 --- a/esphome/components/datetime/datetime_entity.cpp +++ b/esphome/components/datetime/datetime_entity.cpp @@ -192,6 +192,7 @@ void DateTimeEntityRestoreState::apply(DateTimeEntity *time) { time->publish_state(); } +#ifdef USE_TIME static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider // there has been a drastic time synchronization @@ -245,6 +246,7 @@ bool OnDateTimeTrigger::matches_(const ESPTime &time) const { time.day_of_month == this->parent_->day && time.hour == this->parent_->hour && time.minute == this->parent_->minute && time.second == this->parent_->second; } +#endif } // namespace datetime } // namespace esphome diff --git a/esphome/components/datetime/datetime_entity.h b/esphome/components/datetime/datetime_entity.h index d541fa96b1..27db84cf7e 100644 --- a/esphome/components/datetime/datetime_entity.h +++ b/esphome/components/datetime/datetime_entity.h @@ -134,6 +134,7 @@ template class DateTimeSetAction : public Action, public } }; +#ifdef USE_TIME class OnDateTimeTrigger : public Trigger<>, public Component, public Parented { public: void loop() override; @@ -143,6 +144,7 @@ class OnDateTimeTrigger : public Trigger<>, public Component, public Parented last_check_; }; +#endif } // namespace datetime } // namespace esphome diff --git a/esphome/components/datetime/time_entity.cpp b/esphome/components/datetime/time_entity.cpp index ea5e6684d0..db0094ae01 100644 --- a/esphome/components/datetime/time_entity.cpp +++ b/esphome/components/datetime/time_entity.cpp @@ -94,6 +94,7 @@ void TimeEntityRestoreState::apply(TimeEntity *time) { time->publish_state(); } +#ifdef USE_TIME static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider // there has been a drastic time synchronization @@ -145,6 +146,7 @@ bool OnTimeTrigger::matches_(const ESPTime &time) const { return time.is_valid() && time.hour == this->parent_->hour && time.minute == this->parent_->minute && time.second == this->parent_->second; } +#endif } // namespace datetime } // namespace esphome diff --git a/esphome/components/datetime/time_entity.h b/esphome/components/datetime/time_entity.h index 62e593d28a..f7e0a7ddd9 100644 --- a/esphome/components/datetime/time_entity.h +++ b/esphome/components/datetime/time_entity.h @@ -113,6 +113,7 @@ template class TimeSetAction : public Action, public Pare } }; +#ifdef USE_TIME class OnTimeTrigger : public Trigger<>, public Component, public Parented { public: void loop() override; @@ -122,6 +123,7 @@ class OnTimeTrigger : public Trigger<>, public Component, public Parented last_check_; }; +#endif } // namespace datetime } // namespace esphome From 01f5ca26dcf30b42fa9dac32130667b990f8b375 Mon Sep 17 00:00:00 2001 From: Darren Griffin Date: Mon, 30 Sep 2024 17:49:13 +0100 Subject: [PATCH 2436/2607] Add OHF logo to README (#7509) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bb6fb37d3a..da1b2b3650 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,5 @@ For issues, please go to [the issue tracker](https://github.com/esphome/issues/issues). For feature requests, please see [feature requests](https://github.com/esphome/feature-requests/issues). + +[![ESPHome - A project from the Open Home Foundation](https://www.openhomefoundation.org/badges/esphome.png)](https://www.openhomefoundation.org/) From 507d27e84a742c2115ecd5d9bf4db1ec0db7d2b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:48:36 +0200 Subject: [PATCH 2437/2607] Bump pypa/gh-action-pypi-publish from 1.10.1 to 1.10.2 (#7487) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 522de63360..d63f221ef5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.10.1 + uses: pypa/gh-action-pypi-publish@v1.10.2 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From 01e03b76a7d42507c514173f84bbe741e7ab4c60 Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Tue, 1 Oct 2024 00:00:40 +0200 Subject: [PATCH 2438/2607] tcs34725: optimize fetch time with burst read for RGB and clear values (#7494) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/tcs34725/tcs34725.cpp | 34 +++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index c9b2ae321a..9d682e094c 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -2,6 +2,7 @@ #include "esphome/core/log.h" #include "esphome/core/hal.h" #include +#include "esphome/core/helpers.h" namespace esphome { namespace tcs34725 { @@ -14,10 +15,7 @@ static const uint8_t TCS34725_REGISTER_ID = TCS34725_COMMAND_BIT | 0x12; static const uint8_t TCS34725_REGISTER_ATIME = TCS34725_COMMAND_BIT | 0x01; static const uint8_t TCS34725_REGISTER_CONTROL = TCS34725_COMMAND_BIT | 0x0F; static const uint8_t TCS34725_REGISTER_ENABLE = TCS34725_COMMAND_BIT | 0x00; -static const uint8_t TCS34725_REGISTER_CDATAL = TCS34725_COMMAND_BIT | 0x14; -static const uint8_t TCS34725_REGISTER_RDATAL = TCS34725_COMMAND_BIT | 0x16; -static const uint8_t TCS34725_REGISTER_GDATAL = TCS34725_COMMAND_BIT | 0x18; -static const uint8_t TCS34725_REGISTER_BDATAL = TCS34725_COMMAND_BIT | 0x1A; +static const uint8_t TCS34725_REGISTER_CRGBDATAL = TCS34725_COMMAND_BIT | 0x14; void TCS34725Component::setup() { ESP_LOGCONFIG(TAG, "Setting up TCS34725..."); @@ -181,27 +179,21 @@ void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, u } void TCS34725Component::update() { - uint16_t raw_c; - uint16_t raw_r; - uint16_t raw_g; - uint16_t raw_b; + uint8_t data[8]; // Buffer to hold the 8 bytes (2 bytes for each of the 4 channels) - if (this->read_data_register_(TCS34725_REGISTER_CDATAL, raw_c) != i2c::ERROR_OK) { - this->status_set_warning(); - return; - } - if (this->read_data_register_(TCS34725_REGISTER_RDATAL, raw_r) != i2c::ERROR_OK) { - this->status_set_warning(); - return; - } - if (this->read_data_register_(TCS34725_REGISTER_GDATAL, raw_g) != i2c::ERROR_OK) { - this->status_set_warning(); - return; - } - if (this->read_data_register_(TCS34725_REGISTER_BDATAL, raw_b) != i2c::ERROR_OK) { + // Perform burst + if (this->read_register(TCS34725_REGISTER_CRGBDATAL, data, 8) != i2c::ERROR_OK) { this->status_set_warning(); + ESP_LOGW(TAG, "Error reading TCS34725 sensor data"); return; } + + // Extract the data + uint16_t raw_c = encode_uint16(data[1], data[0]); // Clear channel + uint16_t raw_r = encode_uint16(data[3], data[2]); // Red channel + uint16_t raw_g = encode_uint16(data[5], data[4]); // Green channel + uint16_t raw_b = encode_uint16(data[7], data[6]); // Blue channel + ESP_LOGV(TAG, "Raw values clear=%d red=%d green=%d blue=%d", raw_c, raw_r, raw_g, raw_b); float channel_c; From c1a28ba5e249c83477f7d0a9bd000d65614db17e Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Tue, 1 Oct 2024 00:03:42 +0200 Subject: [PATCH 2439/2607] tcs34725: Remove IR compensation and improve illuminance and color temperature handling in extreme conditions (#7492) --- esphome/components/tcs34725/tcs34725.cpp | 82 +++++++++++++----------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 9d682e094c..0830004b5a 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -73,20 +73,21 @@ float TCS34725Component::get_setup_priority() const { return setup_priority::DAT * @return Color temperature in degrees Kelvin */ void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, uint16_t b, uint16_t c) { - float r2, g2, b2; /* RGB values minus IR component */ - float sat; /* Digital saturation level */ - float ir; /* Inferred IR content */ + float sat; /* Digital saturation level */ - this->illuminance_ = 0; // Assign 0 value before calculation - this->color_temperature_ = 0; + this->illuminance_ = NAN; + this->color_temperature_ = NAN; - const float ga = this->glass_attenuation_; // Glass Attenuation Factor - static const float DF = 310.f; // Device Factor - static const float R_COEF = 0.136f; // - static const float G_COEF = 1.f; // used in lux computation - static const float B_COEF = -0.444f; // - static const float CT_COEF = 3810.f; // Color Temperature Coefficient - static const float CT_OFFSET = 1391.f; // Color Temperatuer Offset + const float ga = this->glass_attenuation_; // Glass Attenuation Factor + static const float DF = 310.f; // Device Factor + static const float R_COEF = 0.136f; // + static const float G_COEF = 1.f; // used in lux computation + static const float B_COEF = -0.444f; // + static const float CT_COEF = 3810.f; // Color Temperature Coefficient + static const float CT_OFFSET = 1391.f; // Color Temperatuer Offset + static const float MAX_ILLUMINANCE = 100000.0f; // Cap illuminance at 100,000 lux + static const float MAX_COLOR_TEMPERATURE = 15000.0f; // Maximum expected color temperature in Kelvin + static const float MIN_COLOR_TEMPERATURE = 1000.0f; // Maximum reasonable color temperature in Kelvin if (c == 0) { return; @@ -137,45 +138,48 @@ void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, u if (c >= sat) { if (this->integration_time_auto_) { ESP_LOGI(TAG, "Saturation too high, sample discarded, autogain ongoing"); + return; } else { - ESP_LOGW( - TAG, - "Saturation too high, sample with saturation %.1f and clear %d treat values carefully or use grey filter", - sat, c); - } - } - - /* AMS RGB sensors have no IR channel, so the IR content must be */ - /* calculated indirectly. */ - ir = ((r + g + b) > c) ? (r + g + b - c) / 2 : 0; - - /* Remove the IR component from the raw RGB values */ - r2 = r - ir; - g2 = g - ir; - b2 = b - ir; - - // discarding super low values? not recemmonded, and avoided by using auto gain. - if (r2 == 0) { - // legacy code - if (!this->integration_time_auto_) { ESP_LOGW(TAG, - "No light detected on red channel, switch to auto gain or adjust timing, values will be unreliable"); + "Saturation too high, sample with saturation %.1f and clear %d lux/color temperature cannot reliably " + "calculated, reduce integration/gain or use a grey filter.", + sat, c); return; } } // Lux Calculation (DN40 3.2) - float g1 = R_COEF * r2 + G_COEF * g2 + B_COEF * b2; + float g1 = R_COEF * (float) r + G_COEF * (float) g + B_COEF * (float) b; float cpl = (this->integration_time_ * this->gain_) / (ga * DF); - this->illuminance_ = g1 / cpl; + + this->illuminance_ = std::max(g1 / cpl, 0.0f); + + if (this->illuminance_ > MAX_ILLUMINANCE) { + ESP_LOGW(TAG, "Calculated illuminance greater than limit (%f), setting to NAN", this->illuminance_); + this->illuminance_ = NAN; + return; + } + + if (r == 0) { + ESP_LOGW(TAG, "Red channel is zero, cannot compute color temperature"); + return; + } // Color Temperature Calculation (DN40) /* A simple method of measuring color temp is to use the ratio of blue */ - /* to red light, taking IR cancellation into account. */ - this->color_temperature_ = (CT_COEF * b2) / /** Color temp coefficient. */ - r2 + - CT_OFFSET; /** Color temp offset. */ + /* to red light. */ + + this->color_temperature_ = (CT_COEF * (float) b) / (float) r + CT_OFFSET; + + // Ensure the color temperature stays within reasonable bounds + if (this->color_temperature_ < MIN_COLOR_TEMPERATURE) { + ESP_LOGW(TAG, "Calculated color temperature value too low (%f), setting to NAN", this->color_temperature_); + this->color_temperature_ = NAN; + } else if (this->color_temperature_ > MAX_COLOR_TEMPERATURE) { + ESP_LOGW(TAG, "Calculated color temperature value too high (%f), setting to NAN", this->color_temperature_); + this->color_temperature_ = NAN; + } } void TCS34725Component::update() { From d5fa17c316d763fc2bac14958f752b1a521aead3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:37:08 +1300 Subject: [PATCH 2440/2607] [rp2040] Always use maxgerhardt platform fork (#7514) --- esphome/components/rp2040/__init__.py | 27 +++++++++---------- esphome/wizard.py | 3 --- platformio.ini | 2 +- .../build_components_base.rp2040-ard.yaml | 3 --- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 8f1d26f780..925acb629d 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -71,6 +71,14 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # return f"~1.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" +def _parse_platform_version(value): + value = cv.string(value) + if value.startswith("http"): + return value + + return f"https://github.com/maxgerhardt/platform-raspberrypi.git#{value}" + + # NOTE: Keep this in mind when updating the recommended version: # * The new version needs to be thoroughly validated before changing the # recommended version as otherwise a bunch of devices could be bricked @@ -82,10 +90,9 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4) -# The platformio/raspberrypi version to use for arduino frameworks -# - https://github.com/platformio/platform-raspberrypi/releases -# - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0) +# The raspberrypi platform version to use for arduino frameworks +# - https://github.com/maxgerhardt/platform-raspberrypi/tags +RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.2.0-gcc12" def _arduino_check_versions(value): @@ -111,7 +118,8 @@ def _arduino_check_versions(value): value[CONF_SOURCE] = source or _format_framework_arduino_version(version) value[CONF_PLATFORM_VERSION] = value.get( - CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) + CONF_PLATFORM_VERSION, + _parse_platform_version(RECOMMENDED_ARDUINO_PLATFORM_VERSION), ) if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: @@ -122,15 +130,6 @@ def _arduino_check_versions(value): return value -def _parse_platform_version(value): - try: - # if platform version is a valid version constraint, prefix the default package - cv.platformio_version_constraint(value) - return f"platformio/raspberrypi@{value}" - except cv.Invalid: - return value - - ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/wizard.py b/esphome/wizard.py index b1057189fd..eecbbdb172 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -90,9 +90,6 @@ esp32: RP2040_CONFIG = """ rp2040: board: {board} - framework: - # Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c """ BK72XX_CONFIG = """ diff --git a/platformio.ini b/platformio.ini index fc38923f65..bb122adc37 100644 --- a/platformio.ini +++ b/platformio.ini @@ -165,7 +165,7 @@ platform_packages = extends = common:arduino board_build.filesystem_size = 0.5m -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12 platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip diff --git a/tests/test_build_components/build_components_base.rp2040-ard.yaml b/tests/test_build_components/build_components_base.rp2040-ard.yaml index f9815578c5..4fb8d51333 100644 --- a/tests/test_build_components/build_components_base.rp2040-ard.yaml +++ b/tests/test_build_components/build_components_base.rp2040-ard.yaml @@ -4,9 +4,6 @@ esphome: rp2040: board: rpipicow - framework: - # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c logger: level: VERY_VERBOSE From 4332301dbbe64e07964bb47d9e12c90776abe0c1 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 24 Sep 2024 17:50:44 -0700 Subject: [PATCH 2441/2607] fix bl0906 reset energy action (#7488) Co-authored-by: Samuel Sieb --- esphome/components/bl0906/sensor.py | 5 +++-- tests/components/bl0906/common.yaml | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/esphome/components/bl0906/sensor.py b/esphome/components/bl0906/sensor.py index bc370c9252..42c6f06092 100644 --- a/esphome/components/bl0906/sensor.py +++ b/esphome/components/bl0906/sensor.py @@ -145,8 +145,9 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ), ) async def reset_energy_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var async def to_code(config): diff --git a/tests/components/bl0906/common.yaml b/tests/components/bl0906/common.yaml index 944791369c..29321a9471 100644 --- a/tests/components/bl0906/common.yaml +++ b/tests/components/bl0906/common.yaml @@ -8,6 +8,7 @@ uart: sensor: - platform: bl0906 + id: bl frequency: name: 'Frequency' temperature: @@ -60,3 +61,9 @@ sensor: name: 'Total_Energy' total_power: name: 'Total_Power' + +button: + - platform: template + id: reset + on_press: + - bl0906.reset_energy: bl From c2518cff89c60f3f9c37691e015132146b931a86 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:34:27 +1200 Subject: [PATCH 2442/2607] [config_validation] Fix bug with extras on schemas (#7497) --- esphome/voluptuous_schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/voluptuous_schema.py b/esphome/voluptuous_schema.py index 7f1573b443..15f9206f21 100644 --- a/esphome/voluptuous_schema.py +++ b/esphome/voluptuous_schema.py @@ -226,4 +226,6 @@ class _Schema(vol.Schema): if isinstance(schema, vol.Schema): schema = schema.schema ret = super().extend(schema, extra=extra) - return _Schema(ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas) + return _Schema( + ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas.copy() + ) From 050e2547ea714f4b72769f481f3e81a76fd719e0 Mon Sep 17 00:00:00 2001 From: Nick Kinnan Date: Sun, 29 Sep 2024 18:59:12 -0700 Subject: [PATCH 2443/2607] Prevent rp2040 randomly breaking the build (#7507) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/wizard.py | 2 +- platformio.ini | 2 +- .../test_build_components/build_components_base.rp2040-ard.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/wizard.py b/esphome/wizard.py index 319fb31938..b1057189fd 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -92,7 +92,7 @@ rp2040: board: {board} framework: # Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git + platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c """ BK72XX_CONFIG = """ diff --git a/platformio.ini b/platformio.ini index 7d912aaf54..583df7452c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -165,7 +165,7 @@ platform_packages = extends = common:arduino board_build.filesystem_size = 0.5m -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip diff --git a/tests/test_build_components/build_components_base.rp2040-ard.yaml b/tests/test_build_components/build_components_base.rp2040-ard.yaml index 6c6a27e0a7..f9815578c5 100644 --- a/tests/test_build_components/build_components_base.rp2040-ard.yaml +++ b/tests/test_build_components/build_components_base.rp2040-ard.yaml @@ -6,7 +6,7 @@ rp2040: board: rpipicow framework: # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git + platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c logger: level: VERY_VERBOSE From 748bc85bfe4edfe7945bb74b8616f1123332a9ae Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:37:08 +1300 Subject: [PATCH 2444/2607] [rp2040] Always use maxgerhardt platform fork (#7514) --- esphome/components/rp2040/__init__.py | 27 +++++++++---------- esphome/wizard.py | 3 --- platformio.ini | 2 +- .../build_components_base.rp2040-ard.yaml | 3 --- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 8f1d26f780..925acb629d 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -71,6 +71,14 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # return f"~1.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" +def _parse_platform_version(value): + value = cv.string(value) + if value.startswith("http"): + return value + + return f"https://github.com/maxgerhardt/platform-raspberrypi.git#{value}" + + # NOTE: Keep this in mind when updating the recommended version: # * The new version needs to be thoroughly validated before changing the # recommended version as otherwise a bunch of devices could be bricked @@ -82,10 +90,9 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4) -# The platformio/raspberrypi version to use for arduino frameworks -# - https://github.com/platformio/platform-raspberrypi/releases -# - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0) +# The raspberrypi platform version to use for arduino frameworks +# - https://github.com/maxgerhardt/platform-raspberrypi/tags +RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.2.0-gcc12" def _arduino_check_versions(value): @@ -111,7 +118,8 @@ def _arduino_check_versions(value): value[CONF_SOURCE] = source or _format_framework_arduino_version(version) value[CONF_PLATFORM_VERSION] = value.get( - CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) + CONF_PLATFORM_VERSION, + _parse_platform_version(RECOMMENDED_ARDUINO_PLATFORM_VERSION), ) if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: @@ -122,15 +130,6 @@ def _arduino_check_versions(value): return value -def _parse_platform_version(value): - try: - # if platform version is a valid version constraint, prefix the default package - cv.platformio_version_constraint(value) - return f"platformio/raspberrypi@{value}" - except cv.Invalid: - return value - - ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { diff --git a/esphome/wizard.py b/esphome/wizard.py index b1057189fd..eecbbdb172 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -90,9 +90,6 @@ esp32: RP2040_CONFIG = """ rp2040: board: {board} - framework: - # Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c """ BK72XX_CONFIG = """ diff --git a/platformio.ini b/platformio.ini index 583df7452c..26617a933b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -165,7 +165,7 @@ platform_packages = extends = common:arduino board_build.filesystem_size = 0.5m -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12 platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip diff --git a/tests/test_build_components/build_components_base.rp2040-ard.yaml b/tests/test_build_components/build_components_base.rp2040-ard.yaml index f9815578c5..4fb8d51333 100644 --- a/tests/test_build_components/build_components_base.rp2040-ard.yaml +++ b/tests/test_build_components/build_components_base.rp2040-ard.yaml @@ -4,9 +4,6 @@ esphome: rp2040: board: rpipicow - framework: - # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 - platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c logger: level: VERY_VERBOSE From f784e5c9f65401666ed7c676848c4ea66f506e91 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:33:40 +1300 Subject: [PATCH 2445/2607] Bump version to 2024.9.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 29084c8955..533b547bcf 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.9.1" +__version__ = "2024.9.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 215f26fbe41d75e5742a6e0b55dc01a10a348a38 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 1 Oct 2024 19:08:12 -0500 Subject: [PATCH 2446/2607] [CI] Remove ``sorted`` from library include dirs (#7526) --- script/clang-tidy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/clang-tidy b/script/clang-tidy index 5bb93846b2..a5da9fd3b0 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -98,7 +98,7 @@ def clang_options(idedata): cmd.extend(["-isystem", directory]) # add library include directories using -isystem to suppress their errors - for directory in sorted(set(idedata["includes"]["build"])): + for directory in set(idedata["includes"]["build"]): # skip our own directories, we add those later if ( not directory.startswith(f"{root_path}/") From d00e0eb2d6194be562219d1313d18d0236280307 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 1 Oct 2024 21:33:35 -0500 Subject: [PATCH 2447/2607] [wifi] Fix error message when no custom MAC is set (#7515) --- esphome/core/helpers.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 2e99b0df70..61fd23508e 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -44,9 +44,7 @@ #endif #ifdef USE_ESP32 #include "esp32/rom/crc.h" -#endif -#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) #include "esp_efuse.h" #include "esp_efuse_table.h" #endif @@ -713,10 +711,11 @@ void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); } bool has_custom_mac_address() { #ifdef USE_ESP32 uint8_t mac[6]; -#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) - return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac); + // do not use 'esp_efuse_mac_get_custom(mac)' because it drops an error in the logs whenever it fails +#ifndef USE_ESP32_VARIANT_ESP32 + return (esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac); #else - return (esp_efuse_mac_get_custom(mac) == ESP_OK) && mac_address_is_valid(mac); + return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac); #endif #else return false; From 0d80286bb3cbd8b0591e2789bf180cc2c05e8cab Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 2 Oct 2024 03:27:46 -0500 Subject: [PATCH 2448/2607] [esp32] Add ``ignore_efuse_custom_mac`` config var (#7527) --- esphome/components/esp32/__init__.py | 6 ++++++ esphome/const.py | 1 + esphome/core/helpers.cpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 9cb9ac257a..b7d3ef4a6d 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_COMPONENTS, CONF_ESPHOME, CONF_FRAMEWORK, + CONF_IGNORE_EFUSE_CUSTOM_MAC, CONF_IGNORE_EFUSE_MAC_CRC, CONF_NAME, CONF_PATH, @@ -401,6 +402,9 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( }, cv.Optional(CONF_ADVANCED, default={}): cv.Schema( { + cv.Optional( + CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False + ): cv.boolean, cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean, } ), @@ -526,6 +530,8 @@ async def to_code(config): for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) + if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: + cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_MAC_CRC]: cg.add_define("USE_ESP32_IGNORE_EFUSE_MAC_CRC") if (framework_ver.major, framework_ver.minor) >= (4, 4): diff --git a/esphome/const.py b/esphome/const.py index 40b7a1c419..830f139077 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -376,6 +376,7 @@ CONF_IDLE_ACTION = "idle_action" CONF_IDLE_LEVEL = "idle_level" CONF_IDLE_TIME = "idle_time" CONF_IF = "if" +CONF_IGNORE_EFUSE_CUSTOM_MAC = "ignore_efuse_custom_mac" CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc" CONF_IGNORE_OUT_OF_RANGE = "ignore_out_of_range" CONF_IGNORE_PIN_VALIDATION_ERROR = "ignore_pin_validation_error" diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 61fd23508e..492ab6dd1a 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -709,7 +709,7 @@ void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); } #endif bool has_custom_mac_address() { -#ifdef USE_ESP32 +#if defined(USE_ESP32) && !defined(USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC) uint8_t mac[6]; // do not use 'esp_efuse_mac_get_custom(mac)' because it drops an error in the logs whenever it fails #ifndef USE_ESP32_VARIANT_ESP32 From 361b6ab961e12634fc040ec11e45ab5ae39359f6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:27:32 +1300 Subject: [PATCH 2449/2607] [mics_4514] Move consts to consts.py (#7528) --- esphome/components/mics_4514/sensor.py | 37 ++++++++------------------ esphome/const.py | 6 +++++ 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/esphome/components/mics_4514/sensor.py b/esphome/components/mics_4514/sensor.py index 80c3524f66..59ccba235a 100644 --- a/esphome/components/mics_4514/sensor.py +++ b/esphome/components/mics_4514/sensor.py @@ -1,10 +1,14 @@ import esphome.codegen as cg +from esphome.components import i2c, sensor import esphome.config_validation as cv - -from esphome.components import sensor, i2c - from esphome.const import ( + CONF_AMMONIA, + CONF_CARBON_MONOXIDE, + CONF_ETHANOL, + CONF_HYDROGEN, CONF_ID, + CONF_METHANE, + CONF_NITROGEN_DIOXIDE, STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, ) @@ -12,13 +16,6 @@ from esphome.const import ( CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2c"] -CONF_CARBON_MONOXIDE = "carbon_monoxide" -CONF_NITROGEN_DIOXIDE = "nitrogen_dioxide" -CONF_METHANE = "methane" -CONF_ETHANOL = "ethanol" -CONF_HYDROGEN = "hydrogen" -CONF_AMMONIA = "ammonia" - mics_4514_ns = cg.esphome_ns.namespace("mics_4514") MICS4514Component = mics_4514_ns.class_( @@ -31,6 +28,7 @@ SENSORS = [ CONF_ETHANOL, CONF_HYDROGEN, CONF_AMMONIA, + CONF_NITROGEN_DIOXIDE, ] common_sensor_schema = sensor.sensor_schema( @@ -40,16 +38,7 @@ common_sensor_schema = sensor.sensor_schema( ) CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(MICS4514Component), - cv.Optional(CONF_NITROGEN_DIOXIDE): sensor.sensor_schema( - unit_of_measurement=UNIT_PARTS_PER_MILLION, - state_class=STATE_CLASS_MEASUREMENT, - accuracy_decimals=2, - ), - } - ) + cv.Schema({cv.GenerateID(): cv.declare_id(MICS4514Component)}) .extend({cv.Optional(sensor_type): common_sensor_schema for sensor_type in SENSORS}) .extend(i2c.i2c_device_schema(0x75)) .extend(cv.polling_component_schema("60s")) @@ -62,10 +51,6 @@ async def to_code(config): await i2c.register_i2c_device(var, config) for sensor_type in SENSORS: - if sensor_type in config: - sens = await sensor.new_sensor(config[sensor_type]) + if sensor_config := config.get(sensor_type): + sens = await sensor.new_sensor(sensor_config) cg.add(getattr(var, f"set_{sensor_type}_sensor")(sens)) - - if CONF_NITROGEN_DIOXIDE in config: - sens = await sensor.new_sensor(config[CONF_NITROGEN_DIOXIDE]) - cg.add(var.set_nitrogen_dioxide_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index 830f139077..bfb0167282 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -53,6 +53,7 @@ CONF_ALLOW_OTHER_USES = "allow_other_uses" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" CONF_AMBIENT_LIGHT = "ambient_light" +CONF_AMMONIA = "ammonia" CONF_ANALOG = "analog" CONF_AND = "and" CONF_ANGLE = "angle" @@ -110,6 +111,7 @@ CONF_CALIBRATE_LINEAR = "calibrate_linear" CONF_CALIBRATION = "calibration" CONF_CAPACITANCE = "capacitance" CONF_CAPACITY = "capacity" +CONF_CARBON_MONOXIDE = "carbon_monoxide" CONF_CARRIER_DUTY_PERCENT = "carrier_duty_percent" CONF_CARRIER_FREQUENCY = "carrier_frequency" CONF_CERTIFICATE = "certificate" @@ -263,6 +265,7 @@ CONF_ENUM_DATAPOINT = "enum_datapoint" CONF_EQUATION = "equation" CONF_ESP8266_DISABLE_SSL_SUPPORT = "esp8266_disable_ssl_support" CONF_ESPHOME = "esphome" +CONF_ETHANOL = "ethanol" CONF_ETHERNET = "ethernet" CONF_EVENT = "event" CONF_EVENT_TYPE = "event_type" @@ -361,6 +364,7 @@ CONF_HOURS = "hours" CONF_HSYNC_PIN = "hsync_pin" CONF_HUMIDITY = "humidity" CONF_HUMIDITY_SENSOR = "humidity_sensor" +CONF_HYDROGEN = "hydrogen" CONF_HYSTERESIS = "hysteresis" CONF_I2C = "i2c" CONF_I2C_ID = "i2c_id" @@ -477,6 +481,7 @@ CONF_MEDIA_PLAYER = "media_player" CONF_MEDIUM = "medium" CONF_MEMORY_BLOCKS = "memory_blocks" CONF_MESSAGE = "message" +CONF_METHANE = "methane" CONF_METHOD = "method" CONF_MICROPHONE = "microphone" CONF_MIN_BRIGHTNESS = "min_brightness" @@ -523,6 +528,7 @@ CONF_NBITS = "nbits" CONF_NEC = "nec" CONF_NETWORKS = "networks" CONF_NEW_PASSWORD = "new_password" +CONF_NITROGEN_DIOXIDE = "nitrogen_dioxide" CONF_NOISE_LEVEL = "noise_level" CONF_NUM_ATTEMPTS = "num_attempts" CONF_NUM_CHANNELS = "num_channels" From e57a1ff42d344d6da5fb0496145585ce25d14bb5 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 2 Oct 2024 19:54:12 +0100 Subject: [PATCH 2450/2607] =?UTF-8?q?Fix=20parsing=20of=20=C2=B5s=20time?= =?UTF-8?q?=20periods=20in=20config=20(#7495)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/config_validation.py | 1 + .../components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml | 8 ++++---- tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index e55879e37e..a7525a62dd 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -750,6 +750,7 @@ def time_period_str_unit(value): "ns": "nanoseconds", "nanoseconds": "nanoseconds", "us": "microseconds", + "µs": "microseconds", "microseconds": "microseconds", "ms": "milliseconds", "milliseconds": "milliseconds", diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml index b226d1de06..8d04d3370b 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml @@ -12,7 +12,7 @@ light: num_leds: 60 rmt_channel: 1 rgb_order: RGB - bit0_high: 100us - bit0_low: 100us - bit1_high: 100us - bit1_low: 100us + bit0_high: 100µs + bit0_low: 100µs + bit1_high: 100µs + bit1_low: 100µs diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml index d51a66451f..6e1763b339 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml @@ -12,7 +12,7 @@ light: num_leds: 60 rmt_channel: 2 rgb_order: RGB - bit0_high: 100us - bit0_low: 100us - bit1_high: 100us - bit1_low: 100us + bit0_high: 100µs + bit0_low: 100µs + bit1_high: 100µs + bit1_low: 100µs From 523eedbc51261ed1f1a330026139dd22e42c69d3 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Thu, 3 Oct 2024 02:34:12 +0200 Subject: [PATCH 2451/2607] [web_server] Expose detail=all on all components (#7531) --- esphome/components/web_server/web_server.cpp | 156 +++++++++++++++---- 1 file changed, 127 insertions(+), 29 deletions(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 3bb7eee8f1..dc27db2f41 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -219,9 +219,16 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM for (sensor::Sensor *obj : App.get_sensors()) { if (obj->get_object_id() != match.id) continue; - std::string data = this->sensor_json(obj, obj->state, DETAIL_STATE); - request->send(200, "application/json", data.c_str()); - return; + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->sensor_json(obj, obj->state, detail); + request->send(200, "application/json", data.c_str()); + return; + } } request->send(404); } @@ -257,9 +264,16 @@ void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const for (text_sensor::TextSensor *obj : App.get_text_sensors()) { if (obj->get_object_id() != match.id) continue; - std::string data = this->text_sensor_json(obj, obj->state, DETAIL_STATE); - request->send(200, "application/json", data.c_str()); - return; + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->text_sensor_json(obj, obj->state, detail); + request->send(200, "application/json", data.c_str()); + return; + } } request->send(404); } @@ -288,7 +302,12 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->switch_json(obj, obj->state, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->switch_json(obj, obj->state, detail); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { this->schedule_([obj]() { obj->toggle(); }); @@ -324,7 +343,15 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM for (button::Button *obj : App.get_buttons()) { if (obj->get_object_id() != match.id) continue; - if (match.method == "press") { + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->button_json(obj, detail); + request->send(200, "application/json", data.c_str()); + } else if (match.method == "press") { this->schedule_([obj]() { obj->press(); }); request->send(200); return; @@ -357,9 +384,16 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) { if (obj->get_object_id() != match.id) continue; - std::string data = this->binary_sensor_json(obj, obj->state, DETAIL_STATE); - request->send(200, "application/json", data.c_str()); - return; + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->binary_sensor_json(obj, obj->state, detail); + request->send(200, "application/json", data.c_str()); + return; + } } request->send(404); } @@ -388,7 +422,12 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->fan_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->fan_json(obj, detail); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { this->schedule_([obj]() { obj->toggle().perform(); }); @@ -466,7 +505,12 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->light_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->light_json(obj, detail); request->send(200, "application/json", data.c_str()); } else if (match.method == "toggle") { this->schedule_([obj]() { obj->toggle().perform(); }); @@ -577,9 +621,14 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->cover_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->cover_json(obj, detail); request->send(200, "application/json", data.c_str()); - continue; + return; } auto call = obj->make_call(); @@ -653,7 +702,12 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->number_json(obj, obj->state, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->number_json(obj, obj->state, detail); request->send(200, "application/json", data.c_str()); return; } @@ -717,8 +771,13 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat for (auto *obj : App.get_dates()) { if (obj->get_object_id() != match.id) continue; - if (request->method() == HTTP_GET) { - std::string data = this->date_json(obj, DETAIL_STATE); + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->date_json(obj, detail); request->send(200, "application/json", data.c_str()); return; } @@ -772,7 +831,12 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat if (obj->get_object_id() != match.id) continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->time_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->time_json(obj, detail); request->send(200, "application/json", data.c_str()); return; } @@ -825,7 +889,12 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur if (obj->get_object_id() != match.id) continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->datetime_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->datetime_json(obj, detail); request->send(200, "application/json", data.c_str()); return; } @@ -880,8 +949,13 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->text_json(obj, obj->state, DETAIL_STATE); - request->send(200, "text/json", data.c_str()); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->text_json(obj, obj->state, detail); + request->send(200, "application/json", data.c_str()); return; } if (match.method != "set") { @@ -995,11 +1069,15 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->climate_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->climate_json(obj, detail); request->send(200, "application/json", data.c_str()); return; } - if (match.method != "set") { request->send(404); return; @@ -1149,7 +1227,12 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->lock_json(obj, obj->state, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->lock_json(obj, obj->state, detail); request->send(200, "application/json", data.c_str()); } else if (match.method == "lock") { this->schedule_([obj]() { obj->lock(); }); @@ -1192,9 +1275,14 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->valve_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->valve_json(obj, detail); request->send(200, "application/json", data.c_str()); - continue; + return; } auto call = obj->make_call(); @@ -1257,7 +1345,12 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->alarm_control_panel_json(obj, obj->get_state(), detail); request->send(200, "application/json", data.c_str()); return; } @@ -1314,7 +1407,12 @@ void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlM continue; if (request->method() == HTTP_GET && match.method.empty()) { - std::string data = this->update_json(obj, DETAIL_STATE); + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->update_json(obj, detail); request->send(200, "application/json", data.c_str()); return; } From 1cf4818640212ad7f980ef7117739e51c0a35fb0 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Fri, 4 Oct 2024 03:07:49 -0500 Subject: [PATCH 2452/2607] [CI] Use a list when reading idedata for includes (#7535) --- script/clang-tidy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/clang-tidy b/script/clang-tidy index a5da9fd3b0..61199edce3 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -98,7 +98,7 @@ def clang_options(idedata): cmd.extend(["-isystem", directory]) # add library include directories using -isystem to suppress their errors - for directory in set(idedata["includes"]["build"]): + for directory in list(idedata["includes"]["build"]): # skip our own directories, we add those later if ( not directory.startswith(f"{root_path}/") From 0a62106b7bb52dd95d93cf2825edd8065be4821d Mon Sep 17 00:00:00 2001 From: guillempages Date: Sat, 5 Oct 2024 09:07:32 +0200 Subject: [PATCH 2453/2607] [image] Use "puremagic" instead of "magic" python module (#7536) --- esphome/components/image/__init__.py | 9 ++++----- requirements.txt | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index e80ba4498f..c72417bcda 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -6,7 +6,7 @@ import logging from pathlib import Path import re -from magic import Magic +import puremagic from esphome import core, external_files import esphome.codegen as cg @@ -237,8 +237,8 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) def load_svg_image(file: bytes, resize: tuple[int, int]): - # Local import only to allow "validate_pillow_installed" to run *before* importing it - # This import is only needed in case of SVG images; adding it + # Local imports only to allow "validate_pillow_installed" to run *before* importing it + # cairosvg is only needed in case of SVG images; adding it # to the top would force configurations not using SVG to also have it # installed for no reason. from cairosvg import svg2png @@ -281,8 +281,7 @@ async def to_code(config): except Exception as e: raise core.EsphomeError(f"Could not load image file {path}: {e}") - mime = Magic(mime=True) - file_type = mime.from_buffer(file_contents) + file_type = puremagic.from_string(file_contents, mime=True) resize = config.get(CONF_RESIZE) if "svg" in file_type: diff --git a/requirements.txt b/requirements.txt index 3e658de8ad..3ffd364d87 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ click==8.1.7 esphome-dashboard==20240620.0 aioesphomeapi==24.6.2 zeroconf==0.132.2 -python-magic==0.4.27 +puremagic==1.27 ruamel.yaml==0.18.6 # dashboard_import # esp-idf requires this, but doesn't bundle it by default From b3cff566eb1ba79eb86a2b31df30e18691c9f241 Mon Sep 17 00:00:00 2001 From: guillempages Date: Sun, 6 Oct 2024 00:44:18 +0200 Subject: [PATCH 2454/2607] [lvgl] Remap image to img in "set_style_*" (#7546) --- esphome/components/lvgl/styles.py | 5 +++-- tests/components/lvgl/lvgl-package.yaml | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/lvgl/styles.py b/esphome/components/lvgl/styles.py index 26c2694a52..030db5fd22 100644 --- a/esphome/components/lvgl/styles.py +++ b/esphome/components/lvgl/styles.py @@ -12,7 +12,7 @@ from .defines import ( ) from .helpers import add_lv_use from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable -from .schemas import ALL_STYLES +from .schemas import ALL_STYLES, STYLE_REMAP from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map from .widgets.obj import obj_spec @@ -31,7 +31,8 @@ async def styles_to_code(config): value = await validator.process(value) if isinstance(value, list): value = "|".join(value) - lv.call(f"style_set_{prop}", svar, literal(value)) + remapped_prop = STYLE_REMAP.get(prop, prop) + lv.call(f"style_set_{remapped_prop}", svar, literal(value)) async def theme_to_code(config): diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index a3ed3047be..2b72f31770 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -67,6 +67,9 @@ lvgl: border_width: 2 pad_all: 4 align: center + - id: image_recolor + image_recolor: 0x10ca1e + image_recolor_opa: cover touchscreens: - touchscreen_id: tft_touch From 6a8e88b1cc5c47f23c394cf01328a96f907d671b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 6 Oct 2024 12:49:52 -0700 Subject: [PATCH 2455/2607] CSE7766 needs even parity (#7549) --- esphome/components/cse7766/sensor.py | 2 +- tests/components/cse7766/test.esp32-ard.yaml | 1 + tests/components/cse7766/test.esp32-c3-ard.yaml | 1 + tests/components/cse7766/test.esp32-c3-idf.yaml | 1 + tests/components/cse7766/test.esp32-idf.yaml | 1 + tests/components/cse7766/test.esp8266-ard.yaml | 1 + tests/components/cse7766/test.rp2040-ard.yaml | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index ecb59c4b5f..b5b11a661e 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -79,7 +79,7 @@ CONFIG_SCHEMA = cv.Schema( } ).extend(uart.UART_DEVICE_SCHEMA) FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( - "cse7766", baud_rate=4800, require_rx=True + "cse7766", baud_rate=4800, parity="EVEN", require_rx=True ) diff --git a/tests/components/cse7766/test.esp32-ard.yaml b/tests/components/cse7766/test.esp32-ard.yaml index f94cd0f7d8..5542b52824 100644 --- a/tests/components/cse7766/test.esp32-ard.yaml +++ b/tests/components/cse7766/test.esp32-ard.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 16 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 diff --git a/tests/components/cse7766/test.esp32-c3-ard.yaml b/tests/components/cse7766/test.esp32-c3-ard.yaml index 432cc0a80e..d27c9d4463 100644 --- a/tests/components/cse7766/test.esp32-c3-ard.yaml +++ b/tests/components/cse7766/test.esp32-c3-ard.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 5 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 diff --git a/tests/components/cse7766/test.esp32-c3-idf.yaml b/tests/components/cse7766/test.esp32-c3-idf.yaml index 432cc0a80e..d27c9d4463 100644 --- a/tests/components/cse7766/test.esp32-c3-idf.yaml +++ b/tests/components/cse7766/test.esp32-c3-idf.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 5 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 diff --git a/tests/components/cse7766/test.esp32-idf.yaml b/tests/components/cse7766/test.esp32-idf.yaml index f94cd0f7d8..5542b52824 100644 --- a/tests/components/cse7766/test.esp32-idf.yaml +++ b/tests/components/cse7766/test.esp32-idf.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 16 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 diff --git a/tests/components/cse7766/test.esp8266-ard.yaml b/tests/components/cse7766/test.esp8266-ard.yaml index 432cc0a80e..d27c9d4463 100644 --- a/tests/components/cse7766/test.esp8266-ard.yaml +++ b/tests/components/cse7766/test.esp8266-ard.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 5 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 diff --git a/tests/components/cse7766/test.rp2040-ard.yaml b/tests/components/cse7766/test.rp2040-ard.yaml index 432cc0a80e..d27c9d4463 100644 --- a/tests/components/cse7766/test.rp2040-ard.yaml +++ b/tests/components/cse7766/test.rp2040-ard.yaml @@ -5,6 +5,7 @@ uart: rx_pin: number: 5 baud_rate: 4800 + parity: EVEN sensor: - platform: cse7766 From e31a96bfe2392e68411019cdc57f0d0b75d65783 Mon Sep 17 00:00:00 2001 From: Tobias Hoff Date: Sun, 6 Oct 2024 21:53:57 +0200 Subject: [PATCH 2456/2607] Allow use of all pulse count unit channels if needed. (#7550) --- .../components/pulse_counter/pulse_counter_sensor.cpp | 9 ++++++++- esphome/components/pulse_counter/pulse_counter_sensor.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.cpp b/esphome/components/pulse_counter/pulse_counter_sensor.cpp index 281a61a66a..bd3e4fcbef 100644 --- a/esphome/components/pulse_counter/pulse_counter_sensor.cpp +++ b/esphome/components/pulse_counter/pulse_counter_sensor.cpp @@ -53,12 +53,19 @@ pulse_counter_t BasicPulseCounterStorage::read_raw_value() { #ifdef HAS_PCNT bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) { static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0; + static pcnt_channel_t next_pcnt_channel = PCNT_CHANNEL_0; this->pin = pin; this->pin->setup(); this->pcnt_unit = next_pcnt_unit; + this->pcnt_channel = next_pcnt_channel; next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1); + if (int(next_pcnt_unit) >= PCNT_UNIT_0 + PCNT_UNIT_MAX) { + next_pcnt_unit = PCNT_UNIT_0; + next_pcnt_channel = pcnt_channel_t(int(next_pcnt_channel) + 1); + } ESP_LOGCONFIG(TAG, " PCNT Unit Number: %u", this->pcnt_unit); + ESP_LOGCONFIG(TAG, " PCNT Channel Number: %u", this->pcnt_channel); pcnt_count_mode_t rising = PCNT_COUNT_DIS, falling = PCNT_COUNT_DIS; switch (this->rising_edge_mode) { @@ -94,7 +101,7 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) { .counter_h_lim = 0, .counter_l_lim = 0, .unit = this->pcnt_unit, - .channel = PCNT_CHANNEL_0, + .channel = this->pcnt_channel, }; esp_err_t error = pcnt_unit_config(&pcnt_config); if (error != ESP_OK) { diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.h b/esphome/components/pulse_counter/pulse_counter_sensor.h index ef9f73f95c..fc3d8711d1 100644 --- a/esphome/components/pulse_counter/pulse_counter_sensor.h +++ b/esphome/components/pulse_counter/pulse_counter_sensor.h @@ -55,6 +55,7 @@ struct HwPulseCounterStorage : public PulseCounterStorageBase { pulse_counter_t read_raw_value() override; pcnt_unit_t pcnt_unit; + pcnt_channel_t pcnt_channel; }; #endif From 949e61db8d6c7642784ee79325ed7f1c49b1596c Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Oct 2024 15:00:09 -0500 Subject: [PATCH 2457/2607] [bang-bang] Remove ``assert()`` (#7533) --- esphome/components/bang_bang/bang_bang_climate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/esphome/components/bang_bang/bang_bang_climate.cpp b/esphome/components/bang_bang/bang_bang_climate.cpp index b34764907f..aed97b2890 100644 --- a/esphome/components/bang_bang/bang_bang_climate.cpp +++ b/esphome/components/bang_bang/bang_bang_climate.cpp @@ -157,8 +157,11 @@ void BangBangClimate::switch_to_action_(climate::ClimateAction action) { default: trig = nullptr; } - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } else { + ESP_LOGW(TAG, "trig not set - unsupported action"); + } this->action = action; this->prev_trigger_ = trig; this->publish_state(); From 1c0ee5ae6b499d38c656dac2cc3725c3bc8e52e3 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Oct 2024 15:01:11 -0500 Subject: [PATCH 2458/2607] [thermostat] Remove ``assert()``s (#7544) --- .../thermostat/thermostat_climate.cpp | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp index 26be6ba53a..f7b3410df9 100644 --- a/esphome/components/thermostat/thermostat_climate.cpp +++ b/esphome/components/thermostat/thermostat_climate.cpp @@ -502,8 +502,9 @@ void ThermostatClimate::switch_to_action_(climate::ClimateAction action, bool pu } this->action = action; this->prev_action_trigger_ = trig; - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } // if enabled, call the fan_only action with cooling/heating actions if (trig_fan != nullptr) { ESP_LOGVV(TAG, "Calling FAN_ONLY action with HEATING/COOLING action"); @@ -564,7 +565,6 @@ void ThermostatClimate::trigger_supplemental_action_() { } if (trig != nullptr) { - assert(trig != nullptr); trig->trigger(); } } @@ -634,8 +634,9 @@ void ThermostatClimate::switch_to_fan_mode_(climate::ClimateFanMode fan_mode, bo this->prev_fan_mode_trigger_ = nullptr; } this->start_timer_(thermostat::TIMER_FAN_MODE); - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } this->prev_fan_mode_ = fan_mode; this->prev_fan_mode_trigger_ = trig; } @@ -678,8 +679,9 @@ void ThermostatClimate::switch_to_mode_(climate::ClimateMode mode, bool publish_ mode = climate::CLIMATE_MODE_HEAT_COOL; // trig = this->auto_mode_trigger_; } - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } this->mode = mode; this->prev_mode_ = mode; this->prev_mode_trigger_ = trig; @@ -718,8 +720,9 @@ void ThermostatClimate::switch_to_swing_mode_(climate::ClimateSwingMode swing_mo swing_mode = climate::CLIMATE_SWING_OFF; // trig = this->swing_mode_off_trigger_; } - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } this->swing_mode = swing_mode; this->prev_swing_mode_ = swing_mode; this->prev_swing_mode_trigger_ = trig; @@ -867,8 +870,9 @@ void ThermostatClimate::check_temperature_change_trigger_() { } // trigger the action Trigger<> *trig = this->temperature_change_trigger_; - assert(trig != nullptr); - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } } bool ThermostatClimate::cooling_required_() { @@ -998,9 +1002,10 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) { this->preset.value() != preset) { // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; - assert(trig != nullptr); this->preset = preset; - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } this->refresh(); ESP_LOGI(TAG, "Preset %s applied", LOG_STR_ARG(climate::climate_preset_to_string(preset))); @@ -1023,9 +1028,10 @@ void ThermostatClimate::change_custom_preset_(const std::string &custom_preset) this->custom_preset.value() != custom_preset) { // Fire any preset changed trigger if defined Trigger<> *trig = this->preset_change_trigger_; - assert(trig != nullptr); this->custom_preset = custom_preset; - trig->trigger(); + if (trig != nullptr) { + trig->trigger(); + } this->refresh(); ESP_LOGI(TAG, "Custom preset %s applied", custom_preset.c_str()); From 56e305f986170bc4667c4d4a40fd41b8f262f6d0 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Oct 2024 15:01:43 -0500 Subject: [PATCH 2459/2607] [bedjet_codec] Remove ``assert()`` (#7543) --- esphome/components/bedjet/bedjet_codec.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/bedjet/bedjet_codec.cpp b/esphome/components/bedjet/bedjet_codec.cpp index 7e90621235..9a312e226c 100644 --- a/esphome/components/bedjet/bedjet_codec.cpp +++ b/esphome/components/bedjet/bedjet_codec.cpp @@ -13,8 +13,10 @@ float bedjet_temp_to_f(const uint8_t temp) { /** Cleans up the packet before sending. */ BedjetPacket *BedjetCodec::clean_packet_() { - // So far no commands require more than 2 bytes of data. - assert(this->packet_.data_length <= 2); + // So far no commands require more than 2 bytes of data + if (this->packet_.data_length > 2) { + ESP_LOGW(TAG, "Packet may be malformed"); + } for (int i = this->packet_.data_length; i < 2; i++) { this->packet_.data[i] = '\0'; } From 9f85d99a2291e8b78aa0afe007e5bcdbbbaf50bd Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Oct 2024 15:59:42 -0500 Subject: [PATCH 2460/2607] [audio_dac] [aic3204] Add new component + platform (#7505) --- CODEOWNERS | 2 + esphome/components/aic3204/__init__.py | 0 esphome/components/aic3204/aic3204.cpp | 173 ++++++++++++++++++ esphome/components/aic3204/aic3204.h | 88 +++++++++ esphome/components/aic3204/audio_dac.py | 52 ++++++ esphome/components/aic3204/automation.h | 23 +++ esphome/components/audio_dac/__init__.py | 57 ++++++ esphome/components/audio_dac/audio_dac.h | 23 +++ esphome/components/audio_dac/automation.h | 43 +++++ tests/components/aic3204/common.yaml | 15 ++ tests/components/aic3204/test.esp32-ard.yaml | 5 + .../components/aic3204/test.esp32-c3-ard.yaml | 5 + .../components/aic3204/test.esp32-c3-idf.yaml | 5 + tests/components/aic3204/test.esp32-idf.yaml | 5 + .../components/aic3204/test.esp8266-ard.yaml | 5 + 15 files changed, 501 insertions(+) create mode 100644 esphome/components/aic3204/__init__.py create mode 100644 esphome/components/aic3204/aic3204.cpp create mode 100644 esphome/components/aic3204/aic3204.h create mode 100644 esphome/components/aic3204/audio_dac.py create mode 100644 esphome/components/aic3204/automation.h create mode 100644 esphome/components/audio_dac/__init__.py create mode 100644 esphome/components/audio_dac/audio_dac.h create mode 100644 esphome/components/audio_dac/automation.h create mode 100644 tests/components/aic3204/common.yaml create mode 100644 tests/components/aic3204/test.esp32-ard.yaml create mode 100644 tests/components/aic3204/test.esp32-c3-ard.yaml create mode 100644 tests/components/aic3204/test.esp32-c3-idf.yaml create mode 100644 tests/components/aic3204/test.esp32-idf.yaml create mode 100644 tests/components/aic3204/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 3f5ff46c02..db48e25743 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,6 +24,7 @@ esphome/components/ade7953_i2c/* @angelnu esphome/components/ade7953_spi/* @angelnu esphome/components/ads1118/* @solomondg1 esphome/components/ags10/* @mak-42 +esphome/components/aic3204/* @kbx81 esphome/components/airthings_ble/* @jeromelaban esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau esphome/components/airthings_wave_mini/* @ncareau @@ -47,6 +48,7 @@ esphome/components/at581x/* @X-Ryl669 esphome/components/atc_mithermometer/* @ahpohl esphome/components/atm90e26/* @danieltwagner esphome/components/atm90e32/* @circuitsetup @descipher +esphome/components/audio_dac/* @kbx81 esphome/components/b_parasite/* @rbaron esphome/components/ballu/* @bazuchan esphome/components/bang_bang/* @OttoWinter diff --git a/esphome/components/aic3204/__init__.py b/esphome/components/aic3204/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/aic3204/aic3204.cpp b/esphome/components/aic3204/aic3204.cpp new file mode 100644 index 0000000000..0560f2366b --- /dev/null +++ b/esphome/components/aic3204/aic3204.cpp @@ -0,0 +1,173 @@ +#include "aic3204.h" + +#include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace aic3204 { + +static const char *const TAG = "aic3204"; + +#define ERROR_CHECK(err, msg) \ + if (!(err)) { \ + ESP_LOGE(TAG, msg); \ + this->mark_failed(); \ + return; \ + } + +void AIC3204::setup() { + ESP_LOGCONFIG(TAG, "Setting up AIC3204..."); + + // Set register page to 0 + ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed"); + // Initiate SW reset (PLL is powered off as part of reset) + ERROR_CHECK(this->write_byte(AIC3204_SW_RST, 0x01), "Software reset failed"); + // *** Program clock settings *** + // Default is CODEC_CLKIN is from MCLK pin. Don't need to change this. + // MDAC*NDAC*FOSR*48Khz = mClk (24.576 MHz when the XMOS is expecting 48kHz audio) + // (See page 51 of https://www.ti.com/lit/ml/slaa557/slaa557.pdf) + // We do need MDAC*DOSR/32 >= the resource compute level for the processing block + // So here 2*128/32 = 8, which is equal to processing block 1 's resource compute + // See page 5 of https://www.ti.com/lit/an/slaa404c/slaa404c.pdf for the workflow + // for determining these settings. + + // Power up NDAC and set to 2 + ERROR_CHECK(this->write_byte(AIC3204_NDAC, 0x82), "Set NDAC failed"); + // Power up MDAC and set to 2 + ERROR_CHECK(this->write_byte(AIC3204_MDAC, 0x82), "Set MDAC failed"); + // Program DOSR = 128 + ERROR_CHECK(this->write_byte(AIC3204_DOSR, 0x80), "Set DOSR failed"); + // Set Audio Interface Config: I2S, 32 bits, DOUT always driving + ERROR_CHECK(this->write_byte(AIC3204_CODEC_IF, 0x30), "Set CODEC_IF failed"); + // For I2S Firmware only, set SCLK/MFP3 pin as Audio Data In + ERROR_CHECK(this->write_byte(AIC3204_SCLK_MFP3, 0x02), "Set SCLK/MFP3 failed"); + ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_4, 0x01), "Set AUDIO_IF_4 failed"); + ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_5, 0x01), "Set AUDIO_IF_5 failed"); + // Program the DAC processing block to be used - PRB_P1 + ERROR_CHECK(this->write_byte(AIC3204_DAC_SIG_PROC, 0x01), "Set DAC_SIG_PROC failed"); + + // *** Select Page 1 *** + ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x01), "Set page 1 failed"); + // Enable the internal AVDD_LDO: + ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x09), "Set LDO_CTRL failed"); + // *** Program Analog Blocks *** + // Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO + ERROR_CHECK(this->write_byte(AIC3204_PWR_CFG, 0x08), "Set PWR_CFG failed"); + // Enable Master Analog Power Control + ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x01), "Set LDO_CTRL failed"); + // Page 125: Common mode control register, set d6 to 1 to make the full chip common mode = 0.75 v + // We are using the internal AVdd regulator with a nominal output of 1.72 V (see LDO_CTRL_REGISTER on page 123) + // Page 86 says to only set the common mode voltage to 0.9 v if AVdd >= 1.8... but it isn't on our hardware + // We also adjust the HPL and HPR gains to -2dB gian later in this config flow compensate (see page 47) + // (All pages refer to the TLV320AIC3204 Application Reference Guide) + ERROR_CHECK(this->write_byte(AIC3204_CM_CTRL, 0x40), "Set CM_CTRL failed"); + // *** Set PowerTune Modes *** + // Set the Left & Right DAC PowerTune mode to PTM_P3/4. Use Class-AB driver. + ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG1, 0x00), "Set PLAY_CFG1 failed"); + ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG2, 0x00), "Set PLAY_CFG2 failed"); + // Set the REF charging time to 40ms + ERROR_CHECK(this->write_byte(AIC3204_REF_STARTUP, 0x01), "Set REF_STARTUP failed"); + // HP soft stepping settings for optimal pop performance at power up + // Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling + // capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. + ERROR_CHECK(this->write_byte(AIC3204_HP_START, 0x25), "Set HP_START failed"); + // Route Left DAC to HPL + ERROR_CHECK(this->write_byte(AIC3204_HPL_ROUTE, 0x08), "Set HPL_ROUTE failed"); + // Route Right DAC to HPR + ERROR_CHECK(this->write_byte(AIC3204_HPR_ROUTE, 0x08), "Set HPR_ROUTE failed"); + // Route Left DAC to LOL + ERROR_CHECK(this->write_byte(AIC3204_LOL_ROUTE, 0x08), "Set LOL_ROUTE failed"); + // Route Right DAC to LOR + ERROR_CHECK(this->write_byte(AIC3204_LOR_ROUTE, 0x08), "Set LOR_ROUTE failed"); + + // Unmute HPL and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register) + ERROR_CHECK(this->write_byte(AIC3204_HPL_GAIN, 0x3e), "Set HPL_GAIN failed"); + // Unmute HPR and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register) + ERROR_CHECK(this->write_byte(AIC3204_HPR_GAIN, 0x3e), "Set HPR_GAIN failed"); + // Unmute LOL and set gain to 0dB + ERROR_CHECK(this->write_byte(AIC3204_LOL_DRV_GAIN, 0x00), "Set LOL_DRV_GAIN failed"); + // Unmute LOR and set gain to 0dB + ERROR_CHECK(this->write_byte(AIC3204_LOR_DRV_GAIN, 0x00), "Set LOR_DRV_GAIN failed"); + + // Power up HPL and HPR, LOL and LOR drivers + ERROR_CHECK(this->write_byte(AIC3204_OP_PWR_CTRL, 0x3C), "Set OP_PWR_CTRL failed"); + + // Wait for 2.5 sec for soft stepping to take effect before attempting power-up + this->set_timeout(2500, [this]() { + // *** Power Up DAC *** + // Select Page 0 + ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set PAGE_CTRL failed"); + // Power up the Left and Right DAC Channels. Route Left data to Left DAC and Right data to Right DAC. + // DAC Vol control soft step 1 step per DAC word clock. + ERROR_CHECK(this->write_byte(AIC3204_DAC_CH_SET1, 0xd4), "Set DAC_CH_SET1 failed"); + // Set left and right DAC digital volume control + ERROR_CHECK(this->write_volume_(), "Set volume failed"); + // Unmute left and right channels + ERROR_CHECK(this->write_mute_(), "Set mute failed"); + }); +} + +void AIC3204::dump_config() { + ESP_LOGCONFIG(TAG, "AIC3204:"); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with AIC3204 failed"); + } +} + +bool AIC3204::set_mute_off() { + this->is_muted_ = false; + return this->write_mute_(); +} + +bool AIC3204::set_mute_on() { + this->is_muted_ = true; + return this->write_mute_(); +} + +bool AIC3204::set_auto_mute_mode(uint8_t auto_mute_mode) { + this->auto_mute_mode_ = auto_mute_mode & 0x07; + ESP_LOGVV(TAG, "Setting auto_mute_mode to 0x%.2x", this->auto_mute_mode_); + return this->write_mute_(); +} + +bool AIC3204::set_volume(float volume) { + this->volume_ = clamp(volume, 0.0, 1.0); + return this->write_volume_(); +} + +bool AIC3204::is_muted() { return this->is_muted_; } + +float AIC3204::volume() { return this->volume_; } + +bool AIC3204::write_mute_() { + uint8_t mute_mode_byte = this->auto_mute_mode_ << 4; // auto-mute control is bits 4-6 + mute_mode_byte |= this->is_muted_ ? 0x0c : 0x00; // mute bits are 2-3 + if (!this->write_byte(AIC3204_PAGE_CTRL, 0x00) || !this->write_byte(AIC3204_DAC_CH_SET2, mute_mode_byte)) { + ESP_LOGE(TAG, "Writing mute modes failed"); + return false; + } + return true; +} + +bool AIC3204::write_volume_() { + const int8_t dvc_min_byte = -127; + const int8_t dvc_max_byte = 48; + + int8_t volume_byte = dvc_min_byte + (this->volume_ * (dvc_max_byte - dvc_min_byte)); + volume_byte = clamp(volume_byte, dvc_min_byte, dvc_max_byte); + + ESP_LOGVV(TAG, "Setting volume to 0x%.2x", volume_byte & 0xFF); + + if ((!this->write_byte(AIC3204_PAGE_CTRL, 0x00)) || (!this->write_byte(AIC3204_DACL_VOL_D, volume_byte)) || + (!this->write_byte(AIC3204_DACR_VOL_D, volume_byte))) { + ESP_LOGE(TAG, "Writing volume failed"); + return false; + } + return true; +} + +} // namespace aic3204 +} // namespace esphome diff --git a/esphome/components/aic3204/aic3204.h b/esphome/components/aic3204/aic3204.h new file mode 100644 index 0000000000..783a58a2b9 --- /dev/null +++ b/esphome/components/aic3204/aic3204.h @@ -0,0 +1,88 @@ +#pragma once + +#include "esphome/components/audio_dac/audio_dac.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace aic3204 { + +// TLV320AIC3204 Register Addresses +// Page 0 +static const uint8_t AIC3204_PAGE_CTRL = 0x00; // Register 0 - Page Control +static const uint8_t AIC3204_SW_RST = 0x01; // Register 1 - Software Reset +static const uint8_t AIC3204_CLK_PLL1 = 0x04; // Register 4 - Clock Setting Register 1, Multiplexers +static const uint8_t AIC3204_CLK_PLL2 = 0x05; // Register 5 - Clock Setting Register 2, P and R values +static const uint8_t AIC3204_CLK_PLL3 = 0x06; // Register 6 - Clock Setting Register 3, J values +static const uint8_t AIC3204_NDAC = 0x0B; // Register 11 - NDAC Divider Value +static const uint8_t AIC3204_MDAC = 0x0C; // Register 12 - MDAC Divider Value +static const uint8_t AIC3204_DOSR = 0x0E; // Register 14 - DOSR Divider Value (LS Byte) +static const uint8_t AIC3204_NADC = 0x12; // Register 18 - NADC Divider Value +static const uint8_t AIC3204_MADC = 0x13; // Register 19 - MADC Divider Value +static const uint8_t AIC3204_AOSR = 0x14; // Register 20 - AOSR Divider Value +static const uint8_t AIC3204_CODEC_IF = 0x1B; // Register 27 - CODEC Interface Control +static const uint8_t AIC3204_AUDIO_IF_4 = 0x1F; // Register 31 - Audio Interface Setting Register 4 +static const uint8_t AIC3204_AUDIO_IF_5 = 0x20; // Register 32 - Audio Interface Setting Register 5 +static const uint8_t AIC3204_SCLK_MFP3 = 0x38; // Register 56 - SCLK/MFP3 Function Control +static const uint8_t AIC3204_DAC_SIG_PROC = 0x3C; // Register 60 - DAC Sig Processing Block Control +static const uint8_t AIC3204_ADC_SIG_PROC = 0x3D; // Register 61 - ADC Sig Processing Block Control +static const uint8_t AIC3204_DAC_CH_SET1 = 0x3F; // Register 63 - DAC Channel Setup 1 +static const uint8_t AIC3204_DAC_CH_SET2 = 0x40; // Register 64 - DAC Channel Setup 2 +static const uint8_t AIC3204_DACL_VOL_D = 0x41; // Register 65 - DAC Left Digital Vol Control +static const uint8_t AIC3204_DACR_VOL_D = 0x42; // Register 66 - DAC Right Digital Vol Control +static const uint8_t AIC3204_DRC_ENABLE = 0x44; +static const uint8_t AIC3204_ADC_CH_SET = 0x51; // Register 81 - ADC Channel Setup +static const uint8_t AIC3204_ADC_FGA_MUTE = 0x52; // Register 82 - ADC Fine Gain Adjust/Mute + +// Page 1 +static const uint8_t AIC3204_PWR_CFG = 0x01; // Register 1 - Power Config +static const uint8_t AIC3204_LDO_CTRL = 0x02; // Register 2 - LDO Control +static const uint8_t AIC3204_PLAY_CFG1 = 0x03; // Register 3 - Playback Config 1 +static const uint8_t AIC3204_PLAY_CFG2 = 0x04; // Register 4 - Playback Config 2 +static const uint8_t AIC3204_OP_PWR_CTRL = 0x09; // Register 9 - Output Driver Power Control +static const uint8_t AIC3204_CM_CTRL = 0x0A; // Register 10 - Common Mode Control +static const uint8_t AIC3204_HPL_ROUTE = 0x0C; // Register 12 - HPL Routing Select +static const uint8_t AIC3204_HPR_ROUTE = 0x0D; // Register 13 - HPR Routing Select +static const uint8_t AIC3204_LOL_ROUTE = 0x0E; // Register 14 - LOL Routing Selection +static const uint8_t AIC3204_LOR_ROUTE = 0x0F; // Register 15 - LOR Routing Selection +static const uint8_t AIC3204_HPL_GAIN = 0x10; // Register 16 - HPL Driver Gain +static const uint8_t AIC3204_HPR_GAIN = 0x11; // Register 17 - HPR Driver Gain +static const uint8_t AIC3204_LOL_DRV_GAIN = 0x12; // Register 18 - LOL Driver Gain Setting +static const uint8_t AIC3204_LOR_DRV_GAIN = 0x13; // Register 19 - LOR Driver Gain Setting +static const uint8_t AIC3204_HP_START = 0x14; // Register 20 - Headphone Driver Startup +static const uint8_t AIC3204_LPGA_P_ROUTE = 0x34; // Register 52 - Left PGA Positive Input Route +static const uint8_t AIC3204_LPGA_N_ROUTE = 0x36; // Register 54 - Left PGA Negative Input Route +static const uint8_t AIC3204_RPGA_P_ROUTE = 0x37; // Register 55 - Right PGA Positive Input Route +static const uint8_t AIC3204_RPGA_N_ROUTE = 0x39; // Register 57 - Right PGA Negative Input Route +static const uint8_t AIC3204_LPGA_VOL = 0x3B; // Register 59 - Left PGA Volume +static const uint8_t AIC3204_RPGA_VOL = 0x3C; // Register 60 - Right PGA Volume +static const uint8_t AIC3204_ADC_PTM = 0x3D; // Register 61 - ADC Power Tune Config +static const uint8_t AIC3204_AN_IN_CHRG = 0x47; // Register 71 - Analog Input Quick Charging Config +static const uint8_t AIC3204_REF_STARTUP = 0x7B; // Register 123 - Reference Power Up Config + +class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + bool set_mute_off() override; + bool set_mute_on() override; + bool set_auto_mute_mode(uint8_t auto_mute_mode); + bool set_volume(float volume) override; + + bool is_muted() override; + float volume() override; + + protected: + bool write_mute_(); + bool write_volume_(); + + uint8_t auto_mute_mode_{0}; + float volume_{0}; +}; + +} // namespace aic3204 +} // namespace esphome diff --git a/esphome/components/aic3204/audio_dac.py b/esphome/components/aic3204/audio_dac.py new file mode 100644 index 0000000000..da7a54df54 --- /dev/null +++ b/esphome/components/aic3204/audio_dac.py @@ -0,0 +1,52 @@ +from esphome import automation +import esphome.codegen as cg +from esphome.components import i2c +from esphome.components.audio_dac import AudioDac +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_MODE + +CODEOWNERS = ["@kbx81"] +DEPENDENCIES = ["i2c"] + +aic3204_ns = cg.esphome_ns.namespace("aic3204") +AIC3204 = aic3204_ns.class_("AIC3204", AudioDac, cg.Component, i2c.I2CDevice) + +SetAutoMuteAction = aic3204_ns.class_("SetAutoMuteAction", automation.Action) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(AIC3204), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x18)) +) + + +SET_AUTO_MUTE_ACTION_SCHEMA = cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(AIC3204), + cv.Required(CONF_MODE): cv.templatable(cv.int_range(max=7, min=0)), + }, + key=CONF_MODE, +) + + +@automation.register_action( + "aic3204.set_auto_mute_mode", SetAutoMuteAction, SET_AUTO_MUTE_ACTION_SCHEMA +) +async def aic3204_set_volume_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config.get(CONF_MODE), args, int) + cg.add(var.set_auto_mute_mode(template_)) + + return var + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/aic3204/automation.h b/esphome/components/aic3204/automation.h new file mode 100644 index 0000000000..416a88fa12 --- /dev/null +++ b/esphome/components/aic3204/automation.h @@ -0,0 +1,23 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "aic3204.h" + +namespace esphome { +namespace aic3204 { + +template class SetAutoMuteAction : public Action { + public: + explicit SetAutoMuteAction(AIC3204 *aic3204) : aic3204_(aic3204) {} + + TEMPLATABLE_VALUE(uint8_t, auto_mute_mode) + + void play(Ts... x) override { this->aic3204_->set_auto_mute_mode(this->auto_mute_mode_.value(x...)); } + + protected: + AIC3204 *aic3204_; +}; + +} // namespace aic3204 +} // namespace esphome diff --git a/esphome/components/audio_dac/__init__.py b/esphome/components/audio_dac/__init__.py new file mode 100644 index 0000000000..978ed195bd --- /dev/null +++ b/esphome/components/audio_dac/__init__.py @@ -0,0 +1,57 @@ +from esphome import automation +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_VOLUME +from esphome.core import coroutine_with_priority + +CODEOWNERS = ["@kbx81"] +IS_PLATFORM_COMPONENT = True + +audio_dac_ns = cg.esphome_ns.namespace("audio_dac") +AudioDac = audio_dac_ns.class_("AudioDac") + +MuteOffAction = audio_dac_ns.class_("MuteOffAction", automation.Action) +MuteOnAction = audio_dac_ns.class_("MuteOnAction", automation.Action) +SetVolumeAction = audio_dac_ns.class_("SetVolumeAction", automation.Action) + + +MUTE_ACTION_SCHEMA = maybe_simple_id( + { + cv.GenerateID(): cv.use_id(AudioDac), + } +) + +SET_VOLUME_ACTION_SCHEMA = cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(AudioDac), + cv.Required(CONF_VOLUME): cv.templatable(cv.percentage), + }, + key=CONF_VOLUME, +) + + +@automation.register_action("audio_dac.mute_off", MuteOffAction, MUTE_ACTION_SCHEMA) +@automation.register_action("audio_dac.mute_on", MuteOnAction, MUTE_ACTION_SCHEMA) +async def audio_dac_mute_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@automation.register_action( + "audio_dac.set_volume", SetVolumeAction, SET_VOLUME_ACTION_SCHEMA +) +async def audio_dac_set_volume_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config.get(CONF_VOLUME), args, float) + cg.add(var.set_volume(template_)) + + return var + + +@coroutine_with_priority(100.0) +async def to_code(config): + cg.add_define("USE_AUDIO_DAC") + cg.add_global(audio_dac_ns.using) diff --git a/esphome/components/audio_dac/audio_dac.h b/esphome/components/audio_dac/audio_dac.h new file mode 100644 index 0000000000..a62d17b849 --- /dev/null +++ b/esphome/components/audio_dac/audio_dac.h @@ -0,0 +1,23 @@ +#pragma once + +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace audio_dac { + +class AudioDac { + public: + virtual bool set_mute_off() = 0; + virtual bool set_mute_on() = 0; + virtual bool set_volume(float volume) = 0; + + virtual bool is_muted() = 0; + virtual float volume() = 0; + + protected: + bool is_muted_{false}; +}; + +} // namespace audio_dac +} // namespace esphome diff --git a/esphome/components/audio_dac/automation.h b/esphome/components/audio_dac/automation.h new file mode 100644 index 0000000000..b6cf2acaf4 --- /dev/null +++ b/esphome/components/audio_dac/automation.h @@ -0,0 +1,43 @@ +#pragma once + +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "audio_dac.h" + +namespace esphome { +namespace audio_dac { + +template class MuteOffAction : public Action { + public: + explicit MuteOffAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {} + + void play(Ts... x) override { this->audio_dac_->set_mute_off(); } + + protected: + AudioDac *audio_dac_; +}; + +template class MuteOnAction : public Action { + public: + explicit MuteOnAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {} + + void play(Ts... x) override { this->audio_dac_->set_mute_on(); } + + protected: + AudioDac *audio_dac_; +}; + +template class SetVolumeAction : public Action { + public: + explicit SetVolumeAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {} + + TEMPLATABLE_VALUE(float, volume) + + void play(Ts... x) override { this->audio_dac_->set_volume(this->volume_.value(x...)); } + + protected: + AudioDac *audio_dac_; +}; + +} // namespace audio_dac +} // namespace esphome diff --git a/tests/components/aic3204/common.yaml b/tests/components/aic3204/common.yaml new file mode 100644 index 0000000000..6e939bd260 --- /dev/null +++ b/tests/components/aic3204/common.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - audio_dac.mute_off: + - audio_dac.mute_on: + - audio_dac.set_volume: + volume: 50% + +i2c: + - id: i2c_aic3204 + scl: ${scl_pin} + sda: ${sda_pin} + +audio_dac: + - platform: aic3204 diff --git a/tests/components/aic3204/test.esp32-ard.yaml b/tests/components/aic3204/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/aic3204/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/aic3204/test.esp32-c3-ard.yaml b/tests/components/aic3204/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/aic3204/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/aic3204/test.esp32-c3-idf.yaml b/tests/components/aic3204/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/aic3204/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/aic3204/test.esp32-idf.yaml b/tests/components/aic3204/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/aic3204/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/aic3204/test.esp8266-ard.yaml b/tests/components/aic3204/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/aic3204/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml From e87169805cf9e38e55241529df479498bf61e3fb Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 6 Oct 2024 16:02:53 -0500 Subject: [PATCH 2461/2607] [wifi] Replace ``USE_ESP32_IGNORE_EFUSE_MAC_CRC`` with IDF's ``CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR`` (#7502) --- esphome/components/esp32/__init__.py | 16 +++++++++++++--- .../components/wifi/wifi_component_esp_idf.cpp | 6 ------ esphome/core/helpers.cpp | 8 ++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index b7d3ef4a6d..8a73f2020d 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -53,6 +53,7 @@ from .const import ( # noqa KEY_SDKCONFIG_OPTIONS, KEY_SUBMODULES, KEY_VARIANT, + VARIANT_ESP32, VARIANT_FRIENDLY, VARIANTS, ) @@ -376,6 +377,15 @@ def final_validate(config): f"Please specify {CONF_FLASH_SIZE} within esp32 configuration only" ) + if ( + config[CONF_VARIANT] != VARIANT_ESP32 + and CONF_ADVANCED in (conf_fw := config[CONF_FRAMEWORK]) + and CONF_IGNORE_EFUSE_MAC_CRC in conf_fw[CONF_ADVANCED] + ): + raise cv.Invalid( + f"{CONF_IGNORE_EFUSE_MAC_CRC} is not supported on {config[CONF_VARIANT]}" + ) + return config @@ -405,7 +415,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( cv.Optional( CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False ): cv.boolean, - cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean, + cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC): cv.boolean, } ), cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list( @@ -532,8 +542,8 @@ async def to_code(config): if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") - if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_MAC_CRC]: - cg.add_define("USE_ESP32_IGNORE_EFUSE_MAC_CRC") + if conf[CONF_ADVANCED].get(CONF_IGNORE_EFUSE_MAC_CRC): + add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) if (framework_ver.major, framework_ver.minor) >= (4, 4): add_idf_sdkconfig_option( "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index c430d160f2..0f2e181e31 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -131,16 +131,10 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi void WiFiComponent::wifi_pre_setup_() { uint8_t mac[6]; -#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC - get_mac_address_raw(mac); - set_mac_address(mac); - ESP_LOGV(TAG, "Use EFuse MAC without checking CRC: %s", get_mac_address_pretty().c_str()); -#else if (has_custom_mac_address()) { get_mac_address_raw(mac); set_mac_address(mac); } -#endif esp_err_t err = esp_netif_init(); if (err != ERR_OK) { ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err)); diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 492ab6dd1a..dca35819ff 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -662,13 +662,9 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame static const uint8_t esphome_host_mac_address[6] = USE_ESPHOME_HOST_MAC_ADDRESS; memcpy(mac, esphome_host_mac_address, sizeof(esphome_host_mac_address)); #elif defined(USE_ESP32) -#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) +#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) // When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default - // returns the 802.15.4 EUI-64 address. Read directly from eFuse instead. - // On some devices, the MAC address that is burnt into EFuse does not - // match the CRC that goes along with it. For those devices, this - // work-around reads and uses the MAC address as-is from EFuse, - // without doing the CRC check. + // returns the 802.15.4 EUI-64 address, so we read directly from eFuse instead. if (has_custom_mac_address()) { esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48); } else { From 239eadb89581083d349bd38dd7a37653afd65e29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:34:03 +1300 Subject: [PATCH 2462/2607] Bump docker/setup-buildx-action from 3.6.1 to 3.7.1 in the docker-actions group across 1 directory (#7542) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 891367d16a..f003e5d24c 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -46,7 +46,7 @@ jobs: with: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Set up QEMU uses: docker/setup-qemu-action@v3.2.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d63f221ef5..210879b50e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,7 +90,7 @@ jobs: python-version: "3.9" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Set up QEMU if: matrix.platform != 'linux/amd64' uses: docker/setup-qemu-action@v3.2.0 @@ -184,7 +184,7 @@ jobs: merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Log in to docker hub if: matrix.registry == 'dockerhub' From fbd600f43f5740cba0efd723236933ca5effdedd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:34:17 +1300 Subject: [PATCH 2463/2607] Bump pypa/gh-action-pypi-publish from 1.10.2 to 1.10.3 (#7541) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 210879b50e..8995c500ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.10.2 + uses: pypa/gh-action-pypi-publish@v1.10.3 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From fc7628cdeaa8138244b98d1c0adbeb40d296c0f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:34:38 +1300 Subject: [PATCH 2464/2607] Bump docker/build-push-action from 6.7.0 to 6.9.0 in /.github/actions/build-image (#7511) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index d277ec06c7..5c686605c3 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 env: DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_RECORD_UPLOAD: false @@ -72,7 +72,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 env: DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_RECORD_UPLOAD: false From 390299894e2b15a8c5ab90919f33a7ec41595880 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 7 Oct 2024 00:53:49 +0200 Subject: [PATCH 2465/2607] [code-quality] fix clang-tidy md5 and hmac_md5 (#7325) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/hmac_md5/hmac_md5.cpp | 2 ++ esphome/components/hmac_md5/hmac_md5.h | 3 ++- esphome/components/md5/__init__.py | 6 ++++++ esphome/components/md5/md5.cpp | 2 ++ esphome/components/md5/md5.h | 2 ++ esphome/core/defines.h | 1 + 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/esphome/components/hmac_md5/hmac_md5.cpp b/esphome/components/hmac_md5/hmac_md5.cpp index 90bf91882f..d766a55fab 100644 --- a/esphome/components/hmac_md5/hmac_md5.cpp +++ b/esphome/components/hmac_md5/hmac_md5.cpp @@ -1,6 +1,7 @@ #include #include #include "hmac_md5.h" +#ifdef USE_MD5 #include "esphome/core/helpers.h" namespace esphome { @@ -54,3 +55,4 @@ bool HmacMD5::equals_hex(const char *expected) { return this->ohash_.equals_hex( } // namespace hmac_md5 } // namespace esphome +#endif diff --git a/esphome/components/hmac_md5/hmac_md5.h b/esphome/components/hmac_md5/hmac_md5.h index e6a97ad2e3..b83b9d5421 100644 --- a/esphome/components/hmac_md5/hmac_md5.h +++ b/esphome/components/hmac_md5/hmac_md5.h @@ -1,8 +1,8 @@ #pragma once #include "esphome/core/defines.h" +#ifdef USE_MD5 #include "esphome/components/md5/md5.h" - #include namespace esphome { @@ -46,3 +46,4 @@ class HmacMD5 { } // namespace hmac_md5 } // namespace esphome +#endif diff --git a/esphome/components/md5/__init__.py b/esphome/components/md5/__init__.py index f70ffa9520..1af9ee0b29 100644 --- a/esphome/components/md5/__init__.py +++ b/esphome/components/md5/__init__.py @@ -1 +1,7 @@ +import esphome.codegen as cg + CODEOWNERS = ["@esphome/core"] + + +async def to_code(config): + cg.add_define("USE_MD5") diff --git a/esphome/components/md5/md5.cpp b/esphome/components/md5/md5.cpp index 620b6749f3..31f52634be 100644 --- a/esphome/components/md5/md5.cpp +++ b/esphome/components/md5/md5.cpp @@ -1,6 +1,7 @@ #include #include #include "md5.h" +#ifdef USE_MD5 #include "esphome/core/helpers.h" namespace esphome { @@ -65,3 +66,4 @@ bool MD5Digest::equals_hex(const char *expected) { } // namespace md5 } // namespace esphome +#endif diff --git a/esphome/components/md5/md5.h b/esphome/components/md5/md5.h index 4ec8a8a12c..cb6accf46f 100644 --- a/esphome/components/md5/md5.h +++ b/esphome/components/md5/md5.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/defines.h" +#ifdef USE_MD5 #ifdef USE_ESP_IDF #include "esp_rom_md5.h" @@ -66,3 +67,4 @@ class MD5Digest { } // namespace md5 } // namespace esphome +#endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index bf676107c7..ca3db0ad56 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -50,6 +50,7 @@ #define USE_LVGL_KEYBOARD #define USE_LVGL_ROTARY_ENCODER #define USE_LVGL_TOUCHSCREEN +#define USE_MD5 #define USE_MDNS #define USE_MEDIA_PLAYER #define USE_MQTT From cbc03aae803118de3f09437ebb52e018c4467fdb Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 7 Oct 2024 00:55:11 +0200 Subject: [PATCH 2466/2607] [code-quality] fix clang-tidy api (#7279) --- esphome/components/api/api_connection.cpp | 2 ++ esphome/components/api/api_connection.h | 4 +++- esphome/components/api/api_frame_helper.cpp | 3 ++- esphome/components/api/api_frame_helper.h | 3 ++- esphome/components/api/api_server.cpp | 2 ++ esphome/components/api/api_server.h | 4 +++- esphome/components/api/custom_api_device.h | 5 +++-- esphome/components/api/homeassistant_service.h | 7 ++++--- esphome/components/api/list_entities.cpp | 2 ++ esphome/components/api/list_entities.h | 5 +++-- esphome/components/api/subscribe_state.cpp | 2 ++ esphome/components/api/subscribe_state.h | 5 +++-- 12 files changed, 31 insertions(+), 13 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index e28b244722..bb55a2ccf6 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1,4 +1,5 @@ #include "api_connection.h" +#ifdef USE_API #include #include #include @@ -1568,3 +1569,4 @@ void APIConnection::on_fatal_error() { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index f176cf7c56..043aaee421 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -1,12 +1,13 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_API #include "api_frame_helper.h" #include "api_pb2.h" #include "api_pb2_service.h" #include "api_server.h" #include "esphome/core/application.h" #include "esphome/core/component.h" -#include "esphome/core/defines.h" #include @@ -268,3 +269,4 @@ class APIConnection : public APIServerConnection { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index f4b18a1fd6..62f375508c 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -1,5 +1,5 @@ #include "api_frame_helper.h" - +#ifdef USE_API #include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" @@ -1028,3 +1028,4 @@ APIError APIPlaintextFrameHelper::shutdown(int how) { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index bf4872d2d6..56d8bf1973 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -5,7 +5,7 @@ #include #include "esphome/core/defines.h" - +#ifdef USE_API #ifdef USE_API_NOISE #include "noise/protocol.h" #endif @@ -190,3 +190,4 @@ class APIPlaintextFrameHelper : public APIFrameHelper { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 0fde3e47af..f16b5a13cf 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -1,4 +1,5 @@ #include "api_server.h" +#ifdef USE_API #include #include "api_connection.h" #include "esphome/components/network/util.h" @@ -403,3 +404,4 @@ void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlP } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 899eaede49..42e0b1048a 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -1,5 +1,7 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_API #include "api_noise_context.h" #include "api_pb2.h" #include "api_pb2_service.h" @@ -7,7 +9,6 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/controller.h" -#include "esphome/core/defines.h" #include "esphome/core/log.h" #include "list_entities.h" #include "subscribe_state.h" @@ -153,3 +154,4 @@ template class APIConnectedCondition : public Condition { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/custom_api_device.h b/esphome/components/api/custom_api_device.h index 845a35fc54..1a8e189f41 100644 --- a/esphome/components/api/custom_api_device.h +++ b/esphome/components/api/custom_api_device.h @@ -1,9 +1,9 @@ #pragma once #include -#include "user_services.h" #include "api_server.h" - +#ifdef USE_API +#include "user_services.h" namespace esphome { namespace api { @@ -216,3 +216,4 @@ class CustomAPIDevice { } // namespace api } // namespace esphome +#endif diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index f04181e5b2..e91756c3c9 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -1,10 +1,10 @@ #pragma once +#include "api_server.h" +#ifdef USE_API +#include "api_pb2.h" #include "esphome/core/helpers.h" #include "esphome/core/automation.h" -#include "api_pb2.h" -#include "api_server.h" - #include namespace esphome { @@ -81,3 +81,4 @@ template class HomeAssistantServiceCallAction : public Action Date: Mon, 7 Oct 2024 11:27:08 +1100 Subject: [PATCH 2467/2607] [lvgl] Bugfixes #3 (#7472) --- esphome/components/image/image.cpp | 44 ++++++++++++++++ esphome/components/image/image.h | 19 ++++++- esphome/components/lvgl/__init__.py | 4 +- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/lv_validation.py | 3 +- esphome/components/lvgl/lvgl_esphome.cpp | 43 --------------- esphome/components/lvgl/lvgl_esphome.h | 4 -- esphome/components/lvgl/widgets/__init__.py | 2 + esphome/components/lvgl/widgets/animimg.py | 7 ++- esphome/components/lvgl/widgets/meter.py | 27 ++++++---- tests/components/image/test.esp32-ard.yaml | 4 +- tests/components/image/test.esp32-c3-ard.yaml | 4 +- tests/components/image/test.esp32-c3-idf.yaml | 4 +- tests/components/image/test.esp32-idf.yaml | 4 +- tests/components/lvgl/lvgl-package.yaml | 52 +++++++++++++++++++ tests/components/lvgl/test.esp32-idf.yaml | 2 +- 16 files changed, 148 insertions(+), 76 deletions(-) diff --git a/esphome/components/image/image.cpp b/esphome/components/image/image.cpp index 0ddb8110cb..ded4c60d25 100644 --- a/esphome/components/image/image.cpp +++ b/esphome/components/image/image.cpp @@ -79,6 +79,50 @@ Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const { return color_off; } } +#ifdef USE_LVGL +lv_img_dsc_t *Image::get_lv_img_dsc() { + // lazily construct lvgl image_dsc. + if (this->dsc_.data != this->data_start_) { + this->dsc_.data = this->data_start_; + this->dsc_.header.always_zero = 0; + this->dsc_.header.reserved = 0; + this->dsc_.header.w = this->width_; + this->dsc_.header.h = this->height_; + this->dsc_.data_size = image_type_to_width_stride(this->dsc_.header.w * this->dsc_.header.h, this->get_type()); + switch (this->get_type()) { + case IMAGE_TYPE_BINARY: + this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT; + break; + + case IMAGE_TYPE_GRAYSCALE: + this->dsc_.header.cf = LV_IMG_CF_ALPHA_8BIT; + break; + + case IMAGE_TYPE_RGB24: + this->dsc_.header.cf = LV_IMG_CF_RGB888; + break; + + case IMAGE_TYPE_RGB565: +#if LV_COLOR_DEPTH == 16 + this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR; +#else + this->dsc_.header.cf = LV_IMG_CF_RGB565; +#endif + break; + + case image::IMAGE_TYPE_RGBA: +#if LV_COLOR_DEPTH == 32 + this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR; +#else + this->dsc_.header.cf = LV_IMG_CF_RGBA8888; +#endif + break; + } + } + return &this->dsc_; +} +#endif // USE_LVGL + bool Image::get_binary_pixel_(int x, int y) const { const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; const uint32_t pos = x + y * width_8; diff --git a/esphome/components/image/image.h b/esphome/components/image/image.h index 5f1f50a134..ae5a7a814d 100644 --- a/esphome/components/image/image.h +++ b/esphome/components/image/image.h @@ -1,6 +1,15 @@ #pragma once #include "esphome/core/color.h" -#include "esphome/components/display/display_buffer.h" +#include "esphome/components/display/display.h" + +#ifdef USE_LVGL +// required for clang-tidy +#ifndef LV_CONF_H +#define LV_CONF_SKIP 1 // NOLINT +#endif // LV_CONF_H + +#include +#endif // USE_LVGL namespace esphome { namespace image { @@ -37,7 +46,7 @@ class Image : public display::BaseImage { Color get_pixel(int x, int y, Color color_on = display::COLOR_ON, Color color_off = display::COLOR_OFF) const; int get_width() const override; int get_height() const override; - const uint8_t *get_data_start() { return this->data_start_; } + const uint8_t *get_data_start() const { return this->data_start_; } ImageType get_type() const; void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override; @@ -45,6 +54,9 @@ class Image : public display::BaseImage { void set_transparency(bool transparent) { transparent_ = transparent; } bool has_transparency() const { return transparent_; } +#ifdef USE_LVGL + lv_img_dsc_t *get_lv_img_dsc(); +#endif protected: bool get_binary_pixel_(int x, int y) const; Color get_rgb24_pixel_(int x, int y) const; @@ -57,6 +69,9 @@ class Image : public display::BaseImage { ImageType type_; const uint8_t *data_start_; bool transparent_; +#ifdef USE_LVGL + lv_img_dsc_t dsc_{}; +#endif }; } // namespace image diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index a3a6f7ddaf..ce3843567b 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -53,7 +53,7 @@ from .types import ( lv_style_t, lvgl_ns, ) -from .widgets import Widget, add_widgets, lv_scr_act, set_obj_properties +from .widgets import Widget, add_widgets, lv_scr_act, set_obj_properties, styles_used from .widgets.animimg import animimg_spec from .widgets.arc import arc_spec from .widgets.button import button_spec @@ -280,6 +280,8 @@ async def to_code(config): for comp in helpers.lvgl_components_required: CORE.add_define(f"USE_LVGL_{comp.upper()}") + if "transform_angle" in styles_used: + add_define("LV_COLOR_SCREEN_TRANSP", "1") for use in helpers.lv_uses: add_define(f"LV_USE_{use.upper()}") lv_conf_h_file = CORE.relative_src_path(LV_CONF_FILENAME) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 3db49d26a4..02f726e49c 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -452,6 +452,7 @@ CONF_OFFSET_Y = "offset_y" CONF_ONE_CHECKED = "one_checked" CONF_ONE_LINE = "one_line" CONF_ON_SELECT = "on_select" +CONF_OPA = "opa" CONF_NEXT = "next" CONF_PAD_ROW = "pad_row" CONF_PAD_COLUMN = "pad_column" diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 3dee0189fb..bd98319fd3 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -31,7 +31,6 @@ from .defines import ( literal, ) from .helpers import esphome_fonts_used, lv_fonts_used, requires_component -from .lvcode import lv_expr from .types import lv_font_t, lv_gradient_t, lv_img_t opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") @@ -330,7 +329,7 @@ def image_validator(value): lv_image = LValidator( image_validator, lv_img_t, - retmapper=lambda x: lv_expr.img_from(MockObj(x)), + retmapper=lambda x: MockObj(x, "->").get_lv_img_dsc(), requires="image", ) lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 89c9828740..b63fb0dab8 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -356,49 +356,6 @@ bool lv_is_pre_initialise() { return false; } -#ifdef USE_LVGL_IMAGE -lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc) { - if (img_dsc == nullptr) - img_dsc = new lv_img_dsc_t(); // NOLINT - img_dsc->header.always_zero = 0; - img_dsc->header.reserved = 0; - img_dsc->header.w = src->get_width(); - img_dsc->header.h = src->get_height(); - img_dsc->data = src->get_data_start(); - img_dsc->data_size = image_type_to_width_stride(img_dsc->header.w * img_dsc->header.h, src->get_type()); - switch (src->get_type()) { - case image::IMAGE_TYPE_BINARY: - img_dsc->header.cf = LV_IMG_CF_ALPHA_1BIT; - break; - - case image::IMAGE_TYPE_GRAYSCALE: - img_dsc->header.cf = LV_IMG_CF_ALPHA_8BIT; - break; - - case image::IMAGE_TYPE_RGB24: - img_dsc->header.cf = LV_IMG_CF_RGB888; - break; - - case image::IMAGE_TYPE_RGB565: -#if LV_COLOR_DEPTH == 16 - img_dsc->header.cf = src->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR; -#else - img_dsc->header.cf = LV_IMG_CF_RGB565; -#endif - break; - - case image::IMAGE_TYPE_RGBA: -#if LV_COLOR_DEPTH == 32 - img_dsc->header.cf = LV_IMG_CF_TRUE_COLOR; -#else - img_dsc->header.cf = LV_IMG_CF_RGBA8888; -#endif - break; - } - return img_dsc; -} -#endif // USE_LVGL_IMAGE - #ifdef USE_LVGL_ANIMIMG void lv_animimg_stop(lv_obj_t *obj) { auto *animg = (lv_animimg_t *) obj; diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index d5cff51de2..0c3738bd1f 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -102,10 +102,6 @@ class FontEngine { lv_font_t lv_font_{}; }; #endif // USE_LVGL_FONT -#ifdef USE_LVGL_IMAGE -lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc = nullptr); -#endif // USE_LVGL_IMAGE - #ifdef USE_LVGL_ANIMIMG void lv_animimg_stop(lv_obj_t *obj); #endif // USE_LVGL_ANIMIMG diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index e093cebd16..533ffdea55 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -52,6 +52,7 @@ from ..types import LV_STATE, LvType, WidgetType, lv_coord_t, lv_obj_t, lv_obj_t EVENT_LAMB = "event_lamb__" theme_widget_map = {} +styles_used = set() class LvScrActType(WidgetType): @@ -158,6 +159,7 @@ class Widget: def set_style(self, prop, value, state): if value is None: return + styles_used.add(prop) lv.call(f"obj_set_style_{prop}", self.obj, value, state) def __type_base(self): diff --git a/esphome/components/lvgl/widgets/animimg.py b/esphome/components/lvgl/widgets/animimg.py index a973ca0702..3b20008c3d 100644 --- a/esphome/components/lvgl/widgets/animimg.py +++ b/esphome/components/lvgl/widgets/animimg.py @@ -2,13 +2,12 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_DURATION, CONF_ID -from esphome.cpp_generator import MockObj from ..automation import action_to_code from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC from ..helpers import lvgl_components_required from ..lv_validation import lv_image, lv_milliseconds -from ..lvcode import lv, lv_expr +from ..lvcode import lv from ..types import LvType, ObjUpdateAction, void_ptr from . import Widget, WidgetType, get_widgets from .img import CONF_IMAGE @@ -63,7 +62,7 @@ class AnimimgType(WidgetType): if CONF_SRC in config: for x in config[CONF_SRC]: await cg.get_variable(x) - srcs = [lv_expr.img_from(MockObj(x)) for x in config[CONF_SRC]] + srcs = [await lv_image.process(x) for x in config[CONF_SRC]] src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs) count = len(config[CONF_SRC]) lv.animimg_set_src(w.obj, src_id, count) @@ -73,7 +72,7 @@ class AnimimgType(WidgetType): lv.animimg_start(w.obj) def get_uses(self): - return CONF_IMAGE, CONF_LABEL + return "img", CONF_IMAGE, CONF_LABEL animimg_spec = AnimimgType() diff --git a/esphome/components/lvgl/widgets/meter.py b/esphome/components/lvgl/widgets/meter.py index 36f6643022..bc455ccebc 100644 --- a/esphome/components/lvgl/widgets/meter.py +++ b/esphome/components/lvgl/widgets/meter.py @@ -20,6 +20,7 @@ from ..defines import ( CONF_END_VALUE, CONF_INDICATOR, CONF_MAIN, + CONF_OPA, CONF_PIVOT_X, CONF_PIVOT_Y, CONF_SRC, @@ -35,10 +36,11 @@ from ..lv_validation import ( lv_color, lv_float, lv_image, + opacity, requires_component, size, ) -from ..lvcode import LocalVariable, lv, lv_assign, lv_expr +from ..lvcode import LocalVariable, lv, lv_assign, lv_expr, lv_obj from ..types import LvType, ObjUpdateAction from . import Widget, WidgetType, get_widgets from .arc import CONF_ARC @@ -76,6 +78,7 @@ INDICATOR_LINE_SCHEMA = cv.Schema( cv.Optional(CONF_COLOR, default=0): lv_color, cv.Optional(CONF_R_MOD, default=0): size, cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_OPA): opacity, } ) INDICATOR_IMG_SCHEMA = cv.Schema( @@ -84,6 +87,7 @@ INDICATOR_IMG_SCHEMA = cv.Schema( cv.Required(CONF_PIVOT_X): pixels, cv.Required(CONF_PIVOT_Y): pixels, cv.Optional(CONF_VALUE): lv_float, + cv.Optional(CONF_OPA): opacity, } ) INDICATOR_ARC_SCHEMA = cv.Schema( @@ -94,6 +98,7 @@ INDICATOR_ARC_SCHEMA = cv.Schema( cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float, cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float, cv.Optional(CONF_END_VALUE): lv_float, + cv.Optional(CONF_OPA): opacity, } ) INDICATOR_TICKS_SCHEMA = cv.Schema( @@ -218,9 +223,7 @@ class MeterType(WidgetType): for indicator in scale_conf.get(CONF_INDICATORS, ()): (t, v) = next(iter(indicator.items())) iid = v[CONF_ID] - ivar = cg.new_variable( - iid, cg.nullptr, type_=lv_meter_indicator_t_ptr - ) + ivar = cg.Pvariable(iid, cg.nullptr, type_=lv_meter_indicator_t) # Enable getting the meter to which this belongs. wid = Widget.create(iid, var, obj_spec, v) wid.obj = ivar @@ -268,9 +271,7 @@ class MeterType(WidgetType): v[CONF_PIVOT_Y], ), ) - start_value = await get_start_value(v) - end_value = await get_end_value(v) - set_indicator_values(var, ivar, start_value, end_value) + await set_indicator_values(var, ivar, v) meter_spec = MeterType() @@ -285,21 +286,22 @@ meter_spec = MeterType() cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float, cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float, cv.Optional(CONF_END_VALUE): lv_float, + cv.Optional(CONF_OPA): opacity, } ), ) async def indicator_update_to_code(config, action_id, template_arg, args): widget = await get_widgets(config) - start_value = await get_start_value(config) - end_value = await get_end_value(config) async def set_value(w: Widget): - set_indicator_values(w.var, w.obj, start_value, end_value) + await set_indicator_values(w.var, w.obj, config) return await action_to_code(widget, set_value, action_id, template_arg, args) -def set_indicator_values(meter, indicator, start_value, end_value): +async def set_indicator_values(meter, indicator, config): + start_value = await get_start_value(config) + end_value = await get_end_value(config) if start_value is not None: if end_value is None: lv.meter_set_indicator_value(meter, indicator, start_value) @@ -307,3 +309,6 @@ def set_indicator_values(meter, indicator, start_value, end_value): lv.meter_set_indicator_start_value(meter, indicator, start_value) if end_value is not None: lv.meter_set_indicator_end_value(meter, indicator, end_value) + if opa := config.get(CONF_OPA): + lv_assign(indicator.opa, await opacity.process(opa)) + lv_obj.invalidate(meter) diff --git a/tests/components/image/test.esp32-ard.yaml b/tests/components/image/test.esp32-ard.yaml index 34c7914976..9dd44d177f 100644 --- a/tests/components/image/test.esp32-ard.yaml +++ b/tests/components/image/test.esp32-ard.yaml @@ -2,13 +2,13 @@ spi: - id: spi_main_lcd clk_pin: 16 mosi_pin: 17 - miso_pin: 15 + miso_pin: 32 display: - platform: ili9xxx id: main_lcd model: ili9342 - cs_pin: 12 + cs_pin: 14 dc_pin: 13 reset_pin: 21 invert_colors: true diff --git a/tests/components/image/test.esp32-c3-ard.yaml b/tests/components/image/test.esp32-c3-ard.yaml index 91ff0a0579..c0b2779773 100644 --- a/tests/components/image/test.esp32-c3-ard.yaml +++ b/tests/components/image/test.esp32-c3-ard.yaml @@ -8,8 +8,8 @@ display: - platform: ili9xxx id: main_lcd model: ili9342 - cs_pin: 8 - dc_pin: 9 + cs_pin: 3 + dc_pin: 11 reset_pin: 10 invert_colors: true diff --git a/tests/components/image/test.esp32-c3-idf.yaml b/tests/components/image/test.esp32-c3-idf.yaml index 91ff0a0579..c0b2779773 100644 --- a/tests/components/image/test.esp32-c3-idf.yaml +++ b/tests/components/image/test.esp32-c3-idf.yaml @@ -8,8 +8,8 @@ display: - platform: ili9xxx id: main_lcd model: ili9342 - cs_pin: 8 - dc_pin: 9 + cs_pin: 3 + dc_pin: 11 reset_pin: 10 invert_colors: true diff --git a/tests/components/image/test.esp32-idf.yaml b/tests/components/image/test.esp32-idf.yaml index 34c7914976..e903afea1f 100644 --- a/tests/components/image/test.esp32-idf.yaml +++ b/tests/components/image/test.esp32-idf.yaml @@ -2,13 +2,13 @@ spi: - id: spi_main_lcd clk_pin: 16 mosi_pin: 17 - miso_pin: 15 + miso_pin: 18 display: - platform: ili9xxx id: main_lcd model: ili9342 - cs_pin: 12 + cs_pin: 19 dc_pin: 13 reset_pin: 21 invert_colors: true diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 2b72f31770..6f79a1f810 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -608,6 +608,58 @@ lvgl: id: tabview_id index: 0 animated: true + - meter: + height: 200px + width: 200px + indicator: + bg_color: 0xFF + radius: 0 + bg_opa: TRANSP + text_color: 0xFFFFFF + scales: + - ticks: + width: 1 + count: 61 + length: 20 + color: 0xFFFFFF + range_from: 0 + range_to: 60 + angle_range: 360 + rotation: 270 + indicators: + - line: + opa: 50% + id: minute_hand + color: 0xFF0000 + r_mod: -1 + width: 3 + - + angle_range: 330 + rotation: 300 + range_from: 1 + range_to: 12 + ticks: + width: 1 + count: 12 + length: 1 + major: + stride: 1 + width: 4 + length: 8 + color: 0xC0C0C0 + label_gap: 6 + - angle_range: 360 + rotation: 270 + range_from: 0 + range_to: 720 + indicators: + - line: + id: hour_hand + value: 180 + width: 4 + color: 0xA0A0A0 + r_mod: -20 + font: - file: "gfonts://Roboto" id: space16 diff --git a/tests/components/lvgl/test.esp32-idf.yaml b/tests/components/lvgl/test.esp32-idf.yaml index 927d72d15c..05a1f243ed 100644 --- a/tests/components/lvgl/test.esp32-idf.yaml +++ b/tests/components/lvgl/test.esp32-idf.yaml @@ -10,7 +10,7 @@ sensor: - platform: rotary_encoder name: "Rotary Encoder" id: encoder - pin_a: 2 + pin_a: 3 pin_b: 1 internal: true From 03a95ee05f21fe0b4e71b9a8629610e875baefb9 Mon Sep 17 00:00:00 2001 From: YorkshireIoT <55233103+YorkshireIoT@users.noreply.github.com> Date: Mon, 7 Oct 2024 03:34:46 +0100 Subject: [PATCH 2468/2607] Feature/add seeed grove gmxxx multichannel gas support (#4304) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../components/grove_gas_mc_v2/__init__.py | 0 .../grove_gas_mc_v2/grove_gas_mc_v2.cpp | 88 +++++++++++++++++++ .../grove_gas_mc_v2/grove_gas_mc_v2.h | 39 ++++++++ esphome/components/grove_gas_mc_v2/sensor.py | 77 ++++++++++++++++ esphome/const.py | 3 + tests/components/grove_gas_mc_v2/common.yaml | 13 +++ .../grove_gas_mc_v2/test.esp32-ard.yaml | 6 ++ .../grove_gas_mc_v2/test.esp32-idf.yaml | 6 ++ .../grove_gas_mc_v2/test.esp8266-ard.yaml | 6 ++ .../grove_gas_mc_v2/test.rp2040-ard.yaml | 6 ++ 11 files changed, 245 insertions(+) create mode 100644 esphome/components/grove_gas_mc_v2/__init__.py create mode 100644 esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp create mode 100644 esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h create mode 100644 esphome/components/grove_gas_mc_v2/sensor.py create mode 100644 tests/components/grove_gas_mc_v2/common.yaml create mode 100644 tests/components/grove_gas_mc_v2/test.esp32-ard.yaml create mode 100644 tests/components/grove_gas_mc_v2/test.esp32-idf.yaml create mode 100644 tests/components/grove_gas_mc_v2/test.esp8266-ard.yaml create mode 100644 tests/components/grove_gas_mc_v2/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index db48e25743..180024cd37 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -162,6 +162,7 @@ esphome/components/gps/* @coogle esphome/components/graph/* @synco esphome/components/graphical_display_menu/* @MrMDavidson esphome/components/gree/* @orestismers +esphome/components/grove_gas_mc_v2/* @YorkshireIoT esphome/components/grove_tb6612fng/* @max246 esphome/components/growatt_solar/* @leeuwte esphome/components/gt911/* @clydebarrow @jesserockz diff --git a/esphome/components/grove_gas_mc_v2/__init__.py b/esphome/components/grove_gas_mc_v2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp b/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp new file mode 100644 index 0000000000..ed40ba42a5 --- /dev/null +++ b/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp @@ -0,0 +1,88 @@ +#include "grove_gas_mc_v2.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace grove_gas_mc_v2 { + +static const char *const TAG = "grove_gas_mc_v2"; + +// I2C Commands for Grove Gas Multichannel V2 Sensor +// Taken from: +// https://github.com/Seeed-Studio/Seeed_Arduino_MultiGas/blob/master/src/Multichannel_Gas_GroveGasMultichannelV2.h +static const uint8_t GROVE_GAS_MC_V2_HEAT_ON = 0xFE; +static const uint8_t GROVE_GAS_MC_V2_HEAT_OFF = 0xFF; +static const uint8_t GROVE_GAS_MC_V2_READ_GM102B = 0x01; +static const uint8_t GROVE_GAS_MC_V2_READ_GM302B = 0x03; +static const uint8_t GROVE_GAS_MC_V2_READ_GM502B = 0x05; +static const uint8_t GROVE_GAS_MC_V2_READ_GM702B = 0x07; + +bool GroveGasMultichannelV2Component::read_sensor_(uint8_t address, sensor::Sensor *sensor) { + if (sensor == nullptr) { + return true; + } + uint32_t value = 0; + if (!this->read_bytes(address, (uint8_t *) &value, 4)) { + ESP_LOGW(TAG, "Reading Grove Gas Sensor data failed!"); + this->error_code_ = COMMUNICATION_FAILED; + this->status_set_warning(); + return false; + } + sensor->publish_state(value); + return true; +} + +void GroveGasMultichannelV2Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up Grove Multichannel Gas Sensor V2..."); + + // Before reading sensor values, must preheat sensor + if (!(this->write_bytes(GROVE_GAS_MC_V2_HEAT_ON, {}))) { + this->mark_failed(); + this->error_code_ = APP_START_FAILED; + } +} + +void GroveGasMultichannelV2Component::update() { + // Read from each of the gas sensors + if (!this->read_sensor_(GROVE_GAS_MC_V2_READ_GM102B, this->nitrogen_dioxide_sensor_)) + return; + if (!this->read_sensor_(GROVE_GAS_MC_V2_READ_GM302B, this->ethanol_sensor_)) + return; + if (!this->read_sensor_(GROVE_GAS_MC_V2_READ_GM502B, this->tvoc_sensor_)) + return; + if (!this->read_sensor_(GROVE_GAS_MC_V2_READ_GM702B, this->carbon_monoxide_sensor_)) + return; + + this->status_clear_warning(); +} + +void GroveGasMultichannelV2Component::dump_config() { + ESP_LOGCONFIG(TAG, "Grove Multichannel Gas Sensor V2"); + LOG_I2C_DEVICE(this) + LOG_UPDATE_INTERVAL(this) + LOG_SENSOR(" ", "Nitrogen Dioxide", this->nitrogen_dioxide_sensor_) + LOG_SENSOR(" ", "Ethanol", this->ethanol_sensor_) + LOG_SENSOR(" ", "Carbon Monoxide", this->carbon_monoxide_sensor_) + LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_) + + if (this->is_failed()) { + switch (this->error_code_) { + case COMMUNICATION_FAILED: + ESP_LOGW(TAG, "Communication failed! Is the sensor connected?"); + break; + case APP_INVALID: + ESP_LOGW(TAG, "Sensor reported invalid APP installed."); + break; + case APP_START_FAILED: + ESP_LOGW(TAG, "Sensor reported APP start failed."); + break; + case UNKNOWN: + default: + ESP_LOGW(TAG, "Unknown setup error!"); + break; + } + } +} + +} // namespace grove_gas_mc_v2 +} // namespace esphome diff --git a/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h b/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h new file mode 100644 index 0000000000..1987d33f37 --- /dev/null +++ b/esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" +#include "esphome/core/preferences.h" + +namespace esphome { +namespace grove_gas_mc_v2 { + +class GroveGasMultichannelV2Component : public PollingComponent, public i2c::I2CDevice { + SUB_SENSOR(tvoc) + SUB_SENSOR(carbon_monoxide) + SUB_SENSOR(nitrogen_dioxide) + SUB_SENSOR(ethanol) + + public: + /// Setup the sensor and test for a connection. + void setup() override; + /// Schedule temperature+pressure readings. + void update() override; + + void dump_config() override; + + float get_setup_priority() const override { return setup_priority::DATA; } + + protected: + enum ErrorCode { + UNKNOWN, + COMMUNICATION_FAILED, + APP_INVALID, + APP_START_FAILED, + } error_code_{UNKNOWN}; + + bool read_sensor_(uint8_t address, sensor::Sensor *sensor); +}; + +} // namespace grove_gas_mc_v2 +} // namespace esphome diff --git a/esphome/components/grove_gas_mc_v2/sensor.py b/esphome/components/grove_gas_mc_v2/sensor.py new file mode 100644 index 0000000000..0c35047850 --- /dev/null +++ b/esphome/components/grove_gas_mc_v2/sensor.py @@ -0,0 +1,77 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_CARBON_MONOXIDE, + CONF_ETHANOL, + CONF_ID, + CONF_NITROGEN_DIOXIDE, + CONF_TVOC, + DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_NITROGEN_DIOXIDE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + ICON_AIR_FILTER, + ICON_FLASK_ROUND_BOTTOM, + ICON_GAS_CYLINDER, + ICON_MOLECULE_CO, + STATE_CLASS_MEASUREMENT, + UNIT_MICROGRAMS_PER_CUBIC_METER, + UNIT_PARTS_PER_MILLION, +) + +CODEOWNERS = ["@YorkshireIoT"] +DEPENDENCIES = ["i2c"] + +grove_gas_mc_v2_ns = cg.esphome_ns.namespace("grove_gas_mc_v2") + +GroveGasMultichannelV2Component = grove_gas_mc_v2_ns.class_( + "GroveGasMultichannelV2Component", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(GroveGasMultichannelV2Component), + cv.Optional(CONF_TVOC): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_AIR_FILTER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CARBON_MONOXIDE): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + icon=ICON_MOLECULE_CO, + accuracy_decimals=0, + device_class=DEVICE_CLASS_CARBON_MONOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_NITROGEN_DIOXIDE): sensor.sensor_schema( + unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER, + icon=ICON_GAS_CYLINDER, + accuracy_decimals=0, + device_class=DEVICE_CLASS_NITROGEN_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_ETHANOL): sensor.sensor_schema( + unit_of_measurement=UNIT_PARTS_PER_MILLION, + icon=ICON_FLASK_ROUND_BOTTOM, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x08)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + for key in [CONF_TVOC, CONF_CARBON_MONOXIDE, CONF_NITROGEN_DIOXIDE, CONF_ETHANOL]: + if sensor_config := config.get(key): + sensor_ = await sensor.new_sensor(sensor_config) + cg.add(getattr(var, f"set_{key}_sensor")(sensor_)) diff --git a/esphome/const.py b/esphome/const.py index bfb0167282..506a30f5ed 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -962,6 +962,7 @@ ICON_ACCELERATION_Y = "mdi:axis-y-arrow" ICON_ACCELERATION_Z = "mdi:axis-z-arrow" ICON_ACCOUNT = "mdi:account" ICON_ACCOUNT_CHECK = "mdi:account-check" +ICON_AIR_FILTER = "mdi:air-filter" ICON_ARROW_EXPAND_VERTICAL = "mdi:arrow-expand-vertical" ICON_BATTERY = "mdi:battery" ICON_BLUETOOTH = "mdi:bluetooth" @@ -983,6 +984,7 @@ ICON_FINGERPRINT = "mdi:fingerprint" ICON_FLASH = "mdi:flash" ICON_FLASK = "mdi:flask" ICON_FLASK_OUTLINE = "mdi:flask-outline" +ICON_FLASK_ROUND_BOTTOM = "mdi:flask-round-bottom" ICON_FLOWER = "mdi:flower" ICON_GAS_CYLINDER = "mdi:gas-cylinder" ICON_GAUGE = "mdi:gauge" @@ -995,6 +997,7 @@ ICON_KEY_PLUS = "mdi:key-plus" ICON_LIGHTBULB = "mdi:lightbulb" ICON_MAGNET = "mdi:magnet" ICON_MEMORY = "mdi:memory" +ICON_MOLECULE_CO = "mdi:molecule-co" ICON_MOLECULE_CO2 = "mdi:molecule-co2" ICON_MOTION_SENSOR = "mdi:motion-sensor" ICON_NEW_BOX = "mdi:new-box" diff --git a/tests/components/grove_gas_mc_v2/common.yaml b/tests/components/grove_gas_mc_v2/common.yaml new file mode 100644 index 0000000000..0729e6b9c7 --- /dev/null +++ b/tests/components/grove_gas_mc_v2/common.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: grove_gas_mc_v2 + i2c_id: i2c_bus + nitrogen_dioxide: + name: "Nitrogen Dioxide" + ethanol: + name: "Ethanol" + carbon_monoxide: + name: "Carbon Monoxide" + tvoc: + name: "Volatile Organic Compounds" + update_interval: 30s + address: 0xAD diff --git a/tests/components/grove_gas_mc_v2/test.esp32-ard.yaml b/tests/components/grove_gas_mc_v2/test.esp32-ard.yaml new file mode 100644 index 0000000000..00c7856c36 --- /dev/null +++ b/tests/components/grove_gas_mc_v2/test.esp32-ard.yaml @@ -0,0 +1,6 @@ +i2c: + sda: 21 + scl: 22 + id: i2c_bus + +<<: !include common.yaml diff --git a/tests/components/grove_gas_mc_v2/test.esp32-idf.yaml b/tests/components/grove_gas_mc_v2/test.esp32-idf.yaml new file mode 100644 index 0000000000..00c7856c36 --- /dev/null +++ b/tests/components/grove_gas_mc_v2/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + sda: 21 + scl: 22 + id: i2c_bus + +<<: !include common.yaml diff --git a/tests/components/grove_gas_mc_v2/test.esp8266-ard.yaml b/tests/components/grove_gas_mc_v2/test.esp8266-ard.yaml new file mode 100644 index 0000000000..2de18bdf39 --- /dev/null +++ b/tests/components/grove_gas_mc_v2/test.esp8266-ard.yaml @@ -0,0 +1,6 @@ +i2c: + sda: 4 + scl: 5 + id: i2c_bus + +<<: !include common.yaml diff --git a/tests/components/grove_gas_mc_v2/test.rp2040-ard.yaml b/tests/components/grove_gas_mc_v2/test.rp2040-ard.yaml new file mode 100644 index 0000000000..00c7856c36 --- /dev/null +++ b/tests/components/grove_gas_mc_v2/test.rp2040-ard.yaml @@ -0,0 +1,6 @@ +i2c: + sda: 21 + scl: 22 + id: i2c_bus + +<<: !include common.yaml From 6a2ed8241edf18867cdd61917cda0a406e179816 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:43:41 +1100 Subject: [PATCH 2469/2607] [lvgl] Fix: allow full range of styles on dropdown list. (#7552) --- esphome/components/lvgl/lv_validation.py | 2 + esphome/components/lvgl/widgets/dropdown.py | 6 ++- esphome/components/lvgl/widgets/meter.py | 2 +- tests/components/lvgl/lvgl-package.yaml | 50 +++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index bd98319fd3..fd840cc417 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -242,6 +242,8 @@ def pixels_or_percent_validator(value): """A length in one axis - either a number (pixels) or a percentage""" if value == SCHEMA_EXTRACT: return ["pixels", "..%"] + if isinstance(value, str) and value.lower().endswith("px"): + value = cv.int_(value[:-2]) value = cv.Any(cv.int_, cv.percentage)(value) if isinstance(value, int): return value diff --git a/esphome/components/lvgl/widgets/dropdown.py b/esphome/components/lvgl/widgets/dropdown.py index dc0346b080..4fd7d8a7ee 100644 --- a/esphome/components/lvgl/widgets/dropdown.py +++ b/esphome/components/lvgl/widgets/dropdown.py @@ -6,6 +6,8 @@ from ..defines import ( CONF_DIR, CONF_INDICATOR, CONF_MAIN, + CONF_SCROLLBAR, + CONF_SELECTED, CONF_SELECTED_INDEX, CONF_SYMBOL, DIRECTIONS, @@ -23,7 +25,9 @@ CONF_DROPDOWN_LIST = "dropdown_list" lv_dropdown_t = LvSelect("lv_dropdown_t") lv_dropdown_list_t = LvType("lv_dropdown_list_t") -dropdown_list_spec = WidgetType(CONF_DROPDOWN_LIST, lv_dropdown_list_t, (CONF_MAIN,)) +dropdown_list_spec = WidgetType( + CONF_DROPDOWN_LIST, lv_dropdown_list_t, (CONF_MAIN, CONF_SELECTED, CONF_SCROLLBAR) +) DROPDOWN_BASE_SCHEMA = cv.Schema( { diff --git a/esphome/components/lvgl/widgets/meter.py b/esphome/components/lvgl/widgets/meter.py index bc455ccebc..cd61d1c775 100644 --- a/esphome/components/lvgl/widgets/meter.py +++ b/esphome/components/lvgl/widgets/meter.py @@ -309,6 +309,6 @@ async def set_indicator_values(meter, indicator, config): lv.meter_set_indicator_start_value(meter, indicator, start_value) if end_value is not None: lv.meter_set_indicator_end_value(meter, indicator, end_value) - if opa := config.get(CONF_OPA): + if (opa := config.get(CONF_OPA)) is not None: lv_assign(indicator.opa, await opacity.process(opa)) lv_obj.invalidate(meter) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 6f79a1f810..c968198e26 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -1,3 +1,16 @@ +substitutions: + light_recessed: "\U000F179B" + wall_sconce_round: "\U000F0748" + gas_burner: "\U000F1A1B" + home_icon: "\U000F02DC" + menu_left: "\U000F0A02" + menu_right: "\U000F035F" + close: "\U000F0156" + delete: "\U000F01B4" + backspace: "\U000F006E" + check: "\U000F012C" + arrow_down: "\U000F004B" + lvgl: log_level: TRACE bg_color: light_blue @@ -599,6 +612,42 @@ lvgl: - name: Cat id: tabview_tab_2 widgets: + - dropdown: + indicator: + text_font: helvetica20 + id: lv_dropdown + options: + - First + - Second + - Third + - 4th + - 5th + - 6th + - 7th + - 8th + - 9th + selected_index: 2 + dir: top + symbol: ${arrow_down} + dropdown_list: + max_height: 100px + bg_color: 0x000080 + text_color: 0xFF00 + selected: + bg_color: 0xFFFF00 + checked: + bg_color: 0x00 + text_color: 0xFF0000 + scrollbar: + bg_color: 0xFF + on_value: + logger.log: + format: "Dropdown changed = %d" + args: [x] + on_cancel: + logger.log: + format: "Dropdown closed = %d" + args: [x] - image: src: cat_image on_click: @@ -659,6 +708,7 @@ lvgl: width: 4 color: 0xA0A0A0 r_mod: -20 + opa: 0% font: - file: "gfonts://Roboto" From 86a34f4b17bf711570e2e18ae32a80fca0099321 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Mon, 7 Oct 2024 04:52:26 +0200 Subject: [PATCH 2470/2607] [web_server] v3 entity grouping (#6833) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../alarm_control_panel/__init__.py | 7 +- esphome/components/binary_sensor/__init__.py | 7 +- esphome/components/button/__init__.py | 7 +- esphome/components/climate/__init__.py | 7 +- esphome/components/cover/__init__.py | 9 +- esphome/components/datetime/__init__.py | 7 +- esphome/components/fan/__init__.py | 7 +- esphome/components/light/__init__.py | 7 +- esphome/components/lock/__init__.py | 7 +- esphome/components/number/__init__.py | 8 +- esphome/components/select/__init__.py | 7 +- esphome/components/sensor/__init__.py | 7 +- esphome/components/switch/__init__.py | 7 +- esphome/components/text/__init__.py | 7 +- esphome/components/text_sensor/__init__.py | 7 +- esphome/components/update/__init__.py | 7 +- esphome/components/valve/__init__.py | 7 +- esphome/components/web_server/__init__.py | 124 +++++++++++++----- esphome/components/web_server/web_server.cpp | 79 ++++++++++- esphome/components/web_server/web_server.h | 11 +- esphome/const.py | 1 - tests/components/web_server/common_v3.yaml | 37 ++++++ .../web_server/test_v3.esp32-ard.yaml | 1 + 23 files changed, 265 insertions(+), 110 deletions(-) create mode 100644 tests/components/web_server/common_v3.yaml create mode 100644 tests/components/web_server/test_v3.esp32-ard.yaml diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 8987d708fd..379fbf32f9 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -9,7 +9,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_ON_STATE, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -195,9 +195,8 @@ async def setup_alarm_control_panel_core_(var, config): for conf in config.get(CONF_ON_READY, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) if mqtt_id := config.get(CONF_MQTT_ID): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 95fd17bcc0..d947c2aba6 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -25,7 +25,7 @@ from esphome.const import ( CONF_STATE, CONF_TIMING, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY_CHARGING, DEVICE_CLASS_CARBON_MONOXIDE, @@ -543,9 +543,8 @@ async def setup_binary_sensor_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_binary_sensor(var, config): diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 3010d3006a..366d0edf7d 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_ON_PRESS, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_EMPTY, DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, @@ -97,9 +97,8 @@ async def setup_button_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_button(var, config): diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index c7e4ce7745..b302e2ab4e 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -43,7 +43,7 @@ from esphome.const import ( CONF_TEMPERATURE_STEP, CONF_TRIGGER_ID, CONF_VISUAL, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -408,9 +408,8 @@ async def setup_climate_core_(var, config): trigger, [(ClimateCall.operator("ref"), "x")], conf ) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_climate(var, config): diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index d25dd91148..e7e3ac3bb0 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -17,7 +17,7 @@ from esphome.const import ( CONF_TILT_COMMAND_TOPIC, CONF_TILT_STATE_TOPIC, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_AWNING, DEVICE_CLASS_BLIND, DEVICE_CLASS_CURTAIN, @@ -137,10 +137,6 @@ async def setup_cover_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) - if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) @@ -156,6 +152,9 @@ async def setup_cover_core_(var, config): if (tilt_command_topic := config.get(CONF_TILT_COMMAND_TOPIC)) is not None: cg.add(mqtt_.set_custom_tilt_command_topic(tilt_command_topic)) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) + async def register_cover(var, config): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 55066006d3..7edf527e01 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -18,7 +18,7 @@ from esphome.const import ( CONF_TIME_ID, CONF_TRIGGER_ID, CONF_TYPE, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, CONF_YEAR, ) from esphome.core import CORE, coroutine_with_priority @@ -138,9 +138,8 @@ async def setup_datetime_core_(var, config): if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) for conf in config.get(CONF_ON_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 62624ec6e3..4e0e52cd65 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -25,7 +25,7 @@ from esphome.const import ( CONF_SPEED_LEVEL_STATE_TOPIC, CONF_SPEED_STATE_TOPIC, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -218,9 +218,8 @@ async def setup_fan_core_(var, config): if (speed_command_topic := config.get(CONF_SPEED_COMMAND_TOPIC)) is not None: cg.add(mqtt_.set_custom_speed_command_topic(speed_command_topic)) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) for conf in config.get(CONF_ON_STATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index d9f139d2f4..7e16b7a648 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -18,7 +18,7 @@ from esphome.const import ( CONF_RESTORE_MODE, CONF_TRIGGER_ID, CONF_WARM_WHITE_COLOR_TEMPERATURE, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -181,9 +181,8 @@ async def setup_light_core_(light_var, output_var, config): mqtt_ = cg.new_Pvariable(mqtt_id, light_var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, light_var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(light_var, web_server_config) async def register_light(output_var, config): diff --git a/esphome/components/lock/__init__.py b/esphome/components/lock/__init__.py index 6b92bc264b..6925861b52 100644 --- a/esphome/components/lock/__init__.py +++ b/esphome/components/lock/__init__.py @@ -9,7 +9,7 @@ from esphome.const import ( CONF_ON_LOCK, CONF_ON_UNLOCK, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -66,9 +66,8 @@ async def setup_lock_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_lock(var, config): diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index ece738af49..f45cfd54f2 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -18,7 +18,7 @@ from esphome.const import ( CONF_TRIGGER_ID, CONF_UNIT_OF_MEASUREMENT, CONF_VALUE, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, DEVICE_CLASS_ATMOSPHERIC_PRESSURE, @@ -254,10 +254,8 @@ async def setup_number_core_( if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_number( diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index 2bc68d43ec..5a3271fdfd 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( CONF_OPERATION, CONF_OPTION, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass @@ -104,9 +104,8 @@ async def setup_select_core_(var, config, *, options: list[str]): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_select(var, config, *, options: list[str]): diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 867cdc1f48..27338b8608 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -36,7 +36,7 @@ from esphome.const import ( CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, CONF_VALUE, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, CONF_WINDOW_SIZE, DEVICE_CLASS_APPARENT_POWER, DEVICE_CLASS_AQI, @@ -800,9 +800,8 @@ async def setup_sensor_core_(var, config): else: cg.add(mqtt_.set_expire_after(expire_after)) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_sensor(var, config): diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index fef4f7f007..0f159f69ec 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( CONF_ON_TURN_ON, CONF_RESTORE_MODE, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_EMPTY, DEVICE_CLASS_OUTLET, DEVICE_CLASS_SWITCH, @@ -156,9 +156,8 @@ async def setup_switch_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: cg.add(var.set_device_class(device_class)) diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index 386baaf756..20e5a645d1 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_ON_VALUE, CONF_TRIGGER_ID, CONF_VALUE, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -82,9 +82,8 @@ async def setup_text_core_( mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_text( diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index ba8a2def41..12993d9ffc 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -15,7 +15,7 @@ from esphome.const import ( CONF_STATE, CONF_TO, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_DATE, DEVICE_CLASS_EMPTY, DEVICE_CLASS_TIMESTAMP, @@ -212,9 +212,8 @@ async def setup_text_sensor_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_text_sensor(var, config): diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ba3b2f20df..4729d954ee 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -8,7 +8,7 @@ from esphome.const import ( CONF_FORCE_UPDATE, CONF_ID, CONF_MQTT_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, ENTITY_CATEGORY_CONFIG, @@ -73,9 +73,8 @@ async def setup_update_core_(var, config): mqtt_ = cg.new_Pvariable(mqtt_id_config, var) await mqtt.register_mqtt_component(mqtt_, config) - if web_server_id_config := config.get(CONF_WEB_SERVER_ID): - web_server_ = await cg.get_variable(web_server_id_config) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_update(var, config): diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index 3c03bab857..e55bb522de 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( CONF_STATE, CONF_STOP, CONF_TRIGGER_ID, - CONF_WEB_SERVER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_EMPTY, DEVICE_CLASS_GAS, DEVICE_CLASS_WATER, @@ -124,9 +124,8 @@ async def setup_valve_core_(var, config): mqtt_.set_custom_position_command_topic(position_command_topic_config) ) - if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: - web_server_ = await cg.get_variable(webserver_id) - web_server.add_entity_to_sorting_list(web_server_, var, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) async def register_valve(var, config): diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index 02074dcf11..d846a3418b 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -17,13 +17,14 @@ from esphome.const import ( CONF_JS_URL, CONF_LOCAL, CONF_LOG, + CONF_NAME, CONF_OTA, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERSION, + CONF_WEB_SERVER, CONF_WEB_SERVER_ID, - CONF_WEB_SERVER_SORTING_WEIGHT, PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, @@ -34,9 +35,15 @@ import esphome.final_validate as fv AUTO_LOAD = ["json", "web_server_base"] +CONF_SORTING_GROUP_ID = "sorting_group_id" +CONF_SORTING_GROUPS = "sorting_groups" +CONF_SORTING_WEIGHT = "sorting_weight" + web_server_ns = cg.esphome_ns.namespace("web_server") WebServer = web_server_ns.class_("WebServer", cg.Component, cg.Controller) +sorting_groups = {} + def default_url(config): config = config.copy() @@ -70,42 +77,74 @@ def validate_ota(config): return config -def _validate_no_sorting_weight( - webserver_version: int, config: dict, path: list[str] | None = None -) -> None: - if path is None: - path = [] - if CONF_WEB_SERVER_SORTING_WEIGHT in config: - raise cv.FinalExternalInvalid( - f"Sorting weight on entities is not supported in web_server version {webserver_version}", - path=path + [CONF_WEB_SERVER_SORTING_WEIGHT], +def validate_sorting_groups(config): + if CONF_SORTING_GROUPS in config and config[CONF_VERSION] != 3: + raise cv.Invalid( + f"'{CONF_SORTING_GROUPS}' is only supported in 'web_server' version 3" ) - for p, value in config.items(): - if isinstance(value, dict): - _validate_no_sorting_weight(webserver_version, value, path + [p]) - elif isinstance(value, list): - for i, item in enumerate(value): - if isinstance(item, dict): - _validate_no_sorting_weight(webserver_version, item, path + [p, i]) - - -def _final_validate_sorting_weight(config): - if (webserver_version := config.get(CONF_VERSION)) != 3: - _validate_no_sorting_weight(webserver_version, fv.full_config.get()) - return config -FINAL_VALIDATE_SCHEMA = _final_validate_sorting_weight +def _validate_no_sorting_component( + sorting_component: str, + webserver_version: int, + config: dict, + path: list[str] | None = None, +) -> None: + if path is None: + path = [] + if CONF_WEB_SERVER in config and sorting_component in config[CONF_WEB_SERVER]: + raise cv.FinalExternalInvalid( + f"{sorting_component} on entities is not supported in web_server version {webserver_version}", + path=path + [sorting_component], + ) + for p, value in config.items(): + if isinstance(value, dict): + _validate_no_sorting_component( + sorting_component, webserver_version, value, path + [p] + ) + elif isinstance(value, list): + for i, item in enumerate(value): + if isinstance(item, dict): + _validate_no_sorting_component( + sorting_component, webserver_version, item, path + [p, i] + ) +def _final_validate_sorting(config): + if (webserver_version := config.get(CONF_VERSION)) != 3: + _validate_no_sorting_component( + CONF_SORTING_WEIGHT, webserver_version, fv.full_config.get() + ) + _validate_no_sorting_component( + CONF_SORTING_GROUP_ID, webserver_version, fv.full_config.get() + ) + return config + + +FINAL_VALIDATE_SCHEMA = _final_validate_sorting + +sorting_group = { + cv.Required(CONF_ID): cv.declare_id(cg.int_), + cv.Required(CONF_NAME): cv.string, + cv.Optional(CONF_SORTING_WEIGHT): cv.float_, +} + WEBSERVER_SORTING_SCHEMA = cv.Schema( { - cv.OnlyWith(CONF_WEB_SERVER_ID, "web_server"): cv.use_id(WebServer), - cv.Optional(CONF_WEB_SERVER_SORTING_WEIGHT): cv.All( - cv.requires_component("web_server"), - cv.float_, - ), + cv.Optional(CONF_WEB_SERVER): cv.Schema( + { + cv.OnlyWith(CONF_WEB_SERVER_ID, "web_server"): cv.use_id(WebServer), + cv.Optional(CONF_SORTING_WEIGHT): cv.All( + cv.requires_component("web_server"), + cv.float_, + ), + cv.Optional(CONF_SORTING_GROUP_ID): cv.All( + cv.requires_component("web_server"), + cv.use_id(cg.int_), + ), + } + ) } ) @@ -145,24 +184,38 @@ CONFIG_SCHEMA = cv.All( ): cv.boolean, cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, + cv.Optional(CONF_SORTING_GROUPS): cv.ensure_list(sorting_group), } ).extend(cv.COMPONENT_SCHEMA), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), default_url, validate_local, validate_ota, + validate_sorting_groups, ) -def add_entity_to_sorting_list(web_server, entity, config): - sorting_weight = 50 - if CONF_WEB_SERVER_SORTING_WEIGHT in config: - sorting_weight = config[CONF_WEB_SERVER_SORTING_WEIGHT] +def add_sorting_groups(web_server_var, config): + for group in config: + sorting_groups[group[CONF_ID]] = group[CONF_NAME] + group_sorting_weight = group.get(CONF_SORTING_WEIGHT, 50) + cg.add( + web_server_var.add_sorting_group( + hash(group[CONF_ID]), group[CONF_NAME], group_sorting_weight + ) + ) + + +async def add_entity_config(entity, config): + web_server = await cg.get_variable(config[CONF_WEB_SERVER_ID]) + sorting_weight = config.get(CONF_SORTING_WEIGHT, 50) + sorting_group_hash = hash(config.get(CONF_SORTING_GROUP_ID)) cg.add( - web_server.add_entity_to_sorting_list( + web_server.add_entity_config( entity, sorting_weight, + sorting_group_hash, ) ) @@ -241,3 +294,6 @@ async def to_code(config): cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL])) if CONF_LOCAL in config and config[CONF_LOCAL]: cg.add_define("USE_WEBSERVER_LOCAL") + + if (sorting_group_config := config.get(CONF_SORTING_GROUPS)) is not None: + add_sorting_groups(var, sorting_group_config) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index dc27db2f41..192feb78d5 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -105,6 +105,14 @@ void WebServer::setup() { // Configure reconnect timeout and send config client->send(this->get_config_json().c_str(), "ping", millis(), 30000); + for (auto &group : this->sorting_groups_) { + client->send(json::build_json([group](JsonObject root) { + root["name"] = group.second.name; + root["sorting_weight"] = group.second.weight; + }).c_str(), + "sorting_group"); + } + this->entities_iterator_.begin(this->include_internal_); }); @@ -246,6 +254,9 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } if (!obj->get_unit_of_measurement().empty()) root["uom"] = obj->get_unit_of_measurement(); @@ -284,6 +295,9 @@ std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std: if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -332,6 +346,9 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail root["assumed_state"] = obj->assumed_state(); if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -368,6 +385,9 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config) if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -404,6 +424,9 @@ std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -487,6 +510,9 @@ std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) { if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -603,6 +629,9 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi } if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -684,6 +713,9 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) { if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -745,6 +777,9 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail root["uom"] = obj->traits.get_unit_of_measurement(); if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } if (std::isnan(value)) { @@ -814,6 +849,9 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -872,6 +910,9 @@ std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_con if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -931,6 +972,9 @@ std::string WebServer::datetime_json(datetime::DateTimeEntity *obj, JsonDetail s if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -992,6 +1036,9 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json root["mode"] = (int) obj->traits.get_mode(); if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -1048,6 +1095,9 @@ std::string WebServer::select_json(select::Select *obj, const std::string &value } if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -1164,6 +1214,9 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf } if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } @@ -1257,6 +1310,9 @@ std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDet if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -1326,8 +1382,13 @@ std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) { if (obj->get_traits().get_supports_position()) root["position"] = obj->position; - if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { - root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (start_config == DETAIL_ALL) { + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } + } } }); } @@ -1367,6 +1428,9 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro if (start_config == DETAIL_ALL) { if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -1453,6 +1517,9 @@ std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_c root["release_url"] = obj->update_info.release_url; if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } } } }); @@ -1751,8 +1818,12 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { bool WebServer::isRequestHandlerTrivial() { return false; } -void WebServer::add_entity_to_sorting_list(EntityBase *entity, float weight) { - this->sorting_entitys_[entity] = SortingComponents{weight}; +void WebServer::add_entity_config(EntityBase *entity, float weight, uint64_t group) { + this->sorting_entitys_[entity] = SortingComponents{weight, group}; +} + +void WebServer::add_sorting_group(uint64_t group_id, const std::string &group_name, float weight) { + this->sorting_groups_[group_id] = SortingGroup{group_name, weight}; } void WebServer::schedule_(std::function &&f) { diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 3195fa7109..ea1f62fc43 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -44,6 +44,12 @@ struct UrlMatch { struct SortingComponents { float weight; + uint64_t group_id; +}; + +struct SortingGroup { + std::string name; + float weight; }; enum JsonDetail { DETAIL_ALL, DETAIL_STATE }; @@ -337,7 +343,8 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { /// This web handle is not trivial. bool isRequestHandlerTrivial() override; // NOLINT(readability-identifier-naming) - void add_entity_to_sorting_list(EntityBase *entity, float weight); + void add_entity_config(EntityBase *entity, float weight, uint64_t group); + void add_sorting_group(uint64_t group_id, const std::string &group_name, float weight); protected: void schedule_(std::function &&f); @@ -346,6 +353,8 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { AsyncEventSource events_{"/events"}; ListEntitiesIterator entities_iterator_; std::map sorting_entitys_; + std::map sorting_groups_; + #if USE_WEBSERVER_VERSION == 1 const char *css_url_{nullptr}; const char *js_url_{nullptr}; diff --git a/esphome/const.py b/esphome/const.py index 506a30f5ed..08fb34976b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -934,7 +934,6 @@ CONF_WARM_WHITE_COLOR_TEMPERATURE = "warm_white_color_temperature" CONF_WATCHDOG_THRESHOLD = "watchdog_threshold" CONF_WEB_SERVER = "web_server" CONF_WEB_SERVER_ID = "web_server_id" -CONF_WEB_SERVER_SORTING_WEIGHT = "web_server_sorting_weight" CONF_WEIGHT = "weight" CONF_WHILE = "while" CONF_WHITE = "white" diff --git a/tests/components/web_server/common_v3.yaml b/tests/components/web_server/common_v3.yaml new file mode 100644 index 0000000000..69f4b67f15 --- /dev/null +++ b/tests/components/web_server/common_v3.yaml @@ -0,0 +1,37 @@ +packages: + device_base: !include common.yaml + +web_server: + port: 8080 + version: 3 + sorting_groups: + - id: sorting_group_1 + name: "Group 1 Diplayed Last" + sorting_weight: 40 + - id: sorting_group_2 + name: "Group 2 Displayed Third" + sorting_weight: 30 + - id: sorting_group_3 + name: "Group 3 Displayed Second" + sorting_weight: 20 + - id: sorting_group_4 + name: "Group 4 Displayed First" + sorting_weight: 10 + +number: + - platform: template + name: "Template number" + optimistic: true + min_value: 0 + max_value: 100 + step: 1 + web_server: + sorting_group_id: sorting_group_1 + sorting_weight: -1 +switch: + - platform: template + name: "Template Switch" + optimistic: true + web_server: + sorting_group_id: sorting_group_2 + sorting_weight: -10 diff --git a/tests/components/web_server/test_v3.esp32-ard.yaml b/tests/components/web_server/test_v3.esp32-ard.yaml new file mode 100644 index 0000000000..00d05521e4 --- /dev/null +++ b/tests/components/web_server/test_v3.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common_v3.yaml From 5ad5ef5a42b5000facf203171d6b4efa41ac074c Mon Sep 17 00:00:00 2001 From: Ken Baker Date: Sun, 6 Oct 2024 22:58:28 -0400 Subject: [PATCH 2471/2607] Add Initial TE-M3200 pressure sensor support (#6862) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/tem3200/__init__.py | 0 esphome/components/tem3200/sensor.py | 55 +++++++ esphome/components/tem3200/tem3200.cpp | 151 ++++++++++++++++++ esphome/components/tem3200/tem3200.h | 30 ++++ tests/components/tem3200/common.yaml | 16 ++ tests/components/tem3200/test.esp32-ard.yaml | 5 + tests/components/tem3200/test.esp32-idf.yaml | 5 + .../components/tem3200/test.esp32-s3-ard.yaml | 5 + .../components/tem3200/test.esp32-s3-idf.yaml | 5 + .../components/tem3200/test.esp8266-ard.yaml | 5 + 11 files changed, 278 insertions(+) create mode 100644 esphome/components/tem3200/__init__.py create mode 100644 esphome/components/tem3200/sensor.py create mode 100644 esphome/components/tem3200/tem3200.cpp create mode 100644 esphome/components/tem3200/tem3200.h create mode 100644 tests/components/tem3200/common.yaml create mode 100644 tests/components/tem3200/test.esp32-ard.yaml create mode 100644 tests/components/tem3200/test.esp32-idf.yaml create mode 100644 tests/components/tem3200/test.esp32-s3-ard.yaml create mode 100644 tests/components/tem3200/test.esp32-s3-idf.yaml create mode 100644 tests/components/tem3200/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 180024cd37..f202936972 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -406,6 +406,7 @@ esphome/components/tca9555/* @mobrembski esphome/components/tcl112/* @glmnet esphome/components/tee501/* @Stock-M esphome/components/teleinfo/* @0hax +esphome/components/tem3200/* @bakerkj esphome/components/template/alarm_control_panel/* @grahambrown11 @hwstar esphome/components/template/datetime/* @rfdarter esphome/components/template/event/* @nohat diff --git a/esphome/components/tem3200/__init__.py b/esphome/components/tem3200/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/tem3200/sensor.py b/esphome/components/tem3200/sensor.py new file mode 100644 index 0000000000..5cd27433d0 --- /dev/null +++ b/esphome/components/tem3200/sensor.py @@ -0,0 +1,55 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor + +from esphome.const import ( + CONF_ID, + CONF_TEMPERATURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) + +CODEOWNERS = ["@bakerkj"] +DEPENDENCIES = ["i2c"] + +tem3200_ns = cg.esphome_ns.namespace("tem3200") + +TEM3200Component = tem3200_ns.class_( + "TEM3200Component", cg.PollingComponent, i2c.I2CDevice +) + +CONF_RAW_PRESSURE = "raw_pressure" + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(TEM3200Component), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RAW_PRESSURE): sensor.sensor_schema( + accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x28)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + + if raw_pressure_config := config.get(CONF_RAW_PRESSURE): + sens = await sensor.new_sensor(raw_pressure_config) + cg.add(var.set_raw_pressure_sensor(sens)) diff --git a/esphome/components/tem3200/tem3200.cpp b/esphome/components/tem3200/tem3200.cpp new file mode 100644 index 0000000000..d8ce48af90 --- /dev/null +++ b/esphome/components/tem3200/tem3200.cpp @@ -0,0 +1,151 @@ +#include "tem3200.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace tem3200 { + +static const char *const TAG = "tem3200"; + +enum ErrorCode { + NONE = 0, + RESERVED = 1, + STALE = 2, + FAULT = 3, +}; + +void TEM3200Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up TEM3200..."); + + uint8_t status(NONE); + uint16_t raw_temperature(0); + uint16_t raw_pressure(0); + + i2c::ErrorCode err = this->read_(status, raw_temperature, raw_pressure); + if (err != i2c::ERROR_OK) { + ESP_LOGCONFIG(TAG, " I2C Communication Failed..."); + this->mark_failed(); + return; + } + + switch (status) { + case RESERVED: + ESP_LOGE(TAG, "Invalid RESERVED Device Status"); + this->mark_failed(); + return; + case FAULT: + ESP_LOGE(TAG, "FAULT condition in the SSC or sensing element"); + this->mark_failed(); + return; + case STALE: + ESP_LOGE(TAG, "STALE data. Data has not been updated since last fetch"); + this->status_set_warning(); + break; + } + ESP_LOGCONFIG(TAG, " Success..."); +} + +void TEM3200Component::dump_config() { + ESP_LOGCONFIG(TAG, "TEM3200:"); + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Raw Pressure", this->raw_pressure_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); +} + +float TEM3200Component::get_setup_priority() const { return setup_priority::DATA; } + +i2c::ErrorCode TEM3200Component::read_(uint8_t &status, uint16_t &raw_temperature, uint16_t &raw_pressure) { + uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; + + // initiate data read + i2c::ErrorCode err = this->read(response, 4); + if (err != i2c::ERROR_OK) { + return err; + } + + // extract top 2 bits of first byte for status + status = (ErrorCode) (response[0] & 0xc0) >> 6; + if (status == RESERVED || status == FAULT) { + return i2c::ERROR_OK; + } + + // if data is stale; reread + if (status == STALE) { + // wait for measurement 2ms + delay(2); + + err = this->read(response, 4); + if (err != i2c::ERROR_OK) { + return err; + } + } + + // extract top 2 bits of first byte for status + status = (ErrorCode) (response[0] & 0xc0) >> 6; + if (status == RESERVED || status == FAULT) { + return i2c::ERROR_OK; + } + + // extract top 6 bits of first byte and all bits of second byte for pressure + raw_pressure = (((response[0] & 0x3f)) << 8 | response[1]); + + // extract all bytes of 3rd byte and top 3 bits of fourth byte for temperature + raw_temperature = ((response[2] << 3) | (response[3] & 0xe0) >> 5); + + return i2c::ERROR_OK; +} + +inline float convert_temperature(uint16_t raw_temperature) { + const float temperature_bits_span = 2048; + const float temperature_max = 150; + const float temperature_min = -50; + const float temperature_span = temperature_max - temperature_min; + + float temperature = (raw_temperature * temperature_span / temperature_bits_span) + temperature_min; + + return temperature; +} + +void TEM3200Component::update() { + uint8_t status(NONE); + uint16_t raw_temperature(0); + uint16_t raw_pressure(0); + i2c::ErrorCode err = this->read_(status, raw_temperature, raw_pressure); + + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "I2C Communication Failed"); + this->status_set_warning(); + return; + } + + switch (status) { + case RESERVED: + ESP_LOGE(TAG, "Failed: Device return RESERVED status"); + this->status_set_warning(); + return; + case FAULT: + ESP_LOGE(TAG, "Failed: FAULT condition in the SSC or sensing element"); + this->mark_failed(); + return; + case STALE: + ESP_LOGE(TAG, "Warning: STALE data. Data has not been updated since last fetch"); + this->status_set_warning(); + return; + } + + float temperature = convert_temperature(raw_temperature); + + ESP_LOGD(TAG, "Got raw pressure=%d, temperature=%.1f°C", raw_pressure, temperature); + + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(temperature); + if (this->raw_pressure_sensor_ != nullptr) + this->raw_pressure_sensor_->publish_state(raw_pressure); + + this->status_clear_warning(); +} + +} // namespace tem3200 +} // namespace esphome diff --git a/esphome/components/tem3200/tem3200.h b/esphome/components/tem3200/tem3200.h new file mode 100644 index 0000000000..c84a2aba21 --- /dev/null +++ b/esphome/components/tem3200/tem3200.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace tem3200 { + +/// This class implements support for the tem3200 pressure and temperature i2c sensors. +class TEM3200Component : public PollingComponent, public i2c::I2CDevice { + public: + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } + void set_raw_pressure_sensor(sensor::Sensor *raw_pressure_sensor) { + this->raw_pressure_sensor_ = raw_pressure_sensor; + } + + float get_setup_priority() const override; + void setup() override; + void dump_config() override; + void update() override; + + protected: + i2c::ErrorCode read_(uint8_t &status, uint16_t &raw_temperature, uint16_t &raw_pressure); + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *raw_pressure_sensor_{nullptr}; +}; + +} // namespace tem3200 +} // namespace esphome diff --git a/tests/components/tem3200/common.yaml b/tests/components/tem3200/common.yaml new file mode 100644 index 0000000000..392c853bf4 --- /dev/null +++ b/tests/components/tem3200/common.yaml @@ -0,0 +1,16 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + frequency: 200kHz + +sensor: + - platform: tem3200 + update_interval: 1s + i2c_id: i2c_bus + + temperature: + name: water temperature + + raw_pressure: + name: water pressure diff --git a/tests/components/tem3200/test.esp32-ard.yaml b/tests/components/tem3200/test.esp32-ard.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/tem3200/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/tem3200/test.esp32-idf.yaml b/tests/components/tem3200/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/tem3200/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/tem3200/test.esp32-s3-ard.yaml b/tests/components/tem3200/test.esp32-s3-ard.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/tem3200/test.esp32-s3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/tem3200/test.esp32-s3-idf.yaml b/tests/components/tem3200/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/tem3200/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/tem3200/test.esp8266-ard.yaml b/tests/components/tem3200/test.esp8266-ard.yaml new file mode 100644 index 0000000000..3be5e53dcb --- /dev/null +++ b/tests/components/tem3200/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO05 + sda_pin: GPIO04 + +<<: !include common.yaml From b2bf2bc448a4e2b0bb92dc6d2d9358ab6c4ed775 Mon Sep 17 00:00:00 2001 From: Ken Baker Date: Sun, 6 Oct 2024 22:59:13 -0400 Subject: [PATCH 2472/2607] Add Initial NPI-19 pressure sensor support (#7181) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/npi19/__init__.py | 0 esphome/components/npi19/npi19.cpp | 111 ++++++++++++++++++ esphome/components/npi19/npi19.h | 30 +++++ esphome/components/npi19/sensor.py | 52 ++++++++ tests/components/npi19/common.yaml | 16 +++ tests/components/npi19/test.esp32-ard.yaml | 5 + tests/components/npi19/test.esp32-idf.yaml | 5 + tests/components/npi19/test.esp32-s3-ard.yaml | 5 + tests/components/npi19/test.esp32-s3-idf.yaml | 5 + tests/components/npi19/test.esp8266-ard.yaml | 5 + 11 files changed, 235 insertions(+) create mode 100644 esphome/components/npi19/__init__.py create mode 100644 esphome/components/npi19/npi19.cpp create mode 100644 esphome/components/npi19/npi19.h create mode 100644 esphome/components/npi19/sensor.py create mode 100644 tests/components/npi19/common.yaml create mode 100644 tests/components/npi19/test.esp32-ard.yaml create mode 100644 tests/components/npi19/test.esp32-idf.yaml create mode 100644 tests/components/npi19/test.esp32-s3-ard.yaml create mode 100644 tests/components/npi19/test.esp32-s3-idf.yaml create mode 100644 tests/components/npi19/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index f202936972..c6ef528a8c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -291,6 +291,7 @@ esphome/components/nextion/switch/* @senexcrenshaw esphome/components/nextion/text_sensor/* @senexcrenshaw esphome/components/nfc/* @jesserockz @kbx81 esphome/components/noblex/* @AGalfra +esphome/components/npi19/* @bakerkj esphome/components/number/* @esphome/core esphome/components/one_wire/* @ssieb esphome/components/online_image/* @guillempages diff --git a/esphome/components/npi19/__init__.py b/esphome/components/npi19/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/npi19/npi19.cpp b/esphome/components/npi19/npi19.cpp new file mode 100644 index 0000000000..ca1fc39943 --- /dev/null +++ b/esphome/components/npi19/npi19.cpp @@ -0,0 +1,111 @@ +#include "npi19.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace npi19 { + +static const char *const TAG = "npi19"; + +static const uint8_t READ_COMMAND = 0xAC; + +void NPI19Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up NPI19..."); + + uint16_t raw_temperature(0); + uint16_t raw_pressure(0); + i2c::ErrorCode err = this->read_(raw_temperature, raw_pressure); + if (err != i2c::ERROR_OK) { + ESP_LOGCONFIG(TAG, " I2C Communication Failed..."); + this->mark_failed(); + return; + } + + ESP_LOGCONFIG(TAG, " Success..."); +} + +void NPI19Component::dump_config() { + ESP_LOGCONFIG(TAG, "NPI19:"); + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Raw Pressure", this->raw_pressure_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); +} + +float NPI19Component::get_setup_priority() const { return setup_priority::DATA; } + +i2c::ErrorCode NPI19Component::read_(uint16_t &raw_temperature, uint16_t &raw_pressure) { + // initiate data read from device + i2c::ErrorCode w_err = write(&READ_COMMAND, sizeof(READ_COMMAND), true); + if (w_err != i2c::ERROR_OK) { + return w_err; + } + + // read 4 bytes from senesor + uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; + i2c::ErrorCode r_err = this->read(response, 4); + + if (r_err != i2c::ERROR_OK) { + return r_err; + } + + // extract top 6 bits of first byte and all bits of second byte for pressure + raw_pressure = ((response[0] & 0x3F) << 8) | response[1]; + + // extract all bytes of 3rd byte and top 3 bits of fourth byte for temperature + raw_temperature = (response[2] << 3) | ((response[3] & 0xE0) >> 5); + + return i2c::ERROR_OK; +} + +inline float convert_temperature(uint16_t raw_temperature) { + /* + * Correspondance with Amphenol confirmed the appropriate equation for computing temperature is: + * T (°C) =(((((Th*8)+Tl)/2048)*200)-50), where Th is the high (third) byte and Tl is the low (fourth) byte. + * + * Tl is actually the upper 3 bits of the fourth data byte; the first 5 (LSBs) must be masked out. + * + * + * The NPI-19 I2C has a temperature output, however the manufacturer does + * not specify its accuracy on the published datasheet. They indicate + * that the sensor should not be used as a calibrated temperature + * reading; it’s only intended for curve fitting data during + * compensation. + */ + const float temperature_bits_span = 2048; + const float temperature_max = 150; + const float temperature_min = -50; + const float temperature_span = temperature_max - temperature_min; + + float temperature = (raw_temperature * temperature_span / temperature_bits_span) + temperature_min; + + return temperature; +} + +void NPI19Component::update() { + uint16_t raw_temperature(0); + uint16_t raw_pressure(0); + + i2c::ErrorCode err = this->read_(raw_temperature, raw_pressure); + + if (err != i2c::ERROR_OK) { + ESP_LOGW(TAG, "I2C Communication Failed"); + this->status_set_warning(); + return; + } + + float temperature = convert_temperature(raw_temperature); + + ESP_LOGD(TAG, "Got raw pressure=%d, temperature=%.1f°C", raw_pressure, temperature); + + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(temperature); + if (this->raw_pressure_sensor_ != nullptr) + this->raw_pressure_sensor_->publish_state(raw_pressure); + + this->status_clear_warning(); +} + +} // namespace npi19 +} // namespace esphome diff --git a/esphome/components/npi19/npi19.h b/esphome/components/npi19/npi19.h new file mode 100644 index 0000000000..df289dffc1 --- /dev/null +++ b/esphome/components/npi19/npi19.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace npi19 { + +/// This class implements support for the npi19 pressure and temperature i2c sensors. +class NPI19Component : public PollingComponent, public i2c::I2CDevice { + public: + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } + void set_raw_pressure_sensor(sensor::Sensor *raw_pressure_sensor) { + this->raw_pressure_sensor_ = raw_pressure_sensor; + } + + float get_setup_priority() const override; + void setup() override; + void dump_config() override; + void update() override; + + protected: + i2c::ErrorCode read_(uint16_t &raw_temperature, uint16_t &raw_pressure); + sensor::Sensor *temperature_sensor_{nullptr}; + sensor::Sensor *raw_pressure_sensor_{nullptr}; +}; + +} // namespace npi19 +} // namespace esphome diff --git a/esphome/components/npi19/sensor.py b/esphome/components/npi19/sensor.py new file mode 100644 index 0000000000..d13e72f5f8 --- /dev/null +++ b/esphome/components/npi19/sensor.py @@ -0,0 +1,52 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_TEMPERATURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) + +CODEOWNERS = ["@bakerkj"] +DEPENDENCIES = ["i2c"] + +npi19_ns = cg.esphome_ns.namespace("npi19") + +NPI19Component = npi19_ns.class_("NPI19Component", cg.PollingComponent, i2c.I2CDevice) + +CONF_RAW_PRESSURE = "raw_pressure" + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(NPI19Component), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RAW_PRESSURE): sensor.sensor_schema( + accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x28)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if temperature_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temperature_config) + cg.add(var.set_temperature_sensor(sens)) + + if raw_pressure_config := config.get(CONF_RAW_PRESSURE): + sens = await sensor.new_sensor(raw_pressure_config) + cg.add(var.set_raw_pressure_sensor(sens)) diff --git a/tests/components/npi19/common.yaml b/tests/components/npi19/common.yaml new file mode 100644 index 0000000000..012e05695e --- /dev/null +++ b/tests/components/npi19/common.yaml @@ -0,0 +1,16 @@ +i2c: + id: i2c_bus + scl: ${scl_pin} + sda: ${sda_pin} + frequency: 200kHz + +sensor: + - platform: npi19 + update_interval: 1s + i2c_id: i2c_bus + + temperature: + name: water temperature + + raw_pressure: + name: water pressure diff --git a/tests/components/npi19/test.esp32-ard.yaml b/tests/components/npi19/test.esp32-ard.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/npi19/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/npi19/test.esp32-idf.yaml b/tests/components/npi19/test.esp32-idf.yaml new file mode 100644 index 0000000000..3b761d3fc1 --- /dev/null +++ b/tests/components/npi19/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO22 + sda_pin: GPIO21 + +<<: !include common.yaml diff --git a/tests/components/npi19/test.esp32-s3-ard.yaml b/tests/components/npi19/test.esp32-s3-ard.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/npi19/test.esp32-s3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/npi19/test.esp32-s3-idf.yaml b/tests/components/npi19/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..4942e3c2b3 --- /dev/null +++ b/tests/components/npi19/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO40 + sda_pin: GPIO41 + +<<: !include common.yaml diff --git a/tests/components/npi19/test.esp8266-ard.yaml b/tests/components/npi19/test.esp8266-ard.yaml new file mode 100644 index 0000000000..3be5e53dcb --- /dev/null +++ b/tests/components/npi19/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO05 + sda_pin: GPIO04 + +<<: !include common.yaml From ea23f49e90fb8848657f2ba1408fb30ce386b829 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Sun, 6 Oct 2024 20:08:56 -0700 Subject: [PATCH 2473/2607] nau7802: new component (#6291) --- CODEOWNERS | 1 + esphome/components/nau7802/__init__.py | 0 esphome/components/nau7802/nau7802.cpp | 323 ++++++++++++++++++ esphome/components/nau7802/nau7802.h | 121 +++++++ esphome/components/nau7802/sensor.py | 134 ++++++++ tests/components/nau7802/common.yaml | 13 + tests/components/nau7802/test.esp32-ard.yaml | 6 + .../components/nau7802/test.esp32-c3-ard.yaml | 6 + .../components/nau7802/test.esp32-c3-idf.yaml | 6 + tests/components/nau7802/test.esp32-idf.yaml | 6 + .../components/nau7802/test.esp8266-ard.yaml | 6 + tests/components/nau7802/test.rp2040-ard.yaml | 6 + 12 files changed, 628 insertions(+) create mode 100644 esphome/components/nau7802/__init__.py create mode 100644 esphome/components/nau7802/nau7802.cpp create mode 100644 esphome/components/nau7802/nau7802.h create mode 100644 esphome/components/nau7802/sensor.py create mode 100644 tests/components/nau7802/common.yaml create mode 100644 tests/components/nau7802/test.esp32-ard.yaml create mode 100644 tests/components/nau7802/test.esp32-c3-ard.yaml create mode 100644 tests/components/nau7802/test.esp32-c3-idf.yaml create mode 100644 tests/components/nau7802/test.esp32-idf.yaml create mode 100644 tests/components/nau7802/test.esp8266-ard.yaml create mode 100644 tests/components/nau7802/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c6ef528a8c..ed9c13a975 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -283,6 +283,7 @@ esphome/components/mopeka_std_check/* @Fabian-Schmidt esphome/components/mpl3115a2/* @kbickar esphome/components/mpu6886/* @fabaff esphome/components/ms8607/* @e28eta +esphome/components/nau7802/* @cujomalainey esphome/components/network/* @esphome/core esphome/components/nextion/* @edwardtfn @senexcrenshaw esphome/components/nextion/binary_sensor/* @senexcrenshaw diff --git a/esphome/components/nau7802/__init__.py b/esphome/components/nau7802/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/nau7802/nau7802.cpp b/esphome/components/nau7802/nau7802.cpp new file mode 100644 index 0000000000..ea6c0258af --- /dev/null +++ b/esphome/components/nau7802/nau7802.cpp @@ -0,0 +1,323 @@ +#include "nau7802.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace nau7802 { + +static const char *const TAG = "nau7802"; + +// Only define what we need + +static const uint8_t READ_BIT = 0x01; + +static const uint8_t PU_CTRL_REG = 0x00; +static const uint8_t PU_CTRL_REGISTER_RESET = 0x01; +static const uint8_t PU_CTRL_POWERUP_DIGITAL = 0x02; +static const uint8_t PU_CTRL_POWERUP_ANALOG = 0x04; +static const uint8_t PU_CTRL_POWERUP_READY = 0x08; +static const uint8_t PU_CTRL_CYCLE_START = 0x10; +static const uint8_t PU_CTRL_CYCLE_READY = 0x20; +static const uint8_t PU_CTRL_AVDD_EXTERNAL = 0x80; + +static const uint8_t CTRL1_REG = 0x01; +static const uint8_t CTRL1_LDO_SHIFT = 3; +static const uint8_t CTRL1_LDO_MASK = (0x7 << CTRL1_LDO_SHIFT); +static const uint8_t CTRL1_GAIN_MASK = 0x7; + +static const uint8_t CTRL2_REG = 0x02; +static const uint8_t CTRL2_CRS_SHIFT = 4; +static const uint8_t CTRL2_CRS_MASK = (0x7 << CTRL2_CRS_SHIFT); +static const uint8_t CTRL2_CALS = 0x04; +static const uint8_t CTRL2_CAL_ERR = 0x08; +static const uint8_t CTRL2_GAIN_CALIBRATION = 0x03; +static const uint8_t CTRL2_CONFIG_MASK = 0xF0; + +static const uint8_t OCAL1_B2_REG = 0x03; +static const uint8_t GCAL1_B3_REG = 0x06; +static const uint8_t GCAL1_FRACTIONAL = 23; + +// only need the first data register for sequential read method +static const uint8_t ADCO_B2_REG = 0x12; + +static const uint8_t ADC_REG = 0x15; +static const uint8_t ADC_CHPS_DISABLE = 0x30; + +static const uint8_t PGA_REG = 0x1B; +static const uint8_t PGA_LDOMODE_ESR = 0x40; + +static const uint8_t POWER_REG = 0x1C; +static const uint8_t POWER_PGA_CAP_EN = 0x80; + +static const uint8_t DEVICE_REV = 0x1F; + +void NAU7802Sensor::setup() { + i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG); + ESP_LOGCONFIG(TAG, "Setting up NAU7802 '%s'...", this->name_.c_str()); + uint8_t rev; + + if (this->read_register(DEVICE_REV | READ_BIT, &rev, 1)) { + ESP_LOGE(TAG, "Failed I2C read during setup()"); + this->mark_failed(); + return; + } + ESP_LOGI(TAG, "Setting up NAU7802 Rev %d", rev); + + // reset + pu_ctrl |= PU_CTRL_REGISTER_RESET; + delay(10); + pu_ctrl &= ~PU_CTRL_REGISTER_RESET; + + // power up digital hw + pu_ctrl |= PU_CTRL_POWERUP_DIGITAL; + + delay(1); + if (!(pu_ctrl.get() & PU_CTRL_POWERUP_READY)) { + ESP_LOGE(TAG, "Failed to reset sensor during setup()"); + this->mark_failed(); + return; + } + + uint32_t gcal = (uint32_t) (round(this->gain_calibration_ * (1 << GCAL1_FRACTIONAL))); + this->write_value_(OCAL1_B2_REG, 3, this->offset_calibration_); + this->write_value_(GCAL1_B3_REG, 4, gcal); + + // turn on AFE + pu_ctrl |= PU_CTRL_POWERUP_ANALOG; + auto f = std::bind(&NAU7802Sensor::complete_setup_, this); + this->set_timeout(600, f); +} + +void NAU7802Sensor::complete_setup_() { + i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG); + i2c::I2CRegister ctrl1 = this->reg(CTRL1_REG); + i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG); + pu_ctrl |= PU_CTRL_CYCLE_START; + + // set gain + ctrl1 &= ~CTRL1_GAIN_MASK; + ctrl1 |= this->gain_; + + // enable internal LDO + if (this->ldo_ != NAU7802_LDO_EXTERNAL) { + pu_ctrl |= PU_CTRL_AVDD_EXTERNAL; + ctrl1 &= ~CTRL1_LDO_MASK; + ctrl1 |= this->ldo_ << CTRL1_LDO_SHIFT; + } + + // set sps + ctrl2 &= ~CTRL2_CRS_MASK; + ctrl2 |= this->sps_ << CTRL2_CRS_SHIFT; + + // disable ADC chopper clock + i2c::I2CRegister adc_reg = this->reg(ADC_REG); + adc_reg |= ADC_CHPS_DISABLE; + + // use low ESR caps + i2c::I2CRegister pga_reg = this->reg(PGA_REG); + pga_reg &= ~PGA_LDOMODE_ESR; + + // PGA stabilizer cap on output + i2c::I2CRegister pwr_reg = this->reg(POWER_REG); + pwr_reg |= POWER_PGA_CAP_EN; + + this->setup_complete_ = true; +} + +void NAU7802Sensor::dump_config() { + LOG_SENSOR("", "NAU7802", this); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with NAU7802 failed earlier, during setup"); + return; + } + // Note these may differ from the values on the device if calbration has been run + ESP_LOGCONFIG(TAG, " Offset Calibration: %s", to_string(this->offset_calibration_).c_str()); + ESP_LOGCONFIG(TAG, " Gain Calibration: %f", this->gain_calibration_); + + std::string voltage = "unknown"; + switch (this->ldo_) { + case NAU7802_LDO_2V4: + voltage = "2.4V"; + break; + case NAU7802_LDO_2V7: + voltage = "2.7V"; + break; + case NAU7802_LDO_3V0: + voltage = "3.0V"; + break; + case NAU7802_LDO_3V3: + voltage = "3.3V"; + break; + case NAU7802_LDO_3V6: + voltage = "3.6V"; + break; + case NAU7802_LDO_3V9: + voltage = "3.9V"; + break; + case NAU7802_LDO_4V2: + voltage = "4.2V"; + break; + case NAU7802_LDO_4V5: + voltage = "4.5V"; + break; + case NAU7802_LDO_EXTERNAL: + voltage = "External"; + break; + } + ESP_LOGCONFIG(TAG, " LDO Voltage: %s", voltage.c_str()); + int gain = 0; + switch (this->gain_) { + case NAU7802_GAIN_128: + gain = 128; + break; + case NAU7802_GAIN_64: + gain = 64; + break; + case NAU7802_GAIN_32: + gain = 32; + break; + case NAU7802_GAIN_16: + gain = 16; + break; + case NAU7802_GAIN_8: + gain = 8; + break; + case NAU7802_GAIN_4: + gain = 4; + break; + case NAU7802_GAIN_2: + gain = 2; + break; + case NAU7802_GAIN_1: + gain = 1; + break; + } + ESP_LOGCONFIG(TAG, " Gain: %dx", gain); + int sps = 0; + switch (this->sps_) { + case NAU7802_SPS_320: + sps = 320; + break; + case NAU7802_SPS_80: + sps = 80; + break; + case NAU7802_SPS_40: + sps = 40; + break; + case NAU7802_SPS_20: + sps = 20; + break; + case NAU7802_SPS_10: + sps = 10; + break; + } + ESP_LOGCONFIG(TAG, " Samples Per Second: %d", sps); + LOG_UPDATE_INTERVAL(this); +} + +void NAU7802Sensor::write_value_(uint8_t start_reg, size_t size, int32_t value) { + uint8_t data[4]; + for (int i = 0; i < size; i++) { + data[i] = 0xFF & (value >> (size - 1 - i) * 8); + } + this->write_register(start_reg, data, size); +} + +int32_t NAU7802Sensor::read_value_(uint8_t start_reg, size_t size) { + uint8_t data[4]; + this->read_register(start_reg, data, size); + int32_t result = 0; + for (int i = 0; i < size; i++) { + result |= data[i] << (size - 1 - i) * 8; + } + // extend sign bit + if (result & 0x800000 && size == 3) { + result |= 0xFF000000; + } + return result; +} + +bool NAU7802Sensor::calibrate_(enum NAU7802CalibrationModes mode) { + // check if already calbrating + if (this->state_ != CalibrationState::INACTIVE) { + ESP_LOGW(TAG, "Calibration already in progress"); + return false; + } + + this->state_ = mode == NAU7802_CALIBRATE_GAIN ? CalibrationState::GAIN : CalibrationState::OFFSET; + + i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG); + // clear calibraye registers + ctrl2 &= CTRL2_CONFIG_MASK; + // Calibrate + ctrl2 |= mode; + ctrl2 |= CTRL2_CALS; + return true; +} + +void NAU7802Sensor::set_calibration_failure_(bool failed) { + switch (this->state_) { + case CalibrationState::GAIN: + this->gain_calibration_failed_ = failed; + break; + case CalibrationState::OFFSET: + this->offset_calibration_failed_ = failed; + break; + case CalibrationState::INACTIVE: + // shouldn't happen + break; + } +} + +void NAU7802Sensor::loop() { + i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG); + + if (this->state_ != CalibrationState::INACTIVE && !(ctrl2.get() & CTRL2_CALS)) { + if (ctrl2.get() & CTRL2_CAL_ERR) { + this->set_calibration_failure_(true); + this->state_ = CalibrationState::INACTIVE; + ESP_LOGE(TAG, "Failed to calibrate sensor"); + this->status_set_error("Calibration Failed"); + return; + } + + this->set_calibration_failure_(false); + this->state_ = CalibrationState::INACTIVE; + + if (!this->offset_calibration_failed_ && !this->gain_calibration_failed_) + this->status_clear_error(); + + int32_t ocal = this->read_value_(OCAL1_B2_REG, 3); + ESP_LOGI(TAG, "New Offset: %s", to_string(ocal).c_str()); + uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4); + float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL)); + ESP_LOGI(TAG, "New Gain: %f", gcal_f); + } +} + +float NAU7802Sensor::get_setup_priority() const { return setup_priority::DATA; } + +void NAU7802Sensor::update() { + if (!this->is_data_ready_()) { + ESP_LOGW(TAG, "No measurements ready!"); + this->status_set_warning(); + return; + } + + this->status_clear_warning(); + + // Get the most recent sample to publish + int32_t result = this->read_value_(ADCO_B2_REG, 3); + + ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), result); + this->publish_state(result); +} + +bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; } + +bool NAU7802Sensor::can_proceed() { return this->setup_complete_; } + +} // namespace nau7802 +} // namespace esphome diff --git a/esphome/components/nau7802/nau7802.h b/esphome/components/nau7802/nau7802.h new file mode 100644 index 0000000000..3b0372aa89 --- /dev/null +++ b/esphome/components/nau7802/nau7802.h @@ -0,0 +1,121 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +#include + +namespace esphome { +namespace nau7802 { + +enum NAU7802Gain { + NAU7802_GAIN_128 = 0b111, + NAU7802_GAIN_64 = 0b110, + NAU7802_GAIN_32 = 0b101, + NAU7802_GAIN_16 = 0b100, + NAU7802_GAIN_8 = 0b011, + NAU7802_GAIN_4 = 0b010, + NAU7802_GAIN_2 = 0b001, + NAU7802_GAIN_1 = 0b000, +}; + +enum NAU7802SPS { + NAU7802_SPS_320 = 0b111, + NAU7802_SPS_80 = 0b011, + NAU7802_SPS_40 = 0b010, + NAU7802_SPS_20 = 0b001, + NAU7802_SPS_10 = 0b000, +}; + +enum NAU7802LDO { + NAU7802_LDO_2V4 = 0b111, + NAU7802_LDO_2V7 = 0b110, + NAU7802_LDO_3V0 = 0b101, + NAU7802_LDO_3V3 = 0b100, + NAU7802_LDO_3V6 = 0b011, + NAU7802_LDO_3V9 = 0b010, + NAU7802_LDO_4V2 = 0b001, + NAU7802_LDO_4V5 = 0b000, + // Never write this to a register + NAU7802_LDO_EXTERNAL = 0b1000, +}; + +enum NAU7802CalibrationModes { + NAU7802_CALIBRATE_EXTERNAL_OFFSET = 0b10, + NAU7802_CALIBRATE_INTERNAL_OFFSET = 0b00, + NAU7802_CALIBRATE_GAIN = 0b11, +}; + +class NAU7802Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void set_samples_per_second(NAU7802SPS sps) { this->sps_ = sps; } + void set_ldo_voltage(NAU7802LDO ldo) { this->ldo_ = ldo; } + void set_gain(NAU7802Gain gain) { this->gain_ = gain; } + void set_gain_calibration(float gain_calibration) { this->gain_calibration_ = gain_calibration; } + void set_offset_calibration(int32_t offset_calibration) { this->offset_calibration_ = offset_calibration; } + bool calibrate_external_offset() { return this->calibrate_(NAU7802_CALIBRATE_EXTERNAL_OFFSET); } + bool calibrate_internal_offset() { return this->calibrate_(NAU7802_CALIBRATE_INTERNAL_OFFSET); } + bool calibrate_gain() { return this->calibrate_(NAU7802_CALIBRATE_GAIN); } + + void setup() override; + void loop() override; + bool can_proceed() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + + protected: + // + // Internal state + // + enum class CalibrationState : uint8_t { + INACTIVE, + OFFSET, + GAIN, + } state_{CalibrationState::INACTIVE}; + + float gain_calibration_; + int32_t offset_calibration_; + bool offset_calibration_failed_ = false; + bool gain_calibration_failed_ = false; + bool setup_complete_ = false; + + // + // Config values + // + NAU7802LDO ldo_; + NAU7802SPS sps_; + NAU7802Gain gain_; + + // + // Internal Methods + // + bool calibrate_(enum NAU7802CalibrationModes mode); + void complete_setup_(); + void write_value_(uint8_t start_reg, size_t size, int32_t value); + int32_t read_value_(uint8_t start_reg, size_t size); + bool is_data_ready_(); + void set_calibration_failure_(bool failed); +}; + +template +class NAU7802CalbrateExternalOffsetAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->calibrate_external_offset(); } +}; + +template +class NAU7802CalbrateInternalOffsetAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->calibrate_internal_offset(); } +}; + +template class NAU7802CalbrateGainAction : public Action, public Parented { + public: + void play(Ts... x) override { this->parent_->calibrate_gain(); } +}; + +} // namespace nau7802 +} // namespace esphome diff --git a/esphome/components/nau7802/sensor.py b/esphome/components/nau7802/sensor.py new file mode 100644 index 0000000000..9192f48f53 --- /dev/null +++ b/esphome/components/nau7802/sensor.py @@ -0,0 +1,134 @@ +from esphome import automation +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import CONF_GAIN, CONF_ID, ICON_SCALE, STATE_CLASS_MEASUREMENT + +CODEOWNERS = ["@cujomalainey"] +DEPENDENCIES = ["i2c"] + +CONF_GAIN_CALIBRATION = "gain_calibration" +CONF_OFFSET_CALIBRATION = "offset_calibration" +CONF_LDO_VOLTAGE = "ldo_voltage" +CONF_SAMPLES_PER_SECOND = "samples_per_second" + +nau7802_ns = cg.esphome_ns.namespace("nau7802") +NAU7802Sensor = nau7802_ns.class_( + "NAU7802Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice +) +NAU7802CalbrateExternalOffsetAction = nau7802_ns.class_( + "NAU7802CalbrateExternalOffsetAction", + automation.Action, + cg.Parented.template(NAU7802Sensor), +) +NAU7802CalbrateInternalOffsetAction = nau7802_ns.class_( + "NAU7802CalbrateInternalOffsetAction", + automation.Action, + cg.Parented.template(NAU7802Sensor), +) +NAU7802CalbrateGainAction = nau7802_ns.class_( + "NAU7802CalbrateGainAction", automation.Action, cg.Parented.template(NAU7802Sensor) +) + +NAU7802Gain = nau7802_ns.enum("NAU7802Gain") +GAINS = { + 128: NAU7802Gain.NAU7802_GAIN_128, + 64: NAU7802Gain.NAU7802_GAIN_64, + 32: NAU7802Gain.NAU7802_GAIN_32, + 16: NAU7802Gain.NAU7802_GAIN_16, + 8: NAU7802Gain.NAU7802_GAIN_8, + 4: NAU7802Gain.NAU7802_GAIN_4, + 2: NAU7802Gain.NAU7802_GAIN_2, + 1: NAU7802Gain.NAU7802_GAIN_1, +} + +NAU7802SPS = nau7802_ns.enum("NAU7802SPS") +SAMPLES_PER_SECOND = { + 320: NAU7802SPS.NAU7802_SPS_320, + 80: NAU7802SPS.NAU7802_SPS_80, + 40: NAU7802SPS.NAU7802_SPS_40, + 20: NAU7802SPS.NAU7802_SPS_20, + 10: NAU7802SPS.NAU7802_SPS_10, +} + +NAU7802LDO = nau7802_ns.enum("NAU7802LDO") +LDO = { + "2.4V": NAU7802LDO.NAU7802_LDO_2V4, + "2.7V": NAU7802LDO.NAU7802_LDO_2V7, + "3.0V": NAU7802LDO.NAU7802_LDO_3V0, + "3.3V": NAU7802LDO.NAU7802_LDO_3V3, + "3.6V": NAU7802LDO.NAU7802_LDO_3V6, + "3.9V": NAU7802LDO.NAU7802_LDO_3V9, + "4.2V": NAU7802LDO.NAU7802_LDO_4V2, + "4.5V": NAU7802LDO.NAU7802_LDO_4V5, + "EXTERNAL": NAU7802LDO.NAU7802_LDO_EXTERNAL, + "EXT": NAU7802LDO.NAU7802_LDO_EXTERNAL, +} + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + NAU7802Sensor, + icon=ICON_SCALE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend( + { + cv.Optional(CONF_LDO_VOLTAGE, default="3.0V"): cv.enum(LDO, upper=True), + cv.Optional(CONF_SAMPLES_PER_SECOND, default=10): cv.enum( + SAMPLES_PER_SECOND, int=True + ), + cv.Optional(CONF_GAIN, default=128): cv.enum(GAINS, int=True), + cv.Optional(CONF_OFFSET_CALIBRATION, default=0): cv.int_range( + min=-8388608, max=8388607 + ), + cv.Optional(CONF_GAIN_CALIBRATION, default=1.0): cv.float_range( + min=0, max=511.9999998807907 + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x2A)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) + + cg.add(var.set_samples_per_second(config[CONF_SAMPLES_PER_SECOND])) + cg.add(var.set_ldo_voltage(config[CONF_LDO_VOLTAGE])) + cg.add(var.set_gain(config[CONF_GAIN])) + cg.add(var.set_gain_calibration(config[CONF_GAIN_CALIBRATION])) + cg.add(var.set_offset_calibration(config[CONF_OFFSET_CALIBRATION])) + + +NAU7802_CALIBRATE_SCHEMA = maybe_simple_id( + { + cv.GenerateID(CONF_ID): cv.use_id(NAU7802Sensor), + } +) + + +@automation.register_action( + "nau7802.calibrate_internal_offset", + NAU7802CalbrateInternalOffsetAction, + NAU7802_CALIBRATE_SCHEMA, +) +@automation.register_action( + "nau7802.calibrate_external_offset", + NAU7802CalbrateExternalOffsetAction, + NAU7802_CALIBRATE_SCHEMA, +) +@automation.register_action( + "nau7802.calibrate_gain", + NAU7802CalbrateGainAction, + NAU7802_CALIBRATE_SCHEMA, +) +async def nau7802_calibrate_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/tests/components/nau7802/common.yaml b/tests/components/nau7802/common.yaml new file mode 100644 index 0000000000..2501911a3f --- /dev/null +++ b/tests/components/nau7802/common.yaml @@ -0,0 +1,13 @@ +sensor: + - platform: nau7802 + id: test_id + name: weight + i2c_id: i2c_nau7802 + gain: 32 + ldo_voltage: "3.0v" + samples_per_second: 10 + on_value: + then: + - nau7802.calibrate_external_offset: test_id + - nau7802.calibrate_internal_offset: test_id + - nau7802.calibrate_gain: test_id diff --git a/tests/components/nau7802/test.esp32-ard.yaml b/tests/components/nau7802/test.esp32-ard.yaml new file mode 100644 index 0000000000..73a4aa4251 --- /dev/null +++ b/tests/components/nau7802/test.esp32-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/nau7802/test.esp32-c3-ard.yaml b/tests/components/nau7802/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..769468f9ec --- /dev/null +++ b/tests/components/nau7802/test.esp32-c3-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/nau7802/test.esp32-c3-idf.yaml b/tests/components/nau7802/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..769468f9ec --- /dev/null +++ b/tests/components/nau7802/test.esp32-c3-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/nau7802/test.esp32-idf.yaml b/tests/components/nau7802/test.esp32-idf.yaml new file mode 100644 index 0000000000..73a4aa4251 --- /dev/null +++ b/tests/components/nau7802/test.esp32-idf.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 16 + sda: 17 + +<<: !include common.yaml diff --git a/tests/components/nau7802/test.esp8266-ard.yaml b/tests/components/nau7802/test.esp8266-ard.yaml new file mode 100644 index 0000000000..769468f9ec --- /dev/null +++ b/tests/components/nau7802/test.esp8266-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 5 + sda: 4 + +<<: !include common.yaml diff --git a/tests/components/nau7802/test.rp2040-ard.yaml b/tests/components/nau7802/test.rp2040-ard.yaml new file mode 100644 index 0000000000..769468f9ec --- /dev/null +++ b/tests/components/nau7802/test.rp2040-ard.yaml @@ -0,0 +1,6 @@ +i2c: + - id: i2c_nau7802 + scl: 5 + sda: 4 + +<<: !include common.yaml From 1d91601094c8696646f07f277c212cf71a91abc4 Mon Sep 17 00:00:00 2001 From: esphomebot Date: Mon, 7 Oct 2024 16:22:17 +1300 Subject: [PATCH 2474/2607] Update webserver local assets to 20241007-025551 (#7553) --- .../components/web_server/server_index_v3.h | 7968 +++++++++-------- 1 file changed, 3989 insertions(+), 3979 deletions(-) diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 0f3f743a73..b5d7189137 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -12,7 +12,7 @@ namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcc, 0xbd, 0xeb, 0x7a, 0x1b, 0xb7, 0xb2, 0x20, 0xfa, 0xfb, 0xcc, 0x53, 0x48, 0xbd, 0x1d, 0xa5, 0x21, 0x82, 0x2d, 0x92, 0xba, 0x58, 0x6e, 0x0a, 0xe2, 0xf8, 0x1a, 0x3b, - 0x71, 0x6c, 0xc7, 0x72, 0xec, 0xd8, 0x0c, 0xb7, 0x02, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, + 0x71, 0x6c, 0xc7, 0x72, 0xec, 0x38, 0x0c, 0xb7, 0x0c, 0x36, 0x41, 0x12, 0x71, 0x13, 0x60, 0x1a, 0xa0, 0x25, 0x99, 0xe4, 0xbb, 0x9f, 0xaf, 0x70, 0xe9, 0x46, 0x93, 0xb4, 0xd7, 0x5a, 0x73, 0x66, 0xce, 0x37, 0x3b, 0x7b, 0x59, 0x6c, 0xdc, 0x51, 0x28, 0x14, 0xaa, 0x0a, 0x55, 0x85, 0x8b, 0xfd, 0x91, 0xcc, 0xf4, 0xdd, 0x9c, 0xed, 0x4d, 0xf5, 0x2c, 0xbf, 0xbc, 0x70, 0xff, 0x32, 0x3a, 0xba, 0xbc, 0xc8, 0xb9, 0xf8, 0xbc, 0x57, 0xb0, 0x9c, 0xf0, 0x4c, 0x8a, 0xbd, @@ -34,3984 +34,3994 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x7b, 0xcf, 0xe4, 0xd2, 0x4c, 0xa3, 0x58, 0x64, 0x5a, 0x16, 0xb1, 0xc6, 0x0c, 0x0b, 0xb4, 0xe4, 0xe3, 0x58, 0x4f, 0xb9, 0x4a, 0xae, 0xef, 0x65, 0x4a, 0xbd, 0x65, 0x6a, 0x91, 0xeb, 0x7b, 0x64, 0xbf, 0x85, 0xc5, 0x3e, 0x21, 0x9f, 0x05, 0xd2, 0xd3, 0x42, 0xde, 0xec, 0x3d, 0x2d, 0x0a, 0x59, 0xc4, 0xd1, 0xe3, 0xab, 0x2b, 0x5b, 0x62, 0x8f, 0xab, - 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0xbf, 0x16, 0x42, 0xd1, 0x31, 0x7b, - 0x7c, 0x75, 0xf5, 0xd7, 0x9e, 0x2c, 0xf6, 0xfe, 0xca, 0x94, 0xfa, 0x6b, 0x8f, 0x0b, 0xa5, 0x19, 0x1d, 0x25, 0x11, - 0xea, 0x9a, 0xce, 0x32, 0xa5, 0xde, 0xb1, 0x5b, 0x4d, 0x34, 0x36, 0x9f, 0x9a, 0xb0, 0xf5, 0x84, 0xe9, 0x3d, 0x55, - 0xce, 0x2b, 0x46, 0xcb, 0x9c, 0xe9, 0x3d, 0x4d, 0x4c, 0xbe, 0x74, 0xf0, 0x67, 0xf6, 0x53, 0x77, 0xf9, 0x38, 0xbe, - 0x11, 0x07, 0x07, 0xba, 0x04, 0x34, 0x5a, 0xba, 0x15, 0x22, 0x6c, 0xdf, 0xa7, 0x1d, 0x1c, 0xb0, 0x24, 0x67, 0x62, - 0xa2, 0xa7, 0x84, 0x90, 0x76, 0x57, 0x1c, 0x1c, 0xc4, 0x9a, 0x7c, 0x10, 0xc9, 0x84, 0xe9, 0x98, 0x21, 0x84, 0xab, - 0xda, 0x07, 0x07, 0xb1, 0x05, 0x82, 0x24, 0xda, 0x00, 0xae, 0x06, 0x63, 0x94, 0x38, 0xe8, 0x5f, 0xdd, 0x89, 0x2c, - 0x0e, 0xc7, 0x8f, 0xb0, 0x38, 0x38, 0xf8, 0x20, 0x12, 0x05, 0x2d, 0x62, 0x8d, 0xd0, 0xba, 0x60, 0x7a, 0x51, 0x88, - 0x3d, 0xbd, 0xd6, 0xf2, 0x4a, 0x17, 0x5c, 0x4c, 0x62, 0xb4, 0xf4, 0x69, 0x41, 0xc5, 0xf5, 0xda, 0x0e, 0xf7, 0xb7, - 0x82, 0x70, 0x72, 0x09, 0x3d, 0x3e, 0x93, 0xb1, 0xc3, 0x41, 0x4e, 0x48, 0xa4, 0x4c, 0xdd, 0xa8, 0xc7, 0x53, 0xde, - 0x88, 0x22, 0x6c, 0x47, 0x89, 0x3f, 0x0b, 0x84, 0xb9, 0x06, 0xd4, 0x4d, 0x92, 0x44, 0x23, 0x72, 0xb9, 0xf4, 0x60, - 0xe1, 0xc1, 0x44, 0x7b, 0xbc, 0xdf, 0x1a, 0xa4, 0x3a, 0x29, 0xd8, 0x68, 0x91, 0xb1, 0x38, 0x16, 0x58, 0x61, 0x89, - 0xc8, 0xa5, 0x68, 0xc4, 0x05, 0xb9, 0x84, 0xf5, 0x2e, 0xea, 0x8b, 0x4d, 0xc8, 0x7e, 0x0b, 0xb9, 0x41, 0x16, 0x7e, - 0x84, 0x00, 0x62, 0x37, 0xa0, 0x82, 0x90, 0x48, 0x2c, 0x66, 0x43, 0x56, 0x44, 0x65, 0xb1, 0x6e, 0x0d, 0x2f, 0x16, - 0x8a, 0xed, 0x65, 0x4a, 0xed, 0x8d, 0x17, 0x22, 0xd3, 0x5c, 0x8a, 0xbd, 0xa8, 0x51, 0x34, 0x22, 0x8b, 0x0f, 0x25, - 0x3a, 0x44, 0x68, 0x8d, 0x62, 0x85, 0x1a, 0xbc, 0x2f, 0x1b, 0xed, 0x01, 0x86, 0x51, 0xa2, 0xae, 0x6b, 0xcf, 0x41, - 0x80, 0x61, 0x0e, 0x93, 0x5c, 0xe3, 0x4f, 0x76, 0xe7, 0xc3, 0x14, 0x6f, 0x44, 0x8f, 0x27, 0xdb, 0x3b, 0x85, 0xe8, - 0x64, 0x46, 0xe7, 0x31, 0x23, 0x97, 0xcc, 0x60, 0x17, 0x15, 0x19, 0x8c, 0xb5, 0xb6, 0x70, 0x3d, 0x96, 0xb2, 0xa4, - 0xc2, 0x29, 0x94, 0xea, 0x64, 0x2c, 0x8b, 0xa7, 0x34, 0x9b, 0x42, 0xbd, 0x12, 0x63, 0x46, 0x7e, 0xc3, 0x65, 0x05, - 0xa3, 0x9a, 0x3d, 0xcd, 0x19, 0x7c, 0xc5, 0x91, 0xa9, 0x19, 0x21, 0xac, 0x60, 0xab, 0xe7, 0x5c, 0xbf, 0x92, 0x22, - 0x63, 0x5d, 0x15, 0xe0, 0x97, 0x59, 0xf9, 0x87, 0x5a, 0x17, 0x7c, 0xb8, 0xd0, 0x2c, 0x8e, 0x04, 0x94, 0x88, 0xb0, - 0x42, 0x58, 0x24, 0x9a, 0xdd, 0xea, 0xc7, 0x52, 0x68, 0x26, 0x34, 0x61, 0x1e, 0xaa, 0x98, 0x27, 0x74, 0x3e, 0x67, - 0x62, 0xf4, 0x78, 0xca, 0xf3, 0x51, 0x2c, 0xd0, 0x1a, 0xad, 0xf1, 0xef, 0x82, 0xc0, 0x24, 0xc9, 0x25, 0x4f, 0xe1, - 0x9f, 0x6f, 0x4f, 0x27, 0xd6, 0xe4, 0xd2, 0x6c, 0x0b, 0x46, 0xa2, 0xa8, 0x3b, 0x96, 0x45, 0xec, 0xa6, 0xb0, 0x07, - 0xa4, 0x0b, 0xfa, 0x78, 0xbb, 0xc8, 0x99, 0x42, 0xac, 0x41, 0x44, 0xb9, 0x8e, 0x0e, 0xc2, 0xbf, 0x15, 0x31, 0x83, - 0x05, 0xe0, 0x28, 0xe5, 0x86, 0x04, 0xbe, 0xe4, 0x6e, 0x53, 0x8d, 0x4a, 0xa2, 0xf6, 0x51, 0x90, 0x11, 0x4f, 0x74, - 0xb1, 0x50, 0x9a, 0x8d, 0xde, 0xdd, 0xcd, 0x99, 0xc2, 0x3f, 0x17, 0xe4, 0xa3, 0xe8, 0x7d, 0x14, 0x09, 0x9b, 0xcd, - 0xf5, 0xdd, 0x95, 0xa1, 0xe6, 0x69, 0x14, 0xe1, 0x7f, 0x4c, 0xd1, 0x82, 0xd1, 0x0c, 0x48, 0x9a, 0x03, 0xd9, 0x1b, - 0x99, 0xdf, 0x8d, 0x79, 0x9e, 0x5f, 0x2d, 0xe6, 0x73, 0x59, 0x68, 0xac, 0x05, 0x59, 0x6a, 0x59, 0xc1, 0x07, 0x56, - 0x74, 0xa9, 0x6e, 0xb8, 0xce, 0xa6, 0xb1, 0x46, 0xcb, 0x8c, 0x2a, 0xb6, 0xf7, 0x48, 0xca, 0x9c, 0x51, 0x91, 0x72, - 0xc2, 0x7b, 0x3f, 0x17, 0xa9, 0x58, 0xe4, 0x79, 0x77, 0x58, 0x30, 0xfa, 0xb9, 0x6b, 0xb2, 0xed, 0xe1, 0x90, 0x9a, - 0xdf, 0x0f, 0x8b, 0x82, 0xde, 0x41, 0x41, 0x42, 0xa0, 0x58, 0x8f, 0xa7, 0x3f, 0x5f, 0xbd, 0x7e, 0x95, 0xd8, 0xbd, - 0xc2, 0xc7, 0x77, 0x31, 0x2f, 0xf7, 0x1f, 0x5f, 0xe3, 0x71, 0x21, 0x67, 0x1b, 0x5d, 0x5b, 0xd0, 0xf1, 0xee, 0x37, - 0x86, 0xc0, 0x08, 0xdf, 0xb7, 0x4d, 0x87, 0x23, 0x78, 0x65, 0x30, 0x1f, 0x32, 0x89, 0xeb, 0x17, 0xfe, 0x49, 0x6d, - 0x72, 0xcc, 0xd1, 0xf7, 0x47, 0xab, 0x8b, 0xbb, 0x25, 0x23, 0x66, 0x9c, 0x73, 0x38, 0x18, 0x61, 0x8c, 0x19, 0xd5, - 0xd9, 0x74, 0xc9, 0x4c, 0x63, 0x6b, 0x3f, 0x62, 0xb6, 0x5e, 0xe3, 0xaf, 0xd2, 0x63, 0xbd, 0xde, 0x27, 0x84, 0x1b, - 0x7a, 0x45, 0xf4, 0x6a, 0xc5, 0x09, 0xe1, 0x08, 0xbf, 0xe5, 0x64, 0x49, 0xfd, 0x84, 0xe0, 0x64, 0x83, 0xed, 0x99, - 0x5a, 0x2a, 0x03, 0x27, 0xe0, 0x17, 0x56, 0x68, 0x56, 0xa4, 0x5a, 0xe0, 0x82, 0x8d, 0x73, 0x18, 0xc7, 0x7e, 0x1b, - 0x4f, 0xa9, 0x7a, 0x3c, 0xa5, 0x62, 0xc2, 0x46, 0xe9, 0x57, 0xb9, 0xc6, 0x4c, 0x90, 0x68, 0xcc, 0x05, 0xcd, 0xf9, - 0x57, 0x36, 0x8a, 0xdc, 0xb9, 0xf0, 0x48, 0xef, 0xb1, 0x5b, 0xcd, 0xc4, 0x48, 0xed, 0x3d, 0x7f, 0xf7, 0xeb, 0x4b, - 0xb7, 0x98, 0xb5, 0xb3, 0x02, 0x2d, 0xd5, 0x62, 0xce, 0x8a, 0x18, 0x61, 0x77, 0x56, 0x3c, 0xe5, 0x86, 0x4e, 0xfe, - 0x4a, 0xe7, 0x36, 0x85, 0xab, 0xdf, 0xe7, 0x23, 0xaa, 0xd9, 0x1b, 0x26, 0x46, 0x5c, 0x4c, 0xc8, 0x7e, 0xdb, 0xa6, - 0x4f, 0xa9, 0xcb, 0x18, 0x95, 0x49, 0xd7, 0xf7, 0x9e, 0xe6, 0x66, 0xee, 0xe5, 0xe7, 0x22, 0x46, 0x6b, 0xa5, 0xa9, - 0xe6, 0xd9, 0x1e, 0x1d, 0x8d, 0x5e, 0x08, 0xae, 0xb9, 0x19, 0x61, 0x01, 0x4b, 0x04, 0xb8, 0xca, 0xec, 0xa9, 0xe1, - 0x47, 0x1e, 0x23, 0x1c, 0xc7, 0xee, 0x2c, 0x98, 0x22, 0xb7, 0x66, 0x07, 0x07, 0x15, 0xe5, 0xef, 0xb1, 0xd4, 0x66, - 0x92, 0xfe, 0x00, 0x25, 0xf3, 0x85, 0x82, 0xc5, 0xf6, 0x5d, 0xc0, 0x41, 0x23, 0x87, 0x8a, 0x15, 0x5f, 0xd8, 0xa8, - 0x44, 0x10, 0x15, 0xa3, 0xe5, 0x46, 0x1f, 0x6e, 0x7b, 0x68, 0xd2, 0x1f, 0x74, 0x43, 0x12, 0xce, 0x1c, 0xb2, 0x5b, - 0x4e, 0x85, 0x33, 0x55, 0x12, 0x95, 0x18, 0x0e, 0xd4, 0x92, 0xb0, 0x28, 0xe2, 0xe7, 0x37, 0x8f, 0x05, 0xf0, 0x10, - 0x21, 0xe5, 0xf0, 0x67, 0xee, 0xd3, 0x2f, 0xe6, 0xf0, 0x50, 0x58, 0x20, 0xac, 0xed, 0x48, 0x15, 0x42, 0x6b, 0x84, - 0xb5, 0x1f, 0xae, 0x25, 0x4a, 0x9e, 0x2f, 0x82, 0x53, 0x9b, 0xbc, 0xe5, 0xe6, 0xd8, 0x06, 0xda, 0x46, 0x35, 0x3b, - 0x38, 0x88, 0x59, 0x52, 0x22, 0x06, 0xd9, 0x6f, 0xbb, 0x45, 0x0a, 0xa0, 0xf5, 0x8d, 0x71, 0x43, 0xcf, 0x86, 0xc1, - 0xd9, 0x67, 0x89, 0x90, 0x0f, 0xb3, 0x8c, 0x29, 0x25, 0x8b, 0x83, 0x83, 0x7d, 0x53, 0xbe, 0xe4, 0x2c, 0x60, 0x11, - 0x5f, 0xdf, 0x88, 0x6a, 0x08, 0xa8, 0x3a, 0x6d, 0x3d, 0xdf, 0x44, 0x2a, 0xbe, 0xc9, 0x33, 0x21, 0x69, 0x74, 0x7d, - 0x1d, 0x35, 0x34, 0x76, 0x70, 0x98, 0x30, 0xdf, 0xf5, 0xdd, 0x13, 0x66, 0xd9, 0x42, 0xc3, 0x84, 0x6c, 0x81, 0x66, - 0x27, 0x3f, 0x18, 0xd7, 0x87, 0x84, 0x35, 0x56, 0x68, 0x1d, 0xac, 0xe8, 0xce, 0xa6, 0x0d, 0x7f, 0x63, 0x97, 0x6e, - 0x39, 0x31, 0x3c, 0x45, 0xb0, 0x8e, 0x7d, 0x36, 0x58, 0x63, 0x03, 0x7b, 0x3f, 0x1b, 0x69, 0x06, 0xda, 0xd7, 0x83, - 0xae, 0xcb, 0x27, 0xca, 0x42, 0xae, 0x60, 0xff, 0x2c, 0x98, 0xd2, 0x16, 0x91, 0x63, 0x8d, 0x25, 0x86, 0x33, 0x6a, - 0x93, 0xe9, 0xac, 0xb1, 0xa4, 0xbb, 0xc6, 0xf6, 0x7a, 0x0e, 0x67, 0xa3, 0x02, 0xa4, 0xfe, 0x3e, 0x3e, 0xc1, 0x58, - 0x35, 0x5a, 0xad, 0xde, 0x72, 0xdf, 0x4a, 0xb5, 0x96, 0x25, 0xbf, 0xb6, 0xb1, 0x28, 0x4c, 0x20, 0x77, 0x38, 0xef, - 0xb7, 0xdd, 0xf8, 0xc5, 0x80, 0xec, 0xb7, 0x4a, 0x2c, 0x76, 0x60, 0xb5, 0xe3, 0xb1, 0x50, 0x7c, 0x6d, 0x9b, 0x42, - 0xe6, 0xac, 0xaf, 0xe1, 0x4b, 0x32, 0xdd, 0xc2, 0xd5, 0x29, 0xe9, 0x03, 0xd7, 0x91, 0x4c, 0x07, 0xdf, 0xc2, 0x27, - 0x4f, 0x11, 0x62, 0xbd, 0x9d, 0x57, 0x11, 0x8e, 0x2f, 0x75, 0xc2, 0xb1, 0x31, 0x8d, 0x68, 0x5e, 0x56, 0x89, 0x4a, - 0x34, 0x73, 0x5b, 0xbd, 0xca, 0xc2, 0xc2, 0x0c, 0xa6, 0x9a, 0x52, 0xd0, 0xc4, 0x2b, 0x3a, 0x63, 0x2a, 0x66, 0x08, - 0x7f, 0xab, 0x80, 0xc5, 0x4f, 0x28, 0x32, 0x08, 0xce, 0x50, 0x05, 0x67, 0x28, 0xb0, 0xbb, 0xc0, 0xa4, 0xd5, 0xb7, - 0x9c, 0xc2, 0xac, 0xaf, 0x06, 0x15, 0x6f, 0x17, 0x4c, 0xde, 0x1c, 0xce, 0x0e, 0xc1, 0x3d, 0xfc, 0x6c, 0x9a, 0x05, - 0x9a, 0x61, 0x21, 0x14, 0xc2, 0xfb, 0xad, 0xcd, 0x95, 0xf4, 0xa5, 0xaa, 0x39, 0xf6, 0x07, 0xb0, 0x0e, 0xe6, 0xd8, - 0x48, 0xb8, 0x32, 0x7f, 0x6b, 0x5b, 0x0d, 0xc0, 0x76, 0x05, 0x98, 0x91, 0x8c, 0x73, 0xaa, 0xe3, 0xf6, 0x51, 0x0b, - 0x18, 0xd3, 0x2f, 0x0c, 0x4e, 0x15, 0x84, 0xb6, 0xa7, 0xc2, 0x92, 0x85, 0x50, 0x53, 0x3e, 0xd6, 0xf1, 0xef, 0xc2, - 0x10, 0x15, 0x96, 0x2b, 0x06, 0x12, 0x4e, 0xc0, 0x1e, 0x1b, 0x82, 0xf3, 0xbb, 0x80, 0x7e, 0xba, 0xe5, 0x41, 0xe4, - 0x46, 0x6a, 0x08, 0x17, 0x90, 0x87, 0x8a, 0xb5, 0xae, 0xc8, 0x4c, 0xc9, 0xb8, 0x01, 0xf7, 0xd8, 0xee, 0xd9, 0x16, - 0x53, 0x47, 0x0d, 0x44, 0xc0, 0xc1, 0x8a, 0x34, 0x24, 0x11, 0x2e, 0x51, 0x27, 0x5a, 0xbe, 0x94, 0x37, 0xac, 0x78, - 0x4c, 0x61, 0xf0, 0xa9, 0xad, 0xbe, 0xb6, 0x47, 0x81, 0xa1, 0xf8, 0xba, 0xeb, 0xf1, 0xe5, 0xda, 0x4c, 0xfc, 0x4d, - 0x21, 0x67, 0x5c, 0x31, 0xe0, 0xdb, 0x2c, 0xfc, 0x05, 0x6c, 0x34, 0xb3, 0x23, 0xe1, 0xb8, 0x61, 0x25, 0x7e, 0x3d, - 0x7c, 0x59, 0xc7, 0xaf, 0xeb, 0x7b, 0x4f, 0x27, 0x9e, 0x02, 0xd6, 0xf7, 0x31, 0xc2, 0xb1, 0x13, 0x2f, 0x82, 0x93, - 0x2e, 0x99, 0x22, 0x77, 0xcc, 0xaf, 0x56, 0x3a, 0x10, 0xe3, 0x6a, 0x9c, 0x23, 0xb3, 0xdb, 0x06, 0xad, 0xe9, 0x68, - 0x04, 0x2c, 0x5e, 0x21, 0xf3, 0x3c, 0x38, 0xac, 0xb0, 0xe8, 0x96, 0xc7, 0xd3, 0xf5, 0xbd, 0xa7, 0x57, 0xdf, 0x3b, - 0xa1, 0x20, 0x3f, 0x3c, 0xa4, 0xfc, 0x40, 0xc5, 0x88, 0x15, 0x20, 0x57, 0x06, 0xab, 0xe5, 0xce, 0xd9, 0xc7, 0x52, - 0x08, 0x96, 0x69, 0x36, 0x02, 0xa1, 0x45, 0x10, 0x9d, 0x4c, 0xa5, 0xd2, 0x65, 0x62, 0x35, 0x7a, 0x11, 0x0a, 0xa1, - 0x49, 0x46, 0xf3, 0x3c, 0xb6, 0x02, 0xca, 0x4c, 0x7e, 0x61, 0x3b, 0x46, 0xdd, 0xad, 0x0d, 0xb9, 0x6c, 0x86, 0x05, - 0xcd, 0xb0, 0x44, 0xcd, 0x73, 0x9e, 0xb1, 0xf2, 0xf0, 0xba, 0x4a, 0xb8, 0x18, 0xb1, 0x5b, 0xa0, 0x23, 0xe8, 0xf2, - 0xf2, 0xb2, 0x85, 0xdb, 0x68, 0x6d, 0x01, 0xbe, 0xdc, 0x02, 0xec, 0x77, 0x8e, 0x4d, 0x2b, 0x88, 0x2f, 0x77, 0x92, - 0x35, 0x14, 0x9c, 0x95, 0xdc, 0x0b, 0x5a, 0x96, 0x3c, 0x23, 0x3c, 0x62, 0x39, 0xd3, 0xcc, 0x93, 0x73, 0x60, 0xa6, - 0xed, 0xd6, 0x7d, 0x5b, 0xc2, 0xaf, 0x44, 0x27, 0xbf, 0xcb, 0xfc, 0x9a, 0xab, 0x52, 0x74, 0xaf, 0x96, 0xa7, 0x82, - 0x76, 0x4f, 0xdb, 0xe5, 0xa1, 0x5a, 0xd3, 0x6c, 0x6a, 0x25, 0xf6, 0x78, 0x6b, 0x4a, 0x55, 0x1b, 0x8e, 0xb4, 0x97, - 0x9b, 0xe8, 0x53, 0xe1, 0x86, 0xb9, 0x0b, 0x04, 0x57, 0x8e, 0x28, 0x30, 0x10, 0x02, 0xed, 0xb2, 0x3d, 0xa6, 0x79, - 0x3e, 0xa4, 0xd9, 0xe7, 0x3a, 0xf6, 0x57, 0x68, 0x40, 0x36, 0xa9, 0x71, 0x90, 0x15, 0x90, 0xac, 0x70, 0xde, 0x9e, - 0x4a, 0xd7, 0x36, 0x4a, 0xbc, 0xdf, 0xaa, 0xd0, 0xbe, 0xbe, 0xd0, 0xdf, 0xc4, 0x76, 0x33, 0x22, 0xe1, 0x66, 0x16, - 0x03, 0x15, 0xf8, 0x97, 0x18, 0xe7, 0xe9, 0x81, 0xc3, 0x3b, 0x10, 0x3c, 0xd6, 0x1b, 0x03, 0xd1, 0x68, 0xb9, 0x1e, - 0x71, 0xf5, 0x6d, 0x08, 0xfc, 0x6f, 0x19, 0xe5, 0x93, 0xa0, 0x87, 0x7f, 0x77, 0xa0, 0x25, 0x8d, 0x73, 0x8c, 0x73, - 0x39, 0x32, 0xc7, 0x50, 0x78, 0x42, 0xf3, 0x0b, 0x30, 0x2f, 0x06, 0xdf, 0x5f, 0xdb, 0x2c, 0xc3, 0x97, 0xc1, 0x30, - 0x54, 0x37, 0x64, 0x28, 0x6a, 0x28, 0xe0, 0x88, 0xaa, 0x30, 0x67, 0xae, 0xac, 0x89, 0x92, 0x8e, 0x6b, 0xb7, 0xe2, - 0xb8, 0xa3, 0xb9, 0x05, 0x89, 0xe3, 0x58, 0x81, 0x34, 0xe7, 0xf9, 0xfb, 0x6a, 0x16, 0x6a, 0x6b, 0x16, 0x2a, 0x09, - 0xa4, 0x2d, 0x54, 0x21, 0x73, 0x50, 0x3d, 0xd5, 0x02, 0x85, 0xa5, 0x80, 0x65, 0x4d, 0x80, 0x42, 0xa3, 0x92, 0xe0, - 0xe6, 0x44, 0xe3, 0xc2, 0x89, 0x3a, 0x0e, 0xd7, 0x80, 0x64, 0x54, 0x55, 0x24, 0xb2, 0x9b, 0xa3, 0x26, 0xfb, 0x4a, - 0x5c, 0xa0, 0x0d, 0xfe, 0x7e, 0xbd, 0x76, 0x50, 0x62, 0xc8, 0xad, 0x4e, 0x8d, 0x31, 0x0e, 0xc0, 0x82, 0x25, 0x71, - 0xcc, 0xb0, 0x65, 0x7d, 0x36, 0x81, 0x53, 0xb6, 0xbb, 0x4f, 0x88, 0xac, 0x60, 0x53, 0x63, 0x2a, 0x3d, 0x77, 0x25, - 0x11, 0xa6, 0x9e, 0x2d, 0x2d, 0xaa, 0x89, 0x13, 0x12, 0x79, 0xed, 0x44, 0xd4, 0x5b, 0xd6, 0x84, 0xc3, 0x34, 0x28, - 0xb6, 0x4e, 0x81, 0xa8, 0x16, 0xbb, 0xe0, 0xbd, 0x0b, 0x6b, 0x6a, 0xed, 0x04, 0x10, 0x2f, 0x6a, 0x10, 0x0f, 0x40, - 0x2b, 0x2d, 0xf1, 0x92, 0x03, 0x42, 0xeb, 0x95, 0x63, 0x86, 0x0b, 0xbb, 0x10, 0x5b, 0x50, 0xdc, 0x64, 0x3f, 0x0d, - 0x16, 0x82, 0x2c, 0xab, 0x80, 0xbf, 0x0b, 0x8f, 0x88, 0x18, 0x06, 0x2f, 0x56, 0xab, 0x2d, 0xb4, 0xdb, 0xc9, 0x85, - 0xa2, 0xa4, 0x92, 0x0e, 0x57, 0xab, 0xaf, 0x12, 0xc5, 0x8e, 0xff, 0xc5, 0x0c, 0xf5, 0x3c, 0xd1, 0x7d, 0xf8, 0x12, - 0x4a, 0x19, 0x76, 0xb4, 0x4a, 0x29, 0x05, 0x87, 0x3a, 0xd6, 0xd6, 0x17, 0x4a, 0x07, 0x94, 0xfb, 0xf1, 0x16, 0x01, - 0x33, 0x89, 0xee, 0xa4, 0xae, 0xa6, 0xfc, 0xd8, 0x35, 0x2d, 0x10, 0x42, 0xa9, 0x32, 0xb2, 0xcc, 0xfe, 0x2e, 0xf9, - 0xf2, 0xe0, 0x40, 0x05, 0x0d, 0x5d, 0x97, 0x94, 0xe2, 0xef, 0x18, 0x4e, 0x65, 0x75, 0x27, 0x0c, 0xfb, 0xf2, 0xb7, - 0x3f, 0x87, 0xb6, 0xa4, 0xd3, 0x56, 0x17, 0x04, 0x73, 0x7a, 0x43, 0xb9, 0xde, 0x2b, 0x5b, 0xb1, 0x82, 0x79, 0xcc, - 0xd0, 0xd2, 0x71, 0x1b, 0x49, 0xc1, 0x80, 0x7f, 0x04, 0xb2, 0xe0, 0xb9, 0x68, 0x8b, 0xf8, 0xd9, 0x94, 0x81, 0x2a, - 0xdb, 0x33, 0x12, 0xa5, 0x78, 0xb8, 0xef, 0x0e, 0x12, 0xd7, 0xf0, 0xee, 0xb1, 0xaf, 0x37, 0xab, 0xd7, 0xa4, 0x81, - 0x39, 0x2b, 0xc6, 0xb2, 0x98, 0xf9, 0xbc, 0xf5, 0xc6, 0xb7, 0x23, 0x8e, 0x7c, 0x1c, 0xef, 0x6c, 0xdb, 0x89, 0x00, - 0xdd, 0x0d, 0xd9, 0xbb, 0x92, 0xda, 0x6b, 0xa7, 0x69, 0x79, 0x00, 0x5b, 0x05, 0xa1, 0xc7, 0x4c, 0x15, 0x4a, 0xf9, - 0x4e, 0xbd, 0xda, 0xb5, 0xba, 0x93, 0xfd, 0x76, 0xb7, 0x94, 0xfc, 0x3c, 0x36, 0x74, 0xad, 0x8e, 0xc3, 0x9d, 0xaa, - 0x72, 0x91, 0x8f, 0xdc, 0x60, 0x05, 0xc2, 0xcc, 0xe1, 0xd1, 0x0d, 0xcf, 0xf3, 0x2a, 0xf5, 0x3f, 0x21, 0xed, 0xca, - 0x91, 0x76, 0xe9, 0x49, 0x3b, 0x90, 0x0a, 0x20, 0xed, 0xb6, 0xb9, 0xaa, 0xba, 0xdc, 0xda, 0x9e, 0xd2, 0x12, 0x75, - 0x65, 0xc4, 0x69, 0xe8, 0x6f, 0xe1, 0x47, 0x80, 0x4a, 0xe6, 0xeb, 0x73, 0xec, 0xf4, 0x31, 0x20, 0x06, 0x5a, 0x9d, - 0x26, 0x0b, 0x35, 0x15, 0x9f, 0x63, 0x84, 0xd5, 0x9a, 0x95, 0x98, 0xfd, 0xf0, 0x29, 0x28, 0xed, 0x82, 0xe9, 0xc0, - 0x39, 0x66, 0x92, 0xff, 0x23, 0x3e, 0xca, 0xcf, 0x4e, 0xb8, 0xd9, 0x29, 0x3f, 0x3b, 0xa0, 0xf5, 0xd5, 0xec, 0x46, - 0xdf, 0xa7, 0xf6, 0x66, 0x7a, 0xa2, 0x9c, 0x5e, 0xb5, 0xde, 0xab, 0x55, 0xbc, 0x91, 0x02, 0x1a, 0x7d, 0x27, 0xa5, - 0x14, 0x65, 0xeb, 0x40, 0x03, 0x42, 0xc8, 0x40, 0xc2, 0xda, 0x4e, 0xba, 0x3c, 0xe5, 0x5e, 0xfe, 0x2b, 0x3d, 0x8f, - 0x51, 0xdc, 0xdb, 0xfa, 0x8f, 0xe5, 0x6c, 0x0e, 0x0c, 0xd9, 0x06, 0x4a, 0x4f, 0x98, 0xeb, 0xb0, 0xca, 0x5f, 0xef, - 0x48, 0xab, 0xd5, 0x31, 0xfb, 0xb1, 0x86, 0x4d, 0xa5, 0xd4, 0xbc, 0xdf, 0x5a, 0x2f, 0xca, 0xa4, 0x92, 0x70, 0xec, - 0xd2, 0xad, 0x3c, 0xde, 0xd4, 0xcc, 0xf8, 0x8c, 0xd7, 0xb1, 0xb0, 0x74, 0x58, 0x00, 0xad, 0x0b, 0xc8, 0x8f, 0x47, - 0xf7, 0x70, 0xfd, 0xd7, 0x15, 0x70, 0x96, 0xeb, 0x0d, 0xf0, 0x2d, 0xd7, 0xeb, 0x47, 0xda, 0x49, 0xda, 0xf8, 0xd1, - 0x0e, 0xb9, 0xb7, 0x84, 0x5e, 0x95, 0xe9, 0x64, 0xc6, 0xfe, 0x00, 0xd2, 0xb6, 0x58, 0x48, 0xb2, 0x9c, 0xc9, 0x11, - 0x4b, 0x23, 0x39, 0x67, 0x22, 0x5a, 0x83, 0x9e, 0xd5, 0x21, 0xc0, 0x3f, 0x22, 0x5e, 0xbe, 0xad, 0xeb, 0x5b, 0xd3, - 0x47, 0x7a, 0x0d, 0xaa, 0xb0, 0x97, 0x7c, 0x87, 0x32, 0xf6, 0x3d, 0x2b, 0x94, 0xe1, 0x49, 0x4b, 0xf6, 0xf6, 0x25, - 0xaf, 0x0e, 0xa8, 0x97, 0x3c, 0xfd, 0x76, 0x95, 0x4a, 0x20, 0x89, 0xda, 0xc9, 0x59, 0x72, 0x1c, 0x21, 0xa3, 0x31, - 0x7e, 0xe6, 0x35, 0xc6, 0x8b, 0x52, 0x63, 0xfc, 0x5c, 0x93, 0xc5, 0x86, 0xc6, 0xf8, 0x0f, 0x41, 0x9e, 0xeb, 0xde, - 0x73, 0xaf, 0x4d, 0x7f, 0x23, 0x73, 0x9e, 0xdd, 0xc5, 0x51, 0xce, 0x75, 0x13, 0x6e, 0x13, 0x23, 0xbc, 0xb4, 0x19, - 0xa0, 0x6a, 0x34, 0xfa, 0xee, 0xb5, 0x97, 0xff, 0xb0, 0x10, 0x24, 0xba, 0x97, 0x73, 0x7d, 0x2f, 0xc2, 0x53, 0x4d, - 0xfe, 0x82, 0x5f, 0xf7, 0x96, 0xf1, 0xaf, 0x54, 0x4f, 0x93, 0x82, 0x8a, 0x91, 0x9c, 0xc5, 0xa8, 0x11, 0x45, 0x28, - 0x51, 0x46, 0x08, 0x79, 0x80, 0xd6, 0xf7, 0xfe, 0xc2, 0xaf, 0x24, 0x89, 0x7a, 0x51, 0x63, 0xaa, 0xb1, 0xa6, 0xe4, - 0xaf, 0x8b, 0x7b, 0xcb, 0x57, 0x72, 0x7d, 0xf9, 0x17, 0x7e, 0xaa, 0x4b, 0xb5, 0x3e, 0xbe, 0x65, 0x24, 0x46, 0xe4, - 0xf2, 0xa9, 0x1f, 0xd2, 0x63, 0x39, 0xb3, 0x0a, 0xfe, 0x08, 0xe1, 0x2f, 0xa0, 0xd7, 0xbd, 0xe4, 0x15, 0x11, 0x72, - 0x77, 0x30, 0xfb, 0x24, 0x92, 0x46, 0x79, 0x10, 0x1d, 0x1c, 0x04, 0x69, 0x25, 0x0b, 0x81, 0xff, 0x96, 0xa4, 0x26, - 0xaa, 0x63, 0x46, 0xa1, 0xa5, 0xbf, 0x65, 0xcc, 0x91, 0x6f, 0x26, 0xf6, 0x9a, 0x6a, 0xb7, 0x63, 0x79, 0xdf, 0xea, - 0x1e, 0x12, 0xae, 0x59, 0x41, 0xb5, 0x2c, 0x06, 0x28, 0x64, 0x4b, 0xf0, 0x57, 0x4e, 0xfe, 0xea, 0xef, 0xfd, 0x3f, - 0xff, 0xe3, 0xcf, 0xf1, 0x9f, 0xc5, 0xe0, 0x2f, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, - 0xfe, 0x3c, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x34, 0x40, 0xab, 0xf8, 0xcf, 0xa3, 0x5e, 0xdf, 0x7d, - 0xf5, 0xff, 0xfb, 0xf2, 0x4f, 0x35, 0x38, 0xb4, 0x89, 0xf7, 0x10, 0x3a, 0x9a, 0xe0, 0x5f, 0x04, 0x39, 0x6a, 0x36, - 0x2f, 0x8f, 0x26, 0xf8, 0x27, 0x41, 0x8e, 0xe0, 0xef, 0x9d, 0x26, 0x6f, 0xd9, 0xe4, 0xe9, 0xed, 0x3c, 0xfe, 0xeb, - 0x72, 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf9, 0xa7, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, - 0x06, 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0x3f, 0xff, 0xba, - 0xb8, 0x24, 0x83, 0x55, 0x1c, 0xad, 0x7e, 0x44, 0x2b, 0x84, 0x56, 0xf7, 0xd0, 0x5f, 0x38, 0x9a, 0x44, 0x08, 0xff, - 0x26, 0xc8, 0xd1, 0x8f, 0x47, 0x13, 0xfc, 0x49, 0x90, 0xa3, 0xe8, 0x68, 0x82, 0xdf, 0x4b, 0x72, 0xf4, 0xdf, 0x71, - 0x2f, 0xb5, 0x4a, 0xb8, 0x95, 0x51, 0x7f, 0xac, 0xe0, 0x26, 0x84, 0x16, 0x8c, 0xae, 0x34, 0xd7, 0x39, 0x43, 0xf7, - 0x8e, 0x38, 0x7e, 0x24, 0x01, 0x58, 0xb1, 0x06, 0x25, 0x8d, 0xb9, 0x84, 0x5d, 0x5e, 0xc3, 0xc2, 0x03, 0x06, 0xdd, - 0x4b, 0x39, 0xb6, 0x7a, 0x02, 0x95, 0x6a, 0x7b, 0x7b, 0xab, 0xe0, 0xfa, 0x16, 0x3f, 0x26, 0x8f, 0x64, 0xdc, 0x46, - 0x98, 0x53, 0xf8, 0xd1, 0x41, 0xf8, 0x83, 0x76, 0x17, 0x9e, 0xb0, 0xcd, 0x2d, 0x86, 0x09, 0x69, 0xf9, 0x99, 0x08, - 0xe1, 0x97, 0x3b, 0x32, 0xf5, 0x14, 0xd4, 0x0f, 0x08, 0xff, 0x5c, 0xbb, 0x1e, 0xc5, 0x8f, 0x35, 0x29, 0x91, 0xe3, - 0x5d, 0xc1, 0xd8, 0x07, 0x9a, 0x7f, 0x66, 0x45, 0xfc, 0x54, 0xe3, 0x76, 0xe7, 0x01, 0x36, 0xaa, 0xea, 0xfd, 0x36, - 0xea, 0x96, 0xb7, 0x5b, 0xcf, 0xa5, 0xbd, 0x4f, 0x80, 0x53, 0xb8, 0xae, 0xaf, 0x81, 0xb5, 0xdf, 0xe7, 0x5b, 0x4a, - 0xad, 0x82, 0xde, 0x44, 0xa8, 0x7e, 0x95, 0xca, 0xc5, 0x17, 0x9a, 0xf3, 0xd1, 0x9e, 0x66, 0xb3, 0x79, 0x4e, 0x35, - 0xdb, 0x73, 0x73, 0xde, 0xa3, 0xd0, 0x50, 0x54, 0xf2, 0x14, 0x7f, 0x88, 0x6a, 0xd3, 0xfe, 0x21, 0x92, 0x6a, 0xef, - 0xc4, 0x70, 0x9f, 0xe5, 0xf8, 0x12, 0x41, 0xcb, 0xeb, 0xb2, 0xcd, 0x1b, 0xc1, 0x66, 0x1b, 0x94, 0x65, 0x03, 0x73, - 0x7e, 0x2b, 0x0c, 0xf7, 0x9b, 0x84, 0x74, 0x7a, 0xd1, 0x85, 0xfa, 0x32, 0xb9, 0x8c, 0xe0, 0x26, 0xa7, 0x20, 0x82, - 0x19, 0xe5, 0x11, 0x94, 0xa0, 0xa4, 0xd5, 0xa5, 0x17, 0xac, 0x4b, 0x1b, 0x0d, 0xcf, 0x66, 0x67, 0x84, 0xf7, 0xa9, - 0xad, 0x9f, 0xe3, 0x29, 0x1e, 0x91, 0x66, 0x1b, 0x2f, 0x48, 0xcb, 0x54, 0xe9, 0x2e, 0x2e, 0x32, 0xd7, 0xcf, 0xc1, - 0x41, 0x5c, 0x24, 0x39, 0x55, 0xfa, 0x05, 0x68, 0x04, 0xc8, 0x02, 0x4f, 0x49, 0x91, 0xb0, 0x5b, 0x96, 0xc5, 0x19, - 0xc2, 0x53, 0x47, 0x83, 0x50, 0x17, 0x2d, 0x48, 0x50, 0x0c, 0xe4, 0x0c, 0x22, 0x58, 0x6f, 0xda, 0x6f, 0x0f, 0x08, - 0x21, 0xd1, 0x7e, 0xb3, 0x19, 0xf5, 0x0a, 0xf2, 0x8b, 0x48, 0x21, 0x25, 0x60, 0xa7, 0xc9, 0x4f, 0x90, 0xd4, 0x09, - 0x92, 0xe2, 0xf7, 0x32, 0xd1, 0x4c, 0xe9, 0x18, 0x92, 0x41, 0x49, 0xa0, 0x3c, 0x86, 0x47, 0x17, 0x47, 0x51, 0x03, - 0x52, 0x0d, 0x8a, 0x22, 0x5c, 0x90, 0x3b, 0x8d, 0xd2, 0x69, 0xff, 0x78, 0x10, 0x9e, 0x11, 0x36, 0x15, 0xfa, 0xbf, - 0xd3, 0xbd, 0x69, 0xbf, 0x65, 0xfa, 0xbf, 0x8c, 0x7a, 0x71, 0x41, 0x94, 0x65, 0xe3, 0x7a, 0x2a, 0x15, 0xcc, 0xcc, - 0x17, 0xa5, 0x6e, 0x80, 0xae, 0xef, 0x11, 0x69, 0x76, 0xd2, 0x78, 0x14, 0xce, 0xa4, 0x09, 0x1d, 0x3a, 0x50, 0xe0, - 0x9c, 0x40, 0x79, 0x5c, 0x10, 0xe8, 0xb4, 0xaa, 0x76, 0xa7, 0x53, 0x97, 0xf0, 0x63, 0xf4, 0x63, 0xef, 0x93, 0x48, - 0x7f, 0x13, 0x76, 0x04, 0x9f, 0xc4, 0x6a, 0x05, 0x7f, 0x7f, 0x13, 0x3d, 0x18, 0x96, 0x49, 0xfb, 0xc5, 0xa5, 0xfd, - 0x04, 0x69, 0x82, 0xa5, 0x66, 0xc0, 0x58, 0x95, 0xfc, 0x98, 0x5d, 0x9c, 0x31, 0xb1, 0x33, 0x38, 0x38, 0xe0, 0x7d, - 0xda, 0x68, 0x0f, 0xe0, 0x46, 0xa0, 0xd0, 0xea, 0x03, 0xd7, 0xd3, 0x38, 0x3a, 0xba, 0x8c, 0x50, 0x2f, 0xda, 0x83, - 0x55, 0xee, 0xca, 0x06, 0x71, 0xb0, 0xce, 0x1a, 0x9a, 0xa6, 0xa3, 0x4b, 0xd2, 0xea, 0xc5, 0xc2, 0x12, 0xf9, 0x1c, - 0xe1, 0xcc, 0xd1, 0xd4, 0x16, 0x1e, 0xa1, 0x86, 0x10, 0x0d, 0xff, 0x3d, 0x42, 0x8d, 0xa9, 0x6e, 0x8c, 0x51, 0x9a, - 0xc1, 0xdf, 0x78, 0x44, 0x08, 0x69, 0x76, 0xca, 0x8a, 0xfe, 0xb0, 0xa4, 0x28, 0x1d, 0x7b, 0xf5, 0x68, 0xdf, 0x6c, - 0x0e, 0xd9, 0x88, 0x79, 0x9f, 0x0d, 0x56, 0xab, 0xe8, 0xa2, 0x77, 0x19, 0xa1, 0x46, 0xec, 0xd1, 0xee, 0xc8, 0xe3, - 0x1d, 0x42, 0x58, 0x0c, 0xd6, 0xee, 0x06, 0xea, 0x86, 0xd5, 0x6e, 0x9b, 0x96, 0xd5, 0xfe, 0x0f, 0xc8, 0x02, 0x5b, - 0x97, 0x72, 0x8f, 0xe5, 0x6f, 0xe7, 0x30, 0x55, 0x8f, 0xdb, 0x92, 0xb4, 0x70, 0x41, 0xbc, 0xba, 0x9b, 0x12, 0x5d, - 0xe1, 0x7f, 0x46, 0xaa, 0xe2, 0xb8, 0x9f, 0xe3, 0xe9, 0x80, 0x08, 0x6a, 0xe4, 0x97, 0xae, 0x57, 0xa6, 0xb3, 0x9c, - 0xdc, 0xb0, 0x8d, 0xfb, 0xdf, 0x1c, 0xee, 0x64, 0x1e, 0xeb, 0x24, 0x5b, 0x14, 0x05, 0x13, 0xfa, 0x95, 0x1c, 0x39, - 0xc6, 0x8e, 0xe5, 0x20, 0x5b, 0xc1, 0xc5, 0x2e, 0x06, 0xae, 0xae, 0xe3, 0x77, 0xca, 0x68, 0x2b, 0x7b, 0x41, 0x46, - 0x96, 0xe1, 0x32, 0xd7, 0xbd, 0xdd, 0x85, 0x13, 0xa5, 0x63, 0x84, 0x47, 0xee, 0x1e, 0x38, 0x4e, 0x92, 0x64, 0x91, - 0x64, 0x90, 0x0d, 0x1d, 0x28, 0xb4, 0x36, 0xfb, 0x2a, 0x56, 0xe4, 0xb1, 0x4e, 0x04, 0xbb, 0x35, 0xdd, 0xc6, 0xa8, - 0x3a, 0xc4, 0xfd, 0x7e, 0xbb, 0xa0, 0x5d, 0x43, 0x80, 0x54, 0x22, 0xe4, 0x88, 0x01, 0x84, 0xe0, 0xee, 0xdf, 0x25, - 0x4d, 0xa9, 0x0a, 0x6f, 0xb6, 0xaa, 0x01, 0xf6, 0x43, 0x95, 0xf7, 0x02, 0xf4, 0xc4, 0x86, 0x3d, 0x2b, 0x0b, 0x5b, - 0xe5, 0x39, 0x42, 0x7c, 0x1c, 0x2f, 0x12, 0xb8, 0x11, 0x34, 0x98, 0x24, 0x04, 0x5a, 0xad, 0x16, 0x21, 0x6e, 0x4d, - 0x2b, 0xc5, 0xf4, 0x98, 0x4c, 0xfb, 0x45, 0xa3, 0x61, 0x94, 0xd7, 0x23, 0x8b, 0x17, 0x0b, 0x84, 0xc7, 0xe5, 0x5e, - 0xf3, 0xe5, 0xe6, 0xa4, 0xde, 0x55, 0x3c, 0xae, 0x2b, 0x81, 0x1b, 0x42, 0x20, 0xa3, 0x5f, 0xd4, 0xd0, 0x3a, 0x9e, - 0x90, 0xa3, 0xb8, 0x9f, 0xf4, 0xfe, 0xe7, 0x00, 0xf5, 0xe2, 0xe4, 0x10, 0x1d, 0x59, 0x5a, 0x32, 0x46, 0xdd, 0xcc, - 0xf6, 0xb1, 0x34, 0xb7, 0x9f, 0x6d, 0x6c, 0x14, 0x90, 0xa9, 0xc4, 0x82, 0xce, 0x58, 0x3a, 0x81, 0x5d, 0xef, 0x91, - 0x67, 0x8e, 0x01, 0x99, 0xd2, 0x89, 0xa3, 0x2d, 0x49, 0xd4, 0x93, 0xb4, 0xfc, 0xea, 0x45, 0x3d, 0x5a, 0x7d, 0xfd, - 0xcf, 0xa8, 0x97, 0xd1, 0xf4, 0x31, 0x5f, 0x3b, 0x25, 0x79, 0xad, 0x8f, 0x33, 0xdf, 0xc7, 0xda, 0x2e, 0x4e, 0x00, - 0xbc, 0x11, 0xda, 0xd6, 0x8e, 0x2c, 0xd0, 0x9a, 0x8f, 0x4b, 0xea, 0xa4, 0x12, 0x4d, 0x27, 0x00, 0xd5, 0x60, 0x11, - 0x54, 0x68, 0x1b, 0x10, 0x4c, 0x19, 0xb0, 0xc5, 0x23, 0x2d, 0x40, 0x73, 0x71, 0xd9, 0x42, 0xcb, 0x5a, 0x61, 0xc7, - 0x59, 0xd5, 0xef, 0xe2, 0x4b, 0xe2, 0x3d, 0x06, 0xaa, 0x7c, 0xb1, 0xe8, 0x8e, 0x1b, 0x0d, 0xa4, 0x3c, 0x7e, 0x8d, - 0xfa, 0xe3, 0x01, 0xbe, 0x05, 0x14, 0xc2, 0x35, 0x8c, 0xc2, 0xb5, 0x39, 0x76, 0xdc, 0x1c, 0x1b, 0x0d, 0xb9, 0x46, - 0xdd, 0xa0, 0xf2, 0xc2, 0x55, 0x5e, 0xaf, 0x2d, 0x64, 0x36, 0x31, 0xee, 0x1c, 0x99, 0x14, 0x30, 0x04, 0x23, 0x84, - 0xbc, 0x92, 0x68, 0x67, 0xb3, 0xd0, 0x28, 0x54, 0x37, 0xbb, 0x17, 0x28, 0xaa, 0x3d, 0x3d, 0x62, 0x80, 0x05, 0x54, - 0x2d, 0xd5, 0xc8, 0x53, 0x8d, 0x47, 0x8d, 0xb6, 0x41, 0xf7, 0x66, 0xbb, 0x5b, 0x6f, 0xec, 0x7e, 0xd5, 0x18, 0x1e, - 0x35, 0xc8, 0xb4, 0xda, 0xe1, 0x6b, 0xd9, 0x68, 0xac, 0xeb, 0xf7, 0xa5, 0x7e, 0x13, 0xd7, 0xee, 0x2f, 0x9e, 0x6e, - 0x99, 0x78, 0xf8, 0xd3, 0xb7, 0x3a, 0x6f, 0x45, 0xc2, 0x85, 0x60, 0x05, 0x9c, 0xb0, 0x44, 0x63, 0xb1, 0x5e, 0x97, - 0xa7, 0xfe, 0xef, 0xda, 0xda, 0x8c, 0x11, 0x0e, 0x74, 0xc8, 0x48, 0x6d, 0x58, 0xe2, 0x02, 0x53, 0x43, 0x45, 0x08, - 0x21, 0x1f, 0xb4, 0x37, 0x8f, 0xd1, 0x86, 0x24, 0x65, 0x24, 0x38, 0xbb, 0x63, 0x45, 0x58, 0x72, 0x7d, 0xef, 0xb1, - 0xfc, 0xae, 0x48, 0xd7, 0x17, 0x83, 0xd4, 0x14, 0xcb, 0x1d, 0x21, 0xcb, 0xc9, 0x17, 0x90, 0x73, 0xca, 0x0b, 0x96, - 0xc4, 0x10, 0xc4, 0x27, 0xbc, 0x60, 0x86, 0x71, 0xbf, 0xe7, 0xe5, 0xc6, 0xac, 0xce, 0x69, 0x66, 0xa1, 0xf6, 0x07, - 0xa0, 0x99, 0x83, 0x72, 0x48, 0x92, 0xad, 0x62, 0xd7, 0xf7, 0x1e, 0xbe, 0xde, 0x25, 0x43, 0xaf, 0x56, 0x4e, 0x7a, - 0xce, 0x80, 0xf5, 0xc1, 0x79, 0x35, 0xd4, 0xcc, 0xfd, 0x48, 0xe3, 0xcc, 0x30, 0x51, 0x79, 0xcc, 0x01, 0x99, 0xae, - 0xef, 0x3d, 0x7c, 0x17, 0x73, 0xa3, 0x9b, 0x42, 0x38, 0x9c, 0x77, 0x5c, 0x90, 0x98, 0x12, 0x86, 0xec, 0xe4, 0x4b, - 0x3a, 0x56, 0x04, 0xa7, 0x7b, 0x4a, 0x4d, 0x26, 0x88, 0x1d, 0x7d, 0x31, 0x20, 0x99, 0x03, 0x01, 0xc9, 0x10, 0xce, - 0x6a, 0x72, 0x1d, 0x31, 0x6b, 0x60, 0x3a, 0xbb, 0x82, 0xc5, 0x48, 0x2c, 0x7b, 0x88, 0x70, 0x66, 0xba, 0xd5, 0x6b, - 0x7b, 0x9c, 0x28, 0xba, 0x69, 0xe8, 0x56, 0xc9, 0xb3, 0xef, 0x41, 0xf0, 0xf2, 0x1f, 0xaf, 0x5c, 0xdb, 0x65, 0xc2, - 0x13, 0x6f, 0x91, 0x76, 0x7d, 0xef, 0xe1, 0xaf, 0xce, 0x28, 0x6d, 0x4e, 0x3d, 0xf9, 0xdf, 0x92, 0x51, 0x1f, 0xfe, - 0x9a, 0x54, 0xb9, 0xa6, 0xf0, 0xf5, 0xbd, 0x87, 0xbf, 0xef, 0x2a, 0x06, 0xe9, 0xeb, 0x45, 0xa5, 0x24, 0x30, 0xe3, - 0x5b, 0xb2, 0x3c, 0x5d, 0xba, 0xb3, 0x22, 0x15, 0x6b, 0x6c, 0x4e, 0xa8, 0x54, 0xad, 0x4b, 0xdd, 0xca, 0x13, 0x2c, - 0x89, 0xb9, 0x4a, 0xaa, 0x2f, 0x9b, 0x43, 0x63, 0x2e, 0xc5, 0x55, 0x26, 0xe7, 0xec, 0x1b, 0xf7, 0x4b, 0x4f, 0x35, - 0x4a, 0xf8, 0x0c, 0x0c, 0x71, 0xcc, 0xd8, 0x05, 0xde, 0x6f, 0xa1, 0xee, 0xc6, 0x79, 0x26, 0x0d, 0xa2, 0x16, 0xf5, - 0xc3, 0x06, 0x53, 0xd2, 0xc2, 0x19, 0x69, 0xe1, 0x9c, 0xa8, 0x7e, 0xcb, 0x9e, 0x18, 0xdd, 0xbc, 0x6c, 0xda, 0x9e, - 0x3b, 0xb0, 0xdd, 0x73, 0xbb, 0x6f, 0xed, 0xa1, 0x3c, 0xed, 0xe6, 0x46, 0x7f, 0x69, 0x0e, 0xfa, 0xa9, 0x41, 0x8d, - 0x27, 0x2c, 0x2e, 0x70, 0x61, 0x5a, 0xbe, 0xe2, 0xc3, 0x1c, 0xec, 0x54, 0x60, 0x66, 0x58, 0xa3, 0xb4, 0x2c, 0xdb, - 0x76, 0x65, 0xf3, 0xc4, 0xac, 0x55, 0x81, 0xf3, 0x04, 0x48, 0x39, 0xce, 0x9d, 0x5d, 0x8f, 0xda, 0xae, 0x72, 0x76, - 0x70, 0x10, 0xbb, 0x4a, 0x34, 0x2e, 0x7c, 0x7e, 0x75, 0x03, 0xf8, 0xde, 0x52, 0x8d, 0x29, 0x32, 0x13, 0x68, 0x34, - 0xb2, 0xc1, 0x9a, 0xee, 0x13, 0x12, 0xe7, 0x75, 0x28, 0xfa, 0xd1, 0x1b, 0x66, 0x70, 0x03, 0x00, 0x8d, 0x46, 0x79, - 0xdd, 0xbb, 0x01, 0xb1, 0xa7, 0x1a, 0xcb, 0xf5, 0x97, 0xb8, 0xb4, 0x26, 0x6a, 0x6d, 0xd9, 0x61, 0xf9, 0x51, 0x20, - 0x11, 0xe2, 0xae, 0xf0, 0xf3, 0x09, 0xb6, 0x86, 0x80, 0x72, 0x2f, 0x9c, 0x0d, 0x04, 0x36, 0x56, 0x5b, 0xae, 0x90, - 0x27, 0x6d, 0x1d, 0x94, 0xfa, 0x42, 0x70, 0xc1, 0x05, 0x85, 0x1a, 0x6b, 0x87, 0xe5, 0x4f, 0xd8, 0xb6, 0x39, 0x27, - 0x56, 0xc8, 0x69, 0xcb, 0xcc, 0x30, 0x0c, 0xc0, 0x3a, 0x25, 0x60, 0x9e, 0x93, 0x97, 0xdf, 0x46, 0xfd, 0x87, 0x01, - 0xea, 0x3f, 0x22, 0x2c, 0xd8, 0x06, 0x56, 0x57, 0x92, 0x48, 0xa7, 0xa0, 0x50, 0x3e, 0xeb, 0xf1, 0x9c, 0x80, 0x36, - 0xae, 0x0e, 0xd5, 0xda, 0x15, 0xe5, 0x37, 0x28, 0x4b, 0xb8, 0x53, 0x8c, 0x3e, 0x13, 0xfb, 0xfb, 0xe4, 0xb8, 0xba, - 0xa0, 0x83, 0xae, 0x77, 0x29, 0x07, 0x43, 0x52, 0xf8, 0xf0, 0xf7, 0xef, 0xdf, 0xad, 0x3e, 0x9e, 0x6f, 0xef, 0xe0, - 0xc0, 0xac, 0x14, 0x66, 0x1d, 0x6c, 0xe0, 0xba, 0x91, 0x29, 0xf4, 0x5f, 0xde, 0x89, 0xd7, 0xa9, 0xd0, 0xc6, 0x66, - 0xf4, 0xc7, 0x21, 0x8c, 0xb6, 0xdd, 0x36, 0x25, 0x58, 0xd0, 0x2c, 0xd0, 0x25, 0x6b, 0xdc, 0x4a, 0x8b, 0x6f, 0x90, - 0x91, 0x87, 0xa6, 0x00, 0x13, 0xa3, 0xdd, 0xd9, 0x8f, 0xd6, 0x0e, 0x4f, 0xec, 0xd0, 0xd0, 0xd2, 0x10, 0x42, 0x8b, - 0xf7, 0x80, 0x39, 0xf6, 0x88, 0x00, 0x10, 0xbd, 0x34, 0x90, 0xaa, 0x40, 0x16, 0x45, 0x95, 0x22, 0xff, 0xf9, 0x3e, - 0x21, 0x2f, 0x2b, 0x45, 0xe6, 0xdb, 0xca, 0x98, 0x0b, 0x10, 0x03, 0xa5, 0x70, 0x91, 0x50, 0x26, 0xd8, 0xcb, 0xd0, - 0x0f, 0xda, 0x97, 0x37, 0xd2, 0x66, 0x52, 0x71, 0xe3, 0xc1, 0x4d, 0xa9, 0x51, 0xf1, 0xd9, 0x7c, 0x0f, 0x89, 0x8d, - 0xdc, 0x7b, 0x90, 0xcb, 0xa8, 0x19, 0x24, 0x7c, 0xbf, 0x33, 0xa5, 0x7d, 0xbb, 0xeb, 0xcf, 0x9b, 0x16, 0x31, 0x1b, - 0xeb, 0x92, 0x70, 0xa1, 0x58, 0xa1, 0x1f, 0xb1, 0xb1, 0x2c, 0xe0, 0xfe, 0xa3, 0x04, 0x0b, 0x5a, 0xdf, 0x0b, 0x74, - 0x80, 0x66, 0x82, 0xc1, 0xa5, 0xc3, 0xc6, 0x0c, 0xcd, 0xaf, 0xcf, 0xe6, 0x0e, 0xfc, 0x7a, 0xb3, 0xd6, 0xcb, 0x83, - 0x83, 0x2f, 0xac, 0x02, 0x94, 0x1b, 0xa6, 0x19, 0x46, 0x40, 0xbc, 0x2c, 0x97, 0xe3, 0x6e, 0x86, 0xef, 0xc5, 0x95, - 0xca, 0xc0, 0x13, 0x8e, 0x90, 0x08, 0x3d, 0x27, 0x7a, 0x3d, 0xd9, 0xa4, 0xf7, 0x4e, 0x9b, 0x21, 0x42, 0xb1, 0x06, - 0xc8, 0x3d, 0xc8, 0xe5, 0x56, 0xc9, 0xa4, 0x2a, 0x5b, 0xdb, 0x72, 0x10, 0x8f, 0x01, 0x5c, 0xb1, 0x11, 0x52, 0x02, - 0x34, 0xdc, 0x2d, 0xb4, 0x3c, 0x97, 0xc0, 0xfe, 0x63, 0x95, 0x80, 0x48, 0x8b, 0x6a, 0x1b, 0x17, 0x21, 0x6c, 0x4d, - 0x7d, 0x02, 0xe3, 0x84, 0x87, 0xcf, 0x77, 0x69, 0xa8, 0x3d, 0x6a, 0x33, 0x73, 0x06, 0x41, 0x09, 0x89, 0xca, 0x0a, - 0xc9, 0x97, 0x58, 0x38, 0x6e, 0xce, 0xdf, 0xc3, 0x01, 0x29, 0x56, 0x34, 0xb6, 0x77, 0x5b, 0x70, 0x7c, 0x14, 0xc9, - 0x22, 0xae, 0x75, 0xdd, 0x2d, 0x4c, 0x35, 0xec, 0x40, 0x47, 0x43, 0x38, 0x15, 0xe6, 0x9e, 0xf0, 0x71, 0x45, 0x52, - 0x7f, 0xb6, 0x26, 0xda, 0xda, 0x13, 0xc3, 0xca, 0x34, 0x25, 0x98, 0xff, 0xcf, 0xd6, 0xea, 0xba, 0x2c, 0x84, 0x99, - 0x19, 0xc6, 0x8d, 0x5d, 0x05, 0xb6, 0x06, 0x1c, 0x5b, 0xfe, 0x2d, 0x83, 0x45, 0xf5, 0x4a, 0x71, 0xd3, 0x69, 0xc0, - 0x04, 0xbc, 0x05, 0xeb, 0x99, 0xcd, 0xad, 0xff, 0xdc, 0x1c, 0x8c, 0x02, 0xab, 0x1a, 0x81, 0x97, 0x86, 0xc0, 0x23, - 0x60, 0xdc, 0xbc, 0x69, 0x79, 0xcf, 0x19, 0xd1, 0x08, 0x7f, 0xe2, 0x39, 0x3c, 0xb3, 0x2c, 0xf7, 0xd6, 0xc7, 0xc6, - 0x8a, 0xa4, 0x82, 0x80, 0x6d, 0x11, 0x76, 0x44, 0x5e, 0x22, 0xac, 0x1a, 0x8d, 0xae, 0xba, 0x60, 0x95, 0x56, 0xa5, - 0x1a, 0xa6, 0x80, 0x5b, 0x62, 0xc0, 0xfb, 0xda, 0x89, 0x0a, 0x86, 0x04, 0xde, 0xfa, 0x5b, 0x81, 0xfa, 0xfe, 0xe1, - 0xdb, 0x38, 0xa4, 0x6f, 0x61, 0xd9, 0xf2, 0x22, 0x16, 0xa6, 0x14, 0x57, 0x77, 0x38, 0x6f, 0xbe, 0x6f, 0x36, 0x02, - 0xe3, 0xde, 0x6f, 0x63, 0xb0, 0x71, 0x43, 0x5d, 0x6d, 0x49, 0x43, 0xb9, 0x09, 0xbb, 0xa8, 0xb2, 0x77, 0x0c, 0x3b, - 0xeb, 0xea, 0x4a, 0xda, 0xd5, 0x44, 0xad, 0xd7, 0x8a, 0x55, 0x46, 0x03, 0x1b, 0x86, 0x9d, 0xe6, 0x98, 0xd9, 0x56, - 0xe0, 0x3f, 0x9e, 0x13, 0x8d, 0x03, 0x64, 0x7d, 0xf3, 0xad, 0xeb, 0x94, 0x6a, 0x98, 0xb0, 0xbd, 0xdd, 0xf9, 0xf8, - 0x98, 0xef, 0x3a, 0x1f, 0xb1, 0x74, 0x5b, 0xdf, 0x9c, 0x8d, 0xed, 0x7f, 0xe3, 0x6c, 0x74, 0x6a, 0x7b, 0x7f, 0x3c, - 0x02, 0x77, 0x52, 0x3b, 0x1e, 0xeb, 0x6b, 0x4a, 0x24, 0x16, 0x6e, 0x39, 0x2e, 0x3b, 0xab, 0x95, 0xe8, 0xb7, 0x40, - 0xed, 0x14, 0x45, 0xf0, 0xb3, 0x6d, 0x7f, 0x06, 0x24, 0xd9, 0xea, 0x90, 0x63, 0x51, 0x8a, 0x32, 0x28, 0x01, 0x03, - 0xea, 0xd8, 0xd8, 0x7a, 0x19, 0xc4, 0x76, 0x38, 0xe4, 0xb0, 0x9c, 0x88, 0xf2, 0xea, 0x0a, 0x46, 0x6c, 0x8e, 0x0d, - 0x27, 0x60, 0xc6, 0x3b, 0xad, 0x0a, 0xbd, 0xf8, 0xf9, 0xaf, 0x99, 0xd3, 0xda, 0x11, 0x63, 0x39, 0x89, 0x9a, 0x15, - 0x83, 0x1b, 0x81, 0x63, 0x18, 0xf7, 0x8d, 0x84, 0x5a, 0x9d, 0xea, 0xa8, 0x76, 0x24, 0xe1, 0x16, 0xa8, 0xdd, 0xf6, - 0xcd, 0xb9, 0xb4, 0x5a, 0xed, 0x3c, 0x58, 0x70, 0x11, 0xe0, 0xf6, 0x73, 0xa2, 0x6b, 0x24, 0x85, 0x12, 0x27, 0x41, - 0xe1, 0xdc, 0xa0, 0xaa, 0x26, 0xb2, 0xdf, 0x1a, 0x00, 0x4f, 0xda, 0xcd, 0x2e, 0x64, 0x25, 0x24, 0x67, 0x8d, 0x06, - 0xca, 0xcb, 0x8e, 0x69, 0x5f, 0x34, 0xb2, 0x01, 0x66, 0x38, 0xb3, 0x02, 0x0b, 0x9c, 0x5e, 0x71, 0x5e, 0x75, 0xdd, - 0xcf, 0x06, 0x08, 0x17, 0xab, 0x55, 0x6c, 0x87, 0x96, 0xa3, 0xd5, 0x2a, 0x0f, 0x87, 0x66, 0xf2, 0xa1, 0xe2, 0xcb, - 0x9e, 0x26, 0x2f, 0xcd, 0x79, 0xf8, 0x12, 0x06, 0xd9, 0x20, 0x71, 0xee, 0x54, 0x82, 0x39, 0x68, 0xae, 0x1a, 0xb2, - 0x9f, 0x35, 0xda, 0x83, 0x80, 0x86, 0xf5, 0xb3, 0x01, 0xc9, 0xd7, 0x60, 0x39, 0xab, 0xdc, 0x81, 0xf9, 0x37, 0x1c, - 0x6c, 0x7f, 0x9b, 0x73, 0xc6, 0x36, 0x18, 0xae, 0xc9, 0xa6, 0xca, 0xa0, 0xc4, 0x2b, 0xb7, 0xb8, 0xbe, 0x5c, 0xcd, - 0xc0, 0xa2, 0x2c, 0x84, 0xdd, 0x35, 0x73, 0x0f, 0x84, 0xff, 0x12, 0xdb, 0x25, 0x2d, 0x8d, 0xb8, 0x37, 0x10, 0xdf, - 0xdb, 0x6e, 0x27, 0x49, 0x42, 0x8b, 0x89, 0xb9, 0x12, 0xf1, 0x37, 0xbc, 0x66, 0x0f, 0x1c, 0xbb, 0x71, 0x06, 0x3d, - 0xf7, 0xcb, 0xce, 0x06, 0xc4, 0x8e, 0xdf, 0x33, 0x3b, 0xde, 0x71, 0xa5, 0xa0, 0xbb, 0x75, 0x11, 0x76, 0x30, 0xf4, - 0x7f, 0x79, 0x30, 0x27, 0x6e, 0x30, 0x16, 0x4d, 0x36, 0xe0, 0xf6, 0x0d, 0x78, 0x14, 0x74, 0x03, 0x6e, 0xdf, 0x86, - 0xaf, 0x87, 0x56, 0xf6, 0xcd, 0x01, 0x06, 0x64, 0xc2, 0x8e, 0xb4, 0x4a, 0x08, 0x86, 0x79, 0xba, 0xc9, 0x91, 0x59, - 0xb2, 0x0a, 0x87, 0xab, 0x26, 0xb1, 0xd8, 0xd8, 0x0b, 0x15, 0x93, 0x1a, 0x08, 0xc6, 0x22, 0x7d, 0x89, 0x42, 0xa5, - 0x41, 0xdd, 0x38, 0x06, 0xb0, 0xca, 0x69, 0xeb, 0x5f, 0x1e, 0x1c, 0x80, 0xd0, 0x00, 0xac, 0x5d, 0x92, 0xd1, 0xb9, - 0x5e, 0x14, 0xc0, 0x5f, 0x29, 0xff, 0x1b, 0x92, 0xc1, 0xed, 0xc4, 0xa4, 0xc1, 0x0f, 0x48, 0x98, 0x53, 0xa5, 0xf8, - 0x17, 0x9b, 0xe6, 0x7e, 0xe3, 0x82, 0x78, 0x8c, 0x56, 0x96, 0x53, 0x94, 0xa8, 0x2b, 0x1d, 0xba, 0xd6, 0x21, 0xf7, - 0xf4, 0x0b, 0x13, 0xfa, 0x25, 0x57, 0x9a, 0x09, 0x00, 0x40, 0x85, 0x78, 0x30, 0x25, 0x85, 0x60, 0xeb, 0xd6, 0x6a, - 0xd1, 0xd1, 0xe8, 0xbb, 0x55, 0x74, 0x9d, 0x2d, 0x9a, 0x52, 0x31, 0xca, 0x6d, 0x27, 0xa1, 0xcd, 0xa4, 0xb7, 0x13, - 0x2d, 0x4b, 0x86, 0x16, 0x3b, 0x15, 0xfb, 0x61, 0x68, 0x7d, 0x2c, 0x88, 0x3f, 0x17, 0xfc, 0x59, 0xfa, 0x5d, 0x3e, - 0x06, 0xae, 0xd4, 0xbf, 0xb1, 0x0a, 0xe1, 0x4c, 0xb0, 0x0e, 0xc8, 0x6b, 0x52, 0x1f, 0xa7, 0x47, 0x9d, 0x7c, 0x4b, - 0xb9, 0x50, 0x1a, 0x85, 0x6d, 0x9c, 0x14, 0x06, 0x53, 0xce, 0xbe, 0x2d, 0x71, 0xfd, 0xea, 0x8f, 0x11, 0x7f, 0x74, - 0x88, 0x7f, 0x97, 0x4a, 0xa3, 0x65, 0x89, 0x60, 0xc8, 0xef, 0x48, 0xad, 0xe0, 0x2a, 0x36, 0xe7, 0xfa, 0xb9, 0x9e, - 0xe5, 0x1b, 0x9e, 0x38, 0x5d, 0xad, 0x4a, 0xa9, 0x40, 0xc5, 0x37, 0x0c, 0x3f, 0x61, 0x70, 0x6f, 0xfc, 0x8c, 0x07, - 0x55, 0xb6, 0xef, 0x8b, 0x9f, 0x05, 0xf7, 0xc5, 0xcf, 0x78, 0xba, 0x5d, 0x34, 0xb8, 0x27, 0xee, 0x24, 0xe7, 0x49, - 0x2b, 0xf2, 0x7c, 0xd4, 0x94, 0x56, 0xfe, 0x95, 0x76, 0x6b, 0xe0, 0xca, 0x26, 0x0e, 0x8c, 0xf3, 0xea, 0x22, 0x14, - 0x73, 0xe6, 0x8c, 0x96, 0xc3, 0xff, 0xd6, 0x3a, 0xb9, 0x93, 0x47, 0x5a, 0x29, 0xe4, 0x0d, 0x2d, 0xf4, 0x3d, 0xd8, - 0x70, 0xc5, 0x96, 0x0f, 0x20, 0x25, 0xa0, 0x6c, 0xfb, 0xf7, 0xba, 0x08, 0xc4, 0x71, 0x65, 0x9d, 0x8f, 0xc2, 0xf6, - 0x49, 0x51, 0x72, 0x75, 0x75, 0x21, 0xe4, 0xd6, 0x68, 0x09, 0x10, 0xa6, 0xde, 0x35, 0x8f, 0x39, 0x9a, 0xcc, 0xd2, - 0xe5, 0xba, 0x54, 0x1d, 0x14, 0x96, 0xab, 0xe3, 0x08, 0x17, 0x6b, 0x73, 0x83, 0xfe, 0x8a, 0xe3, 0xbf, 0xb9, 0xa3, - 0x91, 0x9f, 0x4a, 0x0a, 0xf4, 0x68, 0xb7, 0xaf, 0xcd, 0x0e, 0x12, 0x69, 0xe7, 0x50, 0x5a, 0x0a, 0x00, 0x56, 0x1b, - 0x7c, 0x5d, 0x7b, 0x9c, 0x7a, 0x22, 0xdd, 0x6c, 0xbe, 0x69, 0x08, 0x8b, 0x59, 0x69, 0xc1, 0x63, 0xba, 0xd9, 0x61, - 0x39, 0xea, 0x65, 0x71, 0x5d, 0xee, 0xb1, 0x5a, 0xbf, 0xe8, 0x1b, 0xa0, 0xac, 0x0c, 0xd1, 0x56, 0xab, 0xb8, 0x0e, - 0x6f, 0x22, 0x82, 0x6b, 0x10, 0x84, 0x45, 0x60, 0xc0, 0x51, 0x63, 0xbc, 0x6d, 0x9d, 0x18, 0x6d, 0xda, 0x2f, 0x79, - 0xd6, 0xbd, 0x36, 0x8e, 0x50, 0xd1, 0x60, 0xab, 0x87, 0x9a, 0x07, 0x6c, 0x67, 0x57, 0x76, 0x14, 0x40, 0x68, 0x4a, - 0xbd, 0x71, 0x6e, 0x65, 0x45, 0xbb, 0x03, 0xbe, 0xe8, 0x3b, 0xe6, 0xb9, 0x0e, 0x74, 0xdb, 0xf9, 0x81, 0x6d, 0xd3, - 0x13, 0xf9, 0x2d, 0xdb, 0xa6, 0x1a, 0x27, 0xbc, 0xdf, 0x42, 0xdf, 0x37, 0x84, 0xb5, 0x7d, 0xed, 0x2e, 0xf2, 0xbf, - 0xd0, 0x5d, 0x1b, 0xd0, 0xd3, 0x82, 0xd9, 0xd3, 0x98, 0x0f, 0x7a, 0xbd, 0xfe, 0x54, 0xfa, 0x2f, 0x18, 0x5b, 0xa1, - 0x4f, 0x76, 0x17, 0x38, 0xb1, 0xd2, 0x38, 0x04, 0xc7, 0xaf, 0x38, 0x99, 0xe4, 0x72, 0x48, 0xf3, 0x77, 0xd0, 0x63, - 0x95, 0xfb, 0xfc, 0x6e, 0x54, 0x50, 0xcd, 0x1c, 0xad, 0xa9, 0x46, 0xf1, 0x8a, 0x07, 0xc3, 0x78, 0xc5, 0x2d, 0xe5, - 0xae, 0x5a, 0xc0, 0xcb, 0x97, 0x65, 0x13, 0xe9, 0xa7, 0x75, 0x29, 0x83, 0xa9, 0xdd, 0xbd, 0x6c, 0x92, 0x34, 0x56, - 0x92, 0x34, 0xa6, 0xe2, 0xcd, 0xa6, 0xe2, 0xf8, 0xef, 0x6f, 0x0c, 0x76, 0x9b, 0xcc, 0xfd, 0x1d, 0x90, 0xb9, 0xbf, - 0x79, 0xfa, 0xdd, 0x5a, 0x01, 0xc5, 0x3b, 0x4e, 0x8e, 0x8d, 0x65, 0x8c, 0x1d, 0xf5, 0x5b, 0x0d, 0x06, 0x0d, 0x9a, - 0x5c, 0x06, 0xde, 0x0e, 0xd5, 0xe9, 0xe5, 0xed, 0x8f, 0xe2, 0x6c, 0xa1, 0xb4, 0x9c, 0xb9, 0x46, 0x95, 0xf3, 0x71, - 0x32, 0x99, 0xa0, 0xc0, 0x36, 0x77, 0xf8, 0x69, 0xdd, 0x8d, 0x6c, 0xf9, 0x99, 0x8b, 0x51, 0xaa, 0xb0, 0x3b, 0x5b, - 0x54, 0x2a, 0xd7, 0xc4, 0x9b, 0x39, 0x6f, 0xe7, 0xe1, 0x31, 0x17, 0x5c, 0x4d, 0x59, 0x11, 0x17, 0x68, 0xf9, 0xad, - 0xce, 0x0a, 0xb8, 0xcd, 0xb1, 0x9d, 0xe1, 0x51, 0x69, 0x39, 0xa0, 0x13, 0x68, 0x0d, 0x74, 0x46, 0x33, 0xa6, 0xa7, - 0x72, 0x04, 0x86, 0x2f, 0xc9, 0xa8, 0x74, 0xa7, 0x3a, 0x38, 0xd8, 0x8f, 0x23, 0xa3, 0xbf, 0x00, 0x1f, 0xf4, 0x30, - 0x07, 0xf5, 0x96, 0xe0, 0x18, 0x54, 0x75, 0xcd, 0xd0, 0x92, 0x6d, 0xfa, 0xd0, 0xe8, 0xe4, 0x33, 0xbb, 0xc3, 0x1c, - 0xad, 0xd7, 0xa9, 0x1d, 0x75, 0x34, 0xe6, 0x2c, 0x1f, 0x45, 0xf8, 0x33, 0xbb, 0x4b, 0x4b, 0xb7, 0x75, 0xe3, 0x65, - 0x6d, 0x16, 0x31, 0x92, 0x37, 0x22, 0xc2, 0x55, 0x27, 0xe9, 0x72, 0x8d, 0x65, 0xc1, 0x27, 0x80, 0xa3, 0xbf, 0xb0, - 0xbb, 0xd4, 0xb5, 0x17, 0xb8, 0x0a, 0xa2, 0xa5, 0x07, 0x7d, 0x12, 0x24, 0x87, 0xcb, 0xe0, 0x04, 0x8e, 0xbe, 0xa9, - 0x3b, 0x20, 0xb5, 0x72, 0x95, 0x08, 0x89, 0xd0, 0xfa, 0xdf, 0x9d, 0x0a, 0x5e, 0x84, 0xe7, 0x9c, 0xae, 0x59, 0xdc, - 0x6e, 0x54, 0x62, 0x50, 0xa1, 0xb2, 0x20, 0xf9, 0x18, 0x73, 0xbf, 0xfb, 0x9c, 0xf7, 0x43, 0xa0, 0x33, 0x5b, 0x50, - 0xd7, 0x68, 0x3a, 0x32, 0xbf, 0x50, 0x75, 0x07, 0x35, 0xd3, 0x55, 0xc5, 0xbd, 0x8f, 0x31, 0x00, 0x1e, 0xac, 0x65, - 0xa8, 0x71, 0x08, 0x5d, 0x7b, 0x33, 0xd5, 0x31, 0x25, 0xf1, 0xd2, 0xcf, 0x21, 0xe5, 0x21, 0x18, 0xf5, 0x1a, 0xd0, - 0xd0, 0x21, 0x98, 0xb5, 0x3c, 0xe4, 0xe3, 0x58, 0x6c, 0x9d, 0xa1, 0xd2, 0x9c, 0xa1, 0x49, 0x00, 0xf2, 0x6f, 0x9c, - 0x99, 0xcc, 0x40, 0xc3, 0xf0, 0x96, 0xe6, 0x00, 0x74, 0xab, 0xeb, 0x70, 0x28, 0x5c, 0xd1, 0xd2, 0x79, 0xcf, 0x2e, - 0xba, 0xac, 0x0d, 0x2b, 0x36, 0xed, 0xa0, 0x75, 0x0a, 0x53, 0x62, 0xb6, 0xc0, 0xda, 0xeb, 0x7d, 0xb8, 0xb7, 0xab, - 0x8d, 0x8b, 0xc4, 0x4f, 0x8b, 0x78, 0x98, 0xc4, 0x14, 0x2d, 0x79, 0x4c, 0xb1, 0x04, 0x3b, 0xc8, 0x62, 0x5d, 0x8e, - 0x9f, 0x85, 0xcb, 0x51, 0xb3, 0x92, 0xde, 0xed, 0x60, 0x08, 0x5c, 0xbe, 0x06, 0xdb, 0x50, 0xcc, 0x3d, 0x61, 0xe1, - 0xb1, 0xf1, 0xf4, 0x0b, 0xd6, 0x6d, 0x6e, 0x17, 0xc4, 0xaf, 0xc0, 0x98, 0xc6, 0xcb, 0x60, 0x16, 0xa1, 0x53, 0xb9, - 0x73, 0x38, 0x74, 0xd7, 0x84, 0x95, 0xf1, 0x6a, 0xac, 0xc8, 0xc6, 0xd1, 0xf3, 0x7d, 0x1b, 0xcf, 0x7f, 0x16, 0xac, - 0xb8, 0xbb, 0x62, 0x60, 0x63, 0x2d, 0xc1, 0xdd, 0xb8, 0x5a, 0x86, 0xca, 0x40, 0xbe, 0x27, 0x0d, 0xeb, 0xb2, 0xc6, - 0xdf, 0x8d, 0x8a, 0xb1, 0x36, 0xf7, 0x94, 0x81, 0xb6, 0xc6, 0x6e, 0x17, 0xf6, 0x4d, 0xd7, 0x4d, 0xd6, 0x35, 0x8a, - 0xb8, 0x0a, 0xd2, 0xee, 0x6e, 0x01, 0x17, 0xa1, 0x3f, 0x6c, 0x5f, 0x0d, 0x36, 0x55, 0x37, 0x90, 0x04, 0xd7, 0x7e, - 0xf2, 0xdb, 0x53, 0xdd, 0x65, 0xad, 0xfb, 0xed, 0xa9, 0xd6, 0x2e, 0x0b, 0x8d, 0x21, 0x11, 0x76, 0xfd, 0x94, 0xfe, - 0xd3, 0x62, 0xbd, 0x46, 0x6b, 0x18, 0xde, 0x7b, 0xde, 0x8d, 0xe3, 0xf7, 0xde, 0x42, 0x31, 0x81, 0x8b, 0xdc, 0xab, - 0x5c, 0x7a, 0x42, 0x5e, 0x8d, 0xe0, 0x3d, 0xdf, 0x1a, 0xc2, 0x7b, 0x1e, 0x38, 0xbd, 0x82, 0xd4, 0x34, 0x11, 0x6c, - 0xe4, 0xe9, 0x27, 0xb2, 0x48, 0x68, 0xf8, 0xb8, 0xd7, 0x9c, 0x70, 0xfd, 0x57, 0x0a, 0xfc, 0x17, 0x1e, 0x2e, 0xb4, - 0x96, 0x02, 0x73, 0x31, 0x5f, 0x68, 0xac, 0xcc, 0xe8, 0x97, 0x63, 0x29, 0x74, 0x73, 0x4c, 0x67, 0x3c, 0xbf, 0x4b, - 0x17, 0xbc, 0x39, 0x93, 0x42, 0xaa, 0x39, 0xcd, 0x18, 0x56, 0x77, 0x4a, 0xb3, 0x59, 0x73, 0xc1, 0xf1, 0x73, 0x96, - 0x7f, 0x61, 0x9a, 0x67, 0x14, 0xbf, 0x95, 0x43, 0xa9, 0x25, 0x7e, 0x7d, 0x7b, 0x37, 0x61, 0x02, 0xff, 0x3e, 0x5c, - 0x08, 0xbd, 0xc0, 0x8a, 0x0a, 0xd5, 0x54, 0xac, 0xe0, 0xe3, 0x6e, 0xb3, 0x39, 0x2f, 0xf8, 0x8c, 0x16, 0x77, 0xcd, - 0x4c, 0xe6, 0xb2, 0x48, 0xff, 0xab, 0x75, 0x4c, 0x1f, 0x8c, 0x4f, 0xba, 0xba, 0xa0, 0x42, 0x71, 0x58, 0x98, 0x94, - 0xe6, 0xf9, 0xde, 0xf1, 0x69, 0x6b, 0xa6, 0xf6, 0xed, 0x85, 0x1f, 0x15, 0x7a, 0xfd, 0x17, 0xfe, 0x20, 0x61, 0x94, - 0xc9, 0x50, 0x0b, 0x37, 0xc8, 0x65, 0xb6, 0x28, 0x94, 0x2c, 0xd2, 0xb9, 0xe4, 0x42, 0xb3, 0xa2, 0x3b, 0x94, 0xc5, - 0x88, 0x15, 0xcd, 0x82, 0x8e, 0xf8, 0x42, 0xa5, 0x27, 0xf3, 0xdb, 0x6e, 0xbd, 0x07, 0x9b, 0x9f, 0x0a, 0x29, 0x58, - 0x17, 0xf8, 0x8d, 0x49, 0x21, 0x17, 0x62, 0xe4, 0x86, 0xb1, 0x10, 0x8a, 0xe9, 0xee, 0x9c, 0x8e, 0xc0, 0x0e, 0x38, - 0x3d, 0x9f, 0xdf, 0x76, 0xcd, 0xac, 0x6f, 0x18, 0x9f, 0x4c, 0x75, 0x7a, 0xda, 0x6a, 0xd9, 0x6f, 0xc5, 0xbf, 0xb2, - 0xb4, 0xdd, 0x49, 0x3a, 0xa7, 0xf3, 0x5b, 0xe0, 0xe0, 0x35, 0x2b, 0x9a, 0x00, 0x0b, 0xa8, 0xd4, 0x4e, 0x5a, 0x0f, - 0x8e, 0xef, 0x43, 0x06, 0xd8, 0x38, 0x34, 0xcd, 0x84, 0xc0, 0xd8, 0x3d, 0x5d, 0xcc, 0xe7, 0xac, 0x00, 0x2f, 0xfa, - 0xee, 0x8c, 0x16, 0x13, 0x2e, 0x9a, 0x85, 0x69, 0xb4, 0x79, 0x3e, 0xbf, 0x5d, 0xc3, 0x7c, 0x52, 0x6b, 0xb6, 0xea, - 0xa6, 0xe5, 0xbe, 0x96, 0xc1, 0x10, 0x4d, 0x4c, 0x9a, 0xb4, 0x98, 0x0c, 0x69, 0xdc, 0xee, 0xdc, 0xc7, 0xfe, 0x7f, - 0x49, 0x07, 0x05, 0x60, 0x6b, 0x8e, 0x16, 0x85, 0xb9, 0x45, 0x4d, 0xdb, 0xca, 0x36, 0x3b, 0x95, 0x5f, 0x58, 0xe1, - 0x5b, 0x35, 0x1f, 0xcb, 0xad, 0x79, 0xff, 0x27, 0x8d, 0xfe, 0x85, 0x27, 0x14, 0xd6, 0xc0, 0x20, 0x47, 0xdf, 0xc8, - 0x83, 0x30, 0xd3, 0xc1, 0xf2, 0x86, 0x8f, 0xf4, 0x34, 0x6d, 0xb7, 0x5a, 0x3f, 0x54, 0x2b, 0xd6, 0x9d, 0x5a, 0xd0, - 0xb5, 0x0b, 0x36, 0xab, 0xad, 0xe3, 0x8c, 0x96, 0xd8, 0xb6, 0x9c, 0x4b, 0xb7, 0xe4, 0x05, 0xcb, 0x4d, 0x34, 0x99, - 0xb5, 0x43, 0xb9, 0xad, 0x71, 0x72, 0x31, 0x65, 0x05, 0xd7, 0xdd, 0xfa, 0x57, 0xd5, 0xf1, 0xf6, 0xea, 0xaf, 0xad, - 0x1c, 0xba, 0xb4, 0x35, 0xdc, 0xa5, 0xe7, 0x63, 0xf8, 0xd8, 0x5e, 0xfd, 0x2f, 0xb4, 0x88, 0x37, 0x10, 0x13, 0x87, - 0x35, 0xd0, 0x3a, 0x98, 0x73, 0x01, 0x26, 0x99, 0x03, 0xfc, 0x0d, 0x28, 0x64, 0x34, 0xcf, 0x62, 0x18, 0xd1, 0x5e, - 0x73, 0xef, 0xb8, 0x60, 0x33, 0xe4, 0x01, 0x91, 0xdc, 0x3f, 0x2d, 0xd8, 0x6c, 0x9d, 0x98, 0xea, 0x4b, 0x83, 0x22, - 0x34, 0xe7, 0x13, 0x91, 0x66, 0x0c, 0xd0, 0x77, 0x9d, 0x30, 0xa1, 0xb9, 0xbe, 0x6b, 0x16, 0xf2, 0x66, 0x39, 0xe2, - 0x6a, 0x9e, 0xd3, 0xbb, 0x74, 0x9c, 0xb3, 0xdb, 0xae, 0x29, 0xd5, 0xe4, 0x9a, 0xcd, 0x94, 0x2b, 0xdb, 0x85, 0xf4, - 0xe6, 0xc8, 0x9a, 0x4d, 0x00, 0xf4, 0xe4, 0xcd, 0xe6, 0xfe, 0x49, 0x8e, 0xd5, 0x1e, 0xa3, 0x8a, 0x35, 0xe5, 0x42, - 0xef, 0xb5, 0x54, 0x77, 0xc6, 0x45, 0xd3, 0x0d, 0xe4, 0xa4, 0x35, 0xbf, 0xed, 0x6e, 0x43, 0x3e, 0xe8, 0x3f, 0x61, - 0xb7, 0x73, 0x2a, 0x46, 0x6c, 0xb4, 0x0c, 0xaa, 0x75, 0xa0, 0x5e, 0x58, 0x2a, 0x15, 0x7a, 0xda, 0x34, 0xb6, 0x5e, - 0x71, 0x47, 0xa0, 0x6f, 0xa0, 0xd6, 0x83, 0x16, 0xb6, 0xff, 0x9f, 0xb4, 0x51, 0x58, 0x79, 0x0f, 0xc2, 0x2e, 0xf1, - 0xf1, 0x5d, 0x13, 0xfe, 0x2e, 0xc1, 0xb7, 0x88, 0x67, 0x34, 0x77, 0x10, 0x99, 0xf1, 0xd1, 0x28, 0xaf, 0x8d, 0xe8, - 0x32, 0xe8, 0xac, 0x8d, 0x96, 0x30, 0xff, 0xb4, 0xb5, 0xd7, 0xda, 0x33, 0x73, 0x71, 0xdb, 0xfc, 0xe4, 0xe4, 0xfe, - 0xf1, 0x03, 0xd6, 0xcd, 0xb9, 0x60, 0xb5, 0xa9, 0x7e, 0x17, 0xd4, 0x61, 0xc3, 0x1d, 0xd7, 0x70, 0x7b, 0xaf, 0xbd, - 0x77, 0xd2, 0xfa, 0xc1, 0xef, 0xd6, 0x9c, 0x8d, 0x75, 0xda, 0x3e, 0x9b, 0xdf, 0xd6, 0xb7, 0xef, 0xb9, 0x6f, 0xfa, - 0xa6, 0xa0, 0xf3, 0x54, 0x48, 0xf8, 0xd3, 0x85, 0x4d, 0x36, 0xce, 0xe5, 0x4d, 0x3a, 0xe5, 0xa3, 0x11, 0x13, 0xb6, - 0x40, 0x99, 0xc8, 0xf2, 0x9c, 0xcf, 0x15, 0xb7, 0xab, 0xe1, 0x70, 0xf7, 0x74, 0x03, 0xaa, 0xe1, 0x80, 0x8e, 0x83, - 0x01, 0x9d, 0x56, 0x03, 0xaa, 0xfa, 0x0f, 0x47, 0xd8, 0xd9, 0x98, 0xab, 0x29, 0xd5, 0xad, 0x61, 0xd2, 0xdf, 0x0b, - 0xa5, 0x01, 0xe6, 0xde, 0x48, 0xc3, 0x50, 0xf1, 0xe6, 0x90, 0xe9, 0x1b, 0xc6, 0xc4, 0xb7, 0x07, 0x71, 0x99, 0x4a, - 0x91, 0xdf, 0xd9, 0xcf, 0x65, 0xd8, 0x25, 0x5d, 0x68, 0xb9, 0x4e, 0x86, 0x5c, 0xd0, 0xe2, 0xee, 0x5a, 0x31, 0xa1, - 0x64, 0x71, 0x2d, 0xc7, 0xe3, 0xe5, 0xb7, 0x48, 0xcb, 0x7d, 0xb4, 0x4e, 0x14, 0x17, 0x93, 0x9c, 0x59, 0xa2, 0x64, - 0x10, 0xc1, 0x11, 0x73, 0xdb, 0xae, 0x69, 0xb2, 0x36, 0xe8, 0x75, 0x92, 0xe5, 0x7c, 0x46, 0x35, 0x33, 0x70, 0x0e, - 0x48, 0x8d, 0x9b, 0x7c, 0xda, 0x6e, 0xcd, 0x6f, 0xf7, 0x5a, 0x7b, 0xf6, 0x4f, 0x55, 0x1a, 0xb6, 0x51, 0x50, 0xd8, - 0x37, 0xc9, 0x85, 0xc1, 0x0f, 0x03, 0x0e, 0xb3, 0x8b, 0xcc, 0xea, 0x99, 0xb5, 0x0b, 0x60, 0x07, 0xb3, 0xab, 0x35, - 0x75, 0xe9, 0xe8, 0x92, 0x6d, 0xf1, 0xb4, 0xf5, 0x43, 0x3d, 0x37, 0xa7, 0x43, 0x96, 0x2f, 0xed, 0x46, 0xf5, 0xc0, - 0x75, 0x5b, 0x35, 0x5c, 0xe6, 0x80, 0x64, 0x18, 0x10, 0x0d, 0xd2, 0xb4, 0x79, 0xc3, 0x86, 0x9f, 0xb9, 0xb6, 0x5b, - 0xa6, 0xa9, 0x6e, 0xc0, 0x79, 0xc7, 0x8c, 0x69, 0xce, 0x8a, 0xa5, 0x3f, 0x8e, 0x5a, 0x35, 0x02, 0x7a, 0x25, 0xcc, - 0x41, 0xa8, 0xe9, 0xb0, 0x09, 0xa1, 0xcc, 0x58, 0xb1, 0xdc, 0x35, 0xb9, 0xcd, 0x0d, 0x1f, 0x1e, 0x67, 0x27, 0xad, - 0x96, 0x3f, 0xea, 0x9a, 0xb6, 0x4e, 0xda, 0x4e, 0x4e, 0xd9, 0x6c, 0x17, 0xa9, 0xa9, 0xd3, 0xd5, 0x76, 0x67, 0x7e, - 0xbb, 0x67, 0xfe, 0x69, 0xed, 0xb5, 0xb6, 0xe9, 0xe8, 0xf6, 0x92, 0x1f, 0x23, 0x8f, 0xa4, 0x5a, 0xce, 0xd3, 0x36, - 0x9b, 0x75, 0x17, 0x0a, 0xce, 0x4c, 0x03, 0x4e, 0x73, 0x16, 0xaf, 0xcd, 0x4c, 0x00, 0x6a, 0x94, 0x0b, 0x38, 0xa2, - 0xec, 0x31, 0x0d, 0x7d, 0x28, 0x09, 0x36, 0xe5, 0x3b, 0x1b, 0xad, 0x0f, 0xab, 0xb5, 0x57, 0x0d, 0x0c, 0xfe, 0x59, - 0xff, 0x55, 0x31, 0xb9, 0x2f, 0x58, 0x20, 0x64, 0xf0, 0x46, 0x72, 0xba, 0x6a, 0x39, 0xc1, 0x62, 0xa4, 0x2b, 0x79, - 0xc7, 0xb8, 0x65, 0xcc, 0xe8, 0xad, 0xf5, 0xcf, 0x98, 0x71, 0x01, 0xd6, 0x5f, 0x08, 0xeb, 0xc0, 0x4e, 0x7e, 0x1a, - 0x36, 0x34, 0xd2, 0x31, 0x34, 0x7c, 0xd8, 0x49, 0x4e, 0x4f, 0x11, 0x6e, 0xe1, 0xce, 0xe9, 0x69, 0x20, 0xd8, 0x8c, - 0xf5, 0xae, 0xa2, 0xbb, 0x4a, 0xaa, 0x1d, 0x25, 0x8f, 0x4c, 0xa3, 0x47, 0xed, 0x56, 0x0b, 0x1b, 0x1f, 0xf4, 0xb2, - 0x30, 0x57, 0x3b, 0x9a, 0x6d, 0xb7, 0x5a, 0xd0, 0x2c, 0xfc, 0x71, 0xf3, 0xfa, 0x85, 0x2c, 0x5b, 0x69, 0x0b, 0xb7, - 0xd3, 0x36, 0xee, 0xa4, 0x1d, 0x7c, 0x9c, 0x1e, 0xe3, 0x93, 0xf4, 0x04, 0x9f, 0xa6, 0xa7, 0xf8, 0x2c, 0x3d, 0xc3, - 0xf7, 0xd3, 0xfb, 0xf8, 0x3c, 0x3d, 0xc7, 0x0f, 0xd2, 0x07, 0xf8, 0x61, 0xda, 0x6e, 0xe1, 0x47, 0x69, 0xbb, 0x8d, - 0x1f, 0xa7, 0xed, 0x0e, 0x7e, 0x92, 0xb6, 0x8f, 0xf1, 0xd3, 0xb4, 0x7d, 0x82, 0x9f, 0xa5, 0xed, 0x53, 0x4c, 0x21, - 0x77, 0x08, 0xb9, 0x19, 0xe4, 0x8e, 0x20, 0x97, 0x41, 0xee, 0x38, 0x6d, 0x9f, 0xae, 0xb1, 0xb2, 0x71, 0x2b, 0xa2, - 0x56, 0xbb, 0x73, 0x7c, 0x72, 0x7a, 0x76, 0xff, 0xfc, 0xc1, 0xc3, 0x47, 0x8f, 0x9f, 0x3c, 0x7d, 0x16, 0x0d, 0xf0, - 0xd0, 0xb8, 0x8f, 0x28, 0xd1, 0xe7, 0x07, 0xed, 0xd3, 0x01, 0xbe, 0xf6, 0x9f, 0x31, 0x3f, 0xe8, 0x9c, 0xb4, 0xd0, - 0xe5, 0xe5, 0xc9, 0xa0, 0x51, 0xe6, 0xbe, 0x37, 0x5e, 0x2b, 0x55, 0x16, 0x21, 0x24, 0x86, 0x1c, 0x84, 0xef, 0x4c, - 0xbd, 0xf7, 0x2c, 0xe6, 0x49, 0x81, 0x0e, 0x0e, 0xcc, 0x8f, 0x89, 0xff, 0x31, 0xf4, 0x3f, 0x68, 0xb0, 0x48, 0xb7, - 0x34, 0x76, 0x6e, 0xcb, 0xba, 0x74, 0x1a, 0x28, 0xed, 0x71, 0xf6, 0xb8, 0xb3, 0x8c, 0xff, 0xaf, 0xc8, 0x5a, 0xbe, - 0x90, 0x13, 0xab, 0x5d, 0x3a, 0xed, 0x31, 0xb2, 0x2c, 0xd2, 0xce, 0xe9, 0xe9, 0xc1, 0x2f, 0x7d, 0xde, 0x6f, 0x0f, - 0x06, 0x87, 0xed, 0xfb, 0x78, 0x52, 0x26, 0x74, 0x6c, 0xc2, 0xb0, 0x4c, 0x38, 0xb6, 0x09, 0x34, 0xb5, 0xb5, 0x21, - 0xe9, 0xc4, 0x24, 0x41, 0x89, 0x75, 0x6a, 0xda, 0xbe, 0x6f, 0xdb, 0x7e, 0x00, 0x26, 0x59, 0xa6, 0x79, 0xd7, 0xf4, - 0xc5, 0xc5, 0xc9, 0xca, 0x35, 0x8a, 0x27, 0xa9, 0x6b, 0xcd, 0x27, 0x9e, 0x0c, 0x06, 0x78, 0x68, 0x12, 0x4f, 0xab, - 0xc4, 0xb3, 0xc1, 0xc0, 0x75, 0xf5, 0xc0, 0x74, 0x75, 0xbf, 0xca, 0x3a, 0x1f, 0x0c, 0x4c, 0x97, 0xc8, 0x39, 0xe0, - 0x2b, 0xbd, 0xf7, 0xa5, 0x54, 0x82, 0xf0, 0x8b, 0xce, 0xe9, 0x69, 0x0f, 0x30, 0xcc, 0x18, 0xd6, 0x7a, 0x18, 0xdd, - 0x04, 0x30, 0xba, 0x83, 0xdf, 0xbd, 0x21, 0x4d, 0xaf, 0x69, 0x09, 0xa4, 0x5e, 0xf4, 0x5f, 0x51, 0x43, 0x1b, 0x98, - 0x9b, 0x3f, 0x13, 0xfb, 0x67, 0x88, 0x1a, 0x5f, 0x28, 0x80, 0x1b, 0xd4, 0x3a, 0x5e, 0x2f, 0x6b, 0x7a, 0xfc, 0x4c, - 0xc1, 0x4f, 0x66, 0xaa, 0x72, 0xda, 0x5b, 0x4d, 0x6f, 0x86, 0xab, 0xa9, 0xfa, 0x82, 0xfe, 0x8c, 0xff, 0x54, 0x87, - 0x71, 0xbf, 0xd9, 0x48, 0xd8, 0x9f, 0x23, 0x70, 0xc8, 0xe9, 0xa5, 0x23, 0x36, 0x41, 0xbd, 0xfe, 0x9f, 0x0a, 0x0f, - 0x1a, 0x41, 0xc6, 0x0f, 0xdb, 0x29, 0xe0, 0xae, 0xb3, 0x99, 0x18, 0xff, 0x80, 0x7a, 0xa8, 0xf7, 0xa7, 0x3a, 0xfc, - 0x13, 0xdd, 0x3b, 0xaa, 0xe6, 0xf2, 0xbb, 0x74, 0x5b, 0xb8, 0x8a, 0xe1, 0x73, 0x58, 0x6e, 0x61, 0x86, 0xdb, 0x4d, - 0x06, 0x11, 0xcf, 0xc0, 0x9f, 0x9b, 0xc4, 0xb2, 0xc1, 0x8f, 0x8e, 0x5b, 0xe8, 0x87, 0x76, 0x07, 0x34, 0x14, 0x4d, - 0x71, 0xb8, 0xbd, 0xe9, 0x8b, 0xe6, 0x31, 0x7e, 0xd0, 0x2c, 0x70, 0x1b, 0xe1, 0x66, 0xdb, 0xab, 0x8e, 0xfb, 0x2a, - 0x6e, 0x21, 0xac, 0xe2, 0x73, 0xf8, 0xe7, 0x04, 0x0d, 0xaa, 0x0d, 0x79, 0x45, 0x37, 0x7b, 0x07, 0xe7, 0x53, 0x12, - 0xab, 0x06, 0x3f, 0x3a, 0x6b, 0xa1, 0x1f, 0xce, 0x4c, 0x47, 0xec, 0x50, 0xef, 0xe8, 0x4a, 0xe2, 0x93, 0xa6, 0x84, - 0x8e, 0x5a, 0x65, 0x3f, 0x22, 0x3e, 0x45, 0x58, 0xc4, 0xc7, 0xf0, 0x4f, 0x3b, 0xec, 0xe7, 0xd7, 0xad, 0x7e, 0xcc, - 0xbc, 0xdb, 0x38, 0x39, 0xb5, 0xbe, 0xac, 0xca, 0x5e, 0x2c, 0x37, 0xd8, 0x65, 0xdb, 0xdc, 0x88, 0xb5, 0x8f, 0xe0, - 0x03, 0x61, 0x7d, 0x48, 0x14, 0x66, 0x87, 0xe0, 0x04, 0x0b, 0xb6, 0x1f, 0xea, 0xe2, 0xb8, 0xab, 0x1a, 0x0d, 0x24, - 0xfa, 0x6a, 0x70, 0x48, 0xda, 0x4d, 0xdd, 0x64, 0x18, 0x7e, 0x37, 0x48, 0x19, 0x59, 0x4d, 0x54, 0xbd, 0x3e, 0x76, - 0xbd, 0xda, 0xeb, 0x73, 0x8f, 0x1d, 0x84, 0x10, 0xd5, 0x8b, 0x75, 0x93, 0xa1, 0x23, 0xd1, 0x88, 0xf5, 0x05, 0xeb, - 0x9d, 0xa5, 0x2d, 0x64, 0xb0, 0x53, 0xf5, 0x62, 0xd6, 0xe4, 0x90, 0xde, 0x49, 0x63, 0xde, 0xd4, 0xf0, 0xeb, 0x24, - 0x98, 0x85, 0x00, 0xbc, 0xab, 0x5c, 0x7a, 0x8a, 0xa3, 0xce, 0xe9, 0x29, 0x16, 0x84, 0x27, 0x13, 0xf3, 0x4b, 0x11, - 0x9e, 0x0c, 0xcd, 0x2f, 0x49, 0x4a, 0x78, 0xd9, 0xde, 0x71, 0x41, 0x82, 0x55, 0x35, 0x29, 0x14, 0x16, 0xb4, 0x40, - 0x47, 0x1d, 0x7f, 0xb7, 0x8e, 0xa7, 0x7e, 0x0e, 0xa0, 0x4b, 0x28, 0x8c, 0x59, 0xa5, 0x6c, 0x16, 0x38, 0x27, 0xf4, - 0x32, 0x39, 0xed, 0x4d, 0x8f, 0xe2, 0x4e, 0x53, 0x36, 0x0b, 0x94, 0x4e, 0x8f, 0x4c, 0x4d, 0x9c, 0x91, 0xc7, 0xd4, - 0xb6, 0x86, 0xa7, 0x70, 0x21, 0x9a, 0x91, 0xec, 0xf0, 0xac, 0xd5, 0x48, 0x4e, 0x11, 0xee, 0x67, 0xab, 0x16, 0xce, - 0x57, 0xab, 0x16, 0xa6, 0xc1, 0x32, 0x3c, 0x16, 0x1e, 0x20, 0xa5, 0xba, 0x6b, 0x33, 0xc0, 0x4d, 0x8f, 0xc7, 0x1a, - 0x2e, 0xf7, 0x35, 0xb8, 0xcc, 0x68, 0x70, 0xe6, 0x49, 0xb9, 0xbb, 0x55, 0x43, 0x26, 0xc4, 0xdf, 0x38, 0x54, 0x80, - 0xbd, 0x16, 0x7e, 0x5d, 0xbd, 0x79, 0xa6, 0x88, 0x7f, 0x97, 0xd8, 0xa6, 0x05, 0xc5, 0xe8, 0x76, 0xb1, 0x5f, 0xe9, - 0x56, 0xb1, 0x37, 0x3b, 0x8a, 0x5d, 0x6d, 0x17, 0xfb, 0x28, 0x03, 0x75, 0x1d, 0xff, 0xe1, 0xf8, 0xac, 0xd5, 0x38, - 0x06, 0x64, 0x3d, 0x3e, 0x6b, 0x55, 0x85, 0xee, 0xd1, 0x6a, 0xad, 0x34, 0xf9, 0x4c, 0xad, 0xc3, 0x02, 0xf7, 0x9e, - 0xd3, 0x66, 0xe1, 0xac, 0xdf, 0x76, 0xe9, 0xa4, 0xdd, 0x3f, 0x05, 0x83, 0x10, 0x61, 0xa8, 0x9d, 0xee, 0x9f, 0x0d, - 0x7a, 0x53, 0x16, 0x37, 0x20, 0x15, 0xa5, 0x63, 0xed, 0x7e, 0xa1, 0xf2, 0x5e, 0xf8, 0xa3, 0x84, 0xa4, 0xce, 0x00, - 0x61, 0x49, 0x1a, 0xba, 0x7f, 0x3c, 0x30, 0xe7, 0x5d, 0x01, 0xbf, 0x4f, 0xcc, 0xef, 0x52, 0x2b, 0xe3, 0xbc, 0x1a, - 0xa6, 0x37, 0xc3, 0xa8, 0x27, 0xc8, 0x6b, 0x1a, 0x1b, 0x43, 0x75, 0x94, 0x96, 0x19, 0xea, 0x0b, 0x64, 0xbc, 0x29, - 0x33, 0x04, 0x79, 0x2d, 0xdc, 0x6f, 0xbc, 0x2c, 0x52, 0x30, 0x5a, 0xc1, 0x93, 0x14, 0x0c, 0x56, 0xf0, 0x30, 0x15, - 0xe0, 0x54, 0x41, 0x53, 0x16, 0x98, 0xc2, 0x3f, 0x74, 0x6a, 0x30, 0x73, 0x75, 0x4b, 0x0c, 0x96, 0x76, 0x19, 0x9c, - 0x14, 0x1f, 0x65, 0x0c, 0x7f, 0x1b, 0x1a, 0x61, 0x06, 0x6d, 0x32, 0x84, 0x79, 0x52, 0x10, 0x48, 0xc3, 0x3c, 0x99, - 0x10, 0x06, 0x4d, 0xf2, 0x64, 0x48, 0x58, 0xbf, 0x13, 0xa0, 0xc9, 0x53, 0x03, 0x3b, 0x00, 0x0e, 0xaf, 0xdf, 0x86, - 0x6b, 0xdb, 0x38, 0x5c, 0xb3, 0x43, 0x13, 0x82, 0x70, 0x15, 0xc3, 0x2c, 0x60, 0x73, 0x9a, 0x9f, 0x9d, 0x2a, 0x86, - 0x24, 0x4f, 0xa8, 0xa1, 0xde, 0x7f, 0x01, 0x59, 0x8d, 0xef, 0x2d, 0xd9, 0x1a, 0xef, 0xdd, 0x5b, 0x8a, 0xf5, 0x0f, - 0xf0, 0x47, 0xb9, 0x3f, 0xda, 0x9c, 0x7e, 0x6b, 0xf4, 0x57, 0x0a, 0xc5, 0x76, 0x94, 0x42, 0x7f, 0x79, 0x9f, 0x3a, - 0x45, 0x96, 0xb7, 0x69, 0x34, 0xa2, 0xc5, 0xe7, 0x08, 0x7f, 0x4a, 0xa3, 0x1c, 0x18, 0xc1, 0x08, 0x7f, 0x4c, 0xa3, - 0x82, 0x45, 0xf8, 0x8f, 0x34, 0x1a, 0xe6, 0x8b, 0x08, 0x7f, 0x48, 0xa3, 0x49, 0x11, 0xe1, 0xf7, 0xa0, 0xf1, 0x1c, - 0xf1, 0xc5, 0x2c, 0xc2, 0xbf, 0xa7, 0x91, 0x32, 0x2e, 0x05, 0xf8, 0x61, 0x1a, 0x31, 0x16, 0xe1, 0x77, 0x69, 0x24, - 0xf3, 0x08, 0x5f, 0xa5, 0x91, 0x2c, 0x22, 0xfc, 0x28, 0x8d, 0x0a, 0x1a, 0xe1, 0xc7, 0x69, 0x04, 0x85, 0x26, 0x11, - 0x7e, 0x92, 0x46, 0xd0, 0xb2, 0x8a, 0xf0, 0xdb, 0x34, 0xe2, 0x22, 0xc2, 0xbf, 0xa5, 0x91, 0x5e, 0x14, 0xff, 0x2c, - 0x24, 0x57, 0x11, 0x7e, 0x9a, 0x46, 0x53, 0x1e, 0xe1, 0x37, 0x69, 0x54, 0xc8, 0x08, 0xbf, 0x4e, 0x23, 0x9a, 0x47, - 0xf8, 0x55, 0x1a, 0xe5, 0x2c, 0xc2, 0xbf, 0xa6, 0xd1, 0x88, 0x45, 0xf8, 0x65, 0x1a, 0xdd, 0xb1, 0x3c, 0x97, 0x11, - 0x7e, 0x96, 0x46, 0x4c, 0x44, 0xf8, 0x97, 0x34, 0xca, 0xa6, 0x11, 0xfe, 0x29, 0x8d, 0x68, 0xf1, 0x59, 0x45, 0xf8, - 0x79, 0x1a, 0x31, 0x1a, 0xe1, 0x17, 0xb6, 0xa3, 0x49, 0x84, 0x7f, 0x4e, 0xa3, 0x9b, 0x69, 0xb4, 0xc6, 0x4a, 0x91, - 0xe5, 0x6b, 0x9e, 0xb1, 0x3f, 0x58, 0x1a, 0x8d, 0x5b, 0xe3, 0xf3, 0xf1, 0x38, 0xc2, 0x54, 0x68, 0xfe, 0xcf, 0x82, - 0xdd, 0x3c, 0xd5, 0x90, 0x48, 0xd9, 0x70, 0x74, 0x3f, 0xc2, 0xf4, 0x9f, 0x05, 0x4d, 0xa3, 0xf1, 0xd8, 0x14, 0xf8, - 0x67, 0x41, 0x67, 0xb4, 0x78, 0xcb, 0xd2, 0xe8, 0xfe, 0x78, 0x3c, 0x1e, 0x9d, 0x44, 0x98, 0x7e, 0x5d, 0x7c, 0x34, - 0x2d, 0x98, 0x02, 0x43, 0xc6, 0x27, 0x50, 0xf7, 0x74, 0x7c, 0x3a, 0xca, 0x22, 0x3c, 0xe4, 0xea, 0x9f, 0x05, 0x7c, - 0x8f, 0xd9, 0x49, 0x76, 0x12, 0xe1, 0x61, 0x4e, 0xb3, 0xcf, 0x69, 0xd4, 0x32, 0xbf, 0xc4, 0x2f, 0x6c, 0xf4, 0x7a, - 0x26, 0xcd, 0x7d, 0xc0, 0x98, 0x0d, 0xb3, 0x51, 0x84, 0xcd, 0x60, 0xc6, 0xf0, 0xf7, 0x0b, 0x7f, 0xc7, 0x74, 0x1a, - 0x9d, 0xd3, 0xce, 0x90, 0x75, 0x22, 0x3c, 0x7c, 0x73, 0x23, 0xd2, 0x88, 0x9e, 0x76, 0x68, 0x87, 0x46, 0x78, 0xb8, - 0x28, 0xf2, 0xbb, 0x1b, 0x29, 0x47, 0x00, 0x84, 0xe1, 0xf9, 0xf9, 0xfd, 0x08, 0x67, 0xf4, 0x57, 0x0d, 0xb5, 0x4f, - 0xc7, 0x0f, 0x18, 0x6d, 0x45, 0xf8, 0x17, 0x5a, 0xe8, 0x8f, 0x0b, 0xe5, 0x06, 0xda, 0x82, 0x14, 0x99, 0xbd, 0x03, - 0x5d, 0x79, 0x34, 0xea, 0x9c, 0x3d, 0x68, 0xb3, 0x08, 0x67, 0x57, 0xaf, 0xa1, 0xb7, 0xfb, 0xe3, 0xd3, 0x16, 0x7c, - 0x08, 0x10, 0x3a, 0x59, 0x01, 0x8d, 0x9c, 0x9d, 0x3c, 0x38, 0x65, 0x23, 0x93, 0xa8, 0x78, 0xfe, 0xd9, 0xcc, 0xfe, - 0x1c, 0xe6, 0x93, 0x15, 0x7c, 0xa6, 0xa4, 0x48, 0xa3, 0x51, 0xd6, 0x3e, 0x39, 0x86, 0x84, 0x3b, 0x2a, 0x3c, 0x70, - 0x6e, 0xa1, 0xea, 0xf9, 0x30, 0xc2, 0xb7, 0x36, 0xf5, 0x7c, 0x68, 0x3e, 0x26, 0xef, 0x7e, 0x15, 0x6f, 0x46, 0x69, - 0x34, 0x3c, 0x3f, 0x3f, 0x6b, 0x41, 0xc2, 0x07, 0x7a, 0x97, 0x46, 0xf4, 0x01, 0xfc, 0x07, 0xd9, 0x1f, 0x9f, 0x41, - 0x87, 0x30, 0xc2, 0xdb, 0xc9, 0xc7, 0x30, 0xe7, 0xf3, 0x94, 0x7e, 0xe6, 0x69, 0x34, 0x1c, 0x0d, 0xef, 0x9f, 0x41, - 0xbd, 0x19, 0x9d, 0x3c, 0xd3, 0x14, 0xda, 0x6d, 0xb5, 0x4c, 0xcb, 0xef, 0xf8, 0x17, 0x66, 0xaa, 0x9f, 0x9e, 0x9e, - 0x0d, 0x3b, 0x30, 0x82, 0x2b, 0xd0, 0x96, 0xc0, 0x78, 0xce, 0x33, 0xd3, 0xe0, 0x55, 0xf6, 0x74, 0x94, 0x46, 0x0f, - 0x1e, 0x1c, 0x77, 0xb2, 0x2c, 0xc2, 0xb7, 0x1f, 0x47, 0xb6, 0xb6, 0xc9, 0x53, 0x00, 0xfb, 0x34, 0x62, 0x0f, 0x1e, - 0x9c, 0xdd, 0xa7, 0xf0, 0xfd, 0xdc, 0xb4, 0x75, 0x3e, 0x1e, 0x66, 0xe7, 0xd0, 0xd6, 0xef, 0x30, 0x9d, 0x93, 0xf3, - 0xe3, 0x91, 0xe9, 0xeb, 0x77, 0x33, 0xea, 0xce, 0xf8, 0x64, 0x7c, 0x62, 0x32, 0xcd, 0x50, 0xcb, 0xcf, 0xdf, 0x58, - 0x1a, 0x65, 0x6c, 0xd4, 0x8e, 0xf0, 0xad, 0x5b, 0xb8, 0x07, 0x27, 0xad, 0xd6, 0xe8, 0x38, 0xc2, 0xa3, 0x87, 0xf3, - 0xf9, 0x5b, 0x03, 0xc1, 0xf6, 0xc9, 0x03, 0xfb, 0xad, 0x3e, 0xdf, 0x41, 0xd3, 0x43, 0x03, 0xb4, 0x11, 0x9f, 0x99, - 0x96, 0xcf, 0x1e, 0xc0, 0x7f, 0xe6, 0xdb, 0x34, 0x5d, 0x7e, 0xcb, 0xd1, 0xc4, 0x2e, 0x4a, 0x9b, 0x3d, 0x68, 0x41, - 0x8d, 0x31, 0xff, 0x38, 0x2c, 0x38, 0xa0, 0xd1, 0xb0, 0x03, 0xff, 0x17, 0xe1, 0x71, 0x7e, 0xf5, 0xda, 0xe1, 0xec, - 0x78, 0x4c, 0xc7, 0xad, 0x08, 0x8f, 0xe5, 0x47, 0xa5, 0x3f, 0x3c, 0x14, 0x69, 0xd4, 0xe9, 0x9c, 0x0f, 0x4d, 0x99, - 0xc5, 0x2f, 0x8a, 0x1b, 0x3c, 0x6e, 0x99, 0x56, 0x26, 0xf4, 0xad, 0x1a, 0x5e, 0x49, 0x58, 0x49, 0xf8, 0x2f, 0xc2, - 0x13, 0x50, 0xb1, 0xb9, 0x56, 0xce, 0xed, 0x76, 0x98, 0xbc, 0x33, 0xa8, 0x39, 0xba, 0x0f, 0xf0, 0xf2, 0xcb, 0x38, - 0xa2, 0xf4, 0xb4, 0xd3, 0x8a, 0xb0, 0x19, 0xf5, 0x79, 0x0b, 0xfe, 0x8b, 0xb0, 0x85, 0x9c, 0x81, 0xeb, 0xe4, 0xe3, - 0xb3, 0x97, 0x37, 0x69, 0x44, 0x47, 0xe3, 0x31, 0x2c, 0x89, 0x99, 0x8c, 0x2f, 0x36, 0x95, 0x82, 0xdd, 0xfd, 0x7a, - 0xe3, 0xb6, 0x8b, 0x49, 0xd0, 0x0e, 0x3a, 0x67, 0x0f, 0x86, 0x27, 0x11, 0x7e, 0x3b, 0xe2, 0x54, 0xc0, 0x2a, 0x65, - 0xa3, 0xd3, 0xec, 0x34, 0x33, 0x09, 0x13, 0x99, 0x46, 0x27, 0xb0, 0xe4, 0x9d, 0x08, 0xf3, 0x2f, 0x57, 0x77, 0x16, - 0xdd, 0xa0, 0xb6, 0x43, 0x90, 0x71, 0x8b, 0x9d, 0x9d, 0x67, 0x11, 0xce, 0xe9, 0x97, 0x67, 0xbf, 0x16, 0x69, 0xc4, - 0xce, 0xd8, 0xd9, 0x98, 0xfa, 0xef, 0x3f, 0xd4, 0xd4, 0xd4, 0x68, 0x8d, 0x4f, 0x21, 0xe9, 0x46, 0x98, 0xb1, 0xde, - 0xcf, 0xc6, 0x06, 0x43, 0x5e, 0xcd, 0xa4, 0xc8, 0x9e, 0x8e, 0xc7, 0xd2, 0x62, 0x31, 0x85, 0x4d, 0xf8, 0x09, 0xa0, - 0x4d, 0x47, 0xa3, 0x73, 0x76, 0x16, 0xe1, 0x4f, 0x76, 0x97, 0xb8, 0x09, 0x7c, 0xb2, 0x98, 0xcd, 0xdc, 0x6e, 0xff, - 0x64, 0x81, 0x02, 0xf3, 0x1d, 0xd3, 0x31, 0x1d, 0x75, 0x22, 0xfc, 0xc9, 0xc0, 0x65, 0x74, 0x0c, 0xff, 0x41, 0x01, - 0xe8, 0xec, 0x41, 0x8b, 0xb1, 0x07, 0x2d, 0xf3, 0x15, 0xe6, 0xb9, 0x99, 0x0f, 0xcf, 0xb2, 0x76, 0x84, 0x3f, 0x39, - 0x74, 0x1c, 0x8f, 0x69, 0x0b, 0xd0, 0xf1, 0x93, 0x43, 0xc7, 0x4e, 0x6b, 0xd8, 0xa1, 0xe6, 0xdb, 0x62, 0xcd, 0xf9, - 0xfd, 0x8c, 0xc1, 0xe4, 0x3e, 0x59, 0x84, 0xbc, 0x7f, 0xff, 0xfc, 0xfc, 0xc1, 0x03, 0xf8, 0x34, 0x6d, 0x97, 0x9f, - 0x4a, 0x3f, 0xcc, 0x0d, 0x92, 0xb5, 0xb2, 0x13, 0xa0, 0x93, 0x9f, 0xcc, 0x18, 0xc7, 0xe3, 0x31, 0x6b, 0x45, 0x38, - 0xe7, 0x33, 0x66, 0x31, 0xc1, 0xfe, 0x36, 0x1d, 0x1d, 0x77, 0xb2, 0xd1, 0x71, 0x27, 0xc2, 0xf9, 0xdb, 0x67, 0x66, - 0x36, 0x2d, 0x98, 0xbd, 0xdf, 0x72, 0x1e, 0x6b, 0x66, 0xf4, 0x0d, 0x0c, 0x12, 0x56, 0x1a, 0x2a, 0xbf, 0x0f, 0xe8, - 0xe1, 0xd9, 0x59, 0x36, 0x82, 0x81, 0xbe, 0x87, 0x6e, 0x01, 0x8c, 0xef, 0xed, 0xe6, 0x1b, 0xd2, 0xd3, 0x53, 0x98, - 0xee, 0xfb, 0xf9, 0xa2, 0x98, 0xbf, 0x4a, 0xa3, 0x07, 0xc7, 0xf7, 0x5b, 0xa3, 0x61, 0x84, 0xdf, 0xbb, 0x09, 0x1e, - 0x67, 0xc3, 0xe3, 0xfb, 0xed, 0x08, 0xbf, 0x37, 0xfb, 0xed, 0xfe, 0xf0, 0xec, 0x1c, 0xce, 0x8d, 0xf7, 0x6a, 0x5e, - 0xbc, 0x9d, 0x98, 0x02, 0x63, 0xfa, 0x00, 0x9a, 0xfd, 0xcd, 0xec, 0xc6, 0x51, 0x1b, 0x36, 0xf2, 0x7b, 0xb3, 0xc9, - 0x0c, 0x9e, 0xdc, 0x6f, 0x9f, 0x9e, 0x9f, 0x46, 0x78, 0xc6, 0x47, 0x02, 0x08, 0xbc, 0xd9, 0x28, 0x0f, 0xda, 0x0f, - 0xee, 0xb7, 0x22, 0x3c, 0x7b, 0xab, 0xb3, 0x8f, 0x74, 0x66, 0xa8, 0xf1, 0x18, 0x60, 0x36, 0xe3, 0x4a, 0xdf, 0xbd, - 0x51, 0x8e, 0x1e, 0xb3, 0x76, 0x84, 0x67, 0x32, 0xcb, 0xa8, 0x7a, 0x6b, 0x13, 0x86, 0xa7, 0x11, 0x16, 0xf4, 0x0b, - 0xfd, 0x5b, 0xfa, 0xcd, 0x34, 0x62, 0x74, 0x64, 0xd2, 0x0c, 0x0e, 0x47, 0xf8, 0xdd, 0x08, 0x6e, 0xf4, 0xd2, 0x68, - 0x3c, 0x1a, 0x9f, 0x02, 0x78, 0x80, 0x00, 0x59, 0xec, 0x06, 0x68, 0xc0, 0xd7, 0xe8, 0xd1, 0x30, 0x8d, 0xce, 0x86, - 0xe7, 0xac, 0x73, 0x1c, 0xe1, 0x92, 0x1a, 0xd1, 0x53, 0xc8, 0x37, 0x9f, 0x1f, 0xcd, 0x96, 0x3a, 0xb1, 0x09, 0x06, - 0x40, 0x23, 0x7a, 0xbf, 0x35, 0x3a, 0x8b, 0xf0, 0xfc, 0x35, 0xf3, 0x7b, 0x8c, 0x31, 0x76, 0x0e, 0xb0, 0x84, 0x24, - 0x83, 0x40, 0xe7, 0xe3, 0xe1, 0x83, 0x73, 0xf3, 0x0d, 0x60, 0xa0, 0x63, 0xc6, 0x00, 0x48, 0xf3, 0xd7, 0xac, 0x04, - 0xc4, 0x68, 0x78, 0xbf, 0x05, 0xf4, 0x65, 0x4e, 0xe7, 0xf4, 0x8e, 0xde, 0x3c, 0x9d, 0x9b, 0x39, 0x8d, 0x47, 0xa7, - 0x11, 0x9e, 0x3f, 0xff, 0x65, 0xbe, 0x18, 0x8f, 0xcd, 0x84, 0xe8, 0xf0, 0x41, 0x84, 0xe7, 0xac, 0x58, 0xc0, 0x1a, - 0x9d, 0x9f, 0x1e, 0x8f, 0x23, 0xec, 0xd0, 0x30, 0x6b, 0x65, 0x43, 0xb8, 0xb2, 0x5c, 0xcc, 0xd2, 0x68, 0x34, 0xa2, - 0xad, 0x11, 0x5c, 0x60, 0xca, 0x9b, 0x5f, 0x0b, 0x8b, 0x46, 0xcc, 0xe0, 0x83, 0x5b, 0x43, 0x98, 0x2f, 0xc0, 0xe3, - 0xe3, 0x90, 0x65, 0x19, 0x75, 0x89, 0x67, 0x67, 0xc7, 0xc7, 0x80, 0x7b, 0x76, 0x86, 0x16, 0x41, 0xde, 0xa8, 0xbb, - 0x61, 0x21, 0xe1, 0xe8, 0x02, 0xa2, 0x0a, 0x64, 0xf5, 0xcd, 0xdd, 0x6b, 0x43, 0x57, 0xdb, 0x67, 0x0f, 0x60, 0x01, - 0x14, 0x1d, 0x8d, 0x5e, 0xd9, 0xc3, 0xed, 0x7c, 0x78, 0x72, 0xda, 0x3e, 0x8e, 0xb0, 0xdf, 0x08, 0xf4, 0xbc, 0x75, - 0xbf, 0x03, 0x25, 0xc4, 0xe8, 0xce, 0x96, 0x18, 0x9f, 0xd0, 0x93, 0xb3, 0x56, 0x84, 0xfd, 0xd6, 0x60, 0xe7, 0xc3, - 0xd3, 0xfb, 0xf0, 0xa9, 0xa6, 0x2c, 0xcf, 0x0d, 0x7e, 0x9f, 0x02, 0x5c, 0x14, 0x7f, 0x26, 0x68, 0x1a, 0xd1, 0xd6, - 0x69, 0xa7, 0x33, 0x82, 0xcf, 0xfc, 0x0b, 0x2b, 0xd2, 0x28, 0x6b, 0xc1, 0x7f, 0x11, 0x0e, 0x76, 0x12, 0x1b, 0x46, - 0xd8, 0xe0, 0xdd, 0x19, 0x3d, 0x35, 0x7b, 0xdf, 0xed, 0xaa, 0xd6, 0x79, 0x0b, 0x36, 0xac, 0xdb, 0x54, 0xee, 0x4b, - 0x09, 0x79, 0xe3, 0x48, 0x2c, 0x8d, 0x70, 0x80, 0xa0, 0xe3, 0xfb, 0xe3, 0x08, 0xfb, 0x1d, 0x77, 0x72, 0x76, 0xde, - 0x01, 0x52, 0xa6, 0x81, 0x50, 0x8c, 0x3a, 0xc3, 0x13, 0x20, 0x4d, 0x9a, 0xbd, 0xb6, 0x78, 0x12, 0x61, 0xfd, 0x54, - 0xe9, 0x57, 0x69, 0x34, 0x3a, 0x1f, 0x8e, 0x47, 0xe7, 0x11, 0xd6, 0x72, 0x46, 0xb5, 0x34, 0x14, 0xf0, 0xf8, 0xe4, - 0x7e, 0x84, 0x0d, 0x9a, 0xb7, 0x58, 0x6b, 0xd4, 0x8a, 0xb0, 0x3b, 0x4a, 0x18, 0x3b, 0xef, 0xc0, 0xb4, 0x7e, 0x7e, - 0xae, 0x01, 0x97, 0x47, 0x6c, 0x78, 0x1c, 0xe1, 0x92, 0xde, 0x1b, 0x42, 0x04, 0x5f, 0x6a, 0x26, 0x3f, 0x3b, 0xd6, - 0x03, 0x48, 0x9d, 0xdf, 0xf0, 0xb0, 0x0c, 0x2f, 0x6f, 0x2c, 0x1a, 0x51, 0xb3, 0xc5, 0x83, 0x2b, 0xdd, 0x27, 0x34, - 0xf6, 0x6c, 0x3b, 0x27, 0xcb, 0x35, 0x2e, 0x23, 0xa5, 0x7e, 0x66, 0x77, 0x2a, 0x56, 0xca, 0x70, 0xb2, 0x41, 0x0a, - 0x78, 0x33, 0x38, 0xdf, 0x00, 0xe7, 0xfe, 0x09, 0x82, 0xa4, 0x20, 0xad, 0xae, 0xb8, 0xf0, 0x2e, 0xa9, 0x5d, 0x01, - 0xf1, 0x13, 0x20, 0xbd, 0x20, 0x94, 0x68, 0x08, 0x33, 0x63, 0x85, 0x49, 0x6f, 0xa9, 0x6f, 0x64, 0x4a, 0x69, 0x6d, - 0xff, 0x29, 0xa1, 0x3e, 0xc0, 0x3c, 0xdc, 0x37, 0x43, 0x08, 0x26, 0xd4, 0x95, 0xc4, 0x84, 0x8b, 0x7e, 0x21, 0x74, - 0xac, 0x54, 0xbf, 0x18, 0xe0, 0xf6, 0x19, 0xc2, 0x10, 0x88, 0x81, 0xf4, 0xe5, 0xe5, 0x65, 0xfb, 0xec, 0xc0, 0x08, - 0x7d, 0x97, 0x97, 0xe7, 0xf6, 0x07, 0xfc, 0x3b, 0xa8, 0x82, 0x5f, 0xc3, 0xf8, 0x1e, 0xb1, 0x40, 0xa3, 0x67, 0xf8, - 0xeb, 0x47, 0x6c, 0xb5, 0x8a, 0x1f, 0x31, 0x02, 0x33, 0xc6, 0x8f, 0x58, 0x62, 0x2e, 0x40, 0xac, 0x9b, 0x0d, 0xe9, - 0x83, 0xe6, 0xac, 0x85, 0x21, 0x24, 0xbb, 0xe7, 0xbc, 0x1f, 0xb1, 0x3e, 0xaf, 0xbb, 0x68, 0x57, 0x71, 0x90, 0x0f, - 0x0e, 0x96, 0x45, 0xaa, 0xad, 0x98, 0xa0, 0xad, 0x98, 0xa0, 0xad, 0x98, 0xa0, 0xab, 0x48, 0xf4, 0x27, 0x3d, 0x90, - 0x52, 0x8c, 0xb2, 0xc5, 0xf1, 0xd4, 0xef, 0x40, 0xed, 0x01, 0xda, 0xc9, 0x5e, 0xa5, 0xec, 0x28, 0x75, 0x15, 0x3b, - 0x15, 0x18, 0x3b, 0x13, 0x9d, 0xb6, 0xe3, 0xe8, 0xdf, 0x51, 0x77, 0xbc, 0xac, 0x89, 0x65, 0xef, 0x76, 0x8a, 0x65, - 0xb0, 0x92, 0x46, 0x34, 0xdb, 0xb7, 0x41, 0x3d, 0x74, 0xff, 0xbe, 0x11, 0xcc, 0xaa, 0x48, 0x73, 0x0d, 0x48, 0xea, - 0x82, 0x14, 0x72, 0x6e, 0xa4, 0xb4, 0x02, 0xa5, 0x23, 0x1d, 0x17, 0xa0, 0xa1, 0xf4, 0x0a, 0xca, 0x32, 0x20, 0x6a, - 0xc3, 0x00, 0x44, 0x59, 0x19, 0xcd, 0xca, 0x6a, 0xa7, 0x20, 0xba, 0x80, 0x26, 0xcc, 0x48, 0x2c, 0xd0, 0x80, 0x30, - 0x0d, 0x08, 0x57, 0x19, 0xc4, 0x19, 0x97, 0x7d, 0x62, 0xb2, 0x95, 0xc9, 0x56, 0x65, 0xb6, 0xf4, 0xd9, 0x56, 0x48, - 0x94, 0x26, 0x5b, 0x96, 0xd9, 0x20, 0xb3, 0xe1, 0x49, 0xaa, 0xf0, 0x30, 0x95, 0x56, 0x54, 0xab, 0x64, 0xab, 0xb7, - 0x34, 0xd4, 0xe6, 0x1e, 0x1c, 0xc4, 0xa5, 0x9c, 0x64, 0xd4, 0xc4, 0xf7, 0x96, 0x3c, 0x29, 0x8c, 0x0c, 0xc4, 0x93, - 0x89, 0xfb, 0x3b, 0x5c, 0x6f, 0xca, 0x4a, 0xc5, 0x64, 0xf8, 0x8d, 0x92, 0xe8, 0x2f, 0xaf, 0x44, 0x7d, 0xc4, 0x4d, - 0x28, 0x9d, 0x0b, 0x92, 0xb4, 0x5a, 0xc7, 0xed, 0xe3, 0xd6, 0x79, 0x8f, 0x1f, 0xb6, 0x3b, 0xc9, 0x83, 0x4e, 0x6a, - 0x14, 0x11, 0x73, 0x79, 0x03, 0x0a, 0x98, 0xa3, 0x4e, 0x72, 0x82, 0x0e, 0xdb, 0x49, 0xeb, 0xf4, 0xb4, 0x09, 0xff, - 0xe0, 0xf7, 0xba, 0xac, 0x76, 0xd2, 0x3a, 0x39, 0xed, 0xf1, 0xa3, 0x8d, 0x4a, 0x31, 0x6f, 0x40, 0x41, 0x74, 0x64, - 0x2a, 0x61, 0xa8, 0x5f, 0x2d, 0xef, 0xb3, 0x2d, 0x3d, 0xcf, 0x7b, 0x1d, 0x2b, 0xab, 0x8a, 0x03, 0xa8, 0xfa, 0xaf, - 0x89, 0x01, 0xa2, 0xff, 0x1a, 0x96, 0xe1, 0x6e, 0x97, 0x05, 0x88, 0xda, 0x8f, 0x78, 0x2c, 0x1a, 0xec, 0x30, 0xb6, - 0xf9, 0x1a, 0xea, 0x36, 0x21, 0x04, 0x1d, 0x9e, 0xb8, 0x5c, 0x15, 0xe6, 0x4e, 0x10, 0x6a, 0x2a, 0xc8, 0x1d, 0xba, - 0x5c, 0x19, 0xe6, 0x0e, 0x11, 0x6a, 0x4a, 0xc8, 0xa5, 0x29, 0x4f, 0x28, 0xe4, 0xe8, 0x84, 0x36, 0x0d, 0x24, 0xab, - 0x45, 0x79, 0xce, 0xfc, 0xb0, 0xf9, 0x18, 0x96, 0xc7, 0x10, 0x14, 0x27, 0x48, 0x0b, 0x78, 0xa6, 0xa4, 0xd4, 0xe6, - 0xb4, 0x70, 0xa9, 0xc6, 0x81, 0x8c, 0x06, 0xfc, 0x73, 0xc8, 0xcc, 0xdb, 0x15, 0xad, 0xde, 0xf1, 0x59, 0x2b, 0x6d, - 0x83, 0xbf, 0x35, 0xc8, 0xda, 0xc2, 0xca, 0xda, 0xc2, 0xcb, 0xda, 0xc2, 0xcb, 0xda, 0x20, 0xc0, 0x07, 0x7d, 0xff, - 0x23, 0x6b, 0x36, 0x2c, 0xbc, 0x34, 0x88, 0xb1, 0x16, 0x0f, 0xb1, 0x5e, 0xad, 0x96, 0x6b, 0x30, 0x57, 0x2a, 0x6b, - 0x48, 0x55, 0xa9, 0x3f, 0x97, 0x45, 0xda, 0xc2, 0x93, 0x14, 0xb4, 0xdc, 0x2d, 0x4c, 0xcd, 0xe6, 0xf6, 0x54, 0x61, - 0x33, 0x14, 0x4e, 0xcf, 0xab, 0x93, 0x2f, 0xc9, 0xb1, 0xd1, 0x1e, 0x2f, 0x8b, 0x94, 0x5b, 0x9a, 0xc1, 0x2d, 0xcd, - 0xe0, 0x96, 0x66, 0x40, 0x23, 0xb8, 0x2c, 0x6c, 0xca, 0x26, 0x94, 0xc0, 0x95, 0x40, 0xff, 0x78, 0x00, 0x91, 0x00, - 0x63, 0x4d, 0xcc, 0xa8, 0x37, 0x3a, 0x6f, 0x43, 0xe4, 0x33, 0x5b, 0x52, 0x27, 0xd4, 0x38, 0x80, 0x97, 0x63, 0xfe, - 0x5a, 0x43, 0xfb, 0x04, 0x9e, 0xa5, 0x79, 0xa8, 0xe3, 0x16, 0xd8, 0x7f, 0x44, 0x45, 0xd4, 0x33, 0x64, 0x21, 0x35, - 0x3a, 0x1b, 0x67, 0xd7, 0xfd, 0x79, 0xc3, 0x9d, 0xd6, 0x52, 0x82, 0xf0, 0x31, 0x86, 0xcf, 0xac, 0xf2, 0xef, 0x2f, - 0xcd, 0x56, 0x9d, 0xcd, 0x99, 0x3d, 0x12, 0xba, 0x60, 0x7b, 0xee, 0x03, 0x47, 0xf5, 0x04, 0x91, 0xca, 0x78, 0x3e, - 0x92, 0x2a, 0xf4, 0x31, 0x78, 0x02, 0x93, 0x5b, 0x6a, 0xfc, 0x62, 0x5e, 0xd8, 0x3f, 0x5f, 0x69, 0xe0, 0x38, 0x58, - 0x4c, 0x86, 0xde, 0xdf, 0xf6, 0xda, 0x04, 0x08, 0x22, 0xfb, 0xfb, 0xd6, 0x2c, 0xdc, 0x7c, 0x6d, 0xda, 0x85, 0x9b, - 0x44, 0x93, 0x0d, 0x3b, 0xd4, 0xaf, 0xd1, 0x3f, 0xde, 0xed, 0xad, 0x98, 0x0c, 0x51, 0x40, 0xb3, 0x0d, 0x58, 0x55, - 0x05, 0x2c, 0xe5, 0xea, 0x95, 0xde, 0x90, 0xd0, 0xbb, 0x19, 0xf3, 0xba, 0x98, 0x0c, 0x77, 0xbe, 0x5f, 0x62, 0x7b, - 0xec, 0xbd, 0xa5, 0x41, 0x0f, 0x5e, 0xb5, 0x3d, 0x65, 0xb7, 0xdf, 0xab, 0x73, 0xb3, 0xb3, 0x8e, 0xca, 0xbf, 0x57, - 0xe7, 0xe9, 0xae, 0x3a, 0x33, 0x7e, 0x1b, 0xfb, 0xbd, 0xa3, 0x03, 0x35, 0xb6, 0xb1, 0x35, 0x9a, 0x0c, 0x21, 0xe0, - 0x3c, 0xfc, 0xb5, 0x61, 0x61, 0xba, 0x9e, 0x84, 0xc3, 0x2a, 0xc8, 0x5e, 0x72, 0x9a, 0x32, 0x4c, 0x49, 0xe7, 0xb0, - 0x30, 0x81, 0x61, 0x44, 0x42, 0x9b, 0x2a, 0xa1, 0x38, 0x27, 0x71, 0x4c, 0x0f, 0x33, 0x08, 0x6f, 0xd3, 0xee, 0xd1, - 0x34, 0xa6, 0x8d, 0x0c, 0x1d, 0xc5, 0xed, 0x06, 0x3d, 0xcc, 0x10, 0x6a, 0xb4, 0x41, 0x67, 0x2a, 0x49, 0xbb, 0x99, - 0x43, 0xc0, 0x4b, 0x43, 0x8a, 0xf3, 0x43, 0x91, 0x14, 0x0d, 0x79, 0xa8, 0x92, 0xa2, 0x91, 0x9c, 0x62, 0x91, 0x4c, - 0xca, 0xe4, 0x89, 0x49, 0x9e, 0xd8, 0xe4, 0x61, 0x99, 0x3c, 0x34, 0xc9, 0x43, 0x9b, 0x4c, 0x49, 0x71, 0x28, 0x12, - 0xda, 0x88, 0xdb, 0xcd, 0x02, 0x1d, 0xc2, 0x08, 0xfc, 0xe8, 0x89, 0x08, 0xe3, 0x8c, 0xaf, 0x8d, 0xa1, 0xce, 0x5c, - 0xe6, 0x2e, 0xf2, 0x67, 0x05, 0xa4, 0xd2, 0x7b, 0x0a, 0xea, 0x3c, 0x0b, 0xc0, 0x84, 0xb5, 0xfd, 0xe3, 0xe3, 0xda, - 0xad, 0xb3, 0x5c, 0x8a, 0xc0, 0x3b, 0x0c, 0x0c, 0xda, 0x3f, 0x3b, 0x9f, 0x18, 0x80, 0xea, 0x9a, 0xe6, 0xf3, 0x29, - 0xdd, 0x72, 0xc1, 0x2d, 0x26, 0x43, 0xb7, 0xb3, 0xca, 0x66, 0x18, 0x2d, 0x6c, 0xbc, 0xe8, 0xba, 0xb3, 0x24, 0x80, - 0xda, 0x3b, 0x68, 0x26, 0xd4, 0x28, 0xc9, 0x6d, 0x8d, 0x49, 0xc1, 0xee, 0x54, 0x46, 0x73, 0x16, 0x57, 0x07, 0x70, - 0x35, 0x4c, 0x46, 0x5e, 0x80, 0x59, 0x7d, 0x71, 0x98, 0x1c, 0x37, 0x74, 0x32, 0x39, 0x4c, 0x4e, 0x1f, 0x34, 0x74, - 0x32, 0x3c, 0x4c, 0xda, 0xed, 0x0a, 0x67, 0x93, 0x82, 0xe8, 0x64, 0x42, 0x34, 0x68, 0x0c, 0x6d, 0xa3, 0x72, 0x4e, - 0xc1, 0x4e, 0xec, 0xdf, 0x18, 0x46, 0xc3, 0x0d, 0x43, 0xb0, 0x89, 0x0d, 0x9d, 0xb9, 0x35, 0x86, 0xb0, 0x9b, 0xce, - 0xe9, 0x69, 0x53, 0x27, 0x05, 0xd6, 0x76, 0x25, 0x9b, 0x3a, 0x99, 0x60, 0x6d, 0x97, 0xaf, 0xa9, 0x93, 0xa1, 0x6d, - 0xca, 0xe8, 0x00, 0x99, 0x08, 0x80, 0xf5, 0x9c, 0x05, 0x90, 0xef, 0x78, 0x4f, 0x97, 0x35, 0x68, 0x0d, 0xbf, 0x57, - 0xae, 0xe9, 0x0b, 0x2a, 0xaa, 0xc1, 0x5e, 0x88, 0x7d, 0xab, 0x68, 0xbb, 0x6a, 0x92, 0xfd, 0xeb, 0xb2, 0x65, 0xb3, - 0x85, 0xd4, 0xf5, 0x82, 0x0f, 0x6b, 0x18, 0xe2, 0x4a, 0xb9, 0x83, 0xfb, 0x15, 0x25, 0x31, 0x04, 0xc8, 0x33, 0xa7, - 0x10, 0x27, 0x5e, 0x8f, 0x0c, 0x49, 0xbc, 0xd1, 0x58, 0xa3, 0x38, 0x38, 0x6f, 0x9f, 0x86, 0x54, 0x75, 0x2b, 0x6a, - 0x1e, 0x21, 0xd1, 0x42, 0x58, 0xbb, 0xca, 0x51, 0x14, 0xb0, 0x20, 0x4e, 0xbb, 0x5b, 0x3b, 0x20, 0x0e, 0x0e, 0x36, - 0xcf, 0x0b, 0xff, 0x7e, 0xc1, 0xd6, 0x9b, 0x05, 0x95, 0x51, 0x9e, 0x7f, 0x55, 0xc9, 0x9a, 0xeb, 0xf2, 0x00, 0x51, - 0x7c, 0xfc, 0xaa, 0xfb, 0x86, 0xc2, 0xf7, 0xab, 0xe0, 0x7d, 0x2e, 0xa7, 0x79, 0x66, 0x32, 0x4c, 0x5f, 0x83, 0x60, - 0x6c, 0x6f, 0xc2, 0x09, 0x95, 0x06, 0x87, 0xff, 0xb2, 0xe3, 0xa0, 0x13, 0xf7, 0xea, 0x4b, 0xd8, 0xe8, 0xdf, 0xa1, - 0x79, 0x6f, 0x05, 0x1b, 0xe7, 0xd8, 0xbd, 0x5a, 0xd5, 0xde, 0xf8, 0xb1, 0x2f, 0xc9, 0xa0, 0x83, 0x03, 0xae, 0x9e, - 0x81, 0x45, 0x32, 0x8b, 0x1b, 0xe1, 0xe1, 0xfb, 0x4f, 0xed, 0xb4, 0xfe, 0xdb, 0x9c, 0xab, 0x69, 0x70, 0xd0, 0x3d, - 0xac, 0xe5, 0xef, 0x5c, 0x89, 0x9e, 0x4e, 0xb9, 0x5b, 0xeb, 0xbf, 0x2b, 0x7b, 0xef, 0xad, 0xd7, 0xa6, 0x0e, 0x0e, - 0x78, 0x15, 0xf3, 0x29, 0xfa, 0x21, 0x42, 0x3d, 0x23, 0x83, 0x3c, 0xcb, 0x25, 0x85, 0x1b, 0x51, 0xb8, 0x62, 0x48, - 0x1b, 0xfc, 0x48, 0xe3, 0x3f, 0xe4, 0xff, 0xa7, 0x46, 0x0e, 0x75, 0xda, 0xe0, 0x81, 0x00, 0x16, 0xb2, 0x42, 0x55, - 0xb4, 0x45, 0x03, 0xe9, 0xd0, 0x7c, 0x1b, 0x95, 0x87, 0x39, 0x9d, 0xcf, 0xf3, 0x3b, 0xf3, 0xe0, 0x56, 0xc0, 0x51, - 0x55, 0x17, 0x4d, 0x2e, 0xd4, 0x1d, 0x2e, 0x80, 0xa7, 0x07, 0xdc, 0x43, 0xc6, 0x55, 0xb5, 0xbc, 0xdc, 0x16, 0x08, - 0x24, 0x33, 0x45, 0x64, 0xb3, 0xdd, 0x55, 0x97, 0x20, 0x97, 0x35, 0x9b, 0x48, 0xbb, 0x08, 0xe0, 0x98, 0x83, 0x4c, - 0xa6, 0xac, 0x3b, 0xea, 0x9e, 0x2d, 0x08, 0x92, 0x9b, 0x34, 0x22, 0xdb, 0xee, 0x52, 0x7c, 0x1c, 0x03, 0x1a, 0x21, - 0x2b, 0xf0, 0x85, 0xc2, 0x22, 0x07, 0xae, 0xb3, 0xf0, 0x1d, 0x7f, 0xa3, 0xa5, 0xa2, 0xaf, 0x06, 0x03, 0x5c, 0x98, - 0x37, 0x26, 0xca, 0xf9, 0x14, 0x2a, 0x78, 0xb3, 0x28, 0x10, 0x51, 0xf8, 0x6a, 0xb5, 0x0f, 0x4f, 0x02, 0xb9, 0x36, - 0xc1, 0x7f, 0xd5, 0xfd, 0xac, 0x9e, 0xff, 0x80, 0x71, 0x30, 0xd2, 0x32, 0x17, 0x85, 0x4e, 0xde, 0x64, 0x17, 0xa2, - 0xdb, 0x68, 0x30, 0x13, 0xad, 0x89, 0x40, 0x68, 0x36, 0x70, 0x2e, 0x84, 0x3f, 0x36, 0x00, 0x93, 0x62, 0x36, 0x8c, - 0x1d, 0xc4, 0xd7, 0xae, 0x25, 0xac, 0x56, 0xca, 0x86, 0x49, 0x31, 0x39, 0x36, 0x60, 0x4a, 0xd9, 0x4f, 0x19, 0x8f, - 0xb5, 0x32, 0xe3, 0xe0, 0x6e, 0xab, 0xbf, 0xad, 0xf6, 0xf3, 0x1e, 0xb7, 0xd7, 0x78, 0xdc, 0x04, 0x1f, 0x30, 0x80, - 0x5a, 0x6e, 0x6c, 0x70, 0x6b, 0x2c, 0x1f, 0x5b, 0xcb, 0x5e, 0xb6, 0x09, 0x41, 0x51, 0x3a, 0xdb, 0xdb, 0x9b, 0x5b, - 0x1f, 0x7c, 0x50, 0x99, 0x39, 0x29, 0xa4, 0xfb, 0x20, 0x47, 0x0f, 0x08, 0x74, 0x6e, 0x7f, 0x56, 0x74, 0xa1, 0x92, - 0x89, 0xcb, 0x31, 0xfe, 0x12, 0xdc, 0xe6, 0xf5, 0xa3, 0xeb, 0x6b, 0xb3, 0xc9, 0xaf, 0xaf, 0x23, 0x1c, 0x5a, 0xa8, - 0x47, 0x01, 0x2f, 0x18, 0x0d, 0xca, 0xf8, 0x54, 0x66, 0xe3, 0x37, 0xdb, 0x55, 0x63, 0xef, 0x69, 0x85, 0x77, 0xb0, - 0x3c, 0xa6, 0xf1, 0x2d, 0x8f, 0xce, 0x3e, 0x07, 0x78, 0xb3, 0x3e, 0x1f, 0x74, 0xdf, 0xc4, 0x0a, 0x1d, 0x1c, 0xbc, - 0x89, 0x25, 0xea, 0x5d, 0x31, 0x73, 0xe7, 0x06, 0x2e, 0xdd, 0x7d, 0x6e, 0x86, 0x2f, 0x03, 0x04, 0xb8, 0x62, 0x9b, - 0x92, 0xcd, 0x5b, 0x13, 0x40, 0x23, 0x85, 0x00, 0xdd, 0x10, 0x26, 0xd8, 0x81, 0x04, 0x7a, 0x7d, 0x13, 0x42, 0xbb, - 0xcb, 0x08, 0x03, 0x16, 0xbe, 0x74, 0xb8, 0x63, 0xc9, 0x8c, 0x15, 0x13, 0x56, 0xac, 0x56, 0xef, 0xa9, 0x75, 0xa2, - 0xdb, 0x88, 0xf7, 0xa8, 0xba, 0x8d, 0x06, 0x35, 0xe3, 0x07, 0xf1, 0x81, 0x0e, 0xf0, 0xfe, 0x9b, 0xb8, 0x40, 0x08, - 0x2c, 0x8c, 0xb8, 0x58, 0x78, 0x87, 0xb1, 0xac, 0xb6, 0x2e, 0x05, 0x2a, 0x1b, 0xc9, 0x49, 0x0b, 0x4f, 0x49, 0x56, - 0xae, 0xd1, 0xc5, 0xb4, 0xdb, 0x68, 0xe4, 0x48, 0xc6, 0x59, 0x3f, 0x1f, 0x60, 0x8e, 0x0b, 0xb8, 0x4c, 0xdd, 0x5e, - 0x87, 0x39, 0xab, 0x51, 0x2e, 0x37, 0xdf, 0xa5, 0x1d, 0x6b, 0xfa, 0x88, 0xae, 0x03, 0x60, 0x3c, 0xa2, 0x01, 0x91, - 0xd8, 0x05, 0x64, 0x61, 0x81, 0xac, 0x3c, 0x90, 0x85, 0x01, 0xb2, 0x42, 0xbd, 0x39, 0x44, 0x3e, 0x52, 0x28, 0xdd, - 0xa2, 0xe8, 0xf5, 0x18, 0x9d, 0xce, 0xff, 0x03, 0x73, 0x13, 0x26, 0xc2, 0x2d, 0x07, 0xf8, 0x82, 0x38, 0x97, 0x42, - 0x45, 0x96, 0x51, 0x64, 0xc2, 0xd5, 0xe2, 0x5b, 0xf3, 0x27, 0xb9, 0xc5, 0x77, 0xf6, 0xc7, 0x5d, 0xa0, 0x4c, 0x7a, - 0x5e, 0xd3, 0x36, 0x70, 0x17, 0xdc, 0x2d, 0x4a, 0x22, 0x40, 0x6b, 0x17, 0xa9, 0x50, 0xd4, 0x1f, 0x6f, 0x53, 0x36, - 0xa6, 0x84, 0x68, 0x10, 0x85, 0x45, 0x40, 0x3a, 0xff, 0xfc, 0x33, 0x42, 0x3d, 0x01, 0x21, 0x81, 0xdc, 0xc9, 0xd6, - 0x6c, 0xa3, 0x46, 0x94, 0x44, 0x69, 0xec, 0x23, 0x4e, 0xc0, 0xce, 0x88, 0xa2, 0xe0, 0xe1, 0x96, 0x72, 0x18, 0x1f, - 0x6a, 0xc3, 0x30, 0x83, 0xaa, 0x62, 0x68, 0x5c, 0x2e, 0x37, 0x23, 0x16, 0x19, 0xa8, 0x0a, 0x13, 0x2e, 0x06, 0xd9, - 0xd7, 0xcc, 0x18, 0x61, 0x07, 0x07, 0xac, 0x2f, 0x06, 0xc1, 0xf3, 0x64, 0xd5, 0x75, 0xb8, 0x0e, 0x17, 0x2e, 0xa6, - 0x10, 0x32, 0x7e, 0xb5, 0xb2, 0x7f, 0xc9, 0x07, 0x23, 0xcd, 0xc0, 0x3b, 0x73, 0xc1, 0x19, 0x2b, 0x76, 0xcb, 0x62, - 0x89, 0x96, 0xbf, 0x83, 0xd9, 0x9e, 0x0b, 0x00, 0xc8, 0xdd, 0x54, 0xdb, 0x1e, 0xea, 0x73, 0xa3, 0x51, 0x08, 0xc2, - 0xef, 0x56, 0x47, 0x1a, 0x9e, 0xeb, 0x30, 0xaf, 0x16, 0x46, 0x37, 0x53, 0x65, 0x34, 0x54, 0x38, 0x52, 0x12, 0x30, - 0x41, 0x37, 0x74, 0x12, 0x7e, 0xd4, 0xa9, 0xa4, 0x63, 0x21, 0x01, 0x0a, 0x1c, 0x99, 0xcb, 0x79, 0x13, 0xed, 0x9e, - 0xa1, 0x1d, 0x44, 0x2e, 0x30, 0xa1, 0xa9, 0xcb, 0x96, 0x2e, 0x2c, 0x55, 0x34, 0x93, 0x0b, 0xc5, 0x16, 0x73, 0x38, - 0xdf, 0xcb, 0xb4, 0x2c, 0xe7, 0xd9, 0xe7, 0x7a, 0x0a, 0x58, 0x3b, 0xde, 0xea, 0x19, 0x13, 0x8b, 0xc8, 0xcd, 0xf3, - 0xab, 0x15, 0xf7, 0xdf, 0xbc, 0xc0, 0x8f, 0x48, 0xe7, 0xf0, 0x2b, 0xfe, 0x48, 0xc9, 0xa3, 0xc6, 0x57, 0x3c, 0xe1, - 0xc4, 0xf2, 0x06, 0xc9, 0x9b, 0xd7, 0x57, 0x2f, 0xde, 0xbd, 0x78, 0xff, 0xf4, 0xfa, 0xc5, 0xab, 0x67, 0x2f, 0x5e, - 0xbd, 0x78, 0xf7, 0x11, 0xff, 0x43, 0xc9, 0xd7, 0xa3, 0xf6, 0x79, 0x0b, 0x7f, 0x20, 0x5f, 0x8f, 0x3a, 0xf8, 0x56, - 0x93, 0xaf, 0x47, 0x27, 0x38, 0x57, 0xe4, 0xeb, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0xb4, 0x6d, 0x32, 0x97, 0x93, 0x76, - 0x0b, 0xff, 0xe3, 0xbe, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x1b, 0xc6, 0x0f, 0xa6, 0x0c, 0x1d, 0x2a, 0x63, 0x88, - 0x72, 0x11, 0xa0, 0xd3, 0x54, 0x85, 0xe8, 0x64, 0xe3, 0x31, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, 0xae, 0x1d, 0x7e, - 0xd4, 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd3, 0x62, 0x8c, 0x73, 0x29, 0x8b, 0x78, - 0x01, 0x8c, 0x80, 0xd1, 0x5a, 0xf0, 0xa3, 0x32, 0xf0, 0x93, 0xb8, 0x20, 0xed, 0x5e, 0x3b, 0x15, 0x17, 0xa4, 0xd3, - 0xeb, 0xc0, 0x9f, 0xd3, 0xde, 0x69, 0xda, 0x6e, 0xa1, 0xc3, 0x60, 0x1c, 0x7f, 0xd4, 0xd0, 0xba, 0x3f, 0xc0, 0xae, - 0x0b, 0xf5, 0x4f, 0xa1, 0xbd, 0x4a, 0x4f, 0x38, 0x75, 0x6c, 0xbb, 0x2b, 0x2e, 0x98, 0xd1, 0xc3, 0xf2, 0x1f, 0x00, - 0xb5, 0x8d, 0x6f, 0x4a, 0xb9, 0x71, 0xdc, 0x2f, 0x7e, 0x24, 0x50, 0x2d, 0xba, 0x4c, 0xcc, 0x56, 0x2d, 0x04, 0x4c, - 0xa3, 0xc9, 0x06, 0x73, 0xa0, 0x44, 0xc9, 0x42, 0xfb, 0x08, 0xf9, 0xaa, 0x29, 0x51, 0x32, 0x97, 0xf3, 0xb8, 0xa6, - 0x6a, 0xf8, 0x35, 0x30, 0x73, 0xdc, 0xe7, 0xea, 0x15, 0x7d, 0x15, 0xd7, 0x78, 0x9e, 0x90, 0xb5, 0x0b, 0xb7, 0xc5, - 0x2f, 0xce, 0x8a, 0xa2, 0x06, 0xae, 0x12, 0xb0, 0x7e, 0x54, 0x4d, 0x7d, 0x01, 0x4f, 0x01, 0xb2, 0x86, 0xbe, 0x24, - 0x01, 0xf5, 0xfc, 0xa9, 0x34, 0xe3, 0x2a, 0x95, 0xd1, 0x5e, 0x11, 0x6d, 0xcc, 0x82, 0xbc, 0x22, 0xfa, 0x42, 0x19, - 0x20, 0x48, 0xc2, 0xfb, 0x62, 0x00, 0x07, 0xbe, 0x1d, 0xa0, 0x34, 0x74, 0x0e, 0xd4, 0x4a, 0x95, 0x99, 0x90, 0xf9, - 0x34, 0x71, 0x0e, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xcc, 0x27, 0x96, 0x28, 0x18, 0xfa, 0x6f, 0xe1, 0x06, 0x38, 0x8c, - 0x0d, 0x2a, 0x06, 0xd9, 0xf7, 0x44, 0x3d, 0xbf, 0x7d, 0xde, 0x3a, 0xfa, 0x1a, 0xe4, 0x8f, 0x94, 0xb7, 0xf7, 0xf8, - 0x3b, 0xa0, 0xe4, 0x36, 0x32, 0x57, 0x1b, 0xfb, 0xa0, 0x6a, 0xdd, 0x10, 0x20, 0x87, 0x1a, 0x1d, 0x99, 0x57, 0x11, - 0xbb, 0x48, 0x1f, 0x92, 0x76, 0x0b, 0x22, 0xa1, 0xed, 0xa0, 0x7c, 0x3f, 0x6d, 0xc0, 0x54, 0x27, 0xb7, 0x4d, 0xa0, - 0xd5, 0xf0, 0x50, 0xd2, 0x5d, 0x93, 0x27, 0x77, 0x58, 0x05, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1c, 0x0a, 0xe4, 0x22, - 0xc8, 0xda, 0x0d, 0xa0, 0xa9, 0xe8, 0xd8, 0x07, 0xfb, 0xbc, 0x71, 0xd4, 0x45, 0x33, 0x39, 0x3d, 0xfc, 0x7a, 0x70, - 0x10, 0xcb, 0x06, 0x79, 0x84, 0xf0, 0x92, 0x82, 0x41, 0x36, 0x38, 0xb0, 0x71, 0xcb, 0xc4, 0xa7, 0x2a, 0xa0, 0x8e, - 0x0b, 0x55, 0x3b, 0xd6, 0xaa, 0xce, 0xca, 0xdd, 0xe0, 0xc7, 0xd4, 0x41, 0x8d, 0x20, 0xcd, 0x8e, 0xae, 0x53, 0x83, - 0x72, 0xcd, 0xdb, 0x0c, 0xb6, 0x65, 0xe3, 0x23, 0x45, 0x3f, 0x3c, 0x6a, 0x7e, 0x0d, 0x26, 0x5c, 0x33, 0x4d, 0x7a, - 0xd4, 0x78, 0x84, 0x7e, 0x78, 0x14, 0xf8, 0x0b, 0xf2, 0x8a, 0x3d, 0xf1, 0xdc, 0xc8, 0x4f, 0x96, 0x2b, 0xfd, 0x09, - 0x24, 0xfb, 0x82, 0xfc, 0x04, 0x58, 0x4e, 0xc9, 0x4f, 0xb1, 0x6c, 0x42, 0x1c, 0x45, 0xf2, 0x53, 0x5c, 0xc0, 0x8f, - 0x9c, 0xfc, 0x14, 0x03, 0xb6, 0xe3, 0xa9, 0xf9, 0x51, 0x94, 0xc0, 0x00, 0x1f, 0x35, 0x69, 0x5d, 0xd5, 0x8a, 0xd5, - 0x4a, 0x1c, 0x1c, 0x48, 0xfb, 0x8b, 0x5e, 0x66, 0x07, 0x07, 0xf9, 0xc5, 0xb4, 0xea, 0x9b, 0xe9, 0x5d, 0xf4, 0xc5, - 0x20, 0x14, 0x0e, 0x4c, 0xd3, 0x78, 0x38, 0xe3, 0x4f, 0x21, 0x65, 0x35, 0x0d, 0x34, 0x8f, 0x3b, 0xf7, 0xcf, 0xce, - 0x31, 0xfc, 0x7b, 0x3f, 0x28, 0xf8, 0x73, 0xc9, 0x77, 0x91, 0x36, 0x6b, 0x9e, 0x55, 0xc8, 0x76, 0x19, 0xe0, 0x33, - 0x66, 0xa8, 0x29, 0x0e, 0x0e, 0xf8, 0x45, 0x80, 0xcb, 0x98, 0xa1, 0x46, 0x60, 0xb1, 0xf7, 0xb0, 0xb4, 0x27, 0x33, - 0x5c, 0x13, 0xbc, 0x90, 0xcb, 0xfb, 0xc5, 0xe0, 0x42, 0x3b, 0x6a, 0x12, 0xc6, 0xd1, 0x56, 0xa4, 0xe5, 0x36, 0x59, - 0x57, 0x34, 0xd5, 0x65, 0xbb, 0x8b, 0x24, 0x51, 0x0d, 0x71, 0x79, 0xd9, 0xc6, 0xa0, 0x92, 0xef, 0x29, 0x22, 0x53, - 0x41, 0xbc, 0xaf, 0xdf, 0x32, 0x97, 0xa9, 0xc2, 0x53, 0x9e, 0x0a, 0x2f, 0x67, 0xbf, 0xf6, 0xd6, 0xd3, 0xc6, 0xfb, - 0xd2, 0xf4, 0xcc, 0xb0, 0xe8, 0xa9, 0xd2, 0x6b, 0x10, 0x36, 0xa9, 0x1a, 0xc0, 0x03, 0x84, 0x25, 0xe6, 0x31, 0xeb, - 0x2a, 0xc7, 0x20, 0xc0, 0xb3, 0x6a, 0xb4, 0x21, 0x13, 0x3e, 0xd7, 0xa9, 0x82, 0x81, 0x9a, 0xc2, 0x17, 0x40, 0xa6, - 0xb2, 0xca, 0x30, 0xdb, 0x37, 0x0c, 0x05, 0x04, 0x14, 0xb8, 0x24, 0x2c, 0x90, 0xe0, 0xe1, 0xf6, 0x23, 0x20, 0x1c, - 0x75, 0x72, 0x61, 0x27, 0x77, 0xa1, 0xa0, 0x3b, 0x31, 0xb8, 0xd0, 0x5d, 0x24, 0x1a, 0x0d, 0xc7, 0x6d, 0x5f, 0x0a, - 0x33, 0x88, 0x66, 0x7b, 0x70, 0xc9, 0xba, 0x48, 0x35, 0x9b, 0xa5, 0x01, 0xe4, 0x65, 0x6b, 0xb5, 0x52, 0x17, 0xbe, - 0x91, 0x9e, 0x3f, 0xc7, 0x0d, 0xdf, 0xe5, 0x05, 0xcf, 0xdf, 0x24, 0xe9, 0x47, 0x40, 0x55, 0x81, 0xcf, 0x96, 0xf3, - 0x08, 0x47, 0xe6, 0x6d, 0x3a, 0xf8, 0x6b, 0xde, 0x14, 0x8b, 0x70, 0xe4, 0x9e, 0xab, 0x8b, 0x06, 0xd5, 0x60, 0x79, - 0x56, 0x46, 0x5a, 0xe7, 0xc9, 0x35, 0x30, 0x0e, 0xfa, 0x6f, 0x85, 0x96, 0xd5, 0xef, 0x24, 0x77, 0x31, 0x47, 0x94, - 0x7f, 0x41, 0xcd, 0x8d, 0x6a, 0xbd, 0xdb, 0xcb, 0x93, 0xe3, 0xc8, 0x57, 0x85, 0x97, 0x08, 0xbe, 0xf3, 0x84, 0x63, - 0xdb, 0xbd, 0x1c, 0xbe, 0x2c, 0x7b, 0x00, 0xce, 0x7b, 0xbd, 0x46, 0xf8, 0x37, 0xb9, 0xf3, 0x19, 0xe1, 0xe8, 0x5a, - 0x8a, 0x27, 0x54, 0xd3, 0xa8, 0xf1, 0xc6, 0x18, 0xbe, 0x59, 0x39, 0xab, 0xfb, 0xad, 0x71, 0xb0, 0x7f, 0xab, 0x7b, - 0x88, 0x02, 0x51, 0x7b, 0xf1, 0xc8, 0xca, 0xbe, 0x26, 0xf6, 0x87, 0x0c, 0x4c, 0xdf, 0x76, 0xc0, 0xc3, 0x8f, 0x91, - 0x82, 0x6f, 0xb2, 0xe5, 0x93, 0x28, 0x84, 0x57, 0xad, 0x79, 0x44, 0x43, 0x8a, 0xed, 0xc3, 0x78, 0xcf, 0xae, 0x51, - 0xc8, 0x75, 0x8f, 0x55, 0x9d, 0x98, 0x56, 0xdd, 0x18, 0xa9, 0x83, 0x6d, 0xb2, 0xe0, 0xac, 0xea, 0xdd, 0x48, 0x28, - 0xd5, 0xe3, 0x70, 0xe6, 0x81, 0xcf, 0x66, 0xdb, 0xbc, 0x98, 0x6c, 0x9f, 0x90, 0x53, 0x60, 0xc8, 0xbb, 0x5f, 0x46, - 0xbe, 0xba, 0x84, 0x63, 0x37, 0x0e, 0x20, 0x2b, 0xc9, 0xe5, 0xd2, 0x3d, 0xef, 0xc6, 0xfb, 0x72, 0xb0, 0x2e, 0x1f, - 0x7b, 0x0b, 0xf0, 0xa0, 0x1a, 0xa9, 0xc8, 0x42, 0xce, 0xc0, 0xbf, 0x94, 0x58, 0xd3, 0x0f, 0xf1, 0xaf, 0x70, 0xc0, - 0x57, 0x48, 0x9a, 0x5a, 0xf5, 0x13, 0x3c, 0xc2, 0x04, 0x0a, 0x6f, 0x5b, 0xf7, 0x93, 0x0c, 0xbd, 0x5d, 0xeb, 0x3a, - 0x15, 0xeb, 0x50, 0x5a, 0x57, 0xac, 0x94, 0x85, 0x83, 0xe3, 0x2e, 0x46, 0xeb, 0xd4, 0x39, 0x9f, 0xba, 0x97, 0x9b, - 0x1e, 0x0a, 0x70, 0x7c, 0xe1, 0x52, 0x3c, 0x2b, 0x20, 0x14, 0x57, 0xa8, 0x4f, 0xfb, 0x59, 0x86, 0x4f, 0x13, 0xf7, - 0xe1, 0x9e, 0xb0, 0xe4, 0x39, 0xcb, 0xe7, 0xb4, 0x61, 0x81, 0x14, 0x50, 0x28, 0x85, 0xc5, 0x6a, 0x15, 0x0b, 0x13, - 0xa0, 0xc1, 0xc5, 0xe7, 0x75, 0x0f, 0x71, 0x18, 0xfd, 0x1d, 0xd4, 0xc5, 0x5e, 0x3d, 0x62, 0x4c, 0x58, 0x51, 0x78, - 0xe9, 0xa4, 0xb2, 0xa0, 0xaf, 0x5d, 0x7d, 0x88, 0x6a, 0xca, 0xbd, 0xd8, 0xe8, 0x7b, 0xdf, 0xf1, 0x19, 0x93, 0x0b, - 0x78, 0x01, 0x09, 0x33, 0xa2, 0x98, 0xf6, 0xdf, 0x40, 0x41, 0xe0, 0x19, 0x1d, 0x1e, 0xe2, 0x23, 0xf0, 0x55, 0x9e, - 0xd6, 0xc9, 0xcc, 0xbf, 0xab, 0x11, 0x99, 0xb8, 0x97, 0x51, 0x2f, 0x02, 0x17, 0x21, 0x10, 0xa1, 0x08, 0x89, 0x98, - 0x18, 0x45, 0xbd, 0xc8, 0xf8, 0x5b, 0x45, 0x60, 0x35, 0x06, 0x4a, 0xee, 0x08, 0xcf, 0x55, 0x45, 0xc4, 0xc2, 0x9a, - 0x3a, 0xa8, 0xc4, 0x52, 0x63, 0xa6, 0x7d, 0xd4, 0xa9, 0x40, 0x58, 0x64, 0x9b, 0x82, 0xb2, 0xde, 0x50, 0x17, 0x60, - 0x49, 0x8c, 0xe9, 0x2d, 0x4f, 0xae, 0x81, 0x9b, 0x63, 0x23, 0x57, 0x74, 0xc9, 0xaf, 0x40, 0x3d, 0x9d, 0x16, 0xf8, - 0xda, 0x30, 0x6c, 0xa3, 0x94, 0xae, 0x09, 0xc7, 0x19, 0x29, 0x12, 0x7a, 0x0b, 0x01, 0x2a, 0x66, 0x5c, 0xa4, 0x39, - 0x9e, 0xd1, 0xdb, 0x74, 0x8a, 0x67, 0x5c, 0x3c, 0xb1, 0xcb, 0x9e, 0x8e, 0x20, 0xc9, 0x7f, 0x2c, 0xd6, 0xc4, 0xbc, - 0xaf, 0xf5, 0xbb, 0x62, 0xc5, 0x23, 0xe0, 0x55, 0x54, 0x8c, 0xba, 0x23, 0x63, 0x53, 0xce, 0x74, 0x65, 0xbc, 0xfe, - 0x5a, 0xc7, 0x14, 0x67, 0x38, 0x47, 0x49, 0x2e, 0x31, 0xeb, 0x89, 0xf4, 0x35, 0x04, 0xa7, 0xce, 0xb0, 0x7d, 0x9b, - 0x8b, 0xdf, 0xb2, 0xfc, 0x99, 0x2c, 0xde, 0x9b, 0x2d, 0x9f, 0x23, 0x28, 0x04, 0x2e, 0x2a, 0xa2, 0x09, 0xb7, 0x7b, - 0x8b, 0x9e, 0xac, 0x9a, 0xa2, 0xb7, 0xb6, 0x29, 0x37, 0xc4, 0x29, 0x44, 0xf5, 0x4d, 0xa6, 0xbc, 0xd1, 0xc6, 0xac, - 0xd7, 0xfa, 0x4e, 0xa3, 0x53, 0x54, 0x96, 0x44, 0x18, 0xd6, 0xaa, 0xa9, 0x52, 0x49, 0x44, 0x53, 0x39, 0x09, 0x6f, - 0x69, 0x80, 0x9d, 0x2a, 0x9c, 0xc9, 0x85, 0xd0, 0xa9, 0x0c, 0xf0, 0x86, 0x56, 0x9b, 0x6b, 0x79, 0x6b, 0x21, 0xa6, - 0xf1, 0x9d, 0xfd, 0xc1, 0xf0, 0xb5, 0x51, 0xf1, 0xbf, 0x05, 0xc3, 0x1e, 0x95, 0x0a, 0x80, 0x1f, 0x18, 0xce, 0x02, - 0xe4, 0x2c, 0x3f, 0x79, 0x0b, 0xe0, 0xb3, 0x2c, 0xe4, 0x1d, 0xa4, 0x32, 0x93, 0x7a, 0x07, 0xa9, 0x0c, 0x52, 0x8d, - 0x5b, 0xfa, 0xbe, 0xa8, 0x94, 0x45, 0x61, 0x83, 0x44, 0xe1, 0x52, 0x1d, 0x2c, 0x89, 0x48, 0xa0, 0x5d, 0x23, 0xca, - 0xcd, 0xb8, 0x80, 0xf8, 0x84, 0xd0, 0xb8, 0xfd, 0xa6, 0xb7, 0xf0, 0x7d, 0x67, 0xf3, 0x99, 0xcf, 0xbf, 0xb3, 0xf9, - 0xa6, 0x23, 0x8f, 0xf1, 0xf5, 0xdb, 0x4e, 0x63, 0x19, 0x2f, 0x1d, 0xd6, 0x7e, 0x28, 0x5f, 0x83, 0x69, 0x99, 0x57, - 0xb7, 0x49, 0x1b, 0x4f, 0x02, 0xa4, 0x6c, 0x56, 0x3c, 0x5c, 0x07, 0xb7, 0x5b, 0x87, 0x31, 0x6f, 0x92, 0x36, 0x42, - 0x87, 0x4e, 0xb8, 0x12, 0xb1, 0x91, 0x9c, 0x0e, 0x1f, 0x1d, 0xc1, 0xdd, 0xcb, 0x4c, 0x6d, 0xf8, 0x4a, 0xd9, 0x6a, - 0xcd, 0x76, 0xeb, 0x90, 0xef, 0xac, 0xd2, 0x68, 0xe3, 0x19, 0x23, 0x4b, 0x70, 0x2e, 0xa3, 0x85, 0x55, 0x35, 0x80, - 0x3f, 0xea, 0x0b, 0xf1, 0xdb, 0x82, 0x8e, 0xcc, 0xf7, 0xa1, 0x4d, 0x79, 0xbd, 0xd0, 0x3e, 0xa9, 0xc9, 0x61, 0x10, - 0x1d, 0xe4, 0x4a, 0x06, 0x39, 0x31, 0x3f, 0x22, 0xc9, 0x29, 0xba, 0x68, 0xf7, 0x92, 0xd3, 0x43, 0x7e, 0xc8, 0x53, - 0xe0, 0x61, 0xe3, 0xa6, 0xaf, 0xd0, 0x6c, 0xfb, 0x3a, 0x8f, 0x17, 0x43, 0x9e, 0xb9, 0xe6, 0xab, 0x0e, 0xca, 0x54, - 0x3b, 0x47, 0xc8, 0x02, 0x14, 0xf3, 0xbd, 0x04, 0xd9, 0xf5, 0x6e, 0x0e, 0x79, 0x0a, 0xfd, 0x40, 0xad, 0x8e, 0xad, - 0x55, 0x0e, 0xee, 0xb7, 0x05, 0x20, 0x98, 0xef, 0xa8, 0x36, 0x17, 0x9b, 0xde, 0x8c, 0xab, 0xce, 0x0e, 0x79, 0x35, - 0xc2, 0xb0, 0xcc, 0x76, 0x7f, 0x7e, 0x6a, 0x55, 0x97, 0x87, 0x01, 0x44, 0x7e, 0x5b, 0x70, 0x11, 0x76, 0x1a, 0x76, - 0xeb, 0x72, 0xc2, 0x4e, 0xeb, 0xb3, 0x0c, 0x8a, 0x6c, 0xf7, 0xba, 0x35, 0xd3, 0xfa, 0x6c, 0xaf, 0xc0, 0x47, 0x10, - 0x26, 0x65, 0x56, 0x3a, 0x83, 0x2b, 0xf4, 0xc3, 0x0f, 0xc8, 0xb5, 0xfe, 0x7a, 0xa1, 0x7d, 0x7e, 0x89, 0x08, 0x90, - 0x5d, 0x75, 0x5d, 0x56, 0x87, 0x3e, 0xca, 0x26, 0xbe, 0x1e, 0xf2, 0x60, 0xe5, 0x9e, 0xde, 0xce, 0x65, 0xea, 0xf1, - 0xb5, 0xd7, 0x4a, 0xb7, 0x90, 0x13, 0x88, 0x87, 0xeb, 0x2e, 0x2c, 0x0b, 0x72, 0x76, 0x73, 0x0b, 0x25, 0xc3, 0x89, - 0xfb, 0xd2, 0x1f, 0x98, 0xbd, 0x6e, 0xe0, 0x17, 0xc9, 0x29, 0x4c, 0x7d, 0xb3, 0x87, 0xc3, 0x0e, 0xf4, 0x61, 0xe0, - 0xb0, 0xd9, 0xa0, 0xcf, 0xac, 0x20, 0xf2, 0x98, 0x17, 0x16, 0xcf, 0x2e, 0x49, 0xbb, 0xc7, 0x53, 0xb7, 0x99, 0x8c, - 0x68, 0xd4, 0x6e, 0xf2, 0x60, 0x66, 0x80, 0x5f, 0xae, 0x6c, 0x58, 0xc4, 0xaf, 0x53, 0x00, 0x25, 0x5f, 0xac, 0x5a, - 0x9f, 0x0a, 0x5e, 0xf5, 0x86, 0xd3, 0xcd, 0x74, 0xbf, 0x6e, 0x70, 0xbb, 0xeb, 0xe1, 0x09, 0xaf, 0xb9, 0x58, 0xb4, - 0xf6, 0x13, 0x9f, 0x00, 0x07, 0x94, 0xb4, 0xee, 0x9f, 0x82, 0x0b, 0x65, 0x09, 0xcb, 0xed, 0x72, 0xb3, 0xad, 0x72, - 0x16, 0x8e, 0xb6, 0x64, 0xc0, 0x1d, 0x6c, 0x42, 0x14, 0x3a, 0x38, 0xec, 0xe0, 0xa4, 0xdd, 0xee, 0x9c, 0xe2, 0xe4, - 0xe4, 0x14, 0x06, 0xda, 0x48, 0x4e, 0x0f, 0x67, 0xca, 0x02, 0x30, 0xc8, 0x59, 0xbb, 0x76, 0x1f, 0x41, 0xe4, 0xa7, - 0x50, 0xbc, 0xe6, 0x87, 0x71, 0xdc, 0x4e, 0xee, 0xb7, 0xda, 0xa7, 0xe7, 0x0d, 0x00, 0x50, 0xd3, 0x7d, 0xb8, 0x1a, - 0xaf, 0x17, 0xba, 0x5e, 0xa5, 0x44, 0xf8, 0x7a, 0xb5, 0x86, 0xaf, 0xd6, 0x68, 0xaf, 0xab, 0x29, 0xf8, 0xaa, 0x4e, - 0x38, 0xb7, 0x45, 0xbc, 0xd2, 0x26, 0xdc, 0x16, 0xb1, 0x1d, 0x48, 0x0c, 0xd2, 0x79, 0x72, 0xda, 0x39, 0x45, 0x76, - 0x2c, 0xda, 0xe1, 0x47, 0xb9, 0x4f, 0xb6, 0x8a, 0x34, 0x34, 0x20, 0x49, 0x39, 0x3b, 0xb9, 0x00, 0x89, 0x9a, 0x93, - 0xcb, 0x76, 0x73, 0xc6, 0x12, 0x3f, 0x01, 0x93, 0x0a, 0xcb, 0x59, 0xae, 0x82, 0x4b, 0x0a, 0x00, 0x71, 0x01, 0xc6, - 0x45, 0xf7, 0x4f, 0x7b, 0xf7, 0x93, 0xd3, 0xb3, 0x8e, 0x25, 0x7a, 0xfc, 0xa2, 0x53, 0x4b, 0x33, 0x53, 0x4f, 0x4e, - 0x4d, 0x1a, 0x74, 0x9d, 0xdc, 0x3f, 0x85, 0x32, 0x2e, 0x25, 0x2c, 0x05, 0x11, 0x2b, 0xaa, 0x62, 0x10, 0xa6, 0x22, - 0xad, 0xe5, 0x9e, 0xd5, 0xb2, 0xcf, 0x4f, 0x8e, 0xef, 0x9f, 0x86, 0x50, 0x2b, 0x67, 0x61, 0x16, 0xda, 0x4d, 0xc4, - 0xcf, 0x0e, 0x96, 0x16, 0x1d, 0x26, 0xa7, 0xe9, 0xd6, 0x04, 0xed, 0xa6, 0x39, 0x34, 0x38, 0x10, 0x28, 0x1c, 0x9f, - 0x0a, 0xa7, 0x2f, 0x09, 0xee, 0xc7, 0x2a, 0x43, 0x93, 0x50, 0xe1, 0xec, 0xef, 0x29, 0x83, 0x47, 0x29, 0xc3, 0xab, - 0xca, 0xc7, 0x54, 0x7c, 0xa1, 0xea, 0x0d, 0x85, 0x30, 0x1c, 0x62, 0x10, 0xb9, 0x20, 0xe1, 0xf5, 0xdc, 0x9f, 0xc0, - 0x45, 0x98, 0x09, 0xb8, 0xd0, 0xf4, 0x4a, 0xd0, 0x8a, 0x17, 0x18, 0x86, 0x0e, 0xb5, 0x66, 0x58, 0x3d, 0x9e, 0x3a, - 0x93, 0x82, 0x50, 0xb7, 0xf5, 0x9c, 0x7f, 0xaf, 0x5c, 0x52, 0x5e, 0x65, 0x27, 0xa7, 0x28, 0x71, 0x97, 0xe5, 0x49, - 0x1b, 0x25, 0x81, 0x09, 0x89, 0x3b, 0x92, 0xb3, 0x8c, 0xf4, 0xa3, 0xdb, 0x08, 0x47, 0x77, 0x11, 0x8e, 0xac, 0x0f, - 0xf3, 0x07, 0x70, 0x10, 0x8f, 0x70, 0x64, 0x5d, 0x99, 0x23, 0x1c, 0x69, 0x26, 0x20, 0x3a, 0x57, 0x34, 0xc0, 0x39, - 0x94, 0x36, 0x9e, 0xd5, 0x65, 0xe9, 0xc7, 0xfe, 0xab, 0x74, 0xbd, 0xb6, 0x29, 0x81, 0x94, 0x39, 0x35, 0x3b, 0xd4, - 0xbe, 0x2e, 0x1d, 0x51, 0xcf, 0xac, 0x47, 0x18, 0x04, 0x10, 0x7a, 0xe7, 0x5f, 0xa7, 0xab, 0x02, 0x7b, 0xb0, 0x63, - 0x58, 0x69, 0xf0, 0x33, 0x8f, 0xc2, 0x33, 0x2c, 0xc2, 0x63, 0xe1, 0x0b, 0x83, 0x58, 0xe1, 0x7f, 0xe7, 0x52, 0xce, - 0xfd, 0x6f, 0x2d, 0xcb, 0x5f, 0xf0, 0xa6, 0x89, 0xb3, 0x68, 0x01, 0xcb, 0x2d, 0x1b, 0x47, 0x68, 0xc8, 0xea, 0x23, - 0xb8, 0x1e, 0xbb, 0x58, 0x6f, 0x20, 0x11, 0x5e, 0x1b, 0x81, 0xca, 0xcb, 0x87, 0xd7, 0x36, 0xee, 0x90, 0xf9, 0x84, - 0xc0, 0x63, 0x10, 0x5b, 0x58, 0xc2, 0x85, 0xc6, 0xa4, 0x60, 0x4a, 0x45, 0x36, 0x20, 0x5f, 0x24, 0x85, 0x7f, 0x61, - 0xd1, 0xa7, 0x8c, 0x45, 0x64, 0x3a, 0xac, 0xcf, 0xd6, 0x8a, 0xc3, 0xb9, 0x2c, 0x54, 0x6a, 0x9f, 0x5b, 0xf1, 0x60, - 0x9c, 0x97, 0x6f, 0x19, 0xa6, 0x79, 0xb6, 0xc6, 0xf6, 0x0e, 0xbb, 0x2c, 0xe4, 0xae, 0xb4, 0xc3, 0x52, 0x59, 0xb6, - 0xfe, 0xd6, 0x84, 0x54, 0x6d, 0x46, 0xc1, 0x44, 0xab, 0x01, 0x55, 0x51, 0x39, 0xa0, 0xb0, 0x8d, 0xec, 0x92, 0x2e, - 0xcb, 0x92, 0xe9, 0xb2, 0x5c, 0x86, 0x93, 0x56, 0x6b, 0xbd, 0xc6, 0x05, 0x33, 0x11, 0x66, 0x76, 0x96, 0x80, 0x7c, - 0x35, 0x95, 0x37, 0x41, 0xae, 0x4a, 0xcb, 0x59, 0x9a, 0x25, 0x8a, 0x02, 0x23, 0xd8, 0x68, 0x8d, 0xbf, 0x70, 0xc5, - 0x01, 0x9e, 0x6e, 0x76, 0x43, 0x29, 0x73, 0x46, 0x21, 0x10, 0x59, 0xd0, 0xe4, 0x1a, 0x4f, 0xf9, 0x88, 0xed, 0x6e, - 0x13, 0xcc, 0x98, 0xff, 0xbd, 0x16, 0x3d, 0x02, 0x59, 0x76, 0xcf, 0xa0, 0x0e, 0x2c, 0xe2, 0x0a, 0x3a, 0x08, 0x65, - 0xf0, 0x51, 0x88, 0x9b, 0x39, 0xbd, 0x93, 0x0b, 0x0d, 0x70, 0x59, 0x68, 0xf9, 0xc6, 0xc5, 0x3a, 0xd8, 0x6f, 0x61, - 0x1f, 0xf6, 0x60, 0x09, 0x21, 0x03, 0x5a, 0xd8, 0x86, 0xbb, 0x68, 0xe1, 0xa1, 0xd4, 0x5a, 0xce, 0xd2, 0x16, 0x36, - 0xb1, 0x27, 0x5a, 0xeb, 0x32, 0x40, 0xd8, 0x75, 0xf9, 0x2e, 0x65, 0xb5, 0x09, 0x16, 0x4e, 0x3a, 0xd4, 0x44, 0x07, - 0xb7, 0x87, 0x8c, 0xf0, 0xc6, 0xcf, 0x57, 0xaf, 0x5f, 0xb9, 0xf0, 0xcf, 0x7c, 0x0c, 0x2e, 0x9b, 0x4e, 0x35, 0x76, - 0x6d, 0x1e, 0x74, 0x8a, 0x2b, 0x45, 0xa9, 0x15, 0x4e, 0xa1, 0xe5, 0x17, 0x42, 0xe7, 0x89, 0xbd, 0xbc, 0x78, 0x26, - 0x8b, 0x19, 0xb5, 0x37, 0x46, 0xf8, 0x5a, 0xb9, 0x17, 0xdc, 0xcd, 0x23, 0x31, 0xd5, 0x24, 0xdf, 0x6d, 0x5e, 0x45, - 0x2c, 0x32, 0x23, 0xbf, 0x82, 0x36, 0xc0, 0x54, 0x2e, 0x1f, 0xe0, 0x2d, 0x88, 0x0b, 0xa2, 0x1f, 0x90, 0x97, 0xb7, - 0x96, 0xba, 0x44, 0x51, 0x83, 0x1b, 0xfc, 0x64, 0x05, 0xcf, 0x82, 0xeb, 0x42, 0xc3, 0x1e, 0x39, 0xf1, 0x22, 0x6a, - 0x45, 0xf5, 0x07, 0x6c, 0x8d, 0x2a, 0xc1, 0x07, 0x60, 0x4d, 0x72, 0x09, 0xa2, 0x47, 0xf9, 0x56, 0x1e, 0x07, 0xd1, - 0xc4, 0xdf, 0x3d, 0x5f, 0xb6, 0x3d, 0x9d, 0xcd, 0x2b, 0x75, 0x62, 0x79, 0x65, 0x02, 0x1e, 0x8e, 0xf6, 0x35, 0x1a, - 0x84, 0x83, 0x44, 0x56, 0x6a, 0x0f, 0x7d, 0x2e, 0xea, 0xc6, 0xf9, 0x45, 0x9b, 0x35, 0x4f, 0x56, 0xab, 0xfc, 0xb2, - 0xcd, 0xda, 0xa7, 0xf6, 0xed, 0xba, 0x48, 0x65, 0x40, 0x73, 0xf9, 0x98, 0x67, 0x11, 0x68, 0x67, 0xc7, 0x99, 0x09, - 0xa7, 0xe0, 0xa3, 0x2d, 0x93, 0x85, 0xae, 0xfa, 0x92, 0x60, 0x5c, 0x4a, 0xac, 0x1e, 0xbf, 0x40, 0xbd, 0x76, 0xba, - 0xed, 0x2a, 0xdd, 0x6c, 0x1f, 0x06, 0x17, 0x2e, 0x05, 0xc2, 0x1d, 0x08, 0x79, 0x00, 0xfa, 0xdd, 0xa5, 0x00, 0xd3, - 0x20, 0x40, 0x65, 0x05, 0x22, 0x2d, 0x9f, 0x2d, 0x66, 0xcf, 0x0a, 0x6a, 0x96, 0xe1, 0x09, 0x9f, 0x70, 0xad, 0x52, - 0x0a, 0xd2, 0xed, 0xae, 0xf4, 0xf5, 0x6e, 0x09, 0x2a, 0xab, 0x05, 0xb1, 0x4d, 0x34, 0xcf, 0x3e, 0x2b, 0xb7, 0x70, - 0x08, 0x9b, 0x95, 0x15, 0x38, 0x43, 0x6b, 0x9c, 0xcb, 0x09, 0x2d, 0xb8, 0x9e, 0xce, 0xfe, 0xad, 0xd5, 0x61, 0x7d, - 0x3d, 0x30, 0x17, 0x56, 0x00, 0x12, 0x2a, 0x46, 0xab, 0x15, 0x3f, 0xfa, 0xfe, 0x7d, 0x92, 0xf7, 0x09, 0x6f, 0xe3, - 0x0e, 0x3e, 0xc6, 0xa7, 0xb8, 0xdd, 0xc2, 0xed, 0x53, 0xb8, 0xba, 0xcf, 0xf2, 0xc5, 0x88, 0xa9, 0x18, 0x1e, 0x31, - 0xd3, 0x97, 0xc9, 0xf9, 0x61, 0x19, 0xba, 0x5f, 0x17, 0x89, 0x43, 0x97, 0x20, 0x82, 0xbc, 0x0b, 0xbd, 0x17, 0x45, - 0x61, 0xdc, 0xb7, 0x71, 0xa8, 0x3a, 0x29, 0xf5, 0x0b, 0x97, 0xc7, 0x3d, 0xb0, 0xe7, 0xb6, 0x2b, 0xdb, 0x04, 0xb3, - 0x6f, 0xfb, 0x33, 0xad, 0x7e, 0x36, 0x75, 0x89, 0x18, 0x1e, 0x7a, 0x15, 0x7a, 0xa0, 0x4b, 0xd2, 0x3e, 0x38, 0x00, - 0xab, 0xa3, 0x60, 0x36, 0xdc, 0x46, 0x3f, 0xe0, 0xcd, 0x5a, 0x1a, 0x04, 0x2b, 0x00, 0xe3, 0xce, 0x37, 0x9c, 0x2c, - 0x2d, 0x6c, 0x35, 0x50, 0x61, 0x5d, 0x84, 0xc1, 0xe9, 0x42, 0x52, 0x61, 0x84, 0x68, 0x38, 0xc2, 0x5c, 0xa4, 0x93, - 0xfd, 0x16, 0x96, 0xe3, 0xb1, 0x62, 0x1a, 0x8e, 0x8e, 0x82, 0x7d, 0x61, 0x85, 0x32, 0xa7, 0xc8, 0x90, 0x4d, 0xb8, - 0x78, 0xa8, 0x3f, 0xb1, 0x42, 0x9a, 0x4f, 0xa3, 0xc1, 0x48, 0x23, 0xb3, 0x8a, 0x11, 0xce, 0x72, 0x3e, 0x87, 0xaa, - 0x93, 0x02, 0x9c, 0x7e, 0xe0, 0x2f, 0x1f, 0xa5, 0x61, 0x9b, 0x40, 0xbe, 0x3e, 0xd8, 0x80, 0x2d, 0x78, 0x54, 0xd0, - 0x9b, 0xd7, 0xe2, 0x31, 0xec, 0xa8, 0x87, 0x05, 0xa3, 0x90, 0x0d, 0x49, 0xef, 0xa0, 0x29, 0xf8, 0x80, 0x36, 0x5f, - 0x1a, 0xc0, 0xa5, 0xe7, 0xe6, 0xc3, 0x56, 0xf4, 0x01, 0x10, 0x93, 0xb2, 0x2d, 0x93, 0x69, 0x4e, 0xe9, 0x2a, 0xd3, - 0x86, 0x98, 0x2a, 0xa7, 0xb0, 0xc6, 0x2e, 0xea, 0x49, 0x38, 0x98, 0x11, 0x55, 0xd3, 0xb4, 0x3f, 0x30, 0x7f, 0x5f, - 0xdb, 0x92, 0x2d, 0xec, 0xc2, 0xc9, 0xac, 0xb1, 0x79, 0x7d, 0x34, 0x28, 0xdf, 0xc6, 0x70, 0x0f, 0x0b, 0x4f, 0x60, - 0xd6, 0xc8, 0xe7, 0x89, 0x27, 0x9b, 0x27, 0xeb, 0xb5, 0x19, 0x88, 0x4a, 0x41, 0x0f, 0xf4, 0xd6, 0x6f, 0x9b, 0x16, - 0x6c, 0x8f, 0xf2, 0xeb, 0xb4, 0x85, 0x67, 0x1c, 0x5e, 0xf4, 0xf4, 0xed, 0x5d, 0xe9, 0x42, 0x7e, 0x76, 0x20, 0x69, - 0x05, 0x29, 0x76, 0x3a, 0x41, 0x67, 0xc7, 0x38, 0x18, 0x39, 0xd0, 0xf3, 0xab, 0xcf, 0x16, 0xd6, 0xfe, 0xf7, 0x9b, - 0xb2, 0xa0, 0x09, 0x96, 0x53, 0x4e, 0x28, 0xf3, 0xe7, 0xe7, 0x1b, 0x9e, 0x54, 0xa8, 0xe0, 0x9e, 0xc2, 0x82, 0x3d, - 0x6d, 0xa3, 0x65, 0xce, 0xe8, 0xdf, 0xf6, 0x87, 0x0d, 0xd0, 0x53, 0x6a, 0xd9, 0xb2, 0x42, 0x2a, 0xf5, 0xd0, 0xa6, - 0xd9, 0xa3, 0x07, 0x8e, 0xc8, 0x97, 0xd0, 0x05, 0xf0, 0xfa, 0xa3, 0x42, 0xce, 0x0d, 0x22, 0xb8, 0xdf, 0x6e, 0xdc, - 0xc6, 0x57, 0x00, 0xbc, 0x1d, 0xf6, 0xaa, 0x7f, 0x5a, 0xc0, 0xfe, 0x46, 0x65, 0x49, 0x3f, 0xde, 0x8e, 0x3d, 0xfe, - 0x0b, 0x09, 0xa1, 0xd7, 0x2d, 0x1e, 0x26, 0x0e, 0x9d, 0x4a, 0xd6, 0xac, 0xfc, 0xb9, 0x55, 0x12, 0x30, 0xac, 0x5e, - 0x30, 0x64, 0xe3, 0xb6, 0x8a, 0xdb, 0xcc, 0xff, 0xa0, 0x82, 0xc1, 0x82, 0x6f, 0x8d, 0xa4, 0x62, 0x59, 0xfc, 0xf6, - 0xa9, 0xf3, 0x5f, 0x75, 0x8e, 0x6b, 0x5f, 0xd7, 0x9e, 0xdb, 0x1c, 0x9a, 0x50, 0xc7, 0x11, 0x3a, 0x38, 0xd8, 0xc8, - 0xa0, 0x63, 0x00, 0x3c, 0x72, 0xec, 0x97, 0x5f, 0x3e, 0xcf, 0x8e, 0x19, 0xcd, 0x63, 0x11, 0x85, 0xcc, 0x9d, 0xe7, - 0xe6, 0xec, 0x44, 0x9e, 0x50, 0x35, 0xf5, 0x85, 0x01, 0x8e, 0x8f, 0xb6, 0x52, 0x01, 0xdf, 0xa3, 0xf5, 0x8e, 0x09, - 0x6c, 0xf0, 0x5b, 0x76, 0x52, 0xbb, 0x0a, 0xfa, 0x05, 0x5a, 0xee, 0x62, 0x2a, 0x37, 0x16, 0x38, 0xda, 0x9c, 0xc8, - 0xce, 0xa1, 0x6f, 0xd4, 0x29, 0x59, 0x8f, 0x27, 0xbb, 0x8d, 0xbe, 0xa4, 0xd8, 0x95, 0x5c, 0xd1, 0xb6, 0x21, 0xab, - 0x9e, 0xdc, 0xd5, 0x95, 0xa9, 0x53, 0x75, 0xcd, 0x5b, 0x59, 0xda, 0x94, 0x76, 0x49, 0xf6, 0x6e, 0x8b, 0x85, 0x57, - 0xe1, 0x8d, 0x46, 0x79, 0x11, 0x0a, 0xf6, 0x58, 0x62, 0xd0, 0xe5, 0x04, 0xae, 0x17, 0x56, 0xab, 0x18, 0xfe, 0xec, - 0x1a, 0xc3, 0x2e, 0xd3, 0xa5, 0x0f, 0x7c, 0x83, 0x5f, 0x09, 0xa2, 0xfe, 0x3a, 0x3b, 0x48, 0xb0, 0xee, 0x72, 0x83, - 0x86, 0xe3, 0xc4, 0x7f, 0xc1, 0x9b, 0xd3, 0xda, 0xbb, 0x1c, 0x4c, 0xb2, 0x6f, 0xbc, 0x53, 0x57, 0xb2, 0x96, 0xb5, - 0x90, 0xf1, 0x1b, 0x12, 0x0c, 0xb1, 0x9b, 0xd2, 0x39, 0x6e, 0x25, 0x6d, 0x14, 0xb9, 0x62, 0x15, 0xfa, 0x7f, 0xab, - 0x48, 0x66, 0x33, 0xff, 0xeb, 0xec, 0xec, 0xcc, 0xa5, 0x38, 0x9b, 0x3f, 0x65, 0x3c, 0xe0, 0x4c, 0x02, 0xfb, 0xc2, - 0x33, 0x66, 0x74, 0xc8, 0x6f, 0x61, 0x28, 0x44, 0x90, 0x4b, 0xe1, 0xd8, 0x25, 0x78, 0x32, 0x11, 0x28, 0x0f, 0xb0, - 0x7f, 0x4f, 0x36, 0xca, 0xf9, 0x37, 0x97, 0x7c, 0x4c, 0xe2, 0xb2, 0x41, 0xf6, 0xc5, 0x7c, 0xf6, 0xad, 0x99, 0x0c, - 0x3c, 0x33, 0x10, 0x61, 0xfb, 0xdb, 0xb0, 0xb4, 0xce, 0x52, 0x06, 0x47, 0x5a, 0x2e, 0xb2, 0xa9, 0xd5, 0xfc, 0xbb, - 0x0f, 0x53, 0xd6, 0xbd, 0xd7, 0x03, 0x41, 0xb9, 0xc8, 0xd2, 0x85, 0xd6, 0x8c, 0x7e, 0x2c, 0xa3, 0x68, 0xee, 0xbd, - 0x62, 0x0b, 0xf6, 0x23, 0xde, 0xab, 0x52, 0xe0, 0xe3, 0x61, 0xc1, 0x69, 0xfe, 0x23, 0xde, 0xab, 0xa2, 0x69, 0x82, - 0x2b, 0xa4, 0x09, 0x48, 0x89, 0xcd, 0xdb, 0xd4, 0x69, 0x24, 0x80, 0x82, 0xe6, 0x91, 0x39, 0xc8, 0x9e, 0xbb, 0x00, - 0x8c, 0x49, 0x07, 0xbb, 0xb8, 0x5f, 0x36, 0xac, 0xaa, 0x8d, 0x46, 0x0e, 0x41, 0xe9, 0xca, 0xd9, 0x98, 0xaf, 0x47, - 0x1b, 0x0b, 0x62, 0x94, 0xc9, 0xe4, 0xf2, 0x39, 0x8f, 0xb7, 0x16, 0x0b, 0x85, 0xd5, 0x82, 0x05, 0xaa, 0x55, 0xa9, - 0xd2, 0xc3, 0xe2, 0xdb, 0x05, 0xb3, 0xa0, 0x88, 0xd9, 0x7a, 0x0f, 0x6f, 0xb9, 0x22, 0x20, 0x25, 0xbb, 0x24, 0x78, - 0x5e, 0xdc, 0x60, 0xaa, 0x7f, 0x4d, 0x1e, 0x08, 0x3d, 0x53, 0x3a, 0xc2, 0x26, 0x4f, 0x41, 0x24, 0xb1, 0xfd, 0x16, - 0x76, 0xac, 0xd1, 0x0b, 0xe1, 0x85, 0x14, 0x38, 0x57, 0x4d, 0x13, 0x33, 0xca, 0x4d, 0x74, 0xb1, 0x87, 0x6a, 0xce, - 0x32, 0x6d, 0x11, 0x60, 0xdf, 0xa1, 0xa1, 0x14, 0xcf, 0x0d, 0x28, 0xcc, 0xbb, 0xd8, 0x2e, 0xe5, 0x31, 0x2c, 0x5e, - 0x90, 0x02, 0x44, 0x8d, 0x8b, 0x49, 0x59, 0x67, 0x9e, 0x2f, 0x26, 0x5c, 0x54, 0xc8, 0x50, 0x30, 0x35, 0x97, 0x02, - 0x9e, 0xa5, 0x28, 0x8b, 0x18, 0x3a, 0x54, 0xc3, 0x77, 0x4b, 0xc2, 0xca, 0x3a, 0xe6, 0x98, 0xe2, 0xa2, 0xaa, 0x01, - 0xcc, 0xc5, 0xc3, 0xf0, 0xfd, 0x7a, 0xf5, 0x5a, 0xbc, 0x93, 0xf3, 0x2a, 0xdf, 0xd3, 0x38, 0x1f, 0xfd, 0xdd, 0xd9, - 0x0d, 0xa3, 0xb5, 0x79, 0x39, 0x2a, 0xd8, 0xbe, 0x1f, 0x78, 0xf5, 0x9a, 0xda, 0xda, 0xbc, 0x3d, 0x55, 0x66, 0x0d, - 0x59, 0xf9, 0xd0, 0x42, 0xd5, 0x5e, 0xbd, 0xaa, 0x14, 0xb6, 0x22, 0x40, 0xa5, 0xe0, 0xa3, 0xad, 0xfc, 0x27, 0xda, - 0xe6, 0xdb, 0x73, 0xa8, 0x0c, 0x0f, 0xe4, 0xc9, 0x50, 0xd5, 0x03, 0x2e, 0xca, 0x0f, 0x01, 0x2c, 0x7e, 0x64, 0x82, - 0xf0, 0xee, 0xba, 0x40, 0xe6, 0x4c, 0xc5, 0x12, 0x2f, 0xfb, 0x74, 0x90, 0x5a, 0x79, 0x28, 0x95, 0x60, 0xdb, 0x73, - 0x53, 0x70, 0xed, 0xa3, 0xfd, 0xe2, 0x3e, 0x1b, 0xa4, 0xcb, 0x7a, 0x44, 0x60, 0x1b, 0x93, 0xd8, 0x9b, 0x73, 0x9a, - 0x10, 0xba, 0x74, 0x80, 0x73, 0x02, 0xb6, 0xc7, 0x9e, 0x3d, 0x7d, 0x13, 0x67, 0xa8, 0x57, 0xe7, 0xf0, 0x97, 0x6b, - 0x9c, 0xe3, 0x0c, 0xa5, 0x0f, 0x63, 0xb8, 0xc0, 0x5a, 0x63, 0x00, 0x5f, 0x66, 0x49, 0x15, 0x78, 0xa4, 0x66, 0x46, - 0x62, 0x75, 0x17, 0x81, 0x68, 0xa9, 0xc3, 0xdb, 0x71, 0xe6, 0x63, 0x6a, 0x1b, 0xee, 0xf5, 0x99, 0x11, 0x0e, 0x27, - 0x59, 0x5c, 0x3b, 0x67, 0x38, 0xb9, 0xdc, 0xe7, 0xb5, 0x13, 0x13, 0xac, 0xbd, 0xc3, 0x53, 0x05, 0xf4, 0x68, 0x70, - 0xaa, 0x58, 0x1a, 0x02, 0x31, 0x13, 0xc0, 0x9b, 0x39, 0x3c, 0xda, 0x02, 0x9c, 0x8f, 0xd6, 0x38, 0xf8, 0x4a, 0x6b, - 0x5d, 0x6d, 0x2a, 0x51, 0xd6, 0x6b, 0xdc, 0x9f, 0x66, 0x78, 0x94, 0xe1, 0x79, 0x36, 0x08, 0x8e, 0x9b, 0x59, 0x16, - 0x9a, 0x74, 0xad, 0x56, 0x4f, 0x9d, 0x19, 0x21, 0xb2, 0x3f, 0x2d, 0xfd, 0x41, 0x3d, 0x40, 0xf8, 0x14, 0xb2, 0x80, - 0x96, 0xf4, 0xdc, 0xdf, 0x86, 0x7d, 0x72, 0x1b, 0x35, 0x62, 0x9e, 0x58, 0x32, 0xd2, 0xf3, 0x3f, 0xca, 0x2c, 0xdb, - 0x5a, 0x23, 0x9a, 0xdf, 0xee, 0x45, 0x0d, 0xdf, 0x5e, 0xa0, 0x65, 0x2b, 0xcd, 0x76, 0x00, 0x51, 0xac, 0x71, 0x92, - 0x0e, 0xd6, 0x48, 0xae, 0x56, 0xb1, 0x4d, 0x21, 0x3c, 0x99, 0x31, 0xaa, 0x16, 0x85, 0x79, 0x85, 0x2e, 0x56, 0x28, - 0x31, 0xfc, 0x2e, 0x76, 0x36, 0xa2, 0xf0, 0xe8, 0x9b, 0x04, 0xc3, 0x8d, 0x58, 0x10, 0x59, 0x13, 0xb9, 0x87, 0x59, - 0x65, 0x19, 0x24, 0x88, 0x30, 0x22, 0xbf, 0xbd, 0x2e, 0x15, 0xf6, 0x9d, 0x3b, 0xfb, 0xc7, 0xf8, 0x02, 0xc2, 0xcd, - 0xdb, 0x84, 0x16, 0x43, 0x3a, 0x01, 0x36, 0x16, 0xe2, 0x10, 0x6e, 0x25, 0xac, 0x56, 0xfd, 0x41, 0x57, 0x18, 0xf2, - 0xec, 0x5e, 0xe1, 0x2b, 0x1b, 0xda, 0xdd, 0x00, 0x5c, 0x75, 0x5b, 0x6a, 0xae, 0x8d, 0xee, 0x87, 0x9a, 0x87, 0xc2, - 0xb8, 0x4b, 0x72, 0x6f, 0x7d, 0x54, 0xcf, 0x79, 0xd7, 0x2c, 0xc0, 0x4d, 0xe8, 0x2a, 0x3c, 0xc2, 0x0b, 0x6b, 0xc3, - 0x69, 0x5e, 0x85, 0xa2, 0xe6, 0x31, 0x28, 0x78, 0x83, 0x9a, 0xb0, 0x7e, 0x36, 0xc0, 0x23, 0x1f, 0x33, 0x7c, 0xff, - 0x6d, 0x3c, 0x42, 0xa8, 0x20, 0x06, 0xa6, 0xd6, 0x65, 0x7b, 0x54, 0xd9, 0xed, 0x9b, 0x4c, 0xc3, 0x30, 0x18, 0x23, - 0xe6, 0x51, 0x68, 0xc4, 0x9c, 0x37, 0x1a, 0x68, 0x41, 0x46, 0x60, 0xc4, 0xbc, 0x08, 0x5a, 0x5b, 0xd8, 0x17, 0x43, - 0x83, 0xf6, 0x16, 0x08, 0x75, 0x39, 0xd0, 0x34, 0x0d, 0x6f, 0x83, 0x54, 0x6f, 0xb3, 0xfb, 0x97, 0xaa, 0x8e, 0x3a, - 0xa0, 0x48, 0x18, 0x5f, 0xfa, 0x49, 0x58, 0xd7, 0x70, 0x3b, 0xee, 0xb1, 0x19, 0xb7, 0xb3, 0x6d, 0x50, 0x7d, 0xd9, - 0xcf, 0x06, 0x83, 0xae, 0xf4, 0x56, 0x12, 0x2d, 0x3c, 0xae, 0x5e, 0x13, 0xa9, 0x16, 0xef, 0x8b, 0xde, 0xbc, 0xf2, - 0xe6, 0xfe, 0x91, 0xd2, 0xcd, 0xf3, 0x18, 0x38, 0xa0, 0x7d, 0xb8, 0x1f, 0xaa, 0xe2, 0x83, 0x1d, 0x75, 0x20, 0x0a, - 0x5a, 0xda, 0xaa, 0x09, 0xa4, 0xd6, 0xcc, 0x2e, 0xd6, 0x4d, 0x85, 0x0e, 0x05, 0x84, 0x21, 0x53, 0x55, 0x77, 0x77, - 0x2a, 0x50, 0x0d, 0x71, 0x38, 0xf5, 0x1f, 0x5b, 0x23, 0xd6, 0x38, 0xea, 0x8c, 0x22, 0x63, 0x24, 0x69, 0x97, 0x0f, - 0x1e, 0x10, 0x02, 0x2b, 0x01, 0x1f, 0xc8, 0xd9, 0x24, 0x19, 0x43, 0x82, 0xb7, 0x2c, 0xd3, 0x86, 0x0f, 0xe1, 0x0e, - 0x41, 0x79, 0x62, 0x63, 0x6d, 0xba, 0x4a, 0x16, 0x72, 0x55, 0x97, 0xd7, 0x01, 0x7a, 0xde, 0x95, 0xbf, 0xb1, 0xe1, - 0xc8, 0x82, 0x81, 0x65, 0x5b, 0xfb, 0x04, 0x3c, 0xf2, 0x71, 0x85, 0x20, 0x7e, 0x29, 0x74, 0x62, 0x82, 0x5e, 0x5f, - 0xc1, 0x06, 0xc5, 0x73, 0x70, 0x10, 0x74, 0x12, 0x1c, 0x06, 0xef, 0x32, 0xab, 0x49, 0x36, 0xb8, 0x35, 0x23, 0xf1, - 0x7c, 0xb5, 0x6a, 0xa1, 0xc3, 0x7f, 0xcc, 0xbb, 0xce, 0xe3, 0x52, 0xe1, 0x3e, 0xae, 0x14, 0xee, 0x60, 0x09, 0x48, - 0xc6, 0x81, 0xae, 0x1d, 0xcb, 0x50, 0x8d, 0x0e, 0x21, 0xc7, 0x5f, 0x40, 0x00, 0x6a, 0x77, 0x2c, 0x81, 0x9e, 0x7d, - 0xab, 0x80, 0xd5, 0xb5, 0x97, 0x25, 0x90, 0x11, 0xdc, 0xfd, 0x26, 0x30, 0x2a, 0x44, 0xe3, 0xf3, 0x67, 0x9e, 0x86, - 0xe0, 0x89, 0xf3, 0xe7, 0x9a, 0x19, 0xd6, 0xbd, 0xa0, 0x37, 0xa6, 0xf9, 0x78, 0x8c, 0x9b, 0x63, 0x0b, 0xce, 0xa3, - 0x0e, 0xfc, 0xb4, 0x10, 0x3d, 0xea, 0x60, 0x97, 0x8a, 0xc7, 0x25, 0x90, 0x43, 0xf4, 0x74, 0x06, 0x52, 0xc0, 0x4a, - 0xc7, 0x56, 0x8b, 0x34, 0x41, 0xab, 0xd5, 0xe4, 0x82, 0xb4, 0x10, 0x5a, 0xaa, 0x1b, 0xae, 0xb3, 0x29, 0xf8, 0x48, - 0x83, 0x62, 0xe0, 0x0d, 0xd5, 0xd3, 0x18, 0xe1, 0x31, 0x5a, 0x8e, 0xd8, 0x98, 0x2e, 0x72, 0x9d, 0xaa, 0x1e, 0x4f, - 0x6c, 0x54, 0x5e, 0x66, 0x23, 0xc1, 0x1d, 0x75, 0xf0, 0xc4, 0xf0, 0x97, 0x8f, 0x8c, 0x39, 0x48, 0x91, 0x99, 0xe4, - 0x89, 0x49, 0xc0, 0x3c, 0xc9, 0x72, 0xa9, 0x98, 0x6d, 0xa6, 0x6b, 0x6d, 0xcb, 0x21, 0xae, 0x77, 0xa4, 0x0b, 0x6e, - 0xac, 0x28, 0xa3, 0x74, 0x4a, 0x54, 0x4f, 0x1d, 0x75, 0xd2, 0x09, 0xe6, 0x09, 0x70, 0x7a, 0xef, 0x64, 0xcc, 0x1a, - 0xe5, 0xad, 0xe8, 0x0c, 0x1d, 0x4e, 0xb1, 0xa8, 0x2e, 0x51, 0x67, 0xe8, 0x70, 0x82, 0xf0, 0xac, 0x41, 0x72, 0x05, - 0x1e, 0xc3, 0x5c, 0xfc, 0x1f, 0x29, 0xff, 0xcd, 0x61, 0x43, 0xfc, 0xe8, 0xb7, 0xb0, 0x53, 0xd8, 0x28, 0x4a, 0x73, - 0x02, 0x5e, 0x8b, 0xed, 0x33, 0x9c, 0x91, 0x49, 0x33, 0xf7, 0x01, 0xf7, 0x4c, 0x2b, 0x8d, 0x5b, 0x8d, 0x0e, 0x33, - 0x3c, 0xda, 0x4c, 0x8a, 0xcd, 0x5c, 0x9b, 0x79, 0x9a, 0xc1, 0xf9, 0x5e, 0x8d, 0xc2, 0x95, 0x5f, 0x6c, 0x26, 0x85, - 0xe5, 0x1d, 0x70, 0x9b, 0x23, 0x2c, 0x9a, 0x14, 0xe7, 0x78, 0xd6, 0xfc, 0x8a, 0x67, 0xcd, 0x0f, 0x65, 0x46, 0x63, - 0x81, 0x05, 0x04, 0xef, 0x83, 0x44, 0x3c, 0xab, 0x92, 0x47, 0x58, 0x34, 0x4c, 0x79, 0x3c, 0x6b, 0x54, 0xa5, 0x9b, - 0x0b, 0x2c, 0x1a, 0xa6, 0x74, 0xe3, 0x03, 0x9e, 0x35, 0xbe, 0xfe, 0x8b, 0x49, 0x47, 0x29, 0xa0, 0xcb, 0x1c, 0x2d, - 0x33, 0x3b, 0xc4, 0xab, 0xdf, 0xde, 0xbe, 0x6b, 0x5f, 0x77, 0x0e, 0x27, 0xd8, 0xaf, 0x5f, 0x66, 0x70, 0x2c, 0xd3, - 0x31, 0x6b, 0x02, 0x44, 0x33, 0xdc, 0x39, 0x9c, 0xe2, 0xce, 0x61, 0xe6, 0x9a, 0x5a, 0xcf, 0x1a, 0xe4, 0x56, 0x87, - 0x50, 0xd4, 0x51, 0x1a, 0xc2, 0xc7, 0x4f, 0x36, 0x9d, 0xa0, 0x1a, 0x28, 0xd1, 0xe1, 0xa4, 0x06, 0x2a, 0xf8, 0x5e, - 0xd4, 0xbe, 0xab, 0x7a, 0x15, 0x06, 0x59, 0x28, 0xa1, 0x70, 0xcd, 0x0d, 0x78, 0x6a, 0x29, 0x06, 0x32, 0x61, 0x8a, - 0x05, 0xca, 0x77, 0x40, 0x61, 0x94, 0x27, 0x66, 0xe8, 0xc1, 0x74, 0x4c, 0xe2, 0xff, 0xcf, 0x93, 0x29, 0x87, 0x5e, - 0x6e, 0x99, 0xad, 0xe9, 0xb9, 0xc9, 0x84, 0xc3, 0x07, 0x1e, 0xeb, 0xff, 0xda, 0x81, 0x62, 0x03, 0x52, 0xfc, 0x7f, - 0xe9, 0xe8, 0x42, 0x30, 0x42, 0x56, 0x94, 0x16, 0x0e, 0xf1, 0xbf, 0x3f, 0xac, 0xa0, 0xfb, 0x62, 0xab, 0xfb, 0xc2, - 0x74, 0x1f, 0x36, 0x6d, 0x54, 0x39, 0x69, 0x55, 0xc9, 0x92, 0xff, 0x3a, 0xdd, 0xda, 0x02, 0x8d, 0xa8, 0xd1, 0xb3, - 0x49, 0xd8, 0xe0, 0x7e, 0x3b, 0xdd, 0x81, 0xcc, 0x6b, 0x6e, 0x9f, 0x19, 0x85, 0xc3, 0x37, 0xb8, 0x53, 0xbd, 0x6c, - 0x81, 0xf7, 0xa6, 0x32, 0xfa, 0xca, 0x38, 0xb4, 0x1c, 0x2c, 0x36, 0x4d, 0xb9, 0x8d, 0xb1, 0x74, 0x72, 0x8a, 0x8d, - 0x2b, 0x22, 0x54, 0xba, 0xbd, 0x04, 0xa5, 0xf8, 0x58, 0x37, 0x99, 0xf9, 0xba, 0xd0, 0x89, 0xb9, 0x84, 0x6a, 0x98, - 0xcf, 0xbb, 0x4b, 0x9d, 0x68, 0x39, 0xb7, 0x79, 0x77, 0x17, 0xd0, 0x27, 0x68, 0x58, 0x1b, 0x81, 0xdd, 0x3e, 0x2b, - 0x9c, 0x7e, 0xa7, 0x3a, 0x04, 0xc3, 0x03, 0xc8, 0x91, 0x16, 0xdb, 0x07, 0x36, 0xad, 0x61, 0xd7, 0x45, 0xb3, 0x4c, - 0xb4, 0xad, 0x36, 0x4d, 0xae, 0xdd, 0xc3, 0x7c, 0x1e, 0xf2, 0x14, 0xbc, 0xb0, 0xfa, 0xf1, 0x1d, 0xec, 0xc6, 0x6d, - 0x8d, 0x91, 0xa8, 0x2b, 0x99, 0x4a, 0xe8, 0x27, 0xb7, 0x98, 0x25, 0x77, 0xc6, 0x8b, 0x51, 0x19, 0x7f, 0x1f, 0x13, - 0x74, 0x3f, 0xaa, 0x24, 0x39, 0xb0, 0xec, 0x6f, 0xb0, 0xe4, 0x16, 0xcc, 0x13, 0xcb, 0x6a, 0x12, 0xeb, 0xe4, 0x2e, - 0x58, 0x44, 0x69, 0x1a, 0x59, 0x1b, 0x06, 0xd4, 0x34, 0x63, 0xd5, 0x83, 0xfb, 0x10, 0xe8, 0xa1, 0x57, 0x96, 0xd2, - 0xae, 0xb3, 0xb4, 0xd6, 0xbd, 0x36, 0xdd, 0x6f, 0x0e, 0x28, 0xe0, 0x0b, 0x03, 0xae, 0xe9, 0x5f, 0x4d, 0x22, 0x19, - 0xb2, 0xaf, 0x9c, 0x15, 0x8f, 0x17, 0x85, 0xc1, 0x34, 0xd1, 0xd3, 0x49, 0x36, 0x6f, 0x83, 0xa9, 0x5e, 0x36, 0xef, - 0xdc, 0x62, 0xf7, 0x7d, 0x67, 0xbf, 0xef, 0xb0, 0xe8, 0x31, 0x93, 0x91, 0x32, 0x53, 0xcc, 0x7f, 0xdf, 0xd9, 0xef, - 0x3b, 0xbc, 0x3d, 0x98, 0x1b, 0x7f, 0xa1, 0x58, 0xb2, 0x33, 0x5c, 0x82, 0x09, 0x79, 0xc0, 0xdd, 0xd4, 0xb2, 0x4c, - 0x10, 0xd8, 0x5a, 0x02, 0xc4, 0xf9, 0x7c, 0x1a, 0x57, 0xbc, 0x1a, 0x02, 0xee, 0xd3, 0xbb, 0xb6, 0x57, 0xa9, 0xc0, - 0x63, 0x82, 0x46, 0xc4, 0xc4, 0xb6, 0x31, 0x4f, 0x84, 0x01, 0x97, 0x47, 0x74, 0xa9, 0x27, 0x49, 0x80, 0x57, 0x35, - 0x2a, 0x6f, 0x53, 0xa4, 0xfc, 0x22, 0x41, 0x8e, 0x2f, 0xf6, 0x88, 0x2a, 0x06, 0xb0, 0x2a, 0x4b, 0xfa, 0x04, 0x52, - 0xcf, 0x0f, 0x26, 0xfa, 0x79, 0x13, 0x79, 0xec, 0x63, 0xb9, 0x9f, 0x99, 0x9e, 0x16, 0x72, 0x31, 0x99, 0x82, 0x0f, - 0x2d, 0xb0, 0x0c, 0x85, 0xa9, 0x57, 0xd9, 0xfa, 0xd7, 0x24, 0x37, 0x01, 0x14, 0x4e, 0x37, 0x65, 0x42, 0x33, 0xbd, - 0xa0, 0xb9, 0xb1, 0x24, 0xe5, 0x62, 0xf2, 0x48, 0xde, 0xbe, 0x04, 0xec, 0xa6, 0x44, 0x37, 0x76, 0xe4, 0xbd, 0x85, - 0x1d, 0x80, 0x33, 0xc2, 0x76, 0x55, 0x7c, 0xa8, 0x40, 0xe7, 0x8f, 0x73, 0xc2, 0x76, 0x55, 0x7d, 0xc2, 0x6c, 0xf6, - 0x94, 0x6c, 0x0c, 0xb7, 0x17, 0x67, 0x8d, 0x1c, 0x1d, 0x75, 0xd2, 0xbc, 0xeb, 0x89, 0x81, 0x05, 0x68, 0x00, 0xdc, - 0xad, 0xed, 0x59, 0xde, 0xdd, 0x10, 0xd0, 0xbb, 0x64, 0xd2, 0x5e, 0x97, 0x9b, 0x94, 0xd5, 0xaa, 0x53, 0x51, 0xc1, - 0x02, 0x4f, 0x83, 0xbd, 0x40, 0xed, 0xd7, 0x0e, 0x8a, 0x73, 0x95, 0x6d, 0x9a, 0x9e, 0x97, 0x7d, 0x77, 0x77, 0x2c, - 0x32, 0xb6, 0x69, 0x6f, 0x77, 0x10, 0x09, 0xcb, 0x09, 0xeb, 0x80, 0x13, 0xae, 0x6a, 0x07, 0x04, 0xe8, 0x3a, 0x10, - 0xb9, 0xb1, 0x24, 0xcb, 0x75, 0x65, 0x74, 0x1f, 0xf8, 0xdd, 0x52, 0x22, 0xdd, 0x68, 0x4b, 0x82, 0xe9, 0x13, 0x8c, - 0x9a, 0xce, 0xbc, 0xef, 0x5c, 0x7b, 0xba, 0x78, 0x53, 0xb4, 0xf5, 0x0f, 0x29, 0x63, 0xb3, 0x3d, 0x4c, 0x0c, 0x65, - 0x10, 0x03, 0xbd, 0x8f, 0x78, 0xb7, 0xd1, 0xc8, 0x10, 0x28, 0x64, 0xb2, 0x01, 0x96, 0x89, 0xd7, 0xa2, 0x1f, 0x1c, - 0x18, 0x78, 0x54, 0x09, 0x08, 0x53, 0x10, 0x42, 0xc2, 0xae, 0x0d, 0xc2, 0x86, 0xcb, 0x55, 0xcb, 0x85, 0x8d, 0x54, - 0x1b, 0x3a, 0xf8, 0x7f, 0x85, 0xcb, 0x56, 0xcf, 0x2c, 0x17, 0xc5, 0xe0, 0x66, 0x6e, 0xc0, 0x22, 0x41, 0x7a, 0xb4, - 0xd9, 0x1e, 0x8a, 0xbb, 0x73, 0xb1, 0xd9, 0x10, 0x90, 0x98, 0xc3, 0x04, 0x45, 0xc3, 0xb9, 0x31, 0xc6, 0x2a, 0xa9, - 0xb4, 0xac, 0x35, 0x89, 0x39, 0xf0, 0xa5, 0x0b, 0xd7, 0x7d, 0x79, 0x9b, 0x32, 0x7c, 0x97, 0x0a, 0x7c, 0x03, 0x9e, - 0x34, 0xa9, 0xc4, 0xee, 0xf1, 0x82, 0x62, 0x4d, 0x74, 0xd7, 0xb3, 0xb7, 0x05, 0xac, 0xb3, 0xd9, 0x23, 0x22, 0xf8, - 0x5d, 0xfd, 0x6a, 0x83, 0xef, 0x16, 0xfe, 0x0a, 0xd6, 0xcf, 0xc1, 0x49, 0x8a, 0x45, 0x43, 0x36, 0x0b, 0x77, 0x64, - 0x40, 0xb9, 0x8a, 0x5f, 0x0e, 0x53, 0xb7, 0x8a, 0xe1, 0xda, 0xc7, 0x57, 0xfc, 0x61, 0xa3, 0xdd, 0x86, 0x2a, 0x8b, - 0xdb, 0xbd, 0x29, 0x1a, 0xb2, 0x6a, 0x7a, 0x47, 0xe6, 0x46, 0x4a, 0xfd, 0xeb, 0x03, 0x6e, 0x6d, 0xb5, 0xef, 0xa7, - 0xf9, 0xd6, 0xa3, 0x73, 0xd5, 0xb4, 0x4f, 0xad, 0x15, 0xc1, 0xc1, 0xcf, 0x16, 0x6e, 0x6e, 0x0d, 0x38, 0x80, 0x9f, - 0xbf, 0xa3, 0x79, 0x9c, 0x41, 0x74, 0x7a, 0xab, 0x19, 0x5f, 0xc5, 0x7f, 0x8e, 0x1a, 0x71, 0x2f, 0xfd, 0x33, 0xf9, - 0x73, 0xd4, 0x40, 0x3d, 0x14, 0xcf, 0x6f, 0x57, 0x6c, 0xb6, 0x82, 0x60, 0x6b, 0xf7, 0x8e, 0xf0, 0xeb, 0xb0, 0x24, - 0xd7, 0x34, 0xe7, 0xd9, 0xca, 0xbd, 0xaa, 0xb7, 0x72, 0x4f, 0x0e, 0xad, 0xcc, 0x43, 0x51, 0xab, 0x58, 0x0e, 0x73, - 0x08, 0x2c, 0x1c, 0xef, 0x35, 0x7b, 0xfd, 0x56, 0xf3, 0xc1, 0xc0, 0xfe, 0x6b, 0x22, 0xdc, 0xa3, 0x5a, 0xc4, 0xb6, - 0x37, 0x1b, 0x5b, 0x3f, 0x06, 0xc3, 0x0e, 0x08, 0x05, 0x0e, 0x72, 0xe9, 0xe3, 0x0c, 0x59, 0xdf, 0x93, 0xd5, 0x8a, - 0xb9, 0x68, 0xd6, 0x4e, 0x83, 0x5f, 0xc6, 0x66, 0x3a, 0x6c, 0x27, 0x9d, 0xae, 0x17, 0x63, 0x49, 0x03, 0x22, 0x4d, - 0x63, 0x06, 0x81, 0xa4, 0x96, 0x86, 0xc3, 0x9a, 0xdf, 0x46, 0x69, 0x75, 0x7f, 0x04, 0x29, 0x3f, 0x44, 0x29, 0x3f, - 0x22, 0x10, 0x40, 0xdb, 0x32, 0x47, 0x65, 0x43, 0xde, 0x77, 0xe9, 0x9e, 0x71, 0x66, 0x68, 0xf0, 0xd5, 0xaa, 0x55, - 0x0d, 0x53, 0x14, 0xf5, 0x61, 0x2e, 0xd7, 0x58, 0x90, 0x37, 0xa0, 0x6b, 0x56, 0x44, 0xf4, 0x42, 0x57, 0x79, 0x78, - 0x54, 0x18, 0x4b, 0x02, 0x4e, 0xfa, 0x3d, 0xd1, 0x2b, 0xc8, 0xe5, 0xc3, 0x18, 0x7c, 0xcc, 0x30, 0xef, 0xeb, 0x7e, - 0x31, 0x18, 0xa0, 0xd4, 0x39, 0x9d, 0xa5, 0x26, 0xe2, 0x4a, 0xe0, 0x97, 0x5c, 0x80, 0x5f, 0xb2, 0x42, 0xac, 0x5f, - 0x0c, 0xc8, 0xbd, 0x2c, 0x96, 0xe0, 0x94, 0xbf, 0xc3, 0xe7, 0xf1, 0x61, 0x68, 0x60, 0x6a, 0x86, 0x65, 0x2e, 0xb2, - 0xc1, 0x62, 0xce, 0x5a, 0x02, 0xc1, 0xcd, 0x80, 0xbb, 0xd4, 0x86, 0x44, 0x63, 0x0d, 0x14, 0xdd, 0x46, 0xa1, 0x99, - 0xd1, 0xd3, 0xad, 0x36, 0xfa, 0x91, 0xc3, 0x0b, 0x73, 0x0d, 0x63, 0x11, 0xc8, 0x5c, 0xae, 0x7a, 0xec, 0x2f, 0x3f, - 0x6c, 0x56, 0x18, 0xbc, 0xc2, 0x98, 0xec, 0x94, 0x56, 0x89, 0x66, 0x7c, 0x95, 0x27, 0x8e, 0x21, 0xc8, 0xc4, 0x52, - 0xe9, 0x86, 0x63, 0xe2, 0x4a, 0xfa, 0x4c, 0x0c, 0xd9, 0x6e, 0x78, 0x66, 0x2e, 0x74, 0xb3, 0xfd, 0xc3, 0xb9, 0x9d, - 0x73, 0xc2, 0x8d, 0x56, 0xd2, 0x68, 0xa3, 0x9e, 0x19, 0xaa, 0xea, 0x82, 0xf9, 0x3d, 0x74, 0x5a, 0x5a, 0xec, 0x5c, - 0xbd, 0xbb, 0xe1, 0x13, 0x77, 0x65, 0xfc, 0x2d, 0x56, 0x85, 0x56, 0x64, 0xb8, 0xdd, 0x42, 0xde, 0x9c, 0xe9, 0xa1, - 0x57, 0xe4, 0x42, 0x75, 0xf8, 0x8b, 0xba, 0xc2, 0xbc, 0x7a, 0x19, 0x35, 0x84, 0x47, 0xbf, 0xd7, 0x19, 0x28, 0xff, - 0x60, 0x62, 0x32, 0x67, 0xc9, 0x0d, 0x2d, 0x44, 0xfc, 0xe3, 0x0b, 0x61, 0x62, 0x55, 0xed, 0xc1, 0x40, 0xf6, 0x4c, - 0xc5, 0x3d, 0xb8, 0x35, 0xe1, 0x63, 0xce, 0x46, 0xe9, 0x5e, 0xf4, 0x63, 0x43, 0x34, 0x7e, 0x8c, 0x7e, 0x04, 0x77, - 0x67, 0xf7, 0xc4, 0x62, 0x19, 0x17, 0xc2, 0xdf, 0x63, 0x3d, 0x2c, 0x55, 0xca, 0x58, 0x7b, 0xdd, 0x72, 0x78, 0x21, - 0xf5, 0x26, 0x8b, 0x1f, 0x3a, 0x62, 0x6d, 0x53, 0xb0, 0x0e, 0x29, 0x29, 0x3c, 0xbb, 0x62, 0x6e, 0xb5, 0x98, 0xbb, - 0xd4, 0x12, 0xfe, 0xfa, 0xea, 0x61, 0xa9, 0x82, 0x86, 0x83, 0xd0, 0x95, 0xb6, 0x90, 0x00, 0x03, 0x97, 0xd2, 0xa7, - 0xd3, 0x9d, 0x49, 0x64, 0x96, 0xc5, 0xf0, 0xee, 0x41, 0x05, 0xf3, 0xdf, 0xd9, 0x46, 0x58, 0x15, 0xb8, 0x5c, 0xa9, - 0xa2, 0x5e, 0x4a, 0x02, 0x01, 0xe8, 0x4b, 0xef, 0x41, 0x79, 0x51, 0x74, 0x1b, 0x0d, 0x09, 0x5a, 0x58, 0x6a, 0xae, - 0x55, 0x31, 0xdd, 0x0f, 0x9f, 0x06, 0x0c, 0x3e, 0xbc, 0x43, 0xda, 0xc6, 0xfb, 0x9c, 0x94, 0x50, 0xbb, 0x83, 0xf6, - 0xc1, 0x2a, 0x3b, 0x28, 0xff, 0x36, 0xa6, 0xc8, 0xe6, 0xf7, 0xd9, 0x0f, 0xd4, 0x75, 0x38, 0x70, 0x05, 0xab, 0x5e, - 0xca, 0x28, 0x18, 0xb0, 0x72, 0x0a, 0xd4, 0xde, 0x49, 0x46, 0xb3, 0x29, 0x03, 0x75, 0xbf, 0x2d, 0x5a, 0xcd, 0xed, - 0x49, 0xdd, 0x6f, 0xc8, 0x38, 0xfb, 0x08, 0xe3, 0xec, 0xa3, 0xc0, 0x8b, 0x45, 0x92, 0x3f, 0x64, 0xac, 0x71, 0xac, - 0x9a, 0x02, 0x1d, 0x75, 0x80, 0x3b, 0x03, 0x07, 0x1e, 0xb0, 0x45, 0x39, 0x38, 0xa0, 0xce, 0xe2, 0x9e, 0x36, 0x32, - 0xef, 0xed, 0x09, 0xb5, 0x8b, 0x58, 0xe0, 0x66, 0xcd, 0x4c, 0x0b, 0x5a, 0x2b, 0x8c, 0xf3, 0x78, 0xc0, 0xdb, 0x3c, - 0xab, 0xc5, 0x4f, 0xd8, 0xb0, 0xa6, 0xaa, 0xdf, 0x40, 0x73, 0x54, 0x0b, 0x72, 0xf3, 0xc4, 0x78, 0xab, 0x92, 0x7e, - 0x14, 0x0d, 0x2c, 0xa7, 0x42, 0x0c, 0xc9, 0xe8, 0xb7, 0x06, 0xc1, 0xad, 0xf6, 0x6a, 0xc5, 0x3d, 0xe2, 0x8b, 0x9a, - 0xb7, 0x9a, 0xb9, 0x05, 0xa0, 0x45, 0x1c, 0x95, 0xf7, 0x26, 0x11, 0x78, 0xdf, 0x96, 0x11, 0xd2, 0x96, 0x7d, 0xfb, - 0xfe, 0x63, 0xa9, 0xd8, 0x7c, 0x47, 0x27, 0x83, 0x34, 0xb2, 0x23, 0x8a, 0xf0, 0x75, 0x09, 0x49, 0xb8, 0x4a, 0xba, - 0x56, 0x99, 0x9c, 0x33, 0x95, 0x72, 0x7c, 0x5d, 0x48, 0xa9, 0xaf, 0xec, 0x97, 0xc4, 0xd5, 0x9d, 0x8c, 0xc0, 0xd7, - 0x13, 0xa6, 0xdf, 0xd1, 0x62, 0xc2, 0xc0, 0xaf, 0xc8, 0xdf, 0x8e, 0xa5, 0x94, 0x5c, 0x3e, 0x11, 0x71, 0x9f, 0x62, - 0x78, 0xbc, 0x74, 0x80, 0xb5, 0x09, 0x81, 0x52, 0xe2, 0x22, 0x5c, 0x10, 0xbd, 0x29, 0xe4, 0xed, 0x5d, 0x5c, 0x60, - 0xe7, 0x00, 0x58, 0x3a, 0x4d, 0x02, 0xfc, 0xcb, 0xc7, 0x7c, 0xac, 0xc6, 0x9c, 0x1a, 0x5d, 0xbf, 0xfb, 0x9d, 0x5c, - 0x03, 0xbd, 0x2d, 0x1d, 0x05, 0xfb, 0xad, 0x01, 0xe4, 0xc2, 0x5d, 0x18, 0x5c, 0x7c, 0x85, 0xb5, 0x65, 0x61, 0xbc, - 0xb1, 0x00, 0x7a, 0x7f, 0x67, 0x60, 0xc1, 0x86, 0x39, 0xa6, 0xf0, 0xf2, 0xeb, 0x84, 0xe9, 0x20, 0x2a, 0xc8, 0x93, - 0xf2, 0x6d, 0xcf, 0x5a, 0xed, 0xb7, 0x6c, 0x0c, 0x77, 0x18, 0xc9, 0xb7, 0x0b, 0x27, 0x0e, 0x3c, 0x20, 0xd3, 0x64, - 0xb6, 0xd9, 0x37, 0x3e, 0xf2, 0xc8, 0xeb, 0x71, 0xbc, 0xab, 0xa5, 0x30, 0xdf, 0xac, 0xe8, 0x1a, 0x43, 0x28, 0x8a, - 0xb0, 0xdf, 0x2f, 0x2a, 0xa6, 0xa8, 0x32, 0x68, 0x83, 0x86, 0xe5, 0x8d, 0xf8, 0x05, 0xce, 0x18, 0x5a, 0x2f, 0x64, - 0xef, 0xe8, 0xac, 0xc3, 0x99, 0xc3, 0x8c, 0x29, 0x81, 0x51, 0x69, 0x59, 0xd0, 0x09, 0x38, 0x3a, 0x57, 0x1f, 0x44, - 0xc5, 0xd5, 0xb1, 0x02, 0xf0, 0x24, 0x53, 0xf8, 0x27, 0xdf, 0x04, 0xeb, 0x7e, 0xab, 0x66, 0x98, 0xfa, 0x8b, 0xde, - 0x76, 0x2d, 0x5f, 0x86, 0x38, 0xd2, 0xc6, 0x10, 0x5a, 0xe7, 0xf6, 0x0e, 0x50, 0xc4, 0x05, 0xbd, 0x48, 0x35, 0xbe, - 0x56, 0x8b, 0xa1, 0x59, 0x5f, 0xe3, 0x3a, 0xa6, 0x0d, 0xa2, 0x58, 0x77, 0x4d, 0x7c, 0x5d, 0x3d, 0xa5, 0xaa, 0x52, - 0x05, 0x67, 0x90, 0x40, 0x58, 0x95, 0x97, 0x0d, 0xa9, 0x24, 0x97, 0xa6, 0x53, 0x69, 0x3a, 0xad, 0x10, 0xca, 0xa5, - 0x27, 0xe5, 0xfd, 0x2b, 0x84, 0x30, 0x30, 0x65, 0x76, 0x60, 0x95, 0xda, 0xc2, 0x2a, 0x78, 0xf5, 0x62, 0x03, 0xab, - 0x24, 0x1c, 0xcf, 0x25, 0x1a, 0x15, 0x15, 0x0e, 0x19, 0xd2, 0x17, 0x62, 0x11, 0x24, 0x00, 0x16, 0xbd, 0xcb, 0x5c, - 0xde, 0xf7, 0x70, 0x28, 0xec, 0x49, 0x26, 0xe1, 0x74, 0x13, 0x9a, 0xc3, 0x1b, 0xbb, 0xaa, 0xe7, 0x11, 0x02, 0x96, - 0x9e, 0x63, 0x78, 0x5b, 0xf9, 0xfb, 0x6f, 0xba, 0x3a, 0x0b, 0xf2, 0xf4, 0x5f, 0xa2, 0x24, 0x34, 0xf6, 0x9f, 0xe3, - 0xa1, 0x43, 0xc2, 0x70, 0xe0, 0x9b, 0x23, 0xac, 0x70, 0x70, 0xab, 0x88, 0xcf, 0xe0, 0x0e, 0x1f, 0xeb, 0xd0, 0x03, - 0xc0, 0x12, 0x8a, 0x43, 0x90, 0x6f, 0xa0, 0x98, 0xc1, 0x01, 0x4d, 0x96, 0xe1, 0x05, 0x2e, 0x58, 0x2d, 0x94, 0xf7, - 0xb7, 0x2d, 0x2f, 0xa5, 0xd5, 0x2e, 0x79, 0x8d, 0x39, 0x50, 0xf9, 0x19, 0x5e, 0xf8, 0x0a, 0xf3, 0xe8, 0xb3, 0xfb, - 0xc2, 0xd7, 0x0e, 0xe8, 0x29, 0x04, 0x8c, 0x74, 0xbf, 0xd7, 0x84, 0x7b, 0x8a, 0x5e, 0xe6, 0xe2, 0xb0, 0xed, 0xa0, - 0x7b, 0x81, 0xb9, 0xba, 0xaa, 0xb2, 0xe6, 0x60, 0x0a, 0x0d, 0x0e, 0xaa, 0x70, 0x46, 0x60, 0xae, 0x5e, 0x94, 0x05, - 0xe7, 0x20, 0xde, 0xf7, 0x84, 0xc9, 0x29, 0xa3, 0x01, 0xbc, 0xc8, 0xca, 0x47, 0xa7, 0x7a, 0x1c, 0x5c, 0xc6, 0x0d, - 0x9b, 0xf8, 0x42, 0xf8, 0x54, 0x60, 0x25, 0xad, 0x71, 0x68, 0x44, 0x47, 0x74, 0x0e, 0x66, 0x1b, 0x40, 0xc1, 0xdd, - 0xf9, 0xb0, 0xb1, 0x50, 0xc1, 0xbb, 0xb6, 0xb5, 0x67, 0xa8, 0x09, 0x71, 0x26, 0x4d, 0xc1, 0xdd, 0xb6, 0x41, 0x06, - 0x6f, 0x7e, 0xfb, 0x6f, 0x85, 0x45, 0x82, 0x01, 0x95, 0x9a, 0x24, 0x08, 0x4f, 0x50, 0x1a, 0xe9, 0x56, 0x6e, 0x26, - 0x90, 0x4e, 0x44, 0xcd, 0xa8, 0x7b, 0xe3, 0x7c, 0x75, 0xd4, 0x40, 0x54, 0xd4, 0x40, 0x05, 0xd4, 0x40, 0xd6, 0xb7, - 0x7f, 0x01, 0x0b, 0x61, 0x23, 0x54, 0x89, 0x20, 0x20, 0xc2, 0x5c, 0x1b, 0x3e, 0xa0, 0x48, 0x42, 0xc8, 0x1b, 0x40, - 0xc5, 0x94, 0xbc, 0x04, 0xa3, 0x71, 0x78, 0xbd, 0x07, 0xdc, 0x2f, 0x2d, 0xc3, 0xe0, 0x39, 0x05, 0x93, 0xff, 0xd6, - 0xe7, 0x43, 0xf5, 0x72, 0x75, 0x10, 0xc2, 0x2f, 0x20, 0x56, 0x84, 0xe3, 0x2f, 0x7e, 0x01, 0xb2, 0xa9, 0xb0, 0x3c, - 0x38, 0x90, 0x20, 0xf0, 0x43, 0x14, 0xe1, 0x80, 0x67, 0x78, 0x99, 0x6d, 0x10, 0x3d, 0x3f, 0x2b, 0x55, 0xcd, 0x4a, - 0x06, 0xb3, 0x2a, 0x3c, 0x8d, 0xa3, 0x6b, 0xc2, 0x40, 0x70, 0xa1, 0x76, 0xdf, 0x20, 0x04, 0xca, 0x96, 0x1b, 0x43, - 0x97, 0x9e, 0x82, 0xf9, 0x68, 0x1c, 0xbd, 0x65, 0xf0, 0x3a, 0xaf, 0x31, 0xf9, 0x67, 0x9a, 0x65, 0xda, 0x30, 0x8f, - 0x8d, 0xc0, 0x49, 0x9d, 0xa2, 0xe4, 0x6f, 0xc9, 0x45, 0x1c, 0x35, 0x2f, 0x23, 0xd4, 0x80, 0x7f, 0x1b, 0x1c, 0x75, - 0x69, 0x42, 0x47, 0x23, 0x1f, 0xfc, 0x26, 0x23, 0x66, 0x93, 0xad, 0x56, 0xa2, 0x22, 0xe8, 0x89, 0xdd, 0x60, 0xc0, - 0x4a, 0xbc, 0x00, 0xf6, 0xc1, 0x72, 0xb0, 0xe4, 0x9d, 0x88, 0x95, 0x3f, 0xa5, 0x30, 0x58, 0x3d, 0x67, 0x08, 0xe1, - 0x2c, 0x88, 0xd9, 0xf8, 0x9f, 0xcf, 0x34, 0x5c, 0x3f, 0x3f, 0x5f, 0xc7, 0x88, 0x48, 0x1f, 0x44, 0xae, 0xc6, 0x8e, - 0x88, 0x20, 0x6c, 0x99, 0xee, 0xbb, 0x32, 0x3f, 0x78, 0xeb, 0xea, 0x81, 0x0d, 0x17, 0x07, 0x06, 0xd4, 0x28, 0x30, - 0x5a, 0xc1, 0x39, 0x29, 0x07, 0x0e, 0x4a, 0x08, 0xcd, 0x8a, 0x78, 0x4a, 0x2e, 0x21, 0x12, 0x5e, 0x86, 0xba, 0x60, - 0x58, 0x10, 0x48, 0x50, 0x53, 0x90, 0xa0, 0x32, 0x5f, 0x7b, 0x04, 0xb3, 0xce, 0xcd, 0x6c, 0xa7, 0xa8, 0xeb, 0x82, - 0xfc, 0xfc, 0xa2, 0xe3, 0x11, 0xb0, 0xb4, 0x07, 0x07, 0x05, 0x44, 0x10, 0x03, 0x0a, 0x5e, 0x4a, 0x80, 0x81, 0x06, - 0xbc, 0xd8, 0xd0, 0x80, 0xcf, 0xb5, 0xf1, 0x3a, 0x30, 0xb6, 0x3e, 0x65, 0x90, 0x8b, 0x67, 0xd5, 0x9e, 0x26, 0x84, - 0xec, 0xb7, 0x7a, 0x3a, 0xdd, 0x8e, 0x90, 0xd8, 0xfb, 0xa8, 0x4d, 0xa0, 0x31, 0x47, 0xba, 0xab, 0x8d, 0xf9, 0xb5, - 0xa6, 0x47, 0xac, 0x26, 0x21, 0x5d, 0x90, 0x2e, 0xcf, 0xa7, 0x3d, 0x83, 0x2b, 0x56, 0x69, 0xe4, 0xe0, 0x02, 0xf4, - 0xd9, 0x80, 0x00, 0x05, 0x2a, 0x4d, 0x25, 0x8a, 0x22, 0x2e, 0x92, 0x92, 0x0d, 0xc3, 0x0c, 0xc2, 0x14, 0x56, 0x2b, - 0x41, 0x37, 0xd6, 0x00, 0x78, 0x67, 0x66, 0xff, 0x94, 0x3e, 0xd8, 0x74, 0xed, 0xcd, 0x23, 0x80, 0x80, 0xec, 0xb7, - 0x4b, 0x76, 0x5d, 0x6c, 0x54, 0x66, 0x61, 0x2d, 0x63, 0x2b, 0xb7, 0xed, 0x31, 0xf6, 0x4e, 0x6c, 0xf3, 0x09, 0x10, - 0xa2, 0xb6, 0x64, 0x1a, 0x21, 0x42, 0x62, 0x11, 0xeb, 0xda, 0x90, 0x8d, 0x36, 0xb4, 0x6f, 0x5e, 0xb7, 0x87, 0xd8, - 0x07, 0xa0, 0x78, 0x73, 0x5c, 0x82, 0x43, 0x78, 0xe1, 0x11, 0xfe, 0x16, 0x58, 0xa4, 0x02, 0x33, 0x2c, 0x57, 0x2b, - 0xa8, 0xe7, 0xf1, 0x3e, 0xdb, 0x0c, 0x4e, 0x2a, 0x37, 0xc6, 0x2e, 0xed, 0xc4, 0xe3, 0xb2, 0x09, 0x89, 0x33, 0xe8, - 0xd7, 0x57, 0x44, 0xbd, 0xfd, 0x76, 0xfa, 0xc4, 0xbf, 0x57, 0xe6, 0x76, 0x20, 0x36, 0xac, 0x37, 0x58, 0x7d, 0x00, - 0x2d, 0x7f, 0x95, 0xf9, 0x87, 0xca, 0x82, 0x9b, 0x04, 0xb5, 0xb9, 0x88, 0x5d, 0xd6, 0x45, 0x8c, 0xd4, 0x16, 0x77, - 0x87, 0x10, 0xff, 0x6a, 0x2b, 0x8a, 0x01, 0x4f, 0x2a, 0xfe, 0x39, 0x46, 0x5d, 0x08, 0x45, 0x6d, 0x3d, 0x6c, 0x80, - 0xd2, 0x2e, 0xd7, 0x95, 0x18, 0x19, 0x12, 0xc8, 0xb7, 0x2e, 0xbc, 0xa0, 0x39, 0x89, 0x14, 0xc8, 0xc9, 0x41, 0x54, - 0xd2, 0x6c, 0x43, 0x98, 0xeb, 0x6e, 0xe1, 0x98, 0xb9, 0xda, 0xa0, 0x45, 0xfc, 0x02, 0xd8, 0x19, 0x6e, 0x24, 0x4b, - 0x07, 0x3e, 0x55, 0x03, 0x9f, 0x5f, 0x73, 0x43, 0x51, 0x14, 0xea, 0xbd, 0xb3, 0x8f, 0xcc, 0xc1, 0xef, 0x34, 0x10, - 0x1f, 0xa9, 0xd3, 0x91, 0x6c, 0x84, 0x5a, 0x73, 0x76, 0xbc, 0x6c, 0x33, 0xc2, 0xa0, 0xb0, 0xd1, 0xfb, 0x2a, 0x64, - 0x15, 0x3b, 0x3b, 0x15, 0xc1, 0x9c, 0xbe, 0xa8, 0xca, 0x39, 0x95, 0x5b, 0x46, 0xb5, 0xd4, 0x34, 0x40, 0x84, 0x2b, - 0x9f, 0x48, 0xde, 0x67, 0x26, 0xfc, 0x83, 0xc1, 0xb8, 0x7a, 0xa4, 0xf0, 0xf7, 0xbb, 0x62, 0x87, 0x6c, 0x47, 0x87, - 0xdb, 0x08, 0x9a, 0x17, 0x2a, 0x78, 0xc0, 0x51, 0xc9, 0x12, 0x22, 0x45, 0x2e, 0xf7, 0x55, 0xcd, 0x94, 0xed, 0x3a, - 0x42, 0x08, 0x69, 0x8f, 0xb3, 0x6e, 0x68, 0xf5, 0xd0, 0x23, 0x55, 0x94, 0xc3, 0x2d, 0x9a, 0xeb, 0x02, 0x54, 0x18, - 0x81, 0x74, 0xf9, 0x99, 0xdd, 0xa5, 0x12, 0xa2, 0x97, 0xaf, 0x5d, 0x08, 0x63, 0x67, 0x65, 0x89, 0x0b, 0x33, 0x6a, - 0x1b, 0x46, 0xd7, 0x6d, 0x0c, 0x67, 0x03, 0x63, 0xa6, 0x41, 0x49, 0x0b, 0x42, 0x5d, 0x77, 0xe9, 0x45, 0x66, 0x02, - 0x3d, 0xe6, 0x84, 0x36, 0x18, 0x9e, 0x12, 0x0d, 0x96, 0x4d, 0x05, 0x58, 0xf0, 0x2d, 0x8b, 0xd4, 0xda, 0x6c, 0xb2, - 0xf8, 0xa3, 0x8e, 0xcd, 0xd3, 0x7e, 0x79, 0xc5, 0x3c, 0x17, 0x8e, 0xba, 0x3d, 0xcf, 0x7c, 0x3c, 0xba, 0xa7, 0x6f, - 0xae, 0x5e, 0xbc, 0x7c, 0xfd, 0x6a, 0xb5, 0x6a, 0xb3, 0x66, 0xfb, 0x04, 0xff, 0xa4, 0xcb, 0x78, 0xb0, 0x65, 0x14, - 0xa0, 0x83, 0x83, 0x7d, 0x6e, 0x5c, 0x78, 0x3e, 0xf3, 0x39, 0xc4, 0x0d, 0xd2, 0x03, 0x9c, 0x15, 0x65, 0x4c, 0x90, - 0xdb, 0xa8, 0x17, 0xdd, 0x45, 0xa0, 0x84, 0xaa, 0xc8, 0xdf, 0x87, 0xcd, 0xd9, 0xef, 0x41, 0x60, 0x22, 0xa8, 0x0f, - 0x11, 0x40, 0x20, 0x5e, 0x29, 0x2e, 0x08, 0xf3, 0x09, 0x10, 0xc5, 0x7b, 0x01, 0x9c, 0xa9, 0x89, 0x5a, 0xb5, 0x50, - 0x71, 0x01, 0x24, 0xd1, 0x86, 0xa3, 0xa4, 0x47, 0x26, 0x80, 0x37, 0x04, 0xa5, 0xb4, 0xbf, 0xba, 0xb9, 0x73, 0x97, - 0xca, 0x51, 0xaf, 0x95, 0xe6, 0x78, 0xea, 0x3e, 0xa7, 0xf0, 0x39, 0xed, 0xfa, 0xd3, 0x41, 0x1c, 0xe6, 0x78, 0x41, - 0xc4, 0xa1, 0x7f, 0x16, 0x71, 0x39, 0x2f, 0xd8, 0x17, 0x2e, 0x17, 0x2a, 0x5d, 0xde, 0xa6, 0x32, 0xb9, 0x6d, 0x8e, - 0x0e, 0xe3, 0x22, 0xb9, 0x6d, 0xaa, 0xe4, 0x16, 0xe1, 0xbb, 0x54, 0x26, 0x77, 0x36, 0xe5, 0xae, 0xa9, 0xe0, 0xe6, - 0x0b, 0x0b, 0x38, 0x14, 0x6d, 0xd1, 0xc6, 0x62, 0xb3, 0xa8, 0x4d, 0x71, 0x45, 0x03, 0x0c, 0xfe, 0x7d, 0xc7, 0xc6, - 0x0f, 0xc3, 0x97, 0xe0, 0xd2, 0xa4, 0x89, 0xfc, 0x04, 0xd2, 0x4f, 0xab, 0x32, 0x70, 0x9f, 0x92, 0x56, 0x77, 0x7a, - 0x21, 0x9a, 0xed, 0x6e, 0xa3, 0x31, 0x85, 0xbd, 0x9b, 0x91, 0xdc, 0x17, 0x9b, 0x36, 0x4c, 0x7c, 0x9d, 0xfd, 0x6c, - 0xb5, 0xda, 0xcf, 0x91, 0xd9, 0x70, 0x13, 0x16, 0xeb, 0xfe, 0x74, 0x80, 0x5b, 0xf8, 0x79, 0x86, 0xd0, 0x92, 0xf5, - 0xa7, 0x03, 0xc2, 0xfa, 0xd3, 0x46, 0x7b, 0x60, 0x0d, 0xed, 0xcc, 0x56, 0x5c, 0x43, 0x08, 0xcd, 0xe9, 0xe0, 0xc8, - 0x94, 0x94, 0x2e, 0xdf, 0x7e, 0xd1, 0x2a, 0xa0, 0x9f, 0xaa, 0x05, 0x2f, 0x93, 0xb8, 0x03, 0x7d, 0xd1, 0x0b, 0xfb, - 0x74, 0x6b, 0x41, 0x8e, 0x8f, 0x2a, 0x57, 0x7b, 0x8a, 0xb0, 0xe9, 0x49, 0x1d, 0x16, 0x87, 0xa6, 0x19, 0xd7, 0xa5, - 0x74, 0xdf, 0xa1, 0x66, 0xe4, 0xa3, 0x83, 0x05, 0x20, 0x48, 0x05, 0x8f, 0xac, 0x70, 0xe1, 0x94, 0x42, 0xb8, 0x38, - 0xa8, 0x6c, 0xc1, 0x24, 0x27, 0xad, 0x6e, 0x6e, 0x2c, 0xfd, 0x73, 0x17, 0xd1, 0x94, 0x62, 0x4a, 0x32, 0x5f, 0x32, - 0x37, 0x60, 0xa1, 0x9b, 0x94, 0x67, 0x0a, 0x7a, 0xa5, 0x01, 0x1e, 0x11, 0x88, 0x87, 0xd4, 0x2d, 0x8c, 0x81, 0x57, - 0x3c, 0x6d, 0x16, 0x7d, 0x36, 0x40, 0x47, 0xc7, 0x98, 0xf6, 0xff, 0xca, 0xe6, 0x6d, 0x78, 0x2c, 0xf0, 0xaf, 0x01, - 0x99, 0x36, 0x65, 0x99, 0x20, 0x20, 0x61, 0xd4, 0x94, 0x87, 0xb0, 0x97, 0x10, 0xce, 0x6c, 0xc5, 0xac, 0xcf, 0x06, - 0xcd, 0x69, 0x59, 0xb1, 0xe3, 0x2b, 0x36, 0x64, 0x99, 0x60, 0x2b, 0x36, 0x5c, 0xc5, 0xf0, 0x75, 0x06, 0x03, 0x82, - 0x10, 0x00, 0x0c, 0x00, 0xa0, 0x51, 0x10, 0xcd, 0x17, 0x2b, 0xe2, 0x37, 0xbb, 0xbd, 0xc7, 0x6f, 0x81, 0x05, 0x5a, - 0x6d, 0xff, 0xef, 0x42, 0x19, 0xb0, 0xa7, 0x2c, 0x4c, 0xcc, 0xdc, 0xc2, 0xaa, 0xe8, 0x00, 0x2a, 0x25, 0xc2, 0x14, - 0x06, 0x32, 0xfb, 0x99, 0x81, 0x5a, 0xa0, 0x35, 0xc8, 0xfb, 0x7a, 0xd0, 0xcc, 0xe0, 0x88, 0x81, 0x77, 0x68, 0xc8, - 0xd4, 0x18, 0x13, 0xc6, 0x39, 0x4c, 0x31, 0x33, 0xe0, 0x99, 0xa6, 0xad, 0xb5, 0x34, 0xb2, 0x5c, 0x2f, 0xef, 0xfd, - 0xa3, 0x63, 0xd5, 0x2f, 0x9a, 0xed, 0x01, 0xda, 0x27, 0xc4, 0x7e, 0x0c, 0x60, 0x93, 0xb9, 0xd4, 0x86, 0xf9, 0x3e, - 0xea, 0xa4, 0xf6, 0x13, 0xfe, 0x0c, 0xd6, 0x66, 0x07, 0x80, 0x8e, 0x0c, 0x9b, 0xf5, 0x97, 0x35, 0x95, 0xd7, 0xc7, - 0x9d, 0x51, 0x2a, 0x77, 0xbd, 0x3b, 0x1d, 0x68, 0x8a, 0x43, 0x6f, 0x3d, 0x5c, 0x3e, 0xd4, 0x43, 0xc0, 0x8c, 0xc1, - 0xdc, 0x32, 0xa3, 0xef, 0x85, 0x48, 0x2e, 0x88, 0xc4, 0xd2, 0x60, 0x0d, 0x83, 0xbd, 0x75, 0x70, 0x60, 0xaa, 0xb1, - 0x06, 0x3c, 0x4f, 0x8a, 0x40, 0x30, 0xf0, 0x11, 0x94, 0x01, 0x4d, 0x94, 0xb9, 0x0d, 0x27, 0x1f, 0x99, 0xfb, 0x85, - 0xcb, 0xdb, 0xc7, 0xc2, 0x69, 0x5b, 0xcd, 0xf5, 0x78, 0x59, 0xe0, 0xae, 0xbc, 0x97, 0xb4, 0x0a, 0x6e, 0x64, 0x6f, - 0xf2, 0x94, 0xb9, 0x5b, 0xf7, 0xa5, 0x3a, 0xbb, 0x9b, 0xe9, 0x94, 0xcd, 0x74, 0xb6, 0x9b, 0x09, 0x35, 0x33, 0xdf, - 0xb2, 0x8a, 0x34, 0x27, 0x6b, 0xa2, 0xe6, 0x54, 0xfc, 0x44, 0xe7, 0xa0, 0x1d, 0xe5, 0xf6, 0x5e, 0x15, 0x4e, 0xae, - 0x9c, 0x5c, 0xee, 0xe7, 0x86, 0xb8, 0x22, 0x73, 0xa1, 0x0e, 0x01, 0x5e, 0x5e, 0x94, 0x8f, 0x0f, 0x70, 0x29, 0x7e, - 0x95, 0x23, 0x17, 0xe5, 0x54, 0x48, 0x2d, 0x05, 0x8b, 0x90, 0x41, 0x55, 0x17, 0x03, 0x7b, 0x69, 0xf7, 0x9e, 0xe8, - 0xf1, 0x7e, 0x15, 0x31, 0x6f, 0x60, 0x9e, 0xfb, 0xf8, 0x9e, 0xa6, 0xd8, 0xa9, 0x89, 0x33, 0xf2, 0x21, 0x8b, 0x73, - 0x90, 0xcd, 0xfa, 0xd5, 0x6b, 0xbf, 0x8d, 0x36, 0x2e, 0x9a, 0xb1, 0xe8, 0x99, 0x27, 0x4e, 0x7e, 0x28, 0x8c, 0x71, - 0x80, 0x75, 0xf4, 0x47, 0x98, 0x5a, 0xb0, 0x67, 0x89, 0xa7, 0xd0, 0xc9, 0xad, 0x4d, 0xbb, 0x0b, 0xd3, 0xee, 0x4c, - 0x5a, 0x07, 0xca, 0x01, 0x69, 0x76, 0x65, 0x3a, 0x77, 0xfe, 0xfb, 0x0e, 0x5e, 0xba, 0x5d, 0x43, 0x24, 0xee, 0xf9, - 0x23, 0x63, 0x0c, 0xf1, 0x06, 0x6c, 0x44, 0xd5, 0xc1, 0xc1, 0x1f, 0xce, 0xfb, 0xb6, 0x92, 0xfb, 0xbe, 0x15, 0x0e, - 0x6c, 0x83, 0xa9, 0x74, 0x79, 0x23, 0x99, 0x2d, 0xc0, 0xae, 0x73, 0xff, 0x1b, 0xf1, 0xf0, 0x45, 0xc8, 0xb4, 0x58, - 0x57, 0xf1, 0x57, 0x72, 0x54, 0x7a, 0x88, 0x6a, 0x88, 0x40, 0x5a, 0x59, 0x97, 0x86, 0xa6, 0xa3, 0x57, 0x53, 0x3a, - 0x92, 0x37, 0x6f, 0xa5, 0xd4, 0x03, 0xfb, 0x22, 0xb7, 0x4e, 0xe0, 0xd1, 0xc2, 0x1a, 0x43, 0x73, 0x57, 0x7a, 0x27, - 0xd9, 0x80, 0xa8, 0xf5, 0x71, 0x87, 0x92, 0x48, 0x2c, 0xaa, 0xbb, 0x10, 0x0e, 0x77, 0x21, 0x98, 0x97, 0x41, 0xdb, - 0x20, 0x76, 0xbb, 0x0b, 0xda, 0x06, 0x4e, 0xdd, 0x36, 0x70, 0x7b, 0x30, 0x58, 0xd8, 0xfb, 0xf0, 0x72, 0x2c, 0xc7, - 0xc2, 0x5f, 0x93, 0xd9, 0x07, 0x80, 0x40, 0xed, 0xc3, 0x8a, 0x27, 0x0e, 0x04, 0x89, 0x33, 0x1c, 0x7d, 0xcf, 0xd9, - 0x8d, 0xb5, 0x1c, 0x9e, 0xcd, 0x17, 0x9a, 0x8d, 0xcc, 0x1d, 0x35, 0xa8, 0xf8, 0xea, 0x7e, 0x5e, 0x3f, 0x65, 0x35, - 0xdd, 0xf8, 0x3d, 0x08, 0x23, 0xe1, 0x94, 0x1d, 0x46, 0x21, 0x61, 0x83, 0x59, 0x95, 0xf1, 0xda, 0x7e, 0x83, 0x78, - 0x0f, 0xda, 0x84, 0x13, 0x2c, 0x6a, 0x17, 0x54, 0x11, 0xb6, 0xf1, 0xc6, 0x82, 0x28, 0x0f, 0x6f, 0xb6, 0x8c, 0xa6, - 0x97, 0x6b, 0x08, 0x74, 0xdc, 0x8b, 0x9a, 0x51, 0x83, 0xa5, 0x2e, 0x28, 0xb3, 0x8f, 0x30, 0xae, 0x2e, 0x4e, 0x4c, - 0x9c, 0xf6, 0x52, 0xaf, 0xfe, 0x5b, 0x06, 0x06, 0xf8, 0x02, 0xbc, 0xc4, 0xc2, 0xe8, 0xae, 0x7d, 0xdd, 0x80, 0xfa, - 0xb2, 0xc1, 0x06, 0x68, 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xb9, 0x6b, 0x2e, 0x61, 0xaf, 0xb9, 0x84, 0xbb, 0xe6, 0x12, - 0xfe, 0x9a, 0x4b, 0x98, 0x6b, 0x2e, 0xe1, 0xaf, 0xb9, 0x3c, 0x08, 0x3f, 0x05, 0x71, 0x1c, 0x63, 0x0e, 0x71, 0x15, - 0xb5, 0x8d, 0x8c, 0x07, 0x17, 0x9e, 0xfb, 0x2c, 0x51, 0xe5, 0xf2, 0x87, 0x31, 0xe4, 0xb6, 0x6c, 0x25, 0x8c, 0xdb, - 0x14, 0x53, 0x10, 0x39, 0xfd, 0xe0, 0xa0, 0x74, 0x77, 0x06, 0x1f, 0xf5, 0x94, 0xe3, 0xa5, 0x75, 0xa2, 0xfd, 0x03, - 0x74, 0xf2, 0xe6, 0xd7, 0xc7, 0x54, 0xae, 0x89, 0x70, 0x26, 0xf7, 0xfb, 0x6d, 0x4f, 0x29, 0x3e, 0x65, 0x26, 0x3c, - 0x39, 0x4f, 0xb4, 0x11, 0x41, 0x10, 0xa2, 0x44, 0xe1, 0x8c, 0x48, 0xbb, 0xdf, 0xbd, 0x2b, 0xbc, 0x51, 0x45, 0x79, - 0xb3, 0x92, 0xc7, 0x39, 0x38, 0xb1, 0x1b, 0x2b, 0x0c, 0xd4, 0x05, 0x17, 0x82, 0xcc, 0x24, 0xfc, 0xd1, 0xcc, 0x2d, - 0x39, 0xcb, 0xca, 0xa4, 0x8f, 0xcd, 0xdc, 0x10, 0xb0, 0x82, 0xec, 0x7b, 0x98, 0x2d, 0x6f, 0x53, 0x8a, 0xef, 0xd2, - 0x0c, 0x0f, 0xe5, 0x6d, 0x5a, 0x84, 0xb6, 0x20, 0xfe, 0xe2, 0xef, 0xff, 0x65, 0xef, 0x5d, 0x9b, 0xdb, 0x36, 0xb2, - 0x76, 0xd1, 0xbf, 0x22, 0xb1, 0x6c, 0x06, 0x30, 0x9b, 0x14, 0xe5, 0xbd, 0x67, 0xaa, 0x0e, 0xa8, 0x16, 0xcb, 0xb1, - 0xe3, 0x89, 0x33, 0xf1, 0x65, 0x2c, 0x4f, 0x26, 0x19, 0x16, 0x0f, 0x03, 0x01, 0x4d, 0x01, 0x0e, 0x08, 0x30, 0x00, - 0x28, 0x91, 0x26, 0xf1, 0xdf, 0x77, 0xad, 0xb5, 0xfa, 0x0a, 0x82, 0xb2, 0xe7, 0x7d, 0xf7, 0xfb, 0xe9, 0x9c, 0x2f, - 0xb6, 0xd8, 0x68, 0x34, 0xfa, 0xde, 0xab, 0xd7, 0xe5, 0x79, 0x96, 0x5e, 0x2f, 0x0f, 0x21, 0xde, 0xa7, 0x97, 0xe6, - 0x67, 0x69, 0x2b, 0x0a, 0x70, 0x1f, 0xa1, 0x47, 0x75, 0x20, 0xd8, 0x09, 0x4f, 0x78, 0x00, 0x27, 0xab, 0x59, 0xc5, - 0x9f, 0xa4, 0x20, 0x4e, 0x14, 0x1c, 0x02, 0xae, 0xb6, 0x37, 0xe9, 0x17, 0x30, 0x7c, 0xe9, 0x60, 0xcb, 0xe1, 0x6d, - 0xb1, 0xed, 0xb1, 0x92, 0x7f, 0x00, 0xf6, 0xad, 0x9e, 0x8c, 0xd5, 0xed, 0x81, 0xb3, 0x2e, 0xa5, 0xe8, 0x78, 0x53, - 0x1c, 0xde, 0x9e, 0xcf, 0xf6, 0xdb, 0x20, 0x62, 0xbb, 0x20, 0xc3, 0x5a, 0x27, 0x0d, 0xff, 0x89, 0xb6, 0x0e, 0x16, - 0x23, 0xec, 0xff, 0xb2, 0x1e, 0x78, 0x09, 0xa9, 0xa1, 0xc0, 0xc5, 0x60, 0xc3, 0xd1, 0xda, 0x2e, 0xd3, 0xc0, 0x4d, - 0x0d, 0x7a, 0x7d, 0x4f, 0x21, 0xca, 0x4b, 0x46, 0x73, 0x23, 0x58, 0x37, 0x86, 0x5c, 0x1c, 0x8e, 0x9b, 0xe5, 0x90, - 0x97, 0x34, 0x9d, 0x06, 0xa1, 0x74, 0x67, 0x59, 0x43, 0x12, 0x65, 0x1f, 0x84, 0xda, 0xb5, 0x65, 0xbf, 0x0d, 0x6c, - 0x5f, 0xfe, 0x68, 0x18, 0xfb, 0x17, 0xcb, 0x67, 0x42, 0xba, 0x88, 0xe7, 0x20, 0x88, 0xda, 0xcf, 0xb3, 0xe1, 0xc6, - 0xbf, 0x58, 0x3f, 0x13, 0xca, 0x6f, 0x3c, 0xb7, 0xe5, 0x90, 0x3a, 0x6b, 0xe1, 0x0b, 0xe3, 0xe1, 0xc1, 0x95, 0xa1, - 0xed, 0x70, 0x10, 0xfa, 0x6f, 0xb3, 0x46, 0x70, 0x63, 0x43, 0xfb, 0x7c, 0xe1, 0xc3, 0xd6, 0x46, 0x63, 0x4d, 0x31, - 0xdd, 0x42, 0xff, 0x26, 0xb3, 0xa5, 0x3d, 0x8d, 0x4a, 0x5e, 0x9c, 0x9a, 0x46, 0x2c, 0x84, 0x01, 0x43, 0x3f, 0x99, - 0x0f, 0xa0, 0x9a, 0x3b, 0x1e, 0x81, 0x4c, 0x3e, 0xd0, 0x83, 0x35, 0xa9, 0x55, 0x7f, 0x0d, 0x33, 0xf9, 0x7f, 0xa4, - 0xc2, 0x62, 0x74, 0xb7, 0x0d, 0x33, 0xf5, 0x47, 0x24, 0xff, 0x60, 0x39, 0xdf, 0xa5, 0x5e, 0xa8, 0xfd, 0x58, 0x58, - 0x81, 0x41, 0x89, 0xaa, 0x01, 0x3d, 0x10, 0x41, 0x55, 0x06, 0x69, 0x86, 0xd5, 0x39, 0xe8, 0x77, 0x4f, 0xab, 0x8e, - 0xe4, 0x90, 0xd6, 0x6a, 0x48, 0x05, 0x53, 0xa5, 0x06, 0xf9, 0xe1, 0x70, 0x97, 0x32, 0x5d, 0x06, 0x5c, 0xd2, 0xef, - 0x52, 0xa5, 0x14, 0xfe, 0x13, 0x01, 0xe8, 0x1c, 0xdc, 0xe3, 0xcb, 0x31, 0x90, 0x66, 0x58, 0xf8, 0xad, 0xd9, 0xf1, - 0x35, 0x09, 0xb7, 0x49, 0x70, 0x31, 0xc0, 0x39, 0xba, 0x0a, 0xcb, 0xbb, 0x14, 0x22, 0xa8, 0x4a, 0xa8, 0x6f, 0x65, - 0x1a, 0x94, 0xb6, 0x1a, 0x84, 0x35, 0x09, 0x75, 0x26, 0xd9, 0xa8, 0xb4, 0xdd, 0x28, 0xcc, 0x16, 0x71, 0x3d, 0x23, - 0xac, 0x39, 0x9b, 0xa9, 0x06, 0x26, 0x0d, 0xc7, 0x4d, 0xa3, 0xb5, 0xa8, 0x50, 0x53, 0x98, 0xd7, 0xb8, 0xaa, 0x54, - 0x75, 0x37, 0xa7, 0x96, 0xd2, 0xb2, 0xbd, 0xea, 0x26, 0xd9, 0x90, 0xcb, 0x50, 0x86, 0xc1, 0x46, 0x8e, 0x60, 0x02, - 0x49, 0x72, 0xe6, 0x6f, 0xe4, 0x1f, 0x6a, 0xd3, 0xb5, 0x80, 0x39, 0xc6, 0x2c, 0x1b, 0x16, 0xf4, 0x0a, 0xdc, 0x03, - 0xad, 0xf4, 0x7c, 0x9a, 0x5d, 0xe4, 0x41, 0x32, 0x2c, 0xf4, 0xb2, 0xc9, 0xf8, 0x9f, 0xc2, 0x48, 0x93, 0x19, 0x2b, - 0x59, 0x64, 0xbb, 0x3a, 0x25, 0xce, 0xe3, 0x04, 0xb6, 0x47, 0xd3, 0x5b, 0xbe, 0xcf, 0x20, 0x2a, 0x08, 0x14, 0xcc, - 0x98, 0x2f, 0xbb, 0x78, 0xee, 0xfb, 0xcc, 0x32, 0x75, 0x1f, 0x0e, 0xc6, 0x8c, 0xed, 0xf7, 0xfb, 0x79, 0xbf, 0xaf, - 0xe6, 0x5b, 0xbf, 0x9f, 0x5c, 0x9b, 0xbf, 0x3d, 0x60, 0x50, 0x90, 0x13, 0xd1, 0x54, 0x88, 0xe0, 0x1f, 0x92, 0x67, - 0x48, 0x46, 0x77, 0xdc, 0xe7, 0x96, 0xb3, 0x65, 0x75, 0x04, 0x82, 0x79, 0x38, 0x5c, 0x2a, 0xb0, 0x6b, 0x89, 0x22, - 0x21, 0xcb, 0x7f, 0x06, 0xc6, 0x33, 0xf7, 0x01, 0x96, 0x0c, 0x40, 0xd8, 0x2a, 0x4f, 0xd7, 0x7b, 0xbe, 0x0a, 0xde, - 0xe9, 0x78, 0xd7, 0x58, 0x91, 0x81, 0xb8, 0x05, 0x36, 0x62, 0xad, 0x3d, 0x20, 0x67, 0x0a, 0x70, 0xbc, 0x38, 0x1c, - 0xce, 0xe5, 0x2f, 0xdd, 0x6c, 0x9d, 0x40, 0xa5, 0xc0, 0xed, 0xd1, 0xc9, 0xc1, 0x7f, 0x07, 0x9a, 0x41, 0x39, 0xcc, - 0xeb, 0xed, 0xef, 0xcc, 0xc9, 0x4f, 0x4f, 0xf1, 0x4f, 0x78, 0x88, 0x4e, 0xbf, 0xdd, 0x9b, 0x3f, 0x28, 0x2a, 0x0f, - 0x07, 0xb5, 0xf8, 0xcf, 0x39, 0xaf, 0xe0, 0x17, 0xbe, 0x09, 0xcc, 0x26, 0x53, 0xef, 0xe4, 0x9b, 0x3c, 0x67, 0xea, - 0x35, 0x5e, 0x31, 0xf9, 0x0e, 0x87, 0x73, 0x31, 0xaa, 0xb7, 0x23, 0x27, 0xda, 0x29, 0xc7, 0x38, 0x18, 0xfc, 0x17, - 0xd1, 0x36, 0x21, 0xc0, 0x90, 0xba, 0x25, 0xcd, 0x6c, 0x5c, 0x59, 0xe2, 0x59, 0x3a, 0xbf, 0x9c, 0xd4, 0xe5, 0x4e, - 0x2b, 0x9e, 0xf6, 0xc0, 0xe2, 0xb6, 0x06, 0x2f, 0x80, 0x7b, 0x8b, 0xad, 0x2b, 0x05, 0x87, 0x0b, 0x88, 0x53, 0x9c, - 0x80, 0x08, 0xda, 0xef, 0x4b, 0xbc, 0x57, 0xd0, 0x27, 0xfd, 0x00, 0xc1, 0x90, 0x3f, 0x4b, 0xc0, 0x5d, 0xaf, 0x57, - 0x63, 0x7c, 0x2f, 0x85, 0xe0, 0xfa, 0x4c, 0x03, 0xd0, 0x82, 0xdf, 0xe5, 0x63, 0x39, 0xfd, 0x26, 0x02, 0xcf, 0x96, - 0xbd, 0x89, 0x72, 0xb7, 0xe1, 0x69, 0xff, 0x68, 0x21, 0x00, 0x4b, 0xf1, 0x4c, 0x09, 0x16, 0xe4, 0x14, 0x73, 0xf1, - 0xff, 0x82, 0x8f, 0x98, 0xef, 0x49, 0x17, 0xb1, 0xf5, 0xf6, 0xc9, 0x85, 0x81, 0x04, 0x9a, 0x0e, 0xc0, 0x8f, 0x57, - 0x01, 0x5d, 0x19, 0x3f, 0x3f, 0xcb, 0x7a, 0xac, 0x8f, 0xff, 0x14, 0xdc, 0xa7, 0x9f, 0x29, 0x7c, 0x74, 0x38, 0xae, - 0xd2, 0xd1, 0x8e, 0x52, 0x10, 0x1d, 0xdd, 0x3e, 0x9f, 0xf2, 0xec, 0x9b, 0x0a, 0xc8, 0x2d, 0x47, 0xed, 0xa9, 0x00, - 0x2c, 0xb6, 0x74, 0x04, 0x3e, 0xcd, 0xf2, 0x09, 0xf9, 0x5e, 0x4f, 0xc5, 0xd5, 0xa5, 0x4e, 0x17, 0xd7, 0xe3, 0x29, - 0xfc, 0x0f, 0xc4, 0x1e, 0x96, 0x29, 0xb2, 0x63, 0xd7, 0xc5, 0x0f, 0xe2, 0x6d, 0x6d, 0x47, 0x7f, 0xec, 0x20, 0xd2, - 0x71, 0x4f, 0x2e, 0xd4, 0x97, 0x90, 0x4a, 0x2e, 0xd4, 0x0d, 0xc4, 0x2e, 0xd4, 0x78, 0xc7, 0x45, 0xac, 0xf5, 0xb7, - 0x35, 0x0a, 0x56, 0x02, 0xce, 0xb4, 0xb7, 0x60, 0xb0, 0x81, 0x75, 0xcb, 0x32, 0xf8, 0x1b, 0xae, 0x69, 0x02, 0x37, - 0x2c, 0xb2, 0xde, 0x1b, 0x6c, 0xa5, 0xb7, 0xe0, 0x68, 0x99, 0x38, 0x97, 0x92, 0xac, 0x6c, 0x91, 0x71, 0xf5, 0x28, - 0xa4, 0x6a, 0xba, 0xbf, 0x15, 0xf5, 0x83, 0x10, 0x79, 0xb0, 0x4a, 0x59, 0x54, 0xac, 0x40, 0x66, 0x0f, 0xfe, 0x11, - 0x32, 0x72, 0x94, 0x03, 0x47, 0xa1, 0xbf, 0x35, 0x81, 0xce, 0xf3, 0x53, 0xa8, 0xf3, 0x48, 0xb0, 0x95, 0x7a, 0x28, - 0xac, 0xbc, 0x80, 0xe8, 0x60, 0x0b, 0x63, 0x95, 0x27, 0xa1, 0x62, 0x53, 0x26, 0xf2, 0x38, 0xa8, 0x25, 0x60, 0xac, - 0x20, 0x98, 0xb3, 0x5c, 0xba, 0x20, 0x55, 0x8d, 0x1e, 0x16, 0x99, 0xfb, 0xa9, 0xa0, 0xfc, 0x4f, 0x55, 0x4e, 0xb8, - 0xbe, 0x0c, 0x01, 0x8e, 0xf6, 0x29, 0x88, 0x12, 0x63, 0xfd, 0xa2, 0xc5, 0x3b, 0x99, 0x39, 0x9b, 0xda, 0x5e, 0x82, - 0x8c, 0xed, 0xf0, 0x2b, 0x84, 0x56, 0x0b, 0x45, 0x16, 0x0d, 0x17, 0x4c, 0xb7, 0xa7, 0xb4, 0xea, 0x1e, 0x36, 0x3c, - 0x2b, 0x3d, 0x54, 0xea, 0xdb, 0x98, 0xc0, 0xb2, 0x4a, 0x19, 0xbe, 0x9d, 0x50, 0x75, 0x62, 0x50, 0xb1, 0x6e, 0xd8, - 0x12, 0x0e, 0xb1, 0x98, 0x34, 0xd6, 0xd9, 0x80, 0x47, 0x2c, 0x81, 0x7f, 0x36, 0x7c, 0xcc, 0x96, 0x3c, 0x9a, 0x6c, - 0xae, 0x96, 0xfd, 0x7e, 0xe9, 0x85, 0x5e, 0x3d, 0xcb, 0x9e, 0x46, 0xf3, 0x59, 0x3e, 0xf7, 0x51, 0x71, 0x31, 0x19, - 0x0c, 0x36, 0x7e, 0x36, 0x1c, 0xb2, 0x64, 0x38, 0x9c, 0x64, 0x4f, 0xe1, 0xb5, 0xa7, 0x3c, 0x52, 0x4b, 0x2a, 0xb9, - 0xca, 0x60, 0x7f, 0x1f, 0xf0, 0xc8, 0x67, 0x9d, 0x9f, 0x96, 0x4d, 0x97, 0xee, 0x67, 0x76, 0xdc, 0x85, 0xee, 0x00, - 0x1b, 0x6f, 0x1b, 0x74, 0xe4, 0x5f, 0xef, 0x90, 0x52, 0x37, 0x19, 0x80, 0xdd, 0x68, 0x80, 0x43, 0xa6, 0x7a, 0x29, - 0xb2, 0x7a, 0x29, 0x53, 0xbd, 0x24, 0x2b, 0x97, 0x60, 0x21, 0x31, 0x55, 0x6e, 0x23, 0x2b, 0xb7, 0x6c, 0xb8, 0x1e, - 0x0e, 0xb6, 0x56, 0x5c, 0x36, 0x77, 0x70, 0x5f, 0x58, 0x51, 0xe0, 0xff, 0x2d, 0x5b, 0xb0, 0x7b, 0x79, 0x0c, 0xbc, - 0x45, 0xc7, 0x24, 0xb8, 0x40, 0xdc, 0xb3, 0x5b, 0xb0, 0xc3, 0xc2, 0x5f, 0x70, 0x9d, 0x1c, 0xb3, 0x1d, 0x3e, 0x0a, - 0xbd, 0x82, 0xdd, 0xfa, 0x04, 0xb4, 0x0b, 0xb6, 0x06, 0xc8, 0xc6, 0xb6, 0xf8, 0xe8, 0xee, 0x70, 0x78, 0xeb, 0xf9, - 0xec, 0x01, 0x7f, 0x9c, 0xdf, 0x1d, 0x0e, 0x3b, 0xcf, 0xa8, 0xf7, 0x6e, 0x78, 0xc2, 0xde, 0xf3, 0x64, 0x72, 0x73, - 0xc5, 0xe3, 0xc9, 0x60, 0x70, 0xe3, 0x2f, 0x78, 0x3d, 0xbb, 0x01, 0xed, 0xc0, 0xf9, 0x42, 0xea, 0x9a, 0xbd, 0x5b, - 0x9e, 0x79, 0x0b, 0x1c, 0x9b, 0x5b, 0x38, 0x7a, 0xfb, 0x7d, 0xef, 0x8e, 0x47, 0xde, 0x2d, 0xa9, 0x98, 0x56, 0x5c, - 0x71, 0xbc, 0x6d, 0x71, 0x3f, 0x5d, 0xf1, 0x10, 0x1e, 0x61, 0x55, 0xa6, 0x37, 0xc1, 0x7b, 0x9f, 0xad, 0x34, 0x0b, - 0xdc, 0x03, 0xe6, 0x58, 0x93, 0x9d, 0xd0, 0x4c, 0xfc, 0x15, 0xf6, 0xcf, 0x8d, 0xea, 0x1f, 0x9a, 0xff, 0xa5, 0xee, - 0x27, 0x70, 0xfb, 0x22, 0x0b, 0x12, 0x7b, 0xcf, 0x6f, 0xd8, 0x3d, 0x37, 0x6c, 0xb3, 0x67, 0xa6, 0xec, 0x13, 0xa5, - 0xc6, 0x8f, 0x94, 0xba, 0xb6, 0x0c, 0x2b, 0x99, 0xbb, 0x2f, 0x23, 0x70, 0x38, 0x20, 0x3f, 0xdd, 0x21, 0x0e, 0x42, - 0xeb, 0x26, 0xab, 0xb9, 0xa2, 0x9c, 0x0b, 0x6d, 0x99, 0x79, 0x39, 0xb0, 0x98, 0xa5, 0x14, 0x1a, 0x0b, 0x00, 0x04, - 0x93, 0x42, 0x6b, 0xef, 0x65, 0x00, 0x39, 0x41, 0xc3, 0x1f, 0x9b, 0xab, 0xa2, 0xac, 0x65, 0x4b, 0x42, 0x94, 0xed, - 0x7a, 0x78, 0x89, 0x90, 0x69, 0xfd, 0xfe, 0x39, 0x91, 0xac, 0x4d, 0xaa, 0xab, 0x1a, 0x2d, 0x01, 0x15, 0x59, 0x02, - 0x26, 0x7e, 0xa5, 0xf9, 0x04, 0xe0, 0x49, 0xc7, 0x83, 0xea, 0x29, 0xaf, 0x99, 0x20, 0xb2, 0x8d, 0xca, 0x9f, 0x14, - 0xd7, 0x48, 0x46, 0x50, 0x3c, 0xad, 0x55, 0xc6, 0xc2, 0x30, 0x0f, 0x14, 0x90, 0x77, 0xef, 0x4e, 0x7d, 0x6b, 0x7f, - 0xec, 0xd8, 0xb3, 0xb5, 0x0a, 0xb5, 0x50, 0x53, 0xb8, 0xe4, 0x10, 0x5d, 0x41, 0x06, 0x0a, 0x19, 0x4f, 0x5e, 0x0f, - 0x2e, 0x27, 0xd1, 0x15, 0x17, 0xe8, 0x8c, 0xaf, 0x6f, 0xba, 0xe9, 0x2c, 0x7a, 0x5a, 0xcd, 0x27, 0xa4, 0x24, 0x3b, - 0x1c, 0xb2, 0x51, 0x55, 0x17, 0xeb, 0x69, 0x28, 0x7f, 0x7a, 0x08, 0xbe, 0x5e, 0x50, 0xaf, 0xc9, 0x2a, 0xd5, 0x4f, - 0xa9, 0x52, 0x5e, 0x34, 0xbc, 0xf4, 0x9f, 0x56, 0x72, 0xdf, 0x03, 0xd2, 0x5a, 0x5e, 0x72, 0xf9, 0x7e, 0x84, 0x18, - 0x23, 0x7e, 0xe0, 0x95, 0x3c, 0x62, 0xa1, 0x9a, 0xc2, 0x35, 0x8f, 0x10, 0xe4, 0x2d, 0xd3, 0xc1, 0xdf, 0x7a, 0xe2, - 0x74, 0x7f, 0xa2, 0xb4, 0x8b, 0x2f, 0x2c, 0xea, 0x9e, 0xac, 0xad, 0x1b, 0x90, 0x83, 0x0d, 0xd3, 0x45, 0x41, 0xb6, - 0x29, 0x8d, 0xa0, 0x8d, 0x96, 0x03, 0x1b, 0x4e, 0xa5, 0x36, 0x9c, 0xb9, 0x86, 0xe0, 0x3e, 0x3f, 0x4f, 0x47, 0x0b, - 0xf8, 0x90, 0xea, 0xf6, 0x12, 0x3f, 0x1f, 0x36, 0x3c, 0x02, 0x32, 0x3b, 0xe2, 0x33, 0x9b, 0x48, 0x3a, 0xa9, 0x73, - 0x05, 0xec, 0x76, 0xf6, 0x16, 0xe4, 0x88, 0x99, 0xfb, 0x0a, 0xd5, 0xb7, 0x68, 0xc0, 0x95, 0xb1, 0xf6, 0x35, 0xc9, - 0x58, 0x78, 0x55, 0x4e, 0xc3, 0x01, 0xc0, 0xd0, 0x65, 0xf4, 0xb5, 0xe5, 0x26, 0xcb, 0x7e, 0x2e, 0x20, 0x08, 0xa2, - 0x24, 0x1e, 0x1f, 0xf0, 0xbe, 0xac, 0x86, 0x1a, 0x25, 0x1f, 0xcb, 0x46, 0x2a, 0xbd, 0x12, 0xfd, 0xdd, 0x98, 0x4b, - 0x0c, 0xf8, 0xb6, 0x6a, 0x0b, 0x0a, 0xe7, 0xf9, 0xe1, 0x70, 0x9e, 0x8f, 0x8c, 0x67, 0x19, 0xa8, 0x56, 0xa6, 0x75, - 0x10, 0x9b, 0xf9, 0x62, 0xe1, 0x2f, 0x76, 0x4e, 0x22, 0xa2, 0x20, 0xb0, 0x23, 0xe1, 0x41, 0xa4, 0x7e, 0x59, 0x79, - 0xba, 0x53, 0x7d, 0xb6, 0x5f, 0xd8, 0x44, 0x7a, 0x41, 0xc9, 0xe4, 0x93, 0x60, 0xaf, 0xfa, 0x3b, 0x08, 0x1b, 0xc2, - 0x9b, 0x57, 0xbd, 0xce, 0x32, 0x35, 0x2b, 0x41, 0xc2, 0x8c, 0x39, 0x82, 0xc7, 0x61, 0xa7, 0xb1, 0x0d, 0x8f, 0x2d, - 0x38, 0x3a, 0x6f, 0xcd, 0xee, 0xd8, 0x8a, 0xdd, 0xaa, 0x3a, 0x2d, 0x78, 0x38, 0x1d, 0x5e, 0x06, 0xb8, 0xfa, 0xd6, - 0xe7, 0x9c, 0xdf, 0xd1, 0x09, 0xb6, 0x1e, 0xf0, 0x68, 0x22, 0x66, 0xeb, 0xa7, 0x91, 0x5a, 0x3c, 0xeb, 0x21, 0x5f, - 0xd0, 0xfa, 0x13, 0xb3, 0x3b, 0x93, 0x7c, 0x37, 0xe0, 0x8b, 0xc9, 0xfa, 0x69, 0x04, 0xaf, 0x3e, 0x05, 0x2b, 0x46, - 0xe6, 0xcc, 0xb2, 0xf5, 0xd3, 0x08, 0xc7, 0xec, 0xee, 0x69, 0x44, 0xa3, 0xb6, 0x92, 0xfb, 0xd2, 0x6d, 0x03, 0xc2, - 0xca, 0x2d, 0x8b, 0xe1, 0x35, 0x10, 0xcf, 0xb4, 0x91, 0x74, 0x2d, 0x0d, 0xbd, 0x31, 0x0f, 0xa7, 0x71, 0xb0, 0xa6, - 0x56, 0xc8, 0x33, 0x43, 0xcc, 0xe2, 0xa7, 0xd1, 0x9c, 0xad, 0xb0, 0x22, 0x1b, 0x1e, 0x0f, 0x2e, 0x27, 0x9b, 0x2b, - 0xbe, 0x06, 0xf2, 0xb3, 0xc9, 0xc6, 0x6c, 0x51, 0xb7, 0x5c, 0xcc, 0x36, 0x4f, 0xa3, 0xf9, 0x64, 0x05, 0x3d, 0x6b, - 0x0f, 0x98, 0xf7, 0x1a, 0x44, 0x28, 0x09, 0xa9, 0x29, 0x37, 0xbd, 0x1e, 0x5b, 0x8f, 0x83, 0x3b, 0xb6, 0xbe, 0x0c, - 0x6e, 0xd9, 0x7a, 0x0c, 0x44, 0x1c, 0xd4, 0xef, 0xde, 0x06, 0x16, 0x5f, 0xc4, 0xd6, 0x97, 0x26, 0x6d, 0xf3, 0x34, - 0x62, 0xee, 0xe0, 0x34, 0x70, 0xc1, 0xda, 0x64, 0xde, 0x8a, 0xc1, 0x25, 0x64, 0xe9, 0xc5, 0x6c, 0x33, 0xbc, 0x64, - 0xeb, 0x11, 0x4e, 0xf5, 0xc4, 0x67, 0x77, 0xfc, 0x96, 0x25, 0x7c, 0xd5, 0xc4, 0x57, 0x1b, 0xd0, 0x88, 0x1e, 0x65, - 0xd0, 0x57, 0x50, 0x33, 0x73, 0x5e, 0x5a, 0x18, 0x95, 0xfb, 0x16, 0x1c, 0x50, 0x90, 0xb6, 0x01, 0x82, 0x24, 0x9e, - 0xdd, 0xcb, 0x70, 0x7d, 0x23, 0x85, 0x01, 0x37, 0x81, 0x19, 0x30, 0x30, 0xfd, 0x0c, 0x7e, 0x58, 0xe9, 0x12, 0x21, - 0xce, 0x7e, 0x4a, 0x49, 0x32, 0xcf, 0x4f, 0x45, 0x9a, 0xbb, 0x85, 0xeb, 0x14, 0x66, 0x45, 0x81, 0xea, 0xa7, 0xa4, - 0x34, 0xb0, 0x50, 0x89, 0x4c, 0xa5, 0xe0, 0x97, 0xcd, 0x79, 0x94, 0x1d, 0xa3, 0x73, 0x9d, 0x5f, 0x4e, 0x9c, 0xd3, - 0x49, 0xdf, 0x7f, 0xe0, 0x18, 0xb6, 0x90, 0x81, 0x0b, 0x7f, 0xea, 0x09, 0xe3, 0xd4, 0x0a, 0xc4, 0x54, 0xf2, 0xec, - 0x29, 0x7c, 0x26, 0xb4, 0x3a, 0xba, 0xf0, 0xfd, 0xa0, 0xd0, 0x26, 0xe9, 0x16, 0x24, 0x29, 0x78, 0x8a, 0x9e, 0x73, - 0xde, 0x06, 0x2a, 0xc5, 0x88, 0x16, 0x44, 0xda, 0x5a, 0x66, 0x0e, 0xd2, 0x96, 0xe6, 0xbb, 0x26, 0x7e, 0x0e, 0x0b, - 0xb8, 0x88, 0x16, 0xb6, 0x86, 0x47, 0x55, 0xac, 0xdc, 0x9b, 0x3c, 0x47, 0x38, 0xa3, 0x4b, 0x99, 0x00, 0xb8, 0xde, - 0xaf, 0xc2, 0x5a, 0xe1, 0x15, 0x35, 0x8b, 0xbc, 0xa8, 0xe9, 0x93, 0x2d, 0x70, 0x1f, 0x8b, 0x12, 0x05, 0xce, 0x5a, - 0x30, 0x60, 0x2b, 0x2c, 0xd9, 0x49, 0x61, 0x53, 0xb4, 0x84, 0xde, 0x1e, 0x3f, 0x1d, 0xd4, 0x4c, 0x06, 0xd0, 0x04, - 0xd0, 0x78, 0xfc, 0x0b, 0x40, 0x4d, 0x6f, 0x6a, 0xb1, 0xae, 0x82, 0x52, 0x29, 0x37, 0xe1, 0x67, 0x60, 0x98, 0xe1, - 0x87, 0x42, 0x6e, 0x13, 0x25, 0x72, 0x7e, 0x2c, 0x4a, 0xb1, 0x2c, 0x45, 0x95, 0xb4, 0x1b, 0x0a, 0x1e, 0x11, 0x6e, - 0x83, 0xc6, 0xcc, 0xed, 0x89, 0x2e, 0x5a, 0x11, 0xca, 0xb1, 0x59, 0xc7, 0x48, 0xa3, 0xcc, 0x4e, 0x76, 0x9d, 0x2c, - 0xb4, 0xdf, 0x57, 0x39, 0x64, 0x1d, 0xb0, 0x46, 0xf2, 0xf5, 0x9a, 0x43, 0xb7, 0x8d, 0xf2, 0xe2, 0xc1, 0xf3, 0x15, - 0x9c, 0xe6, 0x78, 0x62, 0x77, 0xbd, 0xee, 0x14, 0x89, 0x78, 0x85, 0x93, 0x2a, 0x1f, 0xc9, 0xc2, 0x71, 0xe7, 0x4e, - 0x6b, 0xb1, 0xaa, 0x5c, 0xd6, 0x53, 0x8b, 0x23, 0x02, 0x9f, 0xca, 0xa3, 0xbd, 0xd0, 0xb6, 0x28, 0x16, 0xc2, 0xe8, - 0xd1, 0x09, 0x3f, 0x29, 0x81, 0xf5, 0x75, 0x38, 0x2c, 0xfd, 0x88, 0xa3, 0xdf, 0x69, 0x34, 0x5a, 0x10, 0xd2, 0xf0, - 0xd4, 0x8b, 0x46, 0x8b, 0xba, 0xa8, 0xc3, 0xec, 0x3a, 0xd7, 0x03, 0x85, 0x61, 0x04, 0xea, 0x07, 0x57, 0x19, 0x7c, - 0x16, 0x21, 0x6a, 0x1e, 0x98, 0x66, 0x43, 0x38, 0xea, 0x02, 0x0f, 0xad, 0xa0, 0xc5, 0xcc, 0x7c, 0x14, 0x62, 0xf8, - 0x90, 0x2e, 0xce, 0x9f, 0x90, 0x95, 0x0f, 0xb0, 0x3b, 0x74, 0x17, 0xca, 0x39, 0x53, 0x31, 0xc0, 0x8f, 0x02, 0xf2, - 0x51, 0x02, 0x6e, 0x06, 0xc8, 0x1e, 0x59, 0x02, 0x88, 0x15, 0xa3, 0xa3, 0xc9, 0xe7, 0xbe, 0x17, 0x29, 0x78, 0x67, - 0x9f, 0xe5, 0x6a, 0xc2, 0x50, 0xf8, 0xc4, 0x40, 0x37, 0xbf, 0xf1, 0xdb, 0xf3, 0x16, 0x8c, 0xec, 0x92, 0x14, 0xaf, - 0x35, 0xc3, 0xfd, 0x06, 0xdc, 0x8e, 0x80, 0xb2, 0xa6, 0x3a, 0x26, 0xd9, 0xa6, 0x21, 0x92, 0x01, 0x33, 0x62, 0x44, - 0x50, 0x59, 0x2e, 0xfc, 0xef, 0x5e, 0x16, 0x05, 0x0e, 0xe0, 0x6a, 0x26, 0x83, 0xd7, 0x2e, 0x8c, 0x0a, 0x80, 0x73, - 0x1a, 0x3a, 0xa5, 0xbd, 0xaa, 0x3a, 0x24, 0xab, 0xe6, 0x07, 0xb3, 0x79, 0xd3, 0x30, 0x31, 0x22, 0x88, 0x2e, 0xc2, - 0x09, 0xa6, 0x57, 0xa4, 0xaf, 0x95, 0x9c, 0x8e, 0x56, 0x1d, 0xad, 0x25, 0x26, 0xe6, 0x8a, 0xe2, 0xaf, 0x01, 0x8f, - 0x1b, 0xbc, 0x3a, 0x49, 0xd3, 0x89, 0xea, 0xd1, 0xe3, 0xd7, 0x69, 0x3a, 0x29, 0x71, 0x57, 0xf8, 0x0d, 0xb8, 0x68, - 0xb6, 0xf9, 0xd0, 0x8f, 0x5f, 0x50, 0xc4, 0x45, 0x0d, 0xae, 0xbc, 0x53, 0x7d, 0xa5, 0xfa, 0x08, 0x6a, 0xe1, 0x89, - 0x91, 0xb5, 0xf0, 0xe4, 0x92, 0xb5, 0x16, 0x04, 0x33, 0x9b, 0x03, 0x17, 0xf2, 0x2b, 0xa5, 0x88, 0x37, 0x91, 0x50, - 0x8b, 0x41, 0xeb, 0x31, 0x73, 0x56, 0x8d, 0x16, 0x2a, 0x33, 0x42, 0xfb, 0xb6, 0x16, 0x9d, 0xdf, 0xc8, 0x4f, 0x79, - 0x6a, 0x5f, 0xb6, 0xc7, 0xf9, 0x78, 0x8f, 0xee, 0xaa, 0xb3, 0xcc, 0xa4, 0x8c, 0x4f, 0x66, 0x09, 0x0a, 0x77, 0x09, - 0x36, 0x20, 0xc9, 0x7e, 0xad, 0x03, 0x64, 0xd4, 0x5e, 0xfb, 0x5d, 0x67, 0xf9, 0xea, 0x66, 0x6b, 0x28, 0x2a, 0xb5, - 0x92, 0x14, 0x07, 0x19, 0xae, 0xdb, 0xca, 0x87, 0x8b, 0x0b, 0xe8, 0x19, 0x23, 0x91, 0x79, 0xfe, 0x44, 0xbe, 0x04, - 0xe7, 0x8c, 0xb3, 0x42, 0x60, 0xc2, 0x58, 0xbd, 0x6b, 0x2d, 0x95, 0x86, 0x14, 0x63, 0x47, 0xa3, 0x2c, 0xab, 0x2c, - 0x5d, 0x66, 0x6b, 0x09, 0x5b, 0x96, 0x93, 0x5b, 0xd8, 0x32, 0x93, 0xd5, 0x7c, 0x5f, 0x71, 0x07, 0xe5, 0x9b, 0xad, - 0x33, 0xbe, 0x97, 0xc8, 0xde, 0x6d, 0xa0, 0x84, 0xeb, 0xd1, 0x5f, 0x90, 0x7e, 0x9b, 0x61, 0x9c, 0x72, 0x5b, 0x49, - 0x0b, 0x70, 0xfa, 0x87, 0xc3, 0xfb, 0x0a, 0x83, 0x06, 0x47, 0x18, 0x47, 0xd6, 0xef, 0xdf, 0x56, 0x5e, 0x8d, 0x89, - 0x3a, 0x3e, 0xab, 0xdf, 0xaf, 0xe8, 0xe1, 0xb4, 0x1a, 0xad, 0xd2, 0x2d, 0xb2, 0x13, 0xda, 0x58, 0xf9, 0x41, 0xad, - 0x80, 0xd9, 0x5b, 0x9f, 0x4f, 0x07, 0xa0, 0x63, 0x01, 0x12, 0xcd, 0x66, 0x22, 0x31, 0x27, 0xdd, 0x93, 0xf0, 0xf8, - 0xc0, 0x02, 0x07, 0x98, 0x8a, 0xff, 0x53, 0x78, 0x33, 0xb0, 0x41, 0xa3, 0x44, 0x5f, 0xa3, 0xab, 0xda, 0xdc, 0xe8, - 0x78, 0xe9, 0x29, 0x24, 0xb2, 0x82, 0x55, 0x73, 0x5f, 0x6e, 0xe0, 0xb4, 0x87, 0x9a, 0x43, 0x65, 0x09, 0xfe, 0xf6, - 0xcb, 0xfc, 0x70, 0x58, 0x67, 0x50, 0xd8, 0x6e, 0x2d, 0xb4, 0x37, 0x66, 0xa9, 0x86, 0x8a, 0x70, 0xd0, 0xf9, 0x4a, - 0xcc, 0xea, 0x11, 0xfd, 0x3d, 0x3f, 0x1c, 0x56, 0x04, 0x06, 0x1c, 0x96, 0x32, 0x13, 0x2d, 0x14, 0x4b, 0xeb, 0x6c, - 0x46, 0x75, 0xe0, 0x81, 0x89, 0x39, 0x0b, 0x77, 0x00, 0xda, 0xa4, 0x56, 0x81, 0x5e, 0x45, 0xf4, 0x13, 0xf7, 0x6b, - 0xfb, 0xf5, 0x7a, 0x64, 0x96, 0x8e, 0xdc, 0x18, 0x0b, 0x00, 0x0e, 0x3c, 0xaf, 0x49, 0x9e, 0x93, 0xaf, 0xa1, 0xdd, - 0x93, 0x0b, 0xf9, 0x13, 0x94, 0x2d, 0x3c, 0x57, 0x4d, 0x2b, 0x8b, 0x15, 0x57, 0xd5, 0xab, 0x0b, 0x5e, 0x99, 0x4c, - 0xab, 0xb4, 0x12, 0x95, 0x12, 0x0c, 0xa8, 0x4b, 0xbc, 0xd6, 0x34, 0xa3, 0xd4, 0x46, 0x9d, 0x89, 0x1a, 0xb0, 0xc1, - 0x7e, 0xaa, 0x36, 0x3a, 0x39, 0x97, 0xcf, 0x2f, 0x8d, 0xc3, 0xa7, 0x5d, 0xbd, 0x99, 0xa9, 0x1c, 0xf8, 0x6b, 0xe5, - 0x43, 0xab, 0xc7, 0x40, 0x07, 0xe4, 0xf4, 0xc7, 0xb0, 0x98, 0xd8, 0x1d, 0x9a, 0xb7, 0xbb, 0xcb, 0xea, 0x22, 0xbd, - 0xd3, 0x94, 0xcc, 0xea, 0x2d, 0x9f, 0x59, 0x3d, 0x3a, 0xe0, 0xc5, 0x63, 0xbd, 0x57, 0x98, 0x49, 0x04, 0x17, 0x43, - 0x35, 0x89, 0xec, 0x0e, 0xb4, 0xe6, 0x51, 0xc5, 0x04, 0xf8, 0x41, 0xa9, 0x35, 0xbd, 0xb7, 0xbb, 0x42, 0x9d, 0x52, - 0x78, 0xdc, 0x5a, 0xf2, 0x03, 0x73, 0xa7, 0x5d, 0xeb, 0x7c, 0x3c, 0xbf, 0xf4, 0xfd, 0x46, 0x9e, 0xd0, 0x66, 0x67, - 0x72, 0xfa, 0x27, 0x6f, 0xf5, 0x0f, 0x53, 0x7d, 0x0b, 0xdd, 0x09, 0xfa, 0x0c, 0x5d, 0x55, 0xdd, 0x95, 0xd8, 0xc2, - 0x50, 0x4f, 0x2c, 0xf2, 0x42, 0x9e, 0xb4, 0xc6, 0x8e, 0x83, 0xbd, 0x01, 0x4e, 0xfc, 0xf2, 0x70, 0x10, 0x57, 0xb9, - 0xcf, 0xce, 0xbb, 0x46, 0x56, 0x0e, 0x60, 0x05, 0x51, 0x30, 0x6e, 0xcd, 0xc7, 0x36, 0x48, 0x97, 0xb8, 0x1a, 0x1f, - 0xbf, 0xa1, 0x58, 0x26, 0x9b, 0x88, 0x8b, 0x8b, 0xfc, 0xe9, 0x73, 0x20, 0x2d, 0xeb, 0xf7, 0xa3, 0xeb, 0xcb, 0xe9, - 0xf3, 0x61, 0x14, 0x80, 0x63, 0x97, 0xbd, 0xbc, 0x8c, 0xf9, 0xea, 0x92, 0x59, 0xa6, 0xb0, 0xc8, 0x37, 0x03, 0xaa, - 0x4b, 0x56, 0x4b, 0xd7, 0x2b, 0xc0, 0xd2, 0xe5, 0x37, 0x0f, 0x61, 0x6a, 0x40, 0x23, 0x6b, 0xee, 0x4e, 0x73, 0x2d, - 0x50, 0xea, 0x79, 0x3f, 0x33, 0xe4, 0xeb, 0x32, 0xe8, 0x0a, 0xd2, 0x3d, 0x8f, 0x48, 0x2f, 0xf7, 0xd2, 0xe9, 0x7e, - 0x5f, 0x0a, 0xb0, 0xd4, 0x97, 0xe2, 0x33, 0x28, 0x2c, 0x1a, 0xdf, 0x08, 0xd0, 0xd6, 0x50, 0x4d, 0x7b, 0xa5, 0xa8, - 0x7a, 0x41, 0xaf, 0x14, 0x9f, 0x7b, 0x7a, 0xa8, 0xcc, 0x97, 0xa5, 0xa3, 0xff, 0x09, 0x35, 0x17, 0x9c, 0x10, 0x33, - 0x31, 0x07, 0x50, 0x09, 0xda, 0xf8, 0x56, 0x47, 0x1b, 0x9f, 0xea, 0x55, 0xdc, 0xf4, 0x79, 0x6d, 0x2d, 0x73, 0x42, - 0xd8, 0x74, 0x2f, 0x01, 0x2a, 0xf2, 0x4a, 0x78, 0x04, 0xcb, 0x2f, 0x7f, 0xc8, 0xd3, 0x15, 0xa2, 0x75, 0xdc, 0xb3, - 0xcc, 0xa5, 0xb1, 0x7f, 0x6d, 0x30, 0x7d, 0x7d, 0xbb, 0x2d, 0xf2, 0x53, 0x13, 0x13, 0xd6, 0x63, 0x45, 0xdf, 0xbc, - 0x0b, 0x57, 0x02, 0x05, 0x0e, 0x25, 0x12, 0xdb, 0x54, 0xa1, 0x88, 0x07, 0x49, 0x9f, 0x2e, 0x5a, 0x9f, 0x06, 0x98, - 0x5a, 0xcb, 0x81, 0x39, 0x84, 0xab, 0xb8, 0xf0, 0xd1, 0xd3, 0xb7, 0x98, 0x85, 0xf3, 0x89, 0xf7, 0xd1, 0x2b, 0x46, - 0xe6, 0xe3, 0x3e, 0x2a, 0x95, 0xf4, 0xcf, 0xc3, 0x61, 0x56, 0xcd, 0x7d, 0x87, 0x3e, 0xd2, 0x43, 0x95, 0x0b, 0xca, - 0xde, 0x18, 0x93, 0x08, 0x94, 0xc6, 0x78, 0x1f, 0x07, 0xc7, 0x79, 0x9f, 0x06, 0x90, 0xda, 0x27, 0xde, 0x93, 0x92, - 0xc3, 0x73, 0x8e, 0x39, 0xa1, 0xb4, 0x22, 0xac, 0xe2, 0x8b, 0x0c, 0xe5, 0xba, 0x53, 0x0a, 0x26, 0x39, 0x24, 0x18, - 0xfe, 0xaa, 0x79, 0x13, 0x2b, 0x10, 0x76, 0xcd, 0xbc, 0x1a, 0x3d, 0xa9, 0x92, 0xb0, 0x14, 0x70, 0x54, 0x66, 0x9e, - 0x61, 0x6f, 0x78, 0x62, 0x18, 0x39, 0x58, 0xee, 0x8f, 0xea, 0x44, 0xe4, 0x1e, 0x5d, 0x60, 0x54, 0x16, 0x9e, 0x37, - 0x74, 0xa5, 0x41, 0x25, 0xd9, 0xf1, 0x57, 0x5c, 0x03, 0x6a, 0x6b, 0x8c, 0x18, 0x0a, 0x18, 0x05, 0xaf, 0xed, 0x0f, - 0x21, 0x8b, 0xb2, 0xf5, 0x1b, 0x1c, 0xf3, 0x59, 0xc9, 0x5d, 0xef, 0x70, 0x16, 0x5a, 0x42, 0x9e, 0xdc, 0x31, 0x48, - 0xd3, 0x58, 0x1a, 0x01, 0x27, 0x22, 0xd9, 0xc6, 0x52, 0x38, 0x02, 0x08, 0x08, 0x74, 0x53, 0x66, 0x18, 0xd3, 0xc1, - 0xc8, 0xf3, 0xa4, 0x67, 0xbc, 0x57, 0xe1, 0x29, 0xa4, 0xc9, 0xf6, 0xf5, 0xfc, 0xbd, 0x11, 0x64, 0xe5, 0x96, 0x73, - 0x3c, 0x2c, 0xbe, 0x71, 0xf6, 0x55, 0x4e, 0x9e, 0x62, 0x96, 0x91, 0xde, 0x29, 0xe6, 0x05, 0xfc, 0xa9, 0x2c, 0xf5, - 0x39, 0x4a, 0x6f, 0x99, 0x4f, 0x56, 0x91, 0x74, 0xe9, 0x6d, 0xfa, 0xfd, 0x78, 0xa4, 0x0e, 0x35, 0x7f, 0x1f, 0x8f, - 0xe4, 0x19, 0xb6, 0x61, 0x09, 0x0b, 0xad, 0x82, 0x31, 0x80, 0x24, 0x36, 0x22, 0x1a, 0x8c, 0xf6, 0xe6, 0x70, 0x38, - 0xdf, 0x98, 0xb3, 0x64, 0x0f, 0xae, 0xaf, 0x3c, 0x31, 0xef, 0xc0, 0x97, 0x79, 0x4c, 0x10, 0xb1, 0x99, 0xb7, 0x61, - 0x35, 0x78, 0xb0, 0x83, 0xeb, 0x23, 0xb6, 0x28, 0xd6, 0x3a, 0x96, 0xca, 0x3a, 0x38, 0xad, 0x63, 0xd3, 0x8c, 0x94, - 0x22, 0xfb, 0x1c, 0xfb, 0x7b, 0x37, 0xb8, 0xba, 0x36, 0x06, 0xb5, 0xc6, 0x1d, 0xe6, 0xce, 0xa9, 0x80, 0x7a, 0x4c, - 0x57, 0x50, 0x3d, 0xcb, 0xc9, 0x97, 0xdf, 0xda, 0x39, 0x20, 0x68, 0x04, 0x02, 0x17, 0x0d, 0xb4, 0x6a, 0x97, 0x72, - 0xde, 0x05, 0x84, 0xf8, 0x26, 0x05, 0x7d, 0x3a, 0x83, 0x4d, 0x6c, 0x3e, 0x81, 0x58, 0x34, 0xdd, 0xe7, 0x5a, 0x33, - 0x5f, 0x8c, 0x68, 0x67, 0xd6, 0xdd, 0x22, 0xb7, 0x5a, 0x88, 0x64, 0xf4, 0x6c, 0x33, 0xe1, 0xa2, 0x43, 0x39, 0x23, - 0x01, 0x13, 0xb4, 0xb6, 0x52, 0xf2, 0xb9, 0xee, 0x75, 0x82, 0xf6, 0x40, 0xd2, 0xba, 0x7f, 0xb3, 0xe8, 0x8c, 0x92, - 0x93, 0xeb, 0x4d, 0xce, 0x20, 0x05, 0x0b, 0xb6, 0x97, 0x39, 0xe1, 0x06, 0xf8, 0xc4, 0x66, 0xc9, 0x69, 0x1a, 0xe4, - 0xb1, 0x30, 0x1e, 0x79, 0x6d, 0x7e, 0x59, 0x40, 0x87, 0x92, 0x45, 0x23, 0xc4, 0x03, 0xec, 0x1c, 0x92, 0xab, 0x02, - 0x75, 0xd3, 0x40, 0x57, 0xae, 0x9c, 0x29, 0xa6, 0xc0, 0x85, 0x50, 0x10, 0xb5, 0xa3, 0x93, 0xa8, 0x9c, 0xf7, 0x49, - 0x75, 0x99, 0x4f, 0x0b, 0x69, 0x1a, 0xc8, 0xa7, 0x95, 0x63, 0x1e, 0xd8, 0xd9, 0xc6, 0x35, 0x81, 0x81, 0x4e, 0xed, - 0x6b, 0x51, 0xce, 0xb1, 0x8a, 0xe8, 0x7d, 0xfe, 0xa1, 0xb2, 0xa7, 0x0f, 0x22, 0x6c, 0x54, 0xa0, 0xb1, 0x94, 0x18, - 0x1b, 0x39, 0xfe, 0x2d, 0x51, 0x36, 0x64, 0x08, 0x08, 0x21, 0x6d, 0xe4, 0xf4, 0xc3, 0xfa, 0xf2, 0x36, 0xd3, 0xfe, - 0x9f, 0x24, 0x7e, 0x1b, 0xec, 0xe5, 0xd4, 0x9f, 0x7a, 0xc4, 0xe3, 0xb5, 0x46, 0x8f, 0x29, 0xe9, 0x36, 0xc8, 0x53, - 0xe5, 0x29, 0x48, 0x26, 0x8c, 0x25, 0x04, 0x8b, 0x72, 0xc1, 0x73, 0x5e, 0x71, 0x09, 0xf7, 0x51, 0xcb, 0x8a, 0x08, - 0x55, 0x89, 0x9c, 0x3e, 0x5f, 0x01, 0xcf, 0x04, 0x04, 0x3a, 0xc6, 0x48, 0xa3, 0x0a, 0xbe, 0x04, 0xc6, 0x3a, 0x50, - 0x76, 0x9a, 0x91, 0xe0, 0xb2, 0x7b, 0x83, 0x44, 0xa9, 0xaf, 0x48, 0x49, 0xfa, 0x56, 0xd4, 0x78, 0x25, 0x56, 0x11, - 0x09, 0x64, 0xa8, 0x21, 0x62, 0x55, 0x3d, 0x75, 0xaf, 0x8a, 0xc9, 0x60, 0x50, 0xf9, 0x72, 0x7a, 0xe2, 0x0d, 0x0d, - 0x95, 0x77, 0x5d, 0xd1, 0x4e, 0x4f, 0xb4, 0x52, 0xde, 0x42, 0x5a, 0x82, 0xa6, 0x61, 0xa4, 0x39, 0x94, 0xba, 0x92, - 0xee, 0xc6, 0x20, 0xbe, 0x64, 0xa2, 0x67, 0x3b, 0xb5, 0xa3, 0xb4, 0x25, 0xed, 0x21, 0xa4, 0xe7, 0x2e, 0xf9, 0x98, - 0x85, 0x5c, 0xdd, 0x29, 0x27, 0xe5, 0x55, 0x88, 0x4e, 0xee, 0x7b, 0x0c, 0x89, 0x40, 0x9f, 0x73, 0x0c, 0xeb, 0xa2, - 0xa1, 0xce, 0x61, 0x85, 0x98, 0x2d, 0x94, 0x30, 0x5f, 0x32, 0x9e, 0x4a, 0x06, 0x0d, 0x80, 0x0c, 0xf8, 0xec, 0x65, - 0x60, 0xf9, 0x2b, 0x88, 0x1f, 0x6d, 0x7c, 0x38, 0xfc, 0x59, 0x53, 0x88, 0xed, 0x9f, 0xb0, 0x19, 0xc2, 0xa3, 0x7a, - 0xc0, 0x33, 0xdf, 0xc4, 0x09, 0x5a, 0x01, 0x49, 0x99, 0x1d, 0x4d, 0x64, 0xaf, 0x7a, 0x08, 0xa7, 0xb2, 0x02, 0x75, - 0x94, 0x75, 0x56, 0xc2, 0x8f, 0x30, 0xd5, 0xad, 0xc4, 0x5a, 0xa0, 0xcd, 0xd5, 0x8a, 0xb5, 0x00, 0x0e, 0xfc, 0x1c, - 0x82, 0x27, 0xf2, 0x39, 0xb8, 0x18, 0x14, 0xe0, 0x73, 0x00, 0xbc, 0xc8, 0x5d, 0x78, 0x30, 0x8f, 0x2c, 0xab, 0x11, - 0x86, 0xa3, 0x8a, 0x58, 0xbf, 0x66, 0x3b, 0xf2, 0x81, 0xdb, 0x31, 0x3e, 0xd7, 0x1e, 0x4b, 0x96, 0x83, 0x51, 0xe6, - 0x5e, 0x2d, 0xd1, 0xf3, 0x26, 0x8d, 0x9b, 0xd1, 0x93, 0x7d, 0x2d, 0xff, 0x17, 0xf4, 0x32, 0xe8, 0x6f, 0xe1, 0x96, - 0xd7, 0xfc, 0x6e, 0x41, 0xa4, 0x99, 0x5e, 0x41, 0xa4, 0x8c, 0x1a, 0x91, 0x31, 0x84, 0x4d, 0xaa, 0x9b, 0xdb, 0xa4, - 0xba, 0x10, 0xf0, 0x74, 0x44, 0xaa, 0x6b, 0x21, 0x6d, 0xe4, 0xd3, 0x3a, 0x90, 0xb1, 0x48, 0xef, 0x7e, 0xf8, 0xdb, - 0x8b, 0x4f, 0x6f, 0x7e, 0xf9, 0x61, 0xf1, 0xe6, 0xdd, 0xeb, 0x37, 0xef, 0xde, 0x7c, 0xfa, 0x8d, 0x20, 0x3c, 0xa6, - 0x42, 0x65, 0xf8, 0xf0, 0xfe, 0xe6, 0x8d, 0x93, 0xc1, 0xf6, 0x66, 0xc8, 0xda, 0x37, 0x72, 0x30, 0x04, 0x22, 0x1b, - 0x84, 0x0c, 0xb2, 0x53, 0xdb, 0xfe, 0x4c, 0xcc, 0x31, 0xf6, 0x4e, 0x60, 0xb2, 0x05, 0x9c, 0x63, 0x99, 0x97, 0x8c, - 0xc8, 0x55, 0xa1, 0xf5, 0x03, 0x5a, 0xf0, 0x16, 0x5c, 0x64, 0xd2, 0xfc, 0xee, 0x17, 0x82, 0xd8, 0xa7, 0x95, 0x94, - 0xfb, 0x6a, 0x5b, 0xf3, 0x7c, 0x7b, 0xbf, 0x97, 0x70, 0xfe, 0x73, 0x69, 0x44, 0x2d, 0xc0, 0x01, 0xf8, 0x1c, 0xfe, - 0xb8, 0xd2, 0x96, 0x34, 0x99, 0x45, 0xfb, 0x19, 0x43, 0xd0, 0xa5, 0xc1, 0x07, 0xb1, 0x47, 0x5e, 0xea, 0x93, 0x85, - 0x04, 0xee, 0x88, 0xe1, 0xd3, 0x8a, 0xa0, 0x57, 0x8c, 0x28, 0x2e, 0xb9, 0x42, 0xa5, 0x94, 0xfc, 0x1b, 0x65, 0x17, - 0x15, 0x72, 0x56, 0xb0, 0x7b, 0x45, 0x8e, 0x8c, 0x1f, 0x04, 0x13, 0x5f, 0x0e, 0xee, 0xbf, 0xc4, 0x3b, 0x9c, 0x29, - 0x8e, 0xe4, 0x84, 0x3f, 0x64, 0x18, 0xd8, 0x9f, 0x83, 0xcf, 0xab, 0xc3, 0xbc, 0xbc, 0xd1, 0xa7, 0xdc, 0x92, 0x8f, - 0x27, 0xcb, 0x2b, 0x30, 0xd8, 0x2f, 0x55, 0x73, 0xd7, 0xbc, 0x9e, 0x2d, 0xe7, 0x6c, 0x3f, 0x8b, 0xe6, 0xc1, 0x1d, - 0x9b, 0x65, 0xf3, 0x60, 0xd5, 0xf0, 0x35, 0xbb, 0xe5, 0x6b, 0xab, 0x6a, 0x6b, 0xbb, 0x6a, 0x93, 0x0d, 0xbf, 0x05, - 0x09, 0xe1, 0x26, 0xf3, 0x80, 0xf7, 0xf8, 0xce, 0x67, 0x1b, 0x90, 0x68, 0x57, 0x6c, 0x03, 0x17, 0xb1, 0x35, 0xff, - 0xa1, 0xf2, 0x36, 0xac, 0x64, 0xe7, 0x63, 0x96, 0xe3, 0xfc, 0xf3, 0xe1, 0x01, 0xed, 0x85, 0xfa, 0xd9, 0xa5, 0x7a, - 0x36, 0x51, 0x76, 0xb3, 0xcd, 0x68, 0x71, 0x9f, 0x56, 0x9b, 0x30, 0x43, 0xcf, 0x72, 0xf8, 0x68, 0x2b, 0x05, 0x3f, - 0xbd, 0xc0, 0x2f, 0xd9, 0x51, 0x5b, 0x69, 0xdb, 0xae, 0x4a, 0x6c, 0x05, 0x2d, 0x8a, 0xac, 0x56, 0x78, 0x60, 0xce, - 0xaf, 0x61, 0x01, 0x63, 0xcf, 0x71, 0xce, 0x6b, 0x7f, 0x84, 0x8c, 0xf7, 0x0e, 0x00, 0x5a, 0xe6, 0x38, 0xc0, 0x23, - 0x56, 0x8c, 0xa2, 0xc1, 0x3b, 0xbf, 0x54, 0x56, 0x2b, 0xcd, 0x49, 0x68, 0x1b, 0xb1, 0x6a, 0x39, 0x52, 0x35, 0x23, - 0xd2, 0x07, 0xe9, 0x79, 0xdf, 0x23, 0xaa, 0xc1, 0x9e, 0xcc, 0xeb, 0xc0, 0x3e, 0xbd, 0x6c, 0xad, 0xea, 0xce, 0xef, - 0xa9, 0xd2, 0x25, 0x47, 0xb6, 0xfc, 0x74, 0x19, 0x3e, 0xa8, 0x3f, 0x25, 0xd7, 0x87, 0x02, 0x47, 0x78, 0xac, 0x02, - 0xce, 0xd7, 0x2b, 0xd1, 0xee, 0x44, 0xd8, 0x95, 0x4b, 0x40, 0x88, 0x2f, 0x69, 0x9a, 0xe3, 0x71, 0x44, 0x13, 0x11, - 0x36, 0x31, 0xfa, 0x0b, 0xbb, 0x0f, 0x25, 0x96, 0xf3, 0x5c, 0x83, 0x92, 0x4b, 0x06, 0xef, 0x49, 0x7b, 0x0d, 0x9a, - 0xe5, 0x55, 0xa9, 0xc9, 0x44, 0x0e, 0xca, 0x87, 0x43, 0x01, 0x7b, 0xa9, 0xf1, 0xd3, 0x84, 0x9f, 0xb0, 0xbc, 0xb5, - 0xb7, 0xa6, 0x14, 0x95, 0x34, 0x40, 0x05, 0x3e, 0x66, 0xf0, 0xbf, 0x3b, 0x43, 0x2c, 0x98, 0xa2, 0xe3, 0x87, 0x33, - 0x31, 0xb7, 0x9e, 0x5b, 0x65, 0x1d, 0x65, 0x6b, 0x94, 0x13, 0xf0, 0x6f, 0xa9, 0x8e, 0x93, 0x44, 0x38, 0xf5, 0x1e, - 0x71, 0x51, 0xf7, 0x72, 0x88, 0xba, 0x61, 0x6f, 0x2a, 0x1d, 0x6c, 0x39, 0x4d, 0x83, 0x23, 0xf1, 0x2b, 0xf5, 0xd9, - 0xfb, 0xcc, 0xe2, 0x51, 0x47, 0x36, 0xa2, 0x24, 0x8d, 0x63, 0x91, 0xc3, 0xf6, 0xbe, 0x90, 0xfb, 0x7f, 0xbf, 0x0f, - 0xe1, 0xa4, 0x55, 0x90, 0x94, 0x9e, 0x40, 0x44, 0x38, 0x3a, 0xfc, 0x88, 0xf0, 0x44, 0xaa, 0x0a, 0x9f, 0xd4, 0x27, - 0x6e, 0xcc, 0xee, 0x85, 0x39, 0xaa, 0xb7, 0x00, 0xc3, 0x58, 0x6f, 0x2d, 0x42, 0x12, 0xad, 0x34, 0xa3, 0xad, 0x07, - 0xc4, 0x88, 0xf7, 0x6b, 0x8b, 0x0c, 0xc6, 0xda, 0x92, 0x48, 0x00, 0xbf, 0x23, 0x21, 0x43, 0xdb, 0x46, 0x60, 0xc6, - 0xf0, 0x76, 0x56, 0x5c, 0xba, 0x0e, 0xdb, 0x9c, 0xc3, 0x17, 0xb2, 0xd0, 0xac, 0x23, 0x4a, 0x13, 0x84, 0xfc, 0x03, - 0x4e, 0x16, 0x0a, 0xa3, 0x79, 0x75, 0x94, 0x4e, 0x12, 0xeb, 0xfb, 0xae, 0x52, 0xc1, 0x66, 0x73, 0x83, 0xfa, 0xb2, - 0xa3, 0xe4, 0x97, 0xe0, 0xa4, 0xe3, 0x24, 0x8b, 0x1c, 0x44, 0x2d, 0x2a, 0xe7, 0x26, 0x09, 0x4b, 0xbb, 0x3a, 0xd5, - 0x66, 0xbd, 0x2e, 0xca, 0xba, 0x7a, 0x25, 0x22, 0x45, 0xef, 0xa3, 0x1e, 0x3d, 0x91, 0x90, 0x0a, 0xad, 0x4a, 0xed, - 0xf2, 0x08, 0xdc, 0x36, 0xb5, 0x62, 0x5b, 0x2e, 0x61, 0x89, 0x1a, 0xff, 0x09, 0xfa, 0x28, 0x17, 0x0f, 0x32, 0x40, - 0xa3, 0xe3, 0xa9, 0x79, 0xeb, 0x91, 0x57, 0x8e, 0xf2, 0x4b, 0xab, 0x4d, 0xfa, 0x05, 0x90, 0x19, 0xed, 0x1f, 0x2d, - 0x25, 0x90, 0x19, 0x98, 0x49, 0x4b, 0x43, 0x22, 0x47, 0x31, 0x4b, 0xf3, 0x3f, 0x70, 0xc5, 0x56, 0x88, 0x34, 0xac, - 0xe6, 0x1e, 0x7f, 0x51, 0x79, 0xb5, 0x5c, 0xcb, 0x4c, 0x73, 0xb3, 0xc4, 0xb1, 0x62, 0x71, 0x51, 0xaf, 0x2b, 0x91, - 0x05, 0x42, 0x1c, 0x61, 0x1a, 0xeb, 0xa9, 0x37, 0x4a, 0xab, 0x0f, 0x48, 0x28, 0xf3, 0x03, 0xf6, 0x76, 0xec, 0xf5, - 0x20, 0x0b, 0x71, 0x6c, 0x39, 0xd8, 0x6c, 0xbd, 0x4f, 0x65, 0x2a, 0xe2, 0xb3, 0xba, 0x38, 0xdb, 0x54, 0xe2, 0xac, - 0x4e, 0xc4, 0xd9, 0x77, 0x90, 0xf3, 0xbb, 0x33, 0x2a, 0xfa, 0xec, 0x21, 0xad, 0x93, 0x62, 0x53, 0xd3, 0x93, 0xd7, - 0x58, 0xc6, 0x77, 0x67, 0xc4, 0x55, 0x73, 0x46, 0x23, 0x19, 0x8f, 0xce, 0x3e, 0x64, 0x40, 0xf2, 0x7a, 0x96, 0xae, - 0x60, 0xf0, 0xce, 0xc2, 0x3c, 0x3e, 0x2b, 0xc5, 0x1d, 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x2a, 0xfc, 0x43, - 0x9c, 0x01, 0xb4, 0xeb, 0x59, 0x5a, 0x9f, 0xa5, 0xd5, 0x59, 0x5e, 0xd4, 0x67, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, - 0x4f, 0x5f, 0xd9, 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x2a, 0xe1, 0xb5, 0xfb, - 0xdb, 0xe6, 0xfe, 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, 0x46, 0x74, 0x41, 0x3d, 0x5e, 0x49, 0x4a, 0x05, 0x05, 0x04, - 0x4e, 0x34, 0x6b, 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, 0x5b, 0xb2, 0xb5, 0xcf, 0xaf, 0x63, 0x19, 0xa6, 0xbd, 0x09, - 0xf0, 0xaf, 0xb2, 0x37, 0x5d, 0x07, 0x4b, 0xbc, 0x6f, 0x21, 0xdb, 0xd0, 0x9b, 0x57, 0xfc, 0x85, 0x97, 0xab, 0xbf, - 0xd9, 0x3f, 0x01, 0x08, 0x03, 0x62, 0x56, 0x7d, 0x34, 0x71, 0xef, 0xac, 0x2c, 0x3b, 0x27, 0xcb, 0xae, 0x87, 0x7e, - 0x4d, 0x62, 0x54, 0x5a, 0x59, 0x4a, 0x27, 0x4b, 0x09, 0x59, 0xc0, 0x27, 0x46, 0x53, 0x1b, 0x01, 0x84, 0xed, 0x28, - 0x95, 0x2f, 0x54, 0x5e, 0x44, 0xe1, 0x9c, 0xe0, 0x79, 0x22, 0x46, 0xf7, 0x56, 0x32, 0x60, 0x38, 0x84, 0x60, 0x0e, - 0xda, 0x62, 0x6f, 0xe8, 0x26, 0xe2, 0xaf, 0xd7, 0x45, 0xf9, 0x26, 0x26, 0x9f, 0x82, 0xdd, 0xc9, 0xc7, 0x25, 0x3c, - 0x2e, 0x4f, 0x3e, 0x0e, 0xd1, 0x23, 0xe1, 0xe4, 0x63, 0xf0, 0x3d, 0x92, 0xf3, 0xba, 0xeb, 0x71, 0x82, 0xdc, 0x42, - 0xba, 0xbf, 0x1d, 0x93, 0x00, 0xcd, 0x6b, 0x58, 0x8e, 0x9a, 0x8a, 0x6b, 0x66, 0xc6, 0x78, 0xde, 0xe8, 0xfd, 0xb1, - 0xe3, 0x2d, 0x53, 0x28, 0x66, 0x31, 0xaf, 0xe1, 0xf7, 0xac, 0x0a, 0xd4, 0x5d, 0x6f, 0x93, 0xdc, 0x32, 0xab, 0xe7, - 0x68, 0xf7, 0x7d, 0x5f, 0x27, 0x82, 0xda, 0xdf, 0x61, 0xcf, 0x33, 0xeb, 0x5d, 0x15, 0x03, 0x97, 0x2a, 0xd9, 0x21, - 0x53, 0xd5, 0xf4, 0x40, 0xa5, 0x34, 0x78, 0x7a, 0x69, 0x5d, 0xbe, 0x54, 0xda, 0xc8, 0x33, 0xcd, 0x6f, 0x00, 0x2f, - 0xa6, 0x2e, 0x8b, 0xdd, 0x57, 0xf7, 0x15, 0xdc, 0xc6, 0xfb, 0xfd, 0x65, 0xe5, 0x99, 0x9f, 0xb8, 0x00, 0xec, 0x4d, - 0x85, 0xd6, 0x09, 0x94, 0x1a, 0xd6, 0xe1, 0xcb, 0x44, 0x44, 0x7f, 0xb4, 0xcb, 0x75, 0xe6, 0x3a, 0x60, 0x44, 0x11, - 0xbf, 0x8d, 0x47, 0x7f, 0x80, 0xe2, 0xda, 0xd8, 0x03, 0xc2, 0x3a, 0x24, 0xf4, 0x19, 0x01, 0x48, 0x3d, 0xe6, 0x28, - 0x01, 0xcd, 0x8a, 0xe6, 0x8e, 0xc9, 0xcf, 0xf5, 0x95, 0xd2, 0xdf, 0x2f, 0x2b, 0x8f, 0xcc, 0x29, 0x6d, 0x33, 0x8d, - 0xd5, 0x9a, 0x4a, 0x20, 0xbc, 0xa2, 0x92, 0x55, 0xf8, 0x6c, 0xde, 0x88, 0x7e, 0x5f, 0x1e, 0xe1, 0x69, 0xf5, 0xc3, - 0x16, 0xe3, 0x5b, 0x01, 0xd1, 0x48, 0x00, 0xf4, 0x13, 0xc0, 0xbc, 0xc8, 0x66, 0x76, 0x1f, 0x07, 0x54, 0x29, 0xd1, - 0x34, 0xce, 0xe6, 0xf9, 0x2d, 0xbd, 0x29, 0x3b, 0xe8, 0xd4, 0xa9, 0x02, 0x17, 0x5c, 0x95, 0x8c, 0x57, 0xd6, 0x13, - 0xf9, 0xfc, 0xe6, 0x76, 0x93, 0x66, 0xf1, 0xfb, 0xf2, 0x9f, 0x38, 0xb6, 0xba, 0x0e, 0x8f, 0x4c, 0x9d, 0xae, 0x9d, - 0x47, 0x5a, 0x7b, 0x21, 0x20, 0xa2, 0x5d, 0x43, 0xad, 0x17, 0x16, 0x7a, 0xa4, 0x27, 0xc2, 0x39, 0x49, 0xd4, 0xb4, - 0x03, 0x2d, 0x8d, 0xd0, 0xd7, 0xd7, 0x9c, 0xfe, 0xc2, 0x60, 0xed, 0xf3, 0x31, 0x03, 0xb2, 0x12, 0xfd, 0x58, 0x3d, - 0x34, 0x36, 0x73, 0xe8, 0x59, 0xab, 0xf2, 0xcc, 0xab, 0x0e, 0x07, 0xc4, 0x87, 0xd1, 0x5f, 0xf2, 0xfb, 0xfd, 0x57, - 0x34, 0xff, 0x98, 0x50, 0xe3, 0x67, 0x9b, 0x01, 0xba, 0xf6, 0x5d, 0x79, 0x20, 0xea, 0xb9, 0x56, 0x09, 0x42, 0xbc, - 0x41, 0x4c, 0x34, 0x23, 0xe6, 0xe0, 0xb4, 0x43, 0xcd, 0x3f, 0x49, 0x0d, 0x08, 0x51, 0xe2, 0x75, 0x4c, 0x59, 0x90, - 0xd3, 0x26, 0x8e, 0xf4, 0xa3, 0x70, 0x22, 0x3f, 0x8a, 0xaa, 0xc8, 0xee, 0xe1, 0x82, 0xc1, 0xd4, 0x7b, 0xda, 0x2f, - 0xd1, 0x6f, 0x09, 0x47, 0xce, 0xd1, 0xaa, 0x10, 0x44, 0x4e, 0x08, 0x6b, 0x0d, 0x61, 0x82, 0xd8, 0x20, 0x5e, 0xf6, - 0x5d, 0x92, 0xe1, 0x48, 0xc1, 0x65, 0x1d, 0x3b, 0xc6, 0x5c, 0x1d, 0x55, 0xaf, 0x01, 0x8c, 0x57, 0x8e, 0xa0, 0xd9, - 0x28, 0xb2, 0x4b, 0x88, 0x2a, 0x72, 0x3c, 0x01, 0xb5, 0x83, 0xd2, 0xd8, 0x4c, 0xcf, 0xc7, 0x41, 0x3e, 0x5a, 0x54, - 0xa8, 0x73, 0x62, 0x19, 0xaf, 0x01, 0x58, 0x3b, 0x57, 0xfd, 0x3c, 0xab, 0xc1, 0x93, 0x86, 0xf8, 0x7c, 0x8c, 0xb6, - 0x57, 0x36, 0x07, 0xd5, 0x76, 0x3a, 0x2b, 0xaf, 0x98, 0x2e, 0x07, 0xc6, 0x7d, 0xc3, 0x2b, 0x8a, 0x33, 0xfc, 0xe8, - 0xc1, 0x16, 0xe7, 0x4f, 0x37, 0xd4, 0x7e, 0xcc, 0x8d, 0x7a, 0x18, 0x68, 0x2d, 0x78, 0x53, 0x10, 0xeb, 0xef, 0x87, - 0x8e, 0x6c, 0xef, 0xb5, 0xc8, 0x68, 0xf2, 0xd9, 0xcf, 0x3f, 0x94, 0xe9, 0x2a, 0x85, 0xfb, 0x92, 0x93, 0x45, 0x33, - 0x0f, 0x81, 0xbd, 0x21, 0x86, 0xeb, 0xa3, 0xc2, 0x23, 0xca, 0xfa, 0x7d, 0xf8, 0x7d, 0x95, 0x81, 0x29, 0x06, 0xae, - 0x2b, 0x04, 0xe3, 0x21, 0x10, 0xc4, 0xc3, 0x34, 0x3a, 0x19, 0xd4, 0xa0, 0x0d, 0xdf, 0x00, 0x64, 0x06, 0x78, 0x64, - 0x2e, 0x3d, 0x02, 0xee, 0x02, 0xd7, 0x9e, 0x8c, 0xc7, 0xfe, 0xc4, 0x34, 0x34, 0x6a, 0x4a, 0x33, 0x3d, 0x37, 0x7e, - 0xd3, 0x51, 0x2d, 0xd7, 0xce, 0x7f, 0x7c, 0xc9, 0x6f, 0xd0, 0x0b, 0x5a, 0x5e, 0xee, 0x23, 0x75, 0xb9, 0xcf, 0x28, - 0x2e, 0x13, 0xc9, 0x61, 0x41, 0x2c, 0x4b, 0x38, 0xf0, 0x18, 0x95, 0x2c, 0xb6, 0xf4, 0x58, 0x15, 0x2d, 0x5f, 0x94, - 0x1b, 0xa4, 0x43, 0x27, 0x04, 0x4b, 0x54, 0x10, 0x2c, 0x81, 0x71, 0x11, 0x6b, 0xbe, 0x19, 0xe4, 0x2c, 0x9e, 0x6d, - 0xe6, 0x1c, 0x09, 0xeb, 0x92, 0xc3, 0xa1, 0x90, 0x60, 0x33, 0xd9, 0x6c, 0x3d, 0x67, 0x6b, 0x9f, 0x81, 0x12, 0xa0, - 0x94, 0x69, 0x82, 0xd2, 0xb4, 0x62, 0x2b, 0x6e, 0x5a, 0x83, 0xd5, 0x6a, 0xca, 0x56, 0x35, 0x65, 0xe7, 0x34, 0xe5, - 0xa8, 0x82, 0x92, 0x13, 0x4a, 0x51, 0x86, 0x01, 0x8c, 0xd8, 0x24, 0xba, 0xca, 0xd0, 0xc7, 0x3b, 0xe1, 0x11, 0x54, - 0x11, 0x91, 0x4f, 0x18, 0x42, 0x60, 0x22, 0x8a, 0x0b, 0x55, 0x28, 0x06, 0xc8, 0x88, 0x04, 0x82, 0x89, 0x4a, 0x9d, - 0x02, 0xf3, 0xd1, 0x54, 0x31, 0x6c, 0xda, 0x13, 0xe5, 0x5b, 0xea, 0xb8, 0x47, 0xd9, 0xe6, 0xef, 0x62, 0x17, 0x84, - 0xc8, 0xdd, 0xb8, 0x53, 0x3f, 0x23, 0xde, 0xdb, 0x1d, 0x61, 0xfc, 0x64, 0xc7, 0x2d, 0xc2, 0x15, 0xc1, 0x96, 0x6a, - 0x0e, 0xb1, 0x98, 0x57, 0x93, 0x04, 0xb5, 0x2c, 0x89, 0xbf, 0xe1, 0xc9, 0x20, 0x67, 0x4b, 0xf0, 0xa0, 0x9d, 0xb3, - 0x0c, 0xf0, 0x57, 0xac, 0x16, 0xfd, 0x56, 0x7b, 0x4b, 0x90, 0x9f, 0x36, 0x76, 0xa3, 0x30, 0x31, 0x82, 0x44, 0xdd, - 0xae, 0x0c, 0xe4, 0x87, 0x0f, 0x38, 0x1d, 0x8f, 0x3d, 0x65, 0xcc, 0xad, 0x4c, 0x2f, 0xd3, 0xb9, 0x92, 0x6f, 0xe4, - 0x5e, 0xfa, 0xd8, 0x4b, 0xb0, 0x73, 0xc0, 0x1b, 0x48, 0x1b, 0x78, 0x03, 0xdb, 0x85, 0xd7, 0x06, 0x09, 0x33, 0x02, - 0x6c, 0x71, 0x7c, 0x8c, 0x94, 0xc0, 0x10, 0x8e, 0xb3, 0x14, 0x80, 0x69, 0xf4, 0x65, 0xb6, 0xb2, 0x2f, 0xb3, 0x5a, - 0xb3, 0xa5, 0x72, 0xba, 0x77, 0x6e, 0xdd, 0xce, 0x27, 0x12, 0x00, 0x4c, 0xea, 0x1c, 0x88, 0x33, 0x13, 0xec, 0xd2, - 0x24, 0xb2, 0x7c, 0x0c, 0xf3, 0x3b, 0xf1, 0xba, 0x2c, 0x56, 0xaa, 0x2b, 0xda, 0x3e, 0x33, 0xf9, 0x8c, 0x74, 0x12, - 0x2a, 0xa0, 0xa0, 0x90, 0x6b, 0x7d, 0xfa, 0x2e, 0x7c, 0x17, 0x14, 0x1a, 0x98, 0xad, 0xc2, 0x3d, 0x4d, 0xd6, 0x48, - 0xbd, 0x51, 0xf5, 0xfb, 0xe4, 0x1a, 0x48, 0x75, 0xe6, 0xd0, 0xb2, 0x27, 0x15, 0x06, 0x88, 0x1d, 0xf5, 0x19, 0x09, - 0x75, 0x20, 0xf5, 0x80, 0x21, 0x44, 0xdb, 0xf4, 0xf1, 0x27, 0x43, 0xa2, 0x0b, 0xb0, 0x85, 0x68, 0x03, 0x3f, 0xfe, - 0x04, 0xfb, 0x2c, 0x08, 0x8f, 0x69, 0xfe, 0x16, 0x92, 0x8e, 0x0d, 0x9c, 0x56, 0x9f, 0x82, 0x0f, 0x92, 0x1c, 0x4c, - 0xd4, 0xc1, 0xcb, 0xfd, 0xa5, 0xdf, 0x87, 0x2d, 0x3b, 0x97, 0x52, 0x1d, 0x2b, 0xf5, 0xb6, 0xad, 0xfd, 0x20, 0xda, - 0x82, 0x23, 0x8b, 0xf8, 0xfb, 0x0c, 0x11, 0xc1, 0xcc, 0x20, 0xc2, 0xae, 0x85, 0xba, 0xdb, 0x53, 0x6a, 0x59, 0xd4, - 0xdb, 0x9e, 0x52, 0xea, 0x36, 0x0c, 0xdf, 0x4d, 0x30, 0x53, 0xdc, 0xf0, 0x3f, 0x32, 0x2f, 0xd4, 0x1b, 0x8f, 0x45, - 0x81, 0xee, 0xf9, 0xfb, 0x25, 0xaf, 0x66, 0x1b, 0x65, 0xc2, 0xbc, 0xe3, 0xcb, 0x59, 0x28, 0xbb, 0x5a, 0x1a, 0x77, - 0x3e, 0x7b, 0x4b, 0x35, 0x1f, 0xfc, 0xc3, 0x21, 0x81, 0x78, 0xa3, 0xf8, 0xea, 0xae, 0x91, 0x5b, 0xd7, 0x64, 0x73, - 0x55, 0x02, 0xea, 0xf7, 0xf9, 0x1a, 0xf7, 0x5b, 0xac, 0x7f, 0xf7, 0x34, 0xc8, 0x58, 0xcd, 0x70, 0xc5, 0x14, 0x3e, - 0x05, 0x80, 0xc1, 0xe1, 0x54, 0x90, 0x16, 0x78, 0xc3, 0xcb, 0xe1, 0xe5, 0x64, 0x43, 0x26, 0xdd, 0x8d, 0x8f, 0xdc, - 0x59, 0xa0, 0xea, 0xfd, 0x86, 0xe2, 0xa4, 0x41, 0xa2, 0xb1, 0xd7, 0xe0, 0x8b, 0x2c, 0xa3, 0x5c, 0x34, 0x71, 0x1f, - 0x93, 0xaf, 0xf4, 0x00, 0xe6, 0x2a, 0x94, 0x00, 0xd1, 0x6f, 0x2c, 0x8b, 0x8d, 0x68, 0x5b, 0x6c, 0x60, 0x29, 0x55, - 0x73, 0xbd, 0x9a, 0x3e, 0x7b, 0x25, 0x9a, 0xf7, 0xd1, 0x8c, 0x53, 0x1a, 0x0d, 0x38, 0x4e, 0xa3, 0x70, 0xfb, 0xfe, - 0x5e, 0x94, 0xcb, 0x0c, 0x2c, 0xd9, 0x2a, 0x9c, 0xe2, 0xb2, 0x51, 0x67, 0xc4, 0x8b, 0x3c, 0x56, 0x00, 0x1d, 0x8f, - 0x09, 0x80, 0xea, 0x82, 0x80, 0x8a, 0x68, 0x29, 0xbd, 0x15, 0x5a, 0x2c, 0xd4, 0x1b, 0x8e, 0x52, 0xf8, 0x23, 0xfd, - 0x79, 0x90, 0x4f, 0x01, 0x88, 0x5d, 0x1f, 0x47, 0xaf, 0x8b, 0x92, 0x3e, 0x55, 0xcc, 0x72, 0x39, 0x98, 0xc0, 0xae, - 0x4e, 0x64, 0xa8, 0x15, 0xe4, 0xad, 0xba, 0xf2, 0x56, 0x26, 0x6f, 0x63, 0x9c, 0x92, 0x1f, 0xb9, 0xe9, 0x58, 0x23, - 0x06, 0x5e, 0x79, 0x5a, 0xa7, 0x09, 0xd2, 0xe4, 0x02, 0x18, 0x86, 0xf8, 0x36, 0xf3, 0x5e, 0x78, 0x8e, 0x54, 0x05, - 0xc9, 0x6c, 0x97, 0x79, 0xea, 0x22, 0xaa, 0xaf, 0x9c, 0x5a, 0x3a, 0x73, 0xfa, 0x11, 0xc0, 0x7b, 0x4c, 0x4d, 0x1a, - 0xf2, 0x11, 0x6e, 0x4b, 0xf1, 0xf5, 0x56, 0x5d, 0xe3, 0xa5, 0xd1, 0xb9, 0x7b, 0xf9, 0xd2, 0x9d, 0x06, 0xfd, 0x14, - 0x04, 0xe5, 0x7c, 0x51, 0x0a, 0xd8, 0x53, 0x66, 0x73, 0xbd, 0x5a, 0xb5, 0x42, 0xeb, 0x70, 0x18, 0x6b, 0x47, 0x21, - 0xad, 0xce, 0x02, 0xb6, 0x1a, 0xe9, 0x94, 0x00, 0x21, 0x38, 0x4e, 0xc3, 0x4e, 0x30, 0xee, 0xd2, 0x69, 0x44, 0xd6, - 0x2b, 0x25, 0xe9, 0xc2, 0x0c, 0x92, 0x7f, 0x92, 0xd7, 0x33, 0xa0, 0x25, 0x80, 0x43, 0x11, 0x4b, 0x78, 0x38, 0x49, - 0xae, 0x00, 0x3a, 0x1d, 0x0e, 0x2a, 0x0d, 0xcd, 0x59, 0xcd, 0x92, 0xf9, 0x24, 0x96, 0xaa, 0xca, 0xc3, 0xc1, 0x53, - 0x6e, 0x06, 0xfd, 0x7e, 0x36, 0x2d, 0x95, 0x0b, 0x40, 0x10, 0xeb, 0xc2, 0x00, 0xf1, 0x48, 0x0b, 0x4f, 0x16, 0x7d, - 0x4a, 0xe2, 0x97, 0xb3, 0x64, 0x6e, 0xb2, 0xe1, 0x1d, 0x18, 0xc1, 0x66, 0x5c, 0x97, 0x94, 0x69, 0x8f, 0xca, 0xef, - 0x19, 0x3d, 0xb5, 0x7d, 0xad, 0xd5, 0x16, 0xb1, 0xae, 0x83, 0xab, 0x12, 0xf5, 0x14, 0x1f, 0x94, 0x24, 0x78, 0xbf, - 0x72, 0x6e, 0x46, 0xca, 0xd7, 0x22, 0xf7, 0x83, 0x76, 0xa6, 0x56, 0x0e, 0x1c, 0x81, 0x1c, 0xab, 0xa8, 0xe4, 0xf5, - 0xae, 0x43, 0xf0, 0xe8, 0xae, 0x54, 0xa0, 0x1c, 0x7c, 0x0d, 0x62, 0x74, 0x7d, 0xd5, 0x59, 0x43, 0xcd, 0x34, 0xaa, - 0x3c, 0x82, 0x4e, 0x1d, 0xc0, 0x93, 0x82, 0x97, 0x5a, 0xfd, 0x78, 0x38, 0x78, 0xe6, 0x07, 0x7f, 0x99, 0xe9, 0x5b, - 0x88, 0x89, 0x72, 0xaa, 0x11, 0x12, 0x57, 0x4a, 0x12, 0xf1, 0xf1, 0xa2, 0x65, 0xc5, 0xa8, 0x0c, 0x1f, 0x78, 0xa5, - 0xca, 0x57, 0xa7, 0x2a, 0x2f, 0x46, 0xda, 0x96, 0xc0, 0x6b, 0xf2, 0x0f, 0x91, 0x6b, 0xde, 0xfa, 0xba, 0xab, 0x0c, - 0x7d, 0x2b, 0x2b, 0xd0, 0x11, 0x6c, 0x65, 0x29, 0x39, 0xe0, 0x93, 0xea, 0xae, 0x5a, 0xb5, 0x3e, 0xa7, 0x6c, 0x23, - 0xdc, 0xe4, 0xd7, 0xb1, 0x83, 0x23, 0xe5, 0x37, 0x78, 0x2e, 0x80, 0xbd, 0x06, 0xec, 0xcd, 0x39, 0x2b, 0x9a, 0x47, - 0x87, 0xb4, 0x2d, 0xd0, 0xc8, 0xcc, 0xed, 0x5c, 0xdd, 0xb7, 0xe5, 0x51, 0x1a, 0x43, 0x64, 0xda, 0x23, 0xd3, 0xc1, - 0x66, 0x94, 0xff, 0x96, 0xf2, 0x5b, 0x85, 0x63, 0xe0, 0xdb, 0xa9, 0x77, 0x00, 0x55, 0x4f, 0x1b, 0x64, 0xac, 0x19, - 0x86, 0x56, 0x76, 0xb9, 0x14, 0x5a, 0x82, 0x96, 0xba, 0x09, 0x82, 0xf3, 0x23, 0xa2, 0x1c, 0x01, 0xe8, 0x22, 0x05, - 0x4c, 0xf0, 0x53, 0xda, 0xee, 0x7e, 0x7f, 0x9d, 0x7a, 0xe4, 0xde, 0x15, 0x6a, 0x94, 0x50, 0x82, 0xb1, 0x9f, 0x68, - 0xcc, 0xa0, 0xa3, 0x2b, 0x72, 0xc2, 0xb3, 0x56, 0x87, 0x75, 0xdd, 0x94, 0x41, 0x59, 0x1c, 0xf3, 0x6a, 0x3a, 0xfb, - 0xfd, 0xc9, 0xbe, 0x6e, 0x90, 0x85, 0xfc, 0x77, 0xd6, 0x43, 0x32, 0xe8, 0x1e, 0x84, 0x42, 0xf4, 0xe6, 0xc1, 0x0c, - 0xff, 0x63, 0x1b, 0x9e, 0x7d, 0xc3, 0x8d, 0x3a, 0x01, 0xcc, 0x11, 0xd7, 0x4b, 0x4f, 0xd1, 0xd6, 0xc3, 0x2d, 0x90, - 0xad, 0xf1, 0xf2, 0xd6, 0x5e, 0x03, 0x39, 0xc5, 0xf1, 0xdf, 0xf1, 0x4c, 0xad, 0x6c, 0xf0, 0xd3, 0x53, 0xb6, 0x03, - 0x0f, 0x2f, 0x42, 0x40, 0x31, 0x2c, 0x1b, 0x7f, 0x67, 0x39, 0xce, 0xe8, 0xbf, 0x79, 0xc4, 0x30, 0x58, 0x44, 0x7e, - 0x7c, 0x59, 0x0a, 0xf1, 0x45, 0x78, 0x6f, 0x2a, 0xef, 0x8e, 0x9c, 0x32, 0xef, 0xf4, 0x30, 0xba, 0x2e, 0x49, 0xdf, - 0x24, 0x1f, 0x5b, 0xc3, 0xf6, 0xbb, 0x76, 0xbf, 0x19, 0x22, 0x08, 0xa1, 0x1c, 0x3f, 0x67, 0x74, 0x42, 0xe3, 0xc3, - 0x6a, 0x76, 0x7a, 0xfd, 0xde, 0x39, 0x5e, 0xb0, 0x35, 0x1a, 0xe0, 0xf1, 0xd0, 0xc5, 0x3c, 0x51, 0x43, 0xa7, 0xeb, - 0xda, 0x39, 0x78, 0x60, 0x90, 0xe5, 0xc9, 0x37, 0x0c, 0x4b, 0xec, 0x4f, 0x22, 0x9e, 0xb4, 0x55, 0x1b, 0x9b, 0x23, - 0xd5, 0x46, 0xcd, 0xc0, 0x0f, 0x5e, 0x41, 0x81, 0xd1, 0x05, 0x69, 0x05, 0xc6, 0xe1, 0x08, 0x40, 0x56, 0x8c, 0xe3, - 0x91, 0xc1, 0x04, 0x86, 0x74, 0x43, 0x51, 0x00, 0x1e, 0x1e, 0xc7, 0x83, 0x90, 0x01, 0xa4, 0x0b, 0x1e, 0x1a, 0xb6, - 0x49, 0x48, 0xf9, 0x79, 0x9e, 0xd7, 0x6a, 0x08, 0x7d, 0x67, 0xa1, 0x3a, 0xf6, 0x23, 0xed, 0x15, 0xeb, 0x5a, 0x95, - 0x8e, 0x6c, 0x75, 0x80, 0xbe, 0x21, 0x03, 0xdf, 0x3a, 0xb6, 0x00, 0x88, 0x96, 0xf8, 0x2d, 0xf5, 0x6a, 0x5f, 0xc6, - 0xac, 0x50, 0xaf, 0x2f, 0x4c, 0xbb, 0x5e, 0x49, 0x8b, 0x02, 0x2a, 0x6e, 0x5b, 0xb5, 0x3d, 0x92, 0xf3, 0x1f, 0xdf, - 0x75, 0xb4, 0xe3, 0xb3, 0x53, 0x63, 0x4b, 0x28, 0x73, 0x8b, 0x27, 0xb2, 0x3a, 0xda, 0x52, 0x9d, 0xea, 0x03, 0x2e, - 0x35, 0xa9, 0xce, 0x0c, 0x0c, 0xaf, 0x11, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xde, 0xf9, 0x64, 0x50, 0x30, 0xb7, - 0x48, 0x40, 0x02, 0xdb, 0xd8, 0xda, 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xaa, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, - 0xce, 0xde, 0x69, 0x2d, 0x20, 0x80, 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, - 0xf9, 0x6f, 0x29, 0x2a, 0x62, 0x4f, 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, - 0x3a, 0x6a, 0x2a, 0xd7, 0xcd, 0x55, 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xba, 0xd6, 0xb9, 0x53, 0xef, 0xbd, 0x8a, 0x23, - 0x06, 0x82, 0x9b, 0xee, 0xf1, 0xc1, 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, - 0x68, 0xce, 0xf4, 0x11, 0x00, 0x11, 0x60, 0x95, 0xa8, 0xff, 0xc3, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, - 0xb6, 0xde, 0x3f, 0xad, 0x91, 0x56, 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, - 0xff, 0x9f, 0xfb, 0x00, 0x35, 0xa2, 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2c, 0x7c, 0xe3, 0x87, 0x8c, - 0xf3, 0xc1, 0x0c, 0x1d, 0xd5, 0xe6, 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, - 0x4f, 0xdc, 0x67, 0x5c, 0x7b, 0x41, 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, - 0x65, 0x93, 0x48, 0x7d, 0x33, 0x06, 0x05, 0x40, 0x71, 0x5d, 0x91, 0x5c, 0xba, 0x48, 0xf3, 0x4a, 0x94, 0xb5, 0x6e, - 0x46, 0xc5, 0x8a, 0x21, 0x00, 0x3c, 0x04, 0xc5, 0x55, 0x65, 0x26, 0x34, 0x62, 0x03, 0xa9, 0x2c, 0x05, 0xab, 0x86, - 0x85, 0xdf, 0xb4, 0xdf, 0x24, 0x27, 0xbd, 0xf3, 0x71, 0xeb, 0xdc, 0xb1, 0xef, 0x1d, 0x85, 0x94, 0xf6, 0x50, 0x4c, - 0x10, 0x04, 0x3f, 0xad, 0xc3, 0xf9, 0x33, 0x7e, 0x4d, 0x60, 0x2a, 0xb2, 0x19, 0x03, 0x0e, 0x42, 0x44, 0x66, 0xfc, - 0x9e, 0xc3, 0x6b, 0x5e, 0x4e, 0xc2, 0xe1, 0xd0, 0x07, 0x7d, 0x28, 0xcf, 0x66, 0xe1, 0x50, 0xcc, 0xa5, 0xf7, 0x3a, - 0x58, 0xeb, 0x42, 0x5e, 0x4f, 0x42, 0x44, 0x0b, 0x0d, 0x7d, 0x70, 0x5e, 0x77, 0xcd, 0x11, 0x96, 0x00, 0x34, 0x71, - 0xf4, 0x65, 0xfd, 0x7e, 0xe4, 0x69, 0x43, 0x8b, 0x14, 0x17, 0x8d, 0x32, 0x9b, 0xe5, 0xb2, 0x13, 0x36, 0xae, 0xdd, - 0x02, 0xa1, 0x78, 0x98, 0xb6, 0x50, 0xb5, 0x9e, 0xea, 0xf5, 0xdc, 0xb4, 0xfb, 0xee, 0x51, 0xb5, 0xca, 0x91, 0xce, - 0xda, 0x74, 0xa5, 0x56, 0xb7, 0x8c, 0xaa, 0x75, 0x96, 0x46, 0x54, 0xb9, 0x49, 0xee, 0x1a, 0xb5, 0xe0, 0x93, 0x0d, - 0x5d, 0xa6, 0xec, 0x6c, 0x0d, 0x4e, 0x1c, 0x79, 0x2e, 0xb9, 0xe5, 0xbb, 0xf3, 0x8a, 0xee, 0x4e, 0xb5, 0x6f, 0x01, - 0xee, 0xcd, 0xb0, 0x21, 0x73, 0x5e, 0x63, 0xa7, 0x41, 0x98, 0x04, 0x7e, 0xc4, 0x3e, 0x66, 0xc8, 0x06, 0x03, 0x3a, - 0x0a, 0xe9, 0x7f, 0x6d, 0x99, 0x23, 0x01, 0x93, 0xbf, 0x9e, 0xfb, 0xcd, 0xa2, 0xc8, 0x61, 0x31, 0x7e, 0xd8, 0x60, - 0xa4, 0xb1, 0x5a, 0x83, 0x61, 0x79, 0x87, 0xc8, 0x9f, 0xda, 0x1d, 0xd3, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, - 0xa7, 0x4f, 0x75, 0x7d, 0xfe, 0xdb, 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xde, 0x2d, 0xce, 0x1d, - 0x89, 0xde, 0xb1, 0xd2, 0xcc, 0x2e, 0xed, 0x92, 0x5d, 0x9a, 0xd2, 0x6e, 0xc8, 0xf5, 0xea, 0x2b, 0xe5, 0x8d, 0x9d, - 0x57, 0x4c, 0xf7, 0xef, 0x85, 0xde, 0x51, 0x4e, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, - 0x27, 0x79, 0xbb, 0x84, 0xa3, 0xae, 0x61, 0xb9, 0xf9, 0xf6, 0x3f, 0xf3, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, - 0xfd, 0x29, 0x88, 0xab, 0xfa, 0xc3, 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe8, - 0x9e, 0x42, 0xd8, 0x60, 0xf6, 0xf3, 0xe3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x92, 0x11, - 0xde, 0xef, 0x18, 0xe7, 0xfe, 0xd5, 0xf7, 0x6a, 0x72, 0x84, 0x88, 0x76, 0x11, 0x0e, 0x00, 0xe2, 0x4e, 0x53, 0x59, - 0x87, 0x1a, 0xa0, 0x0f, 0x08, 0xac, 0x43, 0xdf, 0x66, 0x00, 0x07, 0x7d, 0xb4, 0x79, 0x16, 0x81, 0xbc, 0xee, 0xdd, - 0xb3, 0xb7, 0x6c, 0xe7, 0xf3, 0xeb, 0x55, 0xea, 0xdd, 0xa3, 0x43, 0xf0, 0xf9, 0xd8, 0x9f, 0x5e, 0x06, 0x06, 0x17, - 0x9a, 0xbd, 0x7d, 0x26, 0xd8, 0x8e, 0xed, 0x9e, 0x21, 0x52, 0x51, 0x77, 0xfe, 0xe1, 0xa5, 0x89, 0x9e, 0x77, 0x5e, - 0xb8, 0xe3, 0x4b, 0x00, 0x0f, 0x64, 0x31, 0xa0, 0xf8, 0x2c, 0xbd, 0x7f, 0xb1, 0x04, 0xd4, 0xe4, 0xb7, 0x7c, 0xed, - 0x7d, 0xa1, 0xd4, 0x05, 0xfc, 0x39, 0xa0, 0xf4, 0x49, 0xce, 0xbd, 0xbb, 0xe1, 0xad, 0x7f, 0xf1, 0x1c, 0x9c, 0x27, - 0x56, 0xc3, 0x05, 0xfc, 0x55, 0xf0, 0xa1, 0x77, 0x37, 0xc0, 0xc4, 0x92, 0x0f, 0xbd, 0xd5, 0x00, 0x52, 0x15, 0x2e, - 0x24, 0xc6, 0x3e, 0xfc, 0x1a, 0xe4, 0x0c, 0xff, 0xf8, 0x4d, 0x63, 0xb0, 0xfe, 0x1a, 0x14, 0x1a, 0x8d, 0xb5, 0x54, - 0x21, 0x4b, 0xb1, 0x38, 0x13, 0x60, 0x13, 0x8e, 0xbb, 0x7d, 0xb1, 0xaa, 0xcd, 0x5a, 0xd0, 0x9f, 0x8f, 0xf8, 0x1e, - 0x8d, 0xd5, 0x55, 0x39, 0x17, 0xe5, 0x47, 0xa4, 0x4f, 0x75, 0x7c, 0x8c, 0x8a, 0x4d, 0xdd, 0x9d, 0x4e, 0xb5, 0xea, - 0x48, 0xfb, 0x4d, 0xb9, 0x06, 0x3b, 0x5e, 0x27, 0x47, 0x96, 0xc2, 0xb3, 0x0e, 0x3b, 0x2f, 0x9d, 0x12, 0x1d, 0x86, - 0xf1, 0x6e, 0xab, 0x9e, 0x31, 0x94, 0xe7, 0x06, 0x63, 0xba, 0xe0, 0x11, 0xbf, 0x1e, 0xe4, 0x32, 0x34, 0xe6, 0x03, - 0xb2, 0x61, 0x28, 0x1f, 0x5a, 0x64, 0x48, 0x88, 0x78, 0x0f, 0x95, 0x80, 0x6d, 0x0b, 0xca, 0xa4, 0x80, 0xb3, 0x68, - 0xf0, 0x5b, 0xed, 0xe5, 0xc0, 0x7b, 0x10, 0xf9, 0x8d, 0x74, 0x29, 0x97, 0xd8, 0xe8, 0xc4, 0xb1, 0x2c, 0xb4, 0xf3, - 0xb8, 0xfe, 0x3a, 0x06, 0xf5, 0x7b, 0xa5, 0xdf, 0xa0, 0x9c, 0xfd, 0x51, 0xb2, 0x4e, 0x1b, 0x4f, 0x8c, 0x7f, 0xb8, - 0xca, 0x3f, 0x45, 0x4b, 0x3d, 0xfc, 0x7f, 0xc6, 0x14, 0x4a, 0xff, 0x32, 0x2d, 0xa3, 0xcd, 0x6a, 0x29, 0x4a, 0x91, - 0x47, 0xe2, 0xe4, 0x6b, 0x91, 0x9d, 0xcb, 0x77, 0x3e, 0x85, 0x7e, 0x01, 0x68, 0xd9, 0x27, 0xc8, 0xe8, 0xef, 0x99, - 0xe0, 0xc3, 0xef, 0xb5, 0x73, 0x6d, 0xce, 0xc7, 0x93, 0xfc, 0xca, 0xda, 0xbb, 0x1d, 0x2f, 0x12, 0xa3, 0x18, 0xcb, - 0x7d, 0xd5, 0xcd, 0xca, 0x89, 0x4a, 0x0e, 0x8c, 0x74, 0x4d, 0xf6, 0x72, 0x25, 0xeb, 0x76, 0xba, 0x95, 0x40, 0x44, - 0x15, 0x78, 0x8f, 0x71, 0x15, 0xfb, 0x08, 0xa6, 0xeb, 0x8e, 0xcb, 0x68, 0xc7, 0x7b, 0xc6, 0xab, 0x13, 0x65, 0x05, - 0xb7, 0x1b, 0xd1, 0x9e, 0xd0, 0xd1, 0x4f, 0x93, 0xda, 0xb2, 0x70, 0x00, 0x72, 0x97, 0x30, 0x96, 0x0d, 0xc1, 0x8a, - 0x41, 0xe9, 0xeb, 0x35, 0x25, 0xcb, 0x02, 0x2c, 0x3a, 0xbb, 0x8c, 0x40, 0x0c, 0xeb, 0xa6, 0x39, 0xa1, 0xe3, 0xa5, - 0x8b, 0xf3, 0x5e, 0xab, 0x48, 0xc1, 0x33, 0x5a, 0x74, 0xcc, 0x4d, 0x47, 0xba, 0x31, 0xda, 0xdb, 0xef, 0x0d, 0x42, - 0x8a, 0xe7, 0x0f, 0x6c, 0xb5, 0x2e, 0x2e, 0x12, 0xaf, 0x90, 0x89, 0x16, 0xc4, 0x52, 0x04, 0x66, 0xbc, 0xd0, 0x34, - 0xc2, 0x04, 0x65, 0x4a, 0xb0, 0x68, 0x8d, 0x0e, 0xed, 0x0f, 0x4b, 0xd8, 0x3d, 0xc6, 0x08, 0x10, 0xa8, 0x32, 0x7d, - 0x0e, 0x5b, 0x13, 0x66, 0x53, 0x17, 0x1b, 0xa0, 0xad, 0x62, 0x68, 0x10, 0xd6, 0x86, 0x98, 0x8f, 0x69, 0x7e, 0xf7, - 0x2f, 0x2c, 0xc6, 0xf6, 0x04, 0x62, 0x7b, 0xb7, 0x6b, 0x12, 0xa6, 0x7b, 0x2d, 0x6e, 0xac, 0x97, 0xdb, 0x53, 0x8e, - 0xa9, 0x1d, 0x6b, 0xa3, 0x76, 0xac, 0xa5, 0xde, 0xb1, 0xd6, 0x7a, 0xc7, 0xba, 0x6b, 0xf8, 0x87, 0xcc, 0x8b, 0x59, - 0x02, 0xfa, 0xdd, 0x15, 0x57, 0x0d, 0x82, 0x66, 0x6c, 0xd8, 0x2d, 0xfc, 0x96, 0x58, 0xbb, 0xa5, 0x7f, 0xb1, 0x64, - 0x0b, 0xd3, 0x07, 0xba, 0x75, 0x80, 0x65, 0x44, 0x4d, 0xbe, 0x47, 0xde, 0x4d, 0x67, 0x45, 0xe1, 0xf6, 0xc4, 0x16, - 0x3e, 0x7b, 0x6b, 0xde, 0xbc, 0x7f, 0x16, 0x41, 0xee, 0x1d, 0xf7, 0xee, 0x87, 0x6f, 0xfd, 0x0b, 0xdd, 0x02, 0x39, - 0x99, 0xe5, 0x0c, 0xa4, 0x8e, 0xf8, 0x04, 0xd1, 0xca, 0x9e, 0xf2, 0x9d, 0x90, 0x3b, 0xdb, 0xfa, 0xd9, 0xbd, 0xbb, - 0xad, 0xdd, 0x3d, 0xbb, 0x67, 0xd5, 0x88, 0x62, 0xc5, 0x69, 0x8a, 0x84, 0x59, 0xb4, 0x01, 0x9e, 0x7a, 0xf9, 0x7e, - 0xc7, 0x8e, 0x39, 0xdc, 0x3d, 0xeb, 0xe8, 0x78, 0x39, 0x07, 0xec, 0xee, 0x3f, 0xda, 0x84, 0x8d, 0x95, 0xae, 0x55, - 0xe8, 0x70, 0xf7, 0x2c, 0xd3, 0x78, 0x0e, 0x47, 0xf2, 0xe9, 0x58, 0x63, 0x83, 0xa0, 0xae, 0xcf, 0x19, 0xd4, 0x8e, - 0xdd, 0xd7, 0x84, 0x5d, 0x76, 0xcc, 0x6b, 0x5d, 0xf3, 0xf6, 0xca, 0x53, 0xb1, 0x21, 0xa0, 0xc3, 0xd7, 0xea, 0x06, - 0xf9, 0x97, 0xc0, 0x29, 0x02, 0x40, 0x0e, 0xc7, 0x4b, 0x1e, 0xfb, 0x3e, 0xcd, 0xd2, 0x7a, 0x87, 0x5a, 0x8b, 0xca, - 0xb2, 0x0c, 0x6b, 0xef, 0x07, 0xad, 0x18, 0x96, 0x9a, 0xfe, 0xe9, 0x38, 0x70, 0x3b, 0xdb, 0xad, 0x8c, 0x5d, 0xc6, - 0xb3, 0xe2, 0xe2, 0xfb, 0xd3, 0x42, 0xb9, 0x76, 0xf3, 0x36, 0x7e, 0xd3, 0x6a, 0xc9, 0xd2, 0x5a, 0x0f, 0x79, 0x69, - 0x59, 0x44, 0x20, 0x80, 0xe1, 0x48, 0xd9, 0xc5, 0x12, 0xee, 0x11, 0x56, 0xf7, 0x20, 0x94, 0xcc, 0x0b, 0x17, 0xcf, - 0x59, 0x0c, 0x89, 0x00, 0xdb, 0x1d, 0x2a, 0xb6, 0x85, 0x8b, 0xe7, 0x6c, 0xc3, 0x8b, 0x7e, 0x3f, 0x53, 0x9d, 0x42, - 0xd6, 0x9d, 0x25, 0xdf, 0xa8, 0xe6, 0x58, 0x43, 0xcd, 0xd6, 0x26, 0xd9, 0x1a, 0xe7, 0xb6, 0xe2, 0xe3, 0xae, 0xad, - 0xf8, 0x58, 0x59, 0xeb, 0xd2, 0xbd, 0xde, 0xa3, 0xba, 0x00, 0xb6, 0xfe, 0xdb, 0xe3, 0x95, 0xeb, 0xf9, 0x8c, 0x00, - 0xbe, 0x16, 0x7c, 0x3c, 0x59, 0xa0, 0x57, 0xc9, 0xc2, 0xbf, 0x1d, 0xa8, 0xf1, 0x77, 0x3a, 0x77, 0x01, 0xd0, 0x95, - 0x94, 0x57, 0x40, 0xde, 0x41, 0x8e, 0xb9, 0x65, 0x57, 0xde, 0x9f, 0x7c, 0x87, 0xbd, 0xe5, 0xf5, 0x6c, 0x31, 0x67, - 0x3b, 0x70, 0x2a, 0x48, 0x06, 0xf6, 0xb2, 0x62, 0xbb, 0x20, 0xb6, 0x13, 0x7e, 0x23, 0x60, 0xca, 0x17, 0x10, 0xc4, - 0x15, 0xdc, 0x42, 0x1c, 0x9e, 0xfc, 0x73, 0x70, 0xdf, 0xda, 0xac, 0xef, 0x99, 0xd5, 0x39, 0xc1, 0x9a, 0x59, 0x3d, - 0x18, 0x2c, 0x9b, 0xc9, 0xaa, 0xdf, 0xf7, 0x76, 0xda, 0xf1, 0xe9, 0x4e, 0xea, 0xc4, 0x4e, 0x6b, 0xb5, 0x16, 0xec, - 0xad, 0xd4, 0xba, 0x18, 0x43, 0x0f, 0x10, 0x3f, 0xdd, 0x0e, 0xf8, 0x7d, 0xc7, 0xda, 0xf2, 0xde, 0xb2, 0x05, 0xdb, - 0xc1, 0x25, 0xa8, 0x69, 0x2f, 0xfb, 0x93, 0xca, 0x05, 0xed, 0xd8, 0x25, 0xf1, 0x70, 0xc6, 0xac, 0x52, 0x66, 0xd6, - 0x49, 0x75, 0x25, 0x3a, 0x63, 0x3a, 0x6b, 0x3d, 0x9f, 0xab, 0xf9, 0xa4, 0xd0, 0xa0, 0x7e, 0xe7, 0xc4, 0x47, 0x54, - 0x74, 0x9e, 0xc0, 0xd6, 0xb2, 0x82, 0x58, 0xed, 0x73, 0xb0, 0xd6, 0x6a, 0x97, 0x7e, 0x2f, 0x1f, 0x70, 0x9b, 0x72, - 0x58, 0x07, 0x06, 0x35, 0x27, 0x56, 0xd4, 0x63, 0xb6, 0x63, 0xdc, 0xfc, 0xf4, 0xf2, 0x07, 0x27, 0x2c, 0x59, 0xb1, - 0xda, 0x9f, 0x7e, 0xff, 0xcc, 0xd3, 0xdf, 0xa9, 0xfd, 0x0b, 0xe1, 0x07, 0xe3, 0xff, 0xd4, 0xee, 0x6b, 0x2d, 0x46, - 0x65, 0xab, 0x1c, 0xa1, 0x71, 0xb7, 0x92, 0x26, 0xcb, 0x4f, 0xc2, 0x13, 0xd6, 0x82, 0x67, 0xb9, 0x5e, 0xa2, 0x59, - 0x01, 0x2b, 0xac, 0x65, 0x12, 0xae, 0x30, 0x56, 0x4b, 0x5b, 0x7d, 0x8b, 0xa6, 0x39, 0x3e, 0x9c, 0x6b, 0x83, 0x32, - 0xe5, 0xec, 0x8c, 0x58, 0x0d, 0x97, 0x61, 0x69, 0x42, 0x11, 0xb2, 0x7b, 0x3b, 0xb8, 0xb1, 0x53, 0x96, 0x52, 0x86, - 0x73, 0x0c, 0x26, 0x3c, 0x12, 0xa3, 0x2a, 0xdf, 0xdf, 0x97, 0x14, 0x39, 0x6d, 0xcb, 0x41, 0x15, 0xc2, 0x3e, 0x92, - 0x28, 0x81, 0x5b, 0x91, 0x16, 0x8a, 0x94, 0xc5, 0xdf, 0x0e, 0xd0, 0x05, 0x5e, 0x40, 0x5d, 0x8d, 0xba, 0xfd, 0xe1, - 0x88, 0x87, 0x8f, 0x4c, 0x7d, 0x60, 0xc4, 0x92, 0x40, 0x6d, 0x2f, 0xb2, 0xf4, 0x0e, 0x54, 0xf8, 0x3d, 0x5c, 0x4d, - 0xc4, 0x7e, 0x6e, 0x49, 0x51, 0x91, 0x8d, 0xf4, 0x86, 0xd6, 0xe0, 0x11, 0x5a, 0x53, 0xbe, 0x77, 0x52, 0x6d, 0xd2, - 0x79, 0x47, 0xc8, 0xb1, 0xfa, 0xd6, 0x12, 0x46, 0xbb, 0xa2, 0x17, 0xf7, 0x8e, 0xde, 0xf3, 0x74, 0xd5, 0x73, 0x7f, - 0xe2, 0x8a, 0x79, 0x72, 0x1b, 0x81, 0xba, 0x15, 0x54, 0xb7, 0xf7, 0x2a, 0xc1, 0x82, 0x25, 0xed, 0x3e, 0x7e, 0x3b, - 0x6b, 0x07, 0xa2, 0x32, 0x56, 0xe9, 0x6b, 0x92, 0xb0, 0x27, 0x06, 0x9d, 0x42, 0x55, 0x6e, 0x77, 0x47, 0x5b, 0xe0, - 0x3a, 0x66, 0x29, 0x7a, 0x61, 0x8b, 0xdc, 0x2d, 0xff, 0xee, 0xb9, 0x22, 0x67, 0xbf, 0x04, 0x04, 0xa7, 0xe6, 0x2b, - 0xe2, 0xcb, 0x11, 0x1e, 0x55, 0xb7, 0xc0, 0x71, 0xfa, 0x0e, 0xe0, 0x1f, 0x0e, 0x97, 0xa0, 0x09, 0x88, 0x05, 0xeb, - 0xa5, 0x71, 0x8f, 0xf5, 0xe2, 0x62, 0x73, 0x97, 0xe4, 0x1b, 0x70, 0x66, 0xa0, 0x54, 0x4b, 0x3f, 0x70, 0xac, 0x16, - 0x50, 0xe1, 0x60, 0x76, 0x52, 0x2f, 0x2c, 0xa3, 0x1e, 0xd3, 0xe7, 0x67, 0xb0, 0x77, 0x84, 0x04, 0xc0, 0xfd, 0xb2, - 0x0f, 0x48, 0xc0, 0x43, 0x67, 0x76, 0x40, 0x38, 0x61, 0x16, 0x55, 0x81, 0x44, 0x72, 0xa4, 0x9f, 0x3d, 0x66, 0x22, - 0xf9, 0x83, 0x59, 0xcf, 0x39, 0x25, 0x7a, 0xac, 0xa7, 0x8e, 0x90, 0x1e, 0xeb, 0x59, 0x47, 0x44, 0x8f, 0xf5, 0xac, - 0xe3, 0xa3, 0xc7, 0x7a, 0xe6, 0xd8, 0xe9, 0x41, 0x60, 0x02, 0x44, 0x1e, 0xb0, 0x1e, 0x4d, 0xa6, 0x9e, 0xe2, 0x1e, - 0x20, 0x1a, 0x04, 0xd6, 0x93, 0xc2, 0x79, 0x0f, 0x90, 0xc7, 0x48, 0xac, 0x0e, 0x7a, 0x7f, 0x19, 0x3f, 0xed, 0x19, - 0x19, 0x79, 0xdc, 0x3a, 0xac, 0xfe, 0xd7, 0x5f, 0x21, 0x00, 0x0e, 0xcf, 0xa6, 0xde, 0xe5, 0x18, 0xb2, 0xca, 0x32, - 0x02, 0xc9, 0x4f, 0x0c, 0xbe, 0x7c, 0x01, 0x50, 0xf5, 0x99, 0xae, 0xd5, 0xe4, 0xa8, 0x3d, 0xe6, 0xd0, 0x15, 0x03, - 0xc0, 0x36, 0x2c, 0x51, 0x55, 0x0b, 0x9b, 0xb0, 0xb8, 0xfd, 0x0c, 0xa3, 0xb9, 0x6c, 0x7a, 0x41, 0x03, 0xf5, 0x08, - 0xc1, 0x2f, 0xad, 0x87, 0xd6, 0x5a, 0xa6, 0x1c, 0xba, 0x36, 0x8a, 0x2a, 0x1b, 0xea, 0x12, 0x56, 0x6b, 0x11, 0xd5, - 0x44, 0x91, 0x72, 0xc9, 0x28, 0x8a, 0xa5, 0x0a, 0xf6, 0x99, 0xb8, 0x83, 0xa8, 0x79, 0xda, 0x6a, 0xab, 0x60, 0x7f, - 0x07, 0x08, 0x6b, 0x61, 0x2d, 0xa4, 0x33, 0xa8, 0xbd, 0xd3, 0x8f, 0x94, 0xbf, 0xbc, 0x90, 0xdb, 0xb9, 0x85, 0x22, - 0xdc, 0x9e, 0x83, 0xf2, 0xa6, 0xae, 0x4a, 0x45, 0x34, 0x5a, 0x02, 0xa5, 0xcc, 0x09, 0x22, 0x0b, 0x10, 0xc0, 0x71, - 0x03, 0x81, 0xcf, 0x6b, 0x7c, 0x02, 0x8d, 0x42, 0x20, 0x3f, 0xb0, 0x0a, 0xd7, 0x1e, 0xd2, 0x52, 0x6b, 0x44, 0x94, - 0x88, 0x1f, 0x5d, 0x3d, 0xc7, 0xf6, 0xd5, 0xd3, 0x58, 0x5b, 0x4a, 0x13, 0xc4, 0x4f, 0x2c, 0xb6, 0x10, 0x13, 0x44, - 0x75, 0x88, 0x8e, 0x60, 0x39, 0x21, 0x44, 0xe1, 0x0f, 0xa1, 0x9f, 0x1a, 0xf8, 0x4b, 0xb6, 0x2c, 0xf2, 0x9a, 0x60, - 0x31, 0x2b, 0x06, 0x68, 0x55, 0x04, 0x9e, 0xe9, 0x6c, 0xa9, 0xcc, 0x69, 0x1e, 0x1d, 0xd9, 0xc1, 0x79, 0xd7, 0xc1, - 0x5e, 0xfa, 0x32, 0x76, 0xb2, 0x6c, 0x1a, 0xb5, 0xb1, 0x21, 0x12, 0x5e, 0x91, 0xbf, 0xcc, 0x52, 0xe3, 0x1c, 0x99, - 0xcb, 0xf5, 0x5d, 0x17, 0x77, 0x77, 0xb4, 0x4d, 0x58, 0x85, 0x08, 0x75, 0xdb, 0x50, 0xb9, 0x14, 0x66, 0x63, 0xd3, - 0x34, 0xc0, 0x17, 0x8a, 0x4a, 0xa5, 0x2a, 0xb5, 0x95, 0x4a, 0x4e, 0x78, 0xd7, 0x57, 0xb5, 0x48, 0x5d, 0x11, 0x6c, - 0x63, 0x86, 0x7a, 0x28, 0x37, 0x6a, 0xec, 0xeb, 0x8e, 0x55, 0x7a, 0x87, 0x09, 0x72, 0x46, 0x5e, 0xe4, 0xe0, 0xa2, - 0xa4, 0x20, 0x73, 0x35, 0x84, 0xf9, 0xa3, 0x86, 0x4f, 0x0b, 0xcb, 0x3d, 0x94, 0x80, 0xd9, 0x51, 0xc3, 0xcb, 0x08, - 0x81, 0x88, 0x4b, 0x65, 0x5f, 0x31, 0xf1, 0x7b, 0x0a, 0x66, 0xc9, 0x84, 0xee, 0x45, 0x2c, 0x8c, 0xd0, 0xc6, 0x27, - 0x49, 0x32, 0xf5, 0x34, 0x05, 0x37, 0x72, 0x19, 0xe6, 0x68, 0x84, 0x96, 0x7c, 0xe4, 0x40, 0xfa, 0x5a, 0x4e, 0x25, - 0xf8, 0x88, 0x3a, 0x05, 0x1c, 0xcf, 0xcf, 0x0b, 0xeb, 0x27, 0xcb, 0x25, 0xe6, 0xb2, 0x36, 0xff, 0x65, 0x47, 0xc7, - 0x60, 0x97, 0xa7, 0x89, 0xe3, 0xea, 0x3f, 0xaa, 0x92, 0xe2, 0xe1, 0xe7, 0x34, 0x07, 0x14, 0xc1, 0xcc, 0x9e, 0x62, - 0x7c, 0xec, 0xb3, 0x4c, 0x01, 0x7f, 0xbb, 0xde, 0x5a, 0x32, 0xb1, 0x4b, 0xda, 0xcd, 0x95, 0xf1, 0x4b, 0x6d, 0xd8, - 0x71, 0x70, 0x6e, 0x00, 0x8a, 0xb3, 0x46, 0x87, 0xe5, 0xb5, 0x6e, 0x5b, 0x15, 0x2a, 0x50, 0xeb, 0xff, 0xec, 0x16, - 0xa6, 0xbc, 0xcd, 0x4b, 0xe5, 0x6d, 0x1e, 0x9a, 0x00, 0x81, 0xc8, 0x0c, 0x79, 0xd6, 0x74, 0x4c, 0x12, 0xf7, 0x8e, - 0x94, 0xb4, 0xef, 0x48, 0xf1, 0xa3, 0x77, 0x24, 0xe4, 0x5b, 0x42, 0x47, 0xf6, 0x25, 0x27, 0x27, 0x50, 0x66, 0xb0, - 0x97, 0xd7, 0x4c, 0xf6, 0x0f, 0x68, 0x2f, 0x9c, 0xcb, 0xf2, 0x8a, 0xbf, 0x15, 0xde, 0xda, 0x9f, 0xae, 0x4f, 0xbb, - 0xaa, 0xde, 0x7e, 0x65, 0x66, 0x1e, 0x0e, 0xc5, 0xe1, 0x50, 0x99, 0xa0, 0xdd, 0x05, 0x17, 0x83, 0x9c, 0xdd, 0xbb, - 0xf1, 0xf1, 0x6f, 0x39, 0x8a, 0xd8, 0x4a, 0x79, 0x24, 0x5d, 0xa8, 0xc4, 0xf0, 0xd2, 0xc0, 0xc3, 0xec, 0xf8, 0x78, - 0xb2, 0xbb, 0xba, 0x9f, 0x0c, 0x06, 0x3b, 0xd5, 0xb7, 0x5b, 0x5e, 0xcf, 0x76, 0x73, 0xf6, 0xc0, 0x6f, 0xa7, 0xdb, - 0x60, 0xdf, 0xc0, 0xb6, 0xbb, 0xbb, 0x12, 0x87, 0xc3, 0xee, 0x9a, 0x2f, 0xfc, 0xfd, 0x03, 0x02, 0x3a, 0xf3, 0xf3, - 0x71, 0x1b, 0xe3, 0xe7, 0xa6, 0xed, 0xaa, 0xb5, 0x03, 0x78, 0xfa, 0x1f, 0xbc, 0x9b, 0xd9, 0x72, 0xee, 0xb3, 0x27, - 0xfc, 0x01, 0xfc, 0xf3, 0x71, 0x93, 0x44, 0xea, 0x13, 0xed, 0x32, 0x79, 0x03, 0x0e, 0xe4, 0x3b, 0x9f, 0xbd, 0xe1, - 0x0f, 0xb3, 0xe5, 0x9c, 0x17, 0x87, 0xc3, 0xfb, 0x69, 0x88, 0x64, 0x4d, 0x61, 0x45, 0x2c, 0x29, 0x9e, 0x1f, 0x84, - 0xc7, 0xef, 0x45, 0x64, 0x88, 0xb4, 0xdc, 0xbb, 0x43, 0x76, 0xc3, 0x22, 0x3f, 0x80, 0x0f, 0xb2, 0x9d, 0x3f, 0x91, - 0x35, 0xa5, 0xfb, 0xc5, 0x13, 0xff, 0x70, 0xa0, 0xbf, 0xde, 0xf8, 0x87, 0xc3, 0x7b, 0xf6, 0x80, 0xe0, 0xe8, 0x7c, - 0x07, 0xfd, 0xa3, 0x6f, 0x1d, 0x50, 0x95, 0xe1, 0xdb, 0xd9, 0x66, 0xee, 0x5f, 0xaf, 0xd8, 0x1d, 0x70, 0xa1, 0x28, - 0x2f, 0xb4, 0x1b, 0xf6, 0x80, 0x5e, 0x67, 0xe4, 0x44, 0x34, 0xdb, 0xcd, 0x7d, 0x16, 0xe3, 0x73, 0x75, 0x5f, 0x4c, - 0xbe, 0x7a, 0x5f, 0xdc, 0xb1, 0x6d, 0xf7, 0x7d, 0x51, 0xbe, 0xe9, 0xae, 0x9f, 0x2d, 0xdb, 0xb1, 0x07, 0x98, 0x61, - 0x6f, 0xf9, 0x4d, 0x73, 0xec, 0x18, 0xfb, 0xd5, 0x1b, 0x23, 0x80, 0x32, 0x5b, 0xb0, 0x58, 0x70, 0x50, 0xaa, 0x55, - 0xdb, 0x92, 0xc8, 0x2b, 0x1d, 0xa8, 0x36, 0x23, 0xb8, 0xaf, 0x16, 0x72, 0xe6, 0x99, 0x81, 0xbe, 0xad, 0x10, 0x2d, - 0x1c, 0x36, 0xe0, 0xaf, 0xb4, 0x75, 0x8c, 0x61, 0x9a, 0xd5, 0x4c, 0xdb, 0xa2, 0x2e, 0xbf, 0xed, 0x3d, 0x93, 0xdf, - 0xc8, 0xc0, 0x16, 0x22, 0x29, 0x1c, 0xc7, 0x17, 0xcf, 0x4f, 0xf8, 0xaf, 0x5a, 0x1e, 0xb5, 0xda, 0x2f, 0x94, 0xfa, - 0xf4, 0x25, 0x1d, 0xd1, 0xc4, 0xbd, 0x68, 0xcb, 0xb0, 0x46, 0x59, 0x53, 0x4b, 0x87, 0x61, 0x5c, 0xc3, 0xbe, 0x3c, - 0x70, 0xe8, 0x3b, 0x20, 0xd0, 0x56, 0xa9, 0x14, 0x68, 0xe1, 0x18, 0x46, 0x61, 0x16, 0x52, 0x1e, 0x17, 0x66, 0x29, - 0xef, 0xb1, 0x40, 0x8b, 0x5b, 0x75, 0x8f, 0xa9, 0xed, 0x16, 0x44, 0x58, 0xbd, 0x65, 0x9c, 0x5f, 0x36, 0xaa, 0x70, - 0x5b, 0x80, 0xa2, 0x08, 0xca, 0x60, 0x4f, 0x72, 0xdb, 0x42, 0x49, 0xb3, 0x51, 0x58, 0x8b, 0xbb, 0xa2, 0xdc, 0xf5, - 0x1a, 0xb6, 0xc0, 0x0b, 0xaa, 0x7e, 0x42, 0xd8, 0x96, 0x3d, 0xeb, 0x50, 0x2e, 0xd2, 0xff, 0xc8, 0xd2, 0xf3, 0xed, - 0xd6, 0x9c, 0xff, 0xe9, 0x2b, 0xfa, 0xa8, 0xfc, 0xcf, 0x2f, 0xe9, 0x27, 0x83, 0x65, 0xe4, 0x94, 0xfa, 0x3e, 0x1a, - 0xdd, 0xa6, 0x39, 0x61, 0x6c, 0xf9, 0xfa, 0xe9, 0x37, 0xc8, 0x14, 0x24, 0x87, 0x52, 0xaa, 0x72, 0xb2, 0x87, 0xbe, - 0xf0, 0xba, 0x0f, 0x33, 0xc1, 0x00, 0x84, 0xd7, 0x68, 0x53, 0x4d, 0x98, 0xc4, 0xa3, 0x2b, 0xf8, 0xbf, 0x11, 0xc4, - 0xa0, 0x7d, 0xa2, 0xa8, 0x63, 0xdb, 0x48, 0xd7, 0x6d, 0xe7, 0x20, 0xb9, 0x53, 0x57, 0xfe, 0xa8, 0x9c, 0xfc, 0x27, - 0x1a, 0x22, 0xaf, 0xb8, 0x42, 0xac, 0x2c, 0xb8, 0xc4, 0x62, 0xa8, 0x48, 0x01, 0xae, 0x21, 0x88, 0x94, 0x45, 0x49, - 0xe1, 0x96, 0x83, 0xaa, 0x08, 0xc0, 0xb8, 0x5a, 0x1d, 0x75, 0x22, 0x7c, 0xdc, 0x5a, 0x8b, 0x10, 0xac, 0x68, 0xd4, - 0xca, 0x5a, 0x81, 0x2f, 0x48, 0x5f, 0x3a, 0x14, 0xc4, 0xf4, 0x28, 0xa4, 0xaa, 0x74, 0x28, 0x90, 0xe6, 0x50, 0xf1, - 0x8d, 0xc1, 0x46, 0x51, 0x91, 0x9e, 0xbf, 0x34, 0x29, 0xb9, 0x34, 0x66, 0x7c, 0x10, 0x65, 0x24, 0xf2, 0x3a, 0xbc, - 0x13, 0xd3, 0x02, 0xf9, 0x46, 0x8f, 0x1f, 0x04, 0x97, 0xf0, 0x6e, 0xc8, 0xbd, 0x02, 0x6c, 0x09, 0xd8, 0x01, 0xee, - 0x95, 0x19, 0xe5, 0x3a, 0xad, 0xeb, 0xb7, 0xd6, 0x43, 0x31, 0x0c, 0x9f, 0x59, 0x02, 0xdb, 0xd1, 0x3a, 0x3a, 0xd2, - 0xc3, 0x87, 0xff, 0x75, 0x55, 0x73, 0xd4, 0xa9, 0x5c, 0xce, 0x8e, 0x27, 0x2c, 0x45, 0xcc, 0xa0, 0xfb, 0xeb, 0xf6, - 0xa5, 0x00, 0xba, 0x5d, 0x16, 0xf3, 0x6c, 0xb4, 0x93, 0x7f, 0x4b, 0x37, 0x56, 0x94, 0x36, 0xf1, 0x2e, 0xeb, 0x8d, - 0xfd, 0xe1, 0xe8, 0x2f, 0xcf, 0xbe, 0x4c, 0x08, 0x55, 0x67, 0xc3, 0xd6, 0x3a, 0xce, 0xe5, 0x7f, 0xfd, 0x75, 0x4c, - 0x56, 0x10, 0x14, 0x84, 0x65, 0xa7, 0x98, 0xa8, 0x60, 0x14, 0x29, 0xd6, 0x7c, 0x3c, 0x59, 0xa3, 0x4e, 0x78, 0xed, - 0x2f, 0xb5, 0x4e, 0x98, 0x18, 0x59, 0xa9, 0xfc, 0x35, 0xab, 0xd8, 0x9d, 0xca, 0x2c, 0x20, 0xf3, 0x20, 0x9f, 0xac, - 0x8d, 0x06, 0x73, 0xc5, 0xeb, 0xd9, 0x7a, 0x2e, 0x95, 0xcf, 0x60, 0xca, 0x59, 0x0e, 0x4e, 0x96, 0xc2, 0xee, 0x49, - 0xa0, 0x68, 0xcd, 0xd0, 0xb5, 0x3f, 0xc5, 0x56, 0xbd, 0x4a, 0xab, 0x1a, 0xe0, 0x01, 0x21, 0x06, 0x86, 0xda, 0xab, - 0x85, 0x87, 0xd6, 0x02, 0x58, 0xfb, 0xa3, 0xd2, 0x0f, 0xc6, 0x93, 0x25, 0x5f, 0x20, 0xff, 0x72, 0xe4, 0xa8, 0xdd, - 0xfb, 0x7d, 0xef, 0x1e, 0xa4, 0xe0, 0xc8, 0xb5, 0x50, 0x20, 0x11, 0xd0, 0x82, 0x6f, 0x7c, 0xe5, 0x83, 0xf1, 0x16, - 0xb5, 0xd5, 0xa0, 0xa0, 0x76, 0x74, 0xcb, 0x63, 0x47, 0xef, 0x7c, 0x7f, 0x42, 0x5f, 0xbd, 0xd0, 0xc2, 0xf1, 0x57, - 0xce, 0xc8, 0x35, 0x5b, 0x75, 0xc8, 0x11, 0xcd, 0xa4, 0x43, 0x88, 0x58, 0xb1, 0x35, 0x7b, 0x4b, 0x2a, 0xe7, 0xce, - 0x21, 0x3b, 0x7d, 0x84, 0x2a, 0xbd, 0xd6, 0xe3, 0xdb, 0x89, 0xd2, 0xdd, 0x1e, 0xef, 0x26, 0xdf, 0xb2, 0x89, 0x88, - 0xc1, 0x80, 0x36, 0x08, 0x67, 0x64, 0x1d, 0x22, 0x95, 0x0e, 0x10, 0x02, 0xc7, 0x04, 0x34, 0xfd, 0xc7, 0xd7, 0x24, - 0x0a, 0x38, 0xd2, 0x46, 0xc8, 0x5a, 0x76, 0x38, 0xe4, 0xa0, 0x51, 0x6e, 0xfe, 0xf0, 0x0a, 0x75, 0x9a, 0x03, 0xf3, - 0x74, 0x09, 0x7b, 0x0e, 0x1e, 0xe9, 0xc5, 0xf1, 0x91, 0xfe, 0xdf, 0xd1, 0x44, 0x8d, 0xff, 0x73, 0x4d, 0x94, 0xd2, - 0x22, 0x39, 0xaa, 0xa5, 0x6f, 0x52, 0x47, 0xc1, 0x45, 0xde, 0x51, 0x0b, 0xd9, 0xb3, 0x6c, 0xdc, 0xa8, 0xe6, 0xfd, - 0xff, 0x5a, 0x99, 0xff, 0xaf, 0x69, 0x65, 0x98, 0x92, 0x1d, 0x4b, 0x35, 0xf3, 0x40, 0xab, 0x18, 0x66, 0x3f, 0x93, - 0x84, 0xc8, 0x70, 0x69, 0xc0, 0x8f, 0x2a, 0xd8, 0xc7, 0x69, 0xb5, 0xce, 0xc2, 0x1d, 0x2a, 0x51, 0x6f, 0xc5, 0x5d, - 0x9a, 0xbf, 0xa8, 0xff, 0x2d, 0xca, 0x02, 0xa6, 0xf6, 0x5d, 0x99, 0xc6, 0x01, 0x59, 0xf8, 0xb3, 0xb0, 0xc4, 0xc9, - 0x8d, 0x6d, 0xfc, 0x59, 0x8e, 0xa7, 0xfd, 0xaa, 0x33, 0xf3, 0x40, 0x02, 0x35, 0x10, 0x7f, 0xe4, 0x5c, 0x56, 0x16, - 0x0f, 0x08, 0xdd, 0xfc, 0x43, 0x59, 0x16, 0xa5, 0xd7, 0xfb, 0x94, 0xa4, 0xd5, 0xd9, 0x4a, 0xd4, 0x49, 0x11, 0x2b, - 0x28, 0x9b, 0x14, 0x60, 0xf4, 0x61, 0xe5, 0x89, 0x38, 0x38, 0x43, 0xa0, 0x86, 0xb3, 0x3a, 0x09, 0x01, 0x68, 0x58, - 0x21, 0xec, 0x9f, 0x41, 0x0b, 0xcf, 0xc2, 0x38, 0x5c, 0x03, 0x4c, 0x4e, 0x5a, 0x9d, 0xad, 0xcb, 0xe2, 0x3e, 0x8d, - 0x45, 0x3c, 0xea, 0x29, 0x4a, 0x96, 0xd7, 0xb9, 0x2b, 0xe7, 0xfa, 0xfb, 0x3f, 0x28, 0x80, 0xdd, 0x80, 0xd9, 0xb6, - 0xc0, 0x0e, 0x00, 0x12, 0x14, 0xc8, 0x16, 0xea, 0x34, 0x3a, 0x53, 0x4b, 0x05, 0xde, 0x73, 0x3d, 0xc0, 0x5f, 0xe7, - 0x80, 0x65, 0x5c, 0x17, 0x32, 0x60, 0x04, 0x01, 0x8c, 0xc0, 0x41, 0x09, 0x18, 0x3a, 0x43, 0xdc, 0x56, 0xe5, 0xac, - 0x85, 0xe6, 0x4a, 0xb7, 0x25, 0x37, 0x8d, 0x72, 0xb6, 0x12, 0x01, 0xf4, 0xd5, 0x4d, 0x89, 0xd3, 0xe5, 0xb2, 0x95, - 0x84, 0x7d, 0xfb, 0xbe, 0x9d, 0x2a, 0xf2, 0xf8, 0x28, 0x0d, 0x79, 0x05, 0x9e, 0x64, 0x1c, 0x49, 0xa2, 0x44, 0xf0, - 0x3a, 0x6f, 0xcc, 0x38, 0xbc, 0x68, 0x53, 0x4e, 0xed, 0xcd, 0x7a, 0x01, 0x38, 0x4f, 0xd0, 0x96, 0x01, 0xc6, 0x02, - 0x06, 0xe7, 0x42, 0x2c, 0x79, 0x8a, 0xe0, 0x97, 0x4e, 0xa4, 0x30, 0xee, 0x72, 0x18, 0xe6, 0x41, 0xd1, 0xbb, 0xa4, - 0xfe, 0xe8, 0xf7, 0x51, 0x9b, 0x0c, 0x86, 0xa0, 0x12, 0x40, 0x65, 0xdd, 0x20, 0x31, 0xb0, 0x2a, 0x2d, 0x24, 0x2e, - 0x21, 0x5e, 0xe6, 0xab, 0x69, 0x1d, 0x05, 0xef, 0xeb, 0x09, 0x21, 0x9c, 0x60, 0x7c, 0x88, 0x1b, 0x20, 0x60, 0xb0, - 0x8a, 0x0b, 0x0c, 0x92, 0xe7, 0x12, 0xdd, 0x1f, 0xcf, 0x77, 0x0c, 0x70, 0xe5, 0xbc, 0xa7, 0xda, 0xd5, 0x03, 0x7b, - 0xb9, 0x4a, 0x97, 0x8c, 0x10, 0x56, 0xfc, 0x5f, 0x44, 0xde, 0xb7, 0xc3, 0x04, 0xd4, 0x36, 0xf2, 0xc7, 0x20, 0x31, - 0x97, 0x89, 0x22, 0x88, 0x47, 0x59, 0xc1, 0x92, 0x34, 0xd8, 0x8c, 0x92, 0x14, 0x34, 0x9a, 0x18, 0x43, 0xa6, 0x42, - 0x3b, 0x24, 0x8d, 0x66, 0x63, 0xb2, 0x8f, 0x21, 0xaf, 0xe1, 0x62, 0xb1, 0xc0, 0xfb, 0x7e, 0x16, 0xaa, 0x83, 0x6d, - 0x69, 0x0e, 0x01, 0x27, 0x09, 0xf6, 0xd4, 0x15, 0x29, 0x09, 0xb3, 0xd1, 0xa7, 0x90, 0x73, 0x03, 0x3a, 0x4e, 0x1a, - 0x43, 0xf5, 0x81, 0x49, 0x78, 0x15, 0xa1, 0x93, 0xb2, 0x42, 0x58, 0xc0, 0x7d, 0x23, 0xa3, 0xd1, 0x4a, 0x1a, 0x04, - 0xde, 0x66, 0xd8, 0x0a, 0x6c, 0x42, 0xc3, 0x5f, 0x64, 0x1e, 0xa6, 0xd5, 0xac, 0x04, 0x73, 0xbe, 0x81, 0x4a, 0x8c, - 0x27, 0xcb, 0x2b, 0xbe, 0x71, 0xb1, 0x12, 0x93, 0xd9, 0x72, 0x3e, 0x59, 0x4b, 0xaa, 0xb9, 0xdc, 0x5b, 0xb3, 0x8c, - 0x2d, 0x61, 0xff, 0x30, 0x30, 0x94, 0x0e, 0xec, 0x68, 0xaa, 0x69, 0x93, 0x00, 0x93, 0xe9, 0x9c, 0xf3, 0xe1, 0x25, - 0xa2, 0xc9, 0xea, 0xd4, 0x9d, 0x4c, 0x55, 0x3b, 0xb8, 0x26, 0x67, 0x72, 0x7a, 0xa4, 0x9e, 0x6a, 0xdd, 0x4b, 0x3e, - 0xda, 0x0e, 0xab, 0xd1, 0xd6, 0x0f, 0xc0, 0xad, 0x53, 0xd8, 0xe9, 0xbb, 0x61, 0x35, 0xda, 0xf9, 0x1a, 0x76, 0x97, - 0x14, 0x02, 0xd5, 0x9f, 0x65, 0x4d, 0xe6, 0xe2, 0x75, 0xf1, 0xe0, 0x15, 0xec, 0xb9, 0x3f, 0xd0, 0xbf, 0x4a, 0xf6, - 0xdc, 0xb7, 0x99, 0x5c, 0xff, 0x4c, 0xbb, 0x46, 0x63, 0xa6, 0xe3, 0xb5, 0x2b, 0xb0, 0x42, 0x03, 0xe4, 0x17, 0xec, - 0x68, 0x6f, 0x72, 0x10, 0x08, 0xd0, 0xbd, 0x04, 0x47, 0x51, 0x40, 0xd4, 0xb4, 0xaa, 0x3c, 0x3a, 0xdd, 0xfb, 0x7b, - 0x7c, 0xa3, 0x04, 0x6c, 0xf2, 0xd4, 0xba, 0xb7, 0x8c, 0xfd, 0xc3, 0x01, 0x42, 0xe8, 0xe5, 0xf4, 0x1b, 0x6d, 0x59, - 0x3d, 0xda, 0xb1, 0xdc, 0x37, 0x8c, 0x7a, 0x0a, 0xc6, 0x30, 0x74, 0x61, 0x15, 0x23, 0x79, 0x06, 0x64, 0x8d, 0xdf, - 0x20, 0xba, 0x80, 0x45, 0xaf, 0xf7, 0xea, 0x88, 0x06, 0x11, 0x50, 0xe9, 0x35, 0x7f, 0x29, 0xf2, 0xb9, 0x2a, 0x44, - 0xef, 0xbd, 0xb5, 0xf3, 0x66, 0x46, 0xb2, 0x4c, 0x1a, 0xa9, 0x76, 0x2b, 0x8b, 0x75, 0xe5, 0xcd, 0x4e, 0x48, 0x17, - 0x73, 0x0c, 0x95, 0xc1, 0xe3, 0x00, 0x94, 0x9e, 0x7f, 0x0b, 0xbd, 0x92, 0x21, 0xd3, 0x2c, 0xd1, 0xcc, 0xee, 0x1a, - 0x7f, 0xb2, 0x4a, 0xbd, 0x18, 0x11, 0xb3, 0x81, 0x2d, 0xc4, 0x6d, 0x51, 0xe9, 0xb6, 0x28, 0x94, 0x2d, 0x8a, 0xf4, - 0xa1, 0x76, 0xa6, 0x3b, 0xb3, 0xf0, 0x59, 0x65, 0xda, 0xf7, 0x26, 0x33, 0x63, 0x03, 0xb4, 0x5d, 0x84, 0x6f, 0xa0, - 0x03, 0x15, 0x42, 0xfe, 0x03, 0x22, 0x22, 0x11, 0xb0, 0xcb, 0xa9, 0x3b, 0xb1, 0xe9, 0x90, 0xcc, 0x43, 0xcc, 0x0a, - 0x35, 0xca, 0x4b, 0x9e, 0x1c, 0x0d, 0x48, 0x45, 0xa8, 0xdb, 0xfd, 0xfe, 0xf9, 0xd2, 0x05, 0xb5, 0x5f, 0x53, 0xec, - 0x18, 0xdd, 0x14, 0x70, 0x2e, 0x78, 0x94, 0xf7, 0xdc, 0x3b, 0x07, 0x34, 0xc7, 0xf6, 0x14, 0x59, 0x03, 0x4e, 0x6f, - 0xbb, 0x10, 0x60, 0xfb, 0xac, 0xd9, 0xda, 0x9f, 0xac, 0xae, 0xa2, 0xa9, 0x57, 0xf2, 0x99, 0xee, 0xa2, 0xc4, 0xed, - 0xa2, 0x58, 0x76, 0xd1, 0xa6, 0x81, 0x60, 0xc7, 0x95, 0x1f, 0x00, 0x6f, 0x68, 0xd4, 0xef, 0x97, 0xad, 0x9e, 0x3d, - 0xf9, 0xda, 0x71, 0xcf, 0x66, 0x3e, 0x2b, 0x4d, 0xcf, 0xfe, 0x9a, 0xba, 0x3d, 0x2b, 0x27, 0x7b, 0xd1, 0x39, 0xd9, - 0xa7, 0xb3, 0x79, 0x20, 0xb8, 0xdc, 0xb9, 0xcf, 0xf3, 0xa9, 0x9e, 0x76, 0x95, 0x1f, 0xb4, 0x86, 0xc8, 0x7c, 0xe1, - 0x53, 0xd5, 0xbd, 0xae, 0x60, 0x01, 0x4b, 0x70, 0xb7, 0x5e, 0x9a, 0xff, 0x8a, 0xdd, 0xdf, 0x0b, 0x7a, 0x69, 0xfe, - 0x1b, 0xfd, 0x49, 0x01, 0x1c, 0x80, 0xc6, 0xd4, 0x6e, 0x81, 0x87, 0x18, 0x2a, 0x28, 0xdc, 0xcd, 0xca, 0xb9, 0x57, - 0x03, 0x1c, 0x26, 0xe9, 0x1b, 0x5a, 0xbd, 0xd2, 0x62, 0xd7, 0xcb, 0x64, 0xaf, 0x00, 0x0f, 0x55, 0xc8, 0xc3, 0xc3, - 0x21, 0xea, 0x18, 0x76, 0x50, 0x47, 0xc0, 0xb0, 0x87, 0xd0, 0xd8, 0x02, 0xcf, 0xc7, 0x4f, 0x19, 0xdf, 0x0b, 0x50, - 0x1b, 0x21, 0x3c, 0x5e, 0x2d, 0xca, 0x10, 0x5b, 0xf6, 0x06, 0xa9, 0xa4, 0x7e, 0x16, 0x88, 0x32, 0x5a, 0x05, 0xb4, - 0xd5, 0x1e, 0xb3, 0x34, 0xde, 0x40, 0xa8, 0x58, 0xea, 0x63, 0x08, 0x0d, 0x1c, 0x7e, 0x87, 0x03, 0x48, 0xf0, 0x25, - 0xd7, 0x64, 0x73, 0x6f, 0xf2, 0x7b, 0xda, 0xe7, 0x0f, 0x87, 0xf3, 0x4b, 0x04, 0xa5, 0x4b, 0xe1, 0x23, 0x95, 0x88, - 0xea, 0x29, 0x6e, 0x4a, 0xc8, 0x66, 0xc9, 0x4a, 0x3f, 0xf8, 0x55, 0xfd, 0x02, 0x00, 0x59, 0x08, 0xb4, 0x89, 0xcc, - 0xfe, 0x74, 0xa6, 0xa2, 0x0b, 0x80, 0x43, 0xfc, 0xf1, 0x13, 0x44, 0xdf, 0xd0, 0x32, 0x2d, 0x1f, 0x27, 0x3c, 0x04, - 0xad, 0x2d, 0xe9, 0x24, 0x62, 0xa5, 0xc0, 0x86, 0x48, 0xf8, 0x7e, 0xff, 0x3c, 0x96, 0x74, 0xa0, 0x51, 0xab, 0x7b, - 0xe3, 0x56, 0xf7, 0xca, 0xd7, 0x75, 0x27, 0x37, 0x3e, 0x28, 0xda, 0x67, 0xf3, 0x46, 0xe5, 0xfb, 0xb6, 0xce, 0xd9, - 0x9d, 0xee, 0x1d, 0x39, 0x27, 0xbe, 0xbd, 0x87, 0x50, 0xf4, 0xd0, 0x14, 0x59, 0x96, 0x84, 0x01, 0xad, 0xb5, 0x6b, - 0xcf, 0x32, 0x3a, 0x78, 0xed, 0x1b, 0x42, 0x44, 0x9e, 0xe2, 0x93, 0x90, 0x5b, 0x1c, 0x1f, 0x14, 0xe8, 0x9f, 0x19, - 0x7f, 0xe6, 0xc4, 0x0f, 0x5b, 0xfd, 0x02, 0x38, 0x37, 0xdd, 0x7b, 0x77, 0x62, 0xd6, 0x63, 0x28, 0x65, 0xe3, 0xff, - 0x7e, 0x9f, 0xc8, 0x02, 0x9d, 0x8e, 0x68, 0x18, 0x08, 0xee, 0xa2, 0xfa, 0xbf, 0x57, 0xbc, 0xee, 0x59, 0xab, 0xf3, - 0xe5, 0xa7, 0x4e, 0x4f, 0x7a, 0xf5, 0x32, 0xee, 0x01, 0x15, 0x3a, 0x40, 0x38, 0xaf, 0xfb, 0x0d, 0xdb, 0x7d, 0xf3, - 0xcb, 0xbb, 0xa3, 0x97, 0x81, 0x4d, 0x8a, 0xc4, 0xb6, 0x92, 0xcf, 0x7a, 0xa0, 0xf0, 0xeb, 0xb1, 0x5e, 0x5d, 0xac, - 0x7b, 0xac, 0x87, 0x5a, 0x40, 0xf4, 0xb0, 0x00, 0xf5, 0x5f, 0xcf, 0x3e, 0x0d, 0x85, 0x83, 0x6c, 0x9c, 0x2a, 0x50, - 0x64, 0xc1, 0xaf, 0xc5, 0x68, 0x5d, 0x10, 0x20, 0xb2, 0x25, 0xa4, 0x55, 0x27, 0xb3, 0xc7, 0xa5, 0x96, 0x64, 0xf0, - 0x4d, 0x40, 0x66, 0x07, 0x56, 0x4e, 0x50, 0x3a, 0x6e, 0x0d, 0xb8, 0xb2, 0xc5, 0xa3, 0xdd, 0xfe, 0x34, 0xc8, 0xce, - 0x9a, 0x93, 0x46, 0xfb, 0xb0, 0x4f, 0xf3, 0x00, 0x81, 0x48, 0xa6, 0x22, 0xc8, 0x35, 0xf7, 0x96, 0xf4, 0xd1, 0xe1, - 0x9c, 0x17, 0xf2, 0xcf, 0xa9, 0xd4, 0x21, 0x0e, 0x25, 0xd6, 0x40, 0xa0, 0xf2, 0x0c, 0x55, 0x0e, 0x1b, 0xe4, 0xf8, - 0x67, 0x47, 0x32, 0x93, 0x98, 0x2c, 0x72, 0xb7, 0x66, 0x2a, 0xfc, 0x40, 0xf0, 0x31, 0xcb, 0x39, 0x70, 0x81, 0xcd, - 0xe6, 0xbe, 0x9a, 0xe2, 0xe2, 0x0a, 0xfc, 0x31, 0x85, 0x5f, 0xf1, 0x14, 0x76, 0xda, 0xfd, 0xba, 0xa8, 0x52, 0xd4, - 0x6d, 0x14, 0x16, 0x95, 0x2c, 0x98, 0xd6, 0x90, 0x26, 0x3a, 0x8c, 0xfe, 0x20, 0x67, 0xa0, 0x20, 0xe4, 0x97, 0x4d, - 0x03, 0x8c, 0x54, 0x72, 0x79, 0x50, 0x25, 0x81, 0x17, 0x60, 0x1b, 0x54, 0x6c, 0x5d, 0x40, 0x90, 0x6d, 0x52, 0x94, - 0xe9, 0x97, 0x22, 0xaf, 0xc3, 0x2c, 0xa8, 0x46, 0x69, 0xf5, 0xa3, 0xfe, 0x09, 0xcc, 0xdb, 0x54, 0x8c, 0x6a, 0x15, - 0x93, 0xdf, 0xe8, 0xf7, 0x8b, 0x41, 0xeb, 0x43, 0x06, 0x1f, 0xbd, 0x36, 0x0d, 0xfe, 0xe8, 0x34, 0xd8, 0x61, 0xa2, - 0x11, 0x00, 0xc9, 0x9c, 0x5a, 0xf2, 0x50, 0xf4, 0x47, 0x90, 0x63, 0x8d, 0x2a, 0xa7, 0x60, 0xb0, 0xfe, 0xe3, 0xd1, - 0x0e, 0x4c, 0xbd, 0x38, 0xda, 0x92, 0x1d, 0xb4, 0xf2, 0x0d, 0x70, 0xbf, 0x46, 0xb6, 0x98, 0xe5, 0x00, 0xcd, 0x5e, - 0x23, 0x32, 0x3e, 0x79, 0x01, 0x8c, 0xd9, 0x3a, 0x0b, 0x23, 0x11, 0x07, 0x63, 0xd5, 0x98, 0x31, 0x03, 0x03, 0x17, - 0xe8, 0x5a, 0x26, 0x25, 0x69, 0x48, 0x07, 0x03, 0x56, 0xca, 0x16, 0x0e, 0x78, 0xd1, 0x1c, 0xb7, 0xe3, 0x75, 0x8b, - 0xc6, 0x03, 0xdb, 0xc5, 0xf6, 0xf7, 0xdf, 0x17, 0xdb, 0xb7, 0xe1, 0x96, 0xf4, 0x0a, 0x39, 0x4b, 0xe8, 0xe7, 0x8f, - 0xb2, 0xcf, 0x1a, 0x4e, 0x4e, 0x85, 0x66, 0x68, 0x29, 0x12, 0x4a, 0xf1, 0x4e, 0x4f, 0x0a, 0x8c, 0x65, 0x2c, 0xfc, - 0x3d, 0x70, 0x4e, 0x17, 0x8a, 0xc8, 0x1d, 0x38, 0x8e, 0x6f, 0xa0, 0x82, 0x51, 0xc3, 0xc1, 0xcb, 0x18, 0xb6, 0x45, - 0x31, 0x0b, 0x09, 0xa7, 0x10, 0x2e, 0x56, 0x59, 0xbf, 0x2f, 0x7f, 0x51, 0x17, 0x5d, 0x64, 0xb2, 0xee, 0x93, 0x70, - 0x64, 0xc6, 0x72, 0xea, 0x85, 0xe4, 0x79, 0xcf, 0x93, 0x69, 0xf2, 0x2c, 0x0f, 0x22, 0x80, 0x7c, 0x0e, 0xef, 0xc3, - 0x34, 0x03, 0xab, 0x34, 0x29, 0x3f, 0x42, 0xe9, 0x8b, 0xcf, 0x2b, 0x3f, 0xd0, 0xd9, 0x73, 0x93, 0x0c, 0x6f, 0x56, - 0xad, 0x37, 0xa9, 0x75, 0x5d, 0x3c, 0xe0, 0x5f, 0x9c, 0xc1, 0xc6, 0xb9, 0xce, 0x04, 0x07, 0x5e, 0x24, 0xb5, 0x5e, - 0x33, 0x7e, 0x9d, 0xe1, 0xba, 0x54, 0x6d, 0xf4, 0x51, 0x88, 0xce, 0x21, 0x53, 0x01, 0x0a, 0x45, 0xda, 0x3f, 0x28, - 0xb5, 0x32, 0xa9, 0xb4, 0x91, 0x00, 0xba, 0x87, 0x49, 0x83, 0x2d, 0x86, 0x32, 0x96, 0x26, 0x51, 0xee, 0x34, 0x88, - 0x2b, 0xfb, 0x73, 0x25, 0x71, 0x68, 0x59, 0x24, 0xff, 0xde, 0xf5, 0xf4, 0x15, 0x52, 0x77, 0xb2, 0x40, 0x66, 0x8c, - 0x17, 0x79, 0xfc, 0x09, 0x08, 0xb3, 0x41, 0x1b, 0x15, 0x85, 0x10, 0xb2, 0x41, 0x0c, 0x1a, 0x2f, 0xf2, 0xf8, 0x7b, - 0x45, 0xe3, 0x21, 0x1f, 0x45, 0xbe, 0xfa, 0xab, 0xd4, 0x7f, 0x85, 0x3e, 0x33, 0xc1, 0x23, 0x54, 0x13, 0xfd, 0xbb, - 0xe7, 0xb3, 0x7b, 0x50, 0x1b, 0x46, 0x61, 0x66, 0xca, 0xaf, 0x7c, 0x53, 0x9c, 0xbd, 0xfe, 0x8a, 0xae, 0xb2, 0xad, - 0xfb, 0xd1, 0xc7, 0x23, 0x02, 0x6b, 0x63, 0x74, 0xc5, 0x8d, 0x01, 0xe4, 0x30, 0x79, 0xbf, 0xa2, 0xb4, 0x1c, 0xd2, - 0x20, 0x74, 0xd0, 0x10, 0xf4, 0x4a, 0xa2, 0x0f, 0x24, 0x16, 0x31, 0x86, 0x17, 0xe2, 0x19, 0xa9, 0xc9, 0x44, 0x43, - 0xbc, 0x22, 0xf6, 0x43, 0xb4, 0xe4, 0xd4, 0x44, 0x37, 0xc2, 0x14, 0x03, 0x89, 0x9d, 0x41, 0x72, 0x92, 0xd4, 0xca, - 0x2f, 0x9e, 0x49, 0xc2, 0x12, 0x3b, 0x0f, 0x31, 0x98, 0xd4, 0xd2, 0x9d, 0xde, 0x54, 0xe9, 0xdd, 0x91, 0x96, 0x83, - 0xf6, 0x01, 0xd8, 0xa5, 0xa4, 0xf7, 0x4f, 0x0a, 0x45, 0x7c, 0x08, 0xe3, 0x18, 0xc2, 0xb7, 0x88, 0xea, 0x0a, 0x9c, - 0x6b, 0x05, 0x1a, 0xab, 0x81, 0x87, 0x66, 0x56, 0xcd, 0x87, 0x9c, 0x7e, 0x2a, 0x2d, 0x7f, 0x8c, 0x68, 0x6c, 0xb4, - 0x6e, 0x0e, 0x87, 0x3d, 0xad, 0x7a, 0xe9, 0x1c, 0x74, 0xd9, 0x4c, 0x62, 0xe2, 0x06, 0xd2, 0xf5, 0xa3, 0xdf, 0x4c, - 0xd8, 0x8b, 0xa8, 0x90, 0x4b, 0x21, 0x28, 0x68, 0x75, 0x20, 0x70, 0x28, 0xbc, 0x45, 0x99, 0x2f, 0x62, 0xda, 0x40, - 0x18, 0x7c, 0x7e, 0x20, 0x3f, 0xdf, 0x14, 0xa4, 0x62, 0xc7, 0xba, 0xf6, 0xfb, 0x9b, 0xd2, 0x03, 0x3c, 0x39, 0x93, - 0xe4, 0x69, 0x33, 0x84, 0x15, 0x01, 0x34, 0x66, 0x35, 0x59, 0x9c, 0x70, 0x65, 0x0e, 0x3f, 0x56, 0x5e, 0xc9, 0x52, - 0xa6, 0xce, 0x53, 0xbd, 0x00, 0xa2, 0x8e, 0x37, 0x68, 0x45, 0xea, 0x57, 0xe8, 0xec, 0x35, 0x2b, 0x21, 0xe3, 0xe1, - 0x39, 0xe7, 0xe9, 0xe8, 0x81, 0x25, 0x3c, 0xc2, 0xbf, 0x92, 0x89, 0x3e, 0xfc, 0x1e, 0x38, 0xdc, 0x8c, 0x13, 0x1e, - 0xb9, 0xcd, 0xde, 0x57, 0xe1, 0x0a, 0x6e, 0xa6, 0x05, 0x20, 0xb9, 0x05, 0x49, 0x13, 0x50, 0x42, 0x22, 0x13, 0x32, - 0x6b, 0x4a, 0x7e, 0x6e, 0x69, 0x1b, 0xac, 0x61, 0xd2, 0x79, 0xc0, 0x8b, 0x56, 0x1f, 0xad, 0x26, 0xda, 0x65, 0x96, - 0xcf, 0x87, 0x38, 0x43, 0x35, 0xc7, 0xdd, 0x19, 0xfc, 0x1c, 0xf0, 0x8a, 0x55, 0x4d, 0x3a, 0xda, 0x0d, 0xb8, 0xf0, - 0xe4, 0x3a, 0x4f, 0x47, 0x5b, 0xfc, 0x25, 0xf7, 0x07, 0x80, 0x0e, 0xa6, 0x2e, 0x81, 0x3f, 0x55, 0x5b, 0x4d, 0xa5, - 0x7e, 0x69, 0xed, 0xd7, 0x75, 0x67, 0xb5, 0x72, 0xcf, 0xba, 0x0c, 0xed, 0x91, 0x21, 0x67, 0xcc, 0x80, 0x3f, 0x67, - 0x2c, 0xf9, 0x73, 0xc6, 0x8a, 0x3f, 0x67, 0xdc, 0x18, 0x19, 0x40, 0x09, 0xee, 0x25, 0xbf, 0xde, 0x23, 0x66, 0x88, - 0xd5, 0xa0, 0x12, 0x58, 0x59, 0xca, 0xb9, 0x8f, 0x9c, 0x62, 0xca, 0x29, 0xc3, 0x4b, 0xa7, 0x33, 0x77, 0x20, 0xe7, - 0xc1, 0xcc, 0x1d, 0x26, 0x67, 0x7d, 0x8a, 0x63, 0x69, 0x4c, 0x8a, 0x0a, 0xd2, 0x39, 0x1d, 0x6e, 0x5e, 0x1d, 0xe7, - 0x09, 0xcb, 0xf8, 0xb8, 0x7d, 0xa6, 0x40, 0x88, 0x2d, 0x9e, 0x21, 0x91, 0x52, 0x35, 0xcb, 0x6d, 0xfe, 0x70, 0xa8, - 0x47, 0x0f, 0x7a, 0xa7, 0x87, 0x5f, 0x09, 0xfb, 0x25, 0xf3, 0xec, 0x13, 0x04, 0x30, 0x49, 0xe4, 0x99, 0x84, 0xa3, - 0x1f, 0xcb, 0xd1, 0xdf, 0x34, 0xfc, 0x5d, 0x86, 0xea, 0xee, 0x10, 0x98, 0xd8, 0xb2, 0x03, 0x87, 0xe0, 0x74, 0x55, - 0x89, 0x04, 0x1c, 0x6c, 0x36, 0x2c, 0xd2, 0x7b, 0x3c, 0xc4, 0xf9, 0xa0, 0xf0, 0x11, 0x1a, 0x66, 0xf4, 0x7e, 0x7f, - 0x23, 0xbc, 0x4a, 0xb6, 0xf2, 0x70, 0x48, 0xac, 0xbb, 0xb0, 0xa3, 0x8f, 0xa3, 0x3d, 0x4a, 0xa8, 0xfd, 0xa8, 0xd6, - 0x9b, 0x4a, 0x3d, 0xc8, 0xcd, 0x2e, 0x24, 0x06, 0x15, 0x4b, 0xf5, 0xe9, 0x95, 0xea, 0x43, 0xcd, 0x3a, 0xbf, 0xab, - 0xe3, 0x3e, 0x15, 0xa3, 0xb5, 0x9c, 0x10, 0xe0, 0x3a, 0x48, 0x34, 0x3a, 0x00, 0xc6, 0xd9, 0x66, 0xcb, 0x4b, 0x6d, - 0x9d, 0x28, 0x1d, 0xc7, 0xb9, 0x3e, 0x8e, 0x0f, 0x07, 0x29, 0x66, 0x5c, 0x1e, 0x89, 0x19, 0x97, 0x0d, 0xc0, 0x9b, - 0x75, 0x1e, 0xd4, 0x87, 0xc3, 0x25, 0x5d, 0x8a, 0x4c, 0x67, 0x1b, 0xe5, 0x67, 0x3d, 0x7a, 0x78, 0x96, 0xa0, 0xb9, - 0xb7, 0xc2, 0xde, 0x8b, 0x64, 0x7b, 0x26, 0xeb, 0xd4, 0xcb, 0xc8, 0xa7, 0x17, 0xee, 0xd9, 0x25, 0x57, 0x3f, 0xac, - 0xbe, 0x9e, 0xfe, 0x2a, 0xbc, 0x88, 0x55, 0xb4, 0x5b, 0x97, 0x4c, 0xd8, 0x5b, 0x4a, 0x25, 0xad, 0xf2, 0xf2, 0xe9, - 0xc6, 0x0f, 0x30, 0x33, 0xed, 0xe9, 0x83, 0x6c, 0x44, 0xf5, 0x67, 0x25, 0x6a, 0x65, 0x98, 0x2c, 0x9c, 0x97, 0x4c, - 0x3d, 0x19, 0xf0, 0x98, 0x95, 0x3c, 0x92, 0x9d, 0xde, 0x18, 0x04, 0x01, 0xac, 0x73, 0xd2, 0xaa, 0x33, 0x8e, 0x46, - 0xab, 0xca, 0xc5, 0xe9, 0x2a, 0x17, 0x18, 0x6e, 0xb7, 0x66, 0x1b, 0x55, 0x67, 0xb9, 0xa9, 0x55, 0xca, 0x77, 0x00, - 0x1f, 0xcb, 0x2a, 0x17, 0x74, 0x4c, 0x99, 0x3a, 0x6f, 0x20, 0x18, 0x5b, 0xd5, 0xb8, 0x70, 0x6a, 0x5c, 0xf0, 0x88, - 0xda, 0xdd, 0x34, 0xf5, 0x68, 0x0b, 0x2c, 0xa5, 0xa3, 0x1d, 0x2f, 0x51, 0xa5, 0xf0, 0x77, 0xc1, 0xf7, 0x61, 0x1c, - 0x7f, 0x5f, 0x6c, 0xd5, 0x81, 0x78, 0x5b, 0x6c, 0x91, 0xf6, 0x45, 0xfe, 0x85, 0x38, 0xe0, 0xb5, 0xae, 0x29, 0xaf, - 0xad, 0x39, 0x0d, 0x6c, 0x0d, 0x23, 0x25, 0x85, 0x73, 0xf3, 0xe7, 0xe1, 0x40, 0x2b, 0xbb, 0x56, 0x77, 0x85, 0x5a, - 0x8f, 0x39, 0x6c, 0xd8, 0x8b, 0x2c, 0xdc, 0x89, 0x12, 0x1c, 0xb9, 0xe4, 0x5f, 0x87, 0x83, 0x56, 0x59, 0xaa, 0x23, - 0x7d, 0xb6, 0xff, 0x12, 0x8c, 0x19, 0xba, 0x34, 0x01, 0xcb, 0xc6, 0x48, 0xfe, 0xd5, 0x34, 0xf3, 0x86, 0xc9, 0x9a, - 0x29, 0x1c, 0x87, 0x86, 0x11, 0xd2, 0x80, 0x6e, 0x83, 0xda, 0xf0, 0x64, 0xbe, 0xa9, 0xca, 0xaf, 0xee, 0x48, 0xb5, - 0x1f, 0x0c, 0x2f, 0x27, 0xe2, 0x9c, 0x2e, 0x49, 0xea, 0xa9, 0x84, 0x92, 0x10, 0xec, 0xd2, 0x07, 0x72, 0x62, 0x05, - 0x64, 0x2d, 0x63, 0xf9, 0xad, 0x1e, 0x10, 0xfa, 0x4f, 0xbb, 0xf5, 0x42, 0xff, 0x69, 0x9a, 0x2d, 0xd4, 0xf5, 0x87, - 0xc9, 0x7d, 0x47, 0xaf, 0x3f, 0x38, 0xbc, 0x53, 0x57, 0x15, 0x57, 0xf1, 0xb0, 0x36, 0x4c, 0x72, 0xa3, 0x2c, 0xdc, - 0x15, 0x9b, 0x5a, 0x2d, 0x4f, 0xc7, 0x61, 0x04, 0x66, 0x04, 0x05, 0xc8, 0xba, 0x6e, 0x23, 0x62, 0x58, 0xc9, 0x65, - 0x42, 0x3e, 0x21, 0x20, 0x8b, 0x52, 0xe3, 0x7c, 0xdc, 0x02, 0x95, 0x08, 0x06, 0xa7, 0xa1, 0xb5, 0xea, 0x26, 0x3f, - 0xaa, 0x6c, 0xec, 0x0e, 0xc8, 0x21, 0xc9, 0x64, 0x71, 0x37, 0xba, 0x15, 0xcb, 0xa2, 0x14, 0x3f, 0x63, 0x3d, 0x5c, - 0xb3, 0x85, 0xfb, 0x0c, 0x08, 0xed, 0x27, 0x4a, 0x7b, 0x13, 0x69, 0x82, 0xee, 0x3b, 0xb6, 0x02, 0x90, 0x01, 0x14, - 0x75, 0xb5, 0x5b, 0x9f, 0xf3, 0x73, 0x24, 0xcd, 0x70, 0x18, 0xdd, 0x3e, 0xbd, 0x0b, 0xee, 0x06, 0x97, 0xa8, 0x95, - 0xbe, 0x64, 0x71, 0x0b, 0x83, 0x6a, 0x6f, 0x96, 0x70, 0x50, 0x33, 0x6b, 0x6d, 0x04, 0x82, 0xc9, 0x1e, 0x0a, 0x2a, - 0xe6, 0x0a, 0xf6, 0x41, 0xc1, 0x5a, 0xf2, 0x3a, 0x38, 0xdc, 0xda, 0x97, 0x95, 0xe2, 0xe2, 0xf9, 0x45, 0xd2, 0xba, - 0xb0, 0x94, 0x17, 0xcf, 0x1b, 0x30, 0xb8, 0x1c, 0x61, 0x53, 0x55, 0xfe, 0x64, 0x03, 0xa0, 0x5b, 0x21, 0x45, 0xbc, - 0x28, 0x85, 0x6d, 0x2b, 0x9f, 0x39, 0x61, 0x83, 0x0d, 0x7b, 0x80, 0x7b, 0x65, 0x50, 0x32, 0xb8, 0x10, 0xe3, 0x76, - 0xb3, 0x0b, 0x70, 0x05, 0x43, 0x61, 0x6c, 0xcd, 0x5f, 0x67, 0x5e, 0xa4, 0x04, 0xdc, 0x0c, 0x51, 0xbe, 0x36, 0x70, - 0x32, 0xe9, 0xc9, 0xb5, 0x64, 0x31, 0x60, 0x41, 0x83, 0xef, 0xa8, 0xf5, 0x77, 0x26, 0xff, 0xc6, 0xd3, 0x43, 0x3f, - 0xf8, 0x9c, 0x79, 0x4b, 0x9f, 0xbd, 0xae, 0x64, 0xb4, 0x26, 0x89, 0xf2, 0xea, 0xe1, 0x12, 0xe4, 0x86, 0xe5, 0xe8, - 0x81, 0x2d, 0x41, 0x9c, 0x58, 0x8e, 0x12, 0xca, 0xe8, 0x0a, 0xf7, 0x2a, 0xb3, 0x65, 0x22, 0x90, 0xe2, 0xc0, 0x52, - 0xca, 0xbd, 0xc5, 0x3a, 0x58, 0xe2, 0xfe, 0x44, 0x72, 0x01, 0x25, 0x0f, 0xa0, 0x5c, 0x29, 0x20, 0xe0, 0xd3, 0x01, - 0x94, 0x2f, 0xe5, 0x45, 0xf8, 0x13, 0x27, 0x6a, 0xb0, 0x1c, 0x3d, 0x34, 0xec, 0x47, 0x2f, 0xb4, 0xec, 0x0f, 0x77, - 0x5a, 0xd3, 0xb0, 0xe2, 0x77, 0x30, 0x2d, 0x26, 0x6e, 0x5f, 0xae, 0xec, 0xaa, 0xf8, 0x6c, 0xa5, 0xce, 0x6e, 0x6a, - 0x48, 0xc2, 0xbe, 0x22, 0xab, 0x00, 0x07, 0xab, 0x22, 0xee, 0x59, 0x96, 0xfb, 0x30, 0xfa, 0x73, 0x93, 0x96, 0xc2, - 0x42, 0x95, 0xf4, 0xf7, 0x4d, 0x29, 0x90, 0xca, 0x44, 0x27, 0x5a, 0x08, 0xae, 0xc0, 0x20, 0x70, 0x2f, 0xf2, 0x1a, - 0x00, 0x63, 0xc0, 0xa5, 0x40, 0x59, 0xb6, 0x25, 0x84, 0x54, 0xf7, 0x33, 0x50, 0xdb, 0x89, 0xfb, 0x34, 0x22, 0x6b, - 0x21, 0xfa, 0x2a, 0x18, 0x33, 0xe7, 0xa5, 0x74, 0x8b, 0x4d, 0x57, 0x9b, 0xd5, 0x0d, 0x3a, 0x97, 0xb6, 0xdc, 0xfc, - 0x84, 0x2d, 0xd6, 0x0a, 0x94, 0x4d, 0x48, 0xda, 0xce, 0x79, 0x8e, 0xb2, 0x09, 0x2d, 0xed, 0x3d, 0xf5, 0xa8, 0x50, - 0x9d, 0x6c, 0xbd, 0x54, 0x4d, 0x2d, 0xc2, 0x6a, 0x71, 0x51, 0xf9, 0x01, 0xe8, 0xa6, 0xd2, 0xea, 0x45, 0x5d, 0xa3, - 0x29, 0xd4, 0x6a, 0xe1, 0xb8, 0xd1, 0xce, 0xa6, 0xcb, 0xf4, 0x0e, 0x71, 0x56, 0xa5, 0x1d, 0xfa, 0xfb, 0x4c, 0xbb, - 0x5e, 0x76, 0xf4, 0x9b, 0x71, 0x75, 0x81, 0x0b, 0xb1, 0x01, 0x9f, 0x73, 0x7f, 0x79, 0xbd, 0xe7, 0x71, 0xcf, 0x3f, - 0x1c, 0x90, 0x3d, 0xa9, 0xfd, 0xa1, 0xfa, 0xd8, 0x15, 0x0c, 0x59, 0x18, 0xa5, 0xfe, 0x22, 0xe5, 0xbd, 0x27, 0x38, - 0xee, 0x9f, 0xab, 0x1e, 0xfb, 0x31, 0xe3, 0xfb, 0xba, 0xd8, 0x44, 0x09, 0x45, 0x35, 0xf4, 0x56, 0xc5, 0xa6, 0x12, - 0x71, 0xf1, 0x90, 0xf7, 0x18, 0x26, 0xc3, 0x58, 0xc8, 0x54, 0xf8, 0x53, 0xa6, 0x82, 0x47, 0x08, 0x25, 0x6e, 0xd6, - 0x3d, 0xd2, 0x6e, 0x42, 0x9c, 0x52, 0x2d, 0x4a, 0x99, 0x8c, 0x7f, 0xeb, 0x27, 0x50, 0x9e, 0x53, 0xb4, 0x4c, 0x3f, - 0x2a, 0x5c, 0xa6, 0x6f, 0xd6, 0xc7, 0xa5, 0x67, 0x22, 0xd4, 0x99, 0x8b, 0x4d, 0xad, 0xd3, 0x31, 0x76, 0x4a, 0xa7, - 0x36, 0xec, 0x4b, 0xa5, 0xb8, 0xac, 0x28, 0xfc, 0x1b, 0x89, 0xac, 0x7a, 0x46, 0x1c, 0xff, 0x57, 0xd6, 0x3e, 0xc3, - 0x2a, 0xf0, 0xcb, 0x40, 0xde, 0x2f, 0x00, 0x3e, 0xae, 0xeb, 0x32, 0xbd, 0xdd, 0x00, 0x6d, 0x08, 0x0d, 0x7f, 0xcf, - 0x47, 0x06, 0x4c, 0xf7, 0x11, 0xce, 0x90, 0x1e, 0xea, 0x9c, 0xd3, 0x59, 0x99, 0xce, 0xb9, 0x0a, 0x6b, 0x09, 0xf6, - 0x72, 0xd2, 0xe4, 0x72, 0x5d, 0x82, 0x9a, 0x09, 0xdc, 0x3e, 0xb4, 0x47, 0x84, 0x50, 0x9b, 0xb2, 0x9a, 0x5e, 0x42, - 0xcd, 0x3b, 0x39, 0xed, 0x68, 0x52, 0x82, 0xab, 0x86, 0xce, 0xca, 0xf5, 0x5f, 0x87, 0x43, 0xef, 0x36, 0x2b, 0xa2, - 0x3f, 0x7a, 0xe8, 0xef, 0xb8, 0xbd, 0x49, 0xbf, 0x40, 0xb4, 0x8c, 0xf5, 0x37, 0x64, 0x40, 0xc7, 0x93, 0xe1, 0x6d, - 0xb1, 0xed, 0xb1, 0x2f, 0xa8, 0xc1, 0xd2, 0xd7, 0x8f, 0x3f, 0x40, 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, - 0x89, 0xb6, 0x85, 0x0f, 0x61, 0xa1, 0x5f, 0x20, 0x32, 0x12, 0xc2, 0x4d, 0x65, 0xf7, 0x28, 0x69, 0x17, 0xfa, 0xd2, - 0xd7, 0xb2, 0xaf, 0x7c, 0xe7, 0x02, 0x60, 0x65, 0x9f, 0xdb, 0x70, 0x4f, 0xfa, 0x53, 0xaa, 0x0f, 0xdb, 0xdf, 0x92, - 0x05, 0x14, 0x5a, 0x58, 0x4f, 0xe5, 0xec, 0x5c, 0x97, 0x3c, 0xcd, 0xa6, 0xfb, 0x35, 0xec, 0x51, 0xf7, 0xe8, 0x35, - 0x15, 0x9c, 0x5f, 0x9a, 0xd1, 0xfb, 0xa7, 0xa1, 0x50, 0x1d, 0x75, 0xee, 0x20, 0xeb, 0xd2, 0xba, 0xe4, 0xfc, 0x66, - 0xe5, 0x8e, 0xc2, 0xfc, 0x3e, 0x04, 0xcf, 0xb0, 0xee, 0xdd, 0xc5, 0x79, 0xef, 0xcf, 0xd6, 0x1c, 0xf9, 0x31, 0x9b, - 0xa5, 0x88, 0x45, 0x32, 0x07, 0xab, 0x1f, 0xfa, 0x79, 0xec, 0xb7, 0x41, 0x0e, 0xc7, 0x4d, 0x03, 0x3a, 0x6c, 0xc8, - 0xac, 0x7d, 0x89, 0xc0, 0xa9, 0x46, 0x90, 0xa6, 0x26, 0xa8, 0x59, 0x1e, 0x22, 0xb1, 0x5d, 0xca, 0xb6, 0x41, 0xae, - 0xbb, 0x60, 0x9a, 0x23, 0xed, 0x19, 0xbc, 0x6f, 0xd2, 0x24, 0x15, 0x9a, 0x45, 0xda, 0x2a, 0x19, 0xff, 0x8e, 0xb4, - 0x99, 0x92, 0x3d, 0xb6, 0x06, 0xde, 0x4b, 0x50, 0x4e, 0x86, 0x29, 0x86, 0xef, 0xf8, 0x7a, 0xe7, 0x31, 0xf7, 0x9c, - 0x63, 0xb6, 0x49, 0xd9, 0x11, 0x4c, 0x92, 0x8d, 0x6f, 0x28, 0xde, 0xf0, 0xfd, 0x6d, 0x25, 0x4a, 0x00, 0xbd, 0x2c, - 0xf8, 0xb5, 0xb4, 0xb9, 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, - 0x17, 0xf1, 0x3b, 0x30, 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, - 0x40, 0x01, 0x46, 0x5f, 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, - 0x1c, 0xe8, 0xfc, 0xbe, 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, 0x86, 0xff, 0xfe, 0x3f, 0xd6, 0x96, 0x56, 0x95, - 0xed, 0xd6, 0x38, 0xcd, 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x52, 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x83, 0xe8, - 0x7d, 0xdd, 0xca, 0xbb, 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, - 0x7a, 0xce, 0xf9, 0xbb, 0xaa, 0xdf, 0xf7, 0xde, 0x01, 0x19, 0xef, 0x4b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, - 0x46, 0xd1, 0xa6, 0x84, 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x93, - 0xf3, 0xfd, 0xa5, 0x90, 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, 0xbe, 0xc7, 0xe9, 0x17, 0xd1, 0x63, 0x77, 0xa5, - 0x0f, 0xdf, 0x95, 0x96, 0x3e, 0xab, 0xa8, 0x7f, 0xa0, 0xa2, 0xe6, 0xa5, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, - 0xa5, 0x76, 0x2d, 0x41, 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1f, 0x1d, 0xf2, 0x7e, 0xff, 0x63, 0xee, 0xb5, 0x78, 0xdd, - 0x75, 0x68, 0xca, 0x4f, 0x85, 0x87, 0x10, 0xc0, 0x5a, 0x06, 0xca, 0x38, 0xc2, 0xa4, 0x8b, 0xbc, 0x46, 0xd9, 0x74, - 0x22, 0xf0, 0x31, 0xcb, 0xae, 0x9c, 0x64, 0x1a, 0x60, 0x46, 0x35, 0x85, 0x99, 0x00, 0x23, 0xf5, 0x11, 0xeb, 0xa6, - 0xa7, 0x55, 0x68, 0xf9, 0x1a, 0x82, 0x75, 0x91, 0x65, 0x1c, 0xc5, 0x4c, 0x00, 0xb0, 0xf9, 0x08, 0xf2, 0x15, 0x5d, - 0x1d, 0x92, 0x56, 0xaa, 0xbc, 0x5f, 0x67, 0x44, 0x46, 0x93, 0x10, 0xcd, 0x6f, 0xe1, 0x81, 0x7d, 0xdb, 0xcc, 0xa8, - 0x52, 0xcf, 0xa8, 0xca, 0x67, 0x38, 0x2c, 0x85, 0x63, 0xc4, 0xff, 0x7b, 0xaa, 0x7a, 0x44, 0xa0, 0x57, 0x65, 0x5a, - 0x45, 0x45, 0x9e, 0x8b, 0x08, 0x11, 0xaa, 0xa5, 0x73, 0x38, 0xf4, 0x63, 0xbf, 0x8f, 0x03, 0x61, 0x5e, 0xfc, 0xe9, - 0xb1, 0xae, 0xfc, 0xa9, 0xc0, 0xb5, 0x92, 0x02, 0xa7, 0xa2, 0x46, 0x88, 0x10, 0xde, 0x9f, 0xc0, 0xb3, 0x9a, 0xfa, - 0x7e, 0x63, 0x99, 0xe8, 0xfe, 0x99, 0x01, 0xe5, 0x0f, 0xc8, 0xd7, 0x95, 0x14, 0x67, 0xea, 0xe4, 0x31, 0x71, 0xc6, - 0x01, 0x88, 0xf9, 0xba, 0x44, 0xa3, 0xb1, 0xff, 0x01, 0x09, 0x86, 0xea, 0x07, 0x3b, 0xdd, 0xd4, 0xfb, 0x57, 0x26, - 0x71, 0x14, 0x7d, 0xda, 0x26, 0x8f, 0x25, 0x4b, 0xa3, 0x85, 0xa3, 0xf7, 0x88, 0x61, 0x1c, 0x4e, 0xe7, 0x63, 0x92, - 0x6d, 0x4c, 0x56, 0x01, 0xa4, 0x93, 0x99, 0x3a, 0xa6, 0xd4, 0xd1, 0x38, 0xd7, 0x0b, 0xaa, 0xd0, 0x63, 0x5d, 0xf2, - 0x1c, 0xac, 0x27, 0x3f, 0x78, 0xa5, 0x3f, 0x15, 0x72, 0x0e, 0x1b, 0x89, 0xa0, 0xf0, 0x03, 0x5c, 0x0d, 0x56, 0x0a, - 0x18, 0x4c, 0x7d, 0x0b, 0x5f, 0x13, 0xcf, 0x51, 0xf0, 0x28, 0xec, 0x62, 0x6c, 0xad, 0x7c, 0xe7, 0x93, 0x82, 0x72, - 0xcf, 0x8a, 0x39, 0xaf, 0x80, 0x73, 0x19, 0x14, 0xc2, 0x74, 0x3c, 0xcb, 0xff, 0x99, 0xe4, 0xf5, 0xc4, 0x86, 0x00, - 0x19, 0xfc, 0x29, 0x71, 0x5a, 0xba, 0x43, 0x77, 0x1e, 0x7a, 0x16, 0x71, 0xd8, 0xe8, 0xc9, 0xba, 0x2c, 0xb6, 0x29, - 0xea, 0x25, 0xcc, 0x0f, 0xe4, 0xe7, 0x2d, 0xf9, 0x3e, 0x44, 0xf1, 0x36, 0xf8, 0x35, 0x63, 0xb1, 0xc0, 0xbf, 0xfe, - 0x9e, 0x31, 0x9a, 0x68, 0xc1, 0xbf, 0xb3, 0x06, 0x89, 0x8a, 0x7f, 0xca, 0x26, 0x00, 0xeb, 0xc8, 0xd5, 0x87, 0x4f, - 0x89, 0xf1, 0xd6, 0x6c, 0x78, 0xe4, 0x9b, 0x15, 0xe8, 0xd4, 0xe7, 0xee, 0xca, 0xf6, 0x54, 0x35, 0xfe, 0x9e, 0xea, - 0x6a, 0xa4, 0xaa, 0x1a, 0x7f, 0x4f, 0xa9, 0x1a, 0xbf, 0x65, 0x14, 0xbf, 0x53, 0xf9, 0x0c, 0x99, 0x93, 0x4d, 0x4c, - 0xd2, 0xe9, 0x7b, 0xc3, 0x89, 0x5d, 0xf6, 0xab, 0xb7, 0x89, 0xcc, 0x44, 0x0a, 0xb9, 0x37, 0x00, 0x6d, 0xbf, 0xcb, - 0x0d, 0xa7, 0xc4, 0xf9, 0xb9, 0x87, 0x2b, 0x36, 0xad, 0x5e, 0xd2, 0x82, 0x05, 0x36, 0x2f, 0xb3, 0x3c, 0x45, 0x02, - 0xdb, 0xa6, 0xcc, 0xfa, 0x73, 0xee, 0x01, 0x04, 0x33, 0xa9, 0x09, 0x00, 0x69, 0x21, 0x2a, 0x85, 0xc8, 0x5f, 0xe2, - 0xac, 0x3e, 0xe7, 0xbd, 0x4d, 0x1e, 0x13, 0x69, 0x75, 0xaf, 0xdf, 0x4f, 0xcf, 0xd2, 0x9c, 0x82, 0x1a, 0x8e, 0xb3, - 0x4e, 0xbf, 0xcf, 0x82, 0x3a, 0x91, 0xab, 0xf4, 0x1f, 0x6e, 0x90, 0x97, 0xf1, 0x7d, 0xdd, 0xf6, 0xfc, 0x89, 0xfa, - 0x7b, 0x67, 0xfd, 0x6d, 0x81, 0xe0, 0x4e, 0x8e, 0xfd, 0x64, 0x55, 0xca, 0x13, 0xe3, 0xd2, 0xde, 0xf3, 0x9b, 0xba, - 0x28, 0xb2, 0x3a, 0x5d, 0x7f, 0x90, 0x7a, 0x1a, 0xdd, 0x17, 0x7b, 0x30, 0x06, 0xef, 0x00, 0xf0, 0x4c, 0x87, 0x06, - 0x48, 0xdf, 0x33, 0xf2, 0x70, 0x9f, 0x5b, 0xf2, 0x93, 0xca, 0xda, 0x24, 0x61, 0x45, 0xb1, 0x19, 0xc6, 0x08, 0x25, - 0xe3, 0x34, 0xb6, 0x7e, 0xbf, 0xaf, 0xfe, 0xde, 0x61, 0x14, 0x15, 0x15, 0x77, 0x8c, 0x46, 0x65, 0x55, 0x8f, 0xb6, - 0x83, 0xc3, 0xe1, 0x3c, 0xb7, 0x71, 0xb4, 0xf5, 0x0a, 0xd8, 0x5b, 0xa1, 0x52, 0xf6, 0x4a, 0x84, 0xe5, 0x87, 0x2b, - 0xbf, 0xdf, 0x87, 0x7f, 0x65, 0xa4, 0x85, 0xe7, 0x4f, 0xf1, 0xd7, 0xa2, 0x2e, 0x30, 0x3c, 0x83, 0xd6, 0x68, 0x05, - 0xc1, 0x04, 0xff, 0xe8, 0x40, 0xbd, 0xb4, 0xd2, 0x3e, 0x82, 0x6e, 0x05, 0x7a, 0x50, 0x0f, 0x7d, 0x9a, 0xb4, 0x2f, - 0x24, 0xea, 0xf6, 0x56, 0xa7, 0xd1, 0x1f, 0x15, 0x5c, 0x4e, 0x61, 0x72, 0xb8, 0xa1, 0x4f, 0xab, 0x70, 0xfb, 0x09, - 0x9e, 0xfe, 0x0c, 0x94, 0x5b, 0x87, 0x43, 0x0e, 0x62, 0x0b, 0xb8, 0x79, 0xac, 0xc2, 0xcf, 0x45, 0x29, 0x23, 0xea, - 0xe3, 0x69, 0x01, 0xda, 0xbb, 0x00, 0x1d, 0xb0, 0x34, 0x88, 0x57, 0x48, 0x9e, 0xb3, 0x11, 0xc0, 0xb2, 0x03, 0xcb, - 0x59, 0xc6, 0x29, 0xcc, 0xb3, 0xbc, 0x56, 0x2b, 0xed, 0xac, 0x4c, 0xbc, 0x9a, 0x65, 0xe0, 0x2c, 0x70, 0x51, 0xf9, - 0x2c, 0xd3, 0xaa, 0xa7, 0x2a, 0x41, 0x9f, 0x57, 0x72, 0x82, 0x2b, 0xc1, 0xc9, 0x06, 0xe4, 0x17, 0x20, 0x49, 0x53, - 0xca, 0x9a, 0xf2, 0xfa, 0x92, 0x6e, 0xc8, 0xe8, 0x39, 0xef, 0x79, 0xd1, 0x30, 0xf4, 0x2f, 0xbc, 0x12, 0xc2, 0x37, - 0x71, 0xdb, 0x46, 0x29, 0xec, 0x6f, 0x02, 0x8b, 0x4f, 0xd8, 0x0f, 0xde, 0xd2, 0x9f, 0x8e, 0x83, 0x70, 0x88, 0xdc, - 0x50, 0x31, 0x07, 0xf6, 0x34, 0x60, 0xb1, 0x89, 0xaf, 0x36, 0x93, 0x78, 0x30, 0xf0, 0x75, 0xc6, 0x62, 0x16, 0x03, - 0x0d, 0x72, 0x3c, 0xb8, 0x9c, 0xeb, 0x13, 0x42, 0x3f, 0x8c, 0xa8, 0x1c, 0x15, 0xe8, 0x1c, 0x44, 0x83, 0x25, 0xe0, - 0xa9, 0xb7, 0xb2, 0x41, 0x92, 0x31, 0xc9, 0x24, 0xae, 0x35, 0x49, 0x75, 0x38, 0xa1, 0x75, 0xa0, 0xe3, 0xea, 0x02, - 0x3a, 0x1f, 0xd7, 0xbd, 0x8f, 0x57, 0xc3, 0x05, 0x95, 0x7e, 0x21, 0x06, 0x5e, 0x3d, 0x1d, 0x07, 0x97, 0x74, 0x2b, - 0x5c, 0xac, 0xc2, 0xed, 0xcf, 0xf2, 0x81, 0xe3, 0x8e, 0x4a, 0x1a, 0x02, 0x83, 0xb7, 0x87, 0xee, 0x66, 0x86, 0x86, - 0x3a, 0x69, 0x1f, 0xc6, 0xa1, 0x1c, 0x62, 0xd5, 0x8a, 0x0b, 0xe9, 0x8d, 0xe0, 0xdb, 0x85, 0x62, 0x2c, 0x1b, 0xbb, - 0x34, 0x14, 0x85, 0xbf, 0x02, 0xd8, 0xa1, 0xf6, 0x57, 0x2a, 0xf9, 0x18, 0x19, 0xd5, 0x34, 0xd0, 0x31, 0x00, 0x4b, - 0x96, 0x26, 0x92, 0x2a, 0xd2, 0x48, 0xfc, 0x91, 0x19, 0xeb, 0xa8, 0xe9, 0xfa, 0x82, 0xa9, 0x6a, 0x91, 0x74, 0x3b, - 0x93, 0x58, 0x4e, 0x24, 0xa9, 0xed, 0x3e, 0x22, 0x06, 0x03, 0x1f, 0x6c, 0xc4, 0x34, 0x13, 0xe1, 0x88, 0x47, 0x25, - 0xb2, 0xe8, 0xf2, 0xdb, 0x28, 0x93, 0xb6, 0x2f, 0x2b, 0xb2, 0x05, 0xc1, 0xf4, 0x24, 0xfa, 0x20, 0x49, 0x39, 0x15, - 0x89, 0x34, 0x23, 0x04, 0xf8, 0xf1, 0xa4, 0xbc, 0xd2, 0x9f, 0x83, 0xa6, 0x95, 0xe0, 0x25, 0x83, 0xe4, 0x91, 0xf8, - 0x99, 0x14, 0xcc, 0x62, 0xac, 0x1a, 0x0c, 0xb0, 0x9c, 0xea, 0x99, 0x63, 0x92, 0xfe, 0x5b, 0xa7, 0x13, 0xf6, 0x0b, - 0x2f, 0xb7, 0xb5, 0xbc, 0x69, 0xee, 0xbd, 0xf0, 0x2a, 0x96, 0x6a, 0x58, 0x06, 0xfd, 0xd7, 0x44, 0xbb, 0x60, 0x6b, - 0xcb, 0x98, 0xb0, 0xea, 0x07, 0x90, 0xf6, 0x48, 0x97, 0x57, 0x0d, 0x73, 0x26, 0x78, 0x74, 0x61, 0xcd, 0x83, 0xe8, - 0x42, 0xf8, 0xc8, 0x65, 0x37, 0x49, 0xae, 0xc6, 0x13, 0x3f, 0x1c, 0x0c, 0x14, 0x00, 0x2d, 0xad, 0x93, 0x62, 0x10, - 0x3e, 0x13, 0x72, 0x20, 0x8d, 0x8e, 0xaa, 0x00, 0x8b, 0x65, 0x76, 0x55, 0x4e, 0xb2, 0xc1, 0xc0, 0x07, 0xb1, 0x31, - 0xb1, 0x1b, 0x9a, 0xcd, 0x7d, 0x76, 0xa2, 0x20, 0xab, 0xcd, 0x61, 0x6b, 0xa6, 0x5b, 0x60, 0x00, 0x30, 0x88, 0x08, - 0x96, 0xfb, 0xdc, 0xc8, 0x47, 0xd4, 0xe9, 0x29, 0x8c, 0x80, 0xe0, 0x97, 0x13, 0x81, 0xc8, 0x45, 0x02, 0xf5, 0x00, - 0x33, 0x01, 0x66, 0x54, 0x31, 0xbc, 0x04, 0x76, 0xf1, 0xdc, 0xbc, 0x62, 0xd0, 0xbf, 0x68, 0x92, 0x25, 0x9a, 0x4a, - 0x1c, 0x8d, 0x91, 0x53, 0x69, 0x8c, 0x0c, 0x88, 0x5d, 0x1c, 0xff, 0x9e, 0xd2, 0xa3, 0x20, 0x65, 0x9f, 0x2b, 0x43, - 0x1c, 0x8e, 0xe2, 0x2b, 0x58, 0x35, 0x0e, 0x87, 0xda, 0xbc, 0x9e, 0xce, 0xea, 0xf9, 0x40, 0x04, 0xf0, 0xdf, 0x50, - 0xb0, 0x5f, 0x34, 0x15, 0xb9, 0x41, 0xea, 0x3c, 0x1c, 0x52, 0x90, 0x4f, 0x75, 0x93, 0xbf, 0xaf, 0xdc, 0xfd, 0x74, - 0x36, 0xb7, 0xe6, 0xe8, 0x45, 0x8d, 0xeb, 0xd6, 0xea, 0x86, 0x42, 0xa2, 0x35, 0x4d, 0x8a, 0xab, 0x6a, 0x52, 0x0c, - 0x78, 0xee, 0x0b, 0xd5, 0xc5, 0xd6, 0x08, 0x16, 0xfe, 0xdc, 0x02, 0x61, 0x32, 0xee, 0xc5, 0x47, 0x0b, 0x39, 0xa5, - 0x5d, 0x5b, 0xed, 0xb6, 0x95, 0x0d, 0x29, 0x9a, 0x0f, 0x2f, 0x61, 0x97, 0x4e, 0x11, 0x6d, 0xbb, 0x24, 0xf8, 0x02, - 0xb4, 0xac, 0x2e, 0x44, 0x1e, 0xd3, 0xaf, 0x90, 0x5f, 0x8a, 0xe1, 0x5f, 0xa5, 0x7b, 0x73, 0x6a, 0x83, 0x1c, 0xc0, - 0x76, 0xef, 0xe1, 0x76, 0x8c, 0x1e, 0xc8, 0xe0, 0x8d, 0x90, 0x73, 0xce, 0x2f, 0xa7, 0xd6, 0x8c, 0x89, 0x86, 0x05, - 0x2b, 0x87, 0x91, 0x1f, 0x20, 0xe3, 0xe5, 0x14, 0x58, 0xd9, 0x8f, 0x8a, 0xb8, 0xf4, 0x87, 0x91, 0x7f, 0xf1, 0x3c, - 0xc8, 0xb8, 0x17, 0x0d, 0x3b, 0xbe, 0x00, 0x7b, 0xf5, 0xc5, 0x73, 0x16, 0x0d, 0x78, 0x75, 0x55, 0x4f, 0xb3, 0x60, - 0x98, 0xb1, 0xe8, 0xaa, 0x18, 0x82, 0x0f, 0xed, 0x75, 0x39, 0x08, 0x7d, 0xdf, 0xec, 0x1c, 0xba, 0x1b, 0x12, 0x79, - 0x84, 0xfd, 0x08, 0x6e, 0xbb, 0x5a, 0x62, 0x06, 0x93, 0xcd, 0x5d, 0xc4, 0x0c, 0xb6, 0xfc, 0xc5, 0x73, 0xc3, 0x25, - 0x54, 0x5d, 0x4b, 0xcd, 0x46, 0x81, 0xe6, 0xe4, 0x0a, 0xcd, 0xc9, 0x4a, 0xa8, 0x25, 0x9f, 0x54, 0x38, 0x61, 0xe7, - 0x93, 0x5c, 0xd9, 0x8d, 0xc6, 0x18, 0xb8, 0x68, 0xcf, 0x6d, 0x61, 0x64, 0xa6, 0xb3, 0x14, 0x0d, 0x58, 0x78, 0x26, - 0x4e, 0x69, 0x0c, 0x68, 0x5f, 0x0e, 0x2c, 0x6d, 0xc8, 0x8f, 0x72, 0x66, 0xa0, 0x6d, 0x48, 0x69, 0xd4, 0x0c, 0xfc, - 0x99, 0x9a, 0x30, 0xbf, 0x82, 0x95, 0x08, 0xa2, 0xba, 0x00, 0x93, 0x24, 0x27, 0xa3, 0x91, 0xb2, 0x12, 0xc9, 0x39, - 0xe0, 0x7d, 0x04, 0x4f, 0x16, 0xb1, 0xad, 0xfd, 0x29, 0xfd, 0xaf, 0x0e, 0x9f, 0x4b, 0xff, 0x99, 0x00, 0x16, 0x72, - 0x69, 0x10, 0x19, 0x28, 0x1c, 0x52, 0x53, 0x89, 0x38, 0x71, 0x3c, 0x03, 0x5f, 0xc3, 0x05, 0x9a, 0x02, 0xfa, 0x83, - 0x9a, 0x51, 0x44, 0x16, 0xfe, 0xea, 0xd9, 0x4d, 0xdd, 0xe8, 0x79, 0xe6, 0xbc, 0x06, 0xcd, 0x0c, 0x84, 0xf4, 0x38, - 0x55, 0x6f, 0x43, 0xa2, 0xf3, 0xf2, 0x52, 0xbf, 0x4c, 0x88, 0x64, 0x45, 0xe4, 0xe9, 0xfb, 0x1c, 0xcc, 0x23, 0x8a, - 0xd0, 0xc1, 0x95, 0x79, 0x38, 0x9c, 0x0b, 0x0a, 0xdf, 0x51, 0x9e, 0x0f, 0x38, 0xcd, 0xa2, 0x04, 0xb4, 0x81, 0x2c, - 0x37, 0x65, 0xae, 0x93, 0x96, 0xa9, 0x7b, 0x0f, 0x56, 0x82, 0x0a, 0xdd, 0x9c, 0x82, 0x42, 0x19, 0x09, 0x4a, 0x69, - 0x35, 0x08, 0xa5, 0x3a, 0x2c, 0x82, 0xc8, 0x21, 0x0b, 0x01, 0x37, 0x53, 0xd1, 0x68, 0x49, 0xc3, 0x23, 0x9c, 0x1b, - 0x28, 0x04, 0x20, 0xb1, 0xa7, 0x8a, 0x32, 0x2e, 0x87, 0x80, 0x8f, 0x12, 0x0e, 0x71, 0xd6, 0xa4, 0x2d, 0xcf, 0x41, - 0x1c, 0xcb, 0x25, 0x5f, 0x57, 0x08, 0x06, 0x11, 0xfa, 0x0c, 0xf9, 0x93, 0xe5, 0xfc, 0xbb, 0x75, 0x98, 0x76, 0x84, - 0x0f, 0xbb, 0xda, 0x82, 0x8b, 0xd9, 0xed, 0x7c, 0x02, 0xf1, 0x2d, 0xb7, 0xf3, 0x63, 0x0c, 0x91, 0x85, 0x3f, 0xb8, - 0x1b, 0x4a, 0xae, 0x28, 0x74, 0x59, 0x8f, 0x48, 0x91, 0x3d, 0x5d, 0x73, 0x04, 0xc1, 0x81, 0x56, 0x0d, 0x32, 0x34, - 0x12, 0x5f, 0x3c, 0x87, 0xac, 0xc1, 0x9a, 0x7f, 0xae, 0xc8, 0x59, 0xdd, 0x9f, 0x6c, 0xa0, 0x9a, 0x64, 0xb2, 0x56, - 0x54, 0xce, 0x5f, 0xaf, 0xca, 0xf2, 0x64, 0x55, 0x86, 0xab, 0x41, 0x57, 0x55, 0x96, 0x1c, 0xa9, 0x0d, 0xd0, 0x9a, - 0xae, 0x10, 0x43, 0x21, 0x6b, 0xb0, 0xb4, 0xaa, 0xb2, 0xa6, 0x3e, 0x81, 0x40, 0x1f, 0x60, 0x19, 0x35, 0xfb, 0xe9, - 0xf0, 0x5f, 0xc1, 0xbf, 0x54, 0xc8, 0x52, 0x9d, 0xd6, 0x99, 0xf8, 0x35, 0x58, 0x32, 0xfc, 0xe3, 0xb7, 0x60, 0x0d, - 0x58, 0x02, 0x64, 0xb9, 0xdb, 0xd8, 0x68, 0xbd, 0xf2, 0x0a, 0xf1, 0xa5, 0xd6, 0x17, 0xfd, 0xd6, 0x6d, 0xa2, 0x56, - 0x80, 0x11, 0x0a, 0x2d, 0x02, 0x6c, 0xf5, 0xc0, 0x3d, 0x05, 0x3f, 0x10, 0xc3, 0xb9, 0x26, 0xad, 0xa9, 0x13, 0x5e, - 0x67, 0xe3, 0x48, 0x44, 0xf5, 0x16, 0x2e, 0xee, 0xf5, 0xd6, 0xe2, 0x6f, 0x54, 0x20, 0x00, 0xb2, 0x98, 0x62, 0xed, - 0xbc, 0x21, 0xbd, 0x32, 0xec, 0x24, 0xf4, 0xde, 0xb0, 0x13, 0xc8, 0x8b, 0xc3, 0x4e, 0xa1, 0x4b, 0xb4, 0x9d, 0x22, - 0x35, 0xd1, 0x76, 0xd2, 0x62, 0x15, 0x96, 0x10, 0xfc, 0xaa, 0xbd, 0x75, 0x94, 0xed, 0x8b, 0x2c, 0x61, 0xda, 0x02, - 0x46, 0xb9, 0x55, 0x9f, 0x39, 0x45, 0xac, 0x94, 0xbd, 0xd3, 0x49, 0x95, 0xbb, 0xc8, 0xa7, 0x56, 0x53, 0x64, 0xf2, - 0xf7, 0xc7, 0x2d, 0x92, 0x4f, 0x7e, 0x6e, 0x37, 0x4c, 0xa6, 0x7f, 0x3c, 0xfa, 0x02, 0xba, 0x22, 0x3b, 0x7d, 0x02, - 0x01, 0x99, 0x0a, 0xaa, 0xd5, 0xad, 0x62, 0x9a, 0xb7, 0xab, 0xec, 0xf6, 0x42, 0x89, 0xe1, 0x74, 0x76, 0x12, 0x1e, - 0x6d, 0x86, 0x0c, 0x1c, 0x82, 0x40, 0x21, 0x54, 0x14, 0xc3, 0x23, 0x50, 0x6b, 0x24, 0x1f, 0xe0, 0x47, 0xbb, 0x53, - 0x41, 0xa4, 0x76, 0x53, 0x71, 0xe3, 0xe4, 0xa6, 0xeb, 0xa5, 0x40, 0xad, 0x53, 0xb2, 0x02, 0x28, 0x21, 0xea, 0x4f, - 0x62, 0x5b, 0xbf, 0x84, 0x2b, 0x36, 0xdf, 0x37, 0x8a, 0x9e, 0x5c, 0x9f, 0xa2, 0x6e, 0xc5, 0xd5, 0x69, 0xda, 0x6a, - 0x8e, 0x1d, 0x67, 0xc8, 0xc1, 0xb3, 0x82, 0x60, 0x3b, 0x2a, 0x51, 0xbe, 0x6d, 0x37, 0x1d, 0x13, 0x5b, 0xfd, 0xb3, - 0xa8, 0x36, 0x77, 0x50, 0x11, 0x11, 0x1f, 0x65, 0x37, 0x4f, 0xda, 0xef, 0x60, 0x8f, 0xb5, 0x1a, 0x44, 0xf6, 0x19, - 0x5c, 0xe5, 0x3a, 0x2d, 0x72, 0x5b, 0x06, 0xe7, 0x1f, 0x5e, 0xed, 0x2a, 0x6c, 0x72, 0xac, 0xab, 0xab, 0x99, 0xea, - 0xa4, 0x62, 0x03, 0x63, 0x4d, 0x6b, 0xa9, 0xe6, 0x31, 0x24, 0xdd, 0x95, 0xc5, 0x59, 0x95, 0x74, 0xd3, 0x73, 0xe3, - 0x4c, 0x21, 0x06, 0xce, 0x56, 0xa3, 0xe5, 0x0c, 0x43, 0x74, 0x7d, 0x98, 0x25, 0x7e, 0xab, 0xa7, 0xdc, 0xe7, 0xe1, - 0xd6, 0xef, 0xea, 0x05, 0x27, 0x93, 0xfd, 0xe4, 0x38, 0x77, 0xbb, 0x48, 0xfb, 0x89, 0x6f, 0xc3, 0xfc, 0xeb, 0x1b, - 0xc4, 0x9d, 0xa8, 0xff, 0x59, 0x01, 0xd0, 0xe0, 0x26, 0x8f, 0x25, 0x4a, 0xfd, 0x5e, 0x55, 0x3f, 0xa8, 0x99, 0xaa, - 0x69, 0x20, 0x98, 0x53, 0x29, 0xe0, 0x0f, 0xb7, 0x0b, 0x57, 0x3c, 0xe2, 0x86, 0x85, 0xf1, 0x4f, 0xaf, 0x66, 0xa7, - 0x82, 0xca, 0xc0, 0xcd, 0xf8, 0x4f, 0x4f, 0xb0, 0x53, 0x58, 0x2b, 0x20, 0x2b, 0xfc, 0xe9, 0xe5, 0x8f, 0xbc, 0x5f, - 0xf1, 0x3f, 0xbd, 0xea, 0x91, 0xf7, 0x11, 0xe7, 0xe5, 0x4f, 0x24, 0x75, 0x42, 0x54, 0x97, 0x3f, 0x09, 0x53, 0x6c, - 0x95, 0xe6, 0xaf, 0x48, 0xe1, 0x13, 0x7c, 0x06, 0xbe, 0xc3, 0x55, 0xb8, 0x35, 0xbf, 0xc1, 0x63, 0xc7, 0x62, 0xdb, - 0xa5, 0xbe, 0x80, 0x72, 0x04, 0x16, 0x91, 0xdb, 0x6f, 0x57, 0xf6, 0xab, 0x85, 0x51, 0xc6, 0xd8, 0x7d, 0xc9, 0x4a, - 0x94, 0xce, 0xfa, 0xfd, 0x42, 0x0a, 0x46, 0x76, 0x61, 0x8d, 0xf6, 0x28, 0x55, 0xaf, 0xbe, 0x0d, 0xeb, 0x28, 0x49, - 0xf3, 0x3b, 0x19, 0x7d, 0x24, 0xc3, 0x8e, 0xf4, 0x95, 0x94, 0x68, 0xaf, 0x55, 0x58, 0x8e, 0x66, 0xbf, 0x2e, 0x39, - 0x50, 0x5e, 0xb7, 0x82, 0xf2, 0x55, 0x13, 0x40, 0xaf, 0x54, 0xfb, 0x0c, 0xb4, 0x82, 0xc2, 0x52, 0x79, 0xb0, 0x12, - 0xe7, 0xa2, 0xcf, 0x8a, 0xc3, 0x41, 0x5d, 0x0c, 0x09, 0x05, 0xaa, 0xc4, 0x49, 0x68, 0xc4, 0x73, 0xb8, 0x10, 0x8a, - 0xeb, 0x1c, 0x63, 0x2b, 0x72, 0xe0, 0x40, 0x86, 0x1f, 0x10, 0x78, 0x2f, 0xfb, 0x57, 0x30, 0x18, 0x26, 0xb8, 0x91, - 0x51, 0x27, 0xe7, 0xec, 0x4f, 0x0c, 0xcc, 0xa0, 0x9e, 0xd4, 0xee, 0xb3, 0x7b, 0x15, 0xd8, 0x0b, 0x67, 0x40, 0x7b, - 0x37, 0x46, 0x3f, 0xab, 0x62, 0xed, 0xa4, 0x7f, 0x2a, 0xd6, 0x90, 0x4c, 0x87, 0xc5, 0xd1, 0x36, 0x0d, 0x8f, 0xe4, - 0xc9, 0x71, 0xbc, 0xe9, 0x1f, 0x0e, 0x63, 0xfc, 0x38, 0xca, 0xaf, 0x2d, 0xe0, 0x55, 0xdc, 0x42, 0x1a, 0x8b, 0x14, - 0xbd, 0x03, 0x31, 0x87, 0xa2, 0x97, 0xec, 0xb7, 0x8c, 0x97, 0x13, 0x41, 0x29, 0x49, 0x6c, 0x78, 0x47, 0x7a, 0x9a, - 0xd6, 0xa3, 0xad, 0x0c, 0xd8, 0xaf, 0x47, 0x3b, 0xfa, 0x0b, 0x14, 0x8f, 0x16, 0xfe, 0x92, 0xfe, 0x2e, 0xee, 0xe6, - 0x9e, 0xf3, 0x4d, 0xe3, 0x3b, 0xe2, 0x02, 0xc5, 0x9a, 0xdd, 0x5f, 0xd3, 0xd2, 0x59, 0x07, 0x82, 0x03, 0xde, 0x62, - 0x17, 0xed, 0xfb, 0x8d, 0xeb, 0xf4, 0xb4, 0xff, 0xd6, 0xad, 0x51, 0xbe, 0xf7, 0x4f, 0x89, 0x72, 0xb0, 0x7f, 0xe5, - 0xa2, 0xf9, 0xdb, 0x4f, 0x19, 0x92, 0x0a, 0xcd, 0x0d, 0xb6, 0x93, 0x2d, 0xc2, 0xda, 0x18, 0x07, 0x15, 0xbb, 0x2b, - 0xc3, 0x08, 0x18, 0xd4, 0xb1, 0xff, 0xd1, 0x67, 0xd3, 0x86, 0xec, 0x03, 0x40, 0xe5, 0x2a, 0x04, 0xec, 0x01, 0x38, - 0xd1, 0x08, 0x37, 0xc0, 0xad, 0x46, 0x4b, 0x3a, 0xa8, 0xdb, 0x82, 0x81, 0x68, 0x09, 0x1b, 0x79, 0xdb, 0xd5, 0xe9, - 0x2b, 0xc2, 0x87, 0xda, 0x49, 0xe9, 0x50, 0xfe, 0xea, 0x39, 0xfb, 0x9f, 0x1d, 0xd6, 0xd4, 0x94, 0x1b, 0xc0, 0xcc, - 0x59, 0x89, 0xbc, 0x42, 0xe8, 0x14, 0xf9, 0xbd, 0xaa, 0x2b, 0x31, 0x5c, 0xd6, 0xa2, 0xec, 0xcc, 0x6e, 0x9d, 0xe8, - 0x9d, 0x53, 0x50, 0x4b, 0x65, 0x83, 0x9c, 0xa4, 0xda, 0x7c, 0x64, 0xad, 0xa0, 0x44, 0x5d, 0xa3, 0xc0, 0xf1, 0x29, - 0xd7, 0xee, 0xff, 0x9d, 0x33, 0x41, 0xcd, 0x36, 0xaa, 0xfb, 0x2b, 0xfd, 0x54, 0xd5, 0x24, 0x16, 0xe0, 0x72, 0x92, - 0xe6, 0x1d, 0x8f, 0xb0, 0xfa, 0xc7, 0xc9, 0x52, 0x04, 0x7a, 0x15, 0xd1, 0xae, 0x04, 0x24, 0x68, 0x27, 0x67, 0xa1, - 0x22, 0x50, 0xa0, 0xaf, 0x7f, 0xbf, 0x49, 0xb3, 0x58, 0xae, 0x66, 0x7b, 0x98, 0x28, 0x8b, 0xf5, 0x10, 0x41, 0xce, - 0x4c, 0x1d, 0xec, 0xf7, 0x34, 0xa3, 0x59, 0x78, 0x65, 0x4a, 0x70, 0x29, 0xae, 0xa2, 0x22, 0x07, 0x9f, 0x43, 0x7c, - 0xe1, 0x53, 0x21, 0x37, 0x88, 0x68, 0xfa, 0xbd, 0x44, 0xb5, 0x23, 0x05, 0x72, 0x28, 0xf9, 0x09, 0xf1, 0x97, 0xac, - 0x8d, 0x71, 0xbf, 0x74, 0xaa, 0xfd, 0x52, 0x21, 0xb8, 0xff, 0x6c, 0x8b, 0x8d, 0x2a, 0x4f, 0xf4, 0xe8, 0x53, 0xac, - 0xff, 0xc9, 0x02, 0x4a, 0x75, 0xdf, 0x06, 0xa7, 0xe2, 0x51, 0xb8, 0xa9, 0x8b, 0x1b, 0x84, 0x16, 0x28, 0x47, 0x55, - 0xb1, 0x29, 0x23, 0xe2, 0x84, 0xdd, 0xd4, 0x45, 0x4f, 0x73, 0xa0, 0x53, 0x87, 0xa5, 0x89, 0x3c, 0x11, 0xda, 0x2d, - 0xe8, 0x9e, 0xe6, 0x58, 0x89, 0x17, 0xb2, 0x74, 0x90, 0x75, 0x22, 0x4d, 0xa8, 0xdc, 0xd5, 0x55, 0x47, 0xa5, 0x52, - 0x37, 0xbc, 0x4e, 0x35, 0xe3, 0xef, 0xd2, 0xfc, 0x89, 0x65, 0xbf, 0x6e, 0xfd, 0x56, 0xab, 0xbd, 0xb1, 0x7a, 0x54, - 0xb2, 0xe6, 0x38, 0x9b, 0x90, 0x94, 0x3e, 0x61, 0xbb, 0x99, 0x74, 0xad, 0x03, 0x4f, 0x82, 0xcb, 0xa1, 0x27, 0xa0, - 0x62, 0xd0, 0xc4, 0xdb, 0x5d, 0xa0, 0x1e, 0x81, 0x67, 0xa0, 0x7c, 0xa2, 0xd6, 0x01, 0x3f, 0xaf, 0xb5, 0x3c, 0x65, - 0x84, 0x61, 0xb5, 0xb3, 0x68, 0x39, 0x38, 0xef, 0x14, 0x81, 0x6b, 0x57, 0x02, 0xcf, 0x87, 0xea, 0xbd, 0x10, 0x30, - 0xdc, 0x3f, 0x15, 0x2a, 0x9b, 0xdd, 0x0c, 0xe7, 0x51, 0xe3, 0xf4, 0x40, 0x7b, 0xdb, 0xb5, 0x1e, 0xea, 0x5d, 0xb7, - 0x73, 0x5b, 0xe9, 0xde, 0xaf, 0x9d, 0x4c, 0xba, 0x80, 0xd6, 0xe6, 0xb3, 0xef, 0xec, 0x4a, 0xeb, 0xa6, 0xe7, 0xec, - 0xc1, 0xd6, 0x2d, 0xd1, 0xb9, 0x20, 0x9a, 0xfc, 0x7e, 0xe0, 0x59, 0xdb, 0x8e, 0x7e, 0x9b, 0x76, 0x6c, 0x73, 0x0f, - 0x75, 0xaf, 0xa0, 0xd6, 0x1b, 0x9a, 0xf7, 0xcf, 0x5c, 0xdb, 0x8e, 0xaf, 0x7e, 0x5d, 0x77, 0xb8, 0xce, 0x9b, 0xe0, - 0xb8, 0xe9, 0xda, 0x56, 0x3b, 0xfb, 0xb9, 0xbb, 0xb7, 0x16, 0x51, 0x98, 0x65, 0x3f, 0x16, 0xc5, 0x1f, 0x95, 0xbe, - 0x23, 0xd0, 0xd1, 0x9d, 0x17, 0x75, 0xba, 0xdc, 0x7d, 0x20, 0x8c, 0x27, 0xaf, 0x3e, 0x22, 0xba, 0xf5, 0x7d, 0xe6, - 0x7e, 0x05, 0xb8, 0x11, 0xdc, 0x41, 0xb4, 0x77, 0x4b, 0x7d, 0x52, 0xab, 0xaf, 0xf5, 0xda, 0x79, 0x7a, 0x7e, 0xd3, - 0xb9, 0xfd, 0xee, 0x9b, 0xa3, 0xad, 0xf7, 0xb8, 0xb0, 0x56, 0x96, 0x9e, 0xaa, 0x82, 0xbd, 0x59, 0x9e, 0xaa, 0x82, - 0xc9, 0x03, 0xaf, 0xd9, 0x2f, 0x68, 0x70, 0xa5, 0xa3, 0x8d, 0xf7, 0x44, 0x0d, 0xdc, 0xa2, 0xb0, 0x74, 0xf8, 0x25, - 0x37, 0x93, 0x97, 0xb8, 0xbf, 0x54, 0xe4, 0x62, 0xdf, 0x39, 0xa3, 0x3b, 0x33, 0xeb, 0x5e, 0x55, 0xb8, 0x5a, 0x90, - 0xab, 0x03, 0x5b, 0xcb, 0x2e, 0x0e, 0x37, 0x2c, 0xa2, 0x00, 0x81, 0x98, 0x5e, 0xa9, 0xb5, 0x3f, 0xa2, 0x41, 0xc8, - 0x07, 0x03, 0xbf, 0xc0, 0x60, 0x55, 0xa0, 0xf0, 0x81, 0x22, 0xf9, 0x2b, 0x4f, 0xc0, 0x2e, 0x9e, 0x01, 0xba, 0x15, - 0x9b, 0x15, 0x23, 0x44, 0xc8, 0x64, 0x39, 0xab, 0xe9, 0x0c, 0xf2, 0xa9, 0x2f, 0xbe, 0xb1, 0x55, 0xa7, 0xf3, 0xb6, - 0xa6, 0xca, 0xa9, 0x43, 0xa1, 0xbb, 0x9b, 0xba, 0x73, 0xeb, 0x22, 0x4f, 0x1d, 0x42, 0xae, 0x54, 0xac, 0xc4, 0x34, - 0xd4, 0x3c, 0x49, 0x33, 0xea, 0x2f, 0xf6, 0x7e, 0xaf, 0x51, 0x38, 0xe5, 0x4f, 0xc7, 0xa0, 0x0a, 0x57, 0x35, 0xc4, - 0xb1, 0x54, 0xc5, 0x23, 0x1b, 0x04, 0x9a, 0x57, 0xb7, 0x2a, 0x69, 0x42, 0x26, 0x37, 0xc2, 0xa7, 0x26, 0xa5, 0x3c, - 0x4d, 0x9b, 0xb4, 0x52, 0xa4, 0x0e, 0x3e, 0xa8, 0x53, 0x8d, 0xe7, 0x66, 0x75, 0x0d, 0x60, 0xc6, 0xf9, 0x15, 0xbf, - 0x54, 0x5c, 0x46, 0x6d, 0x65, 0x26, 0xed, 0x4f, 0x8e, 0xc6, 0x46, 0x5d, 0x4e, 0x1b, 0x65, 0x84, 0x95, 0xd2, 0x9c, - 0x14, 0xcb, 0xf1, 0xfc, 0x03, 0x06, 0x6b, 0x9e, 0xc0, 0x0e, 0x26, 0x2a, 0xe5, 0x7d, 0x04, 0xc4, 0xd7, 0x49, 0x7a, - 0x97, 0x40, 0x8a, 0xf4, 0x2f, 0x5d, 0x72, 0x97, 0xb1, 0x81, 0x18, 0xb3, 0x62, 0x66, 0xf4, 0x3f, 0xb8, 0x4b, 0xfa, - 0x93, 0x10, 0x00, 0x37, 0xd1, 0x14, 0x3a, 0x75, 0x9e, 0x5c, 0xe4, 0xc1, 0xf2, 0xc2, 0x43, 0x2b, 0x46, 0x3c, 0xf8, - 0xeb, 0x75, 0x88, 0x20, 0xe6, 0x98, 0xe2, 0xe9, 0x17, 0x46, 0x7f, 0x09, 0x2e, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, - 0x21, 0xdc, 0xec, 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, 0x6a, 0xf8, 0x63, 0xe5, 0x41, 0xff, 0xd7, 0x99, 0xb0, 0xd4, - 0x7e, 0x7a, 0x3a, 0x80, 0x0a, 0xde, 0x57, 0xbc, 0x8d, 0x88, 0xef, 0x13, 0x3f, 0x8b, 0x07, 0x9b, 0x67, 0x1b, 0xb0, - 0xd6, 0x3d, 0xc9, 0x8d, 0x75, 0x95, 0xb0, 0x81, 0x80, 0xaf, 0x51, 0xd4, 0x9e, 0xd7, 0x6e, 0xf7, 0xe0, 0xaf, 0xfe, - 0x45, 0xc8, 0x80, 0x89, 0xd3, 0xf7, 0x99, 0x93, 0x35, 0xba, 0xc8, 0x64, 0xfa, 0xd0, 0x49, 0xdf, 0xe8, 0x74, 0xdf, - 0x09, 0xff, 0xa8, 0x98, 0xc5, 0x87, 0x5b, 0xfa, 0x4a, 0x93, 0xe2, 0x0e, 0x58, 0xd9, 0x3c, 0x2a, 0x08, 0x75, 0x2e, - 0xa2, 0xaf, 0x4c, 0xf9, 0x96, 0x50, 0xb3, 0x6f, 0x2c, 0x29, 0xa5, 0x7b, 0x0d, 0xbd, 0x4e, 0x6b, 0xfd, 0x36, 0x4a, - 0x30, 0x26, 0x3a, 0x9e, 0xbc, 0x8c, 0xc7, 0xca, 0xfb, 0x78, 0xdc, 0x48, 0x85, 0x3c, 0x00, 0x11, 0xa8, 0x18, 0x7f, - 0xba, 0xf2, 0xe4, 0xa4, 0x17, 0xc6, 0xab, 0x50, 0x0a, 0x0a, 0x03, 0xba, 0x02, 0x29, 0xe0, 0x51, 0x7b, 0xa2, 0xb3, - 0xb0, 0x4b, 0xb8, 0x47, 0x37, 0x01, 0x63, 0x7d, 0xfe, 0x11, 0xd0, 0xdc, 0x85, 0x3b, 0xbc, 0x18, 0xa0, 0x36, 0xf5, - 0xea, 0xee, 0xe3, 0x5a, 0x9d, 0xc3, 0x21, 0x38, 0x58, 0x0d, 0x22, 0x38, 0x9d, 0x4f, 0x1d, 0xcd, 0xb2, 0x00, 0x95, - 0x93, 0xe5, 0x46, 0xde, 0x3c, 0x5a, 0xf4, 0xea, 0xbe, 0xb7, 0x4c, 0xcb, 0xaa, 0x0e, 0x32, 0x96, 0x85, 0x15, 0xe0, - 0xea, 0xd0, 0xfa, 0x41, 0xb8, 0x2c, 0x9c, 0x3f, 0x10, 0x82, 0xd8, 0xbd, 0xda, 0x96, 0x3c, 0x57, 0x73, 0xf8, 0xd9, - 0x73, 0xb6, 0xe6, 0x12, 0x75, 0xd2, 0x99, 0x08, 0x40, 0xec, 0xa9, 0x59, 0x45, 0xd7, 0x40, 0x52, 0xa7, 0x59, 0x45, - 0xd7, 0xd4, 0x6c, 0x63, 0x1c, 0xc8, 0x47, 0xab, 0x14, 0xb0, 0xef, 0xa6, 0xe3, 0x60, 0xf5, 0x2c, 0x96, 0xd7, 0xa1, - 0xbb, 0x67, 0x1b, 0xe5, 0x33, 0xa8, 0x5b, 0x6d, 0x8c, 0x89, 0xed, 0xe6, 0xcb, 0xb9, 0x7e, 0x3b, 0x58, 0xfa, 0x76, - 0xd0, 0x9c, 0x53, 0xf6, 0x9d, 0x2e, 0x7b, 0x65, 0x97, 0x4d, 0x3d, 0x77, 0x54, 0xb4, 0x1a, 0x03, 0x7a, 0x03, 0x0b, - 0xd6, 0xe7, 0x22, 0xcd, 0x56, 0xa5, 0x2a, 0x01, 0x2f, 0x8c, 0x15, 0xbb, 0xf3, 0x1b, 0x99, 0x21, 0x09, 0xf3, 0x38, - 0x13, 0x6f, 0xe9, 0x5e, 0x0b, 0x93, 0xe3, 0x58, 0x24, 0x53, 0x42, 0xa7, 0x74, 0x67, 0x1b, 0x3a, 0x57, 0x61, 0x14, - 0xd1, 0x5a, 0x49, 0xa5, 0x91, 0xc0, 0xd4, 0x0c, 0x50, 0x32, 0x57, 0xe0, 0x94, 0x2e, 0xf7, 0xbf, 0x23, 0x31, 0xce, - 0x7c, 0x51, 0x32, 0x03, 0xba, 0xe5, 0xd7, 0xc5, 0xba, 0x95, 0x22, 0x23, 0xcc, 0x9b, 0xe3, 0xf6, 0xba, 0x3e, 0x04, - 0x72, 0xb5, 0xec, 0x51, 0x34, 0x0e, 0x0a, 0x1d, 0x2e, 0x55, 0x02, 0xec, 0x8b, 0xc4, 0xcf, 0x08, 0x5b, 0xda, 0x03, - 0xb9, 0x3d, 0x3a, 0x13, 0xe6, 0x9c, 0x93, 0xb2, 0xec, 0x5c, 0x9a, 0xc1, 0xe5, 0xc4, 0x95, 0xe0, 0x22, 0xbd, 0x6d, - 0x4f, 0x93, 0x96, 0xb6, 0x8f, 0x0d, 0xe7, 0x68, 0x68, 0x1b, 0x74, 0xc7, 0xfe, 0xd0, 0x5c, 0x2c, 0x62, 0xeb, 0x62, - 0x31, 0xec, 0xcc, 0x7e, 0xb4, 0x58, 0x80, 0x1c, 0x00, 0x8e, 0xba, 0x0d, 0x1f, 0xb3, 0x25, 0x70, 0x5a, 0x4d, 0xb3, - 0xa9, 0xb7, 0xe1, 0xd5, 0x33, 0xd5, 0xd3, 0x4b, 0x9e, 0x3f, 0x13, 0x66, 0x2c, 0x36, 0x3c, 0x7f, 0x66, 0x1d, 0x39, - 0xd5, 0x33, 0xa1, 0x44, 0xeb, 0x02, 0x9a, 0x81, 0xd7, 0x14, 0x30, 0x62, 0xc9, 0x64, 0x4a, 0x15, 0x79, 0xdc, 0x9b, - 0x6e, 0xd4, 0xe0, 0x05, 0x85, 0x43, 0x20, 0xa5, 0xd3, 0x2f, 0x9e, 0x33, 0xfd, 0xde, 0xc5, 0xf3, 0x0e, 0x59, 0xdb, - 0x30, 0x5d, 0x6e, 0x86, 0xc9, 0xa0, 0xf4, 0x9f, 0x99, 0x89, 0x71, 0x61, 0x4d, 0x12, 0x40, 0xfc, 0x1b, 0xfb, 0x1d, - 0x52, 0xb8, 0x79, 0x7f, 0x39, 0x8c, 0x1f, 0x79, 0x3f, 0x46, 0xf6, 0x24, 0xcd, 0x10, 0x6b, 0x26, 0x15, 0x72, 0xf7, - 0xd5, 0xfa, 0xc7, 0xc4, 0x6e, 0xb2, 0x07, 0x16, 0x80, 0xd8, 0x9a, 0xb6, 0xba, 0xe5, 0xfd, 0xbe, 0x67, 0x8a, 0x00, - 0x3f, 0x28, 0xff, 0xe8, 0xce, 0x90, 0x0c, 0xca, 0xae, 0x1b, 0x42, 0x3c, 0x28, 0x9b, 0xa6, 0xbd, 0xde, 0xf6, 0xce, - 0x3c, 0x56, 0xd7, 0x69, 0x67, 0x71, 0xb5, 0xc8, 0x20, 0xad, 0x3e, 0x64, 0xc7, 0x99, 0x7d, 0x76, 0xb4, 0x54, 0xba, - 0xdf, 0x87, 0x88, 0xb8, 0xa3, 0xac, 0xed, 0xb7, 0x5b, 0x70, 0x0d, 0x47, 0x83, 0xd0, 0x95, 0xbd, 0x5d, 0x46, 0x1b, - 0x17, 0xe2, 0xb8, 0x67, 0x3a, 0x5f, 0xf0, 0xe5, 0x51, 0xda, 0x79, 0x70, 0xaa, 0x27, 0xfa, 0xdc, 0x74, 0x57, 0x99, - 0x5c, 0xeb, 0xb0, 0x1a, 0x83, 0xda, 0x2c, 0x6c, 0xe1, 0x2e, 0x6c, 0xa3, 0x83, 0xd6, 0xbe, 0x2c, 0xf8, 0xa7, 0x0c, - 0xc0, 0x97, 0x9e, 0x2d, 0xdb, 0x5e, 0x93, 0x56, 0xaf, 0x65, 0x14, 0x62, 0x4b, 0xdb, 0xab, 0x4f, 0x47, 0xf9, 0xb8, - 0x39, 0xa1, 0xb8, 0x90, 0xa3, 0xfc, 0xe8, 0x35, 0x44, 0x5d, 0xeb, 0x3a, 0x2e, 0x16, 0x1d, 0x6e, 0x5c, 0x75, 0xdb, - 0x8d, 0xeb, 0x07, 0xc4, 0x5b, 0xa3, 0x4d, 0x0a, 0xb5, 0x32, 0x76, 0x04, 0x2f, 0xcb, 0x87, 0x43, 0x26, 0x86, 0x43, - 0x09, 0x99, 0xfa, 0xd8, 0xbd, 0xa1, 0x69, 0x9f, 0x9f, 0xb6, 0x7e, 0xc4, 0x52, 0xe3, 0x28, 0x36, 0xbc, 0xd3, 0x77, - 0x1e, 0x5b, 0xe3, 0x4a, 0xbe, 0x0c, 0x66, 0xbb, 0x82, 0x6a, 0x6b, 0xbc, 0x61, 0x2f, 0xe7, 0xdf, 0x57, 0x52, 0xc9, - 0xdf, 0xfe, 0x0c, 0xd7, 0xf0, 0xd6, 0x96, 0x0e, 0x9a, 0x6a, 0x96, 0xb3, 0x5c, 0xdf, 0x0b, 0x8e, 0x3f, 0xee, 0x5e, - 0x11, 0x0c, 0x7e, 0x4f, 0x47, 0x41, 0x2e, 0x96, 0x6a, 0x0d, 0x28, 0x48, 0x47, 0x76, 0x4c, 0x65, 0x81, 0x61, 0x00, - 0x6f, 0xc8, 0x00, 0x79, 0x4c, 0xe1, 0x6e, 0xa8, 0xf0, 0xc2, 0x5f, 0x2a, 0xb2, 0x4b, 0x60, 0x5b, 0x33, 0x3e, 0x66, - 0xb8, 0x83, 0x90, 0x7f, 0x04, 0xbb, 0x63, 0x2b, 0x76, 0xcb, 0x16, 0x0c, 0xc9, 0xc6, 0x71, 0x18, 0x63, 0x3e, 0x9e, - 0xc4, 0x57, 0x62, 0x12, 0x0f, 0x78, 0x84, 0x8e, 0x11, 0x6b, 0x5e, 0xcf, 0x62, 0x39, 0x80, 0xec, 0x8e, 0x2b, 0x1d, - 0x10, 0x42, 0x63, 0x43, 0x4b, 0x5e, 0x17, 0x06, 0x17, 0x3b, 0xf6, 0x19, 0x89, 0x64, 0x1c, 0x82, 0x45, 0xab, 0x1a, - 0x58, 0x98, 0xd8, 0x2d, 0x2f, 0x66, 0xab, 0x39, 0xfe, 0x73, 0x38, 0x20, 0x00, 0x76, 0xb0, 0x6f, 0xd8, 0x5d, 0x84, - 0x48, 0x6f, 0x0b, 0x7e, 0x67, 0x79, 0xba, 0xb0, 0x7b, 0xfe, 0x96, 0x8f, 0xd9, 0xf9, 0x0f, 0x1e, 0x44, 0xce, 0x9e, - 0x7f, 0x04, 0x34, 0xc4, 0x7b, 0x7e, 0x9b, 0x7a, 0x15, 0xbb, 0x25, 0x0a, 0xc2, 0x5b, 0x70, 0x06, 0xba, 0x87, 0x08, - 0xd8, 0xb7, 0x7c, 0x81, 0xb1, 0x62, 0x67, 0xe9, 0xd2, 0xc3, 0x8c, 0x50, 0x7b, 0x3a, 0x5f, 0xd6, 0x6a, 0x12, 0x6e, - 0xae, 0x96, 0x93, 0xc1, 0x60, 0xe3, 0xef, 0xf8, 0x1a, 0xf8, 0x60, 0xce, 0x7f, 0xf0, 0x76, 0x54, 0x2e, 0xfc, 0xe7, - 0x75, 0x96, 0xbc, 0xf3, 0xd9, 0xdb, 0x01, 0x5f, 0x00, 0xde, 0x12, 0x3a, 0x70, 0xdd, 0xfb, 0x4c, 0xe2, 0xb5, 0xbd, - 0xd5, 0xd7, 0x08, 0x24, 0xf2, 0x05, 0x60, 0xc4, 0xc4, 0xfc, 0x7e, 0x0b, 0x11, 0x18, 0x09, 0xf8, 0xb6, 0x6a, 0x8f, - 0xf8, 0x2d, 0x37, 0x80, 0x5f, 0x99, 0xcf, 0x1e, 0x78, 0xa8, 0x7f, 0x26, 0x3e, 0xbb, 0xe1, 0xef, 0xf9, 0xb5, 0x27, - 0x25, 0xe9, 0x72, 0xf6, 0x7e, 0x0e, 0xd7, 0x43, 0x29, 0x4f, 0x87, 0xf4, 0xb3, 0x31, 0x18, 0x40, 0x28, 0x64, 0xde, - 0x78, 0xc0, 0x9a, 0x14, 0xe2, 0x5f, 0xc0, 0xb7, 0xa3, 0x84, 0xcd, 0x1b, 0x6f, 0xeb, 0x6b, 0x79, 0xf3, 0xc6, 0x7b, - 0xf0, 0x29, 0x0a, 0xb0, 0x0a, 0x4a, 0x59, 0x60, 0x15, 0x84, 0x8d, 0x36, 0xc2, 0x18, 0xb8, 0x7a, 0xd7, 0x18, 0xea, - 0x7a, 0x8e, 0xd8, 0xb6, 0xd2, 0x77, 0xe1, 0x3b, 0xc8, 0x80, 0x0f, 0x5e, 0x17, 0x25, 0xd1, 0xe7, 0xd4, 0x14, 0x49, - 0xeb, 0x9e, 0xfb, 0xad, 0x75, 0x47, 0x6b, 0x4a, 0x7d, 0xe4, 0x6a, 0x7c, 0x38, 0xd4, 0xd7, 0x42, 0x8b, 0x04, 0x53, - 0xd0, 0xb8, 0x06, 0x6d, 0x01, 0x82, 0x3e, 0x0f, 0x90, 0xb5, 0xa4, 0x58, 0xf0, 0xed, 0xaf, 0x10, 0x83, 0x57, 0xa6, - 0x77, 0x2e, 0x57, 0x19, 0x09, 0xdb, 0x0b, 0xbf, 0x1c, 0xd6, 0xfe, 0xc4, 0xa9, 0x85, 0xa5, 0xd5, 0x1c, 0xd4, 0xcf, - 0x6c, 0x39, 0x4e, 0x55, 0xed, 0xdf, 0x92, 0xa4, 0xda, 0x55, 0x5a, 0x4e, 0xef, 0xed, 0x9b, 0x2e, 0x13, 0x6c, 0xec, - 0x07, 0x54, 0x1d, 0x59, 0x0d, 0xbb, 0x2f, 0xd4, 0x17, 0x3d, 0x25, 0x13, 0x9a, 0x8f, 0x2a, 0x9a, 0x67, 0xf7, 0x9b, - 0x1d, 0xf5, 0x9f, 0x5e, 0x0e, 0x45, 0x80, 0x64, 0x95, 0x16, 0x4b, 0x91, 0xb3, 0xb1, 0x1f, 0x0f, 0x93, 0x4c, 0x85, - 0x17, 0xa4, 0xa3, 0xbb, 0xdf, 0xb8, 0xbf, 0xe5, 0x06, 0xb2, 0x42, 0xab, 0x36, 0x18, 0x2b, 0x45, 0xcb, 0x60, 0x7d, - 0x35, 0xee, 0xf7, 0xc5, 0xd5, 0x78, 0x2a, 0x82, 0x1a, 0x88, 0x8b, 0xc4, 0xf5, 0x78, 0x5a, 0x13, 0x4b, 0x6a, 0x57, - 0x60, 0x8c, 0x1e, 0x57, 0x45, 0xed, 0x53, 0x5f, 0x43, 0x28, 0x52, 0xad, 0x99, 0x63, 0x8d, 0x1b, 0x23, 0xe2, 0x0e, - 0x2b, 0xd7, 0x4e, 0xed, 0x75, 0x00, 0x96, 0x57, 0xe3, 0x82, 0xb0, 0x49, 0x8e, 0x9d, 0x0b, 0x58, 0x8d, 0x86, 0x54, - 0xbb, 0xe1, 0xd6, 0xcb, 0xce, 0x6f, 0x1e, 0x27, 0xb6, 0x36, 0xc2, 0x2d, 0x05, 0x94, 0x51, 0x7e, 0x63, 0x39, 0x61, - 0x77, 0xaa, 0x77, 0xa4, 0x6a, 0x47, 0x9c, 0xb8, 0x80, 0xe5, 0x86, 0xa7, 0x56, 0xdf, 0xc4, 0xe0, 0x44, 0xa8, 0x5a, - 0xe9, 0x78, 0xed, 0x47, 0xdc, 0xaf, 0xee, 0xeb, 0x5e, 0x09, 0x7e, 0x12, 0xf2, 0xfa, 0x2d, 0xef, 0x00, 0xb0, 0xe2, - 0x43, 0x5e, 0x4c, 0x0b, 0x47, 0xeb, 0x32, 0x28, 0x03, 0x44, 0x68, 0x06, 0x40, 0x27, 0x57, 0x07, 0x51, 0x1a, 0xb8, - 0xe2, 0x0e, 0x11, 0x7e, 0x1a, 0x3d, 0xcb, 0xaf, 0xc3, 0x67, 0xd5, 0x34, 0xbc, 0xc8, 0x83, 0xe8, 0xa2, 0x0a, 0xa2, - 0x67, 0xd5, 0x55, 0xf8, 0x2c, 0x9f, 0x46, 0x17, 0x79, 0x10, 0x5e, 0x54, 0x8d, 0x7d, 0xd7, 0xee, 0xee, 0x09, 0x79, - 0xdb, 0xd5, 0x1f, 0x39, 0x57, 0xf6, 0x94, 0xe9, 0xf9, 0x79, 0xad, 0x57, 0x6a, 0xb7, 0xb9, 0x5e, 0xa3, 0x66, 0xea, - 0xa3, 0xec, 0x6f, 0xb6, 0xb1, 0xf0, 0x68, 0x0e, 0xa1, 0xcf, 0x48, 0x8b, 0xb9, 0xc7, 0xb9, 0xde, 0xec, 0x49, 0x61, - 0x60, 0xc4, 0xa4, 0x92, 0x91, 0xd3, 0x0b, 0x5c, 0x84, 0x2a, 0xc4, 0xb0, 0x96, 0xae, 0xf6, 0x59, 0x97, 0xde, 0x40, - 0x5d, 0x53, 0xec, 0x6b, 0xc8, 0xc0, 0x8b, 0xa6, 0x97, 0xc1, 0x18, 0x90, 0x23, 0xf0, 0x8e, 0xcf, 0x96, 0x70, 0x60, - 0xae, 0x01, 0xfa, 0xe6, 0x51, 0x5f, 0x97, 0x3b, 0xbe, 0x56, 0x7d, 0x33, 0x5d, 0x8f, 0x94, 0xf2, 0x63, 0xc5, 0xef, - 0x2e, 0x9e, 0xb3, 0x5b, 0xae, 0x51, 0x51, 0x7e, 0xd1, 0x8b, 0xf5, 0x1e, 0xb8, 0xea, 0x7e, 0x81, 0xdb, 0x2c, 0x1e, - 0xbb, 0xf2, 0x80, 0x65, 0x5b, 0xf6, 0xc0, 0x6e, 0xd8, 0x7b, 0xf6, 0x84, 0xbd, 0x61, 0xef, 0xd8, 0x4f, 0xa8, 0xda, - 0x50, 0x42, 0x9e, 0xbf, 0xe0, 0xb7, 0xd2, 0xf4, 0x28, 0x51, 0xc9, 0x1e, 0x6c, 0x33, 0xcd, 0x70, 0xc3, 0xde, 0xf3, - 0xc5, 0x70, 0xc5, 0xde, 0x40, 0x36, 0x94, 0x89, 0x07, 0x2b, 0xf6, 0x13, 0x57, 0x20, 0x66, 0xfa, 0x2c, 0x2c, 0x2d, - 0x51, 0xd1, 0x94, 0x89, 0x32, 0xf4, 0x1b, 0x8e, 0x2f, 0xb2, 0x9f, 0xb0, 0x08, 0xf9, 0x99, 0xe1, 0x8a, 0x3d, 0xf0, - 0xc5, 0x60, 0xc5, 0xde, 0x6b, 0x03, 0xd1, 0x60, 0xe3, 0x96, 0x46, 0x48, 0x56, 0xba, 0x2c, 0x29, 0x4d, 0x6f, 0xed, - 0x6b, 0xe0, 0x86, 0xdd, 0x60, 0xed, 0x9e, 0x60, 0xd1, 0x28, 0xf0, 0x0f, 0x56, 0xec, 0x1d, 0x97, 0x00, 0x6a, 0x6e, - 0x79, 0xd2, 0x2b, 0x54, 0x17, 0x48, 0xf7, 0x83, 0x27, 0x9c, 0x5e, 0x64, 0xef, 0xb0, 0x0c, 0xfa, 0xca, 0x70, 0xc5, - 0xb6, 0x58, 0xbb, 0x1b, 0x63, 0xd9, 0xb2, 0xaa, 0x27, 0x11, 0x81, 0x51, 0x50, 0x29, 0x2d, 0xff, 0x46, 0x2c, 0x9b, - 0xba, 0x69, 0x50, 0x1b, 0xfa, 0xf3, 0xc1, 0xe8, 0x2f, 0xbe, 0x7e, 0xf7, 0x83, 0x57, 0xea, 0x6b, 0xef, 0x2f, 0x8e, - 0x6b, 0x65, 0x89, 0xae, 0x95, 0xbf, 0xf2, 0x72, 0xf6, 0xcb, 0x7c, 0xa2, 0x6b, 0x49, 0x3b, 0x0c, 0xf9, 0x9a, 0xce, - 0x7e, 0xe9, 0x70, 0xb6, 0xfc, 0xd5, 0xf7, 0x1b, 0xd3, 0xc5, 0xea, 0xb3, 0xba, 0x77, 0x1f, 0x06, 0x9b, 0xc6, 0xa9, - 0xf7, 0xee, 0x74, 0xbd, 0xb1, 0x99, 0xb5, 0xf6, 0xcc, 0xfc, 0x1f, 0xae, 0xf4, 0x16, 0x87, 0xee, 0x86, 0x6f, 0x87, - 0x1b, 0x7b, 0x14, 0xe4, 0xf7, 0xa5, 0xd2, 0x38, 0xab, 0xf9, 0x0b, 0xaf, 0x53, 0x8a, 0x05, 0x44, 0xa3, 0x4f, 0x46, - 0x12, 0xba, 0x64, 0x26, 0x9e, 0x21, 0xbe, 0xc8, 0x00, 0x99, 0x0b, 0x44, 0xb3, 0x7b, 0x3e, 0x9e, 0xdc, 0x5f, 0xc5, - 0x93, 0xfb, 0x01, 0xff, 0x64, 0x5a, 0xd0, 0x5e, 0x6c, 0xf7, 0x3e, 0xfb, 0x95, 0x17, 0xf6, 0x72, 0xfc, 0xc5, 0x67, - 0x5f, 0x84, 0xbb, 0x42, 0x7f, 0xf1, 0xd9, 0x3b, 0xc1, 0x7f, 0x1d, 0x69, 0xa2, 0x0c, 0xf6, 0xae, 0xe6, 0xbf, 0x8e, - 0x90, 0xf1, 0x83, 0x7d, 0x16, 0xfc, 0x0b, 0xf8, 0x7e, 0x57, 0x09, 0x5a, 0xc5, 0x3f, 0xd7, 0xea, 0xe7, 0x7b, 0x19, - 0x97, 0x03, 0x6f, 0x42, 0x2b, 0xe8, 0xcd, 0xdb, 0x5a, 0xfe, 0x24, 0x1e, 0x8e, 0x54, 0x3d, 0x35, 0xfc, 0xb3, 0x58, - 0xcc, 0xa2, 0x3e, 0x4a, 0xa7, 0xf2, 0x26, 0x6f, 0x79, 0x26, 0xad, 0xcb, 0xf7, 0x10, 0x0a, 0xfc, 0xd6, 0x86, 0x28, - 0xd8, 0x71, 0xdc, 0x08, 0xde, 0xb2, 0x77, 0xc2, 0x67, 0xd9, 0x74, 0xcb, 0x6f, 0xf8, 0x13, 0xfe, 0x8e, 0xef, 0x82, - 0x07, 0xfe, 0x9e, 0xbf, 0xe1, 0x3f, 0xf1, 0x1d, 0x5b, 0x4a, 0xb4, 0xd3, 0x7a, 0x7b, 0x19, 0x6c, 0x59, 0xbd, 0xbb, - 0x0c, 0x1e, 0x58, 0xbd, 0x7d, 0x1e, 0xdc, 0xb0, 0x7a, 0xf7, 0x3c, 0x78, 0xcf, 0xb6, 0x97, 0xc1, 0x13, 0xb6, 0xbb, - 0x0c, 0xde, 0xb0, 0xed, 0xf3, 0xe0, 0x1d, 0xdb, 0x3d, 0x0f, 0x7e, 0x92, 0x18, 0x0f, 0xef, 0x84, 0xe4, 0x38, 0x79, - 0x57, 0x33, 0xc3, 0xa7, 0x1b, 0x7c, 0x16, 0xd6, 0x2f, 0xaa, 0x63, 0xf0, 0xb9, 0x66, 0xba, 0xc5, 0x81, 0x10, 0x4c, - 0xb7, 0x37, 0xb8, 0xa5, 0x27, 0xa6, 0x55, 0x41, 0x2a, 0x58, 0x57, 0x3b, 0x83, 0x45, 0xdd, 0xb4, 0xce, 0x64, 0xc7, - 0x2f, 0x31, 0xee, 0xf0, 0x4b, 0x5c, 0xb0, 0x65, 0xd3, 0xe9, 0xa4, 0x73, 0xfa, 0x24, 0xd0, 0x9b, 0xbf, 0xde, 0xf5, - 0x2b, 0xe9, 0x3b, 0x53, 0x34, 0x3c, 0x57, 0x5a, 0xe3, 0xd6, 0x4e, 0x1f, 0x5a, 0x3b, 0x3d, 0x93, 0x2a, 0xb4, 0x88, - 0x45, 0x65, 0x51, 0x55, 0xc8, 0x24, 0x1e, 0x64, 0x5a, 0x9f, 0x96, 0x30, 0x52, 0x64, 0x02, 0x1a, 0x7d, 0x41, 0xc7, - 0x40, 0x4e, 0x16, 0x05, 0xb6, 0xe4, 0x9b, 0x41, 0xc2, 0xd6, 0x3c, 0x9e, 0x0e, 0x93, 0x60, 0xc9, 0xee, 0xf8, 0xb0, - 0x5b, 0x20, 0x58, 0xa9, 0x00, 0x26, 0x7d, 0x71, 0x6a, 0xef, 0xeb, 0xbc, 0xb7, 0x4a, 0xe3, 0x38, 0x13, 0xa8, 0x6c, - 0xab, 0xf4, 0x06, 0xbf, 0x75, 0xf6, 0xf3, 0xb5, 0xda, 0xdf, 0x41, 0x52, 0xf8, 0x15, 0x18, 0x76, 0x88, 0xf0, 0x0e, - 0x2a, 0x8c, 0x3c, 0x4b, 0x66, 0xd1, 0x57, 0xf6, 0x96, 0xbe, 0x35, 0xdb, 0xf4, 0x7f, 0x5a, 0x04, 0xed, 0xe3, 0xb2, - 0xf3, 0x3f, 0x99, 0x57, 0x7f, 0xeb, 0x78, 0x75, 0xe3, 0x4f, 0x1e, 0xf8, 0x27, 0x0c, 0x4b, 0xc0, 0x44, 0xb6, 0xe3, - 0x9f, 0x46, 0xdb, 0xc6, 0x29, 0x4f, 0xee, 0xe3, 0xff, 0x57, 0x0a, 0xb4, 0x77, 0xf2, 0xca, 0xde, 0x11, 0xb7, 0xbc, - 0x63, 0x1f, 0x5f, 0x5a, 0x1b, 0xa2, 0x81, 0x26, 0xf9, 0xc4, 0xdd, 0x68, 0x68, 0xd8, 0x10, 0x7f, 0xe1, 0xd5, 0xec, - 0xd3, 0x7c, 0xb2, 0xe5, 0xc7, 0xdb, 0xe1, 0xa7, 0x8e, 0xed, 0xf0, 0x17, 0x7f, 0xb0, 0x6c, 0xbe, 0xd6, 0xab, 0x9d, - 0xdb, 0xb8, 0x53, 0xe9, 0x1d, 0x3f, 0xde, 0xc4, 0x87, 0xff, 0x71, 0xa5, 0x77, 0xdf, 0x5c, 0x69, 0xbb, 0xca, 0xdd, - 0x9d, 0x6f, 0x3a, 0xbe, 0x91, 0xb5, 0xc6, 0x38, 0x33, 0xa3, 0x59, 0xfc, 0x89, 0x66, 0x69, 0x10, 0x59, 0x0a, 0xc5, - 0x9f, 0xcc, 0xb4, 0x53, 0x77, 0xaa, 0xac, 0xee, 0x96, 0x6f, 0x71, 0x8f, 0xbf, 0xe5, 0x63, 0xb6, 0x30, 0x9e, 0x9a, - 0xb7, 0x57, 0x8b, 0xc9, 0x60, 0x70, 0xeb, 0xef, 0xef, 0x79, 0x38, 0xbb, 0x9d, 0xb3, 0xb7, 0xfc, 0x9e, 0x16, 0xd3, - 0x44, 0x35, 0xbd, 0x78, 0x4c, 0xf0, 0xba, 0xf5, 0xfd, 0x89, 0xc5, 0xff, 0x6a, 0x5f, 0x34, 0x6f, 0xfd, 0x81, 0xb4, - 0x46, 0xcb, 0x5d, 0xfd, 0xfd, 0xe3, 0x8a, 0x89, 0x5b, 0x10, 0x2f, 0xde, 0xdb, 0x9a, 0x86, 0x37, 0xfc, 0xa3, 0xf7, - 0xd6, 0x9f, 0xbe, 0xd5, 0x31, 0x37, 0x13, 0x75, 0x24, 0xbd, 0xb9, 0x78, 0xce, 0x7e, 0xe5, 0x9f, 0xe4, 0x71, 0xf2, - 0x45, 0xc8, 0x49, 0x7b, 0x83, 0xdc, 0x4d, 0x74, 0x4a, 0xbc, 0x73, 0x13, 0x09, 0x0b, 0x02, 0x61, 0x38, 0x6a, 0xfe, - 0x30, 0x29, 0xa7, 0xde, 0x0e, 0xb8, 0x5d, 0xb9, 0xad, 0x7f, 0xbe, 0xe5, 0x9c, 0x2f, 0x86, 0x97, 0xd3, 0x77, 0xdd, - 0x2e, 0x3d, 0x2a, 0x9a, 0x4d, 0x05, 0xba, 0xdd, 0x62, 0xec, 0xd5, 0xc9, 0xcc, 0x32, 0x97, 0x7c, 0xe9, 0x5d, 0x6d, - 0x66, 0x1e, 0xd3, 0xfb, 0xcd, 0x34, 0x43, 0x22, 0x5f, 0x20, 0x64, 0x3a, 0x1c, 0xee, 0xce, 0xb1, 0x3c, 0x3e, 0x7c, - 0xf3, 0xec, 0xc9, 0xe0, 0x09, 0x46, 0x6e, 0x59, 0xd1, 0x20, 0xef, 0xf8, 0x30, 0xab, 0x5b, 0xb7, 0x8d, 0x8b, 0xe7, - 0xc3, 0x5f, 0x20, 0x6f, 0xd0, 0xf5, 0xd0, 0x14, 0xd1, 0x2a, 0xbf, 0xa3, 0xe8, 0x13, 0x25, 0x07, 0x1d, 0x4f, 0xa0, - 0x76, 0x48, 0x81, 0xfb, 0xee, 0x19, 0x07, 0xfd, 0x06, 0x96, 0xda, 0xef, 0x9f, 0x7f, 0x22, 0x1e, 0x69, 0x18, 0xef, - 0xef, 0xc3, 0xe8, 0x8f, 0xb8, 0x2c, 0xd6, 0x70, 0xba, 0x0e, 0xe0, 0x73, 0xcf, 0xf4, 0xed, 0xeb, 0xce, 0xf7, 0xfd, - 0xc0, 0xdb, 0xf2, 0x1b, 0xf6, 0x8e, 0x7b, 0x97, 0xc3, 0x37, 0xfe, 0xb3, 0x27, 0x20, 0x3a, 0xc1, 0xb8, 0x7c, 0xc6, - 0x48, 0xd8, 0x8e, 0x62, 0xd4, 0x2a, 0xfc, 0x5c, 0x43, 0x88, 0xd6, 0x27, 0x64, 0xec, 0x82, 0xf4, 0x0f, 0x0a, 0xd0, - 0x4f, 0x08, 0xac, 0x26, 0xa9, 0x51, 0x60, 0x12, 0xdf, 0xd6, 0x90, 0x40, 0x0a, 0x16, 0x08, 0xbd, 0x81, 0xe2, 0x53, - 0xc1, 0xdf, 0x0d, 0x3f, 0x93, 0xe4, 0xb7, 0xa8, 0xf9, 0x18, 0xfe, 0x86, 0xa1, 0x99, 0x54, 0x0f, 0x69, 0x1d, 0x25, - 0xde, 0x4f, 0xfe, 0x3e, 0x0a, 0x2b, 0xa1, 0x8e, 0x85, 0x20, 0x15, 0x43, 0x2e, 0xc4, 0xc5, 0xf3, 0xc9, 0x6d, 0x29, - 0xc2, 0x3f, 0x26, 0xf8, 0x4c, 0x2e, 0x34, 0xf9, 0x8c, 0x9e, 0x34, 0xf2, 0xfd, 0x07, 0xf9, 0xbe, 0xec, 0xd4, 0x60, - 0x51, 0x0f, 0xf9, 0x6d, 0xed, 0xbe, 0x2f, 0xa7, 0x04, 0x3d, 0xb2, 0x1f, 0xd0, 0x14, 0x0c, 0xd4, 0x04, 0xa4, 0x0c, - 0xc1, 0x2d, 0x5c, 0xf5, 0x3d, 0x55, 0x90, 0x2f, 0xbf, 0xf7, 0x59, 0xc8, 0x70, 0x95, 0x05, 0x21, 0xc9, 0xa5, 0x42, - 0x0a, 0x1b, 0xb7, 0xf5, 0xe0, 0xb3, 0xc6, 0x24, 0x91, 0x90, 0x53, 0x02, 0x92, 0xa4, 0xbd, 0x81, 0x24, 0x11, 0xd3, - 0x7f, 0xb8, 0x4e, 0x9a, 0x66, 0x25, 0xa5, 0x1b, 0xe2, 0x54, 0x7d, 0x8b, 0x34, 0x67, 0xc1, 0x7b, 0x06, 0x4b, 0x47, - 0x8a, 0x15, 0xef, 0x8c, 0xc1, 0x58, 0x07, 0x0b, 0xdd, 0xc9, 0xe2, 0x7e, 0x95, 0x84, 0x69, 0x24, 0xaa, 0x7c, 0x11, - 0xf2, 0xe7, 0xbf, 0x94, 0xf8, 0xa3, 0xb7, 0x34, 0x10, 0x81, 0xe0, 0x07, 0x68, 0x3d, 0x60, 0x8d, 0x07, 0x3f, 0xb1, - 0xba, 0x0c, 0xf3, 0x2a, 0xa3, 0xf2, 0x66, 0x3b, 0xb6, 0x9d, 0x33, 0x55, 0xb5, 0xe0, 0xb3, 0x30, 0xb4, 0x68, 0x67, - 0xab, 0xe6, 0xe4, 0x36, 0x6f, 0xf0, 0x9d, 0x49, 0x12, 0xa9, 0xa5, 0x24, 0xd2, 0x56, 0xd7, 0xa7, 0x4b, 0xaf, 0x5b, - 0x54, 0xd0, 0x18, 0x01, 0x7a, 0x49, 0xba, 0xab, 0x7c, 0x42, 0xf1, 0xca, 0x6a, 0x58, 0x0d, 0x2f, 0x1d, 0x8a, 0x30, - 0xd6, 0xde, 0x5c, 0xc9, 0xb3, 0x3b, 0xb0, 0x1e, 0xa1, 0xb5, 0xab, 0x52, 0x87, 0xb0, 0xfd, 0x44, 0xef, 0x39, 0x95, - 0xfa, 0x1b, 0x50, 0x05, 0x4e, 0x1d, 0x0d, 0xf5, 0x51, 0x3b, 0x85, 0x6c, 0xe7, 0xde, 0x92, 0xa0, 0x72, 0x25, 0x37, - 0x55, 0x5a, 0x94, 0x52, 0xa6, 0x7c, 0x2d, 0xb3, 0x95, 0xdd, 0x27, 0x03, 0x88, 0x67, 0x83, 0x02, 0xc9, 0x45, 0x6d, - 0x35, 0x07, 0xe9, 0xa3, 0x59, 0xe2, 0x58, 0x3b, 0x28, 0xbc, 0xac, 0x02, 0x33, 0x97, 0xb9, 0x5c, 0x0e, 0x0a, 0x96, - 0xeb, 0xad, 0x66, 0x9a, 0xa9, 0xbe, 0xc8, 0xed, 0x6d, 0xc6, 0xcb, 0xf4, 0xdf, 0x2c, 0x19, 0xf0, 0xe8, 0xe2, 0xb9, - 0x1f, 0x40, 0x9a, 0xe4, 0x75, 0x80, 0x24, 0xd8, 0x1c, 0xec, 0x62, 0x87, 0x61, 0xab, 0x58, 0xd9, 0x93, 0xa7, 0xcb, - 0x1d, 0x9a, 0x72, 0x09, 0x23, 0x39, 0x31, 0x97, 0x52, 0xdf, 0x97, 0x54, 0x37, 0x14, 0x9c, 0x6c, 0x9a, 0x80, 0x52, - 0x40, 0xbb, 0x05, 0xff, 0x85, 0x4f, 0x0d, 0x9d, 0x16, 0x60, 0xa9, 0xed, 0x06, 0xfc, 0x17, 0xfa, 0xc5, 0xf6, 0x11, - 0xf5, 0x03, 0xf3, 0x60, 0x6f, 0xd6, 0x56, 0xc6, 0x80, 0x88, 0xc4, 0x15, 0xe4, 0x91, 0xe0, 0x07, 0xc5, 0x9e, 0x2e, - 0x13, 0x07, 0xce, 0x14, 0x17, 0x4b, 0xa9, 0xcd, 0xcc, 0x6b, 0xbf, 0xa5, 0x26, 0xde, 0x44, 0x49, 0x54, 0xd8, 0x0e, - 0x69, 0xf4, 0x92, 0x32, 0xa6, 0x0a, 0x36, 0x44, 0xf7, 0x75, 0x13, 0x4c, 0x81, 0x37, 0x55, 0x15, 0x10, 0xa1, 0xf6, - 0x22, 0xcb, 0xf3, 0x9b, 0x2e, 0xb0, 0xba, 0xe0, 0x63, 0x63, 0x9a, 0x5d, 0xb0, 0x92, 0xab, 0x99, 0xf4, 0x99, 0xb7, - 0x03, 0x2d, 0xe4, 0x5d, 0x5e, 0x16, 0xad, 0xd0, 0xf5, 0x20, 0x5a, 0xf8, 0x7b, 0xcd, 0xf1, 0xe8, 0xd9, 0xb6, 0x9a, - 0xda, 0xec, 0x6b, 0x2d, 0x16, 0xc8, 0x40, 0x34, 0xf4, 0x85, 0x9c, 0x51, 0xb8, 0xab, 0x34, 0x57, 0xab, 0x7d, 0x55, - 0x06, 0x09, 0x4c, 0x04, 0x59, 0xcb, 0xc2, 0x7b, 0x74, 0xaf, 0x1e, 0x69, 0x5e, 0x49, 0xf0, 0xcc, 0xc5, 0x5f, 0x00, - 0x08, 0xe5, 0x49, 0x42, 0x0e, 0xc8, 0x01, 0xfc, 0x2d, 0x45, 0xa9, 0x34, 0xc0, 0x3f, 0xab, 0xcb, 0xb1, 0xad, 0xef, - 0xef, 0xb4, 0x8a, 0xc1, 0xf5, 0xe7, 0xeb, 0xae, 0x67, 0xed, 0x10, 0xe7, 0xca, 0x56, 0xaf, 0x2d, 0xd3, 0x3c, 0x46, - 0xea, 0x1a, 0x80, 0x3b, 0x91, 0x1e, 0x81, 0x48, 0x66, 0xa2, 0x41, 0xce, 0xae, 0xf9, 0x78, 0x2a, 0x1e, 0x93, 0xf6, - 0x2a, 0xdf, 0x37, 0x17, 0xfa, 0x60, 0x8c, 0x7d, 0x0b, 0x1a, 0xc4, 0x47, 0xab, 0xad, 0x15, 0x88, 0xf5, 0x56, 0xa9, - 0x0f, 0xdd, 0x18, 0x05, 0x1d, 0x3c, 0xe2, 0x46, 0x2e, 0x38, 0xb6, 0xbb, 0xb6, 0x9e, 0xd2, 0x57, 0x00, 0xe6, 0x3a, - 0x50, 0xc9, 0x30, 0x48, 0x9d, 0x27, 0x0a, 0x93, 0xfc, 0x3c, 0x21, 0x09, 0x11, 0xd5, 0xd9, 0x72, 0x94, 0x72, 0xd3, - 0x02, 0x2e, 0x33, 0x32, 0xc0, 0x6c, 0xd2, 0xac, 0x9f, 0x5c, 0xbe, 0x04, 0xa9, 0x34, 0x44, 0x70, 0xc3, 0xf6, 0x92, - 0xd1, 0xad, 0xa3, 0x6e, 0x50, 0x25, 0x99, 0xeb, 0x37, 0xb7, 0xb3, 0x48, 0x99, 0x37, 0x1f, 0x61, 0xac, 0xc9, 0x87, - 0xb0, 0x4e, 0xf0, 0xdb, 0x00, 0x95, 0xf4, 0xa9, 0xf0, 0xa2, 0x11, 0x40, 0xa8, 0xef, 0x54, 0x19, 0x9f, 0x0a, 0x2f, - 0x1b, 0x6d, 0x59, 0x46, 0x29, 0x54, 0x17, 0xcc, 0x6e, 0x4d, 0x17, 0xa2, 0x5b, 0x55, 0x03, 0x6d, 0xe0, 0xda, 0x75, - 0xa0, 0x80, 0x86, 0x6a, 0x57, 0x6e, 0x58, 0x00, 0x56, 0x33, 0x11, 0x18, 0x2e, 0xff, 0x3e, 0x7f, 0xa9, 0x62, 0x78, - 0xfa, 0xfd, 0xd0, 0xdb, 0x6f, 0x83, 0x68, 0xb4, 0xbd, 0x64, 0xbb, 0x20, 0x1a, 0xed, 0x2e, 0x1b, 0x46, 0xbf, 0x9f, - 0xd3, 0xef, 0xe7, 0x0d, 0xe8, 0x48, 0x84, 0x09, 0xb3, 0xd7, 0x6f, 0xd4, 0xf2, 0x95, 0x5a, 0xbf, 0x53, 0xcb, 0x97, - 0x6a, 0x78, 0x6b, 0x4f, 0x12, 0x41, 0x64, 0xa9, 0x6a, 0x1e, 0x24, 0x45, 0xaa, 0xa5, 0xcb, 0x31, 0x5a, 0x8c, 0xa8, - 0xa5, 0xac, 0x39, 0xd6, 0x89, 0xb4, 0x73, 0x50, 0x32, 0xc0, 0xd1, 0xe2, 0xaa, 0xc6, 0x74, 0xb3, 0xa2, 0x25, 0x10, - 0x23, 0xac, 0x6c, 0xcb, 0xc5, 0x4d, 0xea, 0xa3, 0x73, 0xf2, 0x6d, 0xab, 0x94, 0x6f, 0x5b, 0xc1, 0xf3, 0xaf, 0x28, - 0x94, 0x4b, 0xae, 0x5d, 0xcb, 0xa6, 0x85, 0x52, 0x28, 0xe3, 0x1a, 0x6c, 0xed, 0x9b, 0xc0, 0x90, 0xf9, 0x48, 0x51, - 0x63, 0x7b, 0xd1, 0x28, 0x87, 0x20, 0x5b, 0x07, 0xa3, 0x4e, 0x59, 0xb0, 0xf8, 0x76, 0x87, 0x0c, 0x64, 0xa0, 0xa3, - 0xaa, 0x8d, 0x57, 0x3b, 0x2b, 0xfd, 0x61, 0x79, 0xf1, 0x9c, 0x25, 0x56, 0x3a, 0xf9, 0x4d, 0x85, 0xfe, 0x20, 0x44, - 0xdf, 0x94, 0x0d, 0x07, 0x2f, 0xba, 0xd8, 0xca, 0x80, 0x78, 0xc3, 0xf4, 0xde, 0xc6, 0x4a, 0x96, 0xbb, 0xa6, 0x7c, - 0x31, 0xe3, 0x09, 0xc7, 0xd1, 0x97, 0xab, 0x45, 0x58, 0xab, 0x45, 0x76, 0x02, 0x3c, 0xb4, 0x56, 0x4b, 0x21, 0x57, - 0x8b, 0x70, 0x66, 0xba, 0x50, 0x33, 0x3d, 0x03, 0xcd, 0xa3, 0x50, 0xb3, 0x3c, 0x01, 0x2c, 0x78, 0x61, 0x66, 0xb8, - 0x30, 0x33, 0x1c, 0x87, 0xd4, 0x38, 0x3d, 0xe8, 0xbd, 0xce, 0x3d, 0xb7, 0xdc, 0x8d, 0x4e, 0xc3, 0xbc, 0x1d, 0x6d, - 0x30, 0xc7, 0x07, 0xe1, 0x04, 0xe2, 0x03, 0x4b, 0x04, 0xe8, 0xd1, 0xb0, 0x3a, 0x6a, 0xa8, 0x1c, 0xc5, 0x97, 0x05, - 0x20, 0x59, 0x12, 0x80, 0xe4, 0x5e, 0x8d, 0x73, 0x69, 0xf9, 0x75, 0x95, 0x84, 0x1c, 0x91, 0xf1, 0x52, 0xda, 0xdd, - 0x13, 0x5e, 0x8e, 0x8c, 0xd0, 0x3c, 0x59, 0xa4, 0x5e, 0xce, 0x32, 0x36, 0x46, 0xe0, 0xa2, 0xd0, 0x6f, 0xaa, 0x7e, - 0x3f, 0x2d, 0xbd, 0x9c, 0xda, 0xf9, 0x09, 0xfc, 0x2d, 0x4f, 0x9d, 0x45, 0x8e, 0x90, 0x57, 0x23, 0x93, 0xb0, 0xbc, - 0x54, 0xea, 0xe9, 0x4b, 0x98, 0x41, 0xdd, 0xbd, 0x51, 0x00, 0xae, 0x45, 0x2e, 0x9d, 0x6a, 0x4b, 0xb8, 0x32, 0xe5, - 0x06, 0xfb, 0x3c, 0xe4, 0x39, 0x09, 0xa1, 0x12, 0x79, 0xa4, 0xb0, 0xee, 0xdb, 0x17, 0xcf, 0x27, 0xae, 0x0f, 0x8b, - 0x8d, 0x46, 0x70, 0x38, 0x00, 0xcc, 0xc1, 0xd4, 0x8b, 0x06, 0xbc, 0x54, 0x73, 0xe6, 0xa3, 0x97, 0x13, 0x36, 0x06, - 0xa8, 0x29, 0x06, 0x4e, 0x59, 0xcf, 0xe4, 0x23, 0xe3, 0x5b, 0xe6, 0xfb, 0x01, 0xbe, 0x5b, 0x17, 0x12, 0xf2, 0x41, - 0xa1, 0x12, 0x64, 0x0a, 0x95, 0x20, 0x31, 0xa8, 0x04, 0xb1, 0x41, 0x25, 0xd8, 0x34, 0x7c, 0x2d, 0x95, 0xb7, 0x11, - 0x70, 0x44, 0xf8, 0xd0, 0xb3, 0xb0, 0xb1, 0x42, 0xf1, 0x6c, 0xcc, 0xc6, 0xac, 0x50, 0x3b, 0x4f, 0x2e, 0xa7, 0x62, - 0x67, 0x31, 0xd6, 0x4d, 0x64, 0x99, 0x78, 0x21, 0x41, 0xc7, 0x39, 0x17, 0x12, 0x75, 0xf5, 0x73, 0xef, 0x25, 0x19, - 0x4b, 0xe6, 0x0d, 0x8d, 0x1a, 0xcc, 0xcb, 0xae, 0x03, 0x98, 0x96, 0x7c, 0x5b, 0xd0, 0x60, 0x3a, 0x55, 0x1e, 0x91, - 0x26, 0x41, 0xed, 0x5c, 0x26, 0x45, 0x4e, 0x08, 0x93, 0xa0, 0x57, 0x82, 0xdf, 0x48, 0x68, 0xff, 0xaf, 0x7a, 0xbe, - 0x03, 0x06, 0x13, 0xad, 0x92, 0x2f, 0x60, 0xb5, 0xcc, 0xf9, 0x0b, 0xe9, 0x89, 0x8d, 0xf8, 0x8b, 0x65, 0x1a, 0x8f, - 0xbe, 0xb0, 0x21, 0xe2, 0x59, 0xbd, 0x40, 0xd3, 0x12, 0xd4, 0x01, 0x1e, 0xd1, 0x5f, 0xa3, 0x2f, 0x86, 0x37, 0xa5, - 0xab, 0x91, 0xba, 0x66, 0xe7, 0x9c, 0x7f, 0xa9, 0x0d, 0x11, 0x32, 0xa6, 0x4d, 0x81, 0x64, 0x40, 0x20, 0xc9, 0x40, - 0x00, 0x60, 0x6a, 0x3a, 0xb3, 0x57, 0x00, 0xd1, 0x40, 0x00, 0x8f, 0xf3, 0x8e, 0xc7, 0x8f, 0xf4, 0x57, 0x71, 0xdc, - 0x3b, 0x4d, 0xc3, 0xf6, 0x5f, 0x80, 0xa6, 0x18, 0xca, 0xf1, 0x7c, 0xa7, 0x20, 0xd9, 0xa3, 0x94, 0xa5, 0xab, 0x26, - 0xb2, 0x43, 0xb1, 0x3e, 0xcd, 0x29, 0x0b, 0x69, 0x5b, 0x8e, 0xd1, 0x16, 0xeb, 0xc7, 0xc8, 0x7b, 0x73, 0xa3, 0x22, - 0x1f, 0xf4, 0xe0, 0xf6, 0xf6, 0xe6, 0x55, 0x8f, 0xd9, 0x24, 0x2b, 0x16, 0xb9, 0x8a, 0x38, 0x71, 0x5a, 0x87, 0x1c, - 0x30, 0x20, 0x27, 0x21, 0x30, 0x8d, 0x71, 0xa9, 0x40, 0x07, 0x25, 0xcb, 0x79, 0x0d, 0xd4, 0xb2, 0x88, 0xac, 0x01, - 0xa2, 0x9a, 0xe6, 0x5f, 0x35, 0xe4, 0x27, 0x55, 0x73, 0x4a, 0xa1, 0xf6, 0x15, 0x0f, 0xab, 0xd3, 0x27, 0x56, 0x6d, - 0x62, 0xac, 0x7f, 0xad, 0x3d, 0x41, 0x5b, 0x49, 0x03, 0xf1, 0x9d, 0xaf, 0xd2, 0x3b, 0x0a, 0xdd, 0x71, 0x66, 0xe2, - 0xa9, 0x0a, 0x8c, 0x7d, 0x6b, 0x47, 0x50, 0x38, 0x34, 0x5d, 0x07, 0x1c, 0xa6, 0xd1, 0x09, 0x8b, 0x7f, 0x4a, 0xc7, - 0xc9, 0x8b, 0x5a, 0x21, 0x92, 0xfc, 0x43, 0xb8, 0x30, 0x24, 0x16, 0xe4, 0x25, 0xa1, 0x8e, 0xc8, 0x88, 0xd5, 0xa8, - 0x58, 0x0b, 0x15, 0x15, 0xa7, 0x78, 0xbc, 0x55, 0x50, 0x5c, 0x8a, 0x52, 0xa5, 0x54, 0xe4, 0x46, 0xa5, 0x80, 0x58, - 0x36, 0xf0, 0x6e, 0x01, 0x07, 0x40, 0xd0, 0x59, 0xee, 0xd6, 0xb6, 0xbb, 0x8d, 0xcc, 0x67, 0xa6, 0x79, 0x5a, 0x7d, - 0x50, 0x7f, 0xbf, 0x5f, 0x62, 0x6c, 0x8d, 0xa7, 0xbf, 0x6f, 0xd3, 0x82, 0x9b, 0xbf, 0x61, 0x88, 0xee, 0x00, 0x11, - 0xb3, 0xb4, 0x87, 0x42, 0x16, 0x4c, 0x58, 0x86, 0xaa, 0x3c, 0xe5, 0xa8, 0x97, 0x4f, 0x6e, 0x01, 0x42, 0x0d, 0xfd, - 0xda, 0xe8, 0x54, 0x57, 0x25, 0x08, 0xdf, 0x77, 0x85, 0x7a, 0x6c, 0x0e, 0x78, 0x32, 0x00, 0xfe, 0x8a, 0xbc, 0xd6, - 0x63, 0xfb, 0x07, 0xbd, 0x51, 0x6f, 0x80, 0x20, 0x3a, 0xe7, 0x85, 0x7f, 0xc4, 0xb9, 0x4e, 0xfd, 0x19, 0x17, 0x82, - 0xf8, 0xd6, 0x93, 0xf0, 0x5e, 0x9c, 0xa5, 0x71, 0x70, 0xd6, 0x1b, 0x98, 0x8b, 0x40, 0x71, 0x96, 0xe6, 0x67, 0x20, - 0x96, 0x23, 0x26, 0x62, 0xcd, 0xee, 0x00, 0x26, 0xb0, 0xd4, 0x71, 0xc8, 0xaa, 0x63, 0xfb, 0xfd, 0xd7, 0x23, 0x43, - 0x96, 0x8e, 0x30, 0x30, 0xfa, 0x77, 0x05, 0x02, 0x14, 0x2c, 0x33, 0xdb, 0x83, 0x49, 0x57, 0x7b, 0x56, 0xcf, 0x9b, - 0x4d, 0xde, 0xd5, 0x3b, 0x56, 0xd3, 0x72, 0x6a, 0x5a, 0x65, 0x35, 0x6d, 0x92, 0x43, 0xcd, 0x44, 0xbf, 0xaf, 0x41, - 0x51, 0xf3, 0x39, 0x80, 0xb1, 0x61, 0xf2, 0xeb, 0x59, 0x35, 0xef, 0xf7, 0x3d, 0xf9, 0x08, 0x7e, 0x21, 0x5b, 0x99, - 0x5b, 0x63, 0xf9, 0xf4, 0x15, 0x91, 0x98, 0x19, 0x98, 0xa3, 0xbb, 0x23, 0x7c, 0xaf, 0x1b, 0xe1, 0x75, 0xcc, 0x15, - 0x36, 0x13, 0xd3, 0xd7, 0x30, 0x78, 0x9e, 0xf0, 0xc1, 0x45, 0x8e, 0xfe, 0x46, 0x0e, 0x33, 0x85, 0x05, 0x39, 0xf7, - 0x27, 0xaf, 0x11, 0x2f, 0x19, 0xe1, 0x1d, 0x74, 0x3a, 0xe1, 0x41, 0xf6, 0xfb, 0x2b, 0xe8, 0xcc, 0x56, 0x2a, 0x65, - 0xab, 0xa2, 0x32, 0x5d, 0xd7, 0x45, 0x59, 0x41, 0xc7, 0xd2, 0xcf, 0x5b, 0x21, 0x33, 0xeb, 0x67, 0x16, 0xdc, 0xd3, - 0x4a, 0x02, 0x4c, 0xd9, 0xb6, 0x89, 0xda, 0xc0, 0xcb, 0xba, 0xf8, 0x5c, 0xe0, 0xd1, 0x59, 0x7b, 0xbd, 0x11, 0x6a, - 0x9f, 0xf3, 0xd1, 0xba, 0x58, 0x7b, 0xe0, 0x07, 0x33, 0x4b, 0xe7, 0x8a, 0x38, 0x23, 0xf7, 0x47, 0x9f, 0x8b, 0x34, - 0xa7, 0x3c, 0xc0, 0x7d, 0x28, 0xe6, 0xf6, 0x5b, 0x20, 0xfd, 0xd0, 0x5b, 0x20, 0xfb, 0xe8, 0x9c, 0x93, 0xd7, 0x80, - 0x48, 0x87, 0x30, 0xb8, 0x15, 0x09, 0x3a, 0x56, 0x0d, 0x6f, 0x2d, 0xb0, 0xd3, 0x5e, 0x1a, 0xf7, 0xd2, 0xfc, 0x2c, - 0xed, 0xf7, 0x0d, 0x6a, 0x66, 0x8a, 0x70, 0xf0, 0x38, 0x23, 0x17, 0x49, 0x0b, 0xb6, 0x94, 0xf6, 0x5f, 0x0d, 0x1c, - 0x41, 0xc8, 0xdf, 0xff, 0x10, 0xde, 0x13, 0x80, 0xd8, 0xa4, 0x0d, 0xb8, 0xea, 0x31, 0x1d, 0x8d, 0x2d, 0x89, 0x5a, - 0x75, 0x36, 0x40, 0xe2, 0x54, 0x69, 0x3d, 0xe5, 0x66, 0x4d, 0x61, 0x90, 0x2a, 0x0b, 0xf5, 0x1b, 0xeb, 0xc9, 0x64, - 0x95, 0x8b, 0x8c, 0x38, 0x2a, 0xd3, 0x97, 0x9a, 0x11, 0x4c, 0x97, 0x7e, 0xbe, 0x80, 0x25, 0x1b, 0x7f, 0xc4, 0xc9, - 0x5b, 0x02, 0x8e, 0xed, 0xac, 0x5d, 0x55, 0xbb, 0x1c, 0xb7, 0x76, 0x73, 0x80, 0xef, 0xf5, 0x46, 0xa3, 0x91, 0x76, - 0x8e, 0x13, 0x30, 0x54, 0x3d, 0xb5, 0x14, 0x7a, 0xac, 0x56, 0x80, 0xba, 0x1d, 0xb9, 0xcc, 0x92, 0xc1, 0x7c, 0x61, - 0x1c, 0xbf, 0x34, 0x1f, 0x7d, 0xbc, 0x54, 0xd6, 0xae, 0x23, 0xbe, 0xfe, 0x83, 0xac, 0xd6, 0xb7, 0xbc, 0xab, 0x9a, - 0x80, 0x2f, 0xaa, 0x80, 0xd2, 0x6f, 0x78, 0x4f, 0xf6, 0x2e, 0xbe, 0x76, 0x83, 0x5d, 0xf2, 0x2d, 0x6f, 0x51, 0xe7, - 0xf9, 0xca, 0xc1, 0x8d, 0x2a, 0xdd, 0xde, 0x4b, 0x16, 0xb8, 0xf6, 0x8e, 0x9a, 0xc6, 0x7a, 0xe6, 0x47, 0x0f, 0x8b, - 0x90, 0xed, 0x7c, 0xec, 0x7d, 0xd5, 0x3c, 0x3d, 0x6b, 0xe8, 0x4d, 0x6a, 0xe8, 0x63, 0x2f, 0xca, 0xf6, 0xa9, 0x69, - 0x44, 0xaf, 0x61, 0x43, 0x1f, 0x7b, 0x4b, 0x4e, 0x0e, 0x89, 0x00, 0xa7, 0xc6, 0xfc, 0xf1, 0xe1, 0x74, 0x86, 0xbf, - 0x63, 0x40, 0x25, 0x10, 0xf3, 0xe9, 0x31, 0xed, 0x28, 0xc0, 0x8c, 0x2a, 0xbd, 0x7d, 0x7a, 0x60, 0x3b, 0x5e, 0xd6, - 0x43, 0x4b, 0xef, 0x9e, 0x1c, 0xdd, 0x8e, 0x57, 0xd5, 0xf8, 0x52, 0x0e, 0x79, 0x9e, 0xcf, 0x46, 0xa3, 0x91, 0x30, - 0x90, 0xdc, 0x95, 0xde, 0xc0, 0x0a, 0xa4, 0x6d, 0x51, 0x7d, 0x28, 0x97, 0xde, 0x4e, 0x1d, 0xda, 0x95, 0x3f, 0xc9, - 0x0f, 0x87, 0x62, 0x64, 0x8e, 0x71, 0x00, 0x37, 0x29, 0x94, 0x1c, 0x25, 0x6b, 0x09, 0xa2, 0x53, 0x1a, 0x4f, 0x65, - 0xbd, 0xb6, 0x22, 0xf2, 0x6a, 0xc4, 0x79, 0x08, 0x7e, 0xf4, 0x40, 0x2d, 0x7e, 0xad, 0x05, 0xb1, 0xc7, 0x3e, 0x55, - 0x4a, 0x2f, 0x78, 0x55, 0x40, 0x88, 0xd8, 0xdf, 0x0d, 0xb4, 0x83, 0x12, 0x1c, 0x4a, 0xb8, 0x0f, 0x08, 0x0b, 0xfd, - 0xca, 0xcb, 0x67, 0x32, 0x46, 0xb9, 0x37, 0xa8, 0xe6, 0x0c, 0x60, 0x2a, 0x7d, 0x06, 0x7e, 0x97, 0x00, 0x75, 0x8a, - 0x4f, 0xd1, 0xa9, 0xde, 0x3c, 0x6c, 0xba, 0x3e, 0x2d, 0x51, 0x14, 0xd1, 0x9d, 0x9f, 0x8f, 0x01, 0xb1, 0xb3, 0x6b, - 0x33, 0xd2, 0xae, 0xfd, 0x06, 0x0d, 0x56, 0x4a, 0x12, 0xed, 0x9c, 0x12, 0x76, 0x3b, 0x1f, 0xd9, 0xd2, 0x8f, 0x52, - 0x20, 0xe6, 0x8e, 0x13, 0x89, 0xec, 0xc1, 0x46, 0x4e, 0xe0, 0x16, 0xed, 0x1d, 0x1d, 0x80, 0xca, 0x8d, 0x82, 0xfc, - 0x6a, 0x8e, 0xe4, 0x8e, 0xef, 0x7a, 0xdf, 0x0d, 0xea, 0xc1, 0x77, 0xbd, 0xb3, 0x94, 0xe4, 0x8e, 0xf0, 0x4c, 0x4d, - 0x09, 0x11, 0x9f, 0x7d, 0x37, 0xc8, 0x07, 0x78, 0x96, 0x68, 0x91, 0x16, 0x09, 0xd5, 0xea, 0x1a, 0x37, 0xe1, 0x45, - 0x22, 0xb9, 0x87, 0x76, 0x9d, 0x47, 0xc4, 0x02, 0x90, 0xb1, 0xf8, 0x6c, 0xde, 0x50, 0xa8, 0xbb, 0x89, 0xd9, 0xa2, - 0xbb, 0x2c, 0xf6, 0xfb, 0x9b, 0x3c, 0xad, 0x7b, 0x3a, 0x3e, 0x06, 0x5f, 0x90, 0x6a, 0x02, 0x3c, 0xda, 0x5f, 0x99, - 0xe3, 0xd5, 0xab, 0xcd, 0x91, 0xb2, 0x50, 0x25, 0xea, 0xb7, 0x58, 0xcd, 0x7a, 0x08, 0xc3, 0x9d, 0x65, 0xc6, 0xda, - 0x5e, 0xf0, 0x4a, 0xce, 0xaa, 0xd8, 0x2e, 0xc7, 0x57, 0x2c, 0xb5, 0x95, 0x44, 0xe5, 0x68, 0x3d, 0xd6, 0xa6, 0x18, - 0xf9, 0x95, 0x42, 0xa2, 0x2c, 0x3a, 0xb6, 0x16, 0x0a, 0x88, 0x17, 0xa0, 0x2f, 0xd9, 0x99, 0x06, 0x58, 0x6f, 0xf4, - 0x2a, 0x22, 0xb4, 0x7c, 0xa4, 0xc2, 0x9b, 0xdc, 0x54, 0x99, 0x95, 0xcd, 0xa2, 0xdd, 0x4f, 0x15, 0xaf, 0x10, 0xac, - 0xde, 0xa8, 0x3d, 0x0a, 0x50, 0x7b, 0x68, 0xa1, 0x0c, 0x20, 0xa5, 0x69, 0x06, 0x80, 0x0c, 0x00, 0x32, 0x55, 0xc4, - 0x67, 0x02, 0x54, 0xda, 0xea, 0x46, 0x81, 0x13, 0xe9, 0x15, 0xd0, 0x2c, 0xb0, 0xd2, 0x47, 0x0a, 0x32, 0x58, 0x6c, - 0x11, 0x80, 0x95, 0x23, 0x67, 0x98, 0xc6, 0x90, 0x6d, 0x34, 0x71, 0x49, 0x9a, 0xdf, 0x87, 0x59, 0x2a, 0xf1, 0x24, - 0x7e, 0x90, 0x35, 0x46, 0x00, 0x20, 0x7d, 0x9f, 0x5e, 0x14, 0x59, 0x4c, 0x38, 0x70, 0xd6, 0x53, 0x07, 0x45, 0x4d, - 0xce, 0xb5, 0xa6, 0xd5, 0xb3, 0xda, 0xe4, 0x21, 0x0b, 0x74, 0xf6, 0x60, 0x4c, 0x6a, 0xf9, 0x9e, 0x47, 0xf6, 0x57, - 0x8e, 0x67, 0x84, 0xef, 0xba, 0x83, 0x53, 0xff, 0xdd, 0xd4, 0xc0, 0xc4, 0x94, 0x00, 0x6c, 0x0c, 0x8e, 0x26, 0xc4, - 0xef, 0x74, 0x4c, 0xa6, 0x36, 0x29, 0x02, 0x81, 0x87, 0xe0, 0x15, 0x3c, 0x37, 0x5c, 0x6e, 0xb9, 0xb1, 0xb3, 0xc8, - 0xd3, 0x04, 0xe0, 0xc4, 0x0b, 0xbe, 0x05, 0x38, 0x4e, 0xbd, 0x2a, 0x64, 0xcf, 0x9e, 0x8b, 0xe9, 0x6c, 0x1e, 0x3c, - 0x24, 0xb4, 0x7f, 0x31, 0xe1, 0x37, 0xdd, 0x55, 0x72, 0x65, 0x6a, 0xdd, 0x9b, 0xe8, 0x2a, 0x97, 0x3b, 0x7d, 0x5a, - 0x71, 0x0c, 0x73, 0x06, 0xab, 0x80, 0x9c, 0xb3, 0x21, 0xbf, 0x3e, 0x07, 0xc0, 0x96, 0x95, 0xf0, 0x22, 0x7e, 0x1d, - 0xca, 0x6a, 0x01, 0xdc, 0x23, 0xe7, 0x91, 0xf9, 0xe5, 0xab, 0xed, 0x50, 0xce, 0x29, 0x0a, 0x63, 0x39, 0x35, 0x2d, - 0x29, 0x4e, 0x87, 0x9e, 0x82, 0xc9, 0xd4, 0x96, 0xbf, 0xb7, 0x89, 0xcb, 0xec, 0xcd, 0x24, 0x9c, 0xaf, 0x23, 0xdb, - 0xd6, 0xaa, 0x7b, 0xe8, 0x86, 0x60, 0xd0, 0xc7, 0x08, 0x5a, 0x36, 0xd7, 0x77, 0xeb, 0xc1, 0x40, 0x61, 0xfb, 0xd6, - 0x74, 0xd3, 0xa2, 0x53, 0x1c, 0x70, 0x66, 0xad, 0x6b, 0x54, 0xaa, 0x8a, 0x43, 0x2f, 0x79, 0xb7, 0xac, 0xca, 0x2e, - 0x4b, 0x2f, 0x04, 0xa9, 0x51, 0x57, 0x11, 0x22, 0xa5, 0x62, 0x87, 0xf7, 0xe4, 0xd7, 0xc0, 0xc4, 0x33, 0x2b, 0x47, - 0x69, 0x3c, 0x07, 0x98, 0x20, 0x85, 0xbe, 0x29, 0xbf, 0x02, 0xdc, 0xd0, 0x45, 0x14, 0x66, 0x6f, 0xe2, 0x2a, 0xa8, - 0xad, 0xa6, 0xdf, 0x3b, 0x38, 0xb1, 0xe7, 0x75, 0xbf, 0x9f, 0x12, 0x8d, 0x1f, 0x86, 0x5e, 0xe0, 0xdf, 0xe3, 0xe9, - 0xbe, 0x09, 0x52, 0xf3, 0xca, 0x03, 0xbc, 0xa2, 0xcb, 0xad, 0x4d, 0xb9, 0xa2, 0x71, 0x31, 0xaf, 0x11, 0x11, 0x3e, - 0x75, 0x14, 0xdb, 0x6d, 0x7e, 0x9c, 0xda, 0x18, 0x0c, 0x42, 0xb8, 0x6f, 0x65, 0xfc, 0x3e, 0xf1, 0xf2, 0x59, 0x34, - 0x07, 0x45, 0x69, 0xa6, 0x49, 0x42, 0x0a, 0xe9, 0x25, 0x40, 0x1f, 0x0d, 0x42, 0xad, 0xae, 0xfc, 0x23, 0xf1, 0x52, - 0x35, 0xad, 0xcd, 0x53, 0xac, 0x51, 0x20, 0x66, 0xd1, 0xbc, 0x61, 0x19, 0x1d, 0x92, 0xea, 0x72, 0x69, 0x9a, 0xf1, - 0x87, 0xd5, 0x0c, 0xd5, 0x8a, 0xa3, 0x26, 0xa8, 0x51, 0xba, 0x81, 0x0b, 0xe0, 0xdf, 0xe9, 0x8e, 0xa3, 0x1a, 0x45, - 0x8a, 0x06, 0x7c, 0x82, 0xc0, 0xb0, 0x66, 0xf3, 0x84, 0xb5, 0xa6, 0xae, 0x19, 0xfd, 0xbe, 0x8c, 0x13, 0x32, 0x49, - 0x48, 0xce, 0x87, 0xcb, 0xf5, 0x23, 0xa9, 0x2e, 0x80, 0x54, 0xb9, 0x62, 0xb3, 0x5e, 0x6f, 0x0e, 0x18, 0xbd, 0xb0, - 0x7e, 0x61, 0xe3, 0x0a, 0xce, 0x2f, 0x09, 0x73, 0x57, 0xfd, 0x08, 0xb3, 0x0c, 0xaa, 0x80, 0x34, 0x3f, 0x16, 0xbc, - 0x79, 0xee, 0x02, 0x51, 0xbf, 0x1e, 0xa9, 0x0b, 0xca, 0x2c, 0x9d, 0x5b, 0x44, 0x20, 0xe0, 0x35, 0xac, 0x9e, 0x40, - 0xb2, 0x2f, 0x1f, 0xfb, 0x34, 0xa3, 0x40, 0x75, 0x04, 0xa0, 0x6c, 0xd6, 0x0f, 0x61, 0xff, 0x80, 0x70, 0x42, 0xfd, - 0xcd, 0x1b, 0x39, 0x6b, 0x48, 0x1e, 0x48, 0x35, 0xe1, 0x31, 0x9c, 0x1a, 0x0b, 0x7c, 0x69, 0xd1, 0x9b, 0x0a, 0x5e, - 0x13, 0x1c, 0xf7, 0x02, 0xad, 0x7d, 0x0b, 0x38, 0x42, 0x04, 0x97, 0xa1, 0x89, 0xd3, 0xde, 0xae, 0x17, 0x20, 0xa1, - 0xb9, 0x85, 0x73, 0xfd, 0xd6, 0x05, 0x2d, 0x4e, 0x91, 0x93, 0x45, 0x17, 0x18, 0xe8, 0x82, 0xcc, 0x1b, 0xff, 0xaa, - 0x60, 0xe5, 0x02, 0x64, 0x2f, 0x15, 0x2b, 0x89, 0xd8, 0x76, 0xea, 0x8f, 0x52, 0xd9, 0x6f, 0xcf, 0xac, 0x09, 0xfc, - 0x32, 0xb1, 0x5f, 0x22, 0x93, 0x6f, 0x7a, 0x6c, 0xf2, 0x95, 0xb1, 0xd0, 0xa9, 0x65, 0x70, 0x4e, 0x8f, 0x0c, 0xce, - 0xbd, 0x9d, 0x55, 0x9b, 0x10, 0x86, 0x82, 0x24, 0xd0, 0x74, 0xe9, 0x61, 0xdd, 0xf4, 0xe7, 0x27, 0x2d, 0x7e, 0xad, - 0xda, 0xb7, 0xee, 0xc7, 0x21, 0x76, 0xf1, 0xcb, 0xc4, 0x33, 0xec, 0xa3, 0x3e, 0x70, 0x80, 0xc9, 0x88, 0x89, 0xcb, - 0x7e, 0x1f, 0x0a, 0x9b, 0x8d, 0xe7, 0xa3, 0xba, 0xf8, 0xb9, 0x78, 0x00, 0x28, 0x87, 0x0a, 0xec, 0x72, 0x28, 0x43, - 0x19, 0xb1, 0xa9, 0x2d, 0xf7, 0xfc, 0xfe, 0x32, 0xcc, 0x41, 0xde, 0xd1, 0x98, 0x38, 0x67, 0x20, 0x86, 0xc1, 0xd7, - 0xbf, 0x7b, 0xb2, 0x4f, 0x9b, 0xef, 0xce, 0xe0, 0xbb, 0xa3, 0xb3, 0x0f, 0xc8, 0x71, 0x73, 0xb6, 0x2e, 0x8b, 0xfb, - 0x34, 0x16, 0x67, 0xdf, 0x41, 0xea, 0x77, 0x67, 0x45, 0x79, 0xf6, 0x9d, 0xaa, 0xcc, 0x77, 0x67, 0xb4, 0xe0, 0x46, - 0xbf, 0x5b, 0x13, 0xef, 0x9f, 0x95, 0xa6, 0x3d, 0x5b, 0x42, 0x38, 0x96, 0x56, 0x3f, 0x82, 0x12, 0x51, 0x91, 0xa2, - 0xca, 0x50, 0x56, 0x6b, 0xc7, 0x79, 0x9f, 0x68, 0x78, 0x6c, 0x9a, 0x90, 0xb8, 0x5a, 0xc2, 0x3a, 0xd4, 0xb3, 0xd3, - 0x26, 0xd9, 0x71, 0x1e, 0xa8, 0x03, 0x22, 0xe7, 0xd7, 0xf9, 0x68, 0x4b, 0x5f, 0x83, 0x6f, 0x1d, 0x0e, 0xf9, 0x68, - 0x67, 0x7e, 0xfa, 0x64, 0xad, 0x94, 0xc1, 0x46, 0x8a, 0x51, 0x08, 0x89, 0xe2, 0xb6, 0x3d, 0x06, 0xc0, 0xff, 0xfe, - 0xe1, 0x40, 0xbf, 0x77, 0xf2, 0xb7, 0xda, 0x2d, 0xad, 0x7a, 0x7e, 0x68, 0x11, 0x66, 0xbc, 0xaa, 0x0d, 0x3b, 0xdb, - 0x5e, 0x02, 0x4a, 0xef, 0x9b, 0x06, 0x35, 0x45, 0xf4, 0x13, 0x56, 0x13, 0xab, 0x38, 0x2c, 0x48, 0x89, 0x43, 0x0c, - 0xc7, 0x68, 0x87, 0x1e, 0xa7, 0x8b, 0x9a, 0x27, 0xf7, 0x1d, 0x32, 0x6e, 0x7d, 0x1f, 0x90, 0x5c, 0x0a, 0xe7, 0x1f, - 0xbc, 0xd0, 0x60, 0xa2, 0x17, 0x79, 0x55, 0x64, 0x62, 0x24, 0x68, 0x94, 0xdf, 0x90, 0x38, 0x73, 0x86, 0xb5, 0x38, - 0x53, 0x08, 0x61, 0x21, 0xa1, 0x72, 0x17, 0x25, 0xa5, 0x07, 0x67, 0x4f, 0xf6, 0x65, 0xf3, 0x3b, 0x61, 0x42, 0x8c, - 0x16, 0x40, 0x83, 0xb3, 0x6b, 0x97, 0xf7, 0x10, 0x96, 0xb9, 0xf7, 0xfb, 0x9b, 0xbb, 0xbc, 0x80, 0xb8, 0xcc, 0x33, - 0xa9, 0x58, 0x2d, 0xcf, 0x80, 0x26, 0x4f, 0xc4, 0x67, 0x61, 0x25, 0xa7, 0x41, 0xd5, 0x51, 0xac, 0xde, 0xc6, 0x73, - 0x0f, 0x78, 0xbd, 0xdf, 0x27, 0x40, 0xe0, 0xee, 0xb3, 0xd7, 0xca, 0x2d, 0x95, 0xf4, 0xc8, 0x73, 0x0c, 0x91, 0x4c, - 0x80, 0xd7, 0x19, 0x82, 0x23, 0x85, 0xd5, 0x73, 0x13, 0xe4, 0x1f, 0x5f, 0x9f, 0x50, 0x7c, 0xd1, 0x3c, 0x8a, 0x1a, - 0x16, 0xb2, 0x04, 0x8e, 0x87, 0x64, 0x96, 0xcd, 0x91, 0x9a, 0x3c, 0x6d, 0x4f, 0x91, 0x8e, 0x4e, 0x2c, 0xf1, 0xdb, - 0x9a, 0x54, 0x2f, 0x52, 0x61, 0x97, 0xb4, 0xb3, 0x95, 0xb9, 0x17, 0xc2, 0x50, 0x25, 0xdc, 0x7b, 0x55, 0xcf, 0x42, - 0xb9, 0x29, 0x5a, 0x15, 0xb3, 0x87, 0x29, 0x31, 0xc3, 0x14, 0xeb, 0x2f, 0x6c, 0xf8, 0x4d, 0xe2, 0xc5, 0x60, 0xb8, - 0x5e, 0xf2, 0x72, 0xb6, 0x31, 0x0b, 0xe1, 0x70, 0xd8, 0x4c, 0x8a, 0xd9, 0x12, 0x62, 0x5b, 0x97, 0xf3, 0xc3, 0xa1, - 0xab, 0x65, 0x6b, 0xe1, 0xc1, 0x43, 0xd5, 0xc2, 0x4d, 0xc3, 0x72, 0xf8, 0x99, 0xcc, 0x62, 0x6c, 0x5f, 0xe3, 0x33, - 0xfb, 0xf3, 0x45, 0xf7, 0x2c, 0x41, 0xc6, 0x8d, 0x35, 0x70, 0x8d, 0xcd, 0xda, 0x1d, 0xae, 0x46, 0x40, 0xf2, 0xb8, - 0x1b, 0xfd, 0x5d, 0xd9, 0x49, 0x4e, 0x82, 0x84, 0xd1, 0x0a, 0xe1, 0x77, 0xdf, 0xf8, 0x13, 0x2d, 0xf6, 0xa0, 0xdd, - 0xc6, 0x96, 0x10, 0xd5, 0xb4, 0xe7, 0x72, 0xa5, 0x58, 0x9a, 0xb7, 0xd2, 0x86, 0xcc, 0x87, 0xf5, 0xb9, 0x6f, 0xe4, - 0x40, 0xc1, 0x18, 0xf1, 0xd4, 0x3a, 0x88, 0x66, 0x73, 0xe0, 0xbe, 0x40, 0xf3, 0x08, 0x4f, 0x2d, 0x48, 0x50, 0x66, - 0x6d, 0xd8, 0x4f, 0x92, 0x93, 0xe5, 0x71, 0xf8, 0x16, 0xfe, 0xe5, 0x33, 0x6c, 0x12, 0x53, 0x14, 0x8f, 0xbf, 0x55, - 0x8a, 0xff, 0x8e, 0x2d, 0x88, 0x60, 0xed, 0x46, 0xd4, 0x86, 0xbf, 0xe1, 0xdf, 0xc2, 0x3e, 0xc2, 0x7e, 0x43, 0x13, - 0x84, 0x01, 0xac, 0x3f, 0x13, 0x88, 0x0b, 0x0b, 0x41, 0x82, 0xbf, 0x55, 0x92, 0x7f, 0x4e, 0xf8, 0x6c, 0x51, 0x02, - 0x59, 0x1d, 0x46, 0xf1, 0x09, 0xc5, 0x44, 0x21, 0x0c, 0xb7, 0x84, 0xde, 0xd1, 0x7f, 0x23, 0x4a, 0xb2, 0x49, 0x6e, - 0xc5, 0x7a, 0x20, 0x93, 0x24, 0x98, 0x60, 0xe5, 0x85, 0xf2, 0x85, 0x7b, 0xa1, 0xd4, 0x5a, 0x0b, 0x5a, 0xbf, 0xfc, - 0x49, 0xe2, 0x19, 0xd0, 0x3d, 0x90, 0x31, 0xe8, 0x36, 0xa2, 0x9a, 0xe4, 0x98, 0x3e, 0x4a, 0xe7, 0x19, 0xa8, 0x80, - 0xce, 0xd6, 0x59, 0x58, 0x2f, 0x8b, 0x72, 0xd5, 0x0a, 0x0f, 0x95, 0xa5, 0x8f, 0xd4, 0x63, 0xcc, 0x0b, 0xf3, 0xe4, - 0x44, 0x3e, 0x78, 0x04, 0x68, 0x78, 0x94, 0xa7, 0x55, 0x47, 0x69, 0xfd, 0xc0, 0x32, 0x60, 0x04, 0x4e, 0x94, 0x01, - 0x8f, 0xb0, 0x0c, 0xcc, 0xd3, 0x2e, 0x43, 0x0d, 0x62, 0x8d, 0xaa, 0x2b, 0xb5, 0xc1, 0x9c, 0x28, 0x4a, 0x3e, 0xc5, - 0xd2, 0x0a, 0x63, 0x68, 0xea, 0xca, 0x23, 0xeb, 0x25, 0x27, 0xec, 0xc9, 0x6e, 0x20, 0xdd, 0xc2, 0x46, 0x81, 0x0b, - 0xba, 0x96, 0x25, 0xca, 0x45, 0xb7, 0x8c, 0x28, 0x13, 0x21, 0xf5, 0xb3, 0x87, 0x33, 0xad, 0xf6, 0x1b, 0x3b, 0x69, - 0xdf, 0x1e, 0x29, 0x7a, 0xc1, 0x40, 0x7c, 0xda, 0x23, 0xa5, 0x9e, 0x35, 0x72, 0x19, 0xd8, 0xd2, 0xa5, 0xaa, 0xe7, - 0xbf, 0x41, 0xf9, 0x0e, 0x66, 0xc6, 0xd9, 0xec, 0x77, 0xbd, 0xb9, 0x3d, 0xd9, 0xd7, 0xcd, 0xef, 0xac, 0xd7, 0x83, - 0xad, 0x41, 0x26, 0xbe, 0x50, 0xd4, 0x53, 0x56, 0x21, 0x56, 0x64, 0xf6, 0xbf, 0x85, 0xf7, 0x3b, 0xbc, 0x35, 0x42, - 0xb3, 0x32, 0x1e, 0xe6, 0xa3, 0x27, 0x7b, 0xd1, 0xfc, 0xde, 0x59, 0xb6, 0x95, 0xab, 0x92, 0xd9, 0x7e, 0x3f, 0x4a, - 0x9a, 0xb3, 0xc7, 0x6b, 0x24, 0x75, 0x80, 0x8f, 0xd7, 0x67, 0xf8, 0x48, 0x25, 0x94, 0x5a, 0x50, 0xd5, 0xa0, 0xf5, - 0xb1, 0xdf, 0x5b, 0xcf, 0xe9, 0xe3, 0xc7, 0x72, 0xba, 0x25, 0x45, 0x18, 0x3f, 0x30, 0x98, 0xb2, 0x13, 0xa7, 0x2e, - 0x79, 0x33, 0xa4, 0x77, 0xdd, 0x2a, 0xa9, 0xcb, 0x1e, 0x25, 0x82, 0x50, 0x07, 0xeb, 0x17, 0xfb, 0x21, 0xcc, 0x6c, - 0xd1, 0x1f, 0x36, 0xab, 0x39, 0xa1, 0x20, 0x02, 0x44, 0xab, 0xbc, 0x0f, 0x1c, 0x93, 0x84, 0x59, 0x73, 0x43, 0xba, - 0xf5, 0xe6, 0x4a, 0x7b, 0x25, 0x05, 0xf4, 0x73, 0x90, 0xb9, 0x7d, 0x74, 0xcb, 0x55, 0xcb, 0x3c, 0x97, 0xb6, 0x1c, - 0xb0, 0x68, 0x21, 0x3a, 0xb3, 0x73, 0xe9, 0x70, 0xf0, 0x1f, 0xd4, 0x95, 0xa8, 0x22, 0x82, 0x8e, 0xa2, 0x05, 0xa3, - 0xd5, 0xaa, 0x5d, 0x4e, 0x36, 0x15, 0xb2, 0x25, 0x11, 0x4e, 0x94, 0xec, 0x95, 0x50, 0x1f, 0xe5, 0x6a, 0xcf, 0x34, - 0xc4, 0x9f, 0x09, 0xd8, 0xb4, 0xc1, 0xdf, 0x02, 0xf7, 0x32, 0x38, 0x33, 0xed, 0xd3, 0x30, 0x02, 0x22, 0x73, 0x08, - 0xf6, 0xf3, 0xbb, 0x1e, 0x54, 0xf0, 0xa0, 0x23, 0xfd, 0x55, 0x3d, 0x2b, 0xf0, 0xcc, 0x3d, 0xf1, 0xfc, 0xf5, 0x89, - 0xf4, 0x22, 0x87, 0x07, 0x9a, 0xfb, 0x30, 0xe3, 0x2f, 0xca, 0x32, 0xdc, 0x8d, 0x96, 0x65, 0xb1, 0xf2, 0x22, 0xbd, - 0x8f, 0x67, 0x52, 0x0c, 0x24, 0x3a, 0xcc, 0x8c, 0xae, 0x62, 0x1d, 0xe7, 0x30, 0xee, 0xed, 0x49, 0x58, 0xa1, 0xfd, - 0xb3, 0xc4, 0x5e, 0x17, 0x00, 0xe0, 0x90, 0x35, 0x68, 0x85, 0x77, 0xba, 0xbd, 0xdd, 0xe3, 0x92, 0x12, 0xc5, 0x8d, - 0x9a, 0x9f, 0xd5, 0xd0, 0x32, 0x41, 0x2d, 0xb3, 0xee, 0x64, 0x32, 0x45, 0x12, 0xf8, 0x36, 0xec, 0x35, 0x2b, 0xf2, - 0x79, 0x23, 0xb7, 0x87, 0x77, 0xe1, 0x4a, 0xc4, 0xda, 0x82, 0x4e, 0x3a, 0x32, 0x0e, 0xf7, 0x42, 0x73, 0x23, 0xdd, - 0x3f, 0xa9, 0x92, 0xb0, 0x14, 0x31, 0xdc, 0x02, 0xd9, 0x5e, 0x6d, 0x2b, 0x41, 0x09, 0x24, 0xb0, 0x1f, 0x4a, 0xb1, - 0x4c, 0xb7, 0x02, 0xc0, 0x1c, 0xf8, 0x9f, 0x12, 0x86, 0xd0, 0xdd, 0x79, 0x88, 0x57, 0x8d, 0xbc, 0x6f, 0x10, 0x82, - 0xfd, 0x15, 0xc8, 0x69, 0xc0, 0x20, 0x52, 0x8c, 0x64, 0xc1, 0x40, 0x02, 0x90, 0xf3, 0x35, 0x98, 0xe4, 0xa6, 0xb9, - 0xe7, 0x07, 0xb9, 0xee, 0x60, 0xda, 0x07, 0xdd, 0x8b, 0x6b, 0xcd, 0x72, 0xf0, 0x8a, 0x89, 0xf8, 0xdf, 0x6b, 0xaf, - 0x64, 0x39, 0xcb, 0xfc, 0xc6, 0x5c, 0x74, 0x32, 0xb8, 0x6a, 0x08, 0xbf, 0x98, 0x65, 0x73, 0x1e, 0xcd, 0x32, 0x1d, - 0xea, 0x5f, 0x34, 0x47, 0xa5, 0x00, 0x86, 0x3a, 0x5e, 0x80, 0x35, 0xde, 0x95, 0x6e, 0x5a, 0xf1, 0x48, 0x63, 0x8c, - 0x82, 0x0a, 0x1d, 0x84, 0xfe, 0x5e, 0x03, 0xbc, 0x06, 0x93, 0xdc, 0x08, 0x95, 0x0f, 0x2e, 0xe8, 0x86, 0x6e, 0xb9, - 0x72, 0x09, 0x6a, 0x52, 0xb5, 0xfc, 0x72, 0x84, 0x7a, 0x57, 0x4b, 0x2e, 0xd5, 0xe6, 0x53, 0xa3, 0xac, 0x11, 0x64, - 0x72, 0x94, 0x7e, 0x9f, 0x72, 0xe1, 0x56, 0xc6, 0x64, 0x7d, 0x38, 0x78, 0x05, 0x37, 0x35, 0x7e, 0x95, 0x13, 0x8b, - 0xa8, 0x3d, 0x24, 0xc2, 0xd6, 0x6e, 0x85, 0xee, 0x3d, 0x6e, 0x94, 0xe6, 0x51, 0xb6, 0x89, 0x45, 0xe5, 0xf5, 0x12, - 0xb0, 0x16, 0xf7, 0x80, 0x0c, 0x95, 0x96, 0x7e, 0xc5, 0x0a, 0x80, 0x0c, 0x90, 0xc2, 0xc6, 0x0f, 0x48, 0x7b, 0xf5, - 0xc1, 0x4b, 0xfd, 0x7e, 0xdf, 0x98, 0xf2, 0xdf, 0x3f, 0xe4, 0xc0, 0x4c, 0x28, 0xca, 0x7a, 0x07, 0x13, 0x08, 0xae, - 0x9d, 0xa4, 0x3d, 0xab, 0xf9, 0xf5, 0xba, 0xf6, 0x80, 0xd4, 0xca, 0xb7, 0x98, 0xab, 0x5e, 0xd9, 0x17, 0x9b, 0x7d, - 0x5a, 0xdd, 0x18, 0x8d, 0x83, 0x60, 0x69, 0xf5, 0x46, 0xab, 0x1c, 0xf2, 0x86, 0x57, 0x20, 0x52, 0x59, 0x57, 0xd7, - 0xca, 0xb9, 0xba, 0x16, 0x1c, 0x09, 0x64, 0x4b, 0x9e, 0xc3, 0x7f, 0x21, 0xf7, 0xca, 0xc3, 0xa1, 0xf0, 0xfb, 0xfd, - 0x74, 0x46, 0x5a, 0x59, 0xa0, 0x4c, 0x5b, 0xd7, 0x5e, 0xe8, 0x1f, 0x0e, 0x3f, 0x80, 0xd7, 0x88, 0x7f, 0x38, 0x94, - 0xfd, 0xfe, 0x47, 0x73, 0x93, 0x39, 0x1f, 0x2b, 0xa5, 0xec, 0x25, 0x2a, 0xdd, 0xdf, 0x24, 0xbc, 0xf7, 0xbf, 0x47, - 0xff, 0x7b, 0x74, 0xd9, 0x53, 0x01, 0x60, 0x09, 0x9f, 0xe1, 0x0d, 0x9d, 0xa9, 0xcb, 0x39, 0x93, 0xee, 0xee, 0xca, - 0x0f, 0xbd, 0xa7, 0xf1, 0xe1, 0x7b, 0x73, 0xd3, 0xc6, 0x5f, 0xab, 0x23, 0x4d, 0x42, 0xc7, 0x45, 0xff, 0x70, 0xf8, - 0x94, 0x68, 0x7d, 0x5a, 0xaa, 0xf4, 0x69, 0x0a, 0x3c, 0xc9, 0xb0, 0xe1, 0xba, 0x85, 0xe9, 0x68, 0x7e, 0xdc, 0x7c, - 0x95, 0xbc, 0x38, 0x4b, 0xe1, 0xda, 0x9b, 0xcf, 0xd2, 0xf9, 0x14, 0xac, 0x2b, 0xc3, 0x7c, 0x56, 0xcf, 0x03, 0x48, - 0x1d, 0x42, 0x9a, 0x35, 0x0d, 0xff, 0x56, 0xb9, 0x82, 0xb7, 0xf6, 0x78, 0x37, 0x18, 0x51, 0xea, 0x48, 0x9f, 0xb4, - 0x21, 0x74, 0x49, 0x25, 0xff, 0x51, 0xe4, 0x31, 0xc6, 0x6c, 0xbc, 0x22, 0xb2, 0xcf, 0x22, 0x7f, 0x59, 0x00, 0x60, - 0x11, 0x20, 0x20, 0xa7, 0x73, 0x47, 0x12, 0xff, 0x39, 0xf9, 0xf6, 0x8f, 0xe9, 0xd2, 0x3e, 0x94, 0xc5, 0x5d, 0x29, - 0xaa, 0xea, 0xa8, 0xb4, 0x9d, 0x2d, 0xd7, 0x03, 0x7d, 0x68, 0xbf, 0x2f, 0xe9, 0x43, 0x53, 0x0c, 0x45, 0x81, 0x5b, - 0x63, 0x6f, 0x9a, 0x72, 0x45, 0x53, 0x3d, 0x32, 0xd6, 0xcf, 0xef, 0x77, 0x6f, 0x62, 0x2f, 0xf5, 0x83, 0x14, 0x04, - 0x61, 0x8d, 0x9f, 0x94, 0x22, 0x09, 0x9c, 0xcf, 0x30, 0x95, 0xf8, 0x74, 0x29, 0x55, 0xfe, 0x30, 0xd2, 0x7c, 0x98, - 0x82, 0x5e, 0xf6, 0x1f, 0x15, 0xcc, 0x7f, 0xdd, 0x1e, 0xac, 0x4f, 0xeb, 0x32, 0x8d, 0x2a, 0xa2, 0xca, 0x0b, 0x53, - 0x6d, 0x02, 0x11, 0xfc, 0x5a, 0x58, 0x24, 0xbf, 0x3e, 0x39, 0x12, 0x34, 0x66, 0xb2, 0x7c, 0x3c, 0x72, 0xbf, 0xb0, - 0xaf, 0x5c, 0xc7, 0xf3, 0x3f, 0x37, 0xf3, 0x7f, 0x80, 0xce, 0x90, 0xc5, 0x35, 0xb7, 0x0c, 0x16, 0x38, 0xfb, 0xa5, - 0xab, 0x07, 0xfc, 0xcd, 0x3c, 0x71, 0x0d, 0x1c, 0xcc, 0xd7, 0xe8, 0xaa, 0x98, 0xce, 0x8a, 0x01, 0x10, 0xd8, 0xfa, - 0x8d, 0x35, 0x27, 0x5e, 0x5b, 0x3c, 0x57, 0x72, 0x41, 0xe8, 0xeb, 0x2a, 0xcc, 0xc6, 0x55, 0xb1, 0xa9, 0x44, 0xb1, - 0xa9, 0x7b, 0xa4, 0x96, 0xcd, 0xa7, 0xb5, 0xad, 0x90, 0xfd, 0x49, 0xb4, 0x68, 0xbb, 0x0c, 0xd5, 0x64, 0x94, 0xa5, - 0xeb, 0x29, 0x90, 0xea, 0x05, 0x70, 0x16, 0x99, 0x57, 0xbe, 0x38, 0x7b, 0xc0, 0x16, 0x8d, 0xa7, 0xc0, 0x88, 0x4a, - 0x7f, 0xe4, 0x8d, 0xd1, 0xe9, 0x89, 0x7e, 0x3f, 0x9f, 0x52, 0xc8, 0xd7, 0x4f, 0x80, 0xc9, 0x55, 0xcb, 0x05, 0xe8, - 0xcb, 0x50, 0x07, 0x95, 0x28, 0xb5, 0x62, 0x18, 0xb1, 0xf0, 0x93, 0x40, 0xf6, 0x66, 0x0a, 0x6a, 0x56, 0x51, 0x12, - 0x2a, 0x51, 0x29, 0xd9, 0x9a, 0xa0, 0x96, 0xde, 0x17, 0x45, 0xbd, 0xaf, 0xc0, 0x51, 0x32, 0xd2, 0x66, 0x39, 0x65, - 0xc6, 0x45, 0x99, 0x8b, 0x7e, 0xb0, 0x7f, 0x57, 0x9e, 0xdf, 0xc8, 0x7c, 0x96, 0xfb, 0x8e, 0xce, 0x69, 0x3b, 0x2e, - 0x50, 0xe6, 0x96, 0xd3, 0x56, 0x4b, 0x1e, 0x93, 0xf7, 0x2c, 0xd8, 0xf6, 0x5f, 0x24, 0xc8, 0xab, 0x08, 0xf3, 0x09, - 0x55, 0x36, 0xff, 0x80, 0x30, 0x5b, 0x1c, 0xd8, 0x63, 0x17, 0x26, 0x22, 0xbd, 0x05, 0x4b, 0x62, 0x98, 0x95, 0x22, - 0x8c, 0x77, 0xe0, 0xfd, 0xb3, 0xa9, 0xc4, 0xe8, 0x0c, 0x9d, 0xdc, 0xcf, 0x1e, 0xd2, 0x3a, 0x39, 0x7b, 0xf3, 0xea, - 0xec, 0xbb, 0xde, 0xa0, 0x18, 0xa5, 0xf1, 0xa0, 0xf7, 0xdd, 0xd9, 0x6a, 0x03, 0x10, 0x99, 0xe2, 0x2c, 0x26, 0x53, - 0x9a, 0x88, 0xcf, 0xc8, 0x30, 0x78, 0x56, 0x27, 0xe2, 0x8c, 0x26, 0xa6, 0xfb, 0x1a, 0xa5, 0xc9, 0xb7, 0xa3, 0x30, - 0x87, 0x97, 0x4b, 0xb1, 0xa9, 0x44, 0x0c, 0x76, 0x4a, 0x35, 0xcf, 0xf2, 0xf6, 0x59, 0x9c, 0x8f, 0x3a, 0x64, 0x95, - 0x0e, 0xd0, 0xed, 0x89, 0xb4, 0xab, 0xd2, 0x15, 0x10, 0x7a, 0x00, 0x9c, 0x74, 0xe5, 0xcf, 0xc3, 0x41, 0x24, 0x10, - 0x6a, 0xc1, 0x9c, 0x4c, 0x23, 0xba, 0x21, 0xbd, 0xc4, 0x3e, 0x03, 0xb3, 0x90, 0xd2, 0x3c, 0xb8, 0xb9, 0x5a, 0xb4, - 0xdc, 0x15, 0x2b, 0x47, 0x61, 0xb5, 0x16, 0x51, 0x8d, 0x54, 0xc7, 0xe0, 0xbc, 0x03, 0x11, 0x00, 0x8a, 0x11, 0x3c, - 0xe3, 0x51, 0xbf, 0x1f, 0xa9, 0xa0, 0x9c, 0x84, 0x7e, 0x51, 0xe8, 0x97, 0xc6, 0xa0, 0x8c, 0xf9, 0xbb, 0x50, 0x13, - 0x03, 0xd4, 0x5b, 0x1e, 0x2a, 0x8e, 0x00, 0x5c, 0xce, 0x11, 0x33, 0xce, 0x7b, 0xdc, 0x45, 0xe3, 0x54, 0xbc, 0x13, - 0xea, 0x3a, 0x58, 0x2a, 0xd4, 0x79, 0x53, 0x1f, 0xe9, 0x39, 0x69, 0x12, 0x34, 0x88, 0x1b, 0x78, 0xbc, 0x1a, 0x02, - 0xaa, 0x95, 0x90, 0x7a, 0x0b, 0x9d, 0x52, 0xd5, 0x21, 0xb0, 0x06, 0xb8, 0x44, 0x61, 0x5b, 0x61, 0x72, 0x44, 0x9b, - 0xb2, 0x14, 0xf9, 0x11, 0x1b, 0xb4, 0x4b, 0x46, 0xa6, 0x0e, 0xae, 0xff, 0xc3, 0xdb, 0xb7, 0x70, 0xb7, 0x6d, 0x63, - 0xeb, 0xfe, 0x15, 0x8b, 0x37, 0x55, 0x89, 0x08, 0x92, 0x25, 0x37, 0xe9, 0xb4, 0x94, 0x21, 0x1d, 0x37, 0x8f, 0x36, - 0x9d, 0xe6, 0xd1, 0x38, 0xed, 0x74, 0x46, 0x57, 0xc7, 0xa5, 0x49, 0xd8, 0x62, 0x43, 0x03, 0x2a, 0x49, 0xf9, 0x51, - 0x89, 0xff, 0xfd, 0xae, 0xbd, 0xf1, 0x24, 0x45, 0x3b, 0x99, 0xb9, 0xe7, 0xde, 0x95, 0xb5, 0x62, 0x11, 0x04, 0xf1, - 0xc6, 0xc6, 0xc6, 0x7e, 0x7c, 0xbb, 0x19, 0xcb, 0x49, 0x85, 0xfe, 0x75, 0x75, 0x01, 0x9c, 0x17, 0xc6, 0xb7, 0x6e, - 0x66, 0xcb, 0x75, 0xb4, 0xeb, 0xd2, 0xc5, 0x2c, 0x29, 0x78, 0xb9, 0x96, 0xa2, 0xcc, 0xae, 0xf9, 0x4f, 0xf6, 0x65, - 0x33, 0x80, 0x14, 0xda, 0x91, 0xbe, 0x6e, 0x77, 0x47, 0x8b, 0x71, 0x6c, 0x39, 0xbe, 0xa5, 0xd2, 0x9d, 0x1e, 0x55, - 0x2f, 0x6e, 0xb6, 0xce, 0xb5, 0xca, 0xd2, 0x94, 0x8b, 0x57, 0x22, 0xcd, 0x12, 0x2f, 0x39, 0xd6, 0x01, 0xaa, 0x5d, - 0xe4, 0x2b, 0x17, 0x1b, 0xf9, 0x79, 0x56, 0x62, 0xc0, 0xe0, 0x46, 0xa3, 0x5a, 0xa1, 0xa6, 0x4c, 0xe0, 0x0b, 0xf9, - 0x1e, 0x23, 0x6e, 0xb3, 0x32, 0x01, 0x86, 0x1f, 0x13, 0xf5, 0x25, 0x3d, 0x85, 0x28, 0x0f, 0x2a, 0x1e, 0xf7, 0x73, - 0x8e, 0x88, 0xd7, 0x56, 0x65, 0x0e, 0x4c, 0xb6, 0x56, 0x41, 0x22, 0xd8, 0x5d, 0xb6, 0xd0, 0x8b, 0x68, 0xa9, 0xee, - 0x42, 0xbd, 0x78, 0xb7, 0xeb, 0x25, 0x8a, 0x0e, 0x38, 0xf9, 0x69, 0xf0, 0x32, 0xce, 0x72, 0x9e, 0x1e, 0x54, 0xf2, - 0x40, 0x6d, 0xa8, 0x03, 0xe5, 0xcc, 0x01, 0x3b, 0xef, 0xcb, 0xea, 0x40, 0xaf, 0xe9, 0x03, 0xdd, 0xce, 0x03, 0xb8, - 0x60, 0xe0, 0xce, 0xbd, 0xcc, 0xae, 0xb9, 0x38, 0x00, 0x65, 0xa0, 0x35, 0x1e, 0xa8, 0x45, 0x35, 0x52, 0x13, 0xa3, - 0x03, 0x57, 0x27, 0xfa, 0x60, 0x0e, 0xe8, 0xf7, 0x10, 0x2b, 0xbc, 0xf5, 0x76, 0xad, 0x0f, 0xda, 0x80, 0xfe, 0xb4, - 0x32, 0x7d, 0xd0, 0xd1, 0xe2, 0x55, 0x48, 0xe0, 0xc6, 0x90, 0x6a, 0xa4, 0x56, 0x23, 0xab, 0x40, 0xf1, 0x86, 0xb7, - 0x78, 0xf7, 0xae, 0x25, 0x5b, 0xef, 0x25, 0x02, 0x7b, 0x65, 0xa2, 0x8a, 0x33, 0x71, 0xe2, 0xa5, 0xf2, 0x5a, 0x3b, - 0xc9, 0x08, 0xe3, 0x5b, 0x56, 0x52, 0x7f, 0x87, 0x98, 0x5b, 0xa4, 0x39, 0x0c, 0x5e, 0x84, 0x15, 0x99, 0xf3, 0x7e, - 0x5f, 0xce, 0x65, 0x54, 0xce, 0xc5, 0x61, 0x19, 0x29, 0x84, 0xb6, 0xfb, 0x44, 0x40, 0x0f, 0x4a, 0x80, 0x7c, 0x01, - 0x50, 0xf5, 0x90, 0xf0, 0xe7, 0x21, 0xa9, 0x4f, 0xa7, 0xd0, 0xa7, 0xd0, 0xd6, 0x2b, 0x5e, 0x41, 0x55, 0xdd, 0x18, - 0xd9, 0x46, 0x05, 0x2d, 0x1e, 0xcb, 0xb3, 0xda, 0x30, 0x36, 0xa7, 0xd6, 0xbb, 0xde, 0x6c, 0x30, 0x65, 0x73, 0xa1, - 0x56, 0x61, 0x48, 0xa2, 0x9b, 0xd2, 0x0b, 0x1f, 0x62, 0xb1, 0xb2, 0x5a, 0x9b, 0xdf, 0xc4, 0xfe, 0xc8, 0x44, 0x8a, - 0xfb, 0xd9, 0x12, 0xe7, 0x2e, 0x1e, 0xcf, 0xab, 0xbe, 0xd6, 0xd2, 0x22, 0xd3, 0xe6, 0x3b, 0x7d, 0x19, 0xd2, 0x54, - 0xd4, 0x90, 0x46, 0x9d, 0x19, 0x74, 0xdf, 0x2e, 0xaf, 0xa8, 0x46, 0x98, 0x00, 0xaf, 0x74, 0x06, 0xdd, 0x68, 0x3c, - 0x10, 0x45, 0x35, 0x2a, 0x36, 0x42, 0x20, 0xda, 0x30, 0xe4, 0x98, 0x5b, 0x42, 0x92, 0xfd, 0xc5, 0xbf, 0x53, 0xc1, - 0x15, 0x8a, 0xf8, 0xc6, 0xc0, 0x79, 0x57, 0xd6, 0xb3, 0xbb, 0x8e, 0xfc, 0x9c, 0x58, 0x58, 0xed, 0x3f, 0x34, 0x8f, - 0x5a, 0xe3, 0x2c, 0xa0, 0xad, 0x69, 0x75, 0xc3, 0xe1, 0x1e, 0xd5, 0xb1, 0x28, 0x0d, 0x20, 0xb1, 0x47, 0x96, 0x8b, - 0xd6, 0x31, 0x83, 0x06, 0xf4, 0xb7, 0xd9, 0xd5, 0xe6, 0x0a, 0x51, 0xdb, 0x4a, 0x64, 0x9d, 0xa4, 0xf2, 0x2f, 0x69, - 0x8f, 0xba, 0xb6, 0xa7, 0xf2, 0xbf, 0x6d, 0x53, 0xe5, 0xd0, 0x02, 0xc9, 0x63, 0x37, 0xe7, 0x81, 0xea, 0x48, 0x10, - 0x05, 0x6a, 0xeb, 0x05, 0x53, 0xef, 0x94, 0x29, 0x3a, 0x90, 0x9f, 0x0b, 0x73, 0x86, 0x7d, 0xc6, 0x11, 0x63, 0x96, - 0x4a, 0x0c, 0xa6, 0x3e, 0xc6, 0xa8, 0xa6, 0xb5, 0x02, 0x74, 0xfd, 0x74, 0x0b, 0x7f, 0xa2, 0xa2, 0x46, 0x43, 0xad, - 0x91, 0x14, 0x8a, 0x26, 0x2a, 0xe8, 0x58, 0x5a, 0xe8, 0x60, 0x0a, 0x9d, 0x44, 0xc2, 0x12, 0xd0, 0x30, 0x21, 0x3a, - 0xa9, 0xc0, 0x5b, 0x03, 0x38, 0xf3, 0x71, 0x51, 0x6e, 0x0a, 0x6d, 0x30, 0xf7, 0x43, 0x7c, 0xcd, 0x5f, 0x3d, 0x77, - 0x46, 0xf5, 0x2d, 0x6b, 0x7d, 0x4f, 0x0b, 0xf2, 0x43, 0xc8, 0x29, 0x3a, 0x30, 0xb1, 0xd9, 0x16, 0x8d, 0x31, 0xca, - 0x5a, 0x87, 0xba, 0x78, 0xab, 0xe3, 0xaf, 0x68, 0x13, 0xbc, 0x07, 0x3c, 0x45, 0xb4, 0xe1, 0xa1, 0x30, 0x56, 0xd5, - 0xf8, 0x54, 0xb2, 0x96, 0x1e, 0xac, 0xe0, 0xe9, 0x26, 0xe1, 0x21, 0xe8, 0x91, 0x08, 0x9b, 0x85, 0xc5, 0x22, 0x5e, - 0xc2, 0x71, 0x52, 0x10, 0x50, 0x3b, 0xe8, 0x2b, 0xf8, 0x62, 0x89, 0xee, 0xaf, 0x12, 0x3d, 0xc0, 0xd0, 0x82, 0xb8, - 0x19, 0xfa, 0x74, 0x74, 0x15, 0xaf, 0x1b, 0x2a, 0x12, 0xbe, 0x28, 0xc0, 0x76, 0x48, 0xa9, 0xa7, 0x40, 0x0b, 0x95, - 0x28, 0xfd, 0x30, 0xf0, 0x1d, 0x1a, 0xf8, 0x5a, 0xeb, 0x00, 0x0d, 0xfd, 0x8c, 0x69, 0x6a, 0x9d, 0xa1, 0xf2, 0xb9, - 0x77, 0xcf, 0x8c, 0x56, 0x73, 0x0b, 0xc6, 0xa0, 0x6f, 0xa3, 0x29, 0x8a, 0x73, 0xf2, 0x79, 0x50, 0xc4, 0x69, 0x16, - 0xe7, 0xe0, 0xb7, 0x19, 0x17, 0x98, 0x31, 0x89, 0x2b, 0x7e, 0x29, 0x0b, 0xd0, 0x76, 0xe7, 0x2a, 0xb5, 0xae, 0x41, - 0x40, 0xf6, 0x03, 0x58, 0xbd, 0x34, 0x74, 0x54, 0xce, 0xbb, 0x4b, 0x9b, 0x42, 0xc4, 0x22, 0x04, 0x9b, 0x66, 0xba, - 0x62, 0x27, 0xa1, 0xd2, 0xe6, 0x40, 0x7c, 0x23, 0x34, 0xee, 0x9f, 0x86, 0xb1, 0xd5, 0x14, 0x5b, 0xbb, 0xb7, 0xdd, - 0xee, 0xb7, 0xd2, 0x4b, 0xa7, 0x39, 0xe9, 0x31, 0xf6, 0x5b, 0x19, 0x16, 0x23, 0xdb, 0x11, 0x02, 0x4b, 0xce, 0xfb, - 0xd4, 0x7f, 0x45, 0xcb, 0x45, 0x02, 0xa6, 0x23, 0x3a, 0x42, 0x2e, 0x50, 0x76, 0x8c, 0xe2, 0x0e, 0x0c, 0xae, 0xe8, - 0xf7, 0xc1, 0x2a, 0xc3, 0x5c, 0x48, 0x56, 0x24, 0x65, 0xf0, 0x3c, 0xf5, 0x30, 0xe0, 0x37, 0x4c, 0x99, 0xbb, 0x28, - 0xeb, 0xd3, 0x15, 0x99, 0xa6, 0xc8, 0x40, 0x6c, 0xc2, 0x6d, 0x96, 0x46, 0x89, 0x12, 0x91, 0xad, 0xd0, 0x3f, 0xd2, - 0x50, 0x2c, 0x1d, 0xae, 0x17, 0xa9, 0x12, 0xa1, 0x62, 0x91, 0xe2, 0x49, 0x9d, 0xd6, 0xe9, 0x08, 0xe3, 0x4d, 0x82, - 0x52, 0xae, 0x86, 0x81, 0x2a, 0xa9, 0x5e, 0x0a, 0xdb, 0x62, 0xb7, 0xd3, 0x17, 0x2b, 0xb1, 0x88, 0x97, 0xf8, 0x52, - 0xe0, 0x28, 0xfe, 0x9d, 0x7b, 0xb1, 0xa6, 0xd4, 0xf6, 0xa0, 0x76, 0x44, 0x09, 0xfd, 0x3b, 0x87, 0x8b, 0xc4, 0x77, - 0x52, 0xc7, 0xfd, 0x43, 0x8b, 0x90, 0x33, 0x75, 0x90, 0x1a, 0x6e, 0x68, 0x4f, 0xf8, 0x6f, 0xb8, 0x3e, 0xe3, 0x8c, - 0xde, 0x54, 0x33, 0x6a, 0xfc, 0x5e, 0x0f, 0xcf, 0x18, 0xf5, 0xd9, 0xc0, 0x61, 0x85, 0x28, 0xb4, 0x61, 0xb3, 0x52, - 0x89, 0x16, 0x86, 0x52, 0xfd, 0x25, 0x54, 0xcc, 0xb8, 0x33, 0xa3, 0x2c, 0x19, 0x9f, 0x96, 0xc7, 0x62, 0x3a, 0x18, - 0x94, 0xa4, 0x32, 0x16, 0x7a, 0x70, 0x3d, 0xf0, 0xfc, 0x7b, 0xe0, 0x16, 0xe2, 0xc1, 0x21, 0x8b, 0x21, 0x37, 0xe0, - 0xf8, 0x2d, 0x4e, 0xae, 0x1a, 0x95, 0x2a, 0x78, 0x35, 0x51, 0x2d, 0xf8, 0x7b, 0x19, 0x06, 0xe8, 0x93, 0x14, 0x80, - 0xc9, 0x60, 0xca, 0x6f, 0x41, 0xa2, 0x74, 0xa6, 0x6e, 0x48, 0xbf, 0x88, 0x82, 0x5f, 0xf0, 0x82, 0x8b, 0xc4, 0x15, - 0x60, 0x79, 0x07, 0xdb, 0xeb, 0xa8, 0xa2, 0x0a, 0x88, 0xd7, 0xf4, 0x38, 0xe2, 0xc6, 0xfb, 0xcf, 0xf4, 0xd8, 0x02, - 0xb5, 0x5a, 0xc7, 0x06, 0x9f, 0x39, 0x06, 0x17, 0x74, 0x2d, 0xb1, 0x35, 0x54, 0xc3, 0x8a, 0xc0, 0xc0, 0x05, 0x1c, - 0x84, 0x25, 0x8a, 0x63, 0x2b, 0x79, 0x45, 0x1a, 0x52, 0xda, 0x07, 0x86, 0xa3, 0x4d, 0x72, 0x7c, 0x9b, 0x65, 0x37, - 0x81, 0x8b, 0x65, 0xe7, 0xa4, 0x99, 0x58, 0x36, 0x78, 0x9f, 0x37, 0xe7, 0xd7, 0xfd, 0x43, 0x42, 0x55, 0xb0, 0x1b, - 0xde, 0x0e, 0x76, 0xe3, 0x84, 0x5f, 0x0b, 0xb1, 0xd4, 0xf1, 0x59, 0xcc, 0x25, 0xcb, 0x6f, 0xad, 0x77, 0x4b, 0x92, - 0x5a, 0x01, 0xed, 0xb3, 0x2c, 0xa8, 0x89, 0x00, 0x74, 0x3f, 0xfc, 0x05, 0x42, 0x67, 0xf8, 0xdb, 0x63, 0x70, 0x45, - 0x0a, 0xef, 0x1d, 0x02, 0x61, 0x4d, 0x37, 0xf7, 0x6a, 0x03, 0xbe, 0x18, 0xf7, 0x67, 0x4c, 0x3d, 0xfd, 0x36, 0x93, - 0xfb, 0xba, 0x6e, 0x8f, 0x2c, 0xc3, 0x47, 0xb8, 0x52, 0x00, 0x2c, 0x13, 0xfe, 0x62, 0x6c, 0x49, 0xf5, 0x09, 0xc0, - 0xa9, 0xe9, 0x88, 0x3e, 0x41, 0x60, 0xe0, 0x94, 0x68, 0x31, 0xba, 0x56, 0x8e, 0x68, 0x06, 0x69, 0x4d, 0xb7, 0xc2, - 0x78, 0xeb, 0x41, 0x0b, 0x3d, 0xd3, 0x70, 0xe2, 0x3f, 0x68, 0xe6, 0x55, 0x01, 0x01, 0xb4, 0x32, 0x82, 0xb7, 0xd6, - 0x47, 0x73, 0x84, 0xf8, 0x84, 0x25, 0xd1, 0x84, 0xc5, 0x33, 0xc5, 0x8f, 0x09, 0xdd, 0x36, 0xb5, 0x4d, 0x1f, 0x90, - 0xfe, 0xe2, 0x9a, 0xf5, 0x53, 0x56, 0xb5, 0x6f, 0x0f, 0x15, 0x2f, 0xa7, 0xcd, 0xe0, 0x87, 0x89, 0x2a, 0xc6, 0xff, - 0xa2, 0xf2, 0xa5, 0x56, 0x00, 0xc3, 0xdc, 0x55, 0x4f, 0xbf, 0xdf, 0xcc, 0x96, 0x03, 0xa1, 0xf2, 0x3b, 0x83, 0xa4, - 0x4f, 0xc7, 0xf3, 0x03, 0x9b, 0x44, 0x6d, 0xa1, 0xe7, 0x8f, 0x4b, 0xdd, 0x84, 0xca, 0x6b, 0x53, 0x23, 0x5a, 0x21, - 0x43, 0x65, 0xeb, 0x80, 0xf5, 0xfd, 0x43, 0xb8, 0xbf, 0xa8, 0x69, 0xa8, 0x75, 0xcf, 0x5d, 0x8b, 0x82, 0x13, 0x7f, - 0x80, 0xb1, 0xb8, 0x90, 0xd4, 0x3a, 0x08, 0x93, 0x7e, 0xb4, 0x38, 0xc9, 0x8d, 0xba, 0x3a, 0x39, 0x53, 0xcc, 0x13, - 0xb8, 0xa8, 0x96, 0x6d, 0x7f, 0x45, 0xa5, 0x2e, 0xe5, 0xf6, 0x8a, 0xd2, 0xf4, 0x90, 0xb6, 0x57, 0x71, 0xde, 0x16, - 0x5c, 0xf0, 0xcf, 0x14, 0x5c, 0x58, 0x07, 0xeb, 0x8e, 0x3b, 0x65, 0x4f, 0x78, 0xa2, 0x4c, 0x6b, 0x83, 0xbb, 0x69, - 0x30, 0x26, 0xc6, 0x7e, 0x77, 0xc5, 0x93, 0x8f, 0xc8, 0x82, 0x7f, 0x97, 0x09, 0xf0, 0x4c, 0x76, 0xaf, 0x54, 0xfe, - 0x1f, 0xfc, 0xab, 0xad, 0x7d, 0x67, 0xcd, 0x3f, 0x3d, 0xeb, 0xe1, 0xce, 0x61, 0xf2, 0x03, 0x74, 0x06, 0x74, 0x7b, - 0x25, 0x53, 0x0e, 0xc8, 0x00, 0xd6, 0x22, 0x19, 0x0d, 0xf8, 0xd0, 0xca, 0xb2, 0xed, 0x3b, 0xad, 0x2e, 0x08, 0xf7, - 0x12, 0xb8, 0xe9, 0xfd, 0xb5, 0x99, 0x99, 0xd3, 0xb5, 0x12, 0x4d, 0x97, 0xc6, 0xd6, 0xb2, 0x54, 0x01, 0xbb, 0xdf, - 0x7b, 0x92, 0x4d, 0xf3, 0xe3, 0xd5, 0x34, 0xb7, 0xd4, 0x6d, 0xeb, 0x96, 0x0d, 0x00, 0x21, 0x76, 0xad, 0xad, 0x1c, - 0x40, 0x72, 0x7b, 0x10, 0xc2, 0xd7, 0x8a, 0xd0, 0x53, 0x25, 0x42, 0x9f, 0xa6, 0xcd, 0x3e, 0xd8, 0x55, 0xb5, 0x69, - 0xc4, 0x39, 0x1a, 0xa4, 0x9a, 0x91, 0x7f, 0x7b, 0xcd, 0x8b, 0x8b, 0x5c, 0xde, 0x00, 0x06, 0x32, 0xa9, 0x8d, 0xc2, - 0xf2, 0x0a, 0xdc, 0xf9, 0xd1, 0x71, 0x9c, 0x89, 0x51, 0x8e, 0xc1, 0x5a, 0x11, 0x1e, 0x59, 0x27, 0xce, 0x01, 0x04, - 0xd9, 0x9f, 0x34, 0x1d, 0xcf, 0xb5, 0xc0, 0x98, 0xbe, 0xc0, 0x5d, 0xe5, 0x6c, 0xb6, 0xcd, 0xed, 0xa2, 0x6f, 0xce, - 0xb0, 0xee, 0x48, 0x69, 0x6d, 0x2c, 0xba, 0xee, 0x60, 0xad, 0x19, 0xb4, 0x45, 0x28, 0xf9, 0x90, 0x3b, 0x69, 0xff, - 0x0a, 0x68, 0x70, 0x96, 0xa5, 0xb7, 0xd6, 0x2a, 0x7f, 0xab, 0x85, 0x38, 0x51, 0x4c, 0x9d, 0xf8, 0x26, 0x4a, 0xf4, - 0xf9, 0x99, 0x18, 0x37, 0x10, 0x48, 0xfd, 0x01, 0x83, 0x6a, 0x14, 0x61, 0x02, 0xd7, 0x81, 0x28, 0xb6, 0x27, 0x6a, - 0x63, 0x39, 0x82, 0x4e, 0x08, 0xf1, 0x0e, 0xca, 0x30, 0x56, 0x17, 0x07, 0xda, 0x60, 0xe9, 0xeb, 0xd6, 0x3a, 0x37, - 0x84, 0xc2, 0x38, 0x81, 0x29, 0x06, 0x49, 0x9d, 0x75, 0x96, 0x09, 0xaa, 0xec, 0x98, 0x74, 0xde, 0x07, 0xe8, 0xfe, - 0x5a, 0x34, 0xc5, 0xd7, 0x9d, 0x3b, 0xe8, 0x3e, 0xae, 0x5f, 0x6b, 0x91, 0x1b, 0xfc, 0x79, 0x4b, 0x84, 0x45, 0xe0, - 0xac, 0x35, 0xf9, 0xaa, 0x11, 0x0e, 0x4c, 0x49, 0xa6, 0x61, 0x2f, 0x51, 0x36, 0xdd, 0xbb, 0x5d, 0xaf, 0x77, 0xaf, - 0x88, 0xab, 0xc7, 0x58, 0xe5, 0xdd, 0xcc, 0xed, 0x9d, 0x6a, 0x23, 0xf6, 0x6f, 0xda, 0x7e, 0x8a, 0x1d, 0xb5, 0xd6, - 0x6e, 0x37, 0x9c, 0x50, 0x43, 0xbe, 0x15, 0x55, 0x5a, 0x9d, 0x6e, 0x0c, 0xda, 0x21, 0x9e, 0xb5, 0xc8, 0xe0, 0x46, - 0xf9, 0xdc, 0x09, 0x9d, 0x54, 0x9c, 0x55, 0xa7, 0x2e, 0xd8, 0x5e, 0xf1, 0x6a, 0x25, 0xd3, 0x48, 0x50, 0xb4, 0x39, - 0x8f, 0x4a, 0x9a, 0xc8, 0x8d, 0xa8, 0x22, 0x59, 0xa3, 0x5e, 0xd4, 0x6a, 0x0c, 0x10, 0x90, 0xe9, 0xac, 0xe9, 0x41, - 0x15, 0xcc, 0x87, 0x32, 0x92, 0xd3, 0xf7, 0x60, 0x69, 0x8f, 0x1c, 0x6b, 0x7d, 0x5f, 0x9d, 0x2d, 0xbe, 0xd5, 0x13, - 0x82, 0x29, 0xcc, 0x1e, 0x08, 0x03, 0xd7, 0x34, 0x86, 0x9c, 0x76, 0x89, 0xcb, 0x9a, 0x6e, 0x09, 0xf7, 0x70, 0xbb, - 0x92, 0xcd, 0xdc, 0x3c, 0x69, 0x6e, 0xae, 0x60, 0xb3, 0x62, 0x31, 0x06, 0xed, 0x97, 0x54, 0xd7, 0x2e, 0xcd, 0xad, - 0xc7, 0x83, 0x80, 0x06, 0x83, 0xc2, 0xf0, 0xaf, 0x13, 0xe3, 0xe1, 0x49, 0x03, 0x82, 0xa4, 0x5c, 0x84, 0x63, 0xdf, - 0x88, 0x7e, 0x32, 0x95, 0xc7, 0x1c, 0x2d, 0xde, 0xa1, 0xd5, 0x09, 0x44, 0xf1, 0x12, 0xa1, 0x24, 0x46, 0x55, 0x68, - 0x44, 0x50, 0x9e, 0x96, 0xbf, 0x54, 0xd5, 0x21, 0xa0, 0x90, 0xf6, 0x15, 0x85, 0xb2, 0x4d, 0x62, 0x68, 0x86, 0x5f, - 0x2e, 0x26, 0x4b, 0x3d, 0x03, 0x03, 0xb9, 0x38, 0x5a, 0xea, 0x59, 0x18, 0xc8, 0xc5, 0x57, 0xcb, 0xda, 0xad, 0x03, - 0x4d, 0x40, 0x3c, 0x17, 0x8e, 0x4e, 0x4a, 0xab, 0xb2, 0x05, 0x74, 0xfb, 0x10, 0x41, 0xff, 0xbb, 0x3d, 0x04, 0x9d, - 0x5c, 0x68, 0x4f, 0x6e, 0x40, 0xdb, 0x71, 0x08, 0xec, 0x15, 0x93, 0x0a, 0x13, 0x80, 0xe8, 0x98, 0x8d, 0xc1, 0x10, - 0x5b, 0x7d, 0x70, 0xcc, 0xc6, 0x53, 0x9f, 0x04, 0x01, 0xa3, 0xfb, 0x83, 0x81, 0x04, 0xbf, 0xc5, 0xab, 0xf4, 0x6c, - 0x2b, 0xd0, 0x4d, 0xdf, 0xdd, 0x0d, 0xbd, 0x8b, 0x2b, 0x38, 0x55, 0xbb, 0x7b, 0x12, 0xba, 0xc9, 0xb4, 0x03, 0xf4, - 0x1a, 0xe2, 0x86, 0xfc, 0xca, 0x68, 0x34, 0xb2, 0x29, 0x21, 0x21, 0x86, 0x73, 0x68, 0xe6, 0xb4, 0x5c, 0xbe, 0xba, - 0xf5, 0x6c, 0x41, 0x86, 0x99, 0xde, 0x32, 0x59, 0x3f, 0x40, 0x59, 0xf5, 0x18, 0xda, 0xa1, 0xf7, 0xc8, 0xf1, 0xc3, - 0x83, 0x6f, 0x32, 0x7e, 0xe2, 0x70, 0xed, 0xe1, 0x5c, 0xf8, 0x2e, 0x6b, 0x46, 0xe6, 0xd0, 0x79, 0xf6, 0x71, 0xbc, - 0x87, 0x71, 0xf2, 0x69, 0x16, 0xca, 0x1b, 0xaf, 0xe9, 0x7f, 0x54, 0x7a, 0xb3, 0xc3, 0x21, 0xa7, 0x6b, 0x58, 0x71, - 0xf3, 0x2a, 0x34, 0xfc, 0x2c, 0xf2, 0xc6, 0x11, 0xaf, 0x49, 0x54, 0x75, 0x9f, 0xf7, 0x36, 0x4c, 0x69, 0xc7, 0x38, - 0x00, 0x38, 0x51, 0xab, 0x86, 0x7d, 0x69, 0x5c, 0xab, 0x83, 0x18, 0x86, 0x12, 0xb6, 0x4a, 0x1c, 0x09, 0xe5, 0x6f, - 0x00, 0xc2, 0x62, 0x28, 0x8e, 0xb7, 0x86, 0xf5, 0x01, 0xf6, 0x43, 0x17, 0x68, 0x9a, 0x53, 0xaa, 0x19, 0x00, 0x24, - 0x01, 0x7f, 0xf4, 0x74, 0xd3, 0x50, 0xd9, 0xe6, 0x79, 0x68, 0x59, 0x5d, 0xc1, 0x03, 0x3d, 0x75, 0x25, 0x03, 0xe3, - 0xaa, 0x8e, 0xbd, 0xed, 0xfd, 0xed, 0xd1, 0x2a, 0xf2, 0xbd, 0x4d, 0x6a, 0x9b, 0x55, 0xa1, 0xb1, 0x8f, 0x27, 0xf4, - 0x74, 0x02, 0xb4, 0x5e, 0x5b, 0x2a, 0xda, 0xef, 0xa3, 0x18, 0x35, 0x2e, 0x14, 0x58, 0x85, 0x89, 0x04, 0x87, 0x08, - 0x23, 0x84, 0x7e, 0x5f, 0x86, 0x5b, 0x5f, 0x90, 0x41, 0x34, 0x5c, 0x8b, 0x8e, 0x3f, 0xe4, 0x78, 0xd1, 0xb6, 0x54, - 0xd5, 0x9c, 0x34, 0x6d, 0x09, 0xbc, 0x09, 0x07, 0xd8, 0xce, 0x3f, 0x6d, 0x88, 0x5c, 0x85, 0x8b, 0x12, 0xbe, 0x27, - 0xae, 0x05, 0xd1, 0x4d, 0x6d, 0xea, 0x6d, 0xd8, 0x21, 0x3a, 0x9a, 0xe2, 0xd1, 0x21, 0xf7, 0xdc, 0x3d, 0xb7, 0x45, - 0x7c, 0xf3, 0x09, 0x72, 0xd7, 0x74, 0xf6, 0x52, 0x84, 0x41, 0xdd, 0xb2, 0x81, 0x62, 0x1d, 0x3b, 0x41, 0x01, 0x46, - 0x6d, 0xf9, 0x0b, 0xe8, 0xd8, 0x60, 0x50, 0x11, 0x7c, 0x52, 0xd8, 0x36, 0x0d, 0xf2, 0x47, 0xbc, 0x1b, 0x3a, 0xbc, - 0xb6, 0xe4, 0x81, 0x78, 0x85, 0x7d, 0xa2, 0x84, 0xfb, 0x17, 0x14, 0x74, 0x47, 0x79, 0xb9, 0x2a, 0x5c, 0x95, 0x06, - 0xa0, 0xca, 0x9e, 0xe7, 0x5a, 0x53, 0xd2, 0x02, 0x56, 0x4a, 0xea, 0xce, 0x6f, 0x22, 0xe2, 0x96, 0x4c, 0xc5, 0x6c, - 0xd5, 0x8d, 0x2a, 0x8f, 0x25, 0x8a, 0x74, 0xec, 0xd9, 0xce, 0xc1, 0x1a, 0x00, 0x4f, 0x61, 0x7b, 0x71, 0x86, 0x05, - 0x65, 0x5c, 0xb6, 0xcc, 0x25, 0x50, 0xd4, 0x0f, 0xe3, 0xbc, 0xec, 0xf9, 0x72, 0x77, 0xb4, 0xbd, 0x87, 0xde, 0x88, - 0x8d, 0xf1, 0xfa, 0x3c, 0x6a, 0xfa, 0xd9, 0x33, 0x5c, 0x59, 0x0a, 0xf2, 0x40, 0x53, 0x3d, 0xc2, 0xe8, 0x10, 0x98, - 0xa6, 0x7c, 0xc6, 0xc6, 0xd3, 0xe1, 0xd0, 0x90, 0x41, 0xaf, 0x99, 0x18, 0xff, 0xeb, 0x33, 0x68, 0x9d, 0x99, 0xb8, - 0xc6, 0xa7, 0xed, 0x2b, 0x68, 0x75, 0x8b, 0x32, 0xb9, 0x33, 0x30, 0x7c, 0xa0, 0x25, 0x53, 0x30, 0x55, 0x78, 0x43, - 0xa4, 0x92, 0xfd, 0xb5, 0xb2, 0x0e, 0xfb, 0x76, 0xa1, 0xd0, 0x42, 0x13, 0xbf, 0xca, 0x10, 0x3f, 0x75, 0x9d, 0xf9, - 0xb7, 0x69, 0x9f, 0x1a, 0xc4, 0xc2, 0x92, 0x18, 0x85, 0xf8, 0xc5, 0xa9, 0xb2, 0x9d, 0x10, 0x2a, 0x20, 0x1e, 0xba, - 0xd6, 0x8d, 0x23, 0xa9, 0x62, 0x4f, 0x0a, 0x8d, 0xa7, 0x86, 0xfb, 0x5e, 0xe8, 0x98, 0x75, 0x98, 0xc5, 0x6d, 0xd6, - 0x48, 0x6a, 0x8c, 0x53, 0x61, 0x82, 0x53, 0xca, 0x75, 0x24, 0x30, 0x3a, 0x9e, 0x2d, 0x0c, 0xa2, 0x4a, 0x62, 0x92, - 0xb1, 0xb5, 0x10, 0x26, 0x76, 0x9d, 0x2b, 0x4c, 0x53, 0x17, 0xa9, 0xdf, 0x0c, 0x4c, 0x16, 0x34, 0xe4, 0xf7, 0x68, - 0xb4, 0xa6, 0x6a, 0x0a, 0x30, 0x8c, 0xa3, 0x54, 0xe3, 0xdf, 0x22, 0xd4, 0x66, 0x18, 0x00, 0xd8, 0xe6, 0x9d, 0xcc, - 0x44, 0xf5, 0x4a, 0x20, 0x04, 0x9a, 0xb3, 0x9f, 0x2a, 0xaa, 0xbd, 0x59, 0x30, 0x8a, 0x76, 0x7b, 0xe5, 0xf3, 0x81, - 0x13, 0xca, 0x13, 0x75, 0x81, 0x7a, 0x29, 0x8b, 0xd7, 0x32, 0xe5, 0xad, 0xb8, 0x98, 0x07, 0x92, 0x7d, 0xc8, 0x47, - 0x70, 0x5e, 0xa1, 0x53, 0xb9, 0xd9, 0x26, 0xca, 0x2c, 0x49, 0x32, 0x16, 0x18, 0x9b, 0x97, 0x60, 0x2e, 0x35, 0x33, - 0x86, 0x5f, 0x43, 0x70, 0xb1, 0xbd, 0x93, 0x70, 0x7b, 0x3f, 0x0f, 0x0c, 0xa1, 0xc9, 0x45, 0x4b, 0x34, 0x6c, 0xed, - 0x78, 0x3d, 0xb9, 0x26, 0xdc, 0x87, 0x8d, 0x58, 0x93, 0x31, 0xc6, 0xb5, 0xb9, 0x91, 0xf5, 0xa3, 0x05, 0x1e, 0x8c, - 0x29, 0xeb, 0x4f, 0x20, 0xd3, 0x4a, 0xca, 0xba, 0x58, 0x1a, 0x31, 0x93, 0x4a, 0xf4, 0x6e, 0xdf, 0xf8, 0xac, 0xee, - 0x22, 0xea, 0xb7, 0xf6, 0x7b, 0x52, 0x0f, 0x77, 0xfe, 0x83, 0xc2, 0x1a, 0x54, 0x46, 0x5c, 0x46, 0x94, 0x67, 0x0e, - 0x74, 0xd3, 0xa4, 0x88, 0xd3, 0xb3, 0x75, 0x5c, 0x94, 0x3c, 0x85, 0x4a, 0x35, 0x75, 0x8b, 0x7a, 0x13, 0xb0, 0x37, - 0x44, 0x92, 0x64, 0x2d, 0x8d, 0xad, 0xd8, 0xa5, 0x41, 0x7a, 0xee, 0x0d, 0xb3, 0xf4, 0xb2, 0x42, 0x43, 0x5a, 0xea, - 0x9d, 0x85, 0x4a, 0xe6, 0xaf, 0xf8, 0xcf, 0xa0, 0x56, 0xa0, 0xa3, 0x4d, 0x8a, 0xf1, 0x0c, 0x18, 0xf1, 0xfd, 0x08, - 0x56, 0x0f, 0x10, 0x17, 0x4d, 0x50, 0xea, 0x3d, 0xb1, 0xe3, 0xa7, 0x26, 0x0f, 0xef, 0x42, 0xce, 0x19, 0x7c, 0xfa, - 0x30, 0x4b, 0xd4, 0x5a, 0x47, 0x62, 0xa4, 0x66, 0x00, 0x4d, 0x07, 0x65, 0xce, 0x63, 0x11, 0xcc, 0x7b, 0x26, 0x31, - 0xea, 0x71, 0xfd, 0x0b, 0x34, 0xd4, 0x7e, 0xb3, 0xb2, 0x3c, 0xab, 0xee, 0x3e, 0x87, 0x03, 0x9b, 0xda, 0x0a, 0x7a, - 0xbc, 0xae, 0xe4, 0xe5, 0xa5, 0xea, 0xb6, 0x5f, 0x88, 0x91, 0xd3, 0x35, 0xae, 0xa5, 0x8b, 0x6a, 0xc9, 0x7a, 0xdd, - 0xe9, 0x66, 0x71, 0x37, 0xcb, 0x68, 0x20, 0xac, 0xed, 0x7d, 0xa2, 0xf9, 0xb3, 0x66, 0xdb, 0x7d, 0xbc, 0x05, 0x31, - 0x0f, 0x00, 0x20, 0x3d, 0x88, 0x82, 0x55, 0x96, 0xf2, 0x80, 0xca, 0xfb, 0x38, 0xca, 0x42, 0xe9, 0xe5, 0x2c, 0xe3, - 0xa7, 0x4d, 0x63, 0xad, 0xb3, 0x42, 0x19, 0x5a, 0x1b, 0xdd, 0xe9, 0x3a, 0x43, 0x6c, 0x3f, 0x89, 0xb3, 0x05, 0xb8, - 0x3f, 0x66, 0x28, 0x34, 0x74, 0x96, 0x91, 0x26, 0x1a, 0xbe, 0xeb, 0x9e, 0x41, 0x46, 0x71, 0xb2, 0xce, 0x2b, 0xe9, - 0x56, 0x9f, 0xb5, 0x91, 0x30, 0xf7, 0x10, 0xfd, 0x2a, 0x06, 0x8f, 0x72, 0x9f, 0xd7, 0x46, 0x27, 0xd3, 0x32, 0xd2, - 0xee, 0xfc, 0xa4, 0x5e, 0x65, 0xa9, 0xd6, 0x61, 0xfb, 0x0c, 0x7b, 0x6b, 0x4c, 0x7a, 0x13, 0x52, 0xc3, 0x48, 0x7c, - 0x3a, 0xa3, 0x46, 0x08, 0x68, 0xcb, 0xf1, 0xf7, 0xf8, 0x0c, 0x43, 0x53, 0x60, 0xa9, 0xe2, 0x16, 0x76, 0xc3, 0xd7, - 0x7c, 0xb2, 0x6a, 0x01, 0x88, 0x60, 0xe5, 0xeb, 0x5d, 0xbc, 0x12, 0xea, 0x33, 0x6d, 0x06, 0x80, 0x2c, 0x28, 0xe5, - 0x8e, 0x9f, 0x52, 0xe9, 0x60, 0x89, 0xa2, 0xed, 0xe5, 0xf4, 0x8d, 0x8e, 0x8d, 0x1f, 0xd2, 0x73, 0x01, 0xdb, 0x85, - 0xfc, 0xd6, 0xbd, 0x7a, 0x89, 0x8a, 0xd4, 0xb6, 0x59, 0x0f, 0xf0, 0xe5, 0x06, 0x4d, 0xc2, 0x08, 0xca, 0x94, 0x29, - 0x80, 0xc1, 0x4d, 0x35, 0x0a, 0x26, 0xad, 0x46, 0xc2, 0x96, 0x7a, 0x92, 0xe5, 0xa6, 0x0f, 0x4e, 0x75, 0x8f, 0xa0, - 0x47, 0x3b, 0x9c, 0xb4, 0xec, 0xd7, 0x0a, 0x8e, 0x4e, 0xae, 0x86, 0xa8, 0x99, 0xf7, 0xda, 0x8e, 0x0c, 0x29, 0x97, - 0x61, 0x20, 0x98, 0x72, 0xcc, 0xd3, 0x63, 0xeb, 0x19, 0x11, 0x3d, 0x70, 0xf6, 0x99, 0x6e, 0xd5, 0x95, 0x04, 0x44, - 0xc7, 0xaf, 0x9f, 0xbc, 0xba, 0x8a, 0x2f, 0x0d, 0x8a, 0x52, 0xc3, 0x22, 0x46, 0x99, 0xf6, 0x55, 0x12, 0x06, 0xef, - 0x97, 0xf7, 0x3f, 0xa9, 0x2c, 0xb5, 0xdf, 0x83, 0xad, 0x15, 0x55, 0xfd, 0x52, 0xf2, 0xa2, 0x29, 0xc0, 0xba, 0xcf, - 0x12, 0x05, 0x72, 0xbf, 0xb7, 0x69, 0xe6, 0x9b, 0xa8, 0x71, 0xb3, 0x61, 0xbd, 0x71, 0xdd, 0x2e, 0xb5, 0x25, 0x3b, - 0xb2, 0x12, 0x39, 0xb3, 0x18, 0xcc, 0xf8, 0x51, 0x61, 0x50, 0x1a, 0xb6, 0xa8, 0x4a, 0xc5, 0xef, 0x8d, 0x08, 0x4e, - 0x1d, 0xab, 0x0a, 0x63, 0x1a, 0x30, 0xdb, 0x8a, 0x5a, 0x83, 0x3a, 0x28, 0xa5, 0xad, 0x89, 0xc2, 0xf6, 0x1b, 0x2b, - 0xa8, 0xf9, 0xfd, 0x4f, 0x63, 0xc8, 0xd7, 0x94, 0x82, 0x4a, 0x02, 0x76, 0x06, 0x8d, 0x9e, 0x2a, 0x61, 0x20, 0x05, - 0xc1, 0x13, 0xa0, 0x7c, 0x11, 0x35, 0x56, 0xfb, 0x7d, 0x75, 0x6a, 0x8c, 0xb6, 0x80, 0xd0, 0x42, 0x7a, 0x74, 0xd9, - 0xc7, 0x6d, 0xad, 0x03, 0x89, 0x07, 0x27, 0xd8, 0xce, 0xd5, 0x35, 0x1a, 0x09, 0xcd, 0x1f, 0x1a, 0x0d, 0x78, 0x4d, - 0x2b, 0x50, 0xa8, 0xe7, 0x38, 0x1a, 0x3a, 0x3b, 0xa4, 0x20, 0x62, 0x83, 0x16, 0xf6, 0xdd, 0xf3, 0xa1, 0xd9, 0xd7, - 0x8b, 0x64, 0x49, 0x6a, 0x2a, 0xdd, 0xe7, 0x6e, 0x09, 0x59, 0xab, 0x0e, 0x65, 0xe5, 0x01, 0x8e, 0x17, 0x4a, 0xe6, - 0xef, 0x30, 0xa9, 0x51, 0x1a, 0x13, 0x1a, 0x23, 0x16, 0xb0, 0x24, 0x68, 0xaf, 0x07, 0xea, 0x97, 0x41, 0xa8, 0x70, - 0xa6, 0x27, 0x12, 0x9f, 0x52, 0xae, 0x3e, 0x2d, 0x48, 0x3d, 0x2d, 0x98, 0x03, 0xbd, 0xf4, 0xad, 0xfc, 0xca, 0xc6, - 0x47, 0xfb, 0x7b, 0xd7, 0x5c, 0x58, 0xc7, 0x10, 0x0c, 0x5b, 0xf8, 0xcd, 0xa9, 0x29, 0x00, 0x1b, 0x9e, 0xe8, 0xb2, - 0x7c, 0xa3, 0x26, 0x32, 0x8f, 0x43, 0x12, 0x81, 0x64, 0xbb, 0xb9, 0xb9, 0x8d, 0x60, 0xdb, 0x5b, 0xa8, 0x0d, 0xf5, - 0x97, 0xb7, 0xdd, 0xef, 0x19, 0x5e, 0xee, 0xc9, 0xbd, 0x9b, 0x36, 0x94, 0x3f, 0xdc, 0xbf, 0x4a, 0xfe, 0xaf, 0x2a, - 0xb9, 0xdf, 0x2a, 0xb3, 0x6e, 0x8b, 0xf7, 0xbb, 0x8e, 0x5b, 0x8e, 0xd1, 0x20, 0xb0, 0xa6, 0xc0, 0x40, 0x7a, 0xd2, - 0x98, 0x26, 0x3a, 0xa4, 0x32, 0x63, 0x06, 0x8f, 0x2e, 0x40, 0x73, 0x98, 0xce, 0xf3, 0x18, 0x80, 0x03, 0xfc, 0x23, - 0x8f, 0x50, 0xff, 0x74, 0x5e, 0x04, 0x67, 0xc1, 0xa0, 0x1c, 0x04, 0xfa, 0x13, 0xd7, 0x9c, 0x60, 0x09, 0x3a, 0xb7, - 0x98, 0x41, 0xb0, 0x49, 0x6b, 0xe6, 0x10, 0x1f, 0x27, 0xd3, 0xc1, 0x20, 0x26, 0x5b, 0x00, 0xe9, 0x8b, 0x97, 0xd6, - 0x39, 0xa8, 0xd0, 0x0b, 0xb2, 0x55, 0x77, 0xd1, 0xac, 0xd8, 0xab, 0x76, 0x9a, 0xf7, 0xfb, 0xf9, 0xa2, 0x1c, 0x04, - 0x8d, 0x0a, 0x0b, 0xe3, 0xfd, 0x47, 0x9b, 0x5f, 0x1a, 0x9d, 0x34, 0xc1, 0x30, 0xb5, 0x27, 0xa8, 0x5e, 0xf1, 0x34, - 0xa3, 0x8d, 0xdb, 0xb1, 0x52, 0xbe, 0x80, 0x28, 0x1e, 0x18, 0xb2, 0x56, 0xde, 0xbd, 0x83, 0xd7, 0xe5, 0xc6, 0x9b, - 0x23, 0x0a, 0xb0, 0x9b, 0xc2, 0x38, 0xa9, 0xb9, 0xe8, 0xa2, 0x26, 0x9e, 0xc1, 0x4e, 0x57, 0x6f, 0x25, 0x5a, 0x8d, - 0xf7, 0xe2, 0x7d, 0xb3, 0xf1, 0x37, 0xf2, 0x40, 0x97, 0x79, 0x70, 0x01, 0x88, 0xb3, 0x07, 0x71, 0x75, 0x80, 0xa5, - 0x1e, 0x04, 0x03, 0x8b, 0x1c, 0xd2, 0xae, 0x56, 0x0f, 0x45, 0xa4, 0xce, 0x63, 0x30, 0x60, 0x32, 0x0d, 0xa9, 0xc9, - 0xb4, 0x57, 0x28, 0x48, 0x1b, 0x6b, 0x2d, 0xa0, 0x0d, 0x87, 0xc5, 0x9e, 0xdd, 0xb0, 0x3b, 0xdd, 0x3a, 0x14, 0x4a, - 0x18, 0xbd, 0xba, 0x6e, 0x1e, 0x6a, 0x0d, 0x4f, 0x04, 0x3d, 0xa8, 0x46, 0xfb, 0xe9, 0xa1, 0x3c, 0x69, 0x8f, 0x05, - 0xb8, 0xe8, 0xe1, 0xcb, 0x17, 0x02, 0x2f, 0xda, 0x7b, 0xc8, 0x73, 0xe6, 0x53, 0xe5, 0x83, 0xd8, 0x70, 0xcb, 0xf0, - 0xa1, 0x7d, 0x7c, 0x2b, 0x90, 0x49, 0xdd, 0xd1, 0xd4, 0xd6, 0xee, 0x68, 0x1c, 0x13, 0xe8, 0x37, 0xe5, 0x28, 0x65, - 0x62, 0x6a, 0x59, 0xb1, 0x59, 0x2f, 0x57, 0xde, 0x50, 0x29, 0x9b, 0xad, 0xda, 0x9c, 0x5f, 0xda, 0x48, 0xe8, 0xf7, - 0xb5, 0x3b, 0x10, 0xbe, 0x51, 0xeb, 0x0d, 0x79, 0xd9, 0x10, 0xb1, 0x1c, 0x62, 0x06, 0x8e, 0x17, 0x52, 0xb9, 0x76, - 0x17, 0x4d, 0x55, 0xdd, 0xde, 0x56, 0x2e, 0x68, 0x89, 0xb7, 0x52, 0x60, 0x15, 0xa9, 0xd3, 0xeb, 0xa9, 0xc4, 0xfb, - 0x3e, 0x8a, 0xed, 0x47, 0xc0, 0x36, 0x36, 0x8e, 0xc6, 0xc6, 0x2d, 0x62, 0x8b, 0xaf, 0xa2, 0x8a, 0x16, 0x1c, 0x20, - 0xb8, 0xdb, 0x92, 0x5a, 0x9a, 0x39, 0xc4, 0x7d, 0xc5, 0x03, 0xb4, 0xef, 0xe2, 0x88, 0x53, 0x01, 0xb6, 0x75, 0xad, - 0x73, 0x56, 0xcb, 0x01, 0x9b, 0x89, 0x9e, 0x7f, 0x5a, 0x35, 0x12, 0x31, 0xac, 0xb2, 0x91, 0xb2, 0x42, 0x7b, 0x50, - 0xba, 0x84, 0x8b, 0x2f, 0xc0, 0xcb, 0xf6, 0xfd, 0xca, 0xee, 0xb3, 0x15, 0xf6, 0x0f, 0xf3, 0xaa, 0x09, 0x1e, 0x79, - 0x8d, 0xb7, 0xf7, 0x30, 0xf1, 0xb9, 0x52, 0x08, 0xaf, 0x52, 0x1a, 0x4a, 0x00, 0x06, 0x49, 0x50, 0xc3, 0x95, 0xb6, - 0xcd, 0x20, 0x95, 0x31, 0xec, 0x7e, 0xf5, 0x56, 0xff, 0xa7, 0x55, 0xb8, 0xa8, 0x64, 0x31, 0x26, 0x81, 0xce, 0xa9, - 0x96, 0x9b, 0x98, 0x82, 0x67, 0xfb, 0xe4, 0x08, 0x14, 0x76, 0x02, 0xb8, 0xa1, 0x84, 0xfd, 0x82, 0xb7, 0xa1, 0x9c, - 0xbd, 0xb4, 0x92, 0x27, 0xb7, 0x2f, 0xa9, 0xa0, 0x09, 0x99, 0x0a, 0xbb, 0x7f, 0x5b, 0x1b, 0xf6, 0x79, 0x28, 0x47, - 0x52, 0xe0, 0xe2, 0xa0, 0x0b, 0x00, 0xfb, 0x83, 0x5c, 0xc6, 0xe6, 0x33, 0xe9, 0xf7, 0xd5, 0xfb, 0x67, 0x79, 0x96, - 0x7c, 0xdc, 0x7b, 0x6f, 0x78, 0x9a, 0x15, 0x03, 0x2a, 0x11, 0x53, 0xeb, 0xaa, 0x18, 0xae, 0xb4, 0x8b, 0x71, 0x83, - 0x64, 0xc4, 0xf7, 0x52, 0x87, 0x18, 0x31, 0xbe, 0xc8, 0x1e, 0x49, 0xc9, 0xe9, 0xaa, 0xee, 0xec, 0xb9, 0x16, 0xcd, - 0xa0, 0x31, 0xdc, 0x9e, 0xf7, 0x92, 0x5e, 0x01, 0x2a, 0x2a, 0x74, 0xcf, 0x02, 0xd7, 0xf0, 0xe6, 0x92, 0x68, 0x6c, - 0xe9, 0x69, 0x4b, 0x34, 0x70, 0xaf, 0x4c, 0x48, 0xaa, 0x8d, 0x03, 0x2c, 0x62, 0x5d, 0x7f, 0x0c, 0x25, 0x00, 0xb5, - 0x1a, 0xa4, 0x57, 0xfa, 0x92, 0x50, 0x95, 0x84, 0x60, 0x74, 0x22, 0xe1, 0x65, 0x40, 0xe3, 0xcc, 0x24, 0x5a, 0xd8, - 0xe0, 0x80, 0x3e, 0xaf, 0x4c, 0xa2, 0xb1, 0x21, 0x0f, 0x68, 0x65, 0xd3, 0x00, 0x06, 0x1f, 0x24, 0x49, 0xf4, 0xd5, - 0xca, 0x24, 0x81, 0xa0, 0x04, 0xe5, 0x1b, 0xf4, 0xe7, 0xd2, 0xf3, 0xb1, 0xfc, 0x97, 0x77, 0x28, 0xfd, 0x10, 0x4a, - 0x90, 0x29, 0xea, 0x8a, 0x69, 0xc6, 0x66, 0x59, 0xb7, 0x31, 0x89, 0xe7, 0x69, 0x77, 0x5b, 0x28, 0x97, 0x2e, 0xf0, - 0x2b, 0xcb, 0x10, 0xc7, 0xfa, 0x59, 0xbc, 0x66, 0x27, 0x21, 0xd7, 0x78, 0xe9, 0xcf, 0xe2, 0x35, 0xce, 0x10, 0xad, - 0x5a, 0x09, 0x44, 0xf9, 0xaf, 0xda, 0xc0, 0x21, 0xee, 0x13, 0x0c, 0x72, 0x51, 0x79, 0x0f, 0x04, 0xf2, 0xb6, 0x82, - 0x88, 0x34, 0xb3, 0xeb, 0x30, 0x22, 0xd5, 0x5e, 0x92, 0xf9, 0xf2, 0x47, 0x99, 0x09, 0xef, 0x1b, 0x78, 0x6c, 0x36, - 0xcb, 0xa6, 0x98, 0x2f, 0x54, 0x30, 0x07, 0xf7, 0x89, 0x8a, 0x4b, 0x51, 0xf9, 0x4f, 0xd8, 0x05, 0x2f, 0xc6, 0x83, - 0xd7, 0x6b, 0x04, 0xd8, 0xaf, 0xfc, 0x27, 0x6f, 0xcc, 0xde, 0x58, 0x37, 0xbe, 0xcc, 0x44, 0x7c, 0xe0, 0xa3, 0x5b, - 0xca, 0x47, 0x77, 0x5e, 0xa6, 0x3f, 0x1a, 0x50, 0x22, 0xa3, 0xb2, 0xe2, 0xeb, 0x35, 0x4f, 0xe7, 0xb7, 0x49, 0x94, - 0x8d, 0x2a, 0x2e, 0x60, 0x7a, 0xc1, 0xf1, 0x2e, 0xd9, 0x9c, 0x67, 0xc9, 0x2b, 0x88, 0x3d, 0xb0, 0x96, 0x0a, 0x8b, - 0x1f, 0x96, 0x99, 0x5a, 0xcc, 0x42, 0x56, 0x52, 0xf0, 0x60, 0x7e, 0x9d, 0x44, 0x6f, 0x56, 0x1e, 0x92, 0x9a, 0x99, - 0xb2, 0x6d, 0xed, 0x08, 0xb5, 0xf1, 0x75, 0xa4, 0x5b, 0x6d, 0x01, 0x00, 0xf7, 0x6c, 0x91, 0x46, 0x92, 0x89, 0xe1, - 0xa4, 0x66, 0xdc, 0xa4, 0x17, 0x98, 0x1a, 0xd7, 0xac, 0xa2, 0x89, 0xb3, 0x90, 0x01, 0xbd, 0x3f, 0xe0, 0xe5, 0xe0, - 0x73, 0x06, 0xf7, 0x1f, 0xb4, 0x06, 0x2e, 0x8f, 0x8b, 0x7e, 0x5f, 0x1e, 0x17, 0xbb, 0x5d, 0x39, 0x8b, 0xfb, 0x7d, - 0x39, 0x8b, 0x0d, 0xff, 0xa0, 0x14, 0xdb, 0xc6, 0xdc, 0x20, 0xa1, 0xb9, 0x84, 0xa8, 0x45, 0x23, 0xf8, 0x43, 0xb3, - 0x9c, 0x8b, 0x28, 0x3f, 0x4e, 0xfa, 0xfd, 0xde, 0x6a, 0x2e, 0x06, 0xf9, 0x30, 0x89, 0xf2, 0x61, 0xe2, 0x39, 0x21, - 0xfe, 0xea, 0x39, 0x21, 0x2a, 0x1a, 0xb8, 0x86, 0x33, 0x03, 0x10, 0x05, 0x7c, 0xfa, 0x47, 0x75, 0x2d, 0x85, 0xae, - 0x25, 0x56, 0xb5, 0x24, 0xba, 0x82, 0x9a, 0x5d, 0x17, 0x61, 0x89, 0xa5, 0xd0, 0x15, 0xfb, 0x63, 0x05, 0x3c, 0x51, - 0xce, 0xab, 0x2d, 0x30, 0xb0, 0x11, 0xde, 0x39, 0x4c, 0x38, 0x89, 0x4d, 0x0d, 0x68, 0xa7, 0xdb, 0x9a, 0x5e, 0xd0, - 0x35, 0xbd, 0x44, 0x7e, 0xf6, 0x02, 0x0c, 0x96, 0x8e, 0x59, 0x3e, 0x1d, 0x0c, 0x2e, 0xc8, 0x9a, 0x95, 0x8b, 0x30, - 0x1e, 0x84, 0x9b, 0x79, 0x3e, 0xbc, 0x88, 0x2e, 0x08, 0xf9, 0xa2, 0x58, 0xd2, 0xde, 0x7a, 0x54, 0x7e, 0xcc, 0x20, - 0xb8, 0x5f, 0x3a, 0x0f, 0x33, 0x13, 0xe7, 0x63, 0x3d, 0xba, 0xa5, 0x6b, 0x88, 0x5f, 0x03, 0x37, 0x12, 0x12, 0x41, - 0x47, 0x2e, 0xe9, 0x9a, 0x6e, 0xa8, 0x34, 0x33, 0x8c, 0x21, 0xba, 0xed, 0x71, 0x92, 0x80, 0x63, 0xb2, 0x2b, 0x3e, - 0x1a, 0xab, 0xc2, 0xbb, 0xbe, 0x23, 0xb4, 0xd7, 0x4b, 0xdc, 0x20, 0x7d, 0xd7, 0x1e, 0x24, 0x60, 0x44, 0x46, 0x6a, - 0xa0, 0xcc, 0xc8, 0x48, 0x6a, 0x26, 0x15, 0x87, 0x24, 0xf6, 0x87, 0x44, 0x8d, 0x43, 0xe2, 0x8f, 0x43, 0xae, 0xc7, - 0x01, 0xb9, 0xfb, 0x15, 0x1b, 0xd3, 0x94, 0x8d, 0xe9, 0x46, 0x8d, 0x0a, 0xbd, 0xa2, 0xe7, 0x9a, 0x3a, 0x9e, 0xb1, - 0xd7, 0x70, 0x60, 0x0f, 0xc2, 0x7c, 0x1e, 0x0f, 0x5f, 0x47, 0xaf, 0x09, 0xf9, 0x42, 0xd2, 0x6b, 0x75, 0x29, 0x83, - 0x30, 0x88, 0x57, 0xe0, 0x5c, 0xea, 0x42, 0x9d, 0x5c, 0x99, 0x1d, 0x87, 0x4f, 0x97, 0x8d, 0xa7, 0x73, 0x88, 0xe8, - 0x83, 0x56, 0x2a, 0xfd, 0x7e, 0x78, 0xc1, 0xca, 0xc5, 0x59, 0x38, 0x26, 0x80, 0xc3, 0xa3, 0x87, 0xf3, 0x62, 0x74, - 0x4b, 0x2f, 0x46, 0x77, 0x04, 0x2c, 0xbc, 0xc6, 0xd3, 0xcd, 0x31, 0x8b, 0xa7, 0x83, 0xc1, 0x06, 0xa9, 0xba, 0xca, - 0xbd, 0x21, 0x4b, 0x7a, 0x81, 0x13, 0x41, 0x80, 0xa1, 0xcf, 0xc4, 0xc6, 0xd0, 0xf0, 0xd7, 0x0c, 0x3e, 0xbe, 0x63, - 0x17, 0xa3, 0x3b, 0x7a, 0xcb, 0x5e, 0xef, 0xc6, 0x53, 0x60, 0xa6, 0xd6, 0xf3, 0xf0, 0xee, 0xf8, 0x72, 0x7e, 0xc9, - 0xee, 0xa2, 0xbb, 0x19, 0x34, 0xf4, 0x8a, 0xdd, 0x21, 0xe0, 0x52, 0xfa, 0x78, 0x35, 0x78, 0x4d, 0x0e, 0x07, 0x83, - 0x94, 0x44, 0xe1, 0x75, 0xe8, 0xb5, 0xf2, 0x35, 0xbd, 0x23, 0x74, 0xcd, 0x6e, 0x71, 0x34, 0x2e, 0x19, 0x7e, 0x70, - 0xce, 0xee, 0xea, 0xeb, 0xd0, 0xdb, 0xcd, 0x89, 0xe8, 0x04, 0x31, 0x42, 0x5f, 0x03, 0x47, 0xb3, 0x5c, 0x98, 0x09, - 0x78, 0x32, 0x17, 0x19, 0x2d, 0x0a, 0xcd, 0x40, 0x9c, 0x95, 0x80, 0x58, 0x12, 0x75, 0xbf, 0xd9, 0xe8, 0x0c, 0x96, - 0x73, 0xbf, 0xdf, 0xab, 0x0c, 0x3d, 0x40, 0xe4, 0xcc, 0x4e, 0x7a, 0xd0, 0xf3, 0xe9, 0x01, 0x7e, 0xa2, 0x57, 0x0d, - 0xe2, 0x64, 0x7e, 0xb7, 0x8a, 0x7e, 0xf5, 0xe8, 0xc3, 0x0f, 0xdd, 0x94, 0x47, 0xe4, 0xff, 0x3e, 0xe5, 0x29, 0xf3, - 0xe8, 0x75, 0xe5, 0x81, 0xe0, 0x79, 0x6b, 0x52, 0x69, 0x24, 0xaa, 0xd1, 0xd9, 0x3a, 0x06, 0x6d, 0x24, 0x6a, 0x1b, - 0xf4, 0x13, 0x5a, 0x58, 0x41, 0x84, 0x9c, 0xa3, 0xe7, 0x60, 0x90, 0x0a, 0xa1, 0x72, 0xd4, 0xa2, 0x44, 0x43, 0x90, - 0x5c, 0x96, 0x5c, 0x85, 0xcf, 0x21, 0x54, 0x9d, 0x3e, 0xce, 0x44, 0xd8, 0xd0, 0xe3, 0xd0, 0x07, 0x80, 0xff, 0x65, - 0x8f, 0x5c, 0x94, 0xfc, 0x12, 0xcf, 0xe6, 0x36, 0xc1, 0x28, 0x58, 0x22, 0x9a, 0xa1, 0x6d, 0x10, 0xfb, 0xb1, 0x24, - 0x58, 0x8f, 0xa4, 0xf1, 0xa8, 0x34, 0x47, 0x84, 0x1f, 0xc5, 0x47, 0xd1, 0xd3, 0xd8, 0x90, 0x48, 0x8e, 0x24, 0x92, - 0x0f, 0x80, 0x70, 0x12, 0xf4, 0x17, 0x77, 0x4d, 0x76, 0x2d, 0x24, 0x06, 0xfd, 0x69, 0xc5, 0xb4, 0xec, 0x5e, 0xf5, - 0xd8, 0x57, 0x04, 0xb9, 0x63, 0xfa, 0x4f, 0xaf, 0x0f, 0xff, 0x5c, 0xe1, 0x0c, 0x5a, 0xcf, 0x17, 0xd5, 0x99, 0xb9, - 0x37, 0xb8, 0x91, 0xd7, 0x65, 0xed, 0xba, 0x7c, 0xc1, 0x0f, 0xf8, 0x6d, 0xc5, 0x45, 0x5a, 0x1e, 0xfc, 0x5c, 0xb5, - 0xf1, 0x9c, 0xca, 0xcd, 0xda, 0xc5, 0x59, 0x51, 0xc6, 0xa9, 0x9e, 0xd4, 0xc5, 0x58, 0xc3, 0x36, 0xfc, 0x1e, 0x51, - 0x57, 0xd2, 0x72, 0xf4, 0x94, 0x72, 0xdd, 0x4c, 0xb9, 0xd8, 0xe4, 0xf9, 0x4f, 0x7b, 0xa9, 0x38, 0xc5, 0xcd, 0x14, - 0xa4, 0x4a, 0x2d, 0x17, 0x50, 0x3d, 0x47, 0x2d, 0x77, 0x4b, 0xb3, 0x03, 0x9c, 0xdb, 0xa6, 0xfa, 0x58, 0x99, 0x5d, - 0x78, 0xc9, 0x8d, 0xfb, 0x93, 0x29, 0xc3, 0x82, 0x51, 0x68, 0xb3, 0xea, 0x4a, 0xdb, 0x17, 0x5a, 0xa7, 0x61, 0xb8, - 0xf2, 0xe3, 0x05, 0xa4, 0x0b, 0x18, 0xc7, 0x8b, 0x92, 0x89, 0x71, 0x7b, 0xf4, 0x56, 0x10, 0x9f, 0xb3, 0x15, 0x08, - 0x98, 0x6b, 0x78, 0xbb, 0xae, 0xa3, 0xed, 0x9e, 0x38, 0x65, 0x54, 0xae, 0x63, 0xf1, 0x7d, 0xbc, 0x36, 0x90, 0xc9, - 0xea, 0x78, 0x6c, 0x8c, 0xe9, 0xf4, 0xef, 0x49, 0xe8, 0x17, 0x42, 0xc1, 0x67, 0xbd, 0xb4, 0xf2, 0xe4, 0xf6, 0xb0, - 0x8c, 0x6b, 0xf4, 0x4a, 0x5c, 0xeb, 0xbe, 0x19, 0x29, 0xa4, 0x1e, 0xf9, 0xaa, 0x29, 0xa0, 0x37, 0x63, 0xdf, 0x4c, - 0x85, 0x79, 0xbb, 0x67, 0xcc, 0x15, 0x82, 0x95, 0x2a, 0xbb, 0x7d, 0xa7, 0xc6, 0x54, 0xcc, 0x60, 0x8a, 0x6d, 0x67, - 0x31, 0xe9, 0x56, 0xfe, 0x69, 0xe7, 0x7e, 0x95, 0x77, 0xb8, 0x2b, 0xea, 0xb7, 0xc0, 0x85, 0x66, 0x45, 0x59, 0xb5, - 0x65, 0xc3, 0xb6, 0xf1, 0x46, 0x16, 0x8a, 0x0d, 0xb0, 0xec, 0xb9, 0x6f, 0xe1, 0x01, 0xe2, 0x26, 0xdc, 0xb3, 0xcb, - 0x1a, 0x6e, 0x0c, 0x9f, 0x57, 0x92, 0xef, 0x4a, 0x63, 0x2e, 0x7d, 0xaa, 0x34, 0x31, 0x9c, 0x2c, 0x47, 0x5c, 0xa4, - 0xcb, 0x3a, 0xb3, 0x6b, 0xe1, 0x13, 0x5e, 0x86, 0x0b, 0xbe, 0x34, 0xba, 0x29, 0x5d, 0x7a, 0xc1, 0x62, 0xdd, 0xe9, - 0xed, 0x5a, 0x63, 0xa5, 0x44, 0xdc, 0x9a, 0x65, 0x02, 0x65, 0x29, 0x6b, 0x25, 0xbc, 0x29, 0x5a, 0xb6, 0x92, 0x46, - 0xde, 0xb3, 0x00, 0xf7, 0xb1, 0x1f, 0x10, 0x13, 0xd9, 0x04, 0x26, 0x45, 0x43, 0x07, 0xb4, 0xab, 0x2e, 0x7c, 0x33, - 0xea, 0xc1, 0x20, 0xb7, 0x24, 0x11, 0x2b, 0x48, 0xb1, 0x82, 0x4d, 0xcd, 0x8a, 0x45, 0xbe, 0xa4, 0x17, 0x4c, 0x2e, - 0xd2, 0x25, 0x5d, 0x33, 0xb9, 0xd8, 0xe0, 0x4d, 0xe8, 0x02, 0x4e, 0x48, 0xb2, 0x8d, 0x95, 0x02, 0xf6, 0x02, 0x2f, - 0x6f, 0x78, 0xa6, 0x6a, 0x5a, 0x76, 0xa9, 0x38, 0xc0, 0xf8, 0xbc, 0x0c, 0xc3, 0x72, 0x78, 0x01, 0xd6, 0x12, 0x87, - 0xe1, 0x7a, 0xc1, 0x97, 0xea, 0x37, 0x04, 0x9c, 0x4f, 0x42, 0xc5, 0x2e, 0xd8, 0xbd, 0x40, 0xa6, 0x57, 0x0b, 0xbe, - 0x54, 0x23, 0xa1, 0x0b, 0xbe, 0xb2, 0xc6, 0x26, 0xb1, 0x27, 0x68, 0x99, 0xc7, 0x8b, 0xf1, 0x32, 0x8a, 0x6b, 0x58, - 0x86, 0xa7, 0x6a, 0x66, 0x5a, 0xf2, 0x9f, 0x44, 0x6d, 0x68, 0xa2, 0x6f, 0xb0, 0x8a, 0xfc, 0xe1, 0xf1, 0xd1, 0x25, - 0x90, 0xb1, 0xb3, 0x2b, 0x99, 0xf9, 0xd0, 0xf7, 0x91, 0xc1, 0x3d, 0x37, 0xe5, 0x8c, 0xab, 0x20, 0x51, 0x06, 0xee, - 0x5e, 0xcd, 0x92, 0xb1, 0x16, 0xe1, 0xfb, 0x47, 0x45, 0xd1, 0x67, 0xd2, 0x34, 0xa0, 0xfb, 0x48, 0x30, 0x07, 0x7a, - 0xaf, 0xd0, 0xe1, 0xb2, 0xda, 0x66, 0x02, 0xfe, 0x22, 0x41, 0x7e, 0x2b, 0xf4, 0xaa, 0xc6, 0xa0, 0x8a, 0x76, 0x11, - 0x4b, 0xff, 0x3e, 0xe2, 0x47, 0xd9, 0xfc, 0xd3, 0xdc, 0xe3, 0x95, 0x84, 0xc1, 0x0f, 0xa9, 0xd9, 0x24, 0xf3, 0xf6, - 0x8a, 0x7d, 0x0f, 0x1d, 0xf5, 0xa8, 0x35, 0xde, 0x57, 0x2f, 0x38, 0x85, 0x18, 0x25, 0x14, 0x9d, 0x04, 0x03, 0xb8, - 0x5d, 0x42, 0x8a, 0xbb, 0xc1, 0x6e, 0x9b, 0xd7, 0xbc, 0x28, 0x38, 0xdf, 0x54, 0x55, 0xe0, 0x07, 0x34, 0x5c, 0x2c, - 0xf7, 0x43, 0x18, 0x8e, 0x69, 0xeb, 0x1a, 0x06, 0x61, 0xc6, 0x30, 0x12, 0x82, 0xd7, 0xbf, 0xe8, 0x2b, 0x9a, 0xc4, - 0xeb, 0xef, 0xf8, 0x5f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x4c, 0x93, 0x02, 0x0a, 0x01, - 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, 0xd4, 0x74, 0x3c, 0x1a, 0xd7, 0xad, 0xce, 0xa8, - 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, 0x69, 0xde, 0xba, 0x87, 0xc0, 0x2b, 0xd3, 0xe2, - 0x9d, 0x07, 0x74, 0x7b, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, 0x4f, 0xae, 0xd8, 0xac, 0xea, 0xa1, 0xf6, 0xde, - 0x8c, 0x50, 0xd0, 0xef, 0x63, 0x0a, 0x74, 0x23, 0xa8, 0xbd, 0xab, 0xfb, 0x8f, 0xe5, 0x3e, 0x87, 0xef, 0x38, 0xcb, - 0x2d, 0x60, 0xa9, 0xc8, 0x5a, 0x81, 0x47, 0x01, 0xea, 0x52, 0x19, 0xc2, 0x16, 0x73, 0x38, 0x54, 0x76, 0xab, 0x56, - 0x43, 0x49, 0x8e, 0xcb, 0x11, 0x38, 0x84, 0x6e, 0xca, 0x41, 0x39, 0x5a, 0x65, 0xd5, 0x7b, 0xfc, 0xad, 0x59, 0x87, - 0x24, 0xbb, 0x8f, 0x75, 0xe0, 0x96, 0x75, 0x98, 0x7e, 0x34, 0x48, 0x01, 0x68, 0xb2, 0x11, 0xb8, 0x04, 0xe0, 0xbd, - 0xfd, 0x47, 0x84, 0x5a, 0x99, 0xde, 0xcb, 0x58, 0xa8, 0xef, 0x1b, 0x49, 0x50, 0x42, 0x33, 0xa1, 0x72, 0x2c, 0x05, - 0xef, 0x3c, 0xd2, 0x39, 0xa9, 0x33, 0xf1, 0x1e, 0xc4, 0x69, 0xe1, 0x03, 0x7b, 0x0b, 0x82, 0x73, 0x16, 0xf4, 0x0e, - 0x6f, 0xb3, 0x5a, 0x6a, 0xa3, 0x07, 0x0a, 0xe0, 0x77, 0x83, 0x3b, 0x04, 0xf9, 0x6a, 0x0c, 0xd7, 0x5a, 0xde, 0x84, - 0x7c, 0x58, 0xd0, 0x23, 0x32, 0xb0, 0xcf, 0x62, 0x18, 0xd3, 0x23, 0x72, 0x6c, 0x9f, 0xa5, 0x1b, 0xc0, 0x81, 0xd4, - 0xa3, 0x4a, 0x8f, 0xa0, 0x41, 0xbf, 0xd9, 0x16, 0x59, 0x92, 0xf5, 0x63, 0x69, 0x14, 0x31, 0x50, 0x25, 0x88, 0xa8, - 0xc5, 0x3f, 0x1f, 0xcc, 0x75, 0x87, 0xb9, 0x40, 0x98, 0x83, 0x01, 0x07, 0x71, 0x1b, 0x84, 0xe6, 0x80, 0xd9, 0xde, - 0x46, 0x82, 0xde, 0x59, 0xc3, 0xcc, 0x8e, 0xfe, 0x70, 0x2b, 0xc1, 0x37, 0x59, 0x6b, 0xd4, 0x79, 0x71, 0x08, 0x04, - 0xc1, 0x9b, 0x42, 0x55, 0x7b, 0xd5, 0x03, 0x1b, 0x6f, 0xd5, 0x8f, 0xdd, 0x6e, 0x3c, 0x15, 0xee, 0xda, 0x2f, 0x28, - 0x9c, 0x7c, 0x4a, 0xfe, 0xf5, 0xde, 0x64, 0x70, 0x60, 0x64, 0xf8, 0xd2, 0xdb, 0xbf, 0xf0, 0xb5, 0x96, 0xee, 0x89, - 0x41, 0x49, 0x1e, 0x1f, 0x29, 0xfa, 0x77, 0xaf, 0xac, 0x7c, 0x6a, 0xa7, 0x7f, 0xb7, 0x33, 0xeb, 0xf3, 0x78, 0x34, - 0xd9, 0xed, 0x7a, 0xda, 0xc0, 0x95, 0x6a, 0x15, 0x02, 0x76, 0xa1, 0x24, 0x87, 0x47, 0x10, 0x15, 0xa1, 0x19, 0x77, - 0xb3, 0x6c, 0x48, 0x64, 0xfc, 0x38, 0x9d, 0x65, 0x43, 0xb0, 0xc3, 0xbd, 0xa8, 0xc4, 0xe5, 0xa8, 0xb5, 0xc1, 0xe9, - 0x59, 0x12, 0x42, 0x28, 0x07, 0xac, 0xec, 0x56, 0xfd, 0xb9, 0x53, 0x66, 0x42, 0x6a, 0xb2, 0xba, 0x9d, 0xd2, 0x3d, - 0x4c, 0xf3, 0x03, 0x33, 0x82, 0x03, 0xee, 0xed, 0xaf, 0xfa, 0x63, 0x98, 0x64, 0x9a, 0x9c, 0x22, 0xf9, 0x45, 0x7a, - 0x0a, 0x49, 0x7b, 0xf4, 0x54, 0x11, 0xc0, 0x09, 0xb5, 0x1f, 0xc3, 0x6f, 0x18, 0xf7, 0xef, 0x9a, 0xaf, 0xdd, 0x54, - 0x44, 0x4f, 0x28, 0x96, 0xa9, 0xc9, 0x69, 0x92, 0x15, 0x09, 0x44, 0x6d, 0x54, 0xcd, 0x88, 0xbe, 0x72, 0x31, 0x1f, - 0x15, 0xe1, 0xf3, 0x6a, 0xfd, 0x9f, 0x21, 0x7c, 0x46, 0xe1, 0x06, 0x70, 0x79, 0xc5, 0xe5, 0x79, 0xf8, 0xf4, 0x09, - 0x3d, 0x98, 0x7c, 0x7d, 0x44, 0x0f, 0x8e, 0xbe, 0x7a, 0x4a, 0x00, 0x16, 0xed, 0xf2, 0x3c, 0x3c, 0x7a, 0xfa, 0x94, - 0x1e, 0x7c, 0xfb, 0x2d, 0x3d, 0x98, 0x7c, 0x75, 0xd4, 0x48, 0x9b, 0x3c, 0xfd, 0x96, 0x1e, 0x7c, 0xfd, 0xa4, 0x91, - 0x76, 0x34, 0x7e, 0x4a, 0x0f, 0xbe, 0xf9, 0xda, 0xa4, 0xfd, 0x0d, 0xb2, 0x7d, 0x7b, 0x84, 0xff, 0x99, 0xb4, 0xc9, - 0xd3, 0xaf, 0xe8, 0xc1, 0x64, 0x0c, 0x95, 0x3c, 0x75, 0x95, 0x8c, 0x27, 0xf0, 0xf1, 0x57, 0xf0, 0xdf, 0xdf, 0x48, - 0xb0, 0xa4, 0x95, 0x64, 0xb9, 0x40, 0xfd, 0x19, 0x8a, 0x38, 0x51, 0x35, 0x91, 0xf0, 0x10, 0x33, 0xab, 0x6f, 0xe2, - 0x30, 0x20, 0x2e, 0x1d, 0x0a, 0xa2, 0x07, 0xe3, 0xd1, 0x53, 0x12, 0xf8, 0xf0, 0x74, 0x37, 0x3e, 0xc8, 0x58, 0x2e, - 0x16, 0xd9, 0x17, 0xb9, 0x89, 0xad, 0xe0, 0x01, 0x58, 0x7d, 0xf4, 0x73, 0x55, 0x72, 0x91, 0x7d, 0x51, 0xc9, 0xfd, - 0x5c, 0xbf, 0xb5, 0x00, 0xe5, 0xfd, 0x55, 0xcb, 0x6e, 0x0a, 0x15, 0x3a, 0xad, 0x35, 0xfa, 0xec, 0x23, 0xa6, 0x0f, - 0x06, 0xde, 0x0d, 0xfb, 0xef, 0x7b, 0xe5, 0xb4, 0xbe, 0xd1, 0x28, 0xd4, 0xa8, 0x3c, 0x24, 0x6c, 0x06, 0x45, 0x0f, - 0x06, 0xc0, 0x13, 0x78, 0xb8, 0x6f, 0xff, 0x66, 0x19, 0x1f, 0x3b, 0xca, 0xf8, 0x19, 0x65, 0x08, 0x68, 0xd4, 0xc3, - 0xec, 0xa6, 0x87, 0x8d, 0x6e, 0xf5, 0x92, 0xa5, 0x3a, 0x99, 0x9a, 0x9e, 0xc1, 0xbe, 0xd6, 0xb5, 0x3c, 0x30, 0xa2, - 0x68, 0x79, 0x71, 0x90, 0xf2, 0x79, 0xc5, 0xfe, 0xbe, 0x42, 0xf5, 0x56, 0xd4, 0x78, 0x23, 0xb3, 0x79, 0xc5, 0xbe, - 0x37, 0x6f, 0x80, 0x9b, 0x61, 0xbf, 0xa9, 0x27, 0x3f, 0x70, 0x06, 0x97, 0xb6, 0x3d, 0xca, 0xc4, 0x08, 0xb0, 0x02, - 0x32, 0x70, 0xe0, 0x01, 0xd0, 0x41, 0x7f, 0xb4, 0x77, 0x3b, 0x95, 0xd2, 0xec, 0xb3, 0x85, 0x01, 0x34, 0xcc, 0xdb, - 0xc4, 0x95, 0xfd, 0xaf, 0x86, 0xbc, 0x04, 0x85, 0x5b, 0xcd, 0xf2, 0xf6, 0x0a, 0x43, 0x08, 0xc1, 0x1f, 0x57, 0x0c, - 0x00, 0x07, 0x02, 0x0c, 0xc6, 0x5a, 0x06, 0xd4, 0x6c, 0xf9, 0x68, 0xcb, 0x95, 0x7a, 0x12, 0x38, 0x83, 0x0b, 0x59, - 0x24, 0xfc, 0xad, 0x16, 0xfb, 0xa3, 0xf5, 0xa3, 0xef, 0xdb, 0xe3, 0xc1, 0xda, 0xf7, 0xf8, 0x48, 0x7f, 0xd6, 0xb8, - 0x0e, 0x6c, 0x5b, 0xbe, 0xf1, 0xa2, 0xb6, 0x12, 0x8f, 0x12, 0x78, 0x03, 0x13, 0x91, 0xc2, 0x20, 0xd5, 0x02, 0xc7, - 0xa0, 0xbc, 0xb1, 0x10, 0x4b, 0xd5, 0xd5, 0x0d, 0xb6, 0x20, 0x32, 0x04, 0x0f, 0xb7, 0x7f, 0xad, 0x54, 0xe0, 0xa8, - 0x7e, 0x9f, 0x4b, 0xdf, 0xed, 0xc9, 0xd8, 0x91, 0xe3, 0xd4, 0x4f, 0x85, 0x83, 0xff, 0x26, 0x75, 0x6d, 0x2c, 0x57, - 0x52, 0x66, 0x59, 0x16, 0x36, 0x0b, 0xb5, 0xdc, 0xa3, 0xf2, 0x20, 0xf9, 0x42, 0x0e, 0x91, 0x2c, 0x30, 0x0a, 0x05, - 0x19, 0x4e, 0xa8, 0x18, 0x6d, 0x44, 0xb9, 0xca, 0x2e, 0xaa, 0x70, 0xab, 0x14, 0xca, 0x9c, 0xa2, 0x6f, 0x37, 0x38, - 0x90, 0x90, 0x28, 0x2b, 0xdf, 0xc4, 0x6f, 0x42, 0x04, 0xab, 0xe3, 0xda, 0x16, 0x8a, 0x7b, 0xfb, 0x93, 0xa7, 0x5d, - 0xfc, 0x91, 0x71, 0x01, 0x75, 0xb1, 0x98, 0x86, 0x13, 0x1b, 0xfb, 0xc6, 0x7d, 0x61, 0x35, 0x3d, 0x00, 0xf5, 0x5d, - 0x2a, 0x31, 0x82, 0xfa, 0xca, 0xd8, 0xc7, 0xf6, 0x18, 0x93, 0x73, 0x88, 0x35, 0xac, 0x72, 0x66, 0xaa, 0x6f, 0x84, - 0xcd, 0x00, 0xb8, 0x11, 0x5a, 0xa3, 0x20, 0xf0, 0x78, 0x15, 0xe2, 0x79, 0xa9, 0xc2, 0xb7, 0x66, 0x84, 0x8e, 0xc1, - 0x9b, 0xca, 0x36, 0x32, 0x93, 0xbe, 0x60, 0xd0, 0x1c, 0xdb, 0x3a, 0x0a, 0xab, 0xad, 0x2c, 0x9b, 0x01, 0xdc, 0x40, - 0x76, 0x6c, 0x2e, 0x9e, 0xf3, 0x6a, 0x91, 0x2d, 0x23, 0x13, 0x14, 0x70, 0x25, 0x2c, 0x83, 0xf6, 0xd7, 0x3d, 0xb2, - 0x1d, 0x87, 0xd0, 0x0d, 0xf7, 0x11, 0x8c, 0xa7, 0xdd, 0x14, 0xac, 0x20, 0x1a, 0x21, 0x1e, 0x66, 0xcc, 0xe2, 0x7b, - 0xa5, 0x29, 0x4f, 0x55, 0x4b, 0x20, 0x70, 0x14, 0x42, 0x5d, 0xec, 0x1b, 0x25, 0xb8, 0x4c, 0x8d, 0x60, 0x06, 0x7b, - 0x76, 0xa4, 0xb6, 0x4b, 0xce, 0xe9, 0x50, 0x4d, 0x69, 0xa9, 0xa7, 0x54, 0xfb, 0x1a, 0x8a, 0x45, 0x89, 0x1e, 0x7a, - 0xe0, 0x7a, 0xa0, 0x1d, 0xf2, 0x4a, 0x3a, 0x31, 0x11, 0x74, 0x5a, 0x6d, 0xc2, 0xce, 0x8d, 0x74, 0xcb, 0x6a, 0xe4, - 0x1d, 0x43, 0xb3, 0x23, 0x5e, 0xf8, 0x81, 0xba, 0x00, 0x22, 0xe4, 0xde, 0x16, 0x99, 0x23, 0x9a, 0x65, 0xe5, 0x4b, - 0x28, 0x8b, 0x23, 0xb6, 0xae, 0x80, 0x6b, 0x29, 0x98, 0x5c, 0xf2, 0x88, 0xa7, 0x88, 0x08, 0x78, 0xa2, 0xb4, 0xeb, - 0x7b, 0x2d, 0x21, 0x34, 0x4b, 0x81, 0xb8, 0xb9, 0x28, 0xce, 0xb5, 0x0d, 0x64, 0x01, 0xf4, 0xed, 0xa7, 0xec, 0xca, - 0x0b, 0x07, 0xbb, 0xbd, 0xca, 0xc4, 0x73, 0x7e, 0x91, 0x09, 0x9e, 0x22, 0xd8, 0xd5, 0xad, 0x79, 0xe0, 0x8e, 0x6d, - 0x03, 0xcb, 0xb7, 0xef, 0x60, 0xc1, 0x94, 0xa1, 0x56, 0x4a, 0x64, 0x22, 0x12, 0x90, 0xd9, 0x67, 0xee, 0x5e, 0x67, - 0xe2, 0x75, 0x7c, 0x0b, 0xde, 0x14, 0x0d, 0x7e, 0x7a, 0x74, 0x8e, 0x5f, 0x22, 0x92, 0x28, 0xc4, 0xb0, 0xc5, 0x88, - 0x58, 0x88, 0x1c, 0x3b, 0x26, 0x94, 0x2b, 0x41, 0x6b, 0x6b, 0x08, 0xbc, 0xf8, 0xd3, 0xaa, 0x7b, 0x57, 0x99, 0x30, - 0xf6, 0x19, 0x57, 0xf1, 0x2d, 0x2b, 0x15, 0x98, 0x05, 0xc6, 0xb9, 0x6f, 0x4b, 0x49, 0xae, 0x32, 0x61, 0x04, 0x24, - 0x57, 0xf1, 0x2d, 0x6d, 0xca, 0x38, 0xb4, 0x15, 0x9d, 0x17, 0xe7, 0x77, 0x7f, 0xf8, 0x25, 0x86, 0x5a, 0x19, 0xf7, - 0xfb, 0x20, 0x31, 0x93, 0xb6, 0x29, 0x73, 0x19, 0x49, 0x8d, 0x16, 0x52, 0x51, 0x3e, 0x98, 0x90, 0xfd, 0x95, 0x6a, - 0x19, 0x51, 0xfb, 0x55, 0x28, 0xe6, 0xe3, 0x68, 0x42, 0xe8, 0xa4, 0x63, 0xbd, 0x9b, 0xd6, 0x42, 0xa6, 0xd1, 0xd3, - 0xc8, 0xf3, 0xe9, 0x2c, 0x58, 0x35, 0x2d, 0x8e, 0x19, 0x9f, 0x16, 0x83, 0x01, 0xd1, 0x2e, 0x85, 0x5b, 0xac, 0x07, - 0x4c, 0x69, 0x5c, 0xbc, 0x35, 0xd3, 0xea, 0x97, 0x52, 0x85, 0xa4, 0xf7, 0x0c, 0x48, 0x32, 0xe9, 0x82, 0xdd, 0x82, - 0x44, 0xd1, 0xf3, 0xbf, 0x53, 0x5b, 0x70, 0xdf, 0x83, 0xb1, 0x19, 0xdd, 0xd7, 0x33, 0xfe, 0x43, 0x6d, 0x0b, 0xa2, - 0x3e, 0x95, 0xac, 0xd7, 0x91, 0xa8, 0x42, 0x2e, 0xc2, 0xcf, 0x8e, 0x86, 0x18, 0xa2, 0xda, 0x63, 0x81, 0xd8, 0x5c, - 0x9d, 0xf3, 0x02, 0xa7, 0x9f, 0xb9, 0xcb, 0x15, 0x6c, 0x0b, 0x5a, 0x19, 0x1a, 0xf5, 0x26, 0x7e, 0x13, 0xd9, 0xcb, - 0x82, 0x2e, 0xf2, 0x39, 0x0a, 0x59, 0xf3, 0x30, 0xac, 0x86, 0xed, 0x41, 0x24, 0x87, 0xed, 0x49, 0x68, 0x34, 0x06, - 0x16, 0xc8, 0x1e, 0x8d, 0xc0, 0x45, 0x68, 0xe5, 0x6f, 0xc7, 0xe0, 0xc2, 0x65, 0x11, 0x59, 0x86, 0x3a, 0x7e, 0x53, - 0xbb, 0x09, 0xaa, 0x57, 0xe8, 0x34, 0x85, 0x55, 0x29, 0x93, 0x7c, 0xf8, 0xf5, 0x52, 0x16, 0x98, 0xc9, 0xeb, 0xb2, - 0x47, 0x5f, 0xdb, 0xed, 0x1d, 0x98, 0x82, 0x75, 0x9f, 0xbc, 0xaf, 0x1f, 0x77, 0xf6, 0x04, 0x8c, 0x62, 0x55, 0x8e, - 0xa6, 0x90, 0x52, 0xfb, 0xa0, 0xd4, 0x1f, 0xc3, 0x95, 0xd0, 0x1c, 0xbb, 0x05, 0x4c, 0x02, 0xf6, 0x19, 0x52, 0x3d, - 0xa6, 0x1d, 0xfb, 0x1c, 0x6d, 0x61, 0x49, 0xc0, 0xe1, 0x1f, 0x65, 0xb2, 0xf6, 0xaf, 0xee, 0x22, 0x6d, 0x86, 0x6c, - 0x59, 0x2c, 0x81, 0xcf, 0x87, 0x5d, 0x1b, 0x95, 0x28, 0x9b, 0x88, 0x24, 0x85, 0x2d, 0x8f, 0x41, 0xda, 0xa3, 0x98, - 0xae, 0x0b, 0x9e, 0x64, 0x28, 0xa5, 0x48, 0xb4, 0x4f, 0x70, 0x0e, 0x6f, 0x70, 0x3f, 0xaa, 0x80, 0xf0, 0x2a, 0xe4, - 0x74, 0x94, 0x52, 0x6d, 0x01, 0xa3, 0xa8, 0x07, 0x88, 0xf2, 0x32, 0x90, 0xe3, 0xed, 0x76, 0x13, 0xba, 0x66, 0xab, - 0xe1, 0x84, 0x22, 0x29, 0xb9, 0xc4, 0x72, 0xaf, 0x40, 0xe7, 0x71, 0xce, 0x7a, 0x2f, 0x00, 0x8b, 0xe0, 0x0c, 0xfe, - 0xc6, 0x84, 0x5e, 0xc3, 0xdf, 0x9c, 0xd0, 0xd7, 0x2c, 0xbc, 0x1a, 0x5e, 0x92, 0xc3, 0x30, 0x1d, 0x4c, 0x94, 0x60, - 0xec, 0x8e, 0xad, 0xca, 0x50, 0x25, 0xae, 0x0f, 0x2f, 0xc8, 0xe3, 0x0b, 0x7a, 0x4b, 0x6f, 0xe8, 0x29, 0x7d, 0x0b, - 0x84, 0xff, 0xee, 0x78, 0xc2, 0x87, 0x93, 0x27, 0xfd, 0x7e, 0xef, 0xbc, 0xdf, 0xef, 0x9d, 0x19, 0x03, 0x0a, 0xbd, - 0x8b, 0x2e, 0x6b, 0xaa, 0x7f, 0x5d, 0xd5, 0xcb, 0xe9, 0x5b, 0xb5, 0x71, 0x13, 0x9e, 0xe5, 0xe1, 0xd5, 0xe1, 0x1d, - 0x19, 0xe2, 0xe3, 0x45, 0x2e, 0x65, 0x11, 0x5e, 0x1e, 0xde, 0x11, 0xfa, 0x76, 0x06, 0x7a, 0x53, 0xac, 0xef, 0xed, - 0xe3, 0x3b, 0x5d, 0x1b, 0xa1, 0x2f, 0xc2, 0x04, 0xb6, 0xc9, 0x2d, 0xb3, 0x77, 0xed, 0xc9, 0x18, 0x62, 0x99, 0xdc, - 0x79, 0xe5, 0xdd, 0x3d, 0xbe, 0x25, 0x87, 0xb7, 0xe0, 0x29, 0x6a, 0xc9, 0xdf, 0x3c, 0xbc, 0x61, 0xad, 0x1a, 0x1e, - 0xdf, 0xd1, 0xd3, 0x56, 0x23, 0x1e, 0xdf, 0x91, 0x28, 0xbc, 0x61, 0x97, 0xf4, 0x94, 0x5d, 0x11, 0x7a, 0xde, 0xef, - 0x9f, 0xf5, 0xfb, 0xb2, 0xdf, 0xff, 0x7b, 0x1c, 0x86, 0xf1, 0xb0, 0x20, 0x87, 0x92, 0xde, 0x1d, 0x4e, 0xf8, 0x57, - 0x64, 0x1e, 0xea, 0xe6, 0xab, 0x05, 0x67, 0x55, 0xde, 0x2a, 0xd7, 0x1d, 0x05, 0x6b, 0x85, 0x3b, 0xa6, 0x9e, 0xde, - 0xd2, 0x1b, 0x56, 0xd0, 0x53, 0x16, 0x93, 0xe8, 0x1a, 0x5a, 0x71, 0x3e, 0x2f, 0xa2, 0x1b, 0x7a, 0xca, 0xce, 0xe6, - 0x71, 0x74, 0x4a, 0xdf, 0xb2, 0x7c, 0x38, 0x81, 0xbc, 0xa7, 0xc3, 0x1b, 0x72, 0xf8, 0x96, 0x44, 0xe1, 0x5b, 0xfd, - 0xfb, 0x8e, 0x5e, 0xf2, 0xf0, 0x2d, 0xf5, 0xaa, 0x79, 0x4b, 0x4c, 0xf5, 0x8d, 0xda, 0xdf, 0x92, 0xc8, 0x1f, 0xcc, - 0xb7, 0xd6, 0x9e, 0xe6, 0x91, 0xa3, 0x8d, 0x69, 0x19, 0x82, 0xbe, 0xb9, 0x0c, 0x6f, 0x08, 0x99, 0x36, 0xc7, 0x0e, - 0x06, 0x74, 0xfe, 0x28, 0x4a, 0x08, 0xbd, 0xf1, 0x4b, 0xbd, 0xc1, 0x31, 0x34, 0x23, 0xa4, 0xd2, 0x4e, 0x31, 0x0d, - 0xd7, 0xc1, 0x2b, 0x0d, 0xd6, 0x71, 0xde, 0xef, 0x87, 0x9b, 0x7e, 0x1f, 0x22, 0xdd, 0x17, 0x73, 0x13, 0xdb, 0xcd, - 0x91, 0x4d, 0x7a, 0x03, 0xda, 0xff, 0x57, 0x83, 0x01, 0x74, 0xc6, 0x2b, 0x29, 0xbc, 0x19, 0xbc, 0x7a, 0x7c, 0x47, - 0x54, 0x1d, 0x05, 0x15, 0x32, 0x2c, 0xe8, 0x6b, 0x9a, 0x01, 0xe0, 0xd7, 0xab, 0xc1, 0x80, 0x44, 0xe6, 0x33, 0x32, - 0x7d, 0x75, 0xfc, 0x76, 0x3a, 0x18, 0xbc, 0x32, 0xdb, 0xe4, 0x0d, 0xbb, 0xa7, 0x14, 0x58, 0x7f, 0x67, 0xfd, 0xfe, - 0x9b, 0x59, 0x4c, 0xce, 0x0b, 0x1e, 0x7f, 0x9c, 0x36, 0xdb, 0xf2, 0xc6, 0x45, 0x55, 0x3b, 0xeb, 0xf7, 0x37, 0xfd, - 0xfe, 0x29, 0x60, 0x17, 0xcd, 0x9d, 0xaf, 0x27, 0x48, 0x5b, 0x16, 0x8e, 0x22, 0x69, 0x92, 0x43, 0x63, 0x68, 0x5b, - 0xac, 0xda, 0x36, 0xef, 0xc8, 0xc0, 0xe2, 0xa8, 0x59, 0x51, 0x5c, 0x93, 0x28, 0xec, 0x9d, 0xed, 0x76, 0xa7, 0x8c, - 0xb1, 0x98, 0x80, 0xf4, 0xc3, 0x7f, 0x7d, 0x5a, 0x37, 0x62, 0x88, 0x09, 0x89, 0xcc, 0xe6, 0x76, 0x65, 0x0f, 0x81, - 0x88, 0xc3, 0xa6, 0x7f, 0x6f, 0xee, 0xe5, 0xa2, 0x76, 0x7c, 0xeb, 0xcf, 0x00, 0x42, 0x24, 0x59, 0xc8, 0xe7, 0x38, - 0x06, 0x65, 0x06, 0x40, 0xe6, 0x91, 0x9a, 0x79, 0x09, 0x20, 0xc0, 0x64, 0xb7, 0x1b, 0x8d, 0xc7, 0x13, 0x5a, 0xb0, - 0xd1, 0xdf, 0x9e, 0x3e, 0xae, 0x1e, 0x87, 0x41, 0x30, 0xc8, 0x48, 0x4b, 0x4f, 0x61, 0x17, 0x6b, 0x75, 0x08, 0x46, - 0xf0, 0x9a, 0x7d, 0xbc, 0xce, 0x3e, 0x9b, 0x7d, 0x44, 0xc2, 0xda, 0x60, 0x1c, 0xb9, 0x48, 0x5b, 0x7a, 0xbb, 0x7b, - 0x18, 0x4c, 0x2e, 0xd2, 0x4f, 0xb0, 0x9d, 0x3e, 0xff, 0xe6, 0xc1, 0x78, 0xc2, 0xc1, 0xe8, 0x2e, 0x0a, 0xfa, 0x4c, - 0xdb, 0xed, 0x2a, 0xff, 0x12, 0xf8, 0x06, 0x53, 0x41, 0xc7, 0x66, 0x59, 0xb8, 0x41, 0x45, 0xd4, 0xd1, 0x32, 0xa8, - 0x6a, 0x65, 0x3b, 0x07, 0xd4, 0x12, 0xab, 0x32, 0x71, 0x0b, 0x0c, 0x43, 0x86, 0xba, 0xdc, 0x93, 0xea, 0x5f, 0xbc, - 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, 0x04, 0xb7, 0x56, 0x22, 0x89, 0x35, - 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0x59, 0xc9, 0xf8, 0xbc, 0x8c, 0x12, 0x1a, 0xc3, 0x83, 0x64, 0x62, 0x2e, 0xa3, - 0x04, 0xed, 0x13, 0x5d, 0x84, 0xc1, 0x3f, 0x01, 0xb3, 0x9f, 0xe6, 0xf0, 0x57, 0x92, 0x69, 0x72, 0x0c, 0x01, 0x21, - 0x8e, 0xc7, 0xf3, 0x38, 0x1c, 0x93, 0x28, 0x99, 0xc1, 0x13, 0xfc, 0x57, 0x84, 0x63, 0x52, 0xeb, 0x3b, 0x8c, 0x54, - 0x97, 0xdb, 0x84, 0x01, 0x5c, 0xd9, 0x78, 0x3e, 0x89, 0xac, 0x74, 0x57, 0x3e, 0x1e, 0x8d, 0x9f, 0x92, 0x69, 0x1c, - 0xca, 0x41, 0x42, 0x28, 0x78, 0xf7, 0x86, 0xe5, 0x30, 0xd1, 0xf0, 0x6c, 0xc0, 0xe6, 0x95, 0x8e, 0xcd, 0x93, 0x70, - 0x02, 0xc2, 0x30, 0x21, 0xc7, 0x7a, 0x0f, 0x52, 0x8a, 0x3e, 0xcf, 0xb1, 0x9f, 0xfa, 0x08, 0xc2, 0xec, 0xa8, 0xa5, - 0xe2, 0x6b, 0x00, 0xba, 0xc4, 0xc1, 0xa1, 0xf6, 0xcc, 0x17, 0xf3, 0xb0, 0xf4, 0xa8, 0x94, 0xa9, 0xee, 0x50, 0x34, - 0x28, 0xbf, 0x69, 0xd0, 0xa1, 0x20, 0x83, 0x09, 0x2d, 0x67, 0x13, 0xfe, 0x15, 0x04, 0xf0, 0x68, 0x44, 0xfc, 0x52, - 0x38, 0x31, 0x10, 0x5e, 0x05, 0x19, 0xa8, 0xb4, 0x56, 0x8d, 0x19, 0xd9, 0x8a, 0x0f, 0x20, 0x4c, 0xca, 0xc1, 0x8d, - 0xdc, 0xe4, 0x29, 0x44, 0x05, 0xdb, 0xe4, 0xd5, 0xc1, 0x25, 0x58, 0xb2, 0xc7, 0x15, 0xc4, 0x09, 0xdb, 0xac, 0x01, - 0x3b, 0xf7, 0xd1, 0xb6, 0xac, 0x0f, 0xd4, 0x77, 0x07, 0xd8, 0x72, 0x78, 0x55, 0xc9, 0x83, 0xc9, 0x78, 0x3c, 0x1e, - 0xfd, 0x0e, 0x47, 0x07, 0x10, 0x5a, 0x12, 0x19, 0x3e, 0x19, 0xa0, 0x71, 0x37, 0x15, 0xf7, 0xc6, 0x85, 0xa2, 0xac, - 0x74, 0x32, 0x21, 0x20, 0x7e, 0x36, 0x7d, 0x83, 0x7d, 0xc5, 0x75, 0xfc, 0x93, 0xfd, 0x4f, 0xcc, 0x8a, 0x56, 0x2b, - 0x75, 0xf4, 0xee, 0xed, 0xe9, 0xab, 0x0f, 0xaf, 0x7e, 0x7d, 0x71, 0xf6, 0xea, 0xcd, 0xcb, 0x57, 0x6f, 0x5e, 0x7d, - 0xf8, 0xe7, 0x03, 0x0c, 0xb6, 0x6f, 0x2b, 0x62, 0xc7, 0xde, 0xbb, 0xc7, 0x78, 0xb5, 0xf8, 0xc2, 0xd9, 0x23, 0x77, - 0x8b, 0x05, 0xd8, 0x04, 0xc3, 0x2d, 0x08, 0xaa, 0x19, 0x8d, 0x4a, 0xdf, 0x13, 0x90, 0xd1, 0xa8, 0x90, 0x8d, 0x87, - 0x15, 0x5b, 0x21, 0x17, 0xef, 0x18, 0x0e, 0x3e, 0xb2, 0xbf, 0x15, 0x67, 0xc2, 0xed, 0x68, 0x6b, 0x56, 0x04, 0x7c, - 0xbe, 0x36, 0xa2, 0xf2, 0xb8, 0x10, 0xb5, 0xb7, 0xed, 0x73, 0x48, 0xa8, 0x47, 0xe4, 0x3a, 0x78, 0xdf, 0x06, 0xd9, - 0xe3, 0x23, 0xef, 0x49, 0x79, 0x86, 0xfa, 0x1c, 0x0d, 0x1f, 0x35, 0x9e, 0xd1, 0x89, 0xb9, 0x36, 0x3a, 0xd4, 0xb3, - 0x02, 0xf6, 0xb7, 0x12, 0x63, 0x43, 0xb4, 0x87, 0x14, 0xb1, 0x3e, 0x9c, 0xee, 0x77, 0xff, 0x66, 0xf4, 0x3d, 0x1c, - 0x3f, 0x4a, 0x35, 0x81, 0xb4, 0x28, 0x50, 0xba, 0x32, 0xe4, 0xb6, 0xe7, 0x61, 0x61, 0x7e, 0x86, 0x0d, 0x02, 0x68, - 0x2f, 0x3b, 0x96, 0x04, 0x9a, 0xc5, 0x6b, 0x5d, 0xff, 0xbc, 0x7c, 0x99, 0x68, 0xe7, 0x8b, 0x6f, 0x21, 0xc4, 0xb0, - 0x7f, 0x45, 0x68, 0x4c, 0xb8, 0x9b, 0x64, 0x77, 0x69, 0x31, 0xf7, 0xaa, 0xab, 0x18, 0x8f, 0xbb, 0x7b, 0xae, 0x14, - 0xcd, 0x5b, 0x17, 0xd8, 0x03, 0x35, 0xaf, 0xe3, 0x25, 0x0b, 0x01, 0x9b, 0xf1, 0xd0, 0x2e, 0x12, 0xe7, 0xf7, 0x4e, - 0x27, 0xe4, 0xf0, 0x68, 0xca, 0x87, 0xac, 0xa4, 0x62, 0xc0, 0xca, 0x7a, 0x8f, 0x9a, 0xf3, 0x36, 0x21, 0x17, 0xfb, - 0x34, 0x5c, 0x0c, 0xf9, 0x43, 0x97, 0xa4, 0x0f, 0xbc, 0xe1, 0x50, 0x6d, 0x9b, 0x8b, 0x21, 0x4d, 0x39, 0xdd, 0xa7, - 0x32, 0x20, 0x44, 0xba, 0x8a, 0x2b, 0x52, 0xeb, 0xa3, 0x2a, 0x75, 0x92, 0x8e, 0xeb, 0x6c, 0xfb, 0x89, 0x4b, 0xb6, - 0xba, 0x5d, 0xfb, 0xd7, 0xea, 0xf6, 0x85, 0x19, 0xc8, 0xdf, 0x1f, 0x88, 0x6a, 0x62, 0x20, 0xba, 0x80, 0x0a, 0xfe, - 0x01, 0x5e, 0x9e, 0x3c, 0xd2, 0x0a, 0xd0, 0xfb, 0xce, 0x8e, 0xae, 0x3d, 0xde, 0x98, 0xc5, 0xd6, 0x12, 0xe7, 0xac, - 0xf2, 0x9d, 0xe5, 0x55, 0xd9, 0x0a, 0x5d, 0x47, 0xb0, 0x9f, 0xc3, 0x8e, 0xbe, 0x7b, 0xdb, 0x00, 0x88, 0x52, 0x58, - 0xb9, 0xb3, 0x5f, 0x78, 0x67, 0xbf, 0xb0, 0x67, 0xbf, 0xdd, 0x04, 0xca, 0x87, 0x15, 0x5a, 0xf6, 0x52, 0x8a, 0xca, - 0x34, 0x79, 0xdc, 0xd4, 0x65, 0x21, 0x2d, 0xe6, 0x87, 0x96, 0x76, 0x3d, 0x19, 0x53, 0x89, 0xea, 0x91, 0x1f, 0xb0, - 0x55, 0x87, 0x25, 0x79, 0xf8, 0x9e, 0xf9, 0x3f, 0x7b, 0x83, 0xbc, 0xef, 0x6e, 0xf7, 0x7f, 0x73, 0xa1, 0x83, 0xdb, - 0x5a, 0x2a, 0x3c, 0x75, 0x75, 0x5c, 0xe0, 0x5d, 0x2d, 0x7d, 0xf8, 0xae, 0xf6, 0x2e, 0xd3, 0xcb, 0xae, 0x02, 0xd4, - 0x20, 0xb1, 0xb9, 0xe2, 0x45, 0x96, 0xd4, 0x56, 0xa1, 0xf1, 0x96, 0x43, 0x68, 0x0f, 0xef, 0xe0, 0x02, 0x39, 0x2c, - 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0xfd, 0x96, 0x87, 0x19, 0x19, 0xf8, 0x12, 0xbf, 0x52, 0xfa, 0xe2, - 0xe2, 0xc3, 0xbd, 0xcc, 0x04, 0xbd, 0x4a, 0x6c, 0x76, 0x29, 0xdb, 0x31, 0x3f, 0xfc, 0x2f, 0x30, 0x1a, 0x84, 0xd7, - 0x96, 0xec, 0x50, 0x74, 0xcc, 0x72, 0x05, 0x47, 0x6d, 0xe9, 0xca, 0x2c, 0x5b, 0xd7, 0xcf, 0x6a, 0x98, 0xe9, 0x33, - 0xe5, 0x2d, 0xc8, 0xbe, 0x90, 0xbb, 0x9f, 0xea, 0x8a, 0x05, 0x99, 0x4d, 0xc6, 0x53, 0x22, 0x06, 0x83, 0x56, 0xf2, - 0x31, 0x26, 0x0f, 0x87, 0x7b, 0xcc, 0xa5, 0xd0, 0xfd, 0xf0, 0xfa, 0x00, 0xf5, 0x35, 0xb6, 0x24, 0xd9, 0x56, 0xec, - 0x4f, 0x30, 0x8b, 0x05, 0xe2, 0xe8, 0xe0, 0x17, 0x17, 0x4b, 0x00, 0x59, 0x86, 0x65, 0xa6, 0x85, 0x45, 0x65, 0xaa, - 0x7c, 0x64, 0x0b, 0x26, 0x8f, 0xc7, 0x73, 0xbf, 0xe7, 0x8e, 0xc1, 0x21, 0x24, 0x9a, 0x58, 0xe3, 0x17, 0x3f, 0x0b, - 0xc6, 0x71, 0x28, 0x67, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, 0x57, 0x89, 0x6a, 0x98, 0x90, 0xc7, - 0x05, 0x39, 0x2c, 0xe8, 0xca, 0x1f, 0x4b, 0x4c, 0x3f, 0x8c, 0x0f, 0x27, 0x63, 0xf2, 0x38, 0x7e, 0x3c, 0x31, 0x70, - 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x22, 0x87, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, 0xcc, 0xaf, 0x24, 0x19, 0xac, 0x06, - 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xe6, 0x98, 0x4f, 0x89, 0x68, 0xdc, 0x18, 0x36, 0xf4, 0x2a, 0xfe, - 0x43, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, 0x22, 0x8d, 0xd2, 0x9a, 0xd0, 0x74, - 0xc6, 0x26, 0xe3, 0x79, 0xca, 0xd2, 0xe3, 0xc9, 0xd3, 0xf9, 0xe4, 0x69, 0x74, 0x34, 0x8e, 0xd2, 0xc1, 0x00, 0x92, - 0x8f, 0xc6, 0xe0, 0x62, 0x07, 0xbf, 0xd9, 0x11, 0x0c, 0xdd, 0x0c, 0x59, 0xc2, 0x02, 0x9a, 0xf6, 0x79, 0x4d, 0xd2, - 0xc3, 0x79, 0xa1, 0x7a, 0x12, 0xdf, 0xd2, 0x8d, 0xe7, 0xe0, 0xe2, 0xb7, 0xf0, 0xc2, 0xb5, 0xf0, 0x62, 0xbf, 0x85, - 0x42, 0x93, 0xed, 0x42, 0xfe, 0xff, 0xb8, 0x61, 0xdc, 0x77, 0x97, 0x30, 0x8b, 0xeb, 0x3a, 0x1b, 0xad, 0x0b, 0x59, - 0x49, 0xb8, 0x4d, 0x28, 0x51, 0xd8, 0x28, 0x5e, 0xaf, 0x73, 0xed, 0x22, 0xb6, 0xa8, 0x28, 0x80, 0xbb, 0x40, 0x9c, - 0x62, 0x60, 0xa1, 0x8d, 0x81, 0xdc, 0x5f, 0xbc, 0x90, 0xcc, 0xaa, 0x7d, 0xcc, 0x3d, 0xf2, 0x8f, 0x10, 0x8c, 0x51, - 0xc5, 0x6c, 0x3c, 0x57, 0x58, 0x17, 0x9f, 0x92, 0xf7, 0xfe, 0x1b, 0x47, 0x91, 0x3d, 0x9a, 0x41, 0x4f, 0x10, 0x39, - 0x8f, 0x38, 0x7b, 0x32, 0x79, 0x19, 0xb8, 0x9f, 0xc1, 0x4a, 0x7f, 0xdd, 0x6d, 0xc6, 0xda, 0xf6, 0xe8, 0x5e, 0x18, - 0xa1, 0xe8, 0x5f, 0xf8, 0xce, 0xd4, 0x0b, 0xb8, 0x84, 0x6a, 0x60, 0x37, 0x97, 0x97, 0xbc, 0x04, 0x10, 0xa1, 0x4c, - 0xf4, 0xfb, 0xbd, 0x3f, 0x0c, 0x34, 0x69, 0xc9, 0x8b, 0xd7, 0x99, 0xb0, 0xce, 0x38, 0xd0, 0x54, 0xa0, 0xfe, 0x1f, - 0x2b, 0xfb, 0x4c, 0xc7, 0x64, 0xee, 0x3f, 0x0e, 0x27, 0x24, 0x6a, 0xbe, 0x26, 0x9f, 0x38, 0x4d, 0x3f, 0x71, 0x45, - 0xfb, 0x0f, 0x64, 0xe6, 0x86, 0x43, 0x86, 0xfa, 0x4b, 0xc7, 0x3c, 0x19, 0xbd, 0x4e, 0xcc, 0x66, 0x82, 0x55, 0x73, - 0x88, 0xc2, 0x5e, 0xc0, 0x83, 0xba, 0x96, 0xc5, 0x53, 0x98, 0x7d, 0x50, 0x23, 0x8a, 0x63, 0x36, 0x9e, 0x87, 0x32, - 0x9c, 0x80, 0x7d, 0xef, 0x64, 0x0c, 0xf7, 0x01, 0x19, 0x7e, 0xac, 0x42, 0xec, 0x1c, 0xa4, 0x7d, 0xac, 0x50, 0x31, - 0x01, 0x10, 0x81, 0x90, 0xb7, 0xdf, 0x97, 0x2a, 0x09, 0x5f, 0x97, 0x98, 0x52, 0xa8, 0x0f, 0xfe, 0x13, 0xa9, 0xba, - 0x63, 0xfa, 0xd5, 0xfa, 0xf1, 0x67, 0x42, 0xf1, 0xe9, 0x2e, 0x25, 0xbe, 0x85, 0xe0, 0xce, 0x12, 0x74, 0x10, 0x15, - 0x9a, 0xb1, 0x3d, 0xcc, 0xef, 0x8a, 0xfb, 0xf9, 0x5d, 0xf1, 0xff, 0x8e, 0xdf, 0x15, 0x0f, 0x31, 0x86, 0x95, 0x85, - 0x86, 0x9f, 0x07, 0xe3, 0x20, 0xfa, 0xcf, 0xf9, 0xc4, 0x7b, 0x79, 0xea, 0xab, 0x4c, 0x4c, 0xef, 0x61, 0x9a, 0x7d, - 0x82, 0x82, 0xb0, 0x8a, 0xfb, 0xf4, 0x64, 0x53, 0xd9, 0x5b, 0x2b, 0x19, 0x62, 0x9e, 0x07, 0x58, 0xa3, 0xb0, 0xf2, - 0x80, 0xee, 0x51, 0xb5, 0x41, 0x9c, 0x08, 0x1e, 0xc6, 0xcc, 0x4a, 0xdf, 0x77, 0x3b, 0xa3, 0xc2, 0x7c, 0x90, 0x8b, - 0x82, 0xec, 0xe6, 0xe3, 0xf9, 0x38, 0x0a, 0xb1, 0x01, 0xff, 0x31, 0x63, 0xd5, 0x90, 0xcd, 0x77, 0x32, 0x52, 0x7b, - 0x26, 0x4f, 0x93, 0x7d, 0xd2, 0x3b, 0xe0, 0x1d, 0xf2, 0xf3, 0xfa, 0x63, 0x58, 0x48, 0xc3, 0x6f, 0xc9, 0xcb, 0xb8, - 0xc8, 0xaa, 0xd5, 0x55, 0x96, 0x20, 0xd3, 0x05, 0x2f, 0x3e, 0x9b, 0xe9, 0xf2, 0x3e, 0xd6, 0x07, 0x8c, 0xa7, 0x14, - 0xaf, 0x1b, 0xa2, 0xf4, 0x4d, 0xcb, 0xb3, 0x42, 0x5d, 0x9e, 0x54, 0xcc, 0xf6, 0xac, 0x04, 0xa7, 0x53, 0x30, 0xc1, - 0xd7, 0x3f, 0x5d, 0xef, 0x63, 0xc0, 0x05, 0x85, 0x9a, 0xd3, 0x42, 0xae, 0x0d, 0x96, 0x93, 0x85, 0xee, 0x04, 0xcc, - 0x50, 0x29, 0xf0, 0x02, 0x05, 0x7f, 0xd1, 0xc0, 0x88, 0xbe, 0x74, 0xbf, 0xc9, 0xc0, 0x20, 0x5d, 0x9a, 0x13, 0x61, - 0xec, 0xb8, 0x9d, 0x22, 0x6d, 0x45, 0x39, 0xe3, 0xec, 0xbd, 0xba, 0x52, 0x80, 0x01, 0xde, 0xf6, 0x26, 0x3a, 0x4f, - 0xd0, 0x6b, 0x41, 0xe9, 0xbc, 0x81, 0xbb, 0x59, 0x45, 0x46, 0xb8, 0xf8, 0xb8, 0xf2, 0x58, 0x70, 0xcf, 0x7e, 0x21, - 0x96, 0x46, 0x33, 0x0d, 0xc6, 0x6c, 0x5e, 0xb0, 0x40, 0xa1, 0x02, 0x05, 0x96, 0x73, 0x6d, 0x69, 0x5a, 0x0d, 0xf9, - 0xe1, 0x11, 0x5a, 0x9b, 0x56, 0x03, 0x7e, 0x78, 0x54, 0x47, 0xd9, 0x31, 0x64, 0x99, 0xf9, 0x19, 0xd4, 0xeb, 0x3a, - 0x32, 0x29, 0x26, 0xbb, 0x5f, 0x5f, 0xea, 0x8f, 0xea, 0x16, 0x5c, 0x3f, 0x00, 0x01, 0x6c, 0x00, 0x0e, 0x81, 0x6a, - 0xb0, 0x34, 0x22, 0x58, 0x94, 0x29, 0xb4, 0xaf, 0xa1, 0xf7, 0x46, 0xc3, 0x7f, 0x81, 0xbb, 0x88, 0x5c, 0xfb, 0x9f, - 0x20, 0xf0, 0x57, 0x94, 0x69, 0x65, 0x8a, 0xff, 0x89, 0x56, 0xaf, 0x50, 0xce, 0x9a, 0xd6, 0x7c, 0x10, 0xad, 0x89, - 0x50, 0xcd, 0x18, 0x82, 0x7f, 0x2b, 0xcb, 0xb4, 0xa5, 0xaa, 0x52, 0x1f, 0x1a, 0xaf, 0xb5, 0xc2, 0x59, 0x3e, 0x8e, - 0xbc, 0xd7, 0x18, 0x3a, 0x36, 0x71, 0x96, 0x72, 0x2a, 0x75, 0xfe, 0xd7, 0xa1, 0x8c, 0x1c, 0xe0, 0x74, 0xc2, 0xc6, - 0xd3, 0xe4, 0x58, 0x4e, 0x13, 0x07, 0x99, 0x9f, 0x33, 0x8c, 0xac, 0x6a, 0x40, 0x58, 0x94, 0x0d, 0xa5, 0x2d, 0xc0, - 0x24, 0x27, 0x84, 0x4c, 0x31, 0x14, 0x45, 0x3e, 0xd2, 0xfd, 0xb0, 0xde, 0xac, 0xee, 0x8b, 0x77, 0x1a, 0xe0, 0x34, - 0x4c, 0x20, 0x10, 0x78, 0x11, 0xdf, 0x64, 0xe2, 0x12, 0x3c, 0x86, 0x07, 0xf0, 0x25, 0xb8, 0xc9, 0xa5, 0xec, 0xb7, - 0x2a, 0xcc, 0x71, 0x6d, 0x01, 0x83, 0x06, 0xab, 0x07, 0xd1, 0xe1, 0x52, 0xda, 0xec, 0x2a, 0x40, 0x6c, 0x4c, 0x21, - 0x96, 0x05, 0xdb, 0x58, 0xf6, 0xec, 0x7b, 0xd5, 0x34, 0xb4, 0x4e, 0x38, 0x11, 0x97, 0x39, 0x44, 0x51, 0x19, 0xc4, - 0xe0, 0x8e, 0xe4, 0xf1, 0x79, 0x8f, 0x44, 0x78, 0x41, 0xc0, 0xad, 0x2c, 0x96, 0xe1, 0x9a, 0xae, 0x46, 0xb7, 0x74, - 0x33, 0xba, 0xa1, 0x63, 0x3a, 0xf9, 0x66, 0x0c, 0x16, 0xd9, 0x3a, 0xf5, 0x8e, 0x6e, 0x46, 0x2b, 0xfa, 0xed, 0x98, - 0x1e, 0xfd, 0x0d, 0x4c, 0xf8, 0xf0, 0x30, 0xa1, 0x17, 0xe0, 0xd8, 0x45, 0x6a, 0xf4, 0xd4, 0xf4, 0x0d, 0x0e, 0xab, - 0x51, 0x3e, 0xe4, 0xa3, 0x9c, 0xf2, 0x51, 0x31, 0xac, 0x46, 0xe0, 0xe9, 0x58, 0x0d, 0xf9, 0xa8, 0xa2, 0x7c, 0x74, - 0x3e, 0xac, 0x46, 0xe7, 0xa4, 0xd9, 0xf4, 0x57, 0x15, 0xbf, 0x2a, 0x59, 0x0a, 0xdb, 0x02, 0x96, 0xaf, 0xe7, 0x15, - 0x95, 0xfa, 0xab, 0xda, 0x9c, 0xcc, 0x96, 0xb3, 0xb7, 0xd7, 0x5d, 0x4e, 0x2c, 0x1e, 0xb7, 0x4d, 0x87, 0xab, 0x2f, - 0x27, 0xea, 0xa4, 0x57, 0xc8, 0x0f, 0xe3, 0xa9, 0x50, 0xe7, 0x10, 0x98, 0x49, 0xcc, 0xc3, 0x98, 0x61, 0x33, 0x75, - 0x1a, 0x28, 0x70, 0xb2, 0x91, 0xe7, 0xa2, 0x98, 0x8d, 0x72, 0x0a, 0xef, 0x63, 0x42, 0x22, 0x01, 0x67, 0xd5, 0xac, - 0x1a, 0x15, 0x10, 0x73, 0x84, 0x85, 0xf8, 0x08, 0xfd, 0x52, 0x1f, 0x79, 0x48, 0xe0, 0x19, 0xf6, 0xb5, 0x18, 0xc4, - 0x70, 0xc4, 0xdb, 0xca, 0xaa, 0x79, 0x98, 0x40, 0x65, 0xd5, 0xb0, 0x34, 0x95, 0x15, 0x34, 0x1b, 0x55, 0x7e, 0x65, - 0x15, 0x8e, 0x51, 0x42, 0x48, 0x54, 0xea, 0xca, 0x40, 0x7d, 0x92, 0xb0, 0xb0, 0xd4, 0x95, 0x9d, 0xab, 0x8f, 0xce, - 0xfd, 0xca, 0xce, 0xc1, 0x85, 0x74, 0x90, 0xf8, 0x57, 0xa9, 0x3c, 0x6d, 0x5f, 0x07, 0x1b, 0xab, 0x8a, 0x6e, 0xf9, - 0x6d, 0x55, 0xc4, 0x51, 0x49, 0x5d, 0x0c, 0x68, 0x5c, 0x18, 0x91, 0xa4, 0x7a, 0x8d, 0x82, 0x3f, 0x24, 0x88, 0x4a, - 0x63, 0xf0, 0xea, 0x4c, 0xba, 0x56, 0x6a, 0x45, 0xc5, 0xa0, 0x1c, 0x14, 0x70, 0x7f, 0xca, 0x5b, 0x0b, 0xe9, 0x7b, - 0x88, 0xa8, 0x0c, 0xe5, 0x0d, 0xfe, 0x81, 0xc1, 0x93, 0xd9, 0x3a, 0x0d, 0x93, 0xd1, 0x1d, 0x8d, 0x47, 0x2b, 0x84, - 0x83, 0x61, 0x9b, 0x54, 0xe1, 0xad, 0x5f, 0x40, 0xfa, 0x2d, 0x8d, 0x47, 0x37, 0x34, 0xb5, 0x36, 0xa7, 0x06, 0xea, - 0xaa, 0x37, 0xa6, 0xb7, 0x11, 0xbc, 0xbe, 0x8b, 0x56, 0x14, 0xb6, 0xd2, 0x49, 0x9e, 0x5d, 0x8a, 0x28, 0xa5, 0x88, - 0x40, 0xb8, 0x41, 0xe4, 0xc0, 0x95, 0x46, 0x1b, 0xdc, 0x0c, 0xa0, 0x0c, 0x0d, 0x17, 0xb8, 0x1a, 0xc4, 0xa3, 0x95, - 0x47, 0xa6, 0x56, 0xfa, 0x22, 0x8b, 0xf0, 0xd1, 0xce, 0x46, 0x4b, 0xf1, 0x8c, 0x58, 0x18, 0x57, 0x30, 0x84, 0xba, - 0xb0, 0xd2, 0x14, 0x24, 0x5d, 0xe0, 0xc8, 0x5e, 0x58, 0x54, 0xe1, 0x16, 0x4c, 0x8b, 0xee, 0xc0, 0x3c, 0x0a, 0x14, - 0x0e, 0x2e, 0x41, 0xfa, 0x09, 0x65, 0x3b, 0x47, 0x69, 0x72, 0x78, 0x13, 0x94, 0xee, 0x4d, 0x10, 0xd2, 0xae, 0x6e, - 0xb2, 0x25, 0x7d, 0x83, 0xed, 0x3d, 0x3a, 0x15, 0x15, 0x54, 0x9f, 0x5b, 0x30, 0x59, 0xb2, 0x41, 0xd8, 0x12, 0xa6, - 0x67, 0x7a, 0x03, 0xd8, 0xd3, 0x87, 0x47, 0x7b, 0xf3, 0x5d, 0xcc, 0xff, 0x3a, 0x2c, 0xa3, 0xb1, 0xb2, 0xe0, 0xcd, - 0x2d, 0xb1, 0x5b, 0xb1, 0xf1, 0x74, 0x75, 0x5c, 0x4e, 0x57, 0x48, 0xec, 0x0c, 0xdd, 0x62, 0x7c, 0xb1, 0x5a, 0xd2, - 0x04, 0xcf, 0x36, 0x56, 0x2d, 0x56, 0x06, 0x2d, 0x25, 0x65, 0xb8, 0xde, 0x56, 0xe8, 0xff, 0xaf, 0x2e, 0x7e, 0x29, - 0xc0, 0x4b, 0x30, 0x16, 0x00, 0xc2, 0x3d, 0x98, 0x16, 0xa4, 0x36, 0xca, 0xc6, 0x2a, 0x0d, 0x53, 0x5c, 0x04, 0x26, - 0xa5, 0xdf, 0x0f, 0x73, 0x96, 0x12, 0x0f, 0x3a, 0xd4, 0x9d, 0xda, 0xa9, 0x2f, 0x04, 0x01, 0x1e, 0x49, 0x9d, 0x63, - 0x93, 0x6f, 0xc6, 0xf3, 0x40, 0x0d, 0x44, 0x10, 0x65, 0xc7, 0xf8, 0x88, 0x81, 0x8b, 0x22, 0x1d, 0xb7, 0xd3, 0x15, - 0x71, 0xb1, 0x7f, 0xcc, 0x42, 0x9c, 0x24, 0xcc, 0x35, 0xcf, 0x86, 0xac, 0x8a, 0x30, 0x41, 0x17, 0x06, 0x66, 0x79, - 0x43, 0x56, 0x1d, 0x1e, 0x41, 0xa4, 0x56, 0x5b, 0xc6, 0xba, 0xab, 0x8c, 0x6f, 0x01, 0xc8, 0x9a, 0x31, 0x76, 0xf4, - 0xb7, 0xf1, 0x5c, 0x7d, 0x13, 0x85, 0x7c, 0x76, 0xf4, 0x37, 0x48, 0x3e, 0xfe, 0x16, 0x99, 0x39, 0x48, 0x6e, 0x14, - 0x74, 0xd9, 0x9c, 0x75, 0x0d, 0xa5, 0x89, 0x6b, 0xaf, 0xd4, 0x6b, 0x4f, 0x9a, 0xb5, 0x57, 0xa0, 0x3b, 0xb5, 0xe1, - 0x3d, 0x94, 0xed, 0x2c, 0x98, 0xa0, 0xa3, 0xd9, 0x1d, 0xe8, 0xe0, 0x9d, 0x22, 0xe8, 0x45, 0x12, 0x1a, 0x8f, 0x50, - 0x65, 0xd4, 0x0b, 0x3b, 0xb2, 0x9b, 0x75, 0xc9, 0x3c, 0x03, 0xe6, 0xd8, 0x9e, 0x43, 0x62, 0x98, 0xab, 0x83, 0x3a, - 0x65, 0xe5, 0x30, 0xc7, 0x03, 0x78, 0xc3, 0xe4, 0x50, 0x0c, 0x72, 0x8d, 0xf2, 0x7d, 0xc1, 0x8a, 0x61, 0x39, 0xc8, - 0x35, 0x37, 0x33, 0x6d, 0xc6, 0xa6, 0x4d, 0x74, 0x78, 0xe6, 0x35, 0x9b, 0xad, 0x7b, 0xc0, 0xc7, 0x82, 0x27, 0xb3, - 0xef, 0xf9, 0xf8, 0x1a, 0x38, 0x99, 0xed, 0x6d, 0xb4, 0xa2, 0x77, 0x51, 0x4a, 0x6f, 0xa2, 0x0d, 0x5d, 0x45, 0x17, - 0xc6, 0xc4, 0x38, 0xa9, 0xe1, 0x1c, 0x80, 0x56, 0x01, 0x24, 0x9e, 0xfa, 0xf5, 0x9e, 0x27, 0x55, 0xb8, 0xa2, 0x29, - 0xb8, 0x0d, 0xfb, 0xf6, 0x99, 0x57, 0xbe, 0x44, 0x6a, 0x8b, 0x18, 0x6b, 0xd6, 0x50, 0x71, 0xeb, 0xad, 0xfb, 0x48, - 0xd4, 0xb0, 0x73, 0x5d, 0x6c, 0xa2, 0x6a, 0x38, 0x99, 0x96, 0x80, 0xd8, 0x5a, 0x0e, 0x87, 0xee, 0x08, 0xd9, 0x3f, - 0x7e, 0x74, 0xa0, 0xe7, 0x9e, 0xb4, 0xd8, 0xb6, 0x2d, 0x7f, 0x60, 0x08, 0x53, 0xfa, 0xe9, 0x23, 0x1f, 0x10, 0x2b, - 0x2e, 0xe1, 0x6c, 0x04, 0xea, 0x68, 0x85, 0x4e, 0xbf, 0x55, 0x61, 0xa1, 0x0f, 0xf0, 0xed, 0x6d, 0x94, 0xd0, 0xbb, - 0x28, 0xf7, 0xc8, 0xda, 0xaa, 0x66, 0x72, 0x7a, 0x96, 0x85, 0xbc, 0x7d, 0xa0, 0x97, 0x4b, 0x00, 0xd1, 0x1a, 0xc4, - 0xbe, 0xd4, 0xf5, 0x08, 0x9c, 0x86, 0xd0, 0x24, 0x34, 0x82, 0xab, 0x0a, 0xc2, 0x08, 0xb8, 0x92, 0xf0, 0x37, 0x98, - 0xa8, 0xc0, 0x17, 0xe0, 0x22, 0x93, 0xa6, 0x39, 0x0f, 0x6a, 0x7f, 0x24, 0x4f, 0x8b, 0xb6, 0xb7, 0x2b, 0x8c, 0x26, - 0x18, 0x7b, 0xa2, 0x7d, 0x1e, 0x29, 0x47, 0x71, 0x91, 0x84, 0xd9, 0xe8, 0x56, 0x9d, 0xe7, 0x34, 0x1b, 0xdd, 0xe9, - 0x5f, 0x15, 0x1d, 0xd3, 0xef, 0x74, 0x40, 0x1b, 0x25, 0x7d, 0xeb, 0x38, 0x1b, 0xd0, 0x7a, 0xb1, 0x34, 0xfe, 0xd7, - 0x72, 0x74, 0x4b, 0xe5, 0xe8, 0xce, 0xb7, 0xa4, 0x9a, 0x4c, 0x8b, 0x63, 0x81, 0x86, 0x54, 0x9d, 0xdf, 0x17, 0xc0, - 0xcf, 0x95, 0xc6, 0x77, 0xda, 0x7c, 0xef, 0xb5, 0xff, 0xbc, 0x93, 0x27, 0x50, 0x2c, 0x51, 0xc1, 0xaa, 0x11, 0xd8, - 0xb1, 0x6f, 0xf2, 0xb8, 0x30, 0xa3, 0x14, 0x53, 0x6b, 0xd2, 0x8f, 0x81, 0x2b, 0xa6, 0xbd, 0x02, 0x5c, 0x2d, 0x77, - 0x3b, 0x15, 0x43, 0x13, 0xf6, 0xec, 0x18, 0xa2, 0x9e, 0x1b, 0xc7, 0x28, 0xd9, 0x70, 0x0f, 0x88, 0xb5, 0xcc, 0x5b, - 0xb9, 0x04, 0x24, 0xf0, 0xd6, 0xc3, 0xa4, 0x00, 0x8c, 0xc1, 0x72, 0x45, 0x74, 0x1e, 0x0f, 0x7d, 0x42, 0xbd, 0xd0, - 0xa8, 0x13, 0xb2, 0xb1, 0x25, 0x70, 0xfc, 0x61, 0x7d, 0x08, 0x04, 0xaf, 0xf2, 0x5c, 0x7f, 0xa5, 0x75, 0xfd, 0xa5, - 0xd2, 0x73, 0xc7, 0x72, 0x5d, 0x3f, 0x6b, 0x53, 0xa3, 0x97, 0x60, 0xe1, 0xbb, 0x55, 0xe6, 0x91, 0xdc, 0x22, 0xa4, - 0x2a, 0xb0, 0x52, 0xb7, 0x90, 0x60, 0xfe, 0x95, 0x9c, 0xad, 0xca, 0x7c, 0xf5, 0xc8, 0x83, 0x72, 0x36, 0x3d, 0xfd, - 0x0d, 0x09, 0xda, 0x5d, 0x47, 0x9a, 0xc7, 0x5b, 0x74, 0xf8, 0xec, 0x5a, 0x4b, 0xcc, 0xbd, 0x44, 0xc5, 0xf3, 0x29, - 0x60, 0xab, 0xe7, 0xd9, 0x95, 0xf2, 0xb1, 0xda, 0xc7, 0xf1, 0x33, 0xe7, 0x4f, 0x5c, 0x85, 0x1b, 0xd1, 0x50, 0x82, - 0x80, 0x37, 0x87, 0xb1, 0x2b, 0x54, 0x01, 0x0d, 0xcd, 0x0d, 0x1c, 0xe7, 0x6a, 0x58, 0x69, 0x02, 0xa6, 0xa5, 0x3c, - 0x3a, 0xc0, 0xa1, 0xc9, 0xa3, 0x76, 0xd3, 0xb0, 0x32, 0x74, 0xad, 0xd1, 0xe7, 0xb6, 0xd2, 0x19, 0x6f, 0x36, 0xfc, - 0xf0, 0x68, 0x50, 0xe1, 0x4f, 0xd2, 0x1c, 0x8d, 0x76, 0x6e, 0xb8, 0xd3, 0x08, 0xcc, 0x5c, 0xc9, 0x35, 0xd9, 0x1f, - 0x25, 0x2f, 0xbf, 0xa7, 0x17, 0x16, 0xd0, 0x9f, 0xff, 0x5c, 0x4c, 0x38, 0x69, 0x89, 0x09, 0xd1, 0xd2, 0x41, 0x8b, - 0x0e, 0xf6, 0x94, 0x57, 0xf6, 0x25, 0x5e, 0x3a, 0xc7, 0xff, 0xbe, 0x1e, 0x6b, 0x5f, 0x81, 0xd0, 0xea, 0xe4, 0x61, - 0x7b, 0xb2, 0x40, 0xd4, 0x80, 0x6a, 0x76, 0x55, 0x8e, 0x32, 0xed, 0xac, 0xc8, 0xb6, 0x21, 0x73, 0xdd, 0xcf, 0xd2, - 0xb0, 0x99, 0xec, 0x58, 0x58, 0x66, 0x18, 0xac, 0x9d, 0x2a, 0xfa, 0x1c, 0xb4, 0xfc, 0x08, 0x9e, 0x37, 0x95, 0x67, - 0x3e, 0x9b, 0x65, 0xc4, 0x0b, 0x74, 0xc1, 0xa9, 0x58, 0x36, 0xa5, 0x63, 0xe5, 0x6e, 0x57, 0xa2, 0xb1, 0x44, 0x19, - 0x05, 0x41, 0x6d, 0x83, 0xb0, 0xeb, 0xd2, 0x3d, 0xe9, 0xd3, 0x3e, 0x3e, 0xad, 0x40, 0xdf, 0xe3, 0xfb, 0x0c, 0x24, - 0xa6, 0x9e, 0xe4, 0xa1, 0x6a, 0x34, 0x47, 0x27, 0xcf, 0xe3, 0x54, 0xe3, 0xf3, 0x2b, 0xd9, 0x59, 0xf3, 0x6e, 0x35, - 0xa6, 0xf8, 0x8f, 0xd4, 0xed, 0x3b, 0x97, 0xa1, 0x89, 0xfe, 0x5a, 0x1e, 0xb4, 0x14, 0x16, 0x1c, 0xb7, 0x8d, 0xbf, - 0x7e, 0x9b, 0x39, 0xc4, 0xb0, 0x74, 0x39, 0xbc, 0x09, 0x1d, 0xba, 0xbb, 0xca, 0xde, 0x5c, 0x1f, 0x51, 0xa7, 0x2e, - 0xd6, 0x6d, 0x40, 0xc9, 0x92, 0x77, 0xeb, 0xf4, 0xc4, 0x4a, 0xdf, 0x1d, 0x86, 0x7b, 0xf3, 0xa8, 0xd9, 0xdd, 0xdd, - 0x6e, 0x42, 0xda, 0xf6, 0xc1, 0x78, 0x5f, 0xc2, 0x42, 0x9c, 0x77, 0xd8, 0xc1, 0xf7, 0x61, 0xf5, 0x98, 0x0f, 0x7e, - 0xc6, 0x71, 0x86, 0xd1, 0xcf, 0x94, 0xa1, 0xcf, 0xcb, 0x42, 0x5e, 0xa9, 0x4e, 0xf9, 0x42, 0xb7, 0x96, 0xa9, 0xf7, - 0x9b, 0xf8, 0x4d, 0x2b, 0x40, 0x8c, 0xd7, 0x15, 0x2b, 0xc5, 0x1b, 0x5a, 0x61, 0x5c, 0x03, 0xb7, 0xc9, 0xa1, 0x96, - 0x6a, 0x81, 0xa8, 0xcb, 0x4f, 0x1e, 0xf3, 0xc8, 0xa8, 0x33, 0xe1, 0xbb, 0xc7, 0xdc, 0x97, 0xae, 0xed, 0x37, 0xf1, - 0x53, 0x4d, 0x3b, 0xdc, 0x1f, 0xe8, 0x8e, 0xd6, 0x3d, 0xdc, 0x3c, 0x9b, 0x9f, 0x47, 0xe6, 0x8b, 0x01, 0x36, 0x6b, - 0x9f, 0x71, 0xd9, 0x33, 0xdc, 0xf7, 0xa6, 0x07, 0x63, 0x01, 0x81, 0xc4, 0x0c, 0xbd, 0x0c, 0x5c, 0xe0, 0x02, 0x77, - 0x85, 0x01, 0x43, 0x5c, 0xd3, 0x92, 0x33, 0x6d, 0x65, 0xeb, 0x23, 0x6f, 0xa3, 0x42, 0xb0, 0xae, 0x3b, 0x6e, 0x92, - 0x1c, 0x82, 0x13, 0xb6, 0xdc, 0xfb, 0xda, 0x6b, 0x67, 0xf8, 0x8f, 0x81, 0x70, 0x6e, 0x89, 0x9e, 0x51, 0xdb, 0x63, - 0xad, 0xee, 0x35, 0xbc, 0xca, 0x5d, 0xe4, 0x59, 0xbf, 0x99, 0x97, 0x86, 0x7d, 0xc1, 0x6b, 0x29, 0x38, 0x34, 0xb6, - 0x5b, 0xe1, 0x16, 0x8b, 0x77, 0xb4, 0x5a, 0x59, 0x6b, 0xab, 0xbd, 0x56, 0x2a, 0x7a, 0xff, 0x9a, 0xe3, 0xc4, 0x59, - 0x0a, 0xdb, 0x0f, 0x1f, 0x2e, 0xd8, 0x35, 0x01, 0x0c, 0x5a, 0x4c, 0x16, 0x28, 0x41, 0x25, 0x6b, 0x55, 0xbb, 0x9d, - 0x12, 0xbf, 0xdc, 0xcf, 0xba, 0xcc, 0x76, 0x1e, 0xbf, 0x6e, 0xd2, 0x3e, 0xf1, 0x39, 0xfa, 0x61, 0x7e, 0x67, 0x9d, - 0x94, 0x9c, 0x61, 0x5c, 0xcb, 0xff, 0xaf, 0xa2, 0x97, 0x45, 0x96, 0x46, 0x5b, 0xc3, 0x83, 0xd9, 0x50, 0x9b, 0x3e, - 0x34, 0x46, 0xe5, 0x96, 0x8d, 0x22, 0xa2, 0xd5, 0x2d, 0x08, 0x66, 0x14, 0xf7, 0x25, 0xda, 0xbc, 0x52, 0x65, 0xe1, - 0x1d, 0x3e, 0xb1, 0xd1, 0x1b, 0xb6, 0x27, 0x84, 0xf2, 0xfd, 0xd3, 0xc2, 0xac, 0x5a, 0x2a, 0x1a, 0x6c, 0x97, 0xf0, - 0x2e, 0x46, 0x95, 0x7e, 0xc2, 0x64, 0xcb, 0x82, 0xa9, 0xfe, 0x7f, 0x5f, 0x64, 0x69, 0x9b, 0xa2, 0x03, 0xd3, 0xd9, - 0xf4, 0xe9, 0xa4, 0x5b, 0x5c, 0x67, 0xc0, 0x22, 0x82, 0x2d, 0x15, 0x8e, 0x47, 0xa9, 0xdd, 0x20, 0x61, 0x22, 0xb8, - 0x89, 0x7a, 0xd9, 0xd1, 0x32, 0x25, 0xab, 0x02, 0x9e, 0x5f, 0xb9, 0xca, 0x74, 0x1c, 0x0d, 0xfd, 0xfe, 0x55, 0x6a, - 0x42, 0xbf, 0x52, 0x2f, 0x55, 0x71, 0x1e, 0x46, 0xd5, 0xa1, 0xc2, 0x18, 0xad, 0x68, 0x0a, 0xc7, 0x60, 0x76, 0x11, - 0xa6, 0x78, 0x39, 0xdb, 0x26, 0xec, 0x33, 0x06, 0x72, 0xa5, 0x0d, 0xea, 0x35, 0x25, 0xda, 0xb0, 0xf6, 0x66, 0x4e, - 0x09, 0xbd, 0x60, 0xa5, 0x7f, 0x17, 0xda, 0x80, 0x40, 0x51, 0x36, 0x53, 0xa6, 0xe7, 0xba, 0x9d, 0x17, 0x34, 0xa1, - 0x05, 0x5d, 0x93, 0x1a, 0xf4, 0xbd, 0x4e, 0xce, 0x8e, 0x4e, 0x76, 0x66, 0xd6, 0x63, 0x56, 0x0c, 0x27, 0xd3, 0x18, - 0xae, 0x69, 0xb1, 0xbb, 0xa6, 0xad, 0x9a, 0x37, 0xae, 0xc6, 0xc6, 0x69, 0xd0, 0x2e, 0x90, 0xb6, 0x69, 0x6e, 0x3f, - 0xf5, 0xb8, 0xfd, 0x4d, 0xcd, 0x56, 0xd3, 0xde, 0x66, 0xb7, 0xeb, 0xa5, 0x60, 0x23, 0xea, 0xf1, 0xf1, 0x1b, 0x25, - 0x5d, 0xb7, 0x5c, 0x7e, 0x0a, 0xcf, 0x1e, 0x5f, 0xbf, 0xf2, 0xc1, 0xe5, 0x68, 0xd5, 0xe6, 0xee, 0x57, 0xfb, 0xc8, - 0x72, 0x9f, 0x35, 0xb4, 0x5c, 0xcf, 0x50, 0x93, 0x3c, 0x1b, 0xed, 0x1d, 0x6a, 0xc1, 0x72, 0xd6, 0x4d, 0x78, 0x62, - 0xb0, 0x63, 0xaf, 0x1a, 0x9b, 0xa3, 0x32, 0x97, 0xac, 0x06, 0x09, 0xf4, 0x49, 0x9e, 0x69, 0xfa, 0x07, 0x19, 0xe6, - 0xa3, 0x5b, 0x9a, 0x03, 0xae, 0x58, 0x65, 0x2f, 0x19, 0xa4, 0xae, 0xda, 0x4b, 0x5c, 0xf9, 0x0a, 0x87, 0x64, 0x8b, - 0x4f, 0x86, 0xa9, 0xfa, 0xe4, 0x92, 0x07, 0xff, 0x6f, 0xab, 0x56, 0xe9, 0xb9, 0x49, 0x6e, 0x38, 0xfe, 0x75, 0xd2, - 0xf6, 0x31, 0x31, 0x48, 0xc0, 0x53, 0xbb, 0x18, 0xaa, 0x51, 0x55, 0xc4, 0xa2, 0xcc, 0x4d, 0xcc, 0xb1, 0x7b, 0xbb, - 0x86, 0x0e, 0xca, 0xe0, 0xd7, 0x0d, 0x9f, 0x98, 0x3b, 0xb0, 0x15, 0xe8, 0xe8, 0x44, 0x73, 0x19, 0x66, 0xe6, 0x32, - 0x4c, 0xbb, 0xb6, 0x0a, 0x0c, 0xaf, 0xda, 0x2a, 0x89, 0x72, 0x35, 0xea, 0x71, 0x33, 0x4b, 0xcd, 0x5e, 0xe4, 0xdd, - 0x6b, 0xd2, 0x93, 0xf8, 0xd3, 0x95, 0x27, 0xaf, 0x87, 0x01, 0x91, 0x9f, 0xb3, 0x34, 0x5c, 0xa3, 0x20, 0x38, 0xb5, - 0xda, 0x81, 0x34, 0x1f, 0x01, 0x32, 0x3f, 0x4e, 0xc3, 0x77, 0x5a, 0x9c, 0x43, 0xb6, 0x4a, 0xe3, 0xc4, 0x56, 0x46, - 0x3d, 0x04, 0x77, 0xde, 0x2b, 0x1e, 0x43, 0xe0, 0xc3, 0x0f, 0xb8, 0x19, 0x54, 0x74, 0x5b, 0x62, 0xa2, 0xb4, 0x79, - 0xd4, 0x2d, 0x1f, 0x35, 0x84, 0x4a, 0x56, 0x86, 0x17, 0x43, 0x7b, 0xf7, 0x04, 0x46, 0x95, 0x13, 0xc8, 0x0c, 0x8b, - 0xc3, 0xa3, 0x61, 0xaa, 0x04, 0x45, 0x43, 0x39, 0x5c, 0xa1, 0x1c, 0x10, 0x93, 0x40, 0x60, 0x54, 0x0c, 0x52, 0x5d, - 0x99, 0x7a, 0x31, 0x48, 0xf5, 0xad, 0x8a, 0xd4, 0x67, 0x59, 0x58, 0x51, 0xdd, 0x22, 0x3a, 0xa6, 0x43, 0x49, 0x57, - 0x66, 0xa7, 0xe6, 0x5a, 0x7a, 0xa1, 0x96, 0xe3, 0x33, 0x9d, 0x06, 0xa3, 0x78, 0xea, 0x52, 0xf4, 0x5b, 0xb5, 0x9f, - 0xfd, 0xb7, 0x98, 0x52, 0x23, 0x36, 0xb5, 0xb7, 0x88, 0x61, 0xd5, 0x7e, 0xc8, 0xaa, 0x1c, 0xb4, 0xbb, 0xa0, 0x6c, - 0xac, 0x8c, 0xf3, 0x7c, 0x23, 0x98, 0x39, 0x68, 0x1b, 0xab, 0xa6, 0x0f, 0xbd, 0x11, 0xa3, 0xf6, 0xc6, 0x54, 0xe3, - 0x9e, 0xc0, 0x4f, 0x1b, 0x34, 0xdd, 0x8b, 0x3c, 0x47, 0x3d, 0xf2, 0xee, 0x7f, 0xe6, 0xc8, 0xce, 0xe4, 0x93, 0x58, - 0x26, 0x75, 0xfb, 0x98, 0x04, 0x0b, 0x55, 0xc7, 0xe8, 0xc2, 0x8d, 0x4c, 0x69, 0x3f, 0xf7, 0xa6, 0x1f, 0xf1, 0x4c, - 0x1e, 0xb6, 0x43, 0xa3, 0xbe, 0x34, 0xac, 0x25, 0x45, 0xd4, 0x17, 0xf4, 0xd6, 0x54, 0x47, 0x47, 0xd4, 0xeb, 0x08, - 0xac, 0xae, 0x68, 0x8b, 0x1a, 0x80, 0xc9, 0xb8, 0xb6, 0xb5, 0xf9, 0x1c, 0x4c, 0x6d, 0x55, 0x05, 0x4f, 0xe9, 0xbe, - 0x50, 0xba, 0x37, 0xa9, 0xeb, 0xd6, 0x10, 0x5b, 0xc0, 0x80, 0xc0, 0x8d, 0x9e, 0x9a, 0xfe, 0xa0, 0x89, 0x0a, 0x40, - 0x83, 0xc6, 0xed, 0x4c, 0xe7, 0x48, 0xf4, 0x3b, 0xb5, 0x69, 0x9b, 0xa9, 0x5e, 0x55, 0x3e, 0x80, 0x8a, 0x3f, 0x4b, - 0x67, 0x17, 0x66, 0xc4, 0x02, 0x18, 0xf7, 0xc0, 0x99, 0xea, 0x9d, 0x64, 0x60, 0x3d, 0x91, 0xe7, 0x59, 0xc9, 0x13, - 0x29, 0x60, 0x46, 0xe4, 0xd5, 0x95, 0x14, 0x30, 0x0c, 0x6a, 0x00, 0xd0, 0xa2, 0xb9, 0x8c, 0x26, 0xfc, 0xab, 0x9a, - 0xde, 0x97, 0x87, 0x7f, 0xa5, 0x73, 0x7d, 0x3d, 0xae, 0xc1, 0x50, 0x79, 0x53, 0xf1, 0xbd, 0x4c, 0x5f, 0xf3, 0x27, - 0x5e, 0xa6, 0x95, 0xdc, 0x14, 0x7b, 0x59, 0xbe, 0xfa, 0x9a, 0x3f, 0xd5, 0x79, 0x8e, 0x9e, 0xd4, 0x34, 0x8d, 0xef, - 0xf6, 0xb2, 0x7c, 0xf3, 0xf5, 0x13, 0x9b, 0xe7, 0xab, 0x71, 0x4d, 0x6f, 0x38, 0xff, 0xe8, 0x32, 0x4d, 0x74, 0x55, - 0xe3, 0x27, 0xdf, 0xd8, 0x5c, 0x4f, 0x6a, 0x7a, 0x25, 0x45, 0xb5, 0xda, 0x2b, 0xea, 0xe8, 0xeb, 0xa3, 0x6f, 0xf8, - 0xd7, 0xa6, 0x7b, 0x47, 0x35, 0xfd, 0x73, 0x13, 0x17, 0x15, 0x2f, 0xf6, 0x8a, 0xfb, 0xdb, 0x37, 0xdf, 0x3c, 0xb1, - 0x19, 0x9f, 0xd4, 0xf4, 0x8e, 0xc7, 0x1d, 0x6d, 0x9f, 0x3c, 0x7d, 0xc2, 0xff, 0x56, 0xd7, 0xf4, 0x17, 0xe6, 0x07, - 0x47, 0x3d, 0xc9, 0x3c, 0x3d, 0x7c, 0x22, 0x9b, 0xa8, 0x01, 0x43, 0x0f, 0x0d, 0x20, 0x97, 0x56, 0x4d, 0x73, 0x8f, - 0x57, 0x2e, 0xb8, 0x7d, 0x9f, 0xc5, 0x69, 0xbc, 0x86, 0x83, 0x60, 0x8b, 0xc6, 0x59, 0x05, 0x70, 0xaa, 0xc0, 0x7b, - 0x46, 0x25, 0xcd, 0x4a, 0xf9, 0x0f, 0xce, 0x3f, 0xc2, 0xa0, 0x21, 0xa4, 0x8d, 0x8a, 0x0c, 0xf4, 0x76, 0xad, 0x23, - 0x1b, 0xa1, 0xff, 0x66, 0x33, 0x0e, 0x8e, 0x0f, 0xa3, 0xd7, 0xef, 0x87, 0x05, 0x13, 0x61, 0x41, 0x08, 0xfd, 0x23, - 0x2c, 0xc0, 0xa1, 0xa4, 0x60, 0x5e, 0x3e, 0xe3, 0x7b, 0xae, 0x8d, 0xc2, 0x42, 0x10, 0xdd, 0x45, 0xf6, 0x01, 0x55, - 0x8f, 0xbe, 0x43, 0x37, 0xc4, 0xcb, 0x0a, 0x0b, 0x86, 0x56, 0x35, 0x30, 0x43, 0x50, 0xfc, 0x6b, 0x1e, 0x4a, 0xf0, - 0x89, 0x07, 0xf8, 0xe8, 0x31, 0x99, 0x73, 0x75, 0xad, 0x7d, 0x7b, 0x11, 0x16, 0x34, 0xd0, 0x6d, 0x87, 0xa0, 0x03, - 0x91, 0xff, 0x02, 0x3c, 0x05, 0x06, 0x3e, 0x2c, 0xec, 0x4a, 0xee, 0xfb, 0xab, 0xff, 0x62, 0x58, 0x47, 0x17, 0x7e, - 0xf4, 0x17, 0xeb, 0xc2, 0x9e, 0x91, 0xa9, 0x3c, 0x2e, 0x87, 0x93, 0xe9, 0x60, 0x20, 0x5d, 0x1c, 0xb7, 0x93, 0x6c, - 0xf1, 0xcb, 0x42, 0x2e, 0x97, 0xa8, 0xfb, 0xc6, 0x79, 0x9d, 0xeb, 0xbf, 0x91, 0x76, 0x3e, 0x78, 0x7d, 0xf2, 0xdb, - 0xd9, 0xe9, 0xc9, 0x4b, 0x70, 0x3e, 0xf8, 0xf0, 0xe2, 0xfb, 0x17, 0xef, 0x55, 0x70, 0x77, 0x35, 0xe7, 0xfd, 0xbe, - 0x93, 0xfa, 0x84, 0x7c, 0x58, 0x91, 0xc3, 0x30, 0x7e, 0x5c, 0x28, 0xa3, 0x07, 0x72, 0xcc, 0x2c, 0x14, 0x32, 0x54, - 0x51, 0xdb, 0xdf, 0xe5, 0x70, 0xe2, 0x81, 0x59, 0xdc, 0x35, 0x44, 0xb8, 0x7e, 0xcb, 0x6d, 0x90, 0x35, 0x39, 0xf3, - 0xfa, 0xc1, 0xc9, 0x54, 0x3a, 0xb6, 0xb0, 0x60, 0x50, 0x36, 0xb4, 0xe9, 0x24, 0x5b, 0x14, 0x4b, 0xdb, 0x2e, 0xb7, - 0x40, 0x46, 0x69, 0x76, 0x71, 0x11, 0x2a, 0xe8, 0xea, 0x19, 0x68, 0x00, 0x4c, 0xa3, 0x0a, 0xd7, 0x22, 0x3e, 0xf7, - 0xcb, 0x8f, 0xc6, 0x5e, 0xf3, 0x6e, 0x51, 0xf7, 0x64, 0x9a, 0x55, 0x35, 0x06, 0x74, 0x30, 0xa1, 0xdc, 0x0d, 0xba, - 0x09, 0x26, 0xa3, 0xda, 0xf2, 0xcb, 0xa2, 0x5a, 0x9a, 0xe6, 0xb8, 0x61, 0xa8, 0xbc, 0x92, 0x37, 0xb2, 0x81, 0xc8, - 0x40, 0x32, 0x0c, 0x7b, 0x34, 0x46, 0x91, 0xfa, 0xc1, 0xbe, 0x77, 0xfc, 0x36, 0x97, 0x10, 0x4d, 0x31, 0x03, 0xe9, - 0xfc, 0x89, 0x50, 0xce, 0xe5, 0x92, 0xf1, 0x85, 0x58, 0xce, 0xc0, 0xed, 0x7c, 0x21, 0x96, 0x11, 0x06, 0xe5, 0xcb, - 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, 0x81, 0x24, 0x1b, 0x94, 0x76, 0xa5, 0x21, - 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x5a, 0x54, 0x6d, 0x4f, 0x36, 0x73, 0x31, 0xc1, 0x55, 0x16, 0x33, - 0x39, 0x8d, 0x8f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, 0x4e, 0xa8, 0x20, 0x24, 0x61, 0x7c, 0x11, - 0x2f, 0x69, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, 0x96, 0xbc, 0xdd, 0x7e, 0x9e, 0x7e, 0x6e, - 0xcf, 0x70, 0x19, 0x15, 0xa1, 0x5b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, 0x8d, 0xb1, 0x62, 0x08, 0x02, 0x5e, 0x60, - 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x22, 0x5e, 0xb2, 0x82, 0x36, 0x6d, 0x4e, 0x63, 0x6d, 0x12, - 0xd4, 0x73, 0x58, 0x6a, 0x07, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x2e, 0xa2, 0x6b, 0x6d, 0x68, 0x00, 0x28, 0x50, 0x4a, - 0x2e, 0x7e, 0xf3, 0xf9, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4d, 0xb4, 0xb3, 0x5c, 0x1d, 0x7a, 0x8b, 0x25, 0x8d, - 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, 0x2e, 0x30, 0x21, 0xe1, 0xa0, 0x4d, 0xbf, - 0x40, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, 0x91, 0x9e, 0x67, 0x7f, 0x35, 0x31, 0xd6, - 0x34, 0x35, 0x33, 0xf1, 0x36, 0x14, 0xa2, 0x41, 0x0b, 0xa2, 0x19, 0xbc, 0x7f, 0xae, 0x38, 0x5e, 0x75, 0xe0, 0x07, - 0xbc, 0x73, 0x71, 0xe6, 0xd5, 0xcc, 0x23, 0x72, 0xea, 0xa3, 0x1c, 0xd1, 0x2f, 0x79, 0x58, 0x8d, 0x74, 0x32, 0xc6, - 0x4a, 0xe2, 0xa0, 0xb7, 0xc1, 0x82, 0x39, 0xa1, 0x6b, 0x1e, 0x5a, 0x3e, 0xfe, 0x25, 0x32, 0x19, 0x25, 0x35, 0x56, - 0x74, 0xa5, 0xc5, 0x88, 0xf3, 0x1a, 0x66, 0x69, 0xb2, 0xa2, 0x8b, 0x85, 0x26, 0xcd, 0x42, 0x99, 0x06, 0xf8, 0x04, - 0x5a, 0x8c, 0xdc, 0x43, 0x4d, 0x1b, 0x08, 0x0d, 0xfb, 0x43, 0xc0, 0x47, 0xee, 0xa1, 0xc3, 0xff, 0xcf, 0xb3, 0x0b, - 0x44, 0xda, 0x9b, 0x9b, 0xc8, 0x78, 0xa4, 0x6e, 0xe0, 0xa0, 0x18, 0x1f, 0xfb, 0x66, 0xe2, 0x67, 0xce, 0xe8, 0x43, - 0x52, 0xf9, 0x0e, 0x1f, 0x2c, 0x7f, 0xbc, 0xa9, 0x99, 0x95, 0x11, 0xac, 0x87, 0xdd, 0x0e, 0x17, 0x44, 0xdb, 0x05, - 0x90, 0x7a, 0xc6, 0xab, 0x85, 0x6f, 0xbc, 0x1a, 0xdf, 0x63, 0xbc, 0xea, 0xce, 0xd4, 0x30, 0x27, 0x5b, 0xd4, 0x67, - 0x29, 0x79, 0x7e, 0x8e, 0x32, 0xc1, 0xa6, 0xcb, 0x59, 0x49, 0x55, 0x2a, 0xa1, 0xbd, 0xd8, 0xcf, 0x18, 0xdf, 0x12, - 0x8c, 0xb3, 0xe2, 0x30, 0x12, 0xa8, 0x4a, 0x25, 0x75, 0xd8, 0x2b, 0x40, 0x3d, 0x06, 0xef, 0x0d, 0x86, 0xa8, 0x91, - 0xb1, 0x9b, 0x36, 0x10, 0x1a, 0x1a, 0xeb, 0xd1, 0x9e, 0xb5, 0x1e, 0xdd, 0xed, 0x2a, 0xe3, 0x6f, 0x27, 0x37, 0x45, - 0x82, 0xa8, 0xc2, 0x6a, 0x34, 0x01, 0xde, 0x34, 0xb1, 0xb7, 0x25, 0xa7, 0xb4, 0xc0, 0xf0, 0xd9, 0x7f, 0x84, 0xa5, - 0x53, 0x49, 0x94, 0x64, 0x5e, 0x46, 0x03, 0x77, 0x0e, 0x3e, 0x8f, 0x2b, 0x58, 0x03, 0x10, 0xc9, 0x11, 0x3d, 0x5c, - 0xff, 0x08, 0xa5, 0xcb, 0x2c, 0xc9, 0x5c, 0x42, 0x66, 0x2e, 0xd2, 0x76, 0xd6, 0xc1, 0xc4, 0x99, 0xd4, 0x7a, 0x63, - 0x21, 0x87, 0x06, 0xf9, 0x01, 0x94, 0x21, 0x0e, 0x9f, 0x7c, 0x30, 0xa1, 0x52, 0x85, 0x52, 0x6d, 0x74, 0xb3, 0x1b, - 0x78, 0xe5, 0x43, 0x76, 0xc5, 0xcb, 0x2a, 0xbe, 0x5a, 0x1b, 0x4b, 0x62, 0xce, 0xee, 0x73, 0xdb, 0xa3, 0xc2, 0xbc, - 0x7a, 0xf3, 0xe2, 0xfb, 0x93, 0xc6, 0xab, 0x7d, 0xc4, 0xd1, 0x10, 0x6c, 0x2b, 0xc6, 0x18, 0xbd, 0xc5, 0xa7, 0xc1, - 0x44, 0xb9, 0x46, 0xa0, 0x77, 0x29, 0xe8, 0xb7, 0x3f, 0xd7, 0x13, 0xf0, 0x8a, 0xeb, 0xe5, 0x97, 0x7c, 0x04, 0x2c, - 0x51, 0xa1, 0x67, 0x85, 0xb9, 0x59, 0x99, 0xdf, 0xdb, 0xad, 0xc8, 0x4c, 0xbb, 0xd2, 0xc8, 0x40, 0xbc, 0xda, 0x0e, - 0x63, 0xe1, 0xd2, 0x35, 0xdd, 0x0e, 0x76, 0xb5, 0xf2, 0x2c, 0x91, 0x77, 0xbb, 0x12, 0x3a, 0x64, 0x07, 0xdc, 0x7b, - 0x19, 0xdf, 0xc2, 0xcb, 0xd2, 0xeb, 0x66, 0x33, 0x78, 0x02, 0x98, 0x09, 0x17, 0xce, 0xb2, 0x38, 0x66, 0x3c, 0x09, - 0x55, 0x6c, 0xae, 0x86, 0xc8, 0x5b, 0x11, 0x5a, 0xb3, 0xbf, 0x42, 0x31, 0x02, 0xbb, 0x93, 0xd3, 0x8f, 0xd9, 0x7a, - 0xbe, 0x02, 0xd4, 0xfc, 0xab, 0x4c, 0x00, 0xcd, 0xb5, 0x6b, 0xc1, 0x36, 0x85, 0x36, 0xd7, 0xf5, 0xb3, 0x78, 0x1d, - 0x27, 0xa0, 0xba, 0x01, 0x6f, 0x91, 0x3b, 0x2d, 0xba, 0x32, 0xe8, 0xa2, 0xf4, 0x81, 0x72, 0x2c, 0x29, 0x74, 0xf4, - 0xbd, 0x27, 0xd4, 0xb9, 0x67, 0x00, 0x97, 0x34, 0x6a, 0x9e, 0x6a, 0x29, 0x63, 0x01, 0xb0, 0xd0, 0xc1, 0x5c, 0x91, - 0xad, 0xe8, 0xd6, 0x60, 0x52, 0xc0, 0x5b, 0x03, 0xfc, 0x21, 0xb2, 0x4a, 0xdd, 0x15, 0xcb, 0xb0, 0xf4, 0xec, 0xaf, - 0xfb, 0xfd, 0xd8, 0xb3, 0xbf, 0xbe, 0xd0, 0xb4, 0x2e, 0x6e, 0x37, 0x80, 0xd4, 0x18, 0x40, 0xe4, 0x44, 0x0f, 0x84, - 0x89, 0x28, 0xd6, 0xf4, 0xfd, 0x3b, 0x31, 0x59, 0x14, 0x08, 0xfd, 0x5e, 0xbd, 0x9e, 0x94, 0x04, 0x74, 0x6a, 0x15, - 0x9b, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xc5, 0x52, 0x39, 0x17, 0xab, 0xf0, 0xe1, 0x63, 0x0a, - 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, 0x9a, 0x17, 0x6b, 0x49, 0xc8, 0x62, 0xbc, - 0x44, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, 0xfb, 0xbf, 0x99, 0x2c, 0x09, 0x6a, 0xae, - 0xfc, 0x40, 0x8e, 0x7b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, 0x82, 0xc0, 0x70, 0xc3, 0xcf, 0xf8, 0xf8, - 0x68, 0x49, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xe3, 0xaf, 0x00, 0x35, 0x66, 0x74, 0xf4, 0x14, 0x40, 0x61, - 0x21, 0x20, 0xfa, 0x18, 0x64, 0xb4, 0x02, 0x7e, 0x0b, 0xf5, 0xbb, 0x75, 0xe2, 0xfb, 0xd0, 0xaf, 0x82, 0x5e, 0xc4, - 0xc0, 0x70, 0x44, 0x93, 0xc3, 0x90, 0x0f, 0x26, 0x03, 0xd0, 0x96, 0x78, 0xbb, 0xaf, 0xa5, 0x15, 0x37, 0xa7, 0x4b, - 0xa7, 0xfb, 0x27, 0x6d, 0x82, 0x24, 0x52, 0xc9, 0x4a, 0x45, 0x0c, 0x20, 0x94, 0xa5, 0xda, 0x26, 0x2b, 0xb0, 0xac, - 0x30, 0x4b, 0x9a, 0x1b, 0x94, 0xc4, 0xfd, 0xcd, 0xc0, 0x31, 0x6a, 0xd6, 0x49, 0x58, 0xb6, 0xdc, 0xa8, 0x01, 0x3e, - 0x27, 0x61, 0x85, 0xbd, 0xe1, 0xcc, 0xa5, 0x77, 0xa6, 0xc3, 0xd5, 0x31, 0x67, 0xaf, 0x39, 0x82, 0x71, 0x24, 0x78, - 0xe3, 0xa1, 0x2b, 0xa6, 0xa1, 0x22, 0x53, 0xc6, 0xc1, 0xb4, 0x07, 0xb8, 0xf7, 0x1c, 0x8c, 0xc3, 0xd8, 0xa0, 0xb2, - 0xa4, 0x3e, 0xf5, 0xee, 0x42, 0x20, 0x48, 0x6b, 0xbd, 0xcc, 0xe7, 0x78, 0x7a, 0x46, 0x28, 0xfb, 0x43, 0x0e, 0x5f, - 0x80, 0x1d, 0x05, 0x99, 0x4d, 0xf8, 0xd3, 0xc7, 0xfb, 0x81, 0xaa, 0xf8, 0x20, 0x38, 0x88, 0x45, 0x7a, 0x10, 0x0c, - 0x04, 0xfc, 0x2a, 0xf8, 0x41, 0x25, 0xe5, 0xc1, 0x45, 0x5c, 0x1c, 0xc4, 0xeb, 0xb8, 0xa8, 0x0e, 0x6e, 0xb2, 0x6a, - 0x75, 0x60, 0x3a, 0x04, 0xd0, 0xbc, 0xc1, 0x20, 0x1e, 0x04, 0x07, 0xc1, 0xa0, 0x30, 0x53, 0xbb, 0x66, 0x65, 0xe3, - 0x38, 0x33, 0x21, 0xca, 0x82, 0x66, 0x80, 0xb0, 0xc6, 0x69, 0x00, 0x7c, 0xea, 0x86, 0xa5, 0xf4, 0x02, 0xc3, 0x0d, - 0x88, 0xe9, 0x06, 0xfa, 0x00, 0x3c, 0xf2, 0x86, 0xc6, 0xb0, 0x04, 0x2e, 0x06, 0x03, 0xb2, 0x81, 0xc8, 0x05, 0x1b, - 0x6a, 0x83, 0x38, 0x84, 0x1b, 0x65, 0xa7, 0xbd, 0x0f, 0xcc, 0xb4, 0xdb, 0x01, 0xa2, 0xf2, 0x84, 0xf4, 0xfb, 0xf6, - 0x1b, 0xea, 0x5f, 0xb0, 0x57, 0x60, 0x7f, 0x55, 0x54, 0x61, 0x22, 0x95, 0xe6, 0xfb, 0x92, 0xcd, 0x06, 0x2a, 0xe2, - 0xf0, 0x9e, 0x23, 0x45, 0x1b, 0x95, 0xcb, 0xb2, 0x27, 0xab, 0x86, 0xaf, 0xc4, 0x15, 0x77, 0x7e, 0x5c, 0x95, 0x94, - 0x79, 0x95, 0xad, 0x15, 0xfb, 0x37, 0xe7, 0x9a, 0xfb, 0x03, 0xeb, 0xcf, 0xe6, 0x2b, 0xb8, 0xb6, 0x7a, 0xef, 0x9a, - 0x5c, 0x23, 0x72, 0x96, 0x50, 0x2e, 0xa9, 0x6d, 0x1e, 0xde, 0xd2, 0xf7, 0xf9, 0xd5, 0xb7, 0x99, 0x4e, 0xe3, 0xb3, - 0x0a, 0x0b, 0x17, 0xa2, 0x15, 0xc1, 0xa1, 0x21, 0x97, 0xcd, 0x23, 0xc0, 0x5c, 0xfb, 0x6c, 0x05, 0x05, 0xa9, 0xcf, - 0x2a, 0xf4, 0x6e, 0x85, 0x84, 0x97, 0x9a, 0x5d, 0x7a, 0x18, 0x48, 0x19, 0xb7, 0x87, 0x96, 0x30, 0x69, 0x79, 0x11, - 0xde, 0x7b, 0xcd, 0x4d, 0xee, 0x79, 0x88, 0xd1, 0x8b, 0x3c, 0x3b, 0x01, 0x63, 0xdd, 0x25, 0x3b, 0x1b, 0x9e, 0xf8, - 0x0d, 0xcf, 0x59, 0x8b, 0x46, 0xd3, 0x15, 0x4b, 0xfa, 0xfd, 0x18, 0x4c, 0xbc, 0x53, 0x96, 0xc3, 0xaf, 0x7c, 0x49, - 0x37, 0x0c, 0x30, 0xc5, 0xe8, 0x05, 0x24, 0xa4, 0x88, 0x44, 0xb2, 0x51, 0x27, 0xc9, 0x27, 0xba, 0x0b, 0xc0, 0xe8, - 0x17, 0xf3, 0x34, 0x5a, 0xdd, 0x6b, 0x66, 0x81, 0xe4, 0x19, 0xfa, 0xae, 0x83, 0xed, 0x8d, 0x7d, 0x90, 0x72, 0x7e, - 0x2c, 0xa6, 0x83, 0x01, 0x27, 0x1a, 0x6e, 0xbc, 0x54, 0xe2, 0x5a, 0xdd, 0xe2, 0x8e, 0x61, 0x2c, 0xf5, 0x6d, 0x11, - 0x83, 0x03, 0x76, 0xd1, 0xca, 0x6e, 0x1f, 0x60, 0x5f, 0x39, 0xde, 0xa5, 0xca, 0xee, 0xf4, 0x98, 0x69, 0x2e, 0x5b, - 0x4d, 0x3a, 0xa9, 0xb8, 0x9f, 0xc8, 0x37, 0xb9, 0x83, 0x2e, 0x97, 0x63, 0xcd, 0x5b, 0x0e, 0x40, 0x45, 0x3f, 0x52, - 0x54, 0xf7, 0x33, 0x1c, 0x61, 0x1e, 0xac, 0xdb, 0x7c, 0x72, 0x68, 0x0a, 0x1c, 0x22, 0x4f, 0xda, 0x68, 0x0a, 0xe8, - 0xde, 0xc5, 0xe3, 0xae, 0x7e, 0x5b, 0xba, 0x0b, 0x94, 0x68, 0xaf, 0xe2, 0x86, 0x1f, 0x13, 0x75, 0x3a, 0xd3, 0x86, - 0xd0, 0xbf, 0x32, 0xe2, 0xfe, 0xd2, 0xb8, 0x8a, 0x37, 0xbd, 0xcb, 0xe7, 0x1c, 0xea, 0xec, 0x86, 0x50, 0x00, 0xae, - 0xda, 0xd3, 0xa9, 0x1b, 0x43, 0x7a, 0xa5, 0x44, 0xb7, 0xc1, 0xc1, 0xee, 0xf5, 0x19, 0x47, 0xd1, 0x8f, 0x51, 0x23, - 0xdf, 0x44, 0xe2, 0xb1, 0x1c, 0xc4, 0x8f, 0x0b, 0xba, 0x8a, 0xc4, 0xe3, 0x62, 0x10, 0x3f, 0x96, 0x75, 0xbd, 0x7f, - 0xae, 0xdc, 0xdf, 0x47, 0xe4, 0x59, 0xf7, 0xf6, 0x52, 0x09, 0x1b, 0x03, 0xcf, 0xae, 0x25, 0x84, 0x53, 0xf0, 0x44, - 0xb6, 0x96, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x65, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, 0xd9, 0xe6, 0xd1, - 0x87, 0x53, 0x20, 0xa1, 0xdb, 0x6d, 0xb3, 0xae, 0xd6, 0x80, 0x62, 0x1a, 0x8e, 0xf9, 0x61, 0x31, 0xba, 0xf1, 0xdd, - 0xf5, 0x0f, 0x8b, 0xd1, 0x8a, 0x0c, 0x27, 0x66, 0xf2, 0xe3, 0xd9, 0x78, 0x1e, 0x47, 0x93, 0xba, 0xe3, 0xb4, 0xd0, - 0xf8, 0xa7, 0xde, 0x2d, 0x14, 0x81, 0x53, 0x31, 0x82, 0x23, 0xa7, 0x42, 0x39, 0x29, 0x35, 0x30, 0xfc, 0x0f, 0xaa, - 0x3d, 0x6d, 0xda, 0xeb, 0xb8, 0x4a, 0x56, 0x99, 0xb8, 0xd4, 0xe1, 0xc3, 0x75, 0x74, 0x71, 0x1b, 0xd0, 0xce, 0xbb, - 0x4c, 0x3b, 0x7e, 0x9d, 0x34, 0xe8, 0x89, 0xab, 0x99, 0x01, 0xb7, 0xee, 0x47, 0x68, 0x86, 0xc0, 0x68, 0x79, 0xfe, - 0x0e, 0x31, 0xb7, 0x7f, 0x55, 0x36, 0xbf, 0x8a, 0xf6, 0x39, 0x32, 0x52, 0xb6, 0xc9, 0x48, 0x05, 0x46, 0x98, 0x52, - 0x24, 0x71, 0x15, 0x42, 0x20, 0xfb, 0xcf, 0x29, 0xae, 0xc5, 0xd2, 0x7b, 0x0d, 0xc2, 0x04, 0xdb, 0x05, 0xed, 0x57, - 0xb7, 0x77, 0x5b, 0x69, 0xb1, 0x47, 0xea, 0xfb, 0xdc, 0xd9, 0xae, 0x68, 0xf2, 0xf7, 0x79, 0x03, 0xda, 0x00, 0xa2, - 0xbc, 0xaf, 0x8f, 0x4a, 0xe0, 0x64, 0xc4, 0x0d, 0x25, 0x46, 0x2f, 0xe8, 0xea, 0x44, 0xee, 0xd9, 0xa9, 0x79, 0x53, - 0x31, 0x57, 0x71, 0xe5, 0x9b, 0x3d, 0xf3, 0x1f, 0x0c, 0x05, 0x15, 0x60, 0xe0, 0x6d, 0xce, 0x78, 0x74, 0xa0, 0xbb, - 0x31, 0x3a, 0x2d, 0xd8, 0x2c, 0xa8, 0xcb, 0xba, 0x69, 0xe3, 0x41, 0x23, 0x0e, 0x8a, 0x62, 0x55, 0xa8, 0x91, 0xf0, - 0x44, 0x20, 0x60, 0xca, 0xae, 0x78, 0x64, 0x04, 0x35, 0xbd, 0x09, 0x85, 0x0d, 0x05, 0x7f, 0x95, 0xa8, 0xa6, 0x37, - 0xa1, 0x4d, 0x26, 0x4e, 0x33, 0x88, 0x60, 0x46, 0x6c, 0xf7, 0x5b, 0x40, 0x9b, 0x5b, 0x33, 0xda, 0xd6, 0xb5, 0xd5, - 0x56, 0x21, 0x97, 0x14, 0x29, 0xcb, 0x7f, 0xa7, 0xa6, 0x82, 0x92, 0x5a, 0x2e, 0x7a, 0x93, 0xa6, 0x8b, 0x1e, 0xcf, - 0x8c, 0x24, 0x50, 0xb9, 0xe5, 0x8e, 0xd1, 0x1f, 0xc2, 0x02, 0x8f, 0x98, 0x38, 0xb1, 0x60, 0x6e, 0x35, 0x63, 0xd9, - 0x42, 0x2c, 0x47, 0x6b, 0x09, 0x61, 0x83, 0x8f, 0x59, 0xb6, 0x28, 0xf5, 0x43, 0xe8, 0x0b, 0x4b, 0xdf, 0x82, 0x5d, - 0x6c, 0xb0, 0x96, 0x65, 0x00, 0xbe, 0x17, 0x74, 0xbb, 0x96, 0x65, 0x24, 0x55, 0xf7, 0xe3, 0x1a, 0x4b, 0x50, 0x69, - 0x85, 0x4a, 0x4b, 0x6a, 0x2c, 0x08, 0x7c, 0x55, 0x75, 0xf9, 0x90, 0xec, 0x2a, 0x50, 0x4f, 0x1d, 0x35, 0xe0, 0x14, - 0xa8, 0x2a, 0xb0, 0x20, 0x09, 0x2a, 0x43, 0x57, 0x05, 0xa6, 0x15, 0x98, 0x66, 0xaa, 0x70, 0x51, 0x66, 0x87, 0xd2, - 0xac, 0x97, 0x7c, 0x1e, 0x0f, 0xc2, 0x64, 0x18, 0x93, 0xc7, 0x08, 0xb5, 0x7f, 0x98, 0x47, 0xb1, 0x96, 0x4b, 0xae, - 0x9d, 0x5f, 0xfc, 0xcd, 0x27, 0xec, 0x75, 0xcf, 0x30, 0x58, 0x80, 0xb3, 0xb4, 0xbd, 0xca, 0xc4, 0x3b, 0xd9, 0x0a, - 0x8e, 0x83, 0x59, 0x94, 0xc3, 0xaa, 0x27, 0x47, 0x34, 0x17, 0xb9, 0xf6, 0x2e, 0x42, 0xe4, 0x20, 0xb3, 0xc7, 0x00, - 0xbb, 0x11, 0xbe, 0x0e, 0xad, 0xcd, 0xad, 0xae, 0x10, 0x7f, 0xa3, 0x44, 0xe2, 0x27, 0x29, 0x3f, 0x6e, 0xd6, 0x2a, - 0x57, 0x65, 0xf0, 0x58, 0x75, 0x33, 0x78, 0xa6, 0x7d, 0x8f, 0xb5, 0x7f, 0x6b, 0xbb, 0x39, 0xde, 0x7b, 0xf0, 0xa0, - 0xf5, 0xbf, 0xf5, 0x24, 0x84, 0xf6, 0xca, 0x49, 0xea, 0x8e, 0x1a, 0x3d, 0x33, 0x59, 0x23, 0x2a, 0x61, 0x6a, 0x77, - 0x2a, 0xc7, 0x40, 0x4d, 0x07, 0x70, 0x2d, 0x51, 0x13, 0xf4, 0xa4, 0x60, 0x63, 0x38, 0xe2, 0x2c, 0x0e, 0xda, 0x71, - 0x8c, 0xe2, 0xe5, 0x5c, 0x89, 0x97, 0xf3, 0x19, 0xe3, 0x00, 0xad, 0x05, 0x48, 0xf5, 0x1a, 0xf6, 0x33, 0x57, 0xb0, - 0xc0, 0xe6, 0xce, 0x77, 0x64, 0x81, 0x0c, 0x71, 0xb2, 0x39, 0x4e, 0xf6, 0xb8, 0xd6, 0x73, 0x2f, 0xf0, 0x71, 0x52, - 0x2f, 0xbd, 0xba, 0xca, 0x76, 0x5d, 0x2b, 0x56, 0x2e, 0x8a, 0xc1, 0x04, 0x82, 0xb2, 0x94, 0x8b, 0x62, 0x38, 0x59, - 0xd2, 0x1c, 0x7e, 0x2c, 0x1b, 0xe8, 0x10, 0xab, 0x41, 0x02, 0x97, 0xce, 0x1e, 0x03, 0xde, 0x50, 0x6a, 0x71, 0x37, - 0xd6, 0x91, 0x63, 0x1d, 0xc5, 0x61, 0x18, 0x03, 0xae, 0xac, 0x13, 0x78, 0xdf, 0x7f, 0x7d, 0x6c, 0x02, 0xb2, 0x6a, - 0x57, 0x78, 0x35, 0xca, 0x5d, 0x57, 0x1a, 0x7d, 0x49, 0xe9, 0x09, 0x2f, 0x78, 0x2a, 0xd9, 0xed, 0x7a, 0x06, 0xce, - 0x96, 0x78, 0x48, 0xbc, 0x63, 0x44, 0x2f, 0xa6, 0x8d, 0xcc, 0x9c, 0xc0, 0x99, 0xed, 0x2e, 0xdb, 0x98, 0x1f, 0x3b, - 0xc0, 0xc1, 0x22, 0x08, 0x89, 0x1b, 0xc2, 0x30, 0xb1, 0x59, 0x39, 0xd4, 0x42, 0xb8, 0xae, 0x85, 0xd7, 0x71, 0x5a, - 0xc6, 0xe0, 0x22, 0xad, 0x6d, 0x13, 0xef, 0xa1, 0xeb, 0x9e, 0x1f, 0x73, 0xab, 0x63, 0xb4, 0x85, 0xf4, 0xdb, 0xd1, - 0xe9, 0x03, 0x87, 0x01, 0x68, 0x7a, 0x30, 0xaf, 0xda, 0x67, 0x12, 0x37, 0xa7, 0x9d, 0x20, 0x24, 0x02, 0x51, 0x94, - 0xce, 0x08, 0xd3, 0xbf, 0xd7, 0x5c, 0x56, 0xd1, 0xea, 0x41, 0x9e, 0x39, 0xe4, 0x59, 0xe8, 0x6d, 0x0f, 0x5a, 0x35, - 0x77, 0x83, 0x71, 0xe2, 0x76, 0x7b, 0xe7, 0xff, 0x2d, 0xeb, 0xda, 0x6a, 0x8d, 0x78, 0xdc, 0xae, 0x7e, 0xd0, 0xd8, - 0xab, 0x3d, 0x15, 0x03, 0x66, 0x2d, 0xbd, 0x33, 0xaa, 0xe4, 0x45, 0xc6, 0x4b, 0x3c, 0xa9, 0xd6, 0x0d, 0x1f, 0xef, - 0x9b, 0x6c, 0x64, 0x1e, 0xc8, 0x14, 0x10, 0xcf, 0x6f, 0x52, 0xa3, 0x3e, 0x4e, 0x51, 0x02, 0xfe, 0x4e, 0xc7, 0x37, - 0xa2, 0x1f, 0xed, 0x8b, 0x4b, 0x5e, 0xbd, 0xbd, 0x11, 0xe6, 0xc5, 0x73, 0xab, 0xf3, 0xa7, 0xaf, 0x0b, 0x1f, 0x3a, - 0x1c, 0xb5, 0x77, 0x50, 0x64, 0xc9, 0xc4, 0x6c, 0x62, 0x64, 0x6d, 0x62, 0xfe, 0x51, 0xc1, 0xc5, 0x44, 0x15, 0x7a, - 0xd6, 0xd9, 0x13, 0xa6, 0x00, 0x7d, 0xe3, 0x18, 0x95, 0x8c, 0x61, 0xc1, 0x40, 0x9d, 0xa6, 0x84, 0xe8, 0xa1, 0x98, - 0x63, 0xbc, 0x62, 0x00, 0x85, 0x29, 0x14, 0x88, 0xa2, 0xb3, 0x0f, 0x07, 0x9a, 0xd0, 0xef, 0xdf, 0xa4, 0x3a, 0x03, - 0x2d, 0xeb, 0xa9, 0x04, 0x51, 0x1d, 0x44, 0x5b, 0xe5, 0x45, 0xf8, 0xe3, 0x8a, 0x96, 0x19, 0x5d, 0x09, 0x9a, 0x0a, - 0x9a, 0x64, 0xf4, 0x82, 0x2b, 0x51, 0xf1, 0x85, 0x60, 0x8a, 0xb6, 0x1b, 0xc2, 0xfe, 0xaf, 0x06, 0x5d, 0x6f, 0xc5, - 0x5a, 0x43, 0xbb, 0x13, 0x64, 0x84, 0x16, 0x4b, 0x1d, 0x84, 0x0c, 0x95, 0x93, 0xd0, 0xb5, 0x4a, 0xe3, 0x15, 0xb8, - 0x64, 0x9a, 0x8d, 0x56, 0x71, 0x19, 0x06, 0xf6, 0xab, 0xc0, 0x62, 0x72, 0x60, 0xd2, 0xe9, 0xe6, 0xfc, 0x99, 0xbc, - 0x5a, 0x4b, 0xc1, 0x45, 0xa5, 0x20, 0xfa, 0x0d, 0xee, 0xbb, 0x89, 0xab, 0xce, 0x9a, 0xb5, 0xd2, 0x87, 0xbe, 0xf5, - 0x59, 0x1b, 0xf7, 0x85, 0xc1, 0x31, 0xd8, 0xfb, 0x88, 0x18, 0x48, 0x83, 0x4a, 0xb7, 0x38, 0x34, 0x01, 0xba, 0x74, - 0x48, 0x21, 0x4b, 0xa6, 0x32, 0x55, 0x82, 0x8a, 0x6f, 0xfc, 0x5e, 0xca, 0x6a, 0xf4, 0xe7, 0x86, 0x17, 0x77, 0xa7, - 0x3c, 0xe7, 0x38, 0x46, 0x41, 0x12, 0x8b, 0xeb, 0xb8, 0x0c, 0x88, 0x6f, 0x79, 0x15, 0x1c, 0xa5, 0x26, 0x6c, 0xcc, - 0x5e, 0xd5, 0xa8, 0xf5, 0x92, 0xe8, 0x2b, 0xa3, 0x7c, 0x63, 0x30, 0x34, 0x11, 0x55, 0xd0, 0xf7, 0x5a, 0xdd, 0xd3, - 0xea, 0x86, 0x05, 0xc4, 0x5f, 0x28, 0xbd, 0x50, 0xeb, 0x75, 0x33, 0xe6, 0x86, 0x89, 0x10, 0x34, 0xfa, 0xaa, 0x5e, - 0xd6, 0x9e, 0x5b, 0x9a, 0x8a, 0x8c, 0x1b, 0x6d, 0x73, 0x7e, 0x09, 0x32, 0x3e, 0x67, 0x2e, 0x34, 0xa9, 0x6b, 0xaa, - 0xa0, 0x0a, 0xa3, 0xed, 0x6d, 0x23, 0x9d, 0xde, 0x81, 0x3b, 0x9b, 0x31, 0x3b, 0xd2, 0x2e, 0x8d, 0x35, 0x2d, 0x78, - 0xb9, 0x96, 0xa2, 0x84, 0x30, 0xce, 0xbd, 0x31, 0xbd, 0x8a, 0x33, 0x51, 0xc5, 0x99, 0x38, 0x29, 0xd7, 0x3c, 0xa9, - 0xde, 0xc3, 0x2d, 0x4e, 0x59, 0xdd, 0xd4, 0x25, 0x5c, 0xe9, 0x92, 0x03, 0x0c, 0xa6, 0xa6, 0xe2, 0x1e, 0x3b, 0x83, - 0x8b, 0xea, 0xf7, 0x68, 0x25, 0x31, 0x16, 0xaa, 0x2e, 0x3e, 0x3e, 0x2f, 0x65, 0xbe, 0xa9, 0x40, 0xbb, 0x7b, 0x51, - 0x45, 0x47, 0x4f, 0xd6, 0xb7, 0x53, 0x75, 0x83, 0x89, 0x9e, 0x1c, 0xad, 0x6f, 0x7b, 0xd9, 0xd5, 0x5a, 0x16, 0x55, - 0x2c, 0xaa, 0xa9, 0x42, 0x24, 0x4b, 0xe2, 0x3c, 0x09, 0x27, 0xe3, 0xf1, 0x17, 0x07, 0xc3, 0x03, 0xc8, 0x40, 0xa6, - 0x7f, 0x0d, 0x95, 0xcb, 0xd1, 0x70, 0x32, 0x1e, 0x4f, 0xa5, 0xba, 0xdb, 0x45, 0xa3, 0x49, 0x8d, 0xf5, 0x0c, 0x13, - 0x3d, 0x33, 0x23, 0x7e, 0xbb, 0x8e, 0x45, 0x0a, 0xf1, 0xeb, 0x74, 0xf1, 0x47, 0x4f, 0xc6, 0x8d, 0xf2, 0xed, 0xa7, - 0x4f, 0xeb, 0xdf, 0x6b, 0x13, 0xd6, 0xda, 0xb4, 0xfb, 0xd9, 0xef, 0xc7, 0x6a, 0xbe, 0x67, 0xc7, 0x87, 0xfa, 0xc7, - 0xef, 0x75, 0x3d, 0x7d, 0x5d, 0x84, 0x8b, 0x7f, 0x86, 0x6a, 0x3e, 0x4f, 0x8a, 0x22, 0xbe, 0xab, 0x21, 0x92, 0xa7, - 0x70, 0xde, 0x24, 0xd4, 0xdb, 0x06, 0xf4, 0x88, 0x4c, 0x2f, 0x04, 0x83, 0x6f, 0xde, 0x57, 0x61, 0xc0, 0xcb, 0xf5, - 0x90, 0x8b, 0x2a, 0xab, 0xee, 0x86, 0x98, 0x27, 0xc0, 0x4f, 0x0d, 0x6f, 0xf6, 0xac, 0x30, 0xc4, 0xe6, 0xa2, 0xe0, - 0xfc, 0x2f, 0x1e, 0x2a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1a, 0x8c, 0xc9, 0xd7, 0x54, 0x77, 0x66, 0xf2, - 0x35, 0x98, 0x20, 0x65, 0xed, 0x6f, 0x94, 0x71, 0x62, 0x34, 0xa6, 0xd7, 0x2f, 0xf3, 0x6c, 0x0d, 0x4c, 0xf0, 0x4a, - 0xff, 0xa8, 0x09, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xb3, 0x82, 0x8e, 0x46, 0xa3, 0x8f, 0x59, 0x4d, 0xe8, - 0x5a, 0x74, 0xbc, 0x7f, 0xcf, 0xe9, 0xb9, 0x4c, 0xef, 0xa2, 0x20, 0xa0, 0xab, 0x2c, 0x4d, 0xb9, 0x50, 0x65, 0x9d, - 0xa6, 0xed, 0xbc, 0xaa, 0x85, 0x08, 0xfc, 0xa3, 0xdb, 0x88, 0x10, 0x44, 0x84, 0xbe, 0xdd, 0xeb, 0xd9, 0x68, 0x34, - 0x3a, 0x4d, 0x4d, 0xb5, 0x8e, 0x21, 0x7f, 0x8d, 0xe6, 0x03, 0xce, 0x2e, 0x1f, 0xac, 0x6f, 0x4c, 0xb4, 0x93, 0xc3, - 0xff, 0x1e, 0xce, 0x17, 0xe3, 0xe1, 0xb7, 0xa3, 0xe5, 0xe3, 0x43, 0x1a, 0x04, 0x3e, 0x68, 0x75, 0xa8, 0xad, 0x39, - 0xa6, 0xe5, 0xf1, 0x78, 0x4a, 0xca, 0x01, 0x7b, 0x62, 0x7d, 0x69, 0xbe, 0x78, 0x02, 0x48, 0xa4, 0x28, 0x42, 0x0d, - 0x9c, 0xf4, 0x0f, 0xaf, 0x22, 0xaf, 0x04, 0xe0, 0xa3, 0xd9, 0x48, 0x06, 0x46, 0x0b, 0x38, 0x8e, 0xa0, 0xbc, 0xda, - 0x9a, 0x46, 0xf4, 0x18, 0xcb, 0x4c, 0x54, 0xd0, 0xf1, 0xb4, 0xbc, 0xc9, 0xaa, 0x64, 0x85, 0x81, 0x8d, 0xe2, 0x92, - 0x07, 0x5f, 0x04, 0x51, 0xc9, 0x8e, 0x9e, 0x4e, 0x15, 0xbc, 0x2f, 0x26, 0xa5, 0xfc, 0x12, 0x12, 0xbf, 0x1d, 0x23, - 0x04, 0x2a, 0xd1, 0x1e, 0x8b, 0x58, 0xe3, 0xcb, 0x5c, 0xc6, 0xe0, 0xc1, 0x59, 0x6a, 0x9e, 0xc5, 0x9e, 0x04, 0xd6, - 0xfe, 0xa2, 0xd5, 0x1c, 0x09, 0xcd, 0x09, 0x25, 0x93, 0x87, 0x25, 0x95, 0x5f, 0x4c, 0xd0, 0x2b, 0x08, 0xdc, 0xaa, - 0x23, 0x38, 0xee, 0xac, 0x65, 0x83, 0x5e, 0x3e, 0x29, 0x3b, 0x5c, 0xfc, 0xef, 0x92, 0x2e, 0x07, 0x87, 0x6e, 0x68, - 0xde, 0x6a, 0xf7, 0xd5, 0x0a, 0x19, 0xa5, 0x2a, 0x7c, 0x96, 0x12, 0x6b, 0x7c, 0xca, 0xd9, 0x6c, 0x6b, 0xba, 0x33, - 0xaa, 0x8a, 0xec, 0x2a, 0x24, 0xba, 0x57, 0x0e, 0x14, 0x33, 0x88, 0xb2, 0x11, 0xae, 0x1f, 0xb0, 0x16, 0xf1, 0x3a, - 0x79, 0xcd, 0x8b, 0x2a, 0x4b, 0xd4, 0xfb, 0xeb, 0xc6, 0x7b, 0xa0, 0x06, 0xaa, 0x41, 0xef, 0x0a, 0x06, 0xf3, 0xfc, - 0xb6, 0x00, 0xd0, 0xce, 0x92, 0x17, 0xd7, 0xdc, 0xa7, 0x1b, 0x41, 0x50, 0xbb, 0x66, 0x5e, 0x36, 0x82, 0x4d, 0xc0, - 0x57, 0xef, 0x0a, 0xc0, 0xdc, 0x08, 0x41, 0x6a, 0x0a, 0xa1, 0x70, 0xe0, 0x02, 0x5f, 0x55, 0x45, 0x76, 0xbe, 0xa9, - 0x38, 0x06, 0xfb, 0xf0, 0xe2, 0x26, 0x2a, 0x27, 0x3c, 0x1e, 0x06, 0xf8, 0x23, 0xa0, 0x2a, 0xe0, 0x86, 0xf1, 0xb0, - 0x83, 0x17, 0xea, 0x97, 0x7b, 0xa3, 0xf6, 0x08, 0x7b, 0x9d, 0x86, 0x10, 0x5c, 0x07, 0x1f, 0x02, 0x58, 0x52, 0x84, - 0xbe, 0xc5, 0x53, 0x35, 0x0c, 0x2e, 0xf2, 0x6c, 0xad, 0x93, 0xaa, 0x51, 0x47, 0xf3, 0xa1, 0xd4, 0x8e, 0xe4, 0x80, - 0x7a, 0xe9, 0x31, 0xa6, 0x17, 0x2a, 0x5d, 0x15, 0xe5, 0x8c, 0x50, 0xde, 0xe9, 0x89, 0x71, 0x61, 0xfa, 0x38, 0x44, - 0x7e, 0x79, 0x57, 0xa8, 0xd0, 0x2f, 0x7c, 0x09, 0xe0, 0x57, 0x70, 0xbb, 0xdf, 0x8f, 0xef, 0xa2, 0xb2, 0x9f, 0x71, - 0x76, 0xf8, 0xdf, 0x8b, 0x78, 0xf8, 0xd7, 0x78, 0xf8, 0xed, 0x72, 0x10, 0x0e, 0xed, 0x4f, 0xf2, 0xf8, 0xd1, 0x21, - 0x7d, 0xc9, 0x2d, 0x57, 0x02, 0x0b, 0xbf, 0x11, 0xdc, 0x46, 0xad, 0x84, 0x20, 0x0a, 0xf0, 0x46, 0xe1, 0x56, 0xe3, - 0x04, 0x00, 0xfe, 0x82, 0xff, 0x0a, 0xd0, 0x48, 0xc8, 0x5d, 0x34, 0x40, 0x3f, 0xa0, 0x7e, 0xcf, 0xbe, 0x6a, 0x18, - 0xc8, 0x81, 0x78, 0x42, 0xc5, 0x40, 0x21, 0xba, 0x8c, 0x89, 0x82, 0xfd, 0xb5, 0xd9, 0x77, 0xbb, 0x5e, 0x5b, 0xf2, - 0x83, 0x5f, 0xfa, 0x99, 0x26, 0x66, 0xde, 0xe1, 0x86, 0xb2, 0x96, 0xeb, 0x10, 0xb1, 0xf1, 0xf4, 0xaf, 0x9c, 0x41, - 0xac, 0xc9, 0xeb, 0x0c, 0x7c, 0x18, 0xec, 0x17, 0xe3, 0x39, 0xb0, 0x0d, 0x70, 0xc7, 0x29, 0xf8, 0x45, 0x06, 0x6e, - 0xcd, 0x22, 0xc6, 0x0b, 0xb6, 0x5d, 0x12, 0xfd, 0x7e, 0x2f, 0xcf, 0xc2, 0x5c, 0xe3, 0x2c, 0xe7, 0xb5, 0x11, 0xbb, - 0xa3, 0x4e, 0x18, 0xc4, 0xed, 0x7a, 0x08, 0x86, 0x6a, 0x08, 0x8a, 0x8e, 0xb6, 0xb8, 0x7a, 0x6d, 0x3d, 0x85, 0xe9, - 0xad, 0xaa, 0xaf, 0x18, 0xfd, 0x21, 0x33, 0x81, 0x85, 0xb4, 0x6b, 0x8e, 0x75, 0xcd, 0x31, 0xd2, 0x9e, 0x7e, 0x5f, - 0x34, 0xc8, 0x4f, 0x67, 0xe1, 0x41, 0xa0, 0x4a, 0x95, 0x7b, 0x65, 0x51, 0x6e, 0x4b, 0xf3, 0xc6, 0xb0, 0xa6, 0x79, - 0x66, 0xe3, 0xba, 0xcc, 0x7b, 0xbd, 0x30, 0x44, 0x87, 0x46, 0x2c, 0x15, 0x6b, 0x83, 0xf0, 0x3e, 0x26, 0x61, 0x74, - 0x05, 0xb2, 0xba, 0xf0, 0x8c, 0x13, 0xe4, 0xcb, 0xc0, 0x64, 0x4d, 0x55, 0xeb, 0xe5, 0x84, 0xc7, 0x46, 0xbe, 0x6c, - 0x04, 0x0d, 0xf2, 0x92, 0xa2, 0xde, 0xc4, 0xed, 0xd8, 0x47, 0x2d, 0xa4, 0xc6, 0x6d, 0x3d, 0xed, 0x69, 0x52, 0xd1, - 0x63, 0xbd, 0x4a, 0xfd, 0x02, 0xcb, 0x02, 0x4b, 0x3e, 0x08, 0xed, 0x69, 0x5a, 0x81, 0x19, 0xae, 0x6d, 0x06, 0x43, - 0x3f, 0x1c, 0xda, 0x22, 0x74, 0x46, 0x6d, 0x4b, 0x08, 0xdb, 0x36, 0x08, 0x2b, 0xef, 0x89, 0x7c, 0xf1, 0xc4, 0x63, - 0x84, 0x43, 0x6e, 0x36, 0xb3, 0x68, 0x60, 0x98, 0x5f, 0xc9, 0x66, 0xf3, 0x74, 0x73, 0xbd, 0xa8, 0x98, 0x02, 0xb6, - 0xdb, 0x5a, 0x10, 0xfc, 0xfb, 0x31, 0x9b, 0xe3, 0xdf, 0xac, 0xdf, 0xef, 0x85, 0xf8, 0x8b, 0x63, 0xf0, 0x9e, 0x85, - 0x58, 0xb2, 0x8f, 0x20, 0x53, 0x21, 0x11, 0xa6, 0x2a, 0xe3, 0x37, 0x56, 0x81, 0x05, 0x9c, 0xf9, 0x40, 0xe5, 0xc2, - 0x4c, 0xf6, 0xf2, 0xe2, 0x1a, 0x72, 0xd2, 0x1a, 0xa7, 0x6c, 0x94, 0x25, 0xca, 0x75, 0x21, 0x1b, 0xc5, 0x79, 0x16, - 0x97, 0xbc, 0xdc, 0xed, 0xf4, 0xe1, 0x98, 0x14, 0x1c, 0xd8, 0x53, 0x45, 0xa5, 0x4a, 0xd6, 0x91, 0xea, 0xc6, 0x5f, - 0x86, 0x05, 0xee, 0x53, 0xbe, 0x28, 0x0c, 0x8d, 0x38, 0x80, 0xcb, 0x3b, 0x53, 0xb7, 0xd2, 0x5e, 0x58, 0x40, 0xf3, - 0x4a, 0x42, 0xb6, 0x98, 0xea, 0x59, 0xb4, 0xc6, 0x4c, 0x2c, 0x8a, 0x25, 0x84, 0x91, 0x29, 0x96, 0x60, 0x33, 0xc5, - 0x05, 0x78, 0x91, 0xc4, 0x00, 0x13, 0x17, 0x93, 0x29, 0xc4, 0x33, 0x57, 0xe5, 0xc4, 0x4b, 0x73, 0xbf, 0x4c, 0x1c, - 0x52, 0x06, 0xbc, 0xaa, 0x0d, 0x9a, 0x98, 0x6d, 0x38, 0xea, 0x04, 0x39, 0x31, 0xf9, 0xfd, 0x54, 0x41, 0x88, 0x3b, - 0x71, 0x24, 0x5c, 0x56, 0x6c, 0x17, 0x5e, 0x74, 0x20, 0xc6, 0xa8, 0xc1, 0x29, 0x3f, 0x31, 0x38, 0x1a, 0x83, 0x73, - 0xeb, 0x9d, 0x20, 0x45, 0x18, 0x93, 0xad, 0x64, 0x57, 0x32, 0x14, 0x8b, 0x78, 0x09, 0xca, 0xba, 0x78, 0x09, 0x96, - 0x35, 0xc6, 0x00, 0x13, 0xe4, 0x55, 0xdc, 0x0b, 0xfd, 0x44, 0x71, 0x85, 0x48, 0xcf, 0xca, 0xf5, 0x51, 0xd1, 0x0e, - 0x7d, 0x81, 0xd7, 0x7b, 0x65, 0x8e, 0x9b, 0xf5, 0x58, 0x20, 0xb1, 0x21, 0x60, 0x6c, 0xa4, 0xd3, 0x54, 0x6b, 0xdd, - 0x1b, 0x33, 0x0f, 0x7c, 0x9a, 0x8d, 0x84, 0xac, 0xce, 0x2e, 0x40, 0x84, 0xe2, 0xa3, 0xc1, 0x23, 0xbf, 0x88, 0x3b, - 0xcb, 0xbc, 0xb5, 0x2d, 0x2a, 0xd9, 0x6c, 0x0b, 0x20, 0x7d, 0x3a, 0x5a, 0x94, 0x92, 0x53, 0x94, 0xa4, 0x76, 0x9b, - 0x02, 0x56, 0x92, 0xbf, 0x80, 0x21, 0xd8, 0xd8, 0x81, 0x70, 0x3a, 0x45, 0x88, 0x4f, 0x34, 0x45, 0x64, 0xc5, 0xb0, - 0xa4, 0x38, 0xb6, 0x25, 0xa2, 0x7e, 0xda, 0xb2, 0xec, 0x60, 0x98, 0xa8, 0xb8, 0xcf, 0x53, 0x8f, 0x12, 0x05, 0x01, - 0xd5, 0x43, 0x0e, 0x12, 0x5b, 0xdb, 0x40, 0x78, 0x40, 0x1e, 0xd1, 0x1b, 0xeb, 0xef, 0xb3, 0xce, 0xb3, 0x0b, 0xcd, - 0x51, 0xb9, 0xde, 0x15, 0x66, 0x8c, 0xf0, 0x24, 0x33, 0x30, 0xf9, 0xde, 0x79, 0x66, 0xd4, 0x14, 0x3d, 0x0f, 0x9f, - 0xec, 0x04, 0x23, 0xd2, 0xdd, 0x33, 0xe8, 0x26, 0x78, 0x55, 0x87, 0x8d, 0x76, 0xa5, 0x20, 0x24, 0x4c, 0x2d, 0x9a, - 0x98, 0xf5, 0xac, 0x01, 0xf5, 0x6e, 0xd7, 0xd3, 0x73, 0x75, 0xff, 0xdc, 0xed, 0x76, 0x3d, 0xec, 0xd6, 0xf3, 0xb4, - 0xdb, 0x0a, 0xbc, 0x52, 0x1f, 0xb4, 0xc7, 0x9f, 0xbb, 0xf1, 0xe7, 0x06, 0xc9, 0xa3, 0x74, 0x34, 0xd3, 0xd6, 0x07, - 0xe1, 0x70, 0xd3, 0xbb, 0x46, 0x93, 0xbe, 0xcf, 0x42, 0x49, 0xd7, 0xa2, 0x51, 0x5d, 0xed, 0x4c, 0x2a, 0x1f, 0x5c, - 0xff, 0x0f, 0xaf, 0x02, 0x3c, 0xe2, 0xd4, 0xce, 0xbe, 0xb7, 0x41, 0x45, 0xa3, 0x2d, 0x1c, 0x29, 0x42, 0x0f, 0x48, - 0xc2, 0x7d, 0x2d, 0x6b, 0x71, 0x9b, 0xa7, 0xd9, 0xc3, 0xf4, 0xe9, 0x55, 0xea, 0x5b, 0xdd, 0xbb, 0x65, 0x96, 0x99, - 0x03, 0xaf, 0xa2, 0x38, 0xa0, 0x51, 0x17, 0xed, 0xbb, 0xca, 0xca, 0x12, 0xbc, 0x3c, 0xe0, 0xfa, 0x7c, 0xca, 0x7d, - 0xb8, 0xb9, 0xcb, 0xaa, 0xb9, 0x49, 0x4f, 0xb3, 0x45, 0xb6, 0xdc, 0xed, 0x42, 0xfc, 0xdb, 0xd5, 0x22, 0x47, 0x93, - 0x17, 0xa0, 0xc3, 0xc3, 0xc8, 0x3d, 0x4c, 0x37, 0xce, 0xdb, 0xfc, 0x7f, 0x89, 0x86, 0x93, 0xc0, 0x09, 0xd0, 0x8b, - 0xf9, 0x23, 0x90, 0xc1, 0x18, 0xa7, 0x7e, 0x31, 0xd7, 0x6b, 0x06, 0xa2, 0x6f, 0x89, 0x08, 0x70, 0x74, 0xb1, 0x91, - 0x68, 0x64, 0xc1, 0x49, 0x4d, 0xc0, 0x62, 0xd3, 0x96, 0xf7, 0xc1, 0xd2, 0xb6, 0xaa, 0xb8, 0xf3, 0x96, 0x34, 0xc7, - 0x75, 0xe0, 0x6c, 0xfb, 0xcd, 0x10, 0x9b, 0xb2, 0xab, 0x25, 0x72, 0xbf, 0xbc, 0xa6, 0xbd, 0x71, 0x9d, 0xc0, 0xac, - 0x6d, 0x6b, 0xcb, 0xf8, 0xd9, 0xd2, 0x7f, 0xd2, 0x83, 0xab, 0x8c, 0x9f, 0x16, 0xc6, 0x2a, 0xc1, 0xee, 0x1b, 0xcf, - 0x77, 0x00, 0xc2, 0xb1, 0xf9, 0xf4, 0xf8, 0x34, 0xf3, 0xe8, 0x31, 0x10, 0x1d, 0xf3, 0x51, 0xe9, 0x3e, 0xb2, 0xbb, - 0xd7, 0x0f, 0x80, 0xb7, 0xa8, 0xda, 0x05, 0x2d, 0xca, 0x25, 0x04, 0x12, 0xf5, 0xca, 0x2b, 0x2c, 0x9f, 0x19, 0xb3, - 0x4b, 0x20, 0x43, 0x05, 0x01, 0x9b, 0xa4, 0xae, 0x73, 0x21, 0x56, 0x1d, 0x56, 0xe6, 0x23, 0x09, 0x9b, 0x85, 0x68, - 0xce, 0x19, 0xcc, 0x83, 0xff, 0x0a, 0x06, 0xe5, 0x20, 0x88, 0x82, 0x28, 0x08, 0xc8, 0xa0, 0x80, 0x5f, 0x88, 0x33, - 0x46, 0x30, 0x46, 0x09, 0x74, 0xf8, 0x1d, 0x67, 0x3e, 0x23, 0xf2, 0xa2, 0x11, 0xc6, 0xd2, 0x0d, 0xc0, 0xb9, 0x94, - 0x39, 0x8f, 0xd1, 0xc7, 0xe2, 0x1d, 0x67, 0x19, 0xa1, 0xef, 0xbc, 0x53, 0xf9, 0x11, 0x6f, 0x04, 0xb7, 0xdb, 0x1f, - 0xb6, 0x97, 0x3c, 0xcc, 0x68, 0x6f, 0x4c, 0xdf, 0x71, 0x12, 0x65, 0x0d, 0xe7, 0x61, 0x0e, 0x3d, 0xab, 0x2c, 0x6b, - 0x45, 0x0d, 0xb9, 0x41, 0xb1, 0x2e, 0xb2, 0x4c, 0x4e, 0x86, 0xab, 0xe6, 0x54, 0xe0, 0xba, 0xb3, 0xeb, 0x05, 0x24, - 0x65, 0x42, 0xb3, 0x74, 0x36, 0x7c, 0xb5, 0x6d, 0xd9, 0xf3, 0xd6, 0x29, 0xe4, 0x35, 0x44, 0x45, 0x3f, 0x74, 0x04, - 0xd4, 0xd0, 0x8a, 0xcb, 0x0a, 0x5c, 0x76, 0x4d, 0x7b, 0xb8, 0x69, 0x8f, 0x69, 0xc6, 0x07, 0x88, 0x11, 0xc7, 0xb1, - 0x65, 0x60, 0x37, 0xe1, 0xf0, 0x6c, 0x9c, 0xef, 0xcb, 0x3e, 0xbd, 0x75, 0xb5, 0x78, 0x84, 0xb5, 0xe7, 0xad, 0x90, - 0x10, 0x20, 0x2d, 0x4d, 0xa5, 0xbb, 0x5d, 0x10, 0xc0, 0x00, 0xf7, 0xfb, 0x3d, 0xe0, 0x5a, 0x0d, 0x3b, 0x69, 0x6e, - 0xcd, 0x96, 0xd8, 0x2b, 0x0a, 0x8f, 0x81, 0x28, 0x35, 0xff, 0x19, 0x04, 0x14, 0xcf, 0xdd, 0x10, 0xec, 0x2b, 0xd9, - 0x6c, 0x5b, 0xf4, 0xfb, 0xcf, 0x0b, 0x7c, 0x40, 0x39, 0x28, 0x88, 0x75, 0x75, 0xdc, 0x0a, 0xc3, 0x3e, 0xa9, 0x0f, - 0x71, 0x2c, 0xf2, 0x2c, 0x74, 0x84, 0xa5, 0x32, 0x84, 0x85, 0x2b, 0x46, 0x3a, 0x88, 0x83, 0x9a, 0x74, 0x0e, 0x56, - 0xe5, 0x82, 0x0d, 0xf7, 0x7a, 0x7f, 0x01, 0x2c, 0x78, 0xe6, 0x0d, 0xcb, 0x7b, 0x0f, 0x00, 0xac, 0xd7, 0xc3, 0x85, - 0xe2, 0x5e, 0xbe, 0x6c, 0xa0, 0x4f, 0xe2, 0x4b, 0xcb, 0xae, 0xcf, 0xb5, 0xac, 0x64, 0x34, 0x1a, 0x55, 0xb5, 0x92, - 0x7c, 0x38, 0xf2, 0xd2, 0x42, 0xad, 0x94, 0x71, 0xca, 0x53, 0xb0, 0xf4, 0x36, 0x94, 0x6e, 0xb1, 0xa4, 0x6b, 0x2e, - 0x52, 0xf5, 0xd3, 0x43, 0x9b, 0x6c, 0x10, 0xd7, 0xac, 0xa9, 0xb3, 0xb0, 0xc3, 0x0f, 0x01, 0x1f, 0xed, 0xc3, 0xdc, - 0xa5, 0x6b, 0x58, 0x5a, 0x10, 0x47, 0xc6, 0x05, 0x0f, 0x5d, 0x1e, 0xc0, 0xfa, 0x33, 0x87, 0x24, 0x7e, 0x0a, 0x3f, - 0xe7, 0x26, 0xad, 0xe3, 0x33, 0x9c, 0xcd, 0xa8, 0x54, 0x37, 0x82, 0xf6, 0x6b, 0x48, 0x24, 0x06, 0xd9, 0xb8, 0xc1, - 0x50, 0xb4, 0xee, 0x36, 0x70, 0xe5, 0xb7, 0xf4, 0xce, 0xa7, 0x41, 0x80, 0x6d, 0x8d, 0xc5, 0x00, 0x60, 0x28, 0xfe, - 0x40, 0x55, 0x8d, 0xb9, 0xa2, 0x98, 0x86, 0xa9, 0x44, 0x7b, 0xc7, 0x71, 0x1d, 0x35, 0xae, 0xb2, 0x82, 0x95, 0xd6, - 0x96, 0xd7, 0xbd, 0xa5, 0x85, 0x2d, 0x01, 0xd5, 0x60, 0xb8, 0x13, 0xc0, 0x67, 0x44, 0xaa, 0x03, 0x41, 0x76, 0x1f, - 0x1c, 0x34, 0x67, 0x09, 0x9e, 0x87, 0x21, 0xfc, 0x81, 0x85, 0x03, 0xcb, 0x52, 0xf5, 0x73, 0x35, 0x8d, 0xe1, 0xdc, - 0xcd, 0xd5, 0x0e, 0x9f, 0xaf, 0x40, 0x91, 0xa7, 0xe6, 0xd4, 0x5c, 0xbe, 0xf2, 0xc6, 0x7e, 0x8f, 0x09, 0xe6, 0x31, - 0xb3, 0x0d, 0xbf, 0xf5, 0x74, 0x5b, 0x5f, 0x58, 0x37, 0x70, 0xd2, 0x5e, 0x38, 0xed, 0xc5, 0x76, 0x65, 0x20, 0xee, - 0xea, 0x86, 0x10, 0xe1, 0x95, 0x26, 0x16, 0x59, 0x43, 0xa6, 0x63, 0xb1, 0x31, 0x54, 0x9b, 0x8a, 0x67, 0x5a, 0x21, - 0x5e, 0x4e, 0xd5, 0x85, 0xa9, 0x95, 0xca, 0x84, 0x41, 0x98, 0x29, 0x61, 0x51, 0x65, 0xe0, 0xb3, 0x5f, 0x21, 0xc5, - 0xb5, 0xf5, 0xbc, 0xc1, 0xe5, 0x9b, 0x99, 0x36, 0xdb, 0x4f, 0x5f, 0xe6, 0xf1, 0xe5, 0x6e, 0x17, 0x76, 0xbf, 0x00, - 0xf3, 0xcb, 0x52, 0x69, 0xd4, 0xc0, 0xe9, 0x21, 0x44, 0x3f, 0xe7, 0x7b, 0x72, 0x4e, 0x1c, 0x27, 0xd7, 0x6e, 0xde, - 0x7c, 0x2f, 0xc5, 0x08, 0x2c, 0xe0, 0xc4, 0x45, 0x3a, 0xd0, 0x52, 0xc1, 0x69, 0xcb, 0x78, 0x6f, 0xd3, 0x3b, 0x4a, - 0x85, 0x57, 0x0b, 0x4d, 0x42, 0x2a, 0x77, 0x2f, 0xb1, 0xa3, 0x06, 0x9c, 0x93, 0xba, 0x83, 0x80, 0x93, 0x9a, 0x6e, - 0xac, 0x55, 0x9c, 0x9a, 0x04, 0xef, 0x95, 0x1e, 0xba, 0x44, 0x3b, 0x71, 0xbb, 0x6d, 0x55, 0xb6, 0x50, 0x1f, 0x0f, - 0x72, 0x96, 0xa8, 0xe3, 0x01, 0x85, 0x2e, 0xea, 0x68, 0xc8, 0x97, 0xa4, 0xd0, 0x2b, 0x47, 0xab, 0x56, 0xf7, 0x25, - 0x03, 0xa5, 0x5a, 0x05, 0x79, 0x4d, 0xac, 0xbb, 0x56, 0xd6, 0x58, 0x5c, 0x39, 0x21, 0x85, 0x4d, 0xf8, 0xdc, 0x52, - 0x2c, 0xac, 0x60, 0x6f, 0x4c, 0x7d, 0xe1, 0x12, 0xa1, 0xed, 0x6e, 0x43, 0x4c, 0x32, 0x58, 0x37, 0xbb, 0xdd, 0xab, - 0x22, 0x5c, 0x64, 0x4b, 0x2a, 0x47, 0x59, 0x8a, 0x10, 0x62, 0xc6, 0x43, 0xd7, 0x76, 0xc1, 0x4c, 0x0c, 0x75, 0xed, - 0xf1, 0x92, 0x4c, 0xb1, 0x36, 0x49, 0x8e, 0xe2, 0x73, 0x59, 0xa8, 0xb5, 0x46, 0x08, 0x1e, 0xee, 0x7f, 0xa4, 0x10, - 0xc3, 0xcd, 0xac, 0xbb, 0x5f, 0xf7, 0x6e, 0x88, 0x7f, 0x40, 0x20, 0x81, 0x92, 0xbd, 0x2a, 0x46, 0xe7, 0x99, 0x48, - 0x71, 0xa7, 0xaa, 0xa8, 0xb8, 0x6a, 0x1d, 0x34, 0x5b, 0x6e, 0xef, 0xc5, 0x96, 0x28, 0x40, 0x5c, 0x63, 0xa1, 0x19, - 0xcf, 0xca, 0x59, 0x8a, 0x64, 0x14, 0x1b, 0x12, 0x95, 0x5e, 0x54, 0x74, 0x9f, 0xa7, 0x31, 0x3d, 0x74, 0x6b, 0x10, - 0x5c, 0x35, 0xf7, 0x36, 0xd2, 0x62, 0x49, 0x88, 0x9a, 0x00, 0x09, 0x1b, 0xd5, 0x9c, 0x5a, 0x97, 0xe2, 0x61, 0x56, - 0xf9, 0x4c, 0x1f, 0xc4, 0x97, 0x02, 0x78, 0x58, 0x6f, 0x7b, 0x5f, 0x09, 0x8f, 0xb5, 0xc1, 0xb7, 0xbb, 0xdd, 0xa5, - 0x58, 0x04, 0x81, 0xc7, 0x68, 0x7e, 0xa7, 0x24, 0xe6, 0xbd, 0x31, 0x85, 0x15, 0xef, 0xbb, 0xb4, 0x75, 0x93, 0x5a, - 0x6b, 0x81, 0xba, 0xc7, 0xf5, 0x01, 0xcf, 0x53, 0xe2, 0x68, 0x47, 0xe5, 0x54, 0x5a, 0x5d, 0x39, 0x76, 0x45, 0x60, - 0x60, 0xe8, 0x1f, 0x52, 0xb6, 0x05, 0x73, 0x3c, 0xb0, 0xb6, 0x41, 0x3f, 0x25, 0xa5, 0x85, 0x19, 0xa3, 0x31, 0x8b, - 0xdc, 0x54, 0xd1, 0x11, 0xd7, 0xd1, 0xdb, 0x79, 0xf4, 0xb7, 0xa7, 0x63, 0x5a, 0xc4, 0x22, 0x95, 0x57, 0xa0, 0x82, - 0x00, 0x65, 0x08, 0x1a, 0xfe, 0x6b, 0x6a, 0x00, 0x1a, 0x04, 0x37, 0x00, 0xff, 0xe8, 0x74, 0x1a, 0xb4, 0x35, 0xf9, - 0x98, 0xa4, 0xaa, 0xc8, 0x79, 0x1b, 0xca, 0x4c, 0x25, 0x87, 0xe4, 0x71, 0x09, 0x78, 0x8e, 0xd8, 0x2c, 0x65, 0x73, - 0xa1, 0x36, 0x9b, 0x7a, 0xad, 0xd8, 0x91, 0xdb, 0x46, 0xd1, 0x66, 0x2d, 0x6a, 0x3b, 0x89, 0xc5, 0x72, 0x7a, 0x6b, - 0x85, 0x81, 0x53, 0xd3, 0x9a, 0x9b, 0x3d, 0xe8, 0x34, 0x5b, 0x9f, 0xc9, 0x4d, 0x80, 0x38, 0xc0, 0x70, 0xdd, 0x2e, - 0x6e, 0x96, 0x84, 0xde, 0xb2, 0x5b, 0x2b, 0x56, 0xbd, 0xb1, 0x72, 0x11, 0x93, 0x76, 0x33, 0x98, 0xc0, 0x65, 0x9c, - 0x15, 0xf6, 0x85, 0x56, 0x37, 0x14, 0x1d, 0x6d, 0x93, 0xf6, 0xf3, 0x8e, 0x76, 0xc3, 0x05, 0xdf, 0x8a, 0x75, 0x9c, - 0x1b, 0xd2, 0x54, 0xa1, 0x47, 0x07, 0x7a, 0x3b, 0x04, 0x34, 0x67, 0x63, 0xba, 0xa2, 0x29, 0x5e, 0xa0, 0xe9, 0x06, - 0xcc, 0x52, 0x2e, 0xa0, 0xaf, 0xdd, 0x3e, 0xc9, 0x17, 0xaa, 0x27, 0xc2, 0x5b, 0xa2, 0xe0, 0xcb, 0x91, 0x82, 0x57, - 0x56, 0xce, 0x63, 0x33, 0x87, 0x80, 0xc7, 0xa2, 0x4a, 0xf4, 0x4e, 0x8a, 0x4b, 0x50, 0xa6, 0xc2, 0x11, 0x68, 0xaa, - 0x46, 0x2c, 0xe1, 0x00, 0xb7, 0x17, 0x4f, 0x03, 0x42, 0x41, 0xaa, 0xbb, 0xb1, 0x2b, 0xf2, 0x96, 0xcd, 0xb6, 0xb7, - 0x60, 0x16, 0x5b, 0x6d, 0xca, 0xd6, 0x57, 0x36, 0xd9, 0x7d, 0x5c, 0x13, 0x6c, 0xbb, 0xb7, 0x41, 0xc2, 0x5b, 0x7a, - 0x43, 0xb6, 0x37, 0xfd, 0x7e, 0x08, 0xfd, 0x21, 0x54, 0x77, 0xe8, 0xb6, 0xb3, 0x43, 0xb7, 0x3e, 0xf3, 0x6b, 0xf5, - 0x7c, 0xca, 0x1b, 0xe2, 0x03, 0x9a, 0x68, 0xd1, 0x75, 0x7c, 0x07, 0x9b, 0x3a, 0xaa, 0xa8, 0xaa, 0x3c, 0x4a, 0x28, - 0xa8, 0x80, 0x33, 0x5e, 0x9e, 0x72, 0x8c, 0x6d, 0xaa, 0x9f, 0xde, 0x69, 0x5e, 0x6d, 0x63, 0xd6, 0x66, 0xb9, 0x39, - 0x07, 0x8b, 0x80, 0x73, 0x1e, 0x5d, 0x69, 0x5a, 0x72, 0xe9, 0x31, 0xf5, 0x67, 0x38, 0x2a, 0xc1, 0x45, 0x9c, 0xe5, - 0x3c, 0x0d, 0xe8, 0x45, 0xb3, 0xff, 0xa1, 0xb6, 0x95, 0x5a, 0x35, 0xce, 0xdc, 0xeb, 0x90, 0x6c, 0xff, 0xc7, 0x06, - 0xea, 0x75, 0x88, 0x11, 0x51, 0xcd, 0x82, 0x7e, 0xcb, 0x20, 0x36, 0x66, 0x50, 0x6e, 0x92, 0x84, 0x97, 0x65, 0x60, - 0x94, 0x5a, 0x1b, 0xb6, 0x31, 0xe7, 0xd9, 0x23, 0x36, 0x7b, 0xd4, 0x63, 0xec, 0x96, 0xd0, 0x44, 0xeb, 0x84, 0x4c, - 0x8d, 0x91, 0xa7, 0x05, 0xd2, 0x1d, 0x8a, 0xb2, 0x8b, 0xf0, 0x2d, 0x0a, 0x59, 0xda, 0xfb, 0xdc, 0x9c, 0xc8, 0xea, - 0x1b, 0x6d, 0x74, 0x11, 0xa9, 0x44, 0x90, 0x8d, 0xdf, 0x20, 0x60, 0x2f, 0x34, 0x3b, 0x20, 0xdb, 0x15, 0x3b, 0xa5, - 0x67, 0xd6, 0x04, 0x06, 0x5e, 0xbf, 0x55, 0x89, 0x66, 0x94, 0x15, 0xd1, 0x55, 0x46, 0x2e, 0x77, 0x21, 0x89, 0xce, - 0x42, 0xe2, 0xe7, 0x86, 0xa5, 0x75, 0x1d, 0xa2, 0x98, 0xd9, 0x6c, 0x78, 0xd5, 0xdd, 0x47, 0x8d, 0x6d, 0x65, 0x7c, - 0xaa, 0x6f, 0x6d, 0x1a, 0x99, 0x42, 0x5f, 0x87, 0x93, 0x7e, 0x1f, 0xfe, 0x6a, 0xfa, 0x81, 0xb7, 0x14, 0xfc, 0xc5, - 0x1e, 0x91, 0x3a, 0x61, 0x01, 0xc0, 0x11, 0xe6, 0xbc, 0x6a, 0x4e, 0xe0, 0x23, 0x36, 0xdb, 0x3e, 0x0a, 0x4f, 0x1b, - 0x33, 0x77, 0x17, 0xe2, 0xa5, 0x2a, 0xe9, 0x79, 0xf3, 0x64, 0x06, 0x62, 0x1d, 0x9a, 0xfd, 0x7a, 0xcb, 0xac, 0x3e, - 0x01, 0x88, 0xd4, 0xad, 0x75, 0x28, 0xc5, 0x8f, 0x4d, 0x97, 0xc9, 0x36, 0x65, 0x6d, 0x26, 0x4a, 0xa9, 0x48, 0x9a, - 0x8b, 0x00, 0xfa, 0x0d, 0xc3, 0x51, 0x03, 0xbc, 0xb7, 0x1e, 0x7b, 0x33, 0x34, 0xde, 0x98, 0x1a, 0x7a, 0xb6, 0xd5, - 0xcb, 0xdb, 0x51, 0x08, 0x33, 0x16, 0xd1, 0xad, 0x3b, 0x16, 0xc3, 0x53, 0xfa, 0x16, 0x2a, 0x7c, 0x1d, 0x62, 0x34, - 0x5d, 0x52, 0xd7, 0xd3, 0x8d, 0xda, 0x4a, 0x37, 0x84, 0xe6, 0x18, 0xc5, 0xc7, 0x6b, 0xdb, 0x1d, 0x35, 0x42, 0x7b, - 0x42, 0x79, 0x78, 0x4b, 0x2b, 0x7a, 0x63, 0x59, 0x04, 0x27, 0x3f, 0xf6, 0xf2, 0x13, 0x7a, 0xee, 0x09, 0x4c, 0x8a, - 0xb6, 0x06, 0xf0, 0x07, 0xd4, 0x0f, 0x67, 0xf5, 0xd4, 0x4a, 0x39, 0x3c, 0x85, 0x2f, 0xd9, 0x82, 0x5c, 0x41, 0x2f, - 0xd6, 0x98, 0xcd, 0x62, 0xd0, 0x41, 0xed, 0xed, 0x0e, 0x6f, 0x52, 0xca, 0x10, 0xad, 0xef, 0x1c, 0xc4, 0xd3, 0x3f, - 0x40, 0xd3, 0x07, 0x69, 0x61, 0x4a, 0x37, 0x28, 0xe0, 0x01, 0x7d, 0x53, 0xbf, 0x9f, 0xe3, 0x73, 0xed, 0x59, 0x62, - 0x61, 0x8f, 0x57, 0x84, 0xae, 0xbc, 0xb8, 0x51, 0x20, 0x6d, 0x76, 0xac, 0x02, 0xb0, 0x22, 0x09, 0x34, 0x22, 0x01, - 0x4b, 0x1d, 0x4f, 0x5c, 0xb6, 0x45, 0x03, 0x92, 0xa8, 0xa4, 0x90, 0x25, 0x92, 0xc0, 0x0f, 0x23, 0x08, 0x51, 0x14, - 0x83, 0xb8, 0x57, 0x2f, 0xaf, 0xb8, 0xa6, 0x06, 0x9c, 0x28, 0x82, 0x09, 0xd6, 0xe9, 0x14, 0x88, 0xad, 0xd8, 0xac, - 0xc1, 0xf3, 0xd2, 0x71, 0xe2, 0xc8, 0x12, 0xa0, 0x41, 0x9a, 0x2f, 0x9d, 0x76, 0xcb, 0xdb, 0x13, 0x2d, 0x55, 0x6c, - 0xe1, 0xbd, 0x58, 0x5a, 0xee, 0xb1, 0xf2, 0xb7, 0x03, 0xed, 0x85, 0xd5, 0x9e, 0x88, 0x1a, 0xac, 0xec, 0xda, 0x76, - 0x6d, 0x28, 0x0d, 0xd5, 0xbd, 0x72, 0x4c, 0x40, 0x45, 0xd7, 0x71, 0xb5, 0x8a, 0xb2, 0x11, 0xfc, 0xd9, 0xed, 0x82, - 0xc3, 0x00, 0x2c, 0x20, 0x7f, 0x79, 0xff, 0x53, 0x84, 0xe1, 0x99, 0x7e, 0x79, 0xff, 0xd3, 0x6e, 0xf7, 0x74, 0x3c, - 0x36, 0x5c, 0x81, 0x53, 0xeb, 0x00, 0x7f, 0x60, 0xd8, 0x06, 0xbb, 0x64, 0x77, 0xbb, 0xa7, 0xc0, 0x41, 0x28, 0xb6, - 0xc1, 0xec, 0x62, 0xe5, 0xc8, 0xa5, 0x58, 0x0d, 0xbd, 0x23, 0x01, 0xab, 0x6e, 0x8f, 0xa5, 0xd8, 0xa7, 0x3e, 0x2a, - 0x04, 0xa3, 0x5e, 0xf4, 0x2f, 0x3a, 0x05, 0x96, 0x14, 0x4c, 0x57, 0x83, 0x55, 0x55, 0xad, 0xcb, 0xe8, 0xf0, 0x30, - 0x5e, 0x67, 0xa3, 0x32, 0x83, 0x6d, 0x5e, 0x5e, 0x5f, 0x02, 0xa0, 0x42, 0x40, 0x1b, 0xef, 0x36, 0x22, 0x33, 0x2f, - 0x96, 0x74, 0x95, 0xe1, 0x9a, 0x04, 0xb3, 0x83, 0x9c, 0x5b, 0xdd, 0xe4, 0x94, 0xd8, 0x07, 0xb0, 0x39, 0xdc, 0xed, - 0x1a, 0xfc, 0xc2, 0x6c, 0xf4, 0x74, 0xbe, 0xca, 0xb4, 0x41, 0x27, 0x37, 0xfb, 0x9f, 0x44, 0x5e, 0x1a, 0x2a, 0x3e, - 0xc9, 0xf4, 0x45, 0x06, 0x7c, 0x1e, 0x7b, 0x23, 0x42, 0x9f, 0xe5, 0x6a, 0xb4, 0x06, 0xd8, 0xd8, 0xec, 0xe2, 0x6e, - 0x94, 0x72, 0x88, 0x48, 0x11, 0x58, 0x75, 0xcd, 0x2a, 0x23, 0xbe, 0x4d, 0xc5, 0x5d, 0x4b, 0x15, 0xf6, 0x46, 0x78, - 0xce, 0x2a, 0xdc, 0x38, 0xca, 0xf4, 0x26, 0x51, 0xf8, 0x02, 0x85, 0xa8, 0x1c, 0x8d, 0xe9, 0x9c, 0x40, 0x2a, 0xf3, - 0x98, 0x50, 0xcc, 0xe1, 0xde, 0xfd, 0x92, 0x3a, 0x73, 0x19, 0x5f, 0xb8, 0xf7, 0xc2, 0x97, 0x99, 0xdc, 0x4a, 0x00, - 0x45, 0x52, 0xb5, 0xff, 0xfc, 0x09, 0xa9, 0xf1, 0x3f, 0x53, 0xad, 0x01, 0xe8, 0xfd, 0x0c, 0x35, 0x39, 0x82, 0x80, - 0xad, 0x98, 0xfa, 0x68, 0xfa, 0x56, 0x32, 0xff, 0x01, 0x75, 0x3b, 0x82, 0x6d, 0x55, 0xfc, 0x9c, 0xa8, 0xa2, 0x05, - 0x4f, 0x37, 0x22, 0x8d, 0x45, 0x72, 0x17, 0xf1, 0x7a, 0x8a, 0x25, 0x31, 0x1b, 0x21, 0xeb, 0xe7, 0x66, 0x17, 0x7e, - 0x2a, 0x1a, 0x26, 0xe0, 0xb4, 0xf4, 0xb7, 0x95, 0xb7, 0x99, 0x2c, 0xe3, 0x8c, 0x4c, 0xb9, 0x42, 0xec, 0xb6, 0xfa, - 0x1e, 0x73, 0x82, 0x3f, 0x39, 0x7a, 0x42, 0xe8, 0xad, 0x9c, 0x96, 0x08, 0x4a, 0x27, 0x52, 0xeb, 0xaa, 0x89, 0xfd, - 0x9a, 0x42, 0x14, 0x07, 0xc1, 0x20, 0x74, 0xa7, 0x69, 0x9f, 0xe2, 0xfb, 0x6c, 0xd9, 0x6f, 0x4c, 0xd9, 0x92, 0x6c, - 0x05, 0x74, 0x4c, 0x3a, 0x6f, 0x4f, 0x6f, 0xcf, 0xce, 0xbd, 0xdf, 0xa0, 0x09, 0x07, 0xd5, 0x0d, 0xb4, 0xab, 0x20, - 0xd3, 0x18, 0xc5, 0x66, 0x31, 0xd6, 0x6e, 0x4d, 0x44, 0x10, 0x74, 0xba, 0x9c, 0x87, 0xed, 0x76, 0x42, 0x7c, 0x09, - 0x24, 0x50, 0xe0, 0xca, 0x45, 0x39, 0x09, 0x89, 0xba, 0x90, 0xe9, 0xc9, 0xba, 0x96, 0x2c, 0xd0, 0x6b, 0xec, 0x28, - 0xa0, 0x27, 0xdc, 0x3e, 0x05, 0xf4, 0x7d, 0xc1, 0x4e, 0xf8, 0x20, 0x18, 0x62, 0x7c, 0xd5, 0x80, 0xde, 0x48, 0xf5, - 0x08, 0x1e, 0xc2, 0xc0, 0x72, 0xd1, 0x97, 0x05, 0x43, 0x58, 0xa1, 0x3f, 0x53, 0x36, 0xf9, 0xfa, 0x1b, 0x37, 0xbf, - 0xe7, 0x5a, 0xcc, 0x0e, 0x42, 0x71, 0x7b, 0x3d, 0x01, 0xe2, 0x57, 0xf1, 0x2b, 0xb0, 0xae, 0xd6, 0x12, 0x6f, 0x37, - 0x3d, 0x7f, 0x08, 0x5f, 0x8e, 0x6e, 0x3f, 0x29, 0xcd, 0x27, 0x10, 0xa4, 0xc6, 0x49, 0xca, 0xdd, 0x77, 0x1f, 0xa5, - 0xab, 0x08, 0x46, 0x0b, 0x10, 0xeb, 0xee, 0xad, 0xe4, 0xac, 0x29, 0xfc, 0xc7, 0x3a, 0xdf, 0x63, 0xec, 0x10, 0x79, - 0x8a, 0xd3, 0xdf, 0x00, 0xc3, 0xbe, 0xf3, 0x6f, 0x65, 0xd6, 0x90, 0xe8, 0x5c, 0x7d, 0x04, 0xf4, 0x7f, 0xac, 0xc7, - 0xef, 0x04, 0x25, 0x7d, 0x49, 0x9c, 0x23, 0x5c, 0x11, 0x2f, 0xd1, 0x54, 0xaf, 0x37, 0xae, 0xe9, 0x5f, 0x85, 0x79, - 0xa1, 0x15, 0x1c, 0xf6, 0xad, 0x51, 0x78, 0xe0, 0x99, 0xf7, 0xab, 0x68, 0x08, 0xba, 0x7f, 0xc3, 0xbd, 0xf1, 0xab, - 0x60, 0x19, 0xde, 0x94, 0xb3, 0xcc, 0xdc, 0xe1, 0x6e, 0x32, 0x91, 0xca, 0x1b, 0xc6, 0x82, 0x8d, 0x50, 0xe6, 0xab, - 0x69, 0x30, 0xdf, 0xd6, 0x91, 0x4a, 0x76, 0xdf, 0xbf, 0x69, 0x9c, 0xb0, 0xd9, 0x20, 0x38, 0xad, 0x64, 0x11, 0x5f, - 0xf2, 0x60, 0xaa, 0x55, 0x14, 0x59, 0xd6, 0xef, 0x67, 0x80, 0x0c, 0xe3, 0xb4, 0x77, 0xf0, 0x64, 0xa9, 0x99, 0x09, - 0x71, 0x6d, 0x75, 0x16, 0xf0, 0xd6, 0x8c, 0xe6, 0x49, 0x05, 0xbb, 0xcc, 0x57, 0x52, 0xfc, 0xd1, 0x92, 0x64, 0x63, - 0xfd, 0x0d, 0x19, 0xb6, 0x95, 0xcf, 0x9c, 0x03, 0xc6, 0xcc, 0x8d, 0x54, 0x41, 0xee, 0x7a, 0xc0, 0x08, 0x21, 0x11, - 0x10, 0xce, 0x62, 0xe2, 0x4e, 0x98, 0xf0, 0x8f, 0x2e, 0x30, 0x4e, 0x8c, 0x81, 0x71, 0x3e, 0xca, 0x90, 0xd3, 0x13, - 0x3e, 0x48, 0x1a, 0xb3, 0xf5, 0x87, 0x2a, 0x91, 0x5e, 0x4b, 0x42, 0xcf, 0xe0, 0xf7, 0xb8, 0xc5, 0x03, 0x35, 0x82, - 0x53, 0xba, 0x9b, 0xd3, 0xe1, 0xcb, 0x82, 0x0c, 0xff, 0x04, 0xef, 0xae, 0xd8, 0x5e, 0x96, 0x13, 0x58, 0xdc, 0xb1, - 0x57, 0x3c, 0xcd, 0x55, 0x8b, 0x13, 0xe2, 0x11, 0x8b, 0xdc, 0x27, 0x16, 0x30, 0xa2, 0x86, 0xd1, 0xf8, 0xf1, 0xf4, - 0xed, 0x1b, 0x8d, 0xd9, 0x94, 0xfb, 0x1f, 0xc0, 0x88, 0x6a, 0x69, 0xbb, 0x1d, 0xf0, 0xd5, 0x08, 0x0d, 0xb6, 0x53, - 0x37, 0xd8, 0xfd, 0xbe, 0x49, 0x9b, 0x95, 0x5e, 0x36, 0x27, 0x06, 0xdd, 0x53, 0xda, 0xac, 0x94, 0x41, 0x6d, 0x57, - 0xe1, 0x68, 0x3e, 0x6b, 0xc4, 0xaa, 0xde, 0x87, 0xe1, 0x8a, 0xc6, 0x56, 0x56, 0x6e, 0x77, 0x13, 0x8e, 0x6c, 0x02, - 0x5c, 0x9f, 0x82, 0xb2, 0x6a, 0xce, 0x41, 0x0b, 0x3a, 0x13, 0x38, 0xa2, 0xdd, 0x2e, 0x84, 0x08, 0x1c, 0xc5, 0x70, - 0x32, 0x0f, 0x8b, 0xe1, 0x50, 0x0d, 0x7c, 0x41, 0x48, 0xf4, 0x57, 0xb1, 0xc8, 0x96, 0x0a, 0xb1, 0xc7, 0xdf, 0x49, - 0xbf, 0x16, 0x8a, 0x53, 0xee, 0xfd, 0x2a, 0xc8, 0xf6, 0xb7, 0x14, 0x63, 0x0e, 0x3a, 0xcd, 0x66, 0x06, 0x12, 0xd6, - 0x93, 0x8a, 0xa8, 0x75, 0x64, 0x67, 0x03, 0x54, 0xb1, 0x68, 0x0a, 0x0b, 0xea, 0x16, 0x4f, 0xac, 0x67, 0xf4, 0x1e, - 0x54, 0x82, 0xa8, 0x16, 0xec, 0xc6, 0x70, 0xad, 0xfd, 0x25, 0x42, 0x49, 0x39, 0x69, 0x32, 0x33, 0x56, 0x34, 0x58, - 0x80, 0x90, 0x34, 0x2e, 0xab, 0xd7, 0x32, 0xcd, 0x2e, 0x32, 0x40, 0x4c, 0x70, 0xfe, 0x73, 0xb2, 0xf1, 0xe6, 0x99, - 0x9a, 0x97, 0xae, 0xc4, 0xb9, 0x85, 0xf9, 0xe8, 0x7a, 0x4b, 0x0b, 0x12, 0x15, 0x40, 0xa3, 0x7c, 0x2d, 0xcf, 0xdf, - 0xf7, 0xac, 0x42, 0xf6, 0x3f, 0x9c, 0x2a, 0xdb, 0x21, 0x3e, 0x63, 0x15, 0xf1, 0x4e, 0xeb, 0x4a, 0x89, 0x34, 0x3a, - 0xda, 0x06, 0xc4, 0xb0, 0x65, 0xdf, 0xa2, 0x86, 0x0f, 0xc2, 0x0c, 0x3a, 0xc9, 0x0f, 0x7a, 0x46, 0xc7, 0xd6, 0x40, - 0xd2, 0xd7, 0x22, 0xf8, 0x1a, 0x1d, 0xe9, 0x44, 0x99, 0x46, 0x62, 0x0a, 0x89, 0x7e, 0xbd, 0xd0, 0x1a, 0xcb, 0x28, - 0xfb, 0x8a, 0xfc, 0xef, 0x75, 0xf7, 0x7e, 0x15, 0xbb, 0x1d, 0x4c, 0xb2, 0xe7, 0x71, 0x05, 0x9b, 0x1a, 0xb5, 0x42, - 0x38, 0x3b, 0x27, 0x15, 0x6a, 0xc7, 0x7a, 0x61, 0x09, 0xe4, 0x01, 0x6c, 0x45, 0x1a, 0x94, 0x41, 0xb2, 0xbf, 0x8a, - 0x85, 0x58, 0x3a, 0x51, 0x8e, 0x54, 0x78, 0x5f, 0x72, 0x94, 0x72, 0xb8, 0x8a, 0x85, 0x05, 0x43, 0x7e, 0x75, 0x74, - 0x51, 0xc8, 0x2b, 0x90, 0x94, 0x18, 0x86, 0xca, 0xf2, 0xba, 0xb8, 0x6a, 0x4b, 0x42, 0x7b, 0x67, 0x00, 0xc2, 0x52, - 0x80, 0xe0, 0xa5, 0x51, 0x43, 0xcc, 0xb6, 0x6a, 0x77, 0x45, 0xf7, 0x92, 0x03, 0xea, 0x74, 0xd7, 0x6e, 0xbd, 0x29, - 0xdb, 0x6c, 0x2b, 0x2e, 0xfc, 0x03, 0x4a, 0x3f, 0xe1, 0x83, 0xc2, 0xa7, 0x12, 0xb8, 0xf1, 0xd5, 0x26, 0xcb, 0x2e, - 0xee, 0x70, 0xe9, 0x57, 0x8d, 0xf1, 0xeb, 0xf7, 0x7b, 0x6a, 0x21, 0x34, 0x52, 0x81, 0xf9, 0xf6, 0x99, 0xa9, 0xca, - 0x68, 0x4a, 0xed, 0x25, 0xb8, 0x72, 0xf6, 0x23, 0xa8, 0x88, 0xeb, 0x8a, 0x4c, 0xa6, 0x06, 0xe8, 0xc0, 0xcb, 0x0a, - 0xb7, 0xb2, 0x00, 0x8f, 0x9d, 0x80, 0xec, 0x76, 0x3c, 0x0c, 0xf4, 0xa1, 0x13, 0xf8, 0x5b, 0xf2, 0x14, 0x99, 0x35, - 0xfb, 0xf8, 0xb3, 0x16, 0xfc, 0x63, 0x0b, 0x7e, 0x42, 0x71, 0xa7, 0x95, 0xf9, 0xb7, 0xd2, 0xba, 0xc5, 0xfd, 0x7b, - 0x99, 0x26, 0x14, 0x95, 0x09, 0xb5, 0x5f, 0xe9, 0xbf, 0x4c, 0xb0, 0x24, 0x95, 0xfd, 0x83, 0x84, 0x0f, 0xe6, 0x8d, - 0x27, 0xd6, 0x78, 0x32, 0x9c, 0x6e, 0xa5, 0x61, 0x08, 0x50, 0xe8, 0xe7, 0x65, 0xae, 0xa8, 0x7e, 0xfe, 0x79, 0xc3, - 0x37, 0xbc, 0xd9, 0x62, 0x9b, 0xf4, 0x40, 0x83, 0xbd, 0x3c, 0x9a, 0x52, 0x38, 0x89, 0x3a, 0x37, 0x12, 0x75, 0x51, - 0xb3, 0x0c, 0xd5, 0x09, 0x5e, 0xcd, 0x53, 0x3d, 0xec, 0xcd, 0x44, 0xb4, 0x56, 0x52, 0x96, 0x18, 0xb0, 0xd6, 0x91, - 0x87, 0xe4, 0x6e, 0xad, 0xe3, 0x4e, 0x43, 0x5d, 0x9a, 0x42, 0x09, 0xb0, 0xc2, 0x05, 0x38, 0x82, 0x7e, 0x2a, 0x42, - 0x0e, 0xd7, 0x54, 0xa5, 0x5f, 0xd0, 0x94, 0x3c, 0xf1, 0x14, 0xb5, 0x5a, 0x91, 0x6e, 0x3f, 0xca, 0xb1, 0x1b, 0xbe, - 0x71, 0x42, 0x4e, 0x8c, 0xd0, 0xdf, 0x1d, 0x4b, 0x39, 0x43, 0x8b, 0x07, 0x75, 0x82, 0xf5, 0xf2, 0x96, 0x02, 0xc5, - 0x1c, 0x5d, 0x56, 0x5d, 0xf3, 0x0a, 0x6d, 0x5f, 0x56, 0xfd, 0x7e, 0x6e, 0xeb, 0x49, 0xd9, 0x6c, 0xbb, 0x32, 0xfb, - 0x10, 0x15, 0x53, 0xb8, 0xeb, 0x13, 0xcd, 0x5f, 0x85, 0xfa, 0xaa, 0x2d, 0x73, 0x3e, 0xe2, 0x88, 0x8b, 0x91, 0x93, - 0xfa, 0x67, 0x35, 0xf5, 0x4a, 0xdc, 0xaf, 0x2a, 0xf9, 0x4e, 0x18, 0x2b, 0x46, 0x07, 0xd4, 0x9f, 0x2a, 0x95, 0xf7, - 0x8b, 0x02, 0xe0, 0x9e, 0x04, 0xfb, 0x0b, 0xec, 0x2b, 0x34, 0xc2, 0x6f, 0x4b, 0xc0, 0xbf, 0x55, 0xdc, 0x80, 0x55, - 0x60, 0x80, 0xd1, 0x64, 0x7b, 0x4e, 0x13, 0x38, 0xe0, 0x84, 0x56, 0x51, 0x50, 0x61, 0x86, 0x86, 0xda, 0xc2, 0xe8, - 0x29, 0xca, 0xb8, 0x55, 0x66, 0xef, 0xc6, 0xd8, 0x69, 0x81, 0xd7, 0xf0, 0xe7, 0xf3, 0x42, 0x0f, 0x1b, 0x75, 0x90, - 0x1e, 0x9d, 0xc4, 0xf4, 0xc7, 0x2d, 0x9c, 0xdc, 0x2c, 0x9c, 0x55, 0xcd, 0x12, 0xe8, 0x0e, 0x5c, 0x10, 0xe3, 0x7e, - 0x3f, 0x87, 0x23, 0xd3, 0x8c, 0x7c, 0xc1, 0x72, 0x1a, 0xb3, 0x15, 0xd5, 0x9e, 0x76, 0x97, 0x55, 0x98, 0xd3, 0x95, - 0x95, 0xf1, 0xa6, 0x0c, 0x54, 0x46, 0xbb, 0x5d, 0x08, 0x7f, 0xba, 0xad, 0x5d, 0xd2, 0xc5, 0x0a, 0x32, 0xc0, 0x1f, - 0x90, 0x88, 0x22, 0xf6, 0xf5, 0xbf, 0xd5, 0x38, 0xa5, 0x27, 0x4a, 0x6b, 0x96, 0xd0, 0x0d, 0xd3, 0xf5, 0xd3, 0x0b, - 0xb6, 0x69, 0x2c, 0x85, 0xdd, 0x2e, 0x6c, 0x26, 0x30, 0xcd, 0xb9, 0x92, 0xe9, 0x05, 0xea, 0xa4, 0x80, 0x8a, 0x85, - 0x17, 0xb8, 0xfc, 0x52, 0x42, 0xa1, 0xb9, 0x8b, 0xd5, 0xd2, 0x28, 0x31, 0xa1, 0x55, 0xf2, 0xf3, 0x87, 0xca, 0x7c, - 0x6d, 0x3c, 0xe2, 0xfe, 0x95, 0x86, 0x89, 0x29, 0x12, 0x15, 0xa2, 0xf3, 0x5f, 0x41, 0x96, 0x23, 0x00, 0xc7, 0xf2, - 0x54, 0xd6, 0xf4, 0xc7, 0x14, 0xe2, 0xa0, 0x43, 0x83, 0xde, 0x15, 0xf2, 0x2a, 0x2b, 0x79, 0x88, 0xf7, 0x04, 0x4f, - 0x33, 0x7a, 0xbf, 0xc1, 0x87, 0xb6, 0xf6, 0xe8, 0x09, 0xb2, 0xf5, 0x94, 0xfb, 0xf5, 0x77, 0x22, 0x5c, 0x40, 0xb4, - 0xca, 0x25, 0xd5, 0xea, 0x6a, 0x07, 0x40, 0xe5, 0xd9, 0x5e, 0x3d, 0x82, 0xd3, 0x4d, 0x5f, 0xdf, 0xaa, 0xd0, 0x99, - 0x03, 0x48, 0x7b, 0x48, 0xd6, 0x35, 0xd7, 0x3b, 0xc0, 0x1d, 0x89, 0xd5, 0x06, 0x68, 0xac, 0xdb, 0x9a, 0x9d, 0xf6, - 0x28, 0x1e, 0x13, 0x99, 0x19, 0x8b, 0x14, 0x63, 0xee, 0xd6, 0x69, 0x51, 0xb4, 0x45, 0x33, 0x84, 0xfd, 0xbb, 0x0e, - 0xdf, 0xb4, 0x22, 0xac, 0xdf, 0x6f, 0xfb, 0x02, 0xa3, 0x61, 0xcc, 0xb5, 0x7b, 0x9e, 0xa1, 0x1b, 0x36, 0xd8, 0x46, - 0xce, 0x43, 0xe4, 0xc3, 0x4c, 0x1d, 0x88, 0xb2, 0xb6, 0x06, 0x6c, 0x8f, 0xb8, 0xde, 0xb4, 0x8a, 0x9f, 0x57, 0x31, - 0x67, 0x7b, 0xd6, 0x38, 0xa5, 0xf5, 0x35, 0xae, 0x39, 0xae, 0x0a, 0x11, 0xb5, 0xf5, 0x8c, 0x87, 0x61, 0xe7, 0x4b, - 0xdc, 0x99, 0x15, 0x06, 0x2f, 0xc2, 0x52, 0xc9, 0x5e, 0xe5, 0xfa, 0x73, 0xd8, 0xe2, 0x20, 0x95, 0x2f, 0xbd, 0xfe, - 0xfe, 0xcb, 0x17, 0x5f, 0xa0, 0x9b, 0x9a, 0xf3, 0x23, 0x08, 0x32, 0x81, 0x0e, 0x59, 0x4a, 0xf5, 0xf8, 0x5d, 0x01, - 0xd4, 0x1e, 0xe6, 0xe1, 0xbb, 0x82, 0x89, 0xf8, 0x3a, 0xbb, 0x8c, 0x2b, 0x59, 0x8c, 0xae, 0xb9, 0x48, 0x65, 0x61, - 0xa5, 0xc6, 0xc1, 0xc9, 0x7a, 0x9d, 0xf3, 0x00, 0x4c, 0xe5, 0x2d, 0xa3, 0x6c, 0x2b, 0xcb, 0xf4, 0xe0, 0x6a, 0x79, - 0x7a, 0xa5, 0x45, 0xe7, 0xe5, 0xf5, 0x65, 0x10, 0xe1, 0xaf, 0x73, 0xf3, 0xe3, 0x2a, 0x2e, 0x3f, 0x06, 0x91, 0xb5, - 0xa9, 0x33, 0x3f, 0x50, 0x2a, 0x0f, 0xfe, 0x53, 0x20, 0xd3, 0xfd, 0xae, 0x00, 0xcb, 0x6c, 0x5b, 0xf1, 0x71, 0x8c, - 0xb5, 0x0e, 0x27, 0x64, 0xae, 0x4a, 0xf4, 0xde, 0x25, 0x9b, 0x02, 0xac, 0xfd, 0x14, 0x96, 0xb1, 0xca, 0x35, 0xc7, - 0xca, 0x54, 0x45, 0x66, 0x56, 0x36, 0xec, 0x30, 0xb4, 0x4e, 0x34, 0x0b, 0xf4, 0x16, 0xd0, 0x0f, 0xe4, 0xf0, 0x92, - 0x96, 0x1b, 0xe6, 0xf9, 0xd8, 0x34, 0x5e, 0x3f, 0x3a, 0xbc, 0x74, 0x0b, 0xf6, 0xd6, 0xde, 0xc9, 0x51, 0x98, 0x08, - 0x9e, 0xb5, 0x66, 0x7c, 0x91, 0x67, 0x05, 0xac, 0x9c, 0xc9, 0x78, 0x4c, 0xbd, 0xa5, 0xd5, 0xba, 0x39, 0x3a, 0x24, - 0xd7, 0xec, 0x71, 0xf5, 0x98, 0x93, 0x43, 0xde, 0x32, 0xb5, 0x6d, 0x5b, 0xc7, 0x79, 0x9a, 0x7c, 0x65, 0xba, 0x2f, - 0x36, 0x36, 0x22, 0xba, 0x72, 0xee, 0x73, 0x5e, 0xc1, 0xad, 0x6f, 0x4a, 0x43, 0xaf, 0x25, 0x00, 0xd1, 0x69, 0x03, - 0xfe, 0x82, 0x95, 0x9b, 0x51, 0xc5, 0xcb, 0x0a, 0x24, 0x2c, 0x28, 0xc2, 0x9b, 0x62, 0x6f, 0x0a, 0x77, 0xe3, 0xf4, - 0x1c, 0x76, 0xe0, 0x62, 0x8a, 0xee, 0x38, 0x31, 0x99, 0x97, 0x46, 0x2b, 0x1a, 0xe9, 0x5f, 0xae, 0x2f, 0xb1, 0xee, - 0x8b, 0x56, 0xe6, 0xd9, 0x9c, 0x0a, 0x8b, 0xdd, 0x55, 0x2e, 0x9d, 0xa8, 0xdf, 0x32, 0xe1, 0xca, 0x95, 0x20, 0x20, - 0xd3, 0x82, 0xf5, 0x0a, 0xb3, 0x8b, 0xe4, 0x06, 0x08, 0x19, 0x18, 0xbe, 0x06, 0x1b, 0x51, 0x72, 0x63, 0x05, 0xeb, - 0xdd, 0xf3, 0x75, 0x82, 0x90, 0x82, 0x07, 0x6e, 0x82, 0x7e, 0x68, 0xdd, 0xbc, 0x1d, 0x25, 0xca, 0x20, 0x1e, 0xb7, - 0x76, 0xca, 0x41, 0x02, 0x01, 0xb8, 0xa7, 0x2a, 0x04, 0x87, 0x02, 0x59, 0x07, 0x57, 0x33, 0x8e, 0xe0, 0xea, 0xca, - 0x99, 0x8b, 0x1b, 0x80, 0x75, 0xe5, 0xcf, 0x65, 0x83, 0x0b, 0xeb, 0x11, 0x55, 0xe6, 0x8c, 0x53, 0x0c, 0x62, 0x64, - 0x09, 0xfa, 0xda, 0x52, 0xda, 0x4b, 0xd0, 0x34, 0x5e, 0xb1, 0xb5, 0xf2, 0x01, 0xa0, 0xe7, 0x6c, 0xad, 0x8c, 0xfd, - 0xf1, 0xeb, 0x33, 0xb6, 0xd6, 0xd2, 0xe0, 0xe9, 0xd5, 0xfc, 0x7c, 0x7e, 0x36, 0x60, 0x47, 0x51, 0xa8, 0x0d, 0x18, - 0x02, 0x87, 0xc4, 0x1f, 0x0c, 0x42, 0x8d, 0x77, 0x32, 0x50, 0x01, 0xb1, 0x88, 0xc7, 0x63, 0x23, 0x6e, 0x56, 0x38, - 0x1e, 0x62, 0xf0, 0xab, 0xe6, 0x0b, 0x12, 0x10, 0x6a, 0x4a, 0x43, 0x97, 0xc7, 0x70, 0x38, 0x39, 0x98, 0x40, 0x2a, - 0x66, 0x66, 0xaa, 0x30, 0x36, 0x26, 0x11, 0xc4, 0x3b, 0xed, 0xac, 0x17, 0xca, 0xed, 0xae, 0xd1, 0x40, 0xae, 0x0c, - 0x3e, 0xab, 0xe2, 0xc9, 0xc1, 0xb0, 0xab, 0x62, 0x1c, 0x85, 0x6b, 0xa3, 0x7c, 0x3b, 0x3b, 0x06, 0xf0, 0xda, 0xb3, - 0xa1, 0x2f, 0x97, 0x38, 0x3b, 0x7c, 0x42, 0x1e, 0x3f, 0x21, 0xf4, 0x8c, 0x9d, 0x7d, 0xf1, 0x84, 0x9e, 0x29, 0x72, - 0x72, 0x30, 0x89, 0xae, 0x99, 0xc5, 0x7c, 0x39, 0x52, 0x4d, 0xa0, 0x97, 0xa3, 0x8d, 0x50, 0x0b, 0x4c, 0x3b, 0x34, - 0x85, 0xdf, 0x8e, 0x0f, 0x82, 0xc1, 0x75, 0xbb, 0xe9, 0xd7, 0xed, 0xb6, 0x7a, 0x5e, 0x5d, 0x07, 0x47, 0xd1, 0x7e, - 0x31, 0x93, 0x6f, 0xc6, 0x07, 0x6e, 0x0e, 0xb0, 0xbe, 0x87, 0xc7, 0xc4, 0x34, 0x69, 0x6f, 0x54, 0xfc, 0x9a, 0xbe, - 0xc2, 0x3e, 0x34, 0x8b, 0xec, 0xe8, 0xc3, 0xf0, 0xdf, 0xea, 0x44, 0x7d, 0xf6, 0xc5, 0x11, 0x90, 0x23, 0x90, 0x81, - 0x62, 0x89, 0x60, 0x86, 0x03, 0x4d, 0x01, 0x05, 0x99, 0x1e, 0x77, 0xaa, 0x87, 0x5f, 0x8d, 0x9a, 0x9a, 0x91, 0x6b, - 0x98, 0x1a, 0x6c, 0x0b, 0x7e, 0xa0, 0xba, 0xa1, 0xbf, 0xd1, 0xe8, 0x46, 0xda, 0xc9, 0xcc, 0xbc, 0xa4, 0x36, 0xae, - 0xdb, 0x35, 0x04, 0x30, 0x76, 0xf0, 0x82, 0x92, 0x7d, 0x79, 0x7c, 0x79, 0x80, 0xab, 0x08, 0x50, 0xb2, 0x58, 0xf0, - 0xe5, 0xe0, 0x52, 0x6f, 0xee, 0x83, 0x80, 0x0c, 0xbe, 0x0c, 0x66, 0x5f, 0x0e, 0xe4, 0x20, 0x38, 0x3e, 0xbc, 0x9c, - 0x05, 0xce, 0xb8, 0x1f, 0x42, 0x3c, 0xaa, 0x8a, 0x62, 0x26, 0x4c, 0x15, 0x89, 0xad, 0x3d, 0xb7, 0xf5, 0x2a, 0xe3, - 0x33, 0x9a, 0x4e, 0x2d, 0xf2, 0x77, 0x98, 0xb2, 0xd8, 0xfc, 0x0e, 0x26, 0xfc, 0x2a, 0x88, 0x5c, 0x10, 0xd4, 0x79, - 0x1e, 0xc5, 0x74, 0xc5, 0x6e, 0x45, 0x98, 0xd2, 0xe4, 0x30, 0x27, 0x24, 0x0a, 0x57, 0x0a, 0x3c, 0x4f, 0xbd, 0x4e, - 0x20, 0x8e, 0xab, 0xfb, 0xfc, 0x56, 0x84, 0x2b, 0x9a, 0x1f, 0x26, 0xa4, 0x55, 0x84, 0x8b, 0xc8, 0xb2, 0xad, 0xe9, - 0x05, 0x0b, 0xd7, 0xf4, 0x12, 0x98, 0x29, 0xb9, 0x09, 0x2f, 0x81, 0xcb, 0xdb, 0x2c, 0xd6, 0x4b, 0x76, 0xd9, 0x90, - 0xbe, 0x19, 0xbe, 0xf8, 0xc2, 0xfa, 0xe4, 0x01, 0x0f, 0xe9, 0xfc, 0xf0, 0x52, 0xb0, 0x01, 0xb8, 0xce, 0xf8, 0xcd, - 0x77, 0xf2, 0x56, 0xcf, 0x4b, 0x7b, 0x8a, 0x71, 0x66, 0xda, 0x89, 0x49, 0x3b, 0x21, 0xf7, 0xef, 0xdb, 0xdb, 0xd8, - 0x9c, 0xec, 0x65, 0xb4, 0x51, 0x2e, 0xab, 0x96, 0x21, 0x29, 0x36, 0x0c, 0xf9, 0x7b, 0x94, 0x9c, 0x5a, 0x81, 0x27, - 0xbb, 0xe0, 0x55, 0xb2, 0xf2, 0x0f, 0x2a, 0x6b, 0x35, 0x60, 0x8f, 0x11, 0xcb, 0x42, 0xe1, 0xd8, 0xbf, 0xce, 0x58, - 0xb1, 0xf1, 0x05, 0x1a, 0x31, 0x72, 0x6f, 0xaf, 0x33, 0xe6, 0xc5, 0x5c, 0x4d, 0x36, 0x5e, 0xa8, 0x3a, 0x2f, 0x3d, - 0x6f, 0xf1, 0x5e, 0x4e, 0xa9, 0x61, 0x24, 0xa2, 0x07, 0x63, 0x65, 0x46, 0xa9, 0x12, 0xb5, 0x06, 0x8d, 0x08, 0x36, - 0x76, 0xc1, 0x2f, 0xc1, 0x09, 0x95, 0x7b, 0xea, 0x6c, 0xdf, 0x4e, 0xa9, 0xf4, 0x80, 0x65, 0xa9, 0x51, 0x95, 0xbb, - 0x65, 0x26, 0x59, 0x35, 0x08, 0x46, 0x7f, 0x94, 0x52, 0xcc, 0xf1, 0xce, 0xc8, 0x82, 0x29, 0x58, 0x09, 0xaa, 0x5a, - 0x86, 0xe5, 0x90, 0xa3, 0x16, 0xcf, 0xf8, 0xa4, 0x4a, 0xfd, 0xa3, 0x23, 0x48, 0xee, 0x6a, 0xd3, 0x0a, 0x92, 0xfb, - 0x64, 0xfc, 0x44, 0x0f, 0x74, 0xba, 0xd1, 0x8e, 0x87, 0x3e, 0xbf, 0x8d, 0xf8, 0xda, 0xba, 0xf7, 0x54, 0x6b, 0x15, - 0xca, 0x40, 0x8b, 0x15, 0x95, 0x2b, 0xb5, 0xa4, 0xf7, 0xbb, 0x08, 0x80, 0x45, 0x6c, 0xcc, 0xc6, 0xfb, 0xb6, 0x59, - 0x21, 0x68, 0x74, 0xd9, 0x6c, 0x1b, 0x0f, 0x58, 0xa2, 0x5b, 0x3b, 0x98, 0xd0, 0x78, 0xc6, 0xca, 0x7e, 0x3f, 0x9f, - 0x01, 0x3d, 0xd5, 0x46, 0x4c, 0x05, 0x1c, 0xf9, 0x9f, 0x5b, 0x91, 0x29, 0x0a, 0x6c, 0xd6, 0xd4, 0xdd, 0x1a, 0xcb, - 0x48, 0xf4, 0x65, 0x4a, 0x97, 0x27, 0x3c, 0x03, 0xa6, 0xcd, 0xa6, 0xe5, 0xb8, 0xb2, 0xaf, 0x38, 0xf2, 0x54, 0x58, - 0x56, 0x9c, 0x57, 0xe1, 0x78, 0xeb, 0xf1, 0x0d, 0x0e, 0x0d, 0x9b, 0x76, 0xe1, 0x0f, 0x21, 0x2c, 0x84, 0xd7, 0x19, - 0xdc, 0x46, 0xb4, 0x9d, 0x04, 0x2a, 0x6f, 0xcc, 0x75, 0x42, 0xd9, 0xdc, 0x6e, 0x36, 0x9e, 0x41, 0x3a, 0x31, 0x07, - 0x4a, 0x35, 0x82, 0xd6, 0x68, 0x16, 0x54, 0x8d, 0x78, 0xe4, 0x78, 0x78, 0x67, 0x10, 0xab, 0xe5, 0x4b, 0x9a, 0x4a, - 0xd1, 0x00, 0x8c, 0x0b, 0xe0, 0xf2, 0xf4, 0xcb, 0xfb, 0x9f, 0x4e, 0x79, 0x5c, 0x24, 0xab, 0x77, 0x71, 0x11, 0x5f, - 0x95, 0xe1, 0x56, 0x8d, 0x51, 0x5c, 0x93, 0xa9, 0x18, 0x30, 0x69, 0x56, 0x52, 0x73, 0x57, 0x6a, 0x42, 0x8c, 0x75, - 0x26, 0x9b, 0xb2, 0x92, 0x57, 0x8d, 0x4a, 0x37, 0x45, 0x86, 0x1f, 0xb7, 0x7c, 0x4e, 0x0f, 0x01, 0xc8, 0xd3, 0xb8, - 0x90, 0x46, 0x52, 0x17, 0x62, 0xcc, 0x45, 0xbc, 0xae, 0x8f, 0xc7, 0x8d, 0xae, 0x97, 0xec, 0xe9, 0xf8, 0xab, 0xe9, - 0xeb, 0x2c, 0xcc, 0x06, 0x82, 0x8c, 0xaa, 0x15, 0x17, 0x2d, 0x53, 0x4e, 0x65, 0x12, 0x80, 0x3e, 0x9e, 0x3d, 0xc6, - 0x8e, 0xc6, 0x63, 0xb2, 0x6d, 0x8b, 0x07, 0x78, 0xb8, 0xda, 0x84, 0x05, 0x99, 0xeb, 0x3a, 0xa2, 0x40, 0xf0, 0xdb, - 0x2a, 0x00, 0x24, 0x47, 0x5b, 0x95, 0xe1, 0xd2, 0xd8, 0xd3, 0xf1, 0x84, 0x4a, 0xec, 0x76, 0x48, 0x6a, 0xaf, 0x42, - 0x37, 0xf3, 0xd2, 0xf7, 0x28, 0x92, 0xc6, 0x65, 0x69, 0xaf, 0x52, 0xa9, 0xf6, 0xcc, 0xdc, 0x75, 0x0d, 0x62, 0x30, - 0x84, 0xba, 0xee, 0xd2, 0xab, 0x7b, 0xbf, 0xb9, 0xd6, 0x6c, 0x07, 0xbc, 0xd7, 0xa0, 0x19, 0x4a, 0xde, 0x62, 0xde, - 0xba, 0x22, 0x6a, 0xba, 0xde, 0x80, 0x59, 0x31, 0xca, 0x96, 0xa2, 0x74, 0x43, 0x41, 0x29, 0x18, 0x5d, 0x6c, 0xbc, - 0x85, 0xfb, 0x5a, 0x36, 0x2e, 0x2c, 0x99, 0x5e, 0x2d, 0x4a, 0x4a, 0xa8, 0x6e, 0x2a, 0x46, 0x4a, 0x18, 0x29, 0x0d, - 0x4f, 0xe5, 0x7b, 0x81, 0xc7, 0x79, 0x1e, 0x44, 0x2d, 0x2f, 0xb0, 0x93, 0x8a, 0x9c, 0x80, 0xa3, 0x97, 0xc9, 0x69, - 0x28, 0xf0, 0x8f, 0x99, 0x02, 0x31, 0x1d, 0xaa, 0xfb, 0x0d, 0x6e, 0xfe, 0x7f, 0x14, 0x2c, 0xf0, 0xf8, 0xd6, 0x4b, - 0xdc, 0x46, 0xff, 0x28, 0x7c, 0x5a, 0xfa, 0x4c, 0xfa, 0xae, 0x2e, 0x9e, 0xb4, 0x37, 0x1b, 0x25, 0xab, 0x2c, 0x4f, - 0xdf, 0xc8, 0x94, 0x83, 0xc8, 0x0c, 0xad, 0x41, 0xd9, 0x4c, 0x34, 0x6e, 0x78, 0x60, 0xc4, 0xd8, 0xb8, 0xf1, 0xfd, - 0x98, 0x81, 0x6c, 0x18, 0xac, 0xbe, 0x59, 0x2a, 0x93, 0xcd, 0x15, 0x60, 0x8a, 0x28, 0xf9, 0xc9, 0x8b, 0x9c, 0xc3, - 0x53, 0xa8, 0xaf, 0x5f, 0xe0, 0x36, 0x57, 0xfa, 0x3e, 0xe7, 0x3f, 0x66, 0xf4, 0x47, 0x04, 0x3a, 0x89, 0xd7, 0x20, - 0xf7, 0x78, 0x06, 0x75, 0x23, 0x4c, 0x2d, 0xc7, 0xe0, 0x40, 0x88, 0x06, 0x22, 0x2a, 0x16, 0x28, 0xa8, 0x0b, 0x03, - 0xac, 0xa1, 0x2e, 0x98, 0xc3, 0xf3, 0x5c, 0x26, 0x1f, 0xa7, 0xc6, 0x67, 0x7e, 0x18, 0x63, 0xcc, 0xe4, 0x60, 0x10, - 0x56, 0xf3, 0x60, 0x38, 0x1e, 0x4d, 0x8e, 0x9e, 0xc2, 0xb9, 0x1d, 0x8c, 0x03, 0x32, 0x08, 0xea, 0x72, 0x1d, 0x0b, - 0x5a, 0x5e, 0x5f, 0xda, 0x32, 0xf0, 0xe3, 0x3a, 0x18, 0xfc, 0xa3, 0xf0, 0x14, 0xef, 0xa0, 0x39, 0x39, 0x93, 0x21, - 0xd8, 0xd8, 0x6f, 0x08, 0x48, 0xca, 0x7a, 0x9a, 0x9f, 0xd4, 0x87, 0x1b, 0x53, 0xda, 0x3f, 0x73, 0x78, 0xc1, 0x61, - 0x87, 0x04, 0x0a, 0xa4, 0xf1, 0x34, 0x1b, 0xbd, 0x52, 0x8a, 0xdc, 0x77, 0x05, 0x87, 0x3b, 0x73, 0xcf, 0x99, 0x1e, - 0x39, 0x85, 0x44, 0x33, 0x0b, 0xb8, 0x91, 0xbf, 0x12, 0xd7, 0x71, 0x9e, 0xa5, 0x07, 0xcd, 0x37, 0x07, 0xe5, 0x9d, - 0xa8, 0xe2, 0xdb, 0x51, 0x60, 0xac, 0x09, 0xb9, 0xaf, 0x7a, 0x02, 0xf4, 0x04, 0xd8, 0x02, 0x60, 0x40, 0xbc, 0x67, - 0x66, 0x32, 0xe7, 0x11, 0x78, 0x04, 0x36, 0x7d, 0x20, 0x8b, 0x3b, 0xe7, 0x92, 0xe4, 0x6f, 0xa6, 0xd2, 0x5e, 0xf5, - 0xca, 0xbd, 0x82, 0xac, 0x57, 0x5b, 0xb9, 0xef, 0xd6, 0x67, 0xdf, 0x74, 0x78, 0x05, 0x9e, 0x4b, 0x70, 0x8b, 0xec, - 0xf7, 0x9b, 0x82, 0x4a, 0x61, 0x54, 0xc4, 0x7b, 0xc9, 0x35, 0xfa, 0xb7, 0x7b, 0x63, 0xa3, 0x48, 0x6e, 0xf9, 0xf0, - 0x00, 0xea, 0x4c, 0xde, 0x15, 0xb7, 0x73, 0x88, 0xda, 0xba, 0x1b, 0x0f, 0xac, 0x36, 0x68, 0x97, 0xb5, 0x40, 0x70, - 0xe1, 0xe5, 0x41, 0x06, 0x63, 0x81, 0xb3, 0x32, 0x52, 0x6a, 0x5c, 0x43, 0x6a, 0xc1, 0x27, 0x79, 0x7a, 0x0f, 0x59, - 0xea, 0x49, 0x50, 0xe4, 0x78, 0x16, 0x43, 0xa6, 0xf1, 0x36, 0xf0, 0xf8, 0x9d, 0x0c, 0x41, 0x9a, 0xb6, 0xdb, 0x35, - 0x47, 0xa0, 0xec, 0x1e, 0x98, 0x92, 0xd4, 0xb5, 0x31, 0x35, 0xd0, 0x50, 0x7b, 0xa8, 0x91, 0x8a, 0x38, 0x9b, 0xbd, - 0x06, 0x1d, 0x22, 0xf8, 0x7e, 0xa7, 0x59, 0xd9, 0xf1, 0x62, 0x42, 0xf0, 0xe4, 0x7d, 0x71, 0x9b, 0x95, 0x55, 0x19, - 0xbd, 0x4f, 0xd1, 0x10, 0x2a, 0x91, 0x22, 0x7a, 0x09, 0xf1, 0xf4, 0x4a, 0xfc, 0x5d, 0x46, 0x3f, 0xa5, 0x34, 0x4e, - 0x53, 0x4c, 0x7f, 0x5e, 0xc0, 0xcf, 0x67, 0x80, 0xea, 0x88, 0x3b, 0x21, 0x3a, 0x97, 0x60, 0xaf, 0x06, 0xd1, 0xac, - 0x2a, 0x0e, 0x18, 0x9a, 0xd1, 0xad, 0xa0, 0x88, 0xd1, 0x86, 0xd9, 0x7f, 0x28, 0x50, 0x28, 0xa4, 0x8a, 0xf9, 0x4e, - 0xd8, 0x87, 0xe8, 0x47, 0x2c, 0xf2, 0xe4, 0xdd, 0x2b, 0x33, 0xa4, 0xd1, 0x9d, 0xa4, 0x7a, 0x6b, 0xe3, 0xb1, 0x85, - 0x81, 0xcb, 0xa2, 0xcb, 0x0d, 0x3d, 0x8b, 0xd7, 0x59, 0xb4, 0x05, 0xfc, 0x89, 0x77, 0xaf, 0x9e, 0x29, 0x0b, 0x93, - 0xe7, 0x19, 0x28, 0x0e, 0x4e, 0xde, 0xbd, 0x7a, 0x2d, 0xd3, 0x4d, 0xce, 0xa3, 0x33, 0x89, 0xa4, 0xf5, 0xe4, 0xdd, - 0xab, 0x9f, 0xd1, 0xdc, 0xeb, 0xa7, 0x02, 0xde, 0xbf, 0x04, 0xde, 0x32, 0x8a, 0x37, 0xd0, 0x27, 0xf5, 0x3b, 0xd9, - 0x60, 0xa7, 0xbc, 0x5a, 0xcb, 0xe8, 0x97, 0xb4, 0xf6, 0xa4, 0x55, 0xff, 0x2c, 0x7c, 0x6a, 0xe7, 0x09, 0x78, 0x6e, - 0xf3, 0x4c, 0x7c, 0x8c, 0xac, 0x68, 0x27, 0x88, 0xbe, 0x3c, 0xb8, 0xbd, 0xca, 0x45, 0x19, 0xe1, 0x0b, 0x86, 0x76, - 0x41, 0xd1, 0xe1, 0xe1, 0xcd, 0xcd, 0xcd, 0xe8, 0xe6, 0xab, 0x91, 0x2c, 0x2e, 0x0f, 0x27, 0xdf, 0x7e, 0xfb, 0xed, - 0x21, 0xbe, 0x0d, 0xbe, 0x6c, 0xbb, 0xbd, 0x57, 0x84, 0x0f, 0x58, 0x80, 0x08, 0xd5, 0x5f, 0xc2, 0x15, 0x05, 0xb4, - 0x70, 0x83, 0x2f, 0x83, 0x2f, 0xf5, 0xa1, 0xf3, 0xe5, 0x71, 0x79, 0x7d, 0xa9, 0xca, 0xef, 0x2a, 0xf9, 0x68, 0x3c, - 0x1e, 0x1f, 0x82, 0x04, 0xea, 0xcb, 0x01, 0x1f, 0x04, 0xb3, 0x60, 0x90, 0xc1, 0x85, 0xa6, 0xbc, 0xbe, 0x9c, 0x05, - 0x9e, 0x69, 0x6e, 0x83, 0x45, 0x74, 0x20, 0x2e, 0xc1, 0xe1, 0x25, 0x0d, 0xbe, 0x0c, 0x88, 0x4b, 0xf9, 0x02, 0x52, - 0xbe, 0x38, 0x7a, 0xea, 0xa7, 0xfd, 0x2f, 0x95, 0xf6, 0x95, 0x9f, 0x76, 0x8c, 0x69, 0x5f, 0x3d, 0xf3, 0xd3, 0x66, - 0x2a, 0xed, 0x85, 0x9f, 0xf6, 0xbf, 0xcb, 0x01, 0xa4, 0x1e, 0xf8, 0xd6, 0x7f, 0xe7, 0x5e, 0x6b, 0xf0, 0x14, 0x8a, - 0xb2, 0xab, 0xf8, 0x92, 0x43, 0xa3, 0x07, 0xb7, 0x57, 0x39, 0x0d, 0x06, 0xd8, 0x5e, 0xcf, 0x24, 0xc4, 0xfb, 0xe0, - 0xcb, 0x4d, 0x91, 0x87, 0xc1, 0x97, 0x03, 0x2c, 0x64, 0xf0, 0x65, 0x40, 0xbe, 0x34, 0x06, 0x32, 0x82, 0x6d, 0x03, - 0x17, 0x8a, 0x74, 0x68, 0x03, 0x84, 0xf9, 0xd2, 0xb8, 0x9a, 0xfe, 0x59, 0x74, 0x67, 0xc3, 0x5b, 0xa2, 0x72, 0xd3, - 0x0d, 0x6a, 0xfa, 0x16, 0xbc, 0x13, 0xa0, 0x51, 0x51, 0x70, 0x1d, 0x17, 0xe1, 0x70, 0x58, 0x5e, 0x5f, 0x12, 0xb0, - 0xcb, 0x5c, 0xf3, 0xb8, 0x8a, 0x02, 0x21, 0x87, 0xea, 0x67, 0xa0, 0x22, 0x5f, 0x05, 0x08, 0x88, 0x04, 0xff, 0x05, - 0x35, 0x7d, 0x27, 0xd9, 0x36, 0x18, 0xde, 0xf0, 0xf3, 0x8f, 0x59, 0x35, 0x54, 0xa2, 0xc5, 0x6b, 0x41, 0xe1, 0x07, - 0xfc, 0x75, 0x55, 0x47, 0x7f, 0x82, 0x1b, 0x77, 0x53, 0xc3, 0xfe, 0x4e, 0x3a, 0x16, 0xf5, 0x9d, 0x5c, 0x64, 0xcb, - 0x69, 0xeb, 0x40, 0x7f, 0x2b, 0x49, 0xb5, 0xc8, 0x06, 0xc1, 0x30, 0x18, 0xf0, 0x25, 0x7b, 0x2b, 0x17, 0xdc, 0x33, - 0x9f, 0x7a, 0x24, 0xfd, 0x69, 0x9e, 0x67, 0x03, 0xf0, 0x4d, 0x41, 0x7e, 0xe4, 0xf0, 0xbf, 0x17, 0x43, 0x14, 0x1e, - 0x0e, 0x1e, 0x1d, 0x92, 0x79, 0xb0, 0xbe, 0x45, 0x8f, 0xce, 0x28, 0xc8, 0xc4, 0x8a, 0x17, 0x59, 0xe5, 0x2d, 0x95, - 0xbb, 0x4d, 0xdb, 0xcb, 0xe3, 0xde, 0xb3, 0x79, 0x1d, 0x8b, 0x40, 0x9d, 0x73, 0xa0, 0x78, 0x43, 0xd9, 0x53, 0xd9, - 0x94, 0x90, 0x6a, 0x43, 0xde, 0xb0, 0x1c, 0xb0, 0xe0, 0xb8, 0x37, 0x1c, 0x1e, 0x04, 0x03, 0xa7, 0xce, 0x1d, 0x04, - 0x07, 0xc3, 0xe1, 0x2c, 0x70, 0xf7, 0xa1, 0x6c, 0xe4, 0xee, 0x8c, 0xb4, 0x60, 0xff, 0x2c, 0xc2, 0x92, 0x82, 0x78, - 0x4c, 0x6a, 0xf1, 0x97, 0x06, 0x97, 0x19, 0x00, 0xf4, 0x91, 0x92, 0x80, 0x19, 0x58, 0x99, 0x01, 0x84, 0xe6, 0xa6, - 0x31, 0x3b, 0x03, 0xe6, 0x11, 0x38, 0xe6, 0x11, 0x32, 0x0e, 0x80, 0x58, 0x12, 0xe0, 0xdc, 0x05, 0x51, 0xac, 0x0b, - 0x79, 0x04, 0xa0, 0xf7, 0xf8, 0x93, 0x98, 0x52, 0x30, 0x49, 0xc7, 0x2a, 0x04, 0x41, 0x1c, 0x9f, 0x5f, 0x8b, 0xd6, - 0xe4, 0xac, 0xd0, 0xc1, 0x8c, 0x24, 0xc0, 0x86, 0x18, 0xd8, 0x39, 0xb8, 0x9f, 0x83, 0xd2, 0xc3, 0xea, 0x9d, 0x90, - 0x0b, 0xbe, 0xe3, 0x9e, 0x6c, 0x16, 0xae, 0x9e, 0x70, 0x10, 0xdc, 0x71, 0xcd, 0x02, 0x8c, 0xaa, 0x62, 0x53, 0x56, - 0x3c, 0xfd, 0x70, 0xb7, 0x86, 0xd8, 0x77, 0x38, 0xa0, 0xef, 0x64, 0x9e, 0x25, 0x77, 0xa1, 0xb3, 0xe7, 0xda, 0xaa, - 0xf4, 0x1f, 0x3e, 0xbc, 0xfe, 0x29, 0x02, 0x91, 0x63, 0x6d, 0x28, 0xfd, 0x1d, 0xc7, 0xb3, 0xc9, 0x8f, 0xf0, 0xe4, - 0x6f, 0xec, 0x3b, 0x6e, 0x4f, 0x8f, 0x7e, 0x1f, 0xea, 0xa6, 0x77, 0x7c, 0x7e, 0xc7, 0x47, 0xae, 0x38, 0x54, 0x57, - 0xb8, 0xaf, 0x6f, 0x36, 0xbe, 0x11, 0xd2, 0xc3, 0xf3, 0x4c, 0x79, 0x63, 0x7e, 0xb4, 0x83, 0x61, 0x10, 0x4c, 0xb5, - 0x50, 0x12, 0xa2, 0x6e, 0x30, 0x25, 0x60, 0x88, 0x0e, 0xf4, 0xb2, 0x9a, 0x22, 0xe7, 0xa6, 0x46, 0x16, 0xde, 0x0f, - 0x98, 0x16, 0x3a, 0x34, 0x72, 0x28, 0x3f, 0x38, 0x9c, 0x30, 0x66, 0xe1, 0xb7, 0x4a, 0x98, 0x7e, 0xb5, 0xa8, 0x9c, - 0x83, 0xe8, 0x01, 0x18, 0xe3, 0x0a, 0x5e, 0x40, 0x57, 0xd8, 0xf5, 0x46, 0x45, 0xc5, 0x40, 0xf0, 0x38, 0xe4, 0x00, - 0x3d, 0xec, 0x82, 0x96, 0x95, 0xa5, 0xba, 0x55, 0x39, 0x4b, 0x15, 0x75, 0x19, 0xca, 0xca, 0x58, 0x61, 0xbe, 0x97, - 0xec, 0x87, 0x02, 0x3d, 0xcb, 0xa7, 0xa2, 0x0b, 0x5e, 0x08, 0x25, 0x58, 0xae, 0xeb, 0x9d, 0x08, 0x44, 0x9d, 0x1f, - 0x7a, 0x57, 0x7d, 0x8d, 0x63, 0xc7, 0xd3, 0xd7, 0x32, 0xe5, 0xda, 0x84, 0x42, 0xf3, 0xf9, 0xd2, 0x57, 0x4c, 0x14, - 0xec, 0x06, 0xfa, 0xd5, 0xb6, 0xd1, 0x67, 0x77, 0x1b, 0xbd, 0x19, 0x94, 0xe8, 0x98, 0xd7, 0x28, 0xb8, 0x56, 0x0a, - 0x05, 0xa3, 0xbd, 0x8d, 0x3f, 0xc1, 0x91, 0x5b, 0xdd, 0x1e, 0x7a, 0xbf, 0x55, 0xf1, 0xe5, 0x1b, 0xf4, 0xed, 0xb4, - 0x3f, 0x47, 0x95, 0xfc, 0x65, 0xbd, 0x06, 0x1f, 0x2a, 0x88, 0x2c, 0x62, 0x71, 0x69, 0xa1, 0x9e, 0xd3, 0x77, 0x27, - 0x6f, 0xc0, 0x8f, 0x12, 0x7f, 0xff, 0xfa, 0x7d, 0x50, 0x93, 0x69, 0x3c, 0x2f, 0xcc, 0x87, 0x36, 0x07, 0x84, 0x26, - 0x71, 0x69, 0xf6, 0xfd, 0x3c, 0x6e, 0xb2, 0xef, 0x9a, 0xad, 0xa7, 0x45, 0x13, 0x49, 0xca, 0x70, 0xfb, 0x60, 0x40, - 0xa0, 0x0f, 0x10, 0xc5, 0xd9, 0x17, 0x34, 0x86, 0x34, 0x9f, 0xd9, 0xf7, 0x23, 0xe2, 0xbd, 0xd8, 0x0b, 0x21, 0xc6, - 0x15, 0x16, 0x8d, 0x1e, 0xf2, 0x39, 0x8f, 0x94, 0x61, 0xd1, 0x7b, 0x4c, 0x20, 0xce, 0x70, 0x5a, 0xbd, 0x47, 0xcc, - 0x63, 0xbc, 0x1b, 0x68, 0xd9, 0x43, 0x94, 0x51, 0x97, 0xbd, 0x61, 0xf1, 0xfd, 0x71, 0x13, 0x66, 0xd6, 0xf2, 0x72, - 0x08, 0x7f, 0x03, 0x6d, 0x00, 0x4e, 0x39, 0xb2, 0x7c, 0x95, 0xd9, 0xe8, 0x6a, 0x89, 0xe9, 0x4d, 0x04, 0xb1, 0x78, - 0x74, 0x3a, 0xac, 0x5d, 0x9d, 0xaa, 0x77, 0xb5, 0xf3, 0x99, 0xe8, 0x55, 0xa0, 0x95, 0x6b, 0xdb, 0xe3, 0x21, 0xdc, - 0xa5, 0x96, 0x56, 0xd8, 0x88, 0x72, 0x2e, 0x9e, 0xee, 0x02, 0x9b, 0x13, 0xd0, 0xe0, 0x4a, 0xa6, 0x00, 0x9c, 0xa5, - 0xd5, 0x68, 0xd4, 0x08, 0xfb, 0xac, 0x9c, 0xcf, 0x61, 0x6b, 0x21, 0x9e, 0x16, 0x80, 0xe1, 0x36, 0x31, 0x28, 0x79, - 0x37, 0x06, 0xe5, 0xf4, 0xa3, 0x82, 0xb7, 0x0e, 0xce, 0xca, 0x55, 0x9c, 0xca, 0x1b, 0xc0, 0x62, 0x0c, 0xfc, 0x54, - 0x2c, 0xd5, 0x4b, 0x48, 0x56, 0x3c, 0xf9, 0x88, 0x56, 0x1b, 0x69, 0x00, 0x5c, 0xe5, 0xd4, 0x58, 0xee, 0x29, 0x90, - 0x50, 0x57, 0x8a, 0x4a, 0x88, 0xab, 0x2a, 0x4e, 0x56, 0xa7, 0x98, 0x1a, 0x6e, 0xa1, 0x17, 0x51, 0x20, 0xd7, 0x5c, - 0x00, 0x49, 0xcf, 0xd9, 0xbf, 0x32, 0x8d, 0x35, 0xfe, 0x4c, 0xa2, 0x80, 0x49, 0xa3, 0x06, 0x63, 0xa5, 0xec, 0x85, - 0x34, 0xd1, 0xde, 0x82, 0xa0, 0x76, 0x2f, 0xff, 0x84, 0xba, 0x9f, 0x41, 0x2b, 0xc2, 0x06, 0x18, 0xa2, 0x3c, 0xc7, - 0x1d, 0x9a, 0xda, 0x25, 0xe7, 0x01, 0x23, 0x3a, 0xef, 0xb3, 0xda, 0x6e, 0xf5, 0x67, 0x2b, 0xc0, 0x36, 0x4d, 0x8d, - 0x4f, 0x61, 0x98, 0x10, 0x13, 0x1b, 0xd8, 0x2a, 0x2b, 0xed, 0x86, 0x32, 0xed, 0xa4, 0x2b, 0xe6, 0xb5, 0x70, 0x9a, - 0xf7, 0x18, 0x5b, 0x8d, 0x54, 0xee, 0x7e, 0x3f, 0x34, 0x3f, 0x59, 0x4e, 0x9f, 0xe9, 0x90, 0xcd, 0xde, 0x78, 0xd0, - 0x9c, 0x68, 0x75, 0x55, 0x47, 0x3f, 0xa0, 0x03, 0x30, 0xd3, 0x16, 0x20, 0xd3, 0x05, 0x9b, 0xf6, 0x95, 0xa8, 0xb8, - 0x24, 0x61, 0xa9, 0x24, 0xb0, 0xb3, 0x9b, 0x92, 0x9d, 0x6d, 0x40, 0x3c, 0xc3, 0x5d, 0x4f, 0x8b, 0x9d, 0x90, 0x26, - 0xbc, 0xc5, 0x41, 0x02, 0xa2, 0x0e, 0x55, 0x5d, 0x42, 0xb6, 0xc6, 0xd0, 0xc5, 0xbf, 0x28, 0x85, 0x09, 0x6b, 0x99, - 0x54, 0x25, 0x26, 0x08, 0x52, 0xb9, 0xdf, 0x22, 0xb0, 0x44, 0xc1, 0x0e, 0x60, 0xef, 0xdd, 0xa8, 0x9b, 0x51, 0x53, - 0xd5, 0xa9, 0x97, 0xe0, 0xe3, 0x34, 0xef, 0x2a, 0xc8, 0x2c, 0xec, 0xaa, 0xd8, 0xf0, 0x40, 0xc7, 0xa6, 0x52, 0xc6, - 0xc4, 0x5d, 0x5a, 0x64, 0x88, 0x07, 0x8c, 0xb1, 0x74, 0x21, 0x90, 0x6f, 0xb6, 0x3f, 0x6e, 0x7a, 0x82, 0xd0, 0x4f, - 0xd8, 0x50, 0x02, 0x37, 0x9d, 0xed, 0xa9, 0x69, 0xe6, 0x03, 0x22, 0x0e, 0x03, 0x0a, 0x24, 0x1b, 0x87, 0x34, 0x47, - 0xfa, 0x82, 0xa4, 0x09, 0x03, 0x43, 0x2b, 0x9e, 0x13, 0x64, 0x45, 0xa1, 0x67, 0xeb, 0xaa, 0x8d, 0x73, 0x65, 0x98, - 0xa3, 0x25, 0xa7, 0xc2, 0xe7, 0x04, 0x99, 0xd8, 0x3d, 0x6d, 0x33, 0x93, 0xe1, 0x28, 0x59, 0x60, 0x7e, 0x05, 0x51, - 0xe2, 0xce, 0x34, 0xab, 0x72, 0x30, 0x2e, 0x60, 0x81, 0x56, 0xbe, 0x07, 0x75, 0x63, 0x0d, 0x6d, 0x35, 0x0c, 0xb1, - 0xdb, 0x9f, 0x60, 0xbf, 0xd6, 0x4e, 0xeb, 0x32, 0xc5, 0xf2, 0x32, 0x85, 0x68, 0x2f, 0x64, 0x7e, 0xa3, 0x48, 0x74, - 0xaf, 0x08, 0x43, 0xc2, 0x3a, 0xca, 0x9e, 0xb4, 0xa9, 0x01, 0xf4, 0xd4, 0x0b, 0x78, 0xde, 0xb9, 0x96, 0x61, 0x17, - 0xe9, 0xfe, 0xaa, 0xe0, 0x53, 0xba, 0x41, 0x90, 0xa2, 0x37, 0x29, 0x98, 0xf3, 0x7a, 0x94, 0xd4, 0x9b, 0xd3, 0x96, - 0x19, 0x55, 0x47, 0x45, 0x48, 0x39, 0xc1, 0x7f, 0xf2, 0x52, 0x6a, 0x62, 0x13, 0x26, 0x78, 0xe0, 0xc3, 0x3c, 0xc3, - 0x06, 0xde, 0xed, 0xde, 0xa5, 0x61, 0xd2, 0x66, 0x1b, 0x52, 0x90, 0x56, 0x98, 0xb8, 0x18, 0x50, 0xd9, 0x2b, 0xdc, - 0x2f, 0xd8, 0x4e, 0x9a, 0x82, 0x07, 0x61, 0xa3, 0x81, 0x89, 0x5b, 0x5d, 0x7c, 0x13, 0x26, 0x34, 0x5c, 0x51, 0xed, - 0xec, 0xa4, 0x25, 0xcd, 0xed, 0x75, 0x79, 0x61, 0xfb, 0xa0, 0x63, 0x87, 0x75, 0x0d, 0x0f, 0x34, 0xaf, 0xd9, 0xc5, - 0x35, 0xd3, 0x34, 0xd1, 0x58, 0x0f, 0x29, 0x4b, 0x8e, 0x4d, 0x3d, 0x5d, 0xe3, 0x6a, 0x99, 0x6b, 0x60, 0x77, 0x89, - 0x17, 0x7a, 0xc0, 0xc3, 0x0e, 0xd7, 0x24, 0xba, 0xc0, 0x66, 0xb3, 0x75, 0x4d, 0xa6, 0xf9, 0x7d, 0xd9, 0x72, 0x13, - 0x10, 0xce, 0x52, 0xdf, 0xdc, 0x27, 0xc7, 0x9a, 0xb6, 0xf9, 0x49, 0x80, 0xe3, 0xed, 0x15, 0x90, 0x74, 0x2c, 0x41, - 0x17, 0xdf, 0xd2, 0x1f, 0x44, 0x6a, 0xa6, 0x82, 0xde, 0x3b, 0x5f, 0xa4, 0x6e, 0x7e, 0x01, 0xb6, 0x51, 0x5b, 0x63, - 0x9a, 0x95, 0x6d, 0xc2, 0x44, 0x59, 0x58, 0x23, 0x0b, 0xb9, 0x02, 0x1f, 0xcc, 0xfd, 0xa6, 0x4e, 0x4f, 0x3a, 0x88, - 0xb0, 0xdf, 0x45, 0x8f, 0x47, 0x18, 0x2b, 0xd6, 0x20, 0x31, 0xac, 0xc2, 0x86, 0x36, 0x97, 0x43, 0x94, 0x53, 0xb3, - 0x64, 0xa2, 0x15, 0xf5, 0x29, 0x45, 0x94, 0x82, 0xb9, 0xf1, 0xb4, 0x6c, 0x98, 0x12, 0x22, 0x64, 0x85, 0x74, 0x40, - 0xb5, 0x16, 0x5a, 0xaa, 0x09, 0x7a, 0x1d, 0x7a, 0x59, 0x68, 0x4c, 0x41, 0xf4, 0x11, 0x19, 0x6e, 0xc4, 0x91, 0xd1, - 0xfd, 0x31, 0x8a, 0x09, 0x84, 0xaa, 0xf6, 0xf2, 0xc2, 0xea, 0xd3, 0xb2, 0xad, 0x0e, 0xe2, 0x0a, 0x91, 0xef, 0xbb, - 0x09, 0x6a, 0x8c, 0x82, 0x36, 0xa7, 0x1b, 0xfd, 0xa5, 0x08, 0x7d, 0xbb, 0x70, 0xec, 0x46, 0x41, 0x24, 0x44, 0x60, - 0xf5, 0x9a, 0x8a, 0x01, 0x59, 0x17, 0xb1, 0x8b, 0xd0, 0xa4, 0xbb, 0x85, 0x28, 0x6f, 0x54, 0xd6, 0x1f, 0x37, 0x21, - 0xd9, 0xed, 0xb0, 0x2c, 0xf0, 0x65, 0x3f, 0xdd, 0xdc, 0x03, 0xf9, 0xfd, 0x7a, 0xf3, 0x49, 0xc8, 0xef, 0x57, 0xd9, - 0xe7, 0x40, 0x7e, 0xbf, 0xde, 0xfc, 0x4f, 0x43, 0x7e, 0x9f, 0x6e, 0x3c, 0xc8, 0x6f, 0x35, 0x18, 0xbf, 0x15, 0x2c, - 0x78, 0xfb, 0x26, 0xa0, 0xcf, 0x25, 0x0b, 0xde, 0xbe, 0x7c, 0xe9, 0x1b, 0x81, 0x08, 0x8d, 0x5c, 0x6f, 0x64, 0xc1, - 0x88, 0xdb, 0x02, 0xaf, 0x50, 0xeb, 0xe4, 0x03, 0x15, 0x65, 0x00, 0xbc, 0x5e, 0xfe, 0x23, 0xab, 0x56, 0x61, 0x70, - 0x18, 0x90, 0xb9, 0x83, 0x04, 0x1d, 0x4e, 0xe0, 0xf6, 0x86, 0x46, 0x96, 0xd5, 0x67, 0xc1, 0x87, 0x8f, 0x46, 0xa3, - 0xb8, 0xb8, 0xc4, 0x4b, 0x9d, 0xd9, 0x48, 0x08, 0x78, 0x9c, 0xf1, 0xd2, 0x86, 0x88, 0x58, 0xc5, 0xe5, 0x99, 0x8e, - 0xcd, 0x52, 0xda, 0xad, 0x08, 0x11, 0xe7, 0xcf, 0x00, 0xa7, 0xde, 0xee, 0xcd, 0x18, 0xfb, 0xa1, 0x38, 0x62, 0x1d, - 0x40, 0xf6, 0xd9, 0x46, 0xbf, 0x3b, 0x8f, 0x4b, 0xfe, 0x2e, 0xae, 0x56, 0x0c, 0x7a, 0x09, 0x77, 0x11, 0xc1, 0x93, - 0xca, 0x63, 0x9b, 0x14, 0x50, 0x79, 0xa6, 0x81, 0xca, 0x3b, 0xde, 0xd3, 0xd0, 0x0e, 0x8b, 0xf6, 0x01, 0x36, 0xd2, - 0xe5, 0x0c, 0x8c, 0x16, 0x5f, 0x5c, 0x73, 0x51, 0xfd, 0x04, 0x78, 0xea, 0x82, 0x17, 0x70, 0x4b, 0x40, 0x2e, 0xb6, - 0xe1, 0x84, 0x40, 0x85, 0xef, 0xd9, 0xa1, 0xa2, 0xc6, 0x18, 0xd1, 0x44, 0xa3, 0xdf, 0x78, 0x13, 0x42, 0xef, 0x4e, - 0xd0, 0x15, 0x61, 0x24, 0xbc, 0x3f, 0x37, 0xfc, 0x2c, 0x03, 0xf3, 0x79, 0x01, 0x50, 0x1a, 0x08, 0x87, 0xca, 0x94, - 0xdc, 0x02, 0x13, 0xb6, 0xc6, 0x5c, 0x29, 0x4b, 0x3d, 0xa4, 0x52, 0xaa, 0xe0, 0x74, 0x05, 0x4d, 0x25, 0xe0, 0x70, - 0x47, 0x12, 0xc0, 0x4c, 0x6d, 0x61, 0x10, 0xdd, 0x36, 0xa5, 0x59, 0x1a, 0x39, 0x45, 0x9a, 0xc3, 0x27, 0xa5, 0x0a, - 0x74, 0xfa, 0x2c, 0x89, 0x2b, 0x7e, 0x29, 0x0b, 0x08, 0x85, 0xdb, 0x4a, 0xa1, 0x48, 0xbf, 0xcf, 0xc4, 0xe6, 0x8a, - 0x17, 0x59, 0x72, 0xb6, 0xca, 0xca, 0x0a, 0xf2, 0x2d, 0xf4, 0xe9, 0xb7, 0xac, 0xa7, 0x05, 0xce, 0x9b, 0x9a, 0x14, - 0x66, 0xe6, 0xf1, 0x44, 0xed, 0x74, 0x50, 0xaf, 0x7a, 0xaf, 0x0d, 0xf6, 0x7b, 0x73, 0xa2, 0xc7, 0xad, 0xf5, 0x60, - 0x35, 0xa9, 0xcd, 0x54, 0x05, 0x71, 0x04, 0xd4, 0x81, 0xcd, 0x70, 0x16, 0x53, 0xba, 0xb1, 0x08, 0x2a, 0x60, 0xed, - 0x80, 0x39, 0x32, 0x71, 0x79, 0x76, 0xa3, 0xe4, 0x27, 0x3d, 0x45, 0x61, 0xd2, 0x28, 0x56, 0xc8, 0x3e, 0x2b, 0x16, - 0x6e, 0x58, 0x72, 0x4f, 0xae, 0x4d, 0x94, 0x34, 0x30, 0xba, 0xe2, 0xf6, 0x40, 0x1c, 0x27, 0xed, 0x94, 0xf9, 0x70, - 0x12, 0xed, 0x65, 0x03, 0xe6, 0xa0, 0x9d, 0x0f, 0xae, 0xaa, 0xab, 0xb9, 0x6a, 0xc5, 0xa8, 0x92, 0x3f, 0xc9, 0x1b, - 0x73, 0xb1, 0x3d, 0x4e, 0x3a, 0x12, 0xa1, 0xdc, 0x49, 0x94, 0x1f, 0xaf, 0xd4, 0x0f, 0x80, 0x5e, 0xd1, 0xe4, 0xf0, - 0xcf, 0x0d, 0x37, 0xe0, 0xf4, 0xa1, 0xf6, 0x10, 0x74, 0xa2, 0x7c, 0x3d, 0x23, 0x9e, 0x51, 0x9d, 0x5e, 0x2e, 0x0b, - 0x30, 0xe8, 0xf2, 0x87, 0x12, 0x22, 0xc8, 0x74, 0x4e, 0xeb, 0x72, 0xaa, 0xcd, 0x8b, 0x0d, 0x6f, 0x43, 0x3f, 0xef, - 0x3b, 0x0d, 0x9c, 0x9b, 0xf0, 0x70, 0xf8, 0x74, 0x4c, 0x6a, 0x6d, 0xeb, 0x8e, 0x0b, 0xcf, 0xfe, 0x56, 0x8b, 0xd3, - 0x3d, 0xdb, 0x05, 0x4a, 0x9b, 0x5e, 0x0a, 0xed, 0x1a, 0xa9, 0xb8, 0xa7, 0xfb, 0x35, 0xa9, 0xdd, 0x42, 0xb3, 0x92, - 0xa7, 0xdf, 0xd5, 0x69, 0x77, 0xf6, 0x68, 0x9b, 0xe9, 0x2a, 0xeb, 0xdf, 0x33, 0x1b, 0xa7, 0xae, 0x41, 0x39, 0x6a, - 0xbd, 0x04, 0x7d, 0x98, 0xb8, 0x8e, 0x6c, 0x7a, 0x3a, 0x59, 0xd6, 0x49, 0x7e, 0x46, 0xea, 0x91, 0xab, 0xb0, 0x5d, - 0xdd, 0x59, 0xf8, 0x2d, 0x4f, 0xc2, 0xae, 0x86, 0xa9, 0x9b, 0x81, 0xe9, 0x02, 0x22, 0x67, 0x82, 0x3e, 0x20, 0xfc, - 0xfd, 0xd1, 0xb6, 0x49, 0xce, 0xea, 0x43, 0xef, 0x33, 0xfc, 0x9d, 0xa5, 0xf0, 0xb7, 0xaa, 0x7f, 0xa7, 0xdb, 0x2b, - 0x5e, 0xad, 0x64, 0x1a, 0x05, 0xef, 0xde, 0x9e, 0x7e, 0x08, 0x34, 0x22, 0x3b, 0xde, 0x4b, 0x8c, 0x26, 0xda, 0x60, - 0x3f, 0x81, 0x66, 0x26, 0x97, 0x97, 0x08, 0x4a, 0xa8, 0x51, 0xed, 0x4f, 0x57, 0xf2, 0xe6, 0x24, 0xcf, 0x7d, 0xe6, - 0xd9, 0x10, 0x5c, 0xcd, 0x4f, 0x36, 0xa8, 0x55, 0x08, 0x32, 0xc0, 0x51, 0x56, 0x9e, 0x69, 0xad, 0x4d, 0x7a, 0x76, - 0x7e, 0x77, 0xa6, 0x25, 0x43, 0x16, 0x15, 0xf2, 0xd9, 0xef, 0xc7, 0x69, 0x76, 0x7d, 0x80, 0xa7, 0x02, 0x0b, 0xc0, - 0xa4, 0x3e, 0xe7, 0xe7, 0x9b, 0xaa, 0x92, 0x62, 0x58, 0xc8, 0x9b, 0x60, 0x76, 0xac, 0x1e, 0x4c, 0x86, 0x58, 0x3d, - 0x06, 0x07, 0xff, 0x95, 0xe4, 0x59, 0xf2, 0x91, 0x05, 0x8f, 0xb6, 0x19, 0x9b, 0xb5, 0x68, 0xff, 0xb8, 0x0e, 0x66, - 0xd0, 0xd6, 0x83, 0x93, 0x3c, 0x3f, 0x3e, 0x54, 0x5f, 0xcc, 0x8e, 0x0f, 0xd3, 0xec, 0x7a, 0xe6, 0x01, 0xf4, 0x3b, - 0x7b, 0x5b, 0x84, 0x42, 0x73, 0xf7, 0x69, 0x70, 0xac, 0x4d, 0x78, 0x68, 0x39, 0x10, 0x90, 0xe2, 0x98, 0xf0, 0x26, - 0x28, 0xf9, 0x09, 0x63, 0x38, 0x6f, 0x77, 0xbb, 0xd0, 0x1a, 0x03, 0x25, 0x1e, 0x52, 0x4e, 0x01, 0x1c, 0x0a, 0x66, - 0xa1, 0x09, 0xa1, 0x49, 0x4d, 0x42, 0x83, 0xe7, 0x13, 0x13, 0x5a, 0xd4, 0x14, 0x8e, 0xa0, 0xd7, 0xf1, 0xda, 0x08, - 0xbf, 0xb4, 0x30, 0xc1, 0xb4, 0x7e, 0xde, 0x18, 0xc7, 0xa8, 0x3d, 0xaa, 0x06, 0x61, 0xab, 0x57, 0xde, 0x37, 0xb0, - 0x20, 0xef, 0x0c, 0x2b, 0x1a, 0xb4, 0xe8, 0x0a, 0xc8, 0x2b, 0x7d, 0x31, 0x1b, 0xa7, 0xe1, 0xa2, 0xa4, 0x72, 0x49, - 0xd8, 0x2c, 0xdc, 0x22, 0xbb, 0x5d, 0x2a, 0xea, 0x1d, 0xc9, 0xda, 0xc1, 0x5d, 0xaa, 0xd9, 0x99, 0x3d, 0xda, 0x0a, - 0x44, 0x58, 0x2c, 0xd9, 0xac, 0x39, 0x5f, 0x55, 0x7c, 0x3e, 0x5c, 0x71, 0xf0, 0xcb, 0x09, 0x0e, 0xfe, 0x2b, 0x3d, - 0xcf, 0xed, 0xa4, 0xa8, 0x15, 0xb9, 0x8a, 0x45, 0x9a, 0xf3, 0x0f, 0xf1, 0xf9, 0x0f, 0x98, 0xe7, 0xf9, 0x79, 0xfe, - 0x0c, 0x32, 0xd4, 0xc1, 0xec, 0xd1, 0x36, 0xa9, 0x46, 0x2f, 0xde, 0x7c, 0x78, 0xf5, 0xe1, 0x9f, 0x67, 0xcf, 0x4e, - 0x3e, 0xbc, 0xf8, 0xfe, 0xed, 0xfb, 0x57, 0x2f, 0x4e, 0x17, 0xd6, 0x11, 0x56, 0xe1, 0xab, 0x91, 0xe5, 0x6e, 0xe7, - 0xf2, 0xfd, 0xf2, 0xe6, 0xf9, 0x8b, 0x97, 0xaf, 0xde, 0xbc, 0x78, 0x5e, 0xab, 0xb9, 0x6c, 0x37, 0x04, 0x76, 0x68, - 0x9c, 0x09, 0x5e, 0x40, 0xf1, 0x3a, 0xca, 0x23, 0x36, 0x5b, 0xc3, 0x02, 0x36, 0x9b, 0xae, 0x23, 0x28, 0xc0, 0x22, - 0x3b, 0xd0, 0x9b, 0x05, 0x1a, 0x2e, 0xcd, 0xc6, 0xf1, 0x97, 0x98, 0xdf, 0x9b, 0x17, 0xf8, 0xdd, 0x7b, 0x79, 0x63, - 0xba, 0xa2, 0x47, 0x48, 0x21, 0x7e, 0xcd, 0x9f, 0xfd, 0x7e, 0xec, 0x4b, 0xd9, 0x50, 0x14, 0xa1, 0xca, 0x85, 0x5f, - 0x75, 0x70, 0xa0, 0x2d, 0xfe, 0x02, 0x08, 0x58, 0x11, 0xcc, 0x8e, 0x0f, 0xfd, 0xdc, 0xb3, 0xdf, 0xa3, 0x9f, 0xbc, - 0xce, 0x61, 0xa9, 0x30, 0x0e, 0xcd, 0xb4, 0xbd, 0x53, 0x11, 0x42, 0x2a, 0xb9, 0x73, 0x53, 0xad, 0x20, 0x43, 0xae, - 0x24, 0x89, 0xec, 0x24, 0x2a, 0x4b, 0x16, 0x53, 0xda, 0xef, 0xfa, 0xaf, 0xeb, 0x33, 0x4a, 0x06, 0xb8, 0x28, 0x65, - 0x11, 0x40, 0x3f, 0xda, 0x71, 0x26, 0x0e, 0xbc, 0x78, 0x2e, 0xd8, 0xa3, 0x4e, 0xf2, 0x0e, 0x23, 0x72, 0xd8, 0xfe, - 0xd4, 0xeb, 0xd8, 0xef, 0xc4, 0xfd, 0xf8, 0x3f, 0xcd, 0x3d, 0xeb, 0x76, 0xdb, 0x36, 0xd2, 0xff, 0xfb, 0x14, 0x0c, - 0x93, 0x4d, 0xc5, 0x84, 0xa4, 0x49, 0xc9, 0xb2, 0x15, 0xc9, 0xb2, 0xdb, 0xe6, 0x72, 0x36, 0xfb, 0xb9, 0x4d, 0x4f, - 0xe2, 0xe6, 0xdb, 0xad, 0xeb, 0x63, 0x51, 0x12, 0x24, 0x71, 0x43, 0x91, 0x3a, 0x24, 0xe5, 0x4b, 0x15, 0xee, 0xb3, - 0xec, 0x23, 0x7c, 0xcf, 0xd0, 0x27, 0xfb, 0xce, 0xcc, 0x00, 0x20, 0x78, 0x93, 0x94, 0x26, 0xed, 0xee, 0x69, 0x93, - 0x88, 0xb8, 0x63, 0x00, 0x0c, 0x06, 0x73, 0xd5, 0xf8, 0x64, 0x4a, 0xe8, 0x45, 0x0e, 0xb0, 0x39, 0x1e, 0xc8, 0xe5, - 0x1b, 0xdf, 0xfc, 0xdf, 0xc8, 0x9c, 0x7b, 0xe6, 0xd2, 0x33, 0xdf, 0x85, 0x57, 0x59, 0xed, 0xea, 0xc8, 0x58, 0x33, - 0x26, 0x1b, 0xb4, 0xc0, 0x63, 0x05, 0x7f, 0x47, 0x70, 0xea, 0xda, 0xb7, 0xb9, 0x8c, 0xed, 0xc2, 0x8b, 0xe7, 0x4c, - 0x84, 0x78, 0x11, 0xb9, 0x29, 0x87, 0x8a, 0xa1, 0x80, 0x05, 0xdc, 0xb9, 0x3c, 0xe0, 0xaa, 0x08, 0xbe, 0x3d, 0x49, - 0xe3, 0xe0, 0x7f, 0xd8, 0x3d, 0x50, 0x7b, 0x49, 0x1a, 0xad, 0x80, 0xc6, 0xf7, 0xe6, 0x9c, 0x67, 0x63, 0xb6, 0xd8, - 0x7e, 0xdd, 0x7d, 0xfc, 0xc8, 0x6c, 0xdc, 0x92, 0x40, 0x28, 0xda, 0x69, 0x34, 0x9f, 0x07, 0xac, 0xa5, 0x8b, 0xa0, - 0x23, 0xba, 0x29, 0xbb, 0x39, 0x7b, 0xe0, 0x08, 0x4f, 0x9f, 0x46, 0xd6, 0x74, 0xb4, 0xc4, 0x8c, 0x99, 0x74, 0x85, - 0x47, 0x14, 0x2f, 0xf2, 0x74, 0x6f, 0x50, 0x2c, 0xc2, 0xd7, 0x25, 0x3f, 0xba, 0xd6, 0x34, 0x5a, 0x8f, 0x03, 0x66, - 0xe1, 0x76, 0x87, 0x2e, 0x37, 0xe3, 0xf5, 0x78, 0x0c, 0xd1, 0x5d, 0x1e, 0x38, 0x26, 0xf8, 0xab, 0x89, 0x12, 0x7c, - 0x47, 0x66, 0xc6, 0x00, 0x26, 0x65, 0xa7, 0xe5, 0xe1, 0x83, 0x8e, 0x09, 0xb0, 0x88, 0xa8, 0x83, 0x14, 0xde, 0x8c, - 0x35, 0xa7, 0x76, 0xa8, 0xbf, 0x83, 0xdd, 0x97, 0xe8, 0x83, 0xba, 0xa3, 0x3f, 0xbc, 0xd4, 0xdf, 0x21, 0x8c, 0x31, - 0xea, 0xf1, 0x73, 0xda, 0xbd, 0xba, 0xa9, 0x93, 0xb0, 0x7c, 0x8d, 0xf1, 0x0f, 0x80, 0x59, 0xfc, 0xc2, 0xf7, 0xe6, - 0x61, 0x94, 0xa4, 0xfe, 0x44, 0xbf, 0x1a, 0xbc, 0xf6, 0x5b, 0x97, 0xcb, 0xb4, 0x65, 0x5c, 0x99, 0x93, 0x54, 0x0d, - 0x9d, 0x22, 0x10, 0x26, 0x46, 0x4e, 0x69, 0x2a, 0xa4, 0x9e, 0xa0, 0xad, 0x05, 0x05, 0x6a, 0xc6, 0x42, 0x93, 0x74, - 0x08, 0xe5, 0x4a, 0x71, 0x58, 0x30, 0xa0, 0x94, 0x8e, 0x35, 0x8d, 0x01, 0xbd, 0x70, 0x9e, 0xaf, 0x37, 0x78, 0x95, - 0xa7, 0xf9, 0x6d, 0x89, 0xbe, 0x83, 0x85, 0xc1, 0x0d, 0x7d, 0x3f, 0x50, 0x95, 0x45, 0x0b, 0xf7, 0xee, 0xe8, 0xdb, - 0x22, 0x5d, 0x00, 0xf7, 0x37, 0x68, 0x6a, 0x84, 0x51, 0xaa, 0x81, 0x43, 0x1c, 0xe8, 0x71, 0x54, 0x56, 0x2e, 0xe3, - 0xad, 0xb6, 0x8c, 0x8c, 0x23, 0x83, 0xef, 0xf0, 0xf2, 0x6b, 0x71, 0xb7, 0x68, 0x05, 0xcf, 0x17, 0xf4, 0xc8, 0x08, - 0x61, 0x01, 0x0b, 0x14, 0xa5, 0x82, 0xfb, 0x77, 0xde, 0xbd, 0x2d, 0x41, 0x5e, 0x8b, 0x68, 0x80, 0x2d, 0x1e, 0xd0, - 0x54, 0x10, 0x3a, 0xa5, 0x33, 0x85, 0x0a, 0x23, 0x82, 0x86, 0x49, 0x41, 0xbf, 0x0c, 0xef, 0x02, 0x40, 0x49, 0xfc, - 0x9a, 0x1e, 0x65, 0xd7, 0x22, 0xe4, 0xb2, 0x08, 0x78, 0xac, 0x5c, 0xce, 0x80, 0x5d, 0xc3, 0xd5, 0x3a, 0x45, 0x17, - 0xbd, 0x30, 0x00, 0x96, 0xe9, 0x1a, 0xba, 0xfc, 0x04, 0x2c, 0x9d, 0x93, 0x89, 0x99, 0xae, 0xf9, 0xd3, 0x6a, 0x1a, - 0x27, 0x7a, 0x01, 0x79, 0x21, 0x7e, 0x47, 0x06, 0x17, 0x7c, 0xc6, 0x7c, 0x1a, 0x13, 0x33, 0xf7, 0x6f, 0xdf, 0x9a, - 0xa0, 0x20, 0xa8, 0x06, 0x33, 0x4c, 0xa8, 0x9d, 0x41, 0x2b, 0xa8, 0x9d, 0x2c, 0xb8, 0xed, 0x2c, 0x4c, 0x73, 0xf4, - 0x68, 0x13, 0x66, 0x67, 0x8f, 0x36, 0x49, 0x36, 0x7c, 0xb4, 0xf1, 0xa4, 0x8e, 0x81, 0x7e, 0xa1, 0x93, 0x82, 0xc1, - 0x08, 0xc1, 0x30, 0xca, 0xae, 0x73, 0x8b, 0x9f, 0x7c, 0xbe, 0xb0, 0xcb, 0x28, 0x5d, 0x43, 0x91, 0xff, 0x90, 0x0b, - 0xf6, 0x57, 0xb1, 0xbf, 0xf4, 0xe2, 0x7b, 0xd2, 0x03, 0x30, 0x55, 0x65, 0x01, 0x43, 0xd7, 0x08, 0xd1, 0x13, 0x00, - 0x08, 0xe7, 0xeb, 0xda, 0x37, 0x32, 0x8d, 0xf1, 0xd9, 0x4a, 0x61, 0x28, 0xf4, 0x75, 0xad, 0x3f, 0x65, 0xf6, 0x94, - 0xa5, 0x9e, 0x1f, 0x50, 0x95, 0x81, 0x88, 0x72, 0x5f, 0x99, 0x5e, 0x52, 0x9c, 0x5e, 0x58, 0xdc, 0x3f, 0x38, 0x19, - 0xba, 0x02, 0x68, 0xdc, 0x38, 0x33, 0x8c, 0x7e, 0x55, 0xbf, 0xa2, 0x94, 0xf7, 0xa7, 0x2e, 0x07, 0x83, 0xe5, 0x08, - 0x61, 0x39, 0x58, 0x38, 0x89, 0xa6, 0xec, 0xa7, 0xb7, 0xaf, 0x65, 0xb8, 0x2d, 0xe0, 0x1c, 0x8d, 0xf8, 0xc6, 0x4c, - 0x90, 0x7e, 0x88, 0x91, 0x76, 0xa0, 0xc0, 0x58, 0x9a, 0xdc, 0x42, 0x71, 0xa6, 0x6b, 0x67, 0x34, 0x76, 0x36, 0xa5, - 0x51, 0x0f, 0x23, 0xac, 0x15, 0x67, 0x27, 0x07, 0x54, 0x9a, 0x6e, 0x3b, 0x2a, 0x04, 0x60, 0x88, 0x61, 0x86, 0x39, - 0x14, 0x20, 0x32, 0xe8, 0xd0, 0xcd, 0x1f, 0x14, 0xf6, 0x12, 0xf9, 0xf3, 0xee, 0x59, 0x91, 0x54, 0xc1, 0x5a, 0xfa, - 0xe9, 0x09, 0xc6, 0xfa, 0x82, 0xfb, 0x1a, 0xbc, 0x83, 0x9c, 0x1c, 0xd0, 0xa7, 0x56, 0x3a, 0x11, 0x79, 0x23, 0xe2, - 0x69, 0xd7, 0xe7, 0x0d, 0x7c, 0xd2, 0x51, 0x81, 0xd0, 0xf2, 0x90, 0xea, 0x65, 0xba, 0xb6, 0xe4, 0xa4, 0x11, 0x77, - 0x43, 0x04, 0x3e, 0x0a, 0x1c, 0x38, 0xbb, 0xba, 0xb6, 0xf4, 0xee, 0x70, 0xe6, 0x22, 0xc7, 0xbb, 0x6b, 0xb9, 0x3c, - 0x2b, 0x3f, 0x6b, 0x49, 0xf1, 0xac, 0x4d, 0xf8, 0xe2, 0x82, 0x01, 0x82, 0x7c, 0x91, 0x2f, 0x50, 0xb0, 0x5b, 0xb3, - 0xb8, 0x0b, 0xb1, 0xb8, 0xd3, 0x86, 0xc5, 0x9d, 0x6e, 0x59, 0xdc, 0x80, 0x2f, 0xa4, 0x26, 0x41, 0x17, 0xa3, 0x51, - 0x99, 0x04, 0x1e, 0x27, 0x34, 0xfa, 0xfc, 0x9c, 0x21, 0x9c, 0xac, 0x24, 0x00, 0xa5, 0xaa, 0x06, 0x58, 0xd5, 0xc1, - 0x45, 0x01, 0x44, 0x75, 0xe2, 0xf2, 0xd4, 0x89, 0x79, 0x43, 0xec, 0xce, 0x56, 0x50, 0x9e, 0x2f, 0xec, 0x52, 0x8a, - 0x4b, 0xde, 0x5a, 0x34, 0xcc, 0x74, 0xb1, 0x65, 0xa6, 0x93, 0xc2, 0xd1, 0xe5, 0xd3, 0xa6, 0x43, 0xa8, 0x4e, 0x0a, - 0xf6, 0x20, 0x28, 0x9a, 0xe2, 0x96, 0x29, 0xee, 0xc3, 0x66, 0x1c, 0xab, 0xec, 0xa8, 0x95, 0x97, 0x24, 0xb7, 0x51, - 0x0c, 0x92, 0x1a, 0x68, 0xe6, 0xd3, 0xb6, 0xd4, 0xd2, 0x0f, 0xb9, 0x13, 0x98, 0xc6, 0xcd, 0x94, 0xe7, 0xab, 0x5b, - 0xaa, 0xdd, 0xed, 0x52, 0x89, 0x95, 0x97, 0xa6, 0x2c, 0x46, 0xa0, 0x7b, 0xe0, 0x2d, 0xfc, 0xbf, 0x64, 0x9b, 0xd5, - 0xe0, 0x90, 0x40, 0xc1, 0xea, 0x88, 0xa1, 0x57, 0x40, 0x5b, 0xc5, 0xe2, 0x22, 0x56, 0x1c, 0xca, 0xc5, 0x12, 0xf0, - 0x3f, 0xe0, 0x71, 0x6d, 0xc5, 0x8a, 0xc9, 0x93, 0x7b, 0x64, 0xd8, 0x2b, 0x6f, 0xfa, 0x0e, 0x04, 0x82, 0xad, 0xb6, - 0x09, 0xca, 0xbd, 0xaa, 0xfb, 0xb8, 0x98, 0x88, 0xbd, 0x49, 0x8e, 0x24, 0x11, 0x4b, 0x72, 0xd5, 0x29, 0xb0, 0xba, - 0xf4, 0xac, 0xd9, 0xd5, 0xa6, 0x9d, 0x1d, 0xcc, 0x7d, 0xa3, 0x82, 0x35, 0x01, 0xb5, 0x05, 0xc3, 0x53, 0xf9, 0xe6, - 0x0a, 0x4c, 0xf7, 0xc8, 0x00, 0x8e, 0xf1, 0x25, 0xc4, 0x41, 0x75, 0xc4, 0x83, 0x76, 0x14, 0xc3, 0xad, 0x75, 0xe9, - 0x5c, 0x65, 0x8f, 0xe7, 0xf8, 0xcb, 0xbd, 0xca, 0x1e, 0x8f, 0xf1, 0x57, 0xfb, 0x0a, 0x23, 0xde, 0xd5, 0x3c, 0xe4, - 0x95, 0x39, 0xeb, 0xa7, 0x85, 0xfd, 0x44, 0x7a, 0x6b, 0x9f, 0xb0, 0x6d, 0xf8, 0x02, 0x3f, 0x7c, 0xb4, 0x49, 0xc0, - 0x52, 0x53, 0x9d, 0x43, 0x68, 0xc7, 0x46, 0x56, 0x9b, 0x3e, 0x6f, 0x48, 0x1f, 0x1b, 0x7f, 0xf2, 0xc5, 0x8f, 0xbb, - 0x24, 0xca, 0xef, 0x94, 0x22, 0x1b, 0xe2, 0x7a, 0xec, 0x87, 0x5e, 0x7c, 0x7f, 0x4d, 0xcf, 0x8b, 0x96, 0xa0, 0xdd, - 0x25, 0x7b, 0x85, 0xc8, 0xcb, 0xa2, 0x98, 0x2c, 0x55, 0x18, 0xc3, 0xf7, 0xfc, 0xa2, 0x1f, 0xfe, 0x3d, 0x56, 0xc8, - 0xb6, 0xc2, 0x03, 0x94, 0x2f, 0x48, 0xa1, 0xa3, 0xeb, 0x47, 0x9b, 0x16, 0xab, 0x36, 0x53, 0x9a, 0x6d, 0x89, 0x2e, - 0x84, 0xe5, 0xc1, 0xc7, 0xec, 0x72, 0xea, 0xf7, 0x51, 0x0e, 0x36, 0x8e, 0xee, 0xac, 0x47, 0x9b, 0xf4, 0x4c, 0x5f, - 0x7a, 0xf1, 0x07, 0x36, 0xb5, 0x26, 0x7e, 0x3c, 0x09, 0x98, 0xde, 0xd7, 0xc7, 0x81, 0x17, 0x7e, 0xe0, 0x9f, 0x56, - 0xb4, 0x4e, 0x51, 0xb2, 0xbd, 0xf3, 0xed, 0x2b, 0x60, 0x42, 0x2c, 0x3b, 0x24, 0x56, 0x6b, 0xa0, 0xa0, 0x3d, 0x97, - 0x0c, 0xaf, 0x9c, 0x50, 0xcc, 0x4b, 0x99, 0xa0, 0x98, 0x09, 0xc2, 0x76, 0xb0, 0x74, 0x35, 0x75, 0x5c, 0x2f, 0xdd, - 0x54, 0xa7, 0x4a, 0xcc, 0x4a, 0x19, 0xaa, 0xf1, 0x1a, 0x5b, 0xf8, 0xfd, 0xdd, 0x51, 0x10, 0xed, 0xfd, 0xbb, 0x93, - 0xad, 0x7c, 0xde, 0x0c, 0x21, 0xd5, 0x22, 0x0b, 0x8b, 0x4f, 0xe8, 0x9c, 0x13, 0x98, 0xcd, 0x5d, 0xab, 0x95, 0xbd, - 0x24, 0x59, 0x2f, 0xd9, 0x94, 0x24, 0x8a, 0x67, 0xf9, 0xa0, 0x8a, 0x2f, 0x0b, 0x75, 0x60, 0xbf, 0xac, 0xdb, 0xc7, - 0x87, 0xcf, 0x41, 0xd3, 0x01, 0x08, 0xca, 0x68, 0x36, 0xd3, 0xf3, 0x37, 0xfe, 0x8e, 0x6a, 0xee, 0xe1, 0x2f, 0xeb, - 0x57, 0x2f, 0x9d, 0x57, 0xb2, 0x72, 0x08, 0x84, 0xb1, 0x10, 0xdb, 0x72, 0xba, 0x58, 0x19, 0xaf, 0x98, 0xd1, 0xcc, - 0x0b, 0x9b, 0xa7, 0x73, 0x59, 0xd8, 0xe2, 0x2b, 0xc6, 0xa6, 0x40, 0x70, 0x9b, 0x95, 0xd4, 0xeb, 0x80, 0xdd, 0x30, - 0x29, 0x12, 0xae, 0x76, 0x56, 0x53, 0x03, 0x7d, 0xd6, 0x71, 0x51, 0x33, 0xa7, 0xea, 0x94, 0x29, 0x8d, 0x70, 0x0e, - 0x7c, 0xe6, 0xea, 0x11, 0x2b, 0x1d, 0xa9, 0x91, 0xa9, 0x2b, 0x03, 0x68, 0x1c, 0xd9, 0x59, 0x43, 0x7a, 0x1f, 0x03, - 0x56, 0xd7, 0x8f, 0xcd, 0x74, 0x8d, 0x3e, 0xf8, 0xf8, 0xe6, 0x70, 0x0a, 0xe0, 0xe4, 0xb5, 0x72, 0x76, 0x48, 0x13, - 0xc4, 0xea, 0x98, 0x64, 0x3a, 0x71, 0x5f, 0x84, 0x96, 0x24, 0xaa, 0x0b, 0x0b, 0x3e, 0x54, 0xed, 0xda, 0x68, 0xc5, - 0x99, 0x8f, 0x31, 0x10, 0x6c, 0xc8, 0x92, 0xa4, 0x11, 0x60, 0x72, 0xd1, 0x4d, 0x3d, 0x2f, 0x5d, 0x84, 0x47, 0x9e, - 0x6e, 0x3a, 0x26, 0x90, 0x04, 0x38, 0xc1, 0x72, 0x5f, 0x78, 0xbd, 0x5c, 0x2f, 0xb9, 0x9e, 0x4b, 0x3c, 0x1f, 0xeb, - 0x5c, 0x07, 0xa1, 0x29, 0xff, 0x56, 0xe7, 0x83, 0x2a, 0x5c, 0xd3, 0xb5, 0x43, 0x6b, 0x15, 0x50, 0x6f, 0x85, 0x5d, - 0x84, 0x0d, 0x88, 0x31, 0x95, 0xf0, 0x2b, 0x9b, 0xcd, 0xd8, 0x24, 0x4d, 0x0c, 0xc1, 0x3c, 0x92, 0x5e, 0x67, 0xc1, - 0xda, 0xe8, 0xc1, 0x50, 0xff, 0x01, 0x6c, 0xef, 0x85, 0x73, 0x26, 0x3e, 0x20, 0xf1, 0x66, 0xaa, 0x07, 0x13, 0xb5, - 0x58, 0x04, 0x11, 0xef, 0x05, 0x82, 0x8a, 0xd7, 0xa4, 0xe3, 0xd0, 0xf8, 0xfd, 0x93, 0xef, 0x8b, 0x48, 0x6a, 0xc3, - 0x6c, 0x47, 0x45, 0xdb, 0x8e, 0xef, 0xc6, 0x7d, 0xd5, 0x75, 0x9d, 0x4c, 0x37, 0xc1, 0xe6, 0xeb, 0xc3, 0xbe, 0x87, - 0x1e, 0x6b, 0x75, 0xa0, 0xd6, 0x3a, 0xfc, 0x94, 0x7a, 0x6d, 0xf7, 0x99, 0xab, 0x9b, 0xa4, 0x6a, 0xa7, 0xe0, 0xb6, - 0x49, 0x74, 0xc3, 0xe2, 0xcf, 0x9e, 0x4a, 0xb1, 0xf1, 0xfd, 0xc6, 0x73, 0xe4, 0x3a, 0x80, 0x84, 0xd3, 0x68, 0xf5, - 0x09, 0x53, 0xe8, 0xe8, 0xa6, 0x3e, 0x09, 0xa2, 0x84, 0xa9, 0x73, 0x20, 0x26, 0xc8, 0x67, 0x4e, 0xe2, 0xc7, 0xb7, - 0x2f, 0xdf, 0xbd, 0xd3, 0x4d, 0x8c, 0x20, 0x9a, 0xa8, 0xad, 0xf3, 0x0d, 0xb5, 0x03, 0xfb, 0xd7, 0xee, 0x3b, 0xba, - 0x61, 0xe8, 0x51, 0x5b, 0xdc, 0x73, 0x94, 0x56, 0xd9, 0x72, 0xfc, 0xe6, 0xe1, 0x3d, 0xd3, 0x4b, 0x74, 0xaf, 0x79, - 0xd5, 0xe0, 0x86, 0xed, 0xd7, 0x5b, 0x21, 0x65, 0xe9, 0x87, 0xd7, 0x35, 0xa9, 0xde, 0x5d, 0x4d, 0x2a, 0x3c, 0xe5, - 0x2a, 0xb8, 0x6a, 0x1d, 0x2d, 0x15, 0xd2, 0x00, 0x02, 0x40, 0xef, 0x02, 0x97, 0xf2, 0x9e, 0xfa, 0x8c, 0x41, 0x73, - 0x0f, 0xf0, 0xe5, 0x51, 0xd7, 0x24, 0xf3, 0x47, 0x90, 0x84, 0xed, 0x24, 0x00, 0x45, 0x41, 0xa6, 0x4a, 0xe5, 0x8a, - 0x64, 0x23, 0x57, 0xf3, 0x1d, 0x96, 0x28, 0x74, 0xaa, 0x46, 0x02, 0x10, 0x8e, 0xdf, 0x57, 0xde, 0x14, 0xb4, 0xef, - 0xac, 0x71, 0x94, 0xa6, 0xd1, 0xb2, 0xef, 0x3a, 0xab, 0x3b, 0x5d, 0x1b, 0x08, 0xc6, 0x03, 0x57, 0x0e, 0xec, 0xff, - 0xf6, 0xef, 0x12, 0xca, 0xa5, 0xf4, 0xeb, 0x94, 0x2d, 0x57, 0x2c, 0xf6, 0xd2, 0x75, 0xcc, 0x32, 0xed, 0xb7, 0xff, - 0x7b, 0x5e, 0x7a, 0x64, 0x0f, 0xd4, 0x3a, 0x44, 0x5e, 0xab, 0x55, 0xae, 0x83, 0xe8, 0xf6, 0x41, 0x6e, 0x06, 0xb0, - 0xa3, 0xf0, 0xc2, 0x9f, 0x2f, 0x64, 0xe9, 0xb3, 0x74, 0xcb, 0xdc, 0xc4, 0xe8, 0x89, 0xe9, 0xae, 0x9d, 0x47, 0xb7, - 0xfd, 0xdf, 0xfe, 0x2d, 0x99, 0x27, 0x3b, 0x77, 0x5d, 0xfd, 0x40, 0x8b, 0x2b, 0x5a, 0x5f, 0xa6, 0xb2, 0xc4, 0x90, - 0x5f, 0x59, 0xe0, 0x4a, 0x22, 0xed, 0xca, 0xaa, 0x84, 0x6b, 0xcb, 0x9c, 0xfe, 0xea, 0xcf, 0x17, 0x9f, 0x3b, 0x29, - 0x00, 0xe8, 0xce, 0x59, 0x41, 0xa1, 0x2f, 0x30, 0xad, 0x51, 0x7f, 0xff, 0x05, 0xfb, 0xcc, 0x79, 0xed, 0x9a, 0xd2, - 0x97, 0x98, 0x0d, 0xe7, 0xa2, 0x3e, 0x1f, 0x8d, 0x64, 0x04, 0x3d, 0xb5, 0x3e, 0x18, 0x32, 0x9c, 0x55, 0x52, 0xf8, - 0x55, 0xdf, 0x77, 0x0c, 0xf2, 0x30, 0xb0, 0x07, 0x40, 0x50, 0x25, 0xaf, 0x06, 0x1c, 0xcd, 0xf8, 0x9a, 0x34, 0xeb, - 0x2b, 0x7d, 0x57, 0x90, 0x35, 0xa4, 0x62, 0xf4, 0x35, 0x29, 0x9a, 0x33, 0xeb, 0x87, 0x73, 0x1b, 0x7b, 0x2b, 0x62, - 0xd8, 0x6b, 0x28, 0x8f, 0x00, 0x06, 0x88, 0x78, 0xd1, 0x62, 0x70, 0x97, 0x37, 0x4d, 0x0a, 0x71, 0x3f, 0xee, 0x56, - 0x88, 0xbb, 0xd8, 0x4b, 0x21, 0xee, 0xc7, 0x2f, 0xae, 0x10, 0xf7, 0x46, 0x55, 0x88, 0x83, 0xb5, 0x7c, 0xc9, 0xf6, - 0xd2, 0x52, 0x13, 0xaa, 0x26, 0xd1, 0x6d, 0x32, 0x74, 0x39, 0x1d, 0x9e, 0x4c, 0x16, 0x0c, 0x18, 0x1b, 0x1c, 0xea, - 0x41, 0x34, 0x07, 0x8d, 0xb5, 0x3f, 0x5e, 0xb7, 0x2c, 0x88, 0xe6, 0xaa, 0x66, 0x59, 0xc8, 0xdd, 0xdb, 0xe6, 0x2e, - 0xab, 0x48, 0x9b, 0xcb, 0x31, 0x85, 0x83, 0x2b, 0xeb, 0xd0, 0x50, 0x42, 0x78, 0x4b, 0x55, 0xbd, 0xb6, 0xd0, 0xf7, - 0xea, 0xa3, 0xaa, 0x98, 0xac, 0xd8, 0x7e, 0x2a, 0x1c, 0x79, 0xa8, 0x2d, 0x48, 0x95, 0x68, 0x72, 0x8a, 0xb1, 0xd1, - 0x7f, 0xb9, 0x73, 0xbf, 0xbb, 0x74, 0x07, 0x1d, 0x17, 0x2c, 0xd1, 0xe1, 0x59, 0x8c, 0x09, 0xce, 0xa0, 0xd3, 0x81, - 0x84, 0x5b, 0x25, 0xa1, 0x0d, 0x09, 0xbe, 0x92, 0xd0, 0x85, 0x84, 0x89, 0x92, 0x70, 0x04, 0x09, 0x53, 0x25, 0xe1, - 0x18, 0x12, 0x6e, 0xf4, 0xec, 0x32, 0x94, 0xc3, 0x3d, 0x36, 0xae, 0x4c, 0x7a, 0x09, 0x89, 0xb4, 0x63, 0xd3, 0x05, - 0x15, 0x31, 0x6f, 0xde, 0x8f, 0x4c, 0x62, 0x89, 0xf6, 0x63, 0xf3, 0x76, 0xc1, 0xc8, 0x2b, 0xf6, 0x0b, 0xbc, 0x28, - 0xed, 0x34, 0x02, 0x25, 0x71, 0xe1, 0x6d, 0x42, 0xc0, 0x41, 0xd3, 0x0d, 0xe0, 0x72, 0x0d, 0xe4, 0xca, 0x09, 0x8f, - 0x1d, 0xca, 0x5a, 0xe6, 0x79, 0xd4, 0x9d, 0x25, 0xb7, 0x40, 0xae, 0x26, 0xd3, 0x52, 0x59, 0xa9, 0x5f, 0x42, 0x59, - 0xe2, 0x05, 0x1b, 0xaf, 0xe7, 0xda, 0x79, 0x34, 0xdf, 0xa9, 0xf7, 0xa0, 0x66, 0xc1, 0x28, 0x75, 0x92, 0x19, 0x59, - 0x62, 0x5b, 0xf2, 0xbe, 0xe8, 0x33, 0x2b, 0x96, 0x4f, 0x61, 0x6c, 0x5a, 0x4a, 0x18, 0x07, 0xfa, 0x01, 0x18, 0x29, - 0x8a, 0x07, 0xe7, 0x00, 0x67, 0xe5, 0xfb, 0xc2, 0x53, 0xc6, 0x73, 0xfa, 0x3d, 0x4b, 0x12, 0x6f, 0x2e, 0xca, 0x57, - 0xc7, 0x09, 0x9a, 0x46, 0xf2, 0xd1, 0x88, 0x00, 0x04, 0xf6, 0xa3, 0x5f, 0x51, 0x28, 0x89, 0xa3, 0x5b, 0x0d, 0x54, - 0x96, 0x60, 0x43, 0xe5, 0xca, 0x15, 0xbe, 0x0d, 0x4b, 0x58, 0x54, 0x83, 0x80, 0xc3, 0x7f, 0xc3, 0x82, 0x72, 0x62, - 0xea, 0xcd, 0xcb, 0x49, 0xb4, 0x0f, 0x32, 0x75, 0x6c, 0x52, 0x0b, 0xa1, 0x90, 0xf8, 0x39, 0x62, 0xf5, 0x20, 0x9a, - 0xff, 0xa1, 0x32, 0xf5, 0x2d, 0xba, 0x10, 0xef, 0x42, 0xd3, 0x4f, 0x47, 0x36, 0xc2, 0x58, 0xb3, 0x01, 0x84, 0xfd, - 0x30, 0x5d, 0x58, 0x68, 0x47, 0xd7, 0x6a, 0x87, 0x86, 0x69, 0xe3, 0xda, 0x6e, 0xca, 0xd6, 0xc3, 0xfd, 0x78, 0x3e, - 0xf6, 0x5a, 0x6e, 0xfb, 0xd8, 0x14, 0x7f, 0x6c, 0xa7, 0x6b, 0x64, 0xd8, 0x82, 0x36, 0xf5, 0x6f, 0x36, 0xb3, 0x28, - 0x4c, 0xad, 0x99, 0xb7, 0xf4, 0x83, 0xfb, 0xfe, 0x32, 0x0a, 0xa3, 0x64, 0xe5, 0x4d, 0xd8, 0x20, 0xe7, 0x02, 0x0c, - 0xd0, 0x2f, 0x05, 0x37, 0x8d, 0x74, 0xed, 0x76, 0xcc, 0x96, 0x54, 0x5b, 0xba, 0x9d, 0x98, 0x05, 0xec, 0x2e, 0xe3, - 0xdd, 0x17, 0x0a, 0x53, 0x51, 0xdc, 0x72, 0x54, 0x03, 0xc8, 0x68, 0xee, 0xd3, 0x02, 0x3c, 0x39, 0x0d, 0x38, 0x2d, - 0xda, 0xb7, 0xdb, 0xdd, 0x98, 0x2d, 0x35, 0xbb, 0xdb, 0xd8, 0x78, 0x1c, 0xdd, 0x9e, 0xc2, 0x68, 0xb1, 0xb2, 0x95, - 0xb0, 0x60, 0x86, 0x39, 0x16, 0x9a, 0xd1, 0x88, 0x76, 0x2c, 0xe4, 0x1e, 0x40, 0x6b, 0x6c, 0x39, 0x80, 0xec, 0x7e, - 0x5b, 0x73, 0x06, 0x4b, 0x3f, 0xb4, 0x68, 0x3a, 0xc7, 0xce, 0x4a, 0x69, 0x4b, 0x85, 0x9f, 0xb1, 0xc1, 0xe2, 0xae, - 0xe6, 0x0c, 0xe0, 0x85, 0x39, 0x0b, 0xa2, 0xdb, 0xfe, 0xc2, 0x9f, 0x4e, 0x59, 0x38, 0xc0, 0x31, 0xcb, 0x44, 0x16, - 0x04, 0xfe, 0x2a, 0xf1, 0x93, 0xc1, 0xd2, 0xbb, 0xe3, 0xad, 0x1e, 0x36, 0xb5, 0xda, 0xe1, 0xad, 0x76, 0xf6, 0x6e, - 0x55, 0x69, 0x06, 0x4c, 0x76, 0xa8, 0x1d, 0x3e, 0xb4, 0xae, 0xe6, 0x94, 0xe6, 0xb9, 0x77, 0xab, 0xab, 0x98, 0x6d, - 0x96, 0x5e, 0x3c, 0xf7, 0xc3, 0xbe, 0x93, 0xd9, 0x37, 0x1b, 0xda, 0x18, 0x0f, 0x7b, 0xbd, 0x5e, 0x66, 0x4f, 0xc5, - 0x97, 0x33, 0x9d, 0x66, 0xf6, 0x44, 0x7c, 0xcd, 0x66, 0x8e, 0x33, 0x9b, 0x65, 0xb6, 0x2f, 0x12, 0x3a, 0xed, 0xc9, - 0xb4, 0xd3, 0xce, 0xec, 0x5b, 0xa5, 0x44, 0x66, 0x33, 0xfe, 0x15, 0xb3, 0xe9, 0x00, 0x37, 0x12, 0xe9, 0xd0, 0xf6, - 0x8f, 0x1d, 0x27, 0x43, 0x0c, 0x70, 0x59, 0xc0, 0x4d, 0xc8, 0xa0, 0xba, 0xda, 0xec, 0x5d, 0x52, 0xcb, 0xbb, 0x9b, - 0x4c, 0x6a, 0xcb, 0x4d, 0xbd, 0xf8, 0xc3, 0x95, 0xa6, 0xcc, 0xc2, 0xf3, 0xa8, 0xd8, 0x46, 0x80, 0xc1, 0xba, 0xeb, - 0x83, 0x7f, 0xb2, 0xc1, 0x38, 0x8a, 0xe1, 0xcc, 0xc6, 0xde, 0xd4, 0x5f, 0x27, 0x7d, 0xb7, 0xbd, 0xba, 0x13, 0x49, - 0x7c, 0xaf, 0xe7, 0x09, 0x78, 0xf6, 0xfa, 0x49, 0x14, 0xf8, 0x53, 0x91, 0xd4, 0x74, 0x96, 0xdc, 0xb6, 0x31, 0x40, - 0xeb, 0x7c, 0x1f, 0x7d, 0x4c, 0x78, 0x41, 0xa0, 0xd9, 0x9d, 0x44, 0x63, 0x5e, 0x82, 0x4c, 0x71, 0xcd, 0x49, 0x08, - 0x2e, 0x68, 0x89, 0xef, 0x1e, 0xae, 0xee, 0xe4, 0x9e, 0x77, 0x8f, 0x56, 0x77, 0xd9, 0x37, 0x4b, 0x36, 0xf5, 0x3d, - 0xad, 0x95, 0xef, 0x26, 0xd7, 0x01, 0xc6, 0xb9, 0xb1, 0x69, 0xd8, 0xa6, 0xe2, 0x58, 0x80, 0x1f, 0xc7, 0x07, 0xfe, - 0x72, 0x15, 0xc5, 0xa9, 0x17, 0xa6, 0x59, 0x36, 0xba, 0xca, 0xb2, 0xc1, 0x85, 0xdf, 0xba, 0xfc, 0x47, 0x8b, 0xee, - 0x69, 0x12, 0x34, 0x65, 0xc6, 0x95, 0xf9, 0x92, 0xa9, 0x8a, 0x2e, 0x70, 0x8d, 0xa1, 0x92, 0x8b, 0x5a, 0x98, 0x6e, - 0xc9, 0x6a, 0x61, 0x02, 0xb2, 0x2c, 0x4e, 0x8a, 0x33, 0xc5, 0x22, 0x78, 0x03, 0x41, 0x81, 0x97, 0x6c, 0x78, 0xa1, - 0x28, 0xcd, 0x00, 0xb1, 0x82, 0x85, 0xc9, 0x88, 0xe2, 0x51, 0x13, 0xcd, 0xf8, 0xed, 0x6e, 0x9a, 0xf1, 0xe7, 0x74, - 0x1f, 0x9a, 0xf1, 0xdb, 0x2f, 0x4e, 0x33, 0x3e, 0xaa, 0x1a, 0x51, 0xbc, 0x8e, 0x86, 0xba, 0x14, 0x8b, 0xc0, 0xd5, - 0x14, 0x93, 0x7b, 0xa2, 0xd7, 0xbf, 0xdb, 0xe6, 0x41, 0xb4, 0x46, 0x01, 0xf7, 0xe8, 0xe6, 0x06, 0x26, 0xf2, 0x9b, - 0x70, 0xf8, 0xf7, 0x58, 0xfd, 0x9e, 0xcd, 0x86, 0x2f, 0x22, 0x25, 0x41, 0x7e, 0x71, 0x8d, 0x91, 0x82, 0x2b, 0x09, - 0xca, 0x11, 0xaa, 0xa3, 0x18, 0x6c, 0x03, 0x2c, 0xd1, 0x49, 0x55, 0x7a, 0x2a, 0x55, 0xe6, 0x06, 0xc5, 0x21, 0xb4, - 0xa4, 0x9e, 0xaa, 0xb0, 0x37, 0xaa, 0xf0, 0x3f, 0xe7, 0x2c, 0xe5, 0x06, 0xc2, 0xdf, 0xdd, 0xbf, 0x9e, 0xb6, 0x5e, - 0x47, 0x46, 0xe6, 0x27, 0x6f, 0xca, 0xd6, 0x3e, 0x5c, 0x60, 0x35, 0x54, 0xa7, 0x93, 0x71, 0xb5, 0x37, 0x35, 0x9a, - 0x36, 0x64, 0x53, 0xf5, 0xb3, 0xc2, 0x4c, 0xfb, 0x6a, 0x45, 0x1e, 0xd5, 0xab, 0x72, 0x19, 0x73, 0x53, 0x8b, 0x0d, - 0xa7, 0x00, 0x31, 0x50, 0x19, 0x1a, 0x49, 0x4f, 0xa9, 0xba, 0x3f, 0xcd, 0x32, 0x63, 0x20, 0x00, 0xa1, 0x5c, 0xb4, - 0x6c, 0x17, 0x11, 0x97, 0xe4, 0xef, 0x31, 0x2e, 0xd6, 0x24, 0x99, 0xe5, 0x6b, 0xd0, 0x02, 0xe0, 0x12, 0x4e, 0x0e, - 0x33, 0x5d, 0x23, 0xf0, 0x91, 0x76, 0x88, 0x32, 0x21, 0x10, 0x5b, 0x4b, 0xf8, 0x8b, 0x2c, 0x91, 0x50, 0x55, 0x3c, - 0x25, 0xe0, 0xa0, 0x1a, 0x03, 0xb8, 0x34, 0x10, 0xcc, 0x1a, 0x42, 0x3b, 0xbc, 0x0c, 0x7e, 0x64, 0xba, 0xa4, 0xfd, - 0x70, 0xfb, 0x9d, 0x9e, 0x1c, 0x40, 0x85, 0xd3, 0x12, 0x23, 0x66, 0x87, 0x5a, 0x25, 0x90, 0x12, 0xc9, 0xad, 0x69, - 0x27, 0xb7, 0xda, 0x93, 0x8d, 0x70, 0x07, 0x92, 0x7a, 0x2b, 0x0b, 0x5e, 0xff, 0x88, 0x7b, 0x39, 0xc6, 0x53, 0x3c, - 0x8f, 0x0c, 0xd6, 0x09, 0xe0, 0x46, 0x7c, 0x88, 0x22, 0xfe, 0x19, 0x4c, 0xd6, 0x71, 0x12, 0xc5, 0xfd, 0x55, 0xe4, - 0x87, 0x29, 0x8b, 0x33, 0x04, 0xd5, 0x25, 0xc2, 0x47, 0x80, 0xe7, 0x6a, 0x13, 0xad, 0xbc, 0x89, 0x9f, 0xde, 0xf7, - 0x1d, 0x4e, 0x52, 0x38, 0x03, 0x4e, 0x1d, 0x38, 0xb5, 0xe5, 0xfb, 0x1c, 0x9a, 0x4f, 0x91, 0xf0, 0x8b, 0xab, 0xe4, - 0x8c, 0xba, 0xcd, 0x07, 0x4a, 0x2e, 0x39, 0x44, 0x01, 0xf2, 0xc3, 0x8b, 0xad, 0x39, 0x60, 0x79, 0x58, 0x6a, 0x67, - 0xca, 0xe6, 0x26, 0x62, 0x6d, 0x10, 0x26, 0x88, 0x3f, 0x76, 0xd7, 0xd0, 0x9c, 0xfa, 0x64, 0xa0, 0x78, 0x8c, 0x7d, - 0x46, 0xd6, 0xf7, 0x20, 0x7c, 0x98, 0xb9, 0x4f, 0xc9, 0x31, 0x9b, 0x45, 0x31, 0x23, 0xe7, 0xb9, 0x6e, 0x6f, 0x75, - 0xb7, 0x7f, 0xf3, 0xdb, 0xa7, 0x5f, 0xdf, 0x4e, 0x18, 0xa5, 0x2d, 0xd1, 0x98, 0xb1, 0xa3, 0xb5, 0xea, 0x7d, 0x06, - 0xa4, 0x21, 0x41, 0x7e, 0x42, 0x7e, 0xca, 0xfa, 0xba, 0x3e, 0xa8, 0xf5, 0x51, 0xb6, 0x8a, 0xf8, 0x9d, 0x17, 0xb3, - 0xc0, 0x4b, 0xfd, 0x1b, 0x41, 0x33, 0x76, 0x8e, 0x56, 0x77, 0x62, 0x8d, 0xf1, 0xc2, 0xfb, 0x84, 0x45, 0x2a, 0x0d, - 0x45, 0x2c, 0x52, 0x39, 0x19, 0x17, 0x69, 0x50, 0x99, 0x8d, 0x70, 0xdb, 0x51, 0xba, 0xe9, 0xbb, 0xab, 0x3b, 0xf5, - 0x8a, 0xce, 0xab, 0xc9, 0x9b, 0xba, 0xec, 0x6f, 0x6d, 0xe9, 0x4f, 0xa7, 0x01, 0xcb, 0x0a, 0x0b, 0x5d, 0x5c, 0x4b, - 0x05, 0x38, 0x12, 0x0e, 0xde, 0x38, 0x89, 0x82, 0x75, 0xca, 0xea, 0xc1, 0x45, 0xc0, 0x69, 0x3b, 0x39, 0x70, 0xf0, - 0x77, 0x71, 0xac, 0x5d, 0x20, 0xb7, 0x61, 0x9b, 0x38, 0x03, 0x70, 0xaf, 0x6c, 0x75, 0x8a, 0x43, 0x87, 0x2c, 0x39, - 0x68, 0xb3, 0x66, 0x22, 0x26, 0x5c, 0x4b, 0x84, 0xbd, 0x35, 0xdb, 0xe5, 0x69, 0xd2, 0xc5, 0xac, 0x4c, 0xca, 0x8a, - 0x93, 0xf9, 0x63, 0xce, 0xd8, 0xb3, 0xfa, 0x33, 0xf6, 0x4c, 0x9c, 0xb1, 0xed, 0x3b, 0xf3, 0xe1, 0xcc, 0x85, 0xff, - 0x06, 0xf9, 0x84, 0xfa, 0x8e, 0xd6, 0x59, 0xdd, 0x69, 0xee, 0xea, 0x4e, 0xb3, 0xda, 0xab, 0x3b, 0x0d, 0x9b, 0x46, - 0x25, 0x16, 0xd3, 0x6e, 0x1b, 0xa6, 0xa3, 0x41, 0x22, 0xfc, 0x71, 0x0a, 0x59, 0xee, 0x21, 0xe4, 0x41, 0xad, 0x6e, - 0x35, 0xaf, 0xbd, 0xfd, 0xa8, 0xd3, 0x59, 0x12, 0x48, 0xdb, 0xb0, 0x53, 0x6f, 0x3c, 0x66, 0xd3, 0xfe, 0x2c, 0x9a, - 0xac, 0x93, 0x7f, 0xf1, 0xf1, 0x73, 0x20, 0x6e, 0x45, 0x04, 0xa5, 0x76, 0x44, 0x55, 0x90, 0xee, 0xdc, 0x30, 0xd1, - 0xc2, 0x46, 0xae, 0x53, 0x9f, 0x7c, 0x41, 0xb7, 0xed, 0xc3, 0x9a, 0x4d, 0x5e, 0x0f, 0xe8, 0x3f, 0x6c, 0x95, 0x9a, - 0x51, 0xcc, 0x67, 0x80, 0x65, 0x2b, 0x38, 0x3e, 0x1d, 0x1a, 0x7c, 0x35, 0x9d, 0x5e, 0xfd, 0x70, 0x2f, 0x45, 0x4f, - 0x57, 0xe2, 0x52, 0xe1, 0xf7, 0x16, 0xb7, 0xa6, 0xd9, 0xde, 0x6a, 0xd3, 0x1e, 0xa9, 0xb4, 0xba, 0xe5, 0x42, 0xc8, - 0xcb, 0xee, 0x89, 0xe5, 0x1f, 0x3e, 0x3b, 0x84, 0xff, 0x88, 0xaa, 0xff, 0x39, 0xad, 0x23, 0xd4, 0x5f, 0x17, 0xd5, - 0xd7, 0x89, 0x54, 0x42, 0x42, 0x7c, 0xff, 0xf2, 0xb3, 0xd9, 0xa7, 0x55, 0xd8, 0xbb, 0x34, 0xe9, 0x7f, 0x95, 0x4b, - 0x7f, 0x17, 0x45, 0x10, 0xa7, 0xb4, 0x5a, 0x5c, 0x80, 0x87, 0x34, 0xf4, 0xd3, 0x21, 0x54, 0x12, 0xef, 0x08, 0x52, - 0x3d, 0xd0, 0xb1, 0x0e, 0x3d, 0x25, 0x5e, 0x36, 0x3d, 0x25, 0x5e, 0xec, 0x7e, 0x4a, 0xfc, 0x6d, 0xaf, 0xa7, 0xc4, - 0x8b, 0x2f, 0xfe, 0x94, 0x78, 0x59, 0x7d, 0x4a, 0x5c, 0x44, 0x42, 0xe9, 0xd7, 0x7c, 0xbd, 0xe6, 0x3f, 0xdf, 0x93, - 0x24, 0xf1, 0x3c, 0x1a, 0x76, 0x1d, 0xf2, 0xef, 0x7c, 0xf1, 0xbb, 0x1f, 0x16, 0xb8, 0x11, 0xdf, 0xa2, 0x0e, 0x5c, - 0xfe, 0xb4, 0xe0, 0x98, 0x1d, 0xfb, 0x51, 0x92, 0x83, 0x28, 0x9c, 0xff, 0x08, 0x92, 0x64, 0x60, 0x07, 0xc6, 0x4a, - 0x86, 0x9f, 0xfc, 0x18, 0xad, 0xd6, 0xab, 0xd7, 0xd0, 0xd6, 0x7b, 0x3f, 0xf1, 0xc7, 0x01, 0x93, 0x66, 0xd7, 0xa4, - 0xb3, 0xc7, 0x79, 0xe2, 0xa0, 0x26, 0x2b, 0x7e, 0x7a, 0x77, 0xe2, 0x27, 0x2a, 0xd2, 0xf2, 0xdf, 0xa4, 0x0c, 0xa8, - 0xd7, 0x3f, 0x44, 0xc0, 0x41, 0x51, 0x69, 0xd0, 0x9f, 0xfe, 0x18, 0xb9, 0x88, 0x8c, 0x9a, 0x59, 0x0a, 0x25, 0x8d, - 0xc6, 0x76, 0x58, 0xe5, 0x51, 0xb3, 0x36, 0x4c, 0xe9, 0x6f, 0xac, 0xca, 0x86, 0x5f, 0x46, 0xeb, 0x84, 0x4d, 0xa3, - 0xdb, 0x50, 0x37, 0x43, 0x69, 0x19, 0x01, 0x62, 0x59, 0x59, 0x07, 0x23, 0x65, 0xbe, 0x43, 0x42, 0x39, 0x8a, 0x5b, - 0x3a, 0x04, 0x6a, 0x5d, 0xaf, 0x2c, 0x92, 0x8f, 0x5b, 0x38, 0x45, 0x5d, 0x86, 0x74, 0x7a, 0xd0, 0x6a, 0x45, 0xc3, - 0x4f, 0xab, 0x29, 0xf4, 0x4b, 0x22, 0x9b, 0x73, 0x85, 0x93, 0x56, 0x28, 0x98, 0x8b, 0xc2, 0xe9, 0x47, 0xcd, 0xc2, - 0xf1, 0x1c, 0xb2, 0xb7, 0xcd, 0x73, 0xc1, 0x65, 0x4a, 0xb6, 0xe6, 0xeb, 0xc1, 0x5d, 0x60, 0xd0, 0xe7, 0x73, 0x05, - 0x8c, 0x6f, 0x6e, 0x58, 0x1c, 0x78, 0xf7, 0x2d, 0x23, 0x8b, 0xc2, 0xef, 0x01, 0x00, 0x2f, 0xa2, 0xdb, 0x50, 0x2d, - 0x80, 0x91, 0x69, 0x6a, 0xf6, 0x52, 0xad, 0xb3, 0x16, 0xb0, 0xb6, 0x51, 0x46, 0x00, 0x31, 0x81, 0xe7, 0xec, 0xef, - 0x26, 0xfd, 0xfb, 0x0f, 0x23, 0x33, 0xcf, 0x23, 0xd9, 0xd1, 0x4f, 0xab, 0x3d, 0xba, 0x79, 0xfc, 0xf8, 0x41, 0xf3, - 0xb4, 0x8b, 0xb1, 0xe8, 0x6b, 0x6a, 0x1b, 0x8d, 0xa7, 0x00, 0x46, 0x71, 0x11, 0xad, 0x27, 0x0b, 0xd4, 0xce, 0xfd, - 0x72, 0xf3, 0x4d, 0xa1, 0x4d, 0x0c, 0xc9, 0x2a, 0xa7, 0x5e, 0x4a, 0xca, 0xa1, 0x80, 0xfd, 0xbf, 0x04, 0x6f, 0xa3, - 0xff, 0x41, 0x30, 0x54, 0x77, 0x0d, 0x7f, 0xc5, 0xfb, 0x9f, 0xb6, 0x79, 0x07, 0x10, 0x39, 0x94, 0xfb, 0xf1, 0x10, - 0xc2, 0xb5, 0x7a, 0x24, 0x93, 0x95, 0x81, 0xa6, 0xfa, 0xcc, 0x6b, 0x72, 0x07, 0x28, 0x7a, 0x61, 0x36, 0x3d, 0xd3, - 0xb9, 0x75, 0x84, 0xc9, 0x38, 0xb6, 0x2a, 0x21, 0x19, 0xae, 0xa7, 0xc1, 0x10, 0x7d, 0x95, 0xf3, 0x96, 0x7e, 0x68, - 0xa2, 0xcb, 0xfb, 0x6a, 0x8e, 0x77, 0x07, 0x4e, 0x9f, 0x01, 0xb9, 0x95, 0xb3, 0x20, 0xd1, 0x54, 0x8d, 0xfd, 0x20, - 0xae, 0x95, 0x5e, 0x0b, 0x09, 0x21, 0xc5, 0x1b, 0x7d, 0xa5, 0x69, 0x9a, 0x26, 0x9f, 0x11, 0x9a, 0x7c, 0x47, 0x60, - 0x3a, 0x3e, 0x07, 0x40, 0x5a, 0x92, 0xad, 0xee, 0x28, 0x05, 0x5e, 0x06, 0x28, 0x99, 0x15, 0x09, 0xdc, 0xaf, 0x61, - 0xd7, 0x11, 0x09, 0xe2, 0x41, 0x0f, 0x3e, 0xe9, 0xbc, 0x18, 0xdc, 0x1f, 0xf7, 0x35, 0x7c, 0xb0, 0x63, 0x2e, 0xe7, - 0x04, 0x6b, 0x0e, 0x7d, 0x8e, 0x06, 0xac, 0xde, 0x01, 0x5e, 0xa8, 0x60, 0x41, 0x90, 0x3a, 0x94, 0xfc, 0x59, 0x9b, - 0xac, 0x06, 0x37, 0xe2, 0xbb, 0xe8, 0x2e, 0x5d, 0xb2, 0x70, 0xad, 0x63, 0x00, 0x2c, 0x74, 0x48, 0x08, 0x65, 0x5e, - 0x10, 0xb1, 0x05, 0xd8, 0xa6, 0xbe, 0xe6, 0x82, 0xee, 0xc2, 0x84, 0xa3, 0x54, 0xcf, 0x9c, 0x70, 0xc1, 0x66, 0xc2, - 0x71, 0x5b, 0xf9, 0x86, 0xe0, 0x4b, 0x1a, 0x95, 0xad, 0xcf, 0x48, 0x7d, 0x1b, 0xda, 0x20, 0x57, 0x20, 0x9c, 0x5d, - 0x24, 0xc0, 0xde, 0xf2, 0xca, 0x8b, 0x26, 0x25, 0x32, 0x5e, 0x89, 0x51, 0x14, 0x1b, 0xd5, 0x66, 0xf8, 0x38, 0xc1, - 0x0b, 0x53, 0x63, 0x3b, 0x93, 0x4a, 0x3b, 0x0d, 0x93, 0xfe, 0xc0, 0xee, 0xe9, 0x22, 0x21, 0x50, 0x7d, 0x60, 0xf7, - 0xa0, 0xb0, 0xf8, 0x12, 0xb8, 0x29, 0xfa, 0x16, 0x74, 0x6d, 0x42, 0x5c, 0x83, 0x09, 0x78, 0xe6, 0xda, 0x72, 0x80, - 0x9c, 0x6c, 0x0b, 0x16, 0x47, 0x10, 0x43, 0x08, 0x6b, 0x71, 0x88, 0xb9, 0x5d, 0x42, 0xab, 0x16, 0xc6, 0x56, 0xcd, - 0xd1, 0x30, 0x9e, 0xb8, 0x8e, 0x73, 0x50, 0x29, 0x0f, 0x8c, 0xec, 0xba, 0xd2, 0x86, 0x99, 0x0e, 0x5d, 0xc7, 0xf2, - 0x9f, 0xd8, 0xed, 0x41, 0xe5, 0x8e, 0x56, 0x1c, 0x67, 0x8e, 0x90, 0xfd, 0x75, 0xfa, 0x68, 0xd3, 0xaa, 0x1c, 0x48, - 0xa3, 0xac, 0xe7, 0x8f, 0x63, 0xcb, 0x38, 0xff, 0x6b, 0x54, 0xbd, 0xfa, 0xc9, 0x6d, 0x27, 0x05, 0x71, 0x19, 0x81, - 0xeb, 0xe7, 0x16, 0x1c, 0xa3, 0xbf, 0x68, 0x4f, 0xb5, 0x16, 0x1d, 0x1f, 0xc3, 0x18, 0xc9, 0xd8, 0xe0, 0xc2, 0x10, - 0x4e, 0x6d, 0xa0, 0xd4, 0x63, 0x52, 0xc6, 0x70, 0xdc, 0xc9, 0x2c, 0xcb, 0x25, 0x7a, 0x5b, 0xa9, 0x05, 0x6c, 0xbf, - 0xe1, 0xfa, 0xb4, 0xc7, 0xe0, 0x4c, 0x01, 0x4a, 0x80, 0xa3, 0xf8, 0x9d, 0x0d, 0xae, 0x57, 0xc5, 0xe6, 0x8a, 0x97, - 0xe4, 0xfe, 0x8d, 0xe1, 0xa5, 0x83, 0x32, 0x34, 0xd9, 0x5e, 0xfd, 0x75, 0xf7, 0x89, 0x4d, 0xb2, 0x70, 0x5a, 0x6c, - 0xb0, 0x74, 0x7f, 0xed, 0xdf, 0x5c, 0x01, 0xa3, 0x40, 0x04, 0x85, 0xa8, 0x06, 0xa3, 0x64, 0x51, 0x88, 0x9b, 0x9f, - 0x8e, 0x9b, 0xbf, 0x17, 0x15, 0x83, 0x15, 0xc8, 0xfd, 0x99, 0xac, 0xa6, 0x30, 0xc5, 0xc1, 0x4d, 0x37, 0xda, 0x32, - 0xb7, 0x04, 0x21, 0xda, 0xb8, 0x13, 0x53, 0xa1, 0x08, 0x99, 0xd7, 0xf1, 0xb9, 0xe3, 0xcd, 0x7d, 0xb9, 0xd6, 0xfe, - 0x6e, 0xae, 0x75, 0xba, 0x8b, 0x6b, 0x4d, 0x36, 0x60, 0xa4, 0xbd, 0x23, 0x6d, 0xe1, 0x04, 0x71, 0xae, 0x5a, 0x13, - 0x16, 0x58, 0xdd, 0x68, 0x32, 0x26, 0x6a, 0x55, 0x5a, 0x23, 0xd5, 0x46, 0x64, 0x7f, 0x2b, 0x0f, 0x14, 0x21, 0x50, - 0x57, 0x79, 0xe3, 0x17, 0x39, 0x6f, 0x9c, 0x5e, 0x35, 0xb9, 0xf5, 0x8f, 0xa0, 0xfe, 0x15, 0xcb, 0x3a, 0xf9, 0x3a, - 0xc8, 0x2d, 0xec, 0xf2, 0x91, 0x2a, 0x36, 0x63, 0xf9, 0x43, 0x43, 0xb1, 0x44, 0x14, 0xaf, 0x8c, 0xa2, 0x41, 0x62, - 0xb1, 0x68, 0x6e, 0x32, 0x96, 0xa7, 0x03, 0xd7, 0x1d, 0x87, 0x2c, 0x93, 0xd5, 0x6d, 0x53, 0xb4, 0x19, 0x52, 0xb3, - 0x95, 0x4d, 0x22, 0x8d, 0x7b, 0x08, 0xc0, 0x82, 0x4d, 0x5f, 0x92, 0x6b, 0x4b, 0x1d, 0x08, 0x1c, 0x64, 0x8d, 0x2d, - 0xe2, 0x6e, 0xee, 0x3c, 0x05, 0x87, 0xc8, 0x45, 0xd7, 0x2e, 0xde, 0xee, 0x24, 0x09, 0x56, 0xf9, 0x11, 0x08, 0xeb, - 0x2b, 0x85, 0x83, 0xd0, 0x77, 0x34, 0x67, 0x50, 0x43, 0x00, 0xe0, 0xfd, 0x5f, 0xfe, 0xe6, 0xa4, 0x00, 0x70, 0x22, - 0x35, 0x47, 0x95, 0xf9, 0xe3, 0x21, 0xb6, 0x48, 0xfd, 0x18, 0x8b, 0x56, 0xfb, 0x24, 0x7e, 0xcf, 0x86, 0x5b, 0xfe, - 0x14, 0xd9, 0xf9, 0xbc, 0x44, 0x5f, 0x8c, 0x83, 0xef, 0xb2, 0x78, 0x1d, 0xa2, 0xcf, 0x7f, 0x2b, 0x8d, 0xbd, 0xc9, - 0x87, 0x8d, 0xd2, 0x1f, 0x67, 0x89, 0x02, 0xbb, 0xb8, 0x28, 0x54, 0x18, 0x78, 0xe8, 0x22, 0x93, 0xf5, 0xed, 0x76, - 0xa2, 0x30, 0x6a, 0xfa, 0x0f, 0x9d, 0x8e, 0xf7, 0x6c, 0x76, 0x58, 0xe2, 0x9f, 0xb6, 0xbb, 0x45, 0xee, 0xba, 0x1c, - 0xc7, 0x32, 0xfa, 0x95, 0xdb, 0x48, 0xfe, 0xf9, 0x5d, 0x27, 0xbc, 0xcf, 0xd2, 0x1a, 0x7d, 0xce, 0x10, 0xa0, 0x7e, - 0x41, 0x30, 0xad, 0x8a, 0x69, 0x2a, 0x29, 0x4d, 0xc3, 0x9a, 0xf9, 0x41, 0x60, 0x05, 0x60, 0xa9, 0xb2, 0xf9, 0xac, - 0xe9, 0x61, 0x3b, 0x6b, 0x70, 0xce, 0xfc, 0x19, 0xed, 0x14, 0x77, 0x4a, 0xba, 0x58, 0x2f, 0xc7, 0x1b, 0x95, 0x51, - 0xae, 0xf0, 0xcf, 0xab, 0x3c, 0x73, 0xb5, 0xdb, 0xd9, 0x6c, 0x56, 0xe4, 0x1a, 0x3b, 0xda, 0x21, 0x72, 0x7e, 0x1f, - 0x3a, 0x8e, 0x53, 0x86, 0x6f, 0xd3, 0x41, 0xa1, 0x83, 0x61, 0x21, 0x13, 0xbe, 0xb7, 0x7b, 0x4f, 0xfd, 0x49, 0xa3, - 0xa5, 0xa6, 0x9a, 0xce, 0x23, 0x6d, 0xb5, 0xff, 0x8a, 0xa1, 0x20, 0x6a, 0xd8, 0x75, 0xfc, 0xab, 0x7b, 0x65, 0x4b, - 0x4b, 0xe5, 0x03, 0xfc, 0x69, 0x95, 0x77, 0xec, 0xf5, 0x3d, 0xaa, 0x36, 0x6d, 0xef, 0xcc, 0xce, 0xaf, 0xdd, 0x82, - 0xce, 0xd2, 0x80, 0x34, 0x95, 0xfc, 0x94, 0x2d, 0x93, 0xfe, 0x84, 0xa1, 0x80, 0xd4, 0x56, 0x6e, 0x5b, 0xd4, 0xea, - 0xb1, 0xe6, 0xa0, 0xc7, 0xe5, 0x0a, 0x3c, 0xec, 0x68, 0x28, 0xac, 0xaa, 0x48, 0xd6, 0x44, 0x27, 0x78, 0x8b, 0x6d, - 0xaa, 0x02, 0x27, 0xdc, 0xa6, 0x5d, 0xe7, 0x2f, 0x85, 0x72, 0x1a, 0x50, 0xa7, 0x1b, 0xa1, 0x6d, 0x42, 0xc2, 0x13, - 0xfc, 0x5b, 0x0a, 0xe7, 0x9e, 0xad, 0xee, 0x8a, 0xca, 0x5d, 0x3d, 0x10, 0x37, 0xe5, 0x57, 0x19, 0x8d, 0xba, 0x0e, - 0xf5, 0x49, 0x15, 0xa0, 0x99, 0xaa, 0xdd, 0x02, 0x1a, 0x34, 0x85, 0x50, 0x44, 0x35, 0xb2, 0x31, 0x7c, 0xce, 0xc2, - 0xce, 0xcb, 0xf9, 0xfb, 0x79, 0x20, 0x4d, 0x98, 0x83, 0xf9, 0xb4, 0x87, 0xc2, 0xbd, 0xc2, 0x56, 0x45, 0x55, 0x19, - 0xdc, 0x03, 0xe2, 0x45, 0xaa, 0xad, 0xe3, 0xc0, 0xa2, 0x38, 0x3d, 0x2d, 0x63, 0x53, 0x9d, 0x77, 0x73, 0xf3, 0x6e, - 0x17, 0xe4, 0x1a, 0x55, 0x50, 0xed, 0x25, 0xda, 0x2b, 0xcb, 0xb0, 0xc5, 0x38, 0x61, 0x05, 0xc0, 0x92, 0x42, 0x43, - 0xa5, 0x21, 0xad, 0x84, 0xfb, 0x68, 0xd2, 0x32, 0x57, 0x45, 0xd6, 0x62, 0x9e, 0xd8, 0x5c, 0x7d, 0x11, 0x6a, 0x5b, - 0x48, 0x06, 0x01, 0x76, 0x1c, 0x3b, 0xe1, 0xb7, 0x05, 0x3b, 0x46, 0x45, 0x57, 0x2e, 0xee, 0x20, 0x3c, 0xa5, 0x16, - 0xd2, 0xc9, 0x09, 0x9d, 0x52, 0x94, 0x25, 0xfc, 0xad, 0x96, 0x79, 0x7f, 0x51, 0xe0, 0xc6, 0x73, 0x73, 0x96, 0xb6, - 0xb1, 0x57, 0xe9, 0xa5, 0x1f, 0xee, 0x5f, 0xd6, 0xbb, 0xdb, 0xbb, 0x2c, 0x10, 0x87, 0x7b, 0x17, 0x06, 0xea, 0x92, - 0xb4, 0x94, 0xd2, 0xe1, 0xdf, 0x14, 0xe1, 0x81, 0xea, 0x16, 0x41, 0xc7, 0x5a, 0xf4, 0xa2, 0xbf, 0x58, 0x0f, 0x47, - 0x27, 0x67, 0x77, 0xcb, 0x40, 0xbb, 0x61, 0x31, 0xc4, 0x2c, 0x1b, 0xea, 0xae, 0xed, 0xe8, 0x1a, 0x1a, 0xf9, 0xfb, - 0xe1, 0x7c, 0xa8, 0xff, 0x74, 0xf1, 0xca, 0xea, 0xe9, 0x67, 0xa0, 0x8e, 0x71, 0x33, 0x47, 0x12, 0xf7, 0xdc, 0xbb, - 0x67, 0xf1, 0x75, 0x5b, 0xd7, 0x30, 0x34, 0x19, 0x11, 0xb7, 0x98, 0xa6, 0xb5, 0xf5, 0x3d, 0x22, 0xe0, 0x68, 0x22, - 0x88, 0xa5, 0x0e, 0x88, 0xd5, 0x6d, 0xf7, 0x34, 0xb7, 0x7d, 0x68, 0x1f, 0xf5, 0xf4, 0xd3, 0xaf, 0x34, 0xed, 0x64, - 0xca, 0x66, 0xc9, 0x29, 0xb2, 0x63, 0x4e, 0x90, 0x1e, 0xa4, 0xdf, 0x9a, 0x66, 0x4f, 0x82, 0xc4, 0x72, 0xb5, 0x0d, - 0xff, 0xd4, 0x34, 0x40, 0x46, 0x7d, 0xed, 0xe1, 0xac, 0x3d, 0x3b, 0x9c, 0x3d, 0x1b, 0xf0, 0xe4, 0xec, 0xab, 0x42, - 0x71, 0x93, 0xfe, 0x6d, 0x2b, 0xd5, 0x92, 0x34, 0x8e, 0x3e, 0x30, 0x4e, 0x4b, 0x6a, 0x92, 0x51, 0x54, 0xae, 0xda, - 0xae, 0xf6, 0xe4, 0xf6, 0xc6, 0x93, 0x59, 0x3b, 0x2f, 0x8e, 0x63, 0x3c, 0x90, 0x83, 0x3c, 0x39, 0x10, 0x43, 0x3f, - 0x51, 0xc1, 0xe4, 0x5a, 0x75, 0x80, 0x72, 0x75, 0x3e, 0xc7, 0xb9, 0x98, 0xdf, 0x09, 0x38, 0x98, 0xcd, 0x0d, 0x10, - 0x12, 0xac, 0x36, 0xd4, 0xbf, 0x77, 0xdb, 0x3d, 0xd3, 0x75, 0x8f, 0xec, 0xa3, 0xde, 0xc4, 0x31, 0x0f, 0xed, 0x43, - 0xab, 0x63, 0x1f, 0x99, 0x3d, 0xab, 0x67, 0xf6, 0xfe, 0xda, 0x9b, 0x58, 0x87, 0xf6, 0xa1, 0xe9, 0x58, 0x3d, 0x48, - 0xb4, 0x7a, 0x56, 0xef, 0xc6, 0x3a, 0xec, 0x4d, 0x1c, 0x4c, 0x6d, 0xdb, 0xdd, 0xae, 0xe5, 0x3a, 0x76, 0xb7, 0x6b, - 0x76, 0xed, 0xa3, 0x23, 0xcb, 0xed, 0xd8, 0x47, 0x47, 0xe7, 0xdd, 0x9e, 0xdd, 0x81, 0xbc, 0x4e, 0x67, 0xd2, 0xb1, - 0x5d, 0xd7, 0x82, 0xbf, 0xcc, 0x9e, 0xdd, 0xa6, 0x1f, 0xae, 0x6b, 0x77, 0x5c, 0xd3, 0x09, 0xba, 0x6d, 0xfb, 0xe8, - 0x99, 0x89, 0x7f, 0x63, 0x31, 0x13, 0xff, 0x82, 0x66, 0xcc, 0x67, 0x76, 0xfb, 0x88, 0x7e, 0x61, 0x83, 0x37, 0x87, - 0xbd, 0x9f, 0xf5, 0x83, 0xc6, 0x39, 0xb8, 0x34, 0x87, 0x5e, 0xd7, 0xee, 0x74, 0xcc, 0x43, 0xd7, 0xee, 0x75, 0x16, - 0xd6, 0x61, 0xdb, 0x3e, 0x3a, 0x9e, 0x58, 0xae, 0x7d, 0x7c, 0x6c, 0x3a, 0x56, 0xc7, 0x6e, 0x9b, 0xae, 0x7d, 0xd8, - 0xc1, 0x1f, 0x1d, 0xbb, 0x7d, 0x73, 0xfc, 0xcc, 0x3e, 0xea, 0x2e, 0x8e, 0xec, 0xc3, 0xf7, 0x87, 0x3d, 0xbb, 0xdd, - 0x59, 0x74, 0x8e, 0xec, 0xf6, 0xf1, 0xcd, 0x91, 0x7d, 0xb8, 0xb0, 0xda, 0x47, 0x5b, 0x6b, 0xba, 0x6d, 0x1b, 0x60, - 0x84, 0xd9, 0x90, 0x61, 0xf2, 0x0c, 0xf8, 0xb3, 0xc0, 0xba, 0x7f, 0x62, 0x33, 0x49, 0xb5, 0xea, 0x33, 0xbb, 0x77, - 0x3c, 0xa1, 0xe2, 0x90, 0x60, 0x89, 0x12, 0x50, 0xe5, 0xc6, 0xa2, 0x6e, 0xb1, 0x39, 0x4b, 0x34, 0x24, 0xfe, 0xf0, - 0xce, 0x6e, 0x2c, 0xe8, 0x98, 0xfa, 0xfd, 0x8f, 0xb6, 0x23, 0x97, 0x1c, 0x42, 0xf2, 0x7e, 0xc5, 0xff, 0xa1, 0x68, - 0x56, 0x23, 0xf3, 0xbc, 0x49, 0x28, 0xf9, 0x76, 0xb7, 0x50, 0xf2, 0xd5, 0x7a, 0x1f, 0xa1, 0xe4, 0xdb, 0x2f, 0x2e, - 0x94, 0x3c, 0x2f, 0xdb, 0xc4, 0xbc, 0x2d, 0x07, 0xdd, 0xf8, 0x79, 0x53, 0x66, 0x39, 0xf8, 0x5e, 0xeb, 0xf2, 0x62, - 0x7d, 0x05, 0xee, 0xdf, 0xde, 0x46, 0xc3, 0x57, 0xeb, 0x82, 0xc2, 0x67, 0x04, 0x38, 0xf6, 0x6d, 0x44, 0x38, 0xf6, - 0xd7, 0xf5, 0x10, 0xb4, 0xcc, 0x38, 0x99, 0xe3, 0x4f, 0xad, 0x85, 0x17, 0xcc, 0x24, 0x89, 0x04, 0x29, 0x03, 0x4c, - 0x06, 0xbb, 0x2b, 0xb8, 0x9e, 0xe1, 0x25, 0xb3, 0x5e, 0x86, 0x09, 0x68, 0x04, 0x83, 0x26, 0xc7, 0x2c, 0xce, 0x4a, - 0x95, 0x6d, 0xe1, 0x30, 0xef, 0x9a, 0x5b, 0x40, 0x35, 0xe6, 0xa3, 0x02, 0x70, 0x7d, 0xeb, 0x6e, 0xb5, 0x5d, 0x0d, - 0x34, 0xeb, 0x84, 0x82, 0x34, 0x50, 0xfb, 0x75, 0xf9, 0x45, 0x35, 0xdc, 0x92, 0xe2, 0x75, 0xf3, 0x48, 0x61, 0x24, - 0xe5, 0xfa, 0x6e, 0x51, 0x8d, 0x77, 0xd7, 0x34, 0x6b, 0xba, 0x2f, 0x54, 0xdf, 0xa2, 0x43, 0x2c, 0x1b, 0x2e, 0x83, - 0xaa, 0x14, 0x32, 0xb2, 0x16, 0x20, 0xf9, 0x03, 0x35, 0x57, 0x34, 0xce, 0x29, 0x55, 0x47, 0x43, 0x7a, 0xc7, 0x51, - 0xf2, 0x0a, 0x6d, 0xaa, 0xca, 0xc9, 0x4f, 0x36, 0xf8, 0xae, 0xf0, 0x7f, 0x05, 0x4a, 0x94, 0x53, 0x3c, 0xe3, 0x48, - 0x85, 0xf3, 0x46, 0x69, 0x97, 0xb8, 0x11, 0xd9, 0xc2, 0xdd, 0x54, 0x69, 0xd1, 0x46, 0xb3, 0x04, 0x97, 0x2d, 0x05, - 0x15, 0x84, 0xdd, 0x93, 0x11, 0x40, 0x46, 0x86, 0x1a, 0x68, 0xe7, 0xb0, 0xad, 0x31, 0x51, 0xee, 0x21, 0x6c, 0x62, - 0x93, 0x7f, 0xa8, 0x8e, 0x4b, 0x36, 0xb3, 0x20, 0xf2, 0xd2, 0x3e, 0x92, 0x69, 0x0a, 0xc9, 0xdb, 0x46, 0x8b, 0x85, - 0xc1, 0x16, 0x65, 0x3a, 0xb5, 0x61, 0xde, 0x08, 0x5a, 0x3e, 0x6c, 0xd3, 0xbf, 0x93, 0x86, 0x62, 0x9b, 0x82, 0x3a, - 0x8a, 0xdb, 0x3d, 0x36, 0xdd, 0x23, 0xd3, 0x3e, 0xee, 0x1a, 0x99, 0x38, 0x70, 0x6a, 0x93, 0x05, 0x80, 0x80, 0x01, - 0x84, 0x1c, 0xa6, 0x1f, 0xfa, 0xa9, 0xef, 0x05, 0x19, 0xd0, 0xc3, 0xc5, 0x47, 0xca, 0x3f, 0xd7, 0x49, 0x0a, 0x73, - 0x14, 0x44, 0x2f, 0x1a, 0x7f, 0x58, 0x63, 0x96, 0xde, 0x32, 0x16, 0x36, 0x28, 0xc6, 0x94, 0x6d, 0x49, 0xfe, 0x38, - 0xcd, 0xfa, 0x8c, 0xb4, 0xd6, 0xc6, 0x69, 0xc8, 0xf7, 0x87, 0x30, 0x7c, 0xc8, 0x46, 0xe6, 0x0f, 0x4d, 0x08, 0xf7, - 0x9f, 0xbb, 0x11, 0x6e, 0xca, 0xf6, 0x41, 0xb8, 0xff, 0xfc, 0xe2, 0x08, 0xf7, 0x07, 0x15, 0xe1, 0x16, 0xec, 0xfe, - 0x72, 0x09, 0xd3, 0x3b, 0xfc, 0x6e, 0x81, 0xb7, 0xfa, 0xa7, 0xfa, 0x01, 0x11, 0xf0, 0xba, 0x12, 0x45, 0xfc, 0x7d, - 0x21, 0x2c, 0x1a, 0x32, 0x40, 0xd1, 0x4b, 0x36, 0x85, 0x60, 0x82, 0x08, 0xdb, 0x8e, 0x0c, 0xc3, 0xc4, 0x6e, 0xb5, - 0xd7, 0x61, 0x1a, 0xd8, 0x6f, 0xf9, 0x3b, 0x12, 0x04, 0xba, 0xaf, 0xa2, 0x78, 0xe9, 0xa1, 0x87, 0x50, 0x1d, 0xc3, - 0xa9, 0xc2, 0x87, 0x03, 0xb6, 0xa4, 0x93, 0x28, 0x9c, 0x4a, 0xa9, 0x24, 0x1b, 0x5e, 0x12, 0xc5, 0xad, 0xdf, 0x33, - 0x2f, 0xd6, 0x4d, 0xca, 0x86, 0xc5, 0x7d, 0xd2, 0x71, 0x9e, 0xb4, 0x0f, 0x9f, 0x1c, 0x39, 0xf0, 0xbf, 0xcb, 0x3a, - 0x99, 0xc9, 0x0b, 0x2e, 0xa3, 0x10, 0x22, 0x3a, 0x89, 0x92, 0x4d, 0xc5, 0x6e, 0x19, 0xfb, 0x90, 0x97, 0x3a, 0xae, - 0x2f, 0x34, 0xf5, 0xee, 0xf3, 0x32, 0xb5, 0x25, 0x16, 0xd1, 0x5a, 0x19, 0x56, 0xcd, 0x68, 0xfc, 0x70, 0x0d, 0x7c, - 0x76, 0xa5, 0x84, 0x9a, 0xcd, 0xa7, 0x9b, 0xcf, 0x8b, 0x75, 0xb2, 0xab, 0x3c, 0x6c, 0x9c, 0x08, 0x5f, 0xb5, 0x13, - 0x82, 0x5c, 0x44, 0xe9, 0x60, 0xd0, 0x09, 0x0c, 0x9c, 0xa6, 0x41, 0xd0, 0x56, 0xb1, 0x40, 0x1e, 0x2d, 0x50, 0x1a, - 0xaf, 0xc3, 0x49, 0x0b, 0x7f, 0x7a, 0xe3, 0xa4, 0xe5, 0x1f, 0x80, 0xfb, 0x68, 0xec, 0xd8, 0xc0, 0x55, 0xf3, 0x4e, - 0x9d, 0x3c, 0xc6, 0x4e, 0x22, 0x56, 0xc5, 0x7b, 0x92, 0x9a, 0x31, 0x45, 0xe6, 0xc6, 0xa5, 0xb5, 0x86, 0xde, 0x13, - 0x59, 0xf1, 0x49, 0x6a, 0x42, 0x74, 0x6c, 0x58, 0xee, 0xc7, 0x8f, 0xa9, 0x14, 0xc4, 0xab, 0xa5, 0x69, 0x9d, 0x4d, - 0x72, 0xff, 0x93, 0x9a, 0x37, 0x8f, 0xc8, 0x05, 0x65, 0x7f, 0x62, 0x46, 0x4f, 0x9f, 0x9e, 0x0e, 0x5d, 0x83, 0x47, - 0x5b, 0x2e, 0x84, 0x06, 0x3c, 0xdf, 0x4f, 0xd1, 0xc8, 0xa8, 0x35, 0x81, 0x5d, 0xc1, 0x9b, 0xc9, 0x11, 0xe6, 0x08, - 0x1c, 0x7b, 0x41, 0xa8, 0x1e, 0x52, 0x28, 0xf0, 0x84, 0xc2, 0x8f, 0x28, 0x23, 0x5f, 0x5d, 0x1d, 0xdb, 0xb1, 0x1d, - 0x5d, 0x56, 0x9c, 0xf9, 0xf3, 0xe1, 0x26, 0x4a, 0x3d, 0x08, 0x7a, 0x16, 0x44, 0x73, 0xb0, 0xa3, 0x4b, 0xfd, 0x34, - 0x80, 0x08, 0x5a, 0x60, 0x50, 0xb7, 0xa4, 0x77, 0x79, 0xc6, 0xad, 0x1b, 0xbc, 0xf8, 0x03, 0x46, 0x51, 0x15, 0x26, - 0xb4, 0xe8, 0x12, 0xed, 0x7b, 0xb8, 0x0c, 0x5b, 0x7a, 0x0b, 0x78, 0x03, 0x2c, 0x4e, 0x2c, 0xd5, 0x5a, 0xa8, 0xaf, - 0x41, 0x1d, 0x43, 0xe7, 0x93, 0x98, 0xc5, 0xde, 0x12, 0x82, 0x4d, 0x6c, 0x32, 0x93, 0x63, 0x5a, 0x9d, 0xa3, 0x5a, - 0xcd, 0x7d, 0x76, 0x64, 0x6a, 0x6d, 0xd7, 0xd4, 0x1c, 0x40, 0xb7, 0x7a, 0x66, 0x6e, 0xb2, 0xab, 0xc1, 0x2e, 0x85, - 0x07, 0xc2, 0x2f, 0x0f, 0x69, 0x1e, 0xa4, 0xea, 0xc0, 0x45, 0x49, 0x29, 0x79, 0xb8, 0x6d, 0x29, 0x61, 0x20, 0x7c, - 0x12, 0x7a, 0x5e, 0xb0, 0xbb, 0xd4, 0xc0, 0x08, 0x53, 0xbc, 0x88, 0x6f, 0x6c, 0xd0, 0xd0, 0xd7, 0x0f, 0x35, 0xff, - 0xe3, 0xc7, 0x96, 0x0f, 0xc6, 0x4c, 0x43, 0x05, 0x3e, 0xf0, 0x6d, 0x14, 0x00, 0xe6, 0xe7, 0x62, 0x7a, 0x04, 0x16, - 0x58, 0x1a, 0xc2, 0xbf, 0x79, 0xb2, 0xf8, 0xc1, 0xd5, 0x24, 0xec, 0xc0, 0x0b, 0xe7, 0x80, 0xd2, 0xbc, 0x70, 0x5e, - 0x51, 0xc7, 0x22, 0x5b, 0xe5, 0x52, 0x6a, 0xde, 0x54, 0xae, 0x2a, 0x95, 0x7c, 0x77, 0x7f, 0x41, 0x11, 0xf4, 0x5a, - 0x3a, 0xdc, 0x72, 0x68, 0x58, 0x9b, 0x4b, 0x72, 0x9f, 0x0e, 0xbf, 0x3e, 0x59, 0xb2, 0xd4, 0x23, 0x31, 0x10, 0x3c, - 0x7e, 0x81, 0x1c, 0xd0, 0x26, 0x22, 0xfa, 0x35, 0x5e, 0x0d, 0xc3, 0x29, 0xbb, 0xf1, 0x27, 0xfc, 0x5d, 0x6a, 0x6a, - 0xfc, 0x9e, 0xb2, 0x50, 0xe3, 0x73, 0xe8, 0x9a, 0x64, 0x70, 0x30, 0xf1, 0xd0, 0x0f, 0xee, 0x30, 0x8c, 0xf4, 0xd3, - 0xaf, 0xa5, 0x6d, 0x66, 0xd3, 0x22, 0x40, 0x18, 0xdb, 0xcb, 0x98, 0x05, 0xff, 0x1a, 0x7e, 0x0d, 0x17, 0xf7, 0xd7, - 0x57, 0xba, 0x31, 0x48, 0xed, 0x45, 0xcc, 0x66, 0xc3, 0xaf, 0x6b, 0xc2, 0xb9, 0xe2, 0xf3, 0x9e, 0xc6, 0xa2, 0x77, - 0xda, 0xb9, 0xf7, 0xb2, 0xce, 0x5e, 0x8f, 0xfa, 0x53, 0xfe, 0x5a, 0x87, 0x17, 0xe0, 0xa6, 0xf0, 0xc6, 0x76, 0x07, - 0xf8, 0x7e, 0x1e, 0x07, 0xde, 0xe4, 0xc3, 0x80, 0x72, 0x0a, 0x1f, 0x16, 0xdc, 0xd6, 0x13, 0x6f, 0xd5, 0xc7, 0xeb, - 0x55, 0x4d, 0x04, 0xd3, 0x6c, 0x4a, 0x95, 0x94, 0x5d, 0xed, 0x5e, 0xc6, 0xad, 0xbc, 0xc1, 0x9e, 0xb1, 0xab, 0xdb, - 0x85, 0x9f, 0x32, 0xd1, 0x15, 0x7e, 0x64, 0x99, 0x78, 0xa8, 0xd3, 0x13, 0x15, 0x1f, 0xd6, 0x76, 0x47, 0x73, 0x7b, - 0x7f, 0xed, 0xde, 0xb8, 0xce, 0xa2, 0xed, 0xda, 0xbd, 0xf7, 0x6e, 0x6f, 0xd1, 0xb1, 0x8f, 0x03, 0xab, 0x63, 0x1f, - 0xc3, 0x9f, 0xf7, 0xc7, 0x76, 0x6f, 0x61, 0xb5, 0xed, 0xc3, 0xf7, 0x6e, 0x3b, 0xb0, 0x7a, 0xf6, 0x31, 0xfc, 0x39, - 0xa7, 0x5a, 0xf0, 0x00, 0xa2, 0xf7, 0xce, 0xd7, 0x05, 0x2c, 0xa0, 0xfc, 0x96, 0x32, 0x59, 0xb3, 0x70, 0xbd, 0xd5, - 0xc8, 0x75, 0x01, 0x65, 0xe8, 0xa6, 0xf0, 0x52, 0x1b, 0x0e, 0x5a, 0xe1, 0x90, 0x47, 0x46, 0x11, 0xea, 0x6d, 0xc2, - 0x06, 0x5d, 0xc4, 0x08, 0xa9, 0x3d, 0x46, 0xbc, 0x4e, 0x7d, 0x44, 0x08, 0x11, 0x72, 0x8f, 0x04, 0xc1, 0x3f, 0xad, - 0xd0, 0xcb, 0x9a, 0x88, 0x61, 0xa1, 0x60, 0xa5, 0x3c, 0xec, 0x6b, 0xb6, 0x7b, 0xe0, 0x68, 0x85, 0xcf, 0x64, 0xd8, - 0xb1, 0x2f, 0xda, 0x36, 0x17, 0x0e, 0xcb, 0xd6, 0x7f, 0x6f, 0x3b, 0x18, 0x6d, 0x9b, 0xda, 0x11, 0xee, 0xa6, 0xa7, - 0x7e, 0x2c, 0x87, 0xa7, 0xa0, 0x68, 0xb7, 0x3e, 0x94, 0x86, 0x01, 0xf1, 0x99, 0x5e, 0x03, 0x95, 0x7c, 0xe3, 0x05, - 0x8a, 0x22, 0x9b, 0x52, 0xf3, 0x81, 0xc4, 0xfc, 0x8f, 0x1f, 0xe7, 0x83, 0xb3, 0x4a, 0xe3, 0x3e, 0x71, 0xbb, 0x70, - 0xed, 0x76, 0x59, 0x67, 0xab, 0x4e, 0xe5, 0x6e, 0x7f, 0xe5, 0xb9, 0x3f, 0x63, 0xa1, 0x37, 0x25, 0x34, 0x36, 0x1a, - 0x15, 0x3b, 0x2b, 0xfa, 0x1a, 0xe0, 0xe9, 0xbd, 0xf4, 0xd4, 0xd1, 0x8d, 0x41, 0x28, 0xd4, 0x0f, 0xc2, 0x2d, 0x3e, - 0xda, 0xf9, 0x5b, 0x4c, 0x07, 0xd0, 0x6c, 0x99, 0xc7, 0x0e, 0x03, 0xf1, 0xff, 0xf4, 0x24, 0xd0, 0x58, 0x13, 0xf4, - 0x25, 0x4a, 0xa7, 0xb5, 0x60, 0xbc, 0x27, 0xef, 0x55, 0xba, 0x50, 0x59, 0x72, 0xa6, 0x43, 0x12, 0x04, 0xee, 0xc3, - 0x58, 0x9d, 0x52, 0x59, 0x54, 0xde, 0x16, 0x79, 0x82, 0xe9, 0x43, 0x90, 0x82, 0x96, 0x30, 0x1c, 0x35, 0x1e, 0x3f, - 0x6e, 0xbc, 0x84, 0x48, 0x39, 0x47, 0x0d, 0x59, 0xac, 0xab, 0xf8, 0x4d, 0x57, 0x51, 0x8c, 0x6c, 0x17, 0xb1, 0x86, - 0xd0, 0x71, 0xa5, 0xbd, 0x87, 0x3f, 0xc7, 0xcc, 0x4b, 0x6d, 0x2e, 0x2c, 0x6d, 0x29, 0x97, 0xbb, 0xe9, 0xb2, 0x0e, - 0x68, 0xb7, 0x72, 0x67, 0x8c, 0xdc, 0xd9, 0xe9, 0xa3, 0xcd, 0xfb, 0x35, 0xf7, 0xea, 0x00, 0x6d, 0x7c, 0x74, 0x72, - 0xff, 0x59, 0x6f, 0x52, 0x8f, 0x9c, 0x2c, 0xa9, 0x57, 0x6e, 0x94, 0x7a, 0x22, 0x40, 0x16, 0xd0, 0xe5, 0x83, 0x5a, - 0xf5, 0x0b, 0xc5, 0xf3, 0xc3, 0xe9, 0x9b, 0x8b, 0x6f, 0x35, 0xbe, 0xff, 0x49, 0x5b, 0x00, 0x1f, 0x32, 0x14, 0x96, - 0x65, 0x48, 0x61, 0x59, 0x34, 0x1e, 0x1f, 0x09, 0x82, 0x9b, 0x64, 0x07, 0x04, 0x41, 0x64, 0x40, 0x93, 0x0e, 0xc5, - 0x72, 0x1d, 0xa4, 0xfe, 0xca, 0x8b, 0xd3, 0x03, 0xa8, 0x6a, 0x01, 0x92, 0xd3, 0x9b, 0xfc, 0x41, 0x90, 0x1a, 0x86, - 0xf0, 0x01, 0x9a, 0x86, 0x42, 0x0f, 0x63, 0xe6, 0x07, 0x52, 0x0d, 0x43, 0x74, 0xe0, 0x4d, 0x26, 0x6c, 0x95, 0x0e, - 0x75, 0x6f, 0x05, 0xe1, 0x79, 0xd0, 0xe1, 0xfe, 0x41, 0x34, 0x49, 0x59, 0x6a, 0x25, 0x69, 0xcc, 0xbc, 0xa5, 0x2e, - 0x7d, 0x4d, 0x57, 0xdb, 0x4b, 0xd6, 0xe3, 0xa5, 0x9f, 0x4a, 0x67, 0xad, 0x34, 0x41, 0x50, 0x88, 0x80, 0x21, 0x82, - 0x73, 0x18, 0x02, 0xe1, 0x79, 0x34, 0x2f, 0xed, 0xa8, 0x9c, 0x72, 0x39, 0x43, 0x57, 0xe0, 0x3c, 0x24, 0xcb, 0x14, - 0xed, 0x1b, 0xaf, 0xb9, 0x0f, 0x0b, 0xe9, 0x53, 0x56, 0x3f, 0x3d, 0xe1, 0xcf, 0x5b, 0x0d, 0xdd, 0xae, 0xe8, 0x5d, - 0x07, 0x9c, 0x9d, 0x37, 0x79, 0xb7, 0x38, 0xe0, 0x85, 0xe1, 0x6a, 0xa2, 0x96, 0x31, 0x10, 0x05, 0x8d, 0xe5, 0x02, - 0x08, 0xa1, 0x82, 0xc2, 0xcc, 0xc2, 0x3d, 0x95, 0xe6, 0x94, 0x38, 0x2a, 0xa4, 0x95, 0x3e, 0x7e, 0x7c, 0x3e, 0xfa, - 0xed, 0xdf, 0x10, 0x2d, 0x63, 0xe1, 0x0a, 0x9f, 0x12, 0x97, 0x6a, 0x29, 0x4e, 0x7d, 0x9a, 0x23, 0x54, 0x96, 0x62, - 0x53, 0xe1, 0x98, 0x47, 0x6c, 0xad, 0x6c, 0x74, 0x25, 0xbc, 0xfd, 0x41, 0x44, 0x1c, 0x43, 0x78, 0xbe, 0x18, 0xc1, - 0xf2, 0x8e, 0x84, 0xc3, 0x15, 0xed, 0x97, 0xbb, 0xef, 0x8e, 0xb5, 0xdc, 0x05, 0x4f, 0x9d, 0x46, 0x0f, 0xed, 0xa1, - 0xd3, 0x13, 0x4f, 0x43, 0xa2, 0x05, 0xc9, 0x8f, 0xa4, 0x7f, 0x00, 0xd3, 0x5c, 0x44, 0x4b, 0x66, 0xfb, 0xd1, 0xc1, - 0x2d, 0x1b, 0x5b, 0xde, 0xca, 0x27, 0xbd, 0x1c, 0xe4, 0xbb, 0x69, 0x44, 0xf9, 0x49, 0x75, 0x17, 0xa2, 0xaf, 0xb3, - 0x1c, 0x94, 0x51, 0xd1, 0xbd, 0x63, 0xb7, 0x9d, 0xcb, 0x01, 0xc1, 0x7f, 0x81, 0x02, 0xc7, 0xe8, 0xf4, 0xe4, 0xc0, - 0x3b, 0x2d, 0xfa, 0x97, 0xb5, 0x45, 0x84, 0x93, 0xe2, 0x25, 0x70, 0x46, 0x6e, 0x62, 0x85, 0x47, 0xd8, 0xfc, 0xc3, - 0x8a, 0x66, 0x33, 0xd5, 0x27, 0xac, 0x5d, 0x1c, 0x9e, 0x04, 0x5a, 0xbe, 0xa5, 0xa3, 0x15, 0xf5, 0x54, 0xed, 0x42, - 0xfe, 0x84, 0xa8, 0xf0, 0xdc, 0x7d, 0x30, 0x1c, 0xf7, 0x8a, 0x6f, 0x59, 0x09, 0xb1, 0x87, 0x54, 0x88, 0xe3, 0x91, - 0x72, 0x24, 0x83, 0x06, 0xca, 0xe5, 0xc1, 0x70, 0x48, 0x68, 0xae, 0x8c, 0xed, 0x00, 0x88, 0x35, 0xd1, 0x5e, 0x60, - 0xb2, 0x29, 0x54, 0xb4, 0xc8, 0x5c, 0x16, 0x2b, 0x95, 0xa7, 0x53, 0x1d, 0xe3, 0x81, 0x27, 0xb6, 0x5f, 0x61, 0x83, - 0xc2, 0xc6, 0xe3, 0xeb, 0x0e, 0xf8, 0x5d, 0xb4, 0x53, 0x42, 0xf3, 0xda, 0x37, 0x84, 0xd1, 0xad, 0xc0, 0xbb, 0x8f, - 0x14, 0x35, 0x26, 0xee, 0xd1, 0xe4, 0x1c, 0x53, 0x2f, 0x84, 0x25, 0x71, 0xe5, 0xa0, 0xc9, 0x88, 0x19, 0xd5, 0xc3, - 0xa6, 0x86, 0xb8, 0xd8, 0x75, 0xd6, 0xd4, 0xb2, 0xc5, 0xc9, 0x20, 0xf2, 0xcc, 0xf2, 0x73, 0x58, 0xc8, 0x44, 0xb4, - 0x90, 0x9d, 0x1c, 0xc0, 0xfc, 0xc0, 0x0b, 0x4b, 0x81, 0x70, 0xf2, 0x0d, 0x70, 0xf5, 0xe2, 0x25, 0xa4, 0x8a, 0xf5, - 0x7a, 0x2a, 0x68, 0x3e, 0x7c, 0x58, 0x4a, 0xe7, 0xd5, 0x85, 0x22, 0x55, 0x5a, 0xc6, 0xa9, 0x27, 0x02, 0x77, 0x47, - 0x98, 0xf9, 0x75, 0x8d, 0xe1, 0x65, 0xb2, 0x41, 0xca, 0x84, 0x93, 0x83, 0xf3, 0xb4, 0xc1, 0x0f, 0x42, 0x53, 0x11, - 0xa2, 0x67, 0xb7, 0x14, 0xc8, 0xf7, 0xf1, 0xb6, 0x52, 0x39, 0xe5, 0x24, 0x8b, 0xad, 0xbc, 0x96, 0xfe, 0x10, 0x77, - 0x7c, 0xa5, 0x34, 0xa6, 0x42, 0xb9, 0xf3, 0x74, 0x08, 0x45, 0x05, 0x2f, 0xde, 0x5b, 0xad, 0xa8, 0xb0, 0x31, 0x38, - 0x39, 0xa0, 0x67, 0xe9, 0x29, 0xed, 0xb0, 0xd3, 0x13, 0x50, 0xe5, 0xa6, 0x45, 0xf7, 0x56, 0x2b, 0xbe, 0xa4, 0xf4, - 0x8b, 0x72, 0x0e, 0x16, 0xe9, 0x32, 0x38, 0xfd, 0x7f, 0x8a, 0xa5, 0x7c, 0x2e, 0xc4, 0x61, 0x03, 0x00}; + 0x3d, 0x21, 0xf5, 0x5e, 0xd9, 0x1e, 0x40, 0x3b, 0xd9, 0xfb, 0x5d, 0xb1, 0xbd, 0x4f, 0x0b, 0xa1, 0xe8, 0x98, 0x3d, + 0xbe, 0xba, 0xfa, 0xb4, 0x27, 0x8b, 0xbd, 0x4f, 0x99, 0x52, 0x9f, 0xf6, 0xb8, 0x50, 0x9a, 0xd1, 0x51, 0x12, 0xa1, + 0xae, 0xe9, 0x2c, 0x53, 0xea, 0x1d, 0xbb, 0xd5, 0x44, 0x63, 0xf3, 0xa9, 0x09, 0x5b, 0x4f, 0x98, 0xde, 0x53, 0xe5, + 0xbc, 0x62, 0xb4, 0xcc, 0x99, 0xde, 0xd3, 0xc4, 0xe4, 0x4b, 0x07, 0x7f, 0x66, 0x3f, 0x75, 0x97, 0x8f, 0xe3, 0x1b, + 0x71, 0x70, 0xa0, 0x4b, 0x40, 0xa3, 0xa5, 0x5b, 0x21, 0xc2, 0xf6, 0x7d, 0xda, 0xc1, 0x01, 0x4b, 0x72, 0x26, 0x26, + 0x7a, 0x4a, 0x08, 0x69, 0x77, 0xc5, 0xc1, 0x41, 0xac, 0xc9, 0x07, 0x91, 0x4c, 0x98, 0x8e, 0x19, 0x42, 0xb8, 0xaa, + 0x7d, 0x70, 0x10, 0x5b, 0x20, 0x48, 0xa2, 0x0d, 0xe0, 0x6a, 0x30, 0x46, 0x89, 0x83, 0xfe, 0xd5, 0x9d, 0xc8, 0xe2, + 0x70, 0xfc, 0x08, 0x8b, 0x83, 0x83, 0x0f, 0x22, 0x51, 0xd0, 0x22, 0xd6, 0x08, 0xad, 0x0b, 0xa6, 0x17, 0x85, 0xd8, + 0xd3, 0x6b, 0x2d, 0xaf, 0x74, 0xc1, 0xc5, 0x24, 0x46, 0x4b, 0x9f, 0x16, 0x54, 0x5c, 0xaf, 0xed, 0x70, 0x7f, 0x2b, + 0x08, 0x27, 0x97, 0xd0, 0xe3, 0x33, 0x19, 0x3b, 0x1c, 0xe4, 0x84, 0x44, 0xca, 0xd4, 0x8d, 0x7a, 0x3c, 0xe5, 0x8d, + 0x28, 0xc2, 0x76, 0x94, 0xf8, 0xb3, 0x40, 0x58, 0x68, 0x40, 0xdd, 0x24, 0x49, 0x34, 0x22, 0x97, 0x4b, 0x0f, 0x16, + 0x1e, 0x4c, 0xb4, 0xc7, 0xfb, 0xad, 0x41, 0xaa, 0x93, 0x82, 0x8d, 0x16, 0x19, 0x8b, 0x63, 0x81, 0x15, 0x96, 0x88, + 0x5c, 0x8a, 0x46, 0x5c, 0x90, 0x4b, 0x58, 0xef, 0xa2, 0xbe, 0xd8, 0x84, 0xec, 0xb7, 0x90, 0x1b, 0x64, 0xe1, 0x47, + 0x08, 0x20, 0x76, 0x03, 0x2a, 0x08, 0x89, 0xc4, 0x62, 0x36, 0x64, 0x45, 0x54, 0x16, 0xeb, 0xd6, 0xf0, 0x62, 0xa1, + 0xd8, 0x5e, 0xa6, 0xd4, 0xde, 0x78, 0x21, 0x32, 0xcd, 0xa5, 0xd8, 0x8b, 0x1a, 0x45, 0x23, 0xb2, 0xf8, 0x50, 0xa2, + 0x43, 0x84, 0xd6, 0x28, 0x56, 0xa8, 0xc1, 0xfb, 0xb2, 0xd1, 0x1e, 0x60, 0x18, 0x25, 0xea, 0xba, 0xf6, 0x1c, 0x04, + 0x18, 0xe6, 0x30, 0xc9, 0x35, 0xfe, 0xd3, 0xee, 0x7c, 0x98, 0xe2, 0x8d, 0xe8, 0xf1, 0x64, 0x7b, 0xa7, 0x10, 0x9d, + 0xcc, 0xe8, 0x3c, 0x66, 0xe4, 0x92, 0x19, 0xec, 0xa2, 0x22, 0x83, 0xb1, 0xd6, 0x16, 0xae, 0xc7, 0x52, 0x96, 0x54, + 0x38, 0x85, 0x52, 0x9d, 0x8c, 0x65, 0xf1, 0x94, 0x66, 0x53, 0xa8, 0x57, 0x62, 0xcc, 0xc8, 0x6f, 0xb8, 0xac, 0x60, + 0x54, 0xb3, 0xa7, 0x39, 0x83, 0xaf, 0x38, 0x32, 0x35, 0x23, 0x84, 0x15, 0x6c, 0xf5, 0x9c, 0xeb, 0x57, 0x52, 0x64, + 0xac, 0xab, 0x02, 0xfc, 0x32, 0x2b, 0xff, 0x50, 0xeb, 0x82, 0x0f, 0x17, 0x9a, 0xc5, 0x91, 0x80, 0x12, 0x11, 0x56, + 0x08, 0x8b, 0x44, 0xb3, 0x5b, 0xfd, 0x58, 0x0a, 0xcd, 0x84, 0x26, 0xcc, 0x43, 0x15, 0xf3, 0x84, 0xce, 0xe7, 0x4c, + 0x8c, 0x1e, 0x4f, 0x79, 0x3e, 0x8a, 0x05, 0x5a, 0xa3, 0x35, 0xfe, 0x5d, 0x10, 0x98, 0x24, 0xb9, 0xe4, 0x29, 0xfc, + 0xf3, 0xed, 0xe9, 0xc4, 0x9a, 0x5c, 0x9a, 0x6d, 0xc1, 0x48, 0x14, 0x75, 0xc7, 0xb2, 0x88, 0xdd, 0x14, 0xf6, 0x80, + 0x74, 0x41, 0x1f, 0x6f, 0x17, 0x39, 0x53, 0x88, 0x35, 0x88, 0x28, 0xd7, 0xd1, 0x41, 0xf8, 0xb7, 0x22, 0x66, 0xb0, + 0x00, 0x1c, 0xa5, 0xdc, 0x90, 0xc0, 0x97, 0xdc, 0x6d, 0xaa, 0x51, 0x49, 0xd4, 0x3e, 0x0a, 0x32, 0xe2, 0x89, 0x2e, + 0x16, 0x4a, 0xb3, 0xd1, 0xbb, 0xbb, 0x39, 0x53, 0xf8, 0xe7, 0x82, 0x7c, 0x14, 0xbd, 0x8f, 0x22, 0x61, 0xb3, 0xb9, + 0xbe, 0xbb, 0x32, 0xd4, 0x3c, 0x8d, 0x22, 0xfc, 0x8f, 0x29, 0x5a, 0x30, 0x9a, 0x01, 0x49, 0x73, 0x20, 0x7b, 0x23, + 0xf3, 0xbb, 0x31, 0xcf, 0xf3, 0xab, 0xc5, 0x7c, 0x2e, 0x0b, 0x8d, 0xb5, 0x20, 0x4b, 0x2d, 0x2b, 0xf8, 0xc0, 0x8a, + 0x2e, 0xd5, 0x0d, 0xd7, 0xd9, 0x34, 0xd6, 0x68, 0x99, 0x51, 0xc5, 0xf6, 0x1e, 0x49, 0x99, 0x33, 0x2a, 0x52, 0x4e, + 0x78, 0xef, 0xe7, 0x22, 0x15, 0x8b, 0x3c, 0xef, 0x0e, 0x0b, 0x46, 0x3f, 0x77, 0x4d, 0xb6, 0x3d, 0x1c, 0x52, 0xf3, + 0xfb, 0x61, 0x51, 0xd0, 0x3b, 0x28, 0x48, 0x08, 0x14, 0xeb, 0xf1, 0xf4, 0xe7, 0xab, 0xd7, 0xaf, 0x12, 0xbb, 0x57, + 0xf8, 0xf8, 0x2e, 0xe6, 0xe5, 0xfe, 0xe3, 0x6b, 0x3c, 0x2e, 0xe4, 0x6c, 0xa3, 0x6b, 0x0b, 0x3a, 0xde, 0xfd, 0xc6, + 0x10, 0x18, 0xe1, 0xfb, 0xb6, 0xe9, 0x70, 0x04, 0xaf, 0x0c, 0xe6, 0x43, 0x26, 0x71, 0xfd, 0xc2, 0x3f, 0xa9, 0x4d, + 0x8e, 0x39, 0xfa, 0xfe, 0x68, 0x75, 0x71, 0xb7, 0x64, 0xc4, 0x8c, 0x73, 0x0e, 0x07, 0x23, 0x8c, 0x31, 0xa3, 0x3a, + 0x9b, 0x2e, 0x99, 0x69, 0x6c, 0xed, 0x47, 0xcc, 0xd6, 0x6b, 0xfc, 0x55, 0x7a, 0xac, 0xd7, 0xfb, 0x84, 0x70, 0x43, + 0xaf, 0x88, 0x5e, 0xad, 0x38, 0x21, 0x1c, 0xe1, 0xb7, 0x9c, 0x2c, 0xa9, 0x9f, 0x10, 0x9c, 0x6c, 0xb0, 0x3d, 0x53, + 0x4b, 0x65, 0xe0, 0x04, 0xfc, 0xc2, 0x0a, 0xcd, 0x8a, 0x54, 0x0b, 0x5c, 0xb0, 0x71, 0x0e, 0xe3, 0xd8, 0x6f, 0xe3, + 0x29, 0x55, 0x8f, 0xa7, 0x54, 0x4c, 0xd8, 0x28, 0xfd, 0x2a, 0xd7, 0x98, 0x09, 0x12, 0x8d, 0xb9, 0xa0, 0x39, 0xff, + 0xca, 0x46, 0x91, 0x3b, 0x17, 0x1e, 0xe9, 0x3d, 0x76, 0xab, 0x99, 0x18, 0xa9, 0xbd, 0xe7, 0xef, 0x7e, 0x7d, 0xe9, + 0x16, 0xb3, 0x76, 0x56, 0xa0, 0xa5, 0x5a, 0xcc, 0x59, 0x11, 0x23, 0xec, 0xce, 0x8a, 0xa7, 0xdc, 0xd0, 0xc9, 0x5f, + 0xe9, 0xdc, 0xa6, 0x70, 0xf5, 0xfb, 0x7c, 0x44, 0x35, 0x7b, 0xc3, 0xc4, 0x88, 0x8b, 0x09, 0xd9, 0x6f, 0xdb, 0xf4, + 0x29, 0x75, 0x19, 0xa3, 0x32, 0xe9, 0xfa, 0xde, 0xd3, 0xdc, 0xcc, 0xbd, 0xfc, 0x5c, 0xc4, 0x68, 0xad, 0x34, 0xd5, + 0x3c, 0xdb, 0xa3, 0xa3, 0xd1, 0x0b, 0xc1, 0x35, 0x37, 0x23, 0x2c, 0x60, 0x89, 0x00, 0x57, 0x99, 0x3d, 0x35, 0xfc, + 0xc8, 0x63, 0x84, 0xe3, 0xd8, 0x9d, 0x05, 0x53, 0xe4, 0xd6, 0xec, 0xe0, 0xa0, 0xa2, 0xfc, 0x3d, 0x96, 0xda, 0x4c, + 0xd2, 0x1f, 0xa0, 0x64, 0xbe, 0x50, 0xb0, 0xd8, 0xbe, 0x0b, 0x38, 0x68, 0xe4, 0x50, 0xb1, 0xe2, 0x0b, 0x1b, 0x95, + 0x08, 0xa2, 0x62, 0xb4, 0xdc, 0xe8, 0xc3, 0x6d, 0x0f, 0x4d, 0xfa, 0x83, 0x6e, 0x48, 0xc2, 0x99, 0x43, 0x76, 0xcb, + 0xa9, 0x70, 0xa6, 0x4a, 0xa2, 0x12, 0xc3, 0x81, 0x5a, 0x12, 0x16, 0x45, 0xfc, 0xfc, 0xe6, 0xb1, 0x00, 0x1e, 0x22, + 0xa4, 0x1c, 0xfe, 0xcc, 0x7d, 0xfa, 0xc5, 0x1c, 0x1e, 0x0a, 0x0b, 0x84, 0xb5, 0x1d, 0xa9, 0x42, 0x68, 0x8d, 0xb0, + 0xf6, 0xc3, 0xb5, 0x44, 0xc9, 0xf3, 0x45, 0x70, 0x6a, 0x93, 0xb7, 0xdc, 0x1c, 0xdb, 0x40, 0xdb, 0xa8, 0x66, 0x07, + 0x07, 0x31, 0x4b, 0x4a, 0xc4, 0x20, 0xfb, 0x6d, 0xb7, 0x48, 0x01, 0xb4, 0xbe, 0x31, 0x6e, 0xe8, 0xd9, 0x30, 0x38, + 0xfb, 0x2c, 0x11, 0xf2, 0x61, 0x96, 0x31, 0xa5, 0x64, 0x71, 0x70, 0xb0, 0x6f, 0xca, 0x97, 0x9c, 0x05, 0x2c, 0xe2, + 0xeb, 0x1b, 0x51, 0x0d, 0x01, 0x55, 0xa7, 0xad, 0xe7, 0x9b, 0x48, 0xc5, 0x37, 0x79, 0x26, 0x24, 0x8d, 0xae, 0xaf, + 0xa3, 0x86, 0xc6, 0x0e, 0x0e, 0x13, 0xe6, 0xbb, 0xbe, 0x7b, 0xc2, 0x2c, 0x5b, 0x68, 0x98, 0x90, 0x2d, 0xd0, 0xec, + 0xe4, 0x07, 0xe3, 0xfa, 0x90, 0xb0, 0xc6, 0x0a, 0xad, 0x83, 0x15, 0xdd, 0xd9, 0xb4, 0xe1, 0x6f, 0xec, 0xd2, 0x2d, + 0x27, 0x86, 0xa7, 0x08, 0xd6, 0xb1, 0xcf, 0x06, 0x6b, 0x6c, 0x60, 0xef, 0x67, 0x23, 0xcd, 0x40, 0xfb, 0x7a, 0xd0, + 0x75, 0xf9, 0x44, 0x59, 0xc8, 0x15, 0xec, 0x9f, 0x05, 0x53, 0xda, 0x22, 0x72, 0xac, 0xb1, 0xc4, 0x70, 0x46, 0x6d, + 0x32, 0x9d, 0x35, 0x96, 0x74, 0xd7, 0xd8, 0x5e, 0xcf, 0xe1, 0x6c, 0x54, 0x80, 0xd4, 0xdf, 0xc7, 0x27, 0x18, 0xab, + 0x46, 0xab, 0xd5, 0x5b, 0xee, 0x5b, 0xa9, 0xd6, 0xb2, 0xe4, 0xd7, 0x36, 0x16, 0x85, 0x09, 0xe4, 0x0e, 0xe7, 0xfd, + 0xb6, 0x1b, 0xbf, 0x18, 0x90, 0xfd, 0x56, 0x89, 0xc5, 0x0e, 0xac, 0x76, 0x3c, 0x16, 0x8a, 0xaf, 0x6d, 0x53, 0xc8, + 0x9c, 0xf5, 0x35, 0x7c, 0x49, 0xa6, 0x5b, 0xb8, 0x3a, 0x25, 0x7d, 0xe0, 0x3a, 0x92, 0xe9, 0xe0, 0x5b, 0xf8, 0xe4, + 0x29, 0x42, 0xac, 0xb7, 0xf3, 0x2a, 0xc2, 0xf1, 0xa5, 0x4e, 0x38, 0x36, 0xa6, 0x11, 0xcd, 0xcb, 0x2a, 0x51, 0x89, + 0x66, 0x6e, 0xab, 0x57, 0x59, 0x58, 0x98, 0xc1, 0x54, 0x53, 0x0a, 0x9a, 0x78, 0x45, 0x67, 0x4c, 0xc5, 0x0c, 0xe1, + 0x6f, 0x15, 0xb0, 0xf8, 0x09, 0x45, 0x06, 0xc1, 0x19, 0xaa, 0xe0, 0x0c, 0x05, 0x76, 0x17, 0x98, 0xb4, 0xfa, 0x96, + 0x53, 0x98, 0xf5, 0xd5, 0xa0, 0xe2, 0xed, 0x82, 0xc9, 0x9b, 0xc3, 0xd9, 0x21, 0xb8, 0x87, 0x9f, 0x4d, 0xb3, 0x40, + 0x33, 0x2c, 0x84, 0x42, 0x78, 0xbf, 0xb5, 0xb9, 0x92, 0xbe, 0x54, 0x35, 0xc7, 0xfe, 0x00, 0xd6, 0xc1, 0x1c, 0x1b, + 0x09, 0x57, 0xe6, 0x6f, 0x6d, 0xab, 0x01, 0xd8, 0xae, 0x00, 0x33, 0x92, 0x71, 0x4e, 0x75, 0xdc, 0x3e, 0x6a, 0x01, + 0x63, 0xfa, 0x85, 0xc1, 0xa9, 0x82, 0xd0, 0xf6, 0x54, 0x58, 0xb2, 0x10, 0x6a, 0xca, 0xc7, 0x3a, 0xfe, 0x5d, 0x18, + 0xa2, 0xc2, 0x72, 0xc5, 0x40, 0xc2, 0x09, 0xd8, 0x63, 0x43, 0x70, 0x7e, 0x17, 0xd0, 0x4f, 0xb7, 0x3c, 0x88, 0xdc, + 0x48, 0x0d, 0xe1, 0x02, 0xf2, 0x50, 0xb1, 0xd6, 0x15, 0x99, 0x29, 0x19, 0x37, 0xe0, 0x1e, 0xdb, 0x3d, 0xdb, 0x62, + 0xea, 0xa8, 0x81, 0x08, 0x38, 0x58, 0x91, 0x86, 0x24, 0xc2, 0x25, 0xea, 0x44, 0xcb, 0x97, 0xf2, 0x86, 0x15, 0x8f, + 0x29, 0x0c, 0x3e, 0xb5, 0xd5, 0xd7, 0xf6, 0x28, 0x30, 0x14, 0x5f, 0x77, 0x3d, 0xbe, 0x5c, 0x9b, 0x89, 0xbf, 0x29, + 0xe4, 0x8c, 0x2b, 0x06, 0x7c, 0x9b, 0x85, 0xbf, 0x80, 0x8d, 0x66, 0x76, 0x24, 0x1c, 0x37, 0xac, 0xc4, 0xaf, 0x87, + 0x2f, 0xeb, 0xf8, 0x75, 0x7d, 0xef, 0xe9, 0xc4, 0x53, 0xc0, 0xfa, 0x3e, 0x46, 0x38, 0x76, 0xe2, 0x45, 0x70, 0xd2, + 0x25, 0x53, 0xe4, 0x8e, 0xf9, 0xd5, 0x4a, 0x07, 0x62, 0x5c, 0x8d, 0x73, 0x64, 0x76, 0xdb, 0xa0, 0x35, 0x1d, 0x8d, + 0x80, 0xc5, 0x2b, 0x64, 0x9e, 0x07, 0x87, 0x15, 0x16, 0xdd, 0xf2, 0x78, 0xba, 0xbe, 0xf7, 0xf4, 0xea, 0x7b, 0x27, + 0x14, 0xe4, 0x87, 0x87, 0x94, 0x1f, 0xa8, 0x18, 0xb1, 0x02, 0xe4, 0xca, 0x60, 0xb5, 0xdc, 0x39, 0xfb, 0x58, 0x0a, + 0xc1, 0x32, 0xcd, 0x46, 0x20, 0xb4, 0x08, 0xa2, 0x93, 0xa9, 0x54, 0xba, 0x4c, 0xac, 0x46, 0x2f, 0x42, 0x21, 0x34, + 0xc9, 0x68, 0x9e, 0xc7, 0x56, 0x40, 0x99, 0xc9, 0x2f, 0x6c, 0xc7, 0xa8, 0xbb, 0xb5, 0x21, 0x97, 0xcd, 0xb0, 0xa0, + 0x19, 0x96, 0xa8, 0x79, 0xce, 0x33, 0x56, 0x1e, 0x5e, 0x57, 0x09, 0x17, 0x23, 0x76, 0x0b, 0x74, 0x04, 0x5d, 0x5e, + 0x5e, 0xb6, 0x70, 0x1b, 0xad, 0x2d, 0xc0, 0x97, 0x5b, 0x80, 0xfd, 0xce, 0xb1, 0x69, 0x05, 0xf1, 0xe5, 0x4e, 0xb2, + 0x86, 0x82, 0xb3, 0x92, 0x7b, 0x41, 0xcb, 0x92, 0x67, 0x84, 0x47, 0x2c, 0x67, 0x9a, 0x79, 0x72, 0x0e, 0xcc, 0xb4, + 0xdd, 0xba, 0x6f, 0x4b, 0xf8, 0x95, 0xe8, 0xe4, 0x77, 0x99, 0x5f, 0x73, 0x55, 0x8a, 0xee, 0xd5, 0xf2, 0x54, 0xd0, + 0xee, 0x69, 0xbb, 0x3c, 0x54, 0x6b, 0x9a, 0x4d, 0xad, 0xc4, 0x1e, 0x6f, 0x4d, 0xa9, 0x6a, 0xc3, 0x91, 0xf6, 0x72, + 0x13, 0xfd, 0x59, 0xb8, 0x61, 0xee, 0x02, 0xc1, 0x95, 0x23, 0x0a, 0x0c, 0x84, 0x40, 0xbb, 0x6c, 0x8f, 0x69, 0x9e, + 0x0f, 0x69, 0xf6, 0xb9, 0x8e, 0xfd, 0x15, 0x1a, 0x90, 0x4d, 0x6a, 0x1c, 0x64, 0x05, 0x24, 0x2b, 0x9c, 0xb7, 0xa7, + 0xd2, 0xb5, 0x8d, 0x12, 0xef, 0xb7, 0x2a, 0xb4, 0xaf, 0x2f, 0xf4, 0x37, 0xb1, 0xdd, 0x8c, 0x48, 0xb8, 0x99, 0xc5, + 0x40, 0x05, 0xfe, 0x25, 0xc6, 0x79, 0x7a, 0xe0, 0xf0, 0x0e, 0x04, 0x8f, 0xf5, 0xc6, 0x40, 0x34, 0x5a, 0xae, 0x47, + 0x5c, 0x7d, 0x1b, 0x02, 0xff, 0x5b, 0x46, 0xf9, 0x24, 0xe8, 0xe1, 0xdf, 0x1d, 0x68, 0x49, 0xe3, 0x1c, 0xe3, 0x5c, + 0x8e, 0xcc, 0x31, 0x14, 0x9e, 0xd0, 0xfc, 0x02, 0xcc, 0x8b, 0xc1, 0xf7, 0xd7, 0x36, 0xcb, 0xf0, 0x65, 0x30, 0x0c, + 0xd5, 0x0d, 0x19, 0x8a, 0x1a, 0x0a, 0x38, 0xa2, 0x2a, 0xcc, 0x99, 0x2b, 0x6b, 0xa2, 0xa4, 0xe3, 0xda, 0xad, 0x38, + 0xee, 0x68, 0x6e, 0x41, 0xe2, 0x38, 0x56, 0x20, 0xcd, 0x79, 0xfe, 0xbe, 0x9a, 0x85, 0xda, 0x9a, 0x85, 0x4a, 0x02, + 0x69, 0x0b, 0x55, 0xc8, 0x1c, 0x54, 0x4f, 0xb5, 0x40, 0x61, 0x29, 0x60, 0x59, 0x13, 0xa0, 0xd0, 0xa8, 0x24, 0xb8, + 0x39, 0xd1, 0xb8, 0x70, 0xa2, 0x8e, 0xc3, 0x35, 0x20, 0x19, 0x55, 0x15, 0x89, 0xec, 0xe6, 0xa8, 0xc9, 0xbe, 0x12, + 0x17, 0x68, 0x83, 0xbf, 0x5f, 0xaf, 0x1d, 0x94, 0x18, 0x72, 0xab, 0x53, 0x63, 0x8c, 0x03, 0xb0, 0x60, 0x49, 0x1c, + 0x33, 0x6c, 0x59, 0x9f, 0x4d, 0xe0, 0x94, 0xed, 0xee, 0x13, 0x22, 0x2b, 0xd8, 0xd4, 0x98, 0x4a, 0xcf, 0x5d, 0x49, + 0x84, 0xa9, 0x67, 0x4b, 0x8b, 0x6a, 0xe2, 0x84, 0x44, 0x5e, 0x3b, 0x11, 0xf5, 0x96, 0x35, 0xe1, 0x30, 0x0d, 0x8a, + 0xad, 0x53, 0x20, 0xaa, 0xc5, 0x2e, 0x78, 0xef, 0xc2, 0x9a, 0x5a, 0x3b, 0x01, 0xc4, 0x8b, 0x1a, 0xc4, 0x03, 0xd0, + 0x4a, 0x4b, 0xbc, 0xe4, 0x80, 0xd0, 0x7a, 0xe5, 0x98, 0xe1, 0xc2, 0x2e, 0xc4, 0x16, 0x14, 0x37, 0xd9, 0x4f, 0x83, + 0x85, 0x20, 0xcb, 0x2a, 0xe0, 0xef, 0xc2, 0x23, 0x22, 0x86, 0xc1, 0x8b, 0xd5, 0x6a, 0x0b, 0xed, 0x76, 0x72, 0xa1, + 0x28, 0xa9, 0xa4, 0xc3, 0xd5, 0xea, 0xab, 0x44, 0xb1, 0xe3, 0x7f, 0x31, 0x43, 0x3d, 0x4f, 0x74, 0x1f, 0xbe, 0x84, + 0x52, 0x86, 0x1d, 0xad, 0x52, 0x4a, 0xc1, 0xa1, 0x8e, 0xb5, 0xf5, 0x85, 0xd2, 0x01, 0xe5, 0x7e, 0xbc, 0x45, 0xc0, + 0x4c, 0xa2, 0x3b, 0xa9, 0xab, 0x29, 0x3f, 0x76, 0x4d, 0x0b, 0x84, 0x50, 0xaa, 0x8c, 0x2c, 0xb3, 0xbf, 0x4b, 0xbe, + 0x3c, 0x38, 0x50, 0x41, 0x43, 0xd7, 0x25, 0xa5, 0xf8, 0x3b, 0x86, 0x53, 0x59, 0xdd, 0x09, 0xc3, 0xbe, 0xfc, 0xed, + 0xcf, 0xa1, 0x2d, 0xe9, 0xb4, 0xd5, 0x05, 0xc1, 0x9c, 0xde, 0x50, 0xae, 0xf7, 0xca, 0x56, 0xac, 0x60, 0x1e, 0x33, + 0xb4, 0x74, 0xdc, 0x46, 0x52, 0x30, 0xe0, 0x1f, 0x81, 0x2c, 0x78, 0x2e, 0xda, 0x22, 0x7e, 0x36, 0x65, 0xa0, 0xca, + 0xf6, 0x8c, 0x44, 0x29, 0x1e, 0xee, 0xbb, 0x83, 0xc4, 0x35, 0xbc, 0x7b, 0xec, 0xeb, 0xcd, 0xea, 0x35, 0x69, 0x60, + 0xce, 0x8a, 0xb1, 0x2c, 0x66, 0x3e, 0x6f, 0xbd, 0xf1, 0xed, 0x88, 0x23, 0x1f, 0xc7, 0x3b, 0xdb, 0x76, 0x22, 0x40, + 0x77, 0x43, 0xf6, 0xae, 0xa4, 0xf6, 0xda, 0x69, 0x5a, 0x1e, 0xc0, 0x56, 0x41, 0xe8, 0x31, 0x53, 0x85, 0x52, 0xbe, + 0x53, 0xaf, 0x76, 0xad, 0xee, 0x64, 0xbf, 0xdd, 0x2d, 0x25, 0x3f, 0x8f, 0x0d, 0x5d, 0xab, 0xe3, 0x70, 0xa7, 0xaa, + 0x5c, 0xe4, 0x23, 0x37, 0x58, 0x81, 0x30, 0x73, 0x78, 0x74, 0xc3, 0xf3, 0xbc, 0x4a, 0xfd, 0x4f, 0x48, 0xbb, 0x72, + 0xa4, 0x5d, 0x7a, 0xd2, 0x0e, 0xa4, 0x02, 0x48, 0xbb, 0x6d, 0xae, 0xaa, 0x2e, 0xb7, 0xb6, 0xa7, 0xb4, 0x44, 0x5d, + 0x19, 0x71, 0x1a, 0xfa, 0x5b, 0xf8, 0x11, 0xa0, 0x92, 0xf9, 0xfa, 0x1c, 0x3b, 0x7d, 0x0c, 0x88, 0x81, 0x56, 0xa7, + 0xc9, 0x42, 0x4d, 0xc5, 0xe7, 0x18, 0x61, 0xb5, 0x66, 0x25, 0x66, 0x3f, 0x7c, 0x0a, 0x4a, 0xbb, 0x60, 0x3a, 0x70, + 0x8e, 0x99, 0xe4, 0xff, 0x88, 0x8f, 0xf2, 0xb3, 0x13, 0x6e, 0x76, 0xca, 0xcf, 0x0e, 0x68, 0x7d, 0x35, 0xbb, 0xd1, + 0xf7, 0xa9, 0xbd, 0x99, 0x9e, 0x28, 0xa7, 0x57, 0xad, 0xf7, 0x6a, 0x15, 0x6f, 0xa4, 0x80, 0x46, 0xdf, 0x49, 0x29, + 0x45, 0xd9, 0x3a, 0xd0, 0x80, 0x10, 0x32, 0x90, 0xb0, 0xb6, 0x93, 0x2e, 0x4f, 0xb9, 0x97, 0xff, 0x4a, 0xcf, 0x63, + 0x14, 0xf7, 0xb6, 0xfe, 0x63, 0x39, 0x9b, 0x03, 0x43, 0xb6, 0x81, 0xd2, 0x13, 0xe6, 0x3a, 0xac, 0xf2, 0xd7, 0x3b, + 0xd2, 0x6a, 0x75, 0xcc, 0x7e, 0xac, 0x61, 0x53, 0x29, 0x35, 0xef, 0xb7, 0xd6, 0x8b, 0x32, 0xa9, 0x24, 0x1c, 0xbb, + 0x74, 0x2b, 0x8f, 0x37, 0x35, 0x33, 0x3e, 0xe3, 0x75, 0x2c, 0x2c, 0x1d, 0x16, 0x40, 0xeb, 0x02, 0xf2, 0xe3, 0xd1, + 0x3d, 0x5c, 0xff, 0x75, 0x05, 0x9c, 0xe5, 0x7a, 0x03, 0x7c, 0xcb, 0xf5, 0xfa, 0x91, 0x76, 0x92, 0x36, 0x7e, 0xb4, + 0x43, 0xee, 0x2d, 0xa1, 0x57, 0x65, 0x3a, 0x99, 0xb1, 0x3f, 0x80, 0xb4, 0x2d, 0x16, 0x92, 0x2c, 0x67, 0x72, 0xc4, + 0xd2, 0x48, 0xce, 0x99, 0x88, 0xd6, 0xa0, 0x67, 0x75, 0x08, 0xf0, 0x8f, 0x88, 0x97, 0x6f, 0xeb, 0xfa, 0xd6, 0xf4, + 0x91, 0x5e, 0x83, 0x2a, 0xec, 0x25, 0xdf, 0xa1, 0x8c, 0x7d, 0xcf, 0x0a, 0x65, 0x78, 0xd2, 0x92, 0xbd, 0x7d, 0xc9, + 0xab, 0x03, 0xea, 0x25, 0x4f, 0xbf, 0x5d, 0xa5, 0x12, 0x48, 0xa2, 0x76, 0x72, 0x96, 0x1c, 0x47, 0xc8, 0x68, 0x8c, + 0x9f, 0x79, 0x8d, 0xf1, 0xa2, 0xd4, 0x18, 0x3f, 0xd7, 0x64, 0xb1, 0xa1, 0x31, 0xfe, 0x43, 0x90, 0xe7, 0xba, 0xf7, + 0xdc, 0x6b, 0xd3, 0xdf, 0xc8, 0x9c, 0x67, 0x77, 0x71, 0x94, 0x73, 0xdd, 0x84, 0xdb, 0xc4, 0x08, 0x2f, 0x6d, 0x06, + 0xa8, 0x1a, 0x8d, 0xbe, 0x7b, 0xed, 0xe5, 0x3f, 0x2c, 0x04, 0x89, 0xee, 0xe5, 0x5c, 0xdf, 0x8b, 0xf0, 0x54, 0x93, + 0x4f, 0xf0, 0xeb, 0xde, 0x32, 0xfe, 0x95, 0xea, 0x69, 0x52, 0x50, 0x31, 0x92, 0xb3, 0x18, 0x35, 0xa2, 0x08, 0x25, + 0xca, 0x08, 0x21, 0x0f, 0xd0, 0xfa, 0xde, 0x27, 0xfc, 0x4a, 0x92, 0xa8, 0x17, 0x35, 0xa6, 0x1a, 0x6b, 0x4a, 0x3e, + 0x5d, 0xdc, 0x5b, 0xbe, 0x92, 0xeb, 0xcb, 0x4f, 0xf8, 0xa9, 0x2e, 0xd5, 0xfa, 0xf8, 0x96, 0x91, 0x18, 0x91, 0xcb, + 0xa7, 0x7e, 0x48, 0x8f, 0xe5, 0xcc, 0x2a, 0xf8, 0x23, 0x84, 0xbf, 0x80, 0x5e, 0xf7, 0x92, 0x57, 0x44, 0xc8, 0xdd, + 0xc1, 0xec, 0x93, 0x48, 0x1a, 0xe5, 0x41, 0x74, 0x70, 0x10, 0xa4, 0x95, 0x2c, 0x04, 0xfe, 0x5b, 0x92, 0x9a, 0xa8, + 0x8e, 0x19, 0x85, 0x96, 0xfe, 0x96, 0x31, 0x47, 0xbe, 0x99, 0xd8, 0x6b, 0xaa, 0xdd, 0x8e, 0xe5, 0x7d, 0xab, 0x7b, + 0x48, 0xb8, 0x66, 0x05, 0xd5, 0xb2, 0x18, 0xa0, 0x90, 0x2d, 0xc1, 0x5f, 0x39, 0xf9, 0xd4, 0xdf, 0xfb, 0x7f, 0xfe, + 0xc7, 0x5f, 0xe3, 0xbf, 0x8a, 0xc1, 0x27, 0x2c, 0x18, 0x39, 0xba, 0x88, 0x7b, 0x69, 0xbc, 0xdf, 0x6c, 0xae, 0xfe, + 0x3a, 0xea, 0xff, 0x37, 0x6d, 0x7e, 0x7d, 0xd8, 0xfc, 0x73, 0x80, 0x56, 0xf1, 0x5f, 0x47, 0xbd, 0xbe, 0xfb, 0xea, + 0xff, 0xf7, 0xe5, 0x5f, 0x6a, 0x70, 0x68, 0x13, 0xef, 0x21, 0x74, 0x34, 0xc1, 0xbf, 0x08, 0x72, 0xd4, 0x6c, 0x5e, + 0x1e, 0x4d, 0xf0, 0x4f, 0x82, 0x1c, 0xc1, 0xdf, 0x3b, 0x4d, 0xde, 0xb2, 0xc9, 0xd3, 0xdb, 0x79, 0xfc, 0xe9, 0x72, + 0x75, 0x6f, 0xf9, 0x95, 0xaf, 0xa1, 0xdd, 0xfe, 0x7f, 0xff, 0xf5, 0x97, 0x8a, 0x7e, 0xbc, 0x24, 0x47, 0x83, 0x06, + 0x8a, 0x4d, 0xf2, 0x21, 0xb1, 0x7f, 0xe2, 0x5e, 0xda, 0xff, 0x6f, 0x37, 0x94, 0xe8, 0xc7, 0xbf, 0x3e, 0x5d, 0x5c, + 0x92, 0xc1, 0x2a, 0x8e, 0x56, 0x3f, 0xa2, 0x15, 0x42, 0xab, 0x7b, 0xe8, 0x13, 0x8e, 0x26, 0x11, 0xc2, 0xbf, 0x09, + 0x72, 0xf4, 0xe3, 0xd1, 0x04, 0xff, 0x29, 0xc8, 0x51, 0x74, 0x34, 0xc1, 0xef, 0x25, 0x39, 0xfa, 0xef, 0xb8, 0x97, + 0x5a, 0x25, 0xdc, 0xca, 0xa8, 0x3f, 0x56, 0x70, 0x13, 0x42, 0x0b, 0x46, 0x57, 0x9a, 0xeb, 0x9c, 0xa1, 0x7b, 0x47, + 0x1c, 0x3f, 0x92, 0x00, 0xac, 0x58, 0x83, 0x92, 0xc6, 0x5c, 0xc2, 0x2e, 0xaf, 0x61, 0xe1, 0x01, 0x83, 0xee, 0xa5, + 0x1c, 0x5b, 0x3d, 0x81, 0x4a, 0xb5, 0xbd, 0xbd, 0x55, 0x70, 0x7d, 0x8b, 0x1f, 0x93, 0x47, 0x32, 0x6e, 0x23, 0xcc, + 0x29, 0xfc, 0xe8, 0x20, 0xfc, 0x41, 0xbb, 0x0b, 0x4f, 0xd8, 0xe6, 0x16, 0xc3, 0x84, 0xb4, 0xfc, 0x4c, 0x84, 0xf0, + 0xcb, 0x1d, 0x99, 0x7a, 0x0a, 0xea, 0x07, 0x84, 0x7f, 0xae, 0x5d, 0x8f, 0xe2, 0xc7, 0x9a, 0x94, 0xc8, 0xf1, 0xae, + 0x60, 0xec, 0x03, 0xcd, 0x3f, 0xb3, 0x22, 0x7e, 0xaa, 0x71, 0xbb, 0xf3, 0x00, 0x1b, 0x55, 0xf5, 0x7e, 0x1b, 0x75, + 0xcb, 0xdb, 0xad, 0xe7, 0xd2, 0xde, 0x27, 0xc0, 0x29, 0x5c, 0xd7, 0xd7, 0xc0, 0xda, 0xef, 0xf3, 0x2d, 0xa5, 0x56, + 0x41, 0x6f, 0x22, 0x54, 0xbf, 0x4a, 0xe5, 0xe2, 0x0b, 0xcd, 0xf9, 0x68, 0x4f, 0xb3, 0xd9, 0x3c, 0xa7, 0x9a, 0xed, + 0xb9, 0x39, 0xef, 0x51, 0x68, 0x28, 0x2a, 0x79, 0x8a, 0x3f, 0x44, 0xb5, 0x69, 0xff, 0x10, 0x49, 0xb5, 0x77, 0x62, + 0xb8, 0xcf, 0x72, 0x7c, 0x89, 0xa0, 0xe5, 0x75, 0xd9, 0xe6, 0x8d, 0x60, 0xb3, 0x0d, 0xca, 0xb2, 0x81, 0x39, 0xbf, + 0x15, 0x86, 0xfb, 0x4d, 0x42, 0x3a, 0xbd, 0xe8, 0x42, 0x7d, 0x99, 0x5c, 0x46, 0x70, 0x93, 0x53, 0x10, 0xc1, 0x8c, + 0xf2, 0x08, 0x4a, 0x50, 0xd2, 0xea, 0xd2, 0x0b, 0xd6, 0xa5, 0x8d, 0x86, 0x67, 0xb3, 0x33, 0xc2, 0xfb, 0xd4, 0xd6, + 0xcf, 0xf1, 0x14, 0x8f, 0x48, 0xb3, 0x8d, 0x17, 0xa4, 0x65, 0xaa, 0x74, 0x17, 0x17, 0x99, 0xeb, 0xe7, 0xe0, 0x20, + 0x2e, 0x92, 0x9c, 0x2a, 0xfd, 0x02, 0x34, 0x02, 0x64, 0x81, 0xa7, 0xa4, 0x48, 0xd8, 0x2d, 0xcb, 0xe2, 0x0c, 0xe1, + 0xa9, 0xa3, 0x41, 0xa8, 0x8b, 0x16, 0x24, 0x28, 0x06, 0x72, 0x06, 0x11, 0xac, 0x37, 0xed, 0xb7, 0x07, 0x84, 0x90, + 0x68, 0xbf, 0xd9, 0x8c, 0x7a, 0x05, 0xf9, 0x45, 0xa4, 0x90, 0x12, 0xb0, 0xd3, 0xe4, 0x27, 0x48, 0xea, 0x04, 0x49, + 0xf1, 0x7b, 0x99, 0x68, 0xa6, 0x74, 0x0c, 0xc9, 0xa0, 0x24, 0x50, 0x1e, 0xc3, 0xa3, 0x8b, 0xa3, 0xa8, 0x01, 0xa9, + 0x06, 0x45, 0x11, 0x2e, 0xc8, 0x9d, 0x46, 0xe9, 0xb4, 0x7f, 0x3c, 0x08, 0xcf, 0x08, 0x9b, 0x0a, 0xfd, 0xdf, 0xe9, + 0xde, 0xb4, 0xdf, 0x32, 0xfd, 0x5f, 0x46, 0xbd, 0xb8, 0x20, 0xca, 0xb2, 0x71, 0x3d, 0x95, 0x0a, 0x66, 0xe6, 0x8b, + 0x52, 0x37, 0x40, 0xd7, 0xf7, 0x88, 0x34, 0x3b, 0x69, 0x3c, 0x0a, 0x67, 0xd2, 0x84, 0x0e, 0x1d, 0x28, 0x70, 0x4e, + 0xa0, 0x3c, 0x2e, 0x08, 0x74, 0x5a, 0x55, 0xbb, 0xd3, 0xa9, 0x4b, 0xf8, 0x31, 0xfa, 0xb1, 0xf7, 0xa7, 0x48, 0x7f, + 0x13, 0x76, 0x04, 0x7f, 0x8a, 0xd5, 0x0a, 0xfe, 0xfe, 0x26, 0x7a, 0x30, 0x2c, 0x93, 0xf6, 0x8b, 0x4b, 0xfb, 0x09, + 0xd2, 0x04, 0x4b, 0xcd, 0x80, 0xb1, 0x2a, 0xf9, 0x31, 0xbb, 0x38, 0x63, 0x62, 0x67, 0x70, 0x70, 0xc0, 0xfb, 0xb4, + 0xd1, 0x1e, 0xc0, 0x8d, 0x40, 0xa1, 0xd5, 0x07, 0xae, 0xa7, 0x71, 0x74, 0x74, 0x19, 0xa1, 0x5e, 0xb4, 0x07, 0xab, + 0xdc, 0x95, 0x0d, 0xe2, 0x60, 0x9d, 0x35, 0x34, 0x4d, 0x47, 0x97, 0xa4, 0xd5, 0x8b, 0x85, 0x25, 0xf2, 0x39, 0xc2, + 0x99, 0xa3, 0xa9, 0x2d, 0x3c, 0x42, 0x0d, 0x21, 0x1a, 0xfe, 0x7b, 0x84, 0x1a, 0x53, 0xdd, 0x18, 0xa3, 0x34, 0x83, + 0xbf, 0xf1, 0x88, 0x10, 0xd2, 0xec, 0x94, 0x15, 0xfd, 0x61, 0x49, 0x51, 0x3a, 0xf6, 0xea, 0xd1, 0xbe, 0xd9, 0x1c, + 0xb2, 0x11, 0xf3, 0x3e, 0x1b, 0xac, 0x56, 0xd1, 0x45, 0xef, 0x32, 0x42, 0x8d, 0xd8, 0xa3, 0xdd, 0x91, 0xc7, 0x3b, + 0x84, 0xb0, 0x18, 0xac, 0xdd, 0x0d, 0xd4, 0x0d, 0xab, 0xdd, 0x36, 0x2d, 0xab, 0xfd, 0x1f, 0x90, 0x05, 0xb6, 0x2e, + 0xe5, 0x1e, 0xcb, 0xdf, 0xce, 0x61, 0xaa, 0x1e, 0xb7, 0x25, 0x69, 0xe1, 0x82, 0x78, 0x75, 0x37, 0x25, 0xba, 0xc2, + 0xff, 0x8c, 0x54, 0xc5, 0x71, 0x3f, 0xc7, 0xd3, 0x01, 0x11, 0xd4, 0xc8, 0x2f, 0x5d, 0xaf, 0x4c, 0x67, 0x39, 0xb9, + 0x61, 0x1b, 0xf7, 0xbf, 0x39, 0xdc, 0xc9, 0x3c, 0xd6, 0x49, 0xb6, 0x28, 0x0a, 0x26, 0xf4, 0x2b, 0x39, 0x72, 0x8c, + 0x1d, 0xcb, 0x41, 0xb6, 0x82, 0x8b, 0x5d, 0x0c, 0x5c, 0x5d, 0xc7, 0xef, 0x94, 0xd1, 0x56, 0xf6, 0x82, 0x8c, 0x2c, + 0xc3, 0x65, 0xae, 0x7b, 0xbb, 0x0b, 0x27, 0x4a, 0xc7, 0x08, 0x8f, 0xdc, 0x3d, 0x70, 0x9c, 0x24, 0xc9, 0x22, 0xc9, + 0x20, 0x1b, 0x3a, 0x50, 0x68, 0x6d, 0xf6, 0x55, 0xac, 0xc8, 0x63, 0x9d, 0x08, 0x76, 0x6b, 0xba, 0x8d, 0x51, 0x75, + 0x88, 0xfb, 0xfd, 0x76, 0x41, 0xbb, 0x86, 0x00, 0xa9, 0x44, 0xc8, 0x11, 0x03, 0x08, 0xc1, 0xdd, 0xbf, 0x4b, 0x9a, + 0x52, 0x15, 0xde, 0x6c, 0x55, 0x03, 0xec, 0x87, 0x2a, 0xef, 0x05, 0xe8, 0x89, 0x0d, 0x7b, 0x56, 0x16, 0xb6, 0xca, + 0x73, 0x84, 0xf8, 0x38, 0x5e, 0x24, 0x70, 0x23, 0x68, 0x30, 0x49, 0x08, 0xb4, 0x5a, 0x2d, 0x42, 0xdc, 0x9a, 0x56, + 0x8a, 0xe9, 0x31, 0x99, 0xf6, 0x8b, 0x46, 0xc3, 0x28, 0xaf, 0x47, 0x16, 0x2f, 0x16, 0x08, 0x8f, 0xcb, 0xbd, 0xe6, + 0xcb, 0xcd, 0x49, 0xbd, 0xab, 0x78, 0x5c, 0x57, 0x02, 0x37, 0x84, 0x40, 0x46, 0xbf, 0xa8, 0xa1, 0x75, 0x3c, 0x21, + 0x47, 0x71, 0x3f, 0xe9, 0xfd, 0xcf, 0x01, 0xea, 0xc5, 0xc9, 0x21, 0x3a, 0xb2, 0xb4, 0x64, 0x8c, 0xba, 0x99, 0xed, + 0x63, 0x69, 0x6e, 0x3f, 0xdb, 0xd8, 0x28, 0x20, 0x53, 0x89, 0x05, 0x9d, 0xb1, 0x74, 0x02, 0xbb, 0xde, 0x23, 0xcf, + 0x1c, 0x03, 0x32, 0xa5, 0x13, 0x47, 0x5b, 0x92, 0xa8, 0x27, 0x69, 0xf9, 0xd5, 0x8b, 0x7a, 0xb4, 0xfa, 0xfa, 0x9f, + 0x51, 0x2f, 0xa3, 0xe9, 0x63, 0xbe, 0x76, 0x4a, 0xf2, 0x5a, 0x1f, 0x67, 0xbe, 0x8f, 0xb5, 0x5d, 0x9c, 0x00, 0x78, + 0x23, 0xb4, 0xad, 0x1d, 0x59, 0xa0, 0x35, 0x1f, 0x97, 0xd4, 0x49, 0x25, 0x9a, 0x4e, 0x00, 0xaa, 0xc1, 0x22, 0xa8, + 0xd0, 0x36, 0x20, 0x98, 0x32, 0x60, 0x8b, 0x47, 0x5a, 0x80, 0xe6, 0xe2, 0xb2, 0x85, 0x96, 0xb5, 0xc2, 0x8e, 0xb3, + 0xaa, 0xdf, 0xc5, 0x97, 0xc4, 0x7b, 0x0c, 0x54, 0xf9, 0x62, 0xd1, 0x1d, 0x37, 0x1a, 0x48, 0x79, 0xfc, 0x1a, 0xf5, + 0xc7, 0x03, 0x7c, 0x0b, 0x28, 0x84, 0x6b, 0x18, 0x85, 0x6b, 0x73, 0xec, 0xb8, 0x39, 0x36, 0x1a, 0x72, 0x8d, 0xba, + 0x41, 0xe5, 0x85, 0xab, 0xbc, 0x5e, 0x5b, 0xc8, 0x6c, 0x62, 0xdc, 0x39, 0x32, 0x29, 0x60, 0x08, 0x46, 0x08, 0x79, + 0x25, 0xd1, 0xce, 0x66, 0xa1, 0x51, 0xa8, 0x6e, 0x76, 0x2f, 0x50, 0x54, 0x7b, 0x7a, 0xc4, 0x00, 0x0b, 0xa8, 0x5a, + 0xaa, 0x91, 0xa7, 0x1a, 0x8f, 0x1a, 0x6d, 0x83, 0xee, 0xcd, 0x76, 0xb7, 0xde, 0xd8, 0xfd, 0xaa, 0x31, 0x3c, 0x6a, + 0x90, 0x69, 0xb5, 0xc3, 0xd7, 0xb2, 0xd1, 0x58, 0xd7, 0xef, 0x4b, 0xfd, 0x26, 0xae, 0xdd, 0x5f, 0x3c, 0xdd, 0x32, + 0xf1, 0xf0, 0xa7, 0x6f, 0x75, 0xde, 0x8a, 0x84, 0x0b, 0xc1, 0x0a, 0x38, 0x61, 0x89, 0xc6, 0x62, 0xbd, 0x2e, 0x4f, + 0xfd, 0xdf, 0xb5, 0xb5, 0x19, 0x23, 0x1c, 0xe8, 0x90, 0x91, 0xda, 0xb0, 0xc4, 0x05, 0xa6, 0x86, 0x8a, 0x10, 0x42, + 0x3e, 0x68, 0x6f, 0x1e, 0xa3, 0x0d, 0x49, 0xca, 0x48, 0x70, 0x76, 0xc7, 0x8a, 0xb0, 0xe4, 0xfa, 0xde, 0x63, 0xf9, + 0x5d, 0x91, 0xae, 0x2f, 0x06, 0xa9, 0x29, 0x96, 0x3b, 0x42, 0x96, 0x93, 0x2f, 0x20, 0xe7, 0x94, 0x17, 0x2c, 0x89, + 0x21, 0x88, 0x4f, 0x78, 0xc1, 0x0c, 0xe3, 0x7e, 0xcf, 0xcb, 0x8d, 0x59, 0x9d, 0xd3, 0xcc, 0x42, 0xed, 0x0f, 0x40, + 0x33, 0x07, 0xe5, 0x90, 0x24, 0x5b, 0xc5, 0xae, 0xef, 0x3d, 0x7c, 0xbd, 0x4b, 0x86, 0x5e, 0xad, 0x9c, 0xf4, 0x9c, + 0x01, 0xeb, 0x83, 0xf3, 0x6a, 0xa8, 0x99, 0xfb, 0x91, 0xc6, 0x99, 0x61, 0xa2, 0xf2, 0x98, 0x03, 0x32, 0x5d, 0xdf, + 0x7b, 0xf8, 0x2e, 0xe6, 0x46, 0x37, 0x85, 0x70, 0x38, 0xef, 0xb8, 0x20, 0x31, 0x25, 0x0c, 0xd9, 0xc9, 0x97, 0x74, + 0xac, 0x08, 0x4e, 0xf7, 0x94, 0x9a, 0x4c, 0x10, 0x3b, 0xfa, 0x62, 0x40, 0x32, 0x07, 0x02, 0x92, 0x21, 0x9c, 0xd5, + 0xe4, 0x3a, 0x62, 0xd6, 0xc0, 0x74, 0x76, 0x05, 0x8b, 0x91, 0x58, 0xf6, 0x10, 0xe1, 0xcc, 0x74, 0xab, 0xd7, 0xf6, + 0x38, 0x51, 0x74, 0xd3, 0xd0, 0xad, 0x92, 0x67, 0xdf, 0x83, 0xe0, 0xe5, 0x3f, 0x5e, 0xb9, 0xb6, 0xcb, 0x84, 0x27, + 0xde, 0x22, 0xed, 0xfa, 0xde, 0xc3, 0x5f, 0x9d, 0x51, 0xda, 0x9c, 0x7a, 0xf2, 0xbf, 0x25, 0xa3, 0x3e, 0xfc, 0x35, + 0xa9, 0x72, 0x4d, 0xe1, 0xeb, 0x7b, 0x0f, 0x7f, 0xdf, 0x55, 0x0c, 0xd2, 0xd7, 0x8b, 0x4a, 0x49, 0x60, 0xc6, 0xb7, + 0x64, 0x79, 0xba, 0x74, 0x67, 0x45, 0x2a, 0xd6, 0xd8, 0x9c, 0x50, 0xa9, 0x5a, 0x97, 0xba, 0x95, 0x27, 0x58, 0x12, + 0x73, 0x95, 0x54, 0x5f, 0x36, 0x87, 0xc6, 0x5c, 0x8a, 0xab, 0x4c, 0xce, 0xd9, 0x37, 0xee, 0x97, 0x9e, 0x6a, 0x94, + 0xf0, 0x19, 0x18, 0xe2, 0x98, 0xb1, 0x0b, 0xbc, 0xdf, 0x42, 0xdd, 0x8d, 0xf3, 0x4c, 0x1a, 0x44, 0x2d, 0xea, 0x87, + 0x0d, 0xa6, 0xa4, 0x85, 0x33, 0xd2, 0xc2, 0x39, 0x51, 0xfd, 0x96, 0x3d, 0x31, 0xba, 0x79, 0xd9, 0xb4, 0x3d, 0x77, + 0x60, 0xbb, 0xe7, 0x76, 0xdf, 0xda, 0x43, 0x79, 0xda, 0xcd, 0x8d, 0xfe, 0xd2, 0x1c, 0xf4, 0x53, 0x83, 0x1a, 0x4f, + 0x58, 0x5c, 0xe0, 0xc2, 0xb4, 0x7c, 0xc5, 0x87, 0x39, 0xd8, 0xa9, 0xc0, 0xcc, 0xb0, 0x46, 0x69, 0x59, 0xb6, 0xed, + 0xca, 0xe6, 0x89, 0x59, 0xab, 0x02, 0xe7, 0x09, 0x90, 0x72, 0x9c, 0x3b, 0xbb, 0x1e, 0xb5, 0x5d, 0xe5, 0xec, 0xe0, + 0x20, 0x76, 0x95, 0x68, 0x5c, 0xf8, 0xfc, 0xea, 0x06, 0xf0, 0xbd, 0xa5, 0x1a, 0x53, 0x64, 0x26, 0xd0, 0x68, 0x64, + 0x83, 0x35, 0xdd, 0x27, 0x24, 0xce, 0xeb, 0x50, 0xf4, 0xa3, 0x37, 0xcc, 0xe0, 0x06, 0x00, 0x1a, 0x8d, 0xf2, 0xba, + 0x77, 0x03, 0x62, 0x4f, 0x35, 0x96, 0xeb, 0x2f, 0x71, 0x69, 0x4d, 0xd4, 0xda, 0xb2, 0xc3, 0xf2, 0xa3, 0x40, 0x22, + 0xc4, 0x5d, 0xe1, 0xe7, 0x13, 0x6c, 0x0d, 0x01, 0xe5, 0x5e, 0x38, 0x1b, 0x08, 0x6c, 0xac, 0xb6, 0x5c, 0x21, 0x4f, + 0xda, 0x3a, 0x28, 0xf5, 0x85, 0xe0, 0x82, 0x0b, 0x0a, 0x35, 0xd6, 0x0e, 0xcb, 0x9f, 0xb0, 0x6d, 0x73, 0x4e, 0xac, + 0x90, 0xd3, 0x96, 0x99, 0x61, 0x18, 0x80, 0x75, 0x4a, 0xc0, 0x3c, 0x27, 0x2f, 0xbf, 0x8d, 0xfa, 0x0f, 0x03, 0xd4, + 0x7f, 0x44, 0x58, 0xb0, 0x0d, 0xac, 0xae, 0x24, 0x91, 0x4e, 0x41, 0xa1, 0x7c, 0xd6, 0xe3, 0x39, 0x01, 0x6d, 0x5c, + 0x1d, 0xaa, 0xb5, 0x2b, 0xca, 0x6f, 0x50, 0x96, 0x70, 0xa7, 0x18, 0x7d, 0x26, 0xf6, 0xf7, 0xc9, 0x71, 0x75, 0x41, + 0x07, 0x5d, 0xef, 0x52, 0x0e, 0x86, 0xa4, 0xf0, 0xe1, 0xef, 0xdf, 0xbf, 0x5b, 0x7d, 0x3c, 0xdf, 0xde, 0xc1, 0x81, + 0x59, 0x29, 0xcc, 0x3a, 0xd8, 0xc0, 0x75, 0x23, 0x53, 0xe8, 0xbf, 0xbc, 0x13, 0xaf, 0x53, 0xa1, 0x8d, 0xcd, 0xe8, + 0x8f, 0x43, 0x18, 0x6d, 0xbb, 0x6d, 0x4a, 0xb0, 0xa0, 0x59, 0xa0, 0x4b, 0xd6, 0xb8, 0x95, 0x16, 0xdf, 0x20, 0x23, + 0x0f, 0x4d, 0x01, 0x26, 0x46, 0xbb, 0xb3, 0x1f, 0xad, 0x1d, 0x9e, 0xd8, 0xa1, 0xa1, 0xa5, 0x21, 0x84, 0x16, 0xef, + 0x01, 0x73, 0xec, 0x11, 0x01, 0x20, 0x7a, 0x69, 0x20, 0x55, 0x81, 0x2c, 0x8a, 0x2a, 0x45, 0xfe, 0xf3, 0x7d, 0x42, + 0x5e, 0x56, 0x8a, 0xcc, 0xb7, 0x95, 0x31, 0x17, 0x20, 0x06, 0x4a, 0xe1, 0x22, 0xa1, 0x4c, 0xb0, 0x97, 0xa1, 0x1f, + 0xb4, 0x2f, 0x6f, 0xa4, 0xcd, 0xa4, 0xe2, 0xc6, 0x83, 0x9b, 0x52, 0xa3, 0xe2, 0xb3, 0xf9, 0x1e, 0x12, 0x1b, 0xb9, + 0xf7, 0x20, 0x97, 0x51, 0x33, 0x48, 0xf8, 0x7e, 0x67, 0x4a, 0xfb, 0x76, 0xd7, 0x9f, 0x37, 0x2d, 0x62, 0x36, 0xd6, + 0x25, 0xe1, 0x42, 0xb1, 0x42, 0x3f, 0x62, 0x63, 0x59, 0xc0, 0xfd, 0x47, 0x09, 0x16, 0xb4, 0xbe, 0x17, 0xe8, 0x00, + 0xcd, 0x04, 0x83, 0x4b, 0x87, 0x8d, 0x19, 0x9a, 0x5f, 0x9f, 0xcd, 0x1d, 0xf8, 0xf5, 0x66, 0xad, 0x97, 0x07, 0x07, + 0x5f, 0x58, 0x05, 0x28, 0x37, 0x4c, 0x33, 0x8c, 0x80, 0x78, 0x59, 0x2e, 0xc7, 0xdd, 0x0c, 0xdf, 0x8b, 0x2b, 0x95, + 0x81, 0x27, 0x1c, 0x21, 0x11, 0x7a, 0x4e, 0xf4, 0x7a, 0xb2, 0x49, 0xef, 0x9d, 0x36, 0x43, 0x84, 0x62, 0x0d, 0x90, + 0x7b, 0x90, 0xcb, 0xad, 0x92, 0x49, 0x55, 0xb6, 0xb6, 0xe5, 0x20, 0x1e, 0x03, 0xb8, 0x62, 0x23, 0xa4, 0x04, 0x68, + 0xb8, 0x5b, 0x68, 0x79, 0x2e, 0x81, 0xfd, 0xc7, 0x2a, 0x01, 0x91, 0x16, 0xd5, 0x36, 0x2e, 0x42, 0xd8, 0x9a, 0xfa, + 0x04, 0xc6, 0x09, 0x0f, 0x9f, 0xef, 0xd2, 0x50, 0x7b, 0xd4, 0x66, 0xe6, 0x0c, 0x82, 0x12, 0x12, 0x95, 0x15, 0x92, + 0x2f, 0xb1, 0x70, 0xdc, 0x9c, 0xbf, 0x87, 0x03, 0x52, 0xac, 0x68, 0x6c, 0xef, 0xb6, 0xe0, 0xf8, 0x28, 0x92, 0x45, + 0x5c, 0xeb, 0xba, 0x5b, 0x98, 0x6a, 0xd8, 0x81, 0x8e, 0x86, 0x70, 0x2a, 0xcc, 0x3d, 0xe1, 0xe3, 0x8a, 0xa4, 0xfe, + 0x6c, 0x4d, 0xb4, 0xb5, 0x27, 0x86, 0x95, 0x69, 0x4a, 0x30, 0xff, 0x9f, 0xad, 0xd5, 0x75, 0x59, 0x08, 0x33, 0x33, + 0x8c, 0x1b, 0xbb, 0x0a, 0x6c, 0x0d, 0x38, 0xb6, 0xfc, 0x5b, 0x06, 0x8b, 0xea, 0x95, 0xe2, 0xa6, 0xd3, 0x80, 0x09, + 0x78, 0x0b, 0xd6, 0x33, 0x9b, 0x5b, 0xff, 0xb9, 0x39, 0x18, 0x05, 0x56, 0x35, 0x02, 0x2f, 0x0d, 0x81, 0x47, 0xc0, + 0xb8, 0x79, 0xd3, 0xf2, 0x9e, 0x33, 0xa2, 0x11, 0xfe, 0xc4, 0x73, 0x78, 0x66, 0x59, 0xee, 0xad, 0x8f, 0x8d, 0x15, + 0x49, 0x05, 0x01, 0xdb, 0x22, 0xec, 0x88, 0xbc, 0x44, 0x58, 0x35, 0x1a, 0x5d, 0x75, 0xc1, 0x2a, 0xad, 0x4a, 0x35, + 0x4c, 0x01, 0xb7, 0xc4, 0x80, 0xf7, 0xb5, 0x13, 0x15, 0x0c, 0x09, 0xbc, 0xf5, 0xb7, 0x02, 0xf5, 0xfd, 0xc3, 0xb7, + 0x71, 0x48, 0xdf, 0xc2, 0xb2, 0xe5, 0x45, 0x2c, 0x4c, 0x29, 0xae, 0xee, 0x70, 0xde, 0x7c, 0xdf, 0x6c, 0x04, 0xc6, + 0xbd, 0xdf, 0xc6, 0x60, 0xe3, 0x86, 0xba, 0xda, 0x92, 0x86, 0x72, 0x13, 0x76, 0x51, 0x65, 0xef, 0x18, 0x76, 0xd6, + 0xd5, 0x95, 0xb4, 0xab, 0x89, 0x5a, 0xaf, 0x15, 0xab, 0x8c, 0x06, 0x36, 0x0c, 0x3b, 0xcd, 0x31, 0xb3, 0xad, 0xc0, + 0x7f, 0x3c, 0x27, 0x1a, 0x07, 0xc8, 0xfa, 0xe6, 0x5b, 0xd7, 0x29, 0xd5, 0x30, 0x61, 0x7b, 0xbb, 0xf3, 0xf1, 0x31, + 0xdf, 0x75, 0x3e, 0x62, 0xe9, 0xb6, 0xbe, 0x39, 0x1b, 0xdb, 0xff, 0xc6, 0xd9, 0xe8, 0xd4, 0xf6, 0xfe, 0x78, 0x04, + 0xee, 0xa4, 0x76, 0x3c, 0xd6, 0xd7, 0x94, 0x48, 0x2c, 0xdc, 0x72, 0x5c, 0x76, 0x56, 0x2b, 0xd1, 0x6f, 0x81, 0xda, + 0x29, 0x8a, 0xe0, 0x67, 0xdb, 0xfe, 0x0c, 0x48, 0xb2, 0xd5, 0x21, 0xc7, 0xa2, 0x14, 0x65, 0x50, 0x02, 0x06, 0xd4, + 0xb1, 0xb1, 0xf5, 0x32, 0x88, 0xed, 0x70, 0xc8, 0x61, 0x39, 0x11, 0xe5, 0xd5, 0x15, 0x8c, 0xd8, 0x1c, 0x1b, 0x4e, + 0xc0, 0x8c, 0x77, 0x5a, 0x15, 0x7a, 0xf1, 0xf3, 0x5f, 0x33, 0xa7, 0xb5, 0x23, 0xc6, 0x72, 0x12, 0x35, 0x2b, 0x06, + 0x37, 0x02, 0xc7, 0x30, 0xee, 0x1b, 0x09, 0xb5, 0x3a, 0xd5, 0x51, 0xed, 0x48, 0xc2, 0x2d, 0x50, 0xbb, 0xed, 0x9b, + 0x73, 0x69, 0xb5, 0xda, 0x79, 0xb0, 0xe0, 0x22, 0xc0, 0xed, 0xe7, 0x44, 0xd7, 0x48, 0x0a, 0x25, 0x4e, 0x82, 0xc2, + 0xb9, 0x41, 0x55, 0x4d, 0x64, 0xbf, 0x35, 0x00, 0x9e, 0xb4, 0x9b, 0x5d, 0xc8, 0x4a, 0x48, 0xce, 0x1a, 0x0d, 0x94, + 0x97, 0x1d, 0xd3, 0xbe, 0x68, 0x64, 0x03, 0xcc, 0x70, 0x66, 0x05, 0x16, 0x38, 0xbd, 0xe2, 0xbc, 0xea, 0xba, 0x9f, + 0x0d, 0x10, 0x2e, 0x56, 0xab, 0xd8, 0x0e, 0x2d, 0x47, 0xab, 0x55, 0x1e, 0x0e, 0xcd, 0xe4, 0x43, 0xc5, 0x97, 0x3d, + 0x4d, 0x5e, 0x9a, 0xf3, 0xf0, 0x25, 0x0c, 0xb2, 0x41, 0xe2, 0xdc, 0xa9, 0x04, 0x73, 0xd0, 0x5c, 0x35, 0x64, 0x3f, + 0x6b, 0xb4, 0x07, 0x01, 0x0d, 0xeb, 0x67, 0x03, 0x92, 0xaf, 0xc1, 0x72, 0x56, 0xb9, 0x03, 0xf3, 0x6f, 0x38, 0xd8, + 0xfe, 0x36, 0xe7, 0x8c, 0x6d, 0x30, 0x5c, 0x93, 0x4d, 0x95, 0x41, 0x89, 0x57, 0x6e, 0x71, 0x7d, 0xb9, 0x9a, 0x81, + 0x45, 0x59, 0x08, 0xbb, 0x6b, 0xe6, 0x1e, 0x08, 0xff, 0x25, 0xb6, 0x4b, 0x5a, 0x1a, 0x71, 0x6f, 0x20, 0xbe, 0xb7, + 0xdd, 0x4e, 0x92, 0x84, 0x16, 0x13, 0x73, 0x25, 0xe2, 0x6f, 0x78, 0xcd, 0x1e, 0x38, 0x76, 0xe3, 0x0c, 0x7a, 0xee, + 0x97, 0x9d, 0x0d, 0x88, 0x1d, 0xbf, 0x67, 0x76, 0xbc, 0xe3, 0x4a, 0x41, 0x77, 0xeb, 0x22, 0xec, 0x60, 0xe8, 0xff, + 0xf2, 0x60, 0x4e, 0xdc, 0x60, 0x2c, 0x9a, 0x6c, 0xc0, 0xed, 0x1b, 0xf0, 0x28, 0xe8, 0x06, 0xdc, 0xbe, 0x0d, 0x5f, + 0x0f, 0xad, 0xec, 0x9b, 0x03, 0x0c, 0xc8, 0x84, 0x1d, 0x69, 0x95, 0x10, 0x0c, 0xf3, 0x74, 0x93, 0x23, 0xb3, 0x64, + 0x15, 0x0e, 0x57, 0x4d, 0x62, 0xb1, 0xb1, 0x17, 0x2a, 0x26, 0x35, 0x10, 0x8c, 0x45, 0xfa, 0x12, 0x85, 0x4a, 0x83, + 0xba, 0x71, 0x0c, 0x60, 0x95, 0xd3, 0xd6, 0xbf, 0x3c, 0x38, 0x00, 0xa1, 0x01, 0x58, 0xbb, 0x24, 0xa3, 0x73, 0xbd, + 0x28, 0x80, 0xbf, 0x52, 0xfe, 0x37, 0x24, 0x83, 0xdb, 0x89, 0x49, 0x83, 0x1f, 0x90, 0x30, 0xa7, 0x4a, 0xf1, 0x2f, + 0x36, 0xcd, 0xfd, 0xc6, 0x05, 0xf1, 0x18, 0xad, 0x2c, 0xa7, 0x28, 0x51, 0x57, 0x3a, 0x74, 0xad, 0x43, 0xee, 0xe9, + 0x17, 0x26, 0xf4, 0x4b, 0xae, 0x34, 0x13, 0x00, 0x80, 0x0a, 0xf1, 0x60, 0x4a, 0x0a, 0xc1, 0xd6, 0xad, 0xd5, 0xa2, + 0xa3, 0xd1, 0x77, 0xab, 0xe8, 0x3a, 0x5b, 0x34, 0xa5, 0x62, 0x94, 0xdb, 0x4e, 0x42, 0x9b, 0x49, 0x6f, 0x27, 0x5a, + 0x96, 0x0c, 0x2d, 0x76, 0x2a, 0xf6, 0xc3, 0xd0, 0xfa, 0x58, 0x10, 0x7f, 0x2e, 0xf8, 0xb3, 0xf4, 0xbb, 0x7c, 0x0c, + 0x5c, 0xa9, 0x7f, 0x63, 0x15, 0xc2, 0x99, 0x60, 0x1d, 0x90, 0xd7, 0xa4, 0x3e, 0x4e, 0x8f, 0x3a, 0xf9, 0x96, 0x72, + 0xa1, 0x34, 0x0a, 0xdb, 0x38, 0x29, 0x0c, 0xa6, 0x9c, 0x7d, 0x5b, 0xe2, 0xfa, 0xd5, 0x1f, 0x23, 0xfe, 0xe8, 0x10, + 0xff, 0x2e, 0x95, 0x46, 0xcb, 0x12, 0xc1, 0x90, 0xdf, 0x91, 0x5a, 0xc1, 0x55, 0x6c, 0xce, 0xf5, 0x73, 0x3d, 0xcb, + 0x37, 0x3c, 0x71, 0xba, 0x5a, 0x95, 0x52, 0x81, 0x8a, 0x6f, 0x18, 0x7e, 0xc2, 0xe0, 0xde, 0xf8, 0x19, 0x0f, 0xaa, + 0x6c, 0xdf, 0x17, 0x3f, 0x0b, 0xee, 0x8b, 0x9f, 0xf1, 0x74, 0xbb, 0x68, 0x70, 0x4f, 0xdc, 0x49, 0xce, 0x93, 0x56, + 0xe4, 0xf9, 0xa8, 0x29, 0xad, 0xfc, 0x2b, 0xed, 0xd6, 0xc0, 0x95, 0x4d, 0x1c, 0x18, 0xe7, 0xd5, 0x45, 0x28, 0xe6, + 0xcc, 0x19, 0x2d, 0x87, 0xff, 0xad, 0x75, 0x72, 0x27, 0x8f, 0xb4, 0x52, 0xc8, 0x1b, 0x5a, 0xe8, 0x7b, 0xb0, 0xe1, + 0x8a, 0x2d, 0x1f, 0x40, 0x4a, 0x40, 0xd9, 0xf6, 0xef, 0x75, 0x11, 0x88, 0xe3, 0xca, 0x3a, 0x1f, 0x85, 0xed, 0x93, + 0xa2, 0xe4, 0xea, 0xea, 0x42, 0xc8, 0xad, 0xd1, 0x12, 0x20, 0x4c, 0xbd, 0x6b, 0x1e, 0x73, 0x34, 0x99, 0xa5, 0xcb, + 0x75, 0xa9, 0x3a, 0x28, 0x2c, 0x57, 0xc7, 0x11, 0x2e, 0xd6, 0xe6, 0x06, 0xfd, 0x15, 0xc7, 0x7f, 0x73, 0x47, 0x23, + 0x7f, 0x2e, 0x29, 0xd0, 0xa3, 0xdd, 0xbe, 0x36, 0x3b, 0x48, 0xa4, 0x9d, 0x43, 0x69, 0x29, 0x00, 0x58, 0x6d, 0xf0, + 0x75, 0xed, 0x71, 0xea, 0x89, 0x74, 0xb3, 0xf9, 0xa6, 0x21, 0x2c, 0x66, 0xa5, 0x05, 0x8f, 0xe9, 0x66, 0x87, 0xe5, + 0xa8, 0x97, 0xc5, 0x75, 0xb9, 0xc7, 0x6a, 0xfd, 0xa2, 0x6f, 0x80, 0xb2, 0x32, 0x44, 0x5b, 0xad, 0xe2, 0x3a, 0xbc, + 0x89, 0x08, 0xae, 0x41, 0x10, 0x16, 0x81, 0x01, 0x47, 0x8d, 0xf1, 0xb6, 0x75, 0x62, 0xb4, 0x69, 0xbf, 0xe4, 0x59, + 0xf7, 0xda, 0x38, 0x42, 0x45, 0x83, 0xad, 0x1e, 0x6a, 0x1e, 0xb0, 0x9d, 0x5d, 0xd9, 0x51, 0x00, 0xa1, 0x29, 0xf5, + 0xc6, 0xb9, 0x95, 0x15, 0xed, 0x0e, 0xf8, 0xa2, 0xef, 0x98, 0xe7, 0x3a, 0xd0, 0x6d, 0xe7, 0x07, 0xb6, 0x4d, 0x4f, + 0xe4, 0xb7, 0x6c, 0x9b, 0x6a, 0x9c, 0xf0, 0x7e, 0x0b, 0x7d, 0xdf, 0x10, 0xd6, 0xf6, 0xb5, 0xbb, 0xc8, 0xff, 0x42, + 0x77, 0x6d, 0x40, 0x4f, 0x0b, 0x66, 0x4f, 0x63, 0x3e, 0xe8, 0xf5, 0xfa, 0xe7, 0xd2, 0x7f, 0xc1, 0xd8, 0x0a, 0xfd, + 0x6c, 0x77, 0x81, 0x13, 0x2b, 0x8d, 0x43, 0x70, 0xfc, 0x8a, 0x93, 0x49, 0x2e, 0x87, 0x34, 0x7f, 0x07, 0x3d, 0x56, + 0xb9, 0xcf, 0xef, 0x46, 0x05, 0xd5, 0xcc, 0xd1, 0x9a, 0x6a, 0x14, 0xaf, 0x78, 0x30, 0x8c, 0x57, 0xdc, 0x52, 0xee, + 0xaa, 0x05, 0xbc, 0x7c, 0x59, 0x36, 0x91, 0xfe, 0xbc, 0x2e, 0x65, 0x30, 0xb5, 0xbb, 0x97, 0x4d, 0x92, 0xc6, 0x4a, + 0x92, 0xc6, 0x54, 0xbc, 0xd9, 0x54, 0x1c, 0xff, 0xfd, 0x8d, 0xc1, 0x6e, 0x93, 0xb9, 0xbf, 0x03, 0x32, 0xf7, 0x37, + 0x4f, 0xbf, 0x5b, 0x2b, 0xa0, 0x78, 0xc7, 0xc9, 0xb1, 0xb1, 0x8c, 0xb1, 0xa3, 0x7e, 0xab, 0xc1, 0xa0, 0x41, 0x93, + 0xcb, 0xc0, 0xdb, 0xa1, 0x3a, 0xbd, 0xbc, 0xfd, 0x51, 0x9c, 0x2d, 0x94, 0x96, 0x33, 0xd7, 0xa8, 0x72, 0x3e, 0x4e, + 0x26, 0x13, 0x14, 0xd8, 0xe6, 0x0e, 0x3f, 0xad, 0xbb, 0x91, 0x2d, 0x3f, 0x73, 0x31, 0x4a, 0x15, 0x76, 0x67, 0x8b, + 0x4a, 0xe5, 0x9a, 0x78, 0x33, 0xe7, 0xed, 0x3c, 0x3c, 0xe6, 0x82, 0xab, 0x29, 0x2b, 0xe2, 0x02, 0x2d, 0xbf, 0xd5, + 0x59, 0x01, 0xb7, 0x39, 0xb6, 0x33, 0x3c, 0x2a, 0x2d, 0x07, 0x74, 0x02, 0xad, 0x81, 0xce, 0x68, 0xc6, 0xf4, 0x54, + 0x8e, 0xc0, 0xf0, 0x25, 0x19, 0x95, 0xee, 0x54, 0x07, 0x07, 0xfb, 0x71, 0x64, 0xf4, 0x17, 0xe0, 0x83, 0x1e, 0xe6, + 0xa0, 0xde, 0x12, 0x1c, 0x83, 0xaa, 0xae, 0x19, 0x5a, 0xb2, 0x4d, 0x1f, 0x1a, 0x9d, 0x7c, 0x66, 0x77, 0x98, 0xa3, + 0xf5, 0x3a, 0xb5, 0xa3, 0x8e, 0xc6, 0x9c, 0xe5, 0xa3, 0x08, 0x7f, 0x66, 0x77, 0x69, 0xe9, 0xb6, 0x6e, 0xbc, 0xac, + 0xcd, 0x22, 0x46, 0xf2, 0x46, 0x44, 0xb8, 0xea, 0x24, 0x5d, 0xae, 0xb1, 0x2c, 0xf8, 0x04, 0x70, 0xf4, 0x17, 0x76, + 0x97, 0xba, 0xf6, 0x02, 0x57, 0x41, 0xb4, 0xf4, 0xa0, 0x4f, 0x82, 0xe4, 0x70, 0x19, 0x9c, 0xc0, 0xd1, 0x37, 0x75, + 0x07, 0xa4, 0x56, 0xae, 0x12, 0x21, 0x11, 0x5a, 0xff, 0xbb, 0x53, 0xc1, 0x8b, 0xf0, 0x9c, 0xd3, 0x35, 0x8b, 0xdb, + 0x8d, 0x4a, 0x0c, 0x2a, 0x54, 0x16, 0x24, 0x1f, 0x63, 0xee, 0x77, 0x9f, 0xf3, 0x7e, 0x08, 0x74, 0x66, 0x0b, 0xea, + 0x1a, 0x4d, 0x47, 0xe6, 0x17, 0xaa, 0xee, 0xa0, 0x66, 0xba, 0xaa, 0xb8, 0xf7, 0x31, 0x06, 0xc0, 0x83, 0xb5, 0x0c, + 0x35, 0x0e, 0xa1, 0x6b, 0x6f, 0xa6, 0x3a, 0xa6, 0x24, 0x5e, 0xfa, 0x39, 0xa4, 0x3c, 0x04, 0xa3, 0x5e, 0x03, 0x1a, + 0x3a, 0x04, 0xb3, 0x96, 0x87, 0x7c, 0x1c, 0x8b, 0xad, 0x33, 0x54, 0x9a, 0x33, 0x34, 0x09, 0x40, 0xfe, 0x8d, 0x33, + 0x93, 0x19, 0x68, 0x18, 0xde, 0xd2, 0x1c, 0x80, 0x6e, 0x75, 0x1d, 0x0e, 0x85, 0x2b, 0x5a, 0x3a, 0xef, 0xd9, 0x45, + 0x97, 0xb5, 0x61, 0xc5, 0xa6, 0x1d, 0xb4, 0x4e, 0x61, 0x4a, 0xcc, 0x16, 0x58, 0x7b, 0xbd, 0x0f, 0xf7, 0x76, 0xb5, + 0x71, 0x91, 0xf8, 0x69, 0x11, 0x0f, 0x93, 0x98, 0xa2, 0x25, 0x8f, 0x29, 0x96, 0x60, 0x07, 0x59, 0xac, 0xcb, 0xf1, + 0xb3, 0x70, 0x39, 0x6a, 0x56, 0xd2, 0xbb, 0x1d, 0x0c, 0x81, 0xcb, 0xd7, 0x60, 0x1b, 0x8a, 0xb9, 0x27, 0x2c, 0x3c, + 0x36, 0x9e, 0x7e, 0xc1, 0xba, 0xcd, 0xed, 0x82, 0xf8, 0x15, 0x18, 0xd3, 0x78, 0x19, 0xcc, 0x22, 0x74, 0x2a, 0x77, + 0x0e, 0x87, 0xee, 0x9a, 0xb0, 0x32, 0x5e, 0x8d, 0x15, 0xd9, 0x38, 0x7a, 0xbe, 0x6f, 0xe3, 0xf9, 0xcf, 0x82, 0x15, + 0x77, 0x57, 0x0c, 0x6c, 0xac, 0x25, 0xb8, 0x1b, 0x57, 0xcb, 0x50, 0x19, 0xc8, 0xf7, 0xa4, 0x61, 0x5d, 0xd6, 0xf8, + 0xbb, 0x51, 0x31, 0xd6, 0xe6, 0x9e, 0x32, 0xd0, 0xd6, 0xd8, 0xed, 0xc2, 0xbe, 0xe9, 0xba, 0xc9, 0xba, 0x46, 0x11, + 0x57, 0x41, 0xda, 0xdd, 0x2d, 0xe0, 0x22, 0xf4, 0x87, 0xed, 0xab, 0xc1, 0xa6, 0xea, 0x06, 0x92, 0xe0, 0xda, 0x4f, + 0x7e, 0x7b, 0xaa, 0xbb, 0xac, 0x75, 0xbf, 0x3d, 0xd5, 0xda, 0x65, 0xa1, 0x31, 0x24, 0xc2, 0xae, 0x9f, 0xd2, 0x7f, + 0x5a, 0xac, 0xd7, 0x68, 0x0d, 0xc3, 0x7b, 0xcf, 0xbb, 0x71, 0xfc, 0xde, 0x5b, 0x28, 0x26, 0x70, 0x91, 0x7b, 0x95, + 0x4b, 0x4f, 0xc8, 0xab, 0x11, 0xbc, 0xe7, 0x5b, 0x43, 0x78, 0xcf, 0x03, 0xa7, 0x57, 0x90, 0x9a, 0x26, 0x82, 0x8d, + 0x3c, 0xfd, 0x44, 0x16, 0x09, 0x0d, 0x1f, 0xf7, 0x9a, 0x13, 0xa1, 0x3f, 0xa5, 0xc0, 0x7f, 0xe1, 0xe1, 0x42, 0x6b, + 0x29, 0x30, 0x17, 0xf3, 0x85, 0xc6, 0xca, 0x8c, 0x7e, 0x39, 0x96, 0x42, 0x37, 0xc7, 0x74, 0xc6, 0xf3, 0xbb, 0x74, + 0xc1, 0x9b, 0x33, 0x29, 0xa4, 0x9a, 0xd3, 0x8c, 0x61, 0x75, 0xa7, 0x34, 0x9b, 0x35, 0x17, 0x1c, 0x3f, 0x67, 0xf9, + 0x17, 0xa6, 0x79, 0x46, 0xf1, 0x5b, 0x39, 0x94, 0x5a, 0xe2, 0xd7, 0xb7, 0x77, 0x13, 0x26, 0xf0, 0xef, 0xc3, 0x85, + 0xd0, 0x0b, 0xac, 0xa8, 0x50, 0x4d, 0xc5, 0x0a, 0x3e, 0xee, 0x36, 0x9b, 0xf3, 0x82, 0xcf, 0x68, 0x71, 0xd7, 0xcc, + 0x64, 0x2e, 0x8b, 0xf4, 0xbf, 0x5a, 0xc7, 0xf4, 0xc1, 0xf8, 0xa4, 0xab, 0x0b, 0x2a, 0x14, 0x87, 0x85, 0x49, 0x69, + 0x9e, 0xef, 0x1d, 0x9f, 0xb6, 0x66, 0x6a, 0xdf, 0x5e, 0xf8, 0x51, 0xa1, 0xd7, 0x9f, 0xf0, 0x07, 0x09, 0xa3, 0x4c, + 0x86, 0x5a, 0xb8, 0x41, 0x2e, 0xb3, 0x45, 0xa1, 0x64, 0x91, 0xce, 0x25, 0x17, 0x9a, 0x15, 0xdd, 0xa1, 0x2c, 0x46, + 0xac, 0x68, 0x16, 0x74, 0xc4, 0x17, 0x2a, 0x3d, 0x99, 0xdf, 0x76, 0xeb, 0x3d, 0xd8, 0xfc, 0x54, 0x48, 0xc1, 0xba, + 0xc0, 0x6f, 0x4c, 0x0a, 0xb9, 0x10, 0x23, 0x37, 0x8c, 0x85, 0x50, 0x4c, 0x77, 0xe7, 0x74, 0x04, 0x76, 0xc0, 0xe9, + 0xf9, 0xfc, 0xb6, 0x6b, 0x66, 0x7d, 0xc3, 0xf8, 0x64, 0xaa, 0xd3, 0xd3, 0x56, 0xcb, 0x7e, 0x2b, 0xfe, 0x95, 0xa5, + 0xed, 0x4e, 0xd2, 0x39, 0x9d, 0xdf, 0x02, 0x07, 0xaf, 0x59, 0xd1, 0x04, 0x58, 0x40, 0xa5, 0x76, 0xd2, 0x7a, 0x70, + 0x7c, 0x1f, 0x32, 0xc0, 0xc6, 0xa1, 0x69, 0x26, 0x04, 0xc6, 0xee, 0xe9, 0x62, 0x3e, 0x67, 0x05, 0x78, 0xd1, 0x77, + 0x67, 0xb4, 0x98, 0x70, 0xd1, 0x2c, 0x4c, 0xa3, 0xcd, 0xf3, 0xf9, 0xed, 0x1a, 0xe6, 0x93, 0x5a, 0xb3, 0x55, 0x37, + 0x2d, 0xf7, 0xb5, 0x0c, 0x86, 0x68, 0x62, 0xd2, 0xa4, 0xc5, 0x64, 0x48, 0xe3, 0x76, 0xe7, 0x3e, 0xf6, 0xff, 0x4b, + 0x3a, 0x28, 0x00, 0x5b, 0x73, 0xb4, 0x28, 0xcc, 0x2d, 0x6a, 0xda, 0x56, 0xb6, 0xd9, 0xa9, 0xfc, 0xc2, 0x0a, 0xdf, + 0xaa, 0xf9, 0x58, 0x6e, 0xcd, 0xfb, 0x3f, 0x69, 0xf4, 0x13, 0x9e, 0x50, 0x58, 0x03, 0x83, 0x1c, 0x7d, 0x23, 0x0f, + 0xc2, 0x4c, 0x07, 0xcb, 0x1b, 0x3e, 0xd2, 0xd3, 0xb4, 0xdd, 0x6a, 0xfd, 0x50, 0xad, 0x58, 0x77, 0x6a, 0x41, 0xd7, + 0x2e, 0xd8, 0xac, 0xb6, 0x8e, 0x33, 0x5a, 0x62, 0xdb, 0x72, 0x2e, 0xdd, 0x92, 0x17, 0x2c, 0x37, 0xd1, 0x64, 0xd6, + 0x0e, 0xe5, 0xb6, 0xc6, 0xc9, 0xc5, 0x94, 0x15, 0x5c, 0x77, 0xeb, 0x5f, 0x55, 0xc7, 0xdb, 0xab, 0xbf, 0xb6, 0x72, + 0xe8, 0xd2, 0xd6, 0x70, 0x97, 0x9e, 0x8f, 0xe1, 0x63, 0x7b, 0xf5, 0xbf, 0xd0, 0x22, 0xde, 0x40, 0x4c, 0x1c, 0xd6, + 0x40, 0xeb, 0x60, 0xce, 0x05, 0x98, 0x64, 0x0e, 0xf0, 0x37, 0xa0, 0x90, 0xd1, 0x3c, 0x8b, 0x61, 0x44, 0x7b, 0xcd, + 0xbd, 0xe3, 0x82, 0xcd, 0x90, 0x07, 0x44, 0x72, 0xff, 0xb4, 0x60, 0xb3, 0x75, 0x62, 0xaa, 0x2f, 0x0d, 0x8a, 0xd0, + 0x9c, 0x4f, 0x44, 0x9a, 0x31, 0x40, 0xdf, 0x75, 0xc2, 0x84, 0xe6, 0xfa, 0xae, 0x59, 0xc8, 0x9b, 0xe5, 0x88, 0xab, + 0x79, 0x4e, 0xef, 0xd2, 0x71, 0xce, 0x6e, 0xbb, 0xa6, 0x54, 0x93, 0x6b, 0x36, 0x53, 0xae, 0x6c, 0x17, 0xd2, 0x9b, + 0x23, 0x6b, 0x36, 0x01, 0xd0, 0x93, 0x37, 0x9b, 0xfb, 0x27, 0x39, 0x56, 0x7b, 0x8c, 0x2a, 0xd6, 0x94, 0x0b, 0xbd, + 0xd7, 0x52, 0xdd, 0x19, 0x17, 0x4d, 0x37, 0x90, 0x93, 0xd6, 0xfc, 0xb6, 0xbb, 0x0d, 0xf9, 0xa0, 0xff, 0x84, 0xdd, + 0xce, 0xa9, 0x18, 0xb1, 0xd1, 0x32, 0xa8, 0xd6, 0x81, 0x7a, 0x61, 0xa9, 0x54, 0xe8, 0x69, 0xd3, 0xd8, 0x7a, 0xc5, + 0x1d, 0x81, 0xbe, 0x81, 0x5a, 0x0f, 0x5a, 0xd8, 0xfe, 0x7f, 0xd2, 0x46, 0x61, 0xe5, 0x3d, 0x08, 0xbb, 0xc4, 0xc7, + 0x77, 0x4d, 0xf8, 0xbb, 0x04, 0xdf, 0x22, 0x9e, 0xd1, 0xdc, 0x41, 0x64, 0xc6, 0x47, 0xa3, 0xbc, 0x36, 0xa2, 0xcb, + 0xa0, 0xb3, 0x36, 0x5a, 0xc2, 0xfc, 0xd3, 0xd6, 0x5e, 0x6b, 0xcf, 0xcc, 0xc5, 0x6d, 0xf3, 0x93, 0x93, 0xfb, 0xc7, + 0x0f, 0x58, 0x37, 0xe7, 0x82, 0xd5, 0xa6, 0xfa, 0x5d, 0x50, 0x87, 0x0d, 0x77, 0x5c, 0xc3, 0xed, 0xbd, 0xf6, 0xde, + 0x49, 0xeb, 0x07, 0xbf, 0x5b, 0x73, 0x36, 0xd6, 0x69, 0xfb, 0x6c, 0x7e, 0x5b, 0xdf, 0xbe, 0xe7, 0xbe, 0xe9, 0x9b, + 0x82, 0xce, 0x53, 0x21, 0xe1, 0x4f, 0x17, 0x36, 0xd9, 0x38, 0x97, 0x37, 0xe9, 0x94, 0x8f, 0x46, 0x4c, 0xd8, 0x02, + 0x65, 0x22, 0xcb, 0x73, 0x3e, 0x57, 0xdc, 0xae, 0x86, 0xc3, 0xdd, 0xd3, 0x0d, 0xa8, 0x86, 0x03, 0x3a, 0x0e, 0x06, + 0x74, 0x5a, 0x0d, 0xa8, 0xea, 0x3f, 0x1c, 0x61, 0x67, 0x63, 0xae, 0xa6, 0x54, 0xb7, 0x86, 0x49, 0x7f, 0x2f, 0x94, + 0x06, 0x98, 0x7b, 0x23, 0x0d, 0x43, 0xc5, 0x9b, 0x43, 0xa6, 0x6f, 0x18, 0x13, 0xdf, 0x1e, 0xc4, 0x65, 0x2a, 0x45, + 0x7e, 0x67, 0x3f, 0x97, 0x61, 0x97, 0x74, 0xa1, 0xe5, 0x3a, 0x19, 0x72, 0x41, 0x8b, 0xbb, 0x6b, 0xc5, 0x84, 0x92, + 0xc5, 0xb5, 0x1c, 0x8f, 0x97, 0xdf, 0x22, 0x2d, 0xf7, 0xd1, 0x3a, 0x51, 0x5c, 0x4c, 0x72, 0x66, 0x89, 0x92, 0x41, + 0x04, 0x47, 0xcc, 0x6d, 0xbb, 0xa6, 0xc9, 0xda, 0xa0, 0xd7, 0x49, 0x96, 0xf3, 0x19, 0xd5, 0xcc, 0xc0, 0x39, 0x20, + 0x35, 0x6e, 0xf2, 0x69, 0xbb, 0x35, 0xbf, 0xdd, 0x6b, 0xed, 0xd9, 0x3f, 0x55, 0x69, 0xd8, 0x46, 0x41, 0x61, 0xdf, + 0x24, 0x17, 0x06, 0x3f, 0x0c, 0x38, 0xcc, 0x2e, 0x32, 0xab, 0x67, 0xd6, 0x2e, 0x80, 0x1d, 0xcc, 0xae, 0xd6, 0xd4, + 0xa5, 0xa3, 0x4b, 0xb6, 0xc5, 0xd3, 0xd6, 0x0f, 0xf5, 0xdc, 0x9c, 0x0e, 0x59, 0xbe, 0xb4, 0x1b, 0xd5, 0x03, 0xd7, + 0x6d, 0xd5, 0x70, 0x99, 0x03, 0x92, 0x61, 0x40, 0x34, 0x48, 0xd3, 0xe6, 0x0d, 0x1b, 0x7e, 0xe6, 0xda, 0x6e, 0x99, + 0xa6, 0xba, 0x01, 0xe7, 0x1d, 0x33, 0xa6, 0x39, 0x2b, 0x96, 0xfe, 0x38, 0x6a, 0xd5, 0x08, 0xe8, 0x95, 0x30, 0x07, + 0xa1, 0xa6, 0xc3, 0x26, 0x84, 0x32, 0x63, 0xc5, 0x72, 0xd7, 0xe4, 0x66, 0xf4, 0xd6, 0xa1, 0xd8, 0x83, 0xd6, 0x0f, + 0xb5, 0xc3, 0xec, 0xa4, 0xd5, 0xf2, 0x07, 0x5d, 0xd3, 0xd6, 0x48, 0xdb, 0xc9, 0x29, 0x9b, 0x95, 0x89, 0x5a, 0xce, + 0xd3, 0x5a, 0xc2, 0x50, 0x6a, 0x2d, 0x67, 0x36, 0x6d, 0x07, 0x35, 0xaa, 0x93, 0xde, 0x76, 0x67, 0x7e, 0xbb, 0x67, + 0xfe, 0x69, 0xed, 0xb5, 0xb6, 0x49, 0xed, 0x36, 0x56, 0x1c, 0x23, 0x8f, 0xc7, 0xd0, 0x71, 0x9b, 0xcd, 0xba, 0x0b, + 0x05, 0xc7, 0xaa, 0x81, 0xb8, 0x39, 0xae, 0xd7, 0x66, 0xb2, 0x00, 0x58, 0xca, 0x05, 0x9c, 0x62, 0xf6, 0x24, 0x87, + 0x3e, 0x94, 0x04, 0xb3, 0xf3, 0x9d, 0x8d, 0xd6, 0x87, 0xd5, 0xda, 0xab, 0x06, 0x06, 0xff, 0xac, 0x3f, 0x55, 0x7c, + 0xf0, 0x0b, 0x16, 0xc8, 0x21, 0xbc, 0x91, 0x9c, 0xae, 0x5a, 0x4e, 0xf6, 0x18, 0xe9, 0x4a, 0x24, 0x32, 0x9e, 0x1b, + 0x33, 0x7a, 0x6b, 0x5d, 0x38, 0x66, 0x5c, 0x80, 0x81, 0x18, 0xc2, 0x3a, 0x30, 0xa5, 0x9f, 0x86, 0x0d, 0x8d, 0x74, + 0x0c, 0x0d, 0x1f, 0x76, 0x92, 0xd3, 0x53, 0x84, 0x5b, 0xb8, 0x73, 0x7a, 0x1a, 0xc8, 0x3e, 0x63, 0xbd, 0xab, 0xe8, + 0xae, 0x92, 0x72, 0x47, 0xc9, 0x23, 0xd3, 0xe8, 0x51, 0xbb, 0xd5, 0xc2, 0xc6, 0x4d, 0xbd, 0x2c, 0xcc, 0xd5, 0x8e, + 0x66, 0xdb, 0xad, 0x16, 0x34, 0x0b, 0x7f, 0xdc, 0xbc, 0x7e, 0x21, 0xcb, 0x56, 0xda, 0xc2, 0xed, 0xb4, 0x8d, 0x3b, + 0x69, 0x07, 0x1f, 0xa7, 0xc7, 0xf8, 0x24, 0x3d, 0xc1, 0xa7, 0xe9, 0x29, 0x3e, 0x4b, 0xcf, 0xf0, 0xfd, 0xf4, 0x3e, + 0x3e, 0x4f, 0xcf, 0xf1, 0x83, 0xf4, 0x01, 0x7e, 0x98, 0xb6, 0x5b, 0xf8, 0x51, 0xda, 0x6e, 0xe3, 0xc7, 0x69, 0xbb, + 0x83, 0x9f, 0xa4, 0xed, 0x63, 0xfc, 0x34, 0x6d, 0x9f, 0xe0, 0x67, 0x69, 0xfb, 0x14, 0x53, 0xc8, 0x1d, 0x42, 0x6e, + 0x06, 0xb9, 0x23, 0xc8, 0x65, 0x90, 0x3b, 0x4e, 0xdb, 0xa7, 0x6b, 0xac, 0x6c, 0x68, 0x8b, 0xa8, 0xd5, 0xee, 0x1c, + 0x9f, 0x9c, 0x9e, 0xdd, 0x3f, 0x7f, 0xf0, 0xf0, 0xd1, 0xe3, 0x27, 0x4f, 0x9f, 0x45, 0x03, 0x3c, 0x34, 0x1e, 0x26, + 0x4a, 0xf4, 0xf9, 0x41, 0xfb, 0x74, 0x80, 0xaf, 0xfd, 0x67, 0xcc, 0x0f, 0x3a, 0x27, 0x2d, 0x74, 0x79, 0x79, 0x32, + 0x68, 0x94, 0xb9, 0xef, 0x8d, 0x63, 0x4b, 0x95, 0x45, 0x08, 0x89, 0x21, 0x07, 0xe1, 0x3b, 0x53, 0xef, 0x3d, 0x8b, + 0x79, 0x52, 0xa0, 0x83, 0x03, 0xf3, 0x63, 0xe2, 0x7f, 0x0c, 0xfd, 0x0f, 0x1a, 0x2c, 0xd2, 0x2d, 0x8d, 0x9d, 0x67, + 0xb3, 0x2e, 0xfd, 0x0a, 0x4a, 0x93, 0x9d, 0x3d, 0xee, 0x8c, 0xe7, 0xff, 0x2b, 0xb2, 0xc6, 0x31, 0xe4, 0xc4, 0x2a, + 0xa0, 0x4e, 0x7b, 0x8c, 0x2c, 0x8b, 0xb4, 0x73, 0x7a, 0x7a, 0xf0, 0x4b, 0x9f, 0xf7, 0xdb, 0x83, 0xc1, 0x61, 0xfb, + 0x3e, 0x9e, 0x94, 0x09, 0x1d, 0x9b, 0x30, 0x2c, 0x13, 0x8e, 0x6d, 0x02, 0x4d, 0x6d, 0x6d, 0x48, 0x3a, 0x31, 0x49, + 0x50, 0x62, 0x9d, 0x9a, 0xb6, 0xef, 0xdb, 0xb6, 0x1f, 0x80, 0xd5, 0x96, 0x69, 0xde, 0x35, 0x7d, 0x71, 0x71, 0xb2, + 0x72, 0x8d, 0xe2, 0x49, 0xea, 0x5a, 0xf3, 0x89, 0x27, 0x83, 0x01, 0x1e, 0x9a, 0xc4, 0xd3, 0x2a, 0xf1, 0x6c, 0x30, + 0x70, 0x5d, 0x3d, 0x30, 0x5d, 0xdd, 0xaf, 0xb2, 0xce, 0x07, 0x03, 0xd3, 0x25, 0x72, 0x3e, 0xfa, 0x4a, 0xef, 0x7d, + 0x29, 0xf5, 0x24, 0xfc, 0xa2, 0x73, 0x7a, 0xda, 0x03, 0x0c, 0x33, 0xb6, 0xb7, 0x1e, 0x46, 0x37, 0x01, 0x8c, 0xee, + 0xe0, 0x77, 0x6f, 0x48, 0xd3, 0x6b, 0x5a, 0x02, 0xa9, 0x17, 0xfd, 0x57, 0xd4, 0xd0, 0x06, 0xe6, 0xe6, 0xcf, 0xc4, + 0xfe, 0x19, 0xa2, 0xc6, 0x17, 0x0a, 0xe0, 0x06, 0xcd, 0x8f, 0x57, 0xdd, 0x9a, 0x1e, 0x3f, 0x53, 0x70, 0xa5, 0x99, + 0xaa, 0x9c, 0xf6, 0x56, 0xd3, 0x9b, 0xe1, 0x6a, 0xaa, 0xbe, 0xa0, 0xbf, 0xe2, 0xbf, 0xd4, 0x61, 0xdc, 0x6f, 0x36, + 0x12, 0xf6, 0xd7, 0x08, 0x7c, 0x76, 0x7a, 0xe9, 0x88, 0x4d, 0x50, 0xaf, 0xff, 0x97, 0xc2, 0x83, 0x46, 0x90, 0xf1, + 0xc3, 0x76, 0x0a, 0x78, 0xf4, 0x6c, 0x26, 0xc6, 0x3f, 0xa0, 0x1e, 0xea, 0xfd, 0xa5, 0x0e, 0xff, 0x42, 0xf7, 0x8e, + 0xaa, 0xb9, 0xfc, 0x2e, 0xdd, 0x16, 0xae, 0xc2, 0xfc, 0x1c, 0x96, 0x5b, 0x98, 0xe1, 0x76, 0x93, 0x41, 0x50, 0x34, + 0x70, 0xf9, 0x26, 0xb1, 0x6c, 0xf0, 0xa3, 0xe3, 0x16, 0xfa, 0xa1, 0xdd, 0x01, 0x25, 0x46, 0x53, 0x1c, 0x6e, 0x6f, + 0xfa, 0xa2, 0x79, 0x8c, 0x1f, 0x34, 0x0b, 0xdc, 0x46, 0xb8, 0xd9, 0xf6, 0xda, 0xe5, 0xbe, 0x8a, 0x5b, 0x08, 0xab, + 0xf8, 0x1c, 0xfe, 0x39, 0x41, 0x83, 0x6a, 0x43, 0x5e, 0xd1, 0xcd, 0xde, 0xc1, 0x3f, 0x95, 0xc4, 0xaa, 0xc1, 0x8f, + 0xce, 0x5a, 0xe8, 0x87, 0x33, 0xd3, 0x11, 0x3b, 0xd4, 0x3b, 0xba, 0x92, 0xf8, 0xa4, 0x29, 0xa1, 0xa3, 0x56, 0xd9, + 0x8f, 0x88, 0x4f, 0x11, 0x16, 0xf1, 0x31, 0xfc, 0xd3, 0x0e, 0xfb, 0xf9, 0x75, 0xab, 0x1f, 0x33, 0xef, 0x36, 0x4e, + 0x4e, 0xad, 0xbb, 0xab, 0xb2, 0x77, 0xcf, 0x0d, 0x76, 0xd9, 0x36, 0x97, 0x66, 0xed, 0x23, 0xf8, 0x40, 0x58, 0x1f, + 0x12, 0x85, 0xd9, 0x21, 0xf8, 0xc9, 0x82, 0x79, 0x88, 0xba, 0x38, 0xee, 0xaa, 0x46, 0x03, 0x89, 0xbe, 0x1a, 0x1c, + 0x92, 0x76, 0x53, 0x37, 0x19, 0x86, 0xdf, 0x0d, 0x52, 0x06, 0x5f, 0x13, 0x55, 0xaf, 0x8f, 0x5d, 0xaf, 0xf6, 0x86, + 0xdd, 0x63, 0x07, 0x21, 0x44, 0xf5, 0x62, 0xdd, 0x64, 0xe8, 0x48, 0x34, 0x62, 0x7d, 0xc1, 0x7a, 0x67, 0x69, 0x0b, + 0x19, 0xec, 0x54, 0xbd, 0x98, 0x35, 0x39, 0xa4, 0x77, 0xd2, 0x98, 0x37, 0x35, 0xfc, 0x3a, 0x09, 0x66, 0x21, 0x00, + 0xef, 0x2a, 0xaf, 0x9f, 0xe2, 0xa8, 0x73, 0x7a, 0x8a, 0x05, 0xe1, 0xc9, 0xc4, 0xfc, 0x52, 0x84, 0x27, 0x43, 0xf3, + 0x4b, 0x92, 0x12, 0x5e, 0xb6, 0x77, 0x5c, 0x90, 0x60, 0x55, 0x4d, 0x0a, 0x85, 0x05, 0x2d, 0xd0, 0x51, 0xc7, 0x5f, + 0xbf, 0xe3, 0xa9, 0x9f, 0x03, 0xa8, 0x1b, 0x0a, 0x63, 0x79, 0x29, 0x9b, 0x05, 0xce, 0x09, 0xbd, 0x4c, 0x4e, 0x7b, + 0xd3, 0xa3, 0xb8, 0xd3, 0x94, 0xcd, 0x02, 0xa5, 0xd3, 0x23, 0x53, 0x13, 0x67, 0xe4, 0x31, 0xb5, 0xad, 0xe1, 0x29, + 0xdc, 0x99, 0x66, 0x24, 0x3b, 0x3c, 0x6b, 0x35, 0x92, 0x53, 0x84, 0xfb, 0xd9, 0xaa, 0x85, 0xf3, 0xd5, 0xaa, 0x85, + 0x69, 0xb0, 0x0c, 0x8f, 0x85, 0x07, 0x48, 0xa9, 0x11, 0xdb, 0x8c, 0x81, 0xd3, 0xe3, 0xb1, 0x86, 0xfb, 0x7f, 0x0d, + 0x5e, 0x35, 0x1a, 0xfc, 0x7d, 0x52, 0xee, 0x2e, 0xde, 0x90, 0x89, 0x02, 0x38, 0x0e, 0x75, 0x64, 0xaf, 0x85, 0x5f, + 0x57, 0x6f, 0xc1, 0x29, 0xe2, 0xdf, 0x25, 0xb6, 0x69, 0x41, 0x31, 0xba, 0x5d, 0xec, 0x57, 0xba, 0x55, 0xec, 0xcd, + 0x8e, 0x62, 0x57, 0xdb, 0xc5, 0x3e, 0xca, 0x40, 0xa3, 0xc7, 0x7f, 0x38, 0x3e, 0x6b, 0x35, 0x8e, 0x01, 0x59, 0x8f, + 0xcf, 0x5a, 0x55, 0xa1, 0x7b, 0xb4, 0x5a, 0x2b, 0x4d, 0x3e, 0x53, 0xeb, 0xd3, 0xc0, 0xbd, 0x73, 0xb5, 0x59, 0x38, + 0xeb, 0xda, 0x5d, 0xfa, 0x71, 0xf7, 0x4f, 0xc1, 0x66, 0x44, 0x18, 0x6a, 0xa7, 0xfb, 0x67, 0x83, 0xde, 0x94, 0xc5, + 0x0d, 0x48, 0x45, 0xe9, 0x58, 0xbb, 0x5f, 0xa8, 0xbc, 0x3a, 0xfe, 0x28, 0x21, 0xa9, 0x33, 0x40, 0x58, 0x92, 0x86, + 0xee, 0x1f, 0x0f, 0xcc, 0x79, 0x57, 0xc0, 0xef, 0x13, 0xf3, 0xbb, 0x54, 0xdc, 0x38, 0xc7, 0x87, 0xe9, 0xcd, 0x30, + 0xea, 0x09, 0xf2, 0x9a, 0xc6, 0xc6, 0x96, 0x1d, 0xa5, 0x65, 0x86, 0xfa, 0x02, 0x19, 0x6f, 0xca, 0x0c, 0x41, 0x5e, + 0x0b, 0xf7, 0x1b, 0x2f, 0x8b, 0x14, 0xec, 0x5a, 0xf0, 0x24, 0x05, 0x9b, 0x16, 0x3c, 0x4c, 0x05, 0xf8, 0x5d, 0xd0, + 0x94, 0x05, 0xd6, 0xf2, 0x0f, 0x9d, 0xa6, 0xcc, 0xdc, 0xee, 0x12, 0x83, 0xa5, 0x5d, 0x06, 0x27, 0xc5, 0x47, 0x19, + 0xc3, 0xdf, 0x86, 0x46, 0x98, 0x41, 0x9b, 0x0c, 0x61, 0x9e, 0x14, 0x04, 0xd2, 0x30, 0x4f, 0x26, 0x84, 0x41, 0x93, + 0x3c, 0x19, 0x12, 0xd6, 0xef, 0x04, 0x68, 0xf2, 0xd4, 0xc0, 0x0e, 0x80, 0xc3, 0xeb, 0x17, 0xe6, 0xda, 0x36, 0x0e, + 0x37, 0xf1, 0xd0, 0x84, 0x20, 0x5c, 0xc5, 0x30, 0x0b, 0xd8, 0x9c, 0xe6, 0x67, 0xa7, 0x0a, 0x33, 0xc9, 0x13, 0x6a, + 0xa8, 0xf7, 0x27, 0x20, 0xab, 0xf1, 0xbd, 0x25, 0x5b, 0xe3, 0xbd, 0x7b, 0x4b, 0xb1, 0xfe, 0x01, 0xfe, 0x28, 0xfb, + 0x07, 0x98, 0x87, 0x84, 0xa2, 0x35, 0xfa, 0x94, 0x42, 0xb1, 0x1d, 0xa5, 0xd0, 0x27, 0xef, 0x76, 0xa7, 0xc8, 0xf2, + 0x36, 0x8d, 0x46, 0xb4, 0xf8, 0x1c, 0xe1, 0x3f, 0xd3, 0x28, 0x07, 0x6e, 0x31, 0xc2, 0x1f, 0xd3, 0xa8, 0x60, 0x11, + 0xfe, 0x23, 0x8d, 0x86, 0xf9, 0x22, 0xc2, 0x1f, 0xd2, 0x68, 0x52, 0x44, 0xf8, 0x3d, 0x28, 0x45, 0x47, 0x7c, 0x31, + 0x8b, 0xf0, 0xef, 0x69, 0xa4, 0x8c, 0xd7, 0x01, 0x7e, 0x98, 0x46, 0x8c, 0x45, 0xf8, 0x5d, 0x1a, 0xc9, 0x3c, 0xc2, + 0x57, 0x69, 0x24, 0x8b, 0x08, 0x3f, 0x4a, 0xa3, 0x82, 0x46, 0xf8, 0x71, 0x1a, 0x41, 0xa1, 0x49, 0x84, 0x9f, 0xa4, + 0x11, 0xb4, 0xac, 0x22, 0xfc, 0x36, 0x8d, 0xb8, 0x88, 0xf0, 0x6f, 0x69, 0xa4, 0x17, 0xc5, 0x3f, 0x0b, 0xc9, 0x55, + 0x84, 0x9f, 0xa6, 0xd1, 0x94, 0x47, 0xf8, 0x4d, 0x1a, 0x15, 0x32, 0xc2, 0xaf, 0xd3, 0x88, 0xe6, 0x11, 0x7e, 0x95, + 0x46, 0x39, 0x8b, 0xf0, 0xaf, 0x69, 0x34, 0x62, 0x11, 0x7e, 0x99, 0x46, 0x77, 0x2c, 0xcf, 0x65, 0x84, 0x9f, 0xa5, + 0x11, 0x13, 0x11, 0xfe, 0x25, 0x8d, 0xb2, 0x69, 0x84, 0x7f, 0x4a, 0x23, 0x5a, 0x7c, 0x56, 0x11, 0x7e, 0x9e, 0x46, + 0x8c, 0x46, 0xf8, 0x85, 0xed, 0x68, 0x12, 0xe1, 0x9f, 0xd3, 0xe8, 0x66, 0x1a, 0xad, 0xb1, 0x52, 0x64, 0xf9, 0x9a, + 0x67, 0xec, 0x0f, 0x96, 0x46, 0xe3, 0xd6, 0xf8, 0x7c, 0x3c, 0x8e, 0x30, 0x15, 0x9a, 0xff, 0xb3, 0x60, 0x37, 0x4f, + 0x35, 0x24, 0x52, 0x36, 0x1c, 0xdd, 0x8f, 0x30, 0xfd, 0x67, 0x41, 0xd3, 0x68, 0x3c, 0x36, 0x05, 0xfe, 0x59, 0xd0, + 0x19, 0x2d, 0xde, 0xb2, 0x34, 0xba, 0x3f, 0x1e, 0x8f, 0x47, 0x27, 0x11, 0xa6, 0x5f, 0x17, 0x1f, 0x4d, 0x0b, 0xa6, + 0xc0, 0x90, 0xf1, 0x09, 0xd4, 0x3d, 0x1d, 0x9f, 0x8e, 0xb2, 0x08, 0x0f, 0xb9, 0xfa, 0x67, 0x01, 0xdf, 0x63, 0x76, + 0x92, 0x9d, 0x44, 0x78, 0x98, 0xd3, 0xec, 0x73, 0x1a, 0xb5, 0xcc, 0x2f, 0xf1, 0x0b, 0x1b, 0xbd, 0x9e, 0x49, 0x73, + 0x65, 0x30, 0x66, 0xc3, 0x6c, 0x14, 0x61, 0x33, 0x98, 0x31, 0xfc, 0xfd, 0xc2, 0xdf, 0x31, 0x9d, 0x46, 0xe7, 0xb4, + 0x33, 0x64, 0x9d, 0x08, 0x0f, 0xdf, 0xdc, 0x88, 0x34, 0xa2, 0xa7, 0x1d, 0xda, 0xa1, 0x11, 0x1e, 0x2e, 0x8a, 0xfc, + 0xee, 0x46, 0xca, 0x11, 0x00, 0x61, 0x78, 0x7e, 0x7e, 0x3f, 0xc2, 0x19, 0xfd, 0x55, 0x43, 0xed, 0xd3, 0xf1, 0x03, + 0x46, 0x5b, 0x11, 0xfe, 0x85, 0x16, 0xfa, 0xe3, 0x42, 0xb9, 0x81, 0xb6, 0x20, 0x45, 0x66, 0xef, 0x40, 0x9d, 0x1e, + 0x8d, 0x3a, 0x67, 0x0f, 0xda, 0x2c, 0xc2, 0xd9, 0xd5, 0x6b, 0xe8, 0xed, 0xfe, 0xf8, 0xb4, 0x05, 0x1f, 0x02, 0xe4, + 0x52, 0x56, 0x40, 0x23, 0x67, 0x27, 0x0f, 0x4e, 0xd9, 0xc8, 0x24, 0x2a, 0x9e, 0x7f, 0x36, 0xb3, 0x3f, 0x87, 0xf9, + 0x64, 0x05, 0x9f, 0x29, 0x29, 0xd2, 0x68, 0x94, 0xb5, 0x4f, 0x8e, 0x21, 0xe1, 0x8e, 0x0a, 0x0f, 0x9c, 0x5b, 0xa8, + 0x7a, 0x3e, 0x8c, 0xf0, 0xad, 0x4d, 0x3d, 0x1f, 0x9a, 0x8f, 0xc9, 0xbb, 0x5f, 0xc5, 0x9b, 0x51, 0x1a, 0x0d, 0xcf, + 0xcf, 0xcf, 0x5a, 0x90, 0xf0, 0x81, 0xde, 0xa5, 0x11, 0x7d, 0x00, 0xff, 0x41, 0xf6, 0xc7, 0x67, 0xd0, 0x21, 0x8c, + 0xf0, 0x76, 0xf2, 0x31, 0xcc, 0xf9, 0x3c, 0xa5, 0x9f, 0x79, 0x1a, 0x0d, 0x47, 0xc3, 0xfb, 0x67, 0x50, 0x6f, 0x46, + 0x27, 0xcf, 0x34, 0x85, 0x76, 0x5b, 0x2d, 0xd3, 0xf2, 0x3b, 0xfe, 0x85, 0x99, 0xea, 0xa7, 0xa7, 0x67, 0xc3, 0x0e, + 0x8c, 0xe0, 0x0a, 0x14, 0x2a, 0x30, 0x9e, 0xf3, 0xcc, 0x34, 0x78, 0x95, 0x3d, 0x1d, 0xa5, 0xd1, 0x83, 0x07, 0xc7, + 0x9d, 0x2c, 0x8b, 0xf0, 0xed, 0xc7, 0x91, 0xad, 0x6d, 0xf2, 0x14, 0xc0, 0x3e, 0x8d, 0xd8, 0x83, 0x07, 0x67, 0xf7, + 0x29, 0x7c, 0x3f, 0x37, 0x6d, 0x9d, 0x8f, 0x87, 0xd9, 0x39, 0xb4, 0xf5, 0x3b, 0x4c, 0xe7, 0xe4, 0xfc, 0x78, 0x64, + 0xfa, 0xfa, 0xdd, 0x8c, 0xba, 0x33, 0x3e, 0x19, 0x9f, 0x98, 0x4c, 0x33, 0xd4, 0xf2, 0xf3, 0x37, 0x96, 0x46, 0x19, + 0x1b, 0xb5, 0x23, 0x7c, 0xeb, 0x16, 0xee, 0xc1, 0x49, 0xab, 0x35, 0x3a, 0x8e, 0xf0, 0xe8, 0xe1, 0x7c, 0xfe, 0xd6, + 0x40, 0xb0, 0x7d, 0xf2, 0xc0, 0x7e, 0xab, 0xcf, 0x77, 0xd0, 0xf4, 0xd0, 0x00, 0x6d, 0xc4, 0x67, 0xa6, 0xe5, 0xb3, + 0x07, 0xf0, 0x9f, 0xf9, 0x36, 0x4d, 0x97, 0xdf, 0x72, 0x34, 0xb1, 0x8b, 0xd2, 0x66, 0x0f, 0x5a, 0x50, 0x63, 0xcc, + 0x3f, 0x0e, 0x0b, 0x0e, 0x68, 0x34, 0xec, 0xc0, 0xff, 0x45, 0x78, 0x9c, 0x5f, 0xbd, 0x76, 0x38, 0x3b, 0x1e, 0xd3, + 0x71, 0x2b, 0xc2, 0x63, 0xf9, 0x51, 0xe9, 0x0f, 0x0f, 0x45, 0x1a, 0x75, 0x3a, 0xe7, 0x43, 0x53, 0x66, 0xf1, 0x8b, + 0xe2, 0x06, 0x8f, 0x5b, 0xa6, 0x95, 0x09, 0x7d, 0xab, 0x86, 0x57, 0x12, 0x56, 0x12, 0xfe, 0x8b, 0xf0, 0x04, 0xb4, + 0x70, 0xae, 0x95, 0x73, 0xbb, 0x1d, 0x26, 0xef, 0x0c, 0x6a, 0x8e, 0xee, 0x03, 0xbc, 0xfc, 0x32, 0x8e, 0x28, 0x3d, + 0xed, 0xb4, 0x22, 0x6c, 0x46, 0x7d, 0xde, 0x82, 0xff, 0x22, 0x6c, 0x21, 0x67, 0xe0, 0x3a, 0xf9, 0xf8, 0xec, 0xe5, + 0x4d, 0x1a, 0xd1, 0xd1, 0x78, 0x0c, 0x4b, 0x62, 0x26, 0xe3, 0x8b, 0x4d, 0xa5, 0x60, 0x77, 0xbf, 0xde, 0xb8, 0xed, + 0x62, 0x12, 0xb4, 0x83, 0xce, 0xd9, 0x83, 0xe1, 0x49, 0x84, 0xdf, 0x8e, 0x38, 0x15, 0xb0, 0x4a, 0xd9, 0xe8, 0x34, + 0x3b, 0xcd, 0x4c, 0xc2, 0x44, 0xa6, 0xd1, 0x09, 0x2c, 0x79, 0x27, 0xc2, 0xfc, 0xcb, 0xd5, 0x9d, 0x45, 0x37, 0xa8, + 0xed, 0x10, 0x64, 0xdc, 0x62, 0x67, 0xe7, 0x59, 0x84, 0x73, 0xfa, 0xe5, 0xd9, 0xaf, 0x45, 0x1a, 0xb1, 0x33, 0x76, + 0x36, 0xa6, 0xfe, 0xfb, 0x0f, 0x35, 0x35, 0x35, 0x5a, 0xe3, 0x53, 0x48, 0xba, 0x11, 0x66, 0xac, 0xf7, 0xb3, 0xb1, + 0xc1, 0x90, 0x57, 0x33, 0x29, 0xb2, 0xa7, 0xe3, 0xb1, 0xb4, 0x58, 0x4c, 0x61, 0x13, 0xfe, 0x09, 0xd0, 0xa6, 0xa3, + 0xd1, 0x39, 0x3b, 0x8b, 0xf0, 0x9f, 0x76, 0x97, 0xb8, 0x09, 0xfc, 0x69, 0x31, 0x9b, 0xb9, 0xdd, 0xfe, 0xa7, 0x05, + 0x0a, 0xcc, 0x77, 0x4c, 0xc7, 0x74, 0xd4, 0x89, 0xf0, 0x9f, 0x06, 0x2e, 0xa3, 0x63, 0xf8, 0x0f, 0x0a, 0x40, 0x67, + 0x0f, 0x5a, 0x8c, 0x3d, 0x68, 0x99, 0xaf, 0x30, 0xcf, 0xcd, 0x7c, 0x78, 0x96, 0xb5, 0x23, 0xfc, 0xa7, 0x43, 0xc7, + 0xf1, 0x98, 0xb6, 0x00, 0x1d, 0xff, 0x74, 0xe8, 0xd8, 0x69, 0x0d, 0x3b, 0xd4, 0x7c, 0x5b, 0xac, 0x39, 0xbf, 0x9f, + 0x31, 0x98, 0xdc, 0x9f, 0x16, 0x21, 0xef, 0xdf, 0x3f, 0x3f, 0x7f, 0xf0, 0x00, 0x3e, 0x4d, 0xdb, 0xe5, 0xa7, 0xd2, + 0x0f, 0x73, 0x83, 0x64, 0xad, 0xec, 0x04, 0xe8, 0xe4, 0x9f, 0x66, 0x8c, 0xe3, 0xf1, 0x98, 0xb5, 0x22, 0x9c, 0xf3, + 0x19, 0xb3, 0x98, 0x60, 0x7f, 0x9b, 0x8e, 0x8e, 0x3b, 0xd9, 0xe8, 0xb8, 0x13, 0xe1, 0xfc, 0xed, 0x33, 0x33, 0x9b, + 0x16, 0xcc, 0xde, 0x6f, 0x39, 0x8f, 0x35, 0x33, 0xfa, 0x06, 0x06, 0x09, 0x2b, 0x0d, 0x95, 0xdf, 0x07, 0xf4, 0xf0, + 0xec, 0x2c, 0x1b, 0xc1, 0x40, 0xdf, 0x43, 0xb7, 0x00, 0xc6, 0xf7, 0x76, 0xf3, 0x0d, 0xe9, 0xe9, 0x29, 0x4c, 0xf7, + 0xfd, 0x7c, 0x51, 0xcc, 0x5f, 0xa5, 0xd1, 0x83, 0xe3, 0xfb, 0xad, 0xd1, 0x30, 0xc2, 0xef, 0xdd, 0x04, 0x8f, 0xb3, + 0xe1, 0xf1, 0xfd, 0x76, 0x84, 0xdf, 0x9b, 0xfd, 0x76, 0x7f, 0x78, 0x76, 0x0e, 0xe7, 0xc6, 0x7b, 0x35, 0x2f, 0xde, + 0x4e, 0x4c, 0x81, 0x31, 0x7d, 0x00, 0xcd, 0xfe, 0x66, 0x76, 0xe3, 0xa8, 0x0d, 0x1b, 0xf9, 0xbd, 0xd9, 0x64, 0x06, + 0x4f, 0xee, 0xb7, 0x4f, 0xcf, 0x4f, 0x23, 0x3c, 0xe3, 0x23, 0x01, 0x04, 0xde, 0x6c, 0x94, 0x07, 0xed, 0x07, 0xf7, + 0x5b, 0x11, 0x9e, 0xbd, 0xd5, 0xd9, 0x47, 0x3a, 0x33, 0xd4, 0x78, 0x0c, 0x30, 0x9b, 0x71, 0xa5, 0xef, 0xde, 0x28, + 0x47, 0x8f, 0x59, 0x3b, 0xc2, 0x33, 0x99, 0x65, 0x54, 0xbd, 0xb5, 0x09, 0xc3, 0xd3, 0x08, 0x0b, 0xfa, 0x85, 0xfe, + 0x2d, 0xfd, 0x66, 0x1a, 0x31, 0x3a, 0x32, 0x69, 0x06, 0x87, 0x23, 0xfc, 0x6e, 0x04, 0x97, 0x7e, 0x69, 0x34, 0x1e, + 0x8d, 0x4f, 0x01, 0x3c, 0x40, 0x80, 0x2c, 0x76, 0x03, 0x34, 0xe0, 0x6b, 0xf4, 0x68, 0x98, 0x46, 0x67, 0xc3, 0x73, + 0xd6, 0x39, 0x8e, 0x70, 0x49, 0x8d, 0xe8, 0x29, 0xe4, 0x9b, 0xcf, 0x8f, 0x66, 0x4b, 0x9d, 0xd8, 0x04, 0x03, 0xa0, + 0x11, 0xbd, 0xdf, 0x1a, 0x9d, 0x45, 0x78, 0xfe, 0x9a, 0xf9, 0x3d, 0xc6, 0x18, 0x3b, 0x07, 0x58, 0x42, 0x92, 0x41, + 0xa0, 0xf3, 0xf1, 0xf0, 0xc1, 0xb9, 0xf9, 0x06, 0x30, 0xd0, 0x31, 0x63, 0x00, 0xa4, 0xf9, 0x6b, 0x56, 0x02, 0x62, + 0x34, 0xbc, 0xdf, 0x02, 0xfa, 0x32, 0xa7, 0x73, 0x7a, 0x47, 0x6f, 0x9e, 0xce, 0xcd, 0x9c, 0xc6, 0xa3, 0xd3, 0x08, + 0xcf, 0x9f, 0xff, 0x32, 0x5f, 0x8c, 0xc7, 0x66, 0x42, 0x74, 0xf8, 0x20, 0xc2, 0x73, 0x56, 0x2c, 0x60, 0x8d, 0xce, + 0x4f, 0x8f, 0xc7, 0x11, 0x76, 0x68, 0x98, 0xb5, 0xb2, 0x21, 0xdc, 0x6a, 0x2e, 0x66, 0x69, 0x34, 0x1a, 0xd1, 0xd6, + 0x08, 0xee, 0x38, 0xe5, 0xcd, 0xaf, 0x85, 0x45, 0x23, 0x66, 0xf0, 0xc1, 0xad, 0x21, 0xcc, 0x17, 0xe0, 0xf1, 0x71, + 0xc8, 0xb2, 0x8c, 0xba, 0xc4, 0xb3, 0xb3, 0xe3, 0x63, 0xc0, 0x3d, 0x3b, 0x43, 0x8b, 0x20, 0x6f, 0xd4, 0xdd, 0xb0, + 0x90, 0x70, 0x74, 0x01, 0x51, 0x05, 0xb2, 0xfa, 0xe6, 0xee, 0xb5, 0xa1, 0xab, 0xed, 0xb3, 0x07, 0xb0, 0x00, 0x8a, + 0x8e, 0x46, 0xaf, 0xec, 0xe1, 0x76, 0x3e, 0x3c, 0x39, 0x6d, 0x1f, 0x47, 0xd8, 0x6f, 0x04, 0x7a, 0xde, 0xba, 0xdf, + 0x81, 0x12, 0x62, 0x74, 0x67, 0x4b, 0x8c, 0x4f, 0xe8, 0xc9, 0x59, 0x2b, 0xc2, 0x7e, 0x6b, 0xb0, 0xf3, 0xe1, 0xe9, + 0x7d, 0xf8, 0x54, 0x53, 0x96, 0xe7, 0x06, 0xbf, 0x4f, 0x01, 0x2e, 0x8a, 0x3f, 0x13, 0x34, 0x8d, 0x68, 0xeb, 0xb4, + 0xd3, 0x19, 0xc1, 0x67, 0xfe, 0x85, 0x15, 0x69, 0x94, 0xb5, 0xe0, 0xbf, 0x08, 0x07, 0x3b, 0x89, 0x0d, 0x23, 0x6c, + 0xf0, 0xee, 0x8c, 0x9e, 0x9a, 0xbd, 0xef, 0x76, 0x55, 0xeb, 0xbc, 0x05, 0x1b, 0xd6, 0x6d, 0x2a, 0xf7, 0xa5, 0x84, + 0xbc, 0x71, 0x24, 0x96, 0x46, 0x38, 0x40, 0xd0, 0xf1, 0xfd, 0x71, 0x84, 0xfd, 0x8e, 0x3b, 0x39, 0x3b, 0xef, 0x00, + 0x29, 0xd3, 0x40, 0x28, 0x46, 0x9d, 0xe1, 0x09, 0x90, 0x26, 0xcd, 0x5e, 0x5b, 0x3c, 0x89, 0xb0, 0x7e, 0xaa, 0xf4, + 0xab, 0x34, 0x1a, 0x9d, 0x0f, 0xc7, 0xa3, 0xf3, 0x08, 0x6b, 0x39, 0xa3, 0x5a, 0x1a, 0x0a, 0x78, 0x7c, 0x72, 0x3f, + 0xc2, 0x06, 0xcd, 0x5b, 0xac, 0x35, 0x6a, 0x45, 0xd8, 0x1d, 0x25, 0x8c, 0x9d, 0x77, 0x60, 0x5a, 0x3f, 0x3f, 0xd7, + 0x80, 0xcb, 0x23, 0x36, 0x3c, 0x8e, 0x70, 0x49, 0xef, 0x0d, 0x21, 0x82, 0x2f, 0x35, 0x93, 0x9f, 0x1d, 0xeb, 0x01, + 0xa4, 0xce, 0x6f, 0x78, 0x58, 0x86, 0x97, 0x37, 0x16, 0x8d, 0xa8, 0xd9, 0xe2, 0xc1, 0xad, 0xef, 0x13, 0x1a, 0x7b, + 0xb6, 0x9d, 0x93, 0xe5, 0x1a, 0x97, 0xc1, 0x54, 0x3f, 0xb3, 0x3b, 0x15, 0x2b, 0x65, 0x38, 0xd9, 0x20, 0x05, 0x1c, + 0x1e, 0x9c, 0xfb, 0x80, 0xf3, 0x10, 0x05, 0x41, 0x52, 0x90, 0x56, 0x57, 0x5c, 0x78, 0xaf, 0xd5, 0xae, 0x80, 0x10, + 0x0b, 0x90, 0x5e, 0x10, 0x4a, 0x34, 0x44, 0xa2, 0xb1, 0xc2, 0xa4, 0x37, 0xe6, 0x37, 0x32, 0xa5, 0xb4, 0xee, 0x01, + 0x94, 0x50, 0x1f, 0x83, 0x1e, 0xae, 0xa4, 0x21, 0x4a, 0x13, 0xea, 0x4a, 0x62, 0x22, 0x4a, 0xbf, 0x10, 0x3a, 0x56, + 0xaa, 0x5f, 0x0c, 0x70, 0xfb, 0x0c, 0x61, 0x88, 0xd5, 0x40, 0xfa, 0xf2, 0xf2, 0xb2, 0x7d, 0x76, 0x60, 0x84, 0xbe, + 0xcb, 0xcb, 0x73, 0xfb, 0x03, 0xfe, 0x1d, 0x54, 0xf1, 0xb1, 0x61, 0x7c, 0x8f, 0x58, 0xa0, 0xd1, 0x33, 0xfc, 0xf5, + 0x23, 0xb6, 0x5a, 0xc5, 0x8f, 0x18, 0x81, 0x19, 0xe3, 0x47, 0x2c, 0x31, 0x77, 0x24, 0xd6, 0x13, 0x87, 0xf4, 0x41, + 0x73, 0xd6, 0xc2, 0x10, 0xb5, 0xdd, 0x73, 0xde, 0x8f, 0x58, 0x9f, 0xd7, 0xbd, 0xb8, 0xab, 0x50, 0xc9, 0x07, 0x07, + 0xcb, 0x22, 0xd5, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, 0x56, 0x4c, 0xd0, 0x55, 0xb0, 0xfa, 0x93, 0x1e, 0x48, 0x29, + 0x46, 0xd9, 0xe2, 0x78, 0xea, 0x77, 0xa0, 0xf6, 0x00, 0xed, 0x64, 0xaf, 0x52, 0x76, 0x94, 0xba, 0x8a, 0x9d, 0x0a, + 0x8c, 0x9d, 0x89, 0x4e, 0xdb, 0x71, 0xf4, 0xef, 0xa8, 0x3b, 0x5e, 0xd6, 0xc4, 0xb2, 0x77, 0x3b, 0xc5, 0x32, 0x58, + 0x49, 0x23, 0x9a, 0xed, 0xdb, 0xb8, 0x1f, 0xba, 0x7f, 0xdf, 0x08, 0x66, 0x55, 0x30, 0xba, 0x06, 0x24, 0x75, 0x41, + 0x0a, 0x39, 0x37, 0x52, 0x5a, 0x81, 0xd2, 0x91, 0x8e, 0x0b, 0xd0, 0x50, 0x7a, 0x05, 0x65, 0x19, 0x33, 0xb5, 0x61, + 0x00, 0xa2, 0xac, 0x8c, 0x66, 0x65, 0xb5, 0x53, 0x10, 0x5d, 0x40, 0x13, 0x66, 0x24, 0x16, 0x68, 0x40, 0x98, 0x06, + 0x84, 0xab, 0x0c, 0xe2, 0x8c, 0xcb, 0x3e, 0x31, 0xd9, 0xca, 0x64, 0xab, 0x32, 0x5b, 0xfa, 0x6c, 0x2b, 0x24, 0x4a, + 0x93, 0x2d, 0xcb, 0x6c, 0x90, 0xd9, 0xf0, 0x24, 0x55, 0x78, 0x98, 0x4a, 0x2b, 0xaa, 0x55, 0xb2, 0xd5, 0x5b, 0x1a, + 0x6a, 0x73, 0x0f, 0x0e, 0xe2, 0x52, 0x4e, 0x32, 0x6a, 0xe2, 0x7b, 0x4b, 0x9e, 0x14, 0x46, 0x06, 0xe2, 0xc9, 0xc4, + 0xfd, 0x1d, 0xae, 0x37, 0x65, 0xa5, 0x62, 0x32, 0xfc, 0x46, 0x49, 0xf4, 0xc9, 0x2b, 0x51, 0x1f, 0x71, 0x13, 0x6d, + 0xe7, 0x82, 0x24, 0xad, 0xd6, 0x71, 0xfb, 0xb8, 0x75, 0xde, 0xe3, 0x87, 0xed, 0x4e, 0xf2, 0xa0, 0x93, 0x1a, 0x45, + 0xc4, 0x5c, 0xde, 0x80, 0x02, 0xe6, 0xa8, 0x93, 0x9c, 0xa0, 0xc3, 0x76, 0xd2, 0x3a, 0x3d, 0x6d, 0xc2, 0x3f, 0xf8, + 0xbd, 0x2e, 0xab, 0x9d, 0xb4, 0x4e, 0x4e, 0x7b, 0xfc, 0x68, 0xa3, 0x52, 0xcc, 0x1b, 0x50, 0x10, 0x1d, 0x99, 0x4a, + 0x18, 0xea, 0x57, 0xcb, 0xfb, 0x6c, 0x4b, 0xcf, 0xf3, 0x5e, 0xc7, 0xd2, 0xaa, 0xe2, 0x00, 0xaa, 0xfe, 0x6b, 0x62, + 0x80, 0xe8, 0xbf, 0x86, 0x65, 0x44, 0xdc, 0x65, 0x01, 0xa2, 0xf6, 0x23, 0x1e, 0x8b, 0x06, 0x3b, 0x8c, 0x6d, 0xbe, + 0x86, 0xba, 0x4d, 0x88, 0x52, 0x87, 0x27, 0x2e, 0x57, 0x85, 0xb9, 0x13, 0x84, 0x9a, 0x0a, 0x72, 0x87, 0x2e, 0x57, + 0x86, 0xb9, 0x43, 0x84, 0x9a, 0x12, 0x72, 0x69, 0xca, 0x13, 0x0a, 0x39, 0x3a, 0xa1, 0x4d, 0x03, 0xc9, 0x6a, 0x51, + 0x9e, 0x33, 0x3f, 0x6c, 0x3e, 0x86, 0xe5, 0x31, 0x04, 0xc5, 0x09, 0xd2, 0x02, 0x5e, 0x32, 0x29, 0xb5, 0x39, 0x2d, + 0x5c, 0xaa, 0x71, 0x20, 0xa3, 0x01, 0xff, 0x1c, 0x32, 0xf3, 0xbc, 0x45, 0xab, 0x77, 0x7c, 0xd6, 0x4a, 0xdb, 0xe0, + 0x92, 0x0d, 0xb2, 0xb6, 0xb0, 0xb2, 0xb6, 0xf0, 0xb2, 0xb6, 0xf0, 0xb2, 0x36, 0x08, 0xf0, 0x41, 0xdf, 0xff, 0xc8, + 0x9a, 0x99, 0x0b, 0x2f, 0x6d, 0x66, 0xac, 0x51, 0x44, 0xac, 0x57, 0xab, 0xe5, 0x1a, 0x2c, 0x9a, 0x2a, 0x95, 0xbb, + 0xaa, 0xd4, 0x9f, 0xcb, 0x22, 0x6d, 0xe1, 0x49, 0x0a, 0x5a, 0xee, 0x16, 0xa6, 0x66, 0x73, 0x7b, 0xaa, 0xb0, 0x19, + 0x2d, 0xa7, 0xe7, 0xd5, 0xc9, 0x97, 0xe4, 0xd8, 0x68, 0x8f, 0x97, 0x45, 0xca, 0x2d, 0xcd, 0xe0, 0x96, 0x66, 0x70, + 0x4b, 0x33, 0xa0, 0x11, 0x5c, 0x16, 0x36, 0x65, 0x13, 0x4a, 0xe0, 0x4a, 0xa0, 0x7f, 0x3c, 0x80, 0x60, 0x81, 0xb1, + 0x26, 0x66, 0xd4, 0x1b, 0x9d, 0xb7, 0x21, 0x38, 0x9a, 0x2d, 0xa9, 0x13, 0x6a, 0x7c, 0xc4, 0xcb, 0x31, 0x7f, 0xad, + 0xa1, 0x7d, 0x02, 0x2f, 0xd7, 0x3c, 0xd4, 0x71, 0x0b, 0x4c, 0x44, 0xa2, 0x22, 0xea, 0x19, 0xb2, 0x90, 0x1a, 0x9d, + 0x8d, 0x33, 0xfd, 0xfe, 0xbc, 0xe1, 0x71, 0x6b, 0x29, 0x41, 0xf8, 0x5e, 0xc3, 0x67, 0x56, 0x85, 0x00, 0x28, 0x2d, + 0x5b, 0x9d, 0x59, 0x9a, 0x3d, 0x12, 0xba, 0x60, 0x9e, 0xee, 0x63, 0x4b, 0xf5, 0x04, 0x91, 0xca, 0x38, 0x47, 0x92, + 0x2a, 0x3a, 0x32, 0x38, 0x0b, 0x93, 0x5b, 0x6a, 0x5c, 0x67, 0x5e, 0xd8, 0x3f, 0x5f, 0x69, 0xe0, 0x5b, 0x58, 0x4c, + 0x86, 0xde, 0x25, 0xf7, 0xda, 0xc4, 0x10, 0x22, 0xfb, 0xfb, 0xd6, 0x72, 0xdc, 0x7c, 0x6d, 0x9a, 0x8e, 0x9b, 0x44, + 0x93, 0x0d, 0x3b, 0xd4, 0xaf, 0xd1, 0x3f, 0xde, 0x33, 0xae, 0x98, 0x0c, 0x51, 0x40, 0xb3, 0x0d, 0x58, 0x65, 0x05, + 0x2c, 0xe5, 0xea, 0x95, 0x0e, 0x93, 0xd0, 0xbb, 0x19, 0xf3, 0xba, 0x98, 0x0c, 0x77, 0x3e, 0x71, 0x62, 0x7b, 0xec, + 0xbd, 0xa5, 0x41, 0x0f, 0x5e, 0xb5, 0x3d, 0x65, 0xb7, 0xdf, 0xab, 0x73, 0xb3, 0xb3, 0x8e, 0xca, 0xbf, 0x57, 0xe7, + 0xe9, 0xae, 0x3a, 0x33, 0x7e, 0x1b, 0xfb, 0xbd, 0xa3, 0x03, 0x35, 0xb6, 0x31, 0x47, 0x9a, 0x0c, 0x21, 0x26, 0x3d, + 0xfc, 0xb5, 0x91, 0x63, 0xba, 0x9e, 0x84, 0xc3, 0x2a, 0xc8, 0x5e, 0x72, 0x9a, 0x32, 0x4c, 0x49, 0xe7, 0xb0, 0x30, + 0xb1, 0x63, 0x44, 0x42, 0x9b, 0x2a, 0xa1, 0x38, 0x27, 0x71, 0x4c, 0x0f, 0x33, 0x88, 0x80, 0xd3, 0xee, 0xd1, 0x34, + 0xa6, 0x8d, 0x0c, 0x1d, 0xc5, 0xed, 0x06, 0x3d, 0xcc, 0x10, 0x6a, 0xb4, 0x41, 0x67, 0x2a, 0x49, 0xbb, 0x99, 0x43, + 0x4c, 0x4c, 0x43, 0x8a, 0xf3, 0x43, 0x91, 0x14, 0x0d, 0x79, 0xa8, 0x92, 0xa2, 0x91, 0x9c, 0x62, 0x91, 0x4c, 0xca, + 0xe4, 0x89, 0x49, 0x9e, 0xd8, 0xe4, 0x61, 0x99, 0x3c, 0x34, 0xc9, 0x43, 0x9b, 0x4c, 0x49, 0x71, 0x28, 0x12, 0xda, + 0x88, 0xdb, 0xcd, 0x02, 0x1d, 0xc2, 0x08, 0xfc, 0xe8, 0x89, 0x08, 0x43, 0x91, 0xaf, 0x8d, 0x2d, 0xcf, 0x5c, 0xe6, + 0x2e, 0x38, 0x68, 0x05, 0xa4, 0xd2, 0xc1, 0x0a, 0xea, 0x3c, 0x0b, 0xc0, 0x84, 0xb5, 0xfd, 0xe3, 0x43, 0xdf, 0xad, + 0xb3, 0x5c, 0x8a, 0xc0, 0x81, 0x0c, 0x6c, 0xde, 0x3f, 0x3b, 0xb7, 0x19, 0x80, 0xea, 0x9a, 0xe6, 0xf3, 0x29, 0xdd, + 0xf2, 0xd2, 0x2d, 0x26, 0x43, 0xb7, 0xb3, 0xca, 0x66, 0x18, 0x2d, 0x6c, 0x48, 0xe9, 0xba, 0x3f, 0x25, 0x80, 0xda, + 0xfb, 0x70, 0x26, 0xd4, 0x28, 0xc9, 0x6d, 0x8d, 0x49, 0xc1, 0xee, 0x54, 0x46, 0x73, 0x16, 0x57, 0x07, 0x70, 0x35, + 0x4c, 0x46, 0x5e, 0x80, 0xe5, 0x7d, 0x71, 0x98, 0x1c, 0x37, 0x74, 0x32, 0x39, 0x4c, 0x4e, 0x1f, 0x34, 0x74, 0x32, + 0x3c, 0x4c, 0xda, 0xed, 0x0a, 0x67, 0x93, 0x82, 0xe8, 0x64, 0x42, 0x34, 0x68, 0x0c, 0x6d, 0xa3, 0x72, 0x4e, 0xc1, + 0x94, 0xec, 0xdf, 0x18, 0x46, 0xc3, 0x0d, 0x43, 0xb0, 0x89, 0x8d, 0xae, 0xb9, 0x35, 0x86, 0xb0, 0x9b, 0xce, 0xe9, + 0x69, 0x53, 0x27, 0x05, 0xd6, 0x76, 0x25, 0x9b, 0x3a, 0x99, 0x60, 0x6d, 0x97, 0xaf, 0xa9, 0x93, 0xa1, 0x6d, 0xca, + 0xe8, 0x00, 0x99, 0x08, 0x80, 0xf5, 0x9c, 0x05, 0x90, 0xef, 0x78, 0x67, 0x98, 0x35, 0x68, 0x0d, 0xbf, 0x57, 0xae, + 0xe9, 0x0b, 0x2a, 0xaa, 0xc1, 0xa4, 0x88, 0x7d, 0xab, 0x68, 0xbb, 0x6a, 0x92, 0xfd, 0xeb, 0xb2, 0x65, 0xb3, 0x85, + 0xd4, 0xf5, 0x82, 0x0f, 0x6b, 0x18, 0xe2, 0x4a, 0xb9, 0x83, 0xfb, 0x15, 0x25, 0x31, 0xc4, 0xd0, 0x33, 0xa7, 0x10, + 0x27, 0x5e, 0x8f, 0x0c, 0x49, 0xbc, 0xd1, 0x58, 0xa3, 0x38, 0x38, 0x6f, 0x9f, 0x86, 0x54, 0x75, 0x2b, 0xb0, 0x1e, + 0x21, 0xd1, 0x42, 0x58, 0xd3, 0xcb, 0x51, 0x14, 0xb0, 0x20, 0x4e, 0xbb, 0x5b, 0x3b, 0x20, 0x0e, 0x0e, 0x36, 0xcf, + 0x0b, 0xff, 0xc4, 0xc1, 0xd6, 0xb3, 0x06, 0x95, 0xdd, 0x9e, 0x7f, 0x78, 0xc9, 0x5a, 0xf4, 0xf2, 0x00, 0x51, 0x7c, + 0x88, 0xab, 0xfb, 0x86, 0xc2, 0xf7, 0xab, 0xf8, 0x7e, 0x2e, 0xa7, 0x79, 0x66, 0x32, 0x4c, 0x5f, 0x83, 0x60, 0x6c, + 0x6f, 0xc2, 0x09, 0x95, 0x36, 0x89, 0xff, 0xb2, 0xe3, 0xa0, 0x13, 0xf7, 0x30, 0x4c, 0xd8, 0xe8, 0xdf, 0xa1, 0x05, + 0x70, 0x05, 0x1b, 0xe7, 0xfb, 0xbd, 0x5a, 0xd5, 0x9e, 0x01, 0xb2, 0x8f, 0xcd, 0xa0, 0x83, 0x03, 0xae, 0x9e, 0x81, + 0xd1, 0x32, 0x8b, 0x1b, 0xe1, 0xe1, 0xfb, 0x4f, 0xed, 0xb4, 0xfe, 0xdb, 0x9c, 0xab, 0x69, 0x70, 0xd0, 0x3d, 0xac, + 0xe5, 0xef, 0x5c, 0x89, 0x9e, 0x4e, 0xb9, 0x5b, 0xeb, 0xbf, 0x2b, 0x93, 0xf0, 0xad, 0x07, 0xa9, 0x0e, 0x0e, 0x78, + 0x15, 0x16, 0x2a, 0xfa, 0x21, 0x42, 0x3d, 0x23, 0x83, 0x3c, 0xcb, 0x25, 0x85, 0x1b, 0x51, 0xb8, 0x62, 0x48, 0x1b, + 0xfc, 0x48, 0xe3, 0x3f, 0xe4, 0xff, 0xa7, 0x46, 0x0e, 0x75, 0xda, 0xe0, 0x81, 0x00, 0x16, 0xb2, 0x42, 0x55, 0x40, + 0x46, 0x03, 0xe9, 0xd0, 0xc2, 0x1b, 0x95, 0x87, 0x39, 0x9d, 0xcf, 0xf3, 0x3b, 0xf3, 0x26, 0x57, 0xc0, 0x51, 0x55, + 0x17, 0x4d, 0x2e, 0x1a, 0x1e, 0x2e, 0x80, 0xa7, 0x07, 0xdc, 0x43, 0xc6, 0x9b, 0xb5, 0xbc, 0xdc, 0x16, 0x08, 0x24, + 0x33, 0x45, 0x64, 0xb3, 0xdd, 0x55, 0x97, 0x20, 0x97, 0x35, 0x9b, 0x48, 0xbb, 0x20, 0xe1, 0x98, 0x83, 0x4c, 0xa6, + 0xac, 0xc7, 0xea, 0x9e, 0x2d, 0x08, 0x92, 0x9b, 0x34, 0x22, 0xdb, 0xee, 0x52, 0x7c, 0x1c, 0x03, 0x1a, 0x21, 0x2b, + 0xf0, 0x85, 0xc2, 0x22, 0x07, 0xae, 0xb3, 0xf0, 0x1d, 0x7f, 0xa3, 0xa5, 0xa2, 0xaf, 0x06, 0x03, 0x5c, 0x98, 0x67, + 0x28, 0xca, 0xf9, 0x14, 0x2a, 0x78, 0xd6, 0x28, 0x10, 0x51, 0xf8, 0x6a, 0xb5, 0x0f, 0xaf, 0x06, 0xb9, 0x36, 0xc1, + 0xc5, 0xd5, 0xfd, 0xac, 0x5e, 0x08, 0x81, 0x71, 0x30, 0xd2, 0x32, 0x17, 0x85, 0x4e, 0xde, 0x64, 0x17, 0xa2, 0xdb, + 0x68, 0x30, 0x13, 0xd0, 0x89, 0x40, 0xf4, 0x36, 0xf0, 0x3f, 0x84, 0x3f, 0x36, 0x46, 0x93, 0x62, 0x36, 0xd2, 0x1d, + 0x84, 0xe0, 0xae, 0x25, 0xac, 0x56, 0xca, 0x46, 0x52, 0x31, 0x39, 0x36, 0xa6, 0x4a, 0xd9, 0x4f, 0x19, 0xb2, 0xb5, + 0x32, 0xe3, 0xe0, 0x6e, 0xab, 0xbf, 0xad, 0xf6, 0xf3, 0x1e, 0xb7, 0xd7, 0x78, 0xdc, 0xc4, 0x27, 0x30, 0x80, 0x5a, + 0x6e, 0x6c, 0x70, 0x6b, 0x4f, 0x1f, 0x5b, 0xe3, 0x5f, 0xb6, 0x09, 0x41, 0x51, 0xfa, 0xe3, 0xdb, 0x9b, 0x5b, 0x1f, + 0x9f, 0x50, 0x99, 0x39, 0x29, 0xa4, 0xfb, 0x20, 0x47, 0x0f, 0x08, 0x74, 0x6e, 0x7f, 0x56, 0x74, 0xa1, 0x92, 0x89, + 0xcb, 0x31, 0xfe, 0x12, 0xdc, 0xe6, 0xf5, 0xa3, 0xeb, 0x6b, 0xb3, 0xc9, 0xaf, 0xaf, 0x23, 0x1c, 0x1a, 0xb1, 0x47, + 0x01, 0x2f, 0x18, 0x0d, 0xca, 0x10, 0x56, 0x66, 0xe3, 0x37, 0xdb, 0x55, 0x63, 0xef, 0x69, 0x85, 0x77, 0xb0, 0x3c, + 0xa6, 0xf1, 0x2d, 0xa7, 0xcf, 0x3e, 0x07, 0x78, 0xb3, 0x3e, 0x1f, 0x74, 0xdf, 0xc4, 0x0a, 0x1d, 0x1c, 0xbc, 0x89, + 0x25, 0xea, 0x5d, 0x31, 0x73, 0xe7, 0x06, 0x5e, 0xdf, 0x7d, 0x6e, 0x86, 0x2f, 0x03, 0x04, 0xb8, 0x62, 0x9b, 0x92, + 0xcd, 0x5b, 0x13, 0x63, 0x23, 0x85, 0x18, 0xde, 0x10, 0x49, 0xd8, 0x81, 0x04, 0x7a, 0x7d, 0x13, 0x42, 0xbb, 0xcb, + 0x08, 0x03, 0x16, 0xbe, 0xf4, 0xc9, 0x63, 0xc9, 0x8c, 0x15, 0x13, 0x56, 0xac, 0x56, 0xef, 0xa9, 0xf5, 0xb3, 0xdb, + 0x08, 0x09, 0xa9, 0xba, 0x8d, 0x06, 0x35, 0xe3, 0x07, 0xf1, 0x81, 0x0e, 0xf0, 0xfe, 0x9b, 0xb8, 0x40, 0x08, 0x2c, + 0x8c, 0xb8, 0x58, 0x78, 0x9f, 0xb2, 0xac, 0xb6, 0x2e, 0x05, 0x2a, 0x1b, 0xc9, 0x49, 0x0b, 0x4f, 0x49, 0x56, 0xae, + 0xd1, 0xc5, 0xb4, 0xdb, 0x68, 0xe4, 0x48, 0xc6, 0x59, 0x3f, 0x1f, 0x60, 0x8e, 0x0b, 0xb8, 0x4c, 0xdd, 0x5e, 0x87, + 0x39, 0xab, 0x51, 0x2e, 0x37, 0xdf, 0xa5, 0x1d, 0x6b, 0xfa, 0x88, 0xae, 0x03, 0x60, 0x3c, 0xa2, 0x01, 0x91, 0xd8, + 0x05, 0x64, 0x61, 0x81, 0xac, 0x3c, 0x90, 0x85, 0x01, 0xb2, 0x42, 0xbd, 0x39, 0x04, 0x47, 0x52, 0x28, 0xdd, 0xa2, + 0xe8, 0xf5, 0x30, 0x9e, 0xce, 0x45, 0x04, 0x73, 0x13, 0x49, 0xc2, 0x2d, 0x07, 0xb8, 0x8b, 0x38, 0xaf, 0x43, 0x45, + 0x96, 0x51, 0x64, 0x22, 0xda, 0xe2, 0x5b, 0xf3, 0x27, 0xb9, 0xc5, 0x77, 0xf6, 0xc7, 0x5d, 0xa0, 0x4c, 0x7a, 0x5e, + 0xd3, 0x36, 0x70, 0x17, 0xff, 0x2d, 0x4a, 0x22, 0x40, 0x6b, 0x17, 0xcc, 0x50, 0xd4, 0xdf, 0x77, 0x53, 0x36, 0xec, + 0x84, 0x68, 0x10, 0x85, 0x45, 0x40, 0x3a, 0xff, 0xfa, 0x2b, 0x42, 0x3d, 0x01, 0x51, 0x83, 0xdc, 0xc9, 0xd6, 0x6c, + 0xa3, 0x46, 0x94, 0x44, 0x69, 0xec, 0x83, 0x52, 0xc0, 0xce, 0x88, 0xa2, 0xe0, 0x6d, 0x97, 0x72, 0x18, 0x1f, 0x6a, + 0xc3, 0x30, 0x83, 0xaa, 0xc2, 0x6c, 0x5c, 0x2e, 0x37, 0x83, 0x1a, 0x19, 0xa8, 0x0a, 0x13, 0x51, 0x06, 0xd9, 0x07, + 0xcf, 0x18, 0x61, 0x07, 0x07, 0xac, 0x2f, 0x06, 0xc1, 0x0b, 0x66, 0xd5, 0x75, 0xb8, 0x0e, 0x17, 0x2e, 0xa6, 0x10, + 0x55, 0x7e, 0xb5, 0xb2, 0x7f, 0xc9, 0x07, 0x23, 0xcd, 0xc0, 0x53, 0x74, 0xc1, 0x19, 0x2b, 0x76, 0xcb, 0x62, 0x89, + 0x96, 0xbf, 0x83, 0x65, 0x9f, 0x8b, 0x11, 0xc8, 0xdd, 0x54, 0xdb, 0x1e, 0xea, 0x73, 0xa3, 0x51, 0x08, 0x22, 0xf4, + 0x56, 0x47, 0x1a, 0x9e, 0xeb, 0x30, 0xaf, 0x16, 0x69, 0x37, 0x53, 0x65, 0xc0, 0x54, 0x38, 0x52, 0x12, 0xb0, 0x52, + 0x37, 0x74, 0x12, 0x7e, 0xd4, 0xa9, 0xa4, 0x63, 0x21, 0x01, 0x0a, 0x1c, 0x99, 0xcb, 0x79, 0x13, 0x10, 0x9f, 0xa1, + 0x1d, 0x44, 0x2e, 0x30, 0xa1, 0xa9, 0xcb, 0x96, 0x2e, 0x72, 0x55, 0x34, 0x93, 0x0b, 0xc5, 0x16, 0x73, 0x38, 0xdf, + 0xcb, 0xb4, 0x2c, 0xe7, 0xd9, 0xe7, 0x7a, 0x0a, 0x18, 0x44, 0xde, 0xea, 0x19, 0x13, 0x8b, 0xc8, 0xcd, 0xf3, 0xab, + 0x15, 0xf7, 0xdf, 0xbc, 0xc0, 0x8f, 0x48, 0xe7, 0xf0, 0x2b, 0xfe, 0x48, 0xc9, 0xa3, 0xc6, 0x57, 0x3c, 0xe1, 0xc4, + 0xf2, 0x06, 0xc9, 0x9b, 0xd7, 0x57, 0x2f, 0xde, 0xbd, 0x78, 0xff, 0xf4, 0xfa, 0xc5, 0xab, 0x67, 0x2f, 0x5e, 0xbd, + 0x78, 0xf7, 0x11, 0xff, 0x43, 0xc9, 0xd7, 0xa3, 0xf6, 0x79, 0x0b, 0x7f, 0x20, 0x5f, 0x8f, 0x3a, 0xf8, 0x56, 0x93, + 0xaf, 0x47, 0x27, 0x38, 0x57, 0xe4, 0xeb, 0x61, 0xe7, 0xe8, 0x18, 0x2f, 0xb4, 0x6d, 0x32, 0x97, 0x93, 0x76, 0x0b, + 0xff, 0xe3, 0xbe, 0x40, 0xbc, 0xaf, 0x66, 0x31, 0x61, 0x1b, 0xc6, 0x0f, 0xa6, 0x0c, 0x1d, 0x2a, 0x63, 0x88, 0x72, + 0x11, 0xa0, 0xd3, 0x54, 0x85, 0xe8, 0x64, 0x43, 0x36, 0x83, 0x0d, 0x23, 0xa0, 0x15, 0x27, 0xae, 0x1d, 0x7e, 0xd4, + 0x66, 0xc7, 0x40, 0x9f, 0x78, 0x29, 0x1c, 0x97, 0x2a, 0x9c, 0xb6, 0xd3, 0x62, 0x8c, 0x73, 0x29, 0x8b, 0x78, 0x01, + 0x8c, 0x80, 0xd1, 0x5a, 0xf0, 0xa3, 0x32, 0x36, 0x94, 0xb8, 0x20, 0xed, 0x5e, 0x3b, 0x15, 0x17, 0xa4, 0xd3, 0xeb, + 0xc0, 0x9f, 0xd3, 0xde, 0x69, 0xda, 0x6e, 0xa1, 0xc3, 0x60, 0x1c, 0x7f, 0xd4, 0xd0, 0xba, 0x3f, 0xc0, 0xae, 0x0b, + 0xf5, 0x4f, 0xa1, 0xbd, 0x4a, 0x4f, 0x38, 0x75, 0x6c, 0xbb, 0x2b, 0x2e, 0x98, 0xd1, 0xc3, 0xf2, 0x1f, 0x00, 0xb5, + 0x8d, 0xfb, 0x4a, 0xb9, 0x71, 0xdc, 0x2f, 0x7e, 0x24, 0x50, 0x2d, 0x00, 0x4d, 0xcc, 0x56, 0x2d, 0x04, 0x4c, 0xa3, + 0xc9, 0x06, 0x73, 0xa0, 0x44, 0xc9, 0x42, 0xfb, 0x20, 0xfa, 0xaa, 0x29, 0x51, 0x32, 0x97, 0xf3, 0xb8, 0xa6, 0x6a, + 0xf8, 0x35, 0x30, 0x73, 0xdc, 0xe7, 0xea, 0x15, 0x7d, 0x15, 0xd7, 0x78, 0x9e, 0x90, 0xb5, 0x0b, 0xb7, 0xc5, 0x2f, + 0xce, 0x8a, 0xa2, 0x06, 0xae, 0x12, 0xb0, 0x7e, 0x54, 0x4d, 0x7d, 0x01, 0xaf, 0x05, 0xb2, 0x86, 0xbe, 0x24, 0x01, + 0xf5, 0xfc, 0xa9, 0x34, 0xe3, 0x2a, 0x95, 0xd1, 0x5e, 0x11, 0x6d, 0xcc, 0x82, 0xbc, 0x22, 0xfa, 0x42, 0x19, 0x20, + 0x48, 0xc2, 0xfb, 0x62, 0x00, 0x07, 0xbe, 0x1d, 0xa0, 0x34, 0x74, 0x0e, 0xd4, 0x4a, 0x95, 0x99, 0x90, 0xf9, 0x34, + 0xa1, 0x10, 0x40, 0xf3, 0x54, 0xa9, 0xa0, 0xcc, 0x27, 0x96, 0x28, 0x18, 0xfa, 0x9f, 0xe1, 0x06, 0x38, 0x8c, 0x0d, + 0x2a, 0x06, 0xd9, 0xf7, 0x44, 0x3d, 0xbf, 0x7d, 0xde, 0x3a, 0xfa, 0x1a, 0xe4, 0x8f, 0x94, 0xb7, 0xf7, 0xf8, 0x3b, + 0xa0, 0xe4, 0x36, 0x78, 0x57, 0x1b, 0xfb, 0xb8, 0x6b, 0xdd, 0x10, 0x20, 0x87, 0x1a, 0x1d, 0x99, 0x87, 0x13, 0xbb, + 0x48, 0x1f, 0x92, 0x76, 0x0b, 0x82, 0xa5, 0xed, 0xa0, 0x7c, 0x3f, 0x6d, 0xc0, 0x54, 0x27, 0xb7, 0x4d, 0xa0, 0xd5, + 0xf0, 0x96, 0xd2, 0x5d, 0x93, 0x27, 0x77, 0x58, 0x05, 0x38, 0xc3, 0x0e, 0x59, 0x43, 0x1c, 0x0a, 0xe4, 0x82, 0xcc, + 0xda, 0x0d, 0xa0, 0xa9, 0xe8, 0xd8, 0x37, 0xfd, 0xbc, 0x71, 0xd4, 0x45, 0x33, 0x39, 0x3d, 0xfc, 0x7a, 0x70, 0x10, + 0xcb, 0x06, 0x79, 0x84, 0xf0, 0x92, 0x82, 0xcd, 0x36, 0xf8, 0xb8, 0x71, 0xcb, 0xc4, 0xa7, 0x2a, 0xa0, 0x8e, 0x0b, + 0x55, 0x3b, 0xd6, 0xaa, 0xce, 0xca, 0xdd, 0xe0, 0xc7, 0xd4, 0x41, 0x8d, 0x20, 0xcd, 0x8e, 0xae, 0x13, 0x42, 0xf9, + 0xb7, 0x9a, 0x43, 0x1a, 0x6c, 0xcb, 0xc6, 0x47, 0x8a, 0x7e, 0x78, 0xd4, 0xfc, 0x1a, 0x94, 0xa9, 0x99, 0x26, 0x3d, + 0x6a, 0x3c, 0x42, 0x3f, 0x3c, 0x0a, 0x5c, 0x0a, 0x79, 0xc5, 0x9e, 0x78, 0x6e, 0xe4, 0x37, 0xcb, 0x95, 0xfe, 0x06, + 0x92, 0x7d, 0x41, 0x7e, 0x03, 0x2c, 0xa7, 0xe4, 0xb7, 0x58, 0x36, 0x21, 0xd4, 0x22, 0xf9, 0x2d, 0x2e, 0xe0, 0x47, + 0x4e, 0x7e, 0x8b, 0x01, 0xdb, 0xf1, 0xd4, 0xfc, 0x28, 0x4a, 0x60, 0x80, 0x1b, 0x9b, 0xb4, 0xde, 0x6c, 0xc5, 0x6a, + 0x25, 0x0e, 0x0e, 0xa4, 0xfd, 0x45, 0x2f, 0xb3, 0x83, 0x83, 0xfc, 0x62, 0x1a, 0xd8, 0xde, 0xea, 0x5d, 0xf4, 0xc5, + 0x20, 0x14, 0x0e, 0x4c, 0xd3, 0x78, 0x0d, 0xaf, 0x6a, 0x94, 0x15, 0x1a, 0x68, 0x1e, 0x77, 0xee, 0x9f, 0x9d, 0x63, + 0xf8, 0xf7, 0x7e, 0x50, 0xf0, 0xe7, 0x92, 0xef, 0x22, 0x6d, 0xd6, 0x3c, 0xab, 0xea, 0x5c, 0x06, 0xf8, 0x8c, 0x19, + 0x6a, 0x8a, 0x83, 0x03, 0x7e, 0x11, 0xe0, 0x32, 0x66, 0xa8, 0x11, 0x58, 0xec, 0x3d, 0x2c, 0xed, 0xc9, 0x0c, 0xd7, + 0x04, 0x8f, 0xe8, 0xf2, 0x7e, 0x31, 0xb8, 0xd0, 0x8e, 0x9a, 0x84, 0xa1, 0xb6, 0x15, 0x69, 0xb9, 0x4d, 0xd6, 0x15, + 0x4d, 0x75, 0xd9, 0xee, 0x22, 0x49, 0x54, 0x43, 0x5c, 0x5e, 0xb6, 0x31, 0xa8, 0xe4, 0x7b, 0x8a, 0xc8, 0x54, 0x10, + 0xef, 0x0e, 0xb8, 0xcc, 0x65, 0xaa, 0xf0, 0x94, 0xa7, 0xc2, 0xcb, 0xd9, 0xaf, 0xbd, 0xf5, 0xb4, 0x71, 0xd0, 0x34, + 0x3d, 0x33, 0x2c, 0x7a, 0xaa, 0x74, 0x2c, 0x84, 0x4d, 0xaa, 0x06, 0xf0, 0x46, 0x61, 0x89, 0x79, 0xcc, 0x7a, 0xd3, + 0x31, 0x88, 0x01, 0xad, 0x1a, 0x6d, 0xc8, 0x84, 0xcf, 0x75, 0xaa, 0x60, 0xa0, 0xa6, 0xf0, 0x05, 0x90, 0xa9, 0xac, + 0x32, 0xcc, 0xf6, 0x0d, 0x43, 0x01, 0x01, 0x05, 0x2e, 0x09, 0x0b, 0x24, 0x78, 0xb8, 0xfd, 0x08, 0x08, 0x47, 0x9d, + 0x5c, 0xd8, 0xc9, 0x5d, 0x28, 0xe8, 0x4e, 0x0c, 0x2e, 0x74, 0x17, 0x89, 0x46, 0xc3, 0x71, 0xdb, 0x97, 0xc2, 0x0c, + 0xa2, 0xd9, 0x1e, 0x5c, 0xb2, 0x2e, 0x52, 0xcd, 0x66, 0x69, 0x00, 0x79, 0xd9, 0x5a, 0xad, 0xd4, 0x85, 0x6f, 0xa4, + 0xe7, 0xcf, 0x71, 0xc3, 0x77, 0x79, 0xc1, 0xf3, 0x37, 0x49, 0xfa, 0x11, 0x50, 0x55, 0xe0, 0xb3, 0xe5, 0x3c, 0xc2, + 0x91, 0x79, 0xbe, 0x0e, 0xfe, 0x9a, 0x67, 0xc7, 0x22, 0x1c, 0xb9, 0x17, 0xed, 0xa2, 0x41, 0x35, 0x58, 0x9e, 0x95, + 0xc1, 0xd8, 0x79, 0x72, 0x0d, 0x8c, 0x83, 0xfe, 0x5b, 0xa1, 0x65, 0xf5, 0x3b, 0xc9, 0x5d, 0x58, 0x12, 0xe5, 0x1f, + 0x59, 0x73, 0xa3, 0x5a, 0xef, 0x76, 0x04, 0xe5, 0x38, 0xf2, 0x55, 0xe1, 0xb1, 0x82, 0xef, 0xbc, 0xf2, 0xd8, 0x76, + 0x8f, 0x8b, 0x2f, 0xcb, 0x1e, 0x80, 0xf3, 0x5e, 0xaf, 0x11, 0xfe, 0x4d, 0xee, 0x7c, 0x69, 0x38, 0xba, 0x96, 0xe2, + 0x09, 0xd5, 0x34, 0x6a, 0xbc, 0x31, 0x86, 0x6f, 0x56, 0xce, 0xea, 0x7e, 0x6b, 0x1c, 0xec, 0xdf, 0xea, 0x1e, 0x02, + 0x45, 0xd4, 0x1e, 0x45, 0xb2, 0xb2, 0xaf, 0x09, 0x0f, 0x22, 0x03, 0xd3, 0xb7, 0x1d, 0xf0, 0xf0, 0x63, 0xa4, 0xe0, + 0xbe, 0x6c, 0xf9, 0x24, 0x0a, 0x11, 0x58, 0x6b, 0x4e, 0xd3, 0x90, 0x62, 0xfb, 0x30, 0x0e, 0xb6, 0x6b, 0x14, 0x72, + 0xdd, 0x63, 0x55, 0x27, 0xa6, 0x55, 0x37, 0x46, 0xea, 0x60, 0x9b, 0x2c, 0x38, 0xab, 0x7a, 0x37, 0x12, 0x4a, 0xf5, + 0x7e, 0x9c, 0x79, 0x03, 0xb4, 0xd9, 0x36, 0x8f, 0x2a, 0xdb, 0x57, 0xe6, 0x14, 0x18, 0xf2, 0xee, 0x97, 0xc1, 0xb1, + 0x2e, 0xe1, 0xd8, 0x8d, 0x03, 0xc8, 0x4a, 0x72, 0xb9, 0x74, 0x2f, 0xc0, 0xf1, 0xbe, 0x1c, 0xac, 0xcb, 0xf7, 0xe0, + 0x02, 0x3c, 0xa8, 0x46, 0x2a, 0xb2, 0x90, 0x33, 0xf0, 0x8f, 0x29, 0xd6, 0xf4, 0x43, 0xfc, 0x2b, 0x1c, 0xf0, 0x15, + 0x92, 0xa6, 0x56, 0xfd, 0x04, 0xef, 0x34, 0x81, 0xc2, 0xdb, 0xd6, 0xfd, 0x53, 0x86, 0x0e, 0xb1, 0x75, 0x9d, 0x8a, + 0xf5, 0x39, 0xad, 0x2b, 0x56, 0xca, 0xc2, 0x01, 0xd5, 0x8a, 0xd1, 0x3a, 0x75, 0xfe, 0xa9, 0xee, 0x71, 0xa7, 0x87, + 0x02, 0x7c, 0x63, 0xb8, 0x14, 0xcf, 0x0a, 0x88, 0xd6, 0x15, 0xea, 0xd3, 0x7e, 0x96, 0xe1, 0xeb, 0xc5, 0x7d, 0xb8, + 0x27, 0x2c, 0x79, 0xce, 0xf2, 0xc5, 0x6d, 0x58, 0x20, 0x05, 0x14, 0x4a, 0x61, 0xb1, 0x5a, 0xc5, 0x02, 0x02, 0x36, + 0xfc, 0xe9, 0x42, 0xf8, 0xba, 0xb7, 0x3a, 0x8c, 0xfe, 0x0e, 0xea, 0x62, 0xaf, 0x1e, 0x31, 0x26, 0xac, 0x28, 0xbc, + 0x74, 0x52, 0x59, 0xd0, 0xd7, 0xae, 0x3e, 0x44, 0x35, 0xe5, 0x5e, 0x6c, 0xf4, 0xbd, 0xef, 0xf8, 0x8c, 0xc9, 0x05, + 0x3c, 0x92, 0x84, 0x19, 0x51, 0x4c, 0xfb, 0x6f, 0xa0, 0x20, 0xf0, 0xd2, 0x0e, 0x0f, 0xf1, 0x11, 0xf8, 0x2a, 0x4f, + 0xeb, 0x64, 0xe6, 0x9f, 0xde, 0x88, 0x4c, 0x68, 0xcc, 0xa8, 0x17, 0x81, 0x17, 0x11, 0x88, 0x50, 0x84, 0x44, 0x4c, + 0x8c, 0xa2, 0x5e, 0x64, 0x5c, 0xb2, 0x22, 0xb0, 0x1a, 0x03, 0x25, 0x77, 0x84, 0xe7, 0xaa, 0x22, 0x62, 0x61, 0x4d, + 0x1d, 0x54, 0x62, 0xa9, 0x31, 0xd3, 0x3e, 0xea, 0x54, 0x20, 0x2c, 0xb2, 0x4d, 0x41, 0x59, 0x6f, 0xa8, 0x0b, 0xb0, + 0x24, 0xc6, 0xf4, 0x96, 0x27, 0xd7, 0xc0, 0xcd, 0xb1, 0x91, 0x2b, 0xba, 0xe4, 0x57, 0xa0, 0x9e, 0x4e, 0x0b, 0x7c, + 0x6d, 0x18, 0xb6, 0x51, 0x4a, 0xd7, 0x84, 0xe3, 0x8c, 0x14, 0x09, 0xbd, 0x85, 0x18, 0x16, 0x33, 0x2e, 0xd2, 0x1c, + 0xcf, 0xe8, 0x6d, 0x3a, 0xc5, 0x33, 0x2e, 0x9e, 0xd8, 0x65, 0x4f, 0x47, 0x90, 0xe4, 0x3f, 0x16, 0x6b, 0x62, 0x9e, + 0xe0, 0xfa, 0x5d, 0xb1, 0xe2, 0x11, 0xf0, 0x2a, 0x2a, 0x46, 0xdd, 0x91, 0xb1, 0x29, 0xe7, 0xba, 0x32, 0x5e, 0x7f, + 0xad, 0x63, 0x8a, 0x33, 0x9c, 0xa3, 0x24, 0x97, 0x98, 0xf5, 0x44, 0xfa, 0x1a, 0xe2, 0x57, 0x67, 0xd8, 0x3e, 0xdf, + 0xc5, 0x6f, 0x59, 0xfe, 0x4c, 0x16, 0xef, 0xcd, 0x96, 0xcf, 0x11, 0x14, 0x02, 0x17, 0x15, 0xd1, 0x84, 0xdb, 0xbd, + 0x45, 0x4f, 0x56, 0x4d, 0xd1, 0x5b, 0xdb, 0x94, 0x1b, 0xe2, 0x14, 0x02, 0xff, 0x26, 0x53, 0xde, 0x68, 0x63, 0xd6, + 0x6b, 0x7d, 0xa7, 0xd1, 0x29, 0x2a, 0x4b, 0x22, 0x0c, 0x6b, 0xd5, 0x54, 0xa9, 0x24, 0xa2, 0xa9, 0x9c, 0x84, 0xb7, + 0x34, 0xc0, 0x4e, 0x15, 0xce, 0xe4, 0x42, 0xe8, 0x54, 0x06, 0x78, 0x43, 0xab, 0xcd, 0xb5, 0xbc, 0xb5, 0x10, 0xd3, + 0xf8, 0xce, 0xfe, 0x60, 0xf8, 0xda, 0xa8, 0xf8, 0xdf, 0x82, 0x61, 0x8f, 0x4a, 0x05, 0xc0, 0x0f, 0x0c, 0x67, 0x01, + 0x72, 0x96, 0x9f, 0xbc, 0x05, 0xf0, 0x59, 0x16, 0xf2, 0x0e, 0x52, 0x99, 0x49, 0xbd, 0x83, 0x54, 0x06, 0xa9, 0xc6, + 0x73, 0x7d, 0x5f, 0x54, 0xca, 0xa2, 0xb0, 0x41, 0xa2, 0x70, 0xa9, 0x0e, 0x96, 0x44, 0x24, 0xd0, 0xae, 0x11, 0xe5, + 0x66, 0x5c, 0x40, 0x08, 0x43, 0x68, 0xdc, 0x7e, 0xd3, 0x5b, 0xf8, 0xbe, 0xb3, 0xf9, 0xcc, 0xe7, 0xdf, 0xd9, 0x7c, + 0xd3, 0x91, 0xc7, 0xf8, 0xfa, 0x6d, 0xa7, 0xb1, 0x8c, 0x97, 0x0e, 0x6b, 0x3f, 0x94, 0x0f, 0xc6, 0xb4, 0xcc, 0xc3, + 0xdc, 0xa4, 0x8d, 0x27, 0x01, 0x52, 0x36, 0x2b, 0x1e, 0xae, 0x83, 0xdb, 0xad, 0xc3, 0x98, 0x37, 0x49, 0x1b, 0xa1, + 0x43, 0x27, 0x5c, 0x89, 0xd8, 0x48, 0x4e, 0x87, 0x8f, 0x8e, 0xe0, 0xee, 0x65, 0xa6, 0x36, 0x7c, 0xa5, 0x6c, 0xb5, + 0x66, 0xbb, 0x75, 0xc8, 0x77, 0x56, 0x69, 0xb4, 0xf1, 0x8c, 0x91, 0x25, 0x78, 0xa0, 0xd1, 0xc2, 0xaa, 0x1a, 0xc0, + 0x65, 0xf5, 0x85, 0xf8, 0x6d, 0x41, 0x47, 0xe6, 0xfb, 0xd0, 0xa6, 0xbc, 0x5e, 0x68, 0x9f, 0xd4, 0xe4, 0x30, 0x88, + 0x0e, 0x72, 0x25, 0x83, 0x9c, 0x98, 0x1f, 0x91, 0xe4, 0x14, 0x5d, 0xb4, 0x7b, 0xc9, 0xe9, 0x21, 0x3f, 0xe4, 0x29, + 0xf0, 0xb0, 0x71, 0xd3, 0x57, 0x68, 0xb6, 0x7d, 0x9d, 0xc7, 0x8b, 0x21, 0xcf, 0x5c, 0xf3, 0x55, 0x07, 0x65, 0xaa, + 0x9d, 0x23, 0x64, 0x01, 0x8a, 0xf9, 0x5e, 0x82, 0xec, 0x7a, 0x37, 0x87, 0x3c, 0x85, 0x7e, 0xa0, 0x56, 0xc7, 0xd6, + 0x2a, 0x07, 0xf7, 0xdb, 0x02, 0x10, 0xcc, 0x77, 0x54, 0x9b, 0x8b, 0x4d, 0x6f, 0xc6, 0x55, 0x67, 0x87, 0xbc, 0x1a, + 0x61, 0x58, 0x66, 0xbb, 0x3f, 0x3f, 0xb5, 0xaa, 0xcb, 0xc3, 0x00, 0x22, 0xbf, 0x2d, 0xb8, 0x08, 0x3b, 0x0d, 0xbb, + 0x75, 0x39, 0x61, 0xa7, 0xf5, 0x59, 0x06, 0x45, 0xb6, 0x7b, 0xdd, 0x9a, 0x69, 0x7d, 0xb6, 0x57, 0xe0, 0x48, 0x08, + 0x93, 0x32, 0x2b, 0x9d, 0xc1, 0x15, 0xfa, 0xe1, 0x07, 0xe4, 0x5a, 0x7f, 0xbd, 0xd0, 0x3e, 0xbf, 0x44, 0x04, 0xc8, + 0xae, 0xba, 0x2e, 0xab, 0x43, 0x1f, 0x65, 0x13, 0x5f, 0x0f, 0x79, 0xb0, 0x72, 0x4f, 0x6f, 0xe7, 0x32, 0xf5, 0xf8, + 0xda, 0x6b, 0xa5, 0x5b, 0xc8, 0x09, 0xc4, 0xc3, 0x75, 0x17, 0x96, 0x05, 0x39, 0xbb, 0xb9, 0x85, 0x92, 0xe1, 0xc4, + 0x7d, 0xe9, 0x0f, 0xcc, 0x5e, 0x37, 0xf0, 0x8b, 0xe4, 0x14, 0xa6, 0xbe, 0xd9, 0xc3, 0x61, 0x07, 0xfa, 0x30, 0x70, + 0xd8, 0x6c, 0xd0, 0x67, 0x56, 0x10, 0x79, 0xcc, 0x0b, 0x8b, 0x67, 0x97, 0xa4, 0xdd, 0xe3, 0xa9, 0xdb, 0x4c, 0x46, + 0x34, 0x6a, 0x37, 0x79, 0x30, 0x33, 0xc0, 0x2f, 0x57, 0x36, 0x2c, 0xe2, 0xd7, 0x29, 0x80, 0x92, 0x2f, 0x56, 0xad, + 0x4f, 0x05, 0xaf, 0x7a, 0xc3, 0xe9, 0x66, 0xba, 0x5f, 0x37, 0xb8, 0xdd, 0xf5, 0xf0, 0x84, 0x07, 0x5f, 0x2c, 0x5a, + 0xfb, 0x89, 0x4f, 0x80, 0x03, 0x4a, 0x5a, 0xf7, 0x4f, 0xc1, 0x85, 0xb2, 0x84, 0xe5, 0x76, 0xb9, 0xd9, 0x56, 0x39, + 0x0b, 0x47, 0x5b, 0x32, 0xe0, 0x0e, 0x36, 0x21, 0x0a, 0x1d, 0x1c, 0x76, 0x70, 0xd2, 0x6e, 0x77, 0x4e, 0x71, 0x72, + 0x72, 0x0a, 0x03, 0x6d, 0x24, 0xa7, 0x87, 0x33, 0x65, 0x01, 0x18, 0xe4, 0xac, 0x5d, 0xbb, 0x8f, 0x20, 0x38, 0x54, + 0x28, 0x5e, 0xf3, 0xc3, 0x38, 0x6e, 0x27, 0xf7, 0x5b, 0xed, 0xd3, 0xf3, 0x06, 0x00, 0xa8, 0xe9, 0x3e, 0x5c, 0x8d, + 0xd7, 0x0b, 0x5d, 0xaf, 0x52, 0x22, 0x7c, 0xbd, 0x5a, 0xc3, 0x57, 0x6b, 0xb4, 0xd7, 0xd5, 0x14, 0x7c, 0x55, 0x27, + 0x9c, 0xdb, 0x22, 0x5e, 0x69, 0x13, 0x6e, 0x8b, 0xd8, 0x0e, 0x24, 0x06, 0xe9, 0x3c, 0x39, 0xed, 0x9c, 0x22, 0x3b, + 0x16, 0xed, 0xf0, 0xa3, 0xdc, 0x27, 0x5b, 0x45, 0x1a, 0x1a, 0x90, 0xa4, 0x9c, 0x9d, 0x5c, 0x80, 0x44, 0xcd, 0xc9, + 0x65, 0xbb, 0x39, 0x63, 0x89, 0x9f, 0x80, 0x49, 0x85, 0xe5, 0x2c, 0x57, 0xc1, 0x25, 0x05, 0x80, 0xb8, 0x00, 0xe3, + 0xa2, 0xfb, 0xa7, 0xbd, 0xfb, 0xc9, 0xe9, 0x59, 0xc7, 0x12, 0x3d, 0x7e, 0xd1, 0xa9, 0xa5, 0x99, 0xa9, 0x27, 0xa7, + 0x26, 0x0d, 0xba, 0x4e, 0xee, 0x9f, 0x42, 0x19, 0x97, 0x12, 0x96, 0x82, 0xa0, 0x16, 0x55, 0x31, 0x88, 0x64, 0x91, + 0xd6, 0x72, 0xcf, 0x6a, 0xd9, 0xe7, 0x27, 0xc7, 0xf7, 0x4f, 0x43, 0xa8, 0x95, 0xb3, 0x30, 0x0b, 0xed, 0x26, 0xe2, + 0x67, 0x07, 0x4b, 0x8b, 0x0e, 0x93, 0xd3, 0x74, 0x6b, 0x82, 0x76, 0xd3, 0x1c, 0x1a, 0x1c, 0x08, 0x14, 0x8e, 0x4f, + 0x85, 0xd3, 0x97, 0x04, 0xf7, 0x63, 0x95, 0xa1, 0x49, 0xa8, 0x70, 0xf6, 0xf7, 0x94, 0xc1, 0xbb, 0x95, 0xe1, 0x55, + 0xe5, 0x63, 0x2a, 0xbe, 0x50, 0xf5, 0x86, 0x42, 0xa4, 0x0e, 0x31, 0x88, 0x5c, 0x1c, 0xf1, 0x7a, 0xee, 0x4f, 0xe0, + 0x22, 0xcc, 0x04, 0x5c, 0x68, 0x7a, 0x25, 0x68, 0xc5, 0x0b, 0x0c, 0x43, 0x87, 0x5a, 0x33, 0xac, 0x1e, 0x4f, 0x9d, + 0x49, 0x41, 0xa8, 0xdb, 0x7a, 0xce, 0xbf, 0x57, 0x2e, 0x29, 0xaf, 0xb2, 0x93, 0x53, 0x94, 0xb8, 0xcb, 0xf2, 0xa4, + 0x8d, 0x92, 0xc0, 0x84, 0xc4, 0x1d, 0xc9, 0x59, 0x46, 0xfa, 0xd1, 0x6d, 0x84, 0xa3, 0xbb, 0x08, 0x47, 0xd6, 0x87, + 0xf9, 0x03, 0xf8, 0x71, 0x47, 0x38, 0xb2, 0xae, 0xcc, 0x11, 0x8e, 0x34, 0x13, 0x10, 0xc0, 0x2b, 0x1a, 0xe0, 0x1c, + 0x4a, 0x1b, 0xcf, 0xea, 0xb2, 0xf4, 0x63, 0xff, 0x55, 0xba, 0x5e, 0xdb, 0x94, 0x40, 0xca, 0x9c, 0x9a, 0x1d, 0x6a, + 0x1f, 0xa0, 0x8e, 0xa8, 0x67, 0xd6, 0x23, 0x0c, 0x02, 0x08, 0xbd, 0xf3, 0x0f, 0xd8, 0x55, 0xb1, 0x3f, 0xd8, 0x31, + 0xac, 0x34, 0xb8, 0xa2, 0x47, 0xe1, 0x19, 0x16, 0xe1, 0xb1, 0xf0, 0x85, 0x41, 0xac, 0xf0, 0xbf, 0x73, 0x29, 0xe7, + 0xfe, 0xb7, 0x96, 0xe5, 0x2f, 0x78, 0xf6, 0xc4, 0x59, 0xb4, 0x80, 0xe5, 0x96, 0x0d, 0x35, 0x34, 0x64, 0xf5, 0x11, + 0x5c, 0x8f, 0x5d, 0x38, 0x38, 0x90, 0x08, 0xaf, 0x8d, 0x40, 0xe5, 0xe5, 0xc3, 0x6b, 0x1b, 0x9a, 0xc8, 0x7c, 0x42, + 0x6c, 0x32, 0x08, 0x3f, 0x2c, 0xe1, 0x42, 0x63, 0x52, 0x30, 0xa5, 0x22, 0x1b, 0xb3, 0x2f, 0x92, 0xc2, 0x3f, 0xc2, + 0xe8, 0x53, 0xc6, 0x22, 0x32, 0x1d, 0xd6, 0x67, 0x6b, 0xc5, 0xe1, 0x5c, 0x16, 0x2a, 0xb5, 0x2f, 0xb2, 0x78, 0x30, + 0xce, 0xcb, 0xe7, 0x0e, 0xd3, 0x3c, 0x5b, 0x63, 0x7b, 0x87, 0x5d, 0x16, 0x72, 0x57, 0xda, 0x61, 0xa9, 0x2c, 0x5b, + 0x7f, 0x6b, 0x42, 0xaa, 0x36, 0xa3, 0x60, 0xa2, 0xd5, 0x80, 0xaa, 0xc0, 0x1d, 0x50, 0xd8, 0x06, 0x7f, 0x49, 0x97, + 0x65, 0xc9, 0x74, 0x59, 0x2e, 0xc3, 0x49, 0xab, 0xb5, 0x5e, 0xe3, 0x82, 0x99, 0x20, 0x34, 0x3b, 0x4b, 0x40, 0xbe, + 0x9a, 0xca, 0x9b, 0x20, 0x57, 0xa5, 0xe5, 0x2c, 0xcd, 0x12, 0x45, 0x81, 0x11, 0x6c, 0xb4, 0xc6, 0x5f, 0xb8, 0xe2, + 0x00, 0x4f, 0x37, 0xbb, 0xa1, 0x94, 0x39, 0xa3, 0x10, 0xab, 0x2c, 0x68, 0x72, 0x8d, 0xa7, 0x7c, 0xc4, 0x76, 0xb7, + 0x09, 0x66, 0xcc, 0xff, 0x5e, 0x8b, 0x1e, 0x81, 0x2c, 0xbb, 0x67, 0x50, 0x07, 0x16, 0x71, 0x05, 0x1d, 0x84, 0x32, + 0xf8, 0x28, 0xc4, 0xcd, 0x9c, 0xde, 0xc9, 0x85, 0x06, 0xb8, 0x2c, 0xb4, 0x7c, 0xe3, 0xc2, 0x21, 0xec, 0xb7, 0xb0, + 0x8f, 0x8c, 0xb0, 0x84, 0x90, 0x01, 0x2d, 0x6c, 0x23, 0x62, 0xb4, 0xb0, 0x0b, 0x54, 0xd0, 0xc2, 0x26, 0x3c, 0x45, + 0x6b, 0x5d, 0xc6, 0x10, 0xbb, 0x2e, 0x9f, 0xae, 0xac, 0x36, 0xc1, 0xc2, 0x49, 0x87, 0x9a, 0xe8, 0xe0, 0xf6, 0x90, + 0x11, 0xde, 0xf8, 0xf9, 0xea, 0xf5, 0x2b, 0x17, 0x21, 0x9a, 0x8f, 0xc1, 0x65, 0xd3, 0xa9, 0xc6, 0xae, 0xcd, 0x9b, + 0x4f, 0x71, 0xa5, 0x28, 0xb5, 0xc2, 0x29, 0xb4, 0xfc, 0x42, 0xe8, 0x3c, 0xb1, 0x97, 0x17, 0xcf, 0x64, 0x31, 0xa3, + 0xf6, 0xc6, 0x08, 0x5f, 0x2b, 0xf7, 0xc8, 0xbb, 0x79, 0x47, 0xa6, 0x9a, 0xe4, 0xbb, 0xcd, 0xab, 0x88, 0x45, 0x66, + 0xe4, 0x57, 0xd0, 0x06, 0x98, 0xca, 0xe5, 0x1b, 0xbd, 0x05, 0x71, 0x71, 0xf6, 0x03, 0xf2, 0xf2, 0xd6, 0x52, 0x97, + 0x28, 0x6a, 0x70, 0x83, 0x9f, 0xac, 0xe0, 0x59, 0x70, 0x5d, 0x68, 0xd8, 0x23, 0x27, 0x5e, 0x44, 0xad, 0xa8, 0xfe, + 0xc6, 0xad, 0x51, 0x25, 0xf8, 0x18, 0xad, 0x49, 0x2e, 0x41, 0xf4, 0x28, 0x9f, 0xd3, 0xe3, 0x20, 0x9a, 0xf8, 0xbb, + 0xe7, 0xcb, 0xb6, 0xa7, 0xb3, 0x79, 0xa5, 0x4e, 0x2c, 0xaf, 0x4c, 0xc0, 0xc3, 0xd1, 0x3e, 0x58, 0x83, 0x70, 0x90, + 0xc8, 0x4a, 0xed, 0xa1, 0xcf, 0x45, 0xdd, 0x38, 0xbf, 0x68, 0xb3, 0xe6, 0xc9, 0x6a, 0x95, 0x5f, 0xb6, 0x59, 0xfb, + 0xd4, 0x3e, 0x6f, 0x17, 0xa9, 0x0c, 0x68, 0x2e, 0x1f, 0xf3, 0x2c, 0x02, 0xed, 0xec, 0x38, 0x33, 0xe1, 0x14, 0x7c, + 0x40, 0x66, 0xb2, 0xd0, 0x55, 0x5f, 0x12, 0x8c, 0x4b, 0x89, 0xd5, 0xe3, 0x17, 0xa8, 0xd7, 0x4e, 0xb7, 0x5d, 0xa5, + 0x9b, 0xed, 0xc3, 0xe0, 0xc2, 0xa5, 0x40, 0xb8, 0x03, 0x21, 0x0f, 0x40, 0xbf, 0xbb, 0x14, 0x60, 0x1a, 0x04, 0xa8, + 0xac, 0x40, 0xa4, 0xe5, 0xb3, 0xc5, 0xec, 0x59, 0x41, 0xcd, 0x32, 0x3c, 0xe1, 0x13, 0xae, 0x55, 0x4a, 0x41, 0xba, + 0xdd, 0x95, 0xbe, 0xde, 0x2d, 0x41, 0x65, 0xb5, 0x38, 0xb7, 0x89, 0xe6, 0xd9, 0x67, 0xe5, 0x16, 0x0e, 0x61, 0xb3, + 0xb2, 0x02, 0x67, 0x68, 0x8d, 0x73, 0x39, 0xa1, 0x05, 0xd7, 0xd3, 0xd9, 0xbf, 0xb5, 0x3a, 0xac, 0xaf, 0x07, 0xe6, + 0xc2, 0x0a, 0x40, 0x42, 0xc5, 0x68, 0xb5, 0xe2, 0x47, 0xdf, 0xbf, 0x4f, 0xf2, 0x3e, 0xe1, 0x6d, 0xdc, 0xc1, 0xc7, + 0xf8, 0x14, 0xb7, 0x5b, 0xb8, 0x7d, 0x0a, 0x57, 0xf7, 0x59, 0xbe, 0x18, 0x31, 0x15, 0xc3, 0x3b, 0x67, 0xfa, 0x32, + 0x39, 0x3f, 0x2c, 0xa3, 0xfb, 0xeb, 0x22, 0x71, 0xe8, 0x12, 0x04, 0x99, 0x77, 0xd1, 0xf9, 0xa2, 0x28, 0x0c, 0x0d, + 0x37, 0x0e, 0x55, 0x27, 0xa5, 0x7e, 0xe1, 0xf2, 0xb8, 0x07, 0xf6, 0xdc, 0x76, 0x65, 0x9b, 0x60, 0xf6, 0x6d, 0x7f, + 0xa6, 0xd5, 0xcf, 0xa6, 0x2e, 0x11, 0xc3, 0x43, 0xaf, 0x42, 0x0f, 0x74, 0x49, 0xda, 0x07, 0x07, 0x60, 0x75, 0x14, + 0xcc, 0x86, 0xdb, 0xe8, 0x07, 0xbc, 0x59, 0x4b, 0x83, 0x60, 0x05, 0x60, 0xdc, 0xf9, 0x86, 0x93, 0xa5, 0x85, 0xad, + 0x06, 0x2a, 0xac, 0x8b, 0x30, 0x7e, 0x5d, 0x48, 0x2a, 0x8c, 0x10, 0x0d, 0x47, 0x98, 0x0b, 0x86, 0xb2, 0xdf, 0xc2, + 0x72, 0x3c, 0x56, 0x4c, 0xc3, 0xd1, 0x51, 0xb0, 0x2f, 0xac, 0x50, 0xe6, 0x14, 0x19, 0xb2, 0x09, 0x17, 0x0f, 0xf5, + 0x9f, 0xac, 0x90, 0xe6, 0xd3, 0x68, 0x30, 0xd2, 0xc8, 0xac, 0x62, 0x84, 0xb3, 0x9c, 0xcf, 0xa1, 0xea, 0xa4, 0x00, + 0xa7, 0x1f, 0xf8, 0xcb, 0x47, 0x69, 0xd8, 0x26, 0x90, 0xaf, 0x0f, 0x36, 0xa6, 0x0b, 0x1e, 0x15, 0xf4, 0xe6, 0xb5, + 0x78, 0x0c, 0x3b, 0xea, 0x61, 0xc1, 0x28, 0x64, 0x43, 0xd2, 0x3b, 0x68, 0x0a, 0x3e, 0xa0, 0xcd, 0x97, 0x06, 0x70, + 0xe9, 0xb9, 0xf9, 0xb0, 0x15, 0x7d, 0x8c, 0xc4, 0xa4, 0x6c, 0xcb, 0x64, 0x9a, 0x53, 0xba, 0xca, 0xb4, 0x51, 0xa8, + 0xca, 0x29, 0xac, 0xb1, 0x8b, 0x7a, 0x12, 0x0e, 0x66, 0x44, 0xd5, 0x34, 0xed, 0x0f, 0xcc, 0xdf, 0xd7, 0xb6, 0x64, + 0x0b, 0xbb, 0x88, 0x33, 0x6b, 0x6c, 0x1e, 0x28, 0x0d, 0xca, 0xb7, 0x31, 0xdc, 0xc3, 0xc2, 0x2b, 0x99, 0x35, 0xf2, + 0x79, 0xe2, 0xc9, 0xe6, 0xc9, 0x7a, 0x6d, 0x06, 0xa2, 0x52, 0xd0, 0x03, 0xbd, 0xf5, 0xdb, 0xa6, 0x05, 0xdb, 0xa3, + 0xfc, 0x3a, 0x6d, 0xe1, 0x19, 0x87, 0x47, 0x3f, 0x7d, 0x7b, 0x57, 0xba, 0x90, 0x9f, 0x1d, 0x48, 0x5a, 0x41, 0x8a, + 0x9d, 0x4e, 0xd0, 0xd9, 0x31, 0x0e, 0x46, 0x0e, 0xf4, 0xfc, 0xea, 0xb3, 0x85, 0xb5, 0xff, 0xfd, 0xa6, 0x2c, 0x68, + 0xe2, 0xe9, 0x94, 0x13, 0xca, 0xfc, 0xf9, 0xf9, 0x86, 0x27, 0x15, 0x2a, 0xb8, 0xd7, 0xb2, 0x60, 0x4f, 0xdb, 0x80, + 0x9a, 0x33, 0xfa, 0xb7, 0xfd, 0x61, 0x63, 0xf8, 0x94, 0x5a, 0xb6, 0xac, 0x90, 0x4a, 0x3d, 0xb4, 0x69, 0xf6, 0xe8, + 0x81, 0x23, 0xf2, 0x25, 0x74, 0x01, 0xbc, 0xfe, 0xa8, 0x90, 0x73, 0x83, 0x08, 0xee, 0xb7, 0x1b, 0xb7, 0xf1, 0x15, + 0x00, 0x6f, 0x87, 0xbd, 0xea, 0x9f, 0x16, 0xb0, 0xbf, 0x51, 0x59, 0xd2, 0x8f, 0xb7, 0x63, 0x8f, 0xff, 0x42, 0x42, + 0x74, 0x76, 0x8b, 0x87, 0x89, 0x43, 0xa7, 0x92, 0x35, 0x2b, 0x7f, 0x6e, 0x95, 0x04, 0x0c, 0xab, 0x17, 0x0c, 0xd9, + 0xb8, 0xad, 0xe2, 0x36, 0xf3, 0x3f, 0xa8, 0x60, 0xb0, 0xe0, 0x5b, 0x23, 0xa9, 0x58, 0x16, 0xbf, 0x7d, 0xea, 0xfc, + 0x57, 0x9d, 0xe3, 0xda, 0xd7, 0xb5, 0x17, 0x39, 0x87, 0x26, 0x1a, 0x72, 0x84, 0x0e, 0x0e, 0x36, 0x32, 0xe8, 0x18, + 0x00, 0x8f, 0x1c, 0xfb, 0xe5, 0x97, 0xcf, 0xb3, 0x63, 0x46, 0xf3, 0x58, 0x44, 0x21, 0x73, 0xe7, 0xb9, 0x39, 0x3b, + 0x91, 0x27, 0x54, 0x4d, 0x7d, 0x61, 0x80, 0xe3, 0xa3, 0xad, 0x54, 0xc0, 0xf7, 0x68, 0xbd, 0x63, 0x02, 0x1b, 0xfc, + 0x96, 0x9d, 0xd4, 0xae, 0x82, 0x7e, 0x81, 0x96, 0xbb, 0x98, 0xca, 0x8d, 0x05, 0x8e, 0x36, 0x27, 0xb2, 0x73, 0xe8, + 0x1b, 0x75, 0x4a, 0xd6, 0xe3, 0xc9, 0x6e, 0xa3, 0x2f, 0x29, 0x76, 0x25, 0x57, 0xb4, 0x6d, 0xc8, 0xaa, 0x57, 0x79, + 0x75, 0x65, 0xea, 0x54, 0x5d, 0xf3, 0x56, 0x96, 0x36, 0xa5, 0x5d, 0x92, 0xbd, 0xdb, 0x62, 0xe1, 0x55, 0x78, 0xa3, + 0x51, 0x5e, 0x84, 0x82, 0x3d, 0x96, 0x18, 0x74, 0x39, 0x81, 0xeb, 0x85, 0xd5, 0x2a, 0x86, 0x3f, 0xbb, 0xc6, 0xb0, + 0xcb, 0x74, 0xe9, 0x03, 0xdf, 0xe0, 0x57, 0x82, 0xc0, 0xc0, 0xce, 0x0e, 0x12, 0xac, 0xbb, 0xdc, 0xa0, 0xe1, 0x38, + 0xf1, 0x5f, 0xf0, 0x2c, 0xb5, 0xf6, 0x2e, 0x07, 0x93, 0xec, 0x1b, 0x4f, 0xd9, 0x95, 0xac, 0x65, 0x2d, 0xaa, 0xfc, + 0x86, 0x04, 0x43, 0xec, 0xa6, 0x74, 0x8e, 0x5b, 0x49, 0x1b, 0x45, 0xae, 0x58, 0x85, 0xfe, 0xdf, 0x2a, 0x92, 0xd9, + 0xcc, 0xff, 0x3a, 0x3b, 0x3b, 0x73, 0x29, 0xce, 0xe6, 0x4f, 0x19, 0x0f, 0x38, 0x93, 0xc0, 0xbe, 0xf0, 0x8c, 0x19, + 0x1d, 0xf2, 0x5b, 0x18, 0x0a, 0x11, 0xe4, 0x52, 0x38, 0x76, 0x09, 0x5e, 0x55, 0x04, 0xca, 0x03, 0xec, 0xdf, 0x93, + 0x8d, 0x72, 0xfe, 0x59, 0x26, 0x1f, 0xb6, 0xb8, 0x6c, 0x90, 0x7d, 0x31, 0x9f, 0x7d, 0x6b, 0x26, 0x03, 0x2f, 0x11, + 0x44, 0xd8, 0xfe, 0x36, 0x2c, 0xad, 0xb3, 0x94, 0xc1, 0x91, 0x96, 0x8b, 0x6c, 0x6a, 0x35, 0xff, 0xee, 0xc3, 0x94, + 0x75, 0x4f, 0xfa, 0x40, 0xe4, 0x2e, 0xb2, 0x74, 0xd1, 0x37, 0xa3, 0x1f, 0xcb, 0x40, 0x9b, 0x7b, 0xaf, 0xd8, 0x82, + 0xfd, 0x88, 0xf7, 0xaa, 0x14, 0xf8, 0x78, 0x58, 0x70, 0x9a, 0xff, 0x88, 0xf7, 0xaa, 0x80, 0x9b, 0xe0, 0x0a, 0x69, + 0x62, 0x56, 0x62, 0xf3, 0x7c, 0x75, 0x1a, 0x09, 0xa0, 0xa0, 0x79, 0x64, 0x0e, 0xb2, 0xe7, 0x2e, 0x46, 0x63, 0xd2, + 0xc1, 0x2e, 0x38, 0x98, 0x8d, 0xbc, 0x6a, 0x03, 0x96, 0x43, 0xdc, 0xba, 0x72, 0x36, 0xe6, 0xeb, 0xd1, 0xc6, 0x82, + 0x18, 0x65, 0x32, 0xb9, 0x7c, 0xce, 0xe3, 0xad, 0xc5, 0x42, 0x61, 0xb5, 0x60, 0x81, 0x6a, 0x55, 0xaa, 0xf4, 0xb0, + 0xf8, 0x76, 0xc1, 0x2c, 0x28, 0x62, 0xb6, 0xde, 0xc3, 0x5b, 0xae, 0x08, 0x48, 0xc9, 0x2e, 0x09, 0x5e, 0x20, 0x37, + 0x98, 0xea, 0x1f, 0x9c, 0x07, 0x42, 0xcf, 0x94, 0x8e, 0xb0, 0xc9, 0x53, 0x10, 0x49, 0x6c, 0xbf, 0x85, 0x1d, 0x6b, + 0xf4, 0x42, 0x78, 0x21, 0x05, 0xce, 0x55, 0xd3, 0xc4, 0x8c, 0x72, 0x13, 0x5d, 0xec, 0xa1, 0x9a, 0xb3, 0x4c, 0x5b, + 0x04, 0xd8, 0x77, 0x68, 0x28, 0xc5, 0x73, 0x03, 0x0a, 0xf3, 0x74, 0xb6, 0x4b, 0x79, 0x0c, 0x8b, 0x17, 0xa4, 0x00, + 0x51, 0xe3, 0x62, 0x52, 0xd6, 0x99, 0xe7, 0x8b, 0x09, 0x17, 0x15, 0x32, 0x14, 0x4c, 0xcd, 0xa5, 0x80, 0x97, 0x2b, + 0xca, 0x22, 0x86, 0x0e, 0xd5, 0xf0, 0xdd, 0x92, 0xb0, 0xb2, 0x8e, 0x39, 0xa6, 0xb8, 0xa8, 0x6a, 0x00, 0x73, 0xf1, + 0x30, 0x7c, 0xe2, 0x5e, 0xbd, 0x16, 0xef, 0xe4, 0xbc, 0xca, 0xf7, 0x34, 0xce, 0x07, 0x88, 0x77, 0x76, 0xc3, 0x68, + 0x6d, 0x1e, 0x97, 0x0a, 0xb6, 0xef, 0x07, 0x5e, 0x3d, 0xb8, 0xb6, 0x36, 0xcf, 0x53, 0x95, 0x59, 0x43, 0x56, 0xbe, + 0xc5, 0x50, 0xb5, 0x57, 0xaf, 0x2a, 0x85, 0xad, 0x08, 0x50, 0x29, 0xf8, 0x68, 0x2b, 0xff, 0x89, 0xb6, 0xf9, 0xf6, + 0x1c, 0x2a, 0xc3, 0x03, 0x79, 0x32, 0x54, 0xf5, 0x80, 0x8b, 0xf2, 0x43, 0x00, 0x8b, 0x1f, 0x99, 0x38, 0xbd, 0xbb, + 0x2e, 0x90, 0x39, 0x53, 0xb1, 0xc4, 0xcb, 0x3e, 0x1d, 0xa4, 0x56, 0x1e, 0x4a, 0x25, 0xd8, 0xf6, 0xdc, 0x14, 0x5c, + 0xfb, 0x80, 0xc0, 0xb8, 0xcf, 0x06, 0xe9, 0xb2, 0x1e, 0x34, 0xd8, 0x86, 0x2d, 0xf6, 0xe6, 0x9c, 0x26, 0xca, 0x2e, + 0x1d, 0xe0, 0x9c, 0x80, 0xed, 0xb1, 0x67, 0x4f, 0xdf, 0xc4, 0x19, 0xea, 0xd5, 0x39, 0xfc, 0xe5, 0x1a, 0xe7, 0x38, + 0x43, 0xe9, 0xc3, 0x18, 0x2e, 0xb0, 0xd6, 0x18, 0xc0, 0x97, 0x59, 0x52, 0x05, 0x1e, 0xa9, 0x99, 0x91, 0x58, 0xdd, + 0x45, 0x20, 0x5a, 0xea, 0xf0, 0x76, 0x9c, 0xf9, 0xb0, 0xdb, 0x86, 0x7b, 0x7d, 0x66, 0x84, 0xc3, 0x49, 0x16, 0xd7, + 0xce, 0x19, 0x4e, 0x2e, 0xf7, 0x79, 0xed, 0xc4, 0x04, 0x6b, 0xef, 0xf0, 0x54, 0x01, 0x3d, 0x1a, 0x9c, 0x2a, 0x96, + 0x86, 0x40, 0xcc, 0x04, 0xf0, 0x66, 0x0e, 0x8f, 0xb6, 0x00, 0xe7, 0xa3, 0x35, 0x0e, 0xbe, 0xd2, 0x5a, 0x57, 0x9b, + 0x4a, 0x94, 0xf5, 0x1a, 0xf7, 0xa7, 0x19, 0x1e, 0x65, 0x78, 0x9e, 0x0d, 0x82, 0xe3, 0x66, 0x96, 0x85, 0x26, 0x5d, + 0xab, 0xd5, 0x53, 0x67, 0x46, 0x88, 0xec, 0x4f, 0x4b, 0x7f, 0x50, 0x0f, 0x10, 0x3e, 0x85, 0x2c, 0xa0, 0x25, 0x3d, + 0xf7, 0xb7, 0x61, 0x5f, 0xe5, 0x46, 0x8d, 0x98, 0x27, 0x96, 0x8c, 0xf4, 0xfc, 0x8f, 0x32, 0xcb, 0xb6, 0xd6, 0x88, + 0xe6, 0xb7, 0x7b, 0x51, 0xc3, 0xb7, 0x17, 0x68, 0xd9, 0x4a, 0xb3, 0x1d, 0x40, 0x14, 0x6b, 0x9c, 0xa4, 0x83, 0x35, + 0x92, 0xab, 0x55, 0x6c, 0x53, 0x08, 0x4f, 0x66, 0x8c, 0xaa, 0x45, 0x61, 0x1e, 0xaa, 0x8b, 0x15, 0x4a, 0x0c, 0xbf, + 0x8b, 0x9d, 0x8d, 0x28, 0xbc, 0x0b, 0x27, 0xc1, 0x70, 0x23, 0x16, 0x44, 0xd6, 0x44, 0xee, 0x61, 0x56, 0x59, 0x06, + 0x09, 0x22, 0x8c, 0xc8, 0x6f, 0xaf, 0x4b, 0x85, 0x7d, 0x0a, 0xcf, 0xfe, 0x31, 0xbe, 0x80, 0x70, 0xf3, 0x36, 0xa1, + 0xc5, 0x90, 0x4e, 0x80, 0x8d, 0x85, 0x38, 0x84, 0x5b, 0x09, 0xab, 0x55, 0x7f, 0xd0, 0x15, 0x86, 0x3c, 0xbb, 0x87, + 0xfa, 0xca, 0x86, 0x76, 0x37, 0x00, 0x57, 0xdd, 0x96, 0x9a, 0x6b, 0xa3, 0xfb, 0xa1, 0xe6, 0x2d, 0x31, 0xee, 0x92, + 0xdc, 0x73, 0x20, 0xd5, 0x8b, 0xdf, 0x35, 0x0b, 0x70, 0x13, 0xba, 0x0a, 0x8f, 0xf0, 0xc2, 0xda, 0x70, 0x9a, 0x87, + 0xa3, 0xa8, 0x79, 0x2f, 0x0a, 0x9e, 0xa9, 0x26, 0xac, 0x9f, 0x0d, 0xf0, 0xc8, 0x87, 0x15, 0xdf, 0x7f, 0x1b, 0x8f, + 0x10, 0x2a, 0x88, 0x81, 0xa9, 0x75, 0xd9, 0x1e, 0x55, 0x76, 0xfb, 0x26, 0xd3, 0x30, 0x0c, 0xc6, 0x88, 0x79, 0x14, + 0x1a, 0x31, 0xe7, 0x8d, 0x06, 0x5a, 0x90, 0x11, 0x18, 0x31, 0x2f, 0x82, 0xd6, 0x16, 0xf6, 0x51, 0xd1, 0xa0, 0xbd, + 0x05, 0x42, 0x5d, 0x0e, 0x34, 0x4d, 0xc3, 0xf3, 0x21, 0xd5, 0xf3, 0xed, 0xfe, 0x31, 0xab, 0xa3, 0x0e, 0x28, 0x12, + 0xc6, 0x97, 0x7e, 0x12, 0xd6, 0x35, 0xdc, 0x8e, 0x7b, 0x6c, 0xc6, 0xed, 0x6c, 0x1b, 0x54, 0x5f, 0xf6, 0xb3, 0xc1, + 0xa0, 0x2b, 0xbd, 0x95, 0x44, 0x0b, 0x8f, 0xab, 0x07, 0x47, 0xaa, 0xc5, 0xfb, 0xa2, 0x37, 0xaf, 0xbc, 0xb9, 0x7f, + 0xc7, 0x74, 0xf3, 0x3c, 0x06, 0x0e, 0x68, 0x1f, 0xee, 0x87, 0xaa, 0xf8, 0x60, 0x47, 0x1d, 0x88, 0x82, 0x96, 0xb6, + 0x6a, 0x02, 0xa9, 0x35, 0xb3, 0x8b, 0x75, 0x53, 0xa1, 0x43, 0x01, 0x61, 0xc8, 0x54, 0xd5, 0xdd, 0x9d, 0x0a, 0x54, + 0x43, 0x1c, 0x4e, 0xfd, 0xc7, 0xd6, 0x88, 0x35, 0x8e, 0x3a, 0xa3, 0xc8, 0x18, 0x49, 0xda, 0xe5, 0x83, 0x37, 0x86, + 0xc0, 0x4a, 0xc0, 0xc7, 0x7a, 0x36, 0x49, 0xc6, 0x90, 0xe0, 0x2d, 0xcb, 0xb4, 0xe1, 0x43, 0xb8, 0x43, 0x50, 0x9e, + 0xd8, 0xa0, 0xb4, 0xae, 0x92, 0x85, 0x5c, 0xd5, 0xe5, 0x75, 0x80, 0x9e, 0x77, 0xe5, 0x6f, 0x6c, 0x38, 0xb2, 0x60, + 0x60, 0xd9, 0xd6, 0x3e, 0x01, 0x8f, 0x7c, 0x5c, 0x21, 0x88, 0x5f, 0x0a, 0x9d, 0x98, 0xb8, 0xd8, 0x57, 0xb0, 0x41, + 0xf1, 0x1c, 0x1c, 0x04, 0x9d, 0x04, 0x87, 0xc1, 0xbb, 0xcc, 0x6a, 0x92, 0x0d, 0x6e, 0xcd, 0x48, 0x3c, 0x5f, 0xad, + 0x5a, 0xe8, 0xf0, 0x1f, 0xf3, 0xf4, 0xf3, 0xb8, 0x54, 0xb8, 0x8f, 0x2b, 0x85, 0x3b, 0x58, 0x02, 0x92, 0x71, 0xa0, + 0x6b, 0xc7, 0x32, 0x54, 0xa3, 0x43, 0x54, 0xf2, 0x17, 0x10, 0xa3, 0xda, 0x1d, 0x4b, 0xa0, 0x67, 0xdf, 0x2a, 0x60, + 0x75, 0xed, 0x65, 0x09, 0x64, 0x04, 0x77, 0xbf, 0x09, 0x8c, 0x0a, 0xd1, 0xf8, 0xfc, 0x99, 0xd7, 0x23, 0x78, 0xe2, + 0xfc, 0xb9, 0x66, 0x86, 0x75, 0x2f, 0xe8, 0x8d, 0x69, 0x3e, 0x1e, 0xe3, 0xe6, 0xd8, 0x82, 0xf3, 0xa8, 0x03, 0x3f, + 0x2d, 0x44, 0x8f, 0x3a, 0xd8, 0xa5, 0xe2, 0x71, 0x09, 0xe4, 0x10, 0x3d, 0x9d, 0x81, 0x14, 0xb0, 0xd2, 0xb1, 0xd5, + 0x22, 0x4d, 0xd0, 0x6a, 0x35, 0xb9, 0x20, 0x2d, 0x84, 0x96, 0xea, 0x86, 0xeb, 0x6c, 0x0a, 0x3e, 0xd2, 0xa0, 0x18, + 0x78, 0x43, 0xf5, 0x34, 0x46, 0x78, 0x8c, 0x96, 0x23, 0x36, 0xa6, 0x8b, 0x5c, 0xa7, 0xaa, 0xc7, 0x13, 0x1b, 0xb8, + 0x97, 0xd9, 0x48, 0x70, 0x47, 0x1d, 0x3c, 0x31, 0xfc, 0xe5, 0x23, 0x63, 0x0e, 0x52, 0x64, 0x26, 0x79, 0x62, 0x12, + 0x30, 0x4f, 0xb2, 0x5c, 0x2a, 0x66, 0x9b, 0xe9, 0x5a, 0xdb, 0x72, 0x08, 0xfd, 0x1d, 0xe9, 0x82, 0x1b, 0x2b, 0xca, + 0x28, 0x9d, 0x12, 0xd5, 0x53, 0x47, 0x9d, 0x74, 0x82, 0x79, 0x02, 0x9c, 0xde, 0x3b, 0x19, 0xb3, 0x46, 0x79, 0x2b, + 0x3a, 0x43, 0x87, 0x53, 0x2c, 0xaa, 0x4b, 0xd4, 0x19, 0x3a, 0x9c, 0x20, 0x3c, 0x6b, 0x90, 0x5c, 0x81, 0xc7, 0x30, + 0x17, 0xff, 0x47, 0xca, 0x7f, 0x73, 0xd8, 0x10, 0x62, 0xfa, 0x2d, 0xec, 0x14, 0x36, 0x8a, 0xd2, 0x9c, 0x80, 0xd7, + 0x62, 0xfb, 0x0c, 0x67, 0x64, 0xd2, 0xcc, 0x7d, 0xc0, 0x3d, 0xd3, 0x4a, 0xe3, 0x56, 0xa3, 0xc3, 0x0c, 0x8f, 0x36, + 0x93, 0x62, 0x33, 0xd7, 0x66, 0x9e, 0x66, 0x70, 0xbe, 0x57, 0xa3, 0x70, 0xe5, 0x17, 0x9b, 0x49, 0x61, 0x79, 0x07, + 0xdc, 0xe6, 0x08, 0x8b, 0x26, 0xc5, 0x39, 0x9e, 0x35, 0xbf, 0xe2, 0x59, 0xf3, 0x43, 0x99, 0xd1, 0x58, 0x60, 0x01, + 0xc1, 0xfb, 0x20, 0x11, 0xcf, 0xaa, 0xe4, 0x11, 0x16, 0x0d, 0x53, 0x1e, 0xcf, 0x1a, 0x55, 0xe9, 0xe6, 0x02, 0x8b, + 0x86, 0x29, 0xdd, 0xf8, 0x80, 0x67, 0x8d, 0xaf, 0xff, 0x62, 0xd2, 0x51, 0x0a, 0xe8, 0x32, 0x47, 0xcb, 0xcc, 0x0e, + 0xf1, 0xea, 0xb7, 0xb7, 0xef, 0xda, 0xd7, 0x9d, 0xc3, 0x09, 0xf6, 0xeb, 0x97, 0x19, 0x1c, 0xcb, 0x74, 0xcc, 0x9a, + 0x00, 0xd1, 0x0c, 0x77, 0x0e, 0xa7, 0xb8, 0x73, 0x98, 0xb9, 0xa6, 0xd6, 0xb3, 0x06, 0xb9, 0xd5, 0x21, 0x14, 0x75, + 0x94, 0x86, 0xf0, 0xf1, 0x93, 0x4d, 0x27, 0xa8, 0x06, 0x4a, 0x74, 0x38, 0xa9, 0x81, 0x0a, 0xbe, 0x17, 0xb5, 0xef, + 0xaa, 0x5e, 0x85, 0x41, 0x16, 0x4a, 0x28, 0x5c, 0x73, 0x03, 0x9e, 0x5a, 0x8a, 0x81, 0x4c, 0x98, 0x62, 0x81, 0xf2, + 0x1d, 0x50, 0x18, 0xe5, 0x89, 0x19, 0x7a, 0x30, 0x1d, 0x93, 0xf8, 0xff, 0xf3, 0x64, 0xca, 0xa1, 0x97, 0x5b, 0x66, + 0x6b, 0x7a, 0x6e, 0x32, 0xe1, 0xf0, 0x81, 0xc7, 0xfa, 0xbf, 0x76, 0xa0, 0xd8, 0x80, 0x14, 0xff, 0x5f, 0x3a, 0xba, + 0x10, 0x8c, 0x90, 0x15, 0xa5, 0x85, 0x43, 0xfc, 0xef, 0x0f, 0x2b, 0xe8, 0xbe, 0xd8, 0xea, 0xbe, 0x30, 0xdd, 0x87, + 0x4d, 0x1b, 0x55, 0x4e, 0x5a, 0x55, 0xb2, 0xe4, 0xbf, 0x4e, 0xb7, 0xb6, 0x40, 0x23, 0x6a, 0xf4, 0x6c, 0x12, 0x36, + 0xb8, 0xdf, 0x4e, 0x77, 0x20, 0xf3, 0x9a, 0xdb, 0x97, 0x48, 0xe1, 0xf0, 0x0d, 0xee, 0x54, 0x2f, 0x5b, 0xe0, 0xbd, + 0xa9, 0x8c, 0xbe, 0x32, 0x0e, 0x2d, 0x07, 0xe9, 0xa6, 0x29, 0xb7, 0x31, 0x96, 0x4e, 0x4e, 0xb1, 0x71, 0x45, 0x84, + 0x4a, 0xb7, 0x97, 0xa0, 0x14, 0x1f, 0xeb, 0x26, 0x33, 0x5f, 0x17, 0x3a, 0x31, 0x97, 0x50, 0x0d, 0xf3, 0x79, 0x77, + 0xa9, 0x13, 0x2d, 0xe7, 0x36, 0xef, 0xee, 0x02, 0xfa, 0x04, 0x0d, 0x6b, 0x23, 0xb0, 0xdb, 0x67, 0x85, 0xd3, 0xef, + 0x54, 0x87, 0x60, 0x78, 0x00, 0x39, 0xd2, 0x62, 0xfb, 0xc0, 0xa6, 0x35, 0xec, 0xba, 0x68, 0x96, 0x89, 0xb6, 0xd5, + 0xa6, 0xc9, 0xb5, 0x7b, 0x98, 0xcf, 0x43, 0x9e, 0x82, 0x17, 0x56, 0x3f, 0xbe, 0x83, 0xdd, 0xb8, 0xad, 0x31, 0x12, + 0x75, 0x25, 0x53, 0x09, 0xfd, 0xe4, 0x16, 0xb3, 0xe4, 0xce, 0x78, 0x31, 0x2a, 0xe3, 0xef, 0x63, 0xe2, 0xf2, 0x47, + 0x95, 0x24, 0x07, 0x96, 0xfd, 0x0d, 0x96, 0xdc, 0x82, 0x79, 0x62, 0x59, 0x4d, 0x62, 0x9d, 0xdc, 0x05, 0x8b, 0x28, + 0x4d, 0x23, 0x6b, 0xc3, 0x80, 0x9a, 0x66, 0xac, 0x7a, 0x70, 0x1f, 0x02, 0x3d, 0xf4, 0xca, 0x52, 0xda, 0x75, 0x96, + 0xd6, 0xba, 0xd7, 0xa6, 0xfb, 0xcd, 0x01, 0x05, 0x7c, 0x61, 0xc0, 0x35, 0xfd, 0xab, 0x49, 0x24, 0x43, 0xf6, 0x95, + 0xb3, 0xe2, 0xf1, 0xa2, 0x30, 0x98, 0x26, 0x7a, 0x3a, 0xc9, 0xe6, 0x6d, 0x30, 0xd5, 0xcb, 0xe6, 0x9d, 0x5b, 0xec, + 0xbe, 0xef, 0xec, 0xf7, 0x1d, 0x16, 0x3d, 0x66, 0x32, 0x52, 0x66, 0x8a, 0xf9, 0xef, 0x3b, 0xfb, 0x7d, 0x87, 0xb7, + 0x07, 0x73, 0xe3, 0x2f, 0x14, 0x4b, 0x76, 0x86, 0x4b, 0x30, 0x21, 0x0f, 0xb8, 0x9b, 0x5a, 0x96, 0x09, 0x02, 0x5b, + 0x4b, 0x80, 0x38, 0x9f, 0x4f, 0xe3, 0x8a, 0x57, 0x43, 0xc0, 0x7d, 0x7a, 0xd7, 0xf6, 0x2a, 0x15, 0x78, 0x4c, 0xd0, + 0x88, 0x98, 0xd8, 0x36, 0xe6, 0x15, 0x31, 0xe0, 0xf2, 0x88, 0x2e, 0xf5, 0x24, 0x09, 0xf0, 0xaa, 0x46, 0xe5, 0x6d, + 0x8a, 0x94, 0x5f, 0x24, 0xc8, 0xf1, 0xc5, 0x1e, 0x51, 0xc5, 0x00, 0x56, 0x65, 0x49, 0x9f, 0x40, 0xea, 0xf9, 0xc1, + 0x44, 0x3f, 0x6f, 0x22, 0x8f, 0x7d, 0x4f, 0xf7, 0x33, 0xd3, 0xd3, 0x42, 0x2e, 0x26, 0x53, 0xf0, 0xa1, 0x05, 0x96, + 0xa1, 0x30, 0xf5, 0x2a, 0x5b, 0xff, 0x9a, 0xe4, 0x26, 0x80, 0xc2, 0xe9, 0xa6, 0x4c, 0x68, 0xa6, 0x17, 0x34, 0x37, + 0x96, 0xa4, 0x5c, 0x4c, 0x1e, 0xc9, 0xdb, 0x97, 0x80, 0xdd, 0x94, 0xe8, 0xc6, 0x8e, 0xbc, 0xb7, 0xb0, 0x03, 0x70, + 0x46, 0xd8, 0xae, 0x8a, 0x0f, 0x15, 0xe8, 0xfc, 0x71, 0x4e, 0xd8, 0xae, 0xaa, 0x4f, 0x98, 0xcd, 0x9e, 0x92, 0x8d, + 0xe1, 0xf6, 0xe2, 0xac, 0x91, 0xa3, 0xa3, 0x4e, 0x9a, 0x77, 0x3d, 0x31, 0xb0, 0x00, 0x0d, 0x80, 0xbb, 0xb5, 0x3d, + 0xcb, 0xbb, 0x1b, 0x02, 0x7a, 0x97, 0x4c, 0xda, 0xeb, 0x72, 0x93, 0xb2, 0x5a, 0x75, 0x2a, 0x2a, 0x58, 0xe0, 0x69, + 0xb0, 0x17, 0xa8, 0xfd, 0xda, 0x41, 0x71, 0xae, 0xb2, 0x4d, 0xd3, 0xf3, 0xb2, 0xef, 0xee, 0x8e, 0x45, 0xc6, 0x36, + 0xed, 0xed, 0x0e, 0x22, 0x61, 0x39, 0x61, 0x1d, 0x70, 0xc2, 0x55, 0xed, 0x80, 0x00, 0x5d, 0x07, 0x22, 0x37, 0x96, + 0x64, 0xb9, 0xae, 0x8c, 0xee, 0x03, 0xbf, 0x5b, 0x4a, 0xa4, 0x1b, 0x6d, 0x49, 0x30, 0x7d, 0x82, 0x51, 0xd3, 0x99, + 0x27, 0xa0, 0x6b, 0xaf, 0x1b, 0x6f, 0x8a, 0xb6, 0xfe, 0xad, 0x65, 0x6c, 0xb6, 0x87, 0x89, 0xa1, 0x0c, 0x62, 0xa0, + 0xf7, 0x11, 0xef, 0x36, 0x1a, 0x19, 0x02, 0x85, 0x4c, 0x36, 0xc0, 0x32, 0xf1, 0x5a, 0xf4, 0x83, 0x03, 0x03, 0x8f, + 0x2a, 0x01, 0x61, 0x0a, 0x42, 0x48, 0xd8, 0xb5, 0x41, 0xd8, 0x70, 0xb9, 0x6a, 0xb9, 0xb0, 0x91, 0x6a, 0x43, 0x07, + 0xff, 0xaf, 0x70, 0xd9, 0xea, 0x99, 0xe5, 0xa2, 0x18, 0xdc, 0xcc, 0x0d, 0x58, 0x24, 0x48, 0x8f, 0x36, 0xdb, 0x43, + 0x71, 0x77, 0x2e, 0x36, 0x1b, 0x02, 0x12, 0x73, 0x98, 0xa0, 0x68, 0x38, 0x37, 0xc6, 0x58, 0x25, 0x95, 0x96, 0xb5, + 0x26, 0x31, 0x07, 0xbe, 0x74, 0xe1, 0xba, 0x2f, 0x6f, 0x53, 0x86, 0xef, 0x52, 0x81, 0x6f, 0xc0, 0x93, 0x26, 0x95, + 0xd8, 0x3d, 0x5e, 0x50, 0xac, 0x89, 0xee, 0x7a, 0xf6, 0xb6, 0x80, 0x75, 0x36, 0x7b, 0x44, 0x04, 0xbf, 0xab, 0x5f, + 0x6d, 0xf0, 0xdd, 0xc2, 0x5f, 0xc1, 0xfa, 0x39, 0x38, 0x49, 0xb1, 0x68, 0xc8, 0x66, 0xe1, 0x8e, 0x0c, 0x28, 0x57, + 0xf1, 0xcb, 0x61, 0xea, 0x56, 0x31, 0x5c, 0xfb, 0xf8, 0x8a, 0x3f, 0x6c, 0xb4, 0xdb, 0x50, 0x65, 0x71, 0xbb, 0x37, + 0x45, 0x43, 0x56, 0x4d, 0xef, 0xc8, 0xdc, 0x48, 0xa9, 0x7f, 0x7d, 0xc0, 0xad, 0xad, 0xf6, 0xfd, 0x34, 0xdf, 0x7a, + 0x74, 0xae, 0x9a, 0xf6, 0xa9, 0xb5, 0x22, 0x38, 0xf8, 0xd9, 0xc2, 0xcd, 0xad, 0x01, 0x07, 0xf0, 0xf3, 0x77, 0x34, + 0x8f, 0x33, 0x88, 0x4e, 0x6f, 0x35, 0xe3, 0xab, 0xf8, 0xaf, 0x51, 0x23, 0xee, 0xa5, 0x7f, 0x25, 0x7f, 0x8d, 0x1a, + 0xa8, 0x87, 0xe2, 0xf9, 0xed, 0x8a, 0xcd, 0x56, 0x10, 0x6c, 0xed, 0xde, 0x11, 0x7e, 0x1d, 0x96, 0xe4, 0x9a, 0xe6, + 0x3c, 0x5b, 0xb9, 0x87, 0xf7, 0x56, 0xee, 0x55, 0xa2, 0x95, 0x79, 0x4b, 0x6a, 0x15, 0xcb, 0x61, 0x0e, 0x81, 0x85, + 0xe3, 0xbd, 0x66, 0xaf, 0xdf, 0x6a, 0x3e, 0x18, 0xd8, 0x7f, 0x4d, 0x84, 0x7b, 0x54, 0x8b, 0xd8, 0xf6, 0x66, 0x63, + 0xeb, 0xc7, 0x60, 0xd8, 0x01, 0xa1, 0xc0, 0x41, 0x2e, 0x7d, 0x9c, 0x21, 0xeb, 0x7b, 0xb2, 0x5a, 0x31, 0x17, 0xcd, + 0xda, 0x69, 0xf0, 0xcb, 0xd8, 0x4c, 0x87, 0xed, 0xa4, 0xd3, 0xf5, 0x62, 0x2c, 0x69, 0x40, 0xa4, 0x69, 0xcc, 0x20, + 0x90, 0xd4, 0xd2, 0x70, 0x58, 0xf3, 0xdb, 0x28, 0xad, 0xee, 0x8f, 0x20, 0xe5, 0x87, 0x28, 0xe5, 0x47, 0x04, 0x02, + 0x68, 0x5b, 0xe6, 0xa8, 0x6c, 0xc8, 0xfb, 0x2e, 0xdd, 0x33, 0xce, 0x0c, 0x0d, 0xbe, 0x5a, 0xb5, 0xaa, 0x61, 0x8a, + 0xa2, 0x3e, 0xcc, 0xe5, 0x1a, 0x0b, 0xf2, 0x06, 0x74, 0xcd, 0x8a, 0x88, 0x5e, 0xe8, 0x2a, 0x0f, 0xef, 0x0e, 0x63, + 0x49, 0xc0, 0x49, 0xbf, 0x27, 0x7a, 0x05, 0xb9, 0x7c, 0x18, 0x83, 0x8f, 0x19, 0xe6, 0x7d, 0xdd, 0x2f, 0x06, 0x03, + 0x94, 0x3a, 0xa7, 0xb3, 0xd4, 0x44, 0x5c, 0x09, 0xfc, 0x92, 0x0b, 0xf0, 0x4b, 0x56, 0x88, 0xf5, 0x8b, 0x01, 0xb9, + 0x97, 0xc5, 0x12, 0x9c, 0xf2, 0x77, 0xf8, 0x3c, 0x3e, 0x0c, 0x0d, 0x4c, 0xcd, 0xb0, 0xcc, 0x45, 0x36, 0x58, 0xcc, + 0x59, 0x4b, 0x20, 0xb8, 0x19, 0x70, 0x97, 0xda, 0x90, 0x68, 0xac, 0x81, 0xa2, 0xdb, 0x28, 0x34, 0x33, 0x7a, 0xba, + 0xd5, 0x46, 0x3f, 0x72, 0x78, 0x61, 0xae, 0x61, 0x2c, 0x02, 0x99, 0xcb, 0x55, 0x8f, 0xfd, 0xe5, 0x87, 0xcd, 0x0a, + 0x83, 0x57, 0x64, 0x3a, 0x74, 0xc7, 0x31, 0xe3, 0xab, 0x3c, 0x71, 0x0c, 0x41, 0x26, 0x96, 0x4a, 0x37, 0x1c, 0x13, + 0x57, 0xd2, 0x67, 0x62, 0xc8, 0x76, 0xc3, 0x33, 0x73, 0xa1, 0x9b, 0xed, 0x1f, 0xce, 0xed, 0x9c, 0x13, 0x6e, 0xb4, + 0x92, 0x46, 0x1b, 0xf5, 0xcc, 0x50, 0x55, 0x17, 0xcc, 0xef, 0xa1, 0xd3, 0xd2, 0x62, 0xe7, 0xea, 0xdd, 0x0d, 0x5f, + 0xc1, 0x2b, 0xe3, 0x6f, 0xb1, 0x2a, 0xb4, 0x22, 0xc3, 0xed, 0x16, 0xf2, 0xe6, 0x4c, 0x0f, 0xbd, 0x22, 0x17, 0xaa, + 0xc3, 0x5f, 0xd4, 0x15, 0xe6, 0x61, 0xcc, 0xa8, 0x21, 0x3c, 0xfa, 0xbd, 0xce, 0x40, 0xf9, 0x07, 0x13, 0x93, 0x39, + 0x4b, 0x6e, 0x68, 0x21, 0xe2, 0x1f, 0x5f, 0x08, 0x13, 0xab, 0x6a, 0x0f, 0x06, 0xb2, 0x67, 0x2a, 0xee, 0xc1, 0xad, + 0x09, 0x1f, 0x73, 0x36, 0x4a, 0xf7, 0xa2, 0x1f, 0x1b, 0xa2, 0xf1, 0x63, 0xf4, 0x23, 0xb8, 0x3b, 0xbb, 0x57, 0x18, + 0xcb, 0xb8, 0x10, 0xfe, 0x1e, 0xeb, 0x61, 0xa9, 0x52, 0xc6, 0xda, 0xeb, 0x96, 0xc3, 0x0b, 0xa9, 0x37, 0x59, 0xfc, + 0xd0, 0x11, 0x6b, 0x9b, 0x82, 0x75, 0x48, 0x49, 0xe1, 0xd9, 0x15, 0x73, 0xab, 0xc5, 0xdc, 0xa5, 0x96, 0xf0, 0xd7, + 0x57, 0x0f, 0x4b, 0x15, 0x34, 0x1c, 0x84, 0xae, 0xb4, 0x85, 0x04, 0x18, 0xb8, 0x94, 0x3e, 0x9d, 0xee, 0x4c, 0x22, + 0xb3, 0x2c, 0x86, 0x77, 0x0f, 0x2a, 0x98, 0xff, 0xce, 0x36, 0xc2, 0xaa, 0xc0, 0xe5, 0x4a, 0x15, 0xf5, 0x52, 0x12, + 0x08, 0x40, 0x5f, 0x7a, 0x0f, 0xca, 0x8b, 0xa2, 0xdb, 0x68, 0x48, 0xd0, 0xc2, 0x52, 0x73, 0xad, 0x8a, 0xe9, 0x7e, + 0xf8, 0x7a, 0x60, 0xf0, 0xe1, 0x1d, 0xd2, 0x36, 0x9e, 0xf0, 0xa4, 0x84, 0xda, 0x1d, 0xb4, 0x0f, 0x56, 0xd9, 0x41, + 0xf9, 0xb7, 0x31, 0x45, 0x36, 0xbf, 0xcf, 0x7e, 0xa0, 0xae, 0xc3, 0x81, 0x2b, 0x58, 0xf5, 0x52, 0x46, 0xc1, 0x80, + 0x95, 0x53, 0xa0, 0xf6, 0x4e, 0x32, 0x9a, 0x4d, 0x19, 0xa8, 0xfb, 0x6d, 0xd1, 0x6a, 0x6e, 0x4f, 0xea, 0x7e, 0x43, + 0xc6, 0xd9, 0x47, 0x18, 0x67, 0x1f, 0x05, 0x5e, 0x2c, 0x92, 0xfc, 0x21, 0x63, 0x8d, 0x63, 0xd5, 0x14, 0xe8, 0xa8, + 0x03, 0xdc, 0x19, 0x38, 0xf0, 0x80, 0x2d, 0xca, 0xc1, 0x01, 0x75, 0x16, 0xf7, 0xb4, 0x91, 0x79, 0x6f, 0x4f, 0xa8, + 0x5d, 0xc4, 0x02, 0x37, 0x6b, 0x66, 0x5a, 0xd0, 0x5a, 0x61, 0x9c, 0xc7, 0x03, 0xde, 0xe6, 0x59, 0x2d, 0x7e, 0xc2, + 0x86, 0x35, 0x55, 0xfd, 0x06, 0x9a, 0xa3, 0x5a, 0x90, 0x9b, 0x27, 0xc6, 0x5b, 0x95, 0xf4, 0xa3, 0x68, 0x60, 0x39, + 0x15, 0x62, 0x48, 0x46, 0xbf, 0x35, 0x08, 0x6e, 0xb5, 0x57, 0x2b, 0xee, 0x11, 0x5f, 0xd4, 0xbc, 0xd5, 0xcc, 0x2d, + 0x00, 0x2d, 0xe2, 0xa8, 0xbc, 0x37, 0x89, 0xc0, 0xfb, 0xb6, 0x8c, 0x90, 0xb6, 0xec, 0xdb, 0x27, 0x22, 0x4b, 0xc5, + 0xe6, 0x3b, 0x3a, 0x19, 0xa4, 0x91, 0x1d, 0x51, 0x84, 0xaf, 0x4b, 0x48, 0xc2, 0x55, 0xd2, 0xb5, 0xca, 0xe4, 0x9c, + 0xa9, 0x94, 0xe3, 0xeb, 0x42, 0x4a, 0x7d, 0x65, 0xbf, 0x24, 0xae, 0xee, 0x64, 0x04, 0xbe, 0x9e, 0x30, 0xfd, 0x8e, + 0x16, 0x13, 0x06, 0x7e, 0x45, 0xfe, 0x76, 0x2c, 0xa5, 0xe4, 0xf2, 0x89, 0x88, 0xfb, 0x14, 0xc3, 0xfb, 0xa6, 0x03, + 0xac, 0x4d, 0x08, 0x94, 0x12, 0x17, 0xe1, 0x82, 0xe8, 0x4d, 0x21, 0x6f, 0xef, 0xe2, 0x02, 0x3b, 0x07, 0xc0, 0xd2, + 0x69, 0x12, 0xe0, 0x5f, 0x3e, 0xe6, 0x63, 0x35, 0xe6, 0xd4, 0xe8, 0xfa, 0xdd, 0xef, 0xe4, 0x1a, 0xe8, 0x6d, 0xe9, + 0x28, 0xd8, 0x6f, 0x0d, 0x20, 0x17, 0xee, 0xc2, 0xe0, 0xe2, 0x2b, 0xac, 0x2d, 0x0b, 0xe3, 0x8d, 0x05, 0xd0, 0xfb, + 0x3b, 0x03, 0x0b, 0x36, 0xcc, 0x31, 0x85, 0xc7, 0x61, 0x27, 0x4c, 0x07, 0x51, 0x41, 0x9e, 0x94, 0xcf, 0x7f, 0xd6, + 0x6a, 0xbf, 0x65, 0x63, 0xb8, 0xc3, 0x48, 0xbe, 0x5d, 0x38, 0x71, 0xe0, 0x01, 0x99, 0x26, 0xb3, 0xcd, 0xbe, 0xf1, + 0x91, 0x47, 0x5e, 0x8f, 0xe3, 0x5d, 0x2d, 0x85, 0xf9, 0x66, 0x45, 0xd7, 0x18, 0x42, 0x51, 0x84, 0xfd, 0x7e, 0x51, + 0x31, 0x45, 0x95, 0x41, 0x1b, 0x34, 0x2c, 0x6f, 0xc4, 0x2f, 0x70, 0xc6, 0xd0, 0x7a, 0x21, 0x7b, 0x47, 0x67, 0x1d, + 0xce, 0x1c, 0x66, 0x4c, 0x09, 0x8c, 0x4a, 0xcb, 0x82, 0x4e, 0xc0, 0xd1, 0xb9, 0xfa, 0x20, 0x2a, 0xae, 0x8e, 0x15, + 0x80, 0x27, 0x99, 0xc2, 0x3f, 0xf9, 0x26, 0x58, 0xf7, 0x5b, 0x35, 0xc3, 0xd4, 0x5f, 0xf4, 0xb6, 0x6b, 0xf9, 0x32, + 0xc4, 0x91, 0x36, 0x86, 0xd0, 0x3a, 0xb7, 0x77, 0x80, 0x22, 0x2e, 0xe8, 0x45, 0xaa, 0xf1, 0xb5, 0x5a, 0x0c, 0xcd, + 0xfa, 0x1a, 0xd7, 0x31, 0x6d, 0x10, 0xc5, 0xba, 0x6b, 0xe2, 0xeb, 0xea, 0xb5, 0x55, 0x95, 0x2a, 0x38, 0x83, 0x04, + 0xc2, 0xaa, 0xbc, 0x6c, 0x48, 0x25, 0xb9, 0x34, 0x9d, 0x4a, 0xd3, 0x69, 0x85, 0x50, 0x2e, 0x3d, 0x29, 0xef, 0x5f, + 0x21, 0x84, 0x81, 0x29, 0xb3, 0x03, 0xab, 0xd4, 0x16, 0x56, 0xc1, 0xab, 0x17, 0x1b, 0x58, 0x25, 0xe1, 0x78, 0x2e, + 0xd1, 0xa8, 0xa8, 0x70, 0xc8, 0x90, 0xbe, 0x10, 0x8b, 0x20, 0x01, 0xb0, 0xe8, 0x5d, 0xe6, 0xf2, 0xbe, 0x87, 0x43, + 0x61, 0x4f, 0x32, 0x09, 0xa7, 0x9b, 0xd0, 0x1c, 0x9e, 0xe1, 0x55, 0x3d, 0x8f, 0x10, 0xb0, 0xf4, 0x1c, 0xc3, 0xf3, + 0xcb, 0xdf, 0x7f, 0xf6, 0xd5, 0x59, 0x90, 0xa7, 0xff, 0x12, 0x25, 0xa1, 0xb1, 0xff, 0x1c, 0x0f, 0x1d, 0x12, 0x86, + 0x03, 0xdf, 0x1c, 0x61, 0x85, 0x83, 0x5b, 0x45, 0x7c, 0x06, 0x77, 0xf8, 0x58, 0x87, 0x1e, 0x00, 0x96, 0x50, 0x1c, + 0x82, 0x7c, 0x03, 0xc5, 0x0c, 0x0e, 0x68, 0xb2, 0x0c, 0x2f, 0x70, 0xc1, 0x6a, 0xa1, 0xbc, 0xbf, 0x6d, 0x79, 0x29, + 0xad, 0x76, 0xc9, 0x6b, 0xcc, 0x81, 0xca, 0xcf, 0xf0, 0xc2, 0x57, 0x98, 0x77, 0xa1, 0xdd, 0x17, 0xbe, 0x76, 0x40, + 0x4f, 0x21, 0x60, 0xa4, 0xfb, 0xbd, 0x26, 0xdc, 0x53, 0xf4, 0x32, 0x17, 0x87, 0x6d, 0x07, 0xdd, 0x0b, 0xcc, 0xd5, + 0x55, 0x95, 0x35, 0x07, 0x53, 0x68, 0x70, 0x50, 0x85, 0x33, 0x02, 0x73, 0xf5, 0xa2, 0x2c, 0x38, 0x07, 0xf1, 0xbe, + 0x27, 0x4c, 0x4e, 0x19, 0x0d, 0xe0, 0x45, 0x56, 0x3e, 0x3a, 0xd5, 0xe3, 0xe0, 0x32, 0x6e, 0xd8, 0xc4, 0x17, 0xc2, + 0xa7, 0x02, 0x2b, 0x69, 0x8d, 0x43, 0x23, 0x3a, 0xa2, 0x73, 0x30, 0xdb, 0x00, 0x0a, 0xee, 0xce, 0x87, 0x8d, 0x85, + 0x0a, 0x9e, 0xbe, 0xad, 0xbd, 0x54, 0x4d, 0x88, 0x33, 0x69, 0x0a, 0xee, 0xb6, 0x0d, 0x32, 0x78, 0xf3, 0xdb, 0x7f, + 0x2b, 0x2c, 0x12, 0x0c, 0xa8, 0xd4, 0x24, 0x41, 0x78, 0x82, 0xd2, 0x48, 0xb7, 0x72, 0x33, 0x81, 0x74, 0x22, 0x6a, + 0x46, 0xdd, 0x1b, 0xe7, 0xab, 0xa3, 0x06, 0xa2, 0xa2, 0x06, 0x2a, 0xa0, 0x06, 0xb2, 0xbe, 0xfd, 0x0b, 0x58, 0x08, + 0x1b, 0xa1, 0x4a, 0x04, 0x01, 0x11, 0xe6, 0xda, 0xf0, 0x01, 0x45, 0x12, 0x42, 0xde, 0x00, 0x2a, 0xa6, 0xe4, 0x25, + 0x18, 0x8d, 0xc3, 0xeb, 0x3d, 0xe0, 0x7e, 0x69, 0x19, 0x06, 0xcf, 0x29, 0x98, 0xfc, 0xb7, 0x3e, 0x1f, 0xaa, 0x97, + 0xab, 0x83, 0x10, 0x7e, 0x01, 0xb1, 0x22, 0x1c, 0x7f, 0xf1, 0x0b, 0x90, 0x4d, 0x85, 0xe5, 0xc1, 0x81, 0x04, 0x81, + 0x1f, 0xa2, 0x08, 0x07, 0x3c, 0xc3, 0xcb, 0x6c, 0x83, 0xe8, 0xf9, 0x59, 0xa9, 0x6a, 0x56, 0x32, 0x98, 0x55, 0xe1, + 0x69, 0x1c, 0x5d, 0x13, 0x06, 0x82, 0x0b, 0xb5, 0xfb, 0x06, 0x21, 0x50, 0xb6, 0xdc, 0x18, 0xba, 0xf4, 0x14, 0xcc, + 0x47, 0xe3, 0xe8, 0x2d, 0x83, 0x07, 0x7c, 0x8d, 0xc9, 0x3f, 0xd3, 0x2c, 0xd3, 0x86, 0x79, 0x6c, 0x04, 0x4e, 0xea, + 0x14, 0x25, 0x7f, 0x4b, 0x2e, 0xe2, 0xa8, 0x79, 0x19, 0xa1, 0x06, 0xfc, 0xdb, 0xe0, 0xa8, 0x4b, 0x13, 0x3a, 0x1a, + 0xf9, 0xe0, 0x37, 0x19, 0x31, 0x9b, 0x6c, 0xb5, 0x12, 0x15, 0x41, 0x4f, 0xec, 0x06, 0x03, 0x56, 0xe2, 0x05, 0xb0, + 0x0f, 0x96, 0x83, 0x25, 0xef, 0x44, 0xac, 0xfc, 0x29, 0x85, 0xc1, 0xea, 0x39, 0x43, 0x08, 0x67, 0x41, 0xcc, 0xc6, + 0xff, 0x7c, 0xa6, 0xe1, 0xfa, 0xf9, 0xf9, 0x3a, 0x46, 0x44, 0xfa, 0x20, 0x72, 0x35, 0x76, 0x44, 0x04, 0x61, 0xcb, + 0x74, 0xdf, 0x95, 0xf9, 0xc1, 0x5b, 0x57, 0x0f, 0x6c, 0xb8, 0x38, 0x30, 0xa0, 0x46, 0x81, 0xd1, 0x0a, 0xce, 0x49, + 0x39, 0x70, 0x50, 0x42, 0x68, 0x56, 0xc4, 0x53, 0x72, 0x09, 0x91, 0xf0, 0x32, 0xd4, 0x05, 0xc3, 0x82, 0x40, 0x82, + 0x9a, 0x82, 0x04, 0x95, 0xf9, 0xda, 0x23, 0x98, 0x75, 0x6e, 0x66, 0x3b, 0x45, 0x5d, 0x17, 0xe4, 0xe7, 0x17, 0x1d, + 0x8f, 0x80, 0xa5, 0x3d, 0x38, 0x28, 0x20, 0x82, 0x18, 0x50, 0xf0, 0x52, 0x02, 0x0c, 0xc2, 0xf1, 0x15, 0x1b, 0x1a, + 0xf0, 0xb9, 0x36, 0x5e, 0x07, 0xc6, 0xd6, 0xa7, 0x0c, 0x72, 0xf1, 0xac, 0xda, 0xd3, 0x84, 0x90, 0xfd, 0x56, 0x4f, + 0xa7, 0xdb, 0x11, 0x12, 0x7b, 0x1f, 0xb5, 0x09, 0x34, 0xe6, 0x48, 0x77, 0xb5, 0x31, 0xbf, 0xd6, 0xf4, 0x88, 0xd5, + 0x24, 0xa4, 0x0b, 0xd2, 0xe5, 0xf9, 0xb4, 0x67, 0x70, 0xc5, 0x2a, 0x8d, 0x1c, 0x5c, 0x80, 0x3e, 0x1b, 0x10, 0xa0, + 0x40, 0xa5, 0xa9, 0x44, 0x51, 0xc4, 0x45, 0x52, 0xb2, 0x61, 0x98, 0x41, 0x98, 0xc2, 0x6a, 0x25, 0xe8, 0xc6, 0x1a, + 0x00, 0xef, 0xcc, 0xec, 0x9f, 0xd2, 0x07, 0x9b, 0xae, 0xbd, 0x79, 0x04, 0x10, 0x90, 0xfd, 0x76, 0xc9, 0xae, 0x8b, + 0x8d, 0xca, 0x2c, 0xac, 0x65, 0x6c, 0xe5, 0xb6, 0x3d, 0xc6, 0xde, 0x89, 0x6d, 0x3e, 0x01, 0x42, 0xd4, 0x96, 0x4c, + 0x23, 0x44, 0x48, 0x2c, 0x62, 0x5d, 0x1b, 0xb2, 0xd1, 0x86, 0xc2, 0x53, 0x89, 0x1c, 0xb8, 0x44, 0x13, 0x24, 0xdf, + 0x71, 0x09, 0x0e, 0xe1, 0x85, 0x47, 0xf8, 0x5b, 0x60, 0x91, 0x0a, 0xcc, 0xb0, 0x5c, 0xad, 0xa0, 0x9e, 0xc7, 0xfb, + 0x6c, 0x33, 0x38, 0xa9, 0xdc, 0x18, 0xbb, 0xb4, 0x13, 0x8f, 0xcb, 0x26, 0x24, 0xce, 0xa0, 0x5f, 0x5f, 0x11, 0xf5, + 0xf6, 0xdb, 0xe9, 0x13, 0xff, 0x5e, 0x99, 0xdb, 0x81, 0xd8, 0xb0, 0xde, 0x60, 0xf5, 0x01, 0xb4, 0xfc, 0x55, 0xe6, + 0x1f, 0x2a, 0x0b, 0x6e, 0x12, 0xd4, 0xe6, 0x22, 0x76, 0x59, 0x17, 0x31, 0x52, 0x5b, 0xdc, 0x1d, 0x42, 0xfc, 0xab, + 0xad, 0x28, 0x06, 0x3c, 0xa9, 0xf8, 0xe7, 0x18, 0x75, 0x21, 0x14, 0xb5, 0xf5, 0xb0, 0x01, 0x4a, 0xbb, 0x5c, 0x57, + 0x62, 0x64, 0x48, 0x20, 0xdf, 0xba, 0xf0, 0x82, 0xe6, 0x24, 0x52, 0x20, 0x27, 0x07, 0x51, 0x49, 0xb3, 0x0d, 0x61, + 0xae, 0xbb, 0x85, 0x63, 0xe6, 0x6a, 0x83, 0x16, 0xf1, 0x0b, 0x60, 0x67, 0xb8, 0x91, 0x2c, 0x1d, 0xf8, 0x54, 0x0d, + 0x7c, 0x7e, 0xcd, 0x0d, 0x45, 0x51, 0xa8, 0xf7, 0xce, 0x3e, 0x32, 0x07, 0xbf, 0xd3, 0x40, 0x7c, 0xa4, 0x4e, 0x47, + 0xb2, 0x11, 0x6a, 0xcd, 0xd9, 0xf1, 0xb2, 0xcd, 0x08, 0x83, 0xc2, 0x46, 0xef, 0xab, 0x90, 0x55, 0xec, 0xec, 0x54, + 0x04, 0x73, 0xfa, 0xa2, 0x2a, 0xe7, 0x54, 0x6e, 0x19, 0xd5, 0x52, 0xd3, 0x00, 0x11, 0xae, 0x7c, 0x22, 0x79, 0x9f, + 0x99, 0xf0, 0x0f, 0x06, 0xe3, 0xea, 0x91, 0xc2, 0xdf, 0xef, 0x8a, 0x1d, 0xb2, 0x1d, 0x1d, 0x6e, 0x23, 0x68, 0x5e, + 0xa8, 0xe0, 0x01, 0x47, 0x25, 0x4b, 0x88, 0x14, 0xb9, 0xdc, 0x57, 0x35, 0x53, 0xb6, 0xeb, 0x08, 0x21, 0xa4, 0x3d, + 0xce, 0xba, 0xa1, 0xd5, 0x43, 0x8f, 0x54, 0x51, 0x0e, 0xb7, 0x68, 0xae, 0x0b, 0x50, 0x61, 0x04, 0xd2, 0xe5, 0x67, + 0x76, 0x97, 0x4a, 0x88, 0x5e, 0xbe, 0x76, 0x21, 0x8c, 0x9d, 0x95, 0x25, 0x2e, 0xcc, 0xa8, 0x6d, 0x18, 0x5d, 0xb7, + 0x31, 0x9c, 0x0d, 0x8c, 0x99, 0x06, 0x25, 0x2d, 0x08, 0x75, 0xdd, 0xa5, 0x17, 0x99, 0x09, 0xf4, 0x98, 0x13, 0xda, + 0x60, 0x78, 0x4a, 0x34, 0x58, 0x36, 0x15, 0x60, 0xc1, 0xb7, 0x2c, 0x52, 0x6b, 0xb3, 0xc9, 0xe2, 0x8f, 0x3a, 0x36, + 0x4f, 0xfb, 0xe5, 0x15, 0xf3, 0x5c, 0x38, 0xea, 0xf6, 0x3c, 0xf3, 0xf1, 0xe8, 0x9e, 0xbe, 0xb9, 0x7a, 0xf1, 0xf2, + 0xf5, 0xab, 0xd5, 0xaa, 0xcd, 0x9a, 0xed, 0x13, 0xfc, 0x93, 0x2e, 0xe3, 0xc1, 0x96, 0x51, 0x80, 0x0e, 0x0e, 0xf6, + 0xb9, 0x71, 0xe1, 0xf9, 0xcc, 0xe7, 0x10, 0x37, 0x48, 0x0f, 0x70, 0x56, 0x94, 0x31, 0x41, 0x6e, 0xa3, 0x5e, 0x74, + 0x17, 0x81, 0x12, 0xaa, 0x22, 0x7f, 0x1f, 0x36, 0x67, 0xbf, 0x07, 0x81, 0x89, 0xa0, 0x3e, 0x44, 0x00, 0x81, 0x78, + 0xa5, 0xb8, 0x20, 0xcc, 0x27, 0x40, 0x14, 0xef, 0x05, 0x70, 0xa6, 0x26, 0x6a, 0xd5, 0x42, 0xc5, 0x05, 0x90, 0x44, + 0x1b, 0x8e, 0x92, 0x1e, 0x99, 0x00, 0xde, 0x10, 0x94, 0xd2, 0xfe, 0xea, 0xe6, 0xce, 0x5d, 0x2a, 0x47, 0xbd, 0x56, + 0x9a, 0xe3, 0xa9, 0xfb, 0x9c, 0xc2, 0xe7, 0xb4, 0xeb, 0x4f, 0x07, 0x71, 0x98, 0xe3, 0x05, 0x11, 0x87, 0xfe, 0x59, + 0xc4, 0xe5, 0xbc, 0x60, 0x5f, 0xb8, 0x5c, 0xa8, 0x74, 0x79, 0x9b, 0xca, 0xe4, 0xb6, 0x39, 0x3a, 0x8c, 0x8b, 0xe4, + 0xb6, 0xa9, 0x92, 0x5b, 0x84, 0xef, 0x52, 0x99, 0xdc, 0xd9, 0x94, 0xbb, 0xa6, 0x82, 0x9b, 0x2f, 0x2c, 0xe0, 0x50, + 0xb4, 0x45, 0x1b, 0x8b, 0xcd, 0xa2, 0x36, 0xc5, 0x15, 0x0d, 0x30, 0xf8, 0xf7, 0x1d, 0x1b, 0x3f, 0x0c, 0x5f, 0x82, + 0x4b, 0x93, 0x26, 0xf2, 0x13, 0x48, 0x3f, 0xad, 0xca, 0xc0, 0x7d, 0x4a, 0x5a, 0xdd, 0xe9, 0x85, 0x68, 0xb6, 0xbb, + 0x8d, 0xc6, 0x14, 0xf6, 0x6e, 0x46, 0x72, 0x5f, 0x6c, 0xda, 0x30, 0xf1, 0x75, 0xf6, 0xb3, 0xd5, 0x6a, 0x3f, 0x47, + 0x66, 0xc3, 0x4d, 0x58, 0xac, 0xfb, 0xd3, 0x01, 0x6e, 0xe1, 0xe7, 0x19, 0x42, 0x4b, 0xd6, 0x9f, 0x0e, 0x08, 0xeb, + 0x4f, 0x1b, 0xed, 0x81, 0x35, 0xb4, 0x33, 0x5b, 0x71, 0x0d, 0x21, 0x34, 0xa7, 0x83, 0x23, 0x53, 0x52, 0xba, 0x7c, + 0xfb, 0x45, 0xab, 0x80, 0x7e, 0xaa, 0x16, 0xbc, 0x4c, 0xe2, 0x0e, 0xf4, 0x45, 0x2f, 0xec, 0xd3, 0xad, 0x05, 0x39, + 0x3e, 0xaa, 0x5c, 0xed, 0x29, 0xc2, 0xa6, 0x27, 0x75, 0x58, 0x1c, 0x9a, 0x66, 0x5c, 0x97, 0xd2, 0x7d, 0x87, 0x9a, + 0x91, 0x8f, 0x0e, 0x16, 0x80, 0x20, 0x15, 0x3c, 0xb2, 0xc2, 0x85, 0x53, 0x0a, 0xe1, 0xe2, 0xa0, 0xb2, 0x05, 0x93, + 0x9c, 0xb4, 0xba, 0xb9, 0xb1, 0xf4, 0xcf, 0x5d, 0x44, 0x53, 0x8a, 0x29, 0xc9, 0x7c, 0xc9, 0xdc, 0x80, 0x85, 0x6e, + 0x52, 0x9e, 0x29, 0xe8, 0x95, 0x06, 0x78, 0x44, 0x20, 0x1e, 0x52, 0xb7, 0x30, 0x06, 0x5e, 0xf1, 0xb4, 0x59, 0xf4, + 0xd9, 0x00, 0x1d, 0x1d, 0x63, 0xda, 0xff, 0x94, 0xcd, 0xdb, 0xf0, 0x58, 0xe0, 0xa7, 0x01, 0x99, 0x36, 0x65, 0x99, + 0x20, 0x20, 0x61, 0xd4, 0x94, 0x87, 0xb0, 0x97, 0x10, 0xce, 0x6c, 0xc5, 0xac, 0xcf, 0x06, 0xcd, 0x69, 0x59, 0xb1, + 0xe3, 0x2b, 0x36, 0x64, 0x99, 0x60, 0x2b, 0x36, 0x5c, 0xc5, 0xf0, 0x75, 0x06, 0x03, 0x82, 0x10, 0x00, 0x0c, 0x00, + 0xa0, 0x51, 0x10, 0xcd, 0x17, 0x2b, 0xe2, 0x37, 0xbb, 0xbd, 0xc7, 0x6f, 0x81, 0x05, 0x5a, 0x6d, 0xff, 0xef, 0x42, + 0x19, 0xb0, 0xa7, 0x2c, 0x4c, 0xcc, 0xdc, 0xc2, 0xaa, 0xe8, 0x00, 0x2a, 0x25, 0xc2, 0x14, 0x06, 0x32, 0xfb, 0x99, + 0x81, 0x5a, 0xa0, 0x35, 0xc8, 0xfb, 0x7a, 0xd0, 0xcc, 0xe0, 0x88, 0x81, 0x77, 0x68, 0xc8, 0xd4, 0x18, 0x13, 0xc6, + 0x39, 0x4c, 0x31, 0x33, 0xe0, 0x99, 0xa6, 0xad, 0xb5, 0x34, 0xb2, 0x5c, 0x2f, 0xef, 0xfd, 0xa3, 0x63, 0xd5, 0x2f, + 0x9a, 0xed, 0x01, 0xda, 0x27, 0xc4, 0x7e, 0x0c, 0x60, 0x93, 0xb9, 0xd4, 0x86, 0xf9, 0x3e, 0xea, 0xa4, 0xf6, 0x13, + 0xfe, 0x0c, 0xd6, 0x66, 0x07, 0x80, 0x8e, 0x0c, 0x9b, 0xf5, 0x97, 0x35, 0x95, 0xd7, 0xc7, 0x9d, 0x51, 0x2a, 0x77, + 0xbd, 0x3b, 0x1d, 0x68, 0x8a, 0x43, 0x6f, 0x3d, 0x5c, 0x3e, 0xd4, 0x43, 0xc0, 0x8c, 0xc1, 0xdc, 0x32, 0xa3, 0xef, + 0x85, 0x48, 0x2e, 0x88, 0xc4, 0xd2, 0x60, 0x0d, 0x83, 0xbd, 0x75, 0x70, 0x60, 0xaa, 0xb1, 0x06, 0x3c, 0x4f, 0x8a, + 0x40, 0x30, 0xf0, 0x11, 0x94, 0x01, 0x4d, 0x94, 0xb9, 0x0d, 0x27, 0x1f, 0x99, 0xfb, 0x85, 0xcb, 0xdb, 0xc7, 0xc2, + 0x69, 0x5b, 0xcd, 0xf5, 0x78, 0x59, 0xe0, 0xae, 0xbc, 0x97, 0xb4, 0x0a, 0x6e, 0x64, 0x6f, 0xf2, 0x94, 0xb9, 0x5b, + 0xf7, 0xa5, 0x3a, 0xbb, 0x9b, 0xe9, 0x94, 0xcd, 0x74, 0xb6, 0x9b, 0x09, 0x35, 0x33, 0xdf, 0xb2, 0x8a, 0x34, 0x27, + 0x6b, 0xa2, 0xe6, 0x54, 0xfc, 0x44, 0xe7, 0xa0, 0x1d, 0xe5, 0xf6, 0x5e, 0x15, 0x4e, 0xae, 0x9c, 0x5c, 0xee, 0xe7, + 0x86, 0xb8, 0x22, 0x73, 0xa1, 0x0e, 0x01, 0x5e, 0x5e, 0x94, 0x8f, 0x0f, 0x70, 0x29, 0x7e, 0x95, 0x23, 0x17, 0xe5, + 0x54, 0x48, 0x2d, 0x05, 0x8b, 0x90, 0x41, 0x55, 0x17, 0x03, 0x7b, 0x69, 0xf7, 0x9e, 0xe8, 0xf1, 0x7e, 0x15, 0x31, + 0x6f, 0x60, 0x9e, 0xfb, 0xf8, 0x9e, 0xa6, 0xd8, 0xa9, 0x89, 0x33, 0xf2, 0x21, 0x8b, 0x73, 0x90, 0xcd, 0xfa, 0xd5, + 0x6b, 0xbf, 0x8d, 0x36, 0x2e, 0x9a, 0xb1, 0xe8, 0x99, 0x27, 0x4e, 0x7e, 0x28, 0x8c, 0x71, 0x80, 0x75, 0xf4, 0x47, + 0x98, 0x5a, 0xb0, 0x67, 0x89, 0xa7, 0xd0, 0xc9, 0xad, 0x4d, 0xbb, 0x0b, 0xd3, 0xee, 0x4c, 0x5a, 0x07, 0xca, 0x01, + 0x69, 0x76, 0x65, 0x3a, 0x77, 0xfe, 0xfb, 0x0e, 0x5e, 0xba, 0x5d, 0x43, 0x24, 0xee, 0xf9, 0x23, 0x63, 0x0c, 0xf1, + 0x06, 0x6c, 0x44, 0xd5, 0xc1, 0xc1, 0x1f, 0xce, 0xfb, 0xb6, 0x92, 0xfb, 0xbe, 0x15, 0x0e, 0x6c, 0x83, 0xa9, 0x74, + 0x79, 0x23, 0x99, 0x2d, 0xc0, 0xae, 0x73, 0xff, 0x1b, 0xf1, 0xf0, 0x45, 0xc8, 0xb4, 0x58, 0x57, 0xf1, 0x57, 0x72, + 0x54, 0x7a, 0x88, 0x6a, 0x88, 0x40, 0x5a, 0x59, 0x97, 0x86, 0xa6, 0xa3, 0x57, 0x53, 0x3a, 0x92, 0x37, 0x6f, 0xa5, + 0xd4, 0x03, 0xfb, 0x22, 0xb7, 0x4e, 0xe0, 0xd1, 0xc2, 0x1a, 0x43, 0x73, 0x57, 0x7a, 0x27, 0xd9, 0x80, 0xa8, 0xf5, + 0x71, 0x87, 0x92, 0x48, 0x2c, 0xaa, 0xbb, 0x10, 0x0e, 0x77, 0x21, 0x98, 0x97, 0x41, 0xdb, 0x20, 0x76, 0xbb, 0x0b, + 0xda, 0x06, 0x4e, 0xdd, 0x36, 0x70, 0x7b, 0x30, 0x58, 0xd8, 0xfb, 0xf0, 0x72, 0x2c, 0xc7, 0xc2, 0x5f, 0x93, 0xd9, + 0x07, 0x80, 0x40, 0xed, 0xc3, 0x8a, 0x27, 0x0e, 0x04, 0x89, 0x33, 0x1c, 0x7d, 0xcf, 0xd9, 0x8d, 0xb5, 0x1c, 0x9e, + 0xcd, 0x17, 0x9a, 0x8d, 0xcc, 0x1d, 0x35, 0xa8, 0xf8, 0xea, 0x7e, 0x5e, 0x3f, 0x65, 0x35, 0xdd, 0xf8, 0x3d, 0x08, + 0x23, 0xe1, 0x94, 0x1d, 0x46, 0x21, 0x61, 0x83, 0x59, 0x95, 0xf1, 0xda, 0x7e, 0x83, 0x78, 0x0f, 0xda, 0x84, 0x13, + 0x2c, 0x6a, 0x17, 0x54, 0x11, 0xb6, 0xf1, 0xc6, 0x82, 0x28, 0x0f, 0x6f, 0xb6, 0x8c, 0xa6, 0x97, 0x6b, 0x08, 0x74, + 0xdc, 0x8b, 0x9a, 0x51, 0x83, 0xa5, 0x2e, 0x28, 0xb3, 0x8f, 0x30, 0xae, 0x2e, 0x4e, 0x4c, 0x9c, 0xf6, 0x52, 0xaf, + 0xfe, 0x5b, 0x06, 0x06, 0xf8, 0x02, 0xbc, 0xc4, 0xc2, 0xe8, 0xae, 0x7d, 0xdd, 0x80, 0xfa, 0xb2, 0xc1, 0x06, 0x68, + 0xb5, 0x6a, 0x95, 0xcf, 0x40, 0xb9, 0x6b, 0x2e, 0x61, 0xaf, 0xb9, 0x84, 0xbb, 0xe6, 0x12, 0xfe, 0x9a, 0x4b, 0x98, + 0x6b, 0x2e, 0xe1, 0xaf, 0xb9, 0x3c, 0x08, 0xff, 0x0c, 0xe2, 0x38, 0xc6, 0x1c, 0xe2, 0x2a, 0x6a, 0x1b, 0x19, 0x0f, + 0x2e, 0x3c, 0xf7, 0x59, 0xa2, 0xca, 0xe5, 0x0f, 0x63, 0xc8, 0x6d, 0xd9, 0x4a, 0x18, 0xb7, 0x29, 0xa6, 0x20, 0x72, + 0xfa, 0xc1, 0x41, 0xe9, 0xee, 0x0c, 0x3e, 0xea, 0x29, 0xc7, 0x4b, 0xeb, 0x44, 0xfb, 0x07, 0xe8, 0xe4, 0xcd, 0xaf, + 0x8f, 0xa9, 0x5c, 0x13, 0xe1, 0x4c, 0xee, 0xf7, 0xdb, 0x9e, 0x52, 0xfc, 0x99, 0x99, 0xf0, 0xe4, 0x3c, 0xd1, 0x46, + 0x04, 0x41, 0x88, 0x12, 0x85, 0x33, 0x22, 0xed, 0x7e, 0xf7, 0xae, 0xf0, 0x46, 0x15, 0xe5, 0xcd, 0x4a, 0x1e, 0xe7, + 0xe0, 0xc4, 0x6e, 0xac, 0x30, 0x50, 0x17, 0x5c, 0x08, 0x32, 0x93, 0xf0, 0x47, 0x33, 0xb7, 0xe4, 0x2c, 0x2b, 0x93, + 0x3e, 0x36, 0x73, 0x43, 0xc0, 0x0a, 0xb2, 0xef, 0x61, 0xb6, 0xbc, 0x4d, 0xe9, 0xff, 0xcb, 0xde, 0xbb, 0x2e, 0xb7, + 0x8d, 0x64, 0xe9, 0xa2, 0xaf, 0x22, 0x31, 0x6c, 0x16, 0x60, 0x26, 0x29, 0xca, 0x7b, 0xcf, 0x44, 0x1c, 0x50, 0x29, + 0x86, 0x2f, 0xe5, 0x2e, 0x77, 0x97, 0x2f, 0x6d, 0xb9, 0xab, 0xab, 0x9a, 0xc1, 0xc3, 0x82, 0x80, 0xa4, 0x00, 0x17, + 0x08, 0xb0, 0x00, 0x50, 0x22, 0x4d, 0xe2, 0xdd, 0x77, 0xac, 0xb5, 0xf2, 0x0a, 0x82, 0xb2, 0x7b, 0x66, 0xcf, 0xaf, + 0x73, 0xfe, 0xd8, 0x62, 0x22, 0x91, 0xc8, 0x7b, 0xae, 0x5c, 0x97, 0xef, 0x63, 0xbb, 0x20, 0x62, 0xb7, 0xc5, 0x36, + 0x28, 0x6d, 0x5f, 0x10, 0x65, 0xf8, 0x5b, 0x7a, 0xbd, 0x3c, 0x84, 0x78, 0x9f, 0x5e, 0x9a, 0x9f, 0xa5, 0xad, 0x28, + 0xc0, 0x7d, 0x84, 0x1e, 0xd5, 0x81, 0x60, 0x27, 0x3c, 0xe1, 0x01, 0x9c, 0xac, 0x66, 0x15, 0x7f, 0x92, 0x82, 0x38, + 0x51, 0x70, 0x08, 0xb8, 0xda, 0xde, 0xa4, 0x5f, 0xc1, 0xf0, 0xa5, 0x83, 0x2d, 0x87, 0xb7, 0xc5, 0xb6, 0xc7, 0x4a, + 0xfe, 0x11, 0xd8, 0xb7, 0x7a, 0x32, 0x56, 0xb7, 0x07, 0xce, 0xba, 0x94, 0xa2, 0xe3, 0x4d, 0x71, 0x78, 0x7b, 0x3e, + 0xdb, 0x6f, 0x83, 0x88, 0xed, 0x82, 0x0c, 0x6b, 0x9d, 0x34, 0xfc, 0xaf, 0xb4, 0x75, 0xb0, 0x18, 0x61, 0xff, 0x97, + 0xf5, 0xc0, 0x4b, 0x48, 0x0d, 0x05, 0x2e, 0x06, 0x1b, 0x8e, 0xd6, 0x76, 0x99, 0x06, 0x6e, 0x6a, 0xd0, 0xeb, 0x7b, + 0x0a, 0x51, 0x5e, 0x32, 0x9a, 0x1b, 0xc1, 0xba, 0x31, 0xe4, 0xe2, 0x70, 0xdc, 0x2c, 0x87, 0xbc, 0xa4, 0xe9, 0x34, + 0x08, 0xa5, 0x3b, 0xcb, 0x1a, 0x92, 0x28, 0xfb, 0x20, 0xd4, 0xae, 0x2d, 0xfb, 0x6d, 0x60, 0xfb, 0xf2, 0x47, 0xc3, + 0xd8, 0xbf, 0x58, 0x3e, 0x13, 0xd2, 0x45, 0x3c, 0x07, 0x41, 0xd4, 0x7e, 0x9e, 0x0d, 0x37, 0xfe, 0xc5, 0xfa, 0x99, + 0x50, 0x7e, 0xe3, 0xb9, 0x2d, 0x87, 0xd4, 0x59, 0x0b, 0x5f, 0x18, 0x0f, 0x0f, 0xae, 0x0c, 0x6d, 0x87, 0x83, 0xd0, + 0x7f, 0x9b, 0x35, 0x82, 0x1b, 0x1b, 0xda, 0xe7, 0x0b, 0x1f, 0xb6, 0x36, 0x1a, 0x6b, 0x8a, 0xe9, 0x16, 0xfa, 0x37, + 0x99, 0x2d, 0xed, 0x69, 0x54, 0xf2, 0xe2, 0xd4, 0x34, 0x62, 0x21, 0x0c, 0x18, 0xfa, 0xc9, 0x7c, 0x04, 0xd5, 0xdc, + 0xf1, 0x08, 0x64, 0xf2, 0x81, 0x1e, 0xac, 0x49, 0xad, 0xfa, 0x6b, 0x98, 0xc9, 0xff, 0x23, 0x15, 0x16, 0xa3, 0xbb, + 0x6d, 0x98, 0xa9, 0x3f, 0x22, 0xf9, 0x07, 0xcb, 0xf9, 0x2e, 0xf5, 0x42, 0xed, 0xc7, 0xc2, 0x0a, 0x0c, 0x4a, 0x54, + 0x0d, 0xe8, 0x81, 0x08, 0xaa, 0x32, 0x48, 0x33, 0xac, 0xce, 0x41, 0xbf, 0x7b, 0x5a, 0x75, 0x24, 0x87, 0xb4, 0x56, + 0x43, 0x2a, 0x98, 0x2a, 0x35, 0xc8, 0x0f, 0x87, 0xbb, 0x94, 0xe9, 0x32, 0xe0, 0x92, 0x7e, 0x97, 0x2a, 0xa5, 0xf0, + 0x9f, 0x08, 0x40, 0xe7, 0xe0, 0x1e, 0x5f, 0x8e, 0x81, 0x34, 0xc3, 0xc2, 0x6f, 0xcd, 0x8e, 0xaf, 0x49, 0xb8, 0x4d, + 0x82, 0x8b, 0x01, 0xce, 0xd1, 0x55, 0x58, 0xde, 0xa5, 0x10, 0x41, 0x55, 0x42, 0x7d, 0x2b, 0xd3, 0xa0, 0xb4, 0xd5, + 0x20, 0xac, 0x49, 0xa8, 0x33, 0xc9, 0x46, 0xa5, 0xed, 0x46, 0x61, 0xb6, 0x88, 0xeb, 0x19, 0x61, 0xcd, 0xd9, 0x4c, + 0x35, 0x30, 0x69, 0x38, 0x6e, 0x1a, 0xad, 0x45, 0x85, 0x9a, 0xc2, 0xbc, 0xc6, 0x55, 0xa5, 0xaa, 0xbb, 0x39, 0xb5, + 0x94, 0x96, 0xed, 0x55, 0x37, 0xc9, 0x86, 0x5c, 0x86, 0x32, 0x0c, 0x36, 0x72, 0x04, 0x13, 0x48, 0x92, 0x33, 0x7f, + 0x23, 0xff, 0x50, 0x9b, 0xae, 0x05, 0xcc, 0x31, 0x66, 0xd9, 0xb0, 0xa0, 0x57, 0xe0, 0x1e, 0x68, 0xa5, 0xe7, 0xd3, + 0xec, 0x22, 0x0f, 0x92, 0x61, 0xa1, 0x97, 0x4d, 0xc6, 0xff, 0x14, 0x46, 0x9a, 0xcc, 0x58, 0xc9, 0x22, 0xdb, 0xd5, + 0x29, 0x71, 0x1e, 0x27, 0xb0, 0x3d, 0x9a, 0xde, 0xf2, 0x7d, 0x06, 0x51, 0x41, 0xa0, 0x60, 0xc6, 0x7c, 0xd9, 0xc5, + 0x73, 0xdf, 0x67, 0x96, 0xa9, 0xfb, 0x70, 0x30, 0x66, 0x6c, 0xbf, 0xdf, 0xcf, 0xfb, 0x7d, 0x35, 0xdf, 0xfa, 0xfd, + 0xe4, 0xda, 0xfc, 0xed, 0x01, 0x83, 0x82, 0x9c, 0x88, 0xa6, 0x42, 0x04, 0xff, 0x90, 0x3c, 0x43, 0x32, 0xba, 0xe3, + 0x3e, 0xb7, 0x9c, 0x2d, 0xab, 0x23, 0x10, 0xcc, 0xc3, 0xe1, 0x52, 0x81, 0x5d, 0x4b, 0x14, 0x09, 0x59, 0xfe, 0x33, + 0x30, 0x9e, 0xb9, 0x0f, 0xb0, 0x64, 0x00, 0xc2, 0x56, 0x79, 0xba, 0xde, 0xf3, 0x55, 0xf0, 0x4e, 0xc7, 0xbb, 0xc6, + 0x8a, 0x0c, 0xc4, 0x2d, 0xb0, 0x11, 0x6b, 0xed, 0x01, 0x39, 0x53, 0x80, 0xe3, 0xc5, 0xe1, 0x70, 0x2e, 0x7f, 0xe9, + 0x66, 0xeb, 0x04, 0x2a, 0x05, 0x6e, 0x8f, 0x4e, 0x0e, 0xfe, 0x3b, 0xd0, 0x0c, 0xca, 0x61, 0x5e, 0x6f, 0x7f, 0x67, + 0x4e, 0x7e, 0x7a, 0x8a, 0x7f, 0xc2, 0x43, 0x74, 0xfa, 0xed, 0xde, 0xfc, 0x41, 0x51, 0x79, 0x38, 0xa8, 0xc5, 0x7f, + 0xce, 0x79, 0x05, 0xbf, 0xf0, 0x4d, 0x60, 0x36, 0x99, 0x7a, 0x27, 0xdf, 0xe4, 0x39, 0x53, 0xaf, 0xf1, 0x8a, 0xc9, + 0x77, 0x38, 0x9c, 0x8b, 0x51, 0xbd, 0x1d, 0x39, 0xd1, 0x4e, 0x39, 0xc6, 0xc1, 0xe0, 0xbf, 0x88, 0xb6, 0x09, 0x01, + 0x86, 0xd4, 0x2d, 0x69, 0x66, 0xe3, 0xca, 0x12, 0xcf, 0xd2, 0xf9, 0xe5, 0xa4, 0x2e, 0x77, 0x5a, 0xf1, 0xb4, 0x07, + 0x16, 0xb7, 0x35, 0x78, 0x01, 0xdc, 0x5b, 0x6c, 0x5d, 0x29, 0x38, 0x5c, 0x40, 0x9c, 0xe2, 0x04, 0x44, 0xd0, 0x7e, + 0x5f, 0xe2, 0xbd, 0x82, 0x3e, 0xe9, 0x47, 0x08, 0x86, 0xfc, 0x59, 0x02, 0xee, 0x7a, 0xbd, 0x1a, 0xe3, 0x7b, 0x29, + 0x04, 0xd7, 0x67, 0x1a, 0x80, 0x16, 0xfc, 0x2e, 0x1f, 0xcb, 0xe9, 0x37, 0x11, 0x78, 0xb6, 0xec, 0x4d, 0x94, 0xbb, + 0x0d, 0x4f, 0xfb, 0x47, 0x0b, 0x01, 0x58, 0x8a, 0x67, 0x4a, 0xb0, 0x20, 0xa7, 0x98, 0x8b, 0xff, 0x17, 0x7c, 0xc4, + 0x7c, 0x4f, 0xba, 0x88, 0xad, 0xb7, 0x4f, 0x2e, 0x0c, 0x24, 0xd0, 0x74, 0x00, 0x7e, 0xbc, 0x0a, 0xe8, 0xca, 0xf8, + 0xf9, 0x59, 0xd6, 0x63, 0x7d, 0xfc, 0xa7, 0xe0, 0x3e, 0xfd, 0x4c, 0xe1, 0xa3, 0xc3, 0x71, 0x95, 0x8e, 0x76, 0x94, + 0x82, 0xe8, 0xe8, 0xf6, 0xf9, 0x94, 0x67, 0xdf, 0x55, 0x40, 0x6e, 0x39, 0x6a, 0x4f, 0x05, 0x60, 0xb1, 0xa5, 0x23, + 0xf0, 0x69, 0x96, 0x4f, 0xc8, 0xf7, 0x7a, 0x2a, 0xae, 0x2e, 0x75, 0xba, 0xb8, 0x1e, 0x4f, 0xe1, 0x7f, 0x20, 0xf6, + 0xb0, 0x4c, 0x91, 0x1d, 0xbb, 0x2e, 0x7e, 0x10, 0x6f, 0x6b, 0x3b, 0xfa, 0x63, 0x07, 0x91, 0x8e, 0x7b, 0x72, 0xa1, + 0xbe, 0x84, 0x54, 0x72, 0xa1, 0x6e, 0x20, 0x76, 0xa1, 0xc6, 0x3b, 0x2e, 0x62, 0xad, 0xbf, 0xab, 0x51, 0xb0, 0x12, + 0x70, 0xa6, 0xbd, 0x03, 0x83, 0x0d, 0xac, 0x5b, 0x96, 0xc1, 0xdf, 0x70, 0x4d, 0x13, 0xb8, 0x61, 0x91, 0xf5, 0xde, + 0x60, 0x2b, 0xbd, 0x03, 0x47, 0xcb, 0xc4, 0xb9, 0x94, 0x64, 0x65, 0x8b, 0x8c, 0xab, 0x47, 0x21, 0x55, 0xd3, 0xfd, + 0xad, 0xa8, 0x1f, 0x84, 0xc8, 0x83, 0x55, 0xca, 0xa2, 0x62, 0x05, 0x32, 0x7b, 0xf0, 0xf7, 0x90, 0x91, 0xa3, 0x1c, + 0x38, 0x0a, 0xfd, 0xbd, 0x09, 0x74, 0x9e, 0xbf, 0x86, 0x3a, 0x8f, 0x04, 0x5b, 0xa9, 0x87, 0xc2, 0xca, 0x0b, 0x88, + 0x0e, 0xb6, 0x30, 0x56, 0x79, 0x12, 0x2a, 0x36, 0x65, 0x22, 0x8f, 0x83, 0x5a, 0x02, 0xc6, 0x0a, 0x82, 0x39, 0xcb, + 0xa5, 0x0b, 0x52, 0xd5, 0xe8, 0x61, 0x91, 0xb9, 0x9f, 0x0a, 0xca, 0xff, 0x54, 0xe5, 0x84, 0xeb, 0xcb, 0x10, 0xe0, + 0x68, 0x9f, 0x82, 0x28, 0x31, 0xd6, 0x2f, 0x5a, 0xbc, 0x93, 0x99, 0xb3, 0xa9, 0xed, 0x25, 0xc8, 0xd8, 0x0e, 0xbf, + 0x42, 0x68, 0xb5, 0x50, 0x64, 0xd1, 0x70, 0xc1, 0x74, 0x7b, 0x4a, 0xab, 0xee, 0x61, 0xc3, 0xb3, 0xd2, 0x43, 0xa5, + 0xbe, 0x8d, 0x09, 0x2c, 0xab, 0x94, 0xe1, 0xdb, 0x09, 0x55, 0x27, 0x06, 0x15, 0xeb, 0x86, 0x2d, 0xe1, 0x10, 0x8b, + 0x49, 0x63, 0x9d, 0x0d, 0x78, 0xc4, 0x12, 0xf8, 0x67, 0xc3, 0xc7, 0x6c, 0xc9, 0xa3, 0xc9, 0xe6, 0x6a, 0xd9, 0xef, + 0x97, 0x5e, 0xe8, 0xd5, 0xb3, 0xec, 0x69, 0x34, 0x9f, 0xe5, 0x73, 0x1f, 0x15, 0x17, 0x93, 0xc1, 0x60, 0xe3, 0x67, + 0xc3, 0x21, 0x4b, 0x86, 0xc3, 0x49, 0xf6, 0x14, 0x5e, 0x7b, 0xca, 0x23, 0xb5, 0xa4, 0x92, 0xab, 0x0c, 0xf6, 0xf7, + 0x01, 0x8f, 0x7c, 0xd6, 0xf9, 0x69, 0xd9, 0x74, 0xe9, 0x7e, 0x66, 0x75, 0x40, 0xa9, 0x3b, 0xc0, 0xc6, 0xdb, 0x06, + 0x1d, 0xf9, 0xb7, 0x3b, 0xa4, 0xd4, 0x4d, 0x06, 0x60, 0x37, 0x1a, 0xe0, 0x90, 0xa9, 0x5e, 0x8a, 0xac, 0x5e, 0xca, + 0x54, 0x2f, 0xc9, 0xca, 0x25, 0x58, 0x48, 0x4c, 0x95, 0xdb, 0xc8, 0xca, 0x2d, 0x1b, 0xae, 0x87, 0x83, 0xad, 0x15, + 0x97, 0xcd, 0x1d, 0xdc, 0x17, 0x56, 0x14, 0xf8, 0x7f, 0xcb, 0x16, 0xec, 0x5e, 0x1e, 0x03, 0xef, 0xd0, 0x31, 0x09, + 0x2e, 0x10, 0xf7, 0xec, 0x16, 0xec, 0xb0, 0xf0, 0x17, 0x5c, 0x27, 0xc7, 0x6c, 0x87, 0x8f, 0x42, 0xaf, 0x60, 0xb7, + 0x3e, 0x01, 0xed, 0x82, 0xad, 0x01, 0xb2, 0xb1, 0x2d, 0x3e, 0xba, 0x3b, 0x1c, 0xde, 0x79, 0x3e, 0x7b, 0xc0, 0x1f, + 0xe7, 0x77, 0x87, 0xc3, 0xce, 0x33, 0xea, 0xbd, 0x1b, 0x9e, 0xb0, 0x0f, 0x3c, 0x99, 0xdc, 0x5c, 0xf1, 0x78, 0x32, + 0x18, 0xdc, 0xf8, 0x0b, 0x5e, 0xcf, 0x6e, 0x40, 0x3b, 0x70, 0xbe, 0x90, 0xba, 0x66, 0xef, 0x96, 0x67, 0xde, 0x02, + 0xc7, 0xe6, 0x16, 0x8e, 0xde, 0x7e, 0xdf, 0xbb, 0xe3, 0x91, 0x77, 0x4b, 0x2a, 0xa6, 0x15, 0x57, 0x1c, 0x6f, 0x5b, + 0xdc, 0x4f, 0x57, 0x3c, 0x84, 0x47, 0x58, 0x95, 0xe9, 0x4d, 0xf0, 0xc1, 0x67, 0x2b, 0xcd, 0x02, 0xf7, 0x80, 0x39, + 0xd6, 0x64, 0x27, 0x34, 0x13, 0x7f, 0x85, 0xfd, 0x73, 0xa3, 0xfa, 0x87, 0xe6, 0x7f, 0xa9, 0xfb, 0x09, 0xdc, 0xbe, + 0xc8, 0x82, 0xc4, 0x3e, 0xf0, 0x1b, 0x76, 0xcf, 0x0d, 0xdb, 0xec, 0x99, 0x29, 0xfb, 0x44, 0xa9, 0xf1, 0x23, 0xa5, + 0xae, 0x2d, 0xc3, 0x4a, 0xe6, 0xee, 0xcb, 0x08, 0x1c, 0x0e, 0xc8, 0x4f, 0x77, 0x88, 0x83, 0xd0, 0xba, 0xc9, 0x6a, + 0xae, 0x28, 0xe7, 0x42, 0x5b, 0x66, 0x5e, 0x0e, 0x2c, 0x66, 0x29, 0x85, 0xc6, 0x02, 0x00, 0xc1, 0xa4, 0xd0, 0xda, + 0x7b, 0x19, 0x40, 0x4e, 0xd0, 0xf0, 0xc7, 0xe6, 0xaa, 0x28, 0x6b, 0xd9, 0x92, 0x10, 0x65, 0xbb, 0x1e, 0x5e, 0x22, + 0x64, 0x5a, 0xbf, 0x7f, 0x4e, 0x24, 0x6b, 0x93, 0xea, 0xaa, 0x46, 0x4b, 0x40, 0x45, 0x96, 0x80, 0x89, 0x5f, 0x69, + 0x3e, 0x01, 0x78, 0xd2, 0xf1, 0xa0, 0x7a, 0xca, 0x6b, 0x26, 0x88, 0x6c, 0xa3, 0xf2, 0x27, 0xc5, 0x35, 0x92, 0x11, + 0x14, 0x4f, 0x6b, 0x95, 0xb1, 0x30, 0xcc, 0x03, 0x05, 0xe4, 0xdd, 0xbb, 0x53, 0xdf, 0xda, 0x1f, 0x3b, 0xf6, 0x6c, + 0xad, 0x42, 0x2d, 0xd4, 0x14, 0x2e, 0x39, 0x44, 0x57, 0x90, 0x81, 0x42, 0xc6, 0x93, 0xd7, 0x83, 0xcb, 0x49, 0x74, + 0xc5, 0x05, 0x3a, 0xe3, 0xeb, 0x9b, 0x6e, 0x3a, 0x8b, 0x9e, 0x56, 0xf3, 0x09, 0x29, 0xc9, 0x0e, 0x87, 0x6c, 0x54, + 0xd5, 0xc5, 0x7a, 0x1a, 0xca, 0x9f, 0x1e, 0x82, 0xaf, 0x17, 0xd4, 0x6b, 0xb2, 0x4a, 0xf5, 0x53, 0xaa, 0x94, 0x17, + 0x0d, 0x2f, 0xfd, 0xa7, 0x95, 0xdc, 0xf7, 0x80, 0xb4, 0x96, 0x97, 0x5c, 0xbe, 0x1f, 0x21, 0xc6, 0x88, 0x1f, 0x78, + 0x25, 0x8f, 0x58, 0xa8, 0xa6, 0x70, 0xcd, 0x23, 0x04, 0x79, 0xcb, 0x74, 0xf0, 0xb7, 0x9e, 0x38, 0xdd, 0x9f, 0x28, + 0xed, 0xe2, 0x0b, 0x8b, 0xba, 0x27, 0x6b, 0xeb, 0x06, 0xe4, 0x60, 0xc3, 0x74, 0x51, 0x90, 0x6d, 0x4a, 0x23, 0x68, + 0xa3, 0xe5, 0xc0, 0x86, 0x53, 0xa9, 0x0d, 0x67, 0xae, 0x21, 0xb8, 0xcf, 0xcf, 0xd3, 0xd1, 0x02, 0x3e, 0xa4, 0xba, + 0xbd, 0xc4, 0xcf, 0x87, 0x0d, 0x8f, 0x80, 0xcc, 0x8e, 0xf8, 0xcc, 0x26, 0x92, 0x4e, 0xea, 0x5c, 0x01, 0xbb, 0x9d, + 0xbd, 0x03, 0x39, 0x62, 0xe6, 0xbe, 0x42, 0xf5, 0x2d, 0x1a, 0x70, 0x65, 0xac, 0x7d, 0x4d, 0x32, 0x16, 0x5e, 0x95, + 0xd3, 0x70, 0x00, 0x30, 0x74, 0x19, 0x7d, 0x6d, 0xb9, 0xc9, 0xb2, 0x9f, 0x0b, 0x08, 0x82, 0x28, 0x89, 0xc7, 0x07, + 0xbc, 0x2f, 0xab, 0xa1, 0x46, 0xc9, 0xc7, 0xb2, 0x91, 0x4a, 0xaf, 0x44, 0x7f, 0x37, 0xe6, 0x12, 0x03, 0xbe, 0xab, + 0xda, 0x82, 0xc2, 0x79, 0x7e, 0x38, 0x9c, 0xe7, 0x23, 0xe3, 0x59, 0x06, 0xaa, 0x95, 0x69, 0x1d, 0xc4, 0x66, 0xbe, + 0x58, 0xf8, 0x8b, 0x9d, 0x93, 0x88, 0x28, 0x08, 0xec, 0x48, 0x78, 0x10, 0xa9, 0x5f, 0x55, 0x9e, 0xee, 0x54, 0x9f, + 0xed, 0x17, 0x36, 0x91, 0x5e, 0x50, 0x32, 0xf9, 0x24, 0xd8, 0xab, 0xfe, 0x0e, 0xc2, 0x86, 0xf0, 0xe6, 0x55, 0xaf, + 0xb3, 0x4c, 0xcd, 0x4a, 0x90, 0x30, 0x63, 0x8e, 0xe0, 0x71, 0xd8, 0x69, 0x6c, 0xc3, 0x63, 0x0b, 0x8e, 0xce, 0x5b, + 0xb3, 0x3b, 0xb6, 0x62, 0xb7, 0xaa, 0x4e, 0x0b, 0x1e, 0x4e, 0x87, 0x97, 0x01, 0xae, 0xbe, 0xf5, 0x39, 0xe7, 0x77, + 0x74, 0x82, 0xad, 0x07, 0x3c, 0x9a, 0x88, 0xd9, 0xfa, 0x69, 0xa4, 0x16, 0xcf, 0x7a, 0xc8, 0x17, 0xb4, 0xfe, 0xc4, + 0xec, 0xce, 0x24, 0xdf, 0x0d, 0xf8, 0x62, 0xb2, 0x7e, 0x1a, 0xc1, 0xab, 0x4f, 0xc1, 0x8a, 0x91, 0x39, 0xb3, 0x6c, + 0xfd, 0x34, 0xc2, 0x31, 0xbb, 0x7b, 0x1a, 0xd1, 0xa8, 0xad, 0xe4, 0xbe, 0x74, 0xdb, 0x80, 0xb0, 0x72, 0xcb, 0x62, + 0x78, 0x0d, 0xc4, 0x33, 0x6d, 0x24, 0x5d, 0x4b, 0x43, 0x6f, 0xcc, 0xc3, 0x69, 0x1c, 0xac, 0xa9, 0x15, 0xf2, 0xcc, + 0x10, 0xb3, 0xf8, 0x69, 0x34, 0x67, 0x2b, 0xac, 0xc8, 0x86, 0xc7, 0x83, 0xcb, 0xc9, 0xe6, 0x8a, 0xaf, 0x81, 0xfc, + 0x6c, 0xb2, 0x31, 0x5b, 0xd4, 0x2d, 0x17, 0xb3, 0xcd, 0xd3, 0x68, 0x3e, 0x59, 0x41, 0xcf, 0xda, 0x03, 0xe6, 0xbd, + 0x01, 0x11, 0x4a, 0x42, 0x6a, 0xca, 0x4d, 0xaf, 0xc7, 0xd6, 0xe3, 0xe0, 0x8e, 0xad, 0x2f, 0x83, 0x5b, 0xb6, 0x1e, + 0x03, 0x11, 0x07, 0xf5, 0xbb, 0xb7, 0x81, 0xc5, 0x17, 0xb1, 0xf5, 0xa5, 0x49, 0xdb, 0x3c, 0x8d, 0x98, 0x3b, 0x38, + 0x0d, 0x5c, 0xb0, 0x36, 0x99, 0xb7, 0x62, 0x70, 0x09, 0x59, 0x7a, 0x31, 0xdb, 0x0c, 0x2f, 0xd9, 0x7a, 0x84, 0x53, + 0x3d, 0xf1, 0xd9, 0x1d, 0xbf, 0x65, 0x09, 0x5f, 0x35, 0xf1, 0xd5, 0x06, 0x34, 0xa2, 0x47, 0x19, 0xf4, 0x15, 0xd4, + 0xcc, 0x9c, 0x57, 0x16, 0x46, 0xe5, 0xbe, 0x05, 0x07, 0x14, 0xa4, 0x6d, 0x80, 0x20, 0x89, 0x67, 0xf7, 0x2a, 0x5c, + 0xdf, 0x48, 0x61, 0xc0, 0x4d, 0x60, 0x06, 0x0c, 0x4c, 0x3f, 0x83, 0x1f, 0x56, 0xba, 0x44, 0x88, 0xb3, 0x9f, 0x52, + 0x92, 0xcc, 0xf3, 0xd7, 0x22, 0xcd, 0xdd, 0xc2, 0x75, 0x0a, 0xb3, 0xa2, 0x40, 0xf5, 0x53, 0x52, 0x1a, 0x58, 0xa8, + 0x44, 0xa6, 0x52, 0xf0, 0xcb, 0xe6, 0x3c, 0xca, 0x8e, 0xd1, 0xb9, 0xce, 0x2f, 0x27, 0xce, 0xe9, 0xa4, 0xef, 0x3f, + 0x70, 0x0c, 0x5b, 0xc8, 0xc0, 0x85, 0x3f, 0xf5, 0x84, 0x71, 0x6a, 0x05, 0x62, 0x2a, 0x79, 0xf6, 0x14, 0x3e, 0x13, + 0x5a, 0x1d, 0x5d, 0xf8, 0x7e, 0x50, 0x68, 0x93, 0x74, 0x0b, 0x92, 0x14, 0x3c, 0x45, 0xcf, 0x39, 0x6f, 0x03, 0x95, + 0x62, 0x44, 0x0b, 0x22, 0x6d, 0x2d, 0x33, 0x07, 0x69, 0x4b, 0xf3, 0x5d, 0x13, 0x3f, 0x87, 0x05, 0x5c, 0x44, 0x0b, + 0x5b, 0xc3, 0xa3, 0x2a, 0x56, 0xee, 0x4d, 0x9e, 0x23, 0x9c, 0xd1, 0xa5, 0x4c, 0x00, 0x5c, 0xef, 0xd7, 0x61, 0xad, + 0xf0, 0x8a, 0x9a, 0x45, 0x5e, 0xd4, 0xf4, 0xc9, 0x16, 0xb8, 0x8f, 0x45, 0x89, 0x02, 0x67, 0x2d, 0x18, 0xb0, 0x15, + 0x96, 0xec, 0xa4, 0xb0, 0x29, 0x5a, 0x42, 0x6f, 0x8f, 0x9f, 0x0e, 0x6a, 0x26, 0x03, 0x68, 0x02, 0x68, 0x3c, 0xfe, + 0x05, 0xa0, 0xa6, 0x37, 0xb5, 0x58, 0x57, 0x41, 0xa9, 0x94, 0x9b, 0xf0, 0x33, 0x30, 0xcc, 0xf0, 0x43, 0x21, 0xb7, + 0x89, 0x12, 0x39, 0x3f, 0x16, 0xa5, 0x58, 0x96, 0xa2, 0x4a, 0xda, 0x0d, 0x05, 0x8f, 0x08, 0xb7, 0x41, 0x63, 0xe6, + 0xf6, 0x44, 0x17, 0xad, 0x08, 0xe5, 0xd8, 0xac, 0x63, 0xa4, 0x51, 0x66, 0x27, 0xbb, 0x4e, 0x16, 0xda, 0xef, 0xab, + 0x1c, 0xb2, 0x0e, 0x58, 0x23, 0xf9, 0x7a, 0xcd, 0xa1, 0xdb, 0x46, 0x79, 0xf1, 0xe0, 0xf9, 0x0a, 0x4e, 0x73, 0x3c, + 0xb1, 0xbb, 0x5e, 0x77, 0x8a, 0x44, 0xbc, 0xc2, 0x49, 0x95, 0x8f, 0x64, 0xe1, 0xb8, 0x73, 0xa7, 0xb5, 0x58, 0x55, + 0x2e, 0xeb, 0xa9, 0xc5, 0x11, 0x81, 0x4f, 0xe5, 0xd1, 0x5e, 0x68, 0x5b, 0x14, 0x0b, 0x61, 0xf4, 0xe8, 0x84, 0x9f, + 0x94, 0xc0, 0xfa, 0x3a, 0x1c, 0x96, 0x7e, 0xc4, 0xd1, 0xef, 0x34, 0x1a, 0x2d, 0x08, 0x69, 0x78, 0xea, 0x45, 0xa3, + 0x45, 0x5d, 0xd4, 0x61, 0x76, 0x9d, 0xeb, 0x81, 0xc2, 0x30, 0x02, 0xf5, 0x83, 0xab, 0x0c, 0x3e, 0x8b, 0x10, 0x35, + 0x0f, 0x4c, 0xb3, 0x21, 0x1c, 0x75, 0x81, 0x87, 0x56, 0xd0, 0x62, 0x66, 0x3e, 0x0a, 0x31, 0x7c, 0x48, 0x17, 0xe7, + 0x4f, 0xc8, 0xca, 0x07, 0xd8, 0x1d, 0xba, 0x0b, 0xe5, 0x9c, 0xa9, 0x18, 0xe0, 0x47, 0x01, 0xf9, 0x28, 0x01, 0x37, + 0x03, 0x64, 0x8f, 0x2c, 0x01, 0xc4, 0x8a, 0xd1, 0xd1, 0xe4, 0x73, 0xdf, 0x8b, 0x14, 0xbc, 0xb3, 0xcf, 0x72, 0x35, + 0x61, 0x28, 0x7c, 0x62, 0xa0, 0x9b, 0xdf, 0xf8, 0xed, 0x79, 0x0b, 0x46, 0x76, 0x49, 0x8a, 0xd7, 0x9a, 0xe1, 0x7e, + 0x03, 0x6e, 0x47, 0x40, 0x59, 0x53, 0x1d, 0x93, 0x6c, 0xd3, 0x10, 0xc9, 0x80, 0x19, 0x31, 0x22, 0xa8, 0x2c, 0x17, + 0xfe, 0x77, 0x2f, 0x8b, 0x02, 0x07, 0x70, 0x35, 0x93, 0xc1, 0x6b, 0x17, 0x46, 0x05, 0xc0, 0x39, 0x0d, 0x9d, 0xd2, + 0x5e, 0x55, 0x1d, 0x92, 0x55, 0xf3, 0x83, 0xd9, 0xbc, 0x69, 0x98, 0x18, 0x11, 0x44, 0x17, 0xe1, 0x04, 0xd3, 0x2b, + 0xd2, 0xd7, 0x4a, 0x4e, 0x47, 0xab, 0x8e, 0xd6, 0x12, 0x13, 0x73, 0x45, 0xf1, 0xd7, 0x80, 0xc7, 0x0d, 0x5e, 0x9d, + 0xa4, 0xe9, 0x44, 0xf5, 0xe8, 0xf1, 0xeb, 0x34, 0x9d, 0x94, 0xb8, 0x2b, 0xfc, 0x06, 0x5c, 0x34, 0xdb, 0x7c, 0xe8, + 0xc7, 0x2f, 0x28, 0xe2, 0xa2, 0x06, 0x57, 0xde, 0xa9, 0xbe, 0x52, 0x7d, 0x04, 0xb5, 0xf0, 0xc4, 0xc8, 0x5a, 0x78, + 0x72, 0xc9, 0x5a, 0x0b, 0x82, 0x99, 0xcd, 0x81, 0x0b, 0xf9, 0x95, 0x52, 0xc4, 0x9b, 0x48, 0xa8, 0xc5, 0xa0, 0xf5, + 0x98, 0x39, 0xab, 0x46, 0x0b, 0x95, 0x19, 0xa1, 0x7d, 0x5b, 0x8b, 0xce, 0x6f, 0xe4, 0xa7, 0x3c, 0xb5, 0x2f, 0xdb, + 0xe3, 0x7c, 0xbc, 0x47, 0x77, 0xd5, 0x59, 0x66, 0x52, 0xc6, 0x27, 0xb3, 0x04, 0x85, 0xbb, 0x04, 0x1b, 0x90, 0x64, + 0xbf, 0xd5, 0x01, 0x32, 0x6a, 0xaf, 0xfd, 0xae, 0xb3, 0x7c, 0x75, 0xb3, 0x35, 0x14, 0x95, 0x5a, 0x49, 0x8a, 0x83, + 0x0c, 0xd7, 0x6d, 0xe5, 0xc3, 0xc5, 0x05, 0xf4, 0x8c, 0x91, 0xc8, 0x3c, 0x7f, 0x22, 0x5f, 0x82, 0x73, 0xc6, 0x59, + 0x21, 0x30, 0x61, 0xac, 0xde, 0xb5, 0x96, 0x4a, 0x43, 0x8a, 0xb1, 0xa3, 0x51, 0x96, 0x55, 0x96, 0x2e, 0xb3, 0xb5, + 0x84, 0x2d, 0xab, 0xc8, 0x2d, 0x6c, 0x99, 0xc9, 0x6a, 0x7e, 0xa8, 0xb8, 0x83, 0xf2, 0xcd, 0xd6, 0x19, 0xdf, 0x4b, + 0x64, 0xef, 0x36, 0x50, 0xc2, 0xf5, 0xe8, 0x3f, 0x90, 0x7e, 0x9b, 0x61, 0x9c, 0x72, 0x5b, 0x49, 0x0b, 0x70, 0xfa, + 0x87, 0xc3, 0x87, 0x0a, 0x83, 0x06, 0x47, 0x18, 0x47, 0xd6, 0xef, 0xdf, 0x56, 0x5e, 0x8d, 0x89, 0x3a, 0x3e, 0xab, + 0xdf, 0xaf, 0xe8, 0xe1, 0xb4, 0x1a, 0xad, 0xd2, 0x2d, 0xb2, 0x13, 0xda, 0x58, 0xf9, 0x41, 0xad, 0x80, 0xd9, 0x5b, + 0x9f, 0x4f, 0x07, 0xa0, 0x63, 0x01, 0x12, 0xcd, 0x66, 0x22, 0x31, 0x27, 0xdd, 0x93, 0xf0, 0xf8, 0xc0, 0x02, 0x07, + 0x98, 0x8a, 0xff, 0x43, 0x78, 0x33, 0xb0, 0x41, 0xa3, 0x44, 0x5f, 0xa3, 0xab, 0xda, 0xdc, 0xe8, 0x78, 0xe9, 0x29, + 0x24, 0xb2, 0x82, 0x55, 0x73, 0x5f, 0x6e, 0xe0, 0xb4, 0x87, 0x9a, 0x43, 0x65, 0x09, 0xfe, 0xf6, 0xcb, 0xfc, 0x70, + 0x58, 0x67, 0x50, 0xd8, 0x6e, 0x2d, 0xb4, 0x37, 0x66, 0xa9, 0x86, 0x8a, 0x70, 0xd0, 0xf9, 0x4a, 0xcc, 0xea, 0x11, + 0xfd, 0x3d, 0x3f, 0x1c, 0x56, 0x04, 0x06, 0x1c, 0x96, 0x32, 0x13, 0x2d, 0x14, 0x4b, 0xeb, 0x6c, 0x46, 0x75, 0xe0, + 0x81, 0x89, 0x39, 0x0b, 0x77, 0x00, 0xda, 0xa4, 0x56, 0x81, 0x5e, 0x45, 0xf4, 0x13, 0xf7, 0x6b, 0xfb, 0xf5, 0x7a, + 0x64, 0x96, 0x8e, 0xdc, 0x18, 0x0b, 0x00, 0x0e, 0x3c, 0xaf, 0x49, 0x9e, 0x93, 0xaf, 0xa1, 0xdd, 0x93, 0x0b, 0xf9, + 0x13, 0x94, 0x2d, 0x3c, 0x57, 0x4d, 0x2b, 0x8b, 0x15, 0x57, 0xd5, 0xab, 0x0b, 0x5e, 0x99, 0x4c, 0xab, 0xb4, 0x12, + 0x95, 0x12, 0x0c, 0xa8, 0x4b, 0xbc, 0xd6, 0x34, 0xa3, 0xd4, 0x46, 0x9d, 0x89, 0x1a, 0xb0, 0xc1, 0x7e, 0xaa, 0x36, + 0x3a, 0x39, 0x97, 0xcf, 0x2f, 0x8d, 0xc3, 0xa7, 0x5d, 0xbd, 0x99, 0xa9, 0x1c, 0xf8, 0x6b, 0xe5, 0x43, 0xab, 0xc7, + 0x40, 0x07, 0xe4, 0xf4, 0xc7, 0xb0, 0x98, 0xd8, 0x1d, 0x9a, 0xb7, 0xbb, 0xcb, 0xea, 0x22, 0xbd, 0xd3, 0x94, 0xcc, + 0xea, 0x2d, 0x9f, 0x59, 0x3d, 0x3a, 0xe0, 0xc5, 0x63, 0xbd, 0x57, 0x98, 0x49, 0x04, 0x17, 0x43, 0x35, 0x89, 0xec, + 0x0e, 0xb4, 0xe6, 0x51, 0xc5, 0x04, 0xf8, 0x41, 0xa9, 0x35, 0xbd, 0xb7, 0xbb, 0x42, 0x9d, 0x52, 0x78, 0xdc, 0x5a, + 0xf2, 0x03, 0x73, 0xa7, 0x5d, 0xeb, 0x7c, 0x3c, 0xbf, 0xf4, 0xfd, 0x46, 0x9e, 0xd0, 0x66, 0x67, 0x72, 0xfa, 0x27, + 0x6f, 0xf5, 0x0f, 0x53, 0x7d, 0x0b, 0xdd, 0x09, 0xfa, 0x0c, 0x5d, 0x55, 0xdd, 0x95, 0xd8, 0xc2, 0x50, 0x4f, 0x2c, + 0xf2, 0x42, 0x9e, 0xb4, 0xc6, 0x8e, 0x83, 0xbd, 0x01, 0x4e, 0xfc, 0xf2, 0x70, 0x10, 0x57, 0xb9, 0xcf, 0xce, 0xbb, + 0x46, 0x56, 0x0e, 0x60, 0x05, 0x51, 0x30, 0x6e, 0xcd, 0xc7, 0x36, 0x48, 0x97, 0xb8, 0x1a, 0x1f, 0xbf, 0xa1, 0x58, + 0x26, 0x9b, 0x88, 0x8b, 0x8b, 0xfc, 0xe9, 0x73, 0x20, 0x2d, 0xeb, 0xf7, 0xa3, 0xeb, 0xcb, 0xe9, 0xf3, 0x61, 0x14, + 0x80, 0x63, 0x97, 0xbd, 0xbc, 0x8c, 0xf9, 0xea, 0x92, 0x59, 0xa6, 0xb0, 0xc8, 0x37, 0x03, 0xaa, 0x4b, 0x56, 0x4b, + 0xd7, 0x2b, 0xc0, 0xd2, 0xe5, 0x37, 0x0f, 0x61, 0x6a, 0x40, 0x23, 0x6b, 0xee, 0x4e, 0x73, 0x2d, 0x50, 0xea, 0x79, + 0x3f, 0x33, 0xe4, 0xeb, 0x32, 0xe8, 0x0a, 0xd2, 0x3d, 0x8f, 0x48, 0x2f, 0xf7, 0xd2, 0xe9, 0x7e, 0x5f, 0x0a, 0xb0, + 0xd4, 0x97, 0xe2, 0x0b, 0x28, 0x2c, 0x1a, 0xdf, 0x08, 0xd0, 0xd6, 0x50, 0x4d, 0x7b, 0xa5, 0xa8, 0x7a, 0x41, 0xaf, + 0x14, 0x5f, 0x7a, 0x7a, 0xa8, 0xcc, 0x97, 0xa5, 0xa3, 0xff, 0x09, 0x35, 0x17, 0x9c, 0x10, 0x33, 0x31, 0x07, 0x50, + 0x09, 0xda, 0xf8, 0x56, 0x47, 0x1b, 0x9f, 0xea, 0x55, 0xdc, 0xf4, 0x79, 0x6d, 0x2d, 0x73, 0x42, 0xd8, 0x74, 0x2f, + 0x01, 0x2a, 0xf2, 0x4a, 0x78, 0x04, 0xcb, 0x2f, 0x7f, 0xc8, 0xd3, 0x15, 0xa2, 0x75, 0xdc, 0xb3, 0xcc, 0xa5, 0xb1, + 0x7f, 0x63, 0x30, 0x7d, 0x7d, 0xbb, 0x2d, 0xf2, 0x53, 0x13, 0x13, 0xd6, 0x63, 0x45, 0xdf, 0xbc, 0x0f, 0x57, 0x02, + 0x05, 0x0e, 0x25, 0x12, 0xdb, 0x54, 0xa1, 0x88, 0x07, 0x49, 0x9f, 0x2e, 0x5a, 0x9f, 0x06, 0x98, 0x5a, 0xcb, 0x81, + 0x39, 0x84, 0xab, 0xb8, 0xf0, 0xd1, 0xd3, 0xb7, 0x98, 0x85, 0xf3, 0x89, 0xf7, 0xc9, 0x2b, 0x46, 0xe6, 0xe3, 0x3e, + 0x2a, 0x95, 0xf4, 0xcf, 0xc3, 0x61, 0x56, 0xcd, 0x7d, 0x87, 0x3e, 0xd2, 0x43, 0x95, 0x0b, 0xca, 0xde, 0x18, 0x93, + 0x08, 0x94, 0xc6, 0x78, 0x1f, 0x07, 0xc7, 0x79, 0x9f, 0x06, 0x90, 0xda, 0x27, 0x3e, 0x90, 0x92, 0xc3, 0x73, 0x8e, + 0x39, 0xa1, 0xb4, 0x22, 0xac, 0xe2, 0x8b, 0x0c, 0xe5, 0xba, 0x53, 0x0a, 0x26, 0x39, 0x24, 0x18, 0xfe, 0xaa, 0x79, + 0x13, 0x2b, 0x10, 0x76, 0xcd, 0xbc, 0x1a, 0x3d, 0xa9, 0x92, 0xb0, 0x14, 0x70, 0x54, 0x66, 0x9e, 0x61, 0x6f, 0x78, + 0x62, 0x18, 0x39, 0x58, 0xee, 0x8f, 0xea, 0x44, 0xe4, 0x1e, 0x5d, 0x60, 0x54, 0x16, 0x9e, 0x37, 0x74, 0xa5, 0x41, + 0x25, 0xd9, 0xf1, 0x57, 0x5c, 0x03, 0x6a, 0x6b, 0x8c, 0x18, 0x0a, 0x18, 0x05, 0xaf, 0xed, 0x0f, 0x21, 0x8b, 0xb2, + 0xf5, 0x1b, 0x1c, 0xf3, 0x59, 0xc9, 0x5d, 0xef, 0x70, 0x16, 0x5a, 0x42, 0x9e, 0xdc, 0x31, 0x48, 0xd3, 0x58, 0x1a, + 0x01, 0x27, 0x22, 0xd9, 0xc6, 0x52, 0x38, 0x02, 0x08, 0x08, 0x74, 0x53, 0x66, 0x18, 0xd3, 0xc1, 0xc8, 0xf3, 0xa4, + 0x67, 0xbc, 0x57, 0xe1, 0x29, 0xa4, 0xc9, 0xf6, 0xf5, 0xfc, 0xbd, 0x11, 0x64, 0xe5, 0x96, 0x73, 0x3c, 0x2c, 0xbe, + 0x71, 0xf6, 0x55, 0x4e, 0x9e, 0x62, 0x96, 0x91, 0xde, 0x29, 0xe6, 0x05, 0xfc, 0xa9, 0x2c, 0xf5, 0x39, 0x4a, 0x6f, + 0x99, 0x4f, 0x56, 0x91, 0x74, 0xe9, 0x6d, 0xfa, 0xfd, 0x78, 0xa4, 0x0e, 0x35, 0x7f, 0x1f, 0x8f, 0xe4, 0x19, 0xb6, + 0x61, 0x09, 0x0b, 0xad, 0x82, 0x31, 0x80, 0x24, 0x36, 0x22, 0x1a, 0x8c, 0xf6, 0xe6, 0x70, 0x38, 0xdf, 0x98, 0xb3, + 0x64, 0x0f, 0xae, 0xaf, 0x3c, 0x31, 0xef, 0xc0, 0x97, 0x79, 0x4c, 0x10, 0xb1, 0x99, 0xb7, 0x61, 0x35, 0x78, 0xb0, + 0x83, 0xeb, 0x23, 0xb6, 0x28, 0xd6, 0x3a, 0x96, 0xca, 0x3a, 0x38, 0xad, 0x63, 0xd3, 0x8c, 0x94, 0x22, 0xfb, 0x1c, + 0xfb, 0x7b, 0x37, 0xb8, 0xba, 0x36, 0x06, 0xb5, 0xc6, 0x1d, 0xe6, 0xce, 0xa9, 0x80, 0x7a, 0x4c, 0x57, 0x50, 0x3d, + 0xab, 0xc8, 0x97, 0xdf, 0xda, 0x39, 0x20, 0x68, 0x04, 0x02, 0x17, 0x0d, 0xb4, 0x6a, 0x97, 0x72, 0xde, 0x05, 0x84, + 0xf8, 0x2e, 0x05, 0x7d, 0x3a, 0x83, 0x4d, 0x6c, 0x3e, 0x81, 0x58, 0x34, 0xdd, 0xe7, 0x5a, 0x33, 0x5f, 0x8c, 0x68, + 0x67, 0xd6, 0xdd, 0x22, 0xb7, 0x5a, 0x88, 0x64, 0xf4, 0x6c, 0x33, 0xe1, 0xa2, 0x43, 0x39, 0x23, 0x01, 0x13, 0xb4, + 0xb6, 0x52, 0xf2, 0xb9, 0xee, 0x75, 0x82, 0xf6, 0x40, 0xd2, 0xba, 0x7f, 0xb3, 0xe8, 0x8c, 0x92, 0x93, 0xeb, 0x4d, + 0xce, 0x20, 0x05, 0x0b, 0xb6, 0x97, 0x39, 0xe1, 0x06, 0xf8, 0xc4, 0x66, 0xc9, 0x69, 0x1a, 0xe4, 0xb1, 0x30, 0x1e, + 0x79, 0x6d, 0x7e, 0x59, 0x40, 0x87, 0x92, 0x45, 0x23, 0xc4, 0x03, 0xec, 0x1c, 0x92, 0xab, 0x02, 0x75, 0xd3, 0x40, + 0x57, 0xae, 0x9c, 0x29, 0xa6, 0xc0, 0x85, 0x50, 0x10, 0xb5, 0xa3, 0x93, 0xa8, 0x9c, 0xf7, 0x49, 0x75, 0x99, 0x4f, + 0x0b, 0x69, 0x1a, 0xc8, 0xa7, 0x95, 0x63, 0x1e, 0xd8, 0xd9, 0xc6, 0x35, 0x81, 0x81, 0x4e, 0xed, 0x6b, 0x51, 0xce, + 0xb1, 0x8a, 0xe8, 0x7d, 0xfe, 0xb1, 0xb2, 0xa7, 0x0f, 0x22, 0x6c, 0x54, 0xa0, 0xb1, 0x94, 0x18, 0x1b, 0x39, 0xfe, + 0x2d, 0x51, 0x36, 0x64, 0x08, 0x08, 0x21, 0x6d, 0xe4, 0xf4, 0xc3, 0xfa, 0xf2, 0x36, 0xd3, 0xfe, 0x9f, 0x24, 0x7e, + 0x1b, 0xec, 0xe5, 0xd4, 0x9f, 0x7a, 0xc4, 0xe3, 0xb5, 0x46, 0x8f, 0x29, 0xe9, 0x36, 0xc8, 0x53, 0xe5, 0x29, 0x48, + 0x26, 0x8c, 0x25, 0x04, 0x8b, 0x72, 0xc1, 0x73, 0x5e, 0x71, 0x09, 0xf7, 0x51, 0xcb, 0x8a, 0x08, 0x55, 0x89, 0x9c, + 0x3e, 0x5f, 0x01, 0xcf, 0x04, 0x04, 0x3a, 0xc6, 0x48, 0xa3, 0x0a, 0xbe, 0x04, 0xc6, 0x3a, 0x50, 0x76, 0x9a, 0x91, + 0xe0, 0xb2, 0x7b, 0x83, 0x44, 0xa9, 0xaf, 0x49, 0x49, 0xfa, 0x4e, 0xd4, 0x78, 0x25, 0x56, 0x11, 0x09, 0x64, 0xa8, + 0x21, 0x62, 0x55, 0x3d, 0x75, 0xaf, 0x8a, 0xc9, 0x60, 0x50, 0xf9, 0x72, 0x7a, 0xe2, 0x0d, 0x0d, 0x95, 0x77, 0x5d, + 0xd1, 0x4e, 0x4f, 0xb4, 0x52, 0xde, 0x42, 0x5a, 0x82, 0xa6, 0x61, 0xa4, 0x39, 0x94, 0xba, 0x92, 0xee, 0xc6, 0x20, + 0xbe, 0x64, 0xa2, 0x67, 0x3b, 0xb5, 0xa3, 0xb4, 0x25, 0xed, 0x21, 0xa4, 0xe7, 0x2e, 0xf9, 0x98, 0x85, 0x5c, 0xdd, + 0x29, 0x27, 0xe5, 0x55, 0x88, 0x4e, 0xee, 0x7b, 0x0c, 0x89, 0x40, 0x9f, 0x73, 0x0c, 0xeb, 0xa2, 0xa1, 0xce, 0x61, + 0x85, 0x98, 0x2d, 0x94, 0x30, 0x5f, 0x32, 0x9e, 0x4a, 0x06, 0x0d, 0x80, 0x0c, 0xf8, 0xe2, 0x65, 0x60, 0xf9, 0x2b, + 0x88, 0x1f, 0x6d, 0x7c, 0x38, 0xfc, 0x59, 0x53, 0x88, 0xed, 0x9f, 0xb0, 0x19, 0xc2, 0xa3, 0x7a, 0xc0, 0x33, 0xdf, + 0xc4, 0x09, 0x5a, 0x01, 0x49, 0x99, 0x1d, 0x4d, 0x64, 0xaf, 0x7a, 0x08, 0xa7, 0xb2, 0x02, 0x75, 0x94, 0x75, 0x56, + 0xc2, 0x8f, 0x30, 0xd5, 0xad, 0xc4, 0x5a, 0xa0, 0xcd, 0xd5, 0x8a, 0xb5, 0x00, 0x0e, 0xfc, 0x1c, 0x82, 0x27, 0xf2, + 0x39, 0xb8, 0x18, 0x14, 0xe0, 0x73, 0x00, 0xbc, 0xc8, 0x5d, 0x78, 0x30, 0x8f, 0x2c, 0xab, 0x11, 0x86, 0xa3, 0x8a, + 0x58, 0xbf, 0x66, 0x3b, 0xf2, 0x81, 0xdb, 0x31, 0x3e, 0xd7, 0x1e, 0x4b, 0x96, 0x83, 0x51, 0xe6, 0x5e, 0x2d, 0xd1, + 0xf3, 0x26, 0x8d, 0x9b, 0xd1, 0x93, 0x7d, 0x2d, 0xff, 0x17, 0xf4, 0x32, 0xe8, 0x6f, 0xe1, 0x96, 0xd7, 0xfc, 0x6e, + 0x41, 0xa4, 0x99, 0x5e, 0x41, 0xa4, 0x8c, 0x1a, 0x91, 0x31, 0x84, 0x4d, 0xaa, 0x9b, 0xdb, 0xa4, 0xba, 0x10, 0xf0, + 0x74, 0x44, 0xaa, 0x6b, 0x21, 0x6d, 0xe4, 0xd3, 0x3a, 0x90, 0xb1, 0x48, 0xef, 0x7f, 0xfc, 0xcb, 0x8b, 0xcf, 0x6f, + 0x7f, 0xf9, 0x71, 0xf1, 0xf6, 0xfd, 0x9b, 0xb7, 0xef, 0xdf, 0x7e, 0xfe, 0x8d, 0x20, 0x3c, 0xa6, 0x42, 0x65, 0xf8, + 0xf8, 0xe1, 0xe6, 0xad, 0x93, 0xc1, 0xf6, 0x66, 0xc8, 0xda, 0x37, 0x72, 0x30, 0x04, 0x22, 0x1b, 0x84, 0x0c, 0xb2, + 0x53, 0x32, 0xc7, 0x4c, 0xcc, 0x31, 0xf6, 0x4e, 0x60, 0xb2, 0x05, 0x9c, 0x63, 0x99, 0x97, 0x8c, 0xc8, 0x55, 0xa1, + 0xf5, 0x03, 0x5a, 0xf0, 0x0e, 0x5c, 0x64, 0xd2, 0xfc, 0xee, 0x17, 0x82, 0xd8, 0xa7, 0x95, 0x94, 0xfb, 0x6a, 0x5b, + 0xf3, 0x7c, 0x7b, 0xbf, 0x97, 0x70, 0xfe, 0x73, 0x69, 0x44, 0x2d, 0xc0, 0x01, 0xf8, 0x1c, 0xfe, 0xb8, 0xd2, 0x96, + 0x34, 0x99, 0x45, 0xfb, 0x19, 0x43, 0xd0, 0xa5, 0xc1, 0x07, 0xb1, 0x47, 0x5e, 0xea, 0x93, 0x85, 0x04, 0xee, 0x88, + 0xe1, 0xd3, 0x8a, 0xa0, 0x57, 0x8c, 0x28, 0x2e, 0xb9, 0x42, 0xa5, 0x94, 0xfc, 0x1b, 0x65, 0x17, 0x15, 0x72, 0x56, + 0xb0, 0x7b, 0x45, 0x8e, 0x8c, 0x1f, 0x04, 0x13, 0x5f, 0x0e, 0xee, 0xbf, 0xc4, 0x3b, 0x9c, 0x29, 0x8e, 0xe4, 0x84, + 0x3f, 0x64, 0x18, 0xd8, 0x9f, 0x83, 0xcf, 0xab, 0xc3, 0xbc, 0xbc, 0xd1, 0xa7, 0xdc, 0x92, 0x8f, 0x27, 0xcb, 0x2b, + 0x30, 0xd8, 0x2f, 0x55, 0x73, 0xd7, 0xbc, 0x9e, 0x2d, 0xe7, 0x6c, 0x3f, 0x8b, 0xe6, 0xc1, 0x1d, 0x9b, 0x65, 0xf3, + 0x60, 0xd5, 0xf0, 0x35, 0xbb, 0xe5, 0x6b, 0xab, 0x6a, 0x6b, 0xbb, 0x6a, 0x93, 0x0d, 0xbf, 0x05, 0x09, 0xe1, 0x26, + 0xf3, 0x80, 0xf7, 0xf8, 0xce, 0x67, 0x1b, 0x90, 0x68, 0x57, 0x6c, 0x03, 0x17, 0xb1, 0x35, 0xff, 0xb1, 0xf2, 0x36, + 0xac, 0x64, 0xe7, 0x63, 0x96, 0xe3, 0xfc, 0xf3, 0xe1, 0x01, 0xed, 0x85, 0xfa, 0xd9, 0xa5, 0x7a, 0x36, 0x51, 0x76, + 0xb3, 0xcd, 0x68, 0x71, 0x9f, 0x56, 0x9b, 0x30, 0x43, 0xcf, 0x72, 0xf8, 0x68, 0x2b, 0x05, 0x3f, 0xbd, 0xc0, 0x2f, + 0xd9, 0x51, 0x5b, 0x69, 0xdb, 0xae, 0x4a, 0x6c, 0x05, 0x2d, 0x8a, 0xac, 0x56, 0x78, 0x60, 0xce, 0xaf, 0x61, 0x01, + 0x63, 0xcf, 0x71, 0xce, 0x6b, 0x7f, 0x84, 0x8c, 0xf7, 0x0e, 0x00, 0x5a, 0xe6, 0x38, 0xc0, 0x23, 0x56, 0x8c, 0xa2, + 0xc1, 0x3b, 0xbf, 0x54, 0x56, 0x2b, 0xcd, 0x49, 0x68, 0x1b, 0xb1, 0x6a, 0x39, 0x52, 0x35, 0x23, 0xd2, 0x07, 0xe9, + 0x79, 0xdf, 0x23, 0xaa, 0xc1, 0x9e, 0xcc, 0xeb, 0xc0, 0x3e, 0xbd, 0x6a, 0xad, 0xea, 0xce, 0xef, 0xa9, 0xd2, 0x25, + 0x47, 0xb6, 0xfc, 0x74, 0x19, 0x3e, 0xa8, 0x3f, 0x25, 0xd7, 0x87, 0x02, 0x47, 0x78, 0xac, 0x02, 0xce, 0xd7, 0x2b, + 0xd1, 0xee, 0x44, 0xd8, 0x95, 0x4b, 0x40, 0x88, 0x2f, 0x69, 0x9a, 0xe3, 0x71, 0x44, 0x13, 0x11, 0x36, 0x31, 0xfa, + 0x0b, 0xbb, 0x0f, 0x25, 0x96, 0xf3, 0x5c, 0x83, 0x92, 0x4b, 0x06, 0xef, 0x49, 0x7b, 0x0d, 0x9a, 0xe5, 0x55, 0xa9, + 0xc9, 0x44, 0x0e, 0xca, 0x87, 0x43, 0x01, 0x7b, 0xa9, 0xf1, 0xd3, 0x84, 0x9f, 0xb0, 0xbc, 0xb5, 0xb7, 0xa6, 0x14, + 0x95, 0x34, 0x40, 0x05, 0x3e, 0x66, 0xf0, 0xbf, 0x3b, 0x43, 0x2c, 0x98, 0xa2, 0xe3, 0x87, 0x33, 0x31, 0xb7, 0x9e, + 0x5b, 0x65, 0x1d, 0x65, 0x6b, 0x94, 0x13, 0xf0, 0x6f, 0xa9, 0x8e, 0x93, 0x44, 0x38, 0xf5, 0x1e, 0x71, 0x51, 0xf7, + 0x72, 0x88, 0xba, 0x61, 0x6f, 0x2b, 0x1d, 0x6c, 0x39, 0x4d, 0x83, 0x23, 0xf1, 0x2b, 0xf5, 0xd9, 0x87, 0xcc, 0xe2, + 0x51, 0x47, 0x36, 0xa2, 0x24, 0x8d, 0x63, 0x91, 0xc3, 0xf6, 0xbe, 0x90, 0xfb, 0x7f, 0xbf, 0x0f, 0xe1, 0xa4, 0x55, + 0x90, 0x94, 0x9e, 0x40, 0x44, 0x38, 0x3a, 0xfc, 0x88, 0xf0, 0x44, 0xaa, 0x0a, 0x9f, 0xd4, 0x27, 0x6e, 0xcc, 0xee, + 0x85, 0x39, 0xaa, 0xb7, 0x00, 0xc3, 0x58, 0x6f, 0x2d, 0x42, 0x12, 0xad, 0x34, 0xa3, 0xad, 0x07, 0xc4, 0x88, 0x0f, + 0x6b, 0x8b, 0x0c, 0xc6, 0xda, 0x92, 0x48, 0x00, 0xbf, 0x23, 0x21, 0x43, 0xdb, 0x46, 0x60, 0xc6, 0xf0, 0x76, 0x56, + 0x5c, 0xba, 0x0e, 0xdb, 0x9c, 0xc3, 0x17, 0xb2, 0xd0, 0xac, 0x23, 0x4a, 0x13, 0x84, 0xfc, 0x03, 0x4e, 0x16, 0x0a, + 0xa3, 0x79, 0x7d, 0x94, 0x4e, 0x12, 0xeb, 0x87, 0xae, 0x52, 0xc1, 0x66, 0x73, 0x83, 0xfa, 0xb2, 0xa3, 0xe4, 0x57, + 0xe0, 0xa4, 0xe3, 0x24, 0x8b, 0x1c, 0x44, 0x2d, 0x2a, 0xe7, 0x26, 0x09, 0x4b, 0xbb, 0x3a, 0xd5, 0x66, 0xbd, 0x2e, + 0xca, 0xba, 0x7a, 0x2d, 0x22, 0x45, 0xef, 0xa3, 0x1e, 0x3d, 0x91, 0x90, 0x0a, 0xad, 0x4a, 0xed, 0xf2, 0x08, 0xdc, + 0x36, 0xb5, 0x62, 0x5b, 0x2e, 0x61, 0x89, 0x1a, 0xff, 0x19, 0xfa, 0x28, 0x17, 0x0f, 0x32, 0x40, 0xa3, 0xe3, 0xa9, + 0x79, 0xeb, 0x91, 0x57, 0x8e, 0xf2, 0x4b, 0xab, 0x4d, 0xfa, 0x15, 0x90, 0x19, 0xed, 0x1f, 0x2d, 0x25, 0x90, 0x19, + 0x98, 0x49, 0x4b, 0x43, 0x22, 0x47, 0x31, 0x4b, 0xf3, 0x3f, 0x70, 0xc5, 0x56, 0x88, 0x34, 0xac, 0xe6, 0x1e, 0x7f, + 0x51, 0x79, 0xb5, 0x5c, 0xcb, 0x4c, 0x73, 0xb3, 0xc4, 0xb1, 0x62, 0x71, 0x51, 0xaf, 0x2b, 0x91, 0x05, 0x42, 0x1c, + 0x61, 0x1a, 0xeb, 0xa9, 0x37, 0x4a, 0xab, 0x8f, 0x48, 0x28, 0xf3, 0x23, 0xf6, 0x76, 0xec, 0xf5, 0x20, 0x0b, 0x71, + 0x6c, 0x39, 0xd8, 0x6c, 0xbd, 0xcf, 0x65, 0x2a, 0xe2, 0xb3, 0xba, 0x38, 0xdb, 0x54, 0xe2, 0xac, 0x4e, 0xc4, 0xd9, + 0x0f, 0x90, 0xf3, 0x87, 0x33, 0x2a, 0xfa, 0xec, 0x21, 0xad, 0x93, 0x62, 0x53, 0xd3, 0x93, 0x37, 0x58, 0xc6, 0x0f, + 0x67, 0xc4, 0x55, 0x73, 0x46, 0x23, 0x19, 0x8f, 0xce, 0x3e, 0x66, 0x40, 0xf2, 0x7a, 0x96, 0xae, 0x60, 0xf0, 0xce, + 0xc2, 0x3c, 0x3e, 0x2b, 0xc5, 0x1d, 0x58, 0x9c, 0xca, 0xce, 0xf7, 0x20, 0xc3, 0x2a, 0xfc, 0x43, 0x9c, 0x01, 0xb4, + 0xeb, 0x59, 0x5a, 0x9f, 0xa5, 0xd5, 0x59, 0x5e, 0xd4, 0x67, 0x4a, 0x0a, 0x87, 0x30, 0x7e, 0x78, 0x4f, 0x5f, 0xd9, + 0xe5, 0x6d, 0x16, 0x77, 0x59, 0xe4, 0x4f, 0xd1, 0xab, 0x88, 0x98, 0x34, 0x2a, 0xe1, 0xb5, 0xfb, 0xdb, 0xe6, 0xfe, + 0xe1, 0x75, 0x63, 0xf7, 0xb3, 0x3b, 0x46, 0x74, 0x41, 0x3d, 0x5e, 0x49, 0x4a, 0x05, 0x05, 0x04, 0x4e, 0x34, 0x6b, + 0x3c, 0xb8, 0xe3, 0x80, 0x57, 0x03, 0x5b, 0xb2, 0xb5, 0xcf, 0xaf, 0x63, 0x19, 0xa6, 0xbd, 0x09, 0xf0, 0xaf, 0xb2, + 0x37, 0x5d, 0x07, 0x4b, 0xbc, 0x6f, 0x21, 0xdb, 0xd0, 0xdb, 0xd7, 0xfc, 0x85, 0x97, 0xab, 0xbf, 0xd9, 0x3f, 0x00, + 0x08, 0x03, 0x62, 0x56, 0x7d, 0x34, 0x71, 0xef, 0xac, 0x2c, 0x3b, 0x27, 0xcb, 0xae, 0x87, 0x7e, 0x4d, 0x62, 0x54, + 0x5a, 0x59, 0x4a, 0x27, 0x4b, 0x09, 0x59, 0xc0, 0x27, 0x46, 0x53, 0x1b, 0x01, 0x84, 0xed, 0x28, 0x95, 0x2f, 0x54, + 0x5e, 0x44, 0xe1, 0x9c, 0xe0, 0x79, 0x22, 0x46, 0xf7, 0x56, 0x32, 0x60, 0x38, 0x84, 0x60, 0x0e, 0xda, 0x62, 0x6f, + 0xe8, 0x26, 0xe2, 0xaf, 0x37, 0x45, 0xf9, 0x36, 0x26, 0x9f, 0x82, 0xdd, 0xc9, 0xc7, 0x25, 0x3c, 0x2e, 0x4f, 0x3e, + 0x0e, 0xd1, 0x23, 0xe1, 0xe4, 0x63, 0xf0, 0x3d, 0x92, 0xf3, 0xba, 0xeb, 0x71, 0x82, 0xdc, 0x42, 0xba, 0xbf, 0x1d, + 0x93, 0x00, 0xcd, 0x6b, 0x58, 0x8e, 0x9a, 0x8a, 0x6b, 0x66, 0xc6, 0x78, 0xde, 0xe8, 0xfd, 0xb1, 0xe3, 0x2d, 0x53, + 0x28, 0x66, 0x31, 0xaf, 0xe1, 0xf7, 0xac, 0x0a, 0xd4, 0x5d, 0x6f, 0x93, 0xdc, 0x32, 0xab, 0xe7, 0x68, 0xf7, 0xfd, + 0x50, 0x27, 0x82, 0xda, 0xdf, 0x61, 0xcf, 0x33, 0xeb, 0x5d, 0x15, 0x03, 0x97, 0x2a, 0xd9, 0x21, 0x53, 0xd5, 0xf4, + 0x40, 0xa5, 0x34, 0x78, 0x7a, 0x69, 0x5d, 0xbe, 0x54, 0xda, 0xc8, 0x33, 0xcd, 0x6f, 0x00, 0x2f, 0xa6, 0x2e, 0x8b, + 0xdd, 0x37, 0xf7, 0x15, 0xdc, 0xc6, 0xfb, 0xfd, 0x65, 0xe5, 0x99, 0x9f, 0xb8, 0x00, 0xec, 0x4d, 0x85, 0xd6, 0x09, + 0x94, 0x1a, 0xd6, 0xe1, 0xab, 0x44, 0x44, 0x7f, 0xb4, 0xcb, 0x75, 0xe6, 0x3a, 0x60, 0x44, 0x11, 0xbf, 0x8d, 0x47, + 0x7f, 0x80, 0xe2, 0xda, 0xd8, 0x03, 0xc2, 0x3a, 0x24, 0xf4, 0x19, 0x01, 0x48, 0x3d, 0xe6, 0x28, 0x01, 0xcd, 0x8a, + 0xe6, 0x8e, 0xc9, 0xcf, 0xf5, 0x95, 0xd2, 0xdf, 0x2f, 0x2b, 0x8f, 0xcc, 0x29, 0x6d, 0x33, 0x8d, 0xd5, 0x9a, 0x4a, + 0x20, 0xbc, 0xa2, 0x92, 0x55, 0xf8, 0x6c, 0xde, 0x88, 0x7e, 0x5f, 0x1e, 0xe1, 0x69, 0xf5, 0xe3, 0x16, 0xe3, 0x5b, + 0x01, 0xd1, 0x48, 0x00, 0xf4, 0x13, 0xc0, 0xbc, 0xc8, 0x66, 0x76, 0x1f, 0x07, 0x54, 0x29, 0xd1, 0x34, 0xce, 0xe6, + 0xf9, 0x3d, 0xbd, 0x29, 0x3b, 0xe8, 0xd4, 0xa9, 0x02, 0x17, 0x5c, 0x95, 0x8c, 0x57, 0xd6, 0x13, 0xf9, 0xfc, 0xe6, + 0x76, 0x93, 0x66, 0xf1, 0x87, 0xf2, 0x1f, 0x38, 0xb6, 0xba, 0x0e, 0x8f, 0x4c, 0x9d, 0xae, 0x9d, 0x47, 0x5a, 0x7b, + 0x21, 0x20, 0xa2, 0x5d, 0x43, 0xad, 0x17, 0x16, 0x7a, 0xa4, 0x27, 0xc2, 0x39, 0x49, 0xd4, 0xb4, 0x03, 0x2d, 0x8d, + 0xd0, 0xd7, 0xd7, 0x9c, 0xfe, 0xc2, 0x60, 0xed, 0xf3, 0x31, 0x03, 0xb2, 0x12, 0xfd, 0x58, 0x3d, 0x34, 0x36, 0x73, + 0xe8, 0x59, 0xab, 0xf2, 0xcc, 0xab, 0x0e, 0x07, 0xc4, 0x87, 0xd1, 0x5f, 0xf2, 0xfb, 0xfd, 0xd7, 0x34, 0xff, 0x98, + 0x50, 0xe3, 0x67, 0x9b, 0x01, 0xba, 0xf6, 0x5d, 0x79, 0x20, 0xea, 0xb9, 0x56, 0x09, 0x42, 0xbc, 0x41, 0x4c, 0x34, + 0x23, 0xe6, 0xe0, 0xb4, 0x43, 0xcd, 0x3f, 0x49, 0x0d, 0x08, 0x51, 0xe2, 0x75, 0x4c, 0x59, 0x90, 0xd3, 0x26, 0x8e, + 0xf4, 0xa3, 0x70, 0x22, 0x3f, 0x89, 0xaa, 0xc8, 0xee, 0xe1, 0x82, 0xc1, 0xd4, 0x7b, 0xda, 0x2f, 0xd1, 0x6f, 0x09, + 0x47, 0xce, 0xd1, 0xaa, 0x10, 0x44, 0x4e, 0x08, 0x6b, 0x0d, 0x61, 0x82, 0xd8, 0x20, 0x5e, 0xf6, 0x5d, 0x92, 0xe1, + 0x48, 0xc1, 0x65, 0x1d, 0x3b, 0xc6, 0x5c, 0x1d, 0x55, 0xaf, 0x01, 0x8c, 0x57, 0x8e, 0xa0, 0xd9, 0x28, 0xb2, 0x4b, + 0x88, 0x2a, 0x72, 0x3c, 0x01, 0xb5, 0x83, 0xd2, 0xd8, 0x4c, 0xcf, 0xc7, 0x41, 0x3e, 0x5a, 0x54, 0xa8, 0x73, 0x62, + 0x19, 0xaf, 0x01, 0x58, 0x3b, 0x57, 0xfd, 0x3c, 0xab, 0xc1, 0x93, 0x86, 0xf8, 0x7c, 0x8c, 0xb6, 0x57, 0x36, 0x07, + 0xd5, 0x76, 0x3a, 0x2b, 0xaf, 0x98, 0x2e, 0x07, 0xc6, 0x7d, 0xc3, 0x2b, 0x8a, 0x33, 0xfc, 0xe4, 0xc1, 0x16, 0xe7, + 0x4f, 0x37, 0xd4, 0x7e, 0xcc, 0x8d, 0x7a, 0x18, 0x68, 0x2d, 0x78, 0x53, 0x10, 0xeb, 0xef, 0xc7, 0x8e, 0x6c, 0x1f, + 0xb4, 0xc8, 0x68, 0xf2, 0xd9, 0xcf, 0x3f, 0x96, 0xe9, 0x2a, 0x85, 0xfb, 0x92, 0x93, 0x45, 0x33, 0x0f, 0x81, 0xbd, + 0x21, 0x86, 0xeb, 0xa3, 0xc2, 0x23, 0xca, 0xfa, 0x7d, 0xf8, 0x7d, 0x95, 0x81, 0x29, 0x06, 0xae, 0x2b, 0x04, 0xe3, + 0x21, 0x10, 0xc4, 0xc3, 0x34, 0x3a, 0x19, 0xd4, 0xa0, 0x0d, 0xdf, 0x00, 0x64, 0x06, 0x78, 0x64, 0x2e, 0x3d, 0x02, + 0xee, 0x02, 0xd7, 0x9e, 0x8c, 0xc7, 0xfe, 0xc4, 0x34, 0x34, 0x6a, 0x4a, 0x33, 0x3d, 0x37, 0x7e, 0xd3, 0x51, 0x2d, + 0xd7, 0xce, 0x7f, 0x7c, 0xc9, 0x6f, 0xd0, 0x0b, 0x5a, 0x5e, 0xee, 0x23, 0x75, 0xb9, 0xcf, 0x28, 0x2e, 0x13, 0xc9, + 0x61, 0x41, 0x2c, 0x4b, 0x38, 0xf0, 0x18, 0x95, 0x2c, 0xb6, 0xf4, 0x58, 0x15, 0x2d, 0x5f, 0x94, 0x1b, 0xa4, 0x43, + 0x27, 0x04, 0x4b, 0x54, 0x10, 0x2c, 0x81, 0x71, 0x11, 0x6b, 0xbe, 0x19, 0xe4, 0x2c, 0x9e, 0x6d, 0xe6, 0x1c, 0x09, + 0xeb, 0x92, 0xc3, 0xa1, 0x90, 0x60, 0x33, 0xd9, 0x6c, 0x3d, 0x67, 0x6b, 0x9f, 0x81, 0x12, 0xa0, 0x94, 0x69, 0x82, + 0xd2, 0xb4, 0x62, 0x2b, 0x6e, 0x5a, 0x83, 0xd5, 0x6a, 0xca, 0x56, 0x35, 0x65, 0xe7, 0x34, 0xe5, 0xa8, 0x82, 0x92, + 0x13, 0x4a, 0x51, 0x86, 0x01, 0x8c, 0xd8, 0x24, 0xba, 0xca, 0xd0, 0xc7, 0x3b, 0xe1, 0x11, 0x54, 0x11, 0x91, 0x4f, + 0x18, 0x42, 0x60, 0x22, 0x8a, 0x0b, 0x55, 0x28, 0x06, 0xc8, 0x88, 0x04, 0x82, 0x89, 0x4a, 0x9d, 0x02, 0xf3, 0xd1, + 0x54, 0x31, 0x6c, 0xda, 0x13, 0xe5, 0x7b, 0xea, 0xb8, 0x47, 0xd9, 0xe6, 0x6f, 0x62, 0x17, 0x84, 0xc8, 0xdd, 0xb8, + 0x53, 0x3f, 0x23, 0xde, 0xdb, 0x1d, 0x61, 0xfc, 0x64, 0xc7, 0x2d, 0xc2, 0x15, 0xc1, 0x96, 0x6a, 0x0e, 0xb1, 0x98, + 0x57, 0x93, 0x04, 0xb5, 0x2c, 0x89, 0xbf, 0xe1, 0xc9, 0x20, 0x67, 0x4b, 0xf0, 0xa0, 0x9d, 0xb3, 0x0c, 0xf0, 0x57, + 0xac, 0x16, 0xfd, 0x56, 0x7b, 0x4b, 0x90, 0x9f, 0x36, 0x76, 0xa3, 0x30, 0x31, 0x82, 0x44, 0xdd, 0xae, 0x0c, 0xe4, + 0x87, 0x8f, 0x38, 0x1d, 0x8f, 0x3d, 0x65, 0xcc, 0xad, 0x4c, 0x2f, 0xd3, 0xb9, 0x92, 0x6f, 0xe4, 0x5e, 0xfa, 0xd8, + 0x4b, 0xb0, 0x73, 0xc0, 0x1b, 0x48, 0x1b, 0x78, 0x03, 0xdb, 0x85, 0xd7, 0x06, 0x09, 0x33, 0x02, 0x6c, 0x71, 0x7c, + 0x8c, 0x94, 0xc0, 0x10, 0x8e, 0xb3, 0x14, 0x80, 0x69, 0xf4, 0x65, 0xb6, 0xb2, 0x2f, 0xb3, 0x5a, 0xb3, 0xa5, 0x72, + 0xba, 0x77, 0x6e, 0xdd, 0xce, 0x27, 0x12, 0x00, 0x4c, 0xea, 0x1c, 0x88, 0x33, 0x13, 0xec, 0xd2, 0x24, 0xb2, 0x7c, + 0x0a, 0xf3, 0x3b, 0xf1, 0xa6, 0x2c, 0x56, 0xaa, 0x2b, 0xda, 0x3e, 0x33, 0xf9, 0x8c, 0x74, 0x12, 0x2a, 0xa0, 0xa0, + 0x90, 0x6b, 0x7d, 0xfa, 0x3e, 0x7c, 0x1f, 0x14, 0x1a, 0x98, 0xad, 0xc2, 0x3d, 0x4d, 0xd6, 0x48, 0xbd, 0x51, 0xf5, + 0xfb, 0xe4, 0x1a, 0x48, 0x75, 0xe6, 0xd0, 0xb2, 0x27, 0x15, 0x06, 0x88, 0x1d, 0xf5, 0x19, 0x09, 0x75, 0x20, 0xf5, + 0x80, 0x21, 0x44, 0xdb, 0xf4, 0xf1, 0x27, 0x43, 0xa2, 0x0b, 0xb0, 0x85, 0x68, 0x03, 0x3f, 0xfe, 0x04, 0xfb, 0x2c, + 0x08, 0x8f, 0x69, 0xfe, 0x0e, 0x92, 0x8e, 0x0d, 0x9c, 0x56, 0x9f, 0x82, 0x0f, 0x92, 0x1c, 0x4c, 0xd4, 0xc1, 0xcb, + 0xfd, 0xa5, 0xdf, 0x87, 0x2d, 0x3b, 0x97, 0x52, 0x1d, 0x2b, 0xf5, 0xb6, 0xad, 0xfd, 0x20, 0xda, 0x82, 0x23, 0x8b, + 0xf8, 0x87, 0x0c, 0x11, 0xc1, 0xcc, 0x20, 0xc2, 0xae, 0x85, 0xba, 0xdb, 0x53, 0x6a, 0x59, 0xd4, 0xdb, 0x9e, 0x52, + 0xea, 0x36, 0x0c, 0xdf, 0x4d, 0x30, 0x53, 0xdc, 0xf0, 0x3f, 0x32, 0x2f, 0xd4, 0x1b, 0x8f, 0x45, 0x81, 0xee, 0xf9, + 0xfb, 0x25, 0xaf, 0x66, 0x1b, 0x65, 0xc2, 0xbc, 0xe3, 0xcb, 0x59, 0x28, 0xbb, 0x5a, 0x1a, 0x77, 0xbe, 0x78, 0x4b, + 0x35, 0x1f, 0xfc, 0xc3, 0x21, 0x81, 0x78, 0xa3, 0xf8, 0xea, 0xae, 0x91, 0x5b, 0xd7, 0x64, 0x73, 0x55, 0x02, 0xea, + 0xf7, 0xf9, 0x1a, 0xf7, 0x5b, 0xac, 0x7f, 0xf7, 0x34, 0xc8, 0x58, 0xcd, 0x70, 0xc5, 0x14, 0x3e, 0x05, 0x80, 0xc1, + 0xe1, 0x54, 0x90, 0x16, 0x78, 0xc3, 0xcb, 0xe1, 0xe5, 0x64, 0x43, 0x26, 0xdd, 0x8d, 0x8f, 0xdc, 0x59, 0xa0, 0xea, + 0xfd, 0x8e, 0xe2, 0xa4, 0x41, 0xa2, 0xb1, 0xd7, 0xe0, 0x8b, 0x2c, 0xa3, 0x5c, 0x34, 0x71, 0x1f, 0x93, 0xaf, 0xf4, + 0x00, 0xe6, 0x2a, 0x94, 0x00, 0xd1, 0x6f, 0x2c, 0x8b, 0x8d, 0x68, 0x5b, 0x6c, 0x60, 0x29, 0x55, 0x73, 0xbd, 0x9a, + 0xbe, 0x78, 0x25, 0x9a, 0xf7, 0xd1, 0x8c, 0x53, 0x1a, 0x0d, 0x38, 0x4e, 0xa3, 0x70, 0xfb, 0xe1, 0x5e, 0x94, 0xcb, + 0x0c, 0x2c, 0xd9, 0x2a, 0x9c, 0xe2, 0xb2, 0x51, 0x67, 0xc4, 0x8b, 0x3c, 0x56, 0x00, 0x1d, 0x8f, 0x09, 0x80, 0xea, + 0x82, 0x80, 0x8a, 0x68, 0x29, 0xbd, 0x15, 0x5a, 0x2c, 0xd4, 0x1b, 0x8e, 0x52, 0xf8, 0x23, 0xfd, 0x79, 0x90, 0x4f, + 0x01, 0x88, 0x5d, 0x1f, 0x47, 0x6f, 0x8a, 0x92, 0x3e, 0x55, 0xcc, 0x72, 0x39, 0x98, 0xc0, 0xae, 0x4e, 0x64, 0xa8, + 0x15, 0xe4, 0xad, 0xba, 0xf2, 0x56, 0x26, 0x6f, 0x63, 0x9c, 0x92, 0x1f, 0xb9, 0xe9, 0x58, 0x23, 0x06, 0x5e, 0x79, + 0x5a, 0xa7, 0x09, 0xd2, 0xe4, 0x02, 0x18, 0x86, 0xf8, 0x36, 0xf3, 0x5e, 0x78, 0x8e, 0x54, 0x05, 0xc9, 0x6c, 0x97, + 0x79, 0xea, 0x22, 0xaa, 0xaf, 0x9c, 0x5a, 0x3a, 0x73, 0xfa, 0x11, 0xc0, 0x7b, 0x4c, 0x4d, 0x1a, 0xf2, 0x11, 0x6e, + 0x4b, 0xf1, 0xf5, 0x56, 0x5d, 0xe3, 0xa5, 0xd1, 0xb9, 0x7b, 0xf9, 0xd2, 0x9d, 0x06, 0xfd, 0x14, 0x04, 0xe5, 0x7c, + 0x51, 0x0a, 0xd8, 0x53, 0x66, 0x73, 0xbd, 0x5a, 0xb5, 0x42, 0xeb, 0x70, 0x18, 0x6b, 0x47, 0x21, 0xad, 0xce, 0x02, + 0xb6, 0x1a, 0xe9, 0x94, 0x00, 0x21, 0x38, 0x4e, 0xc3, 0x4e, 0x30, 0xee, 0xd2, 0x69, 0x44, 0xd6, 0x2b, 0x25, 0xe9, + 0xc2, 0x0c, 0x92, 0x7f, 0x92, 0xd7, 0x33, 0xa0, 0x25, 0x80, 0x43, 0x11, 0x4b, 0x78, 0x38, 0x49, 0xae, 0x00, 0x3a, + 0x1d, 0x0e, 0x2a, 0x0d, 0xcd, 0x59, 0xcd, 0x92, 0xf9, 0x24, 0x96, 0xaa, 0xca, 0xc3, 0xc1, 0x53, 0x6e, 0x06, 0xfd, + 0x7e, 0x36, 0x2d, 0x95, 0x0b, 0x40, 0x10, 0xeb, 0xc2, 0x00, 0xf1, 0x48, 0x0b, 0x4f, 0x16, 0x7d, 0x4a, 0xe2, 0x97, + 0xb3, 0x64, 0x6e, 0xb2, 0xe1, 0x1d, 0x18, 0xc1, 0x66, 0x5c, 0x97, 0x94, 0x69, 0x8f, 0xca, 0xef, 0x19, 0x3d, 0xb5, + 0x7d, 0xad, 0xd5, 0x16, 0xb1, 0xae, 0x83, 0xab, 0x12, 0xf5, 0x14, 0x1f, 0x94, 0x24, 0x78, 0xbf, 0x76, 0x6e, 0x46, + 0xca, 0xd7, 0x22, 0xf7, 0x83, 0x76, 0xa6, 0x56, 0x0e, 0x1c, 0x81, 0x1c, 0xab, 0xa8, 0xe4, 0xf5, 0xae, 0x43, 0xf0, + 0xe8, 0xae, 0x54, 0xa0, 0x1c, 0x7c, 0x0d, 0x62, 0x74, 0x7d, 0xd5, 0x59, 0x43, 0xcd, 0x34, 0xaa, 0x3c, 0x82, 0x4e, + 0x1d, 0xc0, 0x93, 0x82, 0x97, 0x5a, 0xfd, 0x78, 0x38, 0x78, 0xe6, 0x07, 0x7f, 0x95, 0xe9, 0x5b, 0x88, 0x89, 0x72, + 0xaa, 0x11, 0x12, 0x57, 0x4a, 0x12, 0xf1, 0xf1, 0xa2, 0x65, 0xc5, 0xa8, 0x0c, 0x1f, 0x78, 0xa5, 0xca, 0x57, 0xa7, + 0x2a, 0x2f, 0x46, 0xda, 0x96, 0xc0, 0x6b, 0xf2, 0x0f, 0x91, 0x6b, 0xde, 0xfa, 0xba, 0xab, 0x0c, 0x7d, 0x27, 0x2b, + 0xd0, 0x11, 0x6c, 0x65, 0x29, 0x39, 0xe0, 0x93, 0xea, 0xae, 0x5a, 0xb5, 0x3e, 0xa7, 0x6c, 0x23, 0xdc, 0xe4, 0xd7, + 0xb1, 0x83, 0x23, 0xe5, 0x37, 0x78, 0x2e, 0x80, 0xbd, 0x06, 0xec, 0xcd, 0x39, 0x2b, 0x9a, 0x47, 0x87, 0xb4, 0x2d, + 0xd0, 0xc8, 0xcc, 0xed, 0x5c, 0xdd, 0xb7, 0xe5, 0x51, 0x1a, 0x43, 0x64, 0xda, 0x23, 0xd3, 0xc1, 0x66, 0x94, 0xff, + 0x9e, 0xf2, 0x5b, 0x85, 0x63, 0xe0, 0xdb, 0xa9, 0x77, 0x00, 0x55, 0x4f, 0x1b, 0x64, 0xac, 0x19, 0x86, 0x56, 0x76, + 0xb9, 0x14, 0x5a, 0x82, 0x96, 0xba, 0x09, 0x82, 0xf3, 0x23, 0xa2, 0x1c, 0x01, 0xe8, 0x22, 0x05, 0x4c, 0xf0, 0x53, + 0xda, 0xee, 0x7e, 0x7f, 0x9d, 0x7a, 0xe4, 0xde, 0x15, 0x6a, 0x94, 0x50, 0x82, 0xb1, 0x9f, 0x68, 0xcc, 0xa0, 0xa3, + 0x2b, 0x72, 0xc2, 0xb3, 0x56, 0x87, 0x75, 0xdd, 0x94, 0x41, 0x59, 0x1c, 0xf3, 0x6a, 0x3a, 0xfb, 0xfd, 0xc9, 0xbe, + 0x6e, 0x90, 0x85, 0xfc, 0x77, 0xd6, 0x43, 0x32, 0xe8, 0x1e, 0x84, 0x42, 0xf4, 0xe6, 0xc1, 0x0c, 0xff, 0x63, 0x1b, + 0x9e, 0x7d, 0xc7, 0x8d, 0x3a, 0x01, 0xcc, 0x11, 0xd7, 0x4b, 0x4f, 0xd1, 0xd6, 0xc3, 0x2d, 0x90, 0xad, 0xf1, 0xf2, + 0xd6, 0x5e, 0x03, 0x39, 0xc5, 0xf1, 0xdf, 0xf1, 0x4c, 0xad, 0x6c, 0xf0, 0xd3, 0x53, 0xb6, 0x03, 0x0f, 0x2f, 0x42, + 0x40, 0x31, 0x2c, 0x1b, 0x7f, 0x67, 0x39, 0xce, 0xe8, 0xbf, 0x79, 0xc4, 0x30, 0x58, 0x44, 0x7e, 0x7c, 0x59, 0x0a, + 0xf1, 0x55, 0x78, 0x6f, 0x2b, 0xef, 0x8e, 0x9c, 0x32, 0xef, 0xf4, 0x30, 0xba, 0x2e, 0x49, 0xdf, 0x25, 0x1f, 0x5b, + 0xc3, 0xf6, 0xbb, 0x76, 0xbf, 0x19, 0x22, 0x08, 0xa1, 0x1c, 0x3f, 0x67, 0x74, 0x42, 0xe3, 0xc3, 0x6a, 0x76, 0x7a, + 0xfd, 0xde, 0x39, 0x5e, 0xb0, 0x35, 0x1a, 0xe0, 0xf1, 0xd0, 0xc5, 0x3c, 0x51, 0x43, 0xa7, 0xeb, 0xda, 0x39, 0x78, + 0x60, 0x90, 0xe5, 0xc9, 0x77, 0x0c, 0x4b, 0xec, 0x4f, 0x22, 0x9e, 0xb4, 0x55, 0x1b, 0x9b, 0x23, 0xd5, 0x46, 0xcd, + 0xc0, 0x0f, 0x5e, 0x41, 0x81, 0xd1, 0x05, 0x69, 0x05, 0xc6, 0xe1, 0x08, 0x40, 0x56, 0x8c, 0xe3, 0x91, 0xc1, 0x04, + 0x86, 0x74, 0x43, 0x51, 0x00, 0x1e, 0x1e, 0xc7, 0x83, 0x90, 0x01, 0xa4, 0x0b, 0x1e, 0x1a, 0xb6, 0x49, 0x48, 0xf9, + 0x79, 0x9e, 0xd7, 0x6a, 0x08, 0x7d, 0x67, 0xa1, 0x3a, 0xf6, 0x23, 0xed, 0x15, 0xeb, 0x5a, 0x95, 0x8e, 0x6c, 0x75, + 0x80, 0xbe, 0x21, 0x03, 0xdf, 0x3a, 0xb6, 0x00, 0x88, 0x96, 0xf8, 0x2d, 0xf5, 0x6a, 0x5f, 0xc6, 0xac, 0x50, 0xaf, + 0x2f, 0x4c, 0xbb, 0x5e, 0x4b, 0x8b, 0x02, 0x2a, 0x6e, 0x5b, 0xb5, 0x3d, 0x92, 0xf3, 0x1f, 0xdf, 0x75, 0xb4, 0xe3, + 0xb3, 0x53, 0x63, 0x4b, 0x28, 0x73, 0x8b, 0x27, 0xb2, 0x3a, 0xda, 0x52, 0x9d, 0xea, 0x03, 0x2e, 0x35, 0xa9, 0xce, + 0x0c, 0x0c, 0xaf, 0x11, 0xa0, 0xdc, 0x42, 0x24, 0x8d, 0xc3, 0xde, 0xf9, 0x64, 0x50, 0x30, 0xb7, 0x48, 0x40, 0x02, + 0xdb, 0xd8, 0xda, 0x45, 0x73, 0xfd, 0xfa, 0x2d, 0xf5, 0xaa, 0x36, 0x55, 0x3d, 0x78, 0xe3, 0x05, 0xce, 0xde, 0x69, + 0x2d, 0x20, 0x80, 0xc2, 0xd6, 0xb2, 0x1c, 0x9c, 0xbb, 0x5d, 0xd5, 0x52, 0x51, 0x46, 0xfd, 0xfe, 0xf9, 0x6f, 0x29, + 0x2a, 0x62, 0x4f, 0x15, 0xa7, 0xac, 0xdf, 0x6e, 0x99, 0x8b, 0xca, 0x92, 0x37, 0xa8, 0xa2, 0xb5, 0x3a, 0x6a, 0x2a, + 0xd7, 0xcd, 0x55, 0x4b, 0x26, 0x88, 0xd1, 0x7d, 0xba, 0xd6, 0xb9, 0x53, 0xef, 0xbd, 0x8a, 0x23, 0x06, 0x82, 0x9b, + 0xee, 0xf1, 0xc1, 0x41, 0x68, 0x54, 0x94, 0x0b, 0x6e, 0x94, 0x56, 0x95, 0x94, 0x42, 0xde, 0xaa, 0x68, 0xce, 0xf4, + 0x11, 0x00, 0x11, 0x60, 0x95, 0xa8, 0xff, 0xcd, 0x97, 0xc6, 0x78, 0xf0, 0xc0, 0xd7, 0xe4, 0x3a, 0xb6, 0xde, 0x3f, + 0xad, 0x91, 0x56, 0x1b, 0xc7, 0xa4, 0x56, 0xbd, 0x6c, 0x15, 0x2f, 0xbb, 0xd7, 0xa9, 0x18, 0x3c, 0xff, 0x9f, 0xfb, + 0x00, 0x35, 0xa2, 0xa5, 0x0c, 0x6e, 0x5d, 0x0d, 0xd0, 0xf8, 0x70, 0x2c, 0x7c, 0xe3, 0x87, 0x8c, 0xf3, 0xc1, 0x0c, + 0x1d, 0xd5, 0xe6, 0xe0, 0x80, 0xe0, 0xa8, 0xee, 0xd1, 0x98, 0x30, 0x0b, 0xe7, 0x1e, 0x04, 0xaa, 0x4f, 0xdc, 0x67, + 0x5c, 0x7b, 0x41, 0x9b, 0xc0, 0x27, 0xeb, 0xba, 0xa6, 0x08, 0x70, 0x11, 0x1b, 0x13, 0x31, 0xc4, 0x65, 0x93, 0x48, + 0x7d, 0x33, 0x06, 0x05, 0x40, 0x71, 0x5d, 0x91, 0x5c, 0xba, 0x48, 0xf3, 0x4a, 0x94, 0xb5, 0x6e, 0x46, 0xc5, 0x8a, + 0x21, 0x00, 0x3c, 0x04, 0xc5, 0x55, 0x65, 0x26, 0x34, 0x62, 0x03, 0xa9, 0x2c, 0x05, 0xab, 0x86, 0x85, 0xdf, 0xb4, + 0xdf, 0x24, 0x27, 0xbd, 0xf3, 0x71, 0xeb, 0xdc, 0xb1, 0xef, 0x1d, 0x85, 0x94, 0xf6, 0x50, 0x4c, 0x10, 0x04, 0x3f, + 0xad, 0xc3, 0xf9, 0x33, 0x7e, 0x4d, 0x60, 0x2a, 0xb2, 0x19, 0x03, 0x0e, 0x42, 0x44, 0x66, 0xfc, 0x9e, 0xc3, 0x6b, + 0x5e, 0x4e, 0xc2, 0xe1, 0xd0, 0x07, 0x7d, 0x28, 0xcf, 0x66, 0xe1, 0x50, 0xcc, 0xa5, 0xf7, 0x3a, 0x58, 0xeb, 0x42, + 0x5e, 0x4f, 0x42, 0x44, 0x0b, 0x0d, 0x7d, 0x70, 0x5e, 0x77, 0xcd, 0x11, 0x96, 0x00, 0x34, 0x71, 0xf4, 0x65, 0xfd, + 0x7e, 0xe4, 0x69, 0x43, 0x8b, 0x14, 0x17, 0x8d, 0x32, 0x9b, 0xe5, 0xb2, 0x13, 0x36, 0xae, 0xdd, 0x02, 0xa1, 0x78, + 0x98, 0xb6, 0x50, 0xb5, 0x9e, 0xea, 0xf5, 0xdc, 0xb4, 0xfb, 0xee, 0x51, 0xb5, 0xca, 0x91, 0xce, 0xda, 0x74, 0xa5, + 0x56, 0xb7, 0x8c, 0xaa, 0x75, 0x96, 0x46, 0x54, 0xb9, 0x49, 0xee, 0x1a, 0xb5, 0xe0, 0x93, 0x0d, 0x5d, 0xa6, 0xec, + 0x6c, 0x0d, 0x4e, 0x1c, 0x79, 0x2e, 0xb9, 0xe5, 0xbb, 0xf3, 0x8a, 0xee, 0x4e, 0xb5, 0x6f, 0x01, 0xee, 0xcd, 0xb0, + 0x21, 0x73, 0x5e, 0x63, 0xa7, 0x41, 0x98, 0x04, 0x7e, 0xc4, 0x3e, 0x66, 0xc8, 0x06, 0x03, 0x3a, 0x0a, 0xe9, 0x7f, + 0x6d, 0x99, 0x23, 0x01, 0x93, 0xbf, 0x9e, 0xfb, 0xcd, 0xa2, 0xc8, 0x61, 0x31, 0x7e, 0xdc, 0x60, 0xa4, 0xb1, 0x5a, + 0x83, 0x61, 0x79, 0x87, 0xc8, 0x9f, 0xda, 0x1d, 0xd3, 0x54, 0xc7, 0x9b, 0xf5, 0x5a, 0xf3, 0xab, 0xa7, 0x4f, 0x75, + 0x7d, 0xfe, 0xdb, 0xf7, 0x97, 0x61, 0xcd, 0xec, 0x0f, 0x41, 0x28, 0xed, 0xde, 0x2d, 0xce, 0x1d, 0x89, 0xde, 0xb1, + 0xd2, 0xcc, 0x2e, 0xed, 0x92, 0x5d, 0x9a, 0xd2, 0x6e, 0xc8, 0xf5, 0xea, 0x1b, 0xe5, 0x8d, 0x9d, 0x57, 0x4c, 0xf7, + 0xef, 0x85, 0xde, 0x51, 0x4e, 0xd5, 0x04, 0x22, 0x9a, 0xb4, 0x23, 0x71, 0xbb, 0x57, 0x86, 0xcf, 0x27, 0x79, 0xbb, + 0x84, 0xa3, 0xae, 0x61, 0xb9, 0xf9, 0xf6, 0x3f, 0xf2, 0xaa, 0xb3, 0xc2, 0xed, 0x97, 0xc6, 0xac, 0xfd, 0x29, 0x88, + 0xab, 0xfa, 0xc3, 0x7b, 0x52, 0x33, 0x25, 0xff, 0x57, 0x3d, 0x06, 0xae, 0x7e, 0x32, 0xed, 0xe8, 0x9e, 0x42, 0xd8, + 0x60, 0xf6, 0xf3, 0xe3, 0x87, 0x16, 0xac, 0xaa, 0x0b, 0x14, 0xc9, 0x01, 0x74, 0xee, 0x92, 0x11, 0xde, 0xef, 0x18, + 0xe7, 0xfe, 0xd5, 0x4b, 0x35, 0x39, 0x42, 0x44, 0xbb, 0x08, 0x07, 0x00, 0x71, 0xa7, 0xa9, 0xac, 0x43, 0x0d, 0xd0, + 0x07, 0x04, 0xd6, 0xa1, 0x6f, 0x33, 0x80, 0x83, 0x3e, 0xda, 0x3c, 0x8b, 0x40, 0x5e, 0xf7, 0xee, 0xd9, 0x3b, 0xb6, + 0xf3, 0xf9, 0xf5, 0x2a, 0xf5, 0xee, 0xd1, 0x21, 0xf8, 0x7c, 0xec, 0x4f, 0x2f, 0x03, 0x83, 0x0b, 0xcd, 0xde, 0x3d, + 0x13, 0x6c, 0xc7, 0x76, 0xcf, 0x10, 0xa9, 0xa8, 0x3b, 0xff, 0xf0, 0xd2, 0x44, 0xcf, 0x3b, 0x2f, 0xdc, 0xf1, 0x25, + 0x80, 0x07, 0xb2, 0x18, 0x50, 0x7c, 0x96, 0xde, 0x3f, 0x59, 0x02, 0x6a, 0xf2, 0x5b, 0xbe, 0xf6, 0xbe, 0x52, 0xea, + 0x02, 0xfe, 0x1c, 0x50, 0xfa, 0x24, 0xe7, 0xde, 0xdd, 0xf0, 0xd6, 0xbf, 0x78, 0x0e, 0xce, 0x13, 0xab, 0xe1, 0x02, + 0xfe, 0x2a, 0xf8, 0xd0, 0xbb, 0x1b, 0x60, 0x62, 0xc9, 0x87, 0xde, 0x6a, 0x00, 0xa9, 0x0a, 0x17, 0x12, 0x63, 0x1f, + 0x7e, 0x0d, 0x72, 0x86, 0x7f, 0xfc, 0xa6, 0x31, 0x58, 0x7f, 0x0d, 0x0a, 0x8d, 0xc6, 0x5a, 0xaa, 0x90, 0xa5, 0x58, + 0x9c, 0x09, 0xb0, 0x09, 0xc7, 0xdd, 0xbe, 0x58, 0xd5, 0x66, 0x2d, 0xe8, 0xcf, 0x47, 0x7c, 0x8f, 0xc6, 0xea, 0xaa, + 0x9c, 0x8b, 0xf2, 0x13, 0xd2, 0xa7, 0x3a, 0x3e, 0x46, 0xc5, 0xa6, 0xee, 0x4e, 0xa7, 0x5a, 0x75, 0xa4, 0xfd, 0xa6, + 0x5c, 0x83, 0x1d, 0xaf, 0x93, 0x23, 0x4b, 0xe1, 0x59, 0x87, 0x9d, 0x97, 0x4e, 0x89, 0x0e, 0xc3, 0x78, 0xb7, 0x55, + 0xcf, 0x18, 0xca, 0x73, 0x83, 0x31, 0x5d, 0xf0, 0x88, 0x5f, 0x0f, 0x72, 0x19, 0x1a, 0xf3, 0x11, 0xd9, 0x30, 0x94, + 0x0f, 0x2d, 0x32, 0x24, 0x44, 0xbc, 0x87, 0x4a, 0xc0, 0xb6, 0x05, 0x65, 0x52, 0xc0, 0x59, 0x34, 0xf8, 0xad, 0xf6, + 0x72, 0xe0, 0x3d, 0x88, 0xfc, 0x46, 0xba, 0x94, 0x4b, 0x6c, 0x74, 0xe2, 0x58, 0x16, 0xda, 0x79, 0x5c, 0x7f, 0x1d, + 0x83, 0xfa, 0xbd, 0xd2, 0x6f, 0x50, 0xce, 0xfe, 0x24, 0x59, 0xa7, 0x8d, 0x27, 0xc6, 0xbf, 0x5c, 0xe5, 0x9f, 0xa2, + 0xa5, 0x1e, 0xfe, 0x3f, 0x63, 0x0a, 0xa5, 0x7f, 0x95, 0x96, 0xd1, 0x66, 0xb5, 0x14, 0xa5, 0xc8, 0x23, 0x71, 0xf2, + 0xb5, 0xc8, 0xce, 0xe5, 0x3b, 0x9f, 0x42, 0xbf, 0x00, 0xb4, 0xec, 0x13, 0x64, 0xf4, 0x4b, 0x26, 0xf8, 0xf0, 0xa5, + 0x76, 0xae, 0xcd, 0xf9, 0x78, 0x92, 0x5f, 0x59, 0x7b, 0xb7, 0xe3, 0x45, 0x62, 0x14, 0x63, 0xb9, 0xaf, 0xba, 0x59, + 0x39, 0x51, 0xc9, 0x81, 0x91, 0xae, 0xc9, 0x5e, 0xae, 0x64, 0xdd, 0x4e, 0xb7, 0x12, 0x88, 0xa8, 0x02, 0xef, 0x31, + 0xae, 0x62, 0x1f, 0xc1, 0x74, 0xdd, 0x71, 0x19, 0xed, 0x78, 0xcf, 0x78, 0x75, 0xa2, 0xac, 0xe0, 0x76, 0x23, 0xda, + 0x13, 0x3a, 0xfa, 0x69, 0x52, 0x5b, 0x16, 0x0e, 0x40, 0xee, 0x12, 0xc6, 0xb2, 0x21, 0x58, 0x31, 0x28, 0x7d, 0xbd, + 0xa6, 0x64, 0x59, 0x80, 0x45, 0x67, 0x97, 0x11, 0x88, 0x61, 0xdd, 0x34, 0x27, 0x74, 0xbc, 0x74, 0x71, 0xde, 0x6b, + 0x15, 0x29, 0x78, 0x46, 0x8b, 0x8e, 0xb9, 0xe9, 0x48, 0x37, 0x46, 0x7b, 0xfb, 0xd2, 0x20, 0xa4, 0x78, 0xfe, 0xc0, + 0x56, 0xeb, 0xe2, 0x22, 0xf1, 0x0a, 0x99, 0x68, 0x41, 0x2c, 0x45, 0x60, 0xc6, 0x0b, 0x4d, 0x23, 0x4c, 0x50, 0xa6, + 0x04, 0x8b, 0xd6, 0xe8, 0xd0, 0xfe, 0xb0, 0x84, 0xdd, 0x63, 0x8c, 0x00, 0x81, 0x2a, 0xd3, 0x97, 0xb0, 0x35, 0x61, + 0x36, 0x75, 0xb1, 0x01, 0xda, 0x2a, 0x86, 0x06, 0x61, 0x6d, 0x88, 0xf9, 0x94, 0xe6, 0x77, 0xff, 0xc4, 0x62, 0x6c, + 0x4f, 0x20, 0xb6, 0x77, 0xbb, 0x26, 0x61, 0xba, 0xd7, 0xe2, 0xc6, 0x7a, 0xb9, 0x3d, 0xe5, 0x98, 0xda, 0xb1, 0x36, + 0x6a, 0xc7, 0x5a, 0xea, 0x1d, 0x6b, 0xad, 0x77, 0xac, 0xbb, 0x86, 0x7f, 0xcc, 0xbc, 0x98, 0x25, 0xa0, 0xdf, 0x5d, + 0x71, 0xd5, 0x20, 0x68, 0xc6, 0x86, 0xdd, 0xc2, 0x6f, 0x89, 0xb5, 0x5b, 0xfa, 0x17, 0x4b, 0xb6, 0x30, 0x7d, 0xa0, + 0x5b, 0x07, 0x58, 0x46, 0xd4, 0xe4, 0x7b, 0xe4, 0xdd, 0x74, 0x56, 0x14, 0x6e, 0x4f, 0x6c, 0xe1, 0xb3, 0x77, 0xe6, + 0xcd, 0xfb, 0x67, 0x11, 0xe4, 0xde, 0x71, 0xef, 0x7e, 0xf8, 0xce, 0xbf, 0xd0, 0x2d, 0x90, 0x93, 0x59, 0xce, 0x40, + 0xea, 0x88, 0xcf, 0x10, 0xad, 0xec, 0x29, 0xdf, 0x09, 0xb9, 0xb3, 0xad, 0x9f, 0xdd, 0xbb, 0xdb, 0xda, 0xdd, 0xb3, + 0x7b, 0x56, 0x8d, 0x28, 0x56, 0x9c, 0xa6, 0x48, 0x98, 0x45, 0x1b, 0xe0, 0xa9, 0x97, 0xef, 0x77, 0xec, 0x98, 0xc3, + 0xdd, 0xb3, 0x8e, 0x8e, 0x97, 0x73, 0xc0, 0xee, 0xfe, 0xa3, 0x4d, 0xd8, 0x58, 0xe9, 0x5a, 0x85, 0x0e, 0x77, 0xcf, + 0x32, 0x8d, 0xe7, 0x70, 0x24, 0x9f, 0x8e, 0x35, 0x36, 0x08, 0xea, 0xfa, 0x9c, 0x41, 0xed, 0xd8, 0x7d, 0x4d, 0xd8, + 0x65, 0xc7, 0xbc, 0xd6, 0x35, 0x6f, 0xaf, 0x3c, 0x15, 0x1b, 0x02, 0x3a, 0x7c, 0xad, 0x6e, 0x90, 0x7f, 0x09, 0x9c, + 0x22, 0x00, 0xe4, 0x70, 0xbc, 0xe4, 0xb1, 0xef, 0xd3, 0x2c, 0xad, 0x77, 0xa8, 0xb5, 0xa8, 0x2c, 0xcb, 0xb0, 0xf6, + 0x7e, 0xd0, 0x8a, 0x61, 0xa9, 0xe9, 0x9f, 0x8e, 0x03, 0xb7, 0xb3, 0xdd, 0xca, 0xd8, 0x65, 0x3c, 0x2b, 0x2e, 0x5e, + 0x9e, 0x16, 0xca, 0xb5, 0x9b, 0xb7, 0xf1, 0x9b, 0x56, 0x4b, 0x96, 0xd6, 0x7a, 0xc8, 0x4b, 0xcb, 0x22, 0x02, 0x01, + 0x0c, 0x47, 0xca, 0x2e, 0x96, 0x70, 0x8f, 0xb0, 0xba, 0x07, 0xa1, 0x64, 0x5e, 0xb8, 0x78, 0xce, 0x62, 0x48, 0x04, + 0xd8, 0xee, 0x50, 0xb1, 0x2d, 0x5c, 0x3c, 0x67, 0x1b, 0x5e, 0xf4, 0xfb, 0x99, 0xea, 0x14, 0xb2, 0xee, 0x2c, 0xf9, + 0x46, 0x35, 0xc7, 0x1a, 0x6a, 0xb6, 0x36, 0xc9, 0xd6, 0x38, 0xb7, 0x15, 0x1f, 0x77, 0x6d, 0xc5, 0xc7, 0xca, 0x5a, + 0x97, 0xee, 0xf5, 0x1e, 0xd5, 0x05, 0xb0, 0xf5, 0xdf, 0x1e, 0xaf, 0x5c, 0xcf, 0x67, 0x04, 0xf0, 0xb5, 0xe0, 0xe3, + 0xc9, 0x02, 0xbd, 0x4a, 0x16, 0xfe, 0xed, 0x40, 0x8d, 0xbf, 0xd3, 0xb9, 0x0b, 0x80, 0xae, 0xa4, 0xbc, 0x02, 0xf2, + 0x0e, 0x72, 0xcc, 0x2d, 0xbb, 0xf2, 0xfe, 0xe4, 0x3b, 0xec, 0x1d, 0xaf, 0x67, 0x8b, 0x39, 0xdb, 0x81, 0x53, 0x41, + 0x32, 0xb0, 0x97, 0x15, 0xdb, 0x05, 0xb1, 0x9d, 0xf0, 0x1b, 0x01, 0x53, 0xbe, 0x80, 0x20, 0xae, 0xe0, 0x16, 0xe2, + 0xf0, 0xe4, 0x9f, 0x83, 0xfb, 0xd6, 0x66, 0x7d, 0xcf, 0xac, 0xce, 0x09, 0xd6, 0xcc, 0xea, 0xc1, 0x60, 0xd9, 0x4c, + 0x56, 0xfd, 0xbe, 0xb7, 0xd3, 0x8e, 0x4f, 0x77, 0x52, 0x27, 0x76, 0x5a, 0xab, 0xb5, 0x60, 0xef, 0xa4, 0xd6, 0xc5, + 0x18, 0x7a, 0x80, 0xf8, 0xe9, 0x76, 0xc0, 0xef, 0x3b, 0xd6, 0x96, 0xf7, 0x8e, 0x2d, 0xd8, 0x0e, 0x2e, 0x41, 0x4d, + 0x7b, 0xd9, 0x9f, 0x54, 0x2e, 0x68, 0xc7, 0x2e, 0x89, 0x87, 0x33, 0x66, 0x95, 0x32, 0xb3, 0x4e, 0xaa, 0x2b, 0xd1, + 0x19, 0xd3, 0x59, 0xeb, 0xf9, 0x5c, 0xcd, 0x27, 0x85, 0x06, 0xf5, 0x3b, 0x27, 0x3e, 0xa2, 0xa2, 0xf3, 0x04, 0xb6, + 0x96, 0x15, 0xc4, 0x6a, 0x9f, 0x83, 0xb5, 0x56, 0xbb, 0xf4, 0x7b, 0xf9, 0x80, 0xdb, 0x94, 0xc3, 0x3a, 0x30, 0xa8, + 0x39, 0xb1, 0xa2, 0x1e, 0xb3, 0x1d, 0xe3, 0xe6, 0xa7, 0x97, 0x3f, 0x38, 0x61, 0xc9, 0x8a, 0xd5, 0xfe, 0xf4, 0xe5, + 0x33, 0x4f, 0x7f, 0xa7, 0xf6, 0x2f, 0x84, 0x1f, 0x8c, 0xff, 0x5d, 0xbb, 0xaf, 0xb5, 0x18, 0x95, 0xad, 0x72, 0x84, + 0xc6, 0xdd, 0x4a, 0x9a, 0x2c, 0x3f, 0x0b, 0x4f, 0x58, 0x0b, 0x9e, 0xe5, 0x7a, 0x89, 0x66, 0x05, 0xac, 0xb0, 0x96, + 0x49, 0xb8, 0xc2, 0x58, 0x2d, 0x6d, 0xf5, 0x2d, 0x9a, 0xe6, 0xf8, 0x70, 0xae, 0x0d, 0xca, 0x94, 0xb3, 0x33, 0x62, + 0x35, 0x5c, 0x86, 0xa5, 0x09, 0x45, 0xc8, 0xee, 0xed, 0xe0, 0xc6, 0x4e, 0x59, 0x4a, 0x19, 0xce, 0x31, 0x98, 0xf0, + 0x48, 0x8c, 0xaa, 0x7c, 0x7f, 0x5f, 0x52, 0xe4, 0xb4, 0x2d, 0x07, 0x55, 0x08, 0xfb, 0x48, 0xa2, 0x04, 0x6e, 0x45, + 0x5a, 0x28, 0x52, 0x16, 0x7f, 0x3b, 0x40, 0x17, 0x78, 0x01, 0x75, 0x35, 0xea, 0xf6, 0x87, 0x23, 0x1e, 0x3e, 0x32, + 0xf5, 0x81, 0x11, 0x4b, 0x02, 0xb5, 0xbd, 0xc8, 0xd2, 0x3b, 0x50, 0xe1, 0xf7, 0x70, 0x35, 0x11, 0xfb, 0xb9, 0x25, + 0x45, 0x45, 0x36, 0xd2, 0x1b, 0x5a, 0x83, 0x47, 0x68, 0x4d, 0x79, 0xe9, 0xa4, 0xda, 0xa4, 0xf3, 0x8e, 0x90, 0x63, + 0xf5, 0xad, 0x25, 0x8c, 0x76, 0x45, 0x2f, 0xee, 0x1d, 0xbd, 0xe7, 0xe9, 0xaa, 0xe7, 0xfe, 0xc4, 0x15, 0xf3, 0xe4, + 0x36, 0x02, 0x75, 0x2b, 0xa8, 0x6e, 0x1f, 0x54, 0x82, 0x05, 0x4b, 0xda, 0x7d, 0xfc, 0x76, 0xd6, 0x0e, 0x44, 0x65, + 0xac, 0xd2, 0xb7, 0x24, 0x61, 0x4f, 0x0c, 0x3a, 0x85, 0xaa, 0xdc, 0xee, 0x8e, 0xb6, 0xc0, 0x75, 0xcc, 0x52, 0xf4, + 0xc2, 0x16, 0xb9, 0x5b, 0xfe, 0xdd, 0x73, 0x45, 0xce, 0x7e, 0x09, 0x08, 0x4e, 0xcd, 0x37, 0xc4, 0x97, 0x23, 0x3c, + 0xaa, 0x6e, 0x81, 0xe3, 0xf4, 0x1d, 0xc0, 0x3f, 0x1c, 0x2e, 0x41, 0x13, 0x10, 0x0b, 0xd6, 0x4b, 0xe3, 0x1e, 0xeb, + 0xc5, 0xc5, 0xe6, 0x2e, 0xc9, 0x37, 0xe0, 0xcc, 0x40, 0xa9, 0x96, 0x7e, 0xe0, 0x58, 0x2d, 0xa0, 0xc2, 0xc1, 0xec, + 0xa4, 0x5e, 0x58, 0x46, 0x3d, 0xa6, 0xcf, 0xcf, 0x60, 0xef, 0x08, 0x09, 0x80, 0xfb, 0x65, 0x1f, 0x90, 0x80, 0x87, + 0xce, 0xec, 0x80, 0x70, 0xc2, 0x2c, 0xaa, 0x02, 0x89, 0xe4, 0x48, 0x3f, 0x7b, 0xcc, 0x44, 0xf2, 0x07, 0xb3, 0x9e, + 0x73, 0x4a, 0xf4, 0x58, 0x4f, 0x1d, 0x21, 0x3d, 0xd6, 0xb3, 0x8e, 0x88, 0x1e, 0xeb, 0x59, 0xc7, 0x47, 0x8f, 0xf5, + 0xcc, 0xb1, 0xd3, 0x83, 0xc0, 0x04, 0x88, 0x3c, 0x60, 0x3d, 0x9a, 0x4c, 0x3d, 0xc5, 0x3d, 0x40, 0x34, 0x08, 0xac, + 0x27, 0x85, 0xf3, 0x1e, 0x20, 0x8f, 0x91, 0x58, 0x1d, 0xf4, 0xfe, 0x63, 0xfc, 0xb4, 0x67, 0x64, 0xe4, 0x71, 0xeb, + 0xb0, 0xfa, 0x5f, 0xff, 0x09, 0x01, 0x70, 0x78, 0x36, 0xf5, 0x2e, 0xc7, 0x90, 0x55, 0x96, 0x11, 0x48, 0x7e, 0x62, + 0xf0, 0xe5, 0x0b, 0x80, 0xaa, 0xcf, 0x74, 0xad, 0x26, 0x47, 0xed, 0x31, 0x87, 0xae, 0x18, 0x00, 0xb6, 0x61, 0x89, + 0xaa, 0x5a, 0xd8, 0x84, 0xc5, 0xed, 0x67, 0x18, 0xcd, 0x65, 0xd3, 0x0b, 0x1a, 0xa8, 0x47, 0x08, 0x7e, 0x69, 0x3d, + 0xb4, 0xd6, 0x32, 0xe5, 0xd0, 0xb5, 0x51, 0x54, 0xd9, 0x50, 0x97, 0xb0, 0x5a, 0x8b, 0xa8, 0x26, 0x8a, 0x94, 0x4b, + 0x46, 0x51, 0x2c, 0x55, 0xb0, 0xcf, 0xc4, 0x1d, 0x44, 0xcd, 0xd3, 0x56, 0x5b, 0x05, 0xfb, 0x3b, 0x40, 0x58, 0x0b, + 0x6b, 0x21, 0x9d, 0x41, 0xed, 0x9d, 0x7e, 0xa4, 0xfc, 0xe5, 0x85, 0xdc, 0xce, 0x2d, 0x14, 0xe1, 0xf6, 0x1c, 0x94, + 0x37, 0x75, 0x55, 0x2a, 0xa2, 0xd1, 0x12, 0x28, 0x65, 0x4e, 0x10, 0x59, 0x80, 0x00, 0x8e, 0x1b, 0x08, 0x7c, 0x5e, + 0xe3, 0x13, 0x68, 0x14, 0x02, 0xf9, 0x81, 0x55, 0xb8, 0xf6, 0x90, 0x96, 0x5a, 0x23, 0xa2, 0x44, 0xfc, 0xe8, 0xea, + 0x39, 0xb6, 0xaf, 0x9e, 0xc6, 0xda, 0x52, 0x9a, 0x20, 0x7e, 0x62, 0xb1, 0x85, 0x98, 0x20, 0xaa, 0x43, 0x74, 0x04, + 0xcb, 0x09, 0x21, 0x0a, 0x7f, 0x08, 0xfd, 0xd4, 0xc0, 0x5f, 0xb2, 0x65, 0x91, 0xd7, 0x04, 0x8b, 0x59, 0x31, 0x40, + 0xab, 0x22, 0xf0, 0x4c, 0x67, 0x4b, 0x65, 0x4e, 0xf3, 0xe8, 0xc8, 0x0e, 0xce, 0xbb, 0x0e, 0xf6, 0xd2, 0x97, 0xb1, + 0x93, 0x65, 0xd3, 0xa8, 0x8d, 0x0d, 0x91, 0xf0, 0x8a, 0xfc, 0x55, 0x96, 0x1a, 0xe7, 0xc8, 0x5c, 0xae, 0xef, 0xba, + 0xb8, 0xbb, 0xa3, 0x6d, 0xc2, 0x2a, 0x44, 0xa8, 0xdb, 0x86, 0xca, 0xa5, 0x30, 0x1b, 0x9b, 0xa6, 0x01, 0xbe, 0x50, + 0x54, 0x2a, 0x55, 0xa9, 0xad, 0x54, 0x72, 0xc2, 0xbb, 0xbe, 0xa9, 0x45, 0xea, 0x8a, 0x60, 0x1b, 0x33, 0xd4, 0x43, + 0xb9, 0x51, 0x63, 0xdf, 0x76, 0xac, 0xd2, 0x3b, 0x4c, 0x90, 0x33, 0xf2, 0x22, 0x07, 0x17, 0x25, 0x05, 0x99, 0xab, + 0x21, 0xcc, 0x1f, 0x35, 0x7c, 0x5a, 0x58, 0xee, 0xa1, 0x04, 0xcc, 0x8e, 0x1a, 0x5e, 0x46, 0x08, 0x44, 0x5c, 0x2a, + 0xfb, 0x8a, 0x89, 0xdf, 0x53, 0x30, 0x4b, 0x26, 0x74, 0x2f, 0x62, 0x61, 0x84, 0x36, 0x3e, 0x49, 0x92, 0xa9, 0xa7, + 0x29, 0xb8, 0x91, 0xcb, 0x30, 0x47, 0x23, 0xb4, 0xe4, 0x23, 0x07, 0xd2, 0xd7, 0x72, 0x2a, 0xc1, 0x47, 0xd4, 0x29, + 0xe0, 0x78, 0x7e, 0x5e, 0x58, 0x3f, 0x59, 0x2e, 0x31, 0x97, 0xb5, 0xf9, 0x2f, 0x3b, 0x3a, 0x06, 0xbb, 0x3c, 0x4d, + 0x1c, 0x57, 0xff, 0x51, 0x95, 0x14, 0x0f, 0x3f, 0xa7, 0x39, 0xa0, 0x08, 0x66, 0xf6, 0x14, 0xe3, 0x63, 0x9f, 0x65, + 0x0a, 0xf8, 0xdb, 0xf5, 0xd6, 0x92, 0x89, 0x5d, 0xd2, 0x6e, 0xae, 0x8c, 0x5f, 0x6a, 0xc3, 0x8e, 0x83, 0x73, 0x03, + 0x50, 0x9c, 0x35, 0x3a, 0x2c, 0xaf, 0x75, 0xdb, 0xaa, 0x50, 0x81, 0x5a, 0xff, 0x7b, 0xb7, 0x30, 0xe5, 0x6d, 0x5e, + 0x2a, 0x6f, 0xf3, 0xd0, 0x04, 0x08, 0x44, 0x66, 0xc8, 0xb3, 0xa6, 0x63, 0x92, 0xb8, 0x77, 0xa4, 0xa4, 0x7d, 0x47, + 0x8a, 0x1f, 0xbd, 0x23, 0x21, 0xdf, 0x12, 0x3a, 0xb2, 0x2f, 0x39, 0x39, 0x81, 0x32, 0x83, 0xbd, 0xbc, 0x66, 0xb2, + 0x7f, 0x40, 0x7b, 0xe1, 0x5c, 0x96, 0x57, 0xfc, 0x9d, 0xf0, 0xd6, 0xfe, 0x74, 0x7d, 0xda, 0x55, 0xf5, 0xf6, 0x1b, + 0x33, 0xf3, 0x70, 0x28, 0x0e, 0x87, 0xca, 0x04, 0xed, 0x2e, 0xb8, 0x18, 0xe4, 0xec, 0xde, 0x8d, 0x8f, 0x7f, 0xc7, + 0x51, 0xc4, 0x56, 0xca, 0x23, 0xe9, 0x42, 0x25, 0x86, 0x97, 0x06, 0x1e, 0x66, 0xc7, 0xc7, 0x93, 0xdd, 0xd5, 0xfd, + 0x64, 0x30, 0xd8, 0xa9, 0xbe, 0xdd, 0xf2, 0x7a, 0xb6, 0x9b, 0xb3, 0x07, 0x7e, 0x3b, 0xdd, 0x06, 0xfb, 0x06, 0xb6, + 0xdd, 0xdd, 0x95, 0x38, 0x1c, 0x76, 0xd7, 0x7c, 0xe1, 0xef, 0x1f, 0x10, 0xd0, 0x99, 0x9f, 0x8f, 0xdb, 0x18, 0x3f, + 0x37, 0x6d, 0x57, 0xad, 0x1d, 0xc0, 0xd3, 0xff, 0xe8, 0xdd, 0xcc, 0x96, 0x73, 0x9f, 0x3d, 0xe1, 0x0f, 0xe0, 0x9f, + 0x8f, 0x9b, 0x24, 0x52, 0x9f, 0x68, 0x97, 0xc9, 0x1b, 0x70, 0x20, 0xdf, 0xf9, 0xec, 0x2d, 0x7f, 0x98, 0x2d, 0xe7, + 0xbc, 0x38, 0x1c, 0x3e, 0x4c, 0x43, 0x24, 0x6b, 0x0a, 0x2b, 0x62, 0x49, 0xf1, 0xfc, 0x20, 0x3c, 0x7e, 0x2f, 0x22, + 0x43, 0xa4, 0xe5, 0xde, 0x1d, 0xb2, 0x1b, 0x16, 0xf9, 0x01, 0x7c, 0x90, 0xed, 0xfc, 0x89, 0xac, 0x29, 0xdd, 0x2f, + 0x9e, 0xf8, 0x87, 0x03, 0xfd, 0xf5, 0xd6, 0x3f, 0x1c, 0x3e, 0xb0, 0x07, 0x04, 0x47, 0xe7, 0x3b, 0xe8, 0x1f, 0x7d, + 0xeb, 0x80, 0xaa, 0x0c, 0xdf, 0xcd, 0x36, 0x73, 0xff, 0x7a, 0xc5, 0xee, 0x80, 0x0b, 0x45, 0x79, 0xa1, 0xdd, 0xb0, + 0x07, 0xf4, 0x3a, 0x23, 0x27, 0xa2, 0xd9, 0x6e, 0xee, 0xb3, 0x18, 0x9f, 0xab, 0xfb, 0x62, 0xf2, 0xcd, 0xfb, 0xe2, + 0x8e, 0x6d, 0xbb, 0xef, 0x8b, 0xf2, 0x4d, 0x77, 0xfd, 0x6c, 0xd9, 0x8e, 0x3d, 0xc0, 0x0c, 0x7b, 0xc7, 0x6f, 0x9a, + 0x63, 0xc7, 0xd8, 0x6f, 0xde, 0x18, 0x01, 0x94, 0xd9, 0x82, 0xc5, 0x82, 0x83, 0x52, 0xad, 0xda, 0x96, 0x44, 0x5e, + 0xe9, 0x40, 0xb5, 0x19, 0xc1, 0x7d, 0xb5, 0x90, 0x33, 0xcf, 0x0c, 0xf4, 0x6d, 0x85, 0x68, 0xe1, 0xb0, 0x01, 0x7f, + 0xa3, 0xad, 0x63, 0x0c, 0xd3, 0xac, 0x66, 0xda, 0x16, 0x75, 0xf9, 0x7d, 0xef, 0x99, 0xfc, 0x46, 0x06, 0xb6, 0x10, + 0x49, 0xe1, 0x38, 0xbe, 0x78, 0x7e, 0xc2, 0x7f, 0xd5, 0xf2, 0xa8, 0xd5, 0x7e, 0xa1, 0xd4, 0xa7, 0xaf, 0xe8, 0x88, + 0x26, 0xee, 0x45, 0x5b, 0x86, 0x35, 0xca, 0x9a, 0x5a, 0x3a, 0x0c, 0xe3, 0x1a, 0xf6, 0xe5, 0x81, 0x43, 0xdf, 0x01, + 0x81, 0xb6, 0x4a, 0xa5, 0x40, 0x0b, 0xc7, 0x30, 0x0a, 0xb3, 0x90, 0xf2, 0xb8, 0x30, 0x4b, 0x79, 0x8f, 0x05, 0x5a, + 0xdc, 0xaa, 0x7b, 0x4c, 0x6d, 0xb7, 0x20, 0xc2, 0xea, 0x2d, 0xe3, 0xfc, 0xb2, 0x51, 0x85, 0xdb, 0x02, 0x14, 0x45, + 0x50, 0x06, 0x7b, 0x92, 0xdb, 0x16, 0x4a, 0x9a, 0x8d, 0xc2, 0x5a, 0xdc, 0x15, 0xe5, 0xae, 0xd7, 0xb0, 0x05, 0x5e, + 0x50, 0xf5, 0x13, 0xc2, 0xb6, 0xec, 0x59, 0x87, 0x72, 0x91, 0xfe, 0x5b, 0x96, 0x9e, 0xef, 0xb7, 0xe6, 0xfc, 0x4f, + 0x5f, 0xd1, 0x47, 0xe5, 0xbf, 0x7f, 0x49, 0x3f, 0x19, 0x2c, 0x23, 0xa7, 0xd4, 0xcb, 0x68, 0x74, 0x9b, 0xe6, 0x84, + 0xb1, 0xe5, 0xeb, 0xa7, 0xdf, 0x21, 0x53, 0x90, 0x1c, 0x4a, 0xa9, 0xca, 0xc9, 0x1e, 0xfa, 0xc2, 0xeb, 0x3e, 0xcc, + 0x04, 0x03, 0x10, 0x5e, 0xa3, 0x4d, 0x35, 0x61, 0x12, 0x8f, 0xae, 0xe0, 0xff, 0x46, 0x10, 0x83, 0xf6, 0x89, 0xa2, + 0x8e, 0x6d, 0x23, 0x5d, 0xb7, 0x9d, 0x83, 0xe4, 0x4e, 0x5d, 0xf9, 0xa3, 0x72, 0xf2, 0xef, 0x68, 0x88, 0xbc, 0xe2, + 0x0a, 0xb1, 0xb2, 0xe0, 0x12, 0x8b, 0xa1, 0x22, 0x05, 0xb8, 0x86, 0x20, 0x52, 0x16, 0x25, 0x85, 0x5b, 0x0e, 0xaa, + 0x22, 0x00, 0xe3, 0x6a, 0x75, 0xd4, 0x89, 0xf0, 0x71, 0x6b, 0x2d, 0x42, 0xb0, 0xa2, 0x51, 0x2b, 0x6b, 0x05, 0xbe, + 0x20, 0x7d, 0xe9, 0x50, 0x10, 0xd3, 0xa3, 0x90, 0xaa, 0xd2, 0xa1, 0x40, 0x9a, 0x43, 0xc5, 0x37, 0x06, 0x1b, 0x45, + 0x45, 0x7a, 0xfe, 0xd2, 0xa4, 0xe4, 0xd2, 0x98, 0xf1, 0x51, 0x94, 0x91, 0xc8, 0xeb, 0xf0, 0x4e, 0x4c, 0x0b, 0xe4, + 0x1b, 0x3d, 0x7e, 0x10, 0x5c, 0xc2, 0xbb, 0x21, 0xf7, 0x0a, 0xb0, 0x25, 0x60, 0x07, 0xb8, 0x57, 0x66, 0x94, 0xeb, + 0xb4, 0xae, 0xdf, 0x5a, 0x0f, 0xc5, 0x30, 0x7c, 0x66, 0x09, 0x6c, 0x47, 0xeb, 0xe8, 0x48, 0x0f, 0x1f, 0xfe, 0xd7, + 0x55, 0xcd, 0x51, 0xa7, 0x72, 0x39, 0x3b, 0x9e, 0xb0, 0x14, 0x31, 0x83, 0xee, 0xaf, 0xdb, 0x57, 0x02, 0xe8, 0x76, + 0x59, 0xcc, 0xb3, 0xd1, 0x4e, 0xfe, 0x2d, 0xdd, 0x58, 0x51, 0xda, 0xc4, 0xbb, 0xac, 0x37, 0xf6, 0x87, 0xa3, 0xff, + 0x78, 0xf6, 0x75, 0x42, 0xa8, 0x3a, 0x1b, 0xb6, 0xd6, 0x71, 0x2e, 0xff, 0xeb, 0x3f, 0xc7, 0x64, 0x05, 0x41, 0x41, + 0x58, 0x76, 0x8a, 0x89, 0x0a, 0x46, 0x91, 0x62, 0xcd, 0xc7, 0x93, 0x35, 0xea, 0x84, 0xd7, 0xfe, 0x52, 0xeb, 0x84, + 0x89, 0x91, 0x95, 0xca, 0x5f, 0xb3, 0x8a, 0xdd, 0xa9, 0xcc, 0x02, 0x32, 0x0f, 0xf2, 0xc9, 0xda, 0x68, 0x30, 0x57, + 0xbc, 0x9e, 0xad, 0xe7, 0x52, 0xf9, 0x0c, 0xa6, 0x9c, 0xe5, 0xe0, 0x64, 0x29, 0xec, 0x9e, 0x04, 0x8a, 0xd6, 0x0c, + 0x5d, 0xfb, 0x53, 0x6c, 0xd5, 0xeb, 0xb4, 0xaa, 0x01, 0x1e, 0x10, 0x62, 0x60, 0xa8, 0xbd, 0x5a, 0x78, 0x68, 0x2d, + 0x80, 0xb5, 0x3f, 0x2a, 0xfd, 0x60, 0x3c, 0x59, 0xf2, 0x05, 0xf2, 0x2f, 0x47, 0x8e, 0xda, 0xbd, 0xdf, 0xf7, 0xee, + 0x41, 0x0a, 0x8e, 0x5c, 0x0b, 0x05, 0x12, 0x01, 0x2d, 0xf8, 0xc6, 0x57, 0x3e, 0x18, 0xef, 0x50, 0x5b, 0x0d, 0x0a, + 0x6a, 0x47, 0xb7, 0x3c, 0x76, 0xf4, 0xce, 0xf7, 0x27, 0xf4, 0xd5, 0x0b, 0x2d, 0x1c, 0x7f, 0xe3, 0x8c, 0x5c, 0xb3, + 0x55, 0x87, 0x1c, 0xd1, 0x4c, 0x3a, 0x84, 0x88, 0x15, 0x5b, 0xb3, 0x77, 0xa4, 0x72, 0xee, 0x1c, 0xb2, 0xd3, 0x47, + 0xa8, 0xd2, 0x6b, 0x3d, 0xbe, 0x9d, 0x28, 0xdd, 0xed, 0xf1, 0x6e, 0xf2, 0x3d, 0x9b, 0x88, 0x18, 0x0c, 0x68, 0x83, + 0x70, 0x46, 0xd6, 0x21, 0x52, 0xe9, 0x00, 0x21, 0x70, 0x4c, 0x40, 0xd3, 0x7f, 0x7d, 0x4b, 0xa2, 0x80, 0x23, 0x6d, + 0x84, 0xac, 0x65, 0x87, 0x43, 0x0e, 0x1a, 0xe5, 0xe6, 0x0f, 0xaf, 0x50, 0xa7, 0x39, 0x30, 0x4f, 0x97, 0xb0, 0xe7, + 0xe0, 0x91, 0x5e, 0x1c, 0x1f, 0xe9, 0xff, 0x1d, 0x4d, 0xd4, 0xf8, 0xdf, 0xd7, 0x44, 0x29, 0x2d, 0x92, 0xa3, 0x5a, + 0xfa, 0x2e, 0x75, 0x14, 0x5c, 0xe4, 0x1d, 0xb5, 0x90, 0x3d, 0xcb, 0xc6, 0x8d, 0x6a, 0xde, 0xff, 0xaf, 0x95, 0xf9, + 0xff, 0x9a, 0x56, 0x86, 0x29, 0xd9, 0xb1, 0x54, 0x33, 0x0f, 0xb4, 0x8a, 0x61, 0xf6, 0x33, 0x49, 0x88, 0x0c, 0x97, + 0x06, 0xfc, 0xa8, 0x82, 0x7d, 0x9c, 0x56, 0xeb, 0x2c, 0xdc, 0xa1, 0x12, 0xf5, 0x56, 0xdc, 0xa5, 0xf9, 0x8b, 0xfa, + 0x5f, 0xa2, 0x2c, 0x60, 0x6a, 0xdf, 0x95, 0x69, 0x1c, 0x90, 0x85, 0x3f, 0x0b, 0x4b, 0x9c, 0xdc, 0xd8, 0xc6, 0x9f, + 0xe5, 0x78, 0xda, 0xaf, 0x3a, 0x33, 0x0f, 0x24, 0x50, 0x03, 0xf1, 0x47, 0xce, 0x65, 0x65, 0xf1, 0x80, 0xd0, 0xcd, + 0x3f, 0x96, 0x65, 0x51, 0x7a, 0xbd, 0xcf, 0x49, 0x5a, 0x9d, 0xad, 0x44, 0x9d, 0x14, 0xb1, 0x82, 0xb2, 0x49, 0x01, + 0x46, 0x1f, 0x56, 0x9e, 0x88, 0x83, 0x33, 0x04, 0x6a, 0x38, 0xab, 0x93, 0x10, 0x80, 0x86, 0x15, 0xc2, 0xfe, 0x19, + 0xb4, 0xf0, 0x2c, 0x8c, 0xc3, 0x35, 0xc0, 0xe4, 0xa4, 0xd5, 0xd9, 0xba, 0x2c, 0xee, 0xd3, 0x58, 0xc4, 0xa3, 0x9e, + 0xa2, 0x64, 0x79, 0x93, 0xbb, 0x72, 0xae, 0xbf, 0xff, 0x83, 0x02, 0xd8, 0x0d, 0x98, 0x6d, 0x0b, 0xec, 0x00, 0x20, + 0x41, 0x81, 0x6c, 0xa1, 0x4e, 0xa3, 0x33, 0xb5, 0x54, 0xe0, 0x3d, 0xd7, 0x03, 0xfc, 0x4d, 0x0e, 0x58, 0xc6, 0x75, + 0x21, 0x03, 0x46, 0x10, 0xc0, 0x08, 0x1c, 0x94, 0x80, 0xa1, 0x33, 0xc4, 0x6d, 0x55, 0xce, 0x5a, 0x68, 0xae, 0x74, + 0x5b, 0x72, 0xd3, 0x28, 0x67, 0x2b, 0x11, 0x40, 0x5f, 0xdd, 0x94, 0x38, 0x5d, 0x2e, 0x5b, 0x49, 0xd8, 0xb7, 0x1f, + 0xda, 0xa9, 0x22, 0x8f, 0x8f, 0xd2, 0x90, 0x57, 0xe0, 0x49, 0xc6, 0x91, 0x24, 0x4a, 0x04, 0x6f, 0xf2, 0xc6, 0x8c, + 0xc3, 0x8b, 0x36, 0xe5, 0xd4, 0xde, 0xac, 0x17, 0x80, 0xf3, 0x04, 0x6d, 0x19, 0x60, 0x2c, 0x60, 0x70, 0x2e, 0xc4, + 0x92, 0xa7, 0x08, 0x7e, 0xe9, 0x44, 0x0a, 0xe3, 0x2e, 0x87, 0x61, 0x1e, 0x14, 0xbd, 0x4b, 0xea, 0x8f, 0x7e, 0x1f, + 0xb5, 0xc9, 0x60, 0x08, 0x2a, 0x01, 0x54, 0xd6, 0x0d, 0x12, 0x03, 0xab, 0xd2, 0x42, 0xe2, 0x12, 0xe2, 0x65, 0xbe, + 0x9a, 0xd6, 0x51, 0xf0, 0xa1, 0x9e, 0x10, 0xc2, 0x09, 0xc6, 0x87, 0xb8, 0x01, 0x02, 0x06, 0xab, 0xb8, 0xc0, 0x20, + 0x79, 0x2e, 0xd1, 0xfd, 0xf1, 0x7c, 0xc7, 0x00, 0x57, 0xce, 0x7b, 0xaa, 0x5d, 0x3d, 0xb0, 0x97, 0xab, 0x74, 0xc9, + 0x08, 0x61, 0xc5, 0xff, 0x45, 0xe4, 0x7d, 0x3b, 0x4c, 0x40, 0x6d, 0x23, 0x7f, 0x0c, 0x12, 0x73, 0x99, 0x28, 0x82, + 0x78, 0x94, 0x15, 0x2c, 0x49, 0x83, 0xcd, 0x28, 0x49, 0x41, 0xa3, 0x89, 0x31, 0x64, 0x2a, 0xb4, 0x43, 0xd2, 0x68, + 0x36, 0x26, 0xfb, 0x18, 0xf2, 0x1a, 0x2e, 0x16, 0x0b, 0xbc, 0xef, 0x67, 0xa1, 0x3a, 0xd8, 0x96, 0xe6, 0x10, 0x70, + 0x92, 0x60, 0x4f, 0x5d, 0x91, 0x92, 0x30, 0x1b, 0x7d, 0x0a, 0x39, 0x37, 0xa0, 0xe3, 0xa4, 0x31, 0x54, 0x1f, 0x98, + 0x84, 0x57, 0x11, 0x3a, 0x29, 0x2b, 0x84, 0x05, 0xdc, 0x37, 0x32, 0x1a, 0xad, 0xa4, 0x41, 0xe0, 0x6d, 0x86, 0xad, + 0xc0, 0x26, 0x34, 0xfc, 0x45, 0xe6, 0x61, 0x5a, 0xcd, 0x4a, 0x30, 0xe7, 0x1b, 0xa8, 0xc4, 0x78, 0xb2, 0xbc, 0xe2, + 0x1b, 0x17, 0x2b, 0x31, 0x99, 0x2d, 0xe7, 0x93, 0xb5, 0xa4, 0x9a, 0xcb, 0xbd, 0x35, 0xcb, 0xd8, 0x12, 0xf6, 0x0f, + 0x03, 0x43, 0xe9, 0xc0, 0x8e, 0xa6, 0x9a, 0x36, 0x09, 0x30, 0x99, 0xce, 0x39, 0x1f, 0x5e, 0x22, 0x9a, 0xac, 0x4e, + 0xdd, 0xc9, 0x54, 0xb5, 0x83, 0x6b, 0x72, 0x26, 0xa7, 0x47, 0xea, 0xa9, 0xd6, 0xbd, 0xe4, 0xa3, 0xed, 0xb0, 0x1a, + 0x6d, 0xfd, 0x00, 0xdc, 0x3a, 0x85, 0x9d, 0xbe, 0x1b, 0x56, 0xa3, 0x9d, 0xaf, 0x61, 0x77, 0x49, 0x21, 0x50, 0xfd, + 0x59, 0xd6, 0x64, 0x2e, 0x5e, 0x17, 0x0f, 0x5e, 0xc1, 0x9e, 0xfb, 0x03, 0xfd, 0xab, 0x64, 0xcf, 0x7d, 0x9b, 0xc9, + 0xf5, 0xcf, 0xb4, 0x6b, 0x34, 0x66, 0x3a, 0x5e, 0xbb, 0x02, 0x2b, 0x34, 0x40, 0x7e, 0xc1, 0x8e, 0xf6, 0x36, 0x07, + 0x81, 0x00, 0xdd, 0x4b, 0x70, 0x14, 0x05, 0x44, 0x4d, 0xab, 0xca, 0xa3, 0xd3, 0xbd, 0xbf, 0xc7, 0x37, 0x42, 0xc0, + 0x26, 0x4f, 0xad, 0x7b, 0xcb, 0xd8, 0x3f, 0x1c, 0x20, 0x84, 0x5e, 0x4e, 0xbf, 0xd1, 0x96, 0xd5, 0xa3, 0x1d, 0xcb, + 0x7d, 0xc3, 0xa8, 0xa7, 0x60, 0x0c, 0x43, 0x17, 0x56, 0x31, 0x92, 0x67, 0x40, 0xd6, 0xf8, 0x0d, 0xa2, 0x0b, 0x58, + 0xf4, 0x7a, 0xaf, 0x8f, 0x68, 0x10, 0x01, 0x95, 0x5e, 0xf3, 0x97, 0x22, 0x9f, 0xab, 0x42, 0xf4, 0xde, 0x5b, 0x3b, + 0x6f, 0x66, 0x24, 0xcb, 0xa4, 0x91, 0x6a, 0xb7, 0xb2, 0x58, 0x57, 0xde, 0xec, 0x84, 0x74, 0x31, 0xc7, 0x50, 0x19, + 0x3c, 0x0e, 0x40, 0xe9, 0xf9, 0x97, 0xd0, 0x2b, 0x19, 0x32, 0xcd, 0x12, 0xcd, 0xec, 0xae, 0xf1, 0x27, 0xab, 0xd4, + 0x8b, 0x11, 0x31, 0x1b, 0xd8, 0x42, 0xdc, 0x16, 0x95, 0x6e, 0x8b, 0x42, 0xd9, 0xa2, 0x48, 0x1f, 0x6a, 0x67, 0xba, + 0x33, 0x0b, 0x9f, 0x55, 0xa6, 0x7d, 0x6f, 0x33, 0x33, 0x36, 0x40, 0xdb, 0x45, 0xf8, 0x06, 0x3a, 0x50, 0x21, 0xe4, + 0x3f, 0x22, 0x22, 0x12, 0x01, 0xbb, 0x9c, 0xba, 0x13, 0x9b, 0x0e, 0xc9, 0x3c, 0xc4, 0xac, 0x50, 0xa3, 0xbc, 0xe4, + 0xc9, 0xd1, 0x80, 0x54, 0x84, 0xba, 0xdd, 0xef, 0x9f, 0x2f, 0x5d, 0x50, 0xfb, 0x35, 0xc5, 0x8e, 0xd1, 0x4d, 0x01, + 0xe7, 0x82, 0x47, 0x79, 0xcf, 0xbd, 0x73, 0x40, 0x73, 0x6c, 0x4f, 0x91, 0x35, 0xe0, 0xf4, 0xb6, 0x0b, 0x01, 0xb6, + 0xcf, 0x9a, 0xad, 0xfd, 0xc9, 0xea, 0x2a, 0x9a, 0x7a, 0x25, 0x9f, 0xe9, 0x2e, 0x4a, 0xdc, 0x2e, 0x8a, 0x65, 0x17, + 0x6d, 0x1a, 0x08, 0x76, 0x5c, 0xf9, 0x01, 0xf0, 0x86, 0x46, 0xfd, 0x7e, 0xd9, 0xea, 0xd9, 0x93, 0xaf, 0x1d, 0xf7, + 0x6c, 0xe6, 0xb3, 0xd2, 0xf4, 0xec, 0xaf, 0xa9, 0xdb, 0xb3, 0x72, 0xb2, 0x17, 0x9d, 0x93, 0x7d, 0x3a, 0x9b, 0x07, + 0x82, 0xcb, 0x9d, 0xfb, 0x3c, 0x9f, 0xea, 0x69, 0x57, 0xf9, 0x41, 0x6b, 0x88, 0xcc, 0x17, 0x3e, 0x57, 0xdd, 0xeb, + 0x0a, 0x16, 0xb0, 0x04, 0x77, 0xeb, 0xa5, 0xf9, 0xaf, 0xd8, 0xfd, 0xbd, 0xa0, 0x97, 0xe6, 0xbf, 0xd1, 0x9f, 0x14, + 0xc0, 0x01, 0x68, 0x4c, 0xed, 0x16, 0x78, 0x88, 0xa1, 0x82, 0xc2, 0xdd, 0xac, 0x9c, 0x7b, 0x35, 0xc0, 0x61, 0x92, + 0xbe, 0xa1, 0xd5, 0x2b, 0x2d, 0x76, 0xbd, 0x4c, 0xf6, 0x0a, 0xf0, 0x50, 0x85, 0x3c, 0x3c, 0x1c, 0xa2, 0x8e, 0x61, + 0x07, 0x75, 0x04, 0x0c, 0x7b, 0x08, 0x8d, 0x2d, 0xf0, 0x7c, 0xfc, 0x9c, 0xf1, 0xbd, 0x00, 0xb5, 0x11, 0xc2, 0xe3, + 0xd5, 0xa2, 0x0c, 0xb1, 0x65, 0x6f, 0x91, 0x4a, 0xea, 0x67, 0x81, 0x28, 0xa3, 0x55, 0x40, 0x5b, 0xed, 0x31, 0x4b, + 0xe3, 0x0d, 0x84, 0x8a, 0xa5, 0x3e, 0x86, 0xd0, 0xc0, 0xe1, 0x77, 0x38, 0x80, 0x04, 0x5f, 0x72, 0x4d, 0x36, 0xf7, + 0x36, 0xbf, 0xa7, 0x7d, 0xfe, 0x70, 0x38, 0xbf, 0x44, 0x50, 0xba, 0x14, 0x3e, 0x52, 0x89, 0xa8, 0x9e, 0xe2, 0xa6, + 0x84, 0x6c, 0x96, 0xac, 0xf4, 0x83, 0x5f, 0xd5, 0x2f, 0x00, 0x90, 0x85, 0x40, 0x9b, 0xc8, 0xec, 0x4f, 0x67, 0x2a, + 0xba, 0x00, 0x38, 0xc4, 0x1f, 0x3f, 0x41, 0xf4, 0x0d, 0x2d, 0xd3, 0xf2, 0x71, 0xc2, 0x43, 0xd0, 0xda, 0x92, 0x4e, + 0x22, 0x56, 0x0a, 0x6c, 0x88, 0x84, 0xef, 0xf7, 0xcf, 0x63, 0x49, 0x07, 0x1a, 0xb5, 0xba, 0x37, 0x6e, 0x75, 0xaf, + 0x7c, 0x5d, 0x77, 0x72, 0xe3, 0x83, 0xa2, 0x7d, 0x36, 0x6f, 0x54, 0xbe, 0xef, 0xeb, 0x9c, 0xdd, 0xe9, 0xde, 0x91, + 0x73, 0xe2, 0xfb, 0x7b, 0x08, 0x45, 0x0f, 0x4d, 0x91, 0x65, 0x49, 0x18, 0xd0, 0x5a, 0xbb, 0xf6, 0x2c, 0xa3, 0x83, + 0xd7, 0xbe, 0x21, 0x44, 0xe4, 0x29, 0x3e, 0x09, 0xb9, 0xc5, 0xf1, 0x41, 0x81, 0xfe, 0x99, 0xf1, 0x67, 0x4e, 0xfc, + 0xb0, 0xd5, 0x2f, 0x80, 0x73, 0xd3, 0xbd, 0x77, 0x27, 0x66, 0x3d, 0x86, 0x52, 0x36, 0xfe, 0xef, 0xf7, 0x89, 0x2c, + 0xd0, 0xe9, 0x88, 0x86, 0x81, 0xe0, 0x2e, 0xaa, 0xff, 0x7b, 0xc5, 0xeb, 0x9e, 0xb5, 0x3a, 0x5f, 0x7e, 0xea, 0xf4, + 0xa4, 0x57, 0x2f, 0xe3, 0x1e, 0x50, 0xa1, 0x03, 0x84, 0xf3, 0xba, 0xdf, 0xb0, 0xdd, 0x77, 0xbf, 0xbc, 0x3b, 0x7a, + 0x19, 0xd8, 0xa4, 0x48, 0x6c, 0x2b, 0xf9, 0xac, 0x07, 0x0a, 0xbf, 0x1e, 0xeb, 0xd5, 0xc5, 0xba, 0xc7, 0x7a, 0xa8, + 0x05, 0x44, 0x0f, 0x0b, 0x50, 0xff, 0xf5, 0xec, 0xd3, 0x50, 0x38, 0xc8, 0xc6, 0xa9, 0x02, 0x45, 0x16, 0xfc, 0x5a, + 0x8c, 0xd6, 0x05, 0x01, 0x22, 0x5b, 0x42, 0x5a, 0x75, 0x32, 0x7b, 0x5c, 0x6a, 0x49, 0x06, 0xdf, 0x04, 0x64, 0x76, + 0x60, 0xe5, 0x04, 0xa5, 0xe3, 0xd6, 0x80, 0x2b, 0x5b, 0x3c, 0xda, 0xed, 0x4f, 0x83, 0xec, 0xac, 0x39, 0x69, 0xb4, + 0x0f, 0xfb, 0x34, 0x0f, 0x10, 0x88, 0x64, 0x2a, 0x82, 0x5c, 0x73, 0x6f, 0x49, 0x1f, 0x1d, 0xce, 0x79, 0x21, 0xff, + 0x9c, 0x4a, 0x1d, 0xe2, 0x50, 0x62, 0x0d, 0x04, 0x2a, 0xcf, 0x50, 0xe5, 0xb0, 0x41, 0x8e, 0x7f, 0x76, 0x24, 0x33, + 0x89, 0xc9, 0x22, 0x77, 0x6b, 0xa6, 0xc2, 0x0f, 0x04, 0x1f, 0xb3, 0x9c, 0x03, 0x17, 0xd8, 0x6c, 0xee, 0xab, 0x29, + 0x2e, 0xae, 0xc0, 0x1f, 0x53, 0xf8, 0x15, 0x4f, 0x61, 0xa7, 0xdd, 0xaf, 0x8b, 0x2a, 0x45, 0xdd, 0x46, 0x61, 0x51, + 0xc9, 0x82, 0x69, 0x0d, 0x69, 0xa2, 0xc3, 0xe8, 0x0f, 0x72, 0x06, 0x0a, 0x42, 0x7e, 0xd9, 0x34, 0xc0, 0x48, 0x25, + 0x97, 0x07, 0x55, 0x12, 0x78, 0x01, 0xb6, 0x41, 0xc5, 0xd6, 0x05, 0x04, 0xd9, 0x26, 0x45, 0x99, 0x7e, 0x2d, 0xf2, + 0x3a, 0xcc, 0x82, 0x6a, 0x94, 0x56, 0x3f, 0xe9, 0x9f, 0xc0, 0xbc, 0x4d, 0xc5, 0xa8, 0x56, 0x31, 0xf9, 0x8d, 0x7e, + 0xbf, 0x18, 0xb4, 0x3e, 0x64, 0xf0, 0xd1, 0x6b, 0xd3, 0xe0, 0x4f, 0x4e, 0x83, 0x1d, 0x26, 0x1a, 0x01, 0x90, 0xcc, + 0xa9, 0x25, 0x0f, 0x45, 0x7f, 0x04, 0x39, 0xd6, 0xa8, 0x72, 0x0a, 0x06, 0xeb, 0x3f, 0x1e, 0xed, 0xc0, 0xd4, 0x8b, + 0xa3, 0x2d, 0xd9, 0x41, 0x2b, 0xdf, 0x00, 0xf7, 0x6b, 0x64, 0x8b, 0x59, 0x0e, 0xd0, 0xec, 0x35, 0x22, 0xe3, 0x93, + 0x17, 0xc0, 0x98, 0xad, 0xb3, 0x30, 0x12, 0x71, 0x30, 0x56, 0x8d, 0x19, 0x33, 0x30, 0x70, 0x81, 0xae, 0x65, 0x52, + 0x92, 0x86, 0x74, 0x30, 0x60, 0xa5, 0x6c, 0xe1, 0x80, 0x17, 0xcd, 0x71, 0x3b, 0xde, 0xb4, 0x68, 0x3c, 0xb0, 0x5d, + 0x6c, 0x7f, 0xff, 0xb2, 0xd8, 0xbe, 0x0b, 0xb7, 0xa4, 0x57, 0xc8, 0x59, 0x42, 0x3f, 0x7f, 0x92, 0x7d, 0xd6, 0x70, + 0x72, 0x2a, 0x34, 0x43, 0x4b, 0x91, 0x50, 0x8a, 0x77, 0x7a, 0x52, 0x60, 0x2c, 0x63, 0xe1, 0xef, 0x81, 0x73, 0xba, + 0x50, 0x44, 0xee, 0xc0, 0x71, 0x7c, 0x03, 0x15, 0x8c, 0x1a, 0x0e, 0x5e, 0xc6, 0xb0, 0x2d, 0x8a, 0x59, 0x48, 0x38, + 0x85, 0x70, 0xb1, 0xca, 0xfa, 0x7d, 0xf9, 0x8b, 0xba, 0xe8, 0x22, 0x93, 0x75, 0x9f, 0x84, 0x23, 0x33, 0x96, 0x53, + 0x2f, 0x24, 0xcf, 0x7b, 0x9e, 0x4c, 0x93, 0x67, 0x79, 0x10, 0x01, 0xe4, 0x73, 0x78, 0x1f, 0xa6, 0x19, 0x58, 0xa5, + 0x49, 0xf9, 0x11, 0x4a, 0x5f, 0x7c, 0x5e, 0xf9, 0x81, 0xce, 0x9e, 0x9b, 0x64, 0x78, 0xb3, 0x6a, 0xbd, 0x49, 0xad, + 0xeb, 0xe2, 0x01, 0xff, 0xea, 0x0c, 0x36, 0xce, 0x75, 0x26, 0x38, 0xf0, 0x22, 0xa9, 0xf5, 0x9a, 0xf1, 0xeb, 0x0c, + 0xd7, 0xa5, 0x6a, 0xa3, 0x8f, 0x42, 0x74, 0x0e, 0x99, 0x0a, 0x50, 0x28, 0xd2, 0xfe, 0x41, 0xa9, 0x95, 0x49, 0xa5, + 0x8d, 0x04, 0xd0, 0x3d, 0x4c, 0x1a, 0x6c, 0x31, 0x94, 0xb1, 0x34, 0x89, 0x72, 0xa7, 0x41, 0x5c, 0xd9, 0x9f, 0x2b, + 0x89, 0x43, 0xcb, 0x22, 0xf9, 0xf7, 0xae, 0xa7, 0xaf, 0x90, 0xba, 0x93, 0x05, 0x32, 0x63, 0xbc, 0xc8, 0xe3, 0xcf, + 0x40, 0x98, 0x0d, 0xda, 0xa8, 0x28, 0x84, 0x90, 0x0d, 0x62, 0xd0, 0x78, 0x91, 0xc7, 0x2f, 0x15, 0x8d, 0x87, 0x7c, + 0x14, 0xf9, 0xea, 0xaf, 0x52, 0xff, 0x15, 0xfa, 0xcc, 0x04, 0x8f, 0x50, 0x4d, 0xf4, 0xef, 0x9e, 0xcf, 0xee, 0x41, + 0x6d, 0x18, 0x85, 0x99, 0x29, 0xbf, 0xf2, 0x4d, 0x71, 0xf6, 0xfa, 0x2b, 0xba, 0xca, 0xb6, 0xee, 0x47, 0x9f, 0x8e, + 0x08, 0xac, 0x8d, 0xd1, 0x15, 0x37, 0x06, 0x90, 0xc3, 0xe4, 0xfd, 0x8a, 0xd2, 0x72, 0x48, 0x83, 0xd0, 0x41, 0x43, + 0xd0, 0x2b, 0x89, 0x3e, 0x90, 0x58, 0xc4, 0x18, 0x5e, 0x88, 0x67, 0xa4, 0x26, 0x13, 0x0d, 0xf1, 0x8a, 0xd8, 0x0f, + 0xd1, 0x92, 0x53, 0x13, 0xdd, 0x08, 0x53, 0x0c, 0x24, 0x76, 0x06, 0xc9, 0x49, 0x52, 0x2b, 0xbf, 0x78, 0x26, 0x09, + 0x4b, 0xec, 0x3c, 0xc4, 0x60, 0x52, 0x4b, 0x77, 0x7a, 0x53, 0xa5, 0xf7, 0x47, 0x5a, 0x0e, 0xda, 0x07, 0x60, 0x97, + 0x92, 0xde, 0x3f, 0x29, 0x14, 0xf1, 0x31, 0x8c, 0x63, 0x08, 0xdf, 0x22, 0xaa, 0x2b, 0x70, 0xae, 0x15, 0x68, 0xac, + 0x06, 0x1e, 0x9a, 0x59, 0x35, 0x1f, 0x72, 0xfa, 0xa9, 0xb4, 0xfc, 0x31, 0xa2, 0xb1, 0xd1, 0xba, 0x39, 0x1c, 0xf6, + 0xb4, 0xea, 0xa5, 0x73, 0xd0, 0x65, 0x33, 0x89, 0x89, 0x1b, 0x48, 0xd7, 0x8f, 0x7e, 0x33, 0x61, 0x2f, 0xa2, 0x42, + 0x2e, 0x85, 0xa0, 0xa0, 0xd5, 0x81, 0xc0, 0xa1, 0xf0, 0x16, 0x65, 0xbe, 0x88, 0x69, 0x03, 0x61, 0xf0, 0xf9, 0x81, + 0xfc, 0x7c, 0x53, 0x90, 0x8a, 0x1d, 0xeb, 0xda, 0xef, 0x6f, 0x4a, 0x0f, 0xf0, 0xe4, 0x4c, 0x92, 0xa7, 0xcd, 0x10, + 0x56, 0x04, 0xd0, 0x98, 0xd5, 0x64, 0x71, 0xc2, 0x95, 0x39, 0xfc, 0x54, 0x79, 0x25, 0x4b, 0x99, 0x3a, 0x4f, 0xf5, + 0x02, 0x88, 0x3a, 0xde, 0xa0, 0x15, 0xa9, 0x5f, 0xa1, 0xb3, 0xd7, 0xac, 0x84, 0x8c, 0x87, 0xe7, 0x9c, 0xa7, 0xa3, + 0x07, 0x96, 0xf0, 0x08, 0xff, 0x4a, 0x26, 0xfa, 0xf0, 0x7b, 0xe0, 0x70, 0x33, 0x4e, 0x78, 0xe4, 0x36, 0x7b, 0x5f, + 0x85, 0x2b, 0xb8, 0x99, 0x16, 0x80, 0xe4, 0x16, 0x24, 0x4d, 0x40, 0x09, 0x89, 0x4c, 0xc8, 0xac, 0x29, 0xf9, 0xa5, + 0xa5, 0x6d, 0xb0, 0x86, 0x49, 0xe7, 0x01, 0x2f, 0x5a, 0x7d, 0xb4, 0x9a, 0x68, 0x97, 0x59, 0x3e, 0x1f, 0xe2, 0x0c, + 0xd5, 0x1c, 0x77, 0x67, 0xf0, 0x73, 0xc0, 0x2b, 0x56, 0x35, 0xe9, 0x68, 0x37, 0xe0, 0xc2, 0x93, 0xeb, 0x3c, 0x1d, + 0x6d, 0xf1, 0x97, 0xdc, 0x1f, 0x00, 0x3a, 0x98, 0xba, 0x04, 0xfe, 0x54, 0x6d, 0x35, 0x95, 0xfa, 0xa5, 0xb5, 0x5f, + 0xd7, 0x9d, 0xd5, 0xca, 0x3d, 0xeb, 0x32, 0xb4, 0x47, 0x86, 0x9c, 0x31, 0x03, 0xfe, 0x9c, 0xb1, 0xe4, 0xcf, 0x19, + 0x2b, 0xfe, 0x9c, 0x71, 0x63, 0x64, 0x00, 0x25, 0xb8, 0x97, 0xfc, 0x7a, 0x8f, 0x98, 0x21, 0x56, 0x83, 0x4a, 0x60, + 0x65, 0x29, 0xe7, 0x3e, 0x72, 0x8a, 0x29, 0xa7, 0x0c, 0x2f, 0x9d, 0xce, 0xdc, 0x81, 0x9c, 0x07, 0x33, 0x77, 0x98, + 0x9c, 0xf5, 0x29, 0x8e, 0xa5, 0x31, 0x29, 0x2a, 0x48, 0xe7, 0x74, 0xb8, 0x79, 0x75, 0x9c, 0x27, 0x2c, 0xe3, 0xe3, + 0xf6, 0x99, 0x02, 0x21, 0xb6, 0x78, 0x86, 0x44, 0x4a, 0xd5, 0x2c, 0xb7, 0xf9, 0xc3, 0xa1, 0x1e, 0x3d, 0xe8, 0x9d, + 0x1e, 0x7e, 0x25, 0xec, 0x97, 0xcc, 0xb3, 0x4f, 0x10, 0xc0, 0x24, 0x91, 0x67, 0x12, 0x8e, 0x7e, 0x2c, 0x47, 0x7f, + 0xd3, 0xf0, 0xf7, 0x19, 0xaa, 0xbb, 0x43, 0x60, 0x62, 0xcb, 0x0e, 0x1c, 0x82, 0xd3, 0x55, 0x25, 0x12, 0x70, 0xb0, + 0xd9, 0xb0, 0x48, 0xef, 0xf1, 0x10, 0xe7, 0x83, 0xc2, 0x47, 0x68, 0x98, 0xd1, 0xfb, 0xfd, 0x8d, 0xf0, 0x2a, 0xd9, + 0xca, 0xc3, 0x21, 0xb1, 0xee, 0xc2, 0x8e, 0x3e, 0x8e, 0xf6, 0x28, 0xa1, 0xf6, 0xa3, 0x5a, 0x6f, 0x2a, 0xf5, 0x20, + 0x37, 0xbb, 0x90, 0x18, 0x54, 0x2c, 0xd5, 0xa7, 0x57, 0xaa, 0x0f, 0x35, 0xeb, 0xfc, 0xae, 0x8e, 0xfb, 0x54, 0x8c, + 0xd6, 0x72, 0x42, 0x80, 0xeb, 0x20, 0xd1, 0xe8, 0x00, 0x18, 0x67, 0x9b, 0x2d, 0x2f, 0xb5, 0x75, 0xa2, 0x74, 0x1c, + 0xe7, 0xfa, 0x38, 0x3e, 0x1c, 0xa4, 0x98, 0x71, 0x79, 0x24, 0x66, 0x5c, 0x36, 0x00, 0x6f, 0xd6, 0x79, 0x50, 0x1f, + 0x0e, 0x97, 0x74, 0x29, 0x32, 0x9d, 0x6d, 0x94, 0x9f, 0xf5, 0xe8, 0xe1, 0x59, 0x82, 0xe6, 0xde, 0x0a, 0x7b, 0x2f, + 0x92, 0xed, 0x99, 0xac, 0x53, 0x2f, 0x23, 0x9f, 0x5e, 0xb8, 0x67, 0x97, 0x5c, 0xfd, 0xb0, 0xfa, 0x7a, 0xfa, 0xab, + 0xf0, 0x22, 0x56, 0xd1, 0x6e, 0x5d, 0x32, 0x61, 0x6f, 0x29, 0x95, 0xb4, 0xca, 0xcb, 0xa7, 0x1b, 0x3f, 0xc0, 0xcc, + 0xb4, 0xa7, 0x0f, 0xb2, 0x11, 0xd5, 0x9f, 0x95, 0xa8, 0x95, 0x61, 0xb2, 0x70, 0x5e, 0x32, 0xf5, 0x64, 0xc0, 0x63, + 0x56, 0xf2, 0x48, 0x76, 0x7a, 0x63, 0x10, 0x04, 0xb0, 0xce, 0x49, 0xab, 0xce, 0x38, 0x1a, 0xad, 0x2a, 0x17, 0xa7, + 0xab, 0x5c, 0x60, 0xb8, 0xdd, 0x9a, 0x6d, 0x54, 0x9d, 0xe5, 0xa6, 0x56, 0x29, 0xdf, 0x01, 0x7c, 0x2c, 0xab, 0x5c, + 0xd0, 0x31, 0x65, 0xea, 0xbc, 0x81, 0x60, 0x6c, 0x55, 0xe3, 0xc2, 0xa9, 0x71, 0xc1, 0x23, 0x6a, 0x77, 0xd3, 0xd4, + 0xa3, 0x2d, 0xb0, 0x94, 0x8e, 0x76, 0xbc, 0x44, 0x95, 0xc2, 0xdf, 0x04, 0xdf, 0x87, 0x71, 0xfc, 0xb2, 0xd8, 0xaa, + 0x03, 0xf1, 0xb6, 0xd8, 0x22, 0xed, 0x8b, 0xfc, 0x0b, 0x71, 0xc0, 0x6b, 0x5d, 0x53, 0x5e, 0x5b, 0x73, 0x1a, 0xd8, + 0x1a, 0x46, 0x4a, 0x0a, 0xe7, 0xe6, 0xcf, 0xc3, 0x81, 0x56, 0x76, 0xad, 0xee, 0x0a, 0xb5, 0x1e, 0x73, 0xd8, 0xb0, + 0x17, 0x59, 0xb8, 0x13, 0x25, 0x38, 0x72, 0xc9, 0xbf, 0x0e, 0x07, 0xad, 0xb2, 0x54, 0x47, 0xfa, 0x6c, 0xff, 0x35, + 0x18, 0x33, 0x74, 0x69, 0x02, 0x96, 0x8d, 0x91, 0xfc, 0xab, 0x69, 0xe6, 0x0d, 0x93, 0x35, 0x53, 0x38, 0x0e, 0x0d, + 0x23, 0xa4, 0x01, 0xdd, 0x06, 0xb5, 0xe1, 0xc9, 0x7c, 0x53, 0x95, 0x5f, 0xdd, 0x91, 0x6a, 0x3f, 0x18, 0x5e, 0x4e, + 0xc4, 0x39, 0x5d, 0x92, 0xd4, 0x53, 0x09, 0x25, 0x21, 0xd8, 0xa5, 0x0f, 0xe4, 0xc4, 0x0a, 0xc8, 0x5a, 0xc6, 0xf2, + 0x5b, 0x3d, 0x20, 0xf4, 0x9f, 0x76, 0xeb, 0x85, 0xfe, 0xd3, 0x34, 0x5b, 0xa8, 0xeb, 0x0f, 0x93, 0xfb, 0x8e, 0x5e, + 0x7f, 0x70, 0x78, 0xa7, 0xae, 0x2a, 0xae, 0xe2, 0x51, 0x6d, 0x98, 0xe4, 0x46, 0x59, 0xb8, 0x2b, 0x36, 0xb5, 0x5a, + 0x9e, 0x8e, 0xc3, 0x08, 0xcc, 0x08, 0x0a, 0x90, 0x75, 0xdd, 0x46, 0xc4, 0xb0, 0x92, 0xcb, 0x84, 0x7c, 0x42, 0x40, + 0x16, 0xa5, 0xc6, 0xf9, 0xb8, 0x05, 0x2a, 0x11, 0x0c, 0x4e, 0x43, 0x6b, 0xd5, 0x4d, 0x7e, 0x52, 0xd9, 0xd8, 0x1d, + 0x90, 0x43, 0x92, 0xc9, 0xe2, 0x6e, 0x74, 0x2b, 0x96, 0x45, 0x29, 0x7e, 0xc6, 0x7a, 0xb8, 0x66, 0x0b, 0xf7, 0x19, + 0x10, 0xda, 0x4f, 0x94, 0xf6, 0x26, 0xd2, 0x04, 0xdd, 0x77, 0x6c, 0x05, 0x20, 0x03, 0x28, 0xea, 0x6a, 0xb7, 0x3e, + 0xe7, 0xe7, 0x48, 0x9a, 0xe1, 0x30, 0xba, 0x7d, 0x7a, 0x17, 0xdc, 0x0d, 0x2e, 0x51, 0x2b, 0x7d, 0xc9, 0xe2, 0x16, + 0x06, 0xd5, 0xde, 0x2c, 0xe1, 0xa0, 0x66, 0xd6, 0xda, 0x08, 0x04, 0x93, 0x3d, 0x14, 0x54, 0xcc, 0x15, 0xec, 0x83, + 0x82, 0xb5, 0xe4, 0x75, 0x70, 0xb8, 0xb5, 0x2f, 0x2b, 0xc5, 0xc5, 0xf3, 0x8b, 0xa4, 0x75, 0x61, 0x29, 0x2f, 0x9e, + 0x37, 0x60, 0x70, 0x39, 0xc2, 0xa6, 0xaa, 0xfc, 0xc9, 0x06, 0x40, 0xb7, 0x22, 0x8a, 0x78, 0x51, 0x0a, 0xdb, 0x56, + 0x3e, 0x73, 0xc2, 0x06, 0x1b, 0xf6, 0x00, 0xf7, 0xca, 0xa0, 0x64, 0x70, 0x21, 0xc6, 0xed, 0x66, 0x17, 0xe0, 0x0a, + 0x86, 0xc2, 0xd8, 0x9a, 0xbf, 0xc9, 0xbc, 0x48, 0x09, 0xb8, 0x19, 0xa2, 0x7c, 0x6d, 0xe0, 0x64, 0xd2, 0x93, 0x6b, + 0xc9, 0x62, 0xc0, 0x82, 0x06, 0xdf, 0x51, 0xeb, 0xef, 0x4c, 0xfe, 0x8d, 0xa7, 0x87, 0x7e, 0xf0, 0x25, 0xf3, 0x96, + 0x3e, 0x7b, 0x53, 0xc9, 0x68, 0x4d, 0x12, 0xe5, 0xd5, 0xc3, 0x25, 0xc8, 0x0d, 0xcb, 0xd1, 0x03, 0x5b, 0x82, 0x38, + 0xb1, 0x1c, 0x25, 0x94, 0xd1, 0x15, 0xee, 0x55, 0x66, 0xcb, 0x44, 0x20, 0xc5, 0x81, 0xa5, 0x94, 0x7b, 0x8b, 0x75, + 0xb0, 0xc4, 0xfd, 0x89, 0xe4, 0x02, 0x4a, 0x1e, 0x40, 0xb9, 0x52, 0x40, 0xc0, 0xa7, 0x03, 0x28, 0x5f, 0xca, 0x8b, + 0xf0, 0x27, 0x4e, 0xd4, 0x60, 0x39, 0x7a, 0x68, 0xd8, 0x4f, 0x5e, 0x68, 0xd9, 0x1f, 0xee, 0xb4, 0xa6, 0x61, 0xc5, + 0xef, 0x60, 0x5a, 0x4c, 0xdc, 0xbe, 0x5c, 0xd9, 0x55, 0xf1, 0xd9, 0x4a, 0x9d, 0xdd, 0xd4, 0x90, 0x84, 0x7d, 0x43, + 0x56, 0x01, 0x0e, 0x56, 0x45, 0xdc, 0xb3, 0x2c, 0xf7, 0x61, 0xf4, 0xe7, 0x26, 0x2d, 0x85, 0x85, 0x2a, 0xe9, 0xef, + 0x9b, 0x52, 0x20, 0x95, 0x89, 0x4e, 0xb4, 0x10, 0x5c, 0x81, 0x41, 0xe0, 0x5e, 0xe4, 0x35, 0x00, 0xc6, 0x80, 0x4b, + 0x81, 0xb2, 0x6c, 0x4b, 0x08, 0xa9, 0xee, 0x67, 0xa0, 0xb6, 0x13, 0xf7, 0x69, 0x44, 0xd6, 0x42, 0xf4, 0x55, 0x30, + 0x66, 0xce, 0x4b, 0xe9, 0x16, 0x9b, 0xae, 0x36, 0xab, 0x1b, 0x74, 0x2e, 0x6d, 0xb9, 0xf9, 0x09, 0x5b, 0xac, 0x15, + 0x28, 0x9b, 0x90, 0xb4, 0x9d, 0xf3, 0x1c, 0x65, 0x13, 0x5a, 0xda, 0x7b, 0xea, 0x51, 0xa1, 0x3a, 0xd9, 0x7a, 0xa9, + 0x9a, 0x5a, 0x84, 0xd5, 0xe2, 0xa2, 0xf2, 0x03, 0xd0, 0x4d, 0xa5, 0xd5, 0x8b, 0xba, 0x46, 0x53, 0xa8, 0xd5, 0xc2, + 0x71, 0xa3, 0x9d, 0x4d, 0x97, 0xe9, 0x1d, 0xe2, 0xac, 0x4a, 0x3b, 0xf4, 0xcb, 0x4c, 0xbb, 0x5e, 0x76, 0xf4, 0x9b, + 0x71, 0x75, 0x81, 0x0b, 0xb1, 0x01, 0x9f, 0x73, 0x7f, 0x79, 0xbd, 0xe7, 0x71, 0xcf, 0x3f, 0x1c, 0x90, 0x3d, 0xa9, + 0xfd, 0xa1, 0xfa, 0xd8, 0x15, 0x0c, 0x59, 0x18, 0xa5, 0xfe, 0x22, 0xe5, 0xbd, 0x27, 0x38, 0xee, 0x5f, 0xaa, 0x1e, + 0xfb, 0x29, 0xe3, 0xfb, 0xba, 0xd8, 0x44, 0x09, 0x45, 0x35, 0xf4, 0x56, 0xc5, 0xa6, 0x12, 0x71, 0xf1, 0x90, 0xf7, + 0x18, 0x26, 0xc3, 0x58, 0xc8, 0x54, 0xf8, 0x53, 0xa6, 0x82, 0x47, 0x08, 0x25, 0x6e, 0xd6, 0x3d, 0xd2, 0x6e, 0x42, + 0x9c, 0x52, 0x2d, 0x4a, 0x99, 0x8c, 0x7f, 0xeb, 0x27, 0x50, 0x9e, 0x53, 0xb4, 0x4c, 0x3f, 0x2a, 0x5c, 0xa6, 0x6f, + 0xd6, 0xc7, 0xa5, 0x67, 0x22, 0xd4, 0x99, 0x8b, 0x4d, 0xad, 0xd3, 0x31, 0x76, 0x4a, 0xa7, 0x36, 0xec, 0x6b, 0xa5, + 0xb8, 0xac, 0x28, 0xfc, 0x1b, 0x89, 0xac, 0x7a, 0x46, 0x1c, 0xff, 0x67, 0xd6, 0x3e, 0xc3, 0x2a, 0xf0, 0xcb, 0x40, + 0xde, 0x2f, 0x00, 0x3e, 0xae, 0xeb, 0x32, 0xbd, 0xdd, 0x00, 0x6d, 0x08, 0x0d, 0x7f, 0xcf, 0x47, 0x06, 0x4c, 0xf7, + 0x11, 0xce, 0x90, 0x1e, 0xea, 0x9c, 0xd3, 0x59, 0x99, 0xce, 0xb9, 0x0a, 0x6b, 0x09, 0xf6, 0x72, 0xd2, 0xe4, 0x72, + 0x5d, 0x82, 0x9a, 0x09, 0xdc, 0x3e, 0xb4, 0x47, 0x84, 0x50, 0x9b, 0xb2, 0x9a, 0x5e, 0x42, 0xcd, 0x3b, 0x39, 0xed, + 0x68, 0x52, 0x82, 0xab, 0x86, 0xce, 0xca, 0xf5, 0x5f, 0x87, 0x43, 0xef, 0x36, 0x2b, 0xa2, 0x3f, 0x7a, 0xe8, 0xef, + 0xb8, 0xbd, 0x49, 0xbf, 0x42, 0xb4, 0x8c, 0xf5, 0x37, 0x64, 0x40, 0xc7, 0x93, 0xe1, 0x6d, 0xb1, 0xed, 0xb1, 0xaf, + 0xa8, 0xc1, 0xd2, 0xd7, 0x8f, 0x3f, 0x40, 0x42, 0xd5, 0xb5, 0x2f, 0x2c, 0x9e, 0x30, 0x4f, 0x89, 0xb6, 0x85, 0x0f, + 0x61, 0xa1, 0x5f, 0x21, 0x32, 0x12, 0xc2, 0x4d, 0x65, 0xf7, 0x28, 0x69, 0x17, 0xfa, 0xd2, 0xd7, 0xb2, 0xaf, 0x7c, + 0xe7, 0x02, 0x60, 0x65, 0x9f, 0xdb, 0x70, 0x4f, 0xfa, 0x53, 0xaa, 0x0f, 0xdb, 0xdf, 0x92, 0x05, 0x14, 0x5a, 0x58, + 0x4f, 0xe5, 0xec, 0x5c, 0x97, 0x3c, 0xcd, 0xa6, 0xfb, 0x35, 0xec, 0x51, 0xf7, 0xe8, 0x35, 0x15, 0x9c, 0x5f, 0x9a, + 0xd1, 0xfb, 0x87, 0xa1, 0x50, 0x1d, 0x75, 0xee, 0x20, 0xeb, 0xd2, 0xba, 0xe4, 0xfc, 0x66, 0xe5, 0x8e, 0xc2, 0xfc, + 0x3e, 0x04, 0xcf, 0xb0, 0xee, 0xdd, 0xc5, 0x79, 0xef, 0xcf, 0xd6, 0x1c, 0xf9, 0x29, 0x9b, 0xa5, 0x88, 0x45, 0x32, + 0x07, 0xab, 0x1f, 0xfa, 0x79, 0xec, 0xb7, 0x41, 0x0e, 0xc7, 0x4d, 0x03, 0x3a, 0x6c, 0xc8, 0xac, 0x7d, 0x89, 0xc0, + 0xa9, 0x46, 0x90, 0xa6, 0x26, 0xa8, 0x59, 0x1e, 0x22, 0xb1, 0x5d, 0xca, 0xb6, 0x41, 0xae, 0xbb, 0x60, 0x9a, 0x23, + 0xed, 0x19, 0xbc, 0x6f, 0xd2, 0x24, 0x15, 0x9a, 0x45, 0xda, 0x2a, 0x19, 0xff, 0x8e, 0xb4, 0x99, 0x92, 0x3d, 0xb6, + 0x06, 0xde, 0x4b, 0x50, 0x4e, 0x86, 0x29, 0x86, 0xef, 0xf8, 0x7a, 0xe7, 0x31, 0xf7, 0x9c, 0x63, 0xb6, 0x49, 0xd9, + 0x11, 0x4c, 0x92, 0x8d, 0x6f, 0x28, 0xde, 0xf0, 0xc3, 0x6d, 0x25, 0x4a, 0x00, 0xbd, 0x2c, 0xf8, 0xb5, 0xb4, 0xb9, + 0x42, 0xb7, 0xbb, 0x77, 0x94, 0xc2, 0x2f, 0x79, 0x79, 0x38, 0x6c, 0x53, 0x2f, 0x84, 0xce, 0x17, 0xf1, 0x7b, 0x30, + 0x87, 0x31, 0xc4, 0x66, 0x04, 0x08, 0x73, 0x7c, 0x40, 0x1d, 0xac, 0x1f, 0x01, 0x68, 0x9c, 0x40, 0x01, 0x46, 0x5f, + 0x6d, 0x0b, 0xfa, 0x96, 0x17, 0x17, 0x11, 0xa2, 0x46, 0x01, 0x26, 0x4a, 0x9a, 0xc5, 0x30, 0x1c, 0xe8, 0xfc, 0xbe, + 0xb9, 0xad, 0x4b, 0x81, 0x43, 0xef, 0x58, 0x86, 0xff, 0xf6, 0x3f, 0xd6, 0x96, 0x56, 0x95, 0xed, 0xd6, 0x38, 0xcd, + 0xfc, 0x6f, 0xb7, 0x85, 0xbe, 0xff, 0x4a, 0x28, 0x9e, 0x77, 0xbc, 0x6e, 0xbf, 0x87, 0xe8, 0x7d, 0xdd, 0xca, 0xbb, + 0x52, 0xbb, 0x61, 0xa6, 0xfc, 0x21, 0xcd, 0xe3, 0xe2, 0x61, 0x14, 0xb7, 0x8e, 0xbc, 0x49, 0x7a, 0xce, 0xf9, 0xfb, + 0xaa, 0xdf, 0xf7, 0xde, 0x03, 0x19, 0xef, 0x2b, 0x61, 0x1c, 0x31, 0x89, 0x83, 0x6f, 0x2f, 0x46, 0xd1, 0xa6, 0x84, + 0x0d, 0xb9, 0x7d, 0x5a, 0x82, 0x66, 0xa6, 0xdf, 0x47, 0x89, 0xd2, 0x9a, 0xef, 0x7f, 0x91, 0xf3, 0xfd, 0x95, 0x90, + 0x37, 0x2b, 0xf9, 0xe1, 0xa3, 0x15, 0x06, 0xbe, 0xc7, 0xe9, 0x57, 0xd1, 0x63, 0x77, 0xa5, 0x0f, 0xdf, 0x95, 0x96, + 0x3e, 0xab, 0xa8, 0xbf, 0xa3, 0xa2, 0xe6, 0x95, 0x18, 0x11, 0xf1, 0x20, 0x68, 0x67, 0xdb, 0xa5, 0x76, 0x2d, 0x41, + 0xbb, 0x60, 0x53, 0xd8, 0xbf, 0x1e, 0x1d, 0xf2, 0x7e, 0xff, 0x53, 0xee, 0xb5, 0x78, 0xdd, 0x75, 0x68, 0xca, 0x5f, + 0x0b, 0x0f, 0x21, 0x80, 0xb5, 0x0c, 0x94, 0x71, 0x84, 0x49, 0x17, 0x79, 0x8d, 0xb2, 0xe9, 0x44, 0xe0, 0x63, 0x96, + 0x5d, 0x39, 0xc9, 0x34, 0xc0, 0x8c, 0x6a, 0x0a, 0x33, 0x01, 0x46, 0xea, 0x13, 0xd6, 0x4d, 0x4f, 0xab, 0xd0, 0xf2, + 0x35, 0x04, 0xeb, 0x22, 0xcb, 0x38, 0x8a, 0x99, 0x00, 0x60, 0xf3, 0x09, 0xe4, 0x2b, 0xba, 0x3a, 0x24, 0xad, 0x54, + 0x79, 0xbf, 0xce, 0x88, 0x8c, 0x26, 0x21, 0x9a, 0xdf, 0xc2, 0x03, 0xfb, 0xb6, 0x99, 0x51, 0xa5, 0x9e, 0x51, 0x95, + 0xcf, 0x70, 0x58, 0x0a, 0xc7, 0x88, 0xff, 0xb7, 0x54, 0xf5, 0x88, 0x40, 0xaf, 0xca, 0xb4, 0x8a, 0x8a, 0x3c, 0x17, + 0x11, 0x22, 0x54, 0x4b, 0xe7, 0x70, 0xe8, 0xc7, 0x7e, 0x1f, 0x07, 0xc2, 0xbc, 0xf8, 0xd7, 0xc7, 0xba, 0xf2, 0xaf, + 0x05, 0xae, 0x95, 0x14, 0x38, 0x15, 0x35, 0x42, 0x84, 0xf0, 0xfe, 0x04, 0x9e, 0xd5, 0xd4, 0xf7, 0x1b, 0xcb, 0x44, + 0xf7, 0x8f, 0x0c, 0x28, 0x7f, 0x40, 0xbe, 0xae, 0xa4, 0x38, 0x53, 0x27, 0x8f, 0x89, 0x33, 0x0e, 0x40, 0xcc, 0xb7, + 0x25, 0x1a, 0x8d, 0xfd, 0x0f, 0x48, 0x30, 0x54, 0x3f, 0xd8, 0xe9, 0xa6, 0xde, 0x3f, 0x33, 0x89, 0xa3, 0xe8, 0xd3, + 0x36, 0x79, 0x2c, 0x59, 0x1a, 0x2d, 0x1c, 0xbd, 0x47, 0x0c, 0xe3, 0x70, 0x3a, 0x1f, 0x93, 0x6c, 0x63, 0xb2, 0x0a, + 0x20, 0x9d, 0xcc, 0xd4, 0x31, 0xa5, 0x8e, 0xc6, 0xb9, 0x5e, 0x50, 0x85, 0x1e, 0xeb, 0x92, 0xe7, 0x60, 0x3d, 0xf9, + 0xd1, 0x2b, 0xfd, 0xa9, 0x90, 0x73, 0xd8, 0x48, 0x04, 0x85, 0x1f, 0xe0, 0x6a, 0xb0, 0x52, 0xc0, 0x60, 0xea, 0x5b, + 0xf8, 0x9a, 0x78, 0x8e, 0x82, 0x47, 0x61, 0x17, 0x63, 0x6b, 0xe5, 0x3b, 0x9f, 0x14, 0x94, 0x7b, 0x56, 0xcc, 0x79, + 0x05, 0x9c, 0xcb, 0xa0, 0x10, 0xa6, 0xe3, 0x59, 0xfe, 0xcf, 0x24, 0xaf, 0x27, 0x36, 0x04, 0xc8, 0xe0, 0x4f, 0x89, + 0xd3, 0xd2, 0x1d, 0xba, 0xf3, 0xd0, 0xb3, 0x88, 0xc3, 0x46, 0x4f, 0xd6, 0x65, 0xb1, 0x4d, 0x51, 0x2f, 0x61, 0x7e, + 0x20, 0x3f, 0x6f, 0xc9, 0xf7, 0x21, 0x8a, 0xb7, 0xc1, 0xaf, 0x19, 0x8b, 0x05, 0xfe, 0xf5, 0xb7, 0x8c, 0xd1, 0x44, + 0x0b, 0xfe, 0x95, 0x35, 0x48, 0x54, 0xfc, 0xd7, 0x6c, 0x02, 0xb0, 0x8e, 0x5c, 0x7d, 0xf8, 0x94, 0x18, 0x6f, 0xcd, + 0x86, 0x47, 0xbe, 0x59, 0x81, 0x4e, 0x7d, 0xee, 0xae, 0x6c, 0x4f, 0x55, 0xe3, 0x6f, 0xa9, 0xae, 0x46, 0xaa, 0xaa, + 0xf1, 0xb7, 0x94, 0xaa, 0xf1, 0x5b, 0x46, 0xf1, 0x3b, 0x95, 0xcf, 0x90, 0x39, 0xd9, 0xc4, 0x24, 0x9d, 0xbe, 0x37, + 0x9c, 0xd8, 0x65, 0xbf, 0x79, 0x9b, 0xc8, 0x4c, 0xa4, 0x90, 0x7b, 0x03, 0xd0, 0xf6, 0xbb, 0xdc, 0x70, 0x4a, 0x9c, + 0x9f, 0x7b, 0xb8, 0x62, 0xd3, 0xea, 0x15, 0x2d, 0x58, 0x60, 0xf3, 0x32, 0xcb, 0x53, 0x24, 0xb0, 0x6d, 0xca, 0xac, + 0x3f, 0xe7, 0x1e, 0x40, 0x30, 0x93, 0x9a, 0x00, 0x90, 0x16, 0xa2, 0x52, 0x88, 0xfc, 0x15, 0xce, 0xea, 0x73, 0xde, + 0xdb, 0xe4, 0x31, 0x91, 0x56, 0xf7, 0xfa, 0xfd, 0xf4, 0x2c, 0xcd, 0x29, 0xa8, 0xe1, 0x38, 0xeb, 0xf4, 0x65, 0x16, + 0xd4, 0x89, 0x5c, 0xa5, 0x7f, 0x77, 0x83, 0xbc, 0x8c, 0xef, 0xeb, 0xb6, 0xe7, 0x4f, 0xd4, 0xdf, 0x3b, 0xeb, 0x6f, + 0x0b, 0x04, 0x77, 0x72, 0xec, 0x27, 0xab, 0x52, 0x9e, 0x18, 0x97, 0xf6, 0x9e, 0xdf, 0xd4, 0x45, 0x91, 0xd5, 0xe9, + 0xfa, 0xa3, 0xd4, 0xd3, 0xe8, 0xbe, 0xd8, 0x83, 0x31, 0x78, 0x07, 0x80, 0x67, 0x3a, 0x34, 0x40, 0xfa, 0x9e, 0x91, + 0x87, 0xfb, 0xdc, 0x92, 0x9f, 0x54, 0xd6, 0x26, 0x09, 0x2b, 0x8a, 0xcd, 0x30, 0x46, 0x28, 0x19, 0xa7, 0xb1, 0xf5, + 0xfb, 0x7d, 0xf5, 0xf7, 0x0e, 0xa3, 0xa8, 0xa8, 0xb8, 0x63, 0x34, 0x2a, 0xab, 0x7a, 0xb4, 0x1d, 0x1c, 0x0e, 0xe7, + 0xb9, 0x8d, 0xa3, 0xad, 0x57, 0xc0, 0xde, 0x0a, 0x95, 0xb2, 0x57, 0x22, 0x2c, 0x3f, 0x5c, 0xf9, 0xfd, 0x3e, 0xfc, + 0x2b, 0x23, 0x2d, 0x3c, 0x7f, 0x8a, 0xbf, 0x16, 0x75, 0x81, 0xe1, 0x19, 0xb4, 0x46, 0x2b, 0x08, 0x26, 0xf8, 0x7b, + 0x07, 0xea, 0xa5, 0x95, 0xf6, 0x09, 0x74, 0x2b, 0xd0, 0x83, 0x7a, 0xe8, 0xd3, 0xa4, 0x7d, 0x21, 0x51, 0xb7, 0xb7, + 0x3a, 0x8d, 0xfe, 0xa8, 0xe0, 0x72, 0x0a, 0x93, 0xc3, 0x0d, 0x7d, 0x5a, 0x85, 0xdb, 0xcf, 0xf0, 0xf4, 0x67, 0xa0, + 0xdc, 0x3a, 0x1c, 0x72, 0x10, 0x5b, 0xc0, 0xcd, 0x63, 0x15, 0x7e, 0x29, 0x4a, 0x19, 0x51, 0x1f, 0x4f, 0x0b, 0xd0, + 0xde, 0x05, 0xe8, 0x80, 0xa5, 0x41, 0xbc, 0x42, 0xf2, 0x9c, 0x8d, 0x00, 0x96, 0x1d, 0x58, 0xce, 0x32, 0x4e, 0x61, + 0x9e, 0xe5, 0xb5, 0x5a, 0x69, 0x67, 0x65, 0xe2, 0xd5, 0x2c, 0x03, 0x67, 0x81, 0x8b, 0xca, 0x67, 0x99, 0x56, 0x3d, + 0x55, 0x09, 0xfa, 0xbc, 0x92, 0x13, 0x5c, 0x09, 0x4e, 0x36, 0x20, 0xbf, 0x00, 0x49, 0x9a, 0x52, 0xd6, 0x94, 0xd7, + 0x97, 0x74, 0x43, 0x46, 0xcf, 0x79, 0xcf, 0x8b, 0x86, 0xa1, 0x7f, 0xe1, 0x95, 0x10, 0xbe, 0x89, 0xdb, 0x36, 0x4a, + 0x61, 0x7f, 0x11, 0x58, 0x7c, 0xc2, 0x7e, 0xf4, 0x96, 0xfe, 0x74, 0x1c, 0x84, 0x43, 0xe4, 0x86, 0x8a, 0x39, 0xb0, + 0xa7, 0x01, 0x8b, 0x4d, 0x7c, 0xb5, 0x99, 0xc4, 0x83, 0x81, 0xaf, 0x33, 0x16, 0xb3, 0x18, 0x68, 0x90, 0xe3, 0xc1, + 0xe5, 0x5c, 0x9f, 0x10, 0xfa, 0x61, 0x44, 0xe5, 0xa8, 0x40, 0xe7, 0x20, 0x1a, 0x2c, 0x01, 0x4f, 0xbd, 0x95, 0x0d, + 0x92, 0x8c, 0x49, 0x26, 0x71, 0xad, 0x49, 0xaa, 0xc3, 0x09, 0xad, 0x03, 0x1d, 0x57, 0x17, 0xd0, 0xf9, 0xb8, 0xee, + 0x7d, 0xbc, 0x1a, 0x2e, 0xa8, 0xf4, 0x0b, 0x31, 0xf0, 0xea, 0xe9, 0x38, 0xb8, 0xa4, 0x5b, 0xe1, 0x62, 0x15, 0x6e, + 0x7f, 0x96, 0x0f, 0x1c, 0x77, 0x54, 0xd2, 0x10, 0x18, 0xbc, 0x3d, 0x74, 0x37, 0x33, 0x34, 0xd4, 0x49, 0xfb, 0x30, + 0x0e, 0xe5, 0x10, 0xab, 0x56, 0x5c, 0x48, 0x6f, 0x04, 0xdf, 0x2e, 0x14, 0x63, 0xd9, 0xd8, 0xa5, 0xa1, 0x28, 0xfc, + 0x15, 0xc0, 0x0e, 0xb5, 0xbf, 0x52, 0xc9, 0xc7, 0xc8, 0xa8, 0xa6, 0x81, 0x8e, 0x01, 0x58, 0xb2, 0x34, 0x91, 0x54, + 0x91, 0x46, 0xe2, 0x8f, 0xcc, 0x58, 0x47, 0x4d, 0xd7, 0x17, 0x4c, 0x55, 0x8b, 0xa4, 0xdb, 0x99, 0xc4, 0x72, 0x22, + 0x49, 0x6d, 0xf7, 0x11, 0x31, 0x18, 0xf8, 0x60, 0x23, 0xa6, 0x99, 0x08, 0x47, 0x3c, 0x2a, 0x91, 0x45, 0x97, 0xdf, + 0x46, 0x99, 0xb4, 0x7d, 0x59, 0x91, 0x2d, 0x08, 0xa6, 0x27, 0xd1, 0x07, 0x49, 0xca, 0xa9, 0x48, 0xa4, 0x19, 0x21, + 0xc0, 0x8f, 0x27, 0xe5, 0x95, 0xfe, 0x1c, 0x34, 0xad, 0x04, 0x2f, 0x19, 0x24, 0x8f, 0xc4, 0xcf, 0xa4, 0x60, 0x16, + 0x63, 0xd5, 0x60, 0x80, 0xe5, 0x54, 0xcf, 0x1c, 0x93, 0xf4, 0x5f, 0x3a, 0x9d, 0xb0, 0x5f, 0x78, 0xb9, 0xad, 0xe5, + 0x4d, 0x73, 0xef, 0x85, 0x57, 0xb1, 0x54, 0xc3, 0x32, 0xe8, 0xbf, 0x26, 0xda, 0x05, 0x5b, 0x5b, 0xc6, 0x84, 0x55, + 0x3f, 0x80, 0xb4, 0x47, 0xba, 0xbc, 0x6a, 0x98, 0x33, 0xc1, 0xa3, 0x0b, 0x6b, 0x1e, 0x44, 0x17, 0xc2, 0x47, 0x2e, + 0xbb, 0x49, 0x72, 0x35, 0x9e, 0xf8, 0xe1, 0x60, 0xa0, 0x00, 0x68, 0x69, 0x9d, 0x14, 0x83, 0xf0, 0x99, 0x90, 0x03, + 0x69, 0x74, 0x54, 0x05, 0x58, 0x2c, 0xb3, 0xab, 0x72, 0x92, 0x0d, 0x06, 0x3e, 0x88, 0x8d, 0x89, 0xdd, 0xd0, 0x6c, + 0xee, 0xb3, 0x13, 0x05, 0x59, 0x6d, 0x0e, 0x5b, 0x33, 0xdd, 0x02, 0x03, 0x80, 0x41, 0x44, 0xb0, 0xdc, 0xe7, 0x46, + 0x3e, 0xa2, 0x4e, 0x4f, 0x61, 0x04, 0x04, 0xbf, 0x9c, 0x08, 0x44, 0x2e, 0x12, 0xa8, 0x07, 0x98, 0x09, 0x30, 0xa3, + 0x8a, 0xe1, 0x25, 0xb0, 0x8b, 0xe7, 0xe6, 0x15, 0x83, 0xfe, 0x45, 0x93, 0x2c, 0xd1, 0x54, 0xe2, 0x68, 0x8c, 0x9c, + 0x4a, 0x63, 0x64, 0x40, 0xec, 0xe2, 0xf8, 0xf7, 0x94, 0x1e, 0x05, 0x29, 0xfb, 0x52, 0x19, 0xe2, 0x70, 0x14, 0x5f, + 0xc1, 0xaa, 0x71, 0x38, 0xd4, 0xe6, 0xf5, 0x74, 0x56, 0xcf, 0x07, 0x22, 0x80, 0xff, 0x86, 0x82, 0xfd, 0xa2, 0xa9, + 0xc8, 0x0d, 0x52, 0xe7, 0xe1, 0x90, 0x82, 0x7c, 0xaa, 0x9b, 0xfc, 0xb2, 0x72, 0xf7, 0xd3, 0xd9, 0xdc, 0x9a, 0xa3, + 0x17, 0x35, 0xae, 0x5b, 0xab, 0x1b, 0x0a, 0x89, 0xd6, 0x34, 0x29, 0xae, 0xaa, 0x49, 0x31, 0xe0, 0xb9, 0x2f, 0x54, + 0x17, 0x5b, 0x23, 0x58, 0xf8, 0x73, 0x0b, 0x84, 0xc9, 0xb8, 0x17, 0x1f, 0x2d, 0xe4, 0x94, 0x76, 0x6d, 0xb5, 0xdb, + 0x56, 0x36, 0xa4, 0x68, 0x3e, 0xbc, 0x84, 0x5d, 0x3a, 0x45, 0xb4, 0xed, 0x92, 0xe0, 0x0b, 0xd0, 0xb2, 0xba, 0x10, + 0x79, 0x4c, 0xbf, 0x42, 0x7e, 0x29, 0x86, 0xff, 0x29, 0xdd, 0x9b, 0x53, 0x1b, 0xe4, 0x00, 0xb6, 0x7b, 0x0f, 0xb7, + 0x63, 0xf4, 0x40, 0x06, 0x6f, 0x84, 0x9c, 0x73, 0x7e, 0x39, 0xb5, 0x66, 0x4c, 0x34, 0x2c, 0x58, 0x39, 0x8c, 0xfc, + 0x00, 0x19, 0x2f, 0xa7, 0xc0, 0xca, 0x7e, 0x54, 0xc4, 0xa5, 0x3f, 0x8c, 0xfc, 0x8b, 0xe7, 0x41, 0xc6, 0xbd, 0x68, + 0xd8, 0xf1, 0x05, 0xd8, 0xab, 0x2f, 0x9e, 0xb3, 0x68, 0xc0, 0xab, 0xab, 0x7a, 0x9a, 0x05, 0xc3, 0x8c, 0x45, 0x57, + 0xc5, 0x10, 0x7c, 0x68, 0xaf, 0xcb, 0x41, 0xe8, 0xfb, 0x66, 0xe7, 0xd0, 0xdd, 0x90, 0xc8, 0x23, 0xec, 0x27, 0x70, + 0xdb, 0xd5, 0x12, 0x33, 0x98, 0x6c, 0xee, 0x22, 0x66, 0xb0, 0xe5, 0x2f, 0x9e, 0x1b, 0x2e, 0xa1, 0xea, 0x5a, 0x6a, + 0x36, 0x0a, 0x34, 0x27, 0x57, 0x68, 0x4e, 0x56, 0x42, 0x2d, 0xf9, 0xa4, 0xc2, 0x09, 0x3b, 0x9f, 0xe4, 0xca, 0x6e, + 0x34, 0xc6, 0xc0, 0x45, 0x7b, 0x6e, 0x0b, 0x23, 0x33, 0x9d, 0xa5, 0x68, 0xc0, 0xc2, 0x33, 0x71, 0x4a, 0x63, 0x40, + 0xfb, 0x72, 0x60, 0x69, 0x43, 0x7e, 0x92, 0x33, 0x03, 0x6d, 0x43, 0x4a, 0xa3, 0x66, 0xe0, 0xcf, 0xd4, 0x84, 0xf9, + 0x15, 0xac, 0x44, 0x10, 0xd5, 0x05, 0x98, 0x24, 0x39, 0x19, 0x8d, 0x94, 0x95, 0x48, 0xce, 0x01, 0xef, 0x13, 0x78, + 0xb2, 0x88, 0x6d, 0xed, 0x4f, 0xe9, 0x7f, 0x75, 0xf8, 0x5c, 0xfa, 0xcf, 0x04, 0xb0, 0x90, 0x4b, 0x83, 0xc8, 0x40, + 0xe1, 0x90, 0x9a, 0x4a, 0xc4, 0x89, 0xe3, 0x19, 0xf8, 0x06, 0x2e, 0xd0, 0x14, 0xd0, 0x1f, 0xd4, 0x8c, 0x22, 0xb2, + 0xf0, 0x57, 0xcf, 0x6e, 0xea, 0x46, 0xcf, 0x33, 0xe7, 0x35, 0x68, 0x66, 0x20, 0xa4, 0xc7, 0xa9, 0x7a, 0x1b, 0x12, + 0x9d, 0x97, 0x97, 0xfa, 0x65, 0x42, 0x24, 0x2b, 0x22, 0x4f, 0xdf, 0xe7, 0x60, 0x1e, 0x51, 0x84, 0x0e, 0xae, 0xcc, + 0xc3, 0xe1, 0x5c, 0x50, 0xf8, 0x8e, 0xf2, 0x7c, 0xc0, 0x69, 0x16, 0x25, 0xa0, 0x0d, 0x64, 0xb9, 0x29, 0x73, 0x9d, + 0xb4, 0x4c, 0xdd, 0x7b, 0xb0, 0x12, 0x54, 0xe8, 0xe6, 0x14, 0x14, 0xca, 0x48, 0x50, 0x4a, 0xab, 0x41, 0x28, 0xd5, + 0x61, 0x11, 0x44, 0x0e, 0x59, 0x08, 0xb8, 0x99, 0x8a, 0x46, 0x4b, 0x1a, 0x1e, 0xe1, 0xdc, 0x40, 0x21, 0x00, 0x89, + 0x3d, 0x55, 0x94, 0x71, 0x39, 0x04, 0x7c, 0x94, 0x70, 0x88, 0xb3, 0x26, 0x6d, 0x79, 0x0e, 0xe2, 0x58, 0x2e, 0xf9, + 0xba, 0x42, 0x30, 0x88, 0xd0, 0x67, 0xc8, 0x9f, 0x2c, 0xe7, 0xdf, 0xad, 0xc3, 0xb4, 0x23, 0x7c, 0xd8, 0xd5, 0x16, + 0x5c, 0xcc, 0x6e, 0xe7, 0x13, 0x88, 0x6f, 0xb9, 0x9d, 0x1f, 0x63, 0x88, 0x2c, 0xfc, 0xc1, 0xdd, 0x50, 0x72, 0x45, + 0xa1, 0xcb, 0x7a, 0x44, 0x8a, 0xec, 0xe9, 0x9a, 0x23, 0x08, 0x0e, 0xb4, 0x6a, 0x90, 0xa1, 0x91, 0xf8, 0xe2, 0x39, + 0x64, 0x0d, 0xd6, 0xfc, 0x4b, 0x45, 0xce, 0xea, 0xfe, 0x64, 0x03, 0xd5, 0x24, 0x93, 0xb5, 0xa2, 0x72, 0xfe, 0x76, + 0x55, 0x96, 0x27, 0xab, 0x32, 0x5c, 0x0d, 0xba, 0xaa, 0xb2, 0xe4, 0x48, 0x6d, 0x80, 0xd6, 0x74, 0x85, 0x18, 0x0a, + 0x59, 0x83, 0xa5, 0x55, 0x95, 0x35, 0xf5, 0x09, 0x04, 0xfa, 0x00, 0xcb, 0xa8, 0xd9, 0x4f, 0x87, 0xff, 0x0c, 0xfe, + 0xa9, 0x42, 0x96, 0xea, 0xb4, 0xce, 0xc4, 0xaf, 0xc1, 0x92, 0xe1, 0x1f, 0xbf, 0x05, 0x6b, 0xc0, 0x12, 0x20, 0xcb, + 0xdd, 0xc6, 0x46, 0xeb, 0x95, 0x57, 0x88, 0xaf, 0xb5, 0xbe, 0xe8, 0xb7, 0x6e, 0x13, 0xb5, 0x02, 0x8c, 0x50, 0x68, + 0x11, 0x60, 0xab, 0x07, 0xee, 0x29, 0xf8, 0x81, 0x18, 0xce, 0x35, 0x69, 0x4d, 0x9d, 0xf0, 0x3a, 0x1b, 0x47, 0x22, + 0xaa, 0xb7, 0x70, 0x71, 0xaf, 0xb7, 0x16, 0x7f, 0xa3, 0x02, 0x01, 0x90, 0xc5, 0x14, 0x6b, 0xe7, 0x0d, 0xe9, 0x95, + 0x61, 0x27, 0xa1, 0xf7, 0x86, 0x9d, 0x40, 0x5e, 0x1c, 0x76, 0x0a, 0x5d, 0xa2, 0xed, 0x14, 0xa9, 0x89, 0xb6, 0x93, + 0x16, 0xab, 0xb0, 0x84, 0xe0, 0x57, 0xed, 0xad, 0xa3, 0x6c, 0x5f, 0x64, 0x09, 0xd3, 0x16, 0x30, 0xca, 0xad, 0xfa, + 0xcc, 0x29, 0x62, 0xa5, 0xec, 0x9d, 0x4e, 0xaa, 0xdc, 0x45, 0x3e, 0xb7, 0x9a, 0x22, 0x93, 0x5f, 0x1e, 0xb7, 0x48, + 0x3e, 0xf9, 0xb9, 0xdd, 0x30, 0x99, 0xfe, 0xe9, 0xe8, 0x0b, 0xe8, 0x8a, 0xec, 0xf4, 0x09, 0x04, 0x64, 0x2a, 0xa8, + 0x56, 0xb7, 0x8a, 0x69, 0xde, 0xae, 0xb2, 0xdb, 0x0b, 0x25, 0x86, 0xd3, 0xd9, 0x49, 0x78, 0xb4, 0x19, 0x32, 0x70, + 0x08, 0x02, 0x85, 0x50, 0x51, 0x0c, 0x8f, 0x40, 0xad, 0x91, 0x7c, 0x80, 0x1f, 0xed, 0x4e, 0x05, 0x91, 0xda, 0x4d, + 0xc5, 0x8d, 0x93, 0x9b, 0xae, 0x97, 0x02, 0xb5, 0x4e, 0xc9, 0x0a, 0xa0, 0x84, 0xa8, 0x3f, 0x8b, 0x6d, 0xfd, 0x0a, + 0xae, 0xd8, 0x7c, 0xdf, 0x28, 0x7a, 0x72, 0x7d, 0x8a, 0xba, 0x15, 0x57, 0xa7, 0x69, 0xab, 0x39, 0x76, 0x9c, 0x21, + 0x07, 0xcf, 0x0a, 0x82, 0xed, 0xa8, 0x44, 0xf9, 0xae, 0xdd, 0x74, 0x4c, 0x6c, 0xf5, 0xcf, 0xa2, 0xda, 0xdc, 0x41, + 0x45, 0x44, 0x7c, 0x94, 0xdd, 0x3c, 0x69, 0xbf, 0x83, 0x3d, 0xd6, 0x6a, 0x10, 0xd9, 0x67, 0x70, 0x95, 0xeb, 0xb4, + 0xc8, 0x6d, 0x19, 0x9c, 0x7f, 0x78, 0xb5, 0xab, 0xb0, 0xc9, 0xb1, 0xae, 0xae, 0x66, 0xaa, 0x93, 0x8a, 0x0d, 0x8c, + 0x35, 0xad, 0xa5, 0x9a, 0xc7, 0x90, 0x74, 0x57, 0x16, 0x67, 0x55, 0xd2, 0x4d, 0xcf, 0x8d, 0x33, 0x85, 0x18, 0x38, + 0x5b, 0x8d, 0x96, 0x33, 0x0c, 0xd1, 0xf5, 0x61, 0x96, 0xf8, 0xad, 0x9e, 0x72, 0x9f, 0x87, 0x5b, 0xbf, 0xab, 0x17, + 0x9c, 0x4c, 0xf6, 0x93, 0xe3, 0xdc, 0xed, 0x22, 0xed, 0x27, 0xbe, 0x0d, 0xf3, 0xaf, 0x6f, 0x10, 0x77, 0xa2, 0xfe, + 0x47, 0x05, 0x40, 0x83, 0x9b, 0x3c, 0x96, 0x28, 0xf5, 0x7b, 0x55, 0xfd, 0xa0, 0x66, 0xaa, 0xa6, 0x81, 0x60, 0x4e, + 0xa5, 0x80, 0x3f, 0xdc, 0x2e, 0x5c, 0xf1, 0x88, 0x1b, 0x16, 0xc6, 0x3f, 0xbd, 0x9a, 0x9d, 0x0a, 0x2a, 0x03, 0x37, + 0xe3, 0x3f, 0x3d, 0xc1, 0x4e, 0x61, 0xad, 0x80, 0xac, 0xf0, 0xa7, 0x97, 0x3f, 0xf2, 0x7e, 0xc5, 0xff, 0xf4, 0xaa, + 0x47, 0xde, 0x47, 0x9c, 0x97, 0x3f, 0x91, 0xd4, 0x09, 0x51, 0x5d, 0xfe, 0x24, 0x4c, 0xb1, 0x55, 0x9a, 0xbf, 0x26, + 0x85, 0x4f, 0xf0, 0x05, 0xf8, 0x0e, 0x57, 0xe1, 0xd6, 0xfc, 0x06, 0x8f, 0x1d, 0x8b, 0x6d, 0x97, 0xfa, 0x02, 0xca, + 0x11, 0x58, 0x44, 0x6e, 0xbf, 0x5d, 0xd9, 0xaf, 0x16, 0x46, 0x19, 0x63, 0xf7, 0x25, 0x2b, 0x51, 0x3a, 0xeb, 0xf7, + 0x0b, 0x29, 0x18, 0xd9, 0x85, 0x35, 0xda, 0xa3, 0x54, 0xbd, 0xfa, 0x2e, 0xac, 0xa3, 0x24, 0xcd, 0xef, 0x64, 0xf4, + 0x91, 0x0c, 0x3b, 0xd2, 0x57, 0x52, 0xa2, 0xbd, 0x56, 0x61, 0x39, 0x9a, 0xfd, 0xba, 0xe4, 0x40, 0x79, 0xdd, 0x0a, + 0xca, 0x57, 0x4d, 0x00, 0xbd, 0x52, 0xed, 0x33, 0xd0, 0x0a, 0x0a, 0x4b, 0xe5, 0xc1, 0x4a, 0x9c, 0x8b, 0x3e, 0x2b, + 0x0e, 0x07, 0x75, 0x31, 0x24, 0x14, 0xa8, 0x12, 0x27, 0xa1, 0x11, 0xcf, 0xe1, 0x42, 0x28, 0xae, 0x73, 0x8c, 0xad, + 0xc8, 0x81, 0x03, 0x19, 0x7e, 0x40, 0xe0, 0xbd, 0xec, 0x5f, 0xc1, 0x60, 0x98, 0xe0, 0x46, 0x46, 0x9d, 0x9c, 0xb3, + 0x3f, 0x31, 0x30, 0x83, 0x7a, 0x52, 0xbb, 0xcf, 0xee, 0x55, 0x60, 0x2f, 0x9c, 0x01, 0xed, 0xdd, 0x18, 0xfd, 0xac, + 0x8a, 0xb5, 0x93, 0xfe, 0xb9, 0x58, 0x43, 0x32, 0x1d, 0x16, 0x47, 0xdb, 0x34, 0x3c, 0x92, 0x27, 0xc7, 0xf1, 0xa6, + 0x7f, 0x38, 0x8c, 0xf1, 0xe3, 0x28, 0xbf, 0xb6, 0x80, 0x57, 0x71, 0x0b, 0x69, 0x2c, 0x52, 0xf4, 0x0e, 0xc4, 0x1c, + 0x8a, 0x5e, 0xb2, 0xdf, 0x32, 0x5e, 0x4e, 0x04, 0xa5, 0x24, 0xb1, 0xe1, 0x1d, 0xe9, 0x69, 0x5a, 0x8f, 0xb6, 0x32, + 0x60, 0xbf, 0x1e, 0xed, 0xe8, 0x2f, 0x50, 0x3c, 0x5a, 0xf8, 0x4b, 0xfa, 0xbb, 0xb8, 0x9b, 0x7b, 0xce, 0x37, 0x8d, + 0xef, 0x88, 0x0b, 0x14, 0x6b, 0x76, 0x7f, 0x4d, 0x4b, 0x67, 0x1d, 0x08, 0x0e, 0x78, 0x8b, 0x5d, 0xb4, 0xef, 0x37, + 0xae, 0xd3, 0xd3, 0xfe, 0x7b, 0xb7, 0x46, 0xf9, 0xde, 0x3f, 0x24, 0xca, 0xc1, 0xfe, 0xb5, 0x8b, 0xe6, 0x6f, 0x3f, + 0x65, 0x48, 0x2a, 0x34, 0x37, 0xd8, 0x4e, 0xb6, 0x08, 0x6b, 0x63, 0x1c, 0x54, 0xec, 0xae, 0x0c, 0x23, 0x60, 0x50, + 0xc7, 0xfe, 0x47, 0x9f, 0x4d, 0x1b, 0xb2, 0x0f, 0x00, 0x95, 0xab, 0x10, 0xb0, 0x07, 0xe0, 0x44, 0x23, 0xdc, 0x00, + 0xb7, 0x1a, 0x2d, 0xe9, 0xa0, 0x6e, 0x0b, 0x06, 0xa2, 0x25, 0x6c, 0xe4, 0x6d, 0x57, 0xa7, 0x6f, 0x08, 0x1f, 0x6a, + 0x27, 0xa5, 0x43, 0xf9, 0x9b, 0xe7, 0xec, 0xbf, 0x77, 0x58, 0x53, 0x53, 0x6e, 0x00, 0x33, 0x67, 0x25, 0xf2, 0x0a, + 0xa1, 0x53, 0xe4, 0xf7, 0xaa, 0xae, 0xc4, 0x70, 0x59, 0x8b, 0xb2, 0x33, 0xbb, 0x75, 0xa2, 0x77, 0x4e, 0x41, 0x2d, + 0x95, 0x0d, 0x72, 0x92, 0x6a, 0xf3, 0x91, 0xb5, 0x82, 0x12, 0x75, 0x8d, 0x02, 0xc7, 0xa7, 0x5c, 0xbb, 0xff, 0x77, + 0xce, 0x04, 0x35, 0xdb, 0xa8, 0xee, 0xaf, 0xf5, 0x53, 0x55, 0x93, 0x58, 0x80, 0xcb, 0x49, 0x9a, 0x77, 0x3c, 0xc2, + 0xea, 0x1f, 0x27, 0x4b, 0x11, 0xe8, 0x75, 0x44, 0xbb, 0x12, 0x90, 0xa0, 0x9d, 0x9c, 0x85, 0x8a, 0x40, 0x81, 0xbe, + 0xfe, 0x72, 0x93, 0x66, 0xb1, 0x5c, 0xcd, 0xf6, 0x30, 0x51, 0x16, 0xeb, 0x21, 0x82, 0x9c, 0x99, 0x3a, 0xd8, 0xef, + 0x69, 0x46, 0xb3, 0xf0, 0xca, 0x94, 0xe0, 0x52, 0x5c, 0x45, 0x45, 0x0e, 0x3e, 0x87, 0xf8, 0xc2, 0xe7, 0x42, 0x6e, + 0x10, 0xd1, 0xf4, 0xa5, 0x44, 0xb5, 0x23, 0x05, 0x72, 0x28, 0xf9, 0x09, 0xf1, 0x97, 0xac, 0x8d, 0x71, 0xbf, 0x74, + 0xaa, 0xfd, 0x4a, 0x21, 0xb8, 0xff, 0x6c, 0x8b, 0x8d, 0x2a, 0x4f, 0xf4, 0xe8, 0x53, 0xac, 0xff, 0xc9, 0x02, 0x4a, + 0x75, 0xdf, 0x06, 0xa7, 0xe2, 0x51, 0xb8, 0xa9, 0x8b, 0x1b, 0x84, 0x16, 0x28, 0x47, 0x55, 0xb1, 0x29, 0x23, 0xe2, + 0x84, 0xdd, 0xd4, 0x45, 0x4f, 0x73, 0xa0, 0x53, 0x87, 0xa5, 0x89, 0x3c, 0x11, 0xda, 0x2d, 0xe8, 0x9e, 0xe6, 0x58, + 0x89, 0x17, 0xb2, 0x74, 0x90, 0x75, 0x22, 0x4d, 0xa8, 0xdc, 0xd5, 0x55, 0x47, 0xa5, 0x52, 0x37, 0xbc, 0x49, 0x35, + 0xe3, 0xef, 0xd2, 0xfc, 0x89, 0x65, 0xbf, 0x69, 0xfd, 0x56, 0xab, 0xbd, 0xb1, 0x7a, 0x54, 0xb2, 0xe6, 0x38, 0x9b, + 0x90, 0x94, 0x3e, 0x61, 0xbb, 0x99, 0x74, 0xad, 0x03, 0x4f, 0x82, 0xcb, 0xa1, 0x27, 0xa0, 0x62, 0xd0, 0xc4, 0xdb, + 0x5d, 0xa0, 0x1e, 0x81, 0x67, 0xa0, 0x7c, 0xa2, 0xd6, 0x01, 0x3f, 0xaf, 0xb5, 0x3c, 0x65, 0x84, 0x61, 0xb5, 0xb3, + 0x68, 0x39, 0x38, 0xef, 0x14, 0x81, 0x6b, 0x57, 0x02, 0xcf, 0x87, 0xea, 0xbd, 0x10, 0x30, 0xdc, 0x3f, 0x17, 0x2a, + 0x9b, 0xdd, 0x0c, 0xe7, 0x51, 0xe3, 0xf4, 0x40, 0x7b, 0xdb, 0xb5, 0x1e, 0xea, 0x5d, 0xb7, 0x73, 0x5b, 0xe9, 0xde, + 0xaf, 0x9d, 0x4c, 0xba, 0x80, 0xd6, 0xe6, 0xb3, 0xef, 0xec, 0x4a, 0xeb, 0xa6, 0xe7, 0xec, 0xc1, 0xd6, 0x2d, 0xd1, + 0xb9, 0x20, 0x9a, 0xfc, 0x7e, 0xe0, 0x59, 0xdb, 0x8e, 0x7e, 0x9b, 0x76, 0x6c, 0x73, 0x0f, 0x75, 0xaf, 0xa0, 0xd6, + 0x1b, 0x9a, 0xf7, 0xcf, 0x5c, 0xdb, 0x8e, 0xaf, 0x7e, 0x5d, 0x77, 0xb8, 0xce, 0x9b, 0xe0, 0xb8, 0xe9, 0xda, 0x56, + 0x3b, 0xfb, 0xb9, 0xbb, 0xb7, 0x16, 0x51, 0x98, 0x65, 0x3f, 0x15, 0xc5, 0x1f, 0x95, 0xbe, 0x23, 0xd0, 0xd1, 0x9d, + 0x17, 0x75, 0xba, 0xdc, 0x7d, 0x24, 0x8c, 0x27, 0xaf, 0x3e, 0x22, 0xba, 0xf5, 0x7d, 0xe6, 0x7e, 0x05, 0xb8, 0x11, + 0xdc, 0x41, 0xb4, 0x77, 0x4b, 0x7d, 0x52, 0xab, 0xaf, 0xf5, 0xda, 0x79, 0x7a, 0x7e, 0xd3, 0xb9, 0xfd, 0xee, 0x9b, + 0xa3, 0xad, 0xf7, 0xb8, 0xb0, 0x56, 0x96, 0x9e, 0xaa, 0x82, 0xbd, 0x59, 0x9e, 0xaa, 0x82, 0xc9, 0x03, 0xaf, 0xd9, + 0x2f, 0x68, 0x70, 0xa5, 0xa3, 0x8d, 0xf7, 0x44, 0x0d, 0xdc, 0xa2, 0xb0, 0x74, 0xf8, 0x25, 0x37, 0x93, 0x57, 0xb8, + 0xbf, 0x54, 0xe4, 0x62, 0xdf, 0x39, 0xa3, 0x3b, 0x33, 0xeb, 0x5e, 0x55, 0xb8, 0x5a, 0x90, 0xab, 0x03, 0x5b, 0xcb, + 0x2e, 0x0e, 0x37, 0x2c, 0xa2, 0x00, 0x81, 0x98, 0x5e, 0xa9, 0xb5, 0x3f, 0xa2, 0x41, 0xc8, 0x07, 0x03, 0xbf, 0xc0, + 0x60, 0x55, 0xa0, 0xf0, 0x81, 0x22, 0xf9, 0x6b, 0x4f, 0xc0, 0x2e, 0x9e, 0x01, 0xba, 0x15, 0x9b, 0x15, 0x23, 0x44, + 0xc8, 0x64, 0x39, 0xab, 0xe9, 0x0c, 0xf2, 0xa9, 0x2f, 0xbe, 0xb3, 0x55, 0xa7, 0xf3, 0xb6, 0xa6, 0xca, 0xa9, 0x43, + 0xa1, 0xbb, 0x9b, 0xba, 0x73, 0xeb, 0x22, 0x4f, 0x1d, 0x42, 0xae, 0x54, 0xac, 0xc4, 0x34, 0xd4, 0x3c, 0x49, 0x33, + 0xea, 0x2f, 0xf6, 0x7e, 0xaf, 0x51, 0x38, 0xe5, 0x4f, 0xc7, 0xa0, 0x0a, 0x57, 0x35, 0xc4, 0xb1, 0x54, 0xc5, 0x23, + 0x1b, 0x04, 0x9a, 0x57, 0xb7, 0x2a, 0x69, 0x42, 0x26, 0x37, 0xc2, 0xa7, 0x26, 0xa5, 0x3c, 0x4d, 0x9b, 0xb4, 0x52, + 0xa4, 0x0e, 0x3e, 0xa8, 0x53, 0x8d, 0xe7, 0x66, 0x75, 0x0d, 0x60, 0xc6, 0xf9, 0x15, 0xbf, 0x54, 0x5c, 0x46, 0x6d, + 0x65, 0x26, 0xed, 0x4f, 0x8e, 0xc6, 0x46, 0x5d, 0x4e, 0x1b, 0x65, 0x84, 0x95, 0xd2, 0x9c, 0x14, 0xcb, 0xf1, 0xfc, + 0x03, 0x06, 0x6b, 0x9e, 0xc0, 0x0e, 0x26, 0x2a, 0xe5, 0x7d, 0x04, 0xc4, 0xd7, 0x49, 0x7a, 0x97, 0x40, 0x8a, 0xf4, + 0x2f, 0x5d, 0xf2, 0xd4, 0x61, 0x6c, 0x20, 0xc6, 0xac, 0x98, 0x19, 0xfd, 0x0f, 0xee, 0x92, 0xfe, 0x24, 0x04, 0xc0, + 0x4d, 0x34, 0x85, 0x4e, 0x9d, 0x27, 0x17, 0x79, 0xb0, 0xbc, 0xf0, 0xd0, 0x8a, 0x11, 0x0f, 0xfe, 0xf3, 0x3a, 0x44, + 0x10, 0x73, 0x4c, 0xf1, 0xf4, 0x0b, 0xa3, 0xff, 0x08, 0x2e, 0x31, 0x82, 0xd0, 0xdd, 0x3b, 0x87, 0x21, 0xdc, 0xec, + 0x41, 0x06, 0xf5, 0x87, 0x3a, 0x24, 0x6a, 0xf8, 0x53, 0xe5, 0x41, 0xff, 0xd7, 0x99, 0xb0, 0xd4, 0x7e, 0x7a, 0x3a, + 0x80, 0x0a, 0xde, 0x57, 0xbc, 0x8d, 0x88, 0xef, 0x13, 0x3f, 0x8b, 0x07, 0x9b, 0x67, 0x1b, 0xb0, 0xd6, 0x3d, 0xc9, + 0x8d, 0x75, 0x95, 0xb0, 0x81, 0x80, 0xaf, 0x31, 0xad, 0x3d, 0xaf, 0xdd, 0xee, 0xc1, 0x7f, 0xfa, 0x17, 0x21, 0x03, + 0x26, 0x4e, 0xdf, 0x67, 0x4e, 0xd6, 0xe8, 0x22, 0x93, 0xe9, 0x43, 0x27, 0x7d, 0xa3, 0xd3, 0x7d, 0x27, 0xfc, 0xa3, + 0x62, 0x16, 0x1f, 0x6e, 0xe9, 0x2b, 0x4d, 0x8a, 0x3b, 0x60, 0x65, 0xf3, 0xa8, 0x20, 0xd4, 0xb9, 0x88, 0xbe, 0x31, + 0xe5, 0x5b, 0x42, 0xcd, 0xbe, 0xb1, 0xa4, 0x94, 0xee, 0x35, 0xf4, 0x26, 0xad, 0xf5, 0xdb, 0x28, 0xc1, 0x98, 0xe8, + 0x78, 0xf2, 0x32, 0x1e, 0x2b, 0xef, 0xe3, 0x71, 0x23, 0x15, 0xf2, 0x00, 0x44, 0xa0, 0x62, 0xfc, 0xe9, 0xca, 0x93, + 0x93, 0x5e, 0x18, 0xaf, 0x42, 0x29, 0x28, 0x0c, 0xe8, 0x0a, 0xa4, 0x80, 0x47, 0xed, 0x89, 0xce, 0xc2, 0x2e, 0xe1, + 0x1e, 0xdd, 0x04, 0x8c, 0xf5, 0xf9, 0x27, 0x40, 0x73, 0x17, 0xee, 0xf0, 0x62, 0x80, 0xda, 0xd4, 0xab, 0xbb, 0x8f, + 0x6b, 0x75, 0x0e, 0x87, 0xe0, 0x60, 0x35, 0x88, 0xe0, 0x74, 0x3e, 0x75, 0x34, 0xcb, 0x02, 0x54, 0x4e, 0x96, 0x1b, + 0x79, 0xf3, 0x68, 0xd1, 0xab, 0xfb, 0xde, 0x32, 0x2d, 0xab, 0x3a, 0xc8, 0x58, 0x16, 0x56, 0x80, 0xab, 0x43, 0xeb, + 0x07, 0xe1, 0xb2, 0x70, 0xfe, 0x40, 0x08, 0x62, 0xf7, 0x6a, 0x5b, 0xf2, 0x5c, 0xcd, 0xe1, 0x67, 0xcf, 0xd9, 0x9a, + 0x4b, 0xd4, 0x49, 0x67, 0x22, 0x00, 0xb1, 0xa7, 0x66, 0x15, 0x5d, 0x03, 0x49, 0x9d, 0x66, 0x15, 0x5d, 0x53, 0xb3, + 0x8d, 0x71, 0x20, 0x1f, 0xad, 0x52, 0xc0, 0xbe, 0x9b, 0x8e, 0x83, 0xd5, 0xb3, 0x58, 0x5e, 0x87, 0xee, 0x9e, 0x6d, + 0x94, 0xcf, 0xa0, 0x6e, 0xb5, 0x31, 0x26, 0xb6, 0x9b, 0x2f, 0xe7, 0xfa, 0xed, 0x60, 0xe9, 0xdb, 0x41, 0x73, 0x4e, + 0xd9, 0x77, 0xba, 0xec, 0x95, 0x5d, 0x36, 0xf5, 0xdc, 0x51, 0xd1, 0x6a, 0x0c, 0xe8, 0x0d, 0x2c, 0x58, 0x9f, 0x8b, + 0x34, 0x5b, 0x95, 0xaa, 0x04, 0xbc, 0x30, 0x56, 0xec, 0xce, 0x6f, 0x64, 0x86, 0x24, 0xcc, 0xe3, 0x4c, 0xbc, 0xa3, + 0x7b, 0x2d, 0x4c, 0x8e, 0x63, 0x91, 0x4c, 0x09, 0x9d, 0xd2, 0x9d, 0x6d, 0xe8, 0x5c, 0x85, 0x51, 0x44, 0x6b, 0x25, + 0x95, 0x46, 0x02, 0x53, 0x33, 0x40, 0xc9, 0x5c, 0x81, 0x53, 0xba, 0xdc, 0xff, 0x8e, 0xc4, 0x38, 0xf3, 0x45, 0xc9, + 0x0c, 0xe8, 0x96, 0x5f, 0x17, 0xeb, 0x56, 0x8a, 0x8c, 0x30, 0x6f, 0x8e, 0xdb, 0xeb, 0xfa, 0x10, 0xc8, 0xd5, 0xb2, + 0x47, 0xd1, 0x38, 0x28, 0x74, 0xb8, 0x54, 0x09, 0xb0, 0x2f, 0x12, 0x3f, 0x23, 0x6c, 0x69, 0x0f, 0xe4, 0xf6, 0xe8, + 0x4c, 0x98, 0x73, 0x4e, 0xca, 0xb2, 0x73, 0x69, 0x06, 0x97, 0x13, 0x57, 0x82, 0x8b, 0xf4, 0xb6, 0x3d, 0x4d, 0x5a, + 0xda, 0x3e, 0x36, 0x9c, 0xa3, 0xa1, 0x6d, 0xd0, 0x1d, 0xfb, 0x43, 0x73, 0xb1, 0x88, 0xad, 0x8b, 0xc5, 0xb0, 0x33, + 0xfb, 0xd1, 0x62, 0x01, 0x72, 0x00, 0x38, 0xea, 0x36, 0x7c, 0xcc, 0x96, 0xc0, 0x69, 0x35, 0xcd, 0xa6, 0xde, 0x86, + 0x57, 0xcf, 0x54, 0x4f, 0x2f, 0x79, 0xfe, 0x4c, 0x98, 0xb1, 0xd8, 0xf0, 0xfc, 0x99, 0x75, 0xe4, 0x54, 0xcf, 0x84, + 0x12, 0xad, 0x0b, 0x68, 0x06, 0x5e, 0x53, 0xc0, 0x88, 0x25, 0x93, 0x29, 0x55, 0xe4, 0x71, 0x6f, 0xba, 0x51, 0x83, + 0x17, 0x14, 0x0e, 0x81, 0x94, 0x4e, 0xbf, 0x78, 0xce, 0xf4, 0x7b, 0x17, 0xcf, 0x3b, 0x64, 0x6d, 0xc3, 0x74, 0xb9, + 0x19, 0x26, 0x83, 0xd2, 0x7f, 0x66, 0x26, 0xc6, 0x85, 0x35, 0x49, 0x00, 0xf1, 0x6f, 0xec, 0x77, 0x48, 0xe1, 0xe6, + 0xfd, 0xe5, 0x30, 0x7e, 0xe4, 0xfd, 0x18, 0xd9, 0x93, 0x34, 0x43, 0xac, 0x99, 0x54, 0xc8, 0xdd, 0x57, 0xeb, 0x1f, + 0x13, 0xbb, 0xc9, 0x1e, 0x58, 0x00, 0x62, 0x6b, 0xda, 0xea, 0x96, 0xf7, 0xfb, 0x9e, 0x29, 0x02, 0xfc, 0xa0, 0xfc, + 0xa3, 0x3b, 0x43, 0x32, 0x28, 0xbb, 0x6e, 0x08, 0xf1, 0xa0, 0x6c, 0x9a, 0xf6, 0x7a, 0xdb, 0x3b, 0xf3, 0x58, 0x5d, + 0xa7, 0x9d, 0xc5, 0xd5, 0x22, 0x83, 0xb4, 0xfa, 0x90, 0x1d, 0x67, 0xf6, 0xd9, 0xd1, 0x52, 0xe9, 0x7e, 0x1f, 0x22, + 0xe2, 0x8e, 0xb2, 0xb6, 0xdf, 0x6e, 0xc1, 0x35, 0x1c, 0x0d, 0x42, 0x57, 0xf6, 0x76, 0x19, 0x6d, 0x5c, 0x88, 0xe3, + 0x9e, 0xe9, 0x7c, 0xc1, 0x97, 0x47, 0x69, 0xe7, 0xc1, 0xa9, 0x9e, 0xe8, 0x73, 0xd3, 0x5d, 0x65, 0x72, 0xad, 0xc3, + 0x6a, 0x0c, 0x6a, 0xb3, 0xb0, 0x85, 0xbb, 0xb0, 0x8d, 0x0e, 0x5a, 0xfb, 0xb2, 0xe0, 0x9f, 0x32, 0x00, 0x5f, 0x7a, + 0xb6, 0x6c, 0x7b, 0x4d, 0x5a, 0xbd, 0x91, 0x51, 0x88, 0x2d, 0x6d, 0xaf, 0x3e, 0x1d, 0xe5, 0xe3, 0xe6, 0x84, 0xe2, + 0x42, 0x8e, 0xf2, 0xa3, 0xd7, 0x10, 0x75, 0xad, 0xeb, 0xb8, 0x58, 0x74, 0xb8, 0x71, 0xd5, 0x6d, 0x37, 0xae, 0x1f, + 0x11, 0x6f, 0x8d, 0x36, 0x29, 0xd4, 0xca, 0xd8, 0x11, 0xbc, 0x2c, 0x1f, 0x0e, 0x99, 0x18, 0x0e, 0x25, 0x64, 0xea, + 0x63, 0xf7, 0x86, 0xa6, 0x7d, 0x7e, 0xda, 0xfa, 0x11, 0x4b, 0x8d, 0xa3, 0xd8, 0xf0, 0x4e, 0xdf, 0x79, 0x6c, 0x8d, + 0x2b, 0xf9, 0x32, 0x98, 0xed, 0x0a, 0xaa, 0xad, 0xf1, 0x86, 0xbd, 0x9c, 0xbf, 0xac, 0xa4, 0x92, 0xbf, 0xfd, 0x19, + 0xae, 0xe1, 0xad, 0x2d, 0x1d, 0x34, 0xd5, 0x2c, 0x67, 0xb9, 0xbe, 0x17, 0x1c, 0x7f, 0xdc, 0xbd, 0x22, 0x18, 0xfc, + 0x9e, 0x8e, 0x82, 0x5c, 0x2c, 0xd5, 0x1a, 0x50, 0x90, 0x8e, 0xec, 0x98, 0xca, 0x02, 0xc3, 0x00, 0xde, 0x90, 0x01, + 0xf2, 0x98, 0xc2, 0xdd, 0x50, 0xe1, 0x85, 0xbf, 0x54, 0x64, 0x97, 0xc0, 0xb6, 0x66, 0x7c, 0xcc, 0x70, 0x07, 0x21, + 0xff, 0x08, 0x76, 0xc7, 0x56, 0xec, 0x96, 0x2d, 0x18, 0x92, 0x8d, 0xe3, 0x30, 0xc6, 0x7c, 0x3c, 0x89, 0xaf, 0xc4, + 0x24, 0x1e, 0xf0, 0x08, 0x1d, 0x23, 0xd6, 0xbc, 0x9e, 0xc5, 0x72, 0x00, 0xd9, 0x1d, 0x57, 0x3a, 0x20, 0x84, 0xc6, + 0x86, 0x96, 0xbc, 0x29, 0x0c, 0x2e, 0x76, 0xec, 0x33, 0x12, 0xc9, 0x38, 0x04, 0x8b, 0x56, 0x35, 0xb0, 0x30, 0xb1, + 0x5b, 0x5e, 0xcc, 0x56, 0x73, 0xfc, 0xe7, 0x70, 0x40, 0x00, 0xec, 0x60, 0xdf, 0xb0, 0xbb, 0x08, 0x91, 0xde, 0x16, + 0xfc, 0xce, 0xf2, 0x74, 0x61, 0xf7, 0xfc, 0x1d, 0x1f, 0xb3, 0xf3, 0x1f, 0x3d, 0x88, 0x9c, 0x3d, 0xff, 0x04, 0x68, + 0x88, 0xf7, 0xfc, 0x36, 0xf5, 0x2a, 0x76, 0x4b, 0x14, 0x84, 0xb7, 0xe0, 0x0c, 0x74, 0x0f, 0x11, 0xb0, 0xef, 0xf8, + 0x02, 0x63, 0xc5, 0xce, 0xd2, 0xa5, 0x87, 0x19, 0xa1, 0xf6, 0x74, 0xbe, 0xac, 0xd5, 0x24, 0xdc, 0x5c, 0x2d, 0x27, + 0x83, 0xc1, 0xc6, 0xdf, 0xf1, 0x35, 0xf0, 0xc1, 0x9c, 0xff, 0xe8, 0xed, 0xa8, 0x5c, 0xf8, 0xcf, 0xeb, 0x2c, 0x79, + 0xe7, 0xb3, 0x77, 0x03, 0xbe, 0x00, 0xbc, 0x25, 0x74, 0xe0, 0xba, 0xf7, 0x99, 0xc4, 0x6b, 0x7b, 0xa7, 0xaf, 0x11, + 0x48, 0xe4, 0x0b, 0xc0, 0x88, 0x89, 0xf9, 0xfd, 0x0e, 0x22, 0x30, 0x12, 0xf0, 0x6d, 0xd5, 0x1e, 0xf1, 0x5b, 0x6e, + 0x00, 0xbf, 0x32, 0x9f, 0x3d, 0xf0, 0x50, 0xff, 0x4c, 0x7c, 0x76, 0xc3, 0x3f, 0xf0, 0x6b, 0x4f, 0x4a, 0xd2, 0xe5, + 0xec, 0xc3, 0x1c, 0xae, 0x87, 0x52, 0x9e, 0x0e, 0xe9, 0x67, 0x63, 0x30, 0x80, 0x50, 0xc8, 0xbc, 0xf1, 0x80, 0x35, + 0x29, 0xc4, 0xbf, 0x80, 0x6f, 0x47, 0x09, 0x9b, 0x37, 0xde, 0xd6, 0xd7, 0xf2, 0xe6, 0x8d, 0xf7, 0xe0, 0x53, 0x14, + 0x60, 0x15, 0x94, 0xb2, 0xc0, 0x2a, 0x08, 0x1b, 0x6d, 0x84, 0x31, 0x70, 0xf5, 0xae, 0x31, 0xd4, 0xf5, 0x1c, 0xb1, + 0x6d, 0xa5, 0xef, 0xc3, 0xf7, 0x90, 0x01, 0x1f, 0xbc, 0x29, 0x4a, 0xa2, 0xcf, 0xa9, 0x29, 0x92, 0xd6, 0x3d, 0xf7, + 0x5b, 0xeb, 0x8e, 0xd6, 0x94, 0xfa, 0xc8, 0xd5, 0xf8, 0x70, 0xa8, 0xaf, 0x85, 0x16, 0x09, 0xa6, 0xa0, 0x71, 0x0d, + 0xda, 0x02, 0x04, 0x7d, 0x1e, 0x20, 0x6b, 0x49, 0xb1, 0xe0, 0xdb, 0x5f, 0x21, 0x06, 0xaf, 0x4c, 0xef, 0x5c, 0xae, + 0x32, 0x12, 0xb6, 0x17, 0x7e, 0x39, 0xac, 0xfd, 0x89, 0x53, 0x0b, 0x4b, 0xab, 0x39, 0xa8, 0x9f, 0xd9, 0x72, 0x9c, + 0xaa, 0xda, 0xbf, 0x24, 0x49, 0xb5, 0xab, 0xb4, 0x9c, 0xde, 0xdb, 0x37, 0x5d, 0x26, 0xd8, 0xd8, 0x0f, 0xa8, 0x3a, + 0xb2, 0x1a, 0x76, 0x5f, 0xa8, 0x2f, 0x7a, 0x4a, 0x26, 0x34, 0x1f, 0x55, 0x34, 0xcf, 0xee, 0x37, 0x3b, 0xea, 0x3f, + 0xbd, 0x1c, 0x8a, 0x00, 0xc9, 0x2a, 0x2d, 0x96, 0x22, 0x67, 0x63, 0x3f, 0x1e, 0x26, 0x99, 0x0a, 0x2f, 0x48, 0x47, + 0x77, 0xbf, 0x71, 0x7f, 0xcb, 0x0d, 0x64, 0x85, 0x56, 0x6d, 0x30, 0x56, 0x8a, 0x96, 0xc1, 0xfa, 0x6a, 0xdc, 0xef, + 0x8b, 0xab, 0xf1, 0x54, 0x04, 0x35, 0x10, 0x17, 0x89, 0xeb, 0xf1, 0xb4, 0x26, 0x96, 0xd4, 0xae, 0xc0, 0x18, 0x3d, + 0xae, 0x8a, 0xda, 0xa7, 0xbe, 0x86, 0x50, 0xa4, 0x5a, 0x33, 0xc7, 0x1a, 0x37, 0x46, 0xc4, 0x1d, 0x56, 0xae, 0x9d, + 0xda, 0xeb, 0x00, 0x2c, 0xaf, 0xc6, 0x05, 0x61, 0x93, 0x1c, 0x3b, 0x17, 0xb0, 0x1a, 0x0d, 0xa9, 0x76, 0xc3, 0xad, + 0x97, 0x9d, 0xdf, 0x3c, 0x4e, 0x6c, 0x6d, 0x84, 0x5b, 0x0a, 0x28, 0xa3, 0xfc, 0xc6, 0x72, 0xc2, 0xee, 0x54, 0xef, + 0x48, 0xd5, 0x8e, 0x38, 0x71, 0x01, 0xcb, 0x0d, 0x4f, 0xad, 0xbe, 0x89, 0xc1, 0x89, 0x50, 0xb5, 0xd2, 0xe1, 0x4e, + 0x26, 0x10, 0xf7, 0xab, 0xfb, 0xba, 0x57, 0x82, 0x9f, 0x84, 0xbc, 0x7e, 0xcb, 0x3b, 0x00, 0xac, 0xf8, 0x90, 0x17, + 0xd3, 0xc2, 0xd1, 0xba, 0x0c, 0xca, 0x00, 0x11, 0x9a, 0x01, 0xd0, 0xc9, 0xd5, 0x41, 0x94, 0x06, 0xae, 0xb8, 0x43, + 0x84, 0x9f, 0x46, 0xcf, 0xf2, 0xeb, 0xf0, 0x59, 0x35, 0x0d, 0x2f, 0xf2, 0x20, 0xba, 0xa8, 0x82, 0xe8, 0x59, 0x75, + 0x15, 0x3e, 0xcb, 0xa7, 0xd1, 0x45, 0x1e, 0x84, 0x17, 0x55, 0x63, 0xdf, 0xb5, 0xbb, 0x7b, 0x42, 0xde, 0x76, 0xf5, + 0x47, 0xce, 0x95, 0x3d, 0x65, 0x7a, 0x7e, 0x5e, 0xeb, 0x95, 0xda, 0x6d, 0xae, 0xd7, 0xa8, 0x99, 0xfa, 0x28, 0xfb, + 0x8b, 0x6d, 0x2c, 0x3c, 0x9a, 0x43, 0xe8, 0x33, 0xd2, 0x62, 0xee, 0x71, 0xae, 0x37, 0x7b, 0x52, 0x18, 0x18, 0x31, + 0xa9, 0x64, 0xe4, 0xf4, 0x02, 0x17, 0xa1, 0x0a, 0x31, 0xac, 0xa5, 0xab, 0x7d, 0xd6, 0xa5, 0x37, 0x50, 0xd7, 0x14, + 0xfb, 0x1a, 0x32, 0xf0, 0xa2, 0xe9, 0x65, 0x30, 0x06, 0xe4, 0x08, 0xbc, 0xe3, 0xb3, 0x25, 0x1c, 0x98, 0x6b, 0x80, + 0xbe, 0x79, 0xd4, 0xd7, 0xe5, 0x8e, 0xaf, 0x55, 0xdf, 0x4c, 0xd7, 0x23, 0xa5, 0xfc, 0x58, 0xf1, 0xbb, 0x8b, 0xe7, + 0xec, 0x96, 0x6b, 0x54, 0x94, 0x5f, 0xf4, 0x62, 0xbd, 0x07, 0xae, 0xba, 0x5f, 0xe0, 0x36, 0x8b, 0xc7, 0xae, 0x3c, + 0x60, 0xd9, 0x96, 0x3d, 0xb0, 0x1b, 0xf6, 0x81, 0x3d, 0x61, 0x6f, 0xd9, 0x7b, 0x56, 0x23, 0x44, 0x79, 0xa9, 0xa4, + 0x3c, 0x7f, 0xc1, 0x6f, 0xa5, 0xed, 0x51, 0xc2, 0x92, 0x3d, 0xd8, 0x76, 0x9a, 0xe1, 0x86, 0x7d, 0xe0, 0x8b, 0xe1, + 0x8a, 0xbd, 0x85, 0x6c, 0x28, 0x14, 0x0f, 0x56, 0xac, 0x86, 0x2b, 0x2c, 0x65, 0xd0, 0xa7, 0x61, 0x69, 0x09, 0x8b, + 0xa6, 0x50, 0x94, 0xa2, 0xdf, 0xf2, 0x9a, 0xb0, 0xd3, 0x6a, 0x2c, 0x44, 0x7e, 0x68, 0xb8, 0x62, 0x0f, 0x7c, 0x31, + 0x58, 0xb1, 0x0f, 0xda, 0x46, 0x34, 0xd8, 0xb8, 0xc5, 0x11, 0x98, 0x95, 0x2e, 0x4c, 0x0a, 0xd4, 0x5b, 0xfb, 0x26, + 0xb8, 0x61, 0x37, 0x58, 0xbf, 0x27, 0x58, 0x34, 0xca, 0xfc, 0x83, 0x15, 0x7b, 0xcf, 0x25, 0x86, 0x9a, 0x5b, 0x9e, + 0x74, 0x0c, 0xd5, 0x05, 0xd2, 0x15, 0xe1, 0x09, 0xa7, 0x17, 0xd9, 0x7b, 0x2c, 0x83, 0xbe, 0x32, 0x5c, 0xb1, 0x2d, + 0xd6, 0xee, 0xc6, 0x18, 0xb7, 0xac, 0xea, 0x49, 0x50, 0x60, 0x94, 0x55, 0x4a, 0xcb, 0xc5, 0x11, 0xcb, 0xa6, 0x8e, + 0x1a, 0xd4, 0x86, 0x01, 0x7d, 0x30, 0xfa, 0x0f, 0x5f, 0xbf, 0xfb, 0xd1, 0x2b, 0xf5, 0xcd, 0xf7, 0x17, 0xc7, 0xbb, + 0xb2, 0x44, 0xef, 0xca, 0x5f, 0x79, 0x39, 0xfb, 0x65, 0x3e, 0xd1, 0xb5, 0xa4, 0x4d, 0x86, 0xdc, 0x4d, 0x67, 0xbf, + 0x74, 0xf8, 0x5b, 0xfe, 0xea, 0xfb, 0x8d, 0xd5, 0xc7, 0xea, 0xbb, 0xba, 0x7b, 0x1f, 0x06, 0x9b, 0xc6, 0xa9, 0xf8, + 0xee, 0x74, 0xc5, 0xb1, 0x9d, 0xb5, 0xf6, 0xce, 0xfc, 0x1f, 0xae, 0xf5, 0x16, 0xc7, 0xee, 0x86, 0x6f, 0x87, 0x1b, + 0x7b, 0x18, 0xe4, 0xf7, 0xa5, 0xe2, 0x38, 0xab, 0xf9, 0x0b, 0xaf, 0x53, 0x92, 0x05, 0x54, 0xa3, 0xcf, 0x46, 0x1a, + 0xba, 0x64, 0x26, 0xa6, 0x21, 0xbe, 0xc8, 0x00, 0x9d, 0x0b, 0xc4, 0xb3, 0x7b, 0x3e, 0x9e, 0xdc, 0x5f, 0xc5, 0x93, + 0xfb, 0x01, 0xff, 0x6c, 0x5a, 0xd0, 0x5e, 0x70, 0xf7, 0x3e, 0xfb, 0x95, 0x17, 0xf6, 0x92, 0xfc, 0xc5, 0x67, 0x5f, + 0x85, 0xbb, 0x4a, 0x7f, 0xf1, 0xd9, 0x7b, 0xc1, 0x7f, 0x1d, 0x69, 0xb2, 0x0c, 0xf6, 0xbe, 0xe6, 0xbf, 0x8e, 0x90, + 0xf5, 0x83, 0x7d, 0x11, 0xfc, 0x2b, 0xf8, 0x7f, 0x57, 0x09, 0x5a, 0xc6, 0xbf, 0xd4, 0xea, 0xe7, 0x07, 0x19, 0x9b, + 0x03, 0x6f, 0x42, 0x2b, 0xe8, 0xcd, 0xdb, 0x5a, 0xfe, 0x24, 0x2e, 0x8e, 0x54, 0x3d, 0x35, 0x1c, 0xb4, 0x58, 0xcc, + 0xa2, 0x3e, 0x4a, 0xa7, 0xf2, 0x26, 0xef, 0x78, 0x26, 0x2d, 0xcc, 0xf7, 0x10, 0x0e, 0xfc, 0xce, 0x86, 0x29, 0xd8, + 0x71, 0xdc, 0x0c, 0xde, 0xb1, 0xf7, 0xc2, 0x67, 0xd9, 0x74, 0xcb, 0x6f, 0xf8, 0x13, 0xfe, 0x9e, 0xef, 0x82, 0x07, + 0xfe, 0x81, 0xbf, 0xe5, 0x75, 0xcd, 0x77, 0x6c, 0x29, 0x21, 0x4f, 0xeb, 0xed, 0x65, 0xb0, 0x65, 0xf5, 0xee, 0x32, + 0x78, 0x60, 0xf5, 0xf6, 0x79, 0x70, 0xc3, 0xea, 0xdd, 0xf3, 0xe0, 0x03, 0xdb, 0x5e, 0x06, 0x4f, 0xd8, 0xee, 0x32, + 0x78, 0xcb, 0xb6, 0xcf, 0x83, 0xf7, 0x6c, 0xf7, 0x3c, 0xa8, 0x15, 0xd2, 0xc3, 0x7b, 0x21, 0x99, 0x4e, 0xde, 0xd7, + 0xcc, 0xb0, 0xea, 0x06, 0x5f, 0x84, 0xf5, 0x8b, 0x6a, 0x19, 0x7c, 0xa9, 0x99, 0x6e, 0x73, 0x20, 0x04, 0xd3, 0x2d, + 0x0e, 0x6e, 0xe9, 0x89, 0x69, 0x57, 0x90, 0x0a, 0xd6, 0xd5, 0xd2, 0x60, 0x51, 0x37, 0xad, 0x93, 0xd9, 0xf1, 0x4e, + 0x8c, 0x3b, 0xbc, 0x13, 0x17, 0x6c, 0xd9, 0x74, 0xba, 0xea, 0x9c, 0x3e, 0x0f, 0xf4, 0x11, 0xa0, 0xf7, 0xfe, 0x4a, + 0x7a, 0xd0, 0x14, 0x0d, 0xcf, 0x95, 0xee, 0xb8, 0xb5, 0xdf, 0x87, 0xd6, 0x7e, 0xcf, 0xa4, 0x22, 0x2d, 0x62, 0x51, + 0x59, 0x54, 0x15, 0xf2, 0x89, 0x07, 0x99, 0xd6, 0xaa, 0x25, 0x8c, 0xd4, 0x99, 0x80, 0x49, 0x5f, 0xd0, 0x61, 0x90, + 0x93, 0x5d, 0x81, 0x2d, 0xf9, 0x66, 0x90, 0xb0, 0x35, 0x8f, 0xa7, 0xc3, 0x24, 0x58, 0xb2, 0x3b, 0x3e, 0xec, 0x16, + 0x0b, 0x56, 0x2a, 0x8c, 0x49, 0x5f, 0x9f, 0x8e, 0x76, 0x77, 0xde, 0x5b, 0xa5, 0x71, 0x9c, 0x09, 0xd4, 0xb9, 0x55, + 0x7a, 0x9b, 0xdf, 0x3a, 0xbb, 0xfa, 0x5a, 0xed, 0xf2, 0x20, 0x30, 0xfc, 0x0a, 0x44, 0x3b, 0xc4, 0x7b, 0x07, 0x35, + 0x46, 0xba, 0x25, 0xb3, 0xee, 0x2b, 0x7b, 0x5f, 0xdf, 0x9a, 0xad, 0xfa, 0xdf, 0x2d, 0x82, 0xf6, 0x72, 0xd9, 0xfb, + 0x9f, 0xcd, 0xab, 0xbf, 0x75, 0xbc, 0xba, 0xf1, 0x27, 0x0f, 0xfc, 0x33, 0x46, 0x27, 0x60, 0x22, 0xdb, 0xf1, 0xcf, + 0xa3, 0x6d, 0xe3, 0x94, 0x27, 0xf7, 0xf2, 0xff, 0x2b, 0x05, 0xda, 0xbb, 0x79, 0x65, 0x6f, 0x8a, 0x5b, 0xde, 0xb1, + 0x97, 0x2f, 0xad, 0x3d, 0xd1, 0x20, 0x94, 0x7c, 0xe6, 0x6e, 0x50, 0x34, 0xec, 0x89, 0xbf, 0xf0, 0x6a, 0xf6, 0x79, + 0x3e, 0xd9, 0xf2, 0xe3, 0x1d, 0xf1, 0x73, 0xc7, 0x8e, 0xf8, 0x8b, 0x3f, 0x58, 0x36, 0xdf, 0xea, 0xd5, 0xce, 0x9d, + 0xdc, 0xa9, 0xf4, 0x8e, 0x1f, 0xef, 0xe3, 0xc3, 0x7f, 0xbb, 0xd2, 0xbb, 0xef, 0xae, 0xb4, 0x5d, 0xe5, 0xee, 0xce, + 0x37, 0x1d, 0xdf, 0xc8, 0x5a, 0x63, 0xb8, 0x99, 0x51, 0x30, 0xc2, 0xb4, 0x85, 0x69, 0x1a, 0x44, 0x96, 0x62, 0x11, + 0x12, 0x35, 0x4a, 0xe7, 0x44, 0x9f, 0x05, 0x9d, 0x82, 0x2e, 0x6e, 0xf4, 0xb7, 0x7c, 0xcc, 0x16, 0xc6, 0x65, 0xf3, + 0xf6, 0x6a, 0x31, 0x19, 0x0c, 0x6e, 0xfd, 0xfd, 0x3d, 0x0f, 0x67, 0xb7, 0x73, 0xf6, 0x8e, 0xdf, 0xd3, 0x7a, 0x9a, + 0xa8, 0xc6, 0x17, 0x8f, 0x49, 0x60, 0xb7, 0xbe, 0x3f, 0xb1, 0x88, 0x60, 0xed, 0x1b, 0xe7, 0xad, 0x3f, 0x90, 0x66, + 0x69, 0xb9, 0xb5, 0x7f, 0x78, 0x5c, 0x43, 0x71, 0x0b, 0x42, 0xc6, 0x07, 0x5b, 0xe5, 0xf0, 0x96, 0x7f, 0xf2, 0xde, + 0xf9, 0xd3, 0x77, 0x3a, 0xf8, 0x66, 0xa2, 0xce, 0xa5, 0xb7, 0x17, 0xcf, 0xd9, 0xaf, 0xfc, 0xb3, 0x3c, 0x53, 0xbe, + 0x0a, 0x39, 0x6d, 0x6f, 0x90, 0xc4, 0x89, 0x8e, 0x8a, 0xf7, 0x6e, 0x22, 0x81, 0x42, 0x20, 0x1e, 0x47, 0xcd, 0x1f, + 0x26, 0xe5, 0xd4, 0xdb, 0x01, 0xc9, 0x2b, 0xb7, 0x15, 0xd1, 0xb7, 0x9c, 0xf3, 0xc5, 0xf0, 0x72, 0xfa, 0xbe, 0xdb, + 0xb7, 0x47, 0x85, 0xb5, 0xa9, 0x88, 0xb7, 0x5b, 0x0c, 0xc2, 0x3a, 0x99, 0x59, 0xe6, 0x92, 0x2f, 0xbd, 0xaf, 0xcd, + 0xdc, 0x63, 0x7a, 0xc7, 0x99, 0x66, 0xc8, 0xe8, 0x0b, 0xcc, 0x4c, 0x87, 0xc3, 0xdd, 0x39, 0x96, 0xc7, 0x87, 0x6f, + 0x9f, 0x3d, 0x19, 0x3c, 0xc1, 0x10, 0x2e, 0x2b, 0x2c, 0xe4, 0x3d, 0x1f, 0x66, 0x75, 0xeb, 0xda, 0x71, 0xf1, 0x7c, + 0xf8, 0x0b, 0xe4, 0x0d, 0xba, 0x1e, 0x9a, 0x22, 0x5a, 0xe5, 0x77, 0x14, 0x7d, 0xa2, 0xe4, 0xa0, 0xe3, 0x09, 0xd4, + 0x0e, 0xb9, 0x70, 0xdf, 0x3f, 0xe3, 0xa0, 0xe8, 0xc0, 0x52, 0xfb, 0xfd, 0xf3, 0xcf, 0x44, 0x28, 0x0d, 0xe3, 0xfd, + 0x32, 0x8c, 0xfe, 0x88, 0xcb, 0x62, 0x0d, 0x47, 0xec, 0x00, 0x3e, 0xf7, 0x4c, 0x5f, 0xc3, 0xee, 0x7c, 0xdf, 0x0f, + 0xbc, 0x2d, 0xbf, 0x61, 0xef, 0xb9, 0x77, 0x39, 0x7c, 0xeb, 0x3f, 0x7b, 0x02, 0xf2, 0x13, 0x8c, 0xcb, 0x17, 0x0c, + 0x89, 0xed, 0x28, 0x46, 0xad, 0xc3, 0x2f, 0x35, 0xc4, 0x6a, 0x7d, 0x46, 0xea, 0x2e, 0x48, 0xff, 0xa8, 0x90, 0xfd, + 0x84, 0xc0, 0x6a, 0x92, 0x3e, 0x05, 0x26, 0xf1, 0x6d, 0x0d, 0x09, 0xa4, 0x69, 0x81, 0x18, 0x1c, 0x28, 0x3e, 0x15, + 0xfc, 0xfd, 0xf0, 0x0b, 0xc9, 0x7f, 0x8b, 0x9a, 0x8f, 0xe1, 0x6f, 0x18, 0x9a, 0x49, 0xf5, 0x90, 0xd6, 0x51, 0xe2, + 0xd5, 0x70, 0xea, 0x85, 0x95, 0x50, 0x27, 0x43, 0x90, 0x8a, 0x21, 0x17, 0xe2, 0xe2, 0xf9, 0xe4, 0xb6, 0x14, 0xe1, + 0x1f, 0x13, 0x7c, 0x26, 0x57, 0x9a, 0x7c, 0x46, 0x4f, 0x1a, 0x59, 0xc0, 0x83, 0x7c, 0x5f, 0xf6, 0x6a, 0xb0, 0xa8, + 0x87, 0xfc, 0xb6, 0x76, 0xdf, 0x97, 0x73, 0x82, 0x1e, 0xd9, 0x0f, 0x68, 0x0e, 0x06, 0x6a, 0x06, 0x52, 0x86, 0xe0, + 0x16, 0x2e, 0xfd, 0x9e, 0x2a, 0xc8, 0x97, 0xdf, 0xfb, 0x22, 0x64, 0xe0, 0xca, 0x82, 0x30, 0xe5, 0x52, 0x21, 0x05, + 0x8e, 0xdb, 0x7a, 0xf0, 0x45, 0xa3, 0x93, 0x48, 0xf0, 0x29, 0x01, 0x49, 0xd2, 0xf2, 0x40, 0xd2, 0x88, 0xe9, 0x40, + 0x5c, 0x28, 0x4d, 0xb3, 0x92, 0x22, 0x0e, 0xb1, 0xab, 0xbe, 0x43, 0xc2, 0xb3, 0xe0, 0x03, 0x83, 0xb5, 0x23, 0x45, + 0x8b, 0xf7, 0xc6, 0x74, 0xac, 0xc3, 0x86, 0xee, 0x64, 0x71, 0xbf, 0x4a, 0xea, 0x34, 0x12, 0x57, 0xbe, 0x0a, 0xf9, + 0xf3, 0x9f, 0x4a, 0x04, 0xd2, 0xbb, 0x1a, 0x88, 0x41, 0xf0, 0x03, 0xf4, 0x1f, 0xb0, 0xc8, 0x41, 0x50, 0xaa, 0xcb, + 0x30, 0xaf, 0x32, 0x2a, 0x70, 0xb6, 0x63, 0xdb, 0x39, 0x53, 0x75, 0x0b, 0xbe, 0x08, 0xc3, 0x90, 0x76, 0xb6, 0x6a, + 0x4e, 0x6e, 0xf5, 0x06, 0xea, 0x99, 0xc4, 0x91, 0x5a, 0x8a, 0x23, 0x6d, 0xcd, 0x7d, 0xba, 0xf4, 0xba, 0xe5, 0x05, + 0x0d, 0x17, 0xa0, 0x17, 0xa5, 0xbb, 0xce, 0x27, 0x14, 0xba, 0xac, 0xc6, 0xd5, 0x50, 0xd4, 0xa1, 0x1c, 0x63, 0xed, + 0xcf, 0x95, 0x3c, 0xbf, 0x03, 0xeb, 0x11, 0x1a, 0xbe, 0x2a, 0x75, 0x10, 0xdb, 0x4f, 0xf4, 0xae, 0x53, 0xa9, 0xbf, + 0x01, 0x60, 0xe0, 0xd4, 0xf1, 0x50, 0x1f, 0xb5, 0x53, 0xc8, 0x76, 0xee, 0x2d, 0x31, 0x2a, 0x57, 0xc2, 0x53, 0xa5, + 0xe5, 0x29, 0x65, 0xd5, 0xd7, 0x82, 0x5b, 0xd9, 0x7d, 0x36, 0x80, 0x8c, 0x36, 0x28, 0x90, 0x67, 0xd4, 0xd6, 0x78, + 0x90, 0x6a, 0x9a, 0x25, 0x8e, 0xe1, 0x83, 0x22, 0xcd, 0x2a, 0xb0, 0x78, 0x99, 0x4b, 0xe6, 0xa0, 0x60, 0xb9, 0xde, + 0x6c, 0xa6, 0x99, 0xea, 0x8b, 0xdc, 0xde, 0x68, 0xbc, 0x4c, 0xff, 0xcd, 0x92, 0x01, 0x8f, 0x2e, 0x9e, 0xfb, 0x01, + 0xa4, 0x49, 0x8a, 0x07, 0x48, 0x82, 0xed, 0xc1, 0x2e, 0x76, 0x18, 0xb6, 0x8a, 0x95, 0x3d, 0x79, 0xba, 0xdc, 0xa1, + 0x29, 0x97, 0xe0, 0x92, 0x13, 0x73, 0x39, 0xf5, 0x7d, 0xc9, 0x7a, 0x43, 0x71, 0xca, 0xa6, 0x09, 0x28, 0x09, 0xb4, + 0x5b, 0xf0, 0x5f, 0xf8, 0xd4, 0xd0, 0x69, 0x01, 0x96, 0xda, 0x6e, 0xc0, 0x7f, 0xa1, 0x5f, 0x6c, 0x77, 0x51, 0x3f, + 0x30, 0x0f, 0xf6, 0x66, 0x71, 0x65, 0x0c, 0x38, 0x49, 0x5c, 0x69, 0x1e, 0xb9, 0x7e, 0x50, 0xf4, 0xe9, 0xb2, 0x76, + 0xe0, 0x4c, 0x71, 0x61, 0x95, 0xda, 0x24, 0xbd, 0xf6, 0x5b, 0x6a, 0xe2, 0x4d, 0x94, 0x54, 0x85, 0xed, 0x90, 0xf6, + 0x2f, 0x29, 0x67, 0xaa, 0xb8, 0x43, 0xf4, 0x64, 0x37, 0x71, 0x15, 0x78, 0x61, 0x55, 0xb1, 0x11, 0x6a, 0x33, 0xb2, + 0x9c, 0xc0, 0xe9, 0x1e, 0xab, 0x0b, 0x3e, 0xb6, 0xab, 0xd9, 0x05, 0x2b, 0xd9, 0x9a, 0x49, 0xf7, 0x79, 0x3b, 0xe6, + 0x42, 0x5e, 0xe9, 0x65, 0xd1, 0x0a, 0x68, 0x0f, 0x02, 0x87, 0x5f, 0x6a, 0xba, 0x47, 0xcf, 0x36, 0xdb, 0xd4, 0x66, + 0x63, 0x6b, 0x11, 0x42, 0x06, 0xa2, 0xa1, 0x2f, 0xe4, 0x8c, 0x22, 0x5f, 0xa5, 0xe5, 0x5a, 0x6d, 0xac, 0x32, 0x5e, + 0x60, 0x22, 0xc8, 0x70, 0x16, 0xde, 0xa3, 0xa7, 0xf5, 0x48, 0x53, 0x4c, 0x82, 0x93, 0x2e, 0xfe, 0x02, 0x6c, 0x28, + 0x4f, 0x72, 0x73, 0x40, 0x0e, 0xa0, 0x72, 0x29, 0x4a, 0xa5, 0x0c, 0xfe, 0x59, 0xdd, 0x91, 0x6d, 0xd5, 0x7f, 0xa7, + 0x81, 0x0c, 0xee, 0x40, 0xdf, 0xf6, 0x42, 0x6b, 0x47, 0x3b, 0x57, 0xb6, 0xa6, 0x6d, 0x99, 0xe6, 0x31, 0xb2, 0xd8, + 0x00, 0xf2, 0x89, 0x74, 0x0e, 0x44, 0x5e, 0x13, 0x8d, 0x77, 0x76, 0xcd, 0xc7, 0x53, 0xf1, 0x98, 0xbc, 0x57, 0xf9, + 0xbe, 0xb9, 0xd7, 0x07, 0x63, 0xec, 0x5b, 0x50, 0x26, 0x3e, 0x5a, 0x6d, 0xad, 0x4b, 0xac, 0xb7, 0x4a, 0x93, 0xe8, + 0x86, 0x2b, 0xe8, 0x38, 0x12, 0x37, 0x88, 0xc1, 0x31, 0xe3, 0xb5, 0x55, 0x96, 0xbe, 0xc2, 0x32, 0xd7, 0x31, 0x4b, + 0x86, 0x4c, 0xea, 0x3c, 0x51, 0xf0, 0xe4, 0xe7, 0x09, 0xc9, 0x88, 0xa8, 0xd9, 0x96, 0xa3, 0x94, 0x9b, 0x16, 0x70, + 0x99, 0x91, 0x01, 0x7c, 0x93, 0x26, 0x00, 0xe5, 0xf2, 0x25, 0x48, 0xa5, 0x21, 0x82, 0x6b, 0xb6, 0x97, 0x8c, 0x6e, + 0x1d, 0xad, 0x83, 0x2a, 0xc9, 0xdc, 0xc1, 0xb9, 0x9d, 0x45, 0x4a, 0xbd, 0xf9, 0x08, 0xc3, 0x4e, 0x3e, 0x86, 0x75, + 0x82, 0xdf, 0x06, 0xd4, 0xa4, 0xcf, 0x85, 0x17, 0x8d, 0x00, 0x4d, 0x7d, 0xa7, 0xca, 0xf8, 0x5c, 0x78, 0xd9, 0x68, + 0xcb, 0x32, 0x4a, 0xa1, 0xba, 0x60, 0x76, 0x6b, 0xba, 0x10, 0xf3, 0xaa, 0x1a, 0x68, 0x83, 0xdc, 0xae, 0x63, 0x06, + 0x34, 0x6a, 0xbb, 0xf2, 0xc8, 0x02, 0xdc, 0x9a, 0x89, 0xc0, 0xc8, 0xf9, 0x0f, 0xf9, 0x2b, 0x15, 0xce, 0xd3, 0xef, + 0x87, 0xde, 0x7e, 0x1b, 0x44, 0xa3, 0xed, 0x25, 0xdb, 0x05, 0xd1, 0x68, 0x77, 0xd9, 0x30, 0xfa, 0xfd, 0x9c, 0x7e, + 0x3f, 0x6f, 0x40, 0x55, 0x22, 0x4c, 0xc4, 0xbd, 0x7e, 0xa3, 0x96, 0xaf, 0xd4, 0xfa, 0x9d, 0x5a, 0xbe, 0x54, 0xc3, + 0x5b, 0x7b, 0x12, 0x09, 0x22, 0x4b, 0x63, 0xf3, 0x20, 0xd9, 0x52, 0x2d, 0x95, 0x8e, 0x51, 0x65, 0x44, 0x2d, 0x9d, + 0xcd, 0xb1, 0x62, 0xa4, 0x9d, 0x83, 0x92, 0x01, 0x99, 0x16, 0x57, 0x35, 0xa6, 0x9b, 0x15, 0x2d, 0x31, 0x19, 0x61, + 0x65, 0x5b, 0xde, 0x6e, 0x52, 0x35, 0x9d, 0x93, 0x9b, 0x5b, 0xa5, 0xdc, 0xdc, 0x0a, 0x9e, 0x7f, 0x43, 0xb7, 0x5c, + 0x72, 0xed, 0x65, 0x36, 0x2d, 0x94, 0x6e, 0x19, 0xd7, 0x60, 0x6b, 0xdf, 0x04, 0xb2, 0xcc, 0x47, 0x8a, 0x1a, 0xdb, + 0x8b, 0x46, 0xf9, 0x06, 0xd9, 0x8a, 0x18, 0x75, 0xca, 0x82, 0xf1, 0xb7, 0x3b, 0x7a, 0x20, 0x03, 0x55, 0x55, 0x6d, + 0x1c, 0xdc, 0x59, 0xe9, 0x0f, 0xcb, 0x8b, 0xe7, 0x2c, 0xb1, 0xd2, 0xc9, 0x85, 0x2a, 0xf4, 0x07, 0x21, 0xba, 0xa9, + 0x6c, 0x38, 0x38, 0xd4, 0xc5, 0x56, 0x06, 0x84, 0x1e, 0xa6, 0xf7, 0x36, 0x56, 0xb2, 0xdc, 0x35, 0xe5, 0x8b, 0x19, + 0x4f, 0x38, 0x8e, 0xbe, 0x5c, 0x2d, 0xc2, 0x5a, 0x2d, 0xb2, 0x13, 0xe0, 0xa1, 0xb5, 0x5a, 0x0a, 0xb9, 0x5a, 0x84, + 0x33, 0xd3, 0x85, 0x9a, 0xe9, 0x19, 0x28, 0x20, 0x85, 0x9a, 0xe5, 0x09, 0xc0, 0xc2, 0x0b, 0x33, 0xc3, 0x85, 0x99, + 0xe1, 0x38, 0xa4, 0xc6, 0xff, 0x41, 0xef, 0x75, 0xee, 0xb9, 0xe5, 0x6e, 0x74, 0x1a, 0xf1, 0xed, 0x68, 0x83, 0x39, + 0x3e, 0x08, 0x27, 0x10, 0x2a, 0x58, 0x22, 0x56, 0x8f, 0x46, 0xd8, 0x51, 0x43, 0xe5, 0x68, 0xbf, 0x2c, 0x2c, 0xc9, + 0x92, 0xb0, 0x24, 0xf7, 0x6a, 0x9c, 0x4b, 0xcb, 0xc5, 0xab, 0x24, 0x10, 0x89, 0x8c, 0x97, 0xd2, 0x04, 0x9f, 0xf0, + 0x72, 0x64, 0xa4, 0xe6, 0xc9, 0x22, 0xf5, 0x72, 0x96, 0xb1, 0x31, 0x62, 0x18, 0x85, 0x7e, 0x53, 0xf5, 0xfb, 0x69, + 0xe9, 0xe5, 0xd4, 0xce, 0xcf, 0xe0, 0x7a, 0x79, 0xea, 0x2c, 0x72, 0x84, 0xbc, 0x1a, 0x49, 0x85, 0xe5, 0xb5, 0x52, + 0x4f, 0x5f, 0x82, 0x0f, 0xea, 0xee, 0x8d, 0x02, 0x20, 0x2e, 0x72, 0xe9, 0x5f, 0x5b, 0xc2, 0xa5, 0x29, 0x37, 0x30, + 0xe8, 0x21, 0xcf, 0x49, 0x08, 0x95, 0x20, 0x24, 0x85, 0x75, 0xe3, 0xbe, 0x78, 0x3e, 0x71, 0xdd, 0x59, 0x6c, 0x60, + 0x82, 0xc3, 0x01, 0x10, 0x0f, 0xa6, 0x5e, 0x34, 0xe0, 0xa5, 0x9a, 0x33, 0x9f, 0xbc, 0x9c, 0x60, 0x32, 0x40, 0x55, + 0x31, 0x70, 0xca, 0x7a, 0x26, 0x1f, 0x19, 0x37, 0x33, 0xdf, 0x0f, 0xf0, 0xdd, 0xba, 0x90, 0xe8, 0x0f, 0x0a, 0xa0, + 0x20, 0x53, 0x00, 0x05, 0x89, 0x01, 0x28, 0x88, 0x0d, 0x40, 0xc1, 0xa6, 0xe1, 0x6b, 0xa9, 0xc3, 0x8d, 0x80, 0x2e, + 0xc2, 0x87, 0x9e, 0x85, 0x8d, 0x15, 0x8a, 0x67, 0x63, 0x36, 0x66, 0x85, 0xda, 0x79, 0x72, 0x39, 0x15, 0x3b, 0x8b, + 0xb1, 0xae, 0x22, 0xcb, 0xc4, 0x0b, 0x09, 0x45, 0xce, 0xb9, 0x91, 0xa8, 0xbb, 0x9f, 0x7b, 0x2f, 0xc9, 0x58, 0x32, + 0x6f, 0x68, 0xd4, 0x60, 0x5e, 0x76, 0x1d, 0xc0, 0xb4, 0xe4, 0xdb, 0x82, 0x06, 0xd3, 0xa9, 0xf2, 0x88, 0x34, 0x09, + 0x6a, 0xe7, 0x32, 0x29, 0x72, 0x42, 0x98, 0x04, 0xbd, 0x12, 0xfc, 0x46, 0xa2, 0xfc, 0x7f, 0xd3, 0x09, 0x1e, 0xe0, + 0x98, 0x68, 0x95, 0x7c, 0x05, 0x03, 0x66, 0xce, 0x5f, 0x48, 0xa7, 0x6c, 0x84, 0x62, 0x2c, 0xd3, 0x78, 0xf4, 0x95, + 0x0d, 0x11, 0xda, 0xea, 0x05, 0x9a, 0x98, 0xa0, 0x0e, 0xf0, 0x88, 0xfe, 0x1a, 0x7d, 0x35, 0x14, 0x2a, 0x5d, 0x8d, + 0xd4, 0x35, 0x3b, 0xe7, 0xfc, 0x6b, 0x6d, 0x38, 0x91, 0x31, 0x6d, 0x0a, 0x7c, 0x03, 0x02, 0xf9, 0x06, 0x02, 0xc0, + 0x55, 0xd3, 0x99, 0xbd, 0x02, 0x38, 0x07, 0x02, 0x78, 0x9c, 0x77, 0x3c, 0x7e, 0xa4, 0xbf, 0x8a, 0xe3, 0xde, 0x69, + 0x1a, 0xb6, 0xff, 0x0a, 0x8c, 0xc5, 0x50, 0x8e, 0xe7, 0x3b, 0x05, 0xc9, 0x1e, 0xa5, 0x2c, 0x5d, 0x35, 0x91, 0x1d, + 0x8a, 0xf5, 0x69, 0x4e, 0x19, 0x4b, 0xdb, 0x72, 0x8c, 0x36, 0x5e, 0x3f, 0xc6, 0xe3, 0x9b, 0x1b, 0x3d, 0xf9, 0xa0, + 0x07, 0xb7, 0xb7, 0xb7, 0xaf, 0x7b, 0xcc, 0xe6, 0x5b, 0xb1, 0x78, 0x56, 0xc4, 0x89, 0xd3, 0x3a, 0xe4, 0x00, 0x07, + 0x39, 0x09, 0x81, 0x74, 0x8c, 0x4b, 0x2d, 0x3a, 0xa8, 0x59, 0xce, 0x6b, 0x60, 0x99, 0x45, 0x90, 0x0d, 0x10, 0xd5, + 0x34, 0x15, 0xab, 0xe1, 0x41, 0xa9, 0x9a, 0x53, 0x2a, 0xb5, 0x6f, 0x38, 0x5b, 0x9d, 0x3e, 0xb1, 0x6a, 0x13, 0x6e, + 0xfd, 0x6b, 0xed, 0x09, 0xda, 0x4a, 0x1a, 0x08, 0xf5, 0x7c, 0x9d, 0xde, 0x51, 0x14, 0x8f, 0x33, 0x13, 0x4f, 0x55, + 0x60, 0xec, 0x5b, 0x3b, 0x82, 0x82, 0xa4, 0xe9, 0x3a, 0xe0, 0x30, 0x8d, 0x4e, 0x58, 0xfc, 0x53, 0xfa, 0x50, 0x5e, + 0xd4, 0x0a, 0x9c, 0xe4, 0xef, 0xc2, 0x45, 0x24, 0xb1, 0xd0, 0x2f, 0x09, 0x80, 0x44, 0x06, 0xaf, 0x46, 0xc5, 0x5a, + 0xa8, 0x00, 0x39, 0x45, 0xe9, 0xad, 0xe2, 0xe3, 0x52, 0x94, 0x2a, 0xa5, 0x32, 0x37, 0x2a, 0x05, 0x84, 0xb5, 0x81, + 0xa3, 0x0b, 0xf8, 0x02, 0x82, 0xd6, 0x72, 0xb7, 0xb6, 0x3d, 0x6f, 0x64, 0x3e, 0x33, 0xcd, 0xd3, 0xea, 0xa3, 0xfa, + 0xfb, 0xc3, 0x12, 0xc3, 0x6c, 0x3c, 0xfd, 0x7d, 0x9b, 0x21, 0xdc, 0xfc, 0x0d, 0x43, 0x74, 0x07, 0xe0, 0x98, 0xa5, + 0x3d, 0x14, 0xb2, 0x60, 0x82, 0x35, 0x54, 0xe5, 0x29, 0x9f, 0xbd, 0x7c, 0x72, 0x0b, 0x68, 0x6a, 0xe8, 0xe2, 0x46, + 0xa7, 0xba, 0x2a, 0x41, 0xf8, 0xbe, 0x2b, 0xd4, 0x63, 0x73, 0xc0, 0xa9, 0x01, 0xa0, 0x58, 0xe4, 0xb5, 0x1e, 0xdb, + 0x3f, 0xe8, 0x8d, 0x7a, 0x03, 0xc4, 0xd3, 0x39, 0x2f, 0xfc, 0x23, 0xfa, 0x75, 0xea, 0xcf, 0xb8, 0x10, 0x44, 0xbd, + 0x9e, 0x84, 0xf7, 0xe2, 0x2c, 0x8d, 0x83, 0xb3, 0xde, 0xc0, 0x5c, 0x04, 0x8a, 0xb3, 0x34, 0x3f, 0x03, 0xb1, 0x1c, + 0xe1, 0x11, 0x6b, 0x76, 0x07, 0x88, 0x81, 0xa5, 0x0e, 0x49, 0x56, 0x1d, 0xdb, 0xef, 0xbf, 0x19, 0x19, 0xde, 0x74, + 0x44, 0x84, 0xd1, 0xbf, 0x2b, 0x10, 0xa0, 0x60, 0x99, 0xd9, 0xce, 0x4c, 0xba, 0xda, 0xb3, 0x7a, 0xde, 0x6c, 0xf2, + 0xae, 0xde, 0xb1, 0x9a, 0x96, 0x53, 0xd3, 0x2a, 0xab, 0x69, 0x93, 0x1c, 0x6a, 0x26, 0xfa, 0x7d, 0x8d, 0x8f, 0x9a, + 0xcf, 0x01, 0x97, 0x0d, 0x93, 0xdf, 0xcc, 0xaa, 0x79, 0xbf, 0xef, 0xc9, 0x47, 0xf0, 0x0b, 0x89, 0xcb, 0xdc, 0x1a, + 0xcb, 0xa7, 0xaf, 0x89, 0xcf, 0xcc, 0x20, 0x1e, 0xdd, 0x1d, 0x41, 0x7d, 0xdd, 0x08, 0xaf, 0x63, 0xae, 0xb0, 0x99, + 0x98, 0xbe, 0x81, 0xc1, 0xf3, 0x84, 0x0f, 0xde, 0x72, 0xf4, 0x37, 0xd2, 0x99, 0x29, 0x58, 0xc8, 0xb9, 0x3f, 0x79, + 0x83, 0xd0, 0xc9, 0x88, 0xf4, 0xa0, 0xd3, 0x09, 0x1a, 0xb2, 0xdf, 0x5f, 0x41, 0x67, 0xb6, 0x52, 0x29, 0x5b, 0x15, + 0x95, 0xe9, 0xba, 0x2e, 0xca, 0x0a, 0x3a, 0x96, 0x7e, 0xde, 0x0a, 0x99, 0x59, 0x3f, 0xb3, 0x90, 0x9f, 0x56, 0x12, + 0x6b, 0xca, 0xb6, 0x4f, 0xd4, 0x06, 0x69, 0xd6, 0x85, 0xea, 0x02, 0xe7, 0xce, 0xda, 0xeb, 0x8d, 0x50, 0xff, 0x9c, + 0x8f, 0xd6, 0xc5, 0xda, 0x03, 0x97, 0x98, 0x59, 0x3a, 0x57, 0x1c, 0x1a, 0xb9, 0x3f, 0xfa, 0x52, 0xa4, 0x39, 0xe5, + 0x01, 0x1a, 0x44, 0x31, 0xb7, 0xdf, 0x02, 0xe9, 0x87, 0xde, 0x02, 0xd9, 0x47, 0xe7, 0x9c, 0xbc, 0x01, 0x70, 0x3a, + 0x44, 0xc4, 0xad, 0x48, 0xd0, 0xb1, 0x6a, 0x78, 0x6b, 0xe1, 0x9e, 0xf6, 0xd2, 0xb8, 0x97, 0xe6, 0x67, 0x69, 0xbf, + 0x6f, 0x00, 0x34, 0x53, 0x44, 0x86, 0xc7, 0x19, 0xb9, 0x48, 0x5a, 0x08, 0xa6, 0xb4, 0xff, 0x6a, 0x0c, 0x09, 0x02, + 0x01, 0xff, 0xbb, 0xf0, 0x9e, 0x00, 0xda, 0x26, 0x6d, 0xc0, 0x55, 0x8f, 0xe9, 0xc0, 0x6c, 0xc9, 0xd9, 0xaa, 0xb3, + 0x01, 0x28, 0xa7, 0x4a, 0xeb, 0x29, 0x8f, 0x6b, 0x8a, 0x88, 0x54, 0x59, 0xa8, 0xdf, 0x58, 0x4f, 0x26, 0xab, 0x5c, + 0x64, 0xc8, 0x51, 0x99, 0xbe, 0xd6, 0x8c, 0x10, 0xbb, 0xf4, 0xf3, 0x05, 0x2c, 0xd9, 0xf8, 0x13, 0x4e, 0xde, 0x12, + 0x20, 0x6d, 0x67, 0xed, 0xaa, 0xda, 0xe5, 0xb8, 0xb5, 0x9b, 0x03, 0x92, 0xaf, 0x37, 0x1a, 0x8d, 0xb4, 0x9f, 0x9c, + 0x80, 0xa1, 0xea, 0xa9, 0xa5, 0xd0, 0x63, 0xb5, 0xc2, 0xd6, 0xed, 0xc8, 0x65, 0x96, 0x0c, 0xe6, 0x0b, 0xe3, 0xf8, + 0x95, 0xf9, 0xe8, 0xe3, 0xa5, 0xb2, 0x76, 0x1d, 0xf1, 0xf5, 0x1f, 0x65, 0xb5, 0xbe, 0xe7, 0x5d, 0xd5, 0x04, 0x7c, + 0x51, 0xc5, 0x96, 0x7e, 0xc7, 0x7b, 0xb2, 0x77, 0xf1, 0xb5, 0x1b, 0xec, 0x92, 0xef, 0x79, 0x8b, 0x3a, 0xcf, 0x57, + 0xbe, 0x6e, 0x54, 0xe9, 0xf6, 0x5e, 0xb2, 0xc0, 0xb5, 0x77, 0xd4, 0x34, 0xd6, 0x33, 0x3f, 0x7a, 0x58, 0x84, 0x6c, + 0xe7, 0x63, 0xef, 0xab, 0xe6, 0xe9, 0x59, 0x43, 0x6f, 0x52, 0x43, 0x1f, 0x7b, 0x51, 0xb6, 0x4f, 0x4d, 0x23, 0x7a, + 0x0d, 0x1b, 0xfa, 0xd8, 0x5b, 0x72, 0x72, 0x48, 0x30, 0x38, 0x35, 0xe6, 0x8f, 0x0f, 0xa7, 0x33, 0xfc, 0x1d, 0x03, + 0x2a, 0x31, 0x99, 0x4f, 0x8f, 0x69, 0x47, 0x01, 0x66, 0x54, 0xe9, 0xed, 0xd3, 0x03, 0xdb, 0xf1, 0xb2, 0x1e, 0x5a, + 0x7a, 0xf7, 0xe4, 0xe8, 0x76, 0xbc, 0xaa, 0xc6, 0x97, 0x72, 0xc8, 0xf3, 0x7c, 0x36, 0x1a, 0x8d, 0x84, 0x41, 0xe7, + 0xae, 0xf4, 0x06, 0x56, 0x20, 0x83, 0x8b, 0xea, 0x43, 0xb9, 0xf4, 0x76, 0xea, 0xd0, 0xae, 0xfc, 0x49, 0x7e, 0x38, + 0x14, 0x23, 0x73, 0x8c, 0x03, 0xce, 0x49, 0xa1, 0xe4, 0x28, 0x59, 0x4b, 0x10, 0x9d, 0xd2, 0x78, 0x2a, 0xeb, 0xb5, + 0x15, 0x91, 0x57, 0x23, 0xe4, 0x43, 0xf0, 0x93, 0x07, 0x6a, 0xf1, 0x6b, 0x2d, 0x88, 0x3d, 0xf6, 0xa9, 0x52, 0x3a, + 0xc4, 0xab, 0x02, 0x42, 0x84, 0x01, 0x6f, 0xa0, 0x1d, 0x94, 0xe0, 0xb0, 0xc3, 0x7d, 0x44, 0x84, 0xe8, 0xd7, 0x5e, + 0x3e, 0x93, 0xe1, 0xca, 0xbd, 0x41, 0x35, 0x67, 0x80, 0x58, 0xe9, 0x33, 0x70, 0xc1, 0x04, 0xd4, 0x53, 0x7c, 0x8a, + 0xfe, 0xf5, 0xe6, 0x61, 0xd3, 0xf5, 0x69, 0x09, 0xa8, 0x88, 0x9e, 0xfd, 0x7c, 0x0c, 0xe0, 0x9d, 0x5d, 0x9b, 0x91, + 0xf6, 0xf2, 0x37, 0xc0, 0xb0, 0x52, 0x92, 0x68, 0xe7, 0x94, 0x08, 0xdc, 0xf9, 0xc8, 0x96, 0x7e, 0x94, 0x02, 0x31, + 0x77, 0x3c, 0x49, 0x64, 0x0f, 0x36, 0x72, 0x02, 0xb7, 0x18, 0xf0, 0xe8, 0x00, 0x54, 0xae, 0x14, 0xe4, 0x5e, 0x73, + 0x24, 0x77, 0xfc, 0xd0, 0xfb, 0x61, 0x50, 0x0f, 0x7e, 0xe8, 0x9d, 0xa5, 0x24, 0x77, 0x84, 0x67, 0x6a, 0x4a, 0x88, + 0xf8, 0xec, 0x87, 0x41, 0x3e, 0xc0, 0xb3, 0x44, 0x8b, 0xb4, 0xc8, 0xad, 0x26, 0x6a, 0xdc, 0x84, 0x17, 0x89, 0xa4, + 0x21, 0xda, 0x75, 0x1e, 0x11, 0x0b, 0x00, 0xc9, 0xe2, 0xb3, 0x79, 0x43, 0x51, 0xef, 0x26, 0x7c, 0x8b, 0xee, 0xb2, + 0xd8, 0xef, 0x6f, 0xf3, 0xb4, 0xee, 0xe9, 0x50, 0x19, 0x7c, 0x41, 0xaa, 0x09, 0xf0, 0x68, 0x7f, 0x6d, 0x8e, 0x57, + 0xaf, 0x36, 0x47, 0xca, 0x42, 0x95, 0xa8, 0xdf, 0x62, 0x35, 0xeb, 0x21, 0x22, 0x77, 0x96, 0x19, 0x7b, 0x7b, 0xc1, + 0x2b, 0x39, 0xab, 0x62, 0xbb, 0x1c, 0x5f, 0x11, 0xd6, 0x56, 0x12, 0xa0, 0xa3, 0xf5, 0x58, 0x9b, 0x62, 0xe4, 0x57, + 0x0a, 0x09, 0xb8, 0xe8, 0xd8, 0x5a, 0x28, 0x36, 0x5e, 0x80, 0xbe, 0x64, 0x67, 0x1a, 0x60, 0xbd, 0xd1, 0xab, 0x88, + 0xdb, 0xf2, 0x91, 0x0a, 0x6f, 0x72, 0x53, 0x65, 0x56, 0x36, 0x8b, 0x76, 0x3f, 0x55, 0xbc, 0x42, 0xdc, 0x7a, 0xa3, + 0xf6, 0x28, 0x40, 0xed, 0xa1, 0x85, 0x32, 0x40, 0x97, 0xa6, 0x19, 0x00, 0x32, 0x00, 0xc8, 0x54, 0x11, 0x9f, 0x09, + 0x50, 0x69, 0xab, 0x1b, 0x05, 0x4e, 0xa4, 0xd7, 0xc0, 0xb8, 0xc0, 0x4a, 0x1f, 0xd9, 0xc8, 0x60, 0xb1, 0x45, 0x80, + 0x5b, 0x8e, 0xf4, 0x61, 0x1a, 0x4e, 0xb6, 0xd1, 0x1c, 0x26, 0x69, 0x7e, 0x1f, 0x66, 0xa9, 0x84, 0x96, 0xf8, 0x51, + 0xd6, 0x18, 0xb1, 0x80, 0xf4, 0x7d, 0x7a, 0x51, 0x64, 0x31, 0x41, 0xc2, 0x59, 0x4f, 0x1d, 0x40, 0x35, 0x39, 0xd7, + 0x9a, 0x56, 0xcf, 0x6a, 0x93, 0x87, 0x2c, 0xd0, 0xd9, 0x83, 0x31, 0xa9, 0xe5, 0x86, 0x1e, 0xd9, 0x5f, 0x39, 0x9e, + 0x11, 0xbe, 0xeb, 0x19, 0x4e, 0xfd, 0x77, 0x53, 0x03, 0x29, 0x53, 0x02, 0x08, 0x32, 0x38, 0x9a, 0x10, 0xca, 0xd3, + 0x31, 0x99, 0xda, 0xfc, 0x08, 0x84, 0x23, 0x82, 0x57, 0xf0, 0xdc, 0xd0, 0xba, 0xe5, 0xc6, 0xce, 0x22, 0x4f, 0x13, + 0x40, 0x16, 0x2f, 0xf8, 0x16, 0x90, 0x39, 0xf5, 0xaa, 0x90, 0x3d, 0x7b, 0x2e, 0xa6, 0xb3, 0x79, 0xf0, 0x90, 0xd0, + 0xfe, 0xc5, 0x84, 0xdf, 0x74, 0x57, 0xc9, 0x95, 0xa9, 0x75, 0x6f, 0xa2, 0xc7, 0x5c, 0xee, 0xf4, 0x69, 0xc5, 0x31, + 0xe2, 0x19, 0xac, 0x02, 0x72, 0xce, 0x86, 0xfc, 0xfa, 0x1c, 0xb0, 0x5b, 0x56, 0xc2, 0x8b, 0xf8, 0x75, 0x28, 0xab, + 0x05, 0xc8, 0x8f, 0x9c, 0x47, 0xe6, 0x97, 0xaf, 0xb6, 0x43, 0x39, 0xa7, 0x28, 0xa2, 0xe5, 0xd4, 0xb4, 0xa4, 0x90, + 0x1d, 0x7a, 0x0a, 0x26, 0x53, 0x5b, 0xfe, 0xde, 0x26, 0x2e, 0xc9, 0x37, 0x93, 0xc8, 0xbe, 0x0e, 0xb0, 0x66, 0xad, + 0xba, 0x87, 0x6e, 0x08, 0x06, 0x88, 0x8c, 0x50, 0x66, 0x73, 0x7d, 0xb7, 0x1e, 0x0c, 0x14, 0xcc, 0xaf, 0xa0, 0x9b, + 0x16, 0x9d, 0xe2, 0x00, 0x39, 0x6b, 0x5d, 0xa3, 0x52, 0x55, 0x1c, 0x3a, 0xcc, 0xbb, 0x65, 0x55, 0x76, 0x59, 0x7a, + 0x21, 0x48, 0x8d, 0xba, 0x0a, 0x16, 0x29, 0x15, 0x51, 0xbc, 0x27, 0xbf, 0x06, 0x26, 0x9e, 0x59, 0x39, 0x4a, 0xe3, + 0x39, 0x20, 0x06, 0x29, 0x20, 0x4e, 0xf9, 0x15, 0xa0, 0x89, 0x2e, 0xa2, 0x30, 0x7b, 0x1b, 0x57, 0x41, 0x6d, 0x35, + 0xfd, 0xde, 0x81, 0x8c, 0x3d, 0xaf, 0xfb, 0xfd, 0x94, 0x18, 0xfd, 0x30, 0x0a, 0x03, 0xff, 0x1e, 0x4f, 0xf7, 0x4d, + 0x90, 0x9a, 0x57, 0x1e, 0xe0, 0x15, 0x5d, 0x6e, 0x6d, 0xca, 0x15, 0x8d, 0x0b, 0x7f, 0x8d, 0xe0, 0xf0, 0xa9, 0xa3, + 0xd8, 0x6e, 0x53, 0xe5, 0xd4, 0xc6, 0x60, 0x10, 0xc2, 0x7d, 0x2b, 0xe3, 0xf7, 0x89, 0x97, 0xcf, 0xa2, 0x39, 0x28, + 0x4a, 0x33, 0xcd, 0x17, 0x52, 0x48, 0x37, 0x01, 0xfa, 0x68, 0x10, 0x6a, 0x75, 0xe5, 0x1f, 0x89, 0x97, 0xaa, 0x69, + 0x6d, 0x9e, 0x62, 0x8d, 0x02, 0x31, 0x8b, 0xe6, 0x0d, 0xcb, 0xe8, 0x90, 0x54, 0x97, 0x4b, 0xd3, 0x8c, 0x3f, 0xac, + 0x66, 0xa8, 0x56, 0x1c, 0x35, 0x41, 0x8d, 0xd2, 0x0d, 0x5c, 0x00, 0xff, 0x46, 0x77, 0x1c, 0xd5, 0x28, 0x52, 0x34, + 0xe0, 0x13, 0xc4, 0x88, 0x35, 0x9b, 0x27, 0xac, 0x35, 0x75, 0xcd, 0xe8, 0xf7, 0x65, 0xc8, 0x90, 0x49, 0x42, 0x9e, + 0x3e, 0x5c, 0xae, 0x9f, 0x48, 0x75, 0x01, 0xfc, 0xca, 0x15, 0x9b, 0xf5, 0x7a, 0x73, 0x80, 0xeb, 0x85, 0xf5, 0x0b, + 0x1b, 0x57, 0x70, 0x7e, 0x49, 0xf0, 0xbb, 0xea, 0x47, 0x98, 0x65, 0x50, 0x05, 0x64, 0xfc, 0xb1, 0x90, 0xce, 0x73, + 0x17, 0x93, 0xfa, 0xcd, 0x48, 0x5d, 0x50, 0x66, 0xe9, 0xdc, 0xe2, 0x04, 0x01, 0xe7, 0x61, 0xf5, 0x04, 0x92, 0x7d, + 0xf9, 0xd8, 0xa7, 0x19, 0x05, 0xaa, 0x23, 0xc0, 0x67, 0xb3, 0x7e, 0x08, 0xfb, 0x07, 0x44, 0x16, 0xea, 0x6f, 0xde, + 0xc8, 0x59, 0x43, 0xf2, 0x40, 0xaa, 0xb9, 0x8f, 0xe1, 0xd4, 0x58, 0xe0, 0x4b, 0x8b, 0xde, 0x54, 0xf0, 0x9a, 0x90, + 0xb9, 0x17, 0x68, 0xed, 0x5b, 0xc0, 0x11, 0x22, 0xb8, 0x8c, 0x52, 0x9c, 0xf6, 0x76, 0xbd, 0x00, 0xb9, 0xcd, 0x2d, + 0xc8, 0xeb, 0x77, 0x2e, 0x7e, 0x71, 0x8a, 0xf4, 0x2c, 0xba, 0xc0, 0x40, 0x17, 0x64, 0xde, 0xf8, 0x67, 0x05, 0x2b, + 0x17, 0xd0, 0x7b, 0xa9, 0x58, 0xc9, 0xc9, 0xb6, 0x53, 0x7f, 0x94, 0xca, 0x7e, 0x7b, 0x66, 0x4d, 0xe0, 0x57, 0x89, + 0xfd, 0x12, 0x99, 0x7c, 0xd3, 0x63, 0x93, 0xaf, 0x0c, 0x8b, 0x4e, 0x2d, 0x83, 0x73, 0x7a, 0x64, 0x70, 0xee, 0xed, + 0xac, 0xda, 0x84, 0x30, 0x14, 0x24, 0x81, 0xa6, 0x4b, 0x0f, 0xeb, 0xa6, 0x3f, 0x3f, 0x69, 0x51, 0x6d, 0xd5, 0xbe, + 0x75, 0x3f, 0x0e, 0xb1, 0x8b, 0x5f, 0x25, 0x9e, 0x21, 0x22, 0xf5, 0x81, 0x0e, 0x4c, 0x06, 0x4f, 0x5c, 0xf6, 0xfb, + 0x50, 0xd8, 0x6c, 0x3c, 0x1f, 0xd5, 0xc5, 0xcf, 0xc5, 0x03, 0xa0, 0x3a, 0x54, 0x60, 0x97, 0x43, 0x19, 0xca, 0x88, + 0x4d, 0x6d, 0xb9, 0xe7, 0xf7, 0x57, 0x61, 0x0e, 0xf2, 0x8e, 0x86, 0xc7, 0x39, 0x03, 0x31, 0x0c, 0xbe, 0xfe, 0xc3, + 0x93, 0x7d, 0xda, 0xfc, 0x70, 0x06, 0xdf, 0x1d, 0x9d, 0x7d, 0x44, 0xba, 0x9b, 0xb3, 0x75, 0x59, 0xdc, 0xa7, 0xb1, + 0x38, 0xfb, 0x01, 0x52, 0x7f, 0x38, 0x2b, 0xca, 0xb3, 0x1f, 0x54, 0x65, 0x7e, 0x38, 0xa3, 0x05, 0x37, 0xfa, 0xdd, + 0x9a, 0x78, 0xff, 0xa8, 0x34, 0x03, 0xda, 0x12, 0x22, 0xb3, 0xb4, 0xfa, 0x11, 0x94, 0x88, 0x8a, 0x1f, 0x55, 0x46, + 0xb5, 0x5a, 0x3b, 0xce, 0x87, 0x44, 0x23, 0x65, 0xd3, 0x84, 0xc4, 0xd5, 0x12, 0xd6, 0xa1, 0x9e, 0x9d, 0x36, 0xdf, + 0x8e, 0xf3, 0x40, 0x1d, 0x10, 0x39, 0xbf, 0xce, 0x47, 0x5b, 0xfa, 0x1a, 0x7c, 0xeb, 0x70, 0xc8, 0x47, 0x3b, 0xf3, + 0xd3, 0x27, 0x6b, 0xa5, 0x8c, 0x3b, 0x52, 0xe4, 0x42, 0xc8, 0x19, 0xb7, 0xed, 0x31, 0xe0, 0x00, 0xf0, 0x0f, 0x07, + 0xfa, 0xbd, 0x93, 0xbf, 0xd5, 0x6e, 0x69, 0xd5, 0xf3, 0x63, 0x8b, 0x3b, 0xe3, 0x75, 0x6d, 0x88, 0xda, 0xf6, 0x12, + 0x5b, 0x7a, 0xdf, 0x34, 0xa8, 0x29, 0xa2, 0x9f, 0xb0, 0x9a, 0x58, 0xc5, 0x61, 0x41, 0x4a, 0x48, 0x62, 0x38, 0x46, + 0x3b, 0xf4, 0x38, 0x5d, 0x2c, 0x3d, 0xb9, 0xef, 0xf0, 0x72, 0xeb, 0xfb, 0x80, 0xa4, 0x55, 0x38, 0xff, 0xe8, 0x85, + 0x06, 0x1e, 0xbd, 0xc8, 0xab, 0x22, 0x13, 0x23, 0x41, 0xa3, 0xfc, 0x96, 0xc4, 0x99, 0x33, 0xac, 0xc5, 0x99, 0x02, + 0x0b, 0x0b, 0x09, 0xa0, 0xbb, 0x28, 0x29, 0x3d, 0x38, 0x7b, 0xb2, 0x2f, 0x9b, 0xdf, 0x09, 0x1e, 0x62, 0xb4, 0x00, + 0x46, 0x9c, 0x5d, 0xbb, 0xbc, 0x87, 0xb0, 0xcc, 0xbd, 0xdf, 0xdf, 0xde, 0xe5, 0x05, 0x84, 0x68, 0x9e, 0x49, 0xc5, + 0x6a, 0x79, 0x06, 0x8c, 0x79, 0x22, 0x3e, 0x0b, 0x2b, 0x39, 0x0d, 0xaa, 0x8e, 0x62, 0xf5, 0x36, 0x9e, 0x7b, 0x40, + 0xf1, 0xfd, 0x21, 0x01, 0x2e, 0x77, 0x9f, 0xbd, 0x51, 0xae, 0xa9, 0xa4, 0x47, 0x9e, 0x63, 0xb4, 0x64, 0x02, 0x14, + 0xcf, 0x10, 0x27, 0x29, 0xac, 0x9e, 0x9b, 0x20, 0x15, 0xf9, 0xfa, 0x84, 0xe2, 0x8b, 0xe6, 0x51, 0xd4, 0xb0, 0x90, + 0x25, 0x70, 0x3c, 0x24, 0xb3, 0x6c, 0x8e, 0x2c, 0xe5, 0x69, 0x7b, 0x8a, 0x74, 0x74, 0x62, 0x89, 0xdf, 0xd6, 0xfc, + 0x7a, 0x91, 0x8a, 0xc0, 0xa4, 0x9d, 0xad, 0xcc, 0xbd, 0x10, 0x86, 0x2a, 0xe1, 0xde, 0xeb, 0x7a, 0x16, 0xca, 0x4d, + 0xd1, 0xaa, 0x98, 0x3d, 0x4c, 0x89, 0x19, 0xa6, 0x58, 0x7f, 0x61, 0xc3, 0x6f, 0x12, 0x2f, 0x06, 0xc3, 0xf5, 0x92, + 0x97, 0xb3, 0x8d, 0x59, 0x08, 0x87, 0xc3, 0x66, 0x52, 0xcc, 0x96, 0x10, 0xe6, 0xba, 0x9c, 0x1f, 0x0e, 0x5d, 0x2d, + 0x5b, 0x0b, 0x0f, 0x1e, 0xaa, 0x16, 0x6e, 0x1a, 0x96, 0xc3, 0xcf, 0x64, 0x16, 0x63, 0xfb, 0x1a, 0x9f, 0xd9, 0x9f, + 0x2f, 0xba, 0x67, 0x09, 0x92, 0x6f, 0xac, 0x81, 0x76, 0x6c, 0xd6, 0xee, 0x70, 0x35, 0x02, 0x92, 0xd2, 0xdd, 0xe8, + 0xef, 0xca, 0x4e, 0x9e, 0x12, 0xe4, 0x8e, 0x56, 0x60, 0xbf, 0xfb, 0xc6, 0x9f, 0x68, 0xb1, 0x07, 0xed, 0x36, 0xb6, + 0x84, 0xa8, 0xa6, 0x3d, 0x97, 0x2b, 0xc5, 0xd2, 0xbc, 0x95, 0x36, 0x7a, 0x3e, 0xac, 0xcf, 0x7d, 0x23, 0x07, 0x0a, + 0xc6, 0x88, 0xa7, 0xd6, 0x41, 0x34, 0x9b, 0x03, 0x0d, 0x06, 0x9a, 0x47, 0x78, 0x6a, 0xa1, 0x83, 0x32, 0x6b, 0xc3, + 0x7e, 0x92, 0x9c, 0x2c, 0x8f, 0xc3, 0xb7, 0xf0, 0x2f, 0x9f, 0x61, 0x93, 0x98, 0x62, 0x7b, 0xfc, 0xad, 0x52, 0x54, + 0x78, 0x6c, 0x41, 0x5c, 0x6b, 0x37, 0xa2, 0x36, 0x54, 0x0e, 0xff, 0x12, 0xf6, 0x11, 0xf6, 0x1b, 0x9a, 0x20, 0x0c, + 0x76, 0xfd, 0x99, 0x40, 0x88, 0x58, 0x88, 0x17, 0xfc, 0xad, 0x92, 0x54, 0x74, 0xc2, 0x67, 0x8b, 0x12, 0x78, 0xeb, + 0x30, 0xa0, 0x4f, 0x28, 0x52, 0x0a, 0x61, 0x68, 0x26, 0xf4, 0x8e, 0xfe, 0x1b, 0xb1, 0x93, 0x4d, 0x72, 0x2b, 0xe4, + 0x03, 0x49, 0x25, 0xc1, 0x04, 0x2b, 0x2f, 0x94, 0x2f, 0xdc, 0x0b, 0xa5, 0xd6, 0x5a, 0xd0, 0xfa, 0xe5, 0x4f, 0x12, + 0xcf, 0xe0, 0xef, 0x81, 0x8c, 0x41, 0xb7, 0x11, 0xd5, 0x24, 0xc7, 0xf4, 0x51, 0x3a, 0xcf, 0x40, 0x05, 0x74, 0xb6, + 0xce, 0xc2, 0x7a, 0x59, 0x94, 0xab, 0x56, 0xa4, 0xa8, 0x2c, 0x7d, 0xa4, 0x1e, 0x63, 0x5e, 0x98, 0x27, 0x27, 0xf2, + 0xc1, 0x23, 0x00, 0xc6, 0xa3, 0x3c, 0xad, 0x3a, 0x4a, 0xeb, 0x07, 0x96, 0x01, 0x23, 0x70, 0xa2, 0x0c, 0x78, 0x84, + 0x65, 0x60, 0x9e, 0x76, 0x19, 0x6a, 0x10, 0x6b, 0x54, 0x5d, 0xa9, 0x0d, 0xe6, 0x44, 0x51, 0xf2, 0x29, 0x96, 0x56, + 0x18, 0x43, 0x53, 0x57, 0x1e, 0x59, 0x2f, 0x39, 0x61, 0x4f, 0x76, 0x03, 0xe9, 0x16, 0x36, 0x0a, 0x67, 0xd0, 0xb5, + 0x2c, 0x51, 0x2e, 0xba, 0x65, 0x44, 0x99, 0x08, 0xa9, 0x9f, 0x3d, 0x9c, 0x69, 0xb5, 0xdf, 0xd8, 0x49, 0xfb, 0xf6, + 0x48, 0xd1, 0x0b, 0x06, 0xed, 0xd3, 0x1e, 0x29, 0xf5, 0xac, 0x91, 0xcb, 0xc0, 0x96, 0x2e, 0x55, 0x3d, 0xff, 0x05, + 0xca, 0x77, 0x30, 0x33, 0xce, 0x66, 0xbf, 0xeb, 0xcd, 0xed, 0xc9, 0xbe, 0x6e, 0x7e, 0x67, 0xbd, 0x1e, 0x6c, 0x0d, + 0x32, 0xf1, 0x85, 0x62, 0xa1, 0xb2, 0x0a, 0xb1, 0x82, 0xb4, 0xff, 0x25, 0xbc, 0xdf, 0xe1, 0xad, 0x11, 0x9a, 0x95, + 0xf1, 0x30, 0x1f, 0x3d, 0xd9, 0x8b, 0xe6, 0xf7, 0xce, 0xb2, 0xad, 0x5c, 0x95, 0xcc, 0xf6, 0xfb, 0x51, 0xd2, 0x9c, + 0x3d, 0x5e, 0x23, 0xa9, 0x03, 0x7c, 0xbc, 0x3e, 0xc3, 0x47, 0x2a, 0xa1, 0xd4, 0x82, 0xaa, 0x06, 0xad, 0x8f, 0xfd, + 0xde, 0x7a, 0x4e, 0x1f, 0x3f, 0x96, 0xd3, 0x2d, 0x29, 0xc2, 0xf8, 0x81, 0xc1, 0x94, 0x9d, 0x38, 0x75, 0xc9, 0x9b, + 0x21, 0xbd, 0xeb, 0x56, 0x49, 0x5d, 0xf6, 0x28, 0x11, 0x84, 0x3a, 0x58, 0xbf, 0xd8, 0x0f, 0x61, 0x66, 0x8b, 0xfe, + 0xb0, 0x59, 0xcd, 0x09, 0x10, 0x11, 0xd0, 0x5a, 0xe5, 0x7d, 0xe0, 0x98, 0x2f, 0xcc, 0x9a, 0x1b, 0xd2, 0xad, 0x37, + 0x57, 0xda, 0x2b, 0x29, 0xa0, 0x9f, 0x83, 0xcc, 0xed, 0xa3, 0x5b, 0xae, 0x5a, 0xe6, 0xb9, 0xb4, 0xe5, 0x80, 0x45, + 0x0b, 0x81, 0x9a, 0x9d, 0x4b, 0x87, 0x03, 0x05, 0xa1, 0xae, 0x44, 0x15, 0x71, 0x75, 0x14, 0x2d, 0x44, 0xad, 0x56, + 0xed, 0x72, 0xb2, 0xa9, 0x90, 0x2d, 0x89, 0x20, 0xa3, 0x64, 0xaf, 0x84, 0xfa, 0x28, 0x57, 0x7b, 0xa6, 0xe1, 0x00, + 0x4d, 0xc0, 0xa6, 0x0d, 0xfe, 0x16, 0xb8, 0x97, 0xc1, 0x99, 0x69, 0x9f, 0x86, 0x11, 0x70, 0x9a, 0x43, 0xcc, 0x9f, + 0xdf, 0xf5, 0xa0, 0x82, 0x07, 0x1d, 0xe9, 0xaf, 0xeb, 0x59, 0x81, 0x67, 0xee, 0x89, 0xe7, 0x6f, 0x4e, 0xa4, 0x17, + 0x39, 0x3c, 0xd0, 0x34, 0x88, 0x19, 0x7f, 0x51, 0x96, 0xe1, 0x6e, 0xb4, 0x2c, 0x8b, 0x95, 0x17, 0xe9, 0x7d, 0x3c, + 0x93, 0x62, 0x20, 0x31, 0x63, 0x66, 0x74, 0x15, 0xeb, 0x38, 0x87, 0x71, 0x6f, 0x4f, 0xc2, 0x0a, 0xed, 0x9f, 0x25, + 0xf6, 0xba, 0x00, 0x2c, 0x87, 0xac, 0x41, 0x2b, 0xbc, 0xd3, 0xed, 0xed, 0x1e, 0x97, 0xec, 0x28, 0x6e, 0x00, 0xfd, + 0xac, 0x86, 0x96, 0x09, 0x6a, 0x99, 0x75, 0x27, 0x93, 0x29, 0x92, 0xcb, 0xb7, 0x61, 0x6f, 0x58, 0x91, 0xcf, 0x1b, + 0xb9, 0x3d, 0xbc, 0x0f, 0x57, 0x22, 0xd6, 0x16, 0x74, 0xd2, 0x91, 0x71, 0xb8, 0x17, 0x9a, 0x1b, 0xe9, 0xfe, 0x49, + 0x95, 0x84, 0xa5, 0x88, 0xe1, 0x16, 0xc8, 0xf6, 0x6a, 0x5b, 0x09, 0x4a, 0xe0, 0x83, 0xfd, 0x58, 0x8a, 0x65, 0xba, + 0x15, 0x80, 0xeb, 0xc0, 0xff, 0x94, 0x88, 0x84, 0xee, 0xce, 0x43, 0x14, 0x6b, 0xe4, 0x7d, 0x83, 0x68, 0xec, 0xaf, + 0x41, 0x4e, 0x03, 0x32, 0x91, 0x62, 0x24, 0x0b, 0x06, 0x3e, 0x80, 0x9c, 0xaf, 0xc1, 0x24, 0x37, 0xcd, 0x3d, 0x3f, + 0xc8, 0x75, 0x07, 0xd3, 0x3e, 0xe8, 0x5e, 0x5c, 0x6b, 0x96, 0x83, 0x57, 0x4c, 0xc4, 0xff, 0x56, 0x7b, 0x25, 0xcb, + 0x59, 0xe6, 0x37, 0xe6, 0xa2, 0x93, 0xc1, 0x55, 0x43, 0xf8, 0xc5, 0x2c, 0x9b, 0xf3, 0x68, 0x96, 0xe9, 0xa8, 0xff, + 0xa2, 0x39, 0x2a, 0x05, 0xe0, 0xd4, 0xf1, 0x02, 0xac, 0xa1, 0xaf, 0x74, 0xd3, 0x8a, 0x47, 0x1a, 0x63, 0x14, 0x54, + 0xe8, 0x20, 0xf4, 0xb7, 0x1a, 0x90, 0x36, 0x98, 0xa4, 0x49, 0xa8, 0x7c, 0x70, 0x41, 0x37, 0xcc, 0xcb, 0x95, 0xcb, + 0x55, 0x93, 0xaa, 0xe5, 0x97, 0x23, 0xea, 0xbb, 0x5a, 0x72, 0xa9, 0x36, 0x9f, 0x1a, 0x65, 0x8d, 0x20, 0x93, 0xa3, + 0xf4, 0xfb, 0x94, 0x0b, 0xb7, 0x32, 0x26, 0xeb, 0xc3, 0xc1, 0x2b, 0xb8, 0xa9, 0xf1, 0xeb, 0x9c, 0x08, 0x45, 0xed, + 0x21, 0x11, 0xb6, 0x76, 0x2b, 0x74, 0xef, 0x71, 0xa3, 0x34, 0x8f, 0xb2, 0x4d, 0x2c, 0x2a, 0xaf, 0x97, 0x80, 0xb5, + 0xb8, 0x07, 0xbc, 0xa8, 0xb4, 0xf4, 0x2b, 0x56, 0x00, 0x7a, 0x80, 0x14, 0x36, 0x7e, 0x44, 0x06, 0xac, 0x8f, 0x5e, + 0xea, 0xf7, 0xfb, 0xc6, 0x94, 0xff, 0xe1, 0x21, 0x07, 0x92, 0x42, 0x51, 0xd6, 0x3b, 0x98, 0x40, 0x70, 0xed, 0x24, + 0xed, 0x59, 0xcd, 0xaf, 0xd7, 0xb5, 0x07, 0xfc, 0x56, 0xbe, 0x45, 0x62, 0xf5, 0xda, 0xbe, 0xd8, 0xec, 0xd3, 0xea, + 0xc6, 0x68, 0x1c, 0x04, 0x4b, 0xab, 0xb7, 0x5a, 0xe5, 0x90, 0x37, 0xbc, 0x02, 0x91, 0xca, 0xba, 0xba, 0x56, 0xce, + 0xd5, 0xb5, 0xe0, 0xc8, 0x25, 0x5b, 0xf2, 0x1c, 0xfe, 0x0b, 0xb9, 0x57, 0x1e, 0x0e, 0x85, 0xdf, 0xef, 0xa7, 0x33, + 0xd2, 0xca, 0x02, 0x7b, 0xda, 0xba, 0xf6, 0x42, 0xff, 0x70, 0xf8, 0x11, 0xbc, 0x46, 0xfc, 0xc3, 0xa1, 0xec, 0xf7, + 0x3f, 0x99, 0x9b, 0xcc, 0xf9, 0x58, 0x29, 0x65, 0x2f, 0x51, 0xe9, 0xfe, 0x36, 0xe1, 0xbd, 0xff, 0x3d, 0xfa, 0xdf, + 0xa3, 0xcb, 0x9e, 0x0a, 0x01, 0x4b, 0xf8, 0x0c, 0x6f, 0xe8, 0x4c, 0x5d, 0xce, 0x99, 0x74, 0x77, 0x57, 0x7e, 0xe8, + 0x3d, 0x0d, 0x15, 0xdf, 0x9b, 0x9b, 0x36, 0xfe, 0x5a, 0x1d, 0x69, 0x12, 0x3a, 0x2e, 0xfa, 0x87, 0xc3, 0xe7, 0x44, + 0xeb, 0xd3, 0x52, 0xa5, 0x4f, 0x53, 0x38, 0x4a, 0x86, 0x18, 0xd7, 0x2d, 0x4c, 0x07, 0xf6, 0xe3, 0xe6, 0xab, 0xe4, + 0xc5, 0x59, 0x0a, 0xd7, 0xde, 0x7c, 0x96, 0xce, 0xa7, 0x60, 0x5d, 0x19, 0xe6, 0xb3, 0x7a, 0x1e, 0x40, 0xea, 0x10, + 0xd2, 0xac, 0x69, 0xf8, 0x97, 0xca, 0x15, 0xbc, 0xb5, 0xc7, 0xbb, 0x81, 0x8b, 0x52, 0x47, 0xfa, 0xa4, 0x8d, 0xa6, + 0x4b, 0x2a, 0xf9, 0x4f, 0x22, 0x8f, 0x31, 0x66, 0xe3, 0x35, 0xf1, 0x7e, 0x16, 0xf9, 0xab, 0x02, 0xb0, 0x8b, 0x00, + 0x0c, 0x39, 0x9d, 0x3b, 0x92, 0xf8, 0xcf, 0xc9, 0xf7, 0x7f, 0x4c, 0x97, 0xf6, 0xb1, 0x2c, 0xee, 0x4a, 0x51, 0x55, + 0x47, 0xa5, 0xed, 0x6c, 0xb9, 0x1e, 0x98, 0x44, 0xfb, 0x7d, 0xc9, 0x24, 0x9a, 0x62, 0x28, 0x0a, 0xdc, 0x1a, 0x7b, + 0xd3, 0x94, 0x2b, 0xc6, 0xea, 0x91, 0xb1, 0x7e, 0xbe, 0xdc, 0xbd, 0x8d, 0xbd, 0xd4, 0x0f, 0x52, 0x10, 0x84, 0x35, + 0x94, 0x52, 0x8a, 0x7c, 0x70, 0x3e, 0xc3, 0x54, 0xa2, 0xd6, 0xa5, 0x54, 0xf9, 0xc3, 0x48, 0xf3, 0x61, 0x0a, 0x7a, + 0xd9, 0xbf, 0x57, 0x30, 0xff, 0x75, 0x7b, 0xb0, 0x3e, 0xad, 0xcb, 0x34, 0xaa, 0x88, 0x2a, 0x2f, 0x4c, 0xb5, 0x09, + 0x44, 0xf0, 0x6b, 0x61, 0xf1, 0xfd, 0xfa, 0xe4, 0x48, 0xd0, 0x98, 0xc9, 0xf2, 0xe9, 0xc8, 0xfd, 0xc2, 0xbe, 0x72, + 0x1d, 0xcf, 0xff, 0xdc, 0xcc, 0xff, 0x01, 0x3a, 0x43, 0x16, 0xd7, 0xdc, 0x32, 0x58, 0xe0, 0xec, 0x97, 0xae, 0x1e, + 0xf0, 0x37, 0xf3, 0xc4, 0x35, 0xd0, 0x31, 0x5f, 0xa3, 0xab, 0x62, 0x3a, 0x2b, 0x06, 0xc0, 0x65, 0xeb, 0x37, 0xd6, + 0x9c, 0x78, 0x63, 0x51, 0x5e, 0xc9, 0x05, 0xa1, 0xaf, 0xab, 0x30, 0x1b, 0x57, 0xc5, 0xa6, 0x12, 0xc5, 0xa6, 0xee, + 0x91, 0x5a, 0x36, 0x9f, 0xd6, 0xb6, 0x42, 0xf6, 0xaf, 0xa2, 0xc5, 0xe0, 0x65, 0x58, 0x27, 0xa3, 0x2c, 0x5d, 0x4f, + 0x81, 0x5f, 0x2f, 0x80, 0xb3, 0xc8, 0xbc, 0xf2, 0xd5, 0xd9, 0x03, 0xb6, 0x68, 0x3c, 0x05, 0x72, 0x54, 0xfa, 0x23, + 0x6f, 0x8c, 0x4e, 0x4f, 0xf4, 0xfb, 0xf9, 0x94, 0x62, 0xbe, 0xfe, 0x0a, 0xf0, 0x5c, 0xb5, 0x5c, 0x80, 0xbe, 0x0c, + 0x75, 0x50, 0x89, 0x52, 0x2b, 0x86, 0x11, 0x0b, 0x7f, 0x15, 0x48, 0xe4, 0x4c, 0x81, 0xcd, 0x2a, 0x4a, 0x42, 0x25, + 0x2a, 0x25, 0x5b, 0x13, 0xd4, 0xd2, 0xfb, 0xa2, 0xac, 0xf7, 0x15, 0x38, 0x4a, 0x46, 0xda, 0x2c, 0x27, 0xcd, 0xb8, + 0x02, 0x65, 0x2e, 0xfa, 0xc1, 0xfe, 0x55, 0x79, 0x7e, 0x23, 0xf3, 0x59, 0xee, 0x3b, 0x3a, 0xa7, 0xed, 0xb8, 0x40, + 0x99, 0x5b, 0x4e, 0x5b, 0x2d, 0x79, 0x4c, 0xde, 0xb3, 0x60, 0xdb, 0x7f, 0x91, 0x20, 0xc5, 0x22, 0xcc, 0x27, 0x54, + 0xd9, 0xfc, 0x1d, 0x42, 0x6d, 0x71, 0x60, 0x8f, 0x5d, 0x98, 0x88, 0xff, 0x16, 0x2c, 0x89, 0x61, 0x56, 0x8a, 0x30, + 0xde, 0x81, 0xf7, 0xcf, 0xa6, 0x12, 0xa3, 0x33, 0x74, 0x72, 0x3f, 0x7b, 0x48, 0xeb, 0xe4, 0xec, 0xed, 0xeb, 0xb3, + 0x1f, 0x7a, 0x83, 0x62, 0x94, 0xc6, 0x83, 0xde, 0x0f, 0x67, 0xab, 0x0d, 0xa0, 0x65, 0x8a, 0xb3, 0x98, 0x4c, 0x69, + 0x22, 0x3e, 0x23, 0xc3, 0xe0, 0x59, 0x9d, 0x88, 0x33, 0x9a, 0x98, 0xee, 0x6b, 0x94, 0x26, 0xdf, 0x8e, 0xc2, 0x1c, + 0x5e, 0x2e, 0xc5, 0xa6, 0x12, 0x31, 0xd8, 0x29, 0xd5, 0x3c, 0xcb, 0xdb, 0x67, 0x71, 0x3e, 0xea, 0x90, 0x55, 0x3a, + 0xf0, 0xb7, 0x27, 0xd2, 0xae, 0x4a, 0x57, 0x40, 0xe8, 0x01, 0x70, 0xd2, 0x95, 0x3f, 0x0f, 0x07, 0x91, 0x40, 0xa8, + 0x05, 0x73, 0x32, 0x8d, 0xe8, 0x86, 0xf4, 0x0a, 0xfb, 0x0c, 0xcc, 0x42, 0x4a, 0xf3, 0xe0, 0xe6, 0x6a, 0x31, 0x74, + 0x57, 0xac, 0x1c, 0x85, 0xd5, 0x5a, 0x44, 0x35, 0xb2, 0x1e, 0x83, 0xf3, 0x0e, 0x44, 0x00, 0x28, 0x72, 0xf0, 0x8c, + 0x47, 0xfd, 0x7e, 0xa4, 0x82, 0x72, 0x12, 0xfa, 0x45, 0xa1, 0x5f, 0x1a, 0x8e, 0x32, 0xe6, 0xef, 0x43, 0xcd, 0x11, + 0x50, 0x6f, 0x79, 0xa8, 0xe8, 0x02, 0x70, 0x39, 0x47, 0xcc, 0x38, 0xef, 0x71, 0x17, 0x98, 0x53, 0x51, 0x50, 0xa8, + 0xeb, 0x60, 0xa9, 0x00, 0xe8, 0x4d, 0x7d, 0xa4, 0xe7, 0xa4, 0x49, 0xd0, 0x78, 0x6e, 0xe0, 0xf1, 0x6a, 0xb8, 0xa8, + 0x56, 0x42, 0xea, 0x2d, 0x74, 0x4a, 0x55, 0x87, 0x40, 0x20, 0xf0, 0x7f, 0x78, 0xfb, 0x16, 0xee, 0xb6, 0x6d, 0x6c, + 0xdd, 0xbf, 0x62, 0xf1, 0xa6, 0x2a, 0x11, 0x41, 0xb2, 0xe4, 0x24, 0x9d, 0x29, 0x65, 0x58, 0xc7, 0xcd, 0xa3, 0x4d, + 0xa7, 0x89, 0xd3, 0x38, 0xed, 0x74, 0xaa, 0xab, 0xe3, 0xd2, 0x24, 0x6c, 0xb1, 0xa1, 0x01, 0x95, 0xa4, 0xfc, 0x88, + 0xc4, 0xff, 0x7e, 0xd7, 0xde, 0x78, 0x92, 0xa2, 0x9d, 0xcc, 0xdc, 0x73, 0xef, 0xca, 0x5a, 0xb1, 0x08, 0x82, 0x78, + 0x63, 0x63, 0x63, 0x3f, 0xbe, 0xdd, 0x8c, 0x19, 0x76, 0xcb, 0x5d, 0x8e, 0x64, 0x5d, 0x14, 0x5c, 0xec, 0x04, 0x86, + 0x6e, 0xc6, 0x25, 0x33, 0x07, 0x57, 0x33, 0xac, 0x93, 0x8a, 0x02, 0xec, 0xea, 0x02, 0x64, 0x2f, 0x0c, 0x75, 0xdd, + 0xcc, 0x96, 0xeb, 0xc0, 0xd7, 0xa5, 0x0b, 0x5f, 0x52, 0xf0, 0x72, 0x25, 0x45, 0x99, 0x5d, 0xf3, 0x9f, 0xec, 0xcb, + 0x66, 0x2c, 0x29, 0xb4, 0x23, 0x7d, 0xd3, 0xee, 0x8e, 0x16, 0xe3, 0xd8, 0x72, 0x7c, 0x4b, 0xa5, 0x3b, 0x3d, 0xaa, + 0x5e, 0x08, 0x6d, 0x9d, 0x6b, 0x99, 0xa5, 0x29, 0x17, 0xaf, 0x45, 0x9a, 0x25, 0x5e, 0x72, 0xac, 0x63, 0x55, 0xbb, + 0x20, 0x58, 0x2e, 0x4c, 0xf2, 0x8b, 0xac, 0xc4, 0xd8, 0xc1, 0x8d, 0x46, 0xb5, 0xa2, 0x4e, 0x99, 0x18, 0x18, 0xf2, + 0x3d, 0x06, 0xdf, 0x66, 0x65, 0x02, 0x0c, 0x3f, 0x26, 0xea, 0x4b, 0x7a, 0x0a, 0x01, 0x1f, 0x54, 0x68, 0xee, 0x17, + 0x1c, 0xc1, 0xaf, 0xad, 0xca, 0x1c, 0x98, 0x6c, 0xad, 0x82, 0x44, 0xdc, 0xbb, 0x6c, 0xae, 0x17, 0xd1, 0x42, 0xdd, + 0x85, 0x7a, 0xf1, 0x76, 0xdb, 0x4b, 0x14, 0x1d, 0x70, 0xf2, 0xd3, 0xe0, 0x55, 0x9c, 0xe5, 0x3c, 0xdd, 0xab, 0xe4, + 0x9e, 0xda, 0x50, 0x7b, 0xca, 0x99, 0x03, 0x76, 0xde, 0xd7, 0xd5, 0x9e, 0x5e, 0xd3, 0x7b, 0xba, 0x9d, 0x7b, 0x70, + 0xc1, 0xc0, 0x9d, 0x7b, 0x99, 0x5d, 0x73, 0xb1, 0x07, 0xca, 0x40, 0x6b, 0x3c, 0x50, 0x97, 0xd5, 0x48, 0x4d, 0x8c, + 0x8e, 0x61, 0x9d, 0xe8, 0x83, 0x39, 0xa0, 0xdf, 0x43, 0x58, 0xfb, 0xd6, 0xdb, 0x95, 0x3e, 0x68, 0x03, 0xfa, 0xd3, + 0xd2, 0xf4, 0x41, 0x07, 0x8e, 0x57, 0xd1, 0x81, 0x1b, 0x43, 0xaa, 0x41, 0x5b, 0x8d, 0xac, 0x02, 0xc5, 0x1b, 0xde, + 0xe2, 0xdd, 0xb9, 0x96, 0x6c, 0xbc, 0x97, 0x88, 0xf1, 0x95, 0x89, 0x2a, 0xce, 0xc4, 0xb1, 0x97, 0xca, 0x6b, 0xed, + 0x24, 0x23, 0x8c, 0x6f, 0x59, 0x49, 0xfd, 0x1d, 0x62, 0x6e, 0x91, 0xe6, 0x30, 0x78, 0x19, 0x56, 0x64, 0xc6, 0xfb, + 0x7d, 0x39, 0x93, 0x51, 0x39, 0x13, 0xfb, 0x65, 0xa4, 0xc0, 0xda, 0xee, 0x13, 0x01, 0x3d, 0x28, 0x01, 0xf2, 0x05, + 0x40, 0xd5, 0x43, 0xc2, 0x9f, 0x87, 0xa4, 0x3e, 0x9d, 0x42, 0x9f, 0x42, 0x5b, 0xaf, 0xb8, 0x82, 0x78, 0x55, 0x37, + 0x46, 0xb6, 0x51, 0x41, 0x8b, 0xc7, 0xf2, 0xac, 0x36, 0x8c, 0xcd, 0xa9, 0xf5, 0xaf, 0x37, 0x1b, 0x4c, 0xd9, 0x5c, + 0xa8, 0x55, 0x18, 0x92, 0xe8, 0xa6, 0xf4, 0x22, 0x89, 0x58, 0xd8, 0xac, 0xd6, 0xe6, 0x37, 0x61, 0x40, 0x32, 0x91, + 0xe2, 0x7e, 0xb6, 0xc4, 0xb9, 0x8b, 0xc7, 0xf3, 0xaa, 0xaf, 0xb5, 0xb4, 0xc8, 0xb4, 0xf9, 0x4e, 0x5f, 0x86, 0x34, + 0x15, 0x35, 0xa4, 0x51, 0x67, 0x06, 0xdd, 0xb7, 0xcb, 0x5b, 0x56, 0x23, 0x4c, 0x80, 0x57, 0x3a, 0x83, 0x6e, 0x34, + 0x1e, 0x88, 0x65, 0x35, 0x2a, 0xd6, 0x42, 0x20, 0xf0, 0x30, 0xe4, 0x98, 0x59, 0x42, 0x92, 0x7d, 0xe2, 0xdf, 0xa9, + 0x38, 0x0b, 0x45, 0x7c, 0x63, 0x90, 0xbd, 0x2b, 0xeb, 0xda, 0x5d, 0x47, 0x7e, 0x4e, 0x2c, 0xac, 0xf6, 0x1f, 0x9a, + 0x47, 0xad, 0x71, 0x16, 0xd0, 0xd6, 0xb4, 0xba, 0xe1, 0x70, 0x8f, 0xea, 0x58, 0x94, 0x06, 0x9b, 0xd8, 0x23, 0xcb, + 0x45, 0xeb, 0x98, 0x41, 0x03, 0xfa, 0xdb, 0xec, 0x6a, 0x7d, 0x85, 0x00, 0x6e, 0x25, 0xb2, 0x4e, 0x52, 0xf9, 0x97, + 0xb4, 0x47, 0x5d, 0xdb, 0x53, 0xf9, 0xdf, 0xb6, 0xa9, 0x72, 0x68, 0x31, 0xe5, 0xb1, 0x9b, 0xb3, 0x40, 0x75, 0x24, + 0x88, 0x02, 0xb5, 0xf5, 0x82, 0xa9, 0x77, 0xca, 0x14, 0x1d, 0x20, 0xd0, 0x85, 0x39, 0xc3, 0xbe, 0xe0, 0x88, 0x31, + 0x4b, 0x25, 0x06, 0x53, 0x1f, 0x63, 0x54, 0xd3, 0x5a, 0x01, 0xba, 0x7e, 0xba, 0x81, 0x3f, 0x51, 0x51, 0xa3, 0xa1, + 0xd6, 0x48, 0x0a, 0x45, 0x13, 0x15, 0x8a, 0x2c, 0x2d, 0x74, 0x5c, 0x85, 0x4e, 0x22, 0x61, 0x09, 0x68, 0x98, 0x10, + 0x9d, 0x54, 0xe0, 0xad, 0x01, 0x9c, 0xf9, 0xb8, 0x28, 0xd7, 0x85, 0x36, 0x98, 0xfb, 0x21, 0xbe, 0xe6, 0xaf, 0x5f, + 0x38, 0xa3, 0xfa, 0x96, 0xb5, 0xbe, 0xa7, 0x05, 0xf9, 0x21, 0xe4, 0x14, 0x1d, 0x98, 0xd8, 0xd1, 0x06, 0x8d, 0x31, + 0xca, 0x5a, 0x47, 0xbd, 0x38, 0xd1, 0xa1, 0x58, 0xb4, 0x09, 0xde, 0x03, 0x9e, 0x22, 0xda, 0xf0, 0x50, 0x18, 0xab, + 0x6a, 0x7c, 0x2a, 0x59, 0x4b, 0x0f, 0x56, 0xf0, 0x74, 0x9d, 0xf0, 0x10, 0xf4, 0x48, 0x84, 0x1d, 0x85, 0xc5, 0x3c, + 0x5e, 0xc0, 0x71, 0x52, 0x10, 0x50, 0x3b, 0xe8, 0x2b, 0xf8, 0x7c, 0x81, 0xee, 0xaf, 0x12, 0x3d, 0xc0, 0xd0, 0x82, + 0xb8, 0x19, 0x05, 0x75, 0x74, 0x15, 0xaf, 0x1a, 0x2a, 0x12, 0x3e, 0x2f, 0xc0, 0x76, 0x48, 0xa9, 0xa7, 0x40, 0x0b, + 0x95, 0x28, 0xfd, 0x30, 0xf0, 0x1d, 0x1a, 0x03, 0x5b, 0xeb, 0x00, 0x0d, 0xfd, 0x8c, 0x69, 0x6a, 0x9d, 0xa1, 0xf2, + 0x99, 0x77, 0xcf, 0x8c, 0x96, 0x33, 0x8b, 0xc6, 0xa0, 0x6f, 0xa3, 0x29, 0x8a, 0x73, 0xf2, 0x59, 0x50, 0xc4, 0x69, + 0x16, 0xe7, 0xe0, 0xb7, 0x19, 0x17, 0x98, 0x31, 0x89, 0x2b, 0x7e, 0x29, 0x0b, 0xd0, 0x76, 0xe7, 0x2a, 0xb5, 0xae, + 0x41, 0x40, 0xf6, 0x03, 0x58, 0xbd, 0x34, 0x74, 0x54, 0xce, 0xbb, 0x4b, 0x9b, 0x42, 0xc4, 0x22, 0x04, 0x9b, 0x66, + 0xba, 0x64, 0xc7, 0xa1, 0xd2, 0xe6, 0x40, 0xa8, 0x23, 0x34, 0xee, 0x9f, 0x86, 0xb1, 0xd5, 0x14, 0x5b, 0xbb, 0xb7, + 0xed, 0xf6, 0xb7, 0xd2, 0x4b, 0xa7, 0x39, 0xe9, 0x31, 0xf6, 0x5b, 0x19, 0x16, 0x23, 0xdb, 0x11, 0x02, 0x4b, 0xce, + 0xfb, 0xd4, 0x7f, 0x45, 0xcb, 0x79, 0x02, 0xa6, 0x23, 0x3a, 0x58, 0x2e, 0x50, 0x76, 0x0c, 0xe8, 0x0e, 0x0c, 0xae, + 0xe8, 0xf7, 0xc1, 0x2a, 0xc3, 0x5c, 0x48, 0x96, 0x24, 0x65, 0xf0, 0x3c, 0xf5, 0xe0, 0xe0, 0xd7, 0x4c, 0x99, 0xbb, + 0x28, 0xeb, 0xd3, 0x25, 0x99, 0xa6, 0xc8, 0x40, 0xac, 0xc3, 0x4d, 0x96, 0x46, 0x89, 0x12, 0x91, 0x2d, 0xd1, 0x3f, + 0xd2, 0x50, 0x2c, 0x1d, 0xb9, 0x17, 0xa9, 0x12, 0xa1, 0x62, 0x9e, 0xe2, 0x49, 0x9d, 0xd6, 0xe9, 0x08, 0x43, 0x4f, + 0x82, 0x52, 0xae, 0x86, 0x81, 0x2a, 0xa9, 0x5e, 0x0a, 0x9b, 0x62, 0xbb, 0xd5, 0x17, 0x2b, 0x31, 0x8f, 0x17, 0xf8, + 0x52, 0xe0, 0x28, 0xfe, 0x83, 0x7b, 0x61, 0xa7, 0xd4, 0xf6, 0xa0, 0x76, 0x44, 0x09, 0xfd, 0x07, 0x87, 0x8b, 0xc4, + 0x77, 0x52, 0x87, 0x00, 0x44, 0x8b, 0x90, 0x33, 0x75, 0x90, 0x1a, 0x6e, 0x68, 0x47, 0xf8, 0x6f, 0xb8, 0x3e, 0xe3, + 0x8c, 0xde, 0x54, 0x33, 0x6a, 0x28, 0x5f, 0x0f, 0xda, 0x18, 0xf5, 0xd9, 0xc0, 0x61, 0x85, 0x28, 0xb4, 0x61, 0x47, + 0xa5, 0x12, 0x2d, 0x0c, 0xa5, 0xfa, 0x4b, 0xa8, 0x38, 0xe2, 0xce, 0x8c, 0xb2, 0x64, 0x7c, 0x5a, 0x1e, 0x8a, 0xe9, + 0x60, 0x50, 0x92, 0xca, 0x58, 0xe8, 0xc1, 0xf5, 0xc0, 0xf3, 0xef, 0x81, 0x5b, 0x88, 0x87, 0x8c, 0x2c, 0x86, 0xdc, + 0xe0, 0xe4, 0xb7, 0x38, 0xb9, 0x6a, 0x54, 0xaa, 0x38, 0xd6, 0x44, 0xb5, 0xe0, 0x1f, 0x65, 0x18, 0xa0, 0x4f, 0x52, + 0x00, 0x26, 0x83, 0x29, 0xbf, 0x05, 0x89, 0xd2, 0x99, 0xba, 0x21, 0xfd, 0x22, 0x0a, 0x7e, 0xc1, 0x0b, 0x2e, 0x12, + 0x57, 0x80, 0xe5, 0x1d, 0x6c, 0xaf, 0xa3, 0x8a, 0x2a, 0x4c, 0x5e, 0xd3, 0xe3, 0x88, 0x1b, 0xef, 0x3f, 0xd3, 0x63, + 0x8b, 0xd9, 0x6a, 0x1d, 0x1b, 0x7c, 0xe6, 0x18, 0x5c, 0xd0, 0xb5, 0xc4, 0xd6, 0x50, 0x0d, 0x2b, 0x02, 0x03, 0x17, + 0x70, 0x10, 0x96, 0x28, 0x8e, 0xad, 0xe4, 0x15, 0x69, 0x48, 0x69, 0x1f, 0x18, 0x8e, 0x36, 0xc9, 0xf1, 0x6d, 0x96, + 0xdd, 0x04, 0xce, 0x17, 0x9d, 0x93, 0x66, 0xc2, 0xda, 0xe0, 0x7d, 0xde, 0x9c, 0x5f, 0xf7, 0x0f, 0x09, 0x55, 0x71, + 0x6f, 0x78, 0x3b, 0xee, 0x8d, 0x13, 0x7e, 0xcd, 0xc5, 0x42, 0x87, 0x6a, 0x31, 0x97, 0x2c, 0xbf, 0xb5, 0xde, 0x2d, + 0x49, 0x6a, 0x05, 0xb4, 0xcf, 0xb2, 0xa0, 0x26, 0x02, 0x40, 0xfe, 0xf0, 0x17, 0x08, 0x9d, 0xe1, 0x6f, 0x8f, 0xc1, + 0x15, 0x29, 0xbc, 0x77, 0x08, 0x84, 0x35, 0xdd, 0xdc, 0xa9, 0x0d, 0xf8, 0x62, 0xdc, 0x9f, 0x31, 0xf5, 0xf4, 0xdb, + 0x4c, 0xee, 0xea, 0xba, 0x3d, 0xb2, 0x0c, 0x1f, 0xe1, 0x4a, 0x01, 0xdc, 0x4c, 0xf8, 0x8b, 0x61, 0x26, 0xd5, 0x27, + 0x80, 0xa9, 0xa6, 0x83, 0xfb, 0x04, 0x81, 0x01, 0x54, 0xa2, 0xc5, 0xe8, 0x5a, 0x39, 0xa2, 0x19, 0xb8, 0x35, 0xdd, + 0x0a, 0xe3, 0xad, 0x07, 0x2d, 0xf4, 0x4c, 0xc3, 0x89, 0xff, 0xa0, 0x99, 0x57, 0x05, 0x04, 0xd0, 0xca, 0x08, 0xde, + 0x5a, 0x1f, 0xcd, 0x11, 0xe2, 0x13, 0x96, 0x44, 0x13, 0x16, 0xcf, 0x14, 0x3f, 0x26, 0x74, 0xd3, 0xd4, 0x36, 0x7d, + 0x40, 0xfa, 0x8b, 0x6b, 0xd6, 0x4f, 0x59, 0xd6, 0xbe, 0x3d, 0x54, 0xbc, 0x98, 0x36, 0xe3, 0x20, 0x26, 0xaa, 0x18, + 0xff, 0x0b, 0xee, 0x4b, 0xad, 0x00, 0x91, 0xb9, 0xab, 0x9e, 0x7e, 0xbf, 0x99, 0x2d, 0x07, 0x42, 0xe5, 0x77, 0x06, + 0x49, 0x9f, 0x0e, 0xed, 0x07, 0x36, 0x89, 0xda, 0x42, 0xcf, 0x1f, 0x97, 0xba, 0x89, 0x97, 0xd7, 0xa6, 0x46, 0xb4, + 0x42, 0x86, 0xca, 0xd6, 0x01, 0xeb, 0xfb, 0x87, 0x70, 0x77, 0x51, 0xd3, 0x50, 0xeb, 0x9e, 0xbb, 0x16, 0x05, 0x27, + 0xfe, 0x00, 0x63, 0x71, 0x21, 0xa9, 0x75, 0x3c, 0x26, 0xfd, 0x68, 0x21, 0x93, 0x1b, 0x75, 0x75, 0x72, 0xa6, 0x98, + 0x27, 0x70, 0x01, 0x2e, 0xdb, 0xfe, 0x8a, 0x4a, 0x5d, 0xca, 0xed, 0x15, 0xa5, 0xe9, 0x21, 0x6d, 0xaf, 0xe2, 0xbc, + 0x2d, 0xb8, 0xe0, 0x5f, 0x28, 0xb8, 0xb0, 0x0e, 0xd6, 0x1d, 0x77, 0xca, 0x9e, 0xf0, 0x44, 0x99, 0xd6, 0x06, 0x77, + 0xdd, 0x60, 0x4c, 0x8c, 0xfd, 0xee, 0x92, 0x27, 0x1f, 0x91, 0x05, 0xff, 0x2e, 0x13, 0xe0, 0x99, 0xec, 0x5e, 0xa9, + 0xfc, 0x3f, 0xf8, 0x57, 0x5b, 0xfb, 0xce, 0x9a, 0x7f, 0x7a, 0xd6, 0xc3, 0x9d, 0xc3, 0xe4, 0xc7, 0xea, 0x0c, 0xe8, + 0xe6, 0x4a, 0xa6, 0x1c, 0x90, 0x01, 0xac, 0x45, 0x32, 0x1a, 0xf0, 0xa1, 0x95, 0x65, 0xdb, 0x77, 0x5a, 0x5d, 0x10, + 0xee, 0x25, 0x70, 0xd3, 0xfb, 0x6b, 0x33, 0x33, 0xa7, 0x6b, 0x25, 0x9a, 0x2e, 0x8d, 0xad, 0x65, 0xa9, 0xc2, 0x78, + 0xbf, 0xf7, 0x24, 0x9b, 0xe6, 0x87, 0xcb, 0x69, 0x6e, 0xa9, 0xdb, 0xc6, 0x2d, 0x1b, 0x40, 0x43, 0xec, 0x5a, 0x5b, + 0x39, 0xe0, 0xe5, 0xf6, 0x20, 0x9a, 0xaf, 0x15, 0xa1, 0xa7, 0x4a, 0x84, 0x3e, 0x4d, 0x9b, 0x7d, 0xb0, 0xab, 0x6a, + 0xdd, 0x08, 0x79, 0x34, 0x48, 0x35, 0x23, 0x7f, 0x72, 0xcd, 0x8b, 0x8b, 0x5c, 0xde, 0x00, 0x1c, 0x32, 0xa9, 0x8d, + 0xc2, 0xf2, 0x0a, 0xdc, 0xf9, 0xd1, 0x71, 0x9c, 0x89, 0x51, 0x8e, 0x71, 0x5b, 0x11, 0x29, 0x59, 0x27, 0xce, 0x00, + 0x0f, 0xd9, 0x9f, 0x34, 0x1d, 0xda, 0xb5, 0xc0, 0xf0, 0xbe, 0xc0, 0x5d, 0xe5, 0xec, 0x68, 0x93, 0xdb, 0x45, 0xdf, + 0x9c, 0x61, 0xdd, 0x91, 0xd2, 0xda, 0x58, 0x74, 0xdd, 0xc1, 0x5a, 0x33, 0x68, 0x8b, 0x50, 0xf2, 0x21, 0x77, 0xd2, + 0x7e, 0x0a, 0x68, 0x70, 0x96, 0xa5, 0xb7, 0xd6, 0x2a, 0x7f, 0xa3, 0x85, 0x38, 0x51, 0x4c, 0x9d, 0xf8, 0x26, 0x4a, + 0xf4, 0xf9, 0x99, 0x18, 0x37, 0x10, 0x48, 0xfd, 0x01, 0xe3, 0x6b, 0x14, 0x61, 0x02, 0xd7, 0x81, 0x28, 0xb6, 0x27, + 0x6a, 0x63, 0x39, 0x82, 0x4e, 0x08, 0xf1, 0x0e, 0xca, 0x30, 0x56, 0x17, 0x07, 0xda, 0x60, 0xe9, 0xeb, 0xd6, 0x3a, + 0x37, 0x84, 0xc2, 0x38, 0x81, 0x29, 0x06, 0x49, 0x9d, 0x75, 0x96, 0x09, 0xaa, 0xec, 0x98, 0x74, 0xde, 0x07, 0xe8, + 0xee, 0x5a, 0x34, 0xc5, 0xd7, 0x9d, 0x3b, 0xe8, 0x3e, 0xae, 0x5f, 0x6b, 0x91, 0x1b, 0xfc, 0x79, 0x4b, 0x84, 0x45, + 0xe0, 0xac, 0x35, 0xf9, 0xaa, 0x11, 0x0e, 0x4c, 0x49, 0xa6, 0x61, 0x2f, 0x51, 0x36, 0xdd, 0xdb, 0x6d, 0xaf, 0x77, + 0xaf, 0x88, 0xab, 0xc7, 0x58, 0xe5, 0xdd, 0xcc, 0xed, 0x9d, 0x6a, 0x2d, 0x76, 0x6f, 0xda, 0x7e, 0x8a, 0x1d, 0xb5, + 0xd6, 0x6e, 0x37, 0x9c, 0x50, 0x43, 0xbe, 0x15, 0x55, 0x5a, 0x9d, 0x6e, 0x0c, 0xda, 0x21, 0xb4, 0xb5, 0xc8, 0xe0, + 0x46, 0xf9, 0xc2, 0x09, 0x9d, 0x54, 0xc8, 0x55, 0xa7, 0x2e, 0xd8, 0x5c, 0xf1, 0x6a, 0x29, 0xd3, 0x48, 0x50, 0xb4, + 0x39, 0x8f, 0x4a, 0x9a, 0xc8, 0xb5, 0xa8, 0x22, 0x59, 0xa3, 0x5e, 0xd4, 0x6a, 0x0c, 0x10, 0x90, 0xe9, 0xac, 0xe9, + 0x41, 0x15, 0xcc, 0x86, 0x32, 0x92, 0xd3, 0xf7, 0x60, 0x69, 0x8f, 0x1c, 0x6b, 0x7d, 0x5f, 0x9d, 0x2d, 0xbe, 0xd5, + 0x13, 0x82, 0x29, 0xcc, 0x1e, 0x88, 0x08, 0xd7, 0x34, 0x86, 0x9c, 0x76, 0x89, 0xcb, 0x9a, 0x6e, 0x09, 0xf7, 0x70, + 0xbb, 0x92, 0x1d, 0xb9, 0x79, 0xd2, 0xdc, 0x5c, 0xc1, 0x8e, 0x8a, 0xf9, 0x18, 0xb4, 0x5f, 0x52, 0x5d, 0xbb, 0x34, + 0xb7, 0x1e, 0x0f, 0x02, 0x1a, 0x0c, 0x0a, 0xc3, 0xbf, 0x4e, 0x8c, 0x87, 0x27, 0x0d, 0x08, 0x92, 0x72, 0x11, 0x8e, + 0x7d, 0x23, 0xfa, 0xc9, 0x54, 0x1e, 0x72, 0xb4, 0x78, 0x87, 0x56, 0x27, 0x10, 0xd0, 0x4b, 0x84, 0x92, 0x18, 0x55, + 0xa1, 0x11, 0x41, 0x79, 0x5a, 0xfe, 0x52, 0x55, 0x87, 0x80, 0x42, 0xda, 0x57, 0x14, 0xca, 0x36, 0x89, 0xa1, 0x19, + 0x7e, 0x39, 0x9f, 0x2c, 0xf4, 0x0c, 0x0c, 0xe4, 0xfc, 0x60, 0xa1, 0x67, 0x61, 0x20, 0xe7, 0x4f, 0x16, 0xb5, 0x5b, + 0x07, 0x9a, 0x80, 0x78, 0x2e, 0x1c, 0x9d, 0x94, 0x56, 0x65, 0x0b, 0xe8, 0xe6, 0x21, 0x82, 0xfe, 0x0f, 0x7b, 0x08, + 0x3a, 0xb9, 0xd0, 0x8e, 0xdc, 0x80, 0xb6, 0x43, 0x12, 0xd8, 0x2b, 0x26, 0x15, 0x26, 0x16, 0xd1, 0x21, 0x1b, 0x83, + 0x21, 0xb6, 0xfa, 0xe0, 0x90, 0x8d, 0xa7, 0x3e, 0x09, 0x02, 0x46, 0xf7, 0x07, 0x03, 0x0e, 0x7e, 0x8b, 0x57, 0xe9, + 0xa3, 0x8d, 0x40, 0x37, 0x7d, 0x77, 0x37, 0xf4, 0x2e, 0xae, 0xe0, 0x54, 0xed, 0xee, 0x49, 0xe8, 0x26, 0xd3, 0x8e, + 0xd5, 0x6b, 0x88, 0x1b, 0xf2, 0x2b, 0xa3, 0xd1, 0xc8, 0xa6, 0x84, 0x84, 0x18, 0xce, 0xa1, 0x99, 0xd3, 0x72, 0xf9, + 0xea, 0xd6, 0xb3, 0x01, 0x19, 0x66, 0x7a, 0xcb, 0x64, 0xfd, 0x00, 0x65, 0xd5, 0x63, 0x68, 0x87, 0xde, 0x23, 0xc7, + 0x0f, 0x0f, 0xbe, 0xc9, 0xf8, 0x99, 0xc3, 0xb5, 0x87, 0x73, 0xe1, 0xbb, 0xac, 0x19, 0x99, 0x43, 0xe7, 0xd9, 0xc7, + 0xf1, 0x1e, 0xc6, 0xc9, 0xe7, 0x59, 0x28, 0x6f, 0xbc, 0xa6, 0xff, 0x51, 0xe9, 0xcd, 0x0e, 0x87, 0x9c, 0xae, 0x60, + 0xc5, 0xcd, 0xaa, 0xd0, 0xf0, 0xb3, 0xc8, 0x1b, 0x47, 0xbc, 0x26, 0x51, 0xd5, 0x7d, 0xde, 0xdb, 0x88, 0xa5, 0x1d, + 0xe3, 0x00, 0xe0, 0x44, 0xad, 0x1a, 0x76, 0xa5, 0x71, 0xad, 0x0e, 0x62, 0x44, 0x4a, 0xd8, 0x2a, 0x71, 0x24, 0x94, + 0xbf, 0x01, 0x08, 0x8b, 0xa1, 0x38, 0xde, 0x1a, 0xd6, 0x07, 0xd8, 0x0f, 0x5d, 0xa0, 0x69, 0x4e, 0xa9, 0x66, 0x00, + 0x90, 0x04, 0xfc, 0xd1, 0xd3, 0x4d, 0x43, 0x65, 0x9b, 0xe7, 0xa1, 0x65, 0x75, 0x05, 0x0f, 0xf4, 0xd4, 0x95, 0x0c, + 0x8c, 0xab, 0x3a, 0xf6, 0x36, 0xf7, 0xb7, 0x47, 0xab, 0xc8, 0x77, 0x36, 0xa9, 0x69, 0x16, 0x40, 0x8a, 0xc6, 0xa5, + 0x2f, 0xf4, 0x74, 0x02, 0xb4, 0x5e, 0x5b, 0x2a, 0xda, 0xef, 0xa3, 0x18, 0x35, 0x2e, 0x14, 0x58, 0x85, 0x09, 0x0a, + 0x87, 0x08, 0x23, 0x84, 0x7e, 0x5f, 0x86, 0x1b, 0x5f, 0x90, 0x41, 0x34, 0x5c, 0x8b, 0x0e, 0x45, 0xe4, 0x78, 0xd1, + 0xb6, 0x54, 0xd5, 0x9c, 0x34, 0x6d, 0x09, 0xbc, 0x89, 0x0c, 0xd8, 0xce, 0x3f, 0x6d, 0x88, 0x5c, 0x85, 0x0b, 0x18, + 0xbe, 0x23, 0xae, 0x05, 0xd1, 0x4d, 0x6d, 0xea, 0x6d, 0xd8, 0x21, 0x3a, 0x9a, 0xe2, 0xd1, 0x21, 0xf7, 0xdc, 0x3d, + 0xb7, 0x45, 0x7c, 0xf3, 0x19, 0x72, 0xd7, 0x74, 0xf6, 0x52, 0x84, 0x41, 0xdd, 0xb2, 0x81, 0x62, 0x1d, 0x3a, 0x41, + 0x01, 0x06, 0x70, 0xf9, 0x04, 0x74, 0x6c, 0x30, 0xa8, 0x08, 0x3e, 0x29, 0x6c, 0x9b, 0x06, 0xf9, 0x23, 0xde, 0x0d, + 0x1d, 0x5e, 0x5b, 0xf2, 0x40, 0xbc, 0xc2, 0x3e, 0x53, 0xc2, 0xfd, 0x0b, 0x0a, 0xba, 0xa3, 0xbc, 0x5c, 0x15, 0xae, + 0x4a, 0x03, 0x50, 0x65, 0xc7, 0x73, 0xad, 0x29, 0x69, 0x01, 0x2b, 0x25, 0x75, 0xe7, 0x37, 0xc1, 0x71, 0x4b, 0xa6, + 0xc2, 0xb7, 0xea, 0x46, 0x95, 0x87, 0x12, 0x45, 0x3a, 0xf6, 0x6c, 0xe7, 0x60, 0x0d, 0x80, 0xa7, 0xb0, 0xbd, 0x38, + 0x13, 0xf0, 0xb9, 0xd3, 0x2e, 0x5b, 0xe6, 0x12, 0x28, 0xea, 0x87, 0x71, 0x5e, 0x76, 0x7c, 0xb9, 0x3b, 0xda, 0xde, + 0x43, 0x6f, 0xc4, 0xc6, 0x78, 0x7d, 0x19, 0x35, 0xfd, 0xe2, 0x19, 0xae, 0x2c, 0x05, 0x79, 0xa0, 0xa9, 0x1e, 0x61, + 0x74, 0x08, 0x4c, 0x53, 0x7e, 0xc4, 0xc6, 0xd3, 0xe1, 0xd0, 0x90, 0x41, 0xaf, 0x99, 0x18, 0x0a, 0xec, 0x0b, 0x68, + 0x9d, 0x99, 0xb8, 0xc6, 0xa7, 0xed, 0x2b, 0x68, 0x75, 0x8b, 0x32, 0xb9, 0x33, 0x30, 0x7c, 0xa0, 0x25, 0x53, 0x30, + 0x55, 0x78, 0x43, 0xa4, 0x92, 0x7d, 0x5a, 0x5a, 0x87, 0x7d, 0xbb, 0x50, 0x68, 0xa1, 0x89, 0x5f, 0x65, 0x88, 0x9f, + 0xba, 0xce, 0xfc, 0xdb, 0xb4, 0x4f, 0x0d, 0x62, 0xe1, 0x48, 0x0c, 0x22, 0x7e, 0x71, 0xaa, 0x6c, 0x27, 0x84, 0x8a, + 0x8d, 0x87, 0xae, 0x75, 0xe3, 0x48, 0xaa, 0x30, 0x94, 0x42, 0xe3, 0xa9, 0xe1, 0xbe, 0x17, 0x3a, 0x7c, 0x1d, 0x66, + 0x71, 0x9b, 0x35, 0x92, 0x1a, 0xe3, 0x54, 0x98, 0x38, 0x95, 0x72, 0x15, 0x09, 0x0c, 0x94, 0x67, 0x0b, 0x83, 0x00, + 0x93, 0x98, 0x64, 0x6c, 0x2d, 0x84, 0x09, 0x63, 0xe7, 0x0a, 0xd3, 0xd4, 0x45, 0xea, 0x37, 0x03, 0x93, 0x05, 0x0d, + 0xf9, 0x3d, 0x1a, 0xad, 0xa9, 0x9a, 0x02, 0x0c, 0xe3, 0x28, 0xd5, 0xf8, 0xb7, 0x08, 0xb5, 0x19, 0x06, 0x00, 0xb6, + 0x79, 0x27, 0x33, 0x51, 0xbd, 0x16, 0x08, 0x81, 0xe6, 0xec, 0xa7, 0xe2, 0x6a, 0x67, 0x16, 0x8c, 0xa2, 0xdd, 0x5e, + 0xf9, 0x7c, 0xe0, 0x84, 0xf2, 0x58, 0x5d, 0xa0, 0x5e, 0xc9, 0xe2, 0x8d, 0x4c, 0x79, 0x2b, 0x44, 0xe6, 0x9e, 0x64, + 0x1f, 0xf2, 0x11, 0x9c, 0x57, 0xe8, 0x54, 0x6e, 0xb6, 0x89, 0x32, 0x4b, 0x92, 0x8c, 0x05, 0xc6, 0xe6, 0x25, 0x98, + 0x49, 0xcd, 0x8c, 0xe1, 0xd7, 0x10, 0x67, 0x6c, 0xe7, 0x24, 0xdc, 0xdc, 0xcf, 0x03, 0x43, 0x94, 0x72, 0xd1, 0x12, + 0x0d, 0x5b, 0x3b, 0x5e, 0x4f, 0xae, 0x09, 0xf7, 0x61, 0x23, 0xd6, 0x64, 0x8c, 0x71, 0x6d, 0x6e, 0x64, 0xfd, 0x68, + 0x81, 0x07, 0x63, 0xca, 0xfa, 0x13, 0xc8, 0xb4, 0x92, 0xb2, 0xce, 0x17, 0x46, 0xcc, 0xa4, 0x12, 0xbd, 0xdb, 0x37, + 0x3e, 0xab, 0xbb, 0x88, 0xfa, 0xad, 0xfd, 0x9e, 0xd4, 0xc3, 0x9d, 0xff, 0xa0, 0xb0, 0x06, 0x95, 0x11, 0x97, 0x11, + 0xe5, 0x99, 0x03, 0xdd, 0x34, 0x29, 0xe2, 0xf4, 0x6c, 0x15, 0x17, 0x25, 0x4f, 0xa1, 0x52, 0x4d, 0xdd, 0xa2, 0xde, + 0x04, 0xec, 0x0d, 0x91, 0x24, 0x59, 0x4b, 0x63, 0x2b, 0x76, 0x69, 0x90, 0x9e, 0x7b, 0x23, 0x2e, 0xbd, 0xaa, 0xd0, + 0x90, 0x96, 0x7a, 0x67, 0xa1, 0x92, 0xf9, 0x2b, 0xfe, 0x33, 0xa8, 0x15, 0xe8, 0x68, 0x93, 0x62, 0x3c, 0x07, 0x46, + 0x7c, 0x37, 0x98, 0xd5, 0x03, 0xc4, 0x45, 0x13, 0x94, 0x7a, 0x47, 0xec, 0xf8, 0xb9, 0xc9, 0xc3, 0xbb, 0x90, 0x73, + 0x06, 0x9f, 0x3e, 0xcc, 0x12, 0xb5, 0xd6, 0x91, 0x18, 0xa9, 0x19, 0x40, 0xd3, 0x41, 0x99, 0xf3, 0x58, 0x04, 0xb3, + 0x9e, 0x49, 0x8c, 0x7a, 0x5c, 0xff, 0x02, 0x0d, 0xb5, 0xdf, 0xac, 0x2c, 0xcf, 0xaa, 0xbb, 0x2f, 0xe1, 0xc0, 0xa6, + 0xb6, 0x82, 0x1e, 0xaf, 0x2b, 0x79, 0x79, 0xa9, 0xba, 0xed, 0x17, 0x62, 0xe4, 0x74, 0x8d, 0x6b, 0xe9, 0xbc, 0x5a, + 0xb0, 0x5e, 0x77, 0xba, 0x59, 0xdc, 0xcd, 0x32, 0x1a, 0x08, 0x6b, 0x3b, 0x9f, 0x68, 0xfe, 0xac, 0xd9, 0x76, 0x1f, + 0x6f, 0x41, 0xcc, 0x02, 0x80, 0x48, 0x0f, 0xa2, 0x60, 0x99, 0xa5, 0x3c, 0xa0, 0xf2, 0x3e, 0x8e, 0xb2, 0x50, 0x7a, + 0x39, 0xcb, 0xf8, 0x69, 0xd3, 0x58, 0xeb, 0xac, 0x50, 0x86, 0xd6, 0x46, 0x77, 0xba, 0xca, 0x10, 0xdb, 0x4f, 0xe2, + 0x6c, 0x01, 0xee, 0x8f, 0x19, 0x0a, 0x0d, 0x9d, 0x65, 0xa4, 0x89, 0x86, 0xef, 0xba, 0x67, 0x90, 0x51, 0x9c, 0xac, + 0xf3, 0x4a, 0xba, 0xd1, 0x67, 0x6d, 0x24, 0xcc, 0x3d, 0x44, 0xbf, 0x8a, 0xc1, 0xa3, 0xdc, 0xe7, 0xb5, 0xd1, 0xc9, + 0xb4, 0x8c, 0xb4, 0x3b, 0x3f, 0xa9, 0x97, 0x59, 0xaa, 0x75, 0xd8, 0x3e, 0xc3, 0xde, 0x1a, 0x93, 0xde, 0x84, 0xd4, + 0x30, 0x12, 0x9f, 0xcf, 0xa8, 0x11, 0x02, 0xda, 0x72, 0xfc, 0x1d, 0x3e, 0xc3, 0xd0, 0x14, 0x58, 0xaa, 0xb8, 0x85, + 0xdd, 0xf0, 0x35, 0x9f, 0xac, 0x5a, 0x00, 0x82, 0x59, 0xf9, 0x7a, 0x17, 0xaf, 0x84, 0xfa, 0x4c, 0x9b, 0x01, 0x20, + 0x0b, 0x4a, 0xb9, 0xe3, 0xa7, 0x54, 0x3a, 0x58, 0xa2, 0x68, 0x7b, 0x39, 0x7d, 0xa3, 0x63, 0xe3, 0x87, 0xf4, 0x5c, + 0xc0, 0x76, 0x21, 0xbf, 0x75, 0xaf, 0x5e, 0xa2, 0x22, 0xb5, 0x6d, 0xd6, 0x03, 0x7c, 0xb9, 0x41, 0x93, 0x30, 0x82, + 0x32, 0x65, 0x0a, 0x60, 0x70, 0x53, 0x8d, 0x82, 0x49, 0xab, 0x91, 0xb0, 0xa5, 0x9e, 0x64, 0xb9, 0xe9, 0x83, 0x53, + 0xdd, 0x23, 0xe8, 0xd1, 0x0e, 0x27, 0x2d, 0xfb, 0xb5, 0x82, 0xa3, 0x93, 0xab, 0x21, 0x6a, 0xe6, 0xbd, 0xb6, 0x23, + 0x43, 0xca, 0x65, 0x18, 0x08, 0xa6, 0x1c, 0xf3, 0xf4, 0xd8, 0x7a, 0x46, 0x44, 0x0f, 0x9c, 0x7d, 0xa6, 0x5b, 0x75, + 0x25, 0x01, 0xd1, 0xf1, 0x9b, 0xa7, 0xaf, 0xaf, 0xe2, 0x4b, 0x83, 0xa2, 0xd4, 0xb0, 0x88, 0x51, 0xa6, 0x7d, 0x95, + 0x84, 0xc1, 0xfb, 0xe5, 0xfd, 0x4f, 0x2a, 0x4b, 0xed, 0xf7, 0x60, 0x63, 0x45, 0x55, 0xbf, 0x94, 0xbc, 0x68, 0x0a, + 0xb0, 0xee, 0xb3, 0x44, 0x81, 0xdc, 0xef, 0x6d, 0x9a, 0xf9, 0x26, 0x6a, 0xdc, 0x6c, 0x58, 0x6f, 0x5c, 0xb7, 0x4b, + 0x6d, 0xc9, 0x8e, 0xac, 0x44, 0xce, 0x2c, 0x06, 0x33, 0x7e, 0x54, 0x18, 0x94, 0x86, 0x0d, 0xaa, 0x52, 0xf1, 0x7b, + 0x23, 0x82, 0x53, 0xc7, 0xaa, 0xc2, 0x98, 0x06, 0xcc, 0xb6, 0xa2, 0xd6, 0xa0, 0x0e, 0x4a, 0x69, 0x6b, 0x02, 0xb2, + 0xfd, 0xc6, 0x0a, 0x6a, 0x7e, 0xff, 0xcb, 0x18, 0xf2, 0x35, 0xa5, 0xa0, 0x92, 0x80, 0x9d, 0x41, 0xa3, 0xa7, 0x4a, + 0x18, 0x48, 0x41, 0xf0, 0x04, 0x28, 0x5f, 0x44, 0x8d, 0xd5, 0x6e, 0x5f, 0x9d, 0x1a, 0xa3, 0x2d, 0x20, 0xb4, 0x90, + 0x1e, 0x5d, 0xf6, 0x71, 0x1b, 0xeb, 0x40, 0xe2, 0xc1, 0x09, 0xb6, 0x73, 0x75, 0x8d, 0x46, 0x42, 0xf3, 0x87, 0x46, + 0x03, 0x5e, 0xd3, 0x0a, 0x14, 0xea, 0x39, 0x8e, 0x86, 0xce, 0x0e, 0x29, 0x88, 0xd8, 0xa0, 0x85, 0x7d, 0xf7, 0x7c, + 0x68, 0xf6, 0xf5, 0x3c, 0x59, 0x90, 0x9a, 0x4a, 0xf7, 0xb9, 0x5b, 0x42, 0xd6, 0xaa, 0x43, 0x59, 0x79, 0x80, 0xe3, + 0x85, 0x92, 0xf9, 0x3b, 0x4c, 0x6a, 0x94, 0xc6, 0x84, 0xc6, 0x88, 0x05, 0x2c, 0x09, 0xda, 0xeb, 0x81, 0xfa, 0x65, + 0x10, 0x2a, 0x9c, 0xe9, 0x89, 0xc4, 0xa7, 0x94, 0xab, 0x4f, 0x0b, 0x52, 0x4f, 0x0b, 0xe6, 0x40, 0x2f, 0x7d, 0x2b, + 0xbf, 0xb2, 0xf1, 0xd1, 0xee, 0xde, 0x35, 0x17, 0xd6, 0x31, 0xc4, 0xc5, 0x16, 0x7e, 0x73, 0x6a, 0x0a, 0xc0, 0x86, + 0xc7, 0xba, 0x2c, 0xdf, 0xa8, 0x89, 0xcc, 0xe2, 0x90, 0x44, 0x20, 0xd9, 0x6e, 0x6e, 0x6e, 0x23, 0xd8, 0xf6, 0x16, + 0x6a, 0x43, 0xfd, 0xe5, 0x6d, 0xf7, 0x7b, 0x86, 0x97, 0x7b, 0x72, 0xef, 0xa6, 0x0d, 0xe5, 0x0f, 0xf7, 0xaf, 0x92, + 0xff, 0xab, 0x4a, 0xee, 0xb7, 0xca, 0xac, 0xdb, 0xe2, 0xfd, 0xae, 0xe3, 0x96, 0x63, 0x34, 0x08, 0xac, 0x29, 0x30, + 0x90, 0x9e, 0x34, 0xa6, 0x89, 0x8e, 0xae, 0xcc, 0x98, 0xc1, 0xa3, 0x0b, 0xd0, 0x1c, 0xa6, 0xf3, 0x3c, 0x06, 0xe0, + 0x00, 0xff, 0xc8, 0x23, 0xd4, 0x3f, 0x9d, 0xe7, 0xc1, 0x59, 0x30, 0x28, 0x07, 0x81, 0xfe, 0xc4, 0x35, 0x27, 0x58, + 0x80, 0xce, 0x2d, 0x66, 0x10, 0x77, 0xd2, 0x9a, 0x39, 0xc4, 0x87, 0xc9, 0x74, 0x30, 0x88, 0xc9, 0x06, 0x40, 0xfa, + 0xe2, 0x85, 0x75, 0x0e, 0x2a, 0xf4, 0x82, 0x6c, 0xd5, 0x5d, 0x34, 0x2b, 0xf6, 0xaa, 0x9d, 0xe6, 0xfd, 0x7e, 0x3e, + 0x2f, 0x07, 0x41, 0xa3, 0xc2, 0xc2, 0x78, 0xff, 0xd1, 0xe6, 0x97, 0x46, 0x27, 0x4d, 0x30, 0x62, 0xed, 0x31, 0xaa, + 0x57, 0x3c, 0xcd, 0x68, 0xe3, 0x76, 0xac, 0x94, 0x2f, 0x20, 0x8a, 0x07, 0x86, 0xac, 0x95, 0x77, 0xe7, 0xe0, 0x75, + 0xb9, 0xf1, 0xe6, 0x88, 0x02, 0xec, 0xa6, 0x30, 0x4e, 0x6a, 0x2e, 0xba, 0xa8, 0x89, 0x67, 0xb0, 0xd3, 0xd5, 0x5b, + 0x89, 0x56, 0xe3, 0xbd, 0x78, 0xd7, 0x6c, 0xfc, 0xad, 0xdc, 0xd3, 0x65, 0xee, 0x5d, 0x00, 0xe2, 0xec, 0x5e, 0x5c, + 0xed, 0x61, 0xa9, 0x7b, 0xc1, 0xc0, 0x22, 0x87, 0xb4, 0xab, 0xd5, 0x43, 0x11, 0xa9, 0xf3, 0x18, 0x0c, 0x98, 0x4c, + 0x43, 0x6a, 0x32, 0xed, 0x15, 0x0a, 0xd2, 0xc6, 0x5a, 0x0b, 0x68, 0xc3, 0x61, 0xb1, 0x63, 0x37, 0xec, 0x4e, 0xb7, + 0x0e, 0x85, 0x12, 0x06, 0xb2, 0xae, 0x9b, 0x87, 0x5a, 0xc3, 0x13, 0x41, 0x0f, 0xaa, 0xd1, 0x7e, 0x7a, 0x28, 0x4f, + 0xda, 0x63, 0x01, 0x2e, 0x7a, 0xf8, 0xf2, 0xa5, 0xc0, 0x8b, 0xf6, 0x0e, 0xf2, 0x9c, 0xf9, 0x54, 0xf9, 0x20, 0x36, + 0xdc, 0x32, 0x7c, 0x68, 0x1f, 0xdf, 0x0a, 0x64, 0x52, 0x77, 0x34, 0xb5, 0xb5, 0x3b, 0x1a, 0xc7, 0x04, 0xfa, 0x4d, + 0x39, 0x4a, 0x99, 0x98, 0x5a, 0x96, 0xec, 0xa8, 0x97, 0x2b, 0x6f, 0xa8, 0x94, 0x1d, 0x2d, 0xdb, 0x9c, 0x5f, 0xda, + 0x48, 0xe8, 0xf7, 0xb5, 0x3b, 0x10, 0xbe, 0x51, 0xeb, 0x0d, 0x79, 0xd9, 0x10, 0xb1, 0x1c, 0x62, 0x06, 0x8e, 0x17, + 0x52, 0xb9, 0x76, 0x17, 0x4d, 0x55, 0xdd, 0xce, 0x56, 0x2e, 0x68, 0x89, 0xb7, 0x52, 0x60, 0x15, 0xa9, 0xd3, 0xeb, + 0xa9, 0xc4, 0xfb, 0x3e, 0x8a, 0xed, 0x47, 0xc0, 0x36, 0x36, 0x8e, 0xc6, 0xc6, 0x2d, 0x62, 0x83, 0xaf, 0xa2, 0x8a, + 0x16, 0x1c, 0x20, 0xb8, 0xdb, 0x92, 0x5a, 0x9a, 0x39, 0xc4, 0x7d, 0xc5, 0x03, 0xb4, 0xef, 0xe2, 0x88, 0x53, 0x01, + 0xb6, 0x75, 0xad, 0x73, 0x56, 0xcb, 0x01, 0x9b, 0x89, 0x9e, 0x7f, 0x5a, 0x35, 0x12, 0x31, 0xac, 0xb2, 0x91, 0xb2, + 0x42, 0x7b, 0x50, 0xba, 0x84, 0x8b, 0x2f, 0xc0, 0xcb, 0xf6, 0xfd, 0xca, 0xee, 0xb3, 0x25, 0xf6, 0x0f, 0xf3, 0xaa, + 0x09, 0x1e, 0x79, 0x8d, 0xb7, 0xf7, 0x30, 0xf1, 0xa5, 0x52, 0x08, 0xaf, 0x52, 0x1a, 0x4a, 0x00, 0x06, 0x49, 0x50, + 0xc3, 0x95, 0xb6, 0xcd, 0x20, 0x95, 0x31, 0xec, 0x6e, 0xf5, 0x56, 0xff, 0xa7, 0x55, 0xb8, 0xa8, 0x64, 0x31, 0x26, + 0x81, 0xce, 0xa9, 0x96, 0x9b, 0xc0, 0x82, 0x67, 0xbb, 0xe4, 0x08, 0x14, 0x76, 0x02, 0xb8, 0xa1, 0x84, 0xfd, 0x82, + 0xb7, 0xa1, 0x9c, 0xbd, 0xb2, 0x92, 0x27, 0xb7, 0x2f, 0xa9, 0xa0, 0x09, 0x99, 0x0a, 0xbb, 0x7f, 0x5b, 0x1b, 0xf6, + 0x45, 0x28, 0x47, 0x52, 0xe0, 0xe2, 0xa0, 0x73, 0x00, 0xfb, 0x83, 0x5c, 0xc6, 0xe6, 0x33, 0xe9, 0xf7, 0xd5, 0xfb, + 0xe7, 0x79, 0x96, 0x7c, 0xdc, 0x79, 0x6f, 0x78, 0x9a, 0x25, 0x03, 0x2a, 0x11, 0x53, 0xeb, 0xaa, 0x18, 0x2e, 0xb5, + 0x8b, 0x71, 0x83, 0x64, 0xc4, 0xf7, 0x52, 0x87, 0x18, 0x31, 0xbe, 0xc8, 0x0e, 0x49, 0xc9, 0xe9, 0xb2, 0xee, 0xec, + 0xb9, 0x16, 0xcd, 0xa0, 0x31, 0xdc, 0x8e, 0xf7, 0x92, 0x5e, 0x01, 0x2a, 0x40, 0x74, 0xcf, 0x02, 0xd7, 0xf0, 0xe6, + 0x92, 0x68, 0x6c, 0xe9, 0x69, 0x4b, 0x34, 0x70, 0xaf, 0x4c, 0x48, 0xaa, 0x8d, 0x03, 0x2c, 0x62, 0x5d, 0x7f, 0x0c, + 0x0b, 0x00, 0x6a, 0x35, 0x48, 0xaf, 0xf4, 0x15, 0xa1, 0x2a, 0x09, 0xc1, 0xe8, 0x44, 0xc2, 0xcb, 0x80, 0xc6, 0x99, + 0x49, 0xb4, 0xb0, 0xc1, 0x01, 0x7d, 0x51, 0x99, 0x44, 0x63, 0x43, 0x1e, 0x50, 0x6e, 0xd3, 0x00, 0x06, 0x1f, 0x24, + 0x49, 0xf4, 0xf5, 0xd2, 0x24, 0x81, 0xa0, 0x04, 0xe5, 0x1b, 0xf4, 0xe7, 0xd2, 0xf3, 0xb1, 0xfc, 0xdd, 0x3b, 0x94, + 0x7e, 0x08, 0x0b, 0x90, 0x29, 0xea, 0x8a, 0x69, 0xc6, 0x8e, 0xb2, 0x6e, 0x63, 0x12, 0xcf, 0xd3, 0xee, 0xb6, 0x50, + 0x2e, 0x5d, 0xe0, 0x57, 0x96, 0x21, 0x8e, 0xf5, 0xf3, 0x78, 0xc5, 0x8e, 0x43, 0xae, 0xf1, 0xd2, 0x9f, 0xc7, 0x2b, + 0x9c, 0x21, 0x5a, 0xb5, 0x12, 0x88, 0xf2, 0x5f, 0xb5, 0x81, 0x43, 0xdc, 0x27, 0x18, 0xe4, 0xa2, 0xf2, 0x1e, 0x08, + 0xe4, 0x6d, 0x05, 0x11, 0x69, 0x66, 0xd7, 0x61, 0x44, 0xaa, 0x9d, 0x24, 0xf3, 0xe5, 0x8f, 0x32, 0x13, 0xde, 0x37, + 0xf0, 0xd8, 0x6c, 0x96, 0x4d, 0x31, 0x5f, 0xa8, 0x60, 0x0e, 0xee, 0x13, 0x15, 0x97, 0xa2, 0xf2, 0x9f, 0xb0, 0x0b, + 0x5e, 0x8c, 0x07, 0xaf, 0xd7, 0x08, 0xb0, 0x5f, 0xf9, 0x4f, 0xde, 0x98, 0xbd, 0xb5, 0x6e, 0x7c, 0x99, 0x89, 0xf8, + 0xc0, 0x47, 0xb7, 0x94, 0x8f, 0xee, 0xbc, 0x4c, 0x7f, 0x36, 0xa0, 0x44, 0x46, 0x65, 0xc5, 0x57, 0x2b, 0x9e, 0xce, + 0x6e, 0x93, 0x28, 0x1b, 0x55, 0x5c, 0xc0, 0xf4, 0x82, 0xe3, 0x5d, 0xb2, 0x3e, 0xcf, 0x92, 0xd7, 0x10, 0x7b, 0x60, + 0x25, 0x15, 0x16, 0x3f, 0x2c, 0x33, 0xb5, 0x98, 0x85, 0xac, 0xa4, 0xe0, 0xc1, 0xec, 0x3a, 0x89, 0xde, 0x2e, 0x3d, + 0x24, 0x35, 0x33, 0x65, 0x9b, 0xda, 0x11, 0x6a, 0xe3, 0xeb, 0x48, 0x37, 0xda, 0x02, 0x00, 0xee, 0xd9, 0x22, 0x8d, + 0x24, 0x13, 0xc3, 0x49, 0xcd, 0xb8, 0x49, 0x2f, 0x30, 0x35, 0xae, 0x59, 0x45, 0x13, 0x67, 0x21, 0x03, 0x7a, 0x7f, + 0xc0, 0xcb, 0xc1, 0xe7, 0x0c, 0xee, 0x3f, 0x68, 0x0d, 0x5c, 0x1e, 0x16, 0xfd, 0xbe, 0x3c, 0x2c, 0xb6, 0xdb, 0xf2, + 0x28, 0xee, 0xf7, 0xe5, 0x51, 0x6c, 0xf8, 0x07, 0xa5, 0xd8, 0x36, 0xe6, 0x06, 0x09, 0xcd, 0x25, 0x44, 0x2d, 0x1a, + 0xc1, 0x1f, 0x9a, 0xe5, 0x5c, 0x44, 0xf9, 0x61, 0xd2, 0xef, 0xf7, 0x96, 0x33, 0x31, 0xc8, 0x87, 0x49, 0x94, 0x0f, + 0x13, 0xcf, 0x09, 0xf1, 0x57, 0xcf, 0x09, 0x51, 0xd1, 0xc0, 0x15, 0x9c, 0x19, 0x80, 0x28, 0xe0, 0xd3, 0x3f, 0xaa, + 0x6b, 0x29, 0x74, 0x2d, 0xb1, 0xaa, 0x25, 0xd1, 0x15, 0xd4, 0xec, 0xba, 0x08, 0x4b, 0x2c, 0x85, 0x2e, 0xd9, 0x9f, + 0x4b, 0xe0, 0x89, 0x72, 0x5e, 0x6d, 0x80, 0x81, 0x8d, 0xf0, 0xce, 0x61, 0xc2, 0x49, 0xac, 0x6b, 0x40, 0x3b, 0xdd, + 0xd4, 0xf4, 0x82, 0xae, 0xe8, 0x25, 0xf2, 0xb3, 0x17, 0x60, 0xb0, 0x74, 0xc8, 0xf2, 0xe9, 0x60, 0x70, 0x41, 0x56, + 0xac, 0x9c, 0x87, 0xf1, 0x20, 0x5c, 0xcf, 0xf2, 0xe1, 0x45, 0x74, 0x41, 0xc8, 0x57, 0xc5, 0x82, 0xf6, 0x56, 0xa3, + 0xf2, 0x63, 0x06, 0xe1, 0xfd, 0xd2, 0x59, 0x98, 0x99, 0x38, 0x1f, 0xab, 0xd1, 0x2d, 0x5d, 0x41, 0xfc, 0x1a, 0xb8, + 0x91, 0x90, 0x08, 0x3a, 0x72, 0x49, 0x57, 0x74, 0x4d, 0xa5, 0x99, 0x61, 0x8c, 0xd6, 0x6d, 0x8f, 0x93, 0x04, 0x1c, + 0x93, 0x5d, 0xf1, 0xd1, 0x58, 0x15, 0xde, 0xf5, 0x1d, 0xa1, 0xbd, 0x5e, 0xe2, 0x06, 0xe9, 0xbb, 0xf6, 0x20, 0x01, + 0x23, 0x32, 0x52, 0x03, 0x65, 0x46, 0x46, 0x52, 0x33, 0xa9, 0x38, 0x24, 0xb1, 0x3f, 0x24, 0x6a, 0x1c, 0x12, 0x7f, + 0x1c, 0x72, 0x3d, 0x0e, 0xc8, 0xdd, 0x2f, 0xd9, 0x98, 0xa6, 0x6c, 0x4c, 0xd7, 0x6a, 0x54, 0xe8, 0x15, 0x3d, 0xd7, + 0xd4, 0xf1, 0x8c, 0xbd, 0x81, 0x03, 0x7b, 0x10, 0xe6, 0xb3, 0x78, 0xf8, 0x26, 0x7a, 0x43, 0xc8, 0x57, 0x92, 0x5e, + 0xab, 0x4b, 0x19, 0x04, 0x42, 0xbc, 0x02, 0xe7, 0x52, 0x17, 0xea, 0xe4, 0xca, 0xec, 0x38, 0x7c, 0xba, 0x6c, 0x3c, + 0x9d, 0x43, 0x44, 0x1f, 0xb4, 0x52, 0xe9, 0xf7, 0xc3, 0x0b, 0x56, 0xce, 0xcf, 0xc2, 0x31, 0x01, 0x1c, 0x1e, 0x3d, + 0x9c, 0x17, 0xa3, 0x5b, 0x7a, 0x31, 0xba, 0x23, 0x60, 0xe1, 0x35, 0x9e, 0xae, 0x0f, 0x59, 0x3c, 0x1d, 0x0c, 0xd6, + 0x48, 0xd5, 0x55, 0xee, 0x35, 0x59, 0xd0, 0x0b, 0x9c, 0x08, 0x02, 0x0c, 0x7d, 0x26, 0xd6, 0x86, 0x86, 0xbf, 0x61, + 0xf0, 0xf1, 0x1d, 0xbb, 0x18, 0xdd, 0xd1, 0x5b, 0xf6, 0x66, 0x3b, 0x9e, 0x02, 0x33, 0xb5, 0x9a, 0x85, 0x77, 0x87, + 0x97, 0xb3, 0x4b, 0x76, 0x17, 0xdd, 0x1d, 0x41, 0x43, 0xaf, 0xd8, 0x1d, 0x02, 0x2e, 0xa5, 0x8f, 0x97, 0x83, 0x37, + 0x64, 0x7f, 0x30, 0x48, 0x49, 0x14, 0x5e, 0x87, 0x5e, 0x2b, 0xdf, 0xd0, 0x3b, 0x42, 0x57, 0xec, 0x16, 0x47, 0xe3, + 0x92, 0xe1, 0x07, 0xe7, 0xec, 0xae, 0xbe, 0x0e, 0xbd, 0xdd, 0x9c, 0x88, 0x4e, 0x10, 0x23, 0xf4, 0x35, 0x70, 0x34, + 0xcb, 0x85, 0x99, 0x80, 0x27, 0x73, 0x91, 0xd1, 0xa2, 0xd0, 0x0c, 0xc4, 0x59, 0x09, 0x88, 0x25, 0x51, 0xf7, 0x9b, + 0x8d, 0xce, 0x60, 0x39, 0xf7, 0xfb, 0xbd, 0xca, 0xd0, 0x03, 0x44, 0xce, 0xec, 0xa4, 0x07, 0x3d, 0x9f, 0x1e, 0xe0, + 0x27, 0x7a, 0xd5, 0x20, 0x4e, 0xe6, 0x77, 0xcb, 0xe8, 0x57, 0x8f, 0x3e, 0xfc, 0xd0, 0x4d, 0x79, 0x44, 0xfe, 0xef, + 0x53, 0x9e, 0x32, 0x8f, 0xde, 0x54, 0x1e, 0x08, 0x9e, 0xb7, 0x26, 0x95, 0x46, 0xa2, 0x1a, 0x9d, 0xad, 0x62, 0xd0, + 0x46, 0xa2, 0xb6, 0x41, 0x3f, 0xa1, 0x85, 0x15, 0x44, 0xc8, 0x39, 0x78, 0x01, 0x06, 0xa9, 0x10, 0x2a, 0x47, 0x2d, + 0x4a, 0x34, 0x04, 0xc9, 0x65, 0xc9, 0x55, 0xf8, 0x1c, 0x42, 0xd5, 0xe9, 0xe3, 0x4c, 0x84, 0x0d, 0x3d, 0x0e, 0x7d, + 0x00, 0xf8, 0x5f, 0x76, 0xc8, 0x45, 0xc9, 0x2f, 0xf1, 0x6c, 0x6e, 0x13, 0x8c, 0x82, 0x25, 0xa2, 0x19, 0xda, 0x06, + 0xb1, 0x1f, 0x4b, 0x82, 0xf5, 0x48, 0x1a, 0x8f, 0x4a, 0x73, 0x44, 0xf8, 0x51, 0x7c, 0x14, 0x3d, 0x8d, 0x0d, 0x89, + 0xe4, 0x48, 0x22, 0xf9, 0x00, 0x08, 0x27, 0x41, 0x7f, 0x71, 0xd7, 0x64, 0xd7, 0x42, 0x62, 0xd0, 0x9f, 0x96, 0x4c, + 0xcb, 0xee, 0x55, 0x8f, 0x7d, 0x45, 0x90, 0x3b, 0xa6, 0xff, 0xf2, 0xfa, 0xf0, 0xaf, 0x25, 0xce, 0xa0, 0xf5, 0x7c, + 0x51, 0x9d, 0x99, 0x79, 0x83, 0x1b, 0x79, 0x5d, 0xd6, 0xae, 0xcb, 0x17, 0x7c, 0x8f, 0xdf, 0x56, 0x5c, 0xa4, 0xe5, + 0xde, 0xcf, 0x55, 0x1b, 0xcf, 0xa9, 0x5c, 0xaf, 0x5c, 0x9c, 0x15, 0x65, 0x9c, 0xea, 0x49, 0x5d, 0x8c, 0x35, 0x6c, + 0xc3, 0xef, 0x11, 0x75, 0x25, 0x2d, 0x47, 0x4f, 0x29, 0x57, 0xcd, 0x94, 0x8b, 0x75, 0x9e, 0xff, 0xb4, 0x93, 0x8a, + 0x53, 0xdc, 0x4c, 0x41, 0xaa, 0xd4, 0x72, 0x01, 0xd5, 0x73, 0xd4, 0x72, 0xb7, 0x34, 0x3b, 0xc0, 0xb9, 0x6d, 0xaa, + 0x8f, 0x95, 0xd9, 0x85, 0x97, 0xdc, 0xb8, 0x3f, 0x99, 0x32, 0x2c, 0x18, 0x85, 0x36, 0xab, 0xae, 0xb4, 0x7d, 0xa1, + 0x75, 0x1a, 0x86, 0x2b, 0x3f, 0x5e, 0x40, 0xba, 0x80, 0x71, 0xbc, 0x28, 0x99, 0x18, 0xb7, 0x47, 0x6f, 0x05, 0xf1, + 0x25, 0x5b, 0x81, 0xf4, 0xfb, 0x3d, 0xe1, 0xed, 0xba, 0x8e, 0xb6, 0x7b, 0xe2, 0x94, 0x51, 0xb9, 0x8a, 0xc5, 0xf7, + 0xf1, 0xca, 0x40, 0x26, 0xab, 0xe3, 0xb1, 0x31, 0xa6, 0xd3, 0x7f, 0x24, 0xa1, 0x5f, 0x08, 0x05, 0x9f, 0xf5, 0xd2, + 0xca, 0x93, 0xdb, 0xc3, 0x32, 0xae, 0xd1, 0x2b, 0x71, 0xa5, 0xfb, 0x66, 0xa4, 0x90, 0x7a, 0xe4, 0xab, 0xa6, 0x80, + 0xde, 0x8c, 0x7d, 0x33, 0x15, 0xe6, 0xed, 0x9e, 0x31, 0x57, 0x08, 0x56, 0xaa, 0xec, 0xf6, 0x9d, 0x1a, 0x53, 0x31, + 0x83, 0x29, 0xb6, 0x9d, 0xc5, 0xa4, 0x5b, 0xf9, 0xa7, 0x9d, 0xfb, 0x65, 0xde, 0xe1, 0xae, 0xa8, 0xdf, 0x02, 0x17, + 0x9a, 0x15, 0x65, 0xd5, 0x96, 0x0d, 0xdb, 0xc6, 0x1b, 0x59, 0x28, 0x36, 0xc0, 0xb2, 0xe7, 0xbe, 0x85, 0x07, 0x88, + 0x9b, 0x70, 0xcf, 0x2e, 0x6a, 0xb8, 0x31, 0x7c, 0x59, 0x49, 0xbe, 0x2b, 0x8d, 0xb9, 0xf4, 0xa9, 0xd2, 0xc4, 0x70, + 0xb2, 0x18, 0x71, 0x91, 0x2e, 0xea, 0xcc, 0xae, 0x85, 0xcf, 0x78, 0x19, 0xce, 0xf9, 0xc2, 0xe8, 0xa6, 0x74, 0xe9, + 0x05, 0x8b, 0x75, 0xa7, 0x37, 0x2b, 0x8d, 0x95, 0x12, 0x71, 0x6b, 0x96, 0x09, 0x94, 0xa5, 0xac, 0x95, 0xf0, 0xa6, + 0x68, 0xd9, 0x4a, 0x1a, 0x79, 0xcf, 0x1c, 0xdc, 0xc7, 0x7e, 0x40, 0x4c, 0x64, 0x13, 0x98, 0x14, 0x0d, 0x1d, 0xd0, + 0xae, 0xba, 0xf0, 0xcd, 0xa8, 0x07, 0x83, 0xdc, 0x92, 0x44, 0xac, 0x20, 0xc5, 0x0a, 0xd6, 0x35, 0x2b, 0xe6, 0xf9, + 0x82, 0x5e, 0x30, 0x39, 0x4f, 0x17, 0x74, 0xc5, 0xe4, 0x7c, 0x8d, 0x37, 0xa1, 0x0b, 0x38, 0x21, 0xc9, 0x26, 0x56, + 0x0a, 0xd8, 0x0b, 0xbc, 0xbc, 0xe1, 0x99, 0xaa, 0x69, 0xd9, 0xa5, 0xe2, 0x00, 0xe3, 0xf3, 0x32, 0x0c, 0xcb, 0xe1, + 0x05, 0x58, 0x4b, 0xec, 0x87, 0xab, 0x39, 0x5f, 0xa8, 0xdf, 0x10, 0x75, 0x3e, 0x09, 0x15, 0xbb, 0x60, 0xf7, 0x02, + 0x99, 0x5e, 0xcd, 0xf9, 0x42, 0x8d, 0x84, 0x2e, 0xf8, 0xca, 0x1a, 0x9b, 0xc4, 0x9e, 0xa0, 0x65, 0x16, 0xcf, 0xc7, + 0x8b, 0x28, 0xae, 0x61, 0x19, 0x9e, 0xaa, 0x99, 0x69, 0xc9, 0x7f, 0x12, 0xb5, 0xa1, 0x89, 0xbe, 0xc1, 0x2a, 0xf2, + 0x87, 0xc7, 0x47, 0x97, 0x40, 0xc6, 0xce, 0xae, 0x64, 0xe6, 0x43, 0xdf, 0x47, 0x06, 0xf7, 0xdc, 0x94, 0x33, 0xae, + 0x82, 0x44, 0x19, 0xb8, 0x7b, 0x35, 0x4b, 0xc6, 0x5a, 0x84, 0xef, 0x1e, 0x15, 0x45, 0x9f, 0x49, 0xd3, 0x80, 0xee, + 0x23, 0xc1, 0x1c, 0xe8, 0xbd, 0x42, 0x87, 0xcb, 0x6a, 0x9b, 0x09, 0xf8, 0x8b, 0x04, 0xf9, 0xad, 0xd0, 0xab, 0x1a, + 0x83, 0x2a, 0xda, 0x45, 0x2c, 0xfd, 0xfb, 0x88, 0x1f, 0x65, 0xf3, 0x2f, 0x73, 0x8f, 0x57, 0x12, 0x06, 0x3f, 0xa4, + 0x66, 0x93, 0xcc, 0xdb, 0x2b, 0xf6, 0x3d, 0x74, 0xd4, 0xa3, 0xd6, 0x78, 0x5f, 0xbd, 0xe0, 0x14, 0x62, 0x94, 0x50, + 0x74, 0x12, 0x0c, 0xe0, 0x76, 0x09, 0x29, 0xee, 0x06, 0xbb, 0x69, 0x5e, 0xf3, 0xa2, 0xe0, 0x7c, 0x5d, 0x55, 0x81, + 0x1f, 0xd0, 0x70, 0xbe, 0xd8, 0x0d, 0x61, 0x38, 0xa6, 0xad, 0x6b, 0x18, 0x84, 0x19, 0xc3, 0x48, 0x08, 0x5e, 0xff, + 0xa2, 0x27, 0x34, 0x89, 0x57, 0xdf, 0xf1, 0x4f, 0x19, 0x2f, 0x14, 0x91, 0x06, 0x11, 0x52, 0x37, 0xf1, 0x8d, 0x4c, + 0x93, 0x02, 0x0a, 0x01, 0x46, 0x01, 0x95, 0xd8, 0xd0, 0x54, 0xfc, 0xad, 0x16, 0x1f, 0xfc, 0xd4, 0x74, 0x3c, 0x1a, + 0xd7, 0xad, 0xce, 0xa8, 0xa0, 0x33, 0xd0, 0xa3, 0x56, 0xd4, 0xd3, 0xa0, 0x95, 0x60, 0x1a, 0x69, 0xde, 0xba, 0x87, + 0xc0, 0x2b, 0xd3, 0xe2, 0x9d, 0x07, 0x74, 0x73, 0xe6, 0x83, 0x27, 0x8f, 0xe9, 0x99, 0x43, 0x4f, 0xae, 0xd8, 0x51, + 0xd5, 0x43, 0xed, 0xbd, 0x19, 0xa1, 0xa0, 0xdf, 0xc7, 0x14, 0xe8, 0x46, 0x50, 0x7b, 0x57, 0xf7, 0x1f, 0xcb, 0x5d, + 0x0e, 0xdf, 0x71, 0x96, 0x1b, 0xc0, 0x52, 0x91, 0xb5, 0x02, 0x8f, 0x02, 0xd4, 0xa5, 0x32, 0x84, 0x2d, 0xe6, 0x70, + 0xa8, 0xec, 0x56, 0xad, 0x86, 0x92, 0x1c, 0x96, 0x23, 0x70, 0x08, 0x5d, 0x97, 0x83, 0x72, 0xb4, 0xcc, 0xaa, 0xf7, + 0xf8, 0x5b, 0xb3, 0x0e, 0x49, 0x76, 0x1f, 0xeb, 0xc0, 0x2d, 0xeb, 0x30, 0xfd, 0x68, 0x90, 0x02, 0xd0, 0x64, 0x23, + 0x70, 0x09, 0xc0, 0x7b, 0xfb, 0x8f, 0x08, 0xb5, 0x32, 0xbd, 0x97, 0xb1, 0x50, 0xdf, 0x37, 0x92, 0xa0, 0x84, 0x66, + 0x42, 0xe5, 0x58, 0x0a, 0xde, 0x79, 0xa4, 0x73, 0x52, 0x67, 0xe2, 0x3d, 0x88, 0xd3, 0xc2, 0x07, 0xf6, 0x16, 0x04, + 0xe7, 0x2c, 0xe8, 0x1d, 0xde, 0x66, 0xb5, 0xd4, 0x46, 0x0f, 0x14, 0xc0, 0xef, 0x06, 0x77, 0x08, 0xf2, 0xd5, 0x18, + 0xae, 0x95, 0xbc, 0x09, 0xf9, 0xb0, 0xa0, 0x07, 0x64, 0x60, 0x9f, 0xc5, 0x30, 0xa6, 0x07, 0xe4, 0xd0, 0x3e, 0x4b, + 0x37, 0x80, 0x03, 0xa9, 0x47, 0x95, 0x1e, 0x40, 0x83, 0x7e, 0xb3, 0x2d, 0xb2, 0x24, 0xeb, 0xc7, 0xd2, 0x28, 0x62, + 0xa0, 0x4a, 0x10, 0x51, 0x8b, 0x7f, 0x3d, 0x98, 0xeb, 0x0e, 0x73, 0x81, 0x30, 0x07, 0x03, 0x0e, 0xe2, 0x36, 0x08, + 0xcd, 0x01, 0xb3, 0xb9, 0x8d, 0x04, 0xbd, 0xb3, 0x86, 0x99, 0x1d, 0xfd, 0xe1, 0x56, 0x82, 0x6f, 0xb2, 0xd6, 0xa8, + 0xf3, 0xe2, 0x10, 0x08, 0x82, 0x37, 0x85, 0xaa, 0xf6, 0xaa, 0x07, 0x36, 0xde, 0xaa, 0x1f, 0xdb, 0xed, 0x78, 0x2a, + 0xdc, 0xb5, 0x5f, 0x50, 0x38, 0xf9, 0x94, 0xfc, 0xeb, 0xbd, 0xc9, 0xe0, 0xc0, 0xc8, 0xf0, 0xa5, 0xb7, 0x7f, 0xe1, + 0x6b, 0x2d, 0xdd, 0x13, 0x83, 0x92, 0x3c, 0x3e, 0x50, 0xf4, 0xef, 0x5e, 0x59, 0xf9, 0xd4, 0x4e, 0xff, 0x76, 0x6b, + 0xd6, 0xe7, 0xe1, 0x68, 0xb2, 0xdd, 0xf6, 0xe2, 0x4a, 0x7b, 0xac, 0xe9, 0x05, 0x81, 0xce, 0xf5, 0x64, 0xff, 0x00, + 0xa2, 0x22, 0x34, 0xe3, 0x6e, 0x96, 0x0d, 0x89, 0x8c, 0x1f, 0xa7, 0xb3, 0x6c, 0x08, 0x76, 0xb8, 0x17, 0x95, 0xb8, + 0x1c, 0xb5, 0x36, 0x38, 0x3d, 0x4b, 0x42, 0x08, 0xe5, 0x80, 0x95, 0xdd, 0xaa, 0x3f, 0x77, 0xca, 0x4c, 0x48, 0x4d, + 0x56, 0xb7, 0x53, 0xba, 0x87, 0x69, 0xbe, 0x67, 0x46, 0x70, 0xc0, 0xbd, 0xfd, 0x55, 0x7f, 0x0c, 0x93, 0x4c, 0x93, + 0x53, 0x24, 0xbf, 0x48, 0x4f, 0x21, 0x69, 0x87, 0x9e, 0x2a, 0x02, 0x38, 0xa1, 0xf6, 0x63, 0xf8, 0x0d, 0xe3, 0xfe, + 0x5d, 0xf3, 0xb5, 0x9b, 0x8a, 0xe8, 0x29, 0xc5, 0x32, 0x35, 0x39, 0x4d, 0xb2, 0x22, 0x81, 0xa8, 0x8d, 0xaa, 0x19, + 0xd1, 0x13, 0x17, 0xf3, 0x51, 0x11, 0x3e, 0xaf, 0xd6, 0xff, 0x19, 0xc2, 0x67, 0x14, 0x6e, 0x00, 0x97, 0x57, 0x5c, + 0x9e, 0x87, 0xcf, 0x9e, 0xd2, 0xbd, 0xc9, 0x37, 0x07, 0x74, 0xef, 0xe0, 0xc9, 0x33, 0x02, 0xb0, 0x68, 0x97, 0xe7, + 0xe1, 0xc1, 0xb3, 0x67, 0x74, 0xef, 0xdb, 0x6f, 0xe9, 0xde, 0xe4, 0xc9, 0x41, 0x23, 0x6d, 0xf2, 0xec, 0x5b, 0xba, + 0xf7, 0xcd, 0xd3, 0x46, 0xda, 0xc1, 0xf8, 0x19, 0xdd, 0xfb, 0xfb, 0x37, 0x26, 0xed, 0x6f, 0x90, 0xed, 0xdb, 0x03, + 0xfc, 0xcf, 0xa4, 0x4d, 0x9e, 0x3d, 0xa1, 0x7b, 0x93, 0x31, 0x54, 0xf2, 0xcc, 0x55, 0x32, 0x9e, 0xc0, 0xc7, 0x4f, + 0xe0, 0xbf, 0xbf, 0x91, 0x60, 0x41, 0x2b, 0xc9, 0x72, 0x81, 0xfa, 0x33, 0x14, 0x71, 0xa2, 0x6a, 0x22, 0xe1, 0x21, + 0x66, 0x56, 0xdf, 0xc4, 0x61, 0x40, 0x5c, 0x3a, 0x14, 0x44, 0xf7, 0xc6, 0xa3, 0x67, 0x24, 0xf0, 0xe1, 0xe9, 0x6e, + 0x7c, 0x90, 0xb1, 0x5c, 0xcc, 0xb3, 0xaf, 0x72, 0x13, 0x5b, 0xc1, 0x03, 0xb0, 0xfa, 0xe8, 0xe7, 0xaa, 0xe4, 0x3c, + 0xfb, 0xaa, 0x92, 0xbb, 0xb9, 0x7e, 0x6b, 0x01, 0xca, 0xfb, 0xab, 0x96, 0xdd, 0x14, 0x2a, 0x74, 0x5a, 0x6b, 0xf4, + 0xd9, 0x47, 0x4c, 0x1f, 0x0c, 0xbc, 0x1b, 0xf6, 0x3f, 0x76, 0xca, 0x69, 0x7d, 0xa3, 0x51, 0xa8, 0x51, 0x79, 0x48, + 0xd8, 0x11, 0x14, 0x3d, 0x18, 0x00, 0x4f, 0xe0, 0xe1, 0xbe, 0xfd, 0x9b, 0x65, 0x7c, 0xec, 0x28, 0xe3, 0x67, 0x94, + 0x21, 0xa0, 0x51, 0x0f, 0xb3, 0x9b, 0x1e, 0x36, 0xba, 0xd5, 0x4b, 0x96, 0xea, 0x64, 0x6a, 0x7a, 0x06, 0xfb, 0x5a, + 0xd7, 0x72, 0xcf, 0x88, 0xa2, 0xe5, 0xc5, 0x5e, 0xca, 0x67, 0x15, 0xfb, 0xc7, 0x12, 0xd5, 0x5b, 0x51, 0xe3, 0x8d, + 0xcc, 0x66, 0x15, 0xfb, 0xde, 0xbc, 0x01, 0x6e, 0x86, 0xfd, 0xa6, 0x9e, 0xfc, 0xc0, 0x19, 0x5c, 0xda, 0xf6, 0x28, + 0x13, 0x23, 0xc0, 0x0a, 0xc8, 0xc0, 0x81, 0x07, 0x40, 0x07, 0xfd, 0xd1, 0xde, 0x6e, 0x55, 0x4a, 0xb3, 0xcf, 0x16, + 0x06, 0xd0, 0x30, 0x6f, 0x13, 0x57, 0xf6, 0xef, 0x0d, 0x79, 0x09, 0x0a, 0xb7, 0x9a, 0xe5, 0xed, 0x14, 0x86, 0x10, + 0x82, 0x3f, 0x2e, 0x19, 0x00, 0x0e, 0x04, 0x18, 0x8c, 0xb5, 0x0c, 0xa8, 0xd9, 0xf2, 0xd1, 0x86, 0x2b, 0xf5, 0x24, + 0x70, 0x06, 0x17, 0xb2, 0x48, 0xf8, 0x89, 0x16, 0xfb, 0xa3, 0xf5, 0xa3, 0xef, 0xdb, 0xe3, 0xc1, 0xda, 0xf7, 0xf8, + 0x48, 0x7f, 0xd6, 0xb8, 0x0e, 0x6c, 0x5a, 0xbe, 0xf1, 0xa2, 0xb6, 0x12, 0x8f, 0x12, 0x78, 0x03, 0x13, 0x91, 0xc2, + 0x20, 0xd5, 0x02, 0xc7, 0xa0, 0xbc, 0xb1, 0x10, 0x4b, 0xd5, 0xd5, 0x0d, 0xb6, 0x20, 0x32, 0x04, 0x0f, 0xb7, 0xdf, + 0x97, 0x2a, 0x70, 0x54, 0xbf, 0xcf, 0xa5, 0xef, 0xf6, 0x64, 0xec, 0xc8, 0x71, 0xea, 0xa7, 0xc2, 0xc1, 0x7f, 0x93, + 0xba, 0x36, 0x96, 0x2b, 0x29, 0xb3, 0x2c, 0x0b, 0x3b, 0x0a, 0xb5, 0xdc, 0xa3, 0xf2, 0x20, 0xf9, 0x42, 0x0e, 0x91, + 0x2c, 0x30, 0x0a, 0x05, 0x19, 0x4e, 0xa8, 0x18, 0xad, 0x45, 0xb9, 0xcc, 0x2e, 0xaa, 0x70, 0xa3, 0x14, 0xca, 0x9c, + 0xa2, 0x6f, 0x37, 0x38, 0x90, 0x90, 0x28, 0x2b, 0xdf, 0xc6, 0x6f, 0x43, 0x04, 0xab, 0xe3, 0xda, 0x16, 0x8a, 0x7b, + 0xfb, 0x93, 0xa7, 0x5d, 0xfc, 0x91, 0x71, 0x01, 0x75, 0xb1, 0x98, 0x86, 0x13, 0x1b, 0xfb, 0xc6, 0x7d, 0x61, 0x35, + 0x3d, 0x00, 0xf5, 0x5d, 0x2a, 0x31, 0x82, 0xfa, 0xca, 0xd8, 0xc7, 0xf6, 0x18, 0x93, 0x33, 0x88, 0x35, 0xac, 0x72, + 0x66, 0xaa, 0x6f, 0x84, 0x1d, 0x01, 0x70, 0x23, 0xb4, 0x46, 0x47, 0x26, 0xa9, 0x42, 0x3c, 0x2f, 0x55, 0xf8, 0xd6, + 0x8c, 0xd0, 0x31, 0x78, 0x53, 0xd9, 0x46, 0x66, 0xd2, 0x17, 0x0c, 0x9a, 0x63, 0x5b, 0x47, 0x61, 0xb5, 0x95, 0x65, + 0x47, 0x00, 0x37, 0x90, 0x1d, 0x9a, 0x8b, 0xe7, 0xac, 0x9a, 0x67, 0x8b, 0xc8, 0x04, 0x05, 0x5c, 0x0a, 0xcb, 0xa0, + 0x7d, 0xba, 0x47, 0xb6, 0xe3, 0x10, 0xba, 0xe1, 0x3e, 0x82, 0xf1, 0xb4, 0x9b, 0x82, 0x15, 0x44, 0x23, 0xc4, 0xc3, + 0x8c, 0x59, 0x7c, 0xaf, 0x34, 0xe5, 0xa9, 0x6a, 0x09, 0x04, 0x8e, 0x42, 0xa8, 0x8b, 0x5d, 0xa3, 0x04, 0x97, 0xa9, + 0x11, 0xcc, 0x60, 0xc7, 0x8e, 0xd4, 0x76, 0xc9, 0x39, 0x1d, 0xaa, 0x29, 0x2d, 0xf5, 0x94, 0x6a, 0x5f, 0x43, 0x31, + 0x2f, 0xd1, 0x43, 0x0f, 0x5c, 0x0f, 0xb4, 0x43, 0x5e, 0x49, 0x27, 0x26, 0x82, 0x4e, 0xab, 0x4d, 0xd8, 0xb9, 0x91, + 0x6e, 0x59, 0x8d, 0xbc, 0x63, 0x68, 0x76, 0xc4, 0x4b, 0x3f, 0x50, 0x17, 0x40, 0x84, 0xdc, 0xdb, 0x22, 0x73, 0x44, + 0xb3, 0xac, 0x7c, 0x05, 0x65, 0x71, 0xc4, 0xd6, 0x15, 0x70, 0x2d, 0x05, 0x93, 0x4b, 0x1e, 0xf1, 0x14, 0x11, 0x01, + 0x8f, 0x95, 0x76, 0x7d, 0xa7, 0x25, 0x84, 0x66, 0x29, 0x10, 0x37, 0x17, 0xc5, 0xb9, 0xb6, 0x81, 0x2c, 0x80, 0xbe, + 0xfd, 0x94, 0x5d, 0x79, 0xe1, 0x60, 0x37, 0x57, 0x99, 0x78, 0xc1, 0x2f, 0x32, 0xc1, 0x53, 0x04, 0xbb, 0xba, 0x35, + 0x0f, 0xdc, 0xb1, 0x6d, 0x60, 0xf9, 0xf6, 0x1d, 0x2c, 0x98, 0x32, 0xd4, 0x4a, 0x89, 0x4c, 0x44, 0x02, 0x32, 0xfb, + 0xcc, 0xdd, 0x9b, 0x4c, 0xbc, 0x89, 0x6f, 0xc1, 0x9b, 0xa2, 0xc1, 0x4f, 0x8f, 0xce, 0xf1, 0x4b, 0x44, 0x12, 0x85, + 0x18, 0xb6, 0x18, 0x11, 0x0b, 0x91, 0x63, 0xc7, 0x84, 0x72, 0x25, 0x68, 0x6d, 0x0d, 0x81, 0x17, 0x7f, 0x5a, 0x75, + 0xef, 0x2a, 0x13, 0xc6, 0x3e, 0xe3, 0x2a, 0xbe, 0x65, 0xa5, 0x02, 0xb3, 0xc0, 0x38, 0xf7, 0x6d, 0x29, 0xc9, 0x55, + 0x26, 0x8c, 0x80, 0xe4, 0x2a, 0xbe, 0xa5, 0x4d, 0x19, 0x87, 0xb6, 0xa2, 0xf3, 0xe2, 0xfc, 0xee, 0x0e, 0xbf, 0xc4, + 0x50, 0x2b, 0xe3, 0x7e, 0x1f, 0x24, 0x66, 0xd2, 0x36, 0x65, 0x26, 0x23, 0xa9, 0xd1, 0x42, 0x2a, 0xca, 0x07, 0x13, + 0xb2, 0xbb, 0x52, 0x2d, 0x23, 0x6a, 0xbf, 0x0a, 0xc5, 0x6c, 0x1c, 0x4d, 0x08, 0x9d, 0x74, 0xac, 0x77, 0xd3, 0x5a, + 0xc8, 0x34, 0x7a, 0x16, 0x79, 0x3e, 0x9d, 0x05, 0xab, 0xa6, 0xc5, 0x21, 0xe3, 0xd3, 0x62, 0x30, 0x20, 0xda, 0xa5, + 0x70, 0x83, 0xf5, 0x80, 0x29, 0x8d, 0x8b, 0xb7, 0x66, 0x5a, 0xfd, 0x4a, 0xaa, 0x90, 0xf4, 0x9e, 0x01, 0x49, 0x26, + 0x5d, 0xb0, 0x5b, 0x90, 0x28, 0x7a, 0xfe, 0x77, 0x6a, 0x0b, 0xee, 0x7a, 0x30, 0x36, 0xa3, 0xfb, 0x7a, 0xc6, 0x7f, + 0xa8, 0x6d, 0x41, 0xd4, 0xa7, 0x92, 0xf5, 0x3a, 0x12, 0x55, 0xc8, 0x45, 0xf8, 0xd9, 0xd1, 0x10, 0x43, 0x54, 0x7b, + 0x2c, 0x10, 0xeb, 0xab, 0x73, 0x5e, 0xe0, 0xf4, 0x33, 0x77, 0xb9, 0x82, 0x6d, 0x41, 0x2b, 0x43, 0xa3, 0xde, 0xc6, + 0x6f, 0x23, 0x7b, 0x59, 0xd0, 0x45, 0xbe, 0x40, 0x21, 0x6b, 0x1e, 0x86, 0xd5, 0xb0, 0x3d, 0x88, 0x64, 0xbf, 0x3d, + 0x09, 0x8d, 0xc6, 0xc0, 0x02, 0xd9, 0xa1, 0x11, 0xb8, 0x08, 0xad, 0xfc, 0xed, 0x10, 0x5c, 0xb8, 0x2c, 0x22, 0xcb, + 0x50, 0xc7, 0x6f, 0x6a, 0x37, 0x41, 0xf5, 0x0a, 0x9d, 0xa6, 0xb0, 0x2a, 0x65, 0x92, 0x0f, 0xbf, 0x5e, 0xc9, 0x02, + 0x33, 0x79, 0x5d, 0xf6, 0xe8, 0x6b, 0xbb, 0xbd, 0x03, 0x53, 0xb0, 0xee, 0x93, 0xf7, 0xf5, 0xe3, 0xce, 0x9e, 0x80, + 0x51, 0xac, 0xca, 0xd1, 0x14, 0x52, 0x6a, 0x1f, 0x94, 0xfa, 0x63, 0xb8, 0x14, 0x9a, 0x63, 0xb7, 0x80, 0x49, 0xc0, + 0x3e, 0x43, 0xaa, 0xc7, 0xb4, 0x63, 0x9f, 0xa3, 0x0d, 0x2c, 0x09, 0x38, 0xfc, 0xa3, 0x4c, 0xd6, 0xfe, 0xd5, 0x5d, + 0xa4, 0xcd, 0x90, 0x2d, 0xf3, 0x05, 0xf0, 0xf9, 0xb0, 0x6b, 0xa3, 0x12, 0x65, 0x13, 0x91, 0xa4, 0xb0, 0xe5, 0x31, + 0x48, 0x7b, 0x14, 0xd3, 0x55, 0xc1, 0x93, 0x0c, 0xa5, 0x14, 0x89, 0xf6, 0x09, 0xce, 0xe1, 0x0d, 0xee, 0x47, 0x15, + 0x10, 0x5e, 0x85, 0x9c, 0x8e, 0x52, 0xaa, 0x2d, 0x60, 0x14, 0xf5, 0x00, 0x51, 0x5e, 0x06, 0x72, 0xbc, 0xed, 0x76, + 0x42, 0x57, 0x6c, 0x39, 0x9c, 0x50, 0x24, 0x25, 0x97, 0x58, 0xee, 0x15, 0xe8, 0x3c, 0xce, 0x59, 0xef, 0x25, 0x60, + 0x11, 0x9c, 0xc1, 0xdf, 0x98, 0xd0, 0x6b, 0xf8, 0x9b, 0x13, 0xfa, 0x86, 0x85, 0x57, 0xc3, 0x4b, 0xb2, 0x1f, 0xa6, + 0x83, 0x89, 0x12, 0x8c, 0xdd, 0xb1, 0x65, 0x19, 0xaa, 0xc4, 0xd5, 0xfe, 0x05, 0x79, 0x7c, 0x41, 0x6f, 0xe9, 0x0d, + 0x3d, 0xa5, 0x27, 0x40, 0xf8, 0xef, 0x0e, 0x27, 0x7c, 0x38, 0x79, 0xda, 0xef, 0xf7, 0xce, 0xfb, 0xfd, 0xde, 0x99, + 0x31, 0xa0, 0xd0, 0xbb, 0xe8, 0xb2, 0xa6, 0xfa, 0xd7, 0x55, 0xbd, 0x98, 0x9e, 0xa8, 0x8d, 0x9b, 0xf0, 0x2c, 0x0f, + 0xaf, 0xf6, 0xef, 0xc8, 0x10, 0x1f, 0x2f, 0x72, 0x29, 0x8b, 0xf0, 0x72, 0xff, 0x8e, 0xd0, 0x93, 0x23, 0xd0, 0x9b, + 0x62, 0x7d, 0x27, 0x8f, 0xef, 0x74, 0x6d, 0x84, 0xbe, 0x0c, 0x13, 0xd8, 0x26, 0xb7, 0xcc, 0xde, 0xb5, 0x27, 0x63, + 0x88, 0x65, 0x72, 0xe7, 0x95, 0x77, 0xf7, 0xf8, 0x96, 0xec, 0xdf, 0x82, 0xa7, 0xa8, 0x25, 0x7f, 0xb3, 0xf0, 0x86, + 0xb5, 0x6a, 0x78, 0x7c, 0x47, 0x4f, 0x5b, 0x8d, 0x78, 0x7c, 0x47, 0xa2, 0xf0, 0x86, 0x5d, 0xd2, 0x53, 0x76, 0x45, + 0xe8, 0x79, 0xbf, 0x7f, 0xd6, 0xef, 0xcb, 0x7e, 0xff, 0x1f, 0x71, 0x18, 0xc6, 0xc3, 0x82, 0xec, 0x4b, 0x7a, 0xb7, + 0x3f, 0xe1, 0x4f, 0xc8, 0x2c, 0xd4, 0xcd, 0x57, 0x0b, 0xce, 0xaa, 0xbc, 0x55, 0xae, 0x3b, 0x0a, 0xd6, 0x0a, 0x77, + 0x4c, 0x3d, 0x9d, 0xd0, 0x1b, 0x56, 0xd0, 0x53, 0x16, 0x93, 0xe8, 0x1a, 0x5a, 0x71, 0x3e, 0x2b, 0xa2, 0x1b, 0x7a, + 0xca, 0xce, 0x66, 0x71, 0x74, 0x4a, 0x4f, 0x58, 0x3e, 0x9c, 0x40, 0xde, 0xd3, 0xe1, 0x0d, 0xd9, 0x3f, 0x21, 0x51, + 0x78, 0xa2, 0x7f, 0xdf, 0xd1, 0x4b, 0x1e, 0x9e, 0x50, 0xaf, 0x9a, 0x13, 0x62, 0xaa, 0x6f, 0xd4, 0x7e, 0x42, 0x22, + 0x7f, 0x30, 0x4f, 0xac, 0x3d, 0xcd, 0x23, 0x47, 0x1b, 0xd3, 0x32, 0x04, 0x7d, 0x73, 0x19, 0xde, 0x10, 0x32, 0x6d, + 0x8e, 0x1d, 0x0c, 0xe8, 0xec, 0x51, 0x94, 0x10, 0x7a, 0xe3, 0x97, 0x7a, 0x83, 0x63, 0x68, 0x46, 0x48, 0xa5, 0x9d, + 0x62, 0x1a, 0xae, 0x83, 0xd7, 0x1a, 0xac, 0xe3, 0xbc, 0xdf, 0x0f, 0xd7, 0xfd, 0x3e, 0x44, 0xba, 0x2f, 0x66, 0x26, + 0xb6, 0x9b, 0x23, 0x9b, 0xf4, 0x06, 0xb4, 0xff, 0xaf, 0x07, 0x03, 0xe8, 0x8c, 0x57, 0x52, 0x78, 0x33, 0x78, 0xfd, + 0xf8, 0x8e, 0xa8, 0x3a, 0x0a, 0x2a, 0x64, 0x58, 0xd0, 0x37, 0x34, 0x03, 0xc0, 0xaf, 0xd7, 0x83, 0x01, 0x89, 0xcc, + 0x67, 0x64, 0xfa, 0xfa, 0xf0, 0x64, 0x3a, 0x18, 0xbc, 0x36, 0xdb, 0xe4, 0x2d, 0xbb, 0xa7, 0x14, 0x58, 0x7f, 0x67, + 0xfd, 0xfe, 0xdb, 0xa3, 0x98, 0x9c, 0x17, 0x3c, 0xfe, 0x38, 0x6d, 0xb6, 0xe5, 0xad, 0x8b, 0xaa, 0x76, 0xd6, 0xef, + 0xaf, 0xfb, 0xfd, 0x53, 0xc0, 0x2e, 0x9a, 0x39, 0x5f, 0x4f, 0x90, 0xb6, 0xcc, 0x1d, 0x45, 0xd2, 0x24, 0x87, 0xc6, + 0xd0, 0xb6, 0x58, 0xb5, 0x6d, 0xd6, 0x91, 0x81, 0xc5, 0x51, 0xb3, 0xa2, 0xb8, 0x26, 0x51, 0xd8, 0x3b, 0xdb, 0x6e, + 0x4f, 0x19, 0x63, 0x31, 0x01, 0xe9, 0x87, 0xff, 0xfa, 0xb4, 0x6e, 0xc4, 0x10, 0x13, 0x12, 0x99, 0xcd, 0xcd, 0xd2, + 0x1e, 0x02, 0x11, 0x87, 0x4d, 0xff, 0xde, 0xdc, 0xcb, 0x45, 0xed, 0xf8, 0xd6, 0xdf, 0x01, 0x84, 0x48, 0xb2, 0x90, + 0xcf, 0x70, 0x0c, 0xca, 0x0c, 0x80, 0xcc, 0x23, 0x35, 0xf3, 0x12, 0x40, 0x80, 0xc9, 0x76, 0x3b, 0x1a, 0x8f, 0x27, + 0xb4, 0x60, 0xa3, 0xbf, 0x3d, 0x7b, 0x5c, 0x3d, 0x0e, 0x83, 0x60, 0x90, 0x91, 0x96, 0x9e, 0xc2, 0x2e, 0xd6, 0x6a, + 0x1f, 0x8c, 0xe0, 0x35, 0xfb, 0x78, 0x9d, 0x7d, 0x31, 0xfb, 0x88, 0x84, 0xb5, 0xc1, 0x38, 0x72, 0x91, 0xb6, 0xf4, + 0x76, 0xf7, 0x30, 0x98, 0x5c, 0xa4, 0x9f, 0x61, 0x3b, 0x7d, 0xfe, 0xcd, 0x83, 0xf1, 0x84, 0x83, 0xd1, 0x5d, 0x14, + 0xf4, 0x99, 0xb6, 0xdd, 0x56, 0xfe, 0x25, 0xf0, 0x2d, 0xa6, 0x82, 0x8e, 0xcd, 0xb2, 0x70, 0x83, 0x8a, 0xa8, 0xa3, + 0x65, 0x50, 0xd5, 0xca, 0x76, 0x0e, 0xa8, 0x25, 0x56, 0x65, 0xe2, 0x16, 0x18, 0x86, 0x0c, 0x75, 0xb9, 0xc7, 0xd5, + 0xef, 0xbc, 0x90, 0x06, 0x3e, 0xc3, 0x89, 0x08, 0x3d, 0x6e, 0x8d, 0xfb, 0xdc, 0x9a, 0xf8, 0x0c, 0xb7, 0x56, 0x22, + 0x89, 0x35, 0xb0, 0xa4, 0xe6, 0x72, 0x94, 0xb0, 0xa3, 0x92, 0xf1, 0x59, 0x19, 0x25, 0x34, 0x86, 0x07, 0xc9, 0xc4, + 0x4c, 0x46, 0x09, 0xda, 0x27, 0xba, 0x08, 0x83, 0x7f, 0x01, 0x66, 0x3f, 0xcd, 0xe1, 0xaf, 0x24, 0xd3, 0xe4, 0x10, + 0x02, 0x42, 0x1c, 0x8e, 0x67, 0x71, 0x38, 0x26, 0x51, 0x72, 0x04, 0x4f, 0xf0, 0x5f, 0x11, 0x8e, 0x49, 0xad, 0xef, + 0x30, 0x52, 0x5d, 0x6e, 0x13, 0x06, 0x70, 0x65, 0xe3, 0xd9, 0x24, 0xb2, 0xd2, 0x5d, 0xf9, 0x78, 0x34, 0x7e, 0x46, + 0xa6, 0x71, 0x28, 0x07, 0x09, 0xa1, 0xe0, 0xdd, 0x1b, 0x96, 0xc3, 0x44, 0xc3, 0xb3, 0x01, 0x9b, 0x57, 0x3a, 0x36, + 0x4f, 0xc2, 0x09, 0x08, 0xc3, 0x84, 0x1c, 0xeb, 0x3d, 0x48, 0x29, 0xfa, 0x3c, 0xc7, 0x7e, 0xea, 0x23, 0x08, 0xb3, + 0xa3, 0x96, 0x8a, 0xaf, 0x00, 0xe8, 0x12, 0x07, 0x87, 0xda, 0x33, 0x5f, 0xcc, 0xc2, 0xd2, 0xa3, 0x52, 0xa6, 0xba, + 0x7d, 0xd1, 0xa0, 0xfc, 0xa6, 0x41, 0xfb, 0x82, 0x0c, 0x26, 0xb4, 0x3c, 0x9a, 0xf0, 0x27, 0x10, 0xc0, 0xa3, 0x11, + 0xf1, 0x4b, 0xe1, 0xc4, 0x40, 0x78, 0x15, 0x64, 0xa0, 0xd2, 0x5a, 0x35, 0x66, 0x64, 0x2b, 0xde, 0x83, 0x30, 0x29, + 0x7b, 0x37, 0x72, 0x9d, 0xa7, 0x10, 0x15, 0x6c, 0x9d, 0x57, 0x7b, 0x97, 0x60, 0xc9, 0x1e, 0x57, 0x10, 0x27, 0x6c, + 0xbd, 0x02, 0xec, 0xdc, 0x47, 0x9b, 0xb2, 0xde, 0x53, 0xdf, 0xed, 0x61, 0xcb, 0xe1, 0x55, 0x25, 0xf7, 0x26, 0xe3, + 0xf1, 0x78, 0xf4, 0x07, 0x1c, 0x1d, 0x40, 0x68, 0x49, 0x64, 0xf8, 0x64, 0x80, 0xc6, 0x5d, 0x57, 0xdc, 0x1b, 0x17, + 0x8a, 0xb2, 0xd2, 0xc9, 0x84, 0x80, 0xf8, 0xd9, 0xf4, 0x0d, 0xf6, 0x15, 0xd7, 0xf1, 0x4f, 0x76, 0x3f, 0x31, 0x2b, + 0x5a, 0xad, 0xd4, 0xd1, 0xbb, 0x93, 0xd3, 0xd7, 0x1f, 0x5e, 0xff, 0xfa, 0xf2, 0xec, 0xf5, 0xdb, 0x57, 0xaf, 0xdf, + 0xbe, 0xfe, 0xf0, 0xaf, 0x07, 0x18, 0x6c, 0xdf, 0x56, 0xc4, 0x8e, 0xbd, 0x77, 0x8f, 0xf1, 0x6a, 0xf1, 0x85, 0xb3, + 0x07, 0xee, 0x16, 0x0b, 0xb0, 0x09, 0x86, 0x5b, 0x10, 0x54, 0x33, 0x1a, 0x95, 0xbe, 0x27, 0x20, 0xa3, 0x51, 0x21, + 0x1b, 0x0f, 0x2b, 0xb6, 0x42, 0x2e, 0xde, 0x31, 0x1c, 0x7c, 0x64, 0x7f, 0x2b, 0xce, 0x84, 0xdb, 0xd1, 0xd6, 0xac, + 0x08, 0xf8, 0x7c, 0xad, 0x45, 0xe5, 0x71, 0x21, 0x6a, 0x6f, 0xdb, 0xe7, 0x90, 0x50, 0x8f, 0xc8, 0x75, 0xf0, 0xbe, + 0x0d, 0xb2, 0xc7, 0x47, 0xde, 0x93, 0xf2, 0x0c, 0xf5, 0x39, 0x1a, 0x3e, 0x6a, 0x3c, 0xa3, 0x13, 0x73, 0x6d, 0x74, + 0xa8, 0x67, 0x05, 0xec, 0x6f, 0x25, 0xc6, 0x86, 0x68, 0x0f, 0x29, 0x62, 0x7d, 0x38, 0xdd, 0xef, 0xee, 0xcd, 0xe8, + 0x7b, 0x38, 0x7e, 0x94, 0x6a, 0x02, 0x69, 0x51, 0xa0, 0x74, 0x65, 0xc8, 0x6d, 0xcf, 0xc2, 0xc2, 0xfc, 0x0c, 0x1b, + 0x04, 0xd0, 0x5e, 0x76, 0x2c, 0x09, 0x34, 0x8b, 0xd7, 0xba, 0xfe, 0x79, 0xf9, 0x32, 0xd1, 0xce, 0x17, 0xdf, 0x42, + 0x88, 0x61, 0xff, 0x8a, 0xd0, 0x98, 0x70, 0x37, 0xc9, 0xee, 0xd2, 0x62, 0xee, 0x55, 0x57, 0x31, 0x1e, 0x77, 0xf7, + 0x5c, 0x29, 0x9a, 0xb7, 0x2e, 0xb0, 0x07, 0x6a, 0x5e, 0xc7, 0x4b, 0x16, 0x02, 0x36, 0xe3, 0xbe, 0x5d, 0x24, 0xce, + 0xef, 0x9d, 0x4e, 0xc8, 0xfe, 0xc1, 0x94, 0x0f, 0x59, 0x49, 0xc5, 0x80, 0x95, 0xf5, 0x0e, 0x35, 0xe7, 0x6d, 0x42, + 0x2e, 0x76, 0x69, 0xb8, 0x18, 0xf2, 0x87, 0x2e, 0x49, 0x1f, 0x78, 0xc3, 0xa1, 0xda, 0x36, 0x17, 0x43, 0x9a, 0x72, + 0xba, 0x4b, 0x65, 0x40, 0x88, 0x74, 0x15, 0x57, 0xa4, 0xd6, 0x47, 0x55, 0xea, 0x24, 0x1d, 0xd7, 0xd9, 0xe6, 0x33, + 0x97, 0x6c, 0x75, 0xbb, 0xf6, 0xaf, 0xd5, 0xed, 0x0b, 0x33, 0x90, 0xbf, 0x3f, 0x11, 0xd5, 0xc4, 0x40, 0x74, 0x01, + 0x15, 0xfc, 0x13, 0xbc, 0x3c, 0x79, 0xa4, 0x15, 0xa0, 0xf7, 0x9d, 0x1d, 0x5d, 0x7b, 0xbc, 0x31, 0x8b, 0xad, 0x25, + 0xce, 0x59, 0xe5, 0x3b, 0xcb, 0xab, 0xb2, 0x15, 0xba, 0x8e, 0x60, 0xbf, 0x87, 0x1d, 0x7d, 0xf7, 0xb6, 0x01, 0x10, + 0xa5, 0xb0, 0x72, 0x67, 0xbf, 0xf0, 0xce, 0x7e, 0x61, 0xcf, 0x7e, 0xbb, 0x09, 0x94, 0x0f, 0x2b, 0xb4, 0xec, 0x95, + 0x14, 0x95, 0x69, 0xf2, 0xb8, 0xa9, 0xcb, 0x42, 0x5a, 0xcc, 0xf7, 0x2d, 0xed, 0x7a, 0x3a, 0xa6, 0x12, 0xd5, 0x23, + 0x3f, 0x60, 0xab, 0xf6, 0x4b, 0xf2, 0xf0, 0x3d, 0xf3, 0x7f, 0xf6, 0x06, 0x79, 0xdf, 0xdd, 0xee, 0xff, 0xe6, 0x42, + 0x07, 0xb7, 0xb5, 0x54, 0x78, 0xea, 0xea, 0xb8, 0xc0, 0xbb, 0x5a, 0xfa, 0xf0, 0x5d, 0xed, 0x5d, 0xa6, 0x97, 0x5d, + 0x05, 0xa8, 0x41, 0x62, 0x7d, 0xc5, 0x8b, 0x2c, 0xa9, 0xad, 0x42, 0xe3, 0x84, 0x43, 0x68, 0x0f, 0xef, 0xe0, 0x02, + 0x39, 0x2c, 0x21, 0xf4, 0x63, 0x65, 0x04, 0x80, 0x3e, 0x8b, 0x7d, 0xc2, 0xc3, 0x8c, 0x0c, 0x7c, 0x89, 0x5f, 0x29, + 0x7d, 0x71, 0xf1, 0xfe, 0x4e, 0x66, 0x82, 0x5e, 0x25, 0x36, 0xbb, 0x94, 0xed, 0x98, 0x1f, 0xfe, 0x17, 0x18, 0x0d, + 0xc2, 0x6b, 0x4b, 0xb6, 0x2f, 0x3a, 0x66, 0xb9, 0x82, 0xa3, 0xb6, 0x74, 0x65, 0x96, 0xad, 0xeb, 0x67, 0x35, 0xcc, + 0xf4, 0x99, 0x72, 0x02, 0xb2, 0x2f, 0xe4, 0xee, 0xa7, 0xba, 0x62, 0x41, 0x8e, 0x26, 0xe3, 0x29, 0x11, 0x83, 0x41, + 0x2b, 0xf9, 0x10, 0x93, 0x87, 0xc3, 0x1d, 0xe6, 0x52, 0xe8, 0x7e, 0x78, 0x7d, 0x80, 0xfa, 0x1a, 0x5b, 0x92, 0x6c, + 0x2a, 0xf6, 0x17, 0x98, 0xc5, 0x02, 0x71, 0x74, 0xf0, 0x8b, 0xf3, 0x05, 0x80, 0x2c, 0xc3, 0x32, 0xd3, 0xc2, 0xa2, + 0x32, 0x55, 0x3e, 0xb2, 0x05, 0x93, 0x87, 0xe3, 0x99, 0xdf, 0x73, 0xc7, 0xe0, 0x10, 0x12, 0x4d, 0xac, 0xf1, 0x8b, + 0x9f, 0x05, 0xe3, 0x38, 0x94, 0x47, 0xb2, 0xf1, 0x5d, 0x49, 0xa2, 0xb1, 0x31, 0x55, 0xd6, 0x57, 0x89, 0x6a, 0x98, + 0x90, 0xc7, 0x05, 0xd9, 0x2f, 0xe8, 0xd2, 0x1f, 0x4b, 0x4c, 0xdf, 0x8f, 0xf7, 0x27, 0x63, 0xf2, 0x38, 0x7e, 0x3c, + 0x31, 0x70, 0xc3, 0x7e, 0x8e, 0x7c, 0xb8, 0x24, 0xfb, 0xcd, 0x2a, 0xc1, 0x14, 0xd5, 0xf4, 0xcc, 0xaf, 0x24, 0x19, + 0x2c, 0x07, 0xe9, 0xe3, 0x56, 0x5e, 0xac, 0x55, 0x8f, 0xf7, 0xfa, 0x90, 0x4f, 0x89, 0x68, 0xdc, 0x18, 0xd6, 0xf4, + 0x2a, 0xfe, 0x53, 0x16, 0x51, 0x29, 0x01, 0x91, 0x10, 0xd4, 0xdb, 0xd9, 0x45, 0x96, 0xc4, 0x22, 0x8d, 0xd2, 0x9a, + 0xd0, 0xf4, 0x88, 0x4d, 0xc6, 0xb3, 0x94, 0xa5, 0x87, 0x93, 0x67, 0xb3, 0xc9, 0xb3, 0xe8, 0x60, 0x1c, 0xa5, 0x83, + 0x01, 0x24, 0x1f, 0x8c, 0xc1, 0xc5, 0x0e, 0x7e, 0xb3, 0x03, 0x18, 0xba, 0x23, 0x64, 0x09, 0x0b, 0x68, 0xda, 0x97, + 0x35, 0x49, 0x0f, 0xe7, 0x85, 0xea, 0x49, 0x7c, 0x4b, 0xd7, 0x9e, 0x83, 0x8b, 0xdf, 0xc2, 0x0b, 0xd7, 0xc2, 0x8b, + 0xdd, 0x16, 0x0a, 0x13, 0x37, 0x45, 0xfe, 0xff, 0xb8, 0x61, 0xdc, 0x77, 0x97, 0x30, 0x8b, 0xeb, 0x3a, 0x1b, 0xad, + 0x0a, 0x59, 0x49, 0xb8, 0x4d, 0x28, 0x51, 0xd8, 0x28, 0x5e, 0xad, 0x72, 0xed, 0x22, 0x36, 0xaf, 0x28, 0x80, 0xbb, + 0x40, 0x9c, 0x62, 0x60, 0xa1, 0x8d, 0x81, 0xdc, 0x27, 0x5e, 0x48, 0x66, 0xd5, 0x3e, 0xe6, 0x1e, 0xf9, 0x67, 0x08, + 0xc6, 0xa8, 0xe2, 0x68, 0x3c, 0x53, 0x58, 0x17, 0x9f, 0x93, 0xf7, 0xfe, 0x1b, 0x47, 0x91, 0x3d, 0x9a, 0x41, 0x4f, + 0x10, 0x39, 0x8f, 0x38, 0x7b, 0x32, 0x79, 0x19, 0xb8, 0x9f, 0xc1, 0x4a, 0x7f, 0xdd, 0x6d, 0xc6, 0xda, 0xf6, 0xe8, + 0x5e, 0x18, 0xa1, 0xe8, 0x27, 0x7c, 0x67, 0xea, 0x05, 0x5c, 0x42, 0x35, 0xb0, 0xeb, 0xcb, 0x4b, 0x5e, 0x02, 0x88, + 0x50, 0x26, 0xfa, 0xfd, 0xde, 0x9f, 0x06, 0x9a, 0xb4, 0xe4, 0xc5, 0x9b, 0x4c, 0x58, 0x67, 0x1c, 0x68, 0x2a, 0x50, + 0xff, 0x8f, 0x95, 0x7d, 0xa6, 0x63, 0x32, 0xf3, 0x1f, 0x87, 0x13, 0x12, 0x35, 0x5f, 0x93, 0xcf, 0x9c, 0xa6, 0x9f, + 0xb9, 0xa2, 0xfd, 0x07, 0x32, 0x73, 0xc3, 0x21, 0x43, 0xfd, 0xa5, 0x63, 0x9e, 0x8c, 0x5e, 0x27, 0x66, 0x47, 0x82, + 0x55, 0x33, 0x88, 0xc2, 0x5e, 0xc0, 0x83, 0xba, 0x96, 0xc5, 0x53, 0x98, 0x7d, 0x50, 0x23, 0x8a, 0x43, 0x36, 0x9e, + 0x85, 0x32, 0x9c, 0x80, 0x7d, 0xef, 0x64, 0x0c, 0xf7, 0x01, 0x19, 0x7e, 0xac, 0x42, 0xec, 0x1c, 0xa4, 0x7d, 0xac, + 0x50, 0x31, 0x01, 0x10, 0x81, 0x90, 0xb7, 0xdf, 0x97, 0x2a, 0x09, 0x5f, 0x97, 0x98, 0x52, 0xa8, 0x0f, 0xfe, 0x13, + 0xa9, 0xba, 0x63, 0xfa, 0xd5, 0xfa, 0xf1, 0x67, 0x42, 0xf1, 0xe9, 0x2e, 0x25, 0xbe, 0x85, 0xe0, 0xce, 0x12, 0x74, + 0x10, 0x15, 0x9a, 0xb1, 0x3d, 0xcc, 0xef, 0x8a, 0xfb, 0xf9, 0x5d, 0xf1, 0xff, 0x8e, 0xdf, 0x15, 0x0f, 0x31, 0x86, + 0x95, 0x85, 0x86, 0x9f, 0x05, 0xe3, 0x20, 0xfa, 0xcf, 0xf9, 0xc4, 0x7b, 0x79, 0xea, 0xab, 0x4c, 0x4c, 0xef, 0x61, + 0x9a, 0x7d, 0x82, 0x82, 0xb0, 0x8a, 0xbb, 0xf4, 0x64, 0x5d, 0xd9, 0x5b, 0x2b, 0x19, 0x62, 0x9e, 0x07, 0x58, 0xa3, + 0xb0, 0xf2, 0x80, 0xee, 0x51, 0xb5, 0x41, 0x9c, 0x08, 0x1e, 0xc6, 0xcc, 0x4a, 0xdf, 0xb7, 0x5b, 0xa3, 0xc2, 0x7c, + 0x90, 0x8b, 0x82, 0xec, 0xe6, 0xe3, 0xd9, 0x38, 0x0a, 0xb1, 0x01, 0xff, 0x31, 0x63, 0xd5, 0x90, 0xcd, 0x77, 0x32, + 0x52, 0x3b, 0x26, 0x4f, 0x93, 0x5d, 0xd2, 0x3b, 0xe0, 0x1d, 0xf2, 0x73, 0x70, 0x67, 0x93, 0x86, 0xdf, 0x92, 0x97, + 0x71, 0x91, 0x55, 0xcb, 0xab, 0x2c, 0x41, 0xa6, 0x0b, 0x5e, 0x7c, 0x31, 0xd3, 0xe5, 0x7d, 0xac, 0x0f, 0x18, 0x4f, + 0x29, 0x5e, 0x37, 0x44, 0xe9, 0xeb, 0x96, 0x67, 0x85, 0xba, 0x3c, 0xa9, 0x98, 0xed, 0x59, 0x09, 0x4e, 0xa7, 0x60, + 0x82, 0xaf, 0x7f, 0xba, 0xde, 0x27, 0x80, 0x0b, 0x0a, 0x35, 0xa7, 0x85, 0x5c, 0x19, 0x2c, 0x27, 0x0b, 0xdd, 0x09, + 0x98, 0xa1, 0x52, 0xe0, 0x05, 0x0a, 0xfe, 0xa2, 0x81, 0x11, 0x7d, 0xe5, 0x7e, 0x93, 0x81, 0x41, 0xba, 0x34, 0x27, + 0xc2, 0xd8, 0x71, 0x3b, 0x45, 0xda, 0x8a, 0x72, 0xc6, 0xd9, 0x7b, 0x75, 0xa5, 0x00, 0x03, 0xbc, 0xcd, 0x4d, 0x74, + 0x9e, 0xa0, 0xd7, 0x82, 0xd2, 0x79, 0x03, 0x77, 0xb3, 0x8c, 0x8c, 0x70, 0xf1, 0x71, 0xe5, 0xb1, 0xe0, 0x9e, 0xfd, + 0x42, 0x2c, 0x8d, 0x66, 0x1a, 0x8c, 0xd9, 0xbc, 0x60, 0x81, 0x42, 0x05, 0x0a, 0x2c, 0x67, 0xda, 0xd2, 0xb4, 0x1a, + 0xf2, 0xfd, 0x03, 0xb4, 0x36, 0xad, 0x06, 0x7c, 0xff, 0xa0, 0x8e, 0xb2, 0x43, 0xc8, 0x72, 0xe4, 0x67, 0x50, 0xaf, + 0xeb, 0xc8, 0xa4, 0x98, 0xec, 0x7e, 0x7d, 0xa9, 0x3f, 0xaa, 0x1b, 0x70, 0xfd, 0x00, 0x04, 0xb0, 0x01, 0x38, 0x04, + 0xaa, 0xc1, 0xd2, 0x88, 0x60, 0x51, 0xa6, 0xd0, 0xbe, 0x86, 0xde, 0x1b, 0x0d, 0xff, 0x05, 0xee, 0x22, 0x72, 0xe5, + 0x7f, 0x82, 0xc0, 0x5f, 0x51, 0xa6, 0x95, 0x29, 0xfe, 0x27, 0x5a, 0xbd, 0x42, 0x39, 0x6b, 0x5a, 0xf3, 0x41, 0xb4, + 0x26, 0x42, 0x35, 0x63, 0x08, 0xfe, 0xad, 0x2c, 0xd3, 0x96, 0xaa, 0x4a, 0x7d, 0x68, 0xbc, 0xd6, 0x0a, 0x67, 0xf9, + 0x38, 0xf2, 0x5e, 0x63, 0xe8, 0xd8, 0xc4, 0x59, 0xca, 0xa9, 0xd4, 0xd9, 0xa7, 0x7d, 0x19, 0x39, 0xc0, 0xe9, 0x84, + 0x8d, 0xa7, 0xc9, 0xa1, 0x9c, 0x26, 0x0e, 0x32, 0x3f, 0x67, 0x18, 0x59, 0xd5, 0x80, 0xb0, 0x28, 0x1b, 0x4a, 0x5b, + 0x80, 0x49, 0x4e, 0x08, 0x99, 0x62, 0x28, 0x8a, 0x7c, 0xa4, 0xfb, 0x61, 0xbd, 0x59, 0xdd, 0x17, 0xef, 0x34, 0xc0, + 0x69, 0x98, 0x40, 0x20, 0xf0, 0x22, 0xbe, 0xc9, 0xc4, 0x25, 0x78, 0x0c, 0x0f, 0xe0, 0x4b, 0x70, 0x93, 0x4b, 0xd9, + 0x6f, 0x55, 0x98, 0xe3, 0xda, 0x02, 0x06, 0x0d, 0x56, 0x0f, 0xa2, 0xc3, 0xa5, 0xb4, 0xd9, 0x55, 0x80, 0xd8, 0x98, + 0x42, 0x2c, 0x0b, 0xb6, 0xb6, 0xec, 0xd9, 0xcf, 0xaa, 0x69, 0x68, 0x9d, 0x70, 0x2c, 0x2e, 0x73, 0x88, 0xa2, 0x32, + 0x88, 0xc1, 0x1d, 0xc9, 0xe3, 0xf3, 0x1e, 0x89, 0xf0, 0x82, 0x80, 0x5b, 0x59, 0x2c, 0xc3, 0x15, 0x5d, 0x8e, 0x6e, + 0xe9, 0x7a, 0x74, 0x43, 0xc7, 0x74, 0xf2, 0xf7, 0x31, 0x58, 0x64, 0xeb, 0xd4, 0x3b, 0xba, 0x1e, 0x2d, 0xe9, 0xb7, + 0x63, 0x7a, 0xf0, 0x37, 0x30, 0xe1, 0xc3, 0xc3, 0x84, 0x5e, 0x80, 0x63, 0x17, 0xa9, 0xd1, 0x53, 0xd3, 0x37, 0x38, + 0xac, 0x46, 0xf9, 0x90, 0x8f, 0x72, 0xca, 0x47, 0xc5, 0xb0, 0x1a, 0x81, 0xa7, 0x63, 0x35, 0xe4, 0xa3, 0x8a, 0xf2, + 0xd1, 0xf9, 0xb0, 0x1a, 0x9d, 0x93, 0x66, 0xd3, 0x5f, 0x57, 0xfc, 0xaa, 0x64, 0x29, 0x6c, 0x0b, 0x58, 0xbe, 0x9e, + 0x57, 0x54, 0xea, 0xaf, 0x6a, 0x73, 0x32, 0x5b, 0xce, 0xde, 0x5e, 0x77, 0x39, 0xb1, 0x78, 0xdc, 0x36, 0x1d, 0xae, + 0xbe, 0x9c, 0xa8, 0x93, 0x5e, 0x21, 0x3f, 0x8c, 0xa7, 0x42, 0x9d, 0x43, 0x60, 0x26, 0x31, 0x0b, 0x63, 0x86, 0xcd, + 0xd4, 0x69, 0xa0, 0xc0, 0xc9, 0x46, 0x9e, 0x8b, 0x62, 0x36, 0xca, 0x29, 0xbc, 0x8f, 0x09, 0x89, 0x04, 0x9c, 0x55, + 0x47, 0xd5, 0xa8, 0x80, 0x98, 0x23, 0x2c, 0xc4, 0x47, 0xe8, 0x97, 0xfa, 0xc8, 0x43, 0x02, 0xcf, 0xb0, 0xaf, 0xc5, + 0x20, 0x86, 0x23, 0xde, 0x56, 0x56, 0xcd, 0xc2, 0x04, 0x2a, 0xab, 0x86, 0xa5, 0xa9, 0xac, 0xa0, 0xd9, 0xa8, 0xf2, + 0x2b, 0xab, 0x70, 0x8c, 0x12, 0x42, 0xa2, 0x52, 0x57, 0x06, 0xea, 0x93, 0x84, 0x85, 0xa5, 0xae, 0xec, 0x5c, 0x7d, + 0x74, 0xee, 0x57, 0x76, 0x0e, 0x2e, 0xa4, 0x83, 0xc4, 0xbf, 0x4a, 0xe5, 0x69, 0xfb, 0x3a, 0xd8, 0x58, 0x55, 0x74, + 0xc3, 0x6f, 0xab, 0x22, 0x8e, 0x4a, 0xea, 0x62, 0x40, 0xe3, 0xc2, 0x88, 0x24, 0xd5, 0x6b, 0x14, 0xfc, 0x21, 0x41, + 0x54, 0x1a, 0x83, 0x57, 0x67, 0xd2, 0xb5, 0x52, 0x2b, 0x2a, 0x06, 0xe5, 0xa0, 0x80, 0xfb, 0x53, 0xde, 0x5a, 0x48, + 0x3f, 0x43, 0x44, 0x65, 0x28, 0x6f, 0xf0, 0x4f, 0x0c, 0x9e, 0xcc, 0x56, 0x69, 0x98, 0x8c, 0xee, 0x68, 0x3c, 0x5a, + 0x22, 0x1c, 0x0c, 0x5b, 0xa7, 0x0a, 0x6f, 0xfd, 0x02, 0xd2, 0x6f, 0x69, 0x3c, 0xba, 0xa1, 0xa9, 0xb5, 0x39, 0x35, + 0x50, 0x57, 0xbd, 0x31, 0xbd, 0x8d, 0xe0, 0xf5, 0x5d, 0xb4, 0xa4, 0xb0, 0x95, 0x8e, 0xf3, 0xec, 0x52, 0x44, 0x29, + 0x45, 0x04, 0xc2, 0x35, 0x22, 0x07, 0x2e, 0x35, 0xda, 0xe0, 0x7a, 0x00, 0x65, 0x68, 0xb8, 0xc0, 0xe5, 0x20, 0x1e, + 0x2d, 0x3d, 0x32, 0xb5, 0xd4, 0x17, 0x59, 0x84, 0x8f, 0x76, 0x36, 0x5a, 0x8a, 0x67, 0xc4, 0xc2, 0xb8, 0x82, 0x21, + 0xd4, 0x85, 0x95, 0xa6, 0x20, 0xe9, 0x02, 0x47, 0xf6, 0xc2, 0xb8, 0x0a, 0x37, 0x60, 0x5a, 0x74, 0x07, 0xe6, 0x51, + 0xa0, 0x70, 0x70, 0x09, 0xd2, 0x4f, 0x28, 0xdb, 0x39, 0x4a, 0x93, 0xc3, 0x9b, 0xa0, 0x74, 0x67, 0x82, 0x90, 0x76, + 0x75, 0x93, 0x2d, 0xe9, 0x1b, 0x6c, 0xef, 0xd0, 0xa9, 0xa8, 0xa0, 0xfa, 0xdc, 0x82, 0xc9, 0x92, 0x0d, 0xc2, 0x96, + 0x30, 0x3d, 0xd3, 0x6b, 0xc0, 0x9e, 0xde, 0x3f, 0xd8, 0x99, 0xef, 0x62, 0xf6, 0x69, 0xbf, 0x8c, 0xc6, 0xca, 0x82, + 0x37, 0xb7, 0xc4, 0x6e, 0xc9, 0xc6, 0xd3, 0xe5, 0x61, 0x39, 0x5d, 0x22, 0xb1, 0x33, 0x74, 0x8b, 0xf1, 0xf9, 0x72, + 0x41, 0x13, 0x3c, 0xdb, 0x58, 0x35, 0x5f, 0x1a, 0xb4, 0x94, 0x94, 0xe1, 0x7a, 0x5b, 0xa2, 0xff, 0xbf, 0xba, 0xf8, + 0xa5, 0x00, 0x2f, 0xc1, 0x58, 0x00, 0x08, 0xf7, 0x60, 0x5a, 0x90, 0xda, 0x28, 0x1b, 0xcb, 0x34, 0x4c, 0x71, 0x11, + 0x98, 0x94, 0x7e, 0x3f, 0xcc, 0x59, 0x4a, 0x3c, 0xe8, 0x50, 0x77, 0x6a, 0xa7, 0xbe, 0x10, 0x04, 0x78, 0x24, 0x75, + 0x8e, 0x4d, 0xfe, 0x3e, 0x9e, 0x05, 0x6a, 0x20, 0x82, 0x28, 0x3b, 0xc4, 0x47, 0x0c, 0x5c, 0x14, 0xe9, 0xb8, 0x9d, + 0xae, 0x88, 0x8b, 0xdd, 0x63, 0x16, 0xe2, 0x24, 0x61, 0xae, 0x59, 0x36, 0x64, 0x55, 0x84, 0x09, 0xba, 0x30, 0x30, + 0xcb, 0x1b, 0xb2, 0x6a, 0xff, 0x00, 0x22, 0xb5, 0xda, 0x32, 0x56, 0x5d, 0x65, 0x7c, 0x0b, 0x40, 0xd6, 0x8c, 0xb1, + 0x83, 0xbf, 0x8d, 0x67, 0xea, 0x9b, 0x28, 0xe4, 0x47, 0x07, 0x7f, 0x83, 0xe4, 0xc3, 0x6f, 0x91, 0x99, 0x83, 0xe4, + 0x46, 0x41, 0x97, 0xcd, 0x59, 0xd7, 0x50, 0x9a, 0xb8, 0xf6, 0x4a, 0xbd, 0xf6, 0xa4, 0x59, 0x7b, 0x05, 0xba, 0x53, + 0x1b, 0xde, 0x43, 0xd9, 0xce, 0x82, 0x09, 0x3a, 0x9a, 0xdd, 0x81, 0x0e, 0xde, 0x29, 0x82, 0x5e, 0x26, 0xa1, 0xf1, + 0x08, 0x55, 0x46, 0xbd, 0x18, 0x0f, 0xaa, 0x93, 0x75, 0xc9, 0x3c, 0x03, 0xe6, 0xd8, 0x9e, 0x43, 0x62, 0x98, 0xab, + 0x83, 0x3a, 0x65, 0xe5, 0x30, 0xc7, 0x03, 0x78, 0xcd, 0xe4, 0x50, 0x0c, 0x72, 0x8d, 0xf2, 0x7d, 0xc1, 0x8a, 0x61, + 0x39, 0xc8, 0x35, 0x37, 0x33, 0x6d, 0xc6, 0xa6, 0x4d, 0x74, 0x78, 0xe6, 0x15, 0x3b, 0x5a, 0xf5, 0x80, 0x8f, 0x05, + 0x4f, 0x66, 0xdf, 0xf3, 0xf1, 0x0d, 0x70, 0x32, 0x9b, 0xdb, 0x68, 0x49, 0xef, 0xa2, 0x94, 0xde, 0x44, 0x6b, 0xba, + 0x8c, 0x2e, 0x8c, 0x89, 0x71, 0x52, 0xc3, 0x39, 0x00, 0xad, 0x02, 0x48, 0x3c, 0xf5, 0xeb, 0x3d, 0x4f, 0xaa, 0x70, + 0x49, 0x53, 0x70, 0x1b, 0xf6, 0xed, 0x33, 0xaf, 0x7c, 0x89, 0xd4, 0x06, 0x31, 0xd6, 0xac, 0xa1, 0xe2, 0xc6, 0x5b, + 0xf7, 0x91, 0xa8, 0x61, 0xe7, 0xba, 0xd8, 0x44, 0xd5, 0x70, 0x32, 0x2d, 0x01, 0xb1, 0xb5, 0x1c, 0x0e, 0xdd, 0x11, + 0xb2, 0x7b, 0xfc, 0xe8, 0x40, 0xcf, 0x3d, 0x69, 0xb1, 0x6d, 0x5b, 0xfe, 0xc0, 0x10, 0xa6, 0xf4, 0xf3, 0x47, 0x3e, + 0x20, 0x56, 0x5c, 0xc2, 0xd9, 0x08, 0xd4, 0xd1, 0x0a, 0x9d, 0x7e, 0xab, 0xc2, 0x42, 0x1f, 0xe0, 0x9b, 0xdb, 0x28, + 0xa1, 0x77, 0x51, 0xee, 0x91, 0xb5, 0x65, 0xcd, 0xe4, 0xf4, 0x2c, 0x0b, 0x79, 0xfb, 0x40, 0x2f, 0x17, 0x00, 0xa2, + 0x35, 0x88, 0x7d, 0xa9, 0xeb, 0x01, 0x38, 0x0d, 0xa1, 0x49, 0x68, 0x04, 0x57, 0x15, 0x84, 0x11, 0x70, 0x25, 0xe1, + 0x6f, 0x30, 0x51, 0x81, 0x2f, 0xc0, 0x45, 0x26, 0x4d, 0x73, 0x1e, 0xd4, 0xfe, 0x48, 0x9e, 0x16, 0x6d, 0x6f, 0x57, + 0x18, 0x4d, 0x30, 0xf6, 0x44, 0xfb, 0x3c, 0x52, 0x8e, 0xe2, 0x22, 0x09, 0xb3, 0xd1, 0xad, 0x3a, 0xcf, 0x69, 0x36, + 0xba, 0xd3, 0xbf, 0x2a, 0x3a, 0xa6, 0xdf, 0xe9, 0x80, 0x36, 0x4a, 0xfa, 0xd6, 0x71, 0x36, 0xa0, 0xf5, 0x62, 0x69, + 0xfc, 0xaf, 0xe5, 0xe8, 0x96, 0xca, 0xd1, 0x9d, 0x6f, 0x49, 0x35, 0x99, 0x16, 0x87, 0x02, 0x0d, 0xa9, 0x3a, 0xbf, + 0x2f, 0x80, 0x9f, 0x2b, 0x8d, 0xef, 0xb4, 0xf9, 0xde, 0x6b, 0xff, 0x79, 0x27, 0x4f, 0xa0, 0x58, 0xa2, 0x82, 0x55, + 0x23, 0xb0, 0x63, 0x5f, 0xe7, 0x71, 0x61, 0x46, 0x29, 0xa6, 0xd6, 0xa4, 0x1f, 0x03, 0x57, 0x4c, 0x7b, 0x05, 0xb8, + 0x5a, 0x82, 0x93, 0x00, 0xc4, 0xd0, 0x84, 0x3d, 0x3b, 0x86, 0xa8, 0xe7, 0xc6, 0x31, 0x4a, 0x36, 0xdc, 0x03, 0x62, + 0x2d, 0xf3, 0x56, 0x2e, 0x01, 0x09, 0xbc, 0xf5, 0x30, 0x29, 0x00, 0x63, 0xb0, 0x5c, 0x12, 0x9d, 0xc7, 0x43, 0x9f, + 0x50, 0x2f, 0x34, 0xea, 0x84, 0x6c, 0x6c, 0x09, 0x1c, 0x7f, 0x58, 0x1f, 0x02, 0xc1, 0xab, 0x3c, 0xd7, 0x5f, 0x69, + 0x5d, 0x7f, 0xa9, 0xf4, 0xdc, 0xb1, 0x5c, 0xd7, 0xcf, 0xda, 0xd4, 0xe8, 0x15, 0x58, 0xf8, 0x6e, 0x94, 0x79, 0x24, + 0xb7, 0x08, 0xa9, 0x0a, 0xac, 0xd4, 0x2d, 0x24, 0x98, 0x7f, 0x25, 0x67, 0xab, 0x32, 0x5f, 0x3d, 0xf2, 0xa0, 0x9c, + 0x4d, 0x4f, 0x7f, 0x43, 0x82, 0x76, 0xd7, 0x91, 0xe6, 0xf1, 0x16, 0x1d, 0x3e, 0xbb, 0xd6, 0x12, 0x73, 0x27, 0x51, + 0xf1, 0x7c, 0x0a, 0xd8, 0xea, 0x45, 0x76, 0xa5, 0x7c, 0xac, 0x76, 0x71, 0xfc, 0xcc, 0xf9, 0x93, 0x54, 0xe1, 0x5a, + 0x34, 0x94, 0x20, 0xe0, 0xcd, 0x61, 0xec, 0x0a, 0x55, 0x40, 0x43, 0x73, 0x03, 0xc7, 0xb9, 0x1a, 0x56, 0x9a, 0x80, + 0x69, 0x29, 0x8f, 0x0e, 0x70, 0x68, 0xf2, 0xa8, 0xdd, 0x34, 0xac, 0x0c, 0x5d, 0x6b, 0xf4, 0xb9, 0xad, 0x74, 0xc6, + 0x9b, 0x0d, 0xdf, 0x3f, 0x18, 0x54, 0xf8, 0x93, 0x34, 0x47, 0xa3, 0x9d, 0x1b, 0xee, 0x34, 0x02, 0x33, 0x57, 0x72, + 0x45, 0x76, 0x47, 0xc9, 0xcb, 0xef, 0xe9, 0x85, 0x05, 0xf4, 0xe7, 0x3f, 0x17, 0x13, 0x4e, 0x5a, 0x62, 0x42, 0xb4, + 0x74, 0xd0, 0xa2, 0x83, 0x1d, 0xe5, 0x95, 0x7d, 0x89, 0x97, 0xce, 0xf1, 0xbf, 0xaf, 0xc7, 0xda, 0x55, 0x20, 0xb4, + 0x3a, 0xb9, 0xdf, 0x9e, 0x2c, 0x10, 0x35, 0xa0, 0x9a, 0x5d, 0x95, 0xa3, 0x4c, 0x3b, 0x2b, 0xb2, 0x69, 0xc8, 0x5c, + 0x77, 0xb3, 0x34, 0x6c, 0x26, 0x3b, 0x16, 0x96, 0x19, 0x06, 0x6b, 0xa7, 0x8a, 0x3e, 0x07, 0x2d, 0x3f, 0x82, 0x17, + 0x4d, 0xe5, 0x99, 0xcf, 0x66, 0x19, 0xf1, 0x02, 0x9d, 0x73, 0x2a, 0x16, 0x4d, 0xe9, 0x58, 0xb9, 0xdd, 0x96, 0x68, + 0x2c, 0x51, 0x46, 0x41, 0x50, 0xdb, 0x20, 0xec, 0xba, 0x74, 0x4f, 0xfa, 0xb4, 0x8b, 0x4f, 0x2b, 0xd0, 0xf7, 0xf8, + 0x3e, 0x03, 0x89, 0xa9, 0x27, 0x79, 0xa8, 0x1a, 0xcd, 0xd1, 0xc9, 0xb3, 0x38, 0xd5, 0xf8, 0xfc, 0x4a, 0x76, 0xd6, + 0xbc, 0x5b, 0x8d, 0x29, 0xfe, 0x23, 0x75, 0xfb, 0xce, 0x65, 0x68, 0xa2, 0xbf, 0x96, 0x07, 0x2d, 0x85, 0x05, 0xc7, + 0x6d, 0xe3, 0xaf, 0xdf, 0x66, 0x0e, 0x31, 0x2c, 0x5d, 0x0e, 0x6f, 0x42, 0x87, 0xee, 0xae, 0xb2, 0x33, 0xd7, 0x07, + 0xd4, 0xa9, 0x8b, 0x75, 0x1b, 0x50, 0xb2, 0xe4, 0xdd, 0x3a, 0x3d, 0xb1, 0xd2, 0x77, 0xfb, 0xe1, 0xce, 0x3c, 0x6a, + 0x76, 0x77, 0xbb, 0x9d, 0x90, 0xb6, 0x7d, 0x30, 0xde, 0x97, 0xb0, 0x10, 0xe7, 0x1d, 0xb6, 0xf7, 0x73, 0x58, 0x3d, + 0xe6, 0x83, 0xdf, 0x71, 0x9c, 0x61, 0xf4, 0x33, 0x65, 0xe8, 0xf3, 0xaa, 0x90, 0x57, 0xaa, 0x53, 0xbe, 0xd0, 0xad, + 0x65, 0xea, 0xfd, 0x36, 0x7e, 0xdb, 0x0a, 0x10, 0xe3, 0x75, 0xc5, 0x4a, 0xf1, 0x86, 0x56, 0x18, 0xd7, 0xc0, 0x6d, + 0x72, 0xa8, 0xa5, 0x5a, 0x20, 0xea, 0xf2, 0x93, 0xc7, 0x3c, 0x32, 0xea, 0x4c, 0xf8, 0xee, 0x31, 0xf7, 0xa5, 0x6b, + 0xbb, 0x4d, 0xfc, 0x5c, 0xd3, 0xf6, 0x77, 0x07, 0xba, 0xa3, 0x75, 0x0f, 0x37, 0xcf, 0xe6, 0xe7, 0x91, 0xf9, 0x62, + 0x80, 0xcd, 0xda, 0x65, 0x5c, 0x76, 0x0c, 0xf7, 0xbd, 0xe9, 0xc1, 0x58, 0x40, 0x20, 0x31, 0x43, 0x2f, 0x03, 0x17, + 0xb8, 0xc0, 0x5d, 0x61, 0xc0, 0x10, 0xd7, 0xb4, 0xe4, 0x4c, 0x5b, 0xd9, 0xfa, 0xc8, 0xdb, 0xa8, 0x10, 0xac, 0xeb, + 0x8e, 0x9b, 0x24, 0x87, 0xe0, 0x84, 0x2d, 0xf7, 0xbe, 0xf6, 0xda, 0x19, 0xfe, 0x73, 0x20, 0x9c, 0x5b, 0xa2, 0x67, + 0xd4, 0xf6, 0x58, 0xab, 0x7b, 0x0d, 0xaf, 0x72, 0x17, 0x79, 0xd6, 0x6f, 0xe6, 0xa5, 0x61, 0x5f, 0xf0, 0x5a, 0x0a, + 0x0e, 0x8d, 0xed, 0x56, 0xb8, 0xc5, 0xe2, 0x1d, 0xad, 0x56, 0xd6, 0xda, 0x6a, 0xaf, 0x95, 0x8a, 0xde, 0xbf, 0xe6, + 0x38, 0x71, 0x96, 0xc2, 0xf6, 0xc3, 0x87, 0x0b, 0x76, 0x4d, 0x00, 0x83, 0x16, 0x93, 0x05, 0x4a, 0x50, 0xc9, 0x5a, + 0xd5, 0x6e, 0xa7, 0xc4, 0x2f, 0xf7, 0x8b, 0x2e, 0xb3, 0x9d, 0xc7, 0xaf, 0x9b, 0xb4, 0xcf, 0x7c, 0x8e, 0x7e, 0x98, + 0xdf, 0x59, 0x27, 0x25, 0x67, 0x18, 0xd7, 0xf2, 0xff, 0xab, 0xe8, 0x65, 0x91, 0xa5, 0xd1, 0xc6, 0xf0, 0x60, 0x36, + 0xd4, 0xa6, 0x0f, 0x8d, 0x51, 0xb9, 0x65, 0xa3, 0x88, 0x68, 0x75, 0x0b, 0x82, 0x19, 0xc5, 0x7d, 0x89, 0x36, 0xaf, + 0x54, 0x59, 0x78, 0x87, 0xcf, 0x6c, 0xf4, 0x86, 0xed, 0x09, 0xa1, 0x7c, 0xf7, 0xb4, 0x30, 0xab, 0x96, 0x8a, 0x06, + 0xdb, 0x25, 0xbc, 0x8b, 0x51, 0xa5, 0x9f, 0x30, 0xd9, 0xb2, 0x60, 0xaa, 0xff, 0xdf, 0x17, 0x59, 0xda, 0xa6, 0xe8, + 0xc0, 0x74, 0x36, 0x7d, 0x3a, 0xe9, 0x06, 0xd7, 0x19, 0xb0, 0x88, 0x60, 0x4b, 0x85, 0xe3, 0x51, 0x6a, 0x37, 0x48, + 0x98, 0x08, 0x6e, 0xa2, 0x5e, 0x76, 0xb4, 0x4c, 0xc9, 0xaa, 0x80, 0xe7, 0x57, 0xae, 0x32, 0x1d, 0x47, 0x43, 0xbf, + 0x7f, 0x95, 0x9a, 0xd0, 0xaf, 0xd4, 0x4b, 0x55, 0x9c, 0x87, 0x51, 0x75, 0xa8, 0x30, 0x46, 0x4b, 0x9a, 0xc2, 0x31, + 0x98, 0x5d, 0x84, 0x29, 0x5e, 0xce, 0x36, 0x09, 0xfb, 0x82, 0x81, 0x5c, 0x6a, 0x83, 0x7a, 0x4d, 0x89, 0xd6, 0xac, + 0xbd, 0x99, 0x53, 0x42, 0x2f, 0x58, 0xe9, 0xdf, 0x85, 0xd6, 0x20, 0x50, 0x94, 0xcd, 0x94, 0xe9, 0xb9, 0x6e, 0xe7, + 0x05, 0x4d, 0x68, 0x41, 0x57, 0xa4, 0x06, 0x7d, 0xaf, 0x93, 0xb3, 0xa3, 0x93, 0x9d, 0x99, 0xf5, 0x98, 0x15, 0xc3, + 0xc9, 0x34, 0x86, 0x6b, 0x5a, 0xec, 0xae, 0x69, 0xcb, 0xe6, 0x8d, 0xab, 0xb1, 0x71, 0x1a, 0xb4, 0x0b, 0xa4, 0x6d, + 0x9a, 0xdb, 0x4f, 0x3d, 0x6e, 0x7f, 0x5d, 0xb3, 0xe5, 0xb4, 0xb7, 0xde, 0x6e, 0x7b, 0x29, 0xd8, 0x88, 0x7a, 0x7c, + 0xfc, 0x5a, 0x49, 0xd7, 0x2d, 0x97, 0x9f, 0xc2, 0xb3, 0xc7, 0xd7, 0x2f, 0x7d, 0x70, 0x39, 0x5a, 0xb5, 0xb9, 0xfb, + 0xe5, 0x2e, 0xb2, 0xdc, 0x17, 0x0d, 0x2d, 0xd7, 0x33, 0xd4, 0x24, 0xcf, 0x46, 0x7b, 0x87, 0x5a, 0xb0, 0x9c, 0x75, + 0x13, 0x9e, 0x18, 0xec, 0xd8, 0xab, 0xc6, 0xe6, 0xa8, 0xcc, 0x25, 0xab, 0x41, 0x02, 0x7d, 0x92, 0x67, 0x9a, 0xfe, + 0x41, 0x86, 0xf9, 0xe8, 0x96, 0xe6, 0x80, 0x2b, 0x56, 0xd9, 0x4b, 0x06, 0xa9, 0xab, 0xf6, 0x12, 0x57, 0xbe, 0xc2, + 0x21, 0xd9, 0xe0, 0x93, 0x61, 0xaa, 0x3e, 0xbb, 0xe4, 0xc1, 0xff, 0xdb, 0xaa, 0x55, 0x7a, 0x6e, 0x92, 0x1b, 0x8e, + 0x7f, 0x9d, 0xb4, 0x7d, 0x4c, 0x0c, 0x12, 0xf0, 0xd4, 0x2e, 0x86, 0x6a, 0x54, 0x15, 0xb1, 0x28, 0x73, 0x13, 0x73, + 0xec, 0xde, 0xae, 0xa1, 0x83, 0x32, 0xf8, 0x75, 0xc3, 0x27, 0xe6, 0x0e, 0x6c, 0x05, 0x3a, 0x3a, 0xd1, 0x5c, 0x86, + 0x99, 0xb9, 0x0c, 0xd3, 0xae, 0xad, 0x02, 0xc3, 0xab, 0xb6, 0x4a, 0xa2, 0x5c, 0x8d, 0x7a, 0xdc, 0xcc, 0x52, 0xb3, + 0x17, 0x79, 0xf7, 0x9a, 0xf4, 0x24, 0xfe, 0x74, 0xe9, 0xc9, 0xeb, 0x61, 0x40, 0xe4, 0x97, 0x2c, 0x0d, 0xd7, 0x28, + 0x08, 0x4e, 0xad, 0x76, 0x20, 0xcd, 0x47, 0x80, 0xcc, 0x8f, 0xd3, 0xf0, 0x9d, 0x16, 0xe7, 0x90, 0x8d, 0xd2, 0x38, + 0xb1, 0xa5, 0x51, 0x0f, 0xc1, 0x9d, 0xf7, 0x8a, 0xc7, 0x10, 0xf8, 0xf0, 0x03, 0x6e, 0x06, 0x15, 0xdd, 0x96, 0x98, + 0x28, 0x6d, 0x1e, 0x75, 0xcb, 0x47, 0x0d, 0xa1, 0x92, 0x95, 0xe1, 0x25, 0xd0, 0xde, 0x1d, 0x81, 0x51, 0xe5, 0x04, + 0x32, 0xc3, 0x62, 0xff, 0x60, 0x98, 0x2a, 0x41, 0xd1, 0x50, 0x0e, 0x97, 0x28, 0x07, 0xc4, 0x24, 0x10, 0x18, 0x15, + 0x83, 0x54, 0x57, 0xa6, 0x5e, 0x0c, 0x52, 0x7d, 0xab, 0x22, 0xf5, 0x59, 0x16, 0x56, 0x54, 0xb7, 0x88, 0x8e, 0xe9, + 0x50, 0xd2, 0xa5, 0xd9, 0xa9, 0xb9, 0x96, 0x5e, 0xa8, 0xe5, 0xf8, 0x5c, 0xa7, 0xc1, 0x28, 0x9e, 0xba, 0x14, 0xfd, + 0x56, 0xed, 0x67, 0xff, 0x2d, 0xa6, 0xd4, 0x88, 0x4d, 0xed, 0x2d, 0x62, 0x58, 0xb5, 0x1f, 0xb2, 0x2a, 0x07, 0xed, + 0x2e, 0x28, 0x1b, 0x2b, 0xe3, 0x3c, 0xdf, 0x08, 0x66, 0x0e, 0xda, 0xc6, 0xaa, 0xe9, 0x43, 0x6f, 0xc4, 0xa8, 0xbd, + 0x31, 0xd5, 0xb8, 0x27, 0xf0, 0xd3, 0x06, 0x4d, 0xf7, 0x22, 0xcf, 0x51, 0x8f, 0xbc, 0xfb, 0x9f, 0x39, 0xb2, 0x33, + 0xf9, 0x2c, 0x96, 0x49, 0xdd, 0x3e, 0x26, 0xc1, 0x42, 0xd5, 0x31, 0xba, 0x70, 0x23, 0x53, 0xda, 0xcf, 0x9d, 0xe9, + 0x47, 0x3c, 0x93, 0x87, 0xed, 0xd0, 0xa8, 0x2f, 0x0d, 0x6b, 0x49, 0x11, 0xf5, 0x05, 0xbd, 0x35, 0xd5, 0xd1, 0x01, + 0xf5, 0x3a, 0x02, 0xab, 0x2b, 0xda, 0xa0, 0x06, 0x60, 0x32, 0xae, 0x6d, 0x6d, 0x3e, 0x07, 0x53, 0x5b, 0x55, 0xc1, + 0x33, 0xba, 0x2b, 0x94, 0xee, 0x4d, 0xea, 0xba, 0x35, 0xc4, 0x16, 0x30, 0x20, 0x70, 0xa3, 0xa7, 0xa6, 0x3f, 0x68, + 0xa2, 0x02, 0xd0, 0xa0, 0x71, 0x3b, 0xd3, 0x39, 0x12, 0xfd, 0x4e, 0x6d, 0xda, 0x66, 0xaa, 0x57, 0x95, 0x0f, 0xa0, + 0xe2, 0xcf, 0xd2, 0xd9, 0x85, 0x19, 0xb1, 0x00, 0xc6, 0x3d, 0x70, 0xa6, 0x7a, 0xc7, 0x19, 0x58, 0x4f, 0xe4, 0x79, + 0x56, 0xf2, 0x44, 0x0a, 0x98, 0x11, 0x79, 0x75, 0x25, 0x05, 0x0c, 0x83, 0x1a, 0x00, 0xb4, 0x68, 0x2e, 0xa3, 0x09, + 0x7f, 0x52, 0xd3, 0xfb, 0xf2, 0xf0, 0x27, 0x3a, 0xd7, 0x37, 0xe3, 0x1a, 0x0c, 0x95, 0xd7, 0x15, 0xdf, 0xc9, 0xf4, + 0x0d, 0x7f, 0xea, 0x65, 0x5a, 0xca, 0x75, 0xb1, 0x93, 0xe5, 0xc9, 0x37, 0xfc, 0x99, 0xce, 0x73, 0xf0, 0xb4, 0xa6, + 0x69, 0x7c, 0xb7, 0x93, 0xe5, 0xef, 0xdf, 0x3c, 0xb5, 0x79, 0x9e, 0x8c, 0x6b, 0x7a, 0xc3, 0xf9, 0x47, 0x97, 0x69, + 0xa2, 0xab, 0x1a, 0x3f, 0xfd, 0xbb, 0xcd, 0xf5, 0xb4, 0xa6, 0x57, 0x52, 0x54, 0xcb, 0x9d, 0xa2, 0x0e, 0xbe, 0x39, + 0xf8, 0x3b, 0xff, 0xc6, 0x74, 0xef, 0xa0, 0xa6, 0x7f, 0xad, 0xe3, 0xa2, 0xe2, 0xc5, 0x4e, 0x71, 0x7f, 0xfb, 0xfb, + 0xdf, 0x9f, 0xda, 0x8c, 0x4f, 0x6b, 0x7a, 0xc7, 0xe3, 0x8e, 0xb6, 0x4f, 0x9e, 0x3d, 0xe5, 0x7f, 0xab, 0x6b, 0xfa, + 0x0b, 0xf3, 0x83, 0xa3, 0x1e, 0x67, 0x9e, 0x1e, 0x3e, 0x91, 0x4d, 0xd4, 0x80, 0xa1, 0x87, 0x06, 0x90, 0x4b, 0xab, + 0xa6, 0xb9, 0xc7, 0x2b, 0x17, 0xdc, 0xbe, 0xcf, 0xe2, 0x34, 0x5e, 0xc1, 0x41, 0xb0, 0x41, 0xe3, 0xac, 0x02, 0x38, + 0x55, 0xe0, 0x3d, 0xa3, 0x92, 0x66, 0xa5, 0xfc, 0x27, 0xe7, 0x1f, 0x61, 0xd0, 0x10, 0xd2, 0x46, 0x45, 0x06, 0x3a, + 0x59, 0xe9, 0xc8, 0x46, 0xe8, 0xbf, 0xd9, 0x8c, 0x83, 0xe3, 0xc3, 0xe8, 0xf5, 0xfb, 0x61, 0xc1, 0x44, 0x58, 0x10, + 0x42, 0xff, 0x0c, 0x0b, 0x70, 0x28, 0x29, 0x98, 0x97, 0xcf, 0xf8, 0x9e, 0x6b, 0xa3, 0xb0, 0x10, 0x44, 0x77, 0x91, + 0x7d, 0x40, 0xd5, 0xa3, 0xef, 0xd0, 0x0d, 0xf1, 0xb2, 0xc2, 0x82, 0xa1, 0x55, 0x0d, 0xcc, 0x10, 0x14, 0xff, 0x86, + 0x87, 0x12, 0x7c, 0xe2, 0x01, 0x3e, 0x7a, 0x4c, 0x66, 0x5c, 0x5d, 0x6b, 0x4f, 0x2e, 0xc2, 0x82, 0x06, 0xba, 0xed, + 0x10, 0x74, 0x20, 0xf2, 0x5f, 0x80, 0xa7, 0xc0, 0xc0, 0x87, 0x85, 0x5d, 0xca, 0x5d, 0x7f, 0xf5, 0x5f, 0x0c, 0xeb, + 0xe8, 0xc2, 0x8f, 0xfe, 0x62, 0x5d, 0xd8, 0x33, 0x32, 0x95, 0x87, 0xe5, 0x70, 0x32, 0x1d, 0x0c, 0xa4, 0x8b, 0xe3, + 0x76, 0x9c, 0xcd, 0x7f, 0x99, 0xcb, 0xc5, 0x02, 0x75, 0xdf, 0x38, 0xaf, 0x33, 0xfd, 0x37, 0xd2, 0xce, 0x07, 0x6f, + 0x8e, 0x7f, 0x3b, 0x3b, 0x3d, 0x7e, 0x05, 0xce, 0x07, 0x1f, 0x5e, 0x7e, 0xff, 0xf2, 0xbd, 0x0a, 0xee, 0xae, 0xe6, + 0xbc, 0xdf, 0x77, 0x52, 0x9f, 0x90, 0x0f, 0x2b, 0xb2, 0x1f, 0xc6, 0x8f, 0x0b, 0x65, 0xf4, 0x40, 0x0e, 0x99, 0x85, + 0x42, 0x86, 0x2a, 0x6a, 0xfb, 0xbb, 0x1c, 0x4e, 0x3c, 0x30, 0x8b, 0xbb, 0x86, 0x08, 0xd7, 0x6f, 0xb9, 0x0d, 0xb2, + 0x26, 0x8f, 0xbc, 0x7e, 0x70, 0x32, 0x95, 0x8e, 0x2d, 0x2c, 0x18, 0x94, 0x0d, 0x6d, 0x3a, 0xce, 0xe6, 0xc5, 0xc2, + 0xb6, 0xcb, 0x2d, 0x90, 0x51, 0x9a, 0x5d, 0x5c, 0x84, 0x0a, 0xba, 0xfa, 0x08, 0x34, 0x00, 0xa6, 0x51, 0x85, 0x6b, + 0x11, 0x9f, 0xf9, 0xe5, 0x47, 0x63, 0xaf, 0x79, 0xb7, 0xa8, 0x7b, 0x32, 0xcd, 0xaa, 0x1a, 0x03, 0x3a, 0x98, 0x50, + 0xee, 0x06, 0xdd, 0x04, 0x93, 0x51, 0x6d, 0xf9, 0x65, 0x5e, 0x2d, 0x4c, 0x73, 0xdc, 0x30, 0x54, 0x5e, 0xc9, 0x6b, + 0xd9, 0x40, 0x64, 0x20, 0x19, 0x86, 0x3d, 0x1a, 0xa3, 0x48, 0x7d, 0x6f, 0xd7, 0x3b, 0x7e, 0x93, 0x4b, 0x88, 0xa6, + 0x98, 0x81, 0x74, 0xfe, 0x58, 0x28, 0xe7, 0x72, 0xc9, 0xf8, 0x5c, 0x2c, 0x8e, 0xc0, 0xed, 0x7c, 0x2e, 0x16, 0x11, + 0x06, 0xe5, 0xcb, 0x20, 0x56, 0x09, 0xd8, 0xbd, 0x38, 0x08, 0xdf, 0x4e, 0x68, 0x03, 0xbb, 0x81, 0x24, 0x1b, 0x94, + 0x76, 0xa5, 0x21, 0xca, 0x9d, 0xf2, 0x68, 0x83, 0xc8, 0x43, 0xac, 0x9a, 0x57, 0x6d, 0x4f, 0x36, 0x73, 0x31, 0xc1, + 0x55, 0x16, 0x33, 0x39, 0x8d, 0x0f, 0x59, 0x31, 0x8d, 0xa1, 0x94, 0x38, 0x4d, 0xc3, 0x98, 0x4e, 0xa8, 0x20, 0x24, + 0x61, 0x7c, 0x1e, 0x2f, 0x68, 0x82, 0x52, 0x82, 0x10, 0x42, 0x7e, 0x8c, 0xd0, 0x36, 0x07, 0x96, 0xbc, 0xdd, 0x7e, + 0x9e, 0x7e, 0x6e, 0xc7, 0x70, 0x19, 0x15, 0xa1, 0x1b, 0x74, 0xd6, 0xf0, 0x6f, 0x44, 0x05, 0x8d, 0xb1, 0x62, 0x08, + 0x02, 0x5e, 0x60, 0x54, 0xc2, 0x82, 0xc4, 0xac, 0x82, 0x28, 0x02, 0xe5, 0x3c, 0x5e, 0xb0, 0x82, 0x36, 0x6d, 0x4e, + 0x63, 0x6d, 0x12, 0xd4, 0x73, 0x58, 0x6a, 0x7b, 0x52, 0xa9, 0x10, 0x7b, 0x7c, 0x26, 0xa2, 0x6b, 0x6d, 0x68, 0x00, + 0x28, 0x50, 0x4a, 0x2e, 0x7e, 0xf3, 0xe5, 0x1e, 0x6e, 0x0a, 0xfa, 0x9f, 0x6d, 0x4c, 0xb4, 0xb3, 0x5c, 0x1d, 0x7a, + 0xf3, 0x05, 0x8d, 0xf3, 0x1c, 0x42, 0xb1, 0x19, 0x04, 0x72, 0x91, 0x55, 0x10, 0xd1, 0xe2, 0x2e, 0x30, 0x21, 0xe1, + 0xa0, 0x4d, 0xbf, 0x40, 0x6a, 0x43, 0x4c, 0xae, 0x3c, 0x31, 0xb0, 0xdb, 0x2a, 0x41, 0xc0, 0x91, 0x9e, 0x67, 0x9f, + 0x9a, 0x18, 0x6b, 0x9a, 0x9a, 0x99, 0x78, 0x1b, 0x0a, 0xd1, 0xa0, 0x05, 0xd1, 0x0c, 0xde, 0x3f, 0x57, 0x1c, 0xaf, + 0x3a, 0xf0, 0x03, 0xde, 0xb9, 0x38, 0xf3, 0x6a, 0xe6, 0x11, 0x39, 0xf5, 0x51, 0x8e, 0xe8, 0x97, 0x3c, 0xac, 0x46, + 0x3a, 0x19, 0x63, 0x25, 0x71, 0xd0, 0xdb, 0x60, 0xc1, 0x9c, 0xd0, 0x15, 0x0f, 0x2d, 0x1f, 0xff, 0x0a, 0x99, 0x8c, + 0x92, 0x1a, 0x2b, 0xba, 0xd2, 0x62, 0xc4, 0x79, 0x0d, 0xb3, 0x34, 0x59, 0xd1, 0xc5, 0x42, 0x93, 0x66, 0xa1, 0x4c, + 0x03, 0x7c, 0x02, 0x2d, 0x46, 0xee, 0xa1, 0xa6, 0x0d, 0x84, 0x86, 0xdd, 0x21, 0xe0, 0x23, 0xf7, 0xd0, 0xe1, 0xff, + 0xe7, 0xd9, 0x05, 0x22, 0xed, 0xcd, 0x4d, 0x64, 0x3c, 0x52, 0x37, 0x70, 0x50, 0x8c, 0x8f, 0x7d, 0x33, 0xf1, 0x0b, + 0x67, 0xf4, 0x21, 0xa9, 0x7c, 0x87, 0x0f, 0x96, 0x3f, 0xde, 0xd4, 0xcc, 0xca, 0x08, 0xd6, 0xc3, 0x76, 0x8b, 0x0b, + 0xa2, 0xed, 0x02, 0x48, 0x3d, 0xe3, 0xd5, 0xc2, 0x37, 0x5e, 0x8d, 0xef, 0x31, 0x5e, 0x75, 0x67, 0x6a, 0x98, 0x93, + 0x0d, 0xea, 0xb3, 0x94, 0x3c, 0x3f, 0x47, 0x99, 0x60, 0xd3, 0xe5, 0xac, 0xa4, 0x2a, 0x95, 0xd0, 0x5e, 0xec, 0x67, + 0x8c, 0x6f, 0x09, 0xc6, 0x59, 0x71, 0x18, 0x09, 0x54, 0xa5, 0x92, 0x3a, 0xec, 0x15, 0xa0, 0x1e, 0x83, 0xf7, 0x06, + 0x43, 0xd4, 0xc8, 0xd8, 0x4d, 0x1b, 0x08, 0x0d, 0x8d, 0xf5, 0x68, 0xcf, 0x5a, 0x8f, 0x6e, 0xb7, 0x95, 0xf1, 0xb7, + 0x93, 0xeb, 0x22, 0x41, 0x54, 0x61, 0x35, 0x9a, 0x00, 0x6f, 0x9a, 0xd8, 0xdb, 0x92, 0x53, 0x5a, 0x60, 0xf8, 0xec, + 0x3f, 0xc3, 0xd2, 0xa9, 0x24, 0x4a, 0x32, 0x2b, 0xa3, 0x81, 0x3b, 0x07, 0x5f, 0xc4, 0x15, 0xac, 0x01, 0x88, 0xe4, + 0x88, 0x1e, 0xae, 0x7f, 0x86, 0xd2, 0x65, 0x96, 0x64, 0x26, 0x21, 0x33, 0x17, 0x69, 0x3b, 0xeb, 0x60, 0xe2, 0x4c, + 0x6a, 0xbd, 0xb1, 0x90, 0x43, 0x83, 0xfc, 0x00, 0xca, 0x10, 0x87, 0x4f, 0x3e, 0x98, 0x50, 0xa9, 0x42, 0xa9, 0x36, + 0xba, 0xd9, 0x0d, 0xbc, 0xf2, 0x21, 0xbb, 0xe2, 0x65, 0x15, 0x5f, 0xad, 0x8c, 0x25, 0x31, 0x67, 0xf7, 0xb9, 0xed, + 0x51, 0x61, 0x5e, 0xbd, 0x7d, 0xf9, 0xfd, 0x71, 0xe3, 0xd5, 0x2e, 0xe2, 0x68, 0x08, 0xb6, 0x15, 0x63, 0x8c, 0xde, + 0xe2, 0xd3, 0x60, 0xa2, 0x5c, 0x23, 0xd0, 0xbb, 0x14, 0xf4, 0xdb, 0x5f, 0xea, 0x09, 0x78, 0xc5, 0xf5, 0xf2, 0x4b, + 0x3e, 0x02, 0x96, 0xa8, 0xd0, 0xb3, 0xc2, 0xdc, 0xac, 0xcc, 0xee, 0xed, 0x56, 0x64, 0xa6, 0x5d, 0x69, 0x64, 0x20, + 0x5e, 0x6d, 0x87, 0xb1, 0x70, 0xe9, 0x9a, 0x6e, 0x07, 0xbb, 0x5a, 0x7a, 0x96, 0xc8, 0xdb, 0x6d, 0x09, 0x1d, 0xb2, + 0x03, 0xee, 0xbd, 0x8c, 0x6f, 0xe1, 0x65, 0xe9, 0x75, 0xb3, 0x19, 0x3c, 0x01, 0xcc, 0x84, 0x0b, 0x67, 0x59, 0x1c, + 0x33, 0x9e, 0x84, 0x2a, 0x36, 0x57, 0x43, 0xe4, 0xad, 0x08, 0xad, 0xd9, 0x5f, 0xa1, 0x18, 0x81, 0xdd, 0xc9, 0xe9, + 0xc7, 0x6c, 0x35, 0x5b, 0x02, 0x6a, 0xfe, 0x55, 0x26, 0x80, 0xe6, 0xda, 0xb5, 0x60, 0x9b, 0x42, 0x9b, 0xeb, 0xfa, + 0x79, 0xbc, 0x8a, 0x13, 0x50, 0xdd, 0x80, 0xb7, 0xc8, 0x9d, 0x16, 0x5d, 0x19, 0x74, 0x51, 0xfa, 0x40, 0x39, 0x96, + 0x14, 0x3a, 0xfa, 0xde, 0x13, 0xea, 0xdc, 0x33, 0x80, 0x4b, 0x1a, 0x35, 0x4f, 0xb5, 0x94, 0xb1, 0x00, 0x58, 0xe8, + 0x60, 0xa6, 0xc8, 0x56, 0x74, 0x6b, 0x30, 0x29, 0xe0, 0xad, 0x01, 0xfe, 0x10, 0x59, 0xa5, 0xee, 0x8a, 0x65, 0x58, + 0x7a, 0xf6, 0xd7, 0xfd, 0x7e, 0xec, 0xd9, 0x5f, 0x5f, 0x68, 0x5a, 0x17, 0xb7, 0x1b, 0x40, 0x6a, 0x0c, 0x20, 0x72, + 0xac, 0x07, 0xc2, 0x44, 0x14, 0x6b, 0xfa, 0xfe, 0x1d, 0x9b, 0x2c, 0x0a, 0x84, 0x7e, 0xa7, 0x5e, 0x4f, 0x4a, 0x02, + 0x3a, 0xb5, 0x8a, 0x1d, 0x0d, 0xb4, 0xd9, 0x07, 0x04, 0x44, 0xf5, 0x33, 0xb2, 0xf9, 0x42, 0x39, 0x17, 0xab, 0xf0, + 0xe1, 0x63, 0x0a, 0x01, 0x85, 0x3b, 0x6a, 0x74, 0xde, 0x86, 0x48, 0xa0, 0xac, 0x50, 0xc4, 0x9a, 0x17, 0x6b, 0x49, + 0xc8, 0x7c, 0xbc, 0x40, 0xc1, 0x95, 0x03, 0x76, 0xe5, 0x6c, 0x32, 0x2c, 0x23, 0xce, 0xc2, 0xfb, 0xbf, 0x99, 0x2c, + 0x08, 0x6a, 0xae, 0xfc, 0x40, 0x8e, 0x3b, 0x99, 0x1a, 0x7b, 0xaa, 0x51, 0x83, 0x60, 0x32, 0x82, 0xc0, 0x70, 0xc3, + 0x2f, 0xf8, 0xf8, 0x60, 0x41, 0x40, 0x45, 0x66, 0xcd, 0x42, 0xcc, 0x8b, 0xc3, 0x27, 0x80, 0x1a, 0x33, 0x3a, 0x78, + 0x36, 0xe5, 0x0c, 0x0e, 0x51, 0x3a, 0x06, 0x19, 0xad, 0x80, 0xdf, 0x42, 0xfd, 0x6e, 0x9d, 0xf8, 0x3e, 0xf4, 0xab, + 0xa0, 0x17, 0x31, 0x30, 0x1c, 0xd1, 0x64, 0x3f, 0xe4, 0x83, 0xc9, 0x00, 0xb4, 0x25, 0xde, 0xee, 0x6b, 0x69, 0xc5, + 0xcd, 0xe9, 0xd2, 0xe9, 0xfe, 0x49, 0x9b, 0x20, 0x89, 0x54, 0xb2, 0x52, 0x11, 0x03, 0x08, 0x65, 0xa9, 0xb6, 0xc9, + 0x12, 0x2c, 0x2b, 0xcc, 0x92, 0xe6, 0x06, 0x25, 0x71, 0x77, 0x33, 0x70, 0x8c, 0x9a, 0x75, 0x1c, 0x96, 0x2d, 0x37, + 0x6a, 0x80, 0xcf, 0x49, 0x58, 0x61, 0x6f, 0x38, 0x33, 0xe9, 0x9d, 0xe9, 0x70, 0x75, 0xcc, 0xd9, 0x1b, 0x8e, 0x60, + 0x1c, 0x09, 0xde, 0x78, 0xe8, 0x92, 0x69, 0xa8, 0xc8, 0x94, 0x71, 0x30, 0xed, 0x01, 0xee, 0x3d, 0x07, 0xe3, 0x30, + 0x36, 0xa8, 0x2c, 0xa9, 0x4f, 0xbd, 0xbb, 0x10, 0x08, 0xd2, 0x5a, 0x2f, 0xf3, 0x19, 0x9e, 0x9e, 0x11, 0xca, 0xfe, + 0x90, 0xc3, 0x17, 0x60, 0x47, 0x41, 0x8e, 0x26, 0xfc, 0xd9, 0xe3, 0xdd, 0x40, 0x55, 0x7c, 0x10, 0xec, 0xc5, 0x22, + 0xdd, 0x0b, 0x06, 0x02, 0x7e, 0x15, 0x7c, 0xaf, 0x92, 0x72, 0xef, 0x22, 0x2e, 0xf6, 0xe2, 0x55, 0x5c, 0x54, 0x7b, + 0x37, 0x59, 0xb5, 0xdc, 0x33, 0x1d, 0x02, 0x68, 0xde, 0x60, 0x10, 0x0f, 0x82, 0xbd, 0x60, 0x50, 0x98, 0xa9, 0x5d, + 0xb1, 0xb2, 0x71, 0x9c, 0x99, 0x10, 0x65, 0x41, 0x33, 0x40, 0x58, 0xe3, 0x34, 0x00, 0x3e, 0x75, 0xcd, 0x52, 0x7a, + 0x81, 0xe1, 0x06, 0xc4, 0x74, 0x0d, 0x7d, 0x00, 0x1e, 0x79, 0x4d, 0x63, 0x58, 0x02, 0x17, 0x83, 0x01, 0x59, 0x43, + 0xe4, 0x82, 0x35, 0xb5, 0x41, 0x1c, 0xc2, 0xb5, 0xb2, 0xd3, 0xde, 0x05, 0x66, 0xda, 0x6e, 0x01, 0x51, 0x79, 0x42, + 0xfa, 0x7d, 0xfb, 0x0d, 0xf5, 0x2f, 0xd8, 0x4b, 0xb0, 0xbf, 0x2a, 0xaa, 0x30, 0x91, 0x4a, 0xf3, 0x7d, 0xc9, 0x8e, + 0x06, 0x2a, 0xe2, 0xf0, 0x8e, 0x23, 0x45, 0x1b, 0x95, 0xcb, 0xb2, 0x27, 0xcb, 0x86, 0xaf, 0xc4, 0x15, 0x77, 0x7e, + 0x5c, 0x95, 0x94, 0x79, 0x95, 0xad, 0x14, 0xfb, 0x37, 0xe3, 0x9a, 0xfb, 0x03, 0xeb, 0xcf, 0xe6, 0x2b, 0xb8, 0xb6, + 0x7a, 0xef, 0x9a, 0x5c, 0x23, 0x72, 0x96, 0x50, 0x2e, 0xa9, 0x6d, 0x1e, 0xde, 0xd2, 0xf7, 0xf9, 0xd5, 0xb7, 0x99, + 0x4e, 0xe3, 0xb3, 0x0a, 0x0b, 0x17, 0xa2, 0x15, 0xc1, 0xa1, 0x21, 0x17, 0xcd, 0x23, 0xc0, 0x5c, 0xfb, 0x6c, 0x05, + 0x05, 0xa9, 0xcf, 0x2a, 0xf4, 0x6e, 0x85, 0x84, 0x57, 0x9a, 0x5d, 0x7a, 0x18, 0x48, 0x19, 0xb7, 0x87, 0x96, 0x30, + 0x69, 0x79, 0x11, 0xde, 0x7b, 0xcd, 0x4d, 0xee, 0x45, 0x88, 0xd1, 0x8b, 0x3c, 0x3b, 0x01, 0x63, 0xdd, 0x25, 0x3b, + 0x1b, 0x9e, 0xf8, 0x0d, 0xcf, 0x59, 0x8b, 0x46, 0xd3, 0x25, 0x4b, 0xfa, 0xfd, 0x18, 0x4c, 0xbc, 0x53, 0x96, 0xc3, + 0xaf, 0x7c, 0x41, 0xd7, 0x0c, 0x30, 0xc5, 0xe8, 0x05, 0x24, 0xa4, 0x88, 0x44, 0xb2, 0x56, 0x27, 0xc9, 0x67, 0xba, + 0x0b, 0xc0, 0xe8, 0x17, 0xb3, 0x34, 0x5a, 0xde, 0x6b, 0x66, 0x81, 0xe4, 0x19, 0xfa, 0xae, 0x83, 0xed, 0x8d, 0x7d, + 0x90, 0x72, 0x7e, 0x28, 0xa6, 0x83, 0x01, 0x27, 0x1a, 0x6e, 0xbc, 0x54, 0xe2, 0x5a, 0xdd, 0xe2, 0x8e, 0x61, 0x2c, + 0xf5, 0x6d, 0x11, 0x83, 0x03, 0x76, 0xd1, 0xca, 0x6e, 0x1f, 0x60, 0x5f, 0x39, 0xde, 0xa5, 0xca, 0xee, 0xf4, 0x98, + 0x69, 0x2e, 0x5b, 0x4d, 0x3a, 0xa9, 0xb8, 0x9f, 0xc8, 0x37, 0xb9, 0x83, 0x2e, 0x97, 0x63, 0xcd, 0x5b, 0x0e, 0x40, + 0x45, 0x3f, 0x52, 0x54, 0xf7, 0x0b, 0x1c, 0x61, 0x1e, 0xac, 0xdb, 0x7c, 0xb2, 0x6f, 0x0a, 0x1c, 0x22, 0x4f, 0xda, + 0x68, 0x0a, 0xe8, 0xde, 0xc5, 0xe3, 0xae, 0x7e, 0x5b, 0xba, 0x0b, 0x94, 0x68, 0xa7, 0xe2, 0x86, 0x1f, 0x13, 0x75, + 0x3a, 0xd3, 0x86, 0xd0, 0xbf, 0x32, 0xe2, 0xfe, 0xd2, 0xb8, 0x8a, 0x37, 0xbd, 0xcb, 0x67, 0x1c, 0xea, 0xec, 0x86, + 0x50, 0x00, 0xae, 0xda, 0xd3, 0xa9, 0x1b, 0x43, 0x7a, 0xa5, 0x44, 0xb7, 0xc1, 0xc1, 0xee, 0xf5, 0x19, 0x47, 0xd1, + 0x8f, 0x51, 0x23, 0xdf, 0x44, 0xe2, 0xb1, 0x1c, 0xc4, 0x8f, 0x0b, 0xba, 0x8c, 0xc4, 0xe3, 0x62, 0x10, 0x3f, 0x96, + 0x75, 0xbd, 0x7b, 0xae, 0xdc, 0xdf, 0x47, 0xe4, 0x59, 0x77, 0xf6, 0x52, 0x09, 0x1b, 0x03, 0xcf, 0xae, 0x05, 0x84, + 0x53, 0xf0, 0x44, 0xb6, 0x96, 0x3e, 0x74, 0x6e, 0xf7, 0xb1, 0x65, 0x92, 0x20, 0xe8, 0x79, 0x9b, 0x4d, 0xa2, 0xd8, + 0xd9, 0xe6, 0xd1, 0x87, 0x53, 0x20, 0xa1, 0xdb, 0x6d, 0xb3, 0xae, 0xd6, 0x80, 0x62, 0x1a, 0x8e, 0xf9, 0x7e, 0x31, + 0xba, 0xf1, 0xdd, 0xf5, 0xf7, 0x8b, 0xd1, 0x92, 0x0c, 0x27, 0x66, 0xf2, 0xe3, 0xa3, 0xf1, 0x2c, 0x8e, 0x26, 0x75, + 0xc7, 0x69, 0xa1, 0xf1, 0x4f, 0xbd, 0x5b, 0x28, 0x02, 0xa7, 0x62, 0x04, 0x47, 0x4e, 0x85, 0x72, 0x52, 0x6a, 0x60, + 0xf8, 0xef, 0x55, 0x3b, 0xda, 0xb4, 0x37, 0x71, 0x95, 0x2c, 0x33, 0x71, 0xa9, 0xc3, 0x87, 0xeb, 0xe8, 0xe2, 0x36, + 0xa0, 0x9d, 0x77, 0x99, 0x76, 0xfc, 0x3a, 0x69, 0xd0, 0x13, 0x57, 0x33, 0x03, 0x6e, 0xdd, 0x8f, 0xd0, 0x0c, 0x81, + 0xd1, 0xf2, 0xfc, 0x1d, 0x62, 0x6e, 0xff, 0xaa, 0x6c, 0x7e, 0x15, 0xed, 0x73, 0x64, 0xa4, 0x6c, 0x93, 0x91, 0x0a, + 0x8c, 0x30, 0xa5, 0x48, 0xe2, 0x2a, 0x84, 0x40, 0xf6, 0x5f, 0x52, 0x5c, 0x8b, 0xa5, 0xf7, 0x1a, 0x84, 0x09, 0xb6, + 0x0b, 0xda, 0xaf, 0x6e, 0xe7, 0xb6, 0xd2, 0x62, 0x8f, 0xd4, 0xf7, 0xb9, 0xb3, 0x5d, 0xd1, 0xe4, 0xef, 0xcb, 0x06, + 0xb4, 0x01, 0x44, 0x79, 0x5f, 0x1f, 0x95, 0xc0, 0xc9, 0x88, 0x1b, 0x4a, 0x8c, 0x5e, 0xd0, 0xd5, 0x89, 0xdc, 0xb3, + 0x53, 0xf3, 0xa6, 0x62, 0xa6, 0xe2, 0xca, 0x37, 0x7b, 0xe6, 0x3f, 0x18, 0x0a, 0x2a, 0xc0, 0xc0, 0xdb, 0x9c, 0xf1, + 0xe8, 0x40, 0x77, 0x63, 0x74, 0x5a, 0xb0, 0x59, 0x50, 0x97, 0x75, 0xd3, 0xc6, 0x83, 0x46, 0x1c, 0x14, 0xc5, 0xaa, + 0x50, 0x23, 0xe1, 0x89, 0x40, 0xc0, 0x94, 0x5d, 0xf1, 0xc8, 0x08, 0x6a, 0x7a, 0x13, 0x0a, 0x1b, 0x0a, 0xfe, 0x2a, + 0x51, 0x4d, 0x6f, 0x42, 0x9b, 0x4c, 0x9c, 0x66, 0x10, 0xc1, 0x8c, 0xd8, 0xee, 0xb7, 0x80, 0x36, 0xb7, 0x66, 0xb4, + 0xa9, 0x6b, 0xab, 0xad, 0x42, 0x2e, 0x29, 0x52, 0x96, 0xff, 0x4e, 0x4d, 0x05, 0x25, 0xb5, 0x5c, 0xf4, 0x26, 0x4d, + 0x17, 0x3d, 0x9e, 0x19, 0x49, 0xa0, 0x72, 0xcb, 0x1d, 0xa3, 0x3f, 0x84, 0x05, 0x1e, 0x31, 0x71, 0x62, 0xc1, 0xdc, + 0xea, 0x88, 0x65, 0x73, 0xb1, 0x18, 0xad, 0x24, 0x84, 0x0d, 0x3e, 0x64, 0xd9, 0xbc, 0xd4, 0x0f, 0xa1, 0x2f, 0x2c, + 0x3d, 0x01, 0xbb, 0xd8, 0x60, 0x25, 0xcb, 0x00, 0x7c, 0x2f, 0xe8, 0x66, 0x25, 0xcb, 0x48, 0xaa, 0xee, 0xc7, 0x35, + 0x96, 0xa0, 0xd2, 0x0a, 0x95, 0x96, 0xd4, 0x58, 0x10, 0xf8, 0xaa, 0xea, 0xf2, 0x21, 0xd9, 0x55, 0xa0, 0x9e, 0x3a, + 0x6a, 0xc0, 0x29, 0x50, 0x55, 0x60, 0x41, 0x12, 0x54, 0x86, 0xae, 0x0a, 0x4c, 0x2b, 0x30, 0xcd, 0x54, 0xe1, 0xa2, + 0xcc, 0x0e, 0xa5, 0x59, 0x2f, 0xf9, 0x2c, 0x1e, 0x84, 0xc9, 0x30, 0x26, 0x8f, 0x11, 0x6a, 0x7f, 0x3f, 0x8f, 0x62, + 0x2d, 0x97, 0x5c, 0x39, 0xbf, 0xf8, 0x9b, 0xcf, 0xd8, 0xeb, 0x9e, 0x61, 0xb0, 0x00, 0x67, 0x69, 0x7b, 0x95, 0x89, + 0x77, 0xb2, 0x15, 0x1c, 0x07, 0xb3, 0x28, 0x87, 0x55, 0x4f, 0x8e, 0x68, 0x2e, 0x72, 0xed, 0x5d, 0x84, 0xc8, 0x41, + 0x66, 0x8f, 0x01, 0x76, 0x23, 0x7c, 0x1d, 0x5a, 0x9b, 0x5b, 0x5d, 0x21, 0xfe, 0x46, 0x89, 0xc4, 0x4f, 0x52, 0x7e, + 0x5c, 0xaf, 0x54, 0xae, 0xca, 0xe0, 0xb1, 0xea, 0x66, 0xf0, 0x4c, 0xfb, 0x1e, 0x6b, 0xff, 0xd6, 0x76, 0x73, 0xbc, + 0xf7, 0xe0, 0x41, 0xeb, 0x7f, 0xeb, 0x49, 0x08, 0xed, 0x95, 0x93, 0xd4, 0x1d, 0x35, 0x7a, 0x66, 0xb2, 0x46, 0x54, + 0xc2, 0xd4, 0xee, 0x54, 0x8e, 0x81, 0x9a, 0x0e, 0xe0, 0x5a, 0xa2, 0x26, 0xe8, 0x49, 0xc1, 0xc6, 0x70, 0xc4, 0x59, + 0x1c, 0xb4, 0xc3, 0x18, 0xc5, 0xcb, 0xb9, 0x12, 0x2f, 0xe7, 0x47, 0x8c, 0x03, 0xb4, 0x16, 0x20, 0xd5, 0x6b, 0xd8, + 0xcf, 0x5c, 0xc1, 0x02, 0x9b, 0x3b, 0xdf, 0x81, 0x05, 0x32, 0xc4, 0xc9, 0xe6, 0x38, 0xd9, 0xe3, 0x5a, 0xcf, 0xbd, + 0xc0, 0xc7, 0x49, 0xbd, 0xf0, 0xea, 0x2a, 0xdb, 0x75, 0x2d, 0x59, 0x39, 0x2f, 0x06, 0x13, 0x08, 0xca, 0x52, 0xce, + 0x8b, 0xe1, 0x64, 0x41, 0x73, 0xf8, 0xb1, 0x68, 0xa0, 0x43, 0x2c, 0x07, 0x09, 0x5c, 0x3a, 0x7b, 0x0c, 0x78, 0x43, + 0xa9, 0xc5, 0xdd, 0x58, 0x47, 0x8e, 0x75, 0x14, 0xfb, 0x61, 0x0c, 0xb8, 0xb2, 0x4e, 0xe0, 0x7d, 0xff, 0xf5, 0xb1, + 0x09, 0xc8, 0xaa, 0x5d, 0xe1, 0xd5, 0x28, 0x77, 0x5d, 0x69, 0xf4, 0x25, 0xa5, 0x27, 0xbc, 0xe0, 0xa9, 0x64, 0xbb, + 0xed, 0x19, 0x38, 0x5b, 0xe2, 0x21, 0xf1, 0x8e, 0x11, 0xbd, 0x98, 0x36, 0x32, 0x73, 0x02, 0x67, 0xb6, 0xbb, 0x6c, + 0x63, 0x7e, 0xec, 0x00, 0x07, 0x8b, 0x20, 0x24, 0x6e, 0x08, 0xc3, 0xc4, 0x8e, 0xca, 0xa1, 0x16, 0xc2, 0x75, 0x2d, + 0xbc, 0x8e, 0xd3, 0x32, 0x06, 0x17, 0x69, 0x6d, 0x9b, 0x78, 0x0f, 0x5d, 0xf7, 0xfc, 0x98, 0x5b, 0x1d, 0xa3, 0x2d, + 0xa4, 0xdf, 0x8e, 0x4e, 0xef, 0x39, 0x0c, 0x40, 0xd3, 0x83, 0x59, 0xd5, 0x3e, 0x93, 0xb8, 0x39, 0xed, 0x04, 0x21, + 0x11, 0x88, 0xa2, 0x74, 0x46, 0x98, 0xfe, 0x9d, 0xe6, 0xb2, 0x8a, 0x56, 0x0f, 0xf2, 0xcc, 0x21, 0xcf, 0x42, 0x6f, + 0x7b, 0xd0, 0xaa, 0xb9, 0x1b, 0x8c, 0x13, 0xb7, 0xdb, 0x3b, 0xff, 0x6f, 0x59, 0xd7, 0x56, 0x6b, 0xc4, 0xe3, 0x76, + 0xf5, 0x83, 0xc6, 0x5e, 0xed, 0xa9, 0x18, 0x30, 0x2b, 0xe9, 0x9d, 0x51, 0x25, 0x2f, 0x32, 0x5e, 0xe2, 0x49, 0xb5, + 0x6a, 0xf8, 0x78, 0xdf, 0x64, 0x23, 0xf3, 0x40, 0xa6, 0x80, 0x78, 0x7e, 0x93, 0x1a, 0xf5, 0x71, 0x8a, 0x12, 0xf0, + 0x77, 0x3a, 0xbe, 0x11, 0xfd, 0x68, 0x5f, 0x5c, 0xf2, 0xea, 0xe4, 0x46, 0x98, 0x17, 0x2f, 0xac, 0xce, 0x9f, 0xbe, + 0x29, 0x7c, 0xe8, 0x70, 0xd4, 0xde, 0x41, 0x91, 0x25, 0x13, 0x47, 0x13, 0x23, 0x6b, 0x13, 0xb3, 0x8f, 0x0a, 0x2e, + 0x26, 0xaa, 0xd0, 0xb3, 0xce, 0x9e, 0x30, 0x05, 0xe8, 0x1b, 0xc7, 0xa8, 0x64, 0x0c, 0x0b, 0x06, 0xea, 0x34, 0x25, + 0x44, 0x0f, 0xc5, 0x0c, 0xe3, 0x15, 0x03, 0x28, 0x4c, 0xa1, 0x40, 0x14, 0x9d, 0x7d, 0x38, 0xd0, 0x84, 0x7e, 0xff, + 0x26, 0xd5, 0x19, 0x68, 0x59, 0x4f, 0x0b, 0x10, 0xd5, 0x41, 0xb4, 0x55, 0x5e, 0x84, 0x3f, 0x2e, 0x69, 0x99, 0xd1, + 0xa5, 0xa0, 0xa9, 0xa0, 0x49, 0x46, 0x2f, 0xb8, 0x12, 0x15, 0x5f, 0x08, 0xa6, 0x68, 0xbb, 0x21, 0xec, 0x3f, 0x36, + 0xe8, 0x7a, 0x2b, 0xd6, 0x1a, 0xda, 0x9d, 0x20, 0x23, 0x34, 0x5f, 0xe8, 0x20, 0x64, 0xa8, 0x9c, 0x84, 0xae, 0x55, + 0x1a, 0xaf, 0xc0, 0x25, 0xd3, 0x6c, 0xb4, 0x8c, 0xcb, 0x30, 0xb0, 0x5f, 0x05, 0x16, 0x93, 0x03, 0x93, 0x4e, 0xd7, + 0xe7, 0xcf, 0xe5, 0xd5, 0x4a, 0x0a, 0x2e, 0x2a, 0x05, 0xd1, 0x6f, 0x70, 0xdf, 0x4d, 0x5c, 0x75, 0xd6, 0xac, 0x95, + 0x3e, 0xf4, 0xad, 0xcf, 0xda, 0xb8, 0x2f, 0x0c, 0x8e, 0xc1, 0xce, 0x47, 0xc4, 0x40, 0x1a, 0x54, 0xba, 0xc5, 0xa1, + 0x09, 0xd0, 0xa5, 0x43, 0x0a, 0x59, 0x32, 0x95, 0xa9, 0x12, 0x54, 0x7c, 0xe3, 0xf7, 0x52, 0x56, 0xa3, 0xbf, 0xd6, + 0xbc, 0xb8, 0x3b, 0xe5, 0x39, 0xc7, 0x31, 0x0a, 0x92, 0x58, 0x5c, 0xc7, 0x65, 0x40, 0x7c, 0xcb, 0xab, 0xe0, 0x20, + 0x35, 0x61, 0x63, 0x76, 0xaa, 0x46, 0xad, 0x57, 0x81, 0xbe, 0x32, 0xca, 0x37, 0x06, 0x43, 0x13, 0x51, 0x05, 0x7d, + 0xaf, 0xd5, 0x3d, 0xad, 0x6e, 0x58, 0x40, 0xfc, 0xb9, 0xd2, 0x0b, 0xb5, 0x5e, 0x37, 0x63, 0x6e, 0x98, 0x08, 0x41, + 0xa3, 0x27, 0xf5, 0xa2, 0xf6, 0xdc, 0xd2, 0x54, 0x64, 0xdc, 0x68, 0x93, 0xf3, 0x4b, 0x90, 0xf1, 0x39, 0x73, 0xa1, + 0x49, 0x5d, 0x53, 0x05, 0x55, 0x18, 0x6d, 0x6e, 0x1b, 0xe9, 0xf4, 0x0e, 0xdc, 0xd9, 0x8c, 0xd9, 0x91, 0x76, 0x69, + 0xac, 0x69, 0xc1, 0xcb, 0x95, 0x14, 0x25, 0x84, 0x71, 0xee, 0x8d, 0xe9, 0x55, 0x9c, 0x89, 0x2a, 0xce, 0xc4, 0x71, + 0xb9, 0xe2, 0x49, 0xf5, 0x1e, 0x6e, 0x71, 0xca, 0xea, 0xa6, 0x2e, 0xe1, 0x4a, 0x97, 0xec, 0x61, 0x30, 0x35, 0x15, + 0xf7, 0xd8, 0x71, 0x92, 0xd5, 0x1f, 0xd1, 0x52, 0x62, 0x2c, 0x54, 0x5d, 0x7c, 0x7c, 0x5e, 0xca, 0x7c, 0x5d, 0x81, + 0x76, 0xf7, 0xa2, 0x8a, 0x0e, 0x9e, 0xae, 0x6e, 0xa7, 0xea, 0x06, 0x13, 0x3d, 0x3d, 0x58, 0xdd, 0xf6, 0xb2, 0xab, + 0x95, 0x2c, 0xaa, 0x58, 0x54, 0x53, 0x85, 0x48, 0x96, 0xc4, 0x79, 0x12, 0x4e, 0xc6, 0xe3, 0xaf, 0xf6, 0x86, 0x7b, + 0x90, 0x81, 0x4c, 0x3f, 0x0d, 0x95, 0xcb, 0xd1, 0x70, 0x32, 0x1e, 0x4f, 0xa5, 0xba, 0xdb, 0x45, 0xa3, 0x49, 0x8d, + 0xf5, 0x0c, 0x13, 0x3d, 0x33, 0x23, 0x7e, 0xbb, 0x8a, 0x45, 0x0a, 0xf1, 0xeb, 0x74, 0xf1, 0x07, 0x4f, 0xc7, 0x8d, + 0xf2, 0xed, 0xa7, 0xcf, 0xea, 0x3f, 0x6a, 0x13, 0xd6, 0xda, 0xb4, 0xfb, 0xf9, 0x1f, 0x87, 0x6a, 0xbe, 0x8f, 0x0e, + 0xf7, 0xf5, 0x8f, 0x3f, 0xea, 0x7a, 0xfa, 0xa6, 0x08, 0xe7, 0xff, 0x0a, 0xd5, 0x7c, 0x1e, 0x17, 0x45, 0x7c, 0x57, + 0x43, 0x24, 0x4f, 0xe1, 0xbc, 0x49, 0xa8, 0xb7, 0x0d, 0xe8, 0x01, 0x99, 0x5e, 0x08, 0x06, 0xdf, 0xbc, 0xaf, 0xc2, + 0x80, 0x97, 0xab, 0x21, 0x17, 0x55, 0x56, 0xdd, 0x0d, 0x31, 0x4f, 0x80, 0x9f, 0x1a, 0xde, 0xec, 0x79, 0x61, 0x88, + 0xcd, 0x45, 0xc1, 0xf9, 0x27, 0x1e, 0x2a, 0xe3, 0xe8, 0x31, 0x1a, 0x47, 0x8f, 0xa9, 0x1a, 0x8c, 0xc9, 0x37, 0x54, + 0x77, 0x66, 0xf2, 0x0d, 0x98, 0x20, 0x65, 0xed, 0x6f, 0x94, 0x71, 0x62, 0x34, 0xa6, 0xd7, 0xaf, 0xf2, 0x6c, 0x05, + 0x4c, 0xf0, 0x52, 0xff, 0xa8, 0x09, 0x7d, 0xcf, 0xdb, 0xd9, 0x47, 0xa3, 0xd1, 0xf3, 0x82, 0x8e, 0x46, 0xa3, 0x8f, + 0x59, 0x4d, 0xe8, 0x4a, 0x74, 0xbc, 0x7f, 0xcf, 0xe9, 0xb9, 0x4c, 0xef, 0xa2, 0x20, 0xa0, 0xcb, 0x2c, 0x4d, 0xb9, + 0x50, 0x65, 0x9d, 0xa6, 0xed, 0xbc, 0xaa, 0x85, 0x08, 0xfc, 0xa3, 0xdb, 0x88, 0x10, 0x44, 0x84, 0x9e, 0xec, 0xf4, + 0x6c, 0x34, 0x1a, 0x9d, 0xa6, 0xa6, 0x5a, 0xc7, 0x90, 0xbf, 0x41, 0xf3, 0x01, 0x67, 0x97, 0x0f, 0xd6, 0x37, 0x26, + 0xda, 0xc9, 0xfe, 0x7f, 0x0f, 0x67, 0xf3, 0xf1, 0xf0, 0xdb, 0xd1, 0xe2, 0xf1, 0x3e, 0x0d, 0x02, 0x1f, 0xb4, 0x3a, + 0xd4, 0xd6, 0x1c, 0xd3, 0xf2, 0x70, 0x3c, 0x25, 0xe5, 0x80, 0x3d, 0xb5, 0xbe, 0x34, 0x5f, 0x3d, 0x05, 0x24, 0x52, + 0x14, 0xa1, 0x06, 0x4e, 0xfa, 0x87, 0x57, 0x91, 0xd7, 0x02, 0xf0, 0xd1, 0x6c, 0x24, 0x03, 0xa3, 0x05, 0x1c, 0x47, + 0x50, 0x5e, 0x6d, 0x4d, 0x23, 0x7a, 0x8c, 0x65, 0x26, 0x2a, 0xe8, 0x78, 0x5a, 0xde, 0x64, 0x55, 0xb2, 0xc4, 0xc0, + 0x46, 0x71, 0xc9, 0x83, 0xaf, 0x82, 0xa8, 0x64, 0x07, 0xcf, 0xa6, 0x0a, 0xde, 0x17, 0x93, 0x52, 0x7e, 0x09, 0x89, + 0xdf, 0x8e, 0x11, 0x02, 0x95, 0x68, 0x8f, 0x45, 0xac, 0xf1, 0x55, 0x2e, 0x63, 0xf0, 0xe0, 0x2c, 0x35, 0xcf, 0x62, + 0x4f, 0x02, 0x6b, 0x7f, 0xd1, 0x6a, 0x8e, 0x84, 0xe6, 0x84, 0x92, 0xc9, 0xfd, 0x92, 0xca, 0xaf, 0x26, 0xe8, 0x15, + 0x04, 0x6e, 0xd5, 0x11, 0x1c, 0x77, 0xd6, 0xb2, 0x41, 0x2f, 0x9f, 0x94, 0xed, 0xcf, 0xff, 0x77, 0x49, 0x17, 0x83, + 0x7d, 0x37, 0x34, 0x27, 0xda, 0x7d, 0xb5, 0x42, 0x46, 0xa9, 0x0a, 0x9f, 0xa7, 0xc4, 0x1a, 0x9f, 0x72, 0x76, 0xb4, + 0x31, 0xdd, 0x19, 0x55, 0x45, 0x76, 0x15, 0x12, 0xdd, 0x2b, 0x07, 0x8a, 0x19, 0x44, 0xd9, 0x08, 0xd7, 0x0f, 0x58, + 0x8b, 0x78, 0x9d, 0xbc, 0xe6, 0x45, 0x95, 0x25, 0xea, 0xfd, 0x75, 0xe3, 0x3d, 0x50, 0x03, 0xd5, 0xa0, 0x77, 0x05, + 0x83, 0x79, 0x3e, 0x29, 0x00, 0xb4, 0xb3, 0xe4, 0xc5, 0x35, 0xf7, 0xe9, 0x46, 0x10, 0xd4, 0xae, 0x99, 0x97, 0x8d, + 0x60, 0x13, 0xf0, 0xd5, 0xbb, 0x02, 0x30, 0x37, 0x42, 0x90, 0x9a, 0x42, 0x28, 0x1c, 0xb8, 0xc0, 0x57, 0x55, 0x91, + 0x9d, 0xaf, 0x2b, 0x8e, 0xc1, 0x3e, 0xbc, 0xb8, 0x89, 0xca, 0x09, 0x8f, 0x87, 0x01, 0xfe, 0x08, 0xa8, 0x0a, 0xb8, + 0x61, 0x3c, 0xec, 0xe0, 0x85, 0xfa, 0xe5, 0xde, 0xa8, 0x3d, 0xc2, 0xde, 0xa4, 0x21, 0x04, 0xd7, 0xc1, 0x87, 0x00, + 0x96, 0x14, 0xa1, 0x27, 0x78, 0xaa, 0x86, 0xc1, 0x45, 0x9e, 0xad, 0x74, 0x52, 0x35, 0xea, 0x68, 0x3e, 0x94, 0xda, + 0x91, 0x1c, 0x50, 0x2f, 0x3d, 0xc6, 0xf4, 0x42, 0xa5, 0xab, 0xa2, 0x9c, 0x11, 0xca, 0x3b, 0x3d, 0x31, 0x2e, 0x4c, + 0x1f, 0x87, 0xc8, 0x2f, 0xef, 0x0a, 0x15, 0xfa, 0x85, 0x2f, 0x00, 0xfc, 0x0a, 0x6e, 0xf7, 0xbb, 0xf1, 0x5d, 0x54, + 0xf6, 0x33, 0xce, 0xf6, 0xff, 0x7b, 0x1e, 0x0f, 0x3f, 0x8d, 0x87, 0xdf, 0x2e, 0x06, 0xe1, 0xd0, 0xfe, 0x24, 0x8f, + 0x1f, 0xed, 0xd3, 0x57, 0xdc, 0x72, 0x25, 0xb0, 0xf0, 0x1b, 0xc1, 0x6d, 0xd4, 0x4a, 0x08, 0xa2, 0x00, 0x6f, 0x14, + 0x6e, 0x35, 0x4e, 0x00, 0xe0, 0x2f, 0xf8, 0xaf, 0x00, 0x8d, 0x84, 0xdc, 0x45, 0x03, 0xf4, 0x03, 0xea, 0xf7, 0xd1, + 0x93, 0x86, 0x81, 0x1c, 0x88, 0x27, 0x54, 0x0c, 0x14, 0xa2, 0xcb, 0x98, 0x28, 0xd8, 0x5f, 0x9b, 0x7d, 0xbb, 0xed, + 0xb5, 0x25, 0x3f, 0xf8, 0xa5, 0x9f, 0x69, 0x62, 0xe6, 0x1d, 0x6e, 0x28, 0x2b, 0xb9, 0x0a, 0x11, 0x1b, 0x4f, 0xff, + 0xca, 0x19, 0xc4, 0x9a, 0xbc, 0xce, 0xc0, 0x87, 0xc1, 0x7e, 0x31, 0x9e, 0x01, 0xdb, 0x00, 0x77, 0x9c, 0x82, 0x5f, + 0x64, 0xe0, 0xd6, 0x2c, 0x62, 0xbc, 0x60, 0xdb, 0x25, 0xd1, 0xef, 0xf7, 0xf2, 0x2c, 0xcc, 0x35, 0xce, 0x72, 0x5e, + 0x1b, 0xb1, 0x3b, 0xea, 0x84, 0x41, 0xdc, 0xae, 0x87, 0x60, 0xa8, 0x86, 0xa0, 0xe8, 0x68, 0x8b, 0xab, 0xd7, 0xd6, + 0x53, 0x98, 0xde, 0xaa, 0xfa, 0x8a, 0xd1, 0x9f, 0x32, 0x13, 0x58, 0x48, 0xbb, 0xe6, 0x58, 0xd7, 0x1c, 0x23, 0xed, + 0xe9, 0xf7, 0x45, 0x83, 0xfc, 0x74, 0x16, 0x1e, 0x04, 0xaa, 0x54, 0xb9, 0x53, 0x16, 0xe5, 0xb6, 0x34, 0x6f, 0x0c, + 0x6b, 0x9a, 0x67, 0x36, 0xae, 0xcb, 0xac, 0xd7, 0x0b, 0x43, 0x74, 0x68, 0xc4, 0x52, 0xb1, 0x36, 0x08, 0xef, 0x63, + 0x12, 0x46, 0x57, 0x20, 0xab, 0x0b, 0xcf, 0x38, 0x41, 0xbe, 0x0c, 0x4c, 0xd6, 0x54, 0xb5, 0x5e, 0x4e, 0x78, 0x6c, + 0xe4, 0xcb, 0x46, 0xd0, 0x20, 0x2f, 0x29, 0xea, 0x4d, 0xdc, 0x8e, 0x7d, 0xd4, 0x42, 0x6a, 0xdc, 0xd4, 0xd3, 0x9e, + 0x26, 0x15, 0x3d, 0xd6, 0xab, 0xd4, 0x2f, 0xb0, 0x2c, 0xb0, 0xe4, 0x83, 0xd0, 0x9e, 0xa6, 0x15, 0x98, 0xe1, 0xda, + 0x66, 0x30, 0xf4, 0xc3, 0xa1, 0x2d, 0x42, 0x67, 0xd4, 0xb6, 0x84, 0xb0, 0x6d, 0x83, 0xb0, 0xf2, 0x9e, 0xc8, 0x57, + 0x4f, 0x3d, 0x46, 0x38, 0xe4, 0x66, 0x33, 0x8b, 0x06, 0x86, 0xf9, 0x95, 0x6c, 0x36, 0x4f, 0x37, 0xd7, 0x8b, 0x8a, + 0x29, 0x60, 0xbb, 0xad, 0x04, 0xc1, 0xbf, 0x1f, 0xb3, 0x19, 0xfe, 0xcd, 0xfa, 0xfd, 0x5e, 0x88, 0xbf, 0x38, 0x06, + 0xef, 0x99, 0x8b, 0x05, 0xfb, 0x08, 0x32, 0x15, 0x12, 0x61, 0xaa, 0x32, 0x7e, 0x63, 0x15, 0x58, 0xc0, 0x99, 0x0f, + 0x54, 0x2e, 0xcc, 0x64, 0x2f, 0x2f, 0xae, 0x21, 0xc7, 0xad, 0x71, 0xca, 0x46, 0x59, 0xa2, 0x5c, 0x17, 0xb2, 0x51, + 0x9c, 0x67, 0x71, 0xc9, 0xcb, 0xed, 0x56, 0x1f, 0x8e, 0x49, 0xc1, 0x81, 0x3d, 0x55, 0x54, 0xaa, 0x64, 0x1d, 0xa9, + 0x6e, 0xfc, 0x65, 0x58, 0xe0, 0x3e, 0xe5, 0xf3, 0xc2, 0xd0, 0x88, 0x3d, 0xb8, 0xbc, 0x33, 0x75, 0x2b, 0xed, 0x85, + 0x05, 0x34, 0xaf, 0x24, 0x64, 0x83, 0xa9, 0x9e, 0x45, 0x6b, 0xcc, 0xc4, 0xbc, 0x58, 0x40, 0x18, 0x99, 0x62, 0x01, + 0x36, 0x53, 0x5c, 0x80, 0x17, 0x49, 0x0c, 0x30, 0x71, 0x31, 0x99, 0x42, 0x3c, 0x73, 0x55, 0x4e, 0xbc, 0x30, 0xf7, + 0xcb, 0xc4, 0x21, 0x65, 0xc0, 0xab, 0xda, 0xa0, 0x89, 0xd9, 0x86, 0xa3, 0x4e, 0x90, 0x13, 0x93, 0xdf, 0x4f, 0x15, + 0x84, 0xb8, 0x13, 0x47, 0xc2, 0x65, 0xc5, 0x76, 0xe1, 0x65, 0x07, 0x62, 0x8c, 0x1a, 0x9c, 0xf2, 0x33, 0x83, 0xa3, + 0x31, 0x38, 0x37, 0xde, 0x09, 0x52, 0x84, 0x31, 0xd9, 0x48, 0x76, 0x25, 0x43, 0x31, 0x8f, 0x17, 0xa0, 0xac, 0x8b, + 0x17, 0x60, 0x59, 0x63, 0x0c, 0x30, 0x41, 0x5e, 0xc5, 0xbd, 0xd0, 0x4f, 0x14, 0x57, 0x88, 0xf4, 0xac, 0x5c, 0x1f, + 0x15, 0xed, 0xd0, 0x17, 0x78, 0xbd, 0x57, 0xe6, 0xb8, 0x59, 0x8f, 0x05, 0x12, 0x1b, 0x02, 0xc6, 0x46, 0x3a, 0x4d, + 0xb5, 0xd6, 0xbd, 0x31, 0xf3, 0xc0, 0xa7, 0xd9, 0x48, 0xc8, 0xea, 0xec, 0x02, 0x44, 0x28, 0x3e, 0x1a, 0x3c, 0xf2, + 0x8b, 0xb8, 0xb3, 0xcc, 0x5b, 0xdb, 0xa2, 0x92, 0x1d, 0x6d, 0x00, 0xa4, 0x4f, 0x47, 0x8b, 0x52, 0x72, 0x8a, 0x92, + 0xd4, 0x6e, 0x53, 0xc0, 0x4a, 0xf2, 0x17, 0x30, 0x04, 0x1b, 0xdb, 0x13, 0x4e, 0xa7, 0x08, 0xf1, 0x89, 0xa6, 0x88, + 0xac, 0x18, 0x96, 0x14, 0xc7, 0xb6, 0x44, 0xd4, 0x4f, 0x5b, 0x96, 0x1d, 0x0c, 0x13, 0x15, 0xf7, 0x45, 0xea, 0x51, + 0xa2, 0x20, 0xa0, 0x7a, 0xc8, 0x41, 0x62, 0x6b, 0x1b, 0x08, 0x0f, 0xc8, 0x23, 0x7a, 0x63, 0xfd, 0x7d, 0xd6, 0x79, + 0x76, 0xa1, 0x39, 0x2a, 0xd7, 0xbb, 0xc2, 0x8c, 0x11, 0x9e, 0x64, 0x06, 0x26, 0xdf, 0x3b, 0xcf, 0x8c, 0x9a, 0xa2, + 0xe7, 0xe1, 0x93, 0x1d, 0x63, 0x44, 0xba, 0x7b, 0x06, 0xdd, 0x04, 0xaf, 0xea, 0xb0, 0xd1, 0xae, 0x14, 0x84, 0x84, + 0xa9, 0x45, 0x13, 0xb3, 0x9e, 0x35, 0xa0, 0xde, 0x6e, 0x7b, 0x7a, 0xae, 0xee, 0x9f, 0xbb, 0xed, 0xb6, 0x87, 0xdd, + 0x7a, 0x91, 0x76, 0x5b, 0x81, 0x57, 0xea, 0x83, 0xf6, 0xf8, 0x73, 0x37, 0xfe, 0xdc, 0x20, 0x79, 0x94, 0x8e, 0x66, + 0xda, 0xfa, 0x20, 0x1c, 0x6e, 0x7a, 0xd7, 0x68, 0xd2, 0xf7, 0x59, 0x28, 0xe9, 0x4a, 0x34, 0xaa, 0xab, 0x9d, 0x49, + 0xe5, 0x83, 0xeb, 0xff, 0xe1, 0x55, 0x80, 0x47, 0x9c, 0xda, 0xd9, 0xf7, 0x36, 0xa8, 0x68, 0xb4, 0x85, 0x23, 0x45, + 0xe8, 0x01, 0x49, 0xb8, 0xaf, 0x65, 0x2d, 0x6e, 0xf3, 0x34, 0x7b, 0x98, 0x3e, 0xbd, 0x4e, 0x7d, 0xab, 0x7b, 0xb7, + 0xcc, 0x32, 0x73, 0xe0, 0x55, 0x14, 0x07, 0x34, 0xea, 0xa2, 0x7d, 0x57, 0x59, 0x59, 0x82, 0x97, 0x07, 0x5c, 0x9f, + 0x4f, 0xb9, 0x0f, 0x37, 0x77, 0x59, 0x35, 0x37, 0xe9, 0x69, 0x36, 0xcf, 0x16, 0xdb, 0x6d, 0x88, 0x7f, 0xbb, 0x5a, + 0xe4, 0x68, 0xf2, 0x1c, 0x74, 0x78, 0x18, 0xb9, 0x87, 0xe9, 0xc6, 0x79, 0x9b, 0xff, 0x93, 0x68, 0x38, 0x09, 0x1c, + 0x03, 0xbd, 0x98, 0x3d, 0x02, 0x19, 0x8c, 0x71, 0xea, 0x17, 0x33, 0xbd, 0x66, 0x20, 0xfa, 0x96, 0x88, 0x00, 0x47, + 0x17, 0x1b, 0x89, 0x46, 0x16, 0x9c, 0xd4, 0x04, 0x2c, 0x36, 0x6d, 0x79, 0x1f, 0x2c, 0x6d, 0xab, 0x8a, 0x3b, 0x6f, + 0x49, 0x73, 0x5c, 0x07, 0xce, 0xb6, 0xdf, 0x0c, 0xb1, 0x29, 0xbb, 0x5a, 0x20, 0xf7, 0xcb, 0x6b, 0xda, 0x1b, 0xd7, + 0x09, 0xcc, 0xda, 0xa6, 0xb6, 0x8c, 0x9f, 0x2d, 0xfd, 0x27, 0x3d, 0xb8, 0xca, 0xf8, 0x69, 0x6e, 0xac, 0x12, 0xec, + 0xbe, 0xf1, 0x7c, 0x07, 0x20, 0x1c, 0x9b, 0x4f, 0x8f, 0x4f, 0x33, 0x8f, 0x1e, 0x03, 0xd1, 0x31, 0x1f, 0x95, 0xee, + 0x23, 0xbb, 0x7b, 0xfd, 0x00, 0x78, 0xf3, 0xaa, 0x5d, 0xd0, 0xbc, 0x5c, 0x40, 0x20, 0x51, 0xaf, 0xbc, 0xc2, 0xf2, + 0x99, 0x31, 0xbb, 0x04, 0x32, 0x54, 0x10, 0x08, 0x54, 0xdd, 0x75, 0x2e, 0xc4, 0xaa, 0xc3, 0xca, 0x7c, 0x24, 0x61, + 0x47, 0x21, 0x9a, 0x73, 0x06, 0xb3, 0xe0, 0xbf, 0x82, 0x41, 0x39, 0x08, 0xa2, 0x20, 0x0a, 0x02, 0x32, 0x28, 0xe0, + 0x17, 0xe2, 0x8c, 0x11, 0x8c, 0x51, 0x02, 0x1d, 0x7e, 0xc7, 0x99, 0xcf, 0x88, 0xbc, 0x6c, 0x84, 0xb1, 0x74, 0x03, + 0x70, 0x2e, 0x65, 0xce, 0x63, 0xf4, 0xb1, 0x78, 0xc7, 0x59, 0x46, 0xe8, 0x3b, 0xef, 0x54, 0x7e, 0xc4, 0x1b, 0xc1, + 0xed, 0x76, 0x87, 0xed, 0x15, 0x0f, 0x33, 0xda, 0x1b, 0xd3, 0x77, 0x9c, 0x44, 0x59, 0xc3, 0x79, 0x98, 0x43, 0xcf, + 0x2a, 0xcb, 0x5a, 0x51, 0x43, 0x6e, 0x50, 0xac, 0x8b, 0x2c, 0x93, 0x93, 0xe1, 0xaa, 0x39, 0x15, 0xb8, 0xee, 0xec, + 0x7a, 0x01, 0x49, 0x99, 0xd0, 0x2c, 0x9d, 0x0d, 0x5f, 0x6d, 0x5b, 0xf6, 0xa2, 0x75, 0x0a, 0x79, 0x0d, 0x51, 0xd1, + 0x0f, 0x1d, 0x01, 0x35, 0xb4, 0xe2, 0xb2, 0x02, 0x97, 0x5d, 0xd3, 0x1e, 0x6e, 0xda, 0x63, 0x9a, 0xf1, 0x01, 0x62, + 0xc4, 0x71, 0x6c, 0x19, 0xd8, 0x4d, 0x38, 0x3c, 0x1b, 0xe7, 0xfb, 0xb2, 0x4b, 0x6f, 0x5d, 0x2d, 0x1e, 0x61, 0xed, + 0x79, 0x2b, 0x24, 0x04, 0x48, 0x4b, 0x53, 0xe9, 0x76, 0x1b, 0x04, 0x30, 0xc0, 0xfd, 0x7e, 0x0f, 0xb8, 0x56, 0xc3, + 0x4e, 0x9a, 0x5b, 0xb3, 0x25, 0xf6, 0x8a, 0xc2, 0x63, 0x20, 0x4a, 0xcd, 0x7f, 0x06, 0x01, 0xc5, 0x73, 0x37, 0x04, + 0xfb, 0x4a, 0x76, 0xb4, 0x29, 0xfa, 0xfd, 0x17, 0x05, 0x3e, 0xa0, 0x1c, 0x14, 0xc4, 0xba, 0x3a, 0x6e, 0x85, 0x61, + 0x9f, 0xd4, 0x87, 0x38, 0x16, 0x79, 0x16, 0x3a, 0xc2, 0x52, 0x19, 0xc2, 0xc2, 0x15, 0x23, 0x1d, 0xc4, 0x41, 0x4d, + 0x3a, 0x07, 0xab, 0x72, 0xc1, 0x86, 0x7b, 0xbd, 0x4f, 0x00, 0x0b, 0x9e, 0x79, 0xc3, 0xf2, 0xde, 0x03, 0x00, 0xeb, + 0xf5, 0x70, 0xa1, 0xb8, 0x97, 0xaf, 0x1a, 0xe8, 0x93, 0xf8, 0xd2, 0xb2, 0xeb, 0x33, 0x2d, 0x2b, 0x19, 0x8d, 0x46, + 0x55, 0xad, 0x24, 0x1f, 0x8e, 0xbc, 0xb4, 0x50, 0x2b, 0x65, 0x9c, 0xf2, 0x14, 0x2c, 0xbd, 0x0d, 0xa5, 0x9b, 0x2f, + 0xe8, 0x8a, 0x8b, 0x54, 0xfd, 0xf4, 0xd0, 0x26, 0x1b, 0xc4, 0x35, 0x6b, 0xea, 0x2c, 0xec, 0xf0, 0x43, 0xc0, 0x47, + 0xfb, 0x30, 0x73, 0xe9, 0x1a, 0x96, 0x16, 0xc4, 0x91, 0x71, 0xc1, 0x43, 0x97, 0x07, 0xb0, 0xfe, 0xcc, 0x21, 0x89, + 0x9f, 0xc2, 0xcf, 0x99, 0x49, 0xeb, 0xf8, 0x0c, 0x67, 0x33, 0x2a, 0xd5, 0x8d, 0xa0, 0xfd, 0x1a, 0x12, 0x89, 0x41, + 0x36, 0x6e, 0x30, 0x14, 0xad, 0xbb, 0x0d, 0x5c, 0xf9, 0x2d, 0xbd, 0xf3, 0x69, 0x10, 0x60, 0x5b, 0x63, 0x31, 0x00, + 0x18, 0x8a, 0x3f, 0x50, 0x55, 0x63, 0xae, 0x28, 0xa6, 0x61, 0x2a, 0xd1, 0xde, 0x71, 0x5c, 0x47, 0x8d, 0xab, 0xac, + 0x60, 0xa5, 0xb5, 0xe5, 0x75, 0x6f, 0x69, 0x61, 0x4b, 0x40, 0x35, 0x18, 0xee, 0x04, 0xf0, 0x19, 0x91, 0xea, 0x40, + 0x90, 0xdd, 0x07, 0x07, 0x00, 0x9a, 0xe1, 0x79, 0x18, 0xc2, 0x1f, 0x58, 0x38, 0xb0, 0x2c, 0x55, 0x3f, 0x97, 0xd3, + 0x18, 0xce, 0xdd, 0x5c, 0xed, 0xf0, 0xd9, 0x12, 0x14, 0x79, 0x6a, 0x4e, 0xcd, 0xe5, 0x2b, 0x6f, 0xec, 0xf7, 0x98, + 0x60, 0x1e, 0x33, 0xdb, 0xf0, 0x5b, 0x4f, 0xb7, 0xf5, 0x85, 0x75, 0x03, 0x27, 0xed, 0x85, 0xd3, 0x5e, 0x6c, 0x97, + 0x06, 0xe2, 0xae, 0x6e, 0x08, 0x11, 0x5e, 0x6b, 0x62, 0x91, 0x35, 0x64, 0x3a, 0x16, 0x1b, 0x43, 0xb5, 0xa9, 0x78, + 0xae, 0x15, 0xe2, 0xe5, 0x54, 0x5d, 0x98, 0x5a, 0xa9, 0x4c, 0x18, 0x84, 0x99, 0x12, 0x16, 0x55, 0x06, 0x3e, 0xfb, + 0x15, 0x52, 0x5c, 0x5b, 0xcf, 0x5b, 0x5c, 0xbe, 0x99, 0x69, 0xb3, 0xfd, 0xf4, 0x55, 0x1e, 0x5f, 0x6e, 0xb7, 0x61, + 0xf7, 0x0b, 0x30, 0xbf, 0x2c, 0x95, 0x46, 0x0d, 0x9c, 0x1e, 0x42, 0xf4, 0x73, 0xbe, 0x27, 0xe7, 0xc4, 0x71, 0x72, + 0xed, 0xe6, 0xcd, 0x76, 0x52, 0x8c, 0xc0, 0x02, 0x4e, 0x5c, 0xa4, 0x03, 0x2d, 0x15, 0x9c, 0xb6, 0x8c, 0xf7, 0x36, + 0xbd, 0xa3, 0x54, 0x78, 0xb5, 0xd0, 0x24, 0xa4, 0x72, 0xf7, 0x12, 0x3b, 0x6a, 0xc0, 0x39, 0xa9, 0x3b, 0x08, 0x38, + 0xa9, 0xe9, 0xc6, 0x5a, 0xc5, 0xa9, 0x49, 0xf0, 0x5e, 0xe9, 0xa1, 0x4b, 0xb4, 0x13, 0xb7, 0xdb, 0x56, 0x65, 0x0b, + 0xf5, 0x71, 0x2f, 0x67, 0x89, 0x3a, 0x1e, 0x50, 0xe8, 0xa2, 0x8e, 0x86, 0x7c, 0x41, 0x0a, 0xbd, 0x72, 0xb4, 0x6a, + 0x75, 0x57, 0x32, 0x50, 0xaa, 0x55, 0x90, 0xd7, 0xc4, 0xba, 0x6b, 0x65, 0x8d, 0xc5, 0x95, 0x13, 0x52, 0xd8, 0x84, + 0x2f, 0x2d, 0xc5, 0xc2, 0x0a, 0xf6, 0xc6, 0xd4, 0x17, 0x2e, 0x11, 0xda, 0xee, 0x36, 0xc4, 0x24, 0x83, 0x75, 0xb3, + 0xdd, 0xbe, 0x2e, 0xc2, 0x79, 0xb6, 0xa0, 0x72, 0x94, 0xa5, 0x08, 0x21, 0x66, 0x3c, 0x74, 0x6d, 0x17, 0xcc, 0xc4, + 0x50, 0xd7, 0x1e, 0x2f, 0xc9, 0x14, 0x6b, 0x93, 0xe4, 0x28, 0x3e, 0x97, 0x85, 0x5a, 0x6b, 0x84, 0xe0, 0xe1, 0xfe, + 0x67, 0x0a, 0x31, 0xdc, 0xcc, 0xba, 0xfb, 0x75, 0xe7, 0x86, 0xf8, 0x27, 0x04, 0x12, 0x28, 0xd9, 0xeb, 0x62, 0x74, + 0x9e, 0x89, 0x14, 0x77, 0xaa, 0x8a, 0x8a, 0xab, 0xd6, 0x41, 0xb3, 0xe5, 0xf6, 0x5e, 0x6c, 0x89, 0x02, 0xc4, 0x35, + 0x16, 0x9a, 0xf1, 0xac, 0x9c, 0xa5, 0x48, 0x46, 0xb1, 0x21, 0x51, 0xe9, 0x45, 0x45, 0xf7, 0x79, 0x1a, 0xd3, 0x43, + 0xb7, 0x06, 0xc1, 0x55, 0x73, 0x67, 0x23, 0xcd, 0x17, 0x84, 0xa8, 0x09, 0x90, 0xb0, 0x51, 0xcd, 0xa9, 0x75, 0x29, + 0x1e, 0x66, 0x95, 0xcf, 0xf4, 0x41, 0x7c, 0x29, 0x80, 0x87, 0xf5, 0xb6, 0xf7, 0x95, 0xf0, 0x58, 0x1b, 0x7c, 0xbb, + 0xdd, 0x5e, 0x8a, 0x79, 0x10, 0x78, 0x8c, 0xe6, 0x77, 0x4a, 0x62, 0xde, 0x1b, 0x53, 0x58, 0xf1, 0xbe, 0x4b, 0x5b, + 0x37, 0xa9, 0xb5, 0x16, 0xa8, 0x3b, 0x5c, 0x1f, 0xf0, 0x3c, 0x25, 0x8e, 0x76, 0x54, 0x4e, 0xa5, 0xd5, 0x95, 0x63, + 0x57, 0x04, 0x06, 0x86, 0xfe, 0x21, 0x65, 0x1b, 0x30, 0xc7, 0x03, 0x6b, 0x1b, 0xf4, 0x53, 0x52, 0x5a, 0x98, 0x31, + 0x1a, 0xb3, 0xc8, 0x75, 0x15, 0x1d, 0x70, 0x1d, 0xbd, 0x9d, 0x47, 0x7f, 0x7b, 0x36, 0xa6, 0x45, 0x2c, 0x52, 0x79, + 0x05, 0x2a, 0x08, 0x50, 0x86, 0xa0, 0xe1, 0xbf, 0xa6, 0x06, 0xa0, 0x41, 0x70, 0x03, 0xf0, 0xcf, 0x4e, 0xa7, 0x41, + 0x5b, 0x93, 0x8f, 0x49, 0xaa, 0x8a, 0x9c, 0xb5, 0xa1, 0xcc, 0x54, 0x72, 0x48, 0x1e, 0x97, 0x80, 0xe7, 0x88, 0xcd, + 0x52, 0x36, 0x17, 0x6a, 0xb3, 0xa9, 0xd7, 0x8a, 0x1d, 0xb9, 0x6d, 0x14, 0x6d, 0xd6, 0xa2, 0xb6, 0x93, 0x98, 0x2f, + 0xa6, 0xb7, 0x56, 0x18, 0x38, 0x35, 0xad, 0xb9, 0xd9, 0x81, 0x4e, 0xb3, 0xf5, 0x99, 0xdc, 0x04, 0x88, 0x03, 0x0c, + 0xd7, 0xed, 0xfc, 0x66, 0x41, 0xe8, 0x2d, 0xbb, 0xb5, 0x62, 0xd5, 0x1b, 0x2b, 0x17, 0x31, 0x69, 0x37, 0x83, 0x09, + 0x5c, 0xc6, 0x59, 0x61, 0x5f, 0x68, 0x75, 0x43, 0xd1, 0xd1, 0x36, 0x69, 0x3f, 0xef, 0x68, 0x37, 0x5c, 0xf0, 0xad, + 0x58, 0xc7, 0xb9, 0x21, 0x4d, 0x15, 0x7a, 0x74, 0xa0, 0xb7, 0x43, 0x40, 0x73, 0x36, 0xa6, 0x4b, 0x9a, 0xe2, 0x05, + 0x9a, 0xae, 0xc1, 0x2c, 0xe5, 0x02, 0xfa, 0xda, 0xed, 0x93, 0x7c, 0xa1, 0x7a, 0x22, 0xbc, 0x25, 0x0a, 0xbe, 0x1c, + 0x29, 0x78, 0x65, 0xe5, 0x3c, 0x36, 0x73, 0x08, 0x78, 0x2c, 0xaa, 0x44, 0xef, 0xa4, 0xb8, 0x04, 0x65, 0x2a, 0x1c, + 0x81, 0xa6, 0x6a, 0xc4, 0x12, 0x0e, 0x70, 0x7b, 0xf1, 0x34, 0x20, 0x14, 0xa4, 0xba, 0x6b, 0xbb, 0x22, 0x6f, 0xd9, + 0xd1, 0xe6, 0x16, 0xcc, 0x62, 0xab, 0x75, 0xd9, 0xfa, 0xca, 0x26, 0xbb, 0x8f, 0x6b, 0x82, 0x6d, 0xf7, 0x36, 0x48, + 0x78, 0x4b, 0x6f, 0xc8, 0xe6, 0xa6, 0xdf, 0x0f, 0xa1, 0x3f, 0x84, 0xea, 0x0e, 0xdd, 0x76, 0x76, 0xe8, 0xd6, 0x67, + 0x7e, 0xad, 0x9e, 0x4f, 0x79, 0x43, 0x7c, 0x40, 0x13, 0x2d, 0xba, 0x8a, 0xef, 0x60, 0x53, 0x47, 0x15, 0x55, 0x95, + 0x47, 0x09, 0x05, 0x15, 0x70, 0xc6, 0xcb, 0x53, 0x8e, 0xb1, 0x4d, 0xf5, 0xd3, 0x3b, 0xcd, 0xab, 0xad, 0xcd, 0xda, + 0x2c, 0xd7, 0xe7, 0x60, 0x11, 0x70, 0xce, 0xa3, 0x2b, 0x4d, 0x4b, 0x2e, 0x3d, 0xa6, 0xfe, 0x0c, 0x47, 0x25, 0xb8, + 0x88, 0xb3, 0x9c, 0xa7, 0x01, 0xbd, 0x68, 0xf6, 0x3f, 0xd4, 0xb6, 0x52, 0xcb, 0xc6, 0x99, 0x7b, 0x1d, 0x92, 0xcd, + 0xff, 0xd8, 0x40, 0xbd, 0x09, 0x31, 0x22, 0xaa, 0x59, 0xd0, 0x27, 0x0c, 0x62, 0x63, 0x06, 0xe5, 0x3a, 0x49, 0x78, + 0x59, 0x06, 0x46, 0xa9, 0xb5, 0x66, 0x6b, 0x73, 0x9e, 0x3d, 0x62, 0x47, 0x8f, 0x7a, 0x8c, 0xdd, 0x12, 0x9a, 0x68, + 0x9d, 0x90, 0xa9, 0x31, 0xf2, 0xb4, 0x40, 0xba, 0x43, 0x51, 0x76, 0x11, 0x9e, 0xa0, 0x90, 0xa5, 0xbd, 0xcf, 0xcd, + 0x89, 0xac, 0xbe, 0xd1, 0x46, 0x17, 0x91, 0x4a, 0x04, 0xd9, 0xf8, 0x0d, 0x02, 0xf6, 0x42, 0xb3, 0x03, 0xb2, 0x59, + 0xb2, 0x53, 0x7a, 0x66, 0x4d, 0x60, 0xe0, 0xf5, 0x89, 0x4a, 0x34, 0xa3, 0xac, 0x88, 0xae, 0x32, 0x72, 0xb9, 0x0b, + 0x49, 0x74, 0x16, 0x12, 0x3f, 0x37, 0x2c, 0xad, 0xeb, 0x10, 0xc5, 0xcc, 0x66, 0xc3, 0xab, 0xee, 0x3e, 0x6a, 0x6c, + 0x2b, 0xe3, 0x53, 0x7d, 0x6b, 0xd3, 0xc8, 0x14, 0xfa, 0x3a, 0x9c, 0xf4, 0xfb, 0xf0, 0x57, 0xd3, 0x0f, 0xbc, 0xa5, + 0xe0, 0x2f, 0xf6, 0x88, 0xd4, 0x09, 0x0b, 0x00, 0x8e, 0x30, 0xe7, 0x55, 0x73, 0x02, 0x1f, 0xb1, 0xa3, 0xcd, 0xa3, + 0xf0, 0xb4, 0x31, 0x73, 0x77, 0x21, 0x5e, 0xaa, 0x92, 0x9e, 0x37, 0x4f, 0x66, 0x20, 0x56, 0xa1, 0xd9, 0xaf, 0xb7, + 0xcc, 0xea, 0x13, 0x80, 0x48, 0xdd, 0x5a, 0x87, 0x52, 0xfc, 0xd8, 0x74, 0x99, 0x6c, 0x52, 0xd6, 0x66, 0xa2, 0x94, + 0x8a, 0xa4, 0xb9, 0x08, 0xa0, 0xdf, 0x30, 0x1c, 0x35, 0xc0, 0x7b, 0xeb, 0xb1, 0x37, 0x43, 0xe3, 0x8d, 0xa9, 0xa1, + 0x67, 0x1b, 0xbd, 0xbc, 0x1d, 0x85, 0x30, 0x63, 0x11, 0xdd, 0xba, 0x63, 0x31, 0x3c, 0xa5, 0x27, 0x50, 0xe1, 0x9b, + 0x10, 0xa3, 0xe9, 0x92, 0xba, 0x9e, 0xae, 0xd5, 0x56, 0xba, 0x21, 0x34, 0xc7, 0x28, 0x3e, 0x5e, 0xdb, 0xee, 0xa8, + 0x11, 0xda, 0x13, 0xca, 0xc3, 0x5b, 0x5a, 0xd1, 0x1b, 0xcb, 0x22, 0x38, 0xf9, 0xb1, 0x97, 0x9f, 0xd0, 0x73, 0x4f, + 0x60, 0x52, 0xb4, 0x35, 0x80, 0x3f, 0xa0, 0x7e, 0x38, 0xab, 0xa7, 0x56, 0xca, 0xe1, 0x29, 0x7c, 0xc9, 0x06, 0xe4, + 0x0a, 0x7a, 0xb1, 0xc6, 0xec, 0x28, 0x06, 0x1d, 0xd4, 0xce, 0xee, 0xf0, 0x26, 0xa5, 0x0c, 0xd1, 0xfa, 0xce, 0x41, + 0x3c, 0xfd, 0x13, 0x34, 0x7d, 0x90, 0x16, 0xa6, 0x74, 0x8d, 0x02, 0x1e, 0xd0, 0x37, 0xf5, 0xfb, 0x39, 0x3e, 0xd7, + 0x9e, 0x25, 0x16, 0xf6, 0x78, 0x49, 0xe8, 0xd2, 0x8b, 0x1b, 0x05, 0xd2, 0x66, 0xc7, 0x2a, 0x00, 0x2b, 0x92, 0x40, + 0x23, 0x12, 0xb0, 0xd4, 0xf1, 0xc4, 0x65, 0x1b, 0x34, 0x20, 0x89, 0x4a, 0x0a, 0x59, 0x22, 0x09, 0xfc, 0x30, 0x82, + 0x10, 0x45, 0x31, 0x88, 0x7b, 0xf5, 0xf2, 0x8a, 0x6b, 0x6a, 0xc0, 0x89, 0x22, 0x98, 0x60, 0x9d, 0x4e, 0x81, 0xd8, + 0x8a, 0xf5, 0x0a, 0x3c, 0x2f, 0x1d, 0x27, 0x8e, 0x2c, 0x01, 0x1a, 0xa4, 0xf9, 0xd2, 0x69, 0xb7, 0xbc, 0x3d, 0xd1, + 0x52, 0xc5, 0xe6, 0xde, 0x8b, 0x85, 0xe5, 0x1e, 0x2b, 0x7f, 0x3b, 0xd0, 0x5e, 0x58, 0xed, 0x88, 0xa8, 0xc1, 0xca, + 0xae, 0x6d, 0xd7, 0x86, 0xd2, 0x50, 0xdd, 0x2b, 0xc7, 0x04, 0x54, 0x74, 0x15, 0x57, 0xcb, 0x28, 0x1b, 0xc1, 0x9f, + 0xed, 0x36, 0xd8, 0x0f, 0xc0, 0x02, 0xf2, 0x97, 0xf7, 0x3f, 0x45, 0x18, 0x9e, 0xe9, 0x97, 0xf7, 0x3f, 0x6d, 0xb7, + 0xcf, 0xc6, 0x63, 0xc3, 0x15, 0x38, 0xb5, 0x0e, 0xf0, 0x07, 0x86, 0x6d, 0xb0, 0x4b, 0x76, 0xbb, 0x7d, 0x06, 0x1c, + 0x84, 0x62, 0x1b, 0xcc, 0x2e, 0x56, 0x8e, 0x5c, 0x8a, 0xd5, 0xd0, 0x3b, 0x12, 0xb0, 0xea, 0x76, 0x58, 0x8a, 0x5d, + 0xea, 0xa3, 0x42, 0x30, 0xea, 0x45, 0xff, 0xb2, 0x53, 0x60, 0x49, 0xc1, 0x74, 0x35, 0x58, 0x56, 0xd5, 0xaa, 0x8c, + 0xf6, 0xf7, 0xe3, 0x55, 0x36, 0x2a, 0x33, 0xd8, 0xe6, 0xe5, 0xf5, 0x25, 0x00, 0x2a, 0x04, 0xb4, 0xf1, 0x6e, 0x2d, + 0x32, 0xf3, 0x62, 0x41, 0x97, 0x19, 0xae, 0x49, 0x30, 0x3b, 0xc8, 0xb9, 0xd5, 0x4d, 0x4e, 0x89, 0x7d, 0x00, 0x9b, + 0xc3, 0xed, 0xb6, 0xc1, 0x2f, 0x1c, 0x8d, 0x9e, 0xcd, 0x96, 0x99, 0x36, 0xe8, 0xe4, 0x66, 0xff, 0x93, 0xc8, 0x4b, + 0x43, 0xc5, 0x27, 0x99, 0xbe, 0xcc, 0x80, 0xcf, 0x63, 0x6f, 0x45, 0xe8, 0xb3, 0x5c, 0x8d, 0xd6, 0x00, 0x1b, 0x9b, + 0x5d, 0xdc, 0x8d, 0x52, 0x0e, 0x11, 0x29, 0x02, 0xab, 0xae, 0x59, 0x66, 0xc4, 0xb7, 0xa9, 0xb8, 0x6b, 0xa9, 0xc2, + 0xde, 0x0a, 0xcf, 0x59, 0x85, 0x1b, 0x47, 0x99, 0xde, 0x24, 0x0a, 0x5f, 0xa2, 0x10, 0x95, 0xa3, 0x31, 0x9d, 0x13, + 0x48, 0x65, 0x1e, 0x13, 0x8a, 0x39, 0xdc, 0xbb, 0x5f, 0x52, 0x67, 0x2e, 0xe3, 0x0b, 0xf7, 0x5e, 0xfa, 0x32, 0x93, + 0x5b, 0x09, 0xa0, 0x48, 0xaa, 0xf6, 0x9f, 0x3f, 0x23, 0x35, 0xfe, 0x57, 0xaa, 0x35, 0x00, 0xbd, 0x9f, 0xa1, 0x26, + 0x47, 0x10, 0xb0, 0x15, 0x53, 0x1f, 0x4d, 0xdf, 0x4a, 0xe6, 0x3f, 0xa0, 0x6e, 0x47, 0xb0, 0x8d, 0x8a, 0x9f, 0x13, + 0x55, 0xb4, 0xe0, 0xe9, 0x5a, 0xa4, 0xb1, 0x48, 0xee, 0x22, 0x5e, 0x4f, 0xb1, 0x24, 0x66, 0x23, 0x64, 0xfd, 0xdc, + 0xec, 0xc2, 0x4f, 0x45, 0xc3, 0x04, 0x9c, 0x96, 0xfe, 0xb6, 0xf2, 0x36, 0x93, 0x65, 0x9c, 0x91, 0x29, 0x57, 0x88, + 0xdd, 0x56, 0xdf, 0x63, 0x4e, 0xf0, 0xa7, 0x07, 0x4f, 0x09, 0xbd, 0x95, 0xd3, 0x12, 0x41, 0xe9, 0x44, 0x6a, 0x5d, + 0x35, 0xb1, 0x5f, 0x53, 0x88, 0xe2, 0x20, 0x18, 0x84, 0xee, 0x34, 0xed, 0x53, 0x7c, 0x9f, 0x2d, 0xfb, 0xad, 0x29, + 0x5b, 0x92, 0x8d, 0x80, 0x8e, 0x49, 0xe7, 0xed, 0xe9, 0xed, 0xd9, 0x99, 0xf7, 0x1b, 0x34, 0xe1, 0xa0, 0xba, 0x81, + 0x76, 0x15, 0x64, 0x1a, 0xa3, 0xd8, 0x2c, 0xc6, 0xda, 0xad, 0x89, 0x08, 0x82, 0x4e, 0x97, 0xb3, 0xb0, 0xdd, 0x4e, + 0x88, 0x2f, 0x81, 0x04, 0x0a, 0x5c, 0xb9, 0x28, 0x27, 0x21, 0x51, 0x17, 0x32, 0x3d, 0x59, 0xd7, 0x92, 0x05, 0x7a, + 0x8d, 0x1d, 0x04, 0xf4, 0x98, 0xdb, 0xa7, 0x80, 0xbe, 0x2f, 0xd8, 0x31, 0x1f, 0x04, 0x43, 0x8c, 0xaf, 0x1a, 0xd0, + 0x1b, 0xa9, 0x1e, 0xc1, 0x43, 0x18, 0x58, 0x2e, 0xfa, 0xaa, 0x60, 0x08, 0x2b, 0xf4, 0x57, 0xca, 0x26, 0xdf, 0xfc, + 0xdd, 0xcd, 0xef, 0xb9, 0x16, 0xb3, 0x83, 0x50, 0xdc, 0x5e, 0x4f, 0x80, 0xf8, 0x55, 0xfc, 0x0a, 0xac, 0xab, 0xb5, + 0xc4, 0xdb, 0x4d, 0xcf, 0x9f, 0xc2, 0x97, 0xa3, 0xdb, 0x4f, 0x4a, 0xf3, 0x09, 0x04, 0xa9, 0x71, 0x92, 0x72, 0xf7, + 0xdd, 0x47, 0xe9, 0x2a, 0x82, 0xd1, 0x02, 0xc4, 0xba, 0x7b, 0x2b, 0x39, 0x6b, 0x0a, 0xff, 0xb1, 0xce, 0xf7, 0x18, + 0x3b, 0x44, 0x9e, 0xe2, 0xf4, 0x37, 0xc0, 0xb0, 0xef, 0xfc, 0x5b, 0x99, 0x35, 0x24, 0x3a, 0x57, 0x1f, 0x01, 0xfd, + 0x1f, 0xeb, 0xf1, 0x3b, 0x46, 0x49, 0x5f, 0x12, 0xe7, 0x08, 0x57, 0xc4, 0x4b, 0x34, 0xd5, 0xeb, 0x8d, 0x6b, 0xfa, + 0xa9, 0x30, 0x2f, 0xb4, 0x82, 0xc3, 0xbe, 0x35, 0x0a, 0x0f, 0x3c, 0xf3, 0x7e, 0x15, 0x0d, 0x41, 0xf7, 0x6f, 0xb8, + 0x37, 0x7e, 0x15, 0x2c, 0xc3, 0x9b, 0x72, 0x96, 0x99, 0x3b, 0xdc, 0x4d, 0x26, 0x52, 0x79, 0xc3, 0x58, 0xb0, 0x16, + 0xca, 0x7c, 0x35, 0x0d, 0x66, 0x9b, 0x3a, 0x52, 0xc9, 0xee, 0xfb, 0xb7, 0x8d, 0x13, 0x36, 0x1b, 0x04, 0xa7, 0x95, + 0x2c, 0xe2, 0x4b, 0x1e, 0x4c, 0xb5, 0x8a, 0x22, 0xcb, 0xfa, 0xfd, 0x0c, 0x90, 0x61, 0x9c, 0xf6, 0x0e, 0x9e, 0x2c, + 0x35, 0x33, 0x21, 0xae, 0xad, 0xce, 0x02, 0xde, 0x9a, 0xd1, 0x3c, 0xae, 0x60, 0x97, 0xf9, 0x4a, 0x8a, 0x3f, 0x5b, + 0x92, 0x6c, 0xac, 0xbf, 0x21, 0xc3, 0xb6, 0xf2, 0x99, 0x73, 0xc0, 0x98, 0xb9, 0x91, 0x2a, 0xc8, 0x5d, 0x0f, 0x18, + 0x21, 0x24, 0x02, 0xc2, 0x59, 0x4c, 0xdc, 0x09, 0x13, 0xfe, 0xd1, 0x05, 0xc6, 0x89, 0x31, 0x30, 0xce, 0x47, 0x19, + 0x72, 0x7a, 0xcc, 0x07, 0x49, 0x63, 0xb6, 0xfe, 0x54, 0x25, 0xd2, 0x6b, 0x49, 0xe8, 0x19, 0xfc, 0x1e, 0xb7, 0x78, + 0xa0, 0x46, 0x70, 0x4a, 0x77, 0x73, 0xda, 0x7f, 0x55, 0x90, 0xe1, 0x5f, 0xe0, 0xdd, 0x15, 0xdb, 0xcb, 0x72, 0x02, + 0x8b, 0x3b, 0xf6, 0x8a, 0xa7, 0xb9, 0x6a, 0x71, 0x42, 0x3c, 0x62, 0x91, 0xfb, 0xc4, 0x02, 0x46, 0xd4, 0x30, 0x1a, + 0x3f, 0x9e, 0x9e, 0xbc, 0xd5, 0x98, 0x4d, 0xb9, 0xff, 0x01, 0x8c, 0xa8, 0x96, 0xb6, 0xdb, 0x01, 0x5f, 0x8e, 0xd0, + 0x60, 0x3b, 0x75, 0x83, 0xdd, 0xef, 0x9b, 0xb4, 0xa3, 0xd2, 0xcb, 0xe6, 0xc4, 0xa0, 0x3b, 0x4a, 0x9b, 0xa5, 0x32, + 0xa8, 0xed, 0x2a, 0x1c, 0xcd, 0x67, 0x8d, 0x58, 0xd5, 0xfb, 0x30, 0x5c, 0xd2, 0xd8, 0xca, 0xca, 0xed, 0x6e, 0xc2, + 0x91, 0x4d, 0x80, 0xeb, 0x53, 0x50, 0x56, 0xcd, 0x39, 0x68, 0x41, 0x67, 0x02, 0x47, 0xb4, 0xdd, 0x86, 0x10, 0x81, + 0xa3, 0x18, 0x4e, 0x66, 0x61, 0x31, 0x1c, 0xaa, 0x81, 0x2f, 0x08, 0x89, 0x3e, 0x15, 0xf3, 0x6c, 0xa1, 0x10, 0x7b, + 0xfc, 0x9d, 0xf4, 0x6b, 0xa1, 0x38, 0xe5, 0xde, 0xaf, 0x82, 0x6c, 0x7e, 0x4b, 0x31, 0xe6, 0xa0, 0xd3, 0x6c, 0x66, + 0x20, 0x61, 0x3d, 0xae, 0x88, 0x5a, 0x47, 0x76, 0x36, 0x40, 0x15, 0x8b, 0xa6, 0xb0, 0xa0, 0x6e, 0xf1, 0xc4, 0x7a, + 0x46, 0xef, 0x41, 0x25, 0x88, 0x6a, 0xc1, 0x6e, 0x0c, 0xd7, 0xda, 0x27, 0x11, 0x4a, 0xca, 0x49, 0x93, 0x99, 0xb1, + 0xa2, 0xc1, 0x02, 0x84, 0xa4, 0x71, 0x59, 0xbd, 0x91, 0x69, 0x76, 0x91, 0x01, 0x62, 0x82, 0xf3, 0x9f, 0x93, 0x8d, + 0x37, 0xcf, 0xd5, 0xbc, 0x74, 0x25, 0xce, 0x2c, 0xcc, 0x47, 0xd7, 0x5b, 0x5a, 0x90, 0xa8, 0x00, 0x1a, 0xe5, 0x6b, + 0x79, 0xfe, 0xb1, 0x63, 0x15, 0xb2, 0xfb, 0xe1, 0x54, 0xd9, 0x0e, 0xf1, 0x23, 0x56, 0x11, 0xef, 0xb4, 0xae, 0x94, + 0x48, 0xa3, 0xa3, 0x6d, 0x40, 0x0c, 0x5b, 0xf6, 0x2d, 0x6a, 0xf8, 0x20, 0xcc, 0xa0, 0x93, 0xfc, 0xa0, 0x67, 0x74, + 0x6c, 0x0d, 0x24, 0x7d, 0x2d, 0x82, 0xaf, 0xd1, 0x91, 0x4e, 0x94, 0x69, 0x24, 0xa6, 0x90, 0xe8, 0xd7, 0x0b, 0xad, + 0xb1, 0x8c, 0xb2, 0xaf, 0xc8, 0xff, 0x5e, 0x77, 0xef, 0x57, 0xb1, 0xdd, 0xc2, 0x24, 0x7b, 0x1e, 0x57, 0xb0, 0xa9, + 0x51, 0x2b, 0x84, 0xb3, 0x73, 0x5c, 0xa1, 0x76, 0xac, 0x17, 0x96, 0x40, 0x1e, 0xc0, 0x56, 0xa4, 0x41, 0x19, 0x24, + 0xfb, 0x54, 0xcc, 0xc5, 0xc2, 0x89, 0x72, 0xa4, 0xc2, 0xfb, 0x92, 0xa3, 0x94, 0xc3, 0x55, 0x2c, 0x2c, 0x18, 0xf2, + 0xab, 0xa3, 0x8b, 0x42, 0x5e, 0x81, 0xa4, 0xc4, 0x30, 0x54, 0x96, 0xd7, 0xc5, 0x55, 0x5b, 0x12, 0xda, 0x3b, 0x03, + 0x10, 0x96, 0x02, 0x04, 0x2f, 0x8d, 0x1a, 0x62, 0xb6, 0x51, 0xbb, 0x2b, 0xba, 0x97, 0x1c, 0x50, 0xa7, 0xbb, 0x76, + 0xeb, 0x4d, 0xd9, 0x66, 0x5b, 0x71, 0xe1, 0x9f, 0x50, 0xfa, 0x31, 0x1f, 0x14, 0x3e, 0x95, 0xc0, 0x8d, 0xaf, 0x36, + 0x59, 0x76, 0x71, 0x87, 0x4b, 0xbf, 0x6a, 0x8c, 0x5f, 0xbf, 0xdf, 0x53, 0x0b, 0xa1, 0x91, 0x0a, 0xcc, 0xb7, 0xcf, + 0x4c, 0x55, 0x46, 0x53, 0x6a, 0x2f, 0xc1, 0x95, 0xb3, 0x1f, 0x41, 0x45, 0x5c, 0x57, 0x64, 0x32, 0x35, 0x40, 0x7b, + 0x5e, 0x56, 0xb8, 0x95, 0x05, 0x78, 0xec, 0x04, 0x64, 0xbb, 0xe5, 0x61, 0xa0, 0x0f, 0x9d, 0xc0, 0xdf, 0x92, 0xa7, + 0xc8, 0xac, 0xd9, 0xc7, 0x9f, 0xb5, 0xe0, 0x1f, 0x5b, 0xf0, 0x13, 0x8a, 0x3b, 0xad, 0xcc, 0xbf, 0x95, 0xd6, 0x2d, + 0xee, 0xdf, 0xc9, 0x34, 0xa1, 0xa8, 0x4c, 0xa8, 0xfd, 0x4a, 0x7f, 0x37, 0xc1, 0x92, 0x54, 0xf6, 0x0f, 0x12, 0x3e, + 0x98, 0x35, 0x9e, 0x58, 0xe3, 0xc9, 0x70, 0xba, 0x95, 0x86, 0x21, 0x40, 0xa1, 0x9f, 0x97, 0xb9, 0xa2, 0xfa, 0xf9, + 0xe7, 0x35, 0x5f, 0xf3, 0x66, 0x8b, 0x6d, 0xd2, 0x03, 0x0d, 0xf6, 0xf2, 0x68, 0x4a, 0xe1, 0x24, 0xea, 0xdc, 0x48, + 0xd4, 0x45, 0xcd, 0x32, 0x54, 0x27, 0x78, 0x35, 0x4f, 0xf5, 0xb0, 0x37, 0x13, 0xd1, 0x5a, 0x49, 0x59, 0x62, 0xc0, + 0x5a, 0x47, 0x1e, 0x92, 0xbb, 0xb5, 0x8e, 0x3b, 0x0d, 0x75, 0x69, 0x0a, 0x25, 0xc0, 0x0a, 0x17, 0xe0, 0x08, 0xfa, + 0xa9, 0x08, 0x39, 0x5c, 0x53, 0x95, 0x7e, 0x41, 0x53, 0xf2, 0xc4, 0x53, 0xd4, 0x6a, 0x45, 0xba, 0xfd, 0x28, 0xc7, + 0x6e, 0xf8, 0xc6, 0x09, 0x39, 0x31, 0x42, 0x7f, 0x77, 0x2c, 0xe5, 0x0c, 0x2d, 0x1e, 0xd4, 0x09, 0xd6, 0xcb, 0x5b, + 0x0a, 0x14, 0x73, 0x74, 0x59, 0x75, 0xcd, 0x6b, 0xb4, 0x7d, 0x59, 0xf6, 0xfb, 0xb9, 0xad, 0x27, 0x65, 0x47, 0x9b, + 0xa5, 0xd9, 0x87, 0xa8, 0x98, 0xc2, 0x5d, 0x9f, 0x68, 0xfe, 0x2a, 0xd4, 0x57, 0x6d, 0x99, 0xf3, 0x11, 0x47, 0x5c, + 0x8c, 0x9c, 0xd4, 0x3f, 0xab, 0xa9, 0x57, 0xe2, 0x7e, 0x55, 0xc9, 0x77, 0xc2, 0x58, 0x31, 0x3a, 0xa0, 0xfe, 0x54, + 0xa9, 0xbc, 0x5f, 0x16, 0x00, 0xf7, 0x24, 0xd8, 0x27, 0xb0, 0xaf, 0xd0, 0x08, 0xbf, 0x2d, 0x01, 0xff, 0x46, 0x71, + 0x03, 0x56, 0x81, 0x01, 0x46, 0x93, 0xed, 0x39, 0x4d, 0xe0, 0x80, 0x13, 0x5a, 0x45, 0x41, 0x85, 0x19, 0x1a, 0x6a, + 0x0b, 0xa3, 0xa7, 0x28, 0xe3, 0x56, 0x99, 0xbd, 0x1b, 0x63, 0xa7, 0x05, 0x5e, 0xc3, 0x9f, 0xcf, 0x0b, 0x3d, 0x6c, + 0xd4, 0x41, 0x7a, 0x74, 0x12, 0xd3, 0x1f, 0xb7, 0x70, 0x72, 0xb3, 0x70, 0x96, 0x35, 0x4b, 0xa0, 0x3b, 0x70, 0x41, + 0x8c, 0xfb, 0xfd, 0x1c, 0x8e, 0x4c, 0x33, 0xf2, 0x05, 0xcb, 0x69, 0xcc, 0x96, 0x54, 0x7b, 0xda, 0x5d, 0x56, 0x61, + 0x4e, 0x97, 0x56, 0xc6, 0x9b, 0x32, 0x50, 0x19, 0x6d, 0xb7, 0x21, 0xfc, 0xe9, 0xb6, 0x76, 0x49, 0xe7, 0x4b, 0xc8, + 0x00, 0x7f, 0x40, 0x22, 0x8a, 0xd8, 0xd7, 0xff, 0x56, 0xe3, 0x94, 0x9e, 0x28, 0xad, 0x59, 0x42, 0xd7, 0x4c, 0xd7, + 0x4f, 0x2f, 0xd8, 0xba, 0xb1, 0x14, 0xb6, 0xdb, 0xb0, 0x99, 0xc0, 0x34, 0xe7, 0x4a, 0xa6, 0x17, 0xa8, 0x93, 0x02, + 0x2a, 0x16, 0x5e, 0xe0, 0xf2, 0x4b, 0x09, 0x85, 0xe6, 0xce, 0x97, 0x0b, 0xa3, 0xc4, 0x84, 0x56, 0xc9, 0x2f, 0x1f, + 0x2a, 0xf3, 0xb5, 0xf1, 0x88, 0xfb, 0x3d, 0x0d, 0x13, 0x53, 0x24, 0x2a, 0x44, 0x67, 0xbf, 0x82, 0x2c, 0x47, 0x00, + 0x8e, 0xe5, 0xa9, 0xac, 0xe9, 0x8f, 0x29, 0xc4, 0x41, 0x87, 0x06, 0xbd, 0x2b, 0xe4, 0x55, 0x56, 0xf2, 0x10, 0xef, + 0x09, 0x9e, 0x66, 0xf4, 0x7e, 0x83, 0x0f, 0x6d, 0xed, 0xd1, 0x13, 0x64, 0xe3, 0x29, 0xf7, 0xeb, 0xef, 0x44, 0x38, + 0x87, 0x68, 0x95, 0x0b, 0xaa, 0xd5, 0xd5, 0x0e, 0x80, 0xca, 0xb3, 0xbd, 0x7a, 0x04, 0xa7, 0x9b, 0xbe, 0xbe, 0x55, + 0xa1, 0x33, 0x07, 0x90, 0xf6, 0x90, 0xac, 0x6b, 0xae, 0x77, 0x80, 0x3b, 0x12, 0xab, 0x35, 0xd0, 0x58, 0xb7, 0x35, + 0x3b, 0xed, 0x51, 0x3c, 0x26, 0x32, 0x33, 0x16, 0x29, 0xc6, 0xdc, 0xad, 0xd3, 0xa2, 0x68, 0x83, 0x66, 0x08, 0xbb, + 0x77, 0x1d, 0xbe, 0x6e, 0x45, 0x58, 0xbf, 0xdf, 0xf6, 0x05, 0x46, 0xc3, 0x98, 0x6b, 0xf7, 0x3c, 0x43, 0x37, 0x6c, + 0xb0, 0x8d, 0x9c, 0x87, 0xc8, 0x87, 0x99, 0x3a, 0x10, 0x65, 0x6d, 0x0d, 0xd8, 0x1e, 0x71, 0xbd, 0x69, 0x15, 0x3f, + 0xaf, 0x62, 0xce, 0xf6, 0xac, 0x71, 0x4a, 0xeb, 0x6b, 0x5c, 0x73, 0x5c, 0x15, 0x22, 0x6a, 0xeb, 0x19, 0x0f, 0xc3, + 0xce, 0x17, 0xb8, 0x33, 0x2b, 0x0c, 0x5e, 0x84, 0xa5, 0x92, 0x9d, 0xca, 0xf5, 0xe7, 0xb0, 0xc5, 0x41, 0x2a, 0x5f, + 0x7a, 0xfd, 0xfd, 0xdd, 0x17, 0x5f, 0xa0, 0x9b, 0x9a, 0xf3, 0x23, 0x08, 0x32, 0x81, 0x0e, 0x59, 0x4a, 0xf5, 0xf8, + 0x5d, 0x01, 0xd4, 0x1e, 0xe6, 0xe1, 0xbb, 0x82, 0x89, 0xf8, 0x3a, 0xbb, 0x8c, 0x2b, 0x59, 0x8c, 0xae, 0xb9, 0x48, + 0x65, 0x61, 0xa5, 0xc6, 0xc1, 0xf1, 0x6a, 0x95, 0xf3, 0x00, 0x4c, 0xe5, 0x2d, 0xa3, 0x6c, 0x2b, 0xcb, 0xf4, 0xe0, + 0x6a, 0x79, 0x7a, 0xa5, 0x45, 0xe7, 0xe5, 0xf5, 0x65, 0x10, 0xe1, 0xaf, 0x73, 0xf3, 0xe3, 0x2a, 0x2e, 0x3f, 0x06, + 0x91, 0xb5, 0xa9, 0x33, 0x3f, 0x50, 0x2a, 0x0f, 0xfe, 0x53, 0x20, 0xd3, 0xfd, 0xae, 0x00, 0xcb, 0x6c, 0x5b, 0xf1, + 0x61, 0x8c, 0xb5, 0x0e, 0x27, 0x64, 0xa6, 0x4a, 0xf4, 0xde, 0x25, 0xeb, 0x02, 0xac, 0xfd, 0x14, 0x96, 0xb1, 0xca, + 0x35, 0xc3, 0xca, 0x54, 0x45, 0x66, 0x56, 0xd6, 0x6c, 0x3f, 0xb4, 0x4e, 0x34, 0x73, 0xf4, 0x16, 0xd0, 0x0f, 0x64, + 0xff, 0x92, 0x96, 0x6b, 0xe6, 0xf9, 0xd8, 0x34, 0x5e, 0x3f, 0xda, 0xbf, 0x74, 0x0b, 0xf6, 0xd6, 0xde, 0xc9, 0x51, + 0x98, 0x08, 0x9e, 0xb5, 0x66, 0x7c, 0x91, 0x67, 0x05, 0xac, 0x9c, 0xc9, 0x78, 0x4c, 0xbd, 0xa5, 0xd5, 0xba, 0x39, + 0x3a, 0x24, 0xd7, 0xec, 0x71, 0xf5, 0x98, 0x93, 0x7d, 0xde, 0x32, 0xb5, 0x6d, 0x5b, 0xc7, 0x79, 0x9a, 0x7c, 0x65, + 0xba, 0x2f, 0xd6, 0x36, 0x22, 0xba, 0x72, 0xee, 0x73, 0x5e, 0xc1, 0xad, 0x6f, 0x4a, 0x43, 0xaf, 0x25, 0x00, 0xd1, + 0x69, 0x03, 0xfe, 0x82, 0x95, 0xeb, 0x51, 0xc5, 0xcb, 0x0a, 0x24, 0x2c, 0x28, 0xc2, 0x9b, 0x62, 0x6f, 0x0a, 0x77, + 0xe3, 0xf4, 0x1c, 0x76, 0xe0, 0x62, 0x8a, 0xee, 0x38, 0x31, 0x99, 0x95, 0x46, 0x2b, 0x1a, 0xe9, 0x5f, 0xae, 0x2f, + 0xb1, 0xee, 0x8b, 0x56, 0xe6, 0xd9, 0x9c, 0x0a, 0x8b, 0xdd, 0x55, 0x2e, 0x9d, 0xa8, 0xdf, 0x32, 0xe1, 0xca, 0x95, + 0x20, 0x20, 0xd3, 0x82, 0xf5, 0x0a, 0xb3, 0x8b, 0xe4, 0x1a, 0x08, 0x19, 0x18, 0xbe, 0x06, 0x6b, 0x51, 0x72, 0x63, + 0x05, 0xeb, 0xdd, 0xf3, 0x75, 0x82, 0x90, 0x82, 0x07, 0x6e, 0x82, 0x7e, 0x68, 0xdd, 0xbc, 0x1d, 0x25, 0xca, 0x20, + 0x1e, 0xb7, 0x76, 0xca, 0x41, 0x02, 0x01, 0xb8, 0xa7, 0x2a, 0x04, 0x87, 0x02, 0x59, 0x07, 0x57, 0x33, 0x8e, 0xe0, + 0xea, 0xca, 0x99, 0x8b, 0x1b, 0x80, 0x75, 0xe5, 0xcf, 0x65, 0x83, 0x0b, 0xeb, 0x11, 0x55, 0xe6, 0x8c, 0x53, 0x0c, + 0x62, 0x64, 0x09, 0xfa, 0xca, 0x52, 0xda, 0x4b, 0xd0, 0x34, 0x5e, 0xb1, 0x95, 0xf2, 0x01, 0xa0, 0xe7, 0x6c, 0xa5, + 0x8c, 0xfd, 0xf1, 0xeb, 0x33, 0xb6, 0xd2, 0xd2, 0xe0, 0xe9, 0xd5, 0xec, 0x7c, 0x76, 0x36, 0x60, 0x07, 0x51, 0xa8, + 0x0d, 0x18, 0x02, 0x87, 0xc4, 0x1f, 0x0c, 0x42, 0x8d, 0x77, 0x32, 0x50, 0x01, 0xb1, 0x88, 0xc7, 0x63, 0x23, 0x6e, + 0x56, 0x38, 0x1e, 0x62, 0xf0, 0xab, 0xe6, 0x0b, 0x12, 0x10, 0x6a, 0x4a, 0x43, 0x97, 0xc7, 0x70, 0x38, 0xd9, 0x9b, + 0x40, 0x2a, 0x66, 0x66, 0xaa, 0x30, 0x36, 0x26, 0x11, 0xc4, 0x3b, 0xed, 0xac, 0x17, 0xca, 0xed, 0xae, 0xd1, 0x40, + 0xae, 0x0c, 0xbe, 0xa8, 0xe2, 0xc9, 0xde, 0xb0, 0xab, 0x62, 0x1c, 0x85, 0x6b, 0xa3, 0x7c, 0x3b, 0x3b, 0x04, 0xf0, + 0xda, 0xb3, 0xa1, 0x2f, 0x97, 0x38, 0xdb, 0x7f, 0x4a, 0x1e, 0x3f, 0x25, 0xf4, 0x8c, 0x9d, 0x7d, 0xf5, 0x94, 0x9e, + 0x29, 0x72, 0xb2, 0x37, 0x89, 0xae, 0x99, 0xc5, 0x7c, 0x39, 0x50, 0x4d, 0xa0, 0x97, 0xa3, 0xb5, 0x50, 0x0b, 0x4c, + 0x3b, 0x34, 0x85, 0xdf, 0x8e, 0xf7, 0x82, 0xc1, 0x75, 0xbb, 0xe9, 0xd7, 0xed, 0xb6, 0x7a, 0x5e, 0x5d, 0x7b, 0x07, + 0xd1, 0x6e, 0x31, 0x93, 0xbf, 0x8f, 0xf7, 0xdc, 0x1c, 0x60, 0x7d, 0x0f, 0x8f, 0x89, 0x69, 0xd2, 0xce, 0xa8, 0xf8, + 0x35, 0x3d, 0xc1, 0x3e, 0x34, 0x8b, 0xec, 0xe8, 0xc3, 0xf0, 0xdf, 0xea, 0x44, 0x7d, 0xf6, 0xd5, 0x01, 0x90, 0x23, + 0x90, 0x81, 0x62, 0x89, 0x60, 0x86, 0x03, 0x4d, 0x01, 0x05, 0x99, 0x1e, 0x77, 0xaa, 0x87, 0x5f, 0x8d, 0x9a, 0x9a, + 0x91, 0x6b, 0x98, 0x1a, 0x6c, 0x0b, 0x7e, 0xa0, 0xba, 0xa1, 0xbf, 0xd1, 0xe8, 0x46, 0xda, 0xc9, 0xcc, 0xbc, 0xa4, + 0x36, 0xae, 0xdb, 0x35, 0x04, 0x30, 0x76, 0xf0, 0x82, 0x92, 0x7d, 0x7d, 0x78, 0xb9, 0x87, 0xab, 0x08, 0x50, 0xb2, + 0x58, 0xf0, 0xf5, 0xe0, 0x52, 0x6f, 0xee, 0xbd, 0x80, 0x0c, 0xbe, 0x0e, 0x8e, 0xbe, 0x1e, 0xc8, 0x41, 0x70, 0xb8, + 0x7f, 0x79, 0x14, 0x38, 0xe3, 0x7e, 0x08, 0xf1, 0xa8, 0x2a, 0x8a, 0x99, 0x30, 0x55, 0x24, 0xb6, 0xf6, 0xdc, 0xd6, + 0xab, 0x8c, 0xcf, 0x68, 0x3a, 0xb5, 0xc8, 0xdf, 0x61, 0xca, 0x62, 0xf3, 0x3b, 0x98, 0xf0, 0xab, 0x20, 0x72, 0x41, + 0x50, 0x67, 0x79, 0x14, 0xd3, 0x25, 0xbb, 0x15, 0x61, 0x4a, 0x93, 0xfd, 0x9c, 0x90, 0x28, 0x5c, 0x2a, 0xf0, 0x3c, + 0xf5, 0x3a, 0x81, 0x38, 0xae, 0xee, 0xf3, 0x5b, 0x11, 0x2e, 0x69, 0xbe, 0x9f, 0x90, 0x56, 0x11, 0x2e, 0x22, 0xcb, + 0xa6, 0xa6, 0x17, 0x2c, 0x5c, 0xd1, 0x4b, 0x60, 0xa6, 0xe4, 0x3a, 0xbc, 0x04, 0x2e, 0x6f, 0x3d, 0x5f, 0x2d, 0xd8, + 0x65, 0x43, 0xfa, 0x66, 0xf8, 0xe2, 0x0b, 0xeb, 0x93, 0x07, 0x3c, 0xa4, 0xf3, 0xc3, 0x4b, 0xc1, 0x06, 0xe0, 0x3a, + 0xe3, 0x37, 0xdf, 0xc9, 0x5b, 0x3d, 0x2f, 0xed, 0x29, 0xc6, 0x99, 0x69, 0x27, 0x26, 0xed, 0x84, 0xdc, 0xbf, 0x6f, + 0x6f, 0x62, 0x73, 0xb2, 0x97, 0xd1, 0x5a, 0xb9, 0xac, 0x5a, 0x86, 0xa4, 0x58, 0x33, 0xe4, 0xef, 0x51, 0x72, 0x6a, + 0x05, 0x9e, 0xec, 0x82, 0x57, 0xc9, 0xd2, 0x3f, 0xa8, 0xac, 0xd5, 0x80, 0x3d, 0x46, 0x2c, 0x0b, 0x85, 0x63, 0xff, + 0x26, 0x63, 0xc5, 0xda, 0x17, 0x68, 0xc4, 0xc8, 0xbd, 0xbd, 0xc9, 0x98, 0x17, 0x73, 0x35, 0x59, 0x7b, 0xa1, 0xea, + 0xbc, 0xf4, 0xbc, 0xc5, 0x7b, 0x39, 0xa5, 0x86, 0x91, 0x88, 0xee, 0x8d, 0x95, 0x19, 0xa5, 0x4a, 0xd4, 0x1a, 0x34, + 0x22, 0xd8, 0xd8, 0x05, 0xbf, 0x04, 0x27, 0x54, 0xee, 0xa9, 0xb3, 0x7d, 0x3b, 0xa5, 0xd2, 0x03, 0x96, 0xa5, 0x46, + 0x55, 0xee, 0x96, 0x99, 0x64, 0xd5, 0x20, 0x18, 0xfd, 0x59, 0x4a, 0x31, 0xc3, 0x3b, 0x23, 0x0b, 0xa6, 0x60, 0x25, + 0xa8, 0x6a, 0x19, 0x96, 0x43, 0x8e, 0x5a, 0x3c, 0xe3, 0x93, 0x2a, 0xf5, 0x8f, 0x8e, 0x20, 0xb9, 0xcb, 0x75, 0x2b, + 0x48, 0xee, 0xd3, 0xf1, 0x53, 0x3d, 0xd0, 0xe9, 0x5a, 0x3b, 0x1e, 0xfa, 0xfc, 0x36, 0xe2, 0x6b, 0xeb, 0xde, 0x53, + 0xad, 0x55, 0x28, 0x03, 0x2d, 0x56, 0x54, 0xae, 0xd4, 0x92, 0xde, 0xef, 0x22, 0x00, 0x16, 0xb1, 0x31, 0x1b, 0xef, + 0xda, 0x66, 0x85, 0xa0, 0xd1, 0x65, 0x47, 0x9b, 0x78, 0xc0, 0x12, 0xdd, 0xda, 0xc1, 0x84, 0xc6, 0x47, 0xac, 0xec, + 0xf7, 0xf3, 0x23, 0xa0, 0xa7, 0xda, 0x88, 0xa9, 0x80, 0x23, 0xff, 0x4b, 0x2b, 0x32, 0x45, 0x81, 0xcd, 0x9a, 0xba, + 0x5b, 0x63, 0x19, 0x89, 0xbe, 0x4c, 0xe9, 0xf2, 0x84, 0x67, 0xc0, 0xb4, 0x5e, 0xb7, 0x1c, 0x57, 0x76, 0x15, 0x47, + 0x9e, 0x0a, 0xcb, 0x8a, 0xf3, 0x2a, 0x1c, 0x6f, 0x3d, 0xbe, 0xc1, 0xbe, 0x61, 0xd3, 0x2e, 0xfc, 0x21, 0x84, 0x85, + 0xf0, 0x26, 0x83, 0xdb, 0x88, 0xb6, 0x93, 0x40, 0xe5, 0x8d, 0xb9, 0x4e, 0x28, 0x9b, 0xdb, 0xf5, 0xda, 0x33, 0x48, + 0x27, 0xe6, 0x40, 0xa9, 0x46, 0xd0, 0x1a, 0xcd, 0x82, 0xaa, 0x11, 0x8f, 0x1c, 0x0f, 0xef, 0x0c, 0x62, 0xb5, 0x7c, + 0x49, 0x53, 0x29, 0x1a, 0x80, 0x71, 0x01, 0x5c, 0x9e, 0x7e, 0x79, 0xff, 0xd3, 0x29, 0x8f, 0x8b, 0x64, 0xf9, 0x2e, + 0x2e, 0xe2, 0xab, 0x32, 0xdc, 0xa8, 0x31, 0x8a, 0x6b, 0x32, 0x15, 0x03, 0x26, 0xcd, 0x4a, 0x6a, 0xee, 0x4a, 0x4d, + 0x88, 0xb1, 0xce, 0x64, 0x5d, 0x56, 0xf2, 0xaa, 0x51, 0xe9, 0xba, 0xc8, 0xf0, 0xe3, 0x96, 0xcf, 0xe9, 0x3e, 0x00, + 0x79, 0x1a, 0x17, 0xd2, 0x48, 0xea, 0x42, 0x8c, 0xb9, 0x88, 0xd7, 0xf5, 0xf1, 0xb8, 0xd1, 0xf5, 0x92, 0x3d, 0x1b, + 0x3f, 0x99, 0xbe, 0xc9, 0xc2, 0x6c, 0x20, 0xc8, 0xa8, 0x5a, 0x72, 0xd1, 0x32, 0xe5, 0x54, 0x26, 0x01, 0xe8, 0xe3, + 0xd9, 0x63, 0xec, 0x60, 0x3c, 0x26, 0x9b, 0xb6, 0x78, 0x80, 0x87, 0xcb, 0x75, 0x58, 0x90, 0x99, 0xae, 0x23, 0x0a, + 0x04, 0xbf, 0xad, 0x02, 0x40, 0x72, 0xb4, 0x55, 0x19, 0x2e, 0x8d, 0x3d, 0x1b, 0x4f, 0xa8, 0xc4, 0x6e, 0x87, 0xa4, + 0xf6, 0x2a, 0x74, 0x33, 0x2f, 0x7d, 0x8f, 0x22, 0x69, 0x5c, 0x96, 0x76, 0x2a, 0x95, 0x6a, 0xcf, 0xcc, 0x5c, 0xd7, + 0x20, 0x06, 0x43, 0xa8, 0xeb, 0x2e, 0xbd, 0xba, 0x77, 0x9b, 0x6b, 0xcd, 0x76, 0xc0, 0x7b, 0x0d, 0x9a, 0xa1, 0xe4, + 0x2d, 0xe6, 0xad, 0x2b, 0xa2, 0xa6, 0xab, 0x35, 0x98, 0x15, 0xa3, 0x6c, 0x29, 0x4a, 0xd7, 0x14, 0x94, 0x82, 0xd1, + 0xc5, 0xda, 0x5b, 0xb8, 0x6f, 0x64, 0xe3, 0xc2, 0x92, 0xe9, 0xd5, 0xa2, 0xa4, 0x84, 0xea, 0xa6, 0x62, 0xa4, 0x84, + 0x91, 0xd2, 0xf0, 0x54, 0xbe, 0x17, 0x78, 0x9c, 0xe7, 0x41, 0xd4, 0xf2, 0x02, 0x3b, 0xae, 0xc8, 0x31, 0x38, 0x7a, + 0x99, 0x9c, 0x86, 0x02, 0xff, 0x98, 0x29, 0x10, 0xd3, 0xa1, 0xba, 0xdf, 0xe0, 0xe6, 0xff, 0x67, 0xc1, 0x02, 0x8f, + 0x6f, 0xbd, 0xc4, 0x6d, 0xf4, 0xcf, 0xc2, 0xa7, 0xa5, 0xcf, 0xa5, 0xef, 0xea, 0xe2, 0x49, 0x7b, 0xb3, 0x51, 0xb2, + 0xcc, 0xf2, 0xf4, 0xad, 0x4c, 0x39, 0x88, 0xcc, 0xd0, 0x1a, 0x94, 0x1d, 0x89, 0xc6, 0x0d, 0x0f, 0x8c, 0x18, 0x1b, + 0x37, 0xbe, 0x1f, 0x33, 0x90, 0x0d, 0x83, 0xd5, 0x37, 0x4b, 0x65, 0xb2, 0xbe, 0x02, 0x4c, 0x11, 0x25, 0x3f, 0x79, + 0x99, 0x73, 0x78, 0x0a, 0xf5, 0xf5, 0x0b, 0xdc, 0xe6, 0x4a, 0xdf, 0xe7, 0xfc, 0xc7, 0x8c, 0xfe, 0x88, 0x40, 0x27, + 0xf1, 0x0a, 0xe4, 0x1e, 0xcf, 0xa1, 0x6e, 0x84, 0xa9, 0xe5, 0x18, 0x1c, 0x08, 0xd1, 0x40, 0x44, 0xc5, 0x02, 0x05, + 0x75, 0x61, 0x80, 0x35, 0xd4, 0x05, 0x73, 0x78, 0x9e, 0xcb, 0xe4, 0xe3, 0xd4, 0xf8, 0xcc, 0x0f, 0x63, 0x8c, 0x99, + 0x1c, 0x0c, 0xc2, 0x6a, 0x16, 0x0c, 0xc7, 0xa3, 0xc9, 0xc1, 0x33, 0x38, 0xb7, 0x83, 0x71, 0x40, 0x06, 0x41, 0x5d, + 0xae, 0x62, 0x41, 0xcb, 0xeb, 0x4b, 0x5b, 0x06, 0x7e, 0x5c, 0x07, 0x83, 0x7f, 0x16, 0x9e, 0xe2, 0x1d, 0x34, 0x27, + 0x67, 0x32, 0x04, 0x1b, 0xfb, 0x35, 0x01, 0x49, 0x59, 0x4f, 0xf3, 0x93, 0xfa, 0x70, 0x63, 0x4a, 0xfb, 0x67, 0x0e, + 0x2f, 0x38, 0xec, 0x90, 0x40, 0x81, 0x34, 0x9e, 0x66, 0xa3, 0xd7, 0x4a, 0x91, 0xfb, 0xae, 0xe0, 0x70, 0x67, 0xee, + 0x39, 0xd3, 0x23, 0xa7, 0x90, 0x68, 0x66, 0x01, 0x37, 0xf2, 0xd7, 0xe2, 0x3a, 0xce, 0xb3, 0x74, 0xaf, 0xf9, 0x66, + 0xaf, 0xbc, 0x13, 0x55, 0x7c, 0x3b, 0x0a, 0x8c, 0x35, 0x21, 0xf7, 0x55, 0x4f, 0x80, 0x9e, 0x00, 0x5b, 0x00, 0x0c, + 0x88, 0x77, 0xcc, 0x4c, 0x66, 0x3c, 0x02, 0x8f, 0xc0, 0xa6, 0x0f, 0x64, 0x71, 0xe7, 0x5c, 0x92, 0xfc, 0xcd, 0x54, + 0xda, 0xab, 0x5e, 0xb9, 0x53, 0x90, 0xf5, 0x6a, 0x2b, 0x77, 0xdd, 0xfa, 0xec, 0x9b, 0x0e, 0xaf, 0xc0, 0x73, 0x09, + 0x6e, 0x91, 0xfd, 0x7e, 0x53, 0x50, 0x29, 0x8c, 0x8a, 0x78, 0x27, 0xb9, 0x46, 0xff, 0x76, 0x6f, 0x6c, 0x14, 0xc9, + 0x2d, 0x1f, 0x1e, 0x40, 0x9d, 0xc9, 0xbb, 0xe2, 0x76, 0x0e, 0x51, 0x5b, 0x77, 0xe3, 0x81, 0xd5, 0x06, 0xed, 0xb2, + 0xe6, 0x08, 0x2e, 0xbc, 0xd8, 0xcb, 0x60, 0x2c, 0x70, 0x56, 0x46, 0x4a, 0x8d, 0x6b, 0x48, 0x2d, 0xf8, 0x24, 0x4f, + 0xef, 0x21, 0x4b, 0x3d, 0x09, 0x8a, 0x1c, 0xcf, 0x62, 0xc8, 0x34, 0xde, 0x06, 0x1e, 0xbf, 0x93, 0x21, 0x48, 0xd3, + 0xb6, 0xdb, 0xe6, 0x08, 0x94, 0xdd, 0x03, 0x53, 0x92, 0xba, 0x36, 0xa6, 0x06, 0x1a, 0x6a, 0x0f, 0x35, 0x52, 0x11, + 0x67, 0x47, 0x6f, 0x40, 0x87, 0x08, 0xbe, 0xdf, 0x69, 0x56, 0x76, 0xbc, 0x98, 0x10, 0x3c, 0x79, 0x5f, 0xde, 0x66, + 0x65, 0x55, 0x46, 0xef, 0x53, 0x34, 0x84, 0x4a, 0xa4, 0x88, 0x5e, 0x41, 0x3c, 0xbd, 0x12, 0x7f, 0x97, 0xd1, 0x4f, + 0x29, 0x8d, 0xd3, 0x14, 0xd3, 0x5f, 0x14, 0xf0, 0xf3, 0x39, 0xa0, 0x3a, 0xe2, 0x4e, 0x88, 0xce, 0x25, 0xd8, 0xab, + 0x41, 0x34, 0xab, 0x8a, 0x03, 0x86, 0x66, 0x74, 0x2b, 0x28, 0x62, 0xb4, 0x61, 0xf6, 0x1f, 0x0a, 0x14, 0x0a, 0xa9, + 0x62, 0xbe, 0x13, 0xf6, 0x21, 0xfa, 0x11, 0x8b, 0x3c, 0x7e, 0xf7, 0xda, 0x0c, 0x69, 0x74, 0x27, 0xa9, 0xde, 0xda, + 0x78, 0x6c, 0x61, 0xe0, 0xb2, 0xe8, 0x72, 0x4d, 0xcf, 0xe2, 0x55, 0x16, 0x6d, 0x00, 0x7f, 0xe2, 0xdd, 0xeb, 0xe7, + 0xca, 0xc2, 0xe4, 0x45, 0x06, 0x8a, 0x83, 0xe3, 0x77, 0xaf, 0xdf, 0xc8, 0x74, 0x9d, 0xf3, 0xe8, 0x4c, 0x22, 0x69, + 0x3d, 0x7e, 0xf7, 0xfa, 0x67, 0x34, 0xf7, 0xfa, 0xa9, 0x80, 0xf7, 0xaf, 0x80, 0xb7, 0x8c, 0xe2, 0x35, 0xf4, 0x49, + 0xfd, 0x4e, 0xd6, 0xd8, 0x29, 0xaf, 0xd6, 0x32, 0xfa, 0x25, 0xad, 0x3d, 0x69, 0xd5, 0xbf, 0x0a, 0x9f, 0xda, 0x79, + 0x02, 0x9e, 0xdb, 0x3c, 0x13, 0x1f, 0x23, 0x2b, 0xda, 0x09, 0xa2, 0xaf, 0xf7, 0x6e, 0xaf, 0x72, 0x51, 0x46, 0xf8, + 0x82, 0xa1, 0x5d, 0x50, 0xb4, 0xbf, 0x7f, 0x73, 0x73, 0x33, 0xba, 0x79, 0x32, 0x92, 0xc5, 0xe5, 0xfe, 0xe4, 0xdb, + 0x6f, 0xbf, 0xdd, 0xc7, 0xb7, 0xc1, 0xd7, 0x6d, 0xb7, 0xf7, 0x8a, 0xf0, 0x01, 0x0b, 0x10, 0xa1, 0xfa, 0x6b, 0xb8, + 0xa2, 0x80, 0x16, 0x6e, 0xf0, 0x75, 0xf0, 0xb5, 0x3e, 0x74, 0xbe, 0x3e, 0x2c, 0xaf, 0x2f, 0x55, 0xf9, 0x5d, 0x25, + 0x1f, 0x8c, 0xc7, 0xe3, 0x7d, 0x90, 0x40, 0x7d, 0x3d, 0xe0, 0x83, 0xe0, 0x28, 0x18, 0x64, 0x70, 0xa1, 0x29, 0xaf, + 0x2f, 0x8f, 0x02, 0xcf, 0x34, 0xb7, 0xc1, 0x22, 0x3a, 0x10, 0x97, 0x60, 0xff, 0x92, 0x06, 0x5f, 0x07, 0xc4, 0xa5, + 0x7c, 0x05, 0x29, 0x5f, 0x1d, 0x3c, 0xf3, 0xd3, 0xfe, 0x97, 0x4a, 0x7b, 0xe2, 0xa7, 0x1d, 0x62, 0xda, 0x93, 0xe7, + 0x7e, 0xda, 0x91, 0x4a, 0x7b, 0xe9, 0xa7, 0xfd, 0xef, 0x72, 0x00, 0xa9, 0x7b, 0xbe, 0xf5, 0xdf, 0xb9, 0xd7, 0x1a, + 0x3c, 0x85, 0xa2, 0xec, 0x2a, 0xbe, 0xe4, 0xd0, 0xe8, 0xc1, 0xed, 0x55, 0x4e, 0x83, 0x01, 0xb6, 0xd7, 0x33, 0x09, + 0xf1, 0x3e, 0xf8, 0x7a, 0x5d, 0xe4, 0x61, 0xf0, 0xf5, 0x00, 0x0b, 0x19, 0x7c, 0x1d, 0x90, 0xaf, 0x8d, 0x81, 0x8c, + 0x60, 0x9b, 0xc0, 0x85, 0x22, 0x1d, 0xda, 0x00, 0x61, 0xbe, 0x34, 0xae, 0xa6, 0x7f, 0x15, 0xdd, 0xd9, 0xf0, 0x96, + 0xa8, 0xdc, 0x74, 0x83, 0x9a, 0x9e, 0x80, 0x77, 0x02, 0x34, 0x2a, 0x0a, 0xae, 0xe3, 0x22, 0x1c, 0x0e, 0xcb, 0xeb, + 0x4b, 0x02, 0x76, 0x99, 0x2b, 0x1e, 0x57, 0x51, 0x20, 0xe4, 0x50, 0xfd, 0x0c, 0x54, 0xe4, 0xab, 0x00, 0x01, 0x91, + 0xe0, 0xbf, 0xa0, 0xa6, 0xef, 0x24, 0xdb, 0x04, 0xc3, 0x1b, 0x7e, 0xfe, 0x31, 0xab, 0x86, 0x4a, 0xb4, 0x78, 0x2d, + 0x28, 0xfc, 0x80, 0xbf, 0xae, 0xea, 0xe8, 0x2f, 0x70, 0xe3, 0x6e, 0x6a, 0xd8, 0xdf, 0x49, 0xc7, 0xa2, 0xbe, 0x93, + 0xf3, 0x6c, 0x31, 0x6d, 0x1d, 0xe8, 0x27, 0x92, 0x54, 0xf3, 0x6c, 0x10, 0x0c, 0x83, 0x01, 0x5f, 0xb0, 0x13, 0x39, + 0xe7, 0x9e, 0xf9, 0xd4, 0x23, 0xe9, 0x4f, 0xf3, 0x2c, 0x1b, 0x80, 0x6f, 0x0a, 0xf2, 0x23, 0xfb, 0xff, 0x3d, 0x1f, + 0xa2, 0xf0, 0x70, 0xf0, 0x68, 0x9f, 0xcc, 0x82, 0xd5, 0x2d, 0x7a, 0x74, 0x46, 0x41, 0x26, 0x96, 0xbc, 0xc8, 0x2a, + 0x6f, 0xa9, 0xdc, 0xad, 0xdb, 0x5e, 0x1e, 0xf7, 0x9e, 0xcd, 0xab, 0x58, 0x04, 0xea, 0x9c, 0x03, 0xc5, 0x1b, 0xca, + 0x9e, 0xca, 0xa6, 0x84, 0x54, 0x1b, 0xf2, 0x86, 0xe5, 0x80, 0x05, 0x87, 0xbd, 0xe1, 0x70, 0x2f, 0x18, 0x38, 0x75, + 0xee, 0x20, 0xd8, 0x1b, 0x0e, 0x8f, 0x02, 0x77, 0x1f, 0xca, 0x46, 0xee, 0xce, 0x48, 0x0b, 0xf6, 0xaf, 0x22, 0x2c, + 0x29, 0x88, 0xc7, 0xa4, 0x16, 0x7f, 0x69, 0x70, 0x99, 0x01, 0x40, 0x1f, 0x29, 0x09, 0x98, 0x81, 0x95, 0x19, 0x40, + 0x68, 0x6e, 0x1a, 0xb3, 0x33, 0x60, 0x1e, 0x81, 0x63, 0x1e, 0x21, 0xe3, 0x00, 0x88, 0x25, 0x01, 0xce, 0x5d, 0x10, + 0xc5, 0xba, 0x90, 0x47, 0x00, 0x7a, 0x8f, 0x3f, 0x89, 0x29, 0x05, 0x93, 0x74, 0xac, 0x42, 0x10, 0xc4, 0xf1, 0xd9, + 0xb5, 0x68, 0x4d, 0xce, 0x12, 0x1d, 0xcc, 0x48, 0x02, 0x6c, 0x88, 0x81, 0x9d, 0x83, 0xfb, 0x39, 0x28, 0x3d, 0xac, + 0xde, 0x09, 0xb9, 0xe0, 0x3b, 0xee, 0xc9, 0x66, 0xe1, 0xea, 0x09, 0x07, 0xc1, 0x1d, 0xd7, 0x2c, 0xc0, 0xa8, 0x2a, + 0xd6, 0x65, 0xc5, 0xd3, 0x0f, 0x77, 0x2b, 0x88, 0x7d, 0x87, 0x03, 0xfa, 0x4e, 0xe6, 0x59, 0x72, 0x17, 0x3a, 0x7b, + 0xae, 0x8d, 0x4a, 0xff, 0xe1, 0xc3, 0x9b, 0x9f, 0x22, 0x10, 0x39, 0xd6, 0x86, 0xd2, 0xdf, 0x71, 0x3c, 0x9b, 0xfc, + 0x08, 0x4f, 0xfe, 0xc6, 0xbe, 0xe3, 0xf6, 0xf4, 0xe8, 0xf7, 0xa1, 0x6e, 0x7a, 0xc7, 0x67, 0x77, 0x7c, 0xe4, 0x8a, + 0x43, 0x75, 0x85, 0xfb, 0xfa, 0x66, 0xed, 0x1b, 0x21, 0x3d, 0x3c, 0xcf, 0x94, 0x37, 0xe6, 0x47, 0x3b, 0x18, 0x06, + 0xc1, 0x54, 0x0b, 0x25, 0x21, 0xea, 0x06, 0x53, 0x02, 0x86, 0x68, 0x4f, 0x2f, 0xab, 0x29, 0x72, 0x6e, 0x6a, 0x64, + 0xe1, 0xfd, 0x80, 0x69, 0xa1, 0x43, 0x23, 0x87, 0xf2, 0x83, 0xc3, 0x09, 0x63, 0x16, 0x7e, 0xab, 0x84, 0xe9, 0x57, + 0x8b, 0xca, 0x39, 0x88, 0xee, 0x81, 0x31, 0xae, 0xe0, 0x05, 0x74, 0x85, 0x5d, 0xaf, 0x55, 0x54, 0x0c, 0x04, 0x8f, + 0x43, 0x0e, 0xd0, 0xc3, 0x2e, 0x68, 0x59, 0x59, 0xaa, 0x5b, 0x95, 0xb3, 0x54, 0x51, 0x97, 0xa1, 0xac, 0x8c, 0x15, + 0xe6, 0x7b, 0xc9, 0x7e, 0x28, 0xd0, 0xb3, 0x7c, 0x2a, 0xba, 0xe0, 0x85, 0x50, 0x82, 0xe5, 0xba, 0xde, 0x89, 0x40, + 0xd4, 0xf9, 0xa1, 0x77, 0xd5, 0xd7, 0x38, 0x76, 0x3c, 0x7d, 0x23, 0x53, 0xae, 0x4d, 0x28, 0x34, 0x9f, 0x2f, 0x7d, + 0xc5, 0x44, 0xc1, 0x6e, 0xa0, 0x5f, 0x6d, 0x1b, 0x7d, 0x76, 0xb7, 0xd6, 0x9b, 0x41, 0x89, 0x8e, 0x79, 0x8d, 0x82, + 0x6b, 0xa5, 0x50, 0x30, 0xda, 0xdb, 0xf8, 0x33, 0x1c, 0xb9, 0xd5, 0xed, 0xa1, 0xf7, 0x5b, 0x15, 0x5f, 0xbe, 0x45, + 0xdf, 0x4e, 0xfb, 0x73, 0x54, 0xc9, 0x5f, 0x56, 0x2b, 0xf0, 0xa1, 0x82, 0xc8, 0x22, 0x16, 0x97, 0x16, 0xea, 0x39, + 0x7d, 0x77, 0xfc, 0x16, 0xfc, 0x28, 0xf1, 0xf7, 0xaf, 0xdf, 0x07, 0x35, 0x99, 0xc6, 0xb3, 0xc2, 0x7c, 0x68, 0x73, + 0x40, 0x68, 0x12, 0x97, 0x66, 0xdf, 0xcf, 0xe2, 0x26, 0xfb, 0xae, 0xd9, 0x7a, 0x5a, 0x34, 0x91, 0xa4, 0x0c, 0xb7, + 0x0f, 0x06, 0x04, 0xfa, 0x00, 0x51, 0x9c, 0x7d, 0x41, 0x63, 0x48, 0xf3, 0x99, 0x7d, 0x3f, 0x22, 0xde, 0xcb, 0x9d, + 0x10, 0x62, 0x5c, 0x61, 0xd1, 0xe8, 0x21, 0x9f, 0xf1, 0x48, 0x19, 0x16, 0xbd, 0xc7, 0x04, 0xe2, 0x0c, 0xa7, 0xd5, + 0x7b, 0xc4, 0x3c, 0xc6, 0xbb, 0x81, 0x96, 0x3d, 0x44, 0x19, 0x75, 0xd9, 0x1b, 0x16, 0xdf, 0x1f, 0xd7, 0x61, 0x66, + 0x2d, 0x2f, 0x87, 0xf0, 0x37, 0xd0, 0x06, 0xe0, 0x94, 0x23, 0xcb, 0x57, 0x99, 0x8d, 0xae, 0x96, 0x98, 0xde, 0x44, + 0x10, 0x8b, 0x47, 0xa7, 0xc3, 0xda, 0xd5, 0xa9, 0x7a, 0x57, 0x3b, 0x9f, 0x89, 0x5e, 0x05, 0x5a, 0xb9, 0xb6, 0x3d, + 0x1e, 0xc2, 0x5d, 0x6a, 0x69, 0x85, 0x8d, 0x28, 0xe7, 0xe2, 0xe9, 0xce, 0xb1, 0x39, 0x01, 0x0d, 0xae, 0x64, 0x0a, + 0xc0, 0x59, 0x5a, 0x8d, 0x46, 0x8d, 0xb0, 0xcf, 0xca, 0xf9, 0x1c, 0xb6, 0x16, 0xe2, 0x69, 0x01, 0x18, 0x6e, 0x13, + 0x83, 0x92, 0x77, 0x63, 0x50, 0x4e, 0x3f, 0x2a, 0x78, 0xeb, 0xe0, 0xac, 0x5c, 0xc6, 0xa9, 0xbc, 0x01, 0x2c, 0xc6, + 0xc0, 0x4f, 0xc5, 0x52, 0xbd, 0x84, 0x64, 0xc9, 0x93, 0x8f, 0x68, 0xb5, 0x91, 0x06, 0xc0, 0x55, 0x4e, 0x8d, 0xe5, + 0x9e, 0x02, 0x09, 0x75, 0xa5, 0xa8, 0x84, 0xb8, 0xaa, 0xe2, 0x64, 0x79, 0x8a, 0xa9, 0xe1, 0x06, 0x7a, 0x11, 0x05, + 0x72, 0xc5, 0x05, 0x90, 0xf4, 0x9c, 0xfd, 0x9e, 0x69, 0xac, 0xf1, 0xe7, 0x12, 0x05, 0x4c, 0x1a, 0x35, 0x18, 0x2b, + 0x65, 0x2f, 0xa5, 0x89, 0xf6, 0x16, 0x04, 0xb5, 0x7b, 0xf9, 0x17, 0xd4, 0xfd, 0x1c, 0x5a, 0x11, 0x36, 0xc0, 0x10, + 0xe5, 0x39, 0xee, 0xd0, 0xd4, 0x2e, 0x39, 0x0f, 0x18, 0xd1, 0x79, 0x9f, 0xd5, 0x76, 0xab, 0x3f, 0x5f, 0x02, 0xb6, + 0x69, 0x6a, 0x7c, 0x0a, 0xc3, 0x84, 0x98, 0xd8, 0xc0, 0x56, 0x59, 0x69, 0x37, 0x94, 0x69, 0x27, 0x5d, 0x32, 0xaf, + 0x85, 0xd3, 0xbc, 0xc7, 0xd8, 0x72, 0xa4, 0x72, 0xf7, 0xfb, 0xa1, 0xf9, 0xc9, 0x72, 0xfa, 0x5c, 0x87, 0x6c, 0xf6, + 0xc6, 0x83, 0xe6, 0x44, 0xab, 0xab, 0x3a, 0xfa, 0x01, 0x1d, 0x80, 0x99, 0xb6, 0x00, 0x99, 0x2e, 0xd8, 0xb4, 0xaf, + 0x44, 0xc5, 0x25, 0x09, 0x4b, 0x25, 0x81, 0x9d, 0xdd, 0x94, 0xec, 0x6c, 0x02, 0xe2, 0x19, 0xee, 0x7a, 0x5a, 0xec, + 0x84, 0x34, 0xe1, 0x2d, 0xf6, 0x12, 0x10, 0x75, 0xa8, 0xea, 0x12, 0xb2, 0x31, 0x86, 0x2e, 0xfe, 0x45, 0x29, 0x4c, + 0x58, 0xcb, 0xa4, 0x2a, 0x31, 0x41, 0x90, 0xca, 0xdd, 0x16, 0x81, 0x25, 0x0a, 0x76, 0x00, 0x7b, 0xef, 0x46, 0xdd, + 0x8c, 0x9a, 0xaa, 0x4e, 0xbd, 0x04, 0x1f, 0xa7, 0x59, 0x57, 0x41, 0x66, 0x61, 0x57, 0xc5, 0x9a, 0x07, 0x3a, 0x36, + 0x95, 0x32, 0x26, 0xee, 0xd2, 0x22, 0x43, 0x3c, 0x60, 0x8c, 0xa5, 0x0b, 0x81, 0x7c, 0xb3, 0xdd, 0x71, 0xd3, 0x13, + 0x84, 0x7e, 0xc2, 0x86, 0x12, 0xb8, 0xe9, 0x6c, 0x4f, 0x4d, 0x33, 0x1f, 0x10, 0x71, 0x18, 0x50, 0x20, 0xd9, 0x38, + 0xa4, 0x39, 0xd2, 0x17, 0x24, 0x4d, 0x18, 0x18, 0x5a, 0xf1, 0x9c, 0x20, 0x2b, 0x0a, 0x3d, 0x5b, 0x57, 0x6d, 0x9c, + 0x2b, 0xc3, 0x1c, 0x2d, 0x39, 0x15, 0x3e, 0x27, 0xc8, 0xc4, 0xee, 0x69, 0x9b, 0x99, 0x0c, 0x47, 0xc9, 0x02, 0xf3, + 0x2b, 0x88, 0x12, 0x77, 0xa6, 0x59, 0x95, 0x83, 0x71, 0x01, 0x0b, 0xb4, 0xf2, 0x3d, 0xa8, 0x1b, 0x6b, 0x68, 0xa3, + 0x61, 0x88, 0xdd, 0xfe, 0x04, 0xfb, 0xb5, 0x76, 0x5a, 0x97, 0x29, 0x96, 0x97, 0x29, 0x44, 0x7b, 0x21, 0xf3, 0x1b, + 0x45, 0xa2, 0x3b, 0x45, 0x18, 0x12, 0xd6, 0x51, 0xf6, 0xa4, 0x4d, 0x0d, 0xa0, 0xa7, 0x5e, 0xc0, 0xf3, 0xce, 0xb5, + 0x0c, 0xbb, 0x48, 0xf7, 0x57, 0x05, 0x9f, 0xd2, 0x0d, 0x82, 0x14, 0xbd, 0x49, 0xc1, 0x9c, 0xd7, 0xa3, 0xa4, 0xde, + 0x9c, 0xb6, 0xcc, 0xa8, 0x3a, 0x2a, 0x42, 0xca, 0x09, 0xfe, 0x93, 0x97, 0x52, 0x13, 0x9b, 0x30, 0xc1, 0x03, 0x1f, + 0xe6, 0x19, 0x36, 0xf0, 0x76, 0xfb, 0x2e, 0x0d, 0x93, 0x36, 0xdb, 0x90, 0x82, 0xb4, 0xc2, 0xc4, 0xc5, 0x80, 0xca, + 0x5e, 0xe3, 0x7e, 0xc1, 0x76, 0xd2, 0x14, 0x3c, 0x08, 0x1b, 0x0d, 0x4c, 0xdc, 0xea, 0xe2, 0xeb, 0x30, 0xa1, 0xe1, + 0x92, 0x6a, 0x67, 0x27, 0x2d, 0x69, 0x6e, 0xaf, 0xcb, 0x0b, 0xdb, 0x07, 0x1d, 0x3b, 0xac, 0x6b, 0x78, 0xa0, 0x79, + 0xcd, 0x2e, 0xae, 0x98, 0xa6, 0x89, 0xc6, 0x7a, 0x48, 0x59, 0x72, 0xac, 0xeb, 0xe9, 0x0a, 0x57, 0xcb, 0x4c, 0x03, + 0xbb, 0x4b, 0xbc, 0xd0, 0x03, 0x1e, 0x76, 0xb8, 0x22, 0xd1, 0x05, 0x36, 0x9b, 0xad, 0x6a, 0x32, 0xcd, 0xef, 0xcb, + 0x96, 0x9b, 0x80, 0x70, 0x96, 0xfa, 0xe6, 0x3e, 0x39, 0xd6, 0xb4, 0xcd, 0x4f, 0x02, 0x1c, 0x6f, 0xaf, 0x80, 0xa4, + 0x63, 0x09, 0xba, 0xf8, 0x96, 0xfe, 0x20, 0x52, 0x33, 0x15, 0xf4, 0xde, 0xf9, 0x22, 0x75, 0xf3, 0x0b, 0xb0, 0x8d, + 0xda, 0x18, 0xd3, 0xac, 0x6c, 0x1d, 0x26, 0xca, 0xc2, 0x1a, 0x59, 0xc8, 0x25, 0xf8, 0x60, 0xee, 0x36, 0x75, 0x7a, + 0xdc, 0x41, 0x84, 0xfd, 0x2e, 0x7a, 0x3c, 0xc2, 0x58, 0xb1, 0x06, 0x89, 0x61, 0x15, 0xd6, 0xb4, 0xb9, 0x1c, 0xa2, + 0x9c, 0x9a, 0x25, 0x13, 0x2d, 0xa9, 0x4f, 0x29, 0xa2, 0x14, 0xcc, 0x8d, 0xa7, 0x65, 0xc3, 0x94, 0x10, 0x21, 0x2b, + 0xa4, 0x03, 0xaa, 0xb5, 0xd0, 0x52, 0x4d, 0xd0, 0xeb, 0xd0, 0xcb, 0x42, 0x63, 0x0a, 0xa2, 0x8f, 0xc8, 0x70, 0x23, + 0x8e, 0x8c, 0xee, 0x8e, 0x51, 0x4c, 0x20, 0x54, 0xb5, 0x97, 0x17, 0x56, 0x9f, 0x96, 0x6d, 0x75, 0x10, 0x57, 0x88, + 0x7c, 0xdf, 0x4d, 0x50, 0x63, 0x14, 0xb4, 0x39, 0xdd, 0xe8, 0x2f, 0x45, 0xe8, 0xdb, 0x85, 0x63, 0x37, 0x0a, 0x22, + 0x21, 0x02, 0xab, 0xd7, 0x54, 0x0c, 0xc8, 0x3a, 0x8f, 0x5d, 0x84, 0x26, 0xdd, 0x2d, 0x44, 0x79, 0xa3, 0xb2, 0xfe, + 0xb8, 0x0e, 0xc9, 0x76, 0x8b, 0x65, 0x81, 0x2f, 0xfb, 0xe9, 0xfa, 0x1e, 0xc8, 0xef, 0x37, 0xeb, 0xcf, 0x42, 0x7e, + 0xbf, 0xce, 0xbe, 0x04, 0xf2, 0xfb, 0xcd, 0xfa, 0x7f, 0x1a, 0xf2, 0xfb, 0x74, 0xed, 0x41, 0x7e, 0xab, 0xc1, 0xf8, + 0xad, 0x60, 0xc1, 0xc9, 0xdb, 0x80, 0xbe, 0x90, 0x2c, 0x38, 0x79, 0xf5, 0xca, 0x37, 0x02, 0x11, 0x1a, 0xb9, 0xde, + 0xc8, 0x82, 0x11, 0xb7, 0x05, 0x5e, 0xa1, 0xd6, 0xc9, 0x07, 0x2a, 0xca, 0x00, 0x78, 0xbd, 0xfc, 0x67, 0x56, 0x2d, + 0xc3, 0x60, 0x3f, 0x20, 0x33, 0x07, 0x09, 0x3a, 0x9c, 0xc0, 0xed, 0x0d, 0x4a, 0xf9, 0xfe, 0x8b, 0xd0, 0xc3, 0x47, + 0xa3, 0x51, 0x5c, 0x5c, 0xe2, 0x9d, 0xce, 0xec, 0x23, 0xc4, 0x3b, 0xce, 0x78, 0x69, 0x23, 0x44, 0x2c, 0xe3, 0xf2, + 0x4c, 0x87, 0x66, 0x29, 0xed, 0x4e, 0x84, 0x80, 0xf3, 0x67, 0x00, 0x53, 0x6f, 0xb7, 0x66, 0x8c, 0xdd, 0x50, 0x0c, + 0xb1, 0x8e, 0x1f, 0xfb, 0x7c, 0xad, 0xdf, 0x9d, 0xc7, 0x25, 0x7f, 0x17, 0x57, 0x4b, 0x06, 0x9d, 0xd4, 0xdb, 0xb5, + 0x90, 0xeb, 0x15, 0x54, 0x02, 0x37, 0x13, 0xc1, 0x93, 0xca, 0x63, 0xa2, 0x14, 0x6c, 0x79, 0x46, 0x0d, 0x70, 0x79, + 0x47, 0x0e, 0x1a, 0xda, 0x61, 0xd2, 0x3e, 0xc1, 0x46, 0xda, 0x9c, 0x81, 0x11, 0xe3, 0xcb, 0x6b, 0x2e, 0xaa, 0x9f, + 0x00, 0x5f, 0x5d, 0xf0, 0x02, 0x6e, 0x0d, 0xc8, 0xd5, 0x02, 0xd8, 0x0a, 0x94, 0x5c, 0x58, 0xc6, 0x99, 0xd3, 0xd2, + 0xf7, 0xf7, 0x50, 0x67, 0xa5, 0x81, 0x2b, 0x6c, 0x0c, 0x07, 0xde, 0x8f, 0xd0, 0xe7, 0x13, 0xdd, 0x57, 0xc1, 0xb5, + 0xf0, 0xaf, 0x35, 0x3f, 0xcb, 0x52, 0x04, 0xb6, 0xc9, 0x52, 0x6d, 0x35, 0xa4, 0xa4, 0x19, 0x98, 0xb0, 0x51, 0x5e, + 0x17, 0xf0, 0xdb, 0xc3, 0x2f, 0xa5, 0x09, 0xda, 0xf3, 0x94, 0x34, 0x95, 0x80, 0xce, 0x1d, 0xc5, 0x00, 0x71, 0x6a, + 0x0b, 0x8b, 0x20, 0x37, 0xcd, 0xd2, 0x28, 0xb6, 0xea, 0x35, 0x87, 0x5a, 0x4a, 0x15, 0x14, 0xf5, 0x59, 0x12, 0x57, + 0xfc, 0x52, 0x82, 0x9b, 0xea, 0xa8, 0x95, 0x42, 0xc1, 0xba, 0x3a, 0x13, 0x97, 0x67, 0x38, 0xba, 0x11, 0x04, 0x17, + 0x1f, 0x35, 0x92, 0x48, 0x4f, 0x6d, 0xef, 0x22, 0xfa, 0x7e, 0xf4, 0xf2, 0xed, 0x87, 0xd7, 0x1f, 0xfe, 0x75, 0xf6, + 0xfc, 0xf8, 0xc3, 0xcb, 0xef, 0x4f, 0xde, 0xbf, 0x7e, 0x79, 0x3a, 0xb7, 0xce, 0x51, 0x3b, 0x05, 0x93, 0xc5, 0x76, + 0x6b, 0xbf, 0xf8, 0xe5, 0xed, 0x8b, 0x97, 0xaf, 0x5e, 0xbf, 0x7d, 0xf9, 0x82, 0xe2, 0x21, 0x72, 0x26, 0xd6, 0x57, + 0xbc, 0xc8, 0x92, 0xb3, 0x65, 0x56, 0x56, 0xd0, 0xac, 0xb9, 0x8e, 0xfb, 0xb5, 0xa8, 0xa7, 0x09, 0xae, 0x1e, 0xb5, + 0x34, 0x98, 0x59, 0x4d, 0xc7, 0x86, 0xdc, 0x50, 0xff, 0xb5, 0x01, 0xa0, 0x6f, 0x2e, 0xb7, 0x71, 0x6b, 0x55, 0x1a, + 0xd5, 0x6e, 0x2b, 0x55, 0xe1, 0x2c, 0x01, 0x79, 0xd7, 0x53, 0x7c, 0x41, 0x57, 0xd6, 0x06, 0x37, 0xbc, 0x60, 0xb9, + 0x1d, 0x86, 0x1b, 0x25, 0xc4, 0xd1, 0xe3, 0x70, 0x11, 0xe5, 0x0a, 0x5e, 0x68, 0xcd, 0xc2, 0x15, 0x5b, 0xde, 0x93, + 0x6b, 0x15, 0x2d, 0x1b, 0x40, 0x61, 0x79, 0x73, 0x50, 0x0f, 0x97, 0xcd, 0xe7, 0xd9, 0x70, 0x12, 0xb5, 0xb2, 0x30, + 0xc6, 0xda, 0x99, 0x60, 0xe1, 0xac, 0x67, 0xaa, 0xfa, 0x51, 0x25, 0x7f, 0x92, 0x37, 0xe6, 0x5a, 0x7d, 0xb8, 0xec, + 0x48, 0x84, 0x42, 0x27, 0x51, 0x7a, 0xb8, 0x56, 0x3f, 0x00, 0xf8, 0x45, 0x13, 0xe3, 0xbf, 0xd6, 0xdc, 0x40, 0xe3, + 0x87, 0xda, 0x3f, 0xd1, 0x29, 0x12, 0xf4, 0x54, 0x78, 0x26, 0x7d, 0x7a, 0x59, 0xce, 0xc1, 0x9c, 0xcc, 0x1f, 0xc3, + 0xb9, 0xd4, 0x31, 0xbc, 0xdb, 0xf3, 0xb9, 0x98, 0xc6, 0x1a, 0x91, 0x52, 0x73, 0x56, 0xf4, 0xcb, 0xbe, 0x03, 0xaf, + 0x46, 0x15, 0xec, 0x63, 0xf8, 0x6c, 0x4c, 0x6a, 0x6d, 0x69, 0x8f, 0x0b, 0xdc, 0xfe, 0x56, 0x9b, 0xc0, 0x3d, 0xdb, + 0x8d, 0x40, 0x9b, 0x3e, 0x12, 0xed, 0x1a, 0x69, 0x79, 0x4f, 0xf7, 0xc1, 0x2e, 0xbc, 0xba, 0x87, 0x32, 0x54, 0x5d, + 0x94, 0xc1, 0x9f, 0x13, 0x45, 0x21, 0x3e, 0x43, 0x1b, 0x4c, 0xbc, 0x2c, 0x45, 0xc0, 0x3c, 0xb2, 0x50, 0xb0, 0xa3, + 0xa2, 0x09, 0x8a, 0xa5, 0xcd, 0x3f, 0x37, 0xda, 0x6e, 0x02, 0xb6, 0x7d, 0x3d, 0xf5, 0x3f, 0x36, 0xb6, 0x09, 0x7e, + 0x9a, 0x5a, 0xca, 0x70, 0xda, 0x02, 0x99, 0x69, 0x2e, 0xc8, 0xc3, 0xa4, 0x95, 0x80, 0x8b, 0x01, 0x7b, 0xed, 0x13, + 0xd5, 0x8e, 0xbd, 0x8d, 0xb0, 0x7d, 0x1a, 0x1a, 0x31, 0xdc, 0x68, 0xfb, 0xdb, 0x66, 0x59, 0x91, 0xa8, 0x49, 0xb3, + 0x29, 0x0a, 0x9b, 0x08, 0x33, 0x77, 0x6c, 0xfe, 0xd6, 0xd7, 0xc3, 0x49, 0x4d, 0x6a, 0xb7, 0xbb, 0xad, 0xcc, 0xf1, + 0x0f, 0xc5, 0xe7, 0x9c, 0x3d, 0xda, 0x64, 0x7a, 0xba, 0xeb, 0x3f, 0x32, 0x1b, 0xa1, 0xb0, 0x71, 0x68, 0xd4, 0x7a, + 0xdf, 0xfb, 0x00, 0x81, 0x1d, 0xd9, 0x34, 0x71, 0x62, 0x59, 0xe7, 0xc9, 0x33, 0x52, 0x8f, 0x5c, 0x05, 0x6c, 0xeb, + 0xce, 0xc2, 0x6f, 0x79, 0x12, 0x76, 0x35, 0x4c, 0xdd, 0x09, 0x4d, 0x17, 0x10, 0x33, 0x15, 0x34, 0x41, 0xe1, 0x1f, + 0x8f, 0x36, 0xcd, 0x93, 0xac, 0xde, 0xf7, 0x3e, 0xc3, 0xdf, 0x59, 0x0a, 0x7f, 0xab, 0xfa, 0x0f, 0xba, 0xb9, 0xe2, + 0xd5, 0x52, 0xa6, 0x51, 0xf0, 0xee, 0xe4, 0xf4, 0x43, 0xa0, 0xb1, 0xf8, 0xf1, 0x46, 0x6a, 0x6c, 0x10, 0xcc, 0x32, + 0x03, 0x9d, 0x5c, 0x2e, 0x2f, 0x11, 0x8e, 0x52, 0xc7, 0x33, 0x38, 0x5d, 0xca, 0x9b, 0xe3, 0x3c, 0xf7, 0xaf, 0x4d, + 0xe6, 0xac, 0xd5, 0x37, 0x89, 0xc6, 0x89, 0x14, 0x82, 0xf4, 0x77, 0x94, 0x95, 0x67, 0x5a, 0x5f, 0x97, 0x9e, 0x9d, + 0xdf, 0x9d, 0x69, 0x99, 0xa0, 0xc5, 0x03, 0x7d, 0xfe, 0xc7, 0x61, 0x9a, 0x5d, 0xef, 0x21, 0x43, 0xc0, 0x02, 0x70, + 0xa6, 0xc8, 0xf9, 0xf9, 0xba, 0xaa, 0xa4, 0x18, 0x16, 0xf2, 0x26, 0x38, 0x3a, 0x54, 0x0f, 0x26, 0x43, 0xac, 0x1e, + 0x83, 0xbd, 0xff, 0x4a, 0xf2, 0x2c, 0xf9, 0xc8, 0x82, 0x47, 0x9b, 0x8c, 0x1d, 0xb5, 0x8e, 0xfd, 0x71, 0x1d, 0x1c, + 0x41, 0x5b, 0xf7, 0x8e, 0xf3, 0xfc, 0x70, 0x5f, 0x7d, 0x71, 0x74, 0xb8, 0x9f, 0x66, 0xd7, 0x47, 0x5e, 0x68, 0x06, + 0xad, 0xb7, 0x60, 0x1a, 0x02, 0xcf, 0x5a, 0x7a, 0x94, 0xe8, 0x53, 0x9d, 0xf0, 0xd0, 0x31, 0x9f, 0x80, 0xf5, 0xa0, + 0xda, 0x1b, 0x26, 0x28, 0xce, 0xca, 0x81, 0xd5, 0xda, 0x6e, 0x43, 0x6b, 0x07, 0xb6, 0xf4, 0x40, 0x92, 0x50, 0xcc, + 0x8e, 0x59, 0x28, 0x22, 0x3d, 0x90, 0xd0, 0x40, 0x39, 0xe5, 0x84, 0x26, 0x35, 0x05, 0xf6, 0xe3, 0x4d, 0xbc, 0x02, + 0x89, 0xbf, 0xfe, 0xe9, 0x71, 0xa4, 0x09, 0x44, 0x71, 0xf5, 0x16, 0x3a, 0xf1, 0x64, 0x9e, 0x8a, 0xce, 0x6b, 0x9c, + 0x2e, 0x10, 0x56, 0x62, 0x3d, 0x4a, 0x0e, 0x19, 0xe6, 0x04, 0xa2, 0x08, 0x59, 0x70, 0x8c, 0xb8, 0x36, 0x71, 0x7b, + 0xcc, 0xb8, 0xcc, 0x1a, 0x33, 0x14, 0xb5, 0xe7, 0xcb, 0xa0, 0xb6, 0xf5, 0xca, 0xfb, 0xa6, 0x0c, 0x64, 0xe8, 0x61, + 0x45, 0x5b, 0x74, 0x09, 0xbc, 0x6a, 0x3c, 0xc1, 0x2d, 0xa7, 0xe1, 0xbc, 0xa4, 0x72, 0xe1, 0xf6, 0x72, 0xa9, 0x8e, + 0xe2, 0x48, 0xd6, 0x0e, 0x40, 0x55, 0xcd, 0xfa, 0xd1, 0xa3, 0x8d, 0xc0, 0xcd, 0x5f, 0xb2, 0xa3, 0xe6, 0x3a, 0xa8, + 0xe2, 0xf3, 0xe1, 0x92, 0x83, 0xa7, 0x57, 0xb0, 0xf7, 0x5f, 0xe9, 0x79, 0x6e, 0x27, 0x5b, 0xad, 0xf4, 0x65, 0x2c, + 0xd2, 0x9c, 0x7f, 0x88, 0xcf, 0x7f, 0xf8, 0x3f, 0xcd, 0x3d, 0xed, 0x76, 0xdb, 0x36, 0xb2, 0xff, 0xfb, 0x14, 0x0c, + 0x93, 0x4d, 0xc9, 0x84, 0xa4, 0x49, 0xca, 0xb2, 0x15, 0xc9, 0xb2, 0xdb, 0xe6, 0x63, 0x37, 0xbd, 0x6e, 0xd3, 0x93, + 0xb8, 0xb9, 0xbb, 0xeb, 0xfa, 0x58, 0x94, 0x04, 0x49, 0xdc, 0x50, 0xa4, 0x0e, 0x49, 0xf9, 0xa3, 0x0a, 0xf7, 0x59, + 0xf6, 0x11, 0xee, 0x33, 0xf4, 0xc9, 0xee, 0x99, 0x19, 0x80, 0x04, 0xbf, 0x24, 0x65, 0x93, 0x76, 0xf7, 0xb4, 0x49, + 0x44, 0x10, 0x00, 0x31, 0x03, 0x60, 0x30, 0x33, 0x98, 0x0f, 0xac, 0xf3, 0x62, 0x1c, 0x3c, 0x87, 0x0a, 0x99, 0x7a, + 0xfa, 0x68, 0x43, 0xe4, 0xad, 0x89, 0x25, 0xc8, 0x68, 0x09, 0x54, 0xbf, 0x03, 0x1b, 0xdb, 0xf3, 0x43, 0x16, 0x53, + 0x6b, 0x1c, 0x2c, 0x91, 0x24, 0x8a, 0x23, 0x59, 0x1e, 0x19, 0x4f, 0xb9, 0x01, 0x6b, 0x53, 0xe1, 0x7b, 0x0c, 0xc6, + 0x15, 0x89, 0xfd, 0x26, 0xaf, 0x4c, 0x79, 0xb0, 0x2f, 0xb1, 0xdd, 0xdb, 0xe8, 0x56, 0x8c, 0x94, 0x23, 0x80, 0x42, + 0xc4, 0x9d, 0x3d, 0x1f, 0x9d, 0xc8, 0x6a, 0x59, 0xd4, 0x5d, 0x51, 0xbf, 0xf0, 0x2b, 0x53, 0x15, 0x6e, 0x22, 0xaa, + 0x42, 0x86, 0x13, 0xf5, 0xf4, 0xe4, 0x40, 0xae, 0x7d, 0x3a, 0xea, 0x9f, 0x4b, 0xc0, 0x61, 0xaf, 0x80, 0x84, 0x72, + 0x59, 0x8d, 0x83, 0x81, 0x1c, 0x5c, 0x05, 0x8f, 0x43, 0xcb, 0x43, 0x50, 0xb9, 0x48, 0xef, 0xe7, 0x73, 0x44, 0xa6, + 0x4f, 0xa2, 0xb7, 0x11, 0xff, 0xb7, 0x80, 0x19, 0x55, 0x49, 0x2c, 0x4c, 0xa2, 0x58, 0x05, 0x38, 0xaa, 0x89, 0x49, + 0x14, 0x29, 0x01, 0x10, 0x42, 0xd4, 0x78, 0x22, 0x03, 0x46, 0x0e, 0xaa, 0x4d, 0x25, 0xc0, 0x46, 0x7a, 0xf1, 0x43, + 0xe1, 0xc0, 0x54, 0xa8, 0x52, 0x3e, 0xc0, 0xf6, 0x04, 0x32, 0x97, 0x6f, 0x7c, 0xe3, 0x7f, 0x23, 0x63, 0xee, 0x19, + 0x4b, 0xcf, 0x78, 0x17, 0x5e, 0x65, 0x8d, 0xb3, 0x93, 0x27, 0x27, 0x32, 0xd8, 0x40, 0x83, 0x10, 0x27, 0x5c, 0xf0, + 0xe4, 0xe2, 0x98, 0x6f, 0xf1, 0x4b, 0xd9, 0x0b, 0x2f, 0x9e, 0x33, 0x91, 0x13, 0x48, 0xbc, 0x4d, 0x39, 0x56, 0x74, + 0x09, 0x2d, 0x10, 0xff, 0xe7, 0x01, 0xb7, 0x5d, 0xf1, 0xad, 0x49, 0x1a, 0x07, 0xff, 0xc3, 0xee, 0x41, 0x1c, 0x48, + 0xd2, 0x68, 0x05, 0x42, 0xa1, 0x37, 0xe7, 0x4a, 0x3e, 0x43, 0x63, 0xfb, 0x7d, 0xee, 0xe3, 0x47, 0x66, 0xe1, 0x92, + 0x04, 0x7e, 0xc1, 0x4a, 0xa3, 0xf9, 0x3c, 0x60, 0x9a, 0x2a, 0xb2, 0xd4, 0xa8, 0x46, 0xfe, 0x99, 0xb3, 0x07, 0xb6, + 0x08, 0x0d, 0xab, 0x67, 0x6d, 0x3b, 0x47, 0x40, 0xcc, 0xf2, 0xd8, 0x89, 0x24, 0x23, 0xe1, 0x25, 0xc0, 0x0d, 0xde, + 0xa3, 0xf1, 0x79, 0x29, 0x76, 0xa6, 0x39, 0x8d, 0xd6, 0xe3, 0x80, 0x99, 0xb8, 0xdc, 0xe1, 0x93, 0x9b, 0xf1, 0x7a, + 0x3c, 0x86, 0x74, 0x40, 0x0f, 0x6c, 0x03, 0x02, 0x1c, 0x45, 0x09, 0x2a, 0x1e, 0x32, 0x7d, 0x00, 0x40, 0x59, 0x69, + 0x75, 0xf8, 0x60, 0x94, 0x04, 0x3a, 0x45, 0xfa, 0x40, 0x0a, 0x4a, 0x86, 0xfa, 0xa6, 0x1d, 0xaa, 0xef, 0x60, 0xf1, + 0x25, 0xea, 0xa0, 0x81, 0x73, 0x18, 0x5e, 0xaa, 0xef, 0x10, 0xc3, 0x98, 0x24, 0xfb, 0x39, 0xad, 0x5d, 0xd5, 0x50, + 0xc9, 0xb6, 0x62, 0x8d, 0xe9, 0x32, 0xe0, 0x6e, 0xe1, 0x85, 0xef, 0xcd, 0xc3, 0x28, 0x49, 0xfd, 0x89, 0x7a, 0x35, + 0x78, 0xed, 0x6b, 0x97, 0xcb, 0x54, 0xd3, 0xaf, 0x8c, 0x3f, 0xcb, 0x89, 0x76, 0x04, 0x29, 0xc4, 0x3c, 0x3b, 0x2d, + 0x75, 0xe4, 0xdd, 0xb3, 0xad, 0x9e, 0x20, 0xb9, 0x58, 0xe7, 0xcf, 0x43, 0xa8, 0x55, 0x49, 0xd9, 0x83, 0xb9, 0xc7, + 0x20, 0x65, 0xcf, 0x9f, 0xf5, 0x01, 0x09, 0xc3, 0xcf, 0xd7, 0x1b, 0x3c, 0xfa, 0xd3, 0xe2, 0x74, 0xc5, 0x28, 0xd3, + 0xc2, 0x35, 0x8b, 0x9e, 0x1f, 0xc8, 0x66, 0xc5, 0xa5, 0x73, 0x7a, 0xf4, 0x6d, 0x99, 0x8f, 0x80, 0xf3, 0x1e, 0x6c, + 0x7a, 0xc2, 0x28, 0x55, 0x20, 0x74, 0x12, 0x7c, 0x70, 0x54, 0x35, 0x43, 0xe4, 0xbd, 0x6a, 0x7a, 0xc6, 0xa9, 0xc0, + 0x77, 0x78, 0x58, 0x6a, 0x3c, 0x80, 0x5e, 0x29, 0x46, 0x0a, 0xdd, 0x94, 0x87, 0x30, 0x73, 0x25, 0xee, 0x5f, 0xa2, + 0xe9, 0x3b, 0xcf, 0x6a, 0x4d, 0xc8, 0x40, 0x22, 0x6f, 0xa4, 0xc6, 0x45, 0x59, 0xc1, 0x18, 0x55, 0x36, 0x13, 0x9a, + 0x16, 0x09, 0x9e, 0x27, 0x05, 0x4b, 0x44, 0xa4, 0xf1, 0x40, 0x8b, 0xf8, 0xb1, 0x3e, 0xca, 0xae, 0x45, 0x72, 0x6e, + 0x91, 0x1a, 0xdb, 0x88, 0xe4, 0xbc, 0x4b, 0x7e, 0xb8, 0x5a, 0xa7, 0x18, 0xcc, 0x19, 0x06, 0xc0, 0x32, 0x55, 0x41, + 0x3e, 0x18, 0xc8, 0x73, 0xc1, 0xd2, 0x67, 0xaa, 0xe2, 0x4f, 0xeb, 0x65, 0x5c, 0x40, 0x01, 0xaa, 0x85, 0x84, 0x1d, + 0x55, 0xa1, 0xf0, 0x18, 0x73, 0x30, 0x26, 0x46, 0x91, 0x09, 0x41, 0x9b, 0xe0, 0x95, 0x61, 0x03, 0x49, 0x98, 0x50, + 0x3f, 0x03, 0x2d, 0x68, 0x04, 0x16, 0x02, 0xbc, 0x96, 0xc0, 0x1c, 0x3d, 0xda, 0x84, 0xd9, 0xd9, 0xa3, 0x4d, 0x92, + 0x0d, 0x1f, 0x6d, 0xbc, 0xdc, 0x1a, 0x45, 0xbd, 0x50, 0xc9, 0x14, 0x65, 0x84, 0x68, 0x18, 0x65, 0xd7, 0x85, 0x6f, + 0x58, 0x01, 0x2f, 0x2c, 0x32, 0x2a, 0x57, 0xd0, 0x38, 0x64, 0xc8, 0x4d, 0x40, 0x56, 0xb1, 0xbf, 0xf4, 0xe2, 0x7b, + 0xb2, 0x18, 0x31, 0x64, 0xb3, 0x12, 0x5d, 0x55, 0x88, 0xc2, 0x13, 0x02, 0x88, 0xd8, 0xab, 0xca, 0x37, 0x79, 0x99, + 0xd0, 0x4d, 0xe4, 0xd7, 0xe6, 0xf0, 0xad, 0x6b, 0xf5, 0x29, 0xb3, 0xa6, 0x2c, 0xf5, 0xfc, 0x80, 0x9a, 0x0c, 0xb4, + 0xa4, 0x05, 0xbc, 0xa4, 0x0c, 0x5e, 0x58, 0x5e, 0x3f, 0x08, 0x0c, 0xd1, 0x7e, 0x1a, 0x37, 0x42, 0x86, 0x79, 0xd2, + 0x9a, 0x67, 0x94, 0xde, 0xfd, 0xa1, 0xd3, 0xc1, 0x60, 0x3a, 0x42, 0x98, 0x0e, 0x16, 0x4e, 0xa2, 0x29, 0xfb, 0xf9, + 0xed, 0xeb, 0x3c, 0x31, 0x1b, 0xe8, 0x18, 0x47, 0x7c, 0x61, 0x26, 0xc8, 0x38, 0xc4, 0xc8, 0x34, 0x50, 0x0a, 0x35, + 0x25, 0x5f, 0x42, 0x71, 0xa6, 0x2a, 0x67, 0x34, 0x76, 0x36, 0xa5, 0x51, 0x0f, 0x23, 0x6c, 0x15, 0x67, 0x27, 0x07, + 0x54, 0x9b, 0x8e, 0x39, 0xaa, 0x04, 0x68, 0x88, 0x01, 0xc2, 0x02, 0x0b, 0x90, 0x43, 0x76, 0xe8, 0x14, 0x02, 0x88, + 0xb5, 0xc4, 0x9b, 0x1c, 0xe7, 0xac, 0xcc, 0xa3, 0x60, 0x2b, 0xf5, 0xf4, 0x04, 0xb3, 0xc2, 0xc1, 0x41, 0x0d, 0x71, + 0x64, 0x4e, 0x0e, 0xe8, 0x51, 0xa9, 0xec, 0x88, 0xa2, 0x13, 0x21, 0x86, 0xf7, 0x79, 0x07, 0x9f, 0xb4, 0x55, 0x92, + 0x94, 0xad, 0xa0, 0xd4, 0xcb, 0x54, 0x65, 0xc9, 0x79, 0x22, 0x1e, 0xb0, 0x0a, 0xa2, 0x59, 0xd8, 0xb0, 0x77, 0x55, + 0x65, 0xe9, 0xdd, 0x21, 0xe4, 0xe2, 0x8d, 0x77, 0xa7, 0x39, 0xfc, 0x55, 0xb1, 0xd7, 0x92, 0xf2, 0x5e, 0x9b, 0xf0, + 0xc9, 0x05, 0x57, 0x15, 0xc1, 0x0b, 0x6b, 0x0b, 0x34, 0x01, 0x68, 0x98, 0xdc, 0x85, 0x98, 0xdc, 0x69, 0xcb, 0xe4, + 0x4e, 0xb7, 0x4c, 0x6e, 0xc0, 0x27, 0x52, 0xc9, 0x51, 0x17, 0xa3, 0xfb, 0x61, 0x8e, 0x3c, 0xce, 0x61, 0xf4, 0xf9, + 0x3e, 0x43, 0x3c, 0x99, 0x49, 0x00, 0xe6, 0x77, 0x2d, 0xb8, 0x6a, 0xc2, 0x8b, 0x84, 0x88, 0x3a, 0xe0, 0xf9, 0xae, + 0x13, 0x70, 0x43, 0x96, 0x57, 0x2d, 0xa8, 0xc2, 0x0b, 0xab, 0x94, 0x32, 0xd8, 0x6b, 0x8b, 0x16, 0x48, 0x17, 0x5b, + 0x20, 0x9d, 0x94, 0xb6, 0x2e, 0x07, 0x9b, 0x36, 0xa1, 0x0c, 0x14, 0xac, 0x41, 0x30, 0x49, 0xc6, 0x25, 0x53, 0x5e, + 0x87, 0xed, 0x34, 0x56, 0x5a, 0x51, 0x2b, 0x2f, 0x49, 0x6e, 0xa3, 0x18, 0xee, 0xf4, 0xa0, 0x9b, 0x4f, 0x5b, 0x52, + 0x4b, 0x3f, 0xe4, 0xe1, 0x82, 0x5a, 0x17, 0x53, 0xf1, 0x5e, 0x5e, 0x52, 0x6e, 0xb7, 0x4b, 0x35, 0x56, 0x5e, 0x9a, + 0xb2, 0x18, 0x91, 0xee, 0x41, 0x5c, 0xf9, 0xff, 0x92, 0x65, 0xd6, 0x40, 0x43, 0x02, 0x89, 0xaa, 0x23, 0x85, 0x5e, + 0x01, 0x53, 0x15, 0x8b, 0x83, 0x58, 0x0a, 0x3d, 0x18, 0xe7, 0x88, 0xff, 0x11, 0xb7, 0xab, 0x16, 0x4b, 0xce, 0x71, + 0xce, 0x91, 0x6e, 0xad, 0xbc, 0xe9, 0x3b, 0xb8, 0x3a, 0xd6, 0x5c, 0x03, 0xcc, 0xc0, 0xe5, 0x40, 0x83, 0x31, 0x71, + 0x79, 0x93, 0x82, 0x48, 0x22, 0x95, 0xe4, 0x46, 0x76, 0xe0, 0x9f, 0xeb, 0x99, 0xb3, 0xab, 0x8d, 0x9b, 0x1d, 0xcc, + 0x7d, 0xbd, 0x46, 0x35, 0x81, 0xb4, 0x05, 0xc3, 0xd3, 0x5c, 0x13, 0x1b, 0x18, 0xce, 0x91, 0x0e, 0x77, 0x0b, 0x97, + 0x90, 0x31, 0xd7, 0x16, 0xf2, 0xef, 0x28, 0x86, 0x53, 0xeb, 0xd2, 0xbe, 0xca, 0x1e, 0xcf, 0xf1, 0x97, 0x73, 0x95, + 0x3d, 0x1e, 0xe3, 0x2f, 0xf7, 0x0a, 0x73, 0x23, 0x36, 0x08, 0xfe, 0x12, 0xcc, 0xea, 0x69, 0x69, 0x3d, 0x91, 0x85, + 0xe3, 0x27, 0x2c, 0x1b, 0x3e, 0xc1, 0x0f, 0x1f, 0x6d, 0x12, 0xf0, 0xe9, 0x95, 0x61, 0x08, 0xad, 0x58, 0xcf, 0x1a, + 0xcb, 0xe7, 0x2d, 0xe5, 0x63, 0xfd, 0x0f, 0x3e, 0xf8, 0x71, 0x95, 0x44, 0xc5, 0x99, 0x52, 0x56, 0x5b, 0x5c, 0x8f, + 0xfd, 0xd0, 0x8b, 0xef, 0xaf, 0x49, 0xae, 0xd0, 0x04, 0xd3, 0x9e, 0xab, 0x63, 0x88, 0xbb, 0x2c, 0x5f, 0xa8, 0xa6, + 0xd2, 0x65, 0xc1, 0x3d, 0x3f, 0xe8, 0x87, 0x7f, 0x8d, 0x25, 0xb6, 0xad, 0x24, 0x79, 0xf2, 0x09, 0x29, 0x7d, 0xe8, + 0xfa, 0xd1, 0x46, 0x63, 0xf5, 0x6e, 0x2a, 0xd0, 0x56, 0xf8, 0x42, 0x98, 0x1e, 0x94, 0x62, 0x97, 0x53, 0xbf, 0x8f, + 0x37, 0xa6, 0xe3, 0xe8, 0xce, 0x7c, 0xb4, 0x49, 0xcf, 0xd4, 0xa5, 0x17, 0x7f, 0x60, 0x53, 0x73, 0xe2, 0xc7, 0x93, + 0x80, 0xa9, 0x7d, 0x75, 0x1c, 0x78, 0xe1, 0x07, 0xfe, 0x68, 0x46, 0xeb, 0x14, 0x6d, 0x20, 0x76, 0x0a, 0xbd, 0x02, + 0x27, 0xa4, 0x5e, 0x45, 0x66, 0xb5, 0x01, 0x0b, 0xca, 0xf3, 0x5c, 0x41, 0x56, 0x30, 0x8a, 0x45, 0x2d, 0x03, 0x4c, + 0x78, 0xc1, 0x2c, 0x03, 0x7c, 0xa2, 0x0d, 0x15, 0xe7, 0x4b, 0x35, 0x64, 0x50, 0x49, 0xb1, 0x9c, 0x27, 0xf5, 0xbc, + 0xc6, 0x1e, 0xfe, 0xfd, 0xcf, 0x51, 0xba, 0xf5, 0xfd, 0x3f, 0x97, 0xf7, 0xf2, 0x79, 0x10, 0x42, 0xa9, 0x49, 0xbe, + 0x38, 0x9f, 0xf0, 0x71, 0xce, 0x60, 0xb6, 0x7f, 0x5a, 0x6e, 0xec, 0x25, 0xc9, 0x7a, 0xc9, 0xa6, 0x74, 0xf7, 0x7c, + 0x56, 0x0c, 0xaa, 0x2c, 0x59, 0xc8, 0x03, 0xfb, 0x65, 0xed, 0x1e, 0x1f, 0x3e, 0x07, 0x9b, 0x18, 0x60, 0x28, 0xa3, + 0xd9, 0x4c, 0x2d, 0x84, 0xfb, 0x1d, 0xcd, 0x9c, 0xc3, 0x5f, 0xd6, 0xaf, 0x5e, 0xda, 0xaf, 0xf2, 0xc6, 0x21, 0x30, + 0xc6, 0xe2, 0x82, 0x9f, 0xf3, 0xc5, 0xd2, 0x78, 0x05, 0x44, 0x33, 0x2f, 0x6c, 0x07, 0xe7, 0xb2, 0xb4, 0xc4, 0x57, + 0x8c, 0x4d, 0x81, 0xe1, 0x36, 0x6a, 0xa5, 0xd7, 0x01, 0xbb, 0x61, 0xb9, 0xf1, 0x40, 0xfd, 0x63, 0x0d, 0x2d, 0x30, + 0xba, 0x21, 0x37, 0x4a, 0xe0, 0x5c, 0x9d, 0x04, 0xd2, 0x08, 0x61, 0xe0, 0x90, 0xcb, 0x5b, 0xac, 0xb2, 0xa5, 0x46, + 0x86, 0x2a, 0x0d, 0xa0, 0x75, 0x64, 0x67, 0x2d, 0xe5, 0x7d, 0x4c, 0x6d, 0xde, 0x3c, 0x36, 0xc3, 0xd1, 0xfb, 0x10, + 0x0d, 0x9e, 0xe3, 0x29, 0x80, 0x9d, 0xa7, 0x15, 0x7a, 0x90, 0x36, 0x8c, 0x35, 0x69, 0xc7, 0x54, 0x52, 0xbb, 0x08, + 0x7b, 0x5a, 0x34, 0x2c, 0x17, 0x0a, 0xa8, 0xc6, 0xb9, 0x51, 0xca, 0x90, 0x8f, 0x31, 0x65, 0x70, 0xc8, 0x92, 0xa4, + 0x15, 0x61, 0xf9, 0xa4, 0x1b, 0x6a, 0x51, 0xbb, 0x8c, 0x8f, 0xa2, 0xdc, 0xb0, 0x0d, 0x60, 0x09, 0x10, 0xc0, 0xea, + 0xb7, 0xf0, 0x78, 0xb9, 0x5e, 0x72, 0x8b, 0xa8, 0x78, 0x3e, 0x56, 0xb9, 0xb5, 0x4a, 0xdb, 0xfb, 0x5b, 0x95, 0x0f, + 0xaa, 0x74, 0x4c, 0x37, 0x0e, 0x4d, 0x2b, 0x91, 0xde, 0x9a, 0x9e, 0x08, 0x3b, 0x10, 0x63, 0xaa, 0xd0, 0x57, 0x36, + 0x9b, 0xb1, 0x49, 0x9a, 0xe8, 0x42, 0x6b, 0x94, 0xc7, 0x27, 0x06, 0xbf, 0xb4, 0x07, 0x43, 0xf5, 0x47, 0x88, 0xd2, + 0x20, 0xc2, 0x78, 0xf1, 0x01, 0x09, 0x99, 0xa9, 0x19, 0x4d, 0xd4, 0x63, 0x19, 0x45, 0xfc, 0x2b, 0xa0, 0x38, 0x6e, + 0x28, 0xc7, 0xa1, 0xf1, 0xf3, 0xa7, 0x58, 0x17, 0x51, 0x6e, 0x37, 0xb5, 0x9d, 0x14, 0x6d, 0xdb, 0xbe, 0x1b, 0xe7, + 0x55, 0xd7, 0xb1, 0x33, 0xd5, 0x00, 0xef, 0xc0, 0x0f, 0xfb, 0x6e, 0x7a, 0x6c, 0xd5, 0x81, 0x56, 0xeb, 0xf0, 0x53, + 0xda, 0xb9, 0xce, 0x33, 0x47, 0x35, 0xc8, 0x28, 0x53, 0xa2, 0x6d, 0x93, 0xe8, 0x86, 0xc5, 0x9f, 0x0d, 0x4a, 0xb9, + 0xf3, 0xfd, 0xc6, 0x73, 0xe4, 0xd8, 0x40, 0x84, 0xd3, 0x68, 0xf5, 0x09, 0x20, 0x74, 0x54, 0x43, 0x9d, 0x04, 0x51, + 0xc2, 0x64, 0x18, 0x48, 0x09, 0xf2, 0x99, 0x40, 0xfc, 0xf4, 0xf6, 0xe5, 0xbb, 0x77, 0xaa, 0x81, 0xb9, 0x66, 0x13, + 0xb9, 0x77, 0xbe, 0xa0, 0x76, 0x50, 0xff, 0xc6, 0x75, 0x47, 0x27, 0x0c, 0x09, 0xb5, 0xe5, 0x35, 0x47, 0x65, 0xb5, + 0x25, 0xc7, 0x4f, 0x1e, 0xfe, 0x65, 0x92, 0x44, 0xf7, 0x82, 0xab, 0x81, 0x36, 0x6c, 0x3f, 0xde, 0x4a, 0x25, 0x4b, + 0x3f, 0xbc, 0x6e, 0x28, 0xf5, 0xee, 0x1a, 0x4a, 0x41, 0x94, 0xab, 0xd1, 0xaa, 0x75, 0xb4, 0x94, 0x58, 0x03, 0x48, + 0x15, 0xbe, 0x0b, 0x5d, 0x92, 0x3c, 0xf5, 0x19, 0x83, 0xe6, 0xb9, 0x02, 0xaa, 0xa3, 0x6e, 0x28, 0xe6, 0x42, 0x50, + 0x8e, 0xdb, 0x49, 0x00, 0x26, 0xa5, 0x4c, 0xbe, 0xc5, 0x2b, 0xb3, 0x8d, 0xdc, 0x20, 0x7c, 0x58, 0xe1, 0xd0, 0xa9, + 0x19, 0xdd, 0x7c, 0x70, 0xfa, 0xbe, 0xf2, 0xa6, 0x60, 0xa7, 0x69, 0x8e, 0xa3, 0x34, 0x8d, 0x96, 0x7d, 0xc7, 0x5e, + 0xdd, 0xa9, 0xca, 0x40, 0x28, 0x1e, 0xb8, 0x19, 0x69, 0xff, 0xb7, 0x7f, 0x55, 0x48, 0x2e, 0x95, 0x5f, 0xa7, 0x6c, + 0xb9, 0x62, 0xb1, 0x97, 0xae, 0x63, 0x96, 0x29, 0xbf, 0xfd, 0xdf, 0xf3, 0x8a, 0x90, 0x3d, 0x90, 0xdb, 0x10, 0x7b, + 0x2d, 0x37, 0xb9, 0x0e, 0xa2, 0xdb, 0x07, 0x85, 0xc3, 0xc8, 0x8e, 0xca, 0x0b, 0x7f, 0xbe, 0xc8, 0x6b, 0x9f, 0xa5, + 0x5b, 0x60, 0x13, 0xa3, 0x27, 0x6d, 0xbb, 0x72, 0x1e, 0xdd, 0xf6, 0x7f, 0xfb, 0x57, 0xae, 0x3c, 0xd9, 0xb9, 0xea, + 0x9a, 0x07, 0x5a, 0x9e, 0xd1, 0xe6, 0x3a, 0xb5, 0x29, 0x86, 0xf7, 0xb5, 0x09, 0xae, 0x15, 0xd2, 0xaa, 0xac, 0x5f, + 0x6d, 0x6d, 0x81, 0xe9, 0x2f, 0xfe, 0x7c, 0xf1, 0xb9, 0x40, 0x01, 0x42, 0x77, 0x42, 0x05, 0x95, 0xbe, 0x00, 0x58, + 0xa3, 0xfe, 0xfe, 0x13, 0xf6, 0x99, 0x70, 0xed, 0x02, 0xe9, 0x4b, 0x40, 0xc3, 0xb5, 0xa8, 0xcf, 0x47, 0xa3, 0x3c, + 0xd7, 0xa2, 0xdc, 0x1e, 0x5c, 0x5e, 0xce, 0x6a, 0x25, 0xfc, 0xa8, 0xef, 0xdb, 0x3a, 0xc5, 0xa2, 0xd8, 0x03, 0x21, + 0x68, 0xbc, 0xd9, 0x80, 0x8e, 0x76, 0x7a, 0x4d, 0x3e, 0x18, 0xb5, 0x6f, 0xd7, 0x88, 0x35, 0x94, 0x62, 0x9e, 0xbe, + 0xfc, 0x4e, 0xce, 0x68, 0x1e, 0xce, 0x6d, 0xec, 0xad, 0x48, 0x61, 0xaf, 0xe0, 0x7d, 0x04, 0x28, 0x40, 0x84, 0x44, + 0x8b, 0x69, 0x80, 0xde, 0xb4, 0x99, 0x4e, 0xfe, 0xb4, 0xdb, 0x74, 0xf2, 0x62, 0x2f, 0xd3, 0xc9, 0x9f, 0xbe, 0xb8, + 0xe9, 0xe4, 0x1b, 0xd9, 0x74, 0x12, 0xe6, 0xf2, 0x25, 0xdb, 0xcb, 0xa0, 0x51, 0x98, 0x05, 0x45, 0xb7, 0xc9, 0xd0, + 0xe1, 0x7c, 0x78, 0x32, 0x59, 0x30, 0x50, 0x6c, 0x70, 0xac, 0x07, 0xd1, 0x7c, 0xbb, 0xdd, 0xe1, 0x97, 0xb2, 0x3a, + 0x0c, 0xa2, 0xb9, 0x2a, 0x05, 0x42, 0x0e, 0x79, 0x20, 0xe4, 0x22, 0xb8, 0x19, 0x59, 0xf8, 0xd9, 0x86, 0x08, 0x85, + 0x66, 0x1e, 0xea, 0x52, 0xb2, 0xf7, 0xdc, 0xa8, 0xd3, 0x15, 0x36, 0x80, 0x7d, 0x15, 0xc2, 0xa2, 0xe4, 0x0d, 0xdd, + 0xa7, 0x22, 0xe4, 0x8b, 0xdc, 0x43, 0x6e, 0x3c, 0x4f, 0xe1, 0x53, 0x36, 0xea, 0x2f, 0x77, 0xce, 0x77, 0x97, 0xce, + 0xa0, 0xe3, 0x40, 0xcc, 0x02, 0x10, 0x8b, 0xb1, 0xc0, 0x1e, 0x74, 0x3a, 0x50, 0x70, 0x2b, 0x15, 0xb8, 0x50, 0xe0, + 0x4b, 0x05, 0x5d, 0x28, 0x98, 0x48, 0x05, 0x47, 0x50, 0x30, 0x95, 0x0a, 0x8e, 0xa1, 0xe0, 0x46, 0xcd, 0x2e, 0xc3, + 0x7c, 0xb8, 0xc7, 0xfa, 0x95, 0x41, 0x92, 0x90, 0x28, 0x3b, 0x36, 0x1c, 0xb0, 0xe3, 0xf3, 0xe6, 0xfd, 0xc8, 0x20, + 0x95, 0x68, 0x3f, 0x36, 0x6e, 0x17, 0x8c, 0xe2, 0xa7, 0xbf, 0xc0, 0x83, 0xd2, 0x4a, 0x23, 0x70, 0x27, 0x10, 0x71, + 0x49, 0x04, 0x1e, 0x14, 0x55, 0x07, 0x2d, 0xd7, 0x20, 0x9f, 0xb9, 0xb2, 0x01, 0x20, 0xce, 0x65, 0xf1, 0x8e, 0x3e, + 0x67, 0xe6, 0x4b, 0xa0, 0x30, 0xab, 0xd1, 0x64, 0x55, 0xea, 0x97, 0x30, 0x82, 0x78, 0xc1, 0xc6, 0xeb, 0xb9, 0x72, + 0x1e, 0xcd, 0x77, 0x1a, 0x3c, 0xc8, 0xaf, 0x60, 0x94, 0x2a, 0xdd, 0x19, 0x99, 0x62, 0x59, 0xf2, 0x6f, 0xd1, 0x63, + 0x56, 0xae, 0x9f, 0xc2, 0xd8, 0x94, 0x94, 0x28, 0x0e, 0x7c, 0x07, 0x70, 0x24, 0x59, 0x1c, 0x9c, 0x03, 0x9e, 0xa5, + 0xe7, 0x0b, 0x4f, 0x1a, 0xcf, 0xe9, 0x0f, 0x2c, 0x49, 0xbc, 0xb9, 0xa8, 0x5f, 0x1f, 0x27, 0x58, 0x26, 0xe5, 0x42, + 0x23, 0x22, 0x10, 0xd4, 0x8f, 0x7e, 0xcd, 0x50, 0x24, 0x8e, 0x6e, 0x15, 0x30, 0x71, 0x82, 0x05, 0x55, 0x58, 0x55, + 0xf8, 0x16, 0x4c, 0x61, 0xd9, 0xfe, 0x01, 0x36, 0xff, 0x0d, 0x0b, 0xaa, 0x85, 0xa9, 0x37, 0xaf, 0x16, 0xd1, 0x3a, + 0xc8, 0xe4, 0xb1, 0xe5, 0xe6, 0x07, 0xa5, 0xc2, 0xcf, 0xb9, 0x4f, 0x0f, 0xa2, 0xf9, 0xef, 0x7a, 0x99, 0xbe, 0xc5, + 0x08, 0xe2, 0x5d, 0x68, 0x84, 0xe9, 0xc8, 0x42, 0x1c, 0x2b, 0x16, 0xa0, 0xb0, 0x1f, 0xa6, 0x0b, 0x13, 0x3d, 0x2e, + 0x35, 0x37, 0xd4, 0x0d, 0x0b, 0xe7, 0x76, 0x53, 0xf5, 0x33, 0xef, 0xc7, 0xf3, 0xb1, 0xa7, 0x39, 0xee, 0xb1, 0x21, + 0xfe, 0x58, 0x76, 0x57, 0xcf, 0xb0, 0x07, 0x65, 0xea, 0xdf, 0x6c, 0x66, 0x51, 0x98, 0x9a, 0x33, 0x6f, 0xe9, 0x07, + 0xf7, 0xfd, 0x65, 0x14, 0x46, 0xc9, 0xca, 0x9b, 0xb0, 0x41, 0xa1, 0x05, 0x18, 0x60, 0x04, 0x13, 0xee, 0x44, 0xeb, + 0x58, 0x6e, 0xcc, 0x96, 0xd4, 0x3a, 0x0f, 0x50, 0x32, 0x0b, 0xd8, 0x5d, 0xc6, 0x3f, 0x5f, 0xaa, 0x4c, 0x55, 0x71, + 0xc9, 0x51, 0x0b, 0x60, 0xa3, 0x79, 0xf4, 0x13, 0x88, 0xf9, 0x35, 0xe0, 0xbc, 0x68, 0xdf, 0x72, 0xbb, 0x31, 0x5b, + 0x2a, 0x56, 0xb7, 0xb5, 0xf3, 0x38, 0xba, 0x3d, 0x85, 0xd1, 0x62, 0x63, 0x33, 0x61, 0xc1, 0x0c, 0xdf, 0x98, 0xe8, + 0x70, 0x25, 0xfa, 0x31, 0x51, 0x7b, 0x00, 0xbd, 0xb1, 0xe5, 0x00, 0x5e, 0xf7, 0x5d, 0xc5, 0x1e, 0x2c, 0xfd, 0xd0, + 0x24, 0x70, 0x8e, 0xed, 0x95, 0xd4, 0x97, 0x8c, 0x3f, 0x7d, 0x83, 0xd5, 0x1d, 0xc5, 0x1e, 0x80, 0x84, 0x39, 0x0b, + 0xa2, 0xdb, 0xfe, 0xc2, 0x9f, 0x4e, 0x59, 0x38, 0xc0, 0x31, 0xe7, 0x85, 0x2c, 0x08, 0xfc, 0x55, 0xe2, 0x27, 0x83, + 0xa5, 0x77, 0xc7, 0x7b, 0x3d, 0x6c, 0xeb, 0xb5, 0xc3, 0x7b, 0xed, 0xec, 0xdd, 0xab, 0xd4, 0x0d, 0x38, 0x77, 0x51, + 0x3f, 0x7c, 0x68, 0x5d, 0xc5, 0xae, 0xc0, 0xb9, 0x77, 0xaf, 0xab, 0x98, 0x6d, 0x96, 0x5e, 0x3c, 0xf7, 0xc3, 0xbe, + 0x9d, 0x59, 0x37, 0x1b, 0x5a, 0x18, 0x0f, 0x7b, 0xbd, 0x5e, 0x66, 0x4d, 0xc5, 0x93, 0x3d, 0x9d, 0x66, 0xd6, 0x44, + 0x3c, 0xcd, 0x66, 0xb6, 0x3d, 0x9b, 0x65, 0x96, 0x2f, 0x0a, 0x3a, 0xee, 0x64, 0xda, 0x71, 0x33, 0xeb, 0x56, 0xaa, + 0x91, 0x59, 0x8c, 0x3f, 0xc5, 0x6c, 0x3a, 0xc0, 0x85, 0xc4, 0x8d, 0x37, 0x8f, 0x6d, 0x3b, 0x43, 0x0a, 0x70, 0x59, + 0xa2, 0x4d, 0xa8, 0xa0, 0xba, 0xda, 0xec, 0x5d, 0x53, 0x29, 0x3e, 0x37, 0x99, 0x34, 0xd6, 0x9b, 0x7a, 0xf1, 0x87, + 0x2b, 0x45, 0x82, 0xc2, 0xf3, 0xa8, 0xda, 0x46, 0xa0, 0xc1, 0xbc, 0xeb, 0x43, 0x24, 0xbb, 0xc1, 0x38, 0x8a, 0x61, + 0xcf, 0xc6, 0xde, 0xd4, 0x5f, 0x27, 0x7d, 0xc7, 0x5d, 0xdd, 0x89, 0x22, 0xbe, 0xd6, 0x8b, 0x02, 0xdc, 0x7b, 0xfd, + 0x24, 0x0a, 0xfc, 0xa9, 0x28, 0x6a, 0xdb, 0x4b, 0x8e, 0xab, 0x0f, 0x30, 0x8e, 0x83, 0x8f, 0xd1, 0x48, 0xbc, 0x20, + 0x50, 0xac, 0x4e, 0xa2, 0x30, 0x2f, 0x41, 0xa5, 0xb8, 0x62, 0x27, 0x84, 0x17, 0x8c, 0xd9, 0xe0, 0x1c, 0xae, 0xee, + 0xf2, 0x35, 0xef, 0x1c, 0xad, 0xee, 0xb2, 0x6f, 0x96, 0x6c, 0xea, 0x7b, 0x8a, 0x56, 0xac, 0x26, 0xc7, 0x06, 0xc5, + 0xb9, 0xbe, 0x69, 0x59, 0xa6, 0x62, 0x5b, 0x40, 0xc4, 0xcf, 0x07, 0xfe, 0x72, 0x15, 0xc5, 0xa9, 0x17, 0xa6, 0x59, + 0x36, 0xba, 0xca, 0xb2, 0xc1, 0x85, 0xaf, 0x5d, 0xfe, 0x4d, 0xa3, 0x73, 0x9a, 0x2e, 0x9a, 0x32, 0xfd, 0xca, 0x78, + 0xc9, 0x64, 0x33, 0x17, 0x38, 0xc6, 0xd0, 0xc4, 0x45, 0xae, 0x4c, 0xa7, 0x64, 0xbd, 0x32, 0x21, 0x39, 0xaf, 0x4e, + 0x56, 0x33, 0xe5, 0x2a, 0x78, 0x02, 0x41, 0x85, 0x97, 0x6c, 0x78, 0x21, 0xd9, 0xcc, 0x00, 0xb3, 0x82, 0x95, 0xc9, + 0xdd, 0xe6, 0x51, 0x1b, 0xcf, 0xf8, 0xed, 0x6e, 0x9e, 0xf1, 0xef, 0xe9, 0x3e, 0x3c, 0xe3, 0xb7, 0x5f, 0x9c, 0x67, + 0x7c, 0x54, 0x77, 0xb7, 0x79, 0x1d, 0x0d, 0xd5, 0xfc, 0x5a, 0x04, 0x8e, 0xa6, 0x98, 0x02, 0x59, 0xbd, 0x4e, 0xff, + 0x5d, 0xf7, 0x18, 0xd1, 0x1b, 0xa5, 0x66, 0xa4, 0x93, 0x1b, 0x94, 0xc8, 0x6f, 0xc2, 0xe1, 0x5f, 0x63, 0xf9, 0x79, + 0x36, 0x1b, 0xbe, 0x88, 0xa4, 0x82, 0xfc, 0x89, 0x5b, 0x8c, 0x94, 0x82, 0x8e, 0xd0, 0x1b, 0x61, 0x10, 0x8a, 0x69, + 0x59, 0x20, 0x66, 0x01, 0x99, 0xb5, 0x4f, 0x73, 0x5b, 0xb9, 0x41, 0x79, 0x08, 0x5a, 0x6e, 0x7d, 0x2a, 0x3c, 0xd3, + 0x6a, 0xfa, 0xcf, 0x39, 0x4b, 0xb9, 0x2b, 0xf9, 0x77, 0xf7, 0xaf, 0xa7, 0xda, 0xeb, 0x48, 0xcf, 0xfc, 0xe4, 0x4d, + 0xd5, 0x2f, 0x8c, 0x5f, 0x58, 0x0d, 0x65, 0x70, 0x32, 0x6e, 0xef, 0x26, 0xe7, 0x5d, 0x87, 0xd7, 0xd4, 0xfc, 0xac, + 0x04, 0x69, 0x5f, 0x6e, 0xc8, 0xf3, 0xbf, 0xd5, 0x0e, 0x63, 0xee, 0x84, 0xb3, 0xe1, 0x1c, 0x20, 0xa6, 0xb4, 0x43, + 0x77, 0xfa, 0x29, 0x35, 0xf7, 0xa7, 0x59, 0xa6, 0x0f, 0x04, 0x22, 0xa4, 0x83, 0x96, 0xed, 0x62, 0xe2, 0x92, 0x42, + 0x1e, 0xe3, 0xd7, 0x9a, 0x74, 0x67, 0xf9, 0x1a, 0xac, 0x00, 0xf8, 0x0d, 0x27, 0xc7, 0x99, 0xaa, 0x10, 0xfa, 0xc8, + 0x3a, 0x44, 0x02, 0x08, 0xae, 0xad, 0x73, 0xfc, 0x8b, 0x57, 0xa2, 0xa0, 0x6e, 0x71, 0x4a, 0xc8, 0x41, 0x33, 0x06, + 0x08, 0x7e, 0x21, 0x94, 0x35, 0x44, 0x76, 0x78, 0x1d, 0x7c, 0xc8, 0xd4, 0x9c, 0xf7, 0xc3, 0xe5, 0x77, 0x7a, 0x72, + 0x00, 0x0d, 0x4e, 0x2b, 0x8a, 0x98, 0x1d, 0xf6, 0x94, 0xc0, 0x4a, 0x24, 0xb7, 0x86, 0x95, 0xdc, 0x2a, 0x4f, 0x36, + 0x22, 0x70, 0x4c, 0xea, 0xad, 0x4c, 0x90, 0xfe, 0x91, 0xf6, 0x72, 0x8a, 0x27, 0xc5, 0xa8, 0x19, 0xac, 0x13, 0xa0, + 0x8d, 0x28, 0x88, 0x22, 0xfd, 0x19, 0x4c, 0xd6, 0x71, 0x12, 0xc5, 0xfd, 0x55, 0xe4, 0x87, 0x29, 0x8b, 0x33, 0x44, + 0xd5, 0x25, 0xe2, 0x47, 0xa0, 0xe7, 0x6a, 0x13, 0xad, 0xbc, 0x89, 0x9f, 0xde, 0xf7, 0x6d, 0xce, 0x52, 0xd8, 0x03, + 0xce, 0x1d, 0xd8, 0x8d, 0xf5, 0xfb, 0x1c, 0x9b, 0x4f, 0x91, 0xf1, 0x8b, 0xeb, 0xec, 0x8c, 0xbc, 0xcc, 0x07, 0xd2, + 0x5b, 0x0a, 0x9d, 0x03, 0xec, 0x87, 0x17, 0x9b, 0x73, 0xa0, 0xf2, 0x30, 0xd5, 0xf6, 0x94, 0xcd, 0x0d, 0xa4, 0xda, + 0x70, 0x99, 0x20, 0xfe, 0x58, 0x5d, 0x5d, 0xb1, 0x9b, 0x8b, 0x81, 0xe3, 0xd1, 0xf7, 0x19, 0x59, 0xdf, 0x83, 0x44, + 0x73, 0xc6, 0x3e, 0x35, 0xc7, 0x6c, 0x16, 0xc5, 0x8c, 0xc2, 0x2c, 0x3b, 0xbd, 0xd5, 0xdd, 0xfe, 0xdd, 0x6f, 0x07, + 0xbf, 0xb9, 0x9f, 0x30, 0x4a, 0x35, 0xd1, 0x99, 0xbe, 0xa3, 0xb7, 0xfa, 0x79, 0x06, 0xac, 0x21, 0x61, 0x7e, 0x42, + 0x11, 0xed, 0xfa, 0xaa, 0x3a, 0x68, 0x8c, 0x66, 0xb7, 0x8a, 0xf8, 0x99, 0x17, 0xb3, 0xc0, 0x4b, 0xfd, 0x1b, 0xc1, + 0x33, 0x76, 0x8e, 0x56, 0x77, 0x62, 0x8e, 0xf1, 0xc0, 0xfb, 0x84, 0x49, 0xaa, 0x0c, 0x45, 0x4c, 0x52, 0xb5, 0x18, + 0x27, 0x69, 0x50, 0x83, 0x46, 0x04, 0x78, 0xa9, 0x9c, 0xf4, 0xdd, 0xd5, 0x9d, 0x7c, 0x44, 0x17, 0xcd, 0xf2, 0x93, + 0xba, 0x1a, 0x99, 0x6f, 0xe9, 0x4f, 0xa7, 0x01, 0xcb, 0x4a, 0x13, 0x5d, 0x9e, 0x4b, 0x09, 0x39, 0x39, 0x1e, 0xbc, + 0x71, 0x12, 0x05, 0xeb, 0x94, 0x35, 0xa3, 0x8b, 0x90, 0xe3, 0xda, 0x05, 0x72, 0xf0, 0x77, 0x79, 0xac, 0x5d, 0x60, + 0xb7, 0x61, 0x99, 0xd8, 0x03, 0x08, 0xc4, 0x6d, 0x76, 0xca, 0x43, 0x87, 0x57, 0xf9, 0xa0, 0x8d, 0x06, 0x40, 0x0c, + 0x38, 0x96, 0x88, 0x7a, 0x2b, 0x96, 0xc3, 0xcb, 0xf2, 0x60, 0xc4, 0x79, 0x51, 0x56, 0x06, 0xe6, 0xf7, 0xd9, 0x63, + 0xcf, 0x9a, 0xf7, 0xd8, 0x33, 0xb1, 0xc7, 0xb6, 0xaf, 0xcc, 0x87, 0x33, 0x07, 0xfe, 0x1b, 0x14, 0x00, 0xf5, 0x6d, + 0xa5, 0xb3, 0xba, 0x53, 0x9c, 0xd5, 0x9d, 0x62, 0xba, 0xab, 0x3b, 0x05, 0xbb, 0x46, 0x23, 0x16, 0xc3, 0x72, 0x75, + 0xc3, 0x56, 0xa0, 0x10, 0xfe, 0xd8, 0xa5, 0x57, 0xce, 0x21, 0xbc, 0x83, 0x56, 0xdd, 0xfa, 0x3b, 0x77, 0xfb, 0x56, + 0xa7, 0xbd, 0x24, 0x88, 0xb6, 0x6e, 0xa5, 0xde, 0x78, 0xcc, 0xa6, 0xfd, 0x59, 0x34, 0x59, 0x27, 0xff, 0xe4, 0xe3, + 0xe7, 0x48, 0xdc, 0x4a, 0x08, 0x2a, 0xfd, 0x88, 0xa6, 0x70, 0xbb, 0x73, 0xc3, 0x44, 0x0f, 0x9b, 0x7c, 0x9e, 0xfa, + 0x14, 0x35, 0xdc, 0xb5, 0x0e, 0x1b, 0x16, 0x79, 0x33, 0xa2, 0x7f, 0xb7, 0x59, 0x6a, 0x27, 0x31, 0x9f, 0x81, 0x96, + 0xad, 0xe8, 0xf8, 0x74, 0x6c, 0xf0, 0xd9, 0xb4, 0x7b, 0xcd, 0xc3, 0xbd, 0x14, 0x5f, 0xba, 0x12, 0x87, 0x0a, 0x3f, + 0xb7, 0xb8, 0x8f, 0xcc, 0xf6, 0x5e, 0xdb, 0xd6, 0x48, 0xad, 0xd7, 0x2d, 0x07, 0x42, 0x51, 0x77, 0x4f, 0x2a, 0xff, + 0xf0, 0xd9, 0x21, 0xfc, 0x47, 0x5c, 0xfd, 0xdf, 0xd3, 0x26, 0x46, 0xfd, 0x75, 0x5a, 0x62, 0xd4, 0x89, 0x55, 0x42, + 0x46, 0x7c, 0xff, 0xfa, 0xb3, 0xd9, 0xa7, 0x35, 0xd8, 0xbb, 0x36, 0xd9, 0x7f, 0x55, 0x6b, 0x7f, 0x17, 0x45, 0x90, + 0xd1, 0xb6, 0x5e, 0x5d, 0xa0, 0x87, 0xcc, 0xf3, 0xd3, 0x21, 0x34, 0x12, 0x72, 0x04, 0x99, 0x1e, 0xa8, 0xd8, 0x86, + 0x44, 0x89, 0x97, 0x6d, 0xa2, 0xc4, 0x8b, 0xdd, 0xa2, 0xc4, 0xf7, 0x7b, 0x89, 0x12, 0x2f, 0xbe, 0xb8, 0x28, 0xf1, + 0xb2, 0x2e, 0x4a, 0x5c, 0x44, 0xc2, 0xe8, 0xd7, 0x78, 0xbd, 0xe6, 0x3f, 0xdf, 0xd3, 0x4d, 0xe2, 0x79, 0x34, 0xec, + 0xda, 0x14, 0x09, 0xfc, 0xe2, 0xdf, 0x16, 0x2c, 0x70, 0x21, 0xbe, 0x45, 0x1b, 0xb8, 0x42, 0xb4, 0xe0, 0x94, 0x1d, + 0xbf, 0x23, 0x15, 0x07, 0x51, 0x38, 0xff, 0x09, 0x6e, 0x92, 0x41, 0x1d, 0x18, 0x4b, 0x2f, 0xfc, 0xe4, 0xa7, 0x68, + 0xb5, 0x5e, 0xbd, 0x86, 0xbe, 0xde, 0xfb, 0x89, 0x3f, 0x0e, 0x58, 0xee, 0xa1, 0x4f, 0x36, 0x7b, 0x5c, 0x27, 0x0e, + 0x66, 0xb2, 0xe2, 0xa7, 0x77, 0x27, 0x7e, 0xa2, 0x21, 0x2d, 0xff, 0x4d, 0xc6, 0x80, 0x6a, 0xb3, 0x20, 0x02, 0xa1, + 0xac, 0x2a, 0x83, 0xfe, 0x74, 0x61, 0xe4, 0x22, 0xd2, 0x1b, 0xa0, 0x14, 0x46, 0x1a, 0xad, 0xfd, 0xb0, 0x9a, 0x50, + 0xb3, 0xd6, 0x8d, 0x3c, 0x32, 0x5d, 0x5d, 0x0d, 0xbf, 0x8c, 0xd6, 0x09, 0x9b, 0x46, 0xb7, 0xa1, 0x6a, 0x84, 0xb9, + 0x67, 0x04, 0x5c, 0xcb, 0xe6, 0x6d, 0x30, 0xa7, 0xea, 0x3b, 0x64, 0x94, 0xa3, 0x58, 0x53, 0x21, 0xa5, 0xef, 0x7a, + 0x65, 0xd2, 0xfd, 0xb8, 0x89, 0x20, 0xaa, 0x79, 0xf2, 0xaf, 0x07, 0x9a, 0x16, 0x0d, 0x3f, 0xad, 0xa5, 0xb0, 0x2f, + 0x89, 0x2c, 0xae, 0x15, 0x4e, 0xb4, 0x50, 0x28, 0x17, 0x45, 0x78, 0x98, 0x86, 0x89, 0xe3, 0x6f, 0xc8, 0x37, 0xba, + 0x78, 0x0b, 0xc1, 0x75, 0xb2, 0x35, 0x9f, 0x0f, 0x1e, 0x2c, 0x85, 0x1e, 0x9f, 0x4b, 0x68, 0x7c, 0x73, 0xc3, 0xe2, + 0xc0, 0xbb, 0xd7, 0xf4, 0x2c, 0x0a, 0x7f, 0x00, 0x04, 0xbc, 0x88, 0x6e, 0x43, 0xb9, 0x02, 0xe6, 0x30, 0x6a, 0x58, + 0x4b, 0x8d, 0x61, 0x7d, 0xc0, 0xd7, 0x46, 0x1a, 0x01, 0x64, 0x8f, 0x9e, 0xb3, 0xbf, 0x1a, 0xf4, 0xef, 0xdf, 0xf4, + 0xcc, 0x38, 0x8f, 0xf2, 0x0f, 0xfd, 0xbc, 0xda, 0xe3, 0x33, 0x8f, 0x1f, 0x3f, 0x68, 0x07, 0x5b, 0x83, 0x44, 0xda, + 0x22, 0x27, 0xb4, 0xd6, 0xd0, 0x5a, 0x6f, 0xdd, 0x05, 0x30, 0x8a, 0x8b, 0x68, 0x3d, 0x59, 0xa0, 0x75, 0xee, 0x97, + 0x83, 0x37, 0x85, 0x3e, 0x31, 0x79, 0x6f, 0x0e, 0x7a, 0xa5, 0xa8, 0xc0, 0x02, 0x7e, 0xff, 0x25, 0xc4, 0xa5, 0xfd, + 0x0f, 0xa2, 0xa1, 0xbe, 0x6a, 0x72, 0x5f, 0xdc, 0x4f, 0x5a, 0xbc, 0x03, 0xc8, 0x31, 0xcb, 0x23, 0xbe, 0x88, 0xcb, + 0xb5, 0x66, 0x22, 0x93, 0x55, 0x91, 0x26, 0x47, 0x57, 0x6c, 0x0b, 0x1c, 0x29, 0xbe, 0xc2, 0x2c, 0x12, 0xd3, 0xb9, + 0x77, 0x84, 0xc1, 0x38, 0xb5, 0xaa, 0x10, 0x19, 0x6e, 0xa7, 0xc1, 0x90, 0x7c, 0x55, 0xdf, 0x2d, 0xfd, 0xd0, 0xc0, + 0xe4, 0x08, 0xf5, 0x37, 0xde, 0x1d, 0x84, 0x07, 0x07, 0xe2, 0x56, 0x7d, 0x05, 0x85, 0x86, 0xec, 0xe5, 0x07, 0x19, + 0xd0, 0xd4, 0x46, 0x4c, 0x88, 0x5b, 0xbc, 0xd1, 0x57, 0x8a, 0xa2, 0x28, 0xb9, 0x18, 0xa1, 0xe4, 0x72, 0x04, 0x96, + 0xa3, 0x38, 0x00, 0xb7, 0x25, 0xd9, 0xea, 0x8e, 0x4a, 0x40, 0x32, 0xc0, 0x9b, 0x59, 0x51, 0xc0, 0x23, 0x60, 0x76, + 0x6d, 0x51, 0x20, 0x04, 0x7a, 0x88, 0x5e, 0xe8, 0xc5, 0x10, 0x28, 0xbb, 0xaf, 0xa0, 0xc0, 0x8e, 0x6f, 0xb9, 0x26, + 0x58, 0xb1, 0xe9, 0x71, 0x34, 0x60, 0xcd, 0xa1, 0x12, 0x43, 0x89, 0x0a, 0xc2, 0xad, 0x43, 0x25, 0xf2, 0xb9, 0xc1, + 0x1a, 0x68, 0x23, 0xca, 0x45, 0x77, 0xe9, 0x92, 0x85, 0x6b, 0x15, 0x53, 0xa5, 0x61, 0xe8, 0x4a, 0xa8, 0xf3, 0x82, + 0x98, 0x2d, 0xa0, 0x36, 0xcd, 0x2d, 0x17, 0x74, 0x16, 0x26, 0x9c, 0xa4, 0x7a, 0xc6, 0x84, 0x5f, 0x6c, 0x26, 0x9c, + 0xb6, 0x55, 0x4f, 0x08, 0x3e, 0xa5, 0x51, 0xd5, 0xfb, 0x8c, 0xcc, 0xb7, 0x31, 0x2e, 0x0b, 0x2a, 0x8d, 0xb8, 0xba, + 0x48, 0xa0, 0x5d, 0xf3, 0xaa, 0x93, 0x96, 0xdf, 0xc8, 0x78, 0x15, 0x45, 0x51, 0xac, 0xd7, 0xbb, 0xe1, 0xe3, 0x84, + 0x78, 0x5d, 0xad, 0xfd, 0x4c, 0x6a, 0xfd, 0xb4, 0x00, 0xfd, 0x81, 0xdd, 0xd3, 0x41, 0x42, 0xa8, 0xfa, 0xc0, 0xee, + 0xc1, 0x60, 0xf1, 0x25, 0x68, 0x53, 0xd4, 0x2d, 0xe4, 0xda, 0x80, 0x0c, 0x18, 0x13, 0x88, 0xe1, 0xb6, 0x65, 0x03, + 0xd9, 0xd9, 0x16, 0x2a, 0x8e, 0x28, 0x86, 0x64, 0xe7, 0x62, 0x13, 0x73, 0xbf, 0x04, 0xad, 0x11, 0xc7, 0x66, 0xc3, + 0xd6, 0xd0, 0x9f, 0x38, 0xb6, 0x7d, 0x50, 0xab, 0x0f, 0x8a, 0xec, 0xa6, 0xda, 0xba, 0x91, 0x0e, 0x1d, 0xdb, 0xf4, + 0x9f, 0x58, 0xee, 0xa0, 0x76, 0x46, 0x4b, 0x21, 0x56, 0x47, 0xa8, 0xfe, 0x3a, 0x7d, 0xb4, 0xd1, 0x6a, 0x1b, 0x52, + 0xaf, 0xda, 0xf9, 0xe3, 0xd8, 0x32, 0xae, 0xff, 0x1a, 0xd5, 0x8f, 0x7e, 0x0a, 0xf0, 0x4a, 0xe9, 0x7e, 0x46, 0x10, + 0x24, 0x5c, 0x83, 0x6d, 0xf4, 0x27, 0xe5, 0xa9, 0xa2, 0xd1, 0xf6, 0xd1, 0xf5, 0x51, 0x9e, 0x45, 0x5e, 0x38, 0xc2, + 0xc9, 0x1d, 0x54, 0xbe, 0x98, 0x54, 0x29, 0x1c, 0x0f, 0x47, 0xcc, 0x8a, 0x1b, 0xbd, 0xad, 0xdc, 0x02, 0xf6, 0xdf, + 0x72, 0x7c, 0x5a, 0x63, 0x08, 0xbe, 0x00, 0x35, 0x20, 0xa5, 0xc0, 0xce, 0x0e, 0x21, 0xb6, 0x88, 0xdc, 0x5d, 0xf9, + 0x90, 0xdc, 0xbf, 0x33, 0x3c, 0x74, 0xf0, 0x0e, 0x2d, 0xef, 0xaf, 0xf9, 0xb8, 0xfb, 0xc4, 0x2e, 0x59, 0x38, 0x2d, + 0x77, 0x58, 0x39, 0xbf, 0xf6, 0xef, 0xae, 0x44, 0x51, 0x20, 0xd7, 0x46, 0xd4, 0x40, 0x51, 0xb2, 0x28, 0xc4, 0xc5, + 0x4f, 0xdb, 0xcd, 0xdf, 0x8b, 0x8b, 0xc1, 0x06, 0x14, 0x28, 0x2f, 0x6f, 0x26, 0x29, 0xc5, 0x21, 0xa0, 0x3b, 0x7a, + 0x31, 0x6b, 0x82, 0x11, 0x6d, 0x5d, 0x89, 0xa9, 0x30, 0x84, 0x2c, 0xda, 0xf8, 0x3c, 0x44, 0xeb, 0xbe, 0x5a, 0x6b, + 0x7f, 0xb7, 0xd6, 0x3a, 0xdd, 0xa5, 0xb5, 0x26, 0x1f, 0x30, 0xb2, 0xde, 0xc9, 0x7d, 0xe1, 0x04, 0x73, 0x2e, 0x7b, + 0x13, 0x96, 0x54, 0xdd, 0xe8, 0x32, 0x26, 0x5a, 0xd5, 0x7a, 0x23, 0xd3, 0x46, 0x54, 0x7f, 0x4b, 0x02, 0x8a, 0xb8, + 0x50, 0x97, 0x75, 0xe3, 0x17, 0x85, 0x6e, 0x9c, 0xa4, 0x9a, 0xc2, 0xfb, 0x47, 0x70, 0xff, 0x92, 0x67, 0x5d, 0x2e, + 0x1d, 0x14, 0x1e, 0x76, 0xc5, 0x48, 0x25, 0x9f, 0xb1, 0x42, 0xd0, 0x90, 0x3c, 0x11, 0x85, 0x94, 0x51, 0x76, 0x48, + 0x2c, 0x57, 0x2d, 0x5c, 0xc6, 0x8a, 0x72, 0xd0, 0xba, 0xe3, 0x90, 0xf3, 0x62, 0x79, 0xd9, 0x94, 0x7d, 0x86, 0xe4, + 0xd7, 0xd2, 0x22, 0xc9, 0x9d, 0x7b, 0x08, 0xc1, 0x42, 0x4d, 0x5f, 0xb9, 0xd7, 0xce, 0x6d, 0x20, 0x70, 0x90, 0x0d, + 0xbe, 0x88, 0xbb, 0xb5, 0xf3, 0x94, 0x46, 0xa4, 0xb8, 0xba, 0x76, 0xf0, 0x74, 0xa7, 0x9b, 0x60, 0x59, 0x1f, 0x81, + 0xb8, 0xbe, 0x92, 0x34, 0x08, 0x7d, 0x5b, 0xb1, 0x07, 0x0d, 0x0c, 0x00, 0x9e, 0xff, 0xd5, 0x67, 0xce, 0x0a, 0x80, + 0x26, 0x52, 0xb1, 0xe5, 0x3b, 0x7f, 0xdc, 0xc4, 0x26, 0x99, 0x1f, 0x63, 0xd5, 0xfa, 0x37, 0x49, 0xdf, 0xb3, 0xe1, + 0x9e, 0x3f, 0x65, 0x75, 0x3e, 0xaf, 0xd1, 0x17, 0xe3, 0xe0, 0xab, 0x2c, 0x5e, 0x87, 0x98, 0x1d, 0xc2, 0x4c, 0x63, + 0x6f, 0xf2, 0x61, 0x23, 0x7d, 0x8f, 0xab, 0x44, 0x41, 0x5d, 0x5c, 0xbe, 0x54, 0x18, 0x78, 0x18, 0x4c, 0x95, 0xf5, + 0x2d, 0x37, 0x91, 0x14, 0x35, 0xfd, 0x87, 0x76, 0xc7, 0x7b, 0x36, 0x3b, 0xac, 0xe8, 0x4f, 0xdd, 0x6e, 0x59, 0xbb, + 0x9e, 0x8f, 0x63, 0x19, 0xfd, 0xca, 0x7d, 0x24, 0xff, 0xf8, 0x4f, 0x27, 0xfc, 0x9b, 0x95, 0x39, 0xfa, 0x9c, 0x21, + 0x40, 0xfb, 0xd2, 0xc5, 0xb4, 0x7c, 0x4d, 0x53, 0x2b, 0x69, 0x1b, 0xd6, 0xcc, 0x0f, 0x02, 0x33, 0x00, 0x4f, 0x95, + 0xcd, 0x67, 0x81, 0x87, 0xfd, 0xac, 0x21, 0x8c, 0xf7, 0x67, 0xf4, 0x53, 0x5e, 0x29, 0xe9, 0x62, 0xbd, 0x1c, 0x6f, + 0x64, 0x45, 0xb9, 0xa4, 0x3f, 0xaf, 0xeb, 0xcc, 0xe5, 0xcf, 0xce, 0x66, 0xb3, 0xb2, 0xd6, 0xd8, 0x56, 0x0e, 0x51, + 0xf3, 0xfb, 0xd0, 0xb6, 0xed, 0x2a, 0x7e, 0xdb, 0x36, 0x0a, 0x6d, 0x0c, 0x13, 0x95, 0xf0, 0xbd, 0xdd, 0x6b, 0xea, + 0x0f, 0x1a, 0x2d, 0x75, 0xd5, 0xb6, 0x1f, 0x69, 0xa9, 0xfd, 0x57, 0x0c, 0x05, 0x49, 0xc3, 0xae, 0xed, 0x5f, 0x5f, + 0x2b, 0x5b, 0x7a, 0xaa, 0x6e, 0xe0, 0x4f, 0x6b, 0xbc, 0x63, 0xad, 0xef, 0xd1, 0xb4, 0x6d, 0x79, 0x67, 0x56, 0x71, + 0xec, 0x96, 0x6c, 0x96, 0x06, 0x64, 0xa9, 0xe4, 0xa7, 0x6c, 0x99, 0xf4, 0x27, 0x0c, 0x2f, 0x48, 0x2d, 0xe9, 0xb4, + 0x45, 0xab, 0x1e, 0x73, 0x0e, 0x76, 0x5c, 0x8e, 0xa0, 0xc3, 0xb6, 0x82, 0x97, 0x55, 0xb5, 0x9b, 0x35, 0xf1, 0x11, + 0x3c, 0xc5, 0x36, 0xf5, 0x0b, 0x27, 0x5c, 0xa6, 0x5d, 0xfb, 0x4f, 0xa5, 0x7a, 0x0a, 0x70, 0xa7, 0x1b, 0x61, 0x6d, + 0x42, 0x97, 0x27, 0xf8, 0x77, 0x7e, 0x39, 0xf7, 0x6c, 0x75, 0x57, 0x36, 0xee, 0xea, 0xc1, 0x75, 0x53, 0x71, 0x94, + 0xd1, 0xa8, 0x9b, 0x48, 0x5f, 0x6e, 0x02, 0x34, 0x93, 0xad, 0x5b, 0xc0, 0x82, 0xa6, 0x94, 0xb4, 0xaa, 0xe1, 0x6e, + 0x0c, 0xc5, 0x59, 0x58, 0x79, 0x85, 0x7e, 0xbf, 0x48, 0xb9, 0x0a, 0x30, 0x18, 0x4f, 0x7b, 0x78, 0xb9, 0x57, 0x5a, + 0xaa, 0x68, 0x2a, 0x83, 0x6b, 0x40, 0x48, 0xa4, 0xca, 0x3a, 0x0e, 0x4c, 0xca, 0xe8, 0xa4, 0xe9, 0x9b, 0x3a, 0xdc, + 0xed, 0xdd, 0x3b, 0x5d, 0xb8, 0xd7, 0xa8, 0xa3, 0x6a, 0xaf, 0xab, 0xbd, 0xea, 0x1d, 0xb6, 0x18, 0x27, 0xcc, 0x00, + 0x78, 0x52, 0x28, 0x68, 0x34, 0xa4, 0x54, 0x68, 0x1f, 0x01, 0x9d, 0xbf, 0x95, 0x89, 0xb5, 0x80, 0x13, 0xbb, 0x6b, + 0xae, 0x42, 0x7d, 0x8b, 0x9b, 0x41, 0xc0, 0x1d, 0xa7, 0x4e, 0xf8, 0x6c, 0xc2, 0x8a, 0x91, 0xc9, 0x95, 0x83, 0x2b, + 0x08, 0x77, 0xa9, 0x89, 0x7c, 0x72, 0x42, 0xbb, 0x14, 0xef, 0x12, 0xbe, 0x6f, 0x54, 0xde, 0x5f, 0x94, 0xb4, 0xf1, + 0xdc, 0x9d, 0xc5, 0xd5, 0xf7, 0xaa, 0xbd, 0xf4, 0xc3, 0xfd, 0xeb, 0x7a, 0x77, 0x7b, 0xd7, 0x05, 0xe6, 0x70, 0xef, + 0xca, 0xc0, 0x5d, 0x92, 0x95, 0x52, 0x3a, 0xfc, 0x5e, 0xba, 0x3c, 0x90, 0xc3, 0x22, 0xa8, 0xd8, 0x8a, 0x24, 0xfa, + 0x8b, 0xf5, 0x70, 0x74, 0x72, 0x76, 0xb7, 0x0c, 0x94, 0x1b, 0x16, 0x43, 0x76, 0xbb, 0xa1, 0xea, 0x58, 0xb6, 0xaa, + 0xa0, 0x93, 0xbf, 0x1f, 0xce, 0x87, 0xea, 0xcf, 0x17, 0xaf, 0xcc, 0x9e, 0x7a, 0x06, 0xe6, 0x18, 0x37, 0x73, 0x64, + 0x71, 0xcf, 0xbd, 0x7b, 0x16, 0x5f, 0xbb, 0xaa, 0x82, 0x49, 0xec, 0x88, 0xb9, 0xc5, 0x32, 0xc5, 0x55, 0xf7, 0xc8, + 0x95, 0xa4, 0x88, 0x74, 0xa7, 0x2a, 0x10, 0x56, 0xc7, 0xed, 0x29, 0x8e, 0x7b, 0x68, 0x1d, 0xf5, 0xd4, 0xd3, 0xaf, + 0x14, 0xe5, 0x64, 0xca, 0x66, 0xc9, 0x29, 0xaa, 0x63, 0x4e, 0x90, 0x1f, 0xa4, 0xdf, 0x8a, 0x62, 0x4d, 0x82, 0xc4, + 0x74, 0x94, 0x0d, 0x7f, 0x54, 0x14, 0x20, 0x46, 0x7d, 0xe5, 0xe1, 0xcc, 0x9d, 0x1d, 0xce, 0x9e, 0x0d, 0x78, 0x71, + 0xf6, 0x55, 0xa9, 0xba, 0x41, 0xff, 0xba, 0x52, 0xb3, 0x24, 0x8d, 0xa3, 0x0f, 0x8c, 0xf3, 0x92, 0x4a, 0xae, 0x28, + 0xaa, 0x36, 0x75, 0xeb, 0x5f, 0x72, 0x7a, 0xe3, 0xc9, 0xcc, 0x2d, 0xaa, 0xe3, 0x18, 0x0f, 0xf2, 0x41, 0x9e, 0x1c, + 0x88, 0xa1, 0x9f, 0xc8, 0x68, 0x72, 0xcc, 0x26, 0x44, 0x39, 0x2a, 0x87, 0x71, 0x2e, 0xe0, 0x3b, 0x81, 0x50, 0xc4, + 0x85, 0x03, 0x42, 0x82, 0xcd, 0x86, 0xea, 0x0f, 0x8e, 0xdb, 0x33, 0x1c, 0xe7, 0xc8, 0x3a, 0xea, 0x4d, 0x6c, 0xe3, + 0xd0, 0x3a, 0x34, 0x3b, 0xd6, 0x91, 0xd1, 0x33, 0x7b, 0x46, 0xef, 0x2f, 0xbd, 0x89, 0x79, 0x68, 0x1d, 0x1a, 0xb6, + 0xd9, 0x83, 0x42, 0xb3, 0x67, 0xf6, 0x6e, 0xcc, 0xc3, 0xde, 0xc4, 0xc6, 0x52, 0xd7, 0xea, 0x76, 0x4d, 0xc7, 0xb6, + 0xba, 0x5d, 0xa3, 0x6b, 0x1d, 0x1d, 0x99, 0x4e, 0xc7, 0x3a, 0x3a, 0x3a, 0xef, 0xf6, 0xac, 0x0e, 0xbc, 0xeb, 0x74, + 0x26, 0x1d, 0xcb, 0x71, 0x4c, 0xf8, 0xcb, 0xe8, 0x59, 0x2e, 0xfd, 0x70, 0x1c, 0xab, 0xe3, 0x18, 0x76, 0xd0, 0x75, + 0xad, 0xa3, 0x67, 0x06, 0xfe, 0x8d, 0xd5, 0x0c, 0xfc, 0x0b, 0xba, 0x31, 0x9e, 0x59, 0xee, 0x11, 0xfd, 0xc2, 0x0e, + 0x6f, 0x0e, 0x7b, 0x7f, 0x57, 0x0f, 0x5a, 0x61, 0x70, 0x08, 0x86, 0x5e, 0xd7, 0xea, 0x74, 0x8c, 0x43, 0xc7, 0xea, + 0x75, 0x16, 0xe6, 0xa1, 0x6b, 0x1d, 0x1d, 0x4f, 0x4c, 0xc7, 0x3a, 0x3e, 0x36, 0x6c, 0xb3, 0x63, 0xb9, 0x86, 0x63, + 0x1d, 0x76, 0xf0, 0x47, 0xc7, 0x72, 0x6f, 0x8e, 0x9f, 0x59, 0x47, 0xdd, 0xc5, 0x91, 0x75, 0xf8, 0xfe, 0xb0, 0x67, + 0xb9, 0x9d, 0x45, 0xe7, 0xc8, 0x72, 0x8f, 0x6f, 0x8e, 0xac, 0xc3, 0x85, 0xe9, 0x1e, 0x6d, 0x6d, 0xe9, 0xb8, 0x16, + 0xe0, 0x08, 0x5f, 0xc3, 0x0b, 0x83, 0xbf, 0x80, 0x3f, 0x0b, 0x6c, 0xfb, 0x07, 0x76, 0x93, 0xd4, 0x9b, 0x3e, 0xb3, + 0x7a, 0xc7, 0x13, 0xaa, 0x0e, 0x05, 0xa6, 0xa8, 0x01, 0x4d, 0x6e, 0x4c, 0xfa, 0x2c, 0x76, 0x67, 0x8a, 0x8e, 0xc4, + 0x1f, 0xfe, 0xb1, 0x1b, 0x13, 0x3e, 0x4c, 0xdf, 0xfd, 0x8f, 0xf6, 0x93, 0x4f, 0x39, 0x24, 0x6f, 0xfe, 0x8a, 0xff, + 0x43, 0x79, 0xcf, 0x46, 0xc6, 0x79, 0xdb, 0xa5, 0xe4, 0xdb, 0xdd, 0x97, 0x92, 0xaf, 0xd6, 0xfb, 0x5c, 0x4a, 0xbe, + 0xfd, 0xe2, 0x97, 0x92, 0xe7, 0x55, 0x9f, 0x98, 0xb7, 0xd5, 0xf4, 0x2c, 0xdf, 0x6f, 0xaa, 0x2a, 0x07, 0xdf, 0xd3, + 0x2e, 0x2f, 0xd6, 0x57, 0x10, 0xf7, 0xed, 0x6d, 0x34, 0x7c, 0xb5, 0x2e, 0x19, 0x7c, 0x46, 0x40, 0x63, 0xdf, 0x46, + 0x44, 0x63, 0x7f, 0x5d, 0x0f, 0xc1, 0xca, 0x8c, 0xb3, 0x39, 0xfe, 0xd4, 0x5c, 0x78, 0xc1, 0x2c, 0x67, 0x91, 0xa0, + 0x64, 0x80, 0xc5, 0xe0, 0x77, 0x05, 0xc7, 0x33, 0x48, 0x32, 0xeb, 0x65, 0x98, 0x80, 0x45, 0x30, 0x58, 0x72, 0xcc, + 0xe2, 0xac, 0xd2, 0xd8, 0x12, 0x91, 0xf2, 0xae, 0xb9, 0x07, 0x54, 0xeb, 0x7b, 0x34, 0x00, 0x6e, 0xee, 0xdd, 0xa9, + 0xf7, 0xab, 0x80, 0x65, 0x9d, 0x30, 0x90, 0x06, 0x6e, 0xbf, 0xe9, 0x7d, 0xd9, 0x0c, 0xb7, 0x62, 0x78, 0xdd, 0x3e, + 0x52, 0x18, 0x49, 0xb5, 0xbd, 0x53, 0x36, 0xe3, 0xdd, 0x05, 0x66, 0xc3, 0xe7, 0x4b, 0xcd, 0xb7, 0xd8, 0x10, 0xe7, + 0x1d, 0x57, 0x51, 0x55, 0x49, 0x2e, 0xda, 0x88, 0x90, 0x42, 0x40, 0x2d, 0x0c, 0x8d, 0x0b, 0x4e, 0xd5, 0x56, 0x90, + 0xdf, 0xb1, 0xa5, 0x77, 0xa5, 0x3e, 0x65, 0xe3, 0xe4, 0x27, 0x1b, 0x94, 0x2b, 0xfc, 0x5f, 0x81, 0x13, 0xe5, 0x1c, + 0xcf, 0x38, 0x92, 0xf1, 0xbc, 0x91, 0xfa, 0x25, 0x6d, 0x44, 0xb6, 0x70, 0x36, 0x75, 0x5e, 0xb4, 0xd5, 0x2d, 0xc1, + 0x61, 0x4b, 0xc1, 0x05, 0xe1, 0xe7, 0xc9, 0x09, 0x20, 0x23, 0x47, 0x0d, 0xf4, 0x73, 0xd8, 0xd6, 0x99, 0xa8, 0xf7, + 0x10, 0x16, 0xb1, 0xc1, 0x1f, 0xe4, 0xc0, 0x25, 0x9b, 0x59, 0x10, 0x79, 0x69, 0x1f, 0xd9, 0x34, 0x89, 0xe5, 0x75, + 0xd1, 0x63, 0x61, 0xb0, 0xc5, 0x98, 0x4e, 0xee, 0x98, 0x77, 0x82, 0x9e, 0x0f, 0xdb, 0xec, 0xef, 0x72, 0x47, 0xb1, + 0x4d, 0xc9, 0x1c, 0xc5, 0xe9, 0x1e, 0x1b, 0xce, 0x91, 0x61, 0x1d, 0x77, 0xf5, 0x4c, 0x6c, 0x38, 0xb9, 0xcb, 0x12, + 0x42, 0xc0, 0x01, 0x22, 0x1f, 0xa6, 0x1f, 0xfa, 0xa9, 0xef, 0x05, 0x19, 0xf0, 0xc3, 0x65, 0x21, 0xe5, 0x1f, 0xeb, + 0x24, 0x05, 0x18, 0x05, 0xd3, 0x8b, 0xce, 0x1f, 0xe6, 0x98, 0xa5, 0xb7, 0x8c, 0x85, 0x2d, 0x86, 0x31, 0x55, 0x5f, + 0x92, 0xdf, 0xcf, 0xb2, 0x3e, 0x23, 0xab, 0xb5, 0x71, 0x1a, 0xf2, 0xf5, 0x21, 0x1c, 0x1f, 0xb2, 0x91, 0xf1, 0x63, + 0x1b, 0xc1, 0xfd, 0xc7, 0x6e, 0x82, 0x9b, 0xb2, 0x7d, 0x08, 0xee, 0x3f, 0xbe, 0x38, 0xc1, 0xfd, 0x51, 0x26, 0xb8, + 0x25, 0xbf, 0xbf, 0xe2, 0x86, 0xe9, 0x1d, 0x3e, 0x6b, 0x90, 0xd8, 0xe0, 0xa9, 0x7a, 0x40, 0x0c, 0xbc, 0x2a, 0xe5, + 0x9b, 0x7f, 0x5f, 0x4a, 0xa0, 0x87, 0x0a, 0x50, 0x8c, 0x68, 0x4e, 0xc9, 0xba, 0x20, 0x17, 0xbb, 0x9d, 0x27, 0xec, + 0x62, 0xb7, 0xca, 0xeb, 0x30, 0x0d, 0xac, 0xb7, 0x5c, 0x8e, 0x84, 0x0b, 0xdd, 0x57, 0x51, 0xbc, 0xf4, 0x30, 0x34, + 0xa8, 0x8a, 0x89, 0x77, 0xe1, 0xc1, 0x06, 0x5f, 0xd2, 0x49, 0x14, 0x4e, 0xf3, 0x5b, 0x49, 0x36, 0xbc, 0x24, 0x8e, + 0x5b, 0xbd, 0x67, 0x5e, 0xac, 0x1a, 0xf4, 0x1a, 0x26, 0xf7, 0x49, 0xc7, 0x7e, 0xe2, 0x1e, 0x3e, 0x39, 0xb2, 0xe1, + 0x7f, 0x87, 0x75, 0x32, 0x83, 0x57, 0x5c, 0x46, 0x21, 0xe4, 0xfe, 0x12, 0x35, 0xdb, 0xaa, 0xdd, 0x32, 0xf6, 0xa1, + 0xa8, 0x75, 0xdc, 0x5c, 0x69, 0xea, 0xdd, 0x17, 0x75, 0x1a, 0x6b, 0x2c, 0xa2, 0xb5, 0x34, 0xac, 0x86, 0xd1, 0xf8, + 0xe1, 0x1a, 0xf4, 0xec, 0x52, 0x0d, 0xf9, 0x35, 0x07, 0xb7, 0x80, 0x8b, 0x75, 0xb2, 0xab, 0x22, 0xc1, 0xa0, 0x48, + 0x74, 0xb6, 0x13, 0x83, 0xfc, 0x8a, 0xd2, 0xc6, 0x60, 0xd0, 0x18, 0x96, 0x1d, 0x42, 0x41, 0xe7, 0x69, 0xe1, 0x3c, + 0x9a, 0xa0, 0x34, 0x5e, 0x87, 0x13, 0x0d, 0x7f, 0x7a, 0xe3, 0x44, 0xf3, 0x0f, 0x62, 0x8b, 0x7f, 0x58, 0xc7, 0x59, + 0xf3, 0x4e, 0xed, 0x22, 0x1b, 0x53, 0x22, 0x66, 0xc5, 0x7b, 0x92, 0x1a, 0x31, 0xe5, 0x70, 0xc7, 0xa9, 0x35, 0x87, + 0xde, 0x93, 0xbc, 0xe1, 0x93, 0xd4, 0x80, 0x3c, 0xea, 0x30, 0xdd, 0x8f, 0x1f, 0x53, 0x2d, 0xc8, 0x6c, 0x4c, 0x60, + 0x9d, 0x4d, 0x8a, 0xf8, 0x93, 0x8a, 0x37, 0x8f, 0x28, 0x04, 0x65, 0x7f, 0x62, 0x44, 0x4f, 0x9f, 0x9e, 0x0e, 0x1d, + 0x9d, 0xe7, 0xe5, 0x2e, 0x25, 0x91, 0x3c, 0xdf, 0xcf, 0xd0, 0x48, 0x6f, 0x74, 0x81, 0x5d, 0x81, 0xcc, 0x64, 0x0b, + 0x77, 0x04, 0x4e, 0xbd, 0x20, 0xa9, 0x13, 0x19, 0x14, 0x78, 0xc2, 0xe0, 0x47, 0xd4, 0xc9, 0xa5, 0xae, 0x8e, 0x65, + 0x5b, 0xb6, 0x9a, 0x37, 0x9c, 0xf9, 0xf3, 0xe1, 0x26, 0x4a, 0x3d, 0x48, 0x8f, 0x17, 0x44, 0x73, 0xf0, 0xa3, 0x4b, + 0xfd, 0x34, 0x80, 0x5c, 0x6b, 0xe0, 0x50, 0xb7, 0x24, 0xb9, 0x3c, 0xe3, 0xde, 0x0d, 0x5e, 0xfc, 0x01, 0xf3, 0xed, + 0x0a, 0x17, 0x5a, 0x0c, 0x89, 0xf6, 0x03, 0x1c, 0x86, 0x9a, 0xaa, 0x81, 0x6e, 0x80, 0xc5, 0x89, 0x29, 0x7b, 0x0b, + 0xf5, 0x15, 0x68, 0xa3, 0xab, 0x1c, 0x88, 0x59, 0xec, 0x2d, 0x21, 0x2f, 0xc9, 0x26, 0x33, 0x38, 0xa5, 0x55, 0x39, + 0xa9, 0x55, 0x9c, 0x67, 0x47, 0x86, 0xe2, 0x3a, 0x86, 0x62, 0x03, 0xb9, 0x55, 0x33, 0x63, 0x93, 0x5d, 0x0d, 0x76, + 0x19, 0x3c, 0x10, 0x7d, 0x79, 0x48, 0x70, 0x90, 0xa9, 0x03, 0xbf, 0x4a, 0x4a, 0x29, 0xb8, 0xad, 0x26, 0x85, 0xff, + 0xf7, 0xe9, 0xd2, 0xf3, 0x82, 0xdd, 0xa5, 0x3a, 0xe6, 0x22, 0xe3, 0x55, 0x7c, 0x7d, 0x83, 0x8e, 0xbe, 0x7e, 0xa8, + 0xf8, 0x1f, 0x3f, 0x6a, 0x3e, 0x38, 0x33, 0x0d, 0x25, 0xfc, 0xc0, 0xb3, 0x5e, 0x42, 0x98, 0x5f, 0x5c, 0xd3, 0x23, + 0xb2, 0xc0, 0xd3, 0x10, 0xfe, 0x2d, 0x8a, 0xc5, 0x0f, 0x6e, 0x26, 0x61, 0x05, 0x5e, 0x38, 0x07, 0x92, 0xe6, 0x85, + 0xf3, 0x9a, 0x39, 0x16, 0xf9, 0x2a, 0x57, 0x4a, 0x8b, 0xae, 0x0a, 0x53, 0xa9, 0xe4, 0xbb, 0xfb, 0x0b, 0xca, 0xb5, + 0xa8, 0xa9, 0x70, 0xca, 0xa1, 0x63, 0x6d, 0x71, 0x93, 0xfb, 0x74, 0xf8, 0xf5, 0xc9, 0x92, 0xa5, 0x1e, 0x5d, 0x03, + 0x81, 0xf0, 0x0b, 0xec, 0x80, 0x32, 0x11, 0x79, 0xd2, 0xf1, 0x68, 0x18, 0x4e, 0xd9, 0x8d, 0x3f, 0xe1, 0x72, 0xa9, + 0xa1, 0xf0, 0x73, 0xca, 0x44, 0x8b, 0xcf, 0xa1, 0x63, 0x90, 0xc3, 0xc1, 0xc4, 0xc3, 0x38, 0xb8, 0xc3, 0x30, 0x52, + 0x4f, 0xbf, 0xce, 0x7d, 0x33, 0xdb, 0x26, 0x01, 0x12, 0x1e, 0x5f, 0xc6, 0x2c, 0xf8, 0xe7, 0xf0, 0x6b, 0x38, 0xb8, + 0xbf, 0xbe, 0x52, 0xf5, 0x41, 0x6a, 0x2d, 0x62, 0x36, 0x1b, 0x7e, 0xdd, 0x90, 0xf8, 0x17, 0xc5, 0x7b, 0x1a, 0x8b, + 0xda, 0x71, 0x8b, 0xe8, 0x65, 0x9d, 0xbd, 0x84, 0xfa, 0x53, 0x2e, 0xad, 0x83, 0x04, 0xb8, 0x29, 0xc9, 0xd8, 0xce, + 0x00, 0xe5, 0xe7, 0x71, 0xe0, 0x4d, 0x3e, 0x0c, 0xe8, 0x4d, 0xe9, 0xc1, 0x84, 0xd3, 0x7a, 0xe2, 0xad, 0xfa, 0x78, + 0xbc, 0xca, 0x85, 0xe0, 0x9a, 0x4d, 0xa5, 0x39, 0x67, 0xd7, 0xb8, 0x96, 0x71, 0x29, 0x6f, 0xf0, 0xcb, 0xf8, 0xa9, + 0xdb, 0x85, 0x9f, 0x32, 0xf1, 0x29, 0x7c, 0xc8, 0x32, 0x21, 0xa8, 0x93, 0x88, 0x8a, 0x82, 0xb5, 0xd5, 0x51, 0x9c, + 0xde, 0x5f, 0xba, 0x37, 0x8e, 0xbd, 0x70, 0x1d, 0xab, 0xf7, 0xde, 0xe9, 0x2d, 0x3a, 0xd6, 0x71, 0x60, 0x76, 0xac, + 0x63, 0xf8, 0xf3, 0xfe, 0xd8, 0xea, 0x2d, 0x4c, 0xd7, 0x3a, 0x7c, 0xef, 0xb8, 0x81, 0xd9, 0xb3, 0x8e, 0xe1, 0xcf, + 0x39, 0xb5, 0x02, 0x01, 0x88, 0xe4, 0x9d, 0xaf, 0x4b, 0x54, 0x40, 0xfa, 0x9d, 0xdf, 0xc9, 0x1a, 0xa5, 0xe3, 0xad, + 0xe1, 0x5e, 0x17, 0x48, 0x46, 0x91, 0x41, 0x27, 0x1c, 0x68, 0xe1, 0x90, 0x51, 0x46, 0x0c, 0x61, 0xde, 0x26, 0x7c, + 0xd0, 0x45, 0x22, 0x97, 0xc6, 0x6d, 0xc4, 0xdb, 0x34, 0x67, 0xef, 0x10, 0xc9, 0x19, 0xe9, 0x22, 0xf8, 0xe7, 0x15, + 0x46, 0x59, 0x13, 0xf9, 0x46, 0x24, 0xaa, 0x54, 0x24, 0x08, 0xce, 0x76, 0x0f, 0x1c, 0xbd, 0xf0, 0x59, 0x9e, 0xa0, + 0xee, 0x8b, 0xf6, 0x2d, 0xe5, 0x15, 0xfa, 0xac, 0x7e, 0x30, 0x2f, 0x7b, 0x91, 0x7d, 0x04, 0xc2, 0x4d, 0x4f, 0xfd, + 0x38, 0x1f, 0x9e, 0x44, 0xa2, 0x9d, 0xe6, 0xb4, 0x27, 0x3a, 0x64, 0xf2, 0x7a, 0x0d, 0x5c, 0xf2, 0x8d, 0x17, 0x48, + 0x86, 0x6c, 0x52, 0xcb, 0x07, 0x39, 0xe5, 0x7f, 0xfc, 0xb8, 0x18, 0x9c, 0x59, 0x19, 0xf7, 0x89, 0xd3, 0x85, 0x63, + 0xb7, 0xcb, 0x3a, 0x5b, 0x6d, 0x2a, 0x77, 0x07, 0x2a, 0x2f, 0xe2, 0x19, 0x0b, 0xbb, 0x29, 0x61, 0xb1, 0xd1, 0x6a, + 0xd8, 0x59, 0xb3, 0xd7, 0x80, 0x10, 0xef, 0x15, 0x51, 0x47, 0xd5, 0x07, 0xa1, 0x30, 0x3f, 0x08, 0xb7, 0x04, 0x67, + 0xe7, 0xb2, 0x98, 0x0a, 0xa8, 0xd9, 0x02, 0xc7, 0x0e, 0x07, 0xf1, 0xff, 0x34, 0x10, 0xe8, 0xac, 0x09, 0xf6, 0x12, + 0x95, 0xdd, 0x5a, 0x72, 0xde, 0xcb, 0xcf, 0x55, 0x3a, 0x50, 0x59, 0x72, 0xa6, 0x42, 0x11, 0xa4, 0x78, 0xc4, 0xac, + 0xae, 0xb9, 0xb1, 0x68, 0x7e, 0x5a, 0x14, 0x05, 0x86, 0x8f, 0x99, 0x2e, 0x84, 0xe3, 0xa8, 0xfe, 0xf8, 0x71, 0xeb, + 0x21, 0x44, 0xc6, 0x39, 0x72, 0x72, 0x6b, 0x55, 0xa6, 0x6f, 0xaa, 0x4c, 0x62, 0xf2, 0x7e, 0x91, 0x6a, 0x08, 0x1b, + 0x57, 0x5a, 0x7b, 0xf8, 0x73, 0xcc, 0xbc, 0xd4, 0xe2, 0x97, 0xa5, 0x9a, 0x74, 0xb8, 0x1b, 0x0e, 0xeb, 0x80, 0x75, + 0x2b, 0x0f, 0xc6, 0xc8, 0x83, 0x9d, 0x3e, 0xda, 0xbc, 0x5f, 0xf3, 0xa8, 0x0e, 0xd0, 0xc7, 0x47, 0xbb, 0x88, 0x9f, + 0xf5, 0x26, 0xf5, 0x28, 0xc8, 0x92, 0x7c, 0xe4, 0x46, 0xa9, 0x27, 0x52, 0xa9, 0x01, 0x5f, 0x3e, 0x68, 0x34, 0xbf, + 0x90, 0x22, 0x3f, 0x9c, 0xbe, 0xb9, 0xf8, 0x56, 0xe1, 0xeb, 0x9f, 0xac, 0x05, 0x50, 0x90, 0xa1, 0x34, 0x2e, 0x43, + 0x4a, 0xe3, 0xa2, 0xf0, 0x24, 0x56, 0x90, 0x0c, 0x25, 0x3b, 0x20, 0x0c, 0xa2, 0x02, 0x9a, 0x6c, 0x28, 0x96, 0xeb, + 0x20, 0xf5, 0x57, 0x5e, 0x9c, 0x1e, 0x40, 0x53, 0x13, 0x88, 0x9c, 0xda, 0x16, 0x0f, 0x82, 0xcc, 0x30, 0x44, 0x0c, + 0xd0, 0x34, 0x14, 0x76, 0x18, 0x33, 0x3f, 0xc8, 0xcd, 0x30, 0xc4, 0x07, 0xbc, 0xc9, 0x84, 0xad, 0xd2, 0xa1, 0xea, + 0xad, 0x20, 0x95, 0x12, 0xc6, 0xda, 0x3f, 0x88, 0x26, 0x29, 0x4b, 0xcd, 0x24, 0x8d, 0x99, 0xb7, 0x54, 0xf3, 0x58, + 0xd3, 0xf5, 0xfe, 0x92, 0xf5, 0x78, 0xe9, 0xa7, 0x79, 0xb0, 0x56, 0x02, 0x10, 0x0c, 0x22, 0x60, 0x88, 0x10, 0x1c, + 0x86, 0x50, 0x78, 0x1e, 0xcd, 0x2b, 0x2b, 0xaa, 0xe0, 0x5c, 0xce, 0x30, 0x14, 0x38, 0x49, 0x32, 0xa0, 0x2d, 0x9e, + 0x44, 0xc1, 0x35, 0x8f, 0x61, 0x91, 0xc7, 0x94, 0x55, 0x4f, 0x4f, 0xb8, 0x78, 0xab, 0x60, 0xd8, 0x15, 0xb5, 0x6b, + 0x43, 0xb0, 0xf3, 0xb6, 0xe8, 0x16, 0x07, 0xbc, 0x32, 0x1c, 0x4d, 0xd4, 0x33, 0x66, 0xa0, 0xa0, 0xb1, 0x5c, 0x00, + 0x23, 0x54, 0x32, 0x98, 0x59, 0x38, 0xa7, 0xb9, 0x3b, 0x25, 0x8e, 0x0a, 0x79, 0xa5, 0x8f, 0x1f, 0x9f, 0x8f, 0x7e, + 0xfb, 0x17, 0xa4, 0xc9, 0x58, 0x38, 0x22, 0xa6, 0xc4, 0xa5, 0x5c, 0x8b, 0x73, 0x9f, 0xc6, 0x08, 0x8d, 0xa5, 0xd8, + 0x54, 0x04, 0xe6, 0x11, 0x4b, 0x2b, 0x1b, 0x5d, 0x89, 0x68, 0x7f, 0x90, 0x41, 0x47, 0x17, 0x91, 0x2f, 0x46, 0x30, + 0xbd, 0x23, 0x11, 0x70, 0x45, 0xf9, 0xe5, 0xee, 0xbb, 0x63, 0xa5, 0x08, 0xc1, 0xd3, 0x64, 0xd1, 0x43, 0x6b, 0xe8, + 0xf4, 0xc4, 0x53, 0x90, 0x69, 0x41, 0xf6, 0x23, 0xe9, 0x1f, 0x00, 0x98, 0x8b, 0x68, 0xc9, 0x2c, 0x3f, 0x3a, 0xb8, + 0x65, 0x63, 0xd3, 0x5b, 0xf9, 0x64, 0x97, 0x83, 0x7a, 0x37, 0x85, 0x38, 0xbf, 0xdc, 0xdc, 0x85, 0xf8, 0xeb, 0xac, + 0x40, 0x65, 0x54, 0x0e, 0xef, 0xd8, 0x75, 0x8b, 0x7b, 0x40, 0x88, 0x5f, 0x20, 0xe1, 0x31, 0x3a, 0x3d, 0x39, 0xf0, + 0x4e, 0xcb, 0xf1, 0x65, 0x2d, 0x91, 0xda, 0xa4, 0x7c, 0x08, 0x9c, 0x51, 0x98, 0x58, 0x11, 0x11, 0xb6, 0x78, 0x30, + 0xa3, 0xd9, 0x4c, 0x8e, 0x09, 0x6b, 0x95, 0x87, 0x97, 0x23, 0xad, 0x58, 0xd2, 0xd1, 0x8a, 0xbe, 0x54, 0xff, 0x44, + 0xfe, 0x53, 0xed, 0x63, 0x30, 0x68, 0x80, 0x19, 0xb6, 0x7b, 0x2d, 0xb6, 0x6c, 0x8e, 0xb1, 0x87, 0x54, 0x89, 0xd3, + 0x91, 0x6a, 0x26, 0x83, 0x16, 0xce, 0xe5, 0xc1, 0x70, 0x48, 0x64, 0xae, 0x4a, 0xed, 0x00, 0x89, 0x0d, 0x69, 0x5e, + 0x00, 0xd8, 0x14, 0x1a, 0x9a, 0xe4, 0x2e, 0x8b, 0x8d, 0xaa, 0xe0, 0xd4, 0xc7, 0x78, 0xe0, 0x89, 0xe5, 0x57, 0x5a, + 0xa0, 0xb0, 0xf0, 0xf8, 0xbc, 0x03, 0x7d, 0x17, 0xfd, 0x54, 0xc8, 0xbc, 0xf2, 0x0d, 0x51, 0x74, 0x33, 0xf0, 0xee, + 0x23, 0xc9, 0x8c, 0x89, 0x47, 0x34, 0x39, 0xc7, 0xd2, 0x0b, 0xe1, 0x49, 0x5c, 0xdb, 0x68, 0x79, 0xb6, 0x8c, 0xfa, + 0x66, 0x93, 0x33, 0x5c, 0xec, 0xda, 0x6b, 0x72, 0xdd, 0x32, 0x30, 0x48, 0x3c, 0xb3, 0x62, 0x1f, 0x96, 0x5e, 0x22, + 0x59, 0xc8, 0x4e, 0x0e, 0x00, 0x3e, 0x88, 0xc2, 0x52, 0x62, 0x9c, 0x7c, 0x1d, 0x42, 0xbd, 0x78, 0x09, 0x99, 0x62, + 0xbd, 0x9e, 0x0a, 0x9e, 0x0f, 0x05, 0xcb, 0x3c, 0x78, 0x75, 0xa9, 0x4a, 0x9d, 0x97, 0xb1, 0x9b, 0x99, 0xc0, 0xdd, + 0xa9, 0x65, 0x7e, 0x5d, 0x63, 0x5e, 0x99, 0x6c, 0x90, 0x32, 0x11, 0xe4, 0xe0, 0x3c, 0x6d, 0x89, 0x83, 0xd0, 0x56, + 0x85, 0xf8, 0xd9, 0x2d, 0x15, 0x8a, 0x75, 0xbc, 0xad, 0x56, 0xc1, 0x39, 0xe5, 0xd5, 0x56, 0x9e, 0xa6, 0x3e, 0xc4, + 0x15, 0x5f, 0xab, 0x8d, 0xa5, 0x50, 0xef, 0x3c, 0x1d, 0x42, 0x55, 0xa1, 0x8b, 0xf7, 0x56, 0x2b, 0xaa, 0xac, 0x0f, + 0x4e, 0x0e, 0x48, 0x2c, 0x3d, 0xa5, 0x15, 0x76, 0x7a, 0x02, 0xa6, 0xdc, 0x34, 0xe9, 0xde, 0x6a, 0xc5, 0xa7, 0x94, + 0x7e, 0xd1, 0x9b, 0x83, 0x45, 0xba, 0x0c, 0x4e, 0xff, 0x1f, 0xca, 0xa4, 0xb6, 0xee, 0x1c, 0x64, 0x03, 0x00}; } // namespace web_server } // namespace esphome From b8630363e0492b88393efe02c93b7f9553b405c5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 8 Oct 2024 03:47:07 +1100 Subject: [PATCH 2475/2607] [online_image] Bugfix: Use std::string instead of const char * (#7556) --- esphome/components/online_image/__init__.py | 2 +- esphome/components/online_image/online_image.h | 3 +-- tests/components/online_image/common-esp32.yaml | 4 ++-- tests/components/online_image/common.yaml | 8 ++++++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/esphome/components/online_image/__init__.py b/esphome/components/online_image/__init__.py index d9a7609543..dfb10137aa 100644 --- a/esphome/components/online_image/__init__.py +++ b/esphome/components/online_image/__init__.py @@ -125,7 +125,7 @@ async def online_image_action_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_URL in config: - template_ = await cg.templatable(config[CONF_URL], args, cg.const_char_ptr) + template_ = await cg.templatable(config[CONF_URL], args, cg.std_string) cg.add(var.set_url(template_)) return var diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h index 775cc46e0b..51c11478cd 100644 --- a/esphome/components/online_image/online_image.h +++ b/esphome/components/online_image/online_image.h @@ -157,7 +157,7 @@ class OnlineImage : public PollingComponent, template class OnlineImageSetUrlAction : public Action { public: OnlineImageSetUrlAction(OnlineImage *parent) : parent_(parent) {} - TEMPLATABLE_VALUE(const char *, url) + TEMPLATABLE_VALUE(std::string, url) void play(Ts... x) override { this->parent_->set_url(this->url_.value(x...)); this->parent_->update(); @@ -170,7 +170,6 @@ template class OnlineImageSetUrlAction : public Action { template class OnlineImageReleaseAction : public Action { public: OnlineImageReleaseAction(OnlineImage *parent) : parent_(parent) {} - TEMPLATABLE_VALUE(const char *, url) void play(Ts... x) override { this->parent_->release(); } protected: diff --git a/tests/components/online_image/common-esp32.yaml b/tests/components/online_image/common-esp32.yaml index d3a304cdc0..787a1ad368 100644 --- a/tests/components/online_image/common-esp32.yaml +++ b/tests/components/online_image/common-esp32.yaml @@ -4,13 +4,13 @@ spi: - id: spi_main_lcd clk_pin: 16 mosi_pin: 17 - miso_pin: 15 + miso_pin: 18 display: - platform: ili9xxx id: main_lcd model: ili9342 - cs_pin: 12 + cs_pin: 20 dc_pin: 13 reset_pin: 21 invert_colors: true diff --git a/tests/components/online_image/common.yaml b/tests/components/online_image/common.yaml index 8f7ea6238b..5c6feb4c81 100644 --- a/tests/components/online_image/common.yaml +++ b/tests/components/online_image/common.yaml @@ -34,4 +34,12 @@ time: - online_image.set_url: id: online_rgba_image url: http://www.example.org/example.png + - online_image.set_url: + id: online_rgba_image + url: !lambda |- + return "http://www.example.org/example.png"; + - online_image.set_url: + id: online_rgba_image + url: !lambda |- + return str_sprintf("http://homeassistant.local:8123"); From 52e59d1dadb1daa3679078f5246b4811bcf1af03 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:28:59 +1100 Subject: [PATCH 2476/2607] [ili9xxx] Put display into sleep mode on shutdown. (#7555) --- esphome/components/ili9xxx/ili9xxx_display.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 5033f702de..c141739d2a 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -89,6 +89,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, void dump_config() override; void setup() override; + void on_shutdown() override { this->command(ILI9XXX_SLPIN); } display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, From 659239e8cdd3d6890153e28197ae9d7f1cac9dc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:34:15 +1300 Subject: [PATCH 2477/2607] Bump actions/upload-artifact from 4.4.0 to 4.4.1 (#7559) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8995c500ef..99e201b1a7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,7 +141,7 @@ jobs: echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT - name: Upload digests - uses: actions/upload-artifact@v4.4.0 + uses: actions/upload-artifact@v4.4.1 with: name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests From 3804b3b7595d32752568fb9e139171e933db21e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:34:26 +1300 Subject: [PATCH 2478/2607] Bump actions/cache from 4.0.2 to 4.1.0 in /.github/actions/restore-python (#7560) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index c618a5ca97..7f4de1e378 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v4.0.2 + uses: actions/cache/restore@v4.1.0 with: path: venv # yamllint disable-line rule:line-length From 6139b933c50302b5b0428ba2d13929ee6776271e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:00:10 +0000 Subject: [PATCH 2479/2607] Bump actions/cache from 4.0.2 to 4.1.0 (#7558) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c4fa65695..b0bae6cbec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v4.0.2 + uses: actions/cache@v4.1.0 with: path: venv # yamllint disable-line rule:line-length @@ -302,14 +302,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@v4.0.2 + uses: actions/cache@v4.1.0 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@v4.0.2 + uses: actions/cache/restore@v4.1.0 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} From 9211aad524ae52a16031cf90242715cf85b11a76 Mon Sep 17 00:00:00 2001 From: baldisos <76702976+baldisos@users.noreply.github.com> Date: Wed, 9 Oct 2024 03:33:50 +0200 Subject: [PATCH 2480/2607] Update radon_eye_listener.cpp for more possible variants (#7567) --- .../components/radon_eye_ble/radon_eye_listener.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/esphome/components/radon_eye_ble/radon_eye_listener.cpp b/esphome/components/radon_eye_ble/radon_eye_listener.cpp index 340322c188..a4c79db753 100644 --- a/esphome/components/radon_eye_ble/radon_eye_listener.cpp +++ b/esphome/components/radon_eye_ble/radon_eye_listener.cpp @@ -1,5 +1,7 @@ #include "radon_eye_listener.h" #include "esphome/core/log.h" +#include +#include #ifdef USE_ESP32 @@ -10,9 +12,14 @@ static const char *const TAG = "radon_eye_ble"; bool RadonEyeListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { if (not device.get_name().empty()) { - if (device.get_name().rfind("FR:R", 0) == 0) { - // This is an RD200, I think - ESP_LOGD(TAG, "Found Radon Eye RD200 device Name: %s (MAC: %s)", device.get_name().c_str(), + // Vector containing the prefixes to search for + std::vector prefixes = {"FR:R", "FR:I", "FR:H"}; + + // Check if the device name starts with any of the prefixes + if (std::any_of(prefixes.begin(), prefixes.end(), + [&](const std::string &prefix) { return device.get_name().rfind(prefix, 0) == 0; })) { + // Device found + ESP_LOGD(TAG, "Found Radon Eye device Name: %s (MAC: %s)", device.get_name().c_str(), device.address_str().c_str()); } } From 1a567b6986e4208c23677afef1b8e9eeaa9cd36a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:41:58 +1100 Subject: [PATCH 2481/2607] [cst816] Allow skipping i2c probe (#7557) --- .../components/cst816/touchscreen/__init__.py | 13 ++++--- .../cst816/touchscreen/cst816_touchscreen.cpp | 39 ++++++++++--------- .../cst816/touchscreen/cst816_touchscreen.h | 2 + tests/components/cst816/common.yaml | 5 ++- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/esphome/components/cst816/touchscreen/__init__.py b/esphome/components/cst816/touchscreen/__init__.py index a3603ef575..288ca17593 100644 --- a/esphome/components/cst816/touchscreen/__init__.py +++ b/esphome/components/cst816/touchscreen/__init__.py @@ -1,11 +1,10 @@ -import esphome.codegen as cg -import esphome.config_validation as cv - from esphome import pins +import esphome.codegen as cg from esphome.components import i2c, touchscreen -from esphome.const import CONF_INTERRUPT_PIN, CONF_ID, CONF_RESET_PIN -from .. import cst816_ns +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from .. import cst816_ns CST816Touchscreen = cst816_ns.class_( "CST816Touchscreen", @@ -14,11 +13,14 @@ CST816Touchscreen = cst816_ns.class_( ) CST816ButtonListener = cst816_ns.class_("CST816ButtonListener") + +CONF_SKIP_PROBE = "skip_probe" CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(CST816Touchscreen), cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_SKIP_PROBE, default=False): cv.boolean, } ).extend(i2c.i2c_device_schema(0x15)) @@ -28,6 +30,7 @@ async def to_code(config): await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) + cg.add(var.set_skip_probe(config[CONF_SKIP_PROBE])) if interrupt_pin := config.get(CONF_INTERRUPT_PIN): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) if reset_pin := config.get(CONF_RESET_PIN): diff --git a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp index 9e59810c7e..7dcb130e20 100644 --- a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +++ b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp @@ -8,32 +8,33 @@ void CST816Touchscreen::continue_setup_() { this->interrupt_pin_->setup(); this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); } - if (!this->read_byte(REG_CHIP_ID, &this->chip_id_)) { + if (this->read_byte(REG_CHIP_ID, &this->chip_id_)) { + switch (this->chip_id_) { + case CST820_CHIP_ID: + case CST826_CHIP_ID: + case CST716_CHIP_ID: + case CST816S_CHIP_ID: + case CST816D_CHIP_ID: + case CST816T_CHIP_ID: + break; + default: + this->mark_failed(); + this->status_set_error(str_sprintf("Unknown chip ID 0x%02X", this->chip_id_).c_str()); + return; + } + this->write_byte(REG_IRQ_CTL, IRQ_EN_MOTION); + } else if (!this->skip_probe_) { + this->status_set_error("Failed to read chip id"); this->mark_failed(); - esph_log_e(TAG, "Failed to read chip id"); return; } - switch (this->chip_id_) { - case CST820_CHIP_ID: - case CST826_CHIP_ID: - case CST716_CHIP_ID: - case CST816S_CHIP_ID: - case CST816D_CHIP_ID: - case CST816T_CHIP_ID: - break; - default: - this->mark_failed(); - esph_log_e(TAG, "Unknown chip ID 0x%02X", this->chip_id_); - return; - } - this->write_byte(REG_IRQ_CTL, IRQ_EN_MOTION); if (this->x_raw_max_ == this->x_raw_min_) { this->x_raw_max_ = this->display_->get_native_width(); } if (this->y_raw_max_ == this->y_raw_min_) { this->y_raw_max_ = this->display_->get_native_height(); } - esph_log_config(TAG, "CST816 Touchscreen setup complete"); + ESP_LOGCONFIG(TAG, "CST816 Touchscreen setup complete"); } void CST816Touchscreen::update_button_state_(bool state) { @@ -45,7 +46,7 @@ void CST816Touchscreen::update_button_state_(bool state) { } void CST816Touchscreen::setup() { - esph_log_config(TAG, "Setting up CST816 Touchscreen..."); + ESP_LOGCONFIG(TAG, "Setting up CST816 Touchscreen..."); if (this->reset_pin_ != nullptr) { this->reset_pin_->setup(); this->reset_pin_->digital_write(true); @@ -73,7 +74,7 @@ void CST816Touchscreen::update_touches() { uint16_t x = encode_uint16(data[REG_XPOS_HIGH] & 0xF, data[REG_XPOS_LOW]); uint16_t y = encode_uint16(data[REG_YPOS_HIGH] & 0xF, data[REG_YPOS_LOW]); - esph_log_v(TAG, "Read touch %d/%d", x, y); + ESP_LOGV(TAG, "Read touch %d/%d", x, y); if (x >= this->x_raw_max_) { this->update_button_state_(true); } else { diff --git a/esphome/components/cst816/touchscreen/cst816_touchscreen.h b/esphome/components/cst816/touchscreen/cst816_touchscreen.h index 24e664e7ee..dc00e675ba 100644 --- a/esphome/components/cst816/touchscreen/cst816_touchscreen.h +++ b/esphome/components/cst816/touchscreen/cst816_touchscreen.h @@ -45,6 +45,7 @@ class CST816Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } + void set_skip_probe(bool skip_probe) { this->skip_probe_ = skip_probe; } protected: void continue_setup_(); @@ -53,6 +54,7 @@ class CST816Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice InternalGPIOPin *interrupt_pin_{}; GPIOPin *reset_pin_{}; uint8_t chip_id_{}; + bool skip_probe_{}; // if set, do not expect to be able to probe the controller on the i2c bus. std::vector button_listeners_; bool button_touched_{}; }; diff --git a/tests/components/cst816/common.yaml b/tests/components/cst816/common.yaml index 91abbfd4f6..765a353d1d 100644 --- a/tests/components/cst816/common.yaml +++ b/tests/components/cst816/common.yaml @@ -4,6 +4,7 @@ touchscreen: interrupt_pin: number: 21 reset_pin: GPIO16 + skip_probe: false transform: mirror_x: false mirror_y: false @@ -11,14 +12,14 @@ touchscreen: i2c: sda: 3 - scl: 2 + scl: 4 display: - id: my_display platform: ili9xxx dimensions: 480x320 model: ST7796 - cs_pin: 15 + cs_pin: 18 dc_pin: 20 reset_pin: 22 transform: From fc97a6d1e3f49d8a6914e450ac4f374c238ae9bc Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:43:28 +1100 Subject: [PATCH 2482/2607] [lvgl] Fix text component (#7563) --- esphome/components/lvgl/text/__init__.py | 6 +++--- tests/components/lvgl/common.yaml | 6 ++++++ tests/components/lvgl/lvgl-package.yaml | 4 ++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 540591d24b..a59e703591 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -34,13 +34,13 @@ async def to_code(config): widget = widget[0] await wait_for_widgets() async with LambdaContext([(cg.std_string, "text_value")]) as control: - await widget.set_property("text", "text_value.c_str())") - lv.event_send(widget.obj, API_EVENT, None) + await widget.set_property("text", "text_value.c_str()") + lv.event_send(widget.obj, API_EVENT, cg.nullptr) control.add(textvar.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as lamb: lv_add(textvar.publish_state(widget.get_value())) async with LvContext(paren): - widget.var.set_control_lambda(await control.get_lambda()) + lv_add(textvar.set_control_lambda(await control.get_lambda())) lv_add( paren.add_event_cb( widget.obj, diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 7ef7772ac9..ad935ae563 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -135,3 +135,9 @@ wifi: time: platform: sntp id: time_id + +text: + - id: lvgl_text + platform: lvgl + widget: hello_label + mode: text diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index c968198e26..1770c1bfbc 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -151,6 +151,10 @@ lvgl: align: center text_font: montserrat_40 border_post: true + on_press: + lvgl.label.update: + id: hello_label + text: Goodbye on_click: then: - lvgl.animimg.stop: anim_img From 66f500e594ca29912e0f6d35d4965c23244a101f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:49:33 +1100 Subject: [PATCH 2483/2607] [template/binary_sensor] Implement `condition:` option as alternative to lambda. (#7561) --- .../template/binary_sensor/__init__.py | 25 ++++++++++++++----- tests/components/template/common.yaml | 7 ++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py index 4ce89503de..c93876380d 100644 --- a/esphome/components/template/binary_sensor/__init__.py +++ b/esphome/components/template/binary_sensor/__init__.py @@ -1,8 +1,10 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import binary_sensor -from esphome.const import CONF_ID, CONF_LAMBDA, CONF_STATE +import esphome.config_validation as cv +from esphome.const import CONF_CONDITION, CONF_ID, CONF_LAMBDA, CONF_STATE +from esphome.cpp_generator import LambdaExpression + from .. import template_ns TemplateBinarySensor = template_ns.class_( @@ -13,7 +15,10 @@ CONFIG_SCHEMA = ( binary_sensor.binary_sensor_schema(TemplateBinarySensor) .extend( { - cv.Optional(CONF_LAMBDA): cv.returning_lambda, + cv.Exclusive(CONF_LAMBDA, CONF_CONDITION): cv.returning_lambda, + cv.Exclusive( + CONF_CONDITION, CONF_CONDITION + ): automation.validate_potentially_and_condition, } ) .extend(cv.COMPONENT_SCHEMA) @@ -24,9 +29,17 @@ async def to_code(config): var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) - if CONF_LAMBDA in config: + if lamb := config.get(CONF_LAMBDA): template_ = await cg.process_lambda( - config[CONF_LAMBDA], [], return_type=cg.optional.template(bool) + lamb, [], return_type=cg.optional.template(bool) + ) + cg.add(var.set_template(template_)) + if condition := config.get(CONF_CONDITION): + condition = await automation.build_condition( + condition, cg.TemplateArguments(), [] + ) + template_ = LambdaExpression( + f"return {condition.check()};", [], return_type=cg.optional.template(bool) ) cg.add(var.set_template(template_)) diff --git a/tests/components/template/common.yaml b/tests/components/template/common.yaml index 9e89424d8a..3565926933 100644 --- a/tests/components/template/common.yaml +++ b/tests/components/template/common.yaml @@ -46,6 +46,13 @@ binary_sensor: // Garage Door is closed. return false; } + - platform: template + id: other_binary_sensor + name: "Garage Door Closed" + condition: + sensor.in_range: + id: template_sens + below: 30.0 output: - platform: template From 69467ea6ff9fd949ffe5913601e8809adbefee57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:51:23 +1300 Subject: [PATCH 2484/2607] Bump actions/upload-artifact from 4.4.1 to 4.4.2 (#7569) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 99e201b1a7..8ffff895a0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,7 +141,7 @@ jobs: echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT - name: Upload digests - uses: actions/upload-artifact@v4.4.1 + uses: actions/upload-artifact@v4.4.2 with: name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests From 94ad1237ce2252bb31c3f734be1be68ddb948482 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:51:31 +1300 Subject: [PATCH 2485/2607] Bump actions/cache from 4.1.0 to 4.1.1 (#7570) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0bae6cbec..38527c20c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v4.1.0 + uses: actions/cache@v4.1.1 with: path: venv # yamllint disable-line rule:line-length @@ -302,14 +302,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@v4.1.0 + uses: actions/cache@v4.1.1 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@v4.1.0 + uses: actions/cache/restore@v4.1.1 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} From 26694cb55e0740524b02a3b373349cc08db826f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:51:43 +1300 Subject: [PATCH 2486/2607] Bump actions/cache from 4.1.0 to 4.1.1 in /.github/actions/restore-python (#7571) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 7f4de1e378..1f5812691e 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v4.1.0 + uses: actions/cache/restore@v4.1.1 with: path: venv # yamllint disable-line rule:line-length From 4a9d3a39275b53ff46e27b8a81da4e4384c0f713 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:01:49 +1300 Subject: [PATCH 2487/2607] Bump version to 2024.10.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 08fb34976b..0752e3b169 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.0-dev" +__version__ = "2024.10.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 1c05f5af03c3ad8b564d478d4c2b5319191143ee Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:01:49 +1300 Subject: [PATCH 2488/2607] Bump version to 2024.11.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 08fb34976b..16f30c179d 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.0-dev" +__version__ = "2024.11.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 4bac9707fe3e002bb140ac27ffee7a14fa693784 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 9 Oct 2024 03:44:19 -0700 Subject: [PATCH 2489/2607] fix uart settings check (#7573) --- esphome/components/cse7766/cse7766.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index 47058badce..48240464b3 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -244,7 +244,7 @@ void CSE7766Component::dump_config() { LOG_SENSOR(" ", "Apparent Power", this->apparent_power_sensor_); LOG_SENSOR(" ", "Reactive Power", this->reactive_power_sensor_); LOG_SENSOR(" ", "Power Factor", this->power_factor_sensor_); - this->check_uart_settings(4800); + this->check_uart_settings(4800, 1, uart::UART_CONFIG_PARITY_EVEN); } } // namespace cse7766 From b08432bd0dbb5617dc95f61f09dce34724971519 Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Thu, 10 Oct 2024 05:44:07 +0300 Subject: [PATCH 2490/2607] Update `pillow` to 10.4.0 (#7566) --- esphome/components/font/__init__.py | 8 ++++---- requirements_optional.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index b5ed02e89a..dacd0779b1 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -98,13 +98,13 @@ def validate_pillow_installed(value): except ImportError as err: raise cv.Invalid( "Please install the pillow python package to use this feature. " - '(pip install "pillow==10.2.0")' + '(pip install "pillow==10.4.0")' ) from err - if version.parse(PIL.__version__) != version.parse("10.2.0"): + if version.parse(PIL.__version__) != version.parse("10.4.0"): raise cv.Invalid( - "Please update your pillow installation to 10.2.0. " - '(pip install "pillow==10.2.0")' + "Please update your pillow installation to 10.4.0. " + '(pip install "pillow==10.4.0")' ) return value diff --git a/requirements_optional.txt b/requirements_optional.txt index c984d41332..2d57c5fd96 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,2 +1,2 @@ -pillow==10.2.0 +pillow==10.4.0 cairosvg==2.7.1 From c18bd3ac8159918679452431fbcfef100300e60c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:07:40 +1300 Subject: [PATCH 2491/2607] Bump actions/upload-artifact from 4.4.2 to 4.4.3 (#7575) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ffff895a0..26a213f170 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,7 +141,7 @@ jobs: echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT - name: Upload digests - uses: actions/upload-artifact@v4.4.2 + uses: actions/upload-artifact@v4.4.3 with: name: digests-${{ steps.sanitize.outputs.name }} path: /tmp/digests From cedb671f075dc2ceb9c3e5f01c0e74268312a4e7 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Thu, 10 Oct 2024 21:51:21 +0300 Subject: [PATCH 2492/2607] [fix] ESP32-C6 Reset Reasons (#7578) --- esphome/components/debug/debug_esp32.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp index 34aea9e26b..cb4330f422 100644 --- a/esphome/components/debug/debug_esp32.cpp +++ b/esphome/components/debug/debug_esp32.cpp @@ -36,7 +36,8 @@ std::string DebugComponent::get_reset_reason_() { break; #if defined(USE_ESP32_VARIANT_ESP32) case SW_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ + defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) case RTC_SW_SYS_RESET: #endif reset_reason = "Software Reset Digital Core"; @@ -72,14 +73,16 @@ std::string DebugComponent::get_reset_reason_() { case TGWDT_CPU_RESET: reset_reason = "Timer Group Reset CPU"; break; -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ + defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) case TG0WDT_CPU_RESET: reset_reason = "Timer Group 0 Reset CPU"; break; #endif #if defined(USE_ESP32_VARIANT_ESP32) case SW_CPU_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ + defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) case RTC_SW_CPU_RESET: #endif reset_reason = "Software Reset CPU"; @@ -98,27 +101,32 @@ std::string DebugComponent::get_reset_reason_() { case RTCWDT_RTC_RESET: reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; break; -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ + defined(USE_ESP32_VARIANT_ESP32C6) case TG1WDT_CPU_RESET: reset_reason = "Timer Group 1 Reset CPU"; break; case SUPER_WDT_RESET: reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; break; - case GLITCH_RTC_RESET: - reset_reason = "Glitch Reset Digital Core And RTC Module"; - break; case EFUSE_RESET: reset_reason = "eFuse Reset Digital Core"; break; #endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case GLITCH_RTC_RESET: + reset_reason = "Glitch Reset Digital Core And RTC Module"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) case USB_UART_CHIP_RESET: reset_reason = "USB UART Reset Digital Core"; break; case USB_JTAG_CHIP_RESET: reset_reason = "USB JTAG Reset Digital Core"; break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) case POWER_GLITCH_RESET: reset_reason = "Power Glitch Reset Digital Core And RTC Module"; break; From efe4c5e3bc496d9f1f4d152c28a27e505b9f3024 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 12 Oct 2024 06:13:32 +1300 Subject: [PATCH 2493/2607] [light] Add ``initial_state`` configuration (#7577) --- esphome/components/light/__init__.py | 33 ++++- esphome/components/light/automation.py | 73 +++++----- esphome/components/light/effects.py | 80 +++++------ esphome/components/light/light_state.cpp | 22 +-- esphome/components/light/light_state.h | 34 +++++ esphome/components/light/types.py | 4 +- esphome/const.py | 1 + tests/components/light/common.yaml | 125 ++++++++++++++++++ tests/components/light/test.esp32-ard.yaml | 115 +--------------- tests/components/light/test.esp32-c3-ard.yaml | 115 +--------------- tests/components/light/test.esp32-c3-idf.yaml | 115 +--------------- tests/components/light/test.esp32-idf.yaml | 115 +--------------- tests/components/light/test.esp8266-ard.yaml | 115 +--------------- tests/components/light/test.rp2040-ard.yaml | 115 +--------------- 14 files changed, 287 insertions(+), 775 deletions(-) create mode 100644 tests/components/light/common.yaml diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 7e16b7a648..feac385b66 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -3,27 +3,39 @@ import esphome.codegen as cg from esphome.components import mqtt, power_supply, web_server import esphome.config_validation as cv from esphome.const import ( + CONF_BLUE, + CONF_BRIGHTNESS, + CONF_COLD_WHITE, CONF_COLD_WHITE_COLOR_TEMPERATURE, + CONF_COLOR_BRIGHTNESS, CONF_COLOR_CORRECT, + CONF_COLOR_MODE, + CONF_COLOR_TEMPERATURE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_FLASH_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, + CONF_GREEN, CONF_ID, + CONF_INITIAL_STATE, CONF_MQTT_ID, CONF_ON_STATE, CONF_ON_TURN_OFF, CONF_ON_TURN_ON, CONF_POWER_SUPPLY, + CONF_RED, CONF_RESTORE_MODE, + CONF_STATE, CONF_TRIGGER_ID, + CONF_WARM_WHITE, CONF_WARM_WHITE_COLOR_TEMPERATURE, CONF_WEB_SERVER, + CONF_WHITE, ) from esphome.core import coroutine_with_priority from esphome.cpp_helpers import setup_entity -from .automation import light_control_to_code # noqa +from .automation import LIGHT_STATE_SCHEMA from .effects import ( ADDRESSABLE_EFFECTS, BINARY_EFFECTS, @@ -35,8 +47,10 @@ from .effects import ( from .types import ( # noqa AddressableLight, AddressableLightState, + ColorMode, LightOutput, LightState, + LightStateRTCState, LightStateTrigger, LightTurnOffTrigger, LightTurnOnTrigger, @@ -85,6 +99,7 @@ LIGHT_SCHEMA = ( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger), } ), + cv.Optional(CONF_INITIAL_STATE): LIGHT_STATE_SCHEMA, } ) ) @@ -145,6 +160,22 @@ async def setup_light_core_(light_var, output_var, config): cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE])) + if (initial_state_config := config.get(CONF_INITIAL_STATE)) is not None: + initial_state = LightStateRTCState( + initial_state_config.get(CONF_COLOR_MODE, ColorMode.UNKNOWN), + initial_state_config.get(CONF_STATE, False), + initial_state_config.get(CONF_BRIGHTNESS, 1.0), + initial_state_config.get(CONF_COLOR_BRIGHTNESS, 1.0), + initial_state_config.get(CONF_RED, 1.0), + initial_state_config.get(CONF_GREEN, 1.0), + initial_state_config.get(CONF_BLUE, 1.0), + initial_state_config.get(CONF_WHITE, 1.0), + initial_state_config.get(CONF_COLOR_TEMPERATURE, 1.0), + initial_state_config.get(CONF_COLD_WHITE, 1.0), + initial_state_config.get(CONF_WARM_WHITE, 1.0), + ) + cg.add(light_var.set_initial_state(initial_state)) + if ( default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH) ) is not None: diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py index ec0375f54a..e5aa8fa0e9 100644 --- a/esphome/components/light/automation.py +++ b/esphome/components/light/automation.py @@ -1,41 +1,42 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome import automation from esphome.const import ( - CONF_ID, - CONF_COLOR_MODE, - CONF_TRANSITION_LENGTH, - CONF_STATE, - CONF_FLASH_LENGTH, - CONF_EFFECT, - CONF_BRIGHTNESS, - CONF_COLOR_BRIGHTNESS, - CONF_RED, - CONF_GREEN, CONF_BLUE, - CONF_WHITE, - CONF_COLOR_TEMPERATURE, + CONF_BRIGHTNESS, + CONF_BRIGHTNESS_LIMITS, CONF_COLD_WHITE, - CONF_WARM_WHITE, + CONF_COLOR_BRIGHTNESS, + CONF_COLOR_MODE, + CONF_COLOR_TEMPERATURE, + CONF_EFFECT, + CONF_FLASH_LENGTH, + CONF_GREEN, + CONF_ID, + CONF_LIMIT_MODE, + CONF_MAX_BRIGHTNESS, + CONF_MIN_BRIGHTNESS, CONF_RANGE_FROM, CONF_RANGE_TO, - CONF_BRIGHTNESS_LIMITS, - CONF_LIMIT_MODE, - CONF_MIN_BRIGHTNESS, - CONF_MAX_BRIGHTNESS, + CONF_RED, + CONF_STATE, + CONF_TRANSITION_LENGTH, + CONF_WARM_WHITE, + CONF_WHITE, ) + from .types import ( - ColorMode, COLOR_MODES, LIMIT_MODES, - DimRelativeAction, - ToggleAction, - LightState, - LightControlAction, AddressableLightState, AddressableSet, - LightIsOnCondition, + ColorMode, + DimRelativeAction, + LightControlAction, LightIsOffCondition, + LightIsOnCondition, + LightState, + ToggleAction, ) @@ -62,18 +63,10 @@ async def light_toggle_to_code(config, action_id, template_arg, args): return var -LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema( +LIGHT_STATE_SCHEMA = cv.Schema( { - cv.Required(CONF_ID): cv.use_id(LightState), cv.Optional(CONF_COLOR_MODE): cv.enum(COLOR_MODES, upper=True, space="_"), cv.Optional(CONF_STATE): cv.templatable(cv.boolean), - cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable( - cv.positive_time_period_milliseconds - ), - cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable( - cv.positive_time_period_milliseconds - ), - cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string), cv.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage), cv.Optional(CONF_COLOR_BRIGHTNESS): cv.templatable(cv.percentage), cv.Optional(CONF_RED): cv.templatable(cv.percentage), @@ -85,6 +78,20 @@ LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema( cv.Optional(CONF_WARM_WHITE): cv.templatable(cv.percentage), } ) + +LIGHT_CONTROL_ACTION_SCHEMA = LIGHT_STATE_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.use_id(LightState), + cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable( + cv.positive_time_period_milliseconds + ), + cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable( + cv.positive_time_period_milliseconds + ), + cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string), + } +) + LIGHT_TURN_OFF_ACTION_SCHEMA = automation.maybe_simple_id( { cv.Required(CONF_ID): cv.use_id(LightState), diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index be50f63321..67c318eb8e 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -1,59 +1,59 @@ -from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome import automation - from esphome.const import ( - CONF_NAME, - CONF_LAMBDA, - CONF_UPDATE_INTERVAL, - CONF_TRANSITION_LENGTH, - CONF_COLORS, - CONF_STATE, - CONF_DURATION, - CONF_BRIGHTNESS, - CONF_COLOR_MODE, - CONF_COLOR_BRIGHTNESS, - CONF_RED, - CONF_GREEN, - CONF_BLUE, - CONF_WHITE, - CONF_COLOR_TEMPERATURE, - CONF_COLD_WHITE, - CONF_WARM_WHITE, CONF_ALPHA, + CONF_BLUE, + CONF_BRIGHTNESS, + CONF_COLD_WHITE, + CONF_COLOR_BRIGHTNESS, + CONF_COLOR_MODE, + CONF_COLOR_TEMPERATURE, + CONF_COLORS, + CONF_DURATION, + CONF_GREEN, CONF_INTENSITY, - CONF_SPEED, - CONF_WIDTH, - CONF_NUM_LEDS, - CONF_RANDOM, - CONF_SEQUENCE, + CONF_LAMBDA, CONF_MAX_BRIGHTNESS, CONF_MIN_BRIGHTNESS, + CONF_NAME, + CONF_NUM_LEDS, + CONF_RANDOM, + CONF_RED, + CONF_SEQUENCE, + CONF_SPEED, + CONF_STATE, + CONF_TRANSITION_LENGTH, + CONF_UPDATE_INTERVAL, + CONF_WARM_WHITE, + CONF_WHITE, + CONF_WIDTH, ) +from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.util import Registry + from .types import ( - ColorMode, COLOR_MODES, + AddressableColorWipeEffect, + AddressableColorWipeEffectColor, + AddressableFireworksEffect, + AddressableFlickerEffect, + AddressableLambdaLightEffect, + AddressableLightRef, + AddressableRainbowLightEffect, + AddressableRandomTwinkleEffect, + AddressableScanEffect, + AddressableTwinkleEffect, + AutomationLightEffect, + Color, + ColorMode, + FlickerLightEffect, LambdaLightEffect, + LightColorValues, PulseLightEffect, RandomLightEffect, StrobeLightEffect, StrobeLightEffectColor, - LightColorValues, - AddressableLightRef, - AddressableLambdaLightEffect, - FlickerLightEffect, - AddressableRainbowLightEffect, - AddressableColorWipeEffect, - AddressableColorWipeEffectColor, - AddressableScanEffect, - AddressableTwinkleEffect, - AddressableRandomTwinkleEffect, - AddressableFireworksEffect, - AddressableFlickerEffect, - AutomationLightEffect, - Color, ) CONF_ADD_LED_INTERVAL = "add_led_interval" diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index fe6538e65e..16b78a17bd 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -1,6 +1,7 @@ #include "esphome/core/log.h" -#include "light_state.h" + #include "light_output.h" +#include "light_state.h" #include "transformers.h" namespace esphome { @@ -16,21 +17,6 @@ LightCall LightState::turn_off() { return this->make_call().set_state(false); } LightCall LightState::toggle() { return this->make_call().set_state(!this->remote_values.is_on()); } LightCall LightState::make_call() { return LightCall(this); } -struct LightStateRTCState { - ColorMode color_mode{ColorMode::UNKNOWN}; - bool state{false}; - float brightness{1.0f}; - float color_brightness{1.0f}; - float red{1.0f}; - float green{1.0f}; - float blue{1.0f}; - float white{1.0f}; - float color_temp{1.0f}; - float cold_white{1.0f}; - float warm_white{1.0f}; - uint32_t effect{0}; -}; - void LightState::setup() { ESP_LOGCONFIG(TAG, "Setting up light '%s'...", this->get_name().c_str()); @@ -48,6 +34,9 @@ void LightState::setup() { auto call = this->make_call(); LightStateRTCState recovered{}; + if (this->initial_state_.has_value()) { + recovered = *this->initial_state_; + } switch (this->restore_mode_) { case LIGHT_RESTORE_DEFAULT_OFF: case LIGHT_RESTORE_DEFAULT_ON: @@ -175,6 +164,7 @@ void LightState::set_flash_transition_length(uint32_t flash_transition_length) { uint32_t LightState::get_flash_transition_length() const { return this->flash_transition_length_; } void LightState::set_gamma_correct(float gamma_correct) { this->gamma_correct_ = gamma_correct; } void LightState::set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; } +void LightState::set_initial_state(const LightStateRTCState &initial_state) { this->initial_state_ = initial_state; } bool LightState::supports_effects() { return !this->effects_.empty(); } const std::vector &LightState::get_effects() const { return this->effects_; } void LightState::add_effects(const std::vector &effects) { diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index b0aaa453b5..acba986f24 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -28,6 +28,35 @@ enum LightRestoreMode { LIGHT_RESTORE_AND_ON, }; +struct LightStateRTCState { + LightStateRTCState(ColorMode color_mode, bool state, float brightness, float color_brightness, float red, float green, + float blue, float white, float color_temp, float cold_white, float warm_white) + : color_mode(color_mode), + state(state), + brightness(brightness), + color_brightness(color_brightness), + red(red), + green(green), + blue(blue), + white(white), + color_temp(color_temp), + cold_white(cold_white), + warm_white(warm_white) {} + LightStateRTCState() = default; + ColorMode color_mode{ColorMode::UNKNOWN}; + bool state{false}; + float brightness{1.0f}; + float color_brightness{1.0f}; + float red{1.0f}; + float green{1.0f}; + float blue{1.0f}; + float white{1.0f}; + float color_temp{1.0f}; + float cold_white{1.0f}; + float warm_white{1.0f}; + uint32_t effect{0}; +}; + /** This class represents the communication layer between the front-end MQTT layer and the * hardware output layer. */ @@ -116,6 +145,9 @@ class LightState : public EntityBase, public Component { /// Set the restore mode of this light void set_restore_mode(LightRestoreMode restore_mode); + /// Set the initial state of this light + void set_initial_state(const LightStateRTCState &initial_state); + /// Return whether the light has any effects that meet the trait requirements. bool supports_effects(); @@ -212,6 +244,8 @@ class LightState : public EntityBase, public Component { float gamma_correct_{}; /// Restore mode of the light. LightRestoreMode restore_mode_; + /// Initial state of the light. + optional initial_state_{}; /// List of effects for this light. std::vector effects_; diff --git a/esphome/components/light/types.py b/esphome/components/light/types.py index 64483bcc9c..a586bcbd13 100644 --- a/esphome/components/light/types.py +++ b/esphome/components/light/types.py @@ -1,5 +1,5 @@ -import esphome.codegen as cg from esphome import automation +import esphome.codegen as cg # Base light_ns = cg.esphome_ns.namespace("light") @@ -12,6 +12,8 @@ AddressableLightRef = AddressableLight.operator("ref") Color = cg.esphome_ns.class_("Color") LightColorValues = light_ns.class_("LightColorValues") +LightStateRTCState = light_ns.struct("LightStateRTCState") + # Color modes ColorMode = light_ns.enum("ColorMode", is_class=True) COLOR_MODES = { diff --git a/esphome/const.py b/esphome/const.py index 16f30c179d..e02a1506cb 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -398,6 +398,7 @@ CONF_INDOOR = "indoor" CONF_INFRARED = "infrared" CONF_INITIAL_MODE = "initial_mode" CONF_INITIAL_OPTION = "initial_option" +CONF_INITIAL_STATE = "initial_state" CONF_INITIAL_VALUE = "initial_value" CONF_INPUT = "input" CONF_INTEGRATION_TIME = "integration_time" diff --git a/tests/components/light/common.yaml b/tests/components/light/common.yaml new file mode 100644 index 0000000000..a224dbe8bc --- /dev/null +++ b/tests/components/light/common.yaml @@ -0,0 +1,125 @@ +esphome: + on_boot: + then: + - light.toggle: test_binary_light + - light.turn_off: test_rgb_light + - light.turn_on: + id: test_rgb_light + brightness: 100% + red: 100% + green: 100% + blue: 1.0 + - light.control: + id: test_monochromatic_light + state: on + - light.dim_relative: + id: test_monochromatic_light + relative_brightness: 5% + brightness_limits: + max_brightness: 90% + +light: + - platform: binary + id: test_binary_light + name: Binary Light + output: test_binary + effects: + - strobe: + on_state: + - logger.log: Binary light state changed + - platform: monochromatic + id: test_monochromatic_light + name: Monochromatic Light + output: test_ledc_1 + gamma_correct: 2.8 + default_transition_length: 2s + effects: + - strobe: + - flicker: + - flicker: + name: My Flicker + alpha: 98% + intensity: 1.5% + - lambda: + name: My Custom Effect + update_interval: 1s + lambda: |- + static int state = 0; + state += 1; + if (state == 4) + state = 0; + - pulse: + transition_length: 10s + update_interval: 20s + min_brightness: 10% + max_brightness: 90% + - pulse: + name: pulse2 + transition_length: + on_length: 10s + off_length: 5s + update_interval: 15s + min_brightness: 10% + max_brightness: 90% + - platform: rgb + id: test_rgb_light + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + - platform: rgbw + id: test_rgbw_light + name: RGBW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + white: test_ledc_4 + color_interlock: true + - platform: rgbww + id: test_rgbww_light + name: RGBWW Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + cold_white: test_ledc_4 + warm_white: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: rgbct + id: test_rgbct_light + name: RGBCT Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + color_temperature: test_ledc_4 + white_brightness: test_ledc_5 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + color_interlock: true + - platform: cwww + id: test_cwww_light + name: CWWW Light + cold_white: test_ledc_1 + warm_white: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + constant_brightness: true + - platform: color_temperature + id: test_color_temperature_light + name: CT Light + color_temperature: test_ledc_1 + brightness: test_ledc_2 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + - platform: rgb + id: test_rgb_light_initial_state + name: RGB Light + red: test_ledc_1 + green: test_ledc_2 + blue: test_ledc_3 + initial_state: + color_mode: rgb + red: 100% + green: 50% + blue: 50% diff --git a/tests/components/light/test.esp32-ard.yaml b/tests/components/light/test.esp32-ard.yaml index 1d0b4cd8f0..925197182c 100644 --- a/tests/components/light/test.esp32-ard.yaml +++ b/tests/components/light/test.esp32-ard.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 17 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml diff --git a/tests/components/light/test.esp32-c3-ard.yaml b/tests/components/light/test.esp32-c3-ard.yaml index 79171805a6..317d5748a3 100644 --- a/tests/components/light/test.esp32-c3-ard.yaml +++ b/tests/components/light/test.esp32-c3-ard.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 5 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml diff --git a/tests/components/light/test.esp32-c3-idf.yaml b/tests/components/light/test.esp32-c3-idf.yaml index 79171805a6..317d5748a3 100644 --- a/tests/components/light/test.esp32-c3-idf.yaml +++ b/tests/components/light/test.esp32-c3-idf.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 5 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml diff --git a/tests/components/light/test.esp32-idf.yaml b/tests/components/light/test.esp32-idf.yaml index 1d0b4cd8f0..925197182c 100644 --- a/tests/components/light/test.esp32-idf.yaml +++ b/tests/components/light/test.esp32-idf.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 17 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml diff --git a/tests/components/light/test.esp8266-ard.yaml b/tests/components/light/test.esp8266-ard.yaml index 555e1a1b67..518011e925 100644 --- a/tests/components/light/test.esp8266-ard.yaml +++ b/tests/components/light/test.esp8266-ard.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 16 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml diff --git a/tests/components/light/test.rp2040-ard.yaml b/tests/components/light/test.rp2040-ard.yaml index a509bc85c9..a5a37fd559 100644 --- a/tests/components/light/test.rp2040-ard.yaml +++ b/tests/components/light/test.rp2040-ard.yaml @@ -1,23 +1,3 @@ -esphome: - on_boot: - then: - - light.toggle: test_binary_light - - light.turn_off: test_rgb_light - - light.turn_on: - id: test_rgb_light - brightness: 100% - red: 100% - green: 100% - blue: 1.0 - - light.control: - id: test_monochromatic_light - state: on - - light.dim_relative: - id: test_monochromatic_light - relative_brightness: 5% - brightness_limits: - max_brightness: 90% - output: - platform: gpio id: test_binary @@ -38,97 +18,4 @@ output: id: test_ledc_5 pin: 5 -light: - - platform: binary - id: test_binary_light - name: Binary Light - output: test_binary - effects: - - strobe: - on_state: - - logger.log: Binary light state changed - - platform: monochromatic - id: test_monochromatic_light - name: Monochromatic Light - output: test_ledc_1 - gamma_correct: 2.8 - default_transition_length: 2s - effects: - - strobe: - - flicker: - - flicker: - name: My Flicker - alpha: 98% - intensity: 1.5% - - lambda: - name: My Custom Effect - update_interval: 1s - lambda: |- - static int state = 0; - state += 1; - if (state == 4) - state = 0; - - pulse: - transition_length: 10s - update_interval: 20s - min_brightness: 10% - max_brightness: 90% - - pulse: - name: pulse2 - transition_length: - on_length: 10s - off_length: 5s - update_interval: 15s - min_brightness: 10% - max_brightness: 90% - - platform: rgb - id: test_rgb_light - name: RGB Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - - platform: rgbw - id: test_rgbw_light - name: RGBW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - white: test_ledc_4 - color_interlock: true - - platform: rgbww - id: test_rgbww_light - name: RGBWW Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - cold_white: test_ledc_4 - warm_white: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: rgbct - id: test_rgbct_light - name: RGBCT Light - red: test_ledc_1 - green: test_ledc_2 - blue: test_ledc_3 - color_temperature: test_ledc_4 - white_brightness: test_ledc_5 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - color_interlock: true - - platform: cwww - id: test_cwww_light - name: CWWW Light - cold_white: test_ledc_1 - warm_white: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds - constant_brightness: true - - platform: color_temperature - id: test_color_temperature_light - name: CT Light - color_temperature: test_ledc_1 - brightness: test_ledc_2 - cold_white_color_temperature: 153 mireds - warm_white_color_temperature: 500 mireds +<<: !include common.yaml From f2249848585e98e532ae3d71d1df0a9f483a5a5c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 13 Oct 2024 10:51:51 +1100 Subject: [PATCH 2494/2607] [CI] failures when installing using apt-get. (#7593) --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38527c20c7..178b914a1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -315,7 +315,9 @@ jobs: key: platformio-${{ matrix.pio_cache_key }} - name: Install clang-tidy - run: sudo apt-get install clang-tidy-14 + run: | + sudo apt-get update + sudo apt-get install clang-tidy-14 - name: Register problem matchers run: | @@ -397,7 +399,9 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install dependencies - run: sudo apt-get install libsdl2-dev + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 @@ -451,7 +455,9 @@ jobs: run: echo ${{ matrix.components }} - name: Install dependencies - run: sudo apt-get install libsdl2-dev + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 From 42f6095960718bc33b40e21ab3dbec50dc347a05 Mon Sep 17 00:00:00 2001 From: Pietro Date: Sun, 13 Oct 2024 11:24:17 +0200 Subject: [PATCH 2495/2607] [core][esp32_rmt_led_strip] Migrate ExternalRAMAllocator to RAMAllocator And add psram flag to esp32_rmt_led_strip Co-authored-by: guillempages Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- .../esp32_rmt_led_strip/led_strip.cpp | 4 +- .../esp32_rmt_led_strip/led_strip.h | 2 + .../components/esp32_rmt_led_strip/light.py | 4 +- esphome/core/helpers.h | 44 ++++++++++++------- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index 71ab099de5..c2209f7a6c 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -22,7 +22,7 @@ void ESP32RMTLEDStripLightOutput::setup() { size_t buffer_size = this->get_buffer_size_(); - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + RAMAllocator allocator(this->use_psram_ ? 0 : RAMAllocator::ALLOC_INTERNAL); this->buf_ = allocator.allocate(buffer_size); if (this->buf_ == nullptr) { ESP_LOGE(TAG, "Cannot allocate LED buffer!"); @@ -37,7 +37,7 @@ void ESP32RMTLEDStripLightOutput::setup() { return; } - ExternalRAMAllocator rmt_allocator(ExternalRAMAllocator::ALLOW_FAILURE); + RAMAllocator rmt_allocator(this->use_psram_ ? 0 : RAMAllocator::ALLOC_INTERNAL); this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index 43215cf12b..d21bd86e75 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -45,6 +45,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; } void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; } void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; } + void set_use_psram(bool use_psram) { this->use_psram_ = use_psram; } /// Set a maximum refresh rate in µs as some lights do not like being updated too often. void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; } @@ -75,6 +76,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { uint16_t num_leds_; bool is_rgbw_; bool is_wrgb_; + bool use_psram_; rmt_item32_t bit0_, bit1_, reset_; RGBOrder rgb_order_; diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 1e3c2d4f72..79f339e248 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -55,7 +55,7 @@ CHIPSETS = { "SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0), } - +CONF_USE_PSRAM = "use_psram" CONF_IS_WRGB = "is_wrgb" CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_LOW = "bit0_low" @@ -77,6 +77,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, cv.Optional(CONF_IS_WRGB, default=False): cv.boolean, + cv.Optional(CONF_USE_PSRAM, default=True): cv.boolean, cv.Inclusive( CONF_BIT0_HIGH, "custom", @@ -145,6 +146,7 @@ async def to_code(config): cg.add(var.set_rgb_order(config[CONF_RGB_ORDER])) cg.add(var.set_is_rgbw(config[CONF_IS_RGBW])) cg.add(var.set_is_wrgb(config[CONF_IS_WRGB])) + cg.add(var.set_use_psram(config[CONF_USE_PSRAM])) cg.add( var.set_rmt_channel( diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 7df4b84230..7f6fe9bfdc 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -651,35 +651,45 @@ void delay_microseconds_safe(uint32_t us); /// @name Memory management ///@{ -/** An STL allocator that uses SPI RAM. +/** An STL allocator that uses SPI or internal RAM. + * Returns `nullptr` in case no memory is available. * - * By setting flags, it can be configured to don't try main memory if SPI RAM is full or unavailable, and to return - * `nulllptr` instead of aborting when no memory is available. + * By setting flags, it can be configured to: + * - perform external allocation falling back to main memory if SPI RAM is full or unavailable + * - perform external allocation only + * - perform internal allocation only */ -template class ExternalRAMAllocator { +template class RAMAllocator { public: using value_type = T; enum Flags { - NONE = 0, - REFUSE_INTERNAL = 1 << 0, ///< Refuse falling back to internal memory when external RAM is full or unavailable. - ALLOW_FAILURE = 1 << 1, ///< Don't abort when memory allocation fails. + NONE = 0, // Perform external allocation and fall back to internal memory + ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only. + ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only. + ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility. }; - ExternalRAMAllocator() = default; - ExternalRAMAllocator(Flags flags) : flags_{flags} {} - template constexpr ExternalRAMAllocator(const ExternalRAMAllocator &other) : flags_{other.flags_} {} + RAMAllocator() = default; + RAMAllocator(uint8_t flags) : flags_{flags} {} + template constexpr RAMAllocator(const RAMAllocator &other) : flags_{other.flags_} {} T *allocate(size_t n) { size_t size = n * sizeof(T); T *ptr = nullptr; #ifdef USE_ESP32 - ptr = static_cast(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); -#endif - if (ptr == nullptr && (this->flags_ & Flags::REFUSE_INTERNAL) == 0) + // External allocation by default or if explicitely requested + if ((this->flags_ & Flags::ALLOC_EXTERNAL) || ((this->flags_ & Flags::ALLOC_INTERNAL) == 0)) { + ptr = static_cast(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); + } + // Fallback to internal allocation if explicitely requested or no flag is specified + if (ptr == nullptr && ((this->flags_ & Flags::ALLOC_INTERNAL) || (this->flags_ & Flags::ALLOC_EXTERNAL) == 0)) { ptr = static_cast(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc) - if (ptr == nullptr && (this->flags_ & Flags::ALLOW_FAILURE) == 0) - abort(); + } +#else + // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported + ptr = static_cast(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc) +#endif return ptr; } @@ -688,9 +698,11 @@ template class ExternalRAMAllocator { } private: - Flags flags_{Flags::ALLOW_FAILURE}; + uint8_t flags_{Flags::ALLOW_FAILURE}; }; +template using ExternalRAMAllocator = RAMAllocator; + /// @} /// @name Internal functions From cf14c02b8a3c1e71ed2dae186481822225e322cf Mon Sep 17 00:00:00 2001 From: RFDarter Date: Sun, 13 Oct 2024 20:50:13 +0200 Subject: [PATCH 2496/2607] [web_server] Event component grouping (#7586) --- esphome/components/event/__init__.py | 32 ++++++++++++-------- esphome/components/web_server/web_server.cpp | 8 ++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py index 031a4c0de8..a7732dfcaf 100644 --- a/esphome/components/event/__init__.py +++ b/esphome/components/event/__init__.py @@ -1,6 +1,6 @@ from esphome import automation import esphome.codegen as cg -from esphome.components import mqtt +from esphome.components import mqtt, web_server import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_ON_EVENT, CONF_TRIGGER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_BUTTON, DEVICE_CLASS_DOORBELL, DEVICE_CLASS_EMPTY, @@ -40,17 +41,21 @@ EventTrigger = event_ns.class_("EventTrigger", automation.Trigger.template()) validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") -EVENT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent), - cv.GenerateID(): cv.declare_id(Event), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_ON_EVENT): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger), - } - ), - } +EVENT_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent), + cv.GenerateID(): cv.declare_id(Event), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_ON_EVENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger), + } + ), + } + ) ) _UNDEF = object() @@ -97,6 +102,9 @@ async def setup_event_core_(var, config, *, event_types: list[str]): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) + async def register_event(var, config, *, event_types: list[str]): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 192feb78d5..c801efbe88 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1443,7 +1443,7 @@ void WebServer::on_event(event::Event *obj, const std::string &event_type) { } std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) { - return json::build_json([obj, event_type, start_config](JsonObject root) { + return json::build_json([this, obj, event_type, start_config](JsonObject root) { set_json_id(root, obj, "event-" + obj->get_object_id(), start_config); if (!event_type.empty()) { root["event_type"] = event_type; @@ -1454,6 +1454,12 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty event_types.add(event_type); } root["device_class"] = obj->get_device_class(); + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } + } } }); } From 654cee6f83a84efd014ebbbe8fd097c1cd196f10 Mon Sep 17 00:00:00 2001 From: RFDarter Date: Sun, 13 Oct 2024 20:50:22 +0200 Subject: [PATCH 2497/2607] [web_server] expose event compoent to REST (#7587) --- esphome/components/web_server/web_server.cpp | 22 ++++++++++++++++++++ esphome/components/web_server/web_server.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index c801efbe88..0467023039 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1441,7 +1441,24 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro void WebServer::on_event(event::Event *obj, const std::string &event_type) { this->events_.send(this->event_json(obj, event_type, DETAIL_STATE).c_str(), "state"); } +void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match) { + for (event::Event *obj : App.get_events()) { + if (obj->get_object_id() != match.id) + continue; + if (request->method() == HTTP_GET && match.method.empty()) { + auto detail = DETAIL_STATE; + auto *param = request->getParam("detail"); + if (param && param->value() == "all") { + detail = DETAIL_ALL; + } + std::string data = this->event_json(obj, "", detail); + request->send(200, "application/json", data.c_str()); + return; + } + } + request->send(404); +} std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) { return json::build_json([this, obj, event_type, start_config](JsonObject root) { set_json_id(root, obj, "event-" + obj->get_object_id(), start_config); @@ -1651,6 +1668,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_EVENT + if (request->method() == HTTP_GET && match.domain == "event") + return true; +#endif + #ifdef USE_UPDATE if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update") return true; diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index ea1f62fc43..8edb678169 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -322,6 +322,9 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { #ifdef USE_EVENT void on_event(event::Event *obj, const std::string &event_type) override; + /// Handle a event request under '/event'. + void handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match); + /// Dump the event details with its value as a JSON string. std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config); #endif From 77d0bfc4bb97edb209cd6481231aea9806125575 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 14 Oct 2024 07:10:48 +1100 Subject: [PATCH 2498/2607] [touchscreen] Fix coordinates when using rotation (#7591) --- esphome/components/touchscreen/touchscreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/touchscreen/touchscreen.cpp b/esphome/components/touchscreen/touchscreen.cpp index b9498de152..dfe723aedf 100644 --- a/esphome/components/touchscreen/touchscreen.cpp +++ b/esphome/components/touchscreen/touchscreen.cpp @@ -18,8 +18,8 @@ void Touchscreen::attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::Int void Touchscreen::call_setup() { if (this->display_ != nullptr) { - this->display_width_ = this->display_->get_native_width(); - this->display_height_ = this->display_->get_native_height(); + this->display_width_ = this->display_->get_width(); + this->display_height_ = this->display_->get_height(); } PollingComponent::call_setup(); } From 39e922580a7e288e80bd6a1f9deaf91bc8f5ff7b Mon Sep 17 00:00:00 2001 From: Niclas Larsson Date: Sun, 13 Oct 2024 22:17:37 +0200 Subject: [PATCH 2499/2607] Fix update sequence when update is set to false (#5225) (#7407) --- .../shelly_dimmer/shelly_dimmer.cpp | 68 +++++++++---------- .../components/shelly_dimmer/shelly_dimmer.h | 2 + 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index 144236bfe1..b415840bdc 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -64,46 +64,46 @@ uint16_t shelly_dimmer_checksum(const uint8_t *buf, int len) { return std::accumulate(buf, buf + len, 0); } +bool ShellyDimmer::is_running_configured_version() const { + return this->version_major_ == USE_SHD_FIRMWARE_MAJOR_VERSION && + this->version_minor_ == USE_SHD_FIRMWARE_MINOR_VERSION; +} + +void ShellyDimmer::handle_firmware() { + // Reset the STM32 and check the firmware version. + this->reset_normal_boot_(); + this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); + ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_, + this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION); + + if (!is_running_configured_version()) { +#ifdef USE_SHD_FIRMWARE_DATA + if (!this->upgrade_firmware_()) { + ESP_LOGW(TAG, "Failed to upgrade firmware"); + this->mark_failed(); + return; + } + + this->reset_normal_boot_(); + this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); + if (!is_running_configured_version()) { + ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect"); + this->mark_failed(); + return; + } +#else + ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update."); +#endif + } +} + void ShellyDimmer::setup() { this->pin_nrst_->setup(); this->pin_boot0_->setup(); ESP_LOGI(TAG, "Initializing Shelly Dimmer..."); - // Reset the STM32 and check the firmware version. - for (int i = 0; i < 2; i++) { - this->reset_normal_boot_(); - this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); - ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_, - this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION); - if (this->version_major_ != USE_SHD_FIRMWARE_MAJOR_VERSION || - this->version_minor_ != USE_SHD_FIRMWARE_MINOR_VERSION) { -#ifdef USE_SHD_FIRMWARE_DATA - // Update firmware if needed. - ESP_LOGW(TAG, "Unsupported STM32 firmware version, flashing"); - if (i > 0) { - // Upgrade was already performed but the reported version is still not right. - ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect"); - this->mark_failed(); - return; - } - - if (!this->upgrade_firmware_()) { - ESP_LOGW(TAG, "Failed to upgrade firmware"); - this->mark_failed(); - return; - } - - // Firmware upgrade completed, do the checks again. - continue; -#else - ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update."); - this->mark_failed(); - return; -#endif - } - break; - } + this->handle_firmware(); this->send_settings_(); // Do an immediate poll to refresh current state. diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.h b/esphome/components/shelly_dimmer/shelly_dimmer.h index 4701f3a32a..fd75caa797 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.h +++ b/esphome/components/shelly_dimmer/shelly_dimmer.h @@ -20,6 +20,8 @@ class ShellyDimmer : public PollingComponent, public light::LightOutput, public public: float get_setup_priority() const override { return setup_priority::LATE; } + bool is_running_configured_version() const; + void handle_firmware(); void setup() override; void update() override; void dump_config() override; From b617b92758004580ce64f4b9426b49c244675c01 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 9 Oct 2024 03:44:19 -0700 Subject: [PATCH 2500/2607] fix uart settings check (#7573) --- esphome/components/cse7766/cse7766.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index 47058badce..48240464b3 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -244,7 +244,7 @@ void CSE7766Component::dump_config() { LOG_SENSOR(" ", "Apparent Power", this->apparent_power_sensor_); LOG_SENSOR(" ", "Reactive Power", this->reactive_power_sensor_); LOG_SENSOR(" ", "Power Factor", this->power_factor_sensor_); - this->check_uart_settings(4800); + this->check_uart_settings(4800, 1, uart::UART_CONFIG_PARITY_EVEN); } } // namespace cse7766 From bafb0ad6889b13d38ac4b6caaaa8798e58daf0dd Mon Sep 17 00:00:00 2001 From: RFDarter Date: Sun, 13 Oct 2024 20:50:13 +0200 Subject: [PATCH 2501/2607] [web_server] Event component grouping (#7586) --- esphome/components/event/__init__.py | 32 ++++++++++++-------- esphome/components/web_server/web_server.cpp | 8 ++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py index 031a4c0de8..a7732dfcaf 100644 --- a/esphome/components/event/__init__.py +++ b/esphome/components/event/__init__.py @@ -1,6 +1,6 @@ from esphome import automation import esphome.codegen as cg -from esphome.components import mqtt +from esphome.components import mqtt, web_server import esphome.config_validation as cv from esphome.const import ( CONF_DEVICE_CLASS, @@ -11,6 +11,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_ON_EVENT, CONF_TRIGGER_ID, + CONF_WEB_SERVER, DEVICE_CLASS_BUTTON, DEVICE_CLASS_DOORBELL, DEVICE_CLASS_EMPTY, @@ -40,17 +41,21 @@ EventTrigger = event_ns.class_("EventTrigger", automation.Trigger.template()) validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") -EVENT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( - { - cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent), - cv.GenerateID(): cv.declare_id(Event), - cv.Optional(CONF_DEVICE_CLASS): validate_device_class, - cv.Optional(CONF_ON_EVENT): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger), - } - ), - } +EVENT_SCHEMA = ( + cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMPONENT_SCHEMA) + .extend( + { + cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent), + cv.GenerateID(): cv.declare_id(Event), + cv.Optional(CONF_DEVICE_CLASS): validate_device_class, + cv.Optional(CONF_ON_EVENT): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger), + } + ), + } + ) ) _UNDEF = object() @@ -97,6 +102,9 @@ async def setup_event_core_(var, config, *, event_types: list[str]): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) + if web_server_config := config.get(CONF_WEB_SERVER): + await web_server.add_entity_config(var, web_server_config) + async def register_event(var, config, *, event_types: list[str]): if not CORE.has_id(config[CONF_ID]): diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 192feb78d5..c801efbe88 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1443,7 +1443,7 @@ void WebServer::on_event(event::Event *obj, const std::string &event_type) { } std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) { - return json::build_json([obj, event_type, start_config](JsonObject root) { + return json::build_json([this, obj, event_type, start_config](JsonObject root) { set_json_id(root, obj, "event-" + obj->get_object_id(), start_config); if (!event_type.empty()) { root["event_type"] = event_type; @@ -1454,6 +1454,12 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty event_types.add(event_type); } root["device_class"] = obj->get_device_class(); + if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) { + root["sorting_weight"] = this->sorting_entitys_[obj].weight; + if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) { + root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name; + } + } } }); } From f52136338dae9dfbb48f05cea83b1a40ec9178de Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 14 Oct 2024 07:10:48 +1100 Subject: [PATCH 2502/2607] [touchscreen] Fix coordinates when using rotation (#7591) --- esphome/components/touchscreen/touchscreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/touchscreen/touchscreen.cpp b/esphome/components/touchscreen/touchscreen.cpp index b9498de152..dfe723aedf 100644 --- a/esphome/components/touchscreen/touchscreen.cpp +++ b/esphome/components/touchscreen/touchscreen.cpp @@ -18,8 +18,8 @@ void Touchscreen::attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::Int void Touchscreen::call_setup() { if (this->display_ != nullptr) { - this->display_width_ = this->display_->get_native_width(); - this->display_height_ = this->display_->get_native_height(); + this->display_width_ = this->display_->get_width(); + this->display_height_ = this->display_->get_height(); } PollingComponent::call_setup(); } From dda27d9de45e56006f4b207c4ad95c22ad16b330 Mon Sep 17 00:00:00 2001 From: Niclas Larsson Date: Sun, 13 Oct 2024 22:17:37 +0200 Subject: [PATCH 2503/2607] Fix update sequence when update is set to false (#5225) (#7407) --- .../shelly_dimmer/shelly_dimmer.cpp | 68 +++++++++---------- .../components/shelly_dimmer/shelly_dimmer.h | 2 + 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index 144236bfe1..b415840bdc 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -64,46 +64,46 @@ uint16_t shelly_dimmer_checksum(const uint8_t *buf, int len) { return std::accumulate(buf, buf + len, 0); } +bool ShellyDimmer::is_running_configured_version() const { + return this->version_major_ == USE_SHD_FIRMWARE_MAJOR_VERSION && + this->version_minor_ == USE_SHD_FIRMWARE_MINOR_VERSION; +} + +void ShellyDimmer::handle_firmware() { + // Reset the STM32 and check the firmware version. + this->reset_normal_boot_(); + this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); + ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_, + this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION); + + if (!is_running_configured_version()) { +#ifdef USE_SHD_FIRMWARE_DATA + if (!this->upgrade_firmware_()) { + ESP_LOGW(TAG, "Failed to upgrade firmware"); + this->mark_failed(); + return; + } + + this->reset_normal_boot_(); + this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); + if (!is_running_configured_version()) { + ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect"); + this->mark_failed(); + return; + } +#else + ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update."); +#endif + } +} + void ShellyDimmer::setup() { this->pin_nrst_->setup(); this->pin_boot0_->setup(); ESP_LOGI(TAG, "Initializing Shelly Dimmer..."); - // Reset the STM32 and check the firmware version. - for (int i = 0; i < 2; i++) { - this->reset_normal_boot_(); - this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); - ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_, - this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION); - if (this->version_major_ != USE_SHD_FIRMWARE_MAJOR_VERSION || - this->version_minor_ != USE_SHD_FIRMWARE_MINOR_VERSION) { -#ifdef USE_SHD_FIRMWARE_DATA - // Update firmware if needed. - ESP_LOGW(TAG, "Unsupported STM32 firmware version, flashing"); - if (i > 0) { - // Upgrade was already performed but the reported version is still not right. - ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect"); - this->mark_failed(); - return; - } - - if (!this->upgrade_firmware_()) { - ESP_LOGW(TAG, "Failed to upgrade firmware"); - this->mark_failed(); - return; - } - - // Firmware upgrade completed, do the checks again. - continue; -#else - ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update."); - this->mark_failed(); - return; -#endif - } - break; - } + this->handle_firmware(); this->send_settings_(); // Do an immediate poll to refresh current state. diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.h b/esphome/components/shelly_dimmer/shelly_dimmer.h index 4701f3a32a..fd75caa797 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.h +++ b/esphome/components/shelly_dimmer/shelly_dimmer.h @@ -20,6 +20,8 @@ class ShellyDimmer : public PollingComponent, public light::LightOutput, public public: float get_setup_priority() const override { return setup_priority::LATE; } + bool is_running_configured_version() const; + void handle_firmware(); void setup() override; void update() override; void dump_config() override; From d24ad2e0e7168e3e841ff09d3021256e38e43977 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:31:16 +1300 Subject: [PATCH 2504/2607] Bump version to 2024.10.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 0752e3b169..86f950dc79 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.0b1" +__version__ = "2024.10.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 27e1233fc0649f48d2f6eb5b89c5f65a59b0669c Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 13 Oct 2024 10:51:51 +1100 Subject: [PATCH 2505/2607] [CI] failures when installing using apt-get. (#7593) --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38527c20c7..178b914a1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -315,7 +315,9 @@ jobs: key: platformio-${{ matrix.pio_cache_key }} - name: Install clang-tidy - run: sudo apt-get install clang-tidy-14 + run: | + sudo apt-get update + sudo apt-get install clang-tidy-14 - name: Register problem matchers run: | @@ -397,7 +399,9 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install dependencies - run: sudo apt-get install libsdl2-dev + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 @@ -451,7 +455,9 @@ jobs: run: echo ${{ matrix.components }} - name: Install dependencies - run: sudo apt-get install libsdl2-dev + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 From 312799babff8c80318b9d80fbaac3fe330e25d54 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 14 Oct 2024 03:31:37 +0200 Subject: [PATCH 2506/2607] Update test_build_components (#7597) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- script/test_build_components | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/script/test_build_components b/script/test_build_components index e885294b99..62fe0f1b55 100755 --- a/script/test_build_components +++ b/script/test_build_components @@ -2,6 +2,15 @@ set -e +help() { + echo "Usage: $0 [-e ] [-c ] [-t ]" 1>&2 + echo 1>&2 + echo " - e - Parameter for esphome command. Default compile. Common alternative is config." 1>&2 + echo " - c - Component folder name to test. Default *. E.g. '-c logger'." 1>&2 + echo " - t - Target name to test. Put '-t list' to display all possibilities. E.g. '-t esp32-s2-idf-51'." 1>&2 + exit 1 +} + # Parse parameter: # - `e` - Parameter for `esphome` command. Default `compile`. Common alternative is `config`. # - `c` - Component folder name to test. Default `*`. @@ -13,7 +22,7 @@ do e) esphome_command=${OPTARG};; c) target_component=${OPTARG};; t) requested_target_platform=${OPTARG};; - \?) echo "Usage: $0 [-e ] [-c ] [-t ]" 1>&2; exit 1;; + \?) help;; esac done @@ -24,8 +33,8 @@ if ! [ -d "./tests/test_build_components/build" ]; then fi start_esphome() { - if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform" ]; then - echo "Skiping $target_platform" + if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then + echo "Skipping $target_platform_with_version" return fi # create dynamic yaml file in `build` folder. From 2cca26ada4f8c4525f1009b3e40f69e0f0675796 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Mon, 14 Oct 2024 20:59:23 +0300 Subject: [PATCH 2507/2607] [fix] ESP32-C6: internal temperature reporting (#7579) --- .../internal_temperature/internal_temperature.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index 47f516f568..9ef5cbecd5 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -7,7 +7,8 @@ extern "C" { uint8_t temprature_sens_read(); } -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ + defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #include "driver/temp_sensor.h" #endif // USE_ESP32_VARIANT #endif // USE_ESP32 @@ -34,7 +35,8 @@ void InternalTemperatureSensor::update() { ESP_LOGV(TAG, "Raw temperature value: %d", raw); temperature = (raw - 32) / 1.8f; success = (raw != 128); -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ + defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT(); temp_sensor_set_config(tsens); temp_sensor_start(); From 9b4b50a3a64e7268d96fdff35026152816e55d98 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:29:17 +1300 Subject: [PATCH 2508/2607] Bump version to 2024.10.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 86f950dc79..5061b1a439 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.0b2" +__version__ = "2024.10.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From b0a25872dadfd75584a0a90f05fb4b49577d1339 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 16 Oct 2024 05:22:45 +0200 Subject: [PATCH 2509/2607] [code-quality] statsd component (#7603) Co-authored-by: Tomasz Duda --- esphome/components/statsd/statsd.cpp | 2 ++ esphome/components/statsd/statsd.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esphome/components/statsd/statsd.cpp b/esphome/components/statsd/statsd.cpp index 68b24908d2..b7fad19332 100644 --- a/esphome/components/statsd/statsd.cpp +++ b/esphome/components/statsd/statsd.cpp @@ -2,6 +2,7 @@ #include "statsd.h" +#ifdef USE_NETWORK namespace esphome { namespace statsd { @@ -154,3 +155,4 @@ void StatsdComponent::send_(std::string *out) { } // namespace statsd } // namespace esphome +#endif diff --git a/esphome/components/statsd/statsd.h b/esphome/components/statsd/statsd.h index ef42579587..34f84cbe00 100644 --- a/esphome/components/statsd/statsd.h +++ b/esphome/components/statsd/statsd.h @@ -3,6 +3,7 @@ #include #include "esphome/core/defines.h" +#ifdef USE_NETWORK #include "esphome/core/component.h" #include "esphome/components/socket/socket.h" #include "esphome/components/network/ip_address.h" @@ -84,3 +85,4 @@ class StatsdComponent : public PollingComponent { } // namespace statsd } // namespace esphome +#endif From de943908bd248c8c803fffb339e3a6e16d16b303 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:23:43 +1100 Subject: [PATCH 2510/2607] [automation] Implement all and any condition shortcuts (#7565) --- esphome/automation.py | 31 +++++++++++++++++++++++++++++-- esphome/const.py | 2 ++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/esphome/automation.py b/esphome/automation.py index 0bd6cf0af0..34159561c2 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -1,6 +1,8 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import ( + CONF_ALL, + CONF_ANY, CONF_AUTOMATION_ID, CONF_CONDITION, CONF_COUNT, @@ -73,6 +75,13 @@ def validate_potentially_and_condition(value): return validate_condition(value) +def validate_potentially_or_condition(value): + if isinstance(value, list): + with cv.remove_prepend_path(["or"]): + return validate_condition({"or": value}) + return validate_condition(value) + + DelayAction = cg.esphome_ns.class_("DelayAction", Action, cg.Component) LambdaAction = cg.esphome_ns.class_("LambdaAction", Action) IfAction = cg.esphome_ns.class_("IfAction", Action) @@ -166,6 +175,18 @@ async def or_condition_to_code(config, condition_id, template_arg, args): return cg.new_Pvariable(condition_id, template_arg, conditions) +@register_condition("all", AndCondition, validate_condition_list) +async def all_condition_to_code(config, condition_id, template_arg, args): + conditions = await build_condition_list(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, conditions) + + +@register_condition("any", OrCondition, validate_condition_list) +async def any_condition_to_code(config, condition_id, template_arg, args): + conditions = await build_condition_list(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, conditions) + + @register_condition("not", NotCondition, validate_potentially_and_condition) async def not_condition_to_code(config, condition_id, template_arg, args): condition = await build_condition(config, template_arg, args) @@ -223,15 +244,21 @@ async def delay_action_to_code(config, action_id, template_arg, args): IfAction, cv.All( { - cv.Required(CONF_CONDITION): validate_potentially_and_condition, + cv.Exclusive( + CONF_CONDITION, CONF_CONDITION + ): validate_potentially_and_condition, + cv.Exclusive(CONF_ANY, CONF_CONDITION): validate_potentially_or_condition, + cv.Exclusive(CONF_ALL, CONF_CONDITION): validate_potentially_and_condition, cv.Optional(CONF_THEN): validate_action_list, cv.Optional(CONF_ELSE): validate_action_list, }, cv.has_at_least_one_key(CONF_THEN, CONF_ELSE), + cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL), ), ) async def if_action_to_code(config, action_id, template_arg, args): - conditions = await build_condition(config[CONF_CONDITION], template_arg, args) + cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION)) + conditions = await build_condition(config[cond_conf], template_arg, args) var = cg.new_Pvariable(action_id, template_arg, conditions) if CONF_THEN in config: actions = await build_action_list(config[CONF_THEN], template_arg, args) diff --git a/esphome/const.py b/esphome/const.py index e02a1506cb..7665c77a32 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -49,6 +49,7 @@ CONF_ADDRESS = "address" CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id" CONF_ADVANCED = "advanced" CONF_AFTER = "after" +CONF_ALL = "all" CONF_ALLOW_OTHER_USES = "allow_other_uses" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" @@ -57,6 +58,7 @@ CONF_AMMONIA = "ammonia" CONF_ANALOG = "analog" CONF_AND = "and" CONF_ANGLE = "angle" +CONF_ANY = "any" CONF_AP = "ap" CONF_APPARENT_POWER = "apparent_power" CONF_ARDUINO_VERSION = "arduino_version" From fb002ac3b0a1e2c31456461daba895807d10eb83 Mon Sep 17 00:00:00 2001 From: Seth Girvan Date: Tue, 15 Oct 2024 20:24:37 -0700 Subject: [PATCH 2511/2607] Add TC74 temperature sensor (#7460) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/tc74/__init__.py | 1 + esphome/components/tc74/sensor.py | 32 +++++++++ esphome/components/tc74/tc74.cpp | 68 ++++++++++++++++++++ esphome/components/tc74/tc74.h | 28 ++++++++ tests/components/tc74/test.esp32-ard.yaml | 8 +++ tests/components/tc74/test.esp32-c3-ard.yaml | 8 +++ tests/components/tc74/test.esp32-c3-idf.yaml | 8 +++ tests/components/tc74/test.esp32-idf.yaml | 8 +++ tests/components/tc74/test.esp8266-ard.yaml | 8 +++ tests/components/tc74/test.rp2040-ard.yaml | 8 +++ 11 files changed, 178 insertions(+) create mode 100644 esphome/components/tc74/__init__.py create mode 100644 esphome/components/tc74/sensor.py create mode 100644 esphome/components/tc74/tc74.cpp create mode 100644 esphome/components/tc74/tc74.h create mode 100644 tests/components/tc74/test.esp32-ard.yaml create mode 100644 tests/components/tc74/test.esp32-c3-ard.yaml create mode 100644 tests/components/tc74/test.esp32-c3-idf.yaml create mode 100644 tests/components/tc74/test.esp32-idf.yaml create mode 100644 tests/components/tc74/test.esp8266-ard.yaml create mode 100644 tests/components/tc74/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index ed9c13a975..a19f3d75ed 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -403,6 +403,7 @@ esphome/components/sun/* @OttoWinter esphome/components/sun_gtil2/* @Mat931 esphome/components/switch/* @esphome/core esphome/components/t6615/* @tylermenezes +esphome/components/tc74/* @sethgirvan esphome/components/tca9548a/* @andreashergert1984 esphome/components/tca9555/* @mobrembski esphome/components/tcl112/* @glmnet diff --git a/esphome/components/tc74/__init__.py b/esphome/components/tc74/__init__.py new file mode 100644 index 0000000000..c1407c7cad --- /dev/null +++ b/esphome/components/tc74/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@sethgirvan"] diff --git a/esphome/components/tc74/sensor.py b/esphome/components/tc74/sensor.py new file mode 100644 index 0000000000..18fc2d9a42 --- /dev/null +++ b/esphome/components/tc74/sensor.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) + +CODEOWNERS = ["@sethgirvan"] +DEPENDENCIES = ["i2c"] + +tc74_ns = cg.esphome_ns.namespace("tc74") +TC74Component = tc74_ns.class_("TC74Component", cg.PollingComponent, i2c.I2CDevice) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + TC74Component, + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x48)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tc74/tc74.cpp b/esphome/components/tc74/tc74.cpp new file mode 100644 index 0000000000..2acb71f921 --- /dev/null +++ b/esphome/components/tc74/tc74.cpp @@ -0,0 +1,68 @@ +// Based on the TC74 datasheet https://ww1.microchip.com/downloads/en/DeviceDoc/21462D.pdf + +#include "tc74.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace tc74 { + +static const char *const TAG = "tc74"; + +static const uint8_t TC74_REGISTER_TEMPERATURE = 0x00; +static const uint8_t TC74_REGISTER_CONFIGURATION = 0x01; +static const uint8_t TC74_DATA_READY_MASK = 0x40; + +// It is possible the "Data Ready" bit will not be set if the TC74 has not been powered on for at least 250ms, so it not +// being set does not constitute a failure. +void TC74Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up TC74..."); + uint8_t config_reg; + if (this->read_register(TC74_REGISTER_CONFIGURATION, &config_reg, 1) != i2c::ERROR_OK) { + this->mark_failed(); + return; + } + this->data_ready_ = config_reg & TC74_DATA_READY_MASK; +} + +void TC74Component::update() { this->read_temperature_(); } + +void TC74Component::dump_config() { + LOG_SENSOR("", "TC74", this); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Connection with TC74 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} + +void TC74Component::read_temperature_() { + if (!this->data_ready_) { + uint8_t config_reg; + if (this->read_register(TC74_REGISTER_CONFIGURATION, &config_reg, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + if (config_reg & TC74_DATA_READY_MASK) { + this->data_ready_ = true; + } else { + ESP_LOGD(TAG, "TC74 not ready"); + return; + } + } + + uint8_t temperature_reg; + if (this->read_register(TC74_REGISTER_TEMPERATURE, &temperature_reg, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + ESP_LOGD(TAG, "Got Temperature=%d °C", temperature_reg); + this->publish_state(temperature_reg); + this->status_clear_warning(); +} + +float TC74Component::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace tc74 +} // namespace esphome diff --git a/esphome/components/tc74/tc74.h b/esphome/components/tc74/tc74.h new file mode 100644 index 0000000000..5d70c05420 --- /dev/null +++ b/esphome/components/tc74/tc74.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace tc74 { + +class TC74Component : public PollingComponent, public i2c::I2CDevice, public sensor::Sensor { + public: + /// Setup the sensor and check connection. + void setup() override; + void dump_config() override; + /// Update the sensor value (temperature). + void update() override; + + float get_setup_priority() const override; + + protected: + /// Internal method to read the temperature from the component after it has been scheduled. + void read_temperature_(); + + bool data_ready_ = false; +}; + +} // namespace tc74 +} // namespace esphome diff --git a/tests/components/tc74/test.esp32-ard.yaml b/tests/components/tc74/test.esp32-ard.yaml new file mode 100644 index 0000000000..ef9b40e184 --- /dev/null +++ b/tests/components/tc74/test.esp32-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 16 + sda: 17 + +sensor: + - platform: tc74 + name: TC74 Temperature diff --git a/tests/components/tc74/test.esp32-c3-ard.yaml b/tests/components/tc74/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..e1a373fbf4 --- /dev/null +++ b/tests/components/tc74/test.esp32-c3-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 5 + sda: 4 + +sensor: + - platform: tc74 + name: TC74 Temperature diff --git a/tests/components/tc74/test.esp32-c3-idf.yaml b/tests/components/tc74/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..e1a373fbf4 --- /dev/null +++ b/tests/components/tc74/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 5 + sda: 4 + +sensor: + - platform: tc74 + name: TC74 Temperature diff --git a/tests/components/tc74/test.esp32-idf.yaml b/tests/components/tc74/test.esp32-idf.yaml new file mode 100644 index 0000000000..ef9b40e184 --- /dev/null +++ b/tests/components/tc74/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 16 + sda: 17 + +sensor: + - platform: tc74 + name: TC74 Temperature diff --git a/tests/components/tc74/test.esp8266-ard.yaml b/tests/components/tc74/test.esp8266-ard.yaml new file mode 100644 index 0000000000..e1a373fbf4 --- /dev/null +++ b/tests/components/tc74/test.esp8266-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 5 + sda: 4 + +sensor: + - platform: tc74 + name: TC74 Temperature diff --git a/tests/components/tc74/test.rp2040-ard.yaml b/tests/components/tc74/test.rp2040-ard.yaml new file mode 100644 index 0000000000..e1a373fbf4 --- /dev/null +++ b/tests/components/tc74/test.rp2040-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_tc74 + scl: 5 + sda: 4 + +sensor: + - platform: tc74 + name: TC74 Temperature From 3ef31e55ca8b55252ad0fa7c342e94c6458ce767 Mon Sep 17 00:00:00 2001 From: Aleksandr Artemev <40710570+artemyevav@users.noreply.github.com> Date: Wed, 16 Oct 2024 05:25:05 +0200 Subject: [PATCH 2512/2607] [display] filled_ring and filled_gauge methods added (#7420) --- esphome/components/display/display.cpp | 142 +++++++++++++++++++++++++ esphome/components/display/display.h | 7 ++ tests/components/display/common.yaml | 4 + 3 files changed, 153 insertions(+) diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 63c74e09ca..145a4f5278 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -156,6 +156,148 @@ void Display::filled_circle(int center_x, int center_y, int radius, Color color) } } while (dx <= 0); } +void Display::filled_ring(int center_x, int center_y, int radius1, int radius2, Color color) { + int rmax = radius1 > radius2 ? radius1 : radius2; + int rmin = radius1 < radius2 ? radius1 : radius2; + int dxmax = -int32_t(rmax), dxmin = -int32_t(rmin); + int dymax = 0, dymin = 0; + int errmax = 2 - 2 * rmax, errmin = 2 - 2 * rmin; + int e2max, e2min; + do { + // 8 dots for borders + this->draw_pixel_at(center_x - dxmax, center_y + dymax, color); + this->draw_pixel_at(center_x + dxmax, center_y + dymax, color); + this->draw_pixel_at(center_x - dxmin, center_y + dymin, color); + this->draw_pixel_at(center_x + dxmin, center_y + dymin, color); + this->draw_pixel_at(center_x + dxmax, center_y - dymax, color); + this->draw_pixel_at(center_x - dxmax, center_y - dymax, color); + this->draw_pixel_at(center_x + dxmin, center_y - dymin, color); + this->draw_pixel_at(center_x - dxmin, center_y - dymin, color); + if (dymin < rmin) { + // two parts - four lines + int hline_width = -(dxmax - dxmin) + 1; + this->horizontal_line(center_x + dxmax, center_y + dymax, hline_width, color); + this->horizontal_line(center_x - dxmin, center_y + dymax, hline_width, color); + this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color); + this->horizontal_line(center_x - dxmin, center_y - dymax, hline_width, color); + } else { + // one part - top and bottom + int hline_width = 2 * (-dxmax) + 1; + this->horizontal_line(center_x + dxmax, center_y + dymax, hline_width, color); + this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color); + } + e2max = errmax; + // tune external + if (e2max < dymax) { + errmax += ++dymax * 2 + 1; + if (-dxmax == dymax && e2max <= dxmax) { + e2max = 0; + } + } + if (e2max > dxmax) { + errmax += ++dxmax * 2 + 1; + } + // tune internal + while (dymin < dymax && dymin < rmin) { + e2min = errmin; + if (e2min < dymin) { + errmin += ++dymin * 2 + 1; + if (-dxmin == dymin && e2min <= dxmin) { + e2min = 0; + } + } + if (e2min > dxmin) { + errmin += ++dxmin * 2 + 1; + } + } + } while (dxmax <= 0); +} +void Display::filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color) { + int rmax = radius1 > radius2 ? radius1 : radius2; + int rmin = radius1 < radius2 ? radius1 : radius2; + int dxmax = -int32_t(rmax), dxmin = -int32_t(rmin), upd_dxmax, upd_dxmin; + int dymax = 0, dymin = 0; + int errmax = 2 - 2 * rmax, errmin = 2 - 2 * rmin; + int e2max, e2min; + progress = std::max(0, std::min(progress, 100)); // 0..100 + int draw_progress = progress > 50 ? (100 - progress) : progress; + float tan_a = (progress == 50) ? 65535 : tan(float(draw_progress) * M_PI / 100); // slope + + do { + // outer dots + this->draw_pixel_at(center_x + dxmax, center_y - dymax, color); + this->draw_pixel_at(center_x - dxmax, center_y - dymax, color); + if (dymin < rmin) { // side parts + int lhline_width = -(dxmax - dxmin) + 1; + if (progress >= 50) { + if (float(dymax) < float(-dxmax) * tan_a) { + upd_dxmax = ceil(float(dymax) / tan_a); + } else { + upd_dxmax = -dxmax; + } + this->horizontal_line(center_x + dxmax, center_y - dymax, lhline_width, color); // left + if (!dymax) + this->horizontal_line(center_x - dxmin, center_y, lhline_width, color); // right horizontal border + if (upd_dxmax > -dxmin) { // right + int rhline_width = (upd_dxmax + dxmin) + 1; + this->horizontal_line(center_x - dxmin, center_y - dymax, + rhline_width > lhline_width ? lhline_width : rhline_width, color); + } + } else { + if (float(dymin) > float(-dxmin) * tan_a) { + upd_dxmin = ceil(float(dymin) / tan_a); + } else { + upd_dxmin = -dxmin; + } + lhline_width = -(dxmax + upd_dxmin) + 1; + if (!dymax) + this->horizontal_line(center_x - dxmin, center_y, lhline_width, color); // right horizontal border + if (lhline_width > 0) + this->horizontal_line(center_x + dxmax, center_y - dymax, lhline_width, color); + } + } else { // top part + int hline_width = 2 * (-dxmax) + 1; + if (progress >= 50) { + if (dymax < float(-dxmax) * tan_a) { + upd_dxmax = ceil(float(dymax) / tan_a); + hline_width = -dxmax + upd_dxmax + 1; + } + } else { + if (dymax < float(-dxmax) * tan_a) { + upd_dxmax = ceil(float(dymax) / tan_a); + hline_width = -dxmax - upd_dxmax + 1; + } else + hline_width = 0; + } + if (hline_width > 0) + this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color); + } + e2max = errmax; + if (e2max < dymax) { + errmax += ++dymax * 2 + 1; + if (-dxmax == dymax && e2max <= dxmax) { + e2max = 0; + } + } + if (e2max > dxmax) { + errmax += ++dxmax * 2 + 1; + } + while (dymin <= dymax && dymin <= rmin && dxmin <= 0) { + this->draw_pixel_at(center_x + dxmin, center_y - dymin, color); + this->draw_pixel_at(center_x - dxmin, center_y - dymin, color); + e2min = errmin; + if (e2min < dymin) { + errmin += ++dymin * 2 + 1; + if (-dxmin == dymin && e2min <= dxmin) { + e2min = 0; + } + } + if (e2min > dxmin) { + errmin += ++dxmin * 2 + 1; + } + } + } while (dxmax <= 0); +} void HOT Display::triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) { this->line(x1, y1, x2, y2, color); this->line(x1, y1, x3, y3, color); diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 34feafea6e..54e897cdec 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -285,6 +285,13 @@ class Display : public PollingComponent { /// Fill a circle centered around [center_x,center_y] with the radius radius with the given color. void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON); + /// Fill a ring centered around [center_x,center_y] between two circles with the radius1 and radius2 with the given + /// color. + void filled_ring(int center_x, int center_y, int radius1, int radius2, Color color = COLOR_ON); + /// Fill a half-ring "gauge" centered around [center_x,center_y] between two circles with the radius1 and radius2 + /// with he given color and filled up to 'progress' percent + void filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color = COLOR_ON); + /// Draw the outline of a triangle contained between the points [x1,y1], [x2,y2] and [x3,y3] with the given color. void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON); diff --git a/tests/components/display/common.yaml b/tests/components/display/common.yaml index 1df2665067..4fc4fafa25 100644 --- a/tests/components/display/common.yaml +++ b/tests/components/display/common.yaml @@ -34,3 +34,7 @@ display: it.line_at_angle(centerX, centerY, minuteAngle, radius - 5, radius); } + + // Nice ring around and some gauge + it.filled_ring(centerX, centerY, radius+5, radius+8); + it.filled_gauge(centerX, centerY, radius/2, radius/2-5, 66); From b274d6901a8542b10262361fb3e5e2ff27959a10 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Wed, 16 Oct 2024 06:25:47 +0300 Subject: [PATCH 2513/2607] [fix] deprecated functions warnings for logger component with ESP IDF version 5.3.0+ (#7600) --- esphome/components/logger/logger_esp32.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index b0f1051d34..c9de3d815a 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -10,8 +10,12 @@ #ifdef USE_LOGGER_USB_SERIAL_JTAG #include +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) #include #include +#else +#include +#endif #endif #include "freertos/FreeRTOS.h" @@ -36,10 +40,17 @@ static const char *const TAG = "logger"; static void init_usb_serial_jtag_() { setvbuf(stdin, NULL, _IONBF, 0); // Disable buffering on stdin +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) // Minicom, screen, idf_monitor send CR when ENTER key is pressed esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR); // Move the caret to the beginning of the next line on '\n' esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); +#else + // Minicom, screen, idf_monitor send CR when ENTER key is pressed + usb_serial_jtag_vfs_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + // Move the caret to the beginning of the next line on '\n' + usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); +#endif // Enable non-blocking mode on stdin and stdout fcntl(fileno(stdout), F_SETFL, 0); @@ -57,7 +68,11 @@ static void init_usb_serial_jtag_() { } // Tell vfs to use usb-serial-jtag driver +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) esp_vfs_usb_serial_jtag_use_driver(); +#else + usb_serial_jtag_vfs_use_driver(); +#endif } #endif From 6a86d92781357a03c49dbdbb68953fcc2b04b933 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:26:06 +1100 Subject: [PATCH 2514/2607] [lvgl] Implement better software rotation (#7595) --- esphome/components/lvgl/__init__.py | 25 ++- esphome/components/lvgl/defines.py | 4 + esphome/components/lvgl/lvgl_esphome.cpp | 176 +++++++++++++++------- esphome/components/lvgl/lvgl_esphome.h | 47 +++++- esphome/components/lvgl/types.py | 1 + tests/components/lvgl/lvgl-package.yaml | 5 + tests/components/lvgl/test.esp32-ard.yaml | 1 + 7 files changed, 201 insertions(+), 58 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index ce3843567b..dea3b11a94 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -48,6 +48,7 @@ from .types import ( FontEngine, IdleTrigger, ObjUpdateAction, + PauseTrigger, lv_font_t, lv_group_t, lv_style_t, @@ -233,6 +234,8 @@ async def to_code(config): frac = 8 cg.add(lv_component.set_buffer_frac(int(frac))) cg.add(lv_component.set_full_refresh(config[df.CONF_FULL_REFRESH])) + cg.add(lv_component.set_draw_rounding(config[df.CONF_DRAW_ROUNDING])) + cg.add(lv_component.set_resume_on_input(config[df.CONF_RESUME_ON_INPUT])) for font in helpers.esphome_fonts_used: await cg.get_variable(font) @@ -272,11 +275,19 @@ async def to_code(config): async with LvContext(lv_component): await generate_triggers(lv_component) await generate_page_triggers(lv_component, config) + await initial_focus_to_code(config) for conf in config.get(CONF_ON_IDLE, ()): templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) await build_automation(idle_trigger, [], conf) - await initial_focus_to_code(config) + for conf in config.get(df.CONF_ON_PAUSE, ()): + pause_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, True) + await build_automation(pause_trigger, [], conf) + for conf in config.get(df.CONF_ON_RESUME, ()): + resume_trigger = cg.new_Pvariable( + conf[CONF_TRIGGER_ID], lv_component, False + ) + await build_automation(resume_trigger, [], conf) for comp in helpers.lvgl_components_required: CORE.add_define(f"USE_LVGL_{comp.upper()}") @@ -314,6 +325,7 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_COLOR_DEPTH, default=16): cv.one_of(16), cv.Optional(df.CONF_DEFAULT_FONT, default="montserrat_14"): lvalid.lv_font, cv.Optional(df.CONF_FULL_REFRESH, default=False): cv.boolean, + cv.Optional(df.CONF_DRAW_ROUNDING, default=2): cv.positive_int, cv.Optional(CONF_BUFFER_SIZE, default="100%"): cv.percentage, cv.Optional(df.CONF_LOG_LEVEL, default="WARN"): cv.one_of( *df.LOG_LEVELS, upper=True @@ -341,6 +353,16 @@ CONFIG_SCHEMA = ( ), } ), + cv.Optional(df.CONF_ON_PAUSE): validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger), + } + ), + cv.Optional(df.CONF_ON_RESUME): validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger), + } + ), cv.Exclusive(df.CONF_WIDGETS, CONF_PAGES): cv.ensure_list(WIDGET_SCHEMA), cv.Exclusive(CONF_PAGES, CONF_PAGES): cv.ensure_list( container_schema(page_spec) @@ -356,6 +378,7 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_TOUCHSCREENS, default=None): touchscreen_schema, cv.Optional(df.CONF_ENCODERS, default=None): ENCODERS_CONFIG, cv.GenerateID(df.CONF_DEFAULT_GROUP): cv.declare_id(lv_group_t), + cv.Optional(df.CONF_RESUME_ON_INPUT, default=True): cv.boolean, } ) .extend(DISP_BG_SCHEMA) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 02f726e49c..7c42ed2f22 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -408,6 +408,7 @@ CONF_DEFAULT_FONT = "default_font" CONF_DEFAULT_GROUP = "default_group" CONF_DIR = "dir" CONF_DISPLAYS = "displays" +CONF_DRAW_ROUNDING = "draw_rounding" CONF_EDITING = "editing" CONF_ENCODERS = "encoders" CONF_END_ANGLE = "end_angle" @@ -451,6 +452,8 @@ CONF_OFFSET_X = "offset_x" CONF_OFFSET_Y = "offset_y" CONF_ONE_CHECKED = "one_checked" CONF_ONE_LINE = "one_line" +CONF_ON_PAUSE = "on_pause" +CONF_ON_RESUME = "on_resume" CONF_ON_SELECT = "on_select" CONF_OPA = "opa" CONF_NEXT = "next" @@ -466,6 +469,7 @@ CONF_POINTS = "points" CONF_PREVIOUS = "previous" CONF_REPEAT_COUNT = "repeat_count" CONF_RECOLOR = "recolor" +CONF_RESUME_ON_INPUT = "resume_on_input" CONF_RIGHT_BUTTON = "right_button" CONF_ROLLOVER = "rollover" CONF_ROOT_BACK_BTN = "root_back_btn" diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index b63fb0dab8..ddf41ae377 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -69,30 +69,38 @@ std::string lv_event_code_name_for(uint8_t event_code) { } return str_sprintf("%2d", event_code); } + static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { - // make sure all coordinates are even - if (area->x1 & 1) - area->x1--; - if (!(area->x2 & 1)) - area->x2++; - if (area->y1 & 1) - area->y1--; - if (!(area->y2 & 1)) - area->y2++; + // cater for display driver chips with special requirements for bounds of partial + // draw areas. Extend the draw area to satisfy: + // * Coordinates must be a multiple of draw_rounding + auto *comp = static_cast(disp_drv->user_data); + auto draw_rounding = comp->draw_rounding; + // round down the start coordinates + area->x1 = area->x1 / draw_rounding * draw_rounding; + area->y1 = area->y1 / draw_rounding * draw_rounding; + // round up the end coordinates + area->x2 = (area->x2 + draw_rounding) / draw_rounding * draw_rounding - 1; + area->y2 = (area->y2 + draw_rounding) / draw_rounding * draw_rounding - 1; } lv_event_code_t lv_api_event; // NOLINT lv_event_code_t lv_update_event; // NOLINT -void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); } +void LvglComponent::dump_config() { + ESP_LOGCONFIG(TAG, "LVGL:"); + ESP_LOGCONFIG(TAG, " Rotation: %d", this->rotation); + ESP_LOGCONFIG(TAG, " Draw rounding: %d", (int) this->draw_rounding); +} void LvglComponent::set_paused(bool paused, bool show_snow) { this->paused_ = paused; this->show_snow_ = show_snow; - this->snow_line_ = 0; if (!paused && lv_scr_act() != nullptr) { lv_disp_trig_activity(this->disp_); // resets the inactivity time lv_obj_invalidate(lv_scr_act()); } + this->pause_callbacks_.call(paused); } + void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) { lv_obj_add_event_cb(obj, callback, event, this); } @@ -133,19 +141,64 @@ void LvglComponent::show_prev_page(lv_scr_load_anim_t anim, uint32_t time) { } while (this->pages_[this->current_page_]->skip); // skip empty pages() this->show_page(this->current_page_, anim, time); } -void LvglComponent::draw_buffer_(const lv_area_t *area, const uint8_t *ptr) { +void LvglComponent::draw_buffer_(const lv_area_t *area, lv_color_t *ptr) { + auto width = lv_area_get_width(area); + auto height = lv_area_get_height(area); + auto x1 = area->x1; + auto y1 = area->y1; + lv_color_t *dst = this->rotate_buf_; + switch (this->rotation) { + case display::DISPLAY_ROTATION_90_DEGREES: + for (lv_coord_t x = height - 1; x-- != 0;) { + for (lv_coord_t y = 0; y != width; y++) { + dst[y * height + x] = *ptr++; + } + } + y1 = x1; + x1 = this->disp_drv_.ver_res - area->y1 - height; + width = height; + height = lv_area_get_width(area); + break; + + case display::DISPLAY_ROTATION_180_DEGREES: + for (lv_coord_t y = height; y-- != 0;) { + for (lv_coord_t x = width; x-- != 0;) { + dst[y * width + x] = *ptr++; + } + } + x1 = this->disp_drv_.hor_res - x1 - width; + y1 = this->disp_drv_.ver_res - y1 - height; + break; + + case display::DISPLAY_ROTATION_270_DEGREES: + for (lv_coord_t x = 0; x != height; x++) { + for (lv_coord_t y = width; y-- != 0;) { + dst[y * height + x] = *ptr++; + } + } + x1 = y1; + y1 = this->disp_drv_.hor_res - area->x1 - width; + width = height; + height = lv_area_get_width(area); + break; + + default: + dst = ptr; + break; + } for (auto *display : this->displays_) { - display->draw_pixels_at(area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area), ptr, - display::COLOR_ORDER_RGB, LV_BITNESS, LV_COLOR_16_SWAP); + ESP_LOGV(TAG, "draw buffer x1=%d, y1=%d, width=%d, height=%d", x1, y1, width, height); + display->draw_pixels_at(x1, y1, width, height, (const uint8_t *) dst, display::COLOR_ORDER_RGB, LV_BITNESS, + LV_COLOR_16_SWAP); } } void LvglComponent::flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { if (!this->paused_) { auto now = millis(); - this->draw_buffer_(area, (const uint8_t *) color_p); - ESP_LOGV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area), - lv_area_get_height(area), (int) (millis() - now)); + this->draw_buffer_(area, color_p); + ESP_LOGVV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area), + lv_area_get_height(area), (int) (millis() - now)); } lv_disp_flush_ready(disp_drv); } @@ -160,6 +213,13 @@ IdleTrigger::IdleTrigger(LvglComponent *parent, TemplatableValue timeo }); } +PauseTrigger::PauseTrigger(LvglComponent *parent, TemplatableValue paused) : paused_(std::move(paused)) { + parent->add_on_pause_callback([this](bool pausing) { + if (this->paused_.value() == pausing) + this->trigger(); + }); +} + #ifdef USE_LVGL_TOUCHSCREEN LVTouchListener::LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) { lv_indev_drv_init(&this->drv_); @@ -261,23 +321,31 @@ void LvKeyboardType::set_obj(lv_obj_t *lv_obj) { #endif // USE_LVGL_KEYBOARD void LvglComponent::write_random_() { - // length of 2 lines in 32 bit units - // we write 2 lines for the benefit of displays that won't write one line at a time. - size_t line_len = this->disp_drv_.hor_res * LV_COLOR_DEPTH / 8 / 4 * 2; - for (size_t i = 0; i != line_len; i++) { - ((uint32_t *) (this->draw_buf_.buf1))[i] = random_uint32(); + int iterations = 6 - lv_disp_get_inactive_time(this->disp_) / 60000; + if (iterations <= 0) + iterations = 1; + while (iterations-- != 0) { + auto col = random_uint32() % this->disp_drv_.hor_res; + col = col / this->draw_rounding * this->draw_rounding; + auto row = random_uint32() % this->disp_drv_.ver_res; + row = row / this->draw_rounding * this->draw_rounding; + auto size = (random_uint32() % 32) / this->draw_rounding * this->draw_rounding - 1; + lv_area_t area; + area.x1 = col; + area.y1 = row; + area.x2 = col + size; + area.y2 = row + size; + if (area.x2 >= this->disp_drv_.hor_res) + area.x2 = this->disp_drv_.hor_res - 1; + if (area.y2 >= this->disp_drv_.ver_res) + area.y2 = this->disp_drv_.ver_res - 1; + + size_t line_len = lv_area_get_width(&area) * lv_area_get_height(&area) / 2; + for (size_t i = 0; i != line_len; i++) { + ((uint32_t *) (this->draw_buf_.buf1))[i] = random_uint32(); + } + this->draw_buffer_(&area, (lv_color_t *) this->draw_buf_.buf1); } - lv_area_t area; - area.x1 = 0; - area.x2 = this->disp_drv_.hor_res - 1; - if (this->snow_line_ == this->disp_drv_.ver_res / 2) { - area.y1 = static_cast(random_uint32() % (this->disp_drv_.ver_res / 2) * 2); - } else { - area.y1 = this->snow_line_++ * 2; - } - // write 2 lines - area.y2 = area.y1 + 1; - this->draw_buffer_(&area, (const uint8_t *) this->draw_buf_.buf1); } void LvglComponent::setup() { @@ -291,7 +359,7 @@ void LvglComponent::setup() { auto *display = this->displays_[0]; size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_; auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; - auto *buf = lv_custom_mem_alloc(buf_bytes); + auto *buf = lv_custom_mem_alloc(buf_bytes); // NOLINT if (buf == nullptr) { #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); @@ -307,26 +375,30 @@ void LvglComponent::setup() { this->disp_drv_.full_refresh = this->full_refresh_; this->disp_drv_.flush_cb = static_flush_cb; this->disp_drv_.rounder_cb = rounder_cb; - switch (display->get_rotation()) { - case display::DISPLAY_ROTATION_0_DEGREES: - break; - case display::DISPLAY_ROTATION_90_DEGREES: - this->disp_drv_.sw_rotate = true; - this->disp_drv_.rotated = LV_DISP_ROT_90; - break; - case display::DISPLAY_ROTATION_180_DEGREES: - this->disp_drv_.sw_rotate = true; - this->disp_drv_.rotated = LV_DISP_ROT_180; - break; - case display::DISPLAY_ROTATION_270_DEGREES: - this->disp_drv_.sw_rotate = true; - this->disp_drv_.rotated = LV_DISP_ROT_270; - break; + this->rotation = display->get_rotation(); + if (this->rotation != display::DISPLAY_ROTATION_0_DEGREES) { + this->rotate_buf_ = static_cast(lv_custom_mem_alloc(buf_bytes)); // NOLINT + if (this->rotate_buf_ == nullptr) { +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR + ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); +#endif + this->mark_failed(); + this->status_set_error("Memory allocation failure"); + return; + } } display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES); - this->disp_drv_.hor_res = (lv_coord_t) display->get_width(); - this->disp_drv_.ver_res = (lv_coord_t) display->get_height(); - ESP_LOGV(TAG, "sw_rotate = %d, rotated=%d", this->disp_drv_.sw_rotate, this->disp_drv_.rotated); + switch (this->rotation) { + default: + this->disp_drv_.hor_res = (lv_coord_t) display->get_width(); + this->disp_drv_.ver_res = (lv_coord_t) display->get_height(); + break; + case display::DISPLAY_ROTATION_90_DEGREES: + case display::DISPLAY_ROTATION_270_DEGREES: + this->disp_drv_.ver_res = (lv_coord_t) display->get_width(); + this->disp_drv_.hor_res = (lv_coord_t) display->get_height(); + break; + } this->disp_ = lv_disp_drv_register(&this->disp_drv_); for (const auto &v : this->init_lambdas_) v(this); diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 0c3738bd1f..b28a9bcbe1 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -119,6 +119,7 @@ class LvglComponent : public PollingComponent { void add_on_idle_callback(std::function &&callback) { this->idle_callbacks_.add(std::move(callback)); } + void add_on_pause_callback(std::function &&callback) { this->pause_callbacks_.add(std::move(callback)); } void add_display(display::Display *display) { this->displays_.push_back(display); } void add_init_lambda(const std::function &lamb) { this->init_lambdas_.push_back(lamb); } void dump_config() override; @@ -126,12 +127,22 @@ class LvglComponent : public PollingComponent { bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; } void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } lv_disp_t *get_disp() { return this->disp_; } + // Pause or resume the display. + // @param paused If true, pause the display. If false, resume the display. + // @param show_snow If true, show the snow effect when paused. void set_paused(bool paused, bool show_snow); + bool is_paused() const { return this->paused_; } + // If the display is paused and we have resume_on_input_ set to true, resume the display. + void maybe_wakeup() { + if (this->paused_ && this->resume_on_input_) { + this->set_paused(false, false); + } + } + void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event); void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2); void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2, lv_event_code_t event3); - bool is_paused() const { return this->paused_; } void add_page(LvPageType *page); void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time); void show_next_page(lv_scr_load_anim_t anim, uint32_t time); @@ -144,10 +155,17 @@ class LvglComponent : public PollingComponent { lv_group_focus_obj(mark); } } + // rounding factor to align bounds of update area when drawing + size_t draw_rounding{2}; + void set_draw_rounding(size_t rounding) { this->draw_rounding = rounding; } + void set_resume_on_input(bool resume_on_input) { this->resume_on_input_ = resume_on_input; } + + // if set to true, the bounds of the update area will always start at 0,0 + display::DisplayRotation rotation{display::DISPLAY_ROTATION_0_DEGREES}; protected: void write_random_(); - void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); + void draw_buffer_(const lv_area_t *area, lv_color_t *ptr); void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); std::vector displays_{}; lv_disp_draw_buf_t draw_buf_{}; @@ -157,14 +175,16 @@ class LvglComponent : public PollingComponent { std::vector pages_{}; size_t current_page_{0}; bool show_snow_{}; - lv_coord_t snow_line_{}; bool page_wrap_{true}; + bool resume_on_input_{}; std::map focus_marks_{}; std::vector> init_lambdas_; CallbackManager idle_callbacks_{}; + CallbackManager pause_callbacks_{}; size_t buffer_frac_{1}; bool full_refresh_{}; + lv_color_t *rotate_buf_{}; }; class IdleTrigger : public Trigger<> { @@ -176,6 +196,14 @@ class IdleTrigger : public Trigger<> { bool is_idle_{}; }; +class PauseTrigger : public Trigger<> { + public: + explicit PauseTrigger(LvglComponent *parent, TemplatableValue paused); + + protected: + TemplatableValue paused_; +}; + template class LvglAction : public Action, public Parented { public: explicit LvglAction(std::function &&lamb) : action_(std::move(lamb)) {} @@ -200,7 +228,10 @@ class LVTouchListener : public touchscreen::TouchListener, public Parentedparent_->maybe_wakeup(); + } lv_indev_drv_t *get_drv() { return &this->drv_; } protected: @@ -236,12 +267,18 @@ class LVEncoderListener : public Parented { if (!this->parent_->is_paused()) { this->pressed_ = pressed; this->key_ = key; + } else if (!pressed) { + // maybe wakeup on release if paused + this->parent_->maybe_wakeup(); } } void set_count(int32_t count) { - if (!this->parent_->is_paused()) + if (!this->parent_->is_paused()) { this->count_ = count; + } else { + this->parent_->maybe_wakeup(); + } } lv_indev_drv_t *get_drv() { return &this->drv_; } diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index b452ab5fb3..2d10b67c2d 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -40,6 +40,7 @@ lv_event_code_t = cg.global_ns.enum("lv_event_code_t") lv_indev_type_t = cg.global_ns.enum("lv_indev_type_t") FontEngine = lvgl_ns.class_("FontEngine") IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template()) +PauseTrigger = lvgl_ns.class_("PauseTrigger", automation.Trigger.template()) ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action) LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition) LvglAction = lvgl_ns.class_("LvglAction", automation.Action) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 1770c1bfbc..6aea606ac4 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -12,6 +12,11 @@ substitutions: arrow_down: "\U000F004B" lvgl: + resume_on_input: true + on_pause: + logger.log: LVGL is Paused + on_resume: + logger.log: LVGL has resumed log_level: TRACE bg_color: light_blue disp_bg_color: color_id diff --git a/tests/components/lvgl/test.esp32-ard.yaml b/tests/components/lvgl/test.esp32-ard.yaml index 51593e7967..80d5ce503f 100644 --- a/tests/components/lvgl/test.esp32-ard.yaml +++ b/tests/components/lvgl/test.esp32-ard.yaml @@ -44,6 +44,7 @@ binary_sensor: number: GPIO39 inverted: true lvgl: + draw_rounding: 8 encoders: group: switches initial_focus: button_button From 254522dd9341c9c6cbbb6903a42d787856d68e90 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:26:50 +1100 Subject: [PATCH 2515/2607] [qspi_dbi] Rename from qspi_amoled, add features (#7594) Co-authored-by: clydeps --- CODEOWNERS | 2 +- esphome/components/ili9xxx/display.py | 2 +- esphome/components/qspi_amoled/display.py | 142 +------------- .../{qspi_amoled => qspi_dbi}/__init__.py | 0 esphome/components/qspi_dbi/display.py | 185 ++++++++++++++++++ esphome/components/qspi_dbi/models.py | 64 ++++++ .../qspi_amoled.cpp => qspi_dbi/qspi_dbi.cpp} | 139 ++++++++----- .../qspi_amoled.h => qspi_dbi/qspi_dbi.h} | 41 ++-- esphome/components/st7701s/display.py | 2 +- esphome/const.py | 1 + .../{qspi_amoled => qspi_dbi}/common.yaml | 14 +- .../test.esp32-s3-idf.yaml | 0 12 files changed, 385 insertions(+), 207 deletions(-) rename esphome/components/{qspi_amoled => qspi_dbi}/__init__.py (100%) create mode 100644 esphome/components/qspi_dbi/display.py create mode 100644 esphome/components/qspi_dbi/models.py rename esphome/components/{qspi_amoled/qspi_amoled.cpp => qspi_dbi/qspi_dbi.cpp} (51%) rename esphome/components/{qspi_amoled/qspi_amoled.h => qspi_dbi/qspi_dbi.h} (80%) rename tests/components/{qspi_amoled => qspi_dbi}/common.yaml (73%) rename tests/components/{qspi_amoled => qspi_dbi}/test.esp32-s3-idf.yaml (100%) diff --git a/CODEOWNERS b/CODEOWNERS index a19f3d75ed..7dd18d2c51 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -324,7 +324,7 @@ esphome/components/pvvx_mithermometer/* @pasiz esphome/components/pylontech/* @functionpointer esphome/components/qmp6988/* @andrewpc esphome/components/qr_code/* @wjtje -esphome/components/qspi_amoled/* @clydebarrow +esphome/components/qspi_dbi/* @clydebarrow esphome/components/qwiic_pir/* @kahrendt esphome/components/radon_eye_ble/* @jeffeb3 esphome/components/radon_eye_rd200/* @jeffeb3 diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 2182ca9a6d..68e3aa953d 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_DIMENSIONS, CONF_HEIGHT, CONF_ID, + CONF_INIT_SEQUENCE, CONF_INVERT_COLORS, CONF_LAMBDA, CONF_MIRROR_X, @@ -89,7 +90,6 @@ CONF_LED_PIN = "led_pin" CONF_COLOR_PALETTE_IMAGES = "color_palette_images" CONF_INVERT_DISPLAY = "invert_display" CONF_PIXEL_MODE = "pixel_mode" -CONF_INIT_SEQUENCE = "init_sequence" def cmd(c, *args): diff --git a/esphome/components/qspi_amoled/display.py b/esphome/components/qspi_amoled/display.py index 77d1e3d095..00773b516a 100644 --- a/esphome/components/qspi_amoled/display.py +++ b/esphome/components/qspi_amoled/display.py @@ -1,143 +1,3 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome import pins -from esphome.components import ( - spi, - display, -) -from esphome.const import ( - CONF_RESET_PIN, - CONF_ID, - CONF_DIMENSIONS, - CONF_WIDTH, - CONF_HEIGHT, - CONF_LAMBDA, - CONF_BRIGHTNESS, - CONF_ENABLE_PIN, - CONF_MODEL, - CONF_OFFSET_HEIGHT, - CONF_OFFSET_WIDTH, - CONF_INVERT_COLORS, - CONF_MIRROR_X, - CONF_MIRROR_Y, - CONF_SWAP_XY, - CONF_COLOR_ORDER, - CONF_TRANSFORM, -) -DEPENDENCIES = ["spi"] - -qspi_amoled_ns = cg.esphome_ns.namespace("qspi_amoled") -QSPI_AMOLED = qspi_amoled_ns.class_( - "QspiAmoLed", display.Display, display.DisplayBuffer, cg.Component, spi.SPIDevice -) -ColorOrder = display.display_ns.enum("ColorMode") -Model = qspi_amoled_ns.enum("Model") - -MODELS = {"RM690B0": Model.RM690B0, "RM67162": Model.RM67162} - -COLOR_ORDERS = { - "RGB": ColorOrder.COLOR_ORDER_RGB, - "BGR": ColorOrder.COLOR_ORDER_BGR, -} -DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema - - -def validate_dimension(value): - value = cv.positive_int(value) - if value % 2 != 0: - raise cv.Invalid("Width/height/offset must be divisible by 2") - return value - - -CONFIG_SCHEMA = cv.All( - display.FULL_DISPLAY_SCHEMA.extend( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(QSPI_AMOLED), - cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True), - cv.Required(CONF_DIMENSIONS): cv.Any( - cv.dimensions, - cv.Schema( - { - cv.Required(CONF_WIDTH): validate_dimension, - cv.Required(CONF_HEIGHT): validate_dimension, - cv.Optional( - CONF_OFFSET_HEIGHT, default=0 - ): validate_dimension, - cv.Optional( - CONF_OFFSET_WIDTH, default=0 - ): validate_dimension, - } - ), - ), - cv.Optional(CONF_TRANSFORM): cv.Schema( - { - cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, - cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, - cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, - } - ), - cv.Optional(CONF_COLOR_ORDER, default="RGB"): cv.enum( - COLOR_ORDERS, upper=True - ), - cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, - cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_BRIGHTNESS, default=0xD0): cv.int_range( - 0, 0xFF, min_included=True, max_included=True - ), - } - ).extend( - spi.spi_device_schema( - cs_pin_required=False, - default_mode="MODE0", - default_data_rate=10e6, - quad=True, - ) - ) - ), - cv.only_with_esp_idf, -) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await display.register_display(var, config) - await spi.register_spi_device(var, config) - - cg.add(var.set_color_mode(config[CONF_COLOR_ORDER])) - cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) - cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) - cg.add(var.set_model(config[CONF_MODEL])) - if enable_pin := config.get(CONF_ENABLE_PIN): - enable = await cg.gpio_pin_expression(enable_pin) - cg.add(var.set_enable_pin(enable)) - - if reset_pin := config.get(CONF_RESET_PIN): - reset = await cg.gpio_pin_expression(reset_pin) - cg.add(var.set_reset_pin(reset)) - - if transform := config.get(CONF_TRANSFORM): - cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) - cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) - cg.add(var.set_swap_xy(transform[CONF_SWAP_XY])) - - if CONF_DIMENSIONS in config: - dimensions = config[CONF_DIMENSIONS] - if isinstance(dimensions, dict): - cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) - cg.add( - var.set_offsets( - dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] - ) - ) - else: - (width, height) = dimensions - cg.add(var.set_dimensions(width, height)) - - if lamb := config.get(CONF_LAMBDA): - lambda_ = await cg.process_lambda( - lamb, [(display.DisplayRef, "it")], return_type=cg.void - ) - cg.add(var.set_writer(lambda_)) +CONFIG_SCHEMA = cv.invalid("The qspi_amoled component has been renamed to qspi_dbi") diff --git a/esphome/components/qspi_amoled/__init__.py b/esphome/components/qspi_dbi/__init__.py similarity index 100% rename from esphome/components/qspi_amoled/__init__.py rename to esphome/components/qspi_dbi/__init__.py diff --git a/esphome/components/qspi_dbi/display.py b/esphome/components/qspi_dbi/display.py new file mode 100644 index 0000000000..71ae31f182 --- /dev/null +++ b/esphome/components/qspi_dbi/display.py @@ -0,0 +1,185 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import display, spi +import esphome.config_validation as cv +from esphome.const import ( + CONF_BRIGHTNESS, + CONF_COLOR_ORDER, + CONF_DIMENSIONS, + CONF_ENABLE_PIN, + CONF_HEIGHT, + CONF_ID, + CONF_INIT_SEQUENCE, + CONF_INVERT_COLORS, + CONF_LAMBDA, + CONF_MIRROR_X, + CONF_MIRROR_Y, + CONF_MODEL, + CONF_OFFSET_HEIGHT, + CONF_OFFSET_WIDTH, + CONF_RESET_PIN, + CONF_SWAP_XY, + CONF_TRANSFORM, + CONF_WIDTH, +) +from esphome.core import TimePeriod + +from .models import DriverChip + +DEPENDENCIES = ["spi"] + +qspi_dbi_ns = cg.esphome_ns.namespace("qspi_dbi") +QSPI_DBI = qspi_dbi_ns.class_( + "QspiDbi", display.Display, display.DisplayBuffer, cg.Component, spi.SPIDevice +) +ColorOrder = display.display_ns.enum("ColorMode") +Model = qspi_dbi_ns.enum("Model") + +COLOR_ORDERS = { + "RGB": ColorOrder.COLOR_ORDER_RGB, + "BGR": ColorOrder.COLOR_ORDER_BGR, +} +DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + +CONF_DRAW_FROM_ORIGIN = "draw_from_origin" +DELAY_FLAG = 0xFF + + +def validate_dimension(value): + value = cv.positive_int(value) + if value % 2 != 0: + raise cv.Invalid("Width/height/offset must be divisible by 2") + return value + + +def map_sequence(value): + """ + The format is a repeated sequence of [CMD, ] where is s a sequence of bytes. The length is inferred + from the length of the sequence and should not be explicit. + A delay can be inserted by specifying "- delay N" where N is in ms + """ + if isinstance(value, str) and value.lower().startswith("delay "): + value = value.lower()[6:] + delay = cv.All( + cv.positive_time_period_milliseconds, + cv.Range(TimePeriod(milliseconds=1), TimePeriod(milliseconds=255)), + )(value) + return [delay, DELAY_FLAG] + value = cv.Length(min=1, max=254)(value) + params = value[1:] + return [value[0], len(params)] + list(params) + + +def _validate(config): + chip = DriverChip.chips[config[CONF_MODEL]] + if not chip.initsequence: + if CONF_INIT_SEQUENCE not in config: + raise cv.Invalid(f"{chip.name} model requires init_sequence") + return config + + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(QSPI_DBI), + cv.Required(CONF_MODEL): cv.one_of( + *DriverChip.chips.keys(), upper=True + ), + cv.Optional(CONF_INIT_SEQUENCE): cv.ensure_list(map_sequence), + cv.Required(CONF_DIMENSIONS): cv.Any( + cv.dimensions, + cv.Schema( + { + cv.Required(CONF_WIDTH): validate_dimension, + cv.Required(CONF_HEIGHT): validate_dimension, + cv.Optional( + CONF_OFFSET_HEIGHT, default=0 + ): validate_dimension, + cv.Optional( + CONF_OFFSET_WIDTH, default=0 + ): validate_dimension, + } + ), + ), + cv.Optional(CONF_TRANSFORM): cv.Schema( + { + cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, + cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, + cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, + } + ), + cv.Optional(CONF_COLOR_ORDER, default="RGB"): cv.enum( + COLOR_ORDERS, upper=True + ), + cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_BRIGHTNESS, default=0xD0): cv.int_range( + 0, 0xFF, min_included=True, max_included=True + ), + cv.Optional(CONF_DRAW_FROM_ORIGIN, default=False): cv.boolean, + } + ).extend( + spi.spi_device_schema( + cs_pin_required=False, + default_mode="MODE0", + default_data_rate=10e6, + quad=True, + ) + ) + ), + cv.only_with_esp_idf, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await display.register_display(var, config) + await spi.register_spi_device(var, config) + + chip = DriverChip.chips[config[CONF_MODEL]] + if chip.initsequence: + cg.add(var.add_init_sequence(chip.initsequence)) + if init_sequences := config.get(CONF_INIT_SEQUENCE): + sequence = [] + for seq in init_sequences: + sequence.extend(seq) + cg.add(var.add_init_sequence(sequence)) + + cg.add(var.set_color_mode(config[CONF_COLOR_ORDER])) + cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) + cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) + cg.add(var.set_model(config[CONF_MODEL])) + cg.add(var.set_draw_from_origin(config[CONF_DRAW_FROM_ORIGIN])) + if enable_pin := config.get(CONF_ENABLE_PIN): + enable = await cg.gpio_pin_expression(enable_pin) + cg.add(var.set_enable_pin(enable)) + + if reset_pin := config.get(CONF_RESET_PIN): + reset = await cg.gpio_pin_expression(reset_pin) + cg.add(var.set_reset_pin(reset)) + + if transform := config.get(CONF_TRANSFORM): + cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) + cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) + cg.add(var.set_swap_xy(transform[CONF_SWAP_XY])) + + if CONF_DIMENSIONS in config: + dimensions = config[CONF_DIMENSIONS] + if isinstance(dimensions, dict): + cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) + cg.add( + var.set_offsets( + dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] + ) + ) + else: + (width, height) = dimensions + cg.add(var.set_dimensions(width, height)) + + if lamb := config.get(CONF_LAMBDA): + lambda_ = await cg.process_lambda( + lamb, [(display.DisplayRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/qspi_dbi/models.py b/esphome/components/qspi_dbi/models.py new file mode 100644 index 0000000000..071ea72d73 --- /dev/null +++ b/esphome/components/qspi_dbi/models.py @@ -0,0 +1,64 @@ +# Commands +SW_RESET_CMD = 0x01 +SLEEP_OUT = 0x11 +INVERT_OFF = 0x20 +INVERT_ON = 0x21 +ALL_ON = 0x23 +WRAM = 0x24 +MIPI = 0x26 +DISPLAY_OFF = 0x28 +DISPLAY_ON = 0x29 +RASET = 0x2B +CASET = 0x2A +WDATA = 0x2C +TEON = 0x35 +MADCTL_CMD = 0x36 +PIXFMT = 0x3A +BRIGHTNESS = 0x51 +SWIRE1 = 0x5A +SWIRE2 = 0x5B +PAGESEL = 0xFE + + +class DriverChip: + chips = {} + + def __init__(self, name: str): + name = name.upper() + self.name = name + self.chips[name] = self + self.initsequence = [] + + def cmd(self, c, *args): + """ + Add a command sequence to the init sequence + :param c: The command (8 bit) + :param args: zero or more arguments (8 bit values) + """ + self.initsequence.extend([c, len(args)] + list(args)) + + def delay(self, ms): + self.initsequence.extend([ms, 0xFF]) + + +chip = DriverChip("RM67162") +chip.cmd(PIXFMT, 0x55) +chip.cmd(BRIGHTNESS, 0) + +chip = DriverChip("RM690B0") +chip.cmd(PAGESEL, 0x20) +chip.cmd(MIPI, 0x0A) +chip.cmd(WRAM, 0x80) +chip.cmd(SWIRE1, 0x51) +chip.cmd(SWIRE2, 0x2E) +chip.cmd(PAGESEL, 0x00) +chip.cmd(0xC2, 0x00) +chip.delay(10) +chip.cmd(TEON, 0x00) + +chip = DriverChip("AXS15231") +chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) +chip.cmd(0xC1, 0x33) +chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + +DriverChip("Custom") diff --git a/esphome/components/qspi_amoled/qspi_amoled.cpp b/esphome/components/qspi_dbi/qspi_dbi.cpp similarity index 51% rename from esphome/components/qspi_amoled/qspi_amoled.cpp rename to esphome/components/qspi_dbi/qspi_dbi.cpp index b1f651025a..a649a25ea6 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.cpp +++ b/esphome/components/qspi_dbi/qspi_dbi.cpp @@ -1,12 +1,12 @@ #ifdef USE_ESP_IDF -#include "qspi_amoled.h" +#include "qspi_dbi.h" #include "esphome/core/log.h" namespace esphome { -namespace qspi_amoled { +namespace qspi_dbi { -void QspiAmoLed::setup() { - esph_log_config(TAG, "Setting up QSPI_AMOLED"); +void QspiDbi::setup() { + ESP_LOGCONFIG(TAG, "Setting up QSPI_DBI"); this->spi_setup(); if (this->enable_pin_ != nullptr) { this->enable_pin_->setup(); @@ -22,13 +22,17 @@ void QspiAmoLed::setup() { } this->set_timeout(120, [this] { this->write_command_(SLEEP_OUT); }); this->set_timeout(240, [this] { this->write_init_sequence_(); }); + if (this->draw_from_origin_) + check_buffer_(); } -void QspiAmoLed::update() { +void QspiDbi::update() { if (!this->setup_complete_) { return; } this->do_update_(); + if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_) + return; // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet) if (this->x_low_ % 2 == 1) { this->x_low_--; @@ -42,10 +46,15 @@ void QspiAmoLed::update() { if (this->y_high_ % 2 == 0) { this->y_high_++; } + if (this->draw_from_origin_) { + this->x_low_ = 0; + this->y_low_ = 0; + this->x_high_ = this->width_ - 1; + } int w = this->x_high_ - this->x_low_ + 1; int h = this->y_high_ - this->y_low_ + 1; - this->draw_pixels_at(this->x_low_, this->y_low_, w, h, this->buffer_, this->color_mode_, display::COLOR_BITNESS_565, - true, this->x_low_, this->y_low_, this->get_width_internal() - w - this->x_low_); + this->write_to_display_(this->x_low_, this->y_low_, w, h, this->buffer_, this->x_low_, this->y_low_, + this->width_ - w - this->x_low_); // invalidate watermarks this->x_low_ = this->width_; this->y_low_ = this->height_; @@ -53,21 +62,19 @@ void QspiAmoLed::update() { this->y_high_ = 0; } -void QspiAmoLed::draw_absolute_pixel_internal(int x, int y, Color color) { +void QspiDbi::draw_absolute_pixel_internal(int x, int y, Color color) { if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) { return; } - if (this->buffer_ == nullptr) - this->init_internal_(this->width_ * this->height_ * 2); if (this->is_failed()) return; + check_buffer_(); uint32_t pos = (y * this->width_) + x; - uint16_t new_color; bool updated = false; pos = pos * 2; - new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); - if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) { - this->buffer_[pos] = (uint8_t) (new_color >> 8); + uint16_t new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); + if (this->buffer_[pos] != static_cast(new_color >> 8)) { + this->buffer_[pos] = static_cast(new_color >> 8); updated = true; } pos = pos + 1; @@ -90,7 +97,7 @@ void QspiAmoLed::draw_absolute_pixel_internal(int x, int y, Color color) { } } -void QspiAmoLed::reset_params_(bool ready) { +void QspiDbi::reset_params_(bool ready) { if (!ready && !this->is_ready()) return; this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); @@ -102,55 +109,64 @@ void QspiAmoLed::reset_params_(bool ready) { mad |= MADCTL_MX; if (this->mirror_y_) mad |= MADCTL_MY; - this->write_command_(MADCTL_CMD, &mad, 1); - this->write_command_(BRIGHTNESS, &this->brightness_, 1); + this->write_command_(MADCTL_CMD, mad); + this->write_command_(BRIGHTNESS, this->brightness_); + this->write_command_(NORON); + this->write_command_(DISPLAY_ON); } -void QspiAmoLed::write_init_sequence_() { - if (this->model_ == RM690B0) { - this->write_command_(PAGESEL, 0x20); - this->write_command_(MIPI, 0x0A); - this->write_command_(WRAM, 0x80); - this->write_command_(SWIRE1, 0x51); - this->write_command_(SWIRE2, 0x2E); - this->write_command_(PAGESEL, 0x00); - this->write_command_(0xC2, 0x00); - delay(10); - this->write_command_(TEON, 0x00); +void QspiDbi::write_init_sequence_() { + for (const auto &seq : this->init_sequences_) { + this->write_sequence_(seq); } - this->write_command_(PIXFMT, 0x55); - this->write_command_(BRIGHTNESS, 0); - this->write_command_(DISPLAY_ON); this->reset_params_(true); this->setup_complete_ = true; - esph_log_config(TAG, "QSPI_AMOLED setup complete"); + ESP_LOGCONFIG(TAG, "QSPI_DBI setup complete"); } -void QspiAmoLed::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { +void QspiDbi::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { + ESP_LOGVV(TAG, "Set addr %d/%d, %d/%d", x1, y1, x2, y2); uint8_t buf[4]; x1 += this->offset_x_; x2 += this->offset_x_; y1 += this->offset_y_; y2 += this->offset_y_; - put16_be(buf, x1); - put16_be(buf + 2, x2); - this->write_command_(CASET, buf, sizeof buf); put16_be(buf, y1); put16_be(buf + 2, y2); this->write_command_(RASET, buf, sizeof buf); + put16_be(buf, x1); + put16_be(buf + 2, x2); + this->write_command_(CASET, buf, sizeof buf); } -void QspiAmoLed::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, - display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { +void QspiDbi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, + display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { if (!this->setup_complete_ || this->is_failed()) return; if (w <= 0 || h <= 0) return; if (bitness != display::COLOR_BITNESS_565 || order != this->color_mode_ || big_endian != (this->bit_order_ == spi::BIT_ORDER_MSB_FIRST)) { - return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, - x_pad); + return Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad); + } else if (this->draw_from_origin_) { + auto stride = x_offset + w + x_pad; + for (int y = 0; y != h; y++) { + memcpy(this->buffer_ + ((y + y_start) * this->width_ + x_start) * 2, + ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2); + } + ptr = this->buffer_; + w = this->width_; + h += y_start; + x_start = 0; + y_start = 0; + x_offset = 0; + y_offset = 0; } + this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad); +} + +void QspiDbi::write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset, + int x_pad) { this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1); this->enable(); // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. @@ -158,17 +174,50 @@ void QspiAmoLed::draw_pixels_at(int x_start, int y_start, int w, int h, const ui // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, ptr, w * h * 2, 4); } else { - this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, nullptr, 0, 4); auto stride = x_offset + w + x_pad; + uint16_t cmd = 0x2C00; for (int y = 0; y != h; y++) { - this->write_cmd_addr_data(0, 0, 0, 0, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4); + this->write_cmd_addr_data(8, 0x32, 24, cmd, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4); + cmd = 0x3C00; } } this->disable(); } +void QspiDbi::write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) { + ESP_LOGV(TAG, "Command %02X, length %d, bytes %s", cmd, len, format_hex_pretty(bytes, len).c_str()); + this->enable(); + this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len); + this->disable(); +} -void QspiAmoLed::dump_config() { - ESP_LOGCONFIG("", "QSPI AMOLED"); +void QspiDbi::write_sequence_(const std::vector &vec) { + size_t index = 0; + while (index != vec.size()) { + if (vec.size() - index < 2) { + ESP_LOGE(TAG, "Malformed init sequence"); + return; + } + uint8_t cmd = vec[index++]; + uint8_t x = vec[index++]; + if (x == DELAY_FLAG) { + ESP_LOGV(TAG, "Delay %dms", cmd); + delay(cmd); + } else { + uint8_t num_args = x & 0x7F; + if (vec.size() - index < num_args) { + ESP_LOGE(TAG, "Malformed init sequence"); + return; + } + const auto *ptr = vec.data() + index; + this->write_command_(cmd, ptr, num_args); + index += num_args; + } + } +} + +void QspiDbi::dump_config() { + ESP_LOGCONFIG("", "QSPI_DBI Display"); + ESP_LOGCONFIG("", "Model: %s", this->model_); ESP_LOGCONFIG(TAG, " Height: %u", this->height_); ESP_LOGCONFIG(TAG, " Width: %u", this->width_); LOG_PIN(" CS Pin: ", this->cs_); @@ -176,6 +225,6 @@ void QspiAmoLed::dump_config() { ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); } -} // namespace qspi_amoled +} // namespace qspi_dbi } // namespace esphome #endif diff --git a/esphome/components/qspi_amoled/qspi_amoled.h b/esphome/components/qspi_dbi/qspi_dbi.h similarity index 80% rename from esphome/components/qspi_amoled/qspi_amoled.h rename to esphome/components/qspi_dbi/qspi_dbi.h index c766b4e685..ebb65a8a05 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.h +++ b/esphome/components/qspi_dbi/qspi_dbi.h @@ -14,11 +14,12 @@ #include "esp_lcd_panel_rgb.h" namespace esphome { -namespace qspi_amoled { +namespace qspi_dbi { -constexpr static const char *const TAG = "display.qspi_amoled"; +constexpr static const char *const TAG = "display.qspi_dbi"; static const uint8_t SW_RESET_CMD = 0x01; static const uint8_t SLEEP_OUT = 0x11; +static const uint8_t NORON = 0x13; static const uint8_t INVERT_OFF = 0x20; static const uint8_t INVERT_ON = 0x21; static const uint8_t ALL_ON = 0x23; @@ -42,6 +43,7 @@ static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order +static const uint8_t DELAY_FLAG = 0xFF; // store a 16 bit value in a buffer, big endian. static inline void put16_be(uint8_t *buf, uint16_t value) { buf[0] = value >> 8; @@ -49,15 +51,16 @@ static inline void put16_be(uint8_t *buf, uint16_t value) { } enum Model { + CUSTOM, RM690B0, RM67162, }; -class QspiAmoLed : public display::DisplayBuffer, - public spi::SPIDevice { +class QspiDbi : public display::DisplayBuffer, + public spi::SPIDevice { public: - void set_model(Model model) { this->model_ = model; } + void set_model(const char *model) { this->model_ = model; } void update() override; void setup() override; display::ColorOrder get_color_mode() { return this->color_mode_; } @@ -93,17 +96,27 @@ class QspiAmoLed : public display::DisplayBuffer, this->offset_x_ = offset_x; this->offset_y_ = offset_y; } + + void set_draw_from_origin(bool draw_from_origin) { this->draw_from_origin_ = draw_from_origin; } display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } void dump_config() override; int get_width_internal() override { return this->width_; } int get_height_internal() override { return this->height_; } bool can_proceed() override { return this->setup_complete_; } + void add_init_sequence(const std::vector &sequence) { this->init_sequences_.push_back(sequence); } protected: + void check_buffer_() { + if (this->buffer_ == nullptr) + this->init_internal_(this->width_ * this->height_ * 2); + } + void write_sequence_(const std::vector &vec); void draw_absolute_pixel_internal(int x, int y, Color color) override; void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; + void write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset, + int x_pad); /** * the RM67162 in quad SPI mode seems to work like this (not in the datasheet, this is deduced from the * sample code.) @@ -122,11 +135,7 @@ class QspiAmoLed : public display::DisplayBuffer, * @param bytes * @param len */ - void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) { - this->enable(); - this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len); - this->disable(); - } + void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len); void write_command_(uint8_t cmd, uint8_t data) { this->write_command_(cmd, &data, 1); } void write_command_(uint8_t cmd) { this->write_command_(cmd, &cmd, 0); } @@ -136,8 +145,8 @@ class QspiAmoLed : public display::DisplayBuffer, GPIOPin *reset_pin_{nullptr}; GPIOPin *enable_pin_{nullptr}; - uint16_t x_low_{0}; - uint16_t y_low_{0}; + uint16_t x_low_{1}; + uint16_t y_low_{1}; uint16_t x_high_{0}; uint16_t y_high_{0}; bool setup_complete_{}; @@ -151,12 +160,14 @@ class QspiAmoLed : public display::DisplayBuffer, bool swap_xy_{}; bool mirror_x_{}; bool mirror_y_{}; + bool draw_from_origin_{false}; uint8_t brightness_{0xD0}; - Model model_{RM690B0}; + const char *model_{"Unknown"}; + std::vector> init_sequences_{}; esp_lcd_panel_handle_t handle_{}; }; -} // namespace qspi_amoled +} // namespace qspi_dbi } // namespace esphome #endif diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py index 9310e9d760..e73c2467da 100644 --- a/esphome/components/st7701s/display.py +++ b/esphome/components/st7701s/display.py @@ -18,6 +18,7 @@ from esphome.const import ( CONF_HSYNC_PIN, CONF_ID, CONF_IGNORE_STRAPPING_WARNING, + CONF_INIT_SEQUENCE, CONF_INVERT_COLORS, CONF_LAMBDA, CONF_MIRROR_X, @@ -35,7 +36,6 @@ from esphome.core import TimePeriod from .init_sequences import ST7701S_INITS, cmd -CONF_INIT_SEQUENCE = "init_sequence" CONF_DE_PIN = "de_pin" CONF_PCLK_PIN = "pclk_pin" diff --git a/esphome/const.py b/esphome/const.py index 7665c77a32..a3a4318d69 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -398,6 +398,7 @@ CONF_INCLUDES = "includes" CONF_INDEX = "index" CONF_INDOOR = "indoor" CONF_INFRARED = "infrared" +CONF_INIT_SEQUENCE = "init_sequence" CONF_INITIAL_MODE = "initial_mode" CONF_INITIAL_OPTION = "initial_option" CONF_INITIAL_STATE = "initial_state" diff --git a/tests/components/qspi_amoled/common.yaml b/tests/components/qspi_dbi/common.yaml similarity index 73% rename from tests/components/qspi_amoled/common.yaml rename to tests/components/qspi_dbi/common.yaml index 01d1a63bcb..655af304af 100644 --- a/tests/components/qspi_amoled/common.yaml +++ b/tests/components/qspi_dbi/common.yaml @@ -5,7 +5,7 @@ spi: data_pins: [14, 10, 16, 12] display: - - platform: qspi_amoled + - platform: qspi_dbi model: RM690B0 data_rate: 80MHz spi_mode: mode0 @@ -20,9 +20,10 @@ display: reset_pin: 13 enable_pin: 9 - - platform: qspi_amoled - model: RM67162 + - platform: qspi_dbi + model: CUSTOM id: main_lcd + draw_from_origin: true dimensions: height: 240 width: 536 @@ -34,3 +35,10 @@ display: cs_pin: 6 reset_pin: 17 enable_pin: 38 + init_sequence: + - [0x3A, 0x66] + - [0x11] + - delay 120ms + - [0x29] + - delay 20ms + diff --git a/tests/components/qspi_amoled/test.esp32-s3-idf.yaml b/tests/components/qspi_dbi/test.esp32-s3-idf.yaml similarity index 100% rename from tests/components/qspi_amoled/test.esp32-s3-idf.yaml rename to tests/components/qspi_dbi/test.esp32-s3-idf.yaml From fa01149771be89caafe4a4103768bb83b6ca947a Mon Sep 17 00:00:00 2001 From: Paul Blacknell Date: Wed, 16 Oct 2024 04:28:24 +0100 Subject: [PATCH 2516/2607] Add support for Analog Devices MAX17043 battery fuel gauge (#7522) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/max17043/__init__.py | 1 + esphome/components/max17043/automation.h | 20 ++++ esphome/components/max17043/max17043.cpp | 98 +++++++++++++++++++ esphome/components/max17043/max17043.h | 29 ++++++ esphome/components/max17043/sensor.py | 77 +++++++++++++++ tests/components/max17043/common.yaml | 19 ++++ tests/components/max17043/test.esp32-ard.yaml | 6 ++ .../max17043/test.esp32-c3-ard.yaml | 5 + .../max17043/test.esp32-c3-idf.yaml | 5 + tests/components/max17043/test.esp32-idf.yaml | 5 + .../components/max17043/test.esp8266-ard.yaml | 5 + .../components/max17043/test.rp2040-ard.yaml | 5 + 13 files changed, 276 insertions(+) create mode 100644 esphome/components/max17043/__init__.py create mode 100644 esphome/components/max17043/automation.h create mode 100644 esphome/components/max17043/max17043.cpp create mode 100644 esphome/components/max17043/max17043.h create mode 100644 esphome/components/max17043/sensor.py create mode 100644 tests/components/max17043/common.yaml create mode 100644 tests/components/max17043/test.esp32-ard.yaml create mode 100644 tests/components/max17043/test.esp32-c3-ard.yaml create mode 100644 tests/components/max17043/test.esp32-c3-idf.yaml create mode 100644 tests/components/max17043/test.esp32-idf.yaml create mode 100644 tests/components/max17043/test.esp8266-ard.yaml create mode 100644 tests/components/max17043/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 7dd18d2c51..d6104c9345 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -237,6 +237,7 @@ esphome/components/ltr_als_ps/* @latonita esphome/components/lvgl/* @clydebarrow esphome/components/m5stack_8angle/* @rnauber esphome/components/matrix_keypad/* @ssieb +esphome/components/max17043/* @blacknell esphome/components/max31865/* @DAVe3283 esphome/components/max44009/* @berfenger esphome/components/max6956/* @looping40 diff --git a/esphome/components/max17043/__init__.py b/esphome/components/max17043/__init__.py new file mode 100644 index 0000000000..1db25ccdd6 --- /dev/null +++ b/esphome/components/max17043/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@blacknell"] diff --git a/esphome/components/max17043/automation.h b/esphome/components/max17043/automation.h new file mode 100644 index 0000000000..44729d119b --- /dev/null +++ b/esphome/components/max17043/automation.h @@ -0,0 +1,20 @@ + +#pragma once +#include "esphome/core/automation.h" +#include "max17043.h" + +namespace esphome { +namespace max17043 { + +template class SleepAction : public Action { + public: + explicit SleepAction(MAX17043Component *max17043) : max17043_(max17043) {} + + void play(Ts... x) override { this->max17043_->sleep_mode(); } + + protected: + MAX17043Component *max17043_; +}; + +} // namespace max17043 +} // namespace esphome diff --git a/esphome/components/max17043/max17043.cpp b/esphome/components/max17043/max17043.cpp new file mode 100644 index 0000000000..4a83320455 --- /dev/null +++ b/esphome/components/max17043/max17043.cpp @@ -0,0 +1,98 @@ +#include "max17043.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace max17043 { + +// MAX174043 is a 1-Cell Fuel Gauge with ModelGauge and Low-Battery Alert +// Consult the datasheet at https://www.analog.com/en/products/max17043.html + +static const char *const TAG = "max17043"; + +static const uint8_t MAX17043_VCELL = 0x02; +static const uint8_t MAX17043_SOC = 0x04; +static const uint8_t MAX17043_CONFIG = 0x0c; + +static const uint16_t MAX17043_CONFIG_POWER_UP_DEFAULT = 0x971C; +static const uint16_t MAX17043_CONFIG_SAFE_MASK = 0xFF1F; // mask out sleep bit (7), unused bit (6) and alert bit (4) +static const uint16_t MAX17043_CONFIG_SLEEP_MASK = 0x0080; + +void MAX17043Component::update() { + uint16_t raw_voltage, raw_percent; + + if (this->voltage_sensor_ != nullptr) { + if (!this->read_byte_16(MAX17043_VCELL, &raw_voltage)) { + this->status_set_warning("Unable to read MAX17043_VCELL"); + } else { + float voltage = (1.25 * (float) (raw_voltage >> 4)) / 1000.0; + this->voltage_sensor_->publish_state(voltage); + this->status_clear_warning(); + } + } + if (this->battery_remaining_sensor_ != nullptr) { + if (!this->read_byte_16(MAX17043_SOC, &raw_percent)) { + this->status_set_warning("Unable to read MAX17043_SOC"); + } else { + float percent = (float) ((raw_percent >> 8) + 0.003906f * (raw_percent & 0x00ff)); + this->battery_remaining_sensor_->publish_state(percent); + this->status_clear_warning(); + } + } +} + +void MAX17043Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up MAX17043..."); + + uint16_t config_reg; + if (this->write(&MAX17043_CONFIG, 1) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + if (this->read(reinterpret_cast(&config_reg), 2) != i2c::ERROR_OK) { + this->status_set_warning(); + return; + } + + config_reg = i2c::i2ctohs(config_reg) & MAX17043_CONFIG_SAFE_MASK; + ESP_LOGV(TAG, "MAX17043 CONFIG register reads 0x%X", config_reg); + + if (config_reg != MAX17043_CONFIG_POWER_UP_DEFAULT) { + ESP_LOGE(TAG, "Device does not appear to be a MAX17043"); + this->status_set_error("unrecognised"); + this->mark_failed(); + return; + } + + // need to write back to config register to reset the sleep bit + if (!this->write_byte_16(MAX17043_CONFIG, MAX17043_CONFIG_POWER_UP_DEFAULT)) { + this->status_set_error("sleep reset failed"); + this->mark_failed(); + return; + } +} + +void MAX17043Component::dump_config() { + ESP_LOGCONFIG(TAG, "MAX17043:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with MAX17043 failed"); + } + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Battery Voltage", this->voltage_sensor_); + LOG_SENSOR(" ", "Battery Level", this->battery_remaining_sensor_); +} + +float MAX17043Component::get_setup_priority() const { return setup_priority::DATA; } + +void MAX17043Component::sleep_mode() { + if (!this->is_failed()) { + if (!this->write_byte_16(MAX17043_CONFIG, MAX17043_CONFIG_POWER_UP_DEFAULT | MAX17043_CONFIG_SLEEP_MASK)) { + ESP_LOGW(TAG, "Unable to write the sleep bit to config register"); + this->status_set_warning(); + } + } +} + +} // namespace max17043 +} // namespace esphome diff --git a/esphome/components/max17043/max17043.h b/esphome/components/max17043/max17043.h new file mode 100644 index 0000000000..540b977789 --- /dev/null +++ b/esphome/components/max17043/max17043.h @@ -0,0 +1,29 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace max17043 { + +class MAX17043Component : public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + void sleep_mode(); + + void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } + void set_battery_remaining_sensor(sensor::Sensor *battery_remaining_sensor) { + battery_remaining_sensor_ = battery_remaining_sensor; + } + + protected: + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *battery_remaining_sensor_{nullptr}; +}; + +} // namespace max17043 +} // namespace esphome diff --git a/esphome/components/max17043/sensor.py b/esphome/components/max17043/sensor.py new file mode 100644 index 0000000000..3da0f953b0 --- /dev/null +++ b/esphome/components/max17043/sensor.py @@ -0,0 +1,77 @@ +from esphome import automation +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_BATTERY_LEVEL, + CONF_BATTERY_VOLTAGE, + CONF_ID, + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_VOLTAGE, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_MEASUREMENT, + UNIT_PERCENT, + UNIT_VOLT, +) + +DEPENDENCIES = ["i2c"] + +max17043_ns = cg.esphome_ns.namespace("max17043") +MAX17043Component = max17043_ns.class_( + "MAX17043Component", cg.PollingComponent, i2c.I2CDevice +) + +# Actions +SleepAction = max17043_ns.class_("SleepAction", automation.Action) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MAX17043Component), + cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_BATTERY, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x36)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if voltage_config := config.get(CONF_BATTERY_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) + cg.add(var.set_voltage_sensor(sens)) + + if CONF_BATTERY_LEVEL in config: + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + cg.add(var.set_battery_remaining_sensor(sens)) + + +MAX17043_ACTION_SCHEMA = maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(MAX17043Component), + } +) + + +@automation.register_action("max17043.sleep_mode", SleepAction, MAX17043_ACTION_SCHEMA) +async def max17043_sleep_mode_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/tests/components/max17043/common.yaml b/tests/components/max17043/common.yaml new file mode 100644 index 0000000000..c2f324212e --- /dev/null +++ b/tests/components/max17043/common.yaml @@ -0,0 +1,19 @@ +esphome: + on_boot: + then: + - max17043.sleep_mode: max17043_id + +i2c: + - id: i2c_id + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: max17043 + id: max17043_id + i2c_id: i2c_id + battery_voltage: + name: "Battery Voltage" + battery_level: + name: Battery + update_interval: 10s diff --git a/tests/components/max17043/test.esp32-ard.yaml b/tests/components/max17043/test.esp32-ard.yaml new file mode 100644 index 0000000000..c84e0a5c2e --- /dev/null +++ b/tests/components/max17043/test.esp32-ard.yaml @@ -0,0 +1,6 @@ +substitutions: + sda_pin: GPIO21 + scl_pin: GPIO22 + +<<: !include common.yaml + diff --git a/tests/components/max17043/test.esp32-c3-ard.yaml b/tests/components/max17043/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..9a1477d4b9 --- /dev/null +++ b/tests/components/max17043/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + sda_pin: GPIO8 + scl_pin: GPIO10 + +<<: !include common.yaml diff --git a/tests/components/max17043/test.esp32-c3-idf.yaml b/tests/components/max17043/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..9a1477d4b9 --- /dev/null +++ b/tests/components/max17043/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + sda_pin: GPIO8 + scl_pin: GPIO10 + +<<: !include common.yaml diff --git a/tests/components/max17043/test.esp32-idf.yaml b/tests/components/max17043/test.esp32-idf.yaml new file mode 100644 index 0000000000..c6615f51cd --- /dev/null +++ b/tests/components/max17043/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + sda_pin: GPIO21 + scl_pin: GPIO22 + +<<: !include common.yaml diff --git a/tests/components/max17043/test.esp8266-ard.yaml b/tests/components/max17043/test.esp8266-ard.yaml new file mode 100644 index 0000000000..a87353b78b --- /dev/null +++ b/tests/components/max17043/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + sda_pin: GPIO4 + scl_pin: GPIO5 + +<<: !include common.yaml diff --git a/tests/components/max17043/test.rp2040-ard.yaml b/tests/components/max17043/test.rp2040-ard.yaml new file mode 100644 index 0000000000..c6615f51cd --- /dev/null +++ b/tests/components/max17043/test.rp2040-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + sda_pin: GPIO21 + scl_pin: GPIO22 + +<<: !include common.yaml From c38cc128dbfc711fb34cbcf59cf1bd89cb16fd65 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Wed, 16 Oct 2024 00:26:17 -0400 Subject: [PATCH 2517/2607] chore: bump pyyaml to 6.0.2 to support py3.13 build (#7610) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3ffd364d87..a89d3e281f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ async_timeout==4.0.3; python_version <= "3.10" cryptography==43.0.0 voluptuous==0.14.2 -PyYAML==6.0.1 +PyYAML==6.0.2 paho-mqtt==1.6.1 colorama==0.4.6 icmplib==3.0.4 From 22478ffb0f8fd67f4b8a0db9c2b84b5f12d27400 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Wed, 16 Oct 2024 00:26:48 -0400 Subject: [PATCH 2518/2607] chore: bump platformio to 6.1.16 to support py3.13 build (#7590) --- docker/Dockerfile | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 85823687c2..52a4794f24 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -86,7 +86,7 @@ RUN \ pip3 install \ --break-system-packages --no-cache-dir \ # Keep platformio version in sync with requirements.txt - platformio==6.1.15 \ + platformio==6.1.16 \ # Change some platformio settings && platformio settings set enable_telemetry No \ && platformio settings set check_platformio_interval 1000000 \ diff --git a/requirements.txt b/requirements.txt index a89d3e281f..c03a9f181a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ tornado==6.4 tzlocal==5.2 # from time tzdata>=2021.1 # from time pyserial==3.5 -platformio==6.1.15 # When updating platformio, also update Dockerfile +platformio==6.1.16 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 esphome-dashboard==20240620.0 From 1c845e0ff87676d93b46ada90f6973122b0fabf3 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 16 Oct 2024 18:47:11 -0400 Subject: [PATCH 2519/2607] [speaker, i2s_audio] I2S Speaker implementation using a ring buffer (#7605) --- CODEOWNERS | 1 + esphome/components/audio/__init__.py | 9 + esphome/components/audio/audio.h | 21 + .../components/i2s_audio/speaker/__init__.py | 3 +- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 651 +++++++++++------- .../i2s_audio/speaker/i2s_audio_speaker.h | 111 ++- esphome/components/speaker/__init__.py | 25 +- esphome/components/speaker/automation.h | 5 + esphome/components/speaker/speaker.h | 37 +- tests/components/speaker/test.esp32-ard.yaml | 1 + .../components/speaker/test.esp32-c3-ard.yaml | 1 + .../components/speaker/test.esp32-c3-idf.yaml | 1 + tests/components/speaker/test.esp32-idf.yaml | 1 + 13 files changed, 601 insertions(+), 266 deletions(-) create mode 100644 esphome/components/audio/__init__.py create mode 100644 esphome/components/audio/audio.h diff --git a/CODEOWNERS b/CODEOWNERS index d6104c9345..7ac6aa2f76 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -48,6 +48,7 @@ esphome/components/at581x/* @X-Ryl669 esphome/components/atc_mithermometer/* @ahpohl esphome/components/atm90e26/* @danieltwagner esphome/components/atm90e32/* @circuitsetup @descipher +esphome/components/audio/* @kahrendt esphome/components/audio_dac/* @kbx81 esphome/components/b_parasite/* @rbaron esphome/components/ballu/* @bazuchan diff --git a/esphome/components/audio/__init__.py b/esphome/components/audio/__init__.py new file mode 100644 index 0000000000..4ffdc401dc --- /dev/null +++ b/esphome/components/audio/__init__.py @@ -0,0 +1,9 @@ +import esphome.codegen as cg +import esphome.config_validation as cv + +CODEOWNERS = ["@kahrendt"] +audio_ns = cg.esphome_ns.namespace("audio") + +CONFIG_SCHEMA = cv.All( + cv.Schema({}), +) diff --git a/esphome/components/audio/audio.h b/esphome/components/audio/audio.h new file mode 100644 index 0000000000..b0968dc8da --- /dev/null +++ b/esphome/components/audio/audio.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace esphome { +namespace audio { + +struct AudioStreamInfo { + bool operator==(const AudioStreamInfo &rhs) const { + return (channels == rhs.channels) && (bits_per_sample == rhs.bits_per_sample) && (sample_rate == rhs.sample_rate); + } + bool operator!=(const AudioStreamInfo &rhs) const { return !operator==(rhs); } + size_t get_bytes_per_sample() const { return bits_per_sample / 8; } + uint8_t channels = 1; + uint8_t bits_per_sample = 16; + uint32_t sample_rate = 16000; +}; + +} // namespace audio +} // namespace esphome diff --git a/esphome/components/i2s_audio/speaker/__init__.py b/esphome/components/i2s_audio/speaker/__init__.py index bba886b39b..9fdaced64c 100644 --- a/esphome/components/i2s_audio/speaker/__init__.py +++ b/esphome/components/i2s_audio/speaker/__init__.py @@ -16,6 +16,7 @@ from .. import ( register_i2s_audio_component, ) +AUTO_LOAD = ["audio"] CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2s_audio"] @@ -72,7 +73,7 @@ BASE_SCHEMA = ( .extend( { cv.Optional( - CONF_TIMEOUT, default="100ms" + CONF_TIMEOUT, default="500ms" ): cv.positive_time_period_milliseconds, } ) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 97c1d86c36..4fc489d0a3 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -4,6 +4,8 @@ #include +#include "esphome/components/audio/audio.h" + #include "esphome/core/application.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" @@ -11,186 +13,296 @@ namespace esphome { namespace i2s_audio { -static const size_t BUFFER_COUNT = 20; +static const size_t DMA_BUFFER_SIZE = 512; +static const size_t DMA_BUFFERS_COUNT = 4; +static const size_t FRAMES_IN_ALL_DMA_BUFFERS = DMA_BUFFER_SIZE * DMA_BUFFERS_COUNT; +static const size_t RING_BUFFER_SAMPLES = 8192; +static const size_t TASK_DELAY_MS = 10; +static const size_t TASK_STACK_SIZE = 4096; +static const ssize_t TASK_PRIORITY = 23; static const char *const TAG = "i2s_audio.speaker"; +enum SpeakerEventGroupBits : uint32_t { + COMMAND_START = (1 << 0), // Starts the main task purpose + COMMAND_STOP = (1 << 1), // stops the main task + COMMAND_STOP_GRACEFULLY = (1 << 2), // Stops the task once all data has been written + MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE = (1 << 5), // Locks the ring buffer when not set + STATE_STARTING = (1 << 10), + STATE_RUNNING = (1 << 11), + STATE_STOPPING = (1 << 12), + STATE_STOPPED = (1 << 13), + ERR_TASK_FAILED_TO_START = (1 << 15), + ERR_ESP_INVALID_STATE = (1 << 16), + ERR_ESP_INVALID_ARG = (1 << 17), + ERR_ESP_INVALID_SIZE = (1 << 18), + ERR_ESP_NO_MEM = (1 << 19), + ERR_ESP_FAIL = (1 << 20), + ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL, + ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits +}; + +// Translates a SpeakerEventGroupBits ERR_ESP bit to the coressponding esp_err_t +static esp_err_t err_bit_to_esp_err(uint32_t bit) { + switch (bit) { + case SpeakerEventGroupBits::ERR_ESP_INVALID_STATE: + return ESP_ERR_INVALID_STATE; + case SpeakerEventGroupBits::ERR_ESP_INVALID_ARG: + return ESP_ERR_INVALID_ARG; + case SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE: + return ESP_ERR_INVALID_SIZE; + case SpeakerEventGroupBits::ERR_ESP_NO_MEM: + return ESP_ERR_NO_MEM; + default: + return ESP_FAIL; + } +} + +/// @brief Multiplies the input array of Q15 numbers by a Q15 constant factor +/// +/// Based on `dsps_mulc_s16_ansi` from the esp-dsp library: +/// https://github.com/espressif/esp-dsp/blob/master/modules/math/mulc/fixed/dsps_mulc_s16_ansi.c +/// (accessed on 2024-09-30). +/// @param input Array of Q15 numbers +/// @param output Array of Q15 numbers +/// @param len Length of array +/// @param c Q15 constant factor +static void q15_multiplication(const int16_t *input, int16_t *output, size_t len, int16_t c) { + for (int i = 0; i < len; i++) { + int32_t acc = (int32_t) input[i] * (int32_t) c; + output[i] = (int16_t) (acc >> 15); + } +} + +// Lists the Q15 fixed point scaling factor for volume reduction. +// Has 100 values representing silence and a reduction [49, 48.5, ... 0.5, 0] dB. +// dB to PCM scaling factor formula: floating_point_scale_factor = 2^(-db/6.014) +// float to Q15 fixed point formula: q15_scale_factor = floating_point_scale_factor * 2^(15) +static const std::vector Q15_VOLUME_SCALING_FACTORS = { + 0, 116, 122, 130, 137, 146, 154, 163, 173, 183, 194, 206, 218, 231, 244, + 259, 274, 291, 308, 326, 345, 366, 388, 411, 435, 461, 488, 517, 548, 580, + 615, 651, 690, 731, 774, 820, 868, 920, 974, 1032, 1094, 1158, 1227, 1300, 1377, + 1459, 1545, 1637, 1734, 1837, 1946, 2061, 2184, 2313, 2450, 2596, 2750, 2913, 3085, 3269, + 3462, 3668, 3885, 4116, 4360, 4619, 4893, 5183, 5490, 5816, 6161, 6527, 6914, 7324, 7758, + 8218, 8706, 9222, 9770, 10349, 10963, 11613, 12302, 13032, 13805, 14624, 15491, 16410, 17384, 18415, + 19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767}; + void I2SAudioSpeaker::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker..."); - this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent)); - if (this->buffer_queue_ == nullptr) { - ESP_LOGE(TAG, "Failed to create buffer queue"); - this->mark_failed(); - return; + if (this->event_group_ == nullptr) { + this->event_group_ = xEventGroupCreate(); } - this->event_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(TaskEvent)); - if (this->event_queue_ == nullptr) { - ESP_LOGE(TAG, "Failed to create event queue"); + if (this->event_group_ == nullptr) { + ESP_LOGE(TAG, "Failed to create event group"); this->mark_failed(); return; } } +void I2SAudioSpeaker::loop() { + uint32_t event_group_bits = xEventGroupGetBits(this->event_group_); + + if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) { + this->status_set_error("Failed to start speaker task"); + } + + if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) { + uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS; + ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits))); + this->status_set_warning(); + } + + if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) { + ESP_LOGD(TAG, "Starting Speaker"); + this->state_ = speaker::STATE_STARTING; + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STARTING); + } + if (event_group_bits & SpeakerEventGroupBits::STATE_RUNNING) { + ESP_LOGD(TAG, "Started Speaker"); + this->state_ = speaker::STATE_RUNNING; + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING); + this->status_clear_warning(); + this->status_clear_error(); + } + if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPING) { + ESP_LOGD(TAG, "Stopping Speaker"); + this->state_ = speaker::STATE_STOPPING; + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING); + } + if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) { + if (!this->task_created_) { + ESP_LOGD(TAG, "Stopped Speaker"); + this->state_ = speaker::STATE_STOPPED; + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS); + this->speaker_task_handle_ = nullptr; + } + } +} + +void I2SAudioSpeaker::set_volume(float volume) { + this->volume_ = volume; + ssize_t decibel_index = remap(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1); + this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index]; +} + +size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) { + if (this->is_failed()) { + ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup"); + return 0; + } + if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) { + this->start(); + } + + // Wait for the ring buffer to be available + uint32_t event_bits = + xEventGroupWaitBits(this->event_group_, SpeakerEventGroupBits::MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE, pdFALSE, + pdFALSE, pdMS_TO_TICKS(TASK_DELAY_MS)); + + if (event_bits & SpeakerEventGroupBits::MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE) { + // Ring buffer is available to write + + // Lock the ring buffer, write to it, then unlock it + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE); + size_t bytes_written = this->audio_ring_buffer_->write_without_replacement((void *) data, length, ticks_to_wait); + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE); + + return bytes_written; + } + + return 0; +} + +bool I2SAudioSpeaker::has_buffered_data() const { + if (this->audio_ring_buffer_ != nullptr) { + return this->audio_ring_buffer_->available() > 0; + } + return false; +} + +void I2SAudioSpeaker::speaker_task(void *params) { + I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params; + uint32_t event_group_bits = + xEventGroupWaitBits(this_speaker->event_group_, + SpeakerEventGroupBits::COMMAND_START | SpeakerEventGroupBits::COMMAND_STOP | + SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY, // Bit message to read + pdTRUE, // Clear the bits on exit + pdFALSE, // Don't wait for all the bits, + portMAX_DELAY); // Block indefinitely until a bit is set + + if (event_group_bits & (SpeakerEventGroupBits::COMMAND_STOP | SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY)) { + // Received a stop signal before the task was requested to start + this_speaker->delete_task_(0); + } + + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING); + + audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_; + const ssize_t bytes_per_sample = audio_stream_info.get_bytes_per_sample(); + const uint8_t number_of_channels = audio_stream_info.channels; + + const size_t dma_buffers_size = FRAMES_IN_ALL_DMA_BUFFERS * bytes_per_sample * number_of_channels; + + if (this_speaker->send_esp_err_to_event_group_( + this_speaker->allocate_buffers_(dma_buffers_size, RING_BUFFER_SAMPLES * bytes_per_sample))) { + // Failed to allocate buffers + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM); + this_speaker->delete_task_(dma_buffers_size); + } + + if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) { + // Failed to start I2S driver + this_speaker->delete_task_(dma_buffers_size); + } else { + // Ring buffer is allocated, so indicate its can be written to + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE); + } + + if (!this_speaker->send_esp_err_to_event_group_(this_speaker->reconfigure_i2s_stream_info_(audio_stream_info))) { + // Successfully set the I2S stream info, ready to write audio data to the I2S port + + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING); + + bool stop_gracefully = false; + uint32_t last_data_received_time = millis(); + + while ((millis() - last_data_received_time) <= this_speaker->timeout_) { + event_group_bits = xEventGroupGetBits(this_speaker->event_group_); + + if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP) { + break; + } + if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY) { + stop_gracefully = true; + } + + size_t bytes_to_read = dma_buffers_size; + size_t bytes_read = this_speaker->audio_ring_buffer_->read((void *) this_speaker->data_buffer_, bytes_to_read, + pdMS_TO_TICKS(TASK_DELAY_MS)); + + if (bytes_read > 0) { + last_data_received_time = millis(); + size_t bytes_written = 0; + + if ((audio_stream_info.bits_per_sample == 16) && (this_speaker->q15_volume_factor_ < INT16_MAX)) { + // Scale samples by the volume factor in place + q15_multiplication((int16_t *) this_speaker->data_buffer_, (int16_t *) this_speaker->data_buffer_, + bytes_read / sizeof(int16_t), this_speaker->q15_volume_factor_); + } + + if (audio_stream_info.bits_per_sample == (uint8_t) this_speaker->bits_per_sample_) { + i2s_write(this_speaker->parent_->get_port(), this_speaker->data_buffer_, bytes_read, &bytes_written, + portMAX_DELAY); + } else if (audio_stream_info.bits_per_sample < (uint8_t) this_speaker->bits_per_sample_) { + i2s_write_expand(this_speaker->parent_->get_port(), this_speaker->data_buffer_, bytes_read, + audio_stream_info.bits_per_sample, this_speaker->bits_per_sample_, &bytes_written, + portMAX_DELAY); + } + + if (bytes_written != bytes_read) { + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE); + } + + } else { + // No data received + + if (stop_gracefully) { + break; + } + + i2s_zero_dma_buffer(this_speaker->parent_->get_port()); + } + } + } + i2s_zero_dma_buffer(this_speaker->parent_->get_port()); + + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING); + + i2s_stop(this_speaker->parent_->get_port()); + i2s_driver_uninstall(this_speaker->parent_->get_port()); + + this_speaker->parent_->unlock(); + this_speaker->delete_task_(dma_buffers_size); +} + void I2SAudioSpeaker::start() { - if (this->is_failed()) { - ESP_LOGE(TAG, "Cannot start audio, speaker failed to setup"); + if (this->is_failed()) return; - } - if (this->task_created_) { - ESP_LOGW(TAG, "Called start while task has been already created."); + if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING)) return; - } - this->state_ = speaker::STATE_STARTING; -} -void I2SAudioSpeaker::start_() { - if (this->task_created_) { - return; - } - if (!this->parent_->try_lock()) { - return; // Waiting for another i2s component to return lock + + if (this->speaker_task_handle_ == nullptr) { + xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY, + &this->speaker_task_handle_); } - xTaskCreate(I2SAudioSpeaker::player_task, "speaker_task", 8192, (void *) this, 1, &this->player_task_handle_); - this->task_created_ = true; -} - -template const uint8_t *convert_data_format(const a *from, b *to, size_t &bytes, bool repeat) { - if (sizeof(a) == sizeof(b) && !repeat) { - return reinterpret_cast(from); - } - const b *result = to; - for (size_t i = 0; i < bytes; i += sizeof(a)) { - b value = static_cast(*from++) << (sizeof(b) - sizeof(a)) * 8; - *to++ = value; - if (repeat) - *to++ = value; - } - bytes *= (sizeof(b) / sizeof(a)) * (repeat ? 2 : 1); // NOLINT - return reinterpret_cast(result); -} - -void I2SAudioSpeaker::player_task(void *params) { - I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params; - - TaskEvent event; - event.type = TaskEventType::STARTING; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); - - i2s_driver_config_t config = { - .mode = (i2s_mode_t) (this_speaker->i2s_mode_ | I2S_MODE_TX), - .sample_rate = this_speaker->sample_rate_, - .bits_per_sample = this_speaker->bits_per_sample_, - .channel_format = this_speaker->channel_, - .communication_format = this_speaker->i2s_comm_fmt_, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, - .dma_buf_count = 8, - .dma_buf_len = 256, - .use_apll = this_speaker->use_apll_, - .tx_desc_auto_clear = true, - .fixed_mclk = 0, - .mclk_multiple = I2S_MCLK_MULTIPLE_256, - .bits_per_chan = this_speaker->bits_per_channel_, - }; -#if SOC_I2S_SUPPORTS_DAC - if (this_speaker->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { - config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN); - } -#endif - - esp_err_t err = i2s_driver_install(this_speaker->parent_->get_port(), &config, 0, nullptr); - if (err != ESP_OK) { - event.type = TaskEventType::WARNING; - event.err = err; - xQueueSend(this_speaker->event_queue_, &event, 0); - event.type = TaskEventType::STOPPED; - xQueueSend(this_speaker->event_queue_, &event, 0); - while (true) { - delay(10); - } - } - -#if SOC_I2S_SUPPORTS_DAC - if (this_speaker->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) { -#endif - i2s_pin_config_t pin_config = this_speaker->parent_->get_pin_config(); - pin_config.data_out_num = this_speaker->dout_pin_; - - i2s_set_pin(this_speaker->parent_->get_port(), &pin_config); -#if SOC_I2S_SUPPORTS_DAC + if (this->speaker_task_handle_ != nullptr) { + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START); + this->task_created_ = true; } else { - i2s_set_dac_mode(this_speaker->internal_dac_mode_); - } -#endif - - DataEvent data_event; - - event.type = TaskEventType::STARTED; - xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); - - int32_t buffer[BUFFER_SIZE]; - - while (true) { - if (xQueueReceive(this_speaker->buffer_queue_, &data_event, this_speaker->timeout_ / portTICK_PERIOD_MS) != - pdTRUE) { - break; // End of audio from main thread - } - if (data_event.stop) { - // Stop signal from main thread - xQueueReset(this_speaker->buffer_queue_); // Flush queue - break; - } - - const uint8_t *data = data_event.data; - size_t remaining = data_event.len; - switch (this_speaker->bits_per_sample_) { - case I2S_BITS_PER_SAMPLE_8BIT: - case I2S_BITS_PER_SAMPLE_16BIT: { - data = convert_data_format(reinterpret_cast(data), reinterpret_cast(buffer), - remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); - break; - } - case I2S_BITS_PER_SAMPLE_24BIT: - case I2S_BITS_PER_SAMPLE_32BIT: { - data = convert_data_format(reinterpret_cast(data), reinterpret_cast(buffer), - remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); - break; - } - } - - while (remaining != 0) { - size_t bytes_written; - esp_err_t err = - i2s_write(this_speaker->parent_->get_port(), data, remaining, &bytes_written, (32 / portTICK_PERIOD_MS)); - if (err != ESP_OK) { - event = {.type = TaskEventType::WARNING, .err = err}; - if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGW(TAG, "Failed to send WARNING event"); - } - continue; - } - data += bytes_written; - remaining -= bytes_written; - } - } - - event.type = TaskEventType::STOPPING; - if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGW(TAG, "Failed to send STOPPING event"); - } - - i2s_zero_dma_buffer(this_speaker->parent_->get_port()); - - i2s_driver_uninstall(this_speaker->parent_->get_port()); - - event.type = TaskEventType::STOPPED; - if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGW(TAG, "Failed to send STOPPED event"); - } - - while (true) { - delay(10); + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START); } } @@ -203,92 +315,169 @@ void I2SAudioSpeaker::stop_(bool wait_on_empty) { return; if (this->state_ == speaker::STATE_STOPPED) return; - if (this->state_ == speaker::STATE_STARTING) { - this->state_ = speaker::STATE_STOPPED; - return; - } - this->state_ = speaker::STATE_STOPPING; - DataEvent data; - data.stop = true; + if (wait_on_empty) { - xQueueSend(this->buffer_queue_, &data, portMAX_DELAY); + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY); } else { - xQueueSendToFront(this->buffer_queue_, &data, portMAX_DELAY); + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP); } } -void I2SAudioSpeaker::watch_() { - TaskEvent event; - if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) { - switch (event.type) { - case TaskEventType::STARTING: - ESP_LOGD(TAG, "Starting I2S Audio Speaker"); - break; - case TaskEventType::STARTED: - ESP_LOGD(TAG, "Started I2S Audio Speaker"); - this->state_ = speaker::STATE_RUNNING; - this->status_clear_warning(); - break; - case TaskEventType::STOPPING: - ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); - break; - case TaskEventType::STOPPED: - this->state_ = speaker::STATE_STOPPED; - vTaskDelete(this->player_task_handle_); - this->task_created_ = false; - this->player_task_handle_ = nullptr; - this->parent_->unlock(); - xQueueReset(this->buffer_queue_); - ESP_LOGD(TAG, "Stopped I2S Audio Speaker"); - break; - case TaskEventType::WARNING: - ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); - this->status_set_warning(); - break; - } +bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) { + switch (err) { + case ESP_OK: + return false; + case ESP_ERR_INVALID_STATE: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_STATE); + return true; + case ESP_ERR_INVALID_ARG: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_ARG); + return true; + case ESP_ERR_INVALID_SIZE: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE); + return true; + case ESP_ERR_NO_MEM: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM); + return true; + default: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL); + return true; } } -void I2SAudioSpeaker::loop() { - switch (this->state_) { - case speaker::STATE_STARTING: - this->start_(); - [[fallthrough]]; - case speaker::STATE_RUNNING: - case speaker::STATE_STOPPING: - this->watch_(); - break; - case speaker::STATE_STOPPED: - break; +esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size) { + if (this->data_buffer_ == nullptr) { + // Allocate data buffer for temporarily storing audio from the ring buffer before writing to the I2S bus + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + this->data_buffer_ = allocator.allocate(data_buffer_size); } + + if (this->data_buffer_ == nullptr) { + return ESP_ERR_NO_MEM; + } + + if (this->audio_ring_buffer_ == nullptr) { + // Allocate ring buffer + this->audio_ring_buffer_ = RingBuffer::create(ring_buffer_size); + } + + if (this->audio_ring_buffer_ == nullptr) { + return ESP_ERR_NO_MEM; + } + + return ESP_OK; } -size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length) { - if (this->is_failed()) { - ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup"); - return 0; +esp_err_t I2SAudioSpeaker::start_i2s_driver_() { + if (!this->parent_->try_lock()) { + return ESP_ERR_INVALID_STATE; } - if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) { - this->start(); + + i2s_driver_config_t config = { + .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX), + .sample_rate = this->sample_rate_, + .bits_per_sample = this->bits_per_sample_, + .channel_format = this->channel_, + .communication_format = this->i2s_comm_fmt_, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = DMA_BUFFERS_COUNT, + .dma_buf_len = DMA_BUFFER_SIZE, + .use_apll = this->use_apll_, + .tx_desc_auto_clear = true, + .fixed_mclk = I2S_PIN_NO_CHANGE, + .mclk_multiple = I2S_MCLK_MULTIPLE_256, + .bits_per_chan = this->bits_per_channel_, +#if SOC_I2S_SUPPORTS_TDM + .chan_mask = (i2s_channel_t) (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1), + .total_chan = 2, + .left_align = false, + .big_edin = false, + .bit_order_msb = false, + .skip_msk = false, +#endif + }; +#if SOC_I2S_SUPPORTS_DAC + if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { + config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN); } - size_t remaining = length; - size_t index = 0; - while (remaining > 0) { - DataEvent event; - event.stop = false; - size_t to_send_length = std::min(remaining, BUFFER_SIZE); - event.len = to_send_length; - memcpy(event.data, data + index, to_send_length); - if (xQueueSend(this->buffer_queue_, &event, 0) != pdTRUE) { - return index; - } - remaining -= to_send_length; - index += to_send_length; +#endif + + esp_err_t err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); + if (err != ESP_OK) { + // Failed to install the driver, so unlock the I2S port + this->parent_->unlock(); + return err; } - return index; + +#if SOC_I2S_SUPPORTS_DAC + if (this->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) { +#endif + i2s_pin_config_t pin_config = this->parent_->get_pin_config(); + pin_config.data_out_num = this->dout_pin_; + + err = i2s_set_pin(this->parent_->get_port(), &pin_config); +#if SOC_I2S_SUPPORTS_DAC + } else { + i2s_set_dac_mode(this->internal_dac_mode_); + } +#endif + + if (err != ESP_OK) { + // Failed to set the data out pin, so uninstall the driver and unlock the I2S port + i2s_driver_uninstall(this->parent_->get_port()); + this->parent_->unlock(); + } + + return err; } -bool I2SAudioSpeaker::has_buffered_data() const { return uxQueueMessagesWaiting(this->buffer_queue_) > 0; } +esp_err_t I2SAudioSpeaker::reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info) { + if (this->i2s_mode_ & I2S_MODE_MASTER) { + // ESP controls for the the I2S bus, so adjust the sample rate and bits per sample to match the incoming audio + this->sample_rate_ = audio_stream_info.sample_rate; + this->bits_per_sample_ = (i2s_bits_per_sample_t) audio_stream_info.bits_per_sample; + } else if (this->sample_rate_ != audio_stream_info.sample_rate) { + // Can't reconfigure I2S bus, so the sample rate must match the configured value + return ESP_ERR_INVALID_ARG; + } + + if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) { + // Currently can't handle the case when the incoming audio has more bits per sample than the configured value + return ESP_ERR_INVALID_ARG; + } + + if (audio_stream_info.channels == 1) { + return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_MONO); + } else if (audio_stream_info.channels == 2) { + return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_STEREO); + } + + return ESP_ERR_INVALID_ARG; +} + +void I2SAudioSpeaker::delete_task_(size_t buffer_size) { + if (this->audio_ring_buffer_ != nullptr) { + xEventGroupWaitBits(this->event_group_, + MESSAGE_RING_BUFFER_AVAILABLE_TO_WRITE, // Bit message to read + pdFALSE, // Don't clear the bits on exit + pdTRUE, // Don't wait for all the bits, + portMAX_DELAY); // Block indefinitely until a command bit is set + + this->audio_ring_buffer_.reset(); // Deallocates the ring buffer stored in the unique_ptr + this->audio_ring_buffer_ = nullptr; + } + + if (this->data_buffer_ != nullptr) { + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + allocator.deallocate(this->data_buffer_, buffer_size); + this->data_buffer_ = nullptr; + } + + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPED); + + this->task_created_ = false; + vTaskDelete(nullptr); +} } // namespace i2s_audio } // namespace esphome diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 9d1817c86f..245f97d1e7 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -5,38 +5,21 @@ #include "../i2s_audio.h" #include -#include -#include +#include +#include + +#include "esphome/components/audio/audio.h" #include "esphome/components/speaker/speaker.h" + #include "esphome/core/component.h" #include "esphome/core/gpio.h" #include "esphome/core/helpers.h" +#include "esphome/core/ring_buffer.h" namespace esphome { namespace i2s_audio { -static const size_t BUFFER_SIZE = 1024; - -enum class TaskEventType : uint8_t { - STARTING = 0, - STARTED, - STOPPING, - STOPPED, - WARNING = 255, -}; - -struct TaskEvent { - TaskEventType type; - esp_err_t err; -}; - -struct DataEvent { - bool stop; - size_t len; - uint8_t data[BUFFER_SIZE]; -}; - class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Component { public: float get_setup_priority() const override { return esphome::setup_priority::LATE; } @@ -55,25 +38,89 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp void stop() override; void finish() override; - size_t play(const uint8_t *data, size_t length) override; + /// @brief Plays the provided audio data. + /// Starts the speaker task, if necessary. Writes the audio data to the ring buffer. + /// @param data Audio data in the format set by the parent speaker classes ``set_audio_stream_info`` method. + /// @param length The length of the audio data in bytes. + /// @param ticks_to_wait The FreeRTOS ticks to wait before writing as much data as possible to the ring buffer. + /// @return The number of bytes that were actually written to the ring buffer. + size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override; + size_t play(const uint8_t *data, size_t length) override { return play(data, length, 0); } bool has_buffered_data() const override; + /// @brief Sets the volume of the speaker. It is implemented as a software volume control. + /// Overrides the default setter to convert the floating point volume to a Q15 fixed-point factor. + /// @param volume + void set_volume(float volume) override; + float get_volume() override { return this->volume_; } + protected: - void start_(); + /// @brief Function for the FreeRTOS task handling audio output. + /// After receiving the COMMAND_START signal, allocates space for the buffers, starts the I2S driver, and reads + /// audio from the ring buffer and writes audio to the I2S port. Stops immmiately after receiving the COMMAND_STOP + /// signal and stops only after the ring buffer is empty after receiving the COMMAND_STOP_GRACEFULLY signal. Stops if + /// the ring buffer hasn't read data for more than timeout_ milliseconds. When stopping, it deallocates the buffers, + /// stops the I2S driver, unlocks the I2S port, and deletes the task. It communicates the state and any errors via + /// event_group_. + /// @param params I2SAudioSpeaker component + static void speaker_task(void *params); + + /// @brief Sends a stop command to the speaker task via event_group_. + /// @param wait_on_empty If false, sends the COMMAND_STOP signal. If true, sends the COMMAND_STOP_GRACEFULLY signal. void stop_(bool wait_on_empty); - void watch_(); - static void player_task(void *params); + /// @brief Sets the corresponding ERR_ESP event group bits. + /// @param err esp_err_t error code. + /// @return True if an ERR_ESP bit is set and false if err == ESP_OK + bool send_esp_err_to_event_group_(esp_err_t err); - TaskHandle_t player_task_handle_{nullptr}; - QueueHandle_t buffer_queue_; - QueueHandle_t event_queue_; + /// @brief Allocates the data buffer and ring buffer + /// @param data_buffer_size Number of bytes to allocate for the data buffer. + /// @param ring_buffer_size Number of bytes to allocate for the ring buffer. + /// @return ESP_ERR_NO_MEM if either buffer fails to allocate + /// ESP_OK if successful + esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size); + + /// @brief Starts the ESP32 I2S driver. + /// Attempts to lock the I2S port, starts the I2S driver, and sets the data out pin. If it fails, it will unlock + /// the I2S port and uninstall the driver, if necessary. + /// @return ESP_ERR_INVALID_STATE if the I2S port is already locked. + /// ESP_ERR_INVALID_ARG if installing the driver or setting the data out pin fails due to a parameter error. + /// ESP_ERR_NO_MEM if the driver fails to install due to a memory allocation error. + /// ESP_FAIL if setting the data out pin fails due to an IO error + /// ESP_OK if successful + esp_err_t start_i2s_driver_(); + + /// @brief Adjusts the I2S driver configuration to match the incoming audio stream. + /// Modifies I2S driver's sample rate, bits per sample, and number of channel settings. If the I2S is in secondary + /// mode, it only modifies the number of channels. + /// @param audio_stream_info Describes the incoming audio stream + /// @return ESP_ERR_INVALID_ARG if there is a parameter error, if there is more than 2 channels in the stream, or if + /// the audio settings are incompatible with the configuration. + /// ESP_ERR_NO_MEM if the driver fails to reconfigure due to a memory allocation error. + /// ESP_OK if successful. + esp_err_t reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info); + + /// @brief Deletes the speaker's task. + /// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by + /// the speaker_task itself. + /// @param buffer_size The allocated size of the data_buffer_. + void delete_task_(size_t buffer_size); + + TaskHandle_t speaker_task_handle_{nullptr}; + EventGroupHandle_t event_group_{nullptr}; + + uint8_t *data_buffer_; + std::unique_ptr audio_ring_buffer_; + + uint32_t timeout_; + uint8_t dout_pin_; - uint32_t timeout_{0}; - uint8_t dout_pin_{0}; bool task_created_{false}; + int16_t q15_volume_factor_{INT16_MAX}; + #if SOC_I2S_SUPPORTS_DAC i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE}; #endif diff --git a/esphome/components/speaker/__init__.py b/esphome/components/speaker/__init__.py index d28b726d1f..1bbc0b02ef 100644 --- a/esphome/components/speaker/__init__.py +++ b/esphome/components/speaker/__init__.py @@ -2,7 +2,7 @@ from esphome import automation from esphome.automation import maybe_simple_id import esphome.codegen as cg import esphome.config_validation as cv -from esphome.const import CONF_DATA, CONF_ID +from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME from esphome.core import CORE from esphome.coroutine import coroutine_with_priority @@ -23,6 +23,10 @@ StopAction = speaker_ns.class_( FinishAction = speaker_ns.class_( "FinishAction", automation.Action, cg.Parented.template(Speaker) ) +VolumeSetAction = speaker_ns.class_( + "VolumeSetAction", automation.Action, cg.Parented.template(Speaker) +) + IsPlayingCondition = speaker_ns.class_("IsPlayingCondition", automation.Condition) IsStoppedCondition = speaker_ns.class_("IsStoppedCondition", automation.Condition) @@ -90,6 +94,25 @@ automation.register_condition( )(speaker_action) +@automation.register_action( + "speaker.volume_set", + VolumeSetAction, + cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(Speaker), + cv.Required(CONF_VOLUME): cv.templatable(cv.percentage), + }, + key=CONF_VOLUME, + ), +) +async def speaker_volume_set_action(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + volume = await cg.templatable(config[CONF_VOLUME], args, float) + cg.add(var.set_volume(volume)) + return var + + @coroutine_with_priority(100.0) async def to_code(config): cg.add_global(speaker_ns.using) diff --git a/esphome/components/speaker/automation.h b/esphome/components/speaker/automation.h index 2716fe6100..9efda011f2 100644 --- a/esphome/components/speaker/automation.h +++ b/esphome/components/speaker/automation.h @@ -34,6 +34,11 @@ template class PlayAction : public Action, public Parente std::vector data_static_{}; }; +template class VolumeSetAction : public Action, public Parented { + TEMPLATABLE_VALUE(float, volume) + void play(Ts... x) override { this->parent_->set_volume(this->volume_.value(x...)); } +}; + template class StopAction : public Action, public Parented { public: void play(Ts... x) override { this->parent_->stop(); } diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 375ccc4e8c..9390e4edb7 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -4,6 +4,12 @@ #include #include +#ifdef USE_ESP32 +#include +#endif + +#include "esphome/components/audio/audio.h" + namespace esphome { namespace speaker { @@ -16,14 +22,33 @@ enum State : uint8_t { class Speaker { public: +#ifdef USE_ESP32 + /// @brief Plays the provided audio data. + /// If the speaker component doesn't implement this method, it falls back to the play method without this parameter. + /// @param data Audio data in the format specified by ``set_audio_stream_info`` method. + /// @param length The length of the audio data in bytes. + /// @param ticks_to_wait The FreeRTOS ticks to wait before writing as much data as possible to the ring buffer. + /// @return The number of bytes that were actually written to the speaker's internal buffer. + virtual size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) { + return this->play(data, length); + }; +#endif + + /// @brief Plays the provided audio data. + /// If the audio stream is not the default defined in "esphome/core/audio.h" and the speaker component implements it, + /// then this should be called after calling ``set_audio_stream_info``. + /// @param data Audio data in the format specified by ``set_audio_stream_info`` method. + /// @param length The length of the audio data in bytes. + /// @return The number of bytes that were actually written to the speaker's internal buffer. virtual size_t play(const uint8_t *data, size_t length) = 0; + size_t play(const std::vector &data) { return this->play(data.data(), data.size()); } virtual void start() = 0; virtual void stop() = 0; // In compare between *STOP()* and *FINISH()*; *FINISH()* will stop after emptying the play buffer, // while *STOP()* will break directly. - // When finish() is not implemented on the plateform component it should just do a normal stop. + // When finish() is not implemented on the platform component it should just do a normal stop. virtual void finish() { this->stop(); } virtual bool has_buffered_data() const = 0; @@ -31,8 +56,18 @@ class Speaker { bool is_running() const { return this->state_ == STATE_RUNNING; } bool is_stopped() const { return this->state_ == STATE_STOPPED; } + // Volume control must be implemented by each speaker component, otherwise it will have no effect. + virtual void set_volume(float volume) { this->volume_ = volume; }; + virtual float get_volume() { return this->volume_; } + + void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info) { + this->audio_stream_info_ = audio_stream_info; + } + protected: State state_{STATE_STOPPED}; + audio::AudioStreamInfo audio_stream_info_; + float volume_{1.0f}; }; } // namespace speaker diff --git a/tests/components/speaker/test.esp32-ard.yaml b/tests/components/speaker/test.esp32-ard.yaml index ab20f36eb6..9a24d00f68 100644 --- a/tests/components/speaker/test.esp32-ard.yaml +++ b/tests/components/speaker/test.esp32-ard.yaml @@ -5,6 +5,7 @@ esphome: condition: speaker.is_stopped then: - speaker.play: [0, 1, 2, 3] + - speaker.volume_set: 0.9 - if: condition: speaker.is_playing then: diff --git a/tests/components/speaker/test.esp32-c3-ard.yaml b/tests/components/speaker/test.esp32-c3-ard.yaml index c966f9daa7..f28014337c 100644 --- a/tests/components/speaker/test.esp32-c3-ard.yaml +++ b/tests/components/speaker/test.esp32-c3-ard.yaml @@ -5,6 +5,7 @@ esphome: condition: speaker.is_stopped then: - speaker.play: [0, 1, 2, 3] + - speaker.volume_set: 0.9 - if: condition: speaker.is_playing then: diff --git a/tests/components/speaker/test.esp32-c3-idf.yaml b/tests/components/speaker/test.esp32-c3-idf.yaml index c966f9daa7..f28014337c 100644 --- a/tests/components/speaker/test.esp32-c3-idf.yaml +++ b/tests/components/speaker/test.esp32-c3-idf.yaml @@ -5,6 +5,7 @@ esphome: condition: speaker.is_stopped then: - speaker.play: [0, 1, 2, 3] + - speaker.volume_set: 0.9 - if: condition: speaker.is_playing then: diff --git a/tests/components/speaker/test.esp32-idf.yaml b/tests/components/speaker/test.esp32-idf.yaml index ab20f36eb6..9a24d00f68 100644 --- a/tests/components/speaker/test.esp32-idf.yaml +++ b/tests/components/speaker/test.esp32-idf.yaml @@ -5,6 +5,7 @@ esphome: condition: speaker.is_stopped then: - speaker.play: [0, 1, 2, 3] + - speaker.volume_set: 0.9 - if: condition: speaker.is_playing then: From 0451b31f9eafc6fa78551c78e9b03671d1ba63d8 Mon Sep 17 00:00:00 2001 From: functionpointer Date: Thu, 17 Oct 2024 02:17:20 +0200 Subject: [PATCH 2520/2607] Bump arduino-mlx90393 to 1.0.2 (#7618) --- esphome/components/mlx90393/sensor.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/mlx90393/sensor.py b/esphome/components/mlx90393/sensor.py index 92ba30bea3..fe01d8ebfc 100644 --- a/esphome/components/mlx90393/sensor.py +++ b/esphome/components/mlx90393/sensor.py @@ -132,4 +132,4 @@ async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_DRDY_PIN]) cg.add(var.set_drdy_gpio(pin)) - cg.add_library("functionpointer/arduino-MLX90393", "1.0.0") + cg.add_library("functionpointer/arduino-MLX90393", "1.0.2") diff --git a/platformio.ini b/platformio.ini index bb122adc37..04afc059af 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,7 +38,7 @@ lib_deps = improv/Improv@1.2.4 ; improv_serial / esp32_improv bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code - functionpointer/arduino-MLX90393@1.0.0 ; mlx90393 + functionpointer/arduino-MLX90393@1.0.2 ; mlx90393 pavlodn/HaierProtocol@0.9.31 ; haier kikuchan98/pngle@1.0.2 ; online_image ; This is using the repository until a new release is published to PlatformIO From c9e59197396c05bc7cc12740adf151a28997f527 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Thu, 17 Oct 2024 03:31:02 +0300 Subject: [PATCH 2521/2607] [fix] ESP32-C6 BLE compile error (#7580) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32_ble/const_esp32c6.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/components/esp32_ble/const_esp32c6.h b/esphome/components/esp32_ble/const_esp32c6.h index 69f9adcf6b..89179d8dd9 100644 --- a/esphome/components/esp32_ble/const_esp32c6.h +++ b/esphome/components/esp32_ble/const_esp32c6.h @@ -40,6 +40,9 @@ static const esp_bt_controller_config_t BT_CONTROLLER_CONFIG = { .controller_run_cpu = 0, .enable_qa_test = RUN_QA_TEST, .enable_bqb_test = RUN_BQB_TEST, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 1) + // The following fields have been removed since ESP IDF version 5.3.1, see commit: + // https://github.com/espressif/esp-idf/commit/e761c1de8f9c0777829d597b4d5a33bb070a30a8 .enable_uart_hci = HCI_UART_EN, .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, @@ -47,6 +50,7 @@ static const esp_bt_controller_config_t BT_CONTROLLER_CONFIG = { .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, +#endif .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, .sleep_en = NIMBLE_SLEEP_ENABLE, @@ -58,6 +62,9 @@ static const esp_bt_controller_config_t BT_CONTROLLER_CONFIG = { .cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, .ignore_wl_for_direct_adv = 0, .enable_pcl = DEFAULT_BT_LE_POWER_CONTROL_ENABLED, +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 3) + .csa2_select = DEFAULT_BT_LE_50_FEATURE_SUPPORT, +#endif .config_magic = CONFIG_MAGIC, }; From 56fa6fef855437dfe34027388a182c166b6823da Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:32:22 +1100 Subject: [PATCH 2522/2607] [config] Fix crash with empty substitutions block (#7612) --- esphome/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config.py b/esphome/config.py index a2d0d15477..7d48569d2d 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -782,7 +782,7 @@ def validate_config( from esphome.components import substitutions result[CONF_SUBSTITUTIONS] = { - **config.get(CONF_SUBSTITUTIONS, {}), + **(config.get(CONF_SUBSTITUTIONS) or {}), **command_line_substitutions, } result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS) From 5ad68e926da373d2e24c2d8891a5d21926ba014f Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:44:20 +1100 Subject: [PATCH 2523/2607] [axs15231] Touchscreen driver (#7592) --- CODEOWNERS | 1 + esphome/components/axs15231/__init__.py | 6 ++ .../axs15231/touchscreen/__init__.py | 36 +++++++++++ .../touchscreen/axs15231_touchscreen.cpp | 64 +++++++++++++++++++ .../touchscreen/axs15231_touchscreen.h | 27 ++++++++ tests/components/axs15231/common.yaml | 20 ++++++ tests/components/axs15231/test.esp32-ard.yaml | 1 + .../axs15231/test.esp32-c3-ard.yaml | 1 + .../axs15231/test.esp32-c3-idf.yaml | 1 + tests/components/axs15231/test.esp32-idf.yaml | 1 + .../components/axs15231/test.esp8266-ard.yaml | 19 ++++++ .../components/axs15231/test.rp2040-ard.yaml | 1 + 12 files changed, 178 insertions(+) create mode 100644 esphome/components/axs15231/__init__.py create mode 100644 esphome/components/axs15231/touchscreen/__init__.py create mode 100644 esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp create mode 100644 esphome/components/axs15231/touchscreen/axs15231_touchscreen.h create mode 100644 tests/components/axs15231/common.yaml create mode 100644 tests/components/axs15231/test.esp32-ard.yaml create mode 100644 tests/components/axs15231/test.esp32-c3-ard.yaml create mode 100644 tests/components/axs15231/test.esp32-c3-idf.yaml create mode 100644 tests/components/axs15231/test.esp32-idf.yaml create mode 100644 tests/components/axs15231/test.esp8266-ard.yaml create mode 100644 tests/components/axs15231/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 7ac6aa2f76..53300d6740 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -50,6 +50,7 @@ esphome/components/atm90e26/* @danieltwagner esphome/components/atm90e32/* @circuitsetup @descipher esphome/components/audio/* @kahrendt esphome/components/audio_dac/* @kbx81 +esphome/components/axs15231/* @clydebarrow esphome/components/b_parasite/* @rbaron esphome/components/ballu/* @bazuchan esphome/components/bang_bang/* @OttoWinter diff --git a/esphome/components/axs15231/__init__.py b/esphome/components/axs15231/__init__.py new file mode 100644 index 0000000000..3246dbed24 --- /dev/null +++ b/esphome/components/axs15231/__init__.py @@ -0,0 +1,6 @@ +import esphome.codegen as cg + +CODEOWNERS = ["@clydebarrow"] +DEPENDENCIES = ["i2c"] + +axs15231_ns = cg.esphome_ns.namespace("axs15231") diff --git a/esphome/components/axs15231/touchscreen/__init__.py b/esphome/components/axs15231/touchscreen/__init__.py new file mode 100644 index 0000000000..8c18d8ca75 --- /dev/null +++ b/esphome/components/axs15231/touchscreen/__init__.py @@ -0,0 +1,36 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import i2c, touchscreen +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN + +from .. import axs15231_ns + +AXS15231Touchscreen = axs15231_ns.class_( + "AXS15231Touchscreen", + touchscreen.Touchscreen, + i2c.I2CDevice, +) + +CONFIG_SCHEMA = ( + touchscreen.touchscreen_schema("50ms") + .extend( + { + cv.GenerateID(): cv.declare_id(AXS15231Touchscreen), + cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + } + ) + .extend(i2c.i2c_device_schema(0x3B)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await touchscreen.register_touchscreen(var, config) + await i2c.register_i2c_device(var, config) + + if interrupt_pin := config.get(CONF_INTERRUPT_PIN): + cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) + if reset_pin := config.get(CONF_RESET_PIN): + cg.add(var.set_reset_pin(await cg.gpio_pin_expression(reset_pin))) diff --git a/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp new file mode 100644 index 0000000000..54b39a6bb9 --- /dev/null +++ b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp @@ -0,0 +1,64 @@ +#include "axs15231_touchscreen.h" + +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace axs15231 { + +static const char *const TAG = "ax15231.touchscreen"; + +constexpr static const uint8_t AXS_READ_TOUCHPAD[11] = {0xb5, 0xab, 0xa5, 0x5a, 0x0, 0x0, 0x0, 0x8}; + +#define ERROR_CHECK(err) \ + if ((err) != i2c::ERROR_OK) { \ + this->status_set_warning("Failed to communicate"); \ + return; \ + } + +void AXS15231Touchscreen::setup() { + ESP_LOGCONFIG(TAG, "Setting up AXS15231 Touchscreen..."); + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + delay(10); + } + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT); + this->interrupt_pin_->setup(); + this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); + } + this->x_raw_max_ = this->display_->get_native_width(); + this->y_raw_max_ = this->display_->get_native_height(); + ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen setup complete"); +} + +void AXS15231Touchscreen::update_touches() { + i2c::ErrorCode err; + uint8_t data[8]{}; + + err = this->write(AXS_READ_TOUCHPAD, sizeof(AXS_READ_TOUCHPAD), false); + ERROR_CHECK(err); + err = this->read(data, sizeof(data)); + ERROR_CHECK(err); + this->status_clear_warning(); + if (data[0] != 0) // no touches + return; + uint16_t x = encode_uint16(data[2] & 0xF, data[3]); + uint16_t y = encode_uint16(data[4] & 0xF, data[5]); + this->add_raw_touch_position_(0, x, y); +} + +void AXS15231Touchscreen::dump_config() { + ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen:"); + LOG_I2C_DEVICE(this); + LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + ESP_LOGCONFIG(TAG, " Width: %d", this->x_raw_max_); + ESP_LOGCONFIG(TAG, " Height: %d", this->y_raw_max_); +} + +} // namespace axs15231 +} // namespace esphome diff --git a/esphome/components/axs15231/touchscreen/axs15231_touchscreen.h b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.h new file mode 100644 index 0000000000..a55c5c0d32 --- /dev/null +++ b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.h @@ -0,0 +1,27 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/touchscreen/touchscreen.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace axs15231 { + +class AXS15231Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } + + protected: + void update_touches() override; + + InternalGPIOPin *interrupt_pin_{}; + GPIOPin *reset_pin_{}; +}; + +} // namespace axs15231 +} // namespace esphome diff --git a/tests/components/axs15231/common.yaml b/tests/components/axs15231/common.yaml new file mode 100644 index 0000000000..1c0c79975f --- /dev/null +++ b/tests/components/axs15231/common.yaml @@ -0,0 +1,20 @@ +i2c: + - id: i2c_axs15231 + scl: 3 + sda: 21 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 19 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: axs15231 + display: ssd1306_display + interrupt_pin: 20 + reset_pin: 18 diff --git a/tests/components/axs15231/test.esp32-ard.yaml b/tests/components/axs15231/test.esp32-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/axs15231/test.esp32-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/axs15231/test.esp32-c3-ard.yaml b/tests/components/axs15231/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/axs15231/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/axs15231/test.esp32-c3-idf.yaml b/tests/components/axs15231/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/axs15231/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/axs15231/test.esp32-idf.yaml b/tests/components/axs15231/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/axs15231/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/axs15231/test.esp8266-ard.yaml b/tests/components/axs15231/test.esp8266-ard.yaml new file mode 100644 index 0000000000..c09d139574 --- /dev/null +++ b/tests/components/axs15231/test.esp8266-ard.yaml @@ -0,0 +1,19 @@ +i2c: + - id: i2c_axs15231 + scl: 5 + sda: 4 + +display: + - platform: ssd1306_i2c + id: ssd1306_display + model: SSD1306_128X64 + reset_pin: 13 + pages: + - id: page1 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); + +touchscreen: + - platform: axs15231 + display: ssd1306_display + interrupt_pin: 12 diff --git a/tests/components/axs15231/test.rp2040-ard.yaml b/tests/components/axs15231/test.rp2040-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/axs15231/test.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From fcfc76b01bed8cfe7d0dad846b74dca8da201e74 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:03:48 +1100 Subject: [PATCH 2524/2607] [lvgl] Roller and Dropdown enhancements; (#7608) --- esphome/components/lvgl/__init__.py | 3 +- esphome/components/lvgl/defines.py | 1 + esphome/components/lvgl/lvgl_esphome.cpp | 35 ++++++++++++ esphome/components/lvgl/lvgl_esphome.h | 50 ++++++++++++++-- esphome/components/lvgl/schemas.py | 2 +- esphome/components/lvgl/select/__init__.py | 30 ++-------- esphome/components/lvgl/select/lvgl_select.h | 60 +++++++++----------- esphome/components/lvgl/trigger.py | 4 +- esphome/components/lvgl/types.py | 10 +++- esphome/components/lvgl/widgets/__init__.py | 18 ++++-- esphome/components/lvgl/widgets/dropdown.py | 32 +++++++---- esphome/components/lvgl/widgets/obj.py | 6 +- esphome/components/lvgl/widgets/roller.py | 35 +++++++----- esphome/components/lvgl/widgets/tileview.py | 3 +- esphome/core/defines.h | 2 + tests/components/lvgl/lvgl-package.yaml | 34 ++++++++--- 16 files changed, 218 insertions(+), 107 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index dea3b11a94..86fdc7d763 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -271,7 +271,8 @@ async def to_code(config): await disp_update(f"{lv_component}->get_disp()", config) # At this point only the setup code should be generated assert LvContext.added_lambda_count == 1 - Widget.set_completed() + # Set this directly since we are limited in how many methods can be added to the Widget class. + Widget.widgets_completed = True async with LvContext(lv_component): await generate_triggers(lv_component) await generate_page_triggers(lv_component, config) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 7c42ed2f22..c8ece02677 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -477,6 +477,7 @@ CONF_ROWS = "rows" CONF_SCALE_LINES = "scale_lines" CONF_SCROLLBAR_MODE = "scrollbar_mode" CONF_SELECTED_INDEX = "selected_index" +CONF_SELECTED_TEXT = "selected_text" CONF_SHOW_SNOW = "show_snow" CONF_SPIN_TIME = "spin_time" CONF_SRC = "src" diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index ddf41ae377..5a6c66c677 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -5,6 +5,8 @@ #include "lvgl_hal.h" #include "lvgl_esphome.h" +#include + namespace esphome { namespace lvgl { static const char *const TAG = "lvgl"; @@ -263,6 +265,39 @@ LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_ } #endif // USE_LVGL_KEY_LISTENER +#if defined(USE_LVGL_DROPDOWN) || defined(LV_USE_ROLLER) +std::string LvSelectable::get_selected_text() { + auto selected = this->get_selected_index(); + if (selected >= this->options_.size()) + return ""; + return this->options_[selected]; +} + +static std::string join_string(std::vector options) { + return std::accumulate( + options.begin(), options.end(), std::string(), + [](const std::string &a, const std::string &b) -> std::string { return a + (a.length() > 0 ? "\n" : "") + b; }); +} + +void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t anim) { + auto index = std::find(this->options_.begin(), this->options_.end(), text); + if (index != this->options_.end()) { + this->set_selected_index(index - this->options_.begin(), anim); + lv_event_send(this->obj, lv_api_event, nullptr); + } +} + +void LvSelectable::set_options(std::vector options) { + auto index = this->get_selected_index(); + if (index >= options.size()) + index = options.size() - 1; + this->options_ = std::move(options); + this->set_option_string(join_string(this->options_).c_str()); + lv_event_send(this->obj, LV_EVENT_REFRESH, nullptr); + this->set_selected_index(index, LV_ANIM_OFF); +} +#endif // USE_LVGL_DROPDOWN || LV_USE_ROLLER + #ifdef USE_LVGL_BUTTONMATRIX void LvButtonMatrixType::set_obj(lv_obj_t *lv_obj) { LvCompound::set_obj(lv_obj); diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index b28a9bcbe1..2d326f4ae2 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -18,11 +18,9 @@ #include "esphome/core/component.h" #include "esphome/core/log.h" #include -#include #include -#ifdef USE_LVGL_IMAGE -#include "esphome/components/image/image.h" -#endif // USE_LVGL_IMAGE +#include +#include #ifdef USE_LVGL_FONT #include "esphome/components/font/font.h" @@ -246,6 +244,7 @@ class LVEncoderListener : public Parented { public: LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt); +#ifdef USE_BINARY_SENSOR void set_left_button(binary_sensor::BinarySensor *left_button) { left_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_LEFT, state); }); } @@ -256,6 +255,7 @@ class LVEncoderListener : public Parented { void set_enter_button(binary_sensor::BinarySensor *enter_button) { enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); }); } +#endif #ifdef USE_LVGL_ROTARY_ENCODER void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor) { @@ -292,6 +292,48 @@ class LVEncoderListener : public Parented { }; #endif // USE_LVGL_KEY_LISTENER +#if defined(USE_LVGL_DROPDOWN) || defined(LV_USE_ROLLER) +class LvSelectable : public LvCompound { + public: + virtual size_t get_selected_index() = 0; + virtual void set_selected_index(size_t index, lv_anim_enable_t anim) = 0; + void set_selected_text(const std::string &text, lv_anim_enable_t anim); + std::string get_selected_text(); + std::vector get_options() { return this->options_; } + void set_options(std::vector options); + + protected: + virtual void set_option_string(const char *options) = 0; + std::vector options_{}; +}; + +#ifdef USE_LVGL_DROPDOWN +class LvDropdownType : public LvSelectable { + public: + size_t get_selected_index() override { return lv_dropdown_get_selected(this->obj); } + void set_selected_index(size_t index, lv_anim_enable_t anim) override { lv_dropdown_set_selected(this->obj, index); } + + protected: + void set_option_string(const char *options) override { lv_dropdown_set_options(this->obj, options); } +}; +#endif // USE_LVGL_DROPDOWN + +#ifdef USE_LVGL_ROLLER +class LvRollerType : public LvSelectable { + public: + size_t get_selected_index() override { return lv_roller_get_selected(this->obj); } + void set_selected_index(size_t index, lv_anim_enable_t anim) override { + lv_roller_set_selected(this->obj, index, anim); + } + void set_mode(lv_roller_mode_t mode) { this->mode_ = mode; } + + protected: + void set_option_string(const char *options) override { lv_roller_set_options(this->obj, options, this->mode_); } + lv_roller_mode_t mode_{LV_ROLLER_MODE_NORMAL}; +}; +#endif +#endif // defined(USE_LVGL_DROPDOWN) || defined(LV_USE_ROLLER) + #ifdef USE_LVGL_BUTTONMATRIX class LvButtonMatrixType : public key_provider::KeyProvider, public LvCompound { public: diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 780057623a..7599d64416 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -216,7 +216,7 @@ def automation_schema(typ: LvType): events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,) else: events = df.LV_EVENT_TRIGGERS - args = [typ.get_arg_type()] if isinstance(typ, LvType) else [] + args = typ.get_arg_type() if isinstance(typ, LvType) else [] args.append(lv_event_t_ptr) return { cv.Optional(event): validate_automation( diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index 73ac50aa55..5e50b6b385 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -3,18 +3,10 @@ from esphome.components import select import esphome.config_validation as cv from esphome.const import CONF_OPTIONS -from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET -from ..lvcode import ( - API_EVENT, - EVENT_ARG, - UPDATE_EVENT, - LambdaContext, - LvContext, - lv, - lv_add, -) +from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET, literal +from ..lvcode import LvContext from ..schemas import LVGL_SCHEMA -from ..types import LV_EVENT, LvSelect, lvgl_ns +from ..types import LvSelect, lvgl_ns from ..widgets import get_widgets, wait_for_widgets LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select) @@ -38,20 +30,10 @@ async def to_code(config): selector = await select.new_select(config, options=options) paren = await cg.get_variable(config[CONF_LVGL_ID]) await wait_for_widgets() - async with LambdaContext(EVENT_ARG) as pub_ctx: - pub_ctx.add(selector.publish_index(widget.get_value())) - async with LambdaContext([(cg.uint16, "v")]) as control: - await widget.set_property("selected", "v", animated=config[CONF_ANIMATED]) - lv.event_send(widget.obj, API_EVENT, cg.nullptr) - control.add(selector.publish_index(widget.get_value())) async with LvContext(paren) as ctx: - lv_add(selector.set_control_lambda(await control.get_lambda())) ctx.add( - paren.add_event_cb( - widget.obj, - await pub_ctx.get_lambda(), - LV_EVENT.VALUE_CHANGED, - UPDATE_EVENT, + selector.set_widget( + widget.var, + literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF"), ) ) - lv_add(selector.publish_index(widget.get_value())) diff --git a/esphome/components/lvgl/select/lvgl_select.h b/esphome/components/lvgl/select/lvgl_select.h index 97cc8697eb..4538e339c3 100644 --- a/esphome/components/lvgl/select/lvgl_select.h +++ b/esphome/components/lvgl/select/lvgl_select.h @@ -6,58 +6,52 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/preferences.h" +#include "../lvgl.h" namespace esphome { namespace lvgl { -static std::vector split_string(const std::string &str) { - std::vector strings; - auto delimiter = std::string("\n"); - - std::string::size_type pos; - std::string::size_type prev = 0; - while ((pos = str.find(delimiter, prev)) != std::string::npos) { - strings.push_back(str.substr(prev, pos - prev)); - prev = pos + delimiter.size(); - } - - // To get the last substring (or only, if delimiter is not found) - strings.push_back(str.substr(prev)); - - return strings; -} - class LVGLSelect : public select::Select { public: - void set_control_lambda(std::function lambda) { - this->control_lambda_ = std::move(lambda); + void set_widget(LvSelectable *widget, lv_anim_enable_t anim = LV_ANIM_OFF) { + this->widget_ = widget; + this->anim_ = anim; + this->set_options_(); + lv_obj_add_event_cb( + this->widget_->obj, + [](lv_event_t *e) { + auto *it = static_cast(e->user_data); + it->set_options_(); + }, + LV_EVENT_REFRESH, this); if (this->initial_state_.has_value()) { this->control(this->initial_state_.value()); this->initial_state_.reset(); } + this->publish(); + auto lamb = [](lv_event_t *e) { + auto *self = static_cast(e->user_data); + self->publish(); + }; + lv_obj_add_event_cb(this->widget_->obj, lamb, LV_EVENT_VALUE_CHANGED, this); + lv_obj_add_event_cb(this->widget_->obj, lamb, lv_update_event, this); } - void publish_index(size_t index) { - auto value = this->at(index); - if (value) - this->publish_state(value.value()); - } - - void set_options(const char *str) { this->traits.set_options(split_string(str)); } + void publish() { this->publish_state(this->widget_->get_selected_text()); } protected: void control(const std::string &value) override { - if (this->control_lambda_ != nullptr) { - auto index = index_of(value); - if (index) - this->control_lambda_(index.value()); + if (this->widget_ != nullptr) { + this->widget_->set_selected_text(value, this->anim_); } else { - this->initial_state_ = value.c_str(); + this->initial_state_ = value; } } + void set_options_() { this->traits.set_options(this->widget_->get_options()); } - std::function control_lambda_{}; - optional initial_state_{}; + LvSelectable *widget_{}; + optional initial_state_{}; + lv_anim_enable_t anim_{LV_ANIM_OFF}; }; } // namespace lvgl diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index 5288745fab..eb6e483203 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -67,9 +67,9 @@ async def add_trigger(conf, lv_component, w, *events): tid = conf[CONF_TRIGGER_ID] trigger = cg.new_Pvariable(tid) args = w.get_args() + [(lv_event_t_ptr, "event")] - value = w.get_value() + value = w.get_values() await automation.build_automation(trigger, args, conf) async with LambdaContext(EVENT_ARG, where=tid) as context: with LvConditional(w.is_selected()): - lv_add(trigger.trigger(value, literal("event"))) + lv_add(trigger.trigger(*value, literal("event"))) lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events)) diff --git a/esphome/components/lvgl/types.py b/esphome/components/lvgl/types.py index 2d10b67c2d..b504f24674 100644 --- a/esphome/components/lvgl/types.py +++ b/esphome/components/lvgl/types.py @@ -18,7 +18,9 @@ class LvType(cg.MockObjClass): self.value_property = None def get_arg_type(self): - return self.args[0][0] if len(self.args) else None + if len(self.args) == 0: + return None + return [arg[0] for arg in self.args] class LvNumber(LvType): @@ -92,11 +94,13 @@ class LvBoolean(LvType): class LvSelect(LvType): def __init__(self, *args, **kwargs): + parens = kwargs.pop("parents", ()) + (LvCompound,) super().__init__( *args, - largs=[(cg.int_, "x")], - lvalue=lambda w: w.get_property("selected"), + largs=[(cg.int_, "x"), (cg.std_string, "text")], + lvalue=lambda w: [w.var.get_selected_index(), w.var.get_selected_text()], has_on_value=True, + parents=parens, **kwargs, ) diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 533ffdea55..35ee6c54e8 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -70,14 +70,11 @@ class LvScrActType(WidgetType): class Widget: """ Represents a Widget. + This class has a lot of methods. Adding any more runs foul of lint checks ("too many public methods"). """ widgets_completed = False - @staticmethod - def set_completed(): - Widget.widgets_completed = True - def __init__(self, var, wtype: WidgetType, config: dict = None): self.var = var self.type = wtype @@ -179,9 +176,20 @@ class Widget: def get_value(self): if isinstance(self.type.w_type, LvType): - return self.type.w_type.value(self) + result = self.type.w_type.value(self) + if isinstance(result, list): + return result[0] + return result return self.obj + def get_values(self): + if isinstance(self.type.w_type, LvType): + result = self.type.w_type.value(self) + if isinstance(result, list): + return result + return [result] + return [self.obj] + def get_number_value(self): value = self.type.mock_obj.get_value(self.obj) if self.scale == 1.0: diff --git a/esphome/components/lvgl/widgets/dropdown.py b/esphome/components/lvgl/widgets/dropdown.py index 4fd7d8a7ee..a6bfc6bb88 100644 --- a/esphome/components/lvgl/widgets/dropdown.py +++ b/esphome/components/lvgl/widgets/dropdown.py @@ -1,4 +1,3 @@ -import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_OPTIONS @@ -9,21 +8,24 @@ from ..defines import ( CONF_SCROLLBAR, CONF_SELECTED, CONF_SELECTED_INDEX, + CONF_SELECTED_TEXT, CONF_SYMBOL, DIRECTIONS, literal, ) +from ..helpers import lvgl_components_required from ..lv_validation import lv_int, lv_text, option_string -from ..lvcode import LocalVariable, lv, lv_expr +from ..lvcode import LocalVariable, lv, lv_add, lv_expr from ..schemas import part_schema -from ..types import LvSelect, LvType, lv_obj_t +from ..types import LvCompound, LvSelect, LvType, lv_obj_t from . import Widget, WidgetType, set_obj_properties from .label import CONF_LABEL CONF_DROPDOWN = "dropdown" CONF_DROPDOWN_LIST = "dropdown_list" -lv_dropdown_t = LvSelect("lv_dropdown_t") +lv_dropdown_t = LvSelect("LvDropdownType", parents=(LvCompound,)) + lv_dropdown_list_t = LvType("lv_dropdown_list_t") dropdown_list_spec = WidgetType( CONF_DROPDOWN_LIST, lv_dropdown_list_t, (CONF_MAIN, CONF_SELECTED, CONF_SCROLLBAR) @@ -32,7 +34,8 @@ dropdown_list_spec = WidgetType( DROPDOWN_BASE_SCHEMA = cv.Schema( { cv.Optional(CONF_SYMBOL): lv_text, - cv.Optional(CONF_SELECTED_INDEX): cv.templatable(cv.int_), + cv.Exclusive(CONF_SELECTED_INDEX, CONF_SELECTED_TEXT): lv_int, + cv.Exclusive(CONF_SELECTED_TEXT, CONF_SELECTED_TEXT): lv_text, cv.Optional(CONF_DIR, default="BOTTOM"): DIRECTIONS.one_of, cv.Optional(CONF_DROPDOWN_LIST): part_schema(dropdown_list_spec), } @@ -44,6 +47,12 @@ DROPDOWN_SCHEMA = DROPDOWN_BASE_SCHEMA.extend( } ) +DROPDOWN_UPDATE_SCHEMA = DROPDOWN_BASE_SCHEMA.extend( + { + cv.Optional(CONF_OPTIONS): cv.ensure_list(option_string), + } +) + class DropdownType(WidgetType): def __init__(self): @@ -52,18 +61,21 @@ class DropdownType(WidgetType): lv_dropdown_t, (CONF_MAIN, CONF_INDICATOR), DROPDOWN_SCHEMA, - DROPDOWN_BASE_SCHEMA, + modify_schema=DROPDOWN_UPDATE_SCHEMA, ) async def to_code(self, w: Widget, config): + lvgl_components_required.add(CONF_DROPDOWN) if options := config.get(CONF_OPTIONS): - text = cg.safe_exp("\n".join(options)) - lv.dropdown_set_options(w.obj, text) + lv_add(w.var.set_options(options)) if symbol := config.get(CONF_SYMBOL): - lv.dropdown_set_symbol(w.obj, await lv_text.process(symbol)) + lv.dropdown_set_symbol(w.var.obj, await lv_text.process(symbol)) if (selected := config.get(CONF_SELECTED_INDEX)) is not None: value = await lv_int.process(selected) - lv.dropdown_set_selected(w.obj, value) + lv_add(w.var.set_selected_index(value, literal("LV_ANIM_OFF"))) + if (selected := config.get(CONF_SELECTED_TEXT)) is not None: + value = await lv_text.process(selected) + lv_add(w.var.set_selected_text(value, literal("LV_ANIM_OFF"))) if dirn := config.get(CONF_DIR): lv.dropdown_set_dir(w.obj, literal(dirn)) if dlist := config.get(CONF_DROPDOWN_LIST): diff --git a/esphome/components/lvgl/widgets/obj.py b/esphome/components/lvgl/widgets/obj.py index 20a24c86f6..afb4c97f33 100644 --- a/esphome/components/lvgl/widgets/obj.py +++ b/esphome/components/lvgl/widgets/obj.py @@ -1,7 +1,7 @@ from esphome import automation from ..automation import update_to_code -from ..defines import CONF_MAIN, CONF_OBJ +from ..defines import CONF_MAIN, CONF_OBJ, CONF_SCROLLBAR from ..schemas import create_modify_schema from ..types import ObjUpdateAction, WidgetType, lv_obj_t @@ -12,7 +12,9 @@ class ObjType(WidgetType): """ def __init__(self): - super().__init__(CONF_OBJ, lv_obj_t, (CONF_MAIN,), schema={}, modify_schema={}) + super().__init__( + CONF_OBJ, lv_obj_t, (CONF_MAIN, CONF_SCROLLBAR), schema={}, modify_schema={} + ) async def to_code(self, w, config): return [] diff --git a/esphome/components/lvgl/widgets/roller.py b/esphome/components/lvgl/widgets/roller.py index 50fdf6113c..6f9fee47d4 100644 --- a/esphome/components/lvgl/widgets/roller.py +++ b/esphome/components/lvgl/widgets/roller.py @@ -1,4 +1,3 @@ -import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_MODE, CONF_OPTIONS @@ -7,36 +6,40 @@ from ..defines import ( CONF_MAIN, CONF_SELECTED, CONF_SELECTED_INDEX, + CONF_SELECTED_TEXT, CONF_VISIBLE_ROW_COUNT, ROLLER_MODES, literal, ) -from ..lv_validation import animated, lv_int, option_string -from ..lvcode import lv +from ..helpers import lvgl_components_required +from ..lv_validation import animated, lv_int, lv_text, option_string +from ..lvcode import lv_add from ..types import LvSelect from . import WidgetType from .label import CONF_LABEL CONF_ROLLER = "roller" -lv_roller_t = LvSelect("lv_roller_t") +lv_roller_t = LvSelect("LvRollerType") ROLLER_BASE_SCHEMA = cv.Schema( { - cv.Optional(CONF_SELECTED_INDEX): cv.templatable(cv.int_), + cv.Exclusive(CONF_SELECTED_INDEX, CONF_SELECTED_TEXT): lv_int, + cv.Exclusive(CONF_SELECTED_TEXT, CONF_SELECTED_TEXT): lv_text, cv.Optional(CONF_VISIBLE_ROW_COUNT): lv_int, + cv.Optional(CONF_MODE): ROLLER_MODES.one_of, } ) ROLLER_SCHEMA = ROLLER_BASE_SCHEMA.extend( { cv.Required(CONF_OPTIONS): cv.ensure_list(option_string), - cv.Optional(CONF_MODE, default="NORMAL"): ROLLER_MODES.one_of, } ) ROLLER_MODIFY_SCHEMA = ROLLER_BASE_SCHEMA.extend( { cv.Optional(CONF_ANIMATED, default=True): animated, + cv.Optional(CONF_OPTIONS): cv.ensure_list(option_string), } ) @@ -52,15 +55,19 @@ class RollerType(WidgetType): ) async def to_code(self, w, config): + lvgl_components_required.add(CONF_ROLLER) + if mode := config.get(CONF_MODE): + mode = await ROLLER_MODES.process(mode) + lv_add(w.var.set_mode(mode)) if options := config.get(CONF_OPTIONS): - mode = await ROLLER_MODES.process(config[CONF_MODE]) - text = cg.safe_exp("\n".join(options)) - lv.roller_set_options(w.obj, text, mode) - animopt = literal(config.get(CONF_ANIMATED) or "LV_ANIM_OFF") - if CONF_SELECTED_INDEX in config: - if selected := config[CONF_SELECTED_INDEX]: - value = await lv_int.process(selected) - lv.roller_set_selected(w.obj, value, animopt) + lv_add(w.var.set_options(options)) + animopt = literal(config.get(CONF_ANIMATED, "LV_ANIM_OFF")) + if (selected := config.get(CONF_SELECTED_INDEX)) is not None: + value = await lv_int.process(selected) + lv_add(w.var.set_selected_index(value, animopt)) + if (selected := config.get(CONF_SELECTED_TEXT)) is not None: + value = await lv_text.process(selected) + lv_add(w.var.set_selected_text(value, animopt)) await w.set_property( CONF_VISIBLE_ROW_COUNT, await lv_int.process(config.get(CONF_VISIBLE_ROW_COUNT)), diff --git a/esphome/components/lvgl/widgets/tileview.py b/esphome/components/lvgl/widgets/tileview.py index 05259fbd3c..3865d404e2 100644 --- a/esphome/components/lvgl/widgets/tileview.py +++ b/esphome/components/lvgl/widgets/tileview.py @@ -9,6 +9,7 @@ from ..defines import ( CONF_COLUMN, CONF_DIR, CONF_MAIN, + CONF_SCROLLBAR, CONF_TILE_ID, CONF_TILES, TILE_DIRECTIONS, @@ -56,7 +57,7 @@ class TileviewType(WidgetType): super().__init__( CONF_TILEVIEW, lv_tileview_t, - (CONF_MAIN,), + (CONF_MAIN, CONF_SCROLLBAR), schema=TILEVIEW_SCHEMA, modify_schema={}, ) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index ca3db0ad56..b5511b57eb 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -44,10 +44,12 @@ #define USE_LVGL_ANIMIMG #define USE_LVGL_BINARY_SENSOR #define USE_LVGL_BUTTONMATRIX +#define USE_LVGL_DROPDOWN #define USE_LVGL_FONT #define USE_LVGL_IMAGE #define USE_LVGL_KEY_LISTENER #define USE_LVGL_KEYBOARD +#define USE_LVGL_ROLLER #define USE_LVGL_ROTARY_ENCODER #define USE_LVGL_TOUCHSCREEN #define USE_MD5 diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 6aea606ac4..1f09bc22eb 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -138,6 +138,19 @@ lvgl: flex_align_cross: start flex_align_track: end widgets: + - roller: + id: lv_roller + visible_row_count: 2 + anim_time: 500ms + options: + - Nov + - Dec + selected_index: 1 + on_value: + then: + - logger.log: + format: "Roller changed = %d: %s" + args: [x, text.c_str()] - animimg: height: 60 id: anim_img @@ -245,9 +258,13 @@ lvgl: y: 120 - buttonmatrix: on_press: - logger.log: - format: "matrix button pressed: %d" - args: ["x"] + then: + - logger.log: + format: "matrix button pressed: %d" + args: ["x"] + - lvgl.widget.show: b_matrix + - lvgl.widget.redraw: + on_long_press: lvgl.matrix.button.update: id: [button_a, button_e, button_c] @@ -629,8 +646,6 @@ lvgl: - First - Second - Third - - 4th - - 5th - 6th - 7th - 8th @@ -651,8 +666,8 @@ lvgl: bg_color: 0xFF on_value: logger.log: - format: "Dropdown changed = %d" - args: [x] + format: "Dropdown changed = %d: %s" + args: [x, text.c_str()] on_cancel: logger.log: format: "Dropdown closed = %d" @@ -661,6 +676,11 @@ lvgl: src: cat_image on_click: then: + - lvgl.dropdown.update: + id: lv_dropdown + options: + ["First", "Second", "Third", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th"] + selected_index: 3 - logger.log: Cat image clicked - lvgl.tabview.select: id: tabview_id From f490585f66a653787f015384c27e2c7e50de214d Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 17 Oct 2024 03:38:02 +0200 Subject: [PATCH 2525/2607] [code-quality] udp component (#7602) Co-authored-by: Tomasz Duda Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/udp/udp_component.cpp | 9 ++++++--- esphome/components/udp/udp_component.h | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/esphome/components/udp/udp_component.cpp b/esphome/components/udp/udp_component.cpp index 799ed813d3..a1c8889997 100644 --- a/esphome/components/udp/udp_component.cpp +++ b/esphome/components/udp/udp_component.cpp @@ -261,7 +261,8 @@ void UDPComponent::setup() { return; } } -#else +#endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP // 8266 and RP2040 `Duino for (const auto &address : this->addresses_) { auto ipaddr = IPAddress(); @@ -370,7 +371,8 @@ void UDPComponent::loop() { for (;;) { #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) auto len = this->listen_socket_->read(buf, sizeof(buf)); -#else +#endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP auto len = this->udp_client_.parsePacket(); if (len > 0) len = this->udp_client_.read(buf, sizeof(buf)); @@ -587,7 +589,8 @@ void UDPComponent::send_packet_(void *data, size_t len) { if (result < 0) ESP_LOGW(TAG, "sendto() error %d", errno); } -#else +#endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP auto iface = IPAddress(0, 0, 0, 0); for (const auto &saddr : this->ipaddrs_) { if (this->udp_client_.beginPacketMulticast(saddr, this->port_, iface, 128) != 0) { diff --git a/esphome/components/udp/udp_component.h b/esphome/components/udp/udp_component.h index 69bf335a90..b4e11cf652 100644 --- a/esphome/components/udp/udp_component.h +++ b/esphome/components/udp/udp_component.h @@ -9,7 +9,8 @@ #endif #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) #include "esphome/components/socket/socket.h" -#else +#endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP #include #endif #include @@ -125,7 +126,8 @@ class UDPComponent : public PollingComponent { std::unique_ptr broadcast_socket_ = nullptr; std::unique_ptr listen_socket_ = nullptr; std::vector sockaddrs_{}; -#else +#endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP std::vector ipaddrs_{}; WiFiUDP udp_client_{}; #endif From 8bbe4efded8803f0686eb4c71bf9b980a1a67456 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:20:19 +1100 Subject: [PATCH 2526/2607] [lvgl] Revise code generation to allow early widget creation (#7611) --- esphome/components/lvgl/__init__.py | 58 +++++++------ esphome/components/lvgl/automation.py | 32 ++++--- esphome/components/lvgl/defines.py | 16 ++-- esphome/components/lvgl/lvcode.py | 8 +- esphome/components/lvgl/lvgl_esphome.cpp | 96 ++++++++++++--------- esphome/components/lvgl/lvgl_esphome.h | 20 ++--- esphome/components/lvgl/styles.py | 7 +- esphome/components/lvgl/widgets/__init__.py | 35 ++++---- esphome/components/lvgl/widgets/msgbox.py | 11 +-- tests/components/lvgl/lvgl-package.yaml | 4 +- 10 files changed, 155 insertions(+), 132 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 86fdc7d763..beaf279a9a 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -22,7 +22,7 @@ from esphome.helpers import write_file_if_changed from . import defines as df, helpers, lv_validation as lvalid from .automation import disp_update, focused_widgets, update_to_code -from .defines import CONF_WIDGETS, add_define +from .defines import add_define from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code from .gradient import GRADIENT_SCHEMA, gradients_to_code from .hello_world import get_hello_world @@ -54,7 +54,7 @@ from .types import ( lv_style_t, lvgl_ns, ) -from .widgets import Widget, add_widgets, lv_scr_act, set_obj_properties, styles_used +from .widgets import Widget, add_widgets, get_scr_act, set_obj_properties, styles_used from .widgets.animimg import animimg_spec from .widgets.arc import arc_spec from .widgets.button import button_spec @@ -186,7 +186,7 @@ def final_validation(config): async def to_code(config): cg.add_library("lvgl/lvgl", "8.4.0") - CORE.add_define("USE_LVGL") + cg.add_define("USE_LVGL") # suppress default enabling of extra widgets add_define("_LV_KCONFIG_PRESENT") # Always enable - lots of things use it. @@ -200,7 +200,13 @@ async def to_code(config): add_define("LV_MEM_CUSTOM_REALLOC", "lv_custom_mem_realloc") add_define("LV_MEM_CUSTOM_INCLUDE", '"esphome/components/lvgl/lvgl_hal.h"') - add_define("LV_LOG_LEVEL", f"LV_LOG_LEVEL_{config[df.CONF_LOG_LEVEL]}") + add_define( + "LV_LOG_LEVEL", f"LV_LOG_LEVEL_{df.LV_LOG_LEVELS[config[df.CONF_LOG_LEVEL]]}" + ) + cg.add_define( + "LVGL_LOG_LEVEL", + cg.RawExpression(f"ESPHOME_LOG_LEVEL_{config[df.CONF_LOG_LEVEL]}"), + ) add_define("LV_COLOR_DEPTH", config[df.CONF_COLOR_DEPTH]) for font in helpers.lv_fonts_used: add_define(f"LV_FONT_{font.upper()}") @@ -214,15 +220,9 @@ async def to_code(config): "LV_COLOR_CHROMA_KEY", await lvalid.lv_color.process(config[df.CONF_TRANSPARENCY_KEY]), ) - CORE.add_build_flag("-Isrc") + cg.add_build_flag("-Isrc") cg.add_global(lvgl_ns.using) - lv_component = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(lv_component, config) - Widget.create(config[CONF_ID], lv_component, obj_spec, config) - for display in config[df.CONF_DISPLAYS]: - cg.add(lv_component.add_display(await cg.get_variable(display))) - frac = config[CONF_BUFFER_SIZE] if frac >= 0.75: frac = 1 @@ -232,10 +232,17 @@ async def to_code(config): frac = 4 else: frac = 8 - cg.add(lv_component.set_buffer_frac(int(frac))) - cg.add(lv_component.set_full_refresh(config[df.CONF_FULL_REFRESH])) - cg.add(lv_component.set_draw_rounding(config[df.CONF_DRAW_ROUNDING])) - cg.add(lv_component.set_resume_on_input(config[df.CONF_RESUME_ON_INPUT])) + displays = [await cg.get_variable(display) for display in config[df.CONF_DISPLAYS]] + lv_component = cg.new_Pvariable( + config[CONF_ID], + displays, + frac, + config[df.CONF_FULL_REFRESH], + config[df.CONF_DRAW_ROUNDING], + config[df.CONF_RESUME_ON_INPUT], + ) + await cg.register_component(lv_component, config) + Widget.create(config[CONF_ID], lv_component, obj_spec, config) for font in helpers.esphome_fonts_used: await cg.get_variable(font) @@ -257,6 +264,7 @@ async def to_code(config): else: add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font)) + lv_scr_act = get_scr_act(lv_component) async with LvContext(lv_component): await touchscreens_to_code(lv_component, config) await encoders_to_code(lv_component, config) @@ -266,11 +274,9 @@ async def to_code(config): await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) await add_pages(lv_component, config) - await add_top_layer(config) - await msgboxes_to_code(config) - await disp_update(f"{lv_component}->get_disp()", config) - # At this point only the setup code should be generated - assert LvContext.added_lambda_count == 1 + await add_top_layer(lv_component, config) + await msgboxes_to_code(lv_component, config) + await disp_update(lv_component.get_disp(), config) # Set this directly since we are limited in how many methods can be added to the Widget class. Widget.widgets_completed = True async with LvContext(lv_component): @@ -291,15 +297,15 @@ async def to_code(config): await build_automation(resume_trigger, [], conf) for comp in helpers.lvgl_components_required: - CORE.add_define(f"USE_LVGL_{comp.upper()}") + cg.add_define(f"USE_LVGL_{comp.upper()}") if "transform_angle" in styles_used: add_define("LV_COLOR_SCREEN_TRANSP", "1") for use in helpers.lv_uses: add_define(f"LV_USE_{use.upper()}") lv_conf_h_file = CORE.relative_src_path(LV_CONF_FILENAME) write_file_if_changed(lv_conf_h_file, generate_lv_conf_h()) - CORE.add_build_flag("-DLV_CONF_H=1") - CORE.add_build_flag(f'-DLV_CONF_PATH="{LV_CONF_FILENAME}"') + cg.add_build_flag("-DLV_CONF_H=1") + cg.add_build_flag(f'-DLV_CONF_PATH="{LV_CONF_FILENAME}"') def display_schema(config): @@ -308,9 +314,9 @@ def display_schema(config): def add_hello_world(config): - if CONF_WIDGETS not in config and CONF_PAGES not in config: + if df.CONF_WIDGETS not in config and CONF_PAGES not in config: LOGGER.info("No pages or widgets configured, creating default hello_world page") - config[CONF_WIDGETS] = cv.ensure_list(WIDGET_SCHEMA)(get_hello_world()) + config[df.CONF_WIDGETS] = cv.ensure_list(WIDGET_SCHEMA)(get_hello_world()) return config @@ -329,7 +335,7 @@ CONFIG_SCHEMA = ( cv.Optional(df.CONF_DRAW_ROUNDING, default=2): cv.positive_int, cv.Optional(CONF_BUFFER_SIZE, default="100%"): cv.percentage, cv.Optional(df.CONF_LOG_LEVEL, default="WARN"): cv.one_of( - *df.LOG_LEVELS, upper=True + *df.LV_LOG_LEVELS, upper=True ), cv.Optional(df.CONF_BYTE_ORDER, default="big_endian"): cv.one_of( "big_endian", "little_endian" diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index cdc7553e81..48472354f8 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -5,7 +5,7 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT -from esphome.cpp_generator import RawExpression, get_variable +from esphome.cpp_generator import get_variable from esphome.cpp_types import nullptr from .defines import ( @@ -23,7 +23,6 @@ from .lvcode import ( UPDATE_EVENT, LambdaContext, LocalVariable, - LvConditional, LvglComponent, ReturnStatement, add_line_marks, @@ -47,8 +46,8 @@ from .types import ( ) from .widgets import ( Widget, + get_scr_act, get_widgets, - lv_scr_act, set_obj_properties, wait_for_widgets, ) @@ -66,8 +65,6 @@ async def action_to_code( ): await wait_for_widgets() async with LambdaContext(parameters=args, where=action_id) as context: - with LvConditional(lv_expr.is_pre_initialise()): - context.add(RawExpression("return")) for widget in widgets: await action(widget) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) @@ -126,7 +123,7 @@ async def lvgl_is_idle(config, condition_id, template_arg, args): async def disp_update(disp, config: dict): if CONF_DISP_BG_COLOR not in config and CONF_DISP_BG_IMAGE not in config: return - with LocalVariable("lv_disp_tmp", lv_disp_t, literal(disp)) as disp_temp: + with LocalVariable("lv_disp_tmp", lv_disp_t, disp) as disp_temp: if (bg_color := config.get(CONF_DISP_BG_COLOR)) is not None: lv.disp_set_bg_color(disp_temp, await lv_color.process(bg_color)) if bg_image := config.get(CONF_DISP_BG_IMAGE): @@ -136,15 +133,24 @@ async def disp_update(disp, config: dict): @automation.register_action( "lvgl.widget.redraw", ObjUpdateAction, - cv.Schema( - { - cv.Optional(CONF_ID): cv.use_id(lv_obj_t), - cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), - } + cv.Any( + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(lv_obj_t), + cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), + }, + key=CONF_ID, + ), + cv.Schema( + { + cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), + } + ), ), ) async def obj_invalidate_to_code(config, action_id, template_arg, args): - widgets = await get_widgets(config) or [lv_scr_act] + lv_comp = await cg.get_variable(config[CONF_LVGL_ID]) + widgets = await get_widgets(config) or [get_scr_act(lv_comp)] async def do_invalidate(widget: Widget): lv_obj.invalidate(widget.obj) @@ -164,7 +170,7 @@ async def obj_invalidate_to_code(config, action_id, template_arg, args): async def lvgl_update_to_code(config, action_id, template_arg, args): widgets = await get_widgets(config) w = widgets[0] - disp = f"{w.obj}->get_disp()" + disp = literal(f"{w.obj}->get_disp()") async with LambdaContext(LVGL_COMP_ARG, where=action_id) as context: await disp_update(disp, config) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index c8ece02677..4d48028611 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -189,14 +189,14 @@ LV_ANIM = LvConstant( LV_GRAD_DIR = LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER") LV_DITHER = LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF") -LOG_LEVELS = ( - "TRACE", - "INFO", - "WARN", - "ERROR", - "USER", - "NONE", -) +LV_LOG_LEVELS = { + "VERBOSE": "TRACE", + "DEBUG": "TRACE", + "INFO": "INFO", + "WARN": "WARN", + "ERROR": "ERROR", + "NONE": "NONE", +} LV_LONG_MODES = LvConstant( "LV_LABEL_LONG_", diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 3a080d63e9..37d6670b84 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -183,17 +183,11 @@ class LvContext(LambdaContext): super().__init__(parameters=self.args) self.lv_component = lv_component - async def add_init_lambda(self): - if self.code_list: - cg.add(self.lv_component.add_init_lambda(await self.get_lambda())) - LvContext.added_lambda_count += 1 - async def __aexit__(self, exc_type, exc_val, exc_tb): await super().__aexit__(exc_type, exc_val, exc_tb) - await self.add_init_lambda() def add(self, expression: Union[Expression, Statement]): - self.code_list.append(self.indented_statement(expression)) + cg.add(expression) return expression def __call__(self, *args): diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 5a6c66c677..413b039af0 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -11,12 +11,6 @@ namespace esphome { namespace lvgl { static const char *const TAG = "lvgl"; -#if LV_USE_LOG -static void log_cb(const char *buf) { - esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); -} -#endif // LV_USE_LOG - static const char *const EVENT_NAMES[] = { "NONE", "PRESSED", @@ -383,26 +377,48 @@ void LvglComponent::write_random_() { } } -void LvglComponent::setup() { - ESP_LOGCONFIG(TAG, "LVGL Setup starts"); -#if LV_USE_LOG - lv_log_register_print_cb(log_cb); -#endif +/** + * @class LvglComponent + * @brief Component for rendering LVGL. + * + * This component renders LVGL widgets on a display. Some initialisation must be done in the constructor + * since LVGL needs to be initialised before any widgets can be created. + * + * @param displays a list of displays to render onto. All displays must have the same + * resolution. + * @param buffer_frac the fraction of the display resolution to use for the LVGL + * draw buffer. A higher value will make animations smoother but + * also increase memory usage. + * @param full_refresh if true, the display will be fully refreshed on every frame. + * If false, only changed areas will be updated. + * @param draw_rounding the rounding to use when drawing. A value of 1 will draw + * without any rounding, a value of 2 will round to the nearest + * multiple of 2, and so on. + * @param resume_on_input if true, this component will resume rendering when the user + * presses a key or clicks on the screen. + */ +LvglComponent::LvglComponent(std::vector displays, float buffer_frac, bool full_refresh, + int draw_rounding, bool resume_on_input) + : draw_rounding(draw_rounding), + displays_(std::move(displays)), + buffer_frac_(buffer_frac), + full_refresh_(full_refresh), + resume_on_input_(resume_on_input) { lv_init(); lv_update_event = static_cast(lv_event_register_id()); lv_api_event = static_cast(lv_event_register_id()); auto *display = this->displays_[0]; size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_; auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; - auto *buf = lv_custom_mem_alloc(buf_bytes); // NOLINT - if (buf == nullptr) { -#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR - ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); -#endif - this->mark_failed(); - this->status_set_error("Memory allocation failure"); - return; + this->rotation = display->get_rotation(); + if (this->rotation != display::DISPLAY_ROTATION_0_DEGREES) { + this->rotate_buf_ = static_cast(lv_custom_mem_alloc(buf_bytes)); // NOLINT + if (this->rotate_buf_ == nullptr) + return; } + auto *buf = lv_custom_mem_alloc(buf_bytes); // NOLINT + if (buf == nullptr) + return; lv_disp_draw_buf_init(&this->draw_buf_, buf, nullptr, buffer_pixels); lv_disp_drv_init(&this->disp_drv_); this->disp_drv_.draw_buf = &this->draw_buf_; @@ -410,18 +426,7 @@ void LvglComponent::setup() { this->disp_drv_.full_refresh = this->full_refresh_; this->disp_drv_.flush_cb = static_flush_cb; this->disp_drv_.rounder_cb = rounder_cb; - this->rotation = display->get_rotation(); - if (this->rotation != display::DISPLAY_ROTATION_0_DEGREES) { - this->rotate_buf_ = static_cast(lv_custom_mem_alloc(buf_bytes)); // NOLINT - if (this->rotate_buf_ == nullptr) { -#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR - ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); -#endif - this->mark_failed(); - this->status_set_error("Memory allocation failure"); - return; - } - } + // reset the display rotation since we will handle all rotations display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES); switch (this->rotation) { default: @@ -435,12 +440,30 @@ void LvglComponent::setup() { break; } this->disp_ = lv_disp_drv_register(&this->disp_drv_); - for (const auto &v : this->init_lambdas_) - v(this); +} + +void LvglComponent::setup() { + if (this->draw_buf_.buf1 == nullptr) { + this->mark_failed(); + this->status_set_error("Memory allocation failure"); + return; + } + ESP_LOGCONFIG(TAG, "LVGL Setup starts"); +#if LV_USE_LOG + lv_log_register_print_cb([](const char *buf) { + auto next = strchr(buf, ')'); + if (next != nullptr) + buf = next + 1; + while (isspace(*buf)) + buf++; + esp_log_printf_(LVGL_LOG_LEVEL, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); + }); +#endif this->show_page(0, LV_SCR_LOAD_ANIM_NONE, 0); lv_disp_trig_activity(this->disp_); ESP_LOGCONFIG(TAG, "LVGL Setup complete"); } + void LvglComponent::update() { // update indicators if (this->paused_) { @@ -455,13 +478,6 @@ void LvglComponent::loop() { } lv_timer_handler_run_in_period(5); } -bool lv_is_pre_initialise() { - if (!lv_is_initialized()) { - ESP_LOGE(TAG, "LVGL call before component is initialised"); - return true; - } - return false; -} #ifdef USE_LVGL_ANIMIMG void lv_animimg_stop(lv_obj_t *obj) { diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 2d326f4ae2..b8c0f5738e 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -39,7 +39,6 @@ namespace lvgl { extern lv_event_code_t lv_api_event; // NOLINT extern lv_event_code_t lv_update_event; // NOLINT extern std::string lv_event_code_name_for(uint8_t event_code); -extern bool lv_is_pre_initialise(); #if LV_COLOR_DEPTH == 16 static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; #elif LV_COLOR_DEPTH == 32 @@ -108,6 +107,8 @@ class LvglComponent : public PollingComponent { constexpr static const char *const TAG = "lvgl"; public: + LvglComponent(std::vector displays, float buffer_frac, bool full_refresh, int draw_rounding, + bool resume_on_input); static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); float get_setup_priority() const override { return setup_priority::PROCESSOR; } @@ -118,13 +119,10 @@ class LvglComponent : public PollingComponent { this->idle_callbacks_.add(std::move(callback)); } void add_on_pause_callback(std::function &&callback) { this->pause_callbacks_.add(std::move(callback)); } - void add_display(display::Display *display) { this->displays_.push_back(display); } - void add_init_lambda(const std::function &lamb) { this->init_lambdas_.push_back(lamb); } void dump_config() override; - void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; } bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; } - void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } lv_disp_t *get_disp() { return this->disp_; } + lv_obj_t *get_scr_act() { return lv_disp_get_scr_act(this->disp_); } // Pause or resume the display. // @param paused If true, pause the display. If false, resume the display. // @param show_snow If true, show the snow effect when paused. @@ -155,17 +153,19 @@ class LvglComponent : public PollingComponent { } // rounding factor to align bounds of update area when drawing size_t draw_rounding{2}; - void set_draw_rounding(size_t rounding) { this->draw_rounding = rounding; } - void set_resume_on_input(bool resume_on_input) { this->resume_on_input_ = resume_on_input; } - // if set to true, the bounds of the update area will always start at 0,0 display::DisplayRotation rotation{display::DISPLAY_ROTATION_0_DEGREES}; protected: void write_random_(); void draw_buffer_(const lv_area_t *area, lv_color_t *ptr); void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); + std::vector displays_{}; + size_t buffer_frac_{1}; + bool full_refresh_{}; + bool resume_on_input_{}; + lv_disp_draw_buf_t draw_buf_{}; lv_disp_drv_t disp_drv_{}; lv_disp_t *disp_{}; @@ -174,14 +174,10 @@ class LvglComponent : public PollingComponent { size_t current_page_{0}; bool show_snow_{}; bool page_wrap_{true}; - bool resume_on_input_{}; std::map focus_marks_{}; - std::vector> init_lambdas_; CallbackManager idle_callbacks_{}; CallbackManager pause_callbacks_{}; - size_t buffer_frac_{1}; - bool full_refresh_{}; lv_color_t *rotate_buf_{}; }; diff --git a/esphome/components/lvgl/styles.py b/esphome/components/lvgl/styles.py index 030db5fd22..6332e0976f 100644 --- a/esphome/components/lvgl/styles.py +++ b/esphome/components/lvgl/styles.py @@ -17,8 +17,6 @@ from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map from .widgets.obj import obj_spec -TOP_LAYER = literal("lv_disp_get_layer_top(lv_component->get_disp())") - async def styles_to_code(config): """Convert styles to C__ code.""" @@ -51,9 +49,10 @@ async def theme_to_code(config): lv_assign(apply, await context.get_lambda()) -async def add_top_layer(config): +async def add_top_layer(lv_component, config): + top_layer = lv.disp_get_layer_top(lv_component.get_disp()) if top_conf := config.get(CONF_TOP_LAYER): - with LocalVariable("top_layer", lv_obj_t, TOP_LAYER) as top_layer_obj: + with LocalVariable("top_layer", lv_obj_t, top_layer) as top_layer_obj: top_w = Widget(top_layer_obj, obj_spec, top_conf) await set_obj_properties(top_w, top_conf) await add_widgets(top_w, top_conf) diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 35ee6c54e8..e946a96000 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -55,18 +55,6 @@ theme_widget_map = {} styles_used = set() -class LvScrActType(WidgetType): - """ - A "widget" representing the active screen. - """ - - def __init__(self): - super().__init__("lv_scr_act()", lv_obj_t, ()) - - async def to_code(self, w, config: dict): - return [] - - class Widget: """ Represents a Widget. @@ -221,6 +209,25 @@ class Widget: widget_map: dict[Any, Widget] = {} +class LvScrActType(WidgetType): + """ + A "widget" representing the active screen. + """ + + def __init__(self): + super().__init__("lv_scr_act()", lv_obj_t, ()) + + async def to_code(self, w, config: dict): + return [] + + +lv_scr_act_spec = LvScrActType() + + +def get_scr_act(lv_comp: MockObj) -> Widget: + return Widget.create(None, lv_comp.get_scr_act(), lv_scr_act_spec, {}) + + def get_widget_generator(wid): """ Used to wait for a widget during code generation. @@ -451,7 +458,3 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent): await set_obj_properties(w, w_cnfig) await add_widgets(w, w_cnfig) await spec.to_code(w, w_cnfig) - - -lv_scr_act_spec = LvScrActType() -lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {}) diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index 1af4ed6e05..be0f2100d7 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -20,6 +20,7 @@ from ..lvcode import ( EVENT_ARG, LambdaContext, LocalVariable, + lv, lv_add, lv_assign, lv_expr, @@ -27,7 +28,6 @@ from ..lvcode import ( lv_Pvariable, ) from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema -from ..styles import TOP_LAYER from ..types import LV_EVENT, char_ptr, lv_obj_t from . import Widget, set_obj_properties from .button import button_spec @@ -59,7 +59,7 @@ MSGBOX_SCHEMA = container_schema( ) -async def msgbox_to_code(conf): +async def msgbox_to_code(top_layer, conf): """ Construct a message box. This consists of a full-screen translucent background enclosing a centered container with an optional title, body, close button and a button matrix. And any other widgets the user cares to add @@ -101,7 +101,7 @@ async def msgbox_to_code(conf): text = await lv_text.process(conf[CONF_BODY].get(CONF_TEXT, "")) title = await lv_text.process(conf[CONF_TITLE].get(CONF_TEXT, "")) close_button = conf[CONF_CLOSE_BUTTON] - lv_assign(outer, lv_expr.obj_create(TOP_LAYER)) + lv_assign(outer, lv_expr.obj_create(top_layer)) lv_obj.set_width(outer, lv_pct(100)) lv_obj.set_height(outer, lv_pct(100)) lv_obj.set_style_bg_opa(outer, 128, 0) @@ -141,6 +141,7 @@ async def msgbox_to_code(conf): set_btn_data(buttonmatrix.obj, ctrl_list, width_list) -async def msgboxes_to_code(config): +async def msgboxes_to_code(lv_component, config): + top_layer = lv.disp_get_layer_top(lv_component.get_disp()) for conf in config.get(CONF_MSGBOXES, ()): - await msgbox_to_code(conf) + await msgbox_to_code(top_layer, conf) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 1f09bc22eb..8d515280c9 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -12,12 +12,12 @@ substitutions: arrow_down: "\U000F004B" lvgl: + log_level: debug resume_on_input: true on_pause: logger.log: LVGL is Paused on_resume: logger.log: LVGL has resumed - log_level: TRACE bg_color: light_blue disp_bg_color: color_id disp_bg_image: cat_image @@ -125,6 +125,8 @@ lvgl: on_unload: - logger.log: page unloaded - lvgl.widget.focus: mark + - lvgl.widget.redraw: hello_label + - lvgl.widget.redraw: on_all_events: logger.log: format: "Event %s" From ef6ccddc0d1bbe61d8c8331ed7eb933f284c8ef7 Mon Sep 17 00:00:00 2001 From: guillempages Date: Thu, 17 Oct 2024 22:23:37 +0200 Subject: [PATCH 2527/2607] [lvgl] Allow esphome::Image in lambda to update image source directly (#7624) --- esphome/components/lvgl/lvgl_esphome.h | 11 +++++++++++ tests/components/lvgl/common.yaml | 5 +++++ tests/components/lvgl/lvgl-package.yaml | 1 + 3 files changed, 17 insertions(+) diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index b8c0f5738e..f357c4950c 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -4,6 +4,9 @@ #ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" #endif // USE_BINARY_SENSOR +#ifdef USE_LVGL_IMAGE +#include "esphome/components/image/image.h" +#endif // USE_LVGL_IMAGE #ifdef USE_LVGL_ROTARY_ENCODER #include "esphome/components/rotary_encoder/rotary_encoder.h" #endif // USE_LVGL_ROTARY_ENCODER @@ -47,6 +50,14 @@ static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BIT static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_332; #endif // LV_COLOR_DEPTH +#ifdef USE_LVGL_IMAGE +// Shortcut / overload, so that the source of an image can easily be updated +// from within a lambda. +inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) { + lv_img_set_src(obj, image->get_lv_img_dsc()); +} +#endif // USE_LVGL_IMAGE + // Parent class for things that wrap an LVGL object class LvCompound { public: diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index ad935ae563..5dcf30e0c1 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -127,6 +127,11 @@ binary_sensor: - platform: lvgl name: LVGL checkbox widget: checkbox_id + on_state: + then: + - lvgl.image.update: + id: lv_image + src: !lambda if (x) return id(cat_image); else return id(dog_image); wifi: ssid: SSID diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 8d515280c9..cef76396c2 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -419,6 +419,7 @@ lvgl: spin_time: 2s align: left_mid - image: + id: lv_image src: cat_image align: top_left y: 50 From c019ff34bccf08b3070cae3c1e71c2767cf70a6e Mon Sep 17 00:00:00 2001 From: Shivam Maurya <54358380+shvmm@users.noreply.github.com> Date: Fri, 18 Oct 2024 06:45:28 +0530 Subject: [PATCH 2528/2607] Bump bme68x_bsec2 version to 1.8.2610 (#7626) --- esphome/components/bme68x_bsec2/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/bme68x_bsec2/__init__.py b/esphome/components/bme68x_bsec2/__init__.py index 1930c7c9e3..d6dbb52f18 100644 --- a/esphome/components/bme68x_bsec2/__init__.py +++ b/esphome/components/bme68x_bsec2/__init__.py @@ -16,7 +16,7 @@ CODEOWNERS = ["@neffs", "@kbx81"] DOMAIN = "bme68x_bsec2" -BSEC2_LIBRARY_VERSION = "v1.7.2502" +BSEC2_LIBRARY_VERSION = "v1.8.2610" CONF_ALGORITHM_OUTPUT = "algorithm_output" CONF_BME68X_BSEC2_ID = "bme68x_bsec2_id" From 43a020641b89b86b7082f956e3c335de38bd97b0 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:16:08 +0200 Subject: [PATCH 2529/2607] Fix broken ibeacon_uuid config in ble_rssi (#7640) --- esphome/components/ble_rssi/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index e3ba1abfd7..c4e767aa21 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -45,7 +45,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, - cv.Optional(CONF_IBEACON_UUID): cv.uuid, + cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid, } ) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) @@ -79,7 +79,7 @@ async def to_code(config): cg.add(var.set_service_uuid128(uuid128)) if ibeacon_uuid := config.get(CONF_IBEACON_UUID): - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) + ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: From f7543a7b8dd1b5f8984c4dc84fc087df3f392784 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:28:52 +1300 Subject: [PATCH 2530/2607] Update Pull request template (#7620) --- .github/PULL_REQUEST_TEMPLATE.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3bf9c4e1f6..5703d39be1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,11 +7,16 @@ - [ ] Bugfix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Code quality improvements to existing code or addition of tests - [ ] Other -**Related issue or feature (if applicable):** fixes +**Related issue or feature (if applicable):** -**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs# +- fixes + +**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** + +- esphome/esphome-docs# ## Test Environment @@ -23,12 +28,6 @@ - [ ] RTL87xx ## Example entry for `config.yaml`: - ```yaml # Example config.yaml From 657527655d380554edfdd3274d7b1d5ac1b4a32a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 20 Oct 2024 17:40:43 -0700 Subject: [PATCH 2531/2607] auto-load preferences (#7642) Co-authored-by: Samuel Sieb --- esphome/components/host/__init__.py | 2 +- esphome/components/libretiny/__init__.py | 2 +- esphome/components/rp2040/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index e83bf2dba8..eb8cfbd984 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -16,7 +16,7 @@ from .const import KEY_HOST from .gpio import host_pin_to_code # noqa CODEOWNERS = ["@esphome/core", "@clydebarrow"] -AUTO_LOAD = ["network"] +AUTO_LOAD = ["network", "preferences"] def set_core_data(config): diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index cc7fae7e70..b29d2e309c 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -46,7 +46,7 @@ from .const import ( _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@kuba2k2"] -AUTO_LOAD = [] +AUTO_LOAD = ["preferences"] def _detect_variant(value): diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 925acb629d..f59962477f 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -26,7 +26,7 @@ from .gpio import rp2040_pin_to_code # noqa _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@jesserockz"] -AUTO_LOAD = [] +AUTO_LOAD = ["preferences"] def set_core_data(config): From 5e8794175dceb777f928a2966c4c5e9a977c2acc Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 21 Oct 2024 17:46:41 -0500 Subject: [PATCH 2532/2607] [wifi] Support custom MAC on Arduino, too (#7644) --- esphome/components/esp32/__init__.py | 12 ++++++++++-- .../components/wifi/wifi_component_esp32_arduino.cpp | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 8a73f2020d..61fbb53e3a 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -395,6 +395,13 @@ ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, + cv.Optional(CONF_ADVANCED, default={}): cv.Schema( + { + cv.Optional( + CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False + ): cv.boolean, + } + ), } ), _arduino_check_versions, @@ -494,6 +501,9 @@ async def to_code(config): conf = config[CONF_FRAMEWORK] cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) + if CONF_ADVANCED in conf and conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: + cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") + add_extra_script( "post", "post_build.py", @@ -540,8 +550,6 @@ async def to_code(config): for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) - if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: - cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") if conf[CONF_ADVANCED].get(CONF_IGNORE_EFUSE_MAC_CRC): add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) if (framework_ver.major, framework_ver.minor) >= (4, 4): diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index b8724838c8..ef4308b28c 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -34,6 +34,11 @@ static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non static bool s_sta_connecting = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) void WiFiComponent::wifi_pre_setup_() { + uint8_t mac[6]; + if (has_custom_mac_address()) { + get_mac_address_raw(mac); + set_mac_address(mac); + } auto f = std::bind(&WiFiComponent::wifi_event_callback_, this, std::placeholders::_1, std::placeholders::_2); WiFi.onEvent(f); WiFi.persistent(false); From c8d0cde329a83dd042412651c033dd133c9a3330 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:49:12 +1100 Subject: [PATCH 2533/2607] [config] Ensure user-supplied build flags don't get silently overwritten (#7622) --- esphome/core/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/config.py b/esphome/core/config.py index f4253bee87..8c130eb6db 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -318,6 +318,8 @@ async def add_includes(includes): async def _add_platformio_options(pio_options): # Add includes at the very end, so that they override everything for key, val in pio_options.items(): + if key == "build_flags" and not isinstance(val, list): + val = [val] cg.add_platformio_option(key, val) From 612e2c164406fe0d4670b8af68478c3b3644c47e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:50:16 +1100 Subject: [PATCH 2534/2607] [lvgl] Defer display rotation reset until setup(). (Bugfix) (#7627) --- esphome/components/lvgl/lvgl_esphome.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 413b039af0..c8f7848a4f 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -84,6 +84,7 @@ lv_event_code_t lv_api_event; // NOLINT lv_event_code_t lv_update_event; // NOLINT void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); + ESP_LOGCONFIG(TAG, " Display width/height: %d x %d", this->disp_drv_.hor_res, this->disp_drv_.ver_res); ESP_LOGCONFIG(TAG, " Rotation: %d", this->rotation); ESP_LOGCONFIG(TAG, " Draw rounding: %d", (int) this->draw_rounding); } @@ -426,19 +427,8 @@ LvglComponent::LvglComponent(std::vector displays, float buf this->disp_drv_.full_refresh = this->full_refresh_; this->disp_drv_.flush_cb = static_flush_cb; this->disp_drv_.rounder_cb = rounder_cb; - // reset the display rotation since we will handle all rotations - display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES); - switch (this->rotation) { - default: - this->disp_drv_.hor_res = (lv_coord_t) display->get_width(); - this->disp_drv_.ver_res = (lv_coord_t) display->get_height(); - break; - case display::DISPLAY_ROTATION_90_DEGREES: - case display::DISPLAY_ROTATION_270_DEGREES: - this->disp_drv_.ver_res = (lv_coord_t) display->get_width(); - this->disp_drv_.hor_res = (lv_coord_t) display->get_height(); - break; - } + this->disp_drv_.hor_res = (lv_coord_t) display->get_width(); + this->disp_drv_.ver_res = (lv_coord_t) display->get_height(); this->disp_ = lv_disp_drv_register(&this->disp_drv_); } @@ -459,6 +449,9 @@ void LvglComponent::setup() { esp_log_printf_(LVGL_LOG_LEVEL, TAG, 0, "%.*s", (int) strlen(buf) - 1, buf); }); #endif + // Rotation will be handled by our drawing function, so reset the display rotation. + for (auto *display : this->displays_) + display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES); this->show_page(0, LV_SCR_LOAD_ANIM_NONE, 0); lv_disp_trig_activity(this->disp_); ESP_LOGCONFIG(TAG, "LVGL Setup complete"); From 40ad6befa83f23674d09bf70198eb8761fa69c81 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:51:40 +1100 Subject: [PATCH 2535/2607] [lvgl] Remove states from style definitions (Bugfix) (#7645) --- esphome/components/lvgl/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index beaf279a9a..215fdecdb5 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -33,7 +33,7 @@ from .schemas import ( FLEX_OBJ_SCHEMA, GRID_CELL_SCHEMA, LAYOUT_SCHEMAS, - STATE_SCHEMA, + STYLE_SCHEMA, WIDGET_TYPES, any_widget_schema, container_schema, @@ -342,7 +342,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(df.CONF_STYLE_DEFINITIONS): cv.ensure_list( cv.Schema({cv.Required(CONF_ID): cv.declare_id(lv_style_t)}) - .extend(STATE_SCHEMA) + .extend(STYLE_SCHEMA) .extend( { cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, From dc42427c604ed14ab94270df8148fad22e101ee4 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 21 Oct 2024 18:14:07 -0500 Subject: [PATCH 2536/2607] Move setting global voice assistant to constructor (#7630) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/voice_assistant/voice_assistant.cpp | 8 ++------ esphome/components/voice_assistant/voice_assistant.h | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index a2210f188d..0b53e74ba3 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -23,6 +23,8 @@ static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t); static const size_t RECEIVE_SIZE = 1024; static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; +VoiceAssistant::VoiceAssistant() { global_voice_assistant = this; } + float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } bool VoiceAssistant::start_udp_socket_() { @@ -68,12 +70,6 @@ bool VoiceAssistant::start_udp_socket_() { return true; } -void VoiceAssistant::setup() { - ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); - - global_voice_assistant = this; -} - bool VoiceAssistant::allocate_buffers_() { if (this->send_buffer_ != nullptr) { return true; // Already allocated diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 56ada0e75a..870e2acdaa 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -91,7 +91,8 @@ struct Configuration { class VoiceAssistant : public Component { public: - void setup() override; + VoiceAssistant(); + void loop() override; float get_setup_priority() const override; void start_streaming(); From 7004053538c16544740e5e866395e9f94da1a63a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:32:22 +1100 Subject: [PATCH 2537/2607] [config] Fix crash with empty substitutions block (#7612) --- esphome/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config.py b/esphome/config.py index a2d0d15477..7d48569d2d 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -782,7 +782,7 @@ def validate_config( from esphome.components import substitutions result[CONF_SUBSTITUTIONS] = { - **config.get(CONF_SUBSTITUTIONS, {}), + **(config.get(CONF_SUBSTITUTIONS) or {}), **command_line_substitutions, } result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS) From 3dd34f66284ff8c5b0a69e70d57f6273d3395544 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:16:08 +0200 Subject: [PATCH 2538/2607] Fix broken ibeacon_uuid config in ble_rssi (#7640) --- esphome/components/ble_rssi/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index e3ba1abfd7..c4e767aa21 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -45,7 +45,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, - cv.Optional(CONF_IBEACON_UUID): cv.uuid, + cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid, } ) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) @@ -79,7 +79,7 @@ async def to_code(config): cg.add(var.set_service_uuid128(uuid128)) if ibeacon_uuid := config.get(CONF_IBEACON_UUID): - ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid)) + ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid) cg.add(var.set_ibeacon_uuid(ibeacon_uuid)) if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None: From 10791db82e7784f2e8b22a69ca8ad01223f8f1d7 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 20 Oct 2024 17:40:43 -0700 Subject: [PATCH 2539/2607] auto-load preferences (#7642) Co-authored-by: Samuel Sieb --- esphome/components/host/__init__.py | 2 +- esphome/components/libretiny/__init__.py | 2 +- esphome/components/rp2040/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index e83bf2dba8..eb8cfbd984 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -16,7 +16,7 @@ from .const import KEY_HOST from .gpio import host_pin_to_code # noqa CODEOWNERS = ["@esphome/core", "@clydebarrow"] -AUTO_LOAD = ["network"] +AUTO_LOAD = ["network", "preferences"] def set_core_data(config): diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index cc7fae7e70..b29d2e309c 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -46,7 +46,7 @@ from .const import ( _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@kuba2k2"] -AUTO_LOAD = [] +AUTO_LOAD = ["preferences"] def _detect_variant(value): diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 925acb629d..f59962477f 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -26,7 +26,7 @@ from .gpio import rp2040_pin_to_code # noqa _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@jesserockz"] -AUTO_LOAD = [] +AUTO_LOAD = ["preferences"] def set_core_data(config): From 748256b3eef8bcce7472983bd5d6f48dd55362cb Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 21 Oct 2024 17:46:41 -0500 Subject: [PATCH 2540/2607] [wifi] Support custom MAC on Arduino, too (#7644) --- esphome/components/esp32/__init__.py | 12 ++++++++++-- .../components/wifi/wifi_component_esp32_arduino.cpp | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 8a73f2020d..61fbb53e3a 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -395,6 +395,13 @@ ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, + cv.Optional(CONF_ADVANCED, default={}): cv.Schema( + { + cv.Optional( + CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False + ): cv.boolean, + } + ), } ), _arduino_check_versions, @@ -494,6 +501,9 @@ async def to_code(config): conf = config[CONF_FRAMEWORK] cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) + if CONF_ADVANCED in conf and conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: + cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") + add_extra_script( "post", "post_build.py", @@ -540,8 +550,6 @@ async def to_code(config): for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) - if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: - cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") if conf[CONF_ADVANCED].get(CONF_IGNORE_EFUSE_MAC_CRC): add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) if (framework_ver.major, framework_ver.minor) >= (4, 4): diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index b8724838c8..ef4308b28c 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -34,6 +34,11 @@ static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non static bool s_sta_connecting = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) void WiFiComponent::wifi_pre_setup_() { + uint8_t mac[6]; + if (has_custom_mac_address()) { + get_mac_address_raw(mac); + set_mac_address(mac); + } auto f = std::bind(&WiFiComponent::wifi_event_callback_, this, std::placeholders::_1, std::placeholders::_2); WiFi.onEvent(f); WiFi.persistent(false); From c26c96b8f469a3071c14ef91b5e7aa073a3aa9ca Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:49:12 +1100 Subject: [PATCH 2541/2607] [config] Ensure user-supplied build flags don't get silently overwritten (#7622) --- esphome/core/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/config.py b/esphome/core/config.py index f4253bee87..8c130eb6db 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -318,6 +318,8 @@ async def add_includes(includes): async def _add_platformio_options(pio_options): # Add includes at the very end, so that they override everything for key, val in pio_options.items(): + if key == "build_flags" and not isinstance(val, list): + val = [val] cg.add_platformio_option(key, val) From 3ebdd62c672dba8fa7d4c4ebd021750394c76596 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:51:40 +1100 Subject: [PATCH 2542/2607] [lvgl] Remove states from style definitions (Bugfix) (#7645) --- esphome/components/lvgl/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index ce3843567b..1a587edb57 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -33,7 +33,7 @@ from .schemas import ( FLEX_OBJ_SCHEMA, GRID_CELL_SCHEMA, LAYOUT_SCHEMAS, - STATE_SCHEMA, + STYLE_SCHEMA, WIDGET_TYPES, any_widget_schema, container_schema, @@ -323,7 +323,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(df.CONF_STYLE_DEFINITIONS): cv.ensure_list( cv.Schema({cv.Required(CONF_ID): cv.declare_id(lv_style_t)}) - .extend(STATE_SCHEMA) + .extend(STYLE_SCHEMA) .extend( { cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, From d95b370998527e279ac3a9c3376ede984929cd5d Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 21 Oct 2024 18:14:07 -0500 Subject: [PATCH 2543/2607] Move setting global voice assistant to constructor (#7630) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/voice_assistant/voice_assistant.cpp | 8 ++------ esphome/components/voice_assistant/voice_assistant.h | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index a2210f188d..0b53e74ba3 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -23,6 +23,8 @@ static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t); static const size_t RECEIVE_SIZE = 1024; static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE; +VoiceAssistant::VoiceAssistant() { global_voice_assistant = this; } + float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } bool VoiceAssistant::start_udp_socket_() { @@ -68,12 +70,6 @@ bool VoiceAssistant::start_udp_socket_() { return true; } -void VoiceAssistant::setup() { - ESP_LOGCONFIG(TAG, "Setting up Voice Assistant..."); - - global_voice_assistant = this; -} - bool VoiceAssistant::allocate_buffers_() { if (this->send_buffer_ != nullptr) { return true; // Already allocated diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 56ada0e75a..870e2acdaa 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -91,7 +91,8 @@ struct Configuration { class VoiceAssistant : public Component { public: - void setup() override; + VoiceAssistant(); + void loop() override; float get_setup_priority() const override; void start_streaming(); From 735c04cd6995e1cd220440af0fb79100a0b638f2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:57:17 +1300 Subject: [PATCH 2544/2607] Bump version to 2024.10.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5061b1a439..5fa457b25a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.0" +__version__ = "2024.10.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 8bb4316956a39a8c7141a9504f56ee0f5c32812a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:03:32 +1100 Subject: [PATCH 2545/2607] [lvgl] light schema should require `widget:` not `led:` (Bugfix) (#7649) --- esphome/components/lvgl/light/__init__.py | 8 ++++---- tests/components/lvgl/common.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/lvgl/light/__init__.py b/esphome/components/lvgl/light/__init__.py index a0eeded349..8031ae8221 100644 --- a/esphome/components/lvgl/light/__init__.py +++ b/esphome/components/lvgl/light/__init__.py @@ -2,9 +2,9 @@ import esphome.codegen as cg from esphome.components import light from esphome.components.light import LightOutput import esphome.config_validation as cv -from esphome.const import CONF_GAMMA_CORRECT, CONF_LED, CONF_OUTPUT_ID +from esphome.const import CONF_GAMMA_CORRECT, CONF_OUTPUT_ID -from ..defines import CONF_LVGL_ID +from ..defines import CONF_LVGL_ID, CONF_WIDGET from ..lvcode import LvContext from ..schemas import LVGL_SCHEMA from ..types import LvType, lvgl_ns @@ -15,7 +15,7 @@ LVLight = lvgl_ns.class_("LVLight", LightOutput) CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( { cv.Optional(CONF_GAMMA_CORRECT, default=0.0): cv.positive_float, - cv.Required(CONF_LED): cv.use_id(lv_led_t), + cv.Required(CONF_WIDGET): cv.use_id(lv_led_t), cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(LVLight), } ).extend(LVGL_SCHEMA) @@ -26,7 +26,7 @@ async def to_code(config): await light.register_light(var, config) paren = await cg.get_variable(config[CONF_LVGL_ID]) - widget = await get_widgets(config, CONF_LED) + widget = await get_widgets(config, CONF_WIDGET) widget = widget[0] await wait_for_widgets() async with LvContext(paren) as ctx: diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 5dcf30e0c1..cebc3caaa7 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -93,7 +93,7 @@ light: - platform: lvgl name: LVGL LED id: lv_light - led: lv_led + widget: lv_led binary_sensor: - platform: lvgl From ff48f53989f7886c167364e04df72f79039a9bac Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:05:39 +1100 Subject: [PATCH 2546/2607] [image] Fix compile time problem with host image not using lvgl (#7654) --- esphome/components/image/image.h | 7 +------ esphome/components/lvgl/lvgl_proxy.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 esphome/components/lvgl/lvgl_proxy.h diff --git a/esphome/components/image/image.h b/esphome/components/image/image.h index ae5a7a814d..a8a8aab2c2 100644 --- a/esphome/components/image/image.h +++ b/esphome/components/image/image.h @@ -3,12 +3,7 @@ #include "esphome/components/display/display.h" #ifdef USE_LVGL -// required for clang-tidy -#ifndef LV_CONF_H -#define LV_CONF_SKIP 1 // NOLINT -#endif // LV_CONF_H - -#include +#include "esphome/components/lvgl/lvgl_proxy.h" #endif // USE_LVGL namespace esphome { diff --git a/esphome/components/lvgl/lvgl_proxy.h b/esphome/components/lvgl/lvgl_proxy.h new file mode 100644 index 0000000000..0ccd80e541 --- /dev/null +++ b/esphome/components/lvgl/lvgl_proxy.h @@ -0,0 +1,17 @@ +#pragma once +/** +* This header is for use in components that might or might not use LVGL. There is a platformio bug where +the mere mention of a header file, even if ifdefed, causes the build to fail. This is a workaround, since if this +file is included in the build, LVGL is always included. +*/ +#ifdef USE_LVGL +// required for clang-tidy +#ifndef LV_CONF_H +#define LV_CONF_SKIP 1 // NOLINT +#endif // LV_CONF_H + +#include +namespace esphome { +namespace lvgl {} // namespace lvgl +} // namespace esphome +#endif // USE_LVGL From 3ac730fb2f5b7231e77d5d7c3822e7cc59fb4e59 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:06:58 +1100 Subject: [PATCH 2547/2607] [lvgl] Fix rotation code for 90deg (Bugfix) (#7653) --- esphome/components/lvgl/lvgl_esphome.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index c8f7848a4f..70cfb859de 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -146,7 +146,7 @@ void LvglComponent::draw_buffer_(const lv_area_t *area, lv_color_t *ptr) { lv_color_t *dst = this->rotate_buf_; switch (this->rotation) { case display::DISPLAY_ROTATION_90_DEGREES: - for (lv_coord_t x = height - 1; x-- != 0;) { + for (lv_coord_t x = height; x-- != 0;) { for (lv_coord_t y = 0; y != width; y++) { dst[y * height + x] = *ptr++; } From 6330177d24b82060afec7628d6152fea6b54f963 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:10:09 +1100 Subject: [PATCH 2548/2607] [lvgl] Allow strings to be interpreted as integers (Bugfix) (#7652) --- esphome/components/lvgl/lv_validation.py | 6 ++---- tests/components/lvgl/lvgl-package.yaml | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index fd840cc417..9af25a4e90 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -274,10 +274,8 @@ def size_validator(value): return ["SIZE_CONTENT", "number of pixels", "percentage"] if isinstance(value, str) and value.lower().endswith("px"): value = cv.int_(value[:-2]) - if isinstance(value, str) and not value.endswith("%"): - if value.upper() == "SIZE_CONTENT": - return "LV_SIZE_CONTENT" - raise cv.Invalid("must be 'size_content', a percentage or an integer (pixels)") + if isinstance(value, str) and value.upper() == "SIZE_CONTENT": + return "LV_SIZE_CONTENT" return pixels_or_percent_validator(value) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index cef76396c2..7fd824a87b 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -422,7 +422,7 @@ lvgl: id: lv_image src: cat_image align: top_left - y: 50 + y: "50" - tileview: id: tileview_id scrollbar_mode: active @@ -461,7 +461,7 @@ lvgl: bg_opa: transp knob: radius: 1 - width: 4 + width: "4" height: 10% bg_color: 0x000000 width: 100% From 2597975ae00dde096522b80824dbf9915a0d2fd7 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Tue, 22 Oct 2024 05:29:16 +0200 Subject: [PATCH 2549/2607] [rtttl] Add `get_gain()` (#7647) --- esphome/components/rtttl/rtttl.cpp | 5 ++++- esphome/components/rtttl/rtttl.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 495b5c1c8a..db4cc731e4 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -26,7 +26,10 @@ inline double deg2rad(double degrees) { return degrees * PI_ON_180; } -void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); } +void Rtttl::dump_config() { + ESP_LOGCONFIG(TAG, "Rtttl:"); + ESP_LOGCONFIG(TAG, " Gain: %f", gain_); +} void Rtttl::play(std::string rtttl) { if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { diff --git a/esphome/components/rtttl/rtttl.h b/esphome/components/rtttl/rtttl.h index 3cb6e3f5fb..10c290c5fb 100644 --- a/esphome/components/rtttl/rtttl.h +++ b/esphome/components/rtttl/rtttl.h @@ -39,6 +39,7 @@ class Rtttl : public Component { #ifdef USE_SPEAKER void set_speaker(speaker::Speaker *speaker) { this->speaker_ = speaker; } #endif + float get_gain() { return gain_; } void set_gain(float gain) { if (gain < 0.1f) gain = 0.1f; From a932ca2f64213e2af34c4d2e25f7f82766e98ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Mart=C3=ADn?= Date: Tue, 22 Oct 2024 05:38:25 +0200 Subject: [PATCH 2550/2607] feat(MQTT): Add subscribe QoS to discovery (#7648) --- esphome/components/mqtt/__init__.py | 3 +++ esphome/components/mqtt/mqtt_component.cpp | 6 ++++++ esphome/components/mqtt/mqtt_component.h | 4 ++++ esphome/components/mqtt/mqtt_const.h | 2 ++ esphome/config_validation.py | 4 +++- esphome/const.py | 1 + tests/components/mqtt/common.yaml | 1 + 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 336d928f71..8851581ea0 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -41,6 +41,7 @@ from esphome.const import ( CONF_SHUTDOWN_MESSAGE, CONF_SSL_FINGERPRINTS, CONF_STATE_TOPIC, + CONF_SUBSCRIBE_QOS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, @@ -518,6 +519,8 @@ async def register_mqtt_component(var, config): cg.add(var.set_qos(config[CONF_QOS])) if CONF_RETAIN in config: cg.add(var.set_retain(config[CONF_RETAIN])) + if CONF_SUBSCRIBE_QOS in config: + cg.add(var.set_subscribe_qos(config[CONF_SUBSCRIBE_QOS])) if not config.get(CONF_DISCOVERY, True): cg.add(var.disable_discovery()) if CONF_STATE_TOPIC in config: diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index 295fbba5e5..3b9d367a7b 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -16,6 +16,8 @@ static const char *const TAG = "mqtt.component"; void MQTTComponent::set_qos(uint8_t qos) { this->qos_ = qos; } +void MQTTComponent::set_subscribe_qos(uint8_t qos) { this->subscribe_qos_ = qos; } + void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; } std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const { @@ -76,6 +78,10 @@ bool MQTTComponent::send_discovery_() { config.command_topic = true; this->send_discovery(root, config); + // Set subscription QoS (default is 0) + if (this->subscribe_qos_ != 0) { + root[MQTT_QOS] = this->subscribe_qos_; + } // Fields from EntityBase if (this->get_entity()->has_own_name()) { diff --git a/esphome/components/mqtt/mqtt_component.h b/esphome/components/mqtt/mqtt_component.h index 147840d11f..01ba98ad40 100644 --- a/esphome/components/mqtt/mqtt_component.h +++ b/esphome/components/mqtt/mqtt_component.h @@ -89,6 +89,9 @@ class MQTTComponent : public Component { void disable_discovery(); bool is_discovery_enabled() const; + /// Set the QOS for subscribe messages (used in discovery). + void set_subscribe_qos(uint8_t qos); + /// Override this method to return the component type (e.g. "light", "sensor", ...) virtual std::string component_type() const = 0; @@ -204,6 +207,7 @@ class MQTTComponent : public Component { bool command_retain_{false}; bool retain_{true}; uint8_t qos_{0}; + uint8_t subscribe_qos_{0}; bool discovery_enabled_{true}; bool resend_state_{false}; }; diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index 71f169fbe8..c1c40c4b6d 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -180,6 +180,7 @@ constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "pr_mode_cmd_t"; constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "pr_mode_stat_t"; constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "pr_mode_val_tpl"; constexpr const char *const MQTT_PRESET_MODES = "pr_modes"; +constexpr const char *const MQTT_QOS = "qos"; constexpr const char *const MQTT_RED_TEMPLATE = "r_tpl"; constexpr const char *const MQTT_RETAIN = "ret"; constexpr const char *const MQTT_RGB_COMMAND_TEMPLATE = "rgb_cmd_tpl"; @@ -441,6 +442,7 @@ constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "preset_mode_comman constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "preset_mode_state_topic"; constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "preset_mode_value_template"; constexpr const char *const MQTT_PRESET_MODES = "preset_modes"; +constexpr const char *const MQTT_QOS = "qos"; constexpr const char *const MQTT_RED_TEMPLATE = "red_template"; constexpr const char *const MQTT_RETAIN = "retain"; constexpr const char *const MQTT_RGB_COMMAND_TEMPLATE = "rgb_command_template"; diff --git a/esphome/config_validation.py b/esphome/config_validation.py index a7525a62dd..98b81ec328 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -40,6 +40,7 @@ from esphome.const import ( CONF_SECOND, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, + CONF_SUBSCRIBE_QOS, CONF_TOPIC, CONF_TYPE, CONF_TYPE_ID, @@ -1893,9 +1894,10 @@ MQTT_COMPONENT_AVAILABILITY_SCHEMA = Schema( MQTT_COMPONENT_SCHEMA = Schema( { - Optional(CONF_QOS): All(requires_component("mqtt"), int_range(min=0, max=2)), + Optional(CONF_QOS): All(requires_component("mqtt"), mqtt_qos), Optional(CONF_RETAIN): All(requires_component("mqtt"), boolean), Optional(CONF_DISCOVERY): All(requires_component("mqtt"), boolean), + Optional(CONF_SUBSCRIBE_QOS): All(requires_component("mqtt"), mqtt_qos), Optional(CONF_STATE_TOPIC): All(requires_component("mqtt"), publish_topic), Optional(CONF_AVAILABILITY): All( requires_component("mqtt"), Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA) diff --git a/esphome/const.py b/esphome/const.py index a3a4318d69..54ebb2815f 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -819,6 +819,7 @@ CONF_STOP = "stop" CONF_STOP_ACTION = "stop_action" CONF_STORE_BASELINE = "store_baseline" CONF_SUBNET = "subnet" +CONF_SUBSCRIBE_QOS = "subscribe_qos" CONF_SUBSTITUTIONS = "substitutions" CONF_SUM = "sum" CONF_SUPPLEMENTAL_COOLING_ACTION = "supplemental_cooling_action" diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index f7a727ab2f..5ed6335d65 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -227,6 +227,7 @@ datetime: type: date state_topic: some/topic/date qos: 2 + subscribe_qos: 2 set_action: - logger.log: "set_value" on_value: From 7c0543862ad593916e1230d1dc2f2dec8e61c507 Mon Sep 17 00:00:00 2001 From: Kyle Cascade Date: Mon, 21 Oct 2024 21:11:23 -0700 Subject: [PATCH 2551/2607] Humanized the missing MQTT log topic error message (#7634) --- esphome/mqtt.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/mqtt.py b/esphome/mqtt.py index c1c45799cc..d55fb0202d 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -209,6 +209,12 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None): elif CONF_MQTT in config: conf = config[CONF_MQTT] if CONF_LOG_TOPIC in conf: + if config[CONF_MQTT][CONF_LOG_TOPIC] is None: + _LOGGER.error("MQTT log topic set to null, can't start MQTT logs") + return 1 + if CONF_TOPIC not in config[CONF_MQTT][CONF_LOG_TOPIC]: + _LOGGER.error("MQTT log topic not available, can't start MQTT logs") + return 1 topic = config[CONF_MQTT][CONF_LOG_TOPIC][CONF_TOPIC] elif CONF_TOPIC_PREFIX in config[CONF_MQTT]: topic = f"{config[CONF_MQTT][CONF_TOPIC_PREFIX]}/debug" From 68844c48698c6983a3d22498dbe70ee20c9835bf Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:16:55 +1100 Subject: [PATCH 2552/2607] [lvgl] Some properties were not templatable (Bugfix) (#7655) --- esphome/components/lvgl/lv_validation.py | 4 ++++ esphome/components/lvgl/schemas.py | 14 +++++++------- tests/components/lvgl/lvgl-package.yaml | 7 +++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 9af25a4e90..b91b0905df 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -267,6 +267,9 @@ def angle(value): return int(cv.float_range(0.0, 360.0)(cv.angle(value)) * 10) +lv_angle = LValidator(angle, uint32) + + @schema_extractor("one_of") def size_validator(value): """A size in one axis - one of "size_content", a number (pixels) or a percentage""" @@ -401,6 +404,7 @@ class TextValidator(LValidator): lv_text = TextValidator() lv_float = LValidator(cv.float_, cg.float_) lv_int = LValidator(cv.int_, cg.int_) +lv_positive_int = LValidator(cv.positive_int, cg.int_) lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255)) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 7599d64416..bb14c11ddd 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -91,7 +91,7 @@ STYLE_PROPS = { "arc_opa": lvalid.opacity, "arc_color": lvalid.lv_color, "arc_rounded": lvalid.lv_bool, - "arc_width": cv.positive_int, + "arc_width": lvalid.lv_positive_int, "anim_time": lvalid.lv_milliseconds, "bg_color": lvalid.lv_color, "bg_grad": lv_gradient, @@ -111,7 +111,7 @@ STYLE_PROPS = { "border_side": df.LvConstant( "LV_BORDER_SIDE_", "NONE", "TOP", "BOTTOM", "LEFT", "RIGHT", "INTERNAL" ).several_of, - "border_width": cv.positive_int, + "border_width": lvalid.lv_positive_int, "clip_corner": lvalid.lv_bool, "color_filter_opa": lvalid.opacity, "height": lvalid.size, @@ -134,11 +134,11 @@ STYLE_PROPS = { "pad_right": lvalid.pixels, "pad_top": lvalid.pixels, "shadow_color": lvalid.lv_color, - "shadow_ofs_x": cv.int_, - "shadow_ofs_y": cv.int_, + "shadow_ofs_x": lvalid.lv_int, + "shadow_ofs_y": lvalid.lv_int, "shadow_opa": lvalid.opacity, - "shadow_spread": cv.int_, - "shadow_width": cv.positive_int, + "shadow_spread": lvalid.lv_int, + "shadow_width": lvalid.lv_positive_int, "text_align": df.LvConstant( "LV_TEXT_ALIGN_", "LEFT", "CENTER", "RIGHT", "AUTO" ).one_of, @@ -150,7 +150,7 @@ STYLE_PROPS = { "text_letter_space": cv.positive_int, "text_line_space": cv.positive_int, "text_opa": lvalid.opacity, - "transform_angle": lvalid.angle, + "transform_angle": lvalid.lv_angle, "transform_height": lvalid.pixels_or_percent, "transform_pivot_x": lvalid.pixels_or_percent, "transform_pivot_y": lvalid.pixels_or_percent, diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 7fd824a87b..4962a71596 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -323,6 +323,13 @@ lvgl: id: button_button width: 20% height: 10% + transform_angle: !lambda return 180*100; + arc_width: !lambda return 4; + border_width: !lambda return 6; + shadow_ofs_x: !lambda return 6; + shadow_ofs_y: !lambda return 6; + shadow_spread: !lambda return 6; + shadow_width: !lambda return 6; pressed: bg_color: light_blue checkable: true From dd8d25e43f6d30f93391aeee207a912dd52907d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Wed, 23 Oct 2024 05:23:10 +0200 Subject: [PATCH 2553/2607] i2c_device (#7641) --- CODEOWNERS | 1 + esphome/components/i2c_device/__init__.py | 26 +++++++++++++++++++ esphome/components/i2c_device/i2c_device.cpp | 17 ++++++++++++ esphome/components/i2c_device/i2c_device.h | 18 +++++++++++++ .../components/i2c_device/test.esp32-ard.yaml | 8 ++++++ .../i2c_device/test.esp32-c3-ard.yaml | 8 ++++++ .../i2c_device/test.esp32-c3-idf.yaml | 8 ++++++ .../components/i2c_device/test.esp32-idf.yaml | 8 ++++++ .../i2c_device/test.esp8266-ard.yaml | 8 ++++++ .../i2c_device/test.rp2040-ard.yaml | 8 ++++++ 10 files changed, 110 insertions(+) create mode 100644 esphome/components/i2c_device/__init__.py create mode 100644 esphome/components/i2c_device/i2c_device.cpp create mode 100644 esphome/components/i2c_device/i2c_device.h create mode 100644 tests/components/i2c_device/test.esp32-ard.yaml create mode 100644 tests/components/i2c_device/test.esp32-c3-ard.yaml create mode 100644 tests/components/i2c_device/test.esp32-c3-idf.yaml create mode 100644 tests/components/i2c_device/test.esp32-idf.yaml create mode 100644 tests/components/i2c_device/test.esp8266-ard.yaml create mode 100644 tests/components/i2c_device/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 53300d6740..616b18293d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -198,6 +198,7 @@ esphome/components/htu31d/* @betterengineering esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hyt271/* @Philippe12 esphome/components/i2c/* @esphome/core +esphome/components/i2c_device/* @gabest11 esphome/components/i2s_audio/* @jesserockz esphome/components/i2s_audio/media_player/* @jesserockz esphome/components/i2s_audio/microphone/* @jesserockz diff --git a/esphome/components/i2c_device/__init__.py b/esphome/components/i2c_device/__init__.py new file mode 100644 index 0000000000..e145ba56f8 --- /dev/null +++ b/esphome/components/i2c_device/__init__.py @@ -0,0 +1,26 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from esphome.const import CONF_ID + +DEPENDENCIES = ["i2c"] +CODEOWNERS = ["@gabest11"] +MULTI_CONF = True + +i2c_device_ns = cg.esphome_ns.namespace("i2c_device") + +I2CDeviceComponent = i2c_device_ns.class_( + "I2CDeviceComponent", cg.Component, i2c.I2CDevice +) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_ID): cv.declare_id(I2CDeviceComponent), + } +).extend(i2c.i2c_device_schema(None)) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/i2c_device/i2c_device.cpp b/esphome/components/i2c_device/i2c_device.cpp new file mode 100644 index 0000000000..455c68fbed --- /dev/null +++ b/esphome/components/i2c_device/i2c_device.cpp @@ -0,0 +1,17 @@ +#include "i2c_device.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include + +namespace esphome { +namespace i2c_device { + +static const char *const TAG = "i2c_device"; + +void I2CDeviceComponent::dump_config() { + ESP_LOGCONFIG(TAG, "I2CDevice"); + LOG_I2C_DEVICE(this); +} + +} // namespace i2c_device +} // namespace esphome diff --git a/esphome/components/i2c_device/i2c_device.h b/esphome/components/i2c_device/i2c_device.h new file mode 100644 index 0000000000..ab118e3e89 --- /dev/null +++ b/esphome/components/i2c_device/i2c_device.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace i2c_device { + +class I2CDeviceComponent : public Component, public i2c::I2CDevice { + public: + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + protected: +}; + +} // namespace i2c_device +} // namespace esphome diff --git a/tests/components/i2c_device/test.esp32-ard.yaml b/tests/components/i2c_device/test.esp32-ard.yaml new file mode 100644 index 0000000000..6169d113f8 --- /dev/null +++ b/tests/components/i2c_device/test.esp32-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 16 + sda: 17 + +i2c_device: + id: i2cdev + address: 0x2C diff --git a/tests/components/i2c_device/test.esp32-c3-ard.yaml b/tests/components/i2c_device/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..5d53d12208 --- /dev/null +++ b/tests/components/i2c_device/test.esp32-c3-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 + +i2c_device: + id: i2cdev + address: 0x2C diff --git a/tests/components/i2c_device/test.esp32-c3-idf.yaml b/tests/components/i2c_device/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..5d53d12208 --- /dev/null +++ b/tests/components/i2c_device/test.esp32-c3-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 + +i2c_device: + id: i2cdev + address: 0x2C diff --git a/tests/components/i2c_device/test.esp32-idf.yaml b/tests/components/i2c_device/test.esp32-idf.yaml new file mode 100644 index 0000000000..6169d113f8 --- /dev/null +++ b/tests/components/i2c_device/test.esp32-idf.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 16 + sda: 17 + +i2c_device: + id: i2cdev + address: 0x2C diff --git a/tests/components/i2c_device/test.esp8266-ard.yaml b/tests/components/i2c_device/test.esp8266-ard.yaml new file mode 100644 index 0000000000..5d53d12208 --- /dev/null +++ b/tests/components/i2c_device/test.esp8266-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 + +i2c_device: + id: i2cdev + address: 0x2C diff --git a/tests/components/i2c_device/test.rp2040-ard.yaml b/tests/components/i2c_device/test.rp2040-ard.yaml new file mode 100644 index 0000000000..5d53d12208 --- /dev/null +++ b/tests/components/i2c_device/test.rp2040-ard.yaml @@ -0,0 +1,8 @@ +i2c: + - id: i2c_i2c + scl: 5 + sda: 4 + +i2c_device: + id: i2cdev + address: 0x2C From fdebf041967549866f438431284c0690bec3d6da Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 23 Oct 2024 13:25:31 -0400 Subject: [PATCH 2554/2607] [voice_assistant] Bugfix: Fix crash on start (#7662) --- .../voice_assistant/voice_assistant.cpp | 54 +++++++++++-------- .../voice_assistant/voice_assistant.h | 6 +-- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 0b53e74ba3..6f164f69d3 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -433,16 +433,18 @@ void VoiceAssistant::loop() { #ifdef USE_SPEAKER void VoiceAssistant::write_speaker_() { - if (this->speaker_buffer_size_ > 0) { - size_t write_chunk = std::min(this->speaker_buffer_size_, 4 * 1024); - size_t written = this->speaker_->play(this->speaker_buffer_, write_chunk); - if (written > 0) { - memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); - this->speaker_buffer_size_ -= written; - this->speaker_buffer_index_ -= written; - this->set_timeout("speaker-timeout", 5000, [this]() { this->speaker_->stop(); }); - } else { - ESP_LOGV(TAG, "Speaker buffer full, trying again next loop"); + if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) { + if (this->speaker_buffer_size_ > 0) { + size_t write_chunk = std::min(this->speaker_buffer_size_, 4 * 1024); + size_t written = this->speaker_->play(this->speaker_buffer_, write_chunk); + if (written > 0) { + memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); + this->speaker_buffer_size_ -= written; + this->speaker_buffer_index_ -= written; + this->set_timeout("speaker-timeout", 5000, [this]() { this->speaker_->stop(); }); + } else { + ESP_LOGV(TAG, "Speaker buffer full, trying again next loop"); + } } } } @@ -772,16 +774,20 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { #ifdef USE_SPEAKER - this->wait_for_stream_end_ = true; - ESP_LOGD(TAG, "TTS stream start"); - this->defer([this] { this->tts_stream_start_trigger_->trigger(); }); + if (this->speaker_ != nullptr) { + this->wait_for_stream_end_ = true; + ESP_LOGD(TAG, "TTS stream start"); + this->defer([this] { this->tts_stream_start_trigger_->trigger(); }); + } #endif break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { #ifdef USE_SPEAKER - this->stream_ended_ = true; - ESP_LOGD(TAG, "TTS stream end"); + if (this->speaker_ != nullptr) { + this->stream_ended_ = true; + ESP_LOGD(TAG, "TTS stream end"); + } #endif break; } @@ -802,14 +808,16 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { #ifdef USE_SPEAKER // We should never get to this function if there is no speaker anyway - if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { - memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); - this->speaker_buffer_index_ += msg.data.length(); - this->speaker_buffer_size_ += msg.data.length(); - this->speaker_bytes_received_ += msg.data.length(); - ESP_LOGV(TAG, "Received audio: %u bytes from API", msg.data.length()); - } else { - ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); + if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) { + if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { + memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); + this->speaker_buffer_index_ += msg.data.length(); + this->speaker_buffer_size_ += msg.data.length(); + this->speaker_bytes_received_ += msg.data.length(); + ESP_LOGV(TAG, "Received audio: %u bytes from API", msg.data.length()); + } else { + ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); + } } #endif } diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 870e2acdaa..0016d3157c 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -250,7 +250,7 @@ class VoiceAssistant : public Component { #ifdef USE_SPEAKER void write_speaker_(); speaker::Speaker *speaker_{nullptr}; - uint8_t *speaker_buffer_; + uint8_t *speaker_buffer_{nullptr}; size_t speaker_buffer_index_{0}; size_t speaker_buffer_size_{0}; size_t speaker_bytes_received_{0}; @@ -282,8 +282,8 @@ class VoiceAssistant : public Component { float volume_multiplier_; uint32_t conversation_timeout_; - uint8_t *send_buffer_; - int16_t *input_buffer_; + uint8_t *send_buffer_{nullptr}; + int16_t *input_buffer_{nullptr}; bool continuous_{false}; bool silence_detection_; From 833565feb985e91c9512774a363ea2e5ca79d267 Mon Sep 17 00:00:00 2001 From: Kyle Cascade Date: Mon, 21 Oct 2024 21:11:23 -0700 Subject: [PATCH 2555/2607] Humanized the missing MQTT log topic error message (#7634) --- esphome/mqtt.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/mqtt.py b/esphome/mqtt.py index c1c45799cc..d55fb0202d 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -209,6 +209,12 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None): elif CONF_MQTT in config: conf = config[CONF_MQTT] if CONF_LOG_TOPIC in conf: + if config[CONF_MQTT][CONF_LOG_TOPIC] is None: + _LOGGER.error("MQTT log topic set to null, can't start MQTT logs") + return 1 + if CONF_TOPIC not in config[CONF_MQTT][CONF_LOG_TOPIC]: + _LOGGER.error("MQTT log topic not available, can't start MQTT logs") + return 1 topic = config[CONF_MQTT][CONF_LOG_TOPIC][CONF_TOPIC] elif CONF_TOPIC_PREFIX in config[CONF_MQTT]: topic = f"{config[CONF_MQTT][CONF_TOPIC_PREFIX]}/debug" From 8d90d256bf2518c46676a0a7dfe37ef3dd1868c8 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:16:55 +1100 Subject: [PATCH 2556/2607] [lvgl] Some properties were not templatable (Bugfix) (#7655) --- esphome/components/lvgl/lv_validation.py | 4 ++++ esphome/components/lvgl/schemas.py | 14 +++++++------- tests/components/lvgl/lvgl-package.yaml | 7 +++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index fd840cc417..a58fbc33e0 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -267,6 +267,9 @@ def angle(value): return int(cv.float_range(0.0, 360.0)(cv.angle(value)) * 10) +lv_angle = LValidator(angle, uint32) + + @schema_extractor("one_of") def size_validator(value): """A size in one axis - one of "size_content", a number (pixels) or a percentage""" @@ -403,6 +406,7 @@ class TextValidator(LValidator): lv_text = TextValidator() lv_float = LValidator(cv.float_, cg.float_) lv_int = LValidator(cv.int_, cg.int_) +lv_positive_int = LValidator(cv.positive_int, cg.int_) lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255)) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 780057623a..0d5a609a2d 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -91,7 +91,7 @@ STYLE_PROPS = { "arc_opa": lvalid.opacity, "arc_color": lvalid.lv_color, "arc_rounded": lvalid.lv_bool, - "arc_width": cv.positive_int, + "arc_width": lvalid.lv_positive_int, "anim_time": lvalid.lv_milliseconds, "bg_color": lvalid.lv_color, "bg_grad": lv_gradient, @@ -111,7 +111,7 @@ STYLE_PROPS = { "border_side": df.LvConstant( "LV_BORDER_SIDE_", "NONE", "TOP", "BOTTOM", "LEFT", "RIGHT", "INTERNAL" ).several_of, - "border_width": cv.positive_int, + "border_width": lvalid.lv_positive_int, "clip_corner": lvalid.lv_bool, "color_filter_opa": lvalid.opacity, "height": lvalid.size, @@ -134,11 +134,11 @@ STYLE_PROPS = { "pad_right": lvalid.pixels, "pad_top": lvalid.pixels, "shadow_color": lvalid.lv_color, - "shadow_ofs_x": cv.int_, - "shadow_ofs_y": cv.int_, + "shadow_ofs_x": lvalid.lv_int, + "shadow_ofs_y": lvalid.lv_int, "shadow_opa": lvalid.opacity, - "shadow_spread": cv.int_, - "shadow_width": cv.positive_int, + "shadow_spread": lvalid.lv_int, + "shadow_width": lvalid.lv_positive_int, "text_align": df.LvConstant( "LV_TEXT_ALIGN_", "LEFT", "CENTER", "RIGHT", "AUTO" ).one_of, @@ -150,7 +150,7 @@ STYLE_PROPS = { "text_letter_space": cv.positive_int, "text_line_space": cv.positive_int, "text_opa": lvalid.opacity, - "transform_angle": lvalid.angle, + "transform_angle": lvalid.lv_angle, "transform_height": lvalid.pixels_or_percent, "transform_pivot_x": lvalid.pixels_or_percent, "transform_pivot_y": lvalid.pixels_or_percent, diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 1770c1bfbc..2e05cf10d3 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -299,6 +299,13 @@ lvgl: id: button_button width: 20% height: 10% + transform_angle: !lambda return 180*100; + arc_width: !lambda return 4; + border_width: !lambda return 6; + shadow_ofs_x: !lambda return 6; + shadow_ofs_y: !lambda return 6; + shadow_spread: !lambda return 6; + shadow_width: !lambda return 6; pressed: bg_color: light_blue checkable: true From 156ad773c91edca8b14a8518363287e027ef8147 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 23 Oct 2024 13:25:31 -0400 Subject: [PATCH 2557/2607] [voice_assistant] Bugfix: Fix crash on start (#7662) --- .../voice_assistant/voice_assistant.cpp | 54 +++++++++++-------- .../voice_assistant/voice_assistant.h | 6 +-- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 0b53e74ba3..6f164f69d3 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -433,16 +433,18 @@ void VoiceAssistant::loop() { #ifdef USE_SPEAKER void VoiceAssistant::write_speaker_() { - if (this->speaker_buffer_size_ > 0) { - size_t write_chunk = std::min(this->speaker_buffer_size_, 4 * 1024); - size_t written = this->speaker_->play(this->speaker_buffer_, write_chunk); - if (written > 0) { - memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); - this->speaker_buffer_size_ -= written; - this->speaker_buffer_index_ -= written; - this->set_timeout("speaker-timeout", 5000, [this]() { this->speaker_->stop(); }); - } else { - ESP_LOGV(TAG, "Speaker buffer full, trying again next loop"); + if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) { + if (this->speaker_buffer_size_ > 0) { + size_t write_chunk = std::min(this->speaker_buffer_size_, 4 * 1024); + size_t written = this->speaker_->play(this->speaker_buffer_, write_chunk); + if (written > 0) { + memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written); + this->speaker_buffer_size_ -= written; + this->speaker_buffer_index_ -= written; + this->set_timeout("speaker-timeout", 5000, [this]() { this->speaker_->stop(); }); + } else { + ESP_LOGV(TAG, "Speaker buffer full, trying again next loop"); + } } } } @@ -772,16 +774,20 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { } case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: { #ifdef USE_SPEAKER - this->wait_for_stream_end_ = true; - ESP_LOGD(TAG, "TTS stream start"); - this->defer([this] { this->tts_stream_start_trigger_->trigger(); }); + if (this->speaker_ != nullptr) { + this->wait_for_stream_end_ = true; + ESP_LOGD(TAG, "TTS stream start"); + this->defer([this] { this->tts_stream_start_trigger_->trigger(); }); + } #endif break; } case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: { #ifdef USE_SPEAKER - this->stream_ended_ = true; - ESP_LOGD(TAG, "TTS stream end"); + if (this->speaker_ != nullptr) { + this->stream_ended_ = true; + ESP_LOGD(TAG, "TTS stream end"); + } #endif break; } @@ -802,14 +808,16 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { void VoiceAssistant::on_audio(const api::VoiceAssistantAudio &msg) { #ifdef USE_SPEAKER // We should never get to this function if there is no speaker anyway - if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { - memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); - this->speaker_buffer_index_ += msg.data.length(); - this->speaker_buffer_size_ += msg.data.length(); - this->speaker_bytes_received_ += msg.data.length(); - ESP_LOGV(TAG, "Received audio: %u bytes from API", msg.data.length()); - } else { - ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); + if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) { + if (this->speaker_buffer_index_ + msg.data.length() < SPEAKER_BUFFER_SIZE) { + memcpy(this->speaker_buffer_ + this->speaker_buffer_index_, msg.data.data(), msg.data.length()); + this->speaker_buffer_index_ += msg.data.length(); + this->speaker_buffer_size_ += msg.data.length(); + this->speaker_bytes_received_ += msg.data.length(); + ESP_LOGV(TAG, "Received audio: %u bytes from API", msg.data.length()); + } else { + ESP_LOGE(TAG, "Cannot receive audio, buffer is full"); + } } #endif } diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index 870e2acdaa..0016d3157c 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -250,7 +250,7 @@ class VoiceAssistant : public Component { #ifdef USE_SPEAKER void write_speaker_(); speaker::Speaker *speaker_{nullptr}; - uint8_t *speaker_buffer_; + uint8_t *speaker_buffer_{nullptr}; size_t speaker_buffer_index_{0}; size_t speaker_buffer_size_{0}; size_t speaker_bytes_received_{0}; @@ -282,8 +282,8 @@ class VoiceAssistant : public Component { float volume_multiplier_; uint32_t conversation_timeout_; - uint8_t *send_buffer_; - int16_t *input_buffer_; + uint8_t *send_buffer_{nullptr}; + int16_t *input_buffer_{nullptr}; bool continuous_{false}; bool silence_detection_; From 127acfde6482ebb7e44894af0c17660263166fce Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 24 Oct 2024 07:15:40 +1300 Subject: [PATCH 2558/2607] Bump version to 2024.10.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5fa457b25a..032a4c79a0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.10.1" +__version__ = "2024.10.2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 4289e00ad0ee3f466a60d9044c97157a8070a047 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 08:06:45 +1300 Subject: [PATCH 2559/2607] Bump actions/cache from 4.1.1 to 4.1.2 in /.github/actions/restore-python (#7659) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 1f5812691e..c6978f68c5 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v4.1.1 + uses: actions/cache/restore@v4.1.2 with: path: venv # yamllint disable-line rule:line-length From 2feffddc550c0241aede210bb273b8e0001084f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 08:06:53 +1300 Subject: [PATCH 2560/2607] Bump actions/cache from 4.1.1 to 4.1.2 (#7660) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 178b914a1c..0d2f1c877d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v4.1.1 + uses: actions/cache@v4.1.2 with: path: venv # yamllint disable-line rule:line-length @@ -302,14 +302,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@v4.1.1 + uses: actions/cache@v4.1.2 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@v4.1.1 + uses: actions/cache/restore@v4.1.2 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} From bff0e81ed3863ee960d1612fd64bec78fe34c03b Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 23 Oct 2024 16:37:38 -0400 Subject: [PATCH 2561/2607] [speaker, i2s_audio] Support audio_dac component, mute actions, and improved logging (#7664) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 4 +- .../components/i2s_audio/speaker/__init__.py | 2 +- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 72 +++++++++++++++---- .../i2s_audio/speaker/i2s_audio_speaker.h | 14 ++-- esphome/components/speaker/__init__.py | 31 ++++++-- esphome/components/speaker/automation.h | 20 ++++++ esphome/components/speaker/speaker.h | 42 ++++++++++- tests/components/speaker/test.esp32-ard.yaml | 2 + .../components/speaker/test.esp32-c3-ard.yaml | 2 + .../components/speaker/test.esp32-c3-idf.yaml | 2 + tests/components/speaker/test.esp32-idf.yaml | 15 +++- 11 files changed, 177 insertions(+), 29 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 616b18293d..f96e43d5b7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -202,7 +202,7 @@ esphome/components/i2c_device/* @gabest11 esphome/components/i2s_audio/* @jesserockz esphome/components/i2s_audio/media_player/* @jesserockz esphome/components/i2s_audio/microphone/* @jesserockz -esphome/components/i2s_audio/speaker/* @jesserockz +esphome/components/i2s_audio/speaker/* @jesserockz @kahrendt esphome/components/iaqcore/* @yozik04 esphome/components/ili9xxx/* @clydebarrow @nielsnl68 esphome/components/improv_base/* @esphome/core @@ -377,7 +377,7 @@ esphome/components/smt100/* @piechade esphome/components/sn74hc165/* @jesserockz esphome/components/socket/* @esphome/core esphome/components/sonoff_d1/* @anatoly-savchenkov -esphome/components/speaker/* @jesserockz +esphome/components/speaker/* @jesserockz @kahrendt esphome/components/spi/* @clydebarrow @esphome/core esphome/components/spi_device/* @clydebarrow esphome/components/spi_led_strip/* @clydebarrow diff --git a/esphome/components/i2s_audio/speaker/__init__.py b/esphome/components/i2s_audio/speaker/__init__.py index 9fdaced64c..dd43d6cb39 100644 --- a/esphome/components/i2s_audio/speaker/__init__.py +++ b/esphome/components/i2s_audio/speaker/__init__.py @@ -17,7 +17,7 @@ from .. import ( ) AUTO_LOAD = ["audio"] -CODEOWNERS = ["@jesserockz"] +CODEOWNERS = ["@jesserockz", "@kahrendt"] DEPENDENCIES = ["i2s_audio"] I2SAudioSpeaker = i2s_audio_ns.class_( diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 4fc489d0a3..cf6c3bbbba 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -32,6 +32,7 @@ enum SpeakerEventGroupBits : uint32_t { STATE_RUNNING = (1 << 11), STATE_STOPPING = (1 << 12), STATE_STOPPED = (1 << 13), + ERR_INVALID_FORMAT = (1 << 14), ERR_TASK_FAILED_TO_START = (1 << 15), ERR_ESP_INVALID_STATE = (1 << 16), ERR_ESP_INVALID_ARG = (1 << 17), @@ -104,16 +105,6 @@ void I2SAudioSpeaker::setup() { void I2SAudioSpeaker::loop() { uint32_t event_group_bits = xEventGroupGetBits(this->event_group_); - if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) { - this->status_set_error("Failed to start speaker task"); - } - - if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) { - uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS; - ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits))); - this->status_set_warning(); - } - if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) { ESP_LOGD(TAG, "Starting Speaker"); this->state_ = speaker::STATE_STARTING; @@ -139,12 +130,64 @@ void I2SAudioSpeaker::loop() { this->speaker_task_handle_ = nullptr; } } + + if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) { + this->status_set_error("Failed to start speaker task"); + xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START); + } + + if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) { + this->status_set_error("Failed to adjust I2S bus to match the incoming audio"); + ESP_LOGE(TAG, + "Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8, + this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels, + this->audio_stream_info_.bits_per_sample); + } + + if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) { + uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS; + ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits))); + this->status_set_warning(); + } } void I2SAudioSpeaker::set_volume(float volume) { this->volume_ = volume; - ssize_t decibel_index = remap(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1); - this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index]; +#ifdef USE_AUDIO_DAC + if (this->audio_dac_ != nullptr) { + if (volume > 0.0) { + this->audio_dac_->set_mute_off(); + } + this->audio_dac_->set_volume(volume); + } else +#endif + { + // Fallback to software volume control by using a Q15 fixed point scaling factor + ssize_t decibel_index = remap(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1); + this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index]; + } +} + +void I2SAudioSpeaker::set_mute_state(bool mute_state) { + this->mute_state_ = mute_state; +#ifdef USE_AUDIO_DAC + if (this->audio_dac_) { + if (mute_state) { + this->audio_dac_->set_mute_on(); + } else { + this->audio_dac_->set_mute_off(); + } + } else +#endif + { + if (mute_state) { + // Fallback to software volume control and scale by 0 + this->q15_volume_factor_ = 0; + } else { + // Revert to previous volume when unmuting + this->set_volume(this->volume_); + } + } } size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) { @@ -275,6 +318,9 @@ void I2SAudioSpeaker::speaker_task(void *params) { i2s_zero_dma_buffer(this_speaker->parent_->get_port()); } } + } else { + // Couldn't configure the I2S port to be compatible with the incoming audio + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT); } i2s_zero_dma_buffer(this_speaker->parent_->get_port()); @@ -288,7 +334,7 @@ void I2SAudioSpeaker::speaker_task(void *params) { } void I2SAudioSpeaker::start() { - if (this->is_failed()) + if (this->is_failed() || this->status_has_error()) return; if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING)) return; diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 245f97d1e7..3c512d4d4d 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -49,11 +49,17 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp bool has_buffered_data() const override; - /// @brief Sets the volume of the speaker. It is implemented as a software volume control. - /// Overrides the default setter to convert the floating point volume to a Q15 fixed-point factor. - /// @param volume + /// @brief Sets the volume of the speaker. Uses the speaker's configured audio dac component. If unavailble, it is + /// implemented as a software volume control. Overrides the default setter to convert the floating point volume to a + /// Q15 fixed-point factor. + /// @param volume between 0.0 and 1.0 void set_volume(float volume) override; - float get_volume() override { return this->volume_; } + + /// @brief Mutes or unmute the speaker. Uses the speaker's configured audio dac component. If unavailble, it is + /// implemented as a software volume control. Overrides the default setter to convert the floating point volume to a + /// Q15 fixed-point factor. + /// @param mute_state true for muting, false for unmuting + void set_mute_state(bool mute_state) override; protected: /// @brief Function for the FreeRTOS task handling audio output. diff --git a/esphome/components/speaker/__init__.py b/esphome/components/speaker/__init__.py index 1bbc0b02ef..7a668dc2f3 100644 --- a/esphome/components/speaker/__init__.py +++ b/esphome/components/speaker/__init__.py @@ -1,15 +1,18 @@ from esphome import automation from esphome.automation import maybe_simple_id import esphome.codegen as cg +from esphome.components import audio_dac import esphome.config_validation as cv from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME from esphome.core import CORE from esphome.coroutine import coroutine_with_priority -CODEOWNERS = ["@jesserockz"] +CODEOWNERS = ["@jesserockz", "@kahrendt"] IS_PLATFORM_COMPONENT = True +CONF_AUDIO_DAC = "audio_dac" + speaker_ns = cg.esphome_ns.namespace("speaker") Speaker = speaker_ns.class_("Speaker") @@ -26,6 +29,12 @@ FinishAction = speaker_ns.class_( VolumeSetAction = speaker_ns.class_( "VolumeSetAction", automation.Action, cg.Parented.template(Speaker) ) +MuteOnAction = speaker_ns.class_( + "MuteOnAction", automation.Action, cg.Parented.template(Speaker) +) +MuteOffAction = speaker_ns.class_( + "MuteOffAction", automation.Action, cg.Parented.template(Speaker) +) IsPlayingCondition = speaker_ns.class_("IsPlayingCondition", automation.Condition) @@ -33,7 +42,9 @@ IsStoppedCondition = speaker_ns.class_("IsStoppedCondition", automation.Conditio async def setup_speaker_core_(var, config): - pass + if audio_dac_config := config.get(CONF_AUDIO_DAC): + aud_dac = await cg.get_variable(audio_dac_config) + cg.add(var.set_audio_dac(aud_dac)) async def register_speaker(var, config): @@ -42,8 +53,11 @@ async def register_speaker(var, config): await setup_speaker_core_(var, config) -SPEAKER_SCHEMA = cv.Schema({}) - +SPEAKER_SCHEMA = cv.Schema( + { + cv.Optional(CONF_AUDIO_DAC): cv.use_id(audio_dac.AudioDac), + } +) SPEAKER_AUTOMATION_SCHEMA = maybe_simple_id({cv.GenerateID(): cv.use_id(Speaker)}) @@ -113,6 +127,15 @@ async def speaker_volume_set_action(config, action_id, template_arg, args): return var +@automation.register_action( + "speaker.mute_off", MuteOffAction, SPEAKER_AUTOMATION_SCHEMA +) +@automation.register_action("speaker.mute_on", MuteOnAction, SPEAKER_AUTOMATION_SCHEMA) +async def speaker_mute_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + @coroutine_with_priority(100.0) async def to_code(config): cg.add_global(speaker_ns.using) diff --git a/esphome/components/speaker/automation.h b/esphome/components/speaker/automation.h index 9efda011f2..c083796eea 100644 --- a/esphome/components/speaker/automation.h +++ b/esphome/components/speaker/automation.h @@ -39,6 +39,26 @@ template class VolumeSetAction : public Action, public Pa void play(Ts... x) override { this->parent_->set_volume(this->volume_.value(x...)); } }; +template class MuteOnAction : public Action { + public: + explicit MuteOnAction(Speaker *speaker) : speaker_(speaker) {} + + void play(Ts... x) override { this->speaker_->set_mute_state(true); } + + protected: + Speaker *speaker_; +}; + +template class MuteOffAction : public Action { + public: + explicit MuteOffAction(Speaker *speaker) : speaker_(speaker) {} + + void play(Ts... x) override { this->speaker_->set_mute_state(false); } + + protected: + Speaker *speaker_; +}; + template class StopAction : public Action, public Parented { public: void play(Ts... x) override { this->parent_->stop(); } diff --git a/esphome/components/speaker/speaker.h b/esphome/components/speaker/speaker.h index 9390e4edb7..96843e2d5a 100644 --- a/esphome/components/speaker/speaker.h +++ b/esphome/components/speaker/speaker.h @@ -8,7 +8,12 @@ #include #endif +#include "esphome/core/defines.h" + #include "esphome/components/audio/audio.h" +#ifdef USE_AUDIO_DAC +#include "esphome/components/audio_dac/audio_dac.h" +#endif namespace esphome { namespace speaker { @@ -56,9 +61,35 @@ class Speaker { bool is_running() const { return this->state_ == STATE_RUNNING; } bool is_stopped() const { return this->state_ == STATE_STOPPED; } - // Volume control must be implemented by each speaker component, otherwise it will have no effect. - virtual void set_volume(float volume) { this->volume_ = volume; }; - virtual float get_volume() { return this->volume_; } + // Volume control is handled by a configured audio dac component. Individual speaker components can + // override and implement in software if an audio dac isn't available. + virtual void set_volume(float volume) { + this->volume_ = volume; +#ifdef USE_AUDIO_DAC + if (this->audio_dac_ != nullptr) { + this->audio_dac_->set_volume(volume); + } +#endif + }; + float get_volume() { return this->volume_; } + + virtual void set_mute_state(bool mute_state) { + this->mute_state_ = mute_state; +#ifdef USE_AUDIO_DAC + if (this->audio_dac_) { + if (mute_state) { + this->audio_dac_->set_mute_on(); + } else { + this->audio_dac_->set_mute_off(); + } + } +#endif + } + bool get_mute_state() { return this->mute_state_; } + +#ifdef USE_AUDIO_DAC + void set_audio_dac(audio_dac::AudioDac *audio_dac) { this->audio_dac_ = audio_dac; } +#endif void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info) { this->audio_stream_info_ = audio_stream_info; @@ -68,6 +99,11 @@ class Speaker { State state_{STATE_STOPPED}; audio::AudioStreamInfo audio_stream_info_; float volume_{1.0f}; + bool mute_state_{false}; + +#ifdef USE_AUDIO_DAC + audio_dac::AudioDac *audio_dac_{nullptr}; +#endif }; } // namespace speaker diff --git a/tests/components/speaker/test.esp32-ard.yaml b/tests/components/speaker/test.esp32-ard.yaml index 9a24d00f68..396b4d95ea 100644 --- a/tests/components/speaker/test.esp32-ard.yaml +++ b/tests/components/speaker/test.esp32-ard.yaml @@ -1,6 +1,8 @@ esphome: on_boot: then: + - speaker.mute_on: + - speaker.mute_off: - if: condition: speaker.is_stopped then: diff --git a/tests/components/speaker/test.esp32-c3-ard.yaml b/tests/components/speaker/test.esp32-c3-ard.yaml index f28014337c..636aeba766 100644 --- a/tests/components/speaker/test.esp32-c3-ard.yaml +++ b/tests/components/speaker/test.esp32-c3-ard.yaml @@ -1,6 +1,8 @@ esphome: on_boot: then: + - speaker.mute_on: + - speaker.mute_off: - if: condition: speaker.is_stopped then: diff --git a/tests/components/speaker/test.esp32-c3-idf.yaml b/tests/components/speaker/test.esp32-c3-idf.yaml index f28014337c..636aeba766 100644 --- a/tests/components/speaker/test.esp32-c3-idf.yaml +++ b/tests/components/speaker/test.esp32-c3-idf.yaml @@ -1,6 +1,8 @@ esphome: on_boot: then: + - speaker.mute_on: + - speaker.mute_off: - if: condition: speaker.is_stopped then: diff --git a/tests/components/speaker/test.esp32-idf.yaml b/tests/components/speaker/test.esp32-idf.yaml index 9a24d00f68..b69440b133 100644 --- a/tests/components/speaker/test.esp32-idf.yaml +++ b/tests/components/speaker/test.esp32-idf.yaml @@ -1,6 +1,8 @@ esphome: on_boot: then: + - speaker.mute_on: + - speaker.mute_off: - if: condition: speaker.is_stopped then: @@ -17,8 +19,17 @@ i2s_audio: i2s_bclk_pin: 17 i2s_mclk_pin: 15 +i2c: + scl: 12 + sda: 10 + +audio_dac: + - platform: aic3204 + id: internal_dac + speaker: - platform: i2s_audio - id: speaker_id + id: speaker_with_audio_dac_id + audio_dac: internal_dac dac_type: external - i2s_dout_pin: 13 + i2s_dout_pin: 14 From 9acc21e81a393a409236f29aeaf195cedb1ea472 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Wed, 23 Oct 2024 23:04:59 +0200 Subject: [PATCH 2562/2607] unified way how all platforms handle copy_files (#7614) Co-authored-by: Tomasz Duda --- esphome/components/rp2040/__init__.py | 9 ++++++--- esphome/writer.py | 25 +++++++------------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index f59962477f..d612631a4c 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -17,7 +17,7 @@ from esphome.const import ( PLATFORM_RP2040, ) from esphome.core import CORE, EsphomeError, coroutine_with_priority -from esphome.helpers import copy_file_if_changed, mkdir_p, write_file +from esphome.helpers import copy_file_if_changed, mkdir_p, write_file, read_file from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns @@ -230,11 +230,14 @@ def generate_pio_files() -> bool: # Called by writer.py -def copy_files() -> bool: +def copy_files(): dir = os.path.dirname(__file__) post_build_file = os.path.join(dir, "post_build.py.script") copy_file_if_changed( post_build_file, CORE.relative_build_path("post_build.py"), ) - return generate_pio_files() + if generate_pio_files(): + path = CORE.relative_src_path("esphome.h") + content = read_file(path).rstrip("\n") + write_file(path, content + '\n#include "pio_includes.h"\n') diff --git a/esphome/writer.py b/esphome/writer.py index 79ee72996c..90446ae4b1 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -1,3 +1,4 @@ +import importlib import logging import os from pathlib import Path @@ -299,25 +300,13 @@ def copy_src_tree(): CORE.relative_src_path("esphome", "core", "version.h"), generate_version_h() ) - if CORE.is_esp32: - from esphome.components.esp32 import copy_files - + platform = "esphome.components." + CORE.target_platform + try: + module = importlib.import_module(platform) + copy_files = getattr(module, "copy_files") copy_files() - - elif CORE.is_esp8266: - from esphome.components.esp8266 import copy_files - - copy_files() - - elif CORE.is_rp2040: - from esphome.components.rp2040 import copy_files - - (pio) = copy_files() - if pio: - write_file_if_changed( - CORE.relative_src_path("esphome.h"), - ESPHOME_H_FORMAT.format(include_s + '\n#include "pio_includes.h"'), - ) + except AttributeError: + pass def generate_defines_h(): From 5b5c2fe71b8307aa692d3def1268837a1b26de51 Mon Sep 17 00:00:00 2001 From: Aaron Solochek Date: Wed, 23 Oct 2024 17:25:53 -0700 Subject: [PATCH 2563/2607] updating ESP32 board definitions (#7650) --- esphome/components/esp32/boards.py | 200 ++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index 60abcd447c..02744ecb6f 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -103,6 +103,173 @@ ESP32_BOARD_PINS = { "LED": 13, "LED_BUILTIN": 13, }, + "adafruit_feather_esp32s3": { + "BUTTON": 0, + "A0": 18, + "A1": 17, + "A2": 16, + "A3": 15, + "A4": 14, + "A5": 8, + "SCK": 36, + "MOSI": 35, + "MISO": 37, + "RX": 38, + "TX": 39, + "SCL": 4, + "SDA": 3, + "NEOPIXEL": 33, + "PIN_NEOPIXEL": 33, + "NEOPIXEL_POWER": 21, + "I2C_POWER": 7, + "LED": 13, + "LED_BUILTIN": 13, + }, + "adafruit_feather_esp32s3_nopsram": { + "BUTTON": 0, + "A0": 18, + "A1": 17, + "A2": 16, + "A3": 15, + "A4": 14, + "A5": 8, + "SCK": 36, + "MOSI": 35, + "MISO": 37, + "RX": 38, + "TX": 39, + "SCL": 4, + "SDA": 3, + "NEOPIXEL": 33, + "PIN_NEOPIXEL": 33, + "NEOPIXEL_POWER": 21, + "I2C_POWER": 7, + "LED": 13, + "LED_BUILTIN": 13, + }, + "adafruit_feather_esp32s3_tft": { + "BUTTON": 0, + "A0": 18, + "A1": 17, + "A2": 16, + "A3": 15, + "A4": 14, + "A5": 8, + "SCK": 36, + "MOSI": 35, + "MISO": 37, + "RX": 2, + "TX": 1, + "SCL": 41, + "SDA": 42, + "NEOPIXEL": 33, + "PIN_NEOPIXEL": 33, + "NEOPIXEL_POWER": 34, + "TFT_I2C_POWER": 21, + "TFT_CS": 7, + "TFT_DC": 39, + "TFT_RESET": 40, + "TFT_BACKLIGHT": 45, + "LED": 13, + "LED_BUILTIN": 13, + }, + "adafruit_funhouse_esp32s2": { + "BUTTON_UP": 5, + "BUTTON_DOWN": 3, + "BUTTON_SELECT": 4, + "DOTSTAR_DATA": 14, + "DOTSTAR_CLOCK": 15, + "PIR_SENSE": 16, + "A0": 17, + "A1": 2, + "A2": 1, + "CAP6": 6, + "CAP7": 7, + "CAP8": 8, + "CAP9": 9, + "CAP10": 10, + "CAP11": 11, + "CAP12": 12, + "CAP13": 13, + "SPEAKER": 42, + "LED": 37, + "LIGHT": 18, + "TFT_MOSI": 35, + "TFT_SCK": 36, + "TFT_CS": 40, + "TFT_DC": 39, + "TFT_RESET": 41, + "TFT_BACKLIGHT": 21, + "RED_LED": 31, + "BUTTON": 0, + }, + "adafruit_itsybitsy_esp32": { + "A0": 25, + "A1": 26, + "A2": 4, + "A3": 38, + "A4": 37, + "A5": 36, + "SCK": 19, + "MOSI": 21, + "MISO": 22, + "SCL": 27, + "SDA": 15, + "TX": 20, + "RX": 8, + "NEOPIXEL": 0, + "PIN_NEOPIXEL": 0, + "NEOPIXEL_POWER": 2, + "BUTTON": 35, + }, + "adafruit_magtag29_esp32s2": { + "A1": 18, + "BUTTON_A": 15, + "BUTTON_B": 14, + "BUTTON_C": 12, + "BUTTON_D": 11, + "SDA": 33, + "SCL": 34, + "SPEAKER": 17, + "SPEAKER_ENABLE": 16, + "VOLTAGE_MONITOR": 4, + "ACCELEROMETER_INT": 9, + "ACCELEROMETER_INTERRUPT": 9, + "LIGHT": 3, + "NEOPIXEL": 1, + "PIN_NEOPIXEL": 1, + "NEOPIXEL_POWER": 21, + "EPD_BUSY": 5, + "EPD_RESET": 6, + "EPD_DC": 7, + "EPD_CS": 8, + "EPD_MOSI": 35, + "EPD_SCK": 36, + "EPD_MISO": 37, + "BUTTON": 0, + "LED": 13, + "LED_BUILTIN": 13, + }, + "adafruit_metro_esp32s2": { + "A0": 17, + "A1": 18, + "A2": 1, + "A3": 2, + "A4": 3, + "A5": 4, + "RX": 38, + "TX": 37, + "SCL": 34, + "SDA": 33, + "MISO": 37, + "SCK": 36, + "MOSI": 35, + "NEOPIXEL": 45, + "PIN_NEOPIXEL": 45, + "LED": 42, + "LED_BUILTIN": 42, + "BUTTON": 0, + }, "adafruit_qtpy_esp32c3": { "A0": 4, "A1": 3, @@ -141,6 +308,26 @@ ESP32_BOARD_PINS = { "BUTTON": 0, "SWITCH": 0, }, + "adafruit_qtpy_esp32s3_nopsram": { + "A0": 18, + "A1": 17, + "A2": 9, + "A3": 8, + "SDA": 7, + "SCL": 6, + "MOSI": 35, + "MISO": 37, + "SCK": 36, + "RX": 16, + "TX": 5, + "SDA1": 41, + "SCL1": 40, + "NEOPIXEL": 39, + "PIN_NEOPIXEL": 39, + "NEOPIXEL_POWER": 38, + "BUTTON": 0, + "SWITCH": 0, + }, "adafruit_qtpy_esp32": { "A0": 26, "A1": 25, @@ -1068,7 +1255,18 @@ ESP32_BOARD_PINS = { "_VBAT": 35, }, "wemosbat": {"LED": 16}, - "wesp32": {"MISO": 32, "SCL": 4, "SDA": 15}, + "wesp32": { + "MISO": 32, + "MOSI": 23, + "SCK": 18, + "SCL": 4, + "SDA": 15, + "MISO1": 12, + "MOSI1": 13, + "SCK1": 14, + "SCL1": 5, + "SDA1": 33, + }, "widora-air": { "A1": 39, "A2": 35, From ca5c73d170c57a256688f51c09b38dac70b1fe6e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 25 Oct 2024 07:55:14 +1300 Subject: [PATCH 2564/2607] Support ignoring discovered devices from the dashboard (#7665) --- esphome/dashboard/core.py | 25 ++++++++++++++++++++ esphome/dashboard/web_server.py | 42 +++++++++++++++++++++++++++++++++ esphome/storage_json.py | 4 ++++ 3 files changed, 71 insertions(+) diff --git a/esphome/dashboard/core.py b/esphome/dashboard/core.py index eec0777da6..563ca1506d 100644 --- a/esphome/dashboard/core.py +++ b/esphome/dashboard/core.py @@ -5,10 +5,14 @@ from collections.abc import Coroutine import contextlib from dataclasses import dataclass from functools import partial +import json import logging +from pathlib import Path import threading from typing import TYPE_CHECKING, Any, Callable +from esphome.storage_json import ignored_devices_storage_path + from ..zeroconf import DiscoveredImport from .dns import DNSCache from .entries import DashboardEntries @@ -20,6 +24,8 @@ if TYPE_CHECKING: _LOGGER = logging.getLogger(__name__) +IGNORED_DEVICES_STORAGE_PATH = "ignored-devices.json" + @dataclass class Event: @@ -74,6 +80,7 @@ class ESPHomeDashboard: "settings", "dns_cache", "_background_tasks", + "ignored_devices", ) def __init__(self) -> None: @@ -89,12 +96,30 @@ class ESPHomeDashboard: self.settings = DashboardSettings() self.dns_cache = DNSCache() self._background_tasks: set[asyncio.Task] = set() + self.ignored_devices: set[str] = set() async def async_setup(self) -> None: """Setup the dashboard.""" self.loop = asyncio.get_running_loop() self.ping_request = asyncio.Event() self.entries = DashboardEntries(self) + self.load_ignored_devices() + + def load_ignored_devices(self) -> None: + storage_path = Path(ignored_devices_storage_path()) + try: + with storage_path.open("r", encoding="utf-8") as f_handle: + data = json.load(f_handle) + self.ignored_devices = set(data.get("ignored_devices", set())) + except FileNotFoundError: + pass + + def save_ignored_devices(self) -> None: + storage_path = Path(ignored_devices_storage_path()) + with storage_path.open("w", encoding="utf-8") as f_handle: + json.dump( + {"ignored_devices": sorted(self.ignored_devices)}, indent=2, fp=f_handle + ) async def async_run(self) -> None: """Run the dashboard.""" diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index e4b7b8d342..1a8b2ab83a 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -541,6 +541,46 @@ class ImportRequestHandler(BaseHandler): self.finish() +class IgnoreDeviceRequestHandler(BaseHandler): + @authenticated + def post(self) -> None: + dashboard = DASHBOARD + try: + args = json.loads(self.request.body.decode()) + device_name = args["name"] + ignore = args["ignore"] + except (json.JSONDecodeError, KeyError): + self.set_status(400) + self.set_header("content-type", "application/json") + self.write(json.dumps({"error": "Invalid payload"})) + return + + ignored_device = next( + ( + res + for res in dashboard.import_result.values() + if res.device_name == device_name + ), + None, + ) + + if ignored_device is None: + self.set_status(404) + self.set_header("content-type", "application/json") + self.write(json.dumps({"error": "Device not found"})) + return + + if ignore: + dashboard.ignored_devices.add(ignored_device.device_name) + else: + dashboard.ignored_devices.discard(ignored_device.device_name) + + dashboard.save_ignored_devices() + + self.set_status(204) + self.finish() + + class DownloadListRequestHandler(BaseHandler): @authenticated @bind_config @@ -688,6 +728,7 @@ class ListDevicesHandler(BaseHandler): "project_name": res.project_name, "project_version": res.project_version, "network": res.network, + "ignored": res.device_name in dashboard.ignored_devices, } for res in dashboard.import_result.values() if res.device_name not in configured @@ -1156,6 +1197,7 @@ def make_app(debug=get_bool_env(ENV_DEV)) -> tornado.web.Application: (f"{rel}prometheus-sd", PrometheusServiceDiscoveryHandler), (f"{rel}boards/([a-z0-9]+)", BoardsRequestHandler), (f"{rel}version", EsphomeVersionHandler), + (f"{rel}ignore-device", IgnoreDeviceRequestHandler), ], **app_settings, ) diff --git a/esphome/storage_json.py b/esphome/storage_json.py index 2d12ee01a0..97cf9ceadd 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -28,6 +28,10 @@ def esphome_storage_path() -> str: return os.path.join(CORE.data_dir, "esphome.json") +def ignored_devices_storage_path() -> str: + return os.path.join(CORE.data_dir, "ignored-devices.json") + + def trash_storage_path() -> str: return CORE.relative_config_path("trash") From 4fa3c6915ca7aaba27d001415aee5b613db33565 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 25 Oct 2024 08:10:30 +1300 Subject: [PATCH 2565/2607] Bump esphome-dashboard to 20241025.0 (#7669) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c03a9f181a..8cc26e4da0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.16 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240620.0 +esphome-dashboard==20241025.0 aioesphomeapi==24.6.2 zeroconf==0.132.2 puremagic==1.27 From c20e1975d1acd9c99fefd1a1da7e446a2e403bc7 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 24 Oct 2024 23:25:19 +0200 Subject: [PATCH 2566/2607] unified way how all platforms handle get_download_types (#7617) Co-authored-by: Tomasz Duda --- esphome/dashboard/web_server.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 1a8b2ab83a..9aeece9aab 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -7,6 +7,7 @@ import datetime import functools import gzip import hashlib +import importlib import json import logging import os @@ -595,26 +596,18 @@ class DownloadListRequestHandler(BaseHandler): downloads = [] platform: str = storage_json.target_platform.lower() - if platform == const.PLATFORM_RP2040: - from esphome.components.rp2040 import get_download_types as rp2040_types - downloads = rp2040_types(storage_json) - elif platform == const.PLATFORM_ESP8266: - from esphome.components.esp8266 import get_download_types as esp8266_types - - downloads = esp8266_types(storage_json) - elif platform.upper() in ESP32_VARIANTS: - from esphome.components.esp32 import get_download_types as esp32_types - - downloads = esp32_types(storage_json) + if platform.upper() in ESP32_VARIANTS: + platform = "esp32" elif platform in (const.PLATFORM_RTL87XX, const.PLATFORM_BK72XX): - from esphome.components.libretiny import ( - get_download_types as libretiny_types, - ) + platform = "libretiny" - downloads = libretiny_types(storage_json) - else: - raise ValueError(f"Unknown platform {platform}") + try: + module = importlib.import_module(f"esphome.components.{platform}") + get_download_types = getattr(module, "get_download_types") + except AttributeError as exc: + raise ValueError(f"Unknown platform {platform}") from exc + downloads = get_download_types(storage_json) self.set_status(200) self.set_header("content-type", "application/json") From 4101d5dad15a5f3162ada989a536bf2cb6da0307 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Thu, 24 Oct 2024 17:26:39 -0400 Subject: [PATCH 2567/2607] [media_player] Add new media player conditions (#7667) --- esphome/components/media_player/__init__.py | 11 +++++++++++ esphome/components/media_player/automation.h | 10 ++++++++++ esphome/components/media_player/media_player.cpp | 4 ++++ tests/components/media_player/common.yaml | 4 ++++ 4 files changed, 29 insertions(+) diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 423cb065dc..a46b30db29 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -21,6 +21,7 @@ media_player_ns = cg.esphome_ns.namespace("media_player") MediaPlayer = media_player_ns.class_("MediaPlayer") + PlayAction = media_player_ns.class_( "PlayAction", automation.Action, cg.Parented.template(MediaPlayer) ) @@ -60,7 +61,11 @@ AnnoucementTrigger = media_player_ns.class_( "AnnouncementTrigger", automation.Trigger.template() ) IsIdleCondition = media_player_ns.class_("IsIdleCondition", automation.Condition) +IsPausedCondition = media_player_ns.class_("IsPausedCondition", automation.Condition) IsPlayingCondition = media_player_ns.class_("IsPlayingCondition", automation.Condition) +IsAnnouncingCondition = media_player_ns.class_( + "IsAnnouncingCondition", automation.Condition +) async def setup_media_player_core_(var, config): @@ -159,9 +164,15 @@ async def media_player_play_media_action(config, action_id, template_arg, args): @automation.register_condition( "media_player.is_idle", IsIdleCondition, MEDIA_PLAYER_ACTION_SCHEMA ) +@automation.register_condition( + "media_player.is_paused", IsPausedCondition, MEDIA_PLAYER_ACTION_SCHEMA +) @automation.register_condition( "media_player.is_playing", IsPlayingCondition, MEDIA_PLAYER_ACTION_SCHEMA ) +@automation.register_condition( + "media_player.is_announcing", IsAnnouncingCondition, MEDIA_PLAYER_ACTION_SCHEMA +) async def media_player_action(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID]) diff --git a/esphome/components/media_player/automation.h b/esphome/components/media_player/automation.h index f0e0a5dd31..7b9220c4a5 100644 --- a/esphome/components/media_player/automation.h +++ b/esphome/components/media_player/automation.h @@ -68,5 +68,15 @@ template class IsPlayingCondition : public Condition, pub bool check(Ts... x) override { return this->parent_->state == MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING; } }; +template class IsPausedCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->state == MediaPlayerState::MEDIA_PLAYER_STATE_PAUSED; } +}; + +template class IsAnnouncingCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->state == MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING; } +}; + } // namespace media_player } // namespace esphome diff --git a/esphome/components/media_player/media_player.cpp b/esphome/components/media_player/media_player.cpp index 586345ac9f..b5190d8573 100644 --- a/esphome/components/media_player/media_player.cpp +++ b/esphome/components/media_player/media_player.cpp @@ -37,6 +37,10 @@ const char *media_player_command_to_string(MediaPlayerCommand command) { return "UNMUTE"; case MEDIA_PLAYER_COMMAND_TOGGLE: return "TOGGLE"; + case MEDIA_PLAYER_COMMAND_VOLUME_UP: + return "VOLUME_UP"; + case MEDIA_PLAYER_COMMAND_VOLUME_DOWN: + return "VOLUME_DOWN"; default: return "UNKNOWN"; } diff --git a/tests/components/media_player/common.yaml b/tests/components/media_player/common.yaml index 24b85cd474..af0d5c7765 100644 --- a/tests/components/media_player/common.yaml +++ b/tests/components/media_player/common.yaml @@ -27,6 +27,10 @@ media_player: media_player.is_idle: - wait_until: media_player.is_playing: + - wait_until: + media_player.is_announcing: + - wait_until: + media_player.is_paused: - media_player.volume_up: - media_player.volume_down: - media_player.volume_set: 50% From 7dbda12008830ba576c2e6cddca87fab112999c6 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 24 Oct 2024 23:55:58 +0200 Subject: [PATCH 2568/2607] [code-quality] weikai.h (#7601) --- esphome/components/weikai/weikai.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/weikai/weikai.h b/esphome/components/weikai/weikai.h index 042c729162..175a067b27 100644 --- a/esphome/components/weikai/weikai.h +++ b/esphome/components/weikai/weikai.h @@ -209,7 +209,7 @@ class WeikaiComponent : public Component { /// @brief store the name for the component /// @param name the name as defined by the python code generator - void set_name(std::string name) { this->name_ = std::move(name); } + void set_name(std::string &&name) { this->name_ = std::move(name); } /// @brief Get the name of the component /// @return the name @@ -308,7 +308,7 @@ class WeikaiChannel : public uart::UARTComponent { /// @brief The name as generated by the Python code generator /// @param name of the channel - void set_channel_name(std::string name) { this->name_ = std::move(name); } + void set_channel_name(std::string &&name) { this->name_ = std::move(name); } /// @brief Get the channel name /// @return the name From 34a8eaddb227738ed1d22d43025a9af56ad5d4a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:56:48 +1300 Subject: [PATCH 2569/2607] Bump actions/setup-python from 5.2.0 to 5.3.0 in /.github/actions/restore-python (#7671) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index c6978f68c5..06c54578f5 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -17,7 +17,7 @@ runs: steps: - name: Set up Python ${{ inputs.python-version }} id: python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment From 09f9d915773c9ad2d15d60a60f6886f9da553da5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:57:09 +1300 Subject: [PATCH 2570/2607] Bump actions/setup-python from 5.2.0 to 5.3.0 (#7670) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .github/workflows/ci-api-proto.yml | 2 +- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/sync-device-classes.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-api-proto.yml b/.github/workflows/ci-api-proto.yml index 8112c4e0ff..a6b2e2b2b3 100644 --- a/.github/workflows/ci-api-proto.yml +++ b/.github/workflows/ci-api-proto.yml @@ -23,7 +23,7 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: "3.11" diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index f003e5d24c..435a58498e 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -42,7 +42,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: "3.9" - name: Set up Docker Buildx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d2f1c877d..82a55d0e2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 26a213f170..5072bec222 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: "3.x" - name: Set up python environment @@ -85,7 +85,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Set up Python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: "3.9" diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index c066ae9fb4..7a46d596a1 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -22,7 +22,7 @@ jobs: path: lib/home-assistant - name: Setup Python - uses: actions/setup-python@v5.2.0 + uses: actions/setup-python@v5.3.0 with: python-version: 3.12 From 33fdbbe30c4d9643300483bf2dfd85d992e2cf86 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:05:25 +1100 Subject: [PATCH 2571/2607] [image][online_image][animation] Fix transparency in RGB565 (#7631) --- esphome/components/animation/__init__.py | 13 +++--- esphome/components/animation/animation.cpp | 2 +- esphome/components/image/__init__.py | 13 +++--- esphome/components/image/image.cpp | 28 ++++++------- esphome/components/image/image.h | 37 ++++++++--------- .../components/online_image/online_image.cpp | 10 +---- .../components/online_image/online_image.h | 8 +--- tests/components/image/common.yaml | 38 ++++++++++++++++++ tests/components/image/test.esp32-ard.yaml | 40 +------------------ tests/components/image/test.esp32-c3-ard.yaml | 39 +----------------- tests/components/image/test.esp32-c3-idf.yaml | 39 +----------------- tests/components/image/test.esp32-idf.yaml | 39 +----------------- tests/components/image/test.esp8266-ard.yaml | 39 +----------------- tests/components/image/test.host.yaml | 8 ++++ tests/components/image/test.rp2040-ard.yaml | 39 +----------------- 15 files changed, 101 insertions(+), 291 deletions(-) create mode 100644 tests/components/image/common.yaml create mode 100644 tests/components/image/test.host.yaml diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index eb3d09ac96..5a308855de 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -271,7 +271,8 @@ async def to_code(config): pos += 1 elif config[CONF_TYPE] in ["RGB565", "TRANSPARENT_IMAGE"]: - data = [0 for _ in range(height * width * 2 * frames)] + bytes_per_pixel = 3 if transparent else 2 + data = [0 for _ in range(height * width * bytes_per_pixel * frames)] pos = 0 for frameIndex in range(frames): image.seek(frameIndex) @@ -288,17 +289,13 @@ async def to_code(config): G = g >> 2 B = b >> 3 rgb = (R << 11) | (G << 5) | B - - if transparent: - if rgb == 0x0020: - rgb = 0 - if a < 0x80: - rgb = 0x0020 - data[pos] = rgb >> 8 pos += 1 data[pos] = rgb & 0xFF pos += 1 + if transparent: + data[pos] = a + pos += 1 elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]: width8 = ((width + 7) // 8) * 8 diff --git a/esphome/components/animation/animation.cpp b/esphome/components/animation/animation.cpp index 7e0efa97e0..1375dfe07e 100644 --- a/esphome/components/animation/animation.cpp +++ b/esphome/components/animation/animation.cpp @@ -62,7 +62,7 @@ void Animation::set_frame(int frame) { } void Animation::update_data_start_() { - const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_; + const uint32_t image_size = this->get_width_stride() * this->height_; this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_; } diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index c72417bcda..8742540067 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -361,24 +361,21 @@ async def to_code(config): elif config[CONF_TYPE] in ["RGB565"]: image = image.convert("RGBA") pixels = list(image.getdata()) - data = [0 for _ in range(height * width * 2)] + bytes_per_pixel = 3 if transparent else 2 + data = [0 for _ in range(height * width * bytes_per_pixel)] pos = 0 for r, g, b, a in pixels: R = r >> 3 G = g >> 2 B = b >> 3 rgb = (R << 11) | (G << 5) | B - - if transparent: - if rgb == 0x0020: - rgb = 0 - if a < 0x80: - rgb = 0x0020 - data[pos] = rgb >> 8 pos += 1 data[pos] = rgb & 0xFF pos += 1 + if transparent: + data[pos] = a + pos += 1 elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]: if transparent: diff --git a/esphome/components/image/image.cpp b/esphome/components/image/image.cpp index ded4c60d25..ca2f659fb0 100644 --- a/esphome/components/image/image.cpp +++ b/esphome/components/image/image.cpp @@ -88,7 +88,7 @@ lv_img_dsc_t *Image::get_lv_img_dsc() { this->dsc_.header.reserved = 0; this->dsc_.header.w = this->width_; this->dsc_.header.h = this->height_; - this->dsc_.data_size = image_type_to_width_stride(this->dsc_.header.w * this->dsc_.header.h, this->get_type()); + this->dsc_.data_size = this->get_width_stride() * this->get_height(); switch (this->get_type()) { case IMAGE_TYPE_BINARY: this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT; @@ -104,17 +104,17 @@ lv_img_dsc_t *Image::get_lv_img_dsc() { case IMAGE_TYPE_RGB565: #if LV_COLOR_DEPTH == 16 - this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR; + this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; #else this->dsc_.header.cf = LV_IMG_CF_RGB565; #endif break; - case image::IMAGE_TYPE_RGBA: + case IMAGE_TYPE_RGBA: #if LV_COLOR_DEPTH == 32 this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR; #else - this->dsc_.header.cf = LV_IMG_CF_RGBA8888; + this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA; #endif break; } @@ -147,21 +147,21 @@ Color Image::get_rgb24_pixel_(int x, int y) const { return color; } Color Image::get_rgb565_pixel_(int x, int y) const { - const uint32_t pos = (x + y * this->width_) * 2; - uint16_t rgb565 = - progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1); + const uint8_t *pos = this->data_start_; + if (this->transparent_) { + pos += (x + y * this->width_) * 3; + } else { + pos += (x + y * this->width_) * 2; + } + uint16_t rgb565 = encode_uint16(progmem_read_byte(pos), progmem_read_byte(pos + 1)); auto r = (rgb565 & 0xF800) >> 11; auto g = (rgb565 & 0x07E0) >> 5; auto b = rgb565 & 0x001F; - Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); - if (rgb565 == 0x0020 && transparent_) { - // darkest green has been defined as transparent color for transparent RGB565 images. - color.w = 0; - } else { - color.w = 0xFF; - } + auto a = this->transparent_ ? progmem_read_byte(pos + 2) : 0xFF; + Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), a); return color; } + Color Image::get_grayscale_pixel_(int x, int y) const { const uint32_t pos = (x + y * this->width_); const uint8_t gray = progmem_read_byte(this->data_start_ + pos); diff --git a/esphome/components/image/image.h b/esphome/components/image/image.h index a8a8aab2c2..40370d18da 100644 --- a/esphome/components/image/image.h +++ b/esphome/components/image/image.h @@ -17,24 +17,6 @@ enum ImageType { IMAGE_TYPE_RGBA = 4, }; -inline int image_type_to_bpp(ImageType type) { - switch (type) { - case IMAGE_TYPE_BINARY: - return 1; - case IMAGE_TYPE_GRAYSCALE: - return 8; - case IMAGE_TYPE_RGB565: - return 16; - case IMAGE_TYPE_RGB24: - return 24; - case IMAGE_TYPE_RGBA: - return 32; - } - return 0; -} - -inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; } - class Image : public display::BaseImage { public: Image(const uint8_t *data_start, int width, int height, ImageType type); @@ -44,6 +26,25 @@ class Image : public display::BaseImage { const uint8_t *get_data_start() const { return this->data_start_; } ImageType get_type() const; + int get_bpp() const { + switch (this->type_) { + case IMAGE_TYPE_BINARY: + return 1; + case IMAGE_TYPE_GRAYSCALE: + return 8; + case IMAGE_TYPE_RGB565: + return this->transparent_ ? 24 : 16; + case IMAGE_TYPE_RGB24: + return 24; + case IMAGE_TYPE_RGBA: + return 32; + } + return 0; + } + + /// Return the stride of the image in bytes, that is, the distance in bytes + /// between two consecutive rows of pixels. + uint32_t get_width_stride() const { return (this->width_ * this->get_bpp() + 7u) / 8u; } void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override; void set_transparency(bool transparent) { transparent_ = transparent; } diff --git a/esphome/components/online_image/online_image.cpp b/esphome/components/online_image/online_image.cpp index 480bad6aca..1786809dfa 100644 --- a/esphome/components/online_image/online_image.cpp +++ b/esphome/components/online_image/online_image.cpp @@ -215,16 +215,10 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) { } case ImageType::IMAGE_TYPE_RGB565: { uint16_t col565 = display::ColorUtil::color_to_565(color); - if (this->has_transparency()) { - if (col565 == 0x0020) { - col565 = 0; - } - if (color.w < 0x80) { - col565 = 0x0020; - } - } this->buffer_[pos + 0] = static_cast((col565 >> 8) & 0xFF); this->buffer_[pos + 1] = static_cast(col565 & 0xFF); + if (this->has_transparency()) + this->buffer_[pos + 2] = color.w; break; } case ImageType::IMAGE_TYPE_RGBA: { diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h index 51c11478cd..017402a088 100644 --- a/esphome/components/online_image/online_image.h +++ b/esphome/components/online_image/online_image.h @@ -86,13 +86,9 @@ class OnlineImage : public PollingComponent, Allocator allocator_{Allocator::Flags::ALLOW_FAILURE}; uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); } - int get_buffer_size_(int width, int height) const { - return std::ceil(image::image_type_to_bpp(this->type_) * width * height / 8.0); - } + int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; } - int get_position_(int x, int y) const { - return ((x + y * this->buffer_width_) * image::image_type_to_bpp(this->type_)) / 8; - } + int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; } ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; } diff --git a/tests/components/image/common.yaml b/tests/components/image/common.yaml new file mode 100644 index 0000000000..313da6bc0b --- /dev/null +++ b/tests/components/image/common.yaml @@ -0,0 +1,38 @@ +image: + - id: binary_image + file: ../../pnglogo.png + type: BINARY + dither: FloydSteinberg + - id: transparent_transparent_image + file: ../../pnglogo.png + type: TRANSPARENT_BINARY + - id: rgba_image + file: ../../pnglogo.png + type: RGBA + resize: 50x50 + - id: rgb24_image + file: ../../pnglogo.png + type: RGB24 + use_transparency: yes + - id: rgb565_image + file: ../../pnglogo.png + type: RGB565 + use_transparency: no + - id: web_svg_image + file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg + resize: 256x48 + type: TRANSPARENT_BINARY + - id: web_tiff_image + file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff + type: RGB24 + resize: 48x48 + - id: web_redirect_image + file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 + type: RGB24 + resize: 48x48 + - id: mdi_alert + file: mdi:alert-circle-outline + resize: 50x50 + - id: another_alert_icon + file: mdi:alert-outline + type: BINARY diff --git a/tests/components/image/test.esp32-ard.yaml b/tests/components/image/test.esp32-ard.yaml index 9dd44d177f..818e720221 100644 --- a/tests/components/image/test.esp32-ard.yaml +++ b/tests/components/image/test.esp32-ard.yaml @@ -13,41 +13,5 @@ display: reset_pin: 21 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml + diff --git a/tests/components/image/test.esp32-c3-ard.yaml b/tests/components/image/test.esp32-c3-ard.yaml index c0b2779773..4dae9cd5ec 100644 --- a/tests/components/image/test.esp32-c3-ard.yaml +++ b/tests/components/image/test.esp32-c3-ard.yaml @@ -13,41 +13,4 @@ display: reset_pin: 10 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml diff --git a/tests/components/image/test.esp32-c3-idf.yaml b/tests/components/image/test.esp32-c3-idf.yaml index c0b2779773..4dae9cd5ec 100644 --- a/tests/components/image/test.esp32-c3-idf.yaml +++ b/tests/components/image/test.esp32-c3-idf.yaml @@ -13,41 +13,4 @@ display: reset_pin: 10 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml diff --git a/tests/components/image/test.esp32-idf.yaml b/tests/components/image/test.esp32-idf.yaml index e903afea1f..814f16c36c 100644 --- a/tests/components/image/test.esp32-idf.yaml +++ b/tests/components/image/test.esp32-idf.yaml @@ -13,41 +13,4 @@ display: reset_pin: 21 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml diff --git a/tests/components/image/test.esp8266-ard.yaml b/tests/components/image/test.esp8266-ard.yaml index 5a96ed9497..f963022ff4 100644 --- a/tests/components/image/test.esp8266-ard.yaml +++ b/tests/components/image/test.esp8266-ard.yaml @@ -13,41 +13,4 @@ display: reset_pin: 16 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml diff --git a/tests/components/image/test.host.yaml b/tests/components/image/test.host.yaml new file mode 100644 index 0000000000..29509db66c --- /dev/null +++ b/tests/components/image/test.host.yaml @@ -0,0 +1,8 @@ +display: + - platform: sdl + auto_clear_enabled: false + dimensions: + width: 480 + height: 480 + +<<: !include common.yaml diff --git a/tests/components/image/test.rp2040-ard.yaml b/tests/components/image/test.rp2040-ard.yaml index 4c40ca464f..5167c99a7d 100644 --- a/tests/components/image/test.rp2040-ard.yaml +++ b/tests/components/image/test.rp2040-ard.yaml @@ -13,41 +13,4 @@ display: reset_pin: 22 invert_colors: true -image: - - id: binary_image - file: ../../pnglogo.png - type: BINARY - dither: FloydSteinberg - - id: transparent_transparent_image - file: ../../pnglogo.png - type: TRANSPARENT_BINARY - - id: rgba_image - file: ../../pnglogo.png - type: RGBA - resize: 50x50 - - id: rgb24_image - file: ../../pnglogo.png - type: RGB24 - use_transparency: yes - - id: rgb565_image - file: ../../pnglogo.png - type: RGB565 - use_transparency: no - - id: web_svg_image - file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg - resize: 256x48 - type: TRANSPARENT_BINARY - - id: web_tiff_image - file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff - type: RGB24 - resize: 48x48 - - id: web_redirect_image - file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4 - type: RGB24 - resize: 48x48 - - id: mdi_alert - file: mdi:alert-circle-outline - resize: 50x50 - - id: another_alert_icon - file: mdi:alert-outline - type: BINARY +<<: !include common.yaml From 21cb941bbe7afb7096ee342fae2c88bdaa27d28b Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Fri, 25 Oct 2024 05:00:28 +0300 Subject: [PATCH 2572/2607] Add OpenTherm component (part 2.1: sensor platform) (#7529) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/opentherm/__init__.py | 20 +- esphome/components/opentherm/const.py | 5 + esphome/components/opentherm/generate.py | 140 ++++++ esphome/components/opentherm/hub.cpp | 108 ++++- esphome/components/opentherm/hub.h | 19 +- esphome/components/opentherm/opentherm.cpp | 3 + esphome/components/opentherm/opentherm.h | 3 +- .../components/opentherm/opentherm_macros.h | 91 ++++ esphome/components/opentherm/schema.py | 438 ++++++++++++++++++ .../components/opentherm/sensor/__init__.py | 35 ++ esphome/components/opentherm/validate.py | 31 ++ tests/components/opentherm/common.yaml | 77 ++- 12 files changed, 933 insertions(+), 37 deletions(-) create mode 100644 esphome/components/opentherm/const.py create mode 100644 esphome/components/opentherm/generate.py create mode 100644 esphome/components/opentherm/opentherm_macros.h create mode 100644 esphome/components/opentherm/schema.py create mode 100644 esphome/components/opentherm/sensor/__init__.py create mode 100644 esphome/components/opentherm/validate.py diff --git a/esphome/components/opentherm/__init__.py b/esphome/components/opentherm/__init__.py index 23443a4028..ee19818a29 100644 --- a/esphome/components/opentherm/__init__.py +++ b/esphome/components/opentherm/__init__.py @@ -1,9 +1,10 @@ from typing import Any -from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv +from esphome import pins from esphome.const import CONF_ID, PLATFORM_ESP32, PLATFORM_ESP8266 +from . import generate CODEOWNERS = ["@olegtarasov"] MULTI_CONF = True @@ -15,15 +16,14 @@ CONF_DHW_ENABLE = "dhw_enable" CONF_COOLING_ENABLE = "cooling_enable" CONF_OTC_ACTIVE = "otc_active" CONF_CH2_ACTIVE = "ch2_active" +CONF_SUMMER_MODE_ACTIVE = "summer_mode_active" +CONF_DHW_BLOCK = "dhw_block" CONF_SYNC_MODE = "sync_mode" -opentherm_ns = cg.esphome_ns.namespace("opentherm") -OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component) - CONFIG_SCHEMA = cv.All( cv.Schema( { - cv.GenerateID(): cv.declare_id(OpenthermHub), + cv.GenerateID(): cv.declare_id(generate.OpenthermHub), cv.Required(CONF_IN_PIN): pins.internal_gpio_input_pin_schema, cv.Required(CONF_OUT_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_CH_ENABLE, True): cv.boolean, @@ -31,6 +31,8 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_COOLING_ENABLE, False): cv.boolean, cv.Optional(CONF_OTC_ACTIVE, False): cv.boolean, cv.Optional(CONF_CH2_ACTIVE, False): cv.boolean, + cv.Optional(CONF_SUMMER_MODE_ACTIVE, False): cv.boolean, + cv.Optional(CONF_DHW_BLOCK, False): cv.boolean, cv.Optional(CONF_SYNC_MODE, False): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA), @@ -39,8 +41,6 @@ CONFIG_SCHEMA = cv.All( async def to_code(config: dict[str, Any]) -> None: - # Create the hub, passing the two callbacks defined below - # Since the hub is used in the callbacks, we need to define it first var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) @@ -53,5 +53,7 @@ async def to_code(config: dict[str, Any]) -> None: non_sensors = {CONF_ID, CONF_IN_PIN, CONF_OUT_PIN} for key, value in config.items(): - if key not in non_sensors: - cg.add(getattr(var, f"set_{key}")(value)) + if key in non_sensors: + continue + + cg.add(getattr(var, f"set_{key}")(value)) diff --git a/esphome/components/opentherm/const.py b/esphome/components/opentherm/const.py new file mode 100644 index 0000000000..1f997c5d9c --- /dev/null +++ b/esphome/components/opentherm/const.py @@ -0,0 +1,5 @@ +OPENTHERM = "opentherm" + +CONF_OPENTHERM_ID = "opentherm_id" + +SENSOR = "sensor" diff --git a/esphome/components/opentherm/generate.py b/esphome/components/opentherm/generate.py new file mode 100644 index 0000000000..6a97835a57 --- /dev/null +++ b/esphome/components/opentherm/generate.py @@ -0,0 +1,140 @@ +from collections.abc import Awaitable +from typing import Any, Callable + +import esphome.codegen as cg +from esphome.const import CONF_ID +from . import const +from .schema import TSchema + +opentherm_ns = cg.esphome_ns.namespace("opentherm") +OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component) + + +def define_has_component(component_type: str, keys: list[str]) -> None: + cg.add_define( + f"OPENTHERM_{component_type.upper()}_LIST(F, sep)", + cg.RawExpression( + " sep ".join(map(lambda key: f"F({key}_{component_type.lower()})", keys)) + ), + ) + for key in keys: + cg.add_define(f"OPENTHERM_HAS_{component_type.upper()}_{key}") + + +def define_message_handler( + component_type: str, keys: list[str], schemas: dict[str, TSchema] +) -> None: + # The macros defined here should be able to generate things like this: + # // Parsing a message and publishing to sensors + # case MessageId::Message: + # // Can have multiple sensors here, for example for a Status message with multiple flags + # this->thing_binary_sensor->publish_state(parse_flag8_lb_0(response)); + # this->other_binary_sensor->publish_state(parse_flag8_lb_1(response)); + # break; + # // Building a message for a write request + # case MessageId::Message: { + # unsigned int data = 0; + # data = write_flag8_lb_0(some_input_switch->state, data); // Where input_sensor can also be a number/output/switch + # data = write_u8_hb(some_number->state, data); + # return opentherm_->build_request_(MessageType::WriteData, MessageId::Message, data); + # } + + messages: dict[str, list[tuple[str, str]]] = {} + for key in keys: + msg = schemas[key].message + if msg not in messages: + messages[msg] = [] + messages[msg].append((key, schemas[key].message_data)) + + cg.add_define( + f"OPENTHERM_{component_type.upper()}_MESSAGE_HANDLERS(MESSAGE, ENTITY, entity_sep, postscript, msg_sep)", + cg.RawExpression( + " msg_sep ".join( + [ + f"MESSAGE({msg}) " + + " entity_sep ".join( + [ + f"ENTITY({key}_{component_type.lower()}, {msg_data})" + for key, msg_data in keys + ] + ) + + " postscript" + for msg, keys in messages.items() + ] + ) + ), + ) + + +def define_readers(component_type: str, keys: list[str]) -> None: + for key in keys: + cg.add_define( + f"OPENTHERM_READ_{key}", + cg.RawExpression(f"this->{key}_{component_type.lower()}->state"), + ) + + +def add_messages(hub: cg.MockObj, keys: list[str], schemas: dict[str, TSchema]): + messages: set[tuple[str, bool]] = set() + for key in keys: + messages.add((schemas[key].message, schemas[key].keep_updated)) + for msg, keep_updated in messages: + msg_expr = cg.RawExpression(f"esphome::opentherm::MessageId::{msg}") + if keep_updated: + cg.add(hub.add_repeating_message(msg_expr)) + else: + cg.add(hub.add_initial_message(msg_expr)) + + +def add_property_set(var: cg.MockObj, config_key: str, config: dict[str, Any]) -> None: + if config_key in config: + cg.add(getattr(var, f"set_{config_key}")(config[config_key])) + + +Create = Callable[[dict[str, Any], str, cg.MockObj], Awaitable[cg.Pvariable]] + + +def create_only_conf( + create: Callable[[dict[str, Any]], Awaitable[cg.Pvariable]] +) -> Create: + return lambda conf, _key, _hub: create(conf) + + +async def component_to_code( + component_type: str, + schemas: dict[str, TSchema], + type: cg.MockObjClass, + create: Create, + config: dict[str, Any], +) -> list[str]: + """Generate the code for each configured component in the schema of a component type. + + Parameters: + - component_type: The type of component, e.g. "sensor" or "binary_sensor" + - schema_: The schema for that component type, a list of available components + - type: The type of the component, e.g. sensor.Sensor or OpenthermOutput + - create: A constructor function for the component, which receives the config, + the key and the hub and should asynchronously return the new component + - config: The configuration for this component type + + Returns: The list of keys for the created components + """ + cg.add_define(f"OPENTHERM_USE_{component_type.upper()}") + + hub = await cg.get_variable(config[const.CONF_OPENTHERM_ID]) + + keys: list[str] = [] + for key, conf in config.items(): + if not isinstance(conf, dict): + continue + id = conf[CONF_ID] + if id and id.type == type: + entity = await create(conf, key, hub) + cg.add(getattr(hub, f"set_{key}_{component_type.lower()}")(entity)) + keys.append(key) + + define_has_component(component_type, keys) + define_message_handler(component_type, keys, schemas) + add_messages(hub, keys, schemas) + + return keys diff --git a/esphome/components/opentherm/hub.cpp b/esphome/components/opentherm/hub.cpp index c26fbced32..770bbd82b7 100644 --- a/esphome/components/opentherm/hub.cpp +++ b/esphome/components/opentherm/hub.cpp @@ -7,50 +7,114 @@ namespace esphome { namespace opentherm { static const char *const TAG = "opentherm"; +namespace message_data { +bool parse_flag8_lb_0(OpenthermData &data) { return read_bit(data.valueLB, 0); } +bool parse_flag8_lb_1(OpenthermData &data) { return read_bit(data.valueLB, 1); } +bool parse_flag8_lb_2(OpenthermData &data) { return read_bit(data.valueLB, 2); } +bool parse_flag8_lb_3(OpenthermData &data) { return read_bit(data.valueLB, 3); } +bool parse_flag8_lb_4(OpenthermData &data) { return read_bit(data.valueLB, 4); } +bool parse_flag8_lb_5(OpenthermData &data) { return read_bit(data.valueLB, 5); } +bool parse_flag8_lb_6(OpenthermData &data) { return read_bit(data.valueLB, 6); } +bool parse_flag8_lb_7(OpenthermData &data) { return read_bit(data.valueLB, 7); } +bool parse_flag8_hb_0(OpenthermData &data) { return read_bit(data.valueHB, 0); } +bool parse_flag8_hb_1(OpenthermData &data) { return read_bit(data.valueHB, 1); } +bool parse_flag8_hb_2(OpenthermData &data) { return read_bit(data.valueHB, 2); } +bool parse_flag8_hb_3(OpenthermData &data) { return read_bit(data.valueHB, 3); } +bool parse_flag8_hb_4(OpenthermData &data) { return read_bit(data.valueHB, 4); } +bool parse_flag8_hb_5(OpenthermData &data) { return read_bit(data.valueHB, 5); } +bool parse_flag8_hb_6(OpenthermData &data) { return read_bit(data.valueHB, 6); } +bool parse_flag8_hb_7(OpenthermData &data) { return read_bit(data.valueHB, 7); } +uint8_t parse_u8_lb(OpenthermData &data) { return data.valueLB; } +uint8_t parse_u8_hb(OpenthermData &data) { return data.valueHB; } +int8_t parse_s8_lb(OpenthermData &data) { return (int8_t) data.valueLB; } +int8_t parse_s8_hb(OpenthermData &data) { return (int8_t) data.valueHB; } +uint16_t parse_u16(OpenthermData &data) { return data.u16(); } +int16_t parse_s16(OpenthermData &data) { return data.s16(); } +float parse_f88(OpenthermData &data) { return data.f88(); } -OpenthermData OpenthermHub::build_request_(MessageId request_id) { +void write_flag8_lb_0(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 0, value); } +void write_flag8_lb_1(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 1, value); } +void write_flag8_lb_2(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 2, value); } +void write_flag8_lb_3(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 3, value); } +void write_flag8_lb_4(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 4, value); } +void write_flag8_lb_5(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 5, value); } +void write_flag8_lb_6(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 6, value); } +void write_flag8_lb_7(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 7, value); } +void write_flag8_hb_0(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 0, value); } +void write_flag8_hb_1(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 1, value); } +void write_flag8_hb_2(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 2, value); } +void write_flag8_hb_3(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 3, value); } +void write_flag8_hb_4(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 4, value); } +void write_flag8_hb_5(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 5, value); } +void write_flag8_hb_6(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 6, value); } +void write_flag8_hb_7(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 7, value); } +void write_u8_lb(const uint8_t value, OpenthermData &data) { data.valueLB = value; } +void write_u8_hb(const uint8_t value, OpenthermData &data) { data.valueHB = value; } +void write_s8_lb(const int8_t value, OpenthermData &data) { data.valueLB = (uint8_t) value; } +void write_s8_hb(const int8_t value, OpenthermData &data) { data.valueHB = (uint8_t) value; } +void write_u16(const uint16_t value, OpenthermData &data) { data.u16(value); } +void write_s16(const int16_t value, OpenthermData &data) { data.s16(value); } +void write_f88(const float value, OpenthermData &data) { data.f88(value); } + +} // namespace message_data + +OpenthermData OpenthermHub::build_request_(MessageId request_id) const { OpenthermData data; data.type = 0; data.id = 0; data.valueHB = 0; data.valueLB = 0; - // First, handle the status request. This requires special logic, because we - // wouldn't want to inadvertently disable domestic hot water, for example. - // It is also included in the macro-generated code below, but that will - // never be executed, because we short-circuit it here. + // We need this special logic for STATUS message because we have two options for specifying boiler modes: + // with static config values in the hub, or with separate switches. if (request_id == MessageId::STATUS) { - bool const ch_enabled = this->ch_enable; - bool dhw_enabled = this->dhw_enable; - bool cooling_enabled = this->cooling_enable; - bool otc_enabled = this->otc_active; - bool ch2_enabled = this->ch2_active; + // NOLINTBEGIN + bool const ch_enabled = this->ch_enable && OPENTHERM_READ_ch_enable && OPENTHERM_READ_t_set > 0.0; + bool const dhw_enabled = this->dhw_enable && OPENTHERM_READ_dhw_enable; + bool const cooling_enabled = + this->cooling_enable && OPENTHERM_READ_cooling_enable && OPENTHERM_READ_cooling_control > 0.0; + bool const otc_enabled = this->otc_active && OPENTHERM_READ_otc_active; + bool const ch2_enabled = this->ch2_active && OPENTHERM_READ_ch2_active && OPENTHERM_READ_t_set_ch2 > 0.0; + bool const summer_mode_is_active = this->summer_mode_active && OPENTHERM_READ_summer_mode_active; + bool const dhw_blocked = this->dhw_block && OPENTHERM_READ_dhw_block; + // NOLINTEND data.type = MessageType::READ_DATA; data.id = MessageId::STATUS; - data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4); + data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4) | + (summer_mode_is_active << 5) | (dhw_blocked << 6); + + return data; + } // Disable incomplete switch statement warnings, because the cases in each // switch are generated based on the configured sensors and inputs. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" - // TODO: This is a placeholder for an auto-generated switch statement which builds request structure based on - // which sensors are enabled in config. + switch (request_id) { OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , ) } #pragma GCC diagnostic pop - return data; - } - return OpenthermData(); + // And if we get here, a message was requested which somehow wasn't handled. + // This shouldn't happen due to the way the defines are configured, so we + // log an error and just return a 0 message. + ESP_LOGE(TAG, "Tried to create a request with unknown id %d. This should never happen, so please open an issue.", + request_id); + return {}; } -OpenthermHub::OpenthermHub() : Component() {} +OpenthermHub::OpenthermHub() : Component(), in_pin_{}, out_pin_{} {} void OpenthermHub::process_response(OpenthermData &data) { ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id, this->opentherm_->message_id_to_str((MessageId) data.id)); ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str()); + + switch (data.id) { + OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_RESPONSE_MESSAGE, OPENTHERM_MESSAGE_RESPONSE_ENTITY, , + OPENTHERM_MESSAGE_RESPONSE_POSTSCRIPT, ) + } } void OpenthermHub::setup() { @@ -254,15 +318,17 @@ void OpenthermHub::handle_timeout_error_() { this->stop_opentherm_(); } -#define ID(x) x -#define SHOW2(x) #x -#define SHOW(x) SHOW2(x) - void OpenthermHub::dump_config() { ESP_LOGCONFIG(TAG, "OpenTherm:"); LOG_PIN(" In: ", this->in_pin_); LOG_PIN(" Out: ", this->out_pin_); ESP_LOGCONFIG(TAG, " Sync mode: %d", this->sync_mode_); + ESP_LOGCONFIG(TAG, " Sensors: %s", SHOW(OPENTHERM_SENSOR_LIST(ID, ))); + ESP_LOGCONFIG(TAG, " Binary sensors: %s", SHOW(OPENTHERM_BINARY_SENSOR_LIST(ID, ))); + ESP_LOGCONFIG(TAG, " Switches: %s", SHOW(OPENTHERM_SWITCH_LIST(ID, ))); + ESP_LOGCONFIG(TAG, " Input sensors: %s", SHOW(OPENTHERM_INPUT_SENSOR_LIST(ID, ))); + ESP_LOGCONFIG(TAG, " Outputs: %s", SHOW(OPENTHERM_OUTPUT_LIST(ID, ))); + ESP_LOGCONFIG(TAG, " Numbers: %s", SHOW(OPENTHERM_NUMBER_LIST(ID, ))); ESP_LOGCONFIG(TAG, " Initial requests:"); for (auto type : this->initial_messages_) { ESP_LOGCONFIG(TAG, " - %d", type); diff --git a/esphome/components/opentherm/hub.h b/esphome/components/opentherm/hub.h index ce9f09fe33..3b90cdf427 100644 --- a/esphome/components/opentherm/hub.h +++ b/esphome/components/opentherm/hub.h @@ -7,11 +7,17 @@ #include "opentherm.h" +#ifdef OPENTHERM_USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif + #include #include #include #include +#include "opentherm_macros.h" + namespace esphome { namespace opentherm { @@ -23,6 +29,8 @@ class OpenthermHub : public Component { // The OpenTherm interface std::unique_ptr opentherm_; + OPENTHERM_SENSOR_LIST(OPENTHERM_DECLARE_SENSOR, ) + // The set of initial messages to send on starting communication with the boiler std::unordered_set initial_messages_; // and the repeating messages which are sent repeatedly to update various sensors @@ -44,7 +52,7 @@ class OpenthermHub : public Component { bool sync_mode_ = false; // Create OpenTherm messages based on the message id - OpenthermData build_request_(MessageId request_id); + OpenthermData build_request_(MessageId request_id) const; void handle_protocol_write_error_(); void handle_protocol_read_error_(); void handle_timeout_error_(); @@ -78,6 +86,8 @@ class OpenthermHub : public Component { void set_in_pin(InternalGPIOPin *in_pin) { this->in_pin_ = in_pin; } void set_out_pin(InternalGPIOPin *out_pin) { this->out_pin_ = out_pin; } + OPENTHERM_SENSOR_LIST(OPENTHERM_SET_SENSOR, ) + // Add a request to the set of initial requests void add_initial_message(MessageId message_id) { this->initial_messages_.insert(message_id); } // Add a request to the set of repeating requests. Note that a large number of repeating @@ -86,9 +96,10 @@ class OpenthermHub : public Component { // will be processed. void add_repeating_message(MessageId message_id) { this->repeating_messages_.insert(message_id); } - // There are five status variables, which can either be set as a simple variable, + // There are seven status variables, which can either be set as a simple variable, // or using a switch. ch_enable and dhw_enable default to true, the others to false. - bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false; + bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false, + summer_mode_active = false, dhw_block = false; // Setters for the status variables void set_ch_enable(bool value) { this->ch_enable = value; } @@ -96,6 +107,8 @@ class OpenthermHub : public Component { void set_cooling_enable(bool value) { this->cooling_enable = value; } void set_otc_active(bool value) { this->otc_active = value; } void set_ch2_active(bool value) { this->ch2_active = value; } + void set_summer_mode_active(bool value) { this->summer_mode_active = value; } + void set_dhw_block(bool value) { this->dhw_block = value; } void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; } float get_setup_priority() const override { return setup_priority::HARDWARE; } diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index b830cc01d3..4a23bb94cf 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -283,6 +283,9 @@ bool OpenTherm::init_esp32_timer_() { .clk_src = TIMER_SRC_CLK_DEFAULT, #endif .divider = 80, +#if defined(SOC_TIMER_GROUP_SUPPORT_XTAL) && ESP_IDF_VERSION_MAJOR < 5 + .clk_src = TIMER_SRC_CLK_APB +#endif }; esp_err_t result; diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 609cfb6243..23f4b39a1a 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -20,7 +20,6 @@ namespace esphome { namespace opentherm { -// TODO: Account for immutable semantics change in hub.cpp when doing later installments of OpenTherm PR template constexpr T read_bit(T value, uint8_t bit) { return (value >> bit) & 0x01; } template constexpr T set_bit(T value, uint8_t bit) { return value |= (1UL << bit); } @@ -28,7 +27,7 @@ template constexpr T set_bit(T value, uint8_t bit) { return value |= (1 template constexpr T clear_bit(T value, uint8_t bit) { return value &= ~(1UL << bit); } template constexpr T write_bit(T value, uint8_t bit, uint8_t bit_value) { - return bit_value ? setBit(value, bit) : clearBit(value, bit); + return bit_value ? set_bit(value, bit) : clear_bit(value, bit); } enum OperationMode { diff --git a/esphome/components/opentherm/opentherm_macros.h b/esphome/components/opentherm/opentherm_macros.h new file mode 100644 index 0000000000..0389e975ff --- /dev/null +++ b/esphome/components/opentherm/opentherm_macros.h @@ -0,0 +1,91 @@ +#pragma once +namespace esphome { +namespace opentherm { + +// ===== hub.h macros ===== + +// *_LIST macros will be generated in defines.h if at least one sensor from each platform is used. +// These lists will look like this: +// #define OPENTHERM_BINARY_SENSOR_LIST(F, sep) F(sensor_1) sep F(sensor_2) +// These lists will be used in hub.h to define sensor fields (passing macros like OPENTHERM_DECLARE_SENSOR as F) +// and setters (passing macros like OPENTHERM_SET_SENSOR as F) (see below) +// In order for things not to break, we define empty lists here in case some platforms are not used in config. +#ifndef OPENTHERM_SENSOR_LIST +#define OPENTHERM_SENSOR_LIST(F, sep) +#endif + +// Use macros to create fields for every entity specified in the ESPHome configuration +#define OPENTHERM_DECLARE_SENSOR(entity) sensor::Sensor *entity; + +// Setter macros +#define OPENTHERM_SET_SENSOR(entity) \ + void set_##entity(sensor::Sensor *sensor) { this->entity = sensor; } + +// ===== hub.cpp macros ===== + +// *_MESSAGE_HANDLERS are generated in defines.h and look like this: +// OPENTHERM_NUMBER_MESSAGE_HANDLERS(MESSAGE, ENTITY, entity_sep, postscript, msg_sep) MESSAGE(COOLING_CONTROL) +// ENTITY(cooling_control_number, f88) postscript msg_sep They contain placeholders for message part and entities parts, +// since one message can contain multiple entities. MESSAGE part is substituted with OPENTHERM_MESSAGE_WRITE_MESSAGE, +// OPENTHERM_MESSAGE_READ_MESSAGE or OPENTHERM_MESSAGE_RESPONSE_MESSAGE. ENTITY part is substituted with +// OPENTHERM_MESSAGE_WRITE_ENTITY or OPENTHERM_MESSAGE_RESPONSE_ENTITY. OPENTHERM_IGNORE is used for sensor read +// requests since no data needs to be sent or processed, just the data id. + +// In order for things not to break, we define empty lists here in case some platforms are not used in config. +#ifndef OPENTHERM_SENSOR_MESSAGE_HANDLERS +#define OPENTHERM_SENSOR_MESSAGE_HANDLERS(MESSAGE, ENTITY, entity_sep, postscript, msg_sep) +#endif + +// Read data request builder +#define OPENTHERM_MESSAGE_READ_MESSAGE(msg) \ + case MessageId::msg: \ + data.type = MessageType::READ_DATA; \ + data.id = request_id; \ + return data; + +// Data processing builders +#define OPENTHERM_MESSAGE_RESPONSE_MESSAGE(msg) case MessageId::msg: +#define OPENTHERM_MESSAGE_RESPONSE_ENTITY(key, msg_data) this->key->publish_state(message_data::parse_##msg_data(data)); +#define OPENTHERM_MESSAGE_RESPONSE_POSTSCRIPT break; + +#define OPENTHERM_IGNORE(x, y) + +// Default macros for STATUS entities +#ifndef OPENTHERM_READ_ch_enable +#define OPENTHERM_READ_ch_enable true +#endif +#ifndef OPENTHERM_READ_dhw_enable +#define OPENTHERM_READ_dhw_enable true +#endif +#ifndef OPENTHERM_READ_t_set +#define OPENTHERM_READ_t_set 0.0 +#endif +#ifndef OPENTHERM_READ_cooling_enable +#define OPENTHERM_READ_cooling_enable false +#endif +#ifndef OPENTHERM_READ_cooling_control +#define OPENTHERM_READ_cooling_control 0.0 +#endif +#ifndef OPENTHERM_READ_otc_active +#define OPENTHERM_READ_otc_active false +#endif +#ifndef OPENTHERM_READ_ch2_active +#define OPENTHERM_READ_ch2_active false +#endif +#ifndef OPENTHERM_READ_t_set_ch2 +#define OPENTHERM_READ_t_set_ch2 0.0 +#endif +#ifndef OPENTHERM_READ_summer_mode_active +#define OPENTHERM_READ_summer_mode_active false +#endif +#ifndef OPENTHERM_READ_dhw_block +#define OPENTHERM_READ_dhw_block false +#endif + +// These macros utilize the structure of *_LIST macros in order +#define ID(x) x +#define SHOW_INNER(x) #x +#define SHOW(x) SHOW_INNER(x) + +} // namespace opentherm +} // namespace esphome diff --git a/esphome/components/opentherm/schema.py b/esphome/components/opentherm/schema.py new file mode 100644 index 0000000000..6ed0029437 --- /dev/null +++ b/esphome/components/opentherm/schema.py @@ -0,0 +1,438 @@ +# This file contains a schema for all supported sensors, binary sensors and +# inputs of the OpenTherm component. + +from dataclasses import dataclass +from typing import Optional, TypeVar + +from esphome.const import ( + UNIT_CELSIUS, + UNIT_EMPTY, + UNIT_KILOWATT, + UNIT_MICROAMP, + UNIT_PERCENT, + UNIT_REVOLUTIONS_PER_MINUTE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_EMPTY, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, + STATE_CLASS_TOTAL_INCREASING, +) + + +@dataclass +class EntitySchema: + description: str + """Description of the item, based on the OpenTherm spec""" + + message: str + """OpenTherm message id used to read or write the value""" + + keep_updated: bool + """Whether the value should be read or write repeatedly (True) or only during + the initialization phase (False) + """ + + message_data: str + """Instructions on how to interpret the data in the message + - flag8_[hb|lb]_[0-7]: data is a byte of single bit flags, + this flag is set in the high (hb) or low byte (lb), + at position 0 to 7 + - u8_[hb|lb]: data is an unsigned 8-bit integer, + in the high (hb) or low byte (lb) + - s8_[hb|lb]: data is an signed 8-bit integer, + in the high (hb) or low byte (lb) + - f88: data is a signed fixed point value with + 1 sign bit, 7 integer bits, 8 fractional bits + - u16: data is an unsigned 16-bit integer + - s16: data is a signed 16-bit integer + """ + + +TSchema = TypeVar("TSchema", bound=EntitySchema) + + +@dataclass +class SensorSchema(EntitySchema): + accuracy_decimals: int + state_class: str + unit_of_measurement: Optional[str] = None + icon: Optional[str] = None + device_class: Optional[str] = None + disabled_by_default: bool = False + + +SENSORS: dict[str, SensorSchema] = { + "rel_mod_level": SensorSchema( + description="Relative modulation level", + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=2, + icon="mdi:percent", + state_class=STATE_CLASS_MEASUREMENT, + message="MODULATION_LEVEL", + keep_updated=True, + message_data="f88", + ), + "ch_pressure": SensorSchema( + description="Water pressure in CH circuit", + unit_of_measurement="bar", + accuracy_decimals=2, + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + message="CH_WATER_PRESSURE", + keep_updated=True, + message_data="f88", + ), + "dhw_flow_rate": SensorSchema( + description="Water flow rate in DHW circuit", + unit_of_measurement="l/min", + accuracy_decimals=2, + icon="mdi:waves-arrow-right", + state_class=STATE_CLASS_MEASUREMENT, + message="DHW_FLOW_RATE", + keep_updated=True, + message_data="f88", + ), + "t_boiler": SensorSchema( + description="Boiler water temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="FEED_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_dhw": SensorSchema( + description="DHW temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="DHW_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_outside": SensorSchema( + description="Outside temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="OUTSIDE_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_ret": SensorSchema( + description="Return water temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="RETURN_WATER_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_storage": SensorSchema( + description="Solar storage temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="SOLAR_STORE_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_collector": SensorSchema( + description="Solar collector temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="SOLAR_COLLECT_TEMP", + keep_updated=True, + message_data="s16", + ), + "t_flow_ch2": SensorSchema( + description="Flow water temperature CH2 circuit", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="FEED_TEMP_CH2", + keep_updated=True, + message_data="f88", + ), + "t_dhw2": SensorSchema( + description="Domestic hot water temperature 2", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="DHW2_TEMP", + keep_updated=True, + message_data="f88", + ), + "t_exhaust": SensorSchema( + description="Boiler exhaust temperature", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="EXHAUST_TEMP", + keep_updated=True, + message_data="s16", + ), + "fan_speed": SensorSchema( + description="Boiler fan speed", + unit_of_measurement=UNIT_REVOLUTIONS_PER_MINUTE, + accuracy_decimals=0, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + message="FAN_SPEED", + keep_updated=True, + message_data="u16", + ), + "flame_current": SensorSchema( + description="Boiler flame current", + unit_of_measurement=UNIT_MICROAMP, + accuracy_decimals=0, + device_class=DEVICE_CLASS_CURRENT, + state_class=STATE_CLASS_MEASUREMENT, + message="FLAME_CURRENT", + keep_updated=True, + message_data="f88", + ), + "burner_starts": SensorSchema( + description="Number of starts burner", + accuracy_decimals=0, + icon="mdi:gas-burner", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="BURNER_STARTS", + keep_updated=True, + message_data="u16", + ), + "ch_pump_starts": SensorSchema( + description="Number of starts CH pump", + accuracy_decimals=0, + icon="mdi:pump", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="CH_PUMP_STARTS", + keep_updated=True, + message_data="u16", + ), + "dhw_pump_valve_starts": SensorSchema( + description="Number of starts DHW pump/valve", + accuracy_decimals=0, + icon="mdi:water-pump", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="DHW_PUMP_STARTS", + keep_updated=True, + message_data="u16", + ), + "dhw_burner_starts": SensorSchema( + description="Number of starts burner during DHW mode", + accuracy_decimals=0, + icon="mdi:gas-burner", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="DHW_BURNER_STARTS", + keep_updated=True, + message_data="u16", + ), + "burner_operation_hours": SensorSchema( + description="Number of hours that burner is in operation", + accuracy_decimals=0, + icon="mdi:clock-outline", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="BURNER_HOURS", + keep_updated=True, + message_data="u16", + ), + "ch_pump_operation_hours": SensorSchema( + description="Number of hours that CH pump has been running", + accuracy_decimals=0, + icon="mdi:clock-outline", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="CH_PUMP_HOURS", + keep_updated=True, + message_data="u16", + ), + "dhw_pump_valve_operation_hours": SensorSchema( + description="Number of hours that DHW pump has been running or DHW valve has been opened", + accuracy_decimals=0, + icon="mdi:clock-outline", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="DHW_PUMP_HOURS", + keep_updated=True, + message_data="u16", + ), + "dhw_burner_operation_hours": SensorSchema( + description="Number of hours that burner is in operation during DHW mode", + accuracy_decimals=0, + icon="mdi:clock-outline", + state_class=STATE_CLASS_TOTAL_INCREASING, + message="DHW_BURNER_HOURS", + keep_updated=True, + message_data="u16", + ), + "t_dhw_set_ub": SensorSchema( + description="Upper bound for adjustment of DHW setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="DHW_BOUNDS", + keep_updated=False, + message_data="s8_hb", + ), + "t_dhw_set_lb": SensorSchema( + description="Lower bound for adjustment of DHW setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="DHW_BOUNDS", + keep_updated=False, + message_data="s8_lb", + ), + "max_t_set_ub": SensorSchema( + description="Upper bound for adjustment of max CH setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="CH_BOUNDS", + keep_updated=False, + message_data="s8_hb", + ), + "max_t_set_lb": SensorSchema( + description="Lower bound for adjustment of max CH setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=0, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="CH_BOUNDS", + keep_updated=False, + message_data="s8_lb", + ), + "t_dhw_set": SensorSchema( + description="Domestic hot water temperature setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="DHW_SETPOINT", + keep_updated=True, + message_data="f88", + ), + "max_t_set": SensorSchema( + description="Maximum allowable CH water setpoint", + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + message="MAX_CH_SETPOINT", + keep_updated=True, + message_data="f88", + ), + "oem_fault_code": SensorSchema( + description="OEM fault code", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + message="FAULT_FLAGS", + keep_updated=True, + message_data="u8_lb", + ), + "oem_diagnostic_code": SensorSchema( + description="OEM diagnostic code", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + message="OEM_DIAGNOSTIC", + keep_updated=True, + message_data="u16", + ), + "max_capacity": SensorSchema( + description="Maximum boiler capacity (KW)", + unit_of_measurement=UNIT_KILOWATT, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + disabled_by_default=True, + message="MAX_BOILER_CAPACITY", + keep_updated=False, + message_data="u8_hb", + ), + "min_mod_level": SensorSchema( + description="Minimum modulation level", + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=0, + icon="mdi:percent", + disabled_by_default=True, + state_class=STATE_CLASS_MEASUREMENT, + message="MAX_BOILER_CAPACITY", + keep_updated=False, + message_data="u8_lb", + ), + "opentherm_version_device": SensorSchema( + description="Version of OpenTherm implemented by device", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="OT_VERSION_DEVICE", + keep_updated=False, + message_data="f88", + ), + "device_type": SensorSchema( + description="Device product type", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="VERSION_DEVICE", + keep_updated=False, + message_data="u8_hb", + ), + "device_version": SensorSchema( + description="Device product version", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="VERSION_DEVICE", + keep_updated=False, + message_data="u8_lb", + ), + "device_id": SensorSchema( + description="Device ID code", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="DEVICE_CONFIG", + keep_updated=False, + message_data="u8_lb", + ), + "otc_hc_ratio_ub": SensorSchema( + description="OTC heat curve ratio upper bound", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="OTC_CURVE_BOUNDS", + keep_updated=False, + message_data="u8_hb", + ), + "otc_hc_ratio_lb": SensorSchema( + description="OTC heat curve ratio lower bound", + unit_of_measurement=UNIT_EMPTY, + accuracy_decimals=0, + state_class=STATE_CLASS_NONE, + disabled_by_default=True, + message="OTC_CURVE_BOUNDS", + keep_updated=False, + message_data="u8_lb", + ), +} diff --git a/esphome/components/opentherm/sensor/__init__.py b/esphome/components/opentherm/sensor/__init__.py new file mode 100644 index 0000000000..20224e0eda --- /dev/null +++ b/esphome/components/opentherm/sensor/__init__.py @@ -0,0 +1,35 @@ +from typing import Any + +import esphome.config_validation as cv +from esphome.components import sensor +from .. import const, schema, validate, generate + +DEPENDENCIES = [const.OPENTHERM] +COMPONENT_TYPE = const.SENSOR + + +def get_entity_validation_schema(entity: schema.SensorSchema) -> cv.Schema: + return sensor.sensor_schema( + unit_of_measurement=entity.unit_of_measurement + or sensor._UNDEF, # pylint: disable=protected-access + accuracy_decimals=entity.accuracy_decimals, + device_class=entity.device_class + or sensor._UNDEF, # pylint: disable=protected-access + icon=entity.icon or sensor._UNDEF, # pylint: disable=protected-access + state_class=entity.state_class, + ) + + +CONFIG_SCHEMA = validate.create_component_schema( + schema.SENSORS, get_entity_validation_schema +) + + +async def to_code(config: dict[str, Any]) -> None: + await generate.component_to_code( + COMPONENT_TYPE, + schema.SENSORS, + sensor.Sensor, + generate.create_only_conf(sensor.new_sensor), + config, + ) diff --git a/esphome/components/opentherm/validate.py b/esphome/components/opentherm/validate.py new file mode 100644 index 0000000000..d4507672a5 --- /dev/null +++ b/esphome/components/opentherm/validate.py @@ -0,0 +1,31 @@ +from typing import Callable + +from voluptuous import Schema + +import esphome.config_validation as cv + +from . import const, schema, generate +from .schema import TSchema + + +def create_entities_schema( + entities: dict[str, schema.EntitySchema], + get_entity_validation_schema: Callable[[TSchema], cv.Schema], +) -> Schema: + entity_schema = {} + for key, entity in entities.items(): + entity_schema[cv.Optional(key)] = get_entity_validation_schema(entity) + return cv.Schema(entity_schema) + + +def create_component_schema( + entities: dict[str, schema.EntitySchema], + get_entity_validation_schema: Callable[[TSchema], cv.Schema], +) -> Schema: + return ( + cv.Schema( + {cv.GenerateID(const.CONF_OPENTHERM_ID): cv.use_id(generate.OpenthermHub)} + ) + .extend(create_entities_schema(entities, get_entity_validation_schema)) + .extend(cv.COMPONENT_SCHEMA) + ) diff --git a/tests/components/opentherm/common.yaml b/tests/components/opentherm/common.yaml index 4148b280d0..27cbae280a 100644 --- a/tests/components/opentherm/common.yaml +++ b/tests/components/opentherm/common.yaml @@ -1,3 +1,76 @@ +api: +wifi: + ap: + ssid: "Thermostat" + password: "MySecretThemostat" + opentherm: - in_pin: 1 - out_pin: 2 + in_pin: 4 + out_pin: 5 + ch_enable: true + dhw_enable: false + cooling_enable: false + otc_active: false + ch2_active: true + summer_mode_active: true + dhw_block: true + sync_mode: true + +sensor: + - platform: opentherm + rel_mod_level: + name: "Boiler Relative modulation level" + ch_pressure: + name: "Boiler Water pressure in CH circuit" + dhw_flow_rate: + name: "Boiler Water flow rate in DHW circuit" + t_boiler: + name: "Boiler water temperature" + t_dhw: + name: "Boiler DHW temperature" + t_outside: + name: "Boiler Outside temperature" + t_ret: + name: "Boiler Return water temperature" + t_storage: + name: "Boiler Solar storage temperature" + t_collector: + name: "Boiler Solar collector temperature" + t_flow_ch2: + name: "Boiler Flow water temperature CH2 circuit" + t_dhw2: + name: "Boiler Domestic hot water temperature 2" + t_exhaust: + name: "Boiler Exhaust temperature" + burner_starts: + name: "Boiler Number of starts burner" + ch_pump_starts: + name: "Boiler Number of starts CH pump" + dhw_pump_valve_starts: + name: "Boiler Number of starts DHW pump/valve" + dhw_burner_starts: + name: "Boiler Number of starts burner during DHW mode" + burner_operation_hours: + name: "Boiler Number of hours that burner is in operation (i.e. flame on)" + ch_pump_operation_hours: + name: "Boiler Number of hours that CH pump has been running" + dhw_pump_valve_operation_hours: + name: "Boiler Number of hours that DHW pump has been running or DHW valve has been opened" + dhw_burner_operation_hours: + name: "Boiler Number of hours that burner is in operation during DHW mode" + t_dhw_set_ub: + name: "Boiler Upper bound for adjustement of DHW setpoint" + t_dhw_set_lb: + name: "Boiler Lower bound for adjustement of DHW setpoint" + max_t_set_ub: + name: "Boiler Upper bound for adjustement of max CH setpoint" + max_t_set_lb: + name: "Boiler Lower bound for adjustement of max CH setpoint" + t_dhw_set: + name: "Boiler Domestic hot water temperature setpoint" + max_t_set: + name: "Boiler Maximum allowable CH water setpoint" + otc_hc_ratio_ub: + name: "OTC heat curve ratio upper bound" + otc_hc_ratio_lb: + name: "OTC heat curve ratio lower bound" From 34de2bbe992b842ad8017daa94ba6500ffb26d1c Mon Sep 17 00:00:00 2001 From: SeByDocKy Date: Sat, 26 Oct 2024 23:54:57 +0200 Subject: [PATCH 2573/2607] gp8403 : Add the possibility to use substitution for channel selection (#7681) --- esphome/components/gp8403/output/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/gp8403/output/__init__.py b/esphome/components/gp8403/output/__init__.py index 1cf95ac6e5..7f17faa1b1 100644 --- a/esphome/components/gp8403/output/__init__.py +++ b/esphome/components/gp8403/output/__init__.py @@ -16,7 +16,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(GP8403Output), cv.GenerateID(CONF_GP8403_ID): cv.use_id(GP8403), - cv.Required(CONF_CHANNEL): cv.one_of(0, 1), + cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=1), } ).extend(cv.COMPONENT_SCHEMA) From 1e2497748d3a18847df868ac8f4b893800426652 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:17:09 +1100 Subject: [PATCH 2574/2607] [rpi_dpi_rgb] Fix get_width and height (Bugfix) (#7675) Co-authored-by: clydeps --- .../components/rpi_dpi_rgb/rpi_dpi_rgb.cpp | 20 +++++++++++++++++++ esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp index 655b469b91..ba09171649 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp @@ -84,6 +84,26 @@ void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uin ESP_LOGE(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err)); } +int RpiDpiRgb::get_width() { + switch (this->rotation_) { + case display::DISPLAY_ROTATION_90_DEGREES: + case display::DISPLAY_ROTATION_270_DEGREES: + return this->get_height_internal(); + default: + return this->get_width_internal(); + } +} + +int RpiDpiRgb::get_height() { + switch (this->rotation_) { + case display::DISPLAY_ROTATION_90_DEGREES: + case display::DISPLAY_ROTATION_270_DEGREES: + return this->get_width_internal(); + default: + return this->get_height_internal(); + } +} + void RpiDpiRgb::draw_pixel_at(int x, int y, Color color) { if (!this->get_clipping().inside(x, y)) return; // NOLINT diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h index 10f77a2624..7525040cd1 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h @@ -24,6 +24,7 @@ class RpiDpiRgb : public display::Display { void update() override { this->do_update_(); } void setup() override; void loop() override; + float get_setup_priority() const override { return setup_priority::HARDWARE; } void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override; void draw_pixel_at(int x, int y, Color color) override; @@ -44,8 +45,8 @@ class RpiDpiRgb : public display::Display { this->width_ = width; this->height_ = height; } - int get_width() override { return this->width_; } - int get_height() override { return this->height_; } + int get_width() override; + int get_height() override; void set_hsync_back_porch(uint16_t hsync_back_porch) { this->hsync_back_porch_ = hsync_back_porch; } void set_hsync_front_porch(uint16_t hsync_front_porch) { this->hsync_front_porch_ = hsync_front_porch; } void set_hsync_pulse_width(uint16_t hsync_pulse_width) { this->hsync_pulse_width_ = hsync_pulse_width; } From 22f30d42a668e89b64318b1d8bf6c5cde38e2b21 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:05:51 +1100 Subject: [PATCH 2575/2607] [lvgl] Implement qrcode (#7623) --- esphome/components/lvgl/__init__.py | 2 + esphome/components/lvgl/widgets/qrcode.py | 54 +++++++++++++++++++++++ tests/components/lvgl/lvgl-package.yaml | 12 +++++ 3 files changed, 68 insertions(+) create mode 100644 esphome/components/lvgl/widgets/qrcode.py diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 215fdecdb5..4a1a26cc0b 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -71,6 +71,7 @@ from .widgets.meter import meter_spec from .widgets.msgbox import MSGBOX_SCHEMA, msgboxes_to_code from .widgets.obj import obj_spec from .widgets.page import add_pages, generate_page_triggers, page_spec +from .widgets.qrcode import qr_code_spec from .widgets.roller import roller_spec from .widgets.slider import slider_spec from .widgets.spinbox import spinbox_spec @@ -109,6 +110,7 @@ for w_type in ( spinbox_spec, keyboard_spec, tileview_spec, + qr_code_spec, ): WIDGET_TYPES[w_type.name] = w_type diff --git a/esphome/components/lvgl/widgets/qrcode.py b/esphome/components/lvgl/widgets/qrcode.py new file mode 100644 index 0000000000..742b538938 --- /dev/null +++ b/esphome/components/lvgl/widgets/qrcode.py @@ -0,0 +1,54 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_SIZE, CONF_TEXT +from esphome.cpp_generator import MockObjClass + +from ..defines import CONF_MAIN, literal +from ..lv_validation import color, color_retmapper, lv_text +from ..lvcode import LocalVariable, lv, lv_expr +from ..schemas import TEXT_SCHEMA +from ..types import WidgetType, lv_obj_t +from . import Widget + +CONF_QRCODE = "qrcode" +CONF_DARK_COLOR = "dark_color" +CONF_LIGHT_COLOR = "light_color" + +QRCODE_SCHEMA = TEXT_SCHEMA.extend( + { + cv.Optional(CONF_DARK_COLOR, default="black"): color, + cv.Optional(CONF_LIGHT_COLOR, default="white"): color, + cv.Required(CONF_SIZE): cv.int_, + } +) + + +class QrCodeType(WidgetType): + def __init__(self): + super().__init__( + CONF_QRCODE, + lv_obj_t, + (CONF_MAIN,), + QRCODE_SCHEMA, + modify_schema=TEXT_SCHEMA, + ) + + def get_uses(self): + return ("canvas", "img") + + def obj_creator(self, parent: MockObjClass, config: dict): + dark_color = color_retmapper(config[CONF_DARK_COLOR]) + light_color = color_retmapper(config[CONF_LIGHT_COLOR]) + size = config[CONF_SIZE] + return lv_expr.call("qrcode_create", parent, size, dark_color, light_color) + + async def to_code(self, w: Widget, config): + if (value := config.get(CONF_TEXT)) is not None: + value = await lv_text.process(value) + with LocalVariable( + "qr_text", cg.const_char_ptr, value, modifier="" + ) as str_obj: + lv.qrcode_update(w.obj, str_obj, literal(f"strlen({str_obj})")) + + +qr_code_spec = QrCodeType() diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 4962a71596..9bfbb5fc95 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -458,6 +458,18 @@ lvgl: - id: page2 widgets: + - qrcode: + id: lv_qr + align: left_mid + size: 100 + light_color: whitesmoke + dark_color: steelblue + text: esphome.io + on_click: + lvgl.qrcode.update: + id: lv_qr + text: homeassistant.io + - slider: min_value: 0 max_value: 255 From 858d97ccefff68f92af1c8f722738424ff2db791 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:08:29 +1100 Subject: [PATCH 2576/2607] [bytebuffer] Rework ByteBuffer using templates (#7638) --- CODEOWNERS | 1 + esphome/components/bytebuffer/__init__.py | 5 + esphome/components/bytebuffer/bytebuffer.h | 421 ++++++++++++++++++ esphome/core/bytebuffer.cpp | 167 ------- esphome/core/bytebuffer.h | 144 ------ tests/components/bytebuffer/common.yaml | 161 +++++++ .../components/bytebuffer/test.esp32-ard.yaml | 1 + .../bytebuffer/test.esp32-c3-ard.yaml | 1 + .../bytebuffer/test.esp32-c3-idf.yaml | 1 + .../components/bytebuffer/test.esp32-idf.yaml | 1 + .../bytebuffer/test.esp8266-ard.yaml | 1 + tests/components/bytebuffer/test.host.yaml | 1 + .../bytebuffer/test.rp2040-ard.yaml | 1 + 13 files changed, 595 insertions(+), 311 deletions(-) create mode 100644 esphome/components/bytebuffer/__init__.py create mode 100644 esphome/components/bytebuffer/bytebuffer.h delete mode 100644 esphome/core/bytebuffer.cpp delete mode 100644 esphome/core/bytebuffer.h create mode 100644 tests/components/bytebuffer/common.yaml create mode 100644 tests/components/bytebuffer/test.esp32-ard.yaml create mode 100644 tests/components/bytebuffer/test.esp32-c3-ard.yaml create mode 100644 tests/components/bytebuffer/test.esp32-c3-idf.yaml create mode 100644 tests/components/bytebuffer/test.esp32-idf.yaml create mode 100644 tests/components/bytebuffer/test.esp8266-ard.yaml create mode 100644 tests/components/bytebuffer/test.host.yaml create mode 100644 tests/components/bytebuffer/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index f96e43d5b7..5eb1f863f2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -85,6 +85,7 @@ esphome/components/bmp581/* @kahrendt esphome/components/bp1658cj/* @Cossid esphome/components/bp5758d/* @Cossid esphome/components/button/* @esphome/core +esphome/components/bytebuffer/* @clydebarrow esphome/components/canbus/* @danielschramm @mvturnho esphome/components/cap1188/* @mreditor97 esphome/components/captive_portal/* @OttoWinter diff --git a/esphome/components/bytebuffer/__init__.py b/esphome/components/bytebuffer/__init__.py new file mode 100644 index 0000000000..3c7c695118 --- /dev/null +++ b/esphome/components/bytebuffer/__init__.py @@ -0,0 +1,5 @@ +CODEOWNERS = ["@clydebarrow"] + +# Allows bytebuffer to be configured in yaml, to allow use of the C++ api. + +CONFIG_SCHEMA = {} diff --git a/esphome/components/bytebuffer/bytebuffer.h b/esphome/components/bytebuffer/bytebuffer.h new file mode 100644 index 0000000000..030484ce32 --- /dev/null +++ b/esphome/components/bytebuffer/bytebuffer.h @@ -0,0 +1,421 @@ +#pragma once + +#include +#include +#include +#include +#include "esphome/core/helpers.h" + +namespace esphome { +namespace bytebuffer { + +enum Endian { LITTLE, BIG }; + +/** + * A class modelled on the Java ByteBuffer class. It wraps a vector of bytes and permits putting and getting + * items of various sizes, with an automatically incremented position. + * + * There are three variables maintained pointing into the buffer: + * + * capacity: the maximum amount of data that can be stored - set on construction and cannot be changed + * limit: the limit of the data currently available to get or put + * position: the current insert or extract position + * + * 0 <= position <= limit <= capacity + * + * In addition a mark can be set to the current position with mark(). A subsequent call to reset() will restore + * the position to the mark. + * + * The buffer can be marked to be little-endian (default) or big-endian. All subsequent operations will use that order. + * + * The flip() operation will reset the position to 0 and limit to the current position. This is useful for reading + * data from a buffer after it has been written. + * + * The code is defined here in the header file rather than in a .cpp file, so that it does not get compiled if not used. + * The templated functions ensure that only those typed functions actually used are compiled. The functions + * are implicitly inline-able which will aid performance. + */ +class ByteBuffer { + public: + // Default constructor (compatibility with TEMPLATABLE_VALUE) + // Creates a zero-length ByteBuffer which is little use to anybody. + ByteBuffer() : ByteBuffer(std::vector()) {} + + /** + * Create a new Bytebuffer with the given capacity + */ + ByteBuffer(size_t capacity, Endian endianness = LITTLE) + : data_(std::vector(capacity)), endianness_(endianness), limit_(capacity){}; + + // templated functions to implement putting and getting data of various types. There are two flavours of all + // functions - one that uses the position as the offset, and updates the position accordingly, and one that + // takes an explicit offset and does not update the position. + // Separate temnplates are provided for types that fit into 32 bits and those that are bigger. These delegate + // the actual put/get to common code based around those sizes. + // This reduces the code size and execution time for smaller types. A similar structure for e.g. 16 bits is unlikely + // to provide any further benefit given that all target platforms are native 32 bit. + + template + T get(typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + // integral types that fit into 32 bit + return static_cast(this->get_uint32_(sizeof(T))); + } + + template + T get(size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + return static_cast(this->get_uint32_(offset, sizeof(T))); + } + + template + void put(const T &value, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + this->put_uint32_(static_cast(value), sizeof(T)); + } + + template + void put(const T &value, size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + this->put_uint32_(static_cast(value), offset, sizeof(T)); + } + + // integral types that do not fit into 32 bit (basically only 64 bit types) + template + T get(typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + return static_cast(this->get_uint64_(sizeof(T))); + } + + template + T get(size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + return static_cast(this->get_uint64_(offset, sizeof(T))); + } + + template + void put(const T &value, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + this->put_uint64_(value, sizeof(T)); + } + + template + void put(const T &value, size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + this->put_uint64_(static_cast(value), offset, sizeof(T)); + } + + // floating point types. Caters for 32 and 64 bit floating point. + template + T get(typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint32_t)), T>::type * = 0) { + return bit_cast(this->get_uint32_(sizeof(T))); + } + + template + T get(typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + return bit_cast(this->get_uint64_(sizeof(T))); + } + + template + T get(size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint32_t)), T>::type * = 0) { + return bit_cast(this->get_uint32_(offset, sizeof(T))); + } + + template + T get(size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + return bit_cast(this->get_uint64_(offset, sizeof(T))); + } + template + void put(const T &value, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + this->put_uint32_(bit_cast(value), sizeof(T)); + } + + template + void put(const T &value, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + this->put_uint64_(bit_cast(value), sizeof(T)); + } + + template + void put(const T &value, size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) <= sizeof(uint32_t)), T>::type * = 0) { + this->put_uint32_(bit_cast(value), offset, sizeof(T)); + } + + template + void put(const T &value, size_t offset, typename std::enable_if::value, T>::type * = 0, + typename std::enable_if<(sizeof(T) == sizeof(uint64_t)), T>::type * = 0) { + this->put_uint64_(bit_cast(value), offset, sizeof(T)); + } + + template static ByteBuffer wrap(T value, Endian endianness = LITTLE) { + ByteBuffer buffer = ByteBuffer(sizeof(T), endianness); + buffer.put(value); + buffer.flip(); + return buffer; + } + + static ByteBuffer wrap(std::vector const &data, Endian endianness = LITTLE) { + ByteBuffer buffer = {data}; + buffer.endianness_ = endianness; + return buffer; + } + + static ByteBuffer wrap(const uint8_t *ptr, size_t len, Endian endianness = LITTLE) { + return wrap(std::vector(ptr, ptr + len), endianness); + } + + // convenience functions with explicit types named.. + void put_float(float value) { this->put(value); } + void put_double(double value) { this->put(value); } + + uint8_t get_uint8() { return this->data_[this->position_++]; } + // Get a 16 bit unsigned value, increment by 2 + uint16_t get_uint16() { return this->get(); } + // Get a 24 bit unsigned value, increment by 3 + uint32_t get_uint24() { return this->get_uint32_(3); }; + // Get a 32 bit unsigned value, increment by 4 + uint32_t get_uint32() { return this->get(); }; + // Get a 64 bit unsigned value, increment by 8 + uint64_t get_uint64() { return this->get(); }; + // Signed versions of the get functions + uint8_t get_int8() { return static_cast(this->get_uint8()); }; + int16_t get_int16() { return this->get(); } + int32_t get_int32() { return this->get(); } + int64_t get_int64() { return this->get(); } + // Get a float value, increment by 4 + float get_float() { return this->get(); } + // Get a double value, increment by 8 + double get_double() { return this->get(); } + + // Get a bool value, increment by 1 + bool get_bool() { return static_cast(this->get_uint8()); } + + uint32_t get_int24(size_t offset) { + auto value = this->get_uint24(offset); + uint32_t mask = (~static_cast(0)) << 23; + if ((value & mask) != 0) + value |= mask; + return value; + } + + uint32_t get_int24() { + auto value = this->get_uint24(); + uint32_t mask = (~static_cast(0)) << 23; + if ((value & mask) != 0) + value |= mask; + return value; + } + std::vector get_vector(size_t length, size_t offset) { + auto start = this->data_.begin() + offset; + return {start, start + length}; + } + + std::vector get_vector(size_t length) { + auto result = this->get_vector(length, this->position_); + this->position_ += length; + return result; + } + + // Convenience named functions + void put_uint8(uint8_t value) { this->data_[this->position_++] = value; } + void put_uint16(uint16_t value) { this->put(value); } + void put_uint24(uint32_t value) { this->put_uint32_(value, 3); } + void put_uint32(uint32_t value) { this->put(value); } + void put_uint64(uint64_t value) { this->put(value); } + // Signed versions of the put functions + void put_int8(int8_t value) { this->put_uint8(static_cast(value)); } + void put_int16(int16_t value) { this->put(value); } + void put_int24(int32_t value) { this->put_uint32_(value, 3); } + void put_int32(int32_t value) { this->put(value); } + void put_int64(int64_t value) { this->put(value); } + // Extra put functions + void put_bool(bool value) { this->put_uint8(value); } + + // versions of the above with an offset, these do not update the position + + uint64_t get_uint64(size_t offset) { return this->get(offset); } + uint32_t get_uint24(size_t offset) { return this->get_uint32_(offset, 3); }; + double get_double(size_t offset) { return get(offset); } + + // Get one byte from the buffer, increment position by 1 + uint8_t get_uint8(size_t offset) { return this->data_[offset]; } + // Get a 16 bit unsigned value, increment by 2 + uint16_t get_uint16(size_t offset) { return get(offset); } + // Get a 24 bit unsigned value, increment by 3 + uint32_t get_uint32(size_t offset) { return this->get(offset); }; + // Get a 64 bit unsigned value, increment by 8 + uint8_t get_int8(size_t offset) { return get(offset); } + int16_t get_int16(size_t offset) { return get(offset); } + int32_t get_int32(size_t offset) { return get(offset); } + int64_t get_int64(size_t offset) { return get(offset); } + // Get a float value, increment by 4 + float get_float(size_t offset) { return get(offset); } + // Get a double value, increment by 8 + + // Get a bool value, increment by 1 + bool get_bool(size_t offset) { return this->get_uint8(offset); } + + void put_uint8(uint8_t value, size_t offset) { this->data_[offset] = value; } + void put_uint16(uint16_t value, size_t offset) { this->put(value, offset); } + void put_uint24(uint32_t value, size_t offset) { this->put(value, offset); } + void put_uint32(uint32_t value, size_t offset) { this->put(value, offset); } + void put_uint64(uint64_t value, size_t offset) { this->put(value, offset); } + // Signed versions of the put functions + void put_int8(int8_t value, size_t offset) { this->put_uint8(static_cast(value), offset); } + void put_int16(int16_t value, size_t offset) { this->put(value, offset); } + void put_int24(int32_t value, size_t offset) { this->put_uint32_(value, offset, 3); } + void put_int32(int32_t value, size_t offset) { this->put(value, offset); } + void put_int64(int64_t value, size_t offset) { this->put(value, offset); } + // Extra put functions + void put_float(float value, size_t offset) { this->put(value, offset); } + void put_double(double value, size_t offset) { this->put(value, offset); } + void put_bool(bool value, size_t offset) { this->put_uint8(value, offset); } + void put(const std::vector &value, size_t offset) { + std::copy(value.begin(), value.end(), this->data_.begin() + offset); + } + void put_vector(const std::vector &value, size_t offset) { this->put(value, offset); } + void put(const std::vector &value) { + this->put_vector(value, this->position_); + this->position_ += value.size(); + } + void put_vector(const std::vector &value) { this->put(value); } + + // Getters + + inline size_t get_capacity() const { return this->data_.size(); } + inline size_t get_position() const { return this->position_; } + inline size_t get_limit() const { return this->limit_; } + inline size_t get_remaining() const { return this->get_limit() - this->get_position(); } + inline Endian get_endianness() const { return this->endianness_; } + inline void mark() { this->mark_ = this->position_; } + inline void big_endian() { this->endianness_ = BIG; } + inline void little_endian() { this->endianness_ = LITTLE; } + // retrieve a pointer to the underlying data. + std::vector get_data() { return this->data_; }; + + void get_bytes(void *dest, size_t length) { + std::copy(this->data_.begin() + this->position_, this->data_.begin() + this->position_ + length, (uint8_t *) dest); + this->position_ += length; + } + + void get_bytes(void *dest, size_t length, size_t offset) { + std::copy(this->data_.begin() + offset, this->data_.begin() + offset + length, (uint8_t *) dest); + } + + void rewind() { this->position_ = 0; } + void reset() { this->position_ = this->mark_; } + + void set_limit(size_t limit) { this->limit_ = limit; } + void set_position(size_t position) { this->position_ = position; } + void clear() { + this->limit_ = this->get_capacity(); + this->position_ = 0; + } + void flip() { + this->limit_ = this->position_; + this->position_ = 0; + } + + protected: + uint64_t get_uint64_(size_t offset, size_t length) const { + uint64_t value = 0; + if (this->endianness_ == LITTLE) { + offset += length; + while (length-- != 0) { + value <<= 8; + value |= this->data_[--offset]; + } + } else { + while (length-- != 0) { + value <<= 8; + value |= this->data_[offset++]; + } + } + return value; + } + + uint64_t get_uint64_(size_t length) { + auto result = this->get_uint64_(this->position_, length); + this->position_ += length; + return result; + } + uint32_t get_uint32_(size_t offset, size_t length) const { + uint32_t value = 0; + if (this->endianness_ == LITTLE) { + offset += length; + while (length-- != 0) { + value <<= 8; + value |= this->data_[--offset]; + } + } else { + while (length-- != 0) { + value <<= 8; + value |= this->data_[offset++]; + } + } + return value; + } + + uint32_t get_uint32_(size_t length) { + auto result = this->get_uint32_(this->position_, length); + this->position_ += length; + return result; + } + + /// Putters + + void put_uint64_(uint64_t value, size_t length) { + this->put_uint64_(value, this->position_, length); + this->position_ += length; + } + void put_uint32_(uint32_t value, size_t length) { + this->put_uint32_(value, this->position_, length); + this->position_ += length; + } + + void put_uint64_(uint64_t value, size_t offset, size_t length) { + if (this->endianness_ == LITTLE) { + while (length-- != 0) { + this->data_[offset++] = static_cast(value); + value >>= 8; + } + } else { + offset += length; + while (length-- != 0) { + this->data_[--offset] = static_cast(value); + value >>= 8; + } + } + } + + void put_uint32_(uint32_t value, size_t offset, size_t length) { + if (this->endianness_ == LITTLE) { + while (length-- != 0) { + this->data_[offset++] = static_cast(value); + value >>= 8; + } + } else { + offset += length; + while (length-- != 0) { + this->data_[--offset] = static_cast(value); + value >>= 8; + } + } + } + ByteBuffer(std::vector const &data) : data_(data), limit_(data.size()) {} + + std::vector data_; + Endian endianness_{LITTLE}; + size_t position_{0}; + size_t mark_{0}; + size_t limit_{0}; +}; + +} // namespace bytebuffer +} // namespace esphome diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp deleted file mode 100644 index 9dd32bf87a..0000000000 --- a/esphome/core/bytebuffer.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "bytebuffer.h" -#include -#include "esphome/core/helpers.h" - -#include -#include - -namespace esphome { - -ByteBuffer ByteBuffer::wrap(const uint8_t *ptr, size_t len, Endian endianness) { - // there is a double copy happening here, could be optimized but at cost of clarity. - std::vector data(ptr, ptr + len); - ByteBuffer buffer = {data}; - buffer.endianness_ = endianness; - return buffer; -} - -ByteBuffer ByteBuffer::wrap(std::vector const &data, Endian endianness) { - ByteBuffer buffer = {data}; - buffer.endianness_ = endianness; - return buffer; -} - -ByteBuffer ByteBuffer::wrap(uint8_t value) { - ByteBuffer buffer = ByteBuffer(1); - buffer.put_uint8(value); - buffer.flip(); - return buffer; -} - -ByteBuffer ByteBuffer::wrap(uint16_t value, Endian endianness) { - ByteBuffer buffer = ByteBuffer(2, endianness); - buffer.put_uint16(value); - buffer.flip(); - return buffer; -} - -ByteBuffer ByteBuffer::wrap(uint32_t value, Endian endianness) { - ByteBuffer buffer = ByteBuffer(4, endianness); - buffer.put_uint32(value); - buffer.flip(); - return buffer; -} - -ByteBuffer ByteBuffer::wrap(uint64_t value, Endian endianness) { - ByteBuffer buffer = ByteBuffer(8, endianness); - buffer.put_uint64(value); - buffer.flip(); - return buffer; -} - -ByteBuffer ByteBuffer::wrap(float value, Endian endianness) { - ByteBuffer buffer = ByteBuffer(sizeof(float), endianness); - buffer.put_float(value); - buffer.flip(); - return buffer; -} - -ByteBuffer ByteBuffer::wrap(double value, Endian endianness) { - ByteBuffer buffer = ByteBuffer(sizeof(double), endianness); - buffer.put_double(value); - buffer.flip(); - return buffer; -} - -void ByteBuffer::set_limit(size_t limit) { - assert(limit <= this->get_capacity()); - this->limit_ = limit; -} -void ByteBuffer::set_position(size_t position) { - assert(position <= this->get_limit()); - this->position_ = position; -} -void ByteBuffer::clear() { - this->limit_ = this->get_capacity(); - this->position_ = 0; -} -void ByteBuffer::flip() { - this->limit_ = this->position_; - this->position_ = 0; -} - -/// Getters -uint8_t ByteBuffer::get_uint8() { - assert(this->get_remaining() >= 1); - return this->data_[this->position_++]; -} -uint64_t ByteBuffer::get_uint(size_t length) { - assert(this->get_remaining() >= length); - uint64_t value = 0; - if (this->endianness_ == LITTLE) { - this->position_ += length; - auto index = this->position_; - while (length-- != 0) { - value <<= 8; - value |= this->data_[--index]; - } - } else { - while (length-- != 0) { - value <<= 8; - value |= this->data_[this->position_++]; - } - } - return value; -} - -uint32_t ByteBuffer::get_int24() { - auto value = this->get_uint24(); - uint32_t mask = (~static_cast(0)) << 23; - if ((value & mask) != 0) - value |= mask; - return value; -} -float ByteBuffer::get_float() { - assert(this->get_remaining() >= sizeof(float)); - return bit_cast(this->get_uint32()); -} -double ByteBuffer::get_double() { - assert(this->get_remaining() >= sizeof(double)); - return bit_cast(this->get_uint64()); -} - -std::vector ByteBuffer::get_vector(size_t length) { - assert(this->get_remaining() >= length); - auto start = this->data_.begin() + this->position_; - this->position_ += length; - return {start, start + length}; -} - -/// Putters -void ByteBuffer::put_uint8(uint8_t value) { - assert(this->get_remaining() >= 1); - this->data_[this->position_++] = value; -} - -void ByteBuffer::put_uint(uint64_t value, size_t length) { - assert(this->get_remaining() >= length); - if (this->endianness_ == LITTLE) { - while (length-- != 0) { - this->data_[this->position_++] = static_cast(value); - value >>= 8; - } - } else { - this->position_ += length; - auto index = this->position_; - while (length-- != 0) { - this->data_[--index] = static_cast(value); - value >>= 8; - } - } -} -void ByteBuffer::put_float(float value) { - static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); - assert(this->get_remaining() >= sizeof(float)); - this->put_uint32(bit_cast(value)); -} -void ByteBuffer::put_double(double value) { - static_assert(sizeof(double) == sizeof(uint64_t), "Double sizes other than 64 bit not supported"); - assert(this->get_remaining() >= sizeof(double)); - this->put_uint64(bit_cast(value)); -} -void ByteBuffer::put_vector(const std::vector &value) { - assert(this->get_remaining() >= value.size()); - std::copy(value.begin(), value.end(), this->data_.begin() + this->position_); - this->position_ += value.size(); -} -} // namespace esphome diff --git a/esphome/core/bytebuffer.h b/esphome/core/bytebuffer.h deleted file mode 100644 index d44d01f275..0000000000 --- a/esphome/core/bytebuffer.h +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace esphome { - -enum Endian { LITTLE, BIG }; - -/** - * A class modelled on the Java ByteBuffer class. It wraps a vector of bytes and permits putting and getting - * items of various sizes, with an automatically incremented position. - * - * There are three variables maintained pointing into the buffer: - * - * capacity: the maximum amount of data that can be stored - set on construction and cannot be changed - * limit: the limit of the data currently available to get or put - * position: the current insert or extract position - * - * 0 <= position <= limit <= capacity - * - * In addition a mark can be set to the current position with mark(). A subsequent call to reset() will restore - * the position to the mark. - * - * The buffer can be marked to be little-endian (default) or big-endian. All subsequent operations will use that order. - * - * The flip() operation will reset the position to 0 and limit to the current position. This is useful for reading - * data from a buffer after it has been written. - * - */ -class ByteBuffer { - public: - // Default constructor (compatibility with TEMPLATABLE_VALUE) - ByteBuffer() : ByteBuffer(std::vector()) {} - /** - * Create a new Bytebuffer with the given capacity - */ - ByteBuffer(size_t capacity, Endian endianness = LITTLE) - : data_(std::vector(capacity)), endianness_(endianness), limit_(capacity){}; - /** - * Wrap an existing vector in a ByteBufffer - */ - static ByteBuffer wrap(std::vector const &data, Endian endianness = LITTLE); - /** - * Wrap an existing array in a ByteBuffer. Note that this will create a copy of the data. - */ - static ByteBuffer wrap(const uint8_t *ptr, size_t len, Endian endianness = LITTLE); - // Convenience functions to create a ByteBuffer from a value - static ByteBuffer wrap(uint8_t value); - static ByteBuffer wrap(uint16_t value, Endian endianness = LITTLE); - static ByteBuffer wrap(uint32_t value, Endian endianness = LITTLE); - static ByteBuffer wrap(uint64_t value, Endian endianness = LITTLE); - static ByteBuffer wrap(int8_t value) { return wrap(static_cast(value)); } - static ByteBuffer wrap(int16_t value, Endian endianness = LITTLE) { - return wrap(static_cast(value), endianness); - } - static ByteBuffer wrap(int32_t value, Endian endianness = LITTLE) { - return wrap(static_cast(value), endianness); - } - static ByteBuffer wrap(int64_t value, Endian endianness = LITTLE) { - return wrap(static_cast(value), endianness); - } - static ByteBuffer wrap(float value, Endian endianness = LITTLE); - static ByteBuffer wrap(double value, Endian endianness = LITTLE); - static ByteBuffer wrap(bool value) { return wrap(static_cast(value)); } - - // Get an integral value from the buffer, increment position by length - uint64_t get_uint(size_t length); - // Get one byte from the buffer, increment position by 1 - uint8_t get_uint8(); - // Get a 16 bit unsigned value, increment by 2 - uint16_t get_uint16() { return static_cast(this->get_uint(sizeof(uint16_t))); }; - // Get a 24 bit unsigned value, increment by 3 - uint32_t get_uint24() { return static_cast(this->get_uint(3)); }; - // Get a 32 bit unsigned value, increment by 4 - uint32_t get_uint32() { return static_cast(this->get_uint(sizeof(uint32_t))); }; - // Get a 64 bit unsigned value, increment by 8 - uint64_t get_uint64() { return this->get_uint(sizeof(uint64_t)); }; - // Signed versions of the get functions - uint8_t get_int8() { return static_cast(this->get_uint8()); }; - int16_t get_int16() { return static_cast(this->get_uint(sizeof(int16_t))); } - uint32_t get_int24(); - int32_t get_int32() { return static_cast(this->get_uint(sizeof(int32_t))); } - int64_t get_int64() { return static_cast(this->get_uint(sizeof(int64_t))); } - // Get a float value, increment by 4 - float get_float(); - // Get a double value, increment by 8 - double get_double(); - // Get a bool value, increment by 1 - bool get_bool() { return this->get_uint8(); } - // Get vector of bytes, increment by length - std::vector get_vector(size_t length); - - // Put values into the buffer, increment the position accordingly - // put any integral value, length represents the number of bytes - void put_uint(uint64_t value, size_t length); - void put_uint8(uint8_t value); - void put_uint16(uint16_t value) { this->put_uint(value, sizeof(uint16_t)); } - void put_uint24(uint32_t value) { this->put_uint(value, 3); } - void put_uint32(uint32_t value) { this->put_uint(value, sizeof(uint32_t)); } - void put_uint64(uint64_t value) { this->put_uint(value, sizeof(uint64_t)); } - // Signed versions of the put functions - void put_int8(int8_t value) { this->put_uint8(static_cast(value)); } - void put_int16(int32_t value) { this->put_uint(static_cast(value), sizeof(uint16_t)); } - void put_int24(int32_t value) { this->put_uint(static_cast(value), 3); } - void put_int32(int32_t value) { this->put_uint(static_cast(value), sizeof(uint32_t)); } - void put_int64(int64_t value) { this->put_uint(static_cast(value), sizeof(uint64_t)); } - // Extra put functions - void put_float(float value); - void put_double(double value); - void put_bool(bool value) { this->put_uint8(value); } - void put_vector(const std::vector &value); - - inline size_t get_capacity() const { return this->data_.size(); } - inline size_t get_position() const { return this->position_; } - inline size_t get_limit() const { return this->limit_; } - inline size_t get_remaining() const { return this->get_limit() - this->get_position(); } - inline Endian get_endianness() const { return this->endianness_; } - inline void mark() { this->mark_ = this->position_; } - inline void big_endian() { this->endianness_ = BIG; } - inline void little_endian() { this->endianness_ = LITTLE; } - void set_limit(size_t limit); - void set_position(size_t position); - // set position to 0, limit to capacity. - void clear(); - // set limit to current position, postition to zero. Used when swapping from write to read operations. - void flip(); - // retrieve a pointer to the underlying data. - std::vector get_data() { return this->data_; }; - void rewind() { this->position_ = 0; } - void reset() { this->position_ = this->mark_; } - - protected: - ByteBuffer(std::vector const &data) : data_(data), limit_(data.size()) {} - std::vector data_; - Endian endianness_{LITTLE}; - size_t position_{0}; - size_t mark_{0}; - size_t limit_{0}; -}; - -} // namespace esphome diff --git a/tests/components/bytebuffer/common.yaml b/tests/components/bytebuffer/common.yaml new file mode 100644 index 0000000000..177f487e1e --- /dev/null +++ b/tests/components/bytebuffer/common.yaml @@ -0,0 +1,161 @@ +bytebuffer: + +esphome: + on_boot: + - lambda: |- + using namespace bytebuffer; + auto buf = ByteBuffer(16); + assert(buf.get_endianness() == LITTLE); + assert(buf.get_remaining() == 16); + buf.set_limit(10); + assert(buf.get_capacity() == 16); + buf.put_uint8(1); + assert(buf.get_remaining() == 9); + buf.put_uint16(0xABCD); + auto da = buf.get_data(); + assert(buf.get_uint8(0) == 1); + auto x = buf.get_uint16(1); + assert(buf.get_uint16(1) == 0xABCD); + assert(buf.get_remaining() == 7); + buf.put_uint32(0x12345678UL); + assert(buf.get_uint32(3) == 0x12345678UL); + assert(buf.get_remaining() == 3); + assert(buf.get_data()[1] == 0xCD); + assert(buf.get_data()[2] == 0xAB); + assert(buf.get_data()[3] == 0x78); + assert(buf.get_data()[4] == 0x56); + assert(buf.get_data()[5] == 0x34); + assert(buf.get_data()[6] == 0x12); + buf.flip(); + assert(buf.get_capacity() == 16); + assert(buf.get_uint32(3) == 0x12345678UL); + assert(buf.get_uint8(0) == 1); + assert(buf.get_uint16(1) == 0xABCD); + buf.put_uint16(0x1234, 1); + assert(buf.get_uint16(1) == 0x1234); + assert(buf.get_remaining() == 7); + assert(buf.get_uint8() == 1); + assert(buf.get_uint16() == 0x1234); + assert(buf.get_uint32() == 0x12345678ul); + assert(buf.get_remaining() == 0); + assert(buf.get_remaining() == 0); + buf.rewind(); + buf.big_endian(); + assert(buf.get_remaining() == 7); + assert(buf.get_uint8() == 1); + assert(buf.get_uint16() == 0x3412); + buf.mark(); + assert(buf.get_uint32() == 0x78563412ul); + assert(buf.get_remaining() == 0); + buf.reset(); + assert(buf.get_remaining() == 4); + assert(buf.get_uint32() == 0x78563412ul); + auto buf1 = ByteBuffer::wrap(buf.get_data().data(), buf.get_limit()); + buf.clear(); + assert(buf.get_position() == 0); + assert(buf.get_capacity() == 16); + assert(buf.get_limit() == 16); + assert(buf1.get_remaining() == 7); + assert(buf1.get_capacity() == 7); + buf1.set_position(3); + assert(buf1.get_uint32() == 0x12345678ul); + buf1.clear(); + assert(buf1.get_limit() == 7); + assert(buf1.get_capacity() == 7); + assert(buf1.get_position() == 0); + float f = 1.2345; + buf1.put_float(f); + buf1.flip(); + assert(buf1.get_remaining() == 4); + assert(buf1.get_float() == f); + buf1.clear(); + buf1.put_uint16(-32760); + buf1.put_uint24(-302760); + buf1.flip(); + assert(buf1.get_int16() == -32760); + assert(buf1.get_int24() == -302760); + uint8_t arr[4] = {0x10, 0x20, 0x30, 0x40}; + buf1 = ByteBuffer::wrap(arr, 4); + assert(buf1.get_capacity() == 4); + assert(buf1.get_limit() == 4); + assert(buf1.get_position() == 0); + assert(buf1.get_uint32() == 0x40302010UL); + assert(buf1.get_position() == 4); + assert(buf1.get_remaining() == 0); + std::vector vec{}; + vec.push_back(0x10); + vec.push_back(0x20); + vec.push_back(0x30); + vec.push_back(0x40); + buf1 = ByteBuffer::wrap(vec); + assert(buf1.get_capacity() == 4); + assert(buf1.get_limit() == 4); + assert(buf1.get_position() == 0); + buf1.mark(); + buf1.reset(); + assert(buf1.get_uint32() == 0x40302010UL); + buf = ByteBuffer::wrap(true); + assert(buf.get_bool() == true); + buf = ByteBuffer::wrap((uint8_t)0xFE); + assert(buf.get_uint8() == 0xFE); + buf = ByteBuffer::wrap((uint16_t)0xA5A6, BIG); + assert(buf.get_remaining() == 2); + assert(buf.get_position() == 0); + assert(buf.get_capacity() == 2); + assert(buf.get_endianness() == BIG); + assert(buf.get_data()[0] == 0xA5); + assert(buf.get_uint16() == 0xA5A6); + buf.flip(); + buf.little_endian(); + assert(buf.get_uint16() == 0xA6A5); + buf = ByteBuffer::wrap(f, BIG); + assert(buf.get_float() == f); + double d = 1.2345678E7; + buf = ByteBuffer::wrap(d, BIG); + assert(buf.get_double() == d); + buf = ByteBuffer::wrap({1, 2, 3, 4}, BIG); + assert(buf.get_endianness() == BIG); + assert(buf.get_remaining() == 4); + assert(buf.get_data()[2] == 3); + buf.little_endian(); + assert(buf.get_data()[2] == 3); + assert(buf.get_uint16() == 0x0201); + buf.big_endian(); + assert(buf.get_uint16() == 0x0304); + buf.rewind(); + vec = buf.get_vector(3); + assert(buf.get_remaining() == 1); + assert(vec[0] == 1); + assert(vec.size() == 3); + buf = ByteBuffer(10); + buf.put_vector(vec); + assert(buf.get_remaining() == 7); + buf.flip(); + assert(buf.get_remaining() == 3); + assert(buf.get_uint24() == 0x030201); + buf = ByteBuffer(64); + buf.put_uint8(1, 1); + buf.put_uint16(16, 2); + buf.put_uint32(1232, 4); + buf.put_uint64(123432ul, 8); + buf.put_float(1.2f, 16); + buf.put_int24(0x678, 20); + + assert(buf.get_uint8(1) == 1); + assert(buf.get(1) == 1); + assert(buf.get_uint16(2) == 16); + assert(buf.get(2) == 16); + assert(buf.get_uint32(4) == 1232); + assert(buf.get(4) == 1232); + assert(buf.get_uint64(8) == 123432ul); + assert(buf.get(8) == 123432ul); + assert(buf.get_float(16) == 1.2f); + assert(buf.get(16) == 1.2f); + assert(buf.get_int24(20) == 0x678); + buf.clear(); + buf.put(1.234, 10); + double dx = buf.get(10); + assert(dx == 1.234); + buf.put((uint16_t)1, 10); + assert(buf.get_uint16(10) == 1); + ESP_LOGD("bytebuffer", "******************** All tests succeeded"); diff --git a/tests/components/bytebuffer/test.esp32-ard.yaml b/tests/components/bytebuffer/test.esp32-ard.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.esp32-ard.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.esp32-c3-ard.yaml b/tests/components/bytebuffer/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.esp32-c3-ard.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.esp32-c3-idf.yaml b/tests/components/bytebuffer/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.esp32-c3-idf.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.esp32-idf.yaml b/tests/components/bytebuffer/test.esp32-idf.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.esp32-idf.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.esp8266-ard.yaml b/tests/components/bytebuffer/test.esp8266-ard.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.esp8266-ard.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.host.yaml b/tests/components/bytebuffer/test.host.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.host.yaml @@ -0,0 +1 @@ +!include common.yaml diff --git a/tests/components/bytebuffer/test.rp2040-ard.yaml b/tests/components/bytebuffer/test.rp2040-ard.yaml new file mode 100644 index 0000000000..380ca87628 --- /dev/null +++ b/tests/components/bytebuffer/test.rp2040-ard.yaml @@ -0,0 +1 @@ +!include common.yaml From 88627095fbc049ca342325be22d72e66e9b9c28a Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:12:32 +1100 Subject: [PATCH 2577/2607] [http_request] Always return defined server response status (#7689) --- esphome/components/http_request/http_request_arduino.cpp | 3 +-- esphome/components/http_request/http_request_idf.cpp | 3 +-- esphome/components/http_request/ota/ota_http_request.cpp | 2 +- esphome/components/http_request/update/http_request_update.cpp | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index 2148d92ad2..f000082034 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -116,8 +116,7 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s if (container->status_code < 200 || container->status_code >= 300) { ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); this->status_momentary_error("failed", 1000); - container->end(); - return nullptr; + // Still return the container, so it can be used to get the status code and error message } int content_length = container->client_.getSize(); diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 3819f5544e..e47e1d488e 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -172,8 +172,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); this->status_momentary_error("failed", 1000); - esp_http_client_cleanup(client); - return nullptr; + return container; } int HttpContainerIDF::read(uint8_t *buf, size_t max_len) { diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index 1553de0bc1..f7c941da18 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -106,7 +106,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { auto container = this->parent_->get(url_with_auth); - if (container == nullptr) { + if (container == nullptr || container->status_code != 200) { return OTA_CONNECTION_ERROR; } diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index 059148e7e5..4d913f2158 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -31,7 +31,7 @@ void HttpRequestUpdate::setup() { void HttpRequestUpdate::update() { auto container = this->request_parent_->get(this->source_url_); - if (container == nullptr) { + if (container == nullptr || container->status_code != 200) { std::string msg = str_sprintf("Failed to fetch manifest from %s", this->source_url_.c_str()); this->status_set_error(msg.c_str()); return; From 63e4d4b493ec6c704ac6d41273b4190614726578 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:56:32 +1100 Subject: [PATCH 2578/2607] [font] Fix failure with bitmap fonts (#7691) --- esphome/components/font/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index dacd0779b1..a3f11df50e 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -344,7 +344,7 @@ class TrueTypeFontWrapper: return offset_x, offset_y def getmask(self, glyph, **kwargs): - return self.font.getmask(glyph, **kwargs) + return self.font.getmask(str(glyph), **kwargs) def getmetrics(self, glyphs): return self.font.getmetrics() @@ -359,7 +359,7 @@ class BitmapFontWrapper: return 0, 0 def getmask(self, glyph, **kwargs): - return self.font.getmask(glyph, **kwargs) + return self.font.getmask(str(glyph), **kwargs) def getmetrics(self, glyphs): max_height = 0 From df750d0d11ce31e793de06d0e00663c8e23a3680 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:05:58 +1100 Subject: [PATCH 2579/2607] [http_request] Add enum for status codes (#7690) --- .../components/http_request/http_request.h | 57 +++++++++++++++++++ .../http_request/http_request_arduino.cpp | 2 +- .../http_request/http_request_idf.cpp | 17 ++---- .../http_request/ota/ota_http_request.cpp | 2 +- .../update/http_request_update.cpp | 2 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index c01baf8644..d87d9b8a45 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -22,6 +22,63 @@ struct Header { const char *value; }; +// Some common HTTP status codes +enum HttpStatus { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + HTTP_STATUS_PARTIAL_CONTENT = 206, + + /* 3xx - Redirection */ + HTTP_STATUS_MULTIPLE_CHOICES = 300, + HTTP_STATUS_MOVED_PERMANENTLY = 301, + HTTP_STATUS_FOUND = 302, + HTTP_STATUS_SEE_OTHER = 303, + HTTP_STATUS_NOT_MODIFIED = 304, + HTTP_STATUS_TEMPORARY_REDIRECT = 307, + HTTP_STATUS_PERMANENT_REDIRECT = 308, + + /* 4XX - CLIENT ERROR */ + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED = 401, + HTTP_STATUS_FORBIDDEN = 403, + HTTP_STATUS_NOT_FOUND = 404, + HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + HTTP_STATUS_NOT_ACCEPTABLE = 406, + HTTP_STATUS_LENGTH_REQUIRED = 411, + + /* 5xx - Server Error */ + HTTP_STATUS_INTERNAL_ERROR = 500 +}; + +/** + * @brief Returns true if the HTTP status code is a redirect. + * + * @param status the HTTP status code to check + * @return true if the status code is a redirect, false otherwise + */ +inline bool is_redirect(int const status) { + switch (status) { + case HTTP_STATUS_MOVED_PERMANENTLY: + case HTTP_STATUS_FOUND: + case HTTP_STATUS_SEE_OTHER: + case HTTP_STATUS_TEMPORARY_REDIRECT: + case HTTP_STATUS_PERMANENT_REDIRECT: + return true; + default: + return false; + } +} + +/** + * @brief Checks if the given HTTP status code indicates a successful request. + * + * A successful request is one where the status code is in the range 200-299 + * + * @param status the HTTP status code to check + * @return true if the status code indicates a successful request, false otherwise + */ +inline bool is_success(int const status) { return status >= HTTP_STATUS_OK && status < HTTP_STATUS_MULTIPLE_CHOICES; } + class HttpRequestComponent; class HttpContainer : public Parented { diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index f000082034..af1eb6f459 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -113,7 +113,7 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s return nullptr; } - if (container->status_code < 200 || container->status_code >= 300) { + if (!is_success(container->status_code)) { ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code); this->status_momentary_error("failed", 1000); // Still return the container, so it can be used to get the status code and error message diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index e47e1d488e..c6c567b620 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -6,7 +6,6 @@ #include "esphome/components/watchdog/watchdog.h" #include "esphome/core/application.h" -#include "esphome/core/defines.h" #include "esphome/core/log.h" #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE @@ -118,20 +117,14 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } - auto is_ok = [](int code) { return code >= HttpStatus_Ok && code < HttpStatus_MultipleChoices; }; - container->content_length = esp_http_client_fetch_headers(client); container->status_code = esp_http_client_get_status_code(client); - if (is_ok(container->status_code)) { + if (is_success(container->status_code)) { container->duration_ms = millis() - start; return container; } if (this->follow_redirects_) { - auto is_redirect = [](int code) { - return code == HttpStatus_MovedPermanently || code == HttpStatus_Found || code == HttpStatus_SeeOther || - code == HttpStatus_TemporaryRedirect || code == HttpStatus_PermanentRedirect; - }; auto num_redirects = this->redirect_limit_; while (is_redirect(container->status_code) && num_redirects > 0) { err = esp_http_client_set_redirection(client); @@ -142,9 +135,9 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE - char url[256]{}; - if (esp_http_client_get_url(client, url, sizeof(url) - 1) == ESP_OK) { - ESP_LOGV(TAG, "redirecting to url: %s", url); + char redirect_url[256]{}; + if (esp_http_client_get_url(client, redirect_url, sizeof(redirect_url) - 1) == ESP_OK) { + ESP_LOGV(TAG, "redirecting to url: %s", redirect_url); } #endif err = esp_http_client_open(client, 0); @@ -157,7 +150,7 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin container->content_length = esp_http_client_fetch_headers(client); container->status_code = esp_http_client_get_status_code(client); - if (is_ok(container->status_code)) { + if (is_success(container->status_code)) { container->duration_ms = millis() - start; return container; } diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index f7c941da18..cec30d72ec 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -106,7 +106,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { auto container = this->parent_->get(url_with_auth); - if (container == nullptr || container->status_code != 200) { + if (container == nullptr || container->status_code != HTTP_STATUS_OK) { return OTA_CONNECTION_ERROR; } diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index 4d913f2158..0e0966c22b 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -31,7 +31,7 @@ void HttpRequestUpdate::setup() { void HttpRequestUpdate::update() { auto container = this->request_parent_->get(this->source_url_); - if (container == nullptr || container->status_code != 200) { + if (container == nullptr || container->status_code != HTTP_STATUS_OK) { std::string msg = str_sprintf("Failed to fetch manifest from %s", this->source_url_.c_str()); this->status_set_error(msg.c_str()); return; From 302ba2874e12960c76a624fa6066bf5df1ffac2e Mon Sep 17 00:00:00 2001 From: Satoshi YAMADA Date: Tue, 29 Oct 2024 12:08:08 +0900 Subject: [PATCH 2580/2607] Support W5500 SPI-Ethernet polling mode if framework is supported (#7503) --- esphome/components/ethernet/__init__.py | 56 ++++++++++++++++++- .../ethernet/ethernet_component.cpp | 15 ++++- .../components/ethernet/ethernet_component.h | 8 ++- esphome/const.py | 1 + 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 475d60df53..dca37b8dc2 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -1,3 +1,4 @@ +import logging from esphome import pins import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant @@ -23,6 +24,7 @@ from esphome.const import ( CONF_MISO_PIN, CONF_MOSI_PIN, CONF_PAGE_ID, + CONF_POLLING_INTERVAL, CONF_RESET_PIN, CONF_SPI, CONF_STATIC_IP, @@ -30,13 +32,16 @@ from esphome.const import ( CONF_TYPE, CONF_USE_ADDRESS, CONF_VALUE, + KEY_CORE, + KEY_FRAMEWORK_VERSION, ) -from esphome.core import CORE, coroutine_with_priority +from esphome.core import CORE, TimePeriodMilliseconds, coroutine_with_priority import esphome.final_validate as fv CONFLICTS_WITH = ["wifi"] DEPENDENCIES = ["esp32"] AUTO_LOAD = ["network"] +LOGGER = logging.getLogger(__name__) ethernet_ns = cg.esphome_ns.namespace("ethernet") PHYRegister = ethernet_ns.struct("PHYRegister") @@ -63,6 +68,7 @@ ETHERNET_TYPES = { } SPI_ETHERNET_TYPES = ["W5500"] +SPI_ETHERNET_DEFAULT_POLLING_INTERVAL = TimePeriodMilliseconds(milliseconds=10) emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") emac_rmii_clock_gpio_t = cg.global_ns.enum("emac_rmii_clock_gpio_t") @@ -100,6 +106,24 @@ EthernetComponent = ethernet_ns.class_("EthernetComponent", cg.Component) ManualIP = ethernet_ns.struct("ManualIP") +def _is_framework_spi_polling_mode_supported(): + # SPI Ethernet without IRQ feature is added in + # esp-idf >= (5.3+ ,5.2.1+, 5.1.4) and arduino-esp32 >= 3.0.0 + framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] + if CORE.using_esp_idf: + if framework_version >= cv.Version(5, 3, 0): + return True + if cv.Version(5, 3, 0) > framework_version >= cv.Version(5, 2, 1): + return True + if cv.Version(5, 2, 0) > framework_version >= cv.Version(5, 1, 4): + return True + return False + if CORE.using_arduino: + return framework_version >= cv.Version(3, 0, 0) + # fail safe: Unknown framework + return False + + def _validate(config): if CONF_USE_ADDRESS not in config: if CONF_MANUAL_IP in config: @@ -107,6 +131,27 @@ def _validate(config): else: use_address = CORE.name + config[CONF_DOMAIN] config[CONF_USE_ADDRESS] = use_address + if config[CONF_TYPE] in SPI_ETHERNET_TYPES: + if _is_framework_spi_polling_mode_supported(): + if CONF_POLLING_INTERVAL in config and CONF_INTERRUPT_PIN in config: + raise cv.Invalid( + f"Cannot specify more than one of {CONF_INTERRUPT_PIN}, {CONF_POLLING_INTERVAL}" + ) + if CONF_POLLING_INTERVAL not in config and CONF_INTERRUPT_PIN not in config: + config[CONF_POLLING_INTERVAL] = SPI_ETHERNET_DEFAULT_POLLING_INTERVAL + else: + if CONF_POLLING_INTERVAL in config: + raise cv.Invalid( + "In this version of the framework " + f"({CORE.target_framework} {CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]}), " + f"'{CONF_POLLING_INTERVAL}' is not supported." + ) + if CONF_INTERRUPT_PIN not in config: + raise cv.Invalid( + "In this version of the framework " + f"({CORE.target_framework} {CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]}), " + f"'{CONF_INTERRUPT_PIN}' is a required option for [ethernet]." + ) return config @@ -157,6 +202,11 @@ SPI_SCHEMA = BASE_SCHEMA.extend( cv.Optional(CONF_CLOCK_SPEED, default="26.67MHz"): cv.All( cv.frequency, cv.int_range(int(8e6), int(80e6)) ), + # Set default value (SPI_ETHERNET_DEFAULT_POLLING_INTERVAL) at _validate() + cv.Optional(CONF_POLLING_INTERVAL): cv.All( + cv.positive_time_period_milliseconds, + cv.Range(min=TimePeriodMilliseconds(milliseconds=1)), + ), } ), ) @@ -234,6 +284,10 @@ async def to_code(config): cg.add(var.set_cs_pin(config[CONF_CS_PIN])) if CONF_INTERRUPT_PIN in config: cg.add(var.set_interrupt_pin(config[CONF_INTERRUPT_PIN])) + else: + cg.add(var.set_polling_interval(config[CONF_POLLING_INTERVAL])) + if _is_framework_spi_polling_mode_supported(): + cg.add_define("USE_ETHERNET_SPI_POLLING_SUPPORT") if CONF_RESET_PIN in config: cg.add(var.set_reset_pin(config[CONF_RESET_PIN])) cg.add(var.set_clock_speed(config[CONF_CLOCK_SPEED])) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 00c7ae4ab8..08f5fa6642 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -116,6 +116,9 @@ void EthernetComponent::setup() { eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); #endif w5500_config.int_gpio_num = this->interrupt_pin_; +#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT + w5500_config.poll_period_ms = this->polling_interval_; +#endif phy_config.phy_addr = this->phy_addr_spi_; phy_config.reset_gpio_num = this->reset_pin_; @@ -327,7 +330,14 @@ void EthernetComponent::dump_config() { ESP_LOGCONFIG(TAG, " MISO Pin: %u", this->miso_pin_); ESP_LOGCONFIG(TAG, " MOSI Pin: %u", this->mosi_pin_); ESP_LOGCONFIG(TAG, " CS Pin: %u", this->cs_pin_); - ESP_LOGCONFIG(TAG, " IRQ Pin: %u", this->interrupt_pin_); +#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT + if (this->polling_interval_ != 0) { + ESP_LOGCONFIG(TAG, " Polling Interval: %lu ms", this->polling_interval_); + } else +#endif + { + ESP_LOGCONFIG(TAG, " IRQ Pin: %d", this->interrupt_pin_); + } ESP_LOGCONFIG(TAG, " Reset Pin: %d", this->reset_pin_); ESP_LOGCONFIG(TAG, " Clock Speed: %d MHz", this->clock_speed_ / 1000000); #else @@ -536,6 +546,9 @@ void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; } void EthernetComponent::set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; } void EthernetComponent::set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; } void EthernetComponent::set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; } +#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT +void EthernetComponent::set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; } +#endif #else void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; } void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; } diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 5ee430c046..fb178431d5 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -67,6 +67,9 @@ class EthernetComponent : public Component { void set_interrupt_pin(uint8_t interrupt_pin); void set_reset_pin(uint8_t reset_pin); void set_clock_speed(int clock_speed); +#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT + void set_polling_interval(uint32_t polling_interval); +#endif #else void set_phy_addr(uint8_t phy_addr); void set_power_pin(int power_pin); @@ -108,10 +111,13 @@ class EthernetComponent : public Component { uint8_t miso_pin_; uint8_t mosi_pin_; uint8_t cs_pin_; - uint8_t interrupt_pin_; + int interrupt_pin_{-1}; int reset_pin_{-1}; int phy_addr_spi_{-1}; int clock_speed_; +#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT + uint32_t polling_interval_{0}; +#endif #else uint8_t phy_addr_{0}; int power_pin_{-1}; diff --git a/esphome/const.py b/esphome/const.py index 54ebb2815f..c39061631b 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -666,6 +666,7 @@ CONF_PMC_1_0 = "pmc_1_0" CONF_PMC_10_0 = "pmc_10_0" CONF_PMC_2_5 = "pmc_2_5" CONF_PMC_4_0 = "pmc_4_0" +CONF_POLLING_INTERVAL = "polling_interval" CONF_PORT = "port" CONF_POSITION = "position" CONF_POSITION_ACTION = "position_action" From 444c0fc67f4284e42e00ad61466febe999122690 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Mon, 28 Oct 2024 20:09:22 -0700 Subject: [PATCH 2581/2607] Add asdf to gitignore (and dockerignore) (#7686) --- .dockerignore | 3 +++ .gitignore | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.dockerignore b/.dockerignore index 9f14b98059..7998ff877f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -75,6 +75,9 @@ target/ # pyenv .python-version +# asdf +.tool-versions + # celery beat schedule file celerybeat-schedule diff --git a/.gitignore b/.gitignore index 79820249ac..ad38e26fdd 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,9 @@ cov.xml # pyenv .python-version +# asdf +.tool-versions + # Environments .env .venv From 90b076eccd67253fb9ce612251130a76039e549d Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Mon, 28 Oct 2024 20:43:02 -0700 Subject: [PATCH 2582/2607] Add more prometheus metrics (#7683) --- .../prometheus/prometheus_handler.cpp | 43 +++++++++++++++++++ .../prometheus/prometheus_handler.h | 7 +++ tests/components/prometheus/common.yaml | 14 ++++++ 3 files changed, 64 insertions(+) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index 3e9cf81e6e..63b3fdf53f 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -50,6 +50,12 @@ void PrometheusHandler::handleRequest(AsyncWebServerRequest *req) { this->lock_row_(stream, obj); #endif +#ifdef USE_TEXT_SENSOR + this->text_sensor_type_(stream); + for (auto *obj : App.get_text_sensors()) + this->text_sensor_row_(stream, obj); +#endif + req->send(stream); } @@ -349,6 +355,43 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) } #endif +// Type-specific implementation +#ifdef USE_TEXT_SENSOR +void PrometheusHandler::text_sensor_type_(AsyncResponseStream *stream) { + stream->print(F("#TYPE esphome_text_sensor_value gauge\n")); + stream->print(F("#TYPE esphome_text_sensor_failed gauge\n")); +} +void PrometheusHandler::text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj) { + if (obj->is_internal() && !this->include_internal_) + return; + if (obj->has_state()) { + // We have a valid value, output this value + stream->print(F("esphome_text_sensor_failed{id=\"")); + stream->print(relabel_id_(obj).c_str()); + stream->print(F("\",name=\"")); + stream->print(relabel_name_(obj).c_str()); + stream->print(F("\"} 0\n")); + // Data itself + stream->print(F("esphome_text_sensor_value{id=\"")); + stream->print(relabel_id_(obj).c_str()); + stream->print(F("\",name=\"")); + stream->print(relabel_name_(obj).c_str()); + stream->print(F("\",value=\"")); + stream->print(obj->state.c_str()); + stream->print(F("\"} ")); + stream->print(F("1.0")); + stream->print(F("\n")); + } else { + // Invalid state + stream->print(F("esphome_text_sensor_failed{id=\"")); + stream->print(relabel_id_(obj).c_str()); + stream->print(F("\",name=\"")); + stream->print(relabel_name_(obj).c_str()); + stream->print(F("\"} 1\n")); + } +} +#endif + } // namespace prometheus } // namespace esphome #endif diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index f5e49a1419..512e1bee4f 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -110,6 +110,13 @@ class PrometheusHandler : public AsyncWebHandler, public Component { void lock_row_(AsyncResponseStream *stream, lock::Lock *obj); #endif +#ifdef USE_TEXT_SENSOR + /// Return the type for prometheus + void text_sensor_type_(AsyncResponseStream *stream); + /// Return the lock Values state as prometheus data point + void text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj); +#endif + web_server_base::WebServerBase *base_; bool include_internal_{false}; std::map relabel_map_id_; diff --git a/tests/components/prometheus/common.yaml b/tests/components/prometheus/common.yaml index c8ce17da88..7aa509f8b2 100644 --- a/tests/components/prometheus/common.yaml +++ b/tests/components/prometheus/common.yaml @@ -13,9 +13,23 @@ sensor: } update_interval: 60s +text_sensor: + - platform: template + id: template_text_sensor1 + lambda: |- + if (millis() > 10000) { + return {"Hello World"}; + } else { + return {"Goodbye (cruel) World"}; + } + update_interval: 60s + prometheus: include_internal: true relabel: template_sensor1: id: hellow_world name: Hello World + template_text_sensor1: + id: hello_text + name: Text Substitution From 0dab280440de853d57d750463b3be4e065fd480d Mon Sep 17 00:00:00 2001 From: Sean Brogan Date: Mon, 28 Oct 2024 20:49:06 -0700 Subject: [PATCH 2583/2607] Mopeka Pro Check improvement to allow user to configure the sensor reporting for lower quality readings (#7475) --- .../mopeka_pro_check/mopeka_pro_check.cpp | 63 ++++++++++++------- .../mopeka_pro_check/mopeka_pro_check.h | 11 +++- esphome/components/mopeka_pro_check/sensor.py | 41 ++++++++++++ tests/components/mopeka_pro_check/common.yaml | 17 +++++ 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp b/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp index f79e40bb4e..9527f09f59 100644 --- a/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +++ b/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp @@ -17,6 +17,8 @@ void MopekaProCheck::dump_config() { LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); LOG_SENSOR(" ", "Reading Distance", this->distance_); + LOG_SENSOR(" ", "Read Quality", this->read_quality_); + LOG_SENSOR(" ", "Ignored Reads", this->ignored_reads_); } /** @@ -66,34 +68,49 @@ bool MopekaProCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device) this->battery_level_->publish_state(level); } + // Get the quality value + SensorReadQuality quality_value = this->parse_read_quality_(manu_data.data); + if (this->read_quality_ != nullptr) { + this->read_quality_->publish_state(static_cast(quality_value)); + } + + // Determine if we have a good enough quality of read to report level and distance + // sensors. This sensor is reported regardless of distance or level sensors being enabled + if (quality_value < this->min_signal_quality_) { + ESP_LOGW(TAG, "Read Quality too low to report distance or level"); + this->ignored_read_count_++; + } else { + // reset to zero since read quality was sufficient + this->ignored_read_count_ = 0; + } + // Report number of contiguous ignored reads if sensor defined + if (this->ignored_reads_ != nullptr) { + this->ignored_reads_->publish_state(this->ignored_read_count_); + } + // Get distance and level if either are sensors if ((this->distance_ != nullptr) || (this->level_ != nullptr)) { uint32_t distance_value = this->parse_distance_(manu_data.data); - SensorReadQuality quality_value = this->parse_read_quality_(manu_data.data); ESP_LOGD(TAG, "Distance Sensor: Quality (0x%X) Distance (%" PRId32 "mm)", quality_value, distance_value); - if (quality_value < QUALITY_HIGH) { - ESP_LOGW(TAG, "Poor read quality."); - } - if (quality_value < QUALITY_MED) { - // if really bad reading set to 0 - ESP_LOGW(TAG, "Setting distance to 0"); - distance_value = 0; - } - // update distance sensor - if (this->distance_ != nullptr) { - this->distance_->publish_state(distance_value); - } - - // update level sensor - if (this->level_ != nullptr) { - uint8_t tank_level = 0; - if (distance_value >= this->full_mm_) { - tank_level = 100; // cap at 100% - } else if (distance_value > this->empty_mm_) { - tank_level = ((100.0f / (this->full_mm_ - this->empty_mm_)) * (distance_value - this->empty_mm_)); + // only update distance and level sensors if read quality was sufficient. This can be determined by + // if the ignored_read_count is zero. + if (this->ignored_read_count_ == 0) { + // update distance sensor + if (this->distance_ != nullptr) { + this->distance_->publish_state(distance_value); + } + + // update level sensor + if (this->level_ != nullptr) { + uint8_t tank_level = 0; + if (distance_value >= this->full_mm_) { + tank_level = 100; // cap at 100% + } else if (distance_value > this->empty_mm_) { + tank_level = ((100.0f / (this->full_mm_ - this->empty_mm_)) * (distance_value - this->empty_mm_)); + } + this->level_->publish_state(tank_level); } - this->level_->publish_state(tank_level); } } @@ -131,6 +148,8 @@ uint32_t MopekaProCheck::parse_distance_(const std::vector &message) { uint8_t MopekaProCheck::parse_temperature_(const std::vector &message) { return (message[2] & 0x7F) - 40; } SensorReadQuality MopekaProCheck::parse_read_quality_(const std::vector &message) { + // Since a 8 bit value is being shifted and truncated to 2 bits all possible values are defined as enumeration + // value and the static cast is safe. return static_cast(message[4] >> 6); } diff --git a/esphome/components/mopeka_pro_check/mopeka_pro_check.h b/esphome/components/mopeka_pro_check/mopeka_pro_check.h index 8b4d47e4c6..c58406ac18 100644 --- a/esphome/components/mopeka_pro_check/mopeka_pro_check.h +++ b/esphome/components/mopeka_pro_check/mopeka_pro_check.h @@ -24,9 +24,9 @@ enum SensorType { }; // Sensor read quality. If sensor is poorly placed or tank level -// gets too low the read quality will show and the distanace +// gets too low the read quality will show and the distance // measurement may be inaccurate. -enum SensorReadQuality { QUALITY_HIGH = 0x3, QUALITY_MED = 0x2, QUALITY_LOW = 0x1, QUALITY_NONE = 0x0 }; +enum SensorReadQuality { QUALITY_HIGH = 0x3, QUALITY_MED = 0x2, QUALITY_LOW = 0x1, QUALITY_ZERO = 0x0 }; class MopekaProCheck : public Component, public esp32_ble_tracker::ESPBTDeviceListener { public: @@ -35,11 +35,14 @@ class MopekaProCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } + void set_min_signal_quality(SensorReadQuality min) { this->min_signal_quality_ = min; }; void set_level(sensor::Sensor *level) { level_ = level; }; void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }; void set_battery_level(sensor::Sensor *bat) { battery_level_ = bat; }; void set_distance(sensor::Sensor *distance) { distance_ = distance; }; + void set_signal_quality(sensor::Sensor *rq) { read_quality_ = rq; }; + void set_ignored_reads(sensor::Sensor *ir) { ignored_reads_ = ir; }; void set_tank_full(float full) { full_mm_ = full; }; void set_tank_empty(float empty) { empty_mm_ = empty; }; @@ -49,9 +52,13 @@ class MopekaProCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi sensor::Sensor *temperature_{nullptr}; sensor::Sensor *distance_{nullptr}; sensor::Sensor *battery_level_{nullptr}; + sensor::Sensor *read_quality_{nullptr}; + sensor::Sensor *ignored_reads_{nullptr}; uint32_t full_mm_; uint32_t empty_mm_; + uint32_t ignored_read_count_ = 0; + SensorReadQuality min_signal_quality_ = QUALITY_MED; uint8_t parse_battery_level_(const std::vector &message); uint32_t parse_distance_(const std::vector &message); diff --git a/esphome/components/mopeka_pro_check/sensor.py b/esphome/components/mopeka_pro_check/sensor.py index 0ba33e94de..95ade53013 100644 --- a/esphome/components/mopeka_pro_check/sensor.py +++ b/esphome/components/mopeka_pro_check/sensor.py @@ -5,9 +5,12 @@ from esphome.const import ( CONF_DISTANCE, CONF_MAC_ADDRESS, CONF_ID, + ICON_COUNTER, ICON_THERMOMETER, ICON_RULER, + ICON_SIGNAL, UNIT_PERCENT, + UNIT_EMPTY, CONF_LEVEL, CONF_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, @@ -16,11 +19,15 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, CONF_BATTERY_LEVEL, DEVICE_CLASS_BATTERY, + ENTITY_CATEGORY_DIAGNOSTIC, ) CONF_TANK_TYPE = "tank_type" CONF_CUSTOM_DISTANCE_FULL = "custom_distance_full" CONF_CUSTOM_DISTANCE_EMPTY = "custom_distance_empty" +CONF_SIGNAL_QUALITY = "signal_quality" +CONF_MINIMUM_SIGNAL_QUALITY = "minimum_signal_quality" +CONF_IGNORED_READS = "ignored_reads" ICON_PROPANE_TANK = "mdi:propane-tank" @@ -56,6 +63,14 @@ MopekaProCheck = mopeka_pro_check_ns.class_( "MopekaProCheck", esp32_ble_tracker.ESPBTDeviceListener, cg.Component ) +SensorReadQuality = mopeka_pro_check_ns.enum("SensorReadQuality") +SIGNAL_QUALITIES = { + "ZERO": SensorReadQuality.QUALITY_ZERO, + "LOW": SensorReadQuality.QUALITY_LOW, + "MEDIUM": SensorReadQuality.QUALITY_MED, + "HIGH": SensorReadQuality.QUALITY_HIGH, +} + CONFIG_SCHEMA = ( cv.Schema( { @@ -89,6 +104,21 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_BATTERY, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_SIGNAL_QUALITY): sensor.sensor_schema( + unit_of_measurement=UNIT_EMPTY, + icon=ICON_SIGNAL, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IGNORED_READS): sensor.sensor_schema( + unit_of_measurement=UNIT_EMPTY, + icon=ICON_COUNTER, + accuracy_decimals=0, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_MINIMUM_SIGNAL_QUALITY, default="MEDIUM"): cv.enum( + SIGNAL_QUALITIES, upper=True + ), } ) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) @@ -119,6 +149,11 @@ async def to_code(config): cg.add(var.set_tank_empty(CONF_SUPPORTED_TANKS_MAP[t][0])) cg.add(var.set_tank_full(CONF_SUPPORTED_TANKS_MAP[t][1])) + if ( + minimum_signal_quality := config.get(CONF_MINIMUM_SIGNAL_QUALITY, None) + ) is not None: + cg.add(var.set_min_signal_quality(minimum_signal_quality)) + if CONF_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) @@ -131,3 +166,9 @@ async def to_code(config): if CONF_BATTERY_LEVEL in config: sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) + if CONF_SIGNAL_QUALITY in config: + sens = await sensor.new_sensor(config[CONF_SIGNAL_QUALITY]) + cg.add(var.set_signal_quality(sens)) + if CONF_IGNORED_READS in config: + sens = await sensor.new_sensor(config[CONF_IGNORED_READS]) + cg.add(var.set_ignored_reads(sens)) diff --git a/tests/components/mopeka_pro_check/common.yaml b/tests/components/mopeka_pro_check/common.yaml index 147cbcb9de..3533ecf631 100644 --- a/tests/components/mopeka_pro_check/common.yaml +++ b/tests/components/mopeka_pro_check/common.yaml @@ -14,3 +14,20 @@ sensor: name: Propane test distance battery_level: name: Propane test battery level + + - platform: mopeka_pro_check + mac_address: AA:BB:CC:DD:EE:FF + tank_type: 20LB_V + temperature: + name: "Propane test2 temp" + level: + name: "Propane test2 level" + distance: + name: "Propane test2 distance" + battery_level: + name: "Propane test2 battery level" + signal_quality: + name: "propane test2 read quality" + ignored_reads: + name: "propane test2 ignored reads" + minimum_signal_quality: "LOW" From aa0e155e22c422c789feeb0b1be9495f703fc8fa Mon Sep 17 00:00:00 2001 From: Bonne Eggleston Date: Mon, 28 Oct 2024 20:52:39 -0700 Subject: [PATCH 2584/2607] Fixes modbus timing error (#7674) --- esphome/components/modbus/modbus.cpp | 36 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index f8dd4c18b9..8544b50261 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -15,23 +15,33 @@ void Modbus::setup() { void Modbus::loop() { const uint32_t now = millis(); - if (now - this->last_modbus_byte_ > 50) { - this->rx_buffer_.clear(); - this->last_modbus_byte_ = now; - } - // stop blocking new send commands after send_wait_time_ ms regardless if a response has been received since then - if (now - this->last_send_ > send_wait_time_) { - waiting_for_response = 0; - } - while (this->available()) { uint8_t byte; this->read_byte(&byte); if (this->parse_modbus_byte_(byte)) { this->last_modbus_byte_ = now; } else { + size_t at = this->rx_buffer_.size(); + if (at > 0) { + ESP_LOGV(TAG, "Clearing buffer of %d bytes - parse failed", at); + this->rx_buffer_.clear(); + } + } + } + + if (now - this->last_modbus_byte_ > 50) { + size_t at = this->rx_buffer_.size(); + if (at > 0) { + ESP_LOGV(TAG, "Clearing buffer of %d bytes - timeout", at); this->rx_buffer_.clear(); } + + // stop blocking new send commands after sent_wait_time_ ms after response received + if (now - this->last_send_ > send_wait_time_) { + if (waiting_for_response > 0) + ESP_LOGV(TAG, "Stop waiting for response from %d", waiting_for_response); + waiting_for_response = 0; + } } } @@ -39,7 +49,7 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { size_t at = this->rx_buffer_.size(); this->rx_buffer_.push_back(byte); const uint8_t *raw = &this->rx_buffer_[0]; - ESP_LOGV(TAG, "Modbus received Byte %d (0X%x)", byte, byte); + ESP_LOGVV(TAG, "Modbus received Byte %d (0X%x)", byte, byte); // Byte 0: modbus address (match all) if (at == 0) return true; @@ -144,8 +154,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { ESP_LOGW(TAG, "Got Modbus frame from unknown address 0x%02X! ", address); } - // return false to reset buffer - return false; + // reset buffer + ESP_LOGV(TAG, "Clearing buffer of %d bytes - parse succeeded", at); + this->rx_buffer_.clear(); + return true; } void Modbus::dump_config() { From abbd7faa641220fc3cbc2e77f76f3bfcf41546ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Mart=C3=ADn?= Date: Tue, 29 Oct 2024 04:56:50 +0100 Subject: [PATCH 2585/2607] fix(WiFi): Fix strncpy missing NULL terminator [-Werror=stringop-truncation] (#7668) --- esphome/components/wifi/wifi_component.cpp | 4 ++-- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 8 ++++---- esphome/components/wifi/wifi_component_esp8266.cpp | 8 ++++---- esphome/components/wifi/wifi_component_esp_idf.cpp | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 583a27466a..8788711d5a 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -297,8 +297,8 @@ void WiFiComponent::set_sta(const WiFiAP &ap) { void WiFiComponent::clear_sta() { this->sta_.clear(); } void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) { SavedWifiSettings save{}; - strncpy(save.ssid, ssid.c_str(), sizeof(save.ssid)); - strncpy(save.password, password.c_str(), sizeof(save.password)); + snprintf(save.ssid, sizeof(save.ssid), "%s", ssid.c_str()); + snprintf(save.password, sizeof(save.password), "%s", password.c_str()); this->pref_.save(&save); // ensure it's written immediately global_preferences->sync(); diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index ef4308b28c..88648093c6 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -137,8 +137,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - strncpy(reinterpret_cast(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid)); - strncpy(reinterpret_cast(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password)); + snprintf(reinterpret_cast(conf.sta.ssid), sizeof(conf.sta.ssid), "%s", ap.get_ssid().c_str()); + snprintf(reinterpret_cast(conf.sta.password), sizeof(conf.sta.password), "%s", ap.get_password().c_str()); // The weakest authmode to accept in the fast scan mode if (ap.get_password().empty()) { @@ -746,7 +746,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - strncpy(reinterpret_cast(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid)); + snprintf(reinterpret_cast(conf.ap.ssid), sizeof(conf.ap.ssid), "%s", ap.get_ssid().c_str()); conf.ap.channel = ap.get_channel().value_or(1); conf.ap.ssid_hidden = ap.get_ssid().size(); conf.ap.max_connection = 5; @@ -757,7 +757,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.ap.password = 0; } else { conf.ap.authmode = WIFI_AUTH_WPA2_PSK; - strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password)); + snprintf(reinterpret_cast(conf.ap.password), sizeof(conf.ap.password), "%s", ap.get_password().c_str()); } // pairwise cipher of SoftAP, group cipher will be derived using this. diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 92f80c1e52..4568895950 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -236,8 +236,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { struct station_config conf {}; memset(&conf, 0, sizeof(conf)); - strncpy(reinterpret_cast(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid)); - strncpy(reinterpret_cast(conf.password), ap.get_password().c_str(), sizeof(conf.password)); + snprintf(reinterpret_cast(conf.ssid), sizeof(conf.ssid), "%s", ap.get_ssid().c_str()); + snprintf(reinterpret_cast(conf.password), sizeof(conf.password), "%s", ap.get_password().c_str()); if (ap.get_bssid().has_value()) { conf.bssid_set = 1; @@ -775,7 +775,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return false; struct softap_config conf {}; - strncpy(reinterpret_cast(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid)); + snprintf(reinterpret_cast(conf.ssid), sizeof(conf.ssid), "%s", ap.get_ssid().c_str()); conf.ssid_len = static_cast(ap.get_ssid().size()); conf.channel = ap.get_channel().value_or(1); conf.ssid_hidden = ap.get_hidden(); @@ -787,7 +787,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.password = 0; } else { conf.authmode = AUTH_WPA2_PSK; - strncpy(reinterpret_cast(conf.password), ap.get_password().c_str(), sizeof(conf.password)); + snprintf(reinterpret_cast(conf.password), sizeof(conf.password), "%s", ap.get_password().c_str()); } ETS_UART_INTR_DISABLE(); diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 0f2e181e31..13870136d4 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -289,8 +289,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - strncpy(reinterpret_cast(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid)); - strncpy(reinterpret_cast(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password)); + snprintf(reinterpret_cast(conf.sta.ssid), sizeof(conf.sta.ssid), "%s", ap.get_ssid().c_str()); + snprintf(reinterpret_cast(conf.sta.password), sizeof(conf.sta.password), "%s", ap.get_password().c_str()); // The weakest authmode to accept in the fast scan mode if (ap.get_password().empty()) { From 71e1e3b5f8575a3c075b90dbf573c95927a9bb0a Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 29 Oct 2024 04:58:36 +0100 Subject: [PATCH 2586/2607] let make new platform implementation in external components (#7615) Co-authored-by: Tomasz Duda --- esphome/core/helpers.cpp | 57 ++++++++++++++++++++++++---------------- esphome/core/helpers.h | 4 +++ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index dca35819ff..8f94f624f1 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef USE_HOST #ifndef _WIN32 @@ -188,37 +189,39 @@ uint32_t fnv1_hash(const std::string &str) { return hash; } -uint32_t random_uint32() { #ifdef USE_ESP32 - return esp_random(); +uint32_t random_uint32() { return esp_random(); } #elif defined(USE_ESP8266) - return os_random(); +uint32_t random_uint32() { return os_random(); } #elif defined(USE_RP2040) +uint32_t random_uint32() { uint32_t result = 0; for (uint8_t i = 0; i < 32; i++) { result <<= 1; result |= rosc_hw->randombit; } return result; +} #elif defined(USE_LIBRETINY) - return rand(); +uint32_t random_uint32() { return rand(); } #elif defined(USE_HOST) +uint32_t random_uint32() { std::random_device dev; std::mt19937 rng(dev()); std::uniform_int_distribution dist(0, std::numeric_limits::max()); return dist(rng); -#else -#error "No random source available for this configuration." -#endif } +#endif float random_float() { return static_cast(random_uint32()) / static_cast(UINT32_MAX); } -bool random_bytes(uint8_t *data, size_t len) { #ifdef USE_ESP32 +bool random_bytes(uint8_t *data, size_t len) { esp_fill_random(data, len); return true; +} #elif defined(USE_ESP8266) - return os_get_random(data, len) == 0; +bool random_bytes(uint8_t *data, size_t len) { return os_get_random(data, len) == 0; } #elif defined(USE_RP2040) +bool random_bytes(uint8_t *data, size_t len) { while (len-- != 0) { uint8_t result = 0; for (uint8_t i = 0; i < 8; i++) { @@ -228,10 +231,14 @@ bool random_bytes(uint8_t *data, size_t len) { *data++ = result; } return true; +} #elif defined(USE_LIBRETINY) +bool random_bytes(uint8_t *data, size_t len) { lt_rand_bytes(data, len); return true; +} #elif defined(USE_HOST) +bool random_bytes(uint8_t *data, size_t len) { FILE *fp = fopen("/dev/urandom", "r"); if (fp == nullptr) { ESP_LOGW(TAG, "Could not open /dev/urandom, errno=%d", errno); @@ -244,10 +251,8 @@ bool random_bytes(uint8_t *data, size_t len) { } fclose(fp); return true; -#else -#error "No random source available for this configuration." -#endif } +#endif // Strings @@ -619,11 +624,13 @@ void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green #if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_HOST) // ESP8266 doesn't have mutexes, but that shouldn't be an issue as it's single-core and non-preemptive OS. Mutex::Mutex() {} +Mutex::~Mutex() {} void Mutex::lock() {} bool Mutex::try_lock() { return true; } void Mutex::unlock() {} #elif defined(USE_ESP32) || defined(USE_LIBRETINY) Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); } +Mutex::~Mutex() {} void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); } bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; } void Mutex::unlock() { xSemaphoreGive(this->handle_); } @@ -657,11 +664,13 @@ void HighFrequencyLoopRequester::stop() { } bool HighFrequencyLoopRequester::is_high_frequency() { return num_requests > 0; } -void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) #if defined(USE_HOST) +void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) static const uint8_t esphome_host_mac_address[6] = USE_ESPHOME_HOST_MAC_ADDRESS; memcpy(mac, esphome_host_mac_address, sizeof(esphome_host_mac_address)); +} #elif defined(USE_ESP32) +void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) #if defined(CONFIG_SOC_IEEE802154_SUPPORTED) // When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default // returns the 802.15.4 EUI-64 address, so we read directly from eFuse instead. @@ -677,16 +686,20 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame esp_efuse_mac_get_default(mac); } #endif -#elif defined(USE_ESP8266) - wifi_get_macaddr(STATION_IF, mac); -#elif defined(USE_RP2040) && defined(USE_WIFI) - WiFi.macAddress(mac); -#elif defined(USE_LIBRETINY) - WiFi.macAddress(mac); -#else -// this should be an error, but that messes with CI checks. #error No mac address method defined -#endif } +#elif defined(USE_ESP8266) +void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) + wifi_get_macaddr(STATION_IF, mac); +} +#elif defined(USE_RP2040) && defined(USE_WIFI) +void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) + WiFi.macAddress(mac); +} +#elif defined(USE_LIBRETINY) +void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) + WiFi.macAddress(mac); +} +#endif std::string get_mac_address() { uint8_t mac[6]; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 7f6fe9bfdc..43001bafdd 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "esphome/core/optional.h" @@ -545,6 +546,7 @@ class Mutex { public: Mutex(); Mutex(const Mutex &) = delete; + ~Mutex(); void lock(); bool try_lock(); void unlock(); @@ -554,6 +556,8 @@ class Mutex { private: #if defined(USE_ESP32) || defined(USE_LIBRETINY) SemaphoreHandle_t handle_; +#else + void *handle_; // d-pointer to store private data on new platforms #endif }; From 38dd566e0cbb51b4eb6f14a8fcb03b36b7b962dc Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 28 Oct 2024 21:12:54 -0700 Subject: [PATCH 2587/2607] remove use of delay (#7680) Co-authored-by: Samuel Sieb Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sgp4x/sgp4x.cpp | 114 ++++++++++------------------- esphome/components/sgp4x/sgp4x.h | 8 +- 2 files changed, 45 insertions(+), 77 deletions(-) diff --git a/esphome/components/sgp4x/sgp4x.cpp b/esphome/components/sgp4x/sgp4x.cpp index 7e474b9371..bf91c90832 100644 --- a/esphome/components/sgp4x/sgp4x.cpp +++ b/esphome/components/sgp4x/sgp4x.cpp @@ -111,7 +111,7 @@ void SGP4xComponent::setup() { number of records reported from being overwhelming. */ ESP_LOGD(TAG, "Component requires sampling of 1Hz, setting up background sampler"); - this->set_interval(1000, [this]() { this->update_gas_indices(); }); + this->set_interval(1000, [this]() { this->take_sample(); }); } void SGP4xComponent::self_test_() { @@ -146,31 +146,15 @@ void SGP4xComponent::self_test_() { }); } -/** - * @brief Combined the measured gasses, temperature, and humidity - * to calculate the VOC Index - * - * @param temperature The measured temperature in degrees C - * @param humidity The measured relative humidity in % rH - * @return int32_t The VOC Index - */ -bool SGP4xComponent::measure_gas_indices_(int32_t &voc, int32_t &nox) { - uint16_t voc_sraw; - uint16_t nox_sraw; - if (!measure_raw_(voc_sraw, nox_sraw)) - return false; - - this->status_clear_warning(); - - voc = voc_algorithm_.process(voc_sraw); - if (nox_sensor_) { - nox = nox_algorithm_.process(nox_sraw); - } - ESP_LOGV(TAG, "VOC = %" PRId32 ", NOx = %" PRId32, voc, nox); +void SGP4xComponent::update_gas_indices_() { + this->voc_index_ = this->voc_algorithm_.process(this->voc_sraw_); + if (this->nox_sensor_ != nullptr) + this->nox_index_ = this->nox_algorithm_.process(this->nox_sraw_); + ESP_LOGV(TAG, "VOC = %" PRId32 ", NOx = %" PRId32, this->voc_index_, this->nox_index_); // Store baselines after defined interval or if the difference between current and stored baseline becomes too // much if (this->store_baseline_ && this->seconds_since_last_store_ > SHORTEST_BASELINE_STORE_INTERVAL) { - voc_algorithm_.get_states(this->voc_state0_, this->voc_state1_); + this->voc_algorithm_.get_states(this->voc_state0_, this->voc_state1_); if (std::abs(this->voc_baselines_storage_.state0 - this->voc_state0_) > MAXIMUM_STORAGE_DIFF || std::abs(this->voc_baselines_storage_.state1 - this->voc_state1_) > MAXIMUM_STORAGE_DIFF) { this->seconds_since_last_store_ = 0; @@ -179,29 +163,27 @@ bool SGP4xComponent::measure_gas_indices_(int32_t &voc, int32_t &nox) { if (this->pref_.save(&this->voc_baselines_storage_)) { ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 " ,state1: 0x%04" PRIX32, - this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); + this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1); } else { ESP_LOGW(TAG, "Could not store VOC baselines"); } } } - return true; + if (this->samples_read_ < this->samples_to_stabilize_) { + this->samples_read_++; + ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %" PRIu32, this->samples_read_, + this->samples_to_stabilize_, this->voc_index_); + } } -/** - * @brief Return the raw gas measurement - * - * @param temperature The measured temperature in degrees C - * @param humidity The measured relative humidity in % rH - * @return uint16_t The current raw gas measurement - */ -bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) { + +void SGP4xComponent::measure_raw_() { float humidity = NAN; static uint32_t nox_conditioning_start = millis(); if (!this->self_test_complete_) { ESP_LOGD(TAG, "Self-test not yet complete"); - return false; + return; } if (this->humidity_sensor_ != nullptr) { humidity = this->humidity_sensor_->state; @@ -243,61 +225,45 @@ bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) { data[1] = tempticks; if (!this->write_command(command, data, 2)) { - this->status_set_warning(); ESP_LOGD(TAG, "write error (%d)", this->last_error_); - return false; + this->status_set_warning("measurement request failed"); + return; } - delay(measure_time_); - uint16_t raw_data[2]; - raw_data[1] = 0; - if (!this->read_data(raw_data, response_words)) { - this->status_set_warning(); - ESP_LOGD(TAG, "read error (%d)", this->last_error_); - return false; - } - voc_raw = raw_data[0]; - nox_raw = raw_data[1]; // either 0 or the measured NOx ticks - return true; + + this->set_timeout(this->measure_time_, [this, response_words]() { + uint16_t raw_data[2]; + raw_data[1] = 0; + if (!this->read_data(raw_data, response_words)) { + ESP_LOGD(TAG, "read error (%d)", this->last_error_); + this->status_set_warning("measurement read failed"); + this->voc_index_ = this->nox_index_ = UINT16_MAX; + return; + } + this->voc_sraw_ = raw_data[0]; + this->nox_sraw_ = raw_data[1]; // either 0 or the measured NOx ticks + this->status_clear_warning(); + this->update_gas_indices_(); + }); } -void SGP4xComponent::update_gas_indices() { +void SGP4xComponent::take_sample() { if (!this->self_test_complete_) return; - this->seconds_since_last_store_ += 1; - if (!this->measure_gas_indices_(this->voc_index_, this->nox_index_)) { - // Set values to UINT16_MAX to indicate failure - this->voc_index_ = this->nox_index_ = UINT16_MAX; - ESP_LOGE(TAG, "measure gas indices failed"); - return; - } - if (this->samples_read_ < this->samples_to_stabilize_) { - this->samples_read_++; - ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %" PRIu32, this->samples_read_, - this->samples_to_stabilize_, this->voc_index_); - return; - } + this->measure_raw_(); } void SGP4xComponent::update() { if (this->samples_read_ < this->samples_to_stabilize_) { return; } - if (this->voc_sensor_) { - if (this->voc_index_ != UINT16_MAX) { - this->status_clear_warning(); + if (this->voc_sensor_ != nullptr) { + if (this->voc_index_ != UINT16_MAX) this->voc_sensor_->publish_state(this->voc_index_); - } else { - this->status_set_warning(); - } } - if (this->nox_sensor_) { - if (this->nox_index_ != UINT16_MAX) { - this->status_clear_warning(); + if (this->nox_sensor_ != nullptr) { + if (this->nox_index_ != UINT16_MAX) this->nox_sensor_->publish_state(this->nox_index_); - } else { - this->status_set_warning(); - } } } @@ -329,7 +295,7 @@ void SGP4xComponent::dump_config() { } LOG_UPDATE_INTERVAL(this); - if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) { + if (this->humidity_sensor_ != nullptr || this->temperature_sensor_ != nullptr) { ESP_LOGCONFIG(TAG, " Compensation:"); LOG_SENSOR(" ", "Temperature Source:", this->temperature_sensor_); LOG_SENSOR(" ", "Humidity Source:", this->humidity_sensor_); diff --git a/esphome/components/sgp4x/sgp4x.h b/esphome/components/sgp4x/sgp4x.h index aa5ae4b9d2..959ff12c27 100644 --- a/esphome/components/sgp4x/sgp4x.h +++ b/esphome/components/sgp4x/sgp4x.h @@ -73,7 +73,7 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se void setup() override; void update() override; - void update_gas_indices(); + void take_sample(); void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } void set_store_baseline(bool store_baseline) { store_baseline_ = store_baseline; } @@ -108,8 +108,10 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se sensor::Sensor *temperature_sensor_{nullptr}; int16_t sensirion_init_sensors_(); - bool measure_gas_indices_(int32_t &voc, int32_t &nox); - bool measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw); + void update_gas_indices_(); + void measure_raw_(); + uint16_t voc_sraw_; + uint16_t nox_sraw_; SgpType sgp_type_{SGP40}; uint64_t serial_number_; From 0982ab58ac1ff8c027bae542908e204b5d053728 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 29 Oct 2024 19:53:36 +0100 Subject: [PATCH 2588/2607] fix build error (#7694) Co-authored-by: Tomasz Duda --- esphome/core/helpers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 8f94f624f1..dae60a4e1d 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -691,9 +691,11 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) wifi_get_macaddr(STATION_IF, mac); } -#elif defined(USE_RP2040) && defined(USE_WIFI) +#elif defined(USE_RP2040) void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) +#ifdef USE_WIFI WiFi.macAddress(mac); +#endif } #elif defined(USE_LIBRETINY) void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) From bac6880a1e9df93a38cb6a7ba467c28a78209c2f Mon Sep 17 00:00:00 2001 From: Ilia Sotnikov Date: Wed, 30 Oct 2024 02:32:55 +0300 Subject: [PATCH 2589/2607] fix: [climate] Allow substitutions in `visual.temperature_step.{target_temperature,current_temperature}` (#7679) --- esphome/components/climate/__init__.py | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index b302e2ab4e..ec68940726 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -119,10 +119,21 @@ visual_temperature = cv.float_with_unit( ) -def single_visual_temperature(value): - if isinstance(value, dict): - return value +VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Schema( + { + cv.Required(CONF_TARGET_TEMPERATURE): visual_temperature, + cv.Required(CONF_CURRENT_TEMPERATURE): visual_temperature, + } +) + +def visual_temperature_step(value): + + # Allow defining target/current temperature steps separately + if isinstance(value, dict): + return VISUAL_TEMPERATURE_STEP_SCHEMA(value) + + # Otherwise, use the single value for both properties value = visual_temperature(value) return VISUAL_TEMPERATURE_STEP_SCHEMA( { @@ -141,16 +152,6 @@ ControlTrigger = climate_ns.class_( "ControlTrigger", automation.Trigger.template(ClimateCall.operator("ref")) ) -VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any( - single_visual_temperature, - cv.Schema( - { - cv.Required(CONF_TARGET_TEMPERATURE): visual_temperature, - cv.Required(CONF_CURRENT_TEMPERATURE): visual_temperature, - } - ), -) - CLIMATE_SCHEMA = ( cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) @@ -162,7 +163,7 @@ CLIMATE_SCHEMA = ( { cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature, cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature, - cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA, + cv.Optional(CONF_TEMPERATURE_STEP): visual_temperature_step, cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int, cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int, } From aae2ee2ecb34222ad61b52064f10006e86fc0fa3 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Tue, 29 Oct 2024 18:03:10 -0700 Subject: [PATCH 2590/2607] Add in area and device to the prometheus labels (#7692) --- .../prometheus/prometheus_handler.cpp | 151 ++++++++++++++++-- .../prometheus/prometheus_handler.h | 27 +++- tests/components/prometheus/common.yaml | 54 +++++++ 3 files changed, 208 insertions(+), 24 deletions(-) diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index 63b3fdf53f..5d1861202a 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -7,53 +7,56 @@ namespace prometheus { void PrometheusHandler::handleRequest(AsyncWebServerRequest *req) { AsyncResponseStream *stream = req->beginResponseStream("text/plain; version=0.0.4; charset=utf-8"); + std::string area = App.get_area(); + std::string node = App.get_name(); + std::string friendly_name = App.get_friendly_name(); #ifdef USE_SENSOR this->sensor_type_(stream); for (auto *obj : App.get_sensors()) - this->sensor_row_(stream, obj); + this->sensor_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_BINARY_SENSOR this->binary_sensor_type_(stream); for (auto *obj : App.get_binary_sensors()) - this->binary_sensor_row_(stream, obj); + this->binary_sensor_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_FAN this->fan_type_(stream); for (auto *obj : App.get_fans()) - this->fan_row_(stream, obj); + this->fan_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_LIGHT this->light_type_(stream); for (auto *obj : App.get_lights()) - this->light_row_(stream, obj); + this->light_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_COVER this->cover_type_(stream); for (auto *obj : App.get_covers()) - this->cover_row_(stream, obj); + this->cover_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_SWITCH this->switch_type_(stream); for (auto *obj : App.get_switches()) - this->switch_row_(stream, obj); + this->switch_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_LOCK this->lock_type_(stream); for (auto *obj : App.get_locks()) - this->lock_row_(stream, obj); + this->lock_row_(stream, obj, area, node, friendly_name); #endif #ifdef USE_TEXT_SENSOR this->text_sensor_type_(stream); for (auto *obj : App.get_text_sensors()) - this->text_sensor_row_(stream, obj); + this->text_sensor_row_(stream, obj, area, node, friendly_name); #endif req->send(stream); @@ -69,25 +72,53 @@ std::string PrometheusHandler::relabel_name_(EntityBase *obj) { return item == relabel_map_name_.end() ? obj->get_name() : item->second; } +void PrometheusHandler::add_area_label_(AsyncResponseStream *stream, std::string &area) { + if (!area.empty()) { + stream->print(F("\",area=\"")); + stream->print(area.c_str()); + } +} + +void PrometheusHandler::add_node_label_(AsyncResponseStream *stream, std::string &node) { + if (!node.empty()) { + stream->print(F("\",node=\"")); + stream->print(node.c_str()); + } +} + +void PrometheusHandler::add_friendly_name_label_(AsyncResponseStream *stream, std::string &friendly_name) { + if (!friendly_name.empty()) { + stream->print(F("\",friendly_name=\"")); + stream->print(friendly_name.c_str()); + } +} + // Type-specific implementation #ifdef USE_SENSOR void PrometheusHandler::sensor_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_sensor_value gauge\n")); stream->print(F("#TYPE esphome_sensor_failed gauge\n")); } -void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj) { +void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj, std::string &area, + std::string &node, std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; if (!std::isnan(obj->state)) { // We have a valid value, output this value stream->print(F("esphome_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_sensor_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",unit=\"")); @@ -99,6 +130,9 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor // Invalid state stream->print(F("esphome_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 1\n")); @@ -112,19 +146,26 @@ void PrometheusHandler::binary_sensor_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_binary_sensor_value gauge\n")); stream->print(F("#TYPE esphome_binary_sensor_failed gauge\n")); } -void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj) { +void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj, + std::string &area, std::string &node, std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; if (obj->has_state()) { // We have a valid value, output this value stream->print(F("esphome_binary_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_binary_sensor_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -134,6 +175,9 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s // Invalid state stream->print(F("esphome_binary_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 1\n")); @@ -148,17 +192,24 @@ void PrometheusHandler::fan_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_fan_speed gauge\n")); stream->print(F("#TYPE esphome_fan_oscillation gauge\n")); } -void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { +void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj, std::string &area, std::string &node, + std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; stream->print(F("esphome_fan_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_fan_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -168,6 +219,9 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { if (obj->get_traits().supports_speed()) { stream->print(F("esphome_fan_speed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -178,6 +232,9 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) { if (obj->get_traits().supports_oscillation()) { stream->print(F("esphome_fan_oscillation{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -193,12 +250,16 @@ void PrometheusHandler::light_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_light_color gauge\n")); stream->print(F("#TYPE esphome_light_effect_active gauge\n")); } -void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightState *obj) { +void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightState *obj, std::string &area, + std::string &node, std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; // State stream->print(F("esphome_light_state{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -211,6 +272,9 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat color.as_rgbw(&r, &g, &b, &w); stream->print(F("esphome_light_color{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",channel=\"brightness\"} ")); @@ -218,6 +282,9 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat stream->print(F("\n")); stream->print(F("esphome_light_color{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",channel=\"r\"} ")); @@ -225,6 +292,9 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat stream->print(F("\n")); stream->print(F("esphome_light_color{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",channel=\"g\"} ")); @@ -232,6 +302,9 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat stream->print(F("\n")); stream->print(F("esphome_light_color{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",channel=\"b\"} ")); @@ -239,6 +312,9 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat stream->print(F("\n")); stream->print(F("esphome_light_color{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",channel=\"w\"} ")); @@ -249,12 +325,18 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat if (effect == "None") { stream->print(F("esphome_light_effect_active{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",effect=\"None\"} 0\n")); } else { stream->print(F("esphome_light_effect_active{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",effect=\"")); @@ -269,19 +351,26 @@ void PrometheusHandler::cover_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_cover_value gauge\n")); stream->print(F("#TYPE esphome_cover_failed gauge\n")); } -void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *obj) { +void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *obj, std::string &area, std::string &node, + std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; if (!std::isnan(obj->position)) { // We have a valid value, output this value stream->print(F("esphome_cover_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_cover_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -290,6 +379,9 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob if (obj->get_traits().get_supports_tilt()) { stream->print(F("esphome_cover_tilt{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -300,6 +392,9 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob // Invalid state stream->print(F("esphome_cover_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 1\n")); @@ -312,17 +407,24 @@ void PrometheusHandler::switch_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_switch_value gauge\n")); stream->print(F("#TYPE esphome_switch_failed gauge\n")); } -void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch *obj) { +void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch *obj, std::string &area, + std::string &node, std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; stream->print(F("esphome_switch_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_switch_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -336,17 +438,24 @@ void PrometheusHandler::lock_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_lock_value gauge\n")); stream->print(F("#TYPE esphome_lock_failed gauge\n")); } -void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj) { +void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj, std::string &area, std::string &node, + std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; stream->print(F("esphome_lock_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_lock_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} ")); @@ -361,19 +470,26 @@ void PrometheusHandler::text_sensor_type_(AsyncResponseStream *stream) { stream->print(F("#TYPE esphome_text_sensor_value gauge\n")); stream->print(F("#TYPE esphome_text_sensor_failed gauge\n")); } -void PrometheusHandler::text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj) { +void PrometheusHandler::text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj, std::string &area, + std::string &node, std::string &friendly_name) { if (obj->is_internal() && !this->include_internal_) return; if (obj->has_state()) { // We have a valid value, output this value stream->print(F("esphome_text_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 0\n")); // Data itself stream->print(F("esphome_text_sensor_value{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\",value=\"")); @@ -385,6 +501,9 @@ void PrometheusHandler::text_sensor_row_(AsyncResponseStream *stream, text_senso // Invalid state stream->print(F("esphome_text_sensor_failed{id=\"")); stream->print(relabel_id_(obj).c_str()); + add_area_label_(stream, area); + add_node_label_(stream, node); + add_friendly_name_label_(stream, friendly_name); stream->print(F("\",name=\"")); stream->print(relabel_name_(obj).c_str()); stream->print(F("\"} 1\n")); diff --git a/esphome/components/prometheus/prometheus_handler.h b/esphome/components/prometheus/prometheus_handler.h index 512e1bee4f..5d08aca63a 100644 --- a/esphome/components/prometheus/prometheus_handler.h +++ b/esphome/components/prometheus/prometheus_handler.h @@ -60,61 +60,72 @@ class PrometheusHandler : public AsyncWebHandler, public Component { protected: std::string relabel_id_(EntityBase *obj); std::string relabel_name_(EntityBase *obj); + void add_area_label_(AsyncResponseStream *stream, std::string &area); + void add_node_label_(AsyncResponseStream *stream, std::string &node); + void add_friendly_name_label_(AsyncResponseStream *stream, std::string &friendly_name); #ifdef USE_SENSOR /// Return the type for prometheus void sensor_type_(AsyncResponseStream *stream); /// Return the sensor state as prometheus data point - void sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj); + void sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_BINARY_SENSOR /// Return the type for prometheus void binary_sensor_type_(AsyncResponseStream *stream); /// Return the sensor state as prometheus data point - void binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj); + void binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj, std::string &area, + std::string &node, std::string &friendly_name); #endif #ifdef USE_FAN /// Return the type for prometheus void fan_type_(AsyncResponseStream *stream); /// Return the sensor state as prometheus data point - void fan_row_(AsyncResponseStream *stream, fan::Fan *obj); + void fan_row_(AsyncResponseStream *stream, fan::Fan *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_LIGHT /// Return the type for prometheus void light_type_(AsyncResponseStream *stream); /// Return the Light Values state as prometheus data point - void light_row_(AsyncResponseStream *stream, light::LightState *obj); + void light_row_(AsyncResponseStream *stream, light::LightState *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_COVER /// Return the type for prometheus void cover_type_(AsyncResponseStream *stream); /// Return the switch Values state as prometheus data point - void cover_row_(AsyncResponseStream *stream, cover::Cover *obj); + void cover_row_(AsyncResponseStream *stream, cover::Cover *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_SWITCH /// Return the type for prometheus void switch_type_(AsyncResponseStream *stream); /// Return the switch Values state as prometheus data point - void switch_row_(AsyncResponseStream *stream, switch_::Switch *obj); + void switch_row_(AsyncResponseStream *stream, switch_::Switch *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_LOCK /// Return the type for prometheus void lock_type_(AsyncResponseStream *stream); /// Return the lock Values state as prometheus data point - void lock_row_(AsyncResponseStream *stream, lock::Lock *obj); + void lock_row_(AsyncResponseStream *stream, lock::Lock *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif #ifdef USE_TEXT_SENSOR /// Return the type for prometheus void text_sensor_type_(AsyncResponseStream *stream); /// Return the lock Values state as prometheus data point - void text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj); + void text_sensor_row_(AsyncResponseStream *stream, text_sensor::TextSensor *obj, std::string &area, std::string &node, + std::string &friendly_name); #endif web_server_base::WebServerBase *base_; diff --git a/tests/components/prometheus/common.yaml b/tests/components/prometheus/common.yaml index 7aa509f8b2..68ef2a2f58 100644 --- a/tests/components/prometheus/common.yaml +++ b/tests/components/prometheus/common.yaml @@ -1,3 +1,8 @@ +esphome: + name: livingroomdevice + friendly_name: Living Room Device + area: Living Room + wifi: ssid: MySSID password: password1 @@ -14,6 +19,9 @@ sensor: update_interval: 60s text_sensor: + - platform: version + name: "ESPHome Version" + hide_timestamp: true - platform: template id: template_text_sensor1 lambda: |- @@ -24,6 +32,52 @@ text_sensor: } update_interval: 60s +binary_sensor: + - platform: template + id: template_binary_sensor1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + +switch: + - platform: template + id: template_switch1 + lambda: |- + if (millis() > 10000) { + return true; + } else { + return false; + } + optimistic: true + +fan: + - platform: template + id: template_fan1 + +cover: + - platform: template + id: template_cover1 + lambda: |- + if (millis() > 10000) { + return COVER_OPEN; + } else { + return COVER_CLOSED; + } + +lock: + - platform: template + id: template_lock1 + lambda: |- + if (millis() > 10000) { + return LOCK_STATE_LOCKED; + } else { + return LOCK_STATE_UNLOCKED; + } + optimistic: true + prometheus: include_internal: true relabel: From ee3ee3a63b784767ea907f2f52935db34f0e1267 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:10:58 +1100 Subject: [PATCH 2591/2607] [http_request] Implement `on_error` trigger for requests (#7696) --- esphome/components/http_request/__init__.py | 12 ++++++++++++ esphome/components/http_request/http_request.h | 11 ++++++++--- tests/components/http_request/common.yaml | 2 ++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 0407bbd326..78064fb4b4 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ESP8266_DISABLE_SSL_SUPPORT, CONF_ID, CONF_METHOD, + CONF_ON_ERROR, CONF_TIMEOUT, CONF_TRIGGER_ID, CONF_URL, @@ -185,6 +186,13 @@ HTTP_REQUEST_ACTION_SCHEMA = cv.Schema( cv.Optional(CONF_ON_RESPONSE): automation.validate_automation( {cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(HttpRequestResponseTrigger)} ), + cv.Optional(CONF_ON_ERROR): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + automation.Trigger.template() + ) + } + ), cv.Optional(CONF_MAX_RESPONSE_BUFFER_SIZE, default="1kB"): cv.validate_bytes, } ) @@ -272,5 +280,9 @@ async def http_request_action_to_code(config, action_id, template_arg, args): ], conf, ) + for conf in config.get(CONF_ON_ERROR, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) + cg.add(var.register_error_trigger(trigger)) + await automation.build_automation(trigger, [], conf) return var diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index d87d9b8a45..4ed2c834f8 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -135,8 +135,8 @@ class HttpRequestComponent : public Component { protected: const char *useragent_{nullptr}; - bool follow_redirects_; - uint16_t redirect_limit_; + bool follow_redirects_{}; + uint16_t redirect_limit_{}; uint16_t timeout_{4500}; uint32_t watchdog_timeout_{0}; }; @@ -157,6 +157,8 @@ template class HttpRequestSendAction : public Action { void register_response_trigger(HttpRequestResponseTrigger *trigger) { this->response_triggers_.push_back(trigger); } + void register_error_trigger(Trigger<> *trigger) { this->error_triggers_.push_back(trigger); } + void set_max_response_buffer_size(size_t max_response_buffer_size) { this->max_response_buffer_size_ = max_response_buffer_size; } @@ -186,6 +188,8 @@ template class HttpRequestSendAction : public Action { auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, headers); if (container == nullptr) { + for (auto *trigger : this->error_triggers_) + trigger->trigger(x...); return; } @@ -237,7 +241,8 @@ template class HttpRequestSendAction : public Action { std::map> headers_{}; std::map> json_{}; std::function json_func_{nullptr}; - std::vector response_triggers_; + std::vector response_triggers_{}; + std::vector *> error_triggers_{}; size_t max_response_buffer_size_{SIZE_MAX}; }; diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml index 589b7fb4b4..593b85e435 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common.yaml @@ -12,6 +12,8 @@ esphome: url: https://esphome.io headers: Content-Type: application/json + on_error: + logger.log: "Request failed" on_response: then: - logger.log: From 6afd004ec54670ed27cd29202a7c290d258a8b64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:25:36 +1300 Subject: [PATCH 2592/2607] Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0 (#7700) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5072bec222..82d7ae5ee8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.10.3 + uses: pypa/gh-action-pypi-publish@v1.11.0 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From 765579dabbd607975901b34b350c4252f80ca3ab Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 30 Oct 2024 15:29:24 -0400 Subject: [PATCH 2593/2607] [es8311] Add es8311 dac component (#7693) --- CODEOWNERS | 1 + esphome/components/es8311/__init__.py | 0 esphome/components/es8311/audio_dac.py | 70 ++++++ esphome/components/es8311/es8311.cpp | 227 ++++++++++++++++++ esphome/components/es8311/es8311.h | 135 +++++++++++ esphome/components/es8311/es8311_const.h | 195 +++++++++++++++ esphome/components/i2s_audio/__init__.py | 4 +- esphome/const.py | 1 + tests/components/es8311/common.yaml | 15 ++ tests/components/es8311/test.esp32-ard.yaml | 5 + .../components/es8311/test.esp32-c3-ard.yaml | 5 + .../components/es8311/test.esp32-c3-idf.yaml | 5 + tests/components/es8311/test.esp32-idf.yaml | 5 + tests/components/es8311/test.esp8266-ard.yaml | 5 + 14 files changed, 670 insertions(+), 3 deletions(-) create mode 100644 esphome/components/es8311/__init__.py create mode 100644 esphome/components/es8311/audio_dac.py create mode 100644 esphome/components/es8311/es8311.cpp create mode 100644 esphome/components/es8311/es8311.h create mode 100644 esphome/components/es8311/es8311_const.h create mode 100644 tests/components/es8311/common.yaml create mode 100644 tests/components/es8311/test.esp32-ard.yaml create mode 100644 tests/components/es8311/test.esp32-c3-ard.yaml create mode 100644 tests/components/es8311/test.esp32-c3-idf.yaml create mode 100644 tests/components/es8311/test.esp32-idf.yaml create mode 100644 tests/components/es8311/test.esp8266-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 5eb1f863f2..8fbbacef59 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -131,6 +131,7 @@ esphome/components/ens160_base/* @latonita @vincentscode esphome/components/ens160_i2c/* @latonita esphome/components/ens160_spi/* @latonita esphome/components/ens210/* @itn3rd77 +esphome/components/es8311/* @kahrendt @kroimon esphome/components/esp32/* @esphome/core esphome/components/esp32_ble/* @Rapsssito @jesserockz esphome/components/esp32_ble_client/* @jesserockz diff --git a/esphome/components/es8311/__init__.py b/esphome/components/es8311/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/es8311/audio_dac.py b/esphome/components/es8311/audio_dac.py new file mode 100644 index 0000000000..1b450c3c11 --- /dev/null +++ b/esphome/components/es8311/audio_dac.py @@ -0,0 +1,70 @@ +import esphome.codegen as cg +from esphome.components import i2c +from esphome.components.audio_dac import AudioDac +import esphome.config_validation as cv +from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_SAMPLE_RATE + +CODEOWNERS = ["@kroimon", "@kahrendt"] +DEPENDENCIES = ["i2c"] + +es8311_ns = cg.esphome_ns.namespace("es8311") +ES8311 = es8311_ns.class_("ES8311", AudioDac, cg.Component, i2c.I2CDevice) + +CONF_MIC_GAIN = "mic_gain" +CONF_USE_MCLK = "use_mclk" +CONF_USE_MICROPHONE = "use_microphone" + +es8311_resolution = es8311_ns.enum("ES8311Resolution") +ES8311_BITS_PER_SAMPLE_ENUM = { + 16: es8311_resolution.ES8311_RESOLUTION_16, + 24: es8311_resolution.ES8311_RESOLUTION_24, + 32: es8311_resolution.ES8311_RESOLUTION_32, +} + +es8311_mic_gain = es8311_ns.enum("ES8311MicGain") +ES8311_MIC_GAIN_ENUM = { + "MIN": es8311_mic_gain.ES8311_MIC_GAIN_MIN, + "0DB": es8311_mic_gain.ES8311_MIC_GAIN_0DB, + "6DB": es8311_mic_gain.ES8311_MIC_GAIN_6DB, + "12DB": es8311_mic_gain.ES8311_MIC_GAIN_12DB, + "18DB": es8311_mic_gain.ES8311_MIC_GAIN_18DB, + "24DB": es8311_mic_gain.ES8311_MIC_GAIN_24DB, + "30DB": es8311_mic_gain.ES8311_MIC_GAIN_30DB, + "36DB": es8311_mic_gain.ES8311_MIC_GAIN_36DB, + "42DB": es8311_mic_gain.ES8311_MIC_GAIN_42DB, + "MAX": es8311_mic_gain.ES8311_MIC_GAIN_MAX, +} + + +_validate_bits = cv.float_with_unit("bits", "bit") + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ES8311), + cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All( + _validate_bits, cv.enum(ES8311_BITS_PER_SAMPLE_ENUM) + ), + cv.Optional(CONF_MIC_GAIN, default="42DB"): cv.enum( + ES8311_MIC_GAIN_ENUM, upper=True + ), + cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1), + cv.Optional(CONF_USE_MCLK, default=True): cv.boolean, + cv.Optional(CONF_USE_MICROPHONE, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x18)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) + cg.add(var.set_mic_gain(config[CONF_MIC_GAIN])) + cg.add(var.set_sample_frequency(config[CONF_SAMPLE_RATE])) + cg.add(var.set_use_mclk(config[CONF_USE_MCLK])) + cg.add(var.set_use_mic(config[CONF_USE_MICROPHONE])) diff --git a/esphome/components/es8311/es8311.cpp b/esphome/components/es8311/es8311.cpp new file mode 100644 index 0000000000..1cb1fbbe08 --- /dev/null +++ b/esphome/components/es8311/es8311.cpp @@ -0,0 +1,227 @@ +#include "es8311.h" +#include "es8311_const.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace es8311 { + +static const char *const TAG = "es8311"; + +// Mark the component as failed; use only in setup +#define ES8311_ERROR_FAILED(func) \ + if (!(func)) { \ + this->mark_failed(); \ + return; \ + } +// Return false; use outside of setup +#define ES8311_ERROR_CHECK(func) \ + if (!(func)) { \ + return false; \ + } + +void ES8311::setup() { + ESP_LOGCONFIG(TAG, "Setting up ES8311..."); + + // Reset + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x1F)); + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x00)); + + ES8311_ERROR_FAILED(this->configure_clock_()); + ES8311_ERROR_FAILED(this->configure_format_()); + ES8311_ERROR_FAILED(this->configure_mic_()); + + // Set initial volume + this->set_volume(0.75); // 0.75 = 0xBF = 0dB + + // Power up analog circuitry + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG0D_SYSTEM, 0x01)); + // Enable analog PGA, enable ADC modulator + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG0E_SYSTEM, 0x02)); + // Power up DAC + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG12_SYSTEM, 0x00)); + // Enable output to HP drive + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG13_SYSTEM, 0x10)); + // ADC Equalizer bypass, cancel DC offset in digital domain + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG1C_ADC, 0x6A)); + // Bypass DAC equalizer + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG37_DAC, 0x08)); + // Power On + ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x80)); +} + +void ES8311::dump_config() { + ESP_LOGCONFIG(TAG, "ES8311 Audio Codec:"); + ESP_LOGCONFIG(TAG, " Use MCLK: %s", YESNO(this->use_mclk_)); + ESP_LOGCONFIG(TAG, " Use Microphone: %s", YESNO(this->use_mic_)); + ESP_LOGCONFIG(TAG, " DAC Bits per Sample: %" PRIu8, this->resolution_out_); + ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_frequency_); + + if (this->is_failed()) { + ESP_LOGCONFIG(TAG, " Failed to initialize!"); + return; + } +} + +bool ES8311::set_volume(float volume) { + volume = clamp(volume, 0.0f, 1.0f); + uint8_t reg32 = remap(volume, 0.0f, 1.0f, 0, 255); + return this->write_byte(ES8311_REG32_DAC, reg32); +} + +float ES8311::volume() { + uint8_t reg32; + this->read_byte(ES8311_REG32_DAC, ®32); + return remap(reg32, 0, 255, 0.0f, 1.0f); +} + +uint8_t ES8311::calculate_resolution_value(ES8311Resolution resolution) { + switch (resolution) { + case ES8311_RESOLUTION_16: + return (3 << 2); + case ES8311_RESOLUTION_18: + return (2 << 2); + case ES8311_RESOLUTION_20: + return (1 << 2); + case ES8311_RESOLUTION_24: + return (0 << 2); + case ES8311_RESOLUTION_32: + return (4 << 2); + default: + return 0; + } +} + +const ES8311Coefficient *ES8311::get_coefficient(uint32_t mclk, uint32_t rate) { + for (const auto &coefficient : ES8311_COEFFICIENTS) { + if (coefficient.mclk == mclk && coefficient.rate == rate) + return &coefficient; + } + return nullptr; +} + +bool ES8311::configure_clock_() { + // Register 0x01: select clock source for internal MCLK and determine its frequency + uint8_t reg01 = 0x3F; // Enable all clocks + + uint32_t mclk_frequency = this->sample_frequency_ * this->mclk_multiple_; + if (!this->use_mclk_) { + reg01 |= BIT(7); // Use SCLK + mclk_frequency = this->sample_frequency_ * (int) this->resolution_out_ * 2; + } + if (this->mclk_inverted_) { + reg01 |= BIT(6); // Invert MCLK pin + } + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG01_CLK_MANAGER, reg01)); + + // Get clock coefficients from coefficient table + auto *coefficient = get_coefficient(mclk_frequency, this->sample_frequency_); + if (coefficient == nullptr) { + ESP_LOGE(TAG, "Unable to configure sample rate %" PRIu32 "Hz with %" PRIu32 "Hz MCLK", this->sample_frequency_, + mclk_frequency); + return false; + } + + // Register 0x02 + uint8_t reg02; + ES8311_ERROR_CHECK(this->read_byte(ES8311_REG02_CLK_MANAGER, ®02)); + reg02 &= 0x07; + reg02 |= (coefficient->pre_div - 1) << 5; + reg02 |= coefficient->pre_mult << 3; + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG02_CLK_MANAGER, reg02)); + + // Register 0x03 + const uint8_t reg03 = (coefficient->fs_mode << 6) | coefficient->adc_osr; + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG03_CLK_MANAGER, reg03)); + + // Register 0x04 + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG04_CLK_MANAGER, coefficient->dac_osr)); + + // Register 0x05 + const uint8_t reg05 = ((coefficient->adc_div - 1) << 4) | (coefficient->dac_div - 1); + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG05_CLK_MANAGER, reg05)); + + // Register 0x06 + uint8_t reg06; + ES8311_ERROR_CHECK(this->read_byte(ES8311_REG06_CLK_MANAGER, ®06)); + if (this->sclk_inverted_) { + reg06 |= BIT(5); + } else { + reg06 &= ~BIT(5); + } + reg06 &= 0xE0; + if (coefficient->bclk_div < 19) { + reg06 |= (coefficient->bclk_div - 1) << 0; + } else { + reg06 |= (coefficient->bclk_div) << 0; + } + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG06_CLK_MANAGER, reg06)); + + // Register 0x07 + uint8_t reg07; + ES8311_ERROR_CHECK(this->read_byte(ES8311_REG07_CLK_MANAGER, ®07)); + reg07 &= 0xC0; + reg07 |= coefficient->lrck_h << 0; + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG07_CLK_MANAGER, reg07)); + + // Register 0x08 + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG08_CLK_MANAGER, coefficient->lrck_l)); + + // Successfully configured the clock + return true; +} + +bool ES8311::configure_format_() { + // Configure I2S mode and format + uint8_t reg00; + ES8311_ERROR_CHECK(this->read_byte(ES8311_REG00_RESET, ®00)); + reg00 &= 0xBF; + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG00_RESET, reg00)); + + // Configure SDP in resolution + uint8_t reg09 = calculate_resolution_value(this->resolution_in_); + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG09_SDPIN, reg09)); + + // Configure SDP out resolution + uint8_t reg0a = calculate_resolution_value(this->resolution_out_); + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG0A_SDPOUT, reg0a)); + + // Successfully configured the format + return true; +} + +bool ES8311::configure_mic_() { + uint8_t reg14 = 0x1A; // Enable analog MIC and max PGA gain + if (this->use_mic_) { + reg14 |= BIT(6); // Enable PDM digital microphone + } + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG14_SYSTEM, reg14)); + + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG16_ADC, this->mic_gain_)); // ADC gain scale up + ES8311_ERROR_CHECK(this->write_byte(ES8311_REG17_ADC, 0xC8)); // Set ADC gain + + // Successfully configured the microphones + return true; +} + +bool ES8311::set_mute_state_(bool mute_state) { + uint8_t reg31; + + this->is_muted_ = mute_state; + + if (!this->read_byte(ES8311_REG31_DAC, ®31)) { + return false; + } + + if (mute_state) { + reg31 |= BIT(6) | BIT(5); + } else { + reg31 &= ~(BIT(6) | BIT(5)); + } + + return this->write_byte(ES8311_REG31_DAC, reg31); +} + +} // namespace es8311 +} // namespace esphome diff --git a/esphome/components/es8311/es8311.h b/esphome/components/es8311/es8311.h new file mode 100644 index 0000000000..840a07204c --- /dev/null +++ b/esphome/components/es8311/es8311.h @@ -0,0 +1,135 @@ +#pragma once + +#include "esphome/components/audio_dac/audio_dac.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace es8311 { + +enum ES8311MicGain { + ES8311_MIC_GAIN_MIN = -1, + ES8311_MIC_GAIN_0DB, + ES8311_MIC_GAIN_6DB, + ES8311_MIC_GAIN_12DB, + ES8311_MIC_GAIN_18DB, + ES8311_MIC_GAIN_24DB, + ES8311_MIC_GAIN_30DB, + ES8311_MIC_GAIN_36DB, + ES8311_MIC_GAIN_42DB, + ES8311_MIC_GAIN_MAX +}; + +enum ES8311Resolution : uint8_t { + ES8311_RESOLUTION_16 = 16, + ES8311_RESOLUTION_18 = 18, + ES8311_RESOLUTION_20 = 20, + ES8311_RESOLUTION_24 = 24, + ES8311_RESOLUTION_32 = 32 +}; + +struct ES8311Coefficient { + uint32_t mclk; // mclk frequency + uint32_t rate; // sample rate + uint8_t pre_div; // the pre divider with range from 1 to 8 + uint8_t pre_mult; // the pre multiplier with x1, x2, x4 and x8 selection + uint8_t adc_div; // adcclk divider + uint8_t dac_div; // dacclk divider + uint8_t fs_mode; // single speed (0) or double speed (1) + uint8_t lrck_h; // adc lrck divider and dac lrck divider + uint8_t lrck_l; // + uint8_t bclk_div; // sclk divider + uint8_t adc_osr; // adc osr + uint8_t dac_osr; // dac osr +}; + +class ES8311 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice { + public: + ///////////////////////// + // Component overrides // + ///////////////////////// + + void setup() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void dump_config() override; + + //////////////////////// + // AudioDac overrides // + //////////////////////// + + /// @brief Writes the volume out to the DAC + /// @param volume floating point between 0.0 and 1.0 + /// @return True if successful and false otherwise + bool set_volume(float volume) override; + + /// @brief Gets the current volume out from the DAC + /// @return floating point between 0.0 and 1.0 + float volume() override; + + /// @brief Disables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_off() override { return this->set_mute_state_(false); } + + /// @brief Enables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_on() override { return this->set_mute_state_(true); } + + bool is_muted() override { return this->is_muted_; } + + ////////////////////////////////// + // ES8311 configuration setters // + ////////////////////////////////// + + void set_use_mclk(bool use_mclk) { this->use_mclk_ = use_mclk; } + void set_bits_per_sample(ES8311Resolution resolution) { + this->resolution_in_ = resolution; + this->resolution_out_ = resolution; + } + void set_sample_frequency(uint32_t sample_frequency) { this->sample_frequency_ = sample_frequency; } + void set_use_mic(bool use_mic) { this->use_mic_ = use_mic; } + void set_mic_gain(ES8311MicGain mic_gain) { this->mic_gain_ = mic_gain; } + + protected: + /// @brief Computes the register value for the configured resolution (bits per sample) + /// @param resolution bits per sample enum for both audio in and audio out + /// @return register value + static uint8_t calculate_resolution_value(ES8311Resolution resolution); + + /// @brief Retrieves the appropriate registers values for the configured mclk and rate + /// @param mclk mlck frequency in Hz + /// @param rate sample rate frequency in Hz + /// @return ES8311Coeffecient containing appropriate register values to configure the ES8311 or nullptr if impossible + static const ES8311Coefficient *get_coefficient(uint32_t mclk, uint32_t rate); + + /// @brief Configures the ES8311 registers for the chosen sample rate + /// @return True if successful and false otherwise + bool configure_clock_(); + + /// @brief Configures the ES8311 registers for the chosen bits per sample + /// @return True if successful and false otherwise + bool configure_format_(); + + /// @brief Configures the ES8311 microphone registers + /// @return True if successful and false otherwise + bool configure_mic_(); + + /// @brief Mutes or unmute the DAC audio out + /// @param mute_state True to mute, false to unmute + /// @return + bool set_mute_state_(bool mute_state); + + bool use_mic_; + ES8311MicGain mic_gain_; + + bool use_mclk_; // true = use dedicated MCLK pin, false = use SCLK + bool sclk_inverted_{false}; // SCLK is inverted + bool mclk_inverted_{false}; // MCLK is inverted (ignored if use_mclk_ == false) + uint32_t mclk_multiple_{256}; // MCLK frequency is sample rate * mclk_multiple_ (ignored if use_mclk_ == false) + + uint32_t sample_frequency_; // in Hz + ES8311Resolution resolution_in_; + ES8311Resolution resolution_out_; +}; + +} // namespace es8311 +} // namespace esphome diff --git a/esphome/components/es8311/es8311_const.h b/esphome/components/es8311/es8311_const.h new file mode 100644 index 0000000000..7463a92ef1 --- /dev/null +++ b/esphome/components/es8311/es8311_const.h @@ -0,0 +1,195 @@ +#pragma once + +#include "es8311.h" + +namespace esphome { +namespace es8311 { + +// ES8311 register addresses +static const uint8_t ES8311_REG00_RESET = 0x00; // Reset +static const uint8_t ES8311_REG01_CLK_MANAGER = 0x01; // Clock Manager: select clk src for mclk, enable clock for codec +static const uint8_t ES8311_REG02_CLK_MANAGER = 0x02; // Clock Manager: clk divider and clk multiplier +static const uint8_t ES8311_REG03_CLK_MANAGER = 0x03; // Clock Manager: adc fsmode and osr +static const uint8_t ES8311_REG04_CLK_MANAGER = 0x04; // Clock Manager: dac osr +static const uint8_t ES8311_REG05_CLK_MANAGER = 0x05; // Clock Manager: clk divider for adc and dac +static const uint8_t ES8311_REG06_CLK_MANAGER = 0x06; // Clock Manager: bclk inverter BIT(5) and divider +static const uint8_t ES8311_REG07_CLK_MANAGER = 0x07; // Clock Manager: tri-state, lrck divider +static const uint8_t ES8311_REG08_CLK_MANAGER = 0x08; // Clock Manager: lrck divider +static const uint8_t ES8311_REG09_SDPIN = 0x09; // Serial Digital Port: DAC +static const uint8_t ES8311_REG0A_SDPOUT = 0x0A; // Serial Digital Port: ADC +static const uint8_t ES8311_REG0B_SYSTEM = 0x0B; // System +static const uint8_t ES8311_REG0C_SYSTEM = 0x0C; // System +static const uint8_t ES8311_REG0D_SYSTEM = 0x0D; // System: power up/down +static const uint8_t ES8311_REG0E_SYSTEM = 0x0E; // System: power up/down +static const uint8_t ES8311_REG0F_SYSTEM = 0x0F; // System: low power +static const uint8_t ES8311_REG10_SYSTEM = 0x10; // System +static const uint8_t ES8311_REG11_SYSTEM = 0x11; // System +static const uint8_t ES8311_REG12_SYSTEM = 0x12; // System: Enable DAC +static const uint8_t ES8311_REG13_SYSTEM = 0x13; // System +static const uint8_t ES8311_REG14_SYSTEM = 0x14; // System: select DMIC, select analog pga gain +static const uint8_t ES8311_REG15_ADC = 0x15; // ADC: adc ramp rate, dmic sense +static const uint8_t ES8311_REG16_ADC = 0x16; // ADC +static const uint8_t ES8311_REG17_ADC = 0x17; // ADC: volume +static const uint8_t ES8311_REG18_ADC = 0x18; // ADC: alc enable and winsize +static const uint8_t ES8311_REG19_ADC = 0x19; // ADC: alc maxlevel +static const uint8_t ES8311_REG1A_ADC = 0x1A; // ADC: alc automute +static const uint8_t ES8311_REG1B_ADC = 0x1B; // ADC: alc automute, adc hpf s1 +static const uint8_t ES8311_REG1C_ADC = 0x1C; // ADC: equalizer, hpf s2 +static const uint8_t ES8311_REG1D_ADCEQ = 0x1D; // ADCEQ: equalizer B0 +static const uint8_t ES8311_REG1E_ADCEQ = 0x1E; // ADCEQ: equalizer B0 +static const uint8_t ES8311_REG1F_ADCEQ = 0x1F; // ADCEQ: equalizer B0 +static const uint8_t ES8311_REG20_ADCEQ = 0x20; // ADCEQ: equalizer B0 +static const uint8_t ES8311_REG21_ADCEQ = 0x21; // ADCEQ: equalizer A1 +static const uint8_t ES8311_REG22_ADCEQ = 0x22; // ADCEQ: equalizer A1 +static const uint8_t ES8311_REG23_ADCEQ = 0x23; // ADCEQ: equalizer A1 +static const uint8_t ES8311_REG24_ADCEQ = 0x24; // ADCEQ: equalizer A1 +static const uint8_t ES8311_REG25_ADCEQ = 0x25; // ADCEQ: equalizer A2 +static const uint8_t ES8311_REG26_ADCEQ = 0x26; // ADCEQ: equalizer A2 +static const uint8_t ES8311_REG27_ADCEQ = 0x27; // ADCEQ: equalizer A2 +static const uint8_t ES8311_REG28_ADCEQ = 0x28; // ADCEQ: equalizer A2 +static const uint8_t ES8311_REG29_ADCEQ = 0x29; // ADCEQ: equalizer B1 +static const uint8_t ES8311_REG2A_ADCEQ = 0x2A; // ADCEQ: equalizer B1 +static const uint8_t ES8311_REG2B_ADCEQ = 0x2B; // ADCEQ: equalizer B1 +static const uint8_t ES8311_REG2C_ADCEQ = 0x2C; // ADCEQ: equalizer B1 +static const uint8_t ES8311_REG2D_ADCEQ = 0x2D; // ADCEQ: equalizer B2 +static const uint8_t ES8311_REG2E_ADCEQ = 0x2E; // ADCEQ: equalizer B2 +static const uint8_t ES8311_REG2F_ADCEQ = 0x2F; // ADCEQ: equalizer B2 +static const uint8_t ES8311_REG30_ADCEQ = 0x30; // ADCEQ: equalizer B2 +static const uint8_t ES8311_REG31_DAC = 0x31; // DAC: mute +static const uint8_t ES8311_REG32_DAC = 0x32; // DAC: volume +static const uint8_t ES8311_REG33_DAC = 0x33; // DAC: offset +static const uint8_t ES8311_REG34_DAC = 0x34; // DAC: drc enable, drc winsize +static const uint8_t ES8311_REG35_DAC = 0x35; // DAC: drc maxlevel, minilevel +static const uint8_t ES8311_REG36_DAC = 0x36; // DAC +static const uint8_t ES8311_REG37_DAC = 0x37; // DAC: ramprate +static const uint8_t ES8311_REG38_DACEQ = 0x38; // DACEQ: equalizer B0 +static const uint8_t ES8311_REG39_DACEQ = 0x39; // DACEQ: equalizer B0 +static const uint8_t ES8311_REG3A_DACEQ = 0x3A; // DACEQ: equalizer B0 +static const uint8_t ES8311_REG3B_DACEQ = 0x3B; // DACEQ: equalizer B0 +static const uint8_t ES8311_REG3C_DACEQ = 0x3C; // DACEQ: equalizer B1 +static const uint8_t ES8311_REG3D_DACEQ = 0x3D; // DACEQ: equalizer B1 +static const uint8_t ES8311_REG3E_DACEQ = 0x3E; // DACEQ: equalizer B1 +static const uint8_t ES8311_REG3F_DACEQ = 0x3F; // DACEQ: equalizer B1 +static const uint8_t ES8311_REG40_DACEQ = 0x40; // DACEQ: equalizer A1 +static const uint8_t ES8311_REG41_DACEQ = 0x41; // DACEQ: equalizer A1 +static const uint8_t ES8311_REG42_DACEQ = 0x42; // DACEQ: equalizer A1 +static const uint8_t ES8311_REG43_DACEQ = 0x43; // DACEQ: equalizer A1 +static const uint8_t ES8311_REG44_GPIO = 0x44; // GPIO: dac2adc for test +static const uint8_t ES8311_REG45_GP = 0x45; // GPIO: GP control +static const uint8_t ES8311_REGFA_I2C = 0xFA; // I2C: reset registers +static const uint8_t ES8311_REGFC_FLAG = 0xFC; // Flag +static const uint8_t ES8311_REGFD_CHD1 = 0xFD; // Chip: ID1 +static const uint8_t ES8311_REGFE_CHD2 = 0xFE; // Chip: ID2 +static const uint8_t ES8311_REGFF_CHVER = 0xFF; // Chip: Version + +// ES8311 clock divider coefficients +static const ES8311Coefficient ES8311_COEFFICIENTS[] = { + // clang-format off + + // mclk, rate, pre_ pre_ adc_ dac_ fs_ lrck lrck bclk_ adc_ dac_ + // div, mult, div, div, mode, _h, _l, div, osr, osr + + // 8k + {12288000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + {18432000, 8000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x20}, + {16384000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 8192000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 6144000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 4096000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 3072000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 2048000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1536000, 8000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1024000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + + // 11.025k + {11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 5644800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 2822400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1411200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + + // 12k + {12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 6144000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 3072000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1536000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + + // 16k + {12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + {18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x20}, + {16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 8192000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 6144000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 4096000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 3072000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 2048000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1536000, 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + { 1024000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20}, + + // 22.05k + {11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 5644800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 2822400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1411200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + + // 24k + {12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 6144000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 3072000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1536000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + + // 32k + {12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, + {16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 8192000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 6144000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 4096000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 3072000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 2048000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1536000, 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + { 1024000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + + // 44.1k + {11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 5644800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 2822400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1411200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + + // 48k + {12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 6144000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 3072000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1536000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + + // 64k + {12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, + {16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 8192000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 6144000, 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, + { 4096000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 3072000, 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, + { 2048000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1536000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18}, + { 1024000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + + // 88.2k + {11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 5644800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 2822400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1411200, 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + + // 96k + {12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 6144000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 3072000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + { 1536000, 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + + // clang-format on +}; + +} // namespace es8311 +} // namespace esphome diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index d376907925..fa515a585f 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -8,7 +8,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S3, ) import esphome.config_validation as cv -from esphome.const import CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE +from esphome.const import CONF_BITS_PER_SAMPLE, CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE from esphome.cpp_generator import MockObjClass import esphome.final_validate as fv @@ -25,13 +25,11 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" CONF_I2S_AUDIO = "i2s_audio" CONF_I2S_AUDIO_ID = "i2s_audio_id" -CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_I2S_MODE = "i2s_mode" CONF_PRIMARY = "primary" CONF_SECONDARY = "secondary" CONF_USE_APLL = "use_apll" -CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_BITS_PER_CHANNEL = "bits_per_channel" CONF_MONO = "mono" CONF_LEFT = "left" diff --git a/esphome/const.py b/esphome/const.py index c39061631b..5645c9eaab 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -92,6 +92,7 @@ CONF_BINARY_SENSORS = "binary_sensors" CONF_BINDKEY = "bindkey" CONF_BIRTH_MESSAGE = "birth_message" CONF_BIT_DEPTH = "bit_depth" +CONF_BITS_PER_SAMPLE = "bits_per_sample" CONF_BLOCK = "block" CONF_BLUE = "blue" CONF_BOARD = "board" diff --git a/tests/components/es8311/common.yaml b/tests/components/es8311/common.yaml new file mode 100644 index 0000000000..d833d1c043 --- /dev/null +++ b/tests/components/es8311/common.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - audio_dac.mute_off: + - audio_dac.mute_on: + - audio_dac.set_volume: + volume: 50% + +i2c: + - id: i2c_aic3204 + scl: ${scl_pin} + sda: ${sda_pin} + +audio_dac: + - platform: es8311 diff --git a/tests/components/es8311/test.esp32-ard.yaml b/tests/components/es8311/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8311/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8311/test.esp32-c3-ard.yaml b/tests/components/es8311/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8311/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8311/test.esp32-c3-idf.yaml b/tests/components/es8311/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8311/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8311/test.esp32-idf.yaml b/tests/components/es8311/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8311/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8311/test.esp8266-ard.yaml b/tests/components/es8311/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8311/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml From d3563e4e9782299c7820ad4783a1813a361a9575 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 31 Oct 2024 06:30:46 +1100 Subject: [PATCH 2594/2607] [sdl] Allow window to be resized. (#7698) --- esphome/components/sdl/sdl_esphome.cpp | 27 +++++++++++++++++++++----- esphome/components/sdl/sdl_esphome.h | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/esphome/components/sdl/sdl_esphome.cpp b/esphome/components/sdl/sdl_esphome.cpp index 5e17ca5650..8f0821a2fa 100644 --- a/esphome/components/sdl/sdl_esphome.cpp +++ b/esphome/components/sdl/sdl_esphome.cpp @@ -9,8 +9,9 @@ void Sdl::setup() { ESP_LOGD(TAG, "Starting setup"); SDL_Init(SDL_INIT_VIDEO); this->window_ = SDL_CreateWindow(App.get_name().c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - this->width_, this->height_, 0); + this->width_, this->height_, SDL_WINDOW_RESIZABLE); this->renderer_ = SDL_CreateRenderer(this->window_, -1, SDL_RENDERER_SOFTWARE); + SDL_RenderSetLogicalSize(this->renderer_, this->width_, this->height_); this->texture_ = SDL_CreateTexture(this->renderer_, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STATIC, this->width_, this->height_); SDL_SetTextureBlendMode(this->texture_, SDL_BLENDMODE_BLEND); @@ -25,6 +26,10 @@ void Sdl::update() { this->y_low_ = this->height_; this->x_high_ = 0; this->y_high_ = 0; + this->redraw_(rect); +} + +void Sdl::redraw_(SDL_Rect &rect) { SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect); SDL_RenderPresent(this->renderer_); } @@ -33,15 +38,13 @@ void Sdl::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t * display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { SDL_Rect rect{x_start, y_start, w, h}; if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || big_endian) { - display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, - x_pad); + Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad); } else { auto stride = x_offset + w + x_pad; auto data = ptr + (stride * y_offset + x_offset) * 2; SDL_UpdateTexture(this->texture_, &rect, data, stride * 2); } - SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect); - SDL_RenderPresent(this->renderer_); + this->redraw_(rect); } void Sdl::draw_pixel_at(int x, int y, Color color) { @@ -84,6 +87,20 @@ void Sdl::loop() { } break; + case SDL_WINDOWEVENT: + switch (e.window.event) { + case SDL_WINDOWEVENT_SIZE_CHANGED: + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_RESIZED: { + SDL_Rect rect{0, 0, this->width_, this->height_}; + this->redraw_(rect); + break; + } + default: + break; + } + break; + default: ESP_LOGV(TAG, "Event %d", e.type); break; diff --git a/esphome/components/sdl/sdl_esphome.h b/esphome/components/sdl/sdl_esphome.h index e4b2d9dd9f..4b0e59c9fe 100644 --- a/esphome/components/sdl/sdl_esphome.h +++ b/esphome/components/sdl/sdl_esphome.h @@ -38,6 +38,7 @@ class Sdl : public display::Display { protected: int get_width_internal() override { return this->width_; } int get_height_internal() override { return this->height_; } + void redraw_(SDL_Rect &rect); int width_{}; int height_{}; SDL_Renderer *renderer_{}; From e85157db4b246fd3c701c7b4195d4f52b735c554 Mon Sep 17 00:00:00 2001 From: Jason Nagin <33561705+JasonN3@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:34:33 -0400 Subject: [PATCH 2595/2607] Add config for current temperature precision (#7699) --- esphome/components/mqtt/mqtt_climate.cpp | 6 ++++-- esphome/components/mqtt/mqtt_const.h | 4 ++++ tests/components/mqtt/common.yaml | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index 49a8f06734..773d863835 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -71,8 +71,10 @@ void MQTTClimateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCo root[MQTT_MIN_TEMP] = traits.get_visual_min_temperature(); // max_temp root[MQTT_MAX_TEMP] = traits.get_visual_max_temperature(); - // temp_step - root["temp_step"] = traits.get_visual_target_temperature_step(); + // target_temp_step + root[MQTT_TARGET_TEMPERATURE_STEP] = traits.get_visual_target_temperature_step(); + // current_temp_step + root[MQTT_CURRENT_TEMPERATURE_STEP] = traits.get_visual_current_temperature_step(); // temperature units are always coerced to Celsius internally root[MQTT_TEMPERATURE_UNIT] = "C"; diff --git a/esphome/components/mqtt/mqtt_const.h b/esphome/components/mqtt/mqtt_const.h index c1c40c4b6d..445457a27f 100644 --- a/esphome/components/mqtt/mqtt_const.h +++ b/esphome/components/mqtt/mqtt_const.h @@ -51,6 +51,7 @@ constexpr const char *const MQTT_COMMAND_TOPIC = "cmd_t"; constexpr const char *const MQTT_CONFIGURATION_URL = "cu"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "curr_hum_tpl"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "curr_hum_t"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_STEP = "precision"; constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "curr_temp_tpl"; constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "curr_temp_t"; constexpr const char *const MQTT_DEVICE = "dev"; @@ -232,6 +233,7 @@ constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "hum_cmd_tpl constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "hum_cmd_t"; constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "hum_state_tpl"; constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "hum_stat_t"; +constexpr const char *const MQTT_TARGET_TEMPERATURE_STEP = "temp_step"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temp_cmd_tpl"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temp_cmd_t"; constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temp_hi_cmd_tpl"; @@ -313,6 +315,7 @@ constexpr const char *const MQTT_COMMAND_TOPIC = "command_topic"; constexpr const char *const MQTT_CONFIGURATION_URL = "configuration_url"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template"; constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"; +constexpr const char *const MQTT_CURRENT_TEMPERATURE_STEP = "precision"; constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "current_temperature_template"; constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "current_temperature_topic"; constexpr const char *const MQTT_DEVICE = "device"; @@ -494,6 +497,7 @@ constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "target_humi constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic"; constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template"; constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic"; +constexpr const char *const MQTT_TARGET_TEMPERATURE_STEP = "temp_step"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temperature_command_template"; constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temperature_command_topic"; constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temperature_high_command_template"; diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index 5ed6335d65..e154be8b5c 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -200,6 +200,10 @@ climate: fan_only_cooling: true fan_with_cooling: true fan_with_heating: true + visual: + temperature_step: + target_temperature: 0.1 + current_temperature: 0.1 cover: - platform: template From 5a2fed35693f7191f81fe31236e69c2132c23d99 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:28:18 +1100 Subject: [PATCH 2596/2607] [spi] Add mosi pin checks for displays (#7702) --- esphome/components/ili9xxx/display.py | 4 ++++ esphome/components/pcd8544/display.py | 12 +++++++---- esphome/components/ssd1306_spi/display.py | 8 +++++-- esphome/components/ssd1322_spi/display.py | 8 +++++-- esphome/components/ssd1325_spi/display.py | 8 +++++-- esphome/components/ssd1327_spi/display.py | 8 +++++-- esphome/components/ssd1331_spi/display.py | 8 +++++-- esphome/components/ssd1351_spi/display.py | 8 +++++-- esphome/components/st7567_spi/display.py | 8 +++++-- esphome/components/st7701s/display.py | 4 ++++ esphome/components/st7735/display.py | 17 +++++++++------ esphome/components/st7789v/display.py | 21 ++++++++++++------- .../components/waveshare_epaper/display.py | 8 +++++-- 13 files changed, 88 insertions(+), 34 deletions(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 68e3aa953d..739ad07843 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -196,6 +196,10 @@ CONFIG_SCHEMA = cv.All( _validate, ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ili9xxx", require_miso=False, require_mosi=True +) + async def to_code(config): rhs = MODELS[config[CONF_MODEL]].new() diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py index d7e72d1c81..2c24b133da 100644 --- a/esphome/components/pcd8544/display.py +++ b/esphome/components/pcd8544/display.py @@ -1,15 +1,15 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import display, spi +import esphome.config_validation as cv from esphome.const import ( + CONF_CONTRAST, + CONF_CS_PIN, CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES, CONF_RESET_PIN, - CONF_CS_PIN, - CONF_CONTRAST, ) DEPENDENCIES = ["spi"] @@ -35,6 +35,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "pcd8544", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1306_spi/display.py b/esphome/components/ssd1306_spi/display.py index 0af1168bde..4af41073d4 100644 --- a/esphome/components/ssd1306_spi/display.py +++ b/esphome/components/ssd1306_spi/display.py @@ -1,8 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1306_base from esphome.components.ssd1306_base import _validate +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES AUTO_LOAD = ["ssd1306_base"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( _validate, ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1306_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1322_spi/display.py b/esphome/components/ssd1322_spi/display.py index 88b3a53355..849e71abee 100644 --- a/esphome/components/ssd1322_spi/display.py +++ b/esphome/components/ssd1322_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1322_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@kbx81"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1322_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1325_spi/display.py b/esphome/components/ssd1325_spi/display.py index a86dc751d5..e18db33c68 100644 --- a/esphome/components/ssd1325_spi/display.py +++ b/esphome/components/ssd1325_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1325_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@kbx81"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1325_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1327_spi/display.py b/esphome/components/ssd1327_spi/display.py index 138e85eecd..b622c098ec 100644 --- a/esphome/components/ssd1327_spi/display.py +++ b/esphome/components/ssd1327_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1327_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@kbx81"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1327_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1331_spi/display.py b/esphome/components/ssd1331_spi/display.py index c32ac60578..50895b3175 100644 --- a/esphome/components/ssd1331_spi/display.py +++ b/esphome/components/ssd1331_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1331_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@kbx81"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1331_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/ssd1351_spi/display.py b/esphome/components/ssd1351_spi/display.py index 3f3409226c..bd7033c3d4 100644 --- a/esphome/components/ssd1351_spi/display.py +++ b/esphome/components/ssd1351_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, ssd1351_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@kbx81"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "ssd1351_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/st7567_spi/display.py b/esphome/components/st7567_spi/display.py index aabe02a2d8..305aa35024 100644 --- a/esphome/components/st7567_spi/display.py +++ b/esphome/components/st7567_spi/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import spi, st7567_base +import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES CODEOWNERS = ["@latonita"] @@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "st7567_spi", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py index e73c2467da..c6ad43c14c 100644 --- a/esphome/components/st7701s/display.py +++ b/esphome/components/st7701s/display.py @@ -167,6 +167,10 @@ CONFIG_SCHEMA = cv.All( cv.only_with_esp_idf, ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "st7701s", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/st7735/display.py b/esphome/components/st7735/display.py index d5bb2fa3d6..2761214315 100644 --- a/esphome/components/st7735/display.py +++ b/esphome/components/st7735/display.py @@ -1,17 +1,17 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins -from esphome.components import spi -from esphome.components import display +import esphome.codegen as cg +from esphome.components import display, spi +import esphome.config_validation as cv from esphome.const import ( CONF_DC_PIN, CONF_ID, + CONF_INVERT_COLORS, CONF_LAMBDA, CONF_MODEL, - CONF_RESET_PIN, CONF_PAGES, - CONF_INVERT_COLORS, + CONF_RESET_PIN, ) + from . import st7735_ns CODEOWNERS = ["@SenexCrenshaw"] @@ -68,6 +68,11 @@ CONFIG_SCHEMA = cv.All( ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "st7735", require_miso=False, require_mosi=True +) + + async def setup_st7735(var, config): await display.register_display(var, config) diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index 04dce2cf6c..8259eacf2d 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -1,22 +1,23 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins -from esphome.components import display, spi, power_supply +import esphome.codegen as cg +from esphome.components import display, power_supply, spi +import esphome.config_validation as cv from esphome.const import ( CONF_BACKLIGHT_PIN, + CONF_CS_PIN, CONF_DC_PIN, CONF_HEIGHT, CONF_ID, CONF_LAMBDA, CONF_MODEL, - CONF_RESET_PIN, - CONF_WIDTH, - CONF_POWER_SUPPLY, - CONF_ROTATION, - CONF_CS_PIN, CONF_OFFSET_HEIGHT, CONF_OFFSET_WIDTH, + CONF_POWER_SUPPLY, + CONF_RESET_PIN, + CONF_ROTATION, + CONF_WIDTH, ) + from . import st7789v_ns CONF_EIGHTBITCOLOR = "eightbitcolor" @@ -168,6 +169,10 @@ CONFIG_SCHEMA = cv.All( validate_st7789v, ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "st7789v", require_miso=False, require_mosi=True +) + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 4d3965449f..8287788de5 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import core, pins +import esphome.codegen as cg from esphome.components import display, spi +import esphome.config_validation as cv from esphome.const import ( CONF_BUSY_PIN, CONF_DC_PIN, @@ -187,6 +187,10 @@ CONFIG_SCHEMA = cv.All( cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), ) +FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( + "waveshare_epaper", require_miso=False, require_mosi=True +) + async def to_code(config): model_type, model = MODELS[config[CONF_MODEL]] From 74ea1b60e35fa351b5a5fc380dfdc1879d22f043 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:37:54 +1300 Subject: [PATCH 2597/2607] [CI] Fix webserver defines to be present based on platform, not just framework (#7703) --- esphome/core/defines.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index b5511b57eb..3798ddba6a 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -86,8 +86,6 @@ #ifdef USE_ARDUINO #define USE_CAPTIVE_PORTAL #define USE_PROMETHEUS -#define USE_WEBSERVER -#define USE_WEBSERVER_PORT 80 // NOLINT #define USE_WIFI_WPA2_EAP #endif @@ -111,6 +109,8 @@ #define USE_SPEAKER #define USE_SPI #define USE_VOICE_ASSISTANT +#define USE_WEBSERVER +#define USE_WEBSERVER_PORT 80 // NOLINT #define USE_WIFI_11KV_SUPPORT #ifdef USE_ARDUINO @@ -147,6 +147,8 @@ #define USE_SHD_FIRMWARE_DATA \ {} +#define USE_WEBSERVER +#define USE_WEBSERVER_PORT 80 // NOLINT #endif #ifdef USE_RP2040 @@ -158,6 +160,8 @@ #ifdef USE_LIBRETINY #define USE_SOCKET_IMPL_LWIP_SOCKETS +#define USE_WEBSERVER +#define USE_WEBSERVER_PORT 80 // NOLINT #endif #ifdef USE_HOST From 8b7e061f3ac5427dcc931feffdd0251100945a57 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:15:39 +1100 Subject: [PATCH 2598/2607] [touchscreen] Calibration fixes (#7704) --- esphome/components/touchscreen/__init__.py | 97 +++++++++---------- esphome/components/touchscreen/touchscreen.h | 12 +-- .../xpt2046/touchscreen/__init__.py | 39 ++------ tests/components/xpt2046/test.esp32-ard.yaml | 4 +- .../components/xpt2046/test.esp32-c3-ard.yaml | 2 +- .../components/xpt2046/test.esp32-c3-idf.yaml | 2 +- tests/components/xpt2046/test.esp32-idf.yaml | 2 +- .../components/xpt2046/test.esp8266-ard.yaml | 2 +- tests/components/xpt2046/test.rp2040-ard.yaml | 4 +- 9 files changed, 63 insertions(+), 101 deletions(-) diff --git a/esphome/components/touchscreen/__init__.py b/esphome/components/touchscreen/__init__.py index b2d3f60d2b..01a271a34e 100644 --- a/esphome/components/touchscreen/__init__.py +++ b/esphome/components/touchscreen/__init__.py @@ -1,21 +1,18 @@ -import esphome.config_validation as cv -import esphome.codegen as cg - -from esphome.components import display from esphome import automation - +import esphome.codegen as cg +from esphome.components import display +import esphome.config_validation as cv from esphome.const import ( + CONF_CALIBRATION, CONF_DISPLAY, - CONF_ON_TOUCH, - CONF_ON_RELEASE, - CONF_ON_UPDATE, - CONF_SWAP_XY, CONF_MIRROR_X, CONF_MIRROR_Y, + CONF_ON_RELEASE, + CONF_ON_TOUCH, + CONF_ON_UPDATE, + CONF_SWAP_XY, CONF_TRANSFORM, - CONF_CALIBRATION, ) - from esphome.core import coroutine_with_priority CODEOWNERS = ["@jesserockz", "@nielsnl68"] @@ -43,51 +40,45 @@ CONF_Y_MIN = "y_min" CONF_Y_MAX = "y_max" -def validate_calibration(config): - if CONF_CALIBRATION in config: - calibration_config = config[CONF_CALIBRATION] - if ( - cv.int_([CONF_X_MIN]) != 0 - and cv.int_(calibration_config[CONF_X_MAX]) != 0 - and abs( - cv.int_(calibration_config[CONF_X_MIN]) - - cv.int_(calibration_config[CONF_X_MAX]) - ) - < 10 - ): - raise cv.Invalid("Calibration X values difference must be more than 10") - - if ( - cv.int_(calibration_config[CONF_Y_MIN]) != 0 - and cv.int_(calibration_config[CONF_Y_MAX]) != 0 - and abs( - cv.int_(calibration_config[CONF_Y_MIN]) - - cv.int_(calibration_config[CONF_Y_MAX]) - ) - < 10 - ): - raise cv.Invalid("Calibration Y values difference must be more than 10") - - return config +def validate_calibration(calibration_config): + x_min = calibration_config[CONF_X_MIN] + x_max = calibration_config[CONF_X_MAX] + y_min = calibration_config[CONF_Y_MIN] + y_max = calibration_config[CONF_Y_MAX] + if x_max < x_min: + raise cv.Invalid( + "x_min must be smaller than x_max. To mirror the direction use the 'transform' options" + ) + if y_max < y_min: + raise cv.Invalid( + "y_min must be smaller than y_max. To mirror the direction use the 'transform' options" + ) + x_delta = x_max - x_min + y_delta = y_max - y_min + if x_delta < 10 or y_delta < 10: + raise cv.Invalid("Calibration value range must be greater than 10") + return calibration_config -def calibration_schema(default_max_values): - return cv.Schema( +CALIBRATION_SCHEMA = cv.All( + cv.Schema( { - cv.Optional(CONF_X_MIN, default=0): cv.int_range(min=0, max=4095), - cv.Optional(CONF_X_MAX, default=default_max_values): cv.int_range( - min=0, max=4095 - ), - cv.Optional(CONF_Y_MIN, default=0): cv.int_range(min=0, max=4095), - cv.Optional(CONF_Y_MAX, default=default_max_values): cv.int_range( - min=0, max=4095 - ), - }, - validate_calibration, + cv.Required(CONF_X_MIN): cv.int_range(min=0, max=4095), + cv.Required(CONF_X_MAX): cv.int_range(min=0, max=4095), + cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=4095), + cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=4095), + } + ), + validate_calibration, +) + + +def touchscreen_schema(default_touch_timeout=cv.UNDEFINED, calibration_required=False): + calibration = ( + cv.Required(CONF_CALIBRATION) + if calibration_required + else cv.Optional(CONF_CALIBRATION) ) - - -def touchscreen_schema(default_touch_timeout): return cv.Schema( { cv.GenerateID(CONF_DISPLAY): cv.use_id(display.Display), @@ -102,7 +93,7 @@ def touchscreen_schema(default_touch_timeout): cv.positive_time_period_milliseconds, cv.Range(max=cv.TimePeriod(milliseconds=65535)), ), - cv.Optional(CONF_CALIBRATION): calibration_schema(0), + calibration: CALIBRATION_SCHEMA, cv.Optional(CONF_ON_TOUCH): automation.validate_automation(single=True), cv.Optional(CONF_ON_UPDATE): automation.validate_automation(single=True), cv.Optional(CONF_ON_RELEASE): automation.validate_automation(single=True), diff --git a/esphome/components/touchscreen/touchscreen.h b/esphome/components/touchscreen/touchscreen.h index 21111f87b3..8016323d49 100644 --- a/esphome/components/touchscreen/touchscreen.h +++ b/esphome/components/touchscreen/touchscreen.h @@ -53,14 +53,10 @@ class Touchscreen : public PollingComponent { void set_swap_xy(bool swap) { this->swap_x_y_ = swap; } void set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) { - this->x_raw_min_ = std::min(x_min, x_max); - this->x_raw_max_ = std::max(x_min, x_max); - this->y_raw_min_ = std::min(y_min, y_max); - this->y_raw_max_ = std::max(y_min, y_max); - if (x_min > x_max) - this->invert_x_ = true; - if (y_min > y_max) - this->invert_y_ = true; + this->x_raw_min_ = x_min; + this->x_raw_max_ = x_max; + this->y_raw_min_ = y_min; + this->y_raw_max_ = y_max; } Trigger *get_touch_trigger() { return &this->touch_trigger_; } diff --git a/esphome/components/xpt2046/touchscreen/__init__.py b/esphome/components/xpt2046/touchscreen/__init__.py index d45f309a3b..d91ae44789 100644 --- a/esphome/components/xpt2046/touchscreen/__init__.py +++ b/esphome/components/xpt2046/touchscreen/__init__.py @@ -1,9 +1,8 @@ -import esphome.codegen as cg -import esphome.config_validation as cv - from esphome import pins +import esphome.codegen as cg from esphome.components import spi, touchscreen -from esphome.const import CONF_ID, CONF_THRESHOLD, CONF_INTERRUPT_PIN +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_THRESHOLD CODEOWNERS = ["@numo68", "@nielsnl68"] DEPENDENCIES = ["spi"] @@ -15,13 +14,9 @@ XPT2046Component = XPT2046_ns.class_( spi.SPIDevice, ) -CONF_CALIBRATION_X_MIN = "calibration_x_min" -CONF_CALIBRATION_X_MAX = "calibration_x_max" -CONF_CALIBRATION_Y_MIN = "calibration_y_min" -CONF_CALIBRATION_Y_MAX = "calibration_y_max" - CONFIG_SCHEMA = cv.All( - touchscreen.TOUCHSCREEN_SCHEMA.extend( + touchscreen.touchscreen_schema(calibration_required=True) + .extend( cv.Schema( { cv.GenerateID(): cv.declare_id(XPT2046Component), @@ -29,30 +24,10 @@ CONFIG_SCHEMA = cv.All( pins.internal_gpio_input_pin_schema ), cv.Optional(CONF_THRESHOLD, default=400): cv.int_range(min=0, max=4095), - cv.Optional( - touchscreen.CONF_CALIBRATION - ): touchscreen.calibration_schema(4095), - cv.Optional(CONF_CALIBRATION_X_MIN): cv.invalid( - "Deprecated: use the new 'calibration' configuration variable" - ), - cv.Optional(CONF_CALIBRATION_X_MAX): cv.invalid( - "Deprecated: use the new 'calibration' configuration variable" - ), - cv.Optional(CONF_CALIBRATION_Y_MIN): cv.invalid( - "Deprecated: use the new 'calibration' configuration variable" - ), - cv.Optional(CONF_CALIBRATION_Y_MAX): cv.invalid( - "Deprecated: use the new 'calibration' configuration variable" - ), - cv.Optional(CONF_CALIBRATION_Y_MAX): cv.invalid( - "Deprecated: use the new 'calibration' configuration variable" - ), - cv.Optional("report_interval"): cv.invalid( - "Deprecated: use the 'update_interval' configuration variable" - ), }, ) - ).extend(spi.spi_device_schema()), + ) + .extend(spi.spi_device_schema()), ) diff --git a/tests/components/xpt2046/test.esp32-ard.yaml b/tests/components/xpt2046/test.esp32-ard.yaml index f15d1f9b41..9e305791e0 100644 --- a/tests/components/xpt2046/test.esp32-ard.yaml +++ b/tests/components/xpt2046/test.esp32-ard.yaml @@ -25,8 +25,8 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 - x_max: 280 + x_min: 280 + x_max: 3860 y_min: 340 y_max: 3860 on_touch: diff --git a/tests/components/xpt2046/test.esp32-c3-ard.yaml b/tests/components/xpt2046/test.esp32-c3-ard.yaml index ef4daa800d..c03fd6b345 100644 --- a/tests/components/xpt2046/test.esp32-c3-ard.yaml +++ b/tests/components/xpt2046/test.esp32-c3-ard.yaml @@ -25,7 +25,7 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 + x_min: 28 x_max: 280 y_min: 340 y_max: 3860 diff --git a/tests/components/xpt2046/test.esp32-c3-idf.yaml b/tests/components/xpt2046/test.esp32-c3-idf.yaml index ef4daa800d..787ca9b1ed 100644 --- a/tests/components/xpt2046/test.esp32-c3-idf.yaml +++ b/tests/components/xpt2046/test.esp32-c3-idf.yaml @@ -25,7 +25,7 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 + x_min: 50 x_max: 280 y_min: 340 y_max: 3860 diff --git a/tests/components/xpt2046/test.esp32-idf.yaml b/tests/components/xpt2046/test.esp32-idf.yaml index f15d1f9b41..e79997146b 100644 --- a/tests/components/xpt2046/test.esp32-idf.yaml +++ b/tests/components/xpt2046/test.esp32-idf.yaml @@ -25,7 +25,7 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 + x_min: 50 x_max: 280 y_min: 340 y_max: 3860 diff --git a/tests/components/xpt2046/test.esp8266-ard.yaml b/tests/components/xpt2046/test.esp8266-ard.yaml index 0daa25ad60..ab71f7b8bc 100644 --- a/tests/components/xpt2046/test.esp8266-ard.yaml +++ b/tests/components/xpt2046/test.esp8266-ard.yaml @@ -25,7 +25,7 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 + x_min: 50 x_max: 280 y_min: 340 y_max: 3860 diff --git a/tests/components/xpt2046/test.rp2040-ard.yaml b/tests/components/xpt2046/test.rp2040-ard.yaml index 8afc45d04d..622e69ac98 100644 --- a/tests/components/xpt2046/test.rp2040-ard.yaml +++ b/tests/components/xpt2046/test.rp2040-ard.yaml @@ -25,8 +25,8 @@ touchscreen: update_interval: 50ms threshold: 400 calibration: - x_min: 3860 - x_max: 280 + x_min: 280 + x_max: 3860 y_min: 340 y_max: 3860 on_touch: From a043022444609d11b2a8b040ae9515e54ce940f2 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Thu, 31 Oct 2024 05:36:23 +0200 Subject: [PATCH 2599/2607] [font] Add support for "glyphsets" (#7429) Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com> --- docker/Dockerfile | 70 +- esphome/components/font/__init__.py | 303 +- requirements.txt | 3 + requirements_optional.txt | 1 - script/ci-custom.py | 2 +- tests/components/font/.gitattributes | 2 + tests/components/font/MatrixChunky8X.bdf | 7461 ++++++++++++++++++++++ tests/components/font/common.yaml | 24 + tests/components/font/test.host.yaml | 34 + tests/components/font/x11.pcf | Bin 0 -> 13368 bytes 10 files changed, 7771 insertions(+), 129 deletions(-) create mode 100644 tests/components/font/.gitattributes create mode 100644 tests/components/font/MatrixChunky8X.bdf create mode 100644 tests/components/font/x11.pcf diff --git a/docker/Dockerfile b/docker/Dockerfile index 52a4794f24..44ee879a12 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -40,25 +40,6 @@ RUN \ libcairo2=1.16.0-7 \ libmagic1=1:5.44-3 \ patch=2.7.6-7 \ - && ( \ - ( \ - [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \ - apt-get install -y --no-install-recommends \ - build-essential=12.9 \ - python3-dev=3.11.2-1+b1 \ - zlib1g-dev=1:1.2.13.dfsg-1 \ - libjpeg-dev=1:2.1.5-2 \ - libfreetype-dev=2.12.1+dfsg-5+deb12u3 \ - libssl-dev=3.0.14-1~deb12u2 \ - libffi-dev=3.4.4-1 \ - libopenjp2-7=2.5.0-2 \ - libtiff6=4.5.0-6+deb12u1 \ - cargo=0.66.0+ds1-1 \ - pkg-config=1.8.1-1 \ - gcc-arm-linux-gnueabihf=4:12.2.0-3 \ - ) \ - || [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \ - ) \ && rm -rf \ /tmp/* \ /var/{cache,log}/* \ @@ -97,15 +78,48 @@ RUN \ # tmpfs is for https://github.com/rust-lang/cargo/issues/8719 COPY requirements.txt requirements_optional.txt / -RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ - curl -L https://www.piwheels.org/cp311/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ - && pip3 install --break-system-packages --no-cache-dir /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ - && rm /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \ - && export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ - fi; \ - CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \ - pip3 install \ - --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt +RUN --mount=type=tmpfs,target=/root/.cargo < len(y_): return 1 - raise cv.Invalid(f"Found duplicate glyph {x}") + return 0 -def validate_glyphs(value): - if isinstance(value, list): - value = cv.Schema([cv.string])(value) - value = cv.Schema([cv.string])(list(value)) +def flatten(lists) -> list: + """ + Given a list of lists, flatten it to a single list of all elements of all lists. + This wraps itertools.chain.from_iterable to make it more readable, and return a list + rather than a single use iterable. + """ + from itertools import chain - value.sort(key=functools.cmp_to_key(glyph_comparator)) - return value + return list(chain.from_iterable(lists)) -font_map = {} +def check_missing_glyphs(file, codepoints: Iterable, warning: bool = False): + """ + Check that the given font file actually contains the requested glyphs + :param file: A Truetype font file + :param codepoints: A list of codepoints to check + :param warning: If true, log a warning instead of raising an exception + """ - -def merge_glyphs(config): - glyphs = [] - glyphs.extend(config[CONF_GLYPHS]) - font_list = [(EFont(config[CONF_FILE], config[CONF_SIZE], config[CONF_GLYPHS]))] - if extras := config.get(CONF_EXTRAS): - extra_fonts = list( - map( - lambda x: EFont(x[CONF_FILE], config[CONF_SIZE], x[CONF_GLYPHS]), extras - ) + font = FONT_CACHE[file] + missing = [chr(x) for x in codepoints if font.get_char_index(x) == 0] + if missing: + # Only list up to 10 missing glyphs + missing.sort(key=functools.cmp_to_key(glyph_comparator)) + count = len(missing) + missing = missing[:10] + missing_str = "\n ".join( + f"{x} ({x.encode('unicode_escape')})" for x in missing ) - font_list.extend(extra_fonts) - for extra in extras: - glyphs.extend(extra[CONF_GLYPHS]) - validate_glyphs(glyphs) - font_map[config[CONF_ID]] = font_list + if count > 10: + missing_str += f"\n and {count - 10} more." + message = f"Font {Path(file).name} is missing {count} glyph{'s' if count != 1 else ''}:\n {missing_str}" + if warning: + _LOGGER.warning(message) + else: + raise cv.Invalid(message) + + +def validate_glyphs(config): + """ + Check for duplicate codepoints, then check that all requested codepoints actually + have glyphs defined in the appropriate font file. + """ + + # Collect all glyph codepoints and flatten to a list of chars + glyphspoints = flatten( + [x[CONF_GLYPHS] for x in config[CONF_EXTRAS]] + config[CONF_GLYPHS] + ) + # Convert a list of strings to a list of chars (one char strings) + glyphspoints = flatten([list(x) for x in glyphspoints]) + if len(set(glyphspoints)) != len(glyphspoints): + duplicates = {x for x in glyphspoints if glyphspoints.count(x) > 1} + dup_str = ", ".join(f"{x} ({x.encode('unicode_escape')})" for x in duplicates) + raise cv.Invalid( + f"Found duplicate glyph{'s' if len(duplicates) != 1 else ''}: {dup_str}" + ) + # convert to codepoints + glyphspoints = {ord(x) for x in glyphspoints} + fileconf = config[CONF_FILE] + setpoints = set( + flatten([glyphsets.unicodes_per_glyphset(x) for x in config[CONF_GLYPHSETS]]) + ) + # Make setpoints and glyphspoints disjoint + setpoints.difference_update(glyphspoints) + if fileconf[CONF_TYPE] == TYPE_LOCAL_BITMAP: + # Pillow only allows 256 glyphs per bitmap font. Not sure if that is a Pillow limitation + # or a file format limitation + if any(x >= 256 for x in setpoints.copy().union(glyphspoints)): + raise cv.Invalid("Codepoints in bitmap fonts must be in the range 0-255") + else: + # for TT fonts, check that glyphs are actually present + # Check extras against their own font, exclude from parent font codepoints + for extra in config[CONF_EXTRAS]: + points = {ord(x) for x in flatten(extra[CONF_GLYPHS])} + glyphspoints.difference_update(points) + setpoints.difference_update(points) + check_missing_glyphs(extra[CONF_FILE][CONF_PATH], points) + + # A named glyph that can't be provided is an error + check_missing_glyphs(fileconf[CONF_PATH], glyphspoints) + # A missing glyph from a set is a warning. + if not config[CONF_IGNORE_MISSING_GLYPHS]: + check_missing_glyphs(fileconf[CONF_PATH], setpoints, warning=True) + + # Populate the default after the above checks so that use of the default doesn't trigger errors + if not config[CONF_GLYPHS] and not config[CONF_GLYPHSETS]: + if fileconf[CONF_TYPE] == TYPE_LOCAL_BITMAP: + config[CONF_GLYPHS] = [DEFAULT_GLYPHS] + else: + # set a default glyphset, intersected with what the font actually offers + font = FONT_CACHE[fileconf[CONF_PATH]] + config[CONF_GLYPHS] = [ + chr(x) + for x in glyphsets.unicodes_per_glyphset(DEFAULT_GLYPHSET) + if font.get_char_index(x) != 0 + ] + return config @@ -120,7 +205,7 @@ def validate_truetype_file(value): ) if not any(map(value.lower().endswith, FONT_EXTENSIONS)): raise cv.Invalid(f"Only {FONT_EXTENSIONS} files are supported.") - return cv.file_(value) + return CORE.relative_config_path(cv.file_(value)) TYPE_LOCAL = "local" @@ -139,6 +224,10 @@ LOCAL_BITMAP_SCHEMA = cv.Schema( } ) +FULLPATH_SCHEMA = cv.maybe_simple_value( + {cv.Required(CONF_PATH): cv.string}, key=CONF_PATH +) + CONF_ITALIC = "italic" FONT_WEIGHTS = { "thin": 100, @@ -167,13 +256,13 @@ def _compute_local_font_path(value: dict) -> Path: return base_dir / key -def get_font_path(value, type) -> Path: - if type == TYPE_GFONTS: +def get_font_path(value, font_type) -> Path: + if font_type == TYPE_GFONTS: name = f"{value[CONF_FAMILY]}@{value[CONF_WEIGHT]}@{value[CONF_ITALIC]}@v1" return external_files.compute_local_file_dir(DOMAIN) / f"{name}.ttf" - if type == TYPE_WEB: + if font_type == TYPE_WEB: return _compute_local_font_path(value) / "font.ttf" - return None + assert False def download_gfont(value): @@ -203,7 +292,7 @@ def download_gfont(value): _LOGGER.debug("download_gfont: ttf_url=%s", ttf_url) external_files.download_content(ttf_url, path) - return value + return FULLPATH_SCHEMA(path) def download_web_font(value): @@ -212,7 +301,7 @@ def download_web_font(value): external_files.download_content(url, path) _LOGGER.debug("download_web_font: path=%s", path) - return value + return FULLPATH_SCHEMA(path) EXTERNAL_FONT_SCHEMA = cv.Schema( @@ -225,7 +314,6 @@ EXTERNAL_FONT_SCHEMA = cv.Schema( } ) - GFONTS_SCHEMA = cv.All( EXTERNAL_FONT_SCHEMA.extend( { @@ -259,10 +347,10 @@ def validate_file_shorthand(value): } if weight is not None: data[CONF_WEIGHT] = weight[1:] - return FILE_SCHEMA(data) + return font_file_schema(data) if value.startswith("http://") or value.startswith("https://"): - return FILE_SCHEMA( + return font_file_schema( { CONF_TYPE: TYPE_WEB, CONF_URL: value, @@ -270,14 +358,15 @@ def validate_file_shorthand(value): ) if value.endswith(".pcf") or value.endswith(".bdf"): - return FILE_SCHEMA( - { - CONF_TYPE: TYPE_LOCAL_BITMAP, - CONF_PATH: value, - } + value = convert_bitmap_to_pillow_font( + CORE.relative_config_path(cv.file_(value)) ) + return { + CONF_TYPE: TYPE_LOCAL_BITMAP, + CONF_PATH: value, + } - return FILE_SCHEMA( + return font_file_schema( { CONF_TYPE: TYPE_LOCAL, CONF_PATH: value, @@ -295,31 +384,35 @@ TYPED_FILE_SCHEMA = cv.typed_schema( ) -def _file_schema(value): +def font_file_schema(value): if isinstance(value, str): return validate_file_shorthand(value) return TYPED_FILE_SCHEMA(value) -FILE_SCHEMA = cv.All(_file_schema) +# Default if no glyphs or glyphsets are provided +DEFAULT_GLYPHSET = "GF_Latin_Kernel" +# default for bitmap fonts +DEFAULT_GLYPHS = ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz' -DEFAULT_GLYPHS = ( - ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' -) CONF_RAW_GLYPH_ID = "raw_glyph_id" FONT_SCHEMA = cv.Schema( { cv.Required(CONF_ID): cv.declare_id(Font), - cv.Required(CONF_FILE): FILE_SCHEMA, - cv.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs, + cv.Required(CONF_FILE): font_file_schema, + cv.Optional(CONF_GLYPHS, default=[]): cv.ensure_list(cv.string_strict), + cv.Optional(CONF_GLYPHSETS, default=[]): cv.ensure_list( + cv.one_of(*glyphsets.defined_glyphsets()) + ), + cv.Optional(CONF_IGNORE_MISSING_GLYPHS, default=False): cv.boolean, cv.Optional(CONF_SIZE, default=20): cv.int_range(min=1), cv.Optional(CONF_BPP, default=1): cv.one_of(1, 2, 4, 8), - cv.Optional(CONF_EXTRAS): cv.ensure_list( + cv.Optional(CONF_EXTRAS, default=[]): cv.ensure_list( cv.Schema( { - cv.Required(CONF_FILE): FILE_SCHEMA, - cv.Required(CONF_GLYPHS): validate_glyphs, + cv.Required(CONF_FILE): font_file_schema, + cv.Required(CONF_GLYPHS): cv.ensure_list(cv.string_strict), } ) ), @@ -328,7 +421,7 @@ FONT_SCHEMA = cv.Schema( }, ) -CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, merge_glyphs) +CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, validate_glyphs) # PIL doesn't provide a consistent interface for both TrueType and bitmap @@ -367,28 +460,20 @@ class BitmapFontWrapper: mask = self.getmask(glyph, mode="1") _, height = mask.size max_height = max(max_height, height) - return (max_height, 0) + return max_height, 0 class EFont: - def __init__(self, file, size, glyphs): - self.glyphs = glyphs + def __init__(self, file, size, codepoints): + self.codepoints = codepoints + path = file[CONF_PATH] + self.name = Path(path).name ftype = file[CONF_TYPE] if ftype == TYPE_LOCAL_BITMAP: - font = load_bitmap_font(CORE.relative_config_path(file[CONF_PATH])) - elif ftype == TYPE_LOCAL: - path = CORE.relative_config_path(file[CONF_PATH]) - font = load_ttf_font(path, size) - elif ftype in (TYPE_GFONTS, TYPE_WEB): - path = get_font_path(file, ftype) - font = load_ttf_font(path, size) + self.font = load_bitmap_font(path) else: - raise cv.Invalid(f"Could not load font: unknown type: {ftype}") - self.font = font - self.ascent, self.descent = font.getmetrics(glyphs) - - def has_glyph(self, glyph): - return glyph in self.glyphs + self.font = load_ttf_font(path, size) + self.ascent, self.descent = self.font.getmetrics(codepoints) def convert_bitmap_to_pillow_font(filepath): @@ -400,6 +485,7 @@ def convert_bitmap_to_pillow_font(filepath): copy_file_if_changed(filepath, local_bitmap_font_file) + local_pil_font_file = local_bitmap_font_file.with_suffix(".pil") with open(local_bitmap_font_file, "rb") as fp: try: try: @@ -409,28 +495,22 @@ def convert_bitmap_to_pillow_font(filepath): p = BdfFontFile.BdfFontFile(fp) # Convert to pillow-formatted fonts, which have a .pil and .pbm extension. - p.save(local_bitmap_font_file) + p.save(local_pil_font_file) except (SyntaxError, OSError) as err: raise core.EsphomeError( f"Failed to parse as bitmap font: '{filepath}': {err}" ) - local_pil_font_file = os.path.splitext(local_bitmap_font_file)[0] + ".pil" - return cv.file_(local_pil_font_file) + return str(local_pil_font_file) def load_bitmap_font(filepath): from PIL import ImageFont - # Convert bpf and pcf files to pillow fonts, first. - pil_font_path = convert_bitmap_to_pillow_font(filepath) - try: - font = ImageFont.load(str(pil_font_path)) + font = ImageFont.load(str(filepath)) except Exception as e: - raise core.EsphomeError( - f"Failed to load bitmap font file: {pil_font_path} : {e}" - ) + raise core.EsphomeError(f"Failed to load bitmap font file: {filepath}: {e}") return BitmapFontWrapper(font) @@ -441,7 +521,7 @@ def load_ttf_font(path, size): try: font = ImageFont.truetype(str(path), size) except Exception as e: - raise core.EsphomeError(f"Could not load truetype file {path}: {e}") + raise core.EsphomeError(f"Could not load TrueType file {path}: {e}") return TrueTypeFontWrapper(font) @@ -456,14 +536,35 @@ class GlyphInfo: async def to_code(config): - glyph_to_font_map = {} - font_list = font_map[config[CONF_ID]] - glyphs = [] - for font in font_list: - glyphs.extend(font.glyphs) - for glyph in font.glyphs: - glyph_to_font_map[glyph] = font - glyphs.sort(key=functools.cmp_to_key(glyph_comparator)) + """ + Collect all glyph codepoints, construct a map from a codepoint to a font file. + Codepoints are either explicit (glyphs key in top level or extras) or part of a glyphset. + Codepoints listed in extras use the extra font and override codepoints from glyphsets. + Achieve this by processing the base codepoints first, then the extras + """ + + # get the codepoints from glyphsets and flatten to a set of chrs. + point_set: set[str] = { + chr(x) + for x in flatten( + [glyphsets.unicodes_per_glyphset(x) for x in config[CONF_GLYPHSETS]] + ) + } + # get the codepoints from the glyphs key, flatten to a list of chrs and combine with the points from glyphsets + point_set.update(flatten(config[CONF_GLYPHS])) + size = config[CONF_SIZE] + # Create the codepoint to font file map + base_font = EFont(config[CONF_FILE], size, point_set) + point_font_map: dict[str, EFont] = {c: base_font for c in point_set} + # process extras, updating the map and extending the codepoint list + for extra in config[CONF_EXTRAS]: + extra_points = flatten(extra[CONF_GLYPHS]) + point_set.update(extra_points) + extra_font = EFont(extra[CONF_FILE], size, extra_points) + point_font_map.update({c: extra_font for c in extra_points}) + + codepoints = list(point_set) + codepoints.sort(key=functools.cmp_to_key(glyph_comparator)) glyph_args = {} data = [] bpp = config[CONF_BPP] @@ -473,10 +574,11 @@ async def to_code(config): else: mode = "L" scale = 256 // (1 << bpp) - for glyph in glyphs: - font = glyph_to_font_map[glyph].font - mask = font.getmask(glyph, mode=mode) - offset_x, offset_y = font.getoffset(glyph) + # create the data array for all glyphs + for codepoint in codepoints: + font = point_font_map[codepoint] + mask = font.font.getmask(codepoint, mode=mode) + offset_x, offset_y = font.font.getoffset(codepoint) width, height = mask.size glyph_data = [0] * ((height * width * bpp + 7) // 8) pos = 0 @@ -487,31 +589,34 @@ async def to_code(config): if pixel & (1 << (bpp - bit_num - 1)): glyph_data[pos // 8] |= 0x80 >> (pos % 8) pos += 1 - glyph_args[glyph] = GlyphInfo(len(data), offset_x, offset_y, width, height) + glyph_args[codepoint] = GlyphInfo(len(data), offset_x, offset_y, width, height) data += glyph_data rhs = [HexInt(x) for x in data] prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) + # Create the glyph table that points to data in the above array. glyph_initializer = [] - for glyph in glyphs: + for codepoint in codepoints: glyph_initializer.append( cg.StructInitializer( GlyphData, ( "a_char", - cg.RawExpression(f"(const uint8_t *){cpp_string_escape(glyph)}"), + cg.RawExpression( + f"(const uint8_t *){cpp_string_escape(codepoint)}" + ), ), ( "data", cg.RawExpression( - f"{str(prog_arr)} + {str(glyph_args[glyph].data_len)}" + f"{str(prog_arr)} + {str(glyph_args[codepoint].data_len)}" ), ), - ("offset_x", glyph_args[glyph].offset_x), - ("offset_y", glyph_args[glyph].offset_y), - ("width", glyph_args[glyph].width), - ("height", glyph_args[glyph].height), + ("offset_x", glyph_args[codepoint].offset_x), + ("offset_y", glyph_args[codepoint].offset_y), + ("width", glyph_args[codepoint].width), + ("height", glyph_args[codepoint].height), ) ) @@ -521,7 +626,7 @@ async def to_code(config): config[CONF_ID], glyphs, len(glyph_initializer), - font_list[0].ascent, - font_list[0].ascent + font_list[0].descent, + base_font.ascent, + base_font.ascent + base_font.descent, bpp, ) diff --git a/requirements.txt b/requirements.txt index 8cc26e4da0..e11e629743 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,9 @@ aioesphomeapi==24.6.2 zeroconf==0.132.2 puremagic==1.27 ruamel.yaml==0.18.6 # dashboard_import +glyphsets==1.0.0 +pillow==10.4.0 +freetype-py==2.5.1 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 diff --git a/requirements_optional.txt b/requirements_optional.txt index 2d57c5fd96..7416753d55 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,2 +1 @@ -pillow==10.4.0 cairosvg==2.7.1 diff --git a/script/ci-custom.py b/script/ci-custom.py index 9a97d3e4a8..81e3da311a 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -58,7 +58,7 @@ file_types = ( ) cpp_include = ("*.h", "*.c", "*.cpp", "*.tcc") py_include = ("*.py",) -ignore_types = (".ico", ".png", ".woff", ".woff2", "", ".ttf", ".otf") +ignore_types = (".ico", ".png", ".woff", ".woff2", "", ".ttf", ".otf", ".pcf") LINT_FILE_CHECKS = [] LINT_CONTENT_CHECKS = [] diff --git a/tests/components/font/.gitattributes b/tests/components/font/.gitattributes new file mode 100644 index 0000000000..18d9a389e8 --- /dev/null +++ b/tests/components/font/.gitattributes @@ -0,0 +1,2 @@ +*.pcf -text + diff --git a/tests/components/font/MatrixChunky8X.bdf b/tests/components/font/MatrixChunky8X.bdf new file mode 100644 index 0000000000..89b3683180 --- /dev/null +++ b/tests/components/font/MatrixChunky8X.bdf @@ -0,0 +1,7461 @@ +STARTFONT 2.1 +FONT -Trip5-MatrixChunky8X-Medium-R-Normal--8-80-75-75-P-40-ISO10646-1 +SIZE 8 75 75 +FONTBOUNDINGBOX 8 8 -1 0 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "Trip5" +COMMENT "Conventional Chaos" +COMMENT "CC-BY" +STARTPROPERTIES 25 +FOUNDRY "Conventional Chaos" +FAMILY_NAME "MatrixChunky8X" +FONT_NAME "MatrixChunky8X" +FACE_NAME "MatrixChunky8X" +COPYRIGHT "https://github.com/trip5/Matrix-Fonts" +FONT_VERSION "001.000" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 8 +POINT_SIZE 80 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 40 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +CHARSET_COLLECTIONS "ISO8859-2 ISO8859-9 ISO8859-4 ISO10646-1" +FONT_ASCENT 8 +FONT_DESCENT 0 +UNDERLINE_POSITION 0 +UNDERLINE_THICKNESS 1 +X_HEIGHT 6 +CAP_HEIGHT 8 +ENDPROPERTIES +CHARS 535 +STARTCHAR uni0000 +ENCODING 0 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 2 +BITMAP +A0 +00 +40 +00 +A0 +ENDCHAR +STARTCHAR space +ENCODING 32 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 1 8 0 0 +BITMAP +80 +80 +80 +80 +80 +80 +00 +80 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 2 0 6 +BITMAP +A0 +A0 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +50 +50 +F8 +50 +50 +F8 +50 +50 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +E0 +80 +E0 +20 +20 +E0 +40 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +20 +40 +40 +80 +A0 +A0 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +E0 +A0 +A0 +40 +B0 +A0 +B0 +D0 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 1 3 0 5 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 8 0 0 +BITMAP +40 +40 +80 +80 +80 +80 +40 +40 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 8 0 0 +BITMAP +80 +80 +40 +40 +40 +40 +80 +80 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 4 0 4 +BITMAP +90 +60 +60 +90 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 3 0 3 +BITMAP +40 +E0 +40 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 2 0 0 +BITMAP +80 +80 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 1 0 4 +BITMAP +E0 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 1 0 0 +BITMAP +80 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +20 +40 +40 +40 +80 +80 +80 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +C0 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +E0 +20 +20 +20 +E0 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +20 +20 +20 +E0 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +20 +20 +20 +E0 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 3 0 3 +BITMAP +80 +00 +80 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 4 0 2 +BITMAP +80 +00 +80 +80 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 2 +BITMAP +20 +40 +80 +40 +20 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 3 0 3 +BITMAP +E0 +00 +E0 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 2 +BITMAP +80 +40 +20 +40 +80 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +20 +60 +40 +40 +00 +40 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +B0 +B0 +80 +80 +F0 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +C0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +80 +80 +80 +80 +A0 +E0 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +A0 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +E0 +80 +80 +B0 +90 +90 +90 +F0 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +90 +F0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +20 +20 +20 +20 +A0 +A0 +E0 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +C0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +88 +D8 +A8 +A8 +88 +88 +88 +88 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +D0 +B0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +F0 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +B0 +B0 +A0 +D0 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +C0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +80 +E0 +20 +20 +A0 +E0 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +A8 +A8 +A8 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +40 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +E0 +40 +40 +40 +40 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +40 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +40 +40 +40 +20 +20 +20 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +20 +20 +20 +20 +E0 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 3 0 5 +BITMAP +40 +E0 +A0 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 1 0 0 +BITMAP +E0 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 2 0 6 +BITMAP +80 +40 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +20 +20 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +60 +40 +40 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +20 +00 +20 +20 +20 +A0 +E0 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +A0 +A0 +C0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +F8 +A8 +A8 +A8 +A8 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +80 +80 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +20 +20 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +40 +40 +E0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +A8 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +40 +A0 +A0 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +60 +40 +40 +C0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 8 0 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +40 +40 +60 +40 +40 +40 +C0 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 2 0 3 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 1 8 0 0 +BITMAP +80 +80 +00 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +E0 +80 +80 +80 +E0 +40 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +70 +50 +40 +E0 +40 +40 +40 +F0 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 6 0 1 +BITMAP +F0 +60 +90 +90 +60 +F0 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +E0 +40 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 8 0 0 +BITMAP +80 +80 +80 +00 +80 +80 +80 +80 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +60 +80 +E0 +A0 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +E0 +A0 +C0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 1000 0 +DWIDTH 7 0 +BBX 6 7 0 1 +BITMAP +78 +CC +B4 +A4 +B4 +CC +78 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 3 +BITMAP +60 +A0 +E0 +00 +E0 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 3 0 3 +BITMAP +50 +F0 +50 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A8 +20 +20 +20 +28 +28 +38 +ENDCHAR +STARTCHAR uni00AD +ENCODING 173 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 1 0 4 +BITMAP +E0 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 1000 0 +DWIDTH 7 0 +BBX 6 7 0 1 +BITMAP +78 +CC +B4 +A4 +A4 +CC +78 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A0 +20 +38 +20 +20 +20 +20 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 3 0 5 +BITMAP +E0 +A0 +E0 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 2 +BITMAP +40 +E0 +40 +00 +E0 +ENDCHAR +STARTCHAR uni00B2 +ENCODING 178 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 5 0 3 +BITMAP +C0 +40 +C0 +80 +C0 +ENDCHAR +STARTCHAR uni00B3 +ENCODING 179 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 5 0 3 +BITMAP +C0 +40 +C0 +40 +C0 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 2 0 6 +BITMAP +40 +C0 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +A0 +A0 +A0 +A0 +E0 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +D0 +F0 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 1 0 4 +BITMAP +80 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +00 +E0 +00 +00 +00 +E0 +ENDCHAR +STARTCHAR uni00B9 +ENCODING 185 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 5 0 3 +BITMAP +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 3 +BITMAP +E0 +A0 +E0 +00 +E0 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 3 0 3 +BITMAP +A0 +F0 +A0 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +30 +60 +40 +F0 +40 +40 +60 +30 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +54 +54 +FE +54 +54 +54 +7C +28 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +70 +50 +10 +F8 +40 +40 +50 +70 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +40 +40 +C0 +80 +A0 +E0 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +40 +00 +E0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +A0 +E0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +A0 +E0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +E0 +A0 +E0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +F8 +A0 +A0 +F8 +A0 +A0 +A0 +B8 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +80 +80 +80 +E0 +40 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +40 +00 +E0 +80 +E0 +80 +E0 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +80 +E0 +80 +E0 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +80 +E0 +80 +E0 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +80 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +40 +00 +E0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +60 +50 +50 +F0 +50 +50 +50 +60 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +60 +00 +90 +D0 +B0 +90 +90 +90 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +20 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 3 0 3 +BITMAP +A0 +40 +A0 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +B0 +D0 +90 +90 +F0 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +40 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +A0 +A0 +E0 +40 +40 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +E0 +A0 +A0 +E0 +80 +80 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +C0 +A0 +A0 +E0 +80 +80 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +20 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +F8 +28 +F8 +A0 +F8 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +E0 +40 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +20 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 375 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +40 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +A0 +20 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +80 +40 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +20 +40 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +A0 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +A0 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 2 +BITMAP +40 +00 +E0 +00 +40 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +F0 +B0 +D0 +90 +F0 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +80 +40 +00 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +20 +40 +00 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +A0 +00 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +E0 +A0 +A0 +E0 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +A0 +E0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 4 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +30 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 4 6 0 0 +BITMAP +E0 +20 +E0 +A0 +E0 +30 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +80 +00 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +A0 +00 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +E0 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +40 +00 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +C0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +30 +30 +20 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +60 +50 +50 +F0 +50 +50 +50 +70 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +70 +20 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +80 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +E0 +80 +E0 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +E0 +80 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 4 8 0 0 +BITMAP +E0 +80 +80 +E0 +80 +80 +E0 +30 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +A0 +E0 +80 +E0 +40 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +E0 +80 +E0 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +A0 +00 +E0 +80 +B0 +90 +F0 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +B0 +90 +F0 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +00 +E0 +80 +80 +B0 +90 +F0 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +E0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR uni0122 +ENCODING 290 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +E0 +80 +80 +B0 +90 +90 +F0 +40 +ENDCHAR +STARTCHAR uni0123 +ENCODING 291 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +40 +00 +E0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +A0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +80 +80 +E0 +A0 +A0 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +50 +F8 +50 +70 +50 +50 +50 +50 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +E0 +40 +40 +70 +50 +50 +50 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +E0 +40 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +C0 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +E4 +44 +44 +44 +44 +54 +54 +FC +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 5 7 -1 0 +BITMAP +48 +00 +C8 +48 +48 +68 +F8 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +50 +00 +20 +20 +A0 +A0 +E0 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +20 +50 +00 +20 +20 +A0 +E0 +ENDCHAR +STARTCHAR uni0136 +ENCODING 310 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +C0 +A0 +A0 +A0 +40 +ENDCHAR +STARTCHAR uni0137 +ENCODING 311 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +A0 +A0 +C0 +A0 +A0 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +A0 +A0 +C0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR uni013B +ENCODING 315 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +80 +80 +80 +E0 +40 +ENDCHAR +STARTCHAR uni013C +ENCODING 316 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +40 +40 +40 +40 +40 +E0 +40 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +80 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +D0 +50 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +A0 +80 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +40 +60 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +40 +60 +C0 +40 +40 +40 +70 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +C0 +40 +60 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +90 +D0 +B0 +90 +90 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni0145 +ENCODING 325 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +D0 +B0 +90 +90 +90 +40 +ENDCHAR +STARTCHAR uni0146 +ENCODING 326 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +A0 +40 +00 +90 +D0 +B0 +90 +90 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +80 +80 +00 +70 +50 +50 +50 +50 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +20 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +A0 +A0 +A0 +A0 +20 +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +F8 +A0 +A0 +B8 +A0 +A0 +A0 +F8 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +F8 +A8 +B8 +A0 +F8 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +A0 +C0 +A0 +A0 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0156 +ENCODING 342 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +C0 +A0 +A0 +A0 +40 +ENDCHAR +STARTCHAR uni0157 +ENCODING 343 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +80 +80 +80 +80 +40 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +A0 +C0 +A0 +A0 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +80 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +20 +20 +E0 +40 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +80 +E0 +20 +E0 +40 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +80 +E0 +20 +E0 +ENDCHAR +STARTCHAR uni0162 +ENCODING 354 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +60 +20 +ENDCHAR +STARTCHAR uni0163 +ENCODING 355 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +40 +E0 +40 +40 +40 +60 +20 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +50 +50 +40 +E0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +E0 +40 +40 +40 +40 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +40 +E0 +40 +E0 +40 +40 +60 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +E0 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +40 +00 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +50 +00 +A8 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 7 0 0 +BITMAP +20 +50 +00 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +A0 +A0 +E0 +40 +40 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +A0 +00 +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +A0 +A0 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +E0 +20 +40 +80 +80 +E0 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +40 +00 +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A8 +28 +38 +28 +28 +28 +28 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A0 +20 +38 +20 +20 +20 +38 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +A4 +A4 +24 +3C +24 +24 +24 +24 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +90 +10 +10 +10 +10 +10 +38 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +BC +A4 +24 +24 +24 +24 +24 +3C +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +A8 +28 +38 +10 +10 +10 +10 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +BE +A2 +22 +22 +22 +36 +14 +36 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +C0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0394 +ENCODING 916 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +20 +50 +50 +88 +88 +88 +F8 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +20 +40 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +90 +F0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +F0 +90 +90 +90 +F0 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +C0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +20 +50 +50 +50 +88 +88 +88 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +88 +D8 +A8 +A8 +88 +88 +88 +88 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +D0 +B0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +00 +E0 +00 +00 +00 +E0 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +F0 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +40 +20 +40 +80 +80 +E0 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +E0 +40 +40 +40 +40 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +F8 +A8 +A8 +A8 +A8 +F8 +20 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +40 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +A8 +A8 +F8 +20 +20 +20 +20 +ENDCHAR +STARTCHAR uni03A9 +ENCODING 937 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +F8 +88 +88 +88 +88 +D8 +50 +D8 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +A0 +A0 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +D0 +A0 +A0 +A0 +D0 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +80 +40 +80 +E0 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +A0 +A0 +A0 +20 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +C0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +D0 +A0 +A0 +A0 +D0 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +60 +A0 +A0 +C0 +A0 +A0 +E0 +80 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +D0 +50 +70 +20 +20 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +40 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +40 +80 +E0 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +20 +C0 +80 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +20 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +C0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +C0 +A0 +A0 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +60 +20 +20 +50 +50 +88 +88 +88 +ENDCHAR +STARTCHAR uni03BC +ENCODING 956 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +E0 +80 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +E0 +80 +60 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +F8 +50 +50 +50 +58 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +E0 +80 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +F0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +B8 +A8 +A8 +F8 +20 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +40 +A0 +A0 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +A8 +A8 +A8 +F8 +20 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +88 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +C0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +20 +40 +00 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +10 +20 +00 +88 +A8 +A8 +F8 +50 +ENDCHAR +STARTCHAR uni0401 +ENCODING 1025 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +80 +E0 +80 +80 +E0 +ENDCHAR +STARTCHAR uni0404 +ENCODING 1028 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +70 +80 +80 +E0 +80 +80 +80 +70 +ENDCHAR +STARTCHAR uni0406 +ENCODING 1030 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR uni0407 +ENCODING 1031 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +00 +E0 +40 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR uni040E +ENCODING 1038 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +00 +A0 +A0 +E0 +20 +20 +60 +ENDCHAR +STARTCHAR uni0410 +ENCODING 1040 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni0411 +ENCODING 1041 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni0412 +ENCODING 1042 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +C0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni0413 +ENCODING 1043 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0414 +ENCODING 1044 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +30 +50 +50 +50 +50 +50 +F8 +88 +ENDCHAR +STARTCHAR uni0415 +ENCODING 1045 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +80 +80 +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR uni0416 +ENCODING 1046 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +A8 +A8 +F8 +A8 +A8 +A8 +A8 +ENDCHAR +STARTCHAR uni0417 +ENCODING 1047 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +20 +40 +20 +20 +A0 +E0 +ENDCHAR +STARTCHAR uni0418 +ENCODING 1048 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +88 +88 +98 +A8 +C8 +88 +88 +88 +ENDCHAR +STARTCHAR uni0419 +ENCODING 1049 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +88 +98 +A8 +C8 +88 +88 +88 +ENDCHAR +STARTCHAR uni041A +ENCODING 1050 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +C0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni041B +ENCODING 1051 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +30 +50 +50 +50 +50 +50 +50 +D0 +ENDCHAR +STARTCHAR uni041C +ENCODING 1052 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +88 +D8 +A8 +A8 +88 +88 +88 +88 +ENDCHAR +STARTCHAR uni041D +ENCODING 1053 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +90 +F0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR uni041E +ENCODING 1054 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +F0 +ENDCHAR +STARTCHAR uni041F +ENCODING 1055 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR uni0420 +ENCODING 1056 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0421 +ENCODING 1057 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +80 +80 +80 +80 +A0 +E0 +ENDCHAR +STARTCHAR uni0422 +ENCODING 1058 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni0423 +ENCODING 1059 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +90 +90 +90 +F0 +10 +10 +10 +70 +ENDCHAR +STARTCHAR uni0424 +ENCODING 1060 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +F8 +A8 +A8 +A8 +A8 +F8 +20 +ENDCHAR +STARTCHAR uni0425 +ENCODING 1061 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +40 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni0426 +ENCODING 1062 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +A0 +F0 +ENDCHAR +STARTCHAR uni0427 +ENCODING 1063 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +A0 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR uni0428 +ENCODING 1064 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +A8 +A8 +A8 +A8 +A8 +A8 +A8 +F8 +ENDCHAR +STARTCHAR uni0429 +ENCODING 1065 +SWIDTH 1000 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +A8 +A8 +A8 +A8 +A8 +A8 +A8 +FC +ENDCHAR +STARTCHAR uni042A +ENCODING 1066 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +C0 +40 +40 +70 +50 +50 +50 +70 +ENDCHAR +STARTCHAR uni042B +ENCODING 1067 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +88 +88 +88 +E8 +A8 +A8 +A8 +E8 +ENDCHAR +STARTCHAR uni042C +ENCODING 1068 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +80 +80 +80 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni042D +ENCODING 1069 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +E0 +10 +10 +70 +10 +10 +10 +E0 +ENDCHAR +STARTCHAR uni042E +ENCODING 1070 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A8 +A8 +E8 +A8 +A8 +A8 +B8 +ENDCHAR +STARTCHAR uni042F +ENCODING 1071 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +A0 +A0 +60 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni0430 +ENCODING 1072 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +20 +E0 +A0 +E0 +ENDCHAR +STARTCHAR uni0431 +ENCODING 1073 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +60 +80 +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni0432 +ENCODING 1074 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +C0 +A0 +E0 +ENDCHAR +STARTCHAR uni0433 +ENCODING 1075 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0434 +ENCODING 1076 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +30 +50 +50 +F8 +88 +ENDCHAR +STARTCHAR uni0435 +ENCODING 1077 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR uni0436 +ENCODING 1078 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +A8 +A8 +F8 +A8 +A8 +ENDCHAR +STARTCHAR uni0437 +ENCODING 1079 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +20 +40 +20 +E0 +ENDCHAR +STARTCHAR uni0438 +ENCODING 1080 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +90 +B0 +D0 +90 +90 +ENDCHAR +STARTCHAR uni0439 +ENCODING 1081 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +00 +90 +B0 +D0 +90 +90 +ENDCHAR +STARTCHAR uni043A +ENCODING 1082 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +C0 +A0 +A0 +ENDCHAR +STARTCHAR uni043B +ENCODING 1083 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +30 +50 +50 +50 +D0 +ENDCHAR +STARTCHAR uni043C +ENCODING 1084 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +88 +D8 +A8 +88 +88 +ENDCHAR +STARTCHAR uni043D +ENCODING 1085 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +E0 +A0 +A0 +ENDCHAR +STARTCHAR uni043E +ENCODING 1086 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni043F +ENCODING 1087 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni0440 +ENCODING 1088 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +E0 +80 +80 +ENDCHAR +STARTCHAR uni0441 +ENCODING 1089 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +80 +E0 +ENDCHAR +STARTCHAR uni0442 +ENCODING 1090 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni0443 +ENCODING 1091 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR uni0444 +ENCODING 1092 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +20 +20 +F8 +A8 +A8 +F8 +20 +ENDCHAR +STARTCHAR uni0445 +ENCODING 1093 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +40 +A0 +A0 +ENDCHAR +STARTCHAR uni0446 +ENCODING 1094 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +A0 +A0 +A0 +A0 +F0 +ENDCHAR +STARTCHAR uni0447 +ENCODING 1095 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +A0 +A0 +E0 +20 +20 +ENDCHAR +STARTCHAR uni0448 +ENCODING 1096 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +A8 +A8 +A8 +A8 +F8 +ENDCHAR +STARTCHAR uni0449 +ENCODING 1097 +SWIDTH 1000 0 +DWIDTH 7 0 +BBX 6 5 0 0 +BITMAP +A8 +A8 +A8 +A8 +FC +ENDCHAR +STARTCHAR uni044A +ENCODING 1098 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +C0 +40 +70 +50 +70 +ENDCHAR +STARTCHAR uni044B +ENCODING 1099 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +88 +88 +E8 +A8 +E8 +ENDCHAR +STARTCHAR uni044C +ENCODING 1100 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +80 +80 +E0 +A0 +E0 +ENDCHAR +STARTCHAR uni044D +ENCODING 1101 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +C0 +20 +E0 +20 +C0 +ENDCHAR +STARTCHAR uni044E +ENCODING 1102 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +B8 +A8 +E8 +A8 +B8 +ENDCHAR +STARTCHAR uni044F +ENCODING 1103 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +A0 +60 +A0 +A0 +ENDCHAR +STARTCHAR uni0451 +ENCODING 1105 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +E0 +A0 +E0 +80 +E0 +ENDCHAR +STARTCHAR uni0454 +ENCODING 1108 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +60 +80 +E0 +80 +60 +ENDCHAR +STARTCHAR uni0456 +ENCODING 1110 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR uni0457 +ENCODING 1111 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +A0 +00 +C0 +40 +40 +40 +E0 +ENDCHAR +STARTCHAR uni045E +ENCODING 1118 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +00 +A0 +A0 +E0 +20 +60 +ENDCHAR +STARTCHAR uni0490 +ENCODING 1168 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +10 +E0 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0491 +ENCODING 1169 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +20 +C0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni2002 +ENCODING 8194 +SWIDTH 375 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2003 +ENCODING 8195 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2009 +ENCODING 8201 +SWIDTH 1000 0 +DWIDTH 1 0 +BBX 1 1 6 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2010 +ENCODING 8208 +SWIDTH 1000 0 +DWIDTH 1 0 +BBX 1 1 0 4 +BITMAP +80 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 1000 0 +DWIDTH 3 0 +BBX 2 1 0 4 +BITMAP +C0 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 1 0 4 +BITMAP +F0 +ENDCHAR +STARTCHAR uni2015 +ENCODING 8213 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 4 1 0 4 +BITMAP +F0 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 1000 0 +DWIDTH 2 0 +BBX 1 1 0 4 +BITMAP +80 +ENDCHAR +STARTCHAR colonmonetary +ENCODING 8353 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +10 +F0 +A0 +A0 +A0 +A0 +F0 +40 +ENDCHAR +STARTCHAR uni20A2 +ENCODING 8354 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +80 +80 +B0 +A0 +A0 +A0 +F0 +ENDCHAR +STARTCHAR uni20A6 +ENCODING 8358 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +48 +48 +EC +58 +CC +48 +48 +48 +ENDCHAR +STARTCHAR uni20A9 +ENCODING 8361 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +54 +54 +FE +54 +54 +54 +7C +28 +ENDCHAR +STARTCHAR uni20AA +ENCODING 8362 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 6 0 0 +BITMAP +F4 +94 +B4 +B4 +A4 +BC +ENDCHAR +STARTCHAR dong +ENCODING 8363 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +70 +20 +E0 +A0 +E0 +00 +E0 +ENDCHAR +STARTCHAR Euro +ENCODING 8364 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +30 +60 +40 +F0 +40 +40 +60 +30 +ENDCHAR +STARTCHAR uni20AD +ENCODING 8365 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +50 +50 +60 +F0 +60 +50 +50 +50 +ENDCHAR +STARTCHAR uni20AE +ENCODING 8366 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +40 +60 +40 +C0 +40 +40 +40 +ENDCHAR +STARTCHAR uni20B1 +ENCODING 8369 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +70 +D8 +50 +70 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni20B2 +ENCODING 8370 +SWIDTH 1000 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +E0 +80 +B0 +90 +90 +F0 +40 +ENDCHAR +STARTCHAR uni20B4 +ENCODING 8372 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +70 +50 +10 +F8 +40 +50 +50 +70 +ENDCHAR +STARTCHAR uni20B5 +ENCODING 8373 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +40 +E0 +80 +80 +80 +E0 +40 +ENDCHAR +STARTCHAR uni20B8 +ENCODING 8376 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +E0 +00 +E0 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni20B9 +ENCODING 8377 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +20 +F0 +80 +40 +20 +10 +10 +ENDCHAR +STARTCHAR uni20BA +ENCODING 8378 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +E0 +40 +E0 +40 +40 +50 +50 +70 +ENDCHAR +STARTCHAR uni20BC +ENCODING 8380 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 7 0 0 +BITMAP +20 +20 +F8 +A8 +A8 +A8 +A8 +ENDCHAR +STARTCHAR uni20BD +ENCODING 8381 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +70 +50 +70 +40 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR uni20BE +ENCODING 8382 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +F8 +A8 +A8 +A0 +80 +40 +F8 +ENDCHAR +STARTCHAR uni20BF +ENCODING 8383 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +40 +E0 +A0 +C0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR uni20C0 +ENCODING 8384 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 6 0 0 +BITMAP +E0 +80 +80 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni2103 +ENCODING 8451 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A8 +20 +20 +20 +20 +28 +38 +ENDCHAR +STARTCHAR uni2109 +ENCODING 8457 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +B8 +A0 +20 +38 +20 +20 +20 +20 +ENDCHAR +STARTCHAR uni2460 +ENCODING 9312 +SWIDTH 125 0 +DWIDTH 1 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2461 +ENCODING 9313 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 1 1 1 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2462 +ENCODING 9314 +SWIDTH 375 0 +DWIDTH 3 0 +BBX 1 1 3 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2463 +ENCODING 9315 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2464 +ENCODING 9316 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2465 +ENCODING 9317 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 1 1 1 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2466 +ENCODING 9318 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 1 1 3 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2467 +ENCODING 9319 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2468 +ENCODING 9320 +SWIDTH 1125 0 +DWIDTH 9 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2469 +ENCODING 9321 +SWIDTH 1250 0 +DWIDTH 10 0 +BBX 1 1 4 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni24EA +ENCODING 9450 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 3 0 +BITMAP +00 +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 1 +BITMAP +E0 +A0 +A0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni4E00 +ENCODING 19968 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 2 0 3 +BITMAP +04 +FE +ENDCHAR +STARTCHAR uni4E03 +ENCODING 19971 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +20 +20 +2E +F0 +20 +20 +22 +1E +ENDCHAR +STARTCHAR uni4E09 +ENCODING 19977 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +7C +00 +00 +38 +00 +00 +04 +FE +ENDCHAR +STARTCHAR uni4E0A +ENCODING 19978 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +40 +70 +40 +40 +40 +40 +F0 +ENDCHAR +STARTCHAR uni4E0B +ENCODING 19979 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +F0 +40 +60 +50 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni4E5D +ENCODING 20061 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +20 +F8 +28 +28 +48 +48 +4A +8E +ENDCHAR +STARTCHAR uni4E8C +ENCODING 20108 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 6 0 1 +BITMAP +7C +00 +00 +00 +04 +FE +ENDCHAR +STARTCHAR uni4E94 +ENCODING 20116 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +7C +10 +10 +7C +24 +24 +24 +FE +ENDCHAR +STARTCHAR uni516B +ENCODING 20843 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +28 +28 +28 +28 +44 +44 +44 +82 +ENDCHAR +STARTCHAR uni516D +ENCODING 20845 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +10 +FE +00 +28 +28 +44 +44 +82 +ENDCHAR +STARTCHAR uni5341 +ENCODING 21313 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +10 +10 +FE +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni5348 +ENCODING 21320 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 5 8 0 0 +BITMAP +40 +70 +A0 +20 +F8 +20 +20 +20 +ENDCHAR +STARTCHAR uni56DB +ENCODING 22235 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +FE +AA +AA +AE +C2 +82 +FE +82 +ENDCHAR +STARTCHAR uni5929 +ENCODING 22825 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +7C +10 +10 +FE +10 +10 +28 +C6 +ENDCHAR +STARTCHAR uni661F +ENCODING 26143 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +FC +84 +FC +5E +90 +7C +10 +FE +ENDCHAR +STARTCHAR uni6708 +ENCODING 26376 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +3E +22 +3E +22 +3E +22 +42 +86 +ENDCHAR +STARTCHAR uni671F +ENCODING 26399 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +5E +FA +5E +7A +5E +EA +12 +A6 +ENDCHAR +STARTCHAR uniAE08 +ENCODING 44552 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +F8 +08 +00 +F8 +00 +F8 +88 +F8 +ENDCHAR +STARTCHAR uniBAA9 +ENCODING 47785 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +F8 +88 +F8 +20 +F8 +00 +F8 +08 +ENDCHAR +STARTCHAR uniC218 +ENCODING 49688 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +20 +50 +88 +00 +F8 +20 +20 +ENDCHAR +STARTCHAR uniC624 +ENCODING 50724 +SWIDTH 750 0 +DWIDTH 6 0 +BBX 5 7 0 1 +BITMAP +70 +88 +88 +70 +20 +20 +F8 +ENDCHAR +STARTCHAR uniC694 +ENCODING 50836 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 7 0 1 +BITMAP +70 +88 +88 +70 +50 +50 +F8 +ENDCHAR +STARTCHAR uniC6D4 +ENCODING 50900 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +48 +A8 +48 +E8 +58 +38 +C0 +F8 +ENDCHAR +STARTCHAR uniC77C +ENCODING 51068 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +48 +A8 +48 +00 +F8 +38 +C0 +F8 +ENDCHAR +STARTCHAR uniC804 +ENCODING 51204 +SWIDTH 875 0 +DWIDTH 7 0 +BBX 6 8 0 0 +BITMAP +F4 +24 +4C +A4 +94 +44 +40 +7C +ENDCHAR +STARTCHAR uniD1A0 +ENCODING 53664 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 7 0 1 +BITMAP +F8 +80 +F0 +80 +F8 +20 +F8 +ENDCHAR +STARTCHAR uniD654 +ENCODING 54868 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 7 8 0 0 +BITMAP +24 +FC +54 +56 +24 +24 +FC +04 +ENDCHAR +STARTCHAR uniD6C4 +ENCODING 54980 +SWIDTH 1000 0 +DWIDTH 6 0 +BBX 5 8 0 0 +BITMAP +20 +F8 +50 +20 +00 +F8 +20 +20 +ENDCHAR +STARTCHAR uniFFE5 +ENCODING 65509 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 8 0 0 +BITMAP +A0 +A0 +E0 +40 +E0 +40 +40 +40 +ENDCHAR +STARTCHAR uniFFFD +ENCODING 65533 +SWIDTH 1000 0 +DWIDTH 4 0 +BBX 3 6 0 1 +BITMAP +A0 +A0 +40 +A0 +A0 +A0 +ENDCHAR +ENDFONT diff --git a/tests/components/font/common.yaml b/tests/components/font/common.yaml index a81457a05d..5be9faf5be 100644 --- a/tests/components/font/common.yaml +++ b/tests/components/font/common.yaml @@ -1,4 +1,12 @@ font: + - file: + type: gfonts + family: "Roboto" + weight: bold + italic: true + size: 32 + id: roboto32 + - file: "gfonts://Roboto" id: roboto size: 20 @@ -9,6 +17,10 @@ font: - file: "gfonts://Roboto" id: roboto_web size: 20 + - file: "gfonts://Roboto" + id: roboto_greek + size: 20 + glyphs: ["\u0300", "\u00C5", "\U000000C7"] - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" id: monocraft size: 20 @@ -20,6 +32,17 @@ font: - file: $component_dir/Monocraft.ttf id: monocraft3 size: 28 + - file: $component_dir/MatrixChunky8X.bdf + id: special_font + glyphs: + - '"' + - "'" + - '#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz°' + + - file: $component_dir/MatrixChunky8X.bdf + id: default_font + - file: $component_dir/x11.pcf + id: pcf_font i2c: scl: ${i2c_scl} @@ -36,3 +59,4 @@ display: it.print(0, 40, id(monocraft), "Hello, World!"); it.print(0, 60, id(monocraft2), "Hello, World!"); it.print(0, 80, id(monocraft3), "Hello, World!"); + it.print(0, 100, id(roboto_greek), "Hello κόσμε!"); diff --git a/tests/components/font/test.host.yaml b/tests/components/font/test.host.yaml index 017328ec83..c5399f2826 100644 --- a/tests/components/font/test.host.yaml +++ b/tests/components/font/test.host.yaml @@ -1,4 +1,12 @@ font: + - file: + type: gfonts + family: "Roboto" + weight: bold + italic: true + size: 32 + id: roboto32 + - file: "gfonts://Roboto" id: roboto size: 20 @@ -9,6 +17,10 @@ font: - file: "gfonts://Roboto" id: roboto_web size: 20 + - file: "gfonts://Roboto" + id: roboto_greek + size: 20 + glyphs: ["\u0300", "\u00C5", "\U000000C7"] - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf" id: monocraft size: 20 @@ -20,4 +32,26 @@ font: - file: $component_dir/Monocraft.ttf id: monocraft3 size: 28 + - file: $component_dir/MatrixChunky8X.bdf + id: special_font + glyphs: + - '"' + - "'" + - '#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz°' + - file: $component_dir/MatrixChunky8X.bdf + id: default_font + +display: + - platform: sdl + id: sdl_display + dimensions: + width: 800 + height: 600 + lambda: |- + it.print(0, 0, id(roboto), "Hello, World!"); + it.print(0, 20, id(roboto_web), "Hello, World!"); + it.print(0, 40, id(roboto_greek), "Hello κόσμε!"); + it.print(0, 60, id(monocraft), "Hello, World!"); + it.print(0, 80, id(monocraft2), "Hello, World!"); + it.print(0, 100, id(monocraft3), "Hello, World!"); diff --git a/tests/components/font/x11.pcf b/tests/components/font/x11.pcf new file mode 100644 index 0000000000000000000000000000000000000000..19a38d4e3918b6bb4796fb23d34a24e2a8fa9656 GIT binary patch literal 13368 zcmbuG4Rl;bb;oD58-K)(tvF6BJBq!DgJZx-ZGj>gOHOPE=&g5G(&CkN zvnx4r;@D4XSznfeo2E1=X=^AYfu_{7lm?o%56E#$j|m3S9JfG^&PgbtC*=r|5>e8) zzyJGKFD8*)cqhL%cV_O~J9F>Md%N-`)S1Z5F~)>o0oY+q ze};<2NdNKW#;l_f_3M=koLps0%&*Tue`+;$gMM_U-%bTv8lQwY>pU5;8r-?K_BE+x zaIJ(IxJg1C+#+EMv`Y90bbxE|qY`AcKM;z6@G&X>Av~;>7I;)GPkOYa1;DO!Y1Z7SHfw8N=Aj4VW>vJ%}|su2H%hlSLk2V@;v-ELd86YN_Y!cQW!_r zErBIh?Ag@1y`^E>PE()E?n;?W^|v)O@9b!)zpc@1@5|=WadSsw)8;MhUekNCnWSlJ zu5W2KO{T4}{f?%F_AOplOE%vV&zSm#hK{!Ooz0D2tJ&JLqp`W8t?7e}W@~FxOS>m- zYiw(6-rnBS+S0MZlvQ?`wypIWn_4!Tt)~9=#%=YR8#`PdX5*InZ8+@M*0{N;t)2Nc zwYApOy>or3qp@XUYlB9vH5==W^;S<>8|d+=<38WSxfN3)$X88;1$ZS74hEV8x5bksMrzPGVsYulz)QsphAMho%R(b3Sj5pKtC zhg6jBHnX+u-M_BtTBvbXRa4em(^TVSyryRDx|+4MwI#OJ++0`VXQyUuS$53_w%0fK z=`5W;?L%Fc0jJ!A&%W;7&z_xDX%^CRncGA4|9k2AVVuEAGGbkLqp?sab$S> zp24xvaa*^+;*p8*!NJ4hV|H=q;P}18;X~ua!9(1Nqa)+@4vvnFFm&jk+J^2MJUCRe zZCPRLm_0bc%^sC>?&fyrRxC+g@6ZsYxD{Qa+zuUZrQ+x?_9hOG+xGaFe=ABFJWSi5 zD~&VV;^A?sN7OcQ2t97a!3ni#G4}mOxT#t!4U=@xGcf8Jz-Up9iW8DPrV)oF>E=2g z)bfkNOvqLYH1YlR$jAY=Z7+^SJa2=e!+|t1GGZSXJv4sM9vc}sSRBKY;%6Vg)IoP@ zZnb#i2qVVFxGAPGrCx3$GUeWe4-rYJ5PNPDhY6S@-45DvS=6G72T4FMzeD@o)GDwz zS3ca>kB*KWD2^)&QpTkcIy^q$E+22B`--EZ!#GkFlv*z?Bg10@Y=N?K0@AQi>p(9qES;?VHm5V1l<_Sg*An;@nv)xTkYiI0yRQFPtggd}cb!R^5P z6DX79Ay$4w%Xe=RLXa zALI6Z{Q5ca55!?VzvrsTg3>)SI5MKG=iSibe0Z7Grm?xvrj4m!``gx){9CzY!tU;a z(LvT5D36b!qAKb3W<}1CO3w<%KmXTLie|VIhTu4SpLZTbXfZTEAB@7Mfmd$mNq7og z;=NZ1d&{y#y51si?3+<4D2LbzG2k;Szz#5=G!q^D*Bd6dMV=k$N2FL*8 zF2Uv{FBvmyF>HV&Ou!cbU$dFV>^iW3xz5JV>@(h{ojI#1w}K6if!gsgXWE##5s1PT zz~)?R&P8V~^ShM3OV>aAG`B& zfZh2|!V5g27Xvs7d{400J;mYTZv93I+Z#2G@LQ!@;Oik-S7}NfbOC-U;%y?(YELnW3E^Y zJ75%!!=y2b7sD19fXCnrOc`@!6*Pkl=w6BLRp?%|0dnvVVD~E4u!Qy{v@hv~AwYi# zb}(V8m`7DR>;vXpbsDCPSsDfWF2&Z;hu|r|)-r4@s|Cg^W6UzfEMv?v#$1i9t1a^T zRpR{5$PXHG^XktX!wr`mb&Fps)sI0JsR#>VpeqKB&lyT_)JLC47x^5ZyxvEzXD08$ z0b-`LGzc5PM8H6uTq=<`3l-Jwi>R7HP8$iFMG1_9=H{vp!y~#w=+O} zIRxuc{Xal{gzU-JevsV=1o4U@TQCVRkevc3KAjM(L3T7}+16ZFf%?U*Ae-`Y5)>oL zCq}6&298e*#H@?4?x-<6$Bg+V<-fxBV#a*f_F}(+GHg6%Q;K@pO+o)d{$A4rLe*n zvmVyk9?F&GzFch(hZs0zd=0r1f<3U*_Uy@KtxsT2Ig`BuHtT>|xQY6$pwa^QNPzV8 z{HO|`t~ms{LH?#`)4b)w0tZ<G378!yI+gZQeC;wUzO z=Bpei&svM(rhTHe99TZMyr8`xFD%1758A7Gj>vXEU|Xdqfaa<(*TF83-+iF@5Boet zIRIyE?=LbBBUb^TD#f!FS!1W+myWk)ty_5zTC+IeBYQ79z8$bfnxWp0X9} z(OTMczRp50Hi{fzA;-?cp*{&VI1no%iX5O=vRv10l`pFvp#EqX7V;znV^$+)putBm ze;pjKKzcgo?}ARBQ}3EJ|TRtPItK}Tv`U4$ASJ$G9`8bq9_QVFzd-t@D@;(4jm<>zqb1~65)SNDd{qQ;{ z7K-Ok8LF%OZcx0|K^DTADA31!kq7=Gj`RMN*fxhY!Xaj?KC<7>#BpuALq@-YW$eOY659kAJ7PzyTy zw}MIwWH$jiPa#+cx-NE%)+xUitA91RLh;l4MRP5mlj^&CG^Z$Nzv)sbUqX82Sk%Q7 zC|}D#SNWJX8ka+78Wa;<7t*)TkqGk^E0L|t>xr8T>I#rF2`n|%)}&-2BO3G#fg`pcPv{9LTQ_JsDs z#p-iJ+~;Eu=PlILCclb7f-(i)@cAxn&%-8o4Kyx@+b=zU@C3C0mS*f#caaZM^fRvDKhU_TL4aK6*#|0Db~t&^tueOnMRerKe|v zu9m8*W1=T0P@^L5wo2QV4u1c5!%V&~O@ljhXTm?GgBG`i`kOLb7$mM(H zX6m~^dm|6-7~A{aD0{)ap2^;oX_w`JAT8q&2npc$GSK3z^ zt9iA+bMOKvW{Ot~a!?1-)wA|_NI(}n1JBvs_fS1A!_+UNr~U;Hobj1#2G2*-XY?(< zvZ?DXP;4&r-8I;+ip>r1b|`?>roE7aGvN5xl;ttMSU>)}&NAG+&i+;xTeyNSN6aN= z79T(7n7RB^Y#tBI%Lu?i4$0*_#I7)l&6OO8B^=771mbEo-!;5!S8&*_pd?|e=4~Lsc{CaZ>eu6J>q3%nBh`RaZ*+jy_J$K1=;>-+dx ze!$pf&=k!S@KQ@12{?r^ZpERE`e`Y>y{@i@VJZc^@pEaK|e_eZl;-`5W^^ z^S96-C&loTBgNw133s z720+nvu)kqFsS4x1!FE$y5krl8v&sc_~Q6i+yjrnG3q?hDte&_cpPYsp&|@XKMwDs z?P1Cv!Y|-Kzx*sE$Ec#4ejaxfdnh0BO4r^;v7xo_Xi@2|g*AnaBDVu}LnkTYl;4Lt zkuQaQZ@AzNE$e*!)UUDUN6))D6MQ9+DCKL*7aKcTr^DgQz2 z&ySsSD(cW4mQ9h*amk3`87FU4V-GjSvH(t z!^t(AS;Kkd&r9$rcoc}aISyZfC*iB`G<+M_-|nBnU!eRin1Y|dEAVrehW~-r;C0qc z5vl;~DfU;0*oN4nA?6-pIiX5e1dHJ+sDfos4a*@4tSxjs)WR*W85C3YaVQC$&<#2- z86fwe9OR)7_P_uT*U&!L4>k}7ozc)RjKVlf!2NI(9suGK`Zy4y5b+6p2EG8qCG<7; zCVU6J2QR>j@G~F=6})0AE(7x8p7Wb1*FyumAGX1rz}$8AE0|lw0U$RO_^UVu?8P&;5&lv$R_~bkg_Y}9;8CNH|Z%C z(!E`ol*z^OsoqSgv(J;^8Yff59ZOJw0*Ly*JmL>Xo&0Hfai(c%j?e zlgejJwl`(^?#`ON?tF?@ZMHveI@5bnrjQ;mh14F#r1ZmO)0;*yk znABbU@r>!pr}(jRp4p`eeQC7feZSF%h+X-3Vt1;~UDGZ^Z>oN4u)ah(ok-^s{XM3? zH%VCdv2}_W#F_VR^07hIQ@+Q%acgCs`qG&s@hHnzGJAKgakHXGXGn!f^ykS$Vz1dt z#CGMgyHmZpl;u>y4MsA}kGczKWyAmdxXI>|odnX2Ygd0dlS%bty=7;zUFk$T)0^!J z(su55;ie~^$P?XUihz@UGK>w?1E9~ zwLiV?c-h#v=Qdt45qHB7=ez}BAln+8@&>2M29r8}Yo$G%w5Q`A5I4^0l1_>+^m^{H zo_f|(&z70Y`U<5{$@HEyM*xGVZ(& J-u(Cf{|En5p|}75 literal 0 HcmV?d00001 From 749b9421329f0ca8453e7df0df0702a3d29e8276 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:37:32 +1100 Subject: [PATCH 2600/2607] [lvlg] fix tests (#7708) --- tests/components/lvgl/common.yaml | 40 +------------------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index cebc3caaa7..c7d635db1c 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -4,56 +4,18 @@ touchscreen: display: tft_display update_interval: 50ms threshold: 1 - calibration: - x_max: 240 - y_max: 320 font: - file: "$component_dir/roboto.ttf" id: roboto20 size: 20 - extras: - - file: '$component_dir/materialdesignicons-webfont.ttf' - glyphs: [ - "\U000F004B", - "\U0000f0ed", - "\U000F006E", - "\U000F012C", - "\U000F179B", - "\U000F0748", - "\U000F1A1B", - "\U000F02DC", - "\U000F0A02", - "\U000F035F", - "\U000F0156", - "\U000F0C5F", - "\U000f0084", - "\U000f0091", - ] + - file: "$component_dir/helvetica.ttf" id: helvetica20 - file: "$component_dir/roboto.ttf" id: roboto10 size: 10 bpp: 4 - extras: - - file: '$component_dir/materialdesignicons-webfont.ttf' - glyphs: [ - "\U000F004B", - "\U0000f0ed", - "\U000F006E", - "\U000F012C", - "\U000F179B", - "\U000F0748", - "\U000F1A1B", - "\U000F02DC", - "\U000F0A02", - "\U000F035F", - "\U000F0156", - "\U000F0C5F", - "\U000f0084", - "\U000f0091", - ] sensor: - platform: lvgl From cefbfb75bd4b5f8baaf5599c1c4221aab1919426 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 31 Oct 2024 23:46:35 +1300 Subject: [PATCH 2601/2607] [esp32_ble] Add disconnect as a virtual function to ``ESPBTClient`` (#7705) --- esphome/components/esp32_ble_client/ble_client_base.h | 2 +- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_ble_client/ble_client_base.h b/esphome/components/esp32_ble_client/ble_client_base.h index fd586e59d6..fca66c0b3c 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.h +++ b/esphome/components/esp32_ble_client/ble_client_base.h @@ -35,7 +35,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; void connect() override; esp_err_t pair(); - void disconnect(); + void disconnect() override; void release_services(); bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; } diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index d2bb6a6e6d..2fc5da829d 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -11,9 +11,9 @@ #ifdef USE_ESP32 +#include #include #include -#include #include #include @@ -172,6 +172,7 @@ class ESPBTClient : public ESPBTDeviceListener { esp_ble_gattc_cb_param_t *param) = 0; virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0; virtual void connect() = 0; + virtual void disconnect() = 0; virtual void set_state(ClientState st) { this->state_ = st; } ClientState state() const { return state_; } int app_id; From 77bb46ff3bf17afb7bfd3fe963a86af014a17d4b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Fri, 1 Nov 2024 02:54:34 -0700 Subject: [PATCH 2602/2607] handle bad pin schemas (#7711) Co-authored-by: Samuel Sieb --- esphome/components/esp32/gpio.py | 4 +++- esphome/components/esp8266/gpio.py | 12 +++++++----- esphome/components/host/gpio.py | 10 ++++++---- esphome/components/libretiny/gpio.py | 6 ++++-- esphome/components/rp2040/gpio.py | 8 +++++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/esphome/components/esp32/gpio.py b/esphome/components/esp32/gpio.py index 558ff51af8..df01769a66 100644 --- a/esphome/components/esp32/gpio.py +++ b/esphome/components/esp32/gpio.py @@ -67,8 +67,10 @@ def _translate_pin(value): "This variable only supports pin numbers, not full pin schemas " "(with inverted and mode)." ) - if isinstance(value, int): + if isinstance(value, int) and not isinstance(value, bool): return value + if not isinstance(value, str): + raise cv.Invalid(f"Invalid pin number: {value}") try: return int(value) except ValueError: diff --git a/esphome/components/esp8266/gpio.py b/esphome/components/esp8266/gpio.py index c42bc9204f..53016d2130 100644 --- a/esphome/components/esp8266/gpio.py +++ b/esphome/components/esp8266/gpio.py @@ -1,6 +1,9 @@ -import logging from dataclasses import dataclass +import logging +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_ANALOG, CONF_ID, @@ -14,10 +17,7 @@ from esphome.const import ( CONF_PULLUP, PLATFORM_ESP8266, ) -from esphome import pins from esphome.core import CORE, coroutine_with_priority -import esphome.config_validation as cv -import esphome.codegen as cg from . import boards from .const import KEY_BOARD, KEY_ESP8266, KEY_PIN_INITIAL_STATES, esp8266_ns @@ -48,8 +48,10 @@ def _translate_pin(value): "This variable only supports pin numbers, not full pin schemas " "(with inverted and mode)." ) - if isinstance(value, int): + if isinstance(value, int) and not isinstance(value, bool): return value + if not isinstance(value, str): + raise cv.Invalid(f"Invalid pin number: {value}") try: return int(value) except ValueError: diff --git a/esphome/components/host/gpio.py b/esphome/components/host/gpio.py index 180919de4f..0f22a790bd 100644 --- a/esphome/components/host/gpio.py +++ b/esphome/components/host/gpio.py @@ -1,5 +1,8 @@ import logging +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_ID, CONF_INPUT, @@ -11,9 +14,6 @@ from esphome.const import ( CONF_PULLDOWN, CONF_PULLUP, ) -from esphome import pins -import esphome.config_validation as cv -import esphome.codegen as cg from .const import host_ns @@ -28,8 +28,10 @@ def _translate_pin(value): "This variable only supports pin numbers, not full pin schemas " "(with inverted and mode)." ) - if isinstance(value, int): + if isinstance(value, int) and not isinstance(value, bool): return value + if not isinstance(value, str): + raise cv.Invalid(f"Invalid pin number: {value}") try: return int(value) except ValueError: diff --git a/esphome/components/libretiny/gpio.py b/esphome/components/libretiny/gpio.py index 1d7b37cc9b..07eb0ce133 100644 --- a/esphome/components/libretiny/gpio.py +++ b/esphome/components/libretiny/gpio.py @@ -1,8 +1,8 @@ import logging +from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv -from esphome import pins from esphome.const import ( CONF_ANALOG, CONF_ID, @@ -103,8 +103,10 @@ def _translate_pin(value): "This variable only supports pin numbers, not full pin schemas " "(with inverted and mode)." ) - if isinstance(value, int): + if isinstance(value, int) and not isinstance(value, bool): return value + if not isinstance(value, str): + raise cv.Invalid(f"Invalid pin number: {value}") try: return int(value) except ValueError: diff --git a/esphome/components/rp2040/gpio.py b/esphome/components/rp2040/gpio.py index 6ba0975a2c..58514f7db5 100644 --- a/esphome/components/rp2040/gpio.py +++ b/esphome/components/rp2040/gpio.py @@ -1,6 +1,8 @@ +from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import ( + CONF_ANALOG, CONF_ID, CONF_INPUT, CONF_INVERTED, @@ -10,10 +12,8 @@ from esphome.const import ( CONF_OUTPUT, CONF_PULLDOWN, CONF_PULLUP, - CONF_ANALOG, ) from esphome.core import CORE -from esphome import pins from . import boards from .const import KEY_BOARD, KEY_RP2040, rp2040_ns @@ -41,8 +41,10 @@ def _translate_pin(value): "This variable only supports pin numbers, not full pin schemas " "(with inverted and mode)." ) - if isinstance(value, int): + if isinstance(value, int) and not isinstance(value, bool): return value + if not isinstance(value, str): + raise cv.Invalid(f"Invalid pin number: {value}") try: return int(value) except ValueError: From 01497c891d08c4a9a245eaadb982e302d43f0b58 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Sun, 3 Nov 2024 22:22:16 +0100 Subject: [PATCH 2603/2607] datetime fix build_language_schema (#7710) Co-authored-by: Tomasz Duda --- esphome/components/datetime/__init__.py | 6 +++--- tests/components/mqtt/common.yaml | 1 + tests/components/web_server/common_v3.yaml | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 7edf527e01..630bf6962c 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -70,8 +70,6 @@ def _validate_time_present(config): _DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( - web_server.WEBSERVER_SORTING_SCHEMA, - cv.MQTT_COMMAND_COMPONENT_SCHEMA, cv.Schema( { cv.Optional(CONF_ON_VALUE): automation.validate_automation( @@ -81,7 +79,9 @@ _DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( ), cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock), } - ), + ) + .extend(web_server.WEBSERVER_SORTING_SCHEMA) + .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA) ).add_extra(_validate_time_present) diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index e154be8b5c..75c34bec56 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -230,6 +230,7 @@ datetime: id: test_date type: date state_topic: some/topic/date + command_topic: test_date/custom_command_topic qos: 2 subscribe_qos: 2 set_action: diff --git a/tests/components/web_server/common_v3.yaml b/tests/components/web_server/common_v3.yaml index 69f4b67f15..bdacaaddbe 100644 --- a/tests/components/web_server/common_v3.yaml +++ b/tests/components/web_server/common_v3.yaml @@ -35,3 +35,11 @@ switch: web_server: sorting_group_id: sorting_group_2 sorting_weight: -10 +datetime: + - platform: template + name: Pick a Date + type: datetime + optimistic: yes + web_server: + sorting_group_id: sorting_group_3 + sorting_weight: -5 From 2dca3d79e490abcf2a03e962cb7c88dc3bbfd83b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:32:18 +1100 Subject: [PATCH 2604/2607] [lvgl] Ensure images are configured before using them. (Bugfix) (#7721) --- esphome/components/lvgl/widgets/animimg.py | 7 ++++--- esphome/components/lvgl/widgets/img.py | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/widgets/animimg.py b/esphome/components/lvgl/widgets/animimg.py index 3b20008c3d..8adea72ad3 100644 --- a/esphome/components/lvgl/widgets/animimg.py +++ b/esphome/components/lvgl/widgets/animimg.py @@ -60,9 +60,10 @@ class AnimimgType(WidgetType): lvgl_components_required.add(CONF_IMAGE) lvgl_components_required.add(CONF_ANIMIMG) if CONF_SRC in config: - for x in config[CONF_SRC]: - await cg.get_variable(x) - srcs = [await lv_image.process(x) for x in config[CONF_SRC]] + srcs = [ + await lv_image.process(await cg.get_variable(x)) + for x in config[CONF_SRC] + ] src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs) count = len(config[CONF_SRC]) lv.animimg_set_src(w.obj, src_id, count) diff --git a/esphome/components/lvgl/widgets/img.py b/esphome/components/lvgl/widgets/img.py index 59b2c97c63..931d0c0b5b 100644 --- a/esphome/components/lvgl/widgets/img.py +++ b/esphome/components/lvgl/widgets/img.py @@ -1,3 +1,4 @@ +import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ANGLE, CONF_MODE @@ -64,6 +65,7 @@ class ImgType(WidgetType): async def to_code(self, w: Widget, config): if src := config.get(CONF_SRC): + src = await cg.get_variable(src) lv.img_set_src(w.obj, await lv_image.process(src)) if (cf_angle := config.get(CONF_ANGLE)) is not None: pivot_x = config[CONF_PIVOT_X] From dcc537d0d43c2b8fdff7ecac86c8154c7ed78172 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:45:40 +1300 Subject: [PATCH 2605/2607] [lvgl] Don't just throw key error if someone types a bad layout type (#7722) Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> --- esphome/components/lvgl/schemas.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index bb14c11ddd..516627708e 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -391,7 +391,9 @@ def container_validator(schema, widget_type: WidgetType): add_lv_use(ltype) if value == SCHEMA_EXTRACT: return result - result = result.extend(LAYOUT_SCHEMAS[ltype.lower()]) + result = result.extend( + LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE]) + ) return result(value) return validator From 5bb4d042e48873812684fcad189c233c64698629 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:54:47 +1100 Subject: [PATCH 2606/2607] [spi_device] rename mode to spi_mode (#7724) --- esphome/components/spi/__init__.py | 29 ++++++++++--------- esphome/components/spi_device/__init__.py | 19 +++--------- .../components/spi_device/test.esp32-ard.yaml | 2 +- .../spi_device/test.esp32-c3-ard.yaml | 2 +- .../spi_device/test.esp32-c3-idf.yaml | 2 +- .../components/spi_device/test.esp32-idf.yaml | 2 +- .../spi_device/test.esp8266-ard.yaml | 2 +- .../spi_device/test.rp2040-ard.yaml | 2 +- 8 files changed, 25 insertions(+), 35 deletions(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index fdf19bb56e..52afbf365e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -1,40 +1,37 @@ import re +from esphome import pins import esphome.codegen as cg -import esphome.config_validation as cv -import esphome.final_validate as fv from esphome.components.esp32.const import ( KEY_ESP32, - VARIANT_ESP32S2, - VARIANT_ESP32S3, VARIANT_ESP32C2, VARIANT_ESP32C3, VARIANT_ESP32C6, VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, ) -from esphome import pins +import esphome.config_validation as cv from esphome.const import ( CONF_CLK_PIN, + CONF_CS_PIN, + CONF_DATA_PINS, + CONF_DATA_RATE, CONF_ID, + CONF_INVERTED, CONF_MISO_PIN, CONF_MOSI_PIN, - CONF_SPI_ID, - CONF_CS_PIN, CONF_NUMBER, - CONF_INVERTED, + CONF_SPI_ID, KEY_CORE, KEY_TARGET_PLATFORM, KEY_VARIANT, - CONF_DATA_RATE, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, - CONF_DATA_PINS, -) -from esphome.core import ( - coroutine_with_priority, - CORE, ) +from esphome.core import CORE, coroutine_with_priority +import esphome.final_validate as fv CODEOWNERS = ["@esphome/core", "@clydebarrow"] spi_ns = cg.esphome_ns.namespace("spi") @@ -69,6 +66,10 @@ SPI_MODE_OPTIONS = { 1: SPIMode.MODE1, 2: SPIMode.MODE2, 3: SPIMode.MODE3, + "0": SPIMode.MODE0, + "1": SPIMode.MODE1, + "2": SPIMode.MODE2, + "3": SPIMode.MODE3, } CONF_SPI_MODE = "spi_mode" diff --git a/esphome/components/spi_device/__init__.py b/esphome/components/spi_device/__init__.py index 65e7ee6fc6..2f23d8a011 100644 --- a/esphome/components/spi_device/__init__.py +++ b/esphome/components/spi_device/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import spi +import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODE DEPENDENCIES = ["spi"] @@ -11,18 +11,6 @@ spi_device_ns = cg.esphome_ns.namespace("spi_device") spi_device = spi_device_ns.class_("SPIDeviceComponent", cg.Component, spi.SPIDevice) -Mode = spi.spi_ns.enum("SPIMode") -MODES = { - "0": Mode.MODE0, - "1": Mode.MODE1, - "2": Mode.MODE2, - "3": Mode.MODE3, - "MODE0": Mode.MODE0, - "MODE1": Mode.MODE1, - "MODE2": Mode.MODE2, - "MODE3": Mode.MODE3, -} - BitOrder = spi.spi_ns.enum("SPIBitOrder") ORDERS = { "msb_first": BitOrder.BIT_ORDER_MSB_FIRST, @@ -34,7 +22,9 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_ID): cv.declare_id(spi_device), cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True), - cv.Optional(CONF_MODE, default="0"): cv.enum(MODES, upper=True), + cv.Optional(CONF_MODE): cv.invalid( + "The 'mode' option has been renamed to 'spi_mode'." + ), } ).extend(spi.spi_device_schema(False, "1MHz")) @@ -42,6 +32,5 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - cg.add(var.set_mode(config[CONF_MODE])) cg.add(var.set_bit_order(config[CONF_BIT_ORDER])) await spi.register_spi_device(var, config) diff --git a/tests/components/spi_device/test.esp32-ard.yaml b/tests/components/spi_device/test.esp32-ard.yaml index cad8ca49f8..b539cb3ec4 100644 --- a/tests/components/spi_device/test.esp32-ard.yaml +++ b/tests/components/spi_device/test.esp32-ard.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32-c3-ard.yaml b/tests/components/spi_device/test.esp32-c3-ard.yaml index 49e2733676..99c0ac1ebb 100644 --- a/tests/components/spi_device/test.esp32-c3-ard.yaml +++ b/tests/components/spi_device/test.esp32-c3-ard.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32-c3-idf.yaml b/tests/components/spi_device/test.esp32-c3-idf.yaml index 49e2733676..99c0ac1ebb 100644 --- a/tests/components/spi_device/test.esp32-c3-idf.yaml +++ b/tests/components/spi_device/test.esp32-c3-idf.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp32-idf.yaml b/tests/components/spi_device/test.esp32-idf.yaml index cad8ca49f8..b539cb3ec4 100644 --- a/tests/components/spi_device/test.esp32-idf.yaml +++ b/tests/components/spi_device/test.esp32-idf.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first diff --git a/tests/components/spi_device/test.esp8266-ard.yaml b/tests/components/spi_device/test.esp8266-ard.yaml index 1b191bdb6a..988825ce2d 100644 --- a/tests/components/spi_device/test.esp8266-ard.yaml +++ b/tests/components/spi_device/test.esp8266-ard.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first diff --git a/tests/components/spi_device/test.rp2040-ard.yaml b/tests/components/spi_device/test.rp2040-ard.yaml index c70493c70d..6020643f21 100644 --- a/tests/components/spi_device/test.rp2040-ard.yaml +++ b/tests/components/spi_device/test.rp2040-ard.yaml @@ -7,5 +7,5 @@ spi: spi_device: id: spi_device_test data_rate: 2MHz - mode: 3 + spi_mode: 3 bit_order: lsb_first From 80b4c264818df8ce79813d3f572e87b9c7d24bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Mart=C3=ADn?= Date: Wed, 6 Nov 2024 01:56:48 +0100 Subject: [PATCH 2607/2607] feat(MQTT): Add `enable`, `disable` and `enable_on_boot` (#7716) --- esphome/components/mqtt/__init__.py | 33 +++++++++++++++++++++++++ esphome/components/mqtt/mqtt_client.cpp | 30 +++++++++++++++++++--- esphome/components/mqtt/mqtt_client.h | 29 ++++++++++++++++++++-- tests/components/mqtt/common.yaml | 3 +++ 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 8851581ea0..86d163e61d 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -22,6 +22,7 @@ from esphome.const import ( CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_DISCOVERY_UNIQUE_ID_GENERATOR, + CONF_ENABLE_ON_BOOT, CONF_ID, CONF_KEEPALIVE, CONF_LEVEL, @@ -99,6 +100,8 @@ MQTTMessage = mqtt_ns.struct("MQTTMessage") MQTTClientComponent = mqtt_ns.class_("MQTTClientComponent", cg.Component) MQTTPublishAction = mqtt_ns.class_("MQTTPublishAction", automation.Action) MQTTPublishJsonAction = mqtt_ns.class_("MQTTPublishJsonAction", automation.Action) +MQTTEnableAction = mqtt_ns.class_("MQTTEnableAction", automation.Action) +MQTTDisableAction = mqtt_ns.class_("MQTTDisableAction", automation.Action) MQTTMessageTrigger = mqtt_ns.class_( "MQTTMessageTrigger", automation.Trigger.template(cg.std_string), cg.Component ) @@ -208,6 +211,7 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(MQTTClientComponent), cv.Required(CONF_BROKER): cv.string_strict, + cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, cv.Optional(CONF_PORT, default=1883): cv.port, cv.Optional(CONF_USERNAME, default=""): cv.string, cv.Optional(CONF_PASSWORD, default=""): cv.string, @@ -325,6 +329,7 @@ async def to_code(config): cg.add_global(mqtt_ns.using) cg.add(var.set_broker_address(config[CONF_BROKER])) + cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) cg.add(var.set_broker_port(config[CONF_PORT])) cg.add(var.set_username(config[CONF_USERNAME])) cg.add(var.set_password(config[CONF_PASSWORD])) @@ -555,3 +560,31 @@ async def register_mqtt_component(var, config): async def mqtt_connected_to_code(config, condition_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) return cg.new_Pvariable(condition_id, template_arg, paren) + + +@automation.register_action( + "mqtt.enable", + MQTTEnableAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(MQTTClientComponent), + } + ), +) +async def mqtt_enable_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + +@automation.register_action( + "mqtt.disable", + MQTTDisableAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(MQTTClientComponent), + } + ), +) +async def mqtt_disable_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index b5ac285026..106192c0e3 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -50,6 +50,8 @@ void MQTTClientComponent::setup() { } }); this->mqtt_backend_.set_on_disconnect([this](MQTTClientDisconnectReason reason) { + if (this->state_ == MQTT_CLIENT_DISABLED) + return; this->state_ = MQTT_CLIENT_DISCONNECTED; this->disconnect_reason_ = reason; }); @@ -77,8 +79,9 @@ void MQTTClientComponent::setup() { topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); } - this->last_connected_ = millis(); - this->start_dnslookup_(); + if (this->enable_on_boot_) { + this->enable(); + } } void MQTTClientComponent::send_device_info_() { @@ -163,7 +166,9 @@ void MQTTClientComponent::dump_config() { ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str()); } } -bool MQTTClientComponent::can_proceed() { return network::is_disabled() || this->is_connected(); } +bool MQTTClientComponent::can_proceed() { + return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected(); +} void MQTTClientComponent::start_dnslookup_() { for (auto &subscription : this->subscriptions_) { @@ -339,6 +344,8 @@ void MQTTClientComponent::loop() { const uint32_t now = millis(); switch (this->state_) { + case MQTT_CLIENT_DISABLED: + return; // Return to avoid a reboot when disabled case MQTT_CLIENT_DISCONNECTED: if (now - this->connect_begin_ > 5000) { this->start_dnslookup_(); @@ -501,6 +508,23 @@ bool MQTTClientComponent::publish_json(const std::string &topic, const json::jso return this->publish(topic, message, qos, retain); } +void MQTTClientComponent::enable() { + if (this->state_ != MQTT_CLIENT_DISABLED) + return; + ESP_LOGD(TAG, "Enabling MQTT..."); + this->state_ = MQTT_CLIENT_DISCONNECTED; + this->last_connected_ = millis(); + this->start_dnslookup_(); +} + +void MQTTClientComponent::disable() { + if (this->state_ == MQTT_CLIENT_DISABLED) + return; + ESP_LOGD(TAG, "Disabling MQTT..."); + this->state_ = MQTT_CLIENT_DISABLED; + this->on_shutdown(); +} + /** Check if the message topic matches the given subscription topic * * INFO: MQTT spec mandates that topics must not be empty and must be valid NULL-terminated UTF-8 strings. diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 887800f201..7ae3a6c5e8 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -87,7 +87,8 @@ struct MQTTDiscoveryInfo { }; enum MQTTClientState { - MQTT_CLIENT_DISCONNECTED = 0, + MQTT_CLIENT_DISABLED = 0, + MQTT_CLIENT_DISCONNECTED, MQTT_CLIENT_RESOLVING_ADDRESS, MQTT_CLIENT_CONNECTING, MQTT_CLIENT_CONNECTED, @@ -247,6 +248,9 @@ class MQTTClientComponent : public Component { void register_mqtt_component(MQTTComponent *component); bool is_connected(); + void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; } + void enable(); + void disable(); void on_shutdown() override; @@ -314,10 +318,11 @@ class MQTTClientComponent : public Component { MQTTBackendLibreTiny mqtt_backend_; #endif - MQTTClientState state_{MQTT_CLIENT_DISCONNECTED}; + MQTTClientState state_{MQTT_CLIENT_DISABLED}; network::IPAddress ip_; bool dns_resolved_{false}; bool dns_resolve_error_{false}; + bool enable_on_boot_{true}; std::vector children_; uint32_t reboot_timeout_{300000}; uint32_t connect_begin_; @@ -414,6 +419,26 @@ template class MQTTConnectedCondition : public Condition MQTTClientComponent *parent_; }; +template class MQTTEnableAction : public Action { + public: + MQTTEnableAction(MQTTClientComponent *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->enable(); } + + protected: + MQTTClientComponent *parent_; +}; + +template class MQTTDisableAction : public Action { + public: + MQTTDisableAction(MQTTClientComponent *parent) : parent_(parent) {} + + void play(Ts... x) override { this->parent_->disable(); } + + protected: + MQTTClientComponent *parent_; +}; + } // namespace mqtt } // namespace esphome diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index 75c34bec56..d22fe9579f 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -10,6 +10,7 @@ mqtt: port: 1883 username: debug password: debug + enable_on_boot: false clean_session: True client_id: someclient use_abbreviations: false @@ -87,6 +88,8 @@ button: state_topic: some/topic/button qos: 2 on_press: + - mqtt.disable + - mqtt.enable - mqtt.publish: topic: some/topic/button payload: Hello